ceph-0.80.11/0000775000175100017510000000000012623077037014671 5ustar jenkins-buildjenkins-buildceph-0.80.11/autogen.sh0000775000175100017510000000176112623076744016703 0ustar jenkins-buildjenkins-build#!/bin/sh set -e check_for_pkg_config() { which pkg-config >/dev/null && return echo echo "Error: could not find pkg-config" echo echo "Please make sure you have pkg-config installed." echo exit 1 } if [ `which libtoolize` ]; then LIBTOOLIZE=libtoolize elif [ `which glibtoolize` ]; then LIBTOOLIZE=glibtoolize else echo "Error: could not find libtoolize" echo " Please install libtoolize or glibtoolize." exit 1 fi if test -d ".git" ; then force=$(if git submodule usage 2>&1 | grep --quiet 'update.*--force'; then echo --force ; fi) if ! git submodule sync || ! git submodule update $force --init --recursive; then echo "Error: could not initialize submodule projects" echo " Network connectivity might be required." exit 1 fi fi rm -f config.cache aclocal -I m4 --install check_for_pkg_config $LIBTOOLIZE --force --copy aclocal -I m4 --install autoconf autoheader automake -a --add-missing -Wall ( cd src/gtest && autoreconf -fvi; ) exit ceph-0.80.11/configure0000775000175100017510000267004512623076763016623 0ustar jenkins-buildjenkins-build#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for ceph 0.80.11. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: ceph-devel@vger.kernel.org about your system, including $0: any error possibly output before this message. Then $0: install a modern shell, or manually run the script $0: under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ceph' PACKAGE_TARNAME='ceph' PACKAGE_VERSION='0.80.11' PACKAGE_STRING='ceph 0.80.11' PACKAGE_BUGREPORT='ceph-devel@vger.kernel.org' PACKAGE_URL='' enable_option_checking=no # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS pkgpyexecdir pyexecdir pkgpythondir pythondir PYTHON_PLATFORM PYTHON_EXEC_PREFIX PYTHON_PREFIX PYTHON_VERSION PYTHON WITH_BUILD_TESTS_FALSE WITH_BUILD_TESTS_TRUE BOOST_PROGRAM_OPTIONS_LIBS USE_BOOST_SPIRIT_OLD_HDR_FALSE USE_BOOST_SPIRIT_OLD_HDR_TRUE WITH_LIBZFS_FALSE WITH_LIBZFS_TRUE LIBZFS_LIBS LIBZFS_CFLAGS WITH_LIBXFS_FALSE WITH_LIBXFS_TRUE WITH_LIBAIO_FALSE WITH_LIBAIO_TRUE WITH_REST_BENCH_FALSE WITH_REST_BENCH_TRUE WITH_SYSTEM_LIBS3_FALSE WITH_SYSTEM_LIBS3_TRUE INTEL_FLAGS INTEL_SSE4_2_FLAGS INTEL_SSE4_1_FLAGS INTEL_PCLMUL_FLAGS INTEL_SSSE3_FLAGS INTEL_SSE3_FLAGS INTEL_SSE2_FLAGS INTEL_SSE_FLAGS WITH_OCF_FALSE WITH_OCF_TRUE WITH_LIBATOMIC_FALSE WITH_LIBATOMIC_TRUE LIBEDIT_LIBS LIBEDIT_CFLAGS HAVE_JUNIT4_FALSE HAVE_JUNIT4_TRUE JDK_CPPFLAGS JAR JAVAH JAVAC EXTRA_CLASSPATH_JAR ENABLE_CEPHFS_JAVA_FALSE ENABLE_CEPHFS_JAVA_TRUE WITH_TCMALLOC_FALSE WITH_TCMALLOC_TRUE LIBTCMALLOC WITH_FUSE_FALSE WITH_FUSE_TRUE LIBFUSE WITH_RADOSGW_FALSE WITH_RADOSGW_TRUE GCOV_PREFIX_STRIP ENABLE_COVERAGE_FALSE ENABLE_COVERAGE_TRUE WITH_DEBUG_FALSE WITH_DEBUG_TRUE WITH_PROFILER_FALSE WITH_PROFILER_TRUE CRYPTO_LIBS CRYPTO_CFLAGS NSS_LIBS NSS_CFLAGS CRYPTOPP_LIBS CRYPTOPP_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG KEYUTILS_LIB RESOLV_LIBS PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC acx_pthread_config COMPILER_HAS_VTA_FALSE COMPILER_HAS_VTA_TRUE ENABLE_FPU_NEON_FALSE ENABLE_FPU_NEON_TRUE WARN_IGNORED_QUALIFIERS WARN_TYPE_LIMITS WITH_GOOD_YASM_ELF64_FALSE WITH_GOOD_YASM_ELF64_TRUE AM_CXXFLAGS CLANG_FALSE CLANG_TRUE CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX FREEBSD_FALSE FREEBSD_TRUE LINUX_FALSE LINUX_TRUE am__fastdepCCAS_FALSE am__fastdepCCAS_TRUE CCASDEPMODE CCASFLAGS CCAS CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED LIBTOOL AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC ac_ct_AR AR target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build subdirs GIT_CHECK RPM_RELEASE target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_dependency_tracking enable_silent_rules enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock with_cryptopp with_nss with_profiler with_debug enable_coverage with_radosgw with_fuse with_tcmalloc enable_pgrefdebugging enable_cephfs_java with_jdk_dir with_libatomic_ops with_ocf with_system_libs3 with_rest_bench with_libaio with_libxfs with_libzfs ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CCAS CCASFLAGS CXX CXXFLAGS CCC CXXCPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR CRYPTOPP_CFLAGS CRYPTOPP_LIBS NSS_CFLAGS NSS_LIBS LIBEDIT_CFLAGS LIBEDIT_LIBS LIBZFS_CFLAGS LIBZFS_LIBS PYTHON' ac_subdirs_all='src/gtest' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures ceph 0.80.11 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/ceph] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of ceph 0.80.11:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --enable-coverage enable code coverage tracking --enable-pgrefdebugging enable pg ref debugging --enable-cephfs-java build libcephfs Java bindings Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-cryptopp Use cryptographic functions from cryptopp --with-nss Use cryptographic functions from nss --with-profiler build extra profiler binaries --with-debug build extra debug binaries --with-radosgw build RADOS gateway --without-fuse disable FUSE userspace client --without-tcmalloc disable tcmalloc for memory allocations --with-jdk-dir(=DIR) Path to JDK directory --without-libatomic-ops disable libatomic-ops for the atomic_t type --with-ocf build OCF-compliant cluster resource agent --with-system-libs3 use system libs3 --with-rest-bench enables rest-bench --without-libaio disable libaio use by journal --without-libxfs disable libxfs use by FileStore --with-libzfs build ZFS support Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CCAS assembler compiler command (defaults to CC) CCASFLAGS assembler compiler flags (defaults to CFLAGS) CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path CRYPTOPP_CFLAGS C compiler flags for CRYPTOPP, overriding pkg-config CRYPTOPP_LIBS linker flags for CRYPTOPP, overriding pkg-config NSS_CFLAGS C compiler flags for NSS, overriding pkg-config NSS_LIBS linker flags for NSS, overriding pkg-config LIBEDIT_CFLAGS C compiler flags for LIBEDIT, overriding pkg-config LIBEDIT_LIBS linker flags for LIBEDIT, overriding pkg-config LIBZFS_CFLAGS C compiler flags for LIBZFS, overriding pkg-config LIBZFS_LIBS linker flags for LIBZFS, overriding pkg-config PYTHON the Python interpreter Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF ceph configure 0.80.11 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ----------------------------------------- ## ## Report this to ceph-devel@vger.kernel.org ## ## ----------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ----------------------------------------- ## ## Report this to ceph-devel@vger.kernel.org ## ## ----------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_mongrel # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_cxx_check_decl LINENO SYMBOL VAR INCLUDES # ----------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_cxx_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_decl # ac_fn_cxx_check_func LINENO FUNC VAR # ------------------------------------ # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_cxx_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_func # ac_fn_cxx_try_run LINENO # ------------------------ # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by ceph $as_me 0.80.11, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Create release string. Used with VERSION for RPMs. RPM_RELEASE=0 if test -d ".git" ; then # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_GIT_CHECK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$GIT_CHECK"; then ac_cv_prog_GIT_CHECK="$GIT_CHECK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_GIT_CHECK="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi GIT_CHECK=$ac_cv_prog_GIT_CHECK if test -n "$GIT_CHECK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GIT_CHECK" >&5 $as_echo "$GIT_CHECK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$GIT_CHECK" = x"yes"; then RPM_RELEASE=`if expr index $(git describe --always) '-' > /dev/null ; then git describe --always | cut -d- -f2- | tr '-' '.' ; else echo "0"; fi` fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: RPM_RELEASE='$RPM_RELEASE'" >&5 $as_echo "$as_me: RPM_RELEASE='$RPM_RELEASE'" >&6;} ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. subdirs="$subdirs src/gtest" # Environment # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- # Fix automake problems in 1.12 # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} { $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 $as_echo_n "checking the archiver ($AR) interface... " >&6; } if ${am_cv_ar_interface+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 $as_echo "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac # Automake am__api_version='1.14' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='ceph' VERSION='0.80.11' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: # By default we simply use the C compiler to build assembly code. test "${CCAS+set}" = set || CCAS=$CC test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS depcc="$CCAS" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CCAS_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CCAS_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CCAS_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CCAS_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5 $as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; } CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then am__fastdepCCAS_TRUE= am__fastdepCCAS_FALSE='#' else am__fastdepCCAS_TRUE='#' am__fastdepCCAS_FALSE= fi # enable make V=0 (if automake >1.11) if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='ceph' VERSION='0.80.11' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=0;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' # Platform case "${target_os}" in darwin*) $as_echo "#define DARWIN 1" >>confdefs.h ;; linux*) linux="yes" ;; freebsd*) freebsd="yes" ;; esac if test x"$linux" = x"yes"; then LINUX_TRUE= LINUX_FALSE='#' else LINUX_TRUE='#' LINUX_FALSE= fi if test x"$freebsd" = x"yes"; then FREEBSD_TRUE= FREEBSD_FALSE='#' else FREEBSD_TRUE='#' FREEBSD_FALSE= fi # Checks for programs. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu else _lt_caught_CXX_error=yes fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= compiler_needs_object_CXX=no export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no inherit_rpath_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds reload_flag_CXX=$reload_flag reload_cmds_CXX=$reload_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC compiler_CXX=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes file_list_spec_CXX='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec_CXX='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty # executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' fi archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds its shared # libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_CXX=' ' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=yes file_list_spec_CXX='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' enable_shared_with_static_runtimes_CXX=yes # Don't use ranlib old_postinstall_cmds_CXX='chmod 644 $oldlib' postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec_CXX='' fi link_all_deplibs_CXX=yes allow_undefined_flag_CXX="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" if test "$lt_cv_apple_cc_single_mod" != "yes"; then archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; haiku*) archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs_CXX=yes ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) ;; *) export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix[3-9]*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: inherit_rpath_CXX=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [1-5].* | *pgcpp\ [1-5].*) prelink_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' old_archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' hardcode_libdir_flag_spec_CXX='-R$libdir' whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object_CXX=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) ld_shlibs_CXX=yes ;; openbsd2*) # C++ shared libraries are fairly broken ld_shlibs_CXX=no ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no hardcode_direct_absolute_CXX=yes archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='${wl}-E' whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else ld_shlibs_CXX=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) case $host in osf3*) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ;; *) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' ;; esac hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='${wl}-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_CXX='${wl}-z,text' allow_undefined_flag_CXX='${wl}-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ '"$old_archive_cmds_CXX" reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ '"$reload_cmds_CXX" ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken case $host_os in interix[3-9]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac compiler_lib_search_dirs_CXX= if test -n "${compiler_lib_search_path_CXX}"; then compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic_CXX='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static_CXX= ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix[4-9]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) # IBM XL 8.0, 9.0 on PPC and BlueGene lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-qpic' lt_prog_compiler_static_CXX='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works_CXX=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works_CXX=yes fi else lt_cv_prog_compiler_static_works_CXX=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then : else lt_prog_compiler_static_CXX= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' case $host_os in aix[4-9]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' ;; esac ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs_CXX=no ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no with_gnu_ld_CXX=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc_CXX=no else lt_cv_archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 $as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || test -n "$runpath_var_CXX" || test "X$hardcode_automatic_CXX" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink || test "$inherit_rpath_CXX" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi if test "$CXX" = no || test "$CXX:$GXX" = "g++:"; then as_fn_error $? "no C++ compiler found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler is clang" >&5 $as_echo_n "checking if compiler is clang... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __clang__ #error "Not Clang" #endif return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : CLANG=yes else CLANG=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLANG" >&5 $as_echo "$CLANG" >&6; } if test "$CLANG" = "yes"; then CLANG_TRUE= CLANG_FALSE='#' else CLANG_TRUE='#' CLANG_FALSE= fi #AC_PROG_CC { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi # Compiler flags AM_CXXFLAGS="${AM_CXXFLAGS}" # Check for yasm if yasm -f elf64 src/common/crc32c_intel_fast_asm.S -o /dev/null; then echo 'we have a modern and working yasm' if test `arch` = "x86_64"; then echo 'we are x86_64' $as_echo "#define HAVE_GOOD_YASM_ELF64 1" >>confdefs.h with_good_yasm=yes fi else echo 'we do not have a modern/working yasm' fi if test "$with_good_yasm" = "yes"; then WITH_GOOD_YASM_ELF64_TRUE= WITH_GOOD_YASM_ELF64_FALSE='#' else WITH_GOOD_YASM_ELF64_TRUE='#' WITH_GOOD_YASM_ELF64_FALSE= fi # Checks for compiler warning types # AC_CHECK_CC_FLAG(FLAG_TO_TEST, VARIABLE_TO_SET_IF_SUPPORTED) # --------- { ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu my_cflags_save="$CFLAGS" CFLAGS="$my_cflags_save -Wtype-limits" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Wtype-limits" >&5 $as_echo_n "checking whether $CC accepts -Wtype-limits... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; WARN_TYPE_LIMITS="-Wtype-limits" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$my_cflags_save" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu } { ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu my_cflags_save="$CFLAGS" CFLAGS="$my_cflags_save -Wignored-qualifiers" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Wignored-qualifiers" >&5 $as_echo_n "checking whether $CC accepts -Wignored-qualifiers... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; WARN_IGNORED_QUALIFIERS="-Wignored-qualifiers" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$my_cflags_save" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu } # Checks for architecture stuff if case $target_cpu in arm*) true;; *) false;; esac; then ENABLE_FPU_NEON_TRUE= ENABLE_FPU_NEON_FALSE='#' else ENABLE_FPU_NEON_TRUE='#' ENABLE_FPU_NEON_FALSE= fi # Check for compiler VTA support { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fvar-tracking-assignments" >&5 $as_echo_n "checking whether C compiler accepts -fvar-tracking-assignments... " >&6; } if ${ax_cv_check_cflags___fvar_tracking_assignments+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fvar-tracking-assignments" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___fvar_tracking_assignments=yes else ax_cv_check_cflags___fvar_tracking_assignments=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fvar_tracking_assignments" >&5 $as_echo "$ax_cv_check_cflags___fvar_tracking_assignments" >&6; } if test x"$ax_cv_check_cflags___fvar_tracking_assignments" = xyes; then : HAS_VTA_SUPPORT=1 else HAS_VTA_SUPPORT=0 fi if test "$HAS_VTA_SUPPORT" = 1; then COMPILER_HAS_VTA_TRUE= COMPILER_HAS_VTA_FALSE='#' else COMPILER_HAS_VTA_TRUE='#' COMPILER_HAS_VTA_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports static_cast<>" >&5 $as_echo_n "checking whether the compiler supports static_cast<>... " >&6; } if ${ax_cv_cxx_static_cast+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include class Base { public : Base () {} virtual void f () = 0; }; class Derived : public Base { public : Derived () {} virtual void f () {} }; int g (Derived&) { return 0; } int main () { Derived d; Base& b = d; Derived& s = static_cast (b); return g (s); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ax_cv_cxx_static_cast=yes else ax_cv_cxx_static_cast=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_static_cast" >&5 $as_echo "$ax_cv_cxx_static_cast" >&6; } if test "$ax_cv_cxx_static_cast" = yes; then $as_echo "#define HAVE_STATIC_CAST /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC recognizes __func__" >&5 $as_echo_n "checking whether $CC recognizes __func__... " >&6; } if ${ac_cv_c_var_func+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { char *s = __func__; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_FUNC /**/" >>confdefs.h ac_cv_c_var_func=yes else ac_cv_c_var_func=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_var_func" >&5 $as_echo "$ac_cv_c_var_func" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC recognizes __PRETTY_FUNCTION__" >&5 $as_echo_n "checking whether $CC recognizes __PRETTY_FUNCTION__... " >&6; } if ${ac_cv_c_pretty_func+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { char *s = __PRETTY_FUNCTION__; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_PRETTY_FUNC /**/" >>confdefs.h ac_cv_c_pretty_func=yes else ac_cv_c_pretty_func=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_pretty_func" >&5 $as_echo "$ac_cv_c_pretty_func" >&6; } # Checks for libraries. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 $as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_join (); int main () { return pthread_join (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 $as_echo_n "checking whether pthreads work without any flags... " >&6; } ;; -*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 $as_echo_n "checking whether pthreads work with $flag... " >&6; } PTHREAD_CFLAGS="$flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_acx_pthread_config+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$acx_pthread_config"; then ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_acx_pthread_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no" fi fi acx_pthread_config=$ac_cv_prog_acx_pthread_config if test -n "$acx_pthread_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5 $as_echo "$acx_pthread_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 $as_echo_n "checking for the pthreads library -l$flag... " >&6; } PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int attr=$attr; return attr; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : attr_name=$attr; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 $as_echo "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then cat >>confdefs.h <<_ACEOF #define PTHREAD_CREATE_JOINABLE $attr_name _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 $as_echo_n "checking if more special flags are required for pthreads... " >&6; } flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 $as_echo "${flag}" >&6; } if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then for ac_prog in xlc_r cc_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PTHREAD_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PTHREAD_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 $as_echo "$PTHREAD_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to check for GCC pthread/shared inconsistencies" >&5 $as_echo_n "checking whether to check for GCC pthread/shared inconsistencies... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is sufficient with -shared" >&5 $as_echo_n "checking whether -pthread is sufficient with -shared... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread fixes that" >&5 $as_echo_n "checking whether -lpthread fixes that... " >&6; } LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc_r fixes that" >&5 $as_echo_n "checking whether -lc_r fixes that... " >&6; } LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test x"$done" = xno; then # OK, we have run out of ideas { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries" >&5 $as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries" >&2;} # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether what we have so far is sufficient with -nostdlib" >&5 $as_echo_n "checking whether what we have so far is sufficient with -nostdlib... " >&6; } CFLAGS="-nostdlib $CFLAGS" # we need c with nostdlib LIBS="$LIBS -lc" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes else done=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread saves the day" >&5 $as_echo_n "checking whether -lpthread saves the day... " >&6; } LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes else done=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries and -nostdlib" >&5 $as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries and -nostdlib" >&2;} fi fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then $as_echo "#define HAVE_PTHREAD 1" >>confdefs.h : else acx_pthread_ok=no fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_parse in -luuid" >&5 $as_echo_n "checking for uuid_parse in -luuid... " >&6; } if ${ac_cv_lib_uuid_uuid_parse+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char uuid_parse (); int main () { return uuid_parse (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_uuid_uuid_parse=yes else ac_cv_lib_uuid_uuid_parse=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_parse" >&5 $as_echo "$ac_cv_lib_uuid_uuid_parse" >&6; } if test "x$ac_cv_lib_uuid_uuid_parse" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libuuid not found See \`config.log' for more details" "$LINENO" 5; } fi if test x"$linux" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid_devno_to_wholedisk in -lblkid" >&5 $as_echo_n "checking for blkid_devno_to_wholedisk in -lblkid... " >&6; } if ${ac_cv_lib_blkid_blkid_devno_to_wholedisk+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lblkid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char blkid_devno_to_wholedisk (); int main () { return blkid_devno_to_wholedisk (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_blkid_blkid_devno_to_wholedisk=yes else ac_cv_lib_blkid_blkid_devno_to_wholedisk=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blkid_blkid_devno_to_wholedisk" >&5 $as_echo "$ac_cv_lib_blkid_blkid_devno_to_wholedisk" >&6; } if test "x$ac_cv_lib_blkid_blkid_devno_to_wholedisk" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libblkid not found See \`config.log' for more details" "$LINENO" 5; } fi fi # # Check for res_nquery in libresolv. There are several variations. On OSX # res_nquery is a macro defined in resolv.h, so the typical AC_CHECK_LIB # doesn't work. On FreeBSD res_nquery can be found in libc. The required # library for linking (if any) is defined RESOLV_LIBS. # ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "#include " if test "x$ac_cv_header_resolv_h" = xyes; then : fi RESOLV_LIBS="" { { $as_echo "$as_me:${as_lineno-$LINENO}: checking if res_nquery will link (LIBS=$RESOLV_LIBS)" >&5 $as_echo_n "checking if res_nquery will link (LIBS=$RESOLV_LIBS)... " >&6; } saved_LIBS="${LIBS}" LIBS="$RESOLV_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { res_nquery(0, 0, 0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } resolv_libs="ok" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="${saved_LIBS}" } if test x"$resolv_libs" != "xok"; then RESOLV_LIBS="-lresolv" { { $as_echo "$as_me:${as_lineno-$LINENO}: checking if res_nquery will link (LIBS=$RESOLV_LIBS)" >&5 $as_echo_n "checking if res_nquery will link (LIBS=$RESOLV_LIBS)... " >&6; } saved_LIBS="${LIBS}" LIBS="$RESOLV_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { res_nquery(0, 0, 0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } resolv_libs="ok" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="${saved_LIBS}" } if test x"$resolv_libs" != "xok"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no resolv library found See \`config.log' for more details" "$LINENO" 5; } fi fi KEYUTILS_LIB="" if test x"$linux" = x"yes"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for add_key in -lkeyutils" >&5 $as_echo_n "checking for add_key in -lkeyutils... " >&6; } if ${ac_cv_lib_keyutils_add_key+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkeyutils $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char add_key (); int main () { return add_key (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_keyutils_add_key=yes else ac_cv_lib_keyutils_add_key=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_keyutils_add_key" >&5 $as_echo "$ac_cv_lib_keyutils_add_key" >&6; } if test "x$ac_cv_lib_keyutils_add_key" = xyes; then : KEYUTILS_LIB="-lkeyutils" else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libkeyutils not found See \`config.log' for more details" "$LINENO" 5; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if ${ac_cv_lib_m_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libm not found See \`config.log' for more details" "$LINENO" 5; } fi for ac_func in syncfs do : ac_fn_c_check_func "$LINENO" "syncfs" "ac_cv_func_syncfs" if test "x$ac_cv_func_syncfs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYNCFS 1 _ACEOF $as_echo "#define HAVE_SYS_SYNCFS 1" >>confdefs.h fi done # Find some crypto library for us to use, while letting user to decide which one to use. # Check whether --with-cryptopp was given. if test "${with_cryptopp+set}" = set; then : withval=$with_cryptopp; else with_cryptopp=check fi have_cryptopp=no # this looks clumsy but it's just if A then { success } else { if B then success } if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi if test "x$with_cryptopp" != "xno"; then : pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CRYPTOPP" >&5 $as_echo_n "checking for CRYPTOPP... " >&6; } if test -n "$CRYPTOPP_CFLAGS"; then pkg_cv_CRYPTOPP_CFLAGS="$CRYPTOPP_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcrypto++\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcrypto++") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CRYPTOPP_CFLAGS=`$PKG_CONFIG --cflags "libcrypto++" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CRYPTOPP_LIBS"; then pkg_cv_CRYPTOPP_LIBS="$CRYPTOPP_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcrypto++\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcrypto++") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CRYPTOPP_LIBS=`$PKG_CONFIG --libs "libcrypto++" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CRYPTOPP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcrypto++" 2>&1` else CRYPTOPP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcrypto++" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CRYPTOPP_PKG_ERRORS" >&5 ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu SAVED_CXXFLAGS="${CXXFLAGS}" SAVED_LIBS="${LIBS}" LIBS="${LIBS} ${PTHREAD_LIBS}" CXXFLAGS="${CXXFLAGS} ${PTHREAD_CFLAGS}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing _ZTIN8CryptoPP14CBC_EncryptionE" >&5 $as_echo_n "checking for library containing _ZTIN8CryptoPP14CBC_EncryptionE... " >&6; } if ${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char _ZTIN8CryptoPP14CBC_EncryptionE (); int main () { return _ZTIN8CryptoPP14CBC_EncryptionE (); ; return 0; } _ACEOF for ac_lib in '' crypto++ cryptopp; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE+:} false; then : break fi done if ${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE+:} false; then : else ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE" >&5 $as_echo "$ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE" >&6; } ac_res=$ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_cryptopp=yes else true fi CRYPTOPP_LIBS="${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE}" LIBS="${SAVED_LIBS}" CXXFLAGS="${SAVED_CXXFLAGS}" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu SAVED_CXXFLAGS="${CXXFLAGS}" SAVED_LIBS="${LIBS}" LIBS="${LIBS} ${PTHREAD_LIBS}" CXXFLAGS="${CXXFLAGS} ${PTHREAD_CFLAGS}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing _ZTIN8CryptoPP14CBC_EncryptionE" >&5 $as_echo_n "checking for library containing _ZTIN8CryptoPP14CBC_EncryptionE... " >&6; } if ${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char _ZTIN8CryptoPP14CBC_EncryptionE (); int main () { return _ZTIN8CryptoPP14CBC_EncryptionE (); ; return 0; } _ACEOF for ac_lib in '' crypto++ cryptopp; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE+:} false; then : break fi done if ${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE+:} false; then : else ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE" >&5 $as_echo "$ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE" >&6; } ac_res=$ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_cryptopp=yes else true fi CRYPTOPP_LIBS="${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE}" LIBS="${SAVED_LIBS}" CXXFLAGS="${SAVED_CXXFLAGS}" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu else CRYPTOPP_CFLAGS=$pkg_cv_CRYPTOPP_CFLAGS CRYPTOPP_LIBS=$pkg_cv_CRYPTOPP_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_cryptopp=yes fi fi # bail out if given explicit --with-cryptopp if test "x$have_cryptopp" = "xno" -a "x$with_cryptopp" != "xcheck" -a "x$with_cryptopp" != "xno"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-cryptopp was given, but library was not found See \`config.log' for more details" "$LINENO" 5; } fi # Check whether --with-nss was given. if test "${with_nss+set}" = set; then : withval=$with_nss; else with_nss=check fi have_nss=no if test "x$with_nss" != "xno"; then : pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NSS" >&5 $as_echo_n "checking for NSS... " >&6; } if test -n "$NSS_CFLAGS"; then pkg_cv_NSS_CFLAGS="$NSS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"nss\""; } >&5 ($PKG_CONFIG --exists --print-errors "nss") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_NSS_CFLAGS=`$PKG_CONFIG --cflags "nss" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$NSS_LIBS"; then pkg_cv_NSS_LIBS="$NSS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"nss\""; } >&5 ($PKG_CONFIG --exists --print-errors "nss") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_NSS_LIBS=`$PKG_CONFIG --libs "nss" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then NSS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "nss" 2>&1` else NSS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "nss" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$NSS_PKG_ERRORS" >&5 true elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } true else NSS_CFLAGS=$pkg_cv_NSS_CFLAGS NSS_LIBS=$pkg_cv_NSS_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_nss=yes fi fi # bail out if given explicit --with-nss if test "x$have_nss" = "xno" -a "x$with_nss" != "xcheck" -a "x$with_nss" != "xno"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-nss was given, but library was not found See \`config.log' for more details" "$LINENO" 5; } fi # now decide which crypto library to really use if test "x$have_cryptopp" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: using cryptopp for cryptography" >&5 $as_echo "$as_me: using cryptopp for cryptography" >&6;} $as_echo "#define USE_CRYPTOPP 1" >>confdefs.h CRYPTO_CFLAGS=$CRYPTOPP_CFLAGS #AC_SUBST([CRYPTO_CXXFLAGS], [$CRYPTOPP_CXXFLAGS]) AM_CXXFLAGS="${AM_CXXFLAGS} ${CRYPTOPP_CXXFLAGS}" CRYPTO_LIBS=$CRYPTOPP_LIBS elif test "x$have_nss" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: using nss for cryptography" >&5 $as_echo "$as_me: using nss for cryptography" >&6;} $as_echo "#define USE_NSS 1" >>confdefs.h CRYPTO_CFLAGS=$NSS_CFLAGS # this needs CFLAGS too in practise to get the includes right. ugly. #AC_SUBST([CRYPTO_CXXFLAGS], [$NSS_CFLAGS $NSS_CXXFLAGS]) AM_CXXFLAGS="${AM_CXXFLAGS} ${NSS_CFLAGS} ${NSS_CXXFLAGS}" CRYPTO_LIBS=$NSS_LIBS else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no suitable crypto library found See \`config.log' for more details" "$LINENO" 5; } fi # profiler? # Check whether --with-profiler was given. if test "${with_profiler+set}" = set; then : withval=$with_profiler; case "${withval}" in yes) with_profiler=yes ;; no) with_profiler=no ;; *) as_fn_error $? "bad value ${withval} for --with-profiler" "$LINENO" 5 ;; esac else with_profiler=no fi if test "x$with_profiler" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ProfilerFlush in -lprofiler" >&5 $as_echo_n "checking for ProfilerFlush in -lprofiler... " >&6; } if ${ac_cv_lib_profiler_ProfilerFlush+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lprofiler $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ProfilerFlush (); int main () { return ProfilerFlush (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_profiler_ProfilerFlush=yes else ac_cv_lib_profiler_ProfilerFlush=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_profiler_ProfilerFlush" >&5 $as_echo "$ac_cv_lib_profiler_ProfilerFlush" >&6; } if test "x$ac_cv_lib_profiler_ProfilerFlush" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPROFILER 1 _ACEOF LIBS="-lprofiler $LIBS" else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-profiler was given but libprofiler (libgoogle-perftools-dev on debian) not found See \`config.log' for more details" "$LINENO" 5; } fi fi if test "$with_profiler" = "yes"; then WITH_PROFILER_TRUE= WITH_PROFILER_FALSE='#' else WITH_PROFILER_TRUE='#' WITH_PROFILER_FALSE= fi if test "$with_profiler" = "yes"; then : $as_echo "#define HAVE_PROFILER 1" >>confdefs.h fi # debug crap? # Check whether --with-debug was given. if test "${with_debug+set}" = set; then : withval=$with_debug; case "${withval}" in yes) with_debug=yes ;; no) with_debug=no ;; *) as_fn_error $? "bad value ${withval} for --with-debug" "$LINENO" 5 ;; esac else with_debug=no fi if test "$with_debug" = "yes"; then WITH_DEBUG_TRUE= WITH_DEBUG_FALSE='#' else WITH_DEBUG_TRUE='#' WITH_DEBUG_FALSE= fi $as_echo "#define DEBUG_GATHER 1" >>confdefs.h # code coverage? # Check whether --enable-coverage was given. if test "${enable_coverage+set}" = set; then : enableval=$enable_coverage; else enable_coverage=no fi if test "x$enable_coverage" != xno; then ENABLE_COVERAGE_TRUE= ENABLE_COVERAGE_FALSE='#' else ENABLE_COVERAGE_TRUE='#' ENABLE_COVERAGE_FALSE= fi if test "x$enable_coverage" != xno; then $as_echo "#define ENABLE_COVERAGE 1" >>confdefs.h fi GCOV_PREFIX_STRIP=`echo $(pwd)/src | tr -dc / | wc -c` # radosgw? # Check whether --with-radosgw was given. if test "${with_radosgw+set}" = set; then : withval=$with_radosgw; else with_radosgw=check fi RADOSGW=0 if test "x$with_radosgw" != xno; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FCGX_Init in -lfcgi" >&5 $as_echo_n "checking for FCGX_Init in -lfcgi... " >&6; } if ${ac_cv_lib_fcgi_FCGX_Init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfcgi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char FCGX_Init (); int main () { return FCGX_Init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_fcgi_FCGX_Init=yes else ac_cv_lib_fcgi_FCGX_Init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fcgi_FCGX_Init" >&5 $as_echo "$ac_cv_lib_fcgi_FCGX_Init" >&6; } if test "x$ac_cv_lib_fcgi_FCGX_Init" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XML_Parse in -lexpat" >&5 $as_echo_n "checking for XML_Parse in -lexpat... " >&6; } if ${ac_cv_lib_expat_XML_Parse+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lexpat $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XML_Parse (); int main () { return XML_Parse (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_expat_XML_Parse=yes else ac_cv_lib_expat_XML_Parse=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_expat_XML_Parse" >&5 $as_echo "$ac_cv_lib_expat_XML_Parse" >&6; } if test "x$ac_cv_lib_expat_XML_Parse" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curl_easy_init in -lcurl" >&5 $as_echo_n "checking for curl_easy_init in -lcurl... " >&6; } if ${ac_cv_lib_curl_curl_easy_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcurl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char curl_easy_init (); int main () { return curl_easy_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_curl_curl_easy_init=yes else ac_cv_lib_curl_curl_easy_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curl_curl_easy_init" >&5 $as_echo "$ac_cv_lib_curl_curl_easy_init" >&6; } if test "x$ac_cv_lib_curl_curl_easy_init" = xyes; then : RADOSGW=1 ac_fn_c_check_header_mongrel "$LINENO" "fastcgi/fcgiapp.h" "ac_cv_header_fastcgi_fcgiapp_h" "$ac_includes_default" if test "x$ac_cv_header_fastcgi_fcgiapp_h" = xyes; then : $as_echo "#define FASTCGI_INCLUDE_DIR 1" >>confdefs.h fi else if test "x$with_radosgw" != "xcheck"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-radosgw was given but libcurl (libcurl-dev on debian) not found See \`config.log' for more details" "$LINENO" 5; } fi fi else if test "x$with_radosgw" != "xcheck"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-radosgw was given but libexpat (libexpat1-dev on debian) not found See \`config.log' for more details" "$LINENO" 5; } fi fi else if test "x$with_radosgw" != "xcheck"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-radosgw was given but libfcgi (libfcgi-dev on debian) not found See \`config.log' for more details" "$LINENO" 5; } fi fi fi if test "$RADOSGW" = "1"; then WITH_RADOSGW_TRUE= WITH_RADOSGW_FALSE='#' else WITH_RADOSGW_TRUE='#' WITH_RADOSGW_FALSE= fi if test "$RADOSGW" = "1"; then : $as_echo "#define WITH_RADOSGW 1" >>confdefs.h fi if test "$RADOSGW" = "1"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curl_multi_wait in -lcurl" >&5 $as_echo_n "checking for curl_multi_wait in -lcurl... " >&6; } if ${ac_cv_lib_curl_curl_multi_wait+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcurl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char curl_multi_wait (); int main () { return curl_multi_wait (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_curl_curl_multi_wait=yes else ac_cv_lib_curl_curl_multi_wait=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curl_curl_multi_wait" >&5 $as_echo "$ac_cv_lib_curl_curl_multi_wait" >&6; } if test "x$ac_cv_lib_curl_curl_multi_wait" = xyes; then : $as_echo "#define HAVE_CURL_MULTI_WAIT 1" >>confdefs.h fi fi # fuse? # Check whether --with-fuse was given. if test "${with_fuse+set}" = set; then : withval=$with_fuse; else with_fuse=yes fi LIBFUSE= if test "x$with_fuse" != xno; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -lfuse" >&5 $as_echo_n "checking for fuse_main in -lfuse... " >&6; } if ${ac_cv_lib_fuse_fuse_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfuse $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char fuse_main (); int main () { return fuse_main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_fuse_fuse_main=yes else ac_cv_lib_fuse_fuse_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fuse_fuse_main" >&5 $as_echo "$ac_cv_lib_fuse_fuse_main" >&6; } if test "x$ac_cv_lib_fuse_fuse_main" = xyes; then : LIBFUSE="-lfuse" $as_echo "#define HAVE_LIBFUSE 1" >>confdefs.h HAVE_LIBFUSE=1 # look for fuse_getgroups and define FUSE_GETGROUPS if found LIBS_saved="$LIBS" LIBS="$LIBS -lfuse" for ac_func in fuse_getgroups do : ac_fn_c_check_func "$LINENO" "fuse_getgroups" "ac_cv_func_fuse_getgroups" if test "x$ac_cv_func_fuse_getgroups" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FUSE_GETGROUPS 1 _ACEOF fi done LIBS="$LIBS_saved" else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no FUSE found (use --without-fuse to disable) See \`config.log' for more details" "$LINENO" 5; } fi fi if test "$HAVE_LIBFUSE" = "1"; then WITH_FUSE_TRUE= WITH_FUSE_FALSE='#' else WITH_FUSE_TRUE='#' WITH_FUSE_FALSE= fi # tcmalloc? # Check whether --with-tcmalloc was given. if test "${with_tcmalloc+set}" = set; then : withval=$with_tcmalloc; else with_tcmalloc=yes fi TCMALLOC= if test "x$with_tcmalloc" != xno; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for malloc in -ltcmalloc" >&5 $as_echo_n "checking for malloc in -ltcmalloc... " >&6; } if ${ac_cv_lib_tcmalloc_malloc+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ltcmalloc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char malloc (); int main () { return malloc (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_tcmalloc_malloc=yes else ac_cv_lib_tcmalloc_malloc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tcmalloc_malloc" >&5 $as_echo "$ac_cv_lib_tcmalloc_malloc" >&6; } if test "x$ac_cv_lib_tcmalloc_malloc" = xyes; then : LIBTCMALLOC="-ltcmalloc" $as_echo "#define HAVE_LIBTCMALLOC 1" >>confdefs.h HAVE_LIBTCMALLOC=1 else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no tcmalloc found (use --without-tcmalloc to disable) See \`config.log' for more details" "$LINENO" 5; } fi fi if test "$HAVE_LIBTCMALLOC" = "1"; then WITH_TCMALLOC_TRUE= WITH_TCMALLOC_FALSE='#' else WITH_TCMALLOC_TRUE='#' WITH_TCMALLOC_FALSE= fi #set pg ref debugging? # Check whether --enable-pgrefdebugging was given. if test "${enable_pgrefdebugging+set}" = set; then : enableval=$enable_pgrefdebugging; $as_echo "#define PG_DEBUG_REFS 1" >>confdefs.h fi # # Java is painful # - adapted from OMPI wrappers package # - this might become bigger. maybe should be own m4 file # # Check whether --enable-cephfs-java was given. if test "${enable_cephfs_java+set}" = set; then : enableval=$enable_cephfs_java; else enable_cephfs_java=no fi if test "x$enable_cephfs_java" = "xyes"; then ENABLE_CEPHFS_JAVA_TRUE= ENABLE_CEPHFS_JAVA_FALSE='#' else ENABLE_CEPHFS_JAVA_TRUE='#' ENABLE_CEPHFS_JAVA_FALSE= fi # Check whether --with-jdk-dir was given. if test "${with_jdk_dir+set}" = set; then : withval=$with_jdk_dir; fi if test "x$enable_cephfs_java" = "xyes"; then # setup bin/include dirs from --with-jdk-dir (search for jni.h, javac) if test -n "$with_jdk_dir"; then : javac_prog=`find $with_jdk_dir/ -name javac | head -n 1` if test -x "$javac_prog"; then : EXTRA_JDK_BIN_DIR=`dirname $javac_prog` fi jnih=`find $with_jdk_dir/ -name jni.h | head -n 1` if test -r "$jnih"; then : EXTRA_JDK_INC_DIR=`dirname $jnih` fi fi # setup defaults for Debian default-jdk package (without --with-jdk-dir) if test -z "$with_jdk_dir"; then : # This works with Debian's and CentOS' default-jdk package for dir in '/usr/lib/jvm/default-java/' '/usr/lib/jvm/java/' '/usr/lib/jvm/java-gcj/'; do # only test if a suitable path has not yet been found if test "$EXTRA_JDK_BIN_DIR" == ""; then : if test -x "$javac_prog"; then : EXTRA_JDK_BIN_DIR=`dirname $javac_prog` fi jnih=`find $dir -name jni.h | head -n 1` if test -r "$jnih"; then : EXTRA_JDK_INC_DIR=`dirname $jnih` fi fi done fi # cephfs_java_test only makes sense if java is already turned on # setup CLASSPATH for Debian default junit4.jar package # # Configuring --with-debug and --enable-cephfs-java will throw an error if # JUnit4 cannot be found. While currently this works for users who have # installed via the package manager on Ubuntu, we need to expand this # check to 1 support other distrubtions and 2 allow users to influence # the search path. if test "x$with_debug" = "xyes"; then : dir='/usr/share/java' junit4_jar=`find $dir -name junit4.jar | head -n 1` if test -r "$junit4_jar"; then : EXTRA_CLASSPATH_JAR=`dirname $junit4_jar`/junit4.jar have_junit4=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: Cannot find junit4.jar (apt-get install junit4)" >&5 $as_echo "$as_me: Cannot find junit4.jar (apt-get install junit4)" >&6;} have_junit4=0 fi fi if test "x$CLASSPATH" = x; then echo "You have no CLASSPATH, I hope it is good" else echo "You have CLASSPATH $CLASSPATH, hope it is correct" fi if test "x$JAVAPREFIX" = x; then test "x$JAVAC" = x && for ac_prog in javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAVAC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAVAC"; then ac_cv_prog_JAVAC="$JAVAC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAVAC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAVAC=$ac_cv_prog_JAVAC if test -n "$JAVAC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5 $as_echo "$JAVAC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAVAC" && break done else test "x$JAVAC" = x && for ac_prog in javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAVAC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAVAC"; then ac_cv_prog_JAVAC="$JAVAC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAVAC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAVAC=$ac_cv_prog_JAVAC if test -n "$JAVAC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5 $as_echo "$JAVAC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAVAC" && break done test -n "$JAVAC" || JAVAC="$JAVAPREFIX" fi test "x$JAVAC" = x && as_fn_error $? "no acceptable Java compiler found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $JAVAC works" >&5 $as_echo_n "checking if $JAVAC works... " >&6; } if ${ac_cv_prog_javac_works+:} false; then : $as_echo_n "(cached) " >&6 else JAVA_TEST=Test.java CLASS_TEST=Test.class cat << \EOF > $JAVA_TEST /* #line 19193 "configure" */ public class Test { } EOF if { ac_try='$JAVAC $JAVACFLAGS $JAVA_TEST' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } >/dev/null 2>&1; then ac_cv_prog_javac_works=yes else as_fn_error $? "The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)" "$LINENO" 5 echo "configure: failed program was:" >&5 cat $JAVA_TEST >&5 fi rm -f $JAVA_TEST $CLASS_TEST fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_javac_works" >&5 $as_echo "$ac_cv_prog_javac_works" >&6; } # Extract the first word of "javah", so it can be a program name with args. set dummy javah; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_JAVAH+:} false; then : $as_echo_n "(cached) " >&6 else case $JAVAH in [\\/]* | ?:[\\/]*) ac_cv_path_JAVAH="$JAVAH" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_JAVAH="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi JAVAH=$ac_cv_path_JAVAH if test -n "$JAVAH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAH" >&5 $as_echo "$JAVAH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"`eval 'echo $ac_cv_path_JAVAH'`" != x ; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else ac_save_CPPFLAGS="$CPPFLAGS" ac_dir=`echo $ac_cv_path_JAVAH | sed 's,\(.*\)/[^/]*/[^/]*$,\1/include,'` ac_machdep=`echo $build_os | sed 's,[-0-9].*,,' | sed 's,cygwin,win32,'` CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_save_CPPFLAGS="$CPPFLAGS" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to include " >&5 $as_echo "$as_me: WARNING: unable to include " >&2;} fi rm -f conftest.err conftest.i conftest.$ac_ext CPPFLAGS="$ac_save_CPPFLAGS" fi rm -f conftest.err conftest.i conftest.$ac_ext fi if test "x$JAVAPREFIX" = x; then test "x$JAR" = x && for ac_prog in jar$EXEEXT do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAR"; then ac_cv_prog_JAR="$JAR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAR=$ac_cv_prog_JAR if test -n "$JAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAR" >&5 $as_echo "$JAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAR" && break done else test "x$JAR" = x && for ac_prog in jar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAR"; then ac_cv_prog_JAR="$JAR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAR=$ac_cv_prog_JAR if test -n "$JAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAR" >&5 $as_echo "$JAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAR" && break done test -n "$JAR" || JAR="$JAVAPREFIX" fi test "x$JAR" = x && as_fn_error $? "no acceptable jar program found in \$PATH" "$LINENO" 5 CLASSPATH=$CLASSPATH:$EXTRA_CLASSPATH_JAR export CLASSPATH { $as_echo "$as_me:${as_lineno-$LINENO}: classpath - $CLASSPATH" >&5 $as_echo "$as_me: classpath - $CLASSPATH" >&6;} # Check for jni.h CPPFLAGS_save=$CPPFLAGS if test -n "$EXTRA_JDK_INC_DIR"; then : JDK_CPPFLAGS="-I$EXTRA_JDK_INC_DIR" if test -d "$EXTRA_JDK_INC_DIR/linux"; then : JDK_CPPFLAGS="$JDK_CPPFLAGS -I$EXTRA_JDK_INC_DIR/linux" fi CPPFLAGS="$CPPFLAGS $JDK_CPPFLAGS" fi ac_fn_c_check_header_mongrel "$LINENO" "jni.h" "ac_cv_header_jni_h" "$ac_includes_default" if test "x$ac_cv_header_jni_h" = xyes; then : else as_fn_error $? "Cannot find header 'jni.h'. Try setting --with-jdk-dir" "$LINENO" 5 fi CPPFLAGS=$CPPFLAGS_save # Setup output var fi if test "$have_junit4" = "1"; then HAVE_JUNIT4_TRUE= HAVE_JUNIT4_FALSE='#' else HAVE_JUNIT4_TRUE='#' HAVE_JUNIT4_FALSE= fi # # FreeBSD has it in base. # if test x"$freebsd" != x"yes"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5 $as_echo_n "checking for LIBEDIT... " >&6; } if test -n "$LIBEDIT_CFLAGS"; then pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit >= 2.11\""; } >&5 ($PKG_CONFIG --exists --print-errors "libedit >= 2.11") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEDIT_CFLAGS=`$PKG_CONFIG --cflags "libedit >= 2.11" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBEDIT_LIBS"; then pkg_cv_LIBEDIT_LIBS="$LIBEDIT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit >= 2.11\""; } >&5 ($PKG_CONFIG --exists --print-errors "libedit >= 2.11") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEDIT_LIBS=`$PKG_CONFIG --libs "libedit >= 2.11" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libedit >= 2.11" 2>&1` else LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libedit >= 2.11" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBEDIT_PKG_ERRORS" >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "No usable version of libedit found. See \`config.log' for more details" "$LINENO" 5; } elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "No usable version of libedit found. See \`config.log' for more details" "$LINENO" 5; } else LIBEDIT_CFLAGS=$pkg_cv_LIBEDIT_CFLAGS LIBEDIT_LIBS=$pkg_cv_LIBEDIT_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi else LIBEDIT_LIBS="-ledit" fi #libatomic-ops? You want it! # Check whether --with-libatomic-ops was given. if test "${with_libatomic_ops+set}" = set; then : withval=$with_libatomic_ops; else with_libatomic_ops=yes fi if test "x$with_libatomic_ops" != xno; then : ac_fn_c_check_header_mongrel "$LINENO" "atomic_ops.h" "ac_cv_header_atomic_ops_h" "$ac_includes_default" if test "x$ac_cv_header_atomic_ops_h" = xyes; then : HAVE_ATOMIC_OPS=1 else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no libatomic-ops found (use --without-libatomic-ops to disable) See \`config.log' for more details" "$LINENO" 5; } fi fi if test "$HAVE_ATOMIC_OPS" = "1"; then : # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of AO_t" >&5 $as_echo_n "checking size of AO_t... " >&6; } if ${ac_cv_sizeof_AO_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (AO_t))" "ac_cv_sizeof_AO_t" " #include "; then : else if test "$ac_cv_type_AO_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (AO_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_AO_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_AO_t" >&5 $as_echo "$ac_cv_sizeof_AO_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_AO_T $ac_cv_sizeof_AO_t _ACEOF else $as_echo "#define NO_ATOMIC_OPS 1" >>confdefs.h fi if test "$HAVE_ATOMIC_OPS" = "1"; then WITH_LIBATOMIC_TRUE= WITH_LIBATOMIC_FALSE='#' else WITH_LIBATOMIC_TRUE='#' WITH_LIBATOMIC_FALSE= fi # newsyn? requires mpi. #AC_ARG_WITH([newsyn], # [AS_HELP_STRING([--with-newsyn], [build newsyn target requires mpi])], # [], # [with_newsyn=no]) # Check whether --with-ocf was given. if test "${with_ocf+set}" = set; then : withval=$with_ocf; else with_ocf=no fi if test "$with_ocf" = "yes" ; then WITH_OCF_TRUE= WITH_OCF_FALSE='#' else WITH_OCF_TRUE='#' WITH_OCF_FALSE= fi # check is snappy-devel is installed, needed by leveldb { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snappy_compress in -lsnappy" >&5 $as_echo_n "checking for snappy_compress in -lsnappy... " >&6; } if ${ac_cv_lib_snappy_snappy_compress+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsnappy $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char snappy_compress (); int main () { return snappy_compress (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_snappy_snappy_compress=yes else ac_cv_lib_snappy_snappy_compress=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_snappy_snappy_compress" >&5 $as_echo "$ac_cv_lib_snappy_snappy_compress" >&6; } if test "x$ac_cv_lib_snappy_snappy_compress" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libsnappy not found See \`config.log' for more details" "$LINENO" 5; } fi # use system leveldb { $as_echo "$as_me:${as_lineno-$LINENO}: checking for leveldb_open in -lleveldb" >&5 $as_echo_n "checking for leveldb_open in -lleveldb... " >&6; } if ${ac_cv_lib_leveldb_leveldb_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lleveldb -lsnappy -lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char leveldb_open (); int main () { return leveldb_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_leveldb_leveldb_open=yes else ac_cv_lib_leveldb_leveldb_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_leveldb_leveldb_open" >&5 $as_echo "$ac_cv_lib_leveldb_leveldb_open" >&6; } if test "x$ac_cv_lib_leveldb_leveldb_open" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libleveldb not found See \`config.log' for more details" "$LINENO" 5; } fi # see if we can use bloom filters with leveldb ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_fn_cxx_check_header_mongrel "$LINENO" "leveldb/filter_policy.h" "ac_cv_header_leveldb_filter_policy_h" "$ac_includes_default" if test "x$ac_cv_header_leveldb_filter_policy_h" = xyes; then : $as_echo "#define HAVE_LEVELDB_FILTER_POLICY 1" >>confdefs.h fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find supported SIMD / SSE extensions supported by the compiler case $target_cpu in i[3456]86*|x86_64*|amd64*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse" >&5 $as_echo_n "checking whether C compiler accepts -msse... " >&6; } if ${ax_cv_check_cflags___msse+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -msse" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___msse=yes else ax_cv_check_cflags___msse=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___msse" >&5 $as_echo "$ax_cv_check_cflags___msse" >&6; } if test x"$ax_cv_check_cflags___msse" = xyes; then : ax_cv_support_sse_ext=yes else : fi if test x"$ax_cv_support_sse_ext" = x"yes"; then INTEL_SSE_FLAGS="-msse -DINTEL_SSE" INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE_FLAGS" $as_echo "#define HAVE_SSE /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse2" >&5 $as_echo_n "checking whether C compiler accepts -msse2... " >&6; } if ${ax_cv_check_cflags___msse2+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -msse2" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___msse2=yes else ax_cv_check_cflags___msse2=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___msse2" >&5 $as_echo "$ax_cv_check_cflags___msse2" >&6; } if test x"$ax_cv_check_cflags___msse2" = xyes; then : ax_cv_support_sse2_ext=yes else : fi if test x"$ax_cv_support_sse2_ext" = x"yes"; then INTEL_SSE2_FLAGS="-msse2 -DINTEL_SSE2" INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE2_FLAGS" $as_echo "#define HAVE_SSE2 /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse3" >&5 $as_echo_n "checking whether C compiler accepts -msse3... " >&6; } if ${ax_cv_check_cflags___msse3+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -msse3" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___msse3=yes else ax_cv_check_cflags___msse3=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___msse3" >&5 $as_echo "$ax_cv_check_cflags___msse3" >&6; } if test x"$ax_cv_check_cflags___msse3" = xyes; then : ax_cv_support_sse3_ext=yes else : fi if test x"$ax_cv_support_sse3_ext" = x"yes"; then INTEL_SSE3_FLAGS="-msse3 -DINTEL_SSE3" INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE3_FLAGS" $as_echo "#define HAVE_SSE3 /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -mssse3" >&5 $as_echo_n "checking whether C compiler accepts -mssse3... " >&6; } if ${ax_cv_check_cflags___mssse3+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -mssse3" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___mssse3=yes else ax_cv_check_cflags___mssse3=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___mssse3" >&5 $as_echo "$ax_cv_check_cflags___mssse3" >&6; } if test x"$ax_cv_check_cflags___mssse3" = xyes; then : ax_cv_support_ssse3_ext=yes else : fi if test x"$ax_cv_support_ssse3_ext" = x"yes"; then INTEL_SSSE3_FLAGS="-mssse3 -DINTEL_SSSE3" INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSSE3_FLAGS" $as_echo "#define HAVE_SSSE3 /**/" >>confdefs.h fi ;; esac case $target_cpu in x86_64*|amd64*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -mpclmul" >&5 $as_echo_n "checking whether C compiler accepts -mpclmul... " >&6; } if ${ax_cv_check_cflags___mpclmul+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -mpclmul" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___mpclmul=yes else ax_cv_check_cflags___mpclmul=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___mpclmul" >&5 $as_echo "$ax_cv_check_cflags___mpclmul" >&6; } if test x"$ax_cv_check_cflags___mpclmul" = xyes; then : ax_cv_support_pclmuldq_ext=yes else : fi if test x"$ax_cv_support_pclmuldq_ext" = x"yes"; then INTEL_PCLMUL_FLAGS="-mpclmul -DINTEL_SSE4_PCLMUL" INTEL_FLAGS="$INTEL_FLAGS $INTEL_PCLMUL_FLAGS" $as_echo "#define HAVE_PCLMUL /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse4.1" >&5 $as_echo_n "checking whether C compiler accepts -msse4.1... " >&6; } if ${ax_cv_check_cflags___msse4_1+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -msse4.1" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___msse4_1=yes else ax_cv_check_cflags___msse4_1=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___msse4_1" >&5 $as_echo "$ax_cv_check_cflags___msse4_1" >&6; } if test x"$ax_cv_check_cflags___msse4_1" = xyes; then : ax_cv_support_sse41_ext=yes else : fi if test x"$ax_cv_support_sse41_ext" = x"yes"; then INTEL_SSE4_1_FLAGS="-msse4.1 -DINTEL_SSE4" INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE4_1_FLAGS" $as_echo "#define HAVE_SSE4_1 /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse4.2" >&5 $as_echo_n "checking whether C compiler accepts -msse4.2... " >&6; } if ${ax_cv_check_cflags___msse4_2+:} false; then : $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -msse4.2" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ax_cv_check_cflags___msse4_2=yes else ax_cv_check_cflags___msse4_2=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___msse4_2" >&5 $as_echo "$ax_cv_check_cflags___msse4_2" >&6; } if test x"$ax_cv_check_cflags___msse4_2" = xyes; then : ax_cv_support_sse42_ext=yes else : fi if test x"$ax_cv_support_sse42_ext" = x"yes"; then INTEL_SSE4_2_FLAGS="-msse4.2 -DINTEL_SSE4" INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE4_2_FLAGS" $as_echo "#define HAVE_SSE4_2 /**/" >>confdefs.h fi ;; esac # use system libs3? # Check whether --with-system-libs3 was given. if test "${with_system_libs3+set}" = set; then : withval=$with_system_libs3; else with_system_libs3=no fi if test "x$with_system_libs3" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for S3_initialize in -ls3" >&5 $as_echo_n "checking for S3_initialize in -ls3... " >&6; } if ${ac_cv_lib_s3_S3_initialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ls3 -lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char S3_initialize (); int main () { return S3_initialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_s3_S3_initialize=yes else ac_cv_lib_s3_S3_initialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_s3_S3_initialize" >&5 $as_echo "$ac_cv_lib_s3_S3_initialize" >&6; } if test "x$ac_cv_lib_s3_S3_initialize" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libs3 not found See \`config.log' for more details" "$LINENO" 5; } fi fi if test "x$with_system_libs3" = xcheck; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing S3_initialize" >&5 $as_echo_n "checking for library containing S3_initialize... " >&6; } if ${ac_cv_search_S3_initialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char S3_initialize (); int main () { return S3_initialize (); ; return 0; } _ACEOF for ac_lib in '' s3; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib -lpthread $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_S3_initialize=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_S3_initialize+:} false; then : break fi done if ${ac_cv_search_S3_initialize+:} false; then : else ac_cv_search_S3_initialize=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_S3_initialize" >&5 $as_echo "$ac_cv_search_S3_initialize" >&6; } ac_res=$ac_cv_search_S3_initialize if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" with_system_libs3=yes else true fi fi if test "$with_system_libs3" = "yes" ; then WITH_SYSTEM_LIBS3_TRUE= WITH_SYSTEM_LIBS3_FALSE='#' else WITH_SYSTEM_LIBS3_TRUE='#' WITH_SYSTEM_LIBS3_FALSE= fi # rest-bench? # Check whether --with-rest-bench was given. if test "${with_rest_bench+set}" = set; then : withval=$with_rest_bench; else with_rest_bench=no fi if test "$with_rest_bench" = "yes" ; then WITH_REST_BENCH_TRUE= WITH_REST_BENCH_FALSE='#' else WITH_REST_BENCH_TRUE='#' WITH_REST_BENCH_FALSE= fi # use libaio? # Check whether --with-libaio was given. if test "${with_libaio+set}" = set; then : withval=$with_libaio; else with_libaio=yes fi if test "x$with_libaio" != xno; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for io_submit in -laio" >&5 $as_echo_n "checking for io_submit in -laio... " >&6; } if ${ac_cv_lib_aio_io_submit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-laio $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char io_submit (); int main () { return io_submit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_aio_io_submit=yes else ac_cv_lib_aio_io_submit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aio_io_submit" >&5 $as_echo "$ac_cv_lib_aio_io_submit" >&6; } if test "x$ac_cv_lib_aio_io_submit" = xyes; then : true else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libaio not found See \`config.log' for more details" "$LINENO" 5; } fi fi if test "x$with_libaio" != xno; then : ac_fn_c_check_header_mongrel "$LINENO" "libaio.h" "ac_cv_header_libaio_h" "$ac_includes_default" if test "x$ac_cv_header_libaio_h" = xyes; then : fi fi if test "$with_libaio" = "yes"; then : $as_echo "#define HAVE_LIBAIO 1" >>confdefs.h fi if test "$with_libaio" = "yes" ; then WITH_LIBAIO_TRUE= WITH_LIBAIO_FALSE='#' else WITH_LIBAIO_TRUE='#' WITH_LIBAIO_FALSE= fi # use libxfs? # Check whether --with-libxfs was given. if test "${with_libxfs+set}" = set; then : withval=$with_libxfs; else with_libxfs=yes fi if test "x$with_libxfs" != "xno"; then : # xfs/xfs.h presence and XFS_XFLAG_EXTSIZE define ac_fn_c_check_header_mongrel "$LINENO" "xfs/xfs.h" "ac_cv_header_xfs_xfs_h" "$ac_includes_default" if test "x$ac_cv_header_xfs_xfs_h" = xyes; then : else as_fn_error $? "xfs/xfs.h not found (--without-libxfs to disable)" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XFS_XFLAG_EXTSIZE in xfs/xfs.h" >&5 $as_echo_n "checking for XFS_XFLAG_EXTSIZE in xfs/xfs.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef XFS_XFLAG_EXTSIZE yes_have_xfs_xflag_extsize #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes_have_xfs_xflag_extsize" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBXFS 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "XFS_XFLAG_EXTSIZE not found (--without-libxfs to disable)" "$LINENO" 5 fi rm -f conftest* fi if test "x$with_libxfs" != "xno"; then WITH_LIBXFS_TRUE= WITH_LIBXFS_FALSE='#' else WITH_LIBXFS_TRUE='#' WITH_LIBXFS_FALSE= fi # use libzfs # Check whether --with-libzfs was given. if test "${with_libzfs+set}" = set; then : withval=$with_libzfs; else with_libzfs=no fi if test "x$with_libzfs" = xyes; then : pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBZFS" >&5 $as_echo_n "checking for LIBZFS... " >&6; } if test -n "$LIBZFS_CFLAGS"; then pkg_cv_LIBZFS_CFLAGS="$LIBZFS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zfs\""; } >&5 ($PKG_CONFIG --exists --print-errors "zfs") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBZFS_CFLAGS=`$PKG_CONFIG --cflags "zfs" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBZFS_LIBS"; then pkg_cv_LIBZFS_LIBS="$LIBZFS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zfs\""; } >&5 ($PKG_CONFIG --exists --print-errors "zfs") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBZFS_LIBS=`$PKG_CONFIG --libs "zfs" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBZFS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zfs" 2>&1` else LIBZFS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zfs" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBZFS_PKG_ERRORS" >&5 true elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } true else LIBZFS_CFLAGS=$pkg_cv_LIBZFS_CFLAGS LIBZFS_LIBS=$pkg_cv_LIBZFS_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi if test "x$with_libzfs" = xyes; then : $as_echo "#define HAVE_LIBZFS 1" >>confdefs.h fi if test "$with_libzfs" = "yes" ; then WITH_LIBZFS_TRUE= WITH_LIBZFS_FALSE='#' else WITH_LIBZFS_TRUE='#' WITH_LIBZFS_FALSE= fi # Checks for header files. ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi # spirit? ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_fn_cxx_check_header_mongrel "$LINENO" "boost/spirit/include/classic_core.hpp" "ac_cv_header_boost_spirit_include_classic_core_hpp" "$ac_includes_default" if test "x$ac_cv_header_boost_spirit_include_classic_core_hpp" = xyes; then : else ac_fn_cxx_check_header_mongrel "$LINENO" "boost/spirit.hpp" "ac_cv_header_boost_spirit_hpp" "$ac_includes_default" if test "x$ac_cv_header_boost_spirit_hpp" = xyes; then : use_bspirit_old_hdr=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "\"Can't find boost spirit headers\" See \`config.log' for more details" "$LINENO" 5; } fi fi if test "$use_bspirit_old_hdr" = "yes"; then USE_BOOST_SPIRIT_OLD_HDR_TRUE= USE_BOOST_SPIRIT_OLD_HDR_FALSE='#' else USE_BOOST_SPIRIT_OLD_HDR_TRUE='#' USE_BOOST_SPIRIT_OLD_HDR_FALSE= fi ac_fn_cxx_check_header_mongrel "$LINENO" "boost/random/discrete_distribution.hpp" "ac_cv_header_boost_random_discrete_distribution_hpp" "$ac_includes_default" if test "x$ac_cv_header_boost_random_discrete_distribution_hpp" = xyes; then : $as_echo "#define HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION /**/" >>confdefs.h fi ac_fn_cxx_check_header_mongrel "$LINENO" "boost/statechart/state.hpp" "ac_cv_header_boost_statechart_state_hpp" "$ac_includes_default" if test "x$ac_cv_header_boost_statechart_state_hpp" = xyes; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "\"Can't find boost statechart headers; need 1.34 or later\" See \`config.log' for more details" "$LINENO" 5; } fi ac_fn_cxx_check_header_mongrel "$LINENO" "boost/program_options/option.hpp" "ac_cv_header_boost_program_options_option_hpp" "$ac_includes_default" if test "x$ac_cv_header_boost_program_options_option_hpp" = xyes; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "\"Can't find boost program_options headers\" See \`config.log' for more details" "$LINENO" 5; } fi # If we have the boost system library installed, then we may want to link # with it. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lboost_system-mt" >&5 $as_echo_n "checking for main in -lboost_system-mt... " >&6; } if ${ac_cv_lib_boost_system_mt_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_system-mt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_boost_system_mt_main=yes else ac_cv_lib_boost_system_mt_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_system_mt_main" >&5 $as_echo "$ac_cv_lib_boost_system_mt_main" >&6; } if test "x$ac_cv_lib_boost_system_mt_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBOOST_SYSTEM_MT 1 _ACEOF LIBS="-lboost_system-mt $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lboost_system" >&5 $as_echo_n "checking for main in -lboost_system... " >&6; } if ${ac_cv_lib_boost_system_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_system $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_boost_system_main=yes else ac_cv_lib_boost_system_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_system_main" >&5 $as_echo "$ac_cv_lib_boost_system_main" >&6; } if test "x$ac_cv_lib_boost_system_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBOOST_SYSTEM 1 _ACEOF LIBS="-lboost_system $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: \"Boost system library not found.\"" >&5 $as_echo "$as_me: \"Boost system library not found.\"" >&6;} fi fi # Find the right boost_thread library. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lboost_thread-mt" >&5 $as_echo_n "checking for main in -lboost_thread-mt... " >&6; } if ${ac_cv_lib_boost_thread_mt_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_thread-mt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_boost_thread_mt_main=yes else ac_cv_lib_boost_thread_mt_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_thread_mt_main" >&5 $as_echo "$ac_cv_lib_boost_thread_mt_main" >&6; } if test "x$ac_cv_lib_boost_thread_mt_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBOOST_THREAD_MT 1 _ACEOF LIBS="-lboost_thread-mt $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lboost_thread" >&5 $as_echo_n "checking for main in -lboost_thread... " >&6; } if ${ac_cv_lib_boost_thread_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_thread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_boost_thread_main=yes else ac_cv_lib_boost_thread_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_thread_main" >&5 $as_echo "$ac_cv_lib_boost_thread_main" >&6; } if test "x$ac_cv_lib_boost_thread_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBOOST_THREAD 1 _ACEOF LIBS="-lboost_thread $LIBS" else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "\"Boost thread library not found.\" See \`config.log' for more details" "$LINENO" 5; } fi fi # # Check for boost_program_options library (defines BOOST_PROGRAM_OPTIONS_LIBS). # BOOST_PROGRAM_OPTIONS_LIBS="" saved_LIBS="${LIBS}" LIBS="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lboost_program_options-mt" >&5 $as_echo_n "checking for main in -lboost_program_options-mt... " >&6; } if ${ac_cv_lib_boost_program_options_mt_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_program_options-mt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_boost_program_options_mt_main=yes else ac_cv_lib_boost_program_options_mt_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_program_options_mt_main" >&5 $as_echo "$ac_cv_lib_boost_program_options_mt_main" >&6; } if test "x$ac_cv_lib_boost_program_options_mt_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBOOST_PROGRAM_OPTIONS_MT 1 _ACEOF LIBS="-lboost_program_options-mt $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lboost_program_options" >&5 $as_echo_n "checking for main in -lboost_program_options... " >&6; } if ${ac_cv_lib_boost_program_options_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_program_options $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_boost_program_options_main=yes else ac_cv_lib_boost_program_options_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_program_options_main" >&5 $as_echo "$ac_cv_lib_boost_program_options_main" >&6; } if test "x$ac_cv_lib_boost_program_options_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBOOST_PROGRAM_OPTIONS 1 _ACEOF LIBS="-lboost_program_options $LIBS" else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "\"Boost program options library not found.\" See \`config.log' for more details" "$LINENO" 5; } fi fi BOOST_PROGRAM_OPTIONS_LIBS="${LIBS}" LIBS="${saved_LIBS}" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_fn_c_check_member "$LINENO" "struct fiemap_extent" "fe_logical" "ac_cv_member_struct_fiemap_extent_fe_logical" "#include " if test "x$ac_cv_member_struct_fiemap_extent_fe_logical" = xyes; then : $as_echo "#define HAVE_FIEMAP_H /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: linux/fiemap.h was not found or not usable; using local Ceph copy" >&5 $as_echo "$as_me: linux/fiemap.h was not found or not usable; using local Ceph copy" >&6;} fi for ac_header in \ arpa/inet.h \ arpa/nameser_compat.h \ linux/version.h \ netdb.h \ netinet/in.h \ sys/file.h \ sys/ioctl.h \ sys/mount.h \ sys/param.h \ sys/socket.h \ sys/statvfs.h \ sys/time.h \ sys/vfs.h \ sys/xattr.h \ syslog.h \ utime.h \ do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # sync_file_range ac_fn_c_check_func "$LINENO" "sync_file_range" "ac_cv_func_sync_file_range" if test "x$ac_cv_func_sync_file_range" = xyes; then : $as_echo "#define HAVE_SYNC_FILE_RANGE /**/" >>confdefs.h fi # fallocate ac_fn_c_check_func "$LINENO" "fallocate" "ac_cv_func_fallocate" if test "x$ac_cv_func_fallocate" = xyes; then : $as_echo "#define CEPH_HAVE_FALLOCATE /**/" >>confdefs.h fi # # Test for time-related `struct stat` members. # ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes; then : $as_echo "#define HAVE_STAT_ST_MTIM_TV_NSEC 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimespec.tv_nsec" "ac_cv_member_struct_stat_st_mtimespec_tv_nsec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtimespec_tv_nsec" = xyes; then : $as_echo "#define HAVE_STAT_ST_MTIMESPEC_TV_NSEC 1" >>confdefs.h fi # splice/tee ac_fn_c_check_func "$LINENO" "splice" "ac_cv_func_splice" if test "x$ac_cv_func_splice" = xyes; then : $as_echo "#define CEPH_HAVE_SPLICE /**/" >>confdefs.h fi # F_SETPIPE_SZ in fcntl.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for F_SETPIPE_SZ in fcntl.h" >&5 $as_echo_n "checking for F_SETPIPE_SZ in fcntl.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include #ifdef F_SETPIPE_SZ yes_have_f_setpipe_sz #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes_have_f_setpipe_sz" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define CEPH_HAVE_SETPIPE_SZ /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: F_SETPIPE_SZ not found, zero-copy may be less efficent" >&5 $as_echo "$as_me: F_SETPIPE_SZ not found, zero-copy may be less efficent" >&6;} fi rm -f conftest* for ac_func in posix_fallocate do : ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate" if test "x$ac_cv_func_posix_fallocate" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSIX_FALLOCATE 1 _ACEOF fi done for ac_header in sys/prctl.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_prctl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PRCTL_H 1 _ACEOF fi done for ac_func in prctl do : ac_fn_c_check_func "$LINENO" "prctl" "ac_cv_func_prctl" if test "x$ac_cv_func_prctl" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PRCTL 1 _ACEOF fi done for ac_func in pipe2 do : ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" if test "x$ac_cv_func_pipe2" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PIPE2 1 _ACEOF fi done for ac_func in posix_fadvise do : ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" if test "x$ac_cv_func_posix_fadvise" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSIX_FADVISE 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fdatasync" >&5 $as_echo_n "checking for fdatasync... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 return fdatasync(0); #else #error Not supported #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_FDATASYNC 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # # Check for pthread spinlock (depends on ACX_PTHREAD) # saved_LIBS="$LIBS" saved_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$PTHREAD_CFLAGS $CFLAGS" ac_fn_c_check_func "$LINENO" "pthread_spin_init" "ac_cv_func_pthread_spin_init" if test "x$ac_cv_func_pthread_spin_init" = xyes; then : $as_echo "#define HAVE_PTHREAD_SPINLOCK 1" >>confdefs.h fi LIBS="$saved_LIBS" CFLAGS="$saved_CFLAGS" ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default" if test "x$ac_cv_type_int8_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT8_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default" if test "x$ac_cv_type_uint8_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT8_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default" if test "x$ac_cv_type_int16_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT16_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default" if test "x$ac_cv_type_uint16_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT16_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default" if test "x$ac_cv_type_int32_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT32_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default" if test "x$ac_cv_type_uint32_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT32_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default" if test "x$ac_cv_type_int64_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT64_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default" if test "x$ac_cv_type_uint64_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT64_T 1 _ACEOF fi for ac_header in linux/types.h do : ac_fn_c_check_header_mongrel "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" if test "x$ac_cv_header_linux_types_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_TYPES_H 1 _ACEOF fi done ac_fn_c_check_type "$LINENO" "__u8" "ac_cv_type___u8" "#include " if test "x$ac_cv_type___u8" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___U8 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__s8" "ac_cv_type___s8" "#include " if test "x$ac_cv_type___s8" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___S8 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__u16" "ac_cv_type___u16" "#include " if test "x$ac_cv_type___u16" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___U16 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__s16" "ac_cv_type___s16" "#include " if test "x$ac_cv_type___s16" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___S16 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__u32" "ac_cv_type___u32" "#include " if test "x$ac_cv_type___u32" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___U32 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__s32" "ac_cv_type___s32" "#include " if test "x$ac_cv_type___s32" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___S32 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__u64" "ac_cv_type___u64" "#include " if test "x$ac_cv_type___u64" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___U64 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__s64" "ac_cv_type___s64" "#include " if test "x$ac_cv_type___s64" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___S64 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__le16" "ac_cv_type___le16" "#include " if test "x$ac_cv_type___le16" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___LE16 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__be16" "ac_cv_type___be16" "#include " if test "x$ac_cv_type___be16" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___BE16 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__le32" "ac_cv_type___le32" "#include " if test "x$ac_cv_type___le32" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___LE32 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__be32" "ac_cv_type___be32" "#include " if test "x$ac_cv_type___be32" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___BE32 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__le64" "ac_cv_type___le64" "#include " if test "x$ac_cv_type___le64" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___LE64 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "__be64" "ac_cv_type___be64" "#include " if test "x$ac_cv_type___be64" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE___BE64 1 _ACEOF fi # Checks for typedefs, structures, and compiler characteristics. #AC_HEADER_STDBOOL #AC_C_CONST #AC_TYPE_UID_T #AC_C_INLINE #AC_TYPE_INT16_T #AC_TYPE_INT32_T #AC_TYPE_INT64_T #AC_TYPE_INT8_T #AC_TYPE_MODE_T #AC_TYPE_OFF_T #AC_TYPE_PID_T #AC_TYPE_SIZE_T #AC_TYPE_SSIZE_T #AC_CHECK_MEMBERS([struct stat.st_blksize]) #AC_STRUCT_ST_BLOCKS #AC_CHECK_MEMBERS([struct stat.st_rdev]) #AC_HEADER_TIME #AC_STRUCT_TM #AC_TYPE_UINT16_T #AC_TYPE_UINT32_T #AC_TYPE_UINT64_T #AC_TYPE_UINT8_T # Checks for library functions. #AC_FUNC_CHOWN #AC_FUNC_CLOSEDIR_VOID #AC_FUNC_ERROR_AT_LINE #AC_FUNC_FORK #AC_PROG_GCC_TRADITIONAL #AC_FUNC_LSTAT #AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK #AC_FUNC_MALLOC # this causes annoying rpl_malloc error on some machines; skip it #AC_FUNC_MEMCMP #AC_FUNC_MMAP #AC_FUNC_REALLOC #AC_FUNC_SELECT_ARGTYPES #AC_TYPE_SIGNAL #AC_FUNC_STAT #AC_FUNC_UTIME_NULL #AC_CHECK_FUNCS([bzero fchdir fdatasync floor ftruncate getcwd gethostbyname gethostname gettimeofday inet_ntoa localtime_r memmove memset mkdir munmap pow rmdir select socket sqrt strcasecmp strchr strerror strstr utime]) # check for return type (and presence) if strerror_r in C++ mode ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_fn_cxx_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" if test "x$ac_cv_have_decl_strerror_r" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_STRERROR_R $ac_have_decl _ACEOF for ac_func in strerror_r do : ac_fn_cxx_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" if test "x$ac_cv_func_strerror_r" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRERROR_R 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 $as_echo_n "checking whether strerror_r returns char *... " >&6; } if ${ac_cv_func_strerror_r_char_p+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_func_strerror_r_char_p=no if test $ac_cv_have_decl_strerror_r = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { char buf[100]; char x = *strerror_r (0, buf, sizeof buf); char *p = strerror_r (0, buf, sizeof buf); return !p || x; ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_func_strerror_r_char_p=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else # strerror_r is not declared. Choose between # systems that have relatively inaccessible declarations for the # function. BeOS and DEC UNIX 4.0 fall in this category, but the # former has a strerror_r that returns char*, while the latter # has a strerror_r that returns `int'. # This test should segfault on the DEC system. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default extern char *strerror_r (); int main () { char buf[100]; char x = *strerror_r (0, buf, sizeof buf); return ! isalpha (x); ; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : ac_cv_func_strerror_r_char_p=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 $as_echo "$ac_cv_func_strerror_r_char_p" >&6; } if test $ac_cv_func_strerror_r_char_p = yes; then $as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "$WITH_BUILD_TESTS" = "1"; then WITH_BUILD_TESTS_TRUE= WITH_BUILD_TESTS_FALSE='#' else WITH_BUILD_TESTS_TRUE='#' WITH_BUILD_TESTS_FALSE= fi if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 2.4" >&5 $as_echo_n "checking whether $PYTHON version is >= 2.4... " >&6; } prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.4'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 ($PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Python interpreter is too old" "$LINENO" 5 fi am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 2.4" >&5 $as_echo_n "checking for a Python interpreter with version >= 2.4... " >&6; } if ${am_cv_pathless_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else for am_cv_pathless_PYTHON in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do test "$am_cv_pathless_PYTHON" = none && break prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.4'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 $as_echo "$am_cv_pathless_PYTHON" >&6; } # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. set dummy $am_cv_pathless_PYTHON; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi am_display_PYTHON=$am_cv_pathless_PYTHON fi if test "$PYTHON" = :; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Failed to find Python 2.4 or newer See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 $as_echo_n "checking for $am_display_PYTHON version... " >&6; } if ${am_cv_python_version+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 $as_echo "$am_cv_python_version" >&6; } PYTHON_VERSION=$am_cv_python_version PYTHON_PREFIX='${prefix}' PYTHON_EXEC_PREFIX='${exec_prefix}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 $as_echo_n "checking for $am_display_PYTHON platform... " >&6; } if ${am_cv_python_platform+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 $as_echo "$am_cv_python_platform" >&6; } PYTHON_PLATFORM=$am_cv_python_platform # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[:3] == '2.7': can_use_sysconfig = 0 except ImportError: pass" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 $as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } if ${am_cv_python_pythondir+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 $as_echo "$am_cv_python_pythondir" >&6; } pythondir=$am_cv_python_pythondir pkgpythondir=\${pythondir}/$PACKAGE { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 $as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } if ${am_cv_python_pyexecdir+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 $as_echo "$am_cv_python_pyexecdir" >&6; } pyexecdir=$am_cv_python_pyexecdir pkgpyexecdir=\${pyexecdir}/$PACKAGE fi ac_config_headers="$ac_config_headers src/acconfig.h" ac_config_files="$ac_config_files Makefile src/Makefile src/ocf/Makefile src/ocf/ceph src/ocf/rbd src/java/Makefile man/Makefile ceph.spec" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCCAS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${LINUX_TRUE}" && test -z "${LINUX_FALSE}"; then as_fn_error $? "conditional \"LINUX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${FREEBSD_TRUE}" && test -z "${FREEBSD_FALSE}"; then as_fn_error $? "conditional \"FREEBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CLANG_TRUE}" && test -z "${CLANG_FALSE}"; then as_fn_error $? "conditional \"CLANG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_GOOD_YASM_ELF64_TRUE}" && test -z "${WITH_GOOD_YASM_ELF64_FALSE}"; then as_fn_error $? "conditional \"WITH_GOOD_YASM_ELF64\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_FPU_NEON_TRUE}" && test -z "${ENABLE_FPU_NEON_FALSE}"; then as_fn_error $? "conditional \"ENABLE_FPU_NEON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${COMPILER_HAS_VTA_TRUE}" && test -z "${COMPILER_HAS_VTA_FALSE}"; then as_fn_error $? "conditional \"COMPILER_HAS_VTA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_PROFILER_TRUE}" && test -z "${WITH_PROFILER_FALSE}"; then as_fn_error $? "conditional \"WITH_PROFILER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_DEBUG_TRUE}" && test -z "${WITH_DEBUG_FALSE}"; then as_fn_error $? "conditional \"WITH_DEBUG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_COVERAGE_TRUE}" && test -z "${ENABLE_COVERAGE_FALSE}"; then as_fn_error $? "conditional \"ENABLE_COVERAGE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_RADOSGW_TRUE}" && test -z "${WITH_RADOSGW_FALSE}"; then as_fn_error $? "conditional \"WITH_RADOSGW\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_FUSE_TRUE}" && test -z "${WITH_FUSE_FALSE}"; then as_fn_error $? "conditional \"WITH_FUSE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_TCMALLOC_TRUE}" && test -z "${WITH_TCMALLOC_FALSE}"; then as_fn_error $? "conditional \"WITH_TCMALLOC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_CEPHFS_JAVA_TRUE}" && test -z "${ENABLE_CEPHFS_JAVA_FALSE}"; then as_fn_error $? "conditional \"ENABLE_CEPHFS_JAVA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_JUNIT4_TRUE}" && test -z "${HAVE_JUNIT4_FALSE}"; then as_fn_error $? "conditional \"HAVE_JUNIT4\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_LIBATOMIC_TRUE}" && test -z "${WITH_LIBATOMIC_FALSE}"; then as_fn_error $? "conditional \"WITH_LIBATOMIC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_OCF_TRUE}" && test -z "${WITH_OCF_FALSE}"; then as_fn_error $? "conditional \"WITH_OCF\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_SYSTEM_LIBS3_TRUE}" && test -z "${WITH_SYSTEM_LIBS3_FALSE}"; then as_fn_error $? "conditional \"WITH_SYSTEM_LIBS3\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_REST_BENCH_TRUE}" && test -z "${WITH_REST_BENCH_FALSE}"; then as_fn_error $? "conditional \"WITH_REST_BENCH\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_LIBAIO_TRUE}" && test -z "${WITH_LIBAIO_FALSE}"; then as_fn_error $? "conditional \"WITH_LIBAIO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_LIBXFS_TRUE}" && test -z "${WITH_LIBXFS_FALSE}"; then as_fn_error $? "conditional \"WITH_LIBXFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_LIBZFS_TRUE}" && test -z "${WITH_LIBZFS_FALSE}"; then as_fn_error $? "conditional \"WITH_LIBZFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_BOOST_SPIRIT_OLD_HDR_TRUE}" && test -z "${USE_BOOST_SPIRIT_OLD_HDR_FALSE}"; then as_fn_error $? "conditional \"USE_BOOST_SPIRIT_OLD_HDR\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_BUILD_TESTS_TRUE}" && test -z "${WITH_BUILD_TESTS_FALSE}"; then as_fn_error $? "conditional \"WITH_BUILD_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by ceph $as_me 0.80.11, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ ceph config.status 0.80.11 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib \ compiler_lib_search_dirs \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ LD_CXX \ reload_flag_CXX \ compiler_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_static_CXX \ lt_cv_prog_compiler_c_o_CXX \ export_dynamic_flag_spec_CXX \ whole_archive_flag_spec_CXX \ compiler_needs_object_CXX \ with_gnu_ld_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_separator_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX \ file_list_spec_CXX \ compiler_lib_search_dirs_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec \ reload_cmds_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ export_symbols_cmds_CXX \ prelink_cmds_CXX \ postlink_cmds_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "src/acconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS src/acconfig.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/ocf/Makefile") CONFIG_FILES="$CONFIG_FILES src/ocf/Makefile" ;; "src/ocf/ceph") CONFIG_FILES="$CONFIG_FILES src/ocf/ceph" ;; "src/ocf/rbd") CONFIG_FILES="$CONFIG_FILES src/ocf/rbd" ;; "src/java/Makefile") CONFIG_FILES="$CONFIG_FILES src/java/Makefile" ;; "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; "ceph.spec") CONFIG_FILES="$CONFIG_FILES ceph.spec" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="CXX " # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects postdep_objects=$lt_postdep_objects predeps=$lt_predeps postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" cat <<_LT_EOF >> "$ofile" # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD=$lt_LD_CXX # How to create reloadable object files. reload_flag=$lt_reload_flag_CXX reload_cmds=$lt_reload_cmds_CXX # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds_CXX # A language specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU compiler? with_gcc=$GCC_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object_CXX # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld_CXX # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute_CXX # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic_CXX # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath_CXX # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds_CXX # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds_CXX # Specify filename containing input files. file_list_spec=$lt_file_list_spec_CXX # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects_CXX postdep_objects=$lt_postdep_objects_CXX predeps=$lt_predeps_CXX postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # ### END LIBTOOL TAG CONFIG: CXX _LT_EOF ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 $as_echo "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for guested configure; otherwise get Cygnus style configure. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure elif test -f "$ac_srcdir/configure.in"; then # This should be Cygnus configure. ac_sub_configure=$ac_aux_dir/configure else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 $as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ceph-0.80.11/configure.ac0000664000175100017510000006167412623076744017201 0ustar jenkins-buildjenkins-build# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # Autoconf AC_PREREQ(2.59) # NOTE: This version is _only_ used for naming the tarball. The # VERSION define is not used by the code. It gets a version string # from 'git describe'; see src/ceph_ver.[ch] AC_INIT([ceph], [0.80.11], [ceph-devel@vger.kernel.org]) # Create release string. Used with VERSION for RPMs. RPM_RELEASE=0 AC_SUBST(RPM_RELEASE) if test -d ".git" ; then AC_CHECK_PROG(GIT_CHECK, git, yes) if test x"$GIT_CHECK" = x"yes"; then RPM_RELEASE=`if expr index $(git describe --always) '-' > /dev/null ; then git describe --always | cut -d- -f2- | tr '-' '.' ; else echo "0"; fi` fi fi AC_MSG_NOTICE([RPM_RELEASE='$RPM_RELEASE']) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SUBDIRS([src/gtest]) # Environment AC_CANONICAL_HOST AC_CANONICAL_TARGET # Fix automake problems in 1.12 m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) # Automake AM_INIT_AUTOMAKE AM_PROG_CC_C_O AM_PROG_LIBTOOL AM_PROG_AS # enable make V=0 (if automake >1.11) AM_INIT_AUTOMAKE([foreign]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) # Platform case "${target_os}" in darwin*) AC_DEFINE([DARWIN], [1], [Define if darwin/osx]) ;; linux*) linux="yes" ;; freebsd*) freebsd="yes" ;; esac AM_CONDITIONAL(LINUX, test x"$linux" = x"yes") AM_CONDITIONAL(FREEBSD, test x"$freebsd" = x"yes") # Checks for programs. AC_PROG_CXX if test "$CXX" = no || test "$CXX:$GXX" = "g++:"; then AC_MSG_ERROR([no C++ compiler found]) fi AC_MSG_CHECKING([if compiler is clang]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[ #ifndef __clang__ #error "Not Clang" #endif return 0; ]])], [CLANG=yes], [CLANG=no]) AC_MSG_RESULT([$CLANG]) AM_CONDITIONAL(CLANG, test "$CLANG" = "yes") #AC_PROG_CC AC_PROG_MAKE_SET AC_PROG_LIBTOOL # Compiler flags AC_SUBST(AM_CXXFLAGS) AM_CXXFLAGS="${AM_CXXFLAGS}" # Check for yasm if yasm -f elf64 src/common/crc32c_intel_fast_asm.S -o /dev/null; then echo 'we have a modern and working yasm' if test `arch` = "x86_64"; then echo 'we are x86_64' AC_DEFINE([HAVE_GOOD_YASM_ELF64], [1], [we have a recent yasm and are x86_64]) with_good_yasm=yes fi else echo 'we do not have a modern/working yasm' fi AM_CONDITIONAL(WITH_GOOD_YASM_ELF64, test "$with_good_yasm" = "yes") # Checks for compiler warning types # AC_CHECK_CC_FLAG(FLAG_TO_TEST, VARIABLE_TO_SET_IF_SUPPORTED) # --------- AC_DEFUN([AC_CHECK_CC_FLAG], [{ AC_LANG_PUSH([C]) my_cflags_save="$CFLAGS" CFLAGS="$my_cflags_save $1" AC_MSG_CHECKING([whether $CC accepts $1]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])], [AC_MSG_RESULT([yes]); AC_SUBST([$2], ["$1"])], [AC_MSG_RESULT([no])] ) CFLAGS="$my_cflags_save" AC_LANG_POP([C]) }]) AC_CHECK_CC_FLAG([-Wtype-limits], [WARN_TYPE_LIMITS]) AC_CHECK_CC_FLAG([-Wignored-qualifiers], [WARN_IGNORED_QUALIFIERS]) # Checks for architecture stuff AM_CONDITIONAL([ENABLE_FPU_NEON], [case $target_cpu in arm*) true;; *) false;; esac]) # Check for compiler VTA support AX_CHECK_COMPILE_FLAG([-fvar-tracking-assignments], [HAS_VTA_SUPPORT=1], [HAS_VTA_SUPPORT=0]) AM_CONDITIONAL(COMPILER_HAS_VTA, [test "$HAS_VTA_SUPPORT" = 1]) AX_CXX_STATIC_CAST AX_C_VAR_FUNC AX_C_PRETTY_FUNC # Checks for libraries. ACX_PTHREAD AC_CHECK_LIB([uuid], [uuid_parse], [true], AC_MSG_FAILURE([libuuid not found])) if test x"$linux" = x"yes"; then AC_CHECK_LIB([blkid], [blkid_devno_to_wholedisk], [true], AC_MSG_FAILURE([libblkid not found])) fi # # Check for res_nquery in libresolv. There are several variations. On OSX # res_nquery is a macro defined in resolv.h, so the typical AC_CHECK_LIB # doesn't work. On FreeBSD res_nquery can be found in libc. The required # library for linking (if any) is defined RESOLV_LIBS. # AC_CHECK_HEADER([resolv.h], [], [], [#include ]) AC_DEFUN([CHECK_RESOLV_LIBS], [{ AC_MSG_CHECKING([if res_nquery will link (LIBS=$1)]) saved_LIBS="${LIBS}" LIBS="$1" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[res_nquery(0, 0, 0, 0, 0, 0);]])], [AC_MSG_RESULT([yes]) [$2]], AC_MSG_RESULT([no])) LIBS="${saved_LIBS}" }]) RESOLV_LIBS="" CHECK_RESOLV_LIBS([$RESOLV_LIBS], [resolv_libs="ok"]) if test x"$resolv_libs" != "xok"; then RESOLV_LIBS="-lresolv" CHECK_RESOLV_LIBS([$RESOLV_LIBS], [resolv_libs="ok"]) if test x"$resolv_libs" != "xok"; then AC_MSG_FAILURE([no resolv library found]) fi fi AC_SUBST([RESOLV_LIBS]) dnl check for libkeyutils on linux KEYUTILS_LIB="" AS_IF([test x"$linux" = x"yes"], [ AC_CHECK_LIB([keyutils], [add_key], [KEYUTILS_LIB="-lkeyutils"], [ AC_MSG_FAILURE([libkeyutils not found])])]) AC_SUBST(KEYUTILS_LIB) AC_CHECK_LIB([m], [pow], [true], AC_MSG_FAILURE([libm not found])) AC_CHECK_FUNCS([syncfs], AC_DEFINE([HAVE_SYS_SYNCFS], [1], [we have syncfs]), []) # Find some crypto library for us to use, while letting user to decide which one to use. AC_ARG_WITH([cryptopp], [AS_HELP_STRING([--with-cryptopp], [Use cryptographic functions from cryptopp])], [], [with_cryptopp=check]) have_cryptopp=no # this looks clumsy but it's just if A then { success } else { if B then success } AS_IF([test "x$with_cryptopp" != "xno"], [PKG_CHECK_MODULES([CRYPTOPP], [libcrypto++], [have_cryptopp=yes], [ AC_LANG_PUSH([C++]) SAVED_CXXFLAGS="${CXXFLAGS}" SAVED_LIBS="${LIBS}" LIBS="${LIBS} ${PTHREAD_LIBS}" CXXFLAGS="${CXXFLAGS} ${PTHREAD_CFLAGS}" AC_SEARCH_LIBS([_ZTIN8CryptoPP14CBC_EncryptionE], [crypto++ cryptopp], [have_cryptopp=yes], [true], []) CRYPTOPP_LIBS="${ac_cv_search__ZTIN8CryptoPP14CBC_EncryptionE}" LIBS="${SAVED_LIBS}" CXXFLAGS="${SAVED_CXXFLAGS}" AC_LANG_POP([C++]) ])]) # bail out if given explicit --with-cryptopp if test "x$have_cryptopp" = "xno" -a "x$with_cryptopp" != "xcheck" -a "x$with_cryptopp" != "xno"; then AC_MSG_FAILURE([--with-cryptopp was given, but library was not found]) fi AC_ARG_WITH([nss], [AS_HELP_STRING([--with-nss], [Use cryptographic functions from nss])], [], [with_nss=check]) have_nss=no AS_IF([test "x$with_nss" != "xno"], [PKG_CHECK_MODULES([NSS], [nss], [have_nss=yes], [true])]) # bail out if given explicit --with-nss if test "x$have_nss" = "xno" -a "x$with_nss" != "xcheck" -a "x$with_nss" != "xno"; then AC_MSG_FAILURE([--with-nss was given, but library was not found]) fi # now decide which crypto library to really use if test "x$have_cryptopp" = "xyes"; then AC_MSG_NOTICE([using cryptopp for cryptography]) AC_DEFINE([USE_CRYPTOPP], [1], [Define if using CryptoPP.]) AC_SUBST([CRYPTO_CFLAGS], [$CRYPTOPP_CFLAGS]) #AC_SUBST([CRYPTO_CXXFLAGS], [$CRYPTOPP_CXXFLAGS]) AM_CXXFLAGS="${AM_CXXFLAGS} ${CRYPTOPP_CXXFLAGS}" AC_SUBST([CRYPTO_LIBS], [$CRYPTOPP_LIBS]) elif test "x$have_nss" = "xyes"; then AC_MSG_NOTICE([using nss for cryptography]) AC_DEFINE([USE_NSS], [1], [Define if using NSS.]) AC_SUBST([CRYPTO_CFLAGS], [$NSS_CFLAGS]) # this needs CFLAGS too in practise to get the includes right. ugly. #AC_SUBST([CRYPTO_CXXFLAGS], [$NSS_CFLAGS $NSS_CXXFLAGS]) AM_CXXFLAGS="${AM_CXXFLAGS} ${NSS_CFLAGS} ${NSS_CXXFLAGS}" AC_SUBST([CRYPTO_LIBS], [$NSS_LIBS]) else AC_MSG_FAILURE([no suitable crypto library found]) fi # profiler? AC_ARG_WITH([profiler], [AS_HELP_STRING([--with-profiler], [build extra profiler binaries])], [case "${withval}" in yes) with_profiler=yes ;; no) with_profiler=no ;; *) AC_MSG_ERROR([bad value ${withval} for --with-profiler]) ;; esac], [with_profiler=no]) AS_IF([test "x$with_profiler" = xyes], [AC_CHECK_LIB([profiler], [ProfilerFlush], [], [AC_MSG_FAILURE([--with-profiler was given but libprofiler (libgoogle-perftools-dev on debian) not found])])], []) AM_CONDITIONAL(WITH_PROFILER, test "$with_profiler" = "yes") AS_IF([test "$with_profiler" = "yes"], [AC_DEFINE([HAVE_PROFILER], [1], [Define if you have perftools profiler enabled])], []) # debug crap? AC_ARG_WITH([debug], [AS_HELP_STRING([--with-debug], [build extra debug binaries])], [case "${withval}" in yes) with_debug=yes ;; no) with_debug=no ;; *) AC_MSG_ERROR([bad value ${withval} for --with-debug]) ;; esac], [with_debug=no]) AM_CONDITIONAL(WITH_DEBUG, test "$with_debug" = "yes") AC_DEFINE([DEBUG_GATHER], [1], [Define if you want C_Gather debugging]) # code coverage? AC_ARG_ENABLE([coverage], [AS_HELP_STRING([--enable-coverage], [enable code coverage tracking])], [], [enable_coverage=no]) AM_CONDITIONAL(ENABLE_COVERAGE, test "x$enable_coverage" != xno) if test "x$enable_coverage" != xno; then AC_DEFINE([ENABLE_COVERAGE], [1], [Define if enabling coverage.]) fi AC_SUBST(GCOV_PREFIX_STRIP, `echo $(pwd)/src | tr -dc / | wc -c`) # radosgw? AC_ARG_WITH([radosgw], [AS_HELP_STRING([--with-radosgw], [build RADOS gateway])], [], [with_radosgw=check]) RADOSGW=0 AS_IF([test "x$with_radosgw" != xno], [AC_CHECK_LIB([fcgi], [FCGX_Init], [AC_CHECK_LIB([expat], [XML_Parse], [AC_CHECK_LIB([curl], [curl_easy_init], [RADOSGW=1 AC_CHECK_HEADER([fastcgi/fcgiapp.h], [AC_DEFINE([FASTCGI_INCLUDE_DIR], [1], [FastCGI headers are in /usr/include/fastcgi])]) ], [if test "x$with_radosgw" != "xcheck"; then AC_MSG_FAILURE([--with-radosgw was given but libcurl (libcurl-dev on debian) not found]) fi]) ], [if test "x$with_radosgw" != "xcheck"; then AC_MSG_FAILURE([--with-radosgw was given but libexpat (libexpat1-dev on debian) not found]) fi]) ], [if test "x$with_radosgw" != "xcheck"; then AC_MSG_FAILURE([--with-radosgw was given but libfcgi (libfcgi-dev on debian) not found]) fi])]) AM_CONDITIONAL(WITH_RADOSGW, test "$RADOSGW" = "1") AS_IF([test "$RADOSGW" = "1"], [AC_DEFINE([WITH_RADOSGW], [1], [define if radosgw enabled])]) AS_IF([test "$RADOSGW" = "1"], [AC_CHECK_LIB([curl], [curl_multi_wait], AC_DEFINE([HAVE_CURL_MULTI_WAIT], [1], [Define if have curl_multi_wait()])) ]) # fuse? AC_ARG_WITH([fuse], [AS_HELP_STRING([--without-fuse], [disable FUSE userspace client])], [], [with_fuse=yes]) LIBFUSE= AS_IF([test "x$with_fuse" != xno], [AC_CHECK_LIB([fuse], [fuse_main], [AC_SUBST([LIBFUSE], ["-lfuse"]) AC_DEFINE([HAVE_LIBFUSE], [1], [Define if you have fuse]) HAVE_LIBFUSE=1 # look for fuse_getgroups and define FUSE_GETGROUPS if found LIBS_saved="$LIBS" LIBS="$LIBS -lfuse" AC_CHECK_FUNCS([fuse_getgroups]) LIBS="$LIBS_saved" ], [AC_MSG_FAILURE( [no FUSE found (use --without-fuse to disable)])])]) AM_CONDITIONAL(WITH_FUSE, [test "$HAVE_LIBFUSE" = "1"]) # tcmalloc? AC_ARG_WITH([tcmalloc], [AS_HELP_STRING([--without-tcmalloc], [disable tcmalloc for memory allocations])], [], [with_tcmalloc=yes]) TCMALLOC= AS_IF([test "x$with_tcmalloc" != xno], [AC_CHECK_LIB([tcmalloc], [malloc], [AC_SUBST([LIBTCMALLOC], ["-ltcmalloc"]) AC_DEFINE([HAVE_LIBTCMALLOC], [1], [Define if you have tcmalloc]) HAVE_LIBTCMALLOC=1 ], [AC_MSG_FAILURE( [no tcmalloc found (use --without-tcmalloc to disable)])])]) AM_CONDITIONAL(WITH_TCMALLOC, [test "$HAVE_LIBTCMALLOC" = "1"]) #set pg ref debugging? AC_ARG_ENABLE([pgrefdebugging], [AS_HELP_STRING([--enable-pgrefdebugging], [enable pg ref debugging])], [AC_DEFINE([PG_DEBUG_REFS], [1], [Defined if you want pg ref debugging])], []) # # Java is painful # - adapted from OMPI wrappers package # - this might become bigger. maybe should be own m4 file # AC_ARG_ENABLE(cephfs-java, [AC_HELP_STRING([--enable-cephfs-java], [build libcephfs Java bindings])], [], [enable_cephfs_java=no]) AM_CONDITIONAL(ENABLE_CEPHFS_JAVA, [test "x$enable_cephfs_java" = "xyes"]) AC_ARG_WITH(jdk-dir, AC_HELP_STRING([--with-jdk-dir(=DIR)], [Path to JDK directory])) if test "x$enable_cephfs_java" = "xyes"; then # setup bin/include dirs from --with-jdk-dir (search for jni.h, javac) AS_IF([test -n "$with_jdk_dir"], [ javac_prog=`find $with_jdk_dir/ -name javac | head -n 1` AS_IF([test -x "$javac_prog"], [ EXTRA_JDK_BIN_DIR=`dirname $javac_prog`]) jnih=`find $with_jdk_dir/ -name jni.h | head -n 1` AS_IF([test -r "$jnih"], [ EXTRA_JDK_INC_DIR=`dirname $jnih`])]) # setup defaults for Debian default-jdk package (without --with-jdk-dir) AS_IF([test -z "$with_jdk_dir"], [ # This works with Debian's and CentOS' default-jdk package for dir in '/usr/lib/jvm/default-java/' '/usr/lib/jvm/java/' '/usr/lib/jvm/java-gcj/'; do # only test if a suitable path has not yet been found AS_IF([test "$EXTRA_JDK_BIN_DIR" == ""], [ AS_IF([test -x "$javac_prog"], [ EXTRA_JDK_BIN_DIR=`dirname $javac_prog`]) jnih=`find $dir -name jni.h | head -n 1` AS_IF([test -r "$jnih"], [ EXTRA_JDK_INC_DIR=`dirname $jnih`]) ]) done ]) # cephfs_java_test only makes sense if java is already turned on # setup CLASSPATH for Debian default junit4.jar package # # Configuring --with-debug and --enable-cephfs-java will throw an error if # JUnit4 cannot be found. While currently this works for users who have # installed via the package manager on Ubuntu, we need to expand this # check to 1 support other distrubtions and 2 allow users to influence # the search path. AS_IF([test "x$with_debug" = "xyes"], [ dir='/usr/share/java' junit4_jar=`find $dir -name junit4.jar | head -n 1` AS_IF([test -r "$junit4_jar"], [ EXTRA_CLASSPATH_JAR=`dirname $junit4_jar`/junit4.jar AC_SUBST(EXTRA_CLASSPATH_JAR) [have_junit4=1]], [ AC_MSG_NOTICE([Cannot find junit4.jar (apt-get install junit4)]) [have_junit4=0]])]) AC_CHECK_CLASSPATH AC_PROG_JAVAC AC_PROG_JAVAH AC_PROG_JAR CLASSPATH=$CLASSPATH:$EXTRA_CLASSPATH_JAR export CLASSPATH AC_MSG_NOTICE([classpath - $CLASSPATH]) # Check for jni.h CPPFLAGS_save=$CPPFLAGS AS_IF([test -n "$EXTRA_JDK_INC_DIR"], [JDK_CPPFLAGS="-I$EXTRA_JDK_INC_DIR" AS_IF([test -d "$EXTRA_JDK_INC_DIR/linux"], [JDK_CPPFLAGS="$JDK_CPPFLAGS -I$EXTRA_JDK_INC_DIR/linux"]) CPPFLAGS="$CPPFLAGS $JDK_CPPFLAGS"]) AC_CHECK_HEADER([jni.h], [], AC_MSG_ERROR([Cannot find header 'jni.h'. Try setting --with-jdk-dir])) CPPFLAGS=$CPPFLAGS_save # Setup output var AC_SUBST(JDK_CPPFLAGS) fi AM_CONDITIONAL(HAVE_JUNIT4, [test "$have_junit4" = "1"]) # # FreeBSD has it in base. # if test x"$freebsd" != x"yes"; then PKG_CHECK_MODULES([LIBEDIT], [libedit >= 2.11], [], AC_MSG_FAILURE([No usable version of libedit found.])) else LIBEDIT_LIBS="-ledit" fi #libatomic-ops? You want it! AC_ARG_WITH([libatomic-ops], [AS_HELP_STRING([--without-libatomic-ops], [disable libatomic-ops for the atomic_t type])], [], [with_libatomic_ops=yes]) AS_IF([test "x$with_libatomic_ops" != xno], [AC_CHECK_HEADER([atomic_ops.h], [HAVE_ATOMIC_OPS=1], [AC_MSG_FAILURE( [no libatomic-ops found (use --without-libatomic-ops to disable)]) ])]) AS_IF([test "$HAVE_ATOMIC_OPS" = "1"], [ AC_CHECK_SIZEOF(AO_t, [], [ #include ]) ], [AC_DEFINE([NO_ATOMIC_OPS], [1], [Defined if you do not have atomic_ops])]) AM_CONDITIONAL(WITH_LIBATOMIC, [test "$HAVE_ATOMIC_OPS" = "1"]) # newsyn? requires mpi. #AC_ARG_WITH([newsyn], # [AS_HELP_STRING([--with-newsyn], [build newsyn target requires mpi])], # [], # [with_newsyn=no]) AC_ARG_WITH([ocf], [AS_HELP_STRING([--with-ocf], [build OCF-compliant cluster resource agent])], , [with_ocf=no]) AM_CONDITIONAL(WITH_OCF, [ test "$with_ocf" = "yes" ]) # check is snappy-devel is installed, needed by leveldb AC_CHECK_LIB([snappy], [snappy_compress], [true], [AC_MSG_FAILURE([libsnappy not found])]) # use system leveldb AC_CHECK_LIB([leveldb], [leveldb_open], [true], [AC_MSG_FAILURE([libleveldb not found])], [-lsnappy -lpthread]) # see if we can use bloom filters with leveldb AC_LANG_PUSH([C++]) AC_CHECK_HEADER([leveldb/filter_policy.h], [AC_DEFINE([HAVE_LEVELDB_FILTER_POLICY], [1], [Defined if LevelDB supports bloom filters ])]) AC_LANG_POP([C++]) # Find supported SIMD / SSE extensions supported by the compiler AX_INTEL_FEATURES() # use system libs3? AC_ARG_WITH([system-libs3], [AS_HELP_STRING([--with-system-libs3], [use system libs3])], , [with_system_libs3=no]) AS_IF([test "x$with_system_libs3" = xyes], [AC_CHECK_LIB([s3], [S3_initialize], [true], [AC_MSG_FAILURE([libs3 not found])], [-lpthread])]) AS_IF([test "x$with_system_libs3" = xcheck], [AC_SEARCH_LIBS([S3_initialize], [s3], [with_system_libs3=yes], [true], [-lpthread])]) AM_CONDITIONAL(WITH_SYSTEM_LIBS3, [ test "$with_system_libs3" = "yes" ]) # rest-bench? AC_ARG_WITH([rest-bench], [AS_HELP_STRING([--with-rest-bench], [enables rest-bench])], [], [with_rest_bench=no]) AM_CONDITIONAL(WITH_REST_BENCH, [ test "$with_rest_bench" = "yes" ]) # use libaio? AC_ARG_WITH([libaio], [AS_HELP_STRING([--without-libaio], [disable libaio use by journal])], , [with_libaio=yes]) AS_IF([test "x$with_libaio" != xno], [AC_CHECK_LIB([aio], [io_submit], [true], AC_MSG_FAILURE([libaio not found]))]) AS_IF([test "x$with_libaio" != xno], [AC_CHECK_HEADER([libaio.h])]) AS_IF([test "$with_libaio" = "yes"], [AC_DEFINE([HAVE_LIBAIO], [1], [Defined if you don't have atomic_ops])]) AM_CONDITIONAL(WITH_LIBAIO, [ test "$with_libaio" = "yes" ]) # use libxfs? AC_ARG_WITH([libxfs], [AS_HELP_STRING([--without-libxfs], [disable libxfs use by FileStore])], [], [with_libxfs=yes]) AS_IF([test "x$with_libxfs" != "xno"], [ # xfs/xfs.h presence and XFS_XFLAG_EXTSIZE define AC_CHECK_HEADER([xfs/xfs.h], [], AC_MSG_ERROR( [xfs/xfs.h not found (--without-libxfs to disable)])) AC_MSG_CHECKING([for XFS_XFLAG_EXTSIZE in xfs/xfs.h]) AC_EGREP_CPP([yes_have_xfs_xflag_extsize], [ #include #ifdef XFS_XFLAG_EXTSIZE yes_have_xfs_xflag_extsize #endif ], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_LIBXFS], [1], [Define to 1 if you have libxfs]) ], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([XFS_XFLAG_EXTSIZE not found (--without-libxfs to disable)]) ]) ]) AM_CONDITIONAL(WITH_LIBXFS, [test "x$with_libxfs" != "xno"]) # use libzfs AC_ARG_WITH([libzfs], [AS_HELP_STRING([--with-libzfs], [build ZFS support])], , [with_libzfs=no]) AS_IF([test "x$with_libzfs" = xyes], [PKG_CHECK_MODULES([LIBZFS], [zfs], [], [true])]) AS_IF([test "x$with_libzfs" = xyes], [AC_DEFINE([HAVE_LIBZFS], [1], [Defined if you have libzfs enabled])]) AM_CONDITIONAL(WITH_LIBZFS, [ test "$with_libzfs" = "yes" ]) # Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT # spirit? AC_LANG([C++]) AC_CHECK_HEADER([boost/spirit/include/classic_core.hpp], [], [AC_CHECK_HEADER([boost/spirit.hpp], [use_bspirit_old_hdr=yes], AC_MSG_FAILURE(["Can't find boost spirit headers"]))]) AM_CONDITIONAL(USE_BOOST_SPIRIT_OLD_HDR, [test "$use_bspirit_old_hdr" = "yes"]) AC_CHECK_HEADER([boost/random/discrete_distribution.hpp], [AC_DEFINE([HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION], [], [have boost::random::discrete_distribution])], []) AC_CHECK_HEADER([boost/statechart/state.hpp], [], AC_MSG_FAILURE(["Can't find boost statechart headers; need 1.34 or later"])) AC_CHECK_HEADER([boost/program_options/option.hpp], [], AC_MSG_FAILURE(["Can't find boost program_options headers"])) # If we have the boost system library installed, then we may want to link # with it. AC_CHECK_LIB(boost_system-mt, main, [], [AC_CHECK_LIB(boost_system, main, [], AC_MSG_NOTICE(["Boost system library not found."]))]) # Find the right boost_thread library. AC_CHECK_LIB(boost_thread-mt, main, [], [AC_CHECK_LIB(boost_thread, main, [], AC_MSG_FAILURE(["Boost thread library not found."]))]) # # Check for boost_program_options library (defines BOOST_PROGRAM_OPTIONS_LIBS). # BOOST_PROGRAM_OPTIONS_LIBS="" saved_LIBS="${LIBS}" LIBS="" AC_CHECK_LIB(boost_program_options-mt, main, [], [AC_CHECK_LIB(boost_program_options, main, [], AC_MSG_FAILURE(["Boost program options library not found."]))]) BOOST_PROGRAM_OPTIONS_LIBS="${LIBS}" LIBS="${saved_LIBS}" AC_SUBST(BOOST_PROGRAM_OPTIONS_LIBS) AC_LANG([C]) AC_CHECK_MEMBER([struct fiemap_extent.fe_logical], [AC_DEFINE([HAVE_FIEMAP_H], [], [linux/fiemap.h was found, fiemap ioctl will be used])], [AC_MSG_NOTICE([linux/fiemap.h was not found or not usable; using local Ceph copy])], [[#include ]]) AC_CHECK_HEADERS([ \ arpa/inet.h \ arpa/nameser_compat.h \ linux/version.h \ netdb.h \ netinet/in.h \ sys/file.h \ sys/ioctl.h \ sys/mount.h \ sys/param.h \ sys/socket.h \ sys/statvfs.h \ sys/time.h \ sys/vfs.h \ sys/xattr.h \ syslog.h \ utime.h \ ]) # sync_file_range AC_CHECK_FUNC([sync_file_range], [AC_DEFINE([HAVE_SYNC_FILE_RANGE], [], [sync_file_range(2) is supported])], []) # fallocate AC_CHECK_FUNC([fallocate], [AC_DEFINE([CEPH_HAVE_FALLOCATE], [], [fallocate(2) is supported])], []) # # Test for time-related `struct stat` members. # AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec], [AC_DEFINE(HAVE_STAT_ST_MTIM_TV_NSEC, 1, [Define if you have struct stat.st_mtim.tv_nsec])]) AC_CHECK_MEMBER([struct stat.st_mtimespec.tv_nsec], [AC_DEFINE(HAVE_STAT_ST_MTIMESPEC_TV_NSEC, 1, [Define if you have struct stat.st_mtimespec.tv_nsec])]) # splice/tee AC_CHECK_FUNC([splice], [AC_DEFINE([CEPH_HAVE_SPLICE], [], [splice(2) is supported])], []) # F_SETPIPE_SZ in fcntl.h AC_MSG_CHECKING([for F_SETPIPE_SZ in fcntl.h]) AC_EGREP_CPP([yes_have_f_setpipe_sz], [ #define _GNU_SOURCE #include #ifdef F_SETPIPE_SZ yes_have_f_setpipe_sz #endif ], [ AC_MSG_RESULT([yes]) AC_DEFINE([CEPH_HAVE_SETPIPE_SZ], [], [F_SETPIPE_SZ is supported]) ], [ AC_MSG_RESULT([no]) AC_MSG_NOTICE([F_SETPIPE_SZ not found, zero-copy may be less efficent]) ]) AC_CHECK_FUNCS([posix_fallocate]) AC_CHECK_HEADERS([sys/prctl.h]) AC_CHECK_FUNCS([prctl]) AC_CHECK_FUNCS([pipe2]) AC_CHECK_FUNCS([posix_fadvise]) AC_MSG_CHECKING([for fdatasync]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 return fdatasync(0); #else #error Not supported #endif ]])], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_FDATASYNC], 1, [Define to 1 if you have fdatasync.]) ], [ AC_MSG_RESULT([no]) ]) # # Check for pthread spinlock (depends on ACX_PTHREAD) # saved_LIBS="$LIBS" saved_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$PTHREAD_CFLAGS $CFLAGS" AC_CHECK_FUNC([pthread_spin_init], [AC_DEFINE(HAVE_PTHREAD_SPINLOCK, 1, [Define if you have pthread_spin_init])]) LIBS="$saved_LIBS" CFLAGS="$saved_CFLAGS" AC_CHECK_TYPES([int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t]) dnl check for Linux types AC_CHECK_HEADERS([linux/types.h]) AC_CHECK_TYPES([__u8, __s8, __u16, __s16, __u32, __s32, __u64, __s64, __le16, __be16, __le32, __be32, __le64, __be64], [], [], [[#include ]]) # Checks for typedefs, structures, and compiler characteristics. #AC_HEADER_STDBOOL #AC_C_CONST #AC_TYPE_UID_T #AC_C_INLINE #AC_TYPE_INT16_T #AC_TYPE_INT32_T #AC_TYPE_INT64_T #AC_TYPE_INT8_T #AC_TYPE_MODE_T #AC_TYPE_OFF_T #AC_TYPE_PID_T #AC_TYPE_SIZE_T #AC_TYPE_SSIZE_T #AC_CHECK_MEMBERS([struct stat.st_blksize]) #AC_STRUCT_ST_BLOCKS #AC_CHECK_MEMBERS([struct stat.st_rdev]) #AC_HEADER_TIME #AC_STRUCT_TM #AC_TYPE_UINT16_T #AC_TYPE_UINT32_T #AC_TYPE_UINT64_T #AC_TYPE_UINT8_T # Checks for library functions. #AC_FUNC_CHOWN #AC_FUNC_CLOSEDIR_VOID #AC_FUNC_ERROR_AT_LINE #AC_FUNC_FORK #AC_PROG_GCC_TRADITIONAL #AC_FUNC_LSTAT #AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK #AC_FUNC_MALLOC # this causes annoying rpl_malloc error on some machines; skip it #AC_FUNC_MEMCMP #AC_FUNC_MMAP #AC_FUNC_REALLOC #AC_FUNC_SELECT_ARGTYPES #AC_TYPE_SIGNAL #AC_FUNC_STAT #AC_FUNC_UTIME_NULL #AC_CHECK_FUNCS([bzero fchdir fdatasync floor ftruncate getcwd gethostbyname gethostname gettimeofday inet_ntoa localtime_r memmove memset mkdir munmap pow rmdir select socket sqrt strcasecmp strchr strerror strstr utime]) # check for return type (and presence) if strerror_r in C++ mode AC_LANG_PUSH([C++]) AC_FUNC_STRERROR_R AC_LANG_POP([C++]) AM_CONDITIONAL(WITH_BUILD_TESTS, test "$WITH_BUILD_TESTS" = "1") AM_PATH_PYTHON([2.4], [], [AC_MSG_FAILURE([Failed to find Python 2.4 or newer])]) AC_CONFIG_HEADERS([src/acconfig.h]) AC_CONFIG_FILES([Makefile src/Makefile src/ocf/Makefile src/ocf/ceph src/ocf/rbd src/java/Makefile man/Makefile ceph.spec]) AC_OUTPUT ceph-0.80.11/py-compile0000755000175100017510000001107612261335263016674 0ustar jenkins-buildjenkins-build#!/bin/sh # py-compile - Compile a Python program scriptversion=2011-06-08.12; # UTC # Copyright (C) 2000-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . if [ -z "$PYTHON" ]; then PYTHON=python fi me=py-compile usage_error () { echo "$me: $*" >&2 echo "Try '$me --help' for more information." >&2 exit 1 } basedir= destdir= while test $# -ne 0; do case "$1" in --basedir) if test $# -lt 2; then usage_error "option '--basedir' requires an argument" else basedir=$2 fi shift ;; --destdir) if test $# -lt 2; then usage_error "option '--destdir' requires an argument" else destdir=$2 fi shift ;; -h|--help) cat <<\EOF Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..." Byte compile some python scripts FILES. Use --destdir to specify any leading directory path to the FILES that you don't want to include in the byte compiled file. Specify --basedir for any additional path information you do want to be shown in the byte compiled file. Example: py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py Report bugs to . EOF exit $? ;; -v|--version) echo "$me $scriptversion" exit $? ;; --) shift break ;; -*) usage_error "unrecognized option '$1'" ;; *) break ;; esac shift done files=$* if test -z "$files"; then usage_error "no files given" fi # if basedir was given, then it should be prepended to filenames before # byte compilation. if [ -z "$basedir" ]; then pathtrans="path = file" else pathtrans="path = os.path.join('$basedir', file)" fi # if destdir was given, then it needs to be prepended to the filename to # byte compile but not go into the compiled file. if [ -z "$destdir" ]; then filetrans="filepath = path" else filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)" fi $PYTHON -c " import sys, os, py_compile, imp files = '''$files''' sys.stdout.write('Byte-compiling python modules...\n') for file in files.split(): $pathtrans $filetrans if not os.path.exists(filepath) or not (len(filepath) >= 3 and filepath[-3:] == '.py'): continue sys.stdout.write(file) sys.stdout.flush() if hasattr(imp, 'get_tag'): py_compile.compile(filepath, imp.cache_from_source(filepath), path) else: py_compile.compile(filepath, filepath + 'c', path) sys.stdout.write('\n')" || exit $? # this will fail for python < 1.5, but that doesn't matter ... $PYTHON -O -c " import sys, os, py_compile, imp # pypy does not use .pyo optimization if hasattr(sys, 'pypy_translation_info'): sys.exit(0) files = '''$files''' sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n') for file in files.split(): $pathtrans $filetrans if not os.path.exists(filepath) or not (len(filepath) >= 3 and filepath[-3:] == '.py'): continue sys.stdout.write(file) sys.stdout.flush() if hasattr(imp, 'get_tag'): py_compile.compile(filepath, imp.cache_from_source(filepath, False), path) else: py_compile.compile(filepath, filepath + 'o', path) sys.stdout.write('\n')" 2>/dev/null || : # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/ceph.spec.in0000664000175100017510000005274612623076744017113 0ustar jenkins-buildjenkins-build%bcond_with ocf %if ! (0%{?fedora} > 12 || 0%{?rhel} > 5) %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} %{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} %endif %{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d} ################################################################################# # common ################################################################################# Name: ceph Version: @VERSION@ Release: @RPM_RELEASE@%{?dist} Summary: User space components of the Ceph file system License: GPL-2.0 Group: System Environment/Base URL: http://ceph.com/ Source0: http://ceph.com/download/%{name}-%{version}.tar.bz2 %if 0%{?fedora} || 0%{?centos} || 0%{?rhel} Patch0: init-ceph.in-fedora.patch %endif Requires: librbd1 = %{version}-%{release} Requires: librados2 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} Requires: ceph-common = %{version}-%{release} Requires: python Requires: python-ceph Requires: python-requests Requires: python-flask Requires: xfsprogs Requires: cryptsetup Requires: parted Requires: util-linux Requires: hdparm Requires(post): binutils BuildRequires: make BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: boost-devel BuildRequires: libedit-devel BuildRequires: perl BuildRequires: gdbm BuildRequires: pkgconfig BuildRequires: python BuildRequires: python-nose BuildRequires: libaio-devel BuildRequires: libcurl-devel BuildRequires: libxml2-devel BuildRequires: libuuid-devel BuildRequires: libblkid-devel >= 2.17 BuildRequires: leveldb-devel > 1.2 BuildRequires: xfsprogs-devel BuildRequires: yasm %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} BuildRequires: snappy-devel %endif ################################################################################# # specific ################################################################################# %if ! 0%{?rhel} || 0%{?fedora} BuildRequires: sharutils %endif %if 0%{defined suse_version} %if 0%{?suse_version} > 1210 Requires: gptfdisk BuildRequires: gperftools-devel %else Requires: scsirastools BuildRequires: google-perftools-devel %endif Recommends: logrotate BuildRequires: %insserv_prereq BuildRequires: mozilla-nss-devel BuildRequires: keyutils-devel BuildRequires: libatomic-ops-devel %else Requires: gdisk BuildRequires: nss-devel BuildRequires: keyutils-libs-devel BuildRequires: libatomic_ops-devel Requires: gdisk Requires(post): chkconfig Requires(preun):chkconfig Requires(preun):initscripts BuildRequires: gperftools-devel %endif %description Ceph is a massively scalable, open-source, distributed storage system that runs on commodity hardware and delivers object, block and file system storage. ################################################################################# # packages ################################################################################# %package -n ceph-common Summary: Ceph Common Group: System Environment/Base Requires: librbd1 = %{version}-%{release} Requires: librados2 = %{version}-%{release} Requires: python-ceph = %{version}-%{release} Requires: python-requests Requires: redhat-lsb-core # python-argparse is only needed in distros with Python 2.6 or lower %if (0%{?rhel} && 0%{?rhel} <= 6) || (0%{?suse_version} && 0%{?suse_version} <= 1110) Requires: python-argparse BuildRequires: python-argparse %endif %description -n ceph-common common utilities to mount and interact with a ceph storage cluster %package fuse Summary: Ceph fuse-based client Group: System Environment/Base Requires: %{name} BuildRequires: fuse-devel %description fuse FUSE based client for Ceph distributed network file system %package -n rbd-fuse Summary: Ceph fuse-based client Group: System Environment/Base Requires: %{name} Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} BuildRequires: fuse-devel %description -n rbd-fuse FUSE based client to map Ceph rbd images to files %package devel Summary: Ceph headers Group: Development/Libraries License: LGPL-2.0 Requires: %{name} = %{version}-%{release} Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} Requires: libcephfs_jni1 = %{version}-%{release} %description devel This package contains libraries and headers needed to develop programs that use Ceph. %package radosgw Summary: Rados REST gateway Group: Development/Libraries Requires: ceph-common = %{version}-%{release} Requires: librados2 = %{version}-%{release} %if 0%{defined suse_version} BuildRequires: libexpat-devel BuildRequires: FastCGI-devel Requires: apache2-mod_fcgid %else BuildRequires: expat-devel BuildRequires: fcgi-devel %endif %description radosgw radosgw is an S3 HTTP REST gateway for the RADOS object store. It is implemented as a FastCGI module using libfcgi, and can be used in conjunction with any FastCGI capable web server. %if %{with ocf} %package resource-agents Summary: OCF-compliant resource agents for Ceph daemons Group: System Environment/Base License: LGPL-2.0 Requires: %{name} = %{version} Requires: resource-agents %description resource-agents Resource agents for monitoring and managing Ceph daemons under Open Cluster Framework (OCF) compliant resource managers such as Pacemaker. %endif %package -n librados2 Summary: RADOS distributed object store client library Group: System Environment/Libraries License: LGPL-2.0 %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} Obsoletes: ceph-libs < %{version}-%{release} %endif %description -n librados2 RADOS is a reliable, autonomic distributed object storage cluster developed as part of the Ceph distributed storage system. This is a shared library allowing applications to access the distributed object store using a simple file-like interface. %package -n librbd1 Summary: RADOS block device client library Group: System Environment/Libraries License: LGPL-2.0 Requires: librados2 = %{version}-%{release} %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} Obsoletes: ceph-libs < %{version}-%{release} %endif %description -n librbd1 RBD is a block device striped across multiple distributed objects in RADOS, a reliable, autonomic distributed object storage cluster developed as part of the Ceph distributed storage system. This is a shared library allowing applications to manage these block devices. %package -n libcephfs1 Summary: Ceph distributed file system client library Group: System Environment/Libraries License: LGPL-2.0 %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} Obsoletes: ceph-libs < %{version}-%{release} Obsoletes: ceph-libcephfs %endif %description -n libcephfs1 Ceph is a distributed network file system designed to provide excellent performance, reliability, and scalability. This is a shared library allowing applications to access a Ceph distributed file system via a POSIX-like interface. %package -n python-ceph Summary: Python libraries for the Ceph distributed filesystem Group: System Environment/Libraries License: LGPL-2.0 Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} %description -n python-ceph This package contains Python libraries for interacting with Cephs RADOS object storage. %package -n rest-bench Summary: RESTful benchmark Group: System Environment/Libraries License: LGPL-2.0 Requires: ceph-common = %{version}-%{release} %description -n rest-bench RESTful bencher that can be used to benchmark radosgw performance. %package -n ceph-test Summary: Ceph benchmarks and test tools Group: System Environment/Libraries License: LGPL-2.0 Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} %description -n ceph-test This package contains Ceph benchmarks and test tools. %package -n libcephfs_jni1 Summary: Java Native Interface library for CephFS Java bindings. Group: System Environment/Libraries License: LGPL-2.0 Requires: java Requires: libcephfs1 = %{version}-%{release} BuildRequires: java-devel %description -n libcephfs_jni1 This package contains the Java Native Interface library for CephFS Java bindings. %package -n cephfs-java Summary: Java libraries for the Ceph File System. Group: System Environment/Libraries License: LGPL-2.0 Requires: java Requires: libcephfs_jni1 = %{version}-%{release} BuildRequires: java-devel %if 0%{?el6} Requires: junit4 BuildRequires: junit4 %else Requires: junit BuildRequires: junit %endif %description -n cephfs-java This package contains the Java libraries for the Ceph File System. %package libs-compat Summary: Meta package to include ceph libraries. Group: System Environment/Libraries License: LGPL-2.0 Obsoletes: ceph-libs Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} Provides: ceph-libs %description libs-compat This is a meta package, that pulls in librados2, librbd1 and libcephfs1. It is included for backwards compatibility with distributions that depend on the former ceph-libs package, which is now split up into these three subpackages. Packages still depending on ceph-libs should be fixed to depend on librados2, librbd1 or libcephfs1 instead. %if 0%{?opensuse} || 0%{?suse_version} %debug_package %endif ################################################################################# # common ################################################################################# %prep %setup -q %if 0%{?fedora} || 0%{?rhel} || 0%{?centos} %patch0 -p1 -b .init %endif %build # Find jni.h for i in /usr/{lib64,lib}/jvm/java/include{,/linux}; do [ -d $i ] && java_inc="$java_inc -I$i" done ./autogen.sh MY_CONF_OPT="" MY_CONF_OPT="$MY_CONF_OPT --with-radosgw" export RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS | sed -e 's/i386/i486/'` %{configure} CPPFLAGS="$java_inc" \ --prefix=/usr \ --localstatedir=/var \ --sysconfdir=/etc \ --docdir=%{_docdir}/ceph \ --with-nss \ --without-cryptopp \ --with-rest-bench \ --with-debug \ --enable-cephfs-java \ $MY_CONF_OPT \ %{?_with_ocf} \ CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" # fix bug in specific version of libedit-devel %if 0%{defined suse_version} sed -i -e "s/-lcurses/-lncurses/g" Makefile sed -i -e "s/-lcurses/-lncurses/g" src/Makefile sed -i -e "s/-lcurses/-lncurses/g" man/Makefile sed -i -e "s/-lcurses/-lncurses/g" src/ocf/Makefile sed -i -e "s/-lcurses/-lncurses/g" src/java/Makefile %endif make -j$(getconf _NPROCESSORS_ONLN) %install make DESTDIR=$RPM_BUILD_ROOT install find $RPM_BUILD_ROOT -type f -name "*.la" -exec rm -f {} ';' find $RPM_BUILD_ROOT -type f -name "*.a" -exec rm -f {} ';' install -D src/init-ceph $RPM_BUILD_ROOT%{_initrddir}/ceph install -D src/init-radosgw.sysv $RPM_BUILD_ROOT%{_initrddir}/ceph-radosgw install -D src/init-rbdmap $RPM_BUILD_ROOT%{_initrddir}/rbdmap install -D src/rbdmap $RPM_BUILD_ROOT%{_sysconfdir}/ceph/rbdmap mkdir -p $RPM_BUILD_ROOT%{_sbindir} ln -sf ../../etc/init.d/ceph %{buildroot}/%{_sbindir}/rcceph ln -sf ../../etc/init.d/ceph-radosgw %{buildroot}/%{_sbindir}/rcceph-radosgw install -m 0644 -D src/logrotate.conf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/ceph install -m 0644 -D src/rgw/logrotate.conf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/radosgw chmod 0644 $RPM_BUILD_ROOT%{_docdir}/ceph/sample.ceph.conf chmod 0644 $RPM_BUILD_ROOT%{_docdir}/ceph/sample.fetch_config # udev rules install -m 0644 -D udev/50-rbd.rules $RPM_BUILD_ROOT%{_udevrulesdir}/50-rbd.rules install -m 0644 -D udev/60-ceph-partuuid-workaround.rules $RPM_BUILD_ROOT%{_udevrulesdir}/60-ceph-partuuid-workaround.rules %if (0%{?rhel} && 0%{?rhel} < 7) install -m 0644 -D udev/95-ceph-osd-alt.rules $RPM_BUILD_ROOT/lib/udev/rules.d/95-ceph-osd.rules %else install -m 0644 -D udev/95-ceph-osd.rules $RPM_BUILD_ROOT/lib/udev/rules.d/95-ceph-osd.rules %endif %if 0%{?rhel} >= 7 || 0%{?fedora} mv $RPM_BUILD_ROOT/lib/udev/rules.d/95-ceph-osd.rules $RPM_BUILD_ROOT/usr/lib/udev/rules.d/95-ceph-osd.rules mv $RPM_BUILD_ROOT/sbin/mkcephfs $RPM_BUILD_ROOT/usr/sbin/mkcephfs mv $RPM_BUILD_ROOT/sbin/mount.ceph $RPM_BUILD_ROOT/usr/sbin/mount.ceph mv $RPM_BUILD_ROOT/sbin/mount.fuse.ceph $RPM_BUILD_ROOT/usr/sbin/mount.fuse.ceph %endif #set up placeholder directories mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/ceph mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/ceph mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/ceph mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/tmp mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/mon mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/osd mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/mds mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/bootstrap-osd mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/bootstrap-mds mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/radosgw %clean rm -rf $RPM_BUILD_ROOT %post /sbin/ldconfig /sbin/chkconfig --add ceph mkdir -p %{_localstatedir}/run/ceph/ %preun %if %{defined suse_version} %stop_on_removal ceph %endif if [ $1 = 0 ] ; then /sbin/service ceph stop >/dev/null 2>&1 /sbin/chkconfig --del ceph fi %postun /sbin/ldconfig %if %{defined suse_version} %insserv_cleanup %endif ################################################################################# # files ################################################################################# %files %defattr(-,root,root,-) %docdir %{_docdir} %dir %{_docdir}/ceph %{_docdir}/ceph/sample.ceph.conf %{_docdir}/ceph/sample.fetch_config %{_bindir}/cephfs %{_bindir}/ceph-clsinfo %{_bindir}/ceph-rest-api %{python_sitelib}/ceph_rest_api.py* %{_bindir}/crushtool %{_bindir}/monmaptool %{_bindir}/osdmaptool %{_bindir}/ceph-run %{_bindir}/ceph-mon %{_bindir}/ceph-mds %{_bindir}/ceph-osd %{_bindir}/ceph-rbdnamer %{_bindir}/librados-config %{_bindir}/ceph-client-debug %{_bindir}/ceph-debugpack %{_bindir}/ceph-coverage %{_bindir}/ceph_mon_store_converter %{_initrddir}/ceph %{_sbindir}/ceph-disk %{_sbindir}/ceph-disk-activate %{_sbindir}/ceph-disk-prepare %{_sbindir}/ceph-disk-udev %{_sbindir}/ceph-create-keys %{_sbindir}/rcceph %if 0%{?rhel} >= 7 || 0%{?fedora} %{_sbindir}/mkcephfs %{_sbindir}/mount.ceph %else /sbin/mkcephfs /sbin/mount.ceph %endif %dir %{_libdir}/ceph %{_libdir}/ceph/ceph_common.sh %dir %{_libdir}/rados-classes %{_libdir}/rados-classes/libcls_rbd.so* %{_libdir}/rados-classes/libcls_hello.so* %{_libdir}/rados-classes/libcls_rgw.so* %{_libdir}/rados-classes/libcls_lock.so* %{_libdir}/rados-classes/libcls_kvs.so* %{_libdir}/rados-classes/libcls_refcount.so* %{_libdir}/rados-classes/libcls_log.so* %{_libdir}/rados-classes/libcls_replica_log.so* %{_libdir}/rados-classes/libcls_statelog.so* %{_libdir}/rados-classes/libcls_user.so* %{_libdir}/rados-classes/libcls_version.so* %dir %{_libdir}/ceph/erasure-code %{_libdir}/ceph/erasure-code/libec_example.so* %{_libdir}/ceph/erasure-code/libec_fail_to_initialize.so* %{_libdir}/ceph/erasure-code/libec_fail_to_register.so* %{_libdir}/ceph/erasure-code/libec_hangs.so* %{_libdir}/ceph/erasure-code/libec_jerasure*.so* %{_libdir}/ceph/erasure-code/libec_test_jerasure*.so* %{_libdir}/ceph/erasure-code/libec_missing_entry_point.so* %{_udevrulesdir}/60-ceph-partuuid-workaround.rules %{_udevrulesdir}/95-ceph-osd.rules %config %{_sysconfdir}/bash_completion.d/ceph %config(noreplace) %{_sysconfdir}/logrotate.d/ceph %config(noreplace) %{_sysconfdir}/logrotate.d/radosgw %{_mandir}/man8/ceph-disk.8* %{_mandir}/man8/ceph-mon.8* %{_mandir}/man8/ceph-mds.8* %{_mandir}/man8/ceph-osd.8* %{_mandir}/man8/mkcephfs.8* %{_mandir}/man8/ceph-run.8* %{_mandir}/man8/ceph-rest-api.8* %{_mandir}/man8/crushtool.8* %{_mandir}/man8/osdmaptool.8* %{_mandir}/man8/monmaptool.8* %{_mandir}/man8/cephfs.8* %{_mandir}/man8/mount.ceph.8* %{_mandir}/man8/ceph-rbdnamer.8* %{_mandir}/man8/ceph-debugpack.8* %{_mandir}/man8/ceph-clsinfo.8.gz %{_mandir}/man8/librados-config.8.gz #set up placeholder directories %dir %{_localstatedir}/lib/ceph/ %dir %{_localstatedir}/lib/ceph/tmp %dir %{_localstatedir}/lib/ceph/mon %dir %{_localstatedir}/lib/ceph/osd %dir %{_localstatedir}/lib/ceph/mds %dir %{_localstatedir}/lib/ceph/bootstrap-osd %dir %{_localstatedir}/lib/ceph/bootstrap-mds %ghost %dir %{_localstatedir}/run/ceph/ ################################################################################# %files -n ceph-common %defattr(-,root,root,-) %{_bindir}/ceph %{_bindir}/ceph-authtool %{_bindir}/ceph-conf %{_bindir}/ceph-dencoder %{_bindir}/ceph-syn %{_bindir}/ceph-crush-location %{_bindir}/rados %{_bindir}/rbd %{_bindir}/ceph-post-file %{_bindir}/ceph-brag %{_mandir}/man8/ceph-authtool.8* %{_mandir}/man8/ceph-conf.8* %{_mandir}/man8/ceph-dencoder.8* %{_mandir}/man8/ceph-syn.8* %{_mandir}/man8/ceph-post-file.8* %{_mandir}/man8/ceph.8* %{_mandir}/man8/rados.8* %{_mandir}/man8/rbd.8* %{_datadir}/ceph/known_hosts_drop.ceph.com %{_datadir}/ceph/id_dsa_drop.ceph.com %{_datadir}/ceph/id_dsa_drop.ceph.com.pub %dir %{_sysconfdir}/ceph/ %dir %{_localstatedir}/log/ceph/ %config %{_sysconfdir}/bash_completion.d/rados %config %{_sysconfdir}/bash_completion.d/rbd %config(noreplace) %{_sysconfdir}/ceph/rbdmap %{_initrddir}/rbdmap %{_udevrulesdir}/50-rbd.rules %postun -n ceph-common # Package removal cleanup if [ "$1" -eq "0" ] ; then rm -rf /var/log/ceph rm -rf /etc/ceph fi ################################################################################# %files fuse %defattr(-,root,root,-) %{_bindir}/ceph-fuse %{_mandir}/man8/ceph-fuse.8* %if 0%{?rhel} >= 7 || 0%{?fedora} %{_sbindir}/mount.fuse.ceph %else /sbin/mount.fuse.ceph %endif ################################################################################# %files -n rbd-fuse %defattr(-,root,root,-) %{_bindir}/rbd-fuse %{_mandir}/man8/rbd-fuse.8* ################################################################################# %files devel %defattr(-,root,root,-) %dir %{_includedir}/cephfs %{_includedir}/cephfs/libcephfs.h %dir %{_includedir}/rados %{_includedir}/rados/librados.h %{_includedir}/rados/librados.hpp %{_includedir}/rados/buffer.h %{_includedir}/rados/page.h %{_includedir}/rados/crc32c.h %{_includedir}/rados/rados_types.h %{_includedir}/rados/rados_types.hpp %{_includedir}/rados/memory.h %dir %{_includedir}/rbd %{_includedir}/rbd/librbd.h %{_includedir}/rbd/librbd.hpp %{_includedir}/rbd/features.h %{_libdir}/libcephfs.so %{_libdir}/librbd.so %{_libdir}/librados.so %{_libdir}/libcephfs_jni.so ################################################################################# %files radosgw %defattr(-,root,root,-) %{_initrddir}/ceph-radosgw %{_bindir}/radosgw %{_bindir}/radosgw-admin %{_mandir}/man8/radosgw.8* %{_mandir}/man8/radosgw-admin.8* %{_sbindir}/rcceph-radosgw %config %{_sysconfdir}/bash_completion.d/radosgw-admin %dir %{_localstatedir}/log/radosgw/ %post radosgw /sbin/ldconfig %if %{defined suse_version} %fillup_and_insserv -f -y ceph-radosgw %endif %preun radosgw %if %{defined suse_version} %stop_on_removal ceph-radosgw %endif %postun radosgw /sbin/ldconfig %if %{defined suse_version} %restart_on_update ceph-radosgw %insserv_cleanup %endif # Package removal cleanup if [ "$1" -eq "0" ] ; then rm -rf /var/log/radosgw fi ################################################################################# %if %{with ocf} %files resource-agents %defattr(0755,root,root,-) %dir /usr/lib/ocf %dir /usr/lib/ocf/resource.d %dir /usr/lib/ocf/resource.d/ceph /usr/lib/ocf/resource.d/%{name}/* %endif ################################################################################# %files -n librados2 %defattr(-,root,root,-) %{_libdir}/librados.so.* %post -n librados2 /sbin/ldconfig %postun -n librados2 /sbin/ldconfig ################################################################################# %files -n librbd1 %defattr(-,root,root,-) %{_libdir}/librbd.so.* %if 0%{?rhel} >= 7 || 0%{?fedora} /usr/lib/udev/rules.d/50-rbd.rules %else /lib/udev/rules.d/50-rbd.rules %endif %post -n librbd1 /sbin/ldconfig mkdir -p /usr/lib64/qemu/ ln -sf %{_libdir}/librbd.so.1 /usr/lib64/qemu/librbd.so.1 %postun -n librbd1 /sbin/ldconfig ################################################################################# %files -n libcephfs1 %defattr(-,root,root,-) %{_libdir}/libcephfs.so.* %post -n libcephfs1 /sbin/ldconfig %postun -n libcephfs1 /sbin/ldconfig ################################################################################# %files -n python-ceph %defattr(-,root,root,-) %{python_sitelib}/rados.py* %{python_sitelib}/rbd.py* %{python_sitelib}/cephfs.py* %{python_sitelib}/ceph_argparse.py* ################################################################################# %files -n rest-bench %defattr(-,root,root,-) %{_bindir}/rest-bench ################################################################################# %files -n ceph-test %defattr(-,root,root,-) %{_bindir}/ceph_bench_log %{_bindir}/ceph_dupstore %{_bindir}/ceph_kvstorebench %{_bindir}/ceph_multi_stress_watch %{_bindir}/ceph_erasure_code %{_bindir}/ceph_erasure_code_benchmark %{_bindir}/ceph_omapbench %{_bindir}/ceph_psim %{_bindir}/ceph_radosacl %{_bindir}/ceph_rgw_jsonparser %{_bindir}/ceph_rgw_multiparser %{_bindir}/ceph_scratchtool %{_bindir}/ceph_scratchtoolpp %{_bindir}/ceph_smalliobench %{_bindir}/ceph_smalliobenchdumb %{_bindir}/ceph_smalliobenchfs %{_bindir}/ceph_smalliobenchrbd %{_bindir}/ceph-objectstore-tool %{_bindir}/ceph_streamtest %{_bindir}/ceph_test_* %{_bindir}/ceph_tpbench %{_bindir}/ceph_xattr_bench %{_bindir}/ceph-monstore-tool %{_bindir}/ceph-osdomap-tool %{_bindir}/ceph-kvstore-tool %files -n libcephfs_jni1 %defattr(-,root,root,-) %{_libdir}/libcephfs_jni.so.* %files -n cephfs-java %defattr(-,root,root,-) %{_javadir}/libcephfs.jar %{_javadir}/libcephfs-test.jar %files libs-compat # We need an empty %files list for ceph-libs-compat, to tell rpmbuild to actually # build this meta package. %changelog ceph-0.80.11/INSTALL0000664000175100017510000000065012623076744015727 0ustar jenkins-buildjenkins-buildInstallation Instructions ************************* If pulling from git, you first need to build the configure script with $ ./autogen.sh Then, $ ./configure $ make Note that if the FUSE library is not found, the user-space fuse client will not be built. If you are doing development, you may want to do $ CXXFLAGS="-g -pg" ./configure or similar to avoid the default (-g -O2), which includes optimizations (-O2). ceph-0.80.11/m4/0000775000175100017510000000000012623077033015205 5ustar jenkins-buildjenkins-buildceph-0.80.11/m4/ltversion.m40000644000175100017510000000126212623076760017501 0ustar jenkins-buildjenkins-build# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) ceph-0.80.11/m4/ac_check_classpath.m40000664000175100017510000000153612623076744021246 0ustar jenkins-buildjenkins-builddnl @synopsis AC_CHECK_CLASSPATH dnl dnl AC_CHECK_CLASSPATH just displays the CLASSPATH, for the edification dnl of the user. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_CHECK_CLASSPATH],[ if test "x$CLASSPATH" = x; then echo "You have no CLASSPATH, I hope it is good" else echo "You have CLASSPATH $CLASSPATH, hope it is correct" fi ]) ceph-0.80.11/m4/ac_prog_javah.m40000664000175100017510000000201712623076744020242 0ustar jenkins-buildjenkins-builddnl @synopsis AC_PROG_JAVAH dnl dnl AC_PROG_JAVAH tests the availability of the javah header generator dnl and looks for the jni.h header file. If available, JAVAH is set to dnl the full path of javah and CPPFLAGS is updated accordingly. dnl dnl @category Java dnl @author Luc Maisonobe dnl @version 2002-03-25 dnl @license AllPermissive AC_DEFUN([AC_PROG_JAVAH],[ AC_REQUIRE([AC_CANONICAL_TARGET])dnl AC_REQUIRE([AC_PROG_CPP])dnl AC_PATH_PROG(JAVAH,javah) if test x"`eval 'echo $ac_cv_path_JAVAH'`" != x ; then AC_TRY_CPP([#include ],,[ ac_save_CPPFLAGS="$CPPFLAGS" changequote(, )dnl ac_dir=`echo $ac_cv_path_JAVAH | sed 's,\(.*\)/[^/]*/[^/]*$,\1/include,'` ac_machdep=`echo $build_os | sed 's,[-0-9].*,,' | sed 's,cygwin,win32,'` changequote([, ])dnl CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep" AC_TRY_CPP([#include ], ac_save_CPPFLAGS="$CPPFLAGS", AC_MSG_WARN([unable to include ])) CPPFLAGS="$ac_save_CPPFLAGS"]) fi]) ceph-0.80.11/m4/ac_prog_jar.m40000664000175100017510000000244212623076744017727 0ustar jenkins-buildjenkins-builddnl @synopsis AC_PROG_JAR dnl dnl AC_PROG_JAR tests for an existing jar program. It uses the dnl environment variable JAR then tests in sequence various common jar dnl programs. dnl dnl If you want to force a specific compiler: dnl dnl - at the configure.in level, set JAR=yourcompiler before calling dnl AC_PROG_JAR dnl dnl - at the configure level, setenv JAR dnl dnl You can use the JAR variable in your Makefile.in, with @JAR@. dnl dnl Note: This macro depends on the autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download that whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. dnl dnl The general documentation of those macros, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Egon Willighagen dnl @version 2000-07-19 dnl @license AllPermissive AC_DEFUN([AC_PROG_JAR],[ AC_REQUIRE([AC_EXEEXT])dnl if test "x$JAVAPREFIX" = x; then test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar$EXEEXT) else test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar, $JAVAPREFIX) fi test "x$JAR" = x && AC_MSG_ERROR([no acceptable jar program found in \$PATH]) AC_PROVIDE([$0])dnl ]) ceph-0.80.11/m4/ltsugar.m40000644000175100017510000001042412623076760017135 0ustar jenkins-buildjenkins-build# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) ceph-0.80.11/m4/ac_prog_javac_works.m40000664000175100017510000000220212623076744021456 0ustar jenkins-buildjenkins-builddnl @synopsis AC_PROG_JAVAC_WORKS dnl dnl Internal use ONLY. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_PROG_JAVAC_WORKS],[ AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [ JAVA_TEST=Test.java CLASS_TEST=Test.class cat << \EOF > $JAVA_TEST /* [#]line __oline__ "configure" */ public class Test { } EOF if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then ac_cv_prog_javac_works=yes else AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)]) echo "configure: failed program was:" >&AC_FD_CC cat $JAVA_TEST >&AC_FD_CC fi rm -f $JAVA_TEST $CLASS_TEST ]) AC_PROVIDE([$0])dnl ]) ceph-0.80.11/m4/pkg.m40000644000175100017510000001302312623076757016241 0ustar jenkins-buildjenkins-build# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES ceph-0.80.11/m4/ac_prog_javac.m40000664000175100017510000000330212623076744020233 0ustar jenkins-buildjenkins-builddnl @synopsis AC_PROG_JAVAC dnl dnl AC_PROG_JAVAC tests an existing Java compiler. It uses the dnl environment variable JAVAC then tests in sequence various common dnl Java compilers. For political reasons, it starts with the free dnl ones. dnl dnl If you want to force a specific compiler: dnl dnl - at the configure.in level, set JAVAC=yourcompiler before calling dnl AC_PROG_JAVAC dnl dnl - at the configure level, setenv JAVAC dnl dnl You can use the JAVAC variable in your Makefile.in, with @JAVAC@. dnl dnl *Warning*: its success or failure can depend on a proper setting of dnl the CLASSPATH env. variable. dnl dnl TODO: allow to exclude compilers (rationale: most Java programs dnl cannot compile with some compilers like guavac). dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_PROG_JAVAC],[ AC_REQUIRE([AC_EXEEXT])dnl if test "x$JAVAPREFIX" = x; then test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT) else test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT, $JAVAPREFIX) fi test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) AC_PROG_JAVAC_WORKS AC_PROVIDE([$0])dnl ]) ceph-0.80.11/m4/acx_pthread.m40000664000175100017510000003404512623076744017747 0ustar jenkins-buildjenkins-build# This was retrieved from # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi # See also (perhaps for new versions?) # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi # # We've rewritten the inconsistency check code (from avahi), to work # more broadly. In particular, it no longer assumes ld accepts -zdefs. # This caused a restructing of the code, but the functionality has only # changed a little. dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2006-05-29 dnl @license GPLWithACException dnl dnl Checks for GCC shared/pthread inconsistency based on work by dnl Marcin Owsiany AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) AC_TRY_LINK(,, , [done=yes]) if test "x$done" = xyes ; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread fixes that]) LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lc_r fixes that]) LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi if test x"$done" = xno; then # OK, we have run out of ideas AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi AC_MSG_CHECKING([whether what we have so far is sufficient with -nostdlib]) CFLAGS="-nostdlib $CFLAGS" # we need c with nostdlib LIBS="$LIBS -lc" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes],[done=no]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread saves the day]) LIBS="-lpthread $LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes],[done=no]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" else AC_MSG_RESULT([no]) AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries and -nostdlib]) fi fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD ceph-0.80.11/m4/ax_c_pretty_func.m40000664000175100017510000000074712623076744021023 0ustar jenkins-buildjenkins-build# # Test for C compiler support of __PRETTY_FUNCTION__ # # - Adapted from ax_c_var_func (Noah Watkins) # AU_ALIAS([AC_C_PRETTY_FUNC], [AX_C_PRETTY_FUNC]) AC_DEFUN([AX_C_PRETTY_FUNC], [AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK(whether $CC recognizes __PRETTY_FUNCTION__, ac_cv_c_pretty_func, AC_TRY_COMPILE(, [ char *s = __PRETTY_FUNCTION__; ], AC_DEFINE(HAVE_PRETTY_FUNC,, [Define if the C complier supports __PRETTY_FUNCTION__]) ac_cv_c_pretty_func=yes, ac_cv_c_pretty_func=no) ) ])dnl ceph-0.80.11/m4/lt~obsolete.m40000644000175100017510000001375612623076760020041 0ustar jenkins-buildjenkins-build# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) ceph-0.80.11/m4/ax_check_compile_flag.m40000664000175100017510000000625112623076744021731 0ustar jenkins-buildjenkins-build# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS ceph-0.80.11/m4/ax_cxx_static_cast.m40000664000175100017510000000262112623076744021333 0ustar jenkins-buildjenkins-build# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_cxx_static_cast.html # =========================================================================== # # SYNOPSIS # # AX_CXX_STATIC_CAST # # DESCRIPTION # # If the compiler supports static_cast<>, define HAVE_STATIC_CAST. # # LICENSE # # Copyright (c) 2008 Todd Veldhuizen # Copyright (c) 2008 Luc Maisonobe # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AU_ALIAS([AC_CXX_STATIC_CAST], [AX_CXX_STATIC_CAST]) AC_DEFUN([AX_CXX_STATIC_CAST], [AC_CACHE_CHECK(whether the compiler supports static_cast<>, ax_cv_cxx_static_cast, [AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([#include class Base { public : Base () {} virtual void f () = 0; }; class Derived : public Base { public : Derived () {} virtual void f () {} }; int g (Derived&) { return 0; }],[ Derived d; Base& b = d; Derived& s = static_cast (b); return g (s);], ax_cv_cxx_static_cast=yes, ax_cv_cxx_static_cast=no) AC_LANG_RESTORE ]) if test "$ax_cv_cxx_static_cast" = yes; then AC_DEFINE(HAVE_STATIC_CAST,, [define if the compiler supports static_cast<>]) fi ]) ceph-0.80.11/m4/ax_c_var_func.m40000664000175100017510000000512712623076744020261 0ustar jenkins-buildjenkins-build# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_c_var_func.html # =========================================================================== # # SYNOPSIS # # AX_C_VAR_FUNC # # DESCRIPTION # # This macro tests if the C complier supports the C9X standard __func__ # indentifier. # # The new C9X standard for the C language stipulates that the identifier # __func__ shall be implictly declared by the compiler as if, immediately # following the opening brace of each function definition, the declaration # # static const char __func__[] = "function-name"; # # appeared, where function-name is the name of the function where the # __func__ identifier is used. # # LICENSE # # Copyright (c) 2008 Christopher Currie # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 5 AU_ALIAS([AC_C_VAR_FUNC], [AX_C_VAR_FUNC]) AC_DEFUN([AX_C_VAR_FUNC], [AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK(whether $CC recognizes __func__, ac_cv_c_var_func, AC_TRY_COMPILE(, [ char *s = __func__; ], AC_DEFINE(HAVE_FUNC,, [Define if the C complier supports __func__]) ac_cv_c_var_func=yes, ac_cv_c_var_func=no) ) ])dnl ceph-0.80.11/m4/libtool.m40000644000175100017510000106011112623076760017117 0ustar jenkins-buildjenkins-build# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS ceph-0.80.11/m4/ax_intel.m40000664000175100017510000000535512623076744017272 0ustar jenkins-buildjenkins-buildAC_DEFUN([AX_INTEL_FEATURES], [ AC_REQUIRE([AC_CANONICAL_HOST]) case $target_cpu in i[[3456]]86*|x86_64*|amd64*) AX_CHECK_COMPILE_FLAG(-msse, ax_cv_support_sse_ext=yes, []) if test x"$ax_cv_support_sse_ext" = x"yes"; then INTEL_SSE_FLAGS="-msse -DINTEL_SSE" AC_SUBST(INTEL_SSE_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE_FLAGS" AC_DEFINE(HAVE_SSE,,[Support SSE (Streaming SIMD Extensions) instructions]) fi AX_CHECK_COMPILE_FLAG(-msse2, ax_cv_support_sse2_ext=yes, []) if test x"$ax_cv_support_sse2_ext" = x"yes"; then INTEL_SSE2_FLAGS="-msse2 -DINTEL_SSE2" AC_SUBST(INTEL_SSE2_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE2_FLAGS" AC_DEFINE(HAVE_SSE2,,[Support SSE2 (Streaming SIMD Extensions 2) instructions]) fi AX_CHECK_COMPILE_FLAG(-msse3, ax_cv_support_sse3_ext=yes, []) if test x"$ax_cv_support_sse3_ext" = x"yes"; then INTEL_SSE3_FLAGS="-msse3 -DINTEL_SSE3" AC_SUBST(INTEL_SSE3_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE3_FLAGS" AC_DEFINE(HAVE_SSE3,,[Support SSE3 (Streaming SIMD Extensions 3) instructions]) fi AX_CHECK_COMPILE_FLAG(-mssse3, ax_cv_support_ssse3_ext=yes, []) if test x"$ax_cv_support_ssse3_ext" = x"yes"; then INTEL_SSSE3_FLAGS="-mssse3 -DINTEL_SSSE3" AC_SUBST(INTEL_SSSE3_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSSE3_FLAGS" AC_DEFINE(HAVE_SSSE3,,[Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions]) fi ;; esac case $target_cpu in x86_64*|amd64*) AX_CHECK_COMPILE_FLAG(-mpclmul, ax_cv_support_pclmuldq_ext=yes, []) if test x"$ax_cv_support_pclmuldq_ext" = x"yes"; then INTEL_PCLMUL_FLAGS="-mpclmul -DINTEL_SSE4_PCLMUL" AC_SUBST(INTEL_PCLMUL_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_PCLMUL_FLAGS" AC_DEFINE(HAVE_PCLMUL,,[Support (PCLMUL) Carry-Free Muliplication]) fi AX_CHECK_COMPILE_FLAG(-msse4.1, ax_cv_support_sse41_ext=yes, []) if test x"$ax_cv_support_sse41_ext" = x"yes"; then INTEL_SSE4_1_FLAGS="-msse4.1 -DINTEL_SSE4" AC_SUBST(INTEL_SSE4_1_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE4_1_FLAGS" AC_DEFINE(HAVE_SSE4_1,,[Support SSE4.1 (Streaming SIMD Extensions 4.1) instructions]) fi AX_CHECK_COMPILE_FLAG(-msse4.2, ax_cv_support_sse42_ext=yes, []) if test x"$ax_cv_support_sse42_ext" = x"yes"; then INTEL_SSE4_2_FLAGS="-msse4.2 -DINTEL_SSE4" AC_SUBST(INTEL_SSE4_2_FLAGS) INTEL_FLAGS="$INTEL_FLAGS $INTEL_SSE4_2_FLAGS" AC_DEFINE(HAVE_SSE4_2,,[Support SSE4.2 (Streaming SIMD Extensions 4.2) instructions]) fi ;; esac AC_SUBST(INTEL_FLAGS) ]) ceph-0.80.11/m4/ltoptions.m40000644000175100017510000003007312623076760017511 0ustar jenkins-buildjenkins-build# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) ceph-0.80.11/ar-lib0000755000175100017510000001330212261335263015756 0ustar jenkins-buildjenkins-build#! /bin/sh # Wrapper for Microsoft lib.exe me=ar-lib scriptversion=2012-03-01.08; # UTC # Copyright (C) 2010-2013 Free Software Foundation, Inc. # Written by Peter Rosin . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # func_error message func_error () { echo "$me: $1" 1>&2 exit 1 } file_conv= # func_file_conv build_file # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv in mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin) file=`cygpath -m "$file" || echo "$file"` ;; wine) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_at_file at_file operation archive # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE # for each of them. # When interpreting the content of the @FILE, do NOT use func_file_conv, # since the user would need to supply preconverted file names to # binutils ar, at least for MinGW. func_at_file () { operation=$2 archive=$3 at_file_contents=`cat "$1"` eval set x "$at_file_contents" shift for member do $AR -NOLOGO $operation:"$member" "$archive" || exit $? done } case $1 in '') func_error "no command. Try '$0 --help' for more information." ;; -h | --h*) cat <. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ceph-0.80.11/ChangeLog0000664000175100017510000000000012623076744016435 0ustar jenkins-buildjenkins-buildceph-0.80.11/aclocal.m40000664000175100017510000015160712623076762016547 0ustar jenkins-buildjenkins-build# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Copyright (C) 2011-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_AR([ACT-IF-FAIL]) # ------------------------- # Try to determine the archiver interface, and trigger the ar-lib wrapper # if it is needed. If the detection of archiver interface fails, run # ACT-IF-FAIL (default is to abort configure with a proper error message). AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [AC_LANG_PUSH([C]) am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) AC_LANG_POP([C])]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) # Figure out how to run the assembler. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_AS # ---------- AC_DEFUN([AM_PROG_AS], [# By default we simply use the C compiler to build assembly code. AC_REQUIRE([AC_PROG_CC]) test "${CCAS+set}" = set || CCAS=$CC test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0]) AC_ARG_VAR([PYTHON], [the Python interpreter]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version is >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([Python interpreter is too old])]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': can_use_sysconfig = 0 except ImportError: pass" dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ac_check_classpath.m4]) m4_include([m4/ac_prog_jar.m4]) m4_include([m4/ac_prog_javac.m4]) m4_include([m4/ac_prog_javac_works.m4]) m4_include([m4/ac_prog_javah.m4]) m4_include([m4/acx_pthread.m4]) m4_include([m4/ax_c_pretty_func.m4]) m4_include([m4/ax_c_var_func.m4]) m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_cxx_static_cast.m4]) m4_include([m4/ax_intel.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/pkg.m4]) ceph-0.80.11/AUTHORS0000664000175100017510000000056212623076744015750 0ustar jenkins-buildjenkins-buildCeph core --------- Sage Weil Yehuda Sadeh-Weinraub Greg Farnum Kernel client ------------- Sage Weil Patience Warnick Yehuda Sadeh-Weinraub Greg Farnum Contributors ------------ Loic Dachary ceph-0.80.11/udev/0000775000175100017510000000000012623077033015630 5ustar jenkins-buildjenkins-buildceph-0.80.11/udev/95-ceph-osd-alt.rules0000664000175100017510000000032012623076744021422 0ustar jenkins-buildjenkins-build# Check gpt partion for ceph tags and activate ACTION=="add", SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_TABLE_TYPE}=="gpt", \ RUN+="/usr/sbin/ceph-disk-udev $number $name $parent" ceph-0.80.11/udev/60-ceph-partuuid-workaround.rules0000664000175100017510000000327112623076744024105 0ustar jenkins-buildjenkins-build# # this is a kludge installed by ceph to fix the /dev/disk/by-partuuid # symlinks on systems with old udev (< 180). it's a stripped down # version of a newer 60-persistent-storage.rules file that hopefully # captures the same set of conditions for setting up those symlinks. # # forward scsi device event to corresponding block device ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change" ACTION=="remove", GOTO="persistent_storage_end_two" SUBSYSTEM!="block", GOTO="persistent_storage_end_two" # skip rules for inappropriate block devices KERNEL=="fd*|mtd*|nbd*|gnbd*|btibm*|dm-*|md*", GOTO="persistent_storage_end_two" # ignore partitions that span the entire disk TEST=="whole_disk", GOTO="persistent_storage_end_two" # for partitions import parent information ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" # skip unpartitioned removable media devices from drivers which do not send "change" events ENV{DEVTYPE}=="disk", KERNEL!="sd*|sr*", ATTR{removable}=="1", GOTO="persistent_storage_end_two" # probe filesystem metadata of disks KERNEL!="sr*", IMPORT{program}="/sbin/blkid -o udev -p $tempnode" # by-partlabel/by-partuuid links (partition metadata) ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}" ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}" # NEW: by-parttypeuuid links (type.id) ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_TYPE}=="?*", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-parttypeuuid/$env{ID_PART_ENTRY_TYPE}.$env{ID_PART_ENTRY_UUID}" LABEL="persistent_storage_end_two" ceph-0.80.11/udev/95-ceph-osd.rules0000664000175100017510000000242512623076744020654 0ustar jenkins-buildjenkins-build# activate ceph-tagged partitions ACTION=="add", SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_ENTRY_TYPE}=="4fbd7e29-9d25-41b8-afd0-062c0ceff05d", \ RUN+="/usr/sbin/ceph-disk-activate /dev/$name" # activate ceph-tagged partitions ACTION=="add", SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_ENTRY_TYPE}=="45b0969e-9b03-4f30-b4c6-b4b80ceff106", \ RUN+="/usr/sbin/ceph-disk activate-journal /dev/$name" # Map journal if using dm-crypt ACTION=="add" SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_ENTRY_TYPE}=="45b0969e-9b03-4f30-b4c6-5ec00ceff106", \ RUN+="/sbin/cryptsetup --key-file /etc/ceph/dmcrypt-keys/$env{ID_PART_ENTRY_UUID} --key-size 256 create $env{ID_PART_ENTRY_UUID} /dev/$name" # Map data device and # activate ceph-tagged partitions # for dm-crypted data devices ACTION=="add" SUBSYSTEM=="block", \ ENV{DEVTYPE}=="partition", \ ENV{ID_PART_ENTRY_TYPE}=="4fbd7e29-9d25-41b8-afd0-5ec00ceff05d", \ RUN+="/sbin/cryptsetup --key-file /etc/ceph/dmcrypt-keys/$env{ID_PART_ENTRY_UUID} --key-size 256 create $env{ID_PART_ENTRY_UUID} /dev/$name", \ RUN+="/bin/bash -c 'while [ ! -e /dev/mapper/$env{ID_PART_ENTRY_UUID} ];do sleep 1; done'", \ RUN+="/usr/sbin/ceph-disk-activate /dev/mapper/$env{ID_PART_ENTRY_UUID}" ceph-0.80.11/udev/50-rbd.rules0000664000175100017510000000034212623076744017704 0ustar jenkins-buildjenkins-buildKERNEL=="rbd[0-9]*", ENV{DEVTYPE}=="disk", PROGRAM="/usr/bin/ceph-rbdnamer %k", SYMLINK+="rbd/%c{1}/%c{2}" KERNEL=="rbd[0-9]*", ENV{DEVTYPE}=="partition", PROGRAM="/usr/bin/ceph-rbdnamer %k", SYMLINK+="rbd/%c{1}/%c{2}-part%n" ceph-0.80.11/config.sub0000755000175100017510000010535412201675101016646 0ustar jenkins-buildjenkins-build#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-08-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ceph-0.80.11/src/0000775000175100017510000000000012623077036015457 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/ceph_mds.cc0000664000175100017510000002331212623076744017556 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include using namespace std; #include "include/ceph_features.h" #include "common/config.h" #include "common/strtol.h" #include "mon/MonMap.h" #include "mds/MDS.h" #include "mds/Dumper.h" #include "mds/Resetter.h" #include "msg/Messenger.h" #include "common/Timer.h" #include "common/ceph_argparse.h" #include "common/pick_address.h" #include "global/global_init.h" #include "global/signal_handler.h" #include "global/pidfile.h" #include "mon/MonClient.h" #include "auth/KeyRing.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds void usage() { derr << "usage: ceph-mds -i name [flags] [[--journal_check rank]|[--hot-standby][rank]]\n" << " -m monitorip:port\n" << " connect to monitor at given address\n" << " --debug_mds n\n" << " debug MDS level (e.g. 10)\n" << " --dump-journal rank filename\n" << " dump the MDS journal (binary) for rank.\n" << " --dump-journal-entries rank filename\n" << " dump the MDS journal (JSON) for rank.\n" << " --journal-check rank\n" << " replay the journal for rank, then exit\n" << " --hot-standby rank\n" << " start up as a hot standby for rank\n" << " --reset-journal rank\n" << " discard the MDS journal for rank, and replace it with a single\n" << " event that updates/resets inotable and sessionmap on replay.\n" << dendl; generic_server_usage(); } static int do_cmds_special_action(const std::string &action, const std::string &dump_file, int rank) { common_init_finish(g_ceph_context, CINIT_FLAG_NO_DAEMON_ACTIONS); if (action == "dump-journal") { dout(0) << "dumping journal for mds." << rank << " to " << dump_file << dendl; Dumper journal_dumper; journal_dumper.init(rank); journal_dumper.dump(dump_file.c_str()); journal_dumper.shutdown(); } else if (action == "dump-journal-entries") { Dumper journal_dumper; journal_dumper.init(rank); journal_dumper.dump_entries(); journal_dumper.shutdown(); } else if (action == "undump-journal") { dout(0) << "undumping journal for mds." << rank << " from " << dump_file << dendl; Dumper journal_dumper; journal_dumper.init(rank); journal_dumper.undump(dump_file.c_str()); journal_dumper.shutdown(); } else if (action == "reset-journal") { dout(0) << "resetting journal" << dendl; Resetter resetter; resetter.init(rank); resetter.reset(); resetter.shutdown(); } else { assert(0); } return 0; } static void set_special_action(std::string &dest, const std::string &act) { if (!dest.empty()) { derr << "Parse error! Can't specify more than one action. You " << "specified both " << act << " and " << dest << "\n" << dendl; usage(); exit(1); } dest = act; } static int parse_rank(const char *opt_name, const std::string &val) { std::string err; int ret = strict_strtol(val.c_str(), 10, &err); if (!err.empty()) { derr << "error parsing " << opt_name << ": failed to parse rank. " << "It must be an int." << "\n" << dendl; usage(); } return ret; } MDS *mds = NULL; static void handle_mds_signal(int signum) { if (mds) mds->handle_signal(signum); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_MDS, CODE_ENVIRONMENT_DAEMON, 0); // mds specific args int shadow = 0; int rank = -1; std::string dump_file; std::string val, action; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_witharg(args, i, &val, "--dump-journal", (char*)NULL)) { set_special_action(action, "dump-journal"); rank = parse_rank("dump-journal", val); if (i == args.end()) { derr << "error parsing --dump-journal: you must give a second " << "dump-journal argument: the filename to dump the journal to. " << "\n" << dendl; usage(); } dump_file = *i++; } else if (ceph_argparse_witharg(args, i, &val, "--undump-journal", (char*)NULL)) { set_special_action(action, "undump-journal"); rank = parse_rank("undump-journal", val); if (i == args.end()) { derr << "error parsing --undump-journal: you must give a second " << "undump-journal argument: the filename to undump the journal from. " << "\n" << dendl; usage(); } dump_file = *i++; } else if (ceph_argparse_witharg(args, i, &val, "--dump-journal-entries", (char*)NULL)){ set_special_action(action, "dump-journal-entries"); rank = parse_rank("dump-journal-entries", val); } else if (ceph_argparse_witharg(args, i, &val, "--reset-journal", (char*)NULL)) { set_special_action(action, "reset-journal"); rank = parse_rank("reset-journal", val); } else if (ceph_argparse_witharg(args, i, &val, "--journal-check", (char*)NULL)) { int r = parse_rank("journal-check", val); if (shadow) { dout(0) << "Error: can only select one standby state" << dendl; return -1; } dout(0) << "requesting oneshot_replay for mds." << r << dendl; shadow = MDSMap::STATE_ONESHOT_REPLAY; char rb[32]; snprintf(rb, sizeof(rb), "%d", r); g_conf->set_val("mds_standby_for_rank", rb); g_conf->apply_changes(NULL); } else if (ceph_argparse_witharg(args, i, &val, "--hot-standby", (char*)NULL)) { int r = parse_rank("hot-standby", val); if (shadow) { dout(0) << "Error: can only select one standby state" << dendl; return -1; } dout(0) << "requesting standby_replay for mds." << r << dendl; shadow = MDSMap::STATE_STANDBY_REPLAY; char rb[32]; snprintf(rb, sizeof(rb), "%d", r); g_conf->set_val("mds_standby_for_rank", rb); g_conf->apply_changes(NULL); } else { derr << "Error: can't understand argument: " << *i << "\n" << dendl; usage(); } } pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC); // Check for special actions if (!action.empty()) { return do_cmds_special_action(action, dump_file, rank); } // Normal startup if (g_conf->name.has_default_id()) { derr << "must specify '-i name' with the ceph-mds instance name" << dendl; usage(); } Messenger *messenger = Messenger::create(g_ceph_context, entity_name_t::MDS(-1), "mds", getpid()); messenger->set_cluster_protocol(CEPH_MDS_PROTOCOL); cout << "starting " << g_conf->name << " at " << messenger->get_myaddr() << std::endl; uint64_t supported = CEPH_FEATURE_UID | CEPH_FEATURE_NOSRCADDR | CEPH_FEATURE_DIRLAYOUTHASH | CEPH_FEATURE_MDS_INLINE_DATA | CEPH_FEATURE_PGID64 | CEPH_FEATURE_MSG_AUTH | CEPH_FEATURE_EXPORT_PEER; uint64_t required = CEPH_FEATURE_OSDREPLYMUX; messenger->set_default_policy(Messenger::Policy::lossy_client(supported, required)); messenger->set_policy(entity_name_t::TYPE_MON, Messenger::Policy::lossy_client(supported, CEPH_FEATURE_UID | CEPH_FEATURE_PGID64)); messenger->set_policy(entity_name_t::TYPE_MDS, Messenger::Policy::lossless_peer(supported, CEPH_FEATURE_UID)); messenger->set_policy(entity_name_t::TYPE_CLIENT, Messenger::Policy::stateful_server(supported, 0)); int r = messenger->bind(g_conf->public_addr); if (r < 0) exit(1); if (shadow != MDSMap::STATE_ONESHOT_REPLAY) global_init_daemonize(g_ceph_context, 0); common_init_finish(g_ceph_context); // get monmap MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) return -1; global_init_chdir(g_ceph_context); messenger->start(); // start mds mds = new MDS(g_conf->name.get_id().c_str(), messenger, &mc); // in case we have to respawn... mds->orig_argc = argc; mds->orig_argv = argv; if (shadow) r = mds->init(shadow); else r = mds->init(); if (r < 0) goto shutdown; // set up signal handlers, now that we've daemonized/forked. init_async_signal_handler(); register_async_signal_handler(SIGHUP, sighup_handler); register_async_signal_handler_oneshot(SIGINT, handle_mds_signal); register_async_signal_handler_oneshot(SIGTERM, handle_mds_signal); if (g_conf->inject_early_sigterm) kill(getpid(), SIGTERM); messenger->wait(); unregister_async_signal_handler(SIGHUP, sighup_handler); unregister_async_signal_handler(SIGINT, handle_mds_signal); unregister_async_signal_handler(SIGTERM, handle_mds_signal); shutdown_async_signal_handler(); shutdown: // yuck: grab the mds lock, so we can be sure that whoever in *mds // called shutdown finishes what they were doing. mds->mds_lock.Lock(); mds->mds_lock.Unlock(); pidfile_remove(); // only delete if it was a clean shutdown (to aid memory leak // detection, etc.). don't bother if it was a suicide. if (mds->is_stopped()) delete mds; g_ceph_context->put(); // cd on exit, so that gmon.out (if any) goes into a separate directory for each node. char s[20]; snprintf(s, sizeof(s), "gmon/%d", getpid()); if ((mkdir(s, 0755) == 0) && (chdir(s) == 0)) { cerr << "ceph-mds: gmon.out should be in " << s << std::endl; } return 0; } ceph-0.80.11/src/vstart.sh0000775000175100017510000003703312623076744017354 0ustar jenkins-buildjenkins-build#!/bin/sh export PYTHONPATH=./pybind export LD_LIBRARY_PATH=.libs export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH # abort on failure set -e [ -z "$CEPH_NUM_MON" ] && CEPH_NUM_MON="$MON" [ -z "$CEPH_NUM_OSD" ] && CEPH_NUM_OSD="$OSD" [ -z "$CEPH_NUM_MDS" ] && CEPH_NUM_MDS="$MDS" [ -z "$CEPH_NUM_RGW" ] && CEPH_NUM_RGW="$RGW" [ -z "$CEPH_NUM_MON" ] && CEPH_NUM_MON=3 [ -z "$CEPH_NUM_OSD" ] && CEPH_NUM_OSD=1 [ -z "$CEPH_NUM_MDS" ] && CEPH_NUM_MDS=3 [ -z "$CEPH_NUM_RGW" ] && CEPH_NUM_RGW=1 [ -z "$CEPH_DIR" ] && CEPH_DIR="$PWD/" [ -z "$CEPH_DEV_DIR" ] && CEPH_DEV_DIR="$CEPH_DIR/dev" [ -z "$CEPH_OUT_DIR" ] && CEPH_OUT_DIR="$CEPH_DIR/out" [ -z "$CEPH_RGW_PORT" ] && CEPH_RGW_PORT=8000 extra_conf="" new=0 standby=0 debug=0 start_all=1 start_mon=0 start_mds=0 start_osd=0 start_rgw=0 ip="" nodaemon=0 smallmds=0 hitset="" overwrite_conf=1 cephx=1 #turn cephx on by default cache="" memstore=0 MON_ADDR="" conf="$CEPH_DIR/ceph.conf" keyring_fn="$CEPH_DIR/keyring" osdmap_fn="/tmp/ceph_osdmap.$$" monmap_fn="/tmp/ceph_monmap.$$" usage="usage: $0 [option]... [mon] [mds] [osd]\n" usage=$usage"options:\n" usage=$usage"\t-d, --debug\n" usage=$usage"\t-s, --standby_mds: Generate standby-replay MDS for each active\n" usage=$usage"\t-l, --localhost: use localhost instead of hostname\n" usage=$usage"\t-i : bind to specific ip\n" usage=$usage"\t-r start radosgw (needs ceph compiled with --radosgw and apache2 with mod_fastcgi)\n" usage=$usage"\t-n, --new\n" usage=$usage"\t--valgrind[_{osd,mds,mon}] 'toolname args...'\n" usage=$usage"\t--nodaemon: use ceph-run as wrapper for mon/osd/mds\n" usage=$usage"\t--smallmds: limit mds cache size\n" usage=$usage"\t-m ip:port\t\tspecify monitor address\n" usage=$usage"\t-k keep old configuration files\n" usage=$usage"\t-x enable cephx (on by default)\n" usage=$usage"\t-X disable cephx\n" usage=$usage"\t--hitset : enable hitset tracking\n" usage=$usage"\t-o config\t\t add extra config parameters to mds section\n" usage_exit() { printf "$usage" exit } while [ $# -ge 1 ]; do case $1 in -d | --debug ) debug=1 ;; -s | --standby_mds) standby=1 ;; -l | --localhost ) ip="127.0.0.1" ;; -i ) [ -z "$2" ] && usage_exit ip="$2" shift ;; -r ) start_rgw=1 ;; --new | -n ) new=1 ;; --valgrind ) [ -z "$2" ] && usage_exit valgrind=$2 shift ;; --valgrind_mds ) [ -z "$2" ] && usage_exit valgrind_mds=$2 shift ;; --valgrind_osd ) [ -z "$2" ] && usage_exit valgrind_osd=$2 shift ;; --valgrind_mon ) [ -z "$2" ] && usage_exit valgrind_mon=$2 shift ;; --nodaemon ) nodaemon=1 ;; --smallmds ) smallmds=1 ;; mon ) start_mon=1 start_all=0 ;; mds ) start_mds=1 start_all=0 ;; osd ) start_osd=1 start_all=0 ;; -m ) [ -z "$2" ] && usage_exit MON_ADDR=$2 shift ;; -x ) cephx=1 # this is on be default, flag exists for historical consistency ;; -X ) cephx=0 ;; -k ) overwrite_conf=0 ;; --memstore ) memstore=1 ;; --hitset ) hitset="$hitset $2 $3" shift shift ;; -o ) extra_conf="$extra_conf $2 " shift ;; --cache ) if [ -z "$cache" ]; then cache="$2" else cache="$cache $2" fi shift ;; * ) usage_exit esac shift done if [ "$start_all" -eq 1 ]; then start_mon=1 start_mds=1 start_osd=1 fi ARGS="-c $conf" run() { type=$1 shift eval "valg=\$valgrind_$type" [ -z "$valg" ] && valg="$valgrind" if [ -n "$valg" ]; then echo "valgrind --tool=$valg $* -f &" valgrind --tool=$valg $* -f & sleep 1 else if [ "$nodaemon" -eq 0 ]; then echo "$*" $* else echo "ceph-run $* -f &" ./ceph-run $* -f & fi fi } if [ "$debug" -eq 0 ]; then CMONDEBUG=' debug mon = 10 debug ms = 1' COSDDEBUG=' debug ms = 1' CMDSDEBUG=' debug ms = 1' else echo "** going verbose **" CMONDEBUG=' debug mon = 20 debug paxos = 20 debug auth = 20 debug ms = 1' COSDDEBUG=' debug ms = 1 debug osd = 25 debug objecter = 20 debug monc = 20 debug journal = 20 debug filestore = 20 debug objclass = 20' CMDSDEBUG=' debug ms = 1 debug mds = 20 debug auth = 20 debug monc = 20 mds debug scatterstat = true mds verify scatter = true mds log max segments = 2' fi if [ -n "$MON_ADDR" ]; then CMON_ARGS=" -m "$MON_ADDR COSD_ARGS=" -m "$MON_ADDR CMDS_ARGS=" -m "$MON_ADDR fi if [ "$memstore" -eq 1 ]; then COSDMEMSTORE=' osd objectstore = memstore' fi # lockdep everywhere? # export CEPH_ARGS="--lockdep 1" [ -z "$CEPH_BIN" ] && CEPH_BIN=. [ -z "$CEPH_PORT" ] && CEPH_PORT=6789 # sudo if btrfs test -d $CEPH_DEV_DIR/osd0/. && test -e $CEPH_DEV_DIR/sudo && SUDO="sudo" if [ "$start_all" -eq 1 ]; then $SUDO $CEPH_BIN/init-ceph stop fi $SUDO rm -f core* test -d $CEPH_OUT_DIR || mkdir $CEPH_OUT_DIR test -d $CEPH_DEV_DIR || mkdir $CEPH_DEV_DIR $SUDO rm -rf $CEPH_OUT_DIR/* test -d gmon && $SUDO rm -rf gmon/* [ "$cephx" -eq 1 ] && [ "$new" -eq 1 ] && test -e $keyring_fn && rm $keyring_fn # figure machine's ip HOSTNAME=`hostname` if [ -n "$ip" ]; then IP="$ip" else echo hostname $HOSTNAME RAW_IP=`hostname -I` # filter out IPv6 and localhost addresses IP="$(echo "$RAW_IP"|tr ' ' '\012'|grep -v :|grep -v '^127\.'|head -n1)" # if that left nothing, then try to use the raw thing, it might work if [ -z "$IP" ]; then IP="$RAW_IP"; fi echo ip $IP fi echo "ip $IP" if [ "$cephx" -eq 1 ]; then CEPH_ADM="$CEPH_BIN/ceph -c $conf -k $keyring_fn" else CEPH_ADM="$CEPH_BIN/ceph -c $conf" fi MONS="" count=0 for f in a b c d e f g h i j k l m n o p q r s t u v w x y z do if [ -z "$MONS" ]; then MONS="$f" else MONS="$MONS $f" fi count=$(($count + 1)) [ $count -eq $CEPH_NUM_MON ] && break; done DAEMONOPTS=" log file = $CEPH_OUT_DIR/\$name.log admin socket = $CEPH_OUT_DIR/\$name.asok chdir = \"\" pid file = $CEPH_OUT_DIR/\$name.pid heartbeat file = $CEPH_OUT_DIR/\$name.heartbeat " if [ "$start_mon" -eq 1 ]; then if [ "$new" -eq 1 ]; then if [ $overwrite_conf -eq 1 ]; then cat < $conf ; generated by vstart.sh on `date` [global] fsid = $(uuidgen) osd pg bits = 3 osd pgp bits = 5 ; (invalid, but ceph should cope!) osd crush chooseleaf type = 0 osd pool default min size = 1 osd pool default erasure code directory = .libs osd pool default erasure code profile = plugin=jerasure technique=reed_sol_van k=2 m=1 ruleset-failure-domain=osd run dir = $CEPH_OUT_DIR EOF if [ "$cephx" -eq 1 ] ; then cat <> $conf auth supported = cephx EOF else cat <> $conf auth cluster required = none auth service required = none auth client required = none EOF fi cat <> $conf [client] keyring = $keyring_fn log file = $CEPH_OUT_DIR/\$name.\$pid.log [mds] $DAEMONOPTS $CMDSDEBUG mds debug frag = true mds debug auth pins = true mds debug subtrees = true mds data = $CEPH_DEV_DIR/mds.\$id $extra_conf [osd] $DAEMONOPTS osd data = $CEPH_DEV_DIR/osd\$id osd journal = $CEPH_DEV_DIR/osd\$id.journal osd journal size = 100 osd class tmp = out osd class dir = .libs osd scrub load threshold = 5.0 osd debug op order = true $COSDDEBUG $COSDMEMSTORE $extra_conf [mon] mon pg warn min per osd = 3 mon osd allow primary affinity = true $DAEMONOPTS $CMONDEBUG $extra_conf mon cluster log file = $CEPH_OUT_DIR/cluster.mon.\$id.log [global] $extra_conf EOF fi if [ `echo $IP | grep '^127\\.'` ] then echo echo "NOTE: hostname resolves to loopback; remote hosts will not be able to" echo " connect. either adjust /etc/hosts, or edit this script to use your" echo " machine's real IP." echo fi $SUDO $CEPH_BIN/ceph-authtool --create-keyring --gen-key --name=mon. $keyring_fn --cap mon 'allow *' $SUDO $CEPH_BIN/ceph-authtool --gen-key --name=client.admin --set-uid=0 \ --cap mon 'allow *' \ --cap osd 'allow *' \ --cap mds allow \ $keyring_fn # build a fresh fs monmap, mon fs str="$CEPH_BIN/monmaptool --create --clobber" count=0 for f in $MONS do str=$str" --add $f $IP:$(($CEPH_PORT+$count))" if [ $overwrite_conf -eq 1 ]; then cat <> $conf [mon.$f] host = $HOSTNAME mon data = $CEPH_DEV_DIR/mon.$f mon addr = $IP:$(($CEPH_PORT+$count)) EOF fi count=$(($count + 1)) done str=$str" --print $monmap_fn" echo $str $str for f in $MONS do cmd="rm -rf $CEPH_DEV_DIR/mon.$f" echo $cmd $cmd cmd="mkdir -p $CEPH_DEV_DIR/mon.$f" echo $cmd $cmd cmd="$CEPH_BIN/ceph-mon --mkfs -c $conf -i $f --monmap=$monmap_fn" cmd="$cmd --keyring=$keyring_fn" echo $cmd $cmd done rm $monmap_fn fi # start monitors if [ "$start_mon" -ne 0 ]; then for f in $MONS do run 'mon' $CEPH_BIN/ceph-mon -i $f $ARGS $CMON_ARGS done fi fi #osd if [ "$start_osd" -eq 1 ]; then for osd in `seq 0 $((CEPH_NUM_OSD-1))` do if [ "$new" -eq 1 ]; then if [ $overwrite_conf -eq 1 ]; then cat <> $conf [osd.$osd] host = $HOSTNAME EOF rm -rf $CEPH_DEV_DIR/osd$osd || true for f in $CEPH_DEV_DIR/osd$osd/* ; do btrfs sub delete $f || true ; done || true mkdir -p $CEPH_DEV_DIR/osd$osd fi uuid=`uuidgen` echo "add osd$osd $uuid" $SUDO $CEPH_ADM osd create $uuid $SUDO $CEPH_ADM osd crush add osd.$osd 1.0 host=$HOSTNAME root=default $SUDO $CEPH_BIN/ceph-osd -i $osd $ARGS --mkfs --mkkey --osd-uuid $uuid key_fn=$CEPH_DEV_DIR/osd$osd/keyring echo adding osd$osd key to auth repository $SUDO $CEPH_ADM -i $key_fn auth add osd.$osd osd "allow *" mon "allow profile osd" fi echo start osd$osd run 'osd' $SUDO $CEPH_BIN/ceph-osd -i $osd $ARGS $COSD_ARGS done fi # mds if [ "$smallmds" -eq 1 ]; then cat <> $conf [mds] mds log max segments = 2 mds cache size = 10000 EOF fi if [ "$start_mds" -eq 1 -a "$CEPH_NUM_MDS" -gt 0 ]; then mds=0 for name in a b c d e f g h i j k l m n o p do if [ "$new" -eq 1 ]; then mkdir -p $CEPH_DEV_DIR/mds.$name key_fn=$CEPH_DEV_DIR/mds.$name/keyring if [ $overwrite_conf -eq 1 ]; then cat <> $conf [mds.$name] host = $HOSTNAME EOF if [ "$standby" -eq 1 ]; then mkdir -p $CEPH_DEV_DIR/mds.${name}s cat <> $conf mds standby for rank = $mds [mds.${name}s] mds standby replay = true mds standby for name = ${name} EOF fi fi $SUDO $CEPH_BIN/ceph-authtool --create-keyring --gen-key --name=mds.$name $key_fn $SUDO $CEPH_ADM -i $key_fn auth add mds.$name mon 'allow profile mds' osd 'allow *' mds 'allow' if [ "$standby" -eq 1 ]; then $SUDO $CEPH_BIN/ceph-authtool --create-keyring --gen-key --name=mds.${name}s \ $CEPH_DEV_DIR/mds.${name}s/keyring $SUDO $CEPH_ADM -i $CEPH_DEV_DIR/mds.${name}s/keyring auth add mds.${name}s \ mon 'allow *' osd 'allow *' mds 'allow' fi fi run 'mds' $CEPH_BIN/ceph-mds -i $name $ARGS $CMDS_ARGS if [ "$standby" -eq 1 ]; then run 'mds' $CEPH_BIN/ceph-mds -i ${name}s $ARGS $CMDS_ARGS fi mds=$(($mds + 1)) [ $mds -eq $CEPH_NUM_MDS ] && break #valgrind --tool=massif $CEPH_BIN/ceph-mds $ARGS --mds_log_max_segments 2 --mds_thrash_fragments 0 --mds_thrash_exports 0 > m #--debug_ms 20 #$CEPH_BIN/ceph-mds -d $ARGS --mds_thrash_fragments 0 --mds_thrash_exports 0 #--debug_ms 20 #$CEPH_ADM mds set max_mds 2 done cmd="$CEPH_ADM mds set max_mds $CEPH_NUM_MDS" echo $cmd $cmd fi # rgw if [ "$start_rgw" -eq 1 ]; then for rgw in `seq 0 $((CEPH_NUM_RGW-1))` do rgwport=$(( $CEPH_RGW_PORT + $rgw )) if [ "$new" -eq 1 ]; then if [ $overwrite_conf -eq 1 ]; then dnsname=`hostname -f` cat <> $conf [client.radosgw.rgw$rgw] host = $HOSTNAME $DAEMONOPTS keyring = $CEPH_OUT_DIR/keyring.client.radosgw.rgw$rgw rgw socket path = $CEPH_OUT_DIR/sock.client.radosgw.rgw$rgw rgw dns name = $dnsname EOF mkdir -p $CEPH_OUT_DIR/htdocs mkdir -p $CEPH_OUT_DIR/fastcgi_sock APACHE2_MODULE_PATH="/usr/lib/apache2/modules" APACHE2_EXTRA_MODULES_NAME="mpm_prefork authz_core" for module in $APACHE2_EXTRA_MODULES_NAME do if [ -f "${APACHE2_MODULE_PATH}/mod_${module}.so" ]; then APACHE2_EXTRA_MODULES="${APACHE2_EXTRA_MODULES}LoadModule ${module}_module ${APACHE2_MODULE_PATH}/mod_${module}.so " fi done echo $APACHE2_EXTRA_MODULES cat < $CEPH_OUT_DIR/apache.conf LoadModule env_module /usr/lib/apache2/modules/mod_env.so LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so $APACHE2_EXTRA_MODULES Listen $rgwport ServerName rgwtest.example.com ServerRoot $CEPH_OUT_DIR ErrorLog $CEPH_OUT_DIR/apache.error.log LogFormat "%h l %u %t \"%r\" %>s %b \"{Referer}i\" \"%{User-agent}i\"" combined CustomLog $CEPH_OUT_DIR/apache.access.log combined PidFile $CEPH_OUT_DIR/apache.pid DocumentRoot $CEPH_OUT_DIR/htdocs FastCgiIPCDir $CEPH_OUT_DIR/fastcgi_sock FastCgiExternalServer $CEPH_OUT_DIR/htdocs/rgw.fcgi -socket $CEPH_OUT_DIR/sock.client.radosgw.rgw$rgw RewriteEngine On RewriteRule ^/([a-zA-Z0-9-_.]*)([/]?.*) /rgw.fcgi?page=$1¶ms=$2&%{QUERY_STRING} [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] # Set fastcgi environment variables. # Note that this is separate from Unix environment variables! SetEnv RGW_LOG_LEVEL 20 SetEnv RGW_PRINT_CONTINUE yes SetEnv RGW_SHOULD_LOG yes Options +ExecCGI AllowOverride All SetHandler fastcgi-script AllowEncodedSlashes On ServerSignature Off EOF $SUDO $CEPH_ADM auth get-or-create client.radosgw.rgw$rgw osd 'allow rwx' mon 'allow r' -o $CEPH_OUT_DIR/keyring.client.radosgw.rgw$rgw #akey=`echo $$ | md5sum | cut -c 1-20` #skey=`dd if=/dev/urandom of=/tmp/random.$$ bs=1 count=40 2>/dev/null ; base64 < /tmp/random.$$ ; rm /tmp/random.$$` akey='0555b35654ad1656d804' skey='h7GhxuBLTrlhVUyxSPUKUV8r/2EI4ngqJxD7iBdBYLhwluN30JaT3Q==' echo access key $akey echo secret key $skey $CEPH_BIN/radosgw-admin user create --uid tester --access-key $akey --secret $skey --display-name 'M. Tester' --email tester@ceph.com -c $conf fi fi echo start rgw$rgw on http://localhost:$rgwport run 'rgw' $SUDO $CEPH_BIN/radosgw -n client.radosgw.rgw$rgw $ARGS run 'apache2' $SUDO apache2 -f $CEPH_OUT_DIR/apache.conf done fi echo "started. stop.sh to stop. see out/* (e.g. 'tail -f out/????') for debug output." do_cache() { while [ -n "$*" ]; do p="$1" shift echo "creating cache for pool $p ..." $SUDO $CEPH_ADM < #include int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/fused-src/gtest/gtest.h0000664000175100017510000265104512623077036023142 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include // Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan) // // Low-level types and utilities for porting Google Test to various // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro // in this list, Google Test will define it. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::string, which is different to std::string). // GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::wstring, which is different to std::wstring). // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple // is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets // GTEST_HAS_TR1_TUPLE to 0. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // This header defines the following utilities: // // Macros indicating the current platform (defined to 1 if compiled on // the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_LINUX - Linux // GTEST_OS_MAC - Mac OS X // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // Note that it is possible that none of the GTEST_OS_* macros are defined. // // Macros indicating available Google Test features (defined to 1 if // the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above two are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // GTEST_IS_THREADSAFE - defined to 1 to indicate that the above // synchronization primitives have real implementations // and Google Test is thread-safe; or 0 otherwise. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax. Not available on // Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. #include // For ptrdiff_t #include #include #include #ifndef _WIN32_WCE #include #endif // !_WIN32_WCE #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_DASH_ "gtest-" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" #define GTEST_NAME_ "Google Test" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. #define GTEST_GCC_VER_ \ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ #define GTEST_OS_CYGWIN 1 #elif defined __SYMBIAN32__ #define GTEST_OS_SYMBIAN 1 #elif defined _WIN32 #define GTEST_OS_WINDOWS 1 #ifdef _WIN32_WCE #define GTEST_OS_WINDOWS_MOBILE 1 #elif defined(__MINGW__) || defined(__MINGW32__) #define GTEST_OS_WINDOWS_MINGW 1 #else #define GTEST_OS_WINDOWS_DESKTOP 1 #endif // _WIN32_WCE #elif defined __APPLE__ #define GTEST_OS_MAC 1 #elif defined __linux__ #define GTEST_OS_LINUX 1 #elif defined __MVS__ #define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) #define GTEST_OS_SOLARIS 1 #elif defined(_AIX) #define GTEST_OS_AIX 1 #endif // __CYGWIN__ #if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \ GTEST_OS_SOLARIS || GTEST_OS_AIX // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS #if !GTEST_OS_WINDOWS_MOBILE #include // NOLINT #include // NOLINT #endif // is not available on Windows. Use our own simple regex // implementation instead. #define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. #define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. #ifndef _HAS_EXCEPTIONS #define _HAS_EXCEPTIONS 1 #endif // _HAS_EXCEPTIONS #define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS #elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. #define GTEST_HAS_EXCEPTIONS 1 #elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. #define GTEST_HAS_EXCEPTIONS 1 #elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. #define GTEST_HAS_EXCEPTIONS 1 #else // For other compilers, we assume exceptions are disabled to be // conservative. #define GTEST_HAS_EXCEPTIONS 0 #endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #if !defined(GTEST_HAS_STD_STRING) // Even though we don't use this macro any longer, we keep it in case // some clients still depend on it. #define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. #error "Google Test cannot be used where ::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING // The user didn't tell us whether ::string is available, so we need // to figure it out. #define GTEST_HAS_GLOBAL_STRING 0 #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // TODO(wan@google.com): uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.5 and below doesn't support ::std::wstring. // Cygwin 1.7 might add wstring support; this should be updated when clear. // Solaris' libc++ doesn't support it either. #define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) #endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_GLOBAL_WSTRING // The user didn't tell us whether ::wstring is available, so we need // to figure it out. #define GTEST_HAS_GLOBAL_WSTRING \ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) #endif // GTEST_HAS_GLOBAL_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. #ifdef _MSC_VER #ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. #define GTEST_HAS_RTTI 1 #else #define GTEST_HAS_RTTI 0 #endif // Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. #elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) #ifdef __GXX_RTTI #define GTEST_HAS_RTTI 1 #else #define GTEST_HAS_RTTI 0 #endif // __GXX_RTTI // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. #elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) #ifdef __RTTI_ALL__ #define GTEST_HAS_RTTI 1 #else #define GTEST_HAS_RTTI 0 #endif #else // For all other compilers, we assume RTTI is enabled. #define GTEST_HAS_RTTI 1 #endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI #include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we assume pthreads support is // available on Linux and Mac. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. #define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) #endif // GTEST_HAS_PTHREAD // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). #ifndef GTEST_HAS_TR1_TUPLE // The user didn't tell us not to do it, so we assume it's OK. #define GTEST_HAS_TR1_TUPLE 1 #endif // GTEST_HAS_TR1_TUPLE // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an // implementation of it already. At this time, GCC 4.0.0+ and MSVC // 2010 are the only mainstream compilers that come with a TR1 tuple // implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by // defining __GNUC__ and friends, but cannot compile GCC's tuple // implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB // Feature Pack download, which we cannot assume the user has. #if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ || _MSC_VER >= 1600 #define GTEST_USE_OWN_TR1_TUPLE 0 #else #define GTEST_USE_OWN_TR1_TUPLE 1 #endif #endif // GTEST_USE_OWN_TR1_TUPLE // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tr1/tuple. #if GTEST_HAS_TR1_TUPLE #if GTEST_USE_OWN_TR1_TUPLE // This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2009 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) #define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else #define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // GTEST_n_TYPENAMES_(T) declares a list of n typenames. #define GTEST_0_TYPENAMES_(T) #define GTEST_1_TYPENAMES_(T) typename T##0 #define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 #define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 #define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3 #define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4 #define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5 #define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6 #define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 #define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8 #define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8, typename T##9 // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), f1_(f1) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} template tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; return *this; } T0 f0_; T1 f1_; T2 f2_; }; template class GTEST_4_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), f3_(f3) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} template tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; }; template class GTEST_5_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} template tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; }; template class GTEST_6_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} template tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; }; template class GTEST_7_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} template tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; }; template class GTEST_8_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} template tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; }; template class GTEST_9_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} template tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; }; template class tuple { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), f9_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} template tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; f9_ = t.f9_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; T9 f9_; }; // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { return GTEST_3_TUPLE_(T)(f0, f1, f2); } template inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3) { return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); } template inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4) { return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); } template inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5) { return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); } template inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6) { return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); } template inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); } template inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8) { return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); } template inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8, const T9& f9) { return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } // 6.1.3.3 Tuple helper classes. template struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std #undef GTEST_0_TUPLE_ #undef GTEST_1_TUPLE_ #undef GTEST_2_TUPLE_ #undef GTEST_3_TUPLE_ #undef GTEST_4_TUPLE_ #undef GTEST_5_TUPLE_ #undef GTEST_6_TUPLE_ #undef GTEST_7_TUPLE_ #undef GTEST_8_TUPLE_ #undef GTEST_9_TUPLE_ #undef GTEST_10_TUPLE_ #undef GTEST_0_TYPENAMES_ #undef GTEST_1_TYPENAMES_ #undef GTEST_2_TYPENAMES_ #undef GTEST_3_TYPENAMES_ #undef GTEST_4_TYPENAMES_ #undef GTEST_5_TYPENAMES_ #undef GTEST_6_TYPENAMES_ #undef GTEST_7_TYPENAMES_ #undef GTEST_8_TYPENAMES_ #undef GTEST_9_TYPENAMES_ #undef GTEST_10_TYPENAMES_ #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // use STLport's tuple implementation, which unfortunately doesn't // work as the copy of STLport distributed with Symbian is incomplete. // By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to // use its own tuple implementation. #ifdef BOOST_HAS_TR1_TUPLE #undef BOOST_HAS_TR1_TUPLE #endif // BOOST_HAS_TR1_TUPLE // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . #define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED #include #elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . #if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. #define _TR1_FUNCTIONAL 1 #include #undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. #else #include // NOLINT #endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 #else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. #include // NOLINT #endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. #if GTEST_OS_LINUX && !defined(__ia64__) #define GTEST_HAS_CLONE 1 #else #define GTEST_HAS_CLONE 0 #endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #define GTEST_HAS_STREAM_REDIRECTION_ 1 #endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX) #define GTEST_HAS_DEATH_TEST 1 #include // NOLINT #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore // all the compilers we care about are adequate for supporting // value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, and IBM Visual Age support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) #define GTEST_HAS_TYPED_TEST 1 #define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether to support Combine(). This only makes sense when // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. #if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) #define GTEST_HAS_COMBINE 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER #define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else #define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) #define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else #define GTEST_ATTRIBUTE_UNUSED_ #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type)\ void operator=(type const &) // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ type(type const &);\ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) #define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else #define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. #if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. #define GTEST_HAS_SEH 1 #else // Assume no SEH. #define GTEST_HAS_SEH 0 #endif #endif // GTEST_HAS_SEH #ifdef _MSC_VER #if GTEST_LINKED_AS_SHARED_LIBRARY #define GTEST_API_ __declspec(dllimport) #elif GTEST_CREATE_SHARED_LIBRARY #define GTEST_API_ __declspec(dllexport) #endif #endif // _MSC_VER #ifndef GTEST_API_ #define GTEST_API_ #endif namespace testing { class Message; namespace internal { class String; typedef ::std::stringstream StrStream; // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines scoped_ptr. // This implementation of scoped_ptr is PARTIAL - it only contains // enough stuff to satisfy Google Test's need. template class scoped_ptr { public: typedef T element_type; explicit scoped_ptr(T* p = NULL) : ptr_(p) {} ~scoped_ptr() { reset(); } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } T* release() { T* const ptr = ptr_; ptr_ = NULL; return ptr; } void reset(T* p = NULL) { if (p != ptr_) { if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. delete ptr_; } ptr_ = p; } } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT #if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT #endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true iff regular expression re matches // the entire str. // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // // TODO(wan@google.com): make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); // We use a const char* instead of a string, as Google Test may be used // where string is not available. We also do not use Google Test's own // String type here, in order to simplify dependencies between the // files. const char* pattern_; bool is_valid_; #if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). #else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); #endif GTEST_DISALLOW_ASSIGN_(RE); }; // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. #define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION_ // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ String GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ String GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector g_argvs; // GTEST_HAS_DEATH_TEST implies we have ::std::string. const ::std::vector& GetArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milli-seconds. This function is only for // testing Google Test's own constructs. Don't use it in user tests, // either directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, NULL); } // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) {} // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { notified_ = true; } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { while(!notified_) { SleepMilliseconds(10); } } private: volatile bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return NULL; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void (*UserThreadFunc)(T); ThreadWithParam( UserThreadFunc func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); finished_ = true; } } virtual void Run() { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); } private: const UserThreadFunc func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true iff we know that the thread function has finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. #include // MutexBase and Mutex implement mutex on pthreads-based platforms. They // are used in conjunction with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the end // // of the current scope. // // MutexBase implements behavior for both statically and dynamically // allocated mutexes. Do not use MutexBase directly. Instead, write // the following to define a static mutex: // // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // // You can forward declare a static mutex like this: // // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // To create a dynamic mutex, just define an object of type Mutex. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); } // Releases this mutex. void Unlock() { // We don't protect writing to owner_ here, as it's the caller's // responsibility to ensure that the current thread holds the // mutex when this is called. owner_ = 0; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(owner_ == pthread_self()) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. }; // Forward-declares a static mutex. #define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. #define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); owner_ = 0; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock as the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // An object managed for a thread by a ThreadLocal instance is deleted // when the thread exits. Or, if the ThreadLocal instance dies in // that thread, when the ThreadLocal dies. It's the user's // responsibility to ensure that all other threads using a ThreadLocal // have exited when it dies, or the per-thread objects for those // threads will not be deleted. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_() {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_(value) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = new ValueHolder(default_); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; const T default_; // The default value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; #define GTEST_IS_THREADSAFE 1 #else // GTEST_HAS_PTHREAD // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void AssertHeld() const {} }; #define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex #define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. #define GTEST_IS_THREADSAFE 0 #endif // GTEST_HAS_PTHREAD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). #define GTEST_ELLIPSIS_NEEDS_POD_ 1 #else #define GTEST_CAN_COMPARE_NULL 1 #endif // The Nokia Symbian and IBM XL C/C++ compilers cannot decide between // const T& and const T* in a function template. These compilers // _can_ decide between class template specializations for T and T*, // so a tr1::type_traits-like is_pointer works. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) #define GTEST_NEEDS_IS_POINTER_ 1 #endif template struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; #if GTEST_OS_WINDOWS #define GTEST_PATH_SEP_ "\\" #define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else #define GTEST_PATH_SEP_ "/" #define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; #ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } #else // !__BORLANDC__ #if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } #else inline int IsATTY(int fd) { return _isatty(fd); } #endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } #endif // __BORLANDC__ #if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. #else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } #endif // GTEST_OS_WINDOWS_MOBILE #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. #ifdef _MSC_VER // Temporarily disable warning 4996 (deprecated function). #pragma warning(push) #pragma warning(disable:4996) #endif inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); } // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != NULL && env[0] != '\0') ? env : NULL; #else return getenv(name); #endif } #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. void Abort(); #else inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name // Macros for declaring flags. #define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) #define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) #define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. // TODO(chandlerc): Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #if GTEST_OS_LINUX #include #include #include #include #endif // GTEST_OS_LINUX #include #include #include #include #include // Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // // This header file is #included by . // It should not be #included by other files. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. #include #endif #include #include namespace testing { namespace internal { // String - a UTF-8 string class. // // For historic reasons, we don't use std::string. // // TODO(wan@google.com): replace this class with std::string or // implement it in terms of the latter. // // Note that String can represent both NULL and the empty string, // while std::string cannot represent NULL. // // NULL and the empty string are considered different. NULL is less // than anything (including the empty string) except itself. // // This class only provides minimum functionality necessary for // implementing Google Test. We do not intend to implement a full-fledged // string class here. // // Since the purpose of this class is to provide a substitute for // std::string on platforms where it cannot be used, we define a copy // constructor and assignment operators such that we don't need // conditional compilation in a lot of places. // // In order to make the representation efficient, the d'tor of String // is not virtual. Therefore DO NOT INHERIT FROM String. class GTEST_API_ String { public: // Static utility methods // Returns the input enclosed in double quotes if it's not NULL; // otherwise returns "(null)". For example, "\"Hello\"" is returned // for input "Hello". // // This is useful for printing a C string in the syntax of a literal. // // Known issue: escape sequences are not handled yet. static String ShowCStringQuoted(const char* c_str); // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting the return value using // delete[]. Returns the cloned string, or NULL if the input is // NULL. // // This is different from strdup() in string.h, which allocates // memory using malloc(). static const char* CloneCString(const char* c_str); #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be // able to pass strings to Win32 APIs on CE we need to convert them // to 'Unicode', UTF-16. // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. // // The wide string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static LPCWSTR AnsiToUtf16(const char* c_str); // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. // // The returned string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CStringEquals(const char* lhs, const char* rhs); // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". If an error occurred during // the conversion, "(failed to convert from wide string)" is // returned. static String ShowWideCString(const wchar_t* wide_c_str); // Similar to ShowWideCString(), except that this function encloses // the converted string in double quotes. static String ShowWideCStringQuoted(const wchar_t* wide_c_str); // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Compares two C strings, ignoring case. Returns true iff they // have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Formats a list of arguments to a String, using the same format // spec string as for printf. // // We do not use the StringPrintf class as it is not universally // available. // // The result is limited to 4096 characters (including the tailing // 0). If 4096 characters are not enough to format the input, // "" is returned. static String Format(const char* format, ...); // C'tors // The default c'tor constructs a NULL string. String() : c_str_(NULL), length_(0) {} // Constructs a String by cloning a 0-terminated C string. String(const char* a_c_str) { // NOLINT if (a_c_str == NULL) { c_str_ = NULL; length_ = 0; } else { ConstructNonNull(a_c_str, strlen(a_c_str)); } } // Constructs a String by copying a given number of chars from a // buffer. E.g. String("hello", 3) creates the string "hel", // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", // and String(NULL, 1) results in access violation. String(const char* buffer, size_t a_length) { ConstructNonNull(buffer, a_length); } // The copy c'tor creates a new copy of the string. The two // String objects do not share content. String(const String& str) : c_str_(NULL), length_(0) { *this = str; } // D'tor. String is intended to be a final class, so the d'tor // doesn't need to be virtual. ~String() { delete[] c_str_; } // Allows a String to be implicitly converted to an ::std::string or // ::string, and vice versa. Converting a String containing a NULL // pointer to ::std::string or ::string is undefined behavior. // Converting a ::std::string or ::string containing an embedded NUL // character to a String will result in the prefix up to the first // NUL character. String(const ::std::string& str) { ConstructNonNull(str.c_str(), str.length()); } operator ::std::string() const { return ::std::string(c_str(), length()); } #if GTEST_HAS_GLOBAL_STRING String(const ::string& str) { ConstructNonNull(str.c_str(), str.length()); } operator ::string() const { return ::string(c_str(), length()); } #endif // GTEST_HAS_GLOBAL_STRING // Returns true iff this is an empty string (i.e. ""). bool empty() const { return (c_str() != NULL) && (length() == 0); } // Compares this with another String. // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 // if this is greater than rhs. int Compare(const String& rhs) const; // Returns true iff this String equals the given C string. A NULL // string and a non-NULL string are considered not equal. bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } // Returns true iff this String is less than the given String. A // NULL string is considered less than "". bool operator<(const String& rhs) const { return Compare(rhs) < 0; } // Returns true iff this String doesn't equal the given C string. A NULL // string and a non-NULL string are considered not equal. bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } // Returns true iff this String ends with the given suffix. *Any* // String is considered to end with a NULL or empty suffix. bool EndsWith(const char* suffix) const; // Returns true iff this String ends with the given suffix, not considering // case. Any String is considered to end with a NULL or empty suffix. bool EndsWithCaseInsensitive(const char* suffix) const; // Returns the length of the encapsulated string, or 0 if the // string is NULL. size_t length() const { return length_; } // Gets the 0-terminated C string this String object represents. // The String object still owns the string. Therefore the caller // should NOT delete the return value. const char* c_str() const { return c_str_; } // Assigns a C string to this object. Self-assignment works. const String& operator=(const char* a_c_str) { return *this = String(a_c_str); } // Assigns a String object to this object. Self-assignment works. const String& operator=(const String& rhs) { if (this != &rhs) { delete[] c_str_; if (rhs.c_str() == NULL) { c_str_ = NULL; length_ = 0; } else { ConstructNonNull(rhs.c_str(), rhs.length()); } } return *this; } private: // Constructs a non-NULL String from the given content. This // function can only be called when data_ has not been allocated. // ConstructNonNull(NULL, 0) results in an empty string (""). // ConstructNonNull(NULL, non_zero) is undefined behavior. void ConstructNonNull(const char* buffer, size_t a_length) { char* const str = new char[a_length + 1]; memcpy(str, buffer, a_length); str[a_length] = '\0'; c_str_ = str; length_ = a_length; } const char* c_str_; size_t length_; }; // class String // Streams a String to an ostream. Each '\0' character in the String // is replaced with "\\0". inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { if (str.c_str() == NULL) { os << "(null)"; } else { const char* const c_str = str.c_str(); for (size_t i = 0; i != str.length(); i++) { if (c_str[i] == '\0') { os << "\\0"; } else { os << c_str[i]; } } } return os; } // Gets the content of the StrStream's buffer as a String. Each '\0' // character in the buffer is replaced with "\\0". GTEST_API_ String StrStreamToString(StrStream* stream); // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". // Declared here but defined in gtest.h, so that it has access // to the definition of the Message class, required by the ARM // compiler. template String StreamableToString(const T& streamable); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ // Copyright 2008, Google Inc. // 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. // // Author: keith.ray@gmail.com (Keith Ray) // // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included in . // Do not include this header file separately! #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ namespace testing { namespace internal { // FilePath - a class for file and directory pathname manipulation which // handles platform-specific conventions (like the pathname separator). // Used for helper functions for naming files in a directory for xml output. // Except for Set methods, all methods are const or static, which provides an // "immutable value object" -- useful for peace of mind. // A FilePath with a value ending in a path separator ("like/this/") represents // a directory, otherwise it is assumed to represent a file. In either case, // it may or may not represent an actual file or directory in the file system. // Names are NOT checked for syntax correctness -- no checking for illegal // characters, malformed paths, etc. class GTEST_API_ FilePath { public: FilePath() : pathname_("") { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } explicit FilePath(const char* pathname) : pathname_(pathname) { Normalize(); } explicit FilePath(const String& pathname) : pathname_(pathname) { Normalize(); } FilePath& operator=(const FilePath& rhs) { Set(rhs); return *this; } void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } String ToString() const { return pathname_; } const char* c_str() const { return pathname_.c_str(); } // Returns the current working directory, or "" if unsuccessful. static FilePath GetCurrentDir(); // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. static FilePath MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension); // Given directory = "dir", relative_path = "test.xml", // returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. static FilePath ConcatPaths(const FilePath& directory, const FilePath& relative_path); // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. static FilePath GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension); // Returns true iff the path is NULL or "". bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } // If input name has a trailing separator character, removes it and returns // the name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath RemoveTrailingPathSeparator() const; // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveDirectoryName() const; // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveFileName() const; // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath RemoveExtension(const char* extension) const; // Creates directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create // directories for any reason. Will also return false if the FilePath does // not represent a directory (that is, it doesn't end with a path separator). bool CreateDirectoriesRecursively() const; // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool CreateFolder() const; // Returns true if FilePath describes something in the file-system, // either a file, directory, or whatever, and that something exists. bool FileOrDirectoryExists() const; // Returns true if pathname describes a directory in the file-system // that exists. bool DirectoryExists() const; // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool IsDirectory() const; // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool IsRootDirectory() const; // Returns true if pathname describes an absolute path. bool IsAbsolutePath() const; private: // Replaces multiple consecutive separators with a single separator. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // // A pathname with multiple consecutive separators may occur either through // user error or as a result of some scripts or APIs that generate a pathname // with a trailing separator. On other platforms the same API or script // may NOT generate a pathname with a trailing "/". Then elsewhere that // pathname may have another "/" and pathname components added to it, // without checking for the separator already being there. // The script language and operating system may allow paths like "foo//bar" // but some of the functions in FilePath will not handle that correctly. In // particular, RemoveTrailingPathSeparator() only removes one separator, and // it is called in CreateDirectoriesRecursively() assuming that it will change // a pathname from directory syntax (trailing separator) to filename syntax. // // On Windows this method also replaces the alternate path separator '/' with // the primary path separator '\\', so that for example "bar\\/\\foo" becomes // "bar\\foo". void Normalize(); // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FindLastPathSeparator() const; String pathname_; }; // class FilePath } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ // This file was GENERATED by command: // pump.py gtest-type-util.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). #ifdef __GLIBCXX__ #include #endif // __GLIBCXX__ namespace testing { namespace internal { // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // GetTypeName() returns a human-readable name of type T. template String GetTypeName() { #if GTEST_HAS_RTTI const char* const name = typeid(T).name(); #ifdef __GLIBCXX__ int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status); const String name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; #else return name; #endif // __GLIBCXX__ #else return ""; #endif // GTEST_HAS_RTTI } // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 Tail; }; } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { #define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; #define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 Tail; }; // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 type; }; // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; } // namespace internal } // namespace testing #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar // Google Test defines the testing::Message class to allow construction of // test messages via the << operator. The idea is that anything // streamable to std::ostream can be streamed to a testing::Message. // This allows a user to use his own types in Google Test assertions by // overloading the << operator. // // util/gtl/stl_logging-inl.h overloads << for STL containers. These // overloads cannot be defined in the std namespace, as that will be // undefined behavior. Therefore, they are defined in the global // namespace instead. // // C++'s symbol lookup rule (i.e. Koenig lookup) says that these // overloads are visible in either the std namespace or the global // namespace, but not other namespaces, including the testing // namespace which Google Test's Message class is in. // // To allow STL containers (and other types that has a << operator // defined in the global namespace) to be used in Google Test assertions, // testing::Message must access the custom << operator from the global // namespace. Hence this helper function. // // Note: Jeffrey Yasskin suggested an alternative fix by "using // ::operator<<;" in the definition of Message's operator<<. That fix // doesn't require a helper function, but unfortunately doesn't // compile with MSVC. template inline void GTestStreamToHelper(std::ostream* os, const T& val) { *os << val; } namespace testing { // Forward declaration of classes. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test cases. namespace internal { struct TraceInfo; // Information about a trace point. class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // How many times InitGoogleTest() has been called. extern int g_init_gtest_count; // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). Their return values have // different sizes, so we can use sizeof() to test which version is // picked by the compiler. These helpers have no implementations, as // we only need their signatures. // // Given IsNullLiteralHelper(x), the compiler will pick the first // version if x can be implicitly converted to Secret*, and pick the // second version otherwise. Since Secret is a secret and incomplete // type, the only expression a user can write that has type Secret* is // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. char IsNullLiteralHelper(Secret* p); char (&IsNullLiteralHelper(...))[2]; // NOLINT // A compile-time bool constant that is true if and only if x is a // null pointer literal (i.e. NULL or any 0-valued compile-time // integral constant). #ifdef GTEST_ELLIPSIS_NEEDS_POD_ // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). #define GTEST_IS_NULL_LITERAL_(x) false #else #define GTEST_IS_NULL_LITERAL_(x) \ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) #endif // GTEST_ELLIPSIS_NEEDS_POD_ // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ String AppendUserMessage(const String& gtest_msg, const Message& user_msg); // A helper class for creating scoped traces in user programs. class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. ScopedTrace(const char* file, int line, const Message& message); // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". // Declared here but defined in gtest.h, so that it has access // to the definition of the Message class, required by the ARM // compiler. template String StreamableToString(const T& streamable); // Formats a value to be used in a failure message. #ifdef GTEST_NEEDS_IS_POINTER_ // These are needed as the Nokia Symbian and IBM XL C/C++ compilers // cannot decide between const T& and const T* in a function template. // These compilers _can_ decide between class template specializations // for T and T*, so a tr1::type_traits-like is_pointer works, and we // can overload on that. // This overload makes sure that all pointers (including // those to char or wchar_t) are printed as raw pointers. template inline String FormatValueForFailureMessage(internal::true_type /*dummy*/, T* pointer) { return StreamableToString(static_cast(pointer)); } template inline String FormatValueForFailureMessage(internal::false_type /*dummy*/, const T& value) { return StreamableToString(value); } template inline String FormatForFailureMessage(const T& value) { return FormatValueForFailureMessage( typename internal::is_pointer::type(), value); } #else // These are needed as the above solution using is_pointer has the // limitation that T cannot be a type without external linkage, when // compiled using MSVC. template inline String FormatForFailureMessage(const T& value) { return StreamableToString(value); } // This overload makes sure that all pointers (including // those to char or wchar_t) are printed as raw pointers. template inline String FormatForFailureMessage(T* pointer) { return StreamableToString(static_cast(pointer)); } #endif // GTEST_NEEDS_IS_POINTER_ // These overloaded versions handle narrow and wide characters. GTEST_API_ String FormatForFailureMessage(char ch); GTEST_API_ String FormatForFailureMessage(wchar_t wchar); // When this operand is a const char* or char*, and the other operand // is a ::std::string or ::string, we print this operand as a C string // rather than a pointer. We do the same for wide strings. // This internal macro is used to avoid duplicated code. #define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ inline String FormatForComparisonFailureMessage(\ operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ return operand1_printer(str);\ }\ inline String FormatForComparisonFailureMessage(\ const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ return operand1_printer(str);\ } GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) #if GTEST_HAS_STD_WSTRING GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_STRING GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) #endif // GTEST_HAS_GLOBAL_WSTRING #undef GTEST_FORMAT_IMPL_ // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const String& expected_value, const String& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ String GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8*sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true iff this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true iff this number is at most kMaxUlps ULP's away from // rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test case, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: virtual Test* CreateTest() { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Formats a source file path and a line number as they would appear // in a compiler error message. inline String FormatFileLocation(const char* file, int line) { const char* const file_name = file == NULL ? "unknown file" : file; if (line < 0) { return String::Format("%s:", file_name); } #ifdef _MSC_VER return String::Format("%s(%d):", file_name, line); #else return String::Format("%s:%d:", file_name, line); #endif // _MSC_VER } // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // test_case_comment: a comment on the test case that will be included in // the test output // comment: a comment on the test that will be included in the // test output // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: TypedTestCasePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test case hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } defined_test_names_.insert(test_name); return true; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: bool registered_; ::std::set defined_test_names_; }; // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == NULL) { return NULL; } while (isspace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline String GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? String(str) : String(str, comma - str); } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", case_name, index).c_str(), GetPrefixUntilComma(test_names).c_str(), String::Format("TypeParam = %s", GetTypeName().c_str()).c_str(), "", GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, const char* case_name, const char* test_names) { typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_(message, result_type) \ ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \ = ::testing::Message() #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) // Suppresses MSVC warnings 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg = "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different " \ "type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg = "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_msg) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail(gtest_msg) #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ gtest_msg = "Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail(gtest_msg) // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ gtest_msg = "Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail(gtest_msg) // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ test_case_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ public:\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ private:\ virtual void TestBody();\ static ::testing::TestInfo* const test_info_;\ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ };\ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ ::test_info_ =\ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, "", "", \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ new ::testing::internal::TestFactoryImpl<\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ namespace testing { namespace internal { GTEST_DECLARE_string_(internal_run_death_test); // Names of the flags (needed for parsing Google Test flags). const char kDeathTestStyleFlag[] = "death_test_style"; const char kDeathTestUseFork[] = "death_test_use_fork"; const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test // style, as defined by the --gtest_death_test_style and/or // --gtest_internal_run_death_test flags. // In describing the results of death tests, these terms are used with // the corresponding definitions: // // exit status: The integer exit information in the format specified // by wait(2) // exit code: The integer code passed to exit(3), _exit(2), or // returned from main() class GTEST_API_ DeathTest { public: // Create returns false if there was an error determining the // appropriate action to take for the current death test; for example, // if the gtest_death_test_style flag is set to an invalid value. // The LastMessage method will return a more detailed message in that // case. Otherwise, the DeathTest pointer pointed to by the "test" // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } // A helper class that aborts a death test when it's deleted. class ReturnSentinel { public: explicit ReturnSentinel(DeathTest* test) : test_(test) { } ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } private: DeathTest* const test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); } GTEST_ATTRIBUTE_UNUSED_; // An enumeration of possible roles that may be taken when a death // test is encountered. EXECUTE means that the death test logic should // be executed immediately. OVERSEE means that the program should prepare // the appropriate environment for a child process to execute the death // test, then wait for it to complete. enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; // An enumeration of the two reasons that a test might be aborted. enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE }; // Assumes one of the above roles. virtual TestRole AssumeRole() = 0; // Waits for the death test to finish and returns its status. virtual int Wait() = 0; // Returns true if the death test passed; that is, the test process // exited during the test, its exit status matches a user-supplied // predicate, and its stderr output matches a user-supplied regular // expression. // The user-supplied predicate may be a macro expression rather // than a function pointer or functor, or else Wait and Passed could // be combined. virtual bool Passed(bool exit_status_ok) = 0; // Signals that the death test did not die as expected. virtual void Abort(AbortReason reason) = 0; // Returns a human-readable outcome message regarding the outcome of // the last death test. static const char* LastMessage(); static void set_last_death_test_message(const String& message); private: // A string containing a description of the outcome of the last death test. static String last_death_test_message_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. #define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ const ::testing::internal::RE& gtest_regex = (regex); \ ::testing::internal::DeathTest* gtest_dt; \ if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ __FILE__, __LINE__, >est_dt)) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ if (gtest_dt != NULL) { \ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ gtest_dt_ptr(gtest_dt); \ switch (gtest_dt->AssumeRole()) { \ case ::testing::internal::DeathTest::OVERSEE_TEST: \ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ break; \ case ::testing::internal::DeathTest::EXECUTE_TEST: { \ ::testing::internal::DeathTest::ReturnSentinel \ gtest_sentinel(gtest_dt); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ break; \ } \ } \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // A class representing the parsed contents of the // --gtest_internal_run_death_test flag, as it existed when // RUN_ALL_TESTS was called. class InternalRunDeathTestFlag { public: InternalRunDeathTestFlag(const String& a_file, int a_line, int an_index, int a_write_fd) : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} ~InternalRunDeathTestFlag() { if (write_fd_ >= 0) posix::Close(write_fd_); } String file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } private: String file_; int line_; int index_; int write_fd_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); }; // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); #else // GTEST_HAS_DEATH_TEST // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems // iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on // systems that support death tests. This allows one to write such a macro // on a system that does not support death tests and be sure that it will // compile on a death-test supporting system. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain // parameter iff EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that // this macro only accepts expressions that a macro such as // EXPECT_DEATH would accept. // terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED // and a return statement for ASSERT_DEATH_IF_SUPPORTED. // This ensures that ASSERT_DEATH_IF_SUPPORTED will not // compile inside functions where ASSERT_DEATH doesn't // compile. // // The branch that has an always false condition is used to ensure that // statement and regex are compiled (and thus syntactically correct) but // never executed. The unreachable code macro protects the terminator // statement from generating an 'unreachable code' warning in case // statement unconditionally returns or throws. The Message constructor at // the end allows the syntax of streaming additional messages into the // macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. #define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_LOG_(WARNING) \ << "Death tests are not supported on this platform.\n" \ << "Statement '" #statement "' cannot be verified."; \ } else if (::testing::internal::AlwaysFalse()) { \ ::testing::internal::RE::PartialMatch(".*", (regex)); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ terminator; \ } else \ ::testing::Message() #endif // GTEST_HAS_DEATH_TEST } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ namespace testing { // This flag controls the style of death tests. Valid values are "threadsafe", // meaning that the death test child process will re-execute the test binary // from the start, running only a single death test, or "fast", // meaning that the child process will execute the test logic immediately // after forking. GTEST_DECLARE_string_(death_test_style); #if GTEST_HAS_DEATH_TEST // The following macros are useful for writing death tests. // Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is // executed: // // 1. It generates a warning if there is more than one active // thread. This is because it's safe to fork() or clone() only // when there is a single thread. // // 2. The parent process clone()s a sub-process and runs the death // test in it; the sub-process exits with code 0 at the end of the // death test, if it hasn't exited already. // // 3. The parent process waits for the sub-process to terminate. // // 4. The parent process checks the exit code and error message of // the sub-process. // // Examples: // // ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); // for (int i = 0; i < 5; i++) { // EXPECT_DEATH(server.ProcessRequest(i), // "Invalid request .* in ProcessRequest()") // << "Failed to die on request " << i); // } // // ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); // // bool KilledBySIGHUP(int exit_code) { // return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; // } // // ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); // // On the regular expressions used in death tests: // // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // // On other platforms (e.g. Windows), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE // or POSIX extended regex syntax. For example, we don't support // union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and // repetition count ("x{5,7}"), among others. // // Below is the syntax that we do support. We chose it to be a // subset of both PCRE and POSIX extended regex, so it's easy to // learn wherever you come from. In the following: 'A' denotes a // literal character, period (.), or a single \\ escape sequence; // 'x' and 'y' denote regular expressions; 'm' and 'n' are for // natural numbers. // // c matches any literal character c // \\d matches any decimal digit // \\D matches any character that's not a decimal digit // \\f matches \f // \\n matches \n // \\r matches \r // \\s matches any ASCII whitespace, including \n // \\S matches any character that's not a whitespace // \\t matches \t // \\v matches \v // \\w matches any letter, _, or decimal digit // \\W matches any character that \\w doesn't match // \\c matches any literal character c, which must be a punctuation // . matches any single character except \n // A? matches 0 or 1 occurrences of A // A* matches 0 or many occurrences of A // A+ matches 1 or many occurrences of A // ^ matches the beginning of a string (not that of each line) // $ matches the end of a string (not that of each line) // xy matches x followed by y // // If you accidentally use PCRE or POSIX extended regex features // not implemented by us, you will get a run-time failure. In that // case, please try to rewrite your regular expression within the // above syntax. // // This implementation is *not* meant to be as highly tuned or robust // as a compiled regex library, but should perform well enough for a // death test, which already incurs significant overhead by launching // a child process. // // Known caveats: // // A "threadsafe" style death test obtains the path to the test // program from argv[0] and re-executes it in the sub-process. For // simplicity, the current implementation doesn't search the PATH // when launching the sub-process. This means that the user must // invoke the test program via a path that contains at least one // path separator (e.g. path/to/foo_test and // /absolute/path/to/bar_test are fine, but foo_test is not). This // is rarely a problem as people usually don't put the test binary // directory in PATH. // // TODO(wan@google.com): make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output // that matches regex. #define ASSERT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the // test case, if any: #define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) // Asserts that a given statement causes the program to exit, either by // explicitly exiting with a nonzero exit code or being killed by a // signal, and emitting error output that matches regex. #define ASSERT_DEATH(statement, regex) \ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the // test case, if any: #define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: // Tests that an exit code describes a normal exit with a given exit code. class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); bool operator()(int exit_status) const; private: // No implementation - assignment is unsupported. void operator=(const ExitedWithCode& other); const int exit_code_; }; #if !GTEST_OS_WINDOWS // Tests that an exit code describes an exit due to termination by a // given signal. class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); bool operator()(int exit_status) const; private: const int signum_; }; #endif // !GTEST_OS_WINDOWS // EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. // The death testing framework causes this to have interesting semantics, // since the sideeffects of the call are only visible in opt mode, and not // in debug mode. // // In practice, this can be used to test functions that utilize the // LOG(DFATAL) macro using the following style: // // int DieInDebugOr12(int* sideeffect) { // if (sideeffect) { // *sideeffect = 12; // } // LOG(DFATAL) << "death"; // return 12; // } // // TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); // // #ifdef NDEBUG // // opt-mode has sideeffect visible. // EXPECT_EQ(12, sideeffect); // #else // // dbg-mode no visible sideeffect. // EXPECT_EQ(0, sideeffect); // #endif // } // // This will assert that DieInDebugReturn12InOpt() crashes in debug // mode, usually due to a DCHECK or LOG(DFATAL), but returns the // appropriate fallback value (12 in this case) in opt mode. If you // need to test that a function has appropriate side-effects in opt // mode, include assertions against the side-effects. A general // pattern for this is: // // EXPECT_DEBUG_DEATH({ // // Side-effects here will have an effect after this statement in // // opt mode, but none in debug mode. // EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); // }, "death"); // #ifdef NDEBUG #define EXPECT_DEBUG_DEATH(statement, regex) \ do { statement; } while (::testing::internal::AlwaysFalse()) #define ASSERT_DEBUG_DEATH(statement, regex) \ do { statement; } while (::testing::internal::AlwaysFalse()) #else #define EXPECT_DEBUG_DEATH(statement, regex) \ EXPECT_DEATH(statement, regex) #define ASSERT_DEBUG_DEATH(statement, regex) \ ASSERT_DEATH(statement, regex) #endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is // useful when you are combining death test assertions with normal test // assertions in one test. #if GTEST_HAS_DEATH_TEST #define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ EXPECT_DEATH(statement, regex) #define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ ASSERT_DEATH(statement, regex) #else #define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) #define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) #endif } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the Message class. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include namespace testing { // The Message class works like an ostream repeater. // // Typical usage: // // 1. You stream a bunch of values to a Message object. // It will remember the text in a StrStream. // 2. Then you stream the Message object to an ostream. // This causes the text in the Message to be streamed // to the ostream. // // For example; // // testing::Message foo; // foo << 1 << " != " << 2; // std::cout << foo; // // will print "1 != 2". // // Message is not intended to be inherited from. In particular, its // destructor is not virtual. // // Note that StrStream behaves differently in gcc and in MSVC. You // can stream a NULL char pointer to it in the former, but not in the // latter (it causes an access violation if you do). The Message // class hides this difference by treating a NULL char pointer as // "(null)". class GTEST_API_ Message { private: // The type of basic IO manipulators (endl, ends, and flush) for // narrow streams. typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); public: // Constructs an empty Message. // We allocate the StrStream separately because it otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message() : ss_(new internal::StrStream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // Copy constructor. Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. explicit Message(const char* str) : ss_(new internal::StrStream) { *ss_ << str; } ~Message() { delete ss_; } #if GTEST_OS_SYMBIAN // Streams a value (either a pointer or not) to this object. template inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { ::GTestStreamToHelper(ss_, val); return *this; } // Streams a pointer value to this object. // // This function is an overload of the previous one. When you // stream a pointer to a Message, this definition will be used as it // is more specialized. (The C++ Standard, section // [temp.func.order].) If you stream a non-pointer, then the // previous definition will be used. // // The reason for this overload is that streaming a NULL pointer to // ostream is undefined behavior. Depending on the compiler, you // may get "0", "(nil)", "(null)", or an access violation. To // ensure consistent result across compilers, we always treat NULL // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT if (pointer == NULL) { *ss_ << "(null)"; } else { ::GTestStreamToHelper(ss_, pointer); } return *this; } #endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition // of operator <<, even though its body is the same as the // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. Message& operator <<(BasicNarrowIoManip val) { *ss_ << val; return *this; } // Instead of 1/0, we want to see true/false for bool values. Message& operator <<(bool b) { return *this << (b ? "true" : "false"); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::wstring& wstr); #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as a String. // Each '\0' character in the buffer is replaced with "\\0". // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::String GetString() const { return internal::StrStreamToString(ss_); } private: #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ // decide between class template specializations for T and T*, so a // tr1::type_traits-like is_pointer works, and we can overload on that. template inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { ::GTestStreamToHelper(ss_, pointer); } } template inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { ::GTestStreamToHelper(ss_, value); } #endif // GTEST_OS_SYMBIAN // We'll hold the text streamed to this object here. internal::StrStream* const ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. void operator=(const Message&); }; // Streams a Message to an ostream. inline std::ostream& operator <<(std::ostream& os, const Message& sb) { return os << sb.GetString(); } } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ // This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // 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. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It must be derived from testing::TestWithParam, where T is // the type of your parameter values. TestWithParam is itself derived // from testing::Test. T can be any copyable type. If it's a raw pointer, // you are responsible for managing the lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. #endif // 0 #if !GTEST_OS_SYMBIAN #include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #include #include #include // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2003 Google Inc. // 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. // // Authors: Dan Egnor (egnor@google.com) // // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. // // Used properly, this deletes the object when the last reference goes away. // There are several caveats: // - Like all reference counting schemes, cycles lead to leaks. // - Each smart pointer is actually two pointers (8 bytes instead of 4). // - Every time a pointer is assigned, the entire list of pointers to that // object is traversed. This class is therefore NOT SUITABLE when there // will often be more than two or three pointers to a particular object. // - References are only tracked as long as linked_ptr<> objects are copied. // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS // will happen (double deletion). // // A good use of this class is storing object references in STL containers. // You can safely put linked_ptr<> in a vector<>. // Other uses may not be as good. // // Note: If you use an incomplete type with linked_ptr<>, the class // *containing* linked_ptr<> must have a constructor and destructor (even // if they do nothing!). // // Bill Gibbons suggested we use something like this. // // Thread Safety: // Unlike other linked_ptr implementations, in this implementation // a linked_ptr object is thread-safe in the sense that: // - it's safe to copy linked_ptr objects concurrently, // - it's safe to copy *from* a linked_ptr and read its underlying // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. // TODO(wan@google.com): rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #include #include namespace testing { namespace internal { // Protects copying of all linked_ptr objects. GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to // the same object (linked_ptr(obj) vs linked_ptr(obj)). // So, it needs to be possible for different types of linked_ptr to participate // in the same circular linked list, so we need a single class type here. // // DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. class linked_ptr_internal { public: // Create a new circle that includes only this instance. void join_new() { next_ = this; } // Many linked_ptr operations may change p.link_ for some linked_ptr // variable p in the same circle as this object. Therefore we need // to prevent two such operations from occurring concurrently. // // Note that different types of linked_ptr objects can coexist in a // circle (e.g. linked_ptr, linked_ptr, and // linked_ptr). Therefore we must use a single mutex to // protect all linked_ptr objects. This can create serious // contention in production code, but is acceptable in a testing // framework. // Join an existing circle. // L < g_linked_ptr_mutex void join(linked_ptr_internal const* ptr) { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; while (p->next_ != ptr) p = p->next_; p->next_ = this; next_ = ptr; } // Leave whatever circle we're part of. Returns true if we were the // last member of the circle. Once this is done, you can join() another. // L < g_linked_ptr_mutex bool depart() { MutexLock lock(&g_linked_ptr_mutex); if (next_ == this) return true; linked_ptr_internal const* p = next_; while (p->next_ != this) p = p->next_; p->next_ = next_; return false; } private: mutable linked_ptr_internal const* next_; }; template class linked_ptr { public: typedef T element_type; // Take over ownership of a raw pointer. This should happen as soon as // possible after the object is created. explicit linked_ptr(T* ptr = NULL) { capture(ptr); } ~linked_ptr() { depart(); } // Copy an existing linked_ptr<>, adding ourselves to the list of references. template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } linked_ptr(linked_ptr const& ptr) { // NOLINT assert(&ptr != this); copy(&ptr); } // Assignment releases the old value and acquires the new. template linked_ptr& operator=(linked_ptr const& ptr) { depart(); copy(&ptr); return *this; } linked_ptr& operator=(linked_ptr const& ptr) { if (&ptr != this) { depart(); copy(&ptr); } return *this; } // Smart pointer members. void reset(T* ptr = NULL) { depart(); capture(ptr); } T* get() const { return value_; } T* operator->() const { return value_; } T& operator*() const { return *value_; } // Release ownership of the pointed object and returns it. // Sole ownership by this linked_ptr object is required. T* release() { bool last = link_.depart(); assert(last); T* v = value_; value_ = NULL; return v; } bool operator==(T* p) const { return value_ == p; } bool operator!=(T* p) const { return value_ != p; } template bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template friend class linked_ptr; T* value_; linked_ptr_internal link_; void depart() { if (link_.depart()) delete value_; } void capture(T* ptr) { value_ = ptr; link_.join_new(); } template void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #if GTEST_HAS_PARAM_TEST namespace testing { namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Outputs a message explaining invalid registration of different // fixture class for the same test case. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line); template class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template class ParamIteratorInterface { public: virtual ~ParamIteratorInterface() {} // A pointer to the base generator instance. // Used only for the purposes of iterator comparison // to make sure that two iterators belong to the same generator. virtual const ParamGeneratorInterface* BaseGenerator() const = 0; // Advances iterator to point to the next element // provided by the generator. The caller is responsible // for not calling Advance() on an iterator equal to // BaseGenerator()->End(). virtual void Advance() = 0; // Clones the iterator object. Used for implementing copy semantics // of ParamIterator. virtual ParamIteratorInterface* Clone() const = 0; // Dereferences the current iterator and provides (read-only) access // to the pointed value. It is the caller's responsibility not to call // Current() on an iterator equal to BaseGenerator()->End(). // Used for implementing ParamGenerator::operator*(). virtual const T* Current() const = 0; // Determines whether the given iterator and other point to the same // element in the sequence generated by the generator. // Used for implementing ParamGenerator::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template class ParamIterator { public: typedef T value_type; typedef const T& reference; typedef ptrdiff_t difference_type; // ParamIterator assumes ownership of the impl_ pointer. ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} ParamIterator& operator=(const ParamIterator& other) { if (this != &other) impl_.reset(other.impl_->Clone()); return *this; } const T& operator*() const { return *impl_->Current(); } const T* operator->() const { return impl_->Current(); } // Prefix version of operator++. ParamIterator& operator++() { impl_->Advance(); return *this; } // Postfix version of operator++. ParamIterator operator++(int /*unused*/) { ParamIteratorInterface* clone = impl_->Clone(); impl_->Advance(); return ParamIterator(clone); } bool operator==(const ParamIterator& other) const { return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); } bool operator!=(const ParamIterator& other) const { return !(*this == other); } private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} ParamGenerator& operator=(const ParamGenerator& other) { impl_ = other.impl_; return *this; } iterator begin() const { return iterator(impl_->Begin()); } iterator end() const { return iterator(impl_->End()); } private: ::testing::internal::linked_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to // generate sequences of user-defined types that implement operator+() and // operator<(). // This class is used in the Range() function. template class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const int other_index = CheckedDowncastToActualType(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; T value_; int index_; const IncrementT step_; }; // class RangeGenerator::Iterator static int CalculateEndIndex(const T& begin, const T& end, const IncrementT& step) { int end_index = 0; for (T i = begin; i < end; i = i + step) end_index++; return end_index; } // No implementation - assignment is unsupported. void operator=(const RangeGenerator& other); const T begin_; const T end_; const IncrementT step_; // The index for the end() iterator. All the elements in the generated // sequence are indexed (0-based) to aid iterator comparison. const int end_index_; }; // class RangeGenerator // Generates values from a pair of STL-style iterators. Used in the // ValuesIn() function. The elements are copied from the source range // since the source can be located on the stack, and the generator // is likely to persist beyond that stack frame. template class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ // can return a temporary object (and of type other then T), so just // having "return &*iterator_;" doesn't work. // value_ is updated here and not in Advance() because Advance() // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. virtual const T* Current() const { if (value_.get() == NULL) value_.reset(new T(*iterator_)); return value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; return iterator_ == CheckedDowncastToActualType(&other)->iterator_; } private: Iterator(const Iterator& other) // The explicit constructor call suppresses a false warning // emitted by gcc when supplied with the -Wextra option. : ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* const base_; typename ContainerType::const_iterator iterator_; // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). // Use of scoped_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. mutable scoped_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. void operator=(const ValuesInIteratorRangeGenerator& other); const ContainerType container_; }; // class ValuesInIteratorRangeGenerator // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that // value. template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} virtual Test* CreateTest() { TestClass::SetParam(¶meter_); return new TestClass(); } private: const ParamType parameter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactoryBase is a base class for meta-factories that create // test factories for passing into MakeAndRegisterTestInfo function. template class TestMetaFactoryBase { public: virtual ~TestMetaFactoryBase() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed // into that method twice. But ParameterizedTestCaseInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. template class TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(parameter); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfoBase is a generic interface // to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase // accumulates test information provided by TEST_P macro invocations // and generators provided by INSTANTIATE_TEST_CASE_P macro invocations // and uses that information to register all resulting test instances // in RegisterTests method. The ParameterizeTestCaseRegistry class holds // a collection of pointers to the ParameterizedTestCaseInfo objects // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. virtual const String& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this // test case right before running them in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. virtual void RegisterTests() = 0; protected: ParameterizedTestCaseInfoBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfo accumulates tests obtained from TEST_P // macro invocations for a particular test case and generators // obtained from INSTANTIATE_TEST_CASE_P macro invocations for that // test case. It registers tests with all values generated by all // generators when asked. template class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and // AddTestCaseInstantiation(). typedef typename TestCase::ParamType ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); explicit ParameterizedTestCaseInfo(const char* name) : test_case_name_(name) {} // Test case base name for display purposes. virtual const String& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. // test_case_name is the base name of the test case (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test case base name and DoBar is test base name. void AddTestPattern(const char* test_case_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { tests_.push_back(linked_ptr(new TestInfo(test_case_name, test_base_name, meta_factory))); } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. int AddTestCaseInstantiation(const char* instantiation_name, GeneratorCreationFunc* func, const char* /* file */, int /* line */) { instantiations_.push_back(::std::make_pair(instantiation_name, func)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test case // test cases right before running tests in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. // UnitTest has a guard to prevent from calling this method more then once. virtual void RegisterTests() { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { linked_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { const String& instantiation_name = gen_it->first; ParamGenerator generator((*gen_it->second)()); Message test_case_name_stream; if ( !instantiation_name.empty() ) test_case_name_stream << instantiation_name.c_str() << "/"; test_case_name_stream << test_info->test_case_base_name.c_str(); int i = 0; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; test_name_stream << test_info->test_base_name.c_str() << "/" << i; ::testing::internal::MakeAndRegisterTestInfo( test_case_name_stream.GetString().c_str(), test_name_stream.GetString().c_str(), "", // test_case_comment "", // comment; TODO(vladl@google.com): provide parameter value // representation. GetTestCaseTypeId(), TestCase::SetUpTestCase, TestCase::TearDownTestCase, test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { TestInfo(const char* a_test_case_base_name, const char* a_test_base_name, TestMetaFactoryBase* a_test_meta_factory) : test_case_base_name(a_test_case_base_name), test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} const String test_case_base_name; const String test_base_name; const scoped_ptr > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > InstantiationContainer; const String test_case_name_; TestInfoContainer tests_; InstantiationContainer instantiations_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); }; // class ParameterizedTestCaseInfo // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase // classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P // macros use it to locate their corresponding ParameterizedTestCaseInfo // descriptors. class ParameterizedTestCaseRegistry { public: ParameterizedTestCaseRegistry() {} ~ParameterizedTestCaseRegistry() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { delete *it; } } // Looks up or creates and returns a structure containing information about // tests and instantiations of a particular test case. template ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* typed_test_info = NULL; for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { if ((*it)->GetTestCaseName() == test_case_name) { if ((*it)->GetTestCaseTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct // test case setup and tear-down in this case. ReportInvalidTestCaseType(test_case_name, file, line); abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< ParameterizedTestCaseInfo >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(test_case_name); test_case_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { (*it)->RegisterTests(); } } private: typedef ::std::vector TestCaseInfoContainer; TestCaseInfoContainer test_case_infos_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); }; } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ // This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most 50 arguments in Values, // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::std::iterator_traits::value_type> ValuesIn( ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); const T1 v1_; const T2 v2_; const T3 v3_; }; template class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; }; template class ValueArray5 { public: ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; }; template class ValueArray6 { public: ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; }; template class ValueArray7 { public: ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; }; template class ValueArray8 { public: ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; }; template class ValueArray9 { public: ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; }; template class ValueArray10 { public: ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; }; template class ValueArray11 { public: ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; }; template class ValueArray12 { public: ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; }; template class ValueArray13 { public: ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; }; template class ValueArray14 { public: ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; }; template class ValueArray15 { public: ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; }; template class ValueArray16 { public: ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; }; template class ValueArray17 { public: ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; }; template class ValueArray18 { public: ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; }; template class ValueArray19 { public: ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; }; template class ValueArray20 { public: ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; }; template class ValueArray21 { public: ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; }; template class ValueArray22 { public: ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; }; template class ValueArray23 { public: ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; }; template class ValueArray24 { public: ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; }; template class ValueArray25 { public: ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; }; template class ValueArray26 { public: ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; }; template class ValueArray27 { public: ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; }; template class ValueArray28 { public: ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; }; template class ValueArray29 { public: ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; }; template class ValueArray30 { public: ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; }; template class ValueArray31 { public: ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; }; template class ValueArray32 { public: ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; }; template class ValueArray33 { public: ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; }; template class ValueArray34 { public: ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; }; template class ValueArray35 { public: ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; }; template class ValueArray36 { public: ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; }; template class ValueArray37 { public: ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; }; template class ValueArray38 { public: ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; }; template class ValueArray39 { public: ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; }; template class ValueArray40 { public: ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; }; template class ValueArray41 { public: ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; }; template class ValueArray42 { public: ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; }; template class ValueArray43 { public: ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; }; template class ValueArray44 { public: ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; }; template class ValueArray45 { public: ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; }; template class ValueArray46 { public: ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; }; template class ValueArray47 { public: ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; }; template class ValueArray48 { public: ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, v48_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; }; template class ValueArray49 { public: ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, v48_, v49_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; }; template class ValueArray50 { public: ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, v48_, v49_, v50_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; const T50 v50_; }; #if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // template class CartesianProductGenerator2 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current2_; if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current3_; if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current4_; if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current5_; if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current6_; if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current7_; if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current8_; if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current9_; if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} virtual ~CartesianProductGenerator10() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end(), g10_, g10_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::iterator& current10) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9), begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current10_; if (current10_ == end10_) { current10_ = begin10_; ++current9_; } if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_ && current10_ == typed_other->current10_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_), begin10_(other.begin10_), end10_(other.end10_), current10_(other.current10_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_, *current10_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_ || current10_ == end10_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder3& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; }; // class CartesianProductHolder3 template class CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder4& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; }; // class CartesianProductHolder4 template class CartesianProductHolder5 { public: CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder5& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; }; // class CartesianProductHolder5 template class CartesianProductHolder6 { public: CartesianProductHolder6(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder6& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; }; // class CartesianProductHolder6 template class CartesianProductHolder7 { public: CartesianProductHolder7(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder7& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; }; // class CartesianProductHolder7 template class CartesianProductHolder8 { public: CartesianProductHolder8(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder8& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; }; // class CartesianProductHolder8 template class CartesianProductHolder9 { public: CartesianProductHolder9(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder9& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; }; // class CartesianProductHolder9 template class CartesianProductHolder10 { public: CartesianProductHolder10(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(g10_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder10& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; const Generator10 g10_; }; // class CartesianProductHolder10 #endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::std::iterator_traits::value_type> ValuesIn( ForwardIterator begin, ForwardIterator end) { typedef typename ::std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to 50 parameters. // template internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) { return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) { return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) { return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) { return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) { return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) { return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { return internal::ValueArray21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) { return internal::ValueArray22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) { return internal::ValueArray23(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) { return internal::ValueArray24(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24); } template internal::ValueArray25 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { return internal::ValueArray25(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25); } template internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) { return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } template internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) { return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); } template internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) { return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28); } template internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) { return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29); } template internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30); } template internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); } template internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) { return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32); } template internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) { return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); } template internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) { return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); } template internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { return internal::ValueArray35(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); } template internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { return internal::ValueArray36(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36); } template internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) { return internal::ValueArray37(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37); } template internal::ValueArray38 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) { return internal::ValueArray38(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38); } template internal::ValueArray39 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) { return internal::ValueArray39(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39); } template internal::ValueArray40 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); } template internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); } template internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) { return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); } template internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) { return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43); } template internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) { return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44); } template internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45); } template internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46); } template internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); } template internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) { return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); } template internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) { return internal::ValueArray49(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); } template internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { return internal::ValueArray50(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } #if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) { return internal::CartesianProductHolder7( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) { return internal::CartesianProductHolder8( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) { return internal::CartesianProductHolder9( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) { return internal::CartesianProductHolder10( g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); } #endif // GTEST_HAS_COMBINE #define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Google C++ Testing Framework definitions useful in production code. #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the // class. For example: // // class MyClass { // private: // void MyMethod(); // FRIEND_TEST(MyClassTest, MyMethod); // }; // // class MyClassTest : public testing::Test { // // ... // }; // // TEST_F(MyClassTest, MyMethod) { // // Can call MyClass::MyMethod() here. // } #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include namespace testing { // A copyable object representing the result of a test part (i.e. an // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). // // Don't inherit from TestPartResult as its destructor is not virtual. class GTEST_API_ TestPartResult { public: // The possible outcomes of a test part (i.e. an assertion or an // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. kFatalFailure // Failed and the test should be terminated. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), file_name_(a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), message_(a_message) { } // Gets the outcome of the test part. Type type() const { return type_; } // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { return file_name_.c_str(); } // Gets the line in the source file where the test part took place, // or -1 if it's unknown. int line_number() const { return line_number_; } // Gets the summary of the failure message. const char* summary() const { return summary_.c_str(); } // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } // Returns true iff the test part passed. bool passed() const { return type_ == kSuccess; } // Returns true iff the test part failed. bool failed() const { return type_ != kSuccess; } // Returns true iff the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } // Returns true iff the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } private: Type type_; // Gets the summary of the failure message by omitting the stack // trace in it. static internal::String ExtractSummary(const char* message); // The name of the source file where the test part took place, or // NULL if the source file is unknown. internal::String file_name_; // The line in the source file where the test part took place, or -1 // if the line number is unknown. int line_number_; internal::String summary_; // The test failure summary. internal::String message_; // The test failure message. }; // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result); // An array of TestPartResult objects. // // Don't inherit from TestPartResultArray as its destructor is not // virtual. class GTEST_API_ TestPartResultArray { public: TestPartResultArray() {} // Appends the given TestPartResult to the array. void Append(const TestPartResult& result); // Returns the TestPartResult at the given index (0-based). const TestPartResult& GetTestPartResult(int index) const; // Returns the number of TestPartResult objects in the array. int size() const; private: std::vector array_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); }; // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; namespace internal { // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a // statement generates new fatal failures. To do so it registers itself as the // current test part result reporter. Besides checking if fatal failures were // reported, it only delegates the reporting to the former result reporter. // The original result reporter is restored in the destructor. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); virtual ~HasNewFatalFailureHelper(); virtual void ReportTestPartResult(const TestPartResult& result); bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; TestPartResultReporterInterface* original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ // Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. // Typed (aka type-driven) tests repeat the same test for types in a // list. You must know which types you want to test with when writing // typed tests. Here's how you do it: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { public: ... typedef std::list List; static T shared_; T value_; }; // Next, associate a list of types with the test case, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // TYPED_TEST_CASE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed // tests for this test case as you want. TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. // Since we are inside a derived class template, C++ requires use to // visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the "typename // TestFixture::" prefix. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } #endif // 0 // Type-parameterized tests are abstract test patterns parameterized // by a type. Compared with typed tests, type-parameterized tests // allow you to define the test pattern without knowing what the type // parameters are. The defined pattern can be instantiated with // different types any number of times, in any number of translation // units. // // If you are designing an interface or concept, you can define a // suite of type-parameterized tests to verify properties that any // valid implementation of the interface/concept should have. Then, // each implementation can easily instantiate the test suite to verify // that it conforms to the requirements, without having to write // similar tests repeatedly. Here's an example: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { ... }; // Next, declare that you will define a type-parameterized test case // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): TYPED_TEST_CASE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests // for this type-parameterized test case as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the // test case name; the rest are the names of the tests in this test // case. REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include // it in multiple C++ source files and instantiate it multiple times. // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added // to the actual test case name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); #endif // 0 // Implements typed tests. #if GTEST_HAS_TYPED_TEST // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the // given test case. #define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) #define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) #define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ bool gtest_##CaseName##_##TestName##_registered_ = \ ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel< \ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ GTEST_TYPE_PARAMS_(CaseName)>::Register(\ "", #CaseName, #TestName, 0); \ template \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for // the given type-parameterized test case are defined in. The exact // name of the namespace is subject to change without notice. #define GTEST_CASE_NAMESPACE_(TestCaseName) \ gtest_case_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of // the defined tests in the given test case. #define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ gtest_typed_test_case_p_state_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of // the registered tests in the given test case. #define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ gtest_registered_test_names_##TestCaseName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. #define TYPED_TEST_CASE_P(CaseName) \ static ::testing::internal::TypedTestCasePState \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) #define TYPED_TEST_P(CaseName, TestName) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ template \ class TestName : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ static bool gtest_##TestName##_defined_ = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ __FILE__, __LINE__, #CaseName, #TestName); \ } \ template \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() #define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) #define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // // The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to // aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. GTEST_DECLARE_bool_(throw_on_failure); // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class TestInfoImpl; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const String& message); class PrettyUnitTestResultPrinter; class XmlUnitTestResultPrinter; // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". // Declared in gtest-internal.h but defined here, so that it has access // to the definition of the Message class, required by the ARM // compiler. template String StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); // Used in the EXPECT_TRUE/FALSE(bool_expression). explicit AssertionResult(bool success) : success_(success) {} // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != NULL && message_->c_str() != NULL ? message_->c_str() : ""; } // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value); private: // No implementation - we want AssertionResult to be // copy-constructible but not assignable. void operator=(const AssertionResult& other); // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr message_; }; // class AssertionResult // Streams a custom failure message into this object. template AssertionResult& AssertionResult::operator<<(const T& value) { Message msg; if (message_.get() != NULL) msg << *message_; msg << value; message_.reset(new internal::String(msg.GetString())); return *this; } // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and // each TestCase contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { ... } // virtual void TearDown() { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class internal::TestInfoImpl; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test. Only the last value for a given // key is remembered. // These are public static so they can be called from utility functions // that are not members of the test fixture. // The arguments are const char* instead strings, as Google Test is used // on platforms where string doesn't compile. // // Note that a driving consideration for these RecordProperty methods // was to produce xml output suited to the Greenspan charting utility, // which at present will only chart values that fit in a 32-bit int. It // is the user's responsibility to restrict their values to 32-bit ints // if they intend them to be used with Greenspan. static void RecordProperty(const char* key, const char* value); static void RecordProperty(const char* key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const char* a_key, const char* a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const char* new_value) { value_ = new_value; } private: // The key supplied by the user. internal::String key_; // The value supplied by the user. internal::String value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } // Returns true iff the test failed. bool Failed() const; // Returns true iff the test fatally failed. bool HasFatalFailure() const; // Returns true iff the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range // from 0 to test_property_count() - 1. If i is not in that range, aborts // the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestInfoImpl; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. void RecordProperty(const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. // TODO(russr): Validate attribute names are legal and human readable. static bool ValidateTestProperty(const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test case name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test case name. const char* test_case_name() const; // Returns the test name. const char* name() const; // Returns the test case comment. const char* test_case_comment() const; // Returns the test comment. const char* comment() const; // Returns true if this test should run, that is if the test is not disabled // (or it is disabled but the also_run_disabled_tests flag has been specified) // and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test case Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const; // Returns the result of the test. const TestResult* result() const; private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::TestInfoImpl; friend class internal::UnitTestImpl; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Returns true if this test matches the user-specified filter. bool matches_filter() const; // Increments the number of death tests encountered in this test so // far. int increment_death_test_count(); // Accessors for the implementation object. internal::TestInfoImpl* impl() { return impl_; } const internal::TestInfoImpl* impl() const { return impl_; } // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // An opaque implementation object. internal::TestInfoImpl* impl_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test case, which consists of a vector of TestInfos. // // TestCase is not copyable. class GTEST_API_ TestCase { public: // Creates a TestCase with the given name. // // TestCase does NOT have a default constructor. Always use this // constructor to create a TestCase object. // // Arguments: // // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase(const char* name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Destructor of TestCase. virtual ~TestCase(); // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } // Returns the test case comment. const char* comment() const { return comment_.c_str(); } // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test case. int successful_test_count() const; // Gets the number of failed tests in this test case. int failed_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Get the number of tests in this test case that should run. int test_to_run_count() const; // Gets the number of all tests in this test case. int total_test_count() const; // Returns true iff the test case passed. bool Passed() const { return !Failed(); } // Returns true iff the test case failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test case. Will delete the TestInfo upon // destruction of the TestCase object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test case. void ClearResult(); // Clears the results of all tests in the given test case. static void ClearTestCaseResult(TestCase* test_case) { test_case->ClearResult(); } // Runs every test in this TestCase. void Run(); // Returns true iff test passed. static bool TestPassed(const TestInfo * test_info); // Returns true iff test failed. static bool TestFailed(const TestInfo * test_info); // Returns true iff test is disabled. static bool TestDisabled(const TestInfo * test_info); // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo *test_info); // Shuffles the tests in this test case. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test case. internal::String name_; // Comment on the test case. internal::String comment_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test case. Test::SetUpTestCaseFunc set_up_tc_; // Pointer to the function that tears down the test case. Test::TearDownTestCaseFunc tear_down_tc_; // True iff any test in this test case should run. bool should_run_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. The user should subclass this to define his own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test case starts. virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCESS(). virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} virtual void OnTestStart(const TestInfo& /*test_info*/) {} virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} virtual void OnTestEnd(const TestInfo& /*test_info*/) {} virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestCase; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::TestInfoImpl; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* current_test_case() const; // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const; // Returns the random seed used at the start of the current test run. int random_seed() const; #if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); #endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const; // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const; // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const internal::String& message, const internal::String& os_stack_trace); // Adds a TestProperty to the current TestResult object. If the result already // contains a property with the same key, the value will be updated. void RecordPropertyForCurrentTest(const char* key, const char* value); // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and funcions are friends as they need to access private // members of UnitTest. friend class Test; friend class internal::AssertHelper; friend class internal::ScopedTrace; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const internal::String& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace(); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { // These overloaded versions handle ::std::string and ::std::wstring. GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) { return (Message() << '"' << str << '"').GetString(); } #if GTEST_HAS_STD_WSTRING GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) { return (Message() << "L\"" << wstr << '"').GetString(); } #endif // GTEST_HAS_STD_WSTRING // These overloaded versions handle ::string and ::wstring. #if GTEST_HAS_GLOBAL_STRING GTEST_API_ inline String FormatForFailureMessage(const ::string& str) { return (Message() << '"' << str << '"').GetString(); } #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) { return (Message() << "L\"" << wstr << '"').GetString(); } #endif // GTEST_HAS_GLOBAL_WSTRING // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char*, and print it as a C string when it is compared against an // std::string object, for example. // // The default implementation ignores the type of the other operand. // Some specialized versions are used to handle formatting wide or // narrow C strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template String FormatForComparisonFailureMessage(const T1& value, const T2& /* other_operand */) { return FormatForFailureMessage(value); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { #ifdef _MSC_VER #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4389) // Temporarily disables warning on // signed/unsigned mismatch. #endif if (expected == actual) { return AssertionSuccess(); } #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() // is a null pointer literal. The following default implementation is // for lhs_is_null_literal being false. template class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal. template <> class EqHelper { public: // We define two overloaded versions of Compare(). The first // version will be picked when the second argument to ASSERT_EQ() is // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or // EXPECT_EQ(false, a_bool). template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // This version will be picked when the second argument to // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& /* expected */, T2* actual) { // We already know that 'expected' is a null pointer. return CmpHelperEQ(expected_expression, actual_expression, static_cast(NULL), actual); } }; // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ Message msg;\ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ return AssertionFailure(msg);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, !=); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <=); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, < ); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >=); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, > ); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } StrStream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; StrStream actual_ss; actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) << actual; return EqFailure(expected_expression, actual_expression, StrStreamToString(&expected_ss), StrStreamToString(&actual_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; String const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; } // namespace internal #if GTEST_HAS_PARAM_TEST // The abstract base class that all value-parameterized tests inherit from. // // This class adds support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // virtual ~FooTest() { // // Can use GetParam() here. // } // virtual void SetUp() { // // Can use GetParam() here. // } // virtual void TearDown { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class TestWithParam : public Test { public: typedef T ParamType; // The current parameter value. Is also available in the test fixture's // constructor. const ParamType& GetParam() const { return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of TestWithParam. template friend class internal::ParameterizedTestFactory; }; template const T* TestWithParam::parameter_ = NULL; #endif // GTEST_HAS_PARAM_TEST // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // // Examples: // // EXPECT_TRUE(server.StatusIsOK()); // ASSERT_FALSE(server.HasPendingRequest(port)) // << "There are still pending requests " << "on port " << port; // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL #define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED #define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Includes the auto-generated header that implements a family of // generic predicate assertion macros. // Copyright 2006, Google Inc. // 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. // This file is AUTOMATICALLY GENERATED on 10/02/2008 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Makes sure this header is not included before gtest.h. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #error Do not include gtest_pred_impl.h directly. Include gtest.h instead. #endif // GTEST_INCLUDE_GTEST_GTEST_H_ // This header implements a family of generic predicate assertion // macros: // // ASSERT_PRED_FORMAT1(pred_format, v1) // ASSERT_PRED_FORMAT2(pred_format, v1, v2) // ... // // where pred_format is a function or functor that takes n (in the // case of ASSERT_PRED_FORMATn) values and their source expression // text, and returns a testing::AssertionResult. See the definition // of ASSERT_EQ in gtest.h for an example. // // If you don't care about formatting, you can use the more // restrictive version: // // ASSERT_PRED1(pred, v1) // ASSERT_PRED2(pred, v1, v2) // ... // // where pred is an n-ary function or functor that returns bool, // and the values v1, v2, ..., must support the << operator for // streaming to std::ostream. // // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. // Please email googletestframework@googlegroups.com if you need // support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. #define GTEST_ASSERT_(expression, on_failure) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar = (expression)) \ ; \ else \ on_failure(gtest_ar.failure_message()) // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. template AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, Pred pred, const T1& v1) { if (pred(v1)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Don't use this in your code. #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ GTEST_ASSERT_(pred_format(#v1, v1),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. #define GTEST_PRED1_(pred, v1, on_failure)\ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ #v1, \ pred, \ v1), on_failure) // Unary predicate assertion macros. #define EXPECT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) #define ASSERT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. template AssertionResult AssertPred2Helper(const char* pred_text, const char* e1, const char* e2, Pred pred, const T1& v1, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Don't use this in your code. #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. #define GTEST_PRED2_(pred, v1, v2, on_failure)\ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ #v1, \ #v2, \ pred, \ v1, \ v2), on_failure) // Binary predicate assertion macros. #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) #define ASSERT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. template AssertionResult AssertPred3Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, Pred pred, const T1& v1, const T2& v2, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Don't use this in your code. #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. #define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ #v1, \ #v2, \ #v3, \ pred, \ v1, \ v2, \ v3), on_failure) // Ternary predicate assertion macros. #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) #define ASSERT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. template AssertionResult AssertPred4Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Don't use this in your code. #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. #define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ pred, \ v1, \ v2, \ v3, \ v4), on_failure) // 4-ary predicate assertion macros. #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. template AssertionResult AssertPred5Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ", " << e5 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4 << "\n" << e5 << " evaluates to " << v5; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Don't use this in your code. #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. #define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ #v5, \ pred, \ v1, \ v2, \ v3, \ v4, \ v5), on_failure) // 5-ary predicate assertion macros. #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to // {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(5, Foo()); // EXPECT_EQ(NULL, a_pointer); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define EXPECT_NE(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define ASSERT_EQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // C String Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. #define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) #define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) #define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. #define SCOPED_TRACE(message) \ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) namespace internal { // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; } // namespace internal // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { internal::StaticAssertTypeEqHelper(); return true; } // Defines a test. // // The first parameter is the name of the test case, and the second // parameter is the name of the test within the test case. // // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // // The user should put his test code between braces after using this // macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_case_name, test_name)\ GTEST_TEST_(test_case_name, test_name, \ ::testing::Test, ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST #define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test case name. The second parameter is the // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put // his test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(0, a_.size()); // EXPECT_EQ(1, b_.size()); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) // Use this macro in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). #define RUN_ALL_TESTS()\ (::testing::UnitTest::GetInstance()->Run()) } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_H_ ceph-0.80.11/src/gtest/fused-src/gtest/gtest-all.cc0000664000175100017510000114575412623077036024052 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // // Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. // This line ensures that gtest.h can be compiled on its own, even // when it's fused. #include // The following lines pull in the real gtest *.cc files. // Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // Copyright 2007, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ namespace testing { // This helper class can be used to mock out Google Test failure reporting // so that we can test Google Test or code that builds on Google Test. // // An object of this class appends a TestPartResult object to the // TestPartResultArray object given in the constructor whenever a Google Test // failure is reported. It can either intercept only failures that are // generated in the same thread that created this object or it can intercept // all generated failures. The scope of this mock object can be controlled with // the second argument to the two arguments constructor. class GTEST_API_ ScopedFakeTestPartResultReporter : public TestPartResultReporterInterface { public: // The two possible mocking modes of this object. enum InterceptMode { INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. INTERCEPT_ALL_THREADS // Intercepts all failures. }; // The c'tor sets this object as the test part result reporter used // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, TestPartResultArray* result); // The d'tor restores the previous test part result reporter. virtual ~ScopedFakeTestPartResultReporter(); // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. virtual void ReportTestPartResult(const TestPartResult& result); private: void Init(); const InterceptMode intercept_mode_; TestPartResultReporterInterface* old_reporter_; TestPartResultArray* const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; namespace internal { // A helper class for implementing EXPECT_FATAL_FAILURE() and // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const char* substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; const String substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; } // namespace internal } // namespace testing // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_FATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - 'statement' cannot reference local non-static variables or // non-static members of the current object. // - 'statement' cannot return a value. // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. The AcceptsMacroThatExpandsToUnprotectedComma test in // gtest_unittest.cc will fail to compile if we do that. #define EXPECT_FATAL_FAILURE(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) // A macro for testing Google Test assertions or code that's expected to // generate Google Test non-fatal failures. It asserts that the given // statement will cause exactly one non-fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // 'statement' is allowed to reference local variables and members of // the current object. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. If we do that, the code won't compile when the user gives // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that // expands to code containing an unprotected comma. The // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc // catches that. // // For the same reason, we have to write // if (::testing::internal::AlwaysTrue()) { statement; } // instead of // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) // to avoid an MSVC warning on unreachable code. #define EXPECT_NONFATAL_FAILURE(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include #include #include #include #include #include #include #include #include #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). #define GTEST_HAS_GETTIMEOFDAY_ 1 #include #include #include // Declares vsnprintf(). This header is not available on Windows. #include #include #include #include #include #include #elif GTEST_OS_SYMBIAN #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT #elif GTEST_OS_ZOS #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. #include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. #include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT #endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. #include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). #define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. #include // NOLINT #include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS #include #endif // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 // Copyright 2005, Google Inc. // 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. // Utility functions and classes used by the Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. #error "gtest-internal-inl.h is part of Google Test's internal implementation." #error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE #include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #if GTEST_OS_WINDOWS #include // For DWORD. #endif // GTEST_OS_WINDOWS namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true iff Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; String color_; String death_test_style_; bool death_test_use_fork_; String filter_; String internal_run_death_test_; bool list_tests_; String output_; bool print_time_; bool pretty_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // The output buffer str must containt at least 32 characters. // The function returns the address of the output buffer. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output // as '(Invalid Unicode 0xXXXXXXXX)'. GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { return static_cast(std::count_if(c.begin(), c.end(), predicate)); } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + random->Generate(range_width); std::swap((*v)[selected], (*v)[last_in_range]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const char* key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return String(test_property.key()).Compare(key_) == 0; } private: String key_; }; class TestInfoImpl { public: TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, TypeId fixture_class_id, internal::TestFactoryBase* factory); ~TestInfoImpl(); // Returns true if this test should run. bool should_run() const { return should_run_; } // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Returns true if this test is disabled. Disabled tests are not run. bool is_disabled() const { return is_disabled_; } // Sets the is_disabled member. void set_is_disabled(bool is) { is_disabled_ = is; } // Returns true if this test matches the filter specified by the user. bool matches_filter() const { return matches_filter_; } // Sets the matches_filter member. void set_matches_filter(bool matches) { matches_filter_ = matches; } // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the test case comment. const char* test_case_comment() const { return test_case_comment_.c_str(); } // Returns the test comment. const char* comment() const { return comment_.c_str(); } // Returns the ID of the test fixture class. TypeId fixture_class_id() const { return fixture_class_id_; } // Returns the test result. TestResult* result() { return &result_; } const TestResult* result() const { return &result_; } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); // Clears the test result. void ClearResult() { result_.Clear(); } // Clears the test result in the given TestInfo object. static void ClearTestResult(TestInfo * test_info) { test_info->impl()->ClearResult(); } private: // These fields are immutable properties of the test. TestInfo* const parent_; // The owner of this object const String test_case_name_; // Test case name const String name_; // Test name const String test_case_comment_; // Test case comment const String comment_; // Test comment const TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static String GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static String GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true iff the user-specified filter matches the test case // name and the test name. static bool FilterMatchesTest(const String &test_case_name, const String &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const String& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as a String. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} virtual String CurrentStackTrace(int max_depth, int skip_count); virtual void UponLeavingGTest(); // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: Mutex mutex_; // protects all internal state // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; String message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const { return !Failed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. String CurrentOsStackTraceExceptTop(int skip_count); // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_case_name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo * test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), test_info->test_case_comment(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has // guards protecting from registering the tests more then once. // If value-parameterized tests are disabled, RegisterParameterizedTests // is present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns 0 if all tests are successful, or 1 otherwise. If any // exception is thrown during a test on Windows, this test is // considered to be failed, but the rest of the tests will still be // run. (We disable exceptions on Linux and Mac OS X, so the issue // doesn't apply there.) int RunAllTests(); // Clears the results of all tests, including the ad hoc test. void ClearResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); ad_hoc_test_result_.Clear(); } enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); private: friend class ::testing::UnitTest; // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True iff PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsDigit(char ch); GTEST_API_ bool IsPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsWhiteSpace(char ch); GTEST_API_ bool IsWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. String GetLastErrnoDescription(); #if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} explicit AutoHandle(HANDLE handle) : handle_(handle) {} ~AutoHandle() { Reset(); } HANDLE Get() const { return handle_; } void Reset() { Reset(INVALID_HANDLE_VALUE); } void Reset(HANDLE handle) { if (handle != handle_) { if (handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(handle_); handle_ = handle; } } private: HANDLE handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; #endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !isdigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. #if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); #else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); #endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const TestProperty& property) { test_result->RecordProperty(property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS #define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test case name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test case whose name matches this filter is considered a death // test case and will be run before test cases whose name doesn't // match this filter. static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. bool g_help_flag = false; } // namespace internal GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", false), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", kUniversalFilter), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " "by a colon and an output file name or directory. A directory " "is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_( shuffle, internal::BoolFromGTestEnv("shuffle", false), "True iff " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). state_ = (1103515245U*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). // // A user must call testing::InitGoogleTest() to initialize Google // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true iff the test case passed. static bool TestCasePassed(const TestCase* test_case) { return test_case->should_run() && test_case->Passed(); } // Returns true iff the test case failed. static bool TestCaseFailed(const TestCase* test_case) { return test_case->should_run() && test_case->Failed(); } // Returns true iff test_case contains at least one test that should // run. static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // Mutex for linked pointers. GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. String g_executable_path; // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. String UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return String(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? String(gtest_output_flag) : String(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. String UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return String(""); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return String(internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).ToString() ); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) // TODO(wan@google.com): on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.ToString(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.ToString(); } // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == NULL) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // TODO(keithray): move String function implementations to gtest-string.cc. // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, const String &test_name) { const String& full_name = String::Format("%s.%s", test_case_name.c_str(), test_name.c_str()); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); String positive; String negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = String(""); } else { positive = String(p, dash - p); // Everything up to the dash negative = String(dash+1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_OS_WINDOWS // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle an exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception. return (GTEST_FLAG(catch_exceptions) && exception_code != EXCEPTION_BREAKPOINT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_OS_WINDOWS } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const char* substr) { const String expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure(msg); } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { msg << "Expected: " << expected << "\n" << " Actual:\n" << r; return AssertionFailure(msg); } if (strstr(r.message(), substr) == NULL) { msg << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; return AssertionFailure(msg); } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, const char* substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; return String(""); } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@google.com): Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; #ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); #pragma warning(pop) // Restores the warning state. #else _ftime64(&now); #endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else #error "Don't know how to get the current time on your system." #endif } // Utilities // class String // Returns the input enclosed in double quotes if it's not NULL; // otherwise returns "(null)". For example, "\"Hello\"" is returned // for input "Hello". // // This is useful for printing a C string in the syntax of a literal. // // Known issue: escape sequences are not handled yet. String String::ShowCStringQuoted(const char* c_str) { return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); } // Copies at most length characters from str into a newly-allocated // piece of memory of size length+1. The memory is allocated with new[]. // A terminating null byte is written to the memory, and a pointer to it // is returned. If str is NULL, NULL is returned. static char* CloneString(const char* str, size_t length) { if (str == NULL) { return NULL; } else { char* const clone = new char[length + 1]; posix::StrNCpy(clone, str, length); clone[length] = '\0'; return clone; } } // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting[] the return value. Returns the // cloned string, or NULL if the input is NULL. const char * String::CloneCString(const char* c_str) { return (c_str == NULL) ? NULL : CloneString(c_str, strlen(c_str)); } #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return NULL; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, NULL, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return NULL; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, NULL, 0, NULL, NULL); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, NULL, NULL); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { // TODO(wan): consider allowing a testing::String object to // contain '\0'. This will make it behave more like std::string, // and will allow ToUtf8String() to return the correct encoding // for '\0' s.t. we can get rid of the conditional here (and in // several other places). for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING } // namespace internal #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_GLOBAL_WSTRING namespace internal { // Formats a value to be used in a failure message. // For a char value, we print it as a C++ char literal and as an // unsigned integer (both in decimal and in hexadecimal). String FormatForFailureMessage(char ch) { const unsigned int ch_as_uint = ch; // A String object cannot contain '\0', so we print "\\0" when ch is // '\0'. return String::Format("'%s' (%u, 0x%X)", ch ? String::Format("%c", ch).c_str() : "\\0", ch_as_uint, ch_as_uint); } // For a wchar_t value, we print it as a C++ wchar_t literal and as an // unsigned integer (both in decimal and in hexidecimal). String FormatForFailureMessage(wchar_t wchar) { // The C++ standard doesn't specify the exact size of the wchar_t // type. It just says that it shall have the same size as another // integral type, called its underlying type. // // Therefore, in order to print a wchar_t value in the numeric form, // we first convert it to the largest integral type (UInt64) and // then print the converted value. // // We use streaming to print the value as "%llu" doesn't work // correctly with MSVC 7.1. const UInt64 wchar_as_uint64 = wchar; Message msg; // A String object cannot contain '\0', so we print "\\0" when wchar is // L'\0'. char buffer[32]; // CodePointToUtf8 requires a buffer that big. msg << "L'" << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) << wchar_as_uint64 << ")"; return msg.GetString(); } } // namespace internal // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new internal::String(*other.message_) : static_cast(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != NULL) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const String& expected_value, const String& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; if (actual_value != actual_expression) { msg << "\n Actual: " << actual_value; } msg << "\nExpected: " << expected_expression; if (ignoring_case) { msg << " (ignoring case)"; } if (expected_value != expected_expression) { msg << "\nWhich is: " << expected_value; } return AssertionFailure(msg); } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); // TODO(wan): do not print the value of an expression if it's // already a literal. Message msg; msg << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; return AssertionFailure(msg); } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. StrStream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; StrStream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; Message msg; msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StrStreamToString(&val1_ss) << " vs " << StrStreamToString(&val2_ss); return AssertionFailure(msg); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { if (expected == actual) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ Message msg;\ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ return AssertionFailure(msg);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, String::ShowCStringQuoted(expected), String::ShowCStringQuoted(actual), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CaseInsensitiveCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, String::ShowCStringQuoted(expected), String::ShowCStringQuoted(actual), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { Message msg; msg << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; return AssertionFailure(msg); } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { Message msg; msg << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; return AssertionFailure(msg); } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true iff needle is a // substring of haystack. NULL is considered a substring of itself // only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return strstr(haystack, needle) != NULL; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return wcsstr(haystack, needle) != NULL; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure( Message() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""); } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; #else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // String::Format can't exceed this length. // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system hr, // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing cr-lf) for (; message_length && isspace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } #endif // GTEST_OS_WINDOWS_MOBILE const String error_hex(String::Format("0x%08X ", hr)); Message msg; msg << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << error_text << "\n"; return ::testing::AssertionFailure(msg); } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // The output buffer str must containt at least 32 characters. // The function returns the address of the output buffer. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output // as '(Invalid Unicode 0xXXXXXXXX)'. char* CodePointToUtf8(UInt32 code_point, char* str) { if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else if (code_point <= kMaxCodePoint4) { str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } else { // The longest string String::Format can produce when invoked // with these parameters is 28 character long (not including // the terminating nul character). We are asking for 32 character // buffer just in case. This is also enough for strncpy to // null-terminate the destination string. posix::StrNCpy( str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); str[31] = '\0'; // Makes sure no change in the format to strncpy leaves // the result unterminated. } return str; } // The following two functions only make sense if the the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first & mask) << 10) | (second & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. String WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); StrStream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } char buffer[32]; // CodePointToUtf8 requires a buffer this big. stream << CodePointToUtf8(unicode_code_point, buffer); } return StrStreamToString(&stream); } // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". String String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return String("(null)"); return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); } // Similar to ShowWideCString(), except that this function encloses // the converted string in double quotes. String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { if (wide_c_str == NULL) return String("(null)"); return String::Format("L\"%s\"", String::ShowWideCString(wide_c_str).c_str()); } // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual) { if (String::WideCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, String::ShowWideCStringQuoted(expected), String::ShowWideCStringQuoted(actual), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } Message msg; msg << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << String::ShowWideCStringQuoted(s1) << " vs " << String::ShowWideCStringQuoted(s2); return AssertionFailure(msg); } // Compares two C strings, ignoring case. Returns true iff they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX return wcscasecmp(lhs, rhs) == 0; #else // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes // may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; #endif // OS selector } // Compares this with another String. // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 // if this is greater than rhs. int String::Compare(const String & rhs) const { const char* const lhs_c_str = c_str(); const char* const rhs_c_str = rhs.c_str(); if (lhs_c_str == NULL) { return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL } else if (rhs_c_str == NULL) { return 1; } const size_t shorter_str_len = length() <= rhs.length() ? length() : rhs.length(); for (size_t i = 0; i != shorter_str_len; i++) { if (lhs_c_str[i] < rhs_c_str[i]) { return -1; } else if (lhs_c_str[i] > rhs_c_str[i]) { return 1; } } return (length() < rhs.length()) ? -1 : (length() > rhs.length()) ? 1 : 0; } // Returns true iff this String ends with the given suffix. *Any* // String is considered to end with a NULL or empty suffix. bool String::EndsWith(const char* suffix) const { if (suffix == NULL || CStringEquals(suffix, "")) return true; if (c_str() == NULL) return false; const size_t this_len = strlen(c_str()); const size_t suffix_len = strlen(suffix); return (this_len >= suffix_len) && CStringEquals(c_str() + this_len - suffix_len, suffix); } // Returns true iff this String ends with the given suffix, ignoring case. // Any String is considered to end with a NULL or empty suffix. bool String::EndsWithCaseInsensitive(const char* suffix) const { if (suffix == NULL || CStringEquals(suffix, "")) return true; if (c_str() == NULL) return false; const size_t this_len = strlen(c_str()); const size_t suffix_len = strlen(suffix); return (this_len >= suffix_len) && CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); } // Formats a list of arguments to a String, using the same format // spec string as for printf. // // We do not use the StringPrintf class as it is not universally // available. // // The result is limited to 4096 characters (including the tailing 0). // If 4096 characters are not enough to format the input, or if // there's an error, "" is // returned. String String::Format(const char * format, ...) { va_list args; va_start(args, format); char buffer[4096]; const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. #ifdef _MSC_VER // We are using MSVC. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. const int size = vsnprintf(buffer, kBufferSize, format, args); #pragma warning(pop) // Restores the warning state. #else // We are not using MSVC. const int size = vsnprintf(buffer, kBufferSize, format, args); #endif // _MSC_VER va_end(args); // vsnprintf()'s behavior is not portable. When the buffer is not // big enough, it returns a negative value in MSVC, and returns the // needed buffer size on Linux. When there is an output error, it // always returns a negative value. For simplicity, we lump the two // error cases together. if (size < 0 || size >= kBufferSize) { return String(""); } else { return String(buffer, size); } } // Converts the buffer in a StrStream to a String, converting NUL // bytes to "\\0" along the way. String StrStreamToString(StrStream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); // We need to use a helper StrStream to do this transformation // because String doesn't support push_back(). StrStream helper; for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { helper << "\\0"; // Replaces NUL with "\\0"; } else { helper.put(*ch); } } return String(helper.str().c_str()); } // Appends the user-supplied message to the Google-Test-generated message. String AppendUserMessage(const String& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const String user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } Message msg; msg << gtest_msg << "\n" << user_msg_string; return msg.GetString(); } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), elapsed_time_(0) { } // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const TestProperty& test_property) { if (!ValidateTestProperty(test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const TestProperty& test_property) { internal::String key(test_property.key()); if (key == "name" || key == "status" || key == "time" || key == "classname") { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << key << " ('name', 'status', 'time', and 'classname' are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true iff the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true iff the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the values of all Google Test flags. Test::Test() : gtest_flag_saver_(new internal::GTestFlagSaver) { } // The d'tor restores the values of all Google Test flags. Test::~Test() { delete gtest_flag_saver_; } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const char* key, const char* value) { UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const char* key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const String& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, String()); // No stack trace, either. } } // namespace internal #if GTEST_OS_WINDOWS // We are on Windows. // Adds an "exception thrown" fatal failure to the current test. static void AddExceptionThrownFailure(DWORD exception_code, const char* location) { Message message; message << "Exception thrown with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " in " << location << "."; internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, message.GetString()); } #endif // GTEST_OS_WINDOWS // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. const internal::TestInfoImpl* const first_test_info = test_case->test_info_list()[0]->impl(); const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); const char* const first_test_name = first_test_info->name(); // Info about the current test. const internal::TestInfoImpl* const this_test_info = impl->current_test_info()->impl(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell // him/her how to fix it. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test case is\n" << "illegal. In test case " << this_test_info->test_case_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // The user defined two fixture classes with the same name in // two namespaces - we'll tell him/her how to fix it. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << this_test_info->test_case_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test cases."; } return false; } return true; } // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); #if GTEST_HAS_SEH // Catch SEH-style exceptions. impl->os_stack_trace_getter()->UponLeavingGTest(); __try { SetUp(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); } // We will run the test only if SetUp() had no fatal failure. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); __try { TestBody(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "the test body"); } } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); __try { TearDown(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); } #else // We are on a compiler or platform that doesn't support SEH. impl->os_stack_trace_getter()->UponLeavingGTest(); SetUp(); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); TestBody(); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); TearDown(); #endif // GTEST_HAS_SEH } // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true iff the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object via impl_. TestInfo::TestInfo(const char* a_test_case_name, const char* a_name, const char* a_test_case_comment, const char* a_comment, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) { impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, a_test_case_comment, a_comment, fixture_class_id, factory); } // Destructs a TestInfo object. TestInfo::~TestInfo() { delete impl_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // test_case_comment: a comment on the test case that will be included in // the test output // comment: a comment on the test that will be included in the // test output // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, test_case_comment, comment, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << test_case_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test cases."; fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal // Returns the test case name. const char* TestInfo::test_case_name() const { return impl_->test_case_name(); } // Returns the test name. const char* TestInfo::name() const { return impl_->name(); } // Returns the test case comment. const char* TestInfo::test_case_comment() const { return impl_->test_case_comment(); } // Returns the test comment. const char* TestInfo::comment() const { return impl_->comment(); } // Returns true if this test should run. bool TestInfo::should_run() const { return impl_->should_run(); } // Returns true if this test matches the user-specified filter. bool TestInfo::matches_filter() const { return impl_->matches_filter(); } // Returns the result of the test. const TestResult* TestInfo::result() const { return impl_->result(); } // Increments the number of death tests encountered in this test so // far. int TestInfo::increment_death_test_count() { return impl_->result()->increment_death_test_count(); } namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestCase class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && internal::String(test_info->name()).Compare(name_) == 0; } private: internal::String name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { #if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } #endif } // Creates the test object, runs it, records its result, and then // deletes it. void TestInfoImpl::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(parent_); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*parent_); const TimeInMillis start = GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); #if GTEST_HAS_SEH // Catch SEH-style exceptions. Test* test = NULL; __try { // Creates the test object. test = factory_->CreateTest(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "the test fixture's constructor"); return; } #else // We are on a compiler or platform that doesn't support SEH. // TODO(wan): If test->Run() throws, test won't be deleted. This is // not a problem now as we don't use exceptions. If we were to // enable exceptions, we should revise the following to be // exception-safe. // Creates the test object. Test* test = factory_->CreateTest(); #endif // GTEST_HAS_SEH // Runs the test only if the constructor of the test fixture didn't // generate a fatal failure. if (!Test::HasFatalFailure()) { test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); delete test; test = NULL; result_.set_elapsed_time(GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*parent_); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } } // namespace internal // class TestCase // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase::TestCase(const char* a_name, const char* a_comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), comment_(a_comment), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. void TestCase::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); set_up_tc_(); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->impl()->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); tear_down_tc_(); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); } // Returns true iff test passed. bool TestCase::TestPassed(const TestInfo * test_info) { const internal::TestInfoImpl* const impl = test_info->impl(); return impl->should_run() && impl->result()->Passed(); } // Returns true iff test failed. bool TestCase::TestFailed(const TestInfo * test_info) { const internal::TestInfoImpl* const impl = test_info->impl(); return impl->should_run() && impl->result()->Failed(); } // Returns true iff test is disabled. bool TestCase::TestDisabled(const TestInfo * test_info) { return test_info->impl()->is_disabled(); } // Returns true if the given test should run. bool TestCase::ShouldRunTest(const TestInfo *test_info) { return test_info->impl()->should_run(); } // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static internal::String FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::String::Format("%d %s", count, count == 1 ? singular_form : plural_form); } // Formats the count of tests. static internal::String FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static internal::String FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif } return "Unknown result type"; } // Prints a TestPartResult to a String. static internal::String PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const internal::String& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter namespace internal { enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return NULL; }; } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); internal::String test_case_name_; }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!internal::String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %s of %s.\n", internal::posix::GetEnv(kTestShardIndex), internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { test_case_name_ = test_case.name(); const internal::String counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case_name_.c_str()); if (test_case.comment()[0] == '\0') { printf("\n"); } else { printf(", where %s\n", test_case.comment()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info.name()); if (test_info.comment()[0] == '\0') { printf("\n"); } else { printf(", where %s\n", test_info.comment()); } fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TestPartResult::kSuccess) return; // Print failure message from the assertion (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_case_name_.c_str(), test_info.name()); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; test_case_name_ = test_case.name(); const internal::String counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case_name_.c_str(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); if (test_case.comment()[0] != '\0' || test_info.comment()[0] != '\0') { printf(", where %s", test_case.comment()); if (test_case.comment()[0] != '\0' && test_info.comment()[0] != '\0') { printf(" and "); } } printf("%s\n", test_info.comment()); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + i); return listener; } } return NULL; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ listeners_[i]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static String EscapeXml(const char* str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static String RemoveInvalidXmlCharacters(const char* str); // Convenience wrapper around EscapeXml when str is an attribute value. static String EscapeXmlAttribute(const char* str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(FILE* out, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the String is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static String TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const String output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.c_str() == NULL || output_file_.empty()) { fprintf(stderr, "XML output file may not be null\n"); fflush(stderr); exit(EXIT_FAILURE); } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. // // We don't do it for now as: // // 1. There is no urgent need for it. // 2. It's a bit involved to make the errno variable thread-safe on // all three operating systems (Linux, Windows, and Mac OS). // 3. To interpret the meaning of errno in a thread-safe way, // we need the strerror_r() function, which is not available on // Windows. fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); fflush(stderr); exit(EXIT_FAILURE); } PrintXmlUnitTest(xmlout, unit_test); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { Message m; if (str != NULL) { for (const char* src = str; *src; ++src) { switch (*src) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(*src)) { if (is_attribute && IsNormalizableWhitespace(*src)) m << String::Format("&#x%02X;", unsigned(*src)); else m << *src; } break; } } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { char* const output = new char[strlen(str) + 1]; char* appender = output; for (char ch = *str; ch != '\0'; ch = *++str) if (IsValidXmlCharacter(ch)) *appender++ = ch; *appender = '\0'; String ret_value(output); delete[] output; return ret_value; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << ms/1000.0; return ss.str(); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); *stream << " \n"; *stream << " "; const String message = RemoveInvalidXmlCharacters(String::Format( "%s:%d\n%s", part.file_name(), part.line_number(), part.message()).c_str()); OutputXmlCDataSection(stream, message.c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, const TestCase& test_case) { fprintf(out, " \n", FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); for (int i = 0; i < test_case.total_test_count(); ++i) { StrStream stream; OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); fprintf(out, "%s", StrStreamToString(&stream).c_str()); } fprintf(out, " \n"); } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, const UnitTest& unit_test) { fprintf(out, "\n"); fprintf(out, "\n"); for (int i = 0; i < unit_test.total_test_case_count(); ++i) PrintXmlTestCase(out, *unit_test.GetTestCase(i)); fprintf(out, "\n"); } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } // End XmlUnitTestResultPrinter // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. // L < UnitTest::mutex_ ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. // L < UnitTest::mutex_ ScopedTrace::~ScopedTrace() { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter // Returns the current OS stack trace as a String. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // // L < mutex_ // We use "L < mutex_" to denote that the function may acquire mutex_. String OsStackTraceGetter::CurrentStackTrace(int, int) { return String(""); } // L < mutex_ void OsStackTraceGetter::UponLeavingGTest() { } const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) default_xml_generator_ = NULL; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != NULL) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != NULL) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest * UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Gets the number of successful test cases. int UnitTest::successful_test_case_count() const { return impl()->successful_test_case_count(); } // Gets the number of failed test cases. int UnitTest::failed_test_case_count() const { return impl()->failed_test_case_count(); } // Gets the number of all test cases. int UnitTest::total_test_case_count() const { return impl()->total_test_case_count(); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTest::test_case_to_run_count() const { return impl()->test_case_to_run_count(); } // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true iff the unit test passed (i.e. all test cases passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { return impl()->GetMutableTestCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == NULL) { return NULL; } impl_->environments().push_back(env); return env; } #if GTEST_HAS_EXCEPTIONS // A failed Google Test assertion will throw an exception of this type // when exceptions are enabled. We derive it from std::runtime_error, // which is for errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} }; #endif // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. // L < mutex_ void UnitTest::AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const internal::String& message, const internal::String& os_stack_trace) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (int i = static_cast(impl_->gtest_trace_stack().size()); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Creates and adds a property to the current TestResult. If a property matching // the supplied value already exists, updates its value instead. void UnitTest::RecordPropertyForCurrentTest(const char* key, const char* value) { const TestProperty test_property(key, value); impl_->current_test_result()->RecordProperty(test_property); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { #if GTEST_HAS_SEH // Catch SEH-style exceptions. const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected.. if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { #if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); #endif // !GTEST_OS_WINDOWS_MOBILE #if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); #endif #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. // TODO(vladl@google.com): find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. #endif } __try { return impl_->RunAllTests(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); fflush(stdout); return 1; } #else // We are on a compiler or platform that doesn't support SEH. return impl_->RunAllTests(); #endif // GTEST_HAS_SEH } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. // L < mutex_ const TestCase* UnitTest::current_test_case() const { internal::MutexLock lock(&mutex_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. // L < mutex_ const TestInfo* UnitTest::current_test_info() const { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // L < mutex_ internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. // L < mutex_ void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. // L < mutex_ void UnitTest::PopGTestTrace() { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #endif // _MSC_VER global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. #if GTEST_HAS_DEATH_TEST elapsed_time_(0), internal_run_death_test_flag_(NULL), death_test_factory_(new DefaultDeathTestFactory) { #else elapsed_time_(0) { #endif // GTEST_HAS_DEATH_TEST listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != NULL) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const String& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); fflush(stdout); } } // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); } } // A predicate that checks the name of a TestCase against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestCaseNameIs is copyable. class TestCaseNameIs { public: // Constructor. explicit TestCaseNameIs(const String& name) : name_(name) {} // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: String name_; }; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_case_name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::const_iterator test_case = std::find_if(test_cases_.begin(), test_cases_.end(), TestCaseNameIs(test_case_name)); if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. TestCase* const new_test_case = new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_case_; test_cases_.insert(test_cases_.begin() + last_death_test_case_, new_test_case); } else { // No. Appends to the end of the list. test_cases_.push_back(new_test_case); } test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns 0 if all tests are successful, or 1 otherwise. If any // exception is thrown during a test on Windows, this test is // considered to be failed, but the rest of the tests will still be // run. (We disable exceptions on Linux and Mac OS X, so the issue // doesn't apply there.) // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. int UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); return 1; } // Do not run any test if the --help flag was specified. if (g_help_flag) return 0; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return 0; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True iff at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { ClearResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test cases and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(random_seed_); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_case_count(); test_index++) { GetMutableTestCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); // Returns 0 if all tests passed, or 1 other wise. return failed ? 1 : 0; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; const String &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; const String test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter(test_case_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->impl()->set_matches_filter(matches_filter); const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests)); num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->impl()->set_should_run(is_selected); test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; if (test_info->matches_filter()) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.\n", test_case->name()); } printf(" %s\n", test_info->name()); } } } fflush(stdout); } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { os_stack_trace_getter_ = new OsStackTraceGetter; } return os_stack_trace_getter_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? current_test_info_->impl()->result() : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. test_case_indices_[i] = static_cast(i); } } // TestInfoImpl constructor. The new instance assumes ownership of the test // factory object. TestInfoImpl::TestInfoImpl(TestInfo* parent, const char* a_test_case_name, const char* a_name, const char* a_test_case_comment, const char* a_comment, TypeId a_fixture_class_id, internal::TestFactoryBase* factory) : parent_(parent), test_case_name_(String(a_test_case_name)), name_(String(a_name)), test_case_comment_(String(a_test_case_comment)), comment_(String(a_comment)), fixture_class_id_(a_fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory) { } // TestInfoImpl destructor. TestInfoImpl::~TestInfoImpl() { delete factory_; } // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable // code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return NULL; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == NULL) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // // TODO(wan@google.com): Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == NULL) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", String(str, p - str).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" #endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" #if GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" " Suppress pop-ups caused by exceptions.\n" #endif // GTEST_OS_WINDOWS "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const String arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; // Do we see a Google Test flag? if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { g_init_gtest_count++; // We don't want to run the initialization code twice. if (g_init_gtest_count != 1) return; if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } } // namespace testing // Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. #if GTEST_HAS_DEATH_TEST #if GTEST_OS_MAC #include #endif // GTEST_OS_MAC #include #include #include #include #if GTEST_OS_WINDOWS #include #else #include #include #endif // GTEST_OS_WINDOWS #endif // GTEST_HAS_DEATH_TEST // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "colons. This flag is specified if and only if the current " "process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { #if GTEST_OS_WINDOWS return exit_status == exit_code_; #else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; #endif // GTEST_OS_WINDOWS } #if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } #endif // !GTEST_OS_WINDOWS namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static String ExitSummary(int exit_code) { Message m; #if GTEST_OS_WINDOWS m << "Exited with exit status " << exit_code; #else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } #ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } #endif #endif // GTEST_OS_WINDOWS return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } #if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static String DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else msg << "detected " << thread_count << " threads."; return msg.GetString(); } #endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestInternalError = 'I'; // An enumeration describing all of the possible ways that a death test // can conclude. DIED means that the process died while executing the // test code; LIVED means that process lived beyond the end of the test // code; and RETURNED means that the test statement attempted a "return," // which is not allowed. IN_PROGRESS means the test has not yet // concluded. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. void DeathTestAbort(const String& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. #define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s", \ __FILE__, __LINE__, #expression)); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. #define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s != -1", \ __FILE__, __LINE__, #expression)); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. String GetLastErrnoDescription() { return String(errno == 0 ? "" : posix::StrError(errno)); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == NULL) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, regex, file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const String& message) { last_death_test_message_ = message; } String DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, const RE* a_regex) : statement_(a_statement), regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // The regular expression which test output must match. DeathTestImpl // doesn't own this object and should not attempt to delete it. const RE* const regex_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, or RETURNED. The death test fails // in the latter two cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // regex: A regular expression object to be applied to // the test's captured standard error output; the death test // fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const String error_message = GetCapturedStderr(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg: " << error_message; break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg: " << error_message; break; case DIED: if (status_ok) { const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" << "Actual msg: " << error_message; } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n"; } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } #if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* statement, const RE* regex, const char* file, int line) : DeathTestImpl(statement, regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status; GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) != FALSE); child_handle_.Reset(); set_status(static_cast(status)); return this->status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); const String filter_flag = String::Format("--%s%s=%s.%s", GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); const String internal_flag = String::Format( "--%s%s=%s|%d|%d|%u|%Iu|%Iu", GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, static_cast(::GetCurrentProcessId()), // size_t has the same with as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. reinterpret_cast(write_handle), reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); String command_line = String::Format("%s %s \"%s\"", ::GetCommandLineA(), filter_flag.c_str(), internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_(::CreateProcessA( executable_path, const_cast(command_line.c_str()), NULL, // Retuned process handle is not inheritable. NULL, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } #else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(NULL); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; #if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } #else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } #endif // GTEST_OS_MAC // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", original_dir, GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", args->argv[0], original_dir, GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. bool StackLowerThanAddress(const void* ptr) { int dummy; return &dummy < ptr; } bool StackGrowsDown() { int dummy; return StackLowerThanAddress(&dummy); } // A threadsafe implementation of fork(2) for threadsafe-style death tests // that uses clone(2). It dies with an error message if anything goes // wrong. static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; #if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const size_t stack_size = getpagesize(); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size : 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } #else const bool use_fork = true; #endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const String filter_flag = String::Format("--%s%s=%s.%s", GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); const String internal_flag = String::Format("--%s%s=%s|%d|%d|%d", GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, pipe_fd[1]); Arguments args; args.AddArguments(GetArgvs()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } #endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != NULL) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message(String::Format( "Death test count (%d) somehow exceeded expected maximum (%d)", death_test_index, flag->index())); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = NULL; return true; } } #if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } #else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } #endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message(String::Format( "Unknown death test style \"%s\" encountered", GTEST_FLAG(death_test_style).c_str())); return false; } return true; } // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } #if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort(String::Format("Unable to open parent process %u", parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort(String::Format( "Unable to duplicate the pipe handle %Iu from the parent process %u", write_handle_as_size_t, parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort(String::Format( "Unable to duplicate the event handle %Iu from the parent process %u", event_handle_as_size_t, parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort(String::Format( "Unable to convert pipe handle %Iu to a file descriptor", write_handle_as_size_t)); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } #endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; #if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort(String::Format( "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); #else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort(String::Format( "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } #endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing // Copyright 2008, Google Inc. // 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. // // Authors: keith.ray@gmail.com (Keith Ray) #include #if GTEST_OS_WINDOWS_MOBILE #include #elif GTEST_OS_WINDOWS #include #include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h #include #else #include #include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS #define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) #define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) #define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else #define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS namespace testing { namespace internal { #if GTEST_OS_WINDOWS // On Windows, '\\' is the standard path separator, but many tools and the // Windows API also accept '/' as an alternate path separator. Unless otherwise // noted, a file path can contain either kind of path separators, or a mixture // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; #else const char kCurrentDirectoryString[] = ".\\"; #endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS // Returns whether the given character is a valid path separator. static bool IsPathSeparator(char c) { #if GTEST_HAS_ALT_PATH_SEP_ return (c == kPathSeparator) || (c == kAlternatePathSeparator); #else return c == kPathSeparator; #endif } // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { String dot_extension(String::Format(".%s", extension)); if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); } return *this; } // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { const char* const last_sep = strrchr(c_str(), kPathSeparator); #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. if (last_alt_sep != NULL && (last_sep == NULL || last_alt_sep > last_sep)) { return last_alt_sep; } #endif return last_sep; } // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { const char* const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(String(last_sep + 1)) : *this; } // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); String dir; if (last_sep) { dir = String(c_str(), last_sep + 1 - c_str()); } else { dir = kCurrentDirectoryString; } return FilePath(dir); } // Helper functions for naming files in a directory for xml output. // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { String file; if (number == 0) { file = String::Format("%s.%s", base_name.c_str(), extension); } else { file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); } return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. FilePath FilePath::ConcatPaths(const FilePath& directory, const FilePath& relative_path) { if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, relative_path.c_str())); } // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; return attributes != kInvalidFileAttributes; #else posix::StatStruct file_stat; return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // GTEST_OS_WINDOWS_MOBILE } // Returns true if pathname describes a directory in the file-system // that exists. bool FilePath::DirectoryExists() const { bool result = false; #if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : RemoveTrailingPathSeparator()); #else const FilePath& path(*this); #endif #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; if ((attributes != kInvalidFileAttributes) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { result = true; } #else posix::StatStruct file_stat; result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // GTEST_OS_WINDOWS_MOBILE return result; } // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); #endif } // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); #if GTEST_OS_WINDOWS return pathname_.length() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && IsPathSeparator(name[2]); #else return IsPathSeparator(name[0]); #endif } // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension) { FilePath full_pathname; int number = 0; do { full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); } while (full_pathname.FileOrDirectoryExists()); return full_pathname; } // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool FilePath::IsDirectory() const { return !pathname_.empty() && IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); } // Create directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create directories // for any reason. bool FilePath::CreateDirectoriesRecursively() const { if (!this->IsDirectory()) { return false; } if (pathname_.length() == 0 || this->DirectoryExists()) { return true; } const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); return parent.CreateDirectoriesRecursively() && this->CreateFolder(); } // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); int result = CreateDirectory(unicode, NULL) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); #else int result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE if (result == -1) { return this->DirectoryExists(); // An error is OK if the directory exists. } return true; // No error. } // If input name has a trailing separator character, remove it and return the // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return IsDirectory() ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) : *this; } // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; return; } const char* src = pathname_.c_str(); char* const dest = new char[pathname_.length() + 1]; char* dest_ptr = dest; memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { *dest_ptr = *src; if (!IsPathSeparator(*src)) { src++; } else { #if GTEST_HAS_ALT_PATH_SEP_ if (*dest_ptr == kAlternatePathSeparator) { *dest_ptr = kPathSeparator; } #endif while (IsPathSeparator(*src)) src++; } dest_ptr++; } *dest_ptr = '\0'; pathname_ = dest; delete[] dest; } } // namespace internal } // namespace testing // Copyright 2008, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include #include #if GTEST_OS_WINDOWS_MOBILE #include // For TerminateProcess() #elif GTEST_OS_WINDOWS #include #include #else #include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC #include #include #include #endif // GTEST_OS_MAC // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; thread_act_array_t thread_list; const kern_return_t status = task_threads(task, &thread_list, &thread_count); if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { return 0; } } #else size_t GetThreadCount() { // There's no portable way to detect the number of threads, so we just // return 0 to indicate that we cannot detect it. return 0; } #endif // GTEST_OS_MAC #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. RE::~RE() { if (is_valid_) { // regfree'ing an invalid regex might crash because the content // of the regex is undefined. Since the regex's are essentially // the same, one cannot be valid (or invalid) without the other // being so too. regfree(&partial_regex_); regfree(&full_regex_); } free(const_cast(pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. const size_t full_regex_len = strlen(regex) + 10; char* const full_pattern = new char[full_regex_len]; snprintf(full_pattern, full_regex_len, "^(%s)$", regex); is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; // We want to call regcomp(&partial_regex_, ...) even if the // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. // // Some implementation of POSIX regex (e.g. on at least some // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. if (is_valid_) { const char* const partial_regex = (*regex == '\0') ? "()" : regex; is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; } EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; delete[] full_pattern; } #elif GTEST_USES_SIMPLE_RE // Returns true iff ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { return ch != '\0' && strchr(str, ch) != NULL; } // Returns true iff ch belongs to the given classification. Unlike // similar functions in , these aren't affected by the // current locale. bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true iff "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true iff the given atom (specified by escaped and pattern) // matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { case 'd': return IsDigit(ch); case 'D': return !IsDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; case 's': return IsWhiteSpace(ch); case 'S': return !IsWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; case 'w': return IsWordChar(ch); case 'W': return !IsWordChar(ch); } return IsPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; } // Helper function used by ValidateRegex() to format error messages. String FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { // TODO(wan@google.com): fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; // True iff ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence i++; if (regex[i] == '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "'\\' cannot appear at the end."; return false; } if (!IsValidEscape(regex[i])) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "invalid escape sequence \"\\" << regex[i] << "\"."; is_valid = false; } prev_repeatable = true; } else { // Not an escape sequence. const char ch = regex[i]; if (ch == '^' && i > 0) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'^' can only appear at the beginning."; is_valid = false; } else if (ch == '$' && regex[i + 1] != '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'$' can only appear at the end."; is_valid = false; } else if (IsInSet(ch, "()[]{}|")) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' is unsupported."; is_valid = false; } else if (IsRepeat(ch) && !prev_repeatable) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' can only follow a repeatable token."; is_valid = false; } prev_repeatable = !IsInSet(ch, "^$?*+"); } } return is_valid; } // Matches a repeated regex atom followed by a valid simple regular // expression. The regex atom is defined as c if escaped is false, // or \c otherwise. repeat is the repetition meta character (?, *, // or +). The behavior is undefined if str contains too many // characters to be indexable by size_t, in which case the test will // probably time out anyway. We are fine with this limitation as // std::string has it too. bool MatchRepetitionAndRegexAtHead( bool escaped, char c, char repeat, const char* regex, const char* str) { const size_t min_count = (repeat == '+') ? 1 : 0; const size_t max_count = (repeat == '?') ? 1 : static_cast(-1) - 1; // We cannot call numeric_limits::max() as it conflicts with the // max() macro on Windows. for (size_t i = 0; i <= max_count; ++i) { // We know that the atom matches each of the first i characters in str. if (i >= min_count && MatchRegexAtHead(regex, str + i)) { // We have enough matches at the head, and the tail matches too. // Since we only care about *whether* the pattern matches str // (as opposed to *how* it matches), there is no need to find a // greedy match. return true; } if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) return false; } return false; } // Returns true iff regex matches a prefix of str. regex must be a // valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. return true; // "$" only matches the end of a string. Note that regex being // valid guarantees that there's nothing after "$" in it. if (*regex == '$') return *str == '\0'; // Is the first thing in regex an escape sequence? const bool escaped = *regex == '\\'; if (escaped) ++regex; if (IsRepeat(regex[1])) { // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so // here's an indirect recursion. It terminates as the regex gets // shorter in each recursion. return MatchRepetitionAndRegexAtHead( escaped, regex[0], regex[1], regex + 2, str); } else { // regex isn't empty, isn't "$", and doesn't start with a // repetition. We match the first atom of regex with the first // character of str and recurse. return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && MatchRegexAtHead(regex + 1, str + 1); } } // Returns true iff regex matches any substring of str. regex must be // a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of // stack space normally. In rare cases the time complexity can be // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { if (regex == NULL || str == NULL) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); // A successful match can be anywhere in str. do { if (MatchRegexAtHead(regex, str)) return true; } while (*str++ != '\0'); return false; } // Implements the RE class. RE::~RE() { free(const_cast(pattern_)); free(const_cast(full_pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { pattern_ = posix::StrDup(regex); } is_valid_ = ValidateRegex(regex); if (!is_valid_) { // No need to calculate the full pattern when the regex is invalid. return; } const size_t len = strlen(regex); // Reserves enough bytes to hold the regular expression used for a // full match: we need space to prepend a '^', append a '$', and // terminate the string with '\0'. char* buffer = static_cast(malloc(len + 3)); full_pattern_ = buffer; if (*regex != '^') *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. // We don't use snprintf or strncpy, as they trigger a warning when // compiled with VC++ 8.0. memcpy(buffer, regex, len); buffer += len; if (len == 0 || regex[len - 1] != '$') *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. *buffer = '\0'; } #endif // GTEST_USES_POSIX_RE GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = severity == GTEST_INFO ? "[ INFO ]" : severity == GTEST_WARNING ? "[WARNING]" : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; GetStream() << ::std::endl << marker << " " << FormatFileLocation(file, line).c_str() << ": "; } // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. GTestLog::~GTestLog() { GetStream() << ::std::endl; if (severity_ == GTEST_FATAL) { fflush(stderr); posix::Abort(); } } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4996) #endif // _MSC_VER #if GTEST_HAS_STREAM_REDIRECTION_ // Object that captures an output stream (stdout/stderr). class CapturedStream { public: // The ctor redirects the stream to a temporary file. CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { #if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); const UINT success = ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, // Generate unique file name. temp_file_path); GTEST_CHECK_(success != 0) << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; #else // There's no guarantee that a test has write access to the // current directory, so we create the temporary file in the /tmp // directory instead. char name_template[] = "/tmp/captured_stream.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; #endif // GTEST_OS_WINDOWS fflush(NULL); dup2(captured_fd, fd_); close(captured_fd); } ~CapturedStream() { remove(filename_.c_str()); } String GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. fflush(NULL); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); const String content = ReadEntireFile(file); posix::FClose(file); return content; } private: // Reads the entire content of a file as a String. static String ReadEntireFile(FILE* file); // Returns the size (in bytes) of a file. static size_t GetFileSize(FILE* file); const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. ::std::string filename_; GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; // Returns the size (in bytes) of a file. size_t CapturedStream::GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } // Reads the entire content of a file as a string. String CapturedStream::ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_read = 0; // # of bytes read so far fseek(file, 0, SEEK_SET); // Keeps reading the file until we cannot read further or the // pre-determined file size is reached. do { bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); const String content(buffer, bytes_read); delete[] buffer; return content; } #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } *stream = new CapturedStream(fd); } // Stops capturing the output stream and returns the captured string. String GetCapturedStream(CapturedStream** captured_stream) { const String content = (*captured_stream)->GetCapturedString(); delete *captured_stream; *captured_stream = NULL; return content; } // Starts capturing stdout. void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); } // Starts capturing stderr. void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); } // Stops capturing stdout and returns the captured string. String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #endif // GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector g_argvs; // Returns the command line as a vector of strings. const ::std::vector& GetArgvs() { return g_argvs; } #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE namespace posix { void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } } // namespace posix #endif // GTEST_OS_WINDOWS_MOBILE // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. static String FlagToEnvVar(const char* flag) { const String full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { env_var << static_cast(toupper(full_flag.c_str()[i])); } return env_var.GetString(); } // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. char* end = NULL; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? if (*end != '\0') { // No - an invalid character was encountered. Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value \"" << str << "\".\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } // Is the parsed value in the range of an Int32? const Int32 result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value // The parsed value overflows as an Int32. ) { Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value " << str << ", which overflows.\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } *value = result; return true; } // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const String env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const String env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; } Int32 result = default_value; if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, &result)) { printf("The default value %s is used.\n", (Message() << default_value).GetString().c_str()); fflush(stdout); return default_value; } return result; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const String env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } } // namespace internal } // namespace testing // Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // // The Google C++ Testing Framework (Google Test) // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. internal::String TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); return stack_trace == NULL ? internal::String(message) : internal::String(message, stack_trace - message); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { return os << result.file_name() << ":" << result.line_number() << ": " << (result.type() == TestPartResult::kSuccess ? "Success" : result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : "Non-fatal failure") << ":\n" << result.message() << std::endl; } // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); internal::posix::Abort(); } return array_[index]; } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { return static_cast(array_.size()); } namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } void HasNewFatalFailureHelper::ReportTestPartResult( const TestPartResult& result) { if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } } // namespace internal } // namespace testing // Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) namespace testing { namespace internal { #if GTEST_HAS_TYPED_TEST_P // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { while (isspace(*str)) str++; return str; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef ::std::set::const_iterator DefinedTestIter; registered_ = true; // Skip initial whitespace in registered_tests since some // preprocessors prefix stringizied literals with whitespace. registered_tests = SkipSpaces(registered_tests); Message errors; ::std::set tests; for (const char* names = registered_tests; names != NULL; names = SkipComma(names)) { const String name = GetPrefixUntilComma(names); if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (name == *it) { found = true; break; } } if (found) { tests.insert(name); } else { errors << "No test named " << name << " can be found in this test case.\n"; } } for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (tests.count(*it) == 0) { errors << "You forgot to list test " << *it << ".\n"; } } const String& errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); fflush(stderr); posix::Abort(); } return registered_tests; } #endif // GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/configure0000775000175100017510000212735512623076773020542 0ustar jenkins-buildjenkins-build#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Google C++ Testing Framework 1.5.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: googletestframework@googlegroups.com about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Google C++ Testing Framework' PACKAGE_TARNAME='gtest' PACKAGE_VERSION='1.5.0' PACKAGE_STRING='Google C++ Testing Framework 1.5.0' PACKAGE_BUGREPORT='googletestframework@googlegroups.com' PACKAGE_URL='' ac_unique_file="./COPYING" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS HAVE_PTHREADS_FALSE HAVE_PTHREADS_TRUE PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC acx_pthread_config HAVE_PYTHON_FALSE HAVE_PYTHON_TRUE PYTHON CXXCPP CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock with_pthreads ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CPP CXXCPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures Google C++ Testing Framework 1.5.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/gtest] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Google C++ Testing Framework 1.5.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-pthreads use pthreads (default is yes) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor CXXCPP C++ preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Google C++ Testing Framework configure 1.5.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Google C++ Testing Framework $as_me 1.5.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Provide various options to initialize the Autoconf and configure processes. ac_aux_dir= for ac_dir in build-aux "$srcdir"/build-aux; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ac_config_headers="$ac_config_headers build-aux/config.h" ac_config_files="$ac_config_files Makefile" ac_config_files="$ac_config_files scripts/gtest-config" # Initialize Automake with various options. We require at least v1.9, prevent # pedantic complaints about package files, and enable various distribution # targets. am__api_version='1.14' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='gtest' VERSION='1.5.0' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi # Check for programs used in building Google Test. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu CC="$lt_save_CC" if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu else _lt_caught_CXX_error=yes fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= compiler_needs_object_CXX=no export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no inherit_rpath_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds reload_flag_CXX=$reload_flag reload_cmds_CXX=$reload_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC compiler_CXX=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes file_list_spec_CXX='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec_CXX='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty # executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' fi archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds its shared # libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_CXX=' ' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=yes file_list_spec_CXX='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' enable_shared_with_static_runtimes_CXX=yes # Don't use ranlib old_postinstall_cmds_CXX='chmod 644 $oldlib' postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec_CXX='' fi link_all_deplibs_CXX=yes allow_undefined_flag_CXX="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" if test "$lt_cv_apple_cc_single_mod" != "yes"; then archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; haiku*) archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs_CXX=yes ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) ;; *) export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix[3-9]*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: inherit_rpath_CXX=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [1-5].* | *pgcpp\ [1-5].*) prelink_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' old_archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' hardcode_libdir_flag_spec_CXX='-R$libdir' whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object_CXX=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) ld_shlibs_CXX=yes ;; openbsd2*) # C++ shared libraries are fairly broken ld_shlibs_CXX=no ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no hardcode_direct_absolute_CXX=yes archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='${wl}-E' whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else ld_shlibs_CXX=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) case $host in osf3*) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ;; *) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' ;; esac hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='${wl}-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_CXX='${wl}-z,text' allow_undefined_flag_CXX='${wl}-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ '"$old_archive_cmds_CXX" reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ '"$reload_cmds_CXX" ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken case $host_os in interix[3-9]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac compiler_lib_search_dirs_CXX= if test -n "${compiler_lib_search_path_CXX}"; then compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic_CXX='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static_CXX= ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix[4-9]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) # IBM XL 8.0, 9.0 on PPC and BlueGene lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-qpic' lt_prog_compiler_static_CXX='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works_CXX=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works_CXX=yes fi else lt_cv_prog_compiler_static_works_CXX=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then : else lt_prog_compiler_static_CXX= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' case $host_os in aix[4-9]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' ;; esac ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs_CXX=no ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no with_gnu_ld_CXX=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc_CXX=no else lt_cv_archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 $as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || test -n "$runpath_var_CXX" || test "X$hardcode_automatic_CXX" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink || test "$inherit_rpath_CXX" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_config_commands="$ac_config_commands libtool" # Only expand once: # TODO(chandlerc@google.com): Currently we aren't running the Python tests # against the interpreter detected by AM_PATH_PYTHON, and so we condition # HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's # version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" # hashbang. PYTHON= # We *do not* allow the user to specify a python interpreter # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PYTHON" && ac_cv_path_PYTHON=":" ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$PYTHON" != ":"; then : prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.3'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 ($PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : : else PYTHON=":" fi fi if test "$PYTHON" != ":"; then HAVE_PYTHON_TRUE= HAVE_PYTHON_FALSE='#' else HAVE_PYTHON_TRUE='#' HAVE_PYTHON_FALSE= fi # Configure pthreads. # Check whether --with-pthreads was given. if test "${with_pthreads+set}" = set; then : withval=$with_pthreads; with_pthreads=$withval else with_pthreads=check fi have_pthreads=no if test "x$with_pthreads" != "xno"; then : ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 $as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_join (); int main () { return pthread_join (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 $as_echo_n "checking whether pthreads work without any flags... " >&6; } ;; -*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 $as_echo_n "checking whether pthreads work with $flag... " >&6; } PTHREAD_CFLAGS="$flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_acx_pthread_config+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$acx_pthread_config"; then ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_acx_pthread_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no" fi fi acx_pthread_config=$ac_cv_prog_acx_pthread_config if test -n "$acx_pthread_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5 $as_echo "$acx_pthread_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 $as_echo_n "checking for the pthreads library -l$flag... " >&6; } PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int attr=$attr; return attr; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : attr_name=$attr; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 $as_echo "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then cat >>confdefs.h <<_ACEOF #define PTHREAD_CREATE_JOINABLE $attr_name _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 $as_echo_n "checking if more special flags are required for pthreads... " >&6; } flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 $as_echo "${flag}" >&6; } if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then for ac_prog in xlc_r cc_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PTHREAD_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PTHREAD_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 $as_echo "$PTHREAD_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to check for GCC pthread/shared inconsistencies" >&5 $as_echo_n "checking whether to check for GCC pthread/shared inconsistencies... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is sufficient with -shared" >&5 $as_echo_n "checking whether -pthread is sufficient with -shared... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread fixes that" >&5 $as_echo_n "checking whether -lpthread fixes that... " >&6; } LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc_r fixes that" >&5 $as_echo_n "checking whether -lc_r fixes that... " >&6; } LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test x"$done" = xno; then # OK, we have run out of ideas { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries" >&5 $as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries" >&2;} # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then $as_echo "#define HAVE_PTHREAD 1" >>confdefs.h : else acx_pthread_ok=no if test "x$with_pthreads" != "xcheck"; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-pthreads was specified, but unable to be used See \`config.log' for more details" "$LINENO" 5; } fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu have_pthreads="$acx_pthread_ok" fi if test "x$have_pthreads" == "xyes"; then HAVE_PTHREADS_TRUE= HAVE_PTHREADS_FALSE='#' else HAVE_PTHREADS_TRUE='#' HAVE_PTHREADS_FALSE= fi # TODO(chandlerc@google.com) Check for the necessary system headers. # TODO(chandlerc@google.com) Check the types, structures, and other compiler # and architecture characteristics. # Output the generated files. No further autoconf macros may be used. cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then as_fn_error $? "conditional \"HAVE_PYTHON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PTHREADS_TRUE}" && test -z "${HAVE_PTHREADS_FALSE}"; then as_fn_error $? "conditional \"HAVE_PTHREADS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Google C++ Testing Framework $as_me 1.5.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Google C++ Testing Framework config.status 1.5.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib \ compiler_lib_search_dirs \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ LD_CXX \ reload_flag_CXX \ compiler_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_static_CXX \ lt_cv_prog_compiler_c_o_CXX \ export_dynamic_flag_spec_CXX \ whole_archive_flag_spec_CXX \ compiler_needs_object_CXX \ with_gnu_ld_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_separator_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX \ file_list_spec_CXX \ compiler_lib_search_dirs_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec \ reload_cmds_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ export_symbols_cmds_CXX \ prelink_cmds_CXX \ postlink_cmds_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "build-aux/config.h") CONFIG_HEADERS="$CONFIG_HEADERS build-aux/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "scripts/gtest-config") CONFIG_FILES="$CONFIG_FILES scripts/gtest-config" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "scripts/gtest-config":F) chmod +x scripts/gtest-config ;; "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="CXX " # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects postdep_objects=$lt_postdep_objects predeps=$lt_predeps postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" cat <<_LT_EOF >> "$ofile" # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD=$lt_LD_CXX # How to create reloadable object files. reload_flag=$lt_reload_flag_CXX reload_cmds=$lt_reload_cmds_CXX # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds_CXX # A language specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU compiler? with_gcc=$GCC_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object_CXX # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld_CXX # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute_CXX # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic_CXX # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath_CXX # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds_CXX # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds_CXX # Specify filename containing input files. file_list_spec=$lt_file_list_spec_CXX # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects_CXX postdep_objects=$lt_postdep_objects_CXX predeps=$lt_predeps_CXX postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # ### END LIBTOOL TAG CONFIG: CXX _LT_EOF ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ceph-0.80.11/src/gtest/configure.ac0000664000175100017510000000501712623076744021103 0ustar jenkins-buildjenkins-buildm4_include(m4/acx_pthread.m4) # At this point, the Xcode project assumes the version string will be three # integers separated by periods and surrounded by square brackets (e.g. # "[1.0.1]"). It also asumes that there won't be any closing parenthesis # between "AC_INIT(" and the closing ")" including comments and strings. AC_INIT([Google C++ Testing Framework], [1.5.0], [googletestframework@googlegroups.com], [gtest]) # Provide various options to initialize the Autoconf and configure processes. AC_PREREQ([2.59]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([./COPYING]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([build-aux/config.h]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config]) # Initialize Automake with various options. We require at least v1.9, prevent # pedantic complaints about package files, and enable various distribution # targets. AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects]) # Check for programs used in building Google Test. AC_PROG_CC AC_PROG_CXX AC_LANG([C++]) AC_PROG_LIBTOOL # TODO(chandlerc@google.com): Currently we aren't running the Python tests # against the interpreter detected by AM_PATH_PYTHON, and so we condition # HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's # version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" # hashbang. PYTHON= # We *do not* allow the user to specify a python interpreter AC_PATH_PROG([PYTHON],[python],[:]) AS_IF([test "$PYTHON" != ":"], [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) # Configure pthreads. AC_ARG_WITH([pthreads], [AS_HELP_STRING([--with-pthreads], [use pthreads (default is yes)])], [with_pthreads=$withval], [with_pthreads=check]) have_pthreads=no AS_IF([test "x$with_pthreads" != "xno"], [ACX_PTHREAD( [], [AS_IF([test "x$with_pthreads" != "xcheck"], [AC_MSG_FAILURE( [--with-pthreads was specified, but unable to be used])])]) have_pthreads="$acx_pthread_ok"]) AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"]) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_LIBS) # TODO(chandlerc@google.com) Check for the necessary system headers. # TODO(chandlerc@google.com) Check the types, structures, and other compiler # and architecture characteristics. # Output the generated files. No further autoconf macros may be used. AC_OUTPUT ceph-0.80.11/src/gtest/scripts/0000775000175100017510000000000012623077036020274 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/scripts/gen_gtest_pred_impl.py0000775000175100017510000005275112623076744024702 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2006, Google Inc. # 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. """gen_gtest_pred_impl.py v0.1 Generates the implementation of Google Test predicate assertions and accompanying tests. Usage: gen_gtest_pred_impl.py MAX_ARITY where MAX_ARITY is a positive integer. The command generates the implementation of up-to MAX_ARITY-ary predicate assertions, and writes it to file gtest_pred_impl.h in the directory where the script is. It also generates the accompanying unit test in file gtest_pred_impl_unittest.cc. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import sys import time # Where this script is. SCRIPT_DIR = os.path.dirname(sys.argv[0]) # Where to store the generated header. HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h') # Where to store the generated unit test. UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc') def HeaderPreamble(n): """Returns the preamble for the header file. Args: n: the maximum arity of the predicate macros to be generated. """ # A map that defines the values used in the preamble template. DEFS = { 'today' : time.strftime('%m/%d/%Y'), 'year' : time.strftime('%Y'), 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n), 'n' : n } return ( """// Copyright 2006, Google Inc. // 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. // This file is AUTOMATICALLY GENERATED on %(today)s by command // '%(command)s'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Makes sure this header is not included before gtest.h. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #error Do not include gtest_pred_impl.h directly. Include gtest.h instead. #endif // GTEST_INCLUDE_GTEST_GTEST_H_ // This header implements a family of generic predicate assertion // macros: // // ASSERT_PRED_FORMAT1(pred_format, v1) // ASSERT_PRED_FORMAT2(pred_format, v1, v2) // ... // // where pred_format is a function or functor that takes n (in the // case of ASSERT_PRED_FORMATn) values and their source expression // text, and returns a testing::AssertionResult. See the definition // of ASSERT_EQ in gtest.h for an example. // // If you don't care about formatting, you can use the more // restrictive version: // // ASSERT_PRED1(pred, v1) // ASSERT_PRED2(pred, v1, v2) // ... // // where pred is an n-ary function or functor that returns bool, // and the values v1, v2, ..., must support the << operator for // streaming to std::ostream. // // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most %(n)s. // Please email googletestframework@googlegroups.com if you need // support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. #define GTEST_ASSERT_(expression, on_failure) \\ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\ if (const ::testing::AssertionResult gtest_ar = (expression)) \\ ; \\ else \\ on_failure(gtest_ar.failure_message()) """ % DEFS) def Arity(n): """Returns the English name of the given arity.""" if n < 0: return None elif n <= 3: return ['nullary', 'unary', 'binary', 'ternary'][n] else: return '%s-ary' % n def Title(word): """Returns the given word in title case. The difference between this and string's title() method is that Title('4-ary') is '4-ary' while '4-ary'.title() is '4-Ary'.""" return word[0].upper() + word[1:] def OneTo(n): """Returns the list [1, 2, 3, ..., n].""" return range(1, n + 1) def Iter(n, format, sep=''): """Given a positive integer n, a format string that contains 0 or more '%s' format specs, and optionally a separator string, returns the join of n strings, each formatted with the format string on an iterator ranged from 1 to n. Example: Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'. """ # How many '%s' specs are in format? spec_count = len(format.split('%s')) - 1 return sep.join([format % (spec_count * (i,)) for i in OneTo(n)]) def ImplementationForArity(n): """Returns the implementation of n-ary predicate assertions.""" # A map the defines the values used in the implementation template. DEFS = { 'n' : str(n), 'vs' : Iter(n, 'v%s', sep=', '), 'vts' : Iter(n, '#v%s', sep=', '), 'arity' : Arity(n), 'Arity' : Title(Arity(n)) } impl = """ // Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use // this in your code. template AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS impl += Iter(n, """, const char* e%s""") impl += """, Pred pred""" impl += Iter(n, """, const T%s& v%s""") impl += """) { if (pred(%(vs)s)) return AssertionSuccess(); Message msg; """ % DEFS impl += ' msg << pred_text << "("' impl += Iter(n, """ << e%s""", sep=' << ", "') impl += ' << ") evaluates to false, where"' impl += Iter(n, """ << "\\n" << e%s << " evaluates to " << v%s""") impl += """; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s. // Don't use this in your code. #define GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, on_failure)\\ GTEST_ASSERT_(pred_format(%(vts)s, %(vs)s),\\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use // this in your code. #define GTEST_PRED%(n)s_(pred, %(vs)s, on_failure)\\ GTEST_ASSERT_(::testing::AssertPred%(n)sHelper(#pred""" % DEFS impl += Iter(n, """, \\ #v%s""") impl += """, \\ pred""" impl += Iter(n, """, \\ v%s""") impl += """), on_failure) // %(Arity)s predicate assertion macros. #define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED%(n)s(pred, %(vs)s) \\ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_FATAL_FAILURE_) #define ASSERT_PRED%(n)s(pred, %(vs)s) \\ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_FATAL_FAILURE_) """ % DEFS return impl def HeaderPostamble(): """Returns the postamble for the header file.""" return """ #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ """ def GenerateFile(path, content): """Given a file path and a content string, overwrites it with the given content.""" print 'Updating file %s . . .' % path f = file(path, 'w+') print >>f, content, f.close() print 'File %s has been updated.' % path def GenerateHeader(n): """Given the maximum arity n, updates the header file that implements the predicate assertions.""" GenerateFile(HEADER, HeaderPreamble(n) + ''.join([ImplementationForArity(i) for i in OneTo(n)]) + HeaderPostamble()) def UnitTestPreamble(): """Returns the preamble for the unit test file.""" # A map that defines the values used in the preamble template. DEFS = { 'today' : time.strftime('%m/%d/%Y'), 'year' : time.strftime('%Y'), 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]), } return ( """// Copyright 2006, Google Inc. // 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. // This file is AUTOMATICALLY GENERATED on %(today)s by command // '%(command)s'. DO NOT EDIT BY HAND! // Regression test for gtest_pred_impl.h // // This file is generated by a script and quite long. If you intend to // learn how Google Test works by reading its unit tests, read // gtest_unittest.cc instead. // // This is intended as a regression test for the Google Test predicate // assertions. We compile it as part of the gtest_unittest target // only to keep the implementation tidy and compact, as it is quite // involved to set up the stage for testing Google Test using Google // Test itself. // // Currently, gtest_unittest takes ~11 seconds to run in the testing // daemon. In the future, if it grows too large and needs much more // time to finish, we should consider separating this file into a // stand-alone regression test. #include #include #include // A user-defined data type. struct Bool { explicit Bool(int val) : value(val != 0) {} bool operator>(int n) const { return value > Bool(n).value; } Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } bool operator==(const Bool& rhs) const { return value == rhs.value; } bool value; }; // Enables Bool to be used in assertions. std::ostream& operator<<(std::ostream& os, const Bool& x) { return os << (x.value ? "true" : "false"); } """ % DEFS) def TestsForArity(n): """Returns the tests for n-ary predicate assertions.""" # A map that defines the values used in the template for the tests. DEFS = { 'n' : n, 'es' : Iter(n, 'e%s', sep=', '), 'vs' : Iter(n, 'v%s', sep=', '), 'vts' : Iter(n, '#v%s', sep=', '), 'tvs' : Iter(n, 'T%s v%s', sep=', '), 'int_vs' : Iter(n, 'int v%s', sep=', '), 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '), 'types' : Iter(n, 'typename T%s', sep=', '), 'v_sum' : Iter(n, 'v%s', sep=' + '), 'arity' : Arity(n), 'Arity' : Title(Arity(n)), } tests = ( """// Sample functions/functors for testing %(arity)s predicate assertions. // A %(arity)s predicate function. template <%(types)s> bool PredFunction%(n)s(%(tvs)s) { return %(v_sum)s > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction%(n)sInt(%(int_vs)s) { return %(v_sum)s > 0; } bool PredFunction%(n)sBool(%(Bool_vs)s) { return %(v_sum)s > 0; } """ % DEFS) tests += """ // A %(arity)s predicate functor. struct PredFunctor%(n)s { template <%(types)s> bool operator()(""" % DEFS tests += Iter(n, 'const T%s& v%s', sep=""", """) tests += """) { return %(v_sum)s > 0; } }; """ % DEFS tests += """ // A %(arity)s predicate-formatter function. template <%(types)s> testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS tests += Iter(n, 'const char* e%s', sep=""", """) tests += Iter(n, """, const T%s& v%s""") tests += """) { if (PredFunction%(n)s(%(vs)s)) return testing::AssertionSuccess(); testing::Message msg; msg << """ % DEFS tests += Iter(n, 'e%s', sep=' << " + " << ') tests += """ << " is expected to be positive, but evaluates to " << %(v_sum)s << "."; return testing::AssertionFailure(msg); } """ % DEFS tests += """ // A %(arity)s predicate-formatter functor. struct PredFormatFunctor%(n)s { template <%(types)s> testing::AssertionResult operator()(""" % DEFS tests += Iter(n, 'const char* e%s', sep=""", """) tests += Iter(n, """, const T%s& v%s""") tests += """) const { return PredFormatFunction%(n)s(%(es)s, %(vs)s); } }; """ % DEFS tests += """ // Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s. class Predicate%(n)sTest : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false;""" % DEFS tests += """ """ + Iter(n, 'n%s_ = ') + """0; } """ tests += """ virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once.""" tests += ''.join([""" EXPECT_EQ(1, n%s_) << "The predicate assertion didn't evaluate argument %s " "exactly once.";""" % (i, i + 1) for i in OneTo(n)]) tests += """ // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; """ % DEFS tests += Iter(n, """ static int n%s_;""") tests += """ }; bool Predicate%(n)sTest::expected_to_finish_; bool Predicate%(n)sTest::finished_; """ % DEFS tests += Iter(n, """int Predicate%%(n)sTest::n%s_; """) % DEFS tests += """ typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest; typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest; typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest; typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest; """ % DEFS def GenTest(use_format, use_assert, expect_failure, use_functor, use_user_type): """Returns the test for a predicate assertion macro. Args: use_format: true iff the assertion is a *_PRED_FORMAT*. use_assert: true iff the assertion is a ASSERT_*. expect_failure: true iff the assertion is expected to fail. use_functor: true iff the first argument of the assertion is a functor (as opposed to a function) use_user_type: true iff the predicate functor/function takes argument(s) of a user-defined type. Example: GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior of a successful EXPECT_PRED_FORMATn() that takes a functor whose arguments have built-in types.""" if use_assert: assrt = 'ASSERT' # 'assert' is reserved, so we cannot use # that identifier here. else: assrt = 'EXPECT' assertion = assrt + '_PRED' if use_format: pred_format = 'PredFormat' assertion += '_FORMAT' else: pred_format = 'Pred' assertion += '%(n)s' % DEFS if use_functor: pred_format_type = 'functor' pred_format += 'Functor%(n)s()' else: pred_format_type = 'function' pred_format += 'Function%(n)s' if not use_format: if use_user_type: pred_format += 'Bool' else: pred_format += 'Int' test_name = pred_format_type.title() if use_user_type: arg_type = 'user-defined type (Bool)' test_name += 'OnUserType' if expect_failure: arg = 'Bool(n%s_++)' else: arg = 'Bool(++n%s_)' else: arg_type = 'built-in type (int)' test_name += 'OnBuiltInType' if expect_failure: arg = 'n%s_++' else: arg = '++n%s_' if expect_failure: successful_or_failed = 'failed' expected_or_not = 'expected.' test_name += 'Failure' else: successful_or_failed = 'successful' expected_or_not = 'UNEXPECTED!' test_name += 'Success' # A map that defines the values used in the test template. defs = DEFS.copy() defs.update({ 'assert' : assrt, 'assertion' : assertion, 'test_name' : test_name, 'pf_type' : pred_format_type, 'pf' : pred_format, 'arg_type' : arg_type, 'arg' : arg, 'successful' : successful_or_failed, 'expected' : expected_or_not, }) test = """ // Tests a %(successful)s %(assertion)s where the // predicate-formatter is a %(pf_type)s on a %(arg_type)s. TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs indent = (len(assertion) + 3)*' ' extra_indent = '' if expect_failure: extra_indent = ' ' if use_assert: test += """ expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT""" else: test += """ EXPECT_NONFATAL_FAILURE({ // NOLINT""" test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs test = test % defs test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs) test += ');\n' + extra_indent + ' finished_ = true;\n' if expect_failure: test += ' }, "");\n' test += '}\n' return test # Generates tests for all 2**6 = 64 combinations. tests += ''.join([GenTest(use_format, use_assert, expect_failure, use_functor, use_user_type) for use_format in [0, 1] for use_assert in [0, 1] for expect_failure in [0, 1] for use_functor in [0, 1] for use_user_type in [0, 1] ]) return tests def UnitTestPostamble(): """Returns the postamble for the tests.""" return '' def GenerateUnitTest(n): """Returns the tests for up-to n-ary predicate assertions.""" GenerateFile(UNIT_TEST, UnitTestPreamble() + ''.join([TestsForArity(i) for i in OneTo(n)]) + UnitTestPostamble()) def _Main(): """The entry point of the script. Generates the header file and its unit test.""" if len(sys.argv) != 2: print __doc__ print 'Author: ' + __author__ sys.exit(1) n = int(sys.argv[1]) GenerateHeader(n) GenerateUnitTest(n) if __name__ == '__main__': _Main() ceph-0.80.11/src/gtest/scripts/gtest-config.in0000775000175100017510000002354212623076744023233 0ustar jenkins-buildjenkins-build#!/bin/sh # These variables are automatically filled in by the configure script. name="@PACKAGE_TARNAME@" version="@PACKAGE_VERSION@" show_usage() { echo "Usage: gtest-config [OPTIONS...]" } show_help() { show_usage cat <<\EOF The `gtest-config' script provides access to the necessary compile and linking flags to connect with Google C++ Testing Framework, both in a build prior to installation, and on the system proper after installation. The installation overrides may be issued in combination with any other queries, but will only affect installation queries if called on a built but not installed gtest. The installation queries may not be issued with any other types of queries, and only one installation query may be made at a time. The version queries and compiler flag queries may be combined as desired but not mixed. Different version queries are always combined with logical "and" semantics, and only the last of any particular query is used while all previous ones ignored. All versions must be specified as a sequence of numbers separated by periods. Compiler flag queries output the union of the sets of flags when combined. Examples: gtest-config --min-version=1.0 || echo "Insufficient Google Test version." g++ $(gtest-config --cppflags --cxxflags) -o foo.o -c foo.cpp g++ $(gtest-config --ldflags --libs) -o foo foo.o # When using a built but not installed Google Test: g++ $(../../my_gtest_build/scripts/gtest-config ...) ... # When using an installed Google Test, but with installation overrides: export GTEST_PREFIX="/opt" g++ $(gtest-config --libdir="/opt/lib64" ...) ... Help: --usage brief usage information --help display this help message Installation Overrides: --prefix= overrides the installation prefix --exec-prefix= overrides the executable installation prefix --libdir= overrides the library installation prefix --includedir= overrides the header file installation prefix Installation Queries: --prefix installation prefix --exec-prefix executable installation prefix --libdir library installation directory --includedir header file installation directory --version the version of the Google Test installation Version Queries: --min-version=VERSION return 0 if the version is at least VERSION --exact-version=VERSION return 0 if the version is exactly VERSION --max-version=VERSION return 0 if the version is at most VERSION Compilation Flag Queries: --cppflags compile flags specific to the C-like preprocessors --cxxflags compile flags appropriate for C++ programs --ldflags linker flags --libs libraries for linking EOF } # This function bounds our version with a min and a max. It uses some clever # POSIX-compliant variable expansion to portably do all the work in the shell # and avoid any dependency on a particular "sed" or "awk" implementation. # Notable is that it will only ever compare the first 3 components of versions. # Further components will be cleanly stripped off. All versions must be # unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and # the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should # investigate expanding this via autom4te from AS_VERSION_COMPARE rather than # continuing to maintain our own shell version. check_versions() { major_version=${version%%.*} minor_version="0" point_version="0" if test "${version#*.}" != "${version}"; then minor_version=${version#*.} minor_version=${minor_version%%.*} fi if test "${version#*.*.}" != "${version}"; then point_version=${version#*.*.} point_version=${point_version%%.*} fi min_version="$1" min_major_version=${min_version%%.*} min_minor_version="0" min_point_version="0" if test "${min_version#*.}" != "${min_version}"; then min_minor_version=${min_version#*.} min_minor_version=${min_minor_version%%.*} fi if test "${min_version#*.*.}" != "${min_version}"; then min_point_version=${min_version#*.*.} min_point_version=${min_point_version%%.*} fi max_version="$2" max_major_version=${max_version%%.*} max_minor_version="0" max_point_version="0" if test "${max_version#*.}" != "${max_version}"; then max_minor_version=${max_version#*.} max_minor_version=${max_minor_version%%.*} fi if test "${max_version#*.*.}" != "${max_version}"; then max_point_version=${max_version#*.*.} max_point_version=${max_point_version%%.*} fi test $(($major_version)) -lt $(($min_major_version)) && exit 1 if test $(($major_version)) -eq $(($min_major_version)); then test $(($minor_version)) -lt $(($min_minor_version)) && exit 1 if test $(($minor_version)) -eq $(($min_minor_version)); then test $(($point_version)) -lt $(($min_point_version)) && exit 1 fi fi test $(($major_version)) -gt $(($max_major_version)) && exit 1 if test $(($major_version)) -eq $(($max_major_version)); then test $(($minor_version)) -gt $(($max_minor_version)) && exit 1 if test $(($minor_version)) -eq $(($max_minor_version)); then test $(($point_version)) -gt $(($max_point_version)) && exit 1 fi fi exit 0 } # Show the usage line when no arguments are specified. if test $# -eq 0; then show_usage exit 1 fi while test $# -gt 0; do case $1 in --usage) show_usage; exit 0;; --help) show_help; exit 0;; # Installation overrides --prefix=*) GTEST_PREFIX=${1#--prefix=};; --exec-prefix=*) GTEST_EXEC_PREFIX=${1#--exec-prefix=};; --libdir=*) GTEST_LIBDIR=${1#--libdir=};; --includedir=*) GTEST_INCLUDEDIR=${1#--includedir=};; # Installation queries --prefix|--exec-prefix|--libdir|--includedir|--version) if test -n "${do_query}"; then show_usage exit 1 fi do_query=${1#--} ;; # Version checking --min-version=*) do_check_versions=yes min_version=${1#--min-version=} ;; --max-version=*) do_check_versions=yes max_version=${1#--max-version=} ;; --exact-version=*) do_check_versions=yes exact_version=${1#--exact-version=} ;; # Compiler flag output --cppflags) echo_cppflags=yes;; --cxxflags) echo_cxxflags=yes;; --ldflags) echo_ldflags=yes;; --libs) echo_libs=yes;; # Everything else is an error *) show_usage; exit 1;; esac shift done # These have defaults filled in by the configure script but can also be # overridden by environment variables or command line parameters. prefix="${GTEST_PREFIX:-@prefix@}" exec_prefix="${GTEST_EXEC_PREFIX:-@exec_prefix@}" libdir="${GTEST_LIBDIR:-@libdir@}" includedir="${GTEST_INCLUDEDIR:-@includedir@}" # We try and detect if our binary is not located at its installed location. If # it's not, we provide variables pointing to the source and build tree rather # than to the install tree. This allows building against a just-built gtest # rather than an installed gtest. bindir="@bindir@" this_relative_bindir=`dirname $0` this_bindir=`cd ${this_relative_bindir}; pwd -P` if test "${this_bindir}" = "${this_bindir%${bindir}}"; then # The path to the script doesn't end in the bindir sequence from Autoconf, # assume that we are in a build tree. build_dir=`dirname ${this_bindir}` src_dir=`cd ${this_bindir}/@top_srcdir@; pwd -P` # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we # should work to remove it, and/or remove libtool altogether, replacing it # with direct references to the library and a link path. gtest_libs="${build_dir}/lib/libgtest.a @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" gtest_ldflags="" # We provide hooks to include from either the source or build dir, where the # build dir is always preferred. This will potentially allow us to write # build rules for generated headers and have them automatically be preferred # over provided versions. gtest_cppflags="-I${build_dir}/include -I${src_dir}/include" gtest_cxxflags="@PTHREAD_CFLAGS@" else # We're using an installed gtest, although it may be staged under some # prefix. Assume (as our own libraries do) that we can resolve the prefix, # and are present in the dynamic link paths. gtest_ldflags="-L${libdir}" gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" gtest_cppflags="-I${includedir}" gtest_cxxflags="@PTHREAD_CFLAGS@" fi # Do an installation query if requested. if test -n "$do_query"; then case $do_query in prefix) echo $prefix; exit 0;; exec-prefix) echo $exec_prefix; exit 0;; libdir) echo $libdir; exit 0;; includedir) echo $includedir; exit 0;; version) echo $version; exit 0;; *) show_usage; exit 1;; esac fi # Do a version check if requested. if test "$do_check_versions" = "yes"; then # Make sure we didn't receive a bad combination of parameters. test "$echo_cppflags" = "yes" && show_usage && exit 1 test "$echo_cxxflags" = "yes" && show_usage && exit 1 test "$echo_ldflags" = "yes" && show_usage && exit 1 test "$echo_libs" = "yes" && show_usage && exit 1 if test "$exact_version" != ""; then check_versions $exact_version $exact_version # unreachable else check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999} # unreachable fi fi # Do the output in the correct order so that these can be used in-line of # a compiler invocation. output="" test "$echo_cppflags" = "yes" && output="$output $gtest_cppflags" test "$echo_cxxflags" = "yes" && output="$output $gtest_cxxflags" test "$echo_ldflags" = "yes" && output="$output $gtest_ldflags" test "$echo_libs" = "yes" && output="$output $gtest_libs" echo $output exit 0 ceph-0.80.11/src/gtest/scripts/fuse_gtest_files.py0000775000175100017510000002115512623076744024214 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2009, Google Inc. # 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. """fuse_gtest_files.py v0.2.0 Fuses Google Test source code into a .h file and a .cc file. SYNOPSIS fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR Scans GTEST_ROOT_DIR for Google Test source code, and generates two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc. Then you can build your tests by adding OUTPUT_DIR to the include search path and linking with OUTPUT_DIR/gtest/gtest-all.cc. These two files contain everything you need to use Google Test. Hence you can "install" Google Test by copying them to wherever you want. GTEST_ROOT_DIR can be omitted and defaults to the parent directory of the directory holding this script. EXAMPLES ./fuse_gtest_files.py fused_gtest ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest This tool is experimental. In particular, it assumes that there is no conditional inclusion of Google Test headers. Please report any problems to googletestframework@googlegroups.com. You can read http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for more information. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sets import sys # We assume that this file is in the scripts/ directory in the Google # Test root directory. DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') # Regex for matching '#include '. INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*<(gtest/.+)>') # Regex for matching '#include "src/..."'. INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"') # Where to find the source seed files. GTEST_H_SEED = 'include/gtest/gtest.h' GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h' GTEST_ALL_CC_SEED = 'src/gtest-all.cc' # Where to put the generated files. GTEST_H_OUTPUT = 'gtest/gtest.h' GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc' def VerifyFileExists(directory, relative_path): """Verifies that the given file exists; aborts on failure. relative_path is the file path relative to the given directory. """ if not os.path.isfile(os.path.join(directory, relative_path)): print 'ERROR: Cannot find %s in directory %s.' % (relative_path, directory) print ('Please either specify a valid project root directory ' 'or omit it on the command line.') sys.exit(1) def ValidateGTestRootDir(gtest_root): """Makes sure gtest_root points to a valid gtest root directory. The function aborts the program on failure. """ VerifyFileExists(gtest_root, GTEST_H_SEED) VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED) def VerifyOutputFile(output_dir, relative_path): """Verifies that the given output file path is valid. relative_path is relative to the output_dir directory. """ # Makes sure the output file either doesn't exist or can be overwritten. output_file = os.path.join(output_dir, relative_path) if os.path.exists(output_file): # TODO(wan@google.com): The following user-interaction doesn't # work with automated processes. We should provide a way for the # Makefile to force overwriting the files. print ('%s already exists in directory %s - overwrite it? (y/N) ' % (relative_path, output_dir)) answer = sys.stdin.readline().strip() if answer not in ['y', 'Y']: print 'ABORTED.' sys.exit(1) # Makes sure the directory holding the output file exists; creates # it and all its ancestors if necessary. parent_directory = os.path.dirname(output_file) if not os.path.isdir(parent_directory): os.makedirs(parent_directory) def ValidateOutputDir(output_dir): """Makes sure output_dir points to a valid output directory. The function aborts the program on failure. """ VerifyOutputFile(output_dir, GTEST_H_OUTPUT) VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT) def FuseGTestH(gtest_root, output_dir): """Scans folder gtest_root to generate gtest/gtest.h in output_dir.""" output_file = file(os.path.join(output_dir, GTEST_H_OUTPUT), 'w') processed_files = sets.Set() # Holds all gtest headers we've processed. def ProcessFile(gtest_header_path): """Processes the given gtest header file.""" # We don't process the same header twice. if gtest_header_path in processed_files: return processed_files.add(gtest_header_path) # Reads each line in the given gtest header. for line in file(os.path.join(gtest_root, gtest_header_path), 'r'): m = INCLUDE_GTEST_FILE_REGEX.match(line) if m: # It's '#include ' - let's process it recursively. ProcessFile('include/' + m.group(1)) else: # Otherwise we copy the line unchanged to the output file. output_file.write(line) ProcessFile(GTEST_H_SEED) output_file.close() def FuseGTestAllCcToFile(gtest_root, output_file): """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file.""" processed_files = sets.Set() def ProcessFile(gtest_source_file): """Processes the given gtest source file.""" # We don't process the same #included file twice. if gtest_source_file in processed_files: return processed_files.add(gtest_source_file) # Reads each line in the given gtest source file. for line in file(os.path.join(gtest_root, gtest_source_file), 'r'): m = INCLUDE_GTEST_FILE_REGEX.match(line) if m: if 'include/' + m.group(1) == GTEST_SPI_H_SEED: # It's '#include '. This file is not # #included by , so we need to process it. ProcessFile(GTEST_SPI_H_SEED) else: # It's '#include ' where foo is not gtest-spi. # We treat it as '#include ', as all other # gtest headers are being fused into gtest.h and cannot be # #included directly. # There is no need to #include more than once. if not GTEST_H_SEED in processed_files: processed_files.add(GTEST_H_SEED) output_file.write('#include <%s>\n' % (GTEST_H_OUTPUT,)) else: m = INCLUDE_SRC_FILE_REGEX.match(line) if m: # It's '#include "src/foo"' - let's process it recursively. ProcessFile(m.group(1)) else: output_file.write(line) ProcessFile(GTEST_ALL_CC_SEED) def FuseGTestAllCc(gtest_root, output_dir): """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir.""" output_file = file(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w') FuseGTestAllCcToFile(gtest_root, output_file) output_file.close() def FuseGTest(gtest_root, output_dir): """Fuses gtest.h and gtest-all.cc.""" ValidateGTestRootDir(gtest_root) ValidateOutputDir(output_dir) FuseGTestH(gtest_root, output_dir) FuseGTestAllCc(gtest_root, output_dir) def main(): argc = len(sys.argv) if argc == 2: # fuse_gtest_files.py OUTPUT_DIR FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1]) elif argc == 3: # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR FuseGTest(sys.argv[1], sys.argv[2]) else: print __doc__ sys.exit(1) if __name__ == '__main__': main() ceph-0.80.11/src/gtest/scripts/test/0000775000175100017510000000000012623077036021253 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/scripts/test/Makefile0000664000175100017510000000323212623076744022720 0ustar jenkins-buildjenkins-build# A Makefile for fusing Google Test and building a sample test against it. # # SYNOPSIS: # # make [all] - makes everything. # make TARGET - makes the given target. # make check - makes everything and runs the built sample test. # make clean - removes all files generated by make. # Points to the root of fused Google Test, relative to where this file is. FUSED_GTEST_DIR = output # Paths to the fused gtest files. FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc # Where to find the sample test. SAMPLE_DIR = ../../samples # Where to find gtest_main.cc. GTEST_MAIN_CC = ../../src/gtest_main.cc # Flags passed to the preprocessor. CPPFLAGS += -I$(FUSED_GTEST_DIR) # Flags passed to the C++ compiler. CXXFLAGS += -g all : sample1_unittest check : all ./sample1_unittest clean : rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o $(FUSED_GTEST_H) : ../fuse_gtest_files.py $(FUSED_GTEST_DIR) $(FUSED_GTEST_ALL_CC) : ../fuse_gtest_files.py $(FUSED_GTEST_DIR) gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC) sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \ $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ ceph-0.80.11/src/gtest/scripts/pump.py0000775000175100017510000005453712623076744021655 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """pump v0.1 - Pretty Useful for Meta Programming. A tool for preprocessor meta programming. Useful for generating repetitive boilerplate code. Especially useful for writing C++ classes, functions, macros, and templates that need to work with various number of arguments. USAGE: pump.py SOURCE_FILE EXAMPLES: pump.py foo.cc.pump Converts foo.cc.pump to foo.cc. GRAMMAR: CODE ::= ATOMIC_CODE* ATOMIC_CODE ::= $var ID = EXPRESSION | $var ID = [[ CODE ]] | $range ID EXPRESSION..EXPRESSION | $for ID SEPARATOR [[ CODE ]] | $($) | $ID | $(EXPRESSION) | $if EXPRESSION [[ CODE ]] ELSE_BRANCH | [[ CODE ]] | RAW_CODE SEPARATOR ::= RAW_CODE | EMPTY ELSE_BRANCH ::= $else [[ CODE ]] | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH | EMPTY EXPRESSION has Python syntax. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sys TOKEN_TABLE = [ (re.compile(r'\$var\s+'), '$var'), (re.compile(r'\$elif\s+'), '$elif'), (re.compile(r'\$else\s+'), '$else'), (re.compile(r'\$for\s+'), '$for'), (re.compile(r'\$if\s+'), '$if'), (re.compile(r'\$range\s+'), '$range'), (re.compile(r'\$[_A-Za-z]\w*'), '$id'), (re.compile(r'\$\(\$\)'), '$($)'), (re.compile(r'\$\$.*'), '$$'), (re.compile(r'\$'), '$'), (re.compile(r'\[\[\n?'), '[['), (re.compile(r'\]\]\n?'), ']]'), ] class Cursor: """Represents a position (line and column) in a text file.""" def __init__(self, line=-1, column=-1): self.line = line self.column = column def __eq__(self, rhs): return self.line == rhs.line and self.column == rhs.column def __ne__(self, rhs): return not self == rhs def __lt__(self, rhs): return self.line < rhs.line or ( self.line == rhs.line and self.column < rhs.column) def __le__(self, rhs): return self < rhs or self == rhs def __gt__(self, rhs): return rhs < self def __ge__(self, rhs): return rhs <= self def __str__(self): if self == Eof(): return 'EOF' else: return '%s(%s)' % (self.line + 1, self.column) def __add__(self, offset): return Cursor(self.line, self.column + offset) def __sub__(self, offset): return Cursor(self.line, self.column - offset) def Clone(self): """Returns a copy of self.""" return Cursor(self.line, self.column) # Special cursor to indicate the end-of-file. def Eof(): """Returns the special cursor to denote the end-of-file.""" return Cursor(-1, -1) class Token: """Represents a token in a Pump source file.""" def __init__(self, start=None, end=None, value=None, token_type=None): if start is None: self.start = Eof() else: self.start = start if end is None: self.end = Eof() else: self.end = end self.value = value self.token_type = token_type def __str__(self): return 'Token @%s: \'%s\' type=%s' % ( self.start, self.value, self.token_type) def Clone(self): """Returns a copy of self.""" return Token(self.start.Clone(), self.end.Clone(), self.value, self.token_type) def StartsWith(lines, pos, string): """Returns True iff the given position in lines starts with 'string'.""" return lines[pos.line][pos.column:].startswith(string) def FindFirstInLine(line, token_table): best_match_start = -1 for (regex, token_type) in token_table: m = regex.search(line) if m: # We found regex in lines if best_match_start < 0 or m.start() < best_match_start: best_match_start = m.start() best_match_length = m.end() - m.start() best_match_token_type = token_type if best_match_start < 0: return None return (best_match_start, best_match_length, best_match_token_type) def FindFirst(lines, token_table, cursor): """Finds the first occurrence of any string in strings in lines.""" start = cursor.Clone() cur_line_number = cursor.line for line in lines[start.line:]: if cur_line_number == start.line: line = line[start.column:] m = FindFirstInLine(line, token_table) if m: # We found a regex in line. (start_column, length, token_type) = m if cur_line_number == start.line: start_column += start.column found_start = Cursor(cur_line_number, start_column) found_end = found_start + length return MakeToken(lines, found_start, found_end, token_type) cur_line_number += 1 # We failed to find str in lines return None def SubString(lines, start, end): """Returns a substring in lines.""" if end == Eof(): end = Cursor(len(lines) - 1, len(lines[-1])) if start >= end: return '' if start.line == end.line: return lines[start.line][start.column:end.column] result_lines = ([lines[start.line][start.column:]] + lines[start.line + 1:end.line] + [lines[end.line][:end.column]]) return ''.join(result_lines) def MakeToken(lines, start, end, token_type): """Creates a new instance of Token.""" return Token(start, end, SubString(lines, start, end), token_type) def ParseToken(lines, pos, regex, token_type): line = lines[pos.line][pos.column:] m = regex.search(line) if m and not m.start(): return MakeToken(lines, pos, pos + m.end(), token_type) else: print 'ERROR: %s expected at %s.' % (token_type, pos) sys.exit(1) ID_REGEX = re.compile(r'[_A-Za-z]\w*') EQ_REGEX = re.compile(r'=') REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)') OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*') WHITE_SPACE_REGEX = re.compile(r'\s') DOT_DOT_REGEX = re.compile(r'\.\.') def Skip(lines, pos, regex): line = lines[pos.line][pos.column:] m = re.search(regex, line) if m and not m.start(): return pos + m.end() else: return pos def SkipUntil(lines, pos, regex, token_type): line = lines[pos.line][pos.column:] m = re.search(regex, line) if m: return pos + m.start() else: print ('ERROR: %s expected on line %s after column %s.' % (token_type, pos.line + 1, pos.column)) sys.exit(1) def ParseExpTokenInParens(lines, pos): def ParseInParens(pos): pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX) pos = Skip(lines, pos, r'\(') pos = Parse(pos) pos = Skip(lines, pos, r'\)') return pos def Parse(pos): pos = SkipUntil(lines, pos, r'\(|\)', ')') if SubString(lines, pos, pos + 1) == '(': pos = Parse(pos + 1) pos = Skip(lines, pos, r'\)') return Parse(pos) else: return pos start = pos.Clone() pos = ParseInParens(pos) return MakeToken(lines, start, pos, 'exp') def RStripNewLineFromToken(token): if token.value.endswith('\n'): return Token(token.start, token.end, token.value[:-1], token.token_type) else: return token def TokenizeLines(lines, pos): while True: found = FindFirst(lines, TOKEN_TABLE, pos) if not found: yield MakeToken(lines, pos, Eof(), 'code') return if found.start == pos: prev_token = None prev_token_rstripped = None else: prev_token = MakeToken(lines, pos, found.start, 'code') prev_token_rstripped = RStripNewLineFromToken(prev_token) if found.token_type == '$$': # A meta comment. if prev_token_rstripped: yield prev_token_rstripped pos = Cursor(found.end.line + 1, 0) elif found.token_type == '$var': if prev_token_rstripped: yield prev_token_rstripped yield found id_token = ParseToken(lines, found.end, ID_REGEX, 'id') yield id_token pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) eq_token = ParseToken(lines, pos, EQ_REGEX, '=') yield eq_token pos = Skip(lines, eq_token.end, r'\s*') if SubString(lines, pos, pos + 2) != '[[': exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp') yield exp_token pos = Cursor(exp_token.end.line + 1, 0) elif found.token_type == '$for': if prev_token_rstripped: yield prev_token_rstripped yield found id_token = ParseToken(lines, found.end, ID_REGEX, 'id') yield id_token pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX) elif found.token_type == '$range': if prev_token_rstripped: yield prev_token_rstripped yield found id_token = ParseToken(lines, found.end, ID_REGEX, 'id') yield id_token pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..') yield MakeToken(lines, pos, dots_pos, 'exp') yield MakeToken(lines, dots_pos, dots_pos + 2, '..') pos = dots_pos + 2 new_pos = Cursor(pos.line + 1, 0) yield MakeToken(lines, pos, new_pos, 'exp') pos = new_pos elif found.token_type == '$': if prev_token: yield prev_token yield found exp_token = ParseExpTokenInParens(lines, found.end) yield exp_token pos = exp_token.end elif (found.token_type == ']]' or found.token_type == '$if' or found.token_type == '$elif' or found.token_type == '$else'): if prev_token_rstripped: yield prev_token_rstripped yield found pos = found.end else: if prev_token: yield prev_token yield found pos = found.end def Tokenize(s): lines = s.splitlines(True) return TokenizeLines(lines, Cursor(0, 0)) class CodeNode: def __init__(self, atomic_code_list=None): self.atomic_code = atomic_code_list class VarNode: def __init__(self, identifier=None, atomic_code=None): self.identifier = identifier self.atomic_code = atomic_code class RangeNode: def __init__(self, identifier=None, exp1=None, exp2=None): self.identifier = identifier self.exp1 = exp1 self.exp2 = exp2 class ForNode: def __init__(self, identifier=None, sep=None, code=None): self.identifier = identifier self.sep = sep self.code = code class ElseNode: def __init__(self, else_branch=None): self.else_branch = else_branch class IfNode: def __init__(self, exp=None, then_branch=None, else_branch=None): self.exp = exp self.then_branch = then_branch self.else_branch = else_branch class RawCodeNode: def __init__(self, token=None): self.raw_code = token class LiteralDollarNode: def __init__(self, token): self.token = token class ExpNode: def __init__(self, token, python_exp): self.token = token self.python_exp = python_exp def PopFront(a_list): head = a_list[0] a_list[:1] = [] return head def PushFront(a_list, elem): a_list[:0] = [elem] def PopToken(a_list, token_type=None): token = PopFront(a_list) if token_type is not None and token.token_type != token_type: print 'ERROR: %s expected at %s' % (token_type, token.start) print 'ERROR: %s found instead' % (token,) sys.exit(1) return token def PeekToken(a_list): if not a_list: return None return a_list[0] def ParseExpNode(token): python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value) return ExpNode(token, python_exp) def ParseElseNode(tokens): def Pop(token_type=None): return PopToken(tokens, token_type) next = PeekToken(tokens) if not next: return None if next.token_type == '$else': Pop('$else') Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') return code_node elif next.token_type == '$elif': Pop('$elif') exp = Pop('code') Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') inner_else_node = ParseElseNode(tokens) return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)]) elif not next.value.strip(): Pop('code') return ParseElseNode(tokens) else: return None def ParseAtomicCodeNode(tokens): def Pop(token_type=None): return PopToken(tokens, token_type) head = PopFront(tokens) t = head.token_type if t == 'code': return RawCodeNode(head) elif t == '$var': id_token = Pop('id') Pop('=') next = PeekToken(tokens) if next.token_type == 'exp': exp_token = Pop() return VarNode(id_token, ParseExpNode(exp_token)) Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') return VarNode(id_token, code_node) elif t == '$for': id_token = Pop('id') next_token = PeekToken(tokens) if next_token.token_type == 'code': sep_token = next_token Pop('code') else: sep_token = None Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') return ForNode(id_token, sep_token, code_node) elif t == '$if': exp_token = Pop('code') Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') else_node = ParseElseNode(tokens) return IfNode(ParseExpNode(exp_token), code_node, else_node) elif t == '$range': id_token = Pop('id') exp1_token = Pop('exp') Pop('..') exp2_token = Pop('exp') return RangeNode(id_token, ParseExpNode(exp1_token), ParseExpNode(exp2_token)) elif t == '$id': return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id')) elif t == '$($)': return LiteralDollarNode(head) elif t == '$': exp_token = Pop('exp') return ParseExpNode(exp_token) elif t == '[[': code_node = ParseCodeNode(tokens) Pop(']]') return code_node else: PushFront(tokens, head) return None def ParseCodeNode(tokens): atomic_code_list = [] while True: if not tokens: break atomic_code_node = ParseAtomicCodeNode(tokens) if atomic_code_node: atomic_code_list.append(atomic_code_node) else: break return CodeNode(atomic_code_list) def Convert(file_path): s = file(file_path, 'r').read() tokens = [] for token in Tokenize(s): tokens.append(token) code_node = ParseCodeNode(tokens) return code_node class Env: def __init__(self): self.variables = [] self.ranges = [] def Clone(self): clone = Env() clone.variables = self.variables[:] clone.ranges = self.ranges[:] return clone def PushVariable(self, var, value): # If value looks like an int, store it as an int. try: int_value = int(value) if ('%s' % int_value) == value: value = int_value except Exception: pass self.variables[:0] = [(var, value)] def PopVariable(self): self.variables[:1] = [] def PushRange(self, var, lower, upper): self.ranges[:0] = [(var, lower, upper)] def PopRange(self): self.ranges[:1] = [] def GetValue(self, identifier): for (var, value) in self.variables: if identifier == var: return value print 'ERROR: meta variable %s is undefined.' % (identifier,) sys.exit(1) def EvalExp(self, exp): try: result = eval(exp.python_exp) except Exception, e: print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e) print ('ERROR: failed to evaluate meta expression %s at %s' % (exp.python_exp, exp.token.start)) sys.exit(1) return result def GetRange(self, identifier): for (var, lower, upper) in self.ranges: if identifier == var: return (lower, upper) print 'ERROR: range %s is undefined.' % (identifier,) sys.exit(1) class Output: def __init__(self): self.string = '' def GetLastLine(self): index = self.string.rfind('\n') if index < 0: return '' return self.string[index + 1:] def Append(self, s): self.string += s def RunAtomicCode(env, node, output): if isinstance(node, VarNode): identifier = node.identifier.value.strip() result = Output() RunAtomicCode(env.Clone(), node.atomic_code, result) value = result.string env.PushVariable(identifier, value) elif isinstance(node, RangeNode): identifier = node.identifier.value.strip() lower = int(env.EvalExp(node.exp1)) upper = int(env.EvalExp(node.exp2)) env.PushRange(identifier, lower, upper) elif isinstance(node, ForNode): identifier = node.identifier.value.strip() if node.sep is None: sep = '' else: sep = node.sep.value (lower, upper) = env.GetRange(identifier) for i in range(lower, upper + 1): new_env = env.Clone() new_env.PushVariable(identifier, i) RunCode(new_env, node.code, output) if i != upper: output.Append(sep) elif isinstance(node, RawCodeNode): output.Append(node.raw_code.value) elif isinstance(node, IfNode): cond = env.EvalExp(node.exp) if cond: RunCode(env.Clone(), node.then_branch, output) elif node.else_branch is not None: RunCode(env.Clone(), node.else_branch, output) elif isinstance(node, ExpNode): value = env.EvalExp(node) output.Append('%s' % (value,)) elif isinstance(node, LiteralDollarNode): output.Append('$') elif isinstance(node, CodeNode): RunCode(env.Clone(), node, output) else: print 'BAD' print node sys.exit(1) def RunCode(env, code_node, output): for atomic_code in code_node.atomic_code: RunAtomicCode(env, atomic_code, output) def IsComment(cur_line): return '//' in cur_line def IsInPreprocessorDirevative(prev_lines, cur_line): if cur_line.lstrip().startswith('#'): return True return prev_lines != [] and prev_lines[-1].endswith('\\') def WrapComment(line, output): loc = line.find('//') before_comment = line[:loc].rstrip() if before_comment == '': indent = loc else: output.append(before_comment) indent = len(before_comment) - len(before_comment.lstrip()) prefix = indent*' ' + '// ' max_len = 80 - len(prefix) comment = line[loc + 2:].strip() segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != ''] cur_line = '' for seg in segs: if len((cur_line + seg).rstrip()) < max_len: cur_line += seg else: if cur_line.strip() != '': output.append(prefix + cur_line.rstrip()) cur_line = seg.lstrip() if cur_line.strip() != '': output.append(prefix + cur_line.strip()) def WrapCode(line, line_concat, output): indent = len(line) - len(line.lstrip()) prefix = indent*' ' # Prefix of the current line max_len = 80 - indent - len(line_concat) # Maximum length of the current line new_prefix = prefix + 4*' ' # Prefix of a continuation line new_max_len = max_len - 4 # Maximum length of a continuation line # Prefers to wrap a line after a ',' or ';'. segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != ''] cur_line = '' # The current line without leading spaces. for seg in segs: # If the line is still too long, wrap at a space. while cur_line == '' and len(seg.strip()) > max_len: seg = seg.lstrip() split_at = seg.rfind(' ', 0, max_len) output.append(prefix + seg[:split_at].strip() + line_concat) seg = seg[split_at + 1:] prefix = new_prefix max_len = new_max_len if len((cur_line + seg).rstrip()) < max_len: cur_line = (cur_line + seg).lstrip() else: output.append(prefix + cur_line.rstrip() + line_concat) prefix = new_prefix max_len = new_max_len cur_line = seg.lstrip() if cur_line.strip() != '': output.append(prefix + cur_line.strip()) def WrapPreprocessorDirevative(line, output): WrapCode(line, ' \\', output) def WrapPlainCode(line, output): WrapCode(line, '', output) def IsHeaderGuardOrInclude(line): return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or re.match(r'^#include\s', line)) def WrapLongLine(line, output): line = line.rstrip() if len(line) <= 80: output.append(line) elif IsComment(line): if IsHeaderGuardOrInclude(line): # The style guide made an exception to allow long header guard lines # and includes. output.append(line) else: WrapComment(line, output) elif IsInPreprocessorDirevative(output, line): if IsHeaderGuardOrInclude(line): # The style guide made an exception to allow long header guard lines # and includes. output.append(line) else: WrapPreprocessorDirevative(line, output) else: WrapPlainCode(line, output) def BeautifyCode(string): lines = string.splitlines() output = [] for line in lines: WrapLongLine(line, output) output2 = [line.rstrip() for line in output] return '\n'.join(output2) + '\n' def main(argv): if len(argv) == 1: print __doc__ sys.exit(1) file_path = argv[-1] ast = Convert(file_path) output = Output() RunCode(Env(), ast, output) output_str = BeautifyCode(output.string) if file_path.endswith('.pump'): output_file_path = file_path[:-5] else: output_file_path = '-' if output_file_path == '-': print output_str, else: output_file = file(output_file_path, 'w') output_file.write('// This file was GENERATED by command:\n') output_file.write('// %s %s\n' % (os.path.basename(__file__), os.path.basename(file_path))) output_file.write('// DO NOT EDIT BY HAND!!!\n\n') output_file.write(output_str) output_file.close() if __name__ == '__main__': main(sys.argv) ceph-0.80.11/src/gtest/m4/0000775000175100017510000000000012623077036017125 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/m4/ltversion.m40000644000175100017510000000126212623076771021420 0ustar jenkins-buildjenkins-build# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) ceph-0.80.11/src/gtest/m4/gtest.m40000664000175100017510000000622112623076744020523 0ustar jenkins-buildjenkins-builddnl GTEST_LIB_CHECK([minimum version [, dnl action if found [,action if not found]]]) dnl dnl Check for the presence of the Google Test library, optionally at a minimum dnl version, and indicate a viable version with the HAVE_GTEST flag. It defines dnl standard variables for substitution including GTEST_CPPFLAGS, dnl GTEST_CXXFLAGS, GTEST_LDFLAGS, and GTEST_LIBS. It also defines dnl GTEST_VERSION as the version of Google Test found. Finally, it provides dnl optional custom action slots in the event GTEST is found or not. AC_DEFUN([GTEST_LIB_CHECK], [ dnl Provide a flag to enable or disable Google Test usage. AC_ARG_ENABLE([gtest], [AS_HELP_STRING([--enable-gtest], [Enable tests using the Google C++ Testing Framework. (Default is enabled.)])], [], [enable_gtest=]) AC_ARG_VAR([GTEST_CONFIG], [The exact path of Google Test's 'gtest-config' script.]) AC_ARG_VAR([GTEST_CPPFLAGS], [C-like preprocessor flags for Google Test.]) AC_ARG_VAR([GTEST_CXXFLAGS], [C++ compile flags for Google Test.]) AC_ARG_VAR([GTEST_LDFLAGS], [Linker path and option flags for Google Test.]) AC_ARG_VAR([GTEST_LIBS], [Library linking flags for Google Test.]) AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_GTEST="no" AS_IF([test "x${enable_gtest}" != "xno"], [AC_MSG_CHECKING([for 'gtest-config']) AS_IF([test "x${enable_gtest}" != "xyes"], [AS_IF([test -x "${enable_gtest}/scripts/gtest-config"], [GTEST_CONFIG="${enable_gtest}/scripts/gtest-config"], [GTEST_CONFIG="${enable_gtest}/bin/gtest-config"]) AS_IF([test -x "${GTEST_CONFIG}"], [], [AC_MSG_RESULT([no]) AC_MSG_ERROR([dnl Unable to locate either a built or installed Google Test. The specific location '${enable_gtest}' was provided for a built or installed Google Test, but no 'gtest-config' script could be found at this location.]) ])], [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])]) AS_IF([test -x "${GTEST_CONFIG}"], [AC_MSG_RESULT([${GTEST_CONFIG}]) m4_ifval([$1], [_gtest_min_version="--min-version=$1" AC_MSG_CHECKING([for Google Test at least version >= $1])], [_gtest_min_version="--min-version=0" AC_MSG_CHECKING([for Google Test])]) AS_IF([${GTEST_CONFIG} ${_gtest_min_version}], [AC_MSG_RESULT([yes]) HAVE_GTEST='yes'], [AC_MSG_RESULT([no])])], [AC_MSG_RESULT([no])]) AS_IF([test "x${HAVE_GTEST}" = "xyes"], [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags` GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags` GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags` GTEST_LIBS=`${GTEST_CONFIG} --libs` GTEST_VERSION=`${GTEST_CONFIG} --version` AC_DEFINE([HAVE_GTEST],[1],[Defined when Google Test is available.])], [AS_IF([test "x${enable_gtest}" = "xyes"], [AC_MSG_ERROR([dnl Google Test was enabled, but no viable version could be found.]) ])])]) AC_SUBST([HAVE_GTEST]) AM_CONDITIONAL([HAVE_GTEST],[test "x$HAVE_GTEST" = "xyes"]) AS_IF([test "x$HAVE_GTEST" = "xyes"], [m4_ifval([$2], [$2])], [m4_ifval([$3], [$3])]) ]) ceph-0.80.11/src/gtest/m4/ltsugar.m40000644000175100017510000001042412623076771021054 0ustar jenkins-buildjenkins-build# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) ceph-0.80.11/src/gtest/m4/acx_pthread.m40000664000175100017510000003176612623076744021673 0ustar jenkins-buildjenkins-build# This was retrieved from # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi # See also (perhaps for new versions?) # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi # # We've rewritten the inconsistency check code (from avahi), to work # more broadly. In particular, it no longer assumes ld accepts -zdefs. # This caused a restructing of the code, but the functionality has only # changed a little. dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2006-05-29 dnl @license GPLWithACException dnl dnl Checks for GCC shared/pthread inconsistency based on work by dnl Marcin Owsiany AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) AC_TRY_LINK(,, , [done=yes]) if test "x$done" = xyes ; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread fixes that]) LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lc_r fixes that]) LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi if test x"$done" = xno; then # OK, we have run out of ideas AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD ceph-0.80.11/src/gtest/m4/lt~obsolete.m40000644000175100017510000001375612623076771021760 0ustar jenkins-buildjenkins-build# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) ceph-0.80.11/src/gtest/m4/libtool.m40000644000175100017510000106011112623076771021036 0ustar jenkins-buildjenkins-build# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS ceph-0.80.11/src/gtest/m4/ltoptions.m40000644000175100017510000003007312623076771021430 0ustar jenkins-buildjenkins-build# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) ceph-0.80.11/src/gtest/aclocal.m40000664000175100017510000014344112623076773020463 0ustar jenkins-buildjenkins-build# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0]) AC_ARG_VAR([PYTHON], [the Python interpreter]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version is >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([Python interpreter is too old])]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': can_use_sysconfig = 0 except ImportError: pass" dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) ceph-0.80.11/src/gtest/include/0000775000175100017510000000000012623077036020230 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/include/gtest/0000775000175100017510000000000012623077036021356 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/include/gtest/gtest-param-test.h.pump0000664000175100017510000004210612623076744025720 0ustar jenkins-buildjenkins-build$$ -*- mode: c++; -*- $var n = 50 $$ Maximum length of Values arguments we want to support. $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // Copyright 2008, Google Inc. // 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. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It must be derived from testing::TestWithParam, where T is // the type of your parameter values. TestWithParam is itself derived // from testing::Test. T can be any copyable type. If it's a raw pointer, // you are responsible for managing the lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions are evaluated in // RUN_ALL_TESTS(), after main() has started. This allows evaluation of // parameter list based on command line parameters. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. #endif // 0 #include #if !GTEST_OS_SYMBIAN #include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include #include #include #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::std::iterator_traits::value_type> ValuesIn( ForwardIterator begin, ForwardIterator end) { typedef typename ::std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to $n parameters. // $range i 1..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) { return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]); } ]] // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } #if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to $maxtuple arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // $range i 2..maxtuple $for i [[ $range j 1..i template <$for j, [[typename Generator$j]]> internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( $for j, [[const Generator$j& g$j]]) { return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>( $for j, [[g$j]]); } ]] #endif // GTEST_HAS_COMBINE #define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ ceph-0.80.11/src/gtest/include/gtest/gtest_pred_impl.h0000664000175100017510000003441412623076744024723 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // This file is AUTOMATICALLY GENERATED on 10/02/2008 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Makes sure this header is not included before gtest.h. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #error Do not include gtest_pred_impl.h directly. Include gtest.h instead. #endif // GTEST_INCLUDE_GTEST_GTEST_H_ // This header implements a family of generic predicate assertion // macros: // // ASSERT_PRED_FORMAT1(pred_format, v1) // ASSERT_PRED_FORMAT2(pred_format, v1, v2) // ... // // where pred_format is a function or functor that takes n (in the // case of ASSERT_PRED_FORMATn) values and their source expression // text, and returns a testing::AssertionResult. See the definition // of ASSERT_EQ in gtest.h for an example. // // If you don't care about formatting, you can use the more // restrictive version: // // ASSERT_PRED1(pred, v1) // ASSERT_PRED2(pred, v1, v2) // ... // // where pred is an n-ary function or functor that returns bool, // and the values v1, v2, ..., must support the << operator for // streaming to std::ostream. // // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. // Please email googletestframework@googlegroups.com if you need // support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. #define GTEST_ASSERT_(expression, on_failure) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar = (expression)) \ ; \ else \ on_failure(gtest_ar.failure_message()) // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. template AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, Pred pred, const T1& v1) { if (pred(v1)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Don't use this in your code. #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ GTEST_ASSERT_(pred_format(#v1, v1),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. #define GTEST_PRED1_(pred, v1, on_failure)\ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ #v1, \ pred, \ v1), on_failure) // Unary predicate assertion macros. #define EXPECT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) #define ASSERT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. template AssertionResult AssertPred2Helper(const char* pred_text, const char* e1, const char* e2, Pred pred, const T1& v1, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Don't use this in your code. #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. #define GTEST_PRED2_(pred, v1, v2, on_failure)\ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ #v1, \ #v2, \ pred, \ v1, \ v2), on_failure) // Binary predicate assertion macros. #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) #define ASSERT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. template AssertionResult AssertPred3Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, Pred pred, const T1& v1, const T2& v2, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Don't use this in your code. #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. #define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ #v1, \ #v2, \ #v3, \ pred, \ v1, \ v2, \ v3), on_failure) // Ternary predicate assertion macros. #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) #define ASSERT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. template AssertionResult AssertPred4Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Don't use this in your code. #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. #define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ pred, \ v1, \ v2, \ v3, \ v4), on_failure) // 4-ary predicate assertion macros. #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. template AssertionResult AssertPred5Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); Message msg; msg << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ", " << e5 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4 << "\n" << e5 << " evaluates to " << v5; return AssertionFailure(msg); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Don't use this in your code. #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. #define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ #v5, \ pred, \ v1, \ v2, \ v3, \ v4, \ v5), on_failure) // 5-ary predicate assertion macros. #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ ceph-0.80.11/src/gtest/include/gtest/gtest.h0000664000175100017510000023002412623076744022663 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include #include #include #include #include #include #include #include #include // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // // The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to // aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. GTEST_DECLARE_bool_(throw_on_failure); // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class TestInfoImpl; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const String& message); class PrettyUnitTestResultPrinter; class XmlUnitTestResultPrinter; // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". // Declared in gtest-internal.h but defined here, so that it has access // to the definition of the Message class, required by the ARM // compiler. template String StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); // Used in the EXPECT_TRUE/FALSE(bool_expression). explicit AssertionResult(bool success) : success_(success) {} // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != NULL && message_->c_str() != NULL ? message_->c_str() : ""; } // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value); private: // No implementation - we want AssertionResult to be // copy-constructible but not assignable. void operator=(const AssertionResult& other); // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr message_; }; // class AssertionResult // Streams a custom failure message into this object. template AssertionResult& AssertionResult::operator<<(const T& value) { Message msg; if (message_.get() != NULL) msg << *message_; msg << value; message_.reset(new internal::String(msg.GetString())); return *this; } // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and // each TestCase contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { ... } // virtual void TearDown() { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class internal::TestInfoImpl; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test. Only the last value for a given // key is remembered. // These are public static so they can be called from utility functions // that are not members of the test fixture. // The arguments are const char* instead strings, as Google Test is used // on platforms where string doesn't compile. // // Note that a driving consideration for these RecordProperty methods // was to produce xml output suited to the Greenspan charting utility, // which at present will only chart values that fit in a 32-bit int. It // is the user's responsibility to restrict their values to 32-bit ints // if they intend them to be used with Greenspan. static void RecordProperty(const char* key, const char* value); static void RecordProperty(const char* key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const char* a_key, const char* a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const char* new_value) { value_ = new_value; } private: // The key supplied by the user. internal::String key_; // The value supplied by the user. internal::String value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } // Returns true iff the test failed. bool Failed() const; // Returns true iff the test fatally failed. bool HasFatalFailure() const; // Returns true iff the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range // from 0 to test_property_count() - 1. If i is not in that range, aborts // the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestInfoImpl; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. void RecordProperty(const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. // TODO(russr): Validate attribute names are legal and human readable. static bool ValidateTestProperty(const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test case name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test case name. const char* test_case_name() const; // Returns the test name. const char* name() const; // Returns the test case comment. const char* test_case_comment() const; // Returns the test comment. const char* comment() const; // Returns true if this test should run, that is if the test is not disabled // (or it is disabled but the also_run_disabled_tests flag has been specified) // and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test case Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const; // Returns the result of the test. const TestResult* result() const; private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::TestInfoImpl; friend class internal::UnitTestImpl; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Returns true if this test matches the user-specified filter. bool matches_filter() const; // Increments the number of death tests encountered in this test so // far. int increment_death_test_count(); // Accessors for the implementation object. internal::TestInfoImpl* impl() { return impl_; } const internal::TestInfoImpl* impl() const { return impl_; } // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // An opaque implementation object. internal::TestInfoImpl* impl_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test case, which consists of a vector of TestInfos. // // TestCase is not copyable. class GTEST_API_ TestCase { public: // Creates a TestCase with the given name. // // TestCase does NOT have a default constructor. Always use this // constructor to create a TestCase object. // // Arguments: // // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase(const char* name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Destructor of TestCase. virtual ~TestCase(); // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } // Returns the test case comment. const char* comment() const { return comment_.c_str(); } // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test case. int successful_test_count() const; // Gets the number of failed tests in this test case. int failed_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Get the number of tests in this test case that should run. int test_to_run_count() const; // Gets the number of all tests in this test case. int total_test_count() const; // Returns true iff the test case passed. bool Passed() const { return !Failed(); } // Returns true iff the test case failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test case. Will delete the TestInfo upon // destruction of the TestCase object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test case. void ClearResult(); // Clears the results of all tests in the given test case. static void ClearTestCaseResult(TestCase* test_case) { test_case->ClearResult(); } // Runs every test in this TestCase. void Run(); // Returns true iff test passed. static bool TestPassed(const TestInfo * test_info); // Returns true iff test failed. static bool TestFailed(const TestInfo * test_info); // Returns true iff test is disabled. static bool TestDisabled(const TestInfo * test_info); // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo *test_info); // Shuffles the tests in this test case. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test case. internal::String name_; // Comment on the test case. internal::String comment_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test case. Test::SetUpTestCaseFunc set_up_tc_; // Pointer to the function that tears down the test case. Test::TearDownTestCaseFunc tear_down_tc_; // True iff any test in this test case should run. bool should_run_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. The user should subclass this to define his own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test case starts. virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCESS(). virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} virtual void OnTestStart(const TestInfo& /*test_info*/) {} virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} virtual void OnTestEnd(const TestInfo& /*test_info*/) {} virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestCase; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::TestInfoImpl; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* current_test_case() const; // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const; // Returns the random seed used at the start of the current test run. int random_seed() const; #if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); #endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const; // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const; // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const internal::String& message, const internal::String& os_stack_trace); // Adds a TestProperty to the current TestResult object. If the result already // contains a property with the same key, the value will be updated. void RecordPropertyForCurrentTest(const char* key, const char* value); // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and funcions are friends as they need to access private // members of UnitTest. friend class Test; friend class internal::AssertHelper; friend class internal::ScopedTrace; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const internal::String& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace(); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { // These overloaded versions handle ::std::string and ::std::wstring. GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) { return (Message() << '"' << str << '"').GetString(); } #if GTEST_HAS_STD_WSTRING GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) { return (Message() << "L\"" << wstr << '"').GetString(); } #endif // GTEST_HAS_STD_WSTRING // These overloaded versions handle ::string and ::wstring. #if GTEST_HAS_GLOBAL_STRING GTEST_API_ inline String FormatForFailureMessage(const ::string& str) { return (Message() << '"' << str << '"').GetString(); } #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) { return (Message() << "L\"" << wstr << '"').GetString(); } #endif // GTEST_HAS_GLOBAL_WSTRING // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char*, and print it as a C string when it is compared against an // std::string object, for example. // // The default implementation ignores the type of the other operand. // Some specialized versions are used to handle formatting wide or // narrow C strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template String FormatForComparisonFailureMessage(const T1& value, const T2& /* other_operand */) { return FormatForFailureMessage(value); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { #ifdef _MSC_VER #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4389) // Temporarily disables warning on // signed/unsigned mismatch. #endif if (expected == actual) { return AssertionSuccess(); } #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() // is a null pointer literal. The following default implementation is // for lhs_is_null_literal being false. template class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal. template <> class EqHelper { public: // We define two overloaded versions of Compare(). The first // version will be picked when the second argument to ASSERT_EQ() is // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or // EXPECT_EQ(false, a_bool). template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // This version will be picked when the second argument to // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& /* expected */, T2* actual) { // We already know that 'expected' is a null pointer. return CmpHelperEQ(expected_expression, actual_expression, static_cast(NULL), actual); } }; // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ Message msg;\ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ return AssertionFailure(msg);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, !=); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <=); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, < ); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >=); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, > ); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } StrStream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; StrStream actual_ss; actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) << actual; return EqFailure(expected_expression, actual_expression, StrStreamToString(&expected_ss), StrStreamToString(&actual_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; String const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; } // namespace internal #if GTEST_HAS_PARAM_TEST // The abstract base class that all value-parameterized tests inherit from. // // This class adds support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // virtual ~FooTest() { // // Can use GetParam() here. // } // virtual void SetUp() { // // Can use GetParam() here. // } // virtual void TearDown { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class TestWithParam : public Test { public: typedef T ParamType; // The current parameter value. Is also available in the test fixture's // constructor. const ParamType& GetParam() const { return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of TestWithParam. template friend class internal::ParameterizedTestFactory; }; template const T* TestWithParam::parameter_ = NULL; #endif // GTEST_HAS_PARAM_TEST // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // // Examples: // // EXPECT_TRUE(server.StatusIsOK()); // ASSERT_FALSE(server.HasPendingRequest(port)) // << "There are still pending requests " << "on port " << port; // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL #define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED #define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Includes the auto-generated header that implements a family of // generic predicate assertion macros. #include // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to // {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(5, Foo()); // EXPECT_EQ(NULL, a_pointer); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define EXPECT_NE(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define ASSERT_EQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // C String Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. #define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) #define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) #define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. #define SCOPED_TRACE(message) \ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) namespace internal { // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; } // namespace internal // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { internal::StaticAssertTypeEqHelper(); return true; } // Defines a test. // // The first parameter is the name of the test case, and the second // parameter is the name of the test within the test case. // // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // // The user should put his test code between braces after using this // macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_case_name, test_name)\ GTEST_TEST_(test_case_name, test_name, \ ::testing::Test, ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST #define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test case name. The second parameter is the // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put // his test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(0, a_.size()); // EXPECT_EQ(1, b_.size()); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) // Use this macro in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). #define RUN_ALL_TESTS()\ (::testing::UnitTest::GetInstance()->Run()) } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_H_ ceph-0.80.11/src/gtest/include/gtest/gtest_prod.h0000664000175100017510000000442412623076744023712 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Google C++ Testing Framework definitions useful in production code. #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the // class. For example: // // class MyClass { // private: // void MyMethod(); // FRIEND_TEST(MyClassTest, MyMethod); // }; // // class MyClassTest : public testing::Test { // // ... // }; // // TEST_F(MyClassTest, MyMethod) { // // Can call MyClass::MyMethod() here. // } #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ ceph-0.80.11/src/gtest/include/gtest/gtest-spi.h0000664000175100017510000002333512623076744023461 0ustar jenkins-buildjenkins-build// Copyright 2007, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include namespace testing { // This helper class can be used to mock out Google Test failure reporting // so that we can test Google Test or code that builds on Google Test. // // An object of this class appends a TestPartResult object to the // TestPartResultArray object given in the constructor whenever a Google Test // failure is reported. It can either intercept only failures that are // generated in the same thread that created this object or it can intercept // all generated failures. The scope of this mock object can be controlled with // the second argument to the two arguments constructor. class GTEST_API_ ScopedFakeTestPartResultReporter : public TestPartResultReporterInterface { public: // The two possible mocking modes of this object. enum InterceptMode { INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. INTERCEPT_ALL_THREADS // Intercepts all failures. }; // The c'tor sets this object as the test part result reporter used // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, TestPartResultArray* result); // The d'tor restores the previous test part result reporter. virtual ~ScopedFakeTestPartResultReporter(); // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. virtual void ReportTestPartResult(const TestPartResult& result); private: void Init(); const InterceptMode intercept_mode_; TestPartResultReporterInterface* old_reporter_; TestPartResultArray* const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; namespace internal { // A helper class for implementing EXPECT_FATAL_FAILURE() and // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const char* substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; const String substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; } // namespace internal } // namespace testing // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_FATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - 'statement' cannot reference local non-static variables or // non-static members of the current object. // - 'statement' cannot return a value. // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. The AcceptsMacroThatExpandsToUnprotectedComma test in // gtest_unittest.cc will fail to compile if we do that. #define EXPECT_FATAL_FAILURE(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) // A macro for testing Google Test assertions or code that's expected to // generate Google Test non-fatal failures. It asserts that the given // statement will cause exactly one non-fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // 'statement' is allowed to reference local variables and members of // the current object. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. If we do that, the code won't compile when the user gives // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that // expands to code containing an unprotected comma. The // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc // catches that. // // For the same reason, we have to write // if (::testing::internal::AlwaysTrue()) { statement; } // instead of // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) // to avoid an MSVC warning on unreachable code. #define EXPECT_NONFATAL_FAILURE(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ ceph-0.80.11/src/gtest/include/gtest/gtest-param-test.h0000664000175100017510000022177412623076744024752 0ustar jenkins-buildjenkins-build// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // 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. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It must be derived from testing::TestWithParam, where T is // the type of your parameter values. TestWithParam is itself derived // from testing::Test. T can be any copyable type. If it's a raw pointer, // you are responsible for managing the lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. #endif // 0 #include #if !GTEST_OS_SYMBIAN #include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include #include #include #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::std::iterator_traits::value_type> ValuesIn( ForwardIterator begin, ForwardIterator end) { typedef typename ::std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to 50 parameters. // template internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) { return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) { return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) { return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) { return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) { return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) { return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { return internal::ValueArray21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) { return internal::ValueArray22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) { return internal::ValueArray23(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) { return internal::ValueArray24(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24); } template internal::ValueArray25 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { return internal::ValueArray25(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25); } template internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) { return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } template internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) { return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); } template internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) { return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28); } template internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) { return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29); } template internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30); } template internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); } template internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) { return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32); } template internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) { return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); } template internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) { return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); } template internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { return internal::ValueArray35(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); } template internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { return internal::ValueArray36(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36); } template internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) { return internal::ValueArray37(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37); } template internal::ValueArray38 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) { return internal::ValueArray38(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38); } template internal::ValueArray39 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) { return internal::ValueArray39(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39); } template internal::ValueArray40 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); } template internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); } template internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) { return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); } template internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) { return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43); } template internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) { return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44); } template internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45); } template internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46); } template internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); } template internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) { return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); } template internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) { return internal::ValueArray49(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); } template internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { return internal::ValueArray50(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } #if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) { return internal::CartesianProductHolder7( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) { return internal::CartesianProductHolder8( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) { return internal::CartesianProductHolder9( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) { return internal::CartesianProductHolder10( g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); } #endif // GTEST_HAS_COMBINE #define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ ceph-0.80.11/src/gtest/include/gtest/gtest-test-part.h0000664000175100017510000001450512623076744024610 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include #include #include namespace testing { // A copyable object representing the result of a test part (i.e. an // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). // // Don't inherit from TestPartResult as its destructor is not virtual. class GTEST_API_ TestPartResult { public: // The possible outcomes of a test part (i.e. an assertion or an // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. kFatalFailure // Failed and the test should be terminated. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), file_name_(a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), message_(a_message) { } // Gets the outcome of the test part. Type type() const { return type_; } // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { return file_name_.c_str(); } // Gets the line in the source file where the test part took place, // or -1 if it's unknown. int line_number() const { return line_number_; } // Gets the summary of the failure message. const char* summary() const { return summary_.c_str(); } // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } // Returns true iff the test part passed. bool passed() const { return type_ == kSuccess; } // Returns true iff the test part failed. bool failed() const { return type_ != kSuccess; } // Returns true iff the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } // Returns true iff the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } private: Type type_; // Gets the summary of the failure message by omitting the stack // trace in it. static internal::String ExtractSummary(const char* message); // The name of the source file where the test part took place, or // NULL if the source file is unknown. internal::String file_name_; // The line in the source file where the test part took place, or -1 // if the line number is unknown. int line_number_; internal::String summary_; // The test failure summary. internal::String message_; // The test failure message. }; // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result); // An array of TestPartResult objects. // // Don't inherit from TestPartResultArray as its destructor is not // virtual. class GTEST_API_ TestPartResultArray { public: TestPartResultArray() {} // Appends the given TestPartResult to the array. void Append(const TestPartResult& result); // Returns the TestPartResult at the given index (0-based). const TestPartResult& GetTestPartResult(int index) const; // Returns the number of TestPartResult objects in the array. int size() const; private: std::vector array_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); }; // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; namespace internal { // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a // statement generates new fatal failures. To do so it registers itself as the // current test part result reporter. Besides checking if fatal failures were // reported, it only delegates the reporting to the former result reporter. // The original result reporter is restored in the destructor. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); virtual ~HasNewFatalFailureHelper(); virtual void ReportTestPartResult(const TestPartResult& result); bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; TestPartResultReporterInterface* original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ ceph-0.80.11/src/gtest/include/gtest/gtest-typed-test.h0000664000175100017510000002366012623076744024771 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. // Typed (aka type-driven) tests repeat the same test for types in a // list. You must know which types you want to test with when writing // typed tests. Here's how you do it: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { public: ... typedef std::list List; static T shared_; T value_; }; // Next, associate a list of types with the test case, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // TYPED_TEST_CASE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed // tests for this test case as you want. TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. // Since we are inside a derived class template, C++ requires use to // visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the "typename // TestFixture::" prefix. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } #endif // 0 // Type-parameterized tests are abstract test patterns parameterized // by a type. Compared with typed tests, type-parameterized tests // allow you to define the test pattern without knowing what the type // parameters are. The defined pattern can be instantiated with // different types any number of times, in any number of translation // units. // // If you are designing an interface or concept, you can define a // suite of type-parameterized tests to verify properties that any // valid implementation of the interface/concept should have. Then, // each implementation can easily instantiate the test suite to verify // that it conforms to the requirements, without having to write // similar tests repeatedly. Here's an example: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { ... }; // Next, declare that you will define a type-parameterized test case // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): TYPED_TEST_CASE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests // for this type-parameterized test case as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the // test case name; the rest are the names of the tests in this test // case. REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include // it in multiple C++ source files and instantiate it multiple times. // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added // to the actual test case name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); #endif // 0 #include #include // Implements typed tests. #if GTEST_HAS_TYPED_TEST // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the // given test case. #define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) #define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) #define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ bool gtest_##CaseName##_##TestName##_registered_ = \ ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel< \ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ GTEST_TYPE_PARAMS_(CaseName)>::Register(\ "", #CaseName, #TestName, 0); \ template \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for // the given type-parameterized test case are defined in. The exact // name of the namespace is subject to change without notice. #define GTEST_CASE_NAMESPACE_(TestCaseName) \ gtest_case_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of // the defined tests in the given test case. #define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ gtest_typed_test_case_p_state_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of // the registered tests in the given test case. #define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ gtest_registered_test_names_##TestCaseName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. #define TYPED_TEST_CASE_P(CaseName) \ static ::testing::internal::TypedTestCasePState \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) #define TYPED_TEST_P(CaseName, TestName) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ template \ class TestName : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ static bool gtest_##TestName##_defined_ = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ __FILE__, __LINE__, #CaseName, #TestName); \ } \ template \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() #define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) #define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ ceph-0.80.11/src/gtest/include/gtest/gtest-message.h0000664000175100017510000002025212623076744024305 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the Message class. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include #include #include namespace testing { // The Message class works like an ostream repeater. // // Typical usage: // // 1. You stream a bunch of values to a Message object. // It will remember the text in a StrStream. // 2. Then you stream the Message object to an ostream. // This causes the text in the Message to be streamed // to the ostream. // // For example; // // testing::Message foo; // foo << 1 << " != " << 2; // std::cout << foo; // // will print "1 != 2". // // Message is not intended to be inherited from. In particular, its // destructor is not virtual. // // Note that StrStream behaves differently in gcc and in MSVC. You // can stream a NULL char pointer to it in the former, but not in the // latter (it causes an access violation if you do). The Message // class hides this difference by treating a NULL char pointer as // "(null)". class GTEST_API_ Message { private: // The type of basic IO manipulators (endl, ends, and flush) for // narrow streams. typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); public: // Constructs an empty Message. // We allocate the StrStream separately because it otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message() : ss_(new internal::StrStream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // Copy constructor. Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. explicit Message(const char* str) : ss_(new internal::StrStream) { *ss_ << str; } ~Message() { delete ss_; } #if GTEST_OS_SYMBIAN // Streams a value (either a pointer or not) to this object. template inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { ::GTestStreamToHelper(ss_, val); return *this; } // Streams a pointer value to this object. // // This function is an overload of the previous one. When you // stream a pointer to a Message, this definition will be used as it // is more specialized. (The C++ Standard, section // [temp.func.order].) If you stream a non-pointer, then the // previous definition will be used. // // The reason for this overload is that streaming a NULL pointer to // ostream is undefined behavior. Depending on the compiler, you // may get "0", "(nil)", "(null)", or an access violation. To // ensure consistent result across compilers, we always treat NULL // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT if (pointer == NULL) { *ss_ << "(null)"; } else { ::GTestStreamToHelper(ss_, pointer); } return *this; } #endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition // of operator <<, even though its body is the same as the // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. Message& operator <<(BasicNarrowIoManip val) { *ss_ << val; return *this; } // Instead of 1/0, we want to see true/false for bool values. Message& operator <<(bool b) { return *this << (b ? "true" : "false"); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::wstring& wstr); #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as a String. // Each '\0' character in the buffer is replaced with "\\0". // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::String GetString() const { return internal::StrStreamToString(ss_); } private: #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ // decide between class template specializations for T and T*, so a // tr1::type_traits-like is_pointer works, and we can overload on that. template inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { ::GTestStreamToHelper(ss_, pointer); } } template inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { ::GTestStreamToHelper(ss_, value); } #endif // GTEST_OS_SYMBIAN // We'll hold the text streamed to this object here. internal::StrStream* const ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. void operator=(const Message&); }; // Streams a Message to an ostream. inline std::ostream& operator <<(std::ostream& os, const Message& sb) { return os << sb.GetString(); } } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ ceph-0.80.11/src/gtest/include/gtest/gtest-death-test.h0000664000175100017510000002551012623076744024725 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #include namespace testing { // This flag controls the style of death tests. Valid values are "threadsafe", // meaning that the death test child process will re-execute the test binary // from the start, running only a single death test, or "fast", // meaning that the child process will execute the test logic immediately // after forking. GTEST_DECLARE_string_(death_test_style); #if GTEST_HAS_DEATH_TEST // The following macros are useful for writing death tests. // Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is // executed: // // 1. It generates a warning if there is more than one active // thread. This is because it's safe to fork() or clone() only // when there is a single thread. // // 2. The parent process clone()s a sub-process and runs the death // test in it; the sub-process exits with code 0 at the end of the // death test, if it hasn't exited already. // // 3. The parent process waits for the sub-process to terminate. // // 4. The parent process checks the exit code and error message of // the sub-process. // // Examples: // // ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); // for (int i = 0; i < 5; i++) { // EXPECT_DEATH(server.ProcessRequest(i), // "Invalid request .* in ProcessRequest()") // << "Failed to die on request " << i); // } // // ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); // // bool KilledBySIGHUP(int exit_code) { // return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; // } // // ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); // // On the regular expressions used in death tests: // // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // // On other platforms (e.g. Windows), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE // or POSIX extended regex syntax. For example, we don't support // union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and // repetition count ("x{5,7}"), among others. // // Below is the syntax that we do support. We chose it to be a // subset of both PCRE and POSIX extended regex, so it's easy to // learn wherever you come from. In the following: 'A' denotes a // literal character, period (.), or a single \\ escape sequence; // 'x' and 'y' denote regular expressions; 'm' and 'n' are for // natural numbers. // // c matches any literal character c // \\d matches any decimal digit // \\D matches any character that's not a decimal digit // \\f matches \f // \\n matches \n // \\r matches \r // \\s matches any ASCII whitespace, including \n // \\S matches any character that's not a whitespace // \\t matches \t // \\v matches \v // \\w matches any letter, _, or decimal digit // \\W matches any character that \\w doesn't match // \\c matches any literal character c, which must be a punctuation // . matches any single character except \n // A? matches 0 or 1 occurrences of A // A* matches 0 or many occurrences of A // A+ matches 1 or many occurrences of A // ^ matches the beginning of a string (not that of each line) // $ matches the end of a string (not that of each line) // xy matches x followed by y // // If you accidentally use PCRE or POSIX extended regex features // not implemented by us, you will get a run-time failure. In that // case, please try to rewrite your regular expression within the // above syntax. // // This implementation is *not* meant to be as highly tuned or robust // as a compiled regex library, but should perform well enough for a // death test, which already incurs significant overhead by launching // a child process. // // Known caveats: // // A "threadsafe" style death test obtains the path to the test // program from argv[0] and re-executes it in the sub-process. For // simplicity, the current implementation doesn't search the PATH // when launching the sub-process. This means that the user must // invoke the test program via a path that contains at least one // path separator (e.g. path/to/foo_test and // /absolute/path/to/bar_test are fine, but foo_test is not). This // is rarely a problem as people usually don't put the test binary // directory in PATH. // // TODO(wan@google.com): make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output // that matches regex. #define ASSERT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the // test case, if any: #define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) // Asserts that a given statement causes the program to exit, either by // explicitly exiting with a nonzero exit code or being killed by a // signal, and emitting error output that matches regex. #define ASSERT_DEATH(statement, regex) \ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the // test case, if any: #define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: // Tests that an exit code describes a normal exit with a given exit code. class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); bool operator()(int exit_status) const; private: // No implementation - assignment is unsupported. void operator=(const ExitedWithCode& other); const int exit_code_; }; #if !GTEST_OS_WINDOWS // Tests that an exit code describes an exit due to termination by a // given signal. class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); bool operator()(int exit_status) const; private: const int signum_; }; #endif // !GTEST_OS_WINDOWS // EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. // The death testing framework causes this to have interesting semantics, // since the sideeffects of the call are only visible in opt mode, and not // in debug mode. // // In practice, this can be used to test functions that utilize the // LOG(DFATAL) macro using the following style: // // int DieInDebugOr12(int* sideeffect) { // if (sideeffect) { // *sideeffect = 12; // } // LOG(DFATAL) << "death"; // return 12; // } // // TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); // // #ifdef NDEBUG // // opt-mode has sideeffect visible. // EXPECT_EQ(12, sideeffect); // #else // // dbg-mode no visible sideeffect. // EXPECT_EQ(0, sideeffect); // #endif // } // // This will assert that DieInDebugReturn12InOpt() crashes in debug // mode, usually due to a DCHECK or LOG(DFATAL), but returns the // appropriate fallback value (12 in this case) in opt mode. If you // need to test that a function has appropriate side-effects in opt // mode, include assertions against the side-effects. A general // pattern for this is: // // EXPECT_DEBUG_DEATH({ // // Side-effects here will have an effect after this statement in // // opt mode, but none in debug mode. // EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); // }, "death"); // #ifdef NDEBUG #define EXPECT_DEBUG_DEATH(statement, regex) \ do { statement; } while (::testing::internal::AlwaysFalse()) #define ASSERT_DEBUG_DEATH(statement, regex) \ do { statement; } while (::testing::internal::AlwaysFalse()) #else #define EXPECT_DEBUG_DEATH(statement, regex) \ EXPECT_DEATH(statement, regex) #define ASSERT_DEBUG_DEATH(statement, regex) \ ASSERT_DEATH(statement, regex) #endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is // useful when you are combining death test assertions with normal test // assertions in one test. #if GTEST_HAS_DEATH_TEST #define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ EXPECT_DEATH(statement, regex) #define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ ASSERT_DEATH(statement, regex) #else #define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) #define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) #endif } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ ceph-0.80.11/src/gtest/include/gtest/internal/0000775000175100017510000000000012623077036023172 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/include/gtest/internal/gtest-filepath.h0000664000175100017510000002274112623076744026276 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: keith.ray@gmail.com (Keith Ray) // // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included in . // Do not include this header file separately! #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #include namespace testing { namespace internal { // FilePath - a class for file and directory pathname manipulation which // handles platform-specific conventions (like the pathname separator). // Used for helper functions for naming files in a directory for xml output. // Except for Set methods, all methods are const or static, which provides an // "immutable value object" -- useful for peace of mind. // A FilePath with a value ending in a path separator ("like/this/") represents // a directory, otherwise it is assumed to represent a file. In either case, // it may or may not represent an actual file or directory in the file system. // Names are NOT checked for syntax correctness -- no checking for illegal // characters, malformed paths, etc. class GTEST_API_ FilePath { public: FilePath() : pathname_("") { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } explicit FilePath(const char* pathname) : pathname_(pathname) { Normalize(); } explicit FilePath(const String& pathname) : pathname_(pathname) { Normalize(); } FilePath& operator=(const FilePath& rhs) { Set(rhs); return *this; } void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } String ToString() const { return pathname_; } const char* c_str() const { return pathname_.c_str(); } // Returns the current working directory, or "" if unsuccessful. static FilePath GetCurrentDir(); // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. static FilePath MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension); // Given directory = "dir", relative_path = "test.xml", // returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. static FilePath ConcatPaths(const FilePath& directory, const FilePath& relative_path); // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. static FilePath GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension); // Returns true iff the path is NULL or "". bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } // If input name has a trailing separator character, removes it and returns // the name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath RemoveTrailingPathSeparator() const; // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveDirectoryName() const; // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveFileName() const; // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath RemoveExtension(const char* extension) const; // Creates directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create // directories for any reason. Will also return false if the FilePath does // not represent a directory (that is, it doesn't end with a path separator). bool CreateDirectoriesRecursively() const; // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool CreateFolder() const; // Returns true if FilePath describes something in the file-system, // either a file, directory, or whatever, and that something exists. bool FileOrDirectoryExists() const; // Returns true if pathname describes a directory in the file-system // that exists. bool DirectoryExists() const; // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool IsDirectory() const; // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool IsRootDirectory() const; // Returns true if pathname describes an absolute path. bool IsAbsolutePath() const; private: // Replaces multiple consecutive separators with a single separator. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // // A pathname with multiple consecutive separators may occur either through // user error or as a result of some scripts or APIs that generate a pathname // with a trailing separator. On other platforms the same API or script // may NOT generate a pathname with a trailing "/". Then elsewhere that // pathname may have another "/" and pathname components added to it, // without checking for the separator already being there. // The script language and operating system may allow paths like "foo//bar" // but some of the functions in FilePath will not handle that correctly. In // particular, RemoveTrailingPathSeparator() only removes one separator, and // it is called in CreateDirectoriesRecursively() assuming that it will change // a pathname from directory syntax (trailing separator) to filename syntax. // // On Windows this method also replaces the alternate path separator '/' with // the primary path separator '\\', so that for example "bar\\/\\foo" becomes // "bar\\foo". void Normalize(); // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FindLastPathSeparator() const; String pathname_; }; // class FilePath } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-param-util-generated.h0000664000175100017510000051232212623076744030510 0ustar jenkins-buildjenkins-build// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most 50 arguments in Values, // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include #include #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::std::iterator_traits::value_type> ValuesIn( ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); const T1 v1_; const T2 v2_; const T3 v3_; }; template class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; }; template class ValueArray5 { public: ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; }; template class ValueArray6 { public: ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; }; template class ValueArray7 { public: ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; }; template class ValueArray8 { public: ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; }; template class ValueArray9 { public: ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; }; template class ValueArray10 { public: ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; }; template class ValueArray11 { public: ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; }; template class ValueArray12 { public: ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; }; template class ValueArray13 { public: ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; }; template class ValueArray14 { public: ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; }; template class ValueArray15 { public: ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; }; template class ValueArray16 { public: ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; }; template class ValueArray17 { public: ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; }; template class ValueArray18 { public: ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; }; template class ValueArray19 { public: ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; }; template class ValueArray20 { public: ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; }; template class ValueArray21 { public: ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; }; template class ValueArray22 { public: ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; }; template class ValueArray23 { public: ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; }; template class ValueArray24 { public: ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; }; template class ValueArray25 { public: ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; }; template class ValueArray26 { public: ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; }; template class ValueArray27 { public: ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; }; template class ValueArray28 { public: ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; }; template class ValueArray29 { public: ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; }; template class ValueArray30 { public: ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; }; template class ValueArray31 { public: ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; }; template class ValueArray32 { public: ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; }; template class ValueArray33 { public: ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; }; template class ValueArray34 { public: ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; }; template class ValueArray35 { public: ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; }; template class ValueArray36 { public: ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; }; template class ValueArray37 { public: ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; }; template class ValueArray38 { public: ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; }; template class ValueArray39 { public: ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; }; template class ValueArray40 { public: ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; }; template class ValueArray41 { public: ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; }; template class ValueArray42 { public: ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; }; template class ValueArray43 { public: ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; }; template class ValueArray44 { public: ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; }; template class ValueArray45 { public: ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; }; template class ValueArray46 { public: ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; }; template class ValueArray47 { public: ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; }; template class ValueArray48 { public: ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, v48_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; }; template class ValueArray49 { public: ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, v48_, v49_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; }; template class ValueArray50 { public: ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} template operator ParamGenerator() const { const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, v48_, v49_, v50_}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; const T50 v50_; }; #if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // template class CartesianProductGenerator2 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current2_; if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current3_; if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current4_; if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current5_; if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current6_; if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current7_; if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current8_; if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current9_; if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} virtual ~CartesianProductGenerator10() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end(), g10_, g10_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::iterator& current10) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9), begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current10_; if (current10_ == end10_) { current10_ = begin10_; ++current9_; } if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_ && current10_ == typed_other->current10_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_), begin10_(other.begin10_), end10_(other.end10_), current10_(other.current10_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_, *current10_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_ || current10_ == end10_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder3& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; }; // class CartesianProductHolder3 template class CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder4& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; }; // class CartesianProductHolder4 template class CartesianProductHolder5 { public: CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder5& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; }; // class CartesianProductHolder5 template class CartesianProductHolder6 { public: CartesianProductHolder6(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder6& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; }; // class CartesianProductHolder6 template class CartesianProductHolder7 { public: CartesianProductHolder7(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder7& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; }; // class CartesianProductHolder7 template class CartesianProductHolder8 { public: CartesianProductHolder8(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder8& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; }; // class CartesianProductHolder8 template class CartesianProductHolder9 { public: CartesianProductHolder9(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder9& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; }; // class CartesianProductHolder9 template class CartesianProductHolder10 { public: CartesianProductHolder10(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(g10_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder10& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; const Generator10 g10_; }; // class CartesianProductHolder10 #endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-tuple.h.pump0000664000175100017510000002200512623076744026604 0ustar jenkins-buildjenkins-build$$ -*- mode: c++; -*- $var n = 10 $$ Maximum number of tuple fields we want to support. $$ This meta comment fixes auto-indentation in Emacs. }} // Copyright 2009 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) #define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else #define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif $range i 0..n-1 $range j 0..n $range k 1..n // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> $for k [[ $range m 0..k-1 $range m2 k..n-1 #define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]> ]] // GTEST_n_TYPENAMES_(T) declares a list of n typenames. $for j [[ $range m 0..j-1 #define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]] ]] // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template <$for i, [[typename T$i = void]]> class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; $for i [[ template struct TupleElement [[]] { typedef T$i type; }; ]] } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; $for k [[ $range m 0..k-1 template class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { public: template friend class gtest_internal::Get; tuple() : $for m, [[f$(m)_()]] {} explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]] $for m, [[f$(m)_(f$m)]] {} tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} template tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} $if k == 2 [[ template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} ]] tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { return CopyFrom(t); } $if k == 2 [[ template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } ]] GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) { $for m [[ f$(m)_ = t.f$(m)_; ]] return *this; } $for m [[ T$m f$(m)_; ]] }; ]] // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } $for k [[ $range m 0..k-1 template inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) { return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]); } ]] // 6.1.3.3 Tuple helper classes. template struct tuple_size; $for j [[ template struct tuple_size { static const int value = $j; }; ]] template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { $for i [[ template <> class Get<$i> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) Field(Tuple& t) { return t.f$(i)_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) ConstField(const Tuple& t) { return t.f$(i)_; } }; ]] } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(const GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, const GTEST_$(n)_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t, const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std $for j [[ #undef GTEST_$(j)_TUPLE_ ]] $for j [[ #undef GTEST_$(j)_TYPENAMES_ ]] #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-tuple.h0000664000175100017510000006673112623076744025642 0ustar jenkins-buildjenkins-build// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2009 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) #define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else #define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // GTEST_n_TYPENAMES_(T) declares a list of n typenames. #define GTEST_0_TYPENAMES_(T) #define GTEST_1_TYPENAMES_(T) typename T##0 #define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 #define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 #define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3 #define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4 #define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5 #define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6 #define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 #define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8 #define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8, typename T##9 // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), f1_(f1) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} template tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; return *this; } T0 f0_; T1 f1_; T2 f2_; }; template class GTEST_4_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), f3_(f3) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} template tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; }; template class GTEST_5_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} template tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; }; template class GTEST_6_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} template tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; }; template class GTEST_7_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} template tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; }; template class GTEST_8_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} template tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; }; template class GTEST_9_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} template tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; }; template class tuple { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), f9_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} template tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; f9_ = t.f9_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; T9 f9_; }; // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { return GTEST_3_TUPLE_(T)(f0, f1, f2); } template inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3) { return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); } template inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4) { return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); } template inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5) { return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); } template inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6) { return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); } template inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); } template inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8) { return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); } template inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8, const T9& f9) { return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } // 6.1.3.3 Tuple helper classes. template struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std #undef GTEST_0_TUPLE_ #undef GTEST_1_TUPLE_ #undef GTEST_2_TUPLE_ #undef GTEST_3_TUPLE_ #undef GTEST_4_TUPLE_ #undef GTEST_5_TUPLE_ #undef GTEST_6_TUPLE_ #undef GTEST_7_TUPLE_ #undef GTEST_8_TUPLE_ #undef GTEST_9_TUPLE_ #undef GTEST_10_TUPLE_ #undef GTEST_0_TYPENAMES_ #undef GTEST_1_TYPENAMES_ #undef GTEST_2_TYPENAMES_ #undef GTEST_3_TYPENAMES_ #undef GTEST_4_TYPENAMES_ #undef GTEST_5_TYPENAMES_ #undef GTEST_6_TYPENAMES_ #undef GTEST_7_TYPENAMES_ #undef GTEST_8_TYPENAMES_ #undef GTEST_9_TYPENAMES_ #undef GTEST_10_TYPENAMES_ #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-linked_ptr.h0000664000175100017510000002016212623076744026630 0ustar jenkins-buildjenkins-build// Copyright 2003 Google Inc. // 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. // // Authors: Dan Egnor (egnor@google.com) // // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. // // Used properly, this deletes the object when the last reference goes away. // There are several caveats: // - Like all reference counting schemes, cycles lead to leaks. // - Each smart pointer is actually two pointers (8 bytes instead of 4). // - Every time a pointer is assigned, the entire list of pointers to that // object is traversed. This class is therefore NOT SUITABLE when there // will often be more than two or three pointers to a particular object. // - References are only tracked as long as linked_ptr<> objects are copied. // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS // will happen (double deletion). // // A good use of this class is storing object references in STL containers. // You can safely put linked_ptr<> in a vector<>. // Other uses may not be as good. // // Note: If you use an incomplete type with linked_ptr<>, the class // *containing* linked_ptr<> must have a constructor and destructor (even // if they do nothing!). // // Bill Gibbons suggested we use something like this. // // Thread Safety: // Unlike other linked_ptr implementations, in this implementation // a linked_ptr object is thread-safe in the sense that: // - it's safe to copy linked_ptr objects concurrently, // - it's safe to copy *from* a linked_ptr and read its underlying // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. // TODO(wan@google.com): rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #include #include #include namespace testing { namespace internal { // Protects copying of all linked_ptr objects. GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to // the same object (linked_ptr(obj) vs linked_ptr(obj)). // So, it needs to be possible for different types of linked_ptr to participate // in the same circular linked list, so we need a single class type here. // // DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. class linked_ptr_internal { public: // Create a new circle that includes only this instance. void join_new() { next_ = this; } // Many linked_ptr operations may change p.link_ for some linked_ptr // variable p in the same circle as this object. Therefore we need // to prevent two such operations from occurring concurrently. // // Note that different types of linked_ptr objects can coexist in a // circle (e.g. linked_ptr, linked_ptr, and // linked_ptr). Therefore we must use a single mutex to // protect all linked_ptr objects. This can create serious // contention in production code, but is acceptable in a testing // framework. // Join an existing circle. // L < g_linked_ptr_mutex void join(linked_ptr_internal const* ptr) { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; while (p->next_ != ptr) p = p->next_; p->next_ = this; next_ = ptr; } // Leave whatever circle we're part of. Returns true if we were the // last member of the circle. Once this is done, you can join() another. // L < g_linked_ptr_mutex bool depart() { MutexLock lock(&g_linked_ptr_mutex); if (next_ == this) return true; linked_ptr_internal const* p = next_; while (p->next_ != this) p = p->next_; p->next_ = next_; return false; } private: mutable linked_ptr_internal const* next_; }; template class linked_ptr { public: typedef T element_type; // Take over ownership of a raw pointer. This should happen as soon as // possible after the object is created. explicit linked_ptr(T* ptr = NULL) { capture(ptr); } ~linked_ptr() { depart(); } // Copy an existing linked_ptr<>, adding ourselves to the list of references. template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } linked_ptr(linked_ptr const& ptr) { // NOLINT assert(&ptr != this); copy(&ptr); } // Assignment releases the old value and acquires the new. template linked_ptr& operator=(linked_ptr const& ptr) { depart(); copy(&ptr); return *this; } linked_ptr& operator=(linked_ptr const& ptr) { if (&ptr != this) { depart(); copy(&ptr); } return *this; } // Smart pointer members. void reset(T* ptr = NULL) { depart(); capture(ptr); } T* get() const { return value_; } T* operator->() const { return value_; } T& operator*() const { return *value_; } // Release ownership of the pointed object and returns it. // Sole ownership by this linked_ptr object is required. T* release() { bool last = link_.depart(); assert(last); T* v = value_; value_ = NULL; return v; } bool operator==(T* p) const { return value_ == p; } bool operator!=(T* p) const { return value_ != p; } template bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template friend class linked_ptr; T* value_; linked_ptr_internal link_; void depart() { if (link_.depart()) delete value_; } void capture(T* ptr) { value_ = ptr; link_.join_new(); } template void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-param-util.h0000664000175100017510000005744512623076744026566 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #include #include #include // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include #include #include #if GTEST_HAS_PARAM_TEST namespace testing { namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Outputs a message explaining invalid registration of different // fixture class for the same test case. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line); template class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template class ParamIteratorInterface { public: virtual ~ParamIteratorInterface() {} // A pointer to the base generator instance. // Used only for the purposes of iterator comparison // to make sure that two iterators belong to the same generator. virtual const ParamGeneratorInterface* BaseGenerator() const = 0; // Advances iterator to point to the next element // provided by the generator. The caller is responsible // for not calling Advance() on an iterator equal to // BaseGenerator()->End(). virtual void Advance() = 0; // Clones the iterator object. Used for implementing copy semantics // of ParamIterator. virtual ParamIteratorInterface* Clone() const = 0; // Dereferences the current iterator and provides (read-only) access // to the pointed value. It is the caller's responsibility not to call // Current() on an iterator equal to BaseGenerator()->End(). // Used for implementing ParamGenerator::operator*(). virtual const T* Current() const = 0; // Determines whether the given iterator and other point to the same // element in the sequence generated by the generator. // Used for implementing ParamGenerator::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template class ParamIterator { public: typedef T value_type; typedef const T& reference; typedef ptrdiff_t difference_type; // ParamIterator assumes ownership of the impl_ pointer. ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} ParamIterator& operator=(const ParamIterator& other) { if (this != &other) impl_.reset(other.impl_->Clone()); return *this; } const T& operator*() const { return *impl_->Current(); } const T* operator->() const { return impl_->Current(); } // Prefix version of operator++. ParamIterator& operator++() { impl_->Advance(); return *this; } // Postfix version of operator++. ParamIterator operator++(int /*unused*/) { ParamIteratorInterface* clone = impl_->Clone(); impl_->Advance(); return ParamIterator(clone); } bool operator==(const ParamIterator& other) const { return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); } bool operator!=(const ParamIterator& other) const { return !(*this == other); } private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} ParamGenerator& operator=(const ParamGenerator& other) { impl_ = other.impl_; return *this; } iterator begin() const { return iterator(impl_->Begin()); } iterator end() const { return iterator(impl_->End()); } private: ::testing::internal::linked_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to // generate sequences of user-defined types that implement operator+() and // operator<(). // This class is used in the Range() function. template class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const int other_index = CheckedDowncastToActualType(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; T value_; int index_; const IncrementT step_; }; // class RangeGenerator::Iterator static int CalculateEndIndex(const T& begin, const T& end, const IncrementT& step) { int end_index = 0; for (T i = begin; i < end; i = i + step) end_index++; return end_index; } // No implementation - assignment is unsupported. void operator=(const RangeGenerator& other); const T begin_; const T end_; const IncrementT step_; // The index for the end() iterator. All the elements in the generated // sequence are indexed (0-based) to aid iterator comparison. const int end_index_; }; // class RangeGenerator // Generates values from a pair of STL-style iterators. Used in the // ValuesIn() function. The elements are copied from the source range // since the source can be located on the stack, and the generator // is likely to persist beyond that stack frame. template class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ // can return a temporary object (and of type other then T), so just // having "return &*iterator_;" doesn't work. // value_ is updated here and not in Advance() because Advance() // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. virtual const T* Current() const { if (value_.get() == NULL) value_.reset(new T(*iterator_)); return value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; return iterator_ == CheckedDowncastToActualType(&other)->iterator_; } private: Iterator(const Iterator& other) // The explicit constructor call suppresses a false warning // emitted by gcc when supplied with the -Wextra option. : ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* const base_; typename ContainerType::const_iterator iterator_; // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). // Use of scoped_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. mutable scoped_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. void operator=(const ValuesInIteratorRangeGenerator& other); const ContainerType container_; }; // class ValuesInIteratorRangeGenerator // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that // value. template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} virtual Test* CreateTest() { TestClass::SetParam(¶meter_); return new TestClass(); } private: const ParamType parameter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactoryBase is a base class for meta-factories that create // test factories for passing into MakeAndRegisterTestInfo function. template class TestMetaFactoryBase { public: virtual ~TestMetaFactoryBase() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed // into that method twice. But ParameterizedTestCaseInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. template class TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(parameter); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfoBase is a generic interface // to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase // accumulates test information provided by TEST_P macro invocations // and generators provided by INSTANTIATE_TEST_CASE_P macro invocations // and uses that information to register all resulting test instances // in RegisterTests method. The ParameterizeTestCaseRegistry class holds // a collection of pointers to the ParameterizedTestCaseInfo objects // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. virtual const String& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this // test case right before running them in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. virtual void RegisterTests() = 0; protected: ParameterizedTestCaseInfoBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfo accumulates tests obtained from TEST_P // macro invocations for a particular test case and generators // obtained from INSTANTIATE_TEST_CASE_P macro invocations for that // test case. It registers tests with all values generated by all // generators when asked. template class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and // AddTestCaseInstantiation(). typedef typename TestCase::ParamType ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); explicit ParameterizedTestCaseInfo(const char* name) : test_case_name_(name) {} // Test case base name for display purposes. virtual const String& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. // test_case_name is the base name of the test case (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test case base name and DoBar is test base name. void AddTestPattern(const char* test_case_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { tests_.push_back(linked_ptr(new TestInfo(test_case_name, test_base_name, meta_factory))); } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. int AddTestCaseInstantiation(const char* instantiation_name, GeneratorCreationFunc* func, const char* /* file */, int /* line */) { instantiations_.push_back(::std::make_pair(instantiation_name, func)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test case // test cases right before running tests in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. // UnitTest has a guard to prevent from calling this method more then once. virtual void RegisterTests() { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { linked_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { const String& instantiation_name = gen_it->first; ParamGenerator generator((*gen_it->second)()); Message test_case_name_stream; if ( !instantiation_name.empty() ) test_case_name_stream << instantiation_name.c_str() << "/"; test_case_name_stream << test_info->test_case_base_name.c_str(); int i = 0; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; test_name_stream << test_info->test_base_name.c_str() << "/" << i; ::testing::internal::MakeAndRegisterTestInfo( test_case_name_stream.GetString().c_str(), test_name_stream.GetString().c_str(), "", // test_case_comment "", // comment; TODO(vladl@google.com): provide parameter value // representation. GetTestCaseTypeId(), TestCase::SetUpTestCase, TestCase::TearDownTestCase, test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { TestInfo(const char* a_test_case_base_name, const char* a_test_base_name, TestMetaFactoryBase* a_test_meta_factory) : test_case_base_name(a_test_case_base_name), test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} const String test_case_base_name; const String test_base_name; const scoped_ptr > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > InstantiationContainer; const String test_case_name_; TestInfoContainer tests_; InstantiationContainer instantiations_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); }; // class ParameterizedTestCaseInfo // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase // classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P // macros use it to locate their corresponding ParameterizedTestCaseInfo // descriptors. class ParameterizedTestCaseRegistry { public: ParameterizedTestCaseRegistry() {} ~ParameterizedTestCaseRegistry() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { delete *it; } } // Looks up or creates and returns a structure containing information about // tests and instantiations of a particular test case. template ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* typed_test_info = NULL; for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { if ((*it)->GetTestCaseName() == test_case_name) { if ((*it)->GetTestCaseTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct // test case setup and tear-down in this case. ReportInvalidTestCaseType(test_case_name, file, line); abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< ParameterizedTestCaseInfo >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(test_case_name); test_case_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { (*it)->RegisterTests(); } } private: typedef ::std::vector TestCaseInfoContainer; TestCaseInfoContainer test_case_infos_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); }; } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-type-util.h0000664000175100017510000055202412623076744026440 0ustar jenkins-buildjenkins-build// This file was GENERATED by command: // pump.py gtest-type-util.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #include #include #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). #ifdef __GLIBCXX__ #include #endif // __GLIBCXX__ namespace testing { namespace internal { // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // GetTypeName() returns a human-readable name of type T. template String GetTypeName() { #if GTEST_HAS_RTTI const char* const name = typeid(T).name(); #ifdef __GLIBCXX__ int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status); const String name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; #else return name; #endif // __GLIBCXX__ #else return ""; #endif // GTEST_HAS_RTTI } // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 Tail; }; } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { #define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; #define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 Tail; }; // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 type; }; // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; } // namespace internal } // namespace testing #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-port.h0000664000175100017510000014524412623076744025472 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan) // // Low-level types and utilities for porting Google Test to various // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro // in this list, Google Test will define it. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::string, which is different to std::string). // GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::wstring, which is different to std::wstring). // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple // is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets // GTEST_HAS_TR1_TUPLE to 0. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // This header defines the following utilities: // // Macros indicating the current platform (defined to 1 if compiled on // the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_LINUX - Linux // GTEST_OS_MAC - Mac OS X // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // Note that it is possible that none of the GTEST_OS_* macros are defined. // // Macros indicating available Google Test features (defined to 1 if // the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above two are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // GTEST_IS_THREADSAFE - defined to 1 to indicate that the above // synchronization primitives have real implementations // and Google Test is thread-safe; or 0 otherwise. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax. Not available on // Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. #include // For ptrdiff_t #include #include #include #ifndef _WIN32_WCE #include #endif // !_WIN32_WCE #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_DASH_ "gtest-" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" #define GTEST_NAME_ "Google Test" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. #define GTEST_GCC_VER_ \ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ #define GTEST_OS_CYGWIN 1 #elif defined __SYMBIAN32__ #define GTEST_OS_SYMBIAN 1 #elif defined _WIN32 #define GTEST_OS_WINDOWS 1 #ifdef _WIN32_WCE #define GTEST_OS_WINDOWS_MOBILE 1 #elif defined(__MINGW__) || defined(__MINGW32__) #define GTEST_OS_WINDOWS_MINGW 1 #else #define GTEST_OS_WINDOWS_DESKTOP 1 #endif // _WIN32_WCE #elif defined __APPLE__ #define GTEST_OS_MAC 1 #elif defined __linux__ #define GTEST_OS_LINUX 1 #elif defined __MVS__ #define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) #define GTEST_OS_SOLARIS 1 #elif defined(_AIX) #define GTEST_OS_AIX 1 #endif // __CYGWIN__ #if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \ GTEST_OS_SOLARIS || GTEST_OS_AIX // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS #if !GTEST_OS_WINDOWS_MOBILE #include // NOLINT #include // NOLINT #endif // is not available on Windows. Use our own simple regex // implementation instead. #define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. #define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. #ifndef _HAS_EXCEPTIONS #define _HAS_EXCEPTIONS 1 #endif // _HAS_EXCEPTIONS #define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS #elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. #define GTEST_HAS_EXCEPTIONS 1 #elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. #define GTEST_HAS_EXCEPTIONS 1 #elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. #define GTEST_HAS_EXCEPTIONS 1 #else // For other compilers, we assume exceptions are disabled to be // conservative. #define GTEST_HAS_EXCEPTIONS 0 #endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #if !defined(GTEST_HAS_STD_STRING) // Even though we don't use this macro any longer, we keep it in case // some clients still depend on it. #define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. #error "Google Test cannot be used where ::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING // The user didn't tell us whether ::string is available, so we need // to figure it out. #define GTEST_HAS_GLOBAL_STRING 0 #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // TODO(wan@google.com): uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.5 and below doesn't support ::std::wstring. // Cygwin 1.7 might add wstring support; this should be updated when clear. // Solaris' libc++ doesn't support it either. #define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) #endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_GLOBAL_WSTRING // The user didn't tell us whether ::wstring is available, so we need // to figure it out. #define GTEST_HAS_GLOBAL_WSTRING \ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) #endif // GTEST_HAS_GLOBAL_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. #ifdef _MSC_VER #ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. #define GTEST_HAS_RTTI 1 #else #define GTEST_HAS_RTTI 0 #endif // Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. #elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) #ifdef __GXX_RTTI #define GTEST_HAS_RTTI 1 #else #define GTEST_HAS_RTTI 0 #endif // __GXX_RTTI // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. #elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) #ifdef __RTTI_ALL__ #define GTEST_HAS_RTTI 1 #else #define GTEST_HAS_RTTI 0 #endif #else // For all other compilers, we assume RTTI is enabled. #define GTEST_HAS_RTTI 1 #endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI #include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we assume pthreads support is // available on Linux and Mac. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. #define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) #endif // GTEST_HAS_PTHREAD // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). #ifndef GTEST_HAS_TR1_TUPLE // The user didn't tell us not to do it, so we assume it's OK. #define GTEST_HAS_TR1_TUPLE 1 #endif // GTEST_HAS_TR1_TUPLE // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an // implementation of it already. At this time, GCC 4.0.0+ and MSVC // 2010 are the only mainstream compilers that come with a TR1 tuple // implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by // defining __GNUC__ and friends, but cannot compile GCC's tuple // implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB // Feature Pack download, which we cannot assume the user has. #if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ || _MSC_VER >= 1600 #define GTEST_USE_OWN_TR1_TUPLE 0 #else #define GTEST_USE_OWN_TR1_TUPLE 1 #endif #endif // GTEST_USE_OWN_TR1_TUPLE // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tr1/tuple. #if GTEST_HAS_TR1_TUPLE #if GTEST_USE_OWN_TR1_TUPLE #include #elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // use STLport's tuple implementation, which unfortunately doesn't // work as the copy of STLport distributed with Symbian is incomplete. // By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to // use its own tuple implementation. #ifdef BOOST_HAS_TR1_TUPLE #undef BOOST_HAS_TR1_TUPLE #endif // BOOST_HAS_TR1_TUPLE // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . #define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED #include #elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . #if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. #define _TR1_FUNCTIONAL 1 #include #undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. #else #include // NOLINT #endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 #else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. #include // NOLINT #endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. #if GTEST_OS_LINUX && !defined(__ia64__) #define GTEST_HAS_CLONE 1 #else #define GTEST_HAS_CLONE 0 #endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #define GTEST_HAS_STREAM_REDIRECTION_ 1 #endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX) #define GTEST_HAS_DEATH_TEST 1 #include // NOLINT #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore // all the compilers we care about are adequate for supporting // value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, and IBM Visual Age support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) #define GTEST_HAS_TYPED_TEST 1 #define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether to support Combine(). This only makes sense when // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. #if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) #define GTEST_HAS_COMBINE 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER #define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else #define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) #define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else #define GTEST_ATTRIBUTE_UNUSED_ #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type)\ void operator=(type const &) // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ type(type const &);\ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) #define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else #define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. #if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. #define GTEST_HAS_SEH 1 #else // Assume no SEH. #define GTEST_HAS_SEH 0 #endif #endif // GTEST_HAS_SEH #ifdef _MSC_VER #if GTEST_LINKED_AS_SHARED_LIBRARY #define GTEST_API_ __declspec(dllimport) #elif GTEST_CREATE_SHARED_LIBRARY #define GTEST_API_ __declspec(dllexport) #endif #endif // _MSC_VER #ifndef GTEST_API_ #define GTEST_API_ #endif namespace testing { class Message; namespace internal { class String; typedef ::std::stringstream StrStream; // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines scoped_ptr. // This implementation of scoped_ptr is PARTIAL - it only contains // enough stuff to satisfy Google Test's need. template class scoped_ptr { public: typedef T element_type; explicit scoped_ptr(T* p = NULL) : ptr_(p) {} ~scoped_ptr() { reset(); } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } T* release() { T* const ptr = ptr_; ptr_ = NULL; return ptr; } void reset(T* p = NULL) { if (p != ptr_) { if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. delete ptr_; } ptr_ = p; } } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT #if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT #endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true iff regular expression re matches // the entire str. // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // // TODO(wan@google.com): make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); // We use a const char* instead of a string, as Google Test may be used // where string is not available. We also do not use Google Test's own // String type here, in order to simplify dependencies between the // files. const char* pattern_; bool is_valid_; #if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). #else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); #endif GTEST_DISALLOW_ASSIGN_(RE); }; // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. #define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION_ // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ String GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ String GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector g_argvs; // GTEST_HAS_DEATH_TEST implies we have ::std::string. const ::std::vector& GetArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milli-seconds. This function is only for // testing Google Test's own constructs. Don't use it in user tests, // either directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, NULL); } // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) {} // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { notified_ = true; } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { while(!notified_) { SleepMilliseconds(10); } } private: volatile bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return NULL; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void (*UserThreadFunc)(T); ThreadWithParam( UserThreadFunc func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); finished_ = true; } } virtual void Run() { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); } private: const UserThreadFunc func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true iff we know that the thread function has finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. #include // MutexBase and Mutex implement mutex on pthreads-based platforms. They // are used in conjunction with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the end // // of the current scope. // // MutexBase implements behavior for both statically and dynamically // allocated mutexes. Do not use MutexBase directly. Instead, write // the following to define a static mutex: // // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // // You can forward declare a static mutex like this: // // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // To create a dynamic mutex, just define an object of type Mutex. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); } // Releases this mutex. void Unlock() { // We don't protect writing to owner_ here, as it's the caller's // responsibility to ensure that the current thread holds the // mutex when this is called. owner_ = 0; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(owner_ == pthread_self()) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. }; // Forward-declares a static mutex. #define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. #define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); owner_ = 0; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock as the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // An object managed for a thread by a ThreadLocal instance is deleted // when the thread exits. Or, if the ThreadLocal instance dies in // that thread, when the ThreadLocal dies. It's the user's // responsibility to ensure that all other threads using a ThreadLocal // have exited when it dies, or the per-thread objects for those // threads will not be deleted. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_() {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_(value) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = new ValueHolder(default_); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; const T default_; // The default value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; #define GTEST_IS_THREADSAFE 1 #else // GTEST_HAS_PTHREAD // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void AssertHeld() const {} }; #define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex #define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. #define GTEST_IS_THREADSAFE 0 #endif // GTEST_HAS_PTHREAD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). #define GTEST_ELLIPSIS_NEEDS_POD_ 1 #else #define GTEST_CAN_COMPARE_NULL 1 #endif // The Nokia Symbian and IBM XL C/C++ compilers cannot decide between // const T& and const T* in a function template. These compilers // _can_ decide between class template specializations for T and T*, // so a tr1::type_traits-like is_pointer works. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) #define GTEST_NEEDS_IS_POINTER_ 1 #endif template struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; #if GTEST_OS_WINDOWS #define GTEST_PATH_SEP_ "\\" #define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else #define GTEST_PATH_SEP_ "/" #define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; #ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } #else // !__BORLANDC__ #if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } #else inline int IsATTY(int fd) { return _isatty(fd); } #endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } #endif // __BORLANDC__ #if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. #else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } #endif // GTEST_OS_WINDOWS_MOBILE #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. #ifdef _MSC_VER // Temporarily disable warning 4996 (deprecated function). #pragma warning(push) #pragma warning(disable:4996) #endif inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); } // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != NULL && env[0] != '\0') ? env : NULL; #else return getenv(name); #endif } #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. void Abort(); #else inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name // Macros for declaring flags. #define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) #define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) #define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. // TODO(chandlerc): Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-internal.h0000664000175100017510000010531412623076744026314 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #include #if GTEST_OS_LINUX #include #include #include #include #endif // GTEST_OS_LINUX #include #include #include #include #include #include #include #include // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar // Google Test defines the testing::Message class to allow construction of // test messages via the << operator. The idea is that anything // streamable to std::ostream can be streamed to a testing::Message. // This allows a user to use his own types in Google Test assertions by // overloading the << operator. // // util/gtl/stl_logging-inl.h overloads << for STL containers. These // overloads cannot be defined in the std namespace, as that will be // undefined behavior. Therefore, they are defined in the global // namespace instead. // // C++'s symbol lookup rule (i.e. Koenig lookup) says that these // overloads are visible in either the std namespace or the global // namespace, but not other namespaces, including the testing // namespace which Google Test's Message class is in. // // To allow STL containers (and other types that has a << operator // defined in the global namespace) to be used in Google Test assertions, // testing::Message must access the custom << operator from the global // namespace. Hence this helper function. // // Note: Jeffrey Yasskin suggested an alternative fix by "using // ::operator<<;" in the definition of Message's operator<<. That fix // doesn't require a helper function, but unfortunately doesn't // compile with MSVC. template inline void GTestStreamToHelper(std::ostream* os, const T& val) { *os << val; } namespace testing { // Forward declaration of classes. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test cases. namespace internal { struct TraceInfo; // Information about a trace point. class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // How many times InitGoogleTest() has been called. extern int g_init_gtest_count; // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). Their return values have // different sizes, so we can use sizeof() to test which version is // picked by the compiler. These helpers have no implementations, as // we only need their signatures. // // Given IsNullLiteralHelper(x), the compiler will pick the first // version if x can be implicitly converted to Secret*, and pick the // second version otherwise. Since Secret is a secret and incomplete // type, the only expression a user can write that has type Secret* is // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. char IsNullLiteralHelper(Secret* p); char (&IsNullLiteralHelper(...))[2]; // NOLINT // A compile-time bool constant that is true if and only if x is a // null pointer literal (i.e. NULL or any 0-valued compile-time // integral constant). #ifdef GTEST_ELLIPSIS_NEEDS_POD_ // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). #define GTEST_IS_NULL_LITERAL_(x) false #else #define GTEST_IS_NULL_LITERAL_(x) \ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) #endif // GTEST_ELLIPSIS_NEEDS_POD_ // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ String AppendUserMessage(const String& gtest_msg, const Message& user_msg); // A helper class for creating scoped traces in user programs. class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. ScopedTrace(const char* file, int line, const Message& message); // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". // Declared here but defined in gtest.h, so that it has access // to the definition of the Message class, required by the ARM // compiler. template String StreamableToString(const T& streamable); // Formats a value to be used in a failure message. #ifdef GTEST_NEEDS_IS_POINTER_ // These are needed as the Nokia Symbian and IBM XL C/C++ compilers // cannot decide between const T& and const T* in a function template. // These compilers _can_ decide between class template specializations // for T and T*, so a tr1::type_traits-like is_pointer works, and we // can overload on that. // This overload makes sure that all pointers (including // those to char or wchar_t) are printed as raw pointers. template inline String FormatValueForFailureMessage(internal::true_type /*dummy*/, T* pointer) { return StreamableToString(static_cast(pointer)); } template inline String FormatValueForFailureMessage(internal::false_type /*dummy*/, const T& value) { return StreamableToString(value); } template inline String FormatForFailureMessage(const T& value) { return FormatValueForFailureMessage( typename internal::is_pointer::type(), value); } #else // These are needed as the above solution using is_pointer has the // limitation that T cannot be a type without external linkage, when // compiled using MSVC. template inline String FormatForFailureMessage(const T& value) { return StreamableToString(value); } // This overload makes sure that all pointers (including // those to char or wchar_t) are printed as raw pointers. template inline String FormatForFailureMessage(T* pointer) { return StreamableToString(static_cast(pointer)); } #endif // GTEST_NEEDS_IS_POINTER_ // These overloaded versions handle narrow and wide characters. GTEST_API_ String FormatForFailureMessage(char ch); GTEST_API_ String FormatForFailureMessage(wchar_t wchar); // When this operand is a const char* or char*, and the other operand // is a ::std::string or ::string, we print this operand as a C string // rather than a pointer. We do the same for wide strings. // This internal macro is used to avoid duplicated code. #define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ inline String FormatForComparisonFailureMessage(\ operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ return operand1_printer(str);\ }\ inline String FormatForComparisonFailureMessage(\ const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ return operand1_printer(str);\ } GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) #if GTEST_HAS_STD_WSTRING GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_STRING GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) #endif // GTEST_HAS_GLOBAL_WSTRING #undef GTEST_FORMAT_IMPL_ // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const String& expected_value, const String& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ String GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8*sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true iff this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true iff this number is at most kMaxUlps ULP's away from // rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test case, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: virtual Test* CreateTest() { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Formats a source file path and a line number as they would appear // in a compiler error message. inline String FormatFileLocation(const char* file, int line) { const char* const file_name = file == NULL ? "unknown file" : file; if (line < 0) { return String::Format("%s:", file_name); } #ifdef _MSC_VER return String::Format("%s(%d):", file_name, line); #else return String::Format("%s:%d:", file_name, line); #endif // _MSC_VER } // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // test_case_comment: a comment on the test case that will be included in // the test output // comment: a comment on the test that will be included in the // test output // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: TypedTestCasePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test case hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } defined_test_names_.insert(test_name); return true; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: bool registered_; ::std::set defined_test_names_; }; // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == NULL) { return NULL; } while (isspace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline String GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? String(str) : String(str, comma - str); } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", case_name, index).c_str(), GetPrefixUntilComma(test_names).c_str(), String::Format("TypeParam = %s", GetTypeName().c_str()).c_str(), "", GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, const char* case_name, const char* test_names) { typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_(message, result_type) \ ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \ = ::testing::Message() #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) // Suppresses MSVC warnings 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg = "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different " \ "type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg = "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_msg) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail(gtest_msg) #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ gtest_msg = "Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail(gtest_msg) // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const char* gtest_msg = "") { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ gtest_msg = "Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail(gtest_msg) // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ test_case_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ public:\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ private:\ virtual void TestBody();\ static ::testing::TestInfo* const test_info_;\ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ };\ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ ::test_info_ =\ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, "", "", \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ new ::testing::internal::TestFactoryImpl<\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-death-test-internal.h0000664000175100017510000002703612623076744030360 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #include namespace testing { namespace internal { GTEST_DECLARE_string_(internal_run_death_test); // Names of the flags (needed for parsing Google Test flags). const char kDeathTestStyleFlag[] = "death_test_style"; const char kDeathTestUseFork[] = "death_test_use_fork"; const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test // style, as defined by the --gtest_death_test_style and/or // --gtest_internal_run_death_test flags. // In describing the results of death tests, these terms are used with // the corresponding definitions: // // exit status: The integer exit information in the format specified // by wait(2) // exit code: The integer code passed to exit(3), _exit(2), or // returned from main() class GTEST_API_ DeathTest { public: // Create returns false if there was an error determining the // appropriate action to take for the current death test; for example, // if the gtest_death_test_style flag is set to an invalid value. // The LastMessage method will return a more detailed message in that // case. Otherwise, the DeathTest pointer pointed to by the "test" // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } // A helper class that aborts a death test when it's deleted. class ReturnSentinel { public: explicit ReturnSentinel(DeathTest* test) : test_(test) { } ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } private: DeathTest* const test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); } GTEST_ATTRIBUTE_UNUSED_; // An enumeration of possible roles that may be taken when a death // test is encountered. EXECUTE means that the death test logic should // be executed immediately. OVERSEE means that the program should prepare // the appropriate environment for a child process to execute the death // test, then wait for it to complete. enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; // An enumeration of the two reasons that a test might be aborted. enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE }; // Assumes one of the above roles. virtual TestRole AssumeRole() = 0; // Waits for the death test to finish and returns its status. virtual int Wait() = 0; // Returns true if the death test passed; that is, the test process // exited during the test, its exit status matches a user-supplied // predicate, and its stderr output matches a user-supplied regular // expression. // The user-supplied predicate may be a macro expression rather // than a function pointer or functor, or else Wait and Passed could // be combined. virtual bool Passed(bool exit_status_ok) = 0; // Signals that the death test did not die as expected. virtual void Abort(AbortReason reason) = 0; // Returns a human-readable outcome message regarding the outcome of // the last death test. static const char* LastMessage(); static void set_last_death_test_message(const String& message); private: // A string containing a description of the outcome of the last death test. static String last_death_test_message_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. #define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ const ::testing::internal::RE& gtest_regex = (regex); \ ::testing::internal::DeathTest* gtest_dt; \ if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ __FILE__, __LINE__, >est_dt)) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ if (gtest_dt != NULL) { \ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ gtest_dt_ptr(gtest_dt); \ switch (gtest_dt->AssumeRole()) { \ case ::testing::internal::DeathTest::OVERSEE_TEST: \ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ break; \ case ::testing::internal::DeathTest::EXECUTE_TEST: { \ ::testing::internal::DeathTest::ReturnSentinel \ gtest_sentinel(gtest_dt); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ break; \ } \ } \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // A class representing the parsed contents of the // --gtest_internal_run_death_test flag, as it existed when // RUN_ALL_TESTS was called. class InternalRunDeathTestFlag { public: InternalRunDeathTestFlag(const String& a_file, int a_line, int an_index, int a_write_fd) : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} ~InternalRunDeathTestFlag() { if (write_fd_ >= 0) posix::Close(write_fd_); } String file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } private: String file_; int line_; int index_; int write_fd_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); }; // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); #else // GTEST_HAS_DEATH_TEST // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems // iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on // systems that support death tests. This allows one to write such a macro // on a system that does not support death tests and be sure that it will // compile on a death-test supporting system. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain // parameter iff EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that // this macro only accepts expressions that a macro such as // EXPECT_DEATH would accept. // terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED // and a return statement for ASSERT_DEATH_IF_SUPPORTED. // This ensures that ASSERT_DEATH_IF_SUPPORTED will not // compile inside functions where ASSERT_DEATH doesn't // compile. // // The branch that has an always false condition is used to ensure that // statement and regex are compiled (and thus syntactically correct) but // never executed. The unreachable code macro protects the terminator // statement from generating an 'unreachable code' warning in case // statement unconditionally returns or throws. The Message constructor at // the end allows the syntax of streaming additional messages into the // macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. #define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_LOG_(WARNING) \ << "Death tests are not supported on this platform.\n" \ << "Statement '" #statement "' cannot be verified."; \ } else if (::testing::internal::AlwaysFalse()) { \ ::testing::internal::RE::PartialMatch(".*", (regex)); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ terminator; \ } else \ ::testing::Message() #endif // GTEST_HAS_DEATH_TEST } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-string.h0000664000175100017510000003241112623076744026003 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // // This header file is #included by . // It should not be #included by other files. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. #include #endif #include #include #include namespace testing { namespace internal { // String - a UTF-8 string class. // // For historic reasons, we don't use std::string. // // TODO(wan@google.com): replace this class with std::string or // implement it in terms of the latter. // // Note that String can represent both NULL and the empty string, // while std::string cannot represent NULL. // // NULL and the empty string are considered different. NULL is less // than anything (including the empty string) except itself. // // This class only provides minimum functionality necessary for // implementing Google Test. We do not intend to implement a full-fledged // string class here. // // Since the purpose of this class is to provide a substitute for // std::string on platforms where it cannot be used, we define a copy // constructor and assignment operators such that we don't need // conditional compilation in a lot of places. // // In order to make the representation efficient, the d'tor of String // is not virtual. Therefore DO NOT INHERIT FROM String. class GTEST_API_ String { public: // Static utility methods // Returns the input enclosed in double quotes if it's not NULL; // otherwise returns "(null)". For example, "\"Hello\"" is returned // for input "Hello". // // This is useful for printing a C string in the syntax of a literal. // // Known issue: escape sequences are not handled yet. static String ShowCStringQuoted(const char* c_str); // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting the return value using // delete[]. Returns the cloned string, or NULL if the input is // NULL. // // This is different from strdup() in string.h, which allocates // memory using malloc(). static const char* CloneCString(const char* c_str); #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be // able to pass strings to Win32 APIs on CE we need to convert them // to 'Unicode', UTF-16. // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. // // The wide string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static LPCWSTR AnsiToUtf16(const char* c_str); // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. // // The returned string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CStringEquals(const char* lhs, const char* rhs); // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". If an error occurred during // the conversion, "(failed to convert from wide string)" is // returned. static String ShowWideCString(const wchar_t* wide_c_str); // Similar to ShowWideCString(), except that this function encloses // the converted string in double quotes. static String ShowWideCStringQuoted(const wchar_t* wide_c_str); // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Compares two C strings, ignoring case. Returns true iff they // have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Formats a list of arguments to a String, using the same format // spec string as for printf. // // We do not use the StringPrintf class as it is not universally // available. // // The result is limited to 4096 characters (including the tailing // 0). If 4096 characters are not enough to format the input, // "" is returned. static String Format(const char* format, ...); // C'tors // The default c'tor constructs a NULL string. String() : c_str_(NULL), length_(0) {} // Constructs a String by cloning a 0-terminated C string. String(const char* a_c_str) { // NOLINT if (a_c_str == NULL) { c_str_ = NULL; length_ = 0; } else { ConstructNonNull(a_c_str, strlen(a_c_str)); } } // Constructs a String by copying a given number of chars from a // buffer. E.g. String("hello", 3) creates the string "hel", // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", // and String(NULL, 1) results in access violation. String(const char* buffer, size_t a_length) { ConstructNonNull(buffer, a_length); } // The copy c'tor creates a new copy of the string. The two // String objects do not share content. String(const String& str) : c_str_(NULL), length_(0) { *this = str; } // D'tor. String is intended to be a final class, so the d'tor // doesn't need to be virtual. ~String() { delete[] c_str_; } // Allows a String to be implicitly converted to an ::std::string or // ::string, and vice versa. Converting a String containing a NULL // pointer to ::std::string or ::string is undefined behavior. // Converting a ::std::string or ::string containing an embedded NUL // character to a String will result in the prefix up to the first // NUL character. String(const ::std::string& str) { ConstructNonNull(str.c_str(), str.length()); } operator ::std::string() const { return ::std::string(c_str(), length()); } #if GTEST_HAS_GLOBAL_STRING String(const ::string& str) { ConstructNonNull(str.c_str(), str.length()); } operator ::string() const { return ::string(c_str(), length()); } #endif // GTEST_HAS_GLOBAL_STRING // Returns true iff this is an empty string (i.e. ""). bool empty() const { return (c_str() != NULL) && (length() == 0); } // Compares this with another String. // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 // if this is greater than rhs. int Compare(const String& rhs) const; // Returns true iff this String equals the given C string. A NULL // string and a non-NULL string are considered not equal. bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } // Returns true iff this String is less than the given String. A // NULL string is considered less than "". bool operator<(const String& rhs) const { return Compare(rhs) < 0; } // Returns true iff this String doesn't equal the given C string. A NULL // string and a non-NULL string are considered not equal. bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } // Returns true iff this String ends with the given suffix. *Any* // String is considered to end with a NULL or empty suffix. bool EndsWith(const char* suffix) const; // Returns true iff this String ends with the given suffix, not considering // case. Any String is considered to end with a NULL or empty suffix. bool EndsWithCaseInsensitive(const char* suffix) const; // Returns the length of the encapsulated string, or 0 if the // string is NULL. size_t length() const { return length_; } // Gets the 0-terminated C string this String object represents. // The String object still owns the string. Therefore the caller // should NOT delete the return value. const char* c_str() const { return c_str_; } // Assigns a C string to this object. Self-assignment works. const String& operator=(const char* a_c_str) { return *this = String(a_c_str); } // Assigns a String object to this object. Self-assignment works. const String& operator=(const String& rhs) { if (this != &rhs) { delete[] c_str_; if (rhs.c_str() == NULL) { c_str_ = NULL; length_ = 0; } else { ConstructNonNull(rhs.c_str(), rhs.length()); } } return *this; } private: // Constructs a non-NULL String from the given content. This // function can only be called when data_ has not been allocated. // ConstructNonNull(NULL, 0) results in an empty string (""). // ConstructNonNull(NULL, non_zero) is undefined behavior. void ConstructNonNull(const char* buffer, size_t a_length) { char* const str = new char[a_length + 1]; memcpy(str, buffer, a_length); str[a_length] = '\0'; c_str_ = str; length_ = a_length; } const char* c_str_; size_t length_; }; // class String // Streams a String to an ostream. Each '\0' character in the String // is replaced with "\\0". inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { if (str.c_str() == NULL) { os << "(null)"; } else { const char* const c_str = str.c_str(); for (size_t i = 0; i != str.length(); i++) { if (c_str[i] == '\0') { os << "\\0"; } else { os << c_str[i]; } } } return os; } // Gets the content of the StrStream's buffer as a String. Each '\0' // character in the buffer is replaced with "\\0". GTEST_API_ String StrStreamToString(StrStream* stream); // Converts a streamable value to a String. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". // Declared here but defined in gtest.h, so that it has access // to the definition of the Message class, required by the ARM // compiler. template String StreamableToString(const T& streamable); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-param-util-generated.h.pump0000664000175100017510000002226412623076744031471 0ustar jenkins-buildjenkins-build$$ -*- mode: c++; -*- $var n = 50 $$ Maximum length of Values arguments we want to support. $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most $n arguments in Values, // and at most $maxtuple arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at $maxtuple. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include #include #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::std::iterator_traits::value_type> ValuesIn( ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; $range i 2..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> class ValueArray$i { public: ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} template operator ParamGenerator() const { const T array[] = {$for j, [[v$(j)_]]}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray$i& other); $for j [[ const T$j v$(j)_; ]] }; ]] #if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // $range i 2..maxtuple $for i [[ $range j 1..i $range k 2..i template <$for j, [[typename T$j]]> class CartesianProductGenerator$i : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { public: typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} virtual ~CartesianProductGenerator$i() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); } virtual ParamIteratorInterface* End() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, $for j, [[ const ParamGenerator& g$j, const typename ParamGenerator::iterator& current$(j)]]) : base_(base), $for j, [[ begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j) ]] { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current$(i)_; $for k [[ if (current$(i+2-k)_ == end$(i+2-k)_) { current$(i+2-k)_ = begin$(i+2-k)_; ++current$(i+2-k-1)_; } ]] ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ($for j && [[ current$(j)_ == typed_other->current$(j)_ ]]); } private: Iterator(const Iterator& other) : base_(other.base_), $for j, [[ begin$(j)_(other.begin$(j)_), end$(j)_(other.end$(j)_), current$(j)_(other.current$(j)_) ]] { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType($for j, [[*current$(j)_]]); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return $for j || [[ current$(j)_ == end$(j)_ ]]; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. $for j [[ const typename ParamGenerator::iterator begin$(j)_; const typename ParamGenerator::iterator end$(j)_; typename ParamGenerator::iterator current$(j)_; ]] ParamType current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator$i& other); $for j [[ const ParamGenerator g$(j)_; ]] }; // class CartesianProductGenerator$i ]] // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // $range i 2..maxtuple $for i [[ $range j 1..i template <$for j, [[class Generator$j]]> class CartesianProductHolder$i { public: CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) : $for j, [[g$(j)_(g$j)]] {} template <$for j, [[typename T$j]]> operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ static_cast >(g$(j)_) ]])); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder$i& other); $for j [[ const Generator$j g$(j)_; ]] }; // class CartesianProductHolder$i ]] #endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ ceph-0.80.11/src/gtest/include/gtest/internal/gtest-type-util.h.pump0000664000175100017510000002146712623076744027422 0ustar jenkins-buildjenkins-build$$ -*- mode: c++; -*- $var n = 50 $$ Maximum length of type lists we want to support. // Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most $n types in a list, and at most $n // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #include #include #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). #ifdef __GLIBCXX__ #include #endif // __GLIBCXX__ namespace testing { namespace internal { // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // GetTypeName() returns a human-readable name of type T. template String GetTypeName() { #if GTEST_HAS_RTTI const char* const name = typeid(T).name(); #ifdef __GLIBCXX__ int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status); const String name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; #else return name; #endif // __GLIBCXX__ #else return ""; #endif // GTEST_HAS_RTTI } // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; $range i 2..n $for i [[ $range j 1..i $range k 2..i template <$for j, [[typename T$j]]> struct Types$i { typedef T1 Head; typedef Types$(i-1)<$for k, [[T$k]]> Tail; }; ]] } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. $range i 1..n template <$for i, [[typename T$i = internal::None]]> struct Types { typedef internal::Types$n<$for i, [[T$i]]> type; }; template <> struct Types<$for i, [[internal::None]]> { typedef internal::Types0 type; }; $range i 1..n-1 $for i [[ $range j 1..i $range k i+1..n template <$for j, [[typename T$j]]> struct Types<$for j, [[T$j]]$for k[[, internal::None]]> { typedef internal::Types$i<$for j, [[T$j]]> type; }; ]] namespace internal { #define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; #define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; $range i 2..n $for i [[ $range j 1..i $range k 2..i template <$for j, [[GTEST_TEMPLATE_ T$j]]> struct Templates$i { typedef TemplateSel Head; typedef Templates$(i-1)<$for k, [[T$k]]> Tail; }; ]] // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. $range i 1..n template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]> struct Templates { typedef Templates$n<$for i, [[T$i]]> type; }; template <> struct Templates<$for i, [[NoneT]]> { typedef Templates0 type; }; $range i 1..n-1 $for i [[ $range j 1..i $range k i+1..n template <$for j, [[GTEST_TEMPLATE_ T$j]]> struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { typedef Templates$i<$for j, [[T$j]]> type; }; ]] // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; $range i 1..n template <$for i, [[typename T$i]]> struct TypeList > { typedef typename Types<$for i, [[T$i]]>::type type; }; } // namespace internal } // namespace testing #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ ceph-0.80.11/src/gtest/src/0000775000175100017510000000000012623077036017374 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/src/gtest-death-test.cc0000664000175100017510000012652312623076744023107 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. #include #include #if GTEST_HAS_DEATH_TEST #if GTEST_OS_MAC #include #endif // GTEST_OS_MAC #include #include #include #include #if GTEST_OS_WINDOWS #include #else #include #include #endif // GTEST_OS_WINDOWS #endif // GTEST_HAS_DEATH_TEST #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "colons. This flag is specified if and only if the current " "process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { #if GTEST_OS_WINDOWS return exit_status == exit_code_; #else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; #endif // GTEST_OS_WINDOWS } #if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } #endif // !GTEST_OS_WINDOWS namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static String ExitSummary(int exit_code) { Message m; #if GTEST_OS_WINDOWS m << "Exited with exit status " << exit_code; #else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } #ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } #endif #endif // GTEST_OS_WINDOWS return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } #if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static String DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else msg << "detected " << thread_count << " threads."; return msg.GetString(); } #endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestInternalError = 'I'; // An enumeration describing all of the possible ways that a death test // can conclude. DIED means that the process died while executing the // test code; LIVED means that process lived beyond the end of the test // code; and RETURNED means that the test statement attempted a "return," // which is not allowed. IN_PROGRESS means the test has not yet // concluded. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. void DeathTestAbort(const String& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. #define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s", \ __FILE__, __LINE__, #expression)); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. #define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort(::testing::internal::String::Format( \ "CHECK failed: File %s, line %d: %s != -1", \ __FILE__, __LINE__, #expression)); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. String GetLastErrnoDescription() { return String(errno == 0 ? "" : posix::StrError(errno)); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == NULL) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, regex, file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const String& message) { last_death_test_message_ = message; } String DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, const RE* a_regex) : statement_(a_statement), regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // The regular expression which test output must match. DeathTestImpl // doesn't own this object and should not attempt to delete it. const RE* const regex_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, or RETURNED. The death test fails // in the latter two cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // regex: A regular expression object to be applied to // the test's captured standard error output; the death test // fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const String error_message = GetCapturedStderr(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg: " << error_message; break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg: " << error_message; break; case DIED: if (status_ok) { const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" << "Actual msg: " << error_message; } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n"; } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } #if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* statement, const RE* regex, const char* file, int line) : DeathTestImpl(statement, regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status; GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) != FALSE); child_handle_.Reset(); set_status(static_cast(status)); return this->status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); const String filter_flag = String::Format("--%s%s=%s.%s", GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); const String internal_flag = String::Format( "--%s%s=%s|%d|%d|%u|%Iu|%Iu", GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, static_cast(::GetCurrentProcessId()), // size_t has the same with as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. reinterpret_cast(write_handle), reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); String command_line = String::Format("%s %s \"%s\"", ::GetCommandLineA(), filter_flag.c_str(), internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_(::CreateProcessA( executable_path, const_cast(command_line.c_str()), NULL, // Retuned process handle is not inheritable. NULL, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } #else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(NULL); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; #if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } #else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } #endif // GTEST_OS_MAC // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", original_dir, GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", args->argv[0], original_dir, GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. bool StackLowerThanAddress(const void* ptr) { int dummy; return &dummy < ptr; } bool StackGrowsDown() { int dummy; return StackLowerThanAddress(&dummy); } // A threadsafe implementation of fork(2) for threadsafe-style death tests // that uses clone(2). It dies with an error message if anything goes // wrong. static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; #if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const size_t stack_size = getpagesize(); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size : 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } #else const bool use_fork = true; #endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const String filter_flag = String::Format("--%s%s=%s.%s", GTEST_FLAG_PREFIX_, kFilterFlag, info->test_case_name(), info->name()); const String internal_flag = String::Format("--%s%s=%s|%d|%d|%d", GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, file_, line_, death_test_index, pipe_fd[1]); Arguments args; args.AddArguments(GetArgvs()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } #endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != NULL) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message(String::Format( "Death test count (%d) somehow exceeded expected maximum (%d)", death_test_index, flag->index())); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = NULL; return true; } } #if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } #else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } #endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message(String::Format( "Unknown death test style \"%s\" encountered", GTEST_FLAG(death_test_style).c_str())); return false; } return true; } // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } #if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort(String::Format("Unable to open parent process %u", parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort(String::Format( "Unable to duplicate the pipe handle %Iu from the parent process %u", write_handle_as_size_t, parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort(String::Format( "Unable to duplicate the event handle %Iu from the parent process %u", event_handle_as_size_t, parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort(String::Format( "Unable to convert pipe handle %Iu to a file descriptor", write_handle_as_size_t)); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } #endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; #if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort(String::Format( "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); #else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort(String::Format( "Bad --gtest_internal_run_death_test flag: %s", GTEST_FLAG(internal_run_death_test).c_str())); } #endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing ceph-0.80.11/src/gtest/src/gtest_main.cc0000664000175100017510000000334112623076744022043 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. #include #include int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/src/gtest-internal-inl.h0000664000175100017510000012166012623076744023300 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // Utility functions and classes used by the Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. #error "gtest-internal-inl.h is part of Google Test's internal implementation." #error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE #include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #include #if GTEST_OS_WINDOWS #include // For DWORD. #endif // GTEST_OS_WINDOWS #include // NOLINT #include namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true iff Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; String color_; String death_test_style_; bool death_test_use_fork_; String filter_; String internal_run_death_test_; bool list_tests_; String output_; bool print_time_; bool pretty_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // The output buffer str must containt at least 32 characters. // The function returns the address of the output buffer. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output // as '(Invalid Unicode 0xXXXXXXXX)'. GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { return static_cast(std::count_if(c.begin(), c.end(), predicate)); } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + random->Generate(range_width); std::swap((*v)[selected], (*v)[last_in_range]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const char* key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return String(test_property.key()).Compare(key_) == 0; } private: String key_; }; class TestInfoImpl { public: TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, TypeId fixture_class_id, internal::TestFactoryBase* factory); ~TestInfoImpl(); // Returns true if this test should run. bool should_run() const { return should_run_; } // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Returns true if this test is disabled. Disabled tests are not run. bool is_disabled() const { return is_disabled_; } // Sets the is_disabled member. void set_is_disabled(bool is) { is_disabled_ = is; } // Returns true if this test matches the filter specified by the user. bool matches_filter() const { return matches_filter_; } // Sets the matches_filter member. void set_matches_filter(bool matches) { matches_filter_ = matches; } // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the test case comment. const char* test_case_comment() const { return test_case_comment_.c_str(); } // Returns the test comment. const char* comment() const { return comment_.c_str(); } // Returns the ID of the test fixture class. TypeId fixture_class_id() const { return fixture_class_id_; } // Returns the test result. TestResult* result() { return &result_; } const TestResult* result() const { return &result_; } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); // Clears the test result. void ClearResult() { result_.Clear(); } // Clears the test result in the given TestInfo object. static void ClearTestResult(TestInfo * test_info) { test_info->impl()->ClearResult(); } private: // These fields are immutable properties of the test. TestInfo* const parent_; // The owner of this object const String test_case_name_; // Test case name const String name_; // Test name const String test_case_comment_; // Test case comment const String comment_; // Test comment const TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static String GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static String GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true iff the user-specified filter matches the test case // name and the test name. static bool FilterMatchesTest(const String &test_case_name, const String &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const String& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as a String. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} virtual String CurrentStackTrace(int max_depth, int skip_count); virtual void UponLeavingGTest(); // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: Mutex mutex_; // protects all internal state // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; String message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const { return !Failed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. String CurrentOsStackTraceExceptTop(int skip_count); // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_case_name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo * test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), test_info->test_case_comment(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has // guards protecting from registering the tests more then once. // If value-parameterized tests are disabled, RegisterParameterizedTests // is present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns 0 if all tests are successful, or 1 otherwise. If any // exception is thrown during a test on Windows, this test is // considered to be failed, but the rest of the tests will still be // run. (We disable exceptions on Linux and Mac OS X, so the issue // doesn't apply there.) int RunAllTests(); // Clears the results of all tests, including the ad hoc test. void ClearResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); ad_hoc_test_result_.Clear(); } enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); private: friend class ::testing::UnitTest; // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True iff PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsDigit(char ch); GTEST_API_ bool IsPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsWhiteSpace(char ch); GTEST_API_ bool IsWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. String GetLastErrnoDescription(); #if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} explicit AutoHandle(HANDLE handle) : handle_(handle) {} ~AutoHandle() { Reset(); } HANDLE Get() const { return handle_; } void Reset() { Reset(INVALID_HANDLE_VALUE); } void Reset(HANDLE handle) { if (handle != handle_) { if (handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(handle_); handle_ = handle; } } private: HANDLE handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; #endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !isdigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. #if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); #else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); #endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const TestProperty& property) { test_result->RecordProperty(property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ ceph-0.80.11/src/gtest/src/gtest-test-part.cc0000664000175100017510000001014512623076744022760 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // // The Google C++ Testing Framework (Google Test) #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace testing { using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. internal::String TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); return stack_trace == NULL ? internal::String(message) : internal::String(message, stack_trace - message); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { return os << result.file_name() << ":" << result.line_number() << ": " << (result.type() == TestPartResult::kSuccess ? "Success" : result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : "Non-fatal failure") << ":\n" << result.message() << std::endl; } // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); internal::posix::Abort(); } return array_[index]; } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { return static_cast(array_.size()); } namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } void HasNewFatalFailureHelper::ReportTestPartResult( const TestPartResult& result) { if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/src/gtest-port.cc0000664000175100017510000005672512623076744022037 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include #include #include #if GTEST_OS_WINDOWS_MOBILE #include // For TerminateProcess() #elif GTEST_OS_WINDOWS #include #include #else #include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC #include #include #include #endif // GTEST_OS_MAC #include #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; thread_act_array_t thread_list; const kern_return_t status = task_threads(task, &thread_list, &thread_count); if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { return 0; } } #else size_t GetThreadCount() { // There's no portable way to detect the number of threads, so we just // return 0 to indicate that we cannot detect it. return 0; } #endif // GTEST_OS_MAC #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. RE::~RE() { if (is_valid_) { // regfree'ing an invalid regex might crash because the content // of the regex is undefined. Since the regex's are essentially // the same, one cannot be valid (or invalid) without the other // being so too. regfree(&partial_regex_); regfree(&full_regex_); } free(const_cast(pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. const size_t full_regex_len = strlen(regex) + 10; char* const full_pattern = new char[full_regex_len]; snprintf(full_pattern, full_regex_len, "^(%s)$", regex); is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; // We want to call regcomp(&partial_regex_, ...) even if the // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. // // Some implementation of POSIX regex (e.g. on at least some // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. if (is_valid_) { const char* const partial_regex = (*regex == '\0') ? "()" : regex; is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; } EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; delete[] full_pattern; } #elif GTEST_USES_SIMPLE_RE // Returns true iff ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { return ch != '\0' && strchr(str, ch) != NULL; } // Returns true iff ch belongs to the given classification. Unlike // similar functions in , these aren't affected by the // current locale. bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true iff "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true iff the given atom (specified by escaped and pattern) // matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { case 'd': return IsDigit(ch); case 'D': return !IsDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; case 's': return IsWhiteSpace(ch); case 'S': return !IsWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; case 'w': return IsWordChar(ch); case 'W': return !IsWordChar(ch); } return IsPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; } // Helper function used by ValidateRegex() to format error messages. String FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { // TODO(wan@google.com): fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; // True iff ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence i++; if (regex[i] == '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "'\\' cannot appear at the end."; return false; } if (!IsValidEscape(regex[i])) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "invalid escape sequence \"\\" << regex[i] << "\"."; is_valid = false; } prev_repeatable = true; } else { // Not an escape sequence. const char ch = regex[i]; if (ch == '^' && i > 0) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'^' can only appear at the beginning."; is_valid = false; } else if (ch == '$' && regex[i + 1] != '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'$' can only appear at the end."; is_valid = false; } else if (IsInSet(ch, "()[]{}|")) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' is unsupported."; is_valid = false; } else if (IsRepeat(ch) && !prev_repeatable) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' can only follow a repeatable token."; is_valid = false; } prev_repeatable = !IsInSet(ch, "^$?*+"); } } return is_valid; } // Matches a repeated regex atom followed by a valid simple regular // expression. The regex atom is defined as c if escaped is false, // or \c otherwise. repeat is the repetition meta character (?, *, // or +). The behavior is undefined if str contains too many // characters to be indexable by size_t, in which case the test will // probably time out anyway. We are fine with this limitation as // std::string has it too. bool MatchRepetitionAndRegexAtHead( bool escaped, char c, char repeat, const char* regex, const char* str) { const size_t min_count = (repeat == '+') ? 1 : 0; const size_t max_count = (repeat == '?') ? 1 : static_cast(-1) - 1; // We cannot call numeric_limits::max() as it conflicts with the // max() macro on Windows. for (size_t i = 0; i <= max_count; ++i) { // We know that the atom matches each of the first i characters in str. if (i >= min_count && MatchRegexAtHead(regex, str + i)) { // We have enough matches at the head, and the tail matches too. // Since we only care about *whether* the pattern matches str // (as opposed to *how* it matches), there is no need to find a // greedy match. return true; } if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) return false; } return false; } // Returns true iff regex matches a prefix of str. regex must be a // valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. return true; // "$" only matches the end of a string. Note that regex being // valid guarantees that there's nothing after "$" in it. if (*regex == '$') return *str == '\0'; // Is the first thing in regex an escape sequence? const bool escaped = *regex == '\\'; if (escaped) ++regex; if (IsRepeat(regex[1])) { // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so // here's an indirect recursion. It terminates as the regex gets // shorter in each recursion. return MatchRepetitionAndRegexAtHead( escaped, regex[0], regex[1], regex + 2, str); } else { // regex isn't empty, isn't "$", and doesn't start with a // repetition. We match the first atom of regex with the first // character of str and recurse. return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && MatchRegexAtHead(regex + 1, str + 1); } } // Returns true iff regex matches any substring of str. regex must be // a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of // stack space normally. In rare cases the time complexity can be // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { if (regex == NULL || str == NULL) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); // A successful match can be anywhere in str. do { if (MatchRegexAtHead(regex, str)) return true; } while (*str++ != '\0'); return false; } // Implements the RE class. RE::~RE() { free(const_cast(pattern_)); free(const_cast(full_pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { pattern_ = posix::StrDup(regex); } is_valid_ = ValidateRegex(regex); if (!is_valid_) { // No need to calculate the full pattern when the regex is invalid. return; } const size_t len = strlen(regex); // Reserves enough bytes to hold the regular expression used for a // full match: we need space to prepend a '^', append a '$', and // terminate the string with '\0'. char* buffer = static_cast(malloc(len + 3)); full_pattern_ = buffer; if (*regex != '^') *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. // We don't use snprintf or strncpy, as they trigger a warning when // compiled with VC++ 8.0. memcpy(buffer, regex, len); buffer += len; if (len == 0 || regex[len - 1] != '$') *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. *buffer = '\0'; } #endif // GTEST_USES_POSIX_RE GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = severity == GTEST_INFO ? "[ INFO ]" : severity == GTEST_WARNING ? "[WARNING]" : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; GetStream() << ::std::endl << marker << " " << FormatFileLocation(file, line).c_str() << ": "; } // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. GTestLog::~GTestLog() { GetStream() << ::std::endl; if (severity_ == GTEST_FATAL) { fflush(stderr); posix::Abort(); } } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4996) #endif // _MSC_VER #if GTEST_HAS_STREAM_REDIRECTION_ // Object that captures an output stream (stdout/stderr). class CapturedStream { public: // The ctor redirects the stream to a temporary file. CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { #if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); const UINT success = ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, // Generate unique file name. temp_file_path); GTEST_CHECK_(success != 0) << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; #else // There's no guarantee that a test has write access to the // current directory, so we create the temporary file in the /tmp // directory instead. char name_template[] = "/tmp/captured_stream.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; #endif // GTEST_OS_WINDOWS fflush(NULL); dup2(captured_fd, fd_); close(captured_fd); } ~CapturedStream() { remove(filename_.c_str()); } String GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. fflush(NULL); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); const String content = ReadEntireFile(file); posix::FClose(file); return content; } private: // Reads the entire content of a file as a String. static String ReadEntireFile(FILE* file); // Returns the size (in bytes) of a file. static size_t GetFileSize(FILE* file); const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. ::std::string filename_; GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; // Returns the size (in bytes) of a file. size_t CapturedStream::GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } // Reads the entire content of a file as a string. String CapturedStream::ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_read = 0; // # of bytes read so far fseek(file, 0, SEEK_SET); // Keeps reading the file until we cannot read further or the // pre-determined file size is reached. do { bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); const String content(buffer, bytes_read); delete[] buffer; return content; } #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } *stream = new CapturedStream(fd); } // Stops capturing the output stream and returns the captured string. String GetCapturedStream(CapturedStream** captured_stream) { const String content = (*captured_stream)->GetCapturedString(); delete *captured_stream; *captured_stream = NULL; return content; } // Starts capturing stdout. void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); } // Starts capturing stderr. void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); } // Stops capturing stdout and returns the captured string. String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #endif // GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector g_argvs; // Returns the command line as a vector of strings. const ::std::vector& GetArgvs() { return g_argvs; } #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE namespace posix { void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } } // namespace posix #endif // GTEST_OS_WINDOWS_MOBILE // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. static String FlagToEnvVar(const char* flag) { const String full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { env_var << static_cast(toupper(full_flag.c_str()[i])); } return env_var.GetString(); } // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. char* end = NULL; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? if (*end != '\0') { // No - an invalid character was encountered. Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value \"" << str << "\".\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } // Is the parsed value in the range of an Int32? const Int32 result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value // The parsed value overflows as an Int32. ) { Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value " << str << ", which overflows.\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } *value = result; return true; } // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const String env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const String env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; } Int32 result = default_value; if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, &result)) { printf("The default value %s is used.\n", (Message() << default_value).GetString().c_str()); fflush(stdout); return default_value; } return result; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const String env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/src/gtest.cc0000664000175100017510000051553312623076744021052 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) #include #include #include #include #include #include #include #include #include #include #include #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). #define GTEST_HAS_GETTIMEOFDAY_ 1 #include #include #include // Declares vsnprintf(). This header is not available on Windows. #include #include #include #include #include #include #elif GTEST_OS_SYMBIAN #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT #elif GTEST_OS_ZOS #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. #include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. #include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. #define GTEST_HAS_GETTIMEOFDAY_ 1 #include // NOLINT #endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. #include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). #define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. #include // NOLINT #include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS #include #endif // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS #define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test case name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test case whose name matches this filter is considered a death // test case and will be run before test cases whose name doesn't // match this filter. static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. bool g_help_flag = false; } // namespace internal GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", false), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", kUniversalFilter), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " "by a colon and an output file name or directory. A directory " "is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_( shuffle, internal::BoolFromGTestEnv("shuffle", false), "True iff " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). state_ = (1103515245U*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). // // A user must call testing::InitGoogleTest() to initialize Google // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true iff the test case passed. static bool TestCasePassed(const TestCase* test_case) { return test_case->should_run() && test_case->Passed(); } // Returns true iff the test case failed. static bool TestCaseFailed(const TestCase* test_case) { return test_case->should_run() && test_case->Failed(); } // Returns true iff test_case contains at least one test that should // run. static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // Mutex for linked pointers. GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. String g_executable_path; // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. String UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return String(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? String(gtest_output_flag) : String(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. String UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return String(""); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return String(internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).ToString() ); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) // TODO(wan@google.com): on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.ToString(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.ToString(); } // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == NULL) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // TODO(keithray): move String function implementations to gtest-string.cc. // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, const String &test_name) { const String& full_name = String::Format("%s.%s", test_case_name.c_str(), test_name.c_str()); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); String positive; String negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = String(""); } else { positive = String(p, dash - p); // Everything up to the dash negative = String(dash+1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_OS_WINDOWS // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle an exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception. return (GTEST_FLAG(catch_exceptions) && exception_code != EXCEPTION_BREAKPOINT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_OS_WINDOWS } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const char* substr) { const String expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure(msg); } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { msg << "Expected: " << expected << "\n" << " Actual:\n" << r; return AssertionFailure(msg); } if (strstr(r.message(), substr) == NULL) { msg << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; return AssertionFailure(msg); } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, const char* substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; return String(""); } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@google.com): Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; #ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); #pragma warning(pop) // Restores the warning state. #else _ftime64(&now); #endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else #error "Don't know how to get the current time on your system." #endif } // Utilities // class String // Returns the input enclosed in double quotes if it's not NULL; // otherwise returns "(null)". For example, "\"Hello\"" is returned // for input "Hello". // // This is useful for printing a C string in the syntax of a literal. // // Known issue: escape sequences are not handled yet. String String::ShowCStringQuoted(const char* c_str) { return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); } // Copies at most length characters from str into a newly-allocated // piece of memory of size length+1. The memory is allocated with new[]. // A terminating null byte is written to the memory, and a pointer to it // is returned. If str is NULL, NULL is returned. static char* CloneString(const char* str, size_t length) { if (str == NULL) { return NULL; } else { char* const clone = new char[length + 1]; posix::StrNCpy(clone, str, length); clone[length] = '\0'; return clone; } } // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting[] the return value. Returns the // cloned string, or NULL if the input is NULL. const char * String::CloneCString(const char* c_str) { return (c_str == NULL) ? NULL : CloneString(c_str, strlen(c_str)); } #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return NULL; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, NULL, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return NULL; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, NULL, 0, NULL, NULL); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, NULL, NULL); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { // TODO(wan): consider allowing a testing::String object to // contain '\0'. This will make it behave more like std::string, // and will allow ToUtf8String() to return the correct encoding // for '\0' s.t. we can get rid of the conditional here (and in // several other places). for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING } // namespace internal #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_GLOBAL_WSTRING namespace internal { // Formats a value to be used in a failure message. // For a char value, we print it as a C++ char literal and as an // unsigned integer (both in decimal and in hexadecimal). String FormatForFailureMessage(char ch) { const unsigned int ch_as_uint = ch; // A String object cannot contain '\0', so we print "\\0" when ch is // '\0'. return String::Format("'%s' (%u, 0x%X)", ch ? String::Format("%c", ch).c_str() : "\\0", ch_as_uint, ch_as_uint); } // For a wchar_t value, we print it as a C++ wchar_t literal and as an // unsigned integer (both in decimal and in hexidecimal). String FormatForFailureMessage(wchar_t wchar) { // The C++ standard doesn't specify the exact size of the wchar_t // type. It just says that it shall have the same size as another // integral type, called its underlying type. // // Therefore, in order to print a wchar_t value in the numeric form, // we first convert it to the largest integral type (UInt64) and // then print the converted value. // // We use streaming to print the value as "%llu" doesn't work // correctly with MSVC 7.1. const UInt64 wchar_as_uint64 = wchar; Message msg; // A String object cannot contain '\0', so we print "\\0" when wchar is // L'\0'. char buffer[32]; // CodePointToUtf8 requires a buffer that big. msg << "L'" << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) << wchar_as_uint64 << ")"; return msg.GetString(); } } // namespace internal // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new internal::String(*other.message_) : static_cast(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != NULL) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const String& expected_value, const String& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; if (actual_value != actual_expression) { msg << "\n Actual: " << actual_value; } msg << "\nExpected: " << expected_expression; if (ignoring_case) { msg << " (ignoring case)"; } if (expected_value != expected_expression) { msg << "\nWhich is: " << expected_value; } return AssertionFailure(msg); } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); // TODO(wan): do not print the value of an expression if it's // already a literal. Message msg; msg << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; return AssertionFailure(msg); } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. StrStream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; StrStream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; Message msg; msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StrStreamToString(&val1_ss) << " vs " << StrStreamToString(&val2_ss); return AssertionFailure(msg); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { if (expected == actual) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ Message msg;\ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ return AssertionFailure(msg);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, String::ShowCStringQuoted(expected), String::ShowCStringQuoted(actual), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CaseInsensitiveCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, String::ShowCStringQuoted(expected), String::ShowCStringQuoted(actual), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { Message msg; msg << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; return AssertionFailure(msg); } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { Message msg; msg << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; return AssertionFailure(msg); } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true iff needle is a // substring of haystack. NULL is considered a substring of itself // only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return strstr(haystack, needle) != NULL; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return wcsstr(haystack, needle) != NULL; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure( Message() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""); } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; #else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // String::Format can't exceed this length. // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system hr, // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing cr-lf) for (; message_length && isspace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } #endif // GTEST_OS_WINDOWS_MOBILE const String error_hex(String::Format("0x%08X ", hr)); Message msg; msg << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << error_text << "\n"; return ::testing::AssertionFailure(msg); } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // The output buffer str must containt at least 32 characters. // The function returns the address of the output buffer. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output // as '(Invalid Unicode 0xXXXXXXXX)'. char* CodePointToUtf8(UInt32 code_point, char* str) { if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else if (code_point <= kMaxCodePoint4) { str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } else { // The longest string String::Format can produce when invoked // with these parameters is 28 character long (not including // the terminating nul character). We are asking for 32 character // buffer just in case. This is also enough for strncpy to // null-terminate the destination string. posix::StrNCpy( str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); str[31] = '\0'; // Makes sure no change in the format to strncpy leaves // the result unterminated. } return str; } // The following two functions only make sense if the the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first & mask) << 10) | (second & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. String WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); StrStream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } char buffer[32]; // CodePointToUtf8 requires a buffer this big. stream << CodePointToUtf8(unicode_code_point, buffer); } return StrStreamToString(&stream); } // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". String String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return String("(null)"); return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); } // Similar to ShowWideCString(), except that this function encloses // the converted string in double quotes. String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { if (wide_c_str == NULL) return String("(null)"); return String::Format("L\"%s\"", String::ShowWideCString(wide_c_str).c_str()); } // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual) { if (String::WideCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, String::ShowWideCStringQuoted(expected), String::ShowWideCStringQuoted(actual), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } Message msg; msg << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << String::ShowWideCStringQuoted(s1) << " vs " << String::ShowWideCStringQuoted(s2); return AssertionFailure(msg); } // Compares two C strings, ignoring case. Returns true iff they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX return wcscasecmp(lhs, rhs) == 0; #else // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes // may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; #endif // OS selector } // Compares this with another String. // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 // if this is greater than rhs. int String::Compare(const String & rhs) const { const char* const lhs_c_str = c_str(); const char* const rhs_c_str = rhs.c_str(); if (lhs_c_str == NULL) { return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL } else if (rhs_c_str == NULL) { return 1; } const size_t shorter_str_len = length() <= rhs.length() ? length() : rhs.length(); for (size_t i = 0; i != shorter_str_len; i++) { if (lhs_c_str[i] < rhs_c_str[i]) { return -1; } else if (lhs_c_str[i] > rhs_c_str[i]) { return 1; } } return (length() < rhs.length()) ? -1 : (length() > rhs.length()) ? 1 : 0; } // Returns true iff this String ends with the given suffix. *Any* // String is considered to end with a NULL or empty suffix. bool String::EndsWith(const char* suffix) const { if (suffix == NULL || CStringEquals(suffix, "")) return true; if (c_str() == NULL) return false; const size_t this_len = strlen(c_str()); const size_t suffix_len = strlen(suffix); return (this_len >= suffix_len) && CStringEquals(c_str() + this_len - suffix_len, suffix); } // Returns true iff this String ends with the given suffix, ignoring case. // Any String is considered to end with a NULL or empty suffix. bool String::EndsWithCaseInsensitive(const char* suffix) const { if (suffix == NULL || CStringEquals(suffix, "")) return true; if (c_str() == NULL) return false; const size_t this_len = strlen(c_str()); const size_t suffix_len = strlen(suffix); return (this_len >= suffix_len) && CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); } // Formats a list of arguments to a String, using the same format // spec string as for printf. // // We do not use the StringPrintf class as it is not universally // available. // // The result is limited to 4096 characters (including the tailing 0). // If 4096 characters are not enough to format the input, or if // there's an error, "" is // returned. String String::Format(const char * format, ...) { va_list args; va_start(args, format); char buffer[4096]; const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); // MSVC 8 deprecates vsnprintf(), so we want to suppress warning // 4996 (deprecated function) there. #ifdef _MSC_VER // We are using MSVC. #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4996) // Temporarily disables warning 4996. const int size = vsnprintf(buffer, kBufferSize, format, args); #pragma warning(pop) // Restores the warning state. #else // We are not using MSVC. const int size = vsnprintf(buffer, kBufferSize, format, args); #endif // _MSC_VER va_end(args); // vsnprintf()'s behavior is not portable. When the buffer is not // big enough, it returns a negative value in MSVC, and returns the // needed buffer size on Linux. When there is an output error, it // always returns a negative value. For simplicity, we lump the two // error cases together. if (size < 0 || size >= kBufferSize) { return String(""); } else { return String(buffer, size); } } // Converts the buffer in a StrStream to a String, converting NUL // bytes to "\\0" along the way. String StrStreamToString(StrStream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); // We need to use a helper StrStream to do this transformation // because String doesn't support push_back(). StrStream helper; for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { helper << "\\0"; // Replaces NUL with "\\0"; } else { helper.put(*ch); } } return String(helper.str().c_str()); } // Appends the user-supplied message to the Google-Test-generated message. String AppendUserMessage(const String& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const String user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } Message msg; msg << gtest_msg << "\n" << user_msg_string; return msg.GetString(); } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), elapsed_time_(0) { } // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const TestProperty& test_property) { if (!ValidateTestProperty(test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const TestProperty& test_property) { internal::String key(test_property.key()); if (key == "name" || key == "status" || key == "time" || key == "classname") { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << key << " ('name', 'status', 'time', and 'classname' are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true iff the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true iff the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the values of all Google Test flags. Test::Test() : gtest_flag_saver_(new internal::GTestFlagSaver) { } // The d'tor restores the values of all Google Test flags. Test::~Test() { delete gtest_flag_saver_; } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const char* key, const char* value) { UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const char* key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const String& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, String()); // No stack trace, either. } } // namespace internal #if GTEST_OS_WINDOWS // We are on Windows. // Adds an "exception thrown" fatal failure to the current test. static void AddExceptionThrownFailure(DWORD exception_code, const char* location) { Message message; message << "Exception thrown with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " in " << location << "."; internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, message.GetString()); } #endif // GTEST_OS_WINDOWS // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. const internal::TestInfoImpl* const first_test_info = test_case->test_info_list()[0]->impl(); const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); const char* const first_test_name = first_test_info->name(); // Info about the current test. const internal::TestInfoImpl* const this_test_info = impl->current_test_info()->impl(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell // him/her how to fix it. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test case is\n" << "illegal. In test case " << this_test_info->test_case_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // The user defined two fixture classes with the same name in // two namespaces - we'll tell him/her how to fix it. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << this_test_info->test_case_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test cases."; } return false; } return true; } // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); #if GTEST_HAS_SEH // Catch SEH-style exceptions. impl->os_stack_trace_getter()->UponLeavingGTest(); __try { SetUp(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); } // We will run the test only if SetUp() had no fatal failure. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); __try { TestBody(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "the test body"); } } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); __try { TearDown(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); } #else // We are on a compiler or platform that doesn't support SEH. impl->os_stack_trace_getter()->UponLeavingGTest(); SetUp(); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); TestBody(); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); TearDown(); #endif // GTEST_HAS_SEH } // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true iff the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object via impl_. TestInfo::TestInfo(const char* a_test_case_name, const char* a_name, const char* a_test_case_comment, const char* a_comment, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) { impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, a_test_case_comment, a_comment, fixture_class_id, factory); } // Destructs a TestInfo object. TestInfo::~TestInfo() { delete impl_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // test_case_comment: a comment on the test case that will be included in // the test output // comment: a comment on the test that will be included in the // test output // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* test_case_comment, const char* comment, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, test_case_comment, comment, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << test_case_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test cases."; fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal // Returns the test case name. const char* TestInfo::test_case_name() const { return impl_->test_case_name(); } // Returns the test name. const char* TestInfo::name() const { return impl_->name(); } // Returns the test case comment. const char* TestInfo::test_case_comment() const { return impl_->test_case_comment(); } // Returns the test comment. const char* TestInfo::comment() const { return impl_->comment(); } // Returns true if this test should run. bool TestInfo::should_run() const { return impl_->should_run(); } // Returns true if this test matches the user-specified filter. bool TestInfo::matches_filter() const { return impl_->matches_filter(); } // Returns the result of the test. const TestResult* TestInfo::result() const { return impl_->result(); } // Increments the number of death tests encountered in this test so // far. int TestInfo::increment_death_test_count() { return impl_->result()->increment_death_test_count(); } namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestCase class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && internal::String(test_info->name()).Compare(name_) == 0; } private: internal::String name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { #if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } #endif } // Creates the test object, runs it, records its result, and then // deletes it. void TestInfoImpl::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(parent_); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*parent_); const TimeInMillis start = GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); #if GTEST_HAS_SEH // Catch SEH-style exceptions. Test* test = NULL; __try { // Creates the test object. test = factory_->CreateTest(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { AddExceptionThrownFailure(GetExceptionCode(), "the test fixture's constructor"); return; } #else // We are on a compiler or platform that doesn't support SEH. // TODO(wan): If test->Run() throws, test won't be deleted. This is // not a problem now as we don't use exceptions. If we were to // enable exceptions, we should revise the following to be // exception-safe. // Creates the test object. Test* test = factory_->CreateTest(); #endif // GTEST_HAS_SEH // Runs the test only if the constructor of the test fixture didn't // generate a fatal failure. if (!Test::HasFatalFailure()) { test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); delete test; test = NULL; result_.set_elapsed_time(GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*parent_); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } } // namespace internal // class TestCase // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase::TestCase(const char* a_name, const char* a_comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), comment_(a_comment), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. void TestCase::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); set_up_tc_(); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->impl()->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); tear_down_tc_(); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); } // Returns true iff test passed. bool TestCase::TestPassed(const TestInfo * test_info) { const internal::TestInfoImpl* const impl = test_info->impl(); return impl->should_run() && impl->result()->Passed(); } // Returns true iff test failed. bool TestCase::TestFailed(const TestInfo * test_info) { const internal::TestInfoImpl* const impl = test_info->impl(); return impl->should_run() && impl->result()->Failed(); } // Returns true iff test is disabled. bool TestCase::TestDisabled(const TestInfo * test_info) { return test_info->impl()->is_disabled(); } // Returns true if the given test should run. bool TestCase::ShouldRunTest(const TestInfo *test_info) { return test_info->impl()->should_run(); } // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static internal::String FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::String::Format("%d %s", count, count == 1 ? singular_form : plural_form); } // Formats the count of tests. static internal::String FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static internal::String FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif } return "Unknown result type"; } // Prints a TestPartResult to a String. static internal::String PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const internal::String& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter namespace internal { enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return NULL; }; } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); internal::String test_case_name_; }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!internal::String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %s of %s.\n", internal::posix::GetEnv(kTestShardIndex), internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { test_case_name_ = test_case.name(); const internal::String counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case_name_.c_str()); if (test_case.comment()[0] == '\0') { printf("\n"); } else { printf(", where %s\n", test_case.comment()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info.name()); if (test_info.comment()[0] == '\0') { printf("\n"); } else { printf(", where %s\n", test_info.comment()); } fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TestPartResult::kSuccess) return; // Print failure message from the assertion (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_case_name_.c_str(), test_info.name()); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; test_case_name_ = test_case.name(); const internal::String counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case_name_.c_str(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); if (test_case.comment()[0] != '\0' || test_info.comment()[0] != '\0') { printf(", where %s", test_case.comment()); if (test_case.comment()[0] != '\0' && test_info.comment()[0] != '\0') { printf(" and "); } } printf("%s\n", test_info.comment()); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + i); return listener; } } return NULL; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ listeners_[i]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static String EscapeXml(const char* str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static String RemoveInvalidXmlCharacters(const char* str); // Convenience wrapper around EscapeXml when str is an attribute value. static String EscapeXmlAttribute(const char* str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(FILE* out, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the String is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static String TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const String output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.c_str() == NULL || output_file_.empty()) { fprintf(stderr, "XML output file may not be null\n"); fflush(stderr); exit(EXIT_FAILURE); } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. // // We don't do it for now as: // // 1. There is no urgent need for it. // 2. It's a bit involved to make the errno variable thread-safe on // all three operating systems (Linux, Windows, and Mac OS). // 3. To interpret the meaning of errno in a thread-safe way, // we need the strerror_r() function, which is not available on // Windows. fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); fflush(stderr); exit(EXIT_FAILURE); } PrintXmlUnitTest(xmlout, unit_test); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { Message m; if (str != NULL) { for (const char* src = str; *src; ++src) { switch (*src) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(*src)) { if (is_attribute && IsNormalizableWhitespace(*src)) m << String::Format("&#x%02X;", unsigned(*src)); else m << *src; } break; } } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { char* const output = new char[strlen(str) + 1]; char* appender = output; for (char ch = *str; ch != '\0'; ch = *++str) if (IsValidXmlCharacter(ch)) *appender++ = ch; *appender = '\0'; String ret_value(output); delete[] output; return ret_value; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << ms/1000.0; return ss.str(); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); *stream << " \n"; *stream << " "; const String message = RemoveInvalidXmlCharacters(String::Format( "%s:%d\n%s", part.file_name(), part.line_number(), part.message()).c_str()); OutputXmlCDataSection(stream, message.c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, const TestCase& test_case) { fprintf(out, " \n", FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); for (int i = 0; i < test_case.total_test_count(); ++i) { StrStream stream; OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); fprintf(out, "%s", StrStreamToString(&stream).c_str()); } fprintf(out, " \n"); } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, const UnitTest& unit_test) { fprintf(out, "\n"); fprintf(out, "\n"); for (int i = 0; i < unit_test.total_test_case_count(); ++i) PrintXmlTestCase(out, *unit_test.GetTestCase(i)); fprintf(out, "\n"); } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } // End XmlUnitTestResultPrinter // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. // L < UnitTest::mutex_ ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. // L < UnitTest::mutex_ ScopedTrace::~ScopedTrace() { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter // Returns the current OS stack trace as a String. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // // L < mutex_ // We use "L < mutex_" to denote that the function may acquire mutex_. String OsStackTraceGetter::CurrentStackTrace(int, int) { return String(""); } // L < mutex_ void OsStackTraceGetter::UponLeavingGTest() { } const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) default_xml_generator_ = NULL; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != NULL) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != NULL) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest * UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Gets the number of successful test cases. int UnitTest::successful_test_case_count() const { return impl()->successful_test_case_count(); } // Gets the number of failed test cases. int UnitTest::failed_test_case_count() const { return impl()->failed_test_case_count(); } // Gets the number of all test cases. int UnitTest::total_test_case_count() const { return impl()->total_test_case_count(); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTest::test_case_to_run_count() const { return impl()->test_case_to_run_count(); } // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true iff the unit test passed (i.e. all test cases passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { return impl()->GetMutableTestCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == NULL) { return NULL; } impl_->environments().push_back(env); return env; } #if GTEST_HAS_EXCEPTIONS // A failed Google Test assertion will throw an exception of this type // when exceptions are enabled. We derive it from std::runtime_error, // which is for errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} }; #endif // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. // L < mutex_ void UnitTest::AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const internal::String& message, const internal::String& os_stack_trace) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (int i = static_cast(impl_->gtest_trace_stack().size()); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Creates and adds a property to the current TestResult. If a property matching // the supplied value already exists, updates its value instead. void UnitTest::RecordPropertyForCurrentTest(const char* key, const char* value) { const TestProperty test_property(key, value); impl_->current_test_result()->RecordProperty(test_property); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { #if GTEST_HAS_SEH // Catch SEH-style exceptions. const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected.. if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { #if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); #endif // !GTEST_OS_WINDOWS_MOBILE #if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); #endif #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. // TODO(vladl@google.com): find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. #endif } __try { return impl_->RunAllTests(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode())) { printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); fflush(stdout); return 1; } #else // We are on a compiler or platform that doesn't support SEH. return impl_->RunAllTests(); #endif // GTEST_HAS_SEH } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. // L < mutex_ const TestCase* UnitTest::current_test_case() const { internal::MutexLock lock(&mutex_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. // L < mutex_ const TestInfo* UnitTest::current_test_info() const { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // L < mutex_ internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. // L < mutex_ void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. // L < mutex_ void UnitTest::PopGTestTrace() { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER #pragma warning(push) // Saves the current warning state. #pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #endif // _MSC_VER global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. #if GTEST_HAS_DEATH_TEST elapsed_time_(0), internal_run_death_test_flag_(NULL), death_test_factory_(new DefaultDeathTestFactory) { #else elapsed_time_(0) { #endif // GTEST_HAS_DEATH_TEST listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != NULL) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const String& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); fflush(stdout); } } // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); } } // A predicate that checks the name of a TestCase against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestCaseNameIs is copyable. class TestCaseNameIs { public: // Constructor. explicit TestCaseNameIs(const String& name) : name_(name) {} // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: String name_; }; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_case_name: name of the test case // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::const_iterator test_case = std::find_if(test_cases_.begin(), test_cases_.end(), TestCaseNameIs(test_case_name)); if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. TestCase* const new_test_case = new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_case_; test_cases_.insert(test_cases_.begin() + last_death_test_case_, new_test_case); } else { // No. Appends to the end of the list. test_cases_.push_back(new_test_case); } test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns 0 if all tests are successful, or 1 otherwise. If any // exception is thrown during a test on Windows, this test is // considered to be failed, but the rest of the tests will still be // run. (We disable exceptions on Linux and Mac OS X, so the issue // doesn't apply there.) // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. int UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); return 1; } // Do not run any test if the --help flag was specified. if (g_help_flag) return 0; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return 0; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True iff at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { ClearResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test cases and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(random_seed_); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_case_count(); test_index++) { GetMutableTestCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); // Returns 0 if all tests passed, or 1 other wise. return failed ? 1 : 0; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; const String &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; const String test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter(test_case_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->impl()->set_matches_filter(matches_filter); const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests)); num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->impl()->set_should_run(is_selected); test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; if (test_info->matches_filter()) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.\n", test_case->name()); } printf(" %s\n", test_info->name()); } } } fflush(stdout); } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { os_stack_trace_getter_ = new OsStackTraceGetter; } return os_stack_trace_getter_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? current_test_info_->impl()->result() : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. test_case_indices_[i] = static_cast(i); } } // TestInfoImpl constructor. The new instance assumes ownership of the test // factory object. TestInfoImpl::TestInfoImpl(TestInfo* parent, const char* a_test_case_name, const char* a_name, const char* a_test_case_comment, const char* a_comment, TypeId a_fixture_class_id, internal::TestFactoryBase* factory) : parent_(parent), test_case_name_(String(a_test_case_name)), name_(String(a_name)), test_case_comment_(String(a_test_case_comment)), comment_(String(a_comment)), fixture_class_id_(a_fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory) { } // TestInfoImpl destructor. TestInfoImpl::~TestInfoImpl() { delete factory_; } // Returns the current OS stack trace as a String. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable // code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return NULL; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == NULL) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // // TODO(wan@google.com): Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == NULL) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", String(str, p - str).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" #endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" #if GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" " Suppress pop-ups caused by exceptions.\n" #endif // GTEST_OS_WINDOWS "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const String arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; // Do we see a Google Test flag? if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { g_init_gtest_count++; // We don't want to run the initialization code twice. if (g_init_gtest_count != 1) return; if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } } // namespace testing ceph-0.80.11/src/gtest/src/gtest-filepath.cc0000664000175100017510000003360712623076744022641 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Authors: keith.ray@gmail.com (Keith Ray) #include #include #include #if GTEST_OS_WINDOWS_MOBILE #include #elif GTEST_OS_WINDOWS #include #include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h #include #else #include #include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS #define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) #define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) #define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else #define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS #include namespace testing { namespace internal { #if GTEST_OS_WINDOWS // On Windows, '\\' is the standard path separator, but many tools and the // Windows API also accept '/' as an alternate path separator. Unless otherwise // noted, a file path can contain either kind of path separators, or a mixture // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; #else const char kCurrentDirectoryString[] = ".\\"; #endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS // Returns whether the given character is a valid path separator. static bool IsPathSeparator(char c) { #if GTEST_HAS_ALT_PATH_SEP_ return (c == kPathSeparator) || (c == kAlternatePathSeparator); #else return c == kPathSeparator; #endif } // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { String dot_extension(String::Format(".%s", extension)); if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); } return *this; } // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { const char* const last_sep = strrchr(c_str(), kPathSeparator); #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. if (last_alt_sep != NULL && (last_sep == NULL || last_alt_sep > last_sep)) { return last_alt_sep; } #endif return last_sep; } // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { const char* const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(String(last_sep + 1)) : *this; } // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); String dir; if (last_sep) { dir = String(c_str(), last_sep + 1 - c_str()); } else { dir = kCurrentDirectoryString; } return FilePath(dir); } // Helper functions for naming files in a directory for xml output. // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { String file; if (number == 0) { file = String::Format("%s.%s", base_name.c_str(), extension); } else { file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); } return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. FilePath FilePath::ConcatPaths(const FilePath& directory, const FilePath& relative_path) { if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, relative_path.c_str())); } // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; return attributes != kInvalidFileAttributes; #else posix::StatStruct file_stat; return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // GTEST_OS_WINDOWS_MOBILE } // Returns true if pathname describes a directory in the file-system // that exists. bool FilePath::DirectoryExists() const { bool result = false; #if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : RemoveTrailingPathSeparator()); #else const FilePath& path(*this); #endif #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; if ((attributes != kInvalidFileAttributes) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { result = true; } #else posix::StatStruct file_stat; result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // GTEST_OS_WINDOWS_MOBILE return result; } // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); #endif } // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); #if GTEST_OS_WINDOWS return pathname_.length() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && IsPathSeparator(name[2]); #else return IsPathSeparator(name[0]); #endif } // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension) { FilePath full_pathname; int number = 0; do { full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); } while (full_pathname.FileOrDirectoryExists()); return full_pathname; } // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool FilePath::IsDirectory() const { return !pathname_.empty() && IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); } // Create directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create directories // for any reason. bool FilePath::CreateDirectoriesRecursively() const { if (!this->IsDirectory()) { return false; } if (pathname_.length() == 0 || this->DirectoryExists()) { return true; } const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); return parent.CreateDirectoriesRecursively() && this->CreateFolder(); } // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); int result = CreateDirectory(unicode, NULL) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); #else int result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE if (result == -1) { return this->DirectoryExists(); // An error is OK if the directory exists. } return true; // No error. } // If input name has a trailing separator character, remove it and return the // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return IsDirectory() ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) : *this; } // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; return; } const char* src = pathname_.c_str(); char* const dest = new char[pathname_.length() + 1]; char* dest_ptr = dest; memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { *dest_ptr = *src; if (!IsPathSeparator(*src)) { src++; } else { #if GTEST_HAS_ALT_PATH_SEP_ if (*dest_ptr == kAlternatePathSeparator) { *dest_ptr = kPathSeparator; } #endif while (IsPathSeparator(*src)) src++; } dest_ptr++; } *dest_ptr = '\0'; pathname_ = dest; delete[] dest; } } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/src/gtest-all.cc0000664000175100017510000000412012623076744021601 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // // Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. // This line ensures that gtest.h can be compiled on its own, even // when it's fused. #include // The following lines pull in the real gtest *.cc files. #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" #include "src/gtest-port.cc" #include "src/gtest-test-part.cc" #include "src/gtest-typed-test.cc" ceph-0.80.11/src/gtest/src/gtest-typed-test.cc0000664000175100017510000000724312623076744023144 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include namespace testing { namespace internal { #if GTEST_HAS_TYPED_TEST_P // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { while (isspace(*str)) str++; return str; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef ::std::set::const_iterator DefinedTestIter; registered_ = true; // Skip initial whitespace in registered_tests since some // preprocessors prefix stringizied literals with whitespace. registered_tests = SkipSpaces(registered_tests); Message errors; ::std::set tests; for (const char* names = registered_tests; names != NULL; names = SkipComma(names)) { const String name = GetPrefixUntilComma(names); if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (name == *it) { found = true; break; } } if (found) { tests.insert(name); } else { errors << "No test named " << name << " can be found in this test case.\n"; } } for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (tests.count(*it) == 0) { errors << "You forgot to list test " << *it << ".\n"; } } const String& errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); fflush(stderr); posix::Abort(); } return registered_tests; } #endif // GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/CMakeLists.txt0000664000175100017510000003447112623076744021363 0ustar jenkins-buildjenkins-build######################################################################## # Experimental CMake build script for Google Test. # # Consider this a prototype. It will change drastically. For now, # this is only for people on the cutting edge. # # To run the tests for Google Test itself on Linux, use 'make test' or # ctest. You can select which tests to run using 'ctest -R regex'. # For more options, run 'ctest --help'. # For hermetic builds, we may need to tell CMake to use compiler in a # specific location. if (gtest_compiler) include(CMakeForceCompiler) cmake_force_c_compiler("${gtest_compiler}" "") cmake_force_cxx_compiler("${gtest_compiler}" "") endif() ######################################################################## # # Project-wide settings # Name of the project. # # CMake files in this project can refer to the root source directory # as ${gtest_SOURCE_DIR} and to the root binary directory as # ${gtest_BINARY_DIR}. # Language "C" is required for find_package(Threads). project(gtest CXX C) cmake_minimum_required(VERSION 2.6.4) if (MSVC) # For MSVC, CMake sets certain flags to defaults we want to override. # This replacement code is taken from sample in the CMake Wiki at # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) # In hermetic build environments, tests may not have access to MS runtime # DLLs, so this replaces /MD (CRT libraries in DLLs) with /MT (static CRT # libraries). string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") # We prefer more strict warning checking for building Google Test. # Replaces /W3 with /W4 in defaults. string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") endforeach() endif() # Where gtest's .h files can be found. include_directories( ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) # Where the gtest libraries can be found. link_directories( ${gtest_BINARY_DIR}/src) # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. find_package(Threads) # Defines the compiler/linker flags used to build gtest. You can # tweak these definitions to suit your need. A variable's value is # empty before it's explicitly assigned to. if (MSVC) # Newlines inside flags variables break CMake's NMake generator. set(cxx_base_flags "-GS -W4 -WX -wd4275 -nologo -J -Zi") set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-GR-") elseif (CMAKE_COMPILER_IS_GNUCXX) set(cxx_base_flags "-Wall -Wshadow") set(cxx_exception_flags "-fexceptions") set(cxx_no_exception_flags "-fno-exceptions") # Until version 4.3.2, GCC doesn't define a macro to indicate # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI # explicitly. set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") set(cxx_strict_flags "-Wextra") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") set(cxx_exception_flags "-features=except") # Sun Pro doesn't provide macros to indicate whether exceptions and # RTTI are enabled, so we define GTEST_HAS_* explicitly. set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR CMAKE_CXX_COMPILER_ID STREQUAL "XL") # CMake 2.8 changes Visual Age's compiler ID to "XL". set(cxx_exception_flags "-qeh") set(cxx_no_exception_flags "-qnoeh") # Until version 9.0, Visual Age doesn't define a macro to indicate # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI # explicitly. set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") endif() if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available. set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") endif() # For building gtest's own tests and samples. set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") set(cxx_no_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") set(cxx_default "${cxx_exception}") set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") # For building the gtest libraries. set(cxx_strict "${cxx_default} ${cxx_strict_flags}") ######################################################################## # # Defines the gtest & gtest_main libraries. User tests should link # with one of them. function(cxx_library_with_type name type cxx_flags) # type can be either STATIC or SHARED to denote a static or shared library. # ARGN refers to additional arguments after 'cxx_flags'. add_library(${name} ${type} ${ARGN}) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") if (CMAKE_USE_PTHREADS_INIT) target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) endif() endfunction() function(cxx_static_library name cxx_flags) cxx_library_with_type(${name} STATIC "${cxx_flags}" ${ARGN}) endfunction() function(cxx_shared_library name cxx_flags) cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) endfunction() function(cxx_library name cxx_flags) # TODO(vladl@google.com): Make static/shared a user option. cxx_static_library(${name} "${cxx_flags}" ${ARGN}) endfunction() # Static versions of Google Test libraries. We build them using more # strict warnings than what are used for other targets, to ensure that # gtest can be compiled by a user aggressive about warnings. cxx_static_library(gtest "${cxx_strict}" src/gtest-all.cc) cxx_static_library(gtest_main "${cxx_strict}" src/gtest_main.cc) target_link_libraries(gtest_main gtest) ######################################################################## # # Samples on how to link user tests with gtest or gtest_main. # # They are not built by default. To build them, set the # build_gtest_samples option to ON. You can do it by running ccmake # or specifying the -Dbuild_gtest_samples=ON flag when running cmake. option(build_gtest_samples "Build gtest's sample programs." OFF) # cxx_executable_with_flags(name cxx_flags lib srcs...) # # creates a named C++ executable that depends on the given library and # is built from the given source files with the given compiler flags. function(cxx_executable_with_flags name cxx_flags lib) add_executable(${name} ${ARGN}) if (cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") endif() target_link_libraries(${name} ${lib}) endfunction() # cxx_executable(name dir lib srcs...) # # creates a named target that depends on the given lib and is built # from the given source files. dir/name.cc is implicitly included in # the source file list. function(cxx_executable name dir lib) cxx_executable_with_flags( ${name} "${cxx_default}" ${lib} "${dir}/${name}.cc" ${ARGN}) endfunction() if (build_gtest_samples) cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) cxx_executable(sample3_unittest samples gtest_main) cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc) cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc) cxx_executable(sample6_unittest samples gtest_main) cxx_executable(sample7_unittest samples gtest_main) cxx_executable(sample8_unittest samples gtest_main) cxx_executable(sample9_unittest samples gtest) cxx_executable(sample10_unittest samples gtest) endif() ######################################################################## # # Google Test's own tests. # # You can skip this section if you aren't interested in testing # Google Test itself. # # Most of the tests are not built by default. To build them, set the # build_all_gtest_tests option to ON. You can do it by running ccmake # or specifying the -Dbuild_all_gtest_tests=ON flag when running cmake. option(build_all_gtest_tests "Build all of gtest's own tests." OFF) # This must be set in the root directory for the tests to be run by # 'make test' or ctest. enable_testing() # Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. find_package(PythonInterp) ############################################################ # C++ tests built with standard compiler flags. # cxx_test_with_flags(name cxx_flags libs srcs...) # # creates a named C++ test that depends on the given libs and is built # from the given source files with the given compiler flags. function(cxx_test_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") # To support mixing linking in static and dynamic libraries, link each # library in with an extra call to target_link_libraries. foreach (lib "${libs}") target_link_libraries(${name} ${lib}) endforeach() add_test(${name} ${name}) endfunction() # cxx_test(name libs srcs...) # # creates a named test target that depends on the given libs and is # built from the given source files. Unlike cxx_test_with_flags, # test/name.cc is already implicitly included in the source file list. function(cxx_test name libs) cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" "test/${name}.cc" ${ARGN}) endfunction() cxx_test(gtest_unittest gtest_main) if (build_all_gtest_tests) cxx_test(gtest-death-test_test gtest_main) cxx_test(gtest_environment_test gtest) cxx_test(gtest-filepath_test gtest_main) cxx_test(gtest-linked_ptr_test gtest_main) cxx_test(gtest-listener_test gtest_main) cxx_test(gtest_main_unittest gtest_main) cxx_test(gtest-message_test gtest_main) cxx_test(gtest_no_test_unittest gtest) cxx_test(gtest-options_test gtest_main) cxx_test(gtest-param-test_test gtest test/gtest-param-test2_test.cc) cxx_test(gtest-port_test gtest_main) cxx_test(gtest_pred_impl_unittest gtest_main) cxx_test(gtest_prod_test gtest_main test/production.cc) cxx_test(gtest_repeat_test gtest) cxx_test(gtest_sole_header_test gtest_main) cxx_test(gtest_stress_test gtest) cxx_test(gtest-test-part_test gtest_main) cxx_test(gtest_throw_on_failure_ex_test gtest) cxx_test(gtest-typed-test_test gtest_main test/gtest-typed-test2_test.cc) cxx_test(gtest-unittest-api_test gtest) endif() ############################################################ # C++ tests built with non-standard compiler flags. if (build_all_gtest_tests) cxx_library(gtest_no_exception "${cxx_no_exception}" src/gtest-all.cc) cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" src/gtest-all.cc src/gtest_main.cc) cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" gtest_main_no_rtti test/gtest_unittest.cc) set(cxx_use_shared_gtest "${cxx_default} -DGTEST_LINKED_AS_SHARED_LIBRARY=1") set(cxx_build_shared_gtest "${cxx_default} -DGTEST_CREATE_SHARED_LIBRARY=1") if (MSVC) # Disables the "class 'X' needs to have dll-interface to be used # by clients of class 'Y'" warning. This particularly concerns generic # classes like vector that MS doesn't mark as exported. set(cxx_use_shared_gtest "${cxx_use_shared_gtest} -wd4251") set(cxx_build_shared_gtest "${cxx_build_shared_gtest} -wd4251") endif() cxx_shared_library(gtest_dll "${cxx_build_shared_gtest}" src/gtest-all.cc) # TODO(vladl): This and the next tests may not run in the hermetic # environment on Windows. Re-evaluate and possibly make them # platform-conditional after implementing hermetic builds. cxx_executable_with_flags(gtest_dll_test_ "${cxx_use_shared_gtest}" gtest_dll test/gtest_all_test.cc) if (NOT(MSVC AND (MSVC_VERSION EQUAL 1600))) # The C++ Standard specifies tuple_element. # Yet MSVC 10's declares tuple_element. # That declaration conflicts with our own standard-conforming # tuple implementation. Therefore using our own tuple with # MSVC 10 doesn't compile. cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}" src/gtest-all.cc src/gtest_main.cc) cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}" gtest_main_use_own_tuple test/gtest-tuple_test.cc) cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}" gtest_main_use_own_tuple test/gtest-param-test_test.cc test/gtest-param-test2_test.cc) endif() endif() ############################################################ # Python tests. # py_test(name) # # creates a Python test with the given name whose main module is in # test/name.py. It does nothing if Python is not installed. function(py_test name) if (PYTHONINTERP_FOUND) # ${gtest_BINARY_DIR} is known at configuration time, so we can # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known # only at ctest runtime (by calling ctest -c ), so # we have to escape $ to delay variable substitution here. add_test(${name} ${PYTHON_EXECUTABLE} ${gtest_SOURCE_DIR}/test/${name}.py --gtest_build_dir=${gtest_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) endif() endfunction() if (build_all_gtest_tests) cxx_executable(gtest_break_on_failure_unittest_ test gtest) py_test(gtest_break_on_failure_unittest) cxx_executable(gtest_color_test_ test gtest) py_test(gtest_color_test) cxx_executable(gtest_env_var_test_ test gtest) py_test(gtest_env_var_test) cxx_executable(gtest_filter_unittest_ test gtest) py_test(gtest_filter_unittest) cxx_executable(gtest_help_test_ test gtest_main) py_test(gtest_help_test) cxx_executable(gtest_list_tests_unittest_ test gtest) py_test(gtest_list_tests_unittest) cxx_executable(gtest_output_test_ test gtest) py_test(gtest_output_test) cxx_executable(gtest_shuffle_test_ test gtest) py_test(gtest_shuffle_test) cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception) set_target_properties(gtest_throw_on_failure_test_ PROPERTIES COMPILE_FLAGS "${cxx_no_exception}") py_test(gtest_throw_on_failure_test) cxx_executable(gtest_uninitialized_test_ test gtest) py_test(gtest_uninitialized_test) cxx_executable(gtest_xml_outfile1_test_ test gtest_main) cxx_executable(gtest_xml_outfile2_test_ test gtest_main) py_test(gtest_xml_outfiles_test) cxx_executable(gtest_xml_output_unittest_ test gtest) py_test(gtest_xml_output_unittest) endif() ceph-0.80.11/src/gtest/build-aux/0000775000175100017510000000000012623077036020477 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/build-aux/config.guess0000755000175100017510000013036112623076774023031 0ustar jenkins-buildjenkins-build#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ceph-0.80.11/src/gtest/build-aux/config.sub0000755000175100017510000010535412623076774022500 0ustar jenkins-buildjenkins-build#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-08-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ceph-0.80.11/src/gtest/build-aux/install-sh0000755000175100017510000003325512623076774022521 0ustar jenkins-buildjenkins-build#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/src/gtest/build-aux/config.h.in0000664000175100017510000000346112623076773022535 0ustar jenkins-buildjenkins-build/* build-aux/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION ceph-0.80.11/src/gtest/build-aux/missing0000755000175100017510000001533012623076774022106 0ustar jenkins-buildjenkins-build#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/src/gtest/build-aux/depcomp0000755000175100017510000005601612623076774022072 0ustar jenkins-buildjenkins-build#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/src/gtest/build-aux/test-driver0000755000175100017510000001027712623076774022712 0ustar jenkins-buildjenkins-build#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2013-07-13.22; # UTC # Copyright (C) 2011-2013 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <$log_file 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then estatus=1 fi case $estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/src/gtest/build-aux/ltmain.sh0000644000175100017510000105204412623076771022330 0ustar jenkins-buildjenkins-build # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.7ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1.7ubuntu1" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 ceph-0.80.11/src/gtest/build-aux/compile0000755000175100017510000001624512623076774022073 0ustar jenkins-buildjenkins-build#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/src/gtest/Makefile.am0000664000175100017510000002226212623076744020652 0ustar jenkins-buildjenkins-build# Automake file ACLOCAL_AMFLAGS = -I m4 AM_LDFLAGS = -lpthread # Nonstandard package files for distribution EXTRA_DIST = \ CHANGES \ CONTRIBUTORS \ include/gtest/gtest-param-test.h.pump \ include/gtest/internal/gtest-tuple.h.pump \ include/gtest/internal/gtest-type-util.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \ make/Makefile \ scripts/fuse_gtest_files.py \ scripts/gen_gtest_pred_impl.py \ scripts/pump.py \ scripts/test/Makefile # gtest source files that we don't compile directly. They are # #included by gtest-all.cc. GTEST_SRC = \ src/gtest.cc \ src/gtest-death-test.cc \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ src/gtest-port.cc \ src/gtest-test-part.cc \ src/gtest-typed-test.cc EXTRA_DIST += $(GTEST_SRC) # Sample files that we don't compile. EXTRA_DIST += \ samples/prime_tables.h \ samples/sample2_unittest.cc \ samples/sample3_unittest.cc \ samples/sample4_unittest.cc \ samples/sample5_unittest.cc \ samples/sample6_unittest.cc \ samples/sample7_unittest.cc \ samples/sample8_unittest.cc \ samples/sample9_unittest.cc # C++ test files that we don't compile directly. EXTRA_DIST += \ test/gtest-death-test_test.cc \ test/gtest_environment_test.cc \ test/gtest-filepath_test.cc \ test/gtest-linked_ptr_test.cc \ test/gtest-message_test.cc \ test/gtest_no_test_unittest.cc \ test/gtest-options_test.cc \ test/gtest-param-test_test.cc \ test/gtest-param-test2_test.cc \ test/gtest-param-test_test.h \ test/gtest-port_test.cc \ test/gtest_pred_impl_unittest.cc \ test/gtest_prod_test.cc \ test/production.cc \ test/production.h \ test/gtest_repeat_test.cc \ test/gtest_sole_header_test.cc \ test/gtest_stress_test.cc \ test/gtest-test-part_test.cc \ test/gtest_throw_on_failure_ex_test.cc \ test/gtest-typed-test_test.cc \ test/gtest-typed-test2_test.cc \ test/gtest-typed-test_test.h \ test/gtest_unittest.cc \ test/gtest-unittest-api_test.cc \ test/gtest-listener_test.cc \ test/gtest_main_unittest.cc \ test/gtest_unittest.cc \ test/gtest-tuple_test.cc \ test/gtest-param-test_test.cc \ test/gtest-param-test2_test.cc \ test/gtest_break_on_failure_unittest_.cc \ test/gtest_color_test_.cc \ test/gtest_env_var_test_.cc \ test/gtest_filter_unittest_.cc \ test/gtest_help_test_.cc \ test/gtest_list_tests_unittest_.cc \ test/gtest_output_test_.cc \ test/gtest_shuffle_test_.cc \ test/gtest_throw_on_failure_test_.cc \ test/gtest_uninitialized_test_.cc \ test/gtest_xml_outfile1_test_.cc \ test/gtest_xml_outfile2_test_.cc \ test/gtest_xml_output_unittest_.cc # Python tests that we don't run. EXTRA_DIST += \ test/gtest_test_utils.py \ test/gtest_xml_test_utils.py \ test/gtest_break_on_failure_unittest.py \ test/gtest_color_test.py \ test/gtest_env_var_test.py \ test/gtest_filter_unittest.py \ test/gtest_help_test.py \ test/gtest_list_tests_unittest.py \ test/gtest_output_test.py \ test/gtest_output_test_golden_lin.txt \ test/gtest_output_test_golden_win.txt \ test/gtest_shuffle_test.py \ test/gtest_throw_on_failure_test.py \ test/gtest_uninitialized_test.py \ test/gtest_xml_outfiles_test.py \ test/gtest_xml_output_unittest.py \ test/run_tests_util.py \ test/run_tests_util_test.py # CMake script EXTRA_DIST += \ CMakeLists.txt # MSVC project files EXTRA_DIST += \ msvc/gtest-md.sln \ msvc/gtest.sln \ msvc/gtest-md.vcproj \ msvc/gtest.vcproj \ msvc/gtest_main-md.vcproj \ msvc/gtest_main.vcproj \ msvc/gtest_prod_test-md.vcproj \ msvc/gtest_prod_test.vcproj \ msvc/gtest_unittest-md.vcproj \ msvc/gtest_unittest.vcproj # xcode project files EXTRA_DIST += \ xcode/Config/DebugProject.xcconfig \ xcode/Config/FrameworkTarget.xcconfig \ xcode/Config/General.xcconfig \ xcode/Config/ReleaseProject.xcconfig \ xcode/Config/StaticLibraryTarget.xcconfig \ xcode/Config/TestTarget.xcconfig \ xcode/Resources/Info.plist \ xcode/Scripts/versiongenerate.py \ xcode/Scripts/runtests.sh \ xcode/gtest.xcodeproj/project.pbxproj # xcode sample files EXTRA_DIST += \ xcode/Samples/FrameworkSample/Info.plist \ xcode/Samples/FrameworkSample/runtests.sh \ xcode/Samples/FrameworkSample/widget_test.cc \ xcode/Samples/FrameworkSample/widget.cc \ xcode/Samples/FrameworkSample/widget.h \ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj # C++Builder project files EXTRA_DIST += \ codegear/gtest_all.cc \ codegear/gtest_link.cc \ codegear/gtest.cbproj \ codegear/gtest_main.cbproj \ codegear/gtest_unittest.cbproj \ codegear/gtest.groupproj # Scripts and utilities bin_SCRIPTS = scripts/gtest-config CLEANFILES = $(bin_SCRIPTS) # Distribute and install M4 macro m4datadir = $(datadir)/aclocal m4data_DATA = m4/gtest.m4 EXTRA_DIST += $(m4data_DATA) # We define the global AM_CPPFLAGS as everything we compile includes from these # directories. AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include -DGTEST_HAS_TR1_TUPLE=0 # Modifies compiler and linker flags for pthreads compatibility. if HAVE_PTHREADS AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 AM_LIBS = @PTHREAD_LIBS@ else AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0 endif # Build rules for libraries. lib_LIBRARIES = lib/libgtest.a lib/libgtest_main.a lib_libgtest_a_SOURCES = src/gtest-all.cc pkginclude_HEADERS = include/gtest/gtest.h \ include/gtest/gtest-death-test.h \ include/gtest/gtest-message.h \ include/gtest/gtest-param-test.h \ include/gtest/gtest_pred_impl.h \ include/gtest/gtest_prod.h \ include/gtest/gtest-spi.h \ include/gtest/gtest-test-part.h \ include/gtest/gtest-typed-test.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ include/gtest/internal/gtest-death-test-internal.h \ include/gtest/internal/gtest-filepath.h \ include/gtest/internal/gtest-internal.h \ include/gtest/internal/gtest-linked_ptr.h \ include/gtest/internal/gtest-param-util-generated.h \ include/gtest/internal/gtest-param-util.h \ include/gtest/internal/gtest-port.h \ include/gtest/internal/gtest-string.h \ include/gtest/internal/gtest-tuple.h \ include/gtest/internal/gtest-type-util.h lib_libgtest_main_a_SOURCES = src/gtest_main.cc lib_libgtest_main_a_LIBADD = lib/libgtest.a # Bulid rules for samples and tests. Automake's naming for some of # these variables isn't terribly obvious, so this is a brief # reference: # # TESTS -- Programs run automatically by "make check" # check_PROGRAMS -- Programs built by "make check" but not necessarily run noinst_LTLIBRARIES = samples/libsamples.la samples_libsamples_la_SOURCES = samples/sample1.cc \ samples/sample1.h \ samples/sample2.cc \ samples/sample2.h \ samples/sample3-inl.h \ samples/sample4.cc \ samples/sample4.h TESTS= TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \ GTEST_BUILD_DIR="$(top_builddir)/test" check_PROGRAMS= # A simple sample on using gtest. TESTS += samples/sample1_unittest check_PROGRAMS += samples/sample1_unittest samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc samples_sample1_unittest_LDADD = lib/libgtest_main.la \ samples/libsamples.la # Another sample. It also verifies that libgtest works. TESTS += samples/sample10_unittest check_PROGRAMS += samples/sample10_unittest samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc samples_sample10_unittest_LDADD = lib/libgtest.a # This tests most constructs of gtest and verifies that libgtest_main # works. TESTS += test/gtest_all_test check_PROGRAMS += test/gtest_all_test test_gtest_all_test_SOURCES = test/gtest_all_test.cc test_gtest_all_test_LDADD = lib/libgtest_main.la # Tests that fused gtest files compile and work. FUSED_GTEST_SRC = \ fused-src/gtest/gtest-all.cc \ fused-src/gtest/gtest_main.cc \ fused-src/gtest/gtest.h TESTS += test/fused_gtest_test check_PROGRAMS += test/fused_gtest_test test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \ samples/sample1.cc samples/sample1_unittest.cc test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src" # Build rules for putting fused Google Test files into the distribution # package. The user can also create those files by manually running # scripts/fuse_gtest_files.py. $(test_fused_gtest_test_SOURCES): fused-gtest fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \ scripts/fuse_gtest_files.py mkdir -p "$(srcdir)/fused-src" chmod -R u+w "$(srcdir)/fused-src" rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc" rm -f "$(srcdir)/fused-src/gtest/gtest.h" "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src" cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/" maintainer-clean-local: rm -rf "$(srcdir)/fused-src" # Death tests may produce core dumps in the build directory. In case # this happens, clean them to keep distcleancheck happy. CLEANFILES += core ceph-0.80.11/src/gtest/msvc/0000775000175100017510000000000012623077036017555 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/msvc/gtest_prod_test-md.vcproj0000664000175100017510000001064312623076744024622 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest_prod_test.vcproj0000664000175100017510000001063512623076744024225 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest.vcproj0000664000175100017510000001476012623076744022145 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest-md.sln0000664000175100017510000000463012623076744022027 0ustar jenkins-buildjenkins-buildMicrosoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest-md.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "gtest_main-md.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test-md", "gtest_prod_test-md.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest-md", "gtest_unittest-md.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.ActiveCfg = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.Build.0 = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.ActiveCfg = Release|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.Build.0 = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.ActiveCfg = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.Build.0 = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.ActiveCfg = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.Build.0 = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.ActiveCfg = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.Build.0 = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.ActiveCfg = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.Build.0 = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.ActiveCfg = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.Build.0 = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.ActiveCfg = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal ceph-0.80.11/src/gtest/msvc/gtest_main-md.vcproj0000664000175100017510000001056212623076744023543 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest.sln0000664000175100017510000000460012623076744021426 0ustar jenkins-buildjenkins-buildMicrosoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest", "gtest_unittest.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test", "gtest_prod_test.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.ActiveCfg = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.Build.0 = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.ActiveCfg = Release|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.Build.0 = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.ActiveCfg = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.Build.0 = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.ActiveCfg = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.Build.0 = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.ActiveCfg = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.Build.0 = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.ActiveCfg = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.Build.0 = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.ActiveCfg = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.Build.0 = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.ActiveCfg = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal ceph-0.80.11/src/gtest/msvc/gtest_main.vcproj0000664000175100017510000001055412623076744023146 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest-md.vcproj0000664000175100017510000001476312623076744022546 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest_unittest.vcproj0000664000175100017510000000764312623076744024106 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/msvc/gtest_unittest-md.vcproj0000664000175100017510000000765112623076744024503 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/gtest/CONTRIBUTORS0000664000175100017510000000244612623076744020500 0ustar jenkins-buildjenkins-build# This file contains a list of people who've made non-trivial # contribution to the Google C++ Testing Framework project. People # who commit code to the project are encouraged to add their names # here. Please keep the list sorted by first names. Ajay Joshi Balázs Dán Bharat Mediratta Chandler Carruth Chris Prince Chris Taylor Dan Egnor Eric Roman Hady Zalek Jeffrey Yasskin Jói Sigurðsson Keir Mierle Keith Ray Kenton Varda Manuel Klimek Markus Heule Mika Raento Miklós Fazekas Patrick Hanna Patrick Riley Peter Kaminski Preston Jackson Rainer Klaffenboeck Russ Cox Russ Rufer Sean Mcafee Sigurður Ãsgeirsson Tracy Bialik Vadim Berman Vlad Losev Zhanyong Wan ceph-0.80.11/src/gtest/samples/0000775000175100017510000000000012623077036020251 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/samples/sample5_unittest.cc0000664000175100017510000001470112623076744024075 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // This sample teaches how to reuse a test fixture in multiple test // cases by deriving sub-fixtures from it. // // When you define a test fixture, you specify the name of the test // case that will use this fixture. Therefore, a test fixture can // be used by only one test case. // // Sometimes, more than one test cases may want to use the same or // slightly different test fixtures. For example, you may want to // make sure that all tests for a GUI library don't leak important // system resources like fonts and brushes. In Google Test, you do // this by putting the shared logic in a super (as in "super class") // test fixture, and then have each test case use a fixture derived // from this super fixture. #include #include #include "sample3-inl.h" #include #include "sample1.h" // In this sample, we want to ensure that every test finishes within // ~5 seconds. If a test takes longer to run, we consider it a // failure. // // We put the code for timing a test in a test fixture called // "QuickTest". QuickTest is intended to be the super fixture that // other fixtures derive from, therefore there is no test case with // the name "QuickTest". This is OK. // // Later, we will derive multiple test fixtures from QuickTest. class QuickTest : public testing::Test { protected: // Remember that SetUp() is run immediately before a test starts. // This is a good place to record the start time. virtual void SetUp() { start_time_ = time(NULL); } // TearDown() is invoked immediately after a test finishes. Here we // check if the test was too slow. virtual void TearDown() { // Gets the time when the test finishes const time_t end_time = time(NULL); // Asserts that the test took no more than ~5 seconds. Did you // know that you can use assertions in SetUp() and TearDown() as // well? EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long."; } // The UTC time (in seconds) when the test starts time_t start_time_; }; // We derive a fixture named IntegerFunctionTest from the QuickTest // fixture. All tests using this fixture will be automatically // required to be quick. class IntegerFunctionTest : public QuickTest { // We don't need any more logic than already in the QuickTest fixture. // Therefore the body is empty. }; // Now we can write tests in the IntegerFunctionTest test case. // Tests Factorial() TEST_F(IntegerFunctionTest, Factorial) { // Tests factorial of negative numbers. EXPECT_EQ(1, Factorial(-5)); EXPECT_EQ(1, Factorial(-1)); EXPECT_TRUE(Factorial(-10) > 0); // Tests factorial of 0. EXPECT_EQ(1, Factorial(0)); // Tests factorial of positive numbers. EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } // Tests IsPrime() TEST_F(IntegerFunctionTest, IsPrime) { // Tests negative input. EXPECT_TRUE(!IsPrime(-1)); EXPECT_TRUE(!IsPrime(-2)); EXPECT_TRUE(!IsPrime(INT_MIN)); // Tests some trivial cases. EXPECT_TRUE(!IsPrime(0)); EXPECT_TRUE(!IsPrime(1)); EXPECT_TRUE(IsPrime(2)); EXPECT_TRUE(IsPrime(3)); // Tests positive input. EXPECT_TRUE(!IsPrime(4)); EXPECT_TRUE(IsPrime(5)); EXPECT_TRUE(!IsPrime(6)); EXPECT_TRUE(IsPrime(23)); } // The next test case (named "QueueTest") also needs to be quick, so // we derive another fixture from QuickTest. // // The QueueTest test fixture has some logic and shared objects in // addition to what's in QuickTest already. We define the additional // stuff inside the body of the test fixture, as usual. class QueueTest : public QuickTest { protected: virtual void SetUp() { // First, we need to set up the super fixture (QuickTest). QuickTest::SetUp(); // Second, some additional setup for this fixture. q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // By default, TearDown() inherits the behavior of // QuickTest::TearDown(). As we have no additional cleaning work // for QueueTest, we omit it here. // // virtual void TearDown() { // QuickTest::TearDown(); // } Queue q0_; Queue q1_; Queue q2_; }; // Now, let's write tests using the QueueTest fixture. // Tests the default constructor. TEST_F(QueueTest, DefaultConstructor) { EXPECT_EQ(0u, q0_.Size()); } // Tests Dequeue(). TEST_F(QueueTest, Dequeue) { int* n = q0_.Dequeue(); EXPECT_TRUE(n == NULL); n = q1_.Dequeue(); EXPECT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0u, q1_.Size()); delete n; n = q2_.Dequeue(); EXPECT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1u, q2_.Size()); delete n; } // If necessary, you can derive further test fixtures from a derived // fixture itself. For example, you can derive another fixture from // QueueTest. Google Test imposes no limit on how deep the hierarchy // can be. In practice, however, you probably don't want it to be too // deep as to be confusing. ceph-0.80.11/src/gtest/samples/sample4.h0000664000175100017510000000404312623076744021775 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE4_H_ #define GTEST_SAMPLES_SAMPLE4_H_ // A simple monotonic counter. class Counter { private: int counter_; public: // Creates a counter that starts at 0. Counter() : counter_(0) {} // Returns the current counter value, and increments it. int Increment(); // Prints the current counter value to STDOUT. void Print() const; }; #endif // GTEST_SAMPLES_SAMPLE4_H_ ceph-0.80.11/src/gtest/samples/sample1.h0000664000175100017510000000362112623076744021773 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE1_H_ #define GTEST_SAMPLES_SAMPLE1_H_ // Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n); // Returns true iff n is a prime number. bool IsPrime(int n); #endif // GTEST_SAMPLES_SAMPLE1_H_ ceph-0.80.11/src/gtest/samples/sample4.cc0000664000175100017510000000360712623076744022140 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #include #include "sample4.h" // Returns the current counter value, and increments it. int Counter::Increment() { return counter_++; } // Prints the current counter value to STDOUT. void Counter::Print() const { printf("%d", counter_); } ceph-0.80.11/src/gtest/samples/sample4_unittest.cc0000664000175100017510000000356512623076744024102 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include "sample4.h" // Tests the Increment() method. TEST(Counter, Increment) { Counter c; // EXPECT_EQ() evaluates its arguments exactly once, so they // can have side effects. EXPECT_EQ(0, c.Increment()); EXPECT_EQ(1, c.Increment()); EXPECT_EQ(2, c.Increment()); } ceph-0.80.11/src/gtest/samples/sample6_unittest.cc0000664000175100017510000002143512623076744024100 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // This sample shows how to test common properties of multiple // implementations of the same interface (aka interface tests). // The interface and its implementations are in this header. #include "prime_tables.h" #include // First, we define some factory functions for creating instances of // the implementations. You may be able to skip this step if all your // implementations can be constructed the same way. template PrimeTable* CreatePrimeTable(); template <> PrimeTable* CreatePrimeTable() { return new OnTheFlyPrimeTable; } template <> PrimeTable* CreatePrimeTable() { return new PreCalculatedPrimeTable(10000); } // Then we define a test fixture class template. template class PrimeTableTest : public testing::Test { protected: // The ctor calls the factory function to create a prime table // implemented by T. PrimeTableTest() : table_(CreatePrimeTable()) {} virtual ~PrimeTableTest() { delete table_; } // Note that we test an implementation via the base interface // instead of the actual implementation class. This is important // for keeping the tests close to the real world scenario, where the // implementation is invoked via the base interface. It avoids // got-yas where the implementation class has a method that shadows // a method with the same name (but slightly different argument // types) in the base interface, for example. PrimeTable* const table_; }; #if GTEST_HAS_TYPED_TEST using testing::Types; // Google Test offers two ways for reusing tests for different types. // The first is called "typed tests". You should use it if you // already know *all* the types you are gonna exercise when you write // the tests. // To write a typed test case, first use // // TYPED_TEST_CASE(TestCaseName, TypeList); // // to declare it and specify the type parameters. As with TEST_F, // TestCaseName must match the test fixture name. // The list of types we want to test. typedef Types Implementations; TYPED_TEST_CASE(PrimeTableTest, Implementations); // Then use TYPED_TEST(TestCaseName, TestName) to define a typed test, // similar to TEST_F. TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) { // Inside the test body, you can refer to the type parameter by // TypeParam, and refer to the fixture class by TestFixture. We // don't need them in this example. // Since we are in the template world, C++ requires explicitly // writing 'this->' when referring to members of the fixture class. // This is something you have to learn to live with. EXPECT_FALSE(this->table_->IsPrime(-5)); EXPECT_FALSE(this->table_->IsPrime(0)); EXPECT_FALSE(this->table_->IsPrime(1)); EXPECT_FALSE(this->table_->IsPrime(4)); EXPECT_FALSE(this->table_->IsPrime(6)); EXPECT_FALSE(this->table_->IsPrime(100)); } TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) { EXPECT_TRUE(this->table_->IsPrime(2)); EXPECT_TRUE(this->table_->IsPrime(3)); EXPECT_TRUE(this->table_->IsPrime(5)); EXPECT_TRUE(this->table_->IsPrime(7)); EXPECT_TRUE(this->table_->IsPrime(11)); EXPECT_TRUE(this->table_->IsPrime(131)); } TYPED_TEST(PrimeTableTest, CanGetNextPrime) { EXPECT_EQ(2, this->table_->GetNextPrime(0)); EXPECT_EQ(3, this->table_->GetNextPrime(2)); EXPECT_EQ(5, this->table_->GetNextPrime(3)); EXPECT_EQ(7, this->table_->GetNextPrime(5)); EXPECT_EQ(11, this->table_->GetNextPrime(7)); EXPECT_EQ(131, this->table_->GetNextPrime(128)); } // That's it! Google Test will repeat each TYPED_TEST for each type // in the type list specified in TYPED_TEST_CASE. Sit back and be // happy that you don't have to define them multiple times. #endif // GTEST_HAS_TYPED_TEST #if GTEST_HAS_TYPED_TEST_P using testing::Types; // Sometimes, however, you don't yet know all the types that you want // to test when you write the tests. For example, if you are the // author of an interface and expect other people to implement it, you // might want to write a set of tests to make sure each implementation // conforms to some basic requirements, but you don't know what // implementations will be written in the future. // // How can you write the tests without committing to the type // parameters? That's what "type-parameterized tests" can do for you. // It is a bit more involved than typed tests, but in return you get a // test pattern that can be reused in many contexts, which is a big // win. Here's how you do it: // First, define a test fixture class template. Here we just reuse // the PrimeTableTest fixture defined earlier: template class PrimeTableTest2 : public PrimeTableTest { }; // Then, declare the test case. The argument is the name of the test // fixture, and also the name of the test case (as usual). The _P // suffix is for "parameterized" or "pattern". TYPED_TEST_CASE_P(PrimeTableTest2); // Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test, // similar to what you do with TEST_F. TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes) { EXPECT_FALSE(this->table_->IsPrime(-5)); EXPECT_FALSE(this->table_->IsPrime(0)); EXPECT_FALSE(this->table_->IsPrime(1)); EXPECT_FALSE(this->table_->IsPrime(4)); EXPECT_FALSE(this->table_->IsPrime(6)); EXPECT_FALSE(this->table_->IsPrime(100)); } TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes) { EXPECT_TRUE(this->table_->IsPrime(2)); EXPECT_TRUE(this->table_->IsPrime(3)); EXPECT_TRUE(this->table_->IsPrime(5)); EXPECT_TRUE(this->table_->IsPrime(7)); EXPECT_TRUE(this->table_->IsPrime(11)); EXPECT_TRUE(this->table_->IsPrime(131)); } TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) { EXPECT_EQ(2, this->table_->GetNextPrime(0)); EXPECT_EQ(3, this->table_->GetNextPrime(2)); EXPECT_EQ(5, this->table_->GetNextPrime(3)); EXPECT_EQ(7, this->table_->GetNextPrime(5)); EXPECT_EQ(11, this->table_->GetNextPrime(7)); EXPECT_EQ(131, this->table_->GetNextPrime(128)); } // Type-parameterized tests involve one extra step: you have to // enumerate the tests you defined: REGISTER_TYPED_TEST_CASE_P( PrimeTableTest2, // The first argument is the test case name. // The rest of the arguments are the test names. ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime); // At this point the test pattern is done. However, you don't have // any real test yet as you haven't said which types you want to run // the tests with. // To turn the abstract test pattern into real tests, you instantiate // it with a list of types. Usually the test pattern will be defined // in a .h file, and anyone can #include and instantiate it. You can // even instantiate it more than once in the same program. To tell // different instances apart, you give each of them a name, which will // become part of the test case name and can be used in test filters. // The list of types we want to test. Note that it doesn't have to be // defined at the time we write the TYPED_TEST_P()s. typedef Types PrimeTableImplementations; INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name PrimeTableTest2, // Test case name PrimeTableImplementations); // Type list #endif // GTEST_HAS_TYPED_TEST_P ceph-0.80.11/src/gtest/samples/sample2_unittest.cc0000664000175100017510000000754612623076744024103 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // This sample shows how to write a more complex unit test for a class // that has multiple member functions. // // Usually, it's a good idea to have one test for each method in your // class. You don't have to do that exactly, but it helps to keep // your tests organized. You may also throw in additional tests as // needed. #include "sample2.h" #include // In this example, we test the MyString class (a simple string). // Tests the default c'tor. TEST(MyString, DefaultConstructor) { const MyString s; // Asserts that s.c_string() returns NULL. // // // // If we write NULL instead of // // static_cast(NULL) // // in this assertion, it will generate a warning on gcc 3.4. The // reason is that EXPECT_EQ needs to know the types of its // arguments in order to print them when it fails. Since NULL is // #defined as 0, the compiler will use the formatter function for // int to print it. However, gcc thinks that NULL should be used as // a pointer, not an int, and therefore complains. // // The root of the problem is C++'s lack of distinction between the // integer number 0 and the null pointer constant. Unfortunately, // we have to live with this fact. // // EXPECT_STREQ(NULL, s.c_string()); EXPECT_EQ(0u, s.Length()); } const char kHelloString[] = "Hello, world!"; // Tests the c'tor that accepts a C string. TEST(MyString, ConstructorFromCString) { const MyString s(kHelloString); EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0); EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1, s.Length()); } // Tests the copy c'tor. TEST(MyString, CopyConstructor) { const MyString s1(kHelloString); const MyString s2 = s1; EXPECT_TRUE(strcmp(s2.c_string(), kHelloString) == 0); } // Tests the Set method. TEST(MyString, Set) { MyString s; s.Set(kHelloString); EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0); // Set should work when the input pointer is the same as the one // already in the MyString object. s.Set(s.c_string()); EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0); // Can we set the MyString to NULL? s.Set(NULL); EXPECT_STREQ(NULL, s.c_string()); } ceph-0.80.11/src/gtest/samples/sample10_unittest.cc0000664000175100017510000001171112623076744024147 0ustar jenkins-buildjenkins-build// Copyright 2009 Google Inc. 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. // // Author: vladl@google.com (Vlad Losev) // This sample shows how to use Google Test listener API to implement // a primitive leak checker. #include #include #include using ::testing::EmptyTestEventListener; using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::TestCase; using ::testing::TestEventListeners; using ::testing::TestInfo; using ::testing::TestPartResult; using ::testing::UnitTest; namespace { // We will track memory used by this class. class Water { public: // Normal Water declarations go here. // operator new and operator delete help us control water allocation. void* operator new(size_t allocation_size) { allocated_++; return malloc(allocation_size); } void operator delete(void* block, size_t /* allocation_size */) { allocated_--; free(block); } static int allocated() { return allocated_; } private: static int allocated_; }; int Water::allocated_ = 0; // This event listener monitors how many Water objects are created and // destroyed by each test, and reports a failure if a test leaks some Water // objects. It does this by comparing the number of live Water objects at // the beginning of a test and at the end of a test. class LeakChecker : public EmptyTestEventListener { private: // Called before a test starts. virtual void OnTestStart(const TestInfo& /* test_info */) { initially_allocated_ = Water::allocated(); } // Called after a test ends. virtual void OnTestEnd(const TestInfo& /* test_info */) { int difference = Water::allocated() - initially_allocated_; // You can generate a failure in any event handler except // OnTestPartResult. Just use an appropriate Google Test assertion to do // it. EXPECT_TRUE(difference <= 0) << "Leaked " << difference << " unit(s) of Water!"; } int initially_allocated_; }; TEST(ListenersTest, DoesNotLeak) { Water* water = new Water; delete water; } // This should fail when the --check_for_leaks command line flag is // specified. TEST(ListenersTest, LeaksWater) { Water* water = new Water; EXPECT_TRUE(water != NULL); } } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); bool check_for_leaks = false; if (argc > 1 && strcmp(argv[1], "--check_for_leaks") == 0 ) check_for_leaks = true; else printf("%s\n", "Run this program with --check_for_leaks to enable " "custom leak checking in the tests."); // If we are given the --check_for_leaks command line flag, installs the // leak checker. if (check_for_leaks) { TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); // Adds the leak checker to the end of the test event listener list, // after the default text output printer and the default XML report // generator. // // The order is important - it ensures that failures generated in the // leak checker's OnTestEnd() method are processed by the text and XML // printers *before* their OnTestEnd() methods are called, such that // they are attributed to the right test. Remember that a listener // receives an OnXyzStart event *after* listeners preceding it in the // list received that event, and receives an OnXyzEnd event *before* // listeners preceding it. // // We don't need to worry about deleting the new listener later, as // Google Test will do it. listeners.Append(new LeakChecker); } return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/samples/prime_tables.h0000664000175100017510000000775012623076744023106 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Author: vladl@google.com (Vlad Losev) // This provides interface PrimeTable that determines whether a number is a // prime and determines a next prime number. This interface is used // in Google Test samples demonstrating use of parameterized tests. #ifndef GTEST_SAMPLES_PRIME_TABLES_H_ #define GTEST_SAMPLES_PRIME_TABLES_H_ #include // The prime table interface. class PrimeTable { public: virtual ~PrimeTable() {} // Returns true iff n is a prime number. virtual bool IsPrime(int n) const = 0; // Returns the smallest prime number greater than p; or returns -1 // if the next prime is beyond the capacity of the table. virtual int GetNextPrime(int p) const = 0; }; // Implementation #1 calculates the primes on-the-fly. class OnTheFlyPrimeTable : public PrimeTable { public: virtual bool IsPrime(int n) const { if (n <= 1) return false; for (int i = 2; i*i <= n; i++) { // n is divisible by an integer other than 1 and itself. if ((n % i) == 0) return false; } return true; } virtual int GetNextPrime(int p) const { for (int n = p + 1; n > 0; n++) { if (IsPrime(n)) return n; } return -1; } }; // Implementation #2 pre-calculates the primes and stores the result // in an array. class PreCalculatedPrimeTable : public PrimeTable { public: // 'max' specifies the maximum number the prime table holds. explicit PreCalculatedPrimeTable(int max) : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) { CalculatePrimesUpTo(max); } virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; } virtual bool IsPrime(int n) const { return 0 <= n && n < is_prime_size_ && is_prime_[n]; } virtual int GetNextPrime(int p) const { for (int n = p + 1; n < is_prime_size_; n++) { if (is_prime_[n]) return n; } return -1; } private: void CalculatePrimesUpTo(int max) { ::std::fill(is_prime_, is_prime_ + is_prime_size_, true); is_prime_[0] = is_prime_[1] = false; for (int i = 2; i <= max; i++) { if (!is_prime_[i]) continue; // Marks all multiples of i (except i itself) as non-prime. for (int j = 2*i; j <= max; j += i) { is_prime_[j] = false; } } } const int is_prime_size_; bool* const is_prime_; // Disables compiler warning "assignment operator could not be generated." void operator=(const PreCalculatedPrimeTable& rhs); }; #endif // GTEST_SAMPLES_PRIME_TABLES_H_ ceph-0.80.11/src/gtest/samples/sample8_unittest.cc0000664000175100017510000001544012623076744024101 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // This sample shows how to test code relying on some global flag variables. // Combine() helps with generating all possible combinations of such flags, // and each test is given one combination as a parameter. // Use class definitions to test from this header. #include "prime_tables.h" #include #if GTEST_HAS_COMBINE // Suppose we want to introduce a new, improved implementation of PrimeTable // which combines speed of PrecalcPrimeTable and versatility of // OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both // PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more // appropriate under the circumstances. But in low memory conditions, it can be // told to instantiate without PrecalcPrimeTable instance at all and use only // OnTheFlyPrimeTable. class HybridPrimeTable : public PrimeTable { public: HybridPrimeTable(bool force_on_the_fly, int max_precalculated) : on_the_fly_impl_(new OnTheFlyPrimeTable), precalc_impl_(force_on_the_fly ? NULL : new PreCalculatedPrimeTable(max_precalculated)), max_precalculated_(max_precalculated) {} virtual ~HybridPrimeTable() { delete on_the_fly_impl_; delete precalc_impl_; } virtual bool IsPrime(int n) const { if (precalc_impl_ != NULL && n < max_precalculated_) return precalc_impl_->IsPrime(n); else return on_the_fly_impl_->IsPrime(n); } virtual int GetNextPrime(int p) const { int next_prime = -1; if (precalc_impl_ != NULL && p < max_precalculated_) next_prime = precalc_impl_->GetNextPrime(p); return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p); } private: OnTheFlyPrimeTable* on_the_fly_impl_; PreCalculatedPrimeTable* precalc_impl_; int max_precalculated_; }; using ::testing::TestWithParam; using ::testing::Bool; using ::testing::Values; using ::testing::Combine; // To test all code paths for HybridPrimeTable we must test it with numbers // both within and outside PreCalculatedPrimeTable's capacity and also with // PreCalculatedPrimeTable disabled. We do this by defining fixture which will // accept different combinations of parameters for instantiating a // HybridPrimeTable instance. class PrimeTableTest : public TestWithParam< ::std::tr1::tuple > { protected: virtual void SetUp() { // This can be written as // // bool force_on_the_fly; // int max_precalculated; // tie(force_on_the_fly, max_precalculated) = GetParam(); // // once the Google C++ Style Guide allows use of ::std::tr1::tie. // bool force_on_the_fly = ::std::tr1::get<0>(GetParam()); int max_precalculated = ::std::tr1::get<1>(GetParam()); table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated); } virtual void TearDown() { delete table_; table_ = NULL; } HybridPrimeTable* table_; }; TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { // Inside the test body, you can refer to the test parameter by GetParam(). // In this case, the test parameter is a PrimeTable interface pointer which // we can use directly. // Please note that you can also save it in the fixture's SetUp() method // or constructor and use saved copy in the tests. EXPECT_FALSE(table_->IsPrime(-5)); EXPECT_FALSE(table_->IsPrime(0)); EXPECT_FALSE(table_->IsPrime(1)); EXPECT_FALSE(table_->IsPrime(4)); EXPECT_FALSE(table_->IsPrime(6)); EXPECT_FALSE(table_->IsPrime(100)); } TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { EXPECT_TRUE(table_->IsPrime(2)); EXPECT_TRUE(table_->IsPrime(3)); EXPECT_TRUE(table_->IsPrime(5)); EXPECT_TRUE(table_->IsPrime(7)); EXPECT_TRUE(table_->IsPrime(11)); EXPECT_TRUE(table_->IsPrime(131)); } TEST_P(PrimeTableTest, CanGetNextPrime) { EXPECT_EQ(2, table_->GetNextPrime(0)); EXPECT_EQ(3, table_->GetNextPrime(2)); EXPECT_EQ(5, table_->GetNextPrime(3)); EXPECT_EQ(7, table_->GetNextPrime(5)); EXPECT_EQ(11, table_->GetNextPrime(7)); EXPECT_EQ(131, table_->GetNextPrime(128)); } // In order to run value-parameterized tests, you need to instantiate them, // or bind them to a list of values which will be used as test parameters. // You can instantiate them in a different translation module, or even // instantiate them several times. // // Here, we instantiate our tests with a list of parameters. We must combine // all variations of the boolean flag suppressing PrecalcPrimeTable and some // meaningful values for tests. We choose a small value (1), and a value that // will put some of the tested numbers beyond the capability of the // PrecalcPrimeTable instance and some inside it (10). Combine will produce all // possible combinations. INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters, PrimeTableTest, Combine(Bool(), Values(1, 10))); #else // Google Test may not support Combine() with some compilers. If we // use conditional compilation to compile out all code referring to // the gtest_main library, MSVC linker will not link that library at // all and consequently complain about missing entry point defined in // that library (fatal error LNK1561: entry point must be // defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {} #endif // GTEST_HAS_COMBINE ceph-0.80.11/src/gtest/samples/sample1.cc0000664000175100017510000000470612623076744022136 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #include "sample1.h" // Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result; } // Returns true iff n is a prime number. bool IsPrime(int n) { // Trivial case 1: small numbers if (n <= 1) return false; // Trivial case 2: even numbers if (n % 2 == 0) return n == 2; // Now, we have that n is odd and n >= 3. // Try to divide n by every odd number i, starting from 3 for (int i = 3; ; i += 2) { // We only have to try i up to the squre root of n if (i > n/i) break; // Now, we have i <= n/i < n. // If n is divisible by i, n is not prime. if (n % i == 0) return false; } // n has no integer factor in the range (1, n), and thus is prime. return true; } ceph-0.80.11/src/gtest/samples/sample7_unittest.cc0000664000175100017510000001204512623076744024076 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // This sample shows how to test common properties of multiple // implementations of an interface (aka interface tests) using // value-parameterized tests. Each test in the test case has // a parameter that is an interface pointer to an implementation // tested. // The interface and its implementations are in this header. #include "prime_tables.h" #include #if GTEST_HAS_PARAM_TEST using ::testing::TestWithParam; using ::testing::Values; // As a general rule, tested objects should not be reused between tests. // Also, their constructors and destructors of tested objects can have // side effects. Thus you should create and destroy them for each test. // In this sample we will define a simple factory function for PrimeTable // objects. We will instantiate objects in test's SetUp() method and // delete them in TearDown() method. typedef PrimeTable* CreatePrimeTableFunc(); PrimeTable* CreateOnTheFlyPrimeTable() { return new OnTheFlyPrimeTable(); } template PrimeTable* CreatePreCalculatedPrimeTable() { return new PreCalculatedPrimeTable(max_precalculated); } // Inside the test body, fixture constructor, SetUp(), and TearDown() // you can refer to the test parameter by GetParam(). // In this case, the test parameter is a PrimeTableFactory interface pointer // which we use in fixture's SetUp() to create and store an instance of // PrimeTable. class PrimeTableTest : public TestWithParam { public: virtual ~PrimeTableTest() { delete table_; } virtual void SetUp() { table_ = (*GetParam())(); } virtual void TearDown() { delete table_; table_ = NULL; } protected: PrimeTable* table_; }; TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { EXPECT_FALSE(table_->IsPrime(-5)); EXPECT_FALSE(table_->IsPrime(0)); EXPECT_FALSE(table_->IsPrime(1)); EXPECT_FALSE(table_->IsPrime(4)); EXPECT_FALSE(table_->IsPrime(6)); EXPECT_FALSE(table_->IsPrime(100)); } TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { EXPECT_TRUE(table_->IsPrime(2)); EXPECT_TRUE(table_->IsPrime(3)); EXPECT_TRUE(table_->IsPrime(5)); EXPECT_TRUE(table_->IsPrime(7)); EXPECT_TRUE(table_->IsPrime(11)); EXPECT_TRUE(table_->IsPrime(131)); } TEST_P(PrimeTableTest, CanGetNextPrime) { EXPECT_EQ(2, table_->GetNextPrime(0)); EXPECT_EQ(3, table_->GetNextPrime(2)); EXPECT_EQ(5, table_->GetNextPrime(3)); EXPECT_EQ(7, table_->GetNextPrime(5)); EXPECT_EQ(11, table_->GetNextPrime(7)); EXPECT_EQ(131, table_->GetNextPrime(128)); } // In order to run value-parameterized tests, you need to instantiate them, // or bind them to a list of values which will be used as test parameters. // You can instantiate them in a different translation module, or even // instantiate them several times. // // Here, we instantiate our tests with a list of two PrimeTable object // factory functions: INSTANTIATE_TEST_CASE_P( OnTheFlyAndPreCalculated, PrimeTableTest, Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>)); #else // Google Test may not support value-parameterized tests with some // compilers. If we use conditional compilation to compile out all // code referring to the gtest_main library, MSVC linker will not link // that library at all and consequently complain about missing entry // point defined in that library (fatal error LNK1561: entry point // must be defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} #endif // GTEST_HAS_PARAM_TEST ceph-0.80.11/src/gtest/samples/sample3_unittest.cc0000664000175100017510000001234712623076744024077 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // In this example, we use a more advanced feature of Google Test called // test fixture. // // A test fixture is a place to hold objects and functions shared by // all tests in a test case. Using a test fixture avoids duplicating // the test code necessary to initialize and cleanup those common // objects for each test. It is also useful for defining sub-routines // that your tests need to invoke a lot. // // // // The tests share the test fixture in the sense of code sharing, not // data sharing. Each test is given its own fresh copy of the // fixture. You cannot expect the data modified by one test to be // passed on to another test, which is a bad idea. // // The reason for this design is that tests should be independent and // repeatable. In particular, a test should not fail as the result of // another test's failure. If one test depends on info produced by // another test, then the two tests should really be one big test. // // The macros for indicating the success/failure of a test // (EXPECT_TRUE, FAIL, etc) need to know what the current test is // (when Google Test prints the test result, it tells you which test // each failure belongs to). Technically, these macros invoke a // member function of the Test class. Therefore, you cannot use them // in a global function. That's why you should put test sub-routines // in a test fixture. // // #include "sample3-inl.h" #include // To use a test fixture, derive a class from testing::Test. class QueueTest : public testing::Test { protected: // You should make the members protected s.t. they can be // accessed from sub-classes. // virtual void SetUp() will be called before each test is run. You // should define it if you need to initialize the varaibles. // Otherwise, this can be skipped. virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() will be called after each test is run. // You should define it if there is cleanup work to do. Otherwise, // you don't have to provide it. // // virtual void TearDown() { // } // A helper function that some test uses. static int Double(int n) { return 2*n; } // A helper function for testing Queue::Map(). void MapTester(const Queue * q) { // Creates a new queue, where each element is twice as big as the // corresponding one in q. const Queue * const new_q = q->Map(Double); // Verifies that the new queue has the same size as q. ASSERT_EQ(q->Size(), new_q->Size()); // Verifies the relationship between the elements of the two queues. for ( const QueueNode * n1 = q->Head(), * n2 = new_q->Head(); n1 != NULL; n1 = n1->next(), n2 = n2->next() ) { EXPECT_EQ(2 * n1->element(), n2->element()); } delete new_q; } // Declares the variables your tests want to use. Queue q0_; Queue q1_; Queue q2_; }; // When you have a test fixture, you define a test using TEST_F // instead of TEST. // Tests the default c'tor. TEST_F(QueueTest, DefaultConstructor) { // You can access data in the test fixture here. EXPECT_EQ(0u, q0_.Size()); } // Tests Dequeue(). TEST_F(QueueTest, Dequeue) { int * n = q0_.Dequeue(); EXPECT_TRUE(n == NULL); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0u, q1_.Size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1u, q2_.Size()); delete n; } // Tests the Queue::Map() function. TEST_F(QueueTest, Map) { MapTester(&q0_); MapTester(&q1_); MapTester(&q2_); } ceph-0.80.11/src/gtest/samples/sample2.cc0000664000175100017510000000437212623076744022136 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #include "sample2.h" #include // Clones a 0-terminated C string, allocating memory using new. const char* MyString::CloneCString(const char* a_c_string) { if (a_c_string == NULL) return NULL; const size_t len = strlen(a_c_string); char* const clone = new char[ len + 1 ]; memcpy(clone, a_c_string, len + 1); return clone; } // Sets the 0-terminated C string this MyString object // represents. void MyString::Set(const char* a_c_string) { // Makes sure this works when c_string == c_string_ const char* const temp = MyString::CloneCString(a_c_string); delete[] c_string_; c_string_ = temp; } ceph-0.80.11/src/gtest/samples/sample2.h0000664000175100017510000000567712623076744022011 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE2_H_ #define GTEST_SAMPLES_SAMPLE2_H_ #include // A simple string class. class MyString { private: const char* c_string_; const MyString& operator=(const MyString& rhs); public: // Clones a 0-terminated C string, allocating memory using new. static const char* CloneCString(const char* a_c_string); //////////////////////////////////////////////////////////// // // C'tors // The default c'tor constructs a NULL string. MyString() : c_string_(NULL) {} // Constructs a MyString by cloning a 0-terminated C string. explicit MyString(const char* a_c_string) : c_string_(NULL) { Set(a_c_string); } // Copy c'tor MyString(const MyString& string) : c_string_(NULL) { Set(string.c_string_); } //////////////////////////////////////////////////////////// // // D'tor. MyString is intended to be a final class, so the d'tor // doesn't need to be virtual. ~MyString() { delete[] c_string_; } // Gets the 0-terminated C string this MyString object represents. const char* c_string() const { return c_string_; } size_t Length() const { return c_string_ == NULL ? 0 : strlen(c_string_); } // Sets the 0-terminated C string this MyString object represents. void Set(const char* c_string); }; #endif // GTEST_SAMPLES_SAMPLE2_H_ ceph-0.80.11/src/gtest/samples/sample3-inl.h0000664000175100017510000001235512623076744022561 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE3_INL_H_ #define GTEST_SAMPLES_SAMPLE3_INL_H_ #include // Queue is a simple queue implemented as a singled-linked list. // // The element type must support copy constructor. template // E is the element type class Queue; // QueueNode is a node in a Queue, which consists of an element of // type E and a pointer to the next node. template // E is the element type class QueueNode { friend class Queue; public: // Gets the element in this node. const E& element() const { return element_; } // Gets the next node in the queue. QueueNode* next() { return next_; } const QueueNode* next() const { return next_; } private: // Creates a node with a given element value. The next pointer is // set to NULL. QueueNode(const E& an_element) : element_(an_element), next_(NULL) {} // We disable the default assignment operator and copy c'tor. const QueueNode& operator = (const QueueNode&); QueueNode(const QueueNode&); E element_; QueueNode* next_; }; template // E is the element type. class Queue { public: // Creates an empty queue. Queue() : head_(NULL), last_(NULL), size_(0) {} // D'tor. Clears the queue. ~Queue() { Clear(); } // Clears the queue. void Clear() { if (size_ > 0) { // 1. Deletes every node. QueueNode* node = head_; QueueNode* next = node->next(); for (; ;) { delete node; node = next; if (node == NULL) break; next = node->next(); } // 2. Resets the member variables. head_ = last_ = NULL; size_ = 0; } } // Gets the number of elements. size_t Size() const { return size_; } // Gets the first element of the queue, or NULL if the queue is empty. QueueNode* Head() { return head_; } const QueueNode* Head() const { return head_; } // Gets the last element of the queue, or NULL if the queue is empty. QueueNode* Last() { return last_; } const QueueNode* Last() const { return last_; } // Adds an element to the end of the queue. A copy of the element is // created using the copy constructor, and then stored in the queue. // Changes made to the element in the queue doesn't affect the source // object, and vice versa. void Enqueue(const E& element) { QueueNode* new_node = new QueueNode(element); if (size_ == 0) { head_ = last_ = new_node; size_ = 1; } else { last_->next_ = new_node; last_ = new_node; size_++; } } // Removes the head of the queue and returns it. Returns NULL if // the queue is empty. E* Dequeue() { if (size_ == 0) { return NULL; } const QueueNode* const old_head = head_; head_ = head_->next_; size_--; if (size_ == 0) { last_ = NULL; } E* element = new E(old_head->element()); delete old_head; return element; } // Applies a function/functor on each element of the queue, and // returns the result in a new queue. The original queue is not // affected. template Queue* Map(F function) const { Queue* new_queue = new Queue(); for (const QueueNode* node = head_; node != NULL; node = node->next_) { new_queue->Enqueue(function(node->element())); } return new_queue; } private: QueueNode* head_; // The first node of the queue. QueueNode* last_; // The last node of the queue. size_t size_; // The number of elements in the queue. // We disallow copying a queue. Queue(const Queue&); const Queue& operator = (const Queue&); }; #endif // GTEST_SAMPLES_SAMPLE3_INL_H_ ceph-0.80.11/src/gtest/samples/sample1_unittest.cc0000664000175100017510000001201412623076744024064 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // This sample shows how to write a simple unit test for a function, // using Google C++ testing framework. // // Writing a unit test using Google C++ testing framework is easy as 1-2-3: // Step 1. Include necessary header files such that the stuff your // test logic needs is declared. // // Don't forget gtest.h, which declares the testing framework. #include #include "sample1.h" #include // Step 2. Use the TEST macro to define your tests. // // TEST has two parameters: the test case name and the test name. // After using the macro, you should define your test logic between a // pair of braces. You can use a bunch of macros to indicate the // success or failure of a test. EXPECT_TRUE and EXPECT_EQ are // examples of such macros. For a complete list, see gtest.h. // // // // In Google Test, tests are grouped into test cases. This is how we // keep test code organized. You should put logically related tests // into the same test case. // // The test case name and the test name should both be valid C++ // identifiers. And you should not use underscore (_) in the names. // // Google Test guarantees that each test you define is run exactly // once, but it makes no guarantee on the order the tests are // executed. Therefore, you should write your tests in such a way // that their results don't depend on their order. // // // Tests Factorial(). // Tests factorial of negative numbers. TEST(FactorialTest, Negative) { // This test is named "Negative", and belongs to the "FactorialTest" // test case. EXPECT_EQ(1, Factorial(-5)); EXPECT_EQ(1, Factorial(-1)); EXPECT_TRUE(Factorial(-10) > 0); // // // EXPECT_EQ(expected, actual) is the same as // // EXPECT_TRUE((expected) == (actual)) // // except that it will print both the expected value and the actual // value when the assertion fails. This is very helpful for // debugging. Therefore in this case EXPECT_EQ is preferred. // // On the other hand, EXPECT_TRUE accepts any Boolean expression, // and is thus more general. // // } // Tests factorial of 0. TEST(FactorialTest, Zero) { EXPECT_EQ(1, Factorial(0)); } // Tests factorial of positive numbers. TEST(FactorialTest, Positive) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } // Tests IsPrime() // Tests negative input. TEST(IsPrimeTest, Negative) { // This test belongs to the IsPrimeTest test case. EXPECT_FALSE(IsPrime(-1)); EXPECT_FALSE(IsPrime(-2)); EXPECT_FALSE(IsPrime(INT_MIN)); } // Tests some trivial cases. TEST(IsPrimeTest, Trivial) { EXPECT_FALSE(IsPrime(0)); EXPECT_FALSE(IsPrime(1)); EXPECT_TRUE(IsPrime(2)); EXPECT_TRUE(IsPrime(3)); } // Tests positive input. TEST(IsPrimeTest, Positive) { EXPECT_FALSE(IsPrime(4)); EXPECT_TRUE(IsPrime(5)); EXPECT_FALSE(IsPrime(6)); EXPECT_TRUE(IsPrime(23)); } // Step 3. Call RUN_ALL_TESTS() in main(). // // We do this by linking in src/gtest_main.cc file, which consists of // a main() function which calls RUN_ALL_TESTS() for us. // // This runs all the tests you've defined, prints the result, and // returns 0 if successful, or 1 otherwise. // // Did you notice that we didn't register the tests? The // RUN_ALL_TESTS() macro magically knows about all the tests we // defined. Isn't this convenient? ceph-0.80.11/src/gtest/samples/sample9_unittest.cc0000664000175100017510000001346412623076744024106 0ustar jenkins-buildjenkins-build// Copyright 2009 Google Inc. 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. // // Author: vladl@google.com (Vlad Losev) // This sample shows how to use Google Test listener API to implement // an alternative console output and how to use the UnitTest reflection API // to enumerate test cases and tests and to inspect their results. #include #include using ::testing::EmptyTestEventListener; using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::TestCase; using ::testing::TestEventListeners; using ::testing::TestInfo; using ::testing::TestPartResult; using ::testing::UnitTest; namespace { // Provides alternative output mode which produces minimal amount of // information about tests. class TersePrinter : public EmptyTestEventListener { private: // Called before any test activity starts. virtual void OnTestProgramStart(const UnitTest& /* unit_test */) {} // Called after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) { fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED"); fflush(stdout); } // Called before a test starts. virtual void OnTestStart(const TestInfo& test_info) { fprintf(stdout, "*** Test %s.%s starting.\n", test_info.test_case_name(), test_info.name()); fflush(stdout); } // Called after a failed assertion or a SUCCESS(). virtual void OnTestPartResult(const TestPartResult& test_part_result) { fprintf(stdout, "%s in %s:%d\n%s\n", test_part_result.failed() ? "*** Failure" : "Success", test_part_result.file_name(), test_part_result.line_number(), test_part_result.summary()); fflush(stdout); } // Called after a test ends. virtual void OnTestEnd(const TestInfo& test_info) { fprintf(stdout, "*** Test %s.%s ending.\n", test_info.test_case_name(), test_info.name()); fflush(stdout); } }; // class TersePrinter TEST(CustomOutputTest, PrintsMessage) { printf("Printing something from the test body...\n"); } TEST(CustomOutputTest, Succeeds) { SUCCEED() << "SUCCEED() has been invoked from here"; } TEST(CustomOutputTest, Fails) { EXPECT_EQ(1, 2) << "This test fails in order to demonstrate alternative failure messages"; } } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); bool terse_output = false; if (argc > 1 && strcmp(argv[1], "--terse_output") == 0 ) terse_output = true; else printf("%s\n", "Run this program with --terse_output to change the way " "it prints its output."); UnitTest& unit_test = *UnitTest::GetInstance(); // If we are given the --terse_output command line flag, suppresses the // standard output and attaches own result printer. if (terse_output) { TestEventListeners& listeners = unit_test.listeners(); // Removes the default console output listener from the list so it will // not receive events from Google Test and won't print any output. Since // this operation transfers ownership of the listener to the caller we // have to delete it as well. delete listeners.Release(listeners.default_result_printer()); // Adds the custom output listener to the list. It will now receive // events from Google Test and print the alternative output. We don't // have to worry about deleting it since Google Test assumes ownership // over it after adding it to the list. listeners.Append(new TersePrinter); } int ret_val = RUN_ALL_TESTS(); // This is an example of using the UnitTest reflection API to inspect test // results. Here we discount failures from the tests we expected to fail. int unexpectedly_failed_tests = 0; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); // Counts failed tests that were not meant to fail (those without // 'Fails' in the name). if (test_info.result()->Failed() && strcmp(test_info.name(), "Fails") != 0) { unexpectedly_failed_tests++; } } } // Test that were meant to fail should not affect the test program outcome. if (unexpectedly_failed_tests == 0) ret_val = 0; return ret_val; } ceph-0.80.11/src/gtest/test/0000775000175100017510000000000012623077036017564 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/test/gtest-tuple_test.cc0000664000175100017510000002204212623076744023414 0ustar jenkins-buildjenkins-build// Copyright 2007, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include #include namespace { using ::std::tr1::get; using ::std::tr1::make_tuple; using ::std::tr1::tuple; using ::std::tr1::tuple_element; using ::std::tr1::tuple_size; using ::testing::StaticAssertTypeEq; // Tests that tuple_element >::type returns TK. TEST(tuple_element_Test, ReturnsElementType) { StaticAssertTypeEq >::type>(); StaticAssertTypeEq >::type>(); StaticAssertTypeEq >::type>(); } // Tests that tuple_size::value gives the number of fields in tuple // type T. TEST(tuple_size_Test, ReturnsNumberOfFields) { EXPECT_EQ(0, +tuple_size >::value); EXPECT_EQ(1, +tuple_size >::value); EXPECT_EQ(1, +tuple_size >::value); EXPECT_EQ(1, +(tuple_size > >::value)); EXPECT_EQ(2, +(tuple_size >::value)); EXPECT_EQ(3, +(tuple_size >::value)); } // Tests comparing a tuple with itself. TEST(ComparisonTest, ComparesWithSelf) { const tuple a(5, 'a', false); EXPECT_TRUE(a == a); EXPECT_FALSE(a != a); } // Tests comparing two tuples with the same value. TEST(ComparisonTest, ComparesEqualTuples) { const tuple a(5, true), b(5, true); EXPECT_TRUE(a == b); EXPECT_FALSE(a != b); } // Tests comparing two different tuples that have no reference fields. TEST(ComparisonTest, ComparesUnequalTuplesWithoutReferenceFields) { typedef tuple FooTuple; const FooTuple a(0, 'x'); const FooTuple b(1, 'a'); EXPECT_TRUE(a != b); EXPECT_FALSE(a == b); const FooTuple c(1, 'b'); EXPECT_TRUE(b != c); EXPECT_FALSE(b == c); } // Tests comparing two different tuples that have reference fields. TEST(ComparisonTest, ComparesUnequalTuplesWithReferenceFields) { typedef tuple FooTuple; int i = 5; const char ch = 'a'; const FooTuple a(i, ch); int j = 6; const FooTuple b(j, ch); EXPECT_TRUE(a != b); EXPECT_FALSE(a == b); j = 5; const char ch2 = 'b'; const FooTuple c(j, ch2); EXPECT_TRUE(b != c); EXPECT_FALSE(b == c); } // Tests that a tuple field with a reference type is an alias of the // variable it's supposed to reference. TEST(ReferenceFieldTest, IsAliasOfReferencedVariable) { int n = 0; tuple t(true, n); n = 1; EXPECT_EQ(n, get<1>(t)) << "Changing a underlying variable should update the reference field."; // Makes sure that the implementation doesn't do anything funny with // the & operator for the return type of get<>(). EXPECT_EQ(&n, &(get<1>(t))) << "The address of a reference field should equal the address of " << "the underlying variable."; get<1>(t) = 2; EXPECT_EQ(2, n) << "Changing a reference field should update the underlying variable."; } // Tests that tuple's default constructor default initializes each field. // This test needs to compile without generating warnings. TEST(TupleConstructorTest, DefaultConstructorDefaultInitializesEachField) { // The TR1 report requires that tuple's default constructor default // initializes each field, even if it's a primitive type. If the // implementation forgets to do this, this test will catch it by // generating warnings about using uninitialized variables (assuming // a decent compiler). tuple<> empty; tuple a1, b1; b1 = a1; EXPECT_EQ(0, get<0>(b1)); tuple a2, b2; b2 = a2; EXPECT_EQ(0, get<0>(b2)); EXPECT_EQ(0.0, get<1>(b2)); tuple a3, b3; b3 = a3; EXPECT_EQ(0.0, get<0>(b3)); EXPECT_EQ('\0', get<1>(b3)); EXPECT_TRUE(get<2>(b3) == NULL); tuple a10, b10; b10 = a10; EXPECT_EQ(0, get<0>(b10)); EXPECT_EQ(0, get<1>(b10)); EXPECT_EQ(0, get<2>(b10)); EXPECT_EQ(0, get<3>(b10)); EXPECT_EQ(0, get<4>(b10)); EXPECT_EQ(0, get<5>(b10)); EXPECT_EQ(0, get<6>(b10)); EXPECT_EQ(0, get<7>(b10)); EXPECT_EQ(0, get<8>(b10)); EXPECT_EQ(0, get<9>(b10)); } // Tests constructing a tuple from its fields. TEST(TupleConstructorTest, ConstructsFromFields) { int n = 1; // Reference field. tuple a(n); EXPECT_EQ(&n, &(get<0>(a))); // Non-reference fields. tuple b(5, 'a'); EXPECT_EQ(5, get<0>(b)); EXPECT_EQ('a', get<1>(b)); // Const reference field. const int m = 2; tuple c(true, m); EXPECT_TRUE(get<0>(c)); EXPECT_EQ(&m, &(get<1>(c))); } // Tests tuple's copy constructor. TEST(TupleConstructorTest, CopyConstructor) { tuple a(0.0, true); tuple b(a); EXPECT_DOUBLE_EQ(0.0, get<0>(b)); EXPECT_TRUE(get<1>(b)); } // Tests constructing a tuple from another tuple that has a compatible // but different type. TEST(TupleConstructorTest, ConstructsFromDifferentTupleType) { tuple a(0, 1, 'a'); tuple b(a); EXPECT_DOUBLE_EQ(0.0, get<0>(b)); EXPECT_EQ(1, get<1>(b)); EXPECT_EQ('a', get<2>(b)); } // Tests constructing a 2-tuple from an std::pair. TEST(TupleConstructorTest, ConstructsFromPair) { ::std::pair a(1, 'a'); tuple b(a); tuple c(a); } // Tests assigning a tuple to another tuple with the same type. TEST(TupleAssignmentTest, AssignsToSameTupleType) { const tuple a(5, 7L); tuple b; b = a; EXPECT_EQ(5, get<0>(b)); EXPECT_EQ(7L, get<1>(b)); } // Tests assigning a tuple to another tuple with a different but // compatible type. TEST(TupleAssignmentTest, AssignsToDifferentTupleType) { const tuple a(1, 7L, true); tuple b; b = a; EXPECT_EQ(1L, get<0>(b)); EXPECT_EQ(7, get<1>(b)); EXPECT_TRUE(get<2>(b)); } // Tests assigning an std::pair to a 2-tuple. TEST(TupleAssignmentTest, AssignsFromPair) { const ::std::pair a(5, true); tuple b; b = a; EXPECT_EQ(5, get<0>(b)); EXPECT_TRUE(get<1>(b)); tuple c; c = a; EXPECT_EQ(5L, get<0>(c)); EXPECT_TRUE(get<1>(c)); } // A fixture for testing big tuples. class BigTupleTest : public testing::Test { protected: typedef tuple BigTuple; BigTupleTest() : a_(1, 0, 0, 0, 0, 0, 0, 0, 0, 2), b_(1, 0, 0, 0, 0, 0, 0, 0, 0, 3) {} BigTuple a_, b_; }; // Tests constructing big tuples. TEST_F(BigTupleTest, Construction) { BigTuple a; BigTuple b(b_); } // Tests that get(t) returns the N-th (0-based) field of tuple t. TEST_F(BigTupleTest, get) { EXPECT_EQ(1, get<0>(a_)); EXPECT_EQ(2, get<9>(a_)); // Tests that get() works on a const tuple too. const BigTuple a(a_); EXPECT_EQ(1, get<0>(a)); EXPECT_EQ(2, get<9>(a)); } // Tests comparing big tuples. TEST_F(BigTupleTest, Comparisons) { EXPECT_TRUE(a_ == a_); EXPECT_FALSE(a_ != a_); EXPECT_TRUE(a_ != b_); EXPECT_FALSE(a_ == b_); } TEST(MakeTupleTest, WorksForScalarTypes) { tuple a; a = make_tuple(true, 5); EXPECT_TRUE(get<0>(a)); EXPECT_EQ(5, get<1>(a)); tuple b; b = make_tuple('a', 'b', 5); EXPECT_EQ('a', get<0>(b)); EXPECT_EQ('b', get<1>(b)); EXPECT_EQ(5, get<2>(b)); } TEST(MakeTupleTest, WorksForPointers) { int a[] = { 1, 2, 3, 4 }; const char* const str = "hi"; int* const p = a; tuple t; t = make_tuple(str, p); EXPECT_EQ(str, get<0>(t)); EXPECT_EQ(p, get<1>(t)); } } // namespace ceph-0.80.11/src/gtest/test/gtest_xml_output_unittest.py0000775000175100017510000002275712623076744025550 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2006, Google Inc. # 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. """Unit test for the gtest_xml_output module""" __author__ = 'eefacm@gmail.com (Sean Mcafee)' import errno import os import sys from xml.dom import minidom, Node import gtest_test_utils import gtest_xml_test_utils GTEST_OUTPUT_FLAG = "--gtest_output" GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_" SUPPORTS_STACK_TRACES = False if SUPPORTS_STACK_TRACES: STACK_TRACE_TEMPLATE = "\nStack trace:\n*" else: STACK_TRACE_TEMPLATE = "" EXPECTED_NON_EMPTY_XML = """ ]]>%(stack)s]]> """ % {'stack': STACK_TRACE_TEMPLATE} EXPECTED_EMPTY_XML = """ """ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): """ Unit test for Google Test's XML output functionality. """ def testNonEmptyXmlOutput(self): """ Runs a test program that generates a non-empty XML output, and tests that the XML output is expected. """ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1) def testEmptyXmlOutput(self): """ Runs a test program that generates an empty XML output, and tests that the XML output is expected. """ self._TestXmlOutput("gtest_no_test_unittest", EXPECTED_EMPTY_XML, 0) def testDefaultOutputFile(self): """ Confirms that Google Test produces an XML output file with the expected default name if no name is explicitly specified. """ output_file = os.path.join(gtest_test_utils.GetTempDir(), GTEST_DEFAULT_OUTPUT_FILE) gtest_prog_path = gtest_test_utils.GetTestExecutablePath( "gtest_no_test_unittest") try: os.remove(output_file) except OSError, e: if e.errno != errno.ENOENT: raise p = gtest_test_utils.Subprocess( [gtest_prog_path, "%s=xml" % GTEST_OUTPUT_FLAG], working_dir=gtest_test_utils.GetTempDir()) self.assert_(p.exited) self.assertEquals(0, p.exit_code) self.assert_(os.path.isfile(output_file)) def testSuppressedXmlOutput(self): """ Tests that no XML file is generated if the default XML listener is shut down before RUN_ALL_TESTS is invoked. """ xml_path = os.path.join(gtest_test_utils.GetTempDir(), GTEST_PROGRAM_NAME + "out.xml") if os.path.isfile(xml_path): os.remove(xml_path) gtest_prog_path = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) command = [gtest_prog_path, "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path), "--shut_down_xml"] p = gtest_test_utils.Subprocess(command) if p.terminated_by_signal: self.assert_(False, "%s was killed by signal %d" % (gtest_prog_name, p.signal)) else: self.assert_(p.exited) self.assertEquals(1, p.exit_code, "'%s' exited with code %s, which doesn't match " "the expected exit code %s." % (command, p.exit_code, 1)) self.assert_(not os.path.isfile(xml_path)) def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code): """ Asserts that the XML document generated by running the program gtest_prog_name matches expected_xml, a string containing another XML document. Furthermore, the program's exit code must be expected_exit_code. """ xml_path = os.path.join(gtest_test_utils.GetTempDir(), gtest_prog_name + "out.xml") gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name) command = [gtest_prog_path, "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path)] p = gtest_test_utils.Subprocess(command) if p.terminated_by_signal: self.assert_(False, "%s was killed by signal %d" % (gtest_prog_name, p.signal)) else: self.assert_(p.exited) self.assertEquals(expected_exit_code, p.exit_code, "'%s' exited with code %s, which doesn't match " "the expected exit code %s." % (command, p.exit_code, expected_exit_code)) expected = minidom.parseString(expected_xml) actual = minidom.parse(xml_path) self.NormalizeXml(actual.documentElement) self.AssertEquivalentNodes(expected.documentElement, actual.documentElement) expected.unlink() actual .unlink() if __name__ == '__main__': os.environ['GTEST_STACK_TRACE_DEPTH'] = '1' gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_main_unittest.cc0000664000175100017510000000354012623076744024173 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include // Tests that we don't have to define main() when we link to // gtest_main instead of gtest. namespace { TEST(GTestMainTest, ShouldSucceed) { } } // namespace // We are using the main() function defined in src/gtest_main.cc, so // we don't define it here. ceph-0.80.11/src/gtest/test/gtest_output_test.py0000775000175100017510000002652112623076744023761 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """Tests the text output of Google C++ Testing Framework. SYNOPSIS gtest_output_test.py --gtest_build_dir=BUILD/DIR --gengolden # where BUILD/DIR contains the built gtest_output_test_ file. gtest_output_test.py --gengolden gtest_output_test.py """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sys import gtest_test_utils # The flag for generating the golden file GENGOLDEN_FLAG = '--gengolden' CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS' IS_WINDOWS = os.name == 'nt' if IS_WINDOWS: GOLDEN_NAME = 'gtest_output_test_golden_win.txt' else: GOLDEN_NAME = 'gtest_output_test_golden_lin.txt' PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_') # At least one command we exercise must not have the # --gtest_internal_skip_environment_and_ad_hoc_tests flag. COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests']) COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes']) COMMAND_WITH_TIME = ({}, [PROGRAM_PATH, '--gtest_print_time', '--gtest_internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=FatalFailureTest.*:LoggingTest.*']) COMMAND_WITH_DISABLED = ( {}, [PROGRAM_PATH, '--gtest_also_run_disabled_tests', '--gtest_internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=*DISABLED_*']) COMMAND_WITH_SHARDING = ( {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, [PROGRAM_PATH, '--gtest_internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=PassingTest.*']) GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME) def ToUnixLineEnding(s): """Changes all Windows/Mac line endings in s to UNIX line endings.""" return s.replace('\r\n', '\n').replace('\r', '\n') def RemoveLocations(test_output): """Removes all file location info from a Google Test program's output. Args: test_output: the output of a Google Test program. Returns: output with all file location info (in the form of 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by 'FILE_NAME:#: '. """ return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output) def RemoveStackTraceDetails(output): """Removes all stack traces from a Google Test program's output.""" # *? means "find the shortest string that matches". return re.sub(r'Stack trace:(.|\n)*?\n\n', 'Stack trace: (omitted)\n\n', output) def RemoveStackTraces(output): """Removes all traces of stack traces from a Google Test program's output.""" # *? means "find the shortest string that matches". return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output) def RemoveTime(output): """Removes all time information from a Google Test program's output.""" return re.sub(r'\(\d+ ms', '(? ms', output) def RemoveTypeInfoDetails(test_output): """Removes compiler-specific type info from Google Test program's output. Args: test_output: the output of a Google Test program. Returns: output with type information normalized to canonical form. """ # some compilers output the name of type 'unsigned int' as 'unsigned' return re.sub(r'unsigned int', 'unsigned', test_output) def RemoveTestCounts(output): """Removes test counts from a Google Test program's output.""" output = re.sub(r'\d+ tests?, listed below', '? tests, listed below', output) output = re.sub(r'\d+ FAILED TESTS', '? FAILED TESTS', output) output = re.sub(r'\d+ tests? from \d+ test cases?', '? tests from ? test cases', output) output = re.sub(r'\d+ tests? from ([a-zA-Z_])', r'? tests from \1', output) return re.sub(r'\d+ tests?\.', '? tests.', output) def RemoveMatchingTests(test_output, pattern): """Removes output of specified tests from a Google Test program's output. This function strips not only the beginning and the end of a test but also all output in between. Args: test_output: A string containing the test output. pattern: A regex string that matches names of test cases or tests to remove. Returns: Contents of test_output with tests whose names match pattern removed. """ test_output = re.sub( r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % ( pattern, pattern), '', test_output) return re.sub(r'.*%s.*\n' % pattern, '', test_output) def NormalizeOutput(output): """Normalizes output (the output of gtest_output_test_.exe).""" output = ToUnixLineEnding(output) output = RemoveLocations(output) output = RemoveStackTraceDetails(output) output = RemoveTime(output) return output def GetShellCommandOutput(env_cmd): """Runs a command in a sub-process, and returns its output in a string. Args: env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra environment variables to set, and element 1 is a string with the command and any flags. Returns: A string with the command's combined standard and diagnostic output. """ # Spawns cmd in a sub-process, and gets its standard I/O file objects. # Set and save the environment properly. environ = os.environ.copy() environ.update(env_cmd[0]) p = gtest_test_utils.Subprocess(env_cmd[1], env=environ) return p.output def GetCommandOutput(env_cmd): """Runs a command and returns its output with all file location info stripped off. Args: env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra environment variables to set, and element 1 is a string with the command and any flags. """ # Disables exception pop-ups on Windows. environ, cmdline = env_cmd environ = dict(environ) # Ensures we are modifying a copy. environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1' return NormalizeOutput(GetShellCommandOutput((environ, cmdline))) def GetOutputOfAllCommands(): """Returns concatenated output from several representative commands.""" return (GetCommandOutput(COMMAND_WITH_COLOR) + GetCommandOutput(COMMAND_WITH_TIME) + GetCommandOutput(COMMAND_WITH_DISABLED) + GetCommandOutput(COMMAND_WITH_SHARDING)) test_list = GetShellCommandOutput(COMMAND_LIST_TESTS) SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list SUPPORTS_STACK_TRACES = False CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and SUPPORTS_TYPED_TESTS and SUPPORTS_THREADS) class GTestOutputTest(gtest_test_utils.TestCase): def RemoveUnsupportedTests(self, test_output): if not SUPPORTS_DEATH_TESTS: test_output = RemoveMatchingTests(test_output, 'DeathTest') if not SUPPORTS_TYPED_TESTS: test_output = RemoveMatchingTests(test_output, 'TypedTest') test_output = RemoveMatchingTests(test_output, 'TypedDeathTest') test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest') if not SUPPORTS_THREADS: test_output = RemoveMatchingTests(test_output, 'ExpectFailureWithThreadsTest') test_output = RemoveMatchingTests(test_output, 'ScopedFakeTestPartResultReporterTest') test_output = RemoveMatchingTests(test_output, 'WorksConcurrently') if not SUPPORTS_STACK_TRACES: test_output = RemoveStackTraces(test_output) return test_output def testOutput(self): output = GetOutputOfAllCommands() golden_file = open(GOLDEN_PATH, 'rb') # A mis-configured source control system can cause \r appear in EOL # sequences when we read the golden file irrespective of an operating # system used. Therefore, we need to strip those \r's from newlines # unconditionally. golden = ToUnixLineEnding(golden_file.read()) golden_file.close() # We want the test to pass regardless of certain features being # supported or not. # We still have to remove type name specifics in all cases. normalized_actual = RemoveTypeInfoDetails(output) normalized_golden = RemoveTypeInfoDetails(golden) if CAN_GENERATE_GOLDEN_FILE: self.assertEqual(normalized_golden, normalized_actual) else: normalized_actual = RemoveTestCounts(normalized_actual) normalized_golden = RemoveTestCounts(self.RemoveUnsupportedTests( normalized_golden)) # This code is very handy when debugging golden file differences: if os.getenv('DEBUG_GTEST_OUTPUT_TEST'): open(os.path.join( gtest_test_utils.GetSourceDir(), '_gtest_output_test_normalized_actual.txt'), 'wb').write( normalized_actual) open(os.path.join( gtest_test_utils.GetSourceDir(), '_gtest_output_test_normalized_golden.txt'), 'wb').write( normalized_golden) self.assertEqual(normalized_golden, normalized_actual) if __name__ == '__main__': if sys.argv[1:] == [GENGOLDEN_FLAG]: if CAN_GENERATE_GOLDEN_FILE: output = GetOutputOfAllCommands() golden_file = open(GOLDEN_PATH, 'wb') golden_file.write(output) golden_file.close() else: message = ( """Unable to write a golden file when compiled in an environment that does not support all the required features (death tests""") if IS_WINDOWS: message += ( """\nand typed tests). Please check that you are using VC++ 8.0 SP1 or higher as your compiler.""") else: message += """\ntyped tests, and threads). Please generate the golden file using a binary built with those features enabled.""" sys.stderr.write(message) sys.exit(1) else: gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest-port_test.cc0000664000175100017510000007642612623076744023266 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Authors: vladl@google.com (Vlad Losev), wan@google.com (Zhanyong Wan) // // This file tests the internal cross-platform support utilities. #include #include #if GTEST_OS_MAC #include #endif // GTEST_OS_MAC #include // For std::pair and std::make_pair. #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ using std::make_pair; using std::pair; namespace testing { namespace internal { // Tests that the element_type typedef is available in scoped_ptr and refers // to the parameter type. TEST(ScopedPtrTest, DefinesElementType) { StaticAssertTypeEq::element_type>(); } // TODO(vladl@google.com): Implement THE REST of scoped_ptr tests. TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { if (AlwaysFalse()) GTEST_CHECK_(false) << "This should never be executed; " "It's a compilation test only."; if (AlwaysTrue()) GTEST_CHECK_(true); else ; // NOLINT if (AlwaysFalse()) ; // NOLINT else GTEST_CHECK_(true) << ""; } TEST(GtestCheckSyntaxTest, WorksWithSwitch) { switch (0) { case 1: break; default: GTEST_CHECK_(true); } switch(0) case 0: GTEST_CHECK_(true) << "Check failed in switch case"; } #if GTEST_OS_MAC void* ThreadFunc(void* data) { pthread_mutex_t* mutex = static_cast(data); pthread_mutex_lock(mutex); pthread_mutex_unlock(mutex); return NULL; } TEST(GetThreadCountTest, ReturnsCorrectValue) { EXPECT_EQ(1U, GetThreadCount()); pthread_mutex_t mutex; pthread_attr_t attr; pthread_t thread_id; // TODO(vladl@google.com): turn mutex into internal::Mutex for automatic // destruction. pthread_mutex_init(&mutex, NULL); pthread_mutex_lock(&mutex); ASSERT_EQ(0, pthread_attr_init(&attr)); ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); ASSERT_EQ(0, pthread_attr_destroy(&attr)); ASSERT_EQ(0, status); EXPECT_EQ(2U, GetThreadCount()); pthread_mutex_unlock(&mutex); void* dummy; ASSERT_EQ(0, pthread_join(thread_id, &dummy)); // MacOS X may not immediately report the updated thread count after // joining a thread, causing flakiness in this test. To counter that, we // wait for up to .5 seconds for the OS to report the correct value. for (int i = 0; i < 5; ++i) { if (GetThreadCount() == 1) break; SleepMilliseconds(100); } EXPECT_EQ(1U, GetThreadCount()); pthread_mutex_destroy(&mutex); } #else TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { EXPECT_EQ(0U, GetThreadCount()); } #endif // GTEST_OS_MAC TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; const char regex[] = #ifdef _MSC_VER "gtest-port_test\\.cc\\(\\d+\\):" #else "gtest-port_test\\.cc:[0-9]+" #endif // _MSC_VER ".*a_false_condition.*Extra info.*"; EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", regex); } #if GTEST_HAS_DEATH_TEST TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { EXPECT_EXIT({ GTEST_CHECK_(true) << "Extra info"; ::std::cerr << "Success\n"; exit(0); }, ::testing::ExitedWithCode(0), "Success"); } #endif // GTEST_HAS_DEATH_TEST #if GTEST_USES_POSIX_RE #if GTEST_HAS_TYPED_TEST template class RETest : public ::testing::Test {}; // Defines StringTypes as the list of all string types that class RE // supports. typedef testing::Types< ::std::string, #if GTEST_HAS_GLOBAL_STRING ::string, #endif // GTEST_HAS_GLOBAL_STRING const char*> StringTypes; TYPED_TEST_CASE(RETest, StringTypes); // Tests RE's implicit constructors. TYPED_TEST(RETest, ImplicitConstructorWorks) { const RE empty(TypeParam("")); EXPECT_STREQ("", empty.pattern()); const RE simple(TypeParam("hello")); EXPECT_STREQ("hello", simple.pattern()); const RE normal(TypeParam(".*(\\w+)")); EXPECT_STREQ(".*(\\w+)", normal.pattern()); } // Tests that RE's constructors reject invalid regular expressions. TYPED_TEST(RETest, RejectsInvalidRegex) { EXPECT_NONFATAL_FAILURE({ const RE invalid(TypeParam("?")); }, "\"?\" is not a valid POSIX Extended regular expression."); } // Tests RE::FullMatch(). TYPED_TEST(RETest, FullMatchWorks) { const RE empty(TypeParam("")); EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty)); EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty)); const RE re(TypeParam("a.*z")); EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re)); EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re)); EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re)); EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re)); } // Tests RE::PartialMatch(). TYPED_TEST(RETest, PartialMatchWorks) { const RE empty(TypeParam("")); EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty)); EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty)); const RE re(TypeParam("a.*z")); EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re)); EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re)); EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re)); EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re)); EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re)); } #endif // GTEST_HAS_TYPED_TEST #elif GTEST_USES_SIMPLE_RE TEST(IsInSetTest, NulCharIsNotInAnySet) { EXPECT_FALSE(IsInSet('\0', "")); EXPECT_FALSE(IsInSet('\0', "\0")); EXPECT_FALSE(IsInSet('\0', "a")); } TEST(IsInSetTest, WorksForNonNulChars) { EXPECT_FALSE(IsInSet('a', "Ab")); EXPECT_FALSE(IsInSet('c', "")); EXPECT_TRUE(IsInSet('b', "bcd")); EXPECT_TRUE(IsInSet('b', "ab")); } TEST(IsDigitTest, IsFalseForNonDigit) { EXPECT_FALSE(IsDigit('\0')); EXPECT_FALSE(IsDigit(' ')); EXPECT_FALSE(IsDigit('+')); EXPECT_FALSE(IsDigit('-')); EXPECT_FALSE(IsDigit('.')); EXPECT_FALSE(IsDigit('a')); } TEST(IsDigitTest, IsTrueForDigit) { EXPECT_TRUE(IsDigit('0')); EXPECT_TRUE(IsDigit('1')); EXPECT_TRUE(IsDigit('5')); EXPECT_TRUE(IsDigit('9')); } TEST(IsPunctTest, IsFalseForNonPunct) { EXPECT_FALSE(IsPunct('\0')); EXPECT_FALSE(IsPunct(' ')); EXPECT_FALSE(IsPunct('\n')); EXPECT_FALSE(IsPunct('a')); EXPECT_FALSE(IsPunct('0')); } TEST(IsPunctTest, IsTrueForPunct) { for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { EXPECT_PRED1(IsPunct, *p); } } TEST(IsRepeatTest, IsFalseForNonRepeatChar) { EXPECT_FALSE(IsRepeat('\0')); EXPECT_FALSE(IsRepeat(' ')); EXPECT_FALSE(IsRepeat('a')); EXPECT_FALSE(IsRepeat('1')); EXPECT_FALSE(IsRepeat('-')); } TEST(IsRepeatTest, IsTrueForRepeatChar) { EXPECT_TRUE(IsRepeat('?')); EXPECT_TRUE(IsRepeat('*')); EXPECT_TRUE(IsRepeat('+')); } TEST(IsWhiteSpaceTest, IsFalseForNonWhiteSpace) { EXPECT_FALSE(IsWhiteSpace('\0')); EXPECT_FALSE(IsWhiteSpace('a')); EXPECT_FALSE(IsWhiteSpace('1')); EXPECT_FALSE(IsWhiteSpace('+')); EXPECT_FALSE(IsWhiteSpace('_')); } TEST(IsWhiteSpaceTest, IsTrueForWhiteSpace) { EXPECT_TRUE(IsWhiteSpace(' ')); EXPECT_TRUE(IsWhiteSpace('\n')); EXPECT_TRUE(IsWhiteSpace('\r')); EXPECT_TRUE(IsWhiteSpace('\t')); EXPECT_TRUE(IsWhiteSpace('\v')); EXPECT_TRUE(IsWhiteSpace('\f')); } TEST(IsWordCharTest, IsFalseForNonWordChar) { EXPECT_FALSE(IsWordChar('\0')); EXPECT_FALSE(IsWordChar('+')); EXPECT_FALSE(IsWordChar('.')); EXPECT_FALSE(IsWordChar(' ')); EXPECT_FALSE(IsWordChar('\n')); } TEST(IsWordCharTest, IsTrueForLetter) { EXPECT_TRUE(IsWordChar('a')); EXPECT_TRUE(IsWordChar('b')); EXPECT_TRUE(IsWordChar('A')); EXPECT_TRUE(IsWordChar('Z')); } TEST(IsWordCharTest, IsTrueForDigit) { EXPECT_TRUE(IsWordChar('0')); EXPECT_TRUE(IsWordChar('1')); EXPECT_TRUE(IsWordChar('7')); EXPECT_TRUE(IsWordChar('9')); } TEST(IsWordCharTest, IsTrueForUnderscore) { EXPECT_TRUE(IsWordChar('_')); } TEST(IsValidEscapeTest, IsFalseForNonPrintable) { EXPECT_FALSE(IsValidEscape('\0')); EXPECT_FALSE(IsValidEscape('\007')); } TEST(IsValidEscapeTest, IsFalseForDigit) { EXPECT_FALSE(IsValidEscape('0')); EXPECT_FALSE(IsValidEscape('9')); } TEST(IsValidEscapeTest, IsFalseForWhiteSpace) { EXPECT_FALSE(IsValidEscape(' ')); EXPECT_FALSE(IsValidEscape('\n')); } TEST(IsValidEscapeTest, IsFalseForSomeLetter) { EXPECT_FALSE(IsValidEscape('a')); EXPECT_FALSE(IsValidEscape('Z')); } TEST(IsValidEscapeTest, IsTrueForPunct) { EXPECT_TRUE(IsValidEscape('.')); EXPECT_TRUE(IsValidEscape('-')); EXPECT_TRUE(IsValidEscape('^')); EXPECT_TRUE(IsValidEscape('$')); EXPECT_TRUE(IsValidEscape('(')); EXPECT_TRUE(IsValidEscape(']')); EXPECT_TRUE(IsValidEscape('{')); EXPECT_TRUE(IsValidEscape('|')); } TEST(IsValidEscapeTest, IsTrueForSomeLetter) { EXPECT_TRUE(IsValidEscape('d')); EXPECT_TRUE(IsValidEscape('D')); EXPECT_TRUE(IsValidEscape('s')); EXPECT_TRUE(IsValidEscape('S')); EXPECT_TRUE(IsValidEscape('w')); EXPECT_TRUE(IsValidEscape('W')); } TEST(AtomMatchesCharTest, EscapedPunct) { EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0')); EXPECT_FALSE(AtomMatchesChar(true, '\\', ' ')); EXPECT_FALSE(AtomMatchesChar(true, '_', '.')); EXPECT_FALSE(AtomMatchesChar(true, '.', 'a')); EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\')); EXPECT_TRUE(AtomMatchesChar(true, '_', '_')); EXPECT_TRUE(AtomMatchesChar(true, '+', '+')); EXPECT_TRUE(AtomMatchesChar(true, '.', '.')); } TEST(AtomMatchesCharTest, Escaped_d) { EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a')); EXPECT_FALSE(AtomMatchesChar(true, 'd', '.')); EXPECT_TRUE(AtomMatchesChar(true, 'd', '0')); EXPECT_TRUE(AtomMatchesChar(true, 'd', '9')); } TEST(AtomMatchesCharTest, Escaped_D) { EXPECT_FALSE(AtomMatchesChar(true, 'D', '0')); EXPECT_FALSE(AtomMatchesChar(true, 'D', '9')); EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0')); EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a')); EXPECT_TRUE(AtomMatchesChar(true, 'D', '-')); } TEST(AtomMatchesCharTest, Escaped_s) { EXPECT_FALSE(AtomMatchesChar(true, 's', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 's', 'a')); EXPECT_FALSE(AtomMatchesChar(true, 's', '.')); EXPECT_FALSE(AtomMatchesChar(true, 's', '9')); EXPECT_TRUE(AtomMatchesChar(true, 's', ' ')); EXPECT_TRUE(AtomMatchesChar(true, 's', '\n')); EXPECT_TRUE(AtomMatchesChar(true, 's', '\t')); } TEST(AtomMatchesCharTest, Escaped_S) { EXPECT_FALSE(AtomMatchesChar(true, 'S', ' ')); EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r')); EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0')); EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a')); EXPECT_TRUE(AtomMatchesChar(true, 'S', '9')); } TEST(AtomMatchesCharTest, Escaped_w) { EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'w', '+')); EXPECT_FALSE(AtomMatchesChar(true, 'w', ' ')); EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n')); EXPECT_TRUE(AtomMatchesChar(true, 'w', '0')); EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b')); EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C')); EXPECT_TRUE(AtomMatchesChar(true, 'w', '_')); } TEST(AtomMatchesCharTest, Escaped_W) { EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A')); EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b')); EXPECT_FALSE(AtomMatchesChar(true, 'W', '9')); EXPECT_FALSE(AtomMatchesChar(true, 'W', '_')); EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0')); EXPECT_TRUE(AtomMatchesChar(true, 'W', '*')); EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n')); } TEST(AtomMatchesCharTest, EscapedWhiteSpace) { EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n')); EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r')); EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a')); EXPECT_FALSE(AtomMatchesChar(true, 't', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 't', 't')); EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f')); EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f')); EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n')); EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r')); EXPECT_TRUE(AtomMatchesChar(true, 't', '\t')); EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v')); } TEST(AtomMatchesCharTest, UnescapedDot) { EXPECT_FALSE(AtomMatchesChar(false, '.', '\n')); EXPECT_TRUE(AtomMatchesChar(false, '.', '\0')); EXPECT_TRUE(AtomMatchesChar(false, '.', '.')); EXPECT_TRUE(AtomMatchesChar(false, '.', 'a')); EXPECT_TRUE(AtomMatchesChar(false, '.', ' ')); } TEST(AtomMatchesCharTest, UnescapedChar) { EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0')); EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b')); EXPECT_FALSE(AtomMatchesChar(false, '$', 'a')); EXPECT_TRUE(AtomMatchesChar(false, '$', '$')); EXPECT_TRUE(AtomMatchesChar(false, '5', '5')); EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z')); } TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid) { EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)), "NULL is not a valid simple regular expression"); EXPECT_NONFATAL_FAILURE( ASSERT_FALSE(ValidateRegex("a\\")), "Syntax error at index 1 in simple regular expression \"a\\\": "); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")), "'\\' cannot appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")), "'\\' cannot appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")), "invalid escape sequence \"\\h\""); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")), "'^' can only appear at the beginning"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")), "'^' can only appear at the beginning"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")), "'$' can only appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")), "'$' can only appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")), "'(' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")), "')' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")), "'[' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")), "'{' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")), "'?' can only follow a repeatable token"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")), "'*' can only follow a repeatable token"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")), "'+' can only follow a repeatable token"); } TEST(ValidateRegexTest, ReturnsTrueForValid) { EXPECT_TRUE(ValidateRegex("")); EXPECT_TRUE(ValidateRegex("a")); EXPECT_TRUE(ValidateRegex(".*")); EXPECT_TRUE(ValidateRegex("^a_+")); EXPECT_TRUE(ValidateRegex("^a\\t\\&?")); EXPECT_TRUE(ValidateRegex("09*$")); EXPECT_TRUE(ValidateRegex("^Z$")); EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}")); } TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne) { EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba")); // Repeating more than once. EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab")); // Repeating zero times. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba")); // Repeating once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab")); EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##")); } TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany) { EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab")); // Repeating zero times. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc")); // Repeating once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc")); // Repeating more than once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g")); } TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany) { EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab")); // Repeating zero times. EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc")); // Repeating once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc")); // Repeating more than once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g")); } TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex) { EXPECT_TRUE(MatchRegexAtHead("", "")); EXPECT_TRUE(MatchRegexAtHead("", "ab")); } TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex) { EXPECT_FALSE(MatchRegexAtHead("$", "a")); EXPECT_TRUE(MatchRegexAtHead("$", "")); EXPECT_TRUE(MatchRegexAtHead("a$", "a")); } TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence) { EXPECT_FALSE(MatchRegexAtHead("\\w", "+")); EXPECT_FALSE(MatchRegexAtHead("\\W", "ab")); EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab")); EXPECT_TRUE(MatchRegexAtHead("\\d", "1a")); } TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) { EXPECT_FALSE(MatchRegexAtHead(".+a", "abc")); EXPECT_FALSE(MatchRegexAtHead("a?b", "aab")); EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab")); EXPECT_TRUE(MatchRegexAtHead("a?b", "b")); EXPECT_TRUE(MatchRegexAtHead("a?b", "ab")); } TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetionOfEscapeSequence) { EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc")); EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b")); EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab")); EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b")); EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b")); EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b")); } TEST(MatchRegexAtHeadTest, MatchesSequentially) { EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc")); EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc")); } TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull) { EXPECT_FALSE(MatchRegexAnywhere("", NULL)); } TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret) { EXPECT_FALSE(MatchRegexAnywhere("^a", "ba")); EXPECT_FALSE(MatchRegexAnywhere("^$", "a")); EXPECT_TRUE(MatchRegexAnywhere("^a", "ab")); EXPECT_TRUE(MatchRegexAnywhere("^", "ab")); EXPECT_TRUE(MatchRegexAnywhere("^$", "")); } TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch) { EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123")); EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888")); } TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix) { EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5")); EXPECT_TRUE(MatchRegexAnywhere(".*=", "=")); EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc")); } TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix) { EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5")); EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...=")); } // Tests RE's implicit constructors. TEST(RETest, ImplicitConstructorWorks) { const RE empty(""); EXPECT_STREQ("", empty.pattern()); const RE simple("hello"); EXPECT_STREQ("hello", simple.pattern()); } // Tests that RE's constructors reject invalid regular expressions. TEST(RETest, RejectsInvalidRegex) { EXPECT_NONFATAL_FAILURE({ const RE normal(NULL); }, "NULL is not a valid simple regular expression"); EXPECT_NONFATAL_FAILURE({ const RE normal(".*(\\w+"); }, "'(' is unsupported"); EXPECT_NONFATAL_FAILURE({ const RE invalid("^?"); }, "'?' can only follow a repeatable token"); } // Tests RE::FullMatch(). TEST(RETest, FullMatchWorks) { const RE empty(""); EXPECT_TRUE(RE::FullMatch("", empty)); EXPECT_FALSE(RE::FullMatch("a", empty)); const RE re1("a"); EXPECT_TRUE(RE::FullMatch("a", re1)); const RE re("a.*z"); EXPECT_TRUE(RE::FullMatch("az", re)); EXPECT_TRUE(RE::FullMatch("axyz", re)); EXPECT_FALSE(RE::FullMatch("baz", re)); EXPECT_FALSE(RE::FullMatch("azy", re)); } // Tests RE::PartialMatch(). TEST(RETest, PartialMatchWorks) { const RE empty(""); EXPECT_TRUE(RE::PartialMatch("", empty)); EXPECT_TRUE(RE::PartialMatch("a", empty)); const RE re("a.*z"); EXPECT_TRUE(RE::PartialMatch("az", re)); EXPECT_TRUE(RE::PartialMatch("axyz", re)); EXPECT_TRUE(RE::PartialMatch("baz", re)); EXPECT_TRUE(RE::PartialMatch("azy", re)); EXPECT_FALSE(RE::PartialMatch("zza", re)); } #endif // GTEST_USES_POSIX_RE #if !GTEST_OS_WINDOWS_MOBILE TEST(CaptureTest, CapturesStdout) { CaptureStdout(); fprintf(stdout, "abc"); EXPECT_STREQ("abc", GetCapturedStdout().c_str()); CaptureStdout(); fprintf(stdout, "def%cghi", '\0'); EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout())); } TEST(CaptureTest, CapturesStderr) { CaptureStderr(); fprintf(stderr, "jkl"); EXPECT_STREQ("jkl", GetCapturedStderr().c_str()); CaptureStderr(); fprintf(stderr, "jkl%cmno", '\0'); EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr())); } // Tests that stdout and stderr capture don't interfere with each other. TEST(CaptureTest, CapturesStdoutAndStderr) { CaptureStdout(); CaptureStderr(); fprintf(stdout, "pqr"); fprintf(stderr, "stu"); EXPECT_STREQ("pqr", GetCapturedStdout().c_str()); EXPECT_STREQ("stu", GetCapturedStderr().c_str()); } TEST(CaptureDeathTest, CannotReenterStdoutCapture) { CaptureStdout(); EXPECT_DEATH_IF_SUPPORTED(CaptureStdout();, "Only one stdout capturer can exist at a time"); GetCapturedStdout(); // We cannot test stderr capturing using death tests as they use it // themselves. } #endif // !GTEST_OS_WINDOWS_MOBILE TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) { ThreadLocal t1; EXPECT_EQ(0, t1.get()); ThreadLocal t2; EXPECT_TRUE(t2.get() == NULL); } TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) { ThreadLocal t1(123); EXPECT_EQ(123, t1.get()); int i = 0; ThreadLocal t2(&i); EXPECT_EQ(&i, t2.get()); } class NoDefaultContructor { public: explicit NoDefaultContructor(const char*) {} NoDefaultContructor(const NoDefaultContructor&) {} }; TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { ThreadLocal bar(NoDefaultContructor("foo")); bar.pointer(); } TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { ThreadLocal thread_local; EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); // Verifies the condition still holds after calling set. thread_local.set("foo"); EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); } TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { ThreadLocal thread_local; const ThreadLocal& const_thread_local = thread_local; EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); thread_local.set("foo"); EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); } #if GTEST_IS_THREADSAFE void AddTwo(int* param) { *param += 2; } TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { int i = 40; ThreadWithParam thread(&AddTwo, &i, NULL); thread.Join(); EXPECT_EQ(42, i); } TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { // AssertHeld() is flaky only in the presence of multiple threads accessing // the lock. In this case, the test is robust. EXPECT_DEATH_IF_SUPPORTED({ Mutex m; { MutexLock lock(&m); } m.AssertHeld(); }, "thread .*hold"); } TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { Mutex m; MutexLock lock(&m); m.AssertHeld(); } class AtomicCounterWithMutex { public: explicit AtomicCounterWithMutex(Mutex* mutex) : value_(0), mutex_(mutex), random_(42) {} void Increment() { MutexLock lock(mutex_); int temp = value_; { // Locking a mutex puts up a memory barrier, preventing reads and // writes to value_ rearranged when observed from other threads. // // We cannot use Mutex and MutexLock here or rely on their memory // barrier functionality as we are testing them here. pthread_mutex_t memory_barrier_mutex; GTEST_CHECK_POSIX_SUCCESS_( pthread_mutex_init(&memory_barrier_mutex, NULL)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); SleepMilliseconds(random_.Generate(30)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); } value_ = temp + 1; } int value() const { return value_; } private: volatile int value_; Mutex* const mutex_; // Protects value_. Random random_; }; void CountingThreadFunc(pair param) { for (int i = 0; i < param.second; ++i) param.first->Increment(); } // Tests that the mutex only lets one thread at a time to lock it. TEST(MutexTest, OnlyOneThreadCanLockAtATime) { Mutex mutex; AtomicCounterWithMutex locked_counter(&mutex); typedef ThreadWithParam > ThreadType; const int kCycleCount = 20; const int kThreadCount = 7; scoped_ptr counting_threads[kThreadCount]; Notification threads_can_start; // Creates and runs kThreadCount threads that increment locked_counter // kCycleCount times each. for (int i = 0; i < kThreadCount; ++i) { counting_threads[i].reset(new ThreadType(&CountingThreadFunc, make_pair(&locked_counter, kCycleCount), &threads_can_start)); } threads_can_start.Notify(); for (int i = 0; i < kThreadCount; ++i) counting_threads[i]->Join(); // If the mutex lets more than one thread to increment the counter at a // time, they are likely to encounter a race condition and have some // increments overwritten, resulting in the lower then expected counter // value. EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); } template void RunFromThread(void (func)(T), T param) { ThreadWithParam thread(func, param, NULL); thread.Join(); } void RetrieveThreadLocalValue(pair*, String*> param) { *param.second = param.first->get(); } TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { ThreadLocal thread_local("foo"); EXPECT_STREQ("foo", thread_local.get().c_str()); thread_local.set("bar"); EXPECT_STREQ("bar", thread_local.get().c_str()); String result; RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); EXPECT_STREQ("foo", result.c_str()); } // DestructorTracker keeps track of whether its instances have been // destroyed. static std::vector g_destroyed; class DestructorTracker { public: DestructorTracker() : index_(GetNewIndex()) {} DestructorTracker(const DestructorTracker& /* rhs */) : index_(GetNewIndex()) {} ~DestructorTracker() { // We never access g_destroyed concurrently, so we don't need to // protect the write operation under a mutex. g_destroyed[index_] = true; } private: static int GetNewIndex() { g_destroyed.push_back(false); return g_destroyed.size() - 1; } const int index_; }; typedef ThreadLocal* ThreadParam; void CallThreadLocalGet(ThreadParam thread_local) { thread_local->get(); } // Tests that when a ThreadLocal object dies in a thread, it destroys // the managed object for that thread. TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) { g_destroyed.clear(); { // The next line default constructs a DestructorTracker object as // the default value of objects managed by thread_local. ThreadLocal thread_local; ASSERT_EQ(1U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); // This creates another DestructorTracker object for the main thread. thread_local.get(); ASSERT_EQ(2U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); ASSERT_FALSE(g_destroyed[1]); } // Now thread_local has died. It should have destroyed both the // default value shared by all threads and the value for the main // thread. ASSERT_EQ(2U, g_destroyed.size()); EXPECT_TRUE(g_destroyed[0]); EXPECT_TRUE(g_destroyed[1]); g_destroyed.clear(); } // Tests that when a thread exits, the thread-local object for that // thread is destroyed. TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) { g_destroyed.clear(); { // The next line default constructs a DestructorTracker object as // the default value of objects managed by thread_local. ThreadLocal thread_local; ASSERT_EQ(1U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); // This creates another DestructorTracker object in the new thread. ThreadWithParam thread( &CallThreadLocalGet, &thread_local, NULL); thread.Join(); // Now the new thread has exited. The per-thread object for it // should have been destroyed. ASSERT_EQ(2U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); ASSERT_TRUE(g_destroyed[1]); } // Now thread_local has died. The default value should have been // destroyed too. ASSERT_EQ(2U, g_destroyed.size()); EXPECT_TRUE(g_destroyed[0]); EXPECT_TRUE(g_destroyed[1]); g_destroyed.clear(); } TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { ThreadLocal thread_local; thread_local.set("Foo"); EXPECT_STREQ("Foo", thread_local.get().c_str()); String result; RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); EXPECT_TRUE(result.c_str() == NULL); } #endif // GTEST_IS_THREADSAFE } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/test/run_tests_util.py0000775000175100017510000004351712623076744023243 0ustar jenkins-buildjenkins-build# Copyright 2008 Google Inc. 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. """Provides facilities for running SCons-built Google Test/Mock tests.""" import optparse import os import re import sets import sys try: # subrocess module is a preferable way to invoke subprocesses but it may # not be available on MacOS X 10.4. # Suppresses the 'Import not at the top of the file' lint complaint. # pylint: disable-msg=C6204 import subprocess except ImportError: subprocess = None HELP_MSG = """Runs the specified tests for %(proj)s. SYNOPSIS run_tests.py [OPTION]... [BUILD_DIR]... [TEST]... DESCRIPTION Runs the specified tests (either binary or Python), and prints a summary of the results. BUILD_DIRS will be used to search for the binaries. If no TESTs are specified, all binary tests found in BUILD_DIRs and all Python tests found in the directory test/ (in the %(proj)s root) are run. TEST is a name of either a binary or a Python test. A binary test is an executable file named *_test or *_unittest (with the .exe extension on Windows) A Python test is a script named *_test.py or *_unittest.py. OPTIONS -h, --help Print this help message. -c CONFIGURATIONS Specify build directories via build configurations. CONFIGURATIONS is either a comma-separated list of build configurations or 'all'. Each configuration is equivalent to adding 'scons/build//%(proj)s/scons' to BUILD_DIRs. Specifying -c=all is equivalent to providing all directories listed in KNOWN BUILD DIRECTORIES section below. -a Equivalent to -c=all -b Equivalent to -c=all with the exception that the script will not fail if some of the KNOWN BUILD DIRECTORIES do not exists; the script will simply not run the tests there. 'b' stands for 'built directories'. RETURN VALUE Returns 0 if all tests are successful; otherwise returns 1. EXAMPLES run_tests.py Runs all tests for the default build configuration. run_tests.py -a Runs all tests with binaries in KNOWN BUILD DIRECTORIES. run_tests.py -b Runs all tests in KNOWN BUILD DIRECTORIES that have been built. run_tests.py foo/ Runs all tests in the foo/ directory and all Python tests in the directory test. The Python tests are instructed to look for binaries in foo/. run_tests.py bar_test.exe test/baz_test.exe foo/ bar/ Runs foo/bar_test.exe, bar/bar_test.exe, foo/baz_test.exe, and bar/baz_test.exe. run_tests.py foo bar test/foo_test.py Runs test/foo_test.py twice instructing it to look for its test binaries in the directories foo and bar, correspondingly. KNOWN BUILD DIRECTORIES run_tests.py knows about directories where the SCons build script deposits its products. These are the directories where run_tests.py will be looking for its binaries. Currently, %(proj)s's SConstruct file defines them as follows (the default build directory is the first one listed in each group): On Windows: <%(proj)s root>/scons/build/win-dbg8/%(proj)s/scons/ <%(proj)s root>/scons/build/win-opt8/%(proj)s/scons/ On Mac: <%(proj)s root>/scons/build/mac-dbg/%(proj)s/scons/ <%(proj)s root>/scons/build/mac-opt/%(proj)s/scons/ On other platforms: <%(proj)s root>/scons/build/dbg/%(proj)s/scons/ <%(proj)s root>/scons/build/opt/%(proj)s/scons/""" IS_WINDOWS = os.name == 'nt' IS_MAC = os.name == 'posix' and os.uname()[0] == 'Darwin' IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] # Definition of CONFIGS must match that of the build directory names in the # SConstruct script. The first list item is the default build configuration. if IS_WINDOWS: CONFIGS = ('win-dbg8', 'win-opt8') elif IS_MAC: CONFIGS = ('mac-dbg', 'mac-opt') else: CONFIGS = ('dbg', 'opt') if IS_WINDOWS or IS_CYGWIN: PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$', re.IGNORECASE) BINARY_TEST_REGEX = re.compile(r'_(unit)?test(\.exe)?$', re.IGNORECASE) BINARY_TEST_SEARCH_REGEX = re.compile(r'_(unit)?test\.exe$', re.IGNORECASE) else: PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$') BINARY_TEST_REGEX = re.compile(r'_(unit)?test$') BINARY_TEST_SEARCH_REGEX = BINARY_TEST_REGEX def _GetGtestBuildDir(injected_os, script_dir, config): """Calculates path to the Google Test SCons build directory.""" return injected_os.path.normpath(injected_os.path.join(script_dir, 'scons/build', config, 'gtest/scons')) def _GetConfigFromBuildDir(build_dir): """Extracts the configuration name from the build directory.""" # We don't want to depend on build_dir containing the correct path # separators. m = re.match(r'.*[\\/]([^\\/]+)[\\/][^\\/]+[\\/]scons[\\/]?$', build_dir) if m: return m.group(1) else: print >>sys.stderr, ('%s is an invalid build directory that does not ' 'correspond to any configuration.' % (build_dir,)) return '' # All paths in this script are either absolute or relative to the current # working directory, unless otherwise specified. class TestRunner(object): """Provides facilities for running Python and binary tests for Google Test.""" def __init__(self, script_dir, build_dir_var_name='GTEST_BUILD_DIR', injected_os=os, injected_subprocess=subprocess, injected_build_dir_finder=_GetGtestBuildDir): """Initializes a TestRunner instance. Args: script_dir: File path to the calling script. build_dir_var_name: Name of the env variable used to pass the the build directory path to the invoked tests. injected_os: standard os module or a mock/stub for testing. injected_subprocess: standard subprocess module or a mock/stub for testing injected_build_dir_finder: function that determines the path to the build directory. """ self.os = injected_os self.subprocess = injected_subprocess self.build_dir_finder = injected_build_dir_finder self.build_dir_var_name = build_dir_var_name self.script_dir = script_dir def _GetBuildDirForConfig(self, config): """Returns the build directory for a given configuration.""" return self.build_dir_finder(self.os, self.script_dir, config) def _Run(self, args): """Runs the executable with given args (args[0] is the executable name). Args: args: Command line arguments for the process. Returns: Process's exit code if it exits normally, or -signal if the process is killed by a signal. """ if self.subprocess: return self.subprocess.Popen(args).wait() else: return self.os.spawnv(self.os.P_WAIT, args[0], args) def _RunBinaryTest(self, test): """Runs the binary test given its path. Args: test: Path to the test binary. Returns: Process's exit code if it exits normally, or -signal if the process is killed by a signal. """ return self._Run([test]) def _RunPythonTest(self, test, build_dir): """Runs the Python test script with the specified build directory. Args: test: Path to the test's Python script. build_dir: Path to the directory where the test binary is to be found. Returns: Process's exit code if it exits normally, or -signal if the process is killed by a signal. """ old_build_dir = self.os.environ.get(self.build_dir_var_name) try: self.os.environ[self.build_dir_var_name] = build_dir # If this script is run on a Windows machine that has no association # between the .py extension and a python interpreter, simply passing # the script name into subprocess.Popen/os.spawn will not work. print 'Running %s . . .' % (test,) return self._Run([sys.executable, test]) finally: if old_build_dir is None: del self.os.environ[self.build_dir_var_name] else: self.os.environ[self.build_dir_var_name] = old_build_dir def _FindFilesByRegex(self, directory, regex): """Returns files in a directory whose names match a regular expression. Args: directory: Path to the directory to search for files. regex: Regular expression to filter file names. Returns: The list of the paths to the files in the directory. """ return [self.os.path.join(directory, file_name) for file_name in self.os.listdir(directory) if re.search(regex, file_name)] # TODO(vladl@google.com): Implement parsing of scons/SConscript to run all # tests defined there when no tests are specified. # TODO(vladl@google.com): Update the docstring after the code is changed to # try to test all builds defined in scons/SConscript. def GetTestsToRun(self, args, named_configurations, built_configurations, available_configurations=CONFIGS, python_tests_to_skip=None): """Determines what tests should be run. Args: args: The list of non-option arguments from the command line. named_configurations: The list of configurations specified via -c or -a. built_configurations: True if -b has been specified. available_configurations: a list of configurations available on the current platform, injectable for testing. python_tests_to_skip: a collection of (configuration, python test name)s that need to be skipped. Returns: A tuple with 2 elements: the list of Python tests to run and the list of binary tests to run. """ if named_configurations == 'all': named_configurations = ','.join(available_configurations) normalized_args = [self.os.path.normpath(arg) for arg in args] # A final list of build directories which will be searched for the test # binaries. First, add directories specified directly on the command # line. build_dirs = filter(self.os.path.isdir, normalized_args) # Adds build directories specified via their build configurations using # the -c or -a options. if named_configurations: build_dirs += [self._GetBuildDirForConfig(config) for config in named_configurations.split(',')] # Adds KNOWN BUILD DIRECTORIES if -b is specified. if built_configurations: build_dirs += [self._GetBuildDirForConfig(config) for config in available_configurations if self.os.path.isdir(self._GetBuildDirForConfig(config))] # If no directories were specified either via -a, -b, -c, or directly, use # the default configuration. elif not build_dirs: build_dirs = [self._GetBuildDirForConfig(available_configurations[0])] # Makes sure there are no duplications. build_dirs = sets.Set(build_dirs) errors_found = False listed_python_tests = [] # All Python tests listed on the command line. listed_binary_tests = [] # All binary tests listed on the command line. test_dir = self.os.path.normpath(self.os.path.join(self.script_dir, 'test')) # Sifts through non-directory arguments fishing for any Python or binary # tests and detecting errors. for argument in sets.Set(normalized_args) - build_dirs: if re.search(PYTHON_TEST_REGEX, argument): python_path = self.os.path.join(test_dir, self.os.path.basename(argument)) if self.os.path.isfile(python_path): listed_python_tests.append(python_path) else: sys.stderr.write('Unable to find Python test %s' % argument) errors_found = True elif re.search(BINARY_TEST_REGEX, argument): # This script also accepts binary test names prefixed with test/ for # the convenience of typing them (can use path completions in the # shell). Strips test/ prefix from the binary test names. listed_binary_tests.append(self.os.path.basename(argument)) else: sys.stderr.write('%s is neither test nor build directory' % argument) errors_found = True if errors_found: return None user_has_listed_tests = listed_python_tests or listed_binary_tests if user_has_listed_tests: selected_python_tests = listed_python_tests else: selected_python_tests = self._FindFilesByRegex(test_dir, PYTHON_TEST_REGEX) # TODO(vladl@google.com): skip unbuilt Python tests when -b is specified. python_test_pairs = [] for directory in build_dirs: for test in selected_python_tests: config = _GetConfigFromBuildDir(directory) file_name = os.path.basename(test) if python_tests_to_skip and (config, file_name) in python_tests_to_skip: print ('NOTE: %s is skipped for configuration %s, as it does not ' 'work there.' % (file_name, config)) else: python_test_pairs.append((directory, test)) binary_test_pairs = [] for directory in build_dirs: if user_has_listed_tests: binary_test_pairs.extend( [(directory, self.os.path.join(directory, test)) for test in listed_binary_tests]) else: tests = self._FindFilesByRegex(directory, BINARY_TEST_SEARCH_REGEX) binary_test_pairs.extend([(directory, test) for test in tests]) return (python_test_pairs, binary_test_pairs) def RunTests(self, python_tests, binary_tests): """Runs Python and binary tests and reports results to the standard output. Args: python_tests: List of Python tests to run in the form of tuples (build directory, Python test script). binary_tests: List of binary tests to run in the form of tuples (build directory, binary file). Returns: The exit code the program should pass into sys.exit(). """ if python_tests or binary_tests: results = [] for directory, test in python_tests: results.append((directory, test, self._RunPythonTest(test, directory) == 0)) for directory, test in binary_tests: results.append((directory, self.os.path.basename(test), self._RunBinaryTest(test) == 0)) failed = [(directory, test) for (directory, test, success) in results if not success] print print '%d tests run.' % len(results) if failed: print 'The following %d tests failed:' % len(failed) for (directory, test) in failed: print '%s in %s' % (test, directory) return 1 else: print 'All tests passed!' else: # No tests defined print 'Nothing to test - no tests specified!' return 0 def ParseArgs(project_name, argv=None, help_callback=None): """Parses the options run_tests.py uses.""" # Suppresses lint warning on unused arguments. These arguments are # required by optparse, even though they are unused. # pylint: disable-msg=W0613 def PrintHelp(option, opt, value, parser): print HELP_MSG % {'proj': project_name} sys.exit(1) parser = optparse.OptionParser() parser.add_option('-c', action='store', dest='configurations', default=None) parser.add_option('-a', action='store_const', dest='configurations', default=None, const='all') parser.add_option('-b', action='store_const', dest='built_configurations', default=False, const=True) # Replaces the built-in help with ours. parser.remove_option('-h') parser.add_option('-h', '--help', action='callback', callback=help_callback or PrintHelp) return parser.parse_args(argv) ceph-0.80.11/src/gtest/test/gtest_no_test_unittest.cc0000664000175100017510000000433612623076744024726 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // Tests that a Google Test program that has no test defined can run // successfully. // // Author: wan@google.com (Zhanyong Wan) #include int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); // An ad-hoc assertion outside of all tests. // // This serves two purposes: // // 1. It verifies that an ad-hoc assertion can be executed even if // no test is defined. // 2. We had a bug where the XML output won't be generated if an // assertion is executed before RUN_ALL_TESTS() is called, even // though --gtest_output=xml is specified. This makes sure the // bug is fixed and doesn't regress. EXPECT_EQ(1, 1); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_throw_on_failure_ex_test.cc0000664000175100017510000000656412623076744026422 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Tests Google Test's throw-on-failure mode with exceptions enabled. #include #include #include #include #include // Prints the given failure message and exits the program with // non-zero. We use this instead of a Google Test assertion to // indicate a failure, as the latter is been tested and cannot be // relied on. void Fail(const char* msg) { printf("FAILURE: %s\n", msg); fflush(stdout); exit(1); } // Tests that an assertion failure throws a subclass of // std::runtime_error. void TestFailureThrowsRuntimeError() { testing::GTEST_FLAG(throw_on_failure) = true; // A successful assertion shouldn't throw. try { EXPECT_EQ(3, 3); } catch(...) { Fail("A successful assertion wrongfully threw."); } // A failed assertion should throw a subclass of std::runtime_error. try { EXPECT_EQ(2, 3) << "Expected failure"; } catch(const std::runtime_error& e) { if (strstr(e.what(), "Expected failure") != NULL) return; printf("%s", "A failed assertion did throw an exception of the right type, " "but the message is incorrect. Instead of containing \"Expected " "failure\", it is:\n"); Fail(e.what()); } catch(...) { Fail("A failed assertion threw the wrong type of exception."); } Fail("A failed assertion should've thrown but didn't."); } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); // We want to ensure that people can use Google Test assertions in // other testing frameworks, as long as they initialize Google Test // properly and set the thrown-on-failure mode. Therefore, we don't // use Google Test's constructs for defining and running tests // (e.g. TEST and RUN_ALL_TESTS) here. TestFailureThrowsRuntimeError(); return 0; } ceph-0.80.11/src/gtest/test/gtest_unittest.cc0000664000175100017510000064054612623076744023204 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Tests for Google Test itself. This verifies that the basic constructs of // Google Test work. #include #include // Verifies that the command line flag variables can be accessed // in code once has been #included. // Do not move it after other #includes. TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { bool dummy = testing::GTEST_FLAG(also_run_disabled_tests) || testing::GTEST_FLAG(break_on_failure) || testing::GTEST_FLAG(catch_exceptions) || testing::GTEST_FLAG(color) != "unknown" || testing::GTEST_FLAG(filter) != "unknown" || testing::GTEST_FLAG(list_tests) || testing::GTEST_FLAG(output) != "unknown" || testing::GTEST_FLAG(print_time) || testing::GTEST_FLAG(random_seed) || testing::GTEST_FLAG(repeat) > 0 || testing::GTEST_FLAG(show_internal_stack_frames) || testing::GTEST_FLAG(shuffle) || testing::GTEST_FLAG(stack_trace_depth) > 0 || testing::GTEST_FLAG(throw_on_failure); EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused. } #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #include // For INT_MAX. #include #include #include namespace testing { namespace internal { // Provides access to otherwise private parts of the TestEventListeners class // that are needed to test it. class TestEventListenersAccessor { public: static TestEventListener* GetRepeater(TestEventListeners* listeners) { return listeners->repeater(); } static void SetDefaultResultPrinter(TestEventListeners* listeners, TestEventListener* listener) { listeners->SetDefaultResultPrinter(listener); } static void SetDefaultXmlGenerator(TestEventListeners* listeners, TestEventListener* listener) { listeners->SetDefaultXmlGenerator(listener); } static bool EventForwardingEnabled(const TestEventListeners& listeners) { return listeners.EventForwardingEnabled(); } static void SuppressEventForwarding(TestEventListeners* listeners) { listeners->SuppressEventForwarding(); } }; } // namespace internal } // namespace testing using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; using testing::DoubleLE; using testing::EmptyTestEventListener; using testing::FloatLE; using testing::GTEST_FLAG(also_run_disabled_tests); using testing::GTEST_FLAG(break_on_failure); using testing::GTEST_FLAG(catch_exceptions); using testing::GTEST_FLAG(color); using testing::GTEST_FLAG(death_test_use_fork); using testing::GTEST_FLAG(filter); using testing::GTEST_FLAG(list_tests); using testing::GTEST_FLAG(output); using testing::GTEST_FLAG(print_time); using testing::GTEST_FLAG(random_seed); using testing::GTEST_FLAG(repeat); using testing::GTEST_FLAG(show_internal_stack_frames); using testing::GTEST_FLAG(shuffle); using testing::GTEST_FLAG(stack_trace_depth); using testing::GTEST_FLAG(throw_on_failure); using testing::IsNotSubstring; using testing::IsSubstring; using testing::Message; using testing::ScopedFakeTestPartResultReporter; using testing::StaticAssertTypeEq; using testing::Test; using testing::TestEventListeners; using testing::TestCase; using testing::TestPartResult; using testing::TestPartResultArray; using testing::TestProperty; using testing::TestResult; using testing::UnitTest; using testing::kMaxStackTraceDepth; using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; using testing::internal::AppendUserMessage; using testing::internal::CodePointToUtf8; using testing::internal::CountIf; using testing::internal::EqFailure; using testing::internal::FloatingPoint; using testing::internal::FormatTimeInMillisAsSeconds; using testing::internal::ForEach; using testing::internal::GTestFlagSaver; using testing::internal::GetCurrentOsStackTraceExceptTop; using testing::internal::GetElementOr; using testing::internal::GetNextRandomSeed; using testing::internal::GetRandomSeedFromFlag; using testing::internal::GetTestTypeId; using testing::internal::GetTypeId; using testing::internal::GetUnitTestImpl; using testing::internal::Int32; using testing::internal::Int32FromEnvOrDie; using testing::internal::ParseInt32Flag; using testing::internal::ShouldRunTestOnShard; using testing::internal::ShouldShard; using testing::internal::ShouldUseColor; using testing::internal::Shuffle; using testing::internal::ShuffleRange; using testing::internal::StreamableToString; using testing::internal::String; using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; using testing::internal::UInt32; using testing::internal::WideStringToUtf8; using testing::internal::kMaxRandomSeed; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::scoped_ptr; #if GTEST_HAS_STREAM_REDIRECTION_ using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; #endif // GTEST_HAS_STREAM_REDIRECTION_ #if GTEST_IS_THREADSAFE using testing::internal::ThreadWithParam; #endif class TestingVector : public std::vector { }; ::std::ostream& operator<<(::std::ostream& os, const TestingVector& vector) { os << "{ "; for (size_t i = 0; i < vector.size(); i++) { os << vector[i] << " "; } os << "}"; return os; } // This line tests that we can define tests in an unnamed namespace. namespace { TEST(GetRandomSeedFromFlagTest, HandlesZero) { const int seed = GetRandomSeedFromFlag(0); EXPECT_LE(1, seed); EXPECT_LE(seed, static_cast(kMaxRandomSeed)); } TEST(GetRandomSeedFromFlagTest, PreservesValidSeed) { EXPECT_EQ(1, GetRandomSeedFromFlag(1)); EXPECT_EQ(2, GetRandomSeedFromFlag(2)); EXPECT_EQ(kMaxRandomSeed - 1, GetRandomSeedFromFlag(kMaxRandomSeed - 1)); EXPECT_EQ(static_cast(kMaxRandomSeed), GetRandomSeedFromFlag(kMaxRandomSeed)); } TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed) { const int seed1 = GetRandomSeedFromFlag(-1); EXPECT_LE(1, seed1); EXPECT_LE(seed1, static_cast(kMaxRandomSeed)); const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1); EXPECT_LE(1, seed2); EXPECT_LE(seed2, static_cast(kMaxRandomSeed)); } TEST(GetNextRandomSeedTest, WorksForValidInput) { EXPECT_EQ(2, GetNextRandomSeed(1)); EXPECT_EQ(3, GetNextRandomSeed(2)); EXPECT_EQ(static_cast(kMaxRandomSeed), GetNextRandomSeed(kMaxRandomSeed - 1)); EXPECT_EQ(1, GetNextRandomSeed(kMaxRandomSeed)); // We deliberately don't test GetNextRandomSeed() with invalid // inputs, as that requires death tests, which are expensive. This // is fine as GetNextRandomSeed() is internal and has a // straightforward definition. } static void ClearCurrentTestPartResults() { TestResultAccessor::ClearTestPartResults( GetUnitTestImpl()->current_test_result()); } // Tests GetTypeId. TEST(GetTypeIdTest, ReturnsSameValueForSameType) { EXPECT_EQ(GetTypeId(), GetTypeId()); EXPECT_EQ(GetTypeId(), GetTypeId()); } class SubClassOfTest : public Test {}; class AnotherSubClassOfTest : public Test {}; TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes) { EXPECT_NE(GetTypeId(), GetTypeId()); EXPECT_NE(GetTypeId(), GetTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTypeId()); } // Verifies that GetTestTypeId() returns the same value, no matter it // is called from inside Google Test or outside of it. TEST(GetTestTypeIdTest, ReturnsTheSameValueInsideOrOutsideOfGoogleTest) { EXPECT_EQ(kTestTypeIdInGoogleTest, GetTestTypeId()); } // Tests FormatTimeInMillisAsSeconds(). TEST(FormatTimeInMillisAsSecondsTest, FormatsZero) { EXPECT_EQ("0", FormatTimeInMillisAsSeconds(0)); } TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber) { EXPECT_EQ("0.003", FormatTimeInMillisAsSeconds(3)); EXPECT_EQ("0.01", FormatTimeInMillisAsSeconds(10)); EXPECT_EQ("0.2", FormatTimeInMillisAsSeconds(200)); EXPECT_EQ("1.2", FormatTimeInMillisAsSeconds(1200)); EXPECT_EQ("3", FormatTimeInMillisAsSeconds(3000)); } TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) { EXPECT_EQ("-0.003", FormatTimeInMillisAsSeconds(-3)); EXPECT_EQ("-0.01", FormatTimeInMillisAsSeconds(-10)); EXPECT_EQ("-0.2", FormatTimeInMillisAsSeconds(-200)); EXPECT_EQ("-1.2", FormatTimeInMillisAsSeconds(-1200)); EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000)); } #if GTEST_CAN_COMPARE_NULL #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" #pragma option push -w-ccc -w-rch #endif // Tests that GTEST_IS_NULL_LITERAL_(x) is true when x is a null // pointer literal. TEST(NullLiteralTest, IsTrueForNullLiterals) { EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(NULL)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0U)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0L)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(false)); #ifndef __BORLANDC__ // Some compilers may fail to detect some null pointer literals; // as long as users of the framework don't use such literals, this // is harmless. EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(1 - 1)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(true && false)); #endif } // Tests that GTEST_IS_NULL_LITERAL_(x) is false when x is not a null // pointer literal. TEST(NullLiteralTest, IsFalseForNonNullLiterals) { EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(1)); EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(0.0)); EXPECT_FALSE(GTEST_IS_NULL_LITERAL_('a')); EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(static_cast(NULL))); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" suppressed them. #pragma option pop #endif #endif // GTEST_CAN_COMPARE_NULL // // Tests CodePointToUtf8(). // Tests that the NUL character L'\0' is encoded correctly. TEST(CodePointToUtf8Test, CanEncodeNul) { char buffer[32]; EXPECT_STREQ("", CodePointToUtf8(L'\0', buffer)); } // Tests that ASCII characters are encoded correctly. TEST(CodePointToUtf8Test, CanEncodeAscii) { char buffer[32]; EXPECT_STREQ("a", CodePointToUtf8(L'a', buffer)); EXPECT_STREQ("Z", CodePointToUtf8(L'Z', buffer)); EXPECT_STREQ("&", CodePointToUtf8(L'&', buffer)); EXPECT_STREQ("\x7F", CodePointToUtf8(L'\x7F', buffer)); } // Tests that Unicode code-points that have 8 to 11 bits are encoded // as 110xxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode8To11Bits) { char buffer[32]; // 000 1101 0011 => 110-00011 10-010011 EXPECT_STREQ("\xC3\x93", CodePointToUtf8(L'\xD3', buffer)); // 101 0111 0110 => 110-10101 10-110110 EXPECT_STREQ("\xD5\xB6", CodePointToUtf8(L'\x576', buffer)); } // Tests that Unicode code-points that have 12 to 16 bits are encoded // as 1110xxxx 10xxxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode12To16Bits) { char buffer[32]; // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 EXPECT_STREQ("\xE0\xA3\x93", CodePointToUtf8(L'\x8D3', buffer)); // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 EXPECT_STREQ("\xEC\x9D\x8D", CodePointToUtf8(L'\xC74D', buffer)); } #if !GTEST_WIDE_STRING_USES_UTF16_ // Tests in this group require a wchar_t to hold > 16 bits, and thus // are skipped on Windows, Cygwin, and Symbian, where a wchar_t is // 16-bit wide. This code may not compile on those systems. // Tests that Unicode code-points that have 17 to 21 bits are encoded // as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode17To21Bits) { char buffer[32]; // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 EXPECT_STREQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3', buffer)); // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000 EXPECT_STREQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400', buffer)); // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 EXPECT_STREQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634', buffer)); } // Tests that encoding an invalid code-point generates the expected result. TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint) { char buffer[32]; EXPECT_STREQ("(Invalid Unicode 0x1234ABCD)", CodePointToUtf8(L'\x1234ABCD', buffer)); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests WideStringToUtf8(). // Tests that the NUL character L'\0' is encoded correctly. TEST(WideStringToUtf8Test, CanEncodeNul) { EXPECT_STREQ("", WideStringToUtf8(L"", 0).c_str()); EXPECT_STREQ("", WideStringToUtf8(L"", -1).c_str()); } // Tests that ASCII strings are encoded correctly. TEST(WideStringToUtf8Test, CanEncodeAscii) { EXPECT_STREQ("a", WideStringToUtf8(L"a", 1).c_str()); EXPECT_STREQ("ab", WideStringToUtf8(L"ab", 2).c_str()); EXPECT_STREQ("a", WideStringToUtf8(L"a", -1).c_str()); EXPECT_STREQ("ab", WideStringToUtf8(L"ab", -1).c_str()); } // Tests that Unicode code-points that have 8 to 11 bits are encoded // as 110xxxxx 10xxxxxx. TEST(WideStringToUtf8Test, CanEncode8To11Bits) { // 000 1101 0011 => 110-00011 10-010011 EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", 1).c_str()); EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", -1).c_str()); // 101 0111 0110 => 110-10101 10-110110 EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(L"\x576", 1).c_str()); EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(L"\x576", -1).c_str()); } // Tests that Unicode code-points that have 12 to 16 bits are encoded // as 1110xxxx 10xxxxxx 10xxxxxx. TEST(WideStringToUtf8Test, CanEncode12To16Bits) { // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(L"\x8D3", 1).c_str()); EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(L"\x8D3", -1).c_str()); // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(L"\xC74D", 1).c_str()); EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(L"\xC74D", -1).c_str()); } // Tests that the conversion stops when the function encounters \0 character. TEST(WideStringToUtf8Test, StopsOnNulCharacter) { EXPECT_STREQ("ABC", WideStringToUtf8(L"ABC\0XYZ", 100).c_str()); } // Tests that the conversion stops when the function reaches the limit // specified by the 'length' parameter. TEST(WideStringToUtf8Test, StopsWhenLengthLimitReached) { EXPECT_STREQ("ABC", WideStringToUtf8(L"ABCDEF", 3).c_str()); } #if !GTEST_WIDE_STRING_USES_UTF16_ // Tests that Unicode code-points that have 17 to 21 bits are encoded // as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. This code may not compile // on the systems using UTF-16 encoding. TEST(WideStringToUtf8Test, CanEncode17To21Bits) { // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", 1).c_str()); EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", -1).c_str()); // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", 1).c_str()); EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", -1).c_str()); } // Tests that encoding an invalid code-point generates the expected result. TEST(WideStringToUtf8Test, CanEncodeInvalidCodePoint) { EXPECT_STREQ("(Invalid Unicode 0xABCDFF)", WideStringToUtf8(L"\xABCDFF", -1).c_str()); } #else // !GTEST_WIDE_STRING_USES_UTF16_ // Tests that surrogate pairs are encoded correctly on the systems using // UTF-16 encoding in the wide strings. TEST(WideStringToUtf8Test, CanEncodeValidUtf16SUrrogatePairs) { EXPECT_STREQ("\xF0\x90\x90\x80", WideStringToUtf8(L"\xD801\xDC00", -1).c_str()); } // Tests that encoding an invalid UTF-16 surrogate pair // generates the expected result. TEST(WideStringToUtf8Test, CanEncodeInvalidUtf16SurrogatePair) { // Leading surrogate is at the end of the string. EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(L"\xD800", -1).c_str()); // Leading surrogate is not followed by the trailing surrogate. EXPECT_STREQ("\xED\xA0\x80$", WideStringToUtf8(L"\xD800$", -1).c_str()); // Trailing surrogate appearas without a leading surrogate. EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(L"\xDC00PQR", -1).c_str()); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests that codepoint concatenation works correctly. #if !GTEST_WIDE_STRING_USES_UTF16_ TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { EXPECT_STREQ( "\xF4\x88\x98\xB4" "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93" "\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634\xC74D\n\x576\x8D3\x108634", -1).c_str()); } #else TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { EXPECT_STREQ( "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93", WideStringToUtf8(L"\xC74D\n\x576\x8D3", -1).c_str()); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests the Random class. TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) { testing::internal::Random random(42); EXPECT_DEATH_IF_SUPPORTED( random.Generate(0), "Cannot generate a number in the range \\[0, 0\\)"); EXPECT_DEATH_IF_SUPPORTED( random.Generate(testing::internal::Random::kMaxRange + 1), "Generation of a number in \\[0, 2147483649\\) was requested, " "but this can only generate numbers in \\[0, 2147483648\\)"); } TEST(RandomTest, GeneratesNumbersWithinRange) { const UInt32 kRange = 10000; testing::internal::Random random(12345); for (int i = 0; i < 10; i++) { EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i; } testing::internal::Random random2(testing::internal::Random::kMaxRange); for (int i = 0; i < 10; i++) { EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i; } } TEST(RandomTest, RepeatsWhenReseeded) { const int kSeed = 123; const int kArraySize = 10; const UInt32 kRange = 10000; UInt32 values[kArraySize]; testing::internal::Random random(kSeed); for (int i = 0; i < kArraySize; i++) { values[i] = random.Generate(kRange); } random.Reseed(kSeed); for (int i = 0; i < kArraySize; i++) { EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i; } } // Tests STL container utilities. // Tests CountIf(). static bool IsPositive(int n) { return n > 0; } TEST(ContainerUtilityTest, CountIf) { std::vector v; EXPECT_EQ(0, CountIf(v, IsPositive)); // Works for an empty container. v.push_back(-1); v.push_back(0); EXPECT_EQ(0, CountIf(v, IsPositive)); // Works when no value satisfies. v.push_back(2); v.push_back(-10); v.push_back(10); EXPECT_EQ(2, CountIf(v, IsPositive)); } // Tests ForEach(). static int g_sum = 0; static void Accumulate(int n) { g_sum += n; } TEST(ContainerUtilityTest, ForEach) { std::vector v; g_sum = 0; ForEach(v, Accumulate); EXPECT_EQ(0, g_sum); // Works for an empty container; g_sum = 0; v.push_back(1); ForEach(v, Accumulate); EXPECT_EQ(1, g_sum); // Works for a container with one element. g_sum = 0; v.push_back(20); v.push_back(300); ForEach(v, Accumulate); EXPECT_EQ(321, g_sum); } // Tests GetElementOr(). TEST(ContainerUtilityTest, GetElementOr) { std::vector a; EXPECT_EQ('x', GetElementOr(a, 0, 'x')); a.push_back('a'); a.push_back('b'); EXPECT_EQ('a', GetElementOr(a, 0, 'x')); EXPECT_EQ('b', GetElementOr(a, 1, 'x')); EXPECT_EQ('x', GetElementOr(a, -2, 'x')); EXPECT_EQ('x', GetElementOr(a, 2, 'x')); } TEST(ContainerUtilityDeathTest, ShuffleRange) { std::vector a; a.push_back(0); a.push_back(1); a.push_back(2); testing::internal::Random random(1); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, -1, 1, &a), "Invalid shuffle range start -1: must be in range \\[0, 3\\]"); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, 4, 4, &a), "Invalid shuffle range start 4: must be in range \\[0, 3\\]"); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, 3, 2, &a), "Invalid shuffle range finish 2: must be in range \\[3, 3\\]"); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, 3, 4, &a), "Invalid shuffle range finish 4: must be in range \\[3, 3\\]"); } class VectorShuffleTest : public Test { protected: static const int kVectorSize = 20; VectorShuffleTest() : random_(1) { for (int i = 0; i < kVectorSize; i++) { vector_.push_back(i); } } static bool VectorIsCorrupt(const TestingVector& vector) { if (kVectorSize != static_cast(vector.size())) { return true; } bool found_in_vector[kVectorSize] = { false }; for (size_t i = 0; i < vector.size(); i++) { const int e = vector[i]; if (e < 0 || e >= kVectorSize || found_in_vector[e]) { return true; } found_in_vector[e] = true; } // Vector size is correct, elements' range is correct, no // duplicate elements. Therefore no corruption has occurred. return false; } static bool VectorIsNotCorrupt(const TestingVector& vector) { return !VectorIsCorrupt(vector); } static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) { for (int i = begin; i < end; i++) { if (i != vector[i]) { return true; } } return false; } static bool RangeIsUnshuffled( const TestingVector& vector, int begin, int end) { return !RangeIsShuffled(vector, begin, end); } static bool VectorIsShuffled(const TestingVector& vector) { return RangeIsShuffled(vector, 0, static_cast(vector.size())); } static bool VectorIsUnshuffled(const TestingVector& vector) { return !VectorIsShuffled(vector); } testing::internal::Random random_; TestingVector vector_; }; // class VectorShuffleTest const int VectorShuffleTest::kVectorSize; TEST_F(VectorShuffleTest, HandlesEmptyRange) { // Tests an empty range at the beginning... ShuffleRange(&random_, 0, 0, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...in the middle... ShuffleRange(&random_, kVectorSize/2, kVectorSize/2, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...at the end... ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...and past the end. ShuffleRange(&random_, kVectorSize, kVectorSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); } TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne) { // Tests a size one range at the beginning... ShuffleRange(&random_, 0, 1, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...in the middle... ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...and at the end. ShuffleRange(&random_, kVectorSize - 1, kVectorSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); } // Because we use our own random number generator and a fixed seed, // we can guarantee that the following "random" tests will succeed. TEST_F(VectorShuffleTest, ShufflesEntireVector) { Shuffle(&random_, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_; // Tests the first and last elements in particular to ensure that // there are no off-by-one problems in our shuffle algorithm. EXPECT_NE(0, vector_[0]); EXPECT_NE(kVectorSize - 1, vector_[kVectorSize - 1]); } TEST_F(VectorShuffleTest, ShufflesStartOfVector) { const int kRangeSize = kVectorSize/2; ShuffleRange(&random_, 0, kRangeSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize); EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, kVectorSize); } TEST_F(VectorShuffleTest, ShufflesEndOfVector) { const int kRangeSize = kVectorSize / 2; ShuffleRange(&random_, kRangeSize, kVectorSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, kVectorSize); } TEST_F(VectorShuffleTest, ShufflesMiddleOfVector) { int kRangeSize = kVectorSize/3; ShuffleRange(&random_, kRangeSize, 2*kRangeSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize); EXPECT_PRED3(RangeIsUnshuffled, vector_, 2*kRangeSize, kVectorSize); } TEST_F(VectorShuffleTest, ShufflesRepeatably) { TestingVector vector2; for (int i = 0; i < kVectorSize; i++) { vector2.push_back(i); } random_.Reseed(1234); Shuffle(&random_, &vector_); random_.Reseed(1234); Shuffle(&random_, &vector2); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector2); for (int i = 0; i < kVectorSize; i++) { EXPECT_EQ(vector_[i], vector2[i]) << " where i is " << i; } } // Tests the size of the AssertHelper class. TEST(AssertHelperTest, AssertHelperIsSmall) { // To avoid breaking clients that use lots of assertions in one // function, we cannot grow the size of AssertHelper. EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*)); } // Tests the String class. // Tests String's constructors. TEST(StringTest, Constructors) { // Default ctor. String s1; // We aren't using EXPECT_EQ(NULL, s1.c_str()) because comparing // pointers with NULL isn't supported on all platforms. EXPECT_EQ(0U, s1.length()); EXPECT_TRUE(NULL == s1.c_str()); // Implicitly constructs from a C-string. String s2 = "Hi"; EXPECT_EQ(2U, s2.length()); EXPECT_STREQ("Hi", s2.c_str()); // Constructs from a C-string and a length. String s3("hello", 3); EXPECT_EQ(3U, s3.length()); EXPECT_STREQ("hel", s3.c_str()); // The empty String should be created when String is constructed with // a NULL pointer and length 0. EXPECT_EQ(0U, String(NULL, 0).length()); EXPECT_FALSE(String(NULL, 0).c_str() == NULL); // Constructs a String that contains '\0'. String s4("a\0bcd", 4); EXPECT_EQ(4U, s4.length()); EXPECT_EQ('a', s4.c_str()[0]); EXPECT_EQ('\0', s4.c_str()[1]); EXPECT_EQ('b', s4.c_str()[2]); EXPECT_EQ('c', s4.c_str()[3]); // Copy ctor where the source is NULL. const String null_str; String s5 = null_str; EXPECT_TRUE(s5.c_str() == NULL); // Copy ctor where the source isn't NULL. String s6 = s3; EXPECT_EQ(3U, s6.length()); EXPECT_STREQ("hel", s6.c_str()); // Copy ctor where the source contains '\0'. String s7 = s4; EXPECT_EQ(4U, s7.length()); EXPECT_EQ('a', s7.c_str()[0]); EXPECT_EQ('\0', s7.c_str()[1]); EXPECT_EQ('b', s7.c_str()[2]); EXPECT_EQ('c', s7.c_str()[3]); } TEST(StringTest, ConvertsFromStdString) { // An empty std::string. const std::string src1(""); const String dest1 = src1; EXPECT_EQ(0U, dest1.length()); EXPECT_STREQ("", dest1.c_str()); // A normal std::string. const std::string src2("Hi"); const String dest2 = src2; EXPECT_EQ(2U, dest2.length()); EXPECT_STREQ("Hi", dest2.c_str()); // An std::string with an embedded NUL character. const char src3[] = "a\0b"; const String dest3 = std::string(src3, sizeof(src3)); EXPECT_EQ(sizeof(src3), dest3.length()); EXPECT_EQ('a', dest3.c_str()[0]); EXPECT_EQ('\0', dest3.c_str()[1]); EXPECT_EQ('b', dest3.c_str()[2]); } TEST(StringTest, ConvertsToStdString) { // An empty String. const String src1(""); const std::string dest1 = src1; EXPECT_EQ("", dest1); // A normal String. const String src2("Hi"); const std::string dest2 = src2; EXPECT_EQ("Hi", dest2); // A String containing a '\0'. const String src3("x\0y", 3); const std::string dest3 = src3; EXPECT_EQ(std::string("x\0y", 3), dest3); } #if GTEST_HAS_GLOBAL_STRING TEST(StringTest, ConvertsFromGlobalString) { // An empty ::string. const ::string src1(""); const String dest1 = src1; EXPECT_EQ(0U, dest1.length()); EXPECT_STREQ("", dest1.c_str()); // A normal ::string. const ::string src2("Hi"); const String dest2 = src2; EXPECT_EQ(2U, dest2.length()); EXPECT_STREQ("Hi", dest2.c_str()); // An ::string with an embedded NUL character. const char src3[] = "x\0y"; const String dest3 = ::string(src3, sizeof(src3)); EXPECT_EQ(sizeof(src3), dest3.length()); EXPECT_EQ('x', dest3.c_str()[0]); EXPECT_EQ('\0', dest3.c_str()[1]); EXPECT_EQ('y', dest3.c_str()[2]); } TEST(StringTest, ConvertsToGlobalString) { // An empty String. const String src1(""); const ::string dest1 = src1; EXPECT_EQ("", dest1); // A normal String. const String src2("Hi"); const ::string dest2 = src2; EXPECT_EQ("Hi", dest2); const String src3("x\0y", 3); const ::string dest3 = src3; EXPECT_EQ(::string("x\0y", 3), dest3); } #endif // GTEST_HAS_GLOBAL_STRING // Tests String::ShowCStringQuoted(). TEST(StringTest, ShowCStringQuoted) { EXPECT_STREQ("(null)", String::ShowCStringQuoted(NULL).c_str()); EXPECT_STREQ("\"\"", String::ShowCStringQuoted("").c_str()); EXPECT_STREQ("\"foo\"", String::ShowCStringQuoted("foo").c_str()); } // Tests String::empty(). TEST(StringTest, Empty) { EXPECT_TRUE(String("").empty()); EXPECT_FALSE(String().empty()); EXPECT_FALSE(String(NULL).empty()); EXPECT_FALSE(String("a").empty()); EXPECT_FALSE(String("\0", 1).empty()); } // Tests String::Compare(). TEST(StringTest, Compare) { // NULL vs NULL. EXPECT_EQ(0, String().Compare(String())); // NULL vs non-NULL. EXPECT_EQ(-1, String().Compare(String(""))); // Non-NULL vs NULL. EXPECT_EQ(1, String("").Compare(String())); // The following covers non-NULL vs non-NULL. // "" vs "". EXPECT_EQ(0, String("").Compare(String(""))); // "" vs non-"". EXPECT_EQ(-1, String("").Compare(String("\0", 1))); EXPECT_EQ(-1, String("").Compare(" ")); // Non-"" vs "". EXPECT_EQ(1, String("a").Compare(String(""))); // The following covers non-"" vs non-"". // Same length and equal. EXPECT_EQ(0, String("a").Compare(String("a"))); // Same length and different. EXPECT_EQ(-1, String("a\0b", 3).Compare(String("a\0c", 3))); EXPECT_EQ(1, String("b").Compare(String("a"))); // Different lengths. EXPECT_EQ(-1, String("a").Compare(String("ab"))); EXPECT_EQ(-1, String("a").Compare(String("a\0", 2))); EXPECT_EQ(1, String("abc").Compare(String("aacd"))); } // Tests String::operator==(). TEST(StringTest, Equals) { const String null(NULL); EXPECT_TRUE(null == NULL); // NOLINT EXPECT_FALSE(null == ""); // NOLINT EXPECT_FALSE(null == "bar"); // NOLINT const String empty(""); EXPECT_FALSE(empty == NULL); // NOLINT EXPECT_TRUE(empty == ""); // NOLINT EXPECT_FALSE(empty == "bar"); // NOLINT const String foo("foo"); EXPECT_FALSE(foo == NULL); // NOLINT EXPECT_FALSE(foo == ""); // NOLINT EXPECT_FALSE(foo == "bar"); // NOLINT EXPECT_TRUE(foo == "foo"); // NOLINT const String bar("x\0y", 3); EXPECT_FALSE(bar == "x"); } // Tests String::operator!=(). TEST(StringTest, NotEquals) { const String null(NULL); EXPECT_FALSE(null != NULL); // NOLINT EXPECT_TRUE(null != ""); // NOLINT EXPECT_TRUE(null != "bar"); // NOLINT const String empty(""); EXPECT_TRUE(empty != NULL); // NOLINT EXPECT_FALSE(empty != ""); // NOLINT EXPECT_TRUE(empty != "bar"); // NOLINT const String foo("foo"); EXPECT_TRUE(foo != NULL); // NOLINT EXPECT_TRUE(foo != ""); // NOLINT EXPECT_TRUE(foo != "bar"); // NOLINT EXPECT_FALSE(foo != "foo"); // NOLINT const String bar("x\0y", 3); EXPECT_TRUE(bar != "x"); } // Tests String::length(). TEST(StringTest, Length) { EXPECT_EQ(0U, String().length()); EXPECT_EQ(0U, String("").length()); EXPECT_EQ(2U, String("ab").length()); EXPECT_EQ(3U, String("a\0b", 3).length()); } // Tests String::EndsWith(). TEST(StringTest, EndsWith) { EXPECT_TRUE(String("foobar").EndsWith("bar")); EXPECT_TRUE(String("foobar").EndsWith("")); EXPECT_TRUE(String("").EndsWith("")); EXPECT_FALSE(String("foobar").EndsWith("foo")); EXPECT_FALSE(String("").EndsWith("foo")); } // Tests String::EndsWithCaseInsensitive(). TEST(StringTest, EndsWithCaseInsensitive) { EXPECT_TRUE(String("foobar").EndsWithCaseInsensitive("BAR")); EXPECT_TRUE(String("foobaR").EndsWithCaseInsensitive("bar")); EXPECT_TRUE(String("foobar").EndsWithCaseInsensitive("")); EXPECT_TRUE(String("").EndsWithCaseInsensitive("")); EXPECT_FALSE(String("Foobar").EndsWithCaseInsensitive("foo")); EXPECT_FALSE(String("foobar").EndsWithCaseInsensitive("Foo")); EXPECT_FALSE(String("").EndsWithCaseInsensitive("foo")); } // C++Builder's preprocessor is buggy; it fails to expand macros that // appear in macro parameters after wide char literals. Provide an alias // for NULL as a workaround. static const wchar_t* const kNull = NULL; // Tests String::CaseInsensitiveWideCStringEquals TEST(StringTest, CaseInsensitiveWideCStringEquals) { EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(NULL, NULL)); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"")); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", kNull)); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"foobar")); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", kNull)); EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar")); EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR")); EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar")); } // Tests that NULL can be assigned to a String. TEST(StringTest, CanBeAssignedNULL) { const String src(NULL); String dest; dest = src; EXPECT_STREQ(NULL, dest.c_str()); } // Tests that the empty string "" can be assigned to a String. TEST(StringTest, CanBeAssignedEmpty) { const String src(""); String dest; dest = src; EXPECT_STREQ("", dest.c_str()); } // Tests that a non-empty string can be assigned to a String. TEST(StringTest, CanBeAssignedNonEmpty) { const String src("hello"); String dest; dest = src; EXPECT_EQ(5U, dest.length()); EXPECT_STREQ("hello", dest.c_str()); const String src2("x\0y", 3); String dest2; dest2 = src2; EXPECT_EQ(3U, dest2.length()); EXPECT_EQ('x', dest2.c_str()[0]); EXPECT_EQ('\0', dest2.c_str()[1]); EXPECT_EQ('y', dest2.c_str()[2]); } // Tests that a String can be assigned to itself. TEST(StringTest, CanBeAssignedSelf) { String dest("hello"); dest = dest; EXPECT_STREQ("hello", dest.c_str()); } // Sun Studio < 12 incorrectly rejects this code due to an overloading // ambiguity. #if !(defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) // Tests streaming a String. TEST(StringTest, Streams) { EXPECT_EQ(StreamableToString(String()), "(null)"); EXPECT_EQ(StreamableToString(String("")), ""); EXPECT_EQ(StreamableToString(String("a\0b", 3)), "a\\0b"); } #endif // Tests that String::Format() works. TEST(StringTest, FormatWorks) { // Normal case: the format spec is valid, the arguments match the // spec, and the result is < 4095 characters. EXPECT_STREQ("Hello, 42", String::Format("%s, %d", "Hello", 42).c_str()); // Edge case: the result is 4095 characters. char buffer[4096]; const size_t kSize = sizeof(buffer); memset(buffer, 'a', kSize - 1); buffer[kSize - 1] = '\0'; EXPECT_STREQ(buffer, String::Format("%s", buffer).c_str()); // The result needs to be 4096 characters, exceeding Format()'s limit. EXPECT_STREQ("", String::Format("x%s", buffer).c_str()); #if GTEST_OS_LINUX // On Linux, invalid format spec should lead to an error message. // In other environment (e.g. MSVC on Windows), String::Format() may // simply ignore a bad format spec, so this assertion is run on // Linux only. EXPECT_STREQ("", String::Format("%").c_str()); #endif } #if GTEST_OS_WINDOWS // Tests String::ShowWideCString(). TEST(StringTest, ShowWideCString) { EXPECT_STREQ("(null)", String::ShowWideCString(NULL).c_str()); EXPECT_STREQ("", String::ShowWideCString(L"").c_str()); EXPECT_STREQ("foo", String::ShowWideCString(L"foo").c_str()); } // Tests String::ShowWideCStringQuoted(). TEST(StringTest, ShowWideCStringQuoted) { EXPECT_STREQ("(null)", String::ShowWideCStringQuoted(NULL).c_str()); EXPECT_STREQ("L\"\"", String::ShowWideCStringQuoted(L"").c_str()); EXPECT_STREQ("L\"foo\"", String::ShowWideCStringQuoted(L"foo").c_str()); } #if GTEST_OS_WINDOWS_MOBILE TEST(StringTest, AnsiAndUtf16Null) { EXPECT_EQ(NULL, String::AnsiToUtf16(NULL)); EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL)); } TEST(StringTest, AnsiAndUtf16ConvertBasic) { const char* ansi = String::Utf16ToAnsi(L"str"); EXPECT_STREQ("str", ansi); delete [] ansi; const WCHAR* utf16 = String::AnsiToUtf16("str"); EXPECT_EQ(0, wcsncmp(L"str", utf16, 3)); delete [] utf16; } TEST(StringTest, AnsiAndUtf16ConvertPathChars) { const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?"); EXPECT_STREQ(".:\\ \"*?", ansi); delete [] ansi; const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?"); EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3)); delete [] utf16; } #endif // GTEST_OS_WINDOWS_MOBILE #endif // GTEST_OS_WINDOWS // Tests TestProperty construction. TEST(TestPropertyTest, StringValue) { TestProperty property("key", "1"); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("1", property.value()); } // Tests TestProperty replacing a value. TEST(TestPropertyTest, ReplaceStringValue) { TestProperty property("key", "1"); EXPECT_STREQ("1", property.value()); property.SetValue("2"); EXPECT_STREQ("2", property.value()); } // AddFatalFailure() and AddNonfatalFailure() must be stand-alone // functions (i.e. their definitions cannot be inlined at the call // sites), or C++Builder won't compile the code. static void AddFatalFailure() { FAIL() << "Expected fatal failure."; } static void AddNonfatalFailure() { ADD_FAILURE() << "Expected non-fatal failure."; } class ScopedFakeTestPartResultReporterTest : public Test { public: // Must be public and not protected due to a bug in g++ 3.4.2. enum FailureMode { FATAL_FAILURE, NONFATAL_FAILURE }; static void AddFailure(FailureMode failure) { if (failure == FATAL_FAILURE) { AddFatalFailure(); } else { AddNonfatalFailure(); } } }; // Tests that ScopedFakeTestPartResultReporter intercepts test // failures. TEST_F(ScopedFakeTestPartResultReporterTest, InterceptsTestFailures) { TestPartResultArray results; { ScopedFakeTestPartResultReporter reporter( ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, &results); AddFailure(NONFATAL_FAILURE); AddFailure(FATAL_FAILURE); } EXPECT_EQ(2, results.size()); EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); } TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) { TestPartResultArray results; { // Tests, that the deprecated constructor still works. ScopedFakeTestPartResultReporter reporter(&results); AddFailure(NONFATAL_FAILURE); } EXPECT_EQ(1, results.size()); } #if GTEST_IS_THREADSAFE class ScopedFakeTestPartResultReporterWithThreadsTest : public ScopedFakeTestPartResultReporterTest { protected: static void AddFailureInOtherThread(FailureMode failure) { ThreadWithParam thread(&AddFailure, failure, NULL); thread.Join(); } }; TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest, InterceptsTestFailuresInAllThreads) { TestPartResultArray results; { ScopedFakeTestPartResultReporter reporter( ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, &results); AddFailure(NONFATAL_FAILURE); AddFailure(FATAL_FAILURE); AddFailureInOtherThread(NONFATAL_FAILURE); AddFailureInOtherThread(FATAL_FAILURE); } EXPECT_EQ(4, results.size()); EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); EXPECT_TRUE(results.GetTestPartResult(2).nonfatally_failed()); EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed()); } #endif // GTEST_IS_THREADSAFE // Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they // work even if the failure is generated in a called function rather than // the current context. typedef ScopedFakeTestPartResultReporterTest ExpectFatalFailureTest; TEST_F(ExpectFatalFailureTest, CatchesFatalFaliure) { EXPECT_FATAL_FAILURE(AddFatalFailure(), "Expected fatal failure."); } TEST_F(ExpectFatalFailureTest, CatchesFatalFailureOnAllThreads) { // We have another test below to verify that the macro catches fatal // failures generated on another thread. EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFatalFailure(), "Expected fatal failure."); } #ifdef __BORLANDC__ // Silences warnings: "Condition is always true" #pragma option push -w-ccc #endif // Tests that EXPECT_FATAL_FAILURE() can be used in a non-void // function even when the statement in it contains ASSERT_*. int NonVoidFunction() { EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); return 0; } TEST_F(ExpectFatalFailureTest, CanBeUsedInNonVoidFunction) { NonVoidFunction(); } // Tests that EXPECT_FATAL_FAILURE(statement, ...) doesn't abort the // current function even though 'statement' generates a fatal failure. void DoesNotAbortHelper(bool* aborted) { EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); *aborted = false; } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" suppressed them. #pragma option pop #endif TEST_F(ExpectFatalFailureTest, DoesNotAbort) { bool aborted = true; DoesNotAbortHelper(&aborted); EXPECT_FALSE(aborted); } // Tests that the EXPECT_FATAL_FAILURE{,_ON_ALL_THREADS} accepts a // statement that contains a macro which expands to code containing an // unprotected comma. static int global_var = 0; #define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++ TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { #if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600 // ICE's in C++Builder 2007. EXPECT_FATAL_FAILURE({ GTEST_USE_UNPROTECTED_COMMA_; AddFatalFailure(); }, ""); #endif EXPECT_FATAL_FAILURE_ON_ALL_THREADS({ GTEST_USE_UNPROTECTED_COMMA_; AddFatalFailure(); }, ""); } // Tests EXPECT_NONFATAL_FAILURE{,ON_ALL_THREADS}. typedef ScopedFakeTestPartResultReporterTest ExpectNonfatalFailureTest; TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailure) { EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), "Expected non-fatal failure."); } TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailureOnAllThreads) { // We have another test below to verify that the macro catches // non-fatal failures generated on another thread. EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddNonfatalFailure(), "Expected non-fatal failure."); } // Tests that the EXPECT_NONFATAL_FAILURE{,_ON_ALL_THREADS} accepts a // statement that contains a macro which expands to code containing an // unprotected comma. TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { EXPECT_NONFATAL_FAILURE({ GTEST_USE_UNPROTECTED_COMMA_; AddNonfatalFailure(); }, ""); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS({ GTEST_USE_UNPROTECTED_COMMA_; AddNonfatalFailure(); }, ""); } #if GTEST_IS_THREADSAFE typedef ScopedFakeTestPartResultReporterWithThreadsTest ExpectFailureWithThreadsTest; TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailureOnAllThreads) { EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailureInOtherThread(FATAL_FAILURE), "Expected fatal failure."); } TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) { EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); } #endif // GTEST_IS_THREADSAFE // Tests the TestProperty class. TEST(TestPropertyTest, ConstructorWorks) { const TestProperty property("key", "value"); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("value", property.value()); } TEST(TestPropertyTest, SetValue) { TestProperty property("key", "value_1"); EXPECT_STREQ("key", property.key()); property.SetValue("value_2"); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("value_2", property.value()); } // Tests the TestResult class // The test fixture for testing TestResult. class TestResultTest : public Test { protected: typedef std::vector TPRVector; // We make use of 2 TestPartResult objects, TestPartResult * pr1, * pr2; // ... and 3 TestResult objects. TestResult * r0, * r1, * r2; virtual void SetUp() { // pr1 is for success. pr1 = new TestPartResult(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"); // pr2 is for fatal failure. pr2 = new TestPartResult(TestPartResult::kFatalFailure, "foo/bar.cc", -1, // This line number means "unknown" "Failure!"); // Creates the TestResult objects. r0 = new TestResult(); r1 = new TestResult(); r2 = new TestResult(); // In order to test TestResult, we need to modify its internal // state, in particular the TestPartResult vector it holds. // test_part_results() returns a const reference to this vector. // We cast it to a non-const object s.t. it can be modified (yes, // this is a hack). TPRVector* results1 = const_cast( &TestResultAccessor::test_part_results(*r1)); TPRVector* results2 = const_cast( &TestResultAccessor::test_part_results(*r2)); // r0 is an empty TestResult. // r1 contains a single SUCCESS TestPartResult. results1->push_back(*pr1); // r2 contains a SUCCESS, and a FAILURE. results2->push_back(*pr1); results2->push_back(*pr2); } virtual void TearDown() { delete pr1; delete pr2; delete r0; delete r1; delete r2; } // Helper that compares two two TestPartResults. static void CompareTestPartResult(const TestPartResult& expected, const TestPartResult& actual) { EXPECT_EQ(expected.type(), actual.type()); EXPECT_STREQ(expected.file_name(), actual.file_name()); EXPECT_EQ(expected.line_number(), actual.line_number()); EXPECT_STREQ(expected.summary(), actual.summary()); EXPECT_STREQ(expected.message(), actual.message()); EXPECT_EQ(expected.passed(), actual.passed()); EXPECT_EQ(expected.failed(), actual.failed()); EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed()); EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed()); } }; // Tests TestResult::total_part_count(). TEST_F(TestResultTest, total_part_count) { ASSERT_EQ(0, r0->total_part_count()); ASSERT_EQ(1, r1->total_part_count()); ASSERT_EQ(2, r2->total_part_count()); } // Tests TestResult::Passed(). TEST_F(TestResultTest, Passed) { ASSERT_TRUE(r0->Passed()); ASSERT_TRUE(r1->Passed()); ASSERT_FALSE(r2->Passed()); } // Tests TestResult::Failed(). TEST_F(TestResultTest, Failed) { ASSERT_FALSE(r0->Failed()); ASSERT_FALSE(r1->Failed()); ASSERT_TRUE(r2->Failed()); } // Tests TestResult::GetTestPartResult(). typedef TestResultTest TestResultDeathTest; TEST_F(TestResultDeathTest, GetTestPartResult) { CompareTestPartResult(*pr1, r2->GetTestPartResult(0)); CompareTestPartResult(*pr2, r2->GetTestPartResult(1)); EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(2), ""); EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(-1), ""); } // Tests TestResult has no properties when none are added. TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) { TestResult test_result; ASSERT_EQ(0, test_result.test_property_count()); } // Tests TestResult has the expected property when added. TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded) { TestResult test_result; TestProperty property("key_1", "1"); TestResultAccessor::RecordProperty(&test_result, property); ASSERT_EQ(1, test_result.test_property_count()); const TestProperty& actual_property = test_result.GetTestProperty(0); EXPECT_STREQ("key_1", actual_property.key()); EXPECT_STREQ("1", actual_property.value()); } // Tests TestResult has multiple properties when added. TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) { TestResult test_result; TestProperty property_1("key_1", "1"); TestProperty property_2("key_2", "2"); TestResultAccessor::RecordProperty(&test_result, property_1); TestResultAccessor::RecordProperty(&test_result, property_2); ASSERT_EQ(2, test_result.test_property_count()); const TestProperty& actual_property_1 = test_result.GetTestProperty(0); EXPECT_STREQ("key_1", actual_property_1.key()); EXPECT_STREQ("1", actual_property_1.value()); const TestProperty& actual_property_2 = test_result.GetTestProperty(1); EXPECT_STREQ("key_2", actual_property_2.key()); EXPECT_STREQ("2", actual_property_2.value()); } // Tests TestResult::RecordProperty() overrides values for duplicate keys. TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) { TestResult test_result; TestProperty property_1_1("key_1", "1"); TestProperty property_2_1("key_2", "2"); TestProperty property_1_2("key_1", "12"); TestProperty property_2_2("key_2", "22"); TestResultAccessor::RecordProperty(&test_result, property_1_1); TestResultAccessor::RecordProperty(&test_result, property_2_1); TestResultAccessor::RecordProperty(&test_result, property_1_2); TestResultAccessor::RecordProperty(&test_result, property_2_2); ASSERT_EQ(2, test_result.test_property_count()); const TestProperty& actual_property_1 = test_result.GetTestProperty(0); EXPECT_STREQ("key_1", actual_property_1.key()); EXPECT_STREQ("12", actual_property_1.value()); const TestProperty& actual_property_2 = test_result.GetTestProperty(1); EXPECT_STREQ("key_2", actual_property_2.key()); EXPECT_STREQ("22", actual_property_2.value()); } // Tests TestResult::GetTestProperty(). TEST(TestResultPropertyDeathTest, GetTestProperty) { TestResult test_result; TestProperty property_1("key_1", "1"); TestProperty property_2("key_2", "2"); TestProperty property_3("key_3", "3"); TestResultAccessor::RecordProperty(&test_result, property_1); TestResultAccessor::RecordProperty(&test_result, property_2); TestResultAccessor::RecordProperty(&test_result, property_3); const TestProperty& fetched_property_1 = test_result.GetTestProperty(0); const TestProperty& fetched_property_2 = test_result.GetTestProperty(1); const TestProperty& fetched_property_3 = test_result.GetTestProperty(2); EXPECT_STREQ("key_1", fetched_property_1.key()); EXPECT_STREQ("1", fetched_property_1.value()); EXPECT_STREQ("key_2", fetched_property_2.key()); EXPECT_STREQ("2", fetched_property_2.value()); EXPECT_STREQ("key_3", fetched_property_3.key()); EXPECT_STREQ("3", fetched_property_3.value()); EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(3), ""); EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(-1), ""); } // When a property using a reserved key is supplied to this function, it tests // that a non-fatal failure is added, a fatal failure is not added, and that the // property is not recorded. void ExpectNonFatalFailureRecordingPropertyWithReservedKey(const char* key) { TestResult test_result; TestProperty property(key, "1"); EXPECT_NONFATAL_FAILURE( TestResultAccessor::RecordProperty(&test_result, property), "Reserved key"); ASSERT_EQ(0, test_result.test_property_count()) << "Not recorded"; } // Attempting to recording a property with the Reserved literal "name" // should add a non-fatal failure and the property should not be recorded. TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledName) { ExpectNonFatalFailureRecordingPropertyWithReservedKey("name"); } // Attempting to recording a property with the Reserved literal "status" // should add a non-fatal failure and the property should not be recorded. TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledStatus) { ExpectNonFatalFailureRecordingPropertyWithReservedKey("status"); } // Attempting to recording a property with the Reserved literal "time" // should add a non-fatal failure and the property should not be recorded. TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledTime) { ExpectNonFatalFailureRecordingPropertyWithReservedKey("time"); } // Attempting to recording a property with the Reserved literal "classname" // should add a non-fatal failure and the property should not be recorded. TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledClassname) { ExpectNonFatalFailureRecordingPropertyWithReservedKey("classname"); } // Tests that GTestFlagSaver works on Windows and Mac. class GTestFlagSaverTest : public Test { protected: // Saves the Google Test flags such that we can restore them later, and // then sets them to their default values. This will be called // before the first test in this test case is run. static void SetUpTestCase() { saver_ = new GTestFlagSaver; GTEST_FLAG(also_run_disabled_tests) = false; GTEST_FLAG(break_on_failure) = false; GTEST_FLAG(catch_exceptions) = false; GTEST_FLAG(death_test_use_fork) = false; GTEST_FLAG(color) = "auto"; GTEST_FLAG(filter) = ""; GTEST_FLAG(list_tests) = false; GTEST_FLAG(output) = ""; GTEST_FLAG(print_time) = true; GTEST_FLAG(random_seed) = 0; GTEST_FLAG(repeat) = 1; GTEST_FLAG(shuffle) = false; GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; GTEST_FLAG(throw_on_failure) = false; } // Restores the Google Test flags that the tests have modified. This will // be called after the last test in this test case is run. static void TearDownTestCase() { delete saver_; saver_ = NULL; } // Verifies that the Google Test flags have their default values, and then // modifies each of them. void VerifyAndModifyFlags() { EXPECT_FALSE(GTEST_FLAG(also_run_disabled_tests)); EXPECT_FALSE(GTEST_FLAG(break_on_failure)); EXPECT_FALSE(GTEST_FLAG(catch_exceptions)); EXPECT_STREQ("auto", GTEST_FLAG(color).c_str()); EXPECT_FALSE(GTEST_FLAG(death_test_use_fork)); EXPECT_STREQ("", GTEST_FLAG(filter).c_str()); EXPECT_FALSE(GTEST_FLAG(list_tests)); EXPECT_STREQ("", GTEST_FLAG(output).c_str()); EXPECT_TRUE(GTEST_FLAG(print_time)); EXPECT_EQ(0, GTEST_FLAG(random_seed)); EXPECT_EQ(1, GTEST_FLAG(repeat)); EXPECT_FALSE(GTEST_FLAG(shuffle)); EXPECT_EQ(kMaxStackTraceDepth, GTEST_FLAG(stack_trace_depth)); EXPECT_FALSE(GTEST_FLAG(throw_on_failure)); GTEST_FLAG(also_run_disabled_tests) = true; GTEST_FLAG(break_on_failure) = true; GTEST_FLAG(catch_exceptions) = true; GTEST_FLAG(color) = "no"; GTEST_FLAG(death_test_use_fork) = true; GTEST_FLAG(filter) = "abc"; GTEST_FLAG(list_tests) = true; GTEST_FLAG(output) = "xml:foo.xml"; GTEST_FLAG(print_time) = false; GTEST_FLAG(random_seed) = 1; GTEST_FLAG(repeat) = 100; GTEST_FLAG(shuffle) = true; GTEST_FLAG(stack_trace_depth) = 1; GTEST_FLAG(throw_on_failure) = true; } private: // For saving Google Test flags during this test case. static GTestFlagSaver* saver_; }; GTestFlagSaver* GTestFlagSaverTest::saver_ = NULL; // Google Test doesn't guarantee the order of tests. The following two // tests are designed to work regardless of their order. // Modifies the Google Test flags in the test body. TEST_F(GTestFlagSaverTest, ModifyGTestFlags) { VerifyAndModifyFlags(); } // Verifies that the Google Test flags in the body of the previous test were // restored to their original values. TEST_F(GTestFlagSaverTest, VerifyGTestFlags) { VerifyAndModifyFlags(); } // Sets an environment variable with the given name to the given // value. If the value argument is "", unsets the environment // variable. The caller must ensure that both arguments are not NULL. static void SetEnv(const char* name, const char* value) { #if GTEST_OS_WINDOWS_MOBILE // Environment variables are not supported on Windows CE. return; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // C++Builder's putenv only stores a pointer to its parameter; we have to // ensure that the string remains valid as long as it might be needed. // We use an std::map to do so. static std::map added_env; // Because putenv stores a pointer to the string buffer, we can't delete the // previous string (if present) until after it's replaced. String *prev_env = NULL; if (added_env.find(name) != added_env.end()) { prev_env = added_env[name]; } added_env[name] = new String((Message() << name << "=" << value).GetString()); // The standard signature of putenv accepts a 'char*' argument. Other // implementations, like C++Builder's, accept a 'const char*'. // We cast away the 'const' since that would work for both variants. putenv(const_cast(added_env[name]->c_str())); delete prev_env; #elif GTEST_OS_WINDOWS // If we are on Windows proper. _putenv((Message() << name << "=" << value).GetString().c_str()); #else if (*value == '\0') { unsetenv(name); } else { setenv(name, value, 1); } #endif // GTEST_OS_WINDOWS_MOBILE } #if !GTEST_OS_WINDOWS_MOBILE // Environment variables are not supported on Windows CE. using testing::internal::Int32FromGTestEnv; // Tests Int32FromGTestEnv(). // Tests that Int32FromGTestEnv() returns the default value when the // environment variable is not set. TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenVariableIsNotSet) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", ""); EXPECT_EQ(10, Int32FromGTestEnv("temp", 10)); } // Tests that Int32FromGTestEnv() returns the default value when the // environment variable overflows as an Int32. TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueOverflows) { printf("(expecting 2 warnings)\n"); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12345678987654321"); EXPECT_EQ(20, Int32FromGTestEnv("temp", 20)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-12345678987654321"); EXPECT_EQ(30, Int32FromGTestEnv("temp", 30)); } // Tests that Int32FromGTestEnv() returns the default value when the // environment variable does not represent a valid decimal integer. TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueIsInvalid) { printf("(expecting 2 warnings)\n"); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "A1"); EXPECT_EQ(40, Int32FromGTestEnv("temp", 40)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12X"); EXPECT_EQ(50, Int32FromGTestEnv("temp", 50)); } // Tests that Int32FromGTestEnv() parses and returns the value of the // environment variable when it represents a valid decimal integer in // the range of an Int32. TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "123"); EXPECT_EQ(123, Int32FromGTestEnv("temp", 0)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321"); EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Tests ParseInt32Flag(). // Tests that ParseInt32Flag() returns false and doesn't change the // output value when the flag has wrong format TEST(ParseInt32FlagTest, ReturnsFalseForInvalidFlag) { Int32 value = 123; EXPECT_FALSE(ParseInt32Flag("--a=100", "b", &value)); EXPECT_EQ(123, value); EXPECT_FALSE(ParseInt32Flag("a=100", "a", &value)); EXPECT_EQ(123, value); } // Tests that ParseInt32Flag() returns false and doesn't change the // output value when the flag overflows as an Int32. TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueOverflows) { printf("(expecting 2 warnings)\n"); Int32 value = 123; EXPECT_FALSE(ParseInt32Flag("--abc=12345678987654321", "abc", &value)); EXPECT_EQ(123, value); EXPECT_FALSE(ParseInt32Flag("--abc=-12345678987654321", "abc", &value)); EXPECT_EQ(123, value); } // Tests that ParseInt32Flag() returns false and doesn't change the // output value when the flag does not represent a valid decimal // integer. TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueIsInvalid) { printf("(expecting 2 warnings)\n"); Int32 value = 123; EXPECT_FALSE(ParseInt32Flag("--abc=A1", "abc", &value)); EXPECT_EQ(123, value); EXPECT_FALSE(ParseInt32Flag("--abc=12X", "abc", &value)); EXPECT_EQ(123, value); } // Tests that ParseInt32Flag() parses the value of the flag and // returns true when the flag represents a valid decimal integer in // the range of an Int32. TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) { Int32 value = 123; EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=456", "abc", &value)); EXPECT_EQ(456, value); EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=-789", "abc", &value)); EXPECT_EQ(-789, value); } // Tests that Int32FromEnvOrDie() parses the value of the var or // returns the correct default. // Environment variables are not supported on Windows CE. #if !GTEST_OS_WINDOWS_MOBILE TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123"); EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123"); EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable is not an Int32. TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx"); EXPECT_DEATH_IF_SUPPORTED( Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), ".*"); } // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable cannot be represnted by an Int32. TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234"); EXPECT_DEATH_IF_SUPPORTED( Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), ".*"); } // Tests that ShouldRunTestOnShard() selects all tests // where there is 1 shard. TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) { EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4)); } class ShouldShardTest : public testing::Test { protected: virtual void SetUp() { index_var_ = GTEST_FLAG_PREFIX_UPPER_ "INDEX"; total_var_ = GTEST_FLAG_PREFIX_UPPER_ "TOTAL"; } virtual void TearDown() { SetEnv(index_var_, ""); SetEnv(total_var_, ""); } const char* index_var_; const char* total_var_; }; // Tests that sharding is disabled if neither of the environment variables // are set. TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet) { SetEnv(index_var_, ""); SetEnv(total_var_, ""); EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } // Tests that sharding is not enabled if total_shards == 1. TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) { SetEnv(index_var_, "0"); SetEnv(total_var_, "1"); EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } // Tests that sharding is enabled if total_shards > 1 and // we are not in a death test subprocess. // Environment variables are not supported on Windows CE. #if !GTEST_OS_WINDOWS_MOBILE TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { SetEnv(index_var_, "4"); SetEnv(total_var_, "22"); EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); SetEnv(index_var_, "8"); SetEnv(total_var_, "9"); EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); SetEnv(index_var_, "0"); SetEnv(total_var_, "9"); EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Tests that we exit in error if the sharding values are not valid. typedef ShouldShardTest ShouldShardDeathTest; TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid) { SetEnv(index_var_, "4"); SetEnv(total_var_, "4"); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); SetEnv(index_var_, "4"); SetEnv(total_var_, "-2"); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); SetEnv(index_var_, "5"); SetEnv(total_var_, ""); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); SetEnv(index_var_, ""); SetEnv(total_var_, "5"); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); } // Tests that ShouldRunTestOnShard is a partition when 5 // shards are used. TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) { // Choose an arbitrary number of tests and shards. const int num_tests = 17; const int num_shards = 5; // Check partitioning: each test should be on exactly 1 shard. for (int test_id = 0; test_id < num_tests; test_id++) { int prev_selected_shard_index = -1; for (int shard_index = 0; shard_index < num_shards; shard_index++) { if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) { if (prev_selected_shard_index < 0) { prev_selected_shard_index = shard_index; } else { ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and " << shard_index << " are both selected to run test " << test_id; } } } } // Check balance: This is not required by the sharding protocol, but is a // desirable property for performance. for (int shard_index = 0; shard_index < num_shards; shard_index++) { int num_tests_on_shard = 0; for (int test_id = 0; test_id < num_tests; test_id++) { num_tests_on_shard += ShouldRunTestOnShard(num_shards, shard_index, test_id); } EXPECT_GE(num_tests_on_shard, num_tests / num_shards); } } // For the same reason we are not explicitly testing everything in the // Test class, there are no separate tests for the following classes // (except for some trivial cases): // // TestCase, UnitTest, UnitTestResultPrinter. // // Similarly, there are no separate tests for the following macros: // // TEST, TEST_F, RUN_ALL_TESTS TEST(UnitTestTest, CanGetOriginalWorkingDir) { ASSERT_TRUE(UnitTest::GetInstance()->original_working_dir() != NULL); EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), ""); } // This group of tests is for predicate assertions (ASSERT_PRED*, etc) // of various arities. They do not attempt to be exhaustive. Rather, // view them as smoke tests that can be easily reviewed and verified. // A more complete set of tests for predicate assertions can be found // in gtest_pred_impl_unittest.cc. // First, some predicates and predicate-formatters needed by the tests. // Returns true iff the argument is an even number. bool IsEven(int n) { return (n % 2) == 0; } // A functor that returns true iff the argument is an even number. struct IsEvenFunctor { bool operator()(int n) { return IsEven(n); } }; // A predicate-formatter function that asserts the argument is an even // number. AssertionResult AssertIsEven(const char* expr, int n) { if (IsEven(n)) { return AssertionSuccess(); } Message msg; msg << expr << " evaluates to " << n << ", which is not even."; return AssertionFailure(msg); } // A predicate function that returns AssertionResult for use in // EXPECT/ASSERT_TRUE/FALSE. AssertionResult ResultIsEven(int n) { if (IsEven(n)) return AssertionSuccess() << n << " is even"; else return AssertionFailure() << n << " is odd"; } // A predicate function that returns AssertionResult but gives no // explanation why it succeeds. Needed for testing that // EXPECT/ASSERT_FALSE handles such functions correctly. AssertionResult ResultIsEvenNoExplanation(int n) { if (IsEven(n)) return AssertionSuccess(); else return AssertionFailure() << n << " is odd"; } // A predicate-formatter functor that asserts the argument is an even // number. struct AssertIsEvenFunctor { AssertionResult operator()(const char* expr, int n) { return AssertIsEven(expr, n); } }; // Returns true iff the sum of the arguments is an even number. bool SumIsEven2(int n1, int n2) { return IsEven(n1 + n2); } // A functor that returns true iff the sum of the arguments is an even // number. struct SumIsEven3Functor { bool operator()(int n1, int n2, int n3) { return IsEven(n1 + n2 + n3); } }; // A predicate-formatter function that asserts the sum of the // arguments is an even number. AssertionResult AssertSumIsEven4( const char* e1, const char* e2, const char* e3, const char* e4, int n1, int n2, int n3, int n4) { const int sum = n1 + n2 + n3 + n4; if (IsEven(sum)) { return AssertionSuccess(); } Message msg; msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4 << ") evaluates to " << sum << ", which is not even."; return AssertionFailure(msg); } // A predicate-formatter functor that asserts the sum of the arguments // is an even number. struct AssertSumIsEven5Functor { AssertionResult operator()( const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, int n1, int n2, int n3, int n4, int n5) { const int sum = n1 + n2 + n3 + n4 + n5; if (IsEven(sum)) { return AssertionSuccess(); } Message msg; msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4 << " + " << n5 << ") evaluates to " << sum << ", which is not even."; return AssertionFailure(msg); } }; // Tests unary predicate assertions. // Tests unary predicate assertions that don't use a custom formatter. TEST(Pred1Test, WithoutFormat) { // Success cases. EXPECT_PRED1(IsEvenFunctor(), 2) << "This failure is UNEXPECTED!"; ASSERT_PRED1(IsEven, 4); // Failure cases. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(IsEven, 5) << "This failure is expected."; }, "This failure is expected."); EXPECT_FATAL_FAILURE(ASSERT_PRED1(IsEvenFunctor(), 5), "evaluates to false"); } // Tests unary predicate assertions that use a custom formatter. TEST(Pred1Test, WithFormat) { // Success cases. EXPECT_PRED_FORMAT1(AssertIsEven, 2); ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), 4) << "This failure is UNEXPECTED!"; // Failure cases. const int n = 5; EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT1(AssertIsEvenFunctor(), n), "n evaluates to 5, which is not even."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(AssertIsEven, 5) << "This failure is expected."; }, "This failure is expected."); } // Tests that unary predicate assertions evaluates their arguments // exactly once. TEST(Pred1Test, SingleEvaluationOnFailure) { // A success case. static int n = 0; EXPECT_PRED1(IsEven, n++); EXPECT_EQ(1, n) << "The argument is not evaluated exactly once."; // A failure case. EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), n++) << "This failure is expected."; }, "This failure is expected."); EXPECT_EQ(2, n) << "The argument is not evaluated exactly once."; } // Tests predicate assertions whose arity is >= 2. // Tests predicate assertions that don't use a custom formatter. TEST(PredTest, WithoutFormat) { // Success cases. ASSERT_PRED2(SumIsEven2, 2, 4) << "This failure is UNEXPECTED!"; EXPECT_PRED3(SumIsEven3Functor(), 4, 6, 8); // Failure cases. const int n1 = 1; const int n2 = 2; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(SumIsEven2, n1, n2) << "This failure is expected."; }, "This failure is expected."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(SumIsEven3Functor(), 1, 2, 4); }, "evaluates to false"); } // Tests predicate assertions that use a custom formatter. TEST(PredTest, WithFormat) { // Success cases. ASSERT_PRED_FORMAT4(AssertSumIsEven4, 4, 6, 8, 10) << "This failure is UNEXPECTED!"; EXPECT_PRED_FORMAT5(AssertSumIsEven5Functor(), 2, 4, 6, 8, 10); // Failure cases. const int n1 = 1; const int n2 = 2; const int n3 = 4; const int n4 = 6; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(AssertSumIsEven4, n1, n2, n3, n4); }, "evaluates to 13, which is not even."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), 1, 2, 4, 6, 8) << "This failure is expected."; }, "This failure is expected."); } // Tests that predicate assertions evaluates their arguments // exactly once. TEST(PredTest, SingleEvaluationOnFailure) { // A success case. int n1 = 0; int n2 = 0; EXPECT_PRED2(SumIsEven2, n1++, n2++); EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; // Another success case. n1 = n2 = 0; int n3 = 0; int n4 = 0; int n5 = 0; ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), n1++, n2++, n3++, n4++, n5++) << "This failure is UNEXPECTED!"; EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; EXPECT_EQ(1, n5) << "Argument 5 is not evaluated exactly once."; // A failure case. n1 = n2 = n3 = 0; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(SumIsEven3Functor(), ++n1, n2++, n3++) << "This failure is expected."; }, "This failure is expected."); EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; // Another failure case. n1 = n2 = n3 = n4 = 0; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(AssertSumIsEven4, ++n1, n2++, n3++, n4++); }, "evaluates to 1, which is not even."); EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; } // Some helper functions for testing using overloaded/template // functions with ASSERT_PREDn and EXPECT_PREDn. bool IsPositive(double x) { return x > 0; } template bool IsNegative(T x) { return x < 0; } template bool GreaterThan(T1 x1, T2 x2) { return x1 > x2; } // Tests that overloaded functions can be used in *_PRED* as long as // their types are explicitly specified. TEST(PredicateAssertionTest, AcceptsOverloadedFunction) { // C++Builder requires C-style casts rather than static_cast. EXPECT_PRED1((bool (*)(int))(IsPositive), 5); // NOLINT ASSERT_PRED1((bool (*)(double))(IsPositive), 6.0); // NOLINT } // Tests that template functions can be used in *_PRED* as long as // their types are explicitly specified. TEST(PredicateAssertionTest, AcceptsTemplateFunction) { EXPECT_PRED1(IsNegative, -5); // Makes sure that we can handle templates with more than one // parameter. ASSERT_PRED2((GreaterThan), 5, 0); } // Some helper functions for testing using overloaded/template // functions with ASSERT_PRED_FORMATn and EXPECT_PRED_FORMATn. AssertionResult IsPositiveFormat(const char* /* expr */, int n) { return n > 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } AssertionResult IsPositiveFormat(const char* /* expr */, double x) { return x > 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } template AssertionResult IsNegativeFormat(const char* /* expr */, T x) { return x < 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } template AssertionResult EqualsFormat(const char* /* expr1 */, const char* /* expr2 */, const T1& x1, const T2& x2) { return x1 == x2 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } // Tests that overloaded functions can be used in *_PRED_FORMAT* // without explicitly specifying their types. TEST(PredicateFormatAssertionTest, AcceptsOverloadedFunction) { EXPECT_PRED_FORMAT1(IsPositiveFormat, 5); ASSERT_PRED_FORMAT1(IsPositiveFormat, 6.0); } // Tests that template functions can be used in *_PRED_FORMAT* without // explicitly specifying their types. TEST(PredicateFormatAssertionTest, AcceptsTemplateFunction) { EXPECT_PRED_FORMAT1(IsNegativeFormat, -5); ASSERT_PRED_FORMAT2(EqualsFormat, 3, 3); } // Tests string assertions. // Tests ASSERT_STREQ with non-NULL arguments. TEST(StringAssertionTest, ASSERT_STREQ) { const char * const p1 = "good"; ASSERT_STREQ(p1, p1); // Let p2 have the same content as p1, but be at a different address. const char p2[] = "good"; ASSERT_STREQ(p1, p2); EXPECT_FATAL_FAILURE(ASSERT_STREQ("bad", "good"), "Expected: \"bad\""); } // Tests ASSERT_STREQ with NULL arguments. TEST(StringAssertionTest, ASSERT_STREQ_Null) { ASSERT_STREQ(static_cast(NULL), NULL); EXPECT_FATAL_FAILURE(ASSERT_STREQ(NULL, "non-null"), "non-null"); } // Tests ASSERT_STREQ with NULL arguments. TEST(StringAssertionTest, ASSERT_STREQ_Null2) { EXPECT_FATAL_FAILURE(ASSERT_STREQ("non-null", NULL), "non-null"); } // Tests ASSERT_STRNE. TEST(StringAssertionTest, ASSERT_STRNE) { ASSERT_STRNE("hi", "Hi"); ASSERT_STRNE("Hi", NULL); ASSERT_STRNE(NULL, "Hi"); ASSERT_STRNE("", NULL); ASSERT_STRNE(NULL, ""); ASSERT_STRNE("", "Hi"); ASSERT_STRNE("Hi", ""); EXPECT_FATAL_FAILURE(ASSERT_STRNE("Hi", "Hi"), "\"Hi\" vs \"Hi\""); } // Tests ASSERT_STRCASEEQ. TEST(StringAssertionTest, ASSERT_STRCASEEQ) { ASSERT_STRCASEEQ("hi", "Hi"); ASSERT_STRCASEEQ(static_cast(NULL), NULL); ASSERT_STRCASEEQ("", ""); EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("Hi", "hi2"), "(ignoring case)"); } // Tests ASSERT_STRCASENE. TEST(StringAssertionTest, ASSERT_STRCASENE) { ASSERT_STRCASENE("hi1", "Hi2"); ASSERT_STRCASENE("Hi", NULL); ASSERT_STRCASENE(NULL, "Hi"); ASSERT_STRCASENE("", NULL); ASSERT_STRCASENE(NULL, ""); ASSERT_STRCASENE("", "Hi"); ASSERT_STRCASENE("Hi", ""); EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("Hi", "hi"), "(ignoring case)"); } // Tests *_STREQ on wide strings. TEST(StringAssertionTest, STREQ_Wide) { // NULL strings. ASSERT_STREQ(static_cast(NULL), NULL); // Empty strings. ASSERT_STREQ(L"", L""); // Non-null vs NULL. EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"non-null", NULL), "non-null"); // Equal strings. EXPECT_STREQ(L"Hi", L"Hi"); // Unequal strings. EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc", L"Abc"), "Abc"); // Strings containing wide characters. EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc\x8119", L"abc\x8120"), "abc"); } // Tests *_STRNE on wide strings. TEST(StringAssertionTest, STRNE_Wide) { // NULL strings. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_STRNE(static_cast(NULL), NULL); }, ""); // Empty strings. EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"", L""), "L\"\""); // Non-null vs NULL. ASSERT_STRNE(L"non-null", NULL); // Equal strings. EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"Hi", L"Hi"), "L\"Hi\""); // Unequal strings. EXPECT_STRNE(L"abc", L"Abc"); // Strings containing wide characters. EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"abc\x8119", L"abc\x8119"), "abc"); } // Tests for ::testing::IsSubstring(). // Tests that IsSubstring() returns the correct result when the input // argument type is const char*. TEST(IsSubstringTest, ReturnsCorrectResultForCString) { EXPECT_FALSE(IsSubstring("", "", NULL, "a")); EXPECT_FALSE(IsSubstring("", "", "b", NULL)); EXPECT_FALSE(IsSubstring("", "", "needle", "haystack")); EXPECT_TRUE(IsSubstring("", "", static_cast(NULL), NULL)); EXPECT_TRUE(IsSubstring("", "", "needle", "two needles")); } // Tests that IsSubstring() returns the correct result when the input // argument type is const wchar_t*. TEST(IsSubstringTest, ReturnsCorrectResultForWideCString) { EXPECT_FALSE(IsSubstring("", "", kNull, L"a")); EXPECT_FALSE(IsSubstring("", "", L"b", kNull)); EXPECT_FALSE(IsSubstring("", "", L"needle", L"haystack")); EXPECT_TRUE(IsSubstring("", "", static_cast(NULL), NULL)); EXPECT_TRUE(IsSubstring("", "", L"needle", L"two needles")); } // Tests that IsSubstring() generates the correct message when the input // argument type is const char*. TEST(IsSubstringTest, GeneratesCorrectMessageForCString) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: \"needle\"\n" "Expected: a substring of haystack_expr\n" "Which is: \"haystack\"", IsSubstring("needle_expr", "haystack_expr", "needle", "haystack").failure_message()); } // Tests that IsSubstring returns the correct result when the input // argument type is ::std::string. TEST(IsSubstringTest, ReturnsCorrectResultsForStdString) { EXPECT_TRUE(IsSubstring("", "", std::string("hello"), "ahellob")); EXPECT_FALSE(IsSubstring("", "", "hello", std::string("world"))); } #if GTEST_HAS_STD_WSTRING // Tests that IsSubstring returns the correct result when the input // argument type is ::std::wstring. TEST(IsSubstringTest, ReturnsCorrectResultForStdWstring) { EXPECT_TRUE(IsSubstring("", "", ::std::wstring(L"needle"), L"two needles")); EXPECT_FALSE(IsSubstring("", "", L"needle", ::std::wstring(L"haystack"))); } // Tests that IsSubstring() generates the correct message when the input // argument type is ::std::wstring. TEST(IsSubstringTest, GeneratesCorrectMessageForWstring) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: L\"needle\"\n" "Expected: a substring of haystack_expr\n" "Which is: L\"haystack\"", IsSubstring( "needle_expr", "haystack_expr", ::std::wstring(L"needle"), L"haystack").failure_message()); } #endif // GTEST_HAS_STD_WSTRING // Tests for ::testing::IsNotSubstring(). // Tests that IsNotSubstring() returns the correct result when the input // argument type is const char*. TEST(IsNotSubstringTest, ReturnsCorrectResultForCString) { EXPECT_TRUE(IsNotSubstring("", "", "needle", "haystack")); EXPECT_FALSE(IsNotSubstring("", "", "needle", "two needles")); } // Tests that IsNotSubstring() returns the correct result when the input // argument type is const wchar_t*. TEST(IsNotSubstringTest, ReturnsCorrectResultForWideCString) { EXPECT_TRUE(IsNotSubstring("", "", L"needle", L"haystack")); EXPECT_FALSE(IsNotSubstring("", "", L"needle", L"two needles")); } // Tests that IsNotSubstring() generates the correct message when the input // argument type is const wchar_t*. TEST(IsNotSubstringTest, GeneratesCorrectMessageForWideCString) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: L\"needle\"\n" "Expected: not a substring of haystack_expr\n" "Which is: L\"two needles\"", IsNotSubstring( "needle_expr", "haystack_expr", L"needle", L"two needles").failure_message()); } // Tests that IsNotSubstring returns the correct result when the input // argument type is ::std::string. TEST(IsNotSubstringTest, ReturnsCorrectResultsForStdString) { EXPECT_FALSE(IsNotSubstring("", "", std::string("hello"), "ahellob")); EXPECT_TRUE(IsNotSubstring("", "", "hello", std::string("world"))); } // Tests that IsNotSubstring() generates the correct message when the input // argument type is ::std::string. TEST(IsNotSubstringTest, GeneratesCorrectMessageForStdString) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: \"needle\"\n" "Expected: not a substring of haystack_expr\n" "Which is: \"two needles\"", IsNotSubstring( "needle_expr", "haystack_expr", ::std::string("needle"), "two needles").failure_message()); } #if GTEST_HAS_STD_WSTRING // Tests that IsNotSubstring returns the correct result when the input // argument type is ::std::wstring. TEST(IsNotSubstringTest, ReturnsCorrectResultForStdWstring) { EXPECT_FALSE( IsNotSubstring("", "", ::std::wstring(L"needle"), L"two needles")); EXPECT_TRUE(IsNotSubstring("", "", L"needle", ::std::wstring(L"haystack"))); } #endif // GTEST_HAS_STD_WSTRING // Tests floating-point assertions. template class FloatingPointTest : public Test { protected: // Pre-calculated numbers to be used by the tests. struct TestValues { RawType close_to_positive_zero; RawType close_to_negative_zero; RawType further_from_negative_zero; RawType close_to_one; RawType further_from_one; RawType infinity; RawType close_to_infinity; RawType further_from_infinity; RawType nan1; RawType nan2; }; typedef typename testing::internal::FloatingPoint Floating; typedef typename Floating::Bits Bits; virtual void SetUp() { const size_t max_ulps = Floating::kMaxUlps; // The bits that represent 0.0. const Bits zero_bits = Floating(0).bits(); // Makes some numbers close to 0.0. values_.close_to_positive_zero = Floating::ReinterpretBits( zero_bits + max_ulps/2); values_.close_to_negative_zero = -Floating::ReinterpretBits( zero_bits + max_ulps - max_ulps/2); values_.further_from_negative_zero = -Floating::ReinterpretBits( zero_bits + max_ulps + 1 - max_ulps/2); // The bits that represent 1.0. const Bits one_bits = Floating(1).bits(); // Makes some numbers close to 1.0. values_.close_to_one = Floating::ReinterpretBits(one_bits + max_ulps); values_.further_from_one = Floating::ReinterpretBits( one_bits + max_ulps + 1); // +infinity. values_.infinity = Floating::Infinity(); // The bits that represent +infinity. const Bits infinity_bits = Floating(values_.infinity).bits(); // Makes some numbers close to infinity. values_.close_to_infinity = Floating::ReinterpretBits( infinity_bits - max_ulps); values_.further_from_infinity = Floating::ReinterpretBits( infinity_bits - max_ulps - 1); // Makes some NAN's. Sets the most significant bit of the fraction so that // our NaN's are quiet; trying to process a signaling NaN would raise an // exception if our environment enables floating point exceptions. values_.nan1 = Floating::ReinterpretBits(Floating::kExponentBitMask | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 1); values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 200); } void TestSize() { EXPECT_EQ(sizeof(RawType), sizeof(Bits)); } static TestValues values_; }; template typename FloatingPointTest::TestValues FloatingPointTest::values_; // Instantiates FloatingPointTest for testing *_FLOAT_EQ. typedef FloatingPointTest FloatTest; // Tests that the size of Float::Bits matches the size of float. TEST_F(FloatTest, Size) { TestSize(); } // Tests comparing with +0 and -0. TEST_F(FloatTest, Zeros) { EXPECT_FLOAT_EQ(0.0, -0.0); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(-0.0, 1.0), "1.0"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.5), "1.5"); } // Tests comparing numbers close to 0. // // This ensures that *_FLOAT_EQ handles the sign correctly and no // overflow occurs when comparing numbers whose absolute value is very // small. TEST_F(FloatTest, AlmostZeros) { // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const FloatTest::TestValues& v = this->values_; EXPECT_FLOAT_EQ(0.0, v.close_to_positive_zero); EXPECT_FLOAT_EQ(-0.0, v.close_to_negative_zero); EXPECT_FLOAT_EQ(v.close_to_positive_zero, v.close_to_negative_zero); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_FLOAT_EQ(v.close_to_positive_zero, v.further_from_negative_zero); }, "v.further_from_negative_zero"); } // Tests comparing numbers close to each other. TEST_F(FloatTest, SmallDiff) { EXPECT_FLOAT_EQ(1.0, values_.close_to_one); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, values_.further_from_one), "values_.further_from_one"); } // Tests comparing numbers far apart. TEST_F(FloatTest, LargeDiff) { EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(2.5, 3.0), "3.0"); } // Tests comparing with infinity. // // This ensures that no overflow occurs when comparing numbers whose // absolute value is very large. TEST_F(FloatTest, Infinity) { EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity); EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity); #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity), "-values_.infinity"); // This is interesting as the representations of infinity and nan1 // are only 1 DLP apart. EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, values_.nan1), "values_.nan1"); #endif // !GTEST_OS_SYMBIAN } // Tests that comparing with NAN always returns false. TEST_F(FloatTest, NaN) { #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const FloatTest::TestValues& v = this->values_; EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1), "v.nan1"); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2), "v.nan2"); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1), "v.nan1"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity), "v.infinity"); #endif // !GTEST_OS_SYMBIAN } // Tests that *_FLOAT_EQ are reflexive. TEST_F(FloatTest, Reflexive) { EXPECT_FLOAT_EQ(0.0, 0.0); EXPECT_FLOAT_EQ(1.0, 1.0); ASSERT_FLOAT_EQ(values_.infinity, values_.infinity); } // Tests that *_FLOAT_EQ are commutative. TEST_F(FloatTest, Commutative) { // We already tested EXPECT_FLOAT_EQ(1.0, values_.close_to_one). EXPECT_FLOAT_EQ(values_.close_to_one, 1.0); // We already tested EXPECT_FLOAT_EQ(1.0, values_.further_from_one). EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.further_from_one, 1.0), "1.0"); } // Tests EXPECT_NEAR. TEST_F(FloatTest, EXPECT_NEAR) { EXPECT_NEAR(-1.0f, -1.1f, 0.2f); EXPECT_NEAR(2.0f, 3.0f, 1.0f); EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f,1.5f, 0.25f), // NOLINT "The difference between 1.0f and 1.5f is 0.5, " "which exceeds 0.25f"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous line. } // Tests ASSERT_NEAR. TEST_F(FloatTest, ASSERT_NEAR) { ASSERT_NEAR(-1.0f, -1.1f, 0.2f); ASSERT_NEAR(2.0f, 3.0f, 1.0f); EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0f,1.5f, 0.25f), // NOLINT "The difference between 1.0f and 1.5f is 0.5, " "which exceeds 0.25f"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous line. } // Tests the cases where FloatLE() should succeed. TEST_F(FloatTest, FloatLESucceeds) { EXPECT_PRED_FORMAT2(FloatLE, 1.0f, 2.0f); // When val1 < val2, ASSERT_PRED_FORMAT2(FloatLE, 1.0f, 1.0f); // val1 == val2, // or when val1 is greater than, but almost equals to, val2. EXPECT_PRED_FORMAT2(FloatLE, values_.close_to_positive_zero, 0.0f); } // Tests the cases where FloatLE() should fail. TEST_F(FloatTest, FloatLEFails) { // When val1 is greater than val2 by a large margin, EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(FloatLE, 2.0f, 1.0f), "(2.0f) <= (1.0f)"); // or by a small yet non-negligible margin, EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(FloatLE, values_.further_from_one, 1.0f); }, "(values_.further_from_one) <= (1.0f)"); #if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) // Nokia's STLport crashes if we try to output infinity or NaN. // C++Builder gives bad results for ordered comparisons involving NaNs // due to compiler bugs. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(FloatLE, values_.nan1, values_.infinity); }, "(values_.nan1) <= (values_.infinity)"); EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(FloatLE, -values_.infinity, values_.nan1); }, "(-values_.infinity) <= (values_.nan1)"); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(FloatLE, values_.nan1, values_.nan1); }, "(values_.nan1) <= (values_.nan1)"); #endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) } // Instantiates FloatingPointTest for testing *_DOUBLE_EQ. typedef FloatingPointTest DoubleTest; // Tests that the size of Double::Bits matches the size of double. TEST_F(DoubleTest, Size) { TestSize(); } // Tests comparing with +0 and -0. TEST_F(DoubleTest, Zeros) { EXPECT_DOUBLE_EQ(0.0, -0.0); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(-0.0, 1.0), "1.0"); EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(0.0, 1.0), "1.0"); } // Tests comparing numbers close to 0. // // This ensures that *_DOUBLE_EQ handles the sign correctly and no // overflow occurs when comparing numbers whose absolute value is very // small. TEST_F(DoubleTest, AlmostZeros) { // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const DoubleTest::TestValues& v = this->values_; EXPECT_DOUBLE_EQ(0.0, v.close_to_positive_zero); EXPECT_DOUBLE_EQ(-0.0, v.close_to_negative_zero); EXPECT_DOUBLE_EQ(v.close_to_positive_zero, v.close_to_negative_zero); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_DOUBLE_EQ(v.close_to_positive_zero, v.further_from_negative_zero); }, "v.further_from_negative_zero"); } // Tests comparing numbers close to each other. TEST_F(DoubleTest, SmallDiff) { EXPECT_DOUBLE_EQ(1.0, values_.close_to_one); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, values_.further_from_one), "values_.further_from_one"); } // Tests comparing numbers far apart. TEST_F(DoubleTest, LargeDiff) { EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(2.0, 3.0), "3.0"); } // Tests comparing with infinity. // // This ensures that no overflow occurs when comparing numbers whose // absolute value is very large. TEST_F(DoubleTest, Infinity) { EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity); EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity); #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity), "-values_.infinity"); // This is interesting as the representations of infinity_ and nan1_ // are only 1 DLP apart. EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, values_.nan1), "values_.nan1"); #endif // !GTEST_OS_SYMBIAN } // Tests that comparing with NAN always returns false. TEST_F(DoubleTest, NaN) { #if !GTEST_OS_SYMBIAN // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const DoubleTest::TestValues& v = this->values_; // Nokia's STLport crashes if we try to output infinity or NaN. EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1), "v.nan1"); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2"); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1"); EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity), "v.infinity"); #endif // !GTEST_OS_SYMBIAN } // Tests that *_DOUBLE_EQ are reflexive. TEST_F(DoubleTest, Reflexive) { EXPECT_DOUBLE_EQ(0.0, 0.0); EXPECT_DOUBLE_EQ(1.0, 1.0); #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. ASSERT_DOUBLE_EQ(values_.infinity, values_.infinity); #endif // !GTEST_OS_SYMBIAN } // Tests that *_DOUBLE_EQ are commutative. TEST_F(DoubleTest, Commutative) { // We already tested EXPECT_DOUBLE_EQ(1.0, values_.close_to_one). EXPECT_DOUBLE_EQ(values_.close_to_one, 1.0); // We already tested EXPECT_DOUBLE_EQ(1.0, values_.further_from_one). EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.further_from_one, 1.0), "1.0"); } // Tests EXPECT_NEAR. TEST_F(DoubleTest, EXPECT_NEAR) { EXPECT_NEAR(-1.0, -1.1, 0.2); EXPECT_NEAR(2.0, 3.0, 1.0); EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT "The difference between 1.0 and 1.5 is 0.5, " "which exceeds 0.25"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous statement. } // Tests ASSERT_NEAR. TEST_F(DoubleTest, ASSERT_NEAR) { ASSERT_NEAR(-1.0, -1.1, 0.2); ASSERT_NEAR(2.0, 3.0, 1.0); EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0, 1.5, 0.25), // NOLINT "The difference between 1.0 and 1.5 is 0.5, " "which exceeds 0.25"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous statement. } // Tests the cases where DoubleLE() should succeed. TEST_F(DoubleTest, DoubleLESucceeds) { EXPECT_PRED_FORMAT2(DoubleLE, 1.0, 2.0); // When val1 < val2, ASSERT_PRED_FORMAT2(DoubleLE, 1.0, 1.0); // val1 == val2, // or when val1 is greater than, but almost equals to, val2. EXPECT_PRED_FORMAT2(DoubleLE, values_.close_to_positive_zero, 0.0); } // Tests the cases where DoubleLE() should fail. TEST_F(DoubleTest, DoubleLEFails) { // When val1 is greater than val2 by a large margin, EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(DoubleLE, 2.0, 1.0), "(2.0) <= (1.0)"); // or by a small yet non-negligible margin, EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(DoubleLE, values_.further_from_one, 1.0); }, "(values_.further_from_one) <= (1.0)"); #if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) // Nokia's STLport crashes if we try to output infinity or NaN. // C++Builder gives bad results for ordered comparisons involving NaNs // due to compiler bugs. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.infinity); }, "(values_.nan1) <= (values_.infinity)"); EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(DoubleLE, -values_.infinity, values_.nan1); }, " (-values_.infinity) <= (values_.nan1)"); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.nan1); }, "(values_.nan1) <= (values_.nan1)"); #endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) } // Verifies that a test or test case whose name starts with DISABLED_ is // not run. // A test whose name starts with DISABLED_. // Should not run. TEST(DisabledTest, DISABLED_TestShouldNotRun) { FAIL() << "Unexpected failure: Disabled test should not be run."; } // A test whose name does not start with DISABLED_. // Should run. TEST(DisabledTest, NotDISABLED_TestShouldRun) { EXPECT_EQ(1, 1); } // A test case whose name starts with DISABLED_. // Should not run. TEST(DISABLED_TestCase, TestShouldNotRun) { FAIL() << "Unexpected failure: Test in disabled test case should not be run."; } // A test case and test whose names start with DISABLED_. // Should not run. TEST(DISABLED_TestCase, DISABLED_TestShouldNotRun) { FAIL() << "Unexpected failure: Test in disabled test case should not be run."; } // Check that when all tests in a test case are disabled, SetupTestCase() and // TearDownTestCase() are not called. class DisabledTestsTest : public Test { protected: static void SetUpTestCase() { FAIL() << "Unexpected failure: All tests disabled in test case. " "SetupTestCase() should not be called."; } static void TearDownTestCase() { FAIL() << "Unexpected failure: All tests disabled in test case. " "TearDownTestCase() should not be called."; } }; TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_1) { FAIL() << "Unexpected failure: Disabled test should not be run."; } TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2) { FAIL() << "Unexpected failure: Disabled test should not be run."; } // Tests that disabled typed tests aren't run. #if GTEST_HAS_TYPED_TEST template class TypedTest : public Test { }; typedef testing::Types NumericTypes; TYPED_TEST_CASE(TypedTest, NumericTypes); TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) { FAIL() << "Unexpected failure: Disabled typed test should not run."; } template class DISABLED_TypedTest : public Test { }; TYPED_TEST_CASE(DISABLED_TypedTest, NumericTypes); TYPED_TEST(DISABLED_TypedTest, ShouldNotRun) { FAIL() << "Unexpected failure: Disabled typed test should not run."; } #endif // GTEST_HAS_TYPED_TEST // Tests that disabled type-parameterized tests aren't run. #if GTEST_HAS_TYPED_TEST_P template class TypedTestP : public Test { }; TYPED_TEST_CASE_P(TypedTestP); TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun) { FAIL() << "Unexpected failure: " << "Disabled type-parameterized test should not run."; } REGISTER_TYPED_TEST_CASE_P(TypedTestP, DISABLED_ShouldNotRun); INSTANTIATE_TYPED_TEST_CASE_P(My, TypedTestP, NumericTypes); template class DISABLED_TypedTestP : public Test { }; TYPED_TEST_CASE_P(DISABLED_TypedTestP); TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun) { FAIL() << "Unexpected failure: " << "Disabled type-parameterized test should not run."; } REGISTER_TYPED_TEST_CASE_P(DISABLED_TypedTestP, ShouldNotRun); INSTANTIATE_TYPED_TEST_CASE_P(My, DISABLED_TypedTestP, NumericTypes); #endif // GTEST_HAS_TYPED_TEST_P // Tests that assertion macros evaluate their arguments exactly once. class SingleEvaluationTest : public Test { public: // Must be public and not protected due to a bug in g++ 3.4.2. // This helper function is needed by the FailedASSERT_STREQ test // below. It's public to work around C++Builder's bug with scoping local // classes. static void CompareAndIncrementCharPtrs() { ASSERT_STREQ(p1_++, p2_++); } // This helper function is needed by the FailedASSERT_NE test below. It's // public to work around C++Builder's bug with scoping local classes. static void CompareAndIncrementInts() { ASSERT_NE(a_++, b_++); } protected: SingleEvaluationTest() { p1_ = s1_; p2_ = s2_; a_ = 0; b_ = 0; } static const char* const s1_; static const char* const s2_; static const char* p1_; static const char* p2_; static int a_; static int b_; }; const char* const SingleEvaluationTest::s1_ = "01234"; const char* const SingleEvaluationTest::s2_ = "abcde"; const char* SingleEvaluationTest::p1_; const char* SingleEvaluationTest::p2_; int SingleEvaluationTest::a_; int SingleEvaluationTest::b_; // Tests that when ASSERT_STREQ fails, it evaluates its arguments // exactly once. TEST_F(SingleEvaluationTest, FailedASSERT_STREQ) { EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementCharPtrs(), "p2_++"); EXPECT_EQ(s1_ + 1, p1_); EXPECT_EQ(s2_ + 1, p2_); } // Tests that string assertion arguments are evaluated exactly once. TEST_F(SingleEvaluationTest, ASSERT_STR) { // successful EXPECT_STRNE EXPECT_STRNE(p1_++, p2_++); EXPECT_EQ(s1_ + 1, p1_); EXPECT_EQ(s2_ + 1, p2_); // failed EXPECT_STRCASEEQ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ(p1_++, p2_++), "ignoring case"); EXPECT_EQ(s1_ + 2, p1_); EXPECT_EQ(s2_ + 2, p2_); } // Tests that when ASSERT_NE fails, it evaluates its arguments exactly // once. TEST_F(SingleEvaluationTest, FailedASSERT_NE) { EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementInts(), "(a_++) != (b_++)"); EXPECT_EQ(1, a_); EXPECT_EQ(1, b_); } // Tests that assertion arguments are evaluated exactly once. TEST_F(SingleEvaluationTest, OtherCases) { // successful EXPECT_TRUE EXPECT_TRUE(0 == a_++); // NOLINT EXPECT_EQ(1, a_); // failed EXPECT_TRUE EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(-1 == a_++), "-1 == a_++"); EXPECT_EQ(2, a_); // successful EXPECT_GT EXPECT_GT(a_++, b_++); EXPECT_EQ(3, a_); EXPECT_EQ(1, b_); // failed EXPECT_LT EXPECT_NONFATAL_FAILURE(EXPECT_LT(a_++, b_++), "(a_++) < (b_++)"); EXPECT_EQ(4, a_); EXPECT_EQ(2, b_); // successful ASSERT_TRUE ASSERT_TRUE(0 < a_++); // NOLINT EXPECT_EQ(5, a_); // successful ASSERT_GT ASSERT_GT(a_++, b_++); EXPECT_EQ(6, a_); EXPECT_EQ(3, b_); } #if GTEST_HAS_EXCEPTIONS void ThrowAnInteger() { throw 1; } // Tests that assertion arguments are evaluated exactly once. TEST_F(SingleEvaluationTest, ExceptionTests) { // successful EXPECT_THROW EXPECT_THROW({ // NOLINT a_++; ThrowAnInteger(); }, int); EXPECT_EQ(1, a_); // failed EXPECT_THROW, throws different EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT a_++; ThrowAnInteger(); }, bool), "throws a different type"); EXPECT_EQ(2, a_); // failed EXPECT_THROW, throws nothing EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); EXPECT_EQ(3, a_); // successful EXPECT_NO_THROW EXPECT_NO_THROW(a_++); EXPECT_EQ(4, a_); // failed EXPECT_NO_THROW EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT a_++; ThrowAnInteger(); }), "it throws"); EXPECT_EQ(5, a_); // successful EXPECT_ANY_THROW EXPECT_ANY_THROW({ // NOLINT a_++; ThrowAnInteger(); }); EXPECT_EQ(6, a_); // failed EXPECT_ANY_THROW EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); EXPECT_EQ(7, a_); } #endif // GTEST_HAS_EXCEPTIONS // Tests {ASSERT|EXPECT}_NO_FATAL_FAILURE. class NoFatalFailureTest : public Test { protected: void Succeeds() {} void FailsNonFatal() { ADD_FAILURE() << "some non-fatal failure"; } void Fails() { FAIL() << "some fatal failure"; } void DoAssertNoFatalFailureOnFails() { ASSERT_NO_FATAL_FAILURE(Fails()); ADD_FAILURE() << "shold not reach here."; } void DoExpectNoFatalFailureOnFails() { EXPECT_NO_FATAL_FAILURE(Fails()); ADD_FAILURE() << "other failure"; } }; TEST_F(NoFatalFailureTest, NoFailure) { EXPECT_NO_FATAL_FAILURE(Succeeds()); ASSERT_NO_FATAL_FAILURE(Succeeds()); } TEST_F(NoFatalFailureTest, NonFatalIsNoFailure) { EXPECT_NONFATAL_FAILURE( EXPECT_NO_FATAL_FAILURE(FailsNonFatal()), "some non-fatal failure"); EXPECT_NONFATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(FailsNonFatal()), "some non-fatal failure"); } TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure) { TestPartResultArray gtest_failures; { ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); DoAssertNoFatalFailureOnFails(); } ASSERT_EQ(2, gtest_failures.size()); EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(0).type()); EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", gtest_failures.GetTestPartResult(0).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", gtest_failures.GetTestPartResult(1).message()); } TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure) { TestPartResultArray gtest_failures; { ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); DoExpectNoFatalFailureOnFails(); } ASSERT_EQ(3, gtest_failures.size()); EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(0).type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(2).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", gtest_failures.GetTestPartResult(0).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", gtest_failures.GetTestPartResult(1).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "other failure", gtest_failures.GetTestPartResult(2).message()); } TEST_F(NoFatalFailureTest, MessageIsStreamable) { TestPartResultArray gtest_failures; { ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message"; } ASSERT_EQ(2, gtest_failures.size()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(0).type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo", gtest_failures.GetTestPartResult(0).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "my message", gtest_failures.GetTestPartResult(1).message()); } // Tests non-string assertions. // Tests EqFailure(), used for implementing *EQ* assertions. TEST(AssertionTest, EqFailure) { const String foo_val("5"), bar_val("6"); const String msg1( EqFailure("foo", "bar", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( "Value of: bar\n" " Actual: 6\n" "Expected: foo\n" "Which is: 5", msg1.c_str()); const String msg2( EqFailure("foo", "6", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( "Value of: 6\n" "Expected: foo\n" "Which is: 5", msg2.c_str()); const String msg3( EqFailure("5", "bar", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( "Value of: bar\n" " Actual: 6\n" "Expected: 5", msg3.c_str()); const String msg4( EqFailure("5", "6", foo_val, bar_val, false).failure_message()); EXPECT_STREQ( "Value of: 6\n" "Expected: 5", msg4.c_str()); const String msg5( EqFailure("foo", "bar", String("\"x\""), String("\"y\""), true).failure_message()); EXPECT_STREQ( "Value of: bar\n" " Actual: \"y\"\n" "Expected: foo (ignoring case)\n" "Which is: \"x\"", msg5.c_str()); } // Tests AppendUserMessage(), used for implementing the *EQ* macros. TEST(AssertionTest, AppendUserMessage) { const String foo("foo"); Message msg; EXPECT_STREQ("foo", AppendUserMessage(foo, msg).c_str()); msg << "bar"; EXPECT_STREQ("foo\nbar", AppendUserMessage(foo, msg).c_str()); } #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" #pragma option push -w-ccc -w-rch #endif // Tests ASSERT_TRUE. TEST(AssertionTest, ASSERT_TRUE) { ASSERT_TRUE(2 > 1); // NOLINT EXPECT_FATAL_FAILURE(ASSERT_TRUE(2 < 1), "2 < 1"); } // Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult. TEST(AssertionTest, AssertTrueWithAssertionResult) { ASSERT_TRUE(ResultIsEven(2)); #if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600 // ICE's in C++Builder 2007. EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)), "Value of: ResultIsEven(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); #endif ASSERT_TRUE(ResultIsEvenNoExplanation(2)); EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)), "Value of: ResultIsEvenNoExplanation(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); } // Tests ASSERT_FALSE. TEST(AssertionTest, ASSERT_FALSE) { ASSERT_FALSE(2 < 1); // NOLINT EXPECT_FATAL_FAILURE(ASSERT_FALSE(2 > 1), "Value of: 2 > 1\n" " Actual: true\n" "Expected: false"); } // Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult. TEST(AssertionTest, AssertFalseWithAssertionResult) { ASSERT_FALSE(ResultIsEven(3)); #if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600 // ICE's in C++Builder 2007. EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)), "Value of: ResultIsEven(2)\n" " Actual: true (2 is even)\n" "Expected: false"); #endif ASSERT_FALSE(ResultIsEvenNoExplanation(3)); EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)), "Value of: ResultIsEvenNoExplanation(2)\n" " Actual: true\n" "Expected: false"); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" supressed them #pragma option pop #endif // Tests using ASSERT_EQ on double values. The purpose is to make // sure that the specialization we did for integer and anonymous enums // isn't used for double arguments. TEST(ExpectTest, ASSERT_EQ_Double) { // A success. ASSERT_EQ(5.6, 5.6); // A failure. EXPECT_FATAL_FAILURE(ASSERT_EQ(5.1, 5.2), "5.1"); } // Tests ASSERT_EQ. TEST(AssertionTest, ASSERT_EQ) { ASSERT_EQ(5, 2 + 3); EXPECT_FATAL_FAILURE(ASSERT_EQ(5, 2*3), "Value of: 2*3\n" " Actual: 6\n" "Expected: 5"); } // Tests ASSERT_EQ(NULL, pointer). #if GTEST_CAN_COMPARE_NULL TEST(AssertionTest, ASSERT_EQ_NULL) { // A success. const char* p = NULL; // Some older GCC versions may issue a spurious waring in this or the next // assertion statement. This warning should not be suppressed with // static_cast since the test verifies the ability to use bare NULL as the // expected parameter to the macro. ASSERT_EQ(NULL, p); // A failure. static int n = 0; EXPECT_FATAL_FAILURE(ASSERT_EQ(NULL, &n), "Value of: &n\n"); } #endif // GTEST_CAN_COMPARE_NULL // Tests ASSERT_EQ(0, non_pointer). Since the literal 0 can be // treated as a null pointer by the compiler, we need to make sure // that ASSERT_EQ(0, non_pointer) isn't interpreted by Google Test as // ASSERT_EQ(static_cast(NULL), non_pointer). TEST(ExpectTest, ASSERT_EQ_0) { int n = 0; // A success. ASSERT_EQ(0, n); // A failure. EXPECT_FATAL_FAILURE(ASSERT_EQ(0, 5.6), "Expected: 0"); } // Tests ASSERT_NE. TEST(AssertionTest, ASSERT_NE) { ASSERT_NE(6, 7); EXPECT_FATAL_FAILURE(ASSERT_NE('a', 'a'), "Expected: ('a') != ('a'), " "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); } // Tests ASSERT_LE. TEST(AssertionTest, ASSERT_LE) { ASSERT_LE(2, 3); ASSERT_LE(2, 2); EXPECT_FATAL_FAILURE(ASSERT_LE(2, 0), "Expected: (2) <= (0), actual: 2 vs 0"); } // Tests ASSERT_LT. TEST(AssertionTest, ASSERT_LT) { ASSERT_LT(2, 3); EXPECT_FATAL_FAILURE(ASSERT_LT(2, 2), "Expected: (2) < (2), actual: 2 vs 2"); } // Tests ASSERT_GE. TEST(AssertionTest, ASSERT_GE) { ASSERT_GE(2, 1); ASSERT_GE(2, 2); EXPECT_FATAL_FAILURE(ASSERT_GE(2, 3), "Expected: (2) >= (3), actual: 2 vs 3"); } // Tests ASSERT_GT. TEST(AssertionTest, ASSERT_GT) { ASSERT_GT(2, 1); EXPECT_FATAL_FAILURE(ASSERT_GT(2, 2), "Expected: (2) > (2), actual: 2 vs 2"); } #if GTEST_HAS_EXCEPTIONS void ThrowNothing() {} // Tests ASSERT_THROW. TEST(AssertionTest, ASSERT_THROW) { ASSERT_THROW(ThrowAnInteger(), int); #ifndef __BORLANDC__ // ICE's in C++Builder 2007 and 2009. EXPECT_FATAL_FAILURE( ASSERT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of type bool.\n" " Actual: it throws a different type."); #endif EXPECT_FATAL_FAILURE( ASSERT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" " Actual: it throws nothing."); } // Tests ASSERT_NO_THROW. TEST(AssertionTest, ASSERT_NO_THROW) { ASSERT_NO_THROW(ThrowNothing()); EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()), "Expected: ThrowAnInteger() doesn't throw an exception." "\n Actual: it throws."); } // Tests ASSERT_ANY_THROW. TEST(AssertionTest, ASSERT_ANY_THROW) { ASSERT_ANY_THROW(ThrowAnInteger()); EXPECT_FATAL_FAILURE( ASSERT_ANY_THROW(ThrowNothing()), "Expected: ThrowNothing() throws an exception.\n" " Actual: it doesn't."); } #endif // GTEST_HAS_EXCEPTIONS // Makes sure we deal with the precedence of <<. This test should // compile. TEST(AssertionTest, AssertPrecedence) { ASSERT_EQ(1 < 2, true); ASSERT_EQ(true && false, false); } // A subroutine used by the following test. void TestEq1(int x) { ASSERT_EQ(1, x); } // Tests calling a test subroutine that's not part of a fixture. TEST(AssertionTest, NonFixtureSubroutine) { EXPECT_FATAL_FAILURE(TestEq1(2), "Value of: x"); } // An uncopyable class. class Uncopyable { public: explicit Uncopyable(int a_value) : value_(a_value) {} int value() const { return value_; } bool operator==(const Uncopyable& rhs) const { return value() == rhs.value(); } private: // This constructor deliberately has no implementation, as we don't // want this class to be copyable. Uncopyable(const Uncopyable&); // NOLINT int value_; }; ::std::ostream& operator<<(::std::ostream& os, const Uncopyable& value) { return os << value.value(); } bool IsPositiveUncopyable(const Uncopyable& x) { return x.value() > 0; } // A subroutine used by the following test. void TestAssertNonPositive() { Uncopyable y(-1); ASSERT_PRED1(IsPositiveUncopyable, y); } // A subroutine used by the following test. void TestAssertEqualsUncopyable() { Uncopyable x(5); Uncopyable y(-1); ASSERT_EQ(x, y); } // Tests that uncopyable objects can be used in assertions. TEST(AssertionTest, AssertWorksWithUncopyableObject) { Uncopyable x(5); ASSERT_PRED1(IsPositiveUncopyable, x); ASSERT_EQ(x, x); EXPECT_FATAL_FAILURE(TestAssertNonPositive(), "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); EXPECT_FATAL_FAILURE(TestAssertEqualsUncopyable(), "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5"); } // Tests that uncopyable objects can be used in expects. TEST(AssertionTest, ExpectWorksWithUncopyableObject) { Uncopyable x(5); EXPECT_PRED1(IsPositiveUncopyable, x); Uncopyable y(-1); EXPECT_NONFATAL_FAILURE(EXPECT_PRED1(IsPositiveUncopyable, y), "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); EXPECT_EQ(x, x); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5"); } // The version of gcc used in XCode 2.2 has a bug and doesn't allow // anonymous enums in assertions. Therefore the following test is not // done on Mac. // Sun Studio also rejects this code. #if !GTEST_OS_MAC && !defined(__SUNPRO_CC) // Tests using assertions with anonymous enums. enum { CASE_A = -1, #if GTEST_OS_LINUX // We want to test the case where the size of the anonymous enum is // larger than sizeof(int), to make sure our implementation of the // assertions doesn't truncate the enums. However, MSVC // (incorrectly) doesn't allow an enum value to exceed the range of // an int, so this has to be conditionally compiled. // // On Linux, CASE_B and CASE_A have the same value when truncated to // int size. We want to test whether this will confuse the // assertions. CASE_B = testing::internal::kMaxBiggestInt, #else CASE_B = INT_MAX, #endif // GTEST_OS_LINUX }; TEST(AssertionTest, AnonymousEnum) { #if GTEST_OS_LINUX EXPECT_EQ(static_cast(CASE_A), static_cast(CASE_B)); #endif // GTEST_OS_LINUX EXPECT_EQ(CASE_A, CASE_A); EXPECT_NE(CASE_A, CASE_B); EXPECT_LT(CASE_A, CASE_B); EXPECT_LE(CASE_A, CASE_B); EXPECT_GT(CASE_B, CASE_A); EXPECT_GE(CASE_A, CASE_A); EXPECT_NONFATAL_FAILURE(EXPECT_GE(CASE_A, CASE_B), "(CASE_A) >= (CASE_B)"); ASSERT_EQ(CASE_A, CASE_A); ASSERT_NE(CASE_A, CASE_B); ASSERT_LT(CASE_A, CASE_B); ASSERT_LE(CASE_A, CASE_B); ASSERT_GT(CASE_B, CASE_A); ASSERT_GE(CASE_A, CASE_A); EXPECT_FATAL_FAILURE(ASSERT_EQ(CASE_A, CASE_B), "Value of: CASE_B"); } #endif // !GTEST_OS_MAC && !defined(__SUNPRO_CC) #if GTEST_OS_WINDOWS static HRESULT UnexpectedHRESULTFailure() { return E_UNEXPECTED; } static HRESULT OkHRESULTSuccess() { return S_OK; } static HRESULT FalseHRESULTSuccess() { return S_FALSE; } // HRESULT assertion tests test both zero and non-zero // success codes as well as failure message for each. // // Windows CE doesn't support message texts. TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED) { EXPECT_HRESULT_SUCCEEDED(S_OK); EXPECT_HRESULT_SUCCEEDED(S_FALSE); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" " Actual: 0x8000FFFF"); } TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED) { ASSERT_HRESULT_SUCCEEDED(S_OK); ASSERT_HRESULT_SUCCEEDED(S_FALSE); EXPECT_FATAL_FAILURE(ASSERT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" " Actual: 0x8000FFFF"); } TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED) { EXPECT_HRESULT_FAILED(E_UNEXPECTED); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(OkHRESULTSuccess()), "Expected: (OkHRESULTSuccess()) fails.\n" " Actual: 0x00000000"); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()), "Expected: (FalseHRESULTSuccess()) fails.\n" " Actual: 0x00000001"); } TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED) { ASSERT_HRESULT_FAILED(E_UNEXPECTED); #ifndef __BORLANDC__ // ICE's in C++Builder 2007 and 2009. EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(OkHRESULTSuccess()), "Expected: (OkHRESULTSuccess()) fails.\n" " Actual: 0x00000000"); #endif EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()), "Expected: (FalseHRESULTSuccess()) fails.\n" " Actual: 0x00000001"); } // Tests that streaming to the HRESULT macros works. TEST(HRESULTAssertionTest, Streaming) { EXPECT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; ASSERT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; EXPECT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; ASSERT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; EXPECT_NONFATAL_FAILURE( EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", "expected failure"); #ifndef __BORLANDC__ // ICE's in C++Builder 2007 and 2009. EXPECT_FATAL_FAILURE( ASSERT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", "expected failure"); #endif EXPECT_NONFATAL_FAILURE( EXPECT_HRESULT_FAILED(S_OK) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE( ASSERT_HRESULT_FAILED(S_OK) << "expected failure", "expected failure"); } #endif // GTEST_OS_WINDOWS #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" #pragma option push -w-ccc -w-rch #endif // Tests that the assertion macros behave like single statements. TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) ASSERT_TRUE(false) << "This should never be executed; " "It's a compilation test only."; if (AlwaysTrue()) EXPECT_FALSE(false); else ; // NOLINT if (AlwaysFalse()) ASSERT_LT(1, 3); if (AlwaysFalse()) ; // NOLINT else EXPECT_GT(3, 2) << ""; } #if GTEST_HAS_EXCEPTIONS // Tests that the compiler will not complain about unreachable code in the // EXPECT_THROW/EXPECT_ANY_THROW/EXPECT_NO_THROW macros. TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { int n = 0; EXPECT_THROW(throw 1, int); EXPECT_NONFATAL_FAILURE(EXPECT_THROW(n++, int), ""); EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw 1, const char*), ""); EXPECT_NO_THROW(n++); EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(throw 1), ""); EXPECT_ANY_THROW(throw 1); EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), ""); } TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_THROW(ThrowNothing(), bool); if (AlwaysTrue()) EXPECT_THROW(ThrowAnInteger(), int); else ; // NOLINT if (AlwaysFalse()) EXPECT_NO_THROW(ThrowAnInteger()); if (AlwaysTrue()) EXPECT_NO_THROW(ThrowNothing()); else ; // NOLINT if (AlwaysFalse()) EXPECT_ANY_THROW(ThrowNothing()); if (AlwaysTrue()) EXPECT_ANY_THROW(ThrowAnInteger()); else ; // NOLINT } #endif // GTEST_HAS_EXCEPTIONS TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. " << "It's a compilation test only."; else ; // NOLINT if (AlwaysFalse()) ASSERT_NO_FATAL_FAILURE(FAIL()) << ""; else ; // NOLINT if (AlwaysTrue()) EXPECT_NO_FATAL_FAILURE(SUCCEED()); else ; // NOLINT if (AlwaysFalse()) ; // NOLINT else ASSERT_NO_FATAL_FAILURE(SUCCEED()); } // Tests that the assertion macros work well with switch statements. TEST(AssertionSyntaxTest, WorksWithSwitch) { switch (0) { case 1: break; default: ASSERT_TRUE(true); } switch (0) case 0: EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case"; // Binary assertions are implemented using a different code path // than the Boolean assertions. Hence we test them separately. switch (0) { case 1: default: ASSERT_EQ(1, 1) << "ASSERT_EQ failed in default switch handler"; } switch (0) case 0: EXPECT_NE(1, 2); } #if GTEST_HAS_EXCEPTIONS void ThrowAString() { throw "String"; } // Test that the exception assertion macros compile and work with const // type qualifier. TEST(AssertionSyntaxTest, WorksWithConst) { ASSERT_THROW(ThrowAString(), const char*); EXPECT_THROW(ThrowAString(), const char*); } #endif // GTEST_HAS_EXCEPTIONS } // namespace namespace testing { // Tests that Google Test tracks SUCCEED*. TEST(SuccessfulAssertionTest, SUCCEED) { SUCCEED(); SUCCEED() << "OK"; EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful EXPECT_*. TEST(SuccessfulAssertionTest, EXPECT) { EXPECT_TRUE(true); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful EXPECT_STR*. TEST(SuccessfulAssertionTest, EXPECT_STR) { EXPECT_STREQ("", ""); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful ASSERT_*. TEST(SuccessfulAssertionTest, ASSERT) { ASSERT_TRUE(true); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful ASSERT_STR*. TEST(SuccessfulAssertionTest, ASSERT_STR) { ASSERT_STREQ("", ""); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } } // namespace testing namespace { // Tests EXPECT_TRUE. TEST(ExpectTest, EXPECT_TRUE) { EXPECT_TRUE(2 > 1); // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 < 1), "Value of: 2 < 1\n" " Actual: false\n" "Expected: true"); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 > 3), "2 > 3"); } // Tests EXPECT_TRUE(predicate) for predicates returning AssertionResult. TEST(ExpectTest, ExpectTrueWithAssertionResult) { EXPECT_TRUE(ResultIsEven(2)); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEven(3)), "Value of: ResultIsEven(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); EXPECT_TRUE(ResultIsEvenNoExplanation(2)); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEvenNoExplanation(3)), "Value of: ResultIsEvenNoExplanation(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); } // Tests EXPECT_FALSE. TEST(ExpectTest, EXPECT_FALSE) { EXPECT_FALSE(2 < 1); // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 > 1), "Value of: 2 > 1\n" " Actual: true\n" "Expected: false"); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 < 3), "2 < 3"); } // Tests EXPECT_FALSE(predicate) for predicates returning AssertionResult. TEST(ExpectTest, ExpectFalseWithAssertionResult) { EXPECT_FALSE(ResultIsEven(3)); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEven(2)), "Value of: ResultIsEven(2)\n" " Actual: true (2 is even)\n" "Expected: false"); EXPECT_FALSE(ResultIsEvenNoExplanation(3)); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEvenNoExplanation(2)), "Value of: ResultIsEvenNoExplanation(2)\n" " Actual: true\n" "Expected: false"); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" supressed them #pragma option pop #endif // Tests EXPECT_EQ. TEST(ExpectTest, EXPECT_EQ) { EXPECT_EQ(5, 2 + 3); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2*3), "Value of: 2*3\n" " Actual: 6\n" "Expected: 5"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2 - 3), "2 - 3"); } // Tests using EXPECT_EQ on double values. The purpose is to make // sure that the specialization we did for integer and anonymous enums // isn't used for double arguments. TEST(ExpectTest, EXPECT_EQ_Double) { // A success. EXPECT_EQ(5.6, 5.6); // A failure. EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5.1, 5.2), "5.1"); } #if GTEST_CAN_COMPARE_NULL // Tests EXPECT_EQ(NULL, pointer). TEST(ExpectTest, EXPECT_EQ_NULL) { // A success. const char* p = NULL; // Some older GCC versions may issue a spurious waring in this or the next // assertion statement. This warning should not be suppressed with // static_cast since the test verifies the ability to use bare NULL as the // expected parameter to the macro. EXPECT_EQ(NULL, p); // A failure. int n = 0; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(NULL, &n), "Value of: &n\n"); } #endif // GTEST_CAN_COMPARE_NULL // Tests EXPECT_EQ(0, non_pointer). Since the literal 0 can be // treated as a null pointer by the compiler, we need to make sure // that EXPECT_EQ(0, non_pointer) isn't interpreted by Google Test as // EXPECT_EQ(static_cast(NULL), non_pointer). TEST(ExpectTest, EXPECT_EQ_0) { int n = 0; // A success. EXPECT_EQ(0, n); // A failure. EXPECT_NONFATAL_FAILURE(EXPECT_EQ(0, 5.6), "Expected: 0"); } // Tests EXPECT_NE. TEST(ExpectTest, EXPECT_NE) { EXPECT_NE(6, 7); EXPECT_NONFATAL_FAILURE(EXPECT_NE('a', 'a'), "Expected: ('a') != ('a'), " "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); EXPECT_NONFATAL_FAILURE(EXPECT_NE(2, 2), "2"); char* const p0 = NULL; EXPECT_NONFATAL_FAILURE(EXPECT_NE(p0, p0), "p0"); // Only way to get the Nokia compiler to compile the cast // is to have a separate void* variable first. Putting // the two casts on the same line doesn't work, neither does // a direct C-style to char*. void* pv1 = (void*)0x1234; // NOLINT char* const p1 = reinterpret_cast(pv1); EXPECT_NONFATAL_FAILURE(EXPECT_NE(p1, p1), "p1"); } // Tests EXPECT_LE. TEST(ExpectTest, EXPECT_LE) { EXPECT_LE(2, 3); EXPECT_LE(2, 2); EXPECT_NONFATAL_FAILURE(EXPECT_LE(2, 0), "Expected: (2) <= (0), actual: 2 vs 0"); EXPECT_NONFATAL_FAILURE(EXPECT_LE(1.1, 0.9), "(1.1) <= (0.9)"); } // Tests EXPECT_LT. TEST(ExpectTest, EXPECT_LT) { EXPECT_LT(2, 3); EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 2), "Expected: (2) < (2), actual: 2 vs 2"); EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1), "(2) < (1)"); } // Tests EXPECT_GE. TEST(ExpectTest, EXPECT_GE) { EXPECT_GE(2, 1); EXPECT_GE(2, 2); EXPECT_NONFATAL_FAILURE(EXPECT_GE(2, 3), "Expected: (2) >= (3), actual: 2 vs 3"); EXPECT_NONFATAL_FAILURE(EXPECT_GE(0.9, 1.1), "(0.9) >= (1.1)"); } // Tests EXPECT_GT. TEST(ExpectTest, EXPECT_GT) { EXPECT_GT(2, 1); EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 2), "Expected: (2) > (2), actual: 2 vs 2"); EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 3), "(2) > (3)"); } #if GTEST_HAS_EXCEPTIONS // Tests EXPECT_THROW. TEST(ExpectTest, EXPECT_THROW) { EXPECT_THROW(ThrowAnInteger(), int); EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of " "type bool.\n Actual: it throws a different type."); EXPECT_NONFATAL_FAILURE( EXPECT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" " Actual: it throws nothing."); } // Tests EXPECT_NO_THROW. TEST(ExpectTest, EXPECT_NO_THROW) { EXPECT_NO_THROW(ThrowNothing()); EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()), "Expected: ThrowAnInteger() doesn't throw an " "exception.\n Actual: it throws."); } // Tests EXPECT_ANY_THROW. TEST(ExpectTest, EXPECT_ANY_THROW) { EXPECT_ANY_THROW(ThrowAnInteger()); EXPECT_NONFATAL_FAILURE( EXPECT_ANY_THROW(ThrowNothing()), "Expected: ThrowNothing() throws an exception.\n" " Actual: it doesn't."); } #endif // GTEST_HAS_EXCEPTIONS // Make sure we deal with the precedence of <<. TEST(ExpectTest, ExpectPrecedence) { EXPECT_EQ(1 < 2, true); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(true, true && false), "Value of: true && false"); } // Tests the StreamableToString() function. // Tests using StreamableToString() on a scalar. TEST(StreamableToStringTest, Scalar) { EXPECT_STREQ("5", StreamableToString(5).c_str()); } // Tests using StreamableToString() on a non-char pointer. TEST(StreamableToStringTest, Pointer) { int n = 0; int* p = &n; EXPECT_STRNE("(null)", StreamableToString(p).c_str()); } // Tests using StreamableToString() on a NULL non-char pointer. TEST(StreamableToStringTest, NullPointer) { int* p = NULL; EXPECT_STREQ("(null)", StreamableToString(p).c_str()); } // Tests using StreamableToString() on a C string. TEST(StreamableToStringTest, CString) { EXPECT_STREQ("Foo", StreamableToString("Foo").c_str()); } // Tests using StreamableToString() on a NULL C string. TEST(StreamableToStringTest, NullCString) { char* p = NULL; EXPECT_STREQ("(null)", StreamableToString(p).c_str()); } // Tests using streamable values as assertion messages. // Tests using std::string as an assertion message. TEST(StreamableTest, string) { static const std::string str( "This failure message is a std::string, and is expected."); EXPECT_FATAL_FAILURE(FAIL() << str, str.c_str()); } // Tests that we can output strings containing embedded NULs. // Limited to Linux because we can only do this with std::string's. TEST(StreamableTest, stringWithEmbeddedNUL) { static const char char_array_with_nul[] = "Here's a NUL\0 and some more string"; static const std::string string_with_nul(char_array_with_nul, sizeof(char_array_with_nul) - 1); // drops the trailing NUL EXPECT_FATAL_FAILURE(FAIL() << string_with_nul, "Here's a NUL\\0 and some more string"); } // Tests that we can output a NUL char. TEST(StreamableTest, NULChar) { EXPECT_FATAL_FAILURE({ // NOLINT FAIL() << "A NUL" << '\0' << " and some more string"; }, "A NUL\\0 and some more string"); } // Tests using int as an assertion message. TEST(StreamableTest, int) { EXPECT_FATAL_FAILURE(FAIL() << 900913, "900913"); } // Tests using NULL char pointer as an assertion message. // // In MSVC, streaming a NULL char * causes access violation. Google Test // implemented a workaround (substituting "(null)" for NULL). This // tests whether the workaround works. TEST(StreamableTest, NullCharPtr) { EXPECT_FATAL_FAILURE(FAIL() << static_cast(NULL), "(null)"); } // Tests that basic IO manipulators (endl, ends, and flush) can be // streamed to testing::Message. TEST(StreamableTest, BasicIoManip) { EXPECT_FATAL_FAILURE({ // NOLINT FAIL() << "Line 1." << std::endl << "A NUL char " << std::ends << std::flush << " in line 2."; }, "Line 1.\nA NUL char \\0 in line 2."); } // Tests the macros that haven't been covered so far. void AddFailureHelper(bool* aborted) { *aborted = true; ADD_FAILURE() << "Failure"; *aborted = false; } // Tests ADD_FAILURE. TEST(MacroTest, ADD_FAILURE) { bool aborted = true; EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted), "Failure"); EXPECT_FALSE(aborted); } // Tests FAIL. TEST(MacroTest, FAIL) { EXPECT_FATAL_FAILURE(FAIL(), "Failed"); EXPECT_FATAL_FAILURE(FAIL() << "Intentional failure.", "Intentional failure."); } // Tests SUCCEED TEST(MacroTest, SUCCEED) { SUCCEED(); SUCCEED() << "Explicit success."; } // Tests for EXPECT_EQ() and ASSERT_EQ(). // // These tests fail *intentionally*, s.t. the failure messages can be // generated and tested. // // We have different tests for different argument types. // Tests using bool values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Bool) { EXPECT_EQ(true, true); EXPECT_FATAL_FAILURE(ASSERT_EQ(false, true), "Value of: true"); } // Tests using int values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Int) { ASSERT_EQ(32, 32); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(32, 33), "33"); } // Tests using time_t values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Time_T) { EXPECT_EQ(static_cast(0), static_cast(0)); EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0), static_cast(1234)), "1234"); } // Tests using char values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Char) { ASSERT_EQ('z', 'z'); const char ch = 'b'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ('\0', ch), "ch"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ('a', ch), "ch"); } // Tests using wchar_t values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, WideChar) { EXPECT_EQ(L'b', L'b'); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'\0', L'x'), "Value of: L'x'\n" " Actual: L'x' (120, 0x78)\n" "Expected: L'\0'\n" "Which is: L'\0' (0, 0x0)"); static wchar_t wchar; wchar = L'b'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar), "wchar"); wchar = L'\x8119'; EXPECT_FATAL_FAILURE(ASSERT_EQ(L'\x8120', wchar), "Value of: wchar"); } // Tests using ::std::string values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, StdString) { // Compares a const char* to an std::string that has identical // content. ASSERT_EQ("Test", ::std::string("Test")); // Compares two identical std::strings. static const ::std::string str1("A * in the middle"); static const ::std::string str2(str1); EXPECT_EQ(str1, str2); // Compares a const char* to an std::string that has different // content EXPECT_NONFATAL_FAILURE(EXPECT_EQ("Test", ::std::string("test")), "::std::string(\"test\")"); // Compares an std::string to a char* that has different content. char* const p1 = const_cast("foo"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::std::string("bar"), p1), "p1"); // Compares two std::strings that have different contents, one of // which having a NUL character in the middle. This should fail. static ::std::string str3(str1); str3.at(2) = '\0'; EXPECT_FATAL_FAILURE(ASSERT_EQ(str1, str3), "Value of: str3\n" " Actual: \"A \\0 in the middle\""); } #if GTEST_HAS_STD_WSTRING // Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, StdWideString) { // Compares an std::wstring to a const wchar_t* that has identical // content. EXPECT_EQ(::std::wstring(L"Test\x8119"), L"Test\x8119"); // Compares two identical std::wstrings. const ::std::wstring wstr1(L"A * in the middle"); const ::std::wstring wstr2(wstr1); ASSERT_EQ(wstr1, wstr2); // Compares an std::wstring to a const wchar_t* that has different // content. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EQ(::std::wstring(L"Test\x8119"), L"Test\x8120"); }, "L\"Test\\x8120\""); // Compares two std::wstrings that have different contents, one of // which having a NUL character in the middle. ::std::wstring wstr3(wstr1); wstr3.at(2) = L'\0'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(wstr1, wstr3), "wstr3"); // Compares a wchar_t* to an std::wstring that has different // content. EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EQ(const_cast(L"foo"), ::std::wstring(L"bar")); }, ""); } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_STRING // Tests using ::string values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, GlobalString) { // Compares a const char* to a ::string that has identical content. EXPECT_EQ("Test", ::string("Test")); // Compares two identical ::strings. const ::string str1("A * in the middle"); const ::string str2(str1); ASSERT_EQ(str1, str2); // Compares a ::string to a const char* that has different content. EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::string("Test"), "test"), "test"); // Compares two ::strings that have different contents, one of which // having a NUL character in the middle. ::string str3(str1); str3.at(2) = '\0'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(str1, str3), "str3"); // Compares a ::string to a char* that has different content. EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EQ(::string("bar"), const_cast("foo")); }, ""); } #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING // Tests using ::wstring values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, GlobalWideString) { // Compares a const wchar_t* to a ::wstring that has identical content. ASSERT_EQ(L"Test\x8119", ::wstring(L"Test\x8119")); // Compares two identical ::wstrings. static const ::wstring wstr1(L"A * in the middle"); static const ::wstring wstr2(wstr1); EXPECT_EQ(wstr1, wstr2); // Compares a const wchar_t* to a ::wstring that has different // content. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EQ(L"Test\x8120", ::wstring(L"Test\x8119")); }, "Test\\x8119"); // Compares a wchar_t* to a ::wstring that has different content. wchar_t* const p1 = const_cast(L"foo"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, ::wstring(L"bar")), "bar"); // Compares two ::wstrings that have different contents, one of which // having a NUL character in the middle. static ::wstring wstr3; wstr3 = wstr1; wstr3.at(2) = L'\0'; EXPECT_FATAL_FAILURE(ASSERT_EQ(wstr1, wstr3), "wstr3"); } #endif // GTEST_HAS_GLOBAL_WSTRING // Tests using char pointers in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, CharPointer) { char* const p0 = NULL; // Only way to get the Nokia compiler to compile the cast // is to have a separate void* variable first. Putting // the two casts on the same line doesn't work, neither does // a direct C-style to char*. void* pv1 = (void*)0x1234; // NOLINT void* pv2 = (void*)0xABC0; // NOLINT char* const p1 = reinterpret_cast(pv1); char* const p2 = reinterpret_cast(pv2); ASSERT_EQ(p1, p1); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), "Value of: p2"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), "p2"); EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast(0x1234), reinterpret_cast(0xABC0)), "ABC0"); } // Tests using wchar_t pointers in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, WideCharPointer) { wchar_t* const p0 = NULL; // Only way to get the Nokia compiler to compile the cast // is to have a separate void* variable first. Putting // the two casts on the same line doesn't work, neither does // a direct C-style to char*. void* pv1 = (void*)0x1234; // NOLINT void* pv2 = (void*)0xABC0; // NOLINT wchar_t* const p1 = reinterpret_cast(pv1); wchar_t* const p2 = reinterpret_cast(pv2); EXPECT_EQ(p0, p0); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), "Value of: p2"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), "p2"); void* pv3 = (void*)0x1234; // NOLINT void* pv4 = (void*)0xABC0; // NOLINT const wchar_t* p3 = reinterpret_cast(pv3); const wchar_t* p4 = reinterpret_cast(pv4); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p3, p4), "p4"); } // Tests using other types of pointers in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, OtherPointer) { ASSERT_EQ(static_cast(NULL), static_cast(NULL)); EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(NULL), reinterpret_cast(0x1234)), "0x1234"); } // Tests the FRIEND_TEST macro. // This class has a private member we want to test. We will test it // both in a TEST and in a TEST_F. class Foo { public: Foo() {} private: int Bar() const { return 1; } // Declares the friend tests that can access the private member // Bar(). FRIEND_TEST(FRIEND_TEST_Test, TEST); FRIEND_TEST(FRIEND_TEST_Test2, TEST_F); }; // Tests that the FRIEND_TEST declaration allows a TEST to access a // class's private members. This should compile. TEST(FRIEND_TEST_Test, TEST) { ASSERT_EQ(1, Foo().Bar()); } // The fixture needed to test using FRIEND_TEST with TEST_F. class FRIEND_TEST_Test2 : public Test { protected: Foo foo; }; // Tests that the FRIEND_TEST declaration allows a TEST_F to access a // class's private members. This should compile. TEST_F(FRIEND_TEST_Test2, TEST_F) { ASSERT_EQ(1, foo.Bar()); } // Tests the life cycle of Test objects. // The test fixture for testing the life cycle of Test objects. // // This class counts the number of live test objects that uses this // fixture. class TestLifeCycleTest : public Test { protected: // Constructor. Increments the number of test objects that uses // this fixture. TestLifeCycleTest() { count_++; } // Destructor. Decrements the number of test objects that uses this // fixture. ~TestLifeCycleTest() { count_--; } // Returns the number of live test objects that uses this fixture. int count() const { return count_; } private: static int count_; }; int TestLifeCycleTest::count_ = 0; // Tests the life cycle of test objects. TEST_F(TestLifeCycleTest, Test1) { // There should be only one test object in this test case that's // currently alive. ASSERT_EQ(1, count()); } // Tests the life cycle of test objects. TEST_F(TestLifeCycleTest, Test2) { // After Test1 is done and Test2 is started, there should still be // only one live test object, as the object for Test1 should've been // deleted. ASSERT_EQ(1, count()); } } // namespace // Tests that the copy constructor works when it is NOT optimized away by // the compiler. TEST(AssertionResultTest, CopyConstructorWorksWhenNotOptimied) { // Checks that the copy constructor doesn't try to dereference NULL pointers // in the source object. AssertionResult r1 = AssertionSuccess(); AssertionResult r2 = r1; // The following line is added to prevent the compiler from optimizing // away the constructor call. r1 << "abc"; AssertionResult r3 = r1; EXPECT_EQ(static_cast(r3), static_cast(r1)); EXPECT_STREQ("abc", r1.message()); } // Tests that AssertionSuccess and AssertionFailure construct // AssertionResult objects as expected. TEST(AssertionResultTest, ConstructionWorks) { AssertionResult r1 = AssertionSuccess(); EXPECT_TRUE(r1); EXPECT_STREQ("", r1.message()); AssertionResult r2 = AssertionSuccess() << "abc"; EXPECT_TRUE(r2); EXPECT_STREQ("abc", r2.message()); AssertionResult r3 = AssertionFailure(); EXPECT_FALSE(r3); EXPECT_STREQ("", r3.message()); AssertionResult r4 = AssertionFailure() << "def"; EXPECT_FALSE(r4); EXPECT_STREQ("def", r4.message()); AssertionResult r5 = AssertionFailure(Message() << "ghi"); EXPECT_FALSE(r5); EXPECT_STREQ("ghi", r5.message()); } // Tests that the negation fips the predicate result but keeps the message. TEST(AssertionResultTest, NegationWorks) { AssertionResult r1 = AssertionSuccess() << "abc"; EXPECT_FALSE(!r1); EXPECT_STREQ("abc", (!r1).message()); AssertionResult r2 = AssertionFailure() << "def"; EXPECT_TRUE(!r2); EXPECT_STREQ("def", (!r2).message()); } TEST(AssertionResultTest, StreamingWorks) { AssertionResult r = AssertionSuccess(); r << "abc" << 'd' << 0 << true; EXPECT_STREQ("abcd0true", r.message()); } // Tests streaming a user type whose definition and operator << are // both in the global namespace. class Base { public: explicit Base(int an_x) : x_(an_x) {} int x() const { return x_; } private: int x_; }; std::ostream& operator<<(std::ostream& os, const Base& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const Base* pointer) { return os << "(" << pointer->x() << ")"; } TEST(MessageTest, CanStreamUserTypeInGlobalNameSpace) { Message msg; Base a(1); msg << a << &a; // Uses ::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming a user type whose definition and operator<< are // both in an unnamed namespace. namespace { class MyTypeInUnnamedNameSpace : public Base { public: explicit MyTypeInUnnamedNameSpace(int an_x): Base(an_x) {} }; std::ostream& operator<<(std::ostream& os, const MyTypeInUnnamedNameSpace& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const MyTypeInUnnamedNameSpace* pointer) { return os << "(" << pointer->x() << ")"; } } // namespace TEST(MessageTest, CanStreamUserTypeInUnnamedNameSpace) { Message msg; MyTypeInUnnamedNameSpace a(1); msg << a << &a; // Uses ::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming a user type whose definition and operator<< are // both in a user namespace. namespace namespace1 { class MyTypeInNameSpace1 : public Base { public: explicit MyTypeInNameSpace1(int an_x): Base(an_x) {} }; std::ostream& operator<<(std::ostream& os, const MyTypeInNameSpace1& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const MyTypeInNameSpace1* pointer) { return os << "(" << pointer->x() << ")"; } } // namespace namespace1 TEST(MessageTest, CanStreamUserTypeInUserNameSpace) { Message msg; namespace1::MyTypeInNameSpace1 a(1); msg << a << &a; // Uses namespace1::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming a user type whose definition is in a user namespace // but whose operator<< is in the global namespace. namespace namespace2 { class MyTypeInNameSpace2 : public ::Base { public: explicit MyTypeInNameSpace2(int an_x): Base(an_x) {} }; } // namespace namespace2 std::ostream& operator<<(std::ostream& os, const namespace2::MyTypeInNameSpace2& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const namespace2::MyTypeInNameSpace2* pointer) { return os << "(" << pointer->x() << ")"; } TEST(MessageTest, CanStreamUserTypeInUserNameSpaceWithStreamOperatorInGlobal) { Message msg; namespace2::MyTypeInNameSpace2 a(1); msg << a << &a; // Uses ::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming NULL pointers to testing::Message. TEST(MessageTest, NullPointers) { Message msg; char* const p1 = NULL; unsigned char* const p2 = NULL; int* p3 = NULL; double* p4 = NULL; bool* p5 = NULL; Message* p6 = NULL; msg << p1 << p2 << p3 << p4 << p5 << p6; ASSERT_STREQ("(null)(null)(null)(null)(null)(null)", msg.GetString().c_str()); } // Tests streaming wide strings to testing::Message. TEST(MessageTest, WideStrings) { // Streams a NULL of type const wchar_t*. const wchar_t* const_wstr = NULL; EXPECT_STREQ("(null)", (Message() << const_wstr).GetString().c_str()); // Streams a NULL of type wchar_t*. wchar_t* wstr = NULL; EXPECT_STREQ("(null)", (Message() << wstr).GetString().c_str()); // Streams a non-NULL of type const wchar_t*. const_wstr = L"abc\x8119"; EXPECT_STREQ("abc\xe8\x84\x99", (Message() << const_wstr).GetString().c_str()); // Streams a non-NULL of type wchar_t*. wstr = const_cast(const_wstr); EXPECT_STREQ("abc\xe8\x84\x99", (Message() << wstr).GetString().c_str()); } // This line tests that we can define tests in the testing namespace. namespace testing { // Tests the TestInfo class. class TestInfoTest : public Test { protected: static const TestInfo* GetTestInfo(const char* test_name) { const TestCase* const test_case = GetUnitTestImpl()-> GetTestCase("TestInfoTest", "", NULL, NULL); for (int i = 0; i < test_case->total_test_count(); ++i) { const TestInfo* const test_info = test_case->GetTestInfo(i); if (strcmp(test_name, test_info->name()) == 0) return test_info; } return NULL; } static const TestResult* GetTestResult( const TestInfo* test_info) { return test_info->result(); } }; // Tests TestInfo::test_case_name() and TestInfo::name(). TEST_F(TestInfoTest, Names) { const TestInfo* const test_info = GetTestInfo("Names"); ASSERT_STREQ("TestInfoTest", test_info->test_case_name()); ASSERT_STREQ("Names", test_info->name()); } // Tests TestInfo::result(). TEST_F(TestInfoTest, result) { const TestInfo* const test_info = GetTestInfo("result"); // Initially, there is no TestPartResult for this test. ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); // After the previous assertion, there is still none. ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); } // Tests setting up and tearing down a test case. class SetUpTestCaseTest : public Test { protected: // This will be called once before the first test in this test case // is run. static void SetUpTestCase() { printf("Setting up the test case . . .\n"); // Initializes some shared resource. In this simple example, we // just create a C string. More complex stuff can be done if // desired. shared_resource_ = "123"; // Increments the number of test cases that have been set up. counter_++; // SetUpTestCase() should be called only once. EXPECT_EQ(1, counter_); } // This will be called once after the last test in this test case is // run. static void TearDownTestCase() { printf("Tearing down the test case . . .\n"); // Decrements the number of test cases that have been set up. counter_--; // TearDownTestCase() should be called only once. EXPECT_EQ(0, counter_); // Cleans up the shared resource. shared_resource_ = NULL; } // This will be called before each test in this test case. virtual void SetUp() { // SetUpTestCase() should be called only once, so counter_ should // always be 1. EXPECT_EQ(1, counter_); } // Number of test cases that have been set up. static int counter_; // Some resource to be shared by all tests in this test case. static const char* shared_resource_; }; int SetUpTestCaseTest::counter_ = 0; const char* SetUpTestCaseTest::shared_resource_ = NULL; // A test that uses the shared resource. TEST_F(SetUpTestCaseTest, Test1) { EXPECT_STRNE(NULL, shared_resource_); } // Another test that uses the shared resource. TEST_F(SetUpTestCaseTest, Test2) { EXPECT_STREQ("123", shared_resource_); } // The InitGoogleTestTest test case tests testing::InitGoogleTest(). // The Flags struct stores a copy of all Google Test flags. struct Flags { // Constructs a Flags struct where each flag has its default value. Flags() : also_run_disabled_tests(false), break_on_failure(false), catch_exceptions(false), death_test_use_fork(false), filter(""), list_tests(false), output(""), print_time(true), random_seed(0), repeat(1), shuffle(false), stack_trace_depth(kMaxStackTraceDepth), throw_on_failure(false) {} // Factory methods. // Creates a Flags struct where the gtest_also_run_disabled_tests flag has // the given value. static Flags AlsoRunDisabledTests(bool also_run_disabled_tests) { Flags flags; flags.also_run_disabled_tests = also_run_disabled_tests; return flags; } // Creates a Flags struct where the gtest_break_on_failure flag has // the given value. static Flags BreakOnFailure(bool break_on_failure) { Flags flags; flags.break_on_failure = break_on_failure; return flags; } // Creates a Flags struct where the gtest_catch_exceptions flag has // the given value. static Flags CatchExceptions(bool catch_exceptions) { Flags flags; flags.catch_exceptions = catch_exceptions; return flags; } // Creates a Flags struct where the gtest_death_test_use_fork flag has // the given value. static Flags DeathTestUseFork(bool death_test_use_fork) { Flags flags; flags.death_test_use_fork = death_test_use_fork; return flags; } // Creates a Flags struct where the gtest_filter flag has the given // value. static Flags Filter(const char* filter) { Flags flags; flags.filter = filter; return flags; } // Creates a Flags struct where the gtest_list_tests flag has the // given value. static Flags ListTests(bool list_tests) { Flags flags; flags.list_tests = list_tests; return flags; } // Creates a Flags struct where the gtest_output flag has the given // value. static Flags Output(const char* output) { Flags flags; flags.output = output; return flags; } // Creates a Flags struct where the gtest_print_time flag has the given // value. static Flags PrintTime(bool print_time) { Flags flags; flags.print_time = print_time; return flags; } // Creates a Flags struct where the gtest_random_seed flag has // the given value. static Flags RandomSeed(Int32 random_seed) { Flags flags; flags.random_seed = random_seed; return flags; } // Creates a Flags struct where the gtest_repeat flag has the given // value. static Flags Repeat(Int32 repeat) { Flags flags; flags.repeat = repeat; return flags; } // Creates a Flags struct where the gtest_shuffle flag has // the given value. static Flags Shuffle(bool shuffle) { Flags flags; flags.shuffle = shuffle; return flags; } // Creates a Flags struct where the GTEST_FLAG(stack_trace_depth) flag has // the given value. static Flags StackTraceDepth(Int32 stack_trace_depth) { Flags flags; flags.stack_trace_depth = stack_trace_depth; return flags; } // Creates a Flags struct where the gtest_throw_on_failure flag has // the given value. static Flags ThrowOnFailure(bool throw_on_failure) { Flags flags; flags.throw_on_failure = throw_on_failure; return flags; } // These fields store the flag values. bool also_run_disabled_tests; bool break_on_failure; bool catch_exceptions; bool death_test_use_fork; const char* filter; bool list_tests; const char* output; bool print_time; Int32 random_seed; Int32 repeat; bool shuffle; Int32 stack_trace_depth; bool throw_on_failure; }; // Fixture for testing InitGoogleTest(). class InitGoogleTestTest : public Test { protected: // Clears the flags before each test. virtual void SetUp() { GTEST_FLAG(also_run_disabled_tests) = false; GTEST_FLAG(break_on_failure) = false; GTEST_FLAG(catch_exceptions) = false; GTEST_FLAG(death_test_use_fork) = false; GTEST_FLAG(filter) = ""; GTEST_FLAG(list_tests) = false; GTEST_FLAG(output) = ""; GTEST_FLAG(print_time) = true; GTEST_FLAG(random_seed) = 0; GTEST_FLAG(repeat) = 1; GTEST_FLAG(shuffle) = false; GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; GTEST_FLAG(throw_on_failure) = false; } // Asserts that two narrow or wide string arrays are equal. template static void AssertStringArrayEq(size_t size1, CharType** array1, size_t size2, CharType** array2) { ASSERT_EQ(size1, size2) << " Array sizes different."; for (size_t i = 0; i != size1; i++) { ASSERT_STREQ(array1[i], array2[i]) << " where i == " << i; } } // Verifies that the flag values match the expected values. static void CheckFlags(const Flags& expected) { EXPECT_EQ(expected.also_run_disabled_tests, GTEST_FLAG(also_run_disabled_tests)); EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure)); EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions)); EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork)); EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str()); EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests)); EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str()); EXPECT_EQ(expected.print_time, GTEST_FLAG(print_time)); EXPECT_EQ(expected.random_seed, GTEST_FLAG(random_seed)); EXPECT_EQ(expected.repeat, GTEST_FLAG(repeat)); EXPECT_EQ(expected.shuffle, GTEST_FLAG(shuffle)); EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure)); EXPECT_EQ(expected.stack_trace_depth, GTEST_FLAG(stack_trace_depth)); } // Parses a command line (specified by argc1 and argv1), then // verifies that the flag values are expected and that the // recognized flags are removed from the command line. template static void TestParsingFlags(int argc1, const CharType** argv1, int argc2, const CharType** argv2, const Flags& expected, bool should_print_help) { const bool saved_help_flag = ::testing::internal::g_help_flag; ::testing::internal::g_help_flag = false; #if GTEST_HAS_STREAM_REDIRECTION_ CaptureStdout(); #endif // GTEST_HAS_STREAM_REDIRECTION_ // Parses the command line. internal::ParseGoogleTestFlagsOnly(&argc1, const_cast(argv1)); #if GTEST_HAS_STREAM_REDIRECTION_ const String captured_stdout = GetCapturedStdout(); #endif // GTEST_HAS_STREAM_REDIRECTION_ // Verifies the flag values. CheckFlags(expected); // Verifies that the recognized flags are removed from the command // line. AssertStringArrayEq(argc1 + 1, argv1, argc2 + 1, argv2); // ParseGoogleTestFlagsOnly should neither set g_help_flag nor print the // help message for the flags it recognizes. EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag); #if GTEST_HAS_STREAM_REDIRECTION_ const char* const expected_help_fragment = "This program contains tests written using"; if (should_print_help) { EXPECT_PRED_FORMAT2(IsSubstring, expected_help_fragment, captured_stdout); } else { EXPECT_PRED_FORMAT2(IsNotSubstring, expected_help_fragment, captured_stdout); } #endif // GTEST_HAS_STREAM_REDIRECTION_ ::testing::internal::g_help_flag = saved_help_flag; } // This macro wraps TestParsingFlags s.t. the user doesn't need // to specify the array sizes. #define GTEST_TEST_PARSING_FLAGS_(argv1, argv2, expected, should_print_help) \ TestParsingFlags(sizeof(argv1)/sizeof(*argv1) - 1, argv1, \ sizeof(argv2)/sizeof(*argv2) - 1, argv2, \ expected, should_print_help) }; // Tests parsing an empty command line. TEST_F(InitGoogleTestTest, Empty) { const char* argv[] = { NULL }; const char* argv2[] = { NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); } // Tests parsing a command line that has no flag. TEST_F(InitGoogleTestTest, NoFlag) { const char* argv[] = { "foo.exe", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); } // Tests parsing a bad --gtest_filter flag. TEST_F(InitGoogleTestTest, FilterBad) { const char* argv[] = { "foo.exe", "--gtest_filter", NULL }; const char* argv2[] = { "foo.exe", "--gtest_filter", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true); } // Tests parsing an empty --gtest_filter flag. TEST_F(InitGoogleTestTest, FilterEmpty) { const char* argv[] = { "foo.exe", "--gtest_filter=", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), false); } // Tests parsing a non-empty --gtest_filter flag. TEST_F(InitGoogleTestTest, FilterNonEmpty) { const char* argv[] = { "foo.exe", "--gtest_filter=abc", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false); } // Tests parsing --gtest_break_on_failure. TEST_F(InitGoogleTestTest, BreakOnFailureWithoutValue) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); } // Tests parsing --gtest_break_on_failure=0. TEST_F(InitGoogleTestTest, BreakOnFailureFalse_0) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); } // Tests parsing --gtest_break_on_failure=f. TEST_F(InitGoogleTestTest, BreakOnFailureFalse_f) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=f", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); } // Tests parsing --gtest_break_on_failure=F. TEST_F(InitGoogleTestTest, BreakOnFailureFalse_F) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=F", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); } // Tests parsing a --gtest_break_on_failure flag that has a "true" // definition. TEST_F(InitGoogleTestTest, BreakOnFailureTrue) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); } // Tests parsing --gtest_catch_exceptions. TEST_F(InitGoogleTestTest, CatchExceptions) { const char* argv[] = { "foo.exe", "--gtest_catch_exceptions", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::CatchExceptions(true), false); } // Tests parsing --gtest_death_test_use_fork. TEST_F(InitGoogleTestTest, DeathTestUseFork) { const char* argv[] = { "foo.exe", "--gtest_death_test_use_fork", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::DeathTestUseFork(true), false); } // Tests having the same flag twice with different values. The // expected behavior is that the one coming last takes precedence. TEST_F(InitGoogleTestTest, DuplicatedFlags) { const char* argv[] = { "foo.exe", "--gtest_filter=a", "--gtest_filter=b", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("b"), false); } // Tests having an unrecognized flag on the command line. TEST_F(InitGoogleTestTest, UnrecognizedFlag) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure", "bar", // Unrecognized by Google Test. "--gtest_filter=b", NULL }; const char* argv2[] = { "foo.exe", "bar", NULL }; Flags flags; flags.break_on_failure = true; flags.filter = "b"; GTEST_TEST_PARSING_FLAGS_(argv, argv2, flags, false); } // Tests having a --gtest_list_tests flag TEST_F(InitGoogleTestTest, ListTestsFlag) { const char* argv[] = { "foo.exe", "--gtest_list_tests", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); } // Tests having a --gtest_list_tests flag with a "true" value TEST_F(InitGoogleTestTest, ListTestsTrue) { const char* argv[] = { "foo.exe", "--gtest_list_tests=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); } // Tests having a --gtest_list_tests flag with a "false" value TEST_F(InitGoogleTestTest, ListTestsFalse) { const char* argv[] = { "foo.exe", "--gtest_list_tests=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } // Tests parsing --gtest_list_tests=f. TEST_F(InitGoogleTestTest, ListTestsFalse_f) { const char* argv[] = { "foo.exe", "--gtest_list_tests=f", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } // Tests parsing --gtest_list_tests=F. TEST_F(InitGoogleTestTest, ListTestsFalse_F) { const char* argv[] = { "foo.exe", "--gtest_list_tests=F", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } // Tests parsing --gtest_output (invalid). TEST_F(InitGoogleTestTest, OutputEmpty) { const char* argv[] = { "foo.exe", "--gtest_output", NULL }; const char* argv2[] = { "foo.exe", "--gtest_output", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true); } // Tests parsing --gtest_output=xml TEST_F(InitGoogleTestTest, OutputXml) { const char* argv[] = { "foo.exe", "--gtest_output=xml", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml"), false); } // Tests parsing --gtest_output=xml:file TEST_F(InitGoogleTestTest, OutputXmlFile) { const char* argv[] = { "foo.exe", "--gtest_output=xml:file", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:file"), false); } // Tests parsing --gtest_output=xml:directory/path/ TEST_F(InitGoogleTestTest, OutputXmlDirectory) { const char* argv[] = { "foo.exe", "--gtest_output=xml:directory/path/", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:directory/path/"), false); } // Tests having a --gtest_print_time flag TEST_F(InitGoogleTestTest, PrintTimeFlag) { const char* argv[] = { "foo.exe", "--gtest_print_time", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); } // Tests having a --gtest_print_time flag with a "true" value TEST_F(InitGoogleTestTest, PrintTimeTrue) { const char* argv[] = { "foo.exe", "--gtest_print_time=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); } // Tests having a --gtest_print_time flag with a "false" value TEST_F(InitGoogleTestTest, PrintTimeFalse) { const char* argv[] = { "foo.exe", "--gtest_print_time=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); } // Tests parsing --gtest_print_time=f. TEST_F(InitGoogleTestTest, PrintTimeFalse_f) { const char* argv[] = { "foo.exe", "--gtest_print_time=f", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); } // Tests parsing --gtest_print_time=F. TEST_F(InitGoogleTestTest, PrintTimeFalse_F) { const char* argv[] = { "foo.exe", "--gtest_print_time=F", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); } // Tests parsing --gtest_random_seed=number TEST_F(InitGoogleTestTest, RandomSeed) { const char* argv[] = { "foo.exe", "--gtest_random_seed=1000", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::RandomSeed(1000), false); } // Tests parsing --gtest_repeat=number TEST_F(InitGoogleTestTest, Repeat) { const char* argv[] = { "foo.exe", "--gtest_repeat=1000", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Repeat(1000), false); } // Tests having a --gtest_also_run_disabled_tests flag TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFlag) { const char* argv[] = { "foo.exe", "--gtest_also_run_disabled_tests", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(true), false); } // Tests having a --gtest_also_run_disabled_tests flag with a "true" value TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsTrue) { const char* argv[] = { "foo.exe", "--gtest_also_run_disabled_tests=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(true), false); } // Tests having a --gtest_also_run_disabled_tests flag with a "false" value TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFalse) { const char* argv[] = { "foo.exe", "--gtest_also_run_disabled_tests=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(false), false); } // Tests parsing --gtest_shuffle. TEST_F(InitGoogleTestTest, ShuffleWithoutValue) { const char* argv[] = { "foo.exe", "--gtest_shuffle", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); } // Tests parsing --gtest_shuffle=0. TEST_F(InitGoogleTestTest, ShuffleFalse_0) { const char* argv[] = { "foo.exe", "--gtest_shuffle=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(false), false); } // Tests parsing a --gtest_shuffle flag that has a "true" // definition. TEST_F(InitGoogleTestTest, ShuffleTrue) { const char* argv[] = { "foo.exe", "--gtest_shuffle=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); } // Tests parsing --gtest_stack_trace_depth=number. TEST_F(InitGoogleTestTest, StackTraceDepth) { const char* argv[] = { "foo.exe", "--gtest_stack_trace_depth=5", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::StackTraceDepth(5), false); } // Tests parsing --gtest_throw_on_failure. TEST_F(InitGoogleTestTest, ThrowOnFailureWithoutValue) { const char* argv[] = { "foo.exe", "--gtest_throw_on_failure", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); } // Tests parsing --gtest_throw_on_failure=0. TEST_F(InitGoogleTestTest, ThrowOnFailureFalse_0) { const char* argv[] = { "foo.exe", "--gtest_throw_on_failure=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(false), false); } // Tests parsing a --gtest_throw_on_failure flag that has a "true" // definition. TEST_F(InitGoogleTestTest, ThrowOnFailureTrue) { const char* argv[] = { "foo.exe", "--gtest_throw_on_failure=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); } #if GTEST_OS_WINDOWS // Tests parsing wide strings. TEST_F(InitGoogleTestTest, WideStrings) { const wchar_t* argv[] = { L"foo.exe", L"--gtest_filter=Foo*", L"--gtest_list_tests=1", L"--gtest_break_on_failure", L"--non_gtest_flag", NULL }; const wchar_t* argv2[] = { L"foo.exe", L"--non_gtest_flag", NULL }; Flags expected_flags; expected_flags.break_on_failure = true; expected_flags.filter = "Foo*"; expected_flags.list_tests = true; GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false); } #endif // GTEST_OS_WINDOWS // Tests current_test_info() in UnitTest. class CurrentTestInfoTest : public Test { protected: // Tests that current_test_info() returns NULL before the first test in // the test case is run. static void SetUpTestCase() { // There should be no tests running at this point. const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); EXPECT_TRUE(test_info == NULL) << "There should be no tests running at this point."; } // Tests that current_test_info() returns NULL after the last test in // the test case has run. static void TearDownTestCase() { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); EXPECT_TRUE(test_info == NULL) << "There should be no tests running at this point."; } }; // Tests that current_test_info() returns TestInfo for currently running // test by checking the expected test name against the actual one. TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestCase) { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(NULL != test_info) << "There is a test running so we should have a valid TestInfo."; EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) << "Expected the name of the currently running test case."; EXPECT_STREQ("WorksForFirstTestInATestCase", test_info->name()) << "Expected the name of the currently running test."; } // Tests that current_test_info() returns TestInfo for currently running // test by checking the expected test name against the actual one. We // use this test to see that the TestInfo object actually changed from // the previous invocation. TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestCase) { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(NULL != test_info) << "There is a test running so we should have a valid TestInfo."; EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) << "Expected the name of the currently running test case."; EXPECT_STREQ("WorksForSecondTestInATestCase", test_info->name()) << "Expected the name of the currently running test."; } } // namespace testing // These two lines test that we can define tests in a namespace that // has the name "testing" and is nested in another namespace. namespace my_namespace { namespace testing { // Makes sure that TEST knows to use ::testing::Test instead of // ::my_namespace::testing::Test. class Test {}; // Makes sure that an assertion knows to use ::testing::Message instead of // ::my_namespace::testing::Message. class Message {}; // Makes sure that an assertion knows to use // ::testing::AssertionResult instead of // ::my_namespace::testing::AssertionResult. class AssertionResult {}; // Tests that an assertion that should succeed works as expected. TEST(NestedTestingNamespaceTest, Success) { EXPECT_EQ(1, 1) << "This shouldn't fail."; } // Tests that an assertion that should fail works as expected. TEST(NestedTestingNamespaceTest, Failure) { EXPECT_FATAL_FAILURE(FAIL() << "This failure is expected.", "This failure is expected."); } } // namespace testing } // namespace my_namespace // Tests that one can call superclass SetUp and TearDown methods-- // that is, that they are not private. // No tests are based on this fixture; the test "passes" if it compiles // successfully. class ProtectedFixtureMethodsTest : public Test { protected: virtual void SetUp() { Test::SetUp(); } virtual void TearDown() { Test::TearDown(); } }; // StreamingAssertionsTest tests the streaming versions of a representative // sample of assertions. TEST(StreamingAssertionsTest, Unconditional) { SUCCEED() << "expected success"; EXPECT_NONFATAL_FAILURE(ADD_FAILURE() << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(FAIL() << "expected failure", "expected failure"); } #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" #pragma option push -w-ccc -w-rch #endif TEST(StreamingAssertionsTest, Truth) { EXPECT_TRUE(true) << "unexpected failure"; ASSERT_TRUE(true) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_TRUE(false) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, Truth2) { EXPECT_FALSE(false) << "unexpected failure"; ASSERT_FALSE(false) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_FALSE(true) << "expected failure", "expected failure"); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" supressed them #pragma option pop #endif TEST(StreamingAssertionsTest, IntegerEquals) { EXPECT_EQ(1, 1) << "unexpected failure"; ASSERT_EQ(1, 1) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(1, 2) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_EQ(1, 2) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, IntegerLessThan) { EXPECT_LT(1, 2) << "unexpected failure"; ASSERT_LT(1, 2) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_LT(2, 1) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringsEqual) { EXPECT_STREQ("foo", "foo") << "unexpected failure"; ASSERT_STREQ("foo", "foo") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STREQ("foo", "bar") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STREQ("foo", "bar") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringsNotEqual) { EXPECT_STRNE("foo", "bar") << "unexpected failure"; ASSERT_STRNE("foo", "bar") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("foo", "foo") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STRNE("foo", "foo") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringsEqualIgnoringCase) { EXPECT_STRCASEEQ("foo", "FOO") << "unexpected failure"; ASSERT_STRCASEEQ("foo", "FOO") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ("foo", "bar") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("foo", "bar") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringNotEqualIgnoringCase) { EXPECT_STRCASENE("foo", "bar") << "unexpected failure"; ASSERT_STRCASENE("foo", "bar") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("foo", "FOO") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("bar", "BAR") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, FloatingPointEquals) { EXPECT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; ASSERT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(0.0, 1.0) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.0) << "expected failure", "expected failure"); } #if GTEST_HAS_EXCEPTIONS TEST(StreamingAssertionsTest, Throw) { EXPECT_THROW(ThrowAnInteger(), int) << "unexpected failure"; ASSERT_THROW(ThrowAnInteger(), int) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_THROW(ThrowAnInteger(), bool) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, NoThrow) { EXPECT_NO_THROW(ThrowNothing()) << "unexpected failure"; ASSERT_NO_THROW(ThrowNothing()) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, AnyThrow) { EXPECT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; ASSERT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(ThrowNothing()) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_ANY_THROW(ThrowNothing()) << "expected failure", "expected failure"); } #endif // GTEST_HAS_EXCEPTIONS // Tests that Google Test correctly decides whether to use colors in the output. TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsYes) { GTEST_FLAG(color) = "yes"; SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. SetEnv("TERM", "dumb"); // TERM doesn't support colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. } TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsAliasOfYes) { SetEnv("TERM", "dumb"); // TERM doesn't support colors. GTEST_FLAG(color) = "True"; EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. GTEST_FLAG(color) = "t"; EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. GTEST_FLAG(color) = "1"; EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. } TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsNo) { GTEST_FLAG(color) = "no"; SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. SetEnv("TERM", "dumb"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. } TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsInvalid) { SetEnv("TERM", "xterm"); // TERM supports colors. GTEST_FLAG(color) = "F"; EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. GTEST_FLAG(color) = "0"; EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. GTEST_FLAG(color) = "unknown"; EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. } TEST(ColoredOutputTest, UsesColorsWhenStdoutIsTty) { GTEST_FLAG(color) = "auto"; SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. } TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) { GTEST_FLAG(color) = "auto"; #if GTEST_OS_WINDOWS // On Windows, we ignore the TERM variable as it's usually not set. SetEnv("TERM", "dumb"); EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", ""); EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm"); EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. #else // On non-Windows platforms, we rely on TERM to determine if the // terminal supports colors. SetEnv("TERM", "dumb"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "emacs"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "vt100"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm-mono"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm-color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "linux"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. #endif // GTEST_OS_WINDOWS } // Verifies that StaticAssertTypeEq works in a namespace scope. static bool dummy1 = StaticAssertTypeEq(); static bool dummy2 = StaticAssertTypeEq(); // Verifies that StaticAssertTypeEq works in a class. template class StaticAssertTypeEqTestHelper { public: StaticAssertTypeEqTestHelper() { StaticAssertTypeEq(); } }; TEST(StaticAssertTypeEqTest, WorksInClass) { StaticAssertTypeEqTestHelper(); } // Verifies that StaticAssertTypeEq works inside a function. typedef int IntAlias; TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { StaticAssertTypeEq(); StaticAssertTypeEq(); } TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) { testing::UnitTest* const unit_test = testing::UnitTest::GetInstance(); // We don't have a stack walker in Google Test yet. EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 0).c_str()); EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 1).c_str()); } TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure) { EXPECT_FALSE(HasNonfatalFailure()); } static void FailFatally() { FAIL(); } TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure) { FailFatally(); const bool has_nonfatal_failure = HasNonfatalFailure(); ClearCurrentTestPartResults(); EXPECT_FALSE(has_nonfatal_failure); } TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { ADD_FAILURE(); const bool has_nonfatal_failure = HasNonfatalFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_nonfatal_failure); } TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { FailFatally(); ADD_FAILURE(); const bool has_nonfatal_failure = HasNonfatalFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_nonfatal_failure); } // A wrapper for calling HasNonfatalFailure outside of a test body. static bool HasNonfatalFailureHelper() { return testing::Test::HasNonfatalFailure(); } TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody) { EXPECT_FALSE(HasNonfatalFailureHelper()); } TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2) { ADD_FAILURE(); const bool has_nonfatal_failure = HasNonfatalFailureHelper(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_nonfatal_failure); } TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure) { EXPECT_FALSE(HasFailure()); } TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure) { FailFatally(); const bool has_failure = HasFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { ADD_FAILURE(); const bool has_failure = HasFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { FailFatally(); ADD_FAILURE(); const bool has_failure = HasFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } // A wrapper for calling HasFailure outside of a test body. static bool HasFailureHelper() { return testing::Test::HasFailure(); } TEST(HasFailureTest, WorksOutsideOfTestBody) { EXPECT_FALSE(HasFailureHelper()); } TEST(HasFailureTest, WorksOutsideOfTestBody2) { ADD_FAILURE(); const bool has_failure = HasFailureHelper(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } class TestListener : public EmptyTestEventListener { public: TestListener() : on_start_counter_(NULL), is_destroyed_(NULL) {} TestListener(int* on_start_counter, bool* is_destroyed) : on_start_counter_(on_start_counter), is_destroyed_(is_destroyed) {} virtual ~TestListener() { if (is_destroyed_) *is_destroyed_ = true; } protected: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { if (on_start_counter_ != NULL) (*on_start_counter_)++; } private: int* on_start_counter_; bool* is_destroyed_; }; // Tests the constructor. TEST(TestEventListenersTest, ConstructionWorks) { TestEventListeners listeners; EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != NULL); EXPECT_TRUE(listeners.default_result_printer() == NULL); EXPECT_TRUE(listeners.default_xml_generator() == NULL); } // Tests that the TestEventListeners destructor deletes all the listeners it // owns. TEST(TestEventListenersTest, DestructionWorks) { bool default_result_printer_is_destroyed = false; bool default_xml_printer_is_destroyed = false; bool extra_listener_is_destroyed = false; TestListener* default_result_printer = new TestListener( NULL, &default_result_printer_is_destroyed); TestListener* default_xml_printer = new TestListener( NULL, &default_xml_printer_is_destroyed); TestListener* extra_listener = new TestListener( NULL, &extra_listener_is_destroyed); { TestEventListeners listeners; TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, default_result_printer); TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, default_xml_printer); listeners.Append(extra_listener); } EXPECT_TRUE(default_result_printer_is_destroyed); EXPECT_TRUE(default_xml_printer_is_destroyed); EXPECT_TRUE(extra_listener_is_destroyed); } // Tests that a listener Append'ed to a TestEventListeners list starts // receiving events. TEST(TestEventListenersTest, Append) { int on_start_counter = 0; bool is_destroyed = false; TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; listeners.Append(listener); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); } EXPECT_TRUE(is_destroyed); } // Tests that listeners receive events in the order they were appended to // the list, except for *End requests, which must be received in the reverse // order. class SequenceTestingListener : public EmptyTestEventListener { public: SequenceTestingListener(std::vector* vector, const char* id) : vector_(vector), id_(id) {} protected: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { vector_->push_back(GetEventDescription("OnTestProgramStart")); } virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { vector_->push_back(GetEventDescription("OnTestProgramEnd")); } virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) { vector_->push_back(GetEventDescription("OnTestIterationStart")); } virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) { vector_->push_back(GetEventDescription("OnTestIterationEnd")); } private: String GetEventDescription(const char* method) { Message message; message << id_ << "." << method; return message.GetString(); } std::vector* vector_; const char* const id_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener); }; TEST(EventListenerTest, AppendKeepsOrder) { std::vector vec; TestEventListeners listeners; listeners.Append(new SequenceTestingListener(&vec, "1st")); listeners.Append(new SequenceTestingListener(&vec, "2nd")); listeners.Append(new SequenceTestingListener(&vec, "3rd")); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("1st.OnTestProgramStart", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestProgramStart", vec[1].c_str()); EXPECT_STREQ("3rd.OnTestProgramStart", vec[2].c_str()); vec.clear(); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd( *UnitTest::GetInstance()); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("3rd.OnTestProgramEnd", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestProgramEnd", vec[1].c_str()); EXPECT_STREQ("1st.OnTestProgramEnd", vec[2].c_str()); vec.clear(); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart( *UnitTest::GetInstance(), 0); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("1st.OnTestIterationStart", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestIterationStart", vec[1].c_str()); EXPECT_STREQ("3rd.OnTestIterationStart", vec[2].c_str()); vec.clear(); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd( *UnitTest::GetInstance(), 0); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("3rd.OnTestIterationEnd", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestIterationEnd", vec[1].c_str()); EXPECT_STREQ("1st.OnTestIterationEnd", vec[2].c_str()); } // Tests that a listener removed from a TestEventListeners list stops receiving // events and is not deleted when the list is destroyed. TEST(TestEventListenersTest, Release) { int on_start_counter = 0; bool is_destroyed = false; // Although Append passes the ownership of this object to the list, // the following calls release it, and we need to delete it before the // test ends. TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; listeners.Append(listener); EXPECT_EQ(listener, listeners.Release(listener)); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_TRUE(listeners.Release(listener) == NULL); } EXPECT_EQ(0, on_start_counter); EXPECT_FALSE(is_destroyed); delete listener; } // Tests that no events are forwarded when event forwarding is disabled. TEST(EventListenerTest, SuppressEventForwarding) { int on_start_counter = 0; TestListener* listener = new TestListener(&on_start_counter, NULL); TestEventListeners listeners; listeners.Append(listener); ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); TestEventListenersAccessor::SuppressEventForwarding(&listeners); ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(0, on_start_counter); } // Tests that events generated by Google Test are not forwarded in // death test subprocesses. TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) { EXPECT_DEATH_IF_SUPPORTED({ GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled( *GetUnitTestImpl()->listeners())) << "expected failure";}, "expected failure"); } // Tests that a listener installed via SetDefaultResultPrinter() starts // receiving events and is returned via default_result_printer() and that // the previous default_result_printer is removed from the list and deleted. TEST(EventListenerTest, default_result_printer) { int on_start_counter = 0; bool is_destroyed = false; TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); TestEventListeners listeners; TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); EXPECT_EQ(listener, listeners.default_result_printer()); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); // Replacing default_result_printer with something else should remove it // from the list and destroy it. TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, NULL); EXPECT_TRUE(listeners.default_result_printer() == NULL); EXPECT_TRUE(is_destroyed); // After broadcasting an event the counter is still the same, indicating // the listener is not in the list anymore. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); } // Tests that the default_result_printer listener stops receiving events // when removed via Release and that is not owned by the list anymore. TEST(EventListenerTest, RemovingDefaultResultPrinterWorks) { int on_start_counter = 0; bool is_destroyed = false; // Although Append passes the ownership of this object to the list, // the following calls release it, and we need to delete it before the // test ends. TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); EXPECT_EQ(listener, listeners.Release(listener)); EXPECT_TRUE(listeners.default_result_printer() == NULL); EXPECT_FALSE(is_destroyed); // Broadcasting events now should not affect default_result_printer. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(0, on_start_counter); } // Destroying the list should not affect the listener now, too. EXPECT_FALSE(is_destroyed); delete listener; } // Tests that a listener installed via SetDefaultXmlGenerator() starts // receiving events and is returned via default_xml_generator() and that // the previous default_xml_generator is removed from the list and deleted. TEST(EventListenerTest, default_xml_generator) { int on_start_counter = 0; bool is_destroyed = false; TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); TestEventListeners listeners; TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); EXPECT_EQ(listener, listeners.default_xml_generator()); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); // Replacing default_xml_generator with something else should remove it // from the list and destroy it. TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, NULL); EXPECT_TRUE(listeners.default_xml_generator() == NULL); EXPECT_TRUE(is_destroyed); // After broadcasting an event the counter is still the same, indicating // the listener is not in the list anymore. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); } // Tests that the default_xml_generator listener stops receiving events // when removed via Release and that is not owned by the list anymore. TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) { int on_start_counter = 0; bool is_destroyed = false; // Although Append passes the ownership of this object to the list, // the following calls release it, and we need to delete it before the // test ends. TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); EXPECT_EQ(listener, listeners.Release(listener)); EXPECT_TRUE(listeners.default_xml_generator() == NULL); EXPECT_FALSE(is_destroyed); // Broadcasting events now should not affect default_xml_generator. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(0, on_start_counter); } // Destroying the list should not affect the listener now, too. EXPECT_FALSE(is_destroyed); delete listener; } // Sanity tests to ensure that the alternative, verbose spellings of // some of the macros work. We don't test them thoroughly as that // would be quite involved. Since their implementations are // straightforward, and they are rarely used, we'll just rely on the // users to tell us when they are broken. GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST. GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED. // GTEST_FAIL is the same as FAIL. EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure", "An expected failure"); } ceph-0.80.11/src/gtest/test/gtest_color_test.py0000775000175100017510000001145712623076744023541 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """Verifies that Google Test correctly determines whether to use colors.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils IS_WINDOWS = os.name = 'nt' COLOR_ENV_VAR = 'GTEST_COLOR' COLOR_FLAG = 'gtest_color' COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_color_test_') def SetEnvVar(env_var, value): """Sets the env variable to 'value'; unsets it when 'value' is None.""" if value is not None: os.environ[env_var] = value elif env_var in os.environ: del os.environ[env_var] def UsesColor(term, color_env_var, color_flag): """Runs gtest_color_test_ and returns its exit code.""" SetEnvVar('TERM', term) SetEnvVar(COLOR_ENV_VAR, color_env_var) if color_flag is None: args = [] else: args = ['--%s=%s' % (COLOR_FLAG, color_flag)] p = gtest_test_utils.Subprocess([COMMAND] + args) return not p.exited or p.exit_code class GTestColorTest(gtest_test_utils.TestCase): def testNoEnvVarNoFlag(self): """Tests the case when there's neither GTEST_COLOR nor --gtest_color.""" if not IS_WINDOWS: self.assert_(not UsesColor('dumb', None, None)) self.assert_(not UsesColor('emacs', None, None)) self.assert_(not UsesColor('xterm-mono', None, None)) self.assert_(not UsesColor('unknown', None, None)) self.assert_(not UsesColor(None, None, None)) self.assert_(UsesColor('linux', None, None)) self.assert_(UsesColor('cygwin', None, None)) self.assert_(UsesColor('xterm', None, None)) self.assert_(UsesColor('xterm-color', None, None)) self.assert_(UsesColor('xterm-256color', None, None)) def testFlagOnly(self): """Tests the case when there's --gtest_color but not GTEST_COLOR.""" self.assert_(not UsesColor('dumb', None, 'no')) self.assert_(not UsesColor('xterm-color', None, 'no')) if not IS_WINDOWS: self.assert_(not UsesColor('emacs', None, 'auto')) self.assert_(UsesColor('xterm', None, 'auto')) self.assert_(UsesColor('dumb', None, 'yes')) self.assert_(UsesColor('xterm', None, 'yes')) def testEnvVarOnly(self): """Tests the case when there's GTEST_COLOR but not --gtest_color.""" self.assert_(not UsesColor('dumb', 'no', None)) self.assert_(not UsesColor('xterm-color', 'no', None)) if not IS_WINDOWS: self.assert_(not UsesColor('dumb', 'auto', None)) self.assert_(UsesColor('xterm-color', 'auto', None)) self.assert_(UsesColor('dumb', 'yes', None)) self.assert_(UsesColor('xterm-color', 'yes', None)) def testEnvVarAndFlag(self): """Tests the case when there are both GTEST_COLOR and --gtest_color.""" self.assert_(not UsesColor('xterm-color', 'no', 'no')) self.assert_(UsesColor('dumb', 'no', 'yes')) self.assert_(UsesColor('xterm-color', 'no', 'auto')) def testAliasesOfYesAndNo(self): """Tests using aliases in specifying --gtest_color.""" self.assert_(UsesColor('dumb', None, 'true')) self.assert_(UsesColor('dumb', None, 'YES')) self.assert_(UsesColor('dumb', None, 'T')) self.assert_(UsesColor('dumb', None, '1')) self.assert_(not UsesColor('xterm', None, 'f')) self.assert_(not UsesColor('xterm', None, 'false')) self.assert_(not UsesColor('xterm', None, '0')) self.assert_(not UsesColor('xterm', None, 'unknown')) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_test_utils.py0000775000175100017510000002467512623076744023571 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2006, Google Inc. # 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. """Unit test utilities for Google C++ Testing Framework.""" __author__ = 'wan@google.com (Zhanyong Wan)' import atexit import os import shutil import sys import tempfile import unittest _test_module = unittest # Suppresses the 'Import not at the top of the file' lint complaint. # pylint: disable-msg=C6204 try: import subprocess _SUBPROCESS_MODULE_AVAILABLE = True except: import popen2 _SUBPROCESS_MODULE_AVAILABLE = False # pylint: enable-msg=C6204 GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' IS_WINDOWS = os.name == 'nt' IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] # Here we expose a class from a particular module, depending on the # environment. The comment suppresses the 'Invalid variable name' lint # complaint. TestCase = _test_module.TestCase # pylint: disable-msg=C6409 # Initially maps a flag to its default value. After # _ParseAndStripGTestFlags() is called, maps a flag to its actual value. _flag_map = {'gtest_source_dir': os.path.dirname(sys.argv[0]), 'gtest_build_dir': os.path.dirname(sys.argv[0])} _gtest_flags_are_parsed = False def _ParseAndStripGTestFlags(argv): """Parses and strips Google Test flags from argv. This is idempotent.""" # Suppresses the lint complaint about a global variable since we need it # here to maintain module-wide state. global _gtest_flags_are_parsed # pylint: disable-msg=W0603 if _gtest_flags_are_parsed: return _gtest_flags_are_parsed = True for flag in _flag_map: # The environment variable overrides the default value. if flag.upper() in os.environ: _flag_map[flag] = os.environ[flag.upper()] # The command line flag overrides the environment variable. i = 1 # Skips the program name. while i < len(argv): prefix = '--' + flag + '=' if argv[i].startswith(prefix): _flag_map[flag] = argv[i][len(prefix):] del argv[i] break else: # We don't increment i in case we just found a --gtest_* flag # and removed it from argv. i += 1 def GetFlag(flag): """Returns the value of the given flag.""" # In case GetFlag() is called before Main(), we always call # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags # are parsed. _ParseAndStripGTestFlags(sys.argv) return _flag_map[flag] def GetSourceDir(): """Returns the absolute path of the directory where the .py files are.""" return os.path.abspath(GetFlag('gtest_source_dir')) def GetBuildDir(): """Returns the absolute path of the directory where the test binaries are.""" return os.path.abspath(GetFlag('gtest_build_dir')) _temp_dir = None def _RemoveTempDir(): if _temp_dir: shutil.rmtree(_temp_dir, ignore_errors=True) atexit.register(_RemoveTempDir) def GetTempDir(): """Returns a directory for temporary files.""" global _temp_dir if not _temp_dir: _temp_dir = tempfile.mkdtemp() return _temp_dir def GetTestExecutablePath(executable_name, build_dir=None): """Returns the absolute path of the test binary given its name. The function will print a message and abort the program if the resulting file doesn't exist. Args: executable_name: name of the test binary that the test script runs. build_dir: directory where to look for executables, by default the result of GetBuildDir(). Returns: The absolute path of the test binary. """ path = os.path.abspath(os.path.join(build_dir or GetBuildDir(), executable_name)) if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'): path += '.exe' if not os.path.exists(path): message = ( 'Unable to find the test binary. Please make sure to provide path\n' 'to the binary via the --gtest_build_dir flag or the GTEST_BUILD_DIR\n' 'environment variable. For convenient use, invoke this script via\n' 'mk_test.py.\n' # TODO(vladl@google.com): change mk_test.py to test.py after renaming # the file. 'Please run mk_test.py -h for help.') print >> sys.stderr, message sys.exit(1) return path def GetExitStatus(exit_code): """Returns the argument to exit(), or -1 if exit() wasn't called. Args: exit_code: the result value of os.system(command). """ if os.name == 'nt': # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns # the argument to exit() directly. return exit_code else: # On Unix, os.WEXITSTATUS() must be used to extract the exit status # from the result of os.system(). if os.WIFEXITED(exit_code): return os.WEXITSTATUS(exit_code) else: return -1 class Subprocess: def __init__(self, command, working_dir=None, capture_stderr=True, env=None): """Changes into a specified directory, if provided, and executes a command. Restores the old directory afterwards. Args: command: The command to run, in the form of sys.argv. working_dir: The directory to change into. capture_stderr: Determines whether to capture stderr in the output member or to discard it. env: Dictionary with environment to pass to the subprocess. Returns: An object that represents outcome of the executed process. It has the following attributes: terminated_by_signal True iff the child process has been terminated by a signal. signal Sygnal that terminated the child process. exited True iff the child process exited normally. exit_code The code with which the child process exited. output Child process's stdout and stderr output combined in a string. """ # The subprocess module is the preferrable way of running programs # since it is available and behaves consistently on all platforms, # including Windows. But it is only available starting in python 2.4. # In earlier python versions, we revert to the popen2 module, which is # available in python 2.0 and later but doesn't provide required # functionality (Popen4) under Windows. This allows us to support Mac # OS X 10.4 Tiger, which has python 2.3 installed. if _SUBPROCESS_MODULE_AVAILABLE: if capture_stderr: stderr = subprocess.STDOUT else: stderr = subprocess.PIPE p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=stderr, cwd=working_dir, universal_newlines=True, env=env) # communicate returns a tuple with the file obect for the child's # output. self.output = p.communicate()[0] self._return_code = p.returncode else: old_dir = os.getcwd() def _ReplaceEnvDict(dest, src): # Changes made by os.environ.clear are not inheritable by child # processes until Python 2.6. To produce inheritable changes we have # to delete environment items with the del statement. for key in dest: del dest[key] dest.update(src) # When 'env' is not None, backup the environment variables and replace # them with the passed 'env'. When 'env' is None, we simply use the # current 'os.environ' for compatibility with the subprocess.Popen # semantics used above. if env is not None: old_environ = os.environ.copy() _ReplaceEnvDict(os.environ, env) try: if working_dir is not None: os.chdir(working_dir) if capture_stderr: p = popen2.Popen4(command) else: p = popen2.Popen3(command) p.tochild.close() self.output = p.fromchild.read() ret_code = p.wait() finally: os.chdir(old_dir) # Restore the old environment variables # if they were replaced. if env is not None: _ReplaceEnvDict(os.environ, old_environ) # Converts ret_code to match the semantics of # subprocess.Popen.returncode. if os.WIFSIGNALED(ret_code): self._return_code = -os.WTERMSIG(ret_code) else: # os.WIFEXITED(ret_code) should return True here. self._return_code = os.WEXITSTATUS(ret_code) if self._return_code < 0: self.terminated_by_signal = True self.exited = False self.signal = -self._return_code else: self.terminated_by_signal = False self.exited = True self.exit_code = self._return_code def Main(): """Runs the unit test.""" # We must call _ParseAndStripGTestFlags() before calling # unittest.main(). Otherwise the latter will be confused by the # --gtest_* flags. _ParseAndStripGTestFlags(sys.argv) # The tested binaries should not be writing XML output files unless the # script explicitly instructs them to. # TODO(vladl@google.com): Move this into Subprocess when we implement # passing environment into it as a parameter. if GTEST_OUTPUT_VAR_NAME in os.environ: del os.environ[GTEST_OUTPUT_VAR_NAME] _test_module.main() ceph-0.80.11/src/gtest/test/gtest_xml_outfiles_test.py0000775000175100017510000001230012623076744025121 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """Unit test for the gtest_xml_output module.""" __author__ = "keith.ray@gmail.com (Keith Ray)" import os from xml.dom import minidom, Node import gtest_test_utils import gtest_xml_test_utils GTEST_OUTPUT_SUBDIR = "xml_outfiles" GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_" GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_" EXPECTED_XML_1 = """ """ EXPECTED_XML_2 = """ """ class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase): """Unit test for Google Test's XML output functionality.""" def setUp(self): # We want the trailing '/' that the last "" provides in os.path.join, for # telling Google Test to create an output directory instead of a single file # for xml output. self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(), GTEST_OUTPUT_SUBDIR, "") self.DeleteFilesAndDir() def tearDown(self): self.DeleteFilesAndDir() def DeleteFilesAndDir(self): try: os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml")) except os.error: pass try: os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml")) except os.error: pass try: os.rmdir(self.output_dir_) except os.error: pass def testOutfile1(self): self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_XML_1) def testOutfile2(self): self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_XML_2) def _TestOutFile(self, test_name, expected_xml): gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name) command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_] p = gtest_test_utils.Subprocess(command, working_dir=gtest_test_utils.GetTempDir()) self.assert_(p.exited) self.assertEquals(0, p.exit_code) # TODO(wan@google.com): libtool causes the built test binary to be # named lt-gtest_xml_outfiles_test_ instead of # gtest_xml_outfiles_test_. To account for this possibillity, we # allow both names in the following code. We should remove this # hack when Chandler Carruth's libtool replacement tool is ready. output_file_name1 = test_name + ".xml" output_file1 = os.path.join(self.output_dir_, output_file_name1) output_file_name2 = 'lt-' + output_file_name1 output_file2 = os.path.join(self.output_dir_, output_file_name2) self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2), output_file1) expected = minidom.parseString(expected_xml) if os.path.isfile(output_file1): actual = minidom.parse(output_file1) else: actual = minidom.parse(output_file2) self.NormalizeXml(actual.documentElement) self.AssertEquivalentNodes(expected.documentElement, actual.documentElement) expected.unlink() actual.unlink() if __name__ == "__main__": os.environ["GTEST_STACK_TRACE_DEPTH"] = "0" gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest-unittest-api_test.cc0000664000175100017510000003165312623076744024721 0ustar jenkins-buildjenkins-build// Copyright 2009 Google Inc. 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. // // Author: vladl@google.com (Vlad Losev) // // The Google C++ Testing Framework (Google Test) // // This file contains tests verifying correctness of data provided via // UnitTest's public methods. #include #include // For strcmp. #include using ::testing::InitGoogleTest; namespace testing { namespace internal { template struct LessByName { bool operator()(const T* a, const T* b) { return strcmp(a->name(), b->name()) < 0; } }; class UnitTestHelper { public: // Returns the array of pointers to all test cases sorted by the test case // name. The caller is responsible for deleting the array. static TestCase const** const GetSortedTestCases() { UnitTest& unit_test = *UnitTest::GetInstance(); TestCase const** const test_cases = new const TestCase*[unit_test.total_test_case_count()]; for (int i = 0; i < unit_test.total_test_case_count(); ++i) test_cases[i] = unit_test.GetTestCase(i); std::sort(test_cases, test_cases + unit_test.total_test_case_count(), LessByName()); return test_cases; } // Returns the test case by its name. The caller doesn't own the returned // pointer. static const TestCase* FindTestCase(const char* name) { UnitTest& unit_test = *UnitTest::GetInstance(); for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase* test_case = unit_test.GetTestCase(i); if (0 == strcmp(test_case->name(), name)) return test_case; } return NULL; } // Returns the array of pointers to all tests in a particular test case // sorted by the test name. The caller is responsible for deleting the // array. static TestInfo const** const GetSortedTests(const TestCase* test_case) { TestInfo const** const tests = new const TestInfo*[test_case->total_test_count()]; for (int i = 0; i < test_case->total_test_count(); ++i) tests[i] = test_case->GetTestInfo(i); std::sort(tests, tests + test_case->total_test_count(), LessByName()); return tests; } }; #if GTEST_HAS_TYPED_TEST template class TestCaseWithCommentTest : public Test {}; TYPED_TEST_CASE(TestCaseWithCommentTest, Types); TYPED_TEST(TestCaseWithCommentTest, Dummy) {} const int kTypedTestCases = 1; const int kTypedTests = 1; String GetExpectedTestCaseComment() { Message comment; comment << "TypeParam = " << GetTypeName().c_str(); return comment.GetString(); } #else const int kTypedTestCases = 0; const int kTypedTests = 0; #endif // GTEST_HAS_TYPED_TEST // We can only test the accessors that do not change value while tests run. // Since tests can be run in any order, the values the accessors that track // test execution (such as failed_test_count) can not be predicted. TEST(ApiTest, UnitTestImmutableAccessorsWork) { UnitTest* unit_test = UnitTest::GetInstance(); ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); EXPECT_EQ(1 + kTypedTestCases, unit_test->test_case_to_run_count()); EXPECT_EQ(2, unit_test->disabled_test_count()); EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count()); EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count()); const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); EXPECT_STREQ("ApiTest", test_cases[0]->name()); EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); #if GTEST_HAS_TYPED_TEST EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name()); #endif // GTEST_HAS_TYPED_TEST delete[] test_cases; // The following lines initiate actions to verify certain methods in // FinalSuccessChecker::TearDown. // Records a test property to verify TestResult::GetTestProperty(). RecordProperty("key", "value"); } TEST(ApiTest, TestCaseImmutableAccessorsWork) { const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("ApiTest", test_case->name()); EXPECT_STREQ("", test_case->comment()); EXPECT_TRUE(test_case->should_run()); EXPECT_EQ(1, test_case->disabled_test_count()); EXPECT_EQ(3, test_case->test_to_run_count()); ASSERT_EQ(4, test_case->total_test_count()); const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); EXPECT_STREQ("", tests[0]->comment()); EXPECT_STREQ("", tests[0]->test_case_comment()); EXPECT_FALSE(tests[0]->should_run()); EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); EXPECT_STREQ("", tests[1]->comment()); EXPECT_STREQ("", tests[1]->test_case_comment()); EXPECT_TRUE(tests[1]->should_run()); EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); EXPECT_STREQ("", tests[2]->comment()); EXPECT_STREQ("", tests[2]->test_case_comment()); EXPECT_TRUE(tests[2]->should_run()); EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); EXPECT_STREQ("", tests[3]->comment()); EXPECT_STREQ("", tests[3]->test_case_comment()); EXPECT_TRUE(tests[3]->should_run()); delete[] tests; tests = NULL; #if GTEST_HAS_TYPED_TEST test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name()); EXPECT_STREQ(GetExpectedTestCaseComment().c_str(), test_case->comment()); EXPECT_TRUE(test_case->should_run()); EXPECT_EQ(0, test_case->disabled_test_count()); EXPECT_EQ(1, test_case->test_to_run_count()); ASSERT_EQ(1, test_case->total_test_count()); tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("Dummy", tests[0]->name()); EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); EXPECT_STREQ("", tests[0]->comment()); EXPECT_STREQ(GetExpectedTestCaseComment().c_str(), tests[0]->test_case_comment()); EXPECT_TRUE(tests[0]->should_run()); delete[] tests; #endif // GTEST_HAS_TYPED_TEST } TEST(ApiTest, TestCaseDisabledAccessorsWork) { const TestCase* test_case = UnitTestHelper::FindTestCase("DISABLED_Test"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("DISABLED_Test", test_case->name()); EXPECT_STREQ("", test_case->comment()); EXPECT_FALSE(test_case->should_run()); EXPECT_EQ(1, test_case->disabled_test_count()); EXPECT_EQ(0, test_case->test_to_run_count()); ASSERT_EQ(1, test_case->total_test_count()); const TestInfo* const test_info = test_case->GetTestInfo(0); EXPECT_STREQ("Dummy2", test_info->name()); EXPECT_STREQ("DISABLED_Test", test_info->test_case_name()); EXPECT_STREQ("", test_info->comment()); EXPECT_STREQ("", test_info->test_case_comment()); EXPECT_FALSE(test_info->should_run()); } // These two tests are here to provide support for testing // test_case_to_run_count, disabled_test_count, and test_to_run_count. TEST(ApiTest, DISABLED_Dummy1) {} TEST(DISABLED_Test, Dummy2) {} class FinalSuccessChecker : public Environment { protected: virtual void TearDown() { UnitTest* unit_test = UnitTest::GetInstance(); EXPECT_EQ(1 + kTypedTestCases, unit_test->successful_test_case_count()); EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count()); EXPECT_EQ(0, unit_test->failed_test_case_count()); EXPECT_EQ(0, unit_test->failed_test_count()); EXPECT_TRUE(unit_test->Passed()); EXPECT_FALSE(unit_test->Failed()); ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); EXPECT_STREQ("ApiTest", test_cases[0]->name()); EXPECT_STREQ("", test_cases[0]->comment()); EXPECT_TRUE(test_cases[0]->should_run()); EXPECT_EQ(1, test_cases[0]->disabled_test_count()); ASSERT_EQ(4, test_cases[0]->total_test_count()); EXPECT_EQ(3, test_cases[0]->successful_test_count()); EXPECT_EQ(0, test_cases[0]->failed_test_count()); EXPECT_TRUE(test_cases[0]->Passed()); EXPECT_FALSE(test_cases[0]->Failed()); EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); EXPECT_STREQ("", test_cases[1]->comment()); EXPECT_FALSE(test_cases[1]->should_run()); EXPECT_EQ(1, test_cases[1]->disabled_test_count()); ASSERT_EQ(1, test_cases[1]->total_test_count()); EXPECT_EQ(0, test_cases[1]->successful_test_count()); EXPECT_EQ(0, test_cases[1]->failed_test_count()); #if GTEST_HAS_TYPED_TEST EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name()); EXPECT_STREQ(GetExpectedTestCaseComment().c_str(), test_cases[2]->comment()); EXPECT_TRUE(test_cases[2]->should_run()); EXPECT_EQ(0, test_cases[2]->disabled_test_count()); ASSERT_EQ(1, test_cases[2]->total_test_count()); EXPECT_EQ(1, test_cases[2]->successful_test_count()); EXPECT_EQ(0, test_cases[2]->failed_test_count()); EXPECT_TRUE(test_cases[2]->Passed()); EXPECT_FALSE(test_cases[2]->Failed()); #endif // GTEST_HAS_TYPED_TEST const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); EXPECT_FALSE(tests[0]->should_run()); EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); EXPECT_STREQ("", tests[1]->comment()); EXPECT_STREQ("", tests[1]->test_case_comment()); EXPECT_TRUE(tests[1]->should_run()); EXPECT_TRUE(tests[1]->result()->Passed()); EXPECT_EQ(0, tests[1]->result()->test_property_count()); EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); EXPECT_STREQ("", tests[2]->comment()); EXPECT_STREQ("", tests[2]->test_case_comment()); EXPECT_TRUE(tests[2]->should_run()); EXPECT_TRUE(tests[2]->result()->Passed()); EXPECT_EQ(0, tests[2]->result()->test_property_count()); EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); EXPECT_STREQ("", tests[3]->comment()); EXPECT_STREQ("", tests[3]->test_case_comment()); EXPECT_TRUE(tests[3]->should_run()); EXPECT_TRUE(tests[3]->result()->Passed()); EXPECT_EQ(1, tests[3]->result()->test_property_count()); const TestProperty& property = tests[3]->result()->GetTestProperty(0); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("value", property.value()); delete[] tests; #if GTEST_HAS_TYPED_TEST test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("Dummy", tests[0]->name()); EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); EXPECT_STREQ("", tests[0]->comment()); EXPECT_STREQ(GetExpectedTestCaseComment().c_str(), tests[0]->test_case_comment()); EXPECT_TRUE(tests[0]->should_run()); EXPECT_TRUE(tests[0]->result()->Passed()); EXPECT_EQ(0, tests[0]->result()->test_property_count()); delete[] tests; #endif // GTEST_HAS_TYPED_TEST delete[] test_cases; } }; } // namespace internal } // namespace testing int main(int argc, char **argv) { InitGoogleTest(&argc, argv); AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker()); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_output_test_.cc0000664000175100017510000010375212623076744024054 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // A unit test for Google Test itself. This verifies that the basic // constructs of Google Test work. // // Author: wan@google.com (Zhanyong Wan) #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #include #if GTEST_IS_THREADSAFE using testing::ScopedFakeTestPartResultReporter; using testing::TestPartResultArray; using testing::internal::Notification; using testing::internal::ThreadWithParam; #endif namespace posix = ::testing::internal::posix; using testing::internal::String; using testing::internal::scoped_ptr; // Tests catching fatal failures. // A subroutine used by the following test. void TestEq1(int x) { ASSERT_EQ(1, x); } // This function calls a test subroutine, catches the fatal failure it // generates, and then returns early. void TryTestSubroutine() { // Calls a subrountine that yields a fatal failure. TestEq1(2); // Catches the fatal failure and aborts the test. // // The testing::Test:: prefix is necessary when calling // HasFatalFailure() outside of a TEST, TEST_F, or test fixture. if (testing::Test::HasFatalFailure()) return; // If we get here, something is wrong. FAIL() << "This should never be reached."; } TEST(PassingTest, PassingTest1) { } TEST(PassingTest, PassingTest2) { } // Tests catching a fatal failure in a subroutine. TEST(FatalFailureTest, FatalFailureInSubroutine) { printf("(expecting a failure that x should be 1)\n"); TryTestSubroutine(); } // Tests catching a fatal failure in a nested subroutine. TEST(FatalFailureTest, FatalFailureInNestedSubroutine) { printf("(expecting a failure that x should be 1)\n"); // Calls a subrountine that yields a fatal failure. TryTestSubroutine(); // Catches the fatal failure and aborts the test. // // When calling HasFatalFailure() inside a TEST, TEST_F, or test // fixture, the testing::Test:: prefix is not needed. if (HasFatalFailure()) return; // If we get here, something is wrong. FAIL() << "This should never be reached."; } // Tests HasFatalFailure() after a failed EXPECT check. TEST(FatalFailureTest, NonfatalFailureInSubroutine) { printf("(expecting a failure on false)\n"); EXPECT_TRUE(false); // Generates a nonfatal failure ASSERT_FALSE(HasFatalFailure()); // This should succeed. } // Tests interleaving user logging and Google Test assertions. TEST(LoggingTest, InterleavingLoggingAndAssertions) { static const int a[4] = { 3, 9, 2, 6 }; printf("(expecting 2 failures on (3) >= (a[i]))\n"); for (int i = 0; i < static_cast(sizeof(a)/sizeof(*a)); i++) { printf("i == %d\n", i); EXPECT_GE(3, a[i]); } } // Tests the SCOPED_TRACE macro. // A helper function for testing SCOPED_TRACE. void SubWithoutTrace(int n) { EXPECT_EQ(1, n); ASSERT_EQ(2, n); } // Another helper function for testing SCOPED_TRACE. void SubWithTrace(int n) { SCOPED_TRACE(testing::Message() << "n = " << n); SubWithoutTrace(n); } // Tests that SCOPED_TRACE() obeys lexical scopes. TEST(SCOPED_TRACETest, ObeysScopes) { printf("(expected to fail)\n"); // There should be no trace before SCOPED_TRACE() is invoked. ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; { SCOPED_TRACE("Expected trace"); // After SCOPED_TRACE(), a failure in the current scope should contain // the trace. ADD_FAILURE() << "This failure is expected, and should have a trace."; } // Once the control leaves the scope of the SCOPED_TRACE(), there // should be no trace again. ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; } // Tests that SCOPED_TRACE works inside a loop. TEST(SCOPED_TRACETest, WorksInLoop) { printf("(expected to fail)\n"); for (int i = 1; i <= 2; i++) { SCOPED_TRACE(testing::Message() << "i = " << i); SubWithoutTrace(i); } } // Tests that SCOPED_TRACE works in a subroutine. TEST(SCOPED_TRACETest, WorksInSubroutine) { printf("(expected to fail)\n"); SubWithTrace(1); SubWithTrace(2); } // Tests that SCOPED_TRACE can be nested. TEST(SCOPED_TRACETest, CanBeNested) { printf("(expected to fail)\n"); SCOPED_TRACE(""); // A trace without a message. SubWithTrace(2); } // Tests that multiple SCOPED_TRACEs can be used in the same scope. TEST(SCOPED_TRACETest, CanBeRepeated) { printf("(expected to fail)\n"); SCOPED_TRACE("A"); ADD_FAILURE() << "This failure is expected, and should contain trace point A."; SCOPED_TRACE("B"); ADD_FAILURE() << "This failure is expected, and should contain trace point A and B."; { SCOPED_TRACE("C"); ADD_FAILURE() << "This failure is expected, and should contain " << "trace point A, B, and C."; } SCOPED_TRACE("D"); ADD_FAILURE() << "This failure is expected, and should contain " << "trace point A, B, and D."; } #if GTEST_IS_THREADSAFE // Tests that SCOPED_TRACE()s can be used concurrently from multiple // threads. Namely, an assertion should be affected by // SCOPED_TRACE()s in its own thread only. // Here's the sequence of actions that happen in the test: // // Thread A (main) | Thread B (spawned) // ===============================|================================ // spawns thread B | // -------------------------------+-------------------------------- // waits for n1 | SCOPED_TRACE("Trace B"); // | generates failure #1 // | notifies n1 // -------------------------------+-------------------------------- // SCOPED_TRACE("Trace A"); | waits for n2 // generates failure #2 | // notifies n2 | // -------------------------------|-------------------------------- // waits for n3 | generates failure #3 // | trace B dies // | generates failure #4 // | notifies n3 // -------------------------------|-------------------------------- // generates failure #5 | finishes // trace A dies | // generates failure #6 | // -------------------------------|-------------------------------- // waits for thread B to finish | struct CheckPoints { Notification n1; Notification n2; Notification n3; }; static void ThreadWithScopedTrace(CheckPoints* check_points) { { SCOPED_TRACE("Trace B"); ADD_FAILURE() << "Expected failure #1 (in thread B, only trace B alive)."; check_points->n1.Notify(); check_points->n2.WaitForNotification(); ADD_FAILURE() << "Expected failure #3 (in thread B, trace A & B both alive)."; } // Trace B dies here. ADD_FAILURE() << "Expected failure #4 (in thread B, only trace A alive)."; check_points->n3.Notify(); } TEST(SCOPED_TRACETest, WorksConcurrently) { printf("(expecting 6 failures)\n"); CheckPoints check_points; ThreadWithParam thread(&ThreadWithScopedTrace, &check_points, NULL); check_points.n1.WaitForNotification(); { SCOPED_TRACE("Trace A"); ADD_FAILURE() << "Expected failure #2 (in thread A, trace A & B both alive)."; check_points.n2.Notify(); check_points.n3.WaitForNotification(); ADD_FAILURE() << "Expected failure #5 (in thread A, only trace A alive)."; } // Trace A dies here. ADD_FAILURE() << "Expected failure #6 (in thread A, no trace alive)."; thread.Join(); } #endif // GTEST_IS_THREADSAFE TEST(DisabledTestsWarningTest, DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { // This test body is intentionally empty. Its sole purpose is for // verifying that the --gtest_also_run_disabled_tests flag // suppresses the "YOU HAVE 12 DISABLED TESTS" warning at the end of // the test output. } // Tests using assertions outside of TEST and TEST_F. // // This function creates two failures intentionally. void AdHocTest() { printf("The non-test part of the code is expected to have 2 failures.\n\n"); EXPECT_TRUE(false); EXPECT_EQ(2, 3); } // Runs all TESTs, all TEST_Fs, and the ad hoc test. int RunAllTests() { AdHocTest(); return RUN_ALL_TESTS(); } // Tests non-fatal failures in the fixture constructor. class NonFatalFailureInFixtureConstructorTest : public testing::Test { protected: NonFatalFailureInFixtureConstructorTest() { printf("(expecting 5 failures)\n"); ADD_FAILURE() << "Expected failure #1, in the test fixture c'tor."; } ~NonFatalFailureInFixtureConstructorTest() { ADD_FAILURE() << "Expected failure #5, in the test fixture d'tor."; } virtual void SetUp() { ADD_FAILURE() << "Expected failure #2, in SetUp()."; } virtual void TearDown() { ADD_FAILURE() << "Expected failure #4, in TearDown."; } }; TEST_F(NonFatalFailureInFixtureConstructorTest, FailureInConstructor) { ADD_FAILURE() << "Expected failure #3, in the test body."; } // Tests fatal failures in the fixture constructor. class FatalFailureInFixtureConstructorTest : public testing::Test { protected: FatalFailureInFixtureConstructorTest() { printf("(expecting 2 failures)\n"); Init(); } ~FatalFailureInFixtureConstructorTest() { ADD_FAILURE() << "Expected failure #2, in the test fixture d'tor."; } virtual void SetUp() { ADD_FAILURE() << "UNEXPECTED failure in SetUp(). " << "We should never get here, as the test fixture c'tor " << "had a fatal failure."; } virtual void TearDown() { ADD_FAILURE() << "UNEXPECTED failure in TearDown(). " << "We should never get here, as the test fixture c'tor " << "had a fatal failure."; } private: void Init() { FAIL() << "Expected failure #1, in the test fixture c'tor."; } }; TEST_F(FatalFailureInFixtureConstructorTest, FailureInConstructor) { ADD_FAILURE() << "UNEXPECTED failure in the test body. " << "We should never get here, as the test fixture c'tor " << "had a fatal failure."; } // Tests non-fatal failures in SetUp(). class NonFatalFailureInSetUpTest : public testing::Test { protected: virtual ~NonFatalFailureInSetUpTest() { Deinit(); } virtual void SetUp() { printf("(expecting 4 failures)\n"); ADD_FAILURE() << "Expected failure #1, in SetUp()."; } virtual void TearDown() { FAIL() << "Expected failure #3, in TearDown()."; } private: void Deinit() { FAIL() << "Expected failure #4, in the test fixture d'tor."; } }; TEST_F(NonFatalFailureInSetUpTest, FailureInSetUp) { FAIL() << "Expected failure #2, in the test function."; } // Tests fatal failures in SetUp(). class FatalFailureInSetUpTest : public testing::Test { protected: virtual ~FatalFailureInSetUpTest() { Deinit(); } virtual void SetUp() { printf("(expecting 3 failures)\n"); FAIL() << "Expected failure #1, in SetUp()."; } virtual void TearDown() { FAIL() << "Expected failure #2, in TearDown()."; } private: void Deinit() { FAIL() << "Expected failure #3, in the test fixture d'tor."; } }; TEST_F(FatalFailureInSetUpTest, FailureInSetUp) { FAIL() << "UNEXPECTED failure in the test function. " << "We should never get here, as SetUp() failed."; } #if GTEST_OS_WINDOWS // This group of tests verifies that Google Test handles SEH and C++ // exceptions correctly. // A function that throws an SEH exception. static void ThrowSEH() { int* p = NULL; *p = 0; // Raises an access violation. } // Tests exceptions thrown in the test fixture constructor. class ExceptionInFixtureCtorTest : public testing::Test { protected: ExceptionInFixtureCtorTest() { printf("(expecting a failure on thrown exception " "in the test fixture's constructor)\n"); ThrowSEH(); } virtual ~ExceptionInFixtureCtorTest() { Deinit(); } virtual void SetUp() { FAIL() << "UNEXPECTED failure in SetUp(). " << "We should never get here, as the test fixture c'tor threw."; } virtual void TearDown() { FAIL() << "UNEXPECTED failure in TearDown(). " << "We should never get here, as the test fixture c'tor threw."; } private: void Deinit() { FAIL() << "UNEXPECTED failure in the d'tor. " << "We should never get here, as the test fixture c'tor threw."; } }; TEST_F(ExceptionInFixtureCtorTest, ExceptionInFixtureCtor) { FAIL() << "UNEXPECTED failure in the test function. " << "We should never get here, as the test fixture c'tor threw."; } // Tests exceptions thrown in SetUp(). class ExceptionInSetUpTest : public testing::Test { protected: virtual ~ExceptionInSetUpTest() { Deinit(); } virtual void SetUp() { printf("(expecting 3 failures)\n"); ThrowSEH(); } virtual void TearDown() { FAIL() << "Expected failure #2, in TearDown()."; } private: void Deinit() { FAIL() << "Expected failure #3, in the test fixture d'tor."; } }; TEST_F(ExceptionInSetUpTest, ExceptionInSetUp) { FAIL() << "UNEXPECTED failure in the test function. " << "We should never get here, as SetUp() threw."; } // Tests that TearDown() and the test fixture d'tor are always called, // even when the test function throws an exception. class ExceptionInTestFunctionTest : public testing::Test { protected: virtual ~ExceptionInTestFunctionTest() { Deinit(); } virtual void TearDown() { FAIL() << "Expected failure #2, in TearDown()."; } private: void Deinit() { FAIL() << "Expected failure #3, in the test fixture d'tor."; } }; // Tests that the test fixture d'tor is always called, even when the // test function throws an SEH exception. TEST_F(ExceptionInTestFunctionTest, SEH) { printf("(expecting 3 failures)\n"); ThrowSEH(); } #if GTEST_HAS_EXCEPTIONS // Tests that the test fixture d'tor is always called, even when the // test function throws a C++ exception. We do this only when // GTEST_HAS_EXCEPTIONS is non-zero, i.e. C++ exceptions are enabled. TEST_F(ExceptionInTestFunctionTest, CppException) { throw 1; } // Tests exceptions thrown in TearDown(). class ExceptionInTearDownTest : public testing::Test { protected: virtual ~ExceptionInTearDownTest() { Deinit(); } virtual void TearDown() { throw 1; } private: void Deinit() { FAIL() << "Expected failure #2, in the test fixture d'tor."; } }; TEST_F(ExceptionInTearDownTest, ExceptionInTearDown) { printf("(expecting 2 failures)\n"); } #endif // GTEST_HAS_EXCEPTIONS #endif // GTEST_OS_WINDOWS #if GTEST_IS_THREADSAFE // A unary function that may die. void DieIf(bool should_die) { GTEST_CHECK_(!should_die) << " - death inside DieIf()."; } // Tests running death tests in a multi-threaded context. // Used for coordination between the main and the spawn thread. struct SpawnThreadNotifications { SpawnThreadNotifications() {} Notification spawn_thread_started; Notification spawn_thread_ok_to_terminate; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications); }; // The function to be executed in the thread spawn by the // MultipleThreads test (below). static void ThreadRoutine(SpawnThreadNotifications* notifications) { // Signals the main thread that this thread has started. notifications->spawn_thread_started.Notify(); // Waits for permission to finish from the main thread. notifications->spawn_thread_ok_to_terminate.WaitForNotification(); } // This is a death-test test, but it's not named with a DeathTest // suffix. It starts threads which might interfere with later // death tests, so it must run after all other death tests. class DeathTestAndMultiThreadsTest : public testing::Test { protected: // Starts a thread and waits for it to begin. virtual void SetUp() { thread_.reset(new ThreadWithParam( &ThreadRoutine, ¬ifications_, NULL)); notifications_.spawn_thread_started.WaitForNotification(); } // Tells the thread to finish, and reaps it. // Depending on the version of the thread library in use, // a manager thread might still be left running that will interfere // with later death tests. This is unfortunate, but this class // cleans up after itself as best it can. virtual void TearDown() { notifications_.spawn_thread_ok_to_terminate.Notify(); } private: SpawnThreadNotifications notifications_; scoped_ptr > thread_; }; #endif // GTEST_IS_THREADSAFE // The MixedUpTestCaseTest test case verifies that Google Test will fail a // test if it uses a different fixture class than what other tests in // the same test case use. It deliberately contains two fixture // classes with the same name but defined in different namespaces. // The MixedUpTestCaseWithSameTestNameTest test case verifies that // when the user defines two tests with the same test case name AND // same test name (but in different namespaces), the second test will // fail. namespace foo { class MixedUpTestCaseTest : public testing::Test { }; TEST_F(MixedUpTestCaseTest, FirstTestFromNamespaceFoo) {} TEST_F(MixedUpTestCaseTest, SecondTestFromNamespaceFoo) {} class MixedUpTestCaseWithSameTestNameTest : public testing::Test { }; TEST_F(MixedUpTestCaseWithSameTestNameTest, TheSecondTestWithThisNameShouldFail) {} } // namespace foo namespace bar { class MixedUpTestCaseTest : public testing::Test { }; // The following two tests are expected to fail. We rely on the // golden file to check that Google Test generates the right error message. TEST_F(MixedUpTestCaseTest, ThisShouldFail) {} TEST_F(MixedUpTestCaseTest, ThisShouldFailToo) {} class MixedUpTestCaseWithSameTestNameTest : public testing::Test { }; // Expected to fail. We rely on the golden file to check that Google Test // generates the right error message. TEST_F(MixedUpTestCaseWithSameTestNameTest, TheSecondTestWithThisNameShouldFail) {} } // namespace bar // The following two test cases verify that Google Test catches the user // error of mixing TEST and TEST_F in the same test case. The first // test case checks the scenario where TEST_F appears before TEST, and // the second one checks where TEST appears before TEST_F. class TEST_F_before_TEST_in_same_test_case : public testing::Test { }; TEST_F(TEST_F_before_TEST_in_same_test_case, DefinedUsingTEST_F) {} // Expected to fail. We rely on the golden file to check that Google Test // generates the right error message. TEST(TEST_F_before_TEST_in_same_test_case, DefinedUsingTESTAndShouldFail) {} class TEST_before_TEST_F_in_same_test_case : public testing::Test { }; TEST(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST) {} // Expected to fail. We rely on the golden file to check that Google Test // generates the right error message. TEST_F(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST_FAndShouldFail) { } // Used for testing EXPECT_NONFATAL_FAILURE() and EXPECT_FATAL_FAILURE(). int global_integer = 0; // Tests that EXPECT_NONFATAL_FAILURE() can reference global variables. TEST(ExpectNonfatalFailureTest, CanReferenceGlobalVariables) { global_integer = 0; EXPECT_NONFATAL_FAILURE({ EXPECT_EQ(1, global_integer) << "Expected non-fatal failure."; }, "Expected non-fatal failure."); } // Tests that EXPECT_NONFATAL_FAILURE() can reference local variables // (static or not). TEST(ExpectNonfatalFailureTest, CanReferenceLocalVariables) { int m = 0; static int n; n = 1; EXPECT_NONFATAL_FAILURE({ EXPECT_EQ(m, n) << "Expected non-fatal failure."; }, "Expected non-fatal failure."); } // Tests that EXPECT_NONFATAL_FAILURE() succeeds when there is exactly // one non-fatal failure and no fatal failure. TEST(ExpectNonfatalFailureTest, SucceedsWhenThereIsOneNonfatalFailure) { EXPECT_NONFATAL_FAILURE({ ADD_FAILURE() << "Expected non-fatal failure."; }, "Expected non-fatal failure."); } // Tests that EXPECT_NONFATAL_FAILURE() fails when there is no // non-fatal failure. TEST(ExpectNonfatalFailureTest, FailsWhenThereIsNoNonfatalFailure) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ }, ""); } // Tests that EXPECT_NONFATAL_FAILURE() fails when there are two // non-fatal failures. TEST(ExpectNonfatalFailureTest, FailsWhenThereAreTwoNonfatalFailures) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ ADD_FAILURE() << "Expected non-fatal failure 1."; ADD_FAILURE() << "Expected non-fatal failure 2."; }, ""); } // Tests that EXPECT_NONFATAL_FAILURE() fails when there is one fatal // failure. TEST(ExpectNonfatalFailureTest, FailsWhenThereIsOneFatalFailure) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ FAIL() << "Expected fatal failure."; }, ""); } // Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being // tested returns. TEST(ExpectNonfatalFailureTest, FailsWhenStatementReturns) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ return; }, ""); } #if GTEST_HAS_EXCEPTIONS // Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being // tested throws. TEST(ExpectNonfatalFailureTest, FailsWhenStatementThrows) { printf("(expecting a failure)\n"); try { EXPECT_NONFATAL_FAILURE({ throw 0; }, ""); } catch(int) { // NOLINT } } #endif // GTEST_HAS_EXCEPTIONS // Tests that EXPECT_FATAL_FAILURE() can reference global variables. TEST(ExpectFatalFailureTest, CanReferenceGlobalVariables) { global_integer = 0; EXPECT_FATAL_FAILURE({ ASSERT_EQ(1, global_integer) << "Expected fatal failure."; }, "Expected fatal failure."); } // Tests that EXPECT_FATAL_FAILURE() can reference local static // variables. TEST(ExpectFatalFailureTest, CanReferenceLocalStaticVariables) { static int n; n = 1; EXPECT_FATAL_FAILURE({ ASSERT_EQ(0, n) << "Expected fatal failure."; }, "Expected fatal failure."); } // Tests that EXPECT_FATAL_FAILURE() succeeds when there is exactly // one fatal failure and no non-fatal failure. TEST(ExpectFatalFailureTest, SucceedsWhenThereIsOneFatalFailure) { EXPECT_FATAL_FAILURE({ FAIL() << "Expected fatal failure."; }, "Expected fatal failure."); } // Tests that EXPECT_FATAL_FAILURE() fails when there is no fatal // failure. TEST(ExpectFatalFailureTest, FailsWhenThereIsNoFatalFailure) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ }, ""); } // A helper for generating a fatal failure. void FatalFailure() { FAIL() << "Expected fatal failure."; } // Tests that EXPECT_FATAL_FAILURE() fails when there are two // fatal failures. TEST(ExpectFatalFailureTest, FailsWhenThereAreTwoFatalFailures) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ FatalFailure(); FatalFailure(); }, ""); } // Tests that EXPECT_FATAL_FAILURE() fails when there is one non-fatal // failure. TEST(ExpectFatalFailureTest, FailsWhenThereIsOneNonfatalFailure) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ ADD_FAILURE() << "Expected non-fatal failure."; }, ""); } // Tests that EXPECT_FATAL_FAILURE() fails when the statement being // tested returns. TEST(ExpectFatalFailureTest, FailsWhenStatementReturns) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ return; }, ""); } #if GTEST_HAS_EXCEPTIONS // Tests that EXPECT_FATAL_FAILURE() fails when the statement being // tested throws. TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) { printf("(expecting a failure)\n"); try { EXPECT_FATAL_FAILURE({ throw 0; }, ""); } catch(int) { // NOLINT } } #endif // GTEST_HAS_EXCEPTIONS // This #ifdef block tests the output of typed tests. #if GTEST_HAS_TYPED_TEST template class TypedTest : public testing::Test { }; TYPED_TEST_CASE(TypedTest, testing::Types); TYPED_TEST(TypedTest, Success) { EXPECT_EQ(0, TypeParam()); } TYPED_TEST(TypedTest, Failure) { EXPECT_EQ(1, TypeParam()) << "Expected failure"; } #endif // GTEST_HAS_TYPED_TEST // This #ifdef block tests the output of type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P template class TypedTestP : public testing::Test { }; TYPED_TEST_CASE_P(TypedTestP); TYPED_TEST_P(TypedTestP, Success) { EXPECT_EQ(0U, TypeParam()); } TYPED_TEST_P(TypedTestP, Failure) { EXPECT_EQ(1U, TypeParam()) << "Expected failure"; } REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure); typedef testing::Types UnsignedTypes; INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes); #endif // GTEST_HAS_TYPED_TEST_P #if GTEST_HAS_DEATH_TEST // We rely on the golden file to verify that tests whose test case // name ends with DeathTest are run first. TEST(ADeathTest, ShouldRunFirst) { } #if GTEST_HAS_TYPED_TEST // We rely on the golden file to verify that typed tests whose test // case name ends with DeathTest are run first. template class ATypedDeathTest : public testing::Test { }; typedef testing::Types NumericTypes; TYPED_TEST_CASE(ATypedDeathTest, NumericTypes); TYPED_TEST(ATypedDeathTest, ShouldRunFirst) { } #endif // GTEST_HAS_TYPED_TEST #if GTEST_HAS_TYPED_TEST_P // We rely on the golden file to verify that type-parameterized tests // whose test case name ends with DeathTest are run first. template class ATypeParamDeathTest : public testing::Test { }; TYPED_TEST_CASE_P(ATypeParamDeathTest); TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst) { } REGISTER_TYPED_TEST_CASE_P(ATypeParamDeathTest, ShouldRunFirst); INSTANTIATE_TYPED_TEST_CASE_P(My, ATypeParamDeathTest, NumericTypes); #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_HAS_DEATH_TEST // Tests various failure conditions of // EXPECT_{,NON}FATAL_FAILURE{,_ON_ALL_THREADS}. class ExpectFailureTest : public testing::Test { public: // Must be public and not protected due to a bug in g++ 3.4.2. enum FailureMode { FATAL_FAILURE, NONFATAL_FAILURE }; static void AddFailure(FailureMode failure) { if (failure == FATAL_FAILURE) { FAIL() << "Expected fatal failure."; } else { ADD_FAILURE() << "Expected non-fatal failure."; } } }; TEST_F(ExpectFailureTest, ExpectFatalFailure) { // Expected fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE(SUCCEED(), "Expected fatal failure."); // Expected fatal failure, but got a non-fatal failure. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Expected non-fatal " "failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE(AddFailure(FATAL_FAILURE), "Some other fatal failure " "expected."); } TEST_F(ExpectFailureTest, ExpectNonFatalFailure) { // Expected non-fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE(SUCCEED(), "Expected non-fatal failure."); // Expected non-fatal failure, but got a fatal failure. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE(AddFailure(FATAL_FAILURE), "Expected fatal failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Some other non-fatal " "failure."); } #if GTEST_IS_THREADSAFE class ExpectFailureWithThreadsTest : public ExpectFailureTest { protected: static void AddFailureInOtherThread(FailureMode failure) { ThreadWithParam thread(&AddFailure, failure, NULL); thread.Join(); } }; TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailure) { // We only intercept the current thread. printf("(expecting 2 failures)\n"); EXPECT_FATAL_FAILURE(AddFailureInOtherThread(FATAL_FAILURE), "Expected fatal failure."); } TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailure) { // We only intercept the current thread. printf("(expecting 2 failures)\n"); EXPECT_NONFATAL_FAILURE(AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); } typedef ExpectFailureWithThreadsTest ScopedFakeTestPartResultReporterTest; // Tests that the ScopedFakeTestPartResultReporter only catches failures from // the current thread if it is instantiated with INTERCEPT_ONLY_CURRENT_THREAD. TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) { printf("(expecting 2 failures)\n"); TestPartResultArray results; { ScopedFakeTestPartResultReporter reporter( ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, &results); AddFailureInOtherThread(FATAL_FAILURE); AddFailureInOtherThread(NONFATAL_FAILURE); } // The two failures should not have been intercepted. EXPECT_EQ(0, results.size()) << "This shouldn't fail."; } #endif // GTEST_IS_THREADSAFE TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) { // Expected fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected fatal failure."); // Expected fatal failure, but got a non-fatal failure. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), "Expected non-fatal failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), "Some other fatal failure expected."); } TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads) { // Expected non-fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected non-fatal " "failure."); // Expected non-fatal failure, but got a fatal failure. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), "Expected fatal failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), "Some other non-fatal failure."); } // Two test environments for testing testing::AddGlobalTestEnvironment(). class FooEnvironment : public testing::Environment { public: virtual void SetUp() { printf("%s", "FooEnvironment::SetUp() called.\n"); } virtual void TearDown() { printf("%s", "FooEnvironment::TearDown() called.\n"); FAIL() << "Expected fatal failure."; } }; class BarEnvironment : public testing::Environment { public: virtual void SetUp() { printf("%s", "BarEnvironment::SetUp() called.\n"); } virtual void TearDown() { printf("%s", "BarEnvironment::TearDown() called.\n"); ADD_FAILURE() << "Expected non-fatal failure."; } }; GTEST_DEFINE_bool_(internal_skip_environment_and_ad_hoc_tests, false, "This flag causes the program to skip test environment " "tests and ad hoc tests."); // The main function. // // The idea is to use Google Test to run all the tests we have defined (some // of them are intended to fail), and then compare the test results // with the "golden" file. int main(int argc, char **argv) { testing::GTEST_FLAG(print_time) = false; // We just run the tests, knowing some of them are intended to fail. // We will use a separate Python script to compare the output of // this program with the golden file. // It's hard to test InitGoogleTest() directly, as it has many // global side effects. The following line serves as a sanity test // for it. testing::InitGoogleTest(&argc, argv); if (argc >= 2 && String(argv[1]) == "--gtest_internal_skip_environment_and_ad_hoc_tests") GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = true; #if GTEST_HAS_DEATH_TEST if (testing::internal::GTEST_FLAG(internal_run_death_test) != "") { // Skip the usual output capturing if we're running as the child // process of an threadsafe-style death test. #if GTEST_OS_WINDOWS posix::FReopen("nul:", "w", stdout); #else posix::FReopen("/dev/null", "w", stdout); #endif // GTEST_OS_WINDOWS return RUN_ALL_TESTS(); } #endif // GTEST_HAS_DEATH_TEST if (GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests)) return RUN_ALL_TESTS(); // Registers two global test environments. // The golden file verifies that they are set up in the order they // are registered, and torn down in the reverse order. testing::AddGlobalTestEnvironment(new FooEnvironment); testing::AddGlobalTestEnvironment(new BarEnvironment); return RunAllTests(); } ceph-0.80.11/src/gtest/test/gtest-linked_ptr_test.cc0000664000175100017510000000770612623076744024430 0ustar jenkins-buildjenkins-build// Copyright 2003, Google Inc. // 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. // // Authors: Dan Egnor (egnor@google.com) // Ported to Windows: Vadim Berman (vadimb@google.com) #include #include #include namespace { using testing::Message; using testing::internal::linked_ptr; int num; Message* history = NULL; // Class which tracks allocation/deallocation class A { public: A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; } virtual ~A() { *history << "A" << mynum << " dtor\n"; } virtual void Use() { *history << "A" << mynum << " use\n"; } protected: int mynum; }; // Subclass class B : public A { public: B() { *history << "B" << mynum << " ctor\n"; } ~B() { *history << "B" << mynum << " dtor\n"; } virtual void Use() { *history << "B" << mynum << " use\n"; } }; class LinkedPtrTest : public testing::Test { public: LinkedPtrTest() { num = 0; history = new Message; } virtual ~LinkedPtrTest() { delete history; history = NULL; } }; TEST_F(LinkedPtrTest, GeneralTest) { { linked_ptr a0, a1, a2; a0 = a0; a1 = a2; ASSERT_EQ(a0.get(), static_cast(NULL)); ASSERT_EQ(a1.get(), static_cast(NULL)); ASSERT_EQ(a2.get(), static_cast(NULL)); ASSERT_TRUE(a0 == NULL); ASSERT_TRUE(a1 == NULL); ASSERT_TRUE(a2 == NULL); { linked_ptr a3(new A); a0 = a3; ASSERT_TRUE(a0 == a3); ASSERT_TRUE(a0 != NULL); ASSERT_TRUE(a0.get() == a3); ASSERT_TRUE(a0 == a3.get()); linked_ptr a4(a0); a1 = a4; linked_ptr a5(new A); ASSERT_TRUE(a5.get() != a3); ASSERT_TRUE(a5 != a3.get()); a2 = a5; linked_ptr b0(new B); linked_ptr a6(b0); ASSERT_TRUE(b0 == a6); ASSERT_TRUE(a6 == b0); ASSERT_TRUE(b0 != NULL); a5 = b0; a5 = b0; a3->Use(); a4->Use(); a5->Use(); a6->Use(); b0->Use(); (*b0).Use(); b0.get()->Use(); } a0->Use(); a1->Use(); a2->Use(); a1 = a2; a2.reset(new A); a0.reset(); linked_ptr a7; } ASSERT_STREQ( "A0 ctor\n" "A1 ctor\n" "A2 ctor\n" "B2 ctor\n" "A0 use\n" "A0 use\n" "B2 use\n" "B2 use\n" "B2 use\n" "B2 use\n" "B2 use\n" "B2 dtor\n" "A2 dtor\n" "A0 use\n" "A0 use\n" "A1 use\n" "A3 ctor\n" "A0 dtor\n" "A3 dtor\n" "A1 dtor\n", history->GetString().c_str() ); } } // Unnamed namespace ceph-0.80.11/src/gtest/test/gtest-typed-test2_test.cc0000664000175100017510000000401312623076744024445 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include "test/gtest-typed-test_test.h" #include #if GTEST_HAS_TYPED_TEST_P // Tests that the same type-parameterized test case can be // instantiated in different translation units linked together. // (ContainerTest is also instantiated in gtest-typed-test_test.cc.) INSTANTIATE_TYPED_TEST_CASE_P(Vector, ContainerTest, testing::Types >); #endif // GTEST_HAS_TYPED_TEST_P ceph-0.80.11/src/gtest/test/gtest-typed-test_test.cc0000664000175100017510000002615112623076744024372 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include #include #include "test/gtest-typed-test_test.h" #include using testing::Test; // Used for testing that SetUpTestCase()/TearDownTestCase(), fixture // ctor/dtor, and SetUp()/TearDown() work correctly in typed tests and // type-parameterized test. template class CommonTest : public Test { // For some technical reason, SetUpTestCase() and TearDownTestCase() // must be public. public: static void SetUpTestCase() { shared_ = new T(5); } static void TearDownTestCase() { delete shared_; shared_ = NULL; } // This 'protected:' is optional. There's no harm in making all // members of this fixture class template public. protected: // We used to use std::list here, but switched to std::vector since // MSVC's doesn't compile cleanly with /W4. typedef std::vector Vector; typedef std::set IntSet; CommonTest() : value_(1) {} virtual ~CommonTest() { EXPECT_EQ(3, value_); } virtual void SetUp() { EXPECT_EQ(1, value_); value_++; } virtual void TearDown() { EXPECT_EQ(2, value_); value_++; } T value_; static T* shared_; }; template T* CommonTest::shared_ = NULL; // This #ifdef block tests typed tests. #if GTEST_HAS_TYPED_TEST using testing::Types; // Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, // and SetUp()/TearDown() work correctly in typed tests typedef Types TwoTypes; TYPED_TEST_CASE(CommonTest, TwoTypes); TYPED_TEST(CommonTest, ValuesAreCorrect) { // Static members of the fixture class template can be visited via // the TestFixture:: prefix. EXPECT_EQ(5, *TestFixture::shared_); // Typedefs in the fixture class template can be visited via the // "typename TestFixture::" prefix. typename TestFixture::Vector empty; EXPECT_EQ(0U, empty.size()); typename TestFixture::IntSet empty2; EXPECT_EQ(0U, empty2.size()); // Non-static members of the fixture class must be visited via // 'this', as required by C++ for class templates. EXPECT_EQ(2, this->value_); } // The second test makes sure shared_ is not deleted after the first // test. TYPED_TEST(CommonTest, ValuesAreStillCorrect) { // Static members of the fixture class template can also be visited // via 'this'. ASSERT_TRUE(this->shared_ != NULL); EXPECT_EQ(5, *this->shared_); // TypeParam can be used to refer to the type parameter. EXPECT_EQ(static_cast(2), this->value_); } // Tests that multiple TYPED_TEST_CASE's can be defined in the same // translation unit. template class TypedTest1 : public Test { }; // Verifies that the second argument of TYPED_TEST_CASE can be a // single type. TYPED_TEST_CASE(TypedTest1, int); TYPED_TEST(TypedTest1, A) {} template class TypedTest2 : public Test { }; // Verifies that the second argument of TYPED_TEST_CASE can be a // Types<...> type list. TYPED_TEST_CASE(TypedTest2, Types); // This also verifies that tests from different typed test cases can // share the same name. TYPED_TEST(TypedTest2, A) {} // Tests that a typed test case can be defined in a namespace. namespace library1 { template class NumericTest : public Test { }; typedef Types NumericTypes; TYPED_TEST_CASE(NumericTest, NumericTypes); TYPED_TEST(NumericTest, DefaultIsZero) { EXPECT_EQ(0, TypeParam()); } } // namespace library1 #endif // GTEST_HAS_TYPED_TEST // This #ifdef block tests type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P using testing::Types; using testing::internal::TypedTestCasePState; // Tests TypedTestCasePState. class TypedTestCasePStateTest : public Test { protected: virtual void SetUp() { state_.AddTestName("foo.cc", 0, "FooTest", "A"); state_.AddTestName("foo.cc", 0, "FooTest", "B"); state_.AddTestName("foo.cc", 0, "FooTest", "C"); } TypedTestCasePState state_; }; TEST_F(TypedTestCasePStateTest, SucceedsForMatchingList) { const char* tests = "A, B, C"; EXPECT_EQ(tests, state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); } // Makes sure that the order of the tests and spaces around the names // don't matter. TEST_F(TypedTestCasePStateTest, IgnoresOrderAndSpaces) { const char* tests = "A,C, B"; EXPECT_EQ(tests, state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); } typedef TypedTestCasePStateTest TypedTestCasePStateDeathTest; TEST_F(TypedTestCasePStateDeathTest, DetectsDuplicates) { EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"), "foo\\.cc.1.?: Test A is listed more than once\\."); } TEST_F(TypedTestCasePStateDeathTest, DetectsExtraTest) { EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"), "foo\\.cc.1.?: No test named D can be found in this test case\\."); } TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest) { EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"), "foo\\.cc.1.?: You forgot to list test B\\."); } // Tests that defining a test for a parameterized test case generates // a run-time error if the test case has been registered. TEST_F(TypedTestCasePStateDeathTest, DetectsTestAfterRegistration) { state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C"); EXPECT_DEATH_IF_SUPPORTED( state_.AddTestName("foo.cc", 2, "FooTest", "D"), "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_CASE_P" "\\(FooTest, \\.\\.\\.\\)\\."); } // Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, // and SetUp()/TearDown() work correctly in type-parameterized tests. template class DerivedTest : public CommonTest { }; TYPED_TEST_CASE_P(DerivedTest); TYPED_TEST_P(DerivedTest, ValuesAreCorrect) { // Static members of the fixture class template can be visited via // the TestFixture:: prefix. EXPECT_EQ(5, *TestFixture::shared_); // Non-static members of the fixture class must be visited via // 'this', as required by C++ for class templates. EXPECT_EQ(2, this->value_); } // The second test makes sure shared_ is not deleted after the first // test. TYPED_TEST_P(DerivedTest, ValuesAreStillCorrect) { // Static members of the fixture class template can also be visited // via 'this'. ASSERT_TRUE(this->shared_ != NULL); EXPECT_EQ(5, *this->shared_); EXPECT_EQ(2, this->value_); } REGISTER_TYPED_TEST_CASE_P(DerivedTest, ValuesAreCorrect, ValuesAreStillCorrect); typedef Types MyTwoTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, DerivedTest, MyTwoTypes); // Tests that multiple TYPED_TEST_CASE_P's can be defined in the same // translation unit. template class TypedTestP1 : public Test { }; TYPED_TEST_CASE_P(TypedTestP1); // For testing that the code between TYPED_TEST_CASE_P() and // TYPED_TEST_P() is not enclosed in a namespace. typedef int IntAfterTypedTestCaseP; TYPED_TEST_P(TypedTestP1, A) {} TYPED_TEST_P(TypedTestP1, B) {} // For testing that the code between TYPED_TEST_P() and // REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace. typedef int IntBeforeRegisterTypedTestCaseP; REGISTER_TYPED_TEST_CASE_P(TypedTestP1, A, B); template class TypedTestP2 : public Test { }; TYPED_TEST_CASE_P(TypedTestP2); // This also verifies that tests from different type-parameterized // test cases can share the same name. TYPED_TEST_P(TypedTestP2, A) {} REGISTER_TYPED_TEST_CASE_P(TypedTestP2, A); // Verifies that the code between TYPED_TEST_CASE_P() and // REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace. IntAfterTypedTestCaseP after = 0; IntBeforeRegisterTypedTestCaseP before = 0; // Verifies that the last argument of INSTANTIATE_TYPED_TEST_CASE_P() // can be either a single type or a Types<...> type list. INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP1, int); INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP2, Types); // Tests that the same type-parameterized test case can be // instantiated more than once in the same translation unit. INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types); // Tests that the same type-parameterized test case can be // instantiated in different translation units linked together. // (ContainerTest is also instantiated in gtest-typed-test_test.cc.) typedef Types, std::set > MyContainers; INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers); // Tests that a type-parameterized test case can be defined and // instantiated in a namespace. namespace library2 { template class NumericTest : public Test { }; TYPED_TEST_CASE_P(NumericTest); TYPED_TEST_P(NumericTest, DefaultIsZero) { EXPECT_EQ(0, TypeParam()); } TYPED_TEST_P(NumericTest, ZeroIsLessThanOne) { EXPECT_LT(TypeParam(0), TypeParam(1)); } REGISTER_TYPED_TEST_CASE_P(NumericTest, DefaultIsZero, ZeroIsLessThanOne); typedef Types NumericTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes); } // namespace library2 #endif // GTEST_HAS_TYPED_TEST_P #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) // Google Test may not support type-parameterized tests with some // compilers. If we use conditional compilation to compile out all // code referring to the gtest_main library, MSVC linker will not link // that library at all and consequently complain about missing entry // point defined in that library (fatal error LNK1561: entry point // must be defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {} #endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) ceph-0.80.11/src/gtest/test/gtest_prod_test.cc0000664000175100017510000000424112623076744023312 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Unit test for include/gtest/gtest_prod.h. #include #include "test/production.h" // Tests that private members can be accessed from a TEST declared as // a friend of the class. TEST(PrivateCodeTest, CanAccessPrivateMembers) { PrivateCode a; EXPECT_EQ(0, a.x_); a.set_x(1); EXPECT_EQ(1, a.x_); } typedef testing::Test PrivateCodeFixtureTest; // Tests that private members can be accessed from a TEST_F declared // as a friend of the class. TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers) { PrivateCode a; EXPECT_EQ(0, a.x_); a.set_x(2); EXPECT_EQ(2, a.x_); } ceph-0.80.11/src/gtest/test/run_tests_util_test.py0000775000175100017510000005621512623076744024301 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2009 Google Inc. 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. """Tests for run_tests_util.py test runner script.""" __author__ = 'vladl@google.com (Vlad Losev)' import os import re import sets import unittest import run_tests_util GTEST_DBG_DIR = 'scons/build/dbg/gtest/scons' GTEST_OPT_DIR = 'scons/build/opt/gtest/scons' GTEST_OTHER_DIR = 'scons/build/other/gtest/scons' def AddExeExtension(path): """Appends .exe to the path on Windows or Cygwin.""" if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN: return path + '.exe' else: return path class FakePath(object): """A fake os.path module for testing.""" def __init__(self, current_dir=os.getcwd(), known_paths=None): self.current_dir = current_dir self.tree = {} self.path_separator = os.sep # known_paths contains either absolute or relative paths. Relative paths # are absolutized with self.current_dir. if known_paths: self._AddPaths(known_paths) def _AddPath(self, path): ends_with_slash = path.endswith('/') path = self.abspath(path) if ends_with_slash: path += self.path_separator name_list = path.split(self.path_separator) tree = self.tree for name in name_list[:-1]: if not name: continue if name in tree: tree = tree[name] else: tree[name] = {} tree = tree[name] name = name_list[-1] if name: if name in tree: assert tree[name] == 1 else: tree[name] = 1 def _AddPaths(self, paths): for path in paths: self._AddPath(path) def PathElement(self, path): """Returns an internal representation of directory tree entry for path.""" tree = self.tree name_list = self.abspath(path).split(self.path_separator) for name in name_list: if not name: continue tree = tree.get(name, None) if tree is None: break return tree # Silences pylint warning about using standard names. # pylint: disable-msg=C6409 def normpath(self, path): return os.path.normpath(path) def abspath(self, path): return self.normpath(os.path.join(self.current_dir, path)) def isfile(self, path): return self.PathElement(self.abspath(path)) == 1 def isdir(self, path): return type(self.PathElement(self.abspath(path))) == type(dict()) def basename(self, path): return os.path.basename(path) def dirname(self, path): return os.path.dirname(path) def join(self, *kargs): return os.path.join(*kargs) class FakeOs(object): """A fake os module for testing.""" P_WAIT = os.P_WAIT def __init__(self, fake_path_module): self.path = fake_path_module # Some methods/attributes are delegated to the real os module. self.environ = os.environ # pylint: disable-msg=C6409 def listdir(self, path): assert self.path.isdir(path) return self.path.PathElement(path).iterkeys() def spawnv(self, wait, executable, *kargs): assert wait == FakeOs.P_WAIT return self.spawn_impl(executable, kargs) class GetTestsToRunTest(unittest.TestCase): """Exercises TestRunner.GetTestsToRun.""" def NormalizeGetTestsToRunResults(self, results): """Normalizes path data returned from GetTestsToRun for comparison.""" def NormalizePythonTestPair(pair): """Normalizes path data in the (directory, python_script) pair.""" return (os.path.normpath(pair[0]), os.path.normpath(pair[1])) def NormalizeBinaryTestPair(pair): """Normalizes path data in the (directory, binary_executable) pair.""" directory, executable = map(os.path.normpath, pair) # On Windows and Cygwin, the test file names have the .exe extension, but # they can be invoked either by name or by name+extension. Our test must # accommodate both situations. if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN: executable = re.sub(r'\.exe$', '', executable) return (directory, executable) python_tests = sets.Set(map(NormalizePythonTestPair, results[0])) binary_tests = sets.Set(map(NormalizeBinaryTestPair, results[1])) return (python_tests, binary_tests) def AssertResultsEqual(self, results, expected): """Asserts results returned by GetTestsToRun equal to expected results.""" self.assertEqual(self.NormalizeGetTestsToRunResults(results), self.NormalizeGetTestsToRunResults(expected), 'Incorrect set of tests returned:\n%s\nexpected:\n%s' % (results, expected)) def setUp(self): self.fake_os = FakeOs(FakePath( current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)), known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'), AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'), 'test/gtest_color_test.py'])) self.fake_configurations = ['dbg', 'opt'] self.test_runner = run_tests_util.TestRunner(script_dir='.', injected_os=self.fake_os, injected_subprocess=None) def testBinaryTestsOnly(self): """Exercises GetTestsToRun with parameters designating binary tests only.""" # A default build. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest'], '', False, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')])) # An explicitly specified directory. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_unittest'], '', False, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')])) # A particular configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest'], 'other', False, available_configurations=self.fake_configurations), ([], [(GTEST_OTHER_DIR, GTEST_OTHER_DIR + '/gtest_unittest')])) # All available configurations self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest'], 'all', False, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'), (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')])) # All built configurations (unbuilt don't cause failure). self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest'], '', True, available_configurations=self.fake_configurations + ['unbuilt']), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'), (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')])) # A combination of an explicit directory and a configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_unittest'], 'opt', False, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'), (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')])) # Same test specified in an explicit directory and via a configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_unittest'], 'dbg', False, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')])) # All built configurations + explicit directory + explicit configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_unittest'], 'opt', True, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'), (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')])) def testPythonTestsOnly(self): """Exercises GetTestsToRun with parameters designating Python tests only.""" # A default build. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_color_test.py'], '', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')], [])) # An explicitly specified directory. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'test/gtest_color_test.py'], '', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')], [])) # A particular configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_color_test.py'], 'other', False, available_configurations=self.fake_configurations), ([(GTEST_OTHER_DIR, 'test/gtest_color_test.py')], [])) # All available configurations self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['test/gtest_color_test.py'], 'all', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'), (GTEST_OPT_DIR, 'test/gtest_color_test.py')], [])) # All built configurations (unbuilt don't cause failure). self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_color_test.py'], '', True, available_configurations=self.fake_configurations + ['unbuilt']), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'), (GTEST_OPT_DIR, 'test/gtest_color_test.py')], [])) # A combination of an explicit directory and a configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_color_test.py'], 'opt', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'), (GTEST_OPT_DIR, 'test/gtest_color_test.py')], [])) # Same test specified in an explicit directory and via a configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_color_test.py'], 'dbg', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')], [])) # All built configurations + explicit directory + explicit configuration. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [GTEST_DBG_DIR, 'gtest_color_test.py'], 'opt', True, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'), (GTEST_OPT_DIR, 'test/gtest_color_test.py')], [])) def testCombinationOfBinaryAndPythonTests(self): """Exercises GetTestsToRun with mixed binary/Python tests.""" # Use only default configuration for this test. # Neither binary nor Python tests are specified so find all. self.AssertResultsEqual( self.test_runner.GetTestsToRun( [], '', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')])) # Specifying both binary and Python tests. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest', 'gtest_color_test.py'], '', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')])) # Specifying binary tests suppresses Python tests. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest'], '', False, available_configurations=self.fake_configurations), ([], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')])) # Specifying Python tests suppresses binary tests. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_color_test.py'], '', False, available_configurations=self.fake_configurations), ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')], [])) def testIgnoresNonTestFiles(self): """Verifies that GetTestsToRun ignores non-test files in the filesystem.""" self.fake_os = FakeOs(FakePath( current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)), known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_nontest'), 'test/'])) self.test_runner = run_tests_util.TestRunner(script_dir='.', injected_os=self.fake_os, injected_subprocess=None) self.AssertResultsEqual( self.test_runner.GetTestsToRun( [], '', True, available_configurations=self.fake_configurations), ([], [])) def testWorksFromDifferentDir(self): """Exercises GetTestsToRun from a directory different from run_test.py's.""" # Here we simulate an test script in directory /d/ called from the # directory /a/b/c/. self.fake_os = FakeOs(FakePath( current_dir=os.path.abspath('/a/b/c'), known_paths=[ '/a/b/c/', AddExeExtension('/d/' + GTEST_DBG_DIR + '/gtest_unittest'), AddExeExtension('/d/' + GTEST_OPT_DIR + '/gtest_unittest'), '/d/test/gtest_color_test.py'])) self.fake_configurations = ['dbg', 'opt'] self.test_runner = run_tests_util.TestRunner(script_dir='/d/', injected_os=self.fake_os, injected_subprocess=None) # A binary test. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_unittest'], '', False, available_configurations=self.fake_configurations), ([], [('/d/' + GTEST_DBG_DIR, '/d/' + GTEST_DBG_DIR + '/gtest_unittest')])) # A Python test. self.AssertResultsEqual( self.test_runner.GetTestsToRun( ['gtest_color_test.py'], '', False, available_configurations=self.fake_configurations), ([('/d/' + GTEST_DBG_DIR, '/d/test/gtest_color_test.py')], [])) def testNonTestBinary(self): """Exercises GetTestsToRun with a non-test parameter.""" self.assert_( not self.test_runner.GetTestsToRun( ['gtest_unittest_not_really'], '', False, available_configurations=self.fake_configurations)) def testNonExistingPythonTest(self): """Exercises GetTestsToRun with a non-existent Python test parameter.""" self.assert_( not self.test_runner.GetTestsToRun( ['nonexistent_test.py'], '', False, available_configurations=self.fake_configurations)) if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN: def testDoesNotPickNonExeFilesOnWindows(self): """Verifies that GetTestsToRun does not find _test files on Windows.""" self.fake_os = FakeOs(FakePath( current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)), known_paths=['/d/' + GTEST_DBG_DIR + '/gtest_test', 'test/'])) self.test_runner = run_tests_util.TestRunner(script_dir='.', injected_os=self.fake_os, injected_subprocess=None) self.AssertResultsEqual( self.test_runner.GetTestsToRun( [], '', True, available_configurations=self.fake_configurations), ([], [])) class RunTestsTest(unittest.TestCase): """Exercises TestRunner.RunTests.""" def SpawnSuccess(self, unused_executable, unused_argv): """Fakes test success by returning 0 as an exit code.""" self.num_spawn_calls += 1 return 0 def SpawnFailure(self, unused_executable, unused_argv): """Fakes test success by returning 1 as an exit code.""" self.num_spawn_calls += 1 return 1 def setUp(self): self.fake_os = FakeOs(FakePath( current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)), known_paths=[ AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'), AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'), 'test/gtest_color_test.py'])) self.fake_configurations = ['dbg', 'opt'] self.test_runner = run_tests_util.TestRunner( script_dir=os.path.dirname(__file__) or '.', injected_os=self.fake_os, injected_subprocess=None) self.num_spawn_calls = 0 # A number of calls to spawn. def testRunPythonTestSuccess(self): """Exercises RunTests to handle a Python test success.""" self.fake_os.spawn_impl = self.SpawnSuccess self.assertEqual( self.test_runner.RunTests( [(GTEST_DBG_DIR, 'test/gtest_color_test.py')], []), 0) self.assertEqual(self.num_spawn_calls, 1) def testRunBinaryTestSuccess(self): """Exercises RunTests to handle a binary test success.""" self.fake_os.spawn_impl = self.SpawnSuccess self.assertEqual( self.test_runner.RunTests( [], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]), 0) self.assertEqual(self.num_spawn_calls, 1) def testRunPythonTestFauilure(self): """Exercises RunTests to handle a Python test failure.""" self.fake_os.spawn_impl = self.SpawnFailure self.assertEqual( self.test_runner.RunTests( [(GTEST_DBG_DIR, 'test/gtest_color_test.py')], []), 1) self.assertEqual(self.num_spawn_calls, 1) def testRunBinaryTestFailure(self): """Exercises RunTests to handle a binary test failure.""" self.fake_os.spawn_impl = self.SpawnFailure self.assertEqual( self.test_runner.RunTests( [], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]), 1) self.assertEqual(self.num_spawn_calls, 1) def testCombinedTestSuccess(self): """Exercises RunTests to handle a success of both Python and binary test.""" self.fake_os.spawn_impl = self.SpawnSuccess self.assertEqual( self.test_runner.RunTests( [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]), 0) self.assertEqual(self.num_spawn_calls, 2) def testCombinedTestSuccessAndFailure(self): """Exercises RunTests to handle a success of both Python and binary test.""" def SpawnImpl(executable, argv): self.num_spawn_calls += 1 # Simulates failure of a Python test and success of a binary test. if '.py' in executable or '.py' in argv[0]: return 1 else: return 0 self.fake_os.spawn_impl = SpawnImpl self.assertEqual( self.test_runner.RunTests( [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')], [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]), 0) self.assertEqual(self.num_spawn_calls, 2) class ParseArgsTest(unittest.TestCase): """Exercises ParseArgs.""" def testNoOptions(self): options, args = run_tests_util.ParseArgs('gtest', argv=['script.py']) self.assertEqual(args, ['script.py']) self.assert_(options.configurations is None) self.assertFalse(options.built_configurations) def testOptionC(self): options, args = run_tests_util.ParseArgs( 'gtest', argv=['script.py', '-c', 'dbg']) self.assertEqual(args, ['script.py']) self.assertEqual(options.configurations, 'dbg') self.assertFalse(options.built_configurations) def testOptionA(self): options, args = run_tests_util.ParseArgs('gtest', argv=['script.py', '-a']) self.assertEqual(args, ['script.py']) self.assertEqual(options.configurations, 'all') self.assertFalse(options.built_configurations) def testOptionB(self): options, args = run_tests_util.ParseArgs('gtest', argv=['script.py', '-b']) self.assertEqual(args, ['script.py']) self.assert_(options.configurations is None) self.assertTrue(options.built_configurations) def testOptionCAndOptionB(self): options, args = run_tests_util.ParseArgs( 'gtest', argv=['script.py', '-c', 'dbg', '-b']) self.assertEqual(args, ['script.py']) self.assertEqual(options.configurations, 'dbg') self.assertTrue(options.built_configurations) def testOptionH(self): help_called = [False] # Suppresses lint warning on unused arguments. These arguments are # required by optparse, even though they are unused. # pylint: disable-msg=W0613 def VerifyHelp(option, opt, value, parser): help_called[0] = True # Verifies that -h causes the help callback to be called. help_called[0] = False _, args = run_tests_util.ParseArgs( 'gtest', argv=['script.py', '-h'], help_callback=VerifyHelp) self.assertEqual(args, ['script.py']) self.assertTrue(help_called[0]) # Verifies that --help causes the help callback to be called. help_called[0] = False _, args = run_tests_util.ParseArgs( 'gtest', argv=['script.py', '--help'], help_callback=VerifyHelp) self.assertEqual(args, ['script.py']) self.assertTrue(help_called[0]) if __name__ == '__main__': unittest.main() ceph-0.80.11/src/gtest/test/gtest_help_test_.cc0000664000175100017510000000412312623076744023434 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // This program is meant to be run by gtest_help_test.py. Do not run // it directly. #include // When a help flag is specified, this program should skip the tests // and exit with 0; otherwise the following test will be executed, // causing this program to exit with a non-zero code. TEST(HelpFlagTest, ShouldNotBeRun) { ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified."; } #if GTEST_HAS_DEATH_TEST TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {} #endif ceph-0.80.11/src/gtest/test/gtest_sole_header_test.cc0000664000175100017510000000425512623076744024625 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // // This test verifies that it's possible to use Google Test by including // the gtest.h header file alone. #include namespace { void Subroutine() { EXPECT_EQ(42, 42); } TEST(NoFatalFailureTest, ExpectNoFatalFailure) { EXPECT_NO_FATAL_FAILURE(;); EXPECT_NO_FATAL_FAILURE(SUCCEED()); EXPECT_NO_FATAL_FAILURE(Subroutine()); EXPECT_NO_FATAL_FAILURE({ SUCCEED(); }); } TEST(NoFatalFailureTest, AssertNoFatalFailure) { ASSERT_NO_FATAL_FAILURE(;); ASSERT_NO_FATAL_FAILURE(SUCCEED()); ASSERT_NO_FATAL_FAILURE(Subroutine()); ASSERT_NO_FATAL_FAILURE({ SUCCEED(); }); } } // namespace ceph-0.80.11/src/gtest/test/gtest-param-test2_test.cc0000664000175100017510000000550412623076744024426 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // // Tests for Google Test itself. This verifies that the basic constructs of // Google Test work. #include #include "test/gtest-param-test_test.h" #if GTEST_HAS_PARAM_TEST using ::testing::Values; using ::testing::internal::ParamGenerator; // Tests that generators defined in a different translation unit // are functional. The test using extern_gen is defined // in gtest-param-test_test.cc. ParamGenerator extern_gen = Values(33); // Tests that a parameterized test case can be defined in one translation unit // and instantiated in another. The test is defined in gtest-param-test_test.cc // and ExternalInstantiationTest fixture class is defined in // gtest-param-test_test.h. INSTANTIATE_TEST_CASE_P(MultiplesOf33, ExternalInstantiationTest, Values(33, 66)); // Tests that a parameterized test case can be instantiated // in multiple translation units. Another instantiation is defined // in gtest-param-test_test.cc and InstantiationInMultipleTranslaionUnitsTest // fixture is defined in gtest-param-test_test.h INSTANTIATE_TEST_CASE_P(Sequence2, InstantiationInMultipleTranslaionUnitsTest, Values(42*3, 42*4, 42*5)); #endif // GTEST_HAS_PARAM_TEST ceph-0.80.11/src/gtest/test/gtest_filter_unittest.py0000775000175100017510000005141512623076744024606 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2005 Google Inc. 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. """Unit test for Google Test test filters. A user can specify which test(s) in a Google Test program to run via either the GTEST_FILTER environment variable or the --gtest_filter flag. This script tests such functionality by invoking gtest_filter_unittest_ (a program written with Google Test) with different environments and command line flags. Note that test sharding may also influence which tests are filtered. Therefore, we test that here also. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sets import sys import gtest_test_utils # Constants. # Checks if this platform can pass empty environment variables to child # processes. We set an env variable to an empty string and invoke a python # script in a subprocess to print whether the variable is STILL in # os.environ. We then use 'eval' to parse the child's output so that an # exception is thrown if the input is anything other than 'True' nor 'False'. os.environ['EMPTY_VAR'] = '' child = gtest_test_utils.Subprocess( [sys.executable, '-c', 'import os; print \'EMPTY_VAR\' in os.environ']) CAN_PASS_EMPTY_ENV = eval(child.output) # Check if this platform can unset environment variables in child processes. # We set an env variable to a non-empty string, unset it, and invoke # a python script in a subprocess to print whether the variable # is NO LONGER in os.environ. # We use 'eval' to parse the child's output so that an exception # is thrown if the input is neither 'True' nor 'False'. os.environ['UNSET_VAR'] = 'X' del os.environ['UNSET_VAR'] child = gtest_test_utils.Subprocess( [sys.executable, '-c', 'import os; print \'UNSET_VAR\' not in os.environ']) CAN_UNSET_ENV = eval(child.output) # Checks if we should test with an empty filter. This doesn't # make sense on platforms that cannot pass empty env variables (Win32) # and on platforms that cannot unset variables (since we cannot tell # the difference between "" and NULL -- Borland and Solaris < 5.10) CAN_TEST_EMPTY_FILTER = (CAN_PASS_EMPTY_ENV and CAN_UNSET_ENV) # The environment variable for specifying the test filters. FILTER_ENV_VAR = 'GTEST_FILTER' # The environment variables for test sharding. TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' # The command line flag for specifying the test filters. FILTER_FLAG = 'gtest_filter' # The command line flag for including disabled tests. ALSO_RUN_DISABED_TESTS_FLAG = 'gtest_also_run_disabled_tests' # Command to run the gtest_filter_unittest_ program. COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_filter_unittest_') # Regex for determining whether parameterized tests are enabled in the binary. PARAM_TEST_REGEX = re.compile(r'/ParamTest') # Regex for parsing test case names from Google Test's output. TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)') # Regex for parsing test names from Google Test's output. TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)') # The command line flag to tell Google Test to output the list of tests it # will run. LIST_TESTS_FLAG = '--gtest_list_tests' # Indicates whether Google Test supports death tests. SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess( [COMMAND, LIST_TESTS_FLAG]).output # Full names of all tests in gtest_filter_unittests_. PARAM_TESTS = [ 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestX/1', 'SeqP/ParamTest.TestY/0', 'SeqP/ParamTest.TestY/1', 'SeqQ/ParamTest.TestX/0', 'SeqQ/ParamTest.TestX/1', 'SeqQ/ParamTest.TestY/0', 'SeqQ/ParamTest.TestY/1', ] DISABLED_TESTS = [ 'BarTest.DISABLED_TestFour', 'BarTest.DISABLED_TestFive', 'BazTest.DISABLED_TestC', 'DISABLED_FoobarTest.Test1', 'DISABLED_FoobarTest.DISABLED_Test2', 'DISABLED_FoobarbazTest.TestA', ] if SUPPORTS_DEATH_TESTS: DEATH_TESTS = [ 'HasDeathTest.Test1', 'HasDeathTest.Test2', ] else: DEATH_TESTS = [] # All the non-disabled tests. ACTIVE_TESTS = [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS param_tests_present = None # Utilities. environ = os.environ.copy() def SetEnvVar(env_var, value): """Sets the env variable to 'value'; unsets it when 'value' is None.""" if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] def RunAndReturnOutput(args = None): """Runs the test program and returns its output.""" return gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ).output def RunAndExtractTestList(args = None): """Runs the test program and returns its exit code and a list of tests run.""" p = gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ) tests_run = [] test_case = '' test = '' for line in p.output.split('\n'): match = TEST_CASE_REGEX.match(line) if match is not None: test_case = match.group(1) else: match = TEST_REGEX.match(line) if match is not None: test = match.group(1) tests_run.append(test_case + '.' + test) return (tests_run, p.exit_code) def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs): """Runs the given function and arguments in a modified environment.""" try: original_env = environ.copy() environ.update(extra_env) return function(*args, **kwargs) finally: environ.clear() environ.update(original_env) def RunWithSharding(total_shards, shard_index, command): """Runs a test program shard and returns exit code and a list of tests run.""" extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index), TOTAL_SHARDS_ENV_VAR: str(total_shards)} return InvokeWithModifiedEnv(extra_env, RunAndExtractTestList, command) # The unit test. class GTestFilterUnitTest(gtest_test_utils.TestCase): """Tests the env variable or the command line flag to filter tests.""" # Utilities. def AssertSetEqual(self, lhs, rhs): """Asserts that two sets are equal.""" for elem in lhs: self.assert_(elem in rhs, '%s in %s' % (elem, rhs)) for elem in rhs: self.assert_(elem in lhs, '%s in %s' % (elem, lhs)) def AssertPartitionIsValid(self, set_var, list_of_sets): """Asserts that list_of_sets is a valid partition of set_var.""" full_partition = [] for slice_var in list_of_sets: full_partition.extend(slice_var) self.assertEqual(len(set_var), len(full_partition)) self.assertEqual(sets.Set(set_var), sets.Set(full_partition)) def AdjustForParameterizedTests(self, tests_to_run): """Adjust tests_to_run in case value parameterized tests are disabled.""" global param_tests_present if not param_tests_present: return list(sets.Set(tests_to_run) - sets.Set(PARAM_TESTS)) else: return tests_to_run def RunAndVerify(self, gtest_filter, tests_to_run): """Checks that the binary runs correct set of tests for a given filter.""" tests_to_run = self.AdjustForParameterizedTests(tests_to_run) # First, tests using the environment variable. # Windows removes empty variables from the environment when passing it # to a new process. This means it is impossible to pass an empty filter # into a process using the environment variable. However, we can still # test the case when the variable is not supplied (i.e., gtest_filter is # None). # pylint: disable-msg=C6403 if CAN_TEST_EMPTY_FILTER or gtest_filter != '': SetEnvVar(FILTER_ENV_VAR, gtest_filter) tests_run = RunAndExtractTestList()[0] SetEnvVar(FILTER_ENV_VAR, None) self.AssertSetEqual(tests_run, tests_to_run) # pylint: enable-msg=C6403 # Next, tests using the command line flag. if gtest_filter is None: args = [] else: args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)] tests_run = RunAndExtractTestList(args)[0] self.AssertSetEqual(tests_run, tests_to_run) def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run, args=None, check_exit_0=False): """Checks that binary runs correct tests for the given filter and shard. Runs all shards of gtest_filter_unittest_ with the given filter, and verifies that the right set of tests were run. The union of tests run on each shard should be identical to tests_to_run, without duplicates. Args: gtest_filter: A filter to apply to the tests. total_shards: A total number of shards to split test run into. tests_to_run: A set of tests expected to run. args : Arguments to pass to the to the test binary. check_exit_0: When set to a true value, make sure that all shards return 0. """ tests_to_run = self.AdjustForParameterizedTests(tests_to_run) # Windows removes empty variables from the environment when passing it # to a new process. This means it is impossible to pass an empty filter # into a process using the environment variable. However, we can still # test the case when the variable is not supplied (i.e., gtest_filter is # None). # pylint: disable-msg=C6403 if CAN_TEST_EMPTY_FILTER or gtest_filter != '': SetEnvVar(FILTER_ENV_VAR, gtest_filter) partition = [] for i in range(0, total_shards): (tests_run, exit_code) = RunWithSharding(total_shards, i, args) if check_exit_0: self.assertEqual(0, exit_code) partition.append(tests_run) self.AssertPartitionIsValid(tests_to_run, partition) SetEnvVar(FILTER_ENV_VAR, None) # pylint: enable-msg=C6403 def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run): """Checks that the binary runs correct set of tests for the given filter. Runs gtest_filter_unittest_ with the given filter, and enables disabled tests. Verifies that the right set of tests were run. Args: gtest_filter: A filter to apply to the tests. tests_to_run: A set of tests expected to run. """ tests_to_run = self.AdjustForParameterizedTests(tests_to_run) # Construct the command line. args = ['--%s' % ALSO_RUN_DISABED_TESTS_FLAG] if gtest_filter is not None: args.append('--%s=%s' % (FILTER_FLAG, gtest_filter)) tests_run = RunAndExtractTestList(args)[0] self.AssertSetEqual(tests_run, tests_to_run) def setUp(self): """Sets up test case. Determines whether value-parameterized tests are enabled in the binary and sets the flags accordingly. """ global param_tests_present if param_tests_present is None: param_tests_present = PARAM_TEST_REGEX.search( RunAndReturnOutput()) is not None def testDefaultBehavior(self): """Tests the behavior of not specifying the filter.""" self.RunAndVerify(None, ACTIVE_TESTS) def testDefaultBehaviorWithShards(self): """Tests the behavior without the filter, with sharding enabled.""" self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS) def testEmptyFilter(self): """Tests an empty filter.""" self.RunAndVerify('', []) self.RunAndVerifyWithSharding('', 1, []) self.RunAndVerifyWithSharding('', 2, []) def testBadFilter(self): """Tests a filter that matches nothing.""" self.RunAndVerify('BadFilter', []) self.RunAndVerifyAllowingDisabled('BadFilter', []) def testFullName(self): """Tests filtering by full name.""" self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz']) self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz']) self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz']) def testUniversalFilters(self): """Tests filters that match everything.""" self.RunAndVerify('*', ACTIVE_TESTS) self.RunAndVerify('*.*', ACTIVE_TESTS) self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS) self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS) self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS) def testFilterByTestCase(self): """Tests filtering by test case name.""" self.RunAndVerify('FooTest.*', ['FooTest.Abc', 'FooTest.Xyz']) BAZ_TESTS = ['BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB'] self.RunAndVerify('BazTest.*', BAZ_TESTS) self.RunAndVerifyAllowingDisabled('BazTest.*', BAZ_TESTS + ['BazTest.DISABLED_TestC']) def testFilterByTest(self): """Tests filtering by test name.""" self.RunAndVerify('*.TestOne', ['BarTest.TestOne', 'BazTest.TestOne']) def testFilterDisabledTests(self): """Select only the disabled tests to run.""" self.RunAndVerify('DISABLED_FoobarTest.Test1', []) self.RunAndVerifyAllowingDisabled('DISABLED_FoobarTest.Test1', ['DISABLED_FoobarTest.Test1']) self.RunAndVerify('*DISABLED_*', []) self.RunAndVerifyAllowingDisabled('*DISABLED_*', DISABLED_TESTS) self.RunAndVerify('*.DISABLED_*', []) self.RunAndVerifyAllowingDisabled('*.DISABLED_*', [ 'BarTest.DISABLED_TestFour', 'BarTest.DISABLED_TestFive', 'BazTest.DISABLED_TestC', 'DISABLED_FoobarTest.DISABLED_Test2', ]) self.RunAndVerify('DISABLED_*', []) self.RunAndVerifyAllowingDisabled('DISABLED_*', [ 'DISABLED_FoobarTest.Test1', 'DISABLED_FoobarTest.DISABLED_Test2', 'DISABLED_FoobarbazTest.TestA', ]) def testWildcardInTestCaseName(self): """Tests using wildcard in the test case name.""" self.RunAndVerify('*a*.*', [ 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS) def testWildcardInTestName(self): """Tests using wildcard in the test name.""" self.RunAndVerify('*.*A*', ['FooTest.Abc', 'BazTest.TestA']) def testFilterWithoutDot(self): """Tests a filter that has no '.' in it.""" self.RunAndVerify('*z*', [ 'FooTest.Xyz', 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', ]) def testTwoPatterns(self): """Tests filters that consist of two patterns.""" self.RunAndVerify('Foo*.*:*A*', [ 'FooTest.Abc', 'FooTest.Xyz', 'BazTest.TestA', ]) # An empty pattern + a non-empty one self.RunAndVerify(':*A*', ['FooTest.Abc', 'BazTest.TestA']) def testThreePatterns(self): """Tests filters that consist of three patterns.""" self.RunAndVerify('*oo*:*A*:*One', [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BazTest.TestOne', 'BazTest.TestA', ]) # The 2nd pattern is empty. self.RunAndVerify('*oo*::*One', [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BazTest.TestOne', ]) # The last 2 patterns are empty. self.RunAndVerify('*oo*::', [ 'FooTest.Abc', 'FooTest.Xyz', ]) def testNegativeFilters(self): self.RunAndVerify('*-BazTest.TestOne', [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', 'BazTest.TestA', 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS) self.RunAndVerify('*-FooTest.Abc:BazTest.*', [ 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', ] + DEATH_TESTS + PARAM_TESTS) self.RunAndVerify('BarTest.*-BarTest.TestOne', [ 'BarTest.TestTwo', 'BarTest.TestThree', ]) # Tests without leading '*'. self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [ 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', ] + DEATH_TESTS + PARAM_TESTS) # Value parameterized tests. self.RunAndVerify('*/*', PARAM_TESTS) # Value parameterized tests filtering by the sequence name. self.RunAndVerify('SeqP/*', [ 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestX/1', 'SeqP/ParamTest.TestY/0', 'SeqP/ParamTest.TestY/1', ]) # Value parameterized tests filtering by the test name. self.RunAndVerify('*/0', [ 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestY/0', 'SeqQ/ParamTest.TestX/0', 'SeqQ/ParamTest.TestY/0', ]) def testFlagOverridesEnvVar(self): """Tests that the filter flag overrides the filtering env. variable.""" SetEnvVar(FILTER_ENV_VAR, 'Foo*') args = ['--%s=%s' % (FILTER_FLAG, '*One')] tests_run = RunAndExtractTestList(args)[0] SetEnvVar(FILTER_ENV_VAR, None) self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne']) def testShardStatusFileIsCreated(self): """Tests that the shard file is created if specified in the environment.""" shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), 'shard_status_file') self.assert_(not os.path.exists(shard_status_file)) extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} try: InvokeWithModifiedEnv(extra_env, RunAndReturnOutput) finally: self.assert_(os.path.exists(shard_status_file)) os.remove(shard_status_file) def testShardStatusFileIsCreatedWithListTests(self): """Tests that the shard file is created with the "list_tests" flag.""" shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), 'shard_status_file2') self.assert_(not os.path.exists(shard_status_file)) extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} try: output = InvokeWithModifiedEnv(extra_env, RunAndReturnOutput, [LIST_TESTS_FLAG]) finally: # This assertion ensures that Google Test enumerated the tests as # opposed to running them. self.assert_('[==========]' not in output, 'Unexpected output during test enumeration.\n' 'Please ensure that LIST_TESTS_FLAG is assigned the\n' 'correct flag value for listing Google Test tests.') self.assert_(os.path.exists(shard_status_file)) os.remove(shard_status_file) if SUPPORTS_DEATH_TESTS: def testShardingWorksWithDeathTests(self): """Tests integration with death tests and sharding.""" gtest_filter = 'HasDeathTest.*:SeqP/*' expected_tests = [ 'HasDeathTest.Test1', 'HasDeathTest.Test2', 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestX/1', 'SeqP/ParamTest.TestY/0', 'SeqP/ParamTest.TestY/1', ] for flag in ['--gtest_death_test_style=threadsafe', '--gtest_death_test_style=fast']: self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests, check_exit_0=True, args=[flag]) self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests, check_exit_0=True, args=[flag]) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_break_on_failure_unittest.py0000775000175100017510000001605612623076744026612 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2006, Google Inc. # 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. """Unit test for Google Test's break-on-failure mode. A user can ask Google Test to seg-fault when an assertion fails, using either the GTEST_BREAK_ON_FAILURE environment variable or the --gtest_break_on_failure flag. This script tests such functionality by invoking gtest_break_on_failure_unittest_ (a program written with Google Test) with different environments and command line flags. """ __author__ = 'wan@google.com (Zhanyong Wan)' import gtest_test_utils import os import sys # Constants. IS_WINDOWS = os.name == 'nt' # The environment variable for enabling/disabling the break-on-failure mode. BREAK_ON_FAILURE_ENV_VAR = 'GTEST_BREAK_ON_FAILURE' # The command line flag for enabling/disabling the break-on-failure mode. BREAK_ON_FAILURE_FLAG = 'gtest_break_on_failure' # The environment variable for enabling/disabling the throw-on-failure mode. THROW_ON_FAILURE_ENV_VAR = 'GTEST_THROW_ON_FAILURE' # The environment variable for enabling/disabling the catch-exceptions mode. CATCH_EXCEPTIONS_ENV_VAR = 'GTEST_CATCH_EXCEPTIONS' # Path to the gtest_break_on_failure_unittest_ program. EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_break_on_failure_unittest_') # Utilities. environ = os.environ.copy() def SetEnvVar(env_var, value): """Sets an environment variable to a given value; unsets it when the given value is None. """ if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] def Run(command): """Runs a command; returns 1 if it was killed by a signal, or 0 otherwise.""" p = gtest_test_utils.Subprocess(command, env=environ) if p.terminated_by_signal: return 1 else: return 0 # The tests. class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase): """Tests using the GTEST_BREAK_ON_FAILURE environment variable or the --gtest_break_on_failure flag to turn assertion failures into segmentation faults. """ def RunAndVerify(self, env_var_value, flag_value, expect_seg_fault): """Runs gtest_break_on_failure_unittest_ and verifies that it does (or does not) have a seg-fault. Args: env_var_value: value of the GTEST_BREAK_ON_FAILURE environment variable; None if the variable should be unset. flag_value: value of the --gtest_break_on_failure flag; None if the flag should not be present. expect_seg_fault: 1 if the program is expected to generate a seg-fault; 0 otherwise. """ SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, env_var_value) if env_var_value is None: env_var_value_msg = ' is not set' else: env_var_value_msg = '=' + env_var_value if flag_value is None: flag = '' elif flag_value == '0': flag = '--%s=0' % BREAK_ON_FAILURE_FLAG else: flag = '--%s' % BREAK_ON_FAILURE_FLAG command = [EXE_PATH] if flag: command.append(flag) if expect_seg_fault: should_or_not = 'should' else: should_or_not = 'should not' has_seg_fault = Run(command) SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, None) msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' % (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command), should_or_not)) self.assert_(has_seg_fault == expect_seg_fault, msg) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(env_var_value=None, flag_value=None, expect_seg_fault=0) def testEnvVar(self): """Tests using the GTEST_BREAK_ON_FAILURE environment variable.""" self.RunAndVerify(env_var_value='0', flag_value=None, expect_seg_fault=0) self.RunAndVerify(env_var_value='1', flag_value=None, expect_seg_fault=1) def testFlag(self): """Tests using the --gtest_break_on_failure flag.""" self.RunAndVerify(env_var_value=None, flag_value='0', expect_seg_fault=0) self.RunAndVerify(env_var_value=None, flag_value='1', expect_seg_fault=1) def testFlagOverridesEnvVar(self): """Tests that the flag overrides the environment variable.""" self.RunAndVerify(env_var_value='0', flag_value='0', expect_seg_fault=0) self.RunAndVerify(env_var_value='0', flag_value='1', expect_seg_fault=1) self.RunAndVerify(env_var_value='1', flag_value='0', expect_seg_fault=0) self.RunAndVerify(env_var_value='1', flag_value='1', expect_seg_fault=1) def testBreakOnFailureOverridesThrowOnFailure(self): """Tests that gtest_break_on_failure overrides gtest_throw_on_failure.""" SetEnvVar(THROW_ON_FAILURE_ENV_VAR, '1') try: self.RunAndVerify(env_var_value=None, flag_value='1', expect_seg_fault=1) finally: SetEnvVar(THROW_ON_FAILURE_ENV_VAR, None) if IS_WINDOWS: def testCatchExceptionsDoesNotInterfere(self): """Tests that gtest_catch_exceptions doesn't interfere.""" SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, '1') try: self.RunAndVerify(env_var_value='1', flag_value='1', expect_seg_fault=1) finally: SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, None) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_filter_unittest_.cc0000664000175100017510000000675412623076744024705 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Unit test for Google Test test filters. // // A user can specify which test(s) in a Google Test program to run via // either the GTEST_FILTER environment variable or the --gtest_filter // flag. This is used for testing such functionality. // // The program will be invoked from a Python unit test. Don't run it // directly. #include namespace { // Test case FooTest. class FooTest : public testing::Test { }; TEST_F(FooTest, Abc) { } TEST_F(FooTest, Xyz) { FAIL() << "Expected failure."; } // Test case BarTest. TEST(BarTest, TestOne) { } TEST(BarTest, TestTwo) { } TEST(BarTest, TestThree) { } TEST(BarTest, DISABLED_TestFour) { FAIL() << "Expected failure."; } TEST(BarTest, DISABLED_TestFive) { FAIL() << "Expected failure."; } // Test case BazTest. TEST(BazTest, TestOne) { FAIL() << "Expected failure."; } TEST(BazTest, TestA) { } TEST(BazTest, TestB) { } TEST(BazTest, DISABLED_TestC) { FAIL() << "Expected failure."; } // Test case HasDeathTest TEST(HasDeathTest, Test1) { EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); } // We need at least two death tests to make sure that the all death tests // aren't on the first shard. TEST(HasDeathTest, Test2) { EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); } // Test case FoobarTest TEST(DISABLED_FoobarTest, Test1) { FAIL() << "Expected failure."; } TEST(DISABLED_FoobarTest, DISABLED_Test2) { FAIL() << "Expected failure."; } // Test case FoobarbazTest TEST(DISABLED_FoobarbazTest, TestA) { FAIL() << "Expected failure."; } #if GTEST_HAS_PARAM_TEST class ParamTest : public testing::TestWithParam { }; TEST_P(ParamTest, TestX) { } TEST_P(ParamTest, TestY) { } INSTANTIATE_TEST_CASE_P(SeqP, ParamTest, testing::Values(1, 2)); INSTANTIATE_TEST_CASE_P(SeqQ, ParamTest, testing::Values(5, 6)); #endif // GTEST_HAS_PARAM_TEST } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_all_test.cc0000664000175100017510000000435012623076744023117 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Tests for Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build most of Google Test's own tests // by compiling a single file. This file serves this purpose. #include "test/gtest-filepath_test.cc" #include "test/gtest-linked_ptr_test.cc" #include "test/gtest-message_test.cc" #include "test/gtest-options_test.cc" #include "test/gtest-port_test.cc" #include "test/gtest_pred_impl_unittest.cc" #include "test/gtest_prod_test.cc" #include "test/gtest-test-part_test.cc" #include "test/gtest-typed-test_test.cc" #include "test/gtest-typed-test2_test.cc" #include "test/gtest_unittest.cc" #include "test/production.cc" #include "src/gtest_main.cc" ceph-0.80.11/src/gtest/test/production.cc0000664000175100017510000000330412623076744022266 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // This is part of the unit test for include/gtest/gtest_prod.h. #include "production.h" PrivateCode::PrivateCode() : x_(0) {} ceph-0.80.11/src/gtest/test/gtest-death-test_test.cc0000664000175100017510000011433112623076744024330 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Tests for death tests. #include #include #include using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; #if GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS #include // For chdir(). #else #include #include // For waitpid. #include // For std::numeric_limits. #endif // GTEST_OS_WINDOWS #include #include #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace posix = ::testing::internal::posix; using testing::Message; using testing::internal::DeathTest; using testing::internal::DeathTestFactory; using testing::internal::FilePath; using testing::internal::GetLastErrnoDescription; using testing::internal::GetUnitTestImpl; using testing::internal::ParseNaturalNumber; using testing::internal::String; namespace testing { namespace internal { // A helper class whose objects replace the death test factory for a // single UnitTest object during their lifetimes. class ReplaceDeathTestFactory { public: explicit ReplaceDeathTestFactory(DeathTestFactory* new_factory) : unit_test_impl_(GetUnitTestImpl()) { old_factory_ = unit_test_impl_->death_test_factory_.release(); unit_test_impl_->death_test_factory_.reset(new_factory); } ~ReplaceDeathTestFactory() { unit_test_impl_->death_test_factory_.release(); unit_test_impl_->death_test_factory_.reset(old_factory_); } private: // Prevents copying ReplaceDeathTestFactory objects. ReplaceDeathTestFactory(const ReplaceDeathTestFactory&); void operator=(const ReplaceDeathTestFactory&); UnitTestImpl* unit_test_impl_; DeathTestFactory* old_factory_; }; } // namespace internal } // namespace testing void DieInside(const char* function) { fprintf(stderr, "death inside %s().", function); fflush(stderr); // We call _exit() instead of exit(), as the former is a direct // system call and thus safer in the presence of threads. exit() // will invoke user-defined exit-hooks, which may do dangerous // things that conflict with death tests. // // Some compilers can recognize that _exit() never returns and issue the // 'unreachable code' warning for code following this function, unless // fooled by a fake condition. if (AlwaysTrue()) _exit(1); } // Tests that death tests work. class TestForDeathTest : public testing::Test { protected: TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {} virtual ~TestForDeathTest() { posix::ChDir(original_dir_.c_str()); } // A static member function that's expected to die. static void StaticMemberFunction() { DieInside("StaticMemberFunction"); } // A method of the test fixture that may die. void MemberFunction() { if (should_die_) DieInside("MemberFunction"); } // True iff MemberFunction() should die. bool should_die_; const FilePath original_dir_; }; // A class with a member function that may die. class MayDie { public: explicit MayDie(bool should_die) : should_die_(should_die) {} // A member function that may die. void MemberFunction() const { if (should_die_) DieInside("MayDie::MemberFunction"); } private: // True iff MemberFunction() should die. bool should_die_; }; // A global function that's expected to die. void GlobalFunction() { DieInside("GlobalFunction"); } // A non-void function that's expected to die. int NonVoidFunction() { DieInside("NonVoidFunction"); return 1; } // A unary function that may die. void DieIf(bool should_die) { if (should_die) DieInside("DieIf"); } // A binary function that may die. bool DieIfLessThan(int x, int y) { if (x < y) { DieInside("DieIfLessThan"); } return true; } // Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. void DeathTestSubroutine() { EXPECT_DEATH(GlobalFunction(), "death.*GlobalFunction"); ASSERT_DEATH(GlobalFunction(), "death.*GlobalFunction"); } // Death in dbg, not opt. int DieInDebugElse12(int* sideeffect) { if (sideeffect) *sideeffect = 12; #ifndef NDEBUG DieInside("DieInDebugElse12"); #endif // NDEBUG return 12; } #if GTEST_OS_WINDOWS // Tests the ExitedWithCode predicate. TEST(ExitStatusPredicateTest, ExitedWithCode) { // On Windows, the process's exit code is the same as its exit status, // so the predicate just compares the its input with its parameter. EXPECT_TRUE(testing::ExitedWithCode(0)(0)); EXPECT_TRUE(testing::ExitedWithCode(1)(1)); EXPECT_TRUE(testing::ExitedWithCode(42)(42)); EXPECT_FALSE(testing::ExitedWithCode(0)(1)); EXPECT_FALSE(testing::ExitedWithCode(1)(0)); } #else // Returns the exit status of a process that calls _exit(2) with a // given exit code. This is a helper function for the // ExitStatusPredicateTest test suite. static int NormalExitStatus(int exit_code) { pid_t child_pid = fork(); if (child_pid == 0) { _exit(exit_code); } int status; waitpid(child_pid, &status, 0); return status; } // Returns the exit status of a process that raises a given signal. // If the signal does not cause the process to die, then it returns // instead the exit status of a process that exits normally with exit // code 1. This is a helper function for the ExitStatusPredicateTest // test suite. static int KilledExitStatus(int signum) { pid_t child_pid = fork(); if (child_pid == 0) { raise(signum); _exit(1); } int status; waitpid(child_pid, &status, 0); return status; } // Tests the ExitedWithCode predicate. TEST(ExitStatusPredicateTest, ExitedWithCode) { const int status0 = NormalExitStatus(0); const int status1 = NormalExitStatus(1); const int status42 = NormalExitStatus(42); const testing::ExitedWithCode pred0(0); const testing::ExitedWithCode pred1(1); const testing::ExitedWithCode pred42(42); EXPECT_PRED1(pred0, status0); EXPECT_PRED1(pred1, status1); EXPECT_PRED1(pred42, status42); EXPECT_FALSE(pred0(status1)); EXPECT_FALSE(pred42(status0)); EXPECT_FALSE(pred1(status42)); } // Tests the KilledBySignal predicate. TEST(ExitStatusPredicateTest, KilledBySignal) { const int status_segv = KilledExitStatus(SIGSEGV); const int status_kill = KilledExitStatus(SIGKILL); const testing::KilledBySignal pred_segv(SIGSEGV); const testing::KilledBySignal pred_kill(SIGKILL); EXPECT_PRED1(pred_segv, status_segv); EXPECT_PRED1(pred_kill, status_kill); EXPECT_FALSE(pred_segv(status_kill)); EXPECT_FALSE(pred_kill(status_segv)); } #endif // GTEST_OS_WINDOWS // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. TEST_F(TestForDeathTest, SingleStatement) { if (AlwaysFalse()) // This would fail if executed; this is a compilation test only ASSERT_DEATH(return, ""); if (AlwaysTrue()) EXPECT_DEATH(_exit(1), ""); else // This empty "else" branch is meant to ensure that EXPECT_DEATH // doesn't expand into an "if" statement without an "else" ; if (AlwaysFalse()) ASSERT_DEATH(return, "") << "did not die"; if (AlwaysFalse()) ; else EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; } void DieWithEmbeddedNul() { fprintf(stderr, "Hello%cmy null world.\n", '\0'); fflush(stderr); _exit(1); } #if GTEST_USES_PCRE // Tests that EXPECT_DEATH and ASSERT_DEATH work when the error // message has a NUL character in it. TEST_F(TestForDeathTest, EmbeddedNulInMessage) { // TODO(wan@google.com): doesn't support matching strings // with embedded NUL characters - find a way to workaround it. EXPECT_DEATH(DieWithEmbeddedNul(), "my null world"); ASSERT_DEATH(DieWithEmbeddedNul(), "my null world"); } #endif // GTEST_USES_PCRE // Tests that death test macros expand to code which interacts well with switch // statements. TEST_F(TestForDeathTest, SwitchStatement) { // Microsoft compiler usually complains about switch statements without // case labels. We suppress that warning for this test. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4065) #endif // _MSC_VER switch (0) default: ASSERT_DEATH(_exit(1), "") << "exit in default switch handler"; switch (0) case 0: EXPECT_DEATH(_exit(1), "") << "exit in switch case"; #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER } // Tests that a static member function can be used in a "fast" style // death test. TEST_F(TestForDeathTest, StaticMemberFunctionFastStyle) { testing::GTEST_FLAG(death_test_style) = "fast"; ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); } // Tests that a method of the test fixture can be used in a "fast" // style death test. TEST_F(TestForDeathTest, MemberFunctionFastStyle) { testing::GTEST_FLAG(death_test_style) = "fast"; should_die_ = true; EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); } void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); } // Tests that death tests work even if the current directory has been // changed. TEST_F(TestForDeathTest, FastDeathTestInChangedDir) { testing::GTEST_FLAG(death_test_style) = "fast"; ChangeToRootDir(); EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ChangeToRootDir(); ASSERT_DEATH(_exit(1), ""); } // Repeats a representative sample of death tests in the "threadsafe" style: TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); } TEST_F(TestForDeathTest, MemberFunctionThreadsafeStyle) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; should_die_ = true; EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); } TEST_F(TestForDeathTest, ThreadsafeDeathTestInLoop) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; for (int i = 0; i < 3; ++i) EXPECT_EXIT(_exit(i), testing::ExitedWithCode(i), "") << ": i = " << i; } TEST_F(TestForDeathTest, ThreadsafeDeathTestInChangedDir) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; ChangeToRootDir(); EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ChangeToRootDir(); ASSERT_DEATH(_exit(1), ""); } TEST_F(TestForDeathTest, MixedStyles) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; EXPECT_DEATH(_exit(1), ""); testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH(_exit(1), ""); } namespace { bool pthread_flag; void SetPthreadFlag() { pthread_flag = true; } } // namespace #if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { if (!testing::GTEST_FLAG(death_test_use_fork)) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; pthread_flag = false; ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL)); ASSERT_DEATH(_exit(1), ""); ASSERT_FALSE(pthread_flag); } } #endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD // Tests that a method of another class can be used in a death test. TEST_F(TestForDeathTest, MethodOfAnotherClass) { const MayDie x(true); ASSERT_DEATH(x.MemberFunction(), "MayDie\\:\\:MemberFunction"); } // Tests that a global function can be used in a death test. TEST_F(TestForDeathTest, GlobalFunction) { EXPECT_DEATH(GlobalFunction(), "GlobalFunction"); } // Tests that any value convertible to an RE works as a second // argument to EXPECT_DEATH. TEST_F(TestForDeathTest, AcceptsAnythingConvertibleToRE) { static const char regex_c_str[] = "GlobalFunction"; EXPECT_DEATH(GlobalFunction(), regex_c_str); const testing::internal::RE regex(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex); #if GTEST_HAS_GLOBAL_STRING const string regex_str(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex_str); #endif // GTEST_HAS_GLOBAL_STRING const ::std::string regex_std_str(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex_std_str); } // Tests that a non-void function can be used in a death test. TEST_F(TestForDeathTest, NonVoidFunction) { ASSERT_DEATH(NonVoidFunction(), "NonVoidFunction"); } // Tests that functions that take parameter(s) can be used in a death test. TEST_F(TestForDeathTest, FunctionWithParameter) { EXPECT_DEATH(DieIf(true), "DieIf\\(\\)"); EXPECT_DEATH(DieIfLessThan(2, 3), "DieIfLessThan"); } // Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. TEST_F(TestForDeathTest, OutsideFixture) { DeathTestSubroutine(); } // Tests that death tests can be done inside a loop. TEST_F(TestForDeathTest, InsideLoop) { for (int i = 0; i < 5; i++) { EXPECT_DEATH(DieIfLessThan(-1, i), "DieIfLessThan") << "where i == " << i; } } // Tests that a compound statement can be used in a death test. TEST_F(TestForDeathTest, CompoundStatement) { EXPECT_DEATH({ // NOLINT const int x = 2; const int y = x + 1; DieIfLessThan(x, y); }, "DieIfLessThan"); } // Tests that code that doesn't die causes a death test to fail. TEST_F(TestForDeathTest, DoesNotDie) { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieIf(false), "DieIf"), "failed to die"); } // Tests that a death test fails when the error message isn't expected. TEST_F(TestForDeathTest, ErrorMessageMismatch) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_DEATH(DieIf(true), "DieIfLessThan") << "End of death test message."; }, "died but not with expected error"); } // On exit, *aborted will be true iff the EXPECT_DEATH() statement // aborted the function. void ExpectDeathTestHelper(bool* aborted) { *aborted = true; EXPECT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. *aborted = false; } // Tests that EXPECT_DEATH doesn't abort the test on failure. TEST_F(TestForDeathTest, EXPECT_DEATH) { bool aborted = true; EXPECT_NONFATAL_FAILURE(ExpectDeathTestHelper(&aborted), "failed to die"); EXPECT_FALSE(aborted); } // Tests that ASSERT_DEATH does abort the test on failure. TEST_F(TestForDeathTest, ASSERT_DEATH) { static bool aborted; EXPECT_FATAL_FAILURE({ // NOLINT aborted = true; ASSERT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. aborted = false; }, "failed to die"); EXPECT_TRUE(aborted); } // Tests that EXPECT_DEATH evaluates the arguments exactly once. TEST_F(TestForDeathTest, SingleEvaluation) { int x = 3; EXPECT_DEATH(DieIf((++x) == 4), "DieIf"); const char* regex = "DieIf"; const char* regex_save = regex; EXPECT_DEATH(DieIfLessThan(3, 4), regex++); EXPECT_EQ(regex_save + 1, regex); } // Tests that run-away death tests are reported as failures. TEST_F(TestForDeathTest, Runaway) { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast(0), "Foo"), "failed to die."); EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"), "illegal return in test statement."); } // Tests that EXPECT_DEBUG_DEATH works as expected, // that is, in debug mode, it: // 1. Asserts on death. // 2. Has no side effect. // // And in opt mode, it: // 1. Has side effects but does not assert. TEST_F(TestForDeathTest, TestExpectDebugDeath) { int sideeffect = 0; EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12"); #ifdef NDEBUG // Checks that the assignment occurs in opt mode (sideeffect). EXPECT_EQ(12, sideeffect); #else // Checks that the assignment does not occur in dbg mode (no sideeffect). EXPECT_EQ(0, sideeffect); #endif } // Tests that ASSERT_DEBUG_DEATH works as expected // In debug mode: // 1. Asserts on debug death. // 2. Has no side effect. // // In opt mode: // 1. Has side effects and returns the expected value (12). TEST_F(TestForDeathTest, TestAssertDebugDeath) { int sideeffect = 0; ASSERT_DEBUG_DEATH({ // NOLINT // Tests that the return value is 12 in opt mode. EXPECT_EQ(12, DieInDebugElse12(&sideeffect)); // Tests that the side effect occurred in opt mode. EXPECT_EQ(12, sideeffect); }, "death.*DieInDebugElse12"); #ifdef NDEBUG // Checks that the assignment occurs in opt mode (sideeffect). EXPECT_EQ(12, sideeffect); #else // Checks that the assignment does not occur in dbg mode (no sideeffect). EXPECT_EQ(0, sideeffect); #endif } #ifndef NDEBUG void ExpectDebugDeathHelper(bool* aborted) { *aborted = true; EXPECT_DEBUG_DEATH(return, "") << "This is expected to fail."; *aborted = false; } #if GTEST_OS_WINDOWS TEST(PopUpDeathTest, DoesNotShowPopUpOnAbort) { printf("This test should be considered failing if it shows " "any pop-up dialogs.\n"); fflush(stdout); EXPECT_DEATH({ testing::GTEST_FLAG(catch_exceptions) = false; abort(); }, ""); } TEST(PopUpDeathTest, DoesNotShowPopUpOnThrow) { printf("This test should be considered failing if it shows " "any pop-up dialogs.\n"); fflush(stdout); EXPECT_DEATH({ testing::GTEST_FLAG(catch_exceptions) = false; throw 1; }, ""); } #endif // GTEST_OS_WINDOWS // Tests that EXPECT_DEBUG_DEATH in debug mode does not abort // the function. TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) { bool aborted = true; EXPECT_NONFATAL_FAILURE(ExpectDebugDeathHelper(&aborted), ""); EXPECT_FALSE(aborted); } void AssertDebugDeathHelper(bool* aborted) { *aborted = true; ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail."; *aborted = false; } // Tests that ASSERT_DEBUG_DEATH in debug mode aborts the function on // failure. TEST_F(TestForDeathTest, AssertDebugDeathAborts) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } #endif // _NDEBUG // Tests the *_EXIT family of macros, using a variety of predicates. static void TestExitMacros() { EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), ""); #if GTEST_OS_WINDOWS // Of all signals effects on the process exit code, only those of SIGABRT // are documented on Windows. // See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx. EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), ""); #else EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo"; ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar"; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EXIT(_exit(0), testing::KilledBySignal(SIGSEGV), "") << "This failure is expected, too."; }, "This failure is expected, too."); #endif // GTEST_OS_WINDOWS EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EXIT(raise(SIGSEGV), testing::ExitedWithCode(0), "") << "This failure is expected."; }, "This failure is expected."); } TEST_F(TestForDeathTest, ExitMacros) { TestExitMacros(); } TEST_F(TestForDeathTest, ExitMacrosUsingFork) { testing::GTEST_FLAG(death_test_use_fork) = true; TestExitMacros(); } TEST_F(TestForDeathTest, InvalidStyle) { testing::GTEST_FLAG(death_test_style) = "rococo"; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_DEATH(_exit(0), "") << "This failure is expected."; }, "This failure is expected."); } // A DeathTestFactory that returns MockDeathTests. class MockDeathTestFactory : public DeathTestFactory { public: MockDeathTestFactory(); virtual bool Create(const char* statement, const ::testing::internal::RE* regex, const char* file, int line, DeathTest** test); // Sets the parameters for subsequent calls to Create. void SetParameters(bool create, DeathTest::TestRole role, int status, bool passed); // Accessors. int AssumeRoleCalls() const { return assume_role_calls_; } int WaitCalls() const { return wait_calls_; } int PassedCalls() const { return passed_args_.size(); } bool PassedArgument(int n) const { return passed_args_[n]; } int AbortCalls() const { return abort_args_.size(); } DeathTest::AbortReason AbortArgument(int n) const { return abort_args_[n]; } bool TestDeleted() const { return test_deleted_; } private: friend class MockDeathTest; // If true, Create will return a MockDeathTest; otherwise it returns // NULL. bool create_; // The value a MockDeathTest will return from its AssumeRole method. DeathTest::TestRole role_; // The value a MockDeathTest will return from its Wait method. int status_; // The value a MockDeathTest will return from its Passed method. bool passed_; // Number of times AssumeRole was called. int assume_role_calls_; // Number of times Wait was called. int wait_calls_; // The arguments to the calls to Passed since the last call to // SetParameters. std::vector passed_args_; // The arguments to the calls to Abort since the last call to // SetParameters. std::vector abort_args_; // True if the last MockDeathTest returned by Create has been // deleted. bool test_deleted_; }; // A DeathTest implementation useful in testing. It returns values set // at its creation from its various inherited DeathTest methods, and // reports calls to those methods to its parent MockDeathTestFactory // object. class MockDeathTest : public DeathTest { public: MockDeathTest(MockDeathTestFactory *parent, TestRole role, int status, bool passed) : parent_(parent), role_(role), status_(status), passed_(passed) { } virtual ~MockDeathTest() { parent_->test_deleted_ = true; } virtual TestRole AssumeRole() { ++parent_->assume_role_calls_; return role_; } virtual int Wait() { ++parent_->wait_calls_; return status_; } virtual bool Passed(bool exit_status_ok) { parent_->passed_args_.push_back(exit_status_ok); return passed_; } virtual void Abort(AbortReason reason) { parent_->abort_args_.push_back(reason); } private: MockDeathTestFactory* const parent_; const TestRole role_; const int status_; const bool passed_; }; // MockDeathTestFactory constructor. MockDeathTestFactory::MockDeathTestFactory() : create_(true), role_(DeathTest::OVERSEE_TEST), status_(0), passed_(true), assume_role_calls_(0), wait_calls_(0), passed_args_(), abort_args_() { } // Sets the parameters for subsequent calls to Create. void MockDeathTestFactory::SetParameters(bool create, DeathTest::TestRole role, int status, bool passed) { create_ = create; role_ = role; status_ = status; passed_ = passed; assume_role_calls_ = 0; wait_calls_ = 0; passed_args_.clear(); abort_args_.clear(); } // Sets test to NULL (if create_ is false) or to the address of a new // MockDeathTest object with parameters taken from the last call // to SetParameters (if create_ is true). Always returns true. bool MockDeathTestFactory::Create(const char* /*statement*/, const ::testing::internal::RE* /*regex*/, const char* /*file*/, int /*line*/, DeathTest** test) { test_deleted_ = false; if (create_) { *test = new MockDeathTest(this, role_, status_, passed_); } else { *test = NULL; } return true; } // A test fixture for testing the logic of the GTEST_DEATH_TEST_ macro. // It installs a MockDeathTestFactory that is used for the duration // of the test case. class MacroLogicDeathTest : public testing::Test { protected: static testing::internal::ReplaceDeathTestFactory* replacer_; static MockDeathTestFactory* factory_; static void SetUpTestCase() { factory_ = new MockDeathTestFactory; replacer_ = new testing::internal::ReplaceDeathTestFactory(factory_); } static void TearDownTestCase() { delete replacer_; replacer_ = NULL; delete factory_; factory_ = NULL; } // Runs a death test that breaks the rules by returning. Such a death // test cannot be run directly from a test routine that uses a // MockDeathTest, or the remainder of the routine will not be executed. static void RunReturningDeathTest(bool* flag) { ASSERT_DEATH({ // NOLINT *flag = true; return; }, ""); } }; testing::internal::ReplaceDeathTestFactory* MacroLogicDeathTest::replacer_ = NULL; MockDeathTestFactory* MacroLogicDeathTest::factory_ = NULL; // Test that nothing happens when the factory doesn't return a DeathTest: TEST_F(MacroLogicDeathTest, NothingHappens) { bool flag = false; factory_->SetParameters(false, DeathTest::OVERSEE_TEST, 0, true); EXPECT_DEATH(flag = true, ""); EXPECT_FALSE(flag); EXPECT_EQ(0, factory_->AssumeRoleCalls()); EXPECT_EQ(0, factory_->WaitCalls()); EXPECT_EQ(0, factory_->PassedCalls()); EXPECT_EQ(0, factory_->AbortCalls()); EXPECT_FALSE(factory_->TestDeleted()); } // Test that the parent process doesn't run the death test code, // and that the Passed method returns false when the (simulated) // child process exits with status 0: TEST_F(MacroLogicDeathTest, ChildExitsSuccessfully) { bool flag = false; factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 0, true); EXPECT_DEATH(flag = true, ""); EXPECT_FALSE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(1, factory_->WaitCalls()); ASSERT_EQ(1, factory_->PassedCalls()); EXPECT_FALSE(factory_->PassedArgument(0)); EXPECT_EQ(0, factory_->AbortCalls()); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that the Passed method was given the argument "true" when // the (simulated) child process exits with status 1: TEST_F(MacroLogicDeathTest, ChildExitsUnsuccessfully) { bool flag = false; factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 1, true); EXPECT_DEATH(flag = true, ""); EXPECT_FALSE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(1, factory_->WaitCalls()); ASSERT_EQ(1, factory_->PassedCalls()); EXPECT_TRUE(factory_->PassedArgument(0)); EXPECT_EQ(0, factory_->AbortCalls()); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that the (simulated) child process executes the death test // code, and is aborted with the correct AbortReason if it // executes a return statement. TEST_F(MacroLogicDeathTest, ChildPerformsReturn) { bool flag = false; factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); RunReturningDeathTest(&flag); EXPECT_TRUE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(0, factory_->WaitCalls()); EXPECT_EQ(0, factory_->PassedCalls()); EXPECT_EQ(1, factory_->AbortCalls()); EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, factory_->AbortArgument(0)); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that the (simulated) child process is aborted with the // correct AbortReason if it does not die. TEST_F(MacroLogicDeathTest, ChildDoesNotDie) { bool flag = false; factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); EXPECT_DEATH(flag = true, ""); EXPECT_TRUE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(0, factory_->WaitCalls()); EXPECT_EQ(0, factory_->PassedCalls()); // This time there are two calls to Abort: one since the test didn't // die, and another from the ReturnSentinel when it's destroyed. The // sentinel normally isn't destroyed if a test doesn't die, since // _exit(2) is called in that case by ForkingDeathTest, but not by // our MockDeathTest. ASSERT_EQ(2, factory_->AbortCalls()); EXPECT_EQ(DeathTest::TEST_DID_NOT_DIE, factory_->AbortArgument(0)); EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, factory_->AbortArgument(1)); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that a successful death test does not register a successful // test part. TEST(SuccessRegistrationDeathTest, NoSuccessPart) { EXPECT_DEATH(_exit(1), ""); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } TEST(StreamingAssertionsDeathTest, DeathTest) { EXPECT_DEATH(_exit(1), "") << "unexpected failure"; ASSERT_DEATH(_exit(1), "") << "unexpected failure"; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_DEATH(_exit(0), "") << "expected failure"; }, "expected failure"); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_DEATH(_exit(0), "") << "expected failure"; }, "expected failure"); } // Tests that GetLastErrnoDescription returns an empty string when the // last error is 0 and non-empty string when it is non-zero. TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks) { errno = ENOENT; EXPECT_STRNE("", GetLastErrnoDescription().c_str()); errno = 0; EXPECT_STREQ("", GetLastErrnoDescription().c_str()); } #if GTEST_OS_WINDOWS TEST(AutoHandleTest, AutoHandleWorks) { HANDLE handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); ASSERT_NE(INVALID_HANDLE_VALUE, handle); // Tests that the AutoHandle is correctly initialized with a handle. testing::internal::AutoHandle auto_handle(handle); EXPECT_EQ(handle, auto_handle.Get()); // Tests that Reset assigns INVALID_HANDLE_VALUE. // Note that this cannot verify whether the original handle is closed. auto_handle.Reset(); EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle.Get()); // Tests that Reset assigns the new handle. // Note that this cannot verify whether the original handle is closed. handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); ASSERT_NE(INVALID_HANDLE_VALUE, handle); auto_handle.Reset(handle); EXPECT_EQ(handle, auto_handle.Get()); // Tests that AutoHandle contains INVALID_HANDLE_VALUE by default. testing::internal::AutoHandle auto_handle2; EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle2.Get()); } #endif // GTEST_OS_WINDOWS #if GTEST_OS_WINDOWS typedef unsigned __int64 BiggestParsable; typedef signed __int64 BiggestSignedParsable; const BiggestParsable kBiggestParsableMax = ULLONG_MAX; const BiggestParsable kBiggestSignedParsableMax = LLONG_MAX; #else typedef unsigned long long BiggestParsable; typedef signed long long BiggestSignedParsable; const BiggestParsable kBiggestParsableMax = ::std::numeric_limits::max(); const BiggestSignedParsable kBiggestSignedParsableMax = ::std::numeric_limits::max(); #endif // GTEST_OS_WINDOWS TEST(ParseNaturalNumberTest, RejectsInvalidFormat) { BiggestParsable result = 0; // Rejects non-numbers. EXPECT_FALSE(ParseNaturalNumber(String("non-number string"), &result)); // Rejects numbers with whitespace prefix. EXPECT_FALSE(ParseNaturalNumber(String(" 123"), &result)); // Rejects negative numbers. EXPECT_FALSE(ParseNaturalNumber(String("-123"), &result)); // Rejects numbers starting with a plus sign. EXPECT_FALSE(ParseNaturalNumber(String("+123"), &result)); errno = 0; } TEST(ParseNaturalNumberTest, RejectsOverflownNumbers) { BiggestParsable result = 0; EXPECT_FALSE(ParseNaturalNumber(String("99999999999999999999999"), &result)); signed char char_result = 0; EXPECT_FALSE(ParseNaturalNumber(String("200"), &char_result)); errno = 0; } TEST(ParseNaturalNumberTest, AcceptsValidNumbers) { BiggestParsable result = 0; result = 0; ASSERT_TRUE(ParseNaturalNumber(String("123"), &result)); EXPECT_EQ(123U, result); // Check 0 as an edge case. result = 1; ASSERT_TRUE(ParseNaturalNumber(String("0"), &result)); EXPECT_EQ(0U, result); result = 1; ASSERT_TRUE(ParseNaturalNumber(String("00000"), &result)); EXPECT_EQ(0U, result); } TEST(ParseNaturalNumberTest, AcceptsTypeLimits) { Message msg; msg << kBiggestParsableMax; BiggestParsable result = 0; EXPECT_TRUE(ParseNaturalNumber(msg.GetString(), &result)); EXPECT_EQ(kBiggestParsableMax, result); Message msg2; msg2 << kBiggestSignedParsableMax; BiggestSignedParsable signed_result = 0; EXPECT_TRUE(ParseNaturalNumber(msg2.GetString(), &signed_result)); EXPECT_EQ(kBiggestSignedParsableMax, signed_result); Message msg3; msg3 << INT_MAX; int int_result = 0; EXPECT_TRUE(ParseNaturalNumber(msg3.GetString(), &int_result)); EXPECT_EQ(INT_MAX, int_result); Message msg4; msg4 << UINT_MAX; unsigned int uint_result = 0; EXPECT_TRUE(ParseNaturalNumber(msg4.GetString(), &uint_result)); EXPECT_EQ(UINT_MAX, uint_result); } TEST(ParseNaturalNumberTest, WorksForShorterIntegers) { short short_result = 0; ASSERT_TRUE(ParseNaturalNumber(String("123"), &short_result)); EXPECT_EQ(123, short_result); signed char char_result = 0; ASSERT_TRUE(ParseNaturalNumber(String("123"), &char_result)); EXPECT_EQ(123, char_result); } #if GTEST_OS_WINDOWS TEST(EnvironmentTest, HandleFitsIntoSizeT) { // TODO(vladl@google.com): Remove this test after this condition is verified // in a static assertion in gtest-death-test.cc in the function // GetStatusFileDescriptor. ASSERT_TRUE(sizeof(HANDLE) <= sizeof(size_t)); } #endif // GTEST_OS_WINDOWS // Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED trigger // failures when death tests are available on the system. TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable) { EXPECT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestExpectMacro"), "death inside CondDeathTestExpectMacro"); ASSERT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestAssertMacro"), "death inside CondDeathTestAssertMacro"); // Empty statement will not crash, which must trigger a failure. EXPECT_NONFATAL_FAILURE(EXPECT_DEATH_IF_SUPPORTED(;, ""), ""); EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(;, ""), ""); } #else using testing::internal::CaptureStderr; using testing::internal::GetCapturedStderr; using testing::internal::String; // Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still // defined but do not trigger failures when death tests are not available on // the system. TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) { // Empty statement will not crash, but that should not trigger a failure // when death tests are not supported. CaptureStderr(); EXPECT_DEATH_IF_SUPPORTED(;, ""); String output = GetCapturedStderr(); ASSERT_TRUE(NULL != strstr(output.c_str(), "Death tests are not supported on this platform")); ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); // The streamed message should not be printed as there is no test failure. CaptureStderr(); EXPECT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; output = GetCapturedStderr(); ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); CaptureStderr(); ASSERT_DEATH_IF_SUPPORTED(;, ""); // NOLINT output = GetCapturedStderr(); ASSERT_TRUE(NULL != strstr(output.c_str(), "Death tests are not supported on this platform")); ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); CaptureStderr(); ASSERT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; // NOLINT output = GetCapturedStderr(); ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); } void FuncWithAssert(int* n) { ASSERT_DEATH_IF_SUPPORTED(return;, ""); (*n)++; } // Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current // function (as ASSERT_DEATH does) if death tests are not supported. TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { int n = 0; FuncWithAssert(&n); EXPECT_EQ(1, n); } #endif // GTEST_HAS_DEATH_TEST // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. // // The syntax should work whether death tests are available or not. TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { if (AlwaysFalse()) // This would fail if executed; this is a compilation test only ASSERT_DEATH_IF_SUPPORTED(return, ""); if (AlwaysTrue()) EXPECT_DEATH_IF_SUPPORTED(_exit(1), ""); else // This empty "else" branch is meant to ensure that EXPECT_DEATH // doesn't expand into an "if" statement without an "else" ; // NOLINT if (AlwaysFalse()) ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die"; if (AlwaysFalse()) ; // NOLINT else EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; } // Tests that conditional death test macros expand to code which interacts // well with switch statements. TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { // Microsoft compiler usually complains about switch statements without // case labels. We suppress that warning for this test. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4065) #endif // _MSC_VER switch (0) default: ASSERT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in default switch handler"; switch (0) case 0: EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case"; #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER } // Tests that a test case whose name ends with "DeathTest" works fine // on Windows. TEST(NotADeathTest, Test) { SUCCEED(); } ceph-0.80.11/src/gtest/test/gtest_help_test.py0000775000175100017510000001320012623076744023337 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2009, Google Inc. # 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. """Tests the --help flag of Google C++ Testing Framework. SYNOPSIS gtest_help_test.py --gtest_build_dir=BUILD/DIR # where BUILD/DIR contains the built gtest_help_test_ file. gtest_help_test.py """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import gtest_test_utils IS_WINDOWS = os.name == 'nt' PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_') FLAG_PREFIX = '--gtest_' CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions' DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style' UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing' LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG), re.sub('^--', '/', LIST_TESTS_FLAG), re.sub('_', '-', LIST_TESTS_FLAG)] INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing' SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess( [PROGRAM_PATH, LIST_TESTS_FLAG]).output # The help message must match this regex. HELP_REGEX = re.compile( FLAG_PREFIX + r'list_tests.*' + FLAG_PREFIX + r'filter=.*' + FLAG_PREFIX + r'also_run_disabled_tests.*' + FLAG_PREFIX + r'repeat=.*' + FLAG_PREFIX + r'shuffle.*' + FLAG_PREFIX + r'random_seed=.*' + FLAG_PREFIX + r'color=.*' + FLAG_PREFIX + r'print_time.*' + FLAG_PREFIX + r'output=.*' + FLAG_PREFIX + r'break_on_failure.*' + FLAG_PREFIX + r'throw_on_failure.*', re.DOTALL) def RunWithFlag(flag): """Runs gtest_help_test_ with the given flag. Returns: the exit code and the text output as a tuple. Args: flag: the command-line flag to pass to gtest_help_test_, or None. """ if flag is None: command = [PROGRAM_PATH] else: command = [PROGRAM_PATH, flag] child = gtest_test_utils.Subprocess(command) return child.exit_code, child.output class GTestHelpTest(gtest_test_utils.TestCase): """Tests the --help flag and its equivalent forms.""" def TestHelpFlag(self, flag): """Verifies correct behavior when help flag is specified. The right message must be printed and the tests must skipped when the given flag is specified. Args: flag: A flag to pass to the binary or None. """ exit_code, output = RunWithFlag(flag) self.assertEquals(0, exit_code) self.assert_(HELP_REGEX.search(output), output) if IS_WINDOWS: self.assert_(CATCH_EXCEPTIONS_FLAG in output, output) else: self.assert_(CATCH_EXCEPTIONS_FLAG not in output, output) if SUPPORTS_DEATH_TESTS and not IS_WINDOWS: self.assert_(DEATH_TEST_STYLE_FLAG in output, output) else: self.assert_(DEATH_TEST_STYLE_FLAG not in output, output) def TestNonHelpFlag(self, flag): """Verifies correct behavior when no help flag is specified. Verifies that when no help flag is specified, the tests are run and the help message is not printed. Args: flag: A flag to pass to the binary or None. """ exit_code, output = RunWithFlag(flag) self.assert_(exit_code != 0) self.assert_(not HELP_REGEX.search(output), output) def testPrintsHelpWithFullFlag(self): self.TestHelpFlag('--help') def testPrintsHelpWithShortFlag(self): self.TestHelpFlag('-h') def testPrintsHelpWithQuestionFlag(self): self.TestHelpFlag('-?') def testPrintsHelpWithWindowsStyleQuestionFlag(self): self.TestHelpFlag('/?') def testPrintsHelpWithUnrecognizedGoogleTestFlag(self): self.TestHelpFlag(UNKNOWN_FLAG) def testPrintsHelpWithIncorrectFlagStyle(self): for incorrect_flag in INCORRECT_FLAG_VARIANTS: self.TestHelpFlag(incorrect_flag) def testRunsTestsWithoutHelpFlag(self): """Verifies that when no help flag is specified, the tests are run and the help message is not printed.""" self.TestNonHelpFlag(None) def testRunsTestsWithGtestInternalFlag(self): """Verifies that the tests are run and no help message is printed when a flag starting with Google Test prefix and 'internal_' is supplied.""" self.TestNonHelpFlag(INTERNAL_FLAG_FOR_TESTING) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_color_test_.cc0000664000175100017510000000551012623076744023623 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // A helper program for testing how Google Test determines whether to use // colors in the output. It prints "YES" and returns 1 if Google Test // decides to use colors, and prints "NO" and returns 0 otherwise. #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ using testing::internal::ShouldUseColor; // The purpose of this is to ensure that the UnitTest singleton is // created before main() is entered, and thus that ShouldUseColor() // works the same way as in a real Google-Test-based test. We don't actual // run the TEST itself. TEST(GTestColorTest, Dummy) { } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); if (ShouldUseColor(true)) { // Google Test decides to use colors in the output (assuming it // goes to a TTY). printf("YES\n"); return 1; } else { // Google Test decides not to use colors in the output. printf("NO\n"); return 0; } } ceph-0.80.11/src/gtest/test/gtest_environment_test.cc0000664000175100017510000001435512623076744024721 0ustar jenkins-buildjenkins-build// Copyright 2007, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Tests using global test environments. #include #include #include namespace testing { GTEST_DECLARE_string_(filter); } namespace { enum FailureType { NO_FAILURE, NON_FATAL_FAILURE, FATAL_FAILURE }; // For testing using global test environments. class MyEnvironment : public testing::Environment { public: MyEnvironment() { Reset(); } // Depending on the value of failure_in_set_up_, SetUp() will // generate a non-fatal failure, generate a fatal failure, or // succeed. virtual void SetUp() { set_up_was_run_ = true; switch (failure_in_set_up_) { case NON_FATAL_FAILURE: ADD_FAILURE() << "Expected non-fatal failure in global set-up."; break; case FATAL_FAILURE: FAIL() << "Expected fatal failure in global set-up."; break; default: break; } } // Generates a non-fatal failure. virtual void TearDown() { tear_down_was_run_ = true; ADD_FAILURE() << "Expected non-fatal failure in global tear-down."; } // Resets the state of the environment s.t. it can be reused. void Reset() { failure_in_set_up_ = NO_FAILURE; set_up_was_run_ = false; tear_down_was_run_ = false; } // We call this function to set the type of failure SetUp() should // generate. void set_failure_in_set_up(FailureType type) { failure_in_set_up_ = type; } // Was SetUp() run? bool set_up_was_run() const { return set_up_was_run_; } // Was TearDown() run? bool tear_down_was_run() const { return tear_down_was_run_; } private: FailureType failure_in_set_up_; bool set_up_was_run_; bool tear_down_was_run_; }; // Was the TEST run? bool test_was_run; // The sole purpose of this TEST is to enable us to check whether it // was run. TEST(FooTest, Bar) { test_was_run = true; } // Prints the message and aborts the program if condition is false. void Check(bool condition, const char* msg) { if (!condition) { printf("FAILED: %s\n", msg); abort(); } } // Runs the tests. Return true iff successful. // // The 'failure' parameter specifies the type of failure that should // be generated by the global set-up. int RunAllTests(MyEnvironment* env, FailureType failure) { env->Reset(); env->set_failure_in_set_up(failure); test_was_run = false; return RUN_ALL_TESTS(); } } // namespace int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); // Registers a global test environment, and verifies that the // registration function returns its argument. MyEnvironment* const env = new MyEnvironment; Check(testing::AddGlobalTestEnvironment(env) == env, "AddGlobalTestEnvironment() should return its argument."); // Verifies that RUN_ALL_TESTS() runs the tests when the global // set-up is successful. Check(RunAllTests(env, NO_FAILURE) != 0, "RUN_ALL_TESTS() should return non-zero, as the global tear-down " "should generate a failure."); Check(test_was_run, "The tests should run, as the global set-up should generate no " "failure"); Check(env->tear_down_was_run(), "The global tear-down should run, as the global set-up was run."); // Verifies that RUN_ALL_TESTS() runs the tests when the global // set-up generates no fatal failure. Check(RunAllTests(env, NON_FATAL_FAILURE) != 0, "RUN_ALL_TESTS() should return non-zero, as both the global set-up " "and the global tear-down should generate a non-fatal failure."); Check(test_was_run, "The tests should run, as the global set-up should generate no " "fatal failure."); Check(env->tear_down_was_run(), "The global tear-down should run, as the global set-up was run."); // Verifies that RUN_ALL_TESTS() runs no test when the global set-up // generates a fatal failure. Check(RunAllTests(env, FATAL_FAILURE) != 0, "RUN_ALL_TESTS() should return non-zero, as the global set-up " "should generate a fatal failure."); Check(!test_was_run, "The tests should not run, as the global set-up should generate " "a fatal failure."); Check(env->tear_down_was_run(), "The global tear-down should run, as the global set-up was run."); // Verifies that RUN_ALL_TESTS() doesn't do global set-up or // tear-down when there is no test to run. testing::GTEST_FLAG(filter) = "-*"; Check(RunAllTests(env, NO_FAILURE) == 0, "RUN_ALL_TESTS() should return zero, as there is no test to run."); Check(!env->set_up_was_run(), "The global set-up should not run, as there is no test to run."); Check(!env->tear_down_was_run(), "The global tear-down should not run, " "as the global set-up was not run."); printf("PASS\n"); return 0; } ceph-0.80.11/src/gtest/test/gtest_stress_test.cc0000664000175100017510000002266712623076744023705 0ustar jenkins-buildjenkins-build// Copyright 2007, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Tests that SCOPED_TRACE() and various Google Test assertions can be // used in a large number of threads concurrently. #include #include #include // We must define this macro in order to #include // gtest-internal-inl.h. This is how Google Test prevents a user from // accidentally depending on its internal implementation. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #if GTEST_IS_THREADSAFE namespace testing { namespace { using internal::Notification; using internal::String; using internal::TestPropertyKeyIs; using internal::ThreadWithParam; using internal::scoped_ptr; // In order to run tests in this file, for platforms where Google Test is // thread safe, implement ThreadWithParam. See the description of its API // in gtest-port.h, where it is defined for already supported platforms. // How many threads to create? const int kThreadCount = 50; String IdToKey(int id, const char* suffix) { Message key; key << "key_" << id << "_" << suffix; return key.GetString(); } String IdToString(int id) { Message id_message; id_message << id; return id_message.GetString(); } void ExpectKeyAndValueWereRecordedForId( const std::vector& properties, int id, const char* suffix) { TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str()); const std::vector::const_iterator property = std::find_if(properties.begin(), properties.end(), matches_key); ASSERT_TRUE(property != properties.end()) << "expecting " << suffix << " value for id " << id; EXPECT_STREQ(IdToString(id).c_str(), property->value()); } // Calls a large number of Google Test assertions, where exactly one of them // will fail. void ManyAsserts(int id) { GTEST_LOG_(INFO) << "Thread #" << id << " running..."; SCOPED_TRACE(Message() << "Thread #" << id); for (int i = 0; i < kThreadCount; i++) { SCOPED_TRACE(Message() << "Iteration #" << i); // A bunch of assertions that should succeed. EXPECT_TRUE(true); ASSERT_FALSE(false) << "This shouldn't fail."; EXPECT_STREQ("a", "a"); ASSERT_LE(5, 6); EXPECT_EQ(i, i) << "This shouldn't fail."; // RecordProperty() should interact safely with other threads as well. // The shared_key forces property updates. Test::RecordProperty(IdToKey(id, "string").c_str(), IdToString(id).c_str()); Test::RecordProperty(IdToKey(id, "int").c_str(), id); Test::RecordProperty("shared_key", IdToString(id).c_str()); // This assertion should fail kThreadCount times per thread. It // is for testing whether Google Test can handle failed assertions in a // multi-threaded context. EXPECT_LT(i, 0) << "This should always fail."; } } void CheckTestFailureCount(int expected_failures) { const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); const TestResult* const result = info->result(); GTEST_CHECK_(expected_failures == result->total_part_count()) << "Logged " << result->total_part_count() << " failures " << " vs. " << expected_failures << " expected"; } // Tests using SCOPED_TRACE() and Google Test assertions in many threads // concurrently. TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { { scoped_ptr > threads[kThreadCount]; Notification threads_can_start; for (int i = 0; i != kThreadCount; i++) threads[i].reset(new ThreadWithParam(&ManyAsserts, i, &threads_can_start)); threads_can_start.Notify(); // Blocks until all the threads are done. for (int i = 0; i != kThreadCount; i++) threads[i]->Join(); } // Ensures that kThreadCount*kThreadCount failures have been reported. const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); const TestResult* const result = info->result(); std::vector properties; // We have no access to the TestResult's list of properties but we can // copy them one by one. for (int i = 0; i < result->test_property_count(); ++i) properties.push_back(result->GetTestProperty(i)); EXPECT_EQ(kThreadCount * 2 + 1, result->test_property_count()) << "String and int values recorded on each thread, " << "as well as one shared_key"; for (int i = 0; i < kThreadCount; ++i) { ExpectKeyAndValueWereRecordedForId(properties, i, "string"); ExpectKeyAndValueWereRecordedForId(properties, i, "int"); } CheckTestFailureCount(kThreadCount*kThreadCount); } void FailingThread(bool is_fatal) { if (is_fatal) FAIL() << "Fatal failure in some other thread. " << "(This failure is expected.)"; else ADD_FAILURE() << "Non-fatal failure in some other thread. " << "(This failure is expected.)"; } void GenerateFatalFailureInAnotherThread(bool is_fatal) { ThreadWithParam thread(&FailingThread, is_fatal, NULL); thread.Join(); } TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads) { EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); // We should only have one failure (the one from // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE // should succeed. CheckTestFailureCount(1); } void AssertNoFatalFailureIgnoresFailuresInOtherThreads() { ASSERT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); } TEST(NoFatalFailureTest, AssertNoFatalFailureIgnoresFailuresInOtherThreads) { // Using a subroutine, to make sure, that the test continues. AssertNoFatalFailureIgnoresFailuresInOtherThreads(); // We should only have one failure (the one from // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE // should succeed. CheckTestFailureCount(1); } TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads) { // This statement should fail, since the current thread doesn't generate a // fatal failure, only another one does. EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected"); CheckTestFailureCount(2); } TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads) { // This statement should succeed, because failures in all threads are // considered. EXPECT_FATAL_FAILURE_ON_ALL_THREADS( GenerateFatalFailureInAnotherThread(true), "expected"); CheckTestFailureCount(0); // We need to add a failure, because main() checks that there are failures. // But when only this test is run, we shouldn't have any failures. ADD_FAILURE() << "This is an expected non-fatal failure."; } TEST(NonFatalFailureTest, ExpectNonFatalFailureIgnoresFailuresInOtherThreads) { // This statement should fail, since the current thread doesn't generate a // fatal failure, only another one does. EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false), "expected"); CheckTestFailureCount(2); } TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) { // This statement should succeed, because failures in all threads are // considered. EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( GenerateFatalFailureInAnotherThread(false), "expected"); CheckTestFailureCount(0); // We need to add a failure, because main() checks that there are failures, // But when only this test is run, we shouldn't have any failures. ADD_FAILURE() << "This is an expected non-fatal failure."; } } // namespace } // namespace testing int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); const int result = RUN_ALL_TESTS(); // Expected to fail. GTEST_CHECK_(result == 1) << "RUN_ALL_TESTS() did not fail as expected"; printf("\nPASS\n"); return 0; } #else TEST(StressTest, DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe) { } int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } #endif // GTEST_IS_THREADSAFE ceph-0.80.11/src/gtest/test/gtest_output_test_golden_lin.txt0000664000175100017510000006440512623076744026342 0ustar jenkins-buildjenkins-buildThe non-test part of the code is expected to have 2 failures. gtest_output_test_.cc:#: Failure Value of: false Actual: false Expected: true gtest_output_test_.cc:#: Failure Value of: 3 Expected: 2 [==========] Running 60 tests from 25 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. [----------] 1 test from ADeathTest [ RUN ] ADeathTest.ShouldRunFirst [ OK ] ADeathTest.ShouldRunFirst [----------] 1 test from ATypedDeathTest/0, where TypeParam = int [ RUN ] ATypedDeathTest/0.ShouldRunFirst [ OK ] ATypedDeathTest/0.ShouldRunFirst [----------] 1 test from ATypedDeathTest/1, where TypeParam = double [ RUN ] ATypedDeathTest/1.ShouldRunFirst [ OK ] ATypedDeathTest/1.ShouldRunFirst [----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int [ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst [ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst [----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double [ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst [ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst [----------] 2 tests from PassingTest [ RUN ] PassingTest.PassingTest1 [ OK ] PassingTest.PassingTest1 [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ RUN ] FatalFailureTest.NonfatalFailureInSubroutine (expecting a failure on false) gtest_output_test_.cc:#: Failure Value of: false Actual: false Expected: true [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [----------] 1 test from LoggingTest [ RUN ] LoggingTest.InterleavingLoggingAndAssertions (expecting 2 failures on (3) >= (a[i])) i == 0 i == 1 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 9 i == 2 i == 3 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 6 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [----------] 6 tests from SCOPED_TRACETest [ RUN ] SCOPED_TRACETest.ObeysScopes (expected to fail) gtest_output_test_.cc:#: Failure Failed This failure is expected, and shouldn't have a trace. gtest_output_test_.cc:#: Failure Failed This failure is expected, and should have a trace. Google Test trace: gtest_output_test_.cc:#: Expected trace gtest_output_test_.cc:#: Failure Failed This failure is expected, and shouldn't have a trace. [ FAILED ] SCOPED_TRACETest.ObeysScopes [ RUN ] SCOPED_TRACETest.WorksInLoop (expected to fail) gtest_output_test_.cc:#: Failure Value of: n Actual: 1 Expected: 2 Google Test trace: gtest_output_test_.cc:#: i = 1 gtest_output_test_.cc:#: Failure Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: i = 2 [ FAILED ] SCOPED_TRACETest.WorksInLoop [ RUN ] SCOPED_TRACETest.WorksInSubroutine (expected to fail) gtest_output_test_.cc:#: Failure Value of: n Actual: 1 Expected: 2 Google Test trace: gtest_output_test_.cc:#: n = 1 gtest_output_test_.cc:#: Failure Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: n = 2 [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ RUN ] SCOPED_TRACETest.CanBeNested (expected to fail) gtest_output_test_.cc:#: Failure Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: n = 2 gtest_output_test_.cc:#: [ FAILED ] SCOPED_TRACETest.CanBeNested [ RUN ] SCOPED_TRACETest.CanBeRepeated (expected to fail) gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A. Google Test trace: gtest_output_test_.cc:#: A gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A and B. Google Test trace: gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A, B, and C. Google Test trace: gtest_output_test_.cc:#: C gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A, B, and D. Google Test trace: gtest_output_test_.cc:#: D gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A [ FAILED ] SCOPED_TRACETest.CanBeRepeated [ RUN ] SCOPED_TRACETest.WorksConcurrently (expecting 6 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1 (in thread B, only trace B alive). Google Test trace: gtest_output_test_.cc:#: Trace B gtest_output_test_.cc:#: Failure Failed Expected failure #2 (in thread A, trace A & B both alive). Google Test trace: gtest_output_test_.cc:#: Trace A gtest_output_test_.cc:#: Failure Failed Expected failure #3 (in thread B, trace A & B both alive). Google Test trace: gtest_output_test_.cc:#: Trace B gtest_output_test_.cc:#: Failure Failed Expected failure #4 (in thread B, only trace A alive). gtest_output_test_.cc:#: Failure Failed Expected failure #5 (in thread A, only trace A alive). Google Test trace: gtest_output_test_.cc:#: Trace A gtest_output_test_.cc:#: Failure Failed Expected failure #6 (in thread A, no trace alive). [ FAILED ] SCOPED_TRACETest.WorksConcurrently [----------] 1 test from NonFatalFailureInFixtureConstructorTest [ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 5 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in the test fixture c'tor. gtest_output_test_.cc:#: Failure Failed Expected failure #2, in SetUp(). gtest_output_test_.cc:#: Failure Failed Expected failure #3, in the test body. gtest_output_test_.cc:#: Failure Failed Expected failure #4, in TearDown. gtest_output_test_.cc:#: Failure Failed Expected failure #5, in the test fixture d'tor. [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [----------] 1 test from FatalFailureInFixtureConstructorTest [ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in the test fixture c'tor. gtest_output_test_.cc:#: Failure Failed Expected failure #2, in the test fixture d'tor. [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [----------] 1 test from NonFatalFailureInSetUpTest [ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp (expecting 4 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in SetUp(). gtest_output_test_.cc:#: Failure Failed Expected failure #2, in the test function. gtest_output_test_.cc:#: Failure Failed Expected failure #3, in TearDown(). gtest_output_test_.cc:#: Failure Failed Expected failure #4, in the test fixture d'tor. [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [----------] 1 test from FatalFailureInSetUpTest [ RUN ] FatalFailureInSetUpTest.FailureInSetUp (expecting 3 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in SetUp(). gtest_output_test_.cc:#: Failure Failed Expected failure #2, in TearDown(). gtest_output_test_.cc:#: Failure Failed Expected failure #3, in the test fixture d'tor. [ FAILED ] FatalFailureInSetUpTest.FailureInSetUp [----------] 4 tests from MixedUpTestCaseTest [ RUN ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo [ OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo [ RUN ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo [ OK ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo [ RUN ] MixedUpTestCaseTest.ThisShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseTest, you defined test FirstTestFromNamespaceFoo and test ThisShouldFail using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseTest.ThisShouldFail [ RUN ] MixedUpTestCaseTest.ThisShouldFailToo gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseTest, you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo [----------] 2 tests from MixedUpTestCaseWithSameTestNameTest [ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ OK ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseWithSameTestNameTest, you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [----------] 2 tests from TEST_F_before_TEST_in_same_test_case [ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F [ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F [ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class, so mixing TEST_F and TEST in the same test case is illegal. In test case TEST_F_before_TEST_in_same_test_case, test DefinedUsingTEST_F is defined using TEST_F but test DefinedUsingTESTAndShouldFail is defined using TEST. You probably want to change the TEST to TEST_F or move it to another test case. [ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail [----------] 2 tests from TEST_before_TEST_F_in_same_test_case [ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST [ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST [ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class, so mixing TEST_F and TEST in the same test case is illegal. In test case TEST_before_TEST_F_in_same_test_case, test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but test DefinedUsingTEST is defined using TEST. You probably want to change the TEST to TEST_F or move it to another test case. [ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail [----------] 8 tests from ExpectNonfatalFailureTest [ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables [ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables [ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables [ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables [ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure [ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 2 failures gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure 1. gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure 2. [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns [ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows [----------] 8 tests from ExpectFatalFailureTest [ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables [ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables [ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables [ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables [ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure [ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 2 failures gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns [ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows [----------] 2 tests from TypedTest/0, where TypeParam = int [ RUN ] TypedTest/0.Success [ OK ] TypedTest/0.Success [ RUN ] TypedTest/0.Failure gtest_output_test_.cc:#: Failure Value of: TypeParam() Actual: 0 Expected: 1 Expected failure [ FAILED ] TypedTest/0.Failure [----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char [ RUN ] Unsigned/TypedTestP/0.Success [ OK ] Unsigned/TypedTestP/0.Success [ RUN ] Unsigned/TypedTestP/0.Failure gtest_output_test_.cc:#: Failure Value of: TypeParam() Actual: \0 Expected: 1U Which is: 1 Expected failure [ FAILED ] Unsigned/TypedTestP/0.Failure [----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int [ RUN ] Unsigned/TypedTestP/1.Success [ OK ] Unsigned/TypedTestP/1.Success [ RUN ] Unsigned/TypedTestP/1.Failure gtest_output_test_.cc:#: Failure Value of: TypeParam() Actual: 0 Expected: 1U Which is: 1 Expected failure [ FAILED ] Unsigned/TypedTestP/1.Failure [----------] 4 tests from ExpectFailureTest [ RUN ] ExpectFailureTest.ExpectFatalFailure (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure containing "Some other fatal failure expected." Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectFatalFailure [ RUN ] ExpectFailureTest.ExpectNonFatalFailure (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure containing "Some other non-fatal failure." Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure containing "Some other fatal failure expected." Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure containing "Some other non-fatal failure." Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads [----------] 2 tests from ExpectFailureWithThreadsTest [ RUN ] ExpectFailureWithThreadsTest.ExpectFatalFailure (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected fatal failure. gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure [ RUN ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected non-fatal failure. gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [----------] 1 test from ScopedFakeTestPartResultReporterTest [ RUN ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected fatal failure. gtest_output_test_.cc:#: Failure Failed Expected non-fatal failure. [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread [----------] Global test environment tear-down BarEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected non-fatal failure. FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. [==========] 60 tests from 25 test cases ran. [ PASSED ] 21 tests. [ FAILED ] 39 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [ FAILED ] SCOPED_TRACETest.ObeysScopes [ FAILED ] SCOPED_TRACETest.WorksInLoop [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ FAILED ] SCOPED_TRACETest.CanBeNested [ FAILED ] SCOPED_TRACETest.CanBeRepeated [ FAILED ] SCOPED_TRACETest.WorksConcurrently [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [ FAILED ] FatalFailureInSetUpTest.FailureInSetUp [ FAILED ] MixedUpTestCaseTest.ThisShouldFail [ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo [ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail [ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows [ FAILED ] TypedTest/0.Failure, where TypeParam = int [ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char [ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int [ FAILED ] ExpectFailureTest.ExpectFatalFailure [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads [ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread 39 FAILED TESTS  YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.* [==========] Running 4 tests from 2 test cases. [----------] Global test environment set-up. [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms) [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms) [ RUN ] FatalFailureTest.NonfatalFailureInSubroutine (expecting a failure on false) gtest_output_test_.cc:#: Failure Value of: false Actual: false Expected: true [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms) [----------] 3 tests from FatalFailureTest (? ms total) [----------] 1 test from LoggingTest [ RUN ] LoggingTest.InterleavingLoggingAndAssertions (expecting 2 failures on (3) >= (a[i])) i == 0 i == 1 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 9 i == 2 i == 3 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 6 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms) [----------] 1 test from LoggingTest (? ms total) [----------] Global test environment tear-down [==========] 4 tests from 2 test cases ran. (? ms total) [ PASSED ] 0 tests. [ FAILED ] 4 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions 4 FAILED TESTS YOU HAVE 1 DISABLED TEST Note: Google Test filter = *DISABLED_* [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from DisabledTestsWarningTest [ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning [ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. Note: Google Test filter = PassingTest.* Note: This is test shard 1 of 2. [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from PassingTest [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. YOU HAVE 1 DISABLED TEST ceph-0.80.11/src/gtest/test/gtest-filepath_test.cc0000664000175100017510000005706612623076744024075 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Authors: keith.ray@gmail.com (Keith Ray) // // Google Test filepath utilities // // This file tests classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included from gtest_unittest.cc, to avoid changing // build or make-files for some existing Google Test clients. Do not // #include this file anywhere else! #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS_MOBILE #include // NOLINT #elif GTEST_OS_WINDOWS #include // NOLINT #endif // GTEST_OS_WINDOWS_MOBILE namespace testing { namespace internal { namespace { #if GTEST_OS_WINDOWS_MOBILE // TODO(wan@google.com): Move these to the POSIX adapter section in // gtest-port.h. // Windows CE doesn't have the remove C function. int remove(const char* path) { LPCWSTR wpath = String::AnsiToUtf16(path); int ret = DeleteFile(wpath) ? 0 : -1; delete [] wpath; return ret; } // Windows CE doesn't have the _rmdir C function. int _rmdir(const char* path) { FilePath filepath(path); LPCWSTR wpath = String::AnsiToUtf16( filepath.RemoveTrailingPathSeparator().c_str()); int ret = RemoveDirectory(wpath) ? 0 : -1; delete [] wpath; return ret; } #else TEST(GetCurrentDirTest, ReturnsCurrentDir) { const FilePath original_dir = FilePath::GetCurrentDir(); EXPECT_FALSE(original_dir.IsEmpty()); posix::ChDir(GTEST_PATH_SEP_); const FilePath cwd = FilePath::GetCurrentDir(); posix::ChDir(original_dir.c_str()); #if GTEST_OS_WINDOWS // Skips the ":". const char* const cwd_without_drive = strchr(cwd.c_str(), ':'); ASSERT_TRUE(cwd_without_drive != NULL); EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1); #else EXPECT_STREQ(GTEST_PATH_SEP_, cwd.c_str()); #endif } #endif // GTEST_OS_WINDOWS_MOBILE TEST(IsEmptyTest, ReturnsTrueForEmptyPath) { EXPECT_TRUE(FilePath("").IsEmpty()); EXPECT_TRUE(FilePath(NULL).IsEmpty()); } TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) { EXPECT_FALSE(FilePath("a").IsEmpty()); EXPECT_FALSE(FilePath(".").IsEmpty()); EXPECT_FALSE(FilePath("a/b").IsEmpty()); EXPECT_FALSE(FilePath("a\\b\\").IsEmpty()); } // RemoveDirectoryName "" -> "" TEST(RemoveDirectoryNameTest, WhenEmptyName) { EXPECT_STREQ("", FilePath("").RemoveDirectoryName().c_str()); } // RemoveDirectoryName "afile" -> "afile" TEST(RemoveDirectoryNameTest, ButNoDirectory) { EXPECT_STREQ("afile", FilePath("afile").RemoveDirectoryName().c_str()); } // RemoveDirectoryName "/afile" -> "afile" TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) { EXPECT_STREQ("afile", FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().c_str()); } // RemoveDirectoryName "adir/" -> "" TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) { EXPECT_STREQ("", FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().c_str()); } // RemoveDirectoryName "adir/afile" -> "afile" TEST(RemoveDirectoryNameTest, ShouldGiveFileName) { EXPECT_STREQ("afile", FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().c_str()); } // RemoveDirectoryName "adir/subdir/afile" -> "afile" TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { EXPECT_STREQ("afile", FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") .RemoveDirectoryName().c_str()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that RemoveDirectoryName() works with the alternate separator // on Windows. // RemoveDirectoryName("/afile") -> "afile" TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) { EXPECT_STREQ("afile", FilePath("/afile").RemoveDirectoryName().c_str()); } // RemoveDirectoryName("adir/") -> "" TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) { EXPECT_STREQ("", FilePath("adir/").RemoveDirectoryName().c_str()); } // RemoveDirectoryName("adir/afile") -> "afile" TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) { EXPECT_STREQ("afile", FilePath("adir/afile").RemoveDirectoryName().c_str()); } // RemoveDirectoryName("adir/subdir/afile") -> "afile" TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) { EXPECT_STREQ("afile", FilePath("adir/subdir/afile").RemoveDirectoryName().c_str()); } #endif // RemoveFileName "" -> "./" TEST(RemoveFileNameTest, EmptyName) { #if GTEST_OS_WINDOWS_MOBILE // On Windows CE, we use the root as the current directory. EXPECT_STREQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().c_str()); #else EXPECT_STREQ("." GTEST_PATH_SEP_, FilePath("").RemoveFileName().c_str()); #endif } // RemoveFileName "adir/" -> "adir/" TEST(RemoveFileNameTest, ButNoFile) { EXPECT_STREQ("adir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().c_str()); } // RemoveFileName "adir/afile" -> "adir/" TEST(RemoveFileNameTest, GivesDirName) { EXPECT_STREQ("adir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_ "afile") .RemoveFileName().c_str()); } // RemoveFileName "adir/subdir/afile" -> "adir/subdir/" TEST(RemoveFileNameTest, GivesDirAndSubDirName) { EXPECT_STREQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") .RemoveFileName().c_str()); } // RemoveFileName "/afile" -> "/" TEST(RemoveFileNameTest, GivesRootDir) { EXPECT_STREQ(GTEST_PATH_SEP_, FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().c_str()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that RemoveFileName() works with the alternate separator on // Windows. // RemoveFileName("adir/") -> "adir/" TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) { EXPECT_STREQ("adir" GTEST_PATH_SEP_, FilePath("adir/").RemoveFileName().c_str()); } // RemoveFileName("adir/afile") -> "adir/" TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) { EXPECT_STREQ("adir" GTEST_PATH_SEP_, FilePath("adir/afile").RemoveFileName().c_str()); } // RemoveFileName("adir/subdir/afile") -> "adir/subdir/" TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) { EXPECT_STREQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, FilePath("adir/subdir/afile").RemoveFileName().c_str()); } // RemoveFileName("/afile") -> "\" TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) { EXPECT_STREQ(GTEST_PATH_SEP_, FilePath("/afile").RemoveFileName().c_str()); } #endif TEST(MakeFileNameTest, GenerateWhenNumberIsZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), 0, "xml"); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); } TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), 12, "xml"); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.c_str()); } TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar"), 0, "xml"); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); } TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar"), 12, "xml"); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.c_str()); } TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) { FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), 0, "xml"); EXPECT_STREQ("bar.xml", actual.c_str()); } TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) { FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), 14, "xml"); EXPECT_STREQ("bar_14.xml", actual.c_str()); } TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("bar.xml")); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); } TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar.xml")); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); } TEST(ConcatPathsTest, Path1BeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath(""), FilePath("bar.xml")); EXPECT_STREQ("bar.xml", actual.c_str()); } TEST(ConcatPathsTest, Path2BeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("")); EXPECT_STREQ("foo" GTEST_PATH_SEP_, actual.c_str()); } TEST(ConcatPathsTest, BothPathBeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath(""), FilePath("")); EXPECT_STREQ("", actual.c_str()); } TEST(ConcatPathsTest, Path1ContainsPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"), FilePath("foobar.xml")); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml", actual.c_str()); } TEST(ConcatPathsTest, Path2ContainsPathSep) { FilePath actual = FilePath::ConcatPaths( FilePath("foo" GTEST_PATH_SEP_), FilePath("bar" GTEST_PATH_SEP_ "bar.xml")); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml", actual.c_str()); } TEST(ConcatPathsTest, Path2EndsWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("bar" GTEST_PATH_SEP_)); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.c_str()); } // RemoveTrailingPathSeparator "" -> "" TEST(RemoveTrailingPathSeparatorTest, EmptyString) { EXPECT_STREQ("", FilePath("").RemoveTrailingPathSeparator().c_str()); } // RemoveTrailingPathSeparator "foo" -> "foo" TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) { EXPECT_STREQ("foo", FilePath("foo").RemoveTrailingPathSeparator().c_str()); } // RemoveTrailingPathSeparator "foo/" -> "foo" TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) { EXPECT_STREQ( "foo", FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().c_str()); #if GTEST_HAS_ALT_PATH_SEP_ EXPECT_STREQ("foo", FilePath("foo/").RemoveTrailingPathSeparator().c_str()); #endif } // RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/" TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) { EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_) .RemoveTrailingPathSeparator().c_str()); } // RemoveTrailingPathSeparator "foo/bar" -> "foo/bar" TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) { EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar") .RemoveTrailingPathSeparator().c_str()); } TEST(DirectoryTest, RootDirectoryExists) { #if GTEST_OS_WINDOWS // We are on Windows. char current_drive[_MAX_PATH]; // NOLINT current_drive[0] = static_cast(_getdrive() + 'A' - 1); current_drive[1] = ':'; current_drive[2] = '\\'; current_drive[3] = '\0'; EXPECT_TRUE(FilePath(current_drive).DirectoryExists()); #else EXPECT_TRUE(FilePath("/").DirectoryExists()); #endif // GTEST_OS_WINDOWS } #if GTEST_OS_WINDOWS TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) { const int saved_drive_ = _getdrive(); // Find a drive that doesn't exist. Start with 'Z' to avoid common ones. for (char drive = 'Z'; drive >= 'A'; drive--) if (_chdrive(drive - 'A' + 1) == -1) { char non_drive[_MAX_PATH]; // NOLINT non_drive[0] = drive; non_drive[1] = ':'; non_drive[2] = '\\'; non_drive[3] = '\0'; EXPECT_FALSE(FilePath(non_drive).DirectoryExists()); break; } _chdrive(saved_drive_); } #endif // GTEST_OS_WINDOWS #if !GTEST_OS_WINDOWS_MOBILE // Windows CE _does_ consider an empty directory to exist. TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) { EXPECT_FALSE(FilePath("").DirectoryExists()); } #endif // !GTEST_OS_WINDOWS_MOBILE TEST(DirectoryTest, CurrentDirectoryExists) { #if GTEST_OS_WINDOWS // We are on Windows. #ifndef _WIN32_CE // Windows CE doesn't have a current directory. EXPECT_TRUE(FilePath(".").DirectoryExists()); EXPECT_TRUE(FilePath(".\\").DirectoryExists()); #endif // _WIN32_CE #else EXPECT_TRUE(FilePath(".").DirectoryExists()); EXPECT_TRUE(FilePath("./").DirectoryExists()); #endif // GTEST_OS_WINDOWS } TEST(NormalizeTest, NullStringsEqualEmptyDirectory) { EXPECT_STREQ("", FilePath(NULL).c_str()); EXPECT_STREQ("", FilePath(String(NULL)).c_str()); } // "foo/bar" == foo//bar" == "foo///bar" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) { EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar").c_str()); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); } // "/bar" == //bar" == "///bar" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) { EXPECT_STREQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ "bar").c_str()); EXPECT_STREQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); EXPECT_STREQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str()); } // "foo/" == foo//" == "foo///" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) { EXPECT_STREQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_).c_str()); EXPECT_STREQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).c_str()); EXPECT_STREQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).c_str()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that separators at the end of the string are normalized // regardless of their combination (e.g. "foo\" =="foo/\" == // "foo\\/"). TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd) { EXPECT_STREQ("foo" GTEST_PATH_SEP_, FilePath("foo/").c_str()); EXPECT_STREQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ "/").c_str()); EXPECT_STREQ("foo" GTEST_PATH_SEP_, FilePath("foo//" GTEST_PATH_SEP_).c_str()); } #endif TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) { FilePath default_path; FilePath non_default_path("path"); non_default_path = default_path; EXPECT_STREQ("", non_default_path.c_str()); EXPECT_STREQ("", default_path.c_str()); // RHS var is unchanged. } TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) { FilePath non_default_path("path"); FilePath default_path; default_path = non_default_path; EXPECT_STREQ("path", default_path.c_str()); EXPECT_STREQ("path", non_default_path.c_str()); // RHS var is unchanged. } TEST(AssignmentOperatorTest, ConstAssignedToNonConst) { const FilePath const_default_path("const_path"); FilePath non_default_path("path"); non_default_path = const_default_path; EXPECT_STREQ("const_path", non_default_path.c_str()); } class DirectoryCreationTest : public Test { protected: virtual void SetUp() { testdata_path_.Set(FilePath(String::Format("%s%s%s", TempDir().c_str(), GetCurrentExecutableName().c_str(), "_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_))); testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator()); unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), 0, "txt")); unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), 1, "txt")); remove(testdata_file_.c_str()); remove(unique_file0_.c_str()); remove(unique_file1_.c_str()); posix::RmDir(testdata_path_.c_str()); } virtual void TearDown() { remove(testdata_file_.c_str()); remove(unique_file0_.c_str()); remove(unique_file1_.c_str()); posix::RmDir(testdata_path_.c_str()); } String TempDir() const { #if GTEST_OS_WINDOWS_MOBILE return String("\\temp\\"); #elif GTEST_OS_WINDOWS const char* temp_dir = posix::GetEnv("TEMP"); if (temp_dir == NULL || temp_dir[0] == '\0') return String("\\temp\\"); else if (String(temp_dir).EndsWith("\\")) return String(temp_dir); else return String::Format("%s\\", temp_dir); #else return String("/tmp/"); #endif // GTEST_OS_WINDOWS_MOBILE } void CreateTextFile(const char* filename) { FILE* f = posix::FOpen(filename, "w"); fprintf(f, "text\n"); fclose(f); } // Strings representing a directory and a file, with identical paths // except for the trailing separator character that distinquishes // a directory named 'test' from a file named 'test'. Example names: FilePath testdata_path_; // "/tmp/directory_creation/test/" FilePath testdata_file_; // "/tmp/directory_creation/test" FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt" FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt" }; TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively) { EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.c_str(); EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); EXPECT_TRUE(testdata_path_.DirectoryExists()); } TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) { EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.c_str(); EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); // Call 'create' again... should still succeed. EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); } TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename) { FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_, FilePath("unique"), "txt")); EXPECT_STREQ(unique_file0_.c_str(), file_path.c_str()); EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there testdata_path_.CreateDirectoriesRecursively(); EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there CreateTextFile(file_path.c_str()); EXPECT_TRUE(file_path.FileOrDirectoryExists()); FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_, FilePath("unique"), "txt")); EXPECT_STREQ(unique_file1_.c_str(), file_path2.c_str()); EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there CreateTextFile(file_path2.c_str()); EXPECT_TRUE(file_path2.FileOrDirectoryExists()); } TEST_F(DirectoryCreationTest, CreateDirectoriesFail) { // force a failure by putting a file where we will try to create a directory. CreateTextFile(testdata_file_.c_str()); EXPECT_TRUE(testdata_file_.FileOrDirectoryExists()); EXPECT_FALSE(testdata_file_.DirectoryExists()); EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively()); } TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile) { const FilePath test_detail_xml("test_detail.xml"); EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively()); } TEST(FilePathTest, DefaultConstructor) { FilePath fp; EXPECT_STREQ("", fp.c_str()); } TEST(FilePathTest, CharAndCopyConstructors) { const FilePath fp("spicy"); EXPECT_STREQ("spicy", fp.c_str()); const FilePath fp_copy(fp); EXPECT_STREQ("spicy", fp_copy.c_str()); } TEST(FilePathTest, StringConstructor) { const FilePath fp(String("cider")); EXPECT_STREQ("cider", fp.c_str()); } TEST(FilePathTest, Set) { const FilePath apple("apple"); FilePath mac("mac"); mac.Set(apple); // Implement Set() since overloading operator= is forbidden. EXPECT_STREQ("apple", mac.c_str()); EXPECT_STREQ("apple", apple.c_str()); } TEST(FilePathTest, ToString) { const FilePath file("drink"); String str(file.ToString()); EXPECT_STREQ("drink", str.c_str()); } TEST(FilePathTest, RemoveExtension) { EXPECT_STREQ("app", FilePath("app.exe").RemoveExtension("exe").c_str()); EXPECT_STREQ("APP", FilePath("APP.EXE").RemoveExtension("exe").c_str()); } TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) { EXPECT_STREQ("app", FilePath("app").RemoveExtension("exe").c_str()); } TEST(FilePathTest, IsDirectory) { EXPECT_FALSE(FilePath("cola").IsDirectory()); EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory()); #if GTEST_HAS_ALT_PATH_SEP_ EXPECT_TRUE(FilePath("koala/").IsDirectory()); #endif } TEST(FilePathTest, IsAbsolutePath) { EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); EXPECT_FALSE(FilePath("").IsAbsolutePath()); #if GTEST_OS_WINDOWS EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath()); EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); #else EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative") .IsAbsolutePath()); #endif // GTEST_OS_WINDOWS } TEST(FilePathTest, IsRootDirectory) { #if GTEST_OS_WINDOWS EXPECT_TRUE(FilePath("a:\\").IsRootDirectory()); EXPECT_TRUE(FilePath("Z:/").IsRootDirectory()); EXPECT_TRUE(FilePath("e://").IsRootDirectory()); EXPECT_FALSE(FilePath("").IsRootDirectory()); EXPECT_FALSE(FilePath("b:").IsRootDirectory()); EXPECT_FALSE(FilePath("b:a").IsRootDirectory()); EXPECT_FALSE(FilePath("8:/").IsRootDirectory()); EXPECT_FALSE(FilePath("c|/").IsRootDirectory()); #else EXPECT_TRUE(FilePath("/").IsRootDirectory()); EXPECT_TRUE(FilePath("//").IsRootDirectory()); EXPECT_FALSE(FilePath("").IsRootDirectory()); EXPECT_FALSE(FilePath("\\").IsRootDirectory()); EXPECT_FALSE(FilePath("/x").IsRootDirectory()); #endif } } // namespace } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/test/gtest_throw_on_failure_test.py0000775000175100017510000001320612623076744025763 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2009, Google Inc. # 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. """Tests Google Test's throw-on-failure mode with exceptions disabled. This script invokes gtest_throw_on_failure_test_ (a program written with Google Test) with different environments and command line flags. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils # Constants. # The command line flag for enabling/disabling the throw-on-failure mode. THROW_ON_FAILURE = 'gtest_throw_on_failure' # Path to the gtest_throw_on_failure_test_ program, compiled with # exceptions disabled. EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_throw_on_failure_test_') # Utilities. def SetEnvVar(env_var, value): """Sets an environment variable to a given value; unsets it when the given value is None. """ env_var = env_var.upper() if value is not None: os.environ[env_var] = value elif env_var in os.environ: del os.environ[env_var] def Run(command): """Runs a command; returns True/False if its exit code is/isn't 0.""" print 'Running "%s". . .' % ' '.join(command) p = gtest_test_utils.Subprocess(command) return p.exited and p.exit_code == 0 # The tests. TODO(wan@google.com): refactor the class to share common # logic with code in gtest_break_on_failure_unittest.py. class ThrowOnFailureTest(gtest_test_utils.TestCase): """Tests the throw-on-failure mode.""" def RunAndVerify(self, env_var_value, flag_value, should_fail): """Runs gtest_throw_on_failure_test_ and verifies that it does (or does not) exit with a non-zero code. Args: env_var_value: value of the GTEST_BREAK_ON_FAILURE environment variable; None if the variable should be unset. flag_value: value of the --gtest_break_on_failure flag; None if the flag should not be present. should_fail: True iff the program is expected to fail. """ SetEnvVar(THROW_ON_FAILURE, env_var_value) if env_var_value is None: env_var_value_msg = ' is not set' else: env_var_value_msg = '=' + env_var_value if flag_value is None: flag = '' elif flag_value == '0': flag = '--%s=0' % THROW_ON_FAILURE else: flag = '--%s' % THROW_ON_FAILURE command = [EXE_PATH] if flag: command.append(flag) if should_fail: should_or_not = 'should' else: should_or_not = 'should not' failed = not Run(command) SetEnvVar(THROW_ON_FAILURE, None) msg = ('when %s%s, an assertion failure in "%s" %s cause a non-zero ' 'exit code.' % (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command), should_or_not)) self.assert_(failed == should_fail, msg) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(env_var_value=None, flag_value=None, should_fail=False) def testThrowOnFailureEnvVar(self): """Tests using the GTEST_THROW_ON_FAILURE environment variable.""" self.RunAndVerify(env_var_value='0', flag_value=None, should_fail=False) self.RunAndVerify(env_var_value='1', flag_value=None, should_fail=True) def testThrowOnFailureFlag(self): """Tests using the --gtest_throw_on_failure flag.""" self.RunAndVerify(env_var_value=None, flag_value='0', should_fail=False) self.RunAndVerify(env_var_value=None, flag_value='1', should_fail=True) def testThrowOnFailureFlagOverridesEnvVar(self): """Tests that --gtest_throw_on_failure overrides GTEST_THROW_ON_FAILURE.""" self.RunAndVerify(env_var_value='0', flag_value='0', should_fail=False) self.RunAndVerify(env_var_value='0', flag_value='1', should_fail=True) self.RunAndVerify(env_var_value='1', flag_value='0', should_fail=False) self.RunAndVerify(env_var_value='1', flag_value='1', should_fail=True) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_xml_output_unittest_.cc0000664000175100017510000001065712623076744025635 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // Author: eefacm@gmail.com (Sean Mcafee) // Unit test for Google Test XML output. // // A user can specify XML output in a Google Test program to run via // either the GTEST_OUTPUT environment variable or the --gtest_output // flag. This is used for testing such functionality. // // This program will be invoked from a Python unit test. Don't run it // directly. #include using ::testing::InitGoogleTest; using ::testing::TestEventListeners; using ::testing::UnitTest; class SuccessfulTest : public testing::Test { }; TEST_F(SuccessfulTest, Succeeds) { SUCCEED() << "This is a success."; ASSERT_EQ(1, 1); } class FailedTest : public testing::Test { }; TEST_F(FailedTest, Fails) { ASSERT_EQ(1, 2); } class DisabledTest : public testing::Test { }; TEST_F(DisabledTest, DISABLED_test_not_run) { FAIL() << "Unexpected failure: Disabled test should not be run"; } TEST(MixedResultTest, Succeeds) { EXPECT_EQ(1, 1); ASSERT_EQ(1, 1); } TEST(MixedResultTest, Fails) { EXPECT_EQ(1, 2); ASSERT_EQ(2, 3); } TEST(MixedResultTest, DISABLED_test) { FAIL() << "Unexpected failure: Disabled test should not be run"; } TEST(XmlQuotingTest, OutputsCData) { FAIL() << "XML output: " ""; } // Helps to test that invalid characters produced by test code do not make // it into the XML file. TEST(InvalidCharactersTest, InvalidCharactersInMessage) { FAIL() << "Invalid characters in brackets [\x1\x2]"; } class PropertyRecordingTest : public testing::Test { }; TEST_F(PropertyRecordingTest, OneProperty) { RecordProperty("key_1", "1"); } TEST_F(PropertyRecordingTest, IntValuedProperty) { RecordProperty("key_int", 1); } TEST_F(PropertyRecordingTest, ThreeProperties) { RecordProperty("key_1", "1"); RecordProperty("key_2", "2"); RecordProperty("key_3", "3"); } TEST_F(PropertyRecordingTest, TwoValuesForOneKeyUsesLastValue) { RecordProperty("key_1", "1"); RecordProperty("key_1", "2"); } TEST(NoFixtureTest, RecordProperty) { RecordProperty("key", "1"); } void ExternalUtilityThatCallsRecordProperty(const char* key, int value) { testing::Test::RecordProperty(key, value); } void ExternalUtilityThatCallsRecordProperty(const char* key, const char* value) { testing::Test::RecordProperty(key, value); } TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1); } TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); } int main(int argc, char** argv) { InitGoogleTest(&argc, argv); if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) { TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); delete listeners.Release(listeners.default_xml_generator()); } return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest-options_test.cc0000664000175100017510000001747012623076744023767 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Authors: keith.ray@gmail.com (Keith Ray) // // Google Test UnitTestOptions tests // // This file tests classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included from gtest.cc, to avoid changing build or // make-files on Windows and other platforms. Do not #include this file // anywhere else! #include #if GTEST_OS_WINDOWS_MOBILE #include #elif GTEST_OS_WINDOWS #include #endif // GTEST_OS_WINDOWS_MOBILE // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { namespace { // Turns the given relative path into an absolute path. FilePath GetAbsolutePathOf(const FilePath& relative_path) { return FilePath::ConcatPaths(FilePath::GetCurrentDir(), relative_path); } // Testing UnitTestOptions::GetOutputFormat/GetOutputFile. TEST(XmlOutputTest, GetOutputFormatDefault) { GTEST_FLAG(output) = ""; EXPECT_STREQ("", UnitTestOptions::GetOutputFormat().c_str()); } TEST(XmlOutputTest, GetOutputFormat) { GTEST_FLAG(output) = "xml:filename"; EXPECT_STREQ("xml", UnitTestOptions::GetOutputFormat().c_str()); } TEST(XmlOutputTest, GetOutputFileDefault) { GTEST_FLAG(output) = ""; EXPECT_STREQ(GetAbsolutePathOf(FilePath("test_detail.xml")).c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); } TEST(XmlOutputTest, GetOutputFileSingleFile) { GTEST_FLAG(output) = "xml:filename.abc"; EXPECT_STREQ(GetAbsolutePathOf(FilePath("filename.abc")).c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); } TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; const std::string expected_output_file = GetAbsolutePathOf( FilePath(std::string("path") + GTEST_PATH_SEP_ + GetCurrentExecutableName().c_str() + ".xml")).c_str(); const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); #if GTEST_OS_WINDOWS EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); #else EXPECT_EQ(expected_output_file, output_file.c_str()); #endif } TEST(OutputFileHelpersTest, GetCurrentExecutableName) { const std::string exe_str = GetCurrentExecutableName().c_str(); #if GTEST_OS_WINDOWS const bool success = _strcmpi("gtest-options_test", exe_str.c_str()) == 0 || _strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 || _strcmpi("gtest_all_test", exe_str.c_str()) == 0 || _strcmpi("gtest_dll_test", exe_str.c_str()) == 0; #else // TODO(wan@google.com): remove the hard-coded "lt-" prefix when // Chandler Carruth's libtool replacement is ready. const bool success = exe_str == "gtest-options_test" || exe_str == "gtest_all_test" || exe_str == "lt-gtest_all_test" || exe_str == "gtest_dll_test"; #endif // GTEST_OS_WINDOWS if (!success) FAIL() << "GetCurrentExecutableName() returns " << exe_str; } class XmlOutputChangeDirTest : public Test { protected: virtual void SetUp() { original_working_dir_ = FilePath::GetCurrentDir(); posix::ChDir(".."); // This will make the test fail if run from the root directory. EXPECT_STRNE(original_working_dir_.c_str(), FilePath::GetCurrentDir().c_str()); } virtual void TearDown() { posix::ChDir(original_working_dir_.c_str()); } FilePath original_working_dir_; }; TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault) { GTEST_FLAG(output) = ""; EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_, FilePath("test_detail.xml")).c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML) { GTEST_FLAG(output) = "xml"; EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_, FilePath("test_detail.xml")).c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile) { GTEST_FLAG(output) = "xml:filename.abc"; EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_, FilePath("filename.abc")).c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) { GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; const std::string expected_output_file = FilePath::ConcatPaths( original_working_dir_, FilePath(std::string("path") + GTEST_PATH_SEP_ + GetCurrentExecutableName().c_str() + ".xml")).c_str(); const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); #if GTEST_OS_WINDOWS EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); #else EXPECT_EQ(expected_output_file, output_file.c_str()); #endif } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsoluteFile) { #if GTEST_OS_WINDOWS GTEST_FLAG(output) = "xml:c:\\tmp\\filename.abc"; EXPECT_STREQ(FilePath("c:\\tmp\\filename.abc").c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); #else GTEST_FLAG(output) ="xml:/tmp/filename.abc"; EXPECT_STREQ(FilePath("/tmp/filename.abc").c_str(), UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); #endif } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) { #if GTEST_OS_WINDOWS const std::string path = "c:\\tmp\\"; #else const std::string path = "/tmp/"; #endif GTEST_FLAG(output) = "xml:" + path; const std::string expected_output_file = path + GetCurrentExecutableName().c_str() + ".xml"; const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); #if GTEST_OS_WINDOWS EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); #else EXPECT_EQ(expected_output_file, output_file.c_str()); #endif } } // namespace } // namespace internal } // namespace testing ceph-0.80.11/src/gtest/test/gtest_repeat_test.cc0000664000175100017510000001765412623076744023642 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Tests the --gtest_repeat=number flag. #include #include #include // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace testing { GTEST_DECLARE_string_(death_test_style); GTEST_DECLARE_string_(filter); GTEST_DECLARE_int32_(repeat); } // namespace testing using testing::GTEST_FLAG(death_test_style); using testing::GTEST_FLAG(filter); using testing::GTEST_FLAG(repeat); namespace { // We need this when we are testing Google Test itself and therefore // cannot use Google Test assertions. #define GTEST_CHECK_INT_EQ_(expected, actual) \ do {\ const int expected_val = (expected);\ const int actual_val = (actual);\ if (::testing::internal::IsTrue(expected_val != actual_val)) {\ ::std::cout << "Value of: " #actual "\n"\ << " Actual: " << actual_val << "\n"\ << "Expected: " #expected "\n"\ << "Which is: " << expected_val << "\n";\ abort();\ }\ } while(::testing::internal::AlwaysFalse()) // Used for verifying that global environment set-up and tear-down are // inside the gtest_repeat loop. int g_environment_set_up_count = 0; int g_environment_tear_down_count = 0; class MyEnvironment : public testing::Environment { public: MyEnvironment() {} virtual void SetUp() { g_environment_set_up_count++; } virtual void TearDown() { g_environment_tear_down_count++; } }; // A test that should fail. int g_should_fail_count = 0; TEST(FooTest, ShouldFail) { g_should_fail_count++; EXPECT_EQ(0, 1) << "Expected failure."; } // A test that should pass. int g_should_pass_count = 0; TEST(FooTest, ShouldPass) { g_should_pass_count++; } // A test that contains a thread-safe death test and a fast death // test. It should pass. int g_death_test_count = 0; TEST(BarDeathTest, ThreadSafeAndFast) { g_death_test_count++; GTEST_FLAG(death_test_style) = "threadsafe"; EXPECT_DEATH_IF_SUPPORTED(abort(), ""); GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH_IF_SUPPORTED(abort(), ""); } #if GTEST_HAS_PARAM_TEST int g_param_test_count = 0; const int kNumberOfParamTests = 10; class MyParamTest : public testing::TestWithParam {}; TEST_P(MyParamTest, ShouldPass) { // TODO(vladl@google.com): Make parameter value checking robust // WRT order of tests. GTEST_CHECK_INT_EQ_(g_param_test_count % kNumberOfParamTests, GetParam()); g_param_test_count++; } INSTANTIATE_TEST_CASE_P(MyParamSequence, MyParamTest, testing::Range(0, kNumberOfParamTests)); #endif // GTEST_HAS_PARAM_TEST // Resets the count for each test. void ResetCounts() { g_environment_set_up_count = 0; g_environment_tear_down_count = 0; g_should_fail_count = 0; g_should_pass_count = 0; g_death_test_count = 0; #if GTEST_HAS_PARAM_TEST g_param_test_count = 0; #endif // GTEST_HAS_PARAM_TEST } // Checks that the count for each test is expected. void CheckCounts(int expected) { GTEST_CHECK_INT_EQ_(expected, g_environment_set_up_count); GTEST_CHECK_INT_EQ_(expected, g_environment_tear_down_count); GTEST_CHECK_INT_EQ_(expected, g_should_fail_count); GTEST_CHECK_INT_EQ_(expected, g_should_pass_count); GTEST_CHECK_INT_EQ_(expected, g_death_test_count); #if GTEST_HAS_PARAM_TEST GTEST_CHECK_INT_EQ_(expected * kNumberOfParamTests, g_param_test_count); #endif // GTEST_HAS_PARAM_TEST } // Tests the behavior of Google Test when --gtest_repeat is not specified. void TestRepeatUnspecified() { ResetCounts(); GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); CheckCounts(1); } // Tests the behavior of Google Test when --gtest_repeat has the given value. void TestRepeat(int repeat) { GTEST_FLAG(repeat) = repeat; ResetCounts(); GTEST_CHECK_INT_EQ_(repeat > 0 ? 1 : 0, RUN_ALL_TESTS()); CheckCounts(repeat); } // Tests using --gtest_repeat when --gtest_filter specifies an empty // set of tests. void TestRepeatWithEmptyFilter(int repeat) { GTEST_FLAG(repeat) = repeat; GTEST_FLAG(filter) = "None"; ResetCounts(); GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); CheckCounts(0); } // Tests using --gtest_repeat when --gtest_filter specifies a set of // successful tests. void TestRepeatWithFilterForSuccessfulTests(int repeat) { GTEST_FLAG(repeat) = repeat; GTEST_FLAG(filter) = "*-*ShouldFail"; ResetCounts(); GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); GTEST_CHECK_INT_EQ_(0, g_should_fail_count); GTEST_CHECK_INT_EQ_(repeat, g_should_pass_count); GTEST_CHECK_INT_EQ_(repeat, g_death_test_count); #if GTEST_HAS_PARAM_TEST GTEST_CHECK_INT_EQ_(repeat * kNumberOfParamTests, g_param_test_count); #endif // GTEST_HAS_PARAM_TEST } // Tests using --gtest_repeat when --gtest_filter specifies a set of // failed tests. void TestRepeatWithFilterForFailedTests(int repeat) { GTEST_FLAG(repeat) = repeat; GTEST_FLAG(filter) = "*ShouldFail"; ResetCounts(); GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); GTEST_CHECK_INT_EQ_(repeat, g_should_fail_count); GTEST_CHECK_INT_EQ_(0, g_should_pass_count); GTEST_CHECK_INT_EQ_(0, g_death_test_count); #if GTEST_HAS_PARAM_TEST GTEST_CHECK_INT_EQ_(0, g_param_test_count); #endif // GTEST_HAS_PARAM_TEST } } // namespace int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); testing::AddGlobalTestEnvironment(new MyEnvironment); TestRepeatUnspecified(); TestRepeat(0); TestRepeat(1); TestRepeat(5); TestRepeatWithEmptyFilter(2); TestRepeatWithEmptyFilter(3); TestRepeatWithFilterForSuccessfulTests(3); TestRepeatWithFilterForFailedTests(4); // It would be nice to verify that the tests indeed loop forever // when GTEST_FLAG(repeat) is negative, but this test will be quite // complicated to write. Since this flag is for interactive // debugging only and doesn't affect the normal test result, such a // test would be an overkill. printf("PASS\n"); return 0; } ceph-0.80.11/src/gtest/test/gtest_pred_impl_unittest.cc0000664000175100017510000022731612623076744025233 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // This file is AUTOMATICALLY GENERATED on 10/02/2008 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // Regression test for gtest_pred_impl.h // // This file is generated by a script and quite long. If you intend to // learn how Google Test works by reading its unit tests, read // gtest_unittest.cc instead. // // This is intended as a regression test for the Google Test predicate // assertions. We compile it as part of the gtest_unittest target // only to keep the implementation tidy and compact, as it is quite // involved to set up the stage for testing Google Test using Google // Test itself. // // Currently, gtest_unittest takes ~11 seconds to run in the testing // daemon. In the future, if it grows too large and needs much more // time to finish, we should consider separating this file into a // stand-alone regression test. #include #include #include // A user-defined data type. struct Bool { explicit Bool(int val) : value(val != 0) {} bool operator>(int n) const { return value > Bool(n).value; } Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } bool operator==(const Bool& rhs) const { return value == rhs.value; } bool value; }; // Enables Bool to be used in assertions. std::ostream& operator<<(std::ostream& os, const Bool& x) { return os << (x.value ? "true" : "false"); } // Sample functions/functors for testing unary predicate assertions. // A unary predicate function. template bool PredFunction1(T1 v1) { return v1 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction1Int(int v1) { return v1 > 0; } bool PredFunction1Bool(Bool v1) { return v1 > 0; } // A unary predicate functor. struct PredFunctor1 { template bool operator()(const T1& v1) { return v1 > 0; } }; // A unary predicate-formatter function. template testing::AssertionResult PredFormatFunction1(const char* e1, const T1& v1) { if (PredFunction1(v1)) return testing::AssertionSuccess(); testing::Message msg; msg << e1 << " is expected to be positive, but evaluates to " << v1 << "."; return testing::AssertionFailure(msg); } // A unary predicate-formatter functor. struct PredFormatFunctor1 { template testing::AssertionResult operator()(const char* e1, const T1& v1) const { return PredFormatFunction1(e1, v1); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT1. class Predicate1Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; }; bool Predicate1Test::expected_to_finish_; bool Predicate1Test::finished_; int Predicate1Test::n1_; typedef Predicate1Test EXPECT_PRED_FORMAT1Test; typedef Predicate1Test ASSERT_PRED_FORMAT1Test; typedef Predicate1Test EXPECT_PRED1Test; typedef Predicate1Test ASSERT_PRED1Test; // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED1(PredFunction1Int, ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeSuccess) { EXPECT_PRED1(PredFunction1Bool, Bool(++n1_)); finished_ = true; } // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED1(PredFunctor1(), ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeSuccess) { EXPECT_PRED1(PredFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunction1Int, n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunction1Bool, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED1(PredFunction1Int, ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeSuccess) { ASSERT_PRED1(PredFunction1Bool, Bool(++n1_)); finished_ = true; } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED1(PredFunctor1(), ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeSuccess) { ASSERT_PRED1(PredFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunction1Int, n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunction1Bool, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunction1, ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunction1, Bool(++n1_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunctor1(), ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunction1, n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunction1, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunction1, ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunction1, Bool(++n1_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunctor1(), ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunction1, n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunction1, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Sample functions/functors for testing binary predicate assertions. // A binary predicate function. template bool PredFunction2(T1 v1, T2 v2) { return v1 + v2 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction2Int(int v1, int v2) { return v1 + v2 > 0; } bool PredFunction2Bool(Bool v1, Bool v2) { return v1 + v2 > 0; } // A binary predicate functor. struct PredFunctor2 { template bool operator()(const T1& v1, const T2& v2) { return v1 + v2 > 0; } }; // A binary predicate-formatter function. template testing::AssertionResult PredFormatFunction2(const char* e1, const char* e2, const T1& v1, const T2& v2) { if (PredFunction2(v1, v2)) return testing::AssertionSuccess(); testing::Message msg; msg << e1 << " + " << e2 << " is expected to be positive, but evaluates to " << v1 + v2 << "."; return testing::AssertionFailure(msg); } // A binary predicate-formatter functor. struct PredFormatFunctor2 { template testing::AssertionResult operator()(const char* e1, const char* e2, const T1& v1, const T2& v2) const { return PredFormatFunction2(e1, e2, v1, v2); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT2. class Predicate2Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; }; bool Predicate2Test::expected_to_finish_; bool Predicate2Test::finished_; int Predicate2Test::n1_; int Predicate2Test::n2_; typedef Predicate2Test EXPECT_PRED_FORMAT2Test; typedef Predicate2Test ASSERT_PRED_FORMAT2Test; typedef Predicate2Test EXPECT_PRED2Test; typedef Predicate2Test ASSERT_PRED2Test; // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED2(PredFunction2Int, ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeSuccess) { EXPECT_PRED2(PredFunction2Bool, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED2(PredFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeSuccess) { EXPECT_PRED2(PredFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunction2Int, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunction2Bool, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED2(PredFunction2Int, ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeSuccess) { ASSERT_PRED2(PredFunction2Bool, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED2(PredFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeSuccess) { ASSERT_PRED2(PredFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunction2Int, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunction2Bool, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunction2, ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunction2, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunction2, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunction2, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunction2, ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunction2, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunction2, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunction2, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Sample functions/functors for testing ternary predicate assertions. // A ternary predicate function. template bool PredFunction3(T1 v1, T2 v2, T3 v3) { return v1 + v2 + v3 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction3Int(int v1, int v2, int v3) { return v1 + v2 + v3 > 0; } bool PredFunction3Bool(Bool v1, Bool v2, Bool v3) { return v1 + v2 + v3 > 0; } // A ternary predicate functor. struct PredFunctor3 { template bool operator()(const T1& v1, const T2& v2, const T3& v3) { return v1 + v2 + v3 > 0; } }; // A ternary predicate-formatter function. template testing::AssertionResult PredFormatFunction3(const char* e1, const char* e2, const char* e3, const T1& v1, const T2& v2, const T3& v3) { if (PredFunction3(v1, v2, v3)) return testing::AssertionSuccess(); testing::Message msg; msg << e1 << " + " << e2 << " + " << e3 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 << "."; return testing::AssertionFailure(msg); } // A ternary predicate-formatter functor. struct PredFormatFunctor3 { template testing::AssertionResult operator()(const char* e1, const char* e2, const char* e3, const T1& v1, const T2& v2, const T3& v3) const { return PredFormatFunction3(e1, e2, e3, v1, v2, v3); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT3. class Predicate3Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = n3_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; EXPECT_EQ(1, n3_) << "The predicate assertion didn't evaluate argument 4 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; static int n3_; }; bool Predicate3Test::expected_to_finish_; bool Predicate3Test::finished_; int Predicate3Test::n1_; int Predicate3Test::n2_; int Predicate3Test::n3_; typedef Predicate3Test EXPECT_PRED_FORMAT3Test; typedef Predicate3Test ASSERT_PRED_FORMAT3Test; typedef Predicate3Test EXPECT_PRED3Test; typedef Predicate3Test ASSERT_PRED3Test; // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED3(PredFunction3Int, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeSuccess) { EXPECT_PRED3(PredFunction3Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED3(PredFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeSuccess) { EXPECT_PRED3(PredFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunction3Int, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunction3Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED3(PredFunction3Int, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeSuccess) { ASSERT_PRED3(PredFunction3Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED3(PredFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeSuccess) { ASSERT_PRED3(PredFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunction3Int, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunction3Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunction3, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunction3, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunction3, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunction3, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunction3, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunction3, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunction3, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunction3, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Sample functions/functors for testing 4-ary predicate assertions. // A 4-ary predicate function. template bool PredFunction4(T1 v1, T2 v2, T3 v3, T4 v4) { return v1 + v2 + v3 + v4 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction4Int(int v1, int v2, int v3, int v4) { return v1 + v2 + v3 + v4 > 0; } bool PredFunction4Bool(Bool v1, Bool v2, Bool v3, Bool v4) { return v1 + v2 + v3 + v4 > 0; } // A 4-ary predicate functor. struct PredFunctor4 { template bool operator()(const T1& v1, const T2& v2, const T3& v3, const T4& v4) { return v1 + v2 + v3 + v4 > 0; } }; // A 4-ary predicate-formatter function. template testing::AssertionResult PredFormatFunction4(const char* e1, const char* e2, const char* e3, const char* e4, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (PredFunction4(v1, v2, v3, v4)) return testing::AssertionSuccess(); testing::Message msg; msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 + v4 << "."; return testing::AssertionFailure(msg); } // A 4-ary predicate-formatter functor. struct PredFormatFunctor4 { template testing::AssertionResult operator()(const char* e1, const char* e2, const char* e3, const char* e4, const T1& v1, const T2& v2, const T3& v3, const T4& v4) const { return PredFormatFunction4(e1, e2, e3, e4, v1, v2, v3, v4); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT4. class Predicate4Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = n3_ = n4_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; EXPECT_EQ(1, n3_) << "The predicate assertion didn't evaluate argument 4 " "exactly once."; EXPECT_EQ(1, n4_) << "The predicate assertion didn't evaluate argument 5 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; static int n3_; static int n4_; }; bool Predicate4Test::expected_to_finish_; bool Predicate4Test::finished_; int Predicate4Test::n1_; int Predicate4Test::n2_; int Predicate4Test::n3_; int Predicate4Test::n4_; typedef Predicate4Test EXPECT_PRED_FORMAT4Test; typedef Predicate4Test ASSERT_PRED_FORMAT4Test; typedef Predicate4Test EXPECT_PRED4Test; typedef Predicate4Test ASSERT_PRED4Test; // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED4(PredFunction4Int, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeSuccess) { EXPECT_PRED4(PredFunction4Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED4(PredFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeSuccess) { EXPECT_PRED4(PredFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunction4Int, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunction4Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED4(PredFunction4Int, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeSuccess) { ASSERT_PRED4(PredFunction4Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED4(PredFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeSuccess) { ASSERT_PRED4(PredFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunction4Int, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunction4Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunction4, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunction4, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunction4, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunction4, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunction4, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunction4, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunction4, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunction4, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Sample functions/functors for testing 5-ary predicate assertions. // A 5-ary predicate function. template bool PredFunction5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return v1 + v2 + v3 + v4 + v5 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction5Int(int v1, int v2, int v3, int v4, int v5) { return v1 + v2 + v3 + v4 + v5 > 0; } bool PredFunction5Bool(Bool v1, Bool v2, Bool v3, Bool v4, Bool v5) { return v1 + v2 + v3 + v4 + v5 > 0; } // A 5-ary predicate functor. struct PredFunctor5 { template bool operator()(const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { return v1 + v2 + v3 + v4 + v5 > 0; } }; // A 5-ary predicate-formatter function. template testing::AssertionResult PredFormatFunction5(const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (PredFunction5(v1, v2, v3, v4, v5)) return testing::AssertionSuccess(); testing::Message msg; msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 + v4 + v5 << "."; return testing::AssertionFailure(msg); } // A 5-ary predicate-formatter functor. struct PredFormatFunctor5 { template testing::AssertionResult operator()(const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) const { return PredFormatFunction5(e1, e2, e3, e4, e5, v1, v2, v3, v4, v5); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT5. class Predicate5Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = n3_ = n4_ = n5_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; EXPECT_EQ(1, n3_) << "The predicate assertion didn't evaluate argument 4 " "exactly once."; EXPECT_EQ(1, n4_) << "The predicate assertion didn't evaluate argument 5 " "exactly once."; EXPECT_EQ(1, n5_) << "The predicate assertion didn't evaluate argument 6 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; static int n3_; static int n4_; static int n5_; }; bool Predicate5Test::expected_to_finish_; bool Predicate5Test::finished_; int Predicate5Test::n1_; int Predicate5Test::n2_; int Predicate5Test::n3_; int Predicate5Test::n4_; int Predicate5Test::n5_; typedef Predicate5Test EXPECT_PRED_FORMAT5Test; typedef Predicate5Test ASSERT_PRED_FORMAT5Test; typedef Predicate5Test EXPECT_PRED5Test; typedef Predicate5Test ASSERT_PRED5Test; // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED5(PredFunction5Int, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeSuccess) { EXPECT_PRED5(PredFunction5Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED5(PredFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeSuccess) { EXPECT_PRED5(PredFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunction5Int, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunction5Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED5(PredFunction5Int, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeSuccess) { ASSERT_PRED5(PredFunction5Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED5(PredFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeSuccess) { ASSERT_PRED5(PredFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunction5Int, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunction5Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunction5, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunction5, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunction5, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunction5, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunction5, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunction5, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunction5, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunction5, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } ceph-0.80.11/src/gtest/test/gtest_xml_outfile2_test_.cc0000664000175100017510000000373312623076744025123 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: keith.ray@gmail.com (Keith Ray) // // gtest_xml_outfile2_test_ writes some xml via TestProperty used by // gtest_xml_outfiles_test.py #include class PropertyTwo : public testing::Test { protected: virtual void SetUp() { RecordProperty("SetUpProp", 2); } virtual void TearDown() { RecordProperty("TearDownProp", 2); } }; TEST_F(PropertyTwo, TestSomeProperties) { RecordProperty("TestSomeProperty", 2); } ceph-0.80.11/src/gtest/test/gtest_shuffle_test.py0000775000175100017510000003040512623076744024051 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2009 Google Inc. 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. """Verifies that test shuffling works.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils # Command to run the gtest_shuffle_test_ program. COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_') # The environment variables for test sharding. TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' TEST_FILTER = 'A*.A:A*.B:C*' ALL_TESTS = [] ACTIVE_TESTS = [] FILTERED_TESTS = [] SHARDED_TESTS = [] SHUFFLED_ALL_TESTS = [] SHUFFLED_ACTIVE_TESTS = [] SHUFFLED_FILTERED_TESTS = [] SHUFFLED_SHARDED_TESTS = [] def AlsoRunDisabledTestsFlag(): return '--gtest_also_run_disabled_tests' def FilterFlag(test_filter): return '--gtest_filter=%s' % (test_filter,) def RepeatFlag(n): return '--gtest_repeat=%s' % (n,) def ShuffleFlag(): return '--gtest_shuffle' def RandomSeedFlag(n): return '--gtest_random_seed=%s' % (n,) def RunAndReturnOutput(extra_env, args): """Runs the test program and returns its output.""" environ_copy = os.environ.copy() environ_copy.update(extra_env) return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output def GetTestsForAllIterations(extra_env, args): """Runs the test program and returns a list of test lists. Args: extra_env: a map from environment variables to their values args: command line flags to pass to gtest_shuffle_test_ Returns: A list where the i-th element is the list of tests run in the i-th test iteration. """ test_iterations = [] for line in RunAndReturnOutput(extra_env, args).split('\n'): if line.startswith('----'): tests = [] test_iterations.append(tests) elif line.strip(): tests.append(line.strip()) # 'TestCaseName.TestName' return test_iterations def GetTestCases(tests): """Returns a list of test cases in the given full test names. Args: tests: a list of full test names Returns: A list of test cases from 'tests', in their original order. Consecutive duplicates are removed. """ test_cases = [] for test in tests: test_case = test.split('.')[0] if not test_case in test_cases: test_cases.append(test_case) return test_cases def CalculateTestLists(): """Calculates the list of tests run under different flags.""" if not ALL_TESTS: ALL_TESTS.extend( GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0]) if not ACTIVE_TESTS: ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0]) if not FILTERED_TESTS: FILTERED_TESTS.extend( GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0]) if not SHARDED_TESTS: SHARDED_TESTS.extend( GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '1'}, [])[0]) if not SHUFFLED_ALL_TESTS: SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations( {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0]) if not SHUFFLED_ACTIVE_TESTS: SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) if not SHUFFLED_FILTERED_TESTS: SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0]) if not SHUFFLED_SHARDED_TESTS: SHUFFLED_SHARDED_TESTS.extend( GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '1'}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) class GTestShuffleUnitTest(gtest_test_utils.TestCase): """Tests test shuffling.""" def setUp(self): CalculateTestLists() def testShufflePreservesNumberOfTests(self): self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS)) self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS)) self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS)) self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS)) def testShuffleChangesTestOrder(self): self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS) self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS) self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS, SHUFFLED_FILTERED_TESTS) self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS, SHUFFLED_SHARDED_TESTS) def testShuffleChangesTestCaseOrder(self): self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS), GetTestCases(SHUFFLED_ALL_TESTS)) self.assert_( GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS), GetTestCases(SHUFFLED_ACTIVE_TESTS)) self.assert_( GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS), GetTestCases(SHUFFLED_FILTERED_TESTS)) self.assert_( GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS), GetTestCases(SHUFFLED_SHARDED_TESTS)) def testShuffleDoesNotRepeatTest(self): for test in SHUFFLED_ALL_TESTS: self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test), '%s appears more than once' % (test,)) for test in SHUFFLED_ACTIVE_TESTS: self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test), '%s appears more than once' % (test,)) for test in SHUFFLED_FILTERED_TESTS: self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test), '%s appears more than once' % (test,)) for test in SHUFFLED_SHARDED_TESTS: self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test), '%s appears more than once' % (test,)) def testShuffleDoesNotCreateNewTest(self): for test in SHUFFLED_ALL_TESTS: self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,)) for test in SHUFFLED_ACTIVE_TESTS: self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,)) for test in SHUFFLED_FILTERED_TESTS: self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,)) for test in SHUFFLED_SHARDED_TESTS: self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,)) def testShuffleIncludesAllTests(self): for test in ALL_TESTS: self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,)) for test in ACTIVE_TESTS: self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,)) for test in FILTERED_TESTS: self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,)) for test in SHARDED_TESTS: self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,)) def testShuffleLeavesDeathTestsAtFront(self): non_death_test_found = False for test in SHUFFLED_ACTIVE_TESTS: if 'DeathTest.' in test: self.assert_(not non_death_test_found, '%s appears after a non-death test' % (test,)) else: non_death_test_found = True def _VerifyTestCasesDoNotInterleave(self, tests): test_cases = [] for test in tests: [test_case, _] = test.split('.') if test_cases and test_cases[-1] != test_case: test_cases.append(test_case) self.assertEqual(1, test_cases.count(test_case), 'Test case %s is not grouped together in %s' % (test_case, tests)) def testShuffleDoesNotInterleaveTestCases(self): self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS) self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS) self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS) self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS) def testShuffleRestoresOrderAfterEachIteration(self): # Get the test lists in all 3 iterations, using random seed 1, 2, # and 3 respectively. Google Test picks a different seed in each # iteration, and this test depends on the current implementation # picking successive numbers. This dependency is not ideal, but # makes the test much easier to write. [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) # Make sure running the tests with random seed 1 gets the same # order as in iteration 1 above. [tests_with_seed1] = GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1)]) self.assertEqual(tests_in_iteration1, tests_with_seed1) # Make sure running the tests with random seed 2 gets the same # order as in iteration 2 above. Success means that Google Test # correctly restores the test order before re-shuffling at the # beginning of iteration 2. [tests_with_seed2] = GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(2)]) self.assertEqual(tests_in_iteration2, tests_with_seed2) # Make sure running the tests with random seed 3 gets the same # order as in iteration 3 above. Success means that Google Test # correctly restores the test order before re-shuffling at the # beginning of iteration 3. [tests_with_seed3] = GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(3)]) self.assertEqual(tests_in_iteration3, tests_with_seed3) def testShuffleGeneratesNewOrderInEachIteration(self): [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) self.assert_(tests_in_iteration1 != tests_in_iteration2, tests_in_iteration1) self.assert_(tests_in_iteration1 != tests_in_iteration3, tests_in_iteration1) self.assert_(tests_in_iteration2 != tests_in_iteration3, tests_in_iteration2) def testShuffleShardedTestsPreservesPartition(self): # If we run M tests on N shards, the same M tests should be run in # total, regardless of the random seeds used by the shards. [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '0'}, [ShuffleFlag(), RandomSeedFlag(1)]) [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '1'}, [ShuffleFlag(), RandomSeedFlag(20)]) [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '2'}, [ShuffleFlag(), RandomSeedFlag(25)]) sorted_sharded_tests = tests1 + tests2 + tests3 sorted_sharded_tests.sort() sorted_active_tests = [] sorted_active_tests.extend(ACTIVE_TESTS) sorted_active_tests.sort() self.assertEqual(sorted_active_tests, sorted_sharded_tests) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest-typed-test_test.h0000664000175100017510000000466512623076744024242 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ #define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ #include #if GTEST_HAS_TYPED_TEST_P using testing::Test; // For testing that the same type-parameterized test case can be // instantiated in different translation units linked together. // ContainerTest will be instantiated in both gtest-typed-test_test.cc // and gtest-typed-test2_test.cc. template class ContainerTest : public Test { }; TYPED_TEST_CASE_P(ContainerTest); TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed) { TypeParam container; } TYPED_TEST_P(ContainerTest, InitialSizeIsZero) { TypeParam container; EXPECT_EQ(0U, container.size()); } REGISTER_TYPED_TEST_CASE_P(ContainerTest, CanBeDefaultConstructed, InitialSizeIsZero); #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ ceph-0.80.11/src/gtest/test/gtest_uninitialized_test_.cc0000664000175100017510000000360112623076744025354 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) #include TEST(DummyTest, Dummy) { // This test doesn't verify anything. We just need it to create a // realistic stage for testing the behavior of Google Test when // RUN_ALL_TESTS() is called without testing::InitGoogleTest() being // called first. } int main() { return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_break_on_failure_unittest_.cc0000664000175100017510000000625012623076744026676 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Unit test for Google Test's break-on-failure mode. // // A user can ask Google Test to seg-fault when an assertion fails, using // either the GTEST_BREAK_ON_FAILURE environment variable or the // --gtest_break_on_failure flag. This file is used for testing such // functionality. // // This program will be invoked from a Python unit test. It is // expected to fail. Don't run it directly. #include #if GTEST_OS_WINDOWS #include #include #endif namespace { // A test that's expected to fail. TEST(Foo, Bar) { EXPECT_EQ(2, 3); } #if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE // On Windows Mobile global exception handlers are not supported. LONG WINAPI ExitWithExceptionCode( struct _EXCEPTION_POINTERS* exception_pointers) { exit(exception_pointers->ExceptionRecord->ExceptionCode); } #endif } // namespace int main(int argc, char **argv) { #if GTEST_OS_WINDOWS // Suppresses display of the Windows error dialog upon encountering // a general protection fault (segment violation). SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); #if !GTEST_OS_WINDOWS_MOBILE // The default unhandled exception filter does not always exit // with the exception code as exit code - for example it exits with // 0 for EXCEPTION_ACCESS_VIOLATION and 1 for EXCEPTION_BREAKPOINT // if the application is compiled in debug mode. Thus we use our own // filter which always exits with the exception code for unhandled // exceptions. SetUnhandledExceptionFilter(ExitWithExceptionCode); #endif #endif testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_shuffle_test_.cc0000664000175100017510000000641512623076744024146 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Verifies that test shuffling works. #include namespace { using ::testing::EmptyTestEventListener; using ::testing::InitGoogleTest; using ::testing::Message; using ::testing::Test; using ::testing::TestEventListeners; using ::testing::TestInfo; using ::testing::UnitTest; using ::testing::internal::String; using ::testing::internal::scoped_ptr; // The test methods are empty, as the sole purpose of this program is // to print the test names before/after shuffling. class A : public Test {}; TEST_F(A, A) {} TEST_F(A, B) {} TEST(ADeathTest, A) {} TEST(ADeathTest, B) {} TEST(ADeathTest, C) {} TEST(B, A) {} TEST(B, B) {} TEST(B, C) {} TEST(B, DISABLED_D) {} TEST(B, DISABLED_E) {} TEST(BDeathTest, A) {} TEST(BDeathTest, B) {} TEST(C, A) {} TEST(C, B) {} TEST(C, C) {} TEST(C, DISABLED_D) {} TEST(CDeathTest, A) {} TEST(DISABLED_D, A) {} TEST(DISABLED_D, DISABLED_B) {} // This printer prints the full test names only, starting each test // iteration with a "----" marker. class TestNamePrinter : public EmptyTestEventListener { public: virtual void OnTestIterationStart(const UnitTest& /* unit_test */, int /* iteration */) { printf("----\n"); } virtual void OnTestStart(const TestInfo& test_info) { printf("%s.%s\n", test_info.test_case_name(), test_info.name()); } }; } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); // Replaces the default printer with TestNamePrinter, which prints // the test name only. TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); delete listeners.Release(listeners.default_result_printer()); listeners.Append(new TestNamePrinter); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_xml_outfile1_test_.cc0000664000175100017510000000373312623076744025122 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: keith.ray@gmail.com (Keith Ray) // // gtest_xml_outfile1_test_ writes some xml via TestProperty used by // gtest_xml_outfiles_test.py #include class PropertyOne : public testing::Test { protected: virtual void SetUp() { RecordProperty("SetUpProp", 1); } virtual void TearDown() { RecordProperty("TearDownProp", 1); } }; TEST_F(PropertyOne, TestSomeProperties) { RecordProperty("TestSomeProperty", 1); } ceph-0.80.11/src/gtest/test/gtest_uninitialized_test.py0000775000175100017510000000466012623076744025271 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """Verifies that Google Test warns the user when not initialized properly.""" __author__ = 'wan@google.com (Zhanyong Wan)' import gtest_test_utils COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_uninitialized_test_') def Assert(condition): if not condition: raise AssertionError def AssertEq(expected, actual): if expected != actual: print 'Expected: %s' % (expected,) print ' Actual: %s' % (actual,) raise AssertionError def TestExitCodeAndOutput(command): """Runs the given command and verifies its exit code and output.""" # Verifies that 'command' exits with code 1. p = gtest_test_utils.Subprocess(command) Assert(p.exited) AssertEq(1, p.exit_code) Assert('InitGoogleTest' in p.output) class GTestUninitializedTest(gtest_test_utils.TestCase): def testExitCodeAndOutput(self): TestExitCodeAndOutput(COMMAND) if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest_output_test_golden_win.txt0000664000175100017510000006036512623076744026356 0ustar jenkins-buildjenkins-buildThe non-test part of the code is expected to have 2 failures. gtest_output_test_.cc:#: error: Value of: false Actual: false Expected: true gtest_output_test_.cc:#: error: Value of: 3 Expected: 2 [==========] Running 61 tests from 27 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. [----------] 1 test from ADeathTest [ RUN ] ADeathTest.ShouldRunFirst [ OK ] ADeathTest.ShouldRunFirst [----------] 1 test from ATypedDeathTest/0, where TypeParam = int [ RUN ] ATypedDeathTest/0.ShouldRunFirst [ OK ] ATypedDeathTest/0.ShouldRunFirst [----------] 1 test from ATypedDeathTest/1, where TypeParam = double [ RUN ] ATypedDeathTest/1.ShouldRunFirst [ OK ] ATypedDeathTest/1.ShouldRunFirst [----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int [ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst [ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst [----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double [ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst [ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst [----------] 2 tests from PassingTest [ RUN ] PassingTest.PassingTest1 [ OK ] PassingTest.PassingTest1 [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: error: Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: error: Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ RUN ] FatalFailureTest.NonfatalFailureInSubroutine (expecting a failure on false) gtest_output_test_.cc:#: error: Value of: false Actual: false Expected: true [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [----------] 1 test from LoggingTest [ RUN ] LoggingTest.InterleavingLoggingAndAssertions (expecting 2 failures on (3) >= (a[i])) i == 0 i == 1 gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 9 i == 2 i == 3 gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 6 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [----------] 5 tests from SCOPED_TRACETest [ RUN ] SCOPED_TRACETest.ObeysScopes (expected to fail) gtest_output_test_.cc:#: error: Failed This failure is expected, and shouldn't have a trace. gtest_output_test_.cc:#: error: Failed This failure is expected, and should have a trace. Google Test trace: gtest_output_test_.cc:#: Expected trace gtest_output_test_.cc:#: error: Failed This failure is expected, and shouldn't have a trace. [ FAILED ] SCOPED_TRACETest.ObeysScopes [ RUN ] SCOPED_TRACETest.WorksInLoop (expected to fail) gtest_output_test_.cc:#: error: Value of: n Actual: 1 Expected: 2 Google Test trace: gtest_output_test_.cc:#: i = 1 gtest_output_test_.cc:#: error: Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: i = 2 [ FAILED ] SCOPED_TRACETest.WorksInLoop [ RUN ] SCOPED_TRACETest.WorksInSubroutine (expected to fail) gtest_output_test_.cc:#: error: Value of: n Actual: 1 Expected: 2 Google Test trace: gtest_output_test_.cc:#: n = 1 gtest_output_test_.cc:#: error: Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: n = 2 [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ RUN ] SCOPED_TRACETest.CanBeNested (expected to fail) gtest_output_test_.cc:#: error: Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: n = 2 gtest_output_test_.cc:#: [ FAILED ] SCOPED_TRACETest.CanBeNested [ RUN ] SCOPED_TRACETest.CanBeRepeated (expected to fail) gtest_output_test_.cc:#: error: Failed This failure is expected, and should contain trace point A. Google Test trace: gtest_output_test_.cc:#: A gtest_output_test_.cc:#: error: Failed This failure is expected, and should contain trace point A and B. Google Test trace: gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A gtest_output_test_.cc:#: error: Failed This failure is expected, and should contain trace point A, B, and C. Google Test trace: gtest_output_test_.cc:#: C gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A gtest_output_test_.cc:#: error: Failed This failure is expected, and should contain trace point A, B, and D. Google Test trace: gtest_output_test_.cc:#: D gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A [ FAILED ] SCOPED_TRACETest.CanBeRepeated [----------] 1 test from NonFatalFailureInFixtureConstructorTest [ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 5 failures) gtest_output_test_.cc:#: error: Failed Expected failure #1, in the test fixture c'tor. gtest_output_test_.cc:#: error: Failed Expected failure #2, in SetUp(). gtest_output_test_.cc:#: error: Failed Expected failure #3, in the test body. gtest_output_test_.cc:#: error: Failed Expected failure #4, in TearDown. gtest_output_test_.cc:#: error: Failed Expected failure #5, in the test fixture d'tor. [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [----------] 1 test from FatalFailureInFixtureConstructorTest [ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 2 failures) gtest_output_test_.cc:#: error: Failed Expected failure #1, in the test fixture c'tor. gtest_output_test_.cc:#: error: Failed Expected failure #2, in the test fixture d'tor. [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [----------] 1 test from NonFatalFailureInSetUpTest [ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp (expecting 4 failures) gtest_output_test_.cc:#: error: Failed Expected failure #1, in SetUp(). gtest_output_test_.cc:#: error: Failed Expected failure #2, in the test function. gtest_output_test_.cc:#: error: Failed Expected failure #3, in TearDown(). gtest_output_test_.cc:#: error: Failed Expected failure #4, in the test fixture d'tor. [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [----------] 1 test from FatalFailureInSetUpTest [ RUN ] FatalFailureInSetUpTest.FailureInSetUp (expecting 3 failures) gtest_output_test_.cc:#: error: Failed Expected failure #1, in SetUp(). gtest_output_test_.cc:#: error: Failed Expected failure #2, in TearDown(). gtest_output_test_.cc:#: error: Failed Expected failure #3, in the test fixture d'tor. [ FAILED ] FatalFailureInSetUpTest.FailureInSetUp [----------] 1 test from ExceptionInFixtureCtorTest [ RUN ] ExceptionInFixtureCtorTest.ExceptionInFixtureCtor (expecting a failure on thrown exception in the test fixture's constructor) unknown file: error: Exception thrown with code 0xc0000005 in the test fixture's constructor. [----------] 1 test from ExceptionInSetUpTest [ RUN ] ExceptionInSetUpTest.ExceptionInSetUp (expecting 3 failures) unknown file: error: Exception thrown with code 0xc0000005 in SetUp(). gtest_output_test_.cc:#: error: Failed Expected failure #2, in TearDown(). gtest_output_test_.cc:#: error: Failed Expected failure #3, in the test fixture d'tor. [ FAILED ] ExceptionInSetUpTest.ExceptionInSetUp [----------] 2 tests from ExceptionInTestFunctionTest [ RUN ] ExceptionInTestFunctionTest.SEH (expecting 3 failures) unknown file: error: Exception thrown with code 0xc0000005 in the test body. gtest_output_test_.cc:#: error: Failed Expected failure #2, in TearDown(). gtest_output_test_.cc:#: error: Failed Expected failure #3, in the test fixture d'tor. [ FAILED ] ExceptionInTestFunctionTest.SEH [ RUN ] ExceptionInTestFunctionTest.CppException unknown file: error: Exception thrown with code 0xe06d7363 in the test body. gtest_output_test_.cc:#: error: Failed Expected failure #2, in TearDown(). gtest_output_test_.cc:#: error: Failed Expected failure #3, in the test fixture d'tor. [ FAILED ] ExceptionInTestFunctionTest.CppException [----------] 1 test from ExceptionInTearDownTest [ RUN ] ExceptionInTearDownTest.ExceptionInTearDown (expecting 2 failures) unknown file: error: Exception thrown with code 0xe06d7363 in TearDown(). gtest_output_test_.cc:#: error: Failed Expected failure #2, in the test fixture d'tor. [ FAILED ] ExceptionInTearDownTest.ExceptionInTearDown [----------] 4 tests from MixedUpTestCaseTest [ RUN ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo [ OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo [ RUN ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo [ OK ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo [ RUN ] MixedUpTestCaseTest.ThisShouldFail gtest.cc:#: error: Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseTest, you defined test FirstTestFromNamespaceFoo and test ThisShouldFail using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseTest.ThisShouldFail [ RUN ] MixedUpTestCaseTest.ThisShouldFailToo gtest.cc:#: error: Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseTest, you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo [----------] 2 tests from MixedUpTestCaseWithSameTestNameTest [ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ OK ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail gtest.cc:#: error: Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseWithSameTestNameTest, you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [----------] 2 tests from TEST_F_before_TEST_in_same_test_case [ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F [ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F [ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail gtest.cc:#: error: Failed All tests in the same test case must use the same test fixture class, so mixing TEST_F and TEST in the same test case is illegal. In test case TEST_F_before_TEST_in_same_test_case, test DefinedUsingTEST_F is defined using TEST_F but test DefinedUsingTESTAndShouldFail is defined using TEST. You probably want to change the TEST to TEST_F or move it to another test case. [ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail [----------] 2 tests from TEST_before_TEST_F_in_same_test_case [ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST [ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST [ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail gtest.cc:#: error: Failed All tests in the same test case must use the same test fixture class, so mixing TEST_F and TEST in the same test case is illegal. In test case TEST_before_TEST_F_in_same_test_case, test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but test DefinedUsingTEST is defined using TEST. You probably want to change the TEST to TEST_F or move it to another test case. [ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail [----------] 8 tests from ExpectNonfatalFailureTest [ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables [ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables [ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables [ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables [ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure [ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure (expecting a failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures (expecting a failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: 2 failures gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure 1. gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure 2. [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure (expecting a failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns (expecting a failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns [ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows (expecting a failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows [----------] 8 tests from ExpectFatalFailureTest [ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables [ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables [ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables [ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables [ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure [ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure (expecting a failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures (expecting a failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: 2 failures gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure (expecting a failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns (expecting a failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns [ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows (expecting a failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows [----------] 2 tests from TypedTest/0, where TypeParam = int [ RUN ] TypedTest/0.Success [ OK ] TypedTest/0.Success [ RUN ] TypedTest/0.Failure gtest_output_test_.cc:#: error: Value of: TypeParam() Actual: 0 Expected: 1 Expected failure [ FAILED ] TypedTest/0.Failure [----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char [ RUN ] Unsigned/TypedTestP/0.Success [ OK ] Unsigned/TypedTestP/0.Success [ RUN ] Unsigned/TypedTestP/0.Failure gtest_output_test_.cc:#: error: Value of: TypeParam() Actual: \0 Expected: 1U Which is: 1 Expected failure [ FAILED ] Unsigned/TypedTestP/0.Failure [----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int [ RUN ] Unsigned/TypedTestP/1.Success [ OK ] Unsigned/TypedTestP/1.Success [ RUN ] Unsigned/TypedTestP/1.Failure gtest_output_test_.cc:#: error: Value of: TypeParam() Actual: 0 Expected: 1U Which is: 1 Expected failure [ FAILED ] Unsigned/TypedTestP/1.Failure [----------] 4 tests from ExpectFailureTest [ RUN ] ExpectFailureTest.ExpectFatalFailure (expecting 1 failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. (expecting 1 failure) gtest.cc:#: error: Expected: 1 fatal failure containing "Some other fatal failure expected." Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectFatalFailure [ RUN ] ExpectFailureTest.ExpectNonFatalFailure (expecting 1 failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. (expecting 1 failure) gtest.cc:#: error: Expected: 1 non-fatal failure containing "Some other non-fatal failure." Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads (expecting 1 failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: error: Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. (expecting 1 failure) gtest.cc:#: error: Expected: 1 fatal failure containing "Some other fatal failure expected." Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads (expecting 1 failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: error: Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. (expecting 1 failure) gtest.cc:#: error: Expected: 1 non-fatal failure containing "Some other non-fatal failure." Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads [----------] Global test environment tear-down BarEnvironment::TearDown() called. gtest_output_test_.cc:#: error: Failed Expected non-fatal failure. FooEnvironment::TearDown() called. gtest_output_test_.cc:#: error: Failed Expected fatal failure. [==========] 61 tests from 27 test cases ran. [ PASSED ] 21 tests. [ FAILED ] 40 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [ FAILED ] SCOPED_TRACETest.ObeysScopes [ FAILED ] SCOPED_TRACETest.WorksInLoop [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ FAILED ] SCOPED_TRACETest.CanBeNested [ FAILED ] SCOPED_TRACETest.CanBeRepeated [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [ FAILED ] FatalFailureInSetUpTest.FailureInSetUp [ FAILED ] ExceptionInFixtureCtorTest.ExceptionInFixtureCtor [ FAILED ] ExceptionInSetUpTest.ExceptionInSetUp [ FAILED ] ExceptionInTestFunctionTest.SEH [ FAILED ] ExceptionInTestFunctionTest.CppException [ FAILED ] ExceptionInTearDownTest.ExceptionInTearDown [ FAILED ] MixedUpTestCaseTest.ThisShouldFail [ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo [ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail [ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows [ FAILED ] TypedTest/0.Failure, where TypeParam = int [ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char [ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int [ FAILED ] ExpectFailureTest.ExpectFatalFailure [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads 40 FAILED TESTS YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.* [==========] Running 4 tests from 2 test cases. [----------] Global test environment set-up. [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: error: Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms) [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: error: Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms) [ RUN ] FatalFailureTest.NonfatalFailureInSubroutine (expecting a failure on false) gtest_output_test_.cc:#: error: Value of: false Actual: false Expected: true [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms) [----------] 3 tests from FatalFailureTest (? ms total) [----------] 1 test from LoggingTest [ RUN ] LoggingTest.InterleavingLoggingAndAssertions (expecting 2 failures on (3) >= (a[i])) i == 0 i == 1 gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 9 i == 2 i == 3 gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 6 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms) [----------] 1 test from LoggingTest (? ms total) [----------] Global test environment tear-down [==========] 4 tests from 2 test cases ran. (? ms total) [ PASSED ] 0 tests. [ FAILED ] 4 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions 4 FAILED TESTS YOU HAVE 1 DISABLED TEST Note: Google Test filter = *DISABLED_* [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from DisabledTestsWarningTest [ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning [ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. Note: Google Test filter = PassingTest.* Note: This is test shard 1 of 2. [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from PassingTest [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. YOU HAVE 1 DISABLED TEST ceph-0.80.11/src/gtest/test/gtest_env_var_test.py0000775000175100017510000000666512623076744024070 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """Verifies that Google Test correctly parses environment variables.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils IS_WINDOWS = os.name == 'nt' IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_env_var_test_') environ = os.environ.copy() def AssertEq(expected, actual): if expected != actual: print 'Expected: %s' % (expected,) print ' Actual: %s' % (actual,) raise AssertionError def SetEnvVar(env_var, value): """Sets the env variable to 'value'; unsets it when 'value' is None.""" if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] def GetFlag(flag): """Runs gtest_env_var_test_ and returns its output.""" args = [COMMAND] if flag is not None: args += [flag] return gtest_test_utils.Subprocess(args, env=environ).output def TestFlag(flag, test_val, default_val): """Verifies that the given flag is affected by the corresponding env var.""" env_var = 'GTEST_' + flag.upper() SetEnvVar(env_var, test_val) AssertEq(test_val, GetFlag(flag)) SetEnvVar(env_var, None) AssertEq(default_val, GetFlag(flag)) class GTestEnvVarTest(gtest_test_utils.TestCase): def testEnvVarAffectsFlag(self): """Tests that environment variable should affect the corresponding flag.""" TestFlag('break_on_failure', '1', '0') TestFlag('color', 'yes', 'auto') TestFlag('filter', 'FooTest.Bar', '*') TestFlag('output', 'xml:tmp/foo.xml', '') TestFlag('print_time', '0', '1') TestFlag('repeat', '999', '1') TestFlag('throw_on_failure', '1', '0') TestFlag('death_test_style', 'threadsafe', 'fast') if IS_WINDOWS: TestFlag('catch_exceptions', '1', '0') if IS_LINUX: TestFlag('death_test_use_fork', '1', '0') TestFlag('stack_trace_depth', '0', '100') if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/test/gtest-listener_test.cc0000664000175100017510000002326312623076744024116 0ustar jenkins-buildjenkins-build// Copyright 2009 Google Inc. 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. // // Author: vladl@google.com (Vlad Losev) // // The Google C++ Testing Framework (Google Test) // // This file verifies Google Test event listeners receive events at the // right times. #include #include using ::testing::AddGlobalTestEnvironment; using ::testing::Environment; using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::TestCase; using ::testing::TestEventListener; using ::testing::TestInfo; using ::testing::TestPartResult; using ::testing::UnitTest; using ::testing::internal::String; // Used by tests to register their events. std::vector* g_events = NULL; namespace testing { namespace internal { class EventRecordingListener : public TestEventListener { public: EventRecordingListener(const char* name) : name_(name) {} protected: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnTestProgramStart")); } virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int iteration) { Message message; message << GetFullMethodName("OnTestIterationStart") << "(" << iteration << ")"; g_events->push_back(message.GetString()); } virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart")); } virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd")); } virtual void OnTestCaseStart(const TestCase& /*test_case*/) { g_events->push_back(GetFullMethodName("OnTestCaseStart")); } virtual void OnTestStart(const TestInfo& /*test_info*/) { g_events->push_back(GetFullMethodName("OnTestStart")); } virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) { g_events->push_back(GetFullMethodName("OnTestPartResult")); } virtual void OnTestEnd(const TestInfo& /*test_info*/) { g_events->push_back(GetFullMethodName("OnTestEnd")); } virtual void OnTestCaseEnd(const TestCase& /*test_case*/) { g_events->push_back(GetFullMethodName("OnTestCaseEnd")); } virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart")); } virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd")); } virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int iteration) { Message message; message << GetFullMethodName("OnTestIterationEnd") << "(" << iteration << ")"; g_events->push_back(message.GetString()); } virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnTestProgramEnd")); } private: String GetFullMethodName(const char* name) { Message message; message << name_ << "." << name; return message.GetString(); } String name_; }; class EnvironmentInvocationCatcher : public Environment { protected: virtual void SetUp() { g_events->push_back(String("Environment::SetUp")); } virtual void TearDown() { g_events->push_back(String("Environment::TearDown")); } }; class ListenerTest : public Test { protected: static void SetUpTestCase() { g_events->push_back(String("ListenerTest::SetUpTestCase")); } static void TearDownTestCase() { g_events->push_back(String("ListenerTest::TearDownTestCase")); } virtual void SetUp() { g_events->push_back(String("ListenerTest::SetUp")); } virtual void TearDown() { g_events->push_back(String("ListenerTest::TearDown")); } }; TEST_F(ListenerTest, DoesFoo) { // Test execution order within a test case is not guaranteed so we are not // recording the test name. g_events->push_back(String("ListenerTest::* Test Body")); SUCCEED(); // Triggers OnTestPartResult. } TEST_F(ListenerTest, DoesBar) { g_events->push_back(String("ListenerTest::* Test Body")); SUCCEED(); // Triggers OnTestPartResult. } } // namespace internal } // namespace testing using ::testing::internal::EnvironmentInvocationCatcher; using ::testing::internal::EventRecordingListener; void VerifyResults(const std::vector& data, const char* const* expected_data, int expected_data_size) { const int actual_size = data.size(); // If the following assertion fails, a new entry will be appended to // data. Hence we save data.size() first. EXPECT_EQ(expected_data_size, actual_size); // Compares the common prefix. const int shorter_size = expected_data_size <= actual_size ? expected_data_size : actual_size; int i = 0; for (; i < shorter_size; ++i) { ASSERT_STREQ(expected_data[i], data[i].c_str()) << "at position " << i; } // Prints extra elements in the actual data. for (; i < actual_size; ++i) { printf(" Actual event #%d: %s\n", i, data[i].c_str()); } } int main(int argc, char **argv) { std::vector events; g_events = &events; InitGoogleTest(&argc, argv); UnitTest::GetInstance()->listeners().Append( new EventRecordingListener("1st")); UnitTest::GetInstance()->listeners().Append( new EventRecordingListener("2nd")); AddGlobalTestEnvironment(new EnvironmentInvocationCatcher); GTEST_CHECK_(events.size() == 0) << "AddGlobalTestEnvironment should not generate any events itself."; ::testing::GTEST_FLAG(repeat) = 2; int ret_val = RUN_ALL_TESTS(); const char* const expected_events[] = { "1st.OnTestProgramStart", "2nd.OnTestProgramStart", "1st.OnTestIterationStart(0)", "2nd.OnTestIterationStart(0)", "1st.OnEnvironmentsSetUpStart", "2nd.OnEnvironmentsSetUpStart", "Environment::SetUp", "2nd.OnEnvironmentsSetUpEnd", "1st.OnEnvironmentsSetUpEnd", "1st.OnTestCaseStart", "2nd.OnTestCaseStart", "ListenerTest::SetUpTestCase", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "ListenerTest::TearDownTestCase", "2nd.OnTestCaseEnd", "1st.OnTestCaseEnd", "1st.OnEnvironmentsTearDownStart", "2nd.OnEnvironmentsTearDownStart", "Environment::TearDown", "2nd.OnEnvironmentsTearDownEnd", "1st.OnEnvironmentsTearDownEnd", "2nd.OnTestIterationEnd(0)", "1st.OnTestIterationEnd(0)", "1st.OnTestIterationStart(1)", "2nd.OnTestIterationStart(1)", "1st.OnEnvironmentsSetUpStart", "2nd.OnEnvironmentsSetUpStart", "Environment::SetUp", "2nd.OnEnvironmentsSetUpEnd", "1st.OnEnvironmentsSetUpEnd", "1st.OnTestCaseStart", "2nd.OnTestCaseStart", "ListenerTest::SetUpTestCase", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "ListenerTest::TearDownTestCase", "2nd.OnTestCaseEnd", "1st.OnTestCaseEnd", "1st.OnEnvironmentsTearDownStart", "2nd.OnEnvironmentsTearDownStart", "Environment::TearDown", "2nd.OnEnvironmentsTearDownEnd", "1st.OnEnvironmentsTearDownEnd", "2nd.OnTestIterationEnd(1)", "1st.OnTestIterationEnd(1)", "2nd.OnTestProgramEnd", "1st.OnTestProgramEnd" }; VerifyResults(events, expected_events, sizeof(expected_events)/sizeof(expected_events[0])); // We need to check manually for ad hoc test failures that happen after // RUN_ALL_TESTS finishes. if (UnitTest::GetInstance()->Failed()) ret_val = 1; return ret_val; } ceph-0.80.11/src/gtest/test/gtest_throw_on_failure_test_.cc0000664000175100017510000000475612623076744026066 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // Tests Google Test's throw-on-failure mode with exceptions disabled. // // This program must be compiled with exceptions disabled. It will be // invoked by gtest_throw_on_failure_test.py, and is expected to exit // with non-zero in the throw-on-failure mode or 0 otherwise. #include int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); // We want to ensure that people can use Google Test assertions in // other testing frameworks, as long as they initialize Google Test // properly and set the thrown-on-failure mode. Therefore, we don't // use Google Test's constructs for defining and running tests // (e.g. TEST and RUN_ALL_TESTS) here. // In the throw-on-failure mode with exceptions disabled, this // assertion will cause the program to exit with a non-zero code. EXPECT_EQ(2, 3); // When not in the throw-on-failure mode, the control will reach // here. return 0; } ceph-0.80.11/src/gtest/test/gtest_list_tests_unittest_.cc0000664000175100017510000000463012623076744025604 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: phanna@google.com (Patrick Hanna) // Unit test for Google Test's --gtest_list_tests flag. // // A user can ask Google Test to list all tests that will run // so that when using a filter, a user will know what // tests to look for. The tests will not be run after listing. // // This program will be invoked from a Python unit test. // Don't run it directly. #include namespace { // Several different test cases and tests that will be listed. TEST(Foo, Bar1) { } TEST(Foo, Bar2) { } TEST(Foo, DISABLED_Bar3) { } TEST(Abc, Xyz) { } TEST(Abc, Def) { } TEST(FooBar, Baz) { } class FooTest : public testing::Test { }; TEST_F(FooTest, Test1) { } TEST_F(FooTest, DISABLED_Test2) { } TEST_F(FooTest, Test3) { } TEST(FooDeathTest, Test1) { } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/production.h0000664000175100017510000000417412623076744022136 0ustar jenkins-buildjenkins-build// Copyright 2006, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // This is part of the unit test for include/gtest/gtest_prod.h. #ifndef GTEST_TEST_PRODUCTION_H_ #define GTEST_TEST_PRODUCTION_H_ #include class PrivateCode { public: // Declares a friend test that does not use a fixture. FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers); // Declares a friend test that uses a fixture. FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers); PrivateCode(); int x() const { return x_; } private: void set_x(int an_x) { x_ = an_x; } int x_; }; #endif // GTEST_TEST_PRODUCTION_H_ ceph-0.80.11/src/gtest/test/gtest-test-part_test.cc0000664000175100017510000001616212623076744024214 0ustar jenkins-buildjenkins-build// Copyright 2008 Google Inc. // 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. // // Author: mheule@google.com (Markus Heule) // #include #include using testing::Message; using testing::Test; using testing::TestPartResult; using testing::TestPartResultArray; namespace { // Tests the TestPartResult class. // The test fixture for testing TestPartResult. class TestPartResultTest : public Test { protected: TestPartResultTest() : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"), r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"), r3_(TestPartResult::kFatalFailure, NULL, -1, "Failure!") {} TestPartResult r1_, r2_, r3_; }; TEST_F(TestPartResultTest, ConstructorWorks) { Message message; message << "something is terribly wrong"; message << static_cast(testing::internal::kStackTraceMarker); message << "some unimportant stack trace"; const TestPartResult result(TestPartResult::kNonFatalFailure, "some_file.cc", 42, message.GetString().c_str()); EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type()); EXPECT_STREQ("some_file.cc", result.file_name()); EXPECT_EQ(42, result.line_number()); EXPECT_STREQ(message.GetString().c_str(), result.message()); EXPECT_STREQ("something is terribly wrong", result.summary()); } TEST_F(TestPartResultTest, ResultAccessorsWork) { const TestPartResult success(TestPartResult::kSuccess, "file.cc", 42, "message"); EXPECT_TRUE(success.passed()); EXPECT_FALSE(success.failed()); EXPECT_FALSE(success.nonfatally_failed()); EXPECT_FALSE(success.fatally_failed()); const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure, "file.cc", 42, "message"); EXPECT_FALSE(nonfatal_failure.passed()); EXPECT_TRUE(nonfatal_failure.failed()); EXPECT_TRUE(nonfatal_failure.nonfatally_failed()); EXPECT_FALSE(nonfatal_failure.fatally_failed()); const TestPartResult fatal_failure(TestPartResult::kFatalFailure, "file.cc", 42, "message"); EXPECT_FALSE(fatal_failure.passed()); EXPECT_TRUE(fatal_failure.failed()); EXPECT_FALSE(fatal_failure.nonfatally_failed()); EXPECT_TRUE(fatal_failure.fatally_failed()); } // Tests TestPartResult::type(). TEST_F(TestPartResultTest, type) { EXPECT_EQ(TestPartResult::kSuccess, r1_.type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type()); EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type()); } // Tests TestPartResult::file_name(). TEST_F(TestPartResultTest, file_name) { EXPECT_STREQ("foo/bar.cc", r1_.file_name()); EXPECT_STREQ(NULL, r3_.file_name()); } // Tests TestPartResult::line_number(). TEST_F(TestPartResultTest, line_number) { EXPECT_EQ(10, r1_.line_number()); EXPECT_EQ(-1, r2_.line_number()); } // Tests TestPartResult::message(). TEST_F(TestPartResultTest, message) { EXPECT_STREQ("Success!", r1_.message()); } // Tests TestPartResult::passed(). TEST_F(TestPartResultTest, Passed) { EXPECT_TRUE(r1_.passed()); EXPECT_FALSE(r2_.passed()); EXPECT_FALSE(r3_.passed()); } // Tests TestPartResult::failed(). TEST_F(TestPartResultTest, Failed) { EXPECT_FALSE(r1_.failed()); EXPECT_TRUE(r2_.failed()); EXPECT_TRUE(r3_.failed()); } // Tests TestPartResult::fatally_failed(). TEST_F(TestPartResultTest, FatallyFailed) { EXPECT_FALSE(r1_.fatally_failed()); EXPECT_FALSE(r2_.fatally_failed()); EXPECT_TRUE(r3_.fatally_failed()); } // Tests TestPartResult::nonfatally_failed(). TEST_F(TestPartResultTest, NonfatallyFailed) { EXPECT_FALSE(r1_.nonfatally_failed()); EXPECT_TRUE(r2_.nonfatally_failed()); EXPECT_FALSE(r3_.nonfatally_failed()); } // Tests the TestPartResultArray class. class TestPartResultArrayTest : public Test { protected: TestPartResultArrayTest() : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"), r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {} const TestPartResult r1_, r2_; }; // Tests that TestPartResultArray initially has size 0. TEST_F(TestPartResultArrayTest, InitialSizeIsZero) { TestPartResultArray results; EXPECT_EQ(0, results.size()); } // Tests that TestPartResultArray contains the given TestPartResult // after one Append() operation. TEST_F(TestPartResultArrayTest, ContainsGivenResultAfterAppend) { TestPartResultArray results; results.Append(r1_); EXPECT_EQ(1, results.size()); EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); } // Tests that TestPartResultArray contains the given TestPartResults // after two Append() operations. TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends) { TestPartResultArray results; results.Append(r1_); results.Append(r2_); EXPECT_EQ(2, results.size()); EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message()); } typedef TestPartResultArrayTest TestPartResultArrayDeathTest; // Tests that the program dies when GetTestPartResult() is called with // an invalid index. TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound) { TestPartResultArray results; results.Append(r1_); EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), ""); EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), ""); } // TODO(mheule@google.com): Add a test for the class HasNewFatalFailureHelper. } // namespace ceph-0.80.11/src/gtest/test/gtest_env_var_test_.cc0000664000175100017510000000677012623076744024156 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // A helper program for testing that Google Test parses the environment // variables correctly. #include #include #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ using ::std::cout; namespace testing { // The purpose of this is to make the test more realistic by ensuring // that the UnitTest singleton is created before main() is entered. // We don't actual run the TEST itself. TEST(GTestEnvVarTest, Dummy) { } void PrintFlag(const char* flag) { if (strcmp(flag, "break_on_failure") == 0) { cout << GTEST_FLAG(break_on_failure); return; } if (strcmp(flag, "catch_exceptions") == 0) { cout << GTEST_FLAG(catch_exceptions); return; } if (strcmp(flag, "color") == 0) { cout << GTEST_FLAG(color); return; } if (strcmp(flag, "death_test_style") == 0) { cout << GTEST_FLAG(death_test_style); return; } if (strcmp(flag, "death_test_use_fork") == 0) { cout << GTEST_FLAG(death_test_use_fork); return; } if (strcmp(flag, "filter") == 0) { cout << GTEST_FLAG(filter); return; } if (strcmp(flag, "output") == 0) { cout << GTEST_FLAG(output); return; } if (strcmp(flag, "print_time") == 0) { cout << GTEST_FLAG(print_time); return; } if (strcmp(flag, "repeat") == 0) { cout << GTEST_FLAG(repeat); return; } if (strcmp(flag, "stack_trace_depth") == 0) { cout << GTEST_FLAG(stack_trace_depth); return; } if (strcmp(flag, "throw_on_failure") == 0) { cout << GTEST_FLAG(throw_on_failure); return; } cout << "Invalid flag name " << flag << ". Valid names are break_on_failure, color, filter, etc.\n"; exit(1); } } // namespace testing int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); if (argc != 2) { cout << "Usage: gtest_env_var_test_ NAME_OF_FLAG\n"; return 1; } testing::PrintFlag(argv[1]); return 0; } ceph-0.80.11/src/gtest/test/gtest-message_test.cc0000664000175100017510000001262212623076744023712 0ustar jenkins-buildjenkins-build// Copyright 2005, Google Inc. // 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. // // Author: wan@google.com (Zhanyong Wan) // // Tests for the Message class. #include #include namespace { using ::testing::Message; using ::testing::internal::StrStream; // A helper function that turns a Message into a C string. const char* ToCString(const Message& msg) { static testing::internal::String result; result = msg.GetString(); return result.c_str(); } // Tests the testing::Message class // Tests the default constructor. TEST(MessageTest, DefaultConstructor) { const Message msg; EXPECT_STREQ("", ToCString(msg)); } // Tests the copy constructor. TEST(MessageTest, CopyConstructor) { const Message msg1("Hello"); const Message msg2(msg1); EXPECT_STREQ("Hello", ToCString(msg2)); } // Tests constructing a Message from a C-string. TEST(MessageTest, ConstructsFromCString) { Message msg("Hello"); EXPECT_STREQ("Hello", ToCString(msg)); } // Tests streaming a float. TEST(MessageTest, StreamsFloat) { const char* const s = ToCString(Message() << 1.23456F << " " << 2.34567F); // Both numbers should be printed with enough precision. EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s); EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s); } // Tests streaming a double. TEST(MessageTest, StreamsDouble) { const char* const s = ToCString(Message() << 1260570880.4555497 << " " << 1260572265.1954534); // Both numbers should be printed with enough precision. EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s); EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s); } // Tests streaming a non-char pointer. TEST(MessageTest, StreamsPointer) { int n = 0; int* p = &n; EXPECT_STRNE("(null)", ToCString(Message() << p)); } // Tests streaming a NULL non-char pointer. TEST(MessageTest, StreamsNullPointer) { int* p = NULL; EXPECT_STREQ("(null)", ToCString(Message() << p)); } // Tests streaming a C string. TEST(MessageTest, StreamsCString) { EXPECT_STREQ("Foo", ToCString(Message() << "Foo")); } // Tests streaming a NULL C string. TEST(MessageTest, StreamsNullCString) { char* p = NULL; EXPECT_STREQ("(null)", ToCString(Message() << p)); } // Tests streaming std::string. TEST(MessageTest, StreamsString) { const ::std::string str("Hello"); EXPECT_STREQ("Hello", ToCString(Message() << str)); } // Tests that we can output strings containing embedded NULs. TEST(MessageTest, StreamsStringWithEmbeddedNUL) { const char char_array_with_nul[] = "Here's a NUL\0 and some more string"; const ::std::string string_with_nul(char_array_with_nul, sizeof(char_array_with_nul) - 1); EXPECT_STREQ("Here's a NUL\\0 and some more string", ToCString(Message() << string_with_nul)); } // Tests streaming a NUL char. TEST(MessageTest, StreamsNULChar) { EXPECT_STREQ("\\0", ToCString(Message() << '\0')); } // Tests streaming int. TEST(MessageTest, StreamsInt) { EXPECT_STREQ("123", ToCString(Message() << 123)); } // Tests that basic IO manipulators (endl, ends, and flush) can be // streamed to Message. TEST(MessageTest, StreamsBasicIoManip) { EXPECT_STREQ("Line 1.\nA NUL char \\0 in line 2.", ToCString(Message() << "Line 1." << std::endl << "A NUL char " << std::ends << std::flush << " in line 2.")); } // Tests Message::GetString() TEST(MessageTest, GetString) { Message msg; msg << 1 << " lamb"; EXPECT_STREQ("1 lamb", msg.GetString().c_str()); } // Tests streaming a Message object to an ostream. TEST(MessageTest, StreamsToOStream) { Message msg("Hello"); StrStream ss; ss << msg; EXPECT_STREQ("Hello", testing::internal::StrStreamToString(&ss).c_str()); } // Tests that a Message object doesn't take up too much stack space. TEST(MessageTest, DoesNotTakeUpMuchStackSpace) { EXPECT_LE(sizeof(Message), 16U); } } // namespace ceph-0.80.11/src/gtest/test/gtest-param-test_test.h0000664000175100017510000000444512623076744024211 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Authors: vladl@google.com (Vlad Losev) // // The Google C++ Testing Framework (Google Test) // // This header file provides classes and functions used internally // for testing Google Test itself. #ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ #define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ #include #if GTEST_HAS_PARAM_TEST // Test fixture for testing definition and instantiation of a test // in separate translation units. class ExternalInstantiationTest : public ::testing::TestWithParam {}; // Test fixture for testing instantiation of a test in multiple // translation units. class InstantiationInMultipleTranslaionUnitsTest : public ::testing::TestWithParam {}; #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ ceph-0.80.11/src/gtest/test/gtest_xml_test_utils.py0000775000175100017510000001670612623076744024445 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2006, Google Inc. # 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. """Unit test utilities for gtest_xml_output""" __author__ = 'eefacm@gmail.com (Sean Mcafee)' import re from xml.dom import minidom, Node import gtest_test_utils GTEST_OUTPUT_FLAG = "--gtest_output" GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" class GTestXMLTestCase(gtest_test_utils.TestCase): """ Base class for tests of Google Test's XML output functionality. """ def AssertEquivalentNodes(self, expected_node, actual_node): """ Asserts that actual_node (a DOM node object) is equivalent to expected_node (another DOM node object), in that either both of them are CDATA nodes and have the same value, or both are DOM elements and actual_node meets all of the following conditions: * It has the same tag name as expected_node. * It has the same set of attributes as expected_node, each with the same value as the corresponding attribute of expected_node. An exception is any attribute named "time", which needs only be convertible to a floating-point number. * It has an equivalent set of child nodes (including elements and CDATA sections) as expected_node. Note that we ignore the order of the children as they are not guaranteed to be in any particular order. """ if expected_node.nodeType == Node.CDATA_SECTION_NODE: self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType) self.assertEquals(expected_node.nodeValue, actual_node.nodeValue) return self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType) self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType) self.assertEquals(expected_node.tagName, actual_node.tagName) expected_attributes = expected_node.attributes actual_attributes = actual_node .attributes self.assertEquals( expected_attributes.length, actual_attributes.length, "attribute numbers differ in element " + actual_node.tagName) for i in range(expected_attributes.length): expected_attr = expected_attributes.item(i) actual_attr = actual_attributes.get(expected_attr.name) self.assert_( actual_attr is not None, "expected attribute %s not found in element %s" % (expected_attr.name, actual_node.tagName)) self.assertEquals(expected_attr.value, actual_attr.value, " values of attribute %s in element %s differ" % (expected_attr.name, actual_node.tagName)) expected_children = self._GetChildren(expected_node) actual_children = self._GetChildren(actual_node) self.assertEquals( len(expected_children), len(actual_children), "number of child elements differ in element " + actual_node.tagName) for child_id, child in expected_children.iteritems(): self.assert_(child_id in actual_children, '<%s> is not in <%s> (in element %s)' % (child_id, actual_children, actual_node.tagName)) self.AssertEquivalentNodes(child, actual_children[child_id]) identifying_attribute = { "testsuites": "name", "testsuite": "name", "testcase": "name", "failure": "message", } def _GetChildren(self, element): """ Fetches all of the child nodes of element, a DOM Element object. Returns them as the values of a dictionary keyed by the IDs of the children. For , and elements, the ID is the value of their "name" attribute; for elements, it is the value of the "message" attribute; CDATA sections and non-whitespace text nodes are concatenated into a single CDATA section with ID "detail". An exception is raised if any element other than the above four is encountered, if two child elements with the same identifying attributes are encountered, or if any other type of node is encountered. """ children = {} for child in element.childNodes: if child.nodeType == Node.ELEMENT_NODE: self.assert_(child.tagName in self.identifying_attribute, "Encountered unknown element <%s>" % child.tagName) childID = child.getAttribute(self.identifying_attribute[child.tagName]) self.assert_(childID not in children) children[childID] = child elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: if "detail" not in children: if (child.nodeType == Node.CDATA_SECTION_NODE or not child.nodeValue.isspace()): children["detail"] = child.ownerDocument.createCDATASection( child.nodeValue) else: children["detail"].nodeValue += child.nodeValue else: self.fail("Encountered unexpected node type %d" % child.nodeType) return children def NormalizeXml(self, element): """ Normalizes Google Test's XML output to eliminate references to transient information that may change from run to run. * The "time" attribute of , and elements is replaced with a single asterisk, if it contains only digit characters. * The line number reported in the first line of the "message" attribute of elements is replaced with a single asterisk. * The directory names in file paths are removed. * The stack traces are removed. """ if element.tagName in ("testsuites", "testsuite", "testcase"): time = element.getAttributeNode("time") time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value) elif element.tagName == "failure": for child in element.childNodes: if child.nodeType == Node.CDATA_SECTION_NODE: # Removes the source line number. cdata = re.sub(r"^.*[/\\](.*:)\d+\n", "\\1*\n", child.nodeValue) # Removes the actual stack trace. child.nodeValue = re.sub(r"\nStack trace:\n(.|\n)*", "", cdata) for child in element.childNodes: if child.nodeType == Node.ELEMENT_NODE: self.NormalizeXml(child) ceph-0.80.11/src/gtest/test/gtest-param-test_test.cc0000664000175100017510000007474312623076744024357 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: vladl@google.com (Vlad Losev) // // Tests for Google Test itself. This file verifies that the parameter // generators objects produce correct parameter sequences and that // Google Test runtime instantiates correct tests from those sequences. #include #if GTEST_HAS_PARAM_TEST #include #include #include #include #include #include // To include gtest-internal-inl.h. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" // for UnitTestOptions #undef GTEST_IMPLEMENTATION_ #include "test/gtest-param-test_test.h" using ::std::vector; using ::std::sort; using ::testing::AddGlobalTestEnvironment; using ::testing::Bool; using ::testing::Message; using ::testing::Range; using ::testing::TestWithParam; using ::testing::Values; using ::testing::ValuesIn; #if GTEST_HAS_COMBINE using ::testing::Combine; using ::std::tr1::get; using ::std::tr1::make_tuple; using ::std::tr1::tuple; #endif // GTEST_HAS_COMBINE using ::testing::internal::ParamGenerator; using ::testing::internal::UnitTestOptions; // Prints a value to a string. // // TODO(wan@google.com): remove PrintValue() when we move matchers and // EXPECT_THAT() from Google Mock to Google Test. At that time, we // can write EXPECT_THAT(x, Eq(y)) to compare two tuples x and y, as // EXPECT_THAT() and the matchers know how to print tuples. template ::std::string PrintValue(const T& value) { ::std::stringstream stream; stream << value; return stream.str(); } #if GTEST_HAS_COMBINE // These overloads allow printing tuples in our tests. We cannot // define an operator<< for tuples, as that definition needs to be in // the std namespace in order to be picked up by Google Test via // Argument-Dependent Lookup, yet defining anything in the std // namespace in non-STL code is undefined behavior. template ::std::string PrintValue(const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ")"; return stream.str(); } template ::std::string PrintValue(const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ", "<< get<2>(value) << ")"; return stream.str(); } template ::std::string PrintValue( const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ", "<< get<2>(value) << ", " << get<3>(value) << ", "<< get<4>(value) << ", " << get<5>(value) << ", "<< get<6>(value) << ", " << get<7>(value) << ", "<< get<8>(value) << ", " << get<9>(value) << ")"; return stream.str(); } #endif // GTEST_HAS_COMBINE // Verifies that a sequence generated by the generator and accessed // via the iterator object matches the expected one using Google Test // assertions. template void VerifyGenerator(const ParamGenerator& generator, const T (&expected_values)[N]) { typename ParamGenerator::iterator it = generator.begin(); for (size_t i = 0; i < N; ++i) { ASSERT_FALSE(it == generator.end()) << "At element " << i << " when accessing via an iterator " << "created with the copy constructor.\n"; // We cannot use EXPECT_EQ() here as the values may be tuples, // which don't support <<. EXPECT_TRUE(expected_values[i] == *it) << "where i is " << i << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; it++; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " << "created with the copy constructor.\n"; // Test the iterator assignment. The following lines verify that // the sequence accessed via an iterator initialized via the // assignment operator (as opposed to a copy constructor) matches // just the same. it = generator.begin(); for (size_t i = 0; i < N; ++i) { ASSERT_FALSE(it == generator.end()) << "At element " << i << " when accessing via an iterator " << "created with the assignment operator.\n"; EXPECT_TRUE(expected_values[i] == *it) << "where i is " << i << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; it++; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " << "created with the assignment operator.\n"; } template void VerifyGeneratorIsEmpty(const ParamGenerator& generator) { typename ParamGenerator::iterator it = generator.begin(); EXPECT_TRUE(it == generator.end()); it = generator.begin(); EXPECT_TRUE(it == generator.end()); } // Generator tests. They test that each of the provided generator functions // generates an expected sequence of values. The general test pattern // instantiates a generator using one of the generator functions, // checks the sequence produced by the generator using its iterator API, // and then resets the iterator back to the beginning of the sequence // and checks the sequence again. // Tests that iterators produced by generator functions conform to the // ForwardIterator concept. TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { const ParamGenerator gen = Range(0, 10); ParamGenerator::iterator it = gen.begin(); // Verifies that iterator initialization works as expected. ParamGenerator::iterator it2 = it; EXPECT_TRUE(*it == *it2) << "Initialized iterators must point to the " << "element same as its source points to"; // Verifies that iterator assignment works as expected. it++; EXPECT_FALSE(*it == *it2); it2 = it; EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the " << "element same as its source points to"; // Verifies that prefix operator++() returns *this. EXPECT_EQ(&it, &(++it)) << "Result of the prefix operator++ must be " << "refer to the original object"; // Verifies that the result of the postfix operator++ points to the value // pointed to by the original iterator. int original_value = *it; // Have to compute it outside of macro call to be // unaffected by the parameter evaluation order. EXPECT_EQ(original_value, *(it++)); // Verifies that prefix and postfix operator++() advance an iterator // all the same. it2 = it; it++; ++it2; EXPECT_TRUE(*it == *it2); } // Tests that Range() generates the expected sequence. TEST(RangeTest, IntRangeWithDefaultStep) { const ParamGenerator gen = Range(0, 3); const int expected_values[] = {0, 1, 2}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that Range() generates the single element sequence // as expected when provided with range limits that are equal. TEST(RangeTest, IntRangeSingleValue) { const ParamGenerator gen = Range(0, 1); const int expected_values[] = {0}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that Range() with generates empty sequence when // supplied with an empty range. TEST(RangeTest, IntRangeEmpty) { const ParamGenerator gen = Range(0, 0); VerifyGeneratorIsEmpty(gen); } // Tests that Range() with custom step (greater then one) generates // the expected sequence. TEST(RangeTest, IntRangeWithCustomStep) { const ParamGenerator gen = Range(0, 9, 3); const int expected_values[] = {0, 3, 6}; VerifyGenerator(gen, expected_values); } // Tests that Range() with custom step (greater then one) generates // the expected sequence when the last element does not fall on the // upper range limit. Sequences generated by Range() must not have // elements beyond the range limits. TEST(RangeTest, IntRangeWithCustomStepOverUpperBound) { const ParamGenerator gen = Range(0, 4, 3); const int expected_values[] = {0, 3}; VerifyGenerator(gen, expected_values); } // Verifies that Range works with user-defined types that define // copy constructor, operator=(), operator+(), and operator<(). class DogAdder { public: explicit DogAdder(const char* a_value) : value_(a_value) {} DogAdder(const DogAdder& other) : value_(other.value_.c_str()) {} DogAdder operator=(const DogAdder& other) { if (this != &other) value_ = other.value_; return *this; } DogAdder operator+(const DogAdder& other) const { Message msg; msg << value_.c_str() << other.value_.c_str(); return DogAdder(msg.GetString().c_str()); } bool operator<(const DogAdder& other) const { return value_ < other.value_; } const ::testing::internal::String& value() const { return value_; } private: ::testing::internal::String value_; }; TEST(RangeTest, WorksWithACustomType) { const ParamGenerator gen = Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog")); ParamGenerator::iterator it = gen.begin(); ASSERT_FALSE(it == gen.end()); EXPECT_STREQ("cat", it->value().c_str()); ASSERT_FALSE(++it == gen.end()); EXPECT_STREQ("catdog", it->value().c_str()); EXPECT_TRUE(++it == gen.end()); } class IntWrapper { public: explicit IntWrapper(int a_value) : value_(a_value) {} IntWrapper(const IntWrapper& other) : value_(other.value_) {} IntWrapper operator=(const IntWrapper& other) { value_ = other.value_; return *this; } // operator+() adds a different type. IntWrapper operator+(int other) const { return IntWrapper(value_ + other); } bool operator<(const IntWrapper& other) const { return value_ < other.value_; } int value() const { return value_; } private: int value_; }; TEST(RangeTest, WorksWithACustomTypeWithDifferentIncrementType) { const ParamGenerator gen = Range(IntWrapper(0), IntWrapper(2)); ParamGenerator::iterator it = gen.begin(); ASSERT_FALSE(it == gen.end()); EXPECT_EQ(0, it->value()); ASSERT_FALSE(++it == gen.end()); EXPECT_EQ(1, it->value()); EXPECT_TRUE(++it == gen.end()); } // Tests that ValuesIn() with an array parameter generates // the expected sequence. TEST(ValuesInTest, ValuesInArray) { int array[] = {3, 5, 8}; const ParamGenerator gen = ValuesIn(array); VerifyGenerator(gen, array); } // Tests that ValuesIn() with a const array parameter generates // the expected sequence. TEST(ValuesInTest, ValuesInConstArray) { const int array[] = {3, 5, 8}; const ParamGenerator gen = ValuesIn(array); VerifyGenerator(gen, array); } // Edge case. Tests that ValuesIn() with an array parameter containing a // single element generates the single element sequence. TEST(ValuesInTest, ValuesInSingleElementArray) { int array[] = {42}; const ParamGenerator gen = ValuesIn(array); VerifyGenerator(gen, array); } // Tests that ValuesIn() generates the expected sequence for an STL // container (vector). TEST(ValuesInTest, ValuesInVector) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(3); values.push_back(5); values.push_back(8); const ParamGenerator gen = ValuesIn(values); const int expected_values[] = {3, 5, 8}; VerifyGenerator(gen, expected_values); } // Tests that ValuesIn() generates the expected sequence. TEST(ValuesInTest, ValuesInIteratorRange) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(3); values.push_back(5); values.push_back(8); const ParamGenerator gen = ValuesIn(values.begin(), values.end()); const int expected_values[] = {3, 5, 8}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that ValuesIn() provided with an iterator range specifying a // single value generates a single-element sequence. TEST(ValuesInTest, ValuesInSingleElementIteratorRange) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(42); const ParamGenerator gen = ValuesIn(values.begin(), values.end()); const int expected_values[] = {42}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that ValuesIn() provided with an empty iterator range // generates an empty sequence. TEST(ValuesInTest, ValuesInEmptyIteratorRange) { typedef ::std::vector ContainerType; ContainerType values; const ParamGenerator gen = ValuesIn(values.begin(), values.end()); VerifyGeneratorIsEmpty(gen); } // Tests that the Values() generates the expected sequence. TEST(ValuesTest, ValuesWorks) { const ParamGenerator gen = Values(3, 5, 8); const int expected_values[] = {3, 5, 8}; VerifyGenerator(gen, expected_values); } // Tests that Values() generates the expected sequences from elements of // different types convertible to ParamGenerator's parameter type. TEST(ValuesTest, ValuesWorksForValuesOfCompatibleTypes) { const ParamGenerator gen = Values(3, 5.0f, 8.0); const double expected_values[] = {3.0, 5.0, 8.0}; VerifyGenerator(gen, expected_values); } TEST(ValuesTest, ValuesWorksForMaxLengthList) { const ParamGenerator gen = Values( 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500); const int expected_values[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500}; VerifyGenerator(gen, expected_values); } // Edge case test. Tests that single-parameter Values() generates the sequence // with the single value. TEST(ValuesTest, ValuesWithSingleParameter) { const ParamGenerator gen = Values(42); const int expected_values[] = {42}; VerifyGenerator(gen, expected_values); } // Tests that Bool() generates sequence (false, true). TEST(BoolTest, BoolWorks) { const ParamGenerator gen = Bool(); const bool expected_values[] = {false, true}; VerifyGenerator(gen, expected_values); } #if GTEST_HAS_COMBINE // Tests that Combine() with two parameters generates the expected sequence. TEST(CombineTest, CombineWithTwoParameters) { const char* foo = "foo"; const char* bar = "bar"; const ParamGenerator > gen = Combine(Values(foo, bar), Values(3, 4)); tuple expected_values[] = { make_tuple(foo, 3), make_tuple(foo, 4), make_tuple(bar, 3), make_tuple(bar, 4)}; VerifyGenerator(gen, expected_values); } // Tests that Combine() with three parameters generates the expected sequence. TEST(CombineTest, CombineWithThreeParameters) { const ParamGenerator > gen = Combine(Values(0, 1), Values(3, 4), Values(5, 6)); tuple expected_values[] = { make_tuple(0, 3, 5), make_tuple(0, 3, 6), make_tuple(0, 4, 5), make_tuple(0, 4, 6), make_tuple(1, 3, 5), make_tuple(1, 3, 6), make_tuple(1, 4, 5), make_tuple(1, 4, 6)}; VerifyGenerator(gen, expected_values); } // Tests that the Combine() with the first parameter generating a single value // sequence generates a sequence with the number of elements equal to the // number of elements in the sequence generated by the second parameter. TEST(CombineTest, CombineWithFirstParameterSingleValue) { const ParamGenerator > gen = Combine(Values(42), Values(0, 1)); tuple expected_values[] = {make_tuple(42, 0), make_tuple(42, 1)}; VerifyGenerator(gen, expected_values); } // Tests that the Combine() with the second parameter generating a single value // sequence generates a sequence with the number of elements equal to the // number of elements in the sequence generated by the first parameter. TEST(CombineTest, CombineWithSecondParameterSingleValue) { const ParamGenerator > gen = Combine(Values(0, 1), Values(42)); tuple expected_values[] = {make_tuple(0, 42), make_tuple(1, 42)}; VerifyGenerator(gen, expected_values); } // Tests that when the first parameter produces an empty sequence, // Combine() produces an empty sequence, too. TEST(CombineTest, CombineWithFirstParameterEmptyRange) { const ParamGenerator > gen = Combine(Range(0, 0), Values(0, 1)); VerifyGeneratorIsEmpty(gen); } // Tests that when the second parameter produces an empty sequence, // Combine() produces an empty sequence, too. TEST(CombineTest, CombineWithSecondParameterEmptyRange) { const ParamGenerator > gen = Combine(Values(0, 1), Range(1, 1)); VerifyGeneratorIsEmpty(gen); } // Edge case. Tests that combine works with the maximum number // of parameters supported by Google Test (currently 10). TEST(CombineTest, CombineWithMaxNumberOfParameters) { const char* foo = "foo"; const char* bar = "bar"; const ParamGenerator > gen = Combine(Values(foo, bar), Values(1), Values(2), Values(3), Values(4), Values(5), Values(6), Values(7), Values(8), Values(9)); tuple expected_values[] = {make_tuple(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9), make_tuple(bar, 1, 2, 3, 4, 5, 6, 7, 8, 9)}; VerifyGenerator(gen, expected_values); } #endif // GTEST_HAS_COMBINE // Tests that an generator produces correct sequence after being // assigned from another generator. TEST(ParamGeneratorTest, AssignmentWorks) { ParamGenerator gen = Values(1, 2); const ParamGenerator gen2 = Values(3, 4); gen = gen2; const int expected_values[] = {3, 4}; VerifyGenerator(gen, expected_values); } // This test verifies that the tests are expanded and run as specified: // one test per element from the sequence produced by the generator // specified in INSTANTIATE_TEST_CASE_P. It also verifies that the test's // fixture constructor, SetUp(), and TearDown() have run and have been // supplied with the correct parameters. // The use of environment object allows detection of the case where no test // case functionality is run at all. In this case TestCaseTearDown will not // be able to detect missing tests, naturally. template class TestGenerationEnvironment : public ::testing::Environment { public: static TestGenerationEnvironment* Instance() { static TestGenerationEnvironment* instance = new TestGenerationEnvironment; return instance; } void FixtureConstructorExecuted() { fixture_constructor_count_++; } void SetUpExecuted() { set_up_count_++; } void TearDownExecuted() { tear_down_count_++; } void TestBodyExecuted() { test_body_count_++; } virtual void TearDown() { // If all MultipleTestGenerationTest tests have been de-selected // by the filter flag, the following checks make no sense. bool perform_check = false; for (int i = 0; i < kExpectedCalls; ++i) { Message msg; msg << "TestsExpandedAndRun/" << i; if (UnitTestOptions::FilterMatchesTest( "TestExpansionModule/MultipleTestGenerationTest", msg.GetString().c_str())) { perform_check = true; } } if (perform_check) { EXPECT_EQ(kExpectedCalls, fixture_constructor_count_) << "Fixture constructor of ParamTestGenerationTest test case " << "has not been run as expected."; EXPECT_EQ(kExpectedCalls, set_up_count_) << "Fixture SetUp method of ParamTestGenerationTest test case " << "has not been run as expected."; EXPECT_EQ(kExpectedCalls, tear_down_count_) << "Fixture TearDown method of ParamTestGenerationTest test case " << "has not been run as expected."; EXPECT_EQ(kExpectedCalls, test_body_count_) << "Test in ParamTestGenerationTest test case " << "has not been run as expected."; } } private: TestGenerationEnvironment() : fixture_constructor_count_(0), set_up_count_(0), tear_down_count_(0), test_body_count_(0) {} int fixture_constructor_count_; int set_up_count_; int tear_down_count_; int test_body_count_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationEnvironment); }; const int test_generation_params[] = {36, 42, 72}; class TestGenerationTest : public TestWithParam { public: enum { PARAMETER_COUNT = sizeof(test_generation_params)/sizeof(test_generation_params[0]) }; typedef TestGenerationEnvironment Environment; TestGenerationTest() { Environment::Instance()->FixtureConstructorExecuted(); current_parameter_ = GetParam(); } virtual void SetUp() { Environment::Instance()->SetUpExecuted(); EXPECT_EQ(current_parameter_, GetParam()); } virtual void TearDown() { Environment::Instance()->TearDownExecuted(); EXPECT_EQ(current_parameter_, GetParam()); } static void SetUpTestCase() { bool all_tests_in_test_case_selected = true; for (int i = 0; i < PARAMETER_COUNT; ++i) { Message test_name; test_name << "TestsExpandedAndRun/" << i; if ( !UnitTestOptions::FilterMatchesTest( "TestExpansionModule/MultipleTestGenerationTest", test_name.GetString())) { all_tests_in_test_case_selected = false; } } EXPECT_TRUE(all_tests_in_test_case_selected) << "When running the TestGenerationTest test case all of its tests\n" << "must be selected by the filter flag for the test case to pass.\n" << "If not all of them are enabled, we can't reliably conclude\n" << "that the correct number of tests have been generated."; collected_parameters_.clear(); } static void TearDownTestCase() { vector expected_values(test_generation_params, test_generation_params + PARAMETER_COUNT); // Test execution order is not guaranteed by Google Test, // so the order of values in collected_parameters_ can be // different and we have to sort to compare. sort(expected_values.begin(), expected_values.end()); sort(collected_parameters_.begin(), collected_parameters_.end()); EXPECT_TRUE(collected_parameters_ == expected_values); } protected: int current_parameter_; static vector collected_parameters_; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest); }; vector TestGenerationTest::collected_parameters_; TEST_P(TestGenerationTest, TestsExpandedAndRun) { Environment::Instance()->TestBodyExecuted(); EXPECT_EQ(current_parameter_, GetParam()); collected_parameters_.push_back(GetParam()); } INSTANTIATE_TEST_CASE_P(TestExpansionModule, TestGenerationTest, ValuesIn(test_generation_params)); // This test verifies that the element sequence (third parameter of // INSTANTIATE_TEST_CASE_P) is evaluated in InitGoogleTest() and neither at // the call site of INSTANTIATE_TEST_CASE_P nor in RUN_ALL_TESTS(). For // that, we declare param_value_ to be a static member of // GeneratorEvaluationTest and initialize it to 0. We set it to 1 in // main(), just before invocation of InitGoogleTest(). After calling // InitGoogleTest(), we set the value to 2. If the sequence is evaluated // before or after InitGoogleTest, INSTANTIATE_TEST_CASE_P will create a // test with parameter other than 1, and the test body will fail the // assertion. class GeneratorEvaluationTest : public TestWithParam { public: static int param_value() { return param_value_; } static void set_param_value(int param_value) { param_value_ = param_value; } private: static int param_value_; }; int GeneratorEvaluationTest::param_value_ = 0; TEST_P(GeneratorEvaluationTest, GeneratorsEvaluatedInMain) { EXPECT_EQ(1, GetParam()); } INSTANTIATE_TEST_CASE_P(GenEvalModule, GeneratorEvaluationTest, Values(GeneratorEvaluationTest::param_value())); // Tests that generators defined in a different translation unit are // functional. Generator extern_gen is defined in gtest-param-test_test2.cc. extern ParamGenerator extern_gen; class ExternalGeneratorTest : public TestWithParam {}; TEST_P(ExternalGeneratorTest, ExternalGenerator) { // Sequence produced by extern_gen contains only a single value // which we verify here. EXPECT_EQ(GetParam(), 33); } INSTANTIATE_TEST_CASE_P(ExternalGeneratorModule, ExternalGeneratorTest, extern_gen); // Tests that a parameterized test case can be defined in one translation // unit and instantiated in another. This test will be instantiated in // gtest-param-test_test2.cc. ExternalInstantiationTest fixture class is // defined in gtest-param-test_test.h. TEST_P(ExternalInstantiationTest, IsMultipleOf33) { EXPECT_EQ(0, GetParam() % 33); } // Tests that a parameterized test case can be instantiated with multiple // generators. class MultipleInstantiationTest : public TestWithParam {}; TEST_P(MultipleInstantiationTest, AllowsMultipleInstances) { } INSTANTIATE_TEST_CASE_P(Sequence1, MultipleInstantiationTest, Values(1, 2)); INSTANTIATE_TEST_CASE_P(Sequence2, MultipleInstantiationTest, Range(3, 5)); // Tests that a parameterized test case can be instantiated // in multiple translation units. This test will be instantiated // here and in gtest-param-test_test2.cc. // InstantiationInMultipleTranslationUnitsTest fixture class // is defined in gtest-param-test_test.h. TEST_P(InstantiationInMultipleTranslaionUnitsTest, IsMultipleOf42) { EXPECT_EQ(0, GetParam() % 42); } INSTANTIATE_TEST_CASE_P(Sequence1, InstantiationInMultipleTranslaionUnitsTest, Values(42, 42*2)); // Tests that each iteration of parameterized test runs in a separate test // object. class SeparateInstanceTest : public TestWithParam { public: SeparateInstanceTest() : count_(0) {} static void TearDownTestCase() { EXPECT_GE(global_count_, 2) << "If some (but not all) SeparateInstanceTest tests have been " << "filtered out this test will fail. Make sure that all " << "GeneratorEvaluationTest are selected or de-selected together " << "by the test filter."; } protected: int count_; static int global_count_; }; int SeparateInstanceTest::global_count_ = 0; TEST_P(SeparateInstanceTest, TestsRunInSeparateInstances) { EXPECT_EQ(0, count_++); global_count_++; } INSTANTIATE_TEST_CASE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4)); // Tests that all instantiations of a test have named appropriately. Test // defined with TEST_P(TestCaseName, TestName) and instantiated with // INSTANTIATE_TEST_CASE_P(SequenceName, TestCaseName, generator) must be named // SequenceName/TestCaseName.TestName/i, where i is the 0-based index of the // sequence element used to instantiate the test. class NamingTest : public TestWithParam {}; TEST_P(NamingTest, TestsAreNamedAppropriately) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name()); Message msg; msg << "TestsAreNamedAppropriately/" << GetParam(); EXPECT_STREQ(msg.GetString().c_str(), test_info->name()); } INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5)); #endif // GTEST_HAS_PARAM_TEST TEST(CompileTest, CombineIsDefinedOnlyWhenGtestHasParamTestIsDefined) { #if GTEST_HAS_COMBINE && !GTEST_HAS_PARAM_TEST FAIL() << "GTEST_HAS_COMBINE is defined while GTEST_HAS_PARAM_TEST is not\n" #endif } int main(int argc, char **argv) { #if GTEST_HAS_PARAM_TEST // Used in TestGenerationTest test case. AddGlobalTestEnvironment(TestGenerationTest::Environment::Instance()); // Used in GeneratorEvaluationTest test case. Tests that the updated value // will be picked up for instantiating tests in GeneratorEvaluationTest. GeneratorEvaluationTest::set_param_value(1); #endif // GTEST_HAS_PARAM_TEST ::testing::InitGoogleTest(&argc, argv); #if GTEST_HAS_PARAM_TEST // Used in GeneratorEvaluationTest test case. Tests that value updated // here will NOT be used for instantiating tests in // GeneratorEvaluationTest. GeneratorEvaluationTest::set_param_value(2); #endif // GTEST_HAS_PARAM_TEST return RUN_ALL_TESTS(); } ceph-0.80.11/src/gtest/test/gtest_list_tests_unittest.py0000775000175100017510000001244712623076744025520 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2006, Google Inc. # 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. """Unit test for Google Test's --gtest_list_tests flag. A user can ask Google Test to list all tests by specifying the --gtest_list_tests flag. This script tests such functionality by invoking gtest_list_tests_unittest_ (a program written with Google Test) the command line flags. """ __author__ = 'phanna@google.com (Patrick Hanna)' import gtest_test_utils # Constants. # The command line flag for enabling/disabling listing all tests. LIST_TESTS_FLAG = 'gtest_list_tests' # Path to the gtest_list_tests_unittest_ program. EXE_PATH = gtest_test_utils.GetTestExecutablePath('gtest_list_tests_unittest_') # The expected output when running gtest_list_tests_unittest_ with # --gtest_list_tests EXPECTED_OUTPUT_NO_FILTER = """FooDeathTest. Test1 Foo. Bar1 Bar2 DISABLED_Bar3 Abc. Xyz Def FooBar. Baz FooTest. Test1 DISABLED_Test2 Test3 """ # The expected output when running gtest_list_tests_unittest_ with # --gtest_list_tests and --gtest_filter=Foo*. EXPECTED_OUTPUT_FILTER_FOO = """FooDeathTest. Test1 Foo. Bar1 Bar2 DISABLED_Bar3 FooBar. Baz FooTest. Test1 DISABLED_Test2 Test3 """ # Utilities. def Run(args): """Runs gtest_list_tests_unittest_ and returns the list of tests printed.""" return gtest_test_utils.Subprocess([EXE_PATH] + args, capture_stderr=False).output # The unit test. class GTestListTestsUnitTest(gtest_test_utils.TestCase): """Tests using the --gtest_list_tests flag to list all tests.""" def RunAndVerify(self, flag_value, expected_output, other_flag): """Runs gtest_list_tests_unittest_ and verifies that it prints the correct tests. Args: flag_value: value of the --gtest_list_tests flag; None if the flag should not be present. expected_output: the expected output after running command; other_flag: a different flag to be passed to command along with gtest_list_tests; None if the flag should not be present. """ if flag_value is None: flag = '' flag_expression = 'not set' elif flag_value == '0': flag = '--%s=0' % LIST_TESTS_FLAG flag_expression = '0' else: flag = '--%s' % LIST_TESTS_FLAG flag_expression = '1' args = [flag] if other_flag is not None: args += [other_flag] output = Run(args) msg = ('when %s is %s, the output of "%s" is "%s".' % (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output)) if expected_output is not None: self.assert_(output == expected_output, msg) else: self.assert_(output != EXPECTED_OUTPUT_NO_FILTER, msg) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(flag_value=None, expected_output=None, other_flag=None) def testFlag(self): """Tests using the --gtest_list_tests flag.""" self.RunAndVerify(flag_value='0', expected_output=None, other_flag=None) self.RunAndVerify(flag_value='1', expected_output=EXPECTED_OUTPUT_NO_FILTER, other_flag=None) def testOverrideNonFilterFlags(self): """Tests that --gtest_list_tests overrides the non-filter flags.""" self.RunAndVerify(flag_value='1', expected_output=EXPECTED_OUTPUT_NO_FILTER, other_flag='--gtest_break_on_failure') def testWithFilterFlags(self): """Tests that --gtest_list_tests takes into account the --gtest_filter flag.""" self.RunAndVerify(flag_value='1', expected_output=EXPECTED_OUTPUT_FILTER_FOO, other_flag='--gtest_filter=Foo*') if __name__ == '__main__': gtest_test_utils.Main() ceph-0.80.11/src/gtest/COPYING0000664000175100017510000000270312623076744017647 0ustar jenkins-buildjenkins-buildCopyright 2008, Google Inc. 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. ceph-0.80.11/src/gtest/CHANGES0000664000175100017510000000730012623076744017605 0ustar jenkins-buildjenkins-buildChanges for 1.5.0: * New feature: assertions can be safely called in multiple threads where the pthreads library is available. * New feature: predicates used inside EXPECT_TRUE() and friends can now generate custom failure messages. * New feature: Google Test can now be compiled as a DLL. * New feature: fused source files are included. * New feature: prints help when encountering unrecognized Google Test flags. * Experimental feature: CMake build script (requires CMake 2.6.4+). * Experimental feature: the Pump script for meta programming. * double values streamed to an assertion are printed with enough precision to differentiate any two different values. * Google Test now works on Solaris and AIX. * Build and test script improvements. * Bug fixes and implementation clean-ups. Potentially breaking changes: * Stopped supporting VC++ 7.1 with exceptions disabled. * Dropped support for 'make install'. Changes for 1.4.0: * New feature: the event listener API * New feature: test shuffling * New feature: the XML report format is closer to junitreport and can be parsed by Hudson now. * New feature: when a test runs under Visual Studio, its failures are integrated in the IDE. * New feature: /MD(d) versions of VC++ projects. * New feature: elapsed time for the tests is printed by default. * New feature: comes with a TR1 tuple implementation such that Boost is no longer needed for Combine(). * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends. * New feature: the Xcode project can now produce static gtest libraries in addition to a framework. * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile, Symbian, gcc, and C++Builder. * Bug fixes and implementation clean-ups. Changes for 1.3.0: * New feature: death tests on Windows, Cygwin, and Mac. * New feature: ability to use Google Test assertions in other testing frameworks. * New feature: ability to run disabled test via --gtest_also_run_disabled_tests. * New feature: the --help flag for printing the usage. * New feature: access to Google Test flag values in user code. * New feature: a script that packs Google Test into one .h and one .cc file for easy deployment. * New feature: support for distributing test functions to multiple machines (requires support from the test runner). * Bug fixes and implementation clean-ups. Changes for 1.2.1: * Compatibility fixes for Linux IA-64 and IBM z/OS. * Added support for using Boost and other TR1 implementations. * Changes to the build scripts to support upcoming release of Google C++ Mocking Framework. * Added Makefile to the distribution package. * Improved build instructions in README. Changes for 1.2.0: * New feature: value-parameterized tests. * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS) macros. * Changed the XML report format to match JUnit/Ant's. * Added tests to the Xcode project. * Added scons/SConscript for building with SCons. * Added src/gtest-all.cc for building Google Test from a single file. * Fixed compatibility with Solaris and z/OS. * Enabled running Python tests on systems with python 2.3 installed, e.g. Mac OS X 10.4. * Bug fixes. Changes for 1.1.0: * New feature: type-parameterized tests. * New feature: exception assertions. * New feature: printing elapsed time of tests. * Improved the robustness of death tests. * Added an Xcode project and samples. * Adjusted the output format on Windows to be understandable by Visual Studio. * Minor bug fixes. Changes for 1.0.1: * Added project files for Visual Studio 7.1. * Fixed issues with compiling on Mac OS X. * Fixed issues with compiling on Cygwin. Changes for 1.0.0: * Initial Open Source release of Google Test ceph-0.80.11/src/gtest/xcode/0000775000175100017510000000000012623077036017707 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Config/0000775000175100017510000000000012623077036021114 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Config/StaticLibraryTarget.xcconfig0000664000175100017510000000111312623076744026562 0ustar jenkins-buildjenkins-build// // StaticLibraryTarget.xcconfig // // These are static library target settings for libgtest.a. It // is set in the "Based On:" dropdown in the "Target" info dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // // Static libs can be included in bundles so make them position independent GCC_DYNAMIC_NO_PIC = NO // Static libs should not have their internal globals or external symbols // stripped. STRIP_STYLE = debugging // Let the user install by specifying the $DSTROOT with xcodebuild SKIP_INSTALL = NO ceph-0.80.11/src/gtest/xcode/Config/General.xcconfig0000664000175100017510000000225712623076744024226 0ustar jenkins-buildjenkins-build// // General.xcconfig // // These are General configuration settings for the gtest framework and // examples. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // // Build for PPC and Intel, 32- and 64-bit ARCHS = i386 x86_64 ppc ppc64 // Zerolink prevents link warnings so turn it off ZERO_LINK = NO // Prebinding considered unhelpful in 10.3 and later PREBINDING = NO // Strictest warning policy WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof -Wno-sign-compare -Wshadow // Work around Xcode bugs by using external strip. See: // http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html SEPARATE_STRIP = YES // Force C99 dialect GCC_C_LANGUAGE_STANDARD = c99 // not sure why apple defaults this on, but it's pretty risky ALWAYS_SEARCH_USER_PATHS = NO // Turn on position dependent code for most cases (overridden where appropriate) GCC_DYNAMIC_NO_PIC = YES // Default SDK and minimum OS version is 10.4 SDKROOT = $(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk MACOSX_DEPLOYMENT_TARGET = 10.4 GCC_VERSION = 4.0 // VERSIONING BUILD SETTINGS (used in Info.plist) GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc. ceph-0.80.11/src/gtest/xcode/Config/TestTarget.xcconfig0000664000175100017510000000035612623076744024735 0ustar jenkins-buildjenkins-build// // TestTarget.xcconfig // // These are Test target settings for the gtest framework and examples. It // is set in the "Based On:" dropdown in the "Target" info dialog. PRODUCT_NAME = $(TARGET_NAME) HEADER_SEARCH_PATHS = ../include ceph-0.80.11/src/gtest/xcode/Config/FrameworkTarget.xcconfig0000664000175100017510000000104712623076744025751 0ustar jenkins-buildjenkins-build// // FrameworkTarget.xcconfig // // These are Framework target settings for the gtest framework and examples. It // is set in the "Based On:" dropdown in the "Target" info dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // // Dynamic libs need to be position independent GCC_DYNAMIC_NO_PIC = NO // Dynamic libs should not have their external symbols stripped. STRIP_STYLE = non-global // Let the user install by specifying the $DSTROOT with xcodebuild SKIP_INSTALL = NO ceph-0.80.11/src/gtest/xcode/Config/DebugProject.xcconfig0000664000175100017510000000172712623076744025227 0ustar jenkins-buildjenkins-build// // DebugProject.xcconfig // // These are Debug Configuration project settings for the gtest framework and // examples. It is set in the "Based On:" dropdown in the "Project" info // dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // #include "General.xcconfig" // No optimization GCC_OPTIMIZATION_LEVEL = 0 // Deployment postprocessing is what triggers Xcode to strip, turn it off DEPLOYMENT_POSTPROCESSING = NO // Dead code stripping off DEAD_CODE_STRIPPING = NO // Debug symbols should be on obviously GCC_GENERATE_DEBUGGING_SYMBOLS = YES // Define the DEBUG macro in all debug builds OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1 // These are turned off to avoid STL incompatibilities with client code // // Turns on special C++ STL checks to "encourage" good STL use // GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS ceph-0.80.11/src/gtest/xcode/Config/ReleaseProject.xcconfig0000664000175100017510000000174112623076744025555 0ustar jenkins-buildjenkins-build// // ReleaseProject.xcconfig // // These are Release Configuration project settings for the gtest framework // and examples. It is set in the "Based On:" dropdown in the "Project" info // dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // #include "General.xcconfig" // subconfig/Release.xcconfig // Optimize for space and size (Apple recommendation) GCC_OPTIMIZATION_LEVEL = s // Deploment postprocessing is what triggers Xcode to strip DEPLOYMENT_POSTPROCESSING = YES // No symbols GCC_GENERATE_DEBUGGING_SYMBOLS = NO // Dead code strip does not affect ObjC code but can help for C DEAD_CODE_STRIPPING = YES // NDEBUG is used by things like assert.h, so define it for general compat. // ASSERT going away in release tends to create unused vars. OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable // When we strip we want to strip all symbols in release, but save externals. STRIP_STYLE = all ceph-0.80.11/src/gtest/xcode/Scripts/0000775000175100017510000000000012623077036021336 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Scripts/versiongenerate.py0000664000175100017510000001067012623076744025121 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright 2008, Google Inc. # 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. """A script to prepare version informtion for use the gtest Info.plist file. This script extracts the version information from the configure.ac file and uses it to generate a header file containing the same information. The #defines in this header file will be included in during the generation of the Info.plist of the framework, giving the correct value to the version shown in the Finder. This script makes the following assumptions (these are faults of the script, not problems with the Autoconf): 1. The AC_INIT macro will be contained within the first 1024 characters of configure.ac 2. The version string will be 3 integers separated by periods and will be surrounded by squre brackets, "[" and "]" (e.g. [1.0.1]). The first segment represents the major version, the second represents the minor version and the third represents the fix version. 3. No ")" character exists between the opening "(" and closing ")" of AC_INIT, including in comments and character strings. """ import sys import re # Read the command line argument (the output directory for Version.h) if (len(sys.argv) < 3): print "Usage: versiongenerate.py input_dir output_dir" sys.exit(1) else: input_dir = sys.argv[1] output_dir = sys.argv[2] # Read the first 1024 characters of the configure.ac file config_file = open("%s/configure.ac" % input_dir, 'r') buffer_size = 1024 opening_string = config_file.read(buffer_size) config_file.close() # Extract the version string from the AC_INIT macro # The following init_expression means: # Extract three integers separated by periods and surrounded by squre # brackets(e.g. "[1.0.1]") between "AC_INIT(" and ")". Do not be greedy # (*? is the non-greedy flag) since that would pull in everything between # the first "(" and the last ")" in the file. version_expression = re.compile(r"AC_INIT\(.*?\[(\d+)\.(\d+)\.(\d+)\].*?\)", re.DOTALL) version_values = version_expression.search(opening_string) major_version = version_values.group(1) minor_version = version_values.group(2) fix_version = version_values.group(3) # Write the version information to a header file to be included in the # Info.plist file. file_data = """// // DO NOT MODIFY THIS FILE (but you can delete it) // // This file is autogenerated by the versiongenerate.py script. This script // is executed in a "Run Script" build phase when creating gtest.framework. This // header file is not used during compilation of C-source. Rather, it simply // defines some version strings for substitution in the Info.plist. Because of // this, we are not not restricted to C-syntax nor are we using include guards. // #define GTEST_VERSIONINFO_SHORT %s.%s #define GTEST_VERSIONINFO_LONG %s.%s.%s """ % (major_version, minor_version, major_version, minor_version, fix_version) version_file = open("%s/Version.h" % output_dir, 'w') version_file.write(file_data) version_file.close() ceph-0.80.11/src/gtest/xcode/Scripts/runtests.sh0000664000175100017510000000503312623076744023567 0ustar jenkins-buildjenkins-build#!/bin/bash # # Copyright 2008, Google Inc. # 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. # Executes the samples and tests for the Google Test Framework. # Help the dynamic linker find the path to the libraries. export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR # Create some executables. test_executables=("$BUILT_PRODUCTS_DIR/gtest_unittest-framework" "$BUILT_PRODUCTS_DIR/gtest_unittest" "$BUILT_PRODUCTS_DIR/sample1_unittest-framework" "$BUILT_PRODUCTS_DIR/sample1_unittest-static") # Now execute each one in turn keeping track of how many succeeded and failed. succeeded=0 failed=0 failed_list=() for test in ${test_executables[*]}; do "$test" result=$? if [ $result -eq 0 ]; then succeeded=$(( $succeeded + 1 )) else failed=$(( failed + 1 )) failed_list="$failed_list $test" fi done # Report the successes and failures to the console. echo "Tests complete with $succeeded successes and $failed failures." if [ $failed -ne 0 ]; then echo "The following tests failed:" echo $failed_list fi exit $failed ceph-0.80.11/src/gtest/xcode/Samples/0000775000175100017510000000000012623077036021313 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/0000775000175100017510000000000012623077036024412 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/widget_test.cc0000664000175100017510000000515512623076744027256 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: preston.a.jackson@gmail.com (Preston Jackson) // // Google Test - FrameworkSample // widget_test.cc // // This is a simple test file for the Widget class in the Widget.framework #include #include #include // This test verifies that the constructor sets the internal state of the // Widget class correctly. TEST(WidgetInitializerTest, TestConstructor) { Widget widget(1.0f, "name"); EXPECT_FLOAT_EQ(1.0f, widget.GetFloatValue()); EXPECT_EQ(std::string("name"), widget.GetStringValue()); } // This test verifies the conversion of the float and string values to int and // char*, respectively. TEST(WidgetInitializerTest, TestConversion) { Widget widget(1.0f, "name"); EXPECT_EQ(1, widget.GetIntValue()); size_t max_size = 128; char buffer[max_size]; widget.GetCharPtrValue(buffer, max_size); EXPECT_STREQ("name", buffer); } // Use the Google Test main that is linked into the framework. It does something // like this: // int main(int argc, char** argv) { // testing::InitGoogleTest(&argc, argv); // return RUN_ALL_TESTS(); // } ceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/Info.plist0000664000175100017510000000151612623076744026372 0ustar jenkins-buildjenkins-build CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.google.gtest.${PRODUCT_NAME:identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 CSResourcesFileMapped ceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/widget.h0000664000175100017510000000433612623076744026061 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: preston.a.jackson@gmail.com (Preston Jackson) // // Google Test - FrameworkSample // widget.h // // Widget is a very simple class used for demonstrating the use of gtest. It // simply stores two values a string and an integer, which are returned via // public accessors in multiple forms. #import class Widget { public: Widget(int number, const std::string& name); ~Widget(); // Public accessors to number data float GetFloatValue() const; int GetIntValue() const; // Public accessors to the string data std::string GetStringValue() const; void GetCharPtrValue(char* buffer, size_t max_size) const; private: // Data members float number_; std::string name_; }; ceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/runtests.sh0000664000175100017510000000446212623076744026650 0ustar jenkins-buildjenkins-build#!/bin/bash # # Copyright 2008, Google Inc. # 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. # Executes the samples and tests for the Google Test Framework. # Help the dynamic linker find the path to the libraries. export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR # Create some executables. test_executables=$@ # Now execute each one in turn keeping track of how many succeeded and failed. succeeded=0 failed=0 failed_list=() for test in ${test_executables[*]}; do "$test" result=$? if [ $result -eq 0 ]; then succeeded=$(( $succeeded + 1 )) else failed=$(( failed + 1 )) failed_list="$failed_list $test" fi done # Report the successes and failures to the console. echo "Tests complete with $succeeded successes and $failed failures." if [ $failed -ne 0 ]; then echo "The following tests failed:" echo $failed_list fi exit $failed ceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/0000775000175100017510000000000012623077036031507 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj0000664000175100017510000003727412623076744034605 0ustar jenkins-buildjenkins-build// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXAggregateTarget section */ 4024D162113D7D2400C7059E /* Test */ = { isa = PBXAggregateTarget; buildConfigurationList = 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */; buildPhases = ( 4024D161113D7D2400C7059E /* ShellScript */, ); dependencies = ( 4024D166113D7D3100C7059E /* PBXTargetDependency */, ); name = Test; productName = TestAndBuild; }; 4024D1E9113D83FF00C7059E /* TestAndBuild */ = { isa = PBXAggregateTarget; buildConfigurationList = 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */; buildPhases = ( ); dependencies = ( 4024D1ED113D840900C7059E /* PBXTargetDependency */, 4024D1EF113D840D00C7059E /* PBXTargetDependency */, ); name = TestAndBuild; productName = TestAndBuild; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1230E5AEE3500C7F239 /* widget.cc */; }; 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7EB1240E5AEE3500C7F239 /* widget.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */; }; 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; }; 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D185113D7D5500C7059E /* libgtest.a */; }; 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D183113D7D5500C7059E /* libgtest_main.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = gTestExample; }; 4024D165113D7D3100C7059E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 3B07BDE90E3F3F9E00647869; remoteInfo = WidgetFrameworkTest; }; 4024D1EC113D840900C7059E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = WidgetFramework; }; 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 4024D162113D7D2400C7059E; remoteInfo = Test; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WidgetFrameworkTest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B7EB1230E5AEE3500C7F239 /* widget.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget.cc; sourceTree = ""; }; 3B7EB1240E5AEE3500C7F239 /* widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = widget.h; sourceTree = ""; }; 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget_test.cc; sourceTree = ""; }; 4024D183113D7D5500C7059E /* libgtest_main.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest_main.a; path = /usr/local/lib/libgtest_main.a; sourceTree = ""; }; 4024D185113D7D5500C7059E /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest.a; path = /usr/local/lib/libgtest.a; sourceTree = ""; }; 4024D1E2113D838200C7059E /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D07F2C80486CC7A007CD1D0 /* Widget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Widget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 3B07BDE80E3F3F9E00647869 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */, 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */, 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 034768DDFF38A45A11DB9C8B /* Products */ = { isa = PBXGroup; children = ( 8D07F2C80486CC7A007CD1D0 /* Widget.framework */, 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */, ); name = Products; sourceTree = ""; }; 0867D691FE84028FC02AAC07 /* gTestExample */ = { isa = PBXGroup; children = ( 4024D1E1113D836C00C7059E /* Scripts */, 08FB77ACFE841707C02AAC07 /* Source */, 089C1665FE841158C02AAC07 /* Resources */, 3B07BE350E4094E400647869 /* Test */, 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, 034768DDFF38A45A11DB9C8B /* Products */, ); name = gTestExample; sourceTree = ""; }; 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { isa = PBXGroup; children = ( 4024D183113D7D5500C7059E /* libgtest_main.a */, 4024D185113D7D5500C7059E /* libgtest.a */, ); name = "External Frameworks and Libraries"; sourceTree = ""; }; 089C1665FE841158C02AAC07 /* Resources */ = { isa = PBXGroup; children = ( 8D07F2C70486CC7A007CD1D0 /* Info.plist */, ); name = Resources; sourceTree = ""; }; 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( 3B7EB1230E5AEE3500C7F239 /* widget.cc */, 3B7EB1240E5AEE3500C7F239 /* widget.h */, ); name = Source; sourceTree = ""; }; 3B07BE350E4094E400647869 /* Test */ = { isa = PBXGroup; children = ( 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */, ); name = Test; sourceTree = ""; }; 4024D1E1113D836C00C7059E /* Scripts */ = { isa = PBXGroup; children = ( 4024D1E2113D838200C7059E /* runtests.sh */, ); name = Scripts; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */ = { isa = PBXNativeTarget; buildConfigurationList = 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */; buildPhases = ( 3B07BDE70E3F3F9E00647869 /* Sources */, 3B07BDE80E3F3F9E00647869 /* Frameworks */, ); buildRules = ( ); dependencies = ( 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */, ); name = WidgetFrameworkTest; productName = gTestExampleTest; productReference = 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */; productType = "com.apple.product-type.tool"; }; 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */ = { isa = PBXNativeTarget; buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */; buildPhases = ( 8D07F2C10486CC7A007CD1D0 /* Sources */, 8D07F2C30486CC7A007CD1D0 /* Frameworks */, 8D07F2BD0486CC7A007CD1D0 /* Headers */, 8D07F2BF0486CC7A007CD1D0 /* Resources */, 8D07F2C50486CC7A007CD1D0 /* Rez */, ); buildRules = ( ); dependencies = ( ); name = WidgetFramework; productInstallPath = "$(HOME)/Library/Frameworks"; productName = gTestExample; productReference = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */; compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 0867D691FE84028FC02AAC07 /* gTestExample */; productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */, 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */, 4024D162113D7D2400C7059E /* Test */, 4024D1E9113D83FF00C7059E /* TestAndBuild */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXRezBuildPhase section */ 8D07F2C50486CC7A007CD1D0 /* Rez */ = { isa = PBXRezBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXRezBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 4024D161113D7D2400C7059E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/bash $SRCROOT/runtests.sh $BUILT_PRODUCTS_DIR/WidgetFrameworkTest\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 3B07BDE70E3F3F9E00647869 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D07F2C10486CC7A007CD1D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */; targetProxy = 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */; }; 4024D166113D7D3100C7059E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */; targetProxy = 4024D165113D7D3100C7059E /* PBXContainerItemProxy */; }; 4024D1ED113D840900C7059E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */; targetProxy = 4024D1EC113D840900C7059E /* PBXContainerItemProxy */; }; 4024D1EF113D840D00C7059E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4024D162113D7D2400C7059E /* Test */; targetProxy = 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 3B07BDEC0E3F3F9F00647869 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = WidgetFrameworkTest; }; name = Debug; }; 3B07BDED0E3F3F9F00647869 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = WidgetFrameworkTest; }; name = Release; }; 4024D163113D7D2400C7059E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Debug; }; 4024D164113D7D2400C7059E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Release; }; 4024D1EA113D83FF00C7059E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Debug; }; 4024D1EB113D83FF00C7059E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Release; }; 4FADC24308B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "@loader_path/../Frameworks"; PRODUCT_NAME = Widget; }; name = Debug; }; 4FADC24408B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "@loader_path/../Frameworks"; PRODUCT_NAME = Widget; }; name = Release; }; 4FADC24708B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = 4.0; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = Debug; }; 4FADC24808B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = 4.0; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */ = { isa = XCConfigurationList; buildConfigurations = ( 3B07BDEC0E3F3F9F00647869 /* Debug */, 3B07BDED0E3F3F9F00647869 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */ = { isa = XCConfigurationList; buildConfigurations = ( 4024D163113D7D2400C7059E /* Debug */, 4024D164113D7D2400C7059E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */ = { isa = XCConfigurationList; buildConfigurations = ( 4024D1EA113D83FF00C7059E /* Debug */, 4024D1EB113D83FF00C7059E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24308B4156D00ABE55E /* Debug */, 4FADC24408B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24708B4156D00ABE55E /* Debug */, 4FADC24808B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; } ceph-0.80.11/src/gtest/xcode/Samples/FrameworkSample/widget.cc0000664000175100017510000000440312623076744026212 0ustar jenkins-buildjenkins-build// Copyright 2008, Google Inc. // 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. // // Author: preston.a.jackson@gmail.com (Preston Jackson) // // Google Test - FrameworkSample // widget.cc // // Widget is a very simple class used for demonstrating the use of gtest #include "widget.h" Widget::Widget(int number, const std::string& name) : number_(number), name_(name) {} Widget::~Widget() {} float Widget::GetFloatValue() const { return number_; } int Widget::GetIntValue() const { return static_cast(number_); } std::string Widget::GetStringValue() const { return name_; } void Widget::GetCharPtrValue(char* buffer, size_t max_size) const { // Copy the char* representation of name_ into buffer, up to max_size. strncpy(buffer, name_.c_str(), max_size-1); buffer[max_size-1] = '\0'; return; } ceph-0.80.11/src/gtest/xcode/gtest.xcodeproj/0000775000175100017510000000000012623077036023031 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/gtest.xcodeproj/project.pbxproj0000664000175100017510000013704312623076744026122 0ustar jenkins-buildjenkins-build// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXAggregateTarget section */ 3B238F5F0E828B5400846E11 /* Check */ = { isa = PBXAggregateTarget; buildConfigurationList = 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */; buildPhases = ( 3B238F5E0E828B5400846E11 /* ShellScript */, ); dependencies = ( 40899F9D0FFA740F000B29AE /* PBXTargetDependency */, 40C849F7101A43440083642A /* PBXTargetDependency */, 4089A0980FFAD34A000B29AE /* PBXTargetDependency */, 40C849F9101A43490083642A /* PBXTargetDependency */, ); name = Check; productName = Check; }; 40C44ADC0E3798F4008FCC51 /* Version Info */ = { isa = PBXAggregateTarget; buildConfigurationList = 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */; buildPhases = ( 40C44ADB0E3798F4008FCC51 /* Generate Version.h */, ); comments = "The generation of Version.h must be performed in its own target. Since the Info.plist is preprocessed before any of the other build phases in gtest, the Version.h file would not be ready if included as a build phase of that target."; dependencies = ( ); name = "Version Info"; productName = Version.h; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */ = {isa = PBXBuildFile; fileRef = 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */; }; 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DB0E2F799B00CF7658 /* gtest-death-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884390E2F799B00CF7658 /* gtest-message.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DC0E2F799B00CF7658 /* gtest-message.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DD0E2F799B00CF7658 /* gtest-spi.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843B0E2F799B00CF7658 /* gtest.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DE0E2F799B00CF7658 /* gtest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883E00E2F799B00CF7658 /* gtest_prod.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884500E2F799B00CF7658 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 404883F60E2F799B00CF7658 /* README */; }; 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */; }; 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E30E2F799B00CF7658 /* gtest-filepath.h */; }; 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E40E2F799B00CF7658 /* gtest-internal.h */; }; 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E50E2F799B00CF7658 /* gtest-port.h */; }; 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E60E2F799B00CF7658 /* gtest-string.h */; }; 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */ = {isa = PBXBuildFile; fileRef = 404884A90E2F7CD900CF7658 /* CHANGES */; }; 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */ = {isa = PBXBuildFile; fileRef = 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */; }; 404884AE0E2F7CD900CF7658 /* COPYING in Resources */ = {isa = PBXBuildFile; fileRef = 404884AB0E2F7CD900CF7658 /* COPYING */; }; 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; }; 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 40899F4D0FFA7271000B29AE /* gtest-tuple.h */; }; 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; }; 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; }; 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; }; 40C848FF101A21150083642A /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; }; 40C84915101A21DF0083642A /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4048840D0E2F799B00CF7658 /* gtest_main.cc */; }; 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C84978101A36540083642A /* libgtest_main.a in Resources */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C84980101A36850083642A /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; }; 40C84982101A36850083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; }; 40C84983101A36850083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C8498F101A36A60083642A /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; }; 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; }; 40C84992101A36A60083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; }; 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C849A2101A37050083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; }; 40C849A4101A37150083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; }; 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 4539C9330EC280AE00A70F4C /* gtest-param-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */; }; 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */; }; 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9370EC280E200A70F4C /* gtest-param-util.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40899F420FFA7184000B29AE; remoteInfo = gtest_unittest; }; 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 4089A0120FFACEFC000B29AE; remoteInfo = sample1_unittest; }; 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C848F9101A209C0083642A; remoteInfo = "gtest-static"; }; 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C44ADC0E3798F4008FCC51; remoteInfo = Version.h; }; 40C8497C101A36850083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C848F9101A209C0083642A; remoteInfo = "gtest-static"; }; 40C8497E101A36850083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8490A101A217E0083642A; remoteInfo = "gtest_main-static"; }; 40C8498B101A36A60083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C848F9101A209C0083642A; remoteInfo = "gtest-static"; }; 40C8498D101A36A60083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8490A101A217E0083642A; remoteInfo = "gtest_main-static"; }; 40C8499B101A36DC0083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8490A101A217E0083642A; remoteInfo = "gtest_main-static"; }; 40C8499D101A36E50083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = "gtest-framework"; }; 40C8499F101A36F10083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = "gtest-framework"; }; 40C849F6101A43440083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8497A101A36850083642A; remoteInfo = "gtest_unittest-static"; }; 40C849F8101A43490083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C84989101A36A60083642A; remoteInfo = "sample1_unittest-static"; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 404884A50E2F7C0400CF7658 /* Copy Headers Internal */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = Headers/internal; dstSubfolderSpec = 6; files = ( 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */, 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */, 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */, 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */, 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */, 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */, 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */, 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */, 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */, 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */, ); name = "Copy Headers Internal"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 224A12A10E9EADA700BD17FD /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-all.cc"; sourceTree = ""; }; 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "gtest-test-part.h"; sourceTree = ""; }; 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_unittest.cc; sourceTree = ""; }; 3B87D2100E96B92E000D1852 /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-type-util.h"; sourceTree = ""; }; 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-typed-test.h"; sourceTree = ""; }; 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = ""; }; 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = ""; }; 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = ""; }; 404883DD0E2F799B00CF7658 /* gtest-spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-spi.h"; sourceTree = ""; }; 404883DE0E2F799B00CF7658 /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest.h; sourceTree = ""; }; 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_pred_impl.h; sourceTree = ""; }; 404883E00E2F799B00CF7658 /* gtest_prod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_prod.h; sourceTree = ""; }; 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test-internal.h"; sourceTree = ""; }; 404883E30E2F799B00CF7658 /* gtest-filepath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-filepath.h"; sourceTree = ""; }; 404883E40E2F799B00CF7658 /* gtest-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-internal.h"; sourceTree = ""; }; 404883E50E2F799B00CF7658 /* gtest-port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-port.h"; sourceTree = ""; }; 404883E60E2F799B00CF7658 /* gtest-string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-string.h"; sourceTree = ""; }; 404883F60E2F799B00CF7658 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README; path = ../README; sourceTree = SOURCE_ROOT; }; 4048840D0E2F799B00CF7658 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_main.cc; sourceTree = ""; }; 404884A90E2F7CD900CF7658 /* CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CHANGES; path = ../CHANGES; sourceTree = SOURCE_ROOT; }; 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CONTRIBUTORS; path = ../CONTRIBUTORS; sourceTree = SOURCE_ROOT; }; 404884AB0E2F7CD900CF7658 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING; path = ../COPYING; sourceTree = SOURCE_ROOT; }; 40899F430FFA7184000B29AE /* gtest_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gtest_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 40899F4D0FFA7271000B29AE /* gtest-tuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-tuple.h"; sourceTree = ""; }; 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryTarget.xcconfig; sourceTree = ""; }; 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 4089A02C0FFACF7F000B29AE /* sample1.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1.cc; sourceTree = ""; }; 4089A02D0FFACF7F000B29AE /* sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample1.h; sourceTree = ""; }; 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1_unittest.cc; sourceTree = ""; }; 40C848FA101A209C0083642A /* libgtest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; }; 40C8490B101A217E0083642A /* libgtest_main.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest_main.a; sourceTree = BUILT_PRODUCTS_DIR; }; 40C84987101A36850083642A /* gtest_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gtest_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; 40C84997101A36A60083642A /* sample1_unittest-static */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-static"; sourceTree = BUILT_PRODUCTS_DIR; }; 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugProject.xcconfig; sourceTree = ""; }; 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = ""; }; 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = ""; }; 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = ""; }; 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4539C8FF0EC27F6400A70F4C /* gtest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = gtest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4539C9330EC280AE00A70F4C /* gtest-param-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-test.h"; sourceTree = ""; }; 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-linked_ptr.h"; sourceTree = ""; }; 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util-generated.h"; sourceTree = ""; }; 4539C9370EC280E200A70F4C /* gtest-param-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util.h"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 40899F410FFA7184000B29AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C849A4101A37150083642A /* gtest.framework in Frameworks */, 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 4089A0110FFACEFC000B29AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C849A2101A37050083642A /* gtest.framework in Frameworks */, 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C84981101A36850083642A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C84982101A36850083642A /* libgtest.a in Frameworks */, 40C84983101A36850083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C84991101A36A60083642A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C84992101A36A60083642A /* libgtest.a in Frameworks */, 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 034768DDFF38A45A11DB9C8B /* Products */ = { isa = PBXGroup; children = ( 4539C8FF0EC27F6400A70F4C /* gtest.framework */, 40C848FA101A209C0083642A /* libgtest.a */, 40C8490B101A217E0083642A /* libgtest_main.a */, 40899F430FFA7184000B29AE /* gtest_unittest-framework */, 40C84987101A36850083642A /* gtest_unittest */, 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */, 40C84997101A36A60083642A /* sample1_unittest-static */, ); name = Products; sourceTree = ""; }; 0867D691FE84028FC02AAC07 /* gtest */ = { isa = PBXGroup; children = ( 40D4CDF00E30E07400294801 /* Config */, 08FB77ACFE841707C02AAC07 /* Source */, 40D4CF4E0E30F5E200294801 /* Resources */, 403EE37B0E377822004BD1E2 /* Scripts */, 034768DDFF38A45A11DB9C8B /* Products */, ); name = gtest; sourceTree = ""; }; 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( 404884A90E2F7CD900CF7658 /* CHANGES */, 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */, 404884AB0E2F7CD900CF7658 /* COPYING */, 404883F60E2F799B00CF7658 /* README */, 404883D90E2F799B00CF7658 /* include */, 4089A02F0FFACF84000B29AE /* samples */, 404884070E2F799B00CF7658 /* src */, 3B238BF00E7FE13B00846E11 /* test */, ); name = Source; sourceTree = ""; }; 3B238BF00E7FE13B00846E11 /* test */ = { isa = PBXGroup; children = ( 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */, ); name = test; path = ../test; sourceTree = SOURCE_ROOT; }; 403EE37B0E377822004BD1E2 /* Scripts */ = { isa = PBXGroup; children = ( 403EE37C0E377822004BD1E2 /* versiongenerate.py */, 3B87D2100E96B92E000D1852 /* runtests.sh */, ); path = Scripts; sourceTree = ""; }; 404883D90E2F799B00CF7658 /* include */ = { isa = PBXGroup; children = ( 404883DA0E2F799B00CF7658 /* gtest */, ); name = include; path = ../include; sourceTree = SOURCE_ROOT; }; 404883DA0E2F799B00CF7658 /* gtest */ = { isa = PBXGroup; children = ( 404883E10E2F799B00CF7658 /* internal */, 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */, 404883DB0E2F799B00CF7658 /* gtest-death-test.h */, 404883DC0E2F799B00CF7658 /* gtest-message.h */, 4539C9330EC280AE00A70F4C /* gtest-param-test.h */, 404883DD0E2F799B00CF7658 /* gtest-spi.h */, 404883DE0E2F799B00CF7658 /* gtest.h */, 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */, 404883E00E2F799B00CF7658 /* gtest_prod.h */, 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */, ); path = gtest; sourceTree = ""; }; 404883E10E2F799B00CF7658 /* internal */ = { isa = PBXGroup; children = ( 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */, 404883E30E2F799B00CF7658 /* gtest-filepath.h */, 404883E40E2F799B00CF7658 /* gtest-internal.h */, 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */, 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */, 4539C9370EC280E200A70F4C /* gtest-param-util.h */, 404883E50E2F799B00CF7658 /* gtest-port.h */, 404883E60E2F799B00CF7658 /* gtest-string.h */, 40899F4D0FFA7271000B29AE /* gtest-tuple.h */, 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */, ); path = internal; sourceTree = ""; }; 404884070E2F799B00CF7658 /* src */ = { isa = PBXGroup; children = ( 224A12A10E9EADA700BD17FD /* gtest-all.cc */, 4048840D0E2F799B00CF7658 /* gtest_main.cc */, ); name = src; path = ../src; sourceTree = SOURCE_ROOT; }; 4089A02F0FFACF84000B29AE /* samples */ = { isa = PBXGroup; children = ( 4089A02C0FFACF7F000B29AE /* sample1.cc */, 4089A02D0FFACF7F000B29AE /* sample1.h */, 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */, ); name = samples; path = ../samples; sourceTree = SOURCE_ROOT; }; 40D4CDF00E30E07400294801 /* Config */ = { isa = PBXGroup; children = ( 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */, 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */, 40D4CDF30E30E07400294801 /* General.xcconfig */, 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */, 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */, ); path = Config; sourceTree = ""; }; 40D4CF4E0E30F5E200294801 /* Resources */ = { isa = PBXGroup; children = ( 40D4CF510E30F5E200294801 /* Info.plist */, ); path = Resources; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */, 404884390E2F799B00CF7658 /* gtest-message.h in Headers */, 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */, 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */, 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */, 4048843B0E2F799B00CF7658 /* gtest.h in Headers */, 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */, 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */, 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 40899F420FFA7184000B29AE /* gtest_unittest-framework */ = { isa = PBXNativeTarget; buildConfigurationList = 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */; buildPhases = ( 40899F400FFA7184000B29AE /* Sources */, 40899F410FFA7184000B29AE /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C849A0101A36F10083642A /* PBXTargetDependency */, ); name = "gtest_unittest-framework"; productName = gtest_unittest; productReference = 40899F430FFA7184000B29AE /* gtest_unittest-framework */; productType = "com.apple.product-type.tool"; }; 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */ = { isa = PBXNativeTarget; buildConfigurationList = 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */; buildPhases = ( 4089A0100FFACEFC000B29AE /* Sources */, 4089A0110FFACEFC000B29AE /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C8499E101A36E50083642A /* PBXTargetDependency */, ); name = "sample1_unittest-framework"; productName = sample1_unittest; productReference = 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */; productType = "com.apple.product-type.tool"; }; 40C848F9101A209C0083642A /* gtest-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */; buildPhases = ( 40C848F7101A209C0083642A /* Sources */, ); buildRules = ( ); dependencies = ( ); name = "gtest-static"; productName = "gtest-static"; productReference = 40C848FA101A209C0083642A /* libgtest.a */; productType = "com.apple.product-type.library.static"; }; 40C8490A101A217E0083642A /* gtest_main-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */; buildPhases = ( 40C84908101A217E0083642A /* Sources */, ); buildRules = ( ); dependencies = ( ); name = "gtest_main-static"; productName = "gtest_main-static"; productReference = 40C8490B101A217E0083642A /* libgtest_main.a */; productType = "com.apple.product-type.library.static"; }; 40C8497A101A36850083642A /* gtest_unittest-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */; buildPhases = ( 40C8497F101A36850083642A /* Sources */, 40C84981101A36850083642A /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C8497B101A36850083642A /* PBXTargetDependency */, 40C8497D101A36850083642A /* PBXTargetDependency */, ); name = "gtest_unittest-static"; productName = gtest_unittest; productReference = 40C84987101A36850083642A /* gtest_unittest */; productType = "com.apple.product-type.tool"; }; 40C84989101A36A60083642A /* sample1_unittest-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */; buildPhases = ( 40C8498E101A36A60083642A /* Sources */, 40C84991101A36A60083642A /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C8498A101A36A60083642A /* PBXTargetDependency */, 40C8498C101A36A60083642A /* PBXTargetDependency */, ); name = "sample1_unittest-static"; productName = sample1_unittest; productReference = 40C84997101A36A60083642A /* sample1_unittest-static */; productType = "com.apple.product-type.tool"; }; 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */ = { isa = PBXNativeTarget; buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */; buildPhases = ( 8D07F2C10486CC7A007CD1D0 /* Sources */, 8D07F2BD0486CC7A007CD1D0 /* Headers */, 404884A50E2F7C0400CF7658 /* Copy Headers Internal */, 8D07F2BF0486CC7A007CD1D0 /* Resources */, ); buildRules = ( ); dependencies = ( 40C44AE60E379922008FCC51 /* PBXTargetDependency */, 408BEC101046CFE900DEF522 /* PBXTargetDependency */, 40C8499C101A36DC0083642A /* PBXTargetDependency */, ); name = "gtest-framework"; productInstallPath = "$(HOME)/Library/Frameworks"; productName = gtest; productReference = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */; compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, en, ); mainGroup = 0867D691FE84028FC02AAC07 /* gtest */; productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */, 40C848F9101A209C0083642A /* gtest-static */, 40C8490A101A217E0083642A /* gtest_main-static */, 40899F420FFA7184000B29AE /* gtest_unittest-framework */, 40C8497A101A36850083642A /* gtest_unittest-static */, 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */, 40C84989101A36A60083642A /* sample1_unittest-static */, 3B238F5F0E828B5400846E11 /* Check */, 40C44ADC0E3798F4008FCC51 /* Version Info */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 404884500E2F799B00CF7658 /* README in Resources */, 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */, 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */, 404884AE0E2F7CD900CF7658 /* COPYING in Resources */, 40C84978101A36540083642A /* libgtest_main.a in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B238F5E0E828B5400846E11 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/bin/bash Scripts/runtests.sh"; }; 40C44ADB0E3798F4008FCC51 /* Generate Version.h */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/Scripts/versiongenerate.py", "$(SRCROOT)/../configure.ac", ); name = "Generate Version.h"; outputPaths = ( "$(PROJECT_TEMP_DIR)/Version.h", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/usr/bin/python Scripts/versiongenerate.py ../ $PROJECT_TEMP_DIR"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 40899F400FFA7184000B29AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 4089A0100FFACEFC000B29AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */, 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C848F7101A209C0083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C848FF101A21150083642A /* gtest-all.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C84908101A217E0083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C84915101A21DF0083642A /* gtest_main.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C8497F101A36850083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C84980101A36850083642A /* gtest_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C8498E101A36A60083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C8498F101A36A60083642A /* sample1.cc in Sources */, 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D07F2C10486CC7A007CD1D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 40899F9D0FFA740F000B29AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40899F420FFA7184000B29AE /* gtest_unittest-framework */; targetProxy = 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */; }; 4089A0980FFAD34A000B29AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */; targetProxy = 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */; }; 408BEC101046CFE900DEF522 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C848F9101A209C0083642A /* gtest-static */; targetProxy = 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */; }; 40C44AE60E379922008FCC51 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C44ADC0E3798F4008FCC51 /* Version Info */; targetProxy = 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */; }; 40C8497B101A36850083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C848F9101A209C0083642A /* gtest-static */; targetProxy = 40C8497C101A36850083642A /* PBXContainerItemProxy */; }; 40C8497D101A36850083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8490A101A217E0083642A /* gtest_main-static */; targetProxy = 40C8497E101A36850083642A /* PBXContainerItemProxy */; }; 40C8498A101A36A60083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C848F9101A209C0083642A /* gtest-static */; targetProxy = 40C8498B101A36A60083642A /* PBXContainerItemProxy */; }; 40C8498C101A36A60083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8490A101A217E0083642A /* gtest_main-static */; targetProxy = 40C8498D101A36A60083642A /* PBXContainerItemProxy */; }; 40C8499C101A36DC0083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8490A101A217E0083642A /* gtest_main-static */; targetProxy = 40C8499B101A36DC0083642A /* PBXContainerItemProxy */; }; 40C8499E101A36E50083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */; targetProxy = 40C8499D101A36E50083642A /* PBXContainerItemProxy */; }; 40C849A0101A36F10083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */; targetProxy = 40C8499F101A36F10083642A /* PBXContainerItemProxy */; }; 40C849F7101A43440083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8497A101A36850083642A /* gtest_unittest-static */; targetProxy = 40C849F6101A43440083642A /* PBXContainerItemProxy */; }; 40C849F9101A43490083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C84989101A36A60083642A /* sample1_unittest-static */; targetProxy = 40C849F8101A43490083642A /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 3B238F600E828B5400846E11 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; PRODUCT_NAME = Check; }; name = Debug; }; 3B238F610E828B5400846E11 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; PRODUCT_NAME = Check; ZERO_LINK = NO; }; name = Release; }; 40899F450FFA7185000B29AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = "gtest_unittest-framework"; }; name = Debug; }; 40899F460FFA7185000B29AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = "gtest_unittest-framework"; }; name = Release; }; 4089A0150FFACEFD000B29AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "sample1_unittest-framework"; }; name = Debug; }; 4089A0160FFACEFD000B29AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "sample1_unittest-framework"; }; name = Release; }; 40C44ADF0E3798F4008FCC51 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = gtest; TARGET_NAME = gtest; }; name = Debug; }; 40C44AE00E3798F4008FCC51 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = gtest; TARGET_NAME = gtest; }; name = Release; }; 40C848FB101A209D0083642A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest; }; name = Debug; }; 40C848FC101A209D0083642A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest; }; name = Release; }; 40C8490E101A217F0083642A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest_main; }; name = Debug; }; 40C8490F101A217F0083642A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest_main; }; name = Release; }; 40C84985101A36850083642A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = gtest_unittest; }; name = Debug; }; 40C84986101A36850083642A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = gtest_unittest; }; name = Release; }; 40C84995101A36A60083642A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "sample1_unittest-static"; }; name = Debug; }; 40C84996101A36A60083642A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "sample1_unittest-static"; }; name = Release; }; 4FADC24308B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; HEADER_SEARCH_PATHS = ( ../, ../include/, ); INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; INFOPLIST_PREPROCESS = YES; PRODUCT_NAME = gtest; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 4FADC24408B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; HEADER_SEARCH_PATHS = ( ../, ../include/, ); INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; INFOPLIST_PREPROCESS = YES; PRODUCT_NAME = gtest; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 4FADC24708B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */; buildSettings = { }; name = Debug; }; 4FADC24808B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */; buildSettings = { }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */ = { isa = XCConfigurationList; buildConfigurations = ( 3B238F600E828B5400846E11 /* Debug */, 3B238F610E828B5400846E11 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 40899F450FFA7185000B29AE /* Debug */, 40899F460FFA7185000B29AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4089A0150FFACEFD000B29AE /* Debug */, 4089A0160FFACEFD000B29AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C44ADF0E3798F4008FCC51 /* Debug */, 40C44AE00E3798F4008FCC51 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C848FB101A209D0083642A /* Debug */, 40C848FC101A209D0083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C8490E101A217F0083642A /* Debug */, 40C8490F101A217F0083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C84985101A36850083642A /* Debug */, 40C84986101A36850083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C84995101A36A60083642A /* Debug */, 40C84996101A36A60083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24308B4156D00ABE55E /* Debug */, 4FADC24408B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24708B4156D00ABE55E /* Debug */, 4FADC24808B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; } ceph-0.80.11/src/gtest/xcode/Resources/0000775000175100017510000000000012623077036021661 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/xcode/Resources/Info.plist0000664000175100017510000000176212623076744023644 0ustar jenkins-buildjenkins-build CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.google.${PRODUCT_NAME} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType FMWK CFBundleSignature ???? CFBundleVersion GTEST_VERSIONINFO_LONG CFBundleShortVersionString GTEST_VERSIONINFO_SHORT CFBundleGetInfoString ${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT} NSHumanReadableCopyright ${GTEST_VERSIONINFO_ABOUT} CSResourcesFileMapped ceph-0.80.11/src/gtest/make/0000775000175100017510000000000012623077036017522 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/make/Makefile0000664000175100017510000000505212623076744021171 0ustar jenkins-buildjenkins-build# A sample Makefile for building Google Test and using it in user # tests. Please tweak it to suit your environment and project. You # may want to move it to your project's root directory. # # SYNOPSIS: # # make [all] - makes everything. # make TARGET - makes the given target. # make clean - removes all files generated by make. # Please tweak the following variable definitions as needed by your # project, except GTEST_HEADERS, which you can use in your own targets # but shouldn't modify. # Points to the root of Google Test, relative to where this file is. # Remember to tweak this if you move this file. GTEST_DIR = .. # Where to find user code. USER_DIR = ../samples # Flags passed to the preprocessor. CPPFLAGS += -I$(GTEST_DIR)/include # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra # All tests produced by this Makefile. Remember to add new tests you # created to the list. TESTS = sample1_unittest # All Google Test headers. Usually you shouldn't change this # definition. GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ $(GTEST_DIR)/include/gtest/internal/*.h # House-keeping build targets. all : $(TESTS) clean : rm -f $(TESTS) gtest.a gtest_main.a *.o # Builds gtest.a and gtest_main.a. # Usually you shouldn't tweak such internal variables, indicated by a # trailing _. GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) # For simplicity and to avoid depending on Google Test's # implementation details, the dependencies specified below are # conservative and not optimized. This is fine as Google Test # compiles fast and for ordinary users its source rarely changes. gtest-all.o : $(GTEST_SRCS_) $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ $(GTEST_DIR)/src/gtest-all.cc gtest_main.o : $(GTEST_SRCS_) $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ $(GTEST_DIR)/src/gtest_main.cc gtest.a : gtest-all.o $(AR) $(ARFLAGS) $@ $^ gtest_main.a : gtest-all.o gtest_main.o $(AR) $(ARFLAGS) $@ $^ # Builds a sample test. A test should link with either gtest.a or # gtest_main.a, depending on whether it defines its own main() # function. sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \ $(USER_DIR)/sample1.h $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc sample1_unittest : sample1.o sample1_unittest.o gtest_main.a $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ ceph-0.80.11/src/gtest/Makefile.in0000664000175100017510000022126712623076774020674 0ustar jenkins-buildjenkins-build# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. @SET_MAKE@ # Automake file VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ TESTS = samples/sample1_unittest$(EXEEXT) \ samples/sample10_unittest$(EXEEXT) \ test/gtest_all_test$(EXEEXT) test/fused_gtest_test$(EXEEXT) check_PROGRAMS = samples/sample1_unittest$(EXEEXT) \ samples/sample10_unittest$(EXEEXT) \ test/gtest_all_test$(EXEEXT) test/fused_gtest_test$(EXEEXT) subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(top_srcdir)/build-aux/config.h.in \ $(top_srcdir)/scripts/gtest-config.in \ $(top_srcdir)/build-aux/depcomp $(pkginclude_HEADERS) \ $(pkginclude_internal_HEADERS) \ $(top_srcdir)/build-aux/test-driver COPYING README \ build-aux/compile build-aux/config.guess build-aux/config.sub \ build-aux/depcomp build-aux/install-sh build-aux/missing \ build-aux/ltmain.sh $(top_srcdir)/build-aux/compile \ $(top_srcdir)/build-aux/config.guess \ $(top_srcdir)/build-aux/config.sub \ $(top_srcdir)/build-aux/install-sh \ $(top_srcdir)/build-aux/ltmain.sh \ $(top_srcdir)/build-aux/missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/acx_pthread.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/build-aux/config.h CONFIG_CLEAN_FILES = scripts/gtest-config CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgincludedir)" \ "$(DESTDIR)$(pkginclude_internaldir)" LIBRARIES = $(lib_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = lib_libgtest_a_AR = $(AR) $(ARFLAGS) lib_libgtest_a_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_lib_libgtest_a_OBJECTS = src/gtest-all.$(OBJEXT) lib_libgtest_a_OBJECTS = $(am_lib_libgtest_a_OBJECTS) lib_libgtest_main_a_AR = $(AR) $(ARFLAGS) lib_libgtest_main_a_DEPENDENCIES = lib/libgtest.a am_lib_libgtest_main_a_OBJECTS = src/gtest_main.$(OBJEXT) lib_libgtest_main_a_OBJECTS = $(am_lib_libgtest_main_a_OBJECTS) LTLIBRARIES = $(noinst_LTLIBRARIES) samples_libsamples_la_LIBADD = am_samples_libsamples_la_OBJECTS = samples/sample1.lo \ samples/sample2.lo samples/sample4.lo samples_libsamples_la_OBJECTS = $(am_samples_libsamples_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_samples_sample10_unittest_OBJECTS = \ samples/sample10_unittest.$(OBJEXT) samples_sample10_unittest_OBJECTS = \ $(am_samples_sample10_unittest_OBJECTS) samples_sample10_unittest_DEPENDENCIES = lib/libgtest.a am_samples_sample1_unittest_OBJECTS = \ samples/sample1_unittest.$(OBJEXT) samples_sample1_unittest_OBJECTS = \ $(am_samples_sample1_unittest_OBJECTS) samples_sample1_unittest_DEPENDENCIES = lib/libgtest_main.la \ samples/libsamples.la am__objects_1 = \ fused-src/gtest/test_fused_gtest_test-gtest-all.$(OBJEXT) \ fused-src/gtest/test_fused_gtest_test-gtest_main.$(OBJEXT) am_test_fused_gtest_test_OBJECTS = $(am__objects_1) \ samples/test_fused_gtest_test-sample1.$(OBJEXT) \ samples/test_fused_gtest_test-sample1_unittest.$(OBJEXT) test_fused_gtest_test_OBJECTS = $(am_test_fused_gtest_test_OBJECTS) test_fused_gtest_test_LDADD = $(LDADD) am_test_gtest_all_test_OBJECTS = test/gtest_all_test.$(OBJEXT) test_gtest_all_test_OBJECTS = $(am_test_gtest_all_test_OBJECTS) test_gtest_all_test_DEPENDENCIES = lib/libgtest_main.la SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/build-aux depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(lib_libgtest_a_SOURCES) $(lib_libgtest_main_a_SOURCES) \ $(samples_libsamples_la_SOURCES) \ $(samples_sample10_unittest_SOURCES) \ $(samples_sample1_unittest_SOURCES) \ $(test_fused_gtest_test_SOURCES) \ $(test_gtest_all_test_SOURCES) DIST_SOURCES = $(lib_libgtest_a_SOURCES) \ $(lib_libgtest_main_a_SOURCES) \ $(samples_libsamples_la_SOURCES) \ $(samples_sample10_unittest_SOURCES) \ $(samples_sample1_unittest_SOURCES) \ $(test_fused_gtest_test_SOURCES) \ $(test_gtest_all_test_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(m4data_DATA) HEADERS = $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope AM_RECURSIVE_TARGETS = cscope check recheck am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).zip GZIP_ENV = --best DIST_TARGETS = dist-bzip2 dist-gzip dist-zip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 AM_LDFLAGS = -lpthread # Nonstandard package files for distribution # Sample files that we don't compile. # C++ test files that we don't compile directly. # Python tests that we don't run. # CMake script # MSVC project files # xcode project files # xcode sample files # C++Builder project files EXTRA_DIST = CHANGES CONTRIBUTORS \ include/gtest/gtest-param-test.h.pump \ include/gtest/internal/gtest-tuple.h.pump \ include/gtest/internal/gtest-type-util.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \ make/Makefile scripts/fuse_gtest_files.py \ scripts/gen_gtest_pred_impl.py scripts/pump.py \ scripts/test/Makefile $(GTEST_SRC) samples/prime_tables.h \ samples/sample2_unittest.cc samples/sample3_unittest.cc \ samples/sample4_unittest.cc samples/sample5_unittest.cc \ samples/sample6_unittest.cc samples/sample7_unittest.cc \ samples/sample8_unittest.cc samples/sample9_unittest.cc \ test/gtest-death-test_test.cc test/gtest_environment_test.cc \ test/gtest-filepath_test.cc test/gtest-linked_ptr_test.cc \ test/gtest-message_test.cc test/gtest_no_test_unittest.cc \ test/gtest-options_test.cc test/gtest-param-test_test.cc \ test/gtest-param-test2_test.cc test/gtest-param-test_test.h \ test/gtest-port_test.cc test/gtest_pred_impl_unittest.cc \ test/gtest_prod_test.cc test/production.cc test/production.h \ test/gtest_repeat_test.cc test/gtest_sole_header_test.cc \ test/gtest_stress_test.cc test/gtest-test-part_test.cc \ test/gtest_throw_on_failure_ex_test.cc \ test/gtest-typed-test_test.cc test/gtest-typed-test2_test.cc \ test/gtest-typed-test_test.h test/gtest_unittest.cc \ test/gtest-unittest-api_test.cc test/gtest-listener_test.cc \ test/gtest_main_unittest.cc test/gtest_unittest.cc \ test/gtest-tuple_test.cc test/gtest-param-test_test.cc \ test/gtest-param-test2_test.cc \ test/gtest_break_on_failure_unittest_.cc \ test/gtest_color_test_.cc test/gtest_env_var_test_.cc \ test/gtest_filter_unittest_.cc test/gtest_help_test_.cc \ test/gtest_list_tests_unittest_.cc test/gtest_output_test_.cc \ test/gtest_shuffle_test_.cc \ test/gtest_throw_on_failure_test_.cc \ test/gtest_uninitialized_test_.cc \ test/gtest_xml_outfile1_test_.cc \ test/gtest_xml_outfile2_test_.cc \ test/gtest_xml_output_unittest_.cc test/gtest_test_utils.py \ test/gtest_xml_test_utils.py \ test/gtest_break_on_failure_unittest.py \ test/gtest_color_test.py test/gtest_env_var_test.py \ test/gtest_filter_unittest.py test/gtest_help_test.py \ test/gtest_list_tests_unittest.py test/gtest_output_test.py \ test/gtest_output_test_golden_lin.txt \ test/gtest_output_test_golden_win.txt \ test/gtest_shuffle_test.py test/gtest_throw_on_failure_test.py \ test/gtest_uninitialized_test.py \ test/gtest_xml_outfiles_test.py \ test/gtest_xml_output_unittest.py test/run_tests_util.py \ test/run_tests_util_test.py CMakeLists.txt msvc/gtest-md.sln \ msvc/gtest.sln msvc/gtest-md.vcproj msvc/gtest.vcproj \ msvc/gtest_main-md.vcproj msvc/gtest_main.vcproj \ msvc/gtest_prod_test-md.vcproj msvc/gtest_prod_test.vcproj \ msvc/gtest_unittest-md.vcproj msvc/gtest_unittest.vcproj \ xcode/Config/DebugProject.xcconfig \ xcode/Config/FrameworkTarget.xcconfig \ xcode/Config/General.xcconfig \ xcode/Config/ReleaseProject.xcconfig \ xcode/Config/StaticLibraryTarget.xcconfig \ xcode/Config/TestTarget.xcconfig xcode/Resources/Info.plist \ xcode/Scripts/versiongenerate.py xcode/Scripts/runtests.sh \ xcode/gtest.xcodeproj/project.pbxproj \ xcode/Samples/FrameworkSample/Info.plist \ xcode/Samples/FrameworkSample/runtests.sh \ xcode/Samples/FrameworkSample/widget_test.cc \ xcode/Samples/FrameworkSample/widget.cc \ xcode/Samples/FrameworkSample/widget.h \ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \ codegear/gtest_all.cc codegear/gtest_link.cc \ codegear/gtest.cbproj codegear/gtest_main.cbproj \ codegear/gtest_unittest.cbproj codegear/gtest.groupproj \ $(m4data_DATA) # gtest source files that we don't compile directly. They are # #included by gtest-all.cc. GTEST_SRC = \ src/gtest.cc \ src/gtest-death-test.cc \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ src/gtest-port.cc \ src/gtest-test-part.cc \ src/gtest-typed-test.cc # Scripts and utilities bin_SCRIPTS = scripts/gtest-config # Death tests may produce core dumps in the build directory. In case # this happens, clean them to keep distcleancheck happy. CLEANFILES = $(bin_SCRIPTS) core # Distribute and install M4 macro m4datadir = $(datadir)/aclocal m4data_DATA = m4/gtest.m4 # We define the global AM_CPPFLAGS as everything we compile includes from these # directories. AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include -DGTEST_HAS_TR1_TUPLE=0 @HAVE_PTHREADS_FALSE@AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0 # Modifies compiler and linker flags for pthreads compatibility. @HAVE_PTHREADS_TRUE@AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 @HAVE_PTHREADS_TRUE@AM_LIBS = @PTHREAD_LIBS@ # Build rules for libraries. lib_LIBRARIES = lib/libgtest.a lib/libgtest_main.a lib_libgtest_a_SOURCES = src/gtest-all.cc pkginclude_HEADERS = include/gtest/gtest.h \ include/gtest/gtest-death-test.h \ include/gtest/gtest-message.h \ include/gtest/gtest-param-test.h \ include/gtest/gtest_pred_impl.h \ include/gtest/gtest_prod.h \ include/gtest/gtest-spi.h \ include/gtest/gtest-test-part.h \ include/gtest/gtest-typed-test.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ include/gtest/internal/gtest-death-test-internal.h \ include/gtest/internal/gtest-filepath.h \ include/gtest/internal/gtest-internal.h \ include/gtest/internal/gtest-linked_ptr.h \ include/gtest/internal/gtest-param-util-generated.h \ include/gtest/internal/gtest-param-util.h \ include/gtest/internal/gtest-port.h \ include/gtest/internal/gtest-string.h \ include/gtest/internal/gtest-tuple.h \ include/gtest/internal/gtest-type-util.h lib_libgtest_main_a_SOURCES = src/gtest_main.cc lib_libgtest_main_a_LIBADD = lib/libgtest.a # Bulid rules for samples and tests. Automake's naming for some of # these variables isn't terribly obvious, so this is a brief # reference: # # TESTS -- Programs run automatically by "make check" # check_PROGRAMS -- Programs built by "make check" but not necessarily run noinst_LTLIBRARIES = samples/libsamples.la samples_libsamples_la_SOURCES = samples/sample1.cc \ samples/sample1.h \ samples/sample2.cc \ samples/sample2.h \ samples/sample3-inl.h \ samples/sample4.cc \ samples/sample4.h TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \ GTEST_BUILD_DIR="$(top_builddir)/test" samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc samples_sample1_unittest_LDADD = lib/libgtest_main.la \ samples/libsamples.la samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc samples_sample10_unittest_LDADD = lib/libgtest.a test_gtest_all_test_SOURCES = test/gtest_all_test.cc test_gtest_all_test_LDADD = lib/libgtest_main.la # Tests that fused gtest files compile and work. FUSED_GTEST_SRC = \ fused-src/gtest/gtest-all.cc \ fused-src/gtest/gtest_main.cc \ fused-src/gtest/gtest.h test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \ samples/sample1.cc samples/sample1_unittest.cc test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src" all: all-am .SUFFIXES: .SUFFIXES: .cc .lo .log .o .obj .test .test$(EXEEXT) .trs am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): build-aux/config.h: build-aux/stamp-h1 @test -f $@ || rm -f build-aux/stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) build-aux/stamp-h1 build-aux/stamp-h1: $(top_srcdir)/build-aux/config.h.in $(top_builddir)/config.status @rm -f build-aux/stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status build-aux/config.h $(top_srcdir)/build-aux/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f build-aux/stamp-h1 touch $@ distclean-hdr: -rm -f build-aux/config.h build-aux/stamp-h1 scripts/gtest-config: $(top_builddir)/config.status $(top_srcdir)/scripts/gtest-config.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-libLIBRARIES: $(lib_LIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \ $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; } @$(POST_INSTALL) @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ if test -f $$p; then \ $(am__strip_dir) \ echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \ ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \ else :; fi; \ done uninstall-libLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(libdir)'; $(am__uninstall_files_from_dir) clean-libLIBRARIES: -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) src/$(am__dirstamp): @$(MKDIR_P) src @: > src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/$(DEPDIR) @: > src/$(DEPDIR)/$(am__dirstamp) src/gtest-all.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) lib/$(am__dirstamp): @$(MKDIR_P) lib @: > lib/$(am__dirstamp) lib/libgtest.a: $(lib_libgtest_a_OBJECTS) $(lib_libgtest_a_DEPENDENCIES) $(EXTRA_lib_libgtest_a_DEPENDENCIES) lib/$(am__dirstamp) $(AM_V_at)-rm -f lib/libgtest.a $(AM_V_AR)$(lib_libgtest_a_AR) lib/libgtest.a $(lib_libgtest_a_OBJECTS) $(lib_libgtest_a_LIBADD) $(AM_V_at)$(RANLIB) lib/libgtest.a src/gtest_main.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) lib/libgtest_main.a: $(lib_libgtest_main_a_OBJECTS) $(lib_libgtest_main_a_DEPENDENCIES) $(EXTRA_lib_libgtest_main_a_DEPENDENCIES) lib/$(am__dirstamp) $(AM_V_at)-rm -f lib/libgtest_main.a $(AM_V_AR)$(lib_libgtest_main_a_AR) lib/libgtest_main.a $(lib_libgtest_main_a_OBJECTS) $(lib_libgtest_main_a_LIBADD) $(AM_V_at)$(RANLIB) lib/libgtest_main.a clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } samples/$(am__dirstamp): @$(MKDIR_P) samples @: > samples/$(am__dirstamp) samples/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) samples/$(DEPDIR) @: > samples/$(DEPDIR)/$(am__dirstamp) samples/sample1.lo: samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample2.lo: samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample4.lo: samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/libsamples.la: $(samples_libsamples_la_OBJECTS) $(samples_libsamples_la_DEPENDENCIES) $(EXTRA_samples_libsamples_la_DEPENDENCIES) samples/$(am__dirstamp) $(AM_V_CXXLD)$(CXXLINK) $(samples_libsamples_la_OBJECTS) $(samples_libsamples_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list samples/sample10_unittest.$(OBJEXT): samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample10_unittest$(EXEEXT): $(samples_sample10_unittest_OBJECTS) $(samples_sample10_unittest_DEPENDENCIES) $(EXTRA_samples_sample10_unittest_DEPENDENCIES) samples/$(am__dirstamp) @rm -f samples/sample10_unittest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(samples_sample10_unittest_OBJECTS) $(samples_sample10_unittest_LDADD) $(LIBS) samples/sample1_unittest.$(OBJEXT): samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample1_unittest$(EXEEXT): $(samples_sample1_unittest_OBJECTS) $(samples_sample1_unittest_DEPENDENCIES) $(EXTRA_samples_sample1_unittest_DEPENDENCIES) samples/$(am__dirstamp) @rm -f samples/sample1_unittest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(samples_sample1_unittest_OBJECTS) $(samples_sample1_unittest_LDADD) $(LIBS) fused-src/gtest/$(am__dirstamp): @$(MKDIR_P) fused-src/gtest @: > fused-src/gtest/$(am__dirstamp) fused-src/gtest/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) fused-src/gtest/$(DEPDIR) @: > fused-src/gtest/$(DEPDIR)/$(am__dirstamp) fused-src/gtest/test_fused_gtest_test-gtest-all.$(OBJEXT): \ fused-src/gtest/$(am__dirstamp) \ fused-src/gtest/$(DEPDIR)/$(am__dirstamp) fused-src/gtest/test_fused_gtest_test-gtest_main.$(OBJEXT): \ fused-src/gtest/$(am__dirstamp) \ fused-src/gtest/$(DEPDIR)/$(am__dirstamp) samples/test_fused_gtest_test-sample1.$(OBJEXT): \ samples/$(am__dirstamp) samples/$(DEPDIR)/$(am__dirstamp) samples/test_fused_gtest_test-sample1_unittest.$(OBJEXT): \ samples/$(am__dirstamp) samples/$(DEPDIR)/$(am__dirstamp) test/$(am__dirstamp): @$(MKDIR_P) test @: > test/$(am__dirstamp) test/fused_gtest_test$(EXEEXT): $(test_fused_gtest_test_OBJECTS) $(test_fused_gtest_test_DEPENDENCIES) $(EXTRA_test_fused_gtest_test_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/fused_gtest_test$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_fused_gtest_test_OBJECTS) $(test_fused_gtest_test_LDADD) $(LIBS) test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/$(DEPDIR) @: > test/$(DEPDIR)/$(am__dirstamp) test/gtest_all_test.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/gtest_all_test$(EXEEXT): $(test_gtest_all_test_OBJECTS) $(test_gtest_all_test_DEPENDENCIES) $(EXTRA_test_gtest_all_test_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/gtest_all_test$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(test_gtest_all_test_OBJECTS) $(test_gtest_all_test_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f fused-src/gtest/*.$(OBJEXT) -rm -f samples/*.$(OBJEXT) -rm -f samples/*.lo -rm -f src/*.$(OBJEXT) -rm -f test/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample10_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample1_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/test_fused_gtest_test-sample1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/gtest-all.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/gtest_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/gtest_all_test.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< fused-src/gtest/test_fused_gtest_test-gtest-all.o: fused-src/gtest/gtest-all.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest-all.o -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.o `test -f 'fused-src/gtest/gtest-all.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest-all.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fused-src/gtest/gtest-all.cc' object='fused-src/gtest/test_fused_gtest_test-gtest-all.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.o `test -f 'fused-src/gtest/gtest-all.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest-all.cc fused-src/gtest/test_fused_gtest_test-gtest-all.obj: fused-src/gtest/gtest-all.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest-all.obj -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.obj `if test -f 'fused-src/gtest/gtest-all.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest-all.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fused-src/gtest/gtest-all.cc' object='fused-src/gtest/test_fused_gtest_test-gtest-all.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.obj `if test -f 'fused-src/gtest/gtest-all.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest-all.cc'; fi` fused-src/gtest/test_fused_gtest_test-gtest_main.o: fused-src/gtest/gtest_main.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest_main.o -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.o `test -f 'fused-src/gtest/gtest_main.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest_main.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fused-src/gtest/gtest_main.cc' object='fused-src/gtest/test_fused_gtest_test-gtest_main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.o `test -f 'fused-src/gtest/gtest_main.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest_main.cc fused-src/gtest/test_fused_gtest_test-gtest_main.obj: fused-src/gtest/gtest_main.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest_main.obj -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.obj `if test -f 'fused-src/gtest/gtest_main.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest_main.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fused-src/gtest/gtest_main.cc' object='fused-src/gtest/test_fused_gtest_test-gtest_main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.obj `if test -f 'fused-src/gtest/gtest_main.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest_main.cc'; fi` samples/test_fused_gtest_test-sample1.o: samples/sample1.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1.o -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo -c -o samples/test_fused_gtest_test-sample1.o `test -f 'samples/sample1.cc' || echo '$(srcdir)/'`samples/sample1.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='samples/sample1.cc' object='samples/test_fused_gtest_test-sample1.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1.o `test -f 'samples/sample1.cc' || echo '$(srcdir)/'`samples/sample1.cc samples/test_fused_gtest_test-sample1.obj: samples/sample1.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1.obj -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo -c -o samples/test_fused_gtest_test-sample1.obj `if test -f 'samples/sample1.cc'; then $(CYGPATH_W) 'samples/sample1.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='samples/sample1.cc' object='samples/test_fused_gtest_test-sample1.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1.obj `if test -f 'samples/sample1.cc'; then $(CYGPATH_W) 'samples/sample1.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1.cc'; fi` samples/test_fused_gtest_test-sample1_unittest.o: samples/sample1_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1_unittest.o -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo -c -o samples/test_fused_gtest_test-sample1_unittest.o `test -f 'samples/sample1_unittest.cc' || echo '$(srcdir)/'`samples/sample1_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='samples/sample1_unittest.cc' object='samples/test_fused_gtest_test-sample1_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1_unittest.o `test -f 'samples/sample1_unittest.cc' || echo '$(srcdir)/'`samples/sample1_unittest.cc samples/test_fused_gtest_test-sample1_unittest.obj: samples/sample1_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1_unittest.obj -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo -c -o samples/test_fused_gtest_test-sample1_unittest.obj `if test -f 'samples/sample1_unittest.cc'; then $(CYGPATH_W) 'samples/sample1_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='samples/sample1_unittest.cc' object='samples/test_fused_gtest_test-sample1_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1_unittest.obj `if test -f 'samples/sample1_unittest.cc'; then $(CYGPATH_W) 'samples/sample1_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1_unittest.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf samples/.libs samples/_libs -rm -rf test/.libs test/_libs distclean-libtool: -rm -f libtool config.lt install-m4dataDATA: $(m4data_DATA) @$(NORMAL_INSTALL) @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(m4datadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(m4datadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4datadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(m4datadir)" || exit $$?; \ done uninstall-m4dataDATA: @$(NORMAL_UNINSTALL) @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(m4datadir)'; $(am__uninstall_files_from_dir) install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) install-pkginclude_internalHEADERS: $(pkginclude_internal_HEADERS) @$(NORMAL_INSTALL) @list='$(pkginclude_internal_HEADERS)'; test -n "$(pkginclude_internaldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkginclude_internaldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkginclude_internaldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginclude_internaldir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginclude_internaldir)" || exit $$?; \ done uninstall-pkginclude_internalHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_internal_HEADERS)'; test -n "$(pkginclude_internaldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkginclude_internaldir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ else \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all $(check_PROGRAMS) @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? samples/sample1_unittest.log: samples/sample1_unittest$(EXEEXT) @p='samples/sample1_unittest$(EXEEXT)'; \ b='samples/sample1_unittest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) samples/sample10_unittest.log: samples/sample10_unittest$(EXEEXT) @p='samples/sample10_unittest$(EXEEXT)'; \ b='samples/sample10_unittest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/gtest_all_test.log: test/gtest_all_test$(EXEEXT) @p='test/gtest_all_test$(EXEEXT)'; \ b='test/gtest_all_test'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/fused_gtest_test.log: test/fused_gtest_test$(EXEEXT) @p='test/fused_gtest_test$(EXEEXT)'; \ b='test/fused_gtest_test'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(SCRIPTS) $(DATA) \ $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgincludedir)" "$(DESTDIR)$(pkginclude_internaldir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f fused-src/gtest/$(DEPDIR)/$(am__dirstamp) -rm -f fused-src/gtest/$(am__dirstamp) -rm -f lib/$(am__dirstamp) -rm -f samples/$(DEPDIR)/$(am__dirstamp) -rm -f samples/$(am__dirstamp) -rm -f src/$(DEPDIR)/$(am__dirstamp) -rm -f src/$(am__dirstamp) -rm -f test/$(DEPDIR)/$(am__dirstamp) -rm -f test/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLIBRARIES \ clean-libtool clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf fused-src/gtest/$(DEPDIR) samples/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-m4dataDATA install-pkgincludeHEADERS \ install-pkginclude_internalHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binSCRIPTS install-libLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf fused-src/gtest/$(DEPDIR) samples/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic \ maintainer-clean-local mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binSCRIPTS uninstall-libLIBRARIES \ uninstall-m4dataDATA uninstall-pkgincludeHEADERS \ uninstall-pkginclude_internalHEADERS .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-TESTS \ check-am clean clean-checkPROGRAMS clean-cscope clean-generic \ clean-libLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags distcleancheck \ distdir distuninstallcheck dvi dvi-am html html-am info \ info-am install install-am install-binSCRIPTS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLIBRARIES install-m4dataDATA \ install-man install-pdf install-pdf-am \ install-pkgincludeHEADERS install-pkginclude_internalHEADERS \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic maintainer-clean-local mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am recheck tags tags-am uninstall \ uninstall-am uninstall-binSCRIPTS uninstall-libLIBRARIES \ uninstall-m4dataDATA uninstall-pkgincludeHEADERS \ uninstall-pkginclude_internalHEADERS # Build rules for putting fused Google Test files into the distribution # package. The user can also create those files by manually running # scripts/fuse_gtest_files.py. $(test_fused_gtest_test_SOURCES): fused-gtest fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \ scripts/fuse_gtest_files.py mkdir -p "$(srcdir)/fused-src" chmod -R u+w "$(srcdir)/fused-src" rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc" rm -f "$(srcdir)/fused-src/gtest/gtest.h" "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src" cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/" maintainer-clean-local: rm -rf "$(srcdir)/fused-src" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ceph-0.80.11/src/gtest/codegear/0000775000175100017510000000000012623077036020356 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/gtest/codegear/gtest_main.cbproj0000664000175100017510000002072612623076744023725 0ustar jenkins-buildjenkins-build {bca37a72-5b07-46cf-b44e-89f8e06451a2} Release true true true Base true true Base true lib JPHNE NO_STRICT true true CppStaticLibrary true rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. rtl.lib;vcl.lib 32 $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppStaticLibrary FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 0 Cfg_1 Cfg_2 ceph-0.80.11/src/gtest/codegear/gtest_link.cc0000664000175100017510000000376112623076744023044 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: Josh Kelley (joshkel@gmail.com) // // Google C++ Testing Framework (Google Test) // // Links gtest.lib and gtest_main.lib into the current project in C++Builder. // This means that these libraries can't be renamed, but it's the only way to // ensure that Debug versus Release test builds are linked against the // appropriate Debug or Release build of the libraries. #pragma link "gtest.lib" #pragma link "gtest_main.lib" ceph-0.80.11/src/gtest/codegear/gtest_all.cc0000664000175100017510000000355712623076744022662 0ustar jenkins-buildjenkins-build// Copyright 2009, Google Inc. // 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. // // Author: Josh Kelley (joshkel@gmail.com) // // Google C++ Testing Framework (Google Test) // // C++Builder's IDE cannot build a static library from files with hyphens // in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 . // This file serves as a workaround. #include "src/gtest-all.cc" ceph-0.80.11/src/gtest/codegear/gtest.cbproj0000664000175100017510000002457712623076744022731 0ustar jenkins-buildjenkins-build {bca37a72-5b07-46cf-b44e-89f8e06451a2} Release true true true Base true true Base true lib JPHNE NO_STRICT true true CppStaticLibrary true rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. rtl.lib;vcl.lib 32 $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppStaticLibrary FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 3 4 5 6 7 8 0 1 2 9 10 11 12 14 13 15 16 17 18 Cfg_1 Cfg_2 ceph-0.80.11/src/gtest/codegear/gtest.groupproj0000664000175100017510000000401512623076744023462 0ustar jenkins-buildjenkins-build {c1d923e0-6cba-4332-9b6f-3420acbf5091} Default.Personality ceph-0.80.11/src/gtest/codegear/gtest_unittest.cbproj0000664000175100017510000002111212623076744024646 0ustar jenkins-buildjenkins-build {eea63393-5ac5-4b9c-8909-d75fef2daa41} Release true true true Base true true Base exe true NO_STRICT JPHNE true ..\test true CppConsoleApplication true true rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;.. $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test true false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppConsoleApplication FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test2NO_STRICTSTRICT 0 1 Cfg_1 Cfg_2 ceph-0.80.11/src/gtest/README0000664000175100017510000003526712623076744017507 0ustar jenkins-buildjenkins-buildGoogle C++ Testing Framework ============================ http://code.google.com/p/googletest/ Overview -------- Google's framework for writing C++ tests on a variety of platforms (Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the xUnit architecture. Supports automatic test discovery, a rich set of assertions, user-defined assertions, death tests, fatal and non-fatal failures, various options for running the tests, and XML test report generation. Please see the project page above for more information as well as the mailing list for questions, discussions, and development. There is also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please join us! Requirements for End Users -------------------------- Google Test is designed to have fairly minimal requirements to build and use with your projects, but there are some. Currently, we support Linux, Windows, Mac OS X, and Cygwin. We will also make our best effort to support other platforms (e.g. Solaris, AIX, and z/OS). However, since core members of the Google Test project have no access to these platforms, Google Test may have outstanding issues there. If you notice any problems on your platform, please notify googletestframework@googlegroups.com. Patches for fixing them are even more welcome! ### Linux Requirements ### These are the base requirements to build and use Google Test from a source package (as described below): * GNU-compatible Make or gmake * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) * A C++98-standard-compliant compiler ### Windows Requirements ### * Microsoft Visual C++ 7.1 or newer ### Cygwin Requirements ### * Cygwin 1.5.25-14 or newer ### Mac OS X Requirements ### * Mac OS X 10.4 Tiger or newer * Developer Tools Installed Also, you'll need CMake 2.6.4 or higher if you want to build the samples using the provided CMake script, regardless of the platform. Requirements for Contributors ----------------------------- We welcome patches. If you plan to contribute a patch, you need to build Google Test and its own tests from an SVN checkout (described below), which has further requirements: * Python version 2.3 or newer (for running some of the tests and re-generating certain source files from templates) * CMake 2.6.4 or newer Getting the Source ------------------ There are two primary ways of getting Google Test's source code: you can download a stable source release in your preferred archive format, or directly check out the source from our Subversion (SVN) repositary. The SVN checkout requires a few extra steps and some extra software packages on your system, but lets you track the latest development and make patches much more easily, so we highly encourage it. ### Source Package ### Google Test is released in versioned source packages which can be downloaded from the download page [1]. Several different archive formats are provided, but the only difference is the tools used to manipulate them, and the size of the resulting file. Download whichever you are most comfortable with. [1] http://code.google.com/p/googletest/downloads/list Once the package is downloaded, expand it using whichever tools you prefer for that type. This will result in a new directory with the name "gtest-X.Y.Z" which contains all of the source code. Here are some examples on Linux: tar -xvzf gtest-X.Y.Z.tar.gz tar -xvjf gtest-X.Y.Z.tar.bz2 unzip gtest-X.Y.Z.zip ### SVN Checkout ### To check out the main branch (also known as the "trunk") of Google Test, run the following Subversion command: svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn Setting up the Build -------------------- To build Google Test and your tests that use it, you need to tell your build system where to find its headers and source files. The exact way to do it depends on which build system you use, and is usually straightforward. ### Generic Build Instructions ### Suppose you put Google Test in directory ${GTEST_DIR}. To build it, create a library build target (or a project as called by Visual Studio and Xcode) to compile ${GTEST_DIR}/src/gtest-all.cc with ${GTEST_DIR}/include and ${GTEST_DIR} in the header search path. Assuming a Linux-like system and gcc, something like the following will do: g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc ar -rv libgtest.a gtest-all.o Next, you should compile your test source file with ${GTEST_DIR}/include in the header search path, and link it with gtest and any other necessary libraries: g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test As an example, the make/ directory contains a Makefile that you can use to build Google Test on systems where GNU make is available (e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google Test's own tests. Instead, it just builds the Google Test library and a sample test. You can use it as a starting point for your own build script. If the default settings are correct for your environment, the following commands should succeed: cd ${GTEST_DIR}/make make ./sample1_unittest If you see errors, try to tweak the contents of make/Makefile to make them go away. There are instructions in make/Makefile on how to do it. ### Using CMake ### Google Test comes with a CMake build script (CMakeLists.txt) that can be used on a wide range of platforms ("C" stands for cross-platofrm.). If you don't have CMake installed already, you can download it for free from http://www.cmake.org/. CMake works by generating native makefiles or build projects that can be used in the compiler environment of your choice. The typical workflow starts with: mkdir mybuild # Create a directory to hold the build output. cd mybuild cmake ${GTEST_DIR} # Generate native build scripts. If you want to build Google Test's samples, you should replace the last command with cmake -Dbuild_gtest_samples=ON ${GTEST_DIR} If you are on a *nix system, you should now see a Makefile in the current directory. Just type 'make' to build gtest. If you use Windows and have Vistual Studio installed, a gtest.sln file and several .vcproj files will be created. You can then build them using Visual Studio. On Mac OS X with Xcode installed, a .xcodeproj file will be generated. ### Legacy Build Scripts ### Before settling on CMake, we have been providing hand-maintained build projects/scripts for Visual Studio, Xcode, and Autotools. While we continue to provide them for convenience, they are not actively maintained any more. We highly recommend that you follow the instructions in the previous two sections to integrate Google Test with your existing build system. If you still need to use the legacy build scripts, here's how: The msvc\ folder contains two solutions with Visual C++ projects. Open the gtest.sln or gtest-md.sln file using Visual Studio, and you are ready to build Google Test the same way you build any Visual Studio project. Files that have names ending with -md use DLL versions of Microsoft runtime libraries (the /MD or the /MDd compiler option). Files without that suffix use static versions of the runtime libraries (the /MT or the /MTd option). Please note that one must use the same option to compile both gtest and the test code. If you use Visual Studio 2005 or above, we recommend the -md version as /MD is the default for new projects in these versions of Visual Studio. On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using Xcode. Build the "gtest" target. The universal binary framework will end up in your selected build directory (selected in the Xcode "Preferences..." -> "Building" pane and defaults to xcode/build). Alternatively, at the command line, enter: xcodebuild This will build the "Release" configuration of gtest.framework in your default build location. See the "xcodebuild" man page for more information about building different configurations and building in different locations. Tweaking Google Test -------------------- Google Test can be used in diverse environments. The default configuration may not work (or may not work well) out of the box in some environments. However, you can easily tweak Google Test by defining control macros on the compiler command line. Generally, these macros are named like GTEST_XYZ and you define them to either 1 or 0 to enable or disable a certain feature. We list the most frequently used macros below. For a complete list, see file include/gtest/internal/gtest-port.h. ### Choosing a TR1 Tuple Library ### Some Google Test features require the C++ Technical Report 1 (TR1) tuple library, which is not yet available with all compilers. The good news is that Google Test implements a subset of TR1 tuple that's enough for its own need, and will automatically use this when the compiler doesn't provide TR1 tuple. Usually you don't need to care about which tuple library Google Test uses. However, if your project already uses TR1 tuple, you need to tell Google Test to use the same TR1 tuple library the rest of your project uses, or the two tuple implementations will clash. To do that, add -DGTEST_USE_OWN_TR1_TUPLE=0 to the compiler flags while compiling Google Test and your tests. If you want to force Google Test to use its own tuple library, just add -DGTEST_USE_OWN_TR1_TUPLE=1 to the compiler flags instead. If you don't want Google Test to use tuple at all, add -DGTEST_HAS_TR1_TUPLE=0 and all features using tuple will be disabled. ### Multi-threaded Tests ### Google Test is thread-safe where the pthread library is available. After #include , you can check the GTEST_IS_THREADSAFE macro to see whether this is the case (yes if the macro is #defined to 1, no if it's undefined.). If Google Test doesn't correctly detect whether pthread is available in your environment, you can force it with -DGTEST_HAS_PTHREAD=1 or -DGTEST_HAS_PTHREAD=0 When Google Test uses pthread, you may need to add flags to your compiler and/or linker to select the pthread library, or you'll get link errors. If you use the CMake script or the deprecated Autotools script, this is taken care of for you. If you use your own build script, you'll need to read your compiler and linker's manual to figure out what flags to add. ### As a Shared Library (DLL) ### Google Test is compact, so most users can build and link it as a static library for the simplicity. You can choose to use Google Test as a shared library (known as a DLL on Windows) if you prefer. To compile gtest as a shared library, add -DGTEST_CREATE_SHARED_LIBRARY=1 to the compiler flags. You'll also need to tell the linker to produce a shared library instead - consult your linker's manual for how to do it. To compile your tests that use the gtest shared library, add -DGTEST_LINKED_AS_SHARED_LIBRARY=1 to the compiler flags. ### Avoiding Macro Name Clashes ### In C++, macros don't obey namespaces. Therefore two libraries that both define a macro of the same name will clash if you #include both definitions. In case a Google Test macro clashes with another library, you can force Google Test to rename its macro to avoid the conflict. Specifically, if both Google Test and some other code define macro FOO, you can add -DGTEST_DONT_DEFINE_FOO=1 to the compiler flags to tell Google Test to change the macro's name from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST. For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write GTEST_TEST(SomeTest, DoesThis) { ... } instead of TEST(SomeTest, DoesThis) { ... } in order to define a test. Upgrating from an Earlier Version --------------------------------- We strive to keep Google Test releases backward compatible. Sometimes, though, we have to make some breaking changes for the users' long-term benefits. This section describes what you'll need to do if you are upgrading from an earlier version of Google Test. ### Upgrading from 1.3.0 or Earlier ### You may need to explicitly enable or disable Google Test's own TR1 tuple library. See the instructions in section "Choosing a TR1 Tuple Library". ### Upgrading from 1.4.0 or Earlier ### The Autotools build script (configure + make) is no longer officially supportted. You are encouraged to migrate to your own build system or use CMake. If you still need to use Autotools, you can find instructions in the README file from Google Test 1.4.0. On platforms where the pthread library is available, Google Test uses it in order to be thread-safe. See the "Multi-threaded Tests" section for what this means to your build script. If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google Test will no longer compile. This should affect very few people, as a large portion of STL (including ) doesn't compile in this mode anyway. We decided to stop supporting it in order to greatly simplify Google Test's implementation. Developing Google Test ---------------------- This section discusses how to make your own changes to Google Test. ### Testing Google Test Itself ### To make sure your changes work as intended and don't break existing functionality, you'll want to compile and run Google Test's own tests. For that you can use CMake: mkdir mybuild cd mybuild cmake -Dbuild_all_gtest_tests=ON ${GTEST_DIR} Make sure you have Python installed, as some of Google Test's tests are written in Python. If the cmake command complains about not being able to find Python ("Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)"), try telling it explicitly where your Python executable can be found: cmake -DPYTHON_EXECUTABLE=path/to/python -Dbuild_all_gtest_tests=ON \ ${GTEST_DIR} Next, you can build Google Test and all of its own tests. On *nix, this is usually done by 'make'. To run the tests, do make test All tests should pass. ### Regenerating Source Files ### Some of Google Test's source files are generated from templates (not in the C++ sense) using a script. A template file is named FOO.pump, where FOO is the name of the file it will generate. For example, the file include/gtest/internal/gtest-type-util.h.pump is used to generate gtest-type-util.h in the same directory. Normally you don't need to worry about regenerating the source files, unless you need to modify them. In that case, you should modify the corresponding .pump files instead and run the pump.py Python script to regenerate them. You can find pump.py in the scripts/ directory. Read the Pump manual [2] for how to use it. [2] http://code.google.com/p/googletest/wiki/PumpManual ### Contributing a Patch ### We welcome patches. Please read the Google Test developer's guide [3] for how you can contribute. In particular, make sure you have signed the Contributor License Agreement, or we won't be able to accept the patch. [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide Happy testing! ceph-0.80.11/src/init-ceph.in0000664000175100017510000003144712623076744017705 0ustar jenkins-buildjenkins-build#!/bin/sh # Start/stop ceph daemons # chkconfig: 2345 60 80 ### BEGIN INIT INFO # Provides: ceph # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Required-Start: $remote_fs $named $network $time # Required-Stop: $remote_fs $named $network $time # Short-Description: Start Ceph distributed file system daemons at boot time # Description: Enable Ceph distributed file system services. ### END INIT INFO . /lib/lsb/init-functions # if we start up as ./mkcephfs, assume everything else is in the # current directory too. if [ `dirname $0` = "." ] && [ $PWD != "/etc/init.d" ]; then BINDIR=. SBINDIR=. LIBDIR=. ETCDIR=. else BINDIR=@bindir@ SBINDIR=@prefix@/sbin LIBDIR=@libdir@/ceph ETCDIR=@sysconfdir@/ceph fi usage_exit() { echo "usage: $0 [options] {start|stop|restart|condrestart} [mon|osd|mds]..." printf "\t-c ceph.conf\n" printf "\t--cluster [cluster name]\tdefine the cluster name\n" printf "\t--valgrind\trun via valgrind\n" printf "\t--hostname [hostname]\toverride hostname lookup\n" exit } # behave if we are not completely installed (e.g., Debian "removed, # config remains" state) test -f $LIBDIR/ceph_common.sh || exit 0 . $LIBDIR/ceph_common.sh EXIT_STATUS=0 # detect systemd SYSTEMD=0 grep -qs systemd /proc/1/comm && SYSTEMD=1 signal_daemon() { name=$1 daemon=$2 pidfile=$3 signal=$4 action=$5 [ -z "$action" ] && action="Stopping" echo -n "$action Ceph $name on $host..." do_cmd "if [ -e $pidfile ]; then pid=`cat $pidfile` if [ -e /proc/\$pid ] && grep -q $daemon /proc/\$pid/cmdline ; then cmd=\"kill $signal \$pid\" echo -n \$cmd... \$cmd fi fi" echo done } daemon_is_running() { name=$1 daemon=$2 daemon_id=$3 pidfile=$4 do_cmd "[ -e $pidfile ] || exit 1 # no pid, presumably not running pid=\`cat $pidfile\` [ -e /proc/\$pid ] && grep -q $daemon /proc/\$pid/cmdline && grep -qwe -i.$daemon_id /proc/\$pid/cmdline && exit 0 # running exit 1 # pid is something else" "" "okfail" } stop_daemon() { name=$1 daemon=$2 pidfile=$3 signal=$4 action=$5 [ -z "$action" ] && action="Stopping" echo -n "$action Ceph $name on $host..." do_cmd "while [ 1 ]; do [ -e $pidfile ] || break pid=\`cat $pidfile\` while [ -e /proc/\$pid ] && grep -q $daemon /proc/\$pid/cmdline ; do cmd=\"kill $signal \$pid\" echo -n \$cmd... \$cmd sleep 1 continue done break done" echo done } ## command line options options= version=0 dovalgrind= docrun= allhosts=0 debug=0 monaddr= dofsmount=1 dofsumount=0 verbose=0 use_default_conf=1 while echo $1 | grep -q '^-'; do # FIXME: why not '^-'? case $1 in -v | --verbose) verbose=1 ;; --valgrind) dovalgrind=1 ;; --novalgrind) dovalgrind=0 ;; --allhosts | -a) allhosts=1; ;; --restart) docrun=1 ;; --norestart) docrun=0 ;; -m ) [ -z "$2" ] && usage_exit options="$options $1" shift MON_ADDR=$1 ;; --btrfs | --fsmount) dofsmount=1 ;; --nobtrfs | --nofsmount) dofsmount=0 ;; --btrfsumount | --fsumount) dofsumount=1 ;; --conf | -c) [ -z "$2" ] && usage_exit options="$options $1" shift use_default_conf=0 conf=$1 ;; --cluster ) [ -z "$2" ] && usage_exit options="$options $1" shift cluster=$1 ;; --hostname ) [ -z "$2" ] && usage_exit options="$options $1" shift hostname=$1 ;; *) echo unrecognized option \'$1\' usage_exit ;; esac options="$options $1" shift done # if `--cluster` was not passed in, fallback to looking at the config name if [ -z "$cluster" ]; then cluster=`echo $conf | awk -F'/' '{print $(NF)}' | cut -d'.' -f 1` else # if we were told to use a given cluster name then $conf needs to be updated # but just define it if `--conf` was not specified, otherwise we would be silently # overriding $conf even if it was defined with `--conf` if [ $use_default_conf -eq 1 ]; then conf="/etc/ceph/$cluster.conf" fi fi verify_conf command=$1 [ -n "$*" ] && shift get_local_name_list get_name_list "$@" # Reverse the order if we are stopping if [ "$command" = "stop" ]; then for f in $what; do new_order="$f $new_order" done what="$new_order" fi for name in $what; do type=`echo $name | cut -c 1-3` # e.g. 'mon', if $item is 'mon1' id=`echo $name | cut -c 4- | sed 's/^\\.//'` num=$id name="$type.$id" check_host $cluster || continue binary="$BINDIR/ceph-$type" cmd="$binary -i $id" get_conf run_dir "/var/run/ceph" "run dir" get_conf pid_file "$run_dir/$type.$id.pid" "pid file" if [ "$command" = "start" ]; then if [ -n "$pid_file" ]; then do_cmd "mkdir -p "`dirname $pid_file` cmd="$cmd --pid-file $pid_file" fi get_conf log_dir "" "log dir" [ -n "$log_dir" ] && do_cmd "mkdir -p $log_dir" get_conf auto_start "" "auto start" if [ "$auto_start" = "no" ] || [ "$auto_start" = "false" ] || [ "$auto_start" = "0" ]; then if [ -z "$@" ]; then echo "Skipping Ceph $name on $host... auto start is disabled" continue fi fi if daemon_is_running $name ceph-$type $id $pid_file; then echo "Starting Ceph $name on $host...already running" continue fi get_conf copy_executable_to "" "copy executable to" if [ -n "$copy_executable_to" ]; then scp $binary "$host:$copy_executable_to" binary="$copy_executable_to" fi fi # conf file cmd="$cmd -c $conf" if echo $name | grep -q ^osd; then get_conf osd_data "/var/lib/ceph/osd/$cluster-$id" "osd data" get_conf fs_path "$osd_data" "fs path" # mount point defaults so osd data get_conf fs_devs "" "devs" if [ -z "$fs_devs" ]; then # try to fallback to old keys get_conf tmp_btrfs_devs "" "btrfs devs" if [ -n "$tmp_btrfs_devs" ]; then fs_devs="$tmp_btrfs_devs" fi fi first_dev=`echo $fs_devs | cut '-d ' -f 1` fi # do lockfile, if RH get_conf lockfile "/var/lock/subsys/ceph" "lock file" lockdir=`dirname $lockfile` if [ ! -d "$lockdir" ]; then lockfile="" fi get_conf asok "$run_dir/ceph-$type.$id.asok" "admin socket" case "$command" in start) # Increase max_open_files, if the configuration calls for it. get_conf max_open_files "32768" "max open files" # build final command wrap="" runmode="" runarg="" [ -z "$docrun" ] && get_conf_bool docrun "0" "restart on core dump" [ "$docrun" -eq 1 ] && wrap="$BINDIR/ceph-run" [ -z "$dovalgrind" ] && get_conf_bool valgrind "" "valgrind" [ -n "$valgrind" ] && wrap="$wrap valgrind $valgrind" [ -n "$wrap" ] && runmode="-f &" && runarg="-f" [ -n "$max_open_files" ] && files="ulimit -n $max_open_files;" if [ $SYSTEMD -eq 1 ]; then cmd="systemd-run -r bash -c '$files $cmd --cluster $cluster -f'" else cmd="$files $wrap $cmd --cluster $cluster $runmode" fi if [ $dofsmount -eq 1 ] && [ -n "$fs_devs" ]; then get_conf pre_mount "true" "pre mount command" get_conf fs_type "" "osd mkfs type" if [ -z "$fs_type" ]; then # try to fallback to to old keys get_conf tmp_devs "" "btrfs devs" if [ -n "$tmp_devs" ]; then fs_type="btrfs" else echo No filesystem type defined! exit 0 fi fi get_conf fs_opt "" "osd mount options $fs_type" if [ -z "$fs_opt" ]; then if [ "$fs_type" = "btrfs" ]; then #try to fallback to old keys get_conf fs_opt "" "btrfs options" fi if [ -z "$fs_opt" ]; then if [ "$fs_type" = "xfs" ]; then fs_opt="rw,noatime,inode64" else #fallback to use at least noatime fs_opt="rw,noatime" fi fi fi [ -n "$fs_opt" ] && fs_opt="-o $fs_opt" [ -n "$pre_mount" ] && do_cmd "$pre_mount" if [ "$fs_type" = "btrfs" ]; then echo Mounting Btrfs on $host:$fs_path do_root_cmd_okfail "modprobe btrfs ; btrfs device scan || btrfsctl -a ; egrep -q '^[^ ]+ $fs_path' /proc/mounts || mount -t btrfs $fs_opt $first_dev $fs_path" else echo Mounting $fs_type on $host:$fs_path do_root_cmd_okfail "modprobe $fs_type ; egrep -q '^[^ ]+ $fs_path' /proc/mounts || mount -t $fs_type $fs_opt $first_dev $fs_path" fi if [ "$ERR" != "0" ]; then EXIT_STATUS=$ERR continue fi fi if [ "$type" = "osd" ]; then get_conf update_crush "" "osd crush update on start" if [ "${update_crush:-1}" = "1" -o "${update_crush:-1}" = "true" ]; then # update location in crush get_conf osd_location_hook "$BINDIR/ceph-crush-location" "osd crush location hook" osd_location=`$osd_location_hook --cluster $cluster --id $id --type osd` get_conf osd_weight "" "osd crush initial weight" defaultweight="$(df -P -k $osd_data/. | tail -1 | awk '{ print sprintf("%.2f",$2/1073741824) }')" get_conf osd_keyring "$osd_data/keyring" "keyring" do_cmd "timeout 30 $BINDIR/ceph -c $conf --name=osd.$id --keyring=$osd_keyring osd crush create-or-move -- $id ${osd_weight:-${defaultweight:-1}} $osd_location" fi fi echo Starting Ceph $name on $host... mkdir -p $run_dir get_conf pre_start_eval "" "pre start eval" [ -n "$pre_start_eval" ] && $pre_start_eval get_conf pre_start "" "pre start command" get_conf post_start "" "post start command" [ -n "$pre_start" ] && do_cmd "$pre_start" do_cmd_okfail "$cmd" $runarg if [ "$ERR" != "0" ]; then EXIT_STATUS=$ERR fi if [ "$type" = "mon" ]; then # this will only work if we are using default paths # for the mon data and admin socket. if so, run # ceph-create-keys. this is the case for (normal) # chef and ceph-deploy clusters, which is who needs # these keys. it's also true for default installs # via mkcephfs, which is fine too; there is no harm # in creating these keys. get_conf mon_data "/var/lib/ceph/mon/ceph-$id" "mon data" if [ "$mon_data" = "/var/lib/ceph/mon/ceph-$id" -a "$asok" = "/var/run/ceph/ceph-mon.$id.asok" ]; then echo Starting ceph-create-keys on $host... cmd2="$SBINDIR/ceph-create-keys --cluster $cluster -i $id 2> /dev/null &" do_cmd "$cmd2" fi fi [ -n "$post_start" ] && do_cmd "$post_start" [ -n "$lockfile" ] && [ "$?" -eq 0 ] && touch $lockfile ;; stop) get_conf pre_stop "" "pre stop command" get_conf post_stop "" "post stop command" [ -n "$pre_stop" ] && do_cmd "$pre_stop" stop_daemon $name ceph-$type $pid_file [ -n "$post_stop" ] && do_cmd "$post_stop" [ -n "$lockfile" ] && [ "$?" -eq 0 ] && rm -f $lockfile if [ $dofsumount -eq 1 ] && [ -n "$fs_devs" ]; then echo Unmounting OSD volume on $host:$fs_path do_root_cmd "umount $fs_path || true" fi ;; status) if daemon_is_running $name ceph-$type $id $pid_file; then echo -n "$name: running " do_cmd "$BINDIR/ceph --admin-daemon $asok version 2>/dev/null" || echo unknown elif [ -e "$pid_file" ]; then # daemon is dead, but pid file still exists echo "$name: dead." EXIT_STATUS=1 else # daemon is dead, and pid file is gone echo "$name: not running." EXIT_STATUS=3 fi ;; ssh) $ssh ;; forcestop) get_conf pre_forcestop "" "pre forcestop command" get_conf post_forcestop "" "post forcestop command" [ -n "$pre_forcestop" ] && do_cmd "$pre_forcestop" stop_daemon $name ceph-$type $pid_file -9 [ -n "$post_forcestop" ] && do_cmd "$post_forcestop" [ -n "$lockfile" ] && [ "$?" -eq 0 ] && rm -f $lockfile ;; killall) echo "killall ceph-$type on $host" do_cmd "pkill ^ceph-$type || true" [ -n "$lockfile" ] && [ "$?" -eq 0 ] && rm -f $lockfile ;; force-reload | reload) signal_daemon $name ceph-$type $pid_file -1 "Reloading" ;; restart) $0 $options stop $name $0 $options start $name ;; condrestart) if daemon_is_running $name ceph-$type $id $pid_file; then $0 $options stop $name $0 $options start $name else echo "$name: not running." fi ;; cleanlogs) echo removing logs [ -n "$log_dir" ] && do_cmd "rm -f $log_dir/$type.$id.*" ;; cleanalllogs) echo removing all logs [ -n "$log_dir" ] && do_cmd "rm -f $log_dir/* || true" ;; *) usage_exit ;; esac done # activate latent osds? if [ "$command" = "start" -a "$BINDIR" != "." ]; then if [ "$*" = "" ] || echo $* | grep -q ^osd\$ ; then ceph-disk activate-all fi fi exit $EXIT_STATUS ceph-0.80.11/src/messages/0000775000175100017510000000000012623077034017264 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/messages/MMonJoin.h0000664000175100017510000000254612623076744021141 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONJOIN_H #define CEPH_MMONJOIN_H #include "messages/PaxosServiceMessage.h" #include using std::vector; class MMonJoin : public PaxosServiceMessage { public: uuid_d fsid; string name; entity_addr_t addr; MMonJoin() : PaxosServiceMessage(MSG_MON_JOIN, 0) {} MMonJoin(uuid_d &f, string n, const entity_addr_t& a) : PaxosServiceMessage(MSG_MON_JOIN, 0), fsid(f), name(n), addr(a) { } private: ~MMonJoin() {} public: const char *get_type_name() const { return "mon_join"; } void print(ostream& o) const { o << "mon_join(" << name << " " << addr << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(name, payload); ::encode(addr, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(name, p); ::decode(addr, p); } }; #endif ceph-0.80.11/src/messages/MOSDSubOp.h0000664000175100017510000001644312623076744021167 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDSUBOP_H #define CEPH_MOSDSUBOP_H #include "msg/Message.h" #include "osd/osd_types.h" /* * OSD sub op - for internal ops on pobjects between primary and replicas(/stripes/whatever) */ class MOSDSubOp : public Message { static const int HEAD_VERSION = 11; static const int COMPAT_VERSION = 1; public: epoch_t map_epoch; // metadata from original request osd_reqid_t reqid; // subop pg_shard_t from; spg_t pgid; hobject_t poid; object_locator_t oloc; __u8 acks_wanted; // op to exec vector ops; utime_t mtime; bool noop; bool old_exists; uint64_t old_size; eversion_t old_version; SnapSet snapset; SnapContext snapc; // transaction to exec bufferlist logbl; pg_stat_t pg_stats; // subop metadata eversion_t version; // piggybacked osd/og state eversion_t pg_trim_to; // primary->replica: trim to here eversion_t pg_trim_rollback_to; // primary->replica: trim rollback // info to here osd_peer_stat_t peer_stat; map attrset; interval_set data_subset; map > clone_subsets; bool first, complete; interval_set data_included; ObjectRecoveryInfo recovery_info; // reflects result of current push ObjectRecoveryProgress recovery_progress; // reflects progress before current push ObjectRecoveryProgress current_progress; map omap_entries; bufferlist omap_header; // indicates that we must fix hobject_t encoding bool hobject_incorrect_pool; hobject_t new_temp_oid; ///< new temp object that we must now start tracking hobject_t discard_temp_oid; ///< previously used temp object that we can now stop tracking /// non-empty if this transaction involves a hit_set history update boost::optional updated_hit_set_history; int get_cost() const { if (ops.size() == 1 && ops[0].op.op == CEPH_OSD_OP_PULL) return ops[0].op.extent.length; return data.length(); } virtual void decode_payload() { hobject_incorrect_pool = false; bufferlist::iterator p = payload.begin(); ::decode(map_epoch, p); ::decode(reqid, p); ::decode(pgid.pgid, p); ::decode(poid, p); __u32 num_ops; ::decode(num_ops, p); ops.resize(num_ops); unsigned off = 0; for (unsigned i = 0; i < num_ops; i++) { ::decode(ops[i].op, p); ops[i].indata.substr_of(data, off, ops[i].op.payload_len); off += ops[i].op.payload_len; } ::decode(mtime, p); ::decode(noop, p); ::decode(acks_wanted, p); ::decode(version, p); ::decode(old_exists, p); ::decode(old_size, p); ::decode(old_version, p); ::decode(snapset, p); ::decode(snapc, p); ::decode(logbl, p); ::decode(pg_stats, p); ::decode(pg_trim_to, p); ::decode(peer_stat, p); ::decode(attrset, p); ::decode(data_subset, p); ::decode(clone_subsets, p); if (header.version >= 2) { ::decode(first, p); ::decode(complete, p); } if (header.version >= 3) ::decode(oloc, p); if (header.version >= 4) { ::decode(data_included, p); recovery_info.decode(p, pgid.pool()); ::decode(recovery_progress, p); ::decode(current_progress, p); } if (header.version >= 5) ::decode(omap_entries, p); if (header.version >= 6) ::decode(omap_header, p); if (header.version < 7) { // Handle hobject_t format change if (!poid.is_max() && poid.pool == -1) poid.pool = pgid.pool(); hobject_incorrect_pool = true; } if (header.version >= 8) { ::decode(new_temp_oid, p); ::decode(discard_temp_oid, p); } if (header.version >= 9) { ::decode(from, p); ::decode(pgid.shard, p); } else { from = pg_shard_t( get_source().num(), ghobject_t::NO_SHARD); pgid.shard = ghobject_t::NO_SHARD; } if (header.version >= 10) { ::decode(updated_hit_set_history, p); } if (header.version >= 11) { ::decode(pg_trim_rollback_to, p); } else { pg_trim_rollback_to = pg_trim_to; } } virtual void encode_payload(uint64_t features) { ::encode(map_epoch, payload); ::encode(reqid, payload); ::encode(pgid.pgid, payload); ::encode(poid, payload); __u32 num_ops = ops.size(); ::encode(num_ops, payload); for (unsigned i = 0; i < ops.size(); i++) { ops[i].op.payload_len = ops[i].indata.length(); ::encode(ops[i].op, payload); data.append(ops[i].indata); } ::encode(mtime, payload); ::encode(noop, payload); ::encode(acks_wanted, payload); ::encode(version, payload); ::encode(old_exists, payload); ::encode(old_size, payload); ::encode(old_version, payload); ::encode(snapset, payload); ::encode(snapc, payload); ::encode(logbl, payload); ::encode(pg_stats, payload); ::encode(pg_trim_to, payload); ::encode(peer_stat, payload); ::encode(attrset, payload); ::encode(data_subset, payload); ::encode(clone_subsets, payload); if (ops.size()) header.data_off = ops[0].op.extent.offset; else header.data_off = 0; ::encode(first, payload); ::encode(complete, payload); ::encode(oloc, payload); ::encode(data_included, payload); ::encode(recovery_info, payload); ::encode(recovery_progress, payload); ::encode(current_progress, payload); ::encode(omap_entries, payload); ::encode(omap_header, payload); ::encode(new_temp_oid, payload); ::encode(discard_temp_oid, payload); ::encode(from, payload); ::encode(pgid.shard, payload); ::encode(updated_hit_set_history, payload); ::encode(pg_trim_rollback_to, payload); } MOSDSubOp() : Message(MSG_OSD_SUBOP, HEAD_VERSION, COMPAT_VERSION) { } MOSDSubOp(osd_reqid_t r, pg_shard_t from, spg_t p, const hobject_t& po, bool noop_, int aw, epoch_t mape, ceph_tid_t rtid, eversion_t v) : Message(MSG_OSD_SUBOP, HEAD_VERSION, COMPAT_VERSION), map_epoch(mape), reqid(r), from(from), pgid(p), poid(po), acks_wanted(aw), noop(noop_), old_exists(false), old_size(0), version(v), first(false), complete(false), hobject_incorrect_pool(false) { memset(&peer_stat, 0, sizeof(peer_stat)); set_tid(rtid); } private: ~MOSDSubOp() {} public: const char *get_type_name() const { return "osd_sub_op"; } void print(ostream& out) const { out << "osd_sub_op(" << reqid << " " << pgid << " " << poid << " " << ops; if (noop) out << " (NOOP)"; if (first) out << " first"; if (complete) out << " complete"; out << " v " << version << " snapset=" << snapset << " snapc=" << snapc; if (!data_subset.empty()) out << " subset " << data_subset; if (updated_hit_set_history) out << ", has_updated_hit_set_history"; out << ")"; } }; #endif ceph-0.80.11/src/messages/MClientSession.h0000664000175100017510000000347712623076744022356 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTSESSION_H #define CEPH_MCLIENTSESSION_H #include "msg/Message.h" class MClientSession : public Message { public: ceph_mds_session_head head; int get_op() const { return head.op; } version_t get_seq() const { return head.seq; } utime_t get_stamp() const { return utime_t(head.stamp); } int get_max_caps() const { return head.max_caps; } int get_max_leases() const { return head.max_leases; } MClientSession() : Message(CEPH_MSG_CLIENT_SESSION) { } MClientSession(int o, version_t s=0) : Message(CEPH_MSG_CLIENT_SESSION) { memset(&head, 0, sizeof(head)); head.op = o; head.seq = s; } MClientSession(int o, utime_t st) : Message(CEPH_MSG_CLIENT_SESSION) { memset(&head, 0, sizeof(head)); head.op = o; head.seq = 0; st.encode_timeval(&head.stamp); } private: ~MClientSession() {} public: const char *get_type_name() const { return "client_session"; } void print(ostream& out) const { out << "client_session(" << ceph_session_op_name(get_op()); if (get_seq()) out << " seq " << get_seq(); if (get_op() == CEPH_SESSION_RECALL_STATE) out << " max_caps " << head.max_caps << " max_leases " << head.max_leases; out << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(head, p); } void encode_payload(uint64_t features) { ::encode(head, payload); } }; #endif ceph-0.80.11/src/messages/MOSDECSubOpReadReply.h0000664000175100017510000000260112623076744023176 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDECSUBOPREADREPLY_H #define MOSDECSUBOPREADREPLY_H #include "msg/Message.h" #include "osd/osd_types.h" #include "osd/ECMsgTypes.h" class MOSDECSubOpReadReply : public Message { static const int HEAD_VERSION = 1; static const int COMPAT_VERSION = 1; public: spg_t pgid; epoch_t map_epoch; ECSubReadReply op; int get_cost() const { return 0; } MOSDECSubOpReadReply() : Message(MSG_OSD_EC_READ_REPLY, HEAD_VERSION, COMPAT_VERSION) {} virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid, p); ::decode(map_epoch, p); ::decode(op, p); } virtual void encode_payload(uint64_t features) { ::encode(pgid, payload); ::encode(map_epoch, payload); ::encode(op, payload); } const char *get_type_name() const { return "MOSDECSubOpReadReply"; } void print(ostream& out) const { out << "MOSDECSubOpReadReply(" << pgid << " " << map_epoch << " " << op; out << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDPGMissing.h0000664000175100017510000000254112623076744021771 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGMISSING_H #define CEPH_MOSDPGMISSING_H #include "msg/Message.h" class MOSDPGMissing : public Message { epoch_t epoch; public: pg_info_t info; pg_missing_t missing; epoch_t get_epoch() { return epoch; } MOSDPGMissing() : Message(MSG_OSD_PG_MISSING) {} MOSDPGMissing(version_t mv, const pg_info_t &info_, const pg_missing_t &missing_) : Message(MSG_OSD_PG_MISSING), epoch(mv), info(info_), missing(missing_) { } private: ~MOSDPGMissing() {} public: const char *get_type_name() const { return "pg_missing"; } void print(ostream& out) const { out << "pg_missing(" << info.pgid << " e" << epoch << ")"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); ::encode(info, payload); ::encode(missing, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); ::decode(info, p); missing.decode(p, info.pgid.pool()); } }; #endif ceph-0.80.11/src/messages/MOSDPing.h0000664000175100017510000000443312623076744021030 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPING_H #define CEPH_MOSDPING_H #include "common/Clock.h" #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPing : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: enum { HEARTBEAT = 0, START_HEARTBEAT = 1, YOU_DIED = 2, STOP_HEARTBEAT = 3, PING = 4, PING_REPLY = 5, }; const char *get_op_name(int op) const { switch (op) { case HEARTBEAT: return "heartbeat"; case START_HEARTBEAT: return "start_heartbeat"; case STOP_HEARTBEAT: return "stop_heartbeat"; case YOU_DIED: return "you_died"; case PING: return "ping"; case PING_REPLY: return "ping_reply"; default: return "???"; } } uuid_d fsid; epoch_t map_epoch, peer_as_of_epoch; __u8 op; osd_peer_stat_t peer_stat; utime_t stamp; MOSDPing(const uuid_d& f, epoch_t e, __u8 o, utime_t s) : Message(MSG_OSD_PING, HEAD_VERSION, COMPAT_VERSION), fsid(f), map_epoch(e), peer_as_of_epoch(0), op(o), stamp(s) { } MOSDPing() : Message(MSG_OSD_PING, HEAD_VERSION, COMPAT_VERSION) {} private: ~MOSDPing() {} public: void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(fsid, p); ::decode(map_epoch, p); ::decode(peer_as_of_epoch, p); ::decode(op, p); ::decode(peer_stat, p); if (header.version >= 2) ::decode(stamp, p); } void encode_payload(uint64_t features) { ::encode(fsid, payload); ::encode(map_epoch, payload); ::encode(peer_as_of_epoch, payload); ::encode(op, payload); ::encode(peer_stat, payload); ::encode(stamp, payload); } const char *get_type_name() const { return "osd_ping"; } void print(ostream& out) const { out << "osd_ping(" << get_op_name(op) << " e" << map_epoch //<< " as_of " << peer_as_of_epoch << " stamp " << stamp << ")"; } }; #endif ceph-0.80.11/src/messages/MHeartbeat.h0000664000175100017510000000262312623076744021463 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MHEARTBEAT_H #define CEPH_MHEARTBEAT_H #include "include/types.h" #include "msg/Message.h" class MHeartbeat : public Message { mds_load_t load; __s32 beat; map<__s32, float> import_map; public: mds_load_t& get_load() { return load; } int get_beat() { return beat; } map<__s32, float>& get_import_map() { return import_map; } MHeartbeat() : Message(MSG_MDS_HEARTBEAT), load(utime_t()) { } MHeartbeat(mds_load_t& load, int beat) : Message(MSG_MDS_HEARTBEAT), load(load) { this->beat = beat; } private: ~MHeartbeat() {} public: const char *get_type_name() const { return "HB"; } void encode_payload(uint64_t features) { ::encode(load, payload); ::encode(beat, payload); ::encode(import_map, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); utime_t now(ceph_clock_now(NULL)); ::decode(load, now, p); ::decode(beat, p); ::decode(import_map, p); } }; #endif ceph-0.80.11/src/messages/MExportDir.h0000664000175100017510000000262412623076744021505 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIR_H #define CEPH_MEXPORTDIR_H #include "msg/Message.h" class MExportDir : public Message { public: dirfrag_t dirfrag; bufferlist export_data; vector bounds; bufferlist client_map; MExportDir() : Message(MSG_MDS_EXPORTDIR) {} MExportDir(dirfrag_t df, uint64_t tid) : Message(MSG_MDS_EXPORTDIR), dirfrag(df) { set_tid(tid); } private: ~MExportDir() {} public: const char *get_type_name() const { return "Ex"; } void print(ostream& o) const { o << "export(" << dirfrag << ")"; } void add_export(dirfrag_t df) { bounds.push_back(df); } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(bounds, payload); ::encode(export_data, payload); ::encode(client_map, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(bounds, p); ::decode(export_data, p); ::decode(client_map, p); } }; #endif ceph-0.80.11/src/messages/MClientReply.h0000664000175100017510000001434112623076744022016 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTREPLY_H #define CEPH_MCLIENTREPLY_H #include "include/types.h" #include "MClientRequest.h" #include "msg/Message.h" #include "include/ceph_features.h" #include "common/errno.h" #include using namespace std; /*** * * MClientReply - container message for MDS reply to a client's MClientRequest * * key fields: * long tid - transaction id, so the client can match up with pending request * int result - error code, or fh if it was open * * for most requests: * trace is a vector of InodeStat's tracing from root to the file/dir/whatever * the operation referred to, so that the client can update it's info about what * metadata lives on what MDS. * * for readdir replies: * dir_contents is a vector of InodeStat*'s. * * that's mostly it, i think! * */ struct LeaseStat { // this matches ceph_mds_reply_lease __u16 mask; __u32 duration_ms; __u32 seq; LeaseStat() : mask(0), duration_ms(0), seq(0) {} void encode(bufferlist &bl) const { ::encode(mask, bl); ::encode(duration_ms, bl); ::encode(seq, bl); } void decode(bufferlist::iterator &bl) { ::decode(mask, bl); ::decode(duration_ms, bl); ::decode(seq, bl); } }; WRITE_CLASS_ENCODER(LeaseStat) inline ostream& operator<<(ostream& out, const LeaseStat& l) { return out << "lease(mask " << l.mask << " dur " << l.duration_ms << ")"; } struct DirStat { // mds distribution hints frag_t frag; __s32 auth; set<__s32> dist; DirStat() : auth(CDIR_AUTH_PARENT) {} DirStat(bufferlist::iterator& p) { decode(p); } void encode(bufferlist& bl) { ::encode(frag, bl); ::encode(auth, bl); ::encode(dist, bl); } void decode(bufferlist::iterator& p) { ::decode(frag, p); ::decode(auth, p); ::decode(dist, p); } // see CDir::encode_dirstat for encoder. }; struct InodeStat { vinodeno_t vino; version_t version; ceph_mds_reply_cap cap; ceph_file_layout layout; unsigned mode, uid, gid, nlink, rdev; loff_t size, max_size; version_t truncate_seq; uint64_t truncate_size; utime_t ctime, mtime, atime; version_t time_warp_seq; bufferlist inline_data; version_t inline_version; frag_info_t dirstat; nest_info_t rstat; string symlink; // symlink content (if symlink) fragtree_t dirfragtree; version_t xattr_version; bufferlist xattrbl; ceph_dir_layout dir_layout; //map xattrs; public: InodeStat() {} InodeStat(bufferlist::iterator& p, uint64_t features) { decode(p, features); } void decode(bufferlist::iterator &p, uint64_t features) { struct ceph_mds_reply_inode e; ::decode(e, p); vino.ino = inodeno_t(e.ino); vino.snapid = snapid_t(e.snapid); version = e.version; layout = e.layout; cap = e.cap; size = e.size; max_size = e.max_size; truncate_seq = e.truncate_seq; truncate_size = e.truncate_size; ctime.decode_timeval(&e.ctime); mtime.decode_timeval(&e.mtime); atime.decode_timeval(&e.atime); time_warp_seq = e.time_warp_seq; mode = e.mode; uid = e.uid; gid = e.gid; nlink = e.nlink; rdev = e.rdev; dirstat.nfiles = e.files; dirstat.nsubdirs = e.subdirs; rstat.rctime.decode_timeval(&e.rctime); rstat.rbytes = e.rbytes; rstat.rfiles = e.rfiles; rstat.rsubdirs = e.rsubdirs; int n = e.fragtree.nsplits; while (n) { ceph_frag_tree_split s; ::decode(s, p); dirfragtree._splits[(__u32)s.frag] = s.by; n--; } ::decode(symlink, p); if (features & CEPH_FEATURE_DIRLAYOUTHASH) ::decode(dir_layout, p); else memset(&dir_layout, 0, sizeof(dir_layout)); xattr_version = e.xattr_version; ::decode(xattrbl, p); if (features & CEPH_FEATURE_MDS_INLINE_DATA) { ::decode(inline_version, p); ::decode(inline_data, p); } else { inline_version = CEPH_INLINE_NONE; } } // see CInode::encode_inodestat for encoder. }; class MClientReply : public Message { // reply data public: struct ceph_mds_reply_head head; bufferlist trace_bl; bufferlist extra_bl; bufferlist snapbl; public: int get_op() const { return head.op; } void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; } epoch_t get_mdsmap_epoch() const { return head.mdsmap_epoch; } int get_result() const { return (__s32)(__u32)head.result; } void set_result(int r) { head.result = r; } void set_unsafe() { head.safe = 0; } bool is_safe() const { return head.safe; } MClientReply() : Message(CEPH_MSG_CLIENT_REPLY) {} MClientReply(MClientRequest *req, int result = 0) : Message(CEPH_MSG_CLIENT_REPLY) { memset(&head, 0, sizeof(head)); header.tid = req->get_tid(); head.op = req->get_op(); head.result = result; head.safe = 1; } private: ~MClientReply() {} public: const char *get_type_name() const { return "creply"; } void print(ostream& o) const { o << "client_reply(???:" << get_tid(); o << " = " << get_result(); if (get_result() <= 0) { o << " " << cpp_strerror(get_result()); } if (head.op & CEPH_MDS_OP_WRITE) { if (head.safe) o << " safe"; else o << " unsafe"; } o << ")"; } // serialization virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(head, p); ::decode(trace_bl, p); ::decode(extra_bl, p); ::decode(snapbl, p); assert(p.end()); } virtual void encode_payload(uint64_t features) { ::encode(head, payload); ::encode(trace_bl, payload); ::encode(extra_bl, payload); ::encode(snapbl, payload); } // dir contents void set_extra_bl(bufferlist& bl) { extra_bl.claim(bl); } bufferlist &get_extra_bl() { return extra_bl; } // trace void set_trace(bufferlist& bl) { trace_bl.claim(bl); } bufferlist& get_trace_bl() { return trace_bl; } }; #endif ceph-0.80.11/src/messages/MOSDPGCreate.h0000664000175100017510000000357512623076744021573 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGCREATE_H #define CEPH_MOSDPGCREATE_H #include "msg/Message.h" #include "osd/osd_types.h" /* * PGCreate - instruct an OSD to create a pg, if it doesn't already exist */ struct MOSDPGCreate : public Message { const static int HEAD_VERSION = 2; version_t epoch; map mkpg; MOSDPGCreate() : Message(MSG_OSD_PG_CREATE, HEAD_VERSION) {} MOSDPGCreate(epoch_t e) : Message(MSG_OSD_PG_CREATE, HEAD_VERSION), epoch(e) { } private: ~MOSDPGCreate() {} public: const char *get_type_name() const { return "pg_create"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); ::encode(mkpg, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); if (header.version >= 2) { ::decode(mkpg, p); } else { __u32 n; ::decode(n, p); while (n--) { pg_t pgid; epoch_t created; // epoch pg created pg_t parent; // split from parent (if != pg_t()) __s32 split_bits; ::decode(pgid, p); ::decode(created, p); ::decode(parent, p); ::decode(split_bits, p); mkpg[pgid] = pg_create_t(created, parent, split_bits); } } } void print(ostream& out) const { out << "osd_pg_create("; for (map::const_iterator i = mkpg.begin(); i != mkpg.end(); ++i) { out << "pg" << i->first << "," << i->second.created << "; "; } out << ")"; } }; #endif ceph-0.80.11/src/messages/MGenericMessage.h0000664000175100017510000000165512623076744022451 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MGENERICMESSAGE_H #define CEPH_MGENERICMESSAGE_H #include "msg/Message.h" class MGenericMessage : public Message { char tname[20]; //long pcid; public: MGenericMessage(int t=0) : Message(t) { snprintf(tname, sizeof(tname), "generic%d", get_type()); } //void set_pcid(long pcid) { this->pcid = pcid; } //long get_pcid() { return pcid; } const char *get_type_name() const { return tname; } void decode_payload() { } void encode_payload(uint64_t features) { } }; #endif ceph-0.80.11/src/messages/MDirUpdate.h0000664000175100017510000000421512623076744021444 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDIRUPDATE_H #define CEPH_MDIRUPDATE_H #include "msg/Message.h" class MDirUpdate : public Message { int32_t from_mds; dirfrag_t dirfrag; int32_t dir_rep; int32_t discover; set dir_rep_by; filepath path; public: int get_source_mds() const { return from_mds; } dirfrag_t get_dirfrag() const { return dirfrag; } int get_dir_rep() const { return dir_rep; } const set& get_dir_rep_by() const { return dir_rep_by; } bool should_discover() const { return discover > 0; } const filepath& get_path() const { return path; } void tried_discover() { if (discover) discover--; } MDirUpdate() : Message(MSG_MDS_DIRUPDATE) {} MDirUpdate(int f, dirfrag_t dirfrag, int dir_rep, set& dir_rep_by, filepath& path, bool discover = false) : Message(MSG_MDS_DIRUPDATE) { this->from_mds = f; this->dirfrag = dirfrag; this->dir_rep = dir_rep; this->dir_rep_by = dir_rep_by; if (discover) this->discover = 5; this->path = path; } private: ~MDirUpdate() {} public: const char *get_type_name() const { return "dir_update"; } void print(ostream& out) const { out << "dir_update(" << get_dirfrag() << ")"; } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(from_mds, p); ::decode(dirfrag, p); ::decode(dir_rep, p); ::decode(discover, p); ::decode(dir_rep_by, p); ::decode(path, p); } virtual void encode_payload(uint64_t features) { ::encode(from_mds, payload); ::encode(dirfrag, payload); ::encode(dir_rep, payload); ::encode(discover, payload); ::encode(dir_rep_by, payload); ::encode(path, payload); } }; #endif ceph-0.80.11/src/messages/MLogAck.h0000664000175100017510000000211412623076744020717 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MLOGACK_H #define CEPH_MLOGACK_H #include class MLogAck : public Message { public: uuid_d fsid; version_t last; MLogAck() : Message(MSG_LOGACK) {} MLogAck(uuid_d& f, version_t l) : Message(MSG_LOGACK), fsid(f), last(l) {} private: ~MLogAck() {} public: const char *get_type_name() const { return "log_ack"; } void print(ostream& out) const { out << "log(last " << last << ")"; } void encode_payload(uint64_t features) { ::encode(fsid, payload); ::encode(last, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(fsid, p); ::decode(last, p); } }; #endif ceph-0.80.11/src/messages/MMonQuorumService.h0000664000175100017510000000272612623076744023053 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMON_QUORUM_SERVICE_H #define CEPH_MMON_QUORUM_SERVICE_H #include "msg/Message.h" struct MMonQuorumService : public Message { epoch_t epoch; version_t round; MMonQuorumService(int type, int head=1, int compat=1) : Message(type, head, compat), epoch(0), round(0) { } protected: ~MMonQuorumService() { } public: void set_epoch(epoch_t e) { epoch = e; } void set_round(version_t r) { round = r; } epoch_t get_epoch() const { return epoch; } version_t get_round() const { return round; } void service_encode() { ::encode(epoch, payload); ::encode(round, payload); } void service_decode(bufferlist::iterator &p) { ::decode(epoch, p); ::decode(round, p); } void encode_payload(uint64_t features) { assert(0 == "MMonQuorumService message must always be a base class"); } void decode_payload() { assert(0 == "MMonQuorumService message must always be a base class"); } const char *get_type_name() const { return "quorum_service"; } }; #endif /* CEPH_MMON_QUORUM_SERVICE_H */ ceph-0.80.11/src/messages/MMonGetMap.h0000664000175100017510000000146112623076744021412 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONGETMAP_H #define CEPH_MMONGETMAP_H #include "msg/Message.h" #include "include/types.h" class MMonGetMap : public Message { public: MMonGetMap() : Message(CEPH_MSG_MON_GET_MAP) { } private: ~MMonGetMap() {} public: const char *get_type_name() const { return "mon_getmap"; } void encode_payload(uint64_t features) { } void decode_payload() { } }; #endif ceph-0.80.11/src/messages/MDiscoverReply.h0000664000175100017510000001377012623076744022363 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDISCOVERREPLY_H #define CEPH_MDISCOVERREPLY_H #include "msg/Message.h" #include "include/filepath.h" #include #include using namespace std; /** * MDiscoverReply - return new replicas (of inodes, dirs, dentries) * * we group returned items by (dir, dentry, inode). each * item in each set shares an index (it's "depth"). * * we can start and end with any type. * no_base_dir = true if the first group has an inode but no dir * no_base_dentry = true if the first group has an inode but no dentry * they are false if there is no returned data, ie the first group is empty. * * we also return errors: * error_flag_dn(string) - the specified dentry dne * error_flag_dir - the last item wasn't a dir, so we couldn't continue. * * and sometimes, * dir_auth_hint - where we think the dir auth is * * depth() gives us the number of depth units/indices for which we have * information. this INCLUDES those for which we have errors but no data. * * see MDCache::handle_discover, handle_discover_reply. * * * so basically, we get * * dir den ino i * x 0 * x x x 1 * or * x x 0 * x x x 1 * or * x x x 0 * x x x 1 * ...and trail off however we want. * * */ class MDiscoverReply : public Message { static const int HEAD_VERSION = 2; // info about original request inodeno_t base_ino; frag_t base_dir_frag; bool wanted_base_dir; bool wanted_xlocked; inodeno_t wanted_ino; snapid_t wanted_snapid; // and the response bool flag_error_dn; bool flag_error_ino; bool flag_error_dir; string error_dentry; // dentry that was not found (to trigger waiters on asker) bool unsolicited; __s32 dir_auth_hint; public: __u8 starts_with; bufferlist trace; enum { DIR, DENTRY, INODE }; // accessors inodeno_t get_base_ino() { return base_ino; } frag_t get_base_dir_frag() { return base_dir_frag; } bool get_wanted_base_dir() { return wanted_base_dir; } bool get_wanted_xlocked() { return wanted_xlocked; } inodeno_t get_wanted_ino() { return wanted_ino; } snapid_t get_wanted_snapid() { return wanted_snapid; } bool is_flag_error_dn() { return flag_error_dn; } bool is_flag_error_ino() { return flag_error_ino; } bool is_flag_error_dir() { return flag_error_dir; } string& get_error_dentry() { return error_dentry; } int get_starts_with() { return starts_with; } int get_dir_auth_hint() { return dir_auth_hint; } bool is_unsolicited() { return unsolicited; } void mark_unsolicited() { unsolicited = true; } void set_base_dir_frag(frag_t df) { base_dir_frag = df; } // cons MDiscoverReply() : Message(MSG_MDS_DISCOVERREPLY, HEAD_VERSION) { } MDiscoverReply(MDiscover *dis) : Message(MSG_MDS_DISCOVERREPLY, HEAD_VERSION), base_ino(dis->get_base_ino()), base_dir_frag(dis->get_base_dir_frag()), wanted_base_dir(dis->wants_base_dir()), wanted_xlocked(dis->wants_xlocked()), wanted_ino(dis->get_want_ino()), wanted_snapid(dis->get_snapid()), flag_error_dn(false), flag_error_ino(false), flag_error_dir(false), unsolicited(false), dir_auth_hint(CDIR_AUTH_UNKNOWN), starts_with(DIR) { header.tid = dis->get_tid(); } MDiscoverReply(dirfrag_t df) : Message(MSG_MDS_DISCOVERREPLY, HEAD_VERSION), base_ino(df.ino), base_dir_frag(df.frag), wanted_base_dir(false), wanted_xlocked(false), wanted_ino(inodeno_t()), wanted_snapid(CEPH_NOSNAP), flag_error_dn(false), flag_error_ino(false), flag_error_dir(false), unsolicited(false), dir_auth_hint(CDIR_AUTH_UNKNOWN), starts_with(DIR) { header.tid = 0; } private: ~MDiscoverReply() {} public: const char *get_type_name() const { return "discover_reply"; } void print(ostream& out) const { out << "discover_reply(" << header.tid << " " << base_ino << ")"; } // builders bool is_empty() { return trace.length() == 0 && !flag_error_dn && !flag_error_ino && !flag_error_dir && dir_auth_hint == CDIR_AUTH_UNKNOWN; } // void set_flag_forward() { flag_forward = true; } void set_flag_error_dn(const string& dn) { flag_error_dn = true; error_dentry = dn; } void set_flag_error_ino() { flag_error_ino = true; } void set_flag_error_dir() { flag_error_dir = true; } void set_dir_auth_hint(int a) { dir_auth_hint = a; } void set_error_dentry(const string& dn) { error_dentry = dn; } // ... virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(base_ino, p); ::decode(base_dir_frag, p); ::decode(wanted_base_dir, p); ::decode(wanted_xlocked, p); ::decode(wanted_snapid, p); ::decode(flag_error_dn, p); ::decode(flag_error_ino, p); ::decode(flag_error_dir, p); ::decode(error_dentry, p); ::decode(dir_auth_hint, p); ::decode(unsolicited, p); ::decode(starts_with, p); ::decode(trace, p); if (header.version >= 2) ::decode(wanted_ino, p); } void encode_payload(uint64_t features) { ::encode(base_ino, payload); ::encode(base_dir_frag, payload); ::encode(wanted_base_dir, payload); ::encode(wanted_xlocked, payload); ::encode(wanted_snapid, payload); ::encode(flag_error_dn, payload); ::encode(flag_error_ino, payload); ::encode(flag_error_dir, payload); ::encode(error_dentry, payload); ::encode(dir_auth_hint, payload); ::encode(unsolicited, payload); ::encode(starts_with, payload); ::encode(trace, payload); ::encode(wanted_ino, payload); } }; #endif ceph-0.80.11/src/messages/MMonGetVersionReply.h0000664000175100017510000000276212623076744023343 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONGETVERSIONREPLY_H #define CEPH_MMONGETVERSIONREPLY_H #include "msg/Message.h" #include "include/types.h" /* * This message is sent from the monitors to clients in response to a * MMonGetVersion. The latest version of the requested thing is sent * back. */ class MMonGetVersionReply : public Message { static const int HEAD_VERSION = 2; public: MMonGetVersionReply() : Message(CEPH_MSG_MON_GET_VERSION_REPLY, HEAD_VERSION) { } const char *get_type_name() const { return "mon_check_map_ack"; } void print(ostream& o) const { o << "mon_check_map_ack(handle=" << handle << " version=" << version << ")"; } void encode_payload(uint64_t features) { ::encode(handle, payload); ::encode(version, payload); ::encode(oldest_version, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(handle, p); ::decode(version, p); if (header.version >= 2) ::decode(oldest_version, p); } ceph_tid_t handle; version_t version; version_t oldest_version; private: ~MMonGetVersionReply() {} }; #endif ceph-0.80.11/src/messages/MMonSubscribeAck.h0000664000175100017510000000240012623076744022567 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONSUBSCRIBEACK_H #define CEPH_MMONSUBSCRIBEACK_H #include "msg/Message.h" struct MMonSubscribeAck : public Message { __u32 interval; uuid_d fsid; MMonSubscribeAck() : Message(CEPH_MSG_MON_SUBSCRIBE_ACK), interval(0) { memset(&fsid, 0, sizeof(fsid)); } MMonSubscribeAck(uuid_d& f, int i) : Message(CEPH_MSG_MON_SUBSCRIBE_ACK), interval(i), fsid(f) { } private: ~MMonSubscribeAck() {} public: const char *get_type_name() const { return "mon_subscribe_ack"; } void print(ostream& o) const { o << "mon_subscribe_ack(" << interval << "s)"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(interval, p); ::decode(fsid, p); } void encode_payload(uint64_t features) { ::encode(interval, payload); ::encode(fsid, payload); } }; #endif ceph-0.80.11/src/messages/PaxosServiceMessage.h0000664000175100017510000000401512623076744023364 0ustar jenkins-buildjenkins-build#ifndef CEPH_PAXOSSERVICEMESSAGE_H #define CEPH_PAXOSSERVICEMESSAGE_H #include "msg/Message.h" #include "mon/Session.h" class PaxosServiceMessage : public Message { public: version_t version; __s16 deprecated_session_mon; uint64_t deprecated_session_mon_tid; // track which epoch the leader received a forwarded request in, so we can // discard forwarded requests appropriately on election boundaries. epoch_t rx_election_epoch; PaxosServiceMessage() : Message(MSG_PAXOS), version(0), deprecated_session_mon(-1), deprecated_session_mon_tid(0), rx_election_epoch(0) { } PaxosServiceMessage(int type, version_t v, int enc_version=1, int compat_enc_version=0) : Message(type, enc_version, compat_enc_version), version(v), deprecated_session_mon(-1), deprecated_session_mon_tid(0), rx_election_epoch(0) { } protected: ~PaxosServiceMessage() {} public: void paxos_encode() { ::encode(version, payload); ::encode(deprecated_session_mon, payload); ::encode(deprecated_session_mon_tid, payload); } void paxos_decode( bufferlist::iterator& p ) { ::decode(version, p); ::decode(deprecated_session_mon, p); ::decode(deprecated_session_mon_tid, p); } void encode_payload(uint64_t features) { assert(0); paxos_encode(); } void decode_payload() { assert(0); bufferlist::iterator p = payload.begin(); paxos_decode(p); } /** * These messages are only used by the monitors and clients, * and the client doesn't care, so we're creating a monitor-specific * function here. Note that this function explicitly exists to bypass * the normal ref-counting, so don't expect the returned pointer to be * very long-lived -- it will still only last as long as the Session would * normally. */ MonSession *get_session() { MonSession *session = (MonSession *)get_connection()->get_priv(); if (session) session->put(); return session; } const char *get_type_name() const { return "PaxosServiceMessage"; } }; #endif ceph-0.80.11/src/messages/MCommandReply.h0000664000175100017510000000244712623076744022162 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCOMMANDREPLY_H #define CEPH_MCOMMANDREPLY_H #include "msg/Message.h" #include "MCommand.h" class MCommandReply : public Message { public: __s32 r; string rs; MCommandReply() : Message(MSG_COMMAND_REPLY) {} MCommandReply(MCommand *m, int _r) : Message(MSG_COMMAND_REPLY), r(_r) { header.tid = m->get_tid(); } MCommandReply(int _r, string s) : Message(MSG_COMMAND_REPLY), r(_r), rs(s) { } private: ~MCommandReply() {} public: const char *get_type_name() const { return "command_reply"; } void print(ostream& o) const { o << "command_reply(tid " << get_tid() << ": " << r << " " << rs << ")"; } void encode_payload(uint64_t features) { ::encode(r, payload); ::encode(rs, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(r, p); ::decode(rs, p); } }; #endif ceph-0.80.11/src/messages/MRecoveryReserve.h0000664000175100017510000000364012623076744022716 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MRECOVERY_H #define CEPH_MRECOVERY_H #include "msg/Message.h" class MRecoveryReserve : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: spg_t pgid; epoch_t query_epoch; enum { REQUEST = 0, GRANT = 1, RELEASE = 2, }; int type; MRecoveryReserve() : Message(MSG_OSD_RECOVERY_RESERVE, HEAD_VERSION, COMPAT_VERSION), query_epoch(0), type(-1) {} MRecoveryReserve(int type, spg_t pgid, epoch_t query_epoch) : Message(MSG_OSD_RECOVERY_RESERVE, HEAD_VERSION, COMPAT_VERSION), pgid(pgid), query_epoch(query_epoch), type(type) {} const char *get_type_name() const { return "MRecoveryReserve"; } void print(ostream& out) const { out << "MRecoveryReserve "; switch (type) { case REQUEST: out << "REQUEST "; break; case GRANT: out << "GRANT "; break; case RELEASE: out << "RELEASE "; break; } out << " pgid: " << pgid << ", query_epoch: " << query_epoch; return; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid.pgid, p); ::decode(query_epoch, p); ::decode(type, p); if (header.version >= 2) ::decode(pgid.shard, p); else pgid.shard = ghobject_t::no_shard(); } void encode_payload(uint64_t features) { ::encode(pgid.pgid, payload); ::encode(query_epoch, payload); ::encode(type, payload); ::encode(pgid.shard, payload); } }; #endif ceph-0.80.11/src/messages/MMonSync.h0000664000175100017510000000604012623076744021147 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CEPH_MMONSYNC_H #define CEPH_MMONSYNC_H #include "msg/Message.h" class MMonSync : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 2; public: /** * Operation types */ enum { OP_GET_COOKIE_FULL = 1, // -> start a session (full scan) OP_GET_COOKIE_RECENT = 2, // -> start a session (only recent paxos events) OP_COOKIE = 3, // <- pass the iterator cookie, or OP_GET_CHUNK = 4, // -> get some keys OP_CHUNK = 5, // <- return some keys OP_LAST_CHUNK = 6, // <- return the last set of keys OP_NO_COOKIE = 8, // <- sorry, no cookie }; /** * Obtain a string corresponding to the operation type @p op * * @param op Operation type * @returns A string */ static const char *get_opname(int op) { switch (op) { case OP_GET_COOKIE_FULL: return "get_cookie_full"; case OP_GET_COOKIE_RECENT: return "get_cookie_recent"; case OP_COOKIE: return "cookie"; case OP_GET_CHUNK: return "get_chunk"; case OP_CHUNK: return "chunk"; case OP_LAST_CHUNK: return "last_chunk"; case OP_NO_COOKIE: return "no_cookie"; default: assert(0 == "unknown op type"); return NULL; } } uint32_t op; uint64_t cookie; version_t last_committed; pair last_key; bufferlist chunk_bl; entity_inst_t reply_to; MMonSync() : Message(MSG_MON_SYNC, HEAD_VERSION, COMPAT_VERSION) { } MMonSync(uint32_t op, uint64_t c = 0) : Message(MSG_MON_SYNC, HEAD_VERSION, COMPAT_VERSION), op(op), cookie(c), last_committed(0) { } const char *get_type_name() const { return "mon_sync"; } void print(ostream& out) const { out << "mon_sync(" << get_opname(op); if (cookie) out << " cookie " << cookie; if (last_committed > 0) out << " lc " << last_committed; if (chunk_bl.length()) out << " bl " << chunk_bl.length() << " bytes"; if (!last_key.first.empty() || !last_key.second.empty()) out << " last_key " << last_key.first << "," << last_key.second; out << ")"; } void encode_payload(uint64_t features) { ::encode(op, payload); ::encode(cookie, payload); ::encode(last_committed, payload); ::encode(last_key.first, payload); ::encode(last_key.second, payload); ::encode(chunk_bl, payload); ::encode(reply_to, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(op, p); ::decode(cookie, p); ::decode(last_committed, p); ::decode(last_key.first, p); ::decode(last_key.second, p); ::decode(chunk_bl, p); ::decode(reply_to, p); } }; #endif /* CEPH_MMONSYNC_H */ ceph-0.80.11/src/messages/MPoolOpReply.h0000664000175100017510000000372112623076744022010 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MPOOLOPREPLY_H #define CEPH_MPOOLOPREPLY_H #include "common/errno.h" class MPoolOpReply : public PaxosServiceMessage { public: uuid_d fsid; __u32 replyCode; epoch_t epoch; bufferlist response_data; MPoolOpReply() : PaxosServiceMessage(CEPH_MSG_POOLOP_REPLY, 0) {} MPoolOpReply( uuid_d& f, ceph_tid_t t, int rc, int e, version_t v) : PaxosServiceMessage(CEPH_MSG_POOLOP_REPLY, v), fsid(f), replyCode(rc), epoch(e) { set_tid(t); } MPoolOpReply( uuid_d& f, ceph_tid_t t, int rc, int e, version_t v, bufferlist *blp) : PaxosServiceMessage(CEPH_MSG_POOLOP_REPLY, v), fsid(f), replyCode(rc), epoch(e) { set_tid(t); if (blp) response_data.claim(*blp); } const char *get_type_name() const { return "poolopreply"; } void print(ostream& out) const { out << "pool_op_reply(tid " << get_tid() << " " << cpp_strerror(-replyCode) << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(replyCode, payload); ::encode(epoch, payload); if (response_data.length()) { ::encode(true, payload); ::encode(response_data, payload); } else ::encode(false, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(replyCode, p); ::decode(epoch, p); bool has_response_data; ::decode(has_response_data, p); if (has_response_data) { ::decode(response_data, p); } } }; #endif ceph-0.80.11/src/messages/MClientSnap.h0000664000175100017510000000332112623076744021620 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTSNAP_H #define CEPH_MCLIENTSNAP_H #include "msg/Message.h" struct MClientSnap : public Message { ceph_mds_snap_head head; bufferlist bl; // (for split only) vector split_inos; vector split_realms; MClientSnap(int o=0) : Message(CEPH_MSG_CLIENT_SNAP) { memset(&head, 0, sizeof(head)); head.op = o; } private: ~MClientSnap() {} public: const char *get_type_name() const { return "client_snap"; } void print(ostream& out) const { out << "client_snap(" << ceph_snap_op_name(head.op); if (head.split) out << " split=" << inodeno_t(head.split); out << " tracelen=" << bl.length(); out << ")"; } void encode_payload(uint64_t features) { head.num_split_inos = split_inos.size(); head.num_split_realms = split_realms.size(); head.trace_len = bl.length(); ::encode(head, payload); ::encode_nohead(split_inos, payload); ::encode_nohead(split_realms, payload); ::encode_nohead(bl, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(head, p); ::decode_nohead(head.num_split_inos, split_inos, p); ::decode_nohead(head.num_split_realms, split_realms, p); ::decode_nohead(head.trace_len, bl, p); assert(p.end()); } }; #endif ceph-0.80.11/src/messages/MRemoveSnaps.h0000664000175100017510000000236112623076744022025 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MREMOVESNAPS_H #define CEPH_MREMOVESNAPS_H #include "messages/PaxosServiceMessage.h" struct MRemoveSnaps : public PaxosServiceMessage { map > snaps; MRemoveSnaps() : PaxosServiceMessage(MSG_REMOVE_SNAPS, 0) { } MRemoveSnaps(map >& s) : PaxosServiceMessage(MSG_REMOVE_SNAPS, 0) { snaps.swap(s); } private: ~MRemoveSnaps() {} public: const char *get_type_name() const { return "remove_snaps"; } void print(ostream& out) const { out << "remove_snaps(" << snaps << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(snaps, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(snaps, p); assert(p.end()); } }; #endif ceph-0.80.11/src/messages/MExportCaps.h0000664000175100017510000000223012623076744021646 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTCAPS_H #define CEPH_MEXPORTCAPS_H #include "msg/Message.h" class MExportCaps : public Message { public: inodeno_t ino; bufferlist cap_bl; map client_map; MExportCaps() : Message(MSG_MDS_EXPORTCAPS) {} private: ~MExportCaps() {} public: const char *get_type_name() const { return "export_caps"; } void print(ostream& o) const { o << "export_caps(" << ino << ")"; } void encode_payload(uint64_t features) { ::encode(ino, payload); ::encode(cap_bl, payload); ::encode(client_map, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(ino, p); ::decode(cap_bl, p); ::decode(client_map, p); } }; #endif ceph-0.80.11/src/messages/MOSDAlive.h0000664000175100017510000000224012623076744021165 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDALIVE_H #define CEPH_MOSDALIVE_H #include "messages/PaxosServiceMessage.h" class MOSDAlive : public PaxosServiceMessage { public: epoch_t want; MOSDAlive(epoch_t h, epoch_t w) : PaxosServiceMessage(MSG_OSD_ALIVE, h), want(w) { } MOSDAlive() : PaxosServiceMessage(MSG_OSD_ALIVE, 0) {} private: ~MOSDAlive() {} public: void encode_payload(uint64_t features) { paxos_encode(); ::encode(want, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(want, p); } const char *get_type_name() const { return "osd_alive"; } void print(ostream &out) const { out << "osd_alive(want up_thru " << want << " have " << version << ")"; } }; #endif ceph-0.80.11/src/messages/MClientCapRelease.h0000664000175100017510000000234512623076744022730 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTCAPRELEASE_H #define CEPH_MCLIENTCAPRELEASE_H #include "msg/Message.h" class MClientCapRelease : public Message { public: struct ceph_mds_cap_release head; vector caps; MClientCapRelease() : Message(CEPH_MSG_CLIENT_CAPRELEASE) { memset(&head, 0, sizeof(head)); } private: ~MClientCapRelease() {} public: const char *get_type_name() const { return "client_cap_release";} void print(ostream& out) const { out << "client_cap_release(" << caps.size() << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(head, p); ::decode_nohead(head.num, caps, p); } void encode_payload(uint64_t features) { head.num = caps.size(); ::encode(head, payload); ::encode_nohead(caps, payload); } }; #endif ceph-0.80.11/src/messages/MCommand.h0000664000175100017510000000236712623076744021147 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCOMMAND_H #define CEPH_MCOMMAND_H #include #include #include "msg/Message.h" class MCommand : public Message { public: uuid_d fsid; std::vector cmd; MCommand() : Message(MSG_MON_COMMAND) {} MCommand(uuid_d &f) : Message(MSG_COMMAND), fsid(f) { } private: ~MCommand() {} public: const char *get_type_name() const { return "command"; } void print(ostream& o) const { o << "command(tid " << get_tid() << ": "; for (unsigned i=0; i * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTRECONNECT_H #define CEPH_MCLIENTRECONNECT_H #include "msg/Message.h" #include "mds/mdstypes.h" #include "include/ceph_features.h" class MClientReconnect : public Message { const static int HEAD_VERSION = 3; public: map caps; // only head inodes vector realms; MClientReconnect() : Message(CEPH_MSG_CLIENT_RECONNECT, HEAD_VERSION) { } private: ~MClientReconnect() {} public: const char *get_type_name() const { return "client_reconnect"; } void print(ostream& out) const { out << "client_reconnect(" << caps.size() << " caps)"; } void add_cap(inodeno_t ino, uint64_t cap_id, inodeno_t pathbase, const string& path, int wanted, int issued, inodeno_t sr, bufferlist& lb) { caps[ino] = cap_reconnect_t(cap_id, pathbase, path, wanted, issued, sr, lb); } void add_snaprealm(inodeno_t ino, snapid_t seq, inodeno_t parent) { ceph_mds_snaprealm_reconnect r; r.ino = ino; r.seq = seq; r.parent = parent; realms.push_back(r); } void encode_payload(uint64_t features) { data.clear(); if (features & CEPH_FEATURE_MDSENC) { ::encode(caps, data); } else if (features & CEPH_FEATURE_FLOCK) { // encode with old cap_reconnect_t encoding __u32 n = caps.size(); ::encode(n, data); for (map::iterator p = caps.begin(); p != caps.end(); ++p) { ::encode(p->first, data); p->second.encode_old(data); } header.version = 2; } else { // compat crap header.version = 1; map ocaps; for (map::iterator p = caps.begin(); p != caps.end(); p++) ocaps[p->first] = p->second; ::encode(ocaps, data); } ::encode_nohead(realms, data); } void decode_payload() { bufferlist::iterator p = data.begin(); if (header.version >= 3) { // new protocol ::decode(caps, p); } else if (header.version == 2) { __u32 n; ::decode(n, p); inodeno_t ino; while (n--) { ::decode(ino, p); caps[ino].decode_old(p); } } else { // compat crap map ocaps; ::decode(ocaps, p); for (map::iterator q = ocaps.begin(); q != ocaps.end(); q++) caps[q->first] = q->second; } while (!p.end()) { realms.push_back(ceph_mds_snaprealm_reconnect()); ::decode(realms.back(), p); } } }; #endif ceph-0.80.11/src/messages/MMDSResolveAck.h0000664000175100017510000000252512623076744022167 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSRESOLVEACK_H #define CEPH_MMDSRESOLVEACK_H #include "msg/Message.h" #include "include/types.h" class MMDSResolveAck : public Message { public: map commit; vector abort; MMDSResolveAck() : Message(MSG_MDS_RESOLVEACK) {} private: ~MMDSResolveAck() {} public: const char *get_type_name() const { return "resolve_ack"; } /*void print(ostream& out) const { out << "resolve_ack.size() << "+" << ambiguous_imap.size() << " imports +" << slave_requests.size() << " slave requests)"; } */ void add_commit(metareqid_t r) { commit[r].clear(); } void add_abort(metareqid_t r) { abort.push_back(r); } void encode_payload(uint64_t features) { ::encode(commit, payload); ::encode(abort, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(commit, p); ::decode(abort, p); } }; #endif ceph-0.80.11/src/messages/MOSDRepScrub.h0000664000175100017510000000632412623076744021661 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDREPSCRUB_H #define CEPH_MOSDREPSCRUB_H #include "msg/Message.h" /* * instruct an OSD initiate a replica scrub on a specific PG */ struct MOSDRepScrub : public Message { static const int HEAD_VERSION = 5; static const int COMPAT_VERSION = 2; spg_t pgid; // PG to scrub eversion_t scrub_from; // only scrub log entries after scrub_from eversion_t scrub_to; // last_update_applied when message sent epoch_t map_epoch; bool chunky; // true for chunky scrubs hobject_t start; // lower bound of scrub, inclusive hobject_t end; // upper bound of scrub, exclusive bool deep; // true if scrub should be deep MOSDRepScrub() : Message(MSG_OSD_REP_SCRUB, HEAD_VERSION, COMPAT_VERSION), chunky(false), deep(false) { } MOSDRepScrub(spg_t pgid, eversion_t scrub_from, eversion_t scrub_to, epoch_t map_epoch) : Message(MSG_OSD_REP_SCRUB, HEAD_VERSION, COMPAT_VERSION), pgid(pgid), scrub_from(scrub_from), scrub_to(scrub_to), map_epoch(map_epoch), chunky(false), deep(false) { } MOSDRepScrub(spg_t pgid, eversion_t scrub_to, epoch_t map_epoch, hobject_t start, hobject_t end, bool deep) : Message(MSG_OSD_REP_SCRUB, HEAD_VERSION, COMPAT_VERSION), pgid(pgid), scrub_to(scrub_to), map_epoch(map_epoch), chunky(true), start(start), end(end), deep(deep) { } private: ~MOSDRepScrub() {} public: const char *get_type_name() const { return "replica scrub"; } void print(ostream& out) const { out << "replica scrub(pg: "; out << pgid << ",from:" << scrub_from << ",to:" << scrub_to << ",epoch:" << map_epoch << ",start:" << start << ",end:" << end << ",chunky:" << chunky << ",deep:" << deep << ",version:" << header.version; out << ")"; } void encode_payload(uint64_t features) { ::encode(pgid.pgid, payload); ::encode(scrub_from, payload); ::encode(scrub_to, payload); ::encode(map_epoch, payload); ::encode(chunky, payload); ::encode(start, payload); ::encode(end, payload); ::encode(deep, payload); ::encode(pgid.shard, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid.pgid, p); ::decode(scrub_from, p); ::decode(scrub_to, p); ::decode(map_epoch, p); if (header.version >= 3) { ::decode(chunky, p); ::decode(start, p); ::decode(end, p); if (header.version >= 4) { ::decode(deep, p); } else { deep = false; } } else { // v2 scrub: non-chunky chunky = false; deep = false; } if (header.version >= 5) { ::decode(pgid.shard, p); } else { pgid.shard = ghobject_t::no_shard(); } } }; #endif ceph-0.80.11/src/messages/MOSDMarkMeDown.h0000664000175100017510000000330412623076744022133 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDMARKMEDOWN_H #define CEPH_MOSDMARKMEDOWN_H #include "messages/PaxosServiceMessage.h" class MOSDMarkMeDown : public PaxosServiceMessage { static const int HEAD_VERSION = 1; public: uuid_d fsid; entity_inst_t target_osd; epoch_t epoch; bool ack; MOSDMarkMeDown() : PaxosServiceMessage(MSG_OSD_MARK_ME_DOWN, 0, HEAD_VERSION) { } MOSDMarkMeDown(const uuid_d &fs, const entity_inst_t& f, epoch_t e, bool ack) : PaxosServiceMessage(MSG_OSD_MARK_ME_DOWN, e, HEAD_VERSION), fsid(fs), target_osd(f), epoch(e), ack(ack) {} private: ~MOSDMarkMeDown() {} public: entity_inst_t get_target() { return target_osd; } epoch_t get_epoch() { return epoch; } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(target_osd, p); ::decode(epoch, p); ::decode(ack, p); } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(target_osd, payload); ::encode(epoch, payload); ::encode(ack, payload); } const char *get_type_name() const { return "osd_mark_me_down"; } void print(ostream& out) const { out << "osd_mark_me_down(" << "ack=" << ack << ", target_osd=" << target_osd << ", fsid=" << fsid << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDPGBackfill.h0000664000175100017510000000536312623076744022074 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGBACKFILL_H #define CEPH_MOSDPGBACKFILL_H #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPGBackfill : public Message { static const int HEAD_VERSION = 3; static const int COMPAT_VERSION = 1; public: enum { OP_BACKFILL_PROGRESS = 2, OP_BACKFILL_FINISH = 3, OP_BACKFILL_FINISH_ACK = 4, }; const char *get_op_name(int o) const { switch (o) { case OP_BACKFILL_PROGRESS: return "progress"; case OP_BACKFILL_FINISH: return "finish"; case OP_BACKFILL_FINISH_ACK: return "finish_ack"; default: return "???"; } } __u32 op; epoch_t map_epoch, query_epoch; spg_t pgid; hobject_t last_backfill; bool compat_stat_sum; pg_stat_t stats; virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(op, p); ::decode(map_epoch, p); ::decode(query_epoch, p); ::decode(pgid.pgid, p); ::decode(last_backfill, p); // For compatibility with version 1 ::decode(stats.stats, p); if (header.version >= 2) { ::decode(stats, p); } else { compat_stat_sum = true; } // Handle hobject_t format change if (!last_backfill.is_max() && last_backfill.pool == -1) last_backfill.pool = pgid.pool(); if (header.version >= 3) ::decode(pgid.shard, p); else pgid.shard = ghobject_t::no_shard(); } virtual void encode_payload(uint64_t features) { ::encode(op, payload); ::encode(map_epoch, payload); ::encode(query_epoch, payload); ::encode(pgid.pgid, payload); ::encode(last_backfill, payload); // For compatibility with version 1 ::encode(stats.stats, payload); ::encode(stats, payload); ::encode(pgid.shard, payload); } MOSDPGBackfill() : Message(MSG_OSD_PG_BACKFILL, HEAD_VERSION, COMPAT_VERSION), compat_stat_sum(false) {} MOSDPGBackfill(__u32 o, epoch_t e, epoch_t qe, spg_t p) : Message(MSG_OSD_PG_BACKFILL, HEAD_VERSION, COMPAT_VERSION), op(o), map_epoch(e), query_epoch(e), pgid(p), compat_stat_sum(false) {} private: ~MOSDPGBackfill() {} public: const char *get_type_name() const { return "pg_backfill"; } void print(ostream& out) const { out << "pg_backfill(" << get_op_name(op) << " " << pgid << " e " << map_epoch << "/" << query_epoch << " lb " << last_backfill << ")"; } }; #endif ceph-0.80.11/src/messages/MMonGetVersion.h0000664000175100017510000000260012623076744022316 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONGETVERSION_H #define CEPH_MMONGETVERSION_H #include "msg/Message.h" #include "include/types.h" /* * This message is sent to the monitors to verify that the client's * version of the map(s) is the latest available. For example, this * can be used to determine whether a pool actually does not exist, or * if it may have been created but the map was not received yet. */ class MMonGetVersion : public Message { public: MMonGetVersion() : Message(CEPH_MSG_MON_GET_VERSION) {} const char *get_type_name() const { return "mon_get_version"; } void print(ostream& o) const { o << "mon_get_version(what=" << what << " handle=" << handle << ")"; } void encode_payload(uint64_t features) { ::encode(handle, payload); ::encode(what, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(handle, p); ::decode(what, p); } ceph_tid_t handle; string what; private: ~MMonGetVersion() {} }; #endif ceph-0.80.11/src/messages/MMDSFragmentNotify.h0000664000175100017510000000306412623076744023064 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSFRAGMENTNOTIFY_H #define CEPH_MMDSFRAGMENTNOTIFY_H #include "msg/Message.h" #include using namespace std; class MMDSFragmentNotify : public Message { inodeno_t ino; frag_t basefrag; int8_t bits; public: inodeno_t get_ino() { return ino; } frag_t get_basefrag() { return basefrag; } int get_bits() { return bits; } bufferlist basebl; MMDSFragmentNotify() : Message(MSG_MDS_FRAGMENTNOTIFY) {} MMDSFragmentNotify(dirfrag_t df, int b) : Message(MSG_MDS_FRAGMENTNOTIFY), ino(df.ino), basefrag(df.frag), bits(b) { } private: ~MMDSFragmentNotify() {} public: const char *get_type_name() const { return "fragment_notify"; } void print(ostream& o) const { o << "fragment_notify(" << ino << "." << basefrag << " " << (int)bits << ")"; } void encode_payload(uint64_t features) { ::encode(ino, payload); ::encode(basefrag, payload); ::encode(bits, payload); ::encode(basebl, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(ino, p); ::decode(basefrag, p); ::decode(bits, p); ::decode(basebl, p); } }; #endif ceph-0.80.11/src/messages/MAuth.h0000664000175100017510000000300412623076744020457 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MAUTH_H #define CEPH_MAUTH_H #include "messages/PaxosServiceMessage.h" struct MAuth : public PaxosServiceMessage { __u32 protocol; bufferlist auth_payload; epoch_t monmap_epoch; /* if protocol == 0, then auth_payload is a set<__u32> listing protocols the client supports */ MAuth() : PaxosServiceMessage(CEPH_MSG_AUTH, 0), protocol(0), monmap_epoch(0) { } private: ~MAuth() {} public: const char *get_type_name() const { return "auth"; } void print(ostream& out) const { out << "auth(proto " << protocol << " " << auth_payload.length() << " bytes" << " epoch " << monmap_epoch << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(protocol, p); ::decode(auth_payload, p); if (!p.end()) ::decode(monmap_epoch, p); else monmap_epoch = 0; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(protocol, payload); ::encode(auth_payload, payload); ::encode(monmap_epoch, payload); } bufferlist& get_auth_payload() { return auth_payload; } }; #endif ceph-0.80.11/src/messages/MMDSResolve.h0000664000175100017510000000351612623076744021551 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSRESOLVE_H #define CEPH_MMDSRESOLVE_H #include "msg/Message.h" #include "include/types.h" class MMDSResolve : public Message { public: map > subtrees; map > ambiguous_imports; map slave_requests; MMDSResolve() : Message(MSG_MDS_RESOLVE) {} private: ~MMDSResolve() {} public: const char *get_type_name() const { return "mds_resolve"; } void print(ostream& out) const { out << "mds_resolve(" << subtrees.size() << "+" << ambiguous_imports.size() << " subtrees +" << slave_requests.size() << " slave requests)"; } void add_subtree(dirfrag_t im) { subtrees[im].clear(); } void add_subtree_bound(dirfrag_t im, dirfrag_t ex) { subtrees[im].push_back(ex); } void add_ambiguous_import(dirfrag_t im, const vector& m) { ambiguous_imports[im] = m; } void add_slave_request(metareqid_t reqid) { slave_requests[reqid].clear(); } void add_slave_request(metareqid_t reqid, bufferlist& bl) { slave_requests[reqid].claim(bl); } void encode_payload(uint64_t features) { ::encode(subtrees, payload); ::encode(ambiguous_imports, payload); ::encode(slave_requests, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(subtrees, p); ::decode(ambiguous_imports, p); ::decode(slave_requests, p); } }; #endif ceph-0.80.11/src/messages/MDentryUnlink.h0000664000175100017510000000247512623076744022217 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDENTRYUNLINK_H #define CEPH_MDENTRYUNLINK_H class MDentryUnlink : public Message { dirfrag_t dirfrag; string dn; public: dirfrag_t get_dirfrag() { return dirfrag; } string& get_dn() { return dn; } bufferlist straybl; MDentryUnlink() : Message(MSG_MDS_DENTRYUNLINK) { } MDentryUnlink(dirfrag_t df, string& n) : Message(MSG_MDS_DENTRYUNLINK), dirfrag(df), dn(n) {} private: ~MDentryUnlink() {} public: const char *get_type_name() const { return "dentry_unlink";} void print(ostream& o) const { o << "dentry_unlink(" << dirfrag << " " << dn << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(dn, p); ::decode(straybl, p); } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(dn, payload); ::encode(straybl, payload); } }; #endif ceph-0.80.11/src/messages/MOSDFailure.h0000664000175100017510000000410312623076744021514 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDFAILURE_H #define CEPH_MOSDFAILURE_H #include "messages/PaxosServiceMessage.h" class MOSDFailure : public PaxosServiceMessage { static const int HEAD_VERSION = 3; public: uuid_d fsid; entity_inst_t target_osd; __u8 is_failed; epoch_t epoch; int32_t failed_for; // known to be failed since at least this long MOSDFailure() : PaxosServiceMessage(MSG_OSD_FAILURE, 0, HEAD_VERSION) { } MOSDFailure(const uuid_d &fs, const entity_inst_t& f, int duration, epoch_t e) : PaxosServiceMessage(MSG_OSD_FAILURE, e, HEAD_VERSION), fsid(fs), target_osd(f), is_failed(true), epoch(e), failed_for(duration) { } private: ~MOSDFailure() {} public: entity_inst_t get_target() { return target_osd; } bool if_osd_failed() { return is_failed; } epoch_t get_epoch() { return epoch; } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(target_osd, p); ::decode(epoch, p); if (header.version >= 2) ::decode(is_failed, p); else is_failed = true; if (header.version >= 3) ::decode(failed_for, p); else failed_for = 0; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(target_osd, payload); ::encode(epoch, payload); ::encode(is_failed, payload); ::encode(failed_for, payload); } const char *get_type_name() const { return "osd_failure"; } void print(ostream& out) const { out << "osd_failure(" << (is_failed ? "failed " : "recovered ") << target_osd << " for " << failed_for << "sec e" << epoch << " v" << version << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDPGTrim.h0000664000175100017510000000306512623076744021275 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGTRIM_H #define CEPH_MOSDPGTRIM_H #include "msg/Message.h" class MOSDPGTrim : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: epoch_t epoch; spg_t pgid; eversion_t trim_to; epoch_t get_epoch() { return epoch; } MOSDPGTrim() : Message(MSG_OSD_PG_TRIM, HEAD_VERSION, COMPAT_VERSION) {} MOSDPGTrim(version_t mv, spg_t p, eversion_t tt) : Message(MSG_OSD_PG_TRIM), epoch(mv), pgid(p), trim_to(tt) { } private: ~MOSDPGTrim() {} public: const char *get_type_name() const { return "pg_trim"; } void print(ostream& out) const { out << "pg_trim(" << pgid << " to " << trim_to << " e" << epoch << ")"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); ::encode(pgid.pgid, payload); ::encode(trim_to, payload); ::encode(pgid.shard, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); ::decode(pgid.pgid, p); ::decode(trim_to, p); if (header.version >= 2) ::decode(pgid.shard, p); else pgid.shard = ghobject_t::no_shard(); } }; #endif ceph-0.80.11/src/messages/MPGStats.h0000664000175100017510000000312412623076744021106 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MPGSTATS_H #define CEPH_MPGSTATS_H #include "osd/osd_types.h" #include "messages/PaxosServiceMessage.h" class MPGStats : public PaxosServiceMessage { public: uuid_d fsid; map pg_stat; osd_stat_t osd_stat; epoch_t epoch; utime_t had_map_for; MPGStats() : PaxosServiceMessage(MSG_PGSTATS, 0) {} MPGStats(const uuid_d& f, epoch_t e, utime_t had) : PaxosServiceMessage(MSG_PGSTATS, 0), fsid(f), epoch(e), had_map_for(had) {} private: ~MPGStats() {}; public: const char *get_type_name() const { return "pg_stats"; } void print(ostream& out) const { out << "pg_stats(" << pg_stat.size() << " pgs tid " << get_tid() << " v " << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(osd_stat, payload); ::encode(pg_stat, payload); ::encode(epoch, payload); ::encode(had_map_for, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(osd_stat, p); ::decode(pg_stat, p); ::decode(epoch, p); ::decode(had_map_for, p); } }; #endif ceph-0.80.11/src/messages/MPing.h0000664000175100017510000000141312623076744020455 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MPING_H #define CEPH_MPING_H #include "msg/Message.h" #include "include/encoding.h" class MPing : public Message { public: MPing() : Message(CEPH_MSG_PING) {} private: ~MPing() {} public: void decode_payload() { } void encode_payload(uint64_t features) { } const char *get_type_name() const { return "ping"; } }; #endif ceph-0.80.11/src/messages/MExportDirDiscoverAck.h0000664000175100017510000000276712623076744023633 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRDISCOVERACK_H #define CEPH_MEXPORTDIRDISCOVERACK_H #include "msg/Message.h" #include "include/types.h" class MExportDirDiscoverAck : public Message { dirfrag_t dirfrag; bool success; public: inodeno_t get_ino() { return dirfrag.ino; } dirfrag_t get_dirfrag() { return dirfrag; } bool is_success() { return success; } MExportDirDiscoverAck() : Message(MSG_MDS_EXPORTDIRDISCOVERACK) {} MExportDirDiscoverAck(dirfrag_t df, uint64_t tid, bool s=true) : Message(MSG_MDS_EXPORTDIRDISCOVERACK), dirfrag(df), success(s) { set_tid(tid); } private: ~MExportDirDiscoverAck() {} public: const char *get_type_name() const { return "ExDisA"; } void print(ostream& o) const { o << "export_discover_ack(" << dirfrag; if (success) o << " success)"; else o << " failure)"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(success, p); } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(success, payload); } }; #endif ceph-0.80.11/src/messages/MMDSOpenIno.h0000664000175100017510000000226612623076744021502 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSOPENINO_H #define CEPH_MDSOPENINO_H #include "msg/Message.h" struct MMDSOpenIno : public Message { inodeno_t ino; vector ancestors; MMDSOpenIno() : Message(MSG_MDS_OPENINO) {} MMDSOpenIno(ceph_tid_t t, inodeno_t i, vector& a) : Message(MSG_MDS_OPENINO), ino(i), ancestors(a) { header.tid = t; } const char *get_type_name() const { return "openino"; } void print(ostream &out) const { out << "openino(" << header.tid << " " << ino << " " << ancestors << ")"; } void encode_payload(uint64_t features) { ::encode(ino, payload); ::encode(ancestors, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(ino, p); ::decode(ancestors, p); } }; #endif ceph-0.80.11/src/messages/MOSDBoot.h0000664000175100017510000000513112623076744021032 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDBOOT_H #define CEPH_MOSDBOOT_H #include "messages/PaxosServiceMessage.h" #include "include/types.h" #include "osd/osd_types.h" class MOSDBoot : public PaxosServiceMessage { static const int HEAD_VERSION = 6; static const int COMPAT_VERSION = 2; public: OSDSuperblock sb; entity_addr_t hb_back_addr, hb_front_addr; entity_addr_t cluster_addr; epoch_t boot_epoch; // last epoch this daemon was added to the map (if any) map metadata; ///< misc metadata about this osd uint64_t osd_features; MOSDBoot() : PaxosServiceMessage(MSG_OSD_BOOT, 0, HEAD_VERSION, COMPAT_VERSION), boot_epoch(0), osd_features(0) { } MOSDBoot(OSDSuperblock& s, epoch_t be, const entity_addr_t& hb_back_addr_ref, const entity_addr_t& hb_front_addr_ref, const entity_addr_t& cluster_addr_ref, uint64_t feat) : PaxosServiceMessage(MSG_OSD_BOOT, s.current_epoch, HEAD_VERSION, COMPAT_VERSION), sb(s), hb_back_addr(hb_back_addr_ref), hb_front_addr(hb_front_addr_ref), cluster_addr(cluster_addr_ref), boot_epoch(be), osd_features(feat) { } private: ~MOSDBoot() { } public: const char *get_type_name() const { return "osd_boot"; } void print(ostream& out) const { out << "osd_boot(osd." << sb.whoami << " booted " << boot_epoch << " features " << osd_features << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(sb, payload); ::encode(hb_back_addr, payload); ::encode(cluster_addr, payload); ::encode(boot_epoch, payload); ::encode(hb_front_addr, payload); ::encode(metadata, payload); ::encode(osd_features, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(sb, p); ::decode(hb_back_addr, p); if (header.version >= 2) ::decode(cluster_addr, p); if (header.version >= 3) ::decode(boot_epoch, p); if (header.version >= 4) ::decode(hb_front_addr, p); if (header.version >= 5) ::decode(metadata, p); if (header.version >= 6) ::decode(osd_features, p); else osd_features = 0; } }; #endif ceph-0.80.11/src/messages/MMonCommand.h0000664000175100017510000000255712623076744021622 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONCOMMAND_H #define CEPH_MMONCOMMAND_H #include "messages/PaxosServiceMessage.h" #include using std::vector; class MMonCommand : public PaxosServiceMessage { public: uuid_d fsid; vector cmd; MMonCommand() : PaxosServiceMessage(MSG_MON_COMMAND, 0) {} MMonCommand(const uuid_d &f) : PaxosServiceMessage(MSG_MON_COMMAND, 0), fsid(f) { } private: ~MMonCommand() {} public: const char *get_type_name() const { return "mon_command"; } void print(ostream& o) const { o << "mon_command("; for (unsigned i=0; i * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSTABLEREQUEST_H #define CEPH_MMDSTABLEREQUEST_H #include "msg/Message.h" #include "mds/mds_table_types.h" class MMDSTableRequest : public Message { public: __u16 table; __s16 op; uint64_t reqid; bufferlist bl; MMDSTableRequest() : Message(MSG_MDS_TABLE_REQUEST) {} MMDSTableRequest(int tab, int o, uint64_t r, version_t v=0) : Message(MSG_MDS_TABLE_REQUEST), table(tab), op(o), reqid(r) { set_tid(v); } private: ~MMDSTableRequest() {} public: virtual const char *get_type_name() const { return "mds_table_request"; } void print(ostream& o) const { o << "mds_table_request(" << get_mdstable_name(table) << " " << get_mdstableserver_opname(op); if (reqid) o << " " << reqid; if (get_tid()) o << " tid " << get_tid(); if (bl.length()) o << " " << bl.length() << " bytes"; o << ")"; } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(table, p); ::decode(op, p); ::decode(reqid, p); ::decode(bl, p); } virtual void encode_payload(uint64_t features) { ::encode(table, payload); ::encode(op, payload); ::encode(reqid, payload); ::encode(bl, payload); } }; #endif ceph-0.80.11/src/messages/MOSDScrub.h0000664000175100017510000000353512623076744021213 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDSCRUB_H #define CEPH_MOSDSCRUB_H #include "msg/Message.h" /* * instruct an OSD to scrub some or all pg(s) */ struct MOSDScrub : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; uuid_d fsid; vector scrub_pgs; bool repair; bool deep; MOSDScrub() : Message(MSG_OSD_SCRUB, HEAD_VERSION, COMPAT_VERSION) {} MOSDScrub(const uuid_d& f, bool r, bool d) : Message(MSG_OSD_SCRUB, HEAD_VERSION, COMPAT_VERSION), fsid(f), repair(r), deep(d) {} MOSDScrub(const uuid_d& f, vector& pgs, bool r, bool d) : Message(MSG_OSD_SCRUB, HEAD_VERSION, COMPAT_VERSION), fsid(f), scrub_pgs(pgs), repair(r), deep(d) {} private: ~MOSDScrub() {} public: const char *get_type_name() const { return "scrub"; } void print(ostream& out) const { out << "scrub("; if (scrub_pgs.empty()) out << "osd"; else out << scrub_pgs; if (repair) out << " repair"; if (deep) out << " deep"; out << ")"; } void encode_payload(uint64_t features) { ::encode(fsid, payload); ::encode(scrub_pgs, payload); ::encode(repair, payload); ::encode(deep, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(fsid, p); ::decode(scrub_pgs, p); ::decode(repair, p); if (header.version >= 2) { ::decode(deep, p); } else { deep = false; } } }; #endif ceph-0.80.11/src/messages/MPoolOp.h0000664000175100017510000000500412623076744020770 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MPOOLOP_H #define CEPH_MPOOLOP_H #include "messages/PaxosServiceMessage.h" class MPoolOp : public PaxosServiceMessage { static const int HEAD_VERSION = 4; static const int COMPAT_VERSION = 2; public: uuid_d fsid; __u32 pool; string name; __u32 op; uint64_t auid; snapid_t snapid; __s16 crush_rule; MPoolOp() : PaxosServiceMessage(CEPH_MSG_POOLOP, 0, HEAD_VERSION, COMPAT_VERSION) { } MPoolOp(const uuid_d& f, ceph_tid_t t, int p, string& n, int o, version_t v) : PaxosServiceMessage(CEPH_MSG_POOLOP, v, HEAD_VERSION, COMPAT_VERSION), fsid(f), pool(p), name(n), op(o), auid(0), snapid(0), crush_rule(0) { set_tid(t); } MPoolOp(const uuid_d& f, ceph_tid_t t, int p, string& n, int o, uint64_t uid, version_t v) : PaxosServiceMessage(CEPH_MSG_POOLOP, v, HEAD_VERSION, COMPAT_VERSION), fsid(f), pool(p), name(n), op(o), auid(uid), snapid(0), crush_rule(0) { set_tid(t); } private: ~MPoolOp() {} public: const char *get_type_name() const { return "poolop"; } void print(ostream& out) const { out << "pool_op(" << ceph_pool_op_name(op) << " pool " << pool << " auid " << auid << " tid " << get_tid() << " name " << name << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(pool, payload); ::encode(op, payload); ::encode(auid, payload); ::encode(snapid, payload); ::encode(name, payload); __u8 pad = 0; ::encode(pad, payload); /* for v3->v4 encoding change */ ::encode(crush_rule, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(pool, p); if (header.version < 2) ::decode(name, p); ::decode(op, p); ::decode(auid, p); ::decode(snapid, p); if (header.version >= 2) ::decode(name, p); if (header.version >= 3) { __u8 pad; ::decode(pad, p); if (header.version >= 4) ::decode(crush_rule, p); else crush_rule = pad; } else crush_rule = -1; } }; #endif ceph-0.80.11/src/messages/MMDSLoadTargets.h0000664000175100017510000000266612623076744022350 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSLoadTargets_H #define CEPH_MMDSLoadTargets_H #include "msg/Message.h" #include "messages/PaxosServiceMessage.h" #include "include/types.h" #include using std::map; class MMDSLoadTargets : public PaxosServiceMessage { public: uint64_t global_id; set targets; MMDSLoadTargets() : PaxosServiceMessage(MSG_MDS_OFFLOAD_TARGETS, 0) {} MMDSLoadTargets(uint64_t g, set& mds_targets) : PaxosServiceMessage(MSG_MDS_OFFLOAD_TARGETS, 0), global_id(g), targets(mds_targets) {} private: ~MMDSLoadTargets() {} public: const char* get_type_name() const { return "mds_load_targets"; } void print(ostream& o) const { o << "mds_load_targets(" << global_id << " " << targets << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(global_id, p); ::decode(targets, p); } void encode_payload(uint64_t features) { paxos_encode(); ::encode(global_id, payload); ::encode(targets, payload); } }; #endif ceph-0.80.11/src/messages/MExportDirNotify.h0000664000175100017510000000416512623076744022700 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRNOTIFY_H #define CEPH_MEXPORTDIRNOTIFY_H #include "msg/Message.h" #include using namespace std; class MExportDirNotify : public Message { dirfrag_t base; bool ack; pair<__s32,__s32> old_auth, new_auth; list bounds; // bounds; these dirs are _not_ included (tho the dirfragdes are) public: dirfrag_t get_dirfrag() { return base; } pair<__s32,__s32> get_old_auth() { return old_auth; } pair<__s32,__s32> get_new_auth() { return new_auth; } bool wants_ack() { return ack; } list& get_bounds() { return bounds; } MExportDirNotify() {} MExportDirNotify(dirfrag_t i, uint64_t tid, bool a, pair<__s32,__s32> oa, pair<__s32,__s32> na) : Message(MSG_MDS_EXPORTDIRNOTIFY), base(i), ack(a), old_auth(oa), new_auth(na) { set_tid(tid); } private: ~MExportDirNotify() {} public: const char *get_type_name() const { return "ExNot"; } void print(ostream& o) const { o << "export_notify(" << base; o << " " << old_auth << " -> " << new_auth; if (ack) o << " ack)"; else o << " no ack)"; } void copy_bounds(list& ex) { this->bounds = ex; } void copy_bounds(set& ex) { for (set::iterator i = ex.begin(); i != ex.end(); ++i) bounds.push_back(*i); } void encode_payload(uint64_t features) { ::encode(base, payload); ::encode(ack, payload); ::encode(old_auth, payload); ::encode(new_auth, payload); ::encode(bounds, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(base, p); ::decode(ack, p); ::decode(old_auth, p); ::decode(new_auth, p); ::decode(bounds, p); } }; #endif ceph-0.80.11/src/messages/MMonSubscribe.h0000664000175100017510000000463112623076744022160 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONSUBSCRIBE_H #define CEPH_MMONSUBSCRIBE_H #include "msg/Message.h" #include "include/ceph_features.h" /* * compatibility with old crap */ struct ceph_mon_subscribe_item_old { __le64 unused; __le64 have; __u8 onetime; } __attribute__ ((packed)); WRITE_RAW_ENCODER(ceph_mon_subscribe_item_old) struct MMonSubscribe : public Message { static const int HEAD_VERSION = 2; map what; MMonSubscribe() : Message(CEPH_MSG_MON_SUBSCRIBE, HEAD_VERSION) { } private: ~MMonSubscribe() {} public: void sub_want(const char *w, version_t start, unsigned flags) { what[w].start = start; what[w].flags = flags; } const char *get_type_name() const { return "mon_subscribe"; } void print(ostream& o) const { o << "mon_subscribe(" << what << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); if (header.version < 2) { map oldwhat; ::decode(oldwhat, p); what.clear(); for (map::iterator q = oldwhat.begin(); q != oldwhat.end(); q++) { if (q->second.have) what[q->first].start = q->second.have + 1; else what[q->first].start = 0; what[q->first].flags = 0; if (q->second.onetime) what[q->first].flags |= CEPH_SUBSCRIBE_ONETIME; } } else { ::decode(what, p); } } void encode_payload(uint64_t features) { if (features & CEPH_FEATURE_SUBSCRIBE2) { ::encode(what, payload); } else { header.version = 0; map oldwhat; for (map::iterator q = what.begin(); q != what.end(); q++) { if (q->second.start) // warning: start=1 -> have=0, which was ambiguous oldwhat[q->first].have = q->second.start - 1; else oldwhat[q->first].have = 0; oldwhat[q->first].onetime = q->second.flags & CEPH_SUBSCRIBE_ONETIME; } ::encode(oldwhat, payload); } } }; #endif ceph-0.80.11/src/messages/MOSDPGNotify.h0000664000175100017510000001034112623076744021625 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGPEERNOTIFY_H #define CEPH_MOSDPGPEERNOTIFY_H #include "msg/Message.h" #include "osd/osd_types.h" /* * PGNotify - notify primary of my PGs and versions. */ class MOSDPGNotify : public Message { static const int HEAD_VERSION = 5; static const int COMPAT_VERSION = 2; epoch_t epoch; /// query_epoch is the epoch of the query being responded to, or /// the current epoch if this is not being sent in response to a /// query. This allows the recipient to disregard responses to old /// queries. vector > pg_list; // pgid -> version public: version_t get_epoch() { return epoch; } vector >& get_pg_list() { return pg_list; } MOSDPGNotify() : Message(MSG_OSD_PG_NOTIFY, HEAD_VERSION, COMPAT_VERSION) { } MOSDPGNotify(epoch_t e, vector >& l) : Message(MSG_OSD_PG_NOTIFY, HEAD_VERSION, COMPAT_VERSION), epoch(e) { pg_list.swap(l); } private: ~MOSDPGNotify() {} public: const char *get_type_name() const { return "PGnot"; } void encode_payload(uint64_t features) { // Use query_epoch for first entry for backwards compatibility epoch_t query_epoch = epoch; if (pg_list.size()) query_epoch = pg_list.begin()->first.query_epoch; ::encode(epoch, payload); // v2 was vector __u32 n = pg_list.size(); ::encode(n, payload); for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); p++) ::encode(p->first.info, payload); ::encode(query_epoch, payload); // v3 needs the pg_interval_map_t for each record for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); p++) ::encode(p->second, payload); // v4 needs epoch_sent, query_epoch for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); p++) ::encode(pair( p->first.epoch_sent, p->first.query_epoch), payload); // v5 needs from, to for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); ++p) { ::encode(p->first.from, payload); ::encode(p->first.to, payload); } } void decode_payload() { epoch_t query_epoch; bufferlist::iterator p = payload.begin(); ::decode(epoch, p); // decode pg_info_t portion of the vector __u32 n; ::decode(n, p); pg_list.resize(n); for (unsigned i=0; i= 3) { // get the pg_interval_map_t portion for (unsigned i=0; i >::iterator i = pg_list.begin(); i != pg_list.end(); i++) { if (header.version >= 4) { pair dec; ::decode(dec, p); i->first.epoch_sent = dec.first; i->first.query_epoch = dec.second; } else { i->first.epoch_sent = epoch; i->first.query_epoch = query_epoch; } } // v5 needs from and to if (header.version >= 5) { for (vector >::iterator i = pg_list.begin(); i != pg_list.end(); i++) { ::decode(i->first.from, p); ::decode(i->first.to, p); } } } void print(ostream& out) const { out << "pg_notify("; for (vector >::const_iterator i = pg_list.begin(); i != pg_list.end(); ++i) { if (i != pg_list.begin()) out << ","; out << i->first.info.pgid; if (i->second.size()) out << "(" << i->second.size() << ")"; } out << " epoch " << epoch << ")"; } }; #endif ceph-0.80.11/src/messages/MMonGlobalID.h0000664000175100017510000000212512623076744021650 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONGLOBALID_H #define CEPH_MMONGLOBALID_H #include "messages/PaxosServiceMessage.h" struct MMonGlobalID : public PaxosServiceMessage { uint64_t old_max_id; MMonGlobalID() : PaxosServiceMessage(MSG_MON_GLOBAL_ID, 0), old_max_id(0) { } private: ~MMonGlobalID() {} public: const char *get_type_name() const { return "global_id"; } void print(ostream& out) const { out << "global_id (" << old_max_id << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(old_max_id, p); } void encode_payload(uint64_t features) { paxos_encode(); ::encode(old_max_id, payload); } }; #endif ceph-0.80.11/src/messages/MOSDPGRemove.h0000664000175100017510000000445412623076744021622 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGREMOVE_H #define CEPH_MOSDPGREMOVE_H #include "common/hobject.h" #include "msg/Message.h" class MOSDPGRemove : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; epoch_t epoch; public: vector pg_list; epoch_t get_epoch() { return epoch; } MOSDPGRemove() : Message(MSG_OSD_PG_REMOVE, HEAD_VERSION, COMPAT_VERSION) {} MOSDPGRemove(epoch_t e, vector& l) : Message(MSG_OSD_PG_REMOVE, HEAD_VERSION, COMPAT_VERSION) { this->epoch = e; pg_list.swap(l); } private: ~MOSDPGRemove() {} public: const char *get_type_name() const { return "PGrm"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); vector _pg_list; _pg_list.reserve(pg_list.size()); vector _shard_list; _shard_list.reserve(pg_list.size()); for (vector::iterator i = pg_list.begin(); i != pg_list.end(); ++i) { _pg_list.push_back(i->pgid); _shard_list.push_back(i->shard); } ::encode(_pg_list, payload); ::encode(_shard_list, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); vector _pg_list; ::decode(_pg_list, p); vector _shard_list(_pg_list.size(), ghobject_t::no_shard()); if (header.version >= 2) { _shard_list.clear(); ::decode(_shard_list, p); } assert(_shard_list.size() == _pg_list.size()); pg_list.reserve(_shard_list.size()); for (unsigned i = 0; i < _shard_list.size(); ++i) { pg_list.push_back(spg_t(_pg_list[i], _shard_list[i])); } } void print(ostream& out) const { out << "osd pg remove(" << "epoch " << epoch << "; "; for (vector::const_iterator i = pg_list.begin(); i != pg_list.end(); ++i) { out << "pg" << *i << "; "; } out << ")"; } }; #endif ceph-0.80.11/src/messages/MLog.h0000664000175100017510000000262612623076744020310 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MLOG_H #define CEPH_MLOG_H #include "common/LogEntry.h" #include "messages/PaxosServiceMessage.h" #include #include class MLog : public PaxosServiceMessage { public: uuid_d fsid; std::deque entries; MLog() : PaxosServiceMessage(MSG_LOG, 0) {} MLog(const uuid_d& f, const std::deque& e) : PaxosServiceMessage(MSG_LOG, 0), fsid(f), entries(e) { } MLog(const uuid_d& f) : PaxosServiceMessage(MSG_LOG, 0), fsid(f) { } private: ~MLog() {} public: const char *get_type_name() const { return "log"; } void print(ostream& out) const { out << "log("; if (entries.size()) out << entries.size() << " entries"; out << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(entries, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(entries, p); } }; #endif ceph-0.80.11/src/messages/MMDSOpenInoReply.h0000664000175100017510000000256612623076744022521 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSOPENINOREPLY_H #define CEPH_MDSOPENINOREPLY_H #include "msg/Message.h" struct MMDSOpenInoReply : public Message { inodeno_t ino; vector ancestors; int32_t hint; int32_t error; MMDSOpenInoReply() : Message(MSG_MDS_OPENINOREPLY) {} MMDSOpenInoReply(ceph_tid_t t, inodeno_t i, int h=-1, int e=0) : Message(MSG_MDS_OPENINOREPLY), ino(i), hint(h), error(e) { header.tid = t; } const char *get_type_name() const { return "openinoreply"; } void print(ostream &out) const { out << "openinoreply(" << header.tid << " " << ino << " " << hint << " " << ancestors << ")"; } void encode_payload(uint64_t features) { ::encode(ino, payload); ::encode(ancestors, payload); ::encode(hint, payload); ::encode(error, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(ino, p); ::decode(ancestors, p); ::decode(hint, p); ::decode(error, p); } }; #endif ceph-0.80.11/src/messages/MMDSSlaveRequest.h0000664000175100017510000001241112623076744022547 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSSLAVEREQUEST_H #define CEPH_MMDSSLAVEREQUEST_H #include "msg/Message.h" #include "mds/mdstypes.h" class MMDSSlaveRequest : public Message { public: static const int OP_XLOCK = 1; static const int OP_XLOCKACK = -1; static const int OP_UNXLOCK = 2; static const int OP_AUTHPIN = 3; static const int OP_AUTHPINACK = -3; static const int OP_LINKPREP = 4; static const int OP_UNLINKPREP = 5; static const int OP_LINKPREPACK = -4; static const int OP_RENAMEPREP = 7; static const int OP_RENAMEPREPACK = -7; static const int OP_WRLOCK = 8; static const int OP_WRLOCKACK = -8; static const int OP_UNWRLOCK = 9; static const int OP_RMDIRPREP = 10; static const int OP_RMDIRPREPACK = -10; static const int OP_DROPLOCKS = 11; static const int OP_RENAMENOTIFY = 12; static const int OP_RENAMENOTIFYACK = -12; static const int OP_FINISH = 17; static const int OP_COMMITTED = -18; static const int OP_ABORT = 20; // used for recovery only //static const int OP_COMMIT = 21; // used for recovery only const static char *get_opname(int o) { switch (o) { case OP_XLOCK: return "xlock"; case OP_XLOCKACK: return "xlock_ack"; case OP_UNXLOCK: return "unxlock"; case OP_AUTHPIN: return "authpin"; case OP_AUTHPINACK: return "authpin_ack"; case OP_LINKPREP: return "link_prep"; case OP_LINKPREPACK: return "link_prep_ack"; case OP_UNLINKPREP: return "unlink_prep"; case OP_RENAMEPREP: return "rename_prep"; case OP_RENAMEPREPACK: return "rename_prep_ack"; case OP_FINISH: return "finish"; // commit case OP_COMMITTED: return "committed"; case OP_WRLOCK: return "wrlock"; case OP_WRLOCKACK: return "wrlock_ack"; case OP_UNWRLOCK: return "unwrlock"; case OP_RMDIRPREP: return "rmdir_prep"; case OP_RMDIRPREPACK: return "rmdir_prep_ack"; case OP_DROPLOCKS: return "drop_locks"; case OP_RENAMENOTIFY: return "reame_notify"; case OP_RENAMENOTIFYACK: return "rename_notify_ack"; case OP_ABORT: return "abort"; //case OP_COMMIT: return "commit"; default: assert(0); return 0; } } private: metareqid_t reqid; __u32 attempt; __s16 op; __u16 flags; static const unsigned FLAG_NONBLOCK = 1; static const unsigned FLAG_WOULDBLOCK = 2; // for locking __u16 lock_type; // lock object type MDSCacheObjectInfo object_info; // for authpins vector authpins; public: // for rename prep filepath srcdnpath; filepath destdnpath; set<__s32> witnesses; bufferlist inode_export; version_t inode_export_v; bufferlist srci_replica; utime_t now; bufferlist stray; // stray dir + dentry public: metareqid_t get_reqid() { return reqid; } __u32 get_attempt() const { return attempt; } int get_op() { return op; } bool is_reply() { return op < 0; } int get_lock_type() { return lock_type; } MDSCacheObjectInfo &get_object_info() { return object_info; } MDSCacheObjectInfo &get_authpin_freeze() { return object_info; } vector& get_authpins() { return authpins; } void mark_nonblock() { flags |= FLAG_NONBLOCK; } bool is_nonblock() { return (flags & FLAG_NONBLOCK); } void mark_error_wouldblock() { flags |= FLAG_WOULDBLOCK; } bool is_error_wouldblock() { return (flags & FLAG_WOULDBLOCK); } void set_lock_type(int t) { lock_type = t; } // ---- MMDSSlaveRequest() : Message(MSG_MDS_SLAVE_REQUEST) { } MMDSSlaveRequest(metareqid_t ri, __u32 att, int o) : Message(MSG_MDS_SLAVE_REQUEST), reqid(ri), attempt(att), op(o), flags(0), lock_type(0), inode_export_v(0) { } private: ~MMDSSlaveRequest() {} public: void encode_payload(uint64_t features) { ::encode(reqid, payload); ::encode(attempt, payload); ::encode(op, payload); ::encode(flags, payload); ::encode(lock_type, payload); ::encode(object_info, payload); ::encode(authpins, payload); ::encode(srcdnpath, payload); ::encode(destdnpath, payload); ::encode(witnesses, payload); ::encode(now, payload); ::encode(inode_export, payload); ::encode(inode_export_v, payload); ::encode(srci_replica, payload); ::encode(stray, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(reqid, p); ::decode(attempt, p); ::decode(op, p); ::decode(flags, p); ::decode(lock_type, p); ::decode(object_info, p); ::decode(authpins, p); ::decode(srcdnpath, p); ::decode(destdnpath, p); ::decode(witnesses, p); ::decode(now, p); ::decode(inode_export, p); ::decode(inode_export_v, p); ::decode(srci_replica, p); ::decode(stray, p); } const char *get_type_name() const { return "slave_request"; } void print(ostream& out) const { out << "slave_request(" << reqid << "." << attempt << " " << get_opname(op) << ")"; } }; #endif ceph-0.80.11/src/messages/MExportDirAck.h0000664000175100017510000000236612623076744022127 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRACK_H #define CEPH_MEXPORTDIRACK_H #include "MExportDir.h" class MExportDirAck : public Message { public: dirfrag_t dirfrag; bufferlist imported_caps; dirfrag_t get_dirfrag() { return dirfrag; } MExportDirAck() : Message(MSG_MDS_EXPORTDIRACK) {} MExportDirAck(dirfrag_t df, uint64_t tid) : Message(MSG_MDS_EXPORTDIRACK), dirfrag(df) { set_tid(tid); } private: ~MExportDirAck() {} public: const char *get_type_name() const { return "ExAck"; } void print(ostream& o) const { o << "export_ack(" << dirfrag << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(imported_caps, p); } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(imported_caps, payload); } }; #endif ceph-0.80.11/src/messages/MDentryLink.h0000664000175100017510000000312112623076744021641 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDENTRYLINK_H #define CEPH_MDENTRYLINK_H class MDentryLink : public Message { dirfrag_t subtree; dirfrag_t dirfrag; string dn; bool is_primary; public: dirfrag_t get_subtree() { return subtree; } dirfrag_t get_dirfrag() { return dirfrag; } string& get_dn() { return dn; } bool get_is_primary() { return is_primary; } bufferlist bl; MDentryLink() : Message(MSG_MDS_DENTRYLINK) { } MDentryLink(dirfrag_t r, dirfrag_t df, string& n, bool p) : Message(MSG_MDS_DENTRYLINK), subtree(r), dirfrag(df), dn(n), is_primary(p) {} private: ~MDentryLink() {} public: const char *get_type_name() const { return "dentry_link";} void print(ostream& o) const { o << "dentry_link(" << dirfrag << " " << dn << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(subtree, p); ::decode(dirfrag, p); ::decode(dn, p); ::decode(is_primary, p); ::decode(bl, p); } void encode_payload(uint64_t features) { ::encode(subtree, payload); ::encode(dirfrag, payload); ::encode(dn, payload); ::encode(is_primary, payload); ::encode(bl, payload); } }; #endif ceph-0.80.11/src/messages/MOSDOpReply.h0000664000175100017510000001724012623076744021525 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDOPREPLY_H #define CEPH_MOSDOPREPLY_H #include "msg/Message.h" #include "MOSDOp.h" #include "os/ObjectStore.h" #include "common/errno.h" /* * OSD op reply * * oid - object id * op - OSD_OP_DELETE, etc. * */ class MOSDOpReply : public Message { static const int HEAD_VERSION = 6; static const int COMPAT_VERSION = 2; object_t oid; pg_t pgid; vector ops; int64_t flags; int32_t result; eversion_t bad_replay_version; eversion_t replay_version; version_t user_version; epoch_t osdmap_epoch; int32_t retry_attempt; request_redirect_t redirect; public: object_t get_oid() const { return oid; } pg_t get_pg() const { return pgid; } int get_flags() const { return flags; } bool is_ondisk() const { return get_flags() & CEPH_OSD_FLAG_ONDISK; } bool is_onnvram() const { return get_flags() & CEPH_OSD_FLAG_ONNVRAM; } int get_result() const { return result; } eversion_t get_replay_version() const { return replay_version; } version_t get_user_version() const { return user_version; } void set_result(int r) { result = r; } void set_reply_versions(eversion_t v, version_t uv) { replay_version = v; user_version = uv; /* We go through some shenanigans here for backwards compatibility * with old clients, who do not look at our replay_version and * user_version but instead see what we now call the * bad_replay_version. On pools without caching * the user_version infrastructure is a slightly-laggy copy of * the regular pg version/at_version infrastructure; the difference * being it is not updated on watch ops like that is -- but on updates * it is set equal to at_version. This means that for non-watch write ops * on classic pools, all three of replay_version, user_version, and * bad_replay_version are identical. But for watch ops the replay_version * has been updated, while the user_at_version has not, and the semantics * we promised old clients are that the version they see is not an update. * So set the bad_replay_version to be the same as the user_at_version. */ bad_replay_version = v; if (uv) { bad_replay_version.version = uv; } } /* Don't fill in replay_version for non-write ops */ void set_enoent_reply_versions(eversion_t v, version_t uv) { user_version = uv; bad_replay_version = v; } void set_redirect(const request_redirect_t& redir) { redirect = redir; } const request_redirect_t& get_redirect() const { return redirect; } bool is_redirect_reply() const { return !redirect.empty(); } void add_flags(int f) { flags |= f; } void claim_op_out_data(vector& o) { assert(ops.size() == o.size()); for (unsigned i = 0; i < o.size(); i++) { ops[i].outdata.claim(o[i].outdata); } } void claim_ops(vector& o) { o.swap(ops); } /** * get retry attempt * * If we don't know the attempt (because the server is old), return -1. */ int get_retry_attempt() const { return retry_attempt; } // osdmap epoch_t get_map_epoch() const { return osdmap_epoch; } /*osd_reqid_t get_reqid() { return osd_reqid_t(get_dest(), head.client_inc, head.tid); } */ public: MOSDOpReply() : Message(CEPH_MSG_OSD_OPREPLY, HEAD_VERSION, COMPAT_VERSION) { } MOSDOpReply(MOSDOp *req, int r, epoch_t e, int acktype, bool ignore_out_data) : Message(CEPH_MSG_OSD_OPREPLY, HEAD_VERSION, COMPAT_VERSION) { set_tid(req->get_tid()); ops = req->ops; result = r; flags = (req->flags & ~(CEPH_OSD_FLAG_ONDISK|CEPH_OSD_FLAG_ONNVRAM|CEPH_OSD_FLAG_ACK)) | acktype; oid = req->oid; pgid = req->pgid; osdmap_epoch = e; user_version = 0; retry_attempt = req->get_retry_attempt(); // zero out ops payload_len and possibly out data for (unsigned i = 0; i < ops.size(); i++) { ops[i].op.payload_len = 0; if (ignore_out_data) ops[i].outdata.clear(); } } private: ~MOSDOpReply() {} public: virtual void encode_payload(uint64_t features) { OSDOp::merge_osd_op_vector_out_data(ops, data); if ((features & CEPH_FEATURE_PGID64) == 0) { header.version = 1; ceph_osd_reply_head head; memset(&head, 0, sizeof(head)); head.layout.ol_pgid = pgid.get_old_pg().v; head.flags = flags; head.osdmap_epoch = osdmap_epoch; head.reassert_version = bad_replay_version; head.result = result; head.num_ops = ops.size(); head.object_len = oid.name.length(); ::encode(head, payload); for (unsigned i = 0; i < head.num_ops; i++) { ::encode(ops[i].op, payload); } ::encode_nohead(oid.name, payload); } else { ::encode(oid, payload); ::encode(pgid, payload); ::encode(flags, payload); ::encode(result, payload); ::encode(bad_replay_version, payload); ::encode(osdmap_epoch, payload); __u32 num_ops = ops.size(); ::encode(num_ops, payload); for (unsigned i = 0; i < num_ops; i++) ::encode(ops[i].op, payload); ::encode(retry_attempt, payload); for (unsigned i = 0; i < num_ops; i++) ::encode(ops[i].rval, payload); ::encode(replay_version, payload); ::encode(user_version, payload); ::encode(redirect, payload); } } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); if (header.version < 2) { ceph_osd_reply_head head; ::decode(head, p); ops.resize(head.num_ops); for (unsigned i = 0; i < head.num_ops; i++) { ::decode(ops[i].op, p); } ::decode_nohead(head.object_len, oid.name, p); pgid = pg_t(head.layout.ol_pgid); result = head.result; flags = head.flags; replay_version = head.reassert_version; user_version = replay_version.version; osdmap_epoch = head.osdmap_epoch; retry_attempt = -1; } else { ::decode(oid, p); ::decode(pgid, p); ::decode(flags, p); ::decode(result, p); ::decode(bad_replay_version, p); ::decode(osdmap_epoch, p); __u32 num_ops = ops.size(); ::decode(num_ops, p); ops.resize(num_ops); for (unsigned i = 0; i < num_ops; i++) ::decode(ops[i].op, p); if (header.version >= 3) ::decode(retry_attempt, p); else retry_attempt = -1; if (header.version >= 4) { for (unsigned i = 0; i < num_ops; ++i) ::decode(ops[i].rval, p); OSDOp::split_osd_op_vector_out_data(ops, data); } if (header.version >= 5) { ::decode(replay_version, p); ::decode(user_version, p); } else { replay_version = bad_replay_version; user_version = replay_version.version; } if (header.version >= 6) ::decode(redirect, p); } } const char *get_type_name() const { return "osd_op_reply"; } void print(ostream& out) const { out << "osd_op_reply(" << get_tid() << " " << oid << " " << ops << " v" << get_replay_version() << " uv" << get_user_version(); if (is_ondisk()) out << " ondisk"; else if (is_onnvram()) out << " onnvram"; else out << " ack"; out << " = " << get_result(); if (get_result() < 0) { out << " (" << cpp_strerror(get_result()) << ")"; } if (is_redirect_reply()) { out << " redirect: { " << redirect << " }"; } out << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDECSubOpWriteReply.h0000664000175100017510000000261112623076744023416 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDECSUBOPWRITEREPLY_H #define MOSDECSUBOPWRITEREPLY_H #include "msg/Message.h" #include "osd/osd_types.h" #include "osd/ECMsgTypes.h" class MOSDECSubOpWriteReply : public Message { static const int HEAD_VERSION = 1; static const int COMPAT_VERSION = 1; public: spg_t pgid; epoch_t map_epoch; ECSubWriteReply op; int get_cost() const { return 0; } MOSDECSubOpWriteReply() : Message(MSG_OSD_EC_WRITE_REPLY, HEAD_VERSION, COMPAT_VERSION) {} virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid, p); ::decode(map_epoch, p); ::decode(op, p); } virtual void encode_payload(uint64_t features) { ::encode(pgid, payload); ::encode(map_epoch, payload); ::encode(op, payload); } const char *get_type_name() const { return "MOSDECSubOpWriteReply"; } void print(ostream& out) const { out << "MOSDECSubOpWriteReply(" << pgid << " " << map_epoch << " " << op; out << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDPGPushReply.h0000664000175100017510000000364112623076744022315 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDPGPUSHREPLY_H #define MOSDPGPUSHREPLY_H #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPGPushReply : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: pg_shard_t from; spg_t pgid; epoch_t map_epoch; vector replies; uint64_t cost; MOSDPGPushReply() : Message(MSG_OSD_PG_PUSH_REPLY, HEAD_VERSION, COMPAT_VERSION), cost(0) {} void compute_cost(CephContext *cct) { cost = 0; for (vector::iterator i = replies.begin(); i != replies.end(); ++i) { cost += i->cost(cct); } } int get_cost() const { return cost; } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid.pgid, p); ::decode(map_epoch, p); ::decode(replies, p); ::decode(cost, p); if (header.version >= 2) { ::decode(pgid.shard, p); ::decode(from, p); } else { pgid.shard = ghobject_t::NO_SHARD; from = pg_shard_t(get_source().num(), ghobject_t::NO_SHARD); } } virtual void encode_payload(uint64_t features) { ::encode(pgid.pgid, payload); ::encode(map_epoch, payload); ::encode(replies, payload); ::encode(cost, payload); ::encode(pgid.shard, payload); ::encode(from, payload); } void print(ostream& out) const { out << "MOSDPGPushReply(" << pgid << " " << map_epoch << " " << replies; out << ")"; } const char *get_type_name() const { return "MOSDPGPushReply"; } }; #endif ceph-0.80.11/src/messages/MOSDPGPull.h0000664000175100017510000000354712623076744021303 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDPGPULL_H #define MOSDPGPULL_H #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPGPull : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: pg_shard_t from; spg_t pgid; epoch_t map_epoch; vector pulls; uint64_t cost; MOSDPGPull() : Message(MSG_OSD_PG_PULL, HEAD_VERSION, COMPAT_VERSION), cost(0) {} void compute_cost(CephContext *cct) { cost = 0; for (vector::iterator i = pulls.begin(); i != pulls.end(); ++i) { cost += i->cost(cct); } } int get_cost() const { return cost; } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid.pgid, p); ::decode(map_epoch, p); ::decode(pulls, p); ::decode(cost, p); if (header.version >= 2) { ::decode(pgid.shard, p); ::decode(from, p); } else { pgid.shard = ghobject_t::NO_SHARD; from = pg_shard_t(get_source().num(), ghobject_t::NO_SHARD); } } virtual void encode_payload(uint64_t features) { ::encode(pgid.pgid, payload); ::encode(map_epoch, payload); ::encode(pulls, payload); ::encode(cost, payload); ::encode(pgid.shard, payload); ::encode(from, payload); } const char *get_type_name() const { return "MOSDPGPull"; } void print(ostream& out) const { out << "MOSDPGPull(" << pgid << " " << map_epoch << " " << pulls; out << ")"; } }; #endif ceph-0.80.11/src/messages/Makefile.am0000664000175100017510000000605512623076744021335 0ustar jenkins-buildjenkins-build noinst_HEADERS += \ messages/MAuth.h \ messages/MAuthReply.h \ messages/MCacheExpire.h \ messages/MClientCaps.h \ messages/MClientCapRelease.h \ messages/MClientLease.h \ messages/MClientReconnect.h \ messages/MClientReply.h \ messages/MClientRequest.h \ messages/MClientRequestForward.h \ messages/MClientSession.h \ messages/MClientSnap.h \ messages/MCommand.h \ messages/MCommandReply.h \ messages/MDentryLink.h \ messages/MDentryUnlink.h \ messages/MDirUpdate.h \ messages/MDiscover.h \ messages/MDiscoverReply.h \ messages/MExportCaps.h \ messages/MExportCapsAck.h \ messages/MExportDir.h \ messages/MExportDirAck.h \ messages/MExportDirCancel.h \ messages/MExportDirDiscover.h \ messages/MExportDirDiscoverAck.h \ messages/MExportDirFinish.h \ messages/MExportDirNotify.h \ messages/MExportDirNotifyAck.h \ messages/MExportDirPrep.h \ messages/MExportDirPrepAck.h \ messages/MGenericMessage.h \ messages/MGetPoolStats.h \ messages/MGetPoolStatsReply.h \ messages/MHeartbeat.h \ messages/MInodeFileCaps.h \ messages/MLock.h \ messages/MLog.h \ messages/MLogAck.h \ messages/MMDSBeacon.h \ messages/MMDSCacheRejoin.h \ messages/MMDSLoadTargets.h \ messages/MMDSFindIno.h \ messages/MMDSFindInoReply.h \ messages/MMDSFragmentNotify.h \ messages/MMDSMap.h \ messages/MMDSOpenIno.h \ messages/MMDSOpenInoReply.h \ messages/MMDSResolve.h \ messages/MMDSResolveAck.h \ messages/MMDSSlaveRequest.h \ messages/MMDSTableRequest.h \ messages/MMonCommand.h \ messages/MMonCommandAck.h \ messages/MMonElection.h \ messages/MMonGetMap.h \ messages/MMonGetVersion.h \ messages/MMonGetVersionReply.h \ messages/MMonGlobalID.h \ messages/MMonHealth.h \ messages/MMonJoin.h \ messages/MMonMap.h \ messages/MMonPaxos.h \ messages/MMonProbe.h \ messages/MMonScrub.h \ messages/MMonSubscribe.h \ messages/MMonSubscribeAck.h \ messages/MMonSync.h \ messages/MOSDAlive.h \ messages/MOSDBoot.h \ messages/MOSDFailure.h \ messages/MOSDMarkMeDown.h \ messages/MOSDMap.h \ messages/MOSDOp.h \ messages/MOSDOpReply.h \ messages/MOSDPGBackfill.h \ messages/MOSDPGCreate.h \ messages/MOSDPGPush.h \ messages/MOSDPGPull.h \ messages/MOSDPGPushReply.h \ messages/MOSDPGInfo.h \ messages/MOSDPGLog.h \ messages/MOSDPGMissing.h \ messages/MOSDPGNotify.h \ messages/MOSDPGQuery.h \ messages/MOSDPGRemove.h \ messages/MOSDPGScan.h \ messages/MOSDECSubOpWrite.h \ messages/MOSDECSubOpWriteReply.h \ messages/MOSDECSubOpRead.h \ messages/MOSDECSubOpReadReply.h \ messages/MBackfillReserve.h \ messages/MRecoveryReserve.h \ messages/MMonQuorumService.h \ messages/MOSDPGTemp.h \ messages/MOSDPGTrim.h \ messages/MOSDPing.h \ messages/MOSDRepScrub.h \ messages/MOSDScrub.h \ messages/MOSDSubOp.h \ messages/MOSDSubOpReply.h \ messages/MPGStats.h \ messages/MPGStatsAck.h \ messages/MPing.h \ messages/MPoolOp.h \ messages/MPoolOpReply.h \ messages/MRemoveSnaps.h \ messages/MRoute.h \ messages/MForward.h \ messages/MStatfs.h \ messages/MStatfsReply.h \ messages/MTimeCheck.h \ messages/MWatchNotify.h \ messages/PaxosServiceMessage.h ceph-0.80.11/src/messages/MOSDECSubOpWrite.h0000664000175100017510000000305712623076744022407 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDECSUBOPWRITE_H #define MOSDECSUBOPWRITE_H #include "msg/Message.h" #include "osd/osd_types.h" #include "osd/ECMsgTypes.h" class MOSDECSubOpWrite : public Message { static const int HEAD_VERSION = 1; static const int COMPAT_VERSION = 1; public: spg_t pgid; epoch_t map_epoch; ECSubWrite op; int get_cost() const { return 0; } MOSDECSubOpWrite() : Message(MSG_OSD_EC_WRITE, HEAD_VERSION, COMPAT_VERSION) {} MOSDECSubOpWrite(ECSubWrite &op) : Message(MSG_OSD_EC_WRITE, HEAD_VERSION, COMPAT_VERSION), op(op) {} virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid, p); ::decode(map_epoch, p); ::decode(op, p); } virtual void encode_payload(uint64_t features) { ::encode(pgid, payload); ::encode(map_epoch, payload); ::encode(op, payload); } const char *get_type_name() const { return "MOSDECSubOpWrite"; } void print(ostream& out) const { out << "MOSDECSubOpWrite(" << pgid << " " << map_epoch << " " << op; out << ")"; } void clear_buffers() { op.t = ObjectStore::Transaction(); op.log_entries.clear(); } }; #endif ceph-0.80.11/src/messages/MCacheExpire.h0000664000175100017510000000525412623076744021747 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCACHEEXPIRE_H #define CEPH_MCACHEEXPIRE_H #include "mds/mdstypes.h" class MCacheExpire : public Message { __s32 from; public: /* group things by realm (auth delgation root), since that's how auth is determined. that makes it less work to process when exports are in progress. */ struct realm { map inodes; map dirs; map,uint32_t> > dentries; void merge(realm& o) { inodes.insert(o.inodes.begin(), o.inodes.end()); dirs.insert(o.dirs.begin(), o.dirs.end()); for (map,uint32_t> >::iterator p = o.dentries.begin(); p != o.dentries.end(); ++p) { if (dentries.count(p->first) == 0) dentries[p->first] = p->second; else dentries[p->first].insert(p->second.begin(), p->second.end()); } } void encode(bufferlist &bl) const { ::encode(inodes, bl); ::encode(dirs, bl); ::encode(dentries, bl); } void decode(bufferlist::iterator &bl) { ::decode(inodes, bl); ::decode(dirs, bl); ::decode(dentries, bl); } }; WRITE_CLASS_ENCODER(realm) map realms; int get_from() { return from; } MCacheExpire() : Message(MSG_MDS_CACHEEXPIRE), from(-1) {} MCacheExpire(int f) : Message(MSG_MDS_CACHEEXPIRE), from(f) { } private: ~MCacheExpire() {} public: virtual const char *get_type_name() const { return "cache_expire";} void add_inode(dirfrag_t r, vinodeno_t vino, unsigned nonce) { realms[r].inodes[vino] = nonce; } void add_dir(dirfrag_t r, dirfrag_t df, unsigned nonce) { realms[r].dirs[df] = nonce; } void add_dentry(dirfrag_t r, dirfrag_t df, const string& dn, snapid_t last, unsigned nonce) { realms[r].dentries[df][pair(dn,last)] = nonce; } void add_realm(dirfrag_t df, realm& r) { if (realms.count(df) == 0) realms[df] = r; else realms[df].merge(r); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(from, p); ::decode(realms, p); } void encode_payload(uint64_t features) { ::encode(from, payload); ::encode(realms, payload); } }; WRITE_CLASS_ENCODER(MCacheExpire::realm) #endif ceph-0.80.11/src/messages/MClientRequest.h0000664000175100017510000001440512623076744022354 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTREQUEST_H #define CEPH_MCLIENTREQUEST_H /** * * MClientRequest - container for a client METADATA request. created/sent by clients. * can be forwarded around between MDS's. * * int client - the originating client * long tid - transaction id, unique among requests for that client. probably just a counter! * -> the MDS passes the Request to the Reply constructor, so this always matches. * * int op - the metadata op code. MDS_OP_RENAME, etc. * int caller_uid, _gid - guess * * fixed size arguments are in a union. * there's also a string argument, for e.g. symlink(). * */ #include "msg/Message.h" #include "include/filepath.h" #include "mds/mdstypes.h" #include #include #include #include // metadata ops. class MClientRequest : public Message { public: struct ceph_mds_request_head head; struct Release { mutable ceph_mds_request_release item; string dname; Release() : item(), dname() {} Release(const ceph_mds_request_release& rel, string name) : item(rel), dname(name) {} void encode(bufferlist& bl) const { item.dname_len = dname.length(); ::encode(item, bl); ::encode_nohead(dname, bl); } void decode(bufferlist::iterator& bl) { ::decode(item, bl); ::decode_nohead(item.dname_len, dname, bl); } }; vector releases; // path arguments filepath path, path2; public: // cons MClientRequest() : Message(CEPH_MSG_CLIENT_REQUEST) {} MClientRequest(int op) : Message(CEPH_MSG_CLIENT_REQUEST) { memset(&head, 0, sizeof(head)); head.op = op; } private: ~MClientRequest() {} public: void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; } epoch_t get_mdsmap_epoch() { return head.mdsmap_epoch; } metareqid_t get_reqid() { // FIXME: for now, assume clients always have 1 incarnation return metareqid_t(get_orig_source(), header.tid); } /*bool open_file_mode_is_readonly() { return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags)); }*/ bool may_write() { return (head.op & CEPH_MDS_OP_WRITE) || (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC))); } int get_flags() const { return head.flags; } bool is_replay() { return get_flags() & CEPH_MDS_FLAG_REPLAY; } // normal fields void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; } void inc_num_fwd() { head.num_fwd = head.num_fwd + 1; } void set_retry_attempt(int a) { head.num_retry = a; } void set_filepath(const filepath& fp) { path = fp; } void set_filepath2(const filepath& fp) { path2 = fp; } void set_string2(const char *s) { path2.set_path(s, 0); } void set_caller_uid(unsigned u) { head.caller_uid = u; } void set_caller_gid(unsigned g) { head.caller_gid = g; } void set_dentry_wanted() { head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY; } void set_replayed_op() { head.flags = head.flags | CEPH_MDS_FLAG_REPLAY; } ceph_tid_t get_oldest_client_tid() const { return head.oldest_client_tid; } int get_num_fwd() const { return head.num_fwd; } int get_retry_attempt() const { return head.num_retry; } int get_op() const { return head.op; } unsigned get_caller_uid() const { return head.caller_uid; } unsigned get_caller_gid() const { return head.caller_gid; } const string& get_path() const { return path.get_path(); } const filepath& get_filepath() const { return path; } const string& get_path2() const { return path2.get_path(); } const filepath& get_filepath2() const { return path2; } int get_dentry_wanted() { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(head, p); ::decode(path, p); ::decode(path2, p); ::decode_nohead(head.num_releases, releases, p); } void encode_payload(uint64_t features) { head.num_releases = releases.size(); ::encode(head, payload); ::encode(path, payload); ::encode(path2, payload); ::encode_nohead(releases, payload); } const char *get_type_name() const { return "creq"; } void print(ostream& out) const { out << "client_request(" << get_orig_source() << ":" << get_tid() << " " << ceph_mds_op_name(get_op()); if (head.op == CEPH_MDS_OP_GETATTR) out << " " << ccap_string(head.args.getattr.mask); if (head.op == CEPH_MDS_OP_SETATTR) { if (head.args.setattr.mask & CEPH_SETATTR_MODE) out << " mode=0" << std::oct << head.args.setattr.mode << std::dec; if (head.args.setattr.mask & CEPH_SETATTR_UID) out << " uid=" << head.args.setattr.uid; if (head.args.setattr.mask & CEPH_SETATTR_GID) out << " gid=" << head.args.setattr.gid; if (head.args.setattr.mask & CEPH_SETATTR_SIZE) out << " size=" << head.args.setattr.size; if (head.args.setattr.mask & CEPH_SETATTR_MTIME) out << " mtime=" << utime_t(head.args.setattr.mtime); if (head.args.setattr.mask & CEPH_SETATTR_ATIME) out << " atime=" << utime_t(head.args.setattr.atime); } if (head.op == CEPH_MDS_OP_SETFILELOCK || head.op == CEPH_MDS_OP_GETFILELOCK) { out << "rule " << (int)head.args.filelock_change.rule << ", type " << (int)head.args.filelock_change.type << ", owner " << head.args.filelock_change.owner << ", pid " << head.args.filelock_change.pid << ", start " << head.args.filelock_change.start << ", length " << head.args.filelock_change.length << ", wait " << (int)head.args.filelock_change.wait; } //if (!get_filepath().empty()) out << " " << get_filepath(); if (!get_filepath2().empty()) out << " " << get_filepath2(); if (head.num_retry) out << " RETRY=" << (int)head.num_retry; if (get_flags() & CEPH_MDS_FLAG_REPLAY) out << " REPLAY"; out << ")"; } }; WRITE_CLASS_ENCODER(MClientRequest::Release) #endif ceph-0.80.11/src/messages/MDiscover.h0000664000175100017510000000515112623076744021341 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDISCOVER_H #define CEPH_MDISCOVER_H #include "msg/Message.h" #include "include/filepath.h" #include #include using namespace std; class MDiscover : public Message { inodeno_t base_ino; // 1 -> root frag_t base_dir_frag; snapid_t snapid; filepath want; // ... [/]need/this/stuff inodeno_t want_ino; bool want_base_dir; bool want_xlocked; public: inodeno_t get_base_ino() { return base_ino; } frag_t get_base_dir_frag() { return base_dir_frag; } snapid_t get_snapid() { return snapid; } filepath& get_want() { return want; } inodeno_t get_want_ino() { return want_ino; } const string& get_dentry(int n) { return want[n]; } bool wants_base_dir() { return want_base_dir; } bool wants_xlocked() { return want_xlocked; } void set_base_dir_frag(frag_t f) { base_dir_frag = f; } MDiscover() : Message(MSG_MDS_DISCOVER) { } MDiscover(inodeno_t base_ino_, frag_t base_frag_, snapid_t s, filepath& want_path_, inodeno_t want_ino_, bool want_base_dir_ = true, bool discover_xlocks_ = false) : Message(MSG_MDS_DISCOVER), base_ino(base_ino_), base_dir_frag(base_frag_), snapid(s), want(want_path_), want_ino(want_ino_), want_base_dir(want_base_dir_), want_xlocked(discover_xlocks_) { } private: ~MDiscover() {} public: const char *get_type_name() const { return "Dis"; } void print(ostream &out) const { out << "discover(" << header.tid << " " << base_ino << "." << base_dir_frag << " " << want; if (want_ino) out << want_ino; out << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(base_ino, p); ::decode(base_dir_frag, p); ::decode(snapid, p); ::decode(want, p); ::decode(want_ino, p); ::decode(want_base_dir, p); ::decode(want_xlocked, p); } void encode_payload(uint64_t features) { ::encode(base_ino, payload); ::encode(base_dir_frag, payload); ::encode(snapid, payload); ::encode(want, payload); ::encode(want_ino, payload); ::encode(want_base_dir, payload); ::encode(want_xlocked, payload); } }; #endif ceph-0.80.11/src/messages/MMDSFindIno.h0000664000175100017510000000213012623076744021447 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSFINDINO_H #define CEPH_MDSFINDINO_H #include "msg/Message.h" #include "include/filepath.h" struct MMDSFindIno : public Message { ceph_tid_t tid; inodeno_t ino; MMDSFindIno() : Message(MSG_MDS_FINDINO) {} MMDSFindIno(ceph_tid_t t, inodeno_t i) : Message(MSG_MDS_FINDINO), tid(t), ino(i) {} const char *get_type_name() const { return "findino"; } void print(ostream &out) const { out << "findino(" << tid << " " << ino << ")"; } void encode_payload(uint64_t features) { ::encode(tid, payload); ::encode(ino, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(tid, p); ::decode(ino, p); } }; #endif ceph-0.80.11/src/messages/MBackfillReserve.h0000664000175100017510000000422512623076744022627 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MBACKFILL_H #define CEPH_MBACKFILL_H #include "msg/Message.h" class MBackfillReserve : public Message { static const int HEAD_VERSION = 3; static const int COMPAT_VERSION = 1; public: spg_t pgid; epoch_t query_epoch; enum { REQUEST = 0, GRANT = 1, REJECT = 2, }; int type; unsigned priority; MBackfillReserve() : Message(MSG_OSD_BACKFILL_RESERVE, HEAD_VERSION, COMPAT_VERSION), query_epoch(0), type(-1), priority(-1) {} MBackfillReserve(int type, spg_t pgid, epoch_t query_epoch, unsigned prio = -1) : Message(MSG_OSD_BACKFILL_RESERVE, HEAD_VERSION, COMPAT_VERSION), pgid(pgid), query_epoch(query_epoch), type(type), priority(prio) {} const char *get_type_name() const { return "MBackfillReserve"; } void print(ostream& out) const { out << "MBackfillReserve "; switch (type) { case REQUEST: out << "REQUEST "; break; case GRANT: out << "GRANT "; break; case REJECT: out << "REJECT "; break; } out << " pgid: " << pgid << ", query_epoch: " << query_epoch; if (type == REQUEST) out << ", prio: " << priority; return; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid.pgid, p); ::decode(query_epoch, p); ::decode(type, p); if (header.version > 1) ::decode(priority, p); else priority = 0; if (header.version >= 3) ::decode(pgid.shard, p); else pgid.shard = ghobject_t::no_shard(); } void encode_payload(uint64_t features) { ::encode(pgid.pgid, payload); ::encode(query_epoch, payload); ::encode(type, payload); ::encode(priority, payload); ::encode(pgid.shard, payload); } }; #endif ceph-0.80.11/src/messages/MMonScrub.h0000664000175100017510000000353312623076744021315 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CEPH_MMONSCRUB_H #define CEPH_MMONSCRUB_H #include "msg/Message.h" #include "mon/mon_types.h" class MMonScrub : public Message { static const int HEAD_VERSION = 1; static const int COMPAT_VERSION = 1; public: typedef enum { OP_SCRUB = 1, // leader->peon: scrub (a range of) keys OP_RESULT = 2, // peon->leader: result of a scrub } op_type_t; static const char *get_opname(op_type_t op) { switch (op) { case OP_SCRUB: return "scrub"; case OP_RESULT: return "result"; default: assert(0 == "unknown op type"); return NULL; } } op_type_t op; version_t version; ScrubResult result; MMonScrub() : Message(MSG_MON_SCRUB, HEAD_VERSION, COMPAT_VERSION) { } MMonScrub(op_type_t op, version_t v) : Message(MSG_MON_SCRUB, HEAD_VERSION, COMPAT_VERSION), op(op), version(v) { } const char *get_type_name() const { return "mon_scrub"; } void print(ostream& out) const { out << "mon_scrub(" << get_opname((op_type_t)op); out << " v " << version; if (op == OP_RESULT) out << " " << result; out << ")"; } void encode_payload(uint64_t features) { uint8_t o = op; ::encode(o, payload); ::encode(version, payload); ::encode(result, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); uint8_t o; ::decode(o, p); op = (op_type_t)o; ::decode(version, p); ::decode(result, p); } }; #endif /* CEPH_MMONSCRUB_H */ ceph-0.80.11/src/messages/MExportDirPrep.h0000664000175100017510000000367712623076744022345 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRPREP_H #define CEPH_MEXPORTDIRPREP_H #include "msg/Message.h" #include "include/types.h" class MExportDirPrep : public Message { dirfrag_t dirfrag; public: bufferlist basedir; list bounds; list traces; private: set<__s32> bystanders; bool b_did_assim; public: dirfrag_t get_dirfrag() { return dirfrag; } list& get_bounds() { return bounds; } set<__s32> &get_bystanders() { return bystanders; } bool did_assim() { return b_did_assim; } void mark_assim() { b_did_assim = true; } MExportDirPrep() { b_did_assim = false; } MExportDirPrep(dirfrag_t df, uint64_t tid) : Message(MSG_MDS_EXPORTDIRPREP), dirfrag(df), b_did_assim(false) { set_tid(tid); } private: ~MExportDirPrep() {} public: const char *get_type_name() const { return "ExP"; } void print(ostream& o) const { o << "export_prep(" << dirfrag << ")"; } void add_bound(dirfrag_t df) { bounds.push_back( df ); } void add_trace(bufferlist& bl) { traces.push_back(bl); } void add_bystander(int who) { bystanders.insert(who); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(basedir, p); ::decode(bounds, p); ::decode(traces, p); ::decode(bystanders, p); } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(basedir, payload); ::encode(bounds, payload); ::encode(traces, payload); ::encode(bystanders, payload); } }; #endif ceph-0.80.11/src/messages/MMonMap.h0000664000175100017510000000235312623076744020753 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONMAP_H #define CEPH_MMONMAP_H #include "include/ceph_features.h" #include "msg/Message.h" #include "mon/MonMap.h" class MMonMap : public Message { public: bufferlist monmapbl; MMonMap() : Message(CEPH_MSG_MON_MAP) { } MMonMap(bufferlist &bl) : Message(CEPH_MSG_MON_MAP) { monmapbl.claim(bl); } private: ~MMonMap() {} public: const char *get_type_name() const { return "mon_map"; } void encode_payload(uint64_t features) { if (monmapbl.length() && (features & CEPH_FEATURE_MONENC) == 0) { // reencode old-format monmap MonMap t; t.decode(monmapbl); monmapbl.clear(); t.encode(monmapbl, features); } ::encode(monmapbl, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(monmapbl, p); } }; #endif ceph-0.80.11/src/messages/MTimeCheck.h0000664000175100017510000000370412623076744021421 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MTIMECHECK_H #define CEPH_MTIMECHECK_H struct MTimeCheck : public Message { static const int HEAD_VERSION = 1; enum { OP_PING = 1, OP_PONG = 2, OP_REPORT = 3, }; int op; version_t epoch; version_t round; utime_t timestamp; map skews; map latencies; MTimeCheck() : Message(MSG_TIMECHECK, HEAD_VERSION) { } MTimeCheck(int op) : Message(MSG_TIMECHECK, HEAD_VERSION), op(op) { } private: ~MTimeCheck() { } public: const char *get_type_name() const { return "time_check"; } const char *get_op_name() const { switch (op) { case OP_PING: return "ping"; case OP_PONG: return "pong"; case OP_REPORT: return "report"; } return "???"; } void print(ostream &o) const { o << "time_check( " << get_op_name() << " e " << epoch << " r " << round; if (op == OP_PONG) { o << " ts " << timestamp; } else if (op == OP_REPORT) { o << " #skews " << skews.size() << " #latencies " << latencies.size(); } o << " )"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(op, p); ::decode(epoch, p); ::decode(round, p); ::decode(timestamp, p); ::decode(skews, p); ::decode(latencies, p); } void encode_payload(uint64_t features) { ::encode(op, payload); ::encode(epoch, payload); ::encode(round, payload); ::encode(timestamp, payload); ::encode(skews, payload); ::encode(latencies, payload); } }; #endif /* CEPH_MTIMECHECK_H */ ceph-0.80.11/src/messages/MMonPaxos.h0000664000175100017510000000751012623076744021330 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONPAXOS_H #define CEPH_MMONPAXOS_H #include "messages/PaxosServiceMessage.h" #include "mon/mon_types.h" #include "include/ceph_features.h" class MMonPaxos : public Message { static const int HEAD_VERSION = 3; static const int COMPAT_VERSION = 3; public: // op types const static int OP_COLLECT = 1; // proposer: propose round const static int OP_LAST = 2; // voter: accept proposed round const static int OP_BEGIN = 3; // proposer: value proposed for this round const static int OP_ACCEPT = 4; // voter: accept propsed value const static int OP_COMMIT = 5; // proposer: notify learners of agreed value const static int OP_LEASE = 6; // leader: extend peon lease const static int OP_LEASE_ACK = 7; // peon: lease ack const static char *get_opname(int op) { switch (op) { case OP_COLLECT: return "collect"; case OP_LAST: return "last"; case OP_BEGIN: return "begin"; case OP_ACCEPT: return "accept"; case OP_COMMIT: return "commit"; case OP_LEASE: return "lease"; case OP_LEASE_ACK: return "lease_ack"; default: assert(0); return 0; } } epoch_t epoch; // monitor epoch __s32 op; // paxos op version_t first_committed; // i've committed to version_t last_committed; // i've committed to version_t pn_from; // i promise to accept after version_t pn; // with with proposal version_t uncommitted_pn; // previous pn, if we are a LAST with an uncommitted value utime_t lease_timestamp; utime_t sent_timestamp; version_t latest_version; bufferlist latest_value; map values; MMonPaxos() : Message(MSG_MON_PAXOS, HEAD_VERSION, COMPAT_VERSION) { } MMonPaxos(epoch_t e, int o, utime_t now) : Message(MSG_MON_PAXOS, HEAD_VERSION, COMPAT_VERSION), epoch(e), op(o), first_committed(0), last_committed(0), pn_from(0), pn(0), uncommitted_pn(0), sent_timestamp(now), latest_version(0) { } private: ~MMonPaxos() {} public: const char *get_type_name() const { return "paxos"; } void print(ostream& out) const { out << "paxos(" << get_opname(op) << " lc " << last_committed << " fc " << first_committed << " pn " << pn << " opn " << uncommitted_pn; if (latest_version) out << " latest " << latest_version << " (" << latest_value.length() << " bytes)"; out << ")"; } void encode_payload(uint64_t features) { if ((features & CEPH_FEATURE_MONCLOCKCHECK) == 0) header.version = 0; ::encode(epoch, payload); ::encode(op, payload); ::encode(first_committed, payload); ::encode(last_committed, payload); ::encode(pn_from, payload); ::encode(pn, payload); ::encode(uncommitted_pn, payload); ::encode(lease_timestamp, payload); if (features & CEPH_FEATURE_MONCLOCKCHECK) ::encode(sent_timestamp, payload); ::encode(latest_version, payload); ::encode(latest_value, payload); ::encode(values, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); ::decode(op, p); ::decode(first_committed, p); ::decode(last_committed, p); ::decode(pn_from, p); ::decode(pn, p); ::decode(uncommitted_pn, p); ::decode(lease_timestamp, p); if (header.version >= 1) ::decode(sent_timestamp, p); ::decode(latest_version, p); ::decode(latest_value, p); ::decode(values, p); } }; #endif ceph-0.80.11/src/messages/MClientLease.h0000664000175100017510000000423112623076744021751 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTLEASE_H #define CEPH_MCLIENTLEASE_H #include "msg/Message.h" struct MClientLease : public Message { struct ceph_mds_lease h; string dname; int get_action() const { return h.action; } ceph_seq_t get_seq() const { return h.seq; } int get_mask() const { return h.mask; } inodeno_t get_ino() const { return inodeno_t(h.ino); } snapid_t get_first() const { return snapid_t(h.first); } snapid_t get_last() const { return snapid_t(h.last); } MClientLease() : Message(CEPH_MSG_CLIENT_LEASE) {} MClientLease(int ac, ceph_seq_t seq, int m, uint64_t i, uint64_t sf, uint64_t sl) : Message(CEPH_MSG_CLIENT_LEASE) { h.action = ac; h.seq = seq; h.mask = m; h.ino = i; h.first = sf; h.last = sl; h.duration_ms = 0; } MClientLease(int ac, ceph_seq_t seq, int m, uint64_t i, uint64_t sf, uint64_t sl, const string& d) : Message(CEPH_MSG_CLIENT_LEASE), dname(d) { h.action = ac; h.seq = seq; h.mask = m; h.ino = i; h.first = sf; h.last = sl; h.duration_ms = 0; } private: ~MClientLease() {} public: const char *get_type_name() const { return "client_lease"; } void print(ostream& out) const { out << "client_lease(a=" << ceph_lease_op_name(get_action()) << " seq " << get_seq() << " mask " << get_mask(); out << " " << get_ino(); if (h.last != CEPH_NOSNAP) out << " [" << snapid_t(h.first) << "," << snapid_t(h.last) << "]"; if (dname.length()) out << "/" << dname; out << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(h, p); ::decode(dname, p); } virtual void encode_payload(uint64_t features) { ::encode(h, payload); ::encode(dname, payload); } }; #endif ceph-0.80.11/src/messages/MOSDPGLog.h0000664000175100017510000000532012623076744021077 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGLOG_H #define CEPH_MOSDPGLOG_H #include "msg/Message.h" class MOSDPGLog : public Message { static const int HEAD_VERSION = 4; static const int COMPAT_VERSION = 2; epoch_t epoch; /// query_epoch is the epoch of the query being responded to, or /// the current epoch if this is not being sent in response to a /// query. This allows the recipient to disregard responses to old /// queries. epoch_t query_epoch; public: shard_id_t to; shard_id_t from; pg_info_t info; pg_log_t log; pg_missing_t missing; pg_interval_map_t past_intervals; epoch_t get_epoch() { return epoch; } spg_t get_pgid() { return spg_t(info.pgid.pgid, to); } epoch_t get_query_epoch() { return query_epoch; } MOSDPGLog() : Message(MSG_OSD_PG_LOG, HEAD_VERSION, COMPAT_VERSION) { } MOSDPGLog(shard_id_t to, shard_id_t from, version_t mv, pg_info_t& i) : Message(MSG_OSD_PG_LOG, HEAD_VERSION, COMPAT_VERSION), epoch(mv), query_epoch(mv), to(to), from(from), info(i) { } MOSDPGLog(shard_id_t to, shard_id_t from, version_t mv, pg_info_t& i, epoch_t query_epoch) : Message(MSG_OSD_PG_LOG, HEAD_VERSION, COMPAT_VERSION), epoch(mv), query_epoch(query_epoch), to(to), from(from), info(i) { } private: ~MOSDPGLog() {} public: const char *get_type_name() const { return "PGlog"; } void print(ostream& out) const { out << "pg_log(" << info.pgid << " epoch " << epoch << " log " << log << " query_epoch " << query_epoch << ")"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); ::encode(info, payload); ::encode(log, payload); ::encode(missing, payload); ::encode(query_epoch, payload); ::encode(past_intervals, payload); ::encode(to, payload); ::encode(from, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); ::decode(info, p); log.decode(p, info.pgid.pool()); missing.decode(p, info.pgid.pool()); if (header.version >= 2) { ::decode(query_epoch, p); } if (header.version >= 3) { ::decode(past_intervals, p); } if (header.version >= 4) { ::decode(to, p); ::decode(from, p); } else { to = ghobject_t::NO_SHARD; from = ghobject_t::NO_SHARD; } } }; #endif ceph-0.80.11/src/messages/MMDSMap.h0000664000175100017510000000456012623076744020647 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSMAP_H #define CEPH_MMDSMAP_H #include "msg/Message.h" #include "mds/MDSMap.h" #include "include/ceph_features.h" #include class MMDSMap : public Message { public: /* map maps; map incremental_maps; epoch_t get_first() { epoch_t e = 0; map::iterator i = maps.begin(); if (i != maps.end()) e = i->first; i = incremental_maps.begin(); if (i != incremental_maps.end() && (e == 0 || i->first < e)) e = i->first; return e; } epoch_t get_last() { epoch_t e = 0; map::reverse_iterator i = maps.rbegin(); if (i != maps.rend()) e = i->first; i = incremental_maps.rbegin(); if (i != incremental_maps.rend() && (e == 0 || i->first > e)) e = i->first; return e; } */ uuid_d fsid; epoch_t epoch; bufferlist encoded; version_t get_epoch() const { return epoch; } bufferlist& get_encoded() { return encoded; } MMDSMap() : Message(CEPH_MSG_MDS_MAP) {} MMDSMap(const uuid_d &f, MDSMap *mm) : Message(CEPH_MSG_MDS_MAP), fsid(f) { epoch = mm->get_epoch(); mm->encode(encoded, -1); // we will reencode with fewer features as necessary } private: ~MMDSMap() {} public: const char *get_type_name() const { return "mdsmap"; } void print(ostream& out) const { out << "mdsmap(e " << epoch << ")"; } // marshalling void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(fsid, p); ::decode(epoch, p); ::decode(encoded, p); } void encode_payload(uint64_t features) { ::encode(fsid, payload); ::encode(epoch, payload); if ((features & CEPH_FEATURE_PGID64) == 0 || (features & CEPH_FEATURE_MDSENC) == 0) { // reencode for old clients. MDSMap m; m.decode(encoded); encoded.clear(); m.encode(encoded, features); } ::encode(encoded, payload); } }; #endif ceph-0.80.11/src/messages/MOSDMap.h0000664000175100017510000000750212623076744020650 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDMAP_H #define CEPH_MOSDMAP_H #include "msg/Message.h" #include "osd/OSDMap.h" #include "include/ceph_features.h" class MOSDMap : public Message { static const int HEAD_VERSION = 3; public: uuid_d fsid; map maps; map incremental_maps; epoch_t oldest_map, newest_map; epoch_t get_first() const { epoch_t e = 0; map::const_iterator i = maps.begin(); if (i != maps.end()) e = i->first; i = incremental_maps.begin(); if (i != incremental_maps.end() && (e == 0 || i->first < e)) e = i->first; return e; } epoch_t get_last() const { epoch_t e = 0; map::const_reverse_iterator i = maps.rbegin(); if (i != maps.rend()) e = i->first; i = incremental_maps.rbegin(); if (i != incremental_maps.rend() && (e == 0 || i->first > e)) e = i->first; return e; } epoch_t get_oldest() { return oldest_map; } epoch_t get_newest() { return newest_map; } MOSDMap() : Message(CEPH_MSG_OSD_MAP, HEAD_VERSION) { } MOSDMap(const uuid_d &f, OSDMap *oc=0) : Message(CEPH_MSG_OSD_MAP, HEAD_VERSION), fsid(f), oldest_map(0), newest_map(0) { if (oc) oc->encode(maps[oc->get_epoch()]); } private: ~MOSDMap() {} public: // marshalling void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(fsid, p); ::decode(incremental_maps, p); ::decode(maps, p); if (header.version >= 2) { ::decode(oldest_map, p); ::decode(newest_map, p); } else { oldest_map = 0; newest_map = 0; } } void encode_payload(uint64_t features) { ::encode(fsid, payload); if ((features & CEPH_FEATURE_PGID64) == 0 || (features & CEPH_FEATURE_PGPOOL3) == 0 || (features & CEPH_FEATURE_OSDENC) == 0 || (features & CEPH_FEATURE_OSDMAP_ENC) == 0) { if ((features & CEPH_FEATURE_PGID64) == 0 || (features & CEPH_FEATURE_PGPOOL3) == 0) header.version = 1; // old old_client version else if ((features & CEPH_FEATURE_OSDENC) == 0) header.version = 2; // old pg_pool_t // reencode maps using old format // // FIXME: this can probably be done more efficiently higher up // the stack, or maybe replaced with something that only // includes the pools the client cares about. for (map::iterator p = incremental_maps.begin(); p != incremental_maps.end(); ++p) { OSDMap::Incremental inc; bufferlist::iterator q = p->second.begin(); inc.decode(q); p->second.clear(); if (inc.fullmap.length()) { // embedded full map? OSDMap m; m.decode(inc.fullmap); inc.fullmap.clear(); m.encode(inc.fullmap, features); } inc.encode(p->second, features); } for (map::iterator p = maps.begin(); p != maps.end(); ++p) { OSDMap m; m.decode(p->second); p->second.clear(); m.encode(p->second, features); } } ::encode(incremental_maps, payload); ::encode(maps, payload); if (header.version >= 2) { ::encode(oldest_map, payload); ::encode(newest_map, payload); } } const char *get_type_name() const { return "omap"; } void print(ostream& out) const { out << "osd_map(" << get_first() << ".." << get_last(); if (oldest_map || newest_map) out << " src has " << oldest_map << ".." << newest_map; out << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDSubOpReply.h0000664000175100017510000001006412623076744022174 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDSUBOPREPLY_H #define CEPH_MOSDSUBOPREPLY_H #include "msg/Message.h" #include "MOSDSubOp.h" #include "os/ObjectStore.h" /* * OSD op reply * * oid - object id * op - OSD_OP_DELETE, etc. * */ class MOSDSubOpReply : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: epoch_t map_epoch; // subop metadata osd_reqid_t reqid; pg_shard_t from; spg_t pgid; hobject_t poid; vector ops; // result __u8 ack_type; int32_t result; // piggybacked osd state eversion_t last_complete_ondisk; osd_peer_stat_t peer_stat; map attrset; virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(map_epoch, p); ::decode(reqid, p); ::decode(pgid.pgid, p); ::decode(poid, p); unsigned num_ops; ::decode(num_ops, p); ops.resize(num_ops); for (unsigned i = 0; i < num_ops; i++) { ::decode(ops[i].op, p); } ::decode(ack_type, p); ::decode(result, p); ::decode(last_complete_ondisk, p); ::decode(peer_stat, p); ::decode(attrset, p); if (!poid.is_max() && poid.pool == -1) poid.pool = pgid.pool(); if (header.version >= 2) { ::decode(from, p); ::decode(pgid.shard, p); } else { from = pg_shard_t( get_source().num(), ghobject_t::NO_SHARD); pgid.shard = ghobject_t::NO_SHARD; } } virtual void encode_payload(uint64_t features) { ::encode(map_epoch, payload); ::encode(reqid, payload); ::encode(pgid.pgid, payload); ::encode(poid, payload); __u32 num_ops = ops.size(); ::encode(num_ops, payload); for (unsigned i = 0; i < ops.size(); i++) { ::encode(ops[i].op, payload); } ::encode(ack_type, payload); ::encode(result, payload); ::encode(last_complete_ondisk, payload); ::encode(peer_stat, payload); ::encode(attrset, payload); ::encode(from, payload); ::encode(pgid.shard, payload); } epoch_t get_map_epoch() { return map_epoch; } spg_t get_pg() { return pgid; } hobject_t get_poid() { return poid; } int get_ack_type() { return ack_type; } bool is_ondisk() { return ack_type & CEPH_OSD_FLAG_ONDISK; } bool is_onnvram() { return ack_type & CEPH_OSD_FLAG_ONNVRAM; } int get_result() { return result; } void set_last_complete_ondisk(eversion_t v) { last_complete_ondisk = v; } eversion_t get_last_complete_ondisk() { return last_complete_ondisk; } void set_peer_stat(const osd_peer_stat_t& stat) { peer_stat = stat; } const osd_peer_stat_t& get_peer_stat() { return peer_stat; } void set_attrset(map &as) { attrset = as; } map& get_attrset() { return attrset; } public: MOSDSubOpReply( MOSDSubOp *req, pg_shard_t from, int result_, epoch_t e, int at) : Message(MSG_OSD_SUBOPREPLY, HEAD_VERSION, COMPAT_VERSION), map_epoch(e), reqid(req->reqid), from(from), pgid(req->pgid.pgid, req->from.shard), poid(req->poid), ops(req->ops), ack_type(at), result(result_) { memset(&peer_stat, 0, sizeof(peer_stat)); set_tid(req->get_tid()); } MOSDSubOpReply() : Message(MSG_OSD_SUBOPREPLY) {} private: ~MOSDSubOpReply() {} public: const char *get_type_name() const { return "osd_op_reply"; } void print(ostream& out) const { out << "osd_sub_op_reply(" << reqid << " " << pgid << " " << poid << " " << ops; if (ack_type & CEPH_OSD_FLAG_ONDISK) out << " ondisk"; if (ack_type & CEPH_OSD_FLAG_ONNVRAM) out << " onnvram"; if (ack_type & CEPH_OSD_FLAG_ACK) out << " ack"; out << ", result = " << result; out << ")"; } }; #endif ceph-0.80.11/src/messages/MClientRequestForward.h0000664000175100017510000000340712623076744023701 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTREQUESTFORWARD_H #define CEPH_MCLIENTREQUESTFORWARD_H class MClientRequestForward : public Message { int32_t dest_mds; int32_t num_fwd; bool client_must_resend; public: MClientRequestForward() : Message(CEPH_MSG_CLIENT_REQUEST_FORWARD), dest_mds(-1), num_fwd(-1), client_must_resend(false) {} MClientRequestForward(ceph_tid_t t, int dm, int nf, bool cmr) : Message(CEPH_MSG_CLIENT_REQUEST_FORWARD), dest_mds(dm), num_fwd(nf), client_must_resend(cmr) { assert(client_must_resend); header.tid = t; } private: ~MClientRequestForward() {} public: int get_dest_mds() { return dest_mds; } int get_num_fwd() { return num_fwd; } bool must_resend() { return client_must_resend; } const char *get_type_name() const { return "client_request_forward"; } void print(ostream& o) const { o << "client_request_forward(" << get_tid() << " to mds." << dest_mds << " num_fwd=" << num_fwd << (client_must_resend ? " client_must_resend":"") << ")"; } void encode_payload(uint64_t features) { ::encode(dest_mds, payload); ::encode(num_fwd, payload); ::encode(client_must_resend, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dest_mds, p); ::decode(num_fwd, p); ::decode(client_must_resend, p); } }; #endif ceph-0.80.11/src/messages/MStatfs.h0000664000175100017510000000234112623076744021025 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MSTATFS_H #define CEPH_MSTATFS_H #include /* or */ #include "messages/PaxosServiceMessage.h" class MStatfs : public PaxosServiceMessage { public: uuid_d fsid; MStatfs() : PaxosServiceMessage(CEPH_MSG_STATFS, 0) {} MStatfs(const uuid_d& f, ceph_tid_t t, version_t v) : PaxosServiceMessage(CEPH_MSG_STATFS, v), fsid(f) { set_tid(t); } private: ~MStatfs() {} public: const char *get_type_name() const { return "statfs"; } void print(ostream& out) const { out << "statfs(" << get_tid() << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); } }; #endif ceph-0.80.11/src/messages/MWatchNotify.h0000664000175100017510000000432012623076744022017 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MWATCHNOTIFY_H #define CEPH_MWATCHNOTIFY_H #include "msg/Message.h" class MWatchNotify : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: uint64_t cookie; ///< client unique id for this watch or notify uint64_t ver; ///< unused uint64_t notify_id; ///< osd unique id for a notify notification uint8_t opcode; ///< always WATCH_NOTIFY bufferlist bl; ///< notify payload (osd->client) int32_t return_code; ///< notify result (osd->client) MWatchNotify() : Message(CEPH_MSG_WATCH_NOTIFY, HEAD_VERSION, COMPAT_VERSION) { } MWatchNotify(uint64_t c, uint64_t v, uint64_t i, uint8_t o, bufferlist b) : Message(CEPH_MSG_WATCH_NOTIFY, HEAD_VERSION, COMPAT_VERSION), cookie(c), ver(v), notify_id(i), opcode(o), bl(b), return_code(0) { } private: ~MWatchNotify() {} public: void decode_payload() { uint8_t msg_ver; bufferlist::iterator p = payload.begin(); ::decode(msg_ver, p); ::decode(opcode, p); ::decode(cookie, p); ::decode(ver, p); ::decode(notify_id, p); if (msg_ver >= 1) ::decode(bl, p); if (header.version >= 2) ::decode(return_code, p); else return_code = 0; } void encode_payload(uint64_t features) { uint8_t msg_ver = 1; ::encode(msg_ver, payload); ::encode(opcode, payload); ::encode(cookie, payload); ::encode(ver, payload); ::encode(notify_id, payload); ::encode(bl, payload); ::encode(return_code, payload); } const char *get_type_name() const { return "watch-notify"; } void print(ostream& out) const { out << "watch-notify(c=" << cookie << " v=" << ver << " i=" << notify_id << " opcode=" << (int)opcode << " r = " << return_code << ")"; } }; #endif ceph-0.80.11/src/messages/MMDSFindInoReply.h0000664000175100017510000000216512623076744022473 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSFINDINOREPLY_H #define CEPH_MDSFINDINOREPLY_H #include "msg/Message.h" #include "include/filepath.h" struct MMDSFindInoReply : public Message { ceph_tid_t tid; filepath path; MMDSFindInoReply() : Message(MSG_MDS_FINDINOREPLY) {} MMDSFindInoReply(ceph_tid_t t) : Message(MSG_MDS_FINDINOREPLY), tid(t) {} const char *get_type_name() const { return "findinoreply"; } void print(ostream &out) const { out << "findinoreply(" << tid << " " << path << ")"; } void encode_payload(uint64_t features) { ::encode(tid, payload); ::encode(path, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(tid, p); ::decode(path, p); } }; #endif ceph-0.80.11/src/messages/MMDSCacheRejoin.h0000664000175100017510000002557612623076744022316 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSCACHEREJOIN_H #define CEPH_MMDSCACHEREJOIN_H #include "msg/Message.h" #include "include/types.h" #include "mds/CInode.h" #include "mds/CDir.h" // sent from replica to auth class MMDSCacheRejoin : public Message { static const int HEAD_VERSION = 1; static const int COMPAT_VERSION = 1; public: static const int OP_WEAK = 1; // replica -> auth, i exist, + maybe open files. static const int OP_STRONG = 2; // replica -> auth, i exist, + open files and lock state. static const int OP_ACK = 3; // auth -> replica, here is your lock state. static const int OP_MISSING = 5; // auth -> replica, i am missing these items static const int OP_FULL = 6; // replica -> auth, here is the full object. static const char *get_opname(int op) { switch (op) { case OP_WEAK: return "weak"; case OP_STRONG: return "strong"; case OP_ACK: return "ack"; case OP_MISSING: return "missing"; case OP_FULL: return "full"; default: assert(0); return 0; } } // -- types -- struct inode_strong { uint32_t nonce; int32_t caps_wanted; int32_t filelock, nestlock, dftlock; inode_strong() {} inode_strong(int n, int cw, int dl, int nl, int dftl) : nonce(n), caps_wanted(cw), filelock(dl), nestlock(nl), dftlock(dftl) { } void encode(bufferlist &bl) const { ::encode(nonce, bl); ::encode(caps_wanted, bl); ::encode(filelock, bl); ::encode(nestlock, bl); ::encode(dftlock, bl); } void decode(bufferlist::iterator &bl) { ::decode(nonce, bl); ::decode(caps_wanted, bl); ::decode(filelock, bl); ::decode(nestlock, bl); ::decode(dftlock, bl); } }; WRITE_CLASS_ENCODER(inode_strong) struct dirfrag_strong { uint32_t nonce; int8_t dir_rep; dirfrag_strong() {} dirfrag_strong(int n, int dr) : nonce(n), dir_rep(dr) {} void encode(bufferlist &bl) const { ::encode(nonce, bl); ::encode(dir_rep, bl); } void decode(bufferlist::iterator &bl) { ::decode(nonce, bl); ::decode(dir_rep, bl); } }; WRITE_CLASS_ENCODER(dirfrag_strong) struct dn_strong { snapid_t first; inodeno_t ino; inodeno_t remote_ino; unsigned char remote_d_type; uint32_t nonce; int32_t lock; dn_strong() : ino(0), remote_ino(0), remote_d_type(0), nonce(0), lock(0) {} dn_strong(snapid_t f, inodeno_t pi, inodeno_t ri, unsigned char rdt, int n, int l) : first(f), ino(pi), remote_ino(ri), remote_d_type(rdt), nonce(n), lock(l) {} bool is_primary() { return ino > 0; } bool is_remote() { return remote_ino > 0; } bool is_null() { return ino == 0 && remote_ino == 0; } void encode(bufferlist &bl) const { ::encode(first, bl); ::encode(ino, bl); ::encode(remote_ino, bl); ::encode(remote_d_type, bl); ::encode(nonce, bl); ::encode(lock, bl); } void decode(bufferlist::iterator &bl) { ::decode(first, bl); ::decode(ino, bl); ::decode(remote_ino, bl); ::decode(remote_d_type, bl); ::decode(nonce, bl); ::decode(lock, bl); } }; WRITE_CLASS_ENCODER(dn_strong) struct dn_weak { snapid_t first; inodeno_t ino; dn_weak() : ino(0) {} dn_weak(snapid_t f, inodeno_t pi) : first(f), ino(pi) {} void encode(bufferlist &bl) const { ::encode(first, bl); ::encode(ino, bl); } void decode(bufferlist::iterator &bl) { ::decode(first, bl); ::decode(ino, bl); } }; WRITE_CLASS_ENCODER(dn_weak) // -- data -- int32_t op; struct lock_bls { bufferlist file, nest, dft; void encode(bufferlist& bl) const { ::encode(file, bl); ::encode(nest, bl); ::encode(dft, bl); } void decode(bufferlist::iterator& bl) { ::decode(file, bl); ::decode(nest, bl); ::decode(dft, bl); } }; WRITE_CLASS_ENCODER(lock_bls) // weak map > weak; set weak_dirfrags; set weak_inodes; map inode_scatterlocks; // strong map strong_dirfrags; map > strong_dentries; map strong_inodes; // open map > cap_exports; map client_map; bufferlist imported_caps; // full bufferlist inode_base; bufferlist inode_locks; map dirfrag_bases; // authpins, xlocks struct slave_reqid { metareqid_t reqid; __u32 attempt; slave_reqid() : attempt(0) {} slave_reqid(const metareqid_t& r, __u32 a) : reqid(r), attempt(a) {} void encode(bufferlist& bl) const { ::encode(reqid, bl); ::encode(attempt, bl); } void decode(bufferlist::iterator& bl) { ::decode(reqid, bl); ::decode(attempt, bl); } }; map > authpinned_inodes; map frozen_authpin_inodes; map > xlocked_inodes; map > > wrlocked_inodes; map > > authpinned_dentries; map > xlocked_dentries; MMDSCacheRejoin() : Message(MSG_MDS_CACHEREJOIN, HEAD_VERSION, COMPAT_VERSION) {} MMDSCacheRejoin(int o) : Message(MSG_MDS_CACHEREJOIN, HEAD_VERSION, COMPAT_VERSION), op(o) {} private: ~MMDSCacheRejoin() {} public: const char *get_type_name() const { return "cache_rejoin"; } void print(ostream& out) const { out << "cache_rejoin " << get_opname(op); } // -- builders -- // inodes void add_weak_inode(vinodeno_t i) { weak_inodes.insert(i); } void add_strong_inode(vinodeno_t i, int n, int cw, int dl, int nl, int dftl) { strong_inodes[i] = inode_strong(n, cw, dl, nl, dftl); } void add_inode_locks(CInode *in, __u32 nonce, bufferlist& bl) { ::encode(in->inode.ino, inode_locks); ::encode(in->last, inode_locks); ::encode(nonce, inode_locks); ::encode(bl, inode_locks); } void add_inode_base(CInode *in) { ::encode(in->inode.ino, inode_base); ::encode(in->last, inode_base); bufferlist bl; in->_encode_base(bl); ::encode(bl, inode_base); } void add_inode_authpin(vinodeno_t ino, const metareqid_t& ri, __u32 attempt) { authpinned_inodes[ino].push_back(slave_reqid(ri, attempt)); } void add_inode_frozen_authpin(vinodeno_t ino, const metareqid_t& ri, __u32 attempt) { frozen_authpin_inodes[ino] = slave_reqid(ri, attempt); } void add_inode_xlock(vinodeno_t ino, int lt, const metareqid_t& ri, __u32 attempt) { xlocked_inodes[ino][lt] = slave_reqid(ri, attempt); } void add_inode_wrlock(vinodeno_t ino, int lt, const metareqid_t& ri, __u32 attempt) { wrlocked_inodes[ino][lt].push_back(slave_reqid(ri, attempt)); } void add_scatterlock_state(CInode *in) { if (inode_scatterlocks.count(in->ino())) return; // already added this one in->encode_lock_state(CEPH_LOCK_IFILE, inode_scatterlocks[in->ino()].file); in->encode_lock_state(CEPH_LOCK_INEST, inode_scatterlocks[in->ino()].nest); in->encode_lock_state(CEPH_LOCK_IDFT, inode_scatterlocks[in->ino()].dft); } // dirfrags void add_strong_dirfrag(dirfrag_t df, int n, int dr) { strong_dirfrags[df] = dirfrag_strong(n, dr); } void add_dirfrag_base(CDir *dir) { bufferlist& bl = dirfrag_bases[dir->dirfrag()]; dir->_encode_base(bl); } // dentries void add_weak_dirfrag(dirfrag_t df) { weak_dirfrags.insert(df); } void add_weak_dentry(inodeno_t dirino, const string& dname, snapid_t last, dn_weak& dnw) { weak[dirino][string_snap_t(dname, last)] = dnw; } void add_weak_primary_dentry(inodeno_t dirino, const string& dname, snapid_t first, snapid_t last, inodeno_t ino) { weak[dirino][string_snap_t(dname, last)] = dn_weak(first, ino); } void add_strong_dentry(dirfrag_t df, const string& dname, snapid_t first, snapid_t last, inodeno_t pi, inodeno_t ri, unsigned char rdt, int n, int ls) { strong_dentries[df][string_snap_t(dname, last)] = dn_strong(first, pi, ri, rdt, n, ls); } void add_dentry_authpin(dirfrag_t df, const string& dname, snapid_t last, const metareqid_t& ri, __u32 attempt) { authpinned_dentries[df][string_snap_t(dname, last)].push_back(slave_reqid(ri, attempt)); } void add_dentry_xlock(dirfrag_t df, const string& dname, snapid_t last, const metareqid_t& ri, __u32 attempt) { xlocked_dentries[df][string_snap_t(dname, last)] = slave_reqid(ri, attempt); } // -- encoding -- void encode_payload(uint64_t features) { ::encode(op, payload); ::encode(strong_inodes, payload); ::encode(inode_base, payload); ::encode(inode_locks, payload); ::encode(inode_scatterlocks, payload); ::encode(authpinned_inodes, payload); ::encode(frozen_authpin_inodes, payload); ::encode(xlocked_inodes, payload); ::encode(wrlocked_inodes, payload); ::encode(cap_exports, payload); ::encode(client_map, payload); ::encode(imported_caps, payload); ::encode(strong_dirfrags, payload); ::encode(dirfrag_bases, payload); ::encode(weak, payload); ::encode(weak_dirfrags, payload); ::encode(weak_inodes, payload); ::encode(strong_dentries, payload); ::encode(authpinned_dentries, payload); ::encode(xlocked_dentries, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(op, p); ::decode(strong_inodes, p); ::decode(inode_base, p); ::decode(inode_locks, p); ::decode(inode_scatterlocks, p); ::decode(authpinned_inodes, p); ::decode(frozen_authpin_inodes, p); ::decode(xlocked_inodes, p); ::decode(wrlocked_inodes, p); ::decode(cap_exports, p); ::decode(client_map, p); ::decode(imported_caps, p); ::decode(strong_dirfrags, p); ::decode(dirfrag_bases, p); ::decode(weak, p); ::decode(weak_dirfrags, p); ::decode(weak_inodes, p); ::decode(strong_dentries, p); ::decode(authpinned_dentries, p); ::decode(xlocked_dentries, p); } }; WRITE_CLASS_ENCODER(MMDSCacheRejoin::inode_strong) WRITE_CLASS_ENCODER(MMDSCacheRejoin::dirfrag_strong) WRITE_CLASS_ENCODER(MMDSCacheRejoin::dn_strong) WRITE_CLASS_ENCODER(MMDSCacheRejoin::dn_weak) WRITE_CLASS_ENCODER(MMDSCacheRejoin::lock_bls) WRITE_CLASS_ENCODER(MMDSCacheRejoin::slave_reqid) inline ostream& operator<<(ostream& out, const MMDSCacheRejoin::slave_reqid& r) { return out << r.reqid << '.' << r.attempt; } #endif ceph-0.80.11/src/messages/MMonCommandAck.h0000664000175100017510000000260012623076744022226 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONCOMMANDACK_H #define CEPH_MMONCOMMANDACK_H #include "messages/PaxosServiceMessage.h" class MMonCommandAck : public PaxosServiceMessage { public: vector cmd; __s32 r; string rs; MMonCommandAck() : PaxosServiceMessage(MSG_MON_COMMAND_ACK, 0) {} MMonCommandAck(vector& c, int _r, string s, version_t v) : PaxosServiceMessage(MSG_MON_COMMAND_ACK, v), cmd(c), r(_r), rs(s) { } private: ~MMonCommandAck() {} public: const char *get_type_name() const { return "mon_command"; } void print(ostream& o) const { o << "mon_command_ack(" << cmd << "=" << r << " " << rs << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(r, payload); ::encode(rs, payload); ::encode(cmd, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(r, p); ::decode(rs, p); ::decode(cmd, p); } }; #endif ceph-0.80.11/src/messages/MMonElection.h0000664000175100017510000000621012623076744021774 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONELECTION_H #define CEPH_MMONELECTION_H #include "msg/Message.h" #include "mon/MonMap.h" class MMonElection : public Message { static const int HEAD_VERSION = 5; static const int COMPAT_VERSION = 2; public: static const int OP_PROPOSE = 1; static const int OP_ACK = 2; static const int OP_NAK = 3; static const int OP_VICTORY = 4; static const char *get_opname(int o) { switch (o) { case OP_PROPOSE: return "propose"; case OP_ACK: return "ack"; case OP_NAK: return "nak"; case OP_VICTORY: return "victory"; default: assert(0); return 0; } } uuid_d fsid; int32_t op; epoch_t epoch; bufferlist monmap_bl; set quorum; uint64_t quorum_features; bufferlist sharing_bl; /* the following were both used in the next branch for a while * on user cluster, so we've left them in for compatibility. */ version_t defunct_one; version_t defunct_two; MMonElection() : Message(MSG_MON_ELECTION, HEAD_VERSION, COMPAT_VERSION), op(0), epoch(0), quorum_features(0), defunct_one(0), defunct_two(0) { } MMonElection(int o, epoch_t e, MonMap *m) : Message(MSG_MON_ELECTION, HEAD_VERSION, COMPAT_VERSION), fsid(m->fsid), op(o), epoch(e), quorum_features(0), defunct_one(0), defunct_two(0) { // encode using full feature set; we will reencode for dest later, // if necessary m->encode(monmap_bl, CEPH_FEATURES_ALL); } private: ~MMonElection() {} public: const char *get_type_name() const { return "election"; } void print(ostream& out) const { out << "election(" << fsid << " " << get_opname(op) << " " << epoch << ")"; } void encode_payload(uint64_t features) { if (monmap_bl.length() && (features != CEPH_FEATURES_ALL)) { // reencode old-format monmap MonMap t; t.decode(monmap_bl); monmap_bl.clear(); t.encode(monmap_bl, features); } ::encode(fsid, payload); ::encode(op, payload); ::encode(epoch, payload); ::encode(monmap_bl, payload); ::encode(quorum, payload); ::encode(quorum_features, payload); ::encode(defunct_one, payload); ::encode(defunct_two, payload); ::encode(sharing_bl, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); if (header.version >= 2) ::decode(fsid, p); else memset(&fsid, 0, sizeof(fsid)); ::decode(op, p); ::decode(epoch, p); ::decode(monmap_bl, p); ::decode(quorum, p); if (header.version >= 3) ::decode(quorum_features, p); else quorum_features = 0; if (header.version >= 4) { ::decode(defunct_one, p); ::decode(defunct_two, p); } if (header.version >= 5) ::decode(sharing_bl, p); } }; #endif ceph-0.80.11/src/messages/MExportDirNotifyAck.h0000664000175100017510000000231712623076744023314 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRNOTIFYACK_H #define CEPH_MEXPORTDIRNOTIFYACK_H #include "msg/Message.h" #include using namespace std; class MExportDirNotifyAck : public Message { dirfrag_t dirfrag; public: dirfrag_t get_dirfrag() { return dirfrag; } MExportDirNotifyAck() {} MExportDirNotifyAck(dirfrag_t df, uint64_t tid) : Message(MSG_MDS_EXPORTDIRNOTIFYACK), dirfrag(df) { set_tid(tid); } private: ~MExportDirNotifyAck() {} public: const char *get_type_name() const { return "ExNotA"; } void print(ostream& o) const { o << "export_notify_ack(" << dirfrag << ")"; } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); } }; #endif ceph-0.80.11/src/messages/MPGStatsAck.h0000664000175100017510000000205212623076744021524 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MPGSTATSACK_H #define CEPH_MPGSTATSACK_H #include "osd/osd_types.h" class MPGStatsAck : public Message { public: map > pg_stat; MPGStatsAck() : Message(MSG_PGSTATSACK) {} private: ~MPGStatsAck() {} public: const char *get_type_name() const { return "pg_stats_ack"; } void print(ostream& out) const { out << "pg_stats_ack(" << pg_stat.size() << " pgs tid " << get_tid() << ")"; } void encode_payload(uint64_t features) { ::encode(pg_stat, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pg_stat, p); } }; #endif ceph-0.80.11/src/messages/MInodeFileCaps.h0000664000175100017510000000242012623076744022224 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MINODEFILECAPS_H #define CEPH_MINODEFILECAPS_H class MInodeFileCaps : public Message { inodeno_t ino; __u32 caps; public: inodeno_t get_ino() { return ino; } int get_caps() { return caps; } MInodeFileCaps() : Message(MSG_MDS_INODEFILECAPS) {} MInodeFileCaps(inodeno_t ino, int caps) : Message(MSG_MDS_INODEFILECAPS) { this->ino = ino; this->caps = caps; } private: ~MInodeFileCaps() {} public: const char *get_type_name() const { return "inode_file_caps";} void print(ostream& out) const { out << "inode_file_caps(" << ino << " " << ccap_string(caps) << ")"; } void encode_payload(uint64_t features) { ::encode(ino, payload); ::encode(caps, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(ino, p); ::decode(caps, p); } }; #endif ceph-0.80.11/src/messages/MMonProbe.h0000664000175100017510000000635212623076744021310 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMONPROBE_H #define CEPH_MMONPROBE_H #include "include/ceph_features.h" #include "msg/Message.h" #include "mon/MonMap.h" class MMonProbe : public Message { public: static const int HEAD_VERSION = 6; static const int COMPAT_VERSION = 5; enum { OP_PROBE = 1, OP_REPLY = 2, OP_SLURP = 3, OP_SLURP_LATEST = 4, OP_DATA = 5, OP_MISSING_FEATURES = 6, }; static const char *get_opname(int o) { switch (o) { case OP_PROBE: return "probe"; case OP_REPLY: return "reply"; case OP_SLURP: return "slurp"; case OP_SLURP_LATEST: return "slurp_latest"; case OP_DATA: return "data"; case OP_MISSING_FEATURES: return "missing_features"; default: assert(0); return 0; } } uuid_d fsid; int32_t op; string name; set quorum; bufferlist monmap_bl; version_t paxos_first_version; version_t paxos_last_version; bool has_ever_joined; uint64_t required_features; MMonProbe() : Message(MSG_MON_PROBE, HEAD_VERSION, COMPAT_VERSION) {} MMonProbe(const uuid_d& f, int o, const string& n, bool hej) : Message(MSG_MON_PROBE, HEAD_VERSION, COMPAT_VERSION), fsid(f), op(o), name(n), paxos_first_version(0), paxos_last_version(0), has_ever_joined(hej), required_features(0) {} private: ~MMonProbe() {} public: const char *get_type_name() const { return "mon_probe"; } void print(ostream& out) const { out << "mon_probe(" << get_opname(op) << " " << fsid << " name " << name; if (quorum.size()) out << " quorum " << quorum; if (op == OP_REPLY) { out << " paxos(" << " fc " << paxos_first_version << " lc " << paxos_last_version << " )"; } if (!has_ever_joined) out << " new"; if (required_features) out << " required_features " << required_features; out << ")"; } void encode_payload(uint64_t features) { if (monmap_bl.length() && (features & CEPH_FEATURE_MONENC) == 0) { // reencode old-format monmap MonMap t; t.decode(monmap_bl); monmap_bl.clear(); t.encode(monmap_bl, features); } ::encode(fsid, payload); ::encode(op, payload); ::encode(name, payload); ::encode(quorum, payload); ::encode(monmap_bl, payload); ::encode(has_ever_joined, payload); ::encode(paxos_first_version, payload); ::encode(paxos_last_version, payload); ::encode(required_features, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(fsid, p); ::decode(op, p); ::decode(name, p); ::decode(quorum, p); ::decode(monmap_bl, p); ::decode(has_ever_joined, p); ::decode(paxos_first_version, p); ::decode(paxos_last_version, p); if (header.version >= 6) ::decode(required_features, p); else required_features = 0; } }; #endif ceph-0.80.11/src/messages/MLock.h0000664000175100017510000000503712623076744020456 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MLOCK_H #define CEPH_MLOCK_H #include "msg/Message.h" #include "mds/locks.h" #include "mds/SimpleLock.h" class MLock : public Message { int32_t action; // action type int32_t asker; // who is initiating this request metareqid_t reqid; // for remote lock requests __u16 lock_type; // lock object type MDSCacheObjectInfo object_info; bufferlist lockdata; // and possibly some data public: bufferlist& get_data() { return lockdata; } int get_asker() { return asker; } int get_action() { return action; } metareqid_t get_reqid() { return reqid; } int get_lock_type() { return lock_type; } MDSCacheObjectInfo &get_object_info() { return object_info; } MLock() : Message(MSG_MDS_LOCK) {} MLock(int ac, int as) : Message(MSG_MDS_LOCK), action(ac), asker(as), lock_type(0) { } MLock(SimpleLock *lock, int ac, int as) : Message(MSG_MDS_LOCK), action(ac), asker(as), lock_type(lock->get_type()) { lock->get_parent()->set_object_info(object_info); } MLock(SimpleLock *lock, int ac, int as, bufferlist& bl) : Message(MSG_MDS_LOCK), action(ac), asker(as), lock_type(lock->get_type()) { lock->get_parent()->set_object_info(object_info); lockdata.claim(bl); } private: ~MLock() {} public: const char *get_type_name() const { return "ILock"; } void print(ostream& out) const { out << "lock(a=" << get_lock_action_name(action) << " " << get_lock_type_name(lock_type) << " " << object_info << ")"; } void set_reqid(metareqid_t ri) { reqid = ri; } void set_data(const bufferlist& lockdata) { this->lockdata = lockdata; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(asker, p); ::decode(action, p); ::decode(reqid, p); ::decode(lock_type, p); ::decode(object_info, p); ::decode(lockdata, p); } virtual void encode_payload(uint64_t features) { ::encode(asker, payload); ::encode(action, payload); ::encode(reqid, payload); ::encode(lock_type, payload); ::encode(object_info, payload); ::encode(lockdata, payload); } }; #endif ceph-0.80.11/src/messages/MExportCapsAck.h0000664000175100017510000000213112623076744022265 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTCAPSACK_H #define CEPH_MEXPORTCAPSACK_H #include "msg/Message.h" class MExportCapsAck : public Message { public: inodeno_t ino; MExportCapsAck() : Message(MSG_MDS_EXPORTCAPSACK) {} MExportCapsAck(inodeno_t i) : Message(MSG_MDS_EXPORTCAPSACK), ino(i) {} private: ~MExportCapsAck() {} public: const char *get_type_name() const { return "export_caps_ack"; } void print(ostream& o) const { o << "export_caps_ack(" << ino << ")"; } virtual void encode_payload(uint64_t features) { ::encode(ino, payload); } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(ino, p); } }; #endif ceph-0.80.11/src/messages/MGetPoolStatsReply.h0000664000175100017510000000255012623076744023167 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MGETPOOLSTATSREPLY_H #define CEPH_MGETPOOLSTATSREPLY_H #include class MGetPoolStatsReply : public PaxosServiceMessage { public: uuid_d fsid; map pool_stats; MGetPoolStatsReply() : PaxosServiceMessage(MSG_GETPOOLSTATSREPLY, 0) {} MGetPoolStatsReply(uuid_d& f, ceph_tid_t t, version_t v) : PaxosServiceMessage(MSG_GETPOOLSTATSREPLY, v), fsid(f) { set_tid(t); } private: ~MGetPoolStatsReply() {} public: const char *get_type_name() const { return "getpoolstats"; } void print(ostream& out) const { out << "getpoolstatsreply(" << get_tid() << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(pool_stats, payload, features); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(pool_stats, p); } }; #endif ceph-0.80.11/src/messages/MExportDirDiscover.h0000664000175100017510000000315112623076744023200 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRDISCOVER_H #define CEPH_MEXPORTDIRDISCOVER_H #include "msg/Message.h" #include "include/types.h" class MExportDirDiscover : public Message { int32_t from; dirfrag_t dirfrag; filepath path; public: int get_source_mds() { return from; } inodeno_t get_ino() { return dirfrag.ino; } dirfrag_t get_dirfrag() { return dirfrag; } filepath& get_path() { return path; } bool started; MExportDirDiscover() : Message(MSG_MDS_EXPORTDIRDISCOVER), started(false) { } MExportDirDiscover(dirfrag_t df, filepath& p, int f, uint64_t tid) : Message(MSG_MDS_EXPORTDIRDISCOVER), from(f), dirfrag(df), path(p), started(false) { set_tid(tid); } private: ~MExportDirDiscover() {} public: const char *get_type_name() const { return "ExDis"; } void print(ostream& o) const { o << "export_discover(" << dirfrag << " " << path << ")"; } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(from, p); ::decode(dirfrag, p); ::decode(path, p); } virtual void encode_payload(uint64_t features) { ::encode(from, payload); ::encode(dirfrag, payload); ::encode(path, payload); } }; #endif ceph-0.80.11/src/messages/MMonHealth.h0000664000175100017510000000360412623076744021443 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMON_HEALTH_H #define CEPH_MMON_HEALTH_H #include "msg/Message.h" #include "messages/MMonQuorumService.h" #include "mon/mon_types.h" struct MMonHealth : public MMonQuorumService { static const int HEAD_VERSION = 1; enum { OP_TELL = 1, }; int service_type; int service_op; // service specific data DataStats data_stats; MMonHealth() : MMonQuorumService(MSG_MON_HEALTH, HEAD_VERSION) { } MMonHealth(uint32_t type, int op = 0) : MMonQuorumService(MSG_MON_HEALTH, HEAD_VERSION), service_type(type), service_op(op) { } private: ~MMonHealth() { } public: const char *get_type_name() const { return "mon_health"; } const char *get_service_op_name() const { switch (service_op) { case OP_TELL: return "tell"; } return "???"; } void print(ostream &o) const { o << "mon_health( service " << get_service_type() << " op " << get_service_op_name() << " e " << get_epoch() << " r " << get_round() << " )"; } int get_service_type() const { return service_type; } int get_service_op() { return service_op; } void decode_payload() { bufferlist::iterator p = payload.begin(); service_decode(p); ::decode(service_type, p); ::decode(service_op, p); ::decode(data_stats, p); } void encode_payload(uint64_t features) { service_encode(); ::encode(service_type, payload); ::encode(service_op, payload); ::encode(data_stats, payload); } }; #endif /* CEPH_MMON_HEALTH_H */ ceph-0.80.11/src/messages/MExportDirPrepAck.h0000664000175100017510000000252712623076744022755 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRPREPACK_H #define CEPH_MEXPORTDIRPREPACK_H #include "msg/Message.h" #include "include/types.h" class MExportDirPrepAck : public Message { dirfrag_t dirfrag; bool success; public: dirfrag_t get_dirfrag() { return dirfrag; } MExportDirPrepAck() {} MExportDirPrepAck(dirfrag_t df, bool s, uint64_t tid) : Message(MSG_MDS_EXPORTDIRPREPACK), dirfrag(df), success(s) { set_tid(tid); } private: ~MExportDirPrepAck() {} public: bool is_success() { return success; } const char *get_type_name() const { return "ExPAck"; } void print(ostream& o) const { o << "export_prep_ack(" << dirfrag << (success ? " success)" : " fail)"); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(success, p); } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(success, payload); } }; #endif ceph-0.80.11/src/messages/MStatfsReply.h0000664000175100017510000000216012623076744022040 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MSTATFSREPLY_H #define CEPH_MSTATFSREPLY_H class MStatfsReply : public Message { public: struct ceph_mon_statfs_reply h; MStatfsReply() : Message(CEPH_MSG_STATFS_REPLY) {} MStatfsReply(uuid_d &f, ceph_tid_t t, epoch_t epoch) : Message(CEPH_MSG_STATFS_REPLY) { memcpy(&h.fsid, f.uuid, sizeof(h.fsid)); header.tid = t; h.version = epoch; } const char *get_type_name() const { return "statfs_reply"; } void print(ostream& out) const { out << "statfs_reply(" << header.tid << ")"; } void encode_payload(uint64_t features) { ::encode(h, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(h, p); } }; #endif ceph-0.80.11/src/messages/MExportDirFinish.h0000664000175100017510000000243312623076744022644 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRFINISH_H #define CEPH_MEXPORTDIRFINISH_H #include "msg/Message.h" class MExportDirFinish : public Message { dirfrag_t dirfrag; bool last; public: dirfrag_t get_dirfrag() { return dirfrag; } bool is_last() { return last; } MExportDirFinish() {} MExportDirFinish(dirfrag_t df, bool l, uint64_t tid) : Message(MSG_MDS_EXPORTDIRFINISH), dirfrag(df), last(l) { set_tid(tid); } private: ~MExportDirFinish() {} public: const char *get_type_name() const { return "ExFin"; } void print(ostream& o) const { o << "export_finish(" << dirfrag << (last ? " last" : "") << ")"; } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); ::encode(last, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); ::decode(last, p); } }; #endif ceph-0.80.11/src/messages/MOSDPGInfo.h0000664000175100017510000000677512623076744021270 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGINFO_H #define CEPH_MOSDPGINFO_H #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPGInfo : public Message { static const int HEAD_VERSION = 4; static const int COMPAT_VERSION = 1; epoch_t epoch; public: vector > pg_list; epoch_t get_epoch() { return epoch; } MOSDPGInfo() : Message(MSG_OSD_PG_INFO, HEAD_VERSION, COMPAT_VERSION) {} MOSDPGInfo(version_t mv) : Message(MSG_OSD_PG_INFO, HEAD_VERSION, COMPAT_VERSION), epoch(mv) { } private: ~MOSDPGInfo() {} public: const char *get_type_name() const { return "pg_info"; } void print(ostream& out) const { out << "pg_info(" << pg_list.size() << " pgs e" << epoch << ":"; for (vector >::const_iterator i = pg_list.begin(); i != pg_list.end(); ++i) { if (i != pg_list.begin()) out << ","; out << i->first.info.pgid; if (i->second.size()) out << "(" << i->second.size() << ")"; } out << ")"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); // v1 was vector __u32 n = pg_list.size(); ::encode(n, payload); for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); p++) ::encode(p->first.info, payload); // v2 needs the pg_interval_map_t for each record for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); p++) ::encode(p->second, payload); // v3 needs epoch_sent, query_epoch for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); p++) ::encode(pair( p->first.epoch_sent, p->first.query_epoch), payload); // v4 needs from, to for (vector >::iterator p = pg_list.begin(); p != pg_list.end(); ++p) { ::encode(p->first.from, payload); ::encode(p->first.to, payload); } } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); // decode pg_info_t portion of the vector __u32 n; ::decode(n, p); pg_list.resize(n); for (unsigned i=0; i= 2) { // get the pg_interval_map_t portion for (unsigned i=0; i >::iterator i = pg_list.begin(); i != pg_list.end(); i++) { if (header.version >= 3) { pair dec; ::decode(dec, p); i->first.epoch_sent = dec.first; i->first.query_epoch = dec.second; } else { i->first.epoch_sent = epoch; i->first.query_epoch = epoch; } } // v4 needs from and to if (header.version >= 4) { for (vector >::iterator i = pg_list.begin(); i != pg_list.end(); i++) { ::decode(i->first.from, p); ::decode(i->first.to, p); } } } }; #endif ceph-0.80.11/src/messages/MForward.h0000664000175100017510000000502112623076744021163 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2010 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Client requests often need to get forwarded from some monitor * to the leader. This class encapsulates the original message * along with the client's caps so the leader can do proper permissions * checking. */ #ifndef CEPH_MFORWARD_H #define CEPH_MFORWARD_H #include "msg/Message.h" #include "mon/MonCap.h" #include "include/encoding.h" struct MForward : public Message { uint64_t tid; PaxosServiceMessage *msg; entity_inst_t client; MonCap client_caps; uint64_t con_features; static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; MForward() : Message(MSG_FORWARD, HEAD_VERSION, COMPAT_VERSION), tid(0), msg(NULL), con_features(0) {} //the message needs to have caps filled in! MForward(uint64_t t, PaxosServiceMessage *m, uint64_t feat) : Message(MSG_FORWARD, HEAD_VERSION, COMPAT_VERSION), tid(t), msg(m) { client = m->get_source_inst(); client_caps = m->get_session()->caps; con_features = feat; } MForward(uint64_t t, PaxosServiceMessage *m, uint64_t feat, const MonCap& caps) : Message(MSG_FORWARD, HEAD_VERSION, COMPAT_VERSION), tid(t), msg(m), client_caps(caps) { client = m->get_source_inst(); con_features = feat; } private: ~MForward() { if (msg) msg->put(); } public: void encode_payload(uint64_t features) { ::encode(tid, payload); ::encode(client, payload); ::encode(client_caps, payload, features); encode_message(msg, features, payload); ::encode(con_features, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(tid, p); ::decode(client, p); ::decode(client_caps, p); msg = (PaxosServiceMessage *)decode_message(NULL, p); if (header.version >= 2) { ::decode(con_features, p); } else { con_features = 0; } } const char *get_type_name() const { return "forward"; } void print(ostream& o) const { if (msg) o << "forward(" << *msg << " caps " << client_caps << " tid " << tid << " con_features " << con_features << ") to leader"; else o << "forward(??? ) to leader"; } }; #endif ceph-0.80.11/src/messages/MGetPoolStats.h0000664000175100017510000000256412623076744022160 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MGETPOOLSTATS_H #define CEPH_MGETPOOLSTATS_H #include #include "messages/PaxosServiceMessage.h" class MGetPoolStats : public PaxosServiceMessage { public: uuid_d fsid; list pools; MGetPoolStats() : PaxosServiceMessage(MSG_GETPOOLSTATS, 0) {} MGetPoolStats(const uuid_d& f, ceph_tid_t t, list& ls, version_t l) : PaxosServiceMessage(MSG_GETPOOLSTATS, l), fsid(f), pools(ls) { set_tid(t); } private: ~MGetPoolStats() {} public: const char *get_type_name() const { return "getpoolstats"; } void print(ostream& out) const { out << "getpoolstats(" << get_tid() << " " << pools << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(pools, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(pools, p); } }; #endif ceph-0.80.11/src/messages/MClientCaps.h0000664000175100017510000001441412623076744021612 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MCLIENTCAPS_H #define CEPH_MCLIENTCAPS_H #include "msg/Message.h" #include "include/ceph_features.h" class MClientCaps : public Message { static const int HEAD_VERSION = 4; // added flock metadata, inline data static const int COMPAT_VERSION = 1; public: struct ceph_mds_caps head; struct ceph_mds_cap_peer peer; bufferlist snapbl; bufferlist xattrbl; bufferlist flockbl; version_t inline_version; bufferlist inline_data; int get_caps() { return head.caps; } int get_wanted() { return head.wanted; } int get_dirty() { return head.dirty; } ceph_seq_t get_seq() { return head.seq; } ceph_seq_t get_issue_seq() { return head.issue_seq; } ceph_seq_t get_mseq() { return head.migrate_seq; } inodeno_t get_ino() { return inodeno_t(head.ino); } inodeno_t get_realm() { return inodeno_t(head.realm); } uint64_t get_cap_id() { return head.cap_id; } uint64_t get_size() { return head.size; } uint64_t get_max_size() { return head.max_size; } __u32 get_truncate_seq() { return head.truncate_seq; } uint64_t get_truncate_size() { return head.truncate_size; } utime_t get_ctime() { return utime_t(head.ctime); } utime_t get_mtime() { return utime_t(head.mtime); } utime_t get_atime() { return utime_t(head.atime); } __u32 get_time_warp_seq() { return head.time_warp_seq; } ceph_file_layout& get_layout() { return head.layout; } int get_migrate_seq() { return head.migrate_seq; } int get_op() { return head.op; } uint64_t get_client_tid() { return get_tid(); } void set_client_tid(uint64_t s) { set_tid(s); } snapid_t get_snap_follows() { return snapid_t(head.snap_follows); } void set_snap_follows(snapid_t s) { head.snap_follows = s; } void set_caps(int c) { head.caps = c; } void set_wanted(int w) { head.wanted = w; } void set_max_size(uint64_t ms) { head.max_size = ms; } void set_migrate_seq(unsigned m) { head.migrate_seq = m; } void set_op(int o) { head.op = o; } void set_size(loff_t s) { head.size = s; } void set_mtime(const utime_t &t) { t.encode_timeval(&head.mtime); } void set_atime(const utime_t &t) { t.encode_timeval(&head.atime); } void set_cap_peer(uint64_t id, ceph_seq_t seq, ceph_seq_t mseq, int mds, int flags) { peer.cap_id = id; peer.seq = seq; peer.mseq = mseq; peer.mds = mds; peer.flags = flags; } MClientCaps() : Message(CEPH_MSG_CLIENT_CAPS, HEAD_VERSION, COMPAT_VERSION) { inline_version = 0; } MClientCaps(int op, inodeno_t ino, inodeno_t realm, uint64_t id, long seq, int caps, int wanted, int dirty, int mseq) : Message(CEPH_MSG_CLIENT_CAPS, HEAD_VERSION, COMPAT_VERSION) { memset(&head, 0, sizeof(head)); head.op = op; head.ino = ino; head.realm = realm; head.cap_id = id; head.seq = seq; head.caps = caps; head.wanted = wanted; head.dirty = dirty; head.migrate_seq = mseq; peer.cap_id = 0; inline_version = 0; } MClientCaps(int op, inodeno_t ino, inodeno_t realm, uint64_t id, int mseq) : Message(CEPH_MSG_CLIENT_CAPS, HEAD_VERSION) { memset(&head, 0, sizeof(head)); head.op = op; head.ino = ino; head.realm = realm; head.cap_id = id; head.migrate_seq = mseq; peer.cap_id = 0; inline_version = 0; } private: ~MClientCaps() {} public: const char *get_type_name() const { return "Cfcap";} void print(ostream& out) const { out << "client_caps(" << ceph_cap_op_name(head.op) << " ino " << inodeno_t(head.ino) << " " << head.cap_id << " seq " << head.seq; if (get_tid()) out << " tid " << get_tid(); out << " caps=" << ccap_string(head.caps) << " dirty=" << ccap_string(head.dirty) << " wanted=" << ccap_string(head.wanted); out << " follows " << snapid_t(head.snap_follows); if (head.migrate_seq) out << " mseq " << head.migrate_seq; out << " size " << head.size << "/" << head.max_size; if (head.truncate_seq) out << " ts " << head.truncate_seq; out << " mtime " << utime_t(head.mtime); if (head.time_warp_seq) out << " tws " << head.time_warp_seq; if (head.xattr_version) out << " xattrs(v=" << head.xattr_version << " l=" << xattrbl.length() << ")"; out << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(head, p); ::decode_nohead(head.snap_trace_len, snapbl, p); assert(middle.length() == head.xattr_len); if (head.xattr_len) xattrbl = middle; // conditionally decode flock metadata if (header.version >= 2) ::decode(flockbl, p); if (header.version >= 3) { if (head.op == CEPH_CAP_OP_IMPORT) ::decode(peer, p); else if (head.op == CEPH_CAP_OP_EXPORT) memcpy(&peer, &head.peer, sizeof(peer)); } if (header.version >= 4) { ::decode(inline_version, p); ::decode(inline_data, p); } else { inline_version = CEPH_INLINE_NONE; } } void encode_payload(uint64_t features) { head.snap_trace_len = snapbl.length(); head.xattr_len = xattrbl.length(); // record peer in unused fields of cap export message if ((features & CEPH_FEATURE_EXPORT_PEER) && head.op == CEPH_CAP_OP_EXPORT) memcpy(&head.peer, &peer, sizeof(peer)); ::encode(head, payload); ::encode_nohead(snapbl, payload); middle = xattrbl; // conditionally include flock metadata if (features & CEPH_FEATURE_FLOCK) { ::encode(flockbl, payload); } else { header.version = 1; return; } if (features & CEPH_FEATURE_EXPORT_PEER) { if (head.op == CEPH_CAP_OP_IMPORT) ::encode(peer, payload); } else { header.version = 2; return; } if (features & CEPH_FEATURE_MDS_INLINE_DATA) { ::encode(inline_version, payload); ::encode(inline_data, payload); } else { header.version = 3; return; } } }; #endif ceph-0.80.11/src/messages/MOSDPGPush.h0000664000175100017510000000355512623076744021305 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDPGPUSH_H #define MOSDPGPUSH_H #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPGPush : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: pg_shard_t from; spg_t pgid; epoch_t map_epoch; vector pushes; uint64_t cost; void compute_cost(CephContext *cct) { cost = 0; for (vector::iterator i = pushes.begin(); i != pushes.end(); ++i) { cost += i->cost(cct); } } int get_cost() const { return cost; } MOSDPGPush() : Message(MSG_OSD_PG_PUSH, HEAD_VERSION, COMPAT_VERSION), cost(0) {} virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid.pgid, p); ::decode(map_epoch, p); ::decode(pushes, p); ::decode(cost, p); if (header.version >= 2) { ::decode(pgid.shard, p); ::decode(from, p); } else { pgid.shard = ghobject_t::NO_SHARD; from = pg_shard_t(get_source().num(), ghobject_t::NO_SHARD); } } virtual void encode_payload(uint64_t features) { ::encode(pgid.pgid, payload); ::encode(map_epoch, payload); ::encode(pushes, payload); ::encode(cost, payload); ::encode(pgid.shard, payload); ::encode(from, payload); } const char *get_type_name() const { return "MOSDPGPush"; } void print(ostream& out) const { out << "MOSDPGPush(" << pgid << " " << map_epoch << " " << pushes; out << ")"; } }; #endif ceph-0.80.11/src/messages/MMDSBeacon.h0000664000175100017510000000537012623076744021321 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MMDSBEACON_H #define CEPH_MMDSBEACON_H #include "messages/PaxosServiceMessage.h" #include "include/types.h" #include "mds/MDSMap.h" #include class MMDSBeacon : public PaxosServiceMessage { static const int HEAD_VERSION = 2; uuid_d fsid; uint64_t global_id; string name; __u32 state; version_t seq; __s32 standby_for_rank; string standby_for_name; CompatSet compat; public: MMDSBeacon() : PaxosServiceMessage(MSG_MDS_BEACON, 0, HEAD_VERSION) { } MMDSBeacon(const uuid_d &f, uint64_t g, string& n, epoch_t les, int st, version_t se) : PaxosServiceMessage(MSG_MDS_BEACON, les, HEAD_VERSION), fsid(f), global_id(g), name(n), state(st), seq(se), standby_for_rank(-1) { } private: ~MMDSBeacon() {} public: uuid_d& get_fsid() { return fsid; } uint64_t get_global_id() { return global_id; } string& get_name() { return name; } epoch_t get_last_epoch_seen() { return version; } int get_state() { return state; } version_t get_seq() { return seq; } const char *get_type_name() const { return "mdsbeacon"; } int get_standby_for_rank() { return standby_for_rank; } const string& get_standby_for_name() { return standby_for_name; } CompatSet& get_compat() { return compat; } void set_compat(const CompatSet& c) { compat = c; } void set_standby_for_rank(int r) { standby_for_rank = r; } void set_standby_for_name(string& n) { standby_for_name = n; } void set_standby_for_name(const char* c) { standby_for_name.assign(c); } void print(ostream& out) const { out << "mdsbeacon(" << global_id << "/" << name << " " << ceph_mds_state_name(state) << " seq " << seq << " v" << version << ")"; } void encode_payload(uint64_t features) { paxos_encode(); ::encode(fsid, payload); ::encode(global_id, payload); ::encode(state, payload); ::encode(seq, payload); ::encode(name, payload); ::encode(standby_for_rank, payload); ::encode(standby_for_name, payload); ::encode(compat, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(fsid, p); ::decode(global_id, p); ::decode(state, p); ::decode(seq, p); ::decode(name, p); ::decode(standby_for_rank, p); ::decode(standby_for_name, p); if (header.version >= 2) ::decode(compat, p); } }; #endif ceph-0.80.11/src/messages/MExportDirCancel.h0000664000175100017510000000231212623076744022605 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEXPORTDIRCANCEL_H #define CEPH_MEXPORTDIRCANCEL_H #include "msg/Message.h" #include "include/types.h" class MExportDirCancel : public Message { dirfrag_t dirfrag; public: dirfrag_t get_dirfrag() { return dirfrag; } MExportDirCancel() : Message(MSG_MDS_EXPORTDIRCANCEL) {} MExportDirCancel(dirfrag_t df, uint64_t tid) : Message(MSG_MDS_EXPORTDIRCANCEL), dirfrag(df) { set_tid(tid); } private: ~MExportDirCancel() {} public: const char *get_type_name() const { return "ExCancel"; } void print(ostream& o) const { o << "export_cancel(" << dirfrag << ")"; } void encode_payload(uint64_t features) { ::encode(dirfrag, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(dirfrag, p); } }; #endif ceph-0.80.11/src/messages/MAuthReply.h0000664000175100017510000000334212623076744021500 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MAUTHREPLY_H #define CEPH_MAUTHREPLY_H #include "msg/Message.h" #include "common/errno.h" struct MAuthReply : public Message { __u32 protocol; __s32 result; uint64_t global_id; // if zero, meaningless string result_msg; bufferlist result_bl; MAuthReply() : Message(CEPH_MSG_AUTH_REPLY), protocol(0), result(0), global_id(0) {} MAuthReply(__u32 p, bufferlist *bl = NULL, int r = 0, uint64_t gid=0, const char *msg = "") : Message(CEPH_MSG_AUTH_REPLY), protocol(p), result(r), global_id(gid), result_msg(msg) { if (bl) result_bl = *bl; } private: ~MAuthReply() {} public: const char *get_type_name() const { return "auth_reply"; } void print(ostream& o) const { o << "auth_reply(proto " << protocol << " " << result << " " << cpp_strerror(result); if (result_msg.length()) o << ": " << result_msg; o << ")"; } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(protocol, p); ::decode(result, p); ::decode(global_id, p); ::decode(result_bl, p); ::decode(result_msg, p); } void encode_payload(uint64_t features) { ::encode(protocol, payload); ::encode(result, payload); ::encode(global_id, payload); ::encode(result_bl, payload); ::encode(result_msg, payload); } }; #endif ceph-0.80.11/src/messages/MOSDPGTemp.h0000664000175100017510000000242712623076744021270 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGTEMP_H #define CEPH_MOSDPGTEMP_H #include "messages/PaxosServiceMessage.h" class MOSDPGTemp : public PaxosServiceMessage { public: epoch_t map_epoch; map > pg_temp; MOSDPGTemp(epoch_t e) : PaxosServiceMessage(MSG_OSD_PGTEMP, e), map_epoch(e) { } MOSDPGTemp() : PaxosServiceMessage(MSG_OSD_PGTEMP, 0) {} private: ~MOSDPGTemp() {} public: void encode_payload(uint64_t features) { paxos_encode(); ::encode(map_epoch, payload); ::encode(pg_temp, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); paxos_decode(p); ::decode(map_epoch, p); ::decode(pg_temp, p); } const char *get_type_name() const { return "osd_pgtemp"; } void print(ostream &out) const { out << "osd_pgtemp(e" << map_epoch << " " << pg_temp << " v" << version << ")"; } }; #endif ceph-0.80.11/src/messages/MRoute.h0000664000175100017510000000424112623076744020660 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MROUTE_H #define CEPH_MROUTE_H #include "msg/Message.h" #include "include/encoding.h" struct MRoute : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 2; uint64_t session_mon_tid; Message *msg; entity_inst_t dest; MRoute() : Message(MSG_ROUTE, HEAD_VERSION, COMPAT_VERSION), msg(NULL) {} MRoute(uint64_t t, Message *m) : Message(MSG_ROUTE, HEAD_VERSION, COMPAT_VERSION), session_mon_tid(t), msg(m) {} MRoute(bufferlist bl, const entity_inst_t& i) : Message(MSG_ROUTE, HEAD_VERSION, COMPAT_VERSION), session_mon_tid(0), dest(i) { bufferlist::iterator p = bl.begin(); msg = decode_message(NULL, p); } private: ~MRoute() { if (msg) msg->put(); } public: void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(session_mon_tid, p); ::decode(dest, p); if (header.version >= 2) { bool m; ::decode(m, p); if (m) msg = decode_message(NULL, p); } else { msg = decode_message(NULL, p); } } void encode_payload(uint64_t features) { ::encode(session_mon_tid, payload); ::encode(dest, payload); if (features & CEPH_FEATURE_MON_NULLROUTE) { bool m = msg ? true : false; ::encode(m, payload); if (msg) encode_message(msg, features, payload); } else { header.version = 1; header.compat_version = 1; assert(msg); encode_message(msg, features, payload); } } const char *get_type_name() const { return "route"; } void print(ostream& o) const { if (msg) o << "route(" << *msg; else o << "route(no-reply"; if (session_mon_tid) o << " tid " << session_mon_tid << ")"; else o << " to " << dest << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDPGScan.h0000664000175100017510000000514712623076744021251 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGSCAN_H #define CEPH_MOSDPGSCAN_H #include "msg/Message.h" #include "osd/osd_types.h" class MOSDPGScan : public Message { static const int HEAD_VERSION = 2; static const int COMPAT_VERSION = 1; public: enum { OP_SCAN_GET_DIGEST = 1, // just objects and versions OP_SCAN_DIGEST = 2, // result }; const char *get_op_name(int o) const { switch (o) { case OP_SCAN_GET_DIGEST: return "get_digest"; case OP_SCAN_DIGEST: return "digest"; default: return "???"; } } __u32 op; epoch_t map_epoch, query_epoch; pg_shard_t from; spg_t pgid; hobject_t begin, end; virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(op, p); ::decode(map_epoch, p); ::decode(query_epoch, p); ::decode(pgid.pgid, p); ::decode(begin, p); ::decode(end, p); // handle hobject_t format upgrade if (!begin.is_max() && begin.pool == -1) begin.pool = pgid.pool(); if (!end.is_max() && end.pool == -1) end.pool = pgid.pool(); if (header.version >= 2) { ::decode(from, p); ::decode(pgid.shard, p); } else { from = pg_shard_t( get_source().num(), ghobject_t::NO_SHARD); pgid.shard = ghobject_t::NO_SHARD; } } virtual void encode_payload(uint64_t features) { ::encode(op, payload); ::encode(map_epoch, payload); ::encode(query_epoch, payload); ::encode(pgid.pgid, payload); ::encode(begin, payload); ::encode(end, payload); ::encode(from, payload); ::encode(pgid.shard, payload); } MOSDPGScan() : Message(MSG_OSD_PG_SCAN, HEAD_VERSION, COMPAT_VERSION) {} MOSDPGScan(__u32 o, pg_shard_t from, epoch_t e, epoch_t qe, spg_t p, hobject_t be, hobject_t en) : Message(MSG_OSD_PG_SCAN, HEAD_VERSION, COMPAT_VERSION), op(o), map_epoch(e), query_epoch(e), from(from), pgid(p), begin(be), end(en) { } private: ~MOSDPGScan() {} public: const char *get_type_name() const { return "pg_scan"; } void print(ostream& out) const { out << "pg_scan(" << get_op_name(op) << " " << pgid << " " << begin << "-" << end << " e " << map_epoch << "/" << query_epoch << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDECSubOpRead.h0000664000175100017510000000253012623076744022163 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MOSDECSUBOPREAD_H #define MOSDECSUBOPREAD_H #include "msg/Message.h" #include "osd/osd_types.h" #include "osd/ECMsgTypes.h" class MOSDECSubOpRead : public Message { static const int HEAD_VERSION = 1; static const int COMPAT_VERSION = 1; public: spg_t pgid; epoch_t map_epoch; ECSubRead op; int get_cost() const { return 0; } MOSDECSubOpRead() : Message(MSG_OSD_EC_READ, HEAD_VERSION, COMPAT_VERSION) {} virtual void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(pgid, p); ::decode(map_epoch, p); ::decode(op, p); } virtual void encode_payload(uint64_t features) { ::encode(pgid, payload); ::encode(map_epoch, payload); ::encode(op, payload); } const char *get_type_name() const { return "MOSDECSubOpRead"; } void print(ostream& out) const { out << "MOSDECSubOpRead(" << pgid << " " << map_epoch << " " << op; out << ")"; } }; #endif ceph-0.80.11/src/messages/MOSDPGQuery.h0000664000175100017510000000525212623076744021467 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDPGQUERY_H #define CEPH_MOSDPGQUERY_H #include "common/hobject.h" #include "msg/Message.h" /* * PGQuery - query another OSD as to the contents of their PGs */ class MOSDPGQuery : public Message { static const int HEAD_VERSION = 3; static const int COMPAT_VERSION = 1; version_t epoch; public: version_t get_epoch() { return epoch; } map pg_list; MOSDPGQuery() : Message(MSG_OSD_PG_QUERY, HEAD_VERSION, COMPAT_VERSION) {} MOSDPGQuery(epoch_t e, map& ls) : Message(MSG_OSD_PG_QUERY, HEAD_VERSION, COMPAT_VERSION), epoch(e) { pg_list.swap(ls); } private: ~MOSDPGQuery() {} public: const char *get_type_name() const { return "pg_query"; } void print(ostream& out) const { out << "pg_query("; for (map::const_iterator p = pg_list.begin(); p != pg_list.end(); ++p) { if (p != pg_list.begin()) out << ","; out << p->first; } out << " epoch " << epoch << ")"; } void encode_payload(uint64_t features) { ::encode(epoch, payload); vector > _pg_list; _pg_list.reserve(pg_list.size()); vector _shard_list; _shard_list.reserve(pg_list.size()); for (map::iterator i = pg_list.begin(); i != pg_list.end(); ++i) { _pg_list.push_back(make_pair(i->first.pgid, i->second)); _shard_list.push_back(i->first.shard); } ::encode(_pg_list, payload, features); ::encode(_shard_list, payload); } void decode_payload() { bufferlist::iterator p = payload.begin(); ::decode(epoch, p); vector > _pg_list; ::decode(_pg_list, p); vector _shard_list(_pg_list.size(), ghobject_t::no_shard()); if (header.version >= 3) { _shard_list.clear(); ::decode(_shard_list, p); } assert(_pg_list.size() == _shard_list.size()); for (unsigned i = 0; i < _pg_list.size(); ++i) { pg_list.insert( make_pair( spg_t(_pg_list[i].first, _shard_list[i]), _pg_list[i].second)); } if (header.version < 2) { for (map::iterator i = pg_list.begin(); i != pg_list.end(); ++i) { i->second.epoch_sent = epoch; } } } }; #endif ceph-0.80.11/src/messages/MOSDOp.h0000664000175100017510000002216212623076744020510 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MOSDOP_H #define CEPH_MOSDOP_H #include "msg/Message.h" #include "osd/osd_types.h" #include "include/ceph_features.h" /* * OSD op * * oid - object id * op - OSD_OP_DELETE, etc. * */ class OSD; class MOSDOp : public Message { static const int HEAD_VERSION = 4; static const int COMPAT_VERSION = 3; private: uint32_t client_inc; __u32 osdmap_epoch; __u32 flags; utime_t mtime; eversion_t reassert_version; int32_t retry_attempt; // 0 is first attempt. -1 if we don't know. object_t oid; object_locator_t oloc; pg_t pgid; public: vector ops; private: snapid_t snapid; snapid_t snap_seq; vector snaps; public: friend class MOSDOpReply; // read snapid_t get_snapid() { return snapid; } void set_snapid(snapid_t s) { snapid = s; } // writ snapid_t get_snap_seq() const { return snap_seq; } const vector &get_snaps() const { return snaps; } void set_snaps(const vector& i) { snaps = i; } void set_snap_seq(snapid_t s) { snap_seq = s; } osd_reqid_t get_reqid() const { return osd_reqid_t(get_orig_source(), client_inc, header.tid); } int get_client_inc() { return client_inc; } ceph_tid_t get_client_tid() { return header.tid; } object_t& get_oid() { return oid; } pg_t get_pg() const { return pgid; } object_locator_t get_object_locator() const { return oloc; } epoch_t get_map_epoch() { return osdmap_epoch; } eversion_t get_version() { return reassert_version; } utime_t get_mtime() { return mtime; } MOSDOp() : Message(CEPH_MSG_OSD_OP, HEAD_VERSION, COMPAT_VERSION) { } MOSDOp(int inc, long tid, object_t& _oid, object_locator_t& _oloc, pg_t _pgid, epoch_t _osdmap_epoch, int _flags) : Message(CEPH_MSG_OSD_OP, HEAD_VERSION, COMPAT_VERSION), client_inc(inc), osdmap_epoch(_osdmap_epoch), flags(_flags), retry_attempt(-1), oid(_oid), oloc(_oloc), pgid(_pgid) { set_tid(tid); } private: ~MOSDOp() {} public: void set_version(eversion_t v) { reassert_version = v; } void set_mtime(utime_t mt) { mtime = mt; } // ops void add_simple_op(int o, uint64_t off, uint64_t len) { OSDOp osd_op; osd_op.op.op = o; osd_op.op.extent.offset = off; osd_op.op.extent.length = len; ops.push_back(osd_op); } void write(uint64_t off, uint64_t len, bufferlist& bl) { add_simple_op(CEPH_OSD_OP_WRITE, off, len); data.claim(bl); header.data_off = off; } void writefull(bufferlist& bl) { add_simple_op(CEPH_OSD_OP_WRITEFULL, 0, bl.length()); data.claim(bl); header.data_off = 0; } void zero(uint64_t off, uint64_t len) { add_simple_op(CEPH_OSD_OP_ZERO, off, len); } void truncate(uint64_t off) { add_simple_op(CEPH_OSD_OP_TRUNCATE, off, 0); } void remove() { add_simple_op(CEPH_OSD_OP_DELETE, 0, 0); } void read(uint64_t off, uint64_t len) { add_simple_op(CEPH_OSD_OP_READ, off, len); } void stat() { add_simple_op(CEPH_OSD_OP_STAT, 0, 0); } // flags int get_flags() const { return flags; } bool wants_ack() const { return flags & CEPH_OSD_FLAG_ACK; } bool wants_ondisk() const { return flags & CEPH_OSD_FLAG_ONDISK; } bool wants_onnvram() const { return flags & CEPH_OSD_FLAG_ONNVRAM; } void set_want_ack(bool b) { flags |= CEPH_OSD_FLAG_ACK; } void set_want_onnvram(bool b) { flags |= CEPH_OSD_FLAG_ONNVRAM; } void set_want_ondisk(bool b) { flags |= CEPH_OSD_FLAG_ONDISK; } bool is_retry_attempt() const { return flags & CEPH_OSD_FLAG_RETRY; } void set_retry_attempt(unsigned a) { if (a) flags |= CEPH_OSD_FLAG_RETRY; else flags &= ~CEPH_OSD_FLAG_RETRY; retry_attempt = a; } /** * get retry attempt * * 0 is the first attempt. * * @return retry attempt, or -1 if we don't know */ int get_retry_attempt() const { return retry_attempt; } // marshalling virtual void encode_payload(uint64_t features) { OSDOp::merge_osd_op_vector_in_data(ops, data); if ((features & CEPH_FEATURE_OBJECTLOCATOR) == 0) { // here is the old structure we are encoding to: // #if 0 struct ceph_osd_request_head { __le32 client_inc; /* client incarnation */ struct ceph_object_layout layout; /* pgid */ __le32 osdmap_epoch; /* client's osdmap epoch */ __le32 flags; struct ceph_timespec mtime; /* for mutations only */ struct ceph_eversion reassert_version; /* if we are replaying op */ __le32 object_len; /* length of object name */ __le64 snapid; /* snapid to read */ __le64 snap_seq; /* writer's snap context */ __le32 num_snaps; __le16 num_ops; struct ceph_osd_op ops[]; /* followed by ops[], obj, ticket, snaps */ } __attribute__ ((packed)); #endif header.version = 1; ::encode(client_inc, payload); __u32 su = 0; ::encode(pgid, payload); ::encode(su, payload); ::encode(osdmap_epoch, payload); ::encode(flags, payload); ::encode(mtime, payload); ::encode(reassert_version, payload); __u32 oid_len = oid.name.length(); ::encode(oid_len, payload); ::encode(snapid, payload); ::encode(snap_seq, payload); __u32 num_snaps = snaps.size(); ::encode(num_snaps, payload); //::encode(ops, payload); __u16 num_ops = ops.size(); ::encode(num_ops, payload); for (unsigned i = 0; i < ops.size(); i++) ::encode(ops[i].op, payload); ::encode_nohead(oid.name, payload); ::encode_nohead(snaps, payload); } else { ::encode(client_inc, payload); ::encode(osdmap_epoch, payload); ::encode(flags, payload); ::encode(mtime, payload); ::encode(reassert_version, payload); ::encode(oloc, payload); ::encode(pgid, payload); ::encode(oid, payload); __u16 num_ops = ops.size(); ::encode(num_ops, payload); for (unsigned i = 0; i < ops.size(); i++) ::encode(ops[i].op, payload); ::encode(snapid, payload); ::encode(snap_seq, payload); ::encode(snaps, payload); ::encode(retry_attempt, payload); } } virtual void decode_payload() { bufferlist::iterator p = payload.begin(); if (header.version < 2) { // old decode ::decode(client_inc, p); old_pg_t opgid; ::decode_raw(opgid, p); pgid = opgid; __u32 su; ::decode(su, p); oloc.pool = pgid.pool(); ::decode(osdmap_epoch, p); ::decode(flags, p); ::decode(mtime, p); ::decode(reassert_version, p); __u32 oid_len; ::decode(oid_len, p); ::decode(snapid, p); ::decode(snap_seq, p); __u32 num_snaps; ::decode(num_snaps, p); //::decode(ops, p); __u16 num_ops; ::decode(num_ops, p); ops.resize(num_ops); for (unsigned i = 0; i < num_ops; i++) ::decode(ops[i].op, p); decode_nohead(oid_len, oid.name, p); decode_nohead(num_snaps, snaps, p); // recalculate pgid hash value pgid.set_ps(ceph_str_hash(CEPH_STR_HASH_RJENKINS, oid.name.c_str(), oid.name.length())); retry_attempt = -1; } else { // new decode ::decode(client_inc, p); ::decode(osdmap_epoch, p); ::decode(flags, p); ::decode(mtime, p); ::decode(reassert_version, p); ::decode(oloc, p); if (header.version < 3) { old_pg_t opgid; ::decode_raw(opgid, p); pgid = opgid; } else { ::decode(pgid, p); } ::decode(oid, p); //::decode(ops, p); __u16 num_ops; ::decode(num_ops, p); ops.resize(num_ops); for (unsigned i = 0; i < num_ops; i++) ::decode(ops[i].op, p); ::decode(snapid, p); ::decode(snap_seq, p); ::decode(snaps, p); if (header.version >= 4) ::decode(retry_attempt, p); else retry_attempt = -1; } OSDOp::split_osd_op_vector_in_data(ops, data); } void clear_buffers() { ops.clear(); } const char *get_type_name() const { return "osd_op"; } void print(ostream& out) const { out << "osd_op(" << get_reqid(); out << " "; if (!oloc.nspace.empty()) out << oloc.nspace << "/"; out << oid; #if 0 out << " "; if (may_read()) out << "r"; if (may_write()) out << "w"; #endif if (snapid != CEPH_NOSNAP) out << "@" << snapid; if (oloc.key.size()) out << " " << oloc; out << " " << ops; out << " " << pgid; if (is_retry_attempt()) out << " RETRY=" << get_retry_attempt(); if (reassert_version != eversion_t()) out << " reassert_version=" << reassert_version; if (get_snap_seq()) out << " snapc " << get_snap_seq() << "=" << snaps; out << " " << ceph_osd_flag_string(get_flags()); out << " e" << osdmap_epoch; out << ")"; } }; #endif ceph-0.80.11/src/ceph-disk-udev0000775000175100017510000000412212623076744020221 0ustar jenkins-buildjenkins-build#! /bin/sh # Wrapper for the ceph udev rules. Since older versions of udev+blkid # do not support gpt label fields, this shell script is invoked from # the udev rule to read the needed gpt label fields and call the # appropriate ceph OSD functions. PARTNO=$1 NAME=$2 PARENT_NAME=$3 # Get GPT partition type guid ID_PART_ENTRY_TYPE=$(/usr/sbin/sgdisk --info=${PARTNO} /dev/${PARENT_NAME} | grep "Partition GUID code" | awk '{print $4}' | tr '[:upper:]' '[:lower:]') if [ -z "$ID_PART_ENTRY_TYPE" ]; then exit fi ID_PART_ENTRY_UUID=$(/usr/sbin/sgdisk --info=${PARTNO} /dev/${PARENT_NAME} | grep "Partition unique GUID" | awk '{print $4}' | tr '[:upper:]' '[:lower:]') # set up the symlinks mkdir -p /dev/disk/by-partuuid ln -sf ../../${NAME} /dev/disk/by-partuuid/$ID_PART_ENTRY_UUID mkdir -p /dev/disk/by-parttypeuuid ln -sf ../../${NAME} /dev/disk/by-parttypeuuid/${ID_PART_ENTRY_TYPE}.${ID_PART_ENTRY_UUID} case $ID_PART_ENTRY_TYPE in 45b0969e-9b03-4f30-b4c6-b4b80ceff106) # JOURNAL_UUID # activate ceph-tagged journal partitions. /usr/sbin/ceph-disk -v activate-journal /dev/${NAME} ;; 45b0969e-9b03-4f30-b4c6-5ec00ceff106) # DMCRYPT_JOURNAL_UUID # Map journal if using dm-crypt /sbin/cryptsetup --key-file /etc/ceph/dmcrypt-keys/${ID_PART_ENTRY_UUID} --key-size 256 create ${ID_PART_ENTRY_UUID} /dev/${NAME} ;; 4fbd7e29-9d25-41b8-afd0-062c0ceff05d) # OSD_UUID # activate ceph-tagged partitions. /usr/sbin/ceph-disk -v activate /dev/${NAME} ;; 4fbd7e29-9d25-41b8-afd0-5ec00ceff05d) # DMCRYPT_OSD_UUID # Map data device and activate ceph-tagged partitions # for dm-crypted data devices /sbin/cryptsetup --key-file /etc/ceph/dmcrypt-keys/${ID_PART_ENTRY_UUID} --key-size 256 create ${ID_PART_ENTRY_UUID} /dev/${NAME} bash -c 'while [ ! -e /dev/mapper/${ID_PART_ENTRY_UUID} ];do sleep 1; done' /usr/sbin/ceph-disk-activate /dev/mapper/${ID_PART_ENTRY_UUID} ;; 89c57f98-2fe5-4dc0-89c1-f3ad0ceff2be) # TOBE_UUID ;; 89c57f98-2fe5-4dc0-89c1-5ec00ceff2be) # DMCRYPT_TOBE_UUID ;; *) # Not a Ceph device ;; esac exit ceph-0.80.11/src/logrotate.conf0000664000175100017510000000232312623076744020333 0ustar jenkins-buildjenkins-build/var/log/ceph/*.log { rotate 7 daily compress sharedscripts postrotate if which invoke-rc.d > /dev/null 2>&1 && [ -x `which invoke-rc.d` ]; then invoke-rc.d ceph reload >/dev/null elif which service > /dev/null 2>&1 && [ -x `which service` ]; then service ceph reload >/dev/null fi # Possibly reload twice, but depending on ceph.conf the reload above may be a no-op if which initctl > /dev/null 2>&1 && [ -x `which initctl` ]; then for daemon in osd mon mds ; do find -L /var/lib/ceph/$daemon/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -printf '%P\n' \ | while read f; do if [ -e "/var/lib/ceph/$daemon/$f/done" -o -e "/var/lib/ceph/$daemon/$f/ready" ] && [ -e "/var/lib/ceph/$daemon/$f/upstart" ] && [ ! -e "/var/lib/ceph/$daemon/$f/sysvinit" ]; then cluster="${f%%-*}" id="${f#*-}" initctl reload ceph-$daemon cluster="$cluster" id="$id" 2>/dev/null || : fi done done fi endscript missingok notifempty } ceph-0.80.11/src/ocf/0000775000175100017510000000000012623077036016226 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/ocf/ceph.in0000664000175100017510000001031212623076744017477 0ustar jenkins-buildjenkins-build#!/bin/sh # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Convenience variables # When sysconfdir isn't passed in as a configure flag, # it's defined in terms of prefix prefix=@prefix@ CEPH_INIT=@sysconfdir@/init.d/ceph ceph_meta_data() { local longdesc local shortdesc case $__SCRIPT_NAME in "osd") longdesc="Wraps the ceph init script to provide an OCF resource agent that manages and monitors the Ceph OSD service." shortdesc="Manages a Ceph OSD instance." ;; "mds") longdesc="Wraps the ceph init script to provide an OCF resource agent that manages and monitors the Ceph MDS service." shortdesc="Manages a Ceph MDS instance." ;; "mon") longdesc="Wraps the ceph init script to provide an OCF resource agent that manages and monitors the Ceph MON service." shortdesc="Manages a Ceph MON instance." ;; esac cat < 0.1 ${longdesc} ${shortdesc} EOF } ceph_action() { local init_action init_action="$1" case ${__SCRIPT_NAME} in osd|mds|mon) ocf_run $CEPH_INIT $init_action ${__SCRIPT_NAME} ;; *) ocf_run $CEPH_INIT $init_action ;; esac } ceph_validate_all() { # Do we have the ceph init script? check_binary @sysconfdir@/init.d/ceph # Do we have a configuration file? [ -e @sysconfdir@/ceph/ceph.conf ] || exit $OCF_ERR_INSTALLED } ceph_monitor() { local rc ceph_action status # 0: running, and fully caught up with master # 3: gracefully stopped # any other: error case "$?" in 0) rc=$OCF_SUCCESS ocf_log debug "Resource is running" ;; 3) rc=$OCF_NOT_RUNNING ocf_log debug "Resource is not running" ;; *) ocf_log err "Resource has failed" rc=$OCF_ERR_GENERIC esac return $rc } ceph_start() { # if resource is already running, bail out early if ceph_monitor; then ocf_log info "Resource is already running" return $OCF_SUCCESS fi ceph_action start while ! ceph_monitor; do ocf_log debug "Resource has not started yet, waiting" sleep 1 done return $OCF_SUCCESS } ceph_stop() { local rc # exit immediately if configuration is not valid ceph_validate_all || exit $? ceph_monitor rc=$? case "$rc" in "$OCF_SUCCESS") # Currently running. Normal, expected behavior. ocf_log debug "Resource is currently running" ;; "$OCF_NOT_RUNNING") # Currently not running. Nothing to do. ocf_log info "Resource is already stopped" return $OCF_SUCCESS ;; esac ceph_action stop while ceph_monitor; do ocf_log debug "Resource has not stopped yet, waiting" sleep 1 done # only return $OCF_SUCCESS if _everything_ succeeded as expected return $OCF_SUCCESS } # Make sure meta-data and usage always succeed case $__OCF_ACTION in meta-data) ceph_meta_data exit $OCF_SUCCESS ;; usage|help) ceph_usage exit $OCF_SUCCESS ;; esac # Anything other than meta-data and usage must pass validation ceph_validate_all || exit $? # Translate each action into the appropriate function call case $__OCF_ACTION in start) ceph_start;; stop) ceph_stop;; status|monitor) ceph_monitor;; reload) ocf_log info "Reloading..." ceph_start ;; validate-all) ;; *) ceph_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac rc=$? exit $rc ceph-0.80.11/src/ocf/Makefile.am0000664000175100017510000000104412623076744020266 0ustar jenkins-buildjenkins-buildEXTRA_DIST = ceph.in Makefile.in if WITH_OCF # The root of the OCF resource agent hierarchy # Per the OCF standard, it's always "lib", # not "lib64" (even on 64-bit platforms). ocfdir = $(prefix)/lib/ocf # The ceph provider directory radir = $(ocfdir)/resource.d/$(PACKAGE_NAME) ra_SCRIPTS = ceph rbd install-data-hook: $(LN_S) ceph $(DESTDIR)$(radir)/osd $(LN_S) ceph $(DESTDIR)$(radir)/mds $(LN_S) ceph $(DESTDIR)$(radir)/mon uninstall-hook: rm -f $(DESTDIR)$(radir)/osd rm -f $(DESTDIR)$(radir)/mds rm -f $(DESTDIR)$(radir)/mon endif ceph-0.80.11/src/ocf/Makefile.in0000664000175100017510000004326112623076766020312 0ustar jenkins-buildjenkins-build# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src/ocf DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/ceph.in $(srcdir)/rbd.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_check_classpath.m4 \ $(top_srcdir)/m4/ac_prog_jar.m4 \ $(top_srcdir)/m4/ac_prog_javac.m4 \ $(top_srcdir)/m4/ac_prog_javac_works.m4 \ $(top_srcdir)/m4/ac_prog_javah.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/ax_c_pretty_func.m4 \ $(top_srcdir)/m4/ax_c_var_func.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_cxx_static_cast.m4 \ $(top_srcdir)/m4/ax_intel.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/acconfig.h CONFIG_CLEAN_FILES = ceph rbd CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(radir)" SCRIPTS = $(ra_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CXXFLAGS = @AM_CXXFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@ CC = @CC@ CCAS = @CCAS@ CCASDEPMODE = @CCASDEPMODE@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOPP_CFLAGS = @CRYPTOPP_CFLAGS@ CRYPTOPP_LIBS = @CRYPTOPP_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CLASSPATH_JAR = @EXTRA_CLASSPATH_JAR@ FGREP = @FGREP@ GCOV_PREFIX_STRIP = @GCOV_PREFIX_STRIP@ GIT_CHECK = @GIT_CHECK@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTEL_FLAGS = @INTEL_FLAGS@ INTEL_PCLMUL_FLAGS = @INTEL_PCLMUL_FLAGS@ INTEL_SSE2_FLAGS = @INTEL_SSE2_FLAGS@ INTEL_SSE3_FLAGS = @INTEL_SSE3_FLAGS@ INTEL_SSE4_1_FLAGS = @INTEL_SSE4_1_FLAGS@ INTEL_SSE4_2_FLAGS = @INTEL_SSE4_2_FLAGS@ INTEL_SSE_FLAGS = @INTEL_SSE_FLAGS@ INTEL_SSSE3_FLAGS = @INTEL_SSSE3_FLAGS@ JAR = @JAR@ JAVAC = @JAVAC@ JAVAH = @JAVAH@ JDK_CPPFLAGS = @JDK_CPPFLAGS@ KEYUTILS_LIB = @KEYUTILS_LIB@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEDIT_CFLAGS = @LIBEDIT_CFLAGS@ LIBEDIT_LIBS = @LIBEDIT_LIBS@ LIBFUSE = @LIBFUSE@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTCMALLOC = @LIBTCMALLOC@ LIBTOOL = @LIBTOOL@ LIBZFS_CFLAGS = @LIBZFS_CFLAGS@ LIBZFS_LIBS = @LIBZFS_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NSS_CFLAGS = @NSS_CFLAGS@ NSS_LIBS = @NSS_LIBS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RESOLV_LIBS = @RESOLV_LIBS@ RPM_RELEASE = @RPM_RELEASE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WARN_IGNORED_QUALIFIERS = @WARN_IGNORED_QUALIFIERS@ WARN_TYPE_LIMITS = @WARN_TYPE_LIMITS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = ceph.in Makefile.in # The root of the OCF resource agent hierarchy # Per the OCF standard, it's always "lib", # not "lib64" (even on 64-bit platforms). @WITH_OCF_TRUE@ocfdir = $(prefix)/lib/ocf # The ceph provider directory @WITH_OCF_TRUE@radir = $(ocfdir)/resource.d/$(PACKAGE_NAME) @WITH_OCF_TRUE@ra_SCRIPTS = ceph rbd all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/ocf/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/ocf/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): ceph: $(top_builddir)/config.status $(srcdir)/ceph.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ rbd: $(top_builddir)/config.status $(srcdir)/rbd.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-raSCRIPTS: $(ra_SCRIPTS) @$(NORMAL_INSTALL) @list='$(ra_SCRIPTS)'; test -n "$(radir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(radir)'"; \ $(MKDIR_P) "$(DESTDIR)$(radir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(radir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(radir)$$dir" || exit $$?; \ } \ ; done uninstall-raSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(ra_SCRIPTS)'; test -n "$(radir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(radir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) installdirs: for dir in "$(DESTDIR)$(radir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @WITH_OCF_FALSE@install-data-hook: @WITH_OCF_FALSE@uninstall-hook: clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-raSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-raSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-data-am install-strip uninstall-am .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-data-hook install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-raSCRIPTS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-hook uninstall-raSCRIPTS @WITH_OCF_TRUE@install-data-hook: @WITH_OCF_TRUE@ $(LN_S) ceph $(DESTDIR)$(radir)/osd @WITH_OCF_TRUE@ $(LN_S) ceph $(DESTDIR)$(radir)/mds @WITH_OCF_TRUE@ $(LN_S) ceph $(DESTDIR)$(radir)/mon @WITH_OCF_TRUE@uninstall-hook: @WITH_OCF_TRUE@ rm -f $(DESTDIR)$(radir)/osd @WITH_OCF_TRUE@ rm -f $(DESTDIR)$(radir)/mds @WITH_OCF_TRUE@ rm -f $(DESTDIR)$(radir)/mon # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ceph-0.80.11/src/ocf/rbd.in0000664000175100017510000002152012623076744017332 0ustar jenkins-buildjenkins-build#!/bin/sh # # OCF resource agent for mapping and unmapping # RADOS Block Devices (RBDs) # # License: GNU Lesser General Public License (LGPL) 2.1 # (c) 2012 Florian Haas, hastexo # # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Convenience variables # When sysconfdir isn't passed in as a configure flag, # it's defined in terms of prefix prefix=@prefix@ # Defaults OCF_RESKEY_pool_default="rbd" OCF_RESKEY_cephconf_default="@sysconfdir@/@PACKAGE_TARNAME@/@PACKAGE_TARNAME@.conf" : ${OCF_RESKEY_pool=${OCF_RESKEY_pool_default}} : ${OCF_RESKEY_cephconf=${OCF_RESKEY_cephconf_default}} rbd_meta_data() { cat < 0.1 Manages RADOS Block Devices (RBDs) as a highly available resource. Maps and unmaps RBDs as needed. Maps and unmaps RADOS Block Devices Name of the RBD device. RBD device name Name of the RADOS pool where the RBD has been created RADOS pool name Name of the device snapshot to map. Snapshot name Location of the Ceph configuration file Ceph configuration file Address (or comma-separated list of addresses) of monitor servers to connect to. Overrides values from configuration file. Monitor address(es) Username to use when mapping the device. Required if Ceph authentication is enabled on the monitor. Authentication username File containing an authentication secret. Required if Ceph authentication is enabled on the monitor. Authentication secret file EOF } rbd_usage() { cat < header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_NAMESER_COMPAT_H /* have boost::random::discrete_distribution */ #undef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION /* Define if have curl_multi_wait() */ #undef HAVE_CURL_MULTI_WAIT /* Define to 1 if you have the declaration of `strerror_r', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR_R /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have fdatasync. */ #undef HAVE_FDATASYNC /* linux/fiemap.h was found, fiemap ioctl will be used */ #undef HAVE_FIEMAP_H /* Define if the C complier supports __func__ */ #undef HAVE_FUNC /* Define to 1 if you have the `fuse_getgroups' function. */ #undef HAVE_FUSE_GETGROUPS /* we have a recent yasm and are x86_64 */ #undef HAVE_GOOD_YASM_ELF64 /* Define to 1 if the system has the type `int16_t'. */ #undef HAVE_INT16_T /* Define to 1 if the system has the type `int32_t'. */ #undef HAVE_INT32_T /* Define to 1 if the system has the type `int64_t'. */ #undef HAVE_INT64_T /* Define to 1 if the system has the type `int8_t'. */ #undef HAVE_INT8_T /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Defined if LevelDB supports bloom filters */ #undef HAVE_LEVELDB_FILTER_POLICY /* Defined if you don't have atomic_ops */ #undef HAVE_LIBAIO /* Define to 1 if you have the `boost_program_options' library (-lboost_program_options). */ #undef HAVE_LIBBOOST_PROGRAM_OPTIONS /* Define to 1 if you have the `boost_program_options-mt' library (-lboost_program_options-mt). */ #undef HAVE_LIBBOOST_PROGRAM_OPTIONS_MT /* Define to 1 if you have the `boost_system' library (-lboost_system). */ #undef HAVE_LIBBOOST_SYSTEM /* Define to 1 if you have the `boost_system-mt' library (-lboost_system-mt). */ #undef HAVE_LIBBOOST_SYSTEM_MT /* Define to 1 if you have the `boost_thread' library (-lboost_thread). */ #undef HAVE_LIBBOOST_THREAD /* Define to 1 if you have the `boost_thread-mt' library (-lboost_thread-mt). */ #undef HAVE_LIBBOOST_THREAD_MT /* Define if you have fuse */ #undef HAVE_LIBFUSE /* Define to 1 if you have the `profiler' library (-lprofiler). */ #undef HAVE_LIBPROFILER /* Define if you have tcmalloc */ #undef HAVE_LIBTCMALLOC /* Define to 1 if you have libxfs */ #undef HAVE_LIBXFS /* Defined if you have libzfs enabled */ #undef HAVE_LIBZFS /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_VERSION_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Support (PCLMUL) Carry-Free Muliplication */ #undef HAVE_PCLMUL /* Define to 1 if you have the `pipe2' function. */ #undef HAVE_PIPE2 /* Define to 1 if you have the `posix_fadvise' function. */ #undef HAVE_POSIX_FADVISE /* Define to 1 if you have the `posix_fallocate' function. */ #undef HAVE_POSIX_FALLOCATE /* Define to 1 if you have the `prctl' function. */ #undef HAVE_PRCTL /* Define if the C complier supports __PRETTY_FUNCTION__ */ #undef HAVE_PRETTY_FUNC /* Define if you have perftools profiler enabled */ #undef HAVE_PROFILER /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define if you have pthread_spin_init */ #undef HAVE_PTHREAD_SPINLOCK /* Support SSE (Streaming SIMD Extensions) instructions */ #undef HAVE_SSE /* Support SSE2 (Streaming SIMD Extensions 2) instructions */ #undef HAVE_SSE2 /* Support SSE3 (Streaming SIMD Extensions 3) instructions */ #undef HAVE_SSE3 /* Support SSE4.1 (Streaming SIMD Extensions 4.1) instructions */ #undef HAVE_SSE4_1 /* Support SSE4.2 (Streaming SIMD Extensions 4.2) instructions */ #undef HAVE_SSE4_2 /* Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions */ #undef HAVE_SSSE3 /* define if the compiler supports static_cast<> */ #undef HAVE_STATIC_CAST /* Define if you have struct stat.st_mtimespec.tv_nsec */ #undef HAVE_STAT_ST_MTIMESPEC_TV_NSEC /* Define if you have struct stat.st_mtim.tv_nsec */ #undef HAVE_STAT_ST_MTIM_TV_NSEC /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strerror_r' function. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `syncfs' function. */ #undef HAVE_SYNCFS /* sync_file_range(2) is supported */ #undef HAVE_SYNC_FILE_RANGE /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STATVFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* we have syncfs */ #undef HAVE_SYS_SYNCFS /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_VFS_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_XATTR_H /* Define to 1 if the system has the type `uint16_t'. */ #undef HAVE_UINT16_T /* Define to 1 if the system has the type `uint32_t'. */ #undef HAVE_UINT32_T /* Define to 1 if the system has the type `uint64_t'. */ #undef HAVE_UINT64_T /* Define to 1 if the system has the type `uint8_t'. */ #undef HAVE_UINT8_T /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H /* Define to 1 if the system has the type `__be16'. */ #undef HAVE___BE16 /* Define to 1 if the system has the type `__be32'. */ #undef HAVE___BE32 /* Define to 1 if the system has the type `__be64'. */ #undef HAVE___BE64 /* Define to 1 if the system has the type `__le16'. */ #undef HAVE___LE16 /* Define to 1 if the system has the type `__le32'. */ #undef HAVE___LE32 /* Define to 1 if the system has the type `__le64'. */ #undef HAVE___LE64 /* Define to 1 if the system has the type `__s16'. */ #undef HAVE___S16 /* Define to 1 if the system has the type `__s32'. */ #undef HAVE___S32 /* Define to 1 if the system has the type `__s64'. */ #undef HAVE___S64 /* Define to 1 if the system has the type `__s8'. */ #undef HAVE___S8 /* Define to 1 if the system has the type `__u16'. */ #undef HAVE___U16 /* Define to 1 if the system has the type `__u32'. */ #undef HAVE___U32 /* Define to 1 if the system has the type `__u64'. */ #undef HAVE___U64 /* Define to 1 if the system has the type `__u8'. */ #undef HAVE___U8 /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Defined if you do not have atomic_ops */ #undef NO_ATOMIC_OPS /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Defined if you want pg ref debugging */ #undef PG_DEBUG_REFS /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* The size of `AO_t', as computed by sizeof. */ #undef SIZEOF_AO_T /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if strerror_r returns char *. */ #undef STRERROR_R_CHAR_P /* Define if using CryptoPP. */ #undef USE_CRYPTOPP /* Define if using NSS. */ #undef USE_NSS /* Version number of package */ #undef VERSION /* define if radosgw enabled */ #undef WITH_RADOSGW ceph-0.80.11/src/mon/0000775000175100017510000000000012623077035016247 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/mon/MDSMonitor.cc0000664000175100017510000012403612623076744020565 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "MDSMonitor.h" #include "Monitor.h" #include "MonitorDBStore.h" #include "OSDMonitor.h" #include "common/strtol.h" #include "common/ceph_argparse.h" #include "messages/MMDSMap.h" #include "messages/MMDSBeacon.h" #include "messages/MMDSLoadTargets.h" #include "messages/MMonCommand.h" #include "messages/MGenericMessage.h" #include "common/perf_counters.h" #include "common/Timer.h" #include "common/config.h" #include "include/assert.h" #include "MonitorDBStore.h" #include "common/cmdparse.h" #include "include/str_list.h" #include "mds/mdstypes.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, mdsmap) static ostream& _prefix(std::ostream *_dout, Monitor *mon, MDSMap& mdsmap) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").mds e" << mdsmap.get_epoch() << " "; } // my methods void MDSMonitor::print_map(MDSMap &m, int dbl) { dout(dbl) << "print_map\n"; m.print(*_dout); *_dout << dendl; } void MDSMonitor::create_new_fs(MDSMap &m, int metadata_pool, int data_pool) { m.max_mds = g_conf->max_mds; m.created = ceph_clock_now(g_ceph_context); m.data_pools.insert(data_pool); m.metadata_pool = metadata_pool; m.cas_pool = -1; m.compat = get_mdsmap_compat_set_default(); m.session_timeout = g_conf->mds_session_timeout; m.session_autoclose = g_conf->mds_session_autoclose; m.max_file_size = g_conf->mds_max_file_size; print_map(m); } // service methods void MDSMonitor::create_initial() { dout(10) << "create_initial" << dendl; create_new_fs(pending_mdsmap, MDS_METADATA_POOL, MDS_DATA_POOL); } void MDSMonitor::update_from_paxos(bool *need_bootstrap) { version_t version = get_last_committed(); if (version == mdsmap.epoch) return; assert(version >= mdsmap.epoch); dout(10) << __func__ << " version " << version << ", my e " << mdsmap.epoch << dendl; // read and decode mdsmap_bl.clear(); int err = get_version(version, mdsmap_bl); assert(err == 0); assert(mdsmap_bl.length() > 0); dout(10) << __func__ << " got " << version << dendl; mdsmap.decode(mdsmap_bl); // new map dout(4) << "new map" << dendl; print_map(mdsmap, 0); check_subs(); update_logger(); } void MDSMonitor::create_pending() { pending_mdsmap = mdsmap; pending_mdsmap.epoch++; dout(10) << "create_pending e" << pending_mdsmap.epoch << dendl; } void MDSMonitor::encode_pending(MonitorDBStore::Transaction *t) { dout(10) << "encode_pending e" << pending_mdsmap.epoch << dendl; pending_mdsmap.modified = ceph_clock_now(g_ceph_context); // print map iff 'debug mon = 30' or higher print_map(pending_mdsmap, 30); // apply to paxos assert(get_last_committed() + 1 == pending_mdsmap.epoch); bufferlist mdsmap_bl; pending_mdsmap.encode(mdsmap_bl, mon->get_quorum_features()); /* put everything in the transaction */ put_version(t, pending_mdsmap.epoch, mdsmap_bl); put_last_committed(t, pending_mdsmap.epoch); } version_t MDSMonitor::get_trim_to() { version_t floor = 0; if (g_conf->mon_mds_force_trim_to > 0 && g_conf->mon_mds_force_trim_to < (int)get_last_committed()) { floor = g_conf->mon_mds_force_trim_to; dout(10) << __func__ << " explicit mon_mds_force_trim_to = " << floor << dendl; } unsigned max = g_conf->mon_max_mdsmap_epochs; version_t last = get_last_committed(); if (last - get_first_committed() > max && floor < last - max) return last - max; return floor; } void MDSMonitor::update_logger() { dout(10) << "update_logger" << dendl; mon->cluster_logger->set(l_cluster_num_mds_up, mdsmap.get_num_up_mds()); mon->cluster_logger->set(l_cluster_num_mds_in, mdsmap.get_num_in_mds()); mon->cluster_logger->set(l_cluster_num_mds_failed, mdsmap.get_num_failed_mds()); mon->cluster_logger->set(l_cluster_mds_epoch, mdsmap.get_epoch()); } bool MDSMonitor::preprocess_query(PaxosServiceMessage *m) { dout(10) << "preprocess_query " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_MDS_BEACON: return preprocess_beacon(static_cast(m)); case MSG_MON_COMMAND: return preprocess_command(static_cast(m)); case MSG_MDS_OFFLOAD_TARGETS: return preprocess_offload_targets(static_cast(m)); default: assert(0); m->put(); return true; } } void MDSMonitor::_note_beacon(MMDSBeacon *m) { uint64_t gid = m->get_global_id(); version_t seq = m->get_seq(); dout(15) << "_note_beacon " << *m << " noting time" << dendl; last_beacon[gid].stamp = ceph_clock_now(g_ceph_context); last_beacon[gid].seq = seq; } bool MDSMonitor::preprocess_beacon(MMDSBeacon *m) { int state = m->get_state(); uint64_t gid = m->get_global_id(); version_t seq = m->get_seq(); MDSMap::mds_info_t info; // check privileges, ignore if fails MonSession *session = m->get_session(); assert(session); if (!session->is_capable("mds", MON_CAP_X)) { dout(0) << "preprocess_beacon got MMDSBeacon from entity with insufficient privileges " << session->caps << dendl; goto ignore; } if (m->get_fsid() != mon->monmap->fsid) { dout(0) << "preprocess_beacon on fsid " << m->get_fsid() << " != " << mon->monmap->fsid << dendl; goto ignore; } dout(12) << "preprocess_beacon " << *m << " from " << m->get_orig_source_inst() << " " << m->get_compat() << dendl; // make sure the address has a port if (m->get_orig_source_addr().get_port() == 0) { dout(1) << " ignoring boot message without a port" << dendl; goto ignore; } // check compat if (!m->get_compat().writeable(mdsmap.compat)) { dout(1) << " mds " << m->get_source_inst() << " can't write to mdsmap " << mdsmap.compat << dendl; goto ignore; } // fw to leader? if (!mon->is_leader()) return false; if (pending_mdsmap.test_flag(CEPH_MDSMAP_DOWN)) { dout(7) << " mdsmap DOWN flag set, ignoring mds " << m->get_source_inst() << " beacon" << dendl; goto ignore; } // booted, but not in map? if (pending_mdsmap.is_dne_gid(gid)) { if (state != MDSMap::STATE_BOOT) { dout(7) << "mds_beacon " << *m << " is not in mdsmap" << dendl; mon->send_reply(m, new MMDSMap(mon->monmap->fsid, &mdsmap)); m->put(); return true; } else { return false; // not booted yet. } } info = pending_mdsmap.get_info_gid(gid); // old seq? if (info.state_seq > seq) { dout(7) << "mds_beacon " << *m << " has old seq, ignoring" << dendl; goto ignore; } if (mdsmap.get_epoch() != m->get_last_epoch_seen()) { dout(10) << "mds_beacon " << *m << " ignoring requested state, because mds hasn't seen latest map" << dendl; goto reply; } if (info.laggy()) { _note_beacon(m); return false; // no longer laggy, need to update map. } if (state == MDSMap::STATE_BOOT) { // ignore, already booted. goto ignore; } // is there a state change here? if (info.state != state) { // legal state change? if ((info.state == MDSMap::STATE_STANDBY || info.state == MDSMap::STATE_STANDBY_REPLAY || info.state == MDSMap::STATE_ONESHOT_REPLAY) && state > 0) { dout(10) << "mds_beacon mds can't activate itself (" << ceph_mds_state_name(info.state) << " -> " << ceph_mds_state_name(state) << ")" << dendl; goto reply; } if (info.state == MDSMap::STATE_STANDBY && (state == MDSMap::STATE_STANDBY_REPLAY || state == MDSMap::STATE_ONESHOT_REPLAY) && (pending_mdsmap.is_degraded() || ((m->get_standby_for_rank() >= 0) && pending_mdsmap.get_state(m->get_standby_for_rank()) < MDSMap::STATE_ACTIVE))) { dout(10) << "mds_beacon can't standby-replay mds." << m->get_standby_for_rank() << " at this time (cluster degraded, or mds not active)" << dendl; dout(10) << "pending_mdsmap.is_degraded()==" << pending_mdsmap.is_degraded() << " rank state: " << ceph_mds_state_name(pending_mdsmap.get_state(m->get_standby_for_rank())) << dendl; goto reply; } _note_beacon(m); return false; // need to update map } reply: // note time and reply _note_beacon(m); mon->send_reply(m, new MMDSBeacon(mon->monmap->fsid, m->get_global_id(), m->get_name(), mdsmap.get_epoch(), state, seq)); m->put(); return true; ignore: // I won't reply this beacon, drop it. mon->no_reply(m); m->put(); return true; } bool MDSMonitor::preprocess_offload_targets(MMDSLoadTargets* m) { dout(10) << "preprocess_offload_targets " << *m << " from " << m->get_orig_source() << dendl; uint64_t gid; // check privileges, ignore message if fails MonSession *session = m->get_session(); if (!session) goto done; if (!session->is_capable("mds", MON_CAP_X)) { dout(0) << "preprocess_offload_targets got MMDSLoadTargets from entity with insufficient caps " << session->caps << dendl; goto done; } gid = m->global_id; if (mdsmap.mds_info.count(gid) && m->targets == mdsmap.mds_info[gid].export_targets) goto done; return false; done: m->put(); return true; } bool MDSMonitor::prepare_update(PaxosServiceMessage *m) { dout(7) << "prepare_update " << *m << dendl; switch (m->get_type()) { case MSG_MDS_BEACON: return prepare_beacon(static_cast(m)); case MSG_MON_COMMAND: return prepare_command(static_cast(m)); case MSG_MDS_OFFLOAD_TARGETS: return prepare_offload_targets(static_cast(m)); default: assert(0); m->put(); } return true; } bool MDSMonitor::prepare_beacon(MMDSBeacon *m) { // -- this is an update -- dout(12) << "prepare_beacon " << *m << " from " << m->get_orig_source_inst() << dendl; entity_addr_t addr = m->get_orig_source_inst().addr; uint64_t gid = m->get_global_id(); int state = m->get_state(); version_t seq = m->get_seq(); // boot? if (state == MDSMap::STATE_BOOT) { // zap previous instance of this name? if (g_conf->mds_enforce_unique_name) { bool failed_mds = false; while (uint64_t existing = pending_mdsmap.find_mds_gid_by_name(m->get_name())) { if (!mon->osdmon()->is_writeable()) { mon->osdmon()->wait_for_writeable(new C_RetryMessage(this, m)); return false; } fail_mds_gid(existing); failed_mds = true; } if (failed_mds) { assert(mon->osdmon()->is_writeable()); request_proposal(mon->osdmon()); } } // add MDSMap::mds_info_t& info = pending_mdsmap.mds_info[gid]; info.global_id = gid; info.name = m->get_name(); info.rank = -1; info.addr = addr; info.state = MDSMap::STATE_STANDBY; info.state_seq = seq; info.standby_for_rank = m->get_standby_for_rank(); info.standby_for_name = m->get_standby_for_name(); if (!info.standby_for_name.empty()) { const MDSMap::mds_info_t *leaderinfo = mdsmap.find_by_name(info.standby_for_name); if (leaderinfo && (leaderinfo->rank >= 0)) { info.standby_for_rank = mdsmap.find_by_name(info.standby_for_name)->rank; if (mdsmap.is_followable(info.standby_for_rank)) { info.state = MDSMap::STATE_STANDBY_REPLAY; } } } // initialize the beacon timer last_beacon[gid].stamp = ceph_clock_now(g_ceph_context); last_beacon[gid].seq = seq; // new incompat? if (!pending_mdsmap.compat.writeable(m->get_compat())) { dout(10) << " mdsmap " << pending_mdsmap.compat << " can't write to new mds' " << m->get_compat() << ", updating mdsmap and killing old mds's" << dendl; pending_mdsmap.compat = m->get_compat(); } } else { // state change MDSMap::mds_info_t& info = pending_mdsmap.get_info_gid(gid); if (info.laggy()) { dout(10) << "prepare_beacon clearing laggy flag on " << addr << dendl; info.clear_laggy(); } dout(10) << "prepare_beacon mds." << info.rank << " " << ceph_mds_state_name(info.state) << " -> " << ceph_mds_state_name(state) << " standby_for_rank=" << m->get_standby_for_rank() << dendl; if (state == MDSMap::STATE_STOPPED) { pending_mdsmap.up.erase(info.rank); pending_mdsmap.in.erase(info.rank); pending_mdsmap.stopped.insert(info.rank); pending_mdsmap.mds_info.erase(gid); // last! info is a ref into this map last_beacon.erase(gid); } else if (state == MDSMap::STATE_STANDBY_REPLAY) { if (m->get_standby_for_rank() == MDSMap::MDS_STANDBY_NAME) { /* convert name to rank. If we don't have it, do nothing. The mds will stay in standby and keep requesting the state change */ dout(20) << "looking for mds " << m->get_standby_for_name() << " to STANDBY_REPLAY for" << dendl; const MDSMap::mds_info_t *found_mds = NULL; if ((found_mds = mdsmap.find_by_name(m->get_standby_for_name())) && (found_mds->rank >= 0) && mdsmap.is_followable(found_mds->rank)) { info.standby_for_rank = found_mds->rank; dout(10) <<" found mds " << m->get_standby_for_name() << "; it has rank " << info.standby_for_rank << dendl; info.state = MDSMap::STATE_STANDBY_REPLAY; info.state_seq = seq; } else { m->put(); return false; } } else if (m->get_standby_for_rank() >= 0 && mdsmap.is_followable(m->get_standby_for_rank())) { /* switch to standby-replay for this MDS*/ info.state = MDSMap::STATE_STANDBY_REPLAY; info.state_seq = seq; info.standby_for_rank = m->get_standby_for_rank(); } else { //it's a standby for anybody, and is already in the list assert(pending_mdsmap.get_mds_info().count(info.global_id)); m->put(); return false; } } else { info.state = state; info.state_seq = seq; } } dout(7) << "prepare_beacon pending map now:" << dendl; print_map(pending_mdsmap); wait_for_finished_proposal(new C_Updated(this, m)); return true; } bool MDSMonitor::prepare_offload_targets(MMDSLoadTargets *m) { uint64_t gid = m->global_id; if (pending_mdsmap.mds_info.count(gid)) { dout(10) << "prepare_offload_targets " << gid << " " << m->targets << dendl; pending_mdsmap.mds_info[gid].export_targets = m->targets; } else { dout(10) << "prepare_offload_targets " << gid << " not in map" << dendl; } m->put(); return true; } bool MDSMonitor::should_propose(double& delay) { // delegate to PaxosService to assess whether we should propose return PaxosService::should_propose(delay); } void MDSMonitor::_updated(MMDSBeacon *m) { dout(10) << "_updated " << m->get_orig_source() << " " << *m << dendl; mon->clog.info() << m->get_orig_source_inst() << " " << ceph_mds_state_name(m->get_state()) << "\n"; if (m->get_state() == MDSMap::STATE_STOPPED) { // send the map manually (they're out of the map, so they won't get it automatic) mon->send_reply(m, new MMDSMap(mon->monmap->fsid, &mdsmap)); } else { mon->send_reply(m, new MMDSBeacon(mon->monmap->fsid, m->get_global_id(), m->get_name(), mdsmap.get_epoch(), m->get_state(), m->get_seq())); } m->put(); } void MDSMonitor::on_active() { tick(); update_logger(); if (mon->is_leader()) mon->clog.info() << "mdsmap " << mdsmap << "\n"; } void MDSMonitor::get_health(list >& summary, list > *detail) const { mdsmap.get_health(summary, detail); } void MDSMonitor::dump_info(Formatter *f) { f->open_object_section("mdsmap"); mdsmap.dump(f); f->close_section(); f->dump_unsigned("mdsmap_first_committed", get_first_committed()); f->dump_unsigned("mdsmap_last_committed", get_last_committed()); } bool MDSMonitor::preprocess_command(MMonCommand *m) { int r = -1; bufferlist rdata; stringstream ss, ds; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, rdata, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", rdata, get_last_committed()); return true; } if (prefix == "mds stat") { if (f) { f->open_object_section("mds_stat"); dump_info(f.get()); f->close_section(); f->flush(ds); } else { ds << mdsmap; } r = 0; } else if (prefix == "mds dump") { int64_t epocharg; epoch_t epoch; MDSMap *p = &mdsmap; if (cmd_getval(g_ceph_context, cmdmap, "epoch", epocharg)) { epoch = epocharg; bufferlist b; int err = get_version(epoch, b); if (err == -ENOENT) { p = 0; r = -ENOENT; } else { assert(err == 0); assert(b.length()); p = new MDSMap; p->decode(b); } } if (p) { stringstream ds; if (f != NULL) { f->open_object_section("mdsmap"); p->dump(f.get()); f->close_section(); f->flush(ds); r = 0; } else { p->print(ds); r = 0; } if (r == 0) { rdata.append(ds); ss << "dumped mdsmap epoch " << p->get_epoch(); } if (p != &mdsmap) delete p; } } else if (prefix == "mds getmap") { epoch_t e; int64_t epocharg; bufferlist b; if (cmd_getval(g_ceph_context, cmdmap, "epoch", epocharg)) { e = epocharg; int err = get_version(e, b); if (err == -ENOENT) { r = -ENOENT; } else { assert(r == 0); assert(b.length()); MDSMap mm; mm.decode(b); mm.encode(rdata, m->get_connection()->get_features()); ss << "got mdsmap epoch " << mm.get_epoch(); } } else { mdsmap.encode(rdata, m->get_connection()->get_features()); ss << "got mdsmap epoch " << mdsmap.get_epoch(); } r = 0; } else if (prefix == "mds tell") { string whostr; cmd_getval(g_ceph_context, cmdmap, "who", whostr); vectorargs_vec; cmd_getval(g_ceph_context, cmdmap, "args", args_vec); if (whostr == "*") { r = -ENOENT; const map mds_info = mdsmap.get_mds_info(); for (map::const_iterator i = mds_info.begin(); i != mds_info.end(); ++i) { m->cmd = args_vec; mon->send_command(i->second.get_inst(), m->cmd); r = 0; } if (r == -ENOENT) { ss << "no mds active"; } else { ss << "ok"; } } else { errno = 0; long who = strtol(whostr.c_str(), 0, 10); if (!errno && who >= 0) { if (mdsmap.is_up(who)) { m->cmd = args_vec; mon->send_command(mdsmap.get_inst(who), m->cmd); r = 0; ss << "ok"; } else { ss << "mds." << who << " not up"; r = -ENOENT; } } else ss << "specify mds number or *"; } } else if (prefix == "mds compat show") { if (f) { f->open_object_section("mds_compat"); mdsmap.compat.dump(f.get()); f->close_section(); f->flush(ds); } else { ds << mdsmap.compat; } r = 0; } if (r != -1) { rdata.append(ds); string rs; getline(ss, rs); mon->reply_command(m, r, rs, rdata, get_last_committed()); return true; } else return false; } void MDSMonitor::fail_mds_gid(uint64_t gid) { assert(pending_mdsmap.mds_info.count(gid)); MDSMap::mds_info_t& info = pending_mdsmap.mds_info[gid]; dout(10) << "fail_mds_gid " << gid << " mds." << info.name << " rank " << info.rank << dendl; utime_t until = ceph_clock_now(g_ceph_context); until += g_conf->mds_blacklist_interval; pending_mdsmap.last_failure_osd_epoch = mon->osdmon()->blacklist(info.addr, until); if (info.rank >= 0) { if (info.state == MDSMap::STATE_CREATING) { // If this gid didn't make it past CREATING, then forget // the rank ever existed so that next time it's handed out // to a gid it'll go back into CREATING. pending_mdsmap.in.erase(info.rank); } else { // Put this rank into the failed list so that the next available STANDBY will // pick it up. pending_mdsmap.failed.insert(info.rank); } pending_mdsmap.up.erase(info.rank); } pending_mdsmap.mds_info.erase(gid); } int MDSMonitor::fail_mds(std::ostream &ss, const std::string &arg) { std::string err; int w = strict_strtoll(arg.c_str(), 10, &err); if (!err.empty()) { // Try to interpret the arg as an MDS name const MDSMap::mds_info_t *mds_info = mdsmap.find_by_name(arg); if (!mds_info) { ss << "Can't find any MDS named '" << arg << "'"; return -ENOENT; } w = mds_info->rank; } if (!mon->osdmon()->is_writeable()) { return -EAGAIN; } bool failed_mds_gid = false; if (pending_mdsmap.up.count(w)) { uint64_t gid = pending_mdsmap.up[w]; if (pending_mdsmap.mds_info.count(gid)) { fail_mds_gid(gid); failed_mds_gid = true; } ss << "failed mds." << w; } else if (pending_mdsmap.mds_info.count(w)) { fail_mds_gid(w); failed_mds_gid = true; ss << "failed mds gid " << w; } if (failed_mds_gid) { assert(mon->osdmon()->is_writeable()); request_proposal(mon->osdmon()); } return 0; } bool MDSMonitor::prepare_command(MMonCommand *m) { int r = -EINVAL; stringstream ss; bufferlist rdata; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, rdata, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", rdata, get_last_committed()); return true; } string whostr; cmd_getval(g_ceph_context, cmdmap, "who", whostr); if (prefix == "mds stop" || prefix == "mds deactivate") { int who = parse_pos_long(whostr.c_str(), &ss); if (who < 0) goto out; if (!pending_mdsmap.is_active(who)) { r = -EEXIST; ss << "mds." << who << " not active (" << ceph_mds_state_name(pending_mdsmap.get_state(who)) << ")"; } else if ((pending_mdsmap.get_root() == who || pending_mdsmap.get_tableserver() == who) && pending_mdsmap.get_num_in_mds() > 1) { r = -EBUSY; ss << "can't tell the root (" << pending_mdsmap.get_root() << ") or tableserver (" << pending_mdsmap.get_tableserver() << " to deactivate unless it is the last mds in the cluster"; } else if (pending_mdsmap.get_num_in_mds() <= pending_mdsmap.get_max_mds()) { r = -EBUSY; ss << "must decrease max_mds or else MDS will immediately reactivate"; } else { r = 0; uint64_t gid = pending_mdsmap.up[who]; ss << "telling mds." << who << " " << pending_mdsmap.mds_info[gid].addr << " to deactivate"; pending_mdsmap.mds_info[gid].state = MDSMap::STATE_STOPPING; } } else if (prefix == "mds set_max_mds") { // NOTE: see also "mds set max_mds", which can modify the same field. int64_t maxmds; if (!cmd_getval(g_ceph_context, cmdmap, "maxmds", maxmds) || maxmds < 0) goto out; pending_mdsmap.max_mds = maxmds; r = 0; ss << "max_mds = " << pending_mdsmap.max_mds; } else if (prefix == "mds set") { string var; if (!cmd_getval(g_ceph_context, cmdmap, "var", var) || var.empty()) { ss << "Invalid variable"; goto out; } string val; string interr; int64_t n = 0; if (!cmd_getval(g_ceph_context, cmdmap, "val", val)) goto out; // we got a string. see if it contains an int. n = strict_strtoll(val.c_str(), 10, &interr); if (var == "max_mds") { // NOTE: see also "mds set_max_mds", which can modify the same field. if (interr.length()) goto out; pending_mdsmap.max_mds = n; } else if (var == "inline_data") { if (val == "true" || val == "yes" || (!interr.length() && n == 1)) { string confirm; if (!cmd_getval(g_ceph_context, cmdmap, "confirm", confirm) || confirm != "--yes-i-really-mean-it") { ss << "inline data is new and experimental; you must specify --yes-i-really-mean-it"; r = -EPERM; goto out; } ss << "inline data enabled"; pending_mdsmap.set_inline_data_enabled(true); pending_mdsmap.compat.incompat.insert(MDS_FEATURE_INCOMPAT_INLINE); } else if (val == "false" || val == "no" || (!interr.length() && n == 0)) { ss << "inline data disabled"; pending_mdsmap.set_inline_data_enabled(false); } else { ss << "value must be false|no|0 or true|yes|1"; r = -EINVAL; goto out; } } else if (var == "max_file_size") { if (interr.length()) { ss << var << " requires an integer value"; goto out; } if (n < CEPH_MIN_STRIPE_UNIT) { r = -ERANGE; ss << var << " must at least " << CEPH_MIN_STRIPE_UNIT; goto out; } pending_mdsmap.max_file_size = n; } else if (var == "allow_new_snaps") { if (val == "false" || val == "no" || (interr.length() == 0 && n == 0)) { pending_mdsmap.clear_snaps_allowed(); ss << "disabled new snapshots"; } else if (val == "true" || val == "yes" || (interr.length() == 0 && n == 1)) { string confirm; if (!cmd_getval(g_ceph_context, cmdmap, "confirm", confirm) || confirm != "--yes-i-really-mean-it") { ss << "Snapshots are unstable and will probably break your FS! Set to --yes-i-really-mean-it if you are sure you want to enable them"; r = -EPERM; goto out; } pending_mdsmap.set_snaps_allowed(); ss << "enabled new snapshots"; } else { ss << "value must be true|yes|1 or false|no|0"; r = -EINVAL; goto out; } } else { ss << "unknown variable " << var; goto out; } r = 0; } else if (prefix == "mds setmap") { MDSMap map; map.decode(m->get_data()); epoch_t e = 0; int64_t epochnum; if (cmd_getval(g_ceph_context, cmdmap, "epoch", epochnum)) e = epochnum; if (pending_mdsmap.epoch == e) { map.epoch = pending_mdsmap.epoch; // make sure epoch is correct pending_mdsmap = map; string rs = "set mds map"; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else { ss << "next mdsmap epoch " << pending_mdsmap.epoch << " != " << e; } } else if (prefix == "mds set_state") { int64_t gid; if (!cmd_getval(g_ceph_context, cmdmap, "gid", gid)) { ss << "error parsing 'gid' value '" << cmd_vartype_stringify(cmdmap["gid"]) << "'"; r = -EINVAL; goto out; } int64_t state; if (!cmd_getval(g_ceph_context, cmdmap, "state", state)) { ss << "error parsing 'state' string value '" << cmd_vartype_stringify(cmdmap["state"]) << "'"; r = -EINVAL; goto out; } if (!pending_mdsmap.is_dne_gid(gid)) { MDSMap::mds_info_t& info = pending_mdsmap.get_info_gid(gid); info.state = state; stringstream ss; ss << "set mds gid " << gid << " to state " << state << " " << ceph_mds_state_name(state); string rs; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else if (prefix == "mds fail") { string who; cmd_getval(g_ceph_context, cmdmap, "who", who); r = fail_mds(ss, who); if (r < 0 && r == -EAGAIN) { mon->osdmon()->wait_for_writeable(new C_RetryMessage(this, m)); return false; // don't propose yet; wait for message to be retried } } else if (prefix == "mds rm") { int64_t gid; if (!cmd_getval(g_ceph_context, cmdmap, "gid", gid)) { ss << "error parsing 'gid' value '" << cmd_vartype_stringify(cmdmap["gid"]) << "'"; r = -EINVAL; goto out; } int state = pending_mdsmap.get_state_gid(gid); if (state == 0) { ss << "mds gid " << gid << " dne"; r = 0; } else if (state > 0) { ss << "cannot remove active mds." << pending_mdsmap.get_info_gid(gid).name << " rank " << pending_mdsmap.get_info_gid(gid).rank; r = -EBUSY; } else { pending_mdsmap.mds_info.erase(gid); stringstream ss; ss << "removed mds gid " << gid; string rs; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else if (prefix == "mds rmfailed") { int64_t w; if (!cmd_getval(g_ceph_context, cmdmap, "who", w)) { ss << "error parsing 'who' value '" << cmd_vartype_stringify(cmdmap["who"]) << "'"; r = -EINVAL; goto out; } pending_mdsmap.failed.erase(w); stringstream ss; ss << "removed failed mds." << w; string rs; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "mds cluster_down") { if (pending_mdsmap.test_flag(CEPH_MDSMAP_DOWN)) { ss << "mdsmap already marked DOWN"; } else { pending_mdsmap.set_flag(CEPH_MDSMAP_DOWN); ss << "marked mdsmap DOWN"; } r = 0; } else if (prefix == "mds cluster_up") { if (pending_mdsmap.test_flag(CEPH_MDSMAP_DOWN)) { pending_mdsmap.clear_flag(CEPH_MDSMAP_DOWN); ss << "unmarked mdsmap DOWN"; } else { ss << "mdsmap not marked DOWN"; } r = 0; } else if (prefix == "mds compat rm_compat") { int64_t f; if (!cmd_getval(g_ceph_context, cmdmap, "feature", f)) { ss << "error parsing feature value '" << cmd_vartype_stringify(cmdmap["feature"]) << "'"; r = -EINVAL; goto out; } if (pending_mdsmap.compat.compat.contains(f)) { ss << "removing compat feature " << f; pending_mdsmap.compat.compat.remove(f); r = 0; } else { ss << "compat feature " << f << " not present in " << pending_mdsmap.compat; r = 0; } } else if (prefix == "mds compat rm_incompat") { int64_t f; if (!cmd_getval(g_ceph_context, cmdmap, "feature", f)) { ss << "error parsing feature value '" << cmd_vartype_stringify(cmdmap["feature"]) << "'"; r = -EINVAL; goto out; } if (pending_mdsmap.compat.incompat.contains(f)) { ss << "removing incompat feature " << f; pending_mdsmap.compat.incompat.remove(f); r = 0; } else { ss << "incompat feature " << f << " not present in " << pending_mdsmap.compat; r = 0; } } else if (prefix == "mds add_data_pool") { string poolname; cmd_getval(g_ceph_context, cmdmap, "pool", poolname); int64_t poolid = mon->osdmon()->osdmap.lookup_pg_pool_name(poolname); if (poolid < 0) { string err; poolid = strict_strtol(poolname.c_str(), 10, &err); if (err.length()) { r = -ENOENT; poolid = -1; ss << "pool '" << poolname << "' does not exist"; } } if (poolid >= 0) { pending_mdsmap.add_data_pool(poolid); ss << "added data pool " << poolid << " to mdsmap"; r = 0; } } else if (prefix == "mds remove_data_pool") { string poolname; cmd_getval(g_ceph_context, cmdmap, "pool", poolname); int64_t poolid = mon->osdmon()->osdmap.lookup_pg_pool_name(poolname); if (poolid < 0) { string err; poolid = strict_strtol(poolname.c_str(), 10, &err); if (err.length()) { r = -ENOENT; poolid = -1; ss << "pool '" << poolname << "' does not exist"; } } if (pending_mdsmap.get_first_data_pool() == poolid) { r = -EINVAL; poolid = -1; ss << "cannot remove default data pool"; } if (poolid >= 0) { cmd_getval(g_ceph_context, cmdmap, "poolid", poolid); r = pending_mdsmap.remove_data_pool(poolid); if (r == -ENOENT) r = 0; if (r == 0) ss << "removed data pool " << poolid << " from mdsmap"; } } else if (prefix == "mds newfs") { MDSMap newmap; int64_t metadata, data; if (!cmd_getval(g_ceph_context, cmdmap, "metadata", metadata)) { ss << "error parsing 'metadata' value '" << cmd_vartype_stringify(cmdmap["metadata"]) << "'"; r = -EINVAL; goto out; } if (!cmd_getval(g_ceph_context, cmdmap, "data", data)) { ss << "error parsing 'data' value '" << cmd_vartype_stringify(cmdmap["data"]) << "'"; r = -EINVAL; goto out; } string sure; cmd_getval(g_ceph_context, cmdmap, "sure", sure); if (sure != "--yes-i-really-mean-it") { ss << "this is DANGEROUS and will wipe out the mdsmap's fs, and may clobber data in the new pools you specify. add --yes-i-really-mean-it if you do."; r = -EPERM; } else { newmap.inc = pending_mdsmap.inc; pending_mdsmap = newmap; pending_mdsmap.epoch = mdsmap.epoch + 1; create_new_fs(pending_mdsmap, metadata, data); ss << "new fs with metadata pool " << metadata << " and data pool " << data; string rs; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else { ss << "unrecognized command"; } out: string rs; getline(ss, rs); if (r >= 0) { // success.. delay reply wait_for_finished_proposal(new Monitor::C_Command(mon, m, r, rs, get_last_committed() + 1)); return true; } else { // reply immediately mon->reply_command(m, r, rs, rdata, get_last_committed()); return false; } } void MDSMonitor::check_subs() { string type = "mdsmap"; if (mon->session_map.subs.count(type) == 0) return; xlist::iterator p = mon->session_map.subs[type]->begin(); while (!p.end()) { Subscription *sub = *p; ++p; check_sub(sub); } } void MDSMonitor::check_sub(Subscription *sub) { if (sub->next <= mdsmap.get_epoch()) { mon->messenger->send_message(new MMDSMap(mon->monmap->fsid, &mdsmap), sub->session->inst); if (sub->onetime) mon->session_map.remove_sub(sub); else sub->next = mdsmap.get_epoch() + 1; } } void MDSMonitor::tick() { // make sure mds's are still alive // ...if i am an active leader if (!is_active()) return; dout(10) << mdsmap << dendl; bool do_propose = false; if (!mon->is_leader()) return; // expand mds cluster (add new nodes to @in)? while (pending_mdsmap.get_num_in_mds() < pending_mdsmap.get_max_mds() && !pending_mdsmap.is_degraded()) { int mds = 0; string name; while (pending_mdsmap.is_in(mds)) mds++; uint64_t newgid = pending_mdsmap.find_replacement_for(mds, name); if (!newgid) break; MDSMap::mds_info_t& info = pending_mdsmap.mds_info[newgid]; dout(1) << "adding standby " << info.addr << " as mds." << mds << dendl; info.rank = mds; if (pending_mdsmap.stopped.count(mds)) { info.state = MDSMap::STATE_STARTING; pending_mdsmap.stopped.erase(mds); } else info.state = MDSMap::STATE_CREATING; info.inc = ++pending_mdsmap.inc[mds]; pending_mdsmap.in.insert(mds); pending_mdsmap.up[mds] = newgid; do_propose = true; } // check beacon timestamps utime_t now = ceph_clock_now(g_ceph_context); utime_t cutoff = now; cutoff -= g_conf->mds_beacon_grace; // make sure last_beacon is fully populated for (map::iterator p = pending_mdsmap.mds_info.begin(); p != pending_mdsmap.mds_info.end(); ++p) { if (last_beacon.count(p->first) == 0) { const MDSMap::mds_info_t& info = p->second; dout(10) << " adding " << p->second.addr << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << " to last_beacon" << dendl; last_beacon[p->first].stamp = ceph_clock_now(g_ceph_context); last_beacon[p->first].seq = 0; } } if (mon->osdmon()->is_writeable()) { bool propose_osdmap = false; map::iterator p = last_beacon.begin(); while (p != last_beacon.end()) { uint64_t gid = p->first; utime_t since = p->second.stamp; uint64_t seq = p->second.seq; ++p; if (pending_mdsmap.mds_info.count(gid) == 0) { // clean it out last_beacon.erase(gid); continue; } if (since >= cutoff) continue; MDSMap::mds_info_t& info = pending_mdsmap.mds_info[gid]; dout(10) << "no beacon from " << gid << " " << info.addr << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << " since " << since << dendl; // are we in? // and is there a non-laggy standby that can take over for us? uint64_t sgid; if (info.rank >= 0 && info.state != MDSMap::STATE_STANDBY && info.state != MDSMap::STATE_STANDBY_REPLAY && (sgid = pending_mdsmap.find_replacement_for(info.rank, info.name)) != 0) { MDSMap::mds_info_t& si = pending_mdsmap.mds_info[sgid]; dout(10) << " replacing " << gid << " " << info.addr << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << " with " << sgid << "/" << si.name << " " << si.addr << dendl; switch (info.state) { case MDSMap::STATE_CREATING: case MDSMap::STATE_STARTING: si.state = info.state; break; case MDSMap::STATE_REPLAY: case MDSMap::STATE_RESOLVE: case MDSMap::STATE_RECONNECT: case MDSMap::STATE_REJOIN: case MDSMap::STATE_CLIENTREPLAY: case MDSMap::STATE_ACTIVE: case MDSMap::STATE_STOPPING: si.state = MDSMap::STATE_REPLAY; break; default: assert(0); } info.state_seq = seq; si.rank = info.rank; si.inc = ++pending_mdsmap.inc[info.rank]; pending_mdsmap.up[info.rank] = sgid; if (si.state > 0) pending_mdsmap.last_failure = pending_mdsmap.epoch; if (si.state > 0 || si.state == MDSMap::STATE_CREATING || si.state == MDSMap::STATE_STARTING) { // blacklist laggy mds utime_t until = now; until += g_conf->mds_blacklist_interval; pending_mdsmap.last_failure_osd_epoch = mon->osdmon()->blacklist(info.addr, until); propose_osdmap = true; } pending_mdsmap.mds_info.erase(gid); last_beacon.erase(gid); do_propose = true; } else if (info.state == MDSMap::STATE_STANDBY_REPLAY) { dout(10) << " failing " << gid << " " << info.addr << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << dendl; pending_mdsmap.mds_info.erase(gid); last_beacon.erase(gid); do_propose = true; } else { if (info.state == MDSMap::STATE_STANDBY || info.state == MDSMap::STATE_STANDBY_REPLAY) { // remove it dout(10) << " removing " << gid << " " << info.addr << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << " (laggy)" << dendl; pending_mdsmap.mds_info.erase(gid); do_propose = true; } else if (!info.laggy()) { dout(10) << " marking " << gid << " " << info.addr << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << " laggy" << dendl; info.laggy_since = now; do_propose = true; } last_beacon.erase(gid); } } if (propose_osdmap) request_proposal(mon->osdmon()); } // have a standby take over? set failed; pending_mdsmap.get_failed_mds_set(failed); if (!failed.empty()) { set::iterator p = failed.begin(); while (p != failed.end()) { int f = *p++; uint64_t sgid; string name; // FIXME sgid = pending_mdsmap.find_replacement_for(f, name); if (sgid) { MDSMap::mds_info_t& si = pending_mdsmap.mds_info[sgid]; dout(0) << " taking over failed mds." << f << " with " << sgid << "/" << si.name << " " << si.addr << dendl; si.state = MDSMap::STATE_REPLAY; si.rank = f; si.inc = ++pending_mdsmap.inc[f]; pending_mdsmap.in.insert(f); pending_mdsmap.up[f] = sgid; pending_mdsmap.failed.erase(f); do_propose = true; } } } // have a standby follow someone? if (failed.empty()) { for (map::iterator j = pending_mdsmap.mds_info.begin(); j != pending_mdsmap.mds_info.end(); ++j) { MDSMap::mds_info_t& info = j->second; if (info.state != MDSMap::STATE_STANDBY) continue; /* * This mds is standby but has no rank assigned. * See if we can find it somebody to shadow */ dout(20) << "gid " << j->first << " is standby and following nobody" << dendl; // standby for someone specific? if (info.standby_for_rank >= 0) { if (pending_mdsmap.is_followable(info.standby_for_rank) && try_standby_replay(info, pending_mdsmap.mds_info[pending_mdsmap.up[info.standby_for_rank]])) do_propose = true; continue; } // check everyone for (map::iterator i = pending_mdsmap.mds_info.begin(); i != pending_mdsmap.mds_info.end(); ++i) { if (i->second.rank >= 0 && pending_mdsmap.is_followable(i->second.rank)) { if ((info.standby_for_name.length() && info.standby_for_name != i->second.name) || info.standby_for_rank >= 0) continue; // we're supposed to follow someone else if (info.standby_for_rank == MDSMap::MDS_STANDBY_ANY && try_standby_replay(info, i->second)) { do_propose = true; break; } continue; } } } } if (do_propose) propose_pending(); } bool MDSMonitor::try_standby_replay(MDSMap::mds_info_t& finfo, MDSMap::mds_info_t& ainfo) { // someone else already following? uint64_t lgid = pending_mdsmap.find_standby_for(ainfo.rank, ainfo.name); if (lgid) { MDSMap::mds_info_t& sinfo = pending_mdsmap.mds_info[lgid]; dout(20) << " mds." << ainfo.rank << " standby gid " << lgid << " with state " << ceph_mds_state_name(sinfo.state) << dendl; if (sinfo.state == MDSMap::STATE_STANDBY_REPLAY) { dout(20) << " skipping this MDS since it has a follower!" << dendl; return false; // this MDS already has a standby } } // hey, we found an MDS without a standby. Pair them! finfo.standby_for_rank = ainfo.rank; dout(10) << " setting to shadow mds rank " << finfo.standby_for_rank << dendl; finfo.state = MDSMap::STATE_STANDBY_REPLAY; return true; } ceph-0.80.11/src/mon/Monitor.h0000664000175100017510000006606712623076744020074 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* * This is the top level monitor. It runs on each machine in the Monitor * Cluster. The election of a leader for the paxos algorithm only happens * once per machine via the elector. There is a separate paxos instance (state) * kept for each of the system components: Object Store Device (OSD) Monitor, * Placement Group (PG) Monitor, Metadata Server (MDS) Monitor, and Client Monitor. */ #ifndef CEPH_MONITOR_H #define CEPH_MONITOR_H #include "include/types.h" #include "msg/Messenger.h" #include "common/Timer.h" #include "MonMap.h" #include "Elector.h" #include "Paxos.h" #include "Session.h" #include "osd/OSDMap.h" #include "common/LogClient.h" #include "common/SimpleRNG.h" #include "common/cmdparse.h" #include "auth/cephx/CephxKeyServer.h" #include "auth/AuthMethodList.h" #include "auth/KeyRing.h" #include "perfglue/heap_profiler.h" #include "messages/MMonCommand.h" #include "messages/MPing.h" #include "mon/MonitorStore.h" #include "mon/MonitorDBStore.h" #include #include "include/memory.h" #include #define CEPH_MON_PROTOCOL 13 /* cluster internal */ enum { l_cluster_first = 555000, l_cluster_num_mon, l_cluster_num_mon_quorum, l_cluster_num_osd, l_cluster_num_osd_up, l_cluster_num_osd_in, l_cluster_osd_epoch, l_cluster_osd_kb, l_cluster_osd_kb_used, l_cluster_osd_kb_avail, l_cluster_num_pool, l_cluster_num_pg, l_cluster_num_pg_active_clean, l_cluster_num_pg_active, l_cluster_num_pg_peering, l_cluster_num_object, l_cluster_num_object_degraded, l_cluster_num_object_unfound, l_cluster_num_bytes, l_cluster_num_mds_up, l_cluster_num_mds_in, l_cluster_num_mds_failed, l_cluster_mds_epoch, l_cluster_last, }; class QuorumService; class PaxosService; class PerfCounters; class AdminSocketHook; class MMonGetMap; class MMonGetVersion; class MMonSync; class MMonScrub; class MMonProbe; struct MMonSubscribe; class MAuthRotating; struct MRoute; struct MForward; struct MTimeCheck; struct MMonHealth; struct MonCommand; #define COMPAT_SET_LOC "feature_set" class Monitor : public Dispatcher { public: // me string name; int rank; Messenger *messenger; ConnectionRef con_self; Mutex lock; SafeTimer timer; /// true if we have ever joined a quorum. if false, we are either a /// new cluster, a newly joining monitor, or a just-upgraded /// monitor. bool has_ever_joined; PerfCounters *logger, *cluster_logger; bool cluster_logger_registered; void register_cluster_logger(); void unregister_cluster_logger(); MonMap *monmap; uuid_d fingerprint; set extra_probe_peers; LogClient clog; KeyRing keyring; KeyServer key_server; AuthMethodList auth_cluster_required; AuthMethodList auth_service_required; CompatSet features; const MonCommand *leader_supported_mon_commands; int leader_supported_mon_commands_size; private: void new_tick(); friend class C_Mon_Tick; // -- local storage -- public: MonitorDBStore *store; static const string MONITOR_NAME; static const string MONITOR_STORE_PREFIX; // -- monitor state -- private: enum { STATE_PROBING = 1, STATE_SYNCHRONIZING, STATE_ELECTING, STATE_LEADER, STATE_PEON, STATE_SHUTDOWN }; int state; public: static const char *get_state_name(int s) { switch (s) { case STATE_PROBING: return "probing"; case STATE_SYNCHRONIZING: return "synchronizing"; case STATE_ELECTING: return "electing"; case STATE_LEADER: return "leader"; case STATE_PEON: return "peon"; case STATE_SHUTDOWN: return "shutdown"; default: return "???"; } } const char *get_state_name() const { return get_state_name(state); } bool is_shutdown() const { return state == STATE_SHUTDOWN; } bool is_probing() const { return state == STATE_PROBING; } bool is_synchronizing() const { return state == STATE_SYNCHRONIZING; } bool is_electing() const { return state == STATE_ELECTING; } bool is_leader() const { return state == STATE_LEADER; } bool is_peon() const { return state == STATE_PEON; } const utime_t &get_leader_since() const; void prepare_new_fingerprint(MonitorDBStore::Transaction *t); // -- elector -- private: Paxos *paxos; Elector elector; friend class Elector; /// features we require of peers (based on on-disk compatset) uint64_t required_features; int leader; // current leader (to best of knowledge) set quorum; // current active set of monitors (if !starting) utime_t leader_since; // when this monitor became the leader, if it is the leader utime_t exited_quorum; // time detected as not in quorum; 0 if in uint64_t quorum_features; ///< intersection of quorum member feature bits bufferlist supported_commands_bl; // encoded MonCommands we support bufferlist classic_commands_bl; // encoded MonCommands supported by Dumpling set classic_mons; // set of "classic" monitors; only valid on leader set outside_quorum; /** * @defgroup scrub * @{ */ version_t scrub_version; ///< paxos version we are scrubbing map scrub_result; ///< results so far /** * trigger a cross-mon scrub * * Verify all mons are storing identical content */ int scrub(); void handle_scrub(MMonScrub *m); void _scrub(ScrubResult *r); void scrub_finish(); void scrub_reset(); /** * @defgroup Synchronization * @{ */ /** * @} // provider state */ struct SyncProvider { entity_inst_t entity; ///< who uint64_t cookie; ///< unique cookie for this sync attempt utime_t timeout; ///< when we give up and expire this attempt version_t last_committed; ///< last paxos version on peer pair last_key; ///< last key sent to (or on) peer bool full; ///< full scan? MonitorDBStore::Synchronizer synchronizer; ///< iterator SyncProvider() : cookie(0), last_committed(0), full(false) {} void reset_timeout(CephContext *cct, int grace) { timeout = ceph_clock_now(cct); timeout += grace; } }; map sync_providers; ///< cookie -> SyncProvider for those syncing from us uint64_t sync_provider_count; ///< counter for issued cookies to keep them unique /** * @} // requester state */ entity_inst_t sync_provider; ///< who we are syncing from uint64_t sync_cookie; ///< 0 if we are starting, non-zero otherwise bool sync_full; ///< true if we are a full sync, false for recent catch-up version_t sync_start_version; ///< last_committed at sync start Context *sync_timeout_event; ///< timeout event /** * floor for sync source * * When we sync we forget about our old last_committed value which * can be dangerous. For example, if we have a cluster of: * * mon.a: lc 100 * mon.b: lc 80 * mon.c: lc 100 (us) * * If something forces us to sync (say, corruption, or manual * intervention, or bug), we forget last_committed, and might abort. * If mon.a happens to be down when we come back, we will see: * * mon.b: lc 80 * mon.c: lc 0 (us) * * and sync from mon.b, at which point a+b will both have lc 80 and * come online with a majority holding out of date commits. * * Avoid this by preserving our old last_committed value prior to * sync and never going backwards. */ version_t sync_last_committed_floor; struct C_SyncTimeout : public Context { Monitor *mon; C_SyncTimeout(Monitor *m) : mon(m) {} void finish(int r) { mon->sync_timeout(); } }; /** * Obtain the synchronization target prefixes in set form. * * We consider a target prefix all those that are relevant when * synchronizing two stores. That is, all those that hold paxos service's * versions, as well as paxos versions, or any control keys such as the * first or last committed version. * * Given the current design, this function should return the name of all and * any available paxos service, plus the paxos name. * * @returns a set of strings referring to the prefixes being synchronized */ set get_sync_targets_names(); /** * Reset the monitor's sync-related data structures for syncing *from* a peer */ void sync_reset_requester(); /** * Reset sync state related to allowing others to sync from us */ void sync_reset_provider(); /** * Caled when a sync attempt times out (requester-side) */ void sync_timeout(); /** * Get the latest monmap for backup purposes during sync */ void sync_obtain_latest_monmap(bufferlist &bl); /** * Start sync process * * Start pulling committed state from another monitor. * * @param entity where to pull committed state from * @param full whether to do a full sync or just catch up on recent paxos */ void sync_start(entity_inst_t &entity, bool full); public: /** * force a sync on next mon restart */ void sync_force(Formatter *f, ostream& ss); private: /** * store critical state for safekeeping during sync * * We store a few things on the side that we don't want to get clobbered by sync. This * includes the latest monmap and a lower bound on last_committed. */ void sync_stash_critical_state(MonitorDBStore::Transaction *tx); /** * reset the sync timeout * * This is used on the client to restart if things aren't progressing */ void sync_reset_timeout(); /** * trim stale sync provider state * * If someone is syncing from us and hasn't talked to us recently, expire their state. */ void sync_trim_providers(); /** * Complete a sync * * Finish up a sync after we've gotten all of the chunks. * * @param last_committed final last_committed value from provider */ void sync_finish(version_t last_committed); /** * request the next chunk from the provider */ void sync_get_next_chunk(); /** * handle sync message * * @param m Sync message with operation type MMonSync::OP_START_CHUNKS */ void handle_sync(MMonSync *m); void _sync_reply_no_cookie(MMonSync *m); void handle_sync_get_cookie(MMonSync *m); void handle_sync_get_chunk(MMonSync *m); void handle_sync_finish(MMonSync *m); void handle_sync_cookie(MMonSync *m); void handle_sync_forward(MMonSync *m); void handle_sync_chunk(MMonSync *m); void handle_sync_no_cookie(MMonSync *m); /** * @} // Synchronization */ list waitfor_quorum; list maybe_wait_for_quorum; /** * @defgroup Monitor_h_TimeCheck Monitor Clock Drift Early Warning System * @{ * * We use time checks to keep track of any clock drifting going on in the * cluster. This is accomplished by periodically ping each monitor in the * quorum and register its response time on a map, assessing how much its * clock has drifted. We also take this opportunity to assess the latency * on response. * * This mechanism works as follows: * * - Leader sends out a 'PING' message to each other monitor in the quorum. * The message is timestamped with the leader's current time. The leader's * current time is recorded in a map, associated with each peon's * instance. * - The peon replies to the leader with a timestamped 'PONG' message. * - The leader calculates a delta between the peon's timestamp and its * current time and stashes it. * - The leader also calculates the time it took to receive the 'PONG' * since the 'PING' was sent, and stashes an approximate latency estimate. * - Once all the quorum members have pong'ed, the leader will share the * clock skew and latency maps with all the monitors in the quorum. */ map timecheck_waiting; map timecheck_skews; map timecheck_latencies; // odd value means we are mid-round; even value means the round has // finished. version_t timecheck_round; unsigned int timecheck_acks; utime_t timecheck_round_start; /** * Time Check event. */ Context *timecheck_event; struct C_TimeCheck : public Context { Monitor *mon; C_TimeCheck(Monitor *m) : mon(m) { } void finish(int r) { mon->timecheck_start_round(); } }; void timecheck_start(); void timecheck_finish(); void timecheck_start_round(); void timecheck_finish_round(bool success = true); void timecheck_cancel_round(); void timecheck_cleanup(); void timecheck_report(); void timecheck(); health_status_t timecheck_status(ostringstream &ss, const double skew_bound, const double latency); void handle_timecheck_leader(MTimeCheck *m); void handle_timecheck_peon(MTimeCheck *m); void handle_timecheck(MTimeCheck *m); /** * @} */ /** * @defgroup Monitor_h_stats Keep track of monitor statistics * @{ */ struct MonStatsEntry { // data dir uint64_t kb_total; uint64_t kb_used; uint64_t kb_avail; unsigned int latest_avail_ratio; utime_t last_update; }; struct MonStats { MonStatsEntry ours; map others; }; MonStats stats; void stats_update(); /** * @} */ /** * Handle ping messages from others. */ void handle_ping(MPing *m); Context *probe_timeout_event; // for probing struct C_ProbeTimeout : public Context { Monitor *mon; C_ProbeTimeout(Monitor *m) : mon(m) {} void finish(int r) { mon->probe_timeout(r); } }; void reset_probe_timeout(); void cancel_probe_timeout(); void probe_timeout(int r); public: epoch_t get_epoch(); int get_leader() { return leader; } const set& get_quorum() { return quorum; } list get_quorum_names() { list q; for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) q.push_back(monmap->get_name(*p)); return q; } uint64_t get_quorum_features() const { return quorum_features; } uint64_t get_required_features() const { return quorum_features; } void apply_quorum_to_compatset_features(); void apply_compatset_features_to_quorum_requirements(); private: void _reset(); ///< called from bootstrap, start_, or join_election public: void bootstrap(); void join_election(); void start_election(); void win_standalone_election(); // end election (called by Elector) void win_election(epoch_t epoch, set& q, uint64_t features, const MonCommand *cmdset, int cmdsize, const set *classic_monitors); void lose_election(epoch_t epoch, set& q, int l, uint64_t features); // end election (called by Elector) void finish_election(); const bufferlist& get_supported_commands_bl() { return supported_commands_bl; } const bufferlist& get_classic_commands_bl() { return classic_commands_bl; } const set& get_classic_mons() { return classic_mons; } void update_logger(); /** * Vector holding the Services serviced by this Monitor. */ vector paxos_service; PaxosService *get_paxos_service_by_name(const string& name); class PGMonitor *pgmon() { return (class PGMonitor *)paxos_service[PAXOS_PGMAP]; } class MDSMonitor *mdsmon() { return (class MDSMonitor *)paxos_service[PAXOS_MDSMAP]; } class MonmapMonitor *monmon() { return (class MonmapMonitor *)paxos_service[PAXOS_MONMAP]; } class OSDMonitor *osdmon() { return (class OSDMonitor *)paxos_service[PAXOS_OSDMAP]; } class AuthMonitor *authmon() { return (class AuthMonitor *)paxos_service[PAXOS_AUTH]; } class LogMonitor *logmon() { return (class LogMonitor*) paxos_service[PAXOS_LOG]; } friend class Paxos; friend class OSDMonitor; friend class MDSMonitor; friend class MonmapMonitor; friend class PGMonitor; friend class LogMonitor; QuorumService *health_monitor; QuorumService *config_key_service; // -- sessions -- MonSessionMap session_map; AdminSocketHook *admin_hook; void check_subs(); void check_sub(Subscription *sub); void send_latest_monmap(Connection *con); // messages void handle_get_version(MMonGetVersion *m); void handle_subscribe(MMonSubscribe *m); void handle_mon_get_map(MMonGetMap *m); static void _generate_command_map(map& cmdmap, map ¶m_str_map); static const MonCommand *_get_moncommand(const string &cmd_prefix, MonCommand *cmds, int cmds_size); bool _allowed_command(MonSession *s, string &module, string &prefix, const map& cmdmap, const map& param_str_map, const MonCommand *this_cmd); void get_mon_status(Formatter *f, ostream& ss); void _quorum_status(Formatter *f, ostream& ss); void _osdmonitor_prepare_command(cmdmap_t& cmdmap, ostream& ss); void _add_bootstrap_peer_hint(string cmd, cmdmap_t& cmdmap, ostream& ss); void handle_command(class MMonCommand *m); void handle_route(MRoute *m); /** * Generate health report * * @param status one-line status summary * @param detailbl optional bufferlist* to fill with a detailed report */ void get_health(string& status, bufferlist *detailbl, Formatter *f); void get_cluster_status(stringstream &ss, Formatter *f); void reply_command(MMonCommand *m, int rc, const string &rs, version_t version); void reply_command(MMonCommand *m, int rc, const string &rs, bufferlist& rdata, version_t version); void handle_probe(MMonProbe *m); /** * Handle a Probe Operation, replying with our name, quorum and known versions. * * We use the MMonProbe message class for anything and everything related with * Monitor probing. One of the operations relates directly with the probing * itself, in which we receive a probe request and to which we reply with * our name, our quorum and the known versions for each Paxos service. Thus the * redundant function name. This reply will obviously be sent to the one * probing/requesting these infos. * * @todo Add @pre and @post * * @param m A Probe message, with an operation of type Probe. */ void handle_probe_probe(MMonProbe *m); void handle_probe_reply(MMonProbe *m); // request routing struct RoutedRequest { uint64_t tid; bufferlist request_bl; MonSession *session; ConnectionRef con; uint64_t con_features; entity_inst_t client_inst; RoutedRequest() : tid(0), session(NULL), con_features(0) {} ~RoutedRequest() { if (session) session->put(); } }; uint64_t routed_request_tid; map routed_requests; void forward_request_leader(PaxosServiceMessage *req); void handle_forward(MForward *m); void try_send_message(Message *m, const entity_inst_t& to); void send_reply(PaxosServiceMessage *req, Message *reply); void no_reply(PaxosServiceMessage *req); void resend_routed_requests(); void remove_session(MonSession *s); void remove_all_sessions(); void waitlist_or_zap_client(Message *m); void send_command(const entity_inst_t& inst, const vector& com); public: struct C_Command : public Context { Monitor *mon; MMonCommand *m; int rc; string rs; bufferlist rdata; version_t version; C_Command(Monitor *_mm, MMonCommand *_m, int r, string s, version_t v) : mon(_mm), m(_m), rc(r), rs(s), version(v){} C_Command(Monitor *_mm, MMonCommand *_m, int r, string s, bufferlist rd, version_t v) : mon(_mm), m(_m), rc(r), rs(s), rdata(rd), version(v){} void finish(int r) { if (r >= 0) mon->reply_command(m, rc, rs, rdata, version); else if (r == -ECANCELED) m->put(); else if (r == -EAGAIN) mon->_ms_dispatch(m); else assert(0 == "bad C_Command return value"); } }; private: class C_RetryMessage : public Context { Monitor *mon; Message *msg; public: C_RetryMessage(Monitor *m, Message *ms) : mon(m), msg(ms) {} void finish(int r) { if (r == -EAGAIN || r >= 0) mon->_ms_dispatch(msg); else if (r == -ECANCELED) msg->put(); else assert(0 == "bad C_RetryMessage return value"); } }; //ms_dispatch handles a lot of logic and we want to reuse it //on forwarded messages, so we create a non-locking version for this class bool _ms_dispatch(Message *m); bool ms_dispatch(Message *m) { lock.Lock(); bool ret = _ms_dispatch(m); lock.Unlock(); return ret; } // dissociate message handling from session and connection logic bool dispatch(MonSession *s, Message *m, const bool src_is_mon); //mon_caps is used for un-connected messages from monitors MonCap * mon_caps; bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); bool ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con) {} int write_default_keyring(bufferlist& bl); void extract_save_mon_key(KeyRing& keyring); // features static CompatSet get_supported_features(); static CompatSet get_legacy_features(); /// read the ondisk features into the CompatSet pointed to by read_features static void read_features_off_disk(MonitorDBStore *store, CompatSet *read_features); void read_features(); void write_features(MonitorDBStore::Transaction &t); public: Monitor(CephContext *cct_, string nm, MonitorDBStore *s, Messenger *m, MonMap *map); ~Monitor(); static int check_features(MonitorDBStore *store); int preinit(); int init(); void init_paxos(); void refresh_from_paxos(bool *need_bootstrap); void shutdown(); void tick(); void handle_signal(int sig); int mkfs(bufferlist& osdmapbl); /** * check cluster_fsid file * * @return EEXIST if file exists and doesn't match, 0 on match, or negative error code */ int check_fsid(); /** * write cluster_fsid file * * @return 0 on success, or negative error code */ int write_fsid(); int write_fsid(MonitorDBStore::Transaction &t); void do_admin_command(std::string command, cmdmap_t& cmdmap, std::string format, ostream& ss); private: // don't allow copying Monitor(const Monitor& rhs); Monitor& operator=(const Monitor &rhs); public: class StoreConverter { const string path; MonitorDBStore *db; boost::scoped_ptr store; set gvs; map > > gv_map; version_t highest_last_pn; version_t highest_accepted_pn; public: StoreConverter(string path, MonitorDBStore *d) : path(path), db(d), store(NULL), highest_last_pn(0), highest_accepted_pn(0) { } /** * Check if store needs to be converted from old format to a * k/v store. * * @returns 0 if store doesn't need conversion; 1 if it does; <0 if error */ int needs_conversion(); int convert(); bool is_converting() { return db->exists("mon_convert", "on_going"); } private: bool _check_gv_store(); void _init() { assert(!store); MonitorStore *store_ptr = new MonitorStore(path); store.reset(store_ptr); } void _deinit() { store.reset(NULL); } set _get_machines_names() { set names; names.insert("auth"); names.insert("logm"); names.insert("mdsmap"); names.insert("monmap"); names.insert("osdmap"); names.insert("pgmap"); return names; } void _mark_convert_start() { MonitorDBStore::Transaction tx; tx.put("mon_convert", "on_going", 1); db->apply_transaction(tx); } void _convert_finish_features(MonitorDBStore::Transaction &t); void _mark_convert_finish() { MonitorDBStore::Transaction tx; tx.erase("mon_convert", "on_going"); _convert_finish_features(tx); db->apply_transaction(tx); } void _convert_monitor(); void _convert_machines(string machine); void _convert_osdmap_full(); void _convert_machines(); void _convert_paxos(); }; static void format_command_descriptions(const MonCommand *commands, unsigned commands_size, Formatter *f, bufferlist *rdata); void get_locally_supported_monitor_commands(const MonCommand **cmds, int *count); void get_classic_monitor_commands(const MonCommand **cmds, int *count); void get_leader_supported_commands(const MonCommand **cmds, int *count); /// the Monitor owns this pointer once you pass it in void set_leader_supported_commands(const MonCommand *cmds, int size); static bool is_keyring_required(); }; #define CEPH_MON_FEATURE_INCOMPAT_BASE CompatSet::Feature (1, "initial feature set (~v.18)") #define CEPH_MON_FEATURE_INCOMPAT_GV CompatSet::Feature (2, "global version sequencing (v0.52)") #define CEPH_MON_FEATURE_INCOMPAT_SINGLE_PAXOS CompatSet::Feature (3, "single paxos with k/v store (v0.\?)") #define CEPH_MON_FEATURE_INCOMPAT_OSD_ERASURE_CODES CompatSet::Feature(4, "support erasure code pools") #define CEPH_MON_FEATURE_INCOMPAT_OSDMAP_ENC CompatSet::Feature(5, "new-style osdmap encoding") // make sure you add your feature to Monitor::get_supported_features long parse_pos_long(const char *s, ostream *pss = NULL); struct MonCommand { string cmdstring; string helpstring; string module; string req_perms; string availability; void encode(bufferlist &bl) const { /* * very naughty: deliberately unversioned because individual commands * shouldn't be encoded standalone, only as a full set (which we do * version, see encode_array() below). */ ::encode(cmdstring, bl); ::encode(helpstring, bl); ::encode(module, bl); ::encode(req_perms, bl); ::encode(availability, bl); } void decode(bufferlist::iterator &bl) { ::decode(cmdstring, bl); ::decode(helpstring, bl); ::decode(module, bl); ::decode(req_perms, bl); ::decode(availability, bl); } bool operator==(const MonCommand& o) const { return cmdstring == o.cmdstring && helpstring == o.helpstring && module == o.module && req_perms == o.req_perms && availability == o.availability; } bool operator!=(const MonCommand& o) const { return !(*this == o); } static void encode_array(const MonCommand *cmds, int size, bufferlist &bl) { ENCODE_START(1, 1, bl); uint16_t s = size; ::encode(s, bl); ::encode_array_nohead(cmds, size, bl); ENCODE_FINISH(bl); } static void decode_array(MonCommand **cmds, int *size, bufferlist::iterator &bl) { DECODE_START(1, bl); uint16_t s = 0; ::decode(s, bl); *size = s; *cmds = new MonCommand[*size]; ::decode_array_nohead(*cmds, *size, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(MonCommand); #endif ceph-0.80.11/src/mon/QuorumService.h0000664000175100017510000000530512623076744021242 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_QUORUM_SERVICE_H #define CEPH_MON_QUORUM_SERVICE_H #include #include "include/types.h" #include "include/Context.h" #include "common/RefCountedObj.h" #include "common/config.h" #include "mon/Monitor.h" class QuorumService { Context *tick_event; double tick_period; struct C_Tick : public Context { QuorumService *s; C_Tick(QuorumService *qs) : s(qs) { } void finish(int r) { if (r < 0) return; s->tick(); } }; public: enum { SERVICE_HEALTH = 0x01, SERVICE_TIMECHECK = 0x02, SERVICE_CONFIG_KEY = 0x03, }; protected: Monitor *mon; epoch_t epoch; QuorumService(Monitor *m) : tick_event(NULL), tick_period(g_conf->mon_tick_interval), mon(m), epoch(0) { } void cancel_tick() { if (tick_event) mon->timer.cancel_event(tick_event); tick_event = NULL; } void start_tick() { generic_dout(10) << __func__ << dendl; cancel_tick(); if (tick_period <= 0) return; tick_event = new C_Tick(this); mon->timer.add_event_after(tick_period, tick_event); } void set_update_period(double t) { tick_period = t; } bool in_quorum() { return (mon->is_leader() || mon->is_peon()); } virtual bool service_dispatch(Message *m) = 0; virtual void service_tick() = 0; virtual void service_shutdown() = 0; virtual void start_epoch() = 0; virtual void finish_epoch() = 0; virtual void cleanup() = 0; public: virtual ~QuorumService() { } void start(epoch_t new_epoch) { epoch = new_epoch; start_epoch(); } void finish() { generic_dout(20) << "QuorumService::finish" << dendl; finish_epoch(); } epoch_t get_epoch() const { return epoch; } bool dispatch(Message *m) { return service_dispatch(m); } void tick() { service_tick(); start_tick(); } void shutdown() { generic_dout(0) << "quorum service shutdown" << dendl; cancel_tick(); service_shutdown(); } virtual void init() { } virtual void get_health(Formatter *f, list >& summary, list > *detail) = 0; virtual int get_type() = 0; virtual string get_name() const = 0; }; #endif /* CEPH_MON_QUORUM_SERVICE_H */ ceph-0.80.11/src/mon/mon_types.h0000664000175100017510000001237712623076744020455 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_TYPES_H #define CEPH_MON_TYPES_H #include "include/utime.h" #include "include/util.h" #include "common/Formatter.h" #define PAXOS_PGMAP 0 // before osd, for pg kick to behave #define PAXOS_MDSMAP 1 #define PAXOS_OSDMAP 2 #define PAXOS_LOG 3 #define PAXOS_MONMAP 4 #define PAXOS_AUTH 5 #define PAXOS_NUM 6 inline const char *get_paxos_name(int p) { switch (p) { case PAXOS_MDSMAP: return "mdsmap"; case PAXOS_MONMAP: return "monmap"; case PAXOS_OSDMAP: return "osdmap"; case PAXOS_PGMAP: return "pgmap"; case PAXOS_LOG: return "logm"; case PAXOS_AUTH: return "auth"; default: assert(0); return 0; } } #define CEPH_MON_ONDISK_MAGIC "ceph mon volume v012" /** * leveldb store stats * * If we ever decide to support multiple backends for the monitor store, * we should then create an abstract class 'MonitorStoreStats' of sorts * and inherit it on LevelDBStoreStats. I'm sure you'll figure something * out. */ struct LevelDBStoreStats { uint64_t bytes_total; uint64_t bytes_sst; uint64_t bytes_log; uint64_t bytes_misc; utime_t last_update; void dump(Formatter *f) const { assert(f != NULL); f->dump_int("bytes_total", bytes_total); f->dump_int("bytes_sst", bytes_sst); f->dump_int("bytes_log", bytes_log); f->dump_int("bytes_misc", bytes_misc); f->dump_stream("last_updated") << last_update; } void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(bytes_total, bl); ::encode(bytes_sst, bl); ::encode(bytes_log, bl); ::encode(bytes_misc, bl); ::encode(last_update, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(bytes_total, p); ::decode(bytes_sst, p); ::decode(bytes_log, p); ::decode(bytes_misc, p); ::decode(last_update, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(LevelDBStoreStats); // data stats struct DataStats { ceph_data_stats_t fs_stats; // data dir utime_t last_update; LevelDBStoreStats store_stats; void dump(Formatter *f) const { assert(f != NULL); f->dump_int("kb_total", (fs_stats.byte_total/1024)); f->dump_int("kb_used", (fs_stats.byte_used/1024)); f->dump_int("kb_avail", (fs_stats.byte_avail/1024)); f->dump_int("avail_percent", fs_stats.avail_percent); f->dump_stream("last_updated") << last_update; f->open_object_section("store_stats"); store_stats.dump(f); f->close_section(); } void encode(bufferlist &bl) const { ENCODE_START(3, 1, bl); ::encode(fs_stats.byte_total, bl); ::encode(fs_stats.byte_used, bl); ::encode(fs_stats.byte_avail, bl); ::encode(fs_stats.avail_percent, bl); ::encode(last_update, bl); ::encode(store_stats, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); // we moved from having fields in kb to fields in byte if (struct_v > 2) { ::decode(fs_stats.byte_total, p); ::decode(fs_stats.byte_used, p); ::decode(fs_stats.byte_avail, p); } else { uint64_t t; ::decode(t, p); fs_stats.byte_total = t*1024; ::decode(t, p); fs_stats.byte_used = t*1024; ::decode(t, p); fs_stats.byte_avail = t*1024; } ::decode(fs_stats.avail_percent, p); ::decode(last_update, p); if (struct_v > 1) ::decode(store_stats, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(DataStats); struct ScrubResult { map prefix_crc; ///< prefix -> crc map prefix_keys; ///< prefix -> key count bool operator!=(const ScrubResult& other) { return prefix_crc != other.prefix_crc || prefix_keys != other.prefix_keys; } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(prefix_crc, bl); ::encode(prefix_keys, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& p) { DECODE_START(1, p); ::decode(prefix_crc, p); ::decode(prefix_keys, p); DECODE_FINISH(p); } void dump(Formatter *f) const { f->open_object_section("crc"); for (map::const_iterator p = prefix_crc.begin(); p != prefix_crc.end(); ++p) f->dump_unsigned(p->first.c_str(), p->second); f->close_section(); f->open_object_section("keys"); for (map::const_iterator p = prefix_keys.begin(); p != prefix_keys.end(); ++p) f->dump_unsigned(p->first.c_str(), p->second); f->close_section(); } static void generate_test_instances(list& ls) { ls.push_back(new ScrubResult); ls.push_back(new ScrubResult); ls.back()->prefix_crc["foo"] = 123; ls.back()->prefix_keys["bar"] = 456; } }; WRITE_CLASS_ENCODER(ScrubResult); static inline ostream& operator<<(ostream& out, const ScrubResult& r) { return out << "ScrubResult(keys " << r.prefix_keys << " crc " << r.prefix_crc << ")"; } #endif ceph-0.80.11/src/mon/MonClient.cc0000664000175100017510000006712512623076744020467 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "msg/Messenger.h" #include "messages/MMonGetMap.h" #include "messages/MMonGetVersion.h" #include "messages/MMonGetVersionReply.h" #include "messages/MMonMap.h" #include "messages/MAuth.h" #include "messages/MLogAck.h" #include "messages/MAuthReply.h" #include "messages/MMonCommand.h" #include "messages/MMonCommandAck.h" #include "messages/MPing.h" #include "messages/MMonSubscribe.h" #include "messages/MMonSubscribeAck.h" #include "common/ConfUtils.h" #include "common/ceph_argparse.h" #include "common/errno.h" #include "common/LogClient.h" #include "MonClient.h" #include "MonMap.h" #include "auth/Auth.h" #include "auth/KeyRing.h" #include "auth/AuthMethodList.h" #include "include/str_list.h" #include "include/addr_parsing.h" #include "common/config.h" #define dout_subsys ceph_subsys_monc #undef dout_prefix #define dout_prefix *_dout << "monclient" << (hunting ? "(hunting)":"") << ": " MonClient::MonClient(CephContext *cct_) : Dispatcher(cct_), state(MC_STATE_NONE), messenger(NULL), cur_con(NULL), rng(getpid()), monc_lock("MonClient::monc_lock"), timer(cct_, monc_lock), finisher(cct_), authorize_handler_registry(NULL), initialized(false), no_keyring_disabled_cephx(false), log_client(NULL), more_log_pending(false), auth_supported(NULL), hunting(true), want_monmap(true), want_keys(0), global_id(0), authenticate_err(0), session_established_context(NULL), had_a_connection(false), reopen_interval_multiplier(1.0), auth(NULL), keyring(NULL), rotating_secrets(NULL), last_mon_command_tid(0), version_req_id(0) { } MonClient::~MonClient() { delete auth_supported; delete session_established_context; delete auth; delete keyring; delete rotating_secrets; } int MonClient::build_initial_monmap() { ldout(cct, 10) << "build_initial_monmap" << dendl; return monmap.build_initial(cct, cerr); } int MonClient::get_monmap() { ldout(cct, 10) << "get_monmap" << dendl; Mutex::Locker l(monc_lock); _sub_want("monmap", 0, 0); if (cur_mon.empty()) _reopen_session(); while (want_monmap) map_cond.Wait(monc_lock); ldout(cct, 10) << "get_monmap done" << dendl; return 0; } int MonClient::get_monmap_privately() { ldout(cct, 10) << "get_monmap_privately" << dendl; Mutex::Locker l(monc_lock); bool temp_msgr = false; Messenger* smessenger = NULL; if (!messenger) { messenger = smessenger = Messenger::create_client_messenger(cct, "temp_mon_client"); messenger->add_dispatcher_head(this); smessenger->start(); temp_msgr = true; } int attempt = 10; ldout(cct, 10) << "have " << monmap.epoch << " fsid " << monmap.fsid << dendl; while (monmap.fsid.is_zero()) { cur_mon = _pick_random_mon(); cur_con = messenger->get_connection(monmap.get_inst(cur_mon)); ldout(cct, 10) << "querying mon." << cur_mon << " " << cur_con->get_peer_addr() << dendl; messenger->send_message(new MMonGetMap, cur_con); if (--attempt == 0) break; utime_t interval; interval.set_from_double(cct->_conf->mon_client_hunt_interval); map_cond.WaitInterval(cct, monc_lock, interval); if (monmap.fsid.is_zero()) { messenger->mark_down(cur_con); // nope, clean that connection up } } if (temp_msgr) { messenger->mark_down(cur_con); cur_con.reset(NULL); monc_lock.Unlock(); messenger->shutdown(); if (smessenger) smessenger->wait(); delete messenger; messenger = 0; monc_lock.Lock(); } hunting = true; // reset this to true! cur_mon.clear(); cur_con.reset(NULL); if (!monmap.fsid.is_zero()) return 0; return -1; } /** * Ping the monitor with id @p mon_id and set the resulting reply in * the provided @p result_reply, if this last parameter is not NULL. * * So that we don't rely on the MonClient's default messenger, set up * during connect(), we create our own messenger to comunicate with the * specified monitor. This is advantageous in the following ways: * * - Isolate the ping procedure from the rest of the MonClient's operations, * allowing us to not acquire or manage the big monc_lock, thus not * having to block waiting for some other operation to finish before we * can proceed. * * for instance, we can ping mon.FOO even if we are currently hunting * or blocked waiting for auth to complete with mon.BAR. * * - Ping a monitor prior to establishing a connection (using connect()) * and properly establish the MonClient's messenger. This frees us * from dealing with the complex foo that happens in connect(). * * We also don't rely on MonClient as a dispatcher for this messenger, * unlike what happens with the MonClient's default messenger. This allows * us to sandbox the whole ping, having it much as a separate entity in * the MonClient class, considerably simplifying the handling and dispatching * of messages without needing to consider monc_lock. * * Current drawback is that we will establish a messenger for each ping * we want to issue, instead of keeping a single messenger instance that * would be used for all pings. */ int MonClient::ping_monitor(const string &mon_id, string *result_reply) { ldout(cct, 10) << __func__ << dendl; if (mon_id.empty()) { ldout(cct, 10) << __func__ << " specified mon id is empty!" << dendl; return -EINVAL; } else if (!monmap.contains(mon_id)) { ldout(cct, 10) << __func__ << " no such monitor 'mon." << mon_id << "'" << dendl; return -ENOENT; } MonClientPinger *pinger = new MonClientPinger(cct, result_reply); Messenger *smsgr = Messenger::create_client_messenger(cct, "temp_ping_client"); smsgr->add_dispatcher_head(pinger); smsgr->start(); ConnectionRef con = smsgr->get_connection(monmap.get_inst(mon_id)); ldout(cct, 10) << __func__ << " ping mon." << mon_id << " " << con->get_peer_addr() << dendl; smsgr->send_message(new MPing, con); pinger->lock.Lock(); int ret = pinger->wait_for_reply(cct->_conf->client_mount_timeout); if (ret == 0) { ldout(cct,10) << __func__ << " got ping reply" << dendl; } else { ret = -ret; } pinger->lock.Unlock(); smsgr->mark_down(con); smsgr->shutdown(); smsgr->wait(); delete smsgr; delete pinger; return ret; } bool MonClient::ms_dispatch(Message *m) { if (my_addr == entity_addr_t()) my_addr = messenger->get_myaddr(); // we only care about these message types switch (m->get_type()) { case CEPH_MSG_MON_MAP: case CEPH_MSG_AUTH_REPLY: case CEPH_MSG_MON_SUBSCRIBE_ACK: case CEPH_MSG_MON_GET_VERSION_REPLY: case MSG_MON_COMMAND_ACK: case MSG_LOGACK: break; default: return false; } Mutex::Locker lock(monc_lock); // ignore any messages outside our current session if (m->get_connection() != cur_con) { ldout(cct, 10) << "discarding stray monitor message " << *m << dendl; m->put(); return true; } switch (m->get_type()) { case CEPH_MSG_MON_MAP: handle_monmap(static_cast(m)); break; case CEPH_MSG_AUTH_REPLY: handle_auth(static_cast(m)); break; case CEPH_MSG_MON_SUBSCRIBE_ACK: handle_subscribe_ack(static_cast(m)); break; case CEPH_MSG_MON_GET_VERSION_REPLY: handle_get_version_reply(static_cast(m)); break; case MSG_MON_COMMAND_ACK: handle_mon_command_ack(static_cast(m)); break; case MSG_LOGACK: if (log_client) { log_client->handle_log_ack(static_cast(m)); if (more_log_pending) { send_log(); } } else { m->put(); } break; } return true; } void MonClient::send_log() { if (log_client) { Message *lm = log_client->get_mon_log_message(); if (lm) _send_mon_message(lm); more_log_pending = log_client->are_pending(); } } void MonClient::handle_monmap(MMonMap *m) { ldout(cct, 10) << "handle_monmap " << *m << dendl; bufferlist::iterator p = m->monmapbl.begin(); ::decode(monmap, p); assert(!cur_mon.empty()); ldout(cct, 10) << " got monmap " << monmap.epoch << ", mon." << cur_mon << " is now rank " << monmap.get_rank(cur_mon) << dendl; ldout(cct, 10) << "dump:\n"; monmap.print(*_dout); *_dout << dendl; _sub_got("monmap", monmap.get_epoch()); if (!monmap.get_addr_name(cur_con->get_peer_addr(), cur_mon)) { ldout(cct, 10) << "mon." << cur_mon << " went away" << dendl; _reopen_session(); // can't find the mon we were talking to (above) } map_cond.Signal(); want_monmap = false; m->put(); } // ---------------------- int MonClient::init() { ldout(cct, 10) << "init" << dendl; messenger->add_dispatcher_head(this); entity_name = cct->_conf->name; Mutex::Locker l(monc_lock); string method; if (cct->_conf->auth_supported.length() != 0) method = cct->_conf->auth_supported; else if (entity_name.get_type() == CEPH_ENTITY_TYPE_OSD || entity_name.get_type() == CEPH_ENTITY_TYPE_MDS || entity_name.get_type() == CEPH_ENTITY_TYPE_MON) method = cct->_conf->auth_cluster_required; else method = cct->_conf->auth_client_required; auth_supported = new AuthMethodList(cct, method); ldout(cct, 10) << "auth_supported " << auth_supported->get_supported_set() << " method " << method << dendl; int r = 0; keyring = new KeyRing; // initializing keyring anyway if (auth_supported->is_supported_auth(CEPH_AUTH_CEPHX)) { r = keyring->from_ceph_context(cct); if (r == -ENOENT) { auth_supported->remove_supported_auth(CEPH_AUTH_CEPHX); if (auth_supported->get_supported_set().size() > 0) { r = 0; no_keyring_disabled_cephx = true; } else { lderr(cct) << "ERROR: missing keyring, cannot use cephx for authentication" << dendl; } } } if (r < 0) { return r; } rotating_secrets = new RotatingKeyRing(cct, cct->get_module_type(), keyring); initialized = true; timer.init(); finisher.start(); schedule_tick(); return 0; } void MonClient::shutdown() { ldout(cct, 10) << __func__ << "shutdown" << dendl; monc_lock.Lock(); while (!version_requests.empty()) { version_requests.begin()->second->context->complete(-ECANCELED); ldout(cct, 20) << __func__ << " canceling and discarding version request " << version_requests.begin()->second << dendl; delete version_requests.begin()->second; version_requests.erase(version_requests.begin()); } while (!waiting_for_session.empty()) { ldout(cct, 20) << __func__ << " discarding pending message " << *waiting_for_session.front() << dendl; waiting_for_session.front()->put(); waiting_for_session.pop_front(); } monc_lock.Unlock(); if (initialized) { finisher.stop(); } monc_lock.Lock(); timer.shutdown(); messenger->mark_down(cur_con); cur_con.reset(NULL); monc_lock.Unlock(); } int MonClient::authenticate(double timeout) { Mutex::Locker lock(monc_lock); if (state == MC_STATE_HAVE_SESSION) { ldout(cct, 5) << "already authenticated" << dendl;; return 0; } _sub_want("monmap", monmap.get_epoch() ? monmap.get_epoch() + 1 : 0, 0); if (cur_mon.empty()) _reopen_session(); utime_t until = ceph_clock_now(cct); until += timeout; if (timeout > 0.0) ldout(cct, 10) << "authenticate will time out at " << until << dendl; while (state != MC_STATE_HAVE_SESSION && !authenticate_err) { if (timeout > 0.0) { int r = auth_cond.WaitUntil(monc_lock, until); if (r == ETIMEDOUT) { ldout(cct, 0) << "authenticate timed out after " << timeout << dendl; authenticate_err = -r; } } else { auth_cond.Wait(monc_lock); } } if (state == MC_STATE_HAVE_SESSION) { ldout(cct, 5) << "authenticate success, global_id " << global_id << dendl; } if (authenticate_err < 0 && no_keyring_disabled_cephx) { lderr(cct) << "authenticate NOTE: no keyring found; disabled cephx authentication" << dendl; } return authenticate_err; } void MonClient::handle_auth(MAuthReply *m) { Context *cb = NULL; bufferlist::iterator p = m->result_bl.begin(); if (state == MC_STATE_NEGOTIATING) { if (!auth || (int)m->protocol != auth->get_protocol()) { delete auth; auth = get_auth_client_handler(cct, m->protocol, rotating_secrets); if (!auth) { ldout(cct, 10) << "no handler for protocol " << m->protocol << dendl; if (m->result == -ENOTSUP) { ldout(cct, 10) << "none of our auth protocols are supported by the server" << dendl; authenticate_err = m->result; auth_cond.SignalAll(); } m->put(); return; } auth->set_want_keys(want_keys); auth->init(entity_name); auth->set_global_id(global_id); } else { auth->reset(); } state = MC_STATE_AUTHENTICATING; } assert(auth); if (m->global_id && m->global_id != global_id) { global_id = m->global_id; auth->set_global_id(global_id); ldout(cct, 10) << "my global_id is " << m->global_id << dendl; } int ret = auth->handle_response(m->result, p); m->put(); if (ret == -EAGAIN) { MAuth *ma = new MAuth; ma->protocol = auth->get_protocol(); auth->prepare_build_request(); ret = auth->build_request(ma->auth_payload); _send_mon_message(ma, true); return; } _finish_hunting(); authenticate_err = ret; if (ret == 0) { if (state != MC_STATE_HAVE_SESSION) { state = MC_STATE_HAVE_SESSION; while (!waiting_for_session.empty()) { _send_mon_message(waiting_for_session.front()); waiting_for_session.pop_front(); } _resend_mon_commands(); if (log_client) { log_client->reset_session(); send_log(); } if (session_established_context) { cb = session_established_context; session_established_context = NULL; } } _check_auth_tickets(); } auth_cond.SignalAll(); if (cb) { monc_lock.Unlock(); cb->complete(0); monc_lock.Lock(); } } // --------- void MonClient::_send_mon_message(Message *m, bool force) { assert(monc_lock.is_locked()); assert(!cur_mon.empty()); if (force || state == MC_STATE_HAVE_SESSION) { assert(cur_con); ldout(cct, 10) << "_send_mon_message to mon." << cur_mon << " at " << cur_con->get_peer_addr() << dendl; messenger->send_message(m, cur_con); } else { waiting_for_session.push_back(m); } } string MonClient::_pick_random_mon() { assert(monmap.size() > 0); if (monmap.size() == 1) { return monmap.get_name(0); } else { int max = monmap.size(); int o = -1; if (!cur_mon.empty()) { o = monmap.get_rank(cur_mon); if (o >= 0) max--; } int32_t n = rng() % max; if (o >= 0 && n >= o) n++; return monmap.get_name(n); } } void MonClient::_reopen_session(int rank, string name) { assert(monc_lock.is_locked()); ldout(cct, 10) << "_reopen_session rank " << rank << " name " << name << dendl; if (rank < 0 && name.length() == 0) { cur_mon = _pick_random_mon(); } else if (name.length()) { cur_mon = name; } else { cur_mon = monmap.get_name(rank); } if (cur_con) { messenger->mark_down(cur_con); } cur_con = messenger->get_connection(monmap.get_inst(cur_mon)); ldout(cct, 10) << "picked mon." << cur_mon << " con " << cur_con << " addr " << cur_con->get_peer_addr() << dendl; // throw out old queued messages while (!waiting_for_session.empty()) { waiting_for_session.front()->put(); waiting_for_session.pop_front(); } // throw out version check requests while (!version_requests.empty()) { finisher.queue(version_requests.begin()->second->context, -EAGAIN); delete version_requests.begin()->second; version_requests.erase(version_requests.begin()); } // adjust timeouts if necessary if (had_a_connection) { reopen_interval_multiplier *= cct->_conf->mon_client_hunt_interval_backoff; if (reopen_interval_multiplier > cct->_conf->mon_client_hunt_interval_max_multiple) reopen_interval_multiplier = cct->_conf->mon_client_hunt_interval_max_multiple; } // restart authentication handshake state = MC_STATE_NEGOTIATING; hunting = true; // send an initial keepalive to ensure our timestamp is valid by the // time we are in an OPENED state (by sequencing this before // authentication). messenger->send_keepalive(cur_con.get()); MAuth *m = new MAuth; m->protocol = 0; m->monmap_epoch = monmap.get_epoch(); __u8 struct_v = 1; ::encode(struct_v, m->auth_payload); ::encode(auth_supported->get_supported_set(), m->auth_payload); ::encode(entity_name, m->auth_payload); ::encode(global_id, m->auth_payload); _send_mon_message(m, true); if (!sub_have.empty()) _renew_subs(); } bool MonClient::ms_handle_reset(Connection *con) { Mutex::Locker lock(monc_lock); if (con->get_peer_type() == CEPH_ENTITY_TYPE_MON) { if (cur_mon.empty() || con != cur_con) { ldout(cct, 10) << "ms_handle_reset stray mon " << con->get_peer_addr() << dendl; return true; } else { ldout(cct, 10) << "ms_handle_reset current mon " << con->get_peer_addr() << dendl; if (hunting) return true; ldout(cct, 0) << "hunting for new mon" << dendl; _reopen_session(); } } return false; } void MonClient::_finish_hunting() { assert(monc_lock.is_locked()); if (hunting) { ldout(cct, 1) << "found mon." << cur_mon << dendl; hunting = false; had_a_connection = true; reopen_interval_multiplier /= 2.0; if (reopen_interval_multiplier < 1.0) reopen_interval_multiplier = 1.0; } } void MonClient::tick() { ldout(cct, 10) << "tick" << dendl; _check_auth_tickets(); if (hunting) { ldout(cct, 1) << "continuing hunt" << dendl; _reopen_session(); } else if (!cur_mon.empty()) { // just renew as needed utime_t now = ceph_clock_now(cct); ldout(cct, 10) << "renew subs? (now: " << now << "; renew after: " << sub_renew_after << ") -- " << (now > sub_renew_after ? "yes" : "no") << dendl; if (now > sub_renew_after) _renew_subs(); messenger->send_keepalive(cur_con.get()); if (state == MC_STATE_HAVE_SESSION) { send_log(); if (cct->_conf->mon_client_ping_timeout > 0 && cur_con->has_feature(CEPH_FEATURE_MSGR_KEEPALIVE2)) { utime_t lk = cur_con->get_last_keepalive_ack(); utime_t interval = ceph_clock_now(cct) - lk; if (interval > cct->_conf->mon_client_ping_timeout) { ldout(cct, 1) << "no keepalive since " << lk << " (" << interval << " seconds), reconnecting" << dendl; _reopen_session(); } } } } schedule_tick(); } void MonClient::schedule_tick() { if (hunting) timer.add_event_after(cct->_conf->mon_client_hunt_interval * reopen_interval_multiplier, new C_Tick(this)); else timer.add_event_after(cct->_conf->mon_client_ping_interval, new C_Tick(this)); } // --------- void MonClient::_renew_subs() { assert(monc_lock.is_locked()); if (sub_have.empty()) { ldout(cct, 10) << "renew_subs - empty" << dendl; return; } ldout(cct, 10) << "renew_subs" << dendl; if (cur_mon.empty()) _reopen_session(); else { if (sub_renew_sent == utime_t()) sub_renew_sent = ceph_clock_now(cct); MMonSubscribe *m = new MMonSubscribe; m->what = sub_have; _send_mon_message(m); } } void MonClient::handle_subscribe_ack(MMonSubscribeAck *m) { if (sub_renew_sent != utime_t()) { sub_renew_after = sub_renew_sent; sub_renew_after += m->interval / 2.0; ldout(cct, 10) << "handle_subscribe_ack sent " << sub_renew_sent << " renew after " << sub_renew_after << dendl; sub_renew_sent = utime_t(); } else { ldout(cct, 10) << "handle_subscribe_ack sent " << sub_renew_sent << ", ignoring" << dendl; } m->put(); } int MonClient::_check_auth_tickets() { assert(monc_lock.is_locked()); if (state == MC_STATE_HAVE_SESSION && auth) { if (auth->need_tickets()) { ldout(cct, 10) << "_check_auth_tickets getting new tickets!" << dendl; MAuth *m = new MAuth; m->protocol = auth->get_protocol(); auth->prepare_build_request(); auth->build_request(m->auth_payload); _send_mon_message(m); } _check_auth_rotating(); } return 0; } int MonClient::_check_auth_rotating() { assert(monc_lock.is_locked()); if (!rotating_secrets || !auth_principal_needs_rotating_keys(entity_name)) { ldout(cct, 20) << "_check_auth_rotating not needed by " << entity_name << dendl; return 0; } if (!auth || state != MC_STATE_HAVE_SESSION) { ldout(cct, 10) << "_check_auth_rotating waiting for auth session" << dendl; return 0; } utime_t cutoff = ceph_clock_now(cct); cutoff -= MIN(30.0, cct->_conf->auth_service_ticket_ttl / 4.0); if (!rotating_secrets->need_new_secrets(cutoff)) { ldout(cct, 10) << "_check_auth_rotating have uptodate secrets (they expire after " << cutoff << ")" << dendl; rotating_secrets->dump_rotating(); return 0; } ldout(cct, 10) << "_check_auth_rotating renewing rotating keys (they expired before " << cutoff << ")" << dendl; MAuth *m = new MAuth; m->protocol = auth->get_protocol(); if (auth->build_rotating_request(m->auth_payload)) { _send_mon_message(m); } else { m->put(); } return 0; } int MonClient::wait_auth_rotating(double timeout) { Mutex::Locker l(monc_lock); utime_t until = ceph_clock_now(cct); until += timeout; if (auth->get_protocol() == CEPH_AUTH_NONE) return 0; if (!rotating_secrets) return 0; while (auth_principal_needs_rotating_keys(entity_name) && rotating_secrets->need_new_secrets()) { utime_t now = ceph_clock_now(cct); if (now >= until) { ldout(cct, 0) << "wait_auth_rotating timed out after " << timeout << dendl; return -ETIMEDOUT; } ldout(cct, 10) << "wait_auth_rotating waiting (until " << until << ")" << dendl; auth_cond.WaitUntil(monc_lock, until); } ldout(cct, 10) << "wait_auth_rotating done" << dendl; return 0; } // --------- void MonClient::_send_command(MonCommand *r) { if (r->target_rank >= 0 && r->target_rank != monmap.get_rank(cur_mon)) { ldout(cct, 10) << "_send_command " << r->tid << " " << r->cmd << " wants rank " << r->target_rank << ", reopening session" << dendl; if (r->target_rank >= (int)monmap.size()) { ldout(cct, 10) << " target " << r->target_rank << " >= max mon " << monmap.size() << dendl; _finish_command(r, -ENOENT, "mon rank dne"); return; } _reopen_session(r->target_rank, string()); return; } if (r->target_name.length() && r->target_name != cur_mon) { ldout(cct, 10) << "_send_command " << r->tid << " " << r->cmd << " wants mon " << r->target_name << ", reopening session" << dendl; if (!monmap.contains(r->target_name)) { ldout(cct, 10) << " target " << r->target_name << " not present in monmap" << dendl; _finish_command(r, -ENOENT, "mon dne"); return; } _reopen_session(-1, r->target_name); return; } ldout(cct, 10) << "_send_command " << r->tid << " " << r->cmd << dendl; MMonCommand *m = new MMonCommand(monmap.fsid); m->set_tid(r->tid); m->cmd = r->cmd; m->set_data(r->inbl); _send_mon_message(m); return; } void MonClient::_resend_mon_commands() { // resend any requests for (map::iterator p = mon_commands.begin(); p != mon_commands.end(); ++p) { _send_command(p->second); } } void MonClient::handle_mon_command_ack(MMonCommandAck *ack) { MonCommand *r = NULL; uint64_t tid = ack->get_tid(); if (tid == 0 && !mon_commands.empty()) { r = mon_commands.begin()->second; ldout(cct, 10) << "handle_mon_command_ack has tid 0, assuming it is " << r->tid << dendl; } else { map::iterator p = mon_commands.find(tid); if (p == mon_commands.end()) { ldout(cct, 10) << "handle_mon_command_ack " << ack->get_tid() << " not found" << dendl; ack->put(); return; } r = p->second; } ldout(cct, 10) << "handle_mon_command_ack " << r->tid << " " << r->cmd << dendl; if (r->poutbl) r->poutbl->claim(ack->get_data()); _finish_command(r, ack->r, ack->rs); ack->put(); } int MonClient::_cancel_mon_command(uint64_t tid, int r) { assert(monc_lock.is_locked()); map::iterator it = mon_commands.find(tid); if (it == mon_commands.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; } ldout(cct, 10) << __func__ << " tid " << tid << dendl; MonCommand *cmd = it->second; _finish_command(cmd, -ETIMEDOUT, ""); return 0; } void MonClient::_finish_command(MonCommand *r, int ret, string rs) { ldout(cct, 10) << "_finish_command " << r->tid << " = " << ret << " " << rs << dendl; if (r->prval) *(r->prval) = ret; if (r->prs) *(r->prs) = rs; if (r->onfinish) finisher.queue(r->onfinish, ret); mon_commands.erase(r->tid); delete r; } int MonClient::start_mon_command(const vector& cmd, const bufferlist& inbl, bufferlist *outbl, string *outs, Context *onfinish) { Mutex::Locker l(monc_lock); MonCommand *r = new MonCommand(++last_mon_command_tid); r->cmd = cmd; r->inbl = inbl; r->poutbl = outbl; r->prs = outs; r->onfinish = onfinish; if (cct->_conf->rados_mon_op_timeout > 0) { r->ontimeout = new C_CancelMonCommand(r->tid, this); timer.add_event_after(cct->_conf->rados_mon_op_timeout, r->ontimeout); } mon_commands[r->tid] = r; _send_command(r); // can't fail return 0; } int MonClient::start_mon_command(const string &mon_name, const vector& cmd, const bufferlist& inbl, bufferlist *outbl, string *outs, Context *onfinish) { Mutex::Locker l(monc_lock); MonCommand *r = new MonCommand(++last_mon_command_tid); r->target_name = mon_name; r->cmd = cmd; r->inbl = inbl; r->poutbl = outbl; r->prs = outs; r->onfinish = onfinish; mon_commands[r->tid] = r; _send_command(r); // can't fail return 0; } int MonClient::start_mon_command(int rank, const vector& cmd, const bufferlist& inbl, bufferlist *outbl, string *outs, Context *onfinish) { Mutex::Locker l(monc_lock); MonCommand *r = new MonCommand(++last_mon_command_tid); r->target_rank = rank; r->cmd = cmd; r->inbl = inbl; r->poutbl = outbl; r->prs = outs; r->onfinish = onfinish; mon_commands[r->tid] = r; _send_command(r); return 0; } // --------- void MonClient::get_version(string map, version_t *newest, version_t *oldest, Context *onfinish) { version_req_d *req = new version_req_d(onfinish, newest, oldest); ldout(cct, 10) << "get_version " << map << " req " << req << dendl; Mutex::Locker l(monc_lock); MMonGetVersion *m = new MMonGetVersion(); m->what = map; m->handle = ++version_req_id; version_requests[m->handle] = req; _send_mon_message(m); } void MonClient::handle_get_version_reply(MMonGetVersionReply* m) { assert(monc_lock.is_locked()); map::iterator iter = version_requests.find(m->handle); if (iter == version_requests.end()) { ldout(cct, 0) << __func__ << " version request with handle " << m->handle << " not found" << dendl; } else { version_req_d *req = iter->second; ldout(cct, 10) << __func__ << " finishing " << req << " version " << m->version << dendl; version_requests.erase(iter); if (req->newest) *req->newest = m->version; if (req->oldest) *req->oldest = m->oldest_version; finisher.queue(req->context, 0); delete req; } m->put(); } ceph-0.80.11/src/mon/MonmapMonitor.h0000664000175100017510000000374212623076744021233 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* * The Monmap Monitor is used to track the monitors in the cluster. */ #ifndef CEPH_MONMAPMONITOR_H #define CEPH_MONMAPMONITOR_H #include #include using namespace std; #include "include/types.h" #include "msg/Messenger.h" #include "PaxosService.h" #include "MonMap.h" #include "MonitorDBStore.h" class MMonGetMap; class MMonMap; class MMonCommand; class MMonJoin; class MonmapMonitor : public PaxosService { public: MonmapMonitor(Monitor *mn, Paxos *p, const string& service_name) : PaxosService(mn, p, service_name) { } MonMap pending_map; //the pending map awaiting passage void create_initial(); void update_from_paxos(bool *need_bootstrap); void create_pending(); void encode_pending(MonitorDBStore::Transaction *t); // we always encode the full map; we have no use for full versions virtual void encode_full(MonitorDBStore::Transaction *t) { } void on_active(); void dump_info(Formatter *f); bool preprocess_query(PaxosServiceMessage *m); bool prepare_update(PaxosServiceMessage *m); bool preprocess_join(MMonJoin *m); bool prepare_join(MMonJoin *m); bool preprocess_command(MMonCommand *m); bool prepare_command(MMonCommand *m); void get_health(list >& summary, list > *detail) const; int get_monmap(bufferlist &bl); int get_monmap(MonMap &m); /* * Since monitors are pretty * important, this implementation will just write 0.0. */ bool should_propose(double& delay); void tick(); private: bufferlist monmap_bl; }; #endif ceph-0.80.11/src/mon/LogMonitor.h0000664000175100017510000000463212623076744020524 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOGMONITOR_H #define CEPH_LOGMONITOR_H #include #include using namespace std; #include "include/types.h" #include "msg/Messenger.h" #include "PaxosService.h" #include "common/LogEntry.h" #include "messages/MLog.h" class MMonCommand; class LogMonitor : public PaxosService { private: multimap pending_log; LogSummary pending_summary, summary; void create_initial(); void update_from_paxos(bool *need_bootstrap); void create_pending(); // prepare a new pending // propose pending update to peers void encode_pending(MonitorDBStore::Transaction *t); virtual void encode_full(MonitorDBStore::Transaction *t); version_t get_trim_to(); bool preprocess_query(PaxosServiceMessage *m); // true if processed. bool prepare_update(PaxosServiceMessage *m); bool preprocess_log(MLog *m); bool prepare_log(MLog *m); void _updated_log(MLog *m); bool should_propose(double& delay); bool should_stash_full() { // commit a LogSummary on every commit return true; } struct C_Log : public Context { LogMonitor *logmon; MLog *ack; C_Log(LogMonitor *p, MLog *a) : logmon(p), ack(a) {} void finish(int r) { if (r == -ECANCELED) { if (ack) ack->put(); return; } logmon->_updated_log(ack); } }; bool preprocess_command(MMonCommand *m); bool prepare_command(MMonCommand *m); bool _create_sub_summary(MLog *mlog, int level); void _create_sub_incremental(MLog *mlog, int level, version_t sv); void store_do_append(MonitorDBStore::Transaction *t, const string& key, bufferlist& bl); public: LogMonitor(Monitor *mn, Paxos *p, const string& service_name) : PaxosService(mn, p, service_name) { } void tick(); // check state, take actions void check_subs(); void check_sub(Subscription *s); /** * translate log sub name ('log-info') to integer id * * @param n name * @return id, or -1 if unrecognized */ int sub_name_to_id(const string& n); }; #endif ceph-0.80.11/src/mon/MDSMonitor.h0000664000175100017510000000600112623076744020416 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* Metadata Server Monitor */ #ifndef CEPH_MDSMONITOR_H #define CEPH_MDSMONITOR_H #include #include using namespace std; #include "include/types.h" #include "msg/Messenger.h" #include "mds/MDSMap.h" #include "PaxosService.h" #include "Session.h" #include "messages/MMDSBeacon.h" class MMDSGetMap; class MMonCommand; class MMDSLoadTargets; class MDSMonitor : public PaxosService { public: // mds maps MDSMap mdsmap; // current bufferlist mdsmap_bl; // encoded MDSMap pending_mdsmap; // current + pending updates // my helpers void print_map(MDSMap &m, int dbl=7); class C_Updated : public Context { MDSMonitor *mm; MMDSBeacon *m; public: C_Updated(MDSMonitor *a, MMDSBeacon *c) : mm(a), m(c) {} void finish(int r) { if (r >= 0) mm->_updated(m); // success else if (r == -ECANCELED) { mm->mon->no_reply(m); m->put(); } else { mm->dispatch((PaxosServiceMessage*)m); // try again } } }; void create_new_fs(MDSMap &m, int metadata_pool, int data_pool); version_t get_trim_to(); // service methods void create_initial(); void update_from_paxos(bool *need_bootstrap); void create_pending(); void encode_pending(MonitorDBStore::Transaction *t); // we don't require full versions; don't encode any. virtual void encode_full(MonitorDBStore::Transaction *t) { } void update_logger(); void _updated(MMDSBeacon *m); bool preprocess_query(PaxosServiceMessage *m); // true if processed. bool prepare_update(PaxosServiceMessage *m); bool should_propose(double& delay); void on_active(); void _note_beacon(class MMDSBeacon *m); bool preprocess_beacon(class MMDSBeacon *m); bool prepare_beacon(class MMDSBeacon *m); bool preprocess_offload_targets(MMDSLoadTargets *m); bool prepare_offload_targets(MMDSLoadTargets *m); void get_health(list >& summary, list > *detail) const; int fail_mds(std::ostream &ss, const std::string &arg); void fail_mds_gid(uint64_t gid); bool preprocess_command(MMonCommand *m); bool prepare_command(MMonCommand *m); // beacons struct beacon_info_t { utime_t stamp; uint64_t seq; }; map last_beacon; bool try_standby_replay(MDSMap::mds_info_t& finfo, MDSMap::mds_info_t& ainfo); public: MDSMonitor(Monitor *mn, Paxos *p, string service_name) : PaxosService(mn, p, service_name) { } void tick(); // check state, take actions void dump_info(Formatter *f); void check_subs(); void check_sub(Subscription *sub); }; #endif ceph-0.80.11/src/mon/Elector.h0000664000175100017510000003207612623076744020033 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_ELECTOR_H #define CEPH_MON_ELECTOR_H #include using namespace std; #include "include/types.h" #include "msg/Message.h" #include "include/Context.h" #include "common/Timer.h" class Monitor; /** * This class is responsible for maintaining the local state when electing * a new Leader. We may win or we may lose. If we win, it means we became the * Leader; if we lose, it means we are a Peon. */ class Elector { /** * @defgroup Elector_h_class Elector * @{ */ private: /** * The Monitor instance associated with this class. */ Monitor *mon; /** * Event callback responsible for dealing with an expired election once a * timer runs out and fires up. */ Context *expire_event; /** * Resets the expire_event timer, by cancelling any existing one and * scheduling a new one. * * @remarks This function assumes as a default firing value the duration of * the monitor's lease interval, and adds to it the value specified * in @plus * * @post expire_event is set * * @param plus The amount of time to be added to the default firing value. */ void reset_timer(double plus=0.0); /** * Cancel the expire_event timer, if it is defined. * * @post expire_event is not set */ void cancel_timer(); /** * Latest epoch we've seen. * * @remarks if its value is odd, we're electing; if it's even, then we're * stable. */ epoch_t epoch; /** * Indicates if we are participating in the quorum. * * @remarks By default, we are created as participating. We may stop * participating if the Monitor explicitely calls * Elector::stop_participating though. If that happens, it will * have to call Elector::start_participating for us to resume * participating in the quorum. */ bool participating; // electing me /** * @defgroup Elector_h_electing_me_vars We are being elected * @{ */ /** * Indicates if we are the ones being elected. * * We always attempt to be the one being elected if we are the ones starting * the election. If we are not the ones that started it, we will only attempt * to be elected if we think we might have a chance (i.e., the other guy's * rank is lower than ours). */ bool electing_me; /** * Holds the time at which we started the election. */ utime_t start_stamp; /** * Set containing all those that acked our proposal to become the Leader. * * If we are acked by everyone in the MonMap, we will declare * victory. Also note each peer's feature set. */ map acked_me; set classic_mons; /** * @} */ /** * @defgroup Elector_h_electing_them_vars We are electing another guy * @{ */ /** * Indicates who we have acked */ int leader_acked; /** * Indicates when we have acked him */ utime_t ack_stamp; /** * @} */ /** * Update our epoch. * * If we come across a higher epoch, we simply update ours, also making * sure we are no longer being elected (even though we could have been, * we no longer are since we no longer are on that old epoch). * * @pre Our epoch is lower than @p e * @post Our epoch equals @p e * * @param e Epoch to which we will update our epoch */ void bump_epoch(epoch_t e); /** * @defgroup Elector_h_callbacks Callbacks * @{ */ /** * This class is used as the callback when the expire_event timer fires up. * * If the expire_event is fired, then it means that we had an election going, * either started by us or by some other participant, but it took too long, * thus expiring. * * When the election expires, we will check if we were the ones who won, and * if so we will declare victory. If that is not the case, then we assume * that the one we defered to didn't declare victory quickly enough (in fact, * as far as we know, we may even be dead); so, just propose ourselves as the * Leader. */ class C_ElectionExpire : public Context { Elector *elector; public: C_ElectionExpire(Elector *e) : elector(e) { } void finish(int r) { elector->expire(); } }; /** * @} */ /** * Start new elections by proposing ourselves as the new Leader. * * Basically, send propose messages to all the monitors in the MonMap and * then reset the expire_event timer so we can limit the amount of time we * will be going at it. * * @pre participating is true * @post epoch is an odd value * @post electing_me is true * @post we sent propose messages to all the monitors in the MonMap * @post we reset the expire_event timer */ void start(); /** * Defer the current election to some other monitor. * * This means that we will ack some other monitor and drop out from the run * to become the Leader. We will only defer an election if the monitor we * are deferring to outranks us. * * @pre @p who outranks us (i.e., who < our rank) * @pre @p who outranks any other monitor we have deferred to in the past * @post electing_me is false * @post leader_acked equals @p who * @post we sent an ack message to @p who * @post we reset the expire_event timer * * @param who Some other monitor's numeric identifier. */ void defer(int who); /** * The election has taken too long and has expired. * * This will happen when no one declared victory or started a new election * during the time span allowed by the expire_event timer. * * When the election expires, we will check if we were the ones who won, and * if so we will declare victory. If that is not the case, then we assume * that the one we defered to didn't declare victory quickly enough (in fact, * as far as we know, we may even be dead); so, just propose ourselves as the * Leader. */ void expire(); /** * Declare Victory. * * We won. Or at least we believe we won, but for all intentions and purposes * that does not matter. What matters is that we Won. * * That said, we must now bump our epoch to reflect that the election is over * and then we must let everybody in the quorum know we are their brand new * Leader. And we will also cancel our expire_event timer. * * Actually, the quorum will be now defined as the group of monitors that * acked us during the election process. * * @pre Election is on-going * @pre electing_me is true * @post electing_me is false * @post epoch is bumped up into an even value * @post Election is not on-going * @post We have a quorum, composed of the monitors that acked us * @post We sent a message of type OP_VICTORY to each quorum member. */ void victory(); /** * Handle a message from some other node proposing himself to become him * the Leader. * * If the message appears to be old (i.e., its epoch is lower than our epoch), * then we may take one of two actions: * * @li Ignore it because it's nothing more than an old proposal * @li Start new elections if we verify that it was sent by a monitor from * outside the quorum; given its old state, it's fair to assume he just * started, so we should start new elections so he may rejoin * * If we did not ignore the received message, then we know that this message * was sent by some other node proposing himself to become the Leader. So, we * will take one of the following actions: * * @li Ignore him because we already acked another node with higher rank * @li Ignore him and start a new election because we outrank him * @li Defer to him because he outranks us and the node we previously * acked, if any * * * @invariant The received message is an operation of type OP_PROPOSE * * @param m A message sent by another participant in the quorum. */ void handle_propose(class MMonElection *m); /** * Handle a message from some other participant Acking us as the Leader. * * When we receive such a message, one of three thing may be happening: * @li We received a message with a newer epoch, which means we must have * somehow lost track of what was going on (maybe we rebooted), thus we * will start a new election * @li We consider ourselves in the run for the Leader (i.e., @p electing_me * is true), and we are actually being Acked by someone; thus simply add * the one acking us to the @p acked_me set. If we do now have acks from * all the participants, then we can declare victory * @li We already deferred the election to somebody else, so we will just * ignore this message * * @pre Election is on-going * @post Election is on-going if we deferred to somebody else * @post Election is on-going if we are still waiting for further Acks * @post Election is not on-going if we are victorious * @post Election is not on-going if we must start a new one * * @param m A message with an operation type of OP_ACK */ void handle_ack(class MMonElection *m); /** * Handle a message from some other participant declaring Victory. * * We just got a message from someone declaring themselves Victorious, thus * the new Leader. * * However, if the message's epoch happens to be different from our epoch+1, * then it means we lost track of something and we must start a new election. * * If that is not the case, then we will simply update our epoch to the one * in the message, cancel our @p expire_event timer and inform our Monitor * that we lost the election and provide it with the new quorum. * * @pre Election in on-going * @post Election is not on-going * @post Updated @p epoch * @post We have a new quorum if we lost the election * * @param m A message with an operation type of OP_VICTORY */ void handle_victory(class MMonElection *m); /** * Send a nak to a peer who's out of date, containing information about why. * * If we get a message from a peer who can't support the required quorum * features, we have to ignore them. This function will at least send * them a message about *why* they're being ignored -- if they're new * enough to support such a message. * * @param m A message from a monitor not supporting required features. We * take ownership of the reference. */ void nak_old_peer(class MMonElection *m); /** * Handle a message from some other participant declaring * we cannot join the quorum. * * Apparently the quorum requires some feature that we do not implement. Shut * down gracefully. * * @pre Election is on-going. * @post We've shut down. * * @param m A message with an operation type of OP_NAK */ void handle_nak(class MMonElection *m); public: /** * Create an Elector class * * @param m A Monitor instance */ Elector(Monitor *m) : mon(m), expire_event(0), epoch(0), participating(true), electing_me(false), leader_acked(-1) { } /** * Initiate the Elector class. * * Basically, we will simply read whatever epoch value we have in our stable * storage, or consider it to be 1 if none is read. * * @post @p epoch is set to 1 or higher. */ void init(); /** * Inform this class it is supposed to shutdown. * * We will simply cancel the @p expire_event if any exists. * * @post @p expire_event is cancelled */ void shutdown(); /** * Obtain our epoch * * @returns Our current epoch number */ epoch_t get_epoch() { return epoch; } /** * advance_epoch * * increase election epoch by 1 */ void advance_epoch() { bump_epoch(epoch + 1); } /** * Handle received messages. * * We will ignore all messages that are not of type @p MSG_MON_ELECTION * (i.e., messages whose interface is not of type @p MMonElection). All of * those that are will then be dispatched to their operation-specific * functions. * * @param m A received message */ void dispatch(Message *m); /** * Call an election. * * This function simply calls Elector::start. */ void call_election() { start(); } /** * Stop participating in subsequent Elections. * * @post @p participating is false */ void stop_participating() { participating = false; } /** * Start participating in Elections. * * If we are already participating (i.e., @p participating is true), then * calling this function is moot. * * However, if we are not participating (i.e., @p participating is false), * then we will start participating by setting @p participating to true and * we will call for an Election. * * @post @p participating is true */ void start_participating(); /** * @} */ }; #endif ceph-0.80.11/src/mon/Monitor.cc0000664000175100017510000040123612623076744020221 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "Monitor.h" #include "common/version.h" #include "osd/OSDMap.h" #include "MonitorStore.h" #include "MonitorDBStore.h" #include "msg/Messenger.h" #include "messages/PaxosServiceMessage.h" #include "messages/MMonMap.h" #include "messages/MMonGetMap.h" #include "messages/MMonGetVersion.h" #include "messages/MMonGetVersionReply.h" #include "messages/MGenericMessage.h" #include "messages/MMonCommand.h" #include "messages/MMonCommandAck.h" #include "messages/MMonSync.h" #include "messages/MMonScrub.h" #include "messages/MMonProbe.h" #include "messages/MMonJoin.h" #include "messages/MMonPaxos.h" #include "messages/MRoute.h" #include "messages/MForward.h" #include "messages/MMonSubscribe.h" #include "messages/MMonSubscribeAck.h" #include "messages/MAuthReply.h" #include "messages/MTimeCheck.h" #include "messages/MMonHealth.h" #include "messages/MPing.h" #include "common/strtol.h" #include "common/ceph_argparse.h" #include "common/Timer.h" #include "common/Clock.h" #include "common/errno.h" #include "common/perf_counters.h" #include "common/admin_socket.h" #include "include/color.h" #include "include/ceph_fs.h" #include "include/str_list.h" #include "OSDMonitor.h" #include "MDSMonitor.h" #include "MonmapMonitor.h" #include "PGMonitor.h" #include "LogMonitor.h" #include "AuthMonitor.h" #include "mon/QuorumService.h" #include "mon/HealthMonitor.h" #include "mon/ConfigKeyService.h" #include "auth/AuthMethodList.h" #include "auth/KeyRing.h" #include "common/config.h" #include "common/cmdparse.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, this) static ostream& _prefix(std::ostream *_dout, const Monitor *mon) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ") e" << mon->monmap->get_epoch() << " "; } const string Monitor::MONITOR_NAME = "monitor"; const string Monitor::MONITOR_STORE_PREFIX = "monitor_store"; #undef COMMAND MonCommand mon_commands[] = { #define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ {parsesig, helptext, modulename, req_perms, avail}, #include }; MonCommand classic_mon_commands[] = { #include }; long parse_pos_long(const char *s, ostream *pss) { if (*s == '-' || *s == '+') { if (pss) *pss << "expected numerical value, got: " << s; return -EINVAL; } string err; long r = strict_strtol(s, 10, &err); if ((r == 0) && !err.empty()) { if (pss) *pss << err; return -1; } if (r < 0) { if (pss) *pss << "unable to parse positive integer '" << s << "'"; return -1; } return r; } Monitor::Monitor(CephContext* cct_, string nm, MonitorDBStore *s, Messenger *m, MonMap *map) : Dispatcher(cct_), name(nm), rank(-1), messenger(m), con_self(m ? m->get_loopback_connection() : NULL), lock("Monitor::lock"), timer(cct_, lock), has_ever_joined(false), logger(NULL), cluster_logger(NULL), cluster_logger_registered(false), monmap(map), clog(cct_, messenger, monmap, LogClient::FLAG_MON), key_server(cct, &keyring), auth_cluster_required(cct, cct->_conf->auth_supported.length() ? cct->_conf->auth_supported : cct->_conf->auth_cluster_required), auth_service_required(cct, cct->_conf->auth_supported.length() ? cct->_conf->auth_supported : cct->_conf->auth_service_required), leader_supported_mon_commands(NULL), leader_supported_mon_commands_size(0), store(s), state(STATE_PROBING), elector(this), required_features(0), leader(0), quorum_features(0), scrub_version(0), // sync state sync_provider_count(0), sync_cookie(0), sync_full(false), sync_start_version(0), sync_timeout_event(NULL), sync_last_committed_floor(0), timecheck_round(0), timecheck_acks(0), timecheck_event(NULL), probe_timeout_event(NULL), paxos_service(PAXOS_NUM), admin_hook(NULL), routed_request_tid(0) { rank = -1; paxos = new Paxos(this, "paxos"); paxos_service[PAXOS_MDSMAP] = new MDSMonitor(this, paxos, "mdsmap"); paxos_service[PAXOS_MONMAP] = new MonmapMonitor(this, paxos, "monmap"); paxos_service[PAXOS_OSDMAP] = new OSDMonitor(this, paxos, "osdmap"); paxos_service[PAXOS_PGMAP] = new PGMonitor(this, paxos, "pgmap"); paxos_service[PAXOS_LOG] = new LogMonitor(this, paxos, "logm"); paxos_service[PAXOS_AUTH] = new AuthMonitor(this, paxos, "auth"); health_monitor = new HealthMonitor(this); config_key_service = new ConfigKeyService(this, paxos); mon_caps = new MonCap(); bool r = mon_caps->parse("allow *", NULL); assert(r); exited_quorum = ceph_clock_now(g_ceph_context); // assume our commands until we have an election. this only means // we won't reply with EINVAL before the election; any command that // actually matters will wait until we have quorum etc and then // retry (and revalidate). const MonCommand *cmds; int cmdsize; get_locally_supported_monitor_commands(&cmds, &cmdsize); set_leader_supported_commands(cmds, cmdsize); } PaxosService *Monitor::get_paxos_service_by_name(const string& name) { if (name == "mdsmap") return paxos_service[PAXOS_MDSMAP]; if (name == "monmap") return paxos_service[PAXOS_MONMAP]; if (name == "osdmap") return paxos_service[PAXOS_OSDMAP]; if (name == "pgmap") return paxos_service[PAXOS_PGMAP]; if (name == "logm") return paxos_service[PAXOS_LOG]; if (name == "auth") return paxos_service[PAXOS_AUTH]; assert(0 == "given name does not match known paxos service"); return NULL; } Monitor::~Monitor() { for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) delete *p; delete health_monitor; delete config_key_service; delete paxos; assert(session_map.sessions.empty()); delete mon_caps; if (leader_supported_mon_commands != mon_commands && leader_supported_mon_commands != classic_mon_commands) delete[] leader_supported_mon_commands; } enum { l_mon_first = 456000, l_mon_last, }; class AdminHook : public AdminSocketHook { Monitor *mon; public: AdminHook(Monitor *m) : mon(m) {} bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out) { stringstream ss; mon->do_admin_command(command, cmdmap, format, ss); out.append(ss); return true; } }; void Monitor::do_admin_command(string command, cmdmap_t& cmdmap, string format, ostream& ss) { Mutex::Locker l(lock); boost::scoped_ptr f(new_formatter(format)); if (command == "mon_status") { get_mon_status(f.get(), ss); if (f) f->flush(ss); } else if (command == "quorum_status") _quorum_status(f.get(), ss); else if (command == "sync_force") { string validate; if ((!cmd_getval(g_ceph_context, cmdmap, "validate", validate)) || (validate != "--yes-i-really-mean-it")) { ss << "are you SURE? this will mean the monitor store will be erased " "the next time the monitor is restarted. pass " "'--yes-i-really-mean-it' if you really do."; return; } sync_force(f.get(), ss); } else if (command.find("add_bootstrap_peer_hint") == 0) { _add_bootstrap_peer_hint(command, cmdmap, ss); } else if (command.find("osdmonitor_prepare_command") == 0) { _osdmonitor_prepare_command(cmdmap, ss); } else if (command == "quorum enter") { elector.start_participating(); start_election(); ss << "started responding to quorum, initiated new election"; } else if (command == "quorum exit") { start_election(); elector.stop_participating(); ss << "stopped responding to quorum, initiated new election"; } else assert(0 == "bad AdminSocket command binding"); } void Monitor::handle_signal(int signum) { assert(signum == SIGINT || signum == SIGTERM); derr << "*** Got Signal " << sys_siglist[signum] << " ***" << dendl; shutdown(); } CompatSet Monitor::get_supported_features() { CompatSet::FeatureSet ceph_mon_feature_compat; CompatSet::FeatureSet ceph_mon_feature_ro_compat; CompatSet::FeatureSet ceph_mon_feature_incompat; ceph_mon_feature_incompat.insert(CEPH_MON_FEATURE_INCOMPAT_BASE); ceph_mon_feature_incompat.insert(CEPH_MON_FEATURE_INCOMPAT_SINGLE_PAXOS); ceph_mon_feature_incompat.insert(CEPH_MON_FEATURE_INCOMPAT_OSD_ERASURE_CODES); ceph_mon_feature_incompat.insert(CEPH_MON_FEATURE_INCOMPAT_OSDMAP_ENC); return CompatSet(ceph_mon_feature_compat, ceph_mon_feature_ro_compat, ceph_mon_feature_incompat); } CompatSet Monitor::get_legacy_features() { CompatSet::FeatureSet ceph_mon_feature_compat; CompatSet::FeatureSet ceph_mon_feature_ro_compat; CompatSet::FeatureSet ceph_mon_feature_incompat; ceph_mon_feature_incompat.insert(CEPH_MON_FEATURE_INCOMPAT_BASE); return CompatSet(ceph_mon_feature_compat, ceph_mon_feature_ro_compat, ceph_mon_feature_incompat); } int Monitor::check_features(MonitorDBStore *store) { CompatSet required = get_supported_features(); CompatSet ondisk; read_features_off_disk(store, &ondisk); if (!required.writeable(ondisk)) { CompatSet diff = required.unsupported(ondisk); generic_derr << "ERROR: on disk data includes unsupported features: " << diff << dendl; return -EPERM; } return 0; } void Monitor::read_features_off_disk(MonitorDBStore *store, CompatSet *features) { bufferlist featuresbl; store->get(MONITOR_NAME, COMPAT_SET_LOC, featuresbl); if (featuresbl.length() == 0) { generic_dout(0) << "WARNING: mon fs missing feature list.\n" << "Assuming it is old-style and introducing one." << dendl; //we only want the baseline ~v.18 features assumed to be on disk. //If new features are introduced this code needs to disappear or //be made smarter. *features = get_legacy_features(); bufferlist bl; features->encode(bl); MonitorDBStore::Transaction t; t.put(MONITOR_NAME, COMPAT_SET_LOC, bl); store->apply_transaction(t); } else { bufferlist::iterator it = featuresbl.begin(); features->decode(it); } } void Monitor::read_features() { read_features_off_disk(store, &features); dout(10) << "features " << features << dendl; apply_compatset_features_to_quorum_requirements(); dout(10) << "required_features " << required_features << dendl; } void Monitor::write_features(MonitorDBStore::Transaction &t) { bufferlist bl; features.encode(bl); t.put(MONITOR_NAME, COMPAT_SET_LOC, bl); } int Monitor::preinit() { lock.Lock(); dout(1) << "preinit fsid " << monmap->fsid << dendl; assert(!logger); { PerfCountersBuilder pcb(g_ceph_context, "mon", l_mon_first, l_mon_last); // ... logger = pcb.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); } assert(!cluster_logger); { PerfCountersBuilder pcb(g_ceph_context, "cluster", l_cluster_first, l_cluster_last); pcb.add_u64(l_cluster_num_mon, "num_mon"); pcb.add_u64(l_cluster_num_mon_quorum, "num_mon_quorum"); pcb.add_u64(l_cluster_num_osd, "num_osd"); pcb.add_u64(l_cluster_num_osd_up, "num_osd_up"); pcb.add_u64(l_cluster_num_osd_in, "num_osd_in"); pcb.add_u64(l_cluster_osd_epoch, "osd_epoch"); pcb.add_u64(l_cluster_osd_kb, "osd_kb"); pcb.add_u64(l_cluster_osd_kb_used, "osd_kb_used"); pcb.add_u64(l_cluster_osd_kb_avail, "osd_kb_avail"); pcb.add_u64(l_cluster_num_pool, "num_pool"); pcb.add_u64(l_cluster_num_pg, "num_pg"); pcb.add_u64(l_cluster_num_pg_active_clean, "num_pg_active_clean"); pcb.add_u64(l_cluster_num_pg_active, "num_pg_active"); pcb.add_u64(l_cluster_num_pg_peering, "num_pg_peering"); pcb.add_u64(l_cluster_num_object, "num_object"); pcb.add_u64(l_cluster_num_object_degraded, "num_object_degraded"); pcb.add_u64(l_cluster_num_object_unfound, "num_object_unfound"); pcb.add_u64(l_cluster_num_bytes, "num_bytes"); pcb.add_u64(l_cluster_num_mds_up, "num_mds_up"); pcb.add_u64(l_cluster_num_mds_in, "num_mds_in"); pcb.add_u64(l_cluster_num_mds_failed, "num_mds_failed"); pcb.add_u64(l_cluster_mds_epoch, "mds_epoch"); cluster_logger = pcb.create_perf_counters(); } paxos->init_logger(); // verify cluster_uuid { int r = check_fsid(); if (r == -ENOENT) r = write_fsid(); if (r < 0) { lock.Unlock(); return r; } } // open compatset read_features(); // have we ever joined a quorum? has_ever_joined = (store->get(MONITOR_NAME, "joined") != 0); dout(10) << "has_ever_joined = " << (int)has_ever_joined << dendl; if (!has_ever_joined) { // impose initial quorum restrictions? list initial_members; get_str_list(g_conf->mon_initial_members, initial_members); if (!initial_members.empty()) { dout(1) << " initial_members " << initial_members << ", filtering seed monmap" << dendl; monmap->set_initial_members(g_ceph_context, initial_members, name, messenger->get_myaddr(), &extra_probe_peers); dout(10) << " monmap is " << *monmap << dendl; dout(10) << " extra probe peers " << extra_probe_peers << dendl; } } else if (!monmap->contains(name)) { derr << "not in monmap and have been in a quorum before; " << "must have been removed" << dendl; if (g_conf->mon_force_quorum_join) { dout(0) << "we should have died but " << "'mon_force_quorum_join' is set -- allowing boot" << dendl; } else { derr << "commit suicide!" << dendl; return -ENOENT; } } { // We have a potentially inconsistent store state in hands. Get rid of it // and start fresh. bool clear_store = false; if (store->exists("mon_sync", "in_sync")) { dout(1) << __func__ << " clean up potentially inconsistent store state" << dendl; clear_store = true; } if (store->get("mon_sync", "force_sync") > 0) { dout(1) << __func__ << " force sync by clearing store state" << dendl; clear_store = true; } if (clear_store) { set sync_prefixes = get_sync_targets_names(); store->clear(sync_prefixes); } } sync_last_committed_floor = store->get("mon_sync", "last_committed_floor"); dout(10) << "sync_last_committed_floor " << sync_last_committed_floor << dendl; init_paxos(); health_monitor->init(); int r; if (is_keyring_required()) { // we need to bootstrap authentication keys so we can form an // initial quorum. if (authmon()->get_last_committed() == 0) { dout(10) << "loading initial keyring to bootstrap authentication for mkfs" << dendl; bufferlist bl; store->get("mkfs", "keyring", bl); KeyRing keyring; bufferlist::iterator p = bl.begin(); ::decode(keyring, p); extract_save_mon_key(keyring); } string keyring_loc = g_conf->mon_data + "/keyring"; r = keyring.load(cct, keyring_loc); if (r < 0) { EntityName mon_name; mon_name.set_type(CEPH_ENTITY_TYPE_MON); EntityAuth mon_key; if (key_server.get_auth(mon_name, mon_key)) { dout(1) << "copying mon. key from old db to external keyring" << dendl; keyring.add(mon_name, mon_key); bufferlist bl; keyring.encode_plaintext(bl); write_default_keyring(bl); } else { derr << "unable to load initial keyring " << g_conf->keyring << dendl; lock.Unlock(); return r; } } } admin_hook = new AdminHook(this); AdminSocket* admin_socket = cct->get_admin_socket(); // unlock while registering to avoid mon_lock -> admin socket lock dependency. lock.Unlock(); r = admin_socket->register_command("mon_status", "mon_status", admin_hook, "show current monitor status"); assert(r == 0); if (g_conf->mon_advanced_debug_mode) { r = admin_socket->register_command("osdmonitor_prepare_command", "osdmonitor_prepare_command", admin_hook, "call OSDMonitor::prepare_command"); assert(r == 0); } r = admin_socket->register_command("quorum_status", "quorum_status", admin_hook, "show current quorum status"); assert(r == 0); r = admin_socket->register_command("sync_force", "sync_force name=validate," "type=CephChoices," "strings=--yes-i-really-mean-it", admin_hook, "force sync of and clear monitor store"); assert(r == 0); r = admin_socket->register_command("add_bootstrap_peer_hint", "add_bootstrap_peer_hint name=addr," "type=CephIPAddr", admin_hook, "add peer address as potential bootstrap" " peer for cluster bringup"); assert(r == 0); r = admin_socket->register_command("quorum enter", "quorum enter", admin_hook, "force monitor back into quorum"); assert(r == 0); r = admin_socket->register_command("quorum exit", "quorum exit", admin_hook, "force monitor out of the quorum"); assert(r == 0); lock.Lock(); lock.Unlock(); return 0; } int Monitor::init() { dout(2) << "init" << dendl; lock.Lock(); // start ticker timer.init(); new_tick(); // i'm ready! messenger->add_dispatcher_tail(this); bootstrap(); // encode command sets const MonCommand *cmds; int cmdsize; get_locally_supported_monitor_commands(&cmds, &cmdsize); MonCommand::encode_array(cmds, cmdsize, supported_commands_bl); get_classic_monitor_commands(&cmds, &cmdsize); MonCommand::encode_array(cmds, cmdsize, classic_commands_bl); lock.Unlock(); return 0; } void Monitor::init_paxos() { dout(10) << __func__ << dendl; paxos->init(); // init services for (int i = 0; i < PAXOS_NUM; ++i) { paxos_service[i]->init(); } refresh_from_paxos(NULL); } void Monitor::refresh_from_paxos(bool *need_bootstrap) { dout(10) << __func__ << dendl; bufferlist bl; int r = store->get(MONITOR_NAME, "cluster_fingerprint", bl); if (r >= 0) { try { bufferlist::iterator p = bl.begin(); ::decode(fingerprint, p); } catch (buffer::error& e) { dout(10) << __func__ << " failed to decode cluster_fingerprint" << dendl; } } else { dout(10) << __func__ << " no cluster_fingerprint" << dendl; } for (int i = 0; i < PAXOS_NUM; ++i) { paxos_service[i]->refresh(need_bootstrap); } for (int i = 0; i < PAXOS_NUM; ++i) { paxos_service[i]->post_refresh(); } } void Monitor::register_cluster_logger() { if (!cluster_logger_registered) { dout(10) << "register_cluster_logger" << dendl; cluster_logger_registered = true; cct->get_perfcounters_collection()->add(cluster_logger); } else { dout(10) << "register_cluster_logger - already registered" << dendl; } } void Monitor::unregister_cluster_logger() { if (cluster_logger_registered) { dout(10) << "unregister_cluster_logger" << dendl; cluster_logger_registered = false; cct->get_perfcounters_collection()->remove(cluster_logger); } else { dout(10) << "unregister_cluster_logger - not registered" << dendl; } } void Monitor::update_logger() { cluster_logger->set(l_cluster_num_mon, monmap->size()); cluster_logger->set(l_cluster_num_mon_quorum, quorum.size()); } void Monitor::shutdown() { dout(1) << "shutdown" << dendl; lock.Lock(); state = STATE_SHUTDOWN; if (admin_hook) { AdminSocket* admin_socket = cct->get_admin_socket(); admin_socket->unregister_command("mon_status"); admin_socket->unregister_command("quorum_status"); admin_socket->unregister_command("sync_force"); admin_socket->unregister_command("add_bootstrap_peer_hint"); delete admin_hook; admin_hook = NULL; } elector.shutdown(); if (logger) { cct->get_perfcounters_collection()->remove(logger); delete logger; logger = NULL; } if (cluster_logger) { if (cluster_logger_registered) cct->get_perfcounters_collection()->remove(cluster_logger); delete cluster_logger; cluster_logger = NULL; } // clean up paxos->shutdown(); for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) (*p)->shutdown(); health_monitor->shutdown(); finish_contexts(g_ceph_context, waitfor_quorum, -ECANCELED); finish_contexts(g_ceph_context, maybe_wait_for_quorum, -ECANCELED); timer.shutdown(); remove_all_sessions(); // unlock before msgr shutdown... lock.Unlock(); messenger->shutdown(); // last thing! ceph_mon.cc will delete mon. } void Monitor::bootstrap() { dout(10) << "bootstrap" << dendl; sync_reset_requester(); unregister_cluster_logger(); cancel_probe_timeout(); // note my rank int newrank = monmap->get_rank(messenger->get_myaddr()); if (newrank < 0 && rank >= 0) { // was i ever part of the quorum? if (has_ever_joined) { dout(0) << " removed from monmap, suicide." << dendl; exit(0); } } if (newrank != rank) { dout(0) << " my rank is now " << newrank << " (was " << rank << ")" << dendl; messenger->set_myname(entity_name_t::MON(newrank)); rank = newrank; // reset all connections, or else our peers will think we are someone else. messenger->mark_down_all(); } // reset state = STATE_PROBING; _reset(); // sync store if (g_conf->mon_compact_on_bootstrap) { dout(10) << "bootstrap -- triggering compaction" << dendl; store->compact(); dout(10) << "bootstrap -- finished compaction" << dendl; } // singleton monitor? if (monmap->size() == 1 && rank == 0) { win_standalone_election(); return; } reset_probe_timeout(); // i'm outside the quorum if (monmap->contains(name)) outside_quorum.insert(name); // probe monitors dout(10) << "probing other monitors" << dendl; for (unsigned i = 0; i < monmap->size(); i++) { if ((int)i != rank) messenger->send_message(new MMonProbe(monmap->fsid, MMonProbe::OP_PROBE, name, has_ever_joined), monmap->get_inst(i)); } for (set::iterator p = extra_probe_peers.begin(); p != extra_probe_peers.end(); ++p) { if (*p != messenger->get_myaddr()) { entity_inst_t i; i.name = entity_name_t::MON(-1); i.addr = *p; messenger->send_message(new MMonProbe(monmap->fsid, MMonProbe::OP_PROBE, name, has_ever_joined), i); } } } void Monitor::_osdmonitor_prepare_command(cmdmap_t& cmdmap, ostream& ss) { if (!is_leader()) { ss << "mon must be a leader"; return; } string cmd; cmd_getval(g_ceph_context, cmdmap, "prepare", cmd); cmdmap["prefix"] = cmdmap["prepare"]; OSDMonitor *monitor = osdmon(); MMonCommand *m = static_cast((new MMonCommand())->get()); if (monitor->prepare_command_impl(m, cmdmap)) ss << "true"; else ss << "false"; m->put(); } void Monitor::_add_bootstrap_peer_hint(string cmd, cmdmap_t& cmdmap, ostream& ss) { string addrstr; if (!cmd_getval(g_ceph_context, cmdmap, "addr", addrstr)) { ss << "unable to parse address string value '" << cmd_vartype_stringify(cmdmap["addr"]) << "'"; return; } dout(10) << "_add_bootstrap_peer_hint '" << cmd << "' '" << addrstr << "'" << dendl; entity_addr_t addr; const char *end = 0; if (!addr.parse(addrstr.c_str(), &end)) { ss << "failed to parse addr '" << addrstr << "'; syntax is 'add_bootstrap_peer_hint ip[:port]'"; return; } if (is_leader() || is_peon()) { ss << "mon already active; ignoring bootstrap hint"; return; } if (addr.get_port() == 0) addr.set_port(CEPH_MON_PORT); extra_probe_peers.insert(addr); ss << "adding peer " << addr << " to list: " << extra_probe_peers; } // called by bootstrap(), or on leader|peon -> electing void Monitor::_reset() { dout(10) << __func__ << dendl; assert(state == STATE_ELECTING || state == STATE_PROBING); cancel_probe_timeout(); timecheck_finish(); leader_since = utime_t(); if (!quorum.empty()) { exited_quorum = ceph_clock_now(g_ceph_context); } quorum.clear(); outside_quorum.clear(); scrub_reset(); paxos->restart(); for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) (*p)->restart(); health_monitor->finish(); } // ----------------------------------------------------------- // sync set Monitor::get_sync_targets_names() { set targets; targets.insert(paxos->get_name()); for (int i = 0; i < PAXOS_NUM; ++i) paxos_service[i]->get_store_prefixes(targets); return targets; } void Monitor::sync_timeout() { dout(10) << __func__ << dendl; assert(state == STATE_SYNCHRONIZING); bootstrap(); } void Monitor::sync_obtain_latest_monmap(bufferlist &bl) { dout(1) << __func__ << dendl; MonMap latest_monmap; // Grab latest monmap from MonmapMonitor bufferlist monmon_bl; int err = monmon()->get_monmap(monmon_bl); if (err < 0) { if (err != -ENOENT) { derr << __func__ << " something wrong happened while reading the store: " << cpp_strerror(err) << dendl; assert(0 == "error reading the store"); } } else { latest_monmap.decode(monmon_bl); } // Grab last backed up monmap (if any) and compare epochs if (store->exists("mon_sync", "latest_monmap")) { bufferlist backup_bl; int err = store->get("mon_sync", "latest_monmap", backup_bl); if (err < 0) { assert(err != -ENOENT); derr << __func__ << " something wrong happened while reading the store: " << cpp_strerror(err) << dendl; assert(0 == "error reading the store"); } assert(backup_bl.length() > 0); MonMap backup_monmap; backup_monmap.decode(backup_bl); if (backup_monmap.epoch > latest_monmap.epoch) latest_monmap = backup_monmap; } // Check if our current monmap's epoch is greater than the one we've // got so far. if (monmap->epoch > latest_monmap.epoch) latest_monmap = *monmap; dout(1) << __func__ << " obtained monmap e" << latest_monmap.epoch << dendl; latest_monmap.encode(bl, quorum_features); } void Monitor::sync_reset_requester() { dout(10) << __func__ << dendl; if (sync_timeout_event) { timer.cancel_event(sync_timeout_event); sync_timeout_event = NULL; } sync_provider = entity_inst_t(); sync_cookie = 0; sync_full = false; sync_start_version = 0; } void Monitor::sync_reset_provider() { dout(10) << __func__ << dendl; sync_providers.clear(); } void Monitor::sync_start(entity_inst_t &other, bool full) { dout(10) << __func__ << " " << other << (full ? " full" : " recent") << dendl; assert(state == STATE_PROBING || state == STATE_SYNCHRONIZING); state = STATE_SYNCHRONIZING; // make sure are not a provider for anyone! sync_reset_provider(); sync_full = full; if (sync_full) { // stash key state, and mark that we are syncing MonitorDBStore::Transaction t; sync_stash_critical_state(&t); t.put("mon_sync", "in_sync", 1); sync_last_committed_floor = MAX(sync_last_committed_floor, paxos->get_version()); dout(10) << __func__ << " marking sync in progress, storing sync_last_committed_floor " << sync_last_committed_floor << dendl; t.put("mon_sync", "last_committed_floor", sync_last_committed_floor); store->apply_transaction(t); assert(g_conf->mon_sync_requester_kill_at != 1); // clear the underlying store set targets = get_sync_targets_names(); dout(10) << __func__ << " clearing prefixes " << targets << dendl; store->clear(targets); // make sure paxos knows it has been reset. this prevents a // bootstrap and then different probe reply order from possibly // deciding a partial or no sync is needed. paxos->init(); assert(g_conf->mon_sync_requester_kill_at != 2); } // assume 'other' as the leader. We will update the leader once we receive // a reply to the sync start. sync_provider = other; sync_reset_timeout(); MMonSync *m = new MMonSync(sync_full ? MMonSync::OP_GET_COOKIE_FULL : MMonSync::OP_GET_COOKIE_RECENT); if (!sync_full) m->last_committed = paxos->get_version(); messenger->send_message(m, sync_provider); } void Monitor::sync_stash_critical_state(MonitorDBStore::Transaction *t) { dout(10) << __func__ << dendl; bufferlist backup_monmap; sync_obtain_latest_monmap(backup_monmap); assert(backup_monmap.length() > 0); t->put("mon_sync", "latest_monmap", backup_monmap); } void Monitor::sync_reset_timeout() { dout(10) << __func__ << dendl; if (sync_timeout_event) timer.cancel_event(sync_timeout_event); sync_timeout_event = new C_SyncTimeout(this); timer.add_event_after(g_conf->mon_sync_timeout, sync_timeout_event); } void Monitor::sync_finish(version_t last_committed) { dout(10) << __func__ << " lc " << last_committed << " from " << sync_provider << dendl; assert(g_conf->mon_sync_requester_kill_at != 7); if (sync_full) { // finalize the paxos commits MonitorDBStore::Transaction tx; paxos->read_and_prepare_transactions(&tx, sync_start_version, last_committed); tx.put(paxos->get_name(), "last_committed", last_committed); dout(30) << __func__ << " final tx dump:\n"; JSONFormatter f(true); tx.dump(&f); f.flush(*_dout); *_dout << dendl; store->apply_transaction(tx); } assert(g_conf->mon_sync_requester_kill_at != 8); MonitorDBStore::Transaction t; t.erase("mon_sync", "in_sync"); t.erase("mon_sync", "force_sync"); t.erase("mon_sync", "last_committed_floor"); store->apply_transaction(t); assert(g_conf->mon_sync_requester_kill_at != 9); init_paxos(); assert(g_conf->mon_sync_requester_kill_at != 10); bootstrap(); } void Monitor::handle_sync(MMonSync *m) { dout(10) << __func__ << " " << *m << dendl; switch (m->op) { // provider --------- case MMonSync::OP_GET_COOKIE_FULL: case MMonSync::OP_GET_COOKIE_RECENT: handle_sync_get_cookie(m); break; case MMonSync::OP_GET_CHUNK: handle_sync_get_chunk(m); break; // client ----------- case MMonSync::OP_COOKIE: handle_sync_cookie(m); break; case MMonSync::OP_CHUNK: case MMonSync::OP_LAST_CHUNK: handle_sync_chunk(m); break; case MMonSync::OP_NO_COOKIE: handle_sync_no_cookie(m); break; default: dout(0) << __func__ << " unknown op " << m->op << dendl; assert(0 == "unknown op"); } m->put(); } // leader void Monitor::_sync_reply_no_cookie(MMonSync *m) { MMonSync *reply = new MMonSync(MMonSync::OP_NO_COOKIE, m->cookie); messenger->send_message(reply, m->get_connection()); } void Monitor::handle_sync_get_cookie(MMonSync *m) { if (is_synchronizing()) { _sync_reply_no_cookie(m); return; } assert(g_conf->mon_sync_provider_kill_at != 1); // make sure they can understand us. if ((required_features ^ m->get_connection()->get_features()) & required_features) { dout(5) << " ignoring peer mon." << m->get_source().num() << " has features " << std::hex << m->get_connection()->get_features() << " but we require " << required_features << std::dec << dendl; return; } // make up a unique cookie. include election epoch (which persists // across restarts for the whole cluster) and a counter for this // process instance. there is no need to be unique *across* // monitors, though. uint64_t cookie = ((unsigned long long)elector.get_epoch() << 24) + ++sync_provider_count; assert(sync_providers.count(cookie) == 0); dout(10) << __func__ << " cookie " << cookie << " for " << m->get_source_inst() << dendl; SyncProvider& sp = sync_providers[cookie]; sp.cookie = cookie; sp.entity = m->get_source_inst(); sp.reset_timeout(g_ceph_context, g_conf->mon_sync_timeout * 2); set sync_targets; if (m->op == MMonSync::OP_GET_COOKIE_FULL) { // full scan sync_targets = get_sync_targets_names(); sp.last_committed = paxos->get_version(); sp.synchronizer = store->get_synchronizer(sp.last_key, sync_targets); sp.full = true; dout(10) << __func__ << " will sync prefixes " << sync_targets << dendl; } else { // just catch up paxos sp.last_committed = m->last_committed; } dout(10) << __func__ << " will sync from version " << sp.last_committed << dendl; MMonSync *reply = new MMonSync(MMonSync::OP_COOKIE, sp.cookie); reply->last_committed = sp.last_committed; messenger->send_message(reply, m->get_connection()); } void Monitor::handle_sync_get_chunk(MMonSync *m) { dout(10) << __func__ << " " << *m << dendl; if (sync_providers.count(m->cookie) == 0) { dout(10) << __func__ << " no cookie " << m->cookie << dendl; _sync_reply_no_cookie(m); return; } assert(g_conf->mon_sync_provider_kill_at != 2); SyncProvider& sp = sync_providers[m->cookie]; sp.reset_timeout(g_ceph_context, g_conf->mon_sync_timeout * 2); if (sp.last_committed < paxos->get_first_committed() && paxos->get_first_committed() > 1) { dout(10) << __func__ << " sync requester fell behind paxos, their lc " << sp.last_committed << " < our fc " << paxos->get_first_committed() << dendl; sync_providers.erase(m->cookie); _sync_reply_no_cookie(m); return; } MMonSync *reply = new MMonSync(MMonSync::OP_CHUNK, sp.cookie); MonitorDBStore::Transaction tx; int left = g_conf->mon_sync_max_payload_size; while (sp.last_committed < paxos->get_version() && left > 0) { bufferlist bl; sp.last_committed++; store->get(paxos->get_name(), sp.last_committed, bl); tx.put(paxos->get_name(), sp.last_committed, bl); left -= bl.length(); dout(20) << __func__ << " including paxos state " << sp.last_committed << dendl; } reply->last_committed = sp.last_committed; if (sp.full && left > 0) { sp.synchronizer->get_chunk_tx(tx, left); sp.last_key = sp.synchronizer->get_last_key(); reply->last_key = sp.last_key; } if ((sp.full && sp.synchronizer->has_next_chunk()) || sp.last_committed < paxos->get_version()) { dout(10) << __func__ << " chunk, through version " << sp.last_committed << " key " << sp.last_key << dendl; } else { dout(10) << __func__ << " last chunk, through version " << sp.last_committed << " key " << sp.last_key << dendl; reply->op = MMonSync::OP_LAST_CHUNK; assert(g_conf->mon_sync_provider_kill_at != 3); // clean up our local state sync_providers.erase(sp.cookie); } ::encode(tx, reply->chunk_bl); messenger->send_message(reply, m->get_connection()); } // requester void Monitor::handle_sync_cookie(MMonSync *m) { dout(10) << __func__ << " " << *m << dendl; if (sync_cookie) { dout(10) << __func__ << " already have a cookie, ignoring" << dendl; return; } if (m->get_source_inst() != sync_provider) { dout(10) << __func__ << " source does not match, discarding" << dendl; return; } sync_cookie = m->cookie; sync_start_version = m->last_committed; sync_reset_timeout(); sync_get_next_chunk(); assert(g_conf->mon_sync_requester_kill_at != 3); } void Monitor::sync_get_next_chunk() { dout(20) << __func__ << " cookie " << sync_cookie << " provider " << sync_provider << dendl; if (g_conf->mon_inject_sync_get_chunk_delay > 0) { dout(20) << __func__ << " injecting delay of " << g_conf->mon_inject_sync_get_chunk_delay << dendl; usleep((long long)(g_conf->mon_inject_sync_get_chunk_delay * 1000000.0)); } MMonSync *r = new MMonSync(MMonSync::OP_GET_CHUNK, sync_cookie); messenger->send_message(r, sync_provider); assert(g_conf->mon_sync_requester_kill_at != 4); } void Monitor::handle_sync_chunk(MMonSync *m) { dout(10) << __func__ << " " << *m << dendl; if (m->cookie != sync_cookie) { dout(10) << __func__ << " cookie does not match, discarding" << dendl; return; } if (m->get_source_inst() != sync_provider) { dout(10) << __func__ << " source does not match, discarding" << dendl; return; } assert(state == STATE_SYNCHRONIZING); assert(g_conf->mon_sync_requester_kill_at != 5); MonitorDBStore::Transaction tx; tx.append_from_encoded(m->chunk_bl); dout(30) << __func__ << " tx dump:\n"; JSONFormatter f(true); tx.dump(&f); f.flush(*_dout); *_dout << dendl; store->apply_transaction(tx); assert(g_conf->mon_sync_requester_kill_at != 6); if (!sync_full) { dout(10) << __func__ << " applying recent paxos transactions as we go" << dendl; MonitorDBStore::Transaction tx; paxos->read_and_prepare_transactions(&tx, paxos->get_version() + 1, m->last_committed); tx.put(paxos->get_name(), "last_committed", m->last_committed); dout(30) << __func__ << " tx dump:\n"; JSONFormatter f(true); tx.dump(&f); f.flush(*_dout); *_dout << dendl; store->apply_transaction(tx); paxos->init(); // to refresh what we just wrote } if (m->op == MMonSync::OP_CHUNK) { sync_reset_timeout(); sync_get_next_chunk(); } else if (m->op == MMonSync::OP_LAST_CHUNK) { sync_finish(m->last_committed); } } void Monitor::handle_sync_no_cookie(MMonSync *m) { dout(10) << __func__ << dendl; bootstrap(); } void Monitor::sync_trim_providers() { dout(20) << __func__ << dendl; utime_t now = ceph_clock_now(g_ceph_context); map::iterator p = sync_providers.begin(); while (p != sync_providers.end()) { if (now > p->second.timeout) { dout(10) << __func__ << " expiring cookie " << p->second.cookie << " for " << p->second.entity << dendl; sync_providers.erase(p++); } else { ++p; } } } // --------------------------------------------------- // probe void Monitor::cancel_probe_timeout() { if (probe_timeout_event) { dout(10) << "cancel_probe_timeout " << probe_timeout_event << dendl; timer.cancel_event(probe_timeout_event); probe_timeout_event = NULL; } else { dout(10) << "cancel_probe_timeout (none scheduled)" << dendl; } } void Monitor::reset_probe_timeout() { cancel_probe_timeout(); probe_timeout_event = new C_ProbeTimeout(this); double t = g_conf->mon_probe_timeout; timer.add_event_after(t, probe_timeout_event); dout(10) << "reset_probe_timeout " << probe_timeout_event << " after " << t << " seconds" << dendl; } void Monitor::probe_timeout(int r) { dout(4) << "probe_timeout " << probe_timeout_event << dendl; assert(is_probing() || is_synchronizing()); assert(probe_timeout_event); probe_timeout_event = NULL; bootstrap(); } void Monitor::handle_probe(MMonProbe *m) { dout(10) << "handle_probe " << *m << dendl; if (m->fsid != monmap->fsid) { dout(0) << "handle_probe ignoring fsid " << m->fsid << " != " << monmap->fsid << dendl; m->put(); return; } switch (m->op) { case MMonProbe::OP_PROBE: handle_probe_probe(m); break; case MMonProbe::OP_REPLY: handle_probe_reply(m); break; case MMonProbe::OP_MISSING_FEATURES: derr << __func__ << " missing features, have " << CEPH_FEATURES_ALL << ", required " << required_features << ", missing " << (required_features & ~CEPH_FEATURES_ALL) << dendl; break; default: m->put(); } } /** * @todo fix this. This is going to cause trouble. */ void Monitor::handle_probe_probe(MMonProbe *m) { MMonProbe *r; dout(10) << "handle_probe_probe " << m->get_source_inst() << *m << " features " << m->get_connection()->get_features() << dendl; uint64_t missing = required_features & ~m->get_connection()->get_features(); if (missing) { dout(1) << " peer " << m->get_source_addr() << " missing features " << missing << dendl; if (m->get_connection()->has_feature(CEPH_FEATURE_OSD_PRIMARY_AFFINITY)) { MMonProbe *r = new MMonProbe(monmap->fsid, MMonProbe::OP_MISSING_FEATURES, name, has_ever_joined); m->required_features = required_features; messenger->send_message(r, m->get_connection()); } goto out; } if (!is_probing() && !is_synchronizing()) { // If the probing mon is way ahead of us, we need to re-bootstrap. // Normally we capture this case when we initially bootstrap, but // it is possible we pass those checks (we overlap with // quorum-to-be) but fail to join a quorum before it moves past // us. We need to be kicked back to bootstrap so we can // synchonize, not keep calling elections. if (paxos->get_version() + 1 < m->paxos_first_version) { dout(1) << " peer " << m->get_source_addr() << " has first_committed " << "ahead of us, re-bootstrapping" << dendl; bootstrap(); goto out; } } r = new MMonProbe(monmap->fsid, MMonProbe::OP_REPLY, name, has_ever_joined); r->name = name; r->quorum = quorum; monmap->encode(r->monmap_bl, m->get_connection()->get_features()); r->paxos_first_version = paxos->get_first_committed(); r->paxos_last_version = paxos->get_version(); messenger->send_message(r, m->get_connection()); // did we discover a peer here? if (!monmap->contains(m->get_source_addr())) { dout(1) << " adding peer " << m->get_source_addr() << " to list of hints" << dendl; extra_probe_peers.insert(m->get_source_addr()); } out: m->put(); } void Monitor::handle_probe_reply(MMonProbe *m) { dout(10) << "handle_probe_reply " << m->get_source_inst() << *m << dendl; dout(10) << " monmap is " << *monmap << dendl; // discover name and addrs during probing or electing states. if (!is_probing() && !is_electing()) { m->put(); return; } // newer map, or they've joined a quorum and we haven't? bufferlist mybl; monmap->encode(mybl, m->get_connection()->get_features()); // make sure it's actually different; the checks below err toward // taking the other guy's map, which could cause us to loop. if (!mybl.contents_equal(m->monmap_bl)) { MonMap *newmap = new MonMap; newmap->decode(m->monmap_bl); if (m->has_ever_joined && (newmap->get_epoch() > monmap->get_epoch() || !has_ever_joined)) { dout(10) << " got newer/committed monmap epoch " << newmap->get_epoch() << ", mine was " << monmap->get_epoch() << dendl; delete newmap; monmap->decode(m->monmap_bl); m->put(); bootstrap(); return; } delete newmap; } // rename peer? string peer_name = monmap->get_name(m->get_source_addr()); if (monmap->get_epoch() == 0 && peer_name.find("noname-") == 0) { dout(10) << " renaming peer " << m->get_source_addr() << " " << peer_name << " -> " << m->name << " in my monmap" << dendl; monmap->rename(peer_name, m->name); if (is_electing()) { m->put(); bootstrap(); return; } } else { dout(10) << " peer name is " << peer_name << dendl; } // new initial peer? if (monmap->get_epoch() == 0 && monmap->contains(m->name) && monmap->get_addr(m->name).is_blank_ip()) { dout(1) << " learned initial mon " << m->name << " addr " << m->get_source_addr() << dendl; monmap->set_addr(m->name, m->get_source_addr()); m->put(); bootstrap(); return; } // end discover phase if (!is_probing()) { m->put(); return; } assert(paxos != NULL); if (is_synchronizing()) { dout(10) << " currently syncing" << dendl; m->put(); return; } entity_inst_t other = m->get_source_inst(); if (m->paxos_last_version < sync_last_committed_floor) { dout(10) << " peer paxos versions [" << m->paxos_first_version << "," << m->paxos_last_version << "] < my sync_last_committed_floor " << sync_last_committed_floor << ", ignoring" << dendl; } else { if (paxos->get_version() < m->paxos_first_version && m->paxos_first_version > 1) { // no need to sync if we're 0 and they start at 1. dout(10) << " peer paxos versions [" << m->paxos_first_version << "," << m->paxos_last_version << "]" << " vs my version " << paxos->get_version() << " (too far ahead)" << dendl; cancel_probe_timeout(); sync_start(other, true); m->put(); return; } if (paxos->get_version() + g_conf->paxos_max_join_drift < m->paxos_last_version) { dout(10) << " peer paxos version " << m->paxos_last_version << " vs my version " << paxos->get_version() << " (too far ahead)" << dendl; cancel_probe_timeout(); sync_start(other, false); m->put(); return; } } // is there an existing quorum? if (m->quorum.size()) { dout(10) << " existing quorum " << m->quorum << dendl; dout(10) << " peer paxos version " << m->paxos_last_version << " vs my version " << paxos->get_version() << " (ok)" << dendl; if (monmap->contains(name) && !monmap->get_addr(name).is_blank_ip()) { // i'm part of the cluster; just initiate a new election start_election(); } else { dout(10) << " ready to join, but i'm not in the monmap or my addr is blank, trying to join" << dendl; messenger->send_message(new MMonJoin(monmap->fsid, name, messenger->get_myaddr()), monmap->get_inst(*m->quorum.begin())); } } else { if (monmap->contains(m->name)) { dout(10) << " mon." << m->name << " is outside the quorum" << dendl; outside_quorum.insert(m->name); } else { dout(10) << " mostly ignoring mon." << m->name << ", not part of monmap" << dendl; m->put(); return; } unsigned need = monmap->size() / 2 + 1; dout(10) << " outside_quorum now " << outside_quorum << ", need " << need << dendl; if (outside_quorum.size() >= need) { if (outside_quorum.count(name)) { dout(10) << " that's enough to form a new quorum, calling election" << dendl; start_election(); } else { dout(10) << " that's enough to form a new quorum, but it does not include me; waiting" << dendl; } } else { dout(10) << " that's not yet enough for a new quorum, waiting" << dendl; } } m->put(); } void Monitor::join_election() { dout(10) << __func__ << dendl; state = STATE_ELECTING; _reset(); } void Monitor::start_election() { dout(10) << "start_election" << dendl; state = STATE_ELECTING; _reset(); cancel_probe_timeout(); clog.info() << "mon." << name << " calling new monitor election\n"; elector.call_election(); } void Monitor::win_standalone_election() { dout(1) << "win_standalone_election" << dendl; // bump election epoch, in case the previous epoch included other // monitors; we need to be able to make the distinction. elector.advance_epoch(); rank = monmap->get_rank(name); assert(rank == 0); set q; q.insert(rank); const MonCommand *my_cmds; int cmdsize; get_locally_supported_monitor_commands(&my_cmds, &cmdsize); win_election(1, q, CEPH_FEATURES_ALL, my_cmds, cmdsize, NULL); } const utime_t& Monitor::get_leader_since() const { assert(state == STATE_LEADER); return leader_since; } epoch_t Monitor::get_epoch() { return elector.get_epoch(); } void Monitor::win_election(epoch_t epoch, set& active, uint64_t features, const MonCommand *cmdset, int cmdsize, const set *classic_monitors) { dout(10) << __func__ << " epoch " << epoch << " quorum " << active << " features " << features << dendl; assert(is_electing()); state = STATE_LEADER; leader_since = ceph_clock_now(g_ceph_context); leader = rank; quorum = active; quorum_features = features; outside_quorum.clear(); clog.info() << "mon." << name << "@" << rank << " won leader election with quorum " << quorum << "\n"; set_leader_supported_commands(cmdset, cmdsize); if (classic_monitors) classic_mons = *classic_monitors; paxos->leader_init(); // NOTE: tell monmap monitor first. This is important for the // bootstrap case to ensure that the very first paxos proposal // codifies the monmap. Otherwise any manner of chaos can ensue // when monitors are call elections or participating in a paxos // round without agreeing on who the participants are. monmon()->election_finished(); for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) { if (*p != monmon()) (*p)->election_finished(); } health_monitor->start(epoch); finish_election(); if (monmap->size() > 1 && monmap->get_epoch() > 0) timecheck_start(); } void Monitor::lose_election(epoch_t epoch, set &q, int l, uint64_t features) { state = STATE_PEON; leader_since = utime_t(); leader = l; quorum = q; outside_quorum.clear(); quorum_features = features; dout(10) << "lose_election, epoch " << epoch << " leader is mon" << leader << " quorum is " << quorum << " features are " << quorum_features << dendl; paxos->peon_init(); for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) (*p)->election_finished(); health_monitor->start(epoch); finish_election(); } void Monitor::finish_election() { apply_quorum_to_compatset_features(); timecheck_finish(); exited_quorum = utime_t(); finish_contexts(g_ceph_context, waitfor_quorum); finish_contexts(g_ceph_context, maybe_wait_for_quorum); resend_routed_requests(); update_logger(); register_cluster_logger(); // am i named properly? string cur_name = monmap->get_name(messenger->get_myaddr()); if (cur_name != name) { dout(10) << " renaming myself from " << cur_name << " -> " << name << dendl; messenger->send_message(new MMonJoin(monmap->fsid, name, messenger->get_myaddr()), monmap->get_inst(*quorum.begin())); } } void Monitor::apply_quorum_to_compatset_features() { CompatSet new_features(features); if (quorum_features & CEPH_FEATURE_OSD_ERASURE_CODES) { new_features.incompat.insert(CEPH_MON_FEATURE_INCOMPAT_OSD_ERASURE_CODES); } if (quorum_features & CEPH_FEATURE_OSDMAP_ENC) { new_features.incompat.insert(CEPH_MON_FEATURE_INCOMPAT_OSDMAP_ENC); } if (new_features.compare(features) != 0) { CompatSet diff = features.unsupported(new_features); dout(1) << __func__ << " enabling new quorum features: " << diff << dendl; features = new_features; MonitorDBStore::Transaction t; write_features(t); store->apply_transaction(t); apply_compatset_features_to_quorum_requirements(); } } void Monitor::apply_compatset_features_to_quorum_requirements() { required_features = 0; if (features.incompat.contains(CEPH_MON_FEATURE_INCOMPAT_OSD_ERASURE_CODES)) { required_features |= CEPH_FEATURE_OSD_ERASURE_CODES; } if (features.incompat.contains(CEPH_MON_FEATURE_INCOMPAT_OSDMAP_ENC)) { required_features |= CEPH_FEATURE_OSDMAP_ENC; } dout(10) << __func__ << " required_features " << required_features << dendl; } void Monitor::sync_force(Formatter *f, ostream& ss) { bool free_formatter = false; if (!f) { // louzy/lazy hack: default to json if no formatter has been defined f = new JSONFormatter(); free_formatter = true; } MonitorDBStore::Transaction tx; sync_stash_critical_state(&tx); tx.put("mon_sync", "force_sync", 1); store->apply_transaction(tx); f->open_object_section("sync_force"); f->dump_int("ret", 0); f->dump_stream("msg") << "forcing store sync the next time the monitor starts"; f->close_section(); // sync_force f->flush(ss); if (free_formatter) delete f; } void Monitor::_quorum_status(Formatter *f, ostream& ss) { bool free_formatter = false; if (!f) { // louzy/lazy hack: default to json if no formatter has been defined f = new JSONFormatter(); free_formatter = true; } f->open_object_section("quorum_status"); f->dump_int("election_epoch", get_epoch()); f->open_array_section("quorum"); for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) f->dump_int("mon", *p); f->close_section(); // quorum list quorum_names = get_quorum_names(); f->open_array_section("quorum_names"); for (list::iterator p = quorum_names.begin(); p != quorum_names.end(); ++p) f->dump_string("mon", *p); f->close_section(); // quorum_names f->dump_string("quorum_leader_name", quorum.empty() ? string() : monmap->get_name(*quorum.begin())); f->open_object_section("monmap"); monmap->dump(f); f->close_section(); // monmap f->close_section(); // quorum_status f->flush(ss); if (free_formatter) delete f; } void Monitor::get_mon_status(Formatter *f, ostream& ss) { bool free_formatter = false; if (!f) { // louzy/lazy hack: default to json if no formatter has been defined f = new JSONFormatter(); free_formatter = true; } f->open_object_section("mon_status"); f->dump_string("name", name); f->dump_int("rank", rank); f->dump_string("state", get_state_name()); f->dump_int("election_epoch", get_epoch()); f->open_array_section("quorum"); for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) { f->dump_int("mon", *p); } f->close_section(); // quorum f->open_array_section("outside_quorum"); for (set::iterator p = outside_quorum.begin(); p != outside_quorum.end(); ++p) f->dump_string("mon", *p); f->close_section(); // outside_quorum f->open_array_section("extra_probe_peers"); for (set::iterator p = extra_probe_peers.begin(); p != extra_probe_peers.end(); ++p) f->dump_stream("peer") << *p; f->close_section(); // extra_probe_peers f->open_array_section("sync_provider"); for (map::const_iterator p = sync_providers.begin(); p != sync_providers.end(); ++p) { f->dump_unsigned("cookie", p->second.cookie); f->dump_stream("entity") << p->second.entity; f->dump_stream("timeout") << p->second.timeout; f->dump_unsigned("last_committed", p->second.last_committed); f->dump_stream("last_key") << p->second.last_key; } f->close_section(); if (is_synchronizing()) { f->open_object_section("sync"); f->dump_stream("sync_provider") << sync_provider; f->dump_unsigned("sync_cookie", sync_cookie); f->dump_unsigned("sync_start_version", sync_start_version); f->close_section(); } if (g_conf->mon_sync_provider_kill_at > 0) f->dump_int("provider_kill_at", g_conf->mon_sync_provider_kill_at); if (g_conf->mon_sync_requester_kill_at > 0) f->dump_int("requester_kill_at", g_conf->mon_sync_requester_kill_at); f->open_object_section("monmap"); monmap->dump(f); f->close_section(); f->close_section(); // mon_status if (free_formatter) { // flush formatter to ss and delete it iff we created the formatter f->flush(ss); delete f; } } void Monitor::get_health(string& status, bufferlist *detailbl, Formatter *f) { list > summary; list > detail; if (f) f->open_object_section("health"); for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) { PaxosService *s = *p; s->get_health(summary, detailbl ? &detail : NULL); } health_monitor->get_health(f, summary, (detailbl ? &detail : NULL)); if (f) { f->open_object_section("timechecks"); f->dump_int("epoch", get_epoch()); f->dump_int("round", timecheck_round); f->dump_stream("round_status") << ((timecheck_round%2) ? "on-going" : "finished"); } stringstream ss; health_status_t overall = HEALTH_OK; if (!timecheck_skews.empty()) { list warns; if (f) f->open_array_section("mons"); for (map::iterator i = timecheck_skews.begin(); i != timecheck_skews.end(); ++i) { entity_inst_t inst = i->first; double skew = i->second; double latency = timecheck_latencies[inst]; string name = monmap->get_name(inst.addr); ostringstream tcss; health_status_t tcstatus = timecheck_status(tcss, skew, latency); if (tcstatus != HEALTH_OK) { if (overall > tcstatus) overall = tcstatus; warns.push_back(name); ostringstream tmp_ss; tmp_ss << "mon." << name << " addr " << inst.addr << " " << tcss.str() << " (latency " << latency << "s)"; detail.push_back(make_pair(tcstatus, tmp_ss.str())); } if (f) { f->open_object_section("mon"); f->dump_string("name", name.c_str()); f->dump_float("skew", skew); f->dump_float("latency", latency); f->dump_stream("health") << tcstatus; if (tcstatus != HEALTH_OK) f->dump_stream("details") << tcss.str(); f->close_section(); } } if (!warns.empty()) { if (!ss.str().empty()) ss << ";"; ss << " clock skew detected on"; while (!warns.empty()) { ss << " mon." << warns.front(); warns.pop_front(); if (!warns.empty()) ss << ","; } summary.push_back(make_pair(HEALTH_WARN, "Monitor clock skew detected ")); } if (f) f->close_section(); } if (f) f->close_section(); if (f) f->open_array_section("summary"); if (!summary.empty()) { ss << ' '; while (!summary.empty()) { if (overall > summary.front().first) overall = summary.front().first; ss << summary.front().second; if (f) { f->open_object_section("item"); f->dump_stream("severity") << summary.front().first; f->dump_string("summary", summary.front().second); f->close_section(); } summary.pop_front(); if (!summary.empty()) ss << "; "; } } if (f) f->close_section(); stringstream fss; fss << overall; status = fss.str() + ss.str(); if (f) f->dump_stream("overall_status") << overall; if (f) f->open_array_section("detail"); while (!detail.empty()) { if (f) f->dump_string("item", detail.front().second); else if (detailbl != NULL) { detailbl->append(detail.front().second); detailbl->append('\n'); } detail.pop_front(); } if (f) f->close_section(); if (f) f->close_section(); } void Monitor::get_cluster_status(stringstream &ss, Formatter *f) { if (f) f->open_object_section("status"); // reply with the status for all the components string health; get_health(health, NULL, f); if (f) { f->dump_stream("fsid") << monmap->get_fsid(); f->dump_unsigned("election_epoch", get_epoch()); { f->open_array_section("quorum"); for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) f->dump_int("rank", *p); f->close_section(); f->open_array_section("quorum_names"); for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) f->dump_string("id", monmap->get_name(*p)); f->close_section(); } f->open_object_section("monmap"); monmap->dump(f); f->close_section(); f->open_object_section("osdmap"); osdmon()->osdmap.print_summary(f, cout); f->close_section(); f->open_object_section("pgmap"); pgmon()->pg_map.print_summary(f, NULL); f->close_section(); f->open_object_section("mdsmap"); mdsmon()->mdsmap.print_summary(f, NULL); f->close_section(); f->close_section(); } else { ss << " cluster " << monmap->get_fsid() << "\n"; ss << " health " << health << "\n"; ss << " monmap " << *monmap << ", election epoch " << get_epoch() << ", quorum " << get_quorum() << " " << get_quorum_names() << "\n"; if (mdsmon()->mdsmap.get_epoch() > 1) ss << " mdsmap " << mdsmon()->mdsmap << "\n"; osdmon()->osdmap.print_summary(NULL, ss); pgmon()->pg_map.print_summary(NULL, &ss); } } void Monitor::_generate_command_map(map& cmdmap, map ¶m_str_map) { for (map::const_iterator p = cmdmap.begin(); p != cmdmap.end(); ++p) { if (p->first == "prefix") continue; if (p->first == "caps") { vector cv; if (cmd_getval(g_ceph_context, cmdmap, "caps", cv) && cv.size() % 2 == 0) { for (unsigned i = 0; i < cv.size(); i += 2) { string k = string("caps_") + cv[i]; param_str_map[k] = cv[i + 1]; } continue; } } param_str_map[p->first] = cmd_vartype_stringify(p->second); } } const MonCommand *Monitor::_get_moncommand(const string &cmd_prefix, MonCommand *cmds, int cmds_size) { MonCommand *this_cmd = NULL; for (MonCommand *cp = cmds; cp < &cmds[cmds_size]; cp++) { if (cp->cmdstring.find(cmd_prefix) != string::npos) { this_cmd = cp; break; } } return this_cmd; } bool Monitor::_allowed_command(MonSession *s, string &module, string &prefix, const map& cmdmap, const map& param_str_map, const MonCommand *this_cmd) { bool cmd_r = (this_cmd->req_perms.find('r') != string::npos); bool cmd_w = (this_cmd->req_perms.find('w') != string::npos); bool cmd_x = (this_cmd->req_perms.find('x') != string::npos); bool capable = s->caps.is_capable(g_ceph_context, s->entity_name, module, prefix, param_str_map, cmd_r, cmd_w, cmd_x); dout(10) << __func__ << " " << (capable ? "" : "not ") << "capable" << dendl; return capable; } void Monitor::format_command_descriptions(const MonCommand *commands, unsigned commands_size, Formatter *f, bufferlist *rdata) { int cmdnum = 0; f->open_object_section("command_descriptions"); for (const MonCommand *cp = commands; cp < &commands[commands_size]; cp++) { ostringstream secname; secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; dump_cmddesc_to_json(f, secname.str(), cp->cmdstring, cp->helpstring, cp->module, cp->req_perms, cp->availability); cmdnum++; } f->close_section(); // command_descriptions f->flush(*rdata); } void Monitor::get_locally_supported_monitor_commands(const MonCommand **cmds, int *count) { *cmds = mon_commands; *count = ARRAY_SIZE(mon_commands); } void Monitor::get_leader_supported_commands(const MonCommand **cmds, int *count) { *cmds = leader_supported_mon_commands; *count = leader_supported_mon_commands_size; } void Monitor::get_classic_monitor_commands(const MonCommand **cmds, int *count) { *cmds = classic_mon_commands; *count = ARRAY_SIZE(classic_mon_commands); } void Monitor::set_leader_supported_commands(const MonCommand *cmds, int size) { if (leader_supported_mon_commands != mon_commands && leader_supported_mon_commands != classic_mon_commands) delete[] leader_supported_mon_commands; leader_supported_mon_commands = cmds; leader_supported_mon_commands_size = size; } bool Monitor::is_keyring_required() { string auth_cluster_required = g_conf->auth_supported.length() ? g_conf->auth_supported : g_conf->auth_cluster_required; string auth_service_required = g_conf->auth_supported.length() ? g_conf->auth_supported : g_conf->auth_service_required; return auth_service_required == "cephx" || auth_cluster_required == "cephx"; } void Monitor::handle_command(MMonCommand *m) { if (m->fsid != monmap->fsid) { dout(0) << "handle_command on fsid " << m->fsid << " != " << monmap->fsid << dendl; reply_command(m, -EPERM, "wrong fsid", 0); return; } MonSession *session = m->get_session(); if (!session) { string rs = "Access denied"; reply_command(m, -EACCES, rs, 0); return; } if (m->cmd.empty()) { string rs = "No command supplied"; reply_command(m, -EINVAL, rs, 0); return; } string prefix; vector fullcmd; map cmdmap; stringstream ss, ds; bufferlist rdata; string rs; int r = -EINVAL; rs = "unrecognized command"; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure r = -EINVAL; rs = ss.str(); if (!m->get_source().is_mon()) // don't reply to mon->mon commands reply_command(m, r, rs, 0); else m->put(); return; } cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); if (prefix == "get_command_descriptions") { bufferlist rdata; Formatter *f = new_formatter("json"); format_command_descriptions(leader_supported_mon_commands, leader_supported_mon_commands_size, f, &rdata); delete f; reply_command(m, 0, "", rdata, 0); return; } string module; string err; dout(0) << "handle_command " << *m << dendl; string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); get_str_vec(prefix, fullcmd); module = fullcmd[0]; // validate command is in leader map const MonCommand *leader_cmd; leader_cmd = _get_moncommand(prefix, // the boost underlying this isn't const for some reason const_cast(leader_supported_mon_commands), leader_supported_mon_commands_size); if (!leader_cmd) { reply_command(m, -EINVAL, "command not known", 0); return; } // validate command is in our map & matches, or forward const MonCommand *mon_cmd = _get_moncommand(prefix, mon_commands, ARRAY_SIZE(mon_commands)); if (!is_leader() && (!mon_cmd || (*leader_cmd != *mon_cmd))) { dout(10) << "We don't match leader, forwarding request " << m << dendl; forward_request_leader(m); return; } // validate user's permissions for requested command map param_str_map; _generate_command_map(cmdmap, param_str_map); if (!_allowed_command(session, module, prefix, cmdmap, param_str_map, mon_cmd)) { dout(1) << __func__ << " access denied" << dendl; reply_command(m, -EACCES, "access denied", 0); return; } if (module == "mds") { mdsmon()->dispatch(m); return; } if (module == "osd") { osdmon()->dispatch(m); return; } if (module == "pg") { pgmon()->dispatch(m); return; } if (module == "mon") { monmon()->dispatch(m); return; } if (module == "auth") { authmon()->dispatch(m); return; } if (module == "log") { logmon()->dispatch(m); return; } if (module == "config-key") { config_key_service->dispatch(m); return; } if (prefix == "fsid") { if (f) { f->open_object_section("fsid"); f->dump_stream("fsid") << monmap->fsid; f->close_section(); f->flush(rdata); } else { ds << monmap->fsid; rdata.append(ds); } reply_command(m, 0, "", rdata, 0); return; } if (prefix == "scrub") { if (is_leader()) { int r = scrub(); reply_command(m, r, "", rdata, 0); } else if (is_peon()) { forward_request_leader(m); } else { reply_command(m, -EAGAIN, "no quorum", rdata, 0); } return; } if (prefix == "compact") { dout(1) << "triggering manual compaction" << dendl; utime_t start = ceph_clock_now(g_ceph_context); store->compact(); utime_t end = ceph_clock_now(g_ceph_context); end -= start; dout(1) << "finished manual compaction in " << end << " seconds" << dendl; ostringstream oss; oss << "compacted leveldb in " << end; rs = oss.str(); r = 0; } else if (prefix == "injectargs") { vector injected_args; cmd_getval(g_ceph_context, cmdmap, "injected_args", injected_args); if (!injected_args.empty()) { dout(0) << "parsing injected options '" << injected_args << "'" << dendl; ostringstream oss; r = g_conf->injectargs(str_join(injected_args, " "), &oss); ss << "injectargs:" << oss.str(); rs = ss.str(); goto out; } else { rs = "must supply options to be parsed in a single string"; r = -EINVAL; } } else if (prefix == "status" || prefix == "health" || prefix == "df") { string detail; cmd_getval(g_ceph_context, cmdmap, "detail", detail); if (prefix == "status") { // get_cluster_status handles f == NULL get_cluster_status(ds, f.get()); if (f) { f->flush(ds); ds << '\n'; } rdata.append(ds); } else if (prefix == "health") { string health_str; get_health(health_str, detail == "detail" ? &rdata : NULL, f.get()); if (f) { f->flush(ds); ds << '\n'; } else { ds << health_str; } bufferlist comb; comb.append(ds); if (detail == "detail") comb.append(rdata); rdata = comb; r = 0; } else if (prefix == "df") { bool verbose = (detail == "detail"); if (f) f->open_object_section("stats"); pgmon()->dump_fs_stats(ds, f.get(), verbose); if (!f) ds << '\n'; pgmon()->dump_pool_stats(ds, f.get(), verbose); if (f) { f->close_section(); f->flush(ds); ds << '\n'; } } else { assert(0 == "We should never get here!"); return; } rdata.append(ds); rs = ""; r = 0; } else if (prefix == "report") { // this must be formatted, in its current form if (!f) f.reset(new_formatter("json-pretty")); f->open_object_section("report"); f->dump_stream("cluster_fingerprint") << fingerprint; f->dump_string("version", ceph_version_to_str()); f->dump_string("commit", git_version_to_str()); f->dump_stream("timestamp") << ceph_clock_now(NULL); vector tagsvec; cmd_getval(g_ceph_context, cmdmap, "tags", tagsvec); string tagstr = str_join(tagsvec, " "); if (!tagstr.empty()) tagstr = tagstr.substr(0, tagstr.find_last_of(' ')); f->dump_string("tag", tagstr); string hs; get_health(hs, NULL, f.get()); monmon()->dump_info(f.get()); osdmon()->dump_info(f.get()); mdsmon()->dump_info(f.get()); pgmon()->dump_info(f.get()); authmon()->dump_info(f.get()); paxos->dump_info(f.get()); f->close_section(); f->flush(rdata); ostringstream ss2; ss2 << "report " << rdata.crc32c(6789); rs = ss2.str(); r = 0; } else if (prefix == "quorum_status") { // make sure our map is readable and up to date if (!is_leader() && !is_peon()) { dout(10) << " waiting for quorum" << dendl; waitfor_quorum.push_back(new C_RetryMessage(this, m)); return; } _quorum_status(f.get(), ds); rdata.append(ds); rs = ""; r = 0; } else if (prefix == "mon_status") { get_mon_status(f.get(), ds); if (f) f->flush(ds); rdata.append(ds); rs = ""; r = 0; } else if (prefix == "sync force") { string validate1, validate2; cmd_getval(g_ceph_context, cmdmap, "validate1", validate1); cmd_getval(g_ceph_context, cmdmap, "validate2", validate2); if (validate1 != "--yes-i-really-mean-it" || validate2 != "--i-know-what-i-am-doing") { r = -EINVAL; rs = "are you SURE? this will mean the monitor store will be " "erased. pass '--yes-i-really-mean-it " "--i-know-what-i-am-doing' if you really do."; goto out; } sync_force(f.get(), ds); rs = ds.str(); r = 0; } else if (prefix == "heap") { if (!ceph_using_tcmalloc()) rs = "tcmalloc not enabled, can't use heap profiler commands\n"; else { string heapcmd; cmd_getval(g_ceph_context, cmdmap, "heapcmd", heapcmd); // XXX 1-element vector, change at callee or make vector here? vector heapcmd_vec; get_str_vec(heapcmd, heapcmd_vec); ceph_heap_profiler_handle_command(heapcmd_vec, ds); rdata.append(ds); rs = ""; r = 0; } } else if (prefix == "quorum") { string quorumcmd; cmd_getval(g_ceph_context, cmdmap, "quorumcmd", quorumcmd); if (quorumcmd == "exit") { start_election(); elector.stop_participating(); rs = "stopped responding to quorum, initiated new election"; r = 0; } else if (quorumcmd == "enter") { elector.start_participating(); start_election(); rs = "started responding to quorum, initiated new election"; r = 0; } else { rs = "needs a valid 'quorum' command"; r = -EINVAL; } } out: if (!m->get_source().is_mon()) // don't reply to mon->mon commands reply_command(m, r, rs, rdata, 0); else m->put(); } void Monitor::reply_command(MMonCommand *m, int rc, const string &rs, version_t version) { bufferlist rdata; reply_command(m, rc, rs, rdata, version); } void Monitor::reply_command(MMonCommand *m, int rc, const string &rs, bufferlist& rdata, version_t version) { MMonCommandAck *reply = new MMonCommandAck(m->cmd, rc, rs, version); reply->set_tid(m->get_tid()); reply->set_data(rdata); send_reply(m, reply); m->put(); } // ------------------------ // request/reply routing // // a client/mds/osd will connect to a random monitor. we need to forward any // messages requiring state updates to the leader, and then route any replies // back via the correct monitor and back to them. (the monitor will not // initiate any connections.) void Monitor::forward_request_leader(PaxosServiceMessage *req) { int mon = get_leader(); MonSession *session = 0; if (req->get_connection()) session = static_cast(req->get_connection()->get_priv()); if (req->get_source().is_mon() && req->get_source_addr() != messenger->get_myaddr()) { dout(10) << "forward_request won't forward (non-local) mon request " << *req << dendl; req->put(); } else if (session && session->proxy_con) { dout(10) << "forward_request won't double fwd request " << *req << dendl; req->put(); } else if (session && !session->closed) { RoutedRequest *rr = new RoutedRequest; rr->tid = ++routed_request_tid; rr->client_inst = req->get_source_inst(); rr->con = req->get_connection(); rr->con_features = rr->con->get_features(); encode_message(req, CEPH_FEATURES_ALL, rr->request_bl); // for my use only; use all features rr->session = static_cast(session->get()); routed_requests[rr->tid] = rr; session->routed_request_tids.insert(rr->tid); dout(10) << "forward_request " << rr->tid << " request " << *req << " features " << rr->con_features << dendl; MForward *forward = new MForward(rr->tid, req, rr->con_features, rr->session->caps); forward->set_priority(req->get_priority()); messenger->send_message(forward, monmap->get_inst(mon)); } else { dout(10) << "forward_request no session for request " << *req << dendl; req->put(); } if (session) session->put(); } //extract the original message and put it into the regular dispatch function void Monitor::handle_forward(MForward *m) { dout(10) << "received forwarded message from " << m->client << " via " << m->get_source_inst() << dendl; MonSession *session = static_cast(m->get_connection()->get_priv()); assert(session); if (!session->is_capable("mon", MON_CAP_X)) { dout(0) << "forward from entity with insufficient caps! " << session->caps << dendl; } else { Connection *c = new Connection(NULL); // msgr must be null; see PaxosService::dispatch() MonSession *s = new MonSession(m->msg->get_source_inst(), c); c->set_priv(s); c->set_peer_addr(m->client.addr); c->set_peer_type(m->client.name.type()); c->set_features(m->con_features); s->caps = m->client_caps; dout(10) << " caps are " << s->caps << dendl; s->proxy_con = m->get_connection(); s->proxy_tid = m->tid; PaxosServiceMessage *req = m->msg; m->msg = NULL; // so ~MForward doesn't delete it req->set_connection(c); // not super accurate, but better than nothing. req->set_recv_stamp(m->get_recv_stamp()); /* * note which election epoch this is; we will drop the message if * there is a future election since our peers will resend routed * requests in that case. */ req->rx_election_epoch = get_epoch(); /* Because this is a special fake connection, we need to break the ref loop between Connection and MonSession differently than we normally do. Here, the Message refers to the Connection which refers to the Session, and nobody else refers to the Connection or the Session. And due to the special nature of this message, nobody refers to the Connection via the Session. So, clear out that half of the ref loop.*/ s->con.reset(NULL); dout(10) << " mesg " << req << " from " << m->get_source_addr() << dendl; _ms_dispatch(req); } session->put(); m->put(); } void Monitor::try_send_message(Message *m, const entity_inst_t& to) { dout(10) << "try_send_message " << *m << " to " << to << dendl; bufferlist bl; encode_message(m, quorum_features, bl); messenger->send_message(m, to); for (int i=0; i<(int)monmap->size(); i++) { if (i != rank) messenger->send_message(new MRoute(bl, to), monmap->get_inst(i)); } } void Monitor::send_reply(PaxosServiceMessage *req, Message *reply) { ConnectionRef connection = req->get_connection(); if (!connection) { dout(2) << "send_reply no connection, dropping reply " << *reply << " to " << req << " " << *req << dendl; reply->put(); return; } MonSession *session = static_cast(connection->get_priv()); if (!session) { dout(2) << "send_reply no session, dropping reply " << *reply << " to " << req << " " << *req << dendl; reply->put(); return; } if (session->proxy_con) { dout(15) << "send_reply routing reply to " << req->get_connection()->get_peer_addr() << " via " << session->proxy_con->get_peer_addr() << " for request " << *req << dendl; messenger->send_message(new MRoute(session->proxy_tid, reply), session->proxy_con); } else { messenger->send_message(reply, session->con); } session->put(); } void Monitor::no_reply(PaxosServiceMessage *req) { MonSession *session = static_cast(req->get_connection()->get_priv()); if (!session) { dout(2) << "no_reply no session, dropping non-reply to " << req << " " << *req << dendl; return; } if (session->proxy_con) { if (get_quorum_features() & CEPH_FEATURE_MON_NULLROUTE) { dout(10) << "no_reply to " << req->get_source_inst() << " via " << session->proxy_con->get_peer_addr() << " for request " << *req << dendl; messenger->send_message(new MRoute(session->proxy_tid, NULL), session->proxy_con); } else { dout(10) << "no_reply no quorum nullroute feature for " << req->get_source_inst() << " via " << session->proxy_con->get_peer_addr() << " for request " << *req << dendl; } } else { dout(10) << "no_reply to " << req->get_source_inst() << " " << *req << dendl; } session->put(); } void Monitor::handle_route(MRoute *m) { MonSession *session = static_cast(m->get_connection()->get_priv()); //check privileges if (session && !session->is_capable("mon", MON_CAP_X)) { dout(0) << "MRoute received from entity without appropriate perms! " << dendl; session->put(); m->put(); return; } if (m->msg) dout(10) << "handle_route " << *m->msg << " to " << m->dest << dendl; else dout(10) << "handle_route null to " << m->dest << dendl; // look it up if (m->session_mon_tid) { if (routed_requests.count(m->session_mon_tid)) { RoutedRequest *rr = routed_requests[m->session_mon_tid]; // reset payload, in case encoding is dependent on target features if (m->msg) { m->msg->clear_payload(); messenger->send_message(m->msg, rr->con); m->msg = NULL; } routed_requests.erase(m->session_mon_tid); rr->session->routed_request_tids.insert(rr->tid); delete rr; } else { dout(10) << " don't have routed request tid " << m->session_mon_tid << dendl; } } else { dout(10) << " not a routed request, trying to send anyway" << dendl; if (m->msg) { messenger->lazy_send_message(m->msg, m->dest); m->msg = NULL; } } m->put(); if (session) session->put(); } void Monitor::resend_routed_requests() { dout(10) << "resend_routed_requests" << dendl; int mon = get_leader(); list retry; for (map::iterator p = routed_requests.begin(); p != routed_requests.end(); ++p) { RoutedRequest *rr = p->second; bufferlist::iterator q = rr->request_bl.begin(); PaxosServiceMessage *req = (PaxosServiceMessage *)decode_message(cct, q); if (mon == rank) { dout(10) << " requeue for self tid " << rr->tid << " " << *req << dendl; req->set_connection(rr->con); retry.push_back(new C_RetryMessage(this, req)); delete rr; } else { dout(10) << " resend to mon." << mon << " tid " << rr->tid << " " << *req << dendl; MForward *forward = new MForward(rr->tid, req, rr->con_features, rr->session->caps); forward->client = rr->client_inst; forward->set_priority(req->get_priority()); messenger->send_message(forward, monmap->get_inst(mon)); } } if (mon == rank) { routed_requests.clear(); finish_contexts(g_ceph_context, retry); } } void Monitor::remove_session(MonSession *s) { dout(10) << "remove_session " << s << " " << s->inst << dendl; assert(!s->closed); for (set::iterator p = s->routed_request_tids.begin(); p != s->routed_request_tids.end(); ++p) { if (routed_requests.count(*p)) { RoutedRequest *rr = routed_requests[*p]; dout(10) << " dropping routed request " << rr->tid << dendl; delete rr; routed_requests.erase(*p); } } s->con->set_priv(NULL); session_map.remove_session(s); } void Monitor::remove_all_sessions() { while (!session_map.sessions.empty()) { MonSession *s = session_map.sessions.front(); remove_session(s); } } void Monitor::send_command(const entity_inst_t& inst, const vector& com) { dout(10) << "send_command " << inst << "" << com << dendl; MMonCommand *c = new MMonCommand(monmap->fsid); c->cmd = com; try_send_message(c, inst); } void Monitor::waitlist_or_zap_client(Message *m) { /** * Wait list the new session until we're in the quorum, assuming it's * sufficiently new. * tick() will periodically send them back through so we can send * the client elsewhere if we don't think we're getting back in. * * But we whitelist a few sorts of messages: * 1) Monitors can talk to us at any time, of course. * 2) auth messages. It's unlikely to go through much faster, but * it's possible we've just lost our quorum status and we want to take... * 3) command messages. We want to accept these under all possible * circumstances. */ ConnectionRef con = m->get_connection(); utime_t too_old = ceph_clock_now(g_ceph_context); too_old -= g_ceph_context->_conf->mon_lease; if (m->get_recv_stamp() > too_old && con->is_connected()) { dout(5) << "waitlisting message " << *m << dendl; maybe_wait_for_quorum.push_back(new C_RetryMessage(this, m)); } else { dout(5) << "discarding message " << *m << " and sending client elsewhere" << dendl; messenger->mark_down(con); m->put(); } } bool Monitor::_ms_dispatch(Message *m) { bool ret = true; if (is_shutdown()) { m->put(); return true; } ConnectionRef connection = m->get_connection(); MonSession *s = NULL; MonCap caps; bool src_is_mon; // regardless of who we are or who the sender is, the message must // have a connection associated. If it doesn't then something fishy // is going on. assert(connection); src_is_mon = (connection->get_peer_type() & CEPH_ENTITY_TYPE_MON); bool reuse_caps = false; dout(20) << "have connection" << dendl; s = static_cast(connection->get_priv()); if (s && s->closed) { caps = s->caps; reuse_caps = true; s->put(); s = NULL; } if (!s) { // if the sender is not a monitor, make sure their first message for a // session is an MAuth. If it is not, assume it's a stray message, // and considering that we are creating a new session it is safe to // assume that the sender hasn't authenticated yet, so we have no way // of assessing whether we should handle it or not. if (!src_is_mon && (m->get_type() != CEPH_MSG_AUTH && m->get_type() != CEPH_MSG_MON_GET_MAP)) { if (m->get_type() == CEPH_MSG_PING) { // let it go through and be dispatched immediately! return dispatch(s, m, false); } dout(1) << __func__ << " dropping stray message " << *m << " from " << m->get_source_inst() << dendl; m->put(); return true; } if (!exited_quorum.is_zero() && !src_is_mon) { waitlist_or_zap_client(m); return true; } dout(10) << "do not have session, making new one" << dendl; s = session_map.new_session(m->get_source_inst(), m->get_connection().get()); m->get_connection()->set_priv(s->get()); dout(10) << "ms_dispatch new session " << s << " for " << s->inst << dendl; if (!src_is_mon) { dout(10) << "setting timeout on session" << dendl; // set an initial timeout here, so we will trim this session even if they don't // do anything. s->until = ceph_clock_now(g_ceph_context); s->until += g_conf->mon_subscribe_interval; } else { //give it monitor caps; the peer type has been authenticated reuse_caps = false; dout(5) << "setting monitor caps on this connection" << dendl; if (!s->caps.is_allow_all()) //but no need to repeatedly copy s->caps = *mon_caps; } if (reuse_caps) s->caps = caps; } else { dout(20) << "ms_dispatch existing session " << s << " for " << s->inst << dendl; } assert(s); if (s->auth_handler) { s->entity_name = s->auth_handler->get_entity_name(); } dout(20) << " caps " << s->caps.get_str() << dendl; if (is_synchronizing() && !src_is_mon) { waitlist_or_zap_client(m); return true; } ret = dispatch(s, m, src_is_mon); s->put(); return ret; } bool Monitor::dispatch(MonSession *s, Message *m, const bool src_is_mon) { bool ret = true; assert(m != NULL); switch (m->get_type()) { case MSG_ROUTE: handle_route(static_cast(m)); break; // misc case CEPH_MSG_MON_GET_MAP: handle_mon_get_map(static_cast(m)); break; case CEPH_MSG_MON_GET_VERSION: handle_get_version(static_cast(m)); break; case MSG_MON_COMMAND: handle_command(static_cast(m)); break; case CEPH_MSG_MON_SUBSCRIBE: /* FIXME: check what's being subscribed, filter accordingly */ handle_subscribe(static_cast(m)); break; case MSG_MON_PROBE: handle_probe(static_cast(m)); break; // Sync (i.e., the new slurp, but on steroids) case MSG_MON_SYNC: handle_sync(static_cast(m)); break; case MSG_MON_SCRUB: handle_scrub(static_cast(m)); break; // OSDs case MSG_OSD_MARK_ME_DOWN: case MSG_OSD_FAILURE: case MSG_OSD_BOOT: case MSG_OSD_ALIVE: case MSG_OSD_PGTEMP: paxos_service[PAXOS_OSDMAP]->dispatch((PaxosServiceMessage*)m); break; case MSG_REMOVE_SNAPS: paxos_service[PAXOS_OSDMAP]->dispatch((PaxosServiceMessage*)m); break; // MDSs case MSG_MDS_BEACON: case MSG_MDS_OFFLOAD_TARGETS: paxos_service[PAXOS_MDSMAP]->dispatch((PaxosServiceMessage*)m); break; // auth case MSG_MON_GLOBAL_ID: case CEPH_MSG_AUTH: /* no need to check caps here */ paxos_service[PAXOS_AUTH]->dispatch((PaxosServiceMessage*)m); break; // pg case CEPH_MSG_STATFS: case MSG_PGSTATS: case MSG_GETPOOLSTATS: paxos_service[PAXOS_PGMAP]->dispatch((PaxosServiceMessage*)m); break; case CEPH_MSG_POOLOP: paxos_service[PAXOS_OSDMAP]->dispatch((PaxosServiceMessage*)m); break; // log case MSG_LOG: paxos_service[PAXOS_LOG]->dispatch((PaxosServiceMessage*)m); break; case MSG_LOGACK: clog.handle_log_ack((MLogAck*)m); break; // monmap case MSG_MON_JOIN: paxos_service[PAXOS_MONMAP]->dispatch((PaxosServiceMessage*)m); break; // paxos case MSG_MON_PAXOS: { MMonPaxos *pm = static_cast(m); if (!src_is_mon || !s->is_capable("mon", MON_CAP_X)) { //can't send these! pm->put(); break; } if (state == STATE_SYNCHRONIZING) { // we are synchronizing. These messages would do us no // good, thus just drop them and ignore them. dout(10) << __func__ << " ignore paxos msg from " << pm->get_source_inst() << dendl; pm->put(); break; } // sanitize if (pm->epoch > get_epoch()) { bootstrap(); pm->put(); break; } if (pm->epoch != get_epoch()) { pm->put(); break; } paxos->dispatch((PaxosServiceMessage*)m); } break; // elector messages case MSG_MON_ELECTION: //check privileges here for simplicity if (s && !s->is_capable("mon", MON_CAP_X)) { dout(0) << "MMonElection received from entity without enough caps!" << s->caps << dendl; m->put(); break; } if (!is_probing() && !is_synchronizing()) { elector.dispatch(m); } else { m->put(); } break; case MSG_FORWARD: handle_forward(static_cast(m)); break; case MSG_TIMECHECK: handle_timecheck(static_cast(m)); break; case MSG_MON_HEALTH: health_monitor->dispatch(static_cast(m)); break; case CEPH_MSG_PING: handle_ping(static_cast(m)); break; default: ret = false; } return ret; } void Monitor::handle_ping(MPing *m) { dout(10) << __func__ << " " << *m << dendl; MPing *reply = new MPing; entity_inst_t inst = m->get_source_inst(); bufferlist payload; Formatter *f = new JSONFormatter(true); f->open_object_section("pong"); string health_str; get_health(health_str, NULL, f); { stringstream ss; get_mon_status(f, ss); } f->close_section(); stringstream ss; f->flush(ss); ::encode(ss.str(), payload); reply->set_payload(payload); dout(10) << __func__ << " reply payload len " << reply->get_payload().length() << dendl; messenger->send_message(reply, inst); m->put(); } void Monitor::timecheck_start() { dout(10) << __func__ << dendl; timecheck_cleanup(); timecheck_start_round(); } void Monitor::timecheck_finish() { dout(10) << __func__ << dendl; timecheck_cleanup(); } void Monitor::timecheck_start_round() { dout(10) << __func__ << " curr " << timecheck_round << dendl; assert(is_leader()); if (monmap->size() == 1) { assert(0 == "We are alone; this shouldn't have been scheduled!"); return; } if (timecheck_round % 2) { dout(10) << __func__ << " there's a timecheck going on" << dendl; utime_t curr_time = ceph_clock_now(g_ceph_context); double max = g_conf->mon_timecheck_interval*3; if (curr_time - timecheck_round_start < max) { dout(10) << __func__ << " keep current round going" << dendl; goto out; } else { dout(10) << __func__ << " finish current timecheck and start new" << dendl; timecheck_cancel_round(); } } assert(timecheck_round % 2 == 0); timecheck_acks = 0; timecheck_round ++; timecheck_round_start = ceph_clock_now(g_ceph_context); dout(10) << __func__ << " new " << timecheck_round << dendl; timecheck(); out: dout(10) << __func__ << " setting up next event" << dendl; timecheck_event = new C_TimeCheck(this); timer.add_event_after(g_conf->mon_timecheck_interval, timecheck_event); } void Monitor::timecheck_finish_round(bool success) { dout(10) << __func__ << " curr " << timecheck_round << dendl; assert(timecheck_round % 2); timecheck_round ++; timecheck_round_start = utime_t(); if (success) { assert(timecheck_waiting.empty()); assert(timecheck_acks == quorum.size()); timecheck_report(); return; } dout(10) << __func__ << " " << timecheck_waiting.size() << " peers still waiting:"; for (map::iterator p = timecheck_waiting.begin(); p != timecheck_waiting.end(); ++p) { *_dout << " " << p->first.name; } *_dout << dendl; timecheck_waiting.clear(); dout(10) << __func__ << " finished to " << timecheck_round << dendl; } void Monitor::timecheck_cancel_round() { timecheck_finish_round(false); } void Monitor::timecheck_cleanup() { timecheck_round = 0; timecheck_acks = 0; timecheck_round_start = utime_t(); if (timecheck_event) { timer.cancel_event(timecheck_event); timecheck_event = NULL; } timecheck_waiting.clear(); timecheck_skews.clear(); timecheck_latencies.clear(); } void Monitor::timecheck_report() { dout(10) << __func__ << dendl; assert(is_leader()); assert((timecheck_round % 2) == 0); if (monmap->size() == 1) { assert(0 == "We are alone; we shouldn't have gotten here!"); return; } assert(timecheck_latencies.size() == timecheck_skews.size()); bool do_output = true; // only output report once for (set::iterator q = quorum.begin(); q != quorum.end(); ++q) { if (monmap->get_name(*q) == name) continue; MTimeCheck *m = new MTimeCheck(MTimeCheck::OP_REPORT); m->epoch = get_epoch(); m->round = timecheck_round; for (map::iterator it = timecheck_skews.begin(); it != timecheck_skews.end(); ++it) { double skew = it->second; double latency = timecheck_latencies[it->first]; m->skews[it->first] = skew; m->latencies[it->first] = latency; if (do_output) { dout(25) << __func__ << " " << it->first << " latency " << latency << " skew " << skew << dendl; } } do_output = false; entity_inst_t inst = monmap->get_inst(*q); dout(10) << __func__ << " send report to " << inst << dendl; messenger->send_message(m, inst); } } void Monitor::timecheck() { dout(10) << __func__ << dendl; assert(is_leader()); if (monmap->size() == 1) { assert(0 == "We are alone; we shouldn't have gotten here!"); return; } assert(timecheck_round % 2 != 0); timecheck_acks = 1; // we ack ourselves dout(10) << __func__ << " start timecheck epoch " << get_epoch() << " round " << timecheck_round << dendl; // we are at the eye of the storm; the point of reference timecheck_skews[messenger->get_myinst()] = 0.0; timecheck_latencies[messenger->get_myinst()] = 0.0; for (set::iterator it = quorum.begin(); it != quorum.end(); ++it) { if (monmap->get_name(*it) == name) continue; entity_inst_t inst = monmap->get_inst(*it); utime_t curr_time = ceph_clock_now(g_ceph_context); timecheck_waiting[inst] = curr_time; MTimeCheck *m = new MTimeCheck(MTimeCheck::OP_PING); m->epoch = get_epoch(); m->round = timecheck_round; dout(10) << __func__ << " send " << *m << " to " << inst << dendl; messenger->send_message(m, inst); } } health_status_t Monitor::timecheck_status(ostringstream &ss, const double skew_bound, const double latency) { health_status_t status = HEALTH_OK; double abs_skew = (skew_bound > 0 ? skew_bound : -skew_bound); assert(latency >= 0); if (abs_skew > g_conf->mon_clock_drift_allowed) { status = HEALTH_WARN; ss << "clock skew " << abs_skew << "s" << " > max " << g_conf->mon_clock_drift_allowed << "s"; } return status; } void Monitor::handle_timecheck_leader(MTimeCheck *m) { dout(10) << __func__ << " " << *m << dendl; /* handles PONG's */ assert(m->op == MTimeCheck::OP_PONG); entity_inst_t other = m->get_source_inst(); if (m->epoch < get_epoch()) { dout(1) << __func__ << " got old timecheck epoch " << m->epoch << " from " << other << " curr " << get_epoch() << " -- severely lagged? discard" << dendl; return; } assert(m->epoch == get_epoch()); if (m->round < timecheck_round) { dout(1) << __func__ << " got old round " << m->round << " from " << other << " curr " << timecheck_round << " -- discard" << dendl; return; } utime_t curr_time = ceph_clock_now(g_ceph_context); assert(timecheck_waiting.count(other) > 0); utime_t timecheck_sent = timecheck_waiting[other]; timecheck_waiting.erase(other); if (curr_time < timecheck_sent) { // our clock was readjusted -- drop everything until it all makes sense. dout(1) << __func__ << " our clock was readjusted --" << " bump round and drop current check" << dendl; timecheck_cancel_round(); return; } /* update peer latencies */ double latency = (double)(curr_time - timecheck_sent); if (timecheck_latencies.count(other) == 0) timecheck_latencies[other] = latency; else { double avg_latency = ((timecheck_latencies[other]*0.8)+(latency*0.2)); timecheck_latencies[other] = avg_latency; } /* * update skews * * some nasty thing goes on if we were to do 'a - b' between two utime_t, * and 'a' happens to be lower than 'b'; so we use double instead. * * latency is always expected to be >= 0. * * delta, the difference between theirs timestamp and ours, may either be * lower or higher than 0; will hardly ever be 0. * * The absolute skew is the absolute delta minus the latency, which is * taken as a whole instead of an rtt given that there is some queueing * and dispatch times involved and it's hard to assess how long exactly * it took for the message to travel to the other side and be handled. So * we call it a bounded skew, the worst case scenario. * * Now, to math! * * Given that the latency is always positive, we can establish that the * bounded skew will be: * * 1. positive if the absolute delta is higher than the latency and * delta is positive * 2. negative if the absolute delta is higher than the latency and * delta is negative. * 3. zero if the absolute delta is lower than the latency. * * On 3. we make a judgement call and treat the skew as non-existent. * This is because that, if the absolute delta is lower than the * latency, then the apparently existing skew is nothing more than a * side-effect of the high latency at work. * * This may not be entirely true though, as a severely skewed clock * may be masked by an even higher latency, but with high latencies * we probably have worse issues to deal with than just skewed clocks. */ assert(latency >= 0); double delta = ((double) m->timestamp) - ((double) curr_time); double abs_delta = (delta > 0 ? delta : -delta); double skew_bound = abs_delta - latency; if (skew_bound < 0) skew_bound = 0; else if (delta < 0) skew_bound = -skew_bound; ostringstream ss; health_status_t status = timecheck_status(ss, skew_bound, latency); if (status == HEALTH_ERR) clog.error() << other << " " << ss.str() << "\n"; else if (status == HEALTH_WARN) clog.warn() << other << " " << ss.str() << "\n"; dout(10) << __func__ << " from " << other << " ts " << m->timestamp << " delta " << delta << " skew_bound " << skew_bound << " latency " << latency << dendl; if (timecheck_skews.count(other) == 0) { timecheck_skews[other] = skew_bound; } else { timecheck_skews[other] = (timecheck_skews[other]*0.8)+(skew_bound*0.2); } timecheck_acks++; if (timecheck_acks == quorum.size()) { dout(10) << __func__ << " got pongs from everybody (" << timecheck_acks << " total)" << dendl; assert(timecheck_skews.size() == timecheck_acks); assert(timecheck_waiting.empty()); // everyone has acked, so bump the round to finish it. timecheck_finish_round(); } } void Monitor::handle_timecheck_peon(MTimeCheck *m) { dout(10) << __func__ << " " << *m << dendl; assert(is_peon()); assert(m->op == MTimeCheck::OP_PING || m->op == MTimeCheck::OP_REPORT); if (m->epoch != get_epoch()) { dout(1) << __func__ << " got wrong epoch " << "(ours " << get_epoch() << " theirs: " << m->epoch << ") -- discarding" << dendl; return; } if (m->round < timecheck_round) { dout(1) << __func__ << " got old round " << m->round << " current " << timecheck_round << " (epoch " << get_epoch() << ") -- discarding" << dendl; return; } timecheck_round = m->round; if (m->op == MTimeCheck::OP_REPORT) { assert((timecheck_round % 2) == 0); timecheck_latencies.swap(m->latencies); timecheck_skews.swap(m->skews); return; } assert((timecheck_round % 2) != 0); MTimeCheck *reply = new MTimeCheck(MTimeCheck::OP_PONG); utime_t curr_time = ceph_clock_now(g_ceph_context); reply->timestamp = curr_time; reply->epoch = m->epoch; reply->round = m->round; dout(10) << __func__ << " send " << *m << " to " << m->get_source_inst() << dendl; messenger->send_message(reply, m->get_connection()); } void Monitor::handle_timecheck(MTimeCheck *m) { dout(10) << __func__ << " " << *m << dendl; if (is_leader()) { if (m->op != MTimeCheck::OP_PONG) { dout(1) << __func__ << " drop unexpected msg (not pong)" << dendl; } else { handle_timecheck_leader(m); } } else if (is_peon()) { if (m->op != MTimeCheck::OP_PING && m->op != MTimeCheck::OP_REPORT) { dout(1) << __func__ << " drop unexpected msg (not ping or report)" << dendl; } else { handle_timecheck_peon(m); } } else { dout(1) << __func__ << " drop unexpected msg" << dendl; } m->put(); } void Monitor::handle_subscribe(MMonSubscribe *m) { dout(10) << "handle_subscribe " << *m << dendl; bool reply = false; MonSession *s = static_cast(m->get_connection()->get_priv()); if (!s) { dout(10) << " no session, dropping" << dendl; m->put(); return; } s->until = ceph_clock_now(g_ceph_context); s->until += g_conf->mon_subscribe_interval; for (map::iterator p = m->what.begin(); p != m->what.end(); ++p) { // if there are any non-onetime subscriptions, we need to reply to start the resubscribe timer if ((p->second.flags & CEPH_SUBSCRIBE_ONETIME) == 0) reply = true; session_map.add_update_sub(s, p->first, p->second.start, p->second.flags & CEPH_SUBSCRIBE_ONETIME, m->get_connection()->has_feature(CEPH_FEATURE_INCSUBOSDMAP)); if (p->first == "mdsmap") { if ((int)s->is_capable("mds", MON_CAP_R)) { mdsmon()->check_sub(s->sub_map["mdsmap"]); } } else if (p->first == "osdmap") { if ((int)s->is_capable("osd", MON_CAP_R)) { osdmon()->check_sub(s->sub_map["osdmap"]); } } else if (p->first == "osd_pg_creates") { if ((int)s->is_capable("osd", MON_CAP_W)) { pgmon()->check_sub(s->sub_map["osd_pg_creates"]); } } else if (p->first == "monmap") { check_sub(s->sub_map["monmap"]); } else if (logmon()->sub_name_to_id(p->first) >= 0) { logmon()->check_sub(s->sub_map[p->first]); } } // ??? if (reply) messenger->send_message(new MMonSubscribeAck(monmap->get_fsid(), (int)g_conf->mon_subscribe_interval), m->get_source_inst()); s->put(); m->put(); } void Monitor::handle_get_version(MMonGetVersion *m) { dout(10) << "handle_get_version " << *m << dendl; PaxosService *svc = NULL; MonSession *s = static_cast(m->get_connection()->get_priv()); if (!s) { dout(10) << " no session, dropping" << dendl; m->put(); return; } if (!is_leader() && !is_peon()) { dout(10) << " waiting for quorum" << dendl; waitfor_quorum.push_back(new C_RetryMessage(this, m)); goto out; } if (m->what == "mdsmap") { svc = mdsmon(); } else if (m->what == "osdmap") { svc = osdmon(); } else if (m->what == "monmap") { svc = monmon(); } else { derr << "invalid map type " << m->what << dendl; } if (svc) { if (!svc->is_readable()) { svc->wait_for_readable(new C_RetryMessage(this, m)); goto out; } MMonGetVersionReply *reply = new MMonGetVersionReply(); reply->handle = m->handle; reply->version = svc->get_last_committed(); reply->oldest_version = svc->get_first_committed(); messenger->send_message(reply, m->get_source_inst()); } m->put(); out: s->put(); } bool Monitor::ms_handle_reset(Connection *con) { dout(10) << "ms_handle_reset " << con << " " << con->get_peer_addr() << dendl; // ignore lossless monitor sessions if (con->get_peer_type() == CEPH_ENTITY_TYPE_MON) return false; MonSession *s = static_cast(con->get_priv()); if (!s) return false; // break any con <-> session ref cycle s->con->set_priv(NULL); if (is_shutdown()) return false; Mutex::Locker l(lock); dout(10) << "reset/close on session " << s->inst << dendl; if (!s->closed) remove_session(s); s->put(); return true; } void Monitor::check_subs() { string type = "monmap"; if (session_map.subs.count(type) == 0) return; xlist::iterator p = session_map.subs[type]->begin(); while (!p.end()) { Subscription *sub = *p; ++p; check_sub(sub); } } void Monitor::check_sub(Subscription *sub) { dout(10) << "check_sub monmap next " << sub->next << " have " << monmap->get_epoch() << dendl; if (sub->next <= monmap->get_epoch()) { send_latest_monmap(sub->session->con.get()); if (sub->onetime) session_map.remove_sub(sub); else sub->next = monmap->get_epoch() + 1; } } // ----- void Monitor::send_latest_monmap(Connection *con) { bufferlist bl; monmap->encode(bl, con->get_features()); messenger->send_message(new MMonMap(bl), con); } void Monitor::handle_mon_get_map(MMonGetMap *m) { dout(10) << "handle_mon_get_map" << dendl; send_latest_monmap(m->get_connection().get()); m->put(); } // ---------------------------------------------- // scrub int Monitor::scrub() { dout(10) << __func__ << dendl; assert(is_leader()); if ((get_quorum_features() & CEPH_FEATURE_MON_SCRUB) == 0) { clog.warn() << "scrub not supported by entire quorum\n"; return -EOPNOTSUPP; } if (!scrub_result.empty()) { clog.info() << "scrub already in progress\n"; return -EBUSY; } scrub_result.clear(); scrub_version = paxos->get_version(); for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) { if (*p == rank) continue; MMonScrub *r = new MMonScrub(MMonScrub::OP_SCRUB, scrub_version); messenger->send_message(r, monmap->get_inst(*p)); } // scrub my keys _scrub(&scrub_result[rank]); if (scrub_result.size() == quorum.size()) scrub_finish(); return 0; } void Monitor::handle_scrub(MMonScrub *m) { dout(10) << __func__ << " " << *m << dendl; switch (m->op) { case MMonScrub::OP_SCRUB: { if (!is_peon()) break; if (m->version != paxos->get_version()) break; MMonScrub *reply = new MMonScrub(MMonScrub::OP_RESULT, m->version); _scrub(&reply->result); messenger->send_message(reply, m->get_connection()); } break; case MMonScrub::OP_RESULT: { if (!is_leader()) break; if (m->version != scrub_version) break; int from = m->get_source().num(); assert(scrub_result.count(from) == 0); scrub_result[from] = m->result; if (scrub_result.size() == quorum.size()) scrub_finish(); } break; } m->put(); } void Monitor::_scrub(ScrubResult *r) { set prefixes = get_sync_targets_names(); prefixes.erase("paxos"); // exclude paxos, as this one may have extra states for proposals, etc. dout(10) << __func__ << " prefixes " << prefixes << dendl; pair start; MonitorDBStore::Synchronizer synchronizer = store->get_synchronizer(start, prefixes); while (synchronizer->has_next_chunk()) { pair k = synchronizer->get_next_key(); bufferlist bl; store->get(k.first, k.second, bl); dout(30) << __func__ << " " << k << " bl " << bl.length() << " bytes crc " << bl.crc32c(0) << dendl; r->prefix_keys[k.first]++; if (r->prefix_crc.count(k.first) == 0) r->prefix_crc[k.first] = 0; r->prefix_crc[k.first] = bl.crc32c(r->prefix_crc[k.first]); } } void Monitor::scrub_finish() { dout(10) << __func__ << dendl; // compare int errors = 0; ScrubResult& mine = scrub_result[rank]; for (map::iterator p = scrub_result.begin(); p != scrub_result.end(); ++p) { if (p->first == rank) continue; if (p->second != mine) { ++errors; clog.error() << "scrub mismatch" << "\n"; clog.error() << " mon." << rank << " " << mine << "\n"; clog.error() << " mon." << p->first << " " << p->second << "\n"; } } if (!errors) clog.info() << "scrub ok on " << quorum << ": " << mine << "\n"; scrub_reset(); } void Monitor::scrub_reset() { dout(10) << __func__ << dendl; scrub_version = 0; scrub_result.clear(); } /************ TICK ***************/ class C_Mon_Tick : public Context { Monitor *mon; public: C_Mon_Tick(Monitor *m) : mon(m) {} void finish(int r) { mon->tick(); } }; void Monitor::new_tick() { C_Mon_Tick *ctx = new C_Mon_Tick(this); timer.add_event_after(g_conf->mon_tick_interval, ctx); } void Monitor::tick() { // ok go. dout(11) << "tick" << dendl; for (vector::iterator p = paxos_service.begin(); p != paxos_service.end(); ++p) { (*p)->tick(); (*p)->maybe_trim(); } // trim sessions utime_t now = ceph_clock_now(g_ceph_context); xlist::iterator p = session_map.sessions.begin(); while (!p.end()) { MonSession *s = *p; ++p; // don't trim monitors if (s->inst.name.is_mon()) continue; if (!s->until.is_zero() && s->until < now) { dout(10) << " trimming session " << s->con << " " << s->inst << " (until " << s->until << " < now " << now << ")" << dendl; messenger->mark_down(s->con); remove_session(s); } else if (!exited_quorum.is_zero()) { if (now > (exited_quorum + 2 * g_conf->mon_lease)) { // boot the client Session because we've taken too long getting back in dout(10) << " trimming session " << s->con << " " << s->inst << " because we've been out of quorum too long" << dendl; messenger->mark_down(s->con); remove_session(s); } } } sync_trim_providers(); if (!maybe_wait_for_quorum.empty()) { finish_contexts(g_ceph_context, maybe_wait_for_quorum); } if (is_leader() && paxos->is_active() && fingerprint.is_zero()) { // this is only necessary on upgraded clusters. MonitorDBStore::Transaction t; prepare_new_fingerprint(&t); bufferlist tbl; t.encode(tbl); paxos->propose_new_value(tbl, new C_NoopContext); } new_tick(); } void Monitor::prepare_new_fingerprint(MonitorDBStore::Transaction *t) { uuid_d nf; nf.generate_random(); dout(10) << __func__ << " proposing cluster_fingerprint " << nf << dendl; bufferlist bl; ::encode(nf, bl); t->put(MONITOR_NAME, "cluster_fingerprint", bl); } int Monitor::check_fsid() { if (!store->exists(MONITOR_NAME, "cluster_uuid")) return -ENOENT; bufferlist ebl; int r = store->get(MONITOR_NAME, "cluster_uuid", ebl); assert(r == 0); string es(ebl.c_str(), ebl.length()); // only keep the first line size_t pos = es.find_first_of('\n'); if (pos != string::npos) es.resize(pos); dout(10) << "check_fsid cluster_uuid contains '" << es << "'" << dendl; uuid_d ondisk; if (!ondisk.parse(es.c_str())) { derr << "error: unable to parse uuid" << dendl; return -EINVAL; } if (monmap->get_fsid() != ondisk) { derr << "error: cluster_uuid file exists with value " << ondisk << ", != our uuid " << monmap->get_fsid() << dendl; return -EEXIST; } return 0; } int Monitor::write_fsid() { MonitorDBStore::Transaction t; int r = write_fsid(t); store->apply_transaction(t); return r; } int Monitor::write_fsid(MonitorDBStore::Transaction &t) { ostringstream ss; ss << monmap->get_fsid() << "\n"; string us = ss.str(); bufferlist b; b.append(us); t.put(MONITOR_NAME, "cluster_uuid", b); return 0; } /* * this is the closest thing to a traditional 'mkfs' for ceph. * initialize the monitor state machines to their initial values. */ int Monitor::mkfs(bufferlist& osdmapbl) { MonitorDBStore::Transaction t; // verify cluster fsid int r = check_fsid(); if (r < 0 && r != -ENOENT) return r; bufferlist magicbl; magicbl.append(CEPH_MON_ONDISK_MAGIC); magicbl.append("\n"); t.put(MONITOR_NAME, "magic", magicbl); features = get_supported_features(); write_features(t); // save monmap, osdmap, keyring. bufferlist monmapbl; monmap->encode(monmapbl, CEPH_FEATURES_ALL); monmap->set_epoch(0); // must be 0 to avoid confusing first MonmapMonitor::update_from_paxos() t.put("mkfs", "monmap", monmapbl); if (osdmapbl.length()) { // make sure it's a valid osdmap try { OSDMap om; om.decode(osdmapbl); } catch (buffer::error& e) { derr << "error decoding provided osdmap: " << e.what() << dendl; return -EINVAL; } t.put("mkfs", "osdmap", osdmapbl); } if (is_keyring_required()) { KeyRing keyring; string keyring_filename; if (!ceph_resolve_file_search(g_conf->keyring, keyring_filename)) { derr << "unable to find a keyring file on " << g_conf->keyring << dendl; if (g_conf->key != "") { string keyring_plaintext = "[mon.]\n\tkey = " + g_conf->key + "\n\tcaps mon = \"allow *\"\n"; bufferlist bl; bl.append(keyring_plaintext); try { bufferlist::iterator i = bl.begin(); keyring.decode_plaintext(i); } catch (const buffer::error& e) { derr << "error decoding keyring " << keyring_plaintext << ": " << e.what() << dendl; return -EINVAL; } } else { return -ENOENT; } } else { r = keyring.load(g_ceph_context, keyring_filename); if (r < 0) { derr << "unable to load initial keyring " << g_conf->keyring << dendl; return r; } } // put mon. key in external keyring; seed with everything else. extract_save_mon_key(keyring); bufferlist keyringbl; keyring.encode_plaintext(keyringbl); t.put("mkfs", "keyring", keyringbl); } write_fsid(t); store->apply_transaction(t); return 0; } int Monitor::write_default_keyring(bufferlist& bl) { ostringstream os; os << g_conf->mon_data << "/keyring"; int err = 0; int fd = ::open(os.str().c_str(), O_WRONLY|O_CREAT, 0644); if (fd < 0) { err = -errno; dout(0) << __func__ << " failed to open " << os.str() << ": " << cpp_strerror(err) << dendl; return err; } err = bl.write_fd(fd); if (!err) ::fsync(fd); ::close(fd); return err; } void Monitor::extract_save_mon_key(KeyRing& keyring) { EntityName mon_name; mon_name.set_type(CEPH_ENTITY_TYPE_MON); EntityAuth mon_key; if (keyring.get_auth(mon_name, mon_key)) { dout(10) << "extract_save_mon_key moving mon. key to separate keyring" << dendl; KeyRing pkey; pkey.add(mon_name, mon_key); bufferlist bl; pkey.encode_plaintext(bl); write_default_keyring(bl); keyring.remove(mon_name); } } bool Monitor::ms_get_authorizer(int service_id, AuthAuthorizer **authorizer, bool force_new) { dout(10) << "ms_get_authorizer for " << ceph_entity_type_name(service_id) << dendl; if (is_shutdown()) return false; // we only connect to other monitors; every else connects to us. if (service_id != CEPH_ENTITY_TYPE_MON) return false; if (!auth_cluster_required.is_supported_auth(CEPH_AUTH_CEPHX)) return false; CephXServiceTicketInfo auth_ticket_info; CephXSessionAuthInfo info; int ret; EntityName name; name.set_type(CEPH_ENTITY_TYPE_MON); auth_ticket_info.ticket.name = name; auth_ticket_info.ticket.global_id = 0; CryptoKey secret; if (!keyring.get_secret(name, secret) && !key_server.get_secret(name, secret)) { dout(0) << " couldn't get secret for mon service from keyring or keyserver" << dendl; stringstream ss, ds; int err = key_server.list_secrets(ds); if (err < 0) ss << "no installed auth entries!"; else ss << "installed auth entries:"; dout(0) << ss.str() << "\n" << ds.str() << dendl; return false; } /* mon to mon authentication uses the private monitor shared key and not the rotating key */ ret = key_server.build_session_auth_info(service_id, auth_ticket_info, info, secret, (uint64_t)-1); if (ret < 0) { dout(0) << "ms_get_authorizer failed to build session auth_info for use with mon ret " << ret << dendl; return false; } CephXTicketBlob blob; if (!cephx_build_service_ticket_blob(cct, info, blob)) { dout(0) << "ms_get_authorizer failed to build service ticket use with mon" << dendl; return false; } bufferlist ticket_data; ::encode(blob, ticket_data); bufferlist::iterator iter = ticket_data.begin(); CephXTicketHandler handler(g_ceph_context, service_id); ::decode(handler.ticket, iter); handler.session_key = info.session_key; *authorizer = handler.build_authorizer(0); return true; } bool Monitor::ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key) { dout(10) << "ms_verify_authorizer " << con->get_peer_addr() << " " << ceph_entity_type_name(peer_type) << " protocol " << protocol << dendl; if (is_shutdown()) return false; if (peer_type == CEPH_ENTITY_TYPE_MON && auth_cluster_required.is_supported_auth(CEPH_AUTH_CEPHX)) { // monitor, and cephx is enabled isvalid = false; if (protocol == CEPH_AUTH_CEPHX) { bufferlist::iterator iter = authorizer_data.begin(); CephXServiceTicketInfo auth_ticket_info; if (authorizer_data.length()) { int ret = cephx_verify_authorizer(g_ceph_context, &keyring, iter, auth_ticket_info, authorizer_reply); if (ret >= 0) { session_key = auth_ticket_info.session_key; isvalid = true; } else { dout(0) << "ms_verify_authorizer bad authorizer from mon " << con->get_peer_addr() << dendl; } } } else { dout(0) << "ms_verify_authorizer cephx enabled, but no authorizer (required for mon)" << dendl; } } else { // who cares. isvalid = true; } return true; }; #undef dout_prefix #define dout_prefix *_dout void Monitor::StoreConverter::_convert_finish_features( MonitorDBStore::Transaction &t) { dout(20) << __func__ << dendl; assert(db->exists(MONITOR_NAME, COMPAT_SET_LOC)); bufferlist features_bl; db->get(MONITOR_NAME, COMPAT_SET_LOC, features_bl); assert(features_bl.length()); CompatSet features; bufferlist::iterator p = features_bl.begin(); features.decode(p); assert(features.incompat.contains(CEPH_MON_FEATURE_INCOMPAT_GV)); features.incompat.remove(CEPH_MON_FEATURE_INCOMPAT_GV); assert(!features.incompat.contains(CEPH_MON_FEATURE_INCOMPAT_GV)); features.incompat.insert(CEPH_MON_FEATURE_INCOMPAT_SINGLE_PAXOS); assert(features.incompat.contains(CEPH_MON_FEATURE_INCOMPAT_SINGLE_PAXOS)); features_bl.clear(); features.encode(features_bl); dout(20) << __func__ << " new features " << features << dendl; t.put(MONITOR_NAME, COMPAT_SET_LOC, features_bl); } bool Monitor::StoreConverter::_check_gv_store() { dout(20) << __func__ << dendl; if (!store->exists_bl_ss(COMPAT_SET_LOC, 0)) return false; bufferlist features_bl; store->get_bl_ss_safe(features_bl, COMPAT_SET_LOC, 0); if (!features_bl.length()) { dout(20) << __func__ << " on-disk features length is zero" << dendl; return false; } CompatSet features; bufferlist::iterator p = features_bl.begin(); features.decode(p); return (features.incompat.contains(CEPH_MON_FEATURE_INCOMPAT_GV)); } int Monitor::StoreConverter::needs_conversion() { bufferlist magicbl; int ret = 0; dout(10) << "check if store needs conversion from legacy format" << dendl; _init(); int err = store->mount(); if (err < 0) { if (err == -ENOENT) { derr << "unable to mount monitor store: " << cpp_strerror(err) << dendl; } else { derr << "it appears that another monitor is running: " << cpp_strerror(err) << dendl; } ret = err; goto out; } assert(err == 0); if (store->exists_bl_ss("magic", 0)) { if (_check_gv_store()) { dout(1) << "found old GV monitor store format " << "-- should convert!" << dendl; ret = 1; } else { dout(0) << "Existing monitor store has not been converted " << "to 0.52 (bobtail) format" << dendl; assert(0 == "Existing store has not been converted to 0.52 format"); } } assert(!store->umount()); out: _deinit(); return ret; } int Monitor::StoreConverter::convert() { _init(); assert(!store->mount()); if (db->exists("mon_convert", "on_going")) { dout(0) << __func__ << " found a mon store in mid-convertion; abort!" << dendl; return -EEXIST; } _mark_convert_start(); _convert_monitor(); _convert_machines(); _convert_paxos(); _mark_convert_finish(); store->umount(); _deinit(); dout(0) << __func__ << " finished conversion" << dendl; return 0; } void Monitor::StoreConverter::_convert_monitor() { dout(10) << __func__ << dendl; assert(store->exists_bl_ss("magic")); assert(store->exists_bl_ss("keyring")); assert(store->exists_bl_ss("feature_set")); assert(store->exists_bl_ss("election_epoch")); MonitorDBStore::Transaction tx; if (store->exists_bl_ss("joined")) { version_t joined = store->get_int("joined"); tx.put(MONITOR_NAME, "joined", joined); } vector keys; keys.push_back("magic"); keys.push_back("feature_set"); keys.push_back("cluster_uuid"); vector::iterator it; for (it = keys.begin(); it != keys.end(); ++it) { if (!store->exists_bl_ss((*it).c_str())) continue; bufferlist bl; int r = store->get_bl_ss(bl, (*it).c_str(), 0); assert(r > 0); tx.put(MONITOR_NAME, *it, bl); } version_t election_epoch = store->get_int("election_epoch"); tx.put(MONITOR_NAME, "election_epoch", election_epoch); assert(!tx.empty()); db->apply_transaction(tx); dout(10) << __func__ << " finished" << dendl; } void Monitor::StoreConverter::_convert_machines(string machine) { dout(10) << __func__ << " " << machine << dendl; version_t first_committed = store->get_int(machine.c_str(), "first_committed"); version_t last_committed = store->get_int(machine.c_str(), "last_committed"); version_t accepted_pn = store->get_int(machine.c_str(), "accepted_pn"); version_t last_pn = store->get_int(machine.c_str(), "last_pn"); if (accepted_pn > highest_accepted_pn) highest_accepted_pn = accepted_pn; if (last_pn > highest_last_pn) highest_last_pn = last_pn; string machine_gv(machine); machine_gv.append("_gv"); bool has_gv = true; if (!store->exists_bl_ss(machine_gv.c_str())) { dout(1) << __func__ << " " << machine << " no gv dir '" << machine_gv << "'" << dendl; has_gv = false; } for (version_t ver = first_committed; ver <= last_committed; ver++) { if (!store->exists_bl_sn(machine.c_str(), ver)) { dout(20) << __func__ << " " << machine << " ver " << ver << " dne" << dendl; continue; } bufferlist bl; int r = store->get_bl_sn(bl, machine.c_str(), ver); assert(r >= 0); dout(20) << __func__ << " " << machine << " ver " << ver << " bl " << bl.length() << dendl; MonitorDBStore::Transaction tx; tx.put(machine, ver, bl); tx.put(machine, "last_committed", ver); if (has_gv && store->exists_bl_sn(machine_gv.c_str(), ver)) { stringstream s; s << ver; string ver_str = s.str(); version_t gv = store->get_int(machine_gv.c_str(), ver_str.c_str()); dout(20) << __func__ << " " << machine << " ver " << ver << " -> " << gv << dendl; MonitorDBStore::Transaction paxos_tx; if (gvs.count(gv) == 0) { gvs.insert(gv); } else { dout(0) << __func__ << " " << machine << " gv " << gv << " already exists" << dendl; // Duplicates aren't supposed to happen, but an old bug introduced // them and the mds state machine wasn't ever trimmed, so many users // will see them. So we'll just merge them all in one // single paxos version. // We know that they are either from another paxos machine or // they are from the same paxos machine but their version is // lower than ours -- given that we are iterating all versions // from the lowest to the highest, duh! // We'll just append our stuff to the existing paxos transaction // as if nothing had happened. // Just make sure we are correct. This shouldn't take long and // should never be triggered! set >& s = gv_map[gv]; for (set >::iterator it = s.begin(); it != s.end(); ++it) { if (it->first == machine) assert(it->second + 1 == ver); } bufferlist paxos_bl; int r = db->get("paxos", gv, paxos_bl); assert(r >= 0); paxos_tx.append_from_encoded(paxos_bl); } gv_map[gv].insert(make_pair(machine,ver)); bufferlist tx_bl; tx.encode(tx_bl); paxos_tx.append_from_encoded(tx_bl); bufferlist paxos_bl; paxos_tx.encode(paxos_bl); tx.put("paxos", gv, paxos_bl); } db->apply_transaction(tx); } version_t lc = db->get(machine, "last_committed"); dout(20) << __func__ << " lc " << lc << " last_committed " << last_committed << dendl; assert(lc == last_committed); MonitorDBStore::Transaction tx; tx.put(machine, "first_committed", first_committed); tx.put(machine, "last_committed", last_committed); tx.put(machine, "conversion_first", first_committed); if (store->exists_bl_ss(machine.c_str(), "latest")) { bufferlist latest_bl_raw; int r = store->get_bl_ss(latest_bl_raw, machine.c_str(), "latest"); assert(r >= 0); if (!latest_bl_raw.length()) { dout(20) << __func__ << " machine " << machine << " skip latest with size 0" << dendl; goto out; } tx.put(machine, "latest", latest_bl_raw); bufferlist::iterator lbl_it = latest_bl_raw.begin(); bufferlist latest_bl; version_t latest_ver; ::decode(latest_ver, lbl_it); ::decode(latest_bl, lbl_it); dout(20) << __func__ << " machine " << machine << " latest ver " << latest_ver << dendl; tx.put(machine, "full_latest", latest_ver); stringstream os; os << "full_" << latest_ver; tx.put(machine, os.str(), latest_bl); } out: db->apply_transaction(tx); dout(10) << __func__ << " machine " << machine << " finished" << dendl; } void Monitor::StoreConverter::_convert_osdmap_full() { dout(10) << __func__ << dendl; version_t first_committed = store->get_int("osdmap", "first_committed"); version_t last_committed = store->get_int("osdmap", "last_committed"); int err = 0; for (version_t ver = first_committed; ver <= last_committed; ver++) { if (!store->exists_bl_sn("osdmap_full", ver)) { dout(20) << __func__ << " osdmap_full ver " << ver << " dne" << dendl; err++; continue; } bufferlist bl; int r = store->get_bl_sn(bl, "osdmap_full", ver); assert(r >= 0); dout(20) << __func__ << " osdmap_full ver " << ver << " bl " << bl.length() << " bytes" << dendl; string full_key = "full_" + stringify(ver); MonitorDBStore::Transaction tx; tx.put("osdmap", full_key, bl); db->apply_transaction(tx); } dout(10) << __func__ << " found " << err << " conversion errors!" << dendl; assert(err == 0); } void Monitor::StoreConverter::_convert_paxos() { dout(10) << __func__ << dendl; assert(!gvs.empty()); set::reverse_iterator rit = gvs.rbegin(); version_t highest_gv = *rit; version_t last_gv = highest_gv; int n = 0; int max_versions = (g_conf->paxos_max_join_drift*2); for (; (rit != gvs.rend()) && (n < max_versions); ++rit, ++n) { version_t gv = *rit; if (last_gv == gv) continue; if ((last_gv - gv) > 1) { // we are done; we found a gap and we are only interested in keeping // contiguous paxos versions. break; } last_gv = gv; } // erase all paxos versions between [first, last_gv[, with first being the // first gv in the map. MonitorDBStore::Transaction tx; set::iterator it = gvs.begin(); dout(1) << __func__ << " first gv " << (*it) << " last gv " << last_gv << dendl; for (; it != gvs.end() && (*it < last_gv); ++it) { tx.erase("paxos", *it); } tx.put("paxos", "first_committed", last_gv); tx.put("paxos", "last_committed", highest_gv); tx.put("paxos", "accepted_pn", highest_accepted_pn); tx.put("paxos", "last_pn", highest_last_pn); tx.put("paxos", "conversion_first", last_gv); db->apply_transaction(tx); dout(10) << __func__ << " finished" << dendl; } void Monitor::StoreConverter::_convert_machines() { dout(10) << __func__ << dendl; set machine_names = _get_machines_names(); set::iterator it = machine_names.begin(); for (; it != machine_names.end(); ++it) { _convert_machines(*it); } // convert osdmap full versions // this stays here as these aren't really an independent paxos // machine, but rather machine-specific and don't fit on the // _convert_machines(string) function. _convert_osdmap_full(); dout(10) << __func__ << " finished" << dendl; } ceph-0.80.11/src/mon/Elector.cc0000664000175100017510000003162212623076744020165 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Elector.h" #include "Monitor.h" #include "common/Timer.h" #include "MonitorDBStore.h" #include "MonmapMonitor.h" #include "messages/MMonElection.h" #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, epoch) static ostream& _prefix(std::ostream *_dout, Monitor *mon, epoch_t epoch) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").elector(" << epoch << ") "; } void Elector::init() { epoch = mon->store->get(Monitor::MONITOR_NAME, "election_epoch"); if (!epoch) epoch = 1; dout(1) << "init, last seen epoch " << epoch << dendl; } void Elector::shutdown() { if (expire_event) mon->timer.cancel_event(expire_event); } void Elector::bump_epoch(epoch_t e) { dout(10) << "bump_epoch " << epoch << " to " << e << dendl; assert(epoch <= e); epoch = e; MonitorDBStore::Transaction t; t.put(Monitor::MONITOR_NAME, "election_epoch", epoch); mon->store->apply_transaction(t); mon->join_election(); // clear up some state electing_me = false; acked_me.clear(); classic_mons.clear(); } void Elector::start() { if (!participating) { dout(0) << "not starting new election -- not participating" << dendl; return; } dout(5) << "start -- can i be leader?" << dendl; acked_me.clear(); classic_mons.clear(); init(); // start by trying to elect me if (epoch % 2 == 0) { bump_epoch(epoch+1); // odd == election cycle } else { // do a trivial db write just to ensure it is writeable. MonitorDBStore::Transaction t; t.put(Monitor::MONITOR_NAME, "election_writeable_test", rand()); int r = mon->store->apply_transaction(t); assert(r >= 0); } start_stamp = ceph_clock_now(g_ceph_context); electing_me = true; acked_me[mon->rank] = CEPH_FEATURES_ALL; leader_acked = -1; // bcast to everyone else for (unsigned i=0; imonmap->size(); ++i) { if ((int)i == mon->rank) continue; Message *m = new MMonElection(MMonElection::OP_PROPOSE, epoch, mon->monmap); mon->messenger->send_message(m, mon->monmap->get_inst(i)); } reset_timer(); } void Elector::defer(int who) { dout(5) << "defer to " << who << dendl; if (electing_me) { // drop out acked_me.clear(); classic_mons.clear(); electing_me = false; } // ack them leader_acked = who; ack_stamp = ceph_clock_now(g_ceph_context); MMonElection *m = new MMonElection(MMonElection::OP_ACK, epoch, mon->monmap); m->sharing_bl = mon->get_supported_commands_bl(); mon->messenger->send_message(m, mon->monmap->get_inst(who)); // set a timer reset_timer(1.0); // give the leader some extra time to declare victory } void Elector::reset_timer(double plus) { // set the timer cancel_timer(); expire_event = new C_ElectionExpire(this); mon->timer.add_event_after(g_conf->mon_lease + plus, expire_event); } void Elector::cancel_timer() { if (expire_event) { mon->timer.cancel_event(expire_event); expire_event = 0; } } void Elector::expire() { dout(5) << "election timer expired" << dendl; // did i win? if (electing_me && acked_me.size() > (unsigned)(mon->monmap->size() / 2)) { // i win victory(); } else { // whoever i deferred to didn't declare victory quickly enough. if (mon->has_ever_joined) start(); else mon->bootstrap(); } } void Elector::victory() { leader_acked = -1; electing_me = false; uint64_t features = CEPH_FEATURES_ALL; set quorum; for (map::iterator p = acked_me.begin(); p != acked_me.end(); ++p) { quorum.insert(p->first); features &= p->second; } // decide what command set we're supporting bool use_classic_commands = !classic_mons.empty(); // keep a copy to share with the monitor; we clear classic_mons in bump_epoch set copy_classic_mons = classic_mons; cancel_timer(); assert(epoch % 2 == 1); // election bump_epoch(epoch+1); // is over! // decide my supported commands for peons to advertise const bufferlist *cmds_bl = NULL; const MonCommand *cmds; int cmdsize; if (use_classic_commands) { mon->get_classic_monitor_commands(&cmds, &cmdsize); cmds_bl = &mon->get_classic_commands_bl(); } else { mon->get_locally_supported_monitor_commands(&cmds, &cmdsize); cmds_bl = &mon->get_supported_commands_bl(); } // tell everyone! for (set::iterator p = quorum.begin(); p != quorum.end(); ++p) { if (*p == mon->rank) continue; MMonElection *m = new MMonElection(MMonElection::OP_VICTORY, epoch, mon->monmap); m->quorum = quorum; m->quorum_features = features; m->sharing_bl = *cmds_bl; mon->messenger->send_message(m, mon->monmap->get_inst(*p)); } // tell monitor mon->win_election(epoch, quorum, features, cmds, cmdsize, ©_classic_mons); } void Elector::handle_propose(MMonElection *m) { dout(5) << "handle_propose from " << m->get_source() << dendl; int from = m->get_source().num(); assert(m->epoch % 2 == 1); // election uint64_t required_features = mon->get_required_features(); if ((required_features ^ m->get_connection()->get_features()) & required_features) { dout(5) << " ignoring propose from mon" << from << " without required features" << dendl; nak_old_peer(m); return; } else if (m->epoch > epoch) { bump_epoch(m->epoch); } else if (m->epoch < epoch) { // got an "old" propose, if (epoch % 2 == 0 && // in a non-election cycle mon->quorum.count(from) == 0) { // from someone outside the quorum // a mon just started up, call a new election so they can rejoin! dout(5) << " got propose from old epoch, quorum is " << mon->quorum << ", " << m->get_source() << " must have just started" << dendl; // we may be active; make sure we reset things in the monitor appropriately. mon->start_election(); } else { dout(5) << " ignoring old propose" << dendl; m->put(); return; } } if (mon->rank < from) { // i would win over them. if (leader_acked >= 0) { // we already acked someone assert(leader_acked < from); // and they still win, of course dout(5) << "no, we already acked " << leader_acked << dendl; } else { // wait, i should win! if (!electing_me) { mon->start_election(); } } } else { // they would win over me if (leader_acked < 0 || // haven't acked anyone yet, or leader_acked > from || // they would win over who you did ack, or leader_acked == from) { // this is the guy we're already deferring to defer(from); } else { // ignore them! dout(5) << "no, we already acked " << leader_acked << dendl; } } m->put(); } void Elector::handle_ack(MMonElection *m) { dout(5) << "handle_ack from " << m->get_source() << dendl; int from = m->get_source().num(); assert(m->epoch % 2 == 1); // election if (m->epoch > epoch) { dout(5) << "woah, that's a newer epoch, i must have rebooted. bumping and re-starting!" << dendl; bump_epoch(m->epoch); start(); m->put(); return; } assert(m->epoch == epoch); uint64_t required_features = mon->get_required_features(); if ((required_features ^ m->get_connection()->get_features()) & required_features) { dout(5) << " ignoring ack from mon" << from << " without required features" << dendl; return; } if (electing_me) { // thanks acked_me[from] = m->get_connection()->get_features(); if (!m->sharing_bl.length()) classic_mons.insert(from); dout(5) << " so far i have " << acked_me << dendl; // is that _everyone_? if (acked_me.size() == mon->monmap->size()) { // if yes, shortcut to election finish victory(); } } else { // ignore, i'm deferring already. assert(leader_acked >= 0); } m->put(); } void Elector::handle_victory(MMonElection *m) { dout(5) << "handle_victory from " << m->get_source() << " quorum_features " << m->quorum_features << dendl; int from = m->get_source().num(); assert(from < mon->rank); assert(m->epoch % 2 == 0); leader_acked = -1; // i should have seen this election if i'm getting the victory. if (m->epoch != epoch + 1) { dout(5) << "woah, that's a funny epoch, i must have rebooted. bumping and re-starting!" << dendl; bump_epoch(m->epoch); start(); m->put(); return; } bump_epoch(m->epoch); // they win mon->lose_election(epoch, m->quorum, from, m->quorum_features); // cancel my timer cancel_timer(); // stash leader's commands if (m->sharing_bl.length()) { MonCommand *new_cmds; int cmdsize; bufferlist::iterator bi = m->sharing_bl.begin(); MonCommand::decode_array(&new_cmds, &cmdsize, bi); mon->set_leader_supported_commands(new_cmds, cmdsize); } else { // they are a legacy monitor; use known legacy command set const MonCommand *new_cmds; int cmdsize; mon->get_classic_monitor_commands(&new_cmds, &cmdsize); mon->set_leader_supported_commands(new_cmds, cmdsize); } m->put(); } void Elector::nak_old_peer(MMonElection *m) { uint64_t supported_features = m->get_connection()->get_features(); if (supported_features & CEPH_FEATURE_OSDMAP_ENC) { uint64_t required_features = mon->get_required_features(); dout(10) << "sending nak to peer " << m->get_source() << " that only supports " << supported_features << " of the required " << required_features << dendl; MMonElection *reply = new MMonElection(MMonElection::OP_NAK, m->epoch, mon->monmap); reply->quorum_features = required_features; mon->features.encode(reply->sharing_bl); mon->messenger->send_message(reply, m->get_connection()); } m->put(); } void Elector::handle_nak(MMonElection *m) { dout(1) << "handle_nak from " << m->get_source() << " quorum_features " << m->quorum_features << dendl; CompatSet other; bufferlist::iterator bi = m->sharing_bl.begin(); other.decode(bi); CompatSet diff = Monitor::get_supported_features().unsupported(other); derr << "Shutting down because I do not support required monitor features: { " << diff << " }" << dendl; exit(0); // the end! } void Elector::dispatch(Message *m) { switch (m->get_type()) { case MSG_MON_ELECTION: { if (!participating) { m->put(); return; } if (m->get_source().num() >= mon->monmap->size()) { dout(5) << " ignoring bogus election message with bad mon rank " << m->get_source() << dendl; m->put(); return; } MMonElection *em = static_cast(m); // assume an old message encoding would have matched if (em->fsid != mon->monmap->fsid) { dout(0) << " ignoring election msg fsid " << em->fsid << " != " << mon->monmap->fsid << dendl; m->put(); return; } if (!mon->monmap->contains(m->get_source_addr())) { dout(1) << "discarding election message: " << m->get_source_addr() << " not in my monmap " << *mon->monmap << dendl; m->put(); return; } MonMap *peermap = new MonMap; peermap->decode(em->monmap_bl); if (peermap->epoch > mon->monmap->epoch) { dout(0) << m->get_source_inst() << " has newer monmap epoch " << peermap->epoch << " > my epoch " << mon->monmap->epoch << ", taking it" << dendl; mon->monmap->decode(em->monmap_bl); MonitorDBStore::Transaction t; t.put("monmap", mon->monmap->epoch, em->monmap_bl); t.put("monmap", "last_committed", mon->monmap->epoch); mon->store->apply_transaction(t); //mon->monmon()->paxos->stash_latest(mon->monmap->epoch, em->monmap_bl); cancel_timer(); mon->bootstrap(); m->put(); delete peermap; return; } if (peermap->epoch < mon->monmap->epoch) { dout(0) << m->get_source_inst() << " has older monmap epoch " << peermap->epoch << " < my epoch " << mon->monmap->epoch << dendl; } delete peermap; switch (em->op) { case MMonElection::OP_PROPOSE: handle_propose(em); return; } if (em->epoch < epoch) { dout(5) << "old epoch, dropping" << dendl; em->put(); break; } switch (em->op) { case MMonElection::OP_ACK: handle_ack(em); return; case MMonElection::OP_VICTORY: handle_victory(em); return; case MMonElection::OP_NAK: handle_nak(em); return; default: assert(0); } } break; default: assert(0); } } void Elector::start_participating() { if (!participating) { participating = true; call_election(); } } ceph-0.80.11/src/mon/HealthMonitor.h0000664000175100017510000000363212623076744021207 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_HEALTH_MONITOR_H #define CEPH_HEALTH_MONITOR_H #include "mon/Monitor.h" #include "mon/QuorumService.h" #include "mon/HealthService.h" #include "messages/MMonHealth.h" #include "common/config.h" #include "common/Formatter.h" class HealthMonitor : public QuorumService { map services; protected: virtual void service_shutdown(); public: HealthMonitor(Monitor *m) : QuorumService(m) { } virtual ~HealthMonitor() { assert(services.empty()); } /** * @defgroup HealthMonitor_Inherited_h Inherited abstract methods * @{ */ virtual void init(); virtual void get_health(Formatter *f, list >& summary, list > *detail); virtual bool service_dispatch(Message *m); virtual void start_epoch() { for (map::iterator it = services.begin(); it != services.end(); ++it) { it->second->start(get_epoch()); } } virtual void finish_epoch() { generic_dout(20) << "HealthMonitor::finish_epoch()" << dendl; for (map::iterator it = services.begin(); it != services.end(); ++it) { assert(it->second != NULL); it->second->finish(); } } virtual void cleanup() { } virtual void service_tick() { } virtual int get_type() { return QuorumService::SERVICE_HEALTH; } virtual string get_name() const { return "health"; } /** * @} // HealthMonitor_Inherited_h */ }; #endif // CEPH_HEALTH_MONITOR_H ceph-0.80.11/src/mon/MonitorStore.cc0000664000175100017510000003255512623076744021242 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MonitorStore.h" #include "common/Clock.h" #include "common/debug.h" #include "common/entity_name.h" #include "common/errno.h" #include "common/run_cmd.h" #include "common/safe_io.h" #include "common/config.h" #include "common/sync_filesystem.h" #if defined(__FreeBSD__) #include #endif #include "include/compat.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, dir) static ostream& _prefix(std::ostream *_dout, const string& dir) { return *_dout << "store(" << dir << ") "; } #include #include #include #include #include #include #include #include int MonitorStore::mount() { char t[1024]; dout(1) << "mount" << dendl; // verify dir exists DIR *d = ::opendir(dir.c_str()); if (!d) { dout(1) << "basedir " << dir << " dne" << dendl; return -ENOENT; } ::closedir(d); // open lockfile snprintf(t, sizeof(t), "%s/lock", dir.c_str()); lock_fd = ::open(t, O_CREAT|O_RDWR, 0600); if (lock_fd < 0) return -errno; struct flock l; memset(&l, 0, sizeof(l)); l.l_type = F_WRLCK; l.l_whence = SEEK_SET; l.l_start = 0; l.l_len = 0; int r = ::fcntl(lock_fd, F_SETLK, &l); if (r < 0) { dout(0) << "failed to lock " << t << ", is another ceph-mon still running?" << dendl; return -errno; } if ((!g_conf->chdir.empty()) && (dir[0] != '/')) { // combine it with the cwd, in case fuse screws things up (i.e. fakefuse) string old = dir; char cwd[PATH_MAX]; char *p = getcwd(cwd, sizeof(cwd)); dir = p; dir += "/"; dir += old; } return 0; } int MonitorStore::umount() { int close_err = TEMP_FAILURE_RETRY(::close(lock_fd)); assert (0 == close_err); return 0; } int MonitorStore::mkfs() { int err; err = ::mkdir(dir.c_str(), 0700); if (err < 0 && errno != EEXIST) { err = -errno; derr << "MonitorStore::mkfs: unable to create " << dir << ": " << cpp_strerror(err) << dendl; return err; } int fd = ::open(dir.c_str(), O_RDONLY); if (fd < 0) { err = -errno; derr << "MonitorStore::mkfs: unable to open " << dir << ": " << cpp_strerror(err) << dendl; return err; } int close_err = TEMP_FAILURE_RETRY(::close(fd)); assert (0 == close_err); dout(0) << "created monfs at " << dir << " for " << g_conf->name.get_id() << dendl; return 0; } version_t MonitorStore::get_int(const char *a, const char *b) { char fn[1024]; if (b) snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b); else snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a); int fd = ::open(fn, O_RDONLY); if (fd < 0) { int err = errno; if (err == ENOENT) { // Non-existent files are treated as containing 0. return 0; } derr << "MonitorStore::get_int: failed to open '" << fn << "': " << cpp_strerror(err) << dendl; assert(0 == "failed to open"); return 0; } char buf[20]; memset(buf, 0, sizeof(buf)); int r = safe_read(fd, buf, sizeof(buf) - 1); if (r < 0) { derr << "MonitorStore::get_int: failed to read '" << fn << "': " << cpp_strerror(r) << dendl; int close_err = TEMP_FAILURE_RETRY(::close(fd)); assert(0 == close_err); assert(0); // the file exists; so this is a different failure return 0; } int close_err = TEMP_FAILURE_RETRY(::close(fd)); assert (0 == close_err); version_t val = atoi(buf); if (b) { dout(15) << "get_int " << a << "/" << b << " = " << val << dendl; } else { dout(15) << "get_int " << a << " = " << val << dendl; } return val; } void MonitorStore::put_int(version_t val, const char *a, const char *b) { char fn[1024]; snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a); if (b) { int r = ::mkdir(fn, 0755); if ((r < 0) && (errno != EEXIST)) { int err = -errno; derr << __func__ << " failed to create dir " << fn << ": " << cpp_strerror(err) << dendl; ceph_abort(); } dout(15) << "set_int " << a << "/" << b << " = " << val << dendl; snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b); } else { dout(15) << "set_int " << a << " = " << val << dendl; } char vs[30]; snprintf(vs, sizeof(vs), "%lld\n", (unsigned long long)val); char tfn[1024]; snprintf(tfn, sizeof(tfn), "%s.new", fn); int fd = TEMP_FAILURE_RETRY(::open(tfn, O_WRONLY|O_CREAT|O_TRUNC, 0600)); if (fd < 0) { int err = errno; derr << "MonitorStore::put_int: failed to open '" << tfn << "': " << cpp_strerror(err) << dendl; ceph_abort(); } int r = safe_write(fd, vs, strlen(vs)); if (r) { derr << "MonitorStore::put_int: failed to write to '" << tfn << "': " << cpp_strerror(r) << dendl; ceph_abort(); } r = ::fsync(fd); if (r) { derr << "Monitor::put_int: failed to fsync fd for '" << tfn << "': " << cpp_strerror(r) << dendl; ceph_abort(); } if (TEMP_FAILURE_RETRY(::close(fd))) { derr << "MonitorStore::put_int: failed to close fd for '" << tfn << "': " << cpp_strerror(r) << dendl; ceph_abort(); } if (::rename(tfn, fn)) { int err = errno; derr << "MonitorStore::put_int: failed to rename '" << tfn << "' to " << "'" << fn << "': " << cpp_strerror(err) << dendl; ceph_abort(); } } // kludge to associate a global version number with each per-machine paxos state version_t MonitorStore::get_global_version(const char *a, version_t b) { char fn[1024], fn2[1024]; snprintf(fn, sizeof(fn), "%s_gv", a); snprintf(fn2, sizeof(fn2), "%llu", (long long unsigned)b); return get_int(fn, fn2); } // ---------------------------------------- // buffers bool MonitorStore::exists_bl_ss(const char *a, const char *b) { char fn[1024]; if (b) { dout(15) << "exists_bl " << a << "/" << b << dendl; snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b); } else { dout(15) << "exists_bl " << a << dendl; snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a); } struct stat st; int r = ::stat(fn, &st); //char buf[80]; //dout(15) << "exists_bl stat " << fn << " r=" << r << " " << cpp_strerror(errno) << dendl; if (r) { assert (errno == ENOENT); } return r == 0; } void MonitorStore::erase_ss(const char *a, const char *b) { char fn[1024]; char dr[1024]; snprintf(dr, sizeof(dr), "%s/%s", dir.c_str(), a); if (b) { dout(15) << "erase_ss " << a << "/" << b << dendl; snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b); } else { dout(15) << "erase_ss " << a << dendl; strcpy(fn, dr); } int r = ::unlink(fn); assert(0 == r || ENOENT == errno); // callers don't check for existence first ::rmdir(dr); // sloppy attempt to clean up empty dirs } int MonitorStore::get_bl_ss(bufferlist& bl, const char *a, const char *b) { char fn[1024]; if (b) { snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b); } else { snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a); } int fd = ::open(fn, O_RDONLY); if (fd < 0) { if (b) { dout(15) << "get_bl " << a << "/" << b << " " << cpp_strerror(errno) << dendl; } else { dout(15) << "get_bl " << a << " " << cpp_strerror(errno) << dendl; } return -errno; } // get size struct stat st; int rc = ::fstat(fd, &st); assert(rc == 0); __int32_t len = st.st_size; // read buffer bl.clear(); bufferptr bp(len); int off = 0; while (off < len) { dout(20) << "reading at off " << off << " of " << len << dendl; int r = ::read(fd, bp.c_str()+off, len-off); if (r < 0) dout(0) << "errno on read " << cpp_strerror(errno) << dendl; assert(r>0); off += r; } bl.append(bp); int close_err = TEMP_FAILURE_RETRY(::close(fd)); assert (0 == close_err); if (b) { dout(15) << "get_bl " << a << "/" << b << " = " << bl.length() << " bytes" << dendl; } else { dout(15) << "get_bl " << a << " = " << bl.length() << " bytes" << dendl; } return len; } void MonitorStore::write_bl_ss(bufferlist& bl, const char *a, const char *b, bool append) { int err = 0; char fn[1024]; snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a); if (b) { int r = ::mkdir(fn, 0755); if ((r < 0) && (errno != EEXIST)) { err = -errno; derr << __func__ << " failed to create dir " << fn << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to create dir"); } dout(15) << "put_bl " << a << "/" << b << " = " << bl.length() << " bytes" << dendl; snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b); } else { dout(15) << "put_bl " << a << " = " << bl.length() << " bytes" << dendl; } char tfn[1024]; int fd; if (append) { fd = ::open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); if (fd < 0) { err = -errno; derr << "failed to open " << fn << "for append: " << cpp_strerror(err) << dendl; assert(0 == "failed to open for append"); } } else { snprintf(tfn, sizeof(tfn), "%s.new", fn); fd = ::open(tfn, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd < 0) { err = -errno; derr << "failed to open " << tfn << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to open"); } } err = bl.write_fd(fd); assert(!err); err = ::fsync(fd); assert(!err); err = TEMP_FAILURE_RETRY(::close(fd)); assert (!err); // this really can't fail, right? right?... if (!append) { err = ::rename(tfn, fn); if (err < 0) { err = -errno; derr << __func__ << " failed to rename '" << tfn << "' -> '" << fn << "': " << cpp_strerror(err) << dendl; assert(0 == "failed to rename"); } } } void MonitorStore::put_bl_sn_map(const char *a, map::iterator start, map::iterator end) { int err = 0; int close_err = 0; version_t first = start->first; map::iterator lastp = end; --lastp; version_t last = lastp->first; dout(15) << "put_bl_sn_map " << a << "/[" << first << ".." << last << "]" << dendl; // only do a big sync if there are several values, or if the feature is disabled. if (g_conf->mon_sync_fs_threshold <= 0 || last - first < (unsigned)g_conf->mon_sync_fs_threshold) { // just do them individually for (map::iterator p = start; p != end; ++p) { put_bl_sn(p->second, a, p->first); } return; } // make sure dir exists char dfn[1024]; snprintf(dfn, sizeof(dfn), "%s/%s", dir.c_str(), a); int r = ::mkdir(dfn, 0755); if ((r < 0) && (errno != EEXIST)) { err = -errno; derr << __func__ << " failed to create dir " << dfn << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to create dir"); } for (map::iterator p = start; p != end; ++p) { char tfn[1024], fn[1024]; snprintf(fn, sizeof(fn), "%s/%llu", dfn, (long long unsigned)p->first); snprintf(tfn, sizeof(tfn), "%s.new", fn); int fd = ::open(tfn, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd < 0) { int err = -errno; derr << "failed to open " << tfn << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to open"); } err = p->second.write_fd(fd); close_err = TEMP_FAILURE_RETRY(::close(fd)); assert (0 == close_err); if (err < 0) assert(0 == "failed to write"); } // sync them all int dirfd = ::open(dir.c_str(), O_RDONLY); if (dirfd < 0) { err = -errno; derr << "failed to open " << dir << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to open temp file"); } err = sync_filesystem(dirfd); if (err < 0) { derr << "sync_filesystem error " << cpp_strerror(err) << dendl; assert(0 == "failed to sync_filesystem"); } close_err = TEMP_FAILURE_RETRY(::close(dirfd)); assert (0 == close_err); // rename them all into place for (map::iterator p = start; p != end; ++p) { char tfn[1024], fn[1024]; snprintf(fn, sizeof(fn), "%s/%llu", dfn, (long long unsigned)p->first); snprintf(tfn, sizeof(tfn), "%s.new", fn); err = ::rename(tfn, fn); if (err < 0) assert(0 == "failed to rename"); } // fsync the dir (to commit the renames) dirfd = ::open(dir.c_str(), O_RDONLY); if (dirfd < 0) { err = -errno; derr << __func__ << " failed to open " << dir << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to open dir"); } err = ::fsync(dirfd); if (err < 0) { err = -errno; derr << __func__ << " failed to fsync " << dir << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to fsync"); } close_err = TEMP_FAILURE_RETRY(::close(dirfd)); assert (0 == close_err); } void MonitorStore::sync() { int dirfd = ::open(dir.c_str(), O_RDONLY); if (dirfd < 0) { int err = -errno; derr << __func__ << " failed to open " << dir << ": " << cpp_strerror(err) << dendl; assert(0 == "failed to open dir for syncing"); } int ret = sync_filesystem(dirfd); if (ret < 0) { derr << __func__ << " sync_filesystem error " << cpp_strerror(ret) << dendl; assert(0 == "failed to sync_filesystem"); } int close_err = TEMP_FAILURE_RETRY(::close(dirfd)); assert (0 == close_err); } ceph-0.80.11/src/mon/Paxos.h0000664000175100017510000012216212623076744017524 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* time----> cccccccccccccccccca???????????????????????????????????????? cccccccccccccccccca???????????????????????????????????????? cccccccccccccccccca???????????????????????????????????????? leader cccccccccccccccccc????????????????????????????????????????? ccccc?????????????????????????????????????????????????????? last_committed pn_from pn a 12v b 12v c 14v d e 12v */ /** * Paxos storage layout and behavior * * Currently, we use a key/value store to hold all the Paxos-related data, but * it can logically be depicted as this: * * paxos: * first_committed -> 1 * last_committed -> 4 * 1 -> value_1 * 2 -> value_2 * 3 -> value_3 * 4 -> value_4 * * Since we are relying on a k/v store supporting atomic transactions, we can * guarantee that if 'last_committed' has a value of '4', then we have up to * version 4 on the store, and no more than that; the same applies to * 'first_committed', which holding '1' will strictly meaning that our lowest * version is 1. * * Each version's value (value_1, value_2, ..., value_n) is a blob of data, * incomprehensible to the Paxos. These values are proposed to the Paxos on * propose_new_value() and each one is a transaction encoded in a bufferlist. * * The Paxos will write the value to disk, associating it with its version, * but will take a step further: the value shall be decoded, and the operations * on that transaction shall be applied during the same transaction that will * write the value's encoded bufferlist to disk. This behavior ensures that * whatever is being proposed will only be available on the store when it is * applied by Paxos, which will then be aware of such new values, guaranteeing * the store state is always consistent without requiring shady workarounds. * * So, let's say that FooMonitor proposes the following transaction, neatly * encoded on a bufferlist of course: * * Tx_Foo * put(foo, last_committed, 3) * put(foo, 3, foo_value_3) * erase(foo, 2) * erase(foo, 1) * put(foo, first_committed, 3) * * And knowing that the Paxos is proposed Tx_Foo as a bufferlist, once it is * ready to commit, and assuming we are now committing version 5 of the Paxos, * we will do something along the lines of: * * Tx proposed_tx; * proposed_tx.decode(Tx_foo_bufferlist); * * Tx our_tx; * our_tx.put(paxos, last_committed, 5); * our_tx.put(paxos, 5, Tx_foo_bufferlist); * our_tx.append(proposed_tx); * * store_apply(our_tx); * * And the store should look like this after we apply 'our_tx': * * paxos: * first_committed -> 1 * last_committed -> 5 * 1 -> value_1 * 2 -> value_2 * 3 -> value_3 * 4 -> value_4 * 5 -> Tx_foo_bufferlist * foo: * first_committed -> 3 * last_committed -> 3 * 3 -> foo_value_3 * */ #ifndef CEPH_MON_PAXOS_H #define CEPH_MON_PAXOS_H #include "include/types.h" #include "mon_types.h" #include "include/buffer.h" #include "messages/PaxosServiceMessage.h" #include "msg/msg_types.h" #include "include/Context.h" #include "common/Timer.h" #include "common/perf_counters.h" #include #include "MonitorDBStore.h" class Monitor; class MMonPaxos; class Paxos; enum { l_paxos_first = 45800, l_paxos_start_leader, l_paxos_start_peon, l_paxos_restart, l_paxos_refresh, l_paxos_refresh_latency, l_paxos_begin, l_paxos_begin_keys, l_paxos_begin_bytes, l_paxos_begin_latency, l_paxos_commit, l_paxos_commit_keys, l_paxos_commit_bytes, l_paxos_commit_latency, l_paxos_collect, l_paxos_collect_keys, l_paxos_collect_bytes, l_paxos_collect_latency, l_paxos_collect_uncommitted, l_paxos_collect_timeout, l_paxos_accept_timeout, l_paxos_lease_ack_timeout, l_paxos_lease_timeout, l_paxos_store_state, l_paxos_store_state_keys, l_paxos_store_state_bytes, l_paxos_store_state_latency, l_paxos_share_state, l_paxos_share_state_keys, l_paxos_share_state_bytes, l_paxos_new_pn, l_paxos_new_pn_latency, l_paxos_last, }; // i am one state machine. /** * This libary is based on the Paxos algorithm, but varies in a few key ways: * 1- Only a single new value is generated at a time, simplifying the recovery logic. * 2- Nodes track "committed" values, and share them generously (and trustingly) * 3- A 'leasing' mechanism is built-in, allowing nodes to determine when it is * safe to "read" their copy of the last committed value. * * This provides a simple replication substrate that services can be built on top of. * See PaxosService.h */ class Paxos { /** * @defgroup Paxos_h_class Paxos * @{ */ /** * The Monitor to which this Paxos class is associated with. */ Monitor *mon; /// perf counter for internal instrumentations PerfCounters *logger; void init_logger(); // my state machine info const string paxos_name; friend class Monitor; friend class PaxosService; list extra_state_dirs; // LEADER+PEON // -- generic state -- public: /** * @defgroup Paxos_h_states States on which the leader/peon may be. * @{ */ enum { /** * Leader/Peon is in Paxos' Recovery state */ STATE_RECOVERING, /** * Leader/Peon is idle, and the Peon may or may not have a valid lease. */ STATE_ACTIVE, /** * Leader/Peon is updating to a new value. */ STATE_UPDATING, /* * Leader proposing an old value */ STATE_UPDATING_PREVIOUS, }; /** * Obtain state name from constant value. * * @note This function will raise a fatal error if @p s is not * a valid state value. * * @param s State value. * @return The state's name. */ static const string get_statename(int s) { switch (s) { case STATE_RECOVERING: return "recovering"; case STATE_ACTIVE: return "active"; case STATE_UPDATING: return "updating"; case STATE_UPDATING_PREVIOUS: return "updating-previous"; default: return "UNKNOWN"; } } private: /** * The state we are in. */ int state; /** * @} */ public: /** * Check if we are recovering. * * @return 'true' if we are on the Recovering state; 'false' otherwise. */ bool is_recovering() const { return (state & STATE_RECOVERING); } /** * Check if we are active. * * @return 'true' if we are on the Active state; 'false' otherwise. */ bool is_active() const { return state == STATE_ACTIVE; } /** * Check if we are updating. * * @return 'true' if we are on the Updating state; 'false' otherwise. */ bool is_updating() const { return state == STATE_UPDATING; } /** * Check if we are updating/proposing a previous value from a * previous quorum */ bool is_updating_previous() const { return state == STATE_UPDATING_PREVIOUS; } private: /** * @defgroup Paxos_h_recovery_vars Common recovery-related member variables * @note These variables are common to both the Leader and the Peons. * @{ */ /** * */ version_t first_committed; /** * Last Proposal Number * * @todo Expand description */ version_t last_pn; /** * Last committed value's version. * * On both the Leader and the Peons, this is the last value's version that * was accepted by a given quorum and thus committed, that this instance * knows about. * * @note It may not be the last committed value's version throughout the * system. If we are a Peon, we may have not been part of the quorum * that accepted the value, and for this very same reason we may still * be a (couple of) version(s) behind, until we learn about the most * recent version. This should only happen if we are not active (i.e., * part of the quorum), which should not happen if we are up, running * and able to communicate with others -- thus able to be part of the * monmap and trigger new elections. */ version_t last_committed; /** * Last committed value's time. * * When the commit happened. */ utime_t last_commit_time; /** * The last Proposal Number we have accepted. * * On the Leader, it will be the Proposal Number picked by the Leader * itself. On the Peon, however, it will be the proposal sent by the Leader * and it will only be updated iif its value is higher than the one * already known by the Peon. */ version_t accepted_pn; /** * The last_committed epoch of the leader at the time we accepted the last pn. * * This has NO SEMANTIC MEANING, and is there only for the debug output. */ version_t accepted_pn_from; /** * Map holding the first committed version by each quorum member. * * The versions kept in this map are updated during the collect phase. * When the Leader starts the collect phase, each Peon will reply with its * first committed version, which will then be kept in this map. */ map peer_first_committed; /** * Map holding the last committed version by each quorum member. * * The versions kept in this map are updated during the collect phase. * When the Leader starts the collect phase, each Peon will reply with its * last committed version, which will then be kept in this map. */ map peer_last_committed; /** * @} */ // active (phase 2) /** * @defgroup Paxos_h_active_vars Common active-related member variables * @{ */ /** * When does our read lease expires. * * Instead of performing a full commit each time a read is requested, we * keep leases. Each lease will have an expiration date, which may or may * not be extended. */ utime_t lease_expire; /** * List of callbacks waiting for our state to change into STATE_ACTIVE. */ list waiting_for_active; /** * List of callbacks waiting for the chance to read a version from us. * * Each entry on the list may result from an attempt to read a version that * wasn't available at the time, or an attempt made during a period during * which we could not satisfy the read request. The first case happens if * the requested version is greater than our last committed version. The * second scenario may happen if we are recovering, or if we don't have a * valid lease. * * The list will be woken up once we change to STATE_ACTIVE with an extended * lease -- which can be achieved if we have everyone on the quorum on board * with the latest proposal, or if we don't really care about the remaining * uncommitted values --, or if we're on a quorum of one. */ list waiting_for_readable; /** * @} */ // -- leader -- // recovery (paxos phase 1) /** * @defgroup Paxos_h_leader_recovery Leader-specific Recovery-related vars * @{ */ /** * Number of replies to the collect phase we've received so far. * * This variable is reset to 1 each time we start a collect phase; it is * incremented each time we receive a reply to the collect message, and * is used to determine whether or not we have received replies from the * whole quorum. */ unsigned num_last; /** * Uncommitted value's version. * * If we have, or end up knowing about, an uncommitted value, then its * version will be kept in this variable. * * @note If this version equals @p last_committed+1 when we reach the final * steps of recovery, then the algorithm will assume this is a value * the Leader does not know about, and trustingly the Leader will * propose this version's value. */ version_t uncommitted_v; /** * Uncommitted value's Proposal Number. * * We use this variable to assess if the Leader should take into consideration * an uncommitted value sent by a Peon. Given that the Peon will send back to * the Leader the last Proposal Number he accepted, the Leader will be able * to infer if this value is more recent than the one the Leader has, thus * more relevant. */ version_t uncommitted_pn; /** * Uncommitted Value. * * If the system fails in-between the accept replies from the Peons and the * instruction to commit from the Leader, then we may end up with accepted * but yet-uncommitted values. During the Leader's recovery, he will attempt * to bring the whole system to the latest state, and that means committing * past accepted but uncommitted values. * * This variable will hold an uncommitted value, which may originate either * on the Leader, or learnt by the Leader from a Peon during the collect * phase. */ bufferlist uncommitted_value; /** * Used to specify when an on-going collect phase times out. */ Context *collect_timeout_event; /** * @} */ // active /** * @defgroup Paxos_h_leader_active Leader-specific Active-related vars * @{ */ /** * Set of participants (Leader & Peons) that have acked a lease extension. * * Each Peon that acknowledges a lease extension will have its place in this * set, which will be used to account for all the acks from all the quorum * members, guaranteeing that we trigger new elections if some don't ack in * the expected timeframe. */ set acked_lease; /** * Callback responsible for extending the lease periodically. */ Context *lease_renew_event; /** * Callback to trigger new elections once the time for acks is out. */ Context *lease_ack_timeout_event; /** * @} */ /** * @defgroup Paxos_h_peon_active Peon-specific Active-related vars * @{ */ /** * Callback to trigger new elections when the Peon's lease times out. * * If the Peon's lease is extended, this callback will be reset (i.e., * we cancel the event and reschedule a new one with starting from the * beginning). */ Context *lease_timeout_event; /** * @} */ // updating (paxos phase 2) /** * @defgroup Paxos_h_leader_updating Leader-specific Updating-related vars * @{ */ /** * New Value being proposed to the Peons. * * This bufferlist holds the value the Leader is proposing to the Peons, and * that will be committed if the Peons do accept the proposal. */ bufferlist new_value; /** * Set of participants (Leader & Peons) that accepted the new proposed value. * * This set is used to keep track of those who have accepted the proposed * value, so the leader may know when to issue a commit (when a majority of * participants has accepted the proposal), and when to extend the lease * (when all the quorum members have accepted the proposal). */ set accepted; /** * Callback to trigger a new election if the proposal is not accepted by the * full quorum within a given timeframe. * * If the full quorum does not accept the proposal, then it means that the * Leader may no longer be recognized as the leader, or that the quorum has * changed, and the value may have not reached all the participants. Thus, * the leader must call new elections, and go through a recovery phase in * order to propagate the new value throughout the system. * * This does not mean that we won't commit. We will commit as soon as we * have a majority of acceptances. But if we do not have full acceptance * from the quorum, then we cannot extend the lease, as some participants * may not have the latest committed value. */ Context *accept_timeout_event; /** * List of callbacks waiting for it to be possible to write again. * * @remarks It is not possible to write if we are not the Leader, or we are * not on the active state, or if the lease has expired. */ list waiting_for_writeable; /** * List of callbacks waiting for a commit to finish. * * @remarks This may be used to a) wait for an on-going commit to finish * before we proceed with, say, a new proposal; or b) wait for the * next commit to be finished so we are sure that our value was * fully committed. */ list waiting_for_commit; /** * */ list proposals; /** * @} */ /** * @defgroup Paxos_h_sync_warns Synchronization warnings * @todo Describe these variables * @{ */ utime_t last_clock_drift_warn; int clock_drift_warned; /** * @} */ /** * Should be true if we have proposed to trim, or are in the middle of * trimming; false otherwise. */ bool trimming; /** * @defgroup Paxos_h_callbacks Callback classes. * @{ */ /** * Callback class responsible for handling a Collect Timeout. */ class C_CollectTimeout : public Context { Paxos *paxos; public: C_CollectTimeout(Paxos *p) : paxos(p) {} void finish(int r) { if (r == -ECANCELED) return; paxos->collect_timeout(); } }; /** * Callback class responsible for handling an Accept Timeout. */ class C_AcceptTimeout : public Context { Paxos *paxos; public: C_AcceptTimeout(Paxos *p) : paxos(p) {} void finish(int r) { if (r == -ECANCELED) return; paxos->accept_timeout(); } }; /** * Callback class responsible for handling a Lease Ack Timeout. */ class C_LeaseAckTimeout : public Context { Paxos *paxos; public: C_LeaseAckTimeout(Paxos *p) : paxos(p) {} void finish(int r) { if (r == -ECANCELED) return; paxos->lease_ack_timeout(); } }; /** * Callback class responsible for handling a Lease Timeout. */ class C_LeaseTimeout : public Context { Paxos *paxos; public: C_LeaseTimeout(Paxos *p) : paxos(p) {} void finish(int r) { if (r == -ECANCELED) return; paxos->lease_timeout(); } }; /** * Callback class responsible for handling a Lease Renew Timeout. */ class C_LeaseRenew : public Context { Paxos *paxos; public: C_LeaseRenew(Paxos *p) : paxos(p) {} void finish(int r) { if (r == -ECANCELED) return; paxos->lease_renew_timeout(); } }; class C_Trimmed : public Context { Paxos *paxos; public: C_Trimmed(Paxos *p) : paxos(p) { } void finish(int r) { paxos->trimming = false; } }; /** * */ public: class C_Proposal : public Context { Context *proposer_context; public: bufferlist bl; // for debug purposes. Will go away. Soon. bool proposed; utime_t proposal_time; C_Proposal(Context *c, bufferlist& proposal_bl) : proposer_context(c), bl(proposal_bl), proposed(false), proposal_time(ceph_clock_now(NULL)) { } void finish(int r) { if (proposer_context) { proposer_context->complete(r); proposer_context = NULL; } } }; /** * @} */ private: /** * @defgroup Paxos_h_election_triggered Steps triggered by an election. * * @note All these functions play a significant role in the Recovery Phase, * which is triggered right after an election once someone becomes * the Leader. * @{ */ /** * Create a new Proposal Number and propose it to the Peons. * * This function starts the Recovery Phase, which can be directly mapped * onto the original Paxos' Prepare phase. Basically, we'll generate a * Proposal Number, taking @p oldpn into consideration, and we will send * it to a quorum, along with our first and last committed versions. By * sending these information in a message to the quorum, we expect to * obtain acceptances from a majority, allowing us to commit, or be * informed of a higher Proposal Number known by one or more of the Peons * in the quorum. * * @pre We are the Leader. * @post Recovery Phase initiated by sending messages to the quorum. * * @param oldpn A proposal number taken as the highest known so far, that * should be taken into consideration when generating a new * Proposal Number for the Recovery Phase. */ void collect(version_t oldpn); /** * Handle the reception of a collect message from the Leader and reply * accordingly. * * Once a Peon receives a collect message from the Leader it will reply * with its first and last committed versions, as well as information so * the Leader may know if his Proposal Number was, or was not, accepted by * the Peon. The Peon will accept the Leader's Proposal Number iif it is * higher than the Peon's currently accepted Proposal Number. The Peon may * also inform the Leader of accepted but uncommitted values. * * @invariant The message is an operation of type OP_COLLECT. * @pre We are a Peon. * @post Replied to the Leader, accepting or not accepting his PN. * * @param collect The collect message sent by the Leader to the Peon. */ void handle_collect(MMonPaxos *collect); /** * Handle a response from a Peon to the Leader's collect phase. * * The received message will state the Peon's last committed version, as * well as its last proposal number. This will lead to one of the following * scenarios: if the replied Proposal Number is equal to the one we proposed, * then the Peon has accepted our proposal, and if all the Peons do accept * our Proposal Number, then we are allowed to proceed with the commit; * however, if a Peon replies with a higher Proposal Number, we assume he * knows something we don't and the Leader will have to abort the current * proposal in order to retry with the Proposal Number specified by the Peon. * It may also occur that the Peon replied with a lower Proposal Number, in * which case we assume it is a reply to an an older value and we'll simply * drop it. * This function will also check if the Peon replied with an accepted but * yet uncommitted value. In this case, if its version is higher than our * last committed value by one, we assume that the Peon knows a value from a * previous proposal that has never been committed, and we should try to * commit that value by proposing it next. On the other hand, if that is * not the case, we'll assume it is an old, uncommitted value, we do not * care about and we'll consider the system active by extending the leases. * * @invariant The message is an operation of type OP_LAST. * @pre We are the Leader. * @post We initiate a commit, or we retry with a higher Proposal Number, * or we drop the message. * @post We move from STATE_RECOVERING to STATE_ACTIVE. * * @param last The message sent by the Peon to the Leader. */ void handle_last(MMonPaxos *last); /** * The Recovery Phase timed out, meaning that a significant part of the * quorum does not believe we are the Leader, and we thus should trigger new * elections. * * @pre We believe to be the Leader. * @post Trigger new elections. */ void collect_timeout(); /** * @} */ /** * @defgroup Paxos_h_updating_funcs Functions used during the Updating State * * These functions may easily be mapped to the original Paxos Algorithm's * phases. * * Taking into account the algorithm can be divided in 4 phases (Prepare, * Promise, Accept Request and Accepted), we can easily map Paxos::begin to * both the Prepare and Accept Request phases; the Paxos::handle_begin to * the Promise phase; and the Paxos::handle_accept to the Accepted phase. * @{ */ /** * Start a new proposal with the intent of committing @p value. * * If we are alone on the system (i.e., a quorum of one), then we will * simply commit the value, but if we are not alone, then we need to propose * the value to the quorum. * * @pre We are the Leader * @pre We are on STATE_ACTIVE * @post We commit, iif we are alone, or we send a message to each quorum * member * @post We are on STATE_ACTIVE, iif we are alone, or on * STATE_UPDATING otherwise * * @param value The value being proposed to the quorum */ void begin(bufferlist& value); /** * Accept or decline (by ignoring) a proposal from the Leader. * * We will decline the proposal (by ignoring it) if we have promised to * accept a higher numbered proposal. If that is not the case, we will * accept it and accordingly reply to the Leader. * * @pre We are a Peon * @pre We are on STATE_ACTIVE * @post We are on STATE_UPDATING iif we accept the Leader's proposal * @post We send a reply message to the Leader iif we accept his proposal * * @invariant The received message is an operation of type OP_BEGIN * * @param begin The message sent by the Leader to the Peon during the * Paxos::begin function * */ void handle_begin(MMonPaxos *begin); /** * Handle an Accept message sent by a Peon. * * In order to commit, the Leader has to receive accepts from a majority of * the quorum. If that does happen, then the Leader may proceed with the * commit. However, the Leader needs the accepts from all the quorum members * in order to extend the lease and move on to STATE_ACTIVE. * * This function handles these two situations, accounting for the amount of * received accepts. * * @pre We are the Leader * @pre We are on STATE_UPDATING * @post We are on STATE_ACTIVE iif we received accepts from the full quorum * @post We extended the lease iif we moved on to STATE_ACTIVE * @post We are on STATE_UPDATING iif we didn't received accepts from the * full quorum * @post We have committed iif we received accepts from a majority * * @invariant The received message is an operation of type OP_ACCEPT * * @param accept The message sent by the Peons to the Leader during the * Paxos::handle_begin function */ void handle_accept(MMonPaxos *accept); /** * Trigger a fresh election. * * During Paxos::begin we set a Callback of type Paxos::C_AcceptTimeout in * order to limit the amount of time we spend waiting for Accept replies. * This callback will call Paxos::accept_timeout when it is fired. * * This is essential to the algorithm because there may be the chance that * we are no longer the Leader (i.e., others don't believe in us) and we * are getting ignored, or we dropped out of the quorum and haven't realised * it. So, our only option is to trigger fresh elections. * * @pre We are the Leader * @pre We are on STATE_UPDATING * @post Triggered fresh elections */ void accept_timeout(); /** * @} */ /** * Commit a value throughout the system. * * The Leader will cancel the current lease (as it was for the old value), * and will store the committed value locally. It will then instruct every * quorum member to do so as well. * * @pre We are the Leader * @pre We are on STATE_UPDATING * @pre A majority of quorum members accepted our proposal * @post Value locally stored * @post Quorum members instructed to commit the new value. */ void commit(); /** * Commit the new value to stable storage as being the latest available * version. * * @pre We are a Peon * @post The new value is locally stored * @post Fire up the callbacks waiting on waiting_for_commit * * @invariant The received message is an operation of type OP_COMMIT * * @param commit The message sent by the Leader to the Peon during * Paxos::commit */ void handle_commit(MMonPaxos *commit); /** * Extend the system's lease. * * This means that the Leader considers that it should now safe to read from * any node on the system, since every quorum member is now in possession of * the latest version. Therefore, the Leader will send a message stating just * this to each quorum member, and will impose a limited timeframe during * which acks will be accepted. If there aren't as many acks as expected * (i.e, if at least one quorum member does not ack the lease) during this * timeframe, then we will force fresh elections. * * @pre We are the Leader * @pre We are on STATE_ACTIVE * @post A message extending the lease is sent to each quorum member * @post A timeout callback is set to limit the amount of time we will wait * for lease acks. * @post A timer is set in order to renew the lease after a certain amount * of time. */ void extend_lease(); /** * Update the lease on the Peon's side of things. * * Once a Peon receives a Lease message, it will update its lease_expire * variable, reply to the Leader acknowledging the lease update and set a * timeout callback to be fired upon the lease's expiration. Finally, the * Peon will fire up all the callbacks waiting for it to become active, * which it just did, and all those waiting for it to become readable, * which should be true if the Peon's lease didn't expire in the mean time. * * @pre We are a Peon * @post We update the lease accordingly * @post A lease timeout callback is set * @post Move to STATE_ACTIVE * @post Fire up all the callbacks waiting for STATE_ACTIVE * @post Fire up all the callbacks waiting for readable iif we are readable * @post Ack the lease to the Leader * * @invariant The received message is an operation of type OP_LEASE * * @param The message sent by the Leader to the Peon during the * Paxos::extend_lease function */ void handle_lease(MMonPaxos *lease); /** * Account for all the Lease Acks the Leader receives from the Peons. * * Once the Leader receives all the Lease Acks from the Peons, it will be * able to cancel the Lease Ack timeout callback, thus avoiding calling * fresh elections. * * @pre We are the Leader * @post Cancel the Lease Ack timeout callback iif we receive acks from all * the quorum members * * @invariant The received message is an operation of type OP_LEASE_ACK * * @param ack The message sent by a Peon to the Leader during the * Paxos::handle_lease function */ void handle_lease_ack(MMonPaxos *ack); /** * Call fresh elections because at least one Peon didn't acked our lease. * * @pre We are the Leader * @pre We are on STATE_ACTIVE * @post Trigger fresh elections */ void lease_ack_timeout(); /** * Extend lease since we haven't had new committed values meanwhile. * * @pre We are the Leader * @pre We are on STATE_ACTIVE * @post Go through with Paxos::extend_lease */ void lease_renew_timeout(); /** * Call fresh elections because the Peon's lease expired without being * renewed or receiving a fresh lease. * * This means that the Peon is no longer assumed as being in the quorum * (or there is no Leader to speak of), so just trigger fresh elections * to circumvent this issue. * * @pre We are a Peon * @post Trigger fresh elections */ void lease_timeout(); // on peon, if lease isn't extended /// restart the lease timeout timer void reset_lease_timeout(); /** * Cancel all of Paxos' timeout/renew events. */ void cancel_events(); /** * Shutdown this Paxos machine */ void shutdown(); /** * Generate a new Proposal Number based on @p gt * * @todo Check what @p gt actually means and what its usage entails * @param gt A hint for the geration of the Proposal Number * @return A globally unique, monotonically increasing Proposal Number */ version_t get_new_proposal_number(version_t gt=0); /** * @todo document sync function */ void warn_on_future_time(utime_t t, entity_name_t from); /** * Queue a new proposal by pushing it at the back of the queue; do not * propose it. * * @param bl The bufferlist to be proposed * @param onfinished The callback to be called once the proposal finishes */ void queue_proposal(bufferlist& bl, Context *onfinished); /** * Begin proposing the Proposal at the front of the proposals queue. */ void propose_queued(); /** * refresh state from store * * Called when we have new state for the mon to consume. If we return false, * abort (we triggered a bootstrap). * * @returns true on success, false if we are now bootstrapping */ bool do_refresh(); void commit_proposal(); void finish_round(); public: /** * @param m A monitor * @param mid A machine id */ Paxos(Monitor *m, const string &name) : mon(m), logger(NULL), paxos_name(name), state(STATE_RECOVERING), first_committed(0), last_pn(0), last_committed(0), accepted_pn(0), accepted_pn_from(0), num_last(0), uncommitted_v(0), uncommitted_pn(0), collect_timeout_event(0), lease_renew_event(0), lease_ack_timeout_event(0), lease_timeout_event(0), accept_timeout_event(0), clock_drift_warned(0), trimming(false) { } const string get_name() const { return paxos_name; } void dispatch(PaxosServiceMessage *m); void read_and_prepare_transactions(MonitorDBStore::Transaction *tx, version_t from, version_t last); void init(); /** * dump state info to a formatter */ void dump_info(Formatter *f); /** * This function runs basic consistency checks. Importantly, if * it is inconsistent and shouldn't be, it asserts out. * * @return True if consistent, false if not. */ bool is_consistent(); void restart(); /** * Initiate the Leader after it wins an election. * * Once an election is won, the Leader will be initiated and there are two * possible outcomes of this method: the Leader directly jumps to the active * state (STATE_ACTIVE) if it believes to be the only one in the quorum, or * will start recovering (STATE_RECOVERING) by initiating the collect phase. * * @pre Our monitor is the Leader. * @post We are either on STATE_ACTIVE if we're the only one in the quorum, * or on STATE_RECOVERING otherwise. */ void leader_init(); /** * Initiate a Peon after it loses an election. * * If we are a Peon, then there must be a Leader and we are not alone in the * quorum, thus automatically assume we are on STATE_RECOVERING, which means * we will soon be enrolled into the Leader's collect phase. * * @pre There is a Leader, and he's about to start the collect phase. * @post We are on STATE_RECOVERING and will soon receive collect phase's * messages. */ void peon_init(); /** * Include an incremental state of values, ranging from peer_first_committed * to the last committed value, on the message m * * @param m A message * @param peer_first_committed Lowest version to take into account * @param peer_last_committed Highest version to take into account */ void share_state(MMonPaxos *m, version_t peer_first_committed, version_t peer_last_committed); /** * Store on disk a state that was shared with us * * Basically, we received a set of version. Or just one. It doesn't matter. * What matters is that we have to stash it in the store. So, we will simply * write every single bufferlist into their own versions on our side (i.e., * onto paxos-related keys), and then we will decode those same bufferlists * we just wrote and apply the transactions they hold. We will also update * our first and last committed values to point to the new values, if need * be. All this is done tightly wrapped in a transaction to ensure we * enjoy the atomicity guarantees given by our awesome k/v store. * * @param m A message * @returns true if we stored something new; false otherwise */ bool store_state(MMonPaxos *m); void _sanity_check_store(); /** * remove legacy paxos versions from before conversion */ void remove_legacy_versions(); /** * Helper function to decode a bufferlist into a transaction and append it * to another transaction. * * This function is used during the Leader's commit and during the * Paxos::store_state in order to apply the bufferlist's transaction onto * the store. * * @param t The transaction to which we will append the operations * @param bl A bufferlist containing an encoded transaction */ static void decode_append_transaction(MonitorDBStore::Transaction& t, bufferlist& bl) { MonitorDBStore::Transaction vt; bufferlist::iterator it = bl.begin(); vt.decode(it); t.append(vt); } /** * @todo This appears to be used only by the OSDMonitor, and I would say * its objective is to allow a third-party to have a "private" * state dir. -JL */ void add_extra_state_dir(string s) { extra_state_dirs.push_back(s); } // -- service interface -- /** * Add c to the list of callbacks waiting for us to become active. * * @param c A callback */ void wait_for_active(Context *c) { waiting_for_active.push_back(c); } /** * Trim the Paxos state as much as we can. */ void trim(); /** * Check if we should trim. * * If trimming is disabled, we must take that into consideration and only * return true if we are positively sure that we should trim soon. * * @returns true if we should trim; false otherwise. */ bool should_trim() { int available_versions = get_version() - get_first_committed(); int maximum_versions = g_conf->paxos_min + g_conf->paxos_trim_min; if (trimming || (available_versions <= maximum_versions)) return false; return true; } // read /** * @defgroup Paxos_h_read_funcs Read-related functions * @{ */ /** * Get latest committed version * * @return latest committed version */ version_t get_version() { return last_committed; } /** * Get first committed version * * @return the first committed version */ version_t get_first_committed() { return first_committed; } /** * Check if a given version is readable. * * A version may not be readable for a myriad of reasons: * @li the version @v is higher that the last committed version * @li we are not the Leader nor a Peon (election may be on-going) * @li we do not have a committed value yet * @li we do not have a valid lease * * @param seen The version we want to check if it is readable. * @return 'true' if the version is readable; 'false' otherwise. */ bool is_readable(version_t seen=0); /** * Read version @v and store its value in @bl * * @param[in] v The version we want to read * @param[out] bl The version's value * @return 'true' if we successfully read the value; 'false' otherwise */ bool read(version_t v, bufferlist &bl); /** * Read the latest committed version * * @param[out] bl The version's value * @return the latest committed version if we successfully read the value; * or 0 (zero) otherwise. */ version_t read_current(bufferlist &bl); /** * Add onreadable to the list of callbacks waiting for us to become readable. * * @param onreadable A callback */ void wait_for_readable(Context *onreadable) { assert(!is_readable()); waiting_for_readable.push_back(onreadable); } /** * @} */ /** * Check if we have a valid lease. * * @returns true if the lease is still valid; false otherwise. */ bool is_lease_valid(); // write /** * @defgroup Paxos_h_write_funcs Write-related functions * @{ */ /** * Check if we are writeable. * * We are writeable if we are alone (i.e., a quorum of one), or if we match * all the following conditions: * @li We are the Leader * @li We are on STATE_ACTIVE * @li We have a valid lease * * @return 'true' if we are writeable; 'false' otherwise. */ bool is_writeable(); /** * Add c to the list of callbacks waiting for us to become writeable. * * @param c A callback */ void wait_for_writeable(Context *c) { assert(!is_writeable()); waiting_for_writeable.push_back(c); } /** * List all queued proposals * * @param out[out] Output Stream onto which we will output the list * of queued proposals. */ void list_proposals(ostream& out); /** * Propose a new value to the Leader. * * This function enables the submission of a new value to the Leader, which * will trigger a new proposal. * * @param bl A bufferlist holding the value to be proposed * @param onfinish A callback to be fired up once we finish the proposal */ bool propose_new_value(bufferlist& bl, Context *onfinished=0); /** * Add oncommit to the back of the list of callbacks waiting for us to * finish committing. * * @param oncommit A callback */ void wait_for_commit(Context *oncommit) { waiting_for_commit.push_back(oncommit); } /** * Add oncommit to the front of the list of callbacks waiting for us to * finish committing. * * @param oncommit A callback */ void wait_for_commit_front(Context *oncommit) { waiting_for_commit.push_front(oncommit); } /** * @} */ /** * @} */ protected: MonitorDBStore *get_store(); }; inline ostream& operator<<(ostream& out, Paxos::C_Proposal& p) { string proposed = (p.proposed ? "proposed" : "unproposed"); out << " " << proposed << " queued " << (ceph_clock_now(NULL) - p.proposal_time) << " tx dump:\n"; MonitorDBStore::Transaction t; bufferlist::iterator p_it = p.bl.begin(); t.decode(p_it); JSONFormatter f(true); t.dump(&f); f.flush(out); return out; } #endif ceph-0.80.11/src/mon/Paxos.cc0000664000175100017510000012517712623076744017673 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "Paxos.h" #include "Monitor.h" #include "MonitorDBStore.h" #include "messages/MMonPaxos.h" #include "common/config.h" #include "include/assert.h" #include "include/stringify.h" #include "common/Formatter.h" #define dout_subsys ceph_subsys_paxos #undef dout_prefix #define dout_prefix _prefix(_dout, mon, mon->name, mon->rank, paxos_name, state, first_committed, last_committed) static ostream& _prefix(std::ostream *_dout, Monitor *mon, const string& name, int rank, const string& paxos_name, int state, version_t first_committed, version_t last_committed) { return *_dout << "mon." << name << "@" << rank << "(" << mon->get_state_name() << ")" << ".paxos(" << paxos_name << " " << Paxos::get_statename(state) << " c " << first_committed << ".." << last_committed << ") "; } MonitorDBStore *Paxos::get_store() { return mon->store; } void Paxos::read_and_prepare_transactions(MonitorDBStore::Transaction *tx, version_t first, version_t last) { dout(10) << __func__ << " first " << first << " last " << last << dendl; for (version_t v = first; v <= last; ++v) { dout(30) << __func__ << " apply version " << v << dendl; bufferlist bl; int err = get_store()->get(get_name(), v, bl); assert(err == 0); assert(bl.length()); decode_append_transaction(*tx, bl); } dout(15) << __func__ << " total versions " << (last-first) << dendl; } void Paxos::init() { // load paxos variables from stable storage last_pn = get_store()->get(get_name(), "last_pn"); accepted_pn = get_store()->get(get_name(), "accepted_pn"); last_committed = get_store()->get(get_name(), "last_committed"); first_committed = get_store()->get(get_name(), "first_committed"); dout(10) << __func__ << " last_pn: " << last_pn << " accepted_pn: " << accepted_pn << " last_committed: " << last_committed << " first_committed: " << first_committed << dendl; dout(10) << "init" << dendl; assert(is_consistent()); } void Paxos::init_logger() { PerfCountersBuilder pcb(g_ceph_context, "paxos", l_paxos_first, l_paxos_last); pcb.add_u64_counter(l_paxos_start_leader, "start_leader"); pcb.add_u64_counter(l_paxos_start_peon, "start_peon"); pcb.add_u64_counter(l_paxos_restart, "restart"); pcb.add_u64_counter(l_paxos_refresh, "refresh"); pcb.add_time_avg(l_paxos_refresh_latency, "refresh_latency"); pcb.add_u64_counter(l_paxos_begin, "begin"); pcb.add_u64_avg(l_paxos_begin_keys, "begin_keys"); pcb.add_u64_avg(l_paxos_begin_bytes, "begin_bytes"); pcb.add_time_avg(l_paxos_begin_latency, "begin_latency"); pcb.add_u64_counter(l_paxos_commit, "commit"); pcb.add_u64_avg(l_paxos_commit_keys, "commit_keys"); pcb.add_u64_avg(l_paxos_commit_bytes, "commit_bytes"); pcb.add_time_avg(l_paxos_commit_latency, "commit_latency"); pcb.add_u64_counter(l_paxos_collect, "collect"); pcb.add_u64_avg(l_paxos_collect_keys, "collect_keys"); pcb.add_u64_avg(l_paxos_collect_bytes, "collect_bytes"); pcb.add_time_avg(l_paxos_collect_latency, "collect_latency"); pcb.add_u64_counter(l_paxos_collect_uncommitted, "collect_uncommitted"); pcb.add_u64_counter(l_paxos_collect_timeout, "collect_timeout"); pcb.add_u64_counter(l_paxos_accept_timeout, "accept_timeout"); pcb.add_u64_counter(l_paxos_lease_ack_timeout, "lease_ack_timeout"); pcb.add_u64_counter(l_paxos_lease_timeout, "lease_timeout"); pcb.add_u64_counter(l_paxos_store_state, "store_state"); pcb.add_u64_avg(l_paxos_store_state_keys, "store_state_keys"); pcb.add_u64_avg(l_paxos_store_state_bytes, "store_state_bytes"); pcb.add_time_avg(l_paxos_store_state_latency, "store_state_latency"); pcb.add_u64_counter(l_paxos_share_state, "share_state"); pcb.add_u64_avg(l_paxos_share_state_keys, "share_state_keys"); pcb.add_u64_avg(l_paxos_share_state_bytes, "share_state_bytes"); pcb.add_u64_counter(l_paxos_new_pn, "new_pn"); pcb.add_time_avg(l_paxos_new_pn_latency, "new_pn_latency"); logger = pcb.create_perf_counters(); g_ceph_context->get_perfcounters_collection()->add(logger); } void Paxos::dump_info(Formatter *f) { f->open_object_section("paxos"); f->dump_unsigned("first_committed", first_committed); f->dump_unsigned("last_committed", last_committed); f->dump_unsigned("last_pn", last_pn); f->dump_unsigned("accepted_pn", accepted_pn); f->close_section(); } // --------------------------------- // PHASE 1 // leader void Paxos::collect(version_t oldpn) { // we're recoverying, it seems! state = STATE_RECOVERING; assert(mon->is_leader()); // reset the number of lasts received uncommitted_v = 0; uncommitted_pn = 0; uncommitted_value.clear(); peer_first_committed.clear(); peer_last_committed.clear(); // look for uncommitted value if (get_store()->exists(get_name(), last_committed+1)) { version_t v = get_store()->get(get_name(), "pending_v"); version_t pn = get_store()->get(get_name(), "pending_pn"); if (v && pn && v == last_committed + 1) { uncommitted_pn = pn; } else { dout(10) << "WARNING: no pending_pn on disk, using previous accepted_pn " << accepted_pn << " and crossing our fingers" << dendl; uncommitted_pn = accepted_pn; } uncommitted_v = last_committed+1; get_store()->get(get_name(), last_committed+1, uncommitted_value); assert(uncommitted_value.length()); dout(10) << "learned uncommitted " << (last_committed+1) << " pn " << uncommitted_pn << " (" << uncommitted_value.length() << " bytes) from myself" << dendl; logger->inc(l_paxos_collect_uncommitted); } // pick new pn accepted_pn = get_new_proposal_number(MAX(accepted_pn, oldpn)); accepted_pn_from = last_committed; num_last = 1; dout(10) << "collect with pn " << accepted_pn << dendl; // send collect for (set::const_iterator p = mon->get_quorum().begin(); p != mon->get_quorum().end(); ++p) { if (*p == mon->rank) continue; MMonPaxos *collect = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_COLLECT, ceph_clock_now(g_ceph_context)); collect->last_committed = last_committed; collect->first_committed = first_committed; collect->pn = accepted_pn; mon->messenger->send_message(collect, mon->monmap->get_inst(*p)); } // set timeout event collect_timeout_event = new C_CollectTimeout(this); mon->timer.add_event_after(g_conf->mon_accept_timeout, collect_timeout_event); } // peon void Paxos::handle_collect(MMonPaxos *collect) { dout(10) << "handle_collect " << *collect << dendl; assert(mon->is_peon()); // mon epoch filter should catch strays // we're recoverying, it seems! state = STATE_RECOVERING; if (collect->first_committed > last_committed+1) { dout(5) << __func__ << " leader's lowest version is too high for our last committed" << " (theirs: " << collect->first_committed << "; ours: " << last_committed << ") -- bootstrap!" << dendl; collect->put(); mon->bootstrap(); return; } // reply MMonPaxos *last = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_LAST, ceph_clock_now(g_ceph_context)); last->last_committed = last_committed; last->first_committed = first_committed; version_t previous_pn = accepted_pn; // can we accept this pn? if (collect->pn > accepted_pn) { // ok, accept it accepted_pn = collect->pn; accepted_pn_from = collect->pn_from; dout(10) << "accepting pn " << accepted_pn << " from " << accepted_pn_from << dendl; MonitorDBStore::Transaction t; t.put(get_name(), "accepted_pn", accepted_pn); dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; logger->inc(l_paxos_collect); logger->inc(l_paxos_collect_keys, t.get_keys()); logger->inc(l_paxos_collect_bytes, t.get_bytes()); utime_t start = ceph_clock_now(NULL); get_store()->apply_transaction(t); utime_t end = ceph_clock_now(NULL); logger->tinc(l_paxos_collect_latency, end - start); } else { // don't accept! dout(10) << "NOT accepting pn " << collect->pn << " from " << collect->pn_from << ", we already accepted " << accepted_pn << " from " << accepted_pn_from << dendl; } last->pn = accepted_pn; last->pn_from = accepted_pn_from; // share whatever committed values we have if (collect->last_committed < last_committed) share_state(last, collect->first_committed, collect->last_committed); // do we have an accepted but uncommitted value? // (it'll be at last_committed+1) bufferlist bl; if (collect->last_committed <= last_committed && get_store()->exists(get_name(), last_committed+1)) { get_store()->get(get_name(), last_committed+1, bl); assert(bl.length() > 0); dout(10) << " sharing our accepted but uncommitted value for " << last_committed+1 << " (" << bl.length() << " bytes)" << dendl; last->values[last_committed+1] = bl; version_t v = get_store()->get(get_name(), "pending_v"); version_t pn = get_store()->get(get_name(), "pending_pn"); if (v && pn && v == last_committed + 1) { last->uncommitted_pn = pn; } else { // previously we didn't record which pn a value was accepted // under! use the pn value we just had... :( dout(10) << "WARNING: no pending_pn on disk, using previous accepted_pn " << previous_pn << " and crossing our fingers" << dendl; last->uncommitted_pn = previous_pn; } logger->inc(l_paxos_collect_uncommitted); } // send reply mon->messenger->send_message(last, collect->get_source_inst()); collect->put(); } /** * @note This is Okay. We share our versions between peer_last_committed and * our last_committed (inclusive), and add their bufferlists to the * message. It will be the peer's job to apply them to his store, as * these bufferlists will contain raw transactions. * This function is called by both the Peon and the Leader. The Peon will * share the state with the Leader during handle_collect(), sharing any * values the leader may be missing (i.e., the leader's last_committed is * lower than the peon's last_committed). The Leader will share the state * with the Peon during handle_last(), if the peon's last_committed is * lower than the leader's last_committed. */ void Paxos::share_state(MMonPaxos *m, version_t peer_first_committed, version_t peer_last_committed) { assert(peer_last_committed < last_committed); dout(10) << "share_state peer has fc " << peer_first_committed << " lc " << peer_last_committed << dendl; version_t v = peer_last_committed + 1; // include incrementals uint64_t bytes = 0; for ( ; v <= last_committed; v++) { if (get_store()->exists(get_name(), v)) { get_store()->get(get_name(), v, m->values[v]); assert(m->values[v].length()); dout(10) << " sharing " << v << " (" << m->values[v].length() << " bytes)" << dendl; bytes += m->values[v].length() + 16; // paxos_ + 10 digits = 16 } } logger->inc(l_paxos_share_state); logger->inc(l_paxos_share_state_keys, m->values.size()); logger->inc(l_paxos_share_state_bytes, bytes); m->last_committed = last_committed; } /** * Store on disk a state that was shared with us * * Basically, we received a set of version. Or just one. It doesn't matter. * What matters is that we have to stash it in the store. So, we will simply * write every single bufferlist into their own versions on our side (i.e., * onto paxos-related keys), and then we will decode those same bufferlists * we just wrote and apply the transactions they hold. We will also update * our first and last committed values to point to the new values, if need * be. All all this is done tightly wrapped in a transaction to ensure we * enjoy the atomicity guarantees given by our awesome k/v store. */ bool Paxos::store_state(MMonPaxos *m) { MonitorDBStore::Transaction t; map::iterator start = m->values.begin(); bool changed = false; // build map of values to store // we want to write the range [last_committed, m->last_committed] only. if (start != m->values.end() && start->first > last_committed + 1) { // ignore everything if values start in the future. dout(10) << "store_state ignoring all values, they start at " << start->first << " > last_committed+1" << dendl; start = m->values.end(); } // push forward the start position on the message's values iterator, up until // we run out of positions or we find a position matching 'last_committed'. while (start != m->values.end() && start->first <= last_committed) { ++start; } // make sure we get the right interval of values to apply by pushing forward // the 'end' iterator until it matches the message's 'last_committed'. map::iterator end = start; while (end != m->values.end() && end->first <= m->last_committed) { last_committed = end->first; ++end; } if (start == end) { dout(10) << "store_state nothing to commit" << dendl; } else { dout(10) << "store_state [" << start->first << ".." << last_committed << "]" << dendl; t.put(get_name(), "last_committed", last_committed); // we should apply the state here -- decode every single bufferlist in the // map and append the transactions to 't'. map::iterator it; for (it = start; it != end; ++it) { // write the bufferlist as the version's value t.put(get_name(), it->first, it->second); // decode the bufferlist and append it to the transaction we will shortly // apply. decode_append_transaction(t, it->second); } // discard obsolete uncommitted value? if (uncommitted_v && uncommitted_v <= last_committed) { dout(10) << " forgetting obsolete uncommitted value " << uncommitted_v << " pn " << uncommitted_pn << dendl; uncommitted_v = 0; uncommitted_pn = 0; uncommitted_value.clear(); } } if (!t.empty()) { dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; logger->inc(l_paxos_store_state); logger->inc(l_paxos_store_state_bytes, t.get_bytes()); logger->inc(l_paxos_store_state_keys, t.get_keys()); utime_t start = ceph_clock_now(NULL); get_store()->apply_transaction(t); utime_t end = ceph_clock_now(NULL); logger->tinc(l_paxos_store_state_latency, end - start); // refresh first_committed; this txn may have trimmed. first_committed = get_store()->get(get_name(), "first_committed"); _sanity_check_store(); changed = true; } remove_legacy_versions(); return changed; } void Paxos::remove_legacy_versions() { if (get_store()->exists(get_name(), "conversion_first")) { MonitorDBStore::Transaction t; version_t v = get_store()->get(get_name(), "conversion_first"); dout(10) << __func__ << " removing pre-conversion paxos states from " << v << " until " << first_committed << dendl; for (; v < first_committed; ++v) { t.erase(get_name(), v); } t.erase(get_name(), "conversion_first"); get_store()->apply_transaction(t); } } void Paxos::_sanity_check_store() { version_t lc = get_store()->get(get_name(), "last_committed"); assert(lc == last_committed); } // leader void Paxos::handle_last(MMonPaxos *last) { bool need_refresh = false; int from = last->get_source().num(); dout(10) << "handle_last " << *last << dendl; if (!mon->is_leader()) { dout(10) << "not leader, dropping" << dendl; last->put(); return; } // note peer's first_ and last_committed, in case we learn a new // commit and need to push it to them. peer_first_committed[from] = last->first_committed; peer_last_committed[from] = last->last_committed; if (last->first_committed > last_committed + 1) { dout(5) << __func__ << " mon." << from << " lowest version is too high for our last committed" << " (theirs: " << last->first_committed << "; ours: " << last_committed << ") -- bootstrap!" << dendl; last->put(); mon->bootstrap(); return; } assert(g_conf->paxos_kill_at != 1); // store any committed values if any are specified in the message need_refresh = store_state(last); assert(g_conf->paxos_kill_at != 2); // is everyone contiguous and up to date? for (map::iterator p = peer_last_committed.begin(); p != peer_last_committed.end(); ++p) { if (p->second + 1 < first_committed && first_committed > 1) { dout(5) << __func__ << " peon " << p->first << " last_committed (" << p->second << ") is too low for our first_committed (" << first_committed << ") -- bootstrap!" << dendl; last->put(); mon->bootstrap(); return; } if (p->second < last_committed) { // share committed values dout(10) << " sending commit to mon." << p->first << dendl; MMonPaxos *commit = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_COMMIT, ceph_clock_now(g_ceph_context)); share_state(commit, peer_first_committed[p->first], p->second); mon->messenger->send_message(commit, mon->monmap->get_inst(p->first)); } } // do they accept your pn? if (last->pn > accepted_pn) { // no, try again. dout(10) << " they had a higher pn than us, picking a new one." << dendl; // cancel timeout event mon->timer.cancel_event(collect_timeout_event); collect_timeout_event = 0; collect(last->pn); } else if (last->pn == accepted_pn) { // yes, they accepted our pn. great. num_last++; dout(10) << " they accepted our pn, we now have " << num_last << " peons" << dendl; // did this person send back an accepted but uncommitted value? if (last->uncommitted_pn) { if (last->uncommitted_pn >= uncommitted_pn && last->last_committed >= last_committed && last->last_committed + 1 >= uncommitted_v) { uncommitted_v = last->last_committed+1; uncommitted_pn = last->uncommitted_pn; uncommitted_value = last->values[uncommitted_v]; dout(10) << "we learned an uncommitted value for " << uncommitted_v << " pn " << uncommitted_pn << " " << uncommitted_value.length() << " bytes" << dendl; } else { dout(10) << "ignoring uncommitted value for " << (last->last_committed+1) << " pn " << last->uncommitted_pn << " " << last->values[last->last_committed+1].length() << " bytes" << dendl; } } // is that everyone? if (num_last == mon->get_quorum().size()) { // cancel timeout event mon->timer.cancel_event(collect_timeout_event); collect_timeout_event = 0; peer_first_committed.clear(); peer_last_committed.clear(); // almost... // did we learn an old value? if (uncommitted_v == last_committed+1 && uncommitted_value.length()) { dout(10) << "that's everyone. begin on old learned value" << dendl; state = STATE_UPDATING_PREVIOUS; begin(uncommitted_value); } else { // active! dout(10) << "that's everyone. active!" << dendl; extend_lease(); need_refresh = false; if (do_refresh()) { finish_round(); finish_contexts(g_ceph_context, waiting_for_active); finish_contexts(g_ceph_context, waiting_for_readable); finish_contexts(g_ceph_context, waiting_for_writeable); } } } } else { // no, this is an old message, discard dout(10) << "old pn, ignoring" << dendl; } if (need_refresh) (void)do_refresh(); last->put(); } void Paxos::collect_timeout() { dout(1) << "collect timeout, calling fresh election" << dendl; collect_timeout_event = 0; logger->inc(l_paxos_collect_timeout); assert(mon->is_leader()); mon->bootstrap(); } // leader void Paxos::begin(bufferlist& v) { dout(10) << "begin for " << last_committed+1 << " " << v.length() << " bytes" << dendl; assert(mon->is_leader()); assert(is_updating() || is_updating_previous()); // we must already have a majority for this to work. assert(mon->get_quorum().size() == 1 || num_last > (unsigned)mon->monmap->size()/2); // and no value, yet. assert(new_value.length() == 0); // accept it ourselves accepted.clear(); accepted.insert(mon->rank); new_value = v; if (last_committed == 0) { MonitorDBStore::Transaction t; // initial base case; set first_committed too t.put(get_name(), "first_committed", 1); decode_append_transaction(t, new_value); bufferlist tx_bl; t.encode(tx_bl); new_value = tx_bl; } // store the proposed value in the store. IF it is accepted, we will then // have to decode it into a transaction and apply it. MonitorDBStore::Transaction t; t.put(get_name(), last_committed+1, new_value); // note which pn this pending value is for. t.put(get_name(), "pending_v", last_committed + 1); t.put(get_name(), "pending_pn", accepted_pn); dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); MonitorDBStore::Transaction debug_tx; bufferlist::iterator new_value_it = new_value.begin(); debug_tx.decode(new_value_it); debug_tx.dump(&f); *_dout << "\nbl dump:\n"; f.flush(*_dout); *_dout << dendl; logger->inc(l_paxos_begin); logger->inc(l_paxos_begin_keys, t.get_keys()); logger->inc(l_paxos_begin_bytes, t.get_bytes()); utime_t start = ceph_clock_now(NULL); get_store()->apply_transaction(t); utime_t end = ceph_clock_now(NULL); logger->tinc(l_paxos_begin_latency, end - start); assert(g_conf->paxos_kill_at != 3); if (mon->get_quorum().size() == 1) { // we're alone, take it easy commit(); if (do_refresh()) { assert(is_updating()); // we can't be updating-previous with quorum of 1 commit_proposal(); finish_round(); finish_contexts(g_ceph_context, waiting_for_active); finish_contexts(g_ceph_context, waiting_for_commit); finish_contexts(g_ceph_context, waiting_for_readable); finish_contexts(g_ceph_context, waiting_for_writeable); } return; } // ask others to accept it too! for (set::const_iterator p = mon->get_quorum().begin(); p != mon->get_quorum().end(); ++p) { if (*p == mon->rank) continue; dout(10) << " sending begin to mon." << *p << dendl; MMonPaxos *begin = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_BEGIN, ceph_clock_now(g_ceph_context)); begin->values[last_committed+1] = new_value; begin->last_committed = last_committed; begin->pn = accepted_pn; mon->messenger->send_message(begin, mon->monmap->get_inst(*p)); } // set timeout event accept_timeout_event = new C_AcceptTimeout(this); mon->timer.add_event_after(g_conf->mon_accept_timeout, accept_timeout_event); } // peon void Paxos::handle_begin(MMonPaxos *begin) { dout(10) << "handle_begin " << *begin << dendl; // can we accept this? if (begin->pn < accepted_pn) { dout(10) << " we accepted a higher pn " << accepted_pn << ", ignoring" << dendl; begin->put(); return; } assert(begin->pn == accepted_pn); assert(begin->last_committed == last_committed); assert(g_conf->paxos_kill_at != 4); logger->inc(l_paxos_begin); // set state. state = STATE_UPDATING; lease_expire = utime_t(); // cancel lease // yes. version_t v = last_committed+1; dout(10) << "accepting value for " << v << " pn " << accepted_pn << dendl; // store the accepted value onto our store. We will have to decode it and // apply its transaction once we receive permission to commit. MonitorDBStore::Transaction t; t.put(get_name(), v, begin->values[v]); // note which pn this pending value is for. t.put(get_name(), "pending_v", v); t.put(get_name(), "pending_pn", accepted_pn); dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; logger->inc(l_paxos_begin_bytes, t.get_bytes()); utime_t start = ceph_clock_now(NULL); get_store()->apply_transaction(t); utime_t end = ceph_clock_now(NULL); logger->tinc(l_paxos_begin_latency, end - start); assert(g_conf->paxos_kill_at != 5); // reply MMonPaxos *accept = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_ACCEPT, ceph_clock_now(g_ceph_context)); accept->pn = accepted_pn; accept->last_committed = last_committed; mon->messenger->send_message(accept, begin->get_source_inst()); begin->put(); } // leader void Paxos::handle_accept(MMonPaxos *accept) { dout(10) << "handle_accept " << *accept << dendl; int from = accept->get_source().num(); if (accept->pn != accepted_pn) { // we accepted a higher pn, from some other leader dout(10) << " we accepted a higher pn " << accepted_pn << ", ignoring" << dendl; goto out; } if (last_committed > 0 && accept->last_committed < last_committed-1) { dout(10) << " this is from an old round, ignoring" << dendl; goto out; } assert(accept->last_committed == last_committed || // not committed accept->last_committed == last_committed-1); // committed assert(is_updating() || is_updating_previous()); assert(accepted.count(from) == 0); accepted.insert(from); dout(10) << " now " << accepted << " have accepted" << dendl; assert(g_conf->paxos_kill_at != 6); // only commit (and expose committed state) when we get *all* quorum // members to accept. otherwise, they may still be sharing the now // stale state. // FIXME: we can improve this with an additional lease revocation message // that doesn't block for the persist. if (accepted == mon->get_quorum()) { // yay, commit! dout(10) << " got majority, committing, done with update" << dendl; commit(); if (!do_refresh()) goto out; if (is_updating()) commit_proposal(); finish_contexts(g_ceph_context, waiting_for_commit); // cancel timeout event mon->timer.cancel_event(accept_timeout_event); accept_timeout_event = 0; // yay! extend_lease(); assert(g_conf->paxos_kill_at != 10); finish_round(); // wake people up finish_contexts(g_ceph_context, waiting_for_active); finish_contexts(g_ceph_context, waiting_for_readable); finish_contexts(g_ceph_context, waiting_for_writeable); } out: accept->put(); } void Paxos::accept_timeout() { dout(1) << "accept timeout, calling fresh election" << dendl; accept_timeout_event = 0; assert(mon->is_leader()); assert(is_updating() || is_updating_previous()); logger->inc(l_paxos_accept_timeout); mon->bootstrap(); } void Paxos::commit() { dout(10) << "commit " << last_committed+1 << dendl; // cancel lease - it was for the old value. // (this would only happen if message layer lost the 'begin', but // leader still got a majority and committed with out us.) lease_expire = utime_t(); // cancel lease assert(g_conf->paxos_kill_at != 7); MonitorDBStore::Transaction t; // commit locally last_committed++; last_commit_time = ceph_clock_now(g_ceph_context); t.put(get_name(), "last_committed", last_committed); // decode the value and apply its transaction to the store. // this value can now be read from last_committed. decode_append_transaction(t, new_value); dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; logger->inc(l_paxos_commit); logger->inc(l_paxos_commit_keys, t.get_keys()); logger->inc(l_paxos_commit_bytes, t.get_bytes()); utime_t start = ceph_clock_now(NULL); get_store()->apply_transaction(t); utime_t end = ceph_clock_now(NULL); logger->tinc(l_paxos_commit_latency, end - start); assert(g_conf->paxos_kill_at != 8); // refresh first_committed; this txn may have trimmed. first_committed = get_store()->get(get_name(), "first_committed"); _sanity_check_store(); // tell everyone for (set::const_iterator p = mon->get_quorum().begin(); p != mon->get_quorum().end(); ++p) { if (*p == mon->rank) continue; dout(10) << " sending commit to mon." << *p << dendl; MMonPaxos *commit = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_COMMIT, ceph_clock_now(g_ceph_context)); commit->values[last_committed] = new_value; commit->pn = accepted_pn; commit->last_committed = last_committed; mon->messenger->send_message(commit, mon->monmap->get_inst(*p)); } assert(g_conf->paxos_kill_at != 9); // get ready for a new round. new_value.clear(); remove_legacy_versions(); } void Paxos::handle_commit(MMonPaxos *commit) { dout(10) << "handle_commit on " << commit->last_committed << dendl; logger->inc(l_paxos_commit); if (!mon->is_peon()) { dout(10) << "not a peon, dropping" << dendl; assert(0); commit->put(); return; } store_state(commit); if (do_refresh()) { finish_contexts(g_ceph_context, waiting_for_commit); } commit->put(); } void Paxos::extend_lease() { assert(mon->is_leader()); //assert(is_active()); lease_expire = ceph_clock_now(g_ceph_context); lease_expire += g_conf->mon_lease; acked_lease.clear(); acked_lease.insert(mon->rank); dout(7) << "extend_lease now+" << g_conf->mon_lease << " (" << lease_expire << ")" << dendl; // bcast for (set::const_iterator p = mon->get_quorum().begin(); p != mon->get_quorum().end(); ++p) { if (*p == mon->rank) continue; MMonPaxos *lease = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_LEASE, ceph_clock_now(g_ceph_context)); lease->last_committed = last_committed; lease->lease_timestamp = lease_expire; lease->first_committed = first_committed; mon->messenger->send_message(lease, mon->monmap->get_inst(*p)); } // set timeout event. // if old timeout is still in place, leave it. if (!lease_ack_timeout_event) { lease_ack_timeout_event = new C_LeaseAckTimeout(this); mon->timer.add_event_after(g_conf->mon_lease_ack_timeout, lease_ack_timeout_event); } // set renew event lease_renew_event = new C_LeaseRenew(this); utime_t at = lease_expire; at -= g_conf->mon_lease; at += g_conf->mon_lease_renew_interval; mon->timer.add_event_at(at, lease_renew_event); } void Paxos::warn_on_future_time(utime_t t, entity_name_t from) { utime_t now = ceph_clock_now(g_ceph_context); if (t > now) { utime_t diff = t - now; if (diff > g_conf->mon_clock_drift_allowed) { utime_t warn_diff = now - last_clock_drift_warn; if (warn_diff > pow(g_conf->mon_clock_drift_warn_backoff, clock_drift_warned)) { mon->clog.warn() << "message from " << from << " was stamped " << diff << "s in the future, clocks not synchronized"; last_clock_drift_warn = ceph_clock_now(g_ceph_context); ++clock_drift_warned; } } } } bool Paxos::do_refresh() { bool need_bootstrap = false; utime_t start = ceph_clock_now(NULL); // make sure we have the latest state loaded up mon->refresh_from_paxos(&need_bootstrap); utime_t end = ceph_clock_now(NULL); logger->inc(l_paxos_refresh); logger->tinc(l_paxos_refresh_latency, end - start); if (need_bootstrap) { dout(10) << " doing requested bootstrap" << dendl; mon->bootstrap(); return false; } return true; } void Paxos::commit_proposal() { dout(10) << __func__ << dendl; assert(mon->is_leader()); assert(!proposals.empty()); assert(is_updating()); C_Proposal *proposal = static_cast(proposals.front()); assert(proposal->proposed); dout(10) << __func__ << " proposal " << proposal << " took " << (ceph_clock_now(NULL) - proposal->proposal_time) << " to finish" << dendl; proposals.pop_front(); proposal->complete(0); } void Paxos::finish_round() { assert(mon->is_leader()); // ok, now go active! state = STATE_ACTIVE; dout(10) << __func__ << " state " << state << " proposals left " << proposals.size() << dendl; if (should_trim()) { trim(); } if (is_active() && !proposals.empty()) { propose_queued(); } } // peon void Paxos::handle_lease(MMonPaxos *lease) { // sanity if (!mon->is_peon() || last_committed != lease->last_committed) { dout(10) << "handle_lease i'm not a peon, or they're not the leader," << " or the last_committed doesn't match, dropping" << dendl; lease->put(); return; } warn_on_future_time(lease->sent_timestamp, lease->get_source()); // extend lease if (lease_expire < lease->lease_timestamp) { lease_expire = lease->lease_timestamp; utime_t now = ceph_clock_now(g_ceph_context); if (lease_expire < now) { utime_t diff = now - lease_expire; derr << "lease_expire from " << lease->get_source_inst() << " is " << diff << " seconds in the past; mons are probably laggy (or possibly clocks are too skewed)" << dendl; } } state = STATE_ACTIVE; dout(10) << "handle_lease on " << lease->last_committed << " now " << lease_expire << dendl; // ack MMonPaxos *ack = new MMonPaxos(mon->get_epoch(), MMonPaxos::OP_LEASE_ACK, ceph_clock_now(g_ceph_context)); ack->last_committed = last_committed; ack->first_committed = first_committed; ack->lease_timestamp = ceph_clock_now(g_ceph_context); mon->messenger->send_message(ack, lease->get_source_inst()); // (re)set timeout event. reset_lease_timeout(); // kick waiters finish_contexts(g_ceph_context, waiting_for_active); if (is_readable()) finish_contexts(g_ceph_context, waiting_for_readable); lease->put(); } void Paxos::handle_lease_ack(MMonPaxos *ack) { int from = ack->get_source().num(); if (!lease_ack_timeout_event) { dout(10) << "handle_lease_ack from " << ack->get_source() << " -- stray (probably since revoked)" << dendl; } else if (acked_lease.count(from) == 0) { acked_lease.insert(from); if (acked_lease == mon->get_quorum()) { // yay! dout(10) << "handle_lease_ack from " << ack->get_source() << " -- got everyone" << dendl; mon->timer.cancel_event(lease_ack_timeout_event); lease_ack_timeout_event = 0; } else { dout(10) << "handle_lease_ack from " << ack->get_source() << " -- still need " << mon->get_quorum().size() - acked_lease.size() << " more" << dendl; } } else { dout(10) << "handle_lease_ack from " << ack->get_source() << " dup (lagging!), ignoring" << dendl; } warn_on_future_time(ack->sent_timestamp, ack->get_source()); ack->put(); } void Paxos::lease_ack_timeout() { dout(1) << "lease_ack_timeout -- calling new election" << dendl; assert(mon->is_leader()); assert(is_active()); logger->inc(l_paxos_lease_ack_timeout); lease_ack_timeout_event = 0; mon->bootstrap(); } void Paxos::reset_lease_timeout() { dout(20) << "reset_lease_timeout - setting timeout event" << dendl; if (lease_timeout_event) mon->timer.cancel_event(lease_timeout_event); lease_timeout_event = new C_LeaseTimeout(this); mon->timer.add_event_after(g_conf->mon_lease_ack_timeout, lease_timeout_event); } void Paxos::lease_timeout() { dout(1) << "lease_timeout -- calling new election" << dendl; assert(mon->is_peon()); logger->inc(l_paxos_lease_timeout); lease_timeout_event = 0; mon->bootstrap(); } void Paxos::lease_renew_timeout() { lease_renew_event = 0; extend_lease(); } /* * trim old states */ void Paxos::trim() { assert(should_trim()); version_t end = MIN(get_version() - g_conf->paxos_min, get_first_committed() + g_conf->paxos_trim_max); if (first_committed >= end) return; dout(10) << "trim to " << end << " (was " << first_committed << ")" << dendl; MonitorDBStore::Transaction t; for (version_t v = first_committed; v < end; ++v) { dout(10) << "trim " << v << dendl; t.erase(get_name(), v); } t.put(get_name(), "first_committed", end); if (g_conf->mon_compact_on_trim) { dout(10) << " compacting trimmed range" << dendl; t.compact_range(get_name(), stringify(first_committed - 1), stringify(end)); } dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; bufferlist bl; t.encode(bl); trimming = true; queue_proposal(bl, new C_Trimmed(this)); } /* * return a globally unique, monotonically increasing proposal number */ version_t Paxos::get_new_proposal_number(version_t gt) { if (last_pn < gt) last_pn = gt; // update. make it unique among all monitors. last_pn /= 100; last_pn++; last_pn *= 100; last_pn += (version_t)mon->rank; // write MonitorDBStore::Transaction t; t.put(get_name(), "last_pn", last_pn); dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; logger->inc(l_paxos_new_pn); utime_t start = ceph_clock_now(NULL); get_store()->apply_transaction(t); utime_t end = ceph_clock_now(NULL); logger->tinc(l_paxos_new_pn_latency, end - start); dout(10) << "get_new_proposal_number = " << last_pn << dendl; return last_pn; } void Paxos::cancel_events() { if (collect_timeout_event) { mon->timer.cancel_event(collect_timeout_event); collect_timeout_event = 0; } if (accept_timeout_event) { mon->timer.cancel_event(accept_timeout_event); accept_timeout_event = 0; } if (lease_renew_event) { mon->timer.cancel_event(lease_renew_event); lease_renew_event = 0; } if (lease_ack_timeout_event) { mon->timer.cancel_event(lease_ack_timeout_event); lease_ack_timeout_event = 0; } if (lease_timeout_event) { mon->timer.cancel_event(lease_timeout_event); lease_timeout_event = 0; } } void Paxos::shutdown() { dout(10) << __func__ << " cancel all contexts" << dendl; finish_contexts(g_ceph_context, waiting_for_writeable, -ECANCELED); finish_contexts(g_ceph_context, waiting_for_commit, -ECANCELED); finish_contexts(g_ceph_context, waiting_for_readable, -ECANCELED); finish_contexts(g_ceph_context, waiting_for_active, -ECANCELED); finish_contexts(g_ceph_context, proposals, -ECANCELED); if (logger) g_ceph_context->get_perfcounters_collection()->remove(logger); delete logger; } void Paxos::leader_init() { cancel_events(); new_value.clear(); finish_contexts(g_ceph_context, proposals, -EAGAIN); logger->inc(l_paxos_start_leader); if (mon->get_quorum().size() == 1) { state = STATE_ACTIVE; return; } state = STATE_RECOVERING; lease_expire = utime_t(); dout(10) << "leader_init -- starting paxos recovery" << dendl; collect(0); } void Paxos::peon_init() { cancel_events(); new_value.clear(); state = STATE_RECOVERING; lease_expire = utime_t(); dout(10) << "peon_init -- i am a peon" << dendl; // start a timer, in case the leader never manages to issue a lease reset_lease_timeout(); // no chance to write now! finish_contexts(g_ceph_context, waiting_for_writeable, -EAGAIN); finish_contexts(g_ceph_context, waiting_for_commit, -EAGAIN); finish_contexts(g_ceph_context, proposals, -EAGAIN); logger->inc(l_paxos_start_peon); } void Paxos::restart() { dout(10) << "restart -- canceling timeouts" << dendl; cancel_events(); new_value.clear(); state = STATE_RECOVERING; finish_contexts(g_ceph_context, proposals, -EAGAIN); finish_contexts(g_ceph_context, waiting_for_commit, -EAGAIN); finish_contexts(g_ceph_context, waiting_for_active, -EAGAIN); logger->inc(l_paxos_restart); } void Paxos::dispatch(PaxosServiceMessage *m) { // election in progress? if (!mon->is_leader() && !mon->is_peon()) { dout(5) << "election in progress, dropping " << *m << dendl; m->put(); return; } // check sanity assert(mon->is_leader() || (mon->is_peon() && m->get_source().num() == mon->get_leader())); switch (m->get_type()) { case MSG_MON_PAXOS: { MMonPaxos *pm = (MMonPaxos*)m; // NOTE: these ops are defined in messages/MMonPaxos.h switch (pm->op) { // learner case MMonPaxos::OP_COLLECT: handle_collect(pm); break; case MMonPaxos::OP_LAST: handle_last(pm); break; case MMonPaxos::OP_BEGIN: handle_begin(pm); break; case MMonPaxos::OP_ACCEPT: handle_accept(pm); break; case MMonPaxos::OP_COMMIT: handle_commit(pm); break; case MMonPaxos::OP_LEASE: handle_lease(pm); break; case MMonPaxos::OP_LEASE_ACK: handle_lease_ack(pm); break; default: assert(0); } } break; default: assert(0); } } // ----------------- // service interface // -- READ -- bool Paxos::is_readable(version_t v) { dout(5) << "is_readable now=" << ceph_clock_now(g_ceph_context) << " lease_expire=" << lease_expire << " has v" << v << " lc " << last_committed << dendl; if (v > last_committed) return false; return (mon->is_peon() || mon->is_leader()) && (is_active() || is_updating()) && last_committed > 0 && // must have a value (mon->get_quorum().size() == 1 || // alone, or is_lease_valid()); // have lease } bool Paxos::read(version_t v, bufferlist &bl) { if (!get_store()->get(get_name(), v, bl)) return false; return true; } version_t Paxos::read_current(bufferlist &bl) { if (read(last_committed, bl)) return last_committed; return 0; } bool Paxos::is_lease_valid() { return ((mon->get_quorum().size() == 1) || (ceph_clock_now(g_ceph_context) < lease_expire)); } // -- WRITE -- bool Paxos::is_writeable() { return mon->is_leader() && is_active() && is_lease_valid(); } void Paxos::list_proposals(ostream& out) { out << __func__ << " " << proposals.size() << " in queue:\n"; list::iterator p_it = proposals.begin(); for (int i = 0; p_it != proposals.end(); ++p_it, ++i) { C_Proposal *p = (C_Proposal*) *p_it; out << "-- entry #" << i << "\n"; out << *p << "\n"; } } void Paxos::propose_queued() { assert(is_active()); assert(!proposals.empty()); C_Proposal *proposal = static_cast(proposals.front()); assert(!proposal->proposed); cancel_events(); dout(10) << __func__ << " " << (last_committed + 1) << " " << proposal->bl.length() << " bytes" << dendl; proposal->proposed = true; dout(30) << __func__ << " "; list_proposals(*_dout); *_dout << dendl; state = STATE_UPDATING; begin(proposal->bl); } void Paxos::queue_proposal(bufferlist& bl, Context *onfinished) { dout(5) << __func__ << " bl " << bl.length() << " bytes;" << " ctx = " << onfinished << dendl; proposals.push_back(new C_Proposal(onfinished, bl)); } bool Paxos::propose_new_value(bufferlist& bl, Context *onfinished) { assert(mon->is_leader()); queue_proposal(bl, onfinished); if (!is_active()) { dout(5) << __func__ << " not active; proposal queued" << dendl; return true; } propose_queued(); return true; } bool Paxos::is_consistent() { return (first_committed <= last_committed); } ceph-0.80.11/src/mon/AuthMonitor.cc0000664000175100017510000007316312623076744021047 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "mon/AuthMonitor.h" #include "mon/Monitor.h" #include "mon/MonitorDBStore.h" #include "messages/MMonCommand.h" #include "messages/MAuth.h" #include "messages/MAuthReply.h" #include "messages/MMonGlobalID.h" #include "include/str_list.h" #include "common/Timer.h" #include "auth/AuthServiceHandler.h" #include "auth/KeyRing.h" #include "osd/osd_types.h" #include "common/config.h" #include "include/assert.h" #include "common/cmdparse.h" #include "include/str_list.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, get_last_committed()) static ostream& _prefix(std::ostream *_dout, Monitor *mon, version_t v) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").auth v" << v << " "; } ostream& operator<<(ostream& out, AuthMonitor& pm) { return out << "auth"; } bool AuthMonitor::check_rotate() { KeyServerData::Incremental rot_inc; rot_inc.op = KeyServerData::AUTH_INC_SET_ROTATING; if (!mon->key_server.updated_rotating(rot_inc.rotating_bl, last_rotating_ver)) return false; dout(10) << __func__ << " updated rotating" << dendl; push_cephx_inc(rot_inc); return true; } /* Tick function to update the map based on performance every N seconds */ void AuthMonitor::tick() { if (!is_active()) return; dout(10) << *this << dendl; if (!mon->is_leader()) return; if (check_rotate()) propose_pending(); } void AuthMonitor::on_active() { dout(10) << "AuthMonitor::on_active()" << dendl; if (!mon->is_leader()) return; mon->key_server.start_server(); } void AuthMonitor::create_initial() { dout(10) << "create_initial -- creating initial map" << dendl; // initialize rotating keys last_rotating_ver = 0; check_rotate(); assert(pending_auth.size() == 1); if (mon->is_keyring_required()) { KeyRing keyring; bufferlist bl; int ret = mon->store->get("mkfs", "keyring", bl); assert(ret == 0); bufferlist::iterator p = bl.begin(); ::decode(keyring, p); import_keyring(keyring); } max_global_id = MIN_GLOBAL_ID; Incremental inc; inc.inc_type = GLOBAL_ID; inc.max_global_id = max_global_id; pending_auth.push_back(inc); format_version = 1; } void AuthMonitor::update_from_paxos(bool *need_bootstrap) { dout(10) << __func__ << dendl; version_t version = get_last_committed(); version_t keys_ver = mon->key_server.get_ver(); if (version == keys_ver) return; assert(version >= keys_ver); version_t latest_full = get_version_latest_full(); dout(10) << __func__ << " version " << version << " keys ver " << keys_ver << " latest " << latest_full << dendl; if ((latest_full > 0) && (latest_full > keys_ver)) { bufferlist latest_bl; int err = get_version_full(latest_full, latest_bl); assert(err == 0); assert(latest_bl.length() != 0); dout(7) << __func__ << " loading summary e " << latest_full << dendl; dout(7) << __func__ << " latest length " << latest_bl.length() << dendl; bufferlist::iterator p = latest_bl.begin(); __u8 struct_v; ::decode(struct_v, p); ::decode(max_global_id, p); ::decode(mon->key_server, p); mon->key_server.set_ver(latest_full); keys_ver = latest_full; } dout(10) << __func__ << " key server version " << mon->key_server.get_ver() << dendl; // walk through incrementals while (version > keys_ver) { bufferlist bl; int ret = get_version(keys_ver+1, bl); assert(ret == 0); assert(bl.length()); // reset if we are moving to initial state. we will normally have // keys in here temporarily for bootstrapping that we need to // clear out. if (keys_ver == 0) mon->key_server.clear_secrets(); dout(20) << __func__ << " walking through version " << (keys_ver+1) << " len " << bl.length() << dendl; bufferlist::iterator p = bl.begin(); __u8 v; ::decode(v, p); while (!p.end()) { Incremental inc; ::decode(inc, p); switch (inc.inc_type) { case GLOBAL_ID: max_global_id = inc.max_global_id; break; case AUTH_DATA: { KeyServerData::Incremental auth_inc; bufferlist::iterator iter = inc.auth_data.begin(); ::decode(auth_inc, iter); mon->key_server.apply_data_incremental(auth_inc); break; } } } keys_ver++; mon->key_server.set_ver(keys_ver); if (keys_ver == 1 && mon->is_keyring_required()) { MonitorDBStore::Transaction t; t.erase("mkfs", "keyring"); mon->store->apply_transaction(t); } } if (last_allocated_id == 0) last_allocated_id = max_global_id; dout(10) << "update_from_paxos() last_allocated_id=" << last_allocated_id << " max_global_id=" << max_global_id << " format_version " << format_version << dendl; } void AuthMonitor::increase_max_global_id() { assert(mon->is_leader()); max_global_id += g_conf->mon_globalid_prealloc; dout(10) << "increasing max_global_id to " << max_global_id << dendl; Incremental inc; inc.inc_type = GLOBAL_ID; inc.max_global_id = max_global_id; pending_auth.push_back(inc); } bool AuthMonitor::should_propose(double& delay) { return (!pending_auth.empty()); } void AuthMonitor::create_pending() { pending_auth.clear(); dout(10) << "create_pending v " << (get_last_committed() + 1) << dendl; } void AuthMonitor::encode_pending(MonitorDBStore::Transaction *t) { dout(10) << __func__ << " v " << (get_last_committed() + 1) << dendl; bufferlist bl; __u8 v = 1; ::encode(v, bl); vector::iterator p; for (p = pending_auth.begin(); p != pending_auth.end(); ++p) p->encode(bl, mon->get_quorum_features()); version_t version = get_last_committed() + 1; put_version(t, version, bl); put_last_committed(t, version); } void AuthMonitor::encode_full(MonitorDBStore::Transaction *t) { version_t version = mon->key_server.get_ver(); // do not stash full version 0 as it will never be removed nor read if (version == 0) return; dout(10) << __func__ << " auth v " << version << dendl; assert(get_last_committed() == version); bufferlist full_bl; Mutex::Locker l(mon->key_server.get_lock()); dout(20) << __func__ << " key server has " << (mon->key_server.has_secrets() ? "" : "no ") << "secrets!" << dendl; __u8 v = 1; ::encode(v, full_bl); ::encode(max_global_id, full_bl); ::encode(mon->key_server, full_bl); put_version_full(t, version, full_bl); put_version_latest_full(t, version); } version_t AuthMonitor::get_trim_to() { unsigned max = g_conf->paxos_max_join_drift * 2; version_t version = get_last_committed(); if (mon->is_leader() && (version > max)) return version - max; return 0; } bool AuthMonitor::preprocess_query(PaxosServiceMessage *m) { dout(10) << "preprocess_query " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_MON_COMMAND: return preprocess_command((MMonCommand*)m); case CEPH_MSG_AUTH: return prep_auth((MAuth *)m, false); case MSG_MON_GLOBAL_ID: return false; default: assert(0); m->put(); return true; } } bool AuthMonitor::prepare_update(PaxosServiceMessage *m) { dout(10) << "prepare_update " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_MON_COMMAND: return prepare_command((MMonCommand*)m); case MSG_MON_GLOBAL_ID: return prepare_global_id((MMonGlobalID*)m); case CEPH_MSG_AUTH: return prep_auth((MAuth *)m, true); default: assert(0); m->put(); return false; } } uint64_t AuthMonitor::assign_global_id(MAuth *m, bool should_increase_max) { int total_mon = mon->monmap->size(); dout(10) << "AuthMonitor::assign_global_id m=" << *m << " mon=" << mon->rank << "/" << total_mon << " last_allocated=" << last_allocated_id << " max_global_id=" << max_global_id << dendl; uint64_t next_global_id = last_allocated_id + 1; int remainder = next_global_id % total_mon; if (remainder) remainder = total_mon - remainder; next_global_id += remainder + mon->rank; dout(10) << "next_global_id should be " << next_global_id << dendl; // if we can't bump the max, bail out now on an out-of-bounds gid if (next_global_id > max_global_id && (!mon->is_leader() || !should_increase_max)) { return 0; } // can we return a gid? bool return_next = (next_global_id <= max_global_id); // bump the max? while (mon->is_leader() && (max_global_id < g_conf->mon_globalid_prealloc || next_global_id >= max_global_id - g_conf->mon_globalid_prealloc / 2)) { increase_max_global_id(); } if (return_next) { last_allocated_id = next_global_id; return next_global_id; } else { return 0; } } bool AuthMonitor::prep_auth(MAuth *m, bool paxos_writable) { dout(10) << "prep_auth() blob_size=" << m->get_auth_payload().length() << dendl; MonSession *s = (MonSession *)m->get_connection()->get_priv(); if (!s) { dout(10) << "no session, dropping" << dendl; m->put(); return true; } int ret = 0; AuthCapsInfo caps_info; MAuthReply *reply; bufferlist response_bl; bufferlist::iterator indata = m->auth_payload.begin(); __u32 proto = m->protocol; bool start = false; EntityName entity_name; // set up handler? if (m->protocol == 0 && !s->auth_handler) { set<__u32> supported; try { __u8 struct_v = 1; ::decode(struct_v, indata); ::decode(supported, indata); ::decode(entity_name, indata); ::decode(s->global_id, indata); } catch (const buffer::error &e) { dout(10) << "failed to decode initial auth message" << dendl; ret = -EINVAL; goto reply; } // do we require cephx signatures? if (!m->get_connection()->has_feature(CEPH_FEATURE_MSG_AUTH)) { if (entity_name.get_type() == CEPH_ENTITY_TYPE_MON || entity_name.get_type() == CEPH_ENTITY_TYPE_OSD || entity_name.get_type() == CEPH_ENTITY_TYPE_MDS) { if (g_conf->cephx_cluster_require_signatures || g_conf->cephx_require_signatures) { dout(1) << m->get_source_inst() << " supports cephx but not signatures and" << " 'cephx [cluster] require signatures = true';" << " disallowing cephx" << dendl; supported.erase(CEPH_AUTH_CEPHX); } } else { if (g_conf->cephx_service_require_signatures || g_conf->cephx_require_signatures) { dout(1) << m->get_source_inst() << " supports cephx but not signatures and" << " 'cephx [service] require signatures = true';" << " disallowing cephx" << dendl; supported.erase(CEPH_AUTH_CEPHX); } } } int type; if (entity_name.get_type() == CEPH_ENTITY_TYPE_MON || entity_name.get_type() == CEPH_ENTITY_TYPE_OSD || entity_name.get_type() == CEPH_ENTITY_TYPE_MDS) type = mon->auth_cluster_required.pick(supported); else type = mon->auth_service_required.pick(supported); s->auth_handler = get_auth_service_handler(type, g_ceph_context, &mon->key_server); if (!s->auth_handler) { dout(1) << "client did not provide supported auth type" << dendl; ret = -ENOTSUP; goto reply; } start = true; } else if (!s->auth_handler) { dout(10) << "protocol specified but no s->auth_handler" << dendl; ret = -EINVAL; goto reply; } /* assign a new global_id? we assume this should only happen on the first request. If a client tries to send it later, it'll screw up its auth session */ if (!s->global_id) { s->global_id = assign_global_id(m, paxos_writable); if (!s->global_id) { delete s->auth_handler; s->auth_handler = NULL; if (mon->is_leader() && paxos_writable) { dout(10) << "increasing global id, waitlisting message" << dendl; wait_for_active(new C_RetryMessage(this, m)); goto done; } s->put(); if (!mon->is_leader()) { dout(10) << "not the leader, requesting more ids from leader" << dendl; int leader = mon->get_leader(); MMonGlobalID *req = new MMonGlobalID(); req->old_max_id = max_global_id; mon->messenger->send_message(req, mon->monmap->get_inst(leader)); wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } assert(!paxos_writable); return false; } } try { uint64_t auid = 0; if (start) { // new session // always send the latest monmap. if (m->monmap_epoch < mon->monmap->get_epoch()) mon->send_latest_monmap(m->get_connection().get()); proto = s->auth_handler->start_session(entity_name, indata, response_bl, caps_info); ret = 0; if (caps_info.allow_all) s->caps.set_allow_all(); } else { // request ret = s->auth_handler->handle_request(indata, response_bl, s->global_id, caps_info, &auid); } if (ret == -EIO) { wait_for_active(new C_RetryMessage(this,m)); goto done; } if (caps_info.caps.length()) { bufferlist::iterator p = caps_info.caps.begin(); string str; try { ::decode(str, p); } catch (const buffer::error &err) { derr << "corrupt cap data for " << entity_name << " in auth db" << dendl; str.clear(); } s->caps.parse(str, NULL); s->auid = auid; } } catch (const buffer::error &err) { ret = -EINVAL; dout(0) << "caught error when trying to handle auth request, probably malformed request" << dendl; } reply: reply = new MAuthReply(proto, &response_bl, ret, s->global_id); mon->send_reply(m, reply); m->put(); done: s->put(); return true; } bool AuthMonitor::preprocess_command(MMonCommand *m) { int r = -1; bufferlist rdata; stringstream ss, ds; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, rdata, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); if (prefix == "auth add" || prefix == "auth del" || prefix == "auth get-or-create" || prefix == "auth get-or-create-key" || prefix == "auth import" || prefix == "auth caps") { return false; } MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", rdata, get_last_committed()); return true; } // entity might not be supplied, but if it is, it should be valid string entity_name; cmd_getval(g_ceph_context, cmdmap, "entity", entity_name); EntityName entity; if (!entity_name.empty() && !entity.from_str(entity_name)) { ss << "invalid entity_auth " << entity_name; mon->reply_command(m, -EINVAL, ss.str(), get_last_committed()); return true; } string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); if (prefix == "auth export") { KeyRing keyring; export_keyring(keyring); if (!entity_name.empty()) { EntityAuth eauth; if (keyring.get_auth(entity, eauth)) { KeyRing kr; kr.add(entity, eauth); if (f) kr.encode_formatted("auth", f.get(), rdata); else kr.encode_plaintext(rdata); ss << "export " << eauth; r = 0; } else { ss << "no key for " << eauth; r = -ENOENT; } } else { if (f) keyring.encode_formatted("auth", f.get(), rdata); else keyring.encode_plaintext(rdata); ss << "exported master keyring"; r = 0; } } else if (prefix == "auth get" && !entity_name.empty()) { KeyRing keyring; EntityAuth entity_auth; if(!mon->key_server.get_auth(entity, entity_auth)) { ss << "failed to find " << entity_name << " in keyring"; r = -ENOENT; } else { keyring.add(entity, entity_auth); if (f) keyring.encode_formatted("auth", f.get(), rdata); else keyring.encode_plaintext(rdata); ss << "exported keyring for " << entity_name; r = 0; } } else if (prefix == "auth print-key" || prefix == "auth print_key" || prefix == "auth get-key") { EntityAuth auth; if (!mon->key_server.get_auth(entity, auth)) { ss << "don't have " << entity; r = -ENOENT; goto done; } if (f) { auth.key.encode_formatted("auth", f.get(), rdata); } else { auth.key.encode_plaintext(rdata); } r = 0; } else if (prefix == "auth list") { if (f) { mon->key_server.encode_formatted("auth", f.get(), rdata); } else { mon->key_server.encode_plaintext(rdata); if (rdata.length() > 0) ss << "installed auth entries:" << std::endl; else ss << "no installed auth entries!" << std::endl; } r = 0; goto done; } else { ss << "invalid command"; r = -EINVAL; } done: rdata.append(ds); string rs; getline(ss, rs, '\0'); mon->reply_command(m, r, rs, rdata, get_last_committed()); return true; } void AuthMonitor::export_keyring(KeyRing& keyring) { mon->key_server.export_keyring(keyring); } void AuthMonitor::import_keyring(KeyRing& keyring) { for (map::iterator p = keyring.get_keys().begin(); p != keyring.get_keys().end(); ++p) { KeyServerData::Incremental auth_inc; auth_inc.name = p->first; auth_inc.auth = p->second; auth_inc.op = KeyServerData::AUTH_INC_ADD; dout(10) << " importing " << auth_inc.name << dendl; dout(30) << " " << auth_inc.auth << dendl; push_cephx_inc(auth_inc); } } bool AuthMonitor::prepare_command(MMonCommand *m) { stringstream ss, ds; bufferlist rdata; string rs; int err = -EINVAL; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, rdata, get_last_committed()); return true; } string prefix; vectorcaps_vec; string entity_name; EntityName entity; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", rdata, get_last_committed()); return true; } cmd_getval(g_ceph_context, cmdmap, "caps", caps_vec); if ((caps_vec.size() % 2) != 0) { ss << "bad capabilities request; odd number of arguments"; err = -EINVAL; goto done; } cmd_getval(g_ceph_context, cmdmap, "entity", entity_name); if (!entity_name.empty() && !entity.from_str(entity_name)) { ss << "bad entity name"; err = -EINVAL; goto done; } if (prefix == "auth import") { bufferlist bl = m->get_data(); if (bl.length() == 0) { ss << "auth import: no data supplied"; getline(ss, rs); mon->reply_command(m, -EINVAL, rs, get_last_committed()); return true; } bufferlist::iterator iter = bl.begin(); KeyRing keyring; try { ::decode(keyring, iter); } catch (const buffer::error &ex) { ss << "error decoding keyring" << " " << ex.what(); rs = err; goto done; } import_keyring(keyring); ss << "imported keyring"; getline(ss, rs); err = 0; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "auth add" && !entity_name.empty()) { /* expected behavior: * - if command reproduces current state, return 0. * - if command adds brand new entity, handle it. * - if command adds new state to existing entity, return error. */ KeyServerData::Incremental auth_inc; auth_inc.name = entity; bufferlist bl = m->get_data(); bool has_keyring = (bl.length() > 0); map new_caps; KeyRing new_keyring; if (has_keyring) { bufferlist::iterator iter = bl.begin(); try { ::decode(new_keyring, iter); } catch (const buffer::error &ex) { ss << "error decoding keyring"; err = -EINVAL; goto done; } } // are we about to have it? for (vector::iterator p = pending_auth.begin(); p != pending_auth.end(); ++p) { if (p->inc_type == AUTH_DATA) { KeyServerData::Incremental inc; bufferlist::iterator q = p->auth_data.begin(); ::decode(inc, q); if (inc.op == KeyServerData::AUTH_INC_ADD && inc.name == entity) { wait_for_finished_proposal( new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } } // build new caps from provided arguments (if available) for (vector::iterator it = caps_vec.begin(); it != caps_vec.end() && (it + 1) != caps_vec.end(); it += 2) { string sys = *it; bufferlist cap; ::encode(*(it+1), cap); new_caps[sys] = cap; } // pull info out of provided keyring EntityAuth new_inc; if (has_keyring) { if (!new_keyring.get_auth(auth_inc.name, new_inc)) { ss << "key for " << auth_inc.name << " not found in provided keyring"; err = -EINVAL; goto done; } if (!new_caps.empty() && !new_inc.caps.empty()) { ss << "caps cannot be specified both in keyring and in command"; err = -EINVAL; goto done; } if (new_caps.empty()) { new_caps = new_inc.caps; } } // does entry already exist? if (mon->key_server.get_auth(auth_inc.name, auth_inc.auth)) { // key match? if (has_keyring) { if (auth_inc.auth.key.get_secret().cmp(new_inc.key.get_secret())) { ss << "entity " << auth_inc.name << " exists but key does not match"; err = -EINVAL; goto done; } } // caps match? if (new_caps.size() != auth_inc.auth.caps.size()) { ss << "entity " << auth_inc.name << " exists but caps do not match"; err = -EINVAL; goto done; } for (map::iterator it = new_caps.begin(); it != new_caps.end(); ++it) { if (auth_inc.auth.caps.count(it->first) == 0 || !auth_inc.auth.caps[it->first].contents_equal(it->second)) { ss << "entity " << auth_inc.name << " exists but cap " << it->first << " does not match"; err = -EINVAL; goto done; } } // they match, no-op err = 0; goto done; } // okay, add it. auth_inc.op = KeyServerData::AUTH_INC_ADD; auth_inc.auth.caps = new_caps; if (has_keyring) { auth_inc.auth.key = new_inc.key; } else { dout(10) << "AuthMonitor::prepare_command generating random key for " << auth_inc.name << dendl; auth_inc.auth.key.create(g_ceph_context, CEPH_CRYPTO_AES); } dout(10) << " importing " << auth_inc.name << dendl; dout(30) << " " << auth_inc.auth << dendl; push_cephx_inc(auth_inc); ss << "added key for " << auth_inc.name; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if ((prefix == "auth get-or-create-key" || prefix == "auth get-or-create") && !entity_name.empty()) { // auth get-or-create [mon osdcapa osd osdcapb ...] // do we have it? EntityAuth entity_auth; if (mon->key_server.get_auth(entity, entity_auth)) { for (vector::iterator it = caps_vec.begin(); it != caps_vec.end(); it += 2) { string sys = *it; bufferlist cap; ::encode(*(it+1), cap); if (entity_auth.caps.count(sys) == 0 || !entity_auth.caps[sys].contents_equal(cap)) { ss << "key for " << entity << " exists but cap " << sys << " does not match"; err = -EINVAL; goto done; } } if (prefix == "auth get-or-create-key") { if (f) { entity_auth.key.encode_formatted("auth", f.get(), rdata); } else { ds << entity_auth.key; } } else { KeyRing kr; kr.add(entity, entity_auth.key); if (f) { kr.encode_formatted("auth", f.get(), rdata); } else { kr.encode_plaintext(rdata); } } err = 0; goto done; } // ...or are we about to? for (vector::iterator p = pending_auth.begin(); p != pending_auth.end(); ++p) { if (p->inc_type == AUTH_DATA) { KeyServerData::Incremental auth_inc; bufferlist::iterator q = p->auth_data.begin(); ::decode(auth_inc, q); if (auth_inc.op == KeyServerData::AUTH_INC_ADD && auth_inc.name == entity) { wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } } // create it KeyServerData::Incremental auth_inc; auth_inc.op = KeyServerData::AUTH_INC_ADD; auth_inc.name = entity; auth_inc.auth.key.create(g_ceph_context, CEPH_CRYPTO_AES); for (vector::iterator it = caps_vec.begin(); it != caps_vec.end(); it += 2) ::encode(*(it+1), auth_inc.auth.caps[*it]); push_cephx_inc(auth_inc); if (prefix == "auth get-or-create-key") { if (f) { auth_inc.auth.key.encode_formatted("auth", f.get(), rdata); } else { ds << auth_inc.auth.key; } } else { KeyRing kr; kr.add(entity, auth_inc.auth.key); if (f) { kr.encode_formatted("auth", f.get(), rdata); } else { kr.encode_plaintext(rdata); } } rdata.append(ds); getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, rdata, get_last_committed() + 1)); return true; } else if (prefix == "auth caps" && !entity_name.empty()) { KeyServerData::Incremental auth_inc; auth_inc.name = entity; if (!mon->key_server.get_auth(auth_inc.name, auth_inc.auth)) { ss << "couldn't find entry " << auth_inc.name; err = -ENOENT; goto done; } map newcaps; for (vector::iterator it = caps_vec.begin(); it != caps_vec.end(); it += 2) ::encode(*(it+1), newcaps[*it]); auth_inc.op = KeyServerData::AUTH_INC_ADD; auth_inc.auth.caps = newcaps; push_cephx_inc(auth_inc); ss << "updated caps for " << auth_inc.name; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "auth del" && !entity_name.empty()) { KeyServerData::Incremental auth_inc; auth_inc.name = entity; if (!mon->key_server.contains(auth_inc.name)) { ss << "entity " << entity << " does not exist"; err = 0; goto done; } auth_inc.op = KeyServerData::AUTH_INC_DEL; push_cephx_inc(auth_inc); ss << "updated"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } done: rdata.append(ds); getline(ss, rs, '\0'); mon->reply_command(m, err, rs, rdata, get_last_committed()); return false; } bool AuthMonitor::prepare_global_id(MMonGlobalID *m) { dout(10) << "AuthMonitor::prepare_global_id" << dendl; increase_max_global_id(); m->put(); return true; } void AuthMonitor::upgrade_format() { unsigned int current = 1; if (format_version >= current) { dout(20) << __func__ << " format " << format_version << " is current" << dendl; return; } dout(1) << __func__ << " upgrading from format " << format_version << " to " << current << dendl; bool changed = false; map::iterator p; for (p = mon->key_server.secrets_begin(); p != mon->key_server.secrets_end(); ++p) { // grab mon caps, if any string mon_caps; if (p->second.caps.count("mon") == 0) continue; try { bufferlist::iterator it = p->second.caps["mon"].begin(); ::decode(mon_caps, it); } catch (buffer::error) { dout(10) << __func__ << " unable to parse mon cap for " << p->first << dendl; continue; } string n = p->first.to_str(); string new_caps; // set daemon profiles if ((p->first.is_osd() || p->first.is_mds()) && mon_caps == "allow rwx") { new_caps = string("allow profile ") + string(p->first.get_type_name()); } // update bootstrap keys if (n == "client.bootstrap-osd") { new_caps = "allow profile bootstrap-osd"; } if (n == "client.bootstrap-mds") { new_caps = "allow profile bootstrap-mds"; } if (new_caps.length() > 0) { dout(5) << __func__ << " updating " << p->first << " mon cap from " << mon_caps << " to " << new_caps << dendl; bufferlist bl; ::encode(new_caps, bl); KeyServerData::Incremental auth_inc; auth_inc.name = p->first; auth_inc.auth = p->second; auth_inc.auth.caps["mon"] = bl; auth_inc.op = KeyServerData::AUTH_INC_ADD; push_cephx_inc(auth_inc); changed = true; } } if (changed) { // note new format dout(10) << __func__ << " proposing update from format " << format_version << " -> " << current << dendl; format_version = current; propose_pending(); } } void AuthMonitor::dump_info(Formatter *f) { /*** WARNING: do not include any privileged information here! ***/ f->open_object_section("auth"); f->dump_unsigned("first_committed", get_first_committed()); f->dump_unsigned("last_committed", get_last_committed()); f->dump_unsigned("num_secrets", mon->key_server.get_num_secrets()); f->close_section(); } ceph-0.80.11/src/mon/LogMonitor.cc0000664000175100017510000003420612623076744020662 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include "LogMonitor.h" #include "Monitor.h" #include "MonitorDBStore.h" #include "messages/MMonCommand.h" #include "messages/MLog.h" #include "messages/MLogAck.h" #include "common/Timer.h" #include "osd/osd_types.h" #include "common/errno.h" #include "common/config.h" #include "include/assert.h" #include "include/str_list.h" #include "include/compat.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, get_last_committed()) static ostream& _prefix(std::ostream *_dout, Monitor *mon, version_t v) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").log v" << v << " "; } ostream& operator<<(ostream& out, LogMonitor& pm) { /* std::stringstream ss; for (ceph::unordered_map::iterator p = pm.pg_map.num_pg_by_state.begin(); p != pm.pg_map.num_pg_by_state.end(); ++p) { if (p != pm.pg_map.num_pg_by_state.begin()) ss << ", "; ss << p->second << " " << pg_state_string(p->first); } string states = ss.str(); return out << "v" << pm.pg_map.version << ": " << pm.pg_map.pg_stat.size() << " pgs: " << states << "; " << kb_t(pm.pg_map.total_pg_kb()) << " data, " << kb_t(pm.pg_map.total_used_kb()) << " used, " << kb_t(pm.pg_map.total_avail_kb()) << " / " << kb_t(pm.pg_map.total_kb()) << " free"; */ return out << "log"; } /* Tick function to update the map based on performance every N seconds */ void LogMonitor::tick() { if (!is_active()) return; dout(10) << *this << dendl; if (!mon->is_leader()) return; } void LogMonitor::create_initial() { dout(10) << "create_initial -- creating initial map" << dendl; LogEntry e; memset(&e.who, 0, sizeof(e.who)); e.stamp = ceph_clock_now(g_ceph_context); e.type = CLOG_INFO; std::stringstream ss; ss << "mkfs " << mon->monmap->get_fsid(); e.msg = ss.str(); e.seq = 0; pending_log.insert(pair(e.stamp, e)); } void LogMonitor::update_from_paxos(bool *need_bootstrap) { dout(10) << __func__ << dendl; version_t version = get_last_committed(); dout(10) << __func__ << " version " << version << " summary v " << summary.version << dendl; if (version == summary.version) return; assert(version >= summary.version); bufferlist blog; version_t latest_full = get_version_latest_full(); dout(10) << __func__ << " latest full " << latest_full << dendl; if ((latest_full > 0) && (latest_full > summary.version)) { bufferlist latest_bl; get_version_full(latest_full, latest_bl); assert(latest_bl.length() != 0); dout(7) << __func__ << " loading summary e" << latest_full << dendl; bufferlist::iterator p = latest_bl.begin(); ::decode(summary, p); dout(7) << __func__ << " loaded summary e" << summary.version << dendl; } // walk through incrementals while (version > summary.version) { bufferlist bl; int err = get_version(summary.version+1, bl); assert(err == 0); assert(bl.length()); bufferlist::iterator p = bl.begin(); __u8 v; ::decode(v, p); while (!p.end()) { LogEntry le; le.decode(p); dout(7) << "update_from_paxos applying incremental log " << summary.version+1 << " " << le << dendl; if (g_conf->mon_cluster_log_to_syslog) { le.log_to_syslog(g_conf->mon_cluster_log_to_syslog_level, g_conf->mon_cluster_log_to_syslog_facility); } if (g_conf->mon_cluster_log_file.length()) { int min = string_to_syslog_level(g_conf->mon_cluster_log_file_level); int l = clog_type_to_syslog_level(le.type); if (l <= min) { stringstream ss; ss << le << "\n"; blog.append(ss.str()); } } summary.add(le); } summary.version++; } if (blog.length()) { int fd = ::open(g_conf->mon_cluster_log_file.c_str(), O_WRONLY|O_APPEND|O_CREAT, 0600); if (fd < 0) { int err = -errno; dout(1) << "unable to write to " << g_conf->mon_cluster_log_file << ": " << cpp_strerror(err) << dendl; } else { int err = blog.write_fd(fd); if (err < 0) { dout(1) << "error writing to " << g_conf->mon_cluster_log_file << ": " << cpp_strerror(err) << dendl; } VOID_TEMP_FAILURE_RETRY(::close(fd)); } } check_subs(); } void LogMonitor::store_do_append(MonitorDBStore::Transaction *t, const string& key, bufferlist& bl) { bufferlist existing_bl; int err = get_value(key, existing_bl); assert(err == 0); existing_bl.append(bl); put_value(t, key, existing_bl); } void LogMonitor::create_pending() { pending_log.clear(); pending_summary = summary; dout(10) << "create_pending v " << (get_last_committed() + 1) << dendl; } void LogMonitor::encode_pending(MonitorDBStore::Transaction *t) { version_t version = get_last_committed() + 1; bufferlist bl; dout(10) << __func__ << " v" << version << dendl; __u8 v = 1; ::encode(v, bl); multimap::iterator p; for (p = pending_log.begin(); p != pending_log.end(); ++p) p->second.encode(bl); put_version(t, version, bl); put_last_committed(t, version); } void LogMonitor::encode_full(MonitorDBStore::Transaction *t) { dout(10) << __func__ << " log v " << summary.version << dendl; assert(get_last_committed() == summary.version); bufferlist summary_bl; ::encode(summary, summary_bl); put_version_full(t, summary.version, summary_bl); put_version_latest_full(t, summary.version); } version_t LogMonitor::get_trim_to() { unsigned max = g_conf->mon_max_log_epochs; version_t version = get_last_committed(); if (mon->is_leader() && version > max) return version - max; return 0; } bool LogMonitor::preprocess_query(PaxosServiceMessage *m) { dout(10) << "preprocess_query " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_MON_COMMAND: return preprocess_command(static_cast(m)); case MSG_LOG: return preprocess_log((MLog*)m); default: assert(0); m->put(); return true; } } bool LogMonitor::prepare_update(PaxosServiceMessage *m) { dout(10) << "prepare_update " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_MON_COMMAND: return prepare_command(static_cast(m)); case MSG_LOG: return prepare_log((MLog*)m); default: assert(0); m->put(); return false; } } bool LogMonitor::preprocess_log(MLog *m) { dout(10) << "preprocess_log " << *m << " from " << m->get_orig_source() << dendl; int num_new = 0; MonSession *session = m->get_session(); if (!session) goto done; if (!session->is_capable("log", MON_CAP_W)) { dout(0) << "preprocess_log got MLog from entity with insufficient privileges " << session->caps << dendl; goto done; } for (deque::iterator p = m->entries.begin(); p != m->entries.end(); ++p) { if (!pending_summary.contains(p->key())) num_new++; } if (!num_new) { dout(10) << " nothing new" << dendl; goto done; } return false; done: m->put(); return true; } bool LogMonitor::prepare_log(MLog *m) { dout(10) << "prepare_log " << *m << " from " << m->get_orig_source() << dendl; if (m->fsid != mon->monmap->fsid) { dout(0) << "handle_log on fsid " << m->fsid << " != " << mon->monmap->fsid << dendl; m->put(); return false; } for (deque::iterator p = m->entries.begin(); p != m->entries.end(); ++p) { dout(10) << " logging " << *p << dendl; if (!pending_summary.contains(p->key())) { pending_summary.add(*p); pending_log.insert(pair(p->stamp, *p)); } } wait_for_finished_proposal(new C_Log(this, m)); return true; } void LogMonitor::_updated_log(MLog *m) { dout(7) << "_updated_log for " << m->get_orig_source_inst() << dendl; mon->send_reply(m, new MLogAck(m->fsid, m->entries.rbegin()->seq)); m->put(); } bool LogMonitor::should_propose(double& delay) { // commit now if we have a lot of pending events if (g_conf->mon_max_log_entries_per_event > 0 && pending_log.size() >= (unsigned)g_conf->mon_max_log_entries_per_event) return true; // otherwise fall back to generic policy return PaxosService::should_propose(delay); } bool LogMonitor::preprocess_command(MMonCommand *m) { int r = -1; bufferlist rdata; stringstream ss; if (r != -1) { string rs; getline(ss, rs); mon->reply_command(m, r, rs, rdata, get_last_committed()); return true; } else return false; } bool LogMonitor::prepare_command(MMonCommand *m) { stringstream ss; string rs; int err = -EINVAL; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", get_last_committed()); return true; } if (prefix == "log") { vector logtext; cmd_getval(g_ceph_context, cmdmap, "logtext", logtext); LogEntry le; le.who = m->get_orig_source_inst(); le.stamp = m->get_recv_stamp(); le.seq = 0; le.type = CLOG_INFO; le.msg = str_join(logtext, " "); pending_summary.add(le); pending_log.insert(pair(le.stamp, le)); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, string(), get_last_committed() + 1)); return true; } getline(ss, rs); mon->reply_command(m, err, rs, get_last_committed()); return false; } int LogMonitor::sub_name_to_id(const string& n) { if (n == "log-debug") return CLOG_DEBUG; if (n == "log-info") return CLOG_INFO; if (n == "log-sec") return CLOG_SEC; if (n == "log-warn") return CLOG_WARN; if (n == "log-error") return CLOG_ERROR; return -1; } void LogMonitor::check_subs() { dout(10) << __func__ << dendl; for (map*>::iterator i = mon->session_map.subs.begin(); i != mon->session_map.subs.end(); ++i) { for (xlist::iterator j = i->second->begin(); !j.end(); ++j) { if (sub_name_to_id((*j)->type) >= 0) check_sub(*j); } } } void LogMonitor::check_sub(Subscription *s) { dout(10) << __func__ << " client wants " << s->type << " ver " << s->next << dendl; int sub_level = sub_name_to_id(s->type); assert(sub_level >= 0); version_t summary_version = summary.version; if (s->next > summary_version) { dout(10) << __func__ << " client " << s->session->inst << " requested version (" << s->next << ") is greater than ours (" << summary_version << "), which means we already sent him" << " everything we have." << dendl; return; } MLog *mlog = new MLog(mon->monmap->fsid); if (s->next == 0) { /* First timer, heh? */ bool ret = _create_sub_summary(mlog, sub_level); if (!ret) { dout(1) << __func__ << " ret = " << ret << dendl; mlog->put(); return; } } else { /* let us send you an incremental log... */ _create_sub_incremental(mlog, sub_level, s->next); } dout(1) << __func__ << " sending message to " << s->session->inst << " with " << mlog->entries.size() << " entries" << " (version " << mlog->version << ")" << dendl; mon->messenger->send_message(mlog, s->session->inst); if (s->onetime) mon->session_map.remove_sub(s); else s->next = summary_version+1; } /** * Create a log message containing only the last message in the summary. * * @param mlog Log message we'll send to the client. * @param level Maximum log level the client is interested in. * @return 'true' if we consider we successfully populated @mlog; * 'false' otherwise. */ bool LogMonitor::_create_sub_summary(MLog *mlog, int level) { dout(10) << __func__ << dendl; assert(mlog != NULL); if (!summary.tail.size()) return false; list::reverse_iterator it = summary.tail.rbegin(); for (; it != summary.tail.rend(); ++it) { LogEntry e = *it; if (e.type < level) continue; mlog->entries.push_back(e); mlog->version = summary.version; break; } return true; } /** * Create an incremental log message from version @sv to @summary.version * * @param mlog Log message we'll send to the client with the messages received * since version @sv, inclusive. * @param level The max log level of the messages the client is interested in. * @param sv The version the client is looking for. */ void LogMonitor::_create_sub_incremental(MLog *mlog, int level, version_t sv) { dout(10) << __func__ << " level " << level << " ver " << sv << " cur summary ver " << summary.version << dendl; if (sv < get_first_committed()) { dout(10) << __func__ << " skipped from " << sv << " to first_committed " << get_first_committed() << dendl; LogEntry le; le.stamp = ceph_clock_now(NULL); le.type = CLOG_WARN; ostringstream ss; ss << "skipped log messages from " << sv << " to " << get_first_committed(); le.msg = ss.str(); mlog->entries.push_back(le); sv = get_first_committed(); } version_t summary_ver = summary.version; while (sv <= summary_ver) { bufferlist bl; int err = get_version(sv, bl); assert(err == 0); assert(bl.length()); bufferlist::iterator p = bl.begin(); __u8 v; ::decode(v,p); while (!p.end()) { LogEntry le; le.decode(p); if (le.type < level) { dout(20) << __func__ << " requested " << level << " entry " << le.type << dendl; continue; } mlog->entries.push_back(le); } mlog->version = sv++; } dout(10) << __func__ << " incremental message ready (" << mlog->entries.size() << " entries)" << dendl; } ceph-0.80.11/src/mon/HealthMonitor.cc0000664000175100017510000000531712623076744021347 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include // Because intusive_ptr clobbers our assert... #include "include/assert.h" #include "mon/Monitor.h" #include "mon/QuorumService.h" #include "mon/HealthService.h" #include "mon/HealthMonitor.h" #include "mon/DataHealthService.h" #include "messages/MMonHealth.h" #include "common/config.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, this) static ostream& _prefix(std::ostream *_dout, const Monitor *mon, const HealthMonitor *hmon) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ")." << hmon->get_name() << "(" << hmon->get_epoch() << ") "; } void HealthMonitor::init() { dout(10) << __func__ << dendl; assert(services.empty()); services[HealthService::SERVICE_HEALTH_DATA] = new DataHealthService(mon); for (map::iterator it = services.begin(); it != services.end(); ++it) { it->second->init(); } } bool HealthMonitor::service_dispatch(Message *m) { assert(m->get_type() == MSG_MON_HEALTH); MMonHealth *hm = (MMonHealth*)m; int service_type = hm->get_service_type(); if (services.count(service_type) == 0) { dout(1) << __func__ << " service type " << service_type << " not registered -- drop message!" << dendl; m->put(); return false; } return services[service_type]->service_dispatch(hm); } void HealthMonitor::service_shutdown() { dout(0) << "HealthMonitor::service_shutdown " << services.size() << " services" << dendl; for (map::iterator it = services.begin(); it != services.end(); ++it) { it->second->shutdown(); delete it->second; } services.clear(); } void HealthMonitor::get_health(Formatter *f, list >& summary, list > *detail) { if (f) { f->open_object_section("health"); f->open_array_section("health_services"); } for (map::iterator it = services.begin(); it != services.end(); ++it) { it->second->get_health(f, summary, detail); } if (f) { f->close_section(); // health_services f->close_section(); // health } } ceph-0.80.11/src/mon/MonCap.cc0000664000175100017510000003304612623076744017747 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include "MonCap.h" #include "include/stringify.h" #include "common/config.h" #include "common/debug.h" #include "common/Formatter.h" #include static inline bool is_not_alnum_space(char c) { return !(isalpha(c) || isdigit(c) || (c == '-') || (c == '_')); } static string maybe_quote_string(const std::string& str) { if (find_if(str.begin(), str.end(), is_not_alnum_space) == str.end()) return str; return string("\"") + str + string("\""); } using std::ostream; using std::vector; #define dout_subsys ceph_subsys_mon ostream& operator<<(ostream& out, mon_rwxa_t p) { if (p == MON_CAP_ANY) return out << "*"; if (p & MON_CAP_R) out << "r"; if (p & MON_CAP_W) out << "w"; if (p & MON_CAP_X) out << "x"; return out; } ostream& operator<<(ostream& out, const StringConstraint& c) { if (c.prefix.length()) return out << "prefix " << c.prefix; else return out << "value " << c.value; } ostream& operator<<(ostream& out, const MonCapGrant& m) { out << "allow"; if (m.service.length()) { out << " service " << maybe_quote_string(m.service); } if (m.command.length()) { out << " command " << maybe_quote_string(m.command); if (!m.command_args.empty()) { out << " with"; for (map::const_iterator p = m.command_args.begin(); p != m.command_args.end(); ++p) { if (p->second.value.length()) out << " " << maybe_quote_string(p->first) << "=" << maybe_quote_string(p->second.value); else out << " " << maybe_quote_string(p->first) << " prefix " << maybe_quote_string(p->second.prefix); } } } if (m.profile.length()) { out << " profile " << maybe_quote_string(m.profile); } if (m.allow != 0) out << " " << m.allow; return out; } // // fusion lets us easily populate structs via the qi parser. typedef map kvmap; BOOST_FUSION_ADAPT_STRUCT(MonCapGrant, (std::string, service) (std::string, profile) (std::string, command) (kvmap, command_args) (mon_rwxa_t, allow)) BOOST_FUSION_ADAPT_STRUCT(StringConstraint, (std::string, value) (std::string, prefix)) // void MonCapGrant::expand_profile(EntityName name) const { // only generate this list once if (!profile_grants.empty()) return; if (profile == "mon") { profile_grants.push_back(MonCapGrant("mon", MON_CAP_ALL)); profile_grants.push_back(MonCapGrant("log", MON_CAP_ALL)); } if (profile == "osd") { profile_grants.push_back(MonCapGrant("osd", MON_CAP_ALL)); profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); profile_grants.push_back(MonCapGrant("pg", MON_CAP_R | MON_CAP_W)); profile_grants.push_back(MonCapGrant("log", MON_CAP_W)); } if (profile == "mds") { profile_grants.push_back(MonCapGrant("mds", MON_CAP_ALL)); profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); profile_grants.push_back(MonCapGrant("osd", MON_CAP_R)); profile_grants.push_back(MonCapGrant("log", MON_CAP_W)); } if (profile == "osd" || profile == "mds" || profile == "mon") { string prefix = string("daemon-private/") + stringify(name) + string("/"); profile_grants.push_back(MonCapGrant("config-key get", "key", StringConstraint("", prefix))); profile_grants.push_back(MonCapGrant("config-key put", "key", StringConstraint("", prefix))); profile_grants.push_back(MonCapGrant("config-key exists", "key", StringConstraint("", prefix))); profile_grants.push_back(MonCapGrant("config-key delete", "key", StringConstraint("", prefix))); } if (profile == "bootstrap-osd") { profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); // read monmap profile_grants.push_back(MonCapGrant("osd", MON_CAP_R)); // read osdmap profile_grants.push_back(MonCapGrant("mon getmap")); profile_grants.push_back(MonCapGrant("osd create")); profile_grants.push_back(MonCapGrant("auth add")); profile_grants.back().command_args["entity"] = StringConstraint("", "osd."); profile_grants.back().command_args["caps_mon"] = StringConstraint("allow profile osd", ""); profile_grants.back().command_args["caps_osd"] = StringConstraint("allow *", ""); } if (profile == "bootstrap-mds") { profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); // read monmap profile_grants.push_back(MonCapGrant("osd", MON_CAP_R)); // read osdmap profile_grants.push_back(MonCapGrant("mon getmap")); profile_grants.push_back(MonCapGrant("auth get-or-create")); // FIXME: this can expose other mds keys profile_grants.back().command_args["entity"] = StringConstraint("", "mds."); profile_grants.back().command_args["caps_mon"] = StringConstraint("allow profile mds", ""); profile_grants.back().command_args["caps_osd"] = StringConstraint("allow rwx", ""); profile_grants.back().command_args["caps_mds"] = StringConstraint("allow", ""); } if (profile == "fs-client") { profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); profile_grants.push_back(MonCapGrant("mds", MON_CAP_R)); profile_grants.push_back(MonCapGrant("osd", MON_CAP_R)); profile_grants.push_back(MonCapGrant("pg", MON_CAP_R)); } if (profile == "simple-rados-client") { profile_grants.push_back(MonCapGrant("mon", MON_CAP_R)); profile_grants.push_back(MonCapGrant("osd", MON_CAP_R)); profile_grants.push_back(MonCapGrant("pg", MON_CAP_R)); } } mon_rwxa_t MonCapGrant::get_allowed(CephContext *cct, EntityName name, const std::string& s, const std::string& c, const map& c_args) const { if (profile.length()) { expand_profile(name); mon_rwxa_t a; for (list::const_iterator p = profile_grants.begin(); p != profile_grants.end(); ++p) a = a | p->get_allowed(cct, name, s, c, c_args); return a; } if (service.length()) { if (service != s) return 0; return allow; } if (command.length()) { if (command != c) return 0; for (map::const_iterator p = command_args.begin(); p != command_args.end(); ++p) { map::const_iterator q = c_args.find(p->first); // argument must be present if a constraint exists if (q == c_args.end()) return 0; if (p->second.value.length()) { // match value if (p->second.value != q->second) return 0; } else { // match prefix if (q->second.find(p->second.prefix) != 0) return 0; } } return MON_CAP_ALL; } return allow; } ostream& operator<<(ostream&out, const MonCap& m) { for (vector::const_iterator p = m.grants.begin(); p != m.grants.end(); ++p) { if (p != m.grants.begin()) out << ", "; out << *p; } return out; } bool MonCap::is_allow_all() const { for (vector::const_iterator p = grants.begin(); p != grants.end(); ++p) if (p->is_allow_all()) return true; return false; } void MonCap::set_allow_all() { grants.clear(); grants.push_back(MonCapGrant(MON_CAP_ANY)); text = "allow *"; } bool MonCap::is_capable(CephContext *cct, EntityName name, const string& service, const string& command, const map& command_args, bool op_may_read, bool op_may_write, bool op_may_exec) const { if (cct) ldout(cct, 20) << "is_capable service=" << service << " command=" << command << (op_may_read ? " read":"") << (op_may_write ? " write":"") << (op_may_exec ? " exec":"") << " on cap " << *this << dendl; mon_rwxa_t allow = 0; for (vector::const_iterator p = grants.begin(); p != grants.end(); ++p) { if (cct) ldout(cct, 20) << " allow so far " << allow << ", doing grant " << *p << dendl; if (p->is_allow_all()) { if (cct) ldout(cct, 20) << " allow all" << dendl; return true; } // check enumerated caps allow = allow | p->get_allowed(cct, name, service, command, command_args); if ((!op_may_read || (allow & MON_CAP_R)) && (!op_may_write || (allow & MON_CAP_W)) && (!op_may_exec || (allow & MON_CAP_X))) { if (cct) ldout(cct, 20) << " match" << dendl; return true; } } return false; } void MonCap::encode(bufferlist& bl) const { ENCODE_START(4, 4, bl); // legacy MonCaps was 3, 3 ::encode(text, bl); ENCODE_FINISH(bl); } void MonCap::decode(bufferlist::iterator& bl) { string s; DECODE_START(4, bl); ::decode(s, bl); DECODE_FINISH(bl); parse(s, NULL); } void MonCap::dump(Formatter *f) const { f->dump_string("text", text); } void MonCap::generate_test_instances(list& ls) { ls.push_back(new MonCap); ls.push_back(new MonCap); ls.back()->parse("allow *"); ls.push_back(new MonCap); ls.back()->parse("allow rwx"); ls.push_back(new MonCap); ls.back()->parse("allow service foo x"); ls.push_back(new MonCap); ls.back()->parse("allow command bar x"); ls.push_back(new MonCap); ls.back()->parse("allow service foo r, allow command bar x"); ls.push_back(new MonCap); ls.back()->parse("allow command bar with k1=v1 x"); ls.push_back(new MonCap); ls.back()->parse("allow command bar with k1=v1 k2=v2 x"); } // grammar namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace phoenix = boost::phoenix; template struct MonCapParser : qi::grammar { MonCapParser() : MonCapParser::base_type(moncap) { using qi::char_; using qi::int_; using qi::ulong_long; using qi::lexeme; using qi::alnum; using qi::_val; using qi::_1; using qi::_2; using qi::_3; using qi::eps; using qi::lit; quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['\'' >> +(char_ - '\'') >> '\'']; unquoted_word %= +char_("a-zA-Z0-9_.-"); str %= quoted_string | unquoted_word; spaces = +(lit(' ') | lit('\n') | lit('\t')); // command := command[=]cmd [k1=v1 k2=v2 ...] str_match = '=' >> str >> qi::attr(string()); str_prefix = spaces >> lit("prefix") >> spaces >> qi::attr(string()) >> str; kv_pair = str >> (str_match | str_prefix); kv_map %= kv_pair >> *(spaces >> kv_pair); command_match = -spaces >> lit("allow") >> spaces >> lit("command") >> (lit('=') | spaces) >> qi::attr(string()) >> qi::attr(string()) >> str >> -(spaces >> lit("with") >> spaces >> kv_map) >> qi::attr(0); // service foo rwxa service_match %= -spaces >> lit("allow") >> spaces >> lit("service") >> (lit('=') | spaces) >> str >> qi::attr(string()) >> qi::attr(string()) >> qi::attr(map()) >> spaces >> rwxa; // profile foo profile_match %= -spaces >> lit("allow") >> spaces >> lit("profile") >> (lit('=') | spaces) >> qi::attr(string()) >> str >> qi::attr(string()) >> qi::attr(map()) >> qi::attr(0); // rwxa rwxa_match %= -spaces >> lit("allow") >> spaces >> qi::attr(string()) >> qi::attr(string()) >> qi::attr(string()) >> qi::attr(map()) >> rwxa; // rwxa := * | [r][w][x] rwxa = (lit("*")[_val = MON_CAP_ANY]) | ( eps[_val = 0] >> ( lit('r')[_val |= MON_CAP_R] || lit('w')[_val |= MON_CAP_W] || lit('x')[_val |= MON_CAP_X] ) ); // grant := allow ... grant = -spaces >> (rwxa_match | profile_match | service_match | command_match) >> -spaces; // moncap := grant [grant ...] grants %= (grant % (*lit(' ') >> (lit(';') | lit(',')) >> *lit(' '))); moncap = grants [_val = phoenix::construct(_1)]; } qi::rule spaces; qi::rule rwxa; qi::rule quoted_string; qi::rule unquoted_word; qi::rule str; qi::rule str_match, str_prefix; qi::rule()> kv_pair; qi::rule()> kv_map; qi::rule rwxa_match; qi::rule command_match; qi::rule service_match; qi::rule profile_match; qi::rule grant; qi::rule()> grants; qi::rule moncap; }; bool MonCap::parse(const string& str, ostream *err) { string s = str; string::iterator iter = s.begin(); string::iterator end = s.end(); MonCapParser g; bool r = qi::parse(iter, end, g, *this); //MonCapGrant foo; //bool r = qi::phrase_parse(iter, end, g, ascii::space, foo); if (r && iter == end) { text = str; return true; } // Make sure no grants are kept after parsing failed! grants.clear(); if (err) { if (iter != end) *err << "moncap parse failed, stopped at '" << std::string(iter, end) << "' of '" << str << "'\n"; else *err << "moncap parse failed, stopped at end of '" << str << "'\n"; } return false; } ceph-0.80.11/src/mon/PGMap.h0000664000175100017510000002337712623076744017406 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* * Placement Group Map. Placement Groups are logical sets of objects * that are replicated by the same set of devices. pgid=(r,hash(o)&m) * where & is a bit-wise AND and m=2^k-1 */ #ifndef CEPH_PGMAP_H #define CEPH_PGMAP_H #include "common/debug.h" #include "osd/osd_types.h" #include "common/config.h" #include #include "MonitorDBStore.h" namespace ceph { class Formatter; } class PGMap { public: // the map version_t version; epoch_t last_osdmap_epoch; // last osdmap epoch i applied to the pgmap epoch_t last_pg_scan; // osdmap epoch ceph::unordered_map pg_stat; ceph::unordered_map osd_stat; set full_osds; set nearfull_osds; float full_ratio; float nearfull_ratio; // mapping of osd to most recently reported osdmap epoch ceph::unordered_map osd_epochs; class Incremental { public: version_t version; map pg_stat_updates; epoch_t osdmap_epoch; epoch_t pg_scan; // osdmap epoch set pg_remove; float full_ratio; float nearfull_ratio; utime_t stamp; private: map osd_stat_updates; set osd_stat_rm; // mapping of osd to most recently reported osdmap epoch map osd_epochs; public: const map &get_osd_stat_updates() const { return osd_stat_updates; } const set &get_osd_stat_rm() const { return osd_stat_rm; } const map &get_osd_epochs() const { return osd_epochs; } void update_stat(int32_t osd, epoch_t epoch, const osd_stat_t &stat) { osd_stat_updates[osd] = stat; osd_epochs[osd] = epoch; assert(osd_epochs.size() == osd_stat_updates.size()); } void stat_osd_out(int32_t osd) { // 0 the stats for the osd osd_stat_updates[osd] = osd_stat_t(); } void rm_stat(int32_t osd) { osd_stat_rm.insert(osd); osd_epochs.erase(osd); osd_stat_updates.erase(osd); } void encode(bufferlist &bl, uint64_t features=-1) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); Incremental() : version(0), osdmap_epoch(0), pg_scan(0), full_ratio(0), nearfull_ratio(0) {} }; // aggregate stats (soft state), generated by calc_stats() ceph::unordered_map num_pg_by_state; int64_t num_pg, num_osd; ceph::unordered_map pg_pool_sum; pool_stat_t pg_sum; osd_stat_t osd_sum; mutable epoch_t min_last_epoch_clean; utime_t stamp; // recent deltas, and summation /** * keep track of last deltas for each pool, calculated using * @p pg_pool_sum as baseline. */ ceph::unordered_map > > per_pool_sum_deltas; /** * keep track of per-pool timestamp deltas, according to last update on * each pool. */ ceph::unordered_map per_pool_sum_deltas_stamps; /** * keep track of sum deltas, per-pool, taking into account any previous * deltas existing in @p per_pool_sum_deltas. The utime_t as second member * of the pair is the timestamp refering to the last update (i.e., the first * member of the pair) for a given pool. */ ceph::unordered_map > per_pool_sum_delta; list< pair > pg_sum_deltas; pool_stat_t pg_sum_delta; utime_t stamp_delta; void update_global_delta(CephContext *cct, const utime_t ts, const pool_stat_t& pg_sum_old); void update_pool_deltas(CephContext *cct, const utime_t ts, const ceph::unordered_map& pg_pool_sum_old); void clear_delta(); void deleted_pool(int64_t pool) { pg_pool_sum.erase(pool); per_pool_sum_deltas.erase(pool); per_pool_sum_deltas_stamps.erase(pool); per_pool_sum_delta.erase(pool); } private: void update_delta(CephContext *cct, const utime_t ts, const pool_stat_t& old_pool_sum, utime_t *last_ts, const pool_stat_t& current_pool_sum, pool_stat_t *result_pool_delta, utime_t *result_ts_delta, list > *delta_avg_list); void update_one_pool_delta(CephContext *cct, const utime_t ts, const uint64_t pool, const pool_stat_t& old_pool_sum); epoch_t calc_min_last_epoch_clean() const; public: set creating_pgs; // lru: front = new additions, back = recently pinged map > creating_pgs_by_osd; enum StuckPG { STUCK_INACTIVE, STUCK_UNCLEAN, STUCK_STALE, STUCK_NONE }; PGMap() : version(0), last_osdmap_epoch(0), last_pg_scan(0), full_ratio(0), nearfull_ratio(0), num_pg(0), num_osd(0), min_last_epoch_clean(0) {} void set_full_ratios(float full, float nearfull) { if (full_ratio == full && nearfull_ratio == nearfull) return; full_ratio = full; nearfull_ratio = nearfull; redo_full_sets(); } version_t get_version() const { return version; } void set_version(version_t v) { version = v; } epoch_t get_last_osdmap_epoch() const { return last_osdmap_epoch; } void set_last_osdmap_epoch(epoch_t e) { last_osdmap_epoch = e; } epoch_t get_last_pg_scan() const { return last_pg_scan; } void set_last_pg_scan(epoch_t e) { last_pg_scan = e; } utime_t get_stamp() const { return stamp; } void set_stamp(utime_t s) { stamp = s; } pool_stat_t get_pg_pool_sum_stat(int64_t pool) const { ceph::unordered_map::const_iterator p = pg_pool_sum.find(pool); if (p != pg_pool_sum.end()) return p->second; return pool_stat_t(); } void update_pg(pg_t pgid, bufferlist& bl); void remove_pg(pg_t pgid); void update_osd(int osd, bufferlist& bl); void remove_osd(int osd); void apply_incremental(CephContext *cct, const Incremental& inc); void redo_full_sets(); void register_nearfull_status(int osd, const osd_stat_t& s); void calc_stats(); void stat_pg_add(const pg_t &pgid, const pg_stat_t &s); void stat_pg_sub(const pg_t &pgid, const pg_stat_t &s); void stat_osd_add(const osd_stat_t &s); void stat_osd_sub(const osd_stat_t &s); void encode(bufferlist &bl, uint64_t features=-1) const; void decode(bufferlist::iterator &bl); void dirty_all(Incremental& inc); void dump(Formatter *f) const; void dump_basic(Formatter *f) const; void dump_pg_stats(Formatter *f, bool brief) const; void dump_pool_stats(Formatter *f) const; void dump_osd_stats(Formatter *f) const; void dump_delta(Formatter *f) const; void dump_pg_stats_plain(ostream& ss, const ceph::unordered_map& pg_stats) const; void get_stuck_stats(StuckPG type, utime_t cutoff, ceph::unordered_map& stuck_pgs) const; void dump_stuck(Formatter *f, StuckPG type, utime_t cutoff) const; void dump_stuck_plain(ostream& ss, StuckPG type, utime_t cutoff) const; void dump(ostream& ss) const; void dump_osd_perf_stats(Formatter *f) const; void print_osd_perf_stats(std::ostream *ss) const; void recovery_summary(Formatter *f, ostream *out, const pool_stat_t& delta_sum) const; void overall_recovery_summary(Formatter *f, ostream *out) const; void pool_recovery_summary(Formatter *f, ostream *out, uint64_t poolid) const; void recovery_rate_summary(Formatter *f, ostream *out, const pool_stat_t& delta_sum, utime_t delta_stamp) const; void overall_recovery_rate_summary(Formatter *f, ostream *out) const; void pool_recovery_rate_summary(Formatter *f, ostream *out, uint64_t poolid) const; /** * Obtain a formatted/plain output for client I/O, source from stats for a * given @p delta_sum pool over a given @p delta_stamp period of time. */ void client_io_rate_summary(Formatter *f, ostream *out, const pool_stat_t& delta_sum, utime_t delta_stamp) const; /** * Obtain a formatted/plain output for the overall client I/O, which is * calculated resorting to @p pg_sum_delta and @p stamp_delta. */ void overall_client_io_rate_summary(Formatter *f, ostream *out) const; /** * Obtain a formatted/plain output for client I/O over a given pool * with id @p pool_id. We will then obtain pool-specific data * from @p per_pool_sum_delta. */ void pool_client_io_rate_summary(Formatter *f, ostream *out, uint64_t poolid) const; void print_summary(Formatter *f, ostream *out) const; void print_oneline_summary(ostream *out) const; epoch_t get_min_last_epoch_clean() const { if (!min_last_epoch_clean) min_last_epoch_clean = calc_min_last_epoch_clean(); return min_last_epoch_clean; } static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER_FEATURES(PGMap::Incremental) WRITE_CLASS_ENCODER_FEATURES(PGMap) inline ostream& operator<<(ostream& out, const PGMap& m) { m.print_oneline_summary(&out); return out; } #endif ceph-0.80.11/src/mon/MonMap.h0000664000175100017510000001431312623076744017617 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MONMAP_H #define CEPH_MONMAP_H #include "include/err.h" #include "msg/Message.h" #include "include/types.h" //#include "common/config.h" namespace ceph { class Formatter; } class MonMap { public: epoch_t epoch; // what epoch/version of the monmap uuid_d fsid; map mon_addr; utime_t last_changed; utime_t created; map addr_name; vector rank_name; vector rank_addr; void calc_ranks() { rank_name.resize(mon_addr.size()); rank_addr.resize(mon_addr.size()); addr_name.clear(); for (map::iterator p = mon_addr.begin(); p != mon_addr.end(); ++p) { assert(addr_name.count(p->second) == 0); addr_name[p->second] = p->first; } unsigned i = 0; for (map::iterator p = addr_name.begin(); p != addr_name.end(); ++p, i++) { rank_name[i] = p->second; rank_addr[i] = p->first; } } MonMap() : epoch(0) { memset(&fsid, 0, sizeof(fsid)); } uuid_d& get_fsid() { return fsid; } unsigned size() { return mon_addr.size(); } epoch_t get_epoch() { return epoch; } void set_epoch(epoch_t e) { epoch = e; } void list_addrs(list& ls) const { for (map::const_iterator p = mon_addr.begin(); p != mon_addr.end(); ++p) ls.push_back(p->second); } void add(const string &name, const entity_addr_t &addr) { assert(mon_addr.count(name) == 0); assert(addr_name.count(addr) == 0); mon_addr[name] = addr; calc_ranks(); } void remove(const string &name) { assert(mon_addr.count(name)); mon_addr.erase(name); calc_ranks(); } void rename(string oldname, string newname) { assert(contains(oldname)); assert(!contains(newname)); mon_addr[newname] = mon_addr[oldname]; mon_addr.erase(oldname); calc_ranks(); } bool contains(const string& name) { return mon_addr.count(name); } bool contains(const entity_addr_t &a) { for (map::iterator p = mon_addr.begin(); p != mon_addr.end(); ++p) { if (p->second == a) return true; } return false; } string get_name(unsigned n) const { assert(n < rank_name.size()); return rank_name[n]; } string get_name(const entity_addr_t& a) const { map::const_iterator p = addr_name.find(a); if (p == addr_name.end()) return string(); else return p->second; } int get_rank(const string& n) { for (unsigned i=0; i& initial_members, string my_name, const entity_addr_t& my_addr, set *removed); void print(ostream& out) const; void print_summary(ostream& out) const; void dump(ceph::Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER_FEATURES(MonMap) inline ostream& operator<<(ostream& out, MonMap& m) { m.print_summary(out); return out; } #endif ceph-0.80.11/src/mon/Makefile.am0000664000175100017510000000202112623076744020304 0ustar jenkins-buildjenkins-buildlibmon_types_la_SOURCES = \ mon/PGMap.cc noinst_LTLIBRARIES += libmon_types.la libmon_la_SOURCES = \ mon/Monitor.cc \ mon/Paxos.cc \ mon/PaxosService.cc \ mon/OSDMonitor.cc \ mon/MDSMonitor.cc \ mon/MonmapMonitor.cc \ mon/PGMonitor.cc \ mon/LogMonitor.cc \ mon/AuthMonitor.cc \ mon/Elector.cc \ mon/MonitorStore.cc \ mon/HealthMonitor.cc \ mon/DataHealthService.cc \ mon/ConfigKeyService.cc libmon_la_LIBADD = $(LIBAUTH) $(LIBCOMMON) $(LIBOS) $(LIBMON_TYPES) noinst_LTLIBRARIES += libmon.la noinst_HEADERS += \ mon/AuthMonitor.h \ mon/DataHealthService.h \ mon/Elector.h \ mon/LogMonitor.h \ mon/ConfigKeyService.h \ mon/HealthMonitor.h \ mon/HealthService.h \ mon/MDSMonitor.h \ mon/MonmapMonitor.h \ mon/MonCap.h \ mon/MonClient.h \ mon/MonCommands.h \ mon/DumplingMonCommands.h \ mon/MonMap.h \ mon/Monitor.h \ mon/MonitorStore.h \ mon/MonitorDBStore.h \ mon/OSDMonitor.h \ mon/PGMap.h \ mon/PGMonitor.h \ mon/Paxos.h \ mon/PaxosService.h \ mon/QuorumService.h \ mon/Session.h \ mon/mon_types.h ceph-0.80.11/src/mon/DumplingMonCommands.h0000664000175100017510000005562712623076744022360 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* no guard; may be included multiple times */ /* * Define commands that are reported by the monitor's * "get_command_descriptions" command, and parsed by the Python * frontend 'ceph' (and perhaps by other frontends, such as a RESTful * server). The format is: * * COMMAND(signature, helpstring, modulename, req perms, availability) * where: * signature: describes the command and its parameters (more below) * helpstring: displays in CLI help, API help (nice if it refers to * parameter names from signature, 40-a few hundred chars) * modulename: the monitor module or daemon this applies to: * mds, osd, pg (osd), mon, auth, log, config-key * req perms: required permission in that modulename space to execute command * this also controls what type of REST command is accepted * availability: cli, rest, or both * * The commands describe themselves completely enough for the separate * frontend(s) to be able to accept user input and validate it against * the command descriptions, and generate a JSON object that contains * key:value mappings of parameter names to validated parameter values. * * 'signature' is a space-separated list of individual command descriptors; * each descriptor is either a literal string, which can contain no spaces or * '=' signs (for instance, in "pg stat", both "pg" and "stat" are literal * strings representing one descriptor each), or a list of key=val[,key=val...] * which also includes no spaces. * * The key=val form describes a non-literal parameter. Each will have at * least a name= and type=, and each type can have its own type-specific * parameters. The parser is the arbiter of these types and their * interpretation. A few more non-type-specific key=val pairs exist: * * req=false marks an optional parameter (default for req is 'true') * n= is a repeat count for how many of this argument must be supplied. * n=1 is the default. * n=N is a special case that means "1 or more". * * A perhaps-incomplete list of types: * * CephInt: Optional: range=min[|max] * CephFloat: Optional range * CephString: optional badchars * CephSocketpath: validation involves "is it S_ISSOCK" * CephIPAddr: v4 or v6 addr with optional port, syntax validated * CephEntityAddr: CephIPAddr + '/nonce' * CephPoolname: Plainold string * CephObjectname: Another plainold string * CephPgid: n.xxx where n is an int > 0, xxx is a hex number > 0 * CephName: daemon name, '*' or '.' (id must be int for type osd) * CephOsdName: osd name, '*' or ' or 'osd.' (id must be int) * CephChoices: strings="foo|bar" means this param can be either * CephFilepath: openable file * CephFragment: cephfs 'fragID': val/bits, val in hex 0xnnn, bits in dec * CephUUID: uuid in text matching Python uuid.UUID() * CephPrefix: special type assigned to literals * * Example: * * COMMAND("auth add " \ * "name=entity,type=CephString " \ * "name=caps,type=CephString,n=N,req=false", \ * "add auth info for from input file, or random key " \ * "if no input given, and/or any caps specified in the command") * * defines a command "auth add" that takes a required argument "entity" * of type "CephString", and from 1 to N arguments named "caps" of type * CephString, at least one of which is required. The front end will * validate user input against this description. Let's say the user * enters auth add client.admin 'mon rwx' 'osd *'. The result will be a * JSON object like {"prefix":"auth add", "entity":"client.admin", * "caps":["mon rwx", "osd *"]}. * Note that * - string literals are accumulated into 'prefix' * - n=1 descriptors are given normal string or int object values * - n=N descriptors are given array values * * NOTE: be careful with spaces. Each descriptor must be separated by * one space, no other characters, so if you split lines as above, be * sure to close and reopen the quotes, and be careful to include the ' * separating spaces in the quoted string. * * The monitor marshals this JSON into a std::map * where cmd_vartype is a boost::variant type-enforcing discriminated * type, so the monitor is expected to know the type of each argument. * See cmdparse.cc/h for more details. */ /* * pg commands PgMonitor.cc */ COMMAND("pg stat", "show placement group status.", "pg", "r", "cli,rest") COMMAND("pg getmap", "get binary pg map to -o/stdout", "pg", "r", "cli,rest") COMMAND("pg send_pg_creates", "trigger pg creates to be issued",\ "pg", "rw", "cli,rest") COMMAND("pg dump " \ "name=dumpcontents,type=CephChoices,strings=all|summary|sum|pools|osds|pgs|pgs_brief,n=N,req=false", \ "show human-readable versions of pg map", "pg", "r", "cli,rest") COMMAND("pg dump_json " \ "name=dumpcontents,type=CephChoices,strings=all|summary|sum|pools|osds|pgs,n=N,req=false", \ "show human-readable version of pg map in json only",\ "pg", "r", "cli,rest") COMMAND("pg dump_pools_json", "show pg pools info in json only",\ "pg", "r", "cli,rest") COMMAND("pg dump_stuck " \ "name=stuckops,type=CephChoices,strings=inactive|unclean|stale,n=N,req=false " \ "name=threshold,type=CephInt,req=false", "show information about stuck pgs",\ "pg", "r", "cli,rest") COMMAND("pg map name=pgid,type=CephPgid", "show mapping of pg to osds", \ "pg", "r", "cli,rest") COMMAND("pg scrub name=pgid,type=CephPgid", "start scrub on ", \ "pg", "rw", "cli,rest") COMMAND("pg deep-scrub name=pgid,type=CephPgid", "start deep-scrub on ", \ "pg", "rw", "cli,rest") COMMAND("pg repair name=pgid,type=CephPgid", "start repair on ", \ "pg", "rw", "cli,rest") COMMAND("pg debug " \ "name=debugop,type=CephChoices,strings=unfound_objects_exist|degraded_pgs_exist", \ "show debug info about pgs", "pg", "r", "cli,rest") COMMAND("pg force_create_pg name=pgid,type=CephPgid", \ "force creation of pg ", "pg", "rw", "cli,rest") COMMAND("pg set_full_ratio name=ratio,type=CephFloat,range=0.0|1.0", \ "set ratio at which pgs are considered full", "pg", "rw", "cli,rest") COMMAND("pg set_nearfull_ratio name=ratio,type=CephFloat,range=0.0|1.0", \ "set ratio at which pgs are considered nearly full", \ "pg", "rw", "cli,rest") /* * auth commands AuthMonitor.cc */ COMMAND("auth export name=entity,type=CephString,req=false", \ "write keyring for requested entity, or master keyring if none given", \ "auth", "r", "cli,rest") COMMAND("auth get name=entity,type=CephString", \ "write keyring file with requested key", "auth", "r", "cli,rest") COMMAND("auth get-key name=entity,type=CephString", "display requested key", \ "auth", "r", "cli,rest") COMMAND("auth print-key name=entity,type=CephString", "display requested key", \ "auth", "r", "cli,rest") COMMAND("auth print_key name=entity,type=CephString", "display requested key", \ "auth", "r", "cli,rest") COMMAND("auth list", "list authentication state", "auth", "r", "cli,rest") COMMAND("auth import", "auth import: read keyring file from -i ", \ "auth", "rw", "cli,rest") COMMAND("auth add " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N,req=false", \ "add auth info for from input file, or random key if no input given, and/or any caps specified in the command", "auth", "rw", "cli,rest") COMMAND("auth get-or-create-key " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N,req=false", \ "get, or add, key for from system/caps pairs specified in the command. If key already exists, any given caps must match the existing caps for that key.", \ "auth", "rw", "cli,rest") COMMAND("auth get-or-create " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N,req=false", \ "add auth info for from input file, or random key if no input given, and/or any caps specified in the command", \ "auth", "rw", "cli,rest") COMMAND("auth caps " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N", \ "update caps for from caps specified in the command", \ "auth", "rw", "cli,rest") COMMAND("auth del " \ "name=entity,type=CephString", \ "delete all caps for ", \ "auth", "rw", "cli,rest") /* * Monitor commands (Monitor.cc) */ COMMAND("compact", "cause compaction of monitor's leveldb storage", \ "mon", "rw", "cli,rest") COMMAND("scrub", "scrub the monitor stores", "mon", "rw", "cli,rest") COMMAND("fsid", "show cluster FSID/UUID", "mon", "r", "cli,rest") COMMAND("log name=logtext,type=CephString,n=N", \ "log supplied text to the monitor log", "mon", "rw", "cli,rest") COMMAND("injectargs " \ "name=injected_args,type=CephString,n=N", \ "inject config arguments into monitor", "mon", "rw", "cli,rest") COMMAND("status", "show cluster status", "mon", "r", "cli,rest") COMMAND("health name=detail,type=CephChoices,strings=detail,req=false", \ "show cluster health", "mon", "r", "cli,rest") COMMAND("df name=detail,type=CephChoices,strings=detail,req=false", \ "show cluster free space stats", "mon", "r", "cli,rest") COMMAND("report name=tags,type=CephString,n=N,req=false", \ "report full status of cluster, optional title tag strings", \ "mon", "r", "cli,rest") COMMAND("quorum_status", "report status of monitor quorum", \ "mon", "r", "cli,rest") COMMAND("mon_status", "report status of monitors", "mon", "r", "cli,rest") COMMAND("sync force " \ "name=validate1,type=CephChoices,strings=--yes-i-really-mean-it " \ "name=validate2,type=CephChoices,strings=--i-know-what-i-am-doing", \ "force sync of and clear monitor store", "mon", "rw", "cli,rest") COMMAND("heap " \ "name=heapcmd,type=CephChoices,strings=dump|start_profiler|stop_profiler|release|stats", \ "show heap usage info (available only if compiled with tcmalloc)", \ "mon", "rw", "cli,rest") COMMAND("quorum name=quorumcmd,type=CephChoices,strings=enter|exit,n=1", \ "enter or exit quorum", "mon", "rw", "cli,rest") COMMAND("tell " \ "name=target,type=CephName " \ "name=args,type=CephString,n=N", \ "send a command to a specific daemon", "mon", "rw", "cli,rest") /* * MDS commands (MDSMonitor.cc) */ COMMAND("mds stat", "show MDS status", "mds", "r", "cli,rest") COMMAND("mds dump " "name=epoch,type=CephInt,req=false,range=0", \ "dump info, optionally from epoch", "mds", "r", "cli,rest") COMMAND("mds getmap " \ "name=epoch,type=CephInt,req=false,range=0", \ "get MDS map, optionally from epoch", "mds", "r", "cli,rest") COMMAND("mds tell " \ "name=who,type=CephString " \ "name=args,type=CephString,n=N", \ "send command to particular mds", "mds", "rw", "cli,rest") COMMAND("mds compat show", "show mds compatibility settings", \ "mds", "r", "cli,rest") COMMAND("mds stop name=who,type=CephString", "stop mds", \ "mds", "rw", "cli,rest") COMMAND("mds deactivate name=who,type=CephString", "stop mds", \ "mds", "rw", "cli,rest") COMMAND("mds set_max_mds " \ "name=maxmds,type=CephInt,range=0", \ "set max MDS index", "mds", "rw", "cli,rest") COMMAND("mds setmap " \ "name=epoch,type=CephInt,range=0", \ "set mds map; must supply correct epoch number", "mds", "rw", "cli,rest") // arbitrary limit 0-20 below; worth standing on head to make it // relate to actual state definitions? // #include "include/ceph_fs.h" COMMAND("mds set_state " \ "name=gid,type=CephInt,range=0 " \ "name=state,type=CephInt,range=0|20", \ "set mds state of to ", "mds", "rw", "cli,rest") COMMAND("mds fail name=who,type=CephString", \ "force mds to status failed", "mds", "rw", "cli,rest") COMMAND("mds rm " \ "name=gid,type=CephInt,range=0 " \ "name=who,type=CephName", \ "remove nonactive mds", "mds", "rw", "cli,rest") COMMAND("mds rmfailed name=who,type=CephInt,range=0", "remove failed mds", \ "mds", "rw", "cli,rest") COMMAND("mds cluster_down", "take MDS cluster down", "mds", "rw", "cli,rest") COMMAND("mds cluster_up", "bring MDS cluster up", "mds", "rw", "cli,rest") COMMAND("mds compat rm_compat " \ "name=feature,type=CephInt,range=0", \ "remove compatible feature", "mds", "rw", "cli,rest") COMMAND("mds compat rm_incompat " \ "name=feature,type=CephInt,range=0", \ "remove incompatible feature", "mds", "rw", "cli,rest") COMMAND("mds add_data_pool " \ "name=poolid,type=CephInt,range=0", \ "add data pool ", "mds", "rw", "cli,rest") COMMAND("mds remove_data_pool " \ "name=poolid,type=CephInt,range=0", \ "remove data pool ", "mds", "rw", "cli,rest") COMMAND("mds newfs " \ "name=metadata,type=CephInt,range=0 " \ "name=data,type=CephInt,range=0 " \ "name=sure,type=CephChoices,strings=--yes-i-really-mean-it", \ "make new filesystom using pools and ", \ "mds", "rw", "cli,rest") /* * Monmap commands */ COMMAND("mon dump " \ "name=epoch,type=CephInt,req=false", \ "dump formatted monmap (optionally from epoch)", \ "mon", "r", "cli,rest") COMMAND("mon stat", "summarize monitor status", "mon", "r", "cli,rest") COMMAND("mon getmap " \ "name=epoch,type=CephInt,range=0,req=false", \ "get monmap", "mon", "r", "cli,rest") COMMAND("mon add " \ "name=name,type=CephString " \ "name=addr,type=CephIPAddr", \ "add new monitor named at ", "mon", "rw", "cli,rest") COMMAND("mon remove " \ "name=name,type=CephString", \ "remove monitor named ", "mon", "rw", "cli,rest") /* * OSD commands */ COMMAND("osd stat", "print summary of OSD map", "osd", "r", "cli,rest") COMMAND("osd dump " \ "name=epoch,type=CephInt,range=0,req=false", "print summary of OSD map", "osd", "r", "cli,rest") COMMAND("osd tree " \ "name=epoch,type=CephInt,range=0,req=false", \ "print OSD tree", "osd", "r", "cli,rest") COMMAND("osd ls " \ "name=epoch,type=CephInt,range=0,req=false", \ "show all OSD ids", "osd", "r", "cli,rest") COMMAND("osd getmap " \ "name=epoch,type=CephInt,range=0,req=false", \ "get OSD map", "osd", "r", "cli,rest") COMMAND("osd getcrushmap " \ "name=epoch,type=CephInt,range=0,req=false", \ "get CRUSH map", "osd", "r", "cli,rest") COMMAND("osd getmaxosd", "show largest OSD id", "osd", "r", "cli,rest") COMMAND("osd find " \ "name=id,type=CephInt,range=0", \ "find osd in the CRUSH map and show its location", \ "osd", "r", "cli,rest") COMMAND("osd map " \ "name=pool,type=CephPoolname " \ "name=object,type=CephObjectname", \ "find pg for in ", "osd", "r", "cli,rest") COMMAND("osd scrub " \ "name=who,type=CephString", \ "initiate scrub on osd ", "osd", "rw", "cli,rest") COMMAND("osd deep-scrub " \ "name=who,type=CephString", \ "initiate deep scrub on osd ", "osd", "rw", "cli,rest") COMMAND("osd repair " \ "name=who,type=CephString", \ "initiate repair on osd ", "osd", "rw", "cli,rest") COMMAND("osd lspools " \ "name=auid,type=CephInt,req=false", \ "list pools", "osd", "r", "cli,rest") COMMAND("osd blacklist ls", "show blacklisted clients", "osd", "r", "cli,rest") COMMAND("osd crush rule list", "list crush rules", "osd", "r", "cli,rest") COMMAND("osd crush rule ls", "list crush rules", "osd", "r", "cli,rest") COMMAND("osd crush rule dump", "dump crush rules", "osd", "r", "cli,rest") COMMAND("osd crush dump", "dump crush map", "osd", "r", "cli,rest") COMMAND("osd setcrushmap", "set crush map from input file", \ "osd", "rw", "cli,rest") COMMAND("osd crush set", "set crush map from input file", \ "osd", "rw", "cli,rest") COMMAND("osd crush add-bucket " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=type,type=CephString", \ "add no-parent (probably root) crush bucket of type ", \ "osd", "rw", "cli,rest") COMMAND("osd crush set " \ "name=id,type=CephOsdName " \ "name=weight,type=CephFloat,range=0.0 " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "set crushmap entry for to with location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush add " \ "name=id,type=CephOsdName " \ "name=weight,type=CephFloat,range=0.0 " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "add crushmap entry for with and location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush create-or-move " \ "name=id,type=CephOsdName " \ "name=weight,type=CephFloat,range=0.0 " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "create entry or move existing entry for at/to location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush move " \ "name=id,type=CephOsdName " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "move existing entry for to location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush link " \ "name=name,type=CephString " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "link existing entry for under location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \ "remove from crush map (everywhere, or just at ",\ "osd", "rw", "cli,rest") COMMAND("osd crush remove " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \ "remove from crush map (everywhere, or just at ", \ "osd", "rw", "cli,rest") COMMAND("osd crush unlink " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \ "unlink from crush map (everywhere, or just at ", \ "osd", "rw", "cli,rest") COMMAND("osd crush reweight " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=weight,type=CephFloat,range=0.0", \ "change 's weight to in crush map", \ "osd", "rw", "cli,rest") COMMAND("osd crush tunables " \ "name=profile,type=CephChoices,strings=legacy|argonaut|bobtail|optimal|default", \ "set crush tunables values to ", "osd", "rw", "cli,rest") COMMAND("osd crush rule create-simple " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=root,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=type,type=CephString,goodchars=[A-Za-z0-9-_.]", "create crush rule in of type ", \ "osd", "rw", "cli,rest") COMMAND("osd crush rule rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] ", \ "remove crush rule ", "osd", "rw", "cli,rest") COMMAND("osd setmaxosd " \ "name=newmax,type=CephInt,range=0", \ "set new maximum osd value", "osd", "rw", "cli,rest") COMMAND("osd pause", "pause osd", "osd", "rw", "cli,rest") COMMAND("osd unpause", "unpause osd", "osd", "rw", "cli,rest") COMMAND("osd set " \ "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub", \ "set ", "osd", "rw", "cli,rest") COMMAND("osd unset " \ "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub", \ "unset ", "osd", "rw", "cli,rest") COMMAND("osd cluster_snap", "take cluster snapshot (disabled)", \ "osd", "r", "") COMMAND("osd down " \ "type=CephString,name=ids,n=N", \ "set osd(s) [...] down", "osd", "rw", "cli,rest") COMMAND("osd out " \ "name=ids,type=CephString,n=N", \ "set osd(s) [...] out", "osd", "rw", "cli,rest") COMMAND("osd in " \ "name=ids,type=CephString,n=N", \ "set osd(s) [...] in", "osd", "rw", "cli,rest") COMMAND("osd rm " \ "name=ids,type=CephString,n=N", \ "remove osd(s) [...] in", "osd", "rw", "cli,rest") COMMAND("osd reweight " \ "name=id,type=CephInt,range=0 " \ "type=CephFloat,name=weight,range=0.0|1.0", \ "reweight osd to 0.0 < < 1.0", "osd", "rw", "cli,rest") COMMAND("osd lost " \ "name=id,type=CephInt,range=0 " \ "name=sure,type=CephChoices,strings=--yes-i-really-mean-it", \ "mark osd as permanently lost. THIS DESTROYS DATA IF NO MORE REPLICAS EXIST, BE CAREFUL", \ "osd", "rw", "cli,rest") COMMAND("osd create " \ "name=uuid,type=CephUUID,req=false", \ "create new osd (with optional UUID)", "osd", "rw", "cli,rest") COMMAND("osd blacklist " \ "name=blacklistop,type=CephChoices,strings=add|rm " \ "name=addr,type=CephEntityAddr " \ "name=expire,type=CephFloat,range=0.0,req=false", \ "add (optionally until seconds from now) or remove from blacklist", \ "osd", "rw", "cli,rest") COMMAND("osd pool mksnap " \ "name=pool,type=CephPoolname " \ "name=snap,type=CephString", \ "make snapshot in ", "osd", "rw", "cli,rest") COMMAND("osd pool rmsnap " \ "name=pool,type=CephPoolname " \ "name=snap,type=CephString", \ "remove snapshot from ", "osd", "rw", "cli,rest") COMMAND("osd pool create " \ "name=pool,type=CephPoolname " \ "name=pg_num,type=CephInt,range=0 " \ "name=pgp_num,type=CephInt,range=0,req=false", \ "create pool", "osd", "rw", "cli,rest") COMMAND("osd pool delete " \ "name=pool,type=CephPoolname " \ "name=pool2,type=CephPoolname " \ "name=sure,type=CephChoices,strings=--yes-i-really-really-mean-it", \ "delete pool (say pool twice, add --yes-i-really-really-mean-it)", \ "osd", "rw", "cli,rest") COMMAND("osd pool rename " \ "name=srcpool,type=CephPoolname " \ "name=destpool,type=CephPoolname", \ "rename to ", "osd", "rw", "cli,rest") COMMAND("osd pool get " \ "name=pool,type=CephPoolname " \ "name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset", \ "get pool parameter ", "osd", "r", "cli,rest") COMMAND("osd pool set " \ "name=pool,type=CephPoolname " \ "name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset " \ "name=val,type=CephInt", \ "set pool parameter to ", "osd", "rw", "cli,rest") // 'val' is a CephString because it can include a unit. Perhaps // there should be a Python type for validation/conversion of strings // with units. COMMAND("osd pool set-quota " \ "name=pool,type=CephPoolname " \ "name=field,type=CephChoices,strings=max_objects|max_bytes " \ "name=val,type=CephString", "set object or byte limit on pool", "osd", "rw", "cli,rest") COMMAND("osd reweight-by-utilization " \ "name=oload,type=CephInt,range=100,req=false", \ "reweight OSDs by utilization [overload-percentage-for-consideration, default 120]", \ "osd", "rw", "cli,rest") COMMAND("osd thrash " \ "name=num_epochs,type=CephInt,range=0", \ "thrash OSDs for ", "osd", "rw", "cli,rest") /* * mon/ConfigKeyService.cc */ COMMAND("config-key get " \ "name=key,type=CephString", \ "get ", "config-key", "r", "cli,rest") COMMAND("config-key put " \ "name=key,type=CephString " \ "name=val,type=CephString,req=false", \ "put , value ", "config-key", "rw", "cli,rest") COMMAND("config-key del " \ "name=key,type=CephString", \ "delete ", "config-key", "rw", "cli,rest") COMMAND("config-key exists " \ "name=key,type=CephString", \ "check for 's existence", "config-key", "r", "cli,rest") COMMAND("config-key list ", "list keys", "config-key", "r", "cli,rest") ceph-0.80.11/src/mon/PaxosService.cc0000664000175100017510000002575512623076744021215 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "PaxosService.h" #include "common/Clock.h" #include "Monitor.h" #include "MonitorDBStore.h" #include "common/config.h" #include "include/assert.h" #include "common/Formatter.h" #define dout_subsys ceph_subsys_paxos #undef dout_prefix #define dout_prefix _prefix(_dout, mon, paxos, service_name, get_first_committed(), get_last_committed()) static ostream& _prefix(std::ostream *_dout, Monitor *mon, Paxos *paxos, string service_name, version_t fc, version_t lc) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").paxosservice(" << service_name << " " << fc << ".." << lc << ") "; } bool PaxosService::dispatch(PaxosServiceMessage *m) { dout(10) << "dispatch " << *m << " from " << m->get_orig_source_inst() << dendl; if (mon->is_shutdown()) { m->put(); return true; } // make sure this message isn't forwarded from a previous election epoch if (m->rx_election_epoch && m->rx_election_epoch < mon->get_epoch()) { dout(10) << " discarding forwarded message from previous election epoch " << m->rx_election_epoch << " < " << mon->get_epoch() << dendl; m->put(); return true; } // make sure the client is still connected. note that a proxied // connection will be disconnected with a null message; don't drop // those. also ignore loopback (e.g., log) messages. if (!m->get_connection()->is_connected() && m->get_connection() != mon->con_self && m->get_connection()->get_messenger() != NULL) { dout(10) << " discarding message from disconnected client " << m->get_source_inst() << " " << *m << dendl; m->put(); return true; } // make sure our map is readable and up to date if (!is_readable(m->version)) { dout(10) << " waiting for paxos -> readable (v" << m->version << ")" << dendl; wait_for_readable(new C_RetryMessage(this, m), m->version); return true; } // preprocess if (preprocess_query(m)) return true; // easy! // leader? if (!mon->is_leader()) { mon->forward_request_leader(m); return true; } // writeable? if (!is_writeable()) { dout(10) << " waiting for paxos -> writeable" << dendl; wait_for_writeable(new C_RetryMessage(this, m)); return true; } // update if (prepare_update(m)) { double delay = 0.0; if (should_propose(delay)) { if (delay == 0.0) { propose_pending(); } else { // delay a bit if (!proposal_timer) { proposal_timer = new C_Propose(this); dout(10) << " setting proposal_timer " << proposal_timer << " with delay of " << delay << dendl; mon->timer.add_event_after(delay, proposal_timer); } else { dout(10) << " proposal_timer already set" << dendl; } } } else { dout(10) << " not proposing" << dendl; } } return true; } void PaxosService::refresh(bool *need_bootstrap) { // update cached versions cached_first_committed = mon->store->get(get_service_name(), first_committed_name); cached_last_committed = mon->store->get(get_service_name(), last_committed_name); version_t new_format = get_value("format_version"); if (new_format != format_version) { dout(1) << __func__ << " upgraded, format " << format_version << " -> " << new_format << dendl; on_upgrade(); } format_version = new_format; dout(10) << __func__ << dendl; update_from_paxos(need_bootstrap); } void PaxosService::post_refresh() { dout(10) << __func__ << dendl; post_paxos_update(); if (mon->is_peon() && !waiting_for_finished_proposal.empty()) { finish_contexts(g_ceph_context, waiting_for_finished_proposal, -EAGAIN); } } void PaxosService::remove_legacy_versions() { dout(10) << __func__ << dendl; if (!mon->store->exists(get_service_name(), "conversion_first")) return; version_t cf = mon->store->get(get_service_name(), "conversion_first"); version_t fc = get_first_committed(); dout(10) << __func__ << " conversion_first " << cf << " first committed " << fc << dendl; MonitorDBStore::Transaction t; if (cf < fc) { trim(&t, cf, fc); } t.erase(get_service_name(), "conversion_first"); mon->store->apply_transaction(t); } bool PaxosService::should_propose(double& delay) { // simple default policy: quick startup, then some damping. if (get_last_committed() <= 1) delay = 0.0; else { utime_t now = ceph_clock_now(g_ceph_context); if ((now - paxos->last_commit_time) > g_conf->paxos_propose_interval) delay = (double)g_conf->paxos_min_wait; else delay = (double)(g_conf->paxos_propose_interval + paxos->last_commit_time - now); } return true; } void PaxosService::propose_pending() { dout(10) << "propose_pending" << dendl; assert(have_pending); assert(!proposing); assert(mon->is_leader()); assert(is_active()); if (proposal_timer) { dout(10) << " canceling proposal_timer " << proposal_timer << dendl; mon->timer.cancel_event(proposal_timer); proposal_timer = NULL; } /** * @note The value we propose is encoded in a bufferlist, passed to * Paxos::propose_new_value and it is obtained by calling a * function that must be implemented by the class implementing us. * I.e., the function encode_pending will be the one responsible * to encode whatever is pending on the implementation class into a * bufferlist, so we can then propose that as a value through Paxos. */ MonitorDBStore::Transaction t; bufferlist bl; if (should_stash_full()) encode_full(&t); encode_pending(&t); have_pending = false; if (format_version > 0) { t.put(get_service_name(), "format_version", format_version); } dout(30) << __func__ << " transaction dump:\n"; JSONFormatter f(true); t.dump(&f); f.flush(*_dout); *_dout << dendl; t.encode(bl); // apply to paxos proposing = true; paxos->propose_new_value(bl, new C_Committed(this)); } bool PaxosService::should_stash_full() { version_t latest_full = get_version_latest_full(); /* @note The first member of the condition is moot and it is here just for * clarity's sake. The second member would end up returing true * nonetheless because, in that event, * latest_full == get_trim_to() == 0. */ return (!latest_full || (latest_full <= get_trim_to()) || (get_last_committed() - latest_full > (unsigned)g_conf->paxos_stash_full_interval)); } void PaxosService::restart() { dout(10) << "restart" << dendl; if (proposal_timer) { dout(10) << " canceling proposal_timer " << proposal_timer << dendl; mon->timer.cancel_event(proposal_timer); proposal_timer = 0; } finish_contexts(g_ceph_context, waiting_for_finished_proposal, -EAGAIN); if (have_pending) { discard_pending(); have_pending = false; } proposing = false; on_restart(); } void PaxosService::election_finished() { dout(10) << "election_finished" << dendl; finish_contexts(g_ceph_context, waiting_for_finished_proposal, -EAGAIN); // make sure we update our state _active(); } void PaxosService::_active() { if (is_proposing()) { dout(10) << "_acting - proposing" << dendl; return; } if (!is_active()) { dout(10) << "_active - not active" << dendl; wait_for_active(new C_Active(this)); return; } dout(10) << "_active" << dendl; remove_legacy_versions(); // create pending state? if (mon->is_leader() && is_active()) { dout(7) << "_active creating new pending" << dendl; if (!have_pending) { create_pending(); have_pending = true; } if (get_last_committed() == 0) { // create initial state create_initial(); propose_pending(); return; } } else { if (!mon->is_leader()) { dout(7) << __func__ << " we are not the leader, hence we propose nothing!" << dendl; } else if (!is_active()) { dout(7) << __func__ << " we are not active, hence we propose nothing!" << dendl; } } // wake up anyone who came in while we were proposing. note that // anyone waiting for the previous proposal to commit is no longer // on this list; it is on Paxos's. finish_contexts(g_ceph_context, waiting_for_finished_proposal, 0); if (is_active() && mon->is_leader()) upgrade_format(); // NOTE: it's possible that this will get called twice if we commit // an old paxos value. Implementations should be mindful of that. if (is_active()) on_active(); } void PaxosService::shutdown() { cancel_events(); if (proposal_timer) { dout(10) << " canceling proposal_timer " << proposal_timer << dendl; mon->timer.cancel_event(proposal_timer); proposal_timer = 0; } finish_contexts(g_ceph_context, waiting_for_finished_proposal, -EAGAIN); on_shutdown(); } void PaxosService::maybe_trim() { if (!is_writeable()) return; version_t trim_to = get_trim_to(); if (trim_to < get_first_committed()) return; version_t to_remove = trim_to - get_first_committed(); if (g_conf->paxos_service_trim_min > 0 && to_remove < (version_t)g_conf->paxos_service_trim_min) { dout(10) << __func__ << " trim_to " << trim_to << " would only trim " << to_remove << " < paxos_service_trim_min " << g_conf->paxos_service_trim_min << dendl; return; } if (g_conf->paxos_service_trim_max > 0 && to_remove > (version_t)g_conf->paxos_service_trim_max) { dout(10) << __func__ << " trim_to " << trim_to << " would only trim " << to_remove << " > paxos_service_trim_max, limiting to " << g_conf->paxos_service_trim_max << dendl; trim_to = get_first_committed() + g_conf->paxos_service_trim_max; to_remove = trim_to - get_first_committed(); } dout(10) << __func__ << " trimming to " << trim_to << ", " << to_remove << " states" << dendl; MonitorDBStore::Transaction t; trim(&t, get_first_committed(), trim_to); put_first_committed(&t, trim_to); // let the service add any extra stuff encode_trim_extra(&t, trim_to); bufferlist bl; t.encode(bl); paxos->propose_new_value(bl, NULL); } void PaxosService::trim(MonitorDBStore::Transaction *t, version_t from, version_t to) { dout(10) << __func__ << " from " << from << " to " << to << dendl; assert(from != to); for (version_t v = from; v < to; ++v) { dout(20) << __func__ << " " << v << dendl; t->erase(get_service_name(), v); string full_key = mon->store->combine_strings("full", v); if (mon->store->exists(get_service_name(), full_key)) { dout(20) << __func__ << " " << full_key << dendl; t->erase(get_service_name(), full_key); } } if (g_conf->mon_compact_on_trim) { dout(20) << " compacting prefix " << get_service_name() << dendl; t->compact_range(get_service_name(), stringify(from - 1), stringify(to)); } } ceph-0.80.11/src/mon/DataHealthService.cc0000664000175100017510000001742712623076744022117 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "include/memory.h" #include #include #include #include #include #include "acconfig.h" #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include "messages/MMonHealth.h" #include "include/types.h" #include "include/Context.h" #include "include/assert.h" #include "common/Formatter.h" #include "common/errno.h" #include "mon/Monitor.h" #include "mon/QuorumService.h" #include "mon/DataHealthService.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, this) static ostream& _prefix(std::ostream *_dout, const Monitor *mon, const DataHealthService *svc) { assert(mon != NULL); assert(svc != NULL); return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ")." << svc->get_name() << "(" << svc->get_epoch() << ") "; } void DataHealthService::start_epoch() { dout(10) << __func__ << " epoch " << get_epoch() << dendl; // we are not bound by election epochs, but we should clear the stats // everytime an election is triggerd. As far as we know, a monitor might // have been running out of disk space and someone fixed it. We don't want // to hold the cluster back, even confusing the user, due to some possibly // outdated stats. stats.clear(); last_warned_percent = 0; } void DataHealthService::get_health( Formatter *f, list >& summary, list > *detail) { dout(10) << __func__ << dendl; if (f) { f->open_object_section("data_health"); f->open_array_section("mons"); } for (map::iterator it = stats.begin(); it != stats.end(); ++it) { string mon_name = mon->monmap->get_name(it->first.addr); DataStats& stats = it->second; health_status_t health_status = HEALTH_OK; string health_detail; if (stats.fs_stats.avail_percent <= g_conf->mon_data_avail_crit) { health_status = HEALTH_ERR; health_detail = "low disk space, shutdown imminent"; } else if (stats.fs_stats.avail_percent <= g_conf->mon_data_avail_warn) { health_status = HEALTH_WARN; health_detail = "low disk space"; } if (stats.store_stats.bytes_total >= g_conf->mon_leveldb_size_warn) { if (health_status > HEALTH_WARN) health_status = HEALTH_WARN; if (!health_detail.empty()) health_detail.append("; "); stringstream ss; ss << "store is getting too big! " << prettybyte_t(stats.store_stats.bytes_total) << " >= " << prettybyte_t(g_conf->mon_leveldb_size_warn); health_detail.append(ss.str()); } if (health_status != HEALTH_OK) { stringstream ss; ss << "mon." << mon_name << " " << health_detail; summary.push_back(make_pair(health_status, ss.str())); ss << " -- " << stats.fs_stats.avail_percent << "% avail"; if (detail) detail->push_back(make_pair(health_status, ss.str())); } if (f) { f->open_object_section("mon"); f->dump_string("name", mon_name.c_str()); // leave this unenclosed by an object section to avoid breaking backward-compatibility stats.dump(f); f->dump_stream("health") << health_status; if (health_status != HEALTH_OK) f->dump_string("health_detail", health_detail); f->close_section(); } } if (f) { f->close_section(); // mons f->close_section(); // data_health } } int DataHealthService::update_store_stats(DataStats &ours) { map extra; uint64_t store_size = mon->store->get_estimated_size(extra); assert(store_size > 0); ours.store_stats.bytes_total = store_size; ours.store_stats.bytes_sst = extra["sst"]; ours.store_stats.bytes_log = extra["log"]; ours.store_stats.bytes_misc = extra["misc"]; ours.last_update = ceph_clock_now(g_ceph_context); return 0; } int DataHealthService::update_stats() { entity_inst_t our_inst = mon->messenger->get_myinst(); DataStats& ours = stats[our_inst]; int err = get_fs_stats(ours.fs_stats, g_conf->mon_data.c_str()); if (err < 0) { derr << __func__ << " get_fs_stats error: " << cpp_strerror(err) << dendl; return err; } dout(0) << __func__ << " avail " << ours.fs_stats.avail_percent << "%" << " total " << prettybyte_t(ours.fs_stats.byte_total) << ", used " << prettybyte_t(ours.fs_stats.byte_used) << ", avail " << prettybyte_t(ours.fs_stats.byte_avail) << dendl; ours.last_update = ceph_clock_now(g_ceph_context); return update_store_stats(ours); } void DataHealthService::share_stats() { dout(10) << __func__ << dendl; if (!in_quorum()) return; assert(!stats.empty()); entity_inst_t our_inst = mon->messenger->get_myinst(); assert(stats.count(our_inst) > 0); DataStats &ours = stats[our_inst]; const set& quorum = mon->get_quorum(); for (set::const_iterator it = quorum.begin(); it != quorum.end(); ++it) { if (mon->monmap->get_name(*it) == mon->name) continue; entity_inst_t inst = mon->monmap->get_inst(*it); MMonHealth *m = new MMonHealth(HealthService::SERVICE_HEALTH_DATA, MMonHealth::OP_TELL); m->data_stats = ours; dout(20) << __func__ << " send " << *m << " to " << inst << dendl; mon->messenger->send_message(m, inst); } } void DataHealthService::service_tick() { dout(10) << __func__ << dendl; int err = update_stats(); if (err < 0) { derr << "something went wrong obtaining our disk stats: " << cpp_strerror(err) << dendl; force_shutdown(); return; } if (in_quorum()) share_stats(); DataStats &ours = stats[mon->messenger->get_myinst()]; if (ours.fs_stats.avail_percent <= g_conf->mon_data_avail_crit) { derr << "reached critical levels of available space on local monitor storage" << " -- shutdown!" << dendl; force_shutdown(); return; } // we must backoff these warnings, and track how much data is being // consumed in-between reports to assess if it's worth to log this info, // otherwise we may very well contribute to the consumption of the // already low available disk space. if (ours.fs_stats.avail_percent <= g_conf->mon_data_avail_warn) { if (ours.fs_stats.avail_percent != last_warned_percent) mon->clog.warn() << "reached concerning levels of available space on local monitor storage" << " (" << ours.fs_stats.avail_percent << "% free)\n"; last_warned_percent = ours.fs_stats.avail_percent; } else { last_warned_percent = 0; } } void DataHealthService::handle_tell(MMonHealth *m) { dout(10) << __func__ << " " << *m << dendl; assert(m->get_service_op() == MMonHealth::OP_TELL); stats[m->get_source_inst()] = m->data_stats; } bool DataHealthService::service_dispatch(MMonHealth *m) { dout(10) << __func__ << " " << *m << dendl; assert(m->get_service_type() == get_type()); if (!in_quorum()) { dout(1) << __func__ << " not in quorum -- drop message" << dendl; m->put(); return false; } switch (m->service_op) { case MMonHealth::OP_TELL: // someone is telling us their stats handle_tell(m); break; default: dout(0) << __func__ << " unknown op " << m->service_op << dendl; assert(0 == "Unknown service op"); break; } m->put(); return true; } ceph-0.80.11/src/mon/OSDMonitor.cc0000664000175100017510000057202312623076744020572 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "OSDMonitor.h" #include "Monitor.h" #include "MDSMonitor.h" #include "PGMonitor.h" #include "MonitorDBStore.h" #include "crush/CrushWrapper.h" #include "crush/CrushTester.h" #include "messages/MOSDFailure.h" #include "messages/MOSDMarkMeDown.h" #include "messages/MOSDMap.h" #include "messages/MOSDBoot.h" #include "messages/MOSDAlive.h" #include "messages/MPoolOp.h" #include "messages/MPoolOpReply.h" #include "messages/MOSDPGTemp.h" #include "messages/MMonCommand.h" #include "messages/MRemoveSnaps.h" #include "messages/MOSDScrub.h" #include "common/Timer.h" #include "common/ceph_argparse.h" #include "common/perf_counters.h" #include "common/strtol.h" #include "common/config.h" #include "common/errno.h" #include "erasure-code/ErasureCodePlugin.h" #include "include/compat.h" #include "include/assert.h" #include "include/stringify.h" #include "include/util.h" #include "common/cmdparse.h" #include "include/str_list.h" #include "include/str_map.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, osdmap) static ostream& _prefix(std::ostream *_dout, Monitor *mon, OSDMap& osdmap) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").osd e" << osdmap.get_epoch() << " "; } OSDMonitor::OSDMonitor(Monitor *mn, Paxos *p, string service_name) : PaxosService(mn, p, service_name), inc_osd_cache(g_conf->mon_osd_cache_size), full_osd_cache(g_conf->mon_osd_cache_size), thrash_map(0), thrash_last_up_osd(-1) { } bool OSDMonitor::_have_pending_crush() { return pending_inc.crush.length(); } CrushWrapper &OSDMonitor::_get_stable_crush() { return *osdmap.crush; } void OSDMonitor::_get_pending_crush(CrushWrapper& newcrush) { bufferlist bl; if (pending_inc.crush.length()) bl = pending_inc.crush; else osdmap.crush->encode(bl); bufferlist::iterator p = bl.begin(); newcrush.decode(p); } void OSDMonitor::create_initial() { dout(10) << "create_initial for " << mon->monmap->fsid << dendl; OSDMap newmap; bufferlist bl; mon->store->get("mkfs", "osdmap", bl); if (bl.length()) { newmap.decode(bl); newmap.set_fsid(mon->monmap->fsid); } else { newmap.build_simple(g_ceph_context, 0, mon->monmap->fsid, 0, g_conf->osd_pg_bits, g_conf->osd_pgp_bits); } newmap.set_epoch(1); newmap.created = newmap.modified = ceph_clock_now(g_ceph_context); // encode into pending incremental newmap.encode(pending_inc.fullmap, mon->quorum_features); } void OSDMonitor::update_from_paxos(bool *need_bootstrap) { version_t version = get_last_committed(); if (version == osdmap.epoch) return; assert(version >= osdmap.epoch); dout(15) << "update_from_paxos paxos e " << version << ", my e " << osdmap.epoch << dendl; /* * We will possibly have a stashed latest that *we* wrote, and we will * always be sure to have the oldest full map in the first..last range * due to encode_trim_extra(), which includes the oldest full map in the trim * transaction. * * encode_trim_extra() does not however write the full map's * version to 'full_latest'. This is only done when we are building the * full maps from the incremental versions. But don't panic! We make sure * that the following conditions find whichever full map version is newer. */ version_t latest_full = get_version_latest_full(); if (latest_full == 0 && get_first_committed() > 1) latest_full = get_first_committed(); if (latest_full > 0) { // make sure we can really believe get_version_latest_full(); see // 76cd7ac1c2094b34ad36bea89b2246fa90eb2f6d bufferlist test; get_version_full(latest_full, test); if (test.length() == 0) { dout(10) << __func__ << " ignoring recorded latest_full as it is missing; fallback to search" << dendl; latest_full = 0; } } if (get_first_committed() > 1 && latest_full < get_first_committed()) { /* a bug introduced in 7fb3804fb860dcd0340dd3f7c39eec4315f8e4b6 would lead * us to not update the on-disk latest_full key. Upon trim, the actual * version would cease to exist but we would still point to it. This * makes sure we get it pointing to a proper version. */ version_t lc = get_last_committed(); version_t fc = get_first_committed(); dout(10) << __func__ << " looking for valid full map in interval" << " [" << fc << ", " << lc << "]" << dendl; latest_full = 0; for (version_t v = lc; v >= fc; v--) { string full_key = "full_" + stringify(v); if (mon->store->exists(get_service_name(), full_key)) { dout(10) << __func__ << " found latest full map v " << v << dendl; latest_full = v; break; } } // if we trigger this, then there's something else going with the store // state, and we shouldn't want to work around it without knowing what // exactly happened. assert(latest_full > 0); MonitorDBStore::Transaction t; put_version_latest_full(&t, latest_full); mon->store->apply_transaction(t); dout(10) << __func__ << " updated the on-disk full map version to " << latest_full << dendl; } if ((latest_full > 0) && (latest_full > osdmap.epoch)) { bufferlist latest_bl; get_version_full(latest_full, latest_bl); assert(latest_bl.length() != 0); dout(7) << __func__ << " loading latest full map e" << latest_full << dendl; osdmap.decode(latest_bl); } // walk through incrementals MonitorDBStore::Transaction *t = NULL; size_t tx_size = 0; while (version > osdmap.epoch) { bufferlist inc_bl; int err = get_version(osdmap.epoch+1, inc_bl); assert(err == 0); assert(inc_bl.length()); dout(7) << "update_from_paxos applying incremental " << osdmap.epoch+1 << dendl; OSDMap::Incremental inc(inc_bl); err = osdmap.apply_incremental(inc); assert(err == 0); if (t == NULL) t = new MonitorDBStore::Transaction; // Write out the full map for all past epochs. Encode the full // map with the same features as the incremental. If we don't // know, use the quorum features. If we don't know those either, // encode with all features. uint64_t f = inc.encode_features; if (!f) f = mon->quorum_features; if (!f) f = -1; bufferlist full_bl; osdmap.encode(full_bl, f); tx_size += full_bl.length(); put_version_full(t, osdmap.epoch, full_bl); put_version_latest_full(t, osdmap.epoch); // share dout(1) << osdmap << dendl; if (osdmap.epoch == 1) { t->erase("mkfs", "osdmap"); } if (tx_size > g_conf->mon_sync_max_payload_size*2) { mon->store->apply_transaction(*t); delete t; t = NULL; tx_size = 0; } } if (t != NULL) { mon->store->apply_transaction(*t); delete t; } for (int o = 0; o < osdmap.get_max_osd(); o++) { if (osdmap.is_down(o)) { // invalidate osd_epoch cache osd_epoch.erase(o); // populate down -> out map if (osdmap.is_in(o) && down_pending_out.count(o) == 0) { dout(10) << " adding osd." << o << " to down_pending_out map" << dendl; down_pending_out[o] = ceph_clock_now(g_ceph_context); } } } // blow away any osd_epoch items beyond max_osd map::iterator p = osd_epoch.upper_bound(osdmap.get_max_osd()); while (p != osd_epoch.end()) { osd_epoch.erase(p++); } /** we don't have any of the feature bit infrastructure in place for * supporting primary_temp mappings without breaking old clients/OSDs.*/ assert(g_conf->mon_osd_allow_primary_temp || osdmap.primary_temp->empty()); if (mon->is_leader()) { // kick pgmon, make sure it's seen the latest map mon->pgmon()->check_osd_map(osdmap.epoch); } check_subs(); share_map_with_random_osd(); update_logger(); process_failures(); // make sure our feature bits reflect the latest map update_msgr_features(); } void OSDMonitor::update_msgr_features() { set types; types.insert((int)entity_name_t::TYPE_OSD); types.insert((int)entity_name_t::TYPE_CLIENT); types.insert((int)entity_name_t::TYPE_MDS); types.insert((int)entity_name_t::TYPE_MON); for (set::iterator q = types.begin(); q != types.end(); ++q) { uint64_t mask; uint64_t features = osdmap.get_features(*q, &mask); if ((mon->messenger->get_policy(*q).features_required & mask) != features) { dout(0) << "crush map has features " << features << ", adjusting msgr requires" << dendl; Messenger::Policy p = mon->messenger->get_policy(*q); p.features_required = (p.features_required & ~mask) | features; mon->messenger->set_policy(*q, p); } } } bool OSDMonitor::thrash() { if (!thrash_map) return false; thrash_map--; int o; // mark a random osd up_thru.. if (rand() % 4 == 0 || thrash_last_up_osd < 0) o = rand() % osdmap.get_num_osds(); else o = thrash_last_up_osd; if (osdmap.is_up(o)) { dout(5) << "thrash_map osd." << o << " up_thru" << dendl; pending_inc.new_up_thru[o] = osdmap.get_epoch(); } // mark a random osd up/down o = rand() % osdmap.get_num_osds(); if (osdmap.is_up(o)) { dout(5) << "thrash_map osd." << o << " down" << dendl; pending_inc.new_state[o] = CEPH_OSD_UP; } else if (osdmap.exists(o)) { dout(5) << "thrash_map osd." << o << " up" << dendl; pending_inc.new_state[o] = CEPH_OSD_UP; pending_inc.new_up_client[o] = entity_addr_t(); pending_inc.new_up_cluster[o] = entity_addr_t(); pending_inc.new_hb_back_up[o] = entity_addr_t(); pending_inc.new_weight[o] = CEPH_OSD_IN; thrash_last_up_osd = o; } // mark a random osd in o = rand() % osdmap.get_num_osds(); if (osdmap.exists(o)) { dout(5) << "thrash_map osd." << o << " in" << dendl; pending_inc.new_weight[o] = CEPH_OSD_IN; } // mark a random osd out o = rand() % osdmap.get_num_osds(); if (osdmap.exists(o)) { dout(5) << "thrash_map osd." << o << " out" << dendl; pending_inc.new_weight[o] = CEPH_OSD_OUT; } // generate some pg_temp entries. // let's assume the ceph::unordered_map iterates in a random-ish order. int n = rand() % mon->pgmon()->pg_map.pg_stat.size(); ceph::unordered_map::iterator p = mon->pgmon()->pg_map.pg_stat.begin(); ceph::unordered_map::iterator e = mon->pgmon()->pg_map.pg_stat.end(); while (n--) ++p; for (int i=0; i<50; i++) { unsigned size = osdmap.get_pg_size(p->first); vector v; bool have_real_osd = false; for (int j=0; j < (int)size; j++) { o = rand() % osdmap.get_num_osds(); if (osdmap.exists(o) && std::find(v.begin(), v.end(), o) == v.end()) { have_real_osd = true; v.push_back(o); } } for (vector::iterator q = p->second.acting.begin(); q != p->second.acting.end() && v.size() < size; ++q) { if (std::find(v.begin(), v.end(), *q) == v.end()) { if (*q != CRUSH_ITEM_NONE) have_real_osd = true; v.push_back(*q); } } if (osdmap.pg_is_ec(p->first)) { while (v.size() < size) v.push_back(CRUSH_ITEM_NONE); } if (!v.empty() && have_real_osd) pending_inc.new_pg_temp[p->first] = v; dout(5) << "thrash_map pg " << p->first << " pg_temp remapped to " << v << dendl; ++p; if (p == e) p = mon->pgmon()->pg_map.pg_stat.begin(); } return true; } void OSDMonitor::on_active() { update_logger(); if (thrash_map) { if (mon->is_leader()) { if (thrash()) propose_pending(); } else { thrash_map = 0; } } if (mon->is_leader()) mon->clog.info() << "osdmap " << osdmap << "\n"; if (!mon->is_leader()) { list ls; take_all_failures(ls); while (!ls.empty()) { dispatch(ls.front()); ls.pop_front(); } } } void OSDMonitor::on_shutdown() { dout(10) << __func__ << dendl; // discard failure info, waiters list ls; take_all_failures(ls); while (!ls.empty()) { ls.front()->put(); ls.pop_front(); } } void OSDMonitor::update_logger() { dout(10) << "update_logger" << dendl; mon->cluster_logger->set(l_cluster_num_osd, osdmap.get_num_osds()); mon->cluster_logger->set(l_cluster_num_osd_up, osdmap.get_num_up_osds()); mon->cluster_logger->set(l_cluster_num_osd_in, osdmap.get_num_in_osds()); mon->cluster_logger->set(l_cluster_osd_epoch, osdmap.get_epoch()); } /* Assign a lower weight to overloaded OSDs. * * The osds that will get a lower weight are those with with a utilization * percentage 'oload' percent greater than the average utilization. */ int OSDMonitor::reweight_by_utilization(int oload, std::string& out_str) { if (oload <= 100) { ostringstream oss; oss << "You must give a percentage higher than 100. " "The reweighting threshold will be calculated as " "times . For example, an argument of 200 would " "reweight OSDs which are twice as utilized as the average OSD.\n"; out_str = oss.str(); dout(0) << "reweight_by_utilization: " << out_str << dendl; return -EINVAL; } // Avoid putting a small number (or 0) in the denominator when calculating // average_util const PGMap &pgm = mon->pgmon()->pg_map; if (pgm.osd_sum.kb < 1024) { ostringstream oss; oss << "Refusing to reweight: we only have " << pgm.osd_sum << " kb " "across all osds!\n"; out_str = oss.str(); dout(0) << "reweight_by_utilization: " << out_str << dendl; return -EDOM; } if (pgm.osd_sum.kb_used < 5 * 1024) { ostringstream oss; oss << "Refusing to reweight: we only have " << pgm.osd_sum << " kb " "used across all osds!\n"; out_str = oss.str(); dout(0) << "reweight_by_utilization: " << out_str << dendl; return -EDOM; } float average_util = pgm.osd_sum.kb_used; average_util /= pgm.osd_sum.kb; float overload_util = average_util * oload / 100.0; ostringstream oss; char buf[128]; snprintf(buf, sizeof(buf), "average_util: %04f, overload_util: %04f. ", average_util, overload_util); oss << buf; std::string sep; oss << "overloaded osds: "; bool changed = false; for (ceph::unordered_map::const_iterator p = pgm.osd_stat.begin(); p != pgm.osd_stat.end(); ++p) { float util = p->second.kb_used; util /= p->second.kb; if (util >= overload_util) { sep = ", "; // Assign a lower weight to overloaded OSDs. The current weight // is a factor to take into account the original weights, // to represent e.g. differing storage capacities unsigned weight = osdmap.get_weight(p->first); unsigned new_weight = (unsigned)((average_util / util) * (float)weight); pending_inc.new_weight[p->first] = new_weight; char buf[128]; snprintf(buf, sizeof(buf), "%d [%04f -> %04f]", p->first, (float)weight / (float)0x10000, (float)new_weight / (float)0x10000); oss << buf << sep; changed = true; } } if (sep.empty()) { oss << "(none)"; } out_str = oss.str(); dout(0) << "reweight_by_utilization: finished with " << out_str << dendl; return changed; } void OSDMonitor::create_pending() { pending_inc = OSDMap::Incremental(osdmap.epoch+1); pending_inc.fsid = mon->monmap->fsid; dout(10) << "create_pending e " << pending_inc.epoch << dendl; // drop any redundant pg_temp entries OSDMap::remove_redundant_temporaries(g_ceph_context, osdmap, &pending_inc); // drop any pg or primary_temp entries with no up entries OSDMap::remove_down_temps(g_ceph_context, osdmap, &pending_inc); } /** * @note receiving a transaction in this function gives a fair amount of * freedom to the service implementation if it does need it. It shouldn't. */ void OSDMonitor::encode_pending(MonitorDBStore::Transaction *t) { dout(10) << "encode_pending e " << pending_inc.epoch << dendl; // finalize up pending_inc pending_inc.modified = ceph_clock_now(g_ceph_context); int r = pending_inc.propagate_snaps_to_tiers(g_ceph_context, osdmap); assert(r == 0); bufferlist bl; // tell me about it for (map::iterator i = pending_inc.new_state.begin(); i != pending_inc.new_state.end(); ++i) { int s = i->second ? i->second : CEPH_OSD_UP; if (s & CEPH_OSD_UP) dout(2) << " osd." << i->first << " DOWN" << dendl; if (s & CEPH_OSD_EXISTS) dout(2) << " osd." << i->first << " DNE" << dendl; } for (map::iterator i = pending_inc.new_up_client.begin(); i != pending_inc.new_up_client.end(); ++i) { //FIXME: insert cluster addresses too dout(2) << " osd." << i->first << " UP " << i->second << dendl; } for (map::iterator i = pending_inc.new_weight.begin(); i != pending_inc.new_weight.end(); ++i) { if (i->second == CEPH_OSD_OUT) { dout(2) << " osd." << i->first << " OUT" << dendl; } else if (i->second == CEPH_OSD_IN) { dout(2) << " osd." << i->first << " IN" << dendl; } else { dout(2) << " osd." << i->first << " WEIGHT " << hex << i->second << dec << dendl; } } // encode assert(get_last_committed() + 1 == pending_inc.epoch); ::encode(pending_inc, bl, mon->quorum_features); /* put everything in the transaction */ put_version(t, pending_inc.epoch, bl); put_last_committed(t, pending_inc.epoch); // metadata, too! for (map::iterator p = pending_metadata.begin(); p != pending_metadata.end(); ++p) t->put(OSD_METADATA_PREFIX, stringify(p->first), p->second); for (set::iterator p = pending_metadata_rm.begin(); p != pending_metadata_rm.end(); ++p) t->erase(OSD_METADATA_PREFIX, stringify(*p)); pending_metadata.clear(); pending_metadata_rm.clear(); } int OSDMonitor::dump_osd_metadata(int osd, Formatter *f, ostream *err) { bufferlist bl; int r = mon->store->get(OSD_METADATA_PREFIX, stringify(osd), bl); if (r < 0) return r; map m; try { bufferlist::iterator p = bl.begin(); ::decode(m, p); } catch (buffer::error& e) { if (err) *err << "osd." << osd << " metadata is corrupt"; return -EIO; } for (map::iterator p = m.begin(); p != m.end(); ++p) f->dump_string(p->first.c_str(), p->second); return 0; } void OSDMonitor::share_map_with_random_osd() { if (osdmap.get_num_up_osds() == 0) { dout(10) << __func__ << " no up osds, don't share with anyone" << dendl; return; } MonSession *s = mon->session_map.get_random_osd_session(&osdmap); if (!s) { dout(10) << __func__ << " no up osd on our session map" << dendl; return; } dout(10) << "committed, telling random " << s->inst << " all about it" << dendl; // whatev, they'll request more if they need it MOSDMap *m = build_incremental(osdmap.get_epoch() - 1, osdmap.get_epoch()); mon->messenger->send_message(m, s->inst); } version_t OSDMonitor::get_trim_to() { if (mon->pgmon()->is_readable() && mon->pgmon()->pg_map.creating_pgs.empty()) { epoch_t floor = mon->pgmon()->pg_map.get_min_last_epoch_clean(); dout(10) << " min_last_epoch_clean " << floor << dendl; if (g_conf->mon_osd_force_trim_to > 0 && g_conf->mon_osd_force_trim_to < (int)get_last_committed()) { floor = g_conf->mon_osd_force_trim_to; dout(10) << " explicit mon_osd_force_trim_to = " << floor << dendl; } unsigned min = g_conf->mon_min_osdmap_epochs; if (floor + min > get_last_committed()) { if (min < get_last_committed()) floor = get_last_committed() - min; else floor = 0; } if (floor > get_first_committed()) return floor; } return 0; } void OSDMonitor::encode_trim_extra(MonitorDBStore::Transaction *tx, version_t first) { dout(10) << __func__ << " including full map for e " << first << dendl; bufferlist bl; get_version_full(first, bl); put_version_full(tx, first, bl); } // ------------- bool OSDMonitor::preprocess_query(PaxosServiceMessage *m) { dout(10) << "preprocess_query " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { // READs case MSG_MON_COMMAND: return preprocess_command(static_cast(m)); // damp updates case MSG_OSD_MARK_ME_DOWN: return preprocess_mark_me_down(static_cast(m)); case MSG_OSD_FAILURE: return preprocess_failure(static_cast(m)); case MSG_OSD_BOOT: return preprocess_boot(static_cast(m)); case MSG_OSD_ALIVE: return preprocess_alive(static_cast(m)); case MSG_OSD_PGTEMP: return preprocess_pgtemp(static_cast(m)); case CEPH_MSG_POOLOP: return preprocess_pool_op(static_cast(m)); case MSG_REMOVE_SNAPS: return preprocess_remove_snaps(static_cast(m)); default: assert(0); m->put(); return true; } } bool OSDMonitor::prepare_update(PaxosServiceMessage *m) { dout(7) << "prepare_update " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { // damp updates case MSG_OSD_MARK_ME_DOWN: return prepare_mark_me_down(static_cast(m)); case MSG_OSD_FAILURE: return prepare_failure(static_cast(m)); case MSG_OSD_BOOT: return prepare_boot(static_cast(m)); case MSG_OSD_ALIVE: return prepare_alive(static_cast(m)); case MSG_OSD_PGTEMP: return prepare_pgtemp(static_cast(m)); case MSG_MON_COMMAND: return prepare_command(static_cast(m)); case CEPH_MSG_POOLOP: return prepare_pool_op(static_cast(m)); case MSG_REMOVE_SNAPS: return prepare_remove_snaps(static_cast(m)); default: assert(0); m->put(); } return false; } bool OSDMonitor::should_propose(double& delay) { dout(10) << "should_propose" << dendl; // if full map, propose immediately! any subsequent changes will be clobbered. if (pending_inc.fullmap.length()) return true; // adjust osd weights? if (!osd_weight.empty() && osd_weight.size() == (unsigned)osdmap.get_max_osd()) { dout(0) << " adjusting osd weights based on " << osd_weight << dendl; osdmap.adjust_osd_weights(osd_weight, pending_inc); delay = 0.0; osd_weight.clear(); return true; } return PaxosService::should_propose(delay); } // --------------------------- // READs // --------------------------- // UPDATEs // failure -- bool OSDMonitor::check_source(PaxosServiceMessage *m, uuid_d fsid) { // check permissions MonSession *session = m->get_session(); if (!session) return true; if (!session->is_capable("osd", MON_CAP_X)) { dout(0) << "got MOSDFailure from entity with insufficient caps " << session->caps << dendl; return true; } if (fsid != mon->monmap->fsid) { dout(0) << "check_source: on fsid " << fsid << " != " << mon->monmap->fsid << dendl; return true; } return false; } bool OSDMonitor::preprocess_failure(MOSDFailure *m) { // who is target_osd int badboy = m->get_target().name.num(); // check permissions if (check_source(m, m->fsid)) goto didit; // first, verify the reporting host is valid if (m->get_orig_source().is_osd()) { int from = m->get_orig_source().num(); if (!osdmap.exists(from) || osdmap.get_addr(from) != m->get_orig_source_inst().addr || osdmap.is_down(from)) { dout(5) << "preprocess_failure from dead osd." << from << ", ignoring" << dendl; send_incremental(m, m->get_epoch()+1); goto didit; } } // weird? if (!osdmap.have_inst(badboy)) { dout(5) << "preprocess_failure dne(/dup?): " << m->get_target() << ", from " << m->get_orig_source_inst() << dendl; if (m->get_epoch() < osdmap.get_epoch()) send_incremental(m, m->get_epoch()+1); goto didit; } if (osdmap.get_inst(badboy) != m->get_target()) { dout(5) << "preprocess_failure wrong osd: report " << m->get_target() << " != map's " << osdmap.get_inst(badboy) << ", from " << m->get_orig_source_inst() << dendl; if (m->get_epoch() < osdmap.get_epoch()) send_incremental(m, m->get_epoch()+1); goto didit; } // already reported? if (osdmap.is_down(badboy) || osdmap.get_up_from(badboy) > m->get_epoch()) { dout(5) << "preprocess_failure dup/old: " << m->get_target() << ", from " << m->get_orig_source_inst() << dendl; if (m->get_epoch() < osdmap.get_epoch()) send_incremental(m, m->get_epoch()+1); goto didit; } if (!can_mark_down(badboy)) { dout(5) << "preprocess_failure ignoring report of " << m->get_target() << " from " << m->get_orig_source_inst() << dendl; goto didit; } dout(10) << "preprocess_failure new: " << m->get_target() << ", from " << m->get_orig_source_inst() << dendl; return false; didit: m->put(); return true; } class C_AckMarkedDown : public Context { OSDMonitor *osdmon; MOSDMarkMeDown *m; public: C_AckMarkedDown( OSDMonitor *osdmon, MOSDMarkMeDown *m) : osdmon(osdmon), m(m) {} void finish(int) { osdmon->mon->send_reply( m, new MOSDMarkMeDown( m->fsid, m->get_target(), m->get_epoch(), m->ack)); } ~C_AckMarkedDown() { m->put(); } }; bool OSDMonitor::preprocess_mark_me_down(MOSDMarkMeDown *m) { int requesting_down = m->get_target().name.num(); int from = m->get_orig_source().num(); // check permissions if (check_source(m, m->fsid)) goto reply; // first, verify the reporting host is valid if (!m->get_orig_source().is_osd()) goto reply; if (!osdmap.exists(from) || osdmap.is_down(from) || osdmap.get_addr(from) != m->get_target().addr) { dout(5) << "preprocess_mark_me_down from dead osd." << from << ", ignoring" << dendl; send_incremental(m, m->get_epoch()+1); goto reply; } // no down might be set if (!can_mark_down(requesting_down)) goto reply; dout(10) << "MOSDMarkMeDown for: " << m->get_target() << dendl; return false; reply: Context *c(new C_AckMarkedDown(this, m)); c->complete(0); return true; } bool OSDMonitor::prepare_mark_me_down(MOSDMarkMeDown *m) { int target_osd = m->get_target().name.num(); assert(osdmap.is_up(target_osd)); assert(osdmap.get_addr(target_osd) == m->get_target().addr); mon->clog.info() << "osd." << target_osd << " marked itself down\n"; pending_inc.new_state[target_osd] = CEPH_OSD_UP; wait_for_finished_proposal(new C_AckMarkedDown(this, m)); return true; } bool OSDMonitor::can_mark_down(int i) { if (osdmap.test_flag(CEPH_OSDMAP_NODOWN)) { dout(5) << "can_mark_down NODOWN flag set, will not mark osd." << i << " down" << dendl; return false; } int up = osdmap.get_num_up_osds() - pending_inc.get_net_marked_down(&osdmap); float up_ratio = (float)up / (float)osdmap.get_num_osds(); if (up_ratio < g_conf->mon_osd_min_up_ratio) { dout(5) << "can_mark_down current up_ratio " << up_ratio << " < min " << g_conf->mon_osd_min_up_ratio << ", will not mark osd." << i << " down" << dendl; return false; } return true; } bool OSDMonitor::can_mark_up(int i) { if (osdmap.test_flag(CEPH_OSDMAP_NOUP)) { dout(5) << "can_mark_up NOUP flag set, will not mark osd." << i << " up" << dendl; return false; } return true; } /** * @note the parameter @p i apparently only exists here so we can output the * osd's id on messages. */ bool OSDMonitor::can_mark_out(int i) { if (osdmap.test_flag(CEPH_OSDMAP_NOOUT)) { dout(5) << "can_mark_out NOOUT flag set, will not mark osds out" << dendl; return false; } int in = osdmap.get_num_in_osds() - pending_inc.get_net_marked_out(&osdmap); float in_ratio = (float)in / (float)osdmap.get_num_osds(); if (in_ratio < g_conf->mon_osd_min_in_ratio) { if (i >= 0) dout(5) << "can_mark_down current in_ratio " << in_ratio << " < min " << g_conf->mon_osd_min_in_ratio << ", will not mark osd." << i << " out" << dendl; else dout(5) << "can_mark_down current in_ratio " << in_ratio << " < min " << g_conf->mon_osd_min_in_ratio << ", will not mark osds out" << dendl; return false; } return true; } bool OSDMonitor::can_mark_in(int i) { if (osdmap.test_flag(CEPH_OSDMAP_NOIN)) { dout(5) << "can_mark_in NOIN flag set, will not mark osd." << i << " in" << dendl; return false; } return true; } void OSDMonitor::check_failures(utime_t now) { for (map::iterator p = failure_info.begin(); p != failure_info.end(); ++p) { check_failure(now, p->first, p->second); } } bool OSDMonitor::check_failure(utime_t now, int target_osd, failure_info_t& fi) { utime_t orig_grace(g_conf->osd_heartbeat_grace, 0); utime_t max_failed_since = fi.get_failed_since(); utime_t failed_for = now - max_failed_since; utime_t grace = orig_grace; double my_grace = 0, peer_grace = 0; if (g_conf->mon_osd_adjust_heartbeat_grace) { double halflife = (double)g_conf->mon_osd_laggy_halflife; double decay_k = ::log(.5) / halflife; // scale grace period based on historical probability of 'lagginess' // (false positive failures due to slowness). const osd_xinfo_t& xi = osdmap.get_xinfo(target_osd); double decay = exp((double)failed_for * decay_k); dout(20) << " halflife " << halflife << " decay_k " << decay_k << " failed_for " << failed_for << " decay " << decay << dendl; my_grace = decay * (double)xi.laggy_interval * xi.laggy_probability; grace += my_grace; // consider the peers reporting a failure a proxy for a potential // 'subcluster' over the overall cluster that is similarly // laggy. this is clearly not true in all cases, but will sometimes // help us localize the grace correction to a subset of the system // (say, a rack with a bad switch) that is unhappy. assert(fi.reporters.size()); for (map::iterator p = fi.reporters.begin(); p != fi.reporters.end(); ++p) { const osd_xinfo_t& xi = osdmap.get_xinfo(p->first); utime_t elapsed = now - xi.down_stamp; double decay = exp((double)elapsed * decay_k); peer_grace += decay * (double)xi.laggy_interval * xi.laggy_probability; } peer_grace /= (double)fi.reporters.size(); grace += peer_grace; } dout(10) << " osd." << target_osd << " has " << fi.reporters.size() << " reporters and " << fi.num_reports << " reports, " << grace << " grace (" << orig_grace << " + " << my_grace << " + " << peer_grace << "), max_failed_since " << max_failed_since << dendl; // already pending failure? if (pending_inc.new_state.count(target_osd) && pending_inc.new_state[target_osd] & CEPH_OSD_UP) { dout(10) << " already pending failure" << dendl; return true; } if (failed_for >= grace && ((int)fi.reporters.size() >= g_conf->mon_osd_min_down_reporters) && (fi.num_reports >= g_conf->mon_osd_min_down_reports)) { dout(1) << " we have enough reports/reporters to mark osd." << target_osd << " down" << dendl; pending_inc.new_state[target_osd] = CEPH_OSD_UP; mon->clog.info() << osdmap.get_inst(target_osd) << " failed (" << fi.num_reports << " reports from " << (int)fi.reporters.size() << " peers after " << failed_for << " >= grace " << grace << ")\n"; return true; } return false; } bool OSDMonitor::prepare_failure(MOSDFailure *m) { dout(1) << "prepare_failure " << m->get_target() << " from " << m->get_orig_source_inst() << " is reporting failure:" << m->if_osd_failed() << dendl; int target_osd = m->get_target().name.num(); int reporter = m->get_orig_source().num(); assert(osdmap.is_up(target_osd)); assert(osdmap.get_addr(target_osd) == m->get_target().addr); // calculate failure time utime_t now = ceph_clock_now(g_ceph_context); utime_t failed_since = m->get_recv_stamp() - utime_t(m->failed_for ? m->failed_for : g_conf->osd_heartbeat_grace, 0); if (m->if_osd_failed()) { // add a report mon->clog.debug() << m->get_target() << " reported failed by " << m->get_orig_source_inst() << "\n"; failure_info_t& fi = failure_info[target_osd]; MOSDFailure *old = fi.add_report(reporter, failed_since, m); if (old) { mon->no_reply(old); old->put(); } return check_failure(now, target_osd, fi); } else { // remove the report mon->clog.debug() << m->get_target() << " failure report canceled by " << m->get_orig_source_inst() << "\n"; if (failure_info.count(target_osd)) { failure_info_t& fi = failure_info[target_osd]; list ls; fi.take_report_messages(ls); fi.cancel_report(reporter); while (!ls.empty()) { mon->no_reply(ls.front()); ls.front()->put(); ls.pop_front(); } if (fi.reporters.empty()) { dout(10) << " removing last failure_info for osd." << target_osd << dendl; failure_info.erase(target_osd); } else { dout(10) << " failure_info for osd." << target_osd << " now " << fi.reporters.size() << " reporters and " << fi.num_reports << " reports" << dendl; } } else { dout(10) << " no failure_info for osd." << target_osd << dendl; } mon->no_reply(m); m->put(); } return false; } void OSDMonitor::process_failures() { map::iterator p = failure_info.begin(); while (p != failure_info.end()) { if (osdmap.is_up(p->first)) { ++p; } else { dout(10) << "process_failures osd." << p->first << dendl; list ls; p->second.take_report_messages(ls); failure_info.erase(p++); while (!ls.empty()) { send_latest(ls.front(), ls.front()->get_epoch()); ls.pop_front(); } } } } void OSDMonitor::take_all_failures(list& ls) { dout(10) << __func__ << " on " << failure_info.size() << " osds" << dendl; for (map::iterator p = failure_info.begin(); p != failure_info.end(); ++p) { p->second.take_report_messages(ls); } failure_info.clear(); } // boot -- bool OSDMonitor::preprocess_boot(MOSDBoot *m) { int from = m->get_orig_source_inst().name.num(); // check permissions, ignore if failed (no response expected) MonSession *session = m->get_session(); if (!session) goto ignore; if (!session->is_capable("osd", MON_CAP_X)) { dout(0) << "got preprocess_boot message from entity with insufficient caps" << session->caps << dendl; goto ignore; } if (m->sb.cluster_fsid != mon->monmap->fsid) { dout(0) << "preprocess_boot on fsid " << m->sb.cluster_fsid << " != " << mon->monmap->fsid << dendl; goto ignore; } if (m->get_orig_source_inst().addr.is_blank_ip()) { dout(0) << "preprocess_boot got blank addr for " << m->get_orig_source_inst() << dendl; goto ignore; } assert(m->get_orig_source_inst().name.is_osd()); // check if osd has required features to boot if ((osdmap.get_features(CEPH_ENTITY_TYPE_OSD, NULL) & CEPH_FEATURE_OSD_ERASURE_CODES) && !(m->get_connection()->get_features() & CEPH_FEATURE_OSD_ERASURE_CODES)) { dout(0) << __func__ << " osdmap requires Erasure Codes but osd at " << m->get_orig_source_inst() << " doesn't announce support -- ignore" << dendl; goto ignore; } // already booted? if (osdmap.is_up(from) && osdmap.get_inst(from) == m->get_orig_source_inst()) { // yup. dout(7) << "preprocess_boot dup from " << m->get_orig_source_inst() << " == " << osdmap.get_inst(from) << dendl; _booted(m, false); return true; } if (osdmap.exists(from) && !osdmap.get_uuid(from).is_zero() && osdmap.get_uuid(from) != m->sb.osd_fsid) { dout(7) << __func__ << " from " << m->get_orig_source_inst() << " clashes with existing osd: different fsid" << " (ours: " << osdmap.get_uuid(from) << " ; theirs: " << m->sb.osd_fsid << ")" << dendl; goto ignore; } if (osdmap.exists(from) && osdmap.get_info(from).up_from > m->version) { dout(7) << "prepare_boot msg from before last up_from, ignoring" << dendl; send_latest(m, m->sb.current_epoch+1); return true; } // noup? if (!can_mark_up(from)) { dout(7) << "preprocess_boot ignoring boot from " << m->get_orig_source_inst() << dendl; send_latest(m, m->sb.current_epoch+1); return true; } dout(10) << "preprocess_boot from " << m->get_orig_source_inst() << dendl; return false; ignore: m->put(); return true; } bool OSDMonitor::prepare_boot(MOSDBoot *m) { dout(7) << "prepare_boot from " << m->get_orig_source_inst() << " sb " << m->sb << " cluster_addr " << m->cluster_addr << " hb_back_addr " << m->hb_back_addr << " hb_front_addr " << m->hb_front_addr << dendl; assert(m->get_orig_source().is_osd()); int from = m->get_orig_source().num(); // does this osd exist? if (from >= osdmap.get_max_osd()) { dout(1) << "boot from osd." << from << " >= max_osd " << osdmap.get_max_osd() << dendl; m->put(); return false; } int oldstate = osdmap.exists(from) ? osdmap.get_state(from) : CEPH_OSD_NEW; if (pending_inc.new_state.count(from)) oldstate ^= pending_inc.new_state[from]; // already up? mark down first? if (osdmap.is_up(from)) { dout(7) << "prepare_boot was up, first marking down " << osdmap.get_inst(from) << dendl; // preprocess should have caught these; if not, assert. assert(osdmap.get_inst(from) != m->get_orig_source_inst()); assert(osdmap.get_uuid(from) == m->sb.osd_fsid); if (pending_inc.new_state.count(from) == 0 || (pending_inc.new_state[from] & CEPH_OSD_UP) == 0) { // mark previous guy down pending_inc.new_state[from] = CEPH_OSD_UP; } wait_for_finished_proposal(new C_RetryMessage(this, m)); } else if (pending_inc.new_up_client.count(from)) { //FIXME: should this be using new_up_client? // already prepared, just wait dout(7) << "prepare_boot already prepared, waiting on " << m->get_orig_source_addr() << dendl; wait_for_finished_proposal(new C_RetryMessage(this, m)); } else { // mark new guy up. pending_inc.new_up_client[from] = m->get_orig_source_addr(); if (!m->cluster_addr.is_blank_ip()) pending_inc.new_up_cluster[from] = m->cluster_addr; pending_inc.new_hb_back_up[from] = m->hb_back_addr; if (!m->hb_front_addr.is_blank_ip()) pending_inc.new_hb_front_up[from] = m->hb_front_addr; // mark in? if ((g_conf->mon_osd_auto_mark_auto_out_in && (oldstate & CEPH_OSD_AUTOOUT)) || (g_conf->mon_osd_auto_mark_new_in && (oldstate & CEPH_OSD_NEW)) || (g_conf->mon_osd_auto_mark_in)) { if (can_mark_in(from)) { pending_inc.new_weight[from] = CEPH_OSD_IN; } else { dout(7) << "prepare_boot NOIN set, will not mark in " << m->get_orig_source_addr() << dendl; } } down_pending_out.erase(from); // if any if (m->sb.weight) osd_weight[from] = m->sb.weight; // set uuid? dout(10) << " setting osd." << from << " uuid to " << m->sb.osd_fsid << dendl; if (!osdmap.exists(from) || osdmap.get_uuid(from) != m->sb.osd_fsid) { // preprocess should have caught this; if not, assert. assert(!osdmap.exists(from) || osdmap.get_uuid(from).is_zero()); pending_inc.new_uuid[from] = m->sb.osd_fsid; } // fresh osd? if (m->sb.newest_map == 0 && osdmap.exists(from)) { const osd_info_t& i = osdmap.get_info(from); if (i.up_from > i.lost_at) { dout(10) << " fresh osd; marking lost_at too" << dendl; pending_inc.new_lost[from] = osdmap.get_epoch(); } } // metadata bufferlist osd_metadata; ::encode(m->metadata, osd_metadata); pending_metadata[from] = osd_metadata; // adjust last clean unmount epoch? const osd_info_t& info = osdmap.get_info(from); dout(10) << " old osd_info: " << info << dendl; if (m->sb.mounted > info.last_clean_begin || (m->sb.mounted == info.last_clean_begin && m->sb.clean_thru > info.last_clean_end)) { epoch_t begin = m->sb.mounted; epoch_t end = m->sb.clean_thru; dout(10) << "prepare_boot osd." << from << " last_clean_interval " << "[" << info.last_clean_begin << "," << info.last_clean_end << ")" << " -> [" << begin << "-" << end << ")" << dendl; pending_inc.new_last_clean_interval[from] = pair(begin, end); } osd_xinfo_t xi = osdmap.get_xinfo(from); if (m->boot_epoch == 0) { xi.laggy_probability *= (1.0 - g_conf->mon_osd_laggy_weight); xi.laggy_interval *= (1.0 - g_conf->mon_osd_laggy_weight); dout(10) << " not laggy, new xi " << xi << dendl; } else { if (xi.down_stamp.sec()) { int interval = ceph_clock_now(g_ceph_context).sec() - xi.down_stamp.sec(); xi.laggy_interval = interval * g_conf->mon_osd_laggy_weight + xi.laggy_interval * (1.0 - g_conf->mon_osd_laggy_weight); } xi.laggy_probability = g_conf->mon_osd_laggy_weight + xi.laggy_probability * (1.0 - g_conf->mon_osd_laggy_weight); dout(10) << " laggy, now xi " << xi << dendl; } // set features shared by the osd if (m->osd_features) xi.features = m->osd_features; else xi.features = m->get_connection()->get_features(); pending_inc.new_xinfo[from] = xi; // wait wait_for_finished_proposal(new C_Booted(this, m)); } return true; } void OSDMonitor::_booted(MOSDBoot *m, bool logit) { dout(7) << "_booted " << m->get_orig_source_inst() << " w " << m->sb.weight << " from " << m->sb.current_epoch << dendl; if (logit) { mon->clog.info() << m->get_orig_source_inst() << " boot\n"; } send_latest(m, m->sb.current_epoch+1); } // ------------- // alive bool OSDMonitor::preprocess_alive(MOSDAlive *m) { int from = m->get_orig_source().num(); // check permissions, ignore if failed MonSession *session = m->get_session(); if (!session) goto ignore; if (!session->is_capable("osd", MON_CAP_X)) { dout(0) << "attempt to send MOSDAlive from entity with insufficient privileges:" << session->caps << dendl; goto ignore; } if (!osdmap.is_up(from) || osdmap.get_inst(from) != m->get_orig_source_inst()) { dout(7) << "preprocess_alive ignoring alive message from down " << m->get_orig_source_inst() << dendl; goto ignore; } if (osdmap.get_up_thru(from) >= m->want) { // yup. dout(7) << "preprocess_alive want up_thru " << m->want << " dup from " << m->get_orig_source_inst() << dendl; _reply_map(m, m->version); return true; } dout(10) << "preprocess_alive want up_thru " << m->want << " from " << m->get_orig_source_inst() << dendl; return false; ignore: m->put(); return true; } bool OSDMonitor::prepare_alive(MOSDAlive *m) { int from = m->get_orig_source().num(); if (0) { // we probably don't care much about these mon->clog.debug() << m->get_orig_source_inst() << " alive\n"; } dout(7) << "prepare_alive want up_thru " << m->want << " have " << m->version << " from " << m->get_orig_source_inst() << dendl; pending_inc.new_up_thru[from] = m->version; // set to the latest map the OSD has wait_for_finished_proposal(new C_ReplyMap(this, m, m->version)); return true; } void OSDMonitor::_reply_map(PaxosServiceMessage *m, epoch_t e) { dout(7) << "_reply_map " << e << " from " << m->get_orig_source_inst() << dendl; send_latest(m, e); } // ------------- // pg_temp changes bool OSDMonitor::preprocess_pgtemp(MOSDPGTemp *m) { dout(10) << "preprocess_pgtemp " << *m << dendl; vector empty; int from = m->get_orig_source().num(); size_t ignore_cnt = 0; // check caps MonSession *session = m->get_session(); if (!session) goto ignore; if (!session->is_capable("osd", MON_CAP_X)) { dout(0) << "attempt to send MOSDPGTemp from entity with insufficient caps " << session->caps << dendl; goto ignore; } if (!osdmap.is_up(from) || osdmap.get_inst(from) != m->get_orig_source_inst()) { dout(7) << "ignoring pgtemp message from down " << m->get_orig_source_inst() << dendl; goto ignore; } for (map >::iterator p = m->pg_temp.begin(); p != m->pg_temp.end(); ++p) { dout(20) << " " << p->first << (osdmap.pg_temp->count(p->first) ? (*osdmap.pg_temp)[p->first] : empty) << " -> " << p->second << dendl; // does the pool exist? if (!osdmap.have_pg_pool(p->first.pool())) { /* * 1. If the osdmap does not have the pool, it means the pool has been * removed in-between the osd sending this message and us handling it. * 2. If osdmap doesn't have the pool, it is safe to assume the pool does * not exist in the pending either, as the osds would not send a * message about a pool they know nothing about (yet). * 3. However, if the pool does exist in the pending, then it must be a * new pool, and not relevant to this message (see 1). */ dout(10) << __func__ << " ignore " << p->first << " -> " << p->second << ": pool has been removed" << dendl; ignore_cnt++; continue; } // removal? if (p->second.empty() && (osdmap.pg_temp->count(p->first) || osdmap.primary_temp->count(p->first))) return false; // change? // NOTE: we assume that this will clear pg_primary, so consider // an existing pg_primary field to imply a change if (p->second.size() && (osdmap.pg_temp->count(p->first) == 0 || (*osdmap.pg_temp)[p->first] != p->second || osdmap.primary_temp->count(p->first))) return false; } // should we ignore all the pgs? if (ignore_cnt == m->pg_temp.size()) goto ignore; dout(7) << "preprocess_pgtemp e" << m->map_epoch << " no changes from " << m->get_orig_source_inst() << dendl; _reply_map(m, m->map_epoch); return true; ignore: m->put(); return true; } bool OSDMonitor::prepare_pgtemp(MOSDPGTemp *m) { int from = m->get_orig_source().num(); dout(7) << "prepare_pgtemp e" << m->map_epoch << " from " << m->get_orig_source_inst() << dendl; for (map >::iterator p = m->pg_temp.begin(); p != m->pg_temp.end(); ++p) { uint64_t pool = p->first.pool(); if (pending_inc.old_pools.count(pool)) { dout(10) << __func__ << " ignore " << p->first << " -> " << p->second << ": pool pending removal" << dendl; continue; } if (!osdmap.have_pg_pool(pool)) { dout(10) << __func__ << " ignore " << p->first << " -> " << p->second << ": pool has been removed" << dendl; continue; } pending_inc.new_pg_temp[p->first] = p->second; // unconditionally clear pg_primary (until this message can encode // a change for that, too.. at which point we need to also fix // preprocess_pg_temp) if (osdmap.primary_temp->count(p->first) || pending_inc.new_primary_temp.count(p->first)) pending_inc.new_primary_temp[p->first] = -1; } pending_inc.new_up_thru[from] = m->map_epoch; // set up_thru too, so the osd doesn't have to ask again wait_for_finished_proposal(new C_ReplyMap(this, m, m->map_epoch)); return true; } // --- bool OSDMonitor::preprocess_remove_snaps(MRemoveSnaps *m) { dout(7) << "preprocess_remove_snaps " << *m << dendl; // check privilege, ignore if failed MonSession *session = m->get_session(); if (!session) goto ignore; if (!session->is_capable("osd", MON_CAP_R | MON_CAP_W)) { dout(0) << "got preprocess_remove_snaps from entity with insufficient caps " << session->caps << dendl; goto ignore; } for (map >::iterator q = m->snaps.begin(); q != m->snaps.end(); ++q) { if (!osdmap.have_pg_pool(q->first)) { dout(10) << " ignoring removed_snaps " << q->second << " on non-existent pool " << q->first << dendl; continue; } const pg_pool_t *pi = osdmap.get_pg_pool(q->first); for (vector::iterator p = q->second.begin(); p != q->second.end(); ++p) { if (*p > pi->get_snap_seq() || !pi->removed_snaps.contains(*p)) return false; } } ignore: m->put(); return true; } bool OSDMonitor::prepare_remove_snaps(MRemoveSnaps *m) { dout(7) << "prepare_remove_snaps " << *m << dendl; for (map >::iterator p = m->snaps.begin(); p != m->snaps.end(); ++p) { pg_pool_t& pi = osdmap.pools[p->first]; for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { if (!pi.removed_snaps.contains(*q) && (!pending_inc.new_pools.count(p->first) || !pending_inc.new_pools[p->first].removed_snaps.contains(*q))) { pg_pool_t *newpi = pending_inc.get_new_pool(p->first, &pi); newpi->removed_snaps.insert(*q); dout(10) << " pool " << p->first << " removed_snaps added " << *q << " (now " << newpi->removed_snaps << ")" << dendl; if (*q > newpi->get_snap_seq()) { dout(10) << " pool " << p->first << " snap_seq " << newpi->get_snap_seq() << " -> " << *q << dendl; newpi->set_snap_seq(*q); } newpi->set_snap_epoch(pending_inc.epoch); } } } m->put(); return true; } // --------------- // map helpers void OSDMonitor::send_latest(PaxosServiceMessage *m, epoch_t start) { dout(5) << "send_latest to " << m->get_orig_source_inst() << " start " << start << dendl; if (start == 0) send_full(m); else send_incremental(m, start); m->put(); } MOSDMap *OSDMonitor::build_latest_full() { MOSDMap *r = new MOSDMap(mon->monmap->fsid, &osdmap); r->oldest_map = get_first_committed(); r->newest_map = osdmap.get_epoch(); return r; } MOSDMap *OSDMonitor::build_incremental(epoch_t from, epoch_t to) { dout(10) << "build_incremental [" << from << ".." << to << "]" << dendl; MOSDMap *m = new MOSDMap(mon->monmap->fsid); m->oldest_map = get_first_committed(); m->newest_map = osdmap.get_epoch(); for (epoch_t e = to; e >= from && e > 0; e--) { bufferlist bl; int err = get_version(e, bl); if (err == 0) { assert(bl.length()); // if (get_version(e, bl) > 0) { dout(20) << "build_incremental inc " << e << " " << bl.length() << " bytes" << dendl; m->incremental_maps[e] = bl; } else { assert(err == -ENOENT); assert(!bl.length()); get_version_full(e, bl); if (bl.length() > 0) { //else if (get_version("full", e, bl) > 0) { dout(20) << "build_incremental full " << e << " " << bl.length() << " bytes" << dendl; m->maps[e] = bl; } else { assert(0); // we should have all maps. } } } return m; } void OSDMonitor::send_full(PaxosServiceMessage *m) { dout(5) << "send_full to " << m->get_orig_source_inst() << dendl; mon->send_reply(m, build_latest_full()); } /* TBH, I'm fairly certain these two functions could somehow be using a single * helper function to do the heavy lifting. As this is not our main focus right * now, I'm leaving it to the next near-future iteration over the services' * code. We should not forget it though. * * TODO: create a helper function and get rid of the duplicated code. */ void OSDMonitor::send_incremental(PaxosServiceMessage *req, epoch_t first) { dout(5) << "send_incremental [" << first << ".." << osdmap.get_epoch() << "]" << " to " << req->get_orig_source_inst() << dendl; int osd = -1; if (req->get_source().is_osd()) { osd = req->get_source().num(); map::iterator p = osd_epoch.find(osd); if (p != osd_epoch.end()) { if (first <= p->second) { dout(10) << __func__ << " osd." << osd << " should already have epoch " << p->second << dendl; first = p->second + 1; if (first > osdmap.get_epoch()) return; } } } if (first < get_first_committed()) { first = get_first_committed(); bufferlist bl; int err = get_version_full(first, bl); assert(err == 0); assert(bl.length()); dout(20) << "send_incremental starting with base full " << first << " " << bl.length() << " bytes" << dendl; MOSDMap *m = new MOSDMap(osdmap.get_fsid()); m->oldest_map = first; m->newest_map = osdmap.get_epoch(); m->maps[first] = bl; mon->send_reply(req, m); if (osd >= 0) osd_epoch[osd] = osdmap.get_epoch(); return; } // send some maps. it may not be all of them, but it will get them // started. epoch_t last = MIN(first + g_conf->osd_map_message_max, osdmap.get_epoch()); MOSDMap *m = build_incremental(first, last); m->oldest_map = get_first_committed(); m->newest_map = osdmap.get_epoch(); mon->send_reply(req, m); if (osd >= 0) osd_epoch[osd] = last; } void OSDMonitor::send_incremental(epoch_t first, entity_inst_t& dest, bool onetime) { dout(5) << "send_incremental [" << first << ".." << osdmap.get_epoch() << "]" << " to " << dest << dendl; if (first < get_first_committed()) { first = get_first_committed(); bufferlist bl; int err = get_version_full(first, bl); assert(err == 0); assert(bl.length()); dout(20) << "send_incremental starting with base full " << first << " " << bl.length() << " bytes" << dendl; MOSDMap *m = new MOSDMap(osdmap.get_fsid()); m->oldest_map = first; m->newest_map = osdmap.get_epoch(); m->maps[first] = bl; mon->messenger->send_message(m, dest); first++; } while (first <= osdmap.get_epoch()) { epoch_t last = MIN(first + g_conf->osd_map_message_max, osdmap.get_epoch()); MOSDMap *m = build_incremental(first, last); mon->messenger->send_message(m, dest); first = last + 1; if (onetime) break; } } int OSDMonitor::get_version(version_t ver, bufferlist& bl) { if (inc_osd_cache.lookup(ver, &bl)) { return 0; } int ret = PaxosService::get_version(ver, bl); if (!ret) { inc_osd_cache.add(ver, bl); } return ret; } int OSDMonitor::get_version_full(version_t ver, bufferlist& bl) { if (full_osd_cache.lookup(ver, &bl)) { return 0; } int ret = PaxosService::get_version_full(ver, bl); if (!ret) { full_osd_cache.add(ver, bl); } return ret; } epoch_t OSDMonitor::blacklist(const entity_addr_t& a, utime_t until) { dout(10) << "blacklist " << a << " until " << until << dendl; pending_inc.new_blacklist[a] = until; return pending_inc.epoch; } void OSDMonitor::check_subs() { dout(10) << __func__ << dendl; string type = "osdmap"; if (mon->session_map.subs.count(type) == 0) return; xlist::iterator p = mon->session_map.subs[type]->begin(); while (!p.end()) { Subscription *sub = *p; ++p; check_sub(sub); } } void OSDMonitor::check_sub(Subscription *sub) { dout(10) << __func__ << " " << sub << " next " << sub->next << (sub->onetime ? " (onetime)":" (ongoing)") << dendl; if (sub->next <= osdmap.get_epoch()) { if (sub->next >= 1) send_incremental(sub->next, sub->session->inst, sub->incremental_onetime); else mon->messenger->send_message(build_latest_full(), sub->session->inst); if (sub->onetime) mon->session_map.remove_sub(sub); else sub->next = osdmap.get_epoch() + 1; } } // TICK void OSDMonitor::tick() { if (!is_active()) return; dout(10) << osdmap << dendl; if (!mon->is_leader()) return; bool do_propose = false; utime_t now = ceph_clock_now(g_ceph_context); // mark osds down? check_failures(now); // mark down osds out? /* can_mark_out() checks if we can mark osds as being out. The -1 has no * influence at all. The decision is made based on the ratio of "in" osds, * and the function returns false if this ratio is lower that the minimum * ratio set by g_conf->mon_osd_min_in_ratio. So it's not really up to us. */ if (can_mark_out(-1)) { set down_cache; // quick cache of down subtrees map::iterator i = down_pending_out.begin(); while (i != down_pending_out.end()) { int o = i->first; utime_t down = now; down -= i->second; ++i; if (osdmap.is_down(o) && osdmap.is_in(o) && can_mark_out(o)) { utime_t orig_grace(g_conf->mon_osd_down_out_interval, 0); utime_t grace = orig_grace; double my_grace = 0.0; if (g_conf->mon_osd_adjust_down_out_interval) { // scale grace period the same way we do the heartbeat grace. const osd_xinfo_t& xi = osdmap.get_xinfo(o); double halflife = (double)g_conf->mon_osd_laggy_halflife; double decay_k = ::log(.5) / halflife; double decay = exp((double)down * decay_k); dout(20) << "osd." << o << " laggy halflife " << halflife << " decay_k " << decay_k << " down for " << down << " decay " << decay << dendl; my_grace = decay * (double)xi.laggy_interval * xi.laggy_probability; grace += my_grace; } // is this an entire large subtree down? if (g_conf->mon_osd_down_out_subtree_limit.length()) { int type = osdmap.crush->get_type_id(g_conf->mon_osd_down_out_subtree_limit); if (type > 0) { if (osdmap.containing_subtree_is_down(g_ceph_context, o, type, &down_cache)) { dout(10) << "tick entire containing " << g_conf->mon_osd_down_out_subtree_limit << " subtree for osd." << o << " is down; resetting timer" << dendl; // reset timer, too. down_pending_out[o] = now; continue; } } } if (g_conf->mon_osd_down_out_interval > 0 && down.sec() >= grace) { dout(10) << "tick marking osd." << o << " OUT after " << down << " sec (target " << grace << " = " << orig_grace << " + " << my_grace << ")" << dendl; pending_inc.new_weight[o] = CEPH_OSD_OUT; // set the AUTOOUT bit. if (pending_inc.new_state.count(o) == 0) pending_inc.new_state[o] = 0; pending_inc.new_state[o] |= CEPH_OSD_AUTOOUT; do_propose = true; mon->clog.info() << "osd." << o << " out (down for " << down << ")\n"; } else continue; } down_pending_out.erase(o); } } else { dout(10) << "tick NOOUT flag set, not checking down osds" << dendl; } // expire blacklisted items? for (ceph::unordered_map::iterator p = osdmap.blacklist.begin(); p != osdmap.blacklist.end(); ++p) { if (p->second < now) { dout(10) << "expiring blacklist item " << p->first << " expired " << p->second << " < now " << now << dendl; pending_inc.old_blacklist.push_back(p->first); do_propose = true; } } //if map full setting has changed, get that info out there! if (mon->pgmon()->is_readable()) { if (!mon->pgmon()->pg_map.full_osds.empty()) { dout(5) << "There are full osds, setting full flag" << dendl; add_flag(CEPH_OSDMAP_FULL); } else if (osdmap.test_flag(CEPH_OSDMAP_FULL)){ dout(10) << "No full osds, removing full flag" << dendl; remove_flag(CEPH_OSDMAP_FULL); } if (pending_inc.new_flags != -1 && (pending_inc.new_flags ^ osdmap.flags) & CEPH_OSDMAP_FULL) { dout(1) << "New setting for CEPH_OSDMAP_FULL -- doing propose" << dendl; do_propose = true; } } // --------------- #define SWAP_PRIMARIES_AT_START 0 #define SWAP_TIME 1 #if 0 if (SWAP_PRIMARIES_AT_START) { // For all PGs that have OSD 0 as the primary, // switch them to use the first replca ps_t numps = osdmap.get_pg_num(); for (int64_t pool=0; pool<1; pool++) for (ps_t ps = 0; ps < numps; ++ps) { pg_t pgid = pg_t(pg_t::TYPE_REPLICATED, ps, pool, -1); vector osds; osdmap.pg_to_osds(pgid, osds); if (osds[0] == 0) { pending_inc.new_pg_swap_primary[pgid] = osds[1]; dout(3) << "Changing primary for PG " << pgid << " from " << osds[0] << " to " << osds[1] << dendl; do_propose = true; } } } #endif // --------------- if (update_pools_status()) do_propose = true; if (do_propose || !pending_inc.new_pg_temp.empty()) // also propose if we adjusted pg_temp propose_pending(); } void OSDMonitor::handle_osd_timeouts(const utime_t &now, std::map &last_osd_report) { utime_t timeo(g_conf->mon_osd_report_timeout, 0); int max_osd = osdmap.get_max_osd(); bool new_down = false; for (int i=0; i < max_osd; ++i) { dout(30) << "handle_osd_timeouts: checking up on osd " << i << dendl; if (!osdmap.exists(i)) continue; if (!osdmap.is_up(i)) continue; const std::map::const_iterator t = last_osd_report.find(i); if (t == last_osd_report.end()) { // it wasn't in the map; start the timer. last_osd_report[i] = now; } else if (can_mark_down(i)) { utime_t diff = now - t->second; if (diff > timeo) { mon->clog.info() << "osd." << i << " marked down after no pg stats for " << diff << "seconds\n"; derr << "no osd or pg stats from osd." << i << " since " << t->second << ", " << diff << " seconds ago. marking down" << dendl; pending_inc.new_state[i] = CEPH_OSD_UP; new_down = true; } } } if (new_down) { propose_pending(); } } void OSDMonitor::mark_all_down() { assert(mon->is_leader()); dout(7) << "mark_all_down" << dendl; set ls; osdmap.get_all_osds(ls); for (set::iterator it = ls.begin(); it != ls.end(); ++it) { if (osdmap.is_down(*it)) continue; pending_inc.new_state[*it] = CEPH_OSD_UP; } propose_pending(); } void OSDMonitor::get_health(list >& summary, list > *detail) const { int num_osds = osdmap.get_num_osds(); if (num_osds == 0) { summary.push_back(make_pair(HEALTH_ERR, "no osds")); } else { int num_in_osds = 0; int num_down_in_osds = 0; for (int i = 0; i < osdmap.get_max_osd(); i++) { if (!osdmap.exists(i) || osdmap.is_out(i)) continue; ++num_in_osds; if (!osdmap.is_up(i)) { ++num_down_in_osds; if (detail) { const osd_info_t& info = osdmap.get_info(i); ostringstream ss; ss << "osd." << i << " is down since epoch " << info.down_at << ", last address " << osdmap.get_addr(i); detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } assert(num_down_in_osds <= num_in_osds); if (num_down_in_osds > 0) { ostringstream ss; ss << num_down_in_osds << "/" << num_in_osds << " in osds are down"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); } // warn about flags if (osdmap.test_flag(CEPH_OSDMAP_PAUSERD | CEPH_OSDMAP_PAUSEWR | CEPH_OSDMAP_NOUP | CEPH_OSDMAP_NODOWN | CEPH_OSDMAP_NOIN | CEPH_OSDMAP_NOOUT | CEPH_OSDMAP_NOBACKFILL | CEPH_OSDMAP_NORECOVER | CEPH_OSDMAP_NOSCRUB | CEPH_OSDMAP_NODEEP_SCRUB | CEPH_OSDMAP_NOTIERAGENT)) { ostringstream ss; ss << osdmap.get_flag_string() << " flag(s) set"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) detail->push_back(make_pair(HEALTH_WARN, ss.str())); } // old crush tunables? if (g_conf->mon_warn_on_legacy_crush_tunables) { if (osdmap.crush->has_legacy_tunables()) { ostringstream ss; ss << "crush map has legacy tunables"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) { ss << "; see http://ceph.com/docs/master/rados/operations/crush-map/#tunables"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } // hit_set-less cache_mode? if (g_conf->mon_warn_on_cache_pools_without_hit_sets) { int problem_cache_pools = 0; for (map::const_iterator p = osdmap.pools.begin(); p != osdmap.pools.end(); ++p) { const pg_pool_t& info = p->second; if (info.cache_mode_requires_hit_set() && info.hit_set_params.get_type() == HitSet::TYPE_NONE) { ++problem_cache_pools; if (detail) { ostringstream ss; ss << "pool '" << osdmap.get_pool_name(p->first) << "' with cache_mode " << info.get_cache_mode_name() << " needs hit_set_type to be set but it is not"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } if (problem_cache_pools) { ostringstream ss; ss << problem_cache_pools << " cache pools are missing hit_sets"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); } } // Warn if 'mon_osd_down_out_interval' is set to zero. // Having this option set to zero on the leader acts much like the // 'noout' flag. It's hard to figure out what's going wrong with clusters // without the 'noout' flag set but acting like that just the same, so // we report a HEALTH_WARN in case this option is set to zero. // This is an ugly hack to get the warning out, but until we find a way // to spread global options throughout the mon cluster and have all mons // using a base set of the same options, we need to work around this sort // of things. // There's also the obvious drawback that if this is set on a single // monitor on a 3-monitor cluster, this warning will only be shown every // third monitor connection. if (g_conf->mon_warn_on_osd_down_out_interval_zero && g_conf->mon_osd_down_out_interval == 0) { ostringstream ss; ss << "mon." << mon->name << " has mon_osd_down_out_interval set to 0"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) { ss << "; this has the same effect as the 'noout' flag"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } get_pools_health(summary, detail); } } void OSDMonitor::dump_info(Formatter *f) { f->open_object_section("osdmap"); osdmap.dump(f); f->close_section(); f->open_array_section("osd_metadata"); for (int i=0; iopen_object_section("osd"); f->dump_unsigned("id", i); dump_osd_metadata(i, f, NULL); f->close_section(); } } f->close_section(); f->dump_unsigned("osdmap_first_committed", get_first_committed()); f->dump_unsigned("osdmap_last_committed", get_last_committed()); f->open_object_section("crushmap"); osdmap.crush->dump(f); f->close_section(); } bool OSDMonitor::preprocess_command(MMonCommand *m) { int r = 0; bufferlist rdata; stringstream ss, ds; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, get_last_committed()); return true; } MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", rdata, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); if (prefix == "osd stat") { osdmap.print_summary(f.get(), ds); if (f) f->flush(rdata); else rdata.append(ds); } else if (prefix == "osd dump" || prefix == "osd tree" || prefix == "osd ls" || prefix == "osd getmap" || prefix == "osd getcrushmap" || prefix == "osd perf") { string val; epoch_t epoch = 0; int64_t epochnum; cmd_getval(g_ceph_context, cmdmap, "epoch", epochnum, (int64_t)0); epoch = epochnum; OSDMap *p = &osdmap; if (epoch) { bufferlist b; int err = get_version_full(epoch, b); if (err == -ENOENT) { r = -ENOENT; ss << "there is no map for epoch " << epoch; goto reply; } assert(err == 0); assert(b.length()); p = new OSDMap; p->decode(b); } if (prefix == "osd dump") { stringstream ds; if (f) { f->open_object_section("osdmap"); p->dump(f.get()); f->close_section(); f->flush(ds); } else { p->print(ds); } rdata.append(ds); if (!f) ds << " "; } else if (prefix == "osd ls") { if (f) { f->open_array_section("osds"); for (int i = 0; i < osdmap.get_max_osd(); i++) { if (osdmap.exists(i)) { f->dump_int("osd", i); } } f->close_section(); f->flush(ds); } else { bool first = true; for (int i = 0; i < osdmap.get_max_osd(); i++) { if (osdmap.exists(i)) { if (!first) ds << "\n"; first = false; ds << i; } } } rdata.append(ds); } else if (prefix == "osd tree") { if (f) { f->open_object_section("tree"); p->print_tree(NULL, f.get()); f->close_section(); f->flush(ds); } else { p->print_tree(&ds, NULL); } rdata.append(ds); } else if (prefix == "osd getmap") { p->encode(rdata, m->get_connection()->get_features()); ss << "got osdmap epoch " << p->get_epoch(); } else if (prefix == "osd getcrushmap") { p->crush->encode(rdata); ss << "got crush map from osdmap epoch " << p->get_epoch(); } else if (prefix == "osd perf") { const PGMap &pgm = mon->pgmon()->pg_map; if (f) { f->open_object_section("osdstats"); pgm.dump_osd_perf_stats(f.get()); f->close_section(); f->flush(ds); } else { pgm.print_osd_perf_stats(&ds); } rdata.append(ds); } if (p != &osdmap) delete p; } else if (prefix == "osd getmaxosd") { if (f) { f->open_object_section("getmaxosd"); f->dump_int("epoch", osdmap.get_epoch()); f->dump_int("max_osd", osdmap.get_max_osd()); f->close_section(); f->flush(rdata); } else { ds << "max_osd = " << osdmap.get_max_osd() << " in epoch " << osdmap.get_epoch(); rdata.append(ds); } } else if (prefix == "osd find") { int64_t osd; if (!cmd_getval(g_ceph_context, cmdmap, "id", osd)) { ss << "unable to parse osd id value '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; r = -EINVAL; goto reply; } if (!osdmap.exists(osd)) { ss << "osd." << osd << " does not exist"; r = -ENOENT; goto reply; } string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty")); boost::scoped_ptr f(new_formatter(format)); if (!f) f.reset(new_formatter("json-pretty")); f->open_object_section("osd_location"); f->dump_int("osd", osd); f->dump_stream("ip") << osdmap.get_addr(osd); f->open_object_section("crush_location"); map loc = osdmap.crush->get_full_location(osd); for (map::iterator p = loc.begin(); p != loc.end(); ++p) f->dump_string(p->first.c_str(), p->second); f->close_section(); f->close_section(); f->flush(rdata); } else if (prefix == "osd metadata") { int64_t osd; if (!cmd_getval(g_ceph_context, cmdmap, "id", osd)) { ss << "unable to parse osd id value '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; r = -EINVAL; goto reply; } if (!osdmap.exists(osd)) { ss << "osd." << osd << " does not exist"; r = -ENOENT; goto reply; } string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty")); boost::scoped_ptr f(new_formatter(format)); if (!f) f.reset(new_formatter("json-pretty")); f->open_object_section("osd_metadata"); r = dump_osd_metadata(osd, f.get(), &ss); if (r < 0) goto reply; f->close_section(); f->flush(rdata); } else if (prefix == "osd map") { string poolstr, objstr, namespacestr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); cmd_getval(g_ceph_context, cmdmap, "object", objstr); cmd_getval(g_ceph_context, cmdmap, "nspace", namespacestr); int64_t pool = osdmap.lookup_pg_pool_name(poolstr.c_str()); if (pool < 0) { ss << "pool " << poolstr << " does not exist"; r = -ENOENT; goto reply; } object_locator_t oloc(pool, namespacestr); object_t oid(objstr); pg_t pgid = osdmap.object_locator_to_pg(oid, oloc); pg_t mpgid = osdmap.raw_pg_to_pg(pgid); vector up, acting; int up_p, acting_p; osdmap.pg_to_up_acting_osds(mpgid, &up, &up_p, &acting, &acting_p); string fullobjname; if (!namespacestr.empty()) fullobjname = namespacestr + string("/") + oid.name; else fullobjname = oid.name; if (f) { f->open_object_section("osd_map"); f->dump_int("epoch", osdmap.get_epoch()); f->dump_string("pool", poolstr); f->dump_int("pool_id", pool); f->dump_stream("objname") << fullobjname; f->dump_stream("raw_pgid") << pgid; f->dump_stream("pgid") << mpgid; f->dump_stream("up") << up; f->dump_int("up_primary", up_p); f->dump_stream("acting") << acting; f->dump_int("acting_primary", acting_p); f->close_section(); // osd_map f->flush(rdata); } else { ds << "osdmap e" << osdmap.get_epoch() << " pool '" << poolstr << "' (" << pool << ")" << " object '" << fullobjname << "' ->" << " pg " << pgid << " (" << mpgid << ")" << " -> up (" << up << ", p" << up_p << ") acting (" << acting << ", p" << acting_p << ")"; rdata.append(ds); } } else if ((prefix == "osd scrub" || prefix == "osd deep-scrub" || prefix == "osd repair")) { string whostr; cmd_getval(g_ceph_context, cmdmap, "who", whostr); vector pvec; get_str_vec(prefix, pvec); if (whostr == "*") { ss << "osds "; int c = 0; for (int i = 0; i < osdmap.get_max_osd(); i++) if (osdmap.is_up(i)) { ss << (c++ ? "," : "") << i; mon->try_send_message(new MOSDScrub(osdmap.get_fsid(), pvec.back() == "repair", pvec.back() == "deep-scrub"), osdmap.get_inst(i)); } r = 0; ss << " instructed to " << pvec.back(); } else { long osd = parse_osd_id(whostr.c_str(), &ss); if (osd < 0) { r = -EINVAL; } else if (osdmap.is_up(osd)) { mon->try_send_message(new MOSDScrub(osdmap.get_fsid(), pvec.back() == "repair", pvec.back() == "deep-scrub"), osdmap.get_inst(osd)); ss << "osd." << osd << " instructed to " << pvec.back(); } else { ss << "osd." << osd << " is not up"; r = -EAGAIN; } } } else if (prefix == "osd lspools") { int64_t auid; cmd_getval(g_ceph_context, cmdmap, "auid", auid, int64_t(0)); if (f) f->open_array_section("pools"); for (map::iterator p = osdmap.pools.begin(); p != osdmap.pools.end(); ++p) { if (!auid || p->second.auid == (uint64_t)auid) { if (f) { f->open_object_section("pool"); f->dump_int("poolnum", p->first); f->dump_string("poolname", osdmap.pool_name[p->first]); f->close_section(); } else { ds << p->first << ' ' << osdmap.pool_name[p->first] << ','; } } } if (f) { f->close_section(); f->flush(ds); } rdata.append(ds); } else if (prefix == "osd blacklist ls") { if (f) f->open_array_section("blacklist"); for (ceph::unordered_map::iterator p = osdmap.blacklist.begin(); p != osdmap.blacklist.end(); ++p) { if (f) { f->open_object_section("entry"); f->dump_stream("addr") << p->first; f->dump_stream("until") << p->second; f->close_section(); } else { stringstream ss; string s; ss << p->first << " " << p->second; getline(ss, s); s += "\n"; rdata.append(s); } } if (f) { f->close_section(); f->flush(rdata); } ss << "listed " << osdmap.blacklist.size() << " entries"; } else if (prefix == "osd crush get-tunable") { string tunable; cmd_getval(g_ceph_context, cmdmap, "tunable", tunable); ostringstream rss; if (f) f->open_object_section("tunable"); if (tunable == "straw_calc_version") { if (f) f->dump_int(tunable.c_str(), osdmap.crush->get_straw_calc_version()); else rss << osdmap.crush->get_straw_calc_version() << "\n"; } else { r = -EINVAL; goto reply; } if (f) { f->close_section(); f->flush(rdata); } else { rdata.append(rss.str()); } r = 0; } else if (prefix == "osd pool get") { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool = osdmap.lookup_pg_pool_name(poolstr.c_str()); if (pool < 0) { ss << "unrecognized pool '" << poolstr << "'"; r = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool); string var; cmd_getval(g_ceph_context, cmdmap, "var", var); if (!p->is_tier() && (var == "hit_set_type" || var == "hit_set_period" || var == "hit_set_count" || var == "hit_set_fpp" || var == "target_max_objects" || var == "target_max_bytes" || var == "cache_target_full_ratio" || var == "cache_target_dirty_ratio" || var == "cache_min_flush_age" || var == "cache_min_evict_age")) { ss << "pool '" << poolstr << "' is not a tier pool: variable not applicable"; r = -EACCES; goto reply; } if (!p->is_erasure() && var == "erasure_code_profile") { ss << "pool '" << poolstr << "' is not a erasure pool: variable not applicable"; r = -EACCES; goto reply; } if (f) { f->open_object_section("pool"); f->dump_string("pool", poolstr); f->dump_int("pool_id", pool); if (var == "pg_num") { f->dump_int("pg_num", p->get_pg_num()); } else if (var == "pgp_num") { f->dump_int("pgp_num", p->get_pgp_num()); } else if (var == "auid") { f->dump_int("auid", p->get_auid()); } else if (var == "size") { f->dump_int("size", p->get_size()); } else if (var == "min_size") { f->dump_int("min_size", p->get_min_size()); } else if (var == "crash_replay_interval") { f->dump_int("crash_replay_interval", p->get_crash_replay_interval()); } else if (var == "crush_ruleset") { f->dump_int("crush_ruleset", p->get_crush_ruleset()); } else if (var == "hit_set_period") { f->dump_int("hit_set_period", p->hit_set_period); } else if (var == "hit_set_count") { f->dump_int("hit_set_count", p->hit_set_count); } else if (var == "hit_set_type") { f->dump_string("hit_set_type", HitSet::get_type_name(p->hit_set_params.get_type())); } else if (var == "hit_set_fpp") { if (p->hit_set_params.get_type() != HitSet::TYPE_BLOOM) { f->close_section(); ss << "hit set is no of type Bloom; invalid to get a false positive rate!"; r = -EINVAL; goto reply; } else { BloomHitSet::Params *bloomp = static_cast(p->hit_set_params.impl.get()); f->dump_float("hit_set_fpp", bloomp->get_fpp()); } } else if (var == "target_max_objects") { f->dump_unsigned("target_max_objects", p->target_max_objects); } else if (var == "target_max_bytes") { f->dump_unsigned("target_max_bytes", p->target_max_bytes); } else if (var == "cache_target_dirty_ratio") { f->dump_unsigned("cache_target_dirty_ratio_micro", p->cache_target_dirty_ratio_micro); f->dump_float("cache_target_dirty_ratio", ((float)p->cache_target_dirty_ratio_micro/1000000)); } else if (var == "cache_target_full_ratio") { f->dump_unsigned("cache_target_full_ratio_micro", p->cache_target_full_ratio_micro); f->dump_float("cache_target_full_ratio", ((float)p->cache_target_full_ratio_micro/1000000)); } else if (var == "cache_min_flush_age") { f->dump_unsigned("cache_min_flush_age", p->cache_min_flush_age); } else if (var == "cache_min_evict_age") { f->dump_unsigned("cache_min_evict_age", p->cache_min_evict_age); } else if (var == "erasure_code_profile") { f->dump_string("erasure_code_profile", p->erasure_code_profile); } else if (var == "min_read_recency_for_promote") { f->dump_int("min_read_recency_for_promote", p->min_read_recency_for_promote); } f->close_section(); f->flush(rdata); } else { if (var == "pg_num") { ss << "pg_num: " << p->get_pg_num(); } else if (var == "pgp_num") { ss << "pgp_num: " << p->get_pgp_num(); } else if (var == "auid") { ss << "auid: " << p->get_auid(); } else if (var == "size") { ss << "size: " << p->get_size(); } else if (var == "min_size") { ss << "min_size: " << p->get_min_size(); } else if (var == "crash_replay_interval") { ss << "crash_replay_interval: " << p->get_crash_replay_interval(); } else if (var == "crush_ruleset") { ss << "crush_ruleset: " << p->get_crush_ruleset(); } else if (var == "hit_set_period") { ss << "hit_set_period: " << p->hit_set_period; } else if (var == "hit_set_count") { ss << "hit_set_count: " << p->hit_set_count; } else if (var == "hit_set_type") { ss << "hit_set_type: " << HitSet::get_type_name(p->hit_set_params.get_type()); } else if (var == "hit_set_fpp") { if (p->hit_set_params.get_type() != HitSet::TYPE_BLOOM) { ss << "hit set is no of type Bloom; invalid to get a false positive rate!"; r = -EINVAL; goto reply; } BloomHitSet::Params *bloomp = static_cast(p->hit_set_params.impl.get()); ss << "hit_set_fpp: " << bloomp->get_fpp(); } else if (var == "target_max_objects") { ss << "target_max_objects: " << p->target_max_objects; } else if (var == "target_max_bytes") { ss << "target_max_bytes: " << p->target_max_bytes; } else if (var == "cache_target_dirty_ratio") { ss << "cache_target_dirty_ratio: " << ((float)p->cache_target_dirty_ratio_micro/1000000); } else if (var == "cache_target_full_ratio") { ss << "cache_target_full_ratio: " << ((float)p->cache_target_full_ratio_micro/1000000); } else if (var == "cache_min_flush_age") { ss << "cache_min_flush_age: " << p->cache_min_flush_age; } else if (var == "cache_min_evict_age") { ss << "cache_min_evict_age: " << p->cache_min_evict_age; } else if (var == "erasure_code_profile") { ss << "erasure_code_profile: " << p->erasure_code_profile; } else if (var == "min_read_recency_for_promote") { ss << "min_read_recency_for_promote: " << p->min_read_recency_for_promote; } rdata.append(ss); ss.str(""); } r = 0; } else if (prefix == "osd pool stats") { string pool_name; cmd_getval(g_ceph_context, cmdmap, "name", pool_name); PGMap& pg_map = mon->pgmon()->pg_map; int64_t poolid = -ENOENT; bool one_pool = false; if (!pool_name.empty()) { poolid = osdmap.lookup_pg_pool_name(pool_name); if (poolid < 0) { assert(poolid == -ENOENT); ss << "unrecognized pool '" << pool_name << "'"; r = -ENOENT; goto reply; } one_pool = true; } stringstream rs; if (f) f->open_array_section("pool_stats"); if (osdmap.get_pools().size() == 0) { if (!f) ss << "there are no pools!"; goto stats_out; } for (map::const_iterator it = osdmap.get_pools().begin(); it != osdmap.get_pools().end(); ++it) { if (!one_pool) poolid = it->first; pool_name = osdmap.get_pool_name(poolid); if (f) { f->open_object_section("pool"); f->dump_string("pool_name", pool_name.c_str()); f->dump_int("pool_id", poolid); f->open_object_section("recovery"); } stringstream rss, tss; pg_map.pool_recovery_summary(f.get(), &rss, poolid); if (!f && !rss.str().empty()) tss << " " << rss.str() << "\n"; if (f) { f->close_section(); f->open_object_section("recovery_rate"); } rss.clear(); rss.str(""); pg_map.pool_recovery_rate_summary(f.get(), &rss, poolid); if (!f && !rss.str().empty()) tss << " recovery io " << rss.str() << "\n"; if (f) { f->close_section(); f->open_object_section("client_io_rate"); } rss.clear(); rss.str(""); pg_map.pool_client_io_rate_summary(f.get(), &rss, poolid); if (!f && !rss.str().empty()) tss << " client io " << rss.str() << "\n"; if (f) { f->close_section(); f->close_section(); } else { rs << "pool " << pool_name << " id " << poolid << "\n"; if (!tss.str().empty()) rs << tss.str() << "\n"; else rs << " nothing is going on\n\n"; } if (one_pool) break; } stats_out: if (f) { f->close_section(); f->flush(rdata); } else { rdata.append(rs.str()); } rdata.append("\n"); r = 0; } else if (prefix == "osd pool get-quota") { string pool_name; cmd_getval(g_ceph_context, cmdmap, "pool", pool_name); int64_t poolid = osdmap.lookup_pg_pool_name(pool_name); if (poolid < 0) { assert(poolid == -ENOENT); ss << "unrecognized pool '" << pool_name << "'"; r = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(poolid); if (f) { f->open_object_section("pool_quotas"); f->dump_string("pool_name", pool_name); f->dump_unsigned("pool_id", poolid); f->dump_unsigned("quota_max_objects", p->quota_max_objects); f->dump_unsigned("quota_max_bytes", p->quota_max_bytes); f->close_section(); f->flush(rdata); } else { stringstream rs; rs << "quotas for pool '" << pool_name << "':\n" << " max objects: "; if (p->quota_max_objects == 0) rs << "N/A"; else rs << si_t(p->quota_max_objects) << " objects"; rs << "\n" << " max bytes : "; if (p->quota_max_bytes == 0) rs << "N/A"; else rs << si_t(p->quota_max_bytes) << "B"; rdata.append(rs.str()); } rdata.append("\n"); r = 0; } else if (prefix == "osd crush rule list" || prefix == "osd crush rule ls") { string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty")); Formatter *fp = new_formatter(format); if (!fp) fp = new_formatter("json-pretty"); boost::scoped_ptr f(fp); f->open_array_section("rules"); osdmap.crush->list_rules(f.get()); f->close_section(); ostringstream rs; f->flush(rs); rs << "\n"; rdata.append(rs.str()); } else if (prefix == "osd crush rule dump") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty")); Formatter *fp = new_formatter(format); if (!fp) fp = new_formatter("json-pretty"); boost::scoped_ptr f(fp); if (name == "") { f->open_array_section("rules"); osdmap.crush->dump_rules(f.get()); f->close_section(); } else { int ruleset = osdmap.crush->get_rule_id(name); if (ruleset < 0) { ss << "unknown crush ruleset '" << name << "'"; r = ruleset; goto reply; } osdmap.crush->dump_rule(ruleset, f.get()); } ostringstream rs; f->flush(rs); rs << "\n"; rdata.append(rs.str()); } else if (prefix == "osd crush dump") { string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty")); Formatter *fp = new_formatter(format); if (!fp) fp = new_formatter("json-pretty"); boost::scoped_ptr f(fp); f->open_object_section("crush_map"); osdmap.crush->dump(f.get()); f->close_section(); ostringstream rs; f->flush(rs); rs << "\n"; rdata.append(rs.str()); } else if (prefix == "osd crush show-tunables") { string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty")); Formatter *fp = new_formatter(format); if (!fp) fp = new_formatter("json-pretty"); boost::scoped_ptr f(fp); f->open_object_section("crush_map_tunables"); osdmap.crush->dump_tunables(f.get()); f->close_section(); ostringstream rs; f->flush(rs); rs << "\n"; rdata.append(rs.str()); } else if (prefix == "osd erasure-code-profile ls") { const map > &profiles = osdmap.get_erasure_code_profiles(); if (f) f->open_array_section("erasure-code-profiles"); for(map >::const_iterator i = profiles.begin(); i != profiles.end(); i++) { if (f) f->dump_string("profile", i->first.c_str()); else rdata.append(i->first + "\n"); } if (f) { f->close_section(); ostringstream rs; f->flush(rs); rs << "\n"; rdata.append(rs.str()); } } else if (prefix == "osd erasure-code-profile get") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); if (!osdmap.has_erasure_code_profile(name)) { ss << "unknown erasure code profile '" << name << "'"; r = -ENOENT; goto reply; } const map &profile = osdmap.get_erasure_code_profile(name); if (f) f->open_object_section("profile"); for (map::const_iterator i = profile.begin(); i != profile.end(); i++) { if (f) f->dump_string(i->first.c_str(), i->second.c_str()); else rdata.append(i->first + "=" + i->second + "\n"); } if (f) { f->close_section(); ostringstream rs; f->flush(rs); rs << "\n"; rdata.append(rs.str()); } } else { // try prepare update return false; } reply: string rs; getline(ss, rs); mon->reply_command(m, r, rs, rdata, get_last_committed()); return true; } void OSDMonitor::update_pool_flags(int64_t pool_id, uint64_t flags) { const pg_pool_t *pool = osdmap.get_pg_pool(pool_id); pending_inc.get_new_pool(pool_id, pool)->flags = flags; } bool OSDMonitor::update_pools_status() { if (!mon->pgmon()->is_readable()) return false; bool ret = false; const map& pools = osdmap.get_pools(); for (map::const_iterator it = pools.begin(); it != pools.end(); ++it) { if (!mon->pgmon()->pg_map.pg_pool_sum.count(it->first)) continue; pool_stat_t& stats = mon->pgmon()->pg_map.pg_pool_sum[it->first]; object_stat_sum_t& sum = stats.stats.sum; const pg_pool_t &pool = it->second; const char *pool_name = osdmap.get_pool_name(it->first); bool pool_is_full = (pool.quota_max_bytes > 0 && (uint64_t)sum.num_bytes >= pool.quota_max_bytes) || (pool.quota_max_objects > 0 && (uint64_t)sum.num_objects >= pool.quota_max_objects); if (pool.get_flags() & pg_pool_t::FLAG_FULL) { if (pool_is_full) continue; mon->clog.info() << "pool '" << pool_name << "' no longer full; removing FULL flag"; update_pool_flags(it->first, pool.get_flags() & ~pg_pool_t::FLAG_FULL); ret = true; } else { if (!pool_is_full) continue; if (pool.quota_max_bytes > 0 && (uint64_t)sum.num_bytes >= pool.quota_max_bytes) { mon->clog.warn() << "pool '" << pool_name << "' is full" << " (reached quota's max_bytes: " << si_t(pool.quota_max_bytes) << ")"; } else if (pool.quota_max_objects > 0 && (uint64_t)sum.num_objects >= pool.quota_max_objects) { mon->clog.warn() << "pool '" << pool_name << "' is full" << " (reached quota's max_objects: " << pool.quota_max_objects << ")"; } else { assert(0 == "we shouldn't reach this"); } update_pool_flags(it->first, pool.get_flags() | pg_pool_t::FLAG_FULL); ret = true; } } return ret; } void OSDMonitor::get_pools_health( list >& summary, list > *detail) const { const map& pools = osdmap.get_pools(); for (map::const_iterator it = pools.begin(); it != pools.end(); ++it) { if (!mon->pgmon()->pg_map.pg_pool_sum.count(it->first)) continue; pool_stat_t& stats = mon->pgmon()->pg_map.pg_pool_sum[it->first]; object_stat_sum_t& sum = stats.stats.sum; const pg_pool_t &pool = it->second; const char *pool_name = osdmap.get_pool_name(it->first); if (pool.get_flags() & pg_pool_t::FLAG_FULL) { // uncomment these asserts if/when we update the FULL flag on pg_stat update //assert((pool.quota_max_objects > 0) || (pool.quota_max_bytes > 0)); stringstream ss; ss << "pool '" << pool_name << "' is full"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) detail->push_back(make_pair(HEALTH_WARN, ss.str())); } float warn_threshold = g_conf->mon_pool_quota_warn_threshold/100; float crit_threshold = g_conf->mon_pool_quota_crit_threshold/100; if (pool.quota_max_objects > 0) { stringstream ss; health_status_t status = HEALTH_OK; if ((uint64_t)sum.num_objects >= pool.quota_max_objects) { // uncomment these asserts if/when we update the FULL flag on pg_stat update //assert(pool.get_flags() & pg_pool_t::FLAG_FULL); } else if (crit_threshold > 0 && sum.num_objects >= pool.quota_max_objects*crit_threshold) { ss << "pool '" << pool_name << "' has " << sum.num_objects << " objects" << " (max " << pool.quota_max_objects << ")"; status = HEALTH_ERR; } else if (warn_threshold > 0 && sum.num_objects >= pool.quota_max_objects*warn_threshold) { ss << "pool '" << pool_name << "' has " << sum.num_objects << " objects" << " (max " << pool.quota_max_objects << ")"; status = HEALTH_WARN; } if (status != HEALTH_OK) { pair s(status, ss.str()); summary.push_back(s); if (detail) detail->push_back(s); } } if (pool.quota_max_bytes > 0) { health_status_t status = HEALTH_OK; stringstream ss; if ((uint64_t)sum.num_bytes >= pool.quota_max_bytes) { // uncomment these asserts if/when we update the FULL flag on pg_stat update //assert(pool.get_flags() & pg_pool_t::FLAG_FULL); } else if (crit_threshold > 0 && sum.num_bytes >= pool.quota_max_bytes*crit_threshold) { ss << "pool '" << pool_name << "' has " << si_t(sum.num_bytes) << " bytes" << " (max " << si_t(pool.quota_max_bytes) << ")"; status = HEALTH_ERR; } else if (warn_threshold > 0 && sum.num_bytes >= pool.quota_max_bytes*warn_threshold) { ss << "pool '" << pool_name << "' has " << si_t(sum.num_bytes) << " bytes" << " (max " << si_t(pool.quota_max_bytes) << ")"; status = HEALTH_WARN; } if (status != HEALTH_OK) { pair s(status, ss.str()); summary.push_back(s); if (detail) detail->push_back(s); } } } } int OSDMonitor::prepare_new_pool(MPoolOp *m) { dout(10) << "prepare_new_pool from " << m->get_connection() << dendl; MonSession *session = m->get_session(); if (!session) return -EPERM; string erasure_code_profile; stringstream ss; string ruleset_name; if (m->auid) return prepare_new_pool(m->name, m->auid, m->crush_rule, ruleset_name, 0, 0, erasure_code_profile, pg_pool_t::TYPE_REPLICATED, ss); else return prepare_new_pool(m->name, session->auid, m->crush_rule, ruleset_name, 0, 0, erasure_code_profile, pg_pool_t::TYPE_REPLICATED, ss); } int OSDMonitor::crush_ruleset_create_erasure(const string &name, const string &profile, int *ruleset, stringstream &ss) { int ruleid = osdmap.crush->get_rule_id(name); if (ruleid != -ENOENT) { *ruleset = osdmap.crush->get_rule_mask_ruleset(ruleid); return -EEXIST; } CrushWrapper newcrush; _get_pending_crush(newcrush); ruleid = newcrush.get_rule_id(name); if (ruleid != -ENOENT) { *ruleset = newcrush.get_rule_mask_ruleset(ruleid); return -EALREADY; } else { ErasureCodeInterfaceRef erasure_code; int err = get_erasure_code(profile, &erasure_code, ss); if (err) { ss << "failed to load plugin using profile " << profile; return err; } err = erasure_code->create_ruleset(name, newcrush, &ss); erasure_code.reset(); if (err < 0) return err; *ruleset = err; pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); return 0; } } int OSDMonitor::get_erasure_code(const string &erasure_code_profile, ErasureCodeInterfaceRef *erasure_code, stringstream &ss) const { if (pending_inc.has_erasure_code_profile(erasure_code_profile)) return -EAGAIN; const map &profile = osdmap.get_erasure_code_profile(erasure_code_profile); map::const_iterator plugin = profile.find("plugin"); if (plugin == profile.end()) { ss << "cannot determine the erasure code plugin" << " because there is no 'plugin' entry in the erasure_code_profile " << profile; return -EINVAL; } ErasureCodePluginRegistry &instance = ErasureCodePluginRegistry::instance(); return instance.factory(plugin->second, profile, erasure_code, ss); } int OSDMonitor::check_cluster_features(uint64_t features, stringstream &ss) { stringstream unsupported_ss; int unsupported_count = 0; if ((mon->get_quorum_features() & features) != features) { unsupported_ss << "the monitor cluster"; ++unsupported_count; } set up_osds; osdmap.get_up_osds(up_osds); for (set::iterator it = up_osds.begin(); it != up_osds.end(); ++it) { const osd_xinfo_t &xi = osdmap.get_xinfo(*it); if ((xi.features & features) != features) { if (unsupported_count > 0) unsupported_ss << ", "; unsupported_ss << "osd." << *it; unsupported_count ++; } } if (unsupported_count > 0) { ss << "features " << features << " unsupported by: " << unsupported_ss.str(); return -ENOTSUP; } // check pending osd state, too! for (map::const_iterator p = pending_inc.new_xinfo.begin(); p != pending_inc.new_xinfo.end(); ++p) { const osd_xinfo_t &xi = p->second; if ((xi.features & features) != features) { dout(10) << __func__ << " pending osd." << p->first << " features are insufficient; retry" << dendl; return -EAGAIN; } } return 0; } bool OSDMonitor::validate_crush_against_features(const CrushWrapper *newcrush, stringstream& ss) { OSDMap::Incremental new_pending = pending_inc; ::encode(*newcrush, new_pending.crush); OSDMap newmap; newmap.deepish_copy_from(osdmap); newmap.apply_incremental(new_pending); uint64_t features = newmap.get_features(CEPH_ENTITY_TYPE_MON, NULL); stringstream features_ss; int r = check_cluster_features(features, features_ss); if (!r) return true; ss << "Could not change CRUSH: " << features_ss.str(); return false; } bool OSDMonitor::erasure_code_profile_in_use(const map &pools, const string &profile, ostream &ss) { bool found = false; for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { if (p->second.erasure_code_profile == profile) { ss << osdmap.pool_name[p->first] << " "; found = true; } } if (found) { ss << "pool(s) are using the erasure code profile '" << profile << "'"; } return found; } int OSDMonitor::parse_erasure_code_profile(const vector &erasure_code_profile, map *erasure_code_profile_map, stringstream &ss) { int r = get_str_map(g_conf->osd_pool_default_erasure_code_profile, ss, erasure_code_profile_map); if (r) return r; (*erasure_code_profile_map)["directory"] = g_conf->osd_pool_default_erasure_code_directory; for (vector::const_iterator i = erasure_code_profile.begin(); i != erasure_code_profile.end(); ++i) { size_t equal = i->find('='); if (equal == string::npos) (*erasure_code_profile_map)[*i] = string(); else { const string key = i->substr(0, equal); equal++; const string value = i->substr(equal); (*erasure_code_profile_map)[key] = value; } } return 0; } int OSDMonitor::prepare_pool_size(const unsigned pool_type, const string &erasure_code_profile, unsigned *size, unsigned *min_size, stringstream &ss) { int err = 0; switch (pool_type) { case pg_pool_t::TYPE_REPLICATED: *size = g_conf->osd_pool_default_size; *min_size = g_conf->get_osd_pool_default_min_size(); break; case pg_pool_t::TYPE_ERASURE: { ErasureCodeInterfaceRef erasure_code; err = get_erasure_code(erasure_code_profile, &erasure_code, ss); if (err == 0) { *size = erasure_code->get_chunk_count(); *min_size = erasure_code->get_data_chunk_count(); } } break; default: ss << "prepare_pool_size: " << pool_type << " is not a known pool type"; err = -EINVAL; break; } return err; } int OSDMonitor::prepare_pool_stripe_width(const unsigned pool_type, const string &erasure_code_profile, uint32_t *stripe_width, stringstream &ss) { int err = 0; switch (pool_type) { case pg_pool_t::TYPE_REPLICATED: // ignored break; case pg_pool_t::TYPE_ERASURE: { ErasureCodeInterfaceRef erasure_code; err = get_erasure_code(erasure_code_profile, &erasure_code, ss); uint32_t desired_stripe_width = g_conf->osd_pool_erasure_code_stripe_width; if (err == 0) *stripe_width = erasure_code->get_data_chunk_count() * erasure_code->get_chunk_size(desired_stripe_width); } break; default: ss << "prepare_pool_stripe_width: " << pool_type << " is not a known pool type"; err = -EINVAL; break; } return err; } int OSDMonitor::prepare_pool_crush_ruleset(const unsigned pool_type, const string &erasure_code_profile, const string &ruleset_name, int *crush_ruleset, stringstream &ss) { if (*crush_ruleset < 0) { switch (pool_type) { case pg_pool_t::TYPE_REPLICATED: { if (ruleset_name == "") { //Use default ruleset *crush_ruleset = osdmap.crush->get_osd_pool_default_crush_replicated_ruleset(g_ceph_context); if (*crush_ruleset < 0) { // Errors may happen e.g. if no valid ruleset is available ss << "No suitable CRUSH ruleset exists"; return *crush_ruleset; } } else { int ret; ret = osdmap.crush->get_rule_id(ruleset_name); if (ret != -ENOENT) { // found it, use it *crush_ruleset = ret; } else { CrushWrapper newcrush; _get_pending_crush(newcrush); ret = newcrush.get_rule_id(ruleset_name); if (ret != -ENOENT) { // found it, wait for it to be proposed dout(20) << "prepare_pool_crush_ruleset: ruleset " << ruleset_name << " is pending, try again" << dendl; return -EAGAIN; } else { //Cannot find it , return error ss << "Specified ruleset " << ruleset_name << " doesn't exist"; return ret; } } } } break; case pg_pool_t::TYPE_ERASURE: { int err = crush_ruleset_create_erasure(ruleset_name, erasure_code_profile, crush_ruleset, ss); switch (err) { case -EALREADY: dout(20) << "prepare_pool_crush_ruleset: ruleset " << ruleset_name << " try again" << dendl; case 0: // need to wait for the crush rule to be proposed before proceeding err = -EAGAIN; break; case -EEXIST: err = 0; break; } return err; } break; default: ss << "prepare_pool_crush_ruleset: " << pool_type << " is not a known pool type"; return -EINVAL; break; } } else { if (!osdmap.crush->ruleset_exists(*crush_ruleset)) { ss << "CRUSH ruleset " << *crush_ruleset << " not found"; return -ENOENT; } } return 0; } /** * @param name The name of the new pool * @param auid The auid of the pool owner. Can be -1 * @param crush_ruleset The crush rule to use. If <0, will use the system default * @param crush_ruleset_name The crush rule to use, if crush_rulset <0 * @param pg_num The pg_num to use. If set to 0, will use the system default * @param pgp_num The pgp_num to use. If set to 0, will use the system default * @param erasure_code_profile The profile name in OSDMap to be used for erasure code * @param pool_type TYPE_ERASURE, TYPE_REP or TYPE_RAID4 * @param ss human readable error message, if any. * * @return 0 on success, negative errno on failure. */ int OSDMonitor::prepare_new_pool(string& name, uint64_t auid, int crush_ruleset, const string &crush_ruleset_name, unsigned pg_num, unsigned pgp_num, const string &erasure_code_profile, const unsigned pool_type, stringstream &ss) { int r; r = prepare_pool_crush_ruleset(pool_type, erasure_code_profile, crush_ruleset_name, &crush_ruleset, ss); if (r) return r; unsigned size, min_size; r = prepare_pool_size(pool_type, erasure_code_profile, &size, &min_size, ss); if (r) return r; uint32_t stripe_width = 0; r = prepare_pool_stripe_width(pool_type, erasure_code_profile, &stripe_width, ss); if (r) return r; for (map::iterator p = pending_inc.new_pool_names.begin(); p != pending_inc.new_pool_names.end(); ++p) { if (p->second == name) return 0; } if (-1 == pending_inc.new_pool_max) pending_inc.new_pool_max = osdmap.pool_max; int64_t pool = ++pending_inc.new_pool_max; pg_pool_t empty; pg_pool_t *pi = pending_inc.get_new_pool(pool, &empty); pi->type = pool_type; pi->flags = g_conf->osd_pool_default_flags; if (g_conf->osd_pool_default_flag_hashpspool) pi->flags |= pg_pool_t::FLAG_HASHPSPOOL; pi->size = size; pi->min_size = min_size; pi->crush_ruleset = crush_ruleset; pi->object_hash = CEPH_STR_HASH_RJENKINS; pi->set_pg_num(pg_num ? pg_num : g_conf->osd_pool_default_pg_num); pi->set_pgp_num(pgp_num ? pgp_num : g_conf->osd_pool_default_pgp_num); pi->last_change = pending_inc.epoch; pi->auid = auid; pi->erasure_code_profile = erasure_code_profile; pi->stripe_width = stripe_width; pi->cache_target_dirty_ratio_micro = g_conf->osd_pool_default_cache_target_dirty_ratio * 1000000; pi->cache_target_full_ratio_micro = g_conf->osd_pool_default_cache_target_full_ratio * 1000000; pi->cache_min_flush_age = g_conf->osd_pool_default_cache_min_flush_age; pi->cache_min_evict_age = g_conf->osd_pool_default_cache_min_evict_age; pending_inc.new_pool_names[pool] = name; return 0; } bool OSDMonitor::prepare_set_flag(MMonCommand *m, int flag) { ostringstream ss; if (pending_inc.new_flags < 0) pending_inc.new_flags = osdmap.get_flags(); pending_inc.new_flags |= flag; ss << "set " << OSDMap::get_flag_string(flag); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } bool OSDMonitor::prepare_unset_flag(MMonCommand *m, int flag) { ostringstream ss; if (pending_inc.new_flags < 0) pending_inc.new_flags = osdmap.get_flags(); pending_inc.new_flags &= ~flag; ss << "unset " << OSDMap::get_flag_string(flag); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } int OSDMonitor::parse_osd_id(const char *s, stringstream *pss) { // osd.NNN? if (strncmp(s, "osd.", 4) == 0) { s += 4; } // NNN? ostringstream ss; long id = parse_pos_long(s, &ss); if (id < 0) { *pss << ss.str(); return id; } if (id > 0xffff) { *pss << "osd id " << id << " is too large"; return -ERANGE; } return id; } int OSDMonitor::prepare_command_pool_set(map &cmdmap, stringstream& ss) { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool = osdmap.lookup_pg_pool_name(poolstr.c_str()); if (pool < 0) { ss << "unrecognized pool '" << poolstr << "'"; return -ENOENT; } string var; cmd_getval(g_ceph_context, cmdmap, "var", var); pg_pool_t p = *osdmap.get_pg_pool(pool); if (pending_inc.new_pools.count(pool)) p = pending_inc.new_pools[pool]; // accept val as a json string in the normal case (current // generation monitor). parse out int or float values from the // string as needed. however, if it is not a string, try to pull // out an int, in case an older monitor with an older json schema is // forwarding a request. string val; string interr, floaterr; int64_t n = 0; double f = 0; int64_t uf = 0; // micro-f if (!cmd_getval(g_ceph_context, cmdmap, "val", val)) { // wasn't a string; maybe an older mon forwarded json with an int? if (!cmd_getval(g_ceph_context, cmdmap, "val", n)) return -EINVAL; // no value! } else { // we got a string. see if it contains an int. n = strict_strtoll(val.c_str(), 10, &interr); // or a float f = strict_strtod(val.c_str(), &floaterr); uf = llrintl(f * (double)1000000.0); } if (!p.is_tier() && (var == "hit_set_type" || var == "hit_set_period" || var == "hit_set_count" || var == "hit_set_fpp" || var == "target_max_objects" || var == "target_max_bytes" || var == "cache_target_full_ratio" || var == "cache_target_dirty_ratio" || var == "cache_min_flush_age" || var == "cache_min_evict_age")) { ss << "pool '" << poolstr << "' is not a tier pool: variable not applicable"; return -EACCES; } if (var == "size") { if (p.type == pg_pool_t::TYPE_ERASURE) { ss << "can not change the size of an erasure-coded pool"; return -ENOTSUP; } if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } if (n == 0 || n > 10) { ss << "pool size must be between 1 and 10"; return -EINVAL; } p.size = n; if (n < p.min_size) p.min_size = n; } else if (var == "min_size") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } p.min_size = n; } else if (var == "auid") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } p.auid = n; } else if (var == "crash_replay_interval") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } p.crash_replay_interval = n; } else if (var == "pg_num") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } if (n <= (int)p.get_pg_num()) { ss << "specified pg_num " << n << " <= current " << p.get_pg_num(); if (n < (int)p.get_pg_num()) return -EEXIST; return 0; } string force; cmd_getval(g_ceph_context,cmdmap, "force", force); if (p.cache_mode != pg_pool_t::CACHEMODE_NONE && force != "--yes-i-really-mean-it") { ss << "splits in cache pools must be followed by scrubs and leave sufficient free space to avoid overfilling. use --yes-i-really-mean-it to force."; return -EPERM; } int expected_osds = MAX(1, MIN(p.get_pg_num(), osdmap.get_num_osds())); int64_t new_pgs = n - p.get_pg_num(); int64_t pgs_per_osd = new_pgs / expected_osds; if (pgs_per_osd > g_conf->mon_osd_max_split_count) { ss << "specified pg_num " << n << " is too large (creating " << new_pgs << " new PGs on ~" << expected_osds << " OSDs exceeds per-OSD max of " << g_conf->mon_osd_max_split_count << ')'; return -E2BIG; } for(set::iterator i = mon->pgmon()->pg_map.creating_pgs.begin(); i != mon->pgmon()->pg_map.creating_pgs.end(); ++i) { if (i->m_pool == static_cast(pool)) { ss << "currently creating pgs, wait"; return -EBUSY; } } p.set_pg_num(n); } else if (var == "pgp_num") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } if (n <= 0) { ss << "specified pgp_num must > 0, but you set to " << n; return -EINVAL; } if (n > (int)p.get_pg_num()) { ss << "specified pgp_num " << n << " > pg_num " << p.get_pg_num(); return -EINVAL; } for(set::iterator i = mon->pgmon()->pg_map.creating_pgs.begin(); i != mon->pgmon()->pg_map.creating_pgs.end(); ++i) { if (i->m_pool == static_cast(pool)) { ss << "currently creating pgs, wait"; return -EBUSY; } } p.set_pgp_num(n); } else if (var == "crush_ruleset") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } if (!osdmap.crush->ruleset_exists(n)) { ss << "crush ruleset " << n << " does not exist"; return -ENOENT; } p.crush_ruleset = n; } else if (var == "hashpspool") { // make sure we only compare against 'n' if we didn't receive a string if (val == "true" || (interr.empty() && n == 1)) { p.flags |= pg_pool_t::FLAG_HASHPSPOOL; } else if (val == "false" || (interr.empty() && n == 0)) { p.flags &= ~pg_pool_t::FLAG_HASHPSPOOL; } else { ss << "expecting value 'true', 'false', '0', or '1'"; return -EINVAL; } } else if (var == "hit_set_type") { if (val == "none") p.hit_set_params = HitSet::Params(); else { int err = check_cluster_features(CEPH_FEATURE_OSD_CACHEPOOL, ss); if (err) return err; if (val == "bloom") { BloomHitSet::Params *bsp = new BloomHitSet::Params; bsp->set_fpp(g_conf->osd_pool_default_hit_set_bloom_fpp); p.hit_set_params = HitSet::Params(bsp); } else if (val == "explicit_hash") p.hit_set_params = HitSet::Params(new ExplicitHashHitSet::Params); else if (val == "explicit_object") p.hit_set_params = HitSet::Params(new ExplicitObjectHitSet::Params); else { ss << "unrecognized hit_set type '" << val << "'"; return -EINVAL; } } } else if (var == "hit_set_period") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } p.hit_set_period = n; } else if (var == "hit_set_count") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } p.hit_set_count = n; } else if (var == "hit_set_fpp") { if (floaterr.length()) { ss << "error parsing floating point value '" << val << "': " << floaterr; return -EINVAL; } if (p.hit_set_params.get_type() != HitSet::TYPE_BLOOM) { ss << "hit set is not of type Bloom; invalid to set a false positive rate!"; return -EINVAL; } BloomHitSet::Params *bloomp = static_cast(p.hit_set_params.impl.get()); bloomp->set_fpp(f); } else if (var == "debug_fake_ec_pool") { if (val == "true" || (interr.empty() && n == 1)) { p.flags |= pg_pool_t::FLAG_DEBUG_FAKE_EC_POOL; } } else if (var == "target_max_objects") { if (interr.length()) { ss << "error parsing int '" << val << "': " << interr; return -EINVAL; } p.target_max_objects = n; } else if (var == "target_max_bytes") { if (interr.length()) { ss << "error parsing int '" << val << "': " << interr; return -EINVAL; } p.target_max_bytes = n; } else if (var == "cache_target_dirty_ratio") { if (floaterr.length()) { ss << "error parsing float '" << val << "': " << floaterr; return -EINVAL; } if (f < 0 || f > 1.0) { ss << "value must be in the range 0..1"; return -ERANGE; } p.cache_target_dirty_ratio_micro = uf; } else if (var == "cache_target_full_ratio") { if (floaterr.length()) { ss << "error parsing float '" << val << "': " << floaterr; return -EINVAL; } if (f < 0 || f > 1.0) { ss << "value must be in the range 0..1"; return -ERANGE; } p.cache_target_full_ratio_micro = uf; } else if (var == "cache_min_flush_age") { if (interr.length()) { ss << "error parsing int '" << val << "': " << interr; return -EINVAL; } p.cache_min_flush_age = n; } else if (var == "cache_min_evict_age") { if (interr.length()) { ss << "error parsing int '" << val << "': " << interr; return -EINVAL; } p.cache_min_evict_age = n; } else if (var == "min_read_recency_for_promote") { if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; } p.min_read_recency_for_promote = n; } else { ss << "unrecognized variable '" << var << "'"; return -EINVAL; } ss << "set pool " << pool << " " << var << " to " << val; p.last_change = pending_inc.epoch; pending_inc.new_pools[pool] = p; return 0; } bool OSDMonitor::prepare_command(MMonCommand *m) { stringstream ss; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, get_last_committed()); return true; } MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", get_last_committed()); return true; } return prepare_command_impl(m, cmdmap); } bool OSDMonitor::prepare_command_impl(MMonCommand *m, map &cmdmap) { bool ret = false; stringstream ss; string rs; bufferlist rdata; int err = 0; string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); int64_t id; string name; bool osdid_present = cmd_getval(g_ceph_context, cmdmap, "id", id); if (osdid_present) { ostringstream oss; oss << "osd." << id; name = oss.str(); } // Even if there's a pending state with changes that could affect // a command, considering that said state isn't yet committed, we // just don't care about those changes if the command currently being // handled acts as a no-op against the current committed state. // In a nutshell, we assume this command happens *before*. // // Let me make this clearer: // // - If we have only one client, and that client issues some // operation that would conflict with this operation but is // still on the pending state, then we would be sure that said // operation wouldn't have returned yet, so the client wouldn't // issue this operation (unless the client didn't wait for the // operation to finish, and that would be the client's own fault). // // - If we have more than one client, each client will observe // whatever is the state at the moment of the commit. So, if we // have two clients, one issuing an unlink and another issuing a // link, and if the link happens while the unlink is still on the // pending state, from the link's point-of-view this is a no-op. // If different clients are issuing conflicting operations and // they care about that, then the clients should make sure they // enforce some kind of concurrency mechanism -- from our // perspective that's what Douglas Adams would call an SEP. // // This should be used as a general guideline for most commands handled // in this function. Adapt as you see fit, but please bear in mind that // this is the expected behavior. if (prefix == "osd setcrushmap" || (prefix == "osd crush set" && !osdid_present)) { dout(10) << "prepare_command setting new crush map" << dendl; bufferlist data(m->get_data()); CrushWrapper crush; try { bufferlist::iterator bl(data.begin()); crush.decode(bl); } catch (const std::exception &e) { err = -EINVAL; ss << "Failed to parse crushmap: " << e.what(); goto reply; } if (!validate_crush_against_features(&crush, ss)) { err = -EINVAL; goto reply; } // sanity check: test some inputs to make sure this map isn't totally broken dout(10) << " testing map" << dendl; stringstream ess; CrushTester tester(crush, ess); tester.test(); dout(10) << " result " << ess.str() << dendl; pending_inc.crush = data; ss << "set crush map"; goto update; } else if (prefix == "osd crush add-bucket") { // os crush add-bucket string name, typestr; cmd_getval(g_ceph_context, cmdmap, "name", name); cmd_getval(g_ceph_context, cmdmap, "type", typestr); if (!_have_pending_crush() && _get_stable_crush().name_exists(name)) { ss << "bucket '" << name << "' already exists"; goto reply; } CrushWrapper newcrush; _get_pending_crush(newcrush); if (newcrush.name_exists(name)) { ss << "bucket '" << name << "' already exists"; goto update; } int type = newcrush.get_type_id(typestr); if (type < 0) { ss << "type '" << typestr << "' does not exist"; err = -EINVAL; goto reply; } if (type == 0) { ss << "type '" << typestr << "' is for devices, not buckets"; err = -EINVAL; goto reply; } int bucketno; err = newcrush.add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_DEFAULT, type, 0, NULL, NULL, &bucketno); if (err < 0) { ss << "add_bucket error: '" << cpp_strerror(err) << "'"; goto reply; } err = newcrush.set_item_name(bucketno, name); if (err < 0) { ss << "error setting bucket name to '" << name << "'"; goto reply; } pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "added bucket " << name << " type " << typestr << " to crush map"; goto update; } else if (osdid_present && (prefix == "osd crush set" || prefix == "osd crush add")) { // is 'osd.' or '', passed as int64_t id // osd crush set [ ...] // osd crush add [ ...] if (!osdmap.exists(id)) { err = -ENOENT; ss << name << " does not exist. create it before updating the crush map"; goto reply; } double weight; if (!cmd_getval(g_ceph_context, cmdmap, "weight", weight)) { ss << "unable to parse weight value '" << cmd_vartype_stringify(cmdmap["weight"]) << "'"; err = -EINVAL; goto reply; } string args; vector argvec; cmd_getval(g_ceph_context, cmdmap, "args", argvec); map loc; CrushWrapper::parse_loc_map(argvec, &loc); if (prefix == "osd crush set" && !_get_stable_crush().item_exists(id)) { err = -ENOENT; ss << "unable to set item id " << id << " name '" << name << "' weight " << weight << " at location " << loc << ": does not exist"; goto reply; } dout(5) << "adding/updating crush item id " << id << " name '" << name << "' weight " << weight << " at location " << loc << dendl; CrushWrapper newcrush; _get_pending_crush(newcrush); string action; if (prefix == "osd crush set" || newcrush.check_item_loc(g_ceph_context, id, loc, (int *)NULL)) { action = "set"; err = newcrush.update_item(g_ceph_context, id, weight, name, loc); } else { action = "add"; err = newcrush.insert_item(g_ceph_context, id, weight, name, loc); if (err == 0) err = 1; } if (err < 0) goto reply; if (err == 0 && !_have_pending_crush()) { ss << action << " item id " << id << " name '" << name << "' weight " << weight << " at location " << loc << ": no change"; goto reply; } pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << action << " item id " << id << " name '" << name << "' weight " << weight << " at location " << loc << " to crush map"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd crush create-or-move") { do { // osd crush create-or-move [ ...] if (!osdmap.exists(id)) { err = -ENOENT; ss << name << " does not exist. create it before updating the crush map"; goto reply; } double weight; if (!cmd_getval(g_ceph_context, cmdmap, "weight", weight)) { ss << "unable to parse weight value '" << cmd_vartype_stringify(cmdmap["weight"]) << "'"; err = -EINVAL; goto reply; } string args; vector argvec; cmd_getval(g_ceph_context, cmdmap, "args", argvec); map loc; CrushWrapper::parse_loc_map(argvec, &loc); dout(0) << "create-or-move crush item name '" << name << "' initial_weight " << weight << " at location " << loc << dendl; CrushWrapper newcrush; _get_pending_crush(newcrush); err = newcrush.create_or_move_item(g_ceph_context, id, weight, name, loc); if (err == 0) { ss << "create-or-move updated item name '" << name << "' weight " << weight << " at location " << loc << " to crush map"; break; } if (err > 0) { pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "create-or-move updating item name '" << name << "' weight " << weight << " at location " << loc << " to crush map"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } while (false); } else if (prefix == "osd crush move") { do { // osd crush move [ ...] string args; vector argvec; cmd_getval(g_ceph_context, cmdmap, "name", name); cmd_getval(g_ceph_context, cmdmap, "args", argvec); map loc; CrushWrapper::parse_loc_map(argvec, &loc); dout(0) << "moving crush item name '" << name << "' to location " << loc << dendl; CrushWrapper newcrush; _get_pending_crush(newcrush); if (!newcrush.name_exists(name)) { err = -ENOENT; ss << "item " << name << " does not exist"; break; } int id = newcrush.get_item_id(name); if (!newcrush.check_item_loc(g_ceph_context, id, loc, (int *)NULL)) { err = newcrush.move_bucket(g_ceph_context, id, loc); if (err >= 0) { ss << "moved item id " << id << " name '" << name << "' to location " << loc << " in crush map"; pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else { ss << "no need to move item id " << id << " name '" << name << "' to location " << loc << " in crush map"; err = 0; } } while (false); } else if (prefix == "osd crush link") { // osd crush link [ ...] string name; cmd_getval(g_ceph_context, cmdmap, "name", name); vector argvec; cmd_getval(g_ceph_context, cmdmap, "args", argvec); map loc; CrushWrapper::parse_loc_map(argvec, &loc); if (!osdmap.crush->name_exists(name)) { err = -ENOENT; ss << "item " << name << " does not exist"; goto reply; } if (osdmap.crush->check_item_loc(g_ceph_context, id, loc, (int*) NULL)) { ss << "no need to move item id " << id << " name '" << name << "' to location " << loc << " in crush map"; err = 0; goto reply; } dout(5) << "linking crush item name '" << name << "' at location " << loc << dendl; CrushWrapper newcrush; _get_pending_crush(newcrush); if (!newcrush.name_exists(name)) { err = -ENOENT; ss << "item " << name << " does not exist"; } else { int id = newcrush.get_item_id(name); if (!newcrush.check_item_loc(g_ceph_context, id, loc, (int *)NULL)) { err = newcrush.link_bucket(g_ceph_context, id, loc); if (err >= 0) { ss << "linked item id " << id << " name '" << name << "' to location " << loc << " in crush map"; pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); } } else { ss << "no need to move item id " << id << " name '" << name << "' to location " << loc << " in crush map"; err = 0; } } wait_for_finished_proposal(new Monitor::C_Command(mon, m, err, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd crush rm" || prefix == "osd crush remove" || prefix == "osd crush unlink") { do { // osd crush rm [ancestor] CrushWrapper newcrush; _get_pending_crush(newcrush); string name; cmd_getval(g_ceph_context, cmdmap, "name", name); if (!osdmap.crush->name_exists(name)) { err = 0; ss << "device '" << name << "' does not appear in the crush map"; break; } if (!newcrush.name_exists(name)) { err = 0; ss << "device '" << name << "' does not appear in the crush map"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } int id = newcrush.get_item_id(name); bool unlink_only = prefix == "osd crush unlink"; string ancestor_str; if (cmd_getval(g_ceph_context, cmdmap, "ancestor", ancestor_str)) { if (!newcrush.name_exists(ancestor_str)) { err = -ENOENT; ss << "ancestor item '" << ancestor_str << "' does not appear in the crush map"; break; } int ancestor = newcrush.get_item_id(ancestor_str); err = newcrush.remove_item_under(g_ceph_context, id, ancestor, unlink_only); } else { err = newcrush.remove_item(g_ceph_context, id, unlink_only); } if (err == -ENOENT) { ss << "item " << id << " does not appear in that position"; err = 0; break; } if (err == 0) { pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "removed item id " << id << " name '" << name << "' from crush map"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } while (false); } else if (prefix == "osd crush reweight-all") { // osd crush reweight CrushWrapper newcrush; _get_pending_crush(newcrush); newcrush.reweight(g_ceph_context); pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "reweighted crush hierarchy"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd crush reweight") { do { // osd crush reweight CrushWrapper newcrush; _get_pending_crush(newcrush); string name; cmd_getval(g_ceph_context, cmdmap, "name", name); if (!newcrush.name_exists(name)) { err = -ENOENT; ss << "device '" << name << "' does not appear in the crush map"; break; } int id = newcrush.get_item_id(name); if (id < 0) { ss << "device '" << name << "' is not a leaf in the crush map"; break; } double w; if (!cmd_getval(g_ceph_context, cmdmap, "weight", w)) { ss << "unable to parse weight value '" << cmd_vartype_stringify(cmdmap["weight"]) << "'"; err = -EINVAL; break; } err = newcrush.adjust_item_weightf(g_ceph_context, id, w); if (err >= 0) { pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "reweighted item id " << id << " name '" << name << "' to " << w << " in crush map"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } while (false); } else if (prefix == "osd crush tunables") { CrushWrapper newcrush; _get_pending_crush(newcrush); err = 0; string profile; cmd_getval(g_ceph_context, cmdmap, "profile", profile); if (profile == "legacy" || profile == "argonaut") { newcrush.set_tunables_legacy(); } else if (profile == "bobtail") { newcrush.set_tunables_bobtail(); } else if (profile == "firefly") { newcrush.set_tunables_firefly(); } else if (profile == "optimal") { newcrush.set_tunables_optimal(); } else if (profile == "default") { newcrush.set_tunables_default(); } else { ss << "unrecognized profile '" << profile << "'"; err = -EINVAL; goto reply; } if (!validate_crush_against_features(&newcrush, ss)) { err = -EINVAL; goto reply; } pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "adjusted tunables profile to " << profile; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd crush set-tunable") { CrushWrapper newcrush; _get_pending_crush(newcrush); err = 0; string tunable; cmd_getval(g_ceph_context, cmdmap, "tunable", tunable); int64_t value = -1; if (!cmd_getval(g_ceph_context, cmdmap, "value", value)) { err = -EINVAL; ss << "failed to parse integer value " << cmd_vartype_stringify(cmdmap["value"]); goto reply; } if (tunable == "straw_calc_version") { if (value < 0 || value > 2) { ss << "value must be 0 or 1; got " << value; err = -EINVAL; goto reply; } newcrush.set_straw_calc_version(value); } else { ss << "unrecognized tunable '" << tunable << "'"; err = -EINVAL; goto reply; } if (!validate_crush_against_features(&newcrush, ss)) { err = -EINVAL; goto reply; } pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); ss << "adjusted tunable " << tunable << " to " << value; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd crush rule create-simple") { string name, root, type, mode; cmd_getval(g_ceph_context, cmdmap, "name", name); cmd_getval(g_ceph_context, cmdmap, "root", root); cmd_getval(g_ceph_context, cmdmap, "type", type); cmd_getval(g_ceph_context, cmdmap, "mode", mode); if (mode == "") mode = "firstn"; if (osdmap.crush->rule_exists(name)) { ss << "rule " << name << " already exists"; err = 0; goto reply; } CrushWrapper newcrush; _get_pending_crush(newcrush); if (newcrush.rule_exists(name)) { ss << "rule " << name << " already exists"; err = 0; } else { int rule = newcrush.add_simple_ruleset(name, root, type, mode, pg_pool_t::TYPE_REPLICATED, &ss); if (rule < 0) { err = rule; goto reply; } pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd erasure-code-profile rm") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); if (erasure_code_profile_in_use(pending_inc.new_pools, name, ss)) goto wait; if (erasure_code_profile_in_use(osdmap.pools, name, ss)) { err = -EBUSY; goto reply; } if (osdmap.has_erasure_code_profile(name) || pending_inc.new_erasure_code_profiles.count(name)) { if (osdmap.has_erasure_code_profile(name)) { pending_inc.old_erasure_code_profiles.push_back(name); } else { dout(20) << "erasure code profile rm " << name << ": creation canceled" << dendl; pending_inc.new_erasure_code_profiles.erase(name); } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else { ss << "erasure-code-profile " << name << " does not exist"; err = 0; goto reply; } } else if (prefix == "osd erasure-code-profile set") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); vector profile; cmd_getval(g_ceph_context, cmdmap, "profile", profile); bool force; if (profile.size() > 0 && profile.back() == "--force") { profile.pop_back(); force = true; } else { force = false; } map profile_map; err = parse_erasure_code_profile(profile, &profile_map, ss); if (err) goto reply; if (osdmap.has_erasure_code_profile(name)) { if (osdmap.get_erasure_code_profile(name) == profile_map) { err = 0; goto reply; } if (!force) { err = -EPERM; ss << "will not override erasure code profile " << name; goto reply; } } if (pending_inc.has_erasure_code_profile(name)) { dout(20) << "erasure code profile " << name << " try again" << dendl; goto wait; } else { dout(20) << "erasure code profile " << name << " set" << dendl; pending_inc.set_erasure_code_profile(name, profile_map); } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd crush rule create-erasure") { err = check_cluster_features(CEPH_FEATURE_CRUSH_V2, ss); if (err == -EAGAIN) goto wait; if (err) goto reply; string name, poolstr; cmd_getval(g_ceph_context, cmdmap, "name", name); string profile; cmd_getval(g_ceph_context, cmdmap, "profile", profile); if (profile == "") profile = "default"; if (profile == "default") { if (!osdmap.has_erasure_code_profile(profile)) { if (pending_inc.has_erasure_code_profile(profile)) { dout(20) << "erasure code profile " << profile << " already pending" << dendl; goto wait; } map profile_map; err = osdmap.get_erasure_code_profile_default(g_ceph_context, profile_map, &ss); if (err) goto reply; dout(20) << "erasure code profile " << profile << " set" << dendl; pending_inc.set_erasure_code_profile(profile, profile_map); goto wait; } } int ruleset; err = crush_ruleset_create_erasure(name, profile, &ruleset, ss); if (err < 0) { switch(err) { case -EEXIST: // return immediately ss << "rule " << name << " already exists"; err = 0; goto reply; break; case -EALREADY: // wait for pending to be proposed ss << "rule " << name << " already exists"; err = 0; break; default: // non recoverable error goto reply; break; } } else { ss << "created ruleset " << name << " at " << ruleset; } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd crush rule rm") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); if (!osdmap.crush->rule_exists(name)) { ss << "rule " << name << " does not exist"; err = 0; goto reply; } CrushWrapper newcrush; _get_pending_crush(newcrush); if (!newcrush.rule_exists(name)) { ss << "rule " << name << " does not exist"; err = 0; } else { int ruleno = newcrush.get_rule_id(name); assert(ruleno >= 0); // make sure it is not in use. // FIXME: this is ok in some situations, but let's not bother with that // complexity now. int ruleset = newcrush.get_rule_mask_ruleset(ruleno); if (osdmap.crush_ruleset_in_use(ruleset)) { ss << "crush rule " << name << " ruleset " << ruleset << " is in use"; err = -EBUSY; goto reply; } err = newcrush.remove_rule(ruleno); if (err < 0) { goto reply; } pending_inc.crush.clear(); newcrush.encode(pending_inc.crush); } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd setmaxosd") { int64_t newmax; if (!cmd_getval(g_ceph_context, cmdmap, "newmax", newmax)) { ss << "unable to parse 'newmax' value '" << cmd_vartype_stringify(cmdmap["newmax"]) << "'"; err = -EINVAL; goto reply; } if (newmax > g_conf->mon_max_osd) { err = -ERANGE; ss << "cannot set max_osd to " << newmax << " which is > conf.mon_max_osd (" << g_conf->mon_max_osd << ")"; goto reply; } pending_inc.new_max_osd = newmax; ss << "set new max_osd = " << pending_inc.new_max_osd; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd pause") { return prepare_set_flag(m, CEPH_OSDMAP_PAUSERD | CEPH_OSDMAP_PAUSEWR); } else if (prefix == "osd unpause") { return prepare_unset_flag(m, CEPH_OSDMAP_PAUSERD | CEPH_OSDMAP_PAUSEWR); } else if (prefix == "osd set") { string key; cmd_getval(g_ceph_context, cmdmap, "key", key); if (key == "pause") return prepare_set_flag(m, CEPH_OSDMAP_PAUSERD | CEPH_OSDMAP_PAUSEWR); else if (key == "noup") return prepare_set_flag(m, CEPH_OSDMAP_NOUP); else if (key == "nodown") return prepare_set_flag(m, CEPH_OSDMAP_NODOWN); else if (key == "noout") return prepare_set_flag(m, CEPH_OSDMAP_NOOUT); else if (key == "noin") return prepare_set_flag(m, CEPH_OSDMAP_NOIN); else if (key == "nobackfill") return prepare_set_flag(m, CEPH_OSDMAP_NOBACKFILL); else if (key == "norecover") return prepare_set_flag(m, CEPH_OSDMAP_NORECOVER); else if (key == "noscrub") return prepare_set_flag(m, CEPH_OSDMAP_NOSCRUB); else if (key == "nodeep-scrub") return prepare_set_flag(m, CEPH_OSDMAP_NODEEP_SCRUB); else if (key == "notieragent") return prepare_set_flag(m, CEPH_OSDMAP_NOTIERAGENT); else { ss << "unrecognized flag '" << key << "'"; err = -EINVAL; } } else if (prefix == "osd unset") { string key; cmd_getval(g_ceph_context, cmdmap, "key", key); if (key == "pause") return prepare_unset_flag(m, CEPH_OSDMAP_PAUSERD | CEPH_OSDMAP_PAUSEWR); else if (key == "noup") return prepare_unset_flag(m, CEPH_OSDMAP_NOUP); else if (key == "nodown") return prepare_unset_flag(m, CEPH_OSDMAP_NODOWN); else if (key == "noout") return prepare_unset_flag(m, CEPH_OSDMAP_NOOUT); else if (key == "noin") return prepare_unset_flag(m, CEPH_OSDMAP_NOIN); else if (key == "nobackfill") return prepare_unset_flag(m, CEPH_OSDMAP_NOBACKFILL); else if (key == "norecover") return prepare_unset_flag(m, CEPH_OSDMAP_NORECOVER); else if (key == "noscrub") return prepare_unset_flag(m, CEPH_OSDMAP_NOSCRUB); else if (key == "nodeep-scrub") return prepare_unset_flag(m, CEPH_OSDMAP_NODEEP_SCRUB); else if (key == "notieragent") return prepare_unset_flag(m, CEPH_OSDMAP_NOTIERAGENT); else { ss << "unrecognized flag '" << key << "'"; err = -EINVAL; } } else if (prefix == "osd cluster_snap") { // ** DISABLE THIS FOR NOW ** ss << "cluster snapshot currently disabled (broken implementation)"; // ** DISABLE THIS FOR NOW ** } else if (prefix == "osd down" || prefix == "osd out" || prefix == "osd in" || prefix == "osd rm") { bool any = false; vector idvec; cmd_getval(g_ceph_context, cmdmap, "ids", idvec); for (unsigned j = 0; j < idvec.size(); j++) { long osd = parse_osd_id(idvec[j].c_str(), &ss); if (osd < 0) { ss << "invalid osd id" << osd; err = -EINVAL; continue; } else if (!osdmap.exists(osd)) { ss << "osd." << osd << " does not exist. "; continue; } if (prefix == "osd down") { if (osdmap.is_down(osd)) { ss << "osd." << osd << " is already down. "; } else { pending_inc.new_state[osd] = CEPH_OSD_UP; ss << "marked down osd." << osd << ". "; any = true; } } else if (prefix == "osd out") { if (osdmap.is_out(osd)) { ss << "osd." << osd << " is already out. "; } else { pending_inc.new_weight[osd] = CEPH_OSD_OUT; ss << "marked out osd." << osd << ". "; any = true; } } else if (prefix == "osd in") { if (osdmap.is_in(osd)) { ss << "osd." << osd << " is already in. "; } else { pending_inc.new_weight[osd] = CEPH_OSD_IN; ss << "marked in osd." << osd << ". "; any = true; } } else if (prefix == "osd rm") { if (osdmap.is_up(osd)) { if (any) ss << ", "; ss << "osd." << osd << " is still up; must be down before removal. "; err = -EBUSY; } else { pending_inc.new_state[osd] = osdmap.get_state(osd); pending_inc.new_uuid[osd] = uuid_d(); pending_metadata_rm.insert(osd); if (any) { ss << ", osd." << osd; } else { ss << "removed osd." << osd; } any = true; } } } if (any) { getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, err, rs, get_last_committed() + 1)); return true; } } else if (prefix == "osd pg-temp") { string pgidstr; if (!cmd_getval(g_ceph_context, cmdmap, "pgid", pgidstr)) { ss << "unable to parse 'pgid' value '" << cmd_vartype_stringify(cmdmap["pgid"]) << "'"; err = -EINVAL; goto reply; } pg_t pgid; if (!pgid.parse(pgidstr.c_str())) { ss << "invalid pgid '" << pgidstr << "'"; err = -EINVAL; goto reply; } PGMap& pg_map = mon->pgmon()->pg_map; if (!pg_map.pg_stat.count(pgid)) { ss << "pg " << pgid << " does not exist"; err = -ENOENT; goto reply; } vector id_vec; vector new_pg_temp; if (!cmd_getval(g_ceph_context, cmdmap, "id", id_vec)) { ss << "unable to parse 'id' value(s) '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; err = -EINVAL; goto reply; } for (unsigned i = 0; i < id_vec.size(); i++) { int32_t osd = parse_osd_id(id_vec[i].c_str(), &ss); if (osd < 0) { err = -EINVAL; goto reply; } if (!osdmap.exists(osd)) { ss << "osd." << osd << " does not exist"; err = -ENOENT; goto reply; } new_pg_temp.push_back(osd); } pending_inc.new_pg_temp[pgid] = new_pg_temp; ss << "set " << pgid << " pg_temp mapping to " << new_pg_temp; goto update; } else if (prefix == "osd primary-temp") { string pgidstr; if (!cmd_getval(g_ceph_context, cmdmap, "pgid", pgidstr)) { ss << "unable to parse 'pgid' value '" << cmd_vartype_stringify(cmdmap["pgid"]) << "'"; err = -EINVAL; goto reply; } pg_t pgid; if (!pgid.parse(pgidstr.c_str())) { ss << "invalid pgid '" << pgidstr << "'"; err = -EINVAL; goto reply; } PGMap& pg_map = mon->pgmon()->pg_map; if (!pg_map.pg_stat.count(pgid)) { ss << "pg " << pgid << " does not exist"; err = -ENOENT; goto reply; } string id; int32_t osd; if (!cmd_getval(g_ceph_context, cmdmap, "id", id)) { ss << "unable to parse 'id' value '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; err = -EINVAL; goto reply; } if (strcmp(id.c_str(), "-1")) { osd = parse_osd_id(id.c_str(), &ss); if (osd < 0) { err = -EINVAL; goto reply; } if (!osdmap.exists(osd)) { ss << "osd." << osd << " does not exist"; err = -ENOENT; goto reply; } } else { osd = -1; } if (!g_conf->mon_osd_allow_primary_temp) { ss << "you must enable 'mon osd allow primary temp = true' on the mons before you can set primary_temp mappings. note that this is for developers only: older clients/OSDs will break and there is no feature bit infrastructure in place."; err = -EPERM; goto reply; } pending_inc.new_primary_temp[pgid] = osd; ss << "set " << pgid << " primary_temp mapping to " << osd; goto update; } else if (prefix == "osd primary-affinity") { int64_t id; if (!cmd_getval(g_ceph_context, cmdmap, "id", id)) { ss << "invalid osd id value '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; err = -EINVAL; goto reply; } double w; if (!cmd_getval(g_ceph_context, cmdmap, "weight", w)) { ss << "unable to parse 'weight' value '" << cmd_vartype_stringify(cmdmap["weight"]) << "'"; err = -EINVAL; goto reply; } long ww = (int)((double)CEPH_OSD_MAX_PRIMARY_AFFINITY*w); if (ww < 0L) { ss << "weight must be >= 0"; err = -EINVAL; goto reply; } if (!g_conf->mon_osd_allow_primary_affinity) { ss << "you must enable 'mon osd allow primary affinity = true' on the mons before you can adjust primary-affinity. note that older clients will no longer be able to communicate with the cluster."; err = -EPERM; goto reply; } err = check_cluster_features(CEPH_FEATURE_OSD_PRIMARY_AFFINITY, ss); if (err == -EAGAIN) goto wait; if (err < 0) goto reply; if (osdmap.exists(id)) { pending_inc.new_primary_affinity[id] = ww; ss << "set osd." << id << " primary-affinity to " << w << " (" << ios::hex << ww << ios::dec << ")"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else if (prefix == "osd reweight") { int64_t id; if (!cmd_getval(g_ceph_context, cmdmap, "id", id)) { ss << "unable to parse osd id value '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; err = -EINVAL; goto reply; } double w; if (!cmd_getval(g_ceph_context, cmdmap, "weight", w)) { ss << "unable to parse weight value '" << cmd_vartype_stringify(cmdmap["weight"]) << "'"; err = -EINVAL; goto reply; } long ww = (int)((double)CEPH_OSD_IN*w); if (ww < 0L) { ss << "weight must be >= 0"; err = -EINVAL; goto reply; } if (osdmap.exists(id)) { pending_inc.new_weight[id] = ww; ss << "reweighted osd." << id << " to " << w << " (" << std::hex << ww << std::dec << ")"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else if (prefix == "osd lost") { int64_t id; if (!cmd_getval(g_ceph_context, cmdmap, "id", id)) { ss << "unable to parse osd id value '" << cmd_vartype_stringify(cmdmap["id"]) << "'"; err = -EINVAL; goto reply; } string sure; if (!cmd_getval(g_ceph_context, cmdmap, "sure", sure) || sure != "--yes-i-really-mean-it") { ss << "are you SURE? this might mean real, permanent data loss. pass " "--yes-i-really-mean-it if you really do."; err = -EPERM; goto reply; } else if (!osdmap.exists(id) || !osdmap.is_down(id)) { ss << "osd." << id << " is not down or doesn't exist"; } else { epoch_t e = osdmap.get_info(id).down_at; pending_inc.new_lost[id] = e; ss << "marked osd lost in epoch " << e; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else if (prefix == "osd create") { int i = -1; // optional uuid provided? uuid_d uuid; string uuidstr; if (cmd_getval(g_ceph_context, cmdmap, "uuid", uuidstr)) { if (!uuid.parse(uuidstr.c_str())) { err = -EINVAL; goto reply; } dout(10) << " osd create got uuid " << uuid << dendl; i = osdmap.identify_osd(uuid); if (i >= 0) { // osd already exists err = 0; if (f) { f->open_object_section("created_osd"); f->dump_int("osdid", i); f->close_section(); f->flush(rdata); } else { ss << i; rdata.append(ss); } goto reply; } i = pending_inc.identify_osd(uuid); if (i >= 0) { // osd is about to exist wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } } // allocate a new id for (i=0; i < osdmap.get_max_osd(); i++) { if (!osdmap.exists(i) && pending_inc.new_up_client.count(i) == 0 && (pending_inc.new_state.count(i) == 0 || (pending_inc.new_state[i] & CEPH_OSD_EXISTS) == 0)) goto done; } // raise max_osd if (pending_inc.new_max_osd < 0) pending_inc.new_max_osd = osdmap.get_max_osd() + 1; else pending_inc.new_max_osd++; i = pending_inc.new_max_osd - 1; done: dout(10) << " creating osd." << i << dendl; pending_inc.new_state[i] |= CEPH_OSD_EXISTS | CEPH_OSD_NEW; if (!uuid.is_zero()) pending_inc.new_uuid[i] = uuid; if (f) { f->open_object_section("created_osd"); f->dump_int("osdid", i); f->close_section(); f->flush(rdata); } else { ss << i; rdata.append(ss); } wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, rdata, get_last_committed() + 1)); return true; } else if (prefix == "osd blacklist") { string addrstr; cmd_getval(g_ceph_context, cmdmap, "addr", addrstr); entity_addr_t addr; if (!addr.parse(addrstr.c_str(), 0)) ss << "unable to parse address " << addrstr; else { string blacklistop; cmd_getval(g_ceph_context, cmdmap, "blacklistop", blacklistop); if (blacklistop == "add") { utime_t expires = ceph_clock_now(g_ceph_context); double d; // default one hour cmd_getval(g_ceph_context, cmdmap, "expire", d, double(60*60)); expires += d; pending_inc.new_blacklist[addr] = expires; ss << "blacklisting " << addr << " until " << expires << " (" << d << " sec)"; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (blacklistop == "rm") { if (osdmap.is_blacklisted(addr) || pending_inc.new_blacklist.count(addr)) { if (osdmap.is_blacklisted(addr)) pending_inc.old_blacklist.push_back(addr); else pending_inc.new_blacklist.erase(addr); ss << "un-blacklisting " << addr; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } ss << addr << " isn't blacklisted"; err = 0; goto reply; } } } else if (prefix == "osd pool mksnap") { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool = osdmap.lookup_pg_pool_name(poolstr.c_str()); if (pool < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string snapname; cmd_getval(g_ceph_context, cmdmap, "snap", snapname); const pg_pool_t *p = osdmap.get_pg_pool(pool); if (p->is_unmanaged_snaps_mode()) { ss << "pool " << poolstr << " is in unmanaged snaps mode"; err = -EINVAL; goto reply; } else if (p->snap_exists(snapname.c_str())) { ss << "pool " << poolstr << " snap " << snapname << " already exists"; err = 0; goto reply; } pg_pool_t *pp = 0; if (pending_inc.new_pools.count(pool)) pp = &pending_inc.new_pools[pool]; if (!pp) { pp = &pending_inc.new_pools[pool]; *pp = *p; } if (pp->snap_exists(snapname.c_str())) { ss << "pool " << poolstr << " snap " << snapname << " already exists"; } else { pp->add_snap(snapname.c_str(), ceph_clock_now(g_ceph_context)); pp->set_snap_epoch(pending_inc.epoch); ss << "created pool " << poolstr << " snap " << snapname; } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd pool rmsnap") { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool = osdmap.lookup_pg_pool_name(poolstr.c_str()); if (pool < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string snapname; cmd_getval(g_ceph_context, cmdmap, "snap", snapname); const pg_pool_t *p = osdmap.get_pg_pool(pool); if (p->is_unmanaged_snaps_mode()) { ss << "pool " << poolstr << " is in unmanaged snaps mode"; err = -EINVAL; goto reply; } else if (!p->snap_exists(snapname.c_str())) { ss << "pool " << poolstr << " snap " << snapname << " does not exist"; err = 0; goto reply; } pg_pool_t *pp = 0; if (pending_inc.new_pools.count(pool)) pp = &pending_inc.new_pools[pool]; if (!pp) { pp = &pending_inc.new_pools[pool]; *pp = *p; } snapid_t sn = pp->snap_exists(snapname.c_str()); if (sn) { pp->remove_snap(sn); pp->set_snap_epoch(pending_inc.epoch); ss << "removed pool " << poolstr << " snap " << snapname; } else { ss << "already removed pool " << poolstr << " snap " << snapname; } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd pool create") { int64_t pg_num; int64_t pgp_num; cmd_getval(g_ceph_context, cmdmap, "pg_num", pg_num, int64_t(0)); if ((pg_num == 0) || (pg_num > g_conf->mon_max_pool_pg_num)) { ss << "'pg_num' must be greater than 0 and less than or equal to " << g_conf->mon_max_pool_pg_num << " (you may adjust 'mon max pool pg num' for higher values)"; err = -ERANGE; goto reply; } cmd_getval(g_ceph_context, cmdmap, "pgp_num", pgp_num, pg_num); if ((pgp_num == 0) || (pgp_num > pg_num)) { ss << "'pgp_num' must be greater than 0 and lower or equal than 'pg_num'" << ", which in this case is " << pg_num; err = -ERANGE; goto reply; } string pool_type_str; cmd_getval(g_ceph_context, cmdmap, "pool_type", pool_type_str); if (pool_type_str.empty()) pool_type_str = pg_pool_t::get_default_type(); string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id >= 0) { const pg_pool_t *p = osdmap.get_pg_pool(pool_id); if (pool_type_str != p->get_type_name()) { ss << "pool '" << poolstr << "' cannot change to type " << pool_type_str; err = -EINVAL; } else { ss << "pool '" << poolstr << "' already exists"; err = 0; } goto reply; } int pool_type; if (pool_type_str == "replicated") { pool_type = pg_pool_t::TYPE_REPLICATED; } else if (pool_type_str == "erasure") { err = check_cluster_features(CEPH_FEATURE_CRUSH_V2 | CEPH_FEATURE_OSD_ERASURE_CODES, ss); if (err == -EAGAIN) goto wait; if (err) goto reply; pool_type = pg_pool_t::TYPE_ERASURE; } else { ss << "unknown pool type '" << pool_type_str << "'"; err = -EINVAL; goto reply; } string ruleset_name; cmd_getval(g_ceph_context, cmdmap, "ruleset", ruleset_name); string erasure_code_profile; cmd_getval(g_ceph_context, cmdmap, "erasure_code_profile", erasure_code_profile); if (pool_type == pg_pool_t::TYPE_ERASURE) { if (erasure_code_profile == "") erasure_code_profile = "default"; //handle the erasure code profile if (erasure_code_profile == "default") { if (!osdmap.has_erasure_code_profile(erasure_code_profile)) { if (pending_inc.has_erasure_code_profile(erasure_code_profile)) { dout(20) << "erasure code profile " << erasure_code_profile << " already pending" << dendl; goto wait; } map profile_map; err = osdmap.get_erasure_code_profile_default(g_ceph_context, profile_map, &ss); if (err) goto reply; dout(20) << "erasure code profile " << erasure_code_profile << " set" << dendl; pending_inc.set_erasure_code_profile(erasure_code_profile, profile_map); goto wait; } } if (ruleset_name == "") { if (erasure_code_profile == "default") { ruleset_name = "erasure-code"; } else { dout(1) << "implicitly use ruleset named after the pool: " << poolstr << dendl; ruleset_name = poolstr; } } } else { //NOTE:for replicated pool,cmd_map will put ruleset_name to erasure_code_profile field ruleset_name = erasure_code_profile; } err = prepare_new_pool(poolstr, 0, // auid=0 for admin created pool -1, // default crush rule ruleset_name, pg_num, pgp_num, erasure_code_profile, pool_type, ss); if (err < 0) { switch(err) { case -EEXIST: ss << "pool '" << poolstr << "' already exists"; break; case -EAGAIN: wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; default: goto reply; break; } } else { ss << "pool '" << poolstr << "' created"; } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd pool delete") { // osd pool delete --yes-i-really-really-mean-it string poolstr, poolstr2, sure; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); cmd_getval(g_ceph_context, cmdmap, "pool2", poolstr2); cmd_getval(g_ceph_context, cmdmap, "sure", sure); int64_t pool = osdmap.lookup_pg_pool_name(poolstr.c_str()); if (pool < 0) { ss << "pool '" << poolstr << "' does not exist"; err = 0; goto reply; } if (poolstr2 != poolstr || sure != "--yes-i-really-really-mean-it") { ss << "WARNING: this will *PERMANENTLY DESTROY* all data stored in pool " << poolstr << ". If you are *ABSOLUTELY CERTAIN* that is what you want, pass the pool name *twice*, " << "followed by --yes-i-really-really-mean-it."; err = -EPERM; goto reply; } err = _prepare_remove_pool(pool, &ss); if (err == -EAGAIN) { wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } if (err < 0) goto reply; goto update; } else if (prefix == "osd pool rename") { string srcpoolstr, destpoolstr; cmd_getval(g_ceph_context, cmdmap, "srcpool", srcpoolstr); cmd_getval(g_ceph_context, cmdmap, "destpool", destpoolstr); int64_t pool_src = osdmap.lookup_pg_pool_name(srcpoolstr.c_str()); int64_t pool_dst = osdmap.lookup_pg_pool_name(destpoolstr.c_str()); if (pool_src < 0) { if (pool_dst >= 0) { // src pool doesn't exist, dst pool does exist: to ensure idempotency // of operations, assume this rename succeeded, as it is not changing // the current state. Make sure we output something understandable // for whoever is issuing the command, if they are paying attention, // in case it was not intentional; or to avoid a "wtf?" and a bug // report in case it was intentional, while expecting a failure. ss << "pool '" << srcpoolstr << "' does not exist; pool '" << destpoolstr << "' does -- assuming successful rename"; err = 0; } else { ss << "unrecognized pool '" << srcpoolstr << "'"; err = -ENOENT; } goto reply; } else if (pool_dst >= 0) { // source pool exists and so does the destination pool ss << "pool '" << destpoolstr << "' already exists"; err = -EEXIST; goto reply; } int ret = _prepare_rename_pool(pool_src, destpoolstr); if (ret == 0) { ss << "pool '" << srcpoolstr << "' renamed to '" << destpoolstr << "'"; } else { ss << "failed to rename pool '" << srcpoolstr << "' to '" << destpoolstr << "': " << cpp_strerror(ret); } getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, ret, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd pool set") { err = prepare_command_pool_set(cmdmap, ss); if (err == -EAGAIN) goto wait; if (err < 0) goto reply; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd tier add") { err = check_cluster_features(CEPH_FEATURE_OSD_CACHEPOOL, ss); if (err == -EAGAIN) goto wait; if (err) goto reply; string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string tierpoolstr; cmd_getval(g_ceph_context, cmdmap, "tierpool", tierpoolstr); int64_t tierpool_id = osdmap.lookup_pg_pool_name(tierpoolstr); if (tierpool_id < 0) { ss << "unrecognized pool '" << tierpoolstr << "'"; err = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool_id); assert(p); const pg_pool_t *tp = osdmap.get_pg_pool(tierpool_id); assert(tp); if (p->tiers.count(tierpool_id)) { assert(tp->tier_of == pool_id); err = 0; ss << "pool '" << tierpoolstr << "' is now (or already was) a tier of '" << poolstr << "'"; goto reply; } if (tp->is_tier()) { ss << "tier pool '" << tierpoolstr << "' is already a tier of '" << osdmap.get_pool_name(tp->tier_of) << "'"; err = -EINVAL; goto reply; } // make sure new tier is empty string force_nonempty; cmd_getval(g_ceph_context, cmdmap, "force_nonempty", force_nonempty); const pool_stat_t& tier_stats = mon->pgmon()->pg_map.get_pg_pool_sum_stat(tierpool_id); if (tier_stats.stats.sum.num_objects != 0 && force_nonempty != "--force-nonempty") { ss << "tier pool '" << tierpoolstr << "' is not empty; --force-nonempty to force"; err = -ENOTEMPTY; goto reply; } if (tp->ec_pool()) { ss << "tier pool '" << tierpoolstr << "' is an ec pool, which cannot be a tier"; err = -ENOTSUP; goto reply; } if (!tp->removed_snaps.empty() || !tp->snaps.empty()) { ss << "tier pool '" << tierpoolstr << "' has snapshot state; it cannot be added as a tier without breaking the pool"; err = -ENOTEMPTY; goto reply; } // go pg_pool_t *np = pending_inc.get_new_pool(pool_id, p); pg_pool_t *ntp = pending_inc.get_new_pool(tierpool_id, tp); if (np->tiers.count(tierpool_id) || ntp->is_tier()) { wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } np->tiers.insert(tierpool_id); np->set_snap_epoch(pending_inc.epoch); // tier will update to our snap info ntp->tier_of = pool_id; ss << "pool '" << tierpoolstr << "' is now (or already was) a tier of '" << poolstr << "'"; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd tier remove") { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string tierpoolstr; cmd_getval(g_ceph_context, cmdmap, "tierpool", tierpoolstr); int64_t tierpool_id = osdmap.lookup_pg_pool_name(tierpoolstr); if (tierpool_id < 0) { ss << "unrecognized pool '" << tierpoolstr << "'"; err = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool_id); assert(p); const pg_pool_t *tp = osdmap.get_pg_pool(tierpool_id); assert(tp); if (p->tiers.count(tierpool_id) == 0) { ss << "pool '" << tierpoolstr << "' is now (or already was) not a tier of '" << poolstr << "'"; err = 0; goto reply; } if (tp->tier_of != pool_id) { ss << "tier pool '" << tierpoolstr << "' is a tier of '" << osdmap.get_pool_name(tp->tier_of) << "': " // be scary about it; this is an inconsistency and bells must go off << "THIS SHOULD NOT HAVE HAPPENED AT ALL"; err = -EINVAL; goto reply; } if (p->read_tier == tierpool_id) { ss << "tier pool '" << tierpoolstr << "' is the overlay for '" << poolstr << "'; please remove-overlay first"; err = -EBUSY; goto reply; } // go pg_pool_t *np = pending_inc.get_new_pool(pool_id, p); pg_pool_t *ntp = pending_inc.get_new_pool(tierpool_id, tp); if (np->tiers.count(tierpool_id) == 0 || ntp->tier_of != pool_id || np->read_tier == tierpool_id) { wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } np->tiers.erase(tierpool_id); ntp->clear_tier(); ss << "pool '" << tierpoolstr << "' is now (or already was) not a tier of '" << poolstr << "'"; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd tier set-overlay") { err = check_cluster_features(CEPH_FEATURE_OSD_CACHEPOOL, ss); if (err == -EAGAIN) goto wait; if (err) goto reply; string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string overlaypoolstr; cmd_getval(g_ceph_context, cmdmap, "overlaypool", overlaypoolstr); int64_t overlaypool_id = osdmap.lookup_pg_pool_name(overlaypoolstr); if (overlaypool_id < 0) { ss << "unrecognized pool '" << overlaypoolstr << "'"; err = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool_id); assert(p); if (p->tiers.count(overlaypool_id) == 0) { ss << "tier pool '" << overlaypoolstr << "' is not a tier of '" << poolstr << "'"; err = -EINVAL; goto reply; } if (p->read_tier == overlaypool_id) { err = 0; ss << "overlay for '" << poolstr << "' is now (or already was) '" << overlaypoolstr << "'"; goto reply; } if (p->has_read_tier()) { ss << "pool '" << poolstr << "' has overlay '" << osdmap.get_pool_name(p->read_tier) << "'; please remove-overlay first"; err = -EINVAL; goto reply; } // go pg_pool_t *np = pending_inc.get_new_pool(pool_id, p); np->read_tier = overlaypool_id; np->write_tier = overlaypool_id; np->last_force_op_resend = pending_inc.epoch; ss << "overlay for '" << poolstr << "' is now (or already was) '" << overlaypoolstr << "'"; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd tier remove-overlay") { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool_id); assert(p); if (!p->has_read_tier()) { err = 0; ss << "there is now (or already was) no overlay for '" << poolstr << "'"; goto reply; } // go pg_pool_t *np = pending_inc.get_new_pool(pool_id, p); np->clear_read_tier(); np->clear_write_tier(); np->last_force_op_resend = pending_inc.epoch; ss << "there is now (or already was) no overlay for '" << poolstr << "'"; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd tier cache-mode") { err = check_cluster_features(CEPH_FEATURE_OSD_CACHEPOOL, ss); if (err == -EAGAIN) goto wait; if (err) goto reply; string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool_id); assert(p); if (!p->is_tier()) { ss << "pool '" << poolstr << "' is not a tier"; err = -EINVAL; goto reply; } string modestr; cmd_getval(g_ceph_context, cmdmap, "mode", modestr); pg_pool_t::cache_mode_t mode = pg_pool_t::get_cache_mode_from_str(modestr); if (mode < 0) { ss << "'" << modestr << "' is not a valid cache mode"; err = -EINVAL; goto reply; } // pool already has this cache-mode set and there are no pending changes if (p->cache_mode == mode && (pending_inc.new_pools.count(pool_id) == 0 || pending_inc.new_pools[pool_id].cache_mode == p->cache_mode)) { ss << "set cache-mode for pool '" << poolstr << "'" << " to " << pg_pool_t::get_cache_mode_name(mode); err = 0; goto reply; } /* Mode description: * * none: No cache-mode defined * forward: Forward all reads and writes to base pool * writeback: Cache writes, promote reads from base pool * readonly: Forward writes to base pool * * Hence, these are the allowed transitions: * * none -> any * forward -> writeback || any IF num_objects_dirty == 0 * writeback -> forward * readonly -> any */ // We check if the transition is valid against the current pool mode, as // it is the only committed state thus far. We will blantly squash // whatever mode is on the pending state. if (p->cache_mode == pg_pool_t::CACHEMODE_WRITEBACK && mode != pg_pool_t::CACHEMODE_FORWARD) { ss << "unable to set cache-mode '" << pg_pool_t::get_cache_mode_name(mode) << "' on a '" << pg_pool_t::get_cache_mode_name(p->cache_mode) << "' pool; only '" << pg_pool_t::get_cache_mode_name(pg_pool_t::CACHEMODE_FORWARD) << "' allowed."; err = -EINVAL; goto reply; } if (p->cache_mode == pg_pool_t::CACHEMODE_FORWARD && mode != pg_pool_t::CACHEMODE_WRITEBACK) { const pool_stat_t& tier_stats = mon->pgmon()->pg_map.get_pg_pool_sum_stat(pool_id); if (tier_stats.stats.sum.num_objects_dirty > 0) { ss << "unable to set cache-mode '" << pg_pool_t::get_cache_mode_name(mode) << "' on pool '" << poolstr << "': dirty objects found"; err = -EBUSY; goto reply; } } // go pg_pool_t *np = pending_inc.get_new_pool(pool_id, p); np->cache_mode = mode; // set this both when moving to and from cache_mode NONE. this is to // capture legacy pools that were set up before this flag existed. np->flags |= pg_pool_t::FLAG_INCOMPLETE_CLONES; ss << "set cache-mode for pool '" << poolstr << "' to " << pg_pool_t::get_cache_mode_name(mode); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd tier add-cache") { err = check_cluster_features(CEPH_FEATURE_OSD_CACHEPOOL, ss); if (err == -EAGAIN) goto wait; if (err) goto reply; string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string tierpoolstr; cmd_getval(g_ceph_context, cmdmap, "tierpool", tierpoolstr); int64_t tierpool_id = osdmap.lookup_pg_pool_name(tierpoolstr); if (tierpool_id < 0) { ss << "unrecognized pool '" << tierpoolstr << "'"; err = -ENOENT; goto reply; } const pg_pool_t *p = osdmap.get_pg_pool(pool_id); assert(p); const pg_pool_t *tp = osdmap.get_pg_pool(tierpool_id); assert(tp); if (p->tiers.count(tierpool_id)) { assert(tp->tier_of == pool_id); err = 0; ss << "pool '" << tierpoolstr << "' is now (or already was) a tier of '" << poolstr << "'"; goto reply; } if (tp->is_tier()) { ss << "tier pool '" << tierpoolstr << "' is already a tier of '" << osdmap.get_pool_name(tp->tier_of) << "'"; err = -EINVAL; goto reply; } int64_t size = 0; if (!cmd_getval(g_ceph_context, cmdmap, "size", size)) { ss << "unable to parse 'size' value '" << cmd_vartype_stringify(cmdmap["size"]) << "'"; err = -EINVAL; goto reply; } // make sure new tier is empty const pool_stat_t& tier_stats = mon->pgmon()->pg_map.get_pg_pool_sum_stat(tierpool_id); if (tier_stats.stats.sum.num_objects != 0) { ss << "tier pool '" << tierpoolstr << "' is not empty"; err = -ENOTEMPTY; goto reply; } string modestr = g_conf->osd_tier_default_cache_mode; pg_pool_t::cache_mode_t mode = pg_pool_t::get_cache_mode_from_str(modestr); if (mode < 0) { ss << "osd tier cache default mode '" << modestr << "' is not a valid cache mode"; err = -EINVAL; goto reply; } HitSet::Params hsp; if (g_conf->osd_tier_default_cache_hit_set_type == "bloom") { BloomHitSet::Params *bsp = new BloomHitSet::Params; bsp->set_fpp(g_conf->osd_pool_default_hit_set_bloom_fpp); hsp = HitSet::Params(bsp); } else if (g_conf->osd_tier_default_cache_hit_set_type == "explicit_hash") { hsp = HitSet::Params(new ExplicitHashHitSet::Params); } else if (g_conf->osd_tier_default_cache_hit_set_type == "explicit_object") { hsp = HitSet::Params(new ExplicitObjectHitSet::Params); } else { ss << "osd tier cache default hit set type '" << g_conf->osd_tier_default_cache_hit_set_type << "' is not a known type"; err = -EINVAL; goto reply; } // go pg_pool_t *np = pending_inc.get_new_pool(pool_id, p); pg_pool_t *ntp = pending_inc.get_new_pool(tierpool_id, tp); if (np->tiers.count(tierpool_id) || ntp->is_tier()) { wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } np->tiers.insert(tierpool_id); np->set_snap_epoch(pending_inc.epoch); // tier will update to our snap info ntp->tier_of = pool_id; ntp->cache_mode = mode; ntp->hit_set_count = g_conf->osd_tier_default_cache_hit_set_count; ntp->hit_set_period = g_conf->osd_tier_default_cache_hit_set_period; ntp->min_read_recency_for_promote = g_conf->osd_tier_default_cache_min_read_recency_for_promote; ntp->hit_set_params = hsp; ntp->target_max_bytes = size; ss << "pool '" << tierpoolstr << "' is now (or already was) a cache tier of '" << poolstr << "'"; wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, ss.str(), get_last_committed() + 1)); return true; } else if (prefix == "osd pool set-quota") { string poolstr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); int64_t pool_id = osdmap.lookup_pg_pool_name(poolstr); if (pool_id < 0) { ss << "unrecognized pool '" << poolstr << "'"; err = -ENOENT; goto reply; } string field; cmd_getval(g_ceph_context, cmdmap, "field", field); if (field != "max_objects" && field != "max_bytes") { ss << "unrecognized field '" << field << "'; max_bytes of max_objects"; err = -EINVAL; goto reply; } // val could contain unit designations, so we treat as a string string val; cmd_getval(g_ceph_context, cmdmap, "val", val); stringstream tss; int64_t value = unit_to_bytesize(val, &tss); if (value < 0) { ss << "error parsing value '" << value << "': " << tss.str(); err = value; goto reply; } pg_pool_t *pi = pending_inc.get_new_pool(pool_id, osdmap.get_pg_pool(pool_id)); if (field == "max_objects") { pi->quota_max_objects = value; } else if (field == "max_bytes") { pi->quota_max_bytes = value; } else { assert(0 == "unrecognized option"); } ss << "set-quota " << field << " = " << value << " for pool " << poolstr; rs = ss.str(); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "osd reweight-by-utilization") { int64_t oload; cmd_getval(g_ceph_context, cmdmap, "oload", oload, int64_t(120)); string out_str; err = reweight_by_utilization(oload, out_str); if (err < 0) { ss << "FAILED reweight-by-utilization: " << out_str; } else if (err == 0) { ss << "no change: " << out_str; } else { ss << "SUCCESSFUL reweight-by-utilization: " << out_str; getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } } else if (prefix == "osd thrash") { int64_t num_epochs; cmd_getval(g_ceph_context, cmdmap, "num_epochs", num_epochs, int64_t(0)); // thrash_map is a member var thrash_map = num_epochs; ss << "will thrash map for " << thrash_map << " epochs"; ret = thrash(); err = 0; } else { err = -EINVAL; } reply: getline(ss, rs); if (err < 0 && rs.length() == 0) rs = cpp_strerror(err); mon->reply_command(m, err, rs, rdata, get_last_committed()); return ret; update: getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; wait: wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } bool OSDMonitor::preprocess_pool_op(MPoolOp *m) { if (m->op == POOL_OP_CREATE) return preprocess_pool_op_create(m); if (!osdmap.get_pg_pool(m->pool)) { dout(10) << "attempt to delete non-existent pool id " << m->pool << dendl; _pool_op_reply(m, 0, osdmap.get_epoch()); return true; } // check if the snap and snapname exists bool snap_exists = false; const pg_pool_t *p = osdmap.get_pg_pool(m->pool); if (p->snap_exists(m->name.c_str())) snap_exists = true; switch (m->op) { case POOL_OP_CREATE_SNAP: if (p->is_unmanaged_snaps_mode()) { _pool_op_reply(m, -EINVAL, osdmap.get_epoch()); return true; } if (snap_exists) { _pool_op_reply(m, 0, osdmap.get_epoch()); return true; } return false; case POOL_OP_CREATE_UNMANAGED_SNAP: if (p->is_pool_snaps_mode()) { _pool_op_reply(m, -EINVAL, osdmap.get_epoch()); return true; } return false; case POOL_OP_DELETE_SNAP: if (p->is_unmanaged_snaps_mode()) { _pool_op_reply(m, -EINVAL, osdmap.get_epoch()); return true; } if (!snap_exists) { _pool_op_reply(m, 0, osdmap.get_epoch()); return true; } return false; case POOL_OP_DELETE_UNMANAGED_SNAP: if (p->is_pool_snaps_mode()) { _pool_op_reply(m, -EINVAL, osdmap.get_epoch()); return true; } if (p->is_removed_snap(m->snapid)) { _pool_op_reply(m, 0, osdmap.get_epoch()); return true; } return false; case POOL_OP_DELETE: if (osdmap.lookup_pg_pool_name(m->name.c_str()) >= 0) { _pool_op_reply(m, 0, osdmap.get_epoch()); return true; } return false; case POOL_OP_AUID_CHANGE: return false; default: assert(0); break; } return false; } bool OSDMonitor::preprocess_pool_op_create(MPoolOp *m) { MonSession *session = m->get_session(); if (!session) { _pool_op_reply(m, -EPERM, osdmap.get_epoch()); return true; } if (!session->is_capable("osd", MON_CAP_W)) { dout(5) << "attempt to create new pool without sufficient auid privileges!" << "message: " << *m << std::endl << "caps: " << session->caps << dendl; _pool_op_reply(m, -EPERM, osdmap.get_epoch()); return true; } int64_t pool = osdmap.lookup_pg_pool_name(m->name.c_str()); if (pool >= 0) { _pool_op_reply(m, 0, osdmap.get_epoch()); return true; } return false; } bool OSDMonitor::prepare_pool_op(MPoolOp *m) { dout(10) << "prepare_pool_op " << *m << dendl; if (m->op == POOL_OP_CREATE) { return prepare_pool_op_create(m); } else if (m->op == POOL_OP_DELETE) { return prepare_pool_op_delete(m); } int ret = 0; bool changed = false; if (!osdmap.have_pg_pool(m->pool)) { _pool_op_reply(m, -ENOENT, osdmap.get_epoch()); return false; } const pg_pool_t *pool = osdmap.get_pg_pool(m->pool); switch (m->op) { case POOL_OP_CREATE_SNAP: case POOL_OP_DELETE_SNAP: if (!pool->is_unmanaged_snaps_mode()) { bool snap_exists = pool->snap_exists(m->name.c_str()); if ((m->op == POOL_OP_CREATE_SNAP && snap_exists) || (m->op == POOL_OP_DELETE_SNAP && !snap_exists)) { ret = 0; } else { break; } } else { ret = -EINVAL; } _pool_op_reply(m, ret, osdmap.get_epoch()); return false; case POOL_OP_DELETE_UNMANAGED_SNAP: // we won't allow removal of an unmanaged snapshot from a pool // not in unmanaged snaps mode. if (!pool->is_unmanaged_snaps_mode()) { _pool_op_reply(m, -ENOTSUP, osdmap.get_epoch()); return false; } /* fall-thru */ case POOL_OP_CREATE_UNMANAGED_SNAP: // but we will allow creating an unmanaged snapshot on any pool // as long as it is not in 'pool' snaps mode. if (pool->is_pool_snaps_mode()) { _pool_op_reply(m, -EINVAL, osdmap.get_epoch()); return false; } } // projected pool info pg_pool_t pp; if (pending_inc.new_pools.count(m->pool)) pp = pending_inc.new_pools[m->pool]; else pp = *osdmap.get_pg_pool(m->pool); bufferlist reply_data; // pool snaps vs unmanaged snaps are mutually exclusive switch (m->op) { case POOL_OP_CREATE_SNAP: case POOL_OP_DELETE_SNAP: if (pp.is_unmanaged_snaps_mode()) { ret = -EINVAL; goto out; } break; case POOL_OP_CREATE_UNMANAGED_SNAP: case POOL_OP_DELETE_UNMANAGED_SNAP: if (pp.is_pool_snaps_mode()) { ret = -EINVAL; goto out; } } switch (m->op) { case POOL_OP_CREATE_SNAP: if (!pp.snap_exists(m->name.c_str())) { pp.add_snap(m->name.c_str(), ceph_clock_now(g_ceph_context)); dout(10) << "create snap in pool " << m->pool << " " << m->name << " seq " << pp.get_snap_epoch() << dendl; changed = true; } break; case POOL_OP_DELETE_SNAP: { snapid_t s = pp.snap_exists(m->name.c_str()); if (s) { pp.remove_snap(s); changed = true; } } break; case POOL_OP_CREATE_UNMANAGED_SNAP: { uint64_t snapid; pp.add_unmanaged_snap(snapid); ::encode(snapid, reply_data); changed = true; } break; case POOL_OP_DELETE_UNMANAGED_SNAP: if (!pp.is_removed_snap(m->snapid)) { pp.remove_unmanaged_snap(m->snapid); changed = true; } break; case POOL_OP_AUID_CHANGE: if (pp.auid != m->auid) { pp.auid = m->auid; changed = true; } break; default: assert(0); break; } if (changed) { pp.set_snap_epoch(pending_inc.epoch); pending_inc.new_pools[m->pool] = pp; } out: wait_for_finished_proposal(new OSDMonitor::C_PoolOp(this, m, ret, pending_inc.epoch, &reply_data)); return true; } bool OSDMonitor::prepare_pool_op_create(MPoolOp *m) { int err = prepare_new_pool(m); wait_for_finished_proposal(new OSDMonitor::C_PoolOp(this, m, err, pending_inc.epoch)); return true; } int OSDMonitor::_check_remove_pool(int64_t pool, const pg_pool_t *p, ostream *ss) { string poolstr = osdmap.get_pool_name(pool); if (p->tier_of >= 0) { *ss << "pool '" << poolstr << "' is a tier of '" << osdmap.get_pool_name(p->tier_of) << "'"; return -EBUSY; } if (!p->tiers.empty()) { *ss << "pool '" << poolstr << "' has tiers"; for(std::set::iterator i = p->tiers.begin(); i != p->tiers.end(); ++i) { const char *name = osdmap.get_pool_name(*i); assert(name != NULL); *ss << " " << name; } return -EBUSY; } if (!g_conf->mon_allow_pool_delete) { *ss << "pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool"; return -EPERM; } *ss << "pool '" << poolstr << "' removed"; return 0; } int OSDMonitor::_prepare_remove_pool(int64_t pool, ostream *ss) { dout(10) << "_prepare_remove_pool " << pool << dendl; const pg_pool_t *p = osdmap.get_pg_pool(pool); int r = _check_remove_pool(pool, p, ss); if (r < 0) return r; if (pending_inc.new_pools.count(pool)) { // if there is a problem with the pending info, wait and retry // this op. pg_pool_t *p = &pending_inc.new_pools[pool]; int r = _check_remove_pool(pool, p, ss); if (r < 0) return -EAGAIN; } if (pending_inc.old_pools.count(pool)) { dout(10) << "_prepare_remove_pool " << pool << " already pending removal" << dendl; return 0; } // remove pending_inc.old_pools.insert(pool); // remove any pg_temp mappings for this pool too for (map >::iterator p = osdmap.pg_temp->begin(); p != osdmap.pg_temp->end(); ++p) { if (p->first.pool() == (uint64_t)pool) { dout(10) << "_prepare_remove_pool " << pool << " removing obsolete pg_temp " << p->first << dendl; pending_inc.new_pg_temp[p->first].clear(); } } for (map::iterator p = osdmap.primary_temp->begin(); p != osdmap.primary_temp->end(); ++p) { if (p->first.pool() == (uint64_t)pool) { dout(10) << "_prepare_remove_pool " << pool << " removing obsolete primary_temp" << p->first << dendl; pending_inc.new_primary_temp[p->first] = -1; } } return 0; } int OSDMonitor::_prepare_rename_pool(int64_t pool, string newname) { dout(10) << "_prepare_rename_pool " << pool << dendl; if (pending_inc.old_pools.count(pool)) { dout(10) << "_prepare_rename_pool " << pool << " pending removal" << dendl; return -ENOENT; } for (map::iterator p = pending_inc.new_pool_names.begin(); p != pending_inc.new_pool_names.end(); ++p) { if (p->second == newname && p->first != pool) { return -EEXIST; } } pending_inc.new_pool_names[pool] = newname; return 0; } bool OSDMonitor::prepare_pool_op_delete(MPoolOp *m) { ostringstream ss; int ret = _prepare_remove_pool(m->pool, &ss); if (ret == -EAGAIN) { wait_for_finished_proposal(new C_RetryMessage(this, m)); return true; } if (ret < 0) dout(10) << __func__ << " got " << ret << " " << ss.str() << dendl; wait_for_finished_proposal(new OSDMonitor::C_PoolOp(this, m, ret, pending_inc.epoch)); return true; } void OSDMonitor::_pool_op_reply(MPoolOp *m, int ret, epoch_t epoch, bufferlist *blp) { dout(20) << "_pool_op_reply " << ret << dendl; MPoolOpReply *reply = new MPoolOpReply(m->fsid, m->get_tid(), ret, epoch, get_last_committed(), blp); mon->send_reply(m, reply); m->put(); } ceph-0.80.11/src/mon/ConfigKeyService.cc0000664000175100017510000001203212623076744021761 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include "mon/Monitor.h" #include "mon/QuorumService.h" #include "mon/ConfigKeyService.h" #include "mon/MonitorDBStore.h" #include "common/config.h" #include "common/cmdparse.h" #include "common/errno.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, this) static ostream& _prefix(std::ostream *_dout, const Monitor *mon, const ConfigKeyService *service) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ")." << service->get_name() << "(" << service->get_epoch() << ") "; } const string ConfigKeyService::STORE_PREFIX = "mon_config_key"; int ConfigKeyService::store_get(string key, bufferlist &bl) { if (!store_exists(key)) return -ENOENT; return mon->store->get(STORE_PREFIX, key, bl); } void ConfigKeyService::store_put(string key, bufferlist &bl, Context *cb) { bufferlist proposal_bl; MonitorDBStore::Transaction t; t.put(STORE_PREFIX, key, bl); t.encode(proposal_bl); paxos->propose_new_value(proposal_bl, cb); } void ConfigKeyService::store_delete(string key, Context *cb) { bufferlist proposal_bl; MonitorDBStore::Transaction t; t.erase(STORE_PREFIX, key); t.encode(proposal_bl); paxos->propose_new_value(proposal_bl, cb); } bool ConfigKeyService::store_exists(string key) { return mon->store->exists(STORE_PREFIX, key); } void ConfigKeyService::store_list(stringstream &ss) { KeyValueDB::Iterator iter = mon->store->get_iterator(STORE_PREFIX); JSONFormatter f(true); f.open_array_section("keys"); while (iter->valid()) { string key(iter->key()); f.dump_string("key", key); iter->next(); } f.close_section(); f.flush(ss); } bool ConfigKeyService::service_dispatch(Message *m) { dout(10) << __func__ << " " << *m << dendl; if (!in_quorum()) { dout(1) << __func__ << " not in quorum -- ignore message" << dendl; m->put(); return false; } assert(m != NULL); assert(m->get_type() == MSG_MON_COMMAND); MMonCommand *cmd = static_cast(m); assert(!cmd->cmd.empty()); int ret = 0; stringstream ss; bufferlist rdata; string prefix; map cmdmap; if (!cmdmap_from_json(cmd->cmd, &cmdmap, ss)) { ret = -EINVAL; return false; } cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); string key; cmd_getval(g_ceph_context, cmdmap, "key", key); if (prefix == "config-key get") { ret = store_get(key, rdata); if (ret < 0) { assert(!rdata.length()); ss << "error obtaining '" << key << "': " << cpp_strerror(ret); goto out; } ss << "obtained '" << key << "'"; } else if (prefix == "config-key put") { if (!mon->is_leader()) { mon->forward_request_leader(cmd); // we forward the message; so return now. return true; } bufferlist data; string val; if (cmd_getval(g_ceph_context, cmdmap, "val", val)) { // they specified a value in the command instead of a file data.append(val); } else if (cmd->get_data_len() > 0) { // they specified '-i ' data = cmd->get_data(); } if (data.length() > (size_t) g_conf->mon_config_key_max_entry_size) { ret = -EFBIG; // File too large ss << "error: entry size limited to " << g_conf->mon_config_key_max_entry_size << " bytes. " << "Use 'mon config key max entry size' to manually adjust"; goto out; } // we'll reply to the message once the proposal has been handled store_put(key, data, new Monitor::C_Command(mon, cmd, 0, "value stored", 0)); // return for now; we'll put the message once it's done. return true; } else if (prefix == "config-key del") { if (!mon->is_leader()) { mon->forward_request_leader(cmd); return true; } if (!store_exists(key)) { ret = 0; ss << "no such key '" << key << "'"; goto out; } store_delete(key, new Monitor::C_Command(mon, cmd, 0, "key deleted", 0)); // return for now; we'll put the message once it's done return true; } else if (prefix == "config-key exists") { bool exists = store_exists(key); ss << "key '" << key << "'"; if (exists) { ss << " exists"; ret = 0; } else { ss << " doesn't exist"; ret = -ENOENT; } } else if (prefix == "config-key list") { stringstream tmp_ss; store_list(tmp_ss); rdata.append(tmp_ss); ret = 0; } out: if (!cmd->get_source().is_mon()) { string rs = ss.str(); mon->reply_command(cmd, ret, rs, rdata, 0); } else { cmd->put(); } return (ret == 0); } ceph-0.80.11/src/mon/DataHealthService.h0000664000175100017510000000421112623076744021744 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_DATA_HEALTH_SERVICE_H #define CEPH_MON_DATA_HEALTH_SERVICE_H #include #include "include/types.h" #include "include/Context.h" #include "mon/mon_types.h" #include "mon/QuorumService.h" #include "mon/HealthService.h" #include "common/Formatter.h" #include "common/config.h" #include "global/signal_handler.h" struct MMonHealth; class DataHealthService : public HealthService { map stats; int last_warned_percent; void handle_tell(MMonHealth *m); int update_store_stats(DataStats &ours); int update_stats(); void share_stats(); void force_shutdown() { generic_dout(0) << "** Shutdown via Data Health Service **" << dendl; queue_async_signal(SIGINT); } protected: virtual void service_tick(); virtual bool service_dispatch(Message *m) { assert(0 == "We should never reach this; only the function below"); return false; } virtual bool service_dispatch(MMonHealth *m); virtual void service_shutdown() { } virtual void start_epoch(); virtual void finish_epoch() { } virtual void cleanup() { } public: DataHealthService(Monitor *m) : HealthService(m), last_warned_percent(0) { set_update_period(g_conf->mon_health_data_update_interval); } virtual ~DataHealthService() { } virtual void init() { generic_dout(20) << "data_health " << __func__ << dendl; start_tick(); } virtual void get_health(Formatter *f, list >& summary, list > *detail); virtual int get_type() { return HealthService::SERVICE_HEALTH_DATA; } virtual string get_name() const { return "data_health"; } }; #endif /* CEPH_MON_DATA_HEALTH_SERVICE_H */ ceph-0.80.11/src/mon/PGMonitor.h0000664000175100017510000001321112623076744020302 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* * Placement Group Monitor. Placement Groups are logical sets of objects * that are replicated by the same set of devices. */ #ifndef CEPH_PGMONITOR_H #define CEPH_PGMONITOR_H #include #include using namespace std; #include "PGMap.h" #include "PaxosService.h" #include "include/types.h" #include "include/utime.h" #include "common/histogram.h" #include "msg/Messenger.h" #include "common/config.h" #include "mon/MonitorDBStore.h" #include "messages/MPGStats.h" #include "messages/MPGStatsAck.h" class MStatfs; class MMonCommand; class MGetPoolStats; class RatioMonitor; class TextTable; class PGMonitor : public PaxosService { public: PGMap pg_map; bool need_check_down_pgs; epoch_t last_map_pg_create_osd_epoch; private: PGMap::Incremental pending_inc; const char *pgmap_meta_prefix; const char *pgmap_pg_prefix; const char *pgmap_osd_prefix; void create_initial(); void update_from_paxos(bool *need_bootstrap); void upgrade_format(); void on_upgrade(); void post_paxos_update(); void handle_osd_timeouts(); void create_pending(); // prepare a new pending // propose pending update to peers version_t get_trim_to(); void update_logger(); void encode_pending(MonitorDBStore::Transaction *t); void read_pgmap_meta(); void read_pgmap_full(); void apply_pgmap_delta(bufferlist& bl); bool preprocess_query(PaxosServiceMessage *m); // true if processed. bool prepare_update(PaxosServiceMessage *m); bool preprocess_pg_stats(MPGStats *stats); bool pg_stats_have_changed(int from, const MPGStats *stats) const; bool prepare_pg_stats(MPGStats *stats); void _updated_stats(MPGStats *req, MPGStatsAck *ack); struct C_Stats : public Context { PGMonitor *pgmon; MPGStats *req; MPGStatsAck *ack; entity_inst_t who; C_Stats(PGMonitor *p, MPGStats *r, MPGStatsAck *a) : pgmon(p), req(r), ack(a) {} void finish(int r) { if (r >= 0) { pgmon->_updated_stats(req, ack); } else if (r == -ECANCELED) { req->put(); ack->put(); } else if (r == -EAGAIN) { pgmon->dispatch(req); ack->put(); } else { assert(0 == "bad C_Stats return value"); } } }; void handle_statfs(MStatfs *statfs); bool preprocess_getpoolstats(MGetPoolStats *m); bool preprocess_command(MMonCommand *m); bool prepare_command(MMonCommand *m); map last_sent_pg_create; // per osd throttle // when we last received PG stats from each osd map last_osd_report; void register_pg(pg_pool_t& pool, pg_t pgid, epoch_t epoch, bool new_pool); /** * check latest osdmap for new pgs to register * * @return true if we updated pending_inc (and should propose) */ bool register_new_pgs(); void map_pg_creates(); void send_pg_creates(); void send_pg_creates(int osd, Connection *con); /** * check pgs for down primary osds * * clears need_check_down_pgs * * @return true if we updated pending_inc (and should propose) */ bool check_down_pgs(); /** * Dump stats from pgs stuck in specified states. * * @return 0 on success, negative error code on failure */ int dump_stuck_pg_stats(stringstream &ds, Formatter *f, int threshold, vector& args) const; void dump_object_stat_sum(TextTable &tbl, Formatter *f, object_stat_sum_t &sum, uint64_t avail, bool verbose); int64_t get_rule_avail(OSDMap& osdmap, int ruleno); public: PGMonitor(Monitor *mn, Paxos *p, const string& service_name) : PaxosService(mn, p, service_name), need_check_down_pgs(false), last_map_pg_create_osd_epoch(0), pgmap_meta_prefix("pgmap_meta"), pgmap_pg_prefix("pgmap_pg"), pgmap_osd_prefix("pgmap_osd") { } ~PGMonitor() { } virtual void get_store_prefixes(set& s) { s.insert(get_service_name()); s.insert(pgmap_meta_prefix); s.insert(pgmap_pg_prefix); s.insert(pgmap_osd_prefix); } virtual void on_restart(); /* Courtesy function provided by PaxosService, called when an election * finishes and the cluster goes active. We use it here to make sure we * haven't lost any PGs from new pools. */ virtual void on_active(); bool should_stash_full() { return false; // never } virtual void encode_full(MonitorDBStore::Transaction *t) { assert(0 == "unimplemented encode_full"); } void tick(); // check state, take actions void check_osd_map(epoch_t epoch); void dump_pool_stats(stringstream &ss, Formatter *f, bool verbose); void dump_fs_stats(stringstream &ss, Formatter *f, bool verbose); void dump_info(Formatter *f); int _warn_slow_request_histogram(const pow2_hist_t& h, string suffix, list >& summary, list > *detail) const; void get_health(list >& summary, list > *detail) const; void check_full_osd_health(list >& summary, list > *detail, const set& s, const char *desc, health_status_t sev) const; void check_sub(Subscription *sub); private: // no copying allowed PGMonitor(const PGMonitor &rhs); PGMonitor &operator=(const PGMonitor &rhs); }; #endif ceph-0.80.11/src/mon/MonitorStore.h0000664000175100017510000000623312623076744021076 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_MONITORSTORE_H #define CEPH_MON_MONITORSTORE_H #include "include/types.h" #include "include/buffer.h" #include "common/compiler_extensions.h" #include #include #include class MonitorStore { string dir; int lock_fd; void write_bl_ss(bufferlist& bl, const char *a, const char *b, bool append); public: MonitorStore(const std::string &d) : dir(d), lock_fd(-1) { } ~MonitorStore() { } int mkfs(); // wipe int mount(); int umount(); void sync(); // ints (stored as ascii) version_t get_int(const char *a, const char *b=0) WARN_UNUSED_RESULT; void put_int(version_t v, const char *a, const char *b=0); version_t get_global_version(const char *a, version_t b) WARN_UNUSED_RESULT; // buffers // ss and sn varieties. bool exists_bl_ss(const char *a, const char *b=0); int get_bl_ss(bufferlist& bl, const char *a, const char *b) WARN_UNUSED_RESULT; void get_bl_ss_safe(bufferlist& bl, const char *a, const char *b) { int ret = get_bl_ss(bl, a, b); assert (ret >= 0 || ret == -ENOENT); } void put_bl_ss(bufferlist& bl, const char *a, const char *b) { write_bl_ss(bl, a, b, false); } void append_bl_ss(bufferlist& bl, const char *a, const char *b) { write_bl_ss(bl, a, b, true); } bool exists_bl_sn(const char *a, version_t b) { char bs[20]; snprintf(bs, sizeof(bs), "%llu", (unsigned long long)b); return exists_bl_ss(a, bs); } int get_bl_sn(bufferlist& bl, const char *a, version_t b) WARN_UNUSED_RESULT { char bs[20]; snprintf(bs, sizeof(bs), "%llu", (unsigned long long)b); return get_bl_ss(bl, a, bs); } void get_bl_sn_safe(bufferlist& bl, const char *a, version_t b) { int ret = get_bl_sn(bl, a, b); assert(ret >= 0 || ret == -ENOENT); } void put_bl_sn(bufferlist& bl, const char *a, version_t b) { char bs[20]; snprintf(bs, sizeof(bs), "%llu", (unsigned long long)b); put_bl_ss(bl, a, bs); } /** * Put a whole set of values efficiently and safely. * * @param a - prefix/directory * @param vals - map of int name -> values * @return 0 for success or negative error code */ void put_bl_sn_map(const char *a, map::iterator start, map::iterator end); void erase_ss(const char *a, const char *b); void erase_sn(const char *a, version_t b) { char bs[20]; snprintf(bs, sizeof(bs), "%llu", (unsigned long long)b); erase_ss(a, bs); } /* version_t get_incarnation() { return get_int("incarnation"); } void set_incarnation(version_t i) { set_int(i, "incarnation"); } version_t get_last_proposal() { return get_int("last_proposal"); } void set_last_proposal(version_t i) { set_int(i, "last_proposal"); } */ }; #endif ceph-0.80.11/src/mon/ConfigKeyService.h0000664000175100017510000000350212623076744021625 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_CONFIG_KEY_SERVICE_H #define CEPH_MON_CONFIG_KEY_SERVICE_H #include "mon/Monitor.h" #include "mon/QuorumService.h" #include "messages/MMonHealth.h" #include "common/config.h" #include "common/Formatter.h" class Paxos; class ConfigKeyService : public QuorumService { Paxos *paxos; int store_get(string key, bufferlist &bl); void store_put(string key, bufferlist &bl, Context *cb = NULL); void store_delete(string key, Context *cb = NULL); void store_list(stringstream &ss); bool store_exists(string key); static const string STORE_PREFIX; protected: virtual void service_shutdown() { } public: ConfigKeyService(Monitor *m, Paxos *p) : QuorumService(m), paxos(p) { } virtual ~ConfigKeyService() { } /** * @defgroup ConfigKeyService_Inherited_h Inherited abstract methods * @{ */ virtual void init() { } virtual void get_health(Formatter *f, list >& summary, list > *detail) { } virtual bool service_dispatch(Message *m); virtual void start_epoch() { } virtual void finish_epoch() { } virtual void cleanup() { } virtual void service_tick() { } virtual int get_type() { return QuorumService::SERVICE_CONFIG_KEY; } virtual string get_name() const { return "config_key"; } /** * @} // ConfigKeyService_Inherited_h */ }; #endif // CEPH_MON_CONFIG_KEY_SERVICE_H ceph-0.80.11/src/mon/PaxosService.h0000664000175100017510000006231712623076744021052 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_PAXOSSERVICE_H #define CEPH_PAXOSSERVICE_H #include "messages/PaxosServiceMessage.h" #include "include/Context.h" #include "include/stringify.h" #include #include "Paxos.h" #include "Monitor.h" #include "MonitorDBStore.h" class Monitor; class Paxos; /** * A Paxos Service is an abstraction that easily allows one to obtain an * association between a Monitor and a Paxos class, in order to implement any * service. */ class PaxosService { /** * @defgroup PaxosService_h_class Paxos Service * @{ */ public: /** * The Monitor to which this class is associated with */ Monitor *mon; /** * The Paxos instance to which this class is associated with */ Paxos *paxos; /** * Our name. This will be associated with the class implementing us, and will * be used mainly for store-related operations. */ string service_name; /** * If we are or have queued anything for proposal, this variable will be true * until our proposal has been finished. */ bool proposing; protected: /** * Services implementing us used to depend on the Paxos version, back when * each service would have a Paxos instance for itself. However, now we only * have a single Paxos instance, shared by all the services. Each service now * must keep its own version, if so they wish. This variable should be used * for that purpose. */ version_t service_version; private: /** * Event callback responsible for proposing our pending value once a timer * runs out and fires. */ Context *proposal_timer; /** * If the implementation class has anything pending to be proposed to Paxos, * then have_pending should be true; otherwise, false. */ bool have_pending; protected: /** * format of our state in leveldb, 0 for default */ version_t format_version; /** * @defgroup PaxosService_h_callbacks Callback classes * @{ */ /** * Retry dispatching a given service message * * This callback class is used when we had to wait for some condition to * become true while we were dispatching it. * * For instance, if the message's version isn't readable, according to Paxos, * then we must wait for it to become readable. So, we just queue an * instance of this class onto the Paxos::wait_for_readable function, and * we will retry the whole dispatch again once the callback is fired. */ class C_RetryMessage : public Context { PaxosService *svc; PaxosServiceMessage *m; public: C_RetryMessage(PaxosService *s, PaxosServiceMessage *m_) : svc(s), m(m_) {} void finish(int r) { if (r == -EAGAIN || r >= 0) svc->dispatch(m); else if (r == -ECANCELED) m->put(); else assert(0 == "bad C_RetryMessage return value"); } }; /** * Callback used to make sure we call the PaxosService::_active function * whenever a condition is fulfilled. * * This is used in multiple situations, from waiting for the Paxos to commit * our proposed value, to waiting for the Paxos to become active once an * election is finished. */ class C_Active : public Context { PaxosService *svc; public: C_Active(PaxosService *s) : svc(s) {} void finish(int r) { if (r >= 0) svc->_active(); } }; /** * Callback class used to propose the pending value once the proposal_timer * fires up. */ class C_Propose : public Context { PaxosService *ps; public: C_Propose(PaxosService *p) : ps(p) { } void finish(int r) { ps->proposal_timer = 0; if (r >= 0) ps->propose_pending(); else if (r == -ECANCELED || r == -EAGAIN) return; else assert(0 == "bad return value for C_Propose"); } }; /** * Callback class used to mark us as active once a proposal finishes going * through Paxos. * * We should wake people up *only* *after* we inform the service we * just went active. And we should wake people up only once we finish * going active. This is why we first go active, avoiding to wake up the * wrong people at the wrong time, such as waking up a C_RetryMessage * before waking up a C_Active, thus ending up without a pending value. */ class C_Committed : public Context { PaxosService *ps; public: C_Committed(PaxosService *p) : ps(p) { } void finish(int r) { ps->proposing = false; if (r >= 0) ps->_active(); else if (r == -ECANCELED || r == -EAGAIN) return; else assert(0 == "bad return value for C_Committed"); } }; /** * @} */ friend class C_Propose; public: /** * @param mn A Monitor instance * @param p A Paxos instance * @parem name Our service's name. */ PaxosService(Monitor *mn, Paxos *p, string name) : mon(mn), paxos(p), service_name(name), proposing(false), service_version(0), proposal_timer(0), have_pending(false), format_version(0), last_committed_name("last_committed"), first_committed_name("first_committed"), full_prefix_name("full"), full_latest_name("latest"), cached_first_committed(0), cached_last_committed(0) { } virtual ~PaxosService() {} /** * Get the service's name. * * @returns The service's name. */ string get_service_name() { return service_name; } /** * Get the store prefixes we utilize */ virtual void get_store_prefixes(set& s) { s.insert(service_name); } // i implement and you ignore /** * Informs this instance that it should consider itself restarted. * * This means that we will cancel our proposal_timer event, if any exists. */ void restart(); /** * Informs this instance that an election has finished. * * This means that we will invoke a PaxosService::discard_pending while * setting have_pending to false (basically, ignore our pending state) and * we will then make sure we obtain a new state. * * Our state shall be updated by PaxosService::_active if the Paxos is * active; otherwise, we will wait for it to become active by adding a * PaxosService::C_Active callback to it. */ void election_finished(); /** * Informs this instance that it is supposed to shutdown. * * Basically, it will instruct Paxos to cancel all events/callbacks and then * will cancel the proposal_timer event if any exists. */ void shutdown(); private: /** * Update our state by updating it from Paxos, and then creating a new * pending state if need be. * * @remarks We only create a pending state we our Monitor is the Leader. * * @pre Paxos is active * @post have_pending is true iif our Monitor is the Leader and Paxos is * active */ void _active(); /** * Scrub our versions after we convert the store from the old layout to * the new k/v store. */ void remove_legacy_versions(); public: /** * Propose a new value through Paxos. * * This function should be called by the classes implementing * PaxosService, in order to propose a new value through Paxos. * * @pre The implementation class implements the encode_pending function. * @pre have_pending is true * @pre Our monitor is the Leader * @pre Paxos is active * @post Cancel the proposal timer, if any * @post have_pending is false * @post propose pending value through Paxos * * @note This function depends on the implementation of encode_pending on * the class that is implementing PaxosService */ void propose_pending(); /** * Let others request us to propose. * * At the moment, this is just a wrapper to propose_pending() with an * extra check for is_writeable(), but it's a good practice to dissociate * requests for proposals from direct usage of propose_pending() for * future use -- we might want to perform additional checks or put a * request on hold, for instance. */ void request_proposal() { assert(is_writeable()); propose_pending(); } /** * Request service @p other to perform a proposal. * * We could simply use the function above, requesting @p other directly, * but we might eventually want to do something to the request -- say, * set a flag stating we're waiting on a cross-proposal to be finished. */ void request_proposal(PaxosService *other) { assert(other != NULL); assert(other->is_writeable()); other->request_proposal(); } /** * Dispatch a message by passing it to several different functions that are * either implemented directly by this service, or that should be implemented * by the class implementing this service. * * @param m A message * @returns 'true' on successful dispatch; 'false' otherwise. */ bool dispatch(PaxosServiceMessage *m); void refresh(bool *need_bootstrap); void post_refresh(); /** * @defgroup PaxosService_h_override_funcs Functions that should be * overridden. * * These functions should be overridden at will by the class implementing * this service. * @{ */ /** * Create the initial state for your system. * * In some of ours the state is actually set up elsewhere so this does * nothing. */ virtual void create_initial() = 0; /** * Query the Paxos system for the latest state and apply it if it's newer * than the current Monitor state. * * @returns 'true' on success; 'false' otherwise. */ virtual void update_from_paxos(bool *need_bootstrap) = 0; /** * Hook called after all services have refreshed their state from paxos * * This is useful for doing any update work that depends on other * service's having up-to-date state. */ virtual void post_paxos_update() {} /** * Init on startup * * This is called on mon startup, after all of the PaxosService instances' * update_from_paxos() methods have been called */ virtual void init() {} /** * Create the pending state. * * @invariant This function is only called on a Leader. * @remarks This created state is then modified by incoming messages. * @remarks Called at startup and after every Paxos ratification round. */ virtual void create_pending() = 0; /** * Encode the pending state into a bufferlist for ratification and * transmission as the next state. * * @invariant This function is only called on a Leader. * * @param t The transaction to hold all changes. */ virtual void encode_pending(MonitorDBStore::Transaction *t) = 0; /** * Discard the pending state * * @invariant This function is only called on a Leader. * * @remarks This function is NOT overridden in any of our code, but it is * called in PaxosService::election_finished if have_pending is * true. */ virtual void discard_pending() { } /** * Look at the query; if the query can be handled without changing state, * do so. * * @param m A query message * @returns 'true' if the query was handled (e.g., was a read that got * answered, was a state change that has no effect); 'false' * otherwise. */ virtual bool preprocess_query(PaxosServiceMessage *m) = 0; /** * Apply the message to the pending state. * * @invariant This function is only called on a Leader. * * @param m An update message * @returns 'true' if the update message was handled (e.g., a command that * went through); 'false' otherwise. */ virtual bool prepare_update(PaxosServiceMessage *m) = 0; /** * @} */ /** * Determine if the Paxos system should vote on pending, and if so how long * it should wait to vote. * * @param[out] delay The wait time, used so we can limit the update traffic * spamming. * @returns 'true' if the Paxos system should propose; 'false' otherwise. */ virtual bool should_propose(double &delay); /** * @defgroup PaxosService_h_courtesy Courtesy functions * * Courtesy functions, in case the class implementing this service has * anything it wants/needs to do at these times. * @{ */ /** * This is called when the Paxos state goes to active. * * On the peon, this is after each election. * On the leader, this is after each election, *and* after each completed * proposal. * * @note This function may get called twice in certain recovery cases. */ virtual void on_active() { } /** * This is called when we are shutting down */ virtual void on_shutdown() {} /** * this is called when activating on the leader * * it should conditionally upgrade the on-disk format by proposing a transaction */ virtual void upgrade_format() { } /** * this is called when we detect the store has just upgraded underneath us */ virtual void on_upgrade() {} /** * Called when the Paxos system enters a Leader election. * * @remarks It's a courtesy method, in case the class implementing this * service has anything it wants/needs to do at that time. */ virtual void on_restart() { } /** * @} */ /** * Tick. */ virtual void tick() {} /** * Get health information * * @param summary list of summary strings and associated severity * @param detail optional list of detailed problem reports; may be NULL */ virtual void get_health(list >& summary, list > *detail) const { } private: /** * @defgroup PaxosService_h_store_keys Set of keys that are usually used on * all the services implementing this * class, and, being almost the only keys * used, should be standardized to avoid * mistakes. * @{ */ const string last_committed_name; const string first_committed_name; const string full_prefix_name; const string full_latest_name; /** * @} */ /** * @defgroup PaxosService_h_version_cache Variables holding cached values * for the most used versions (first * and last committed); we only have * to read them when the store is * updated, so in-between updates we * may very well use cached versions * and avoid the overhead. * @{ */ version_t cached_first_committed; version_t cached_last_committed; /** * @} */ /** * Callback list to be used whenever we are running a proposal through * Paxos. These callbacks will be awaken whenever the said proposal * finishes. */ list waiting_for_finished_proposal; public: /** * Check if we are proposing a value through Paxos * * @returns true if we are proposing; false otherwise. */ bool is_proposing() { return proposing; } /** * Check if we are in the Paxos ACTIVE state. * * @note This function is a wrapper for Paxos::is_active * * @returns true if in state ACTIVE; false otherwise. */ bool is_active() { return !is_proposing() && (paxos->is_active() || paxos->is_updating()); } /** * Check if we are readable. * * This mirrors on the paxos check, except that we also verify that * * - the client hasn't seen the future relative to this PaxosService * - this service isn't proposing. * - we have committed our initial state (last_committed > 0) * * @param ver The version we want to check if is readable * @returns true if it is readable; false otherwise */ bool is_readable(version_t ver = 0) { if (ver > get_last_committed() || is_proposing() || !paxos->is_readable(0) || get_last_committed() == 0) return false; return true; } /** * Check if we are writeable. * * We consider to be writeable iff: * * - we are not proposing a new version; * - we are ready to be written to -- i.e., we have a pending value. * - paxos is (active or updating) * * @returns true if writeable; false otherwise */ bool is_writeable() { return !is_proposing() && is_write_ready() && (paxos->is_active() || paxos->is_updating()); } /** * Check if we are ready to be written to. This means we must have a * pending value and be active. * * @returns true if we are ready to be written to; false otherwise. */ bool is_write_ready() { return is_active() && have_pending; } /** * Wait for a proposal to finish. * * Add a callback to be awaken whenever our current proposal finishes being * proposed through Paxos. * * @param c The callback to be awaken once the proposal is finished. */ void wait_for_finished_proposal(Context *c) { waiting_for_finished_proposal.push_back(c); } /** * Wait for us to become active * * @param c The callback to be awaken once we become active. */ void wait_for_active(Context *c) { if (!is_proposing()) { paxos->wait_for_active(c); return; } wait_for_finished_proposal(c); } /** * Wait for us to become readable * * @param c The callback to be awaken once we become active. * @param ver The version we want to wait on. */ void wait_for_readable(Context *c, version_t ver = 0) { /* This is somewhat of a hack. We only do check if a version is readable on * PaxosService::dispatch(), but, nonetheless, we must make sure that if that * is why we are not readable, then we must wait on PaxosService and not on * Paxos; otherwise, we may assert on Paxos::wait_for_readable() if it * happens to be readable at that specific point in time. */ if (is_proposing() || ver > get_last_committed() || get_last_committed() == 0) wait_for_finished_proposal(c); else paxos->wait_for_readable(c); } /** * Wait for us to become writeable * * @param c The callback to be awaken once we become writeable. */ void wait_for_writeable(Context *c) { if (is_proposing()) wait_for_finished_proposal(c); else if (!is_write_ready()) wait_for_active(c); else paxos->wait_for_writeable(c); } /** * @defgroup PaxosService_h_Trim * @{ */ /** * trim service states if appropriate * * Called at same interval as tick() */ void maybe_trim(); /** * Auxiliary function to trim our state from version @from to version @to, * not including; i.e., the interval [from, to[ * * @param t The transaction to which we will add the trim operations. * @param from the lower limit of the interval to be trimmed * @param to the upper limit of the interval to be trimmed (not including) */ void trim(MonitorDBStore::Transaction *t, version_t from, version_t to); /** * encode service-specific extra bits into trim transaction * * @param tx transaction * @param first new first_committed value */ virtual void encode_trim_extra(MonitorDBStore::Transaction *tx, version_t first) {} /** * Get the version we should trim to. * * Should be overloaded by service if it wants to trim states. * * @returns the version we should trim to; if we return zero, it should be * assumed that there's no version to trim to. */ virtual version_t get_trim_to() { return 0; } /** * @} */ /** * @defgroup PaxosService_h_Stash_Full * @{ */ virtual bool should_stash_full(); /** * Encode a full version on @p t * * @note We force every service to implement this function, since we strongly * desire the encoding of full versions. * @note Services that do not trim their state, will be bound to only create * one full version. Full version stashing is determined/controled by * trimming: we stash a version each time a trim is bound to erase the * latest full version. * * @param t Transaction on which the full version shall be encoded. */ virtual void encode_full(MonitorDBStore::Transaction *t) = 0; /** * @} */ /** * Cancel events. * * @note This function is a wrapper for Paxos::cancel_events */ void cancel_events() { paxos->cancel_events(); } /** * @defgroup PaxosService_h_store_funcs Back storage interface functions * @{ */ /** * @defgroup PaxosService_h_store_modify Wrapper function interface to access * the back store for modification * purposes * @{ */ void put_first_committed(MonitorDBStore::Transaction *t, version_t ver) { t->put(get_service_name(), first_committed_name, ver); } /** * Set the last committed version to @p ver * * @param t A transaction to which we add this put operation * @param ver The last committed version number being put */ void put_last_committed(MonitorDBStore::Transaction *t, version_t ver) { t->put(get_service_name(), last_committed_name, ver); /* We only need to do this once, and that is when we are about to make our * first proposal. There are some services that rely on first_committed * being set -- and it should! -- so we need to guarantee that it is, * specially because the services itself do not do it themselves. They do * rely on it, but they expect us to deal with it, and so we shall. */ if (!get_first_committed()) put_first_committed(t, ver); } /** * Put the contents of @p bl into version @p ver * * @param t A transaction to which we will add this put operation * @param ver The version to which we will add the value * @param bl A bufferlist containing the version's value */ void put_version(MonitorDBStore::Transaction *t, version_t ver, bufferlist& bl) { t->put(get_service_name(), ver, bl); } /** * Put the contents of @p bl into a full version key for this service, that * will be created with @p ver in mind. * * @param t The transaction to which we will add this put operation * @param ver A version number * @param bl A bufferlist containing the version's value */ void put_version_full(MonitorDBStore::Transaction *t, version_t ver, bufferlist& bl) { string key = mon->store->combine_strings(full_prefix_name, ver); t->put(get_service_name(), key, bl); } /** * Put the version number in @p ver into the key pointing to the latest full * version of this service. * * @param t The transaction to which we will add this put operation * @param ver A version number */ void put_version_latest_full(MonitorDBStore::Transaction *t, version_t ver) { string key = mon->store->combine_strings(full_prefix_name, full_latest_name); t->put(get_service_name(), key, ver); } /** * Put the contents of @p bl into the key @p key. * * @param t A transaction to which we will add this put operation * @param key The key to which we will add the value * @param bl A bufferlist containing the value */ void put_value(MonitorDBStore::Transaction *t, const string& key, bufferlist& bl) { t->put(get_service_name(), key, bl); } /** * @} */ /** * @defgroup PaxosService_h_store_get Wrapper function interface to access * the back store for reading purposes * @{ */ /** * @defgroup PaxosService_h_version_cache Obtain cached versions for this * service. * @{ */ /** * Get the first committed version * * @returns Our first committed version (that is available) */ version_t get_first_committed() { return cached_first_committed; } /** * Get the last committed version * * @returns Our last committed version */ version_t get_last_committed() { return cached_last_committed; } /** * @} */ /** * Get the contents of a given version @p ver * * @param ver The version being obtained * @param bl The bufferlist to be populated * @return 0 on success; <0 otherwise */ virtual int get_version(version_t ver, bufferlist& bl) { return mon->store->get(get_service_name(), ver, bl); } /** * Get the contents of a given full version of this service. * * @param ver A version number * @param bl The bufferlist to be populated * @returns 0 on success; <0 otherwise */ virtual int get_version_full(version_t ver, bufferlist& bl) { string key = mon->store->combine_strings(full_prefix_name, ver); return mon->store->get(get_service_name(), key, bl); } /** * Get the latest full version number * * @returns A version number */ version_t get_version_latest_full() { string key = mon->store->combine_strings(full_prefix_name, full_latest_name); return mon->store->get(get_service_name(), key); } /** * Get a value from a given key. * * @param[in] key The key * @param[out] bl The bufferlist to be populated with the value */ int get_value(const string& key, bufferlist& bl) { return mon->store->get(get_service_name(), key, bl); } /** * Get an integer value from a given key. * * @param[in] key The key */ version_t get_value(const string& key) { return mon->store->get(get_service_name(), key); } /** * @} */ /** * @} */ }; #endif ceph-0.80.11/src/mon/AuthMonitor.h0000664000175100017510000001043112623076744020676 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_AUTHMONITOR_H #define CEPH_AUTHMONITOR_H #include #include using namespace std; #include "include/ceph_features.h" #include "include/types.h" #include "msg/Messenger.h" #include "mon/PaxosService.h" #include "mon/Monitor.h" #include "mon/MonitorDBStore.h" class MMonCommand; struct MAuth; class MAuthMon; struct MMonGlobalID; class KeyRing; #define MIN_GLOBAL_ID 0x1000 class AuthMonitor : public PaxosService { enum IncType { GLOBAL_ID, AUTH_DATA, }; public: struct Incremental { IncType inc_type; uint64_t max_global_id; uint32_t auth_type; bufferlist auth_data; Incremental() : inc_type(GLOBAL_ID), max_global_id(0), auth_type(0) {} void encode(bufferlist& bl, uint64_t features=-1) const { if ((features & CEPH_FEATURE_MONENC) == 0) { __u8 v = 1; ::encode(v, bl); __u32 _type = (__u32)inc_type; ::encode(_type, bl); if (_type == GLOBAL_ID) { ::encode(max_global_id, bl); } else { ::encode(auth_type, bl); ::encode(auth_data, bl); } return; } ENCODE_START(2, 2, bl); __u32 _type = (__u32)inc_type; ::encode(_type, bl); if (_type == GLOBAL_ID) { ::encode(max_global_id, bl); } else { ::encode(auth_type, bl); ::encode(auth_data, bl); } ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); __u32 _type; ::decode(_type, bl); inc_type = (IncType)_type; assert(inc_type >= GLOBAL_ID && inc_type <= AUTH_DATA); if (_type == GLOBAL_ID) { ::decode(max_global_id, bl); } else { ::decode(auth_type, bl); ::decode(auth_data, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_int("type", inc_type); f->dump_int("max_global_id", max_global_id); f->dump_int("auth_type", auth_type); f->dump_int("auth_data_len", auth_data.length()); } static void generate_test_instances(list& ls) { ls.push_back(new Incremental); ls.push_back(new Incremental); ls.back()->inc_type = GLOBAL_ID; ls.back()->max_global_id = 1234; ls.push_back(new Incremental); ls.back()->inc_type = AUTH_DATA; ls.back()->auth_type = 12; ls.back()->auth_data.append("foo"); } }; private: vector pending_auth; version_t last_rotating_ver; uint64_t max_global_id; uint64_t last_allocated_id; void upgrade_format(); void export_keyring(KeyRing& keyring); void import_keyring(KeyRing& keyring); void push_cephx_inc(KeyServerData::Incremental& auth_inc) { Incremental inc; inc.inc_type = AUTH_DATA; ::encode(auth_inc, inc.auth_data); inc.auth_type = CEPH_AUTH_CEPHX; pending_auth.push_back(inc); } void on_active(); bool should_propose(double& delay); void create_initial(); void update_from_paxos(bool *need_bootstrap); void create_pending(); // prepare a new pending bool prepare_global_id(MMonGlobalID *m); void increase_max_global_id(); uint64_t assign_global_id(MAuth *m, bool should_increase_max); // propose pending update to peers void encode_pending(MonitorDBStore::Transaction *t); virtual void encode_full(MonitorDBStore::Transaction *t); version_t get_trim_to(); bool preprocess_query(PaxosServiceMessage *m); // true if processed. bool prepare_update(PaxosServiceMessage *m); bool prep_auth(MAuth *m, bool paxos_writable); bool preprocess_command(MMonCommand *m); bool prepare_command(MMonCommand *m); bool check_rotate(); public: AuthMonitor(Monitor *mn, Paxos *p, const string& service_name) : PaxosService(mn, p, service_name), last_rotating_ver(0), max_global_id(0), last_allocated_id(0) {} void pre_auth(MAuth *m); void tick(); // check state, take actions void dump_info(Formatter *f); }; WRITE_CLASS_ENCODER_FEATURES(AuthMonitor::Incremental); #endif ceph-0.80.11/src/mon/MonMap.cc0000664000175100017510000002020512623076744017752 0ustar jenkins-buildjenkins-build #include "MonMap.h" #include #include #include #include #include "common/Formatter.h" #include "include/ceph_features.h" #include "include/addr_parsing.h" #include "common/ceph_argparse.h" #include "common/errno.h" #include "common/dout.h" using ceph::Formatter; void MonMap::encode(bufferlist& blist, uint64_t features) const { if ((features & CEPH_FEATURE_MONNAMES) == 0) { __u16 v = 1; ::encode(v, blist); ::encode_raw(fsid, blist); ::encode(epoch, blist); vector mon_inst(mon_addr.size()); for (unsigned n = 0; n < mon_addr.size(); n++) mon_inst[n] = get_inst(n); ::encode(mon_inst, blist); ::encode(last_changed, blist); ::encode(created, blist); return; } if ((features & CEPH_FEATURE_MONENC) == 0) { __u16 v = 2; ::encode(v, blist); ::encode_raw(fsid, blist); ::encode(epoch, blist); ::encode(mon_addr, blist); ::encode(last_changed, blist); ::encode(created, blist); } ENCODE_START(3, 3, blist); ::encode_raw(fsid, blist); ::encode(epoch, blist); ::encode(mon_addr, blist); ::encode(last_changed, blist); ::encode(created, blist); ENCODE_FINISH(blist); } void MonMap::decode(bufferlist::iterator &p) { DECODE_START_LEGACY_COMPAT_LEN_16(3, 3, 3, p); ::decode_raw(fsid, p); ::decode(epoch, p); if (struct_v == 1) { vector mon_inst; ::decode(mon_inst, p); for (unsigned i = 0; i < mon_inst.size(); i++) { char n[2]; n[0] = '0' + i; n[1] = 0; string name = n; mon_addr[name] = mon_inst[i].addr; } } else { ::decode(mon_addr, p); } ::decode(last_changed, p); ::decode(created, p); DECODE_FINISH(p); calc_ranks(); } void MonMap::generate_test_instances(list& o) { o.push_back(new MonMap); o.push_back(new MonMap); o.back()->epoch = 1; o.back()->last_changed = utime_t(123, 456); o.back()->created = utime_t(789, 101112); o.back()->add("one", entity_addr_t()); } // read from/write to a file int MonMap::write(const char *fn) { // encode bufferlist bl; encode(bl, CEPH_FEATURES_ALL); return bl.write_file(fn); } int MonMap::read(const char *fn) { // read bufferlist bl; std::string error; int r = bl.read_file(fn, &error); if (r < 0) return r; decode(bl); return 0; } void MonMap::print_summary(ostream& out) const { out << "e" << epoch << ": " << mon_addr.size() << " mons at " << mon_addr; } void MonMap::print(ostream& out) const { out << "epoch " << epoch << "\n"; out << "fsid " << fsid << "\n"; out << "last_changed " << last_changed << "\n"; out << "created " << created << "\n"; unsigned i = 0; for (map::const_iterator p = addr_name.begin(); p != addr_name.end(); ++p) out << i++ << ": " << p->first << " mon." << p->second << "\n"; } void MonMap::dump(Formatter *f) const { f->dump_int("epoch", epoch); f->dump_stream("fsid") << fsid; f->dump_stream("modified") << last_changed; f->dump_stream("created") << created; f->open_array_section("mons"); int i = 0; for (map::const_iterator p = addr_name.begin(); p != addr_name.end(); ++p, ++i) { f->open_object_section("mon"); f->dump_int("rank", i); f->dump_string("name", p->second); f->dump_stream("addr") << p->first; f->close_section(); } f->close_section(); } int MonMap::build_from_host_list(std::string hostlist, std::string prefix) { vector addrs; if (parse_ip_port_vec(hostlist.c_str(), addrs)) { for (unsigned i=0; i& initial_members, string my_name, const entity_addr_t& my_addr, set *removed) { // remove non-initial members unsigned i = 0; while (i < size()) { string n = get_name(i); if (std::find(initial_members.begin(), initial_members.end(), n) != initial_members.end()) { lgeneric_dout(cct, 1) << " keeping " << n << " " << get_addr(i) << dendl; i++; continue; } lgeneric_dout(cct, 1) << " removing " << get_name(i) << " " << get_addr(i) << dendl; if (removed) removed->insert(get_addr(i)); remove(n); assert(!contains(n)); } // add missing initial members for (list::iterator p = initial_members.begin(); p != initial_members.end(); ++p) { if (!contains(*p)) { if (*p == my_name) { lgeneric_dout(cct, 1) << " adding self " << *p << " " << my_addr << dendl; add(*p, my_addr); } else { entity_addr_t a; a.set_family(AF_INET); for (int n=1; ; n++) { a.set_nonce(n); if (!contains(a)) break; } lgeneric_dout(cct, 1) << " adding " << *p << " " << a << dendl; add(*p, a); } assert(contains(*p)); } } } int MonMap::build_initial(CephContext *cct, ostream& errout) { const md_config_t *conf = cct->_conf; // file? if (!conf->monmap.empty()) { int r; try { r = read(conf->monmap.c_str()); } catch (const buffer::error &e) { r = -EINVAL; } if (r >= 0) return 0; errout << "unable to read/decode monmap from " << conf->monmap << ": " << cpp_strerror(-r) << std::endl; return r; } // fsid from conf? if (!cct->_conf->fsid.is_zero()) { fsid = cct->_conf->fsid; } // -m foo? if (!conf->mon_host.empty()) { int r = build_from_host_list(conf->mon_host, "noname-"); if (r < 0) { errout << "unable to parse addrs in '" << conf->mon_host << "'" << std::endl; return r; } return 0; } // What monitors are in the config file? std::vector sections; int ret = conf->get_all_sections(sections); if (ret) { errout << "Unable to find any monitors in the configuration " << "file, because there was an error listing the sections. error " << ret << std::endl; return -ENOENT; } std::vector mon_names; for (std::vector ::const_iterator s = sections.begin(); s != sections.end(); ++s) { if ((s->substr(0, 4) == "mon.") && (s->size() > 4)) { mon_names.push_back(s->substr(4)); } } // Find an address for each monitor in the config file. for (std::vector ::const_iterator m = mon_names.begin(); m != mon_names.end(); ++m) { std::vector sections; std::string m_name("mon"); m_name += "."; m_name += *m; sections.push_back(m_name); sections.push_back("mon"); sections.push_back("global"); std::string val; int res = conf->get_val_from_conf_file(sections, "mon addr", val, true); if (res) { errout << "failed to get an address for mon." << *m << ": error " << res << std::endl; continue; } entity_addr_t addr; if (!addr.parse(val.c_str())) { errout << "unable to parse address for mon." << *m << ": addr='" << val << "'" << std::endl; continue; } if (addr.get_port() == 0) addr.set_port(CEPH_MON_PORT); // the make sure this mon isn't already in the map if (contains(addr)) remove(get_name(addr)); if (contains(*m)) remove(*m); add(m->c_str(), addr); } if (size() == 0) { errout << "no monitors specified to connect to." << std::endl; return -ENOENT; } return 0; } ceph-0.80.11/src/mon/MonCommands.h0000664000175100017510000007102412623076744020645 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* no guard; may be included multiple times */ /* * Define commands that are reported by the monitor's * "get_command_descriptions" command, and parsed by the Python * frontend 'ceph' (and perhaps by other frontends, such as a RESTful * server). The format is: * * COMMAND(signature, helpstring, modulename, req perms, availability) * where: * signature: describes the command and its parameters (more below) * helpstring: displays in CLI help, API help (nice if it refers to * parameter names from signature, 40-a few hundred chars) * modulename: the monitor module or daemon this applies to: * mds, osd, pg (osd), mon, auth, log, config-key * req perms: required permission in that modulename space to execute command * this also controls what type of REST command is accepted * availability: cli, rest, or both * * The commands describe themselves completely enough for the separate * frontend(s) to be able to accept user input and validate it against * the command descriptions, and generate a JSON object that contains * key:value mappings of parameter names to validated parameter values. * * 'signature' is a space-separated list of individual command descriptors; * each descriptor is either a literal string, which can contain no spaces or * '=' signs (for instance, in "pg stat", both "pg" and "stat" are literal * strings representing one descriptor each), or a list of key=val[,key=val...] * which also includes no spaces. * * The key=val form describes a non-literal parameter. Each will have at * least a name= and type=, and each type can have its own type-specific * parameters. The parser is the arbiter of these types and their * interpretation. A few more non-type-specific key=val pairs exist: * * req=false marks an optional parameter (default for req is 'true') * n= is a repeat count for how many of this argument must be supplied. * n=1 is the default. * n=N is a special case that means "1 or more". * * A perhaps-incomplete list of types: * * CephInt: Optional: range=min[|max] * CephFloat: Optional range * CephString: optional badchars * CephSocketpath: validation involves "is it S_ISSOCK" * CephIPAddr: v4 or v6 addr with optional port, syntax validated * CephEntityAddr: CephIPAddr + optional '/nonce' * CephPoolname: Plainold string * CephObjectname: Another plainold string * CephPgid: n.xxx where n is an int > 0, xxx is a hex number > 0 * CephName: daemon name, '*' or '.' (id must be int for type osd) * CephOsdName: osd name, '*' or ' or 'osd.' (id must be int) * CephChoices: strings="foo|bar" means this param can be either * CephFilepath: openable file * CephFragment: cephfs 'fragID': val/bits, val in hex 0xnnn, bits in dec * CephUUID: uuid in text matching Python uuid.UUID() * CephPrefix: special type assigned to literals * * Example: * * COMMAND("auth add " \ * "name=entity,type=CephString " \ * "name=caps,type=CephString,n=N,req=false", \ * "add auth info for from input file, or random key " \ * "if no input given, and/or any caps specified in the command") * * defines a command "auth add" that takes a required argument "entity" * of type "CephString", and from 1 to N arguments named "caps" of type * CephString, at least one of which is required. The front end will * validate user input against this description. Let's say the user * enters auth add client.admin 'mon rwx' 'osd *'. The result will be a * JSON object like {"prefix":"auth add", "entity":"client.admin", * "caps":["mon rwx", "osd *"]}. * Note that * - string literals are accumulated into 'prefix' * - n=1 descriptors are given normal string or int object values * - n=N descriptors are given array values * * NOTE: be careful with spaces. Each descriptor must be separated by * one space, no other characters, so if you split lines as above, be * sure to close and reopen the quotes, and be careful to include the ' * separating spaces in the quoted string. * * The monitor marshals this JSON into a std::map * where cmd_vartype is a boost::variant type-enforcing discriminated * type, so the monitor is expected to know the type of each argument. * See cmdparse.cc/h for more details. */ /* * pg commands PgMonitor.cc */ COMMAND("pg stat", "show placement group status.", "pg", "r", "cli,rest") COMMAND("pg getmap", "get binary pg map to -o/stdout", "pg", "r", "cli,rest") COMMAND("pg send_pg_creates", "trigger pg creates to be issued",\ "pg", "rw", "cli,rest") COMMAND("pg dump " \ "name=dumpcontents,type=CephChoices,strings=all|summary|sum|delta|pools|osds|pgs|pgs_brief,n=N,req=false", \ "show human-readable versions of pg map (only 'all' valid with plain)", "pg", "r", "cli,rest") COMMAND("pg dump_json " \ "name=dumpcontents,type=CephChoices,strings=all|summary|sum|pools|osds|pgs,n=N,req=false", \ "show human-readable version of pg map in json only",\ "pg", "r", "cli,rest") COMMAND("pg dump_pools_json", "show pg pools info in json only",\ "pg", "r", "cli,rest") COMMAND("pg dump_stuck " \ "name=stuckops,type=CephChoices,strings=inactive|unclean|stale,n=N,req=false " \ "name=threshold,type=CephInt,req=false", "show information about stuck pgs",\ "pg", "r", "cli,rest") COMMAND("pg map name=pgid,type=CephPgid", "show mapping of pg to osds", \ "pg", "r", "cli,rest") COMMAND("pg scrub name=pgid,type=CephPgid", "start scrub on ", \ "pg", "rw", "cli,rest") COMMAND("pg deep-scrub name=pgid,type=CephPgid", "start deep-scrub on ", \ "pg", "rw", "cli,rest") COMMAND("pg repair name=pgid,type=CephPgid", "start repair on ", \ "pg", "rw", "cli,rest") COMMAND("pg debug " \ "name=debugop,type=CephChoices,strings=unfound_objects_exist|degraded_pgs_exist", \ "show debug info about pgs", "pg", "r", "cli,rest") COMMAND("pg force_create_pg name=pgid,type=CephPgid", \ "force creation of pg ", "pg", "rw", "cli,rest") COMMAND("pg set_full_ratio name=ratio,type=CephFloat,range=0.0|1.0", \ "set ratio at which pgs are considered full", "pg", "rw", "cli,rest") COMMAND("pg set_nearfull_ratio name=ratio,type=CephFloat,range=0.0|1.0", \ "set ratio at which pgs are considered nearly full", \ "pg", "rw", "cli,rest") /* * auth commands AuthMonitor.cc */ COMMAND("auth export name=entity,type=CephString,req=false", \ "write keyring for requested entity, or master keyring if none given", \ "auth", "rx", "cli,rest") COMMAND("auth get name=entity,type=CephString", \ "write keyring file with requested key", "auth", "rx", "cli,rest") COMMAND("auth get-key name=entity,type=CephString", "display requested key", \ "auth", "rx", "cli,rest") COMMAND("auth print-key name=entity,type=CephString", "display requested key", \ "auth", "rx", "cli,rest") COMMAND("auth print_key name=entity,type=CephString", "display requested key", \ "auth", "rx", "cli,rest") COMMAND("auth list", "list authentication state", "auth", "rx", "cli,rest") COMMAND("auth import", "auth import: read keyring file from -i ", \ "auth", "rwx", "cli,rest") COMMAND("auth add " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N,req=false", \ "add auth info for from input file, or random key if no input given, and/or any caps specified in the command", "auth", "rwx", "cli,rest") COMMAND("auth get-or-create-key " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N,req=false", \ "get, or add, key for from system/caps pairs specified in the command. If key already exists, any given caps must match the existing caps for that key.", \ "auth", "rwx", "cli,rest") COMMAND("auth get-or-create " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N,req=false", \ "add auth info for from input file, or random key if no input given, and/or any caps specified in the command", \ "auth", "rwx", "cli,rest") COMMAND("auth caps " \ "name=entity,type=CephString " \ "name=caps,type=CephString,n=N", \ "update caps for from caps specified in the command", \ "auth", "rwx", "cli,rest") COMMAND("auth del " \ "name=entity,type=CephString", \ "delete all caps for ", \ "auth", "rwx", "cli,rest") /* * Monitor commands (Monitor.cc) */ COMMAND("compact", "cause compaction of monitor's leveldb storage", \ "mon", "rw", "cli,rest") COMMAND("scrub", "scrub the monitor stores", "mon", "rw", "cli,rest") COMMAND("fsid", "show cluster FSID/UUID", "mon", "r", "cli,rest") COMMAND("log name=logtext,type=CephString,n=N", \ "log supplied text to the monitor log", "mon", "rw", "cli,rest") COMMAND("injectargs " \ "name=injected_args,type=CephString,n=N", \ "inject config arguments into monitor", "mon", "rw", "cli,rest") COMMAND("status", "show cluster status", "mon", "r", "cli,rest") COMMAND("health name=detail,type=CephChoices,strings=detail,req=false", \ "show cluster health", "mon", "r", "cli,rest") COMMAND("df name=detail,type=CephChoices,strings=detail,req=false", \ "show cluster free space stats", "mon", "r", "cli,rest") COMMAND("report name=tags,type=CephString,n=N,req=false", \ "report full status of cluster, optional title tag strings", \ "mon", "r", "cli,rest") COMMAND("quorum_status", "report status of monitor quorum", \ "mon", "r", "cli,rest") COMMAND("mon_status", "report status of monitors", "mon", "r", "cli,rest") COMMAND("sync force " \ "name=validate1,type=CephChoices,strings=--yes-i-really-mean-it,req=false " \ "name=validate2,type=CephChoices,strings=--i-know-what-i-am-doing,req=false", \ "force sync of and clear monitor store", "mon", "rw", "cli,rest") COMMAND("heap " \ "name=heapcmd,type=CephChoices,strings=dump|start_profiler|stop_profiler|release|stats", \ "show heap usage info (available only if compiled with tcmalloc)", \ "mon", "rw", "cli,rest") COMMAND("quorum name=quorumcmd,type=CephChoices,strings=enter|exit,n=1", \ "enter or exit quorum", "mon", "rw", "cli,rest") COMMAND("tell " \ "name=target,type=CephName " \ "name=args,type=CephString,n=N", \ "send a command to a specific daemon", "mon", "rw", "cli,rest") /* * MDS commands (MDSMonitor.cc) */ COMMAND("mds stat", "show MDS status", "mds", "r", "cli,rest") COMMAND("mds dump " "name=epoch,type=CephInt,req=false,range=0", \ "dump info, optionally from epoch", "mds", "r", "cli,rest") COMMAND("mds getmap " \ "name=epoch,type=CephInt,req=false,range=0", \ "get MDS map, optionally from epoch", "mds", "r", "cli,rest") COMMAND("mds tell " \ "name=who,type=CephString " \ "name=args,type=CephString,n=N", \ "send command to particular mds", "mds", "rw", "cli,rest") COMMAND("mds compat show", "show mds compatibility settings", \ "mds", "r", "cli,rest") COMMAND("mds stop name=who,type=CephString", "stop mds", \ "mds", "rw", "cli,rest") COMMAND("mds deactivate name=who,type=CephString", "stop mds", \ "mds", "rw", "cli,rest") COMMAND("mds set_max_mds " \ "name=maxmds,type=CephInt,range=0", \ "set max MDS index", "mds", "rw", "cli,rest") COMMAND("mds set " \ "name=var,type=CephChoices,strings=max_mds|max_file_size|allow_new_snaps|inline_data " \ "name=val,type=CephString " \ "name=confirm,type=CephString,req=false", \ "set mds parameter to ", "mds", "rw", "cli,rest") COMMAND("mds setmap " \ "name=epoch,type=CephInt,range=0", \ "set mds map; must supply correct epoch number", "mds", "rw", "cli,rest") // arbitrary limit 0-20 below; worth standing on head to make it // relate to actual state definitions? // #include "include/ceph_fs.h" COMMAND("mds set_state " \ "name=gid,type=CephInt,range=0 " \ "name=state,type=CephInt,range=0|20", \ "set mds state of to ", "mds", "rw", "cli,rest") COMMAND("mds fail name=who,type=CephString", \ "force mds to status failed", "mds", "rw", "cli,rest") COMMAND("mds rm " \ "name=gid,type=CephInt,range=0 " \ "name=who,type=CephName", \ "remove nonactive mds", "mds", "rw", "cli,rest") COMMAND("mds rmfailed name=who,type=CephInt,range=0", "remove failed mds", \ "mds", "rw", "cli,rest") COMMAND("mds cluster_down", "take MDS cluster down", "mds", "rw", "cli,rest") COMMAND("mds cluster_up", "bring MDS cluster up", "mds", "rw", "cli,rest") COMMAND("mds compat rm_compat " \ "name=feature,type=CephInt,range=0", \ "remove compatible feature", "mds", "rw", "cli,rest") COMMAND("mds compat rm_incompat " \ "name=feature,type=CephInt,range=0", \ "remove incompatible feature", "mds", "rw", "cli,rest") COMMAND("mds add_data_pool " \ "name=pool,type=CephString", \ "add data pool ", "mds", "rw", "cli,rest") COMMAND("mds remove_data_pool " \ "name=pool,type=CephString", \ "remove data pool ", "mds", "rw", "cli,rest") COMMAND("mds newfs " \ "name=metadata,type=CephInt,range=0 " \ "name=data,type=CephInt,range=0 " \ "name=sure,type=CephChoices,strings=--yes-i-really-mean-it,req=false", \ "make new filesystom using pools and ", \ "mds", "rw", "cli,rest") /* * Monmap commands */ COMMAND("mon dump " \ "name=epoch,type=CephInt,range=0,req=false", \ "dump formatted monmap (optionally from epoch)", \ "mon", "r", "cli,rest") COMMAND("mon stat", "summarize monitor status", "mon", "r", "cli,rest") COMMAND("mon getmap " \ "name=epoch,type=CephInt,range=0,req=false", \ "get monmap", "mon", "r", "cli,rest") COMMAND("mon add " \ "name=name,type=CephString " \ "name=addr,type=CephIPAddr", \ "add new monitor named at ", "mon", "rw", "cli,rest") COMMAND("mon remove " \ "name=name,type=CephString", \ "remove monitor named ", "mon", "rw", "cli,rest") /* * OSD commands */ COMMAND("osd stat", "print summary of OSD map", "osd", "r", "cli,rest") COMMAND("osd dump " \ "name=epoch,type=CephInt,range=0,req=false", "print summary of OSD map", "osd", "r", "cli,rest") COMMAND("osd tree " \ "name=epoch,type=CephInt,range=0,req=false", \ "print OSD tree", "osd", "r", "cli,rest") COMMAND("osd ls " \ "name=epoch,type=CephInt,range=0,req=false", \ "show all OSD ids", "osd", "r", "cli,rest") COMMAND("osd getmap " \ "name=epoch,type=CephInt,range=0,req=false", \ "get OSD map", "osd", "r", "cli,rest") COMMAND("osd getcrushmap " \ "name=epoch,type=CephInt,range=0,req=false", \ "get CRUSH map", "osd", "r", "cli,rest") COMMAND("osd perf", \ "print dump of OSD perf summary stats", \ "osd", \ "r", \ "cli,rest") COMMAND("osd getmaxosd", "show largest OSD id", "osd", "r", "cli,rest") COMMAND("osd find " \ "name=id,type=CephInt,range=0", \ "find osd in the CRUSH map and show its location", \ "osd", "r", "cli,rest") COMMAND("osd metadata " \ "name=id,type=CephInt,range=0", \ "fetch metadata for osd ", \ "osd", "r", "cli,rest") COMMAND("osd map " \ "name=pool,type=CephPoolname " \ "name=object,type=CephObjectname", \ "find pg for in ", "osd", "r", "cli,rest") COMMAND("osd scrub " \ "name=who,type=CephString", \ "initiate scrub on osd ", "osd", "rw", "cli,rest") COMMAND("osd deep-scrub " \ "name=who,type=CephString", \ "initiate deep scrub on osd ", "osd", "rw", "cli,rest") COMMAND("osd repair " \ "name=who,type=CephString", \ "initiate repair on osd ", "osd", "rw", "cli,rest") COMMAND("osd lspools " \ "name=auid,type=CephInt,req=false", \ "list pools", "osd", "r", "cli,rest") COMMAND("osd blacklist ls", "show blacklisted clients", "osd", "r", "cli,rest") COMMAND("osd crush rule list", "list crush rules", "osd", "r", "cli,rest") COMMAND("osd crush rule ls", "list crush rules", "osd", "r", "cli,rest") COMMAND("osd crush rule dump " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.],req=false", \ "dump crush rule (default all)", \ "osd", "r", "cli,rest") COMMAND("osd crush dump", \ "dump crush map", \ "osd", "r", "cli,rest") COMMAND("osd setcrushmap", "set crush map from input file", \ "osd", "rw", "cli,rest") COMMAND("osd crush set", "set crush map from input file", \ "osd", "rw", "cli,rest") COMMAND("osd crush add-bucket " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=type,type=CephString", \ "add no-parent (probably root) crush bucket of type ", \ "osd", "rw", "cli,rest") COMMAND("osd crush set " \ "name=id,type=CephOsdName " \ "name=weight,type=CephFloat,range=0.0 " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "update crushmap position and weight for to with location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush add " \ "name=id,type=CephOsdName " \ "name=weight,type=CephFloat,range=0.0 " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "add or update crushmap position and weight for with and location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush create-or-move " \ "name=id,type=CephOsdName " \ "name=weight,type=CephFloat,range=0.0 " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "create entry or move existing entry for at/to location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush move " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "move existing entry for to location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush link " \ "name=name,type=CephString " \ "name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]", \ "link existing entry for under location ", \ "osd", "rw", "cli,rest") COMMAND("osd crush rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \ "remove from crush map (everywhere, or just at )",\ "osd", "rw", "cli,rest") COMMAND("osd crush remove " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \ "remove from crush map (everywhere, or just at )", \ "osd", "rw", "cli,rest") COMMAND("osd crush unlink " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=ancestor,type=CephString,req=false,goodchars=[A-Za-z0-9-_.]", \ "unlink from crush map (everywhere, or just at )", \ "osd", "rw", "cli,rest") COMMAND("osd crush reweight-all", "recalculate the weights for the tree to ensure they sum correctly", "osd", "rw", "cli,rest") COMMAND("osd crush reweight " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=weight,type=CephFloat,range=0.0", \ "change 's weight to in crush map", \ "osd", "rw", "cli,rest") COMMAND("osd crush tunables " \ "name=profile,type=CephChoices,strings=legacy|argonaut|bobtail|firefly|optimal|default", \ "set crush tunables values to ", "osd", "rw", "cli,rest") COMMAND("osd crush set-tunable " \ "name=tunable,type=CephChoices,strings=straw_calc_version " \ "name=value,type=CephInt", "set crush tunable to ", "osd", "rw", "cli,rest") COMMAND("osd crush get-tunable " \ "name=tunable,type=CephChoices,strings=straw_calc_version", "get crush tunable ", "osd", "rw", "cli,rest") COMMAND("osd crush show-tunables", \ "show current crush tunables", "osd", "r", "cli,rest") COMMAND("osd crush rule create-simple " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=root,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=type,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=mode,type=CephChoices,strings=firstn|indep,req=false", "create crush rule to start from , replicate across buckets of type , using a choose mode of (default firstn; indep best for erasure pools)", \ "osd", "rw", "cli,rest") COMMAND("osd crush rule create-erasure " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=profile,type=CephString,req=false,goodchars=[A-Za-z0-9-_.=]", \ "create crush rule for erasure coded pool created with (default default)", \ "osd", "rw", "cli,rest") COMMAND("osd crush rule rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] ", \ "remove crush rule ", "osd", "rw", "cli,rest") COMMAND("osd setmaxosd " \ "name=newmax,type=CephInt,range=0", \ "set new maximum osd value", "osd", "rw", "cli,rest") COMMAND("osd pause", "pause osd", "osd", "rw", "cli,rest") COMMAND("osd unpause", "unpause osd", "osd", "rw", "cli,rest") COMMAND("osd erasure-code-profile set " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ "name=profile,type=CephString,n=N,req=false,goodchars=[A-Za-z0-9-_.=]", \ "create erasure code profile with [ ...] pairs. Add a --force at the end to override an existing profile (VERY DANGEROUS)", \ "osd", "rw", "cli,rest") COMMAND("osd erasure-code-profile get " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.]", \ "get erasure code profile ", \ "osd", "r", "cli,rest") COMMAND("osd erasure-code-profile rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.]", \ "remove erasure code profile ", \ "osd", "rw", "cli,rest") COMMAND("osd erasure-code-profile ls", \ "list all erasure code profiles", \ "osd", "r", "cli,rest") COMMAND("osd set " \ "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub|notieragent", \ "set ", "osd", "rw", "cli,rest") COMMAND("osd unset " \ "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub|notieragent", \ "unset ", "osd", "rw", "cli,rest") COMMAND("osd cluster_snap", "take cluster snapshot (disabled)", \ "osd", "r", "") COMMAND("osd down " \ "type=CephString,name=ids,n=N", \ "set osd(s) [...] down", "osd", "rw", "cli,rest") COMMAND("osd out " \ "name=ids,type=CephString,n=N", \ "set osd(s) [...] out", "osd", "rw", "cli,rest") COMMAND("osd in " \ "name=ids,type=CephString,n=N", \ "set osd(s) [...] in", "osd", "rw", "cli,rest") COMMAND("osd rm " \ "name=ids,type=CephString,n=N", \ "remove osd(s) [...] in", "osd", "rw", "cli,rest") COMMAND("osd reweight " \ "name=id,type=CephInt,range=0 " \ "type=CephFloat,name=weight,range=0.0|1.0", \ "reweight osd to 0.0 < < 1.0", "osd", "rw", "cli,rest") COMMAND("osd pg-temp " \ "name=pgid,type=CephPgid " \ "name=id,type=CephString,n=N,req=false", \ "set pg_temp mapping pgid:[ [...]] (developers only)", \ "osd", "rw", "cli,rest") COMMAND("osd primary-temp " \ "name=pgid,type=CephPgid " \ "name=id,type=CephString", \ "set primary_temp mapping pgid:|-1 (developers only)", \ "osd", "rw", "cli,rest") COMMAND("osd primary-affinity " \ "name=id,type=CephOsdName " \ "type=CephFloat,name=weight,range=0.0|1.0", \ "adjust osd primary-affinity from 0.0 <= <= 1.0", \ "osd", "rw", "cli,rest") COMMAND("osd lost " \ "name=id,type=CephInt,range=0 " \ "name=sure,type=CephChoices,strings=--yes-i-really-mean-it,req=false", \ "mark osd as permanently lost. THIS DESTROYS DATA IF NO MORE REPLICAS EXIST, BE CAREFUL", \ "osd", "rw", "cli,rest") COMMAND("osd create " \ "name=uuid,type=CephUUID,req=false", \ "create new osd (with optional UUID)", "osd", "rw", "cli,rest") COMMAND("osd blacklist " \ "name=blacklistop,type=CephChoices,strings=add|rm " \ "name=addr,type=CephEntityAddr " \ "name=expire,type=CephFloat,range=0.0,req=false", \ "add (optionally until seconds from now) or remove from blacklist", \ "osd", "rw", "cli,rest") COMMAND("osd pool mksnap " \ "name=pool,type=CephPoolname " \ "name=snap,type=CephString", \ "make snapshot in ", "osd", "rw", "cli,rest") COMMAND("osd pool rmsnap " \ "name=pool,type=CephPoolname " \ "name=snap,type=CephString", \ "remove snapshot from ", "osd", "rw", "cli,rest") COMMAND("osd pool create " \ "name=pool,type=CephPoolname " \ "name=pg_num,type=CephInt,range=0 " \ "name=pgp_num,type=CephInt,range=0,req=false " \ "name=pool_type,type=CephChoices,strings=replicated|erasure,req=false " \ "name=erasure_code_profile,type=CephString,req=false,goodchars=[A-Za-z0-9-_.=] " \ "name=ruleset,type=CephString,req=false,goodchars=[A-Za-z0-9-_.=]", \ "create pool", "osd", "rw", "cli,rest") COMMAND("osd pool delete " \ "name=pool,type=CephPoolname " \ "name=pool2,type=CephPoolname,req=false " \ "name=sure,type=CephChoices,strings=--yes-i-really-really-mean-it,req=false", \ "delete pool", \ "osd", "rw", "cli,rest") COMMAND("osd pool rename " \ "name=srcpool,type=CephPoolname " \ "name=destpool,type=CephPoolname", \ "rename to ", "osd", "rw", "cli,rest") COMMAND("osd pool get " \ "name=pool,type=CephPoolname " \ "name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|auid|target_max_objects|target_max_bytes|cache_target_dirty_ratio|cache_target_full_ratio|cache_min_flush_age|cache_min_evict_age|erasure_code_profile|min_read_recency_for_promote", \ "get pool parameter ", "osd", "r", "cli,rest") COMMAND("osd pool set " \ "name=pool,type=CephPoolname " \ "name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hashpspool|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|debug_fake_ec_pool|target_max_bytes|target_max_objects|cache_target_dirty_ratio|cache_target_full_ratio|cache_min_flush_age|cache_min_evict_age|auid|min_read_recency_for_promote " \ "name=val,type=CephString " \ "name=force,type=CephChoices,strings=--yes-i-really-mean-it,req=false", \ "set pool parameter to ", "osd", "rw", "cli,rest") // 'val' is a CephString because it can include a unit. Perhaps // there should be a Python type for validation/conversion of strings // with units. COMMAND("osd pool set-quota " \ "name=pool,type=CephPoolname " \ "name=field,type=CephChoices,strings=max_objects|max_bytes " \ "name=val,type=CephString", "set object or byte limit on pool", "osd", "rw", "cli,rest") COMMAND("osd pool get-quota " \ "name=pool,type=CephPoolname ", "obtain object or byte limits for pool", "osd", "r", "cli,rest") COMMAND("osd pool stats " \ "name=name,type=CephString,req=false", "obtain stats from all pools, or from specified pool", "osd", "r", "cli,rest") COMMAND("osd reweight-by-utilization " \ "name=oload,type=CephInt,range=100,req=false", \ "reweight OSDs by utilization [overload-percentage-for-consideration, default 120]", \ "osd", "rw", "cli,rest") COMMAND("osd thrash " \ "name=num_epochs,type=CephInt,range=0", \ "thrash OSDs for ", "osd", "rw", "cli,rest") // tiering COMMAND("osd tier add " \ "name=pool,type=CephPoolname " \ "name=tierpool,type=CephPoolname " \ "name=force_nonempty,type=CephChoices,strings=--force-nonempty,req=false", "add the tier (the second one) to base pool (the first one)", \ "osd", "rw", "cli,rest") COMMAND("osd tier remove " \ "name=pool,type=CephPoolname " \ "name=tierpool,type=CephPoolname", "remove the tier (the second one) from base pool (the first one)", \ "osd", "rw", "cli,rest") COMMAND("osd tier cache-mode " \ "name=pool,type=CephPoolname " \ "name=mode,type=CephChoices,strings=none|writeback|forward|readonly", \ "specify the caching mode for cache tier ", "osd", "rw", "cli,rest") COMMAND("osd tier set-overlay " \ "name=pool,type=CephPoolname " \ "name=overlaypool,type=CephPoolname", \ "set the overlay pool for base pool to be ", "osd", "rw", "cli,rest") COMMAND("osd tier remove-overlay " \ "name=pool,type=CephPoolname ", \ "remove the overlay pool for base pool ", "osd", "rw", "cli,rest") COMMAND("osd tier add-cache " \ "name=pool,type=CephPoolname " \ "name=tierpool,type=CephPoolname " \ "name=size,type=CephInt,range=0", \ "add a cache (the second one) of size to existing pool (the first one)", \ "osd", "rw", "cli,rest") /* * mon/ConfigKeyService.cc */ COMMAND("config-key get " \ "name=key,type=CephString", \ "get ", "config-key", "r", "cli,rest") COMMAND("config-key put " \ "name=key,type=CephString " \ "name=val,type=CephString,req=false", \ "put , value ", "config-key", "rw", "cli,rest") COMMAND("config-key del " \ "name=key,type=CephString", \ "delete ", "config-key", "rw", "cli,rest") COMMAND("config-key exists " \ "name=key,type=CephString", \ "check for 's existence", "config-key", "r", "cli,rest") COMMAND("config-key list ", "list keys", "config-key", "r", "cli,rest") ceph-0.80.11/src/mon/HealthService.h0000664000175100017510000000226412623076744021160 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_HEALTH_SERVICE_H #define CEPH_MON_HEALTH_SERVICE_H #include "mon/Monitor.h" #include "mon/QuorumService.h" #include "messages/MMonHealth.h" #include "common/config.h" struct HealthService : public QuorumService { enum { SERVICE_HEALTH_DATA = 0x01 }; HealthService(Monitor *m) : QuorumService(m) { } virtual ~HealthService() { } virtual bool service_dispatch(Message *m) { return service_dispatch(static_cast(m)); } virtual bool service_dispatch(MMonHealth *m) = 0; public: virtual void get_health(Formatter *f, list >& summary, list > *detail) = 0; virtual int get_type() = 0; virtual string get_name() const = 0; }; #endif // CEPH_MON_HEALTH_SERVICE_H ceph-0.80.11/src/mon/MonClient.h0000664000175100017510000002502512623076744020322 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MONCLIENT_H #define CEPH_MONCLIENT_H #include "msg/Dispatcher.h" #include "msg/Messenger.h" #include "MonMap.h" #include "common/Timer.h" #include "common/Finisher.h" #include "auth/AuthClientHandler.h" #include "auth/RotatingKeyRing.h" #include "messages/MMonSubscribe.h" #include "common/SimpleRNG.h" #include "osd/osd_types.h" #include class MonMap; class MMonMap; class MMonGetVersion; class MMonGetVersionReply; struct MMonSubscribeAck; class MMonCommandAck; class MCommandReply; struct MAuthReply; class MAuthRotating; class MPing; class LogClient; class AuthSupported; class AuthAuthorizeHandlerRegistry; class AuthMethodList; enum MonClientState { MC_STATE_NONE, MC_STATE_NEGOTIATING, MC_STATE_AUTHENTICATING, MC_STATE_HAVE_SESSION, }; struct MonClientPinger : public Dispatcher { Mutex lock; Cond ping_recvd_cond; string *result; bool done; MonClientPinger(CephContext *cct_, string *res_) : Dispatcher(cct_), lock("MonClientPinger::lock"), result(res_), done(false) { } int wait_for_reply(double timeout = 0.0) { utime_t until = ceph_clock_now(cct); until += (timeout > 0 ? timeout : cct->_conf->client_mount_timeout); done = false; int ret = 0; while (!done) { ret = ping_recvd_cond.WaitUntil(lock, until); if (ret == -ETIMEDOUT) break; } return ret; } bool ms_dispatch(Message *m) { Mutex::Locker l(lock); if (m->get_type() != CEPH_MSG_PING) return false; bufferlist &payload = m->get_payload(); if (result && payload.length() > 0) { bufferlist::iterator p = payload.begin(); ::decode(*result, p); } done = true; ping_recvd_cond.SignalAll(); m->put(); return true; } bool ms_handle_reset(Connection *con) { Mutex::Locker l(lock); done = true; ping_recvd_cond.SignalAll(); return true; } void ms_handle_remote_reset(Connection *con) {} }; class MonClient : public Dispatcher { public: MonMap monmap; private: MonClientState state; Messenger *messenger; string cur_mon; ConnectionRef cur_con; SimpleRNG rng; EntityName entity_name; entity_addr_t my_addr; Mutex monc_lock; SafeTimer timer; Finisher finisher; // Added to support session signatures. PLR AuthAuthorizeHandlerRegistry *authorize_handler_registry; bool initialized; bool no_keyring_disabled_cephx; LogClient *log_client; bool more_log_pending; void send_log(); AuthMethodList *auth_supported; bool ms_dispatch(Message *m); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con) {} void handle_monmap(MMonMap *m); void handle_auth(MAuthReply *m); // monitor session bool hunting; struct C_Tick : public Context { MonClient *monc; C_Tick(MonClient *m) : monc(m) {} void finish(int r) { monc->tick(); } }; void tick(); void schedule_tick(); Cond auth_cond; void handle_auth_rotating_response(MAuthRotating *m); // monclient bool want_monmap; uint32_t want_keys; uint64_t global_id; // authenticate private: Cond map_cond; int authenticate_err; list waiting_for_session; Context *session_established_context; bool had_a_connection; double reopen_interval_multiplier; string _pick_random_mon(); void _finish_hunting(); void _reopen_session(int rank, string name); void _reopen_session() { _reopen_session(-1, string()); } void _send_mon_message(Message *m, bool force=false); public: void set_entity_name(EntityName name) { entity_name = name; } int _check_auth_tickets(); int _check_auth_rotating(); int wait_auth_rotating(double timeout); int authenticate(double timeout=0.0); // mon subscriptions private: map sub_have; // my subs, and current versions utime_t sub_renew_sent, sub_renew_after; void _renew_subs(); void handle_subscribe_ack(MMonSubscribeAck* m); bool _sub_want(string what, version_t start, unsigned flags) { if (sub_have.count(what) && sub_have[what].start == start && sub_have[what].flags == flags) return false; sub_have[what].start = start; sub_have[what].flags = flags; return true; } void _sub_got(string what, version_t got) { if (sub_have.count(what)) { if (sub_have[what].flags & CEPH_SUBSCRIBE_ONETIME) sub_have.erase(what); else sub_have[what].start = got + 1; } } void _sub_unwant(string what) { sub_have.erase(what); } // auth tickets public: AuthClientHandler *auth; public: void renew_subs() { Mutex::Locker l(monc_lock); _renew_subs(); } bool sub_want(string what, version_t start, unsigned flags) { Mutex::Locker l(monc_lock); return _sub_want(what, start, flags); } void sub_got(string what, version_t have) { Mutex::Locker l(monc_lock); _sub_got(what, have); } void sub_unwant(string what) { Mutex::Locker l(monc_lock); _sub_unwant(what); } /** * Increase the requested subscription start point. If you do increase * the value, apply the passed-in flags as well; otherwise do nothing. */ bool sub_want_increment(string what, version_t start, unsigned flags) { Mutex::Locker l(monc_lock); map::iterator i = sub_have.find(what); if (i == sub_have.end() || i->second.start < start) { ceph_mon_subscribe_item& item = sub_have[what]; item.start = start; item.flags = flags; return true; } return false; } KeyRing *keyring; RotatingKeyRing *rotating_secrets; public: MonClient(CephContext *cct_); ~MonClient(); int init(); void shutdown(); void set_log_client(LogClient *clog) { log_client = clog; } int build_initial_monmap(); int get_monmap(); int get_monmap_privately(); /** * Ping monitor with ID @p mon_id and record the resulting * reply in @p result_reply. * * @param[in] mon_id Target monitor's ID * @param[out] Resulting reply from mon.ID, if param != NULL * @returns 0 in case of success; < 0 in case of error, * -ETIMEDOUT if monitor didn't reply before timeout * expired (default: conf->client_mount_timeout). */ int ping_monitor(const string &mon_id, string *result_reply); void send_mon_message(Message *m) { Mutex::Locker l(monc_lock); _send_mon_message(m); } /** * If you specify a callback, you should not call * reopen_session() again until it has been triggered. The MonClient * will behave, but the first callback could be triggered after * the session has been killed and the MonClient has started trying * to reconnect to another monitor. */ void reopen_session(Context *cb=NULL) { Mutex::Locker l(monc_lock); if (cb) { delete session_established_context; session_established_context = cb; } _reopen_session(); } entity_addr_t get_my_addr() const { return my_addr; } const uuid_d& get_fsid() { return monmap.fsid; } entity_addr_t get_mon_addr(unsigned i) { Mutex::Locker l(monc_lock); if (i < monmap.size()) return monmap.get_addr(i); return entity_addr_t(); } entity_inst_t get_mon_inst(unsigned i) { Mutex::Locker l(monc_lock); if (i < monmap.size()) return monmap.get_inst(i); return entity_inst_t(); } int get_num_mon() { Mutex::Locker l(monc_lock); return monmap.size(); } uint64_t get_global_id() const { return global_id; } void set_messenger(Messenger *m) { messenger = m; } void send_auth_message(Message *m) { _send_mon_message(m, true); } void set_want_keys(uint32_t want) { want_keys = want; if (auth) auth->set_want_keys(want | CEPH_ENTITY_TYPE_MON); } void add_want_keys(uint32_t want) { want_keys |= want; if (auth) auth->add_want_keys(want); } // admin commands private: uint64_t last_mon_command_tid; struct MonCommand { string target_name; int target_rank; uint64_t tid; vector cmd; bufferlist inbl; bufferlist *poutbl; string *prs; int *prval; Context *onfinish, *ontimeout; MonCommand(uint64_t t) : target_rank(-1), tid(t), poutbl(NULL), prs(NULL), prval(NULL), onfinish(NULL), ontimeout(NULL) {} }; map mon_commands; class C_CancelMonCommand : public Context { uint64_t tid; MonClient *monc; public: C_CancelMonCommand(uint64_t tid, MonClient *monc) : tid(tid), monc(monc) {} void finish(int r) { monc->_cancel_mon_command(tid, -ETIMEDOUT); } }; void _send_command(MonCommand *r); void _resend_mon_commands(); int _cancel_mon_command(uint64_t tid, int r); void _finish_command(MonCommand *r, int ret, string rs); void handle_mon_command_ack(MMonCommandAck *ack); public: int start_mon_command(const vector& cmd, const bufferlist& inbl, bufferlist *outbl, string *outs, Context *onfinish); int start_mon_command(int mon_rank, const vector& cmd, const bufferlist& inbl, bufferlist *outbl, string *outs, Context *onfinish); int start_mon_command(const string &mon_name, ///< mon name, with mon. prefix const vector& cmd, const bufferlist& inbl, bufferlist *outbl, string *outs, Context *onfinish); // version requests public: /** * get latest known version(s) of cluster map * * @param map string name of map (e.g., 'osdmap') * @param newest pointer where newest map version will be stored * @param oldest pointer where oldest map version will be stored * @param onfinish context that will be triggered on completion * @return (via context) 0 on success, -EAGAIN if we need to resubmit our request */ void get_version(string map, version_t *newest, version_t *oldest, Context *onfinish); private: struct version_req_d { Context *context; version_t *newest, *oldest; version_req_d(Context *con, version_t *n, version_t *o) : context(con),newest(n), oldest(o) {} }; map version_requests; ceph_tid_t version_req_id; void handle_get_version_reply(MMonGetVersionReply* m); MonClient(const MonClient &rhs); MonClient& operator=(const MonClient &rhs); }; #endif ceph-0.80.11/src/mon/OSDMonitor.h0000664000175100017510000003102112623076744020420 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* Object Store Device (OSD) Monitor */ #ifndef CEPH_OSDMONITOR_H #define CEPH_OSDMONITOR_H #include #include using namespace std; #include "include/types.h" #include "common/simple_cache.hpp" #include "msg/Messenger.h" #include "osd/OSDMap.h" #include "PaxosService.h" #include "Session.h" class Monitor; #include "messages/MOSDBoot.h" #include "messages/MMonCommand.h" #include "messages/MOSDMap.h" #include "messages/MOSDFailure.h" #include "messages/MPoolOp.h" #include "erasure-code/ErasureCodeInterface.h" #define OSD_METADATA_PREFIX "osd_metadata" /// information about a particular peer's failure reports for one osd struct failure_reporter_t { int num_reports; ///< reports from this reporter utime_t failed_since; ///< when they think it failed MOSDFailure *msg; ///< most recent failure message failure_reporter_t() : num_reports(0), msg(NULL) {} failure_reporter_t(utime_t s) : num_reports(1), failed_since(s), msg(NULL) {} ~failure_reporter_t() { // caller should have taken this message before removing the entry. assert(!msg); } }; /// information about all failure reports for one osd struct failure_info_t { map reporters; ///< reporter -> # reports utime_t max_failed_since; ///< most recent failed_since int num_reports; failure_info_t() : num_reports(0) {} utime_t get_failed_since() { if (max_failed_since == utime_t() && !reporters.empty()) { // the old max must have canceled; recalculate. for (map::iterator p = reporters.begin(); p != reporters.end(); ++p) if (p->second.failed_since > max_failed_since) max_failed_since = p->second.failed_since; } return max_failed_since; } // set the message for the latest report. return any old message we had, // if any, so we can discard it. MOSDFailure *add_report(int who, utime_t failed_since, MOSDFailure *msg) { map::iterator p = reporters.find(who); if (p == reporters.end()) { if (max_failed_since == utime_t()) max_failed_since = failed_since; else if (max_failed_since < failed_since) max_failed_since = failed_since; p = reporters.insert(map::value_type(who, failure_reporter_t(failed_since))).first; } else { p->second.num_reports++; } num_reports++; MOSDFailure *ret = p->second.msg; p->second.msg = msg; return ret; } void take_report_messages(list& ls) { for (map::iterator p = reporters.begin(); p != reporters.end(); ++p) { if (p->second.msg) { ls.push_back(p->second.msg); p->second.msg = NULL; } } } void cancel_report(int who) { map::iterator p = reporters.find(who); if (p == reporters.end()) return; num_reports -= p->second.num_reports; reporters.erase(p); if (reporters.empty()) max_failed_since = utime_t(); } }; class OSDMonitor : public PaxosService { public: OSDMap osdmap; private: // [leader] OSDMap::Incremental pending_inc; map pending_metadata; set pending_metadata_rm; map failure_info; map down_pending_out; // osd down -> out map osd_weight; /* * cache what epochs we think osds have. this is purely * optimization to try to avoid sending the same inc maps twice. */ map osd_epoch; SimpleLRU inc_osd_cache; SimpleLRU full_osd_cache; void check_failures(utime_t now); bool check_failure(utime_t now, int target_osd, failure_info_t& fi); // map thrashing int thrash_map; int thrash_last_up_osd; bool thrash(); bool _have_pending_crush(); CrushWrapper &_get_stable_crush(); void _get_pending_crush(CrushWrapper& newcrush); // svc public: void create_initial(); private: void update_from_paxos(bool *need_bootstrap); void create_pending(); // prepare a new pending void encode_pending(MonitorDBStore::Transaction *t); void on_active(); void on_shutdown(); /** * we haven't delegated full version stashing to paxosservice for some time * now, making this function useless in current context. */ virtual void encode_full(MonitorDBStore::Transaction *t) { } /** * do not let paxosservice periodically stash full osdmaps, or we will break our * locally-managed full maps. (update_from_paxos loads the latest and writes them * out going forward from there, but if we just synced that may mean we skip some.) */ virtual bool should_stash_full() { return false; } /** * hook into trim to include the oldest full map in the trim transaction * * This ensures that anyone post-sync will have enough to rebuild their * full osdmaps. */ void encode_trim_extra(MonitorDBStore::Transaction *tx, version_t first); void update_msgr_features(); int check_cluster_features(uint64_t features, stringstream &ss); /** * check if the cluster supports the features required by the * given crush map. Outputs the daemons which don't support it * to the stringstream. * * @returns true if the map is passable, false otherwise */ bool validate_crush_against_features(const CrushWrapper *newcrush, stringstream &ss); void share_map_with_random_osd(); void update_logger(); void handle_query(PaxosServiceMessage *m); bool preprocess_query(PaxosServiceMessage *m); // true if processed. bool prepare_update(PaxosServiceMessage *m); bool should_propose(double &delay); version_t get_trim_to(); bool can_mark_down(int o); bool can_mark_up(int o); bool can_mark_out(int o); bool can_mark_in(int o); // ... MOSDMap *build_latest_full(); MOSDMap *build_incremental(epoch_t first, epoch_t last); void send_full(PaxosServiceMessage *m); void send_incremental(PaxosServiceMessage *m, epoch_t first); void send_incremental(epoch_t first, entity_inst_t& dest, bool onetime); int reweight_by_utilization(int oload, std::string& out_str); bool check_source(PaxosServiceMessage *m, uuid_d fsid); bool preprocess_mark_me_down(class MOSDMarkMeDown *m); friend class C_AckMarkedDown; bool preprocess_failure(class MOSDFailure *m); bool prepare_failure(class MOSDFailure *m); bool prepare_mark_me_down(class MOSDMarkMeDown *m); void process_failures(); void take_all_failures(list& ls); bool preprocess_boot(class MOSDBoot *m); bool prepare_boot(class MOSDBoot *m); void _booted(MOSDBoot *m, bool logit); bool preprocess_alive(class MOSDAlive *m); bool prepare_alive(class MOSDAlive *m); void _reply_map(PaxosServiceMessage *m, epoch_t e); bool preprocess_pgtemp(class MOSDPGTemp *m); bool prepare_pgtemp(class MOSDPGTemp *m); int _check_remove_pool(int64_t pool, const pg_pool_t *pi, ostream *ss); int _prepare_remove_pool(int64_t pool, ostream *ss); int _prepare_rename_pool(int64_t pool, string newname); bool preprocess_pool_op ( class MPoolOp *m); bool preprocess_pool_op_create ( class MPoolOp *m); bool prepare_pool_op (MPoolOp *m); bool prepare_pool_op_create (MPoolOp *m); bool prepare_pool_op_delete(MPoolOp *m); int crush_ruleset_create_erasure(const string &name, const string &profile, int *ruleset, stringstream &ss); int get_erasure_code(const string &erasure_code_profile, ErasureCodeInterfaceRef *erasure_code, stringstream &ss) const; int prepare_pool_crush_ruleset(const unsigned pool_type, const string &erasure_code_profile, const string &ruleset_name, int *crush_ruleset, stringstream &ss); bool erasure_code_profile_in_use(const map &pools, const string &profile, ostream &ss); int parse_erasure_code_profile(const vector &erasure_code_profile, map *erasure_code_profile_map, stringstream &ss); int prepare_pool_size(const unsigned pool_type, const string &erasure_code_profile, unsigned *size, unsigned *min_size, stringstream &ss); int prepare_pool_stripe_width(const unsigned pool_type, const string &erasure_code_profile, unsigned *stripe_width, stringstream &ss); int prepare_new_pool(string& name, uint64_t auid, int crush_ruleset, const string &crush_ruleset_name, unsigned pg_num, unsigned pgp_num, const string &erasure_code_profile, const unsigned pool_type, stringstream &ss); int prepare_new_pool(MPoolOp *m); void update_pool_flags(int64_t pool_id, uint64_t flags); bool update_pools_status(); void get_pools_health(list >& summary, list > *detail) const; bool prepare_set_flag(MMonCommand *m, int flag); bool prepare_unset_flag(MMonCommand *m, int flag); void _pool_op_reply(MPoolOp *m, int ret, epoch_t epoch, bufferlist *blp=NULL); struct C_Booted : public Context { OSDMonitor *cmon; MOSDBoot *m; bool logit; C_Booted(OSDMonitor *cm, MOSDBoot *m_, bool l=true) : cmon(cm), m(m_), logit(l) {} void finish(int r) { if (r >= 0) cmon->_booted(m, logit); else if (r == -ECANCELED) m->put(); else if (r == -EAGAIN) cmon->dispatch((PaxosServiceMessage*)m); else assert(0 == "bad C_Booted return value"); } }; struct C_ReplyMap : public Context { OSDMonitor *osdmon; PaxosServiceMessage *m; epoch_t e; C_ReplyMap(OSDMonitor *o, PaxosServiceMessage *mm, epoch_t ee) : osdmon(o), m(mm), e(ee) {} void finish(int r) { if (r >= 0) osdmon->_reply_map(m, e); else if (r == -ECANCELED) m->put(); else if (r == -EAGAIN) osdmon->dispatch(m); else assert(0 == "bad C_ReplyMap return value"); } }; struct C_PoolOp : public Context { OSDMonitor *osdmon; MPoolOp *m; int replyCode; int epoch; bufferlist reply_data; C_PoolOp(OSDMonitor * osd, MPoolOp *m_, int rc, int e, bufferlist *rd=NULL) : osdmon(osd), m(m_), replyCode(rc), epoch(e) { if (rd) reply_data = *rd; } void finish(int r) { if (r >= 0) osdmon->_pool_op_reply(m, replyCode, epoch, &reply_data); else if (r == -ECANCELED) m->put(); else if (r == -EAGAIN) osdmon->dispatch(m); else assert(0 == "bad C_PoolOp return value"); } }; bool preprocess_remove_snaps(struct MRemoveSnaps *m); bool prepare_remove_snaps(struct MRemoveSnaps *m); public: OSDMonitor(Monitor *mn, Paxos *p, string service_name); void tick(); // check state, take actions int parse_osd_id(const char *s, stringstream *pss); void get_health(list >& summary, list > *detail) const; bool preprocess_command(MMonCommand *m); bool prepare_command(MMonCommand *m); bool prepare_command_impl(MMonCommand *m, map &cmdmap); int prepare_command_pool_set(map &cmdmap, stringstream& ss); void handle_osd_timeouts(const utime_t &now, std::map &last_osd_report); void mark_all_down(); void send_latest(PaxosServiceMessage *m, epoch_t start=0); void send_latest_now_nodelete(PaxosServiceMessage *m, epoch_t start=0) { send_incremental(m, start); } int get_version(version_t ver, bufferlist& bl); int get_version_full(version_t ver, bufferlist& bl); epoch_t blacklist(const entity_addr_t& a, utime_t until); void dump_info(Formatter *f); int dump_osd_metadata(int osd, Formatter *f, ostream *err); void check_subs(); void check_sub(Subscription *sub); void add_flag(int flag) { if (!(osdmap.flags & flag)) { if (pending_inc.new_flags < 0) pending_inc.new_flags = osdmap.flags; pending_inc.new_flags |= flag; } } void remove_flag(int flag) { if(osdmap.flags & flag) { if (pending_inc.new_flags < 0) pending_inc.new_flags = osdmap.flags; pending_inc.new_flags &= ~flag; } } }; #endif ceph-0.80.11/src/mon/PGMonitor.cc0000664000175100017510000017706212623076744020457 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "json_spirit/json_spirit.h" #include "common/debug.h" // undo damage #include "PGMonitor.h" #include "Monitor.h" #include "MDSMonitor.h" #include "OSDMonitor.h" #include "MonitorDBStore.h" #include "messages/MPGStats.h" #include "messages/MPGStatsAck.h" #include "messages/MGetPoolStats.h" #include "messages/MGetPoolStatsReply.h" #include "messages/MStatfs.h" #include "messages/MStatfsReply.h" #include "messages/MOSDPGCreate.h" #include "messages/MMonCommand.h" #include "messages/MOSDScrub.h" #include "common/Timer.h" #include "common/Formatter.h" #include "common/ceph_argparse.h" #include "common/perf_counters.h" #include "common/TextTable.h" #include "include/stringify.h" #include "osd/osd_types.h" #include "common/config.h" #include "common/errno.h" #include "common/strtol.h" #include "include/str_list.h" #include #include #include "common/cmdparse.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, pg_map) static ostream& _prefix(std::ostream *_dout, const Monitor *mon, const PGMap& pg_map) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").pg v" << pg_map.version << " "; } /* Tick function to update the map based on performance every N seconds */ void PGMonitor::on_restart() { // clear leader state last_sent_pg_create.clear(); last_osd_report.clear(); } void PGMonitor::on_active() { if (mon->is_leader()) { check_osd_map(mon->osdmon()->osdmap.epoch); need_check_down_pgs = true; } update_logger(); if (mon->is_leader()) mon->clog.info() << "pgmap " << pg_map << "\n"; } void PGMonitor::update_logger() { dout(10) << "update_logger" << dendl; mon->cluster_logger->set(l_cluster_osd_kb, pg_map.osd_sum.kb); mon->cluster_logger->set(l_cluster_osd_kb_used, pg_map.osd_sum.kb_used); mon->cluster_logger->set(l_cluster_osd_kb_avail, pg_map.osd_sum.kb_avail); mon->cluster_logger->set(l_cluster_num_pool, pg_map.pg_pool_sum.size()); mon->cluster_logger->set(l_cluster_num_pg, pg_map.pg_stat.size()); unsigned active = 0, active_clean = 0, peering = 0; for (ceph::unordered_map::iterator p = pg_map.num_pg_by_state.begin(); p != pg_map.num_pg_by_state.end(); ++p) { if (p->first & PG_STATE_ACTIVE) { active += p->second; if (p->first & PG_STATE_CLEAN) active_clean += p->second; } if (p->first & PG_STATE_PEERING) peering += p->second; } mon->cluster_logger->set(l_cluster_num_pg_active_clean, active_clean); mon->cluster_logger->set(l_cluster_num_pg_active, active); mon->cluster_logger->set(l_cluster_num_pg_peering, peering); mon->cluster_logger->set(l_cluster_num_object, pg_map.pg_sum.stats.sum.num_objects); mon->cluster_logger->set(l_cluster_num_object_degraded, pg_map.pg_sum.stats.sum.num_objects_degraded); mon->cluster_logger->set(l_cluster_num_object_unfound, pg_map.pg_sum.stats.sum.num_objects_unfound); mon->cluster_logger->set(l_cluster_num_bytes, pg_map.pg_sum.stats.sum.num_bytes); } void PGMonitor::tick() { if (!is_active()) return; handle_osd_timeouts(); if (mon->is_leader()) { bool propose = false; if (need_check_down_pgs && check_down_pgs()) propose = true; if (propose) { propose_pending(); } } if (!pg_map.pg_sum_deltas.empty()) { utime_t age = ceph_clock_now(g_ceph_context) - pg_map.stamp; if (age > 2 * g_conf->mon_delta_reset_interval) { dout(10) << " clearing pg_map delta (" << age << " > " << g_conf->mon_delta_reset_interval << " seconds old)" << dendl; pg_map.clear_delta(); } } /* If we have deltas for pools, run through pgmap's 'per_pool_sum_delta' and * clear any deltas that are old enough. * * Note that 'per_pool_sum_delta' keeps a pool id as key, and a pair containing * the calc'ed stats delta and an absolute timestamp from when those stats were * obtained -- the timestamp IS NOT a delta itself. */ if (!pg_map.per_pool_sum_deltas.empty()) { ceph::unordered_map >::iterator it; for (it = pg_map.per_pool_sum_delta.begin(); it != pg_map.per_pool_sum_delta.end(); ) { utime_t age = ceph_clock_now(g_ceph_context) - it->second.second; if (age > 2*g_conf->mon_delta_reset_interval) { dout(10) << " clearing pg_map delta for pool " << it->first << " (" << age << " > " << g_conf->mon_delta_reset_interval << " seconds old)" << dendl; pg_map.per_pool_sum_deltas.erase(it->first); pg_map.per_pool_sum_deltas_stamps.erase(it->first); pg_map.per_pool_sum_delta.erase((it++)->first); } else { ++it; } } } dout(10) << pg_map << dendl; } void PGMonitor::create_initial() { dout(10) << "create_initial -- creating initial map" << dendl; format_version = 1; } void PGMonitor::update_from_paxos(bool *need_bootstrap) { version_t version = get_last_committed(); if (version == pg_map.version) return; assert(version >= pg_map.version); if (format_version == 0) { // old format /* Obtain latest full pgmap version, if available and whose version is * greater than the current pgmap's version. */ version_t latest_full = get_version_latest_full(); if ((latest_full > 0) && (latest_full > pg_map.version)) { bufferlist latest_bl; int err = get_version_full(latest_full, latest_bl); assert(err == 0); dout(7) << __func__ << " loading latest full pgmap v" << latest_full << dendl; try { PGMap tmp_pg_map; bufferlist::iterator p = latest_bl.begin(); tmp_pg_map.decode(p); pg_map = tmp_pg_map; } catch (const std::exception& e) { dout(0) << __func__ << ": error parsing update: " << e.what() << dendl; assert(0 == "update_from_paxos: error parsing update"); return; } } // walk through incrementals while (version > pg_map.version) { bufferlist bl; int err = get_version(pg_map.version+1, bl); assert(err == 0); assert(bl.length()); dout(7) << "update_from_paxos applying incremental " << pg_map.version+1 << dendl; PGMap::Incremental inc; try { bufferlist::iterator p = bl.begin(); inc.decode(p); } catch (const std::exception &e) { dout(0) << "update_from_paxos: error parsing " << "incremental update: " << e.what() << dendl; assert(0 == "update_from_paxos: error parsing incremental update"); return; } pg_map.apply_incremental(g_ceph_context, inc); dout(10) << pg_map << dendl; if (inc.pg_scan) last_sent_pg_create.clear(); // reset pg_create throttle timer } } else if (format_version == 1) { // pg/osd keys in leveldb // read meta epoch_t last_pg_scan = pg_map.last_pg_scan; while (version > pg_map.version) { // load full state? if (pg_map.version == 0) { dout(10) << __func__ << " v0, read_full" << dendl; read_pgmap_full(); goto out; } // incremental state? dout(10) << __func__ << " read_incremental" << dendl; bufferlist bl; int r = get_version(pg_map.version + 1, bl); if (r == -ENOENT) { dout(10) << __func__ << " failed to read_incremental, read_full" << dendl; read_pgmap_full(); goto out; } assert(r == 0); apply_pgmap_delta(bl); } read_pgmap_meta(); out: if (last_pg_scan != pg_map.last_pg_scan) last_sent_pg_create.clear(); // reset pg_create throttle timer } assert(version == pg_map.version); if (mon->osdmon()->osdmap.get_epoch()) { map_pg_creates(); send_pg_creates(); } update_logger(); } void PGMonitor::on_upgrade() { dout(1) << __func__ << " discarding in-core PGMap" << dendl; pg_map = PGMap(); } void PGMonitor::upgrade_format() { unsigned current = 1; assert(format_version <= current); if (format_version == current) return; dout(1) << __func__ << " to " << current << dendl; // upgrade by dirtying it all pg_map.dirty_all(pending_inc); format_version = current; propose_pending(); } void PGMonitor::post_paxos_update() { if (mon->osdmon()->osdmap.get_epoch()) { map_pg_creates(); send_pg_creates(); } } void PGMonitor::handle_osd_timeouts() { if (!mon->is_leader()) return; utime_t now(ceph_clock_now(g_ceph_context)); utime_t timeo(g_conf->mon_osd_report_timeout, 0); if (now - mon->get_leader_since() < timeo) { // We haven't been the leader for long enough to consider OSD timeouts return; } if (mon->osdmon()->is_writeable()) mon->osdmon()->handle_osd_timeouts(now, last_osd_report); } void PGMonitor::create_pending() { pending_inc = PGMap::Incremental(); pending_inc.version = pg_map.version + 1; if (pg_map.version == 0) { // pull initial values from first leader mon's config pending_inc.full_ratio = g_conf->mon_osd_full_ratio; if (pending_inc.full_ratio > 1.0) pending_inc.full_ratio /= 100.0; pending_inc.nearfull_ratio = g_conf->mon_osd_nearfull_ratio; if (pending_inc.nearfull_ratio > 1.0) pending_inc.nearfull_ratio /= 100.0; } else { pending_inc.full_ratio = pg_map.full_ratio; pending_inc.nearfull_ratio = pg_map.nearfull_ratio; } dout(10) << "create_pending v " << pending_inc.version << dendl; } void PGMonitor::read_pgmap_meta() { dout(10) << __func__ << dendl; string prefix = pgmap_meta_prefix; version_t version = mon->store->get(prefix, "version"); epoch_t last_osdmap_epoch = mon->store->get(prefix, "last_osdmap_epoch"); epoch_t last_pg_scan = mon->store->get(prefix, "last_pg_scan"); pg_map.set_version(version); pg_map.set_last_osdmap_epoch(last_osdmap_epoch); if (last_pg_scan != pg_map.get_last_pg_scan()) { pg_map.set_last_pg_scan(last_pg_scan); // clear our osdmap epoch so that map_pg_creates() will re-run last_map_pg_create_osd_epoch = 0; } float full_ratio, nearfull_ratio; { bufferlist bl; mon->store->get(prefix, "full_ratio", bl); bufferlist::iterator p = bl.begin(); ::decode(full_ratio, p); } { bufferlist bl; mon->store->get(prefix, "nearfull_ratio", bl); bufferlist::iterator p = bl.begin(); ::decode(nearfull_ratio, p); } pg_map.set_full_ratios(full_ratio, nearfull_ratio); { bufferlist bl; mon->store->get(prefix, "stamp", bl); bufferlist::iterator p = bl.begin(); utime_t stamp; ::decode(stamp, p); pg_map.set_stamp(stamp); } } void PGMonitor::read_pgmap_full() { read_pgmap_meta(); string prefix = pgmap_pg_prefix; for (KeyValueDB::Iterator i = mon->store->get_iterator(prefix); i->valid(); i->next()) { string key = i->key(); pg_t pgid; if (!pgid.parse(key.c_str())) { dout(0) << "unable to parse key " << key << dendl; continue; } bufferlist bl = i->value(); pg_map.update_pg(pgid, bl); dout(20) << " got " << pgid << dendl; } prefix = pgmap_osd_prefix; for (KeyValueDB::Iterator i = mon->store->get_iterator(prefix); i->valid(); i->next()) { string key = i->key(); int osd = atoi(key.c_str()); bufferlist bl = i->value(); pg_map.update_osd(osd, bl); dout(20) << " got osd." << osd << dendl; } } void PGMonitor::apply_pgmap_delta(bufferlist& bl) { version_t v = pg_map.version + 1; utime_t inc_stamp; bufferlist dirty_pgs, dirty_osds; { bufferlist::iterator p = bl.begin(); ::decode(inc_stamp, p); ::decode(dirty_pgs, p); ::decode(dirty_osds, p); } pool_stat_t pg_sum_old = pg_map.pg_sum; ceph::unordered_map pg_pool_sum_old; // pgs set deleted_pools; bufferlist::iterator p = dirty_pgs.begin(); while (!p.end()) { pg_t pgid; ::decode(pgid, p); bufferlist bl; int r = mon->store->get(pgmap_pg_prefix, stringify(pgid), bl); dout(20) << " refreshing pg " << pgid << " got " << r << " len " << bl.length() << dendl; if (pg_pool_sum_old.count(pgid.pool()) == 0) pg_pool_sum_old[pgid.pool()] = pg_map.pg_pool_sum[pgid.pool()]; if (r >= 0) { pg_map.update_pg(pgid, bl); } else { pg_map.remove_pg(pgid); if (pgid.ps() == 0) deleted_pools.insert(pgid.pool()); } } // osds p = dirty_osds.begin(); while (!p.end()) { int32_t osd; ::decode(osd, p); dout(20) << " refreshing osd." << osd << dendl; bufferlist bl; int r = mon->store->get(pgmap_osd_prefix, stringify(osd), bl); if (r >= 0) { pg_map.update_osd(osd, bl); } else { pg_map.remove_osd(osd); } } pg_map.update_global_delta(g_ceph_context, inc_stamp, pg_sum_old); pg_map.update_pool_deltas(g_ceph_context, inc_stamp, pg_pool_sum_old); // clean up deleted pools after updating the deltas for (set::iterator p = deleted_pools.begin(); p != deleted_pools.end(); ++p) { dout(20) << " deleted pool " << *p << dendl; pg_map.deleted_pool(*p); } // ok, we're now on the new version pg_map.version = v; } void PGMonitor::encode_pending(MonitorDBStore::Transaction *t) { version_t version = pending_inc.version; dout(10) << __func__ << " v " << version << dendl; assert(get_last_committed() + 1 == version); pending_inc.stamp = ceph_clock_now(g_ceph_context); uint64_t features = mon->get_quorum_features(); string prefix = pgmap_meta_prefix; t->put(prefix, "version", pending_inc.version); { bufferlist bl; ::encode(pending_inc.stamp, bl); t->put(prefix, "stamp", bl); } if (pending_inc.osdmap_epoch) t->put(prefix, "last_osdmap_epoch", pending_inc.osdmap_epoch); if (pending_inc.pg_scan) t->put(prefix, "last_pg_scan", pending_inc.pg_scan); if (pending_inc.full_ratio > 0) { bufferlist bl; ::encode(pending_inc.full_ratio, bl); t->put(prefix, "full_ratio", bl); } if (pending_inc.nearfull_ratio > 0) { bufferlist bl; ::encode(pending_inc.nearfull_ratio, bl); t->put(prefix, "nearfull_ratio", bl); } bufferlist incbl; ::encode(pending_inc.stamp, incbl); { bufferlist dirty; string prefix = pgmap_pg_prefix; for (map::const_iterator p = pending_inc.pg_stat_updates.begin(); p != pending_inc.pg_stat_updates.end(); ++p) { ::encode(p->first, dirty); bufferlist bl; ::encode(p->second, bl, features); t->put(prefix, stringify(p->first), bl); } for (set::const_iterator p = pending_inc.pg_remove.begin(); p != pending_inc.pg_remove.end(); ++p) { ::encode(*p, dirty); t->erase(prefix, stringify(*p)); } ::encode(dirty, incbl); } { bufferlist dirty; string prefix = pgmap_osd_prefix; for (map::const_iterator p = pending_inc.get_osd_stat_updates().begin(); p != pending_inc.get_osd_stat_updates().end(); ++p) { ::encode(p->first, dirty); bufferlist bl; ::encode(p->second, bl, features); ::encode(pending_inc.get_osd_epochs().find(p->first)->second, bl); t->put(prefix, stringify(p->first), bl); } for (set::const_iterator p = pending_inc.get_osd_stat_rm().begin(); p != pending_inc.get_osd_stat_rm().end(); ++p) { ::encode(*p, dirty); t->erase(prefix, stringify(*p)); } ::encode(dirty, incbl); } put_version(t, version, incbl); put_last_committed(t, version); } version_t PGMonitor::get_trim_to() { unsigned max = g_conf->mon_max_pgmap_epochs; version_t version = get_last_committed(); if (mon->is_leader() && (version > max)) return version - max; return 0; } bool PGMonitor::preprocess_query(PaxosServiceMessage *m) { dout(10) << "preprocess_query " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case CEPH_MSG_STATFS: handle_statfs(static_cast(m)); return true; case MSG_GETPOOLSTATS: return preprocess_getpoolstats(static_cast(m)); case MSG_PGSTATS: return preprocess_pg_stats(static_cast(m)); case MSG_MON_COMMAND: return preprocess_command(static_cast(m)); default: assert(0); m->put(); return true; } } bool PGMonitor::prepare_update(PaxosServiceMessage *m) { dout(10) << "prepare_update " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_PGSTATS: return prepare_pg_stats((MPGStats*)m); case MSG_MON_COMMAND: return prepare_command(static_cast(m)); default: assert(0); m->put(); return false; } } void PGMonitor::handle_statfs(MStatfs *statfs) { // check caps MonSession *session = statfs->get_session(); if (!session) goto out; if (!session->is_capable("pg", MON_CAP_R)) { dout(0) << "MStatfs received from entity with insufficient privileges " << session->caps << dendl; goto out; } MStatfsReply *reply; dout(10) << "handle_statfs " << *statfs << " from " << statfs->get_orig_source() << dendl; if (statfs->fsid != mon->monmap->fsid) { dout(0) << "handle_statfs on fsid " << statfs->fsid << " != " << mon->monmap->fsid << dendl; goto out; } // fill out stfs reply = new MStatfsReply(mon->monmap->fsid, statfs->get_tid(), get_last_committed()); // these are in KB. reply->h.st.kb = pg_map.osd_sum.kb; reply->h.st.kb_used = pg_map.osd_sum.kb_used; reply->h.st.kb_avail = pg_map.osd_sum.kb_avail; reply->h.st.num_objects = pg_map.pg_sum.stats.sum.num_objects; // reply mon->send_reply(statfs, reply); out: statfs->put(); } bool PGMonitor::preprocess_getpoolstats(MGetPoolStats *m) { MGetPoolStatsReply *reply; MonSession *session = m->get_session(); if (!session) goto out; if (!session->is_capable("pg", MON_CAP_R)) { dout(0) << "MGetPoolStats received from entity with insufficient caps " << session->caps << dendl; goto out; } if (m->fsid != mon->monmap->fsid) { dout(0) << "preprocess_getpoolstats on fsid " << m->fsid << " != " << mon->monmap->fsid << dendl; goto out; } reply = new MGetPoolStatsReply(m->fsid, m->get_tid(), get_last_committed()); for (list::iterator p = m->pools.begin(); p != m->pools.end(); ++p) { int64_t poolid = mon->osdmon()->osdmap.lookup_pg_pool_name(p->c_str()); if (poolid < 0) continue; if (pg_map.pg_pool_sum.count(poolid) == 0) continue; reply->pool_stats[*p] = pg_map.pg_pool_sum[poolid]; } mon->send_reply(m, reply); out: m->put(); return true; } bool PGMonitor::preprocess_pg_stats(MPGStats *stats) { // check caps MonSession *session = stats->get_session(); if (!session) { dout(10) << "PGMonitor::preprocess_pg_stats: no monitor session!" << dendl; stats->put(); return true; } if (!session->is_capable("pg", MON_CAP_R)) { derr << "PGMonitor::preprocess_pg_stats: MPGStats received from entity " << "with insufficient privileges " << session->caps << dendl; stats->put(); return true; } // First, just see if they need a new osdmap. But // only if they've had the map for a while. if (stats->had_map_for > 30.0 && mon->osdmon()->is_readable() && stats->epoch < mon->osdmon()->osdmap.get_epoch()) mon->osdmon()->send_latest_now_nodelete(stats, stats->epoch+1); // Always forward the PGStats to the leader, even if they are the same as // the old PGStats. The leader will mark as down osds that haven't sent // PGStats for a few minutes. return false; } bool PGMonitor::pg_stats_have_changed(int from, const MPGStats *stats) const { // any new osd info? ceph::unordered_map::const_iterator s = pg_map.osd_stat.find(from); if (s == pg_map.osd_stat.end()) return true; if (s->second != stats->osd_stat) return true; // any new pg info? for (map::const_iterator p = stats->pg_stat.begin(); p != stats->pg_stat.end(); ++p) { ceph::unordered_map::const_iterator t = pg_map.pg_stat.find(p->first); if (t == pg_map.pg_stat.end()) return true; if (t->second.reported_epoch != p->second.reported_epoch || t->second.reported_seq != p->second.reported_seq) return true; } return false; } bool PGMonitor::prepare_pg_stats(MPGStats *stats) { dout(10) << "prepare_pg_stats " << *stats << " from " << stats->get_orig_source() << dendl; int from = stats->get_orig_source().num(); if (stats->fsid != mon->monmap->fsid) { dout(0) << "prepare_pg_stats on fsid " << stats->fsid << " != " << mon->monmap->fsid << dendl; stats->put(); return false; } last_osd_report[from] = ceph_clock_now(g_ceph_context); if (!stats->get_orig_source().is_osd() || !mon->osdmon()->osdmap.is_up(from) || stats->get_orig_source_inst() != mon->osdmon()->osdmap.get_inst(from)) { dout(1) << " ignoring stats from non-active osd." << dendl; stats->put(); return false; } if (!pg_stats_have_changed(from, stats)) { dout(10) << " message contains no new osd|pg stats" << dendl; MPGStatsAck *ack = new MPGStatsAck; ack->set_tid(stats->get_tid()); for (map::const_iterator p = stats->pg_stat.begin(); p != stats->pg_stat.end(); ++p) { ack->pg_stat[p->first] = make_pair(p->second.reported_seq, p->second.reported_epoch); } mon->send_reply(stats, ack); stats->put(); return false; } // osd stat if (mon->osdmon()->osdmap.is_in(from)) { pending_inc.update_stat(from, stats->epoch, stats->osd_stat); } else { pending_inc.update_stat(from, stats->epoch, osd_stat_t()); } if (pg_map.osd_stat.count(from)) dout(10) << " got osd." << from << " " << stats->osd_stat << " (was " << pg_map.osd_stat[from] << ")" << dendl; else dout(10) << " got osd." << from << " " << stats->osd_stat << " (first report)" << dendl; // pg stats MPGStatsAck *ack = new MPGStatsAck; ack->set_tid(stats->get_tid()); for (map::iterator p = stats->pg_stat.begin(); p != stats->pg_stat.end(); ++p) { pg_t pgid = p->first; ack->pg_stat[pgid] = make_pair(p->second.reported_seq, p->second.reported_epoch); if (pg_map.pg_stat.count(pgid) && pg_map.pg_stat[pgid].get_version_pair() > p->second.get_version_pair()) { dout(15) << " had " << pgid << " from " << pg_map.pg_stat[pgid].reported_epoch << ":" << pg_map.pg_stat[pgid].reported_seq << dendl; continue; } if (pending_inc.pg_stat_updates.count(pgid) && pending_inc.pg_stat_updates[pgid].get_version_pair() > p->second.get_version_pair()) { dout(15) << " had " << pgid << " from " << pending_inc.pg_stat_updates[pgid].reported_epoch << ":" << pending_inc.pg_stat_updates[pgid].reported_seq << " (pending)" << dendl; continue; } if (pg_map.pg_stat.count(pgid) == 0) { dout(15) << " got " << pgid << " reported at " << p->second.reported_epoch << ":" << p->second.reported_seq << " state " << pg_state_string(p->second.state) << " but DNE in pg_map; pool was probably deleted." << dendl; continue; } dout(15) << " got " << pgid << " reported at " << p->second.reported_epoch << ":" << p->second.reported_seq << " state " << pg_state_string(pg_map.pg_stat[pgid].state) << " -> " << pg_state_string(p->second.state) << dendl; pending_inc.pg_stat_updates[pgid] = p->second; /* // we don't care much about consistency, here; apply to live map. pg_map.stat_pg_sub(pgid, pg_map.pg_stat[pgid]); pg_map.pg_stat[pgid] = p->second; pg_map.stat_pg_add(pgid, pg_map.pg_stat[pgid]); */ } wait_for_finished_proposal(new C_Stats(this, stats, ack)); return true; } void PGMonitor::_updated_stats(MPGStats *req, MPGStatsAck *ack) { dout(7) << "_updated_stats for " << req->get_orig_source_inst() << dendl; mon->send_reply(req, ack); req->put(); } // ------------------------ struct RetryCheckOSDMap : public Context { PGMonitor *pgmon; epoch_t epoch; RetryCheckOSDMap(PGMonitor *p, epoch_t e) : pgmon(p), epoch(e) {} void finish(int r) { if (r == -ECANCELED) return; pgmon->check_osd_map(epoch); } }; void PGMonitor::check_osd_map(epoch_t epoch) { if (mon->is_peon()) return; // whatever. if (pg_map.last_osdmap_epoch >= epoch) { dout(10) << "check_osd_map already seen " << pg_map.last_osdmap_epoch << " >= " << epoch << dendl; return; } if (!mon->osdmon()->is_readable()) { dout(10) << "check_osd_map -- osdmap not readable, waiting" << dendl; mon->osdmon()->wait_for_readable(new RetryCheckOSDMap(this, epoch)); return; } if (!is_writeable()) { dout(10) << "check_osd_map -- pgmap not writeable, waiting" << dendl; wait_for_writeable(new RetryCheckOSDMap(this, epoch)); return; } // apply latest map(s) for (epoch_t e = pg_map.last_osdmap_epoch+1; e <= epoch; e++) { dout(10) << "check_osd_map applying osdmap e" << e << " to pg_map" << dendl; bufferlist bl; int err = mon->osdmon()->get_version(e, bl); assert(err == 0); assert(bl.length()); OSDMap::Incremental inc(bl); for (map::iterator p = inc.new_weight.begin(); p != inc.new_weight.end(); ++p) if (p->second == CEPH_OSD_OUT) { dout(10) << "check_osd_map osd." << p->first << " went OUT" << dendl; pending_inc.stat_osd_out(p->first); } // this is conservative: we want to know if any osds (maybe) got marked down. for (map::iterator p = inc.new_state.begin(); p != inc.new_state.end(); ++p) { if (p->second & CEPH_OSD_UP) { // true if marked up OR down, but we're too lazy to check which need_check_down_pgs = true; // clear out the last_osd_report for this OSD map::iterator report = last_osd_report.find(p->first); if (report != last_osd_report.end()) { last_osd_report.erase(report); } } if (p->second & CEPH_OSD_EXISTS) { // whether it was created *or* destroyed, we can safely drop // it's osd_stat_t record. dout(10) << "check_osd_map osd." << p->first << " created or destroyed" << dendl; pending_inc.rm_stat(p->first); // and adjust full, nearfull set pg_map.nearfull_osds.erase(p->first); pg_map.full_osds.erase(p->first); } } } bool propose = false; if (pg_map.last_osdmap_epoch < epoch) { pending_inc.osdmap_epoch = epoch; propose = true; } // scan pg space? if (register_new_pgs()) propose = true; if (need_check_down_pgs && check_down_pgs()) propose = true; if (propose) propose_pending(); if (mon->osdmon()->osdmap.get_epoch()) { map_pg_creates(); send_pg_creates(); } } void PGMonitor::register_pg(pg_pool_t& pool, pg_t pgid, epoch_t epoch, bool new_pool) { pg_t parent; int split_bits = 0; if (!new_pool) { parent = pgid; while (1) { // remove most significant bit int msb = pool.calc_bits_of(parent.ps()); if (!msb) break; parent.set_ps(parent.ps() & ~(1<<(msb-1))); split_bits++; dout(10) << " is " << pgid << " parent " << parent << " ?" << dendl; //if (parent.u.pg.ps < mon->osdmon->osdmap.get_pgp_num()) { if (pg_map.pg_stat.count(parent) && pg_map.pg_stat[parent].state != PG_STATE_CREATING) { dout(10) << " parent is " << parent << dendl; break; } } } pending_inc.pg_stat_updates[pgid].state = PG_STATE_CREATING; pending_inc.pg_stat_updates[pgid].created = epoch; pending_inc.pg_stat_updates[pgid].parent = parent; pending_inc.pg_stat_updates[pgid].parent_split_bits = split_bits; if (split_bits == 0) { dout(10) << "register_new_pgs will create " << pgid << dendl; } else { dout(10) << "register_new_pgs will create " << pgid << " parent " << parent << " by " << split_bits << " bits" << dendl; } } bool PGMonitor::register_new_pgs() { // iterate over crush mapspace epoch_t epoch = mon->osdmon()->osdmap.get_epoch(); dout(10) << "register_new_pgs checking pg pools for osdmap epoch " << epoch << ", last_pg_scan " << pg_map.last_pg_scan << dendl; OSDMap *osdmap = &mon->osdmon()->osdmap; int created = 0; for (map::iterator p = osdmap->pools.begin(); p != osdmap->pools.end(); ++p) { int64_t poolid = p->first; pg_pool_t &pool = p->second; int ruleno = osdmap->crush->find_rule(pool.get_crush_ruleset(), pool.get_type(), pool.get_size()); if (ruleno < 0 || !osdmap->crush->rule_exists(ruleno)) continue; if (pool.get_last_change() <= pg_map.last_pg_scan || pool.get_last_change() <= pending_inc.pg_scan) { dout(10) << " no change in pool " << p->first << " " << pool << dendl; continue; } dout(10) << "register_new_pgs scanning pool " << p->first << " " << pool << dendl; bool new_pool = pg_map.pg_pool_sum.count(poolid) == 0; // first pgs in this pool for (ps_t ps = 0; ps < pool.get_pg_num(); ps++) { pg_t pgid(ps, poolid, -1); if (pg_map.pg_stat.count(pgid)) { dout(20) << "register_new_pgs have " << pgid << dendl; continue; } created++; register_pg(pool, pgid, pool.get_last_change(), new_pool); } } int removed = 0; for (set::iterator p = pg_map.creating_pgs.begin(); p != pg_map.creating_pgs.end(); ++p) { if (p->preferred() >= 0) { dout(20) << " removing creating_pg " << *p << " because it is localized and obsolete" << dendl; pending_inc.pg_remove.insert(*p); removed++; } if (!osdmap->have_pg_pool(p->pool())) { dout(20) << " removing creating_pg " << *p << " because containing pool deleted" << dendl; pending_inc.pg_remove.insert(*p); ++removed; } } // deleted pools? for (ceph::unordered_map::const_iterator p = pg_map.pg_stat.begin(); p != pg_map.pg_stat.end(); ++p) { if (!osdmap->have_pg_pool(p->first.pool())) { dout(20) << " removing pg_stat " << p->first << " because " << "containing pool deleted" << dendl; pending_inc.pg_remove.insert(p->first); ++removed; } if (p->first.preferred() >= 0) { dout(20) << " removing localized pg " << p->first << dendl; pending_inc.pg_remove.insert(p->first); ++removed; } } dout(10) << "register_new_pgs registered " << created << " new pgs, removed " << removed << " uncreated pgs" << dendl; if (created || removed) { pending_inc.pg_scan = epoch; return true; } return false; } void PGMonitor::map_pg_creates() { OSDMap *osdmap = &mon->osdmon()->osdmap; if (osdmap->get_epoch() == last_map_pg_create_osd_epoch) { dout(10) << "map_pg_creates to " << pg_map.creating_pgs.size() << " pgs -- no change" << dendl; return; } dout(10) << "map_pg_creates to " << pg_map.creating_pgs.size() << " pgs osdmap epoch " << osdmap->get_epoch() << dendl; last_map_pg_create_osd_epoch = osdmap->get_epoch(); for (set::iterator p = pg_map.creating_pgs.begin(); p != pg_map.creating_pgs.end(); ++p) { pg_t pgid = *p; pg_t on = pgid; pg_stat_t& s = pg_map.pg_stat[pgid]; if (s.parent_split_bits) on = s.parent; vector up, acting; int up_primary, acting_primary; osdmap->pg_to_up_acting_osds( on, &up, &up_primary, &acting, &acting_primary); if (s.acting_primary != -1) { pg_map.creating_pgs_by_osd[s.acting_primary].erase(pgid); if (pg_map.creating_pgs_by_osd[s.acting_primary].size() == 0) pg_map.creating_pgs_by_osd.erase(s.acting_primary); } s.up = up; s.up_primary = up_primary; s.acting = acting; s.acting_primary = acting_primary; // don't send creates for localized pgs if (pgid.preferred() >= 0) continue; // don't send creates for splits if (s.parent_split_bits) continue; if (acting_primary != -1) { pg_map.creating_pgs_by_osd[acting_primary].insert(pgid); } else { dout(20) << "map_pg_creates " << pgid << " -> no osds in epoch " << mon->osdmon()->osdmap.get_epoch() << ", skipping" << dendl; continue; // blarney! } } for (map >::iterator p = pg_map.creating_pgs_by_osd.begin(); p != pg_map.creating_pgs_by_osd.end(); ++p) { dout(10) << "map_pg_creates osd." << p->first << " has " << p->second.size() << " pgs" << dendl; } } void PGMonitor::send_pg_creates() { dout(10) << "send_pg_creates to " << pg_map.creating_pgs.size() << " pgs" << dendl; utime_t now = ceph_clock_now(g_ceph_context); for (map >::iterator p = pg_map.creating_pgs_by_osd.begin(); p != pg_map.creating_pgs_by_osd.end(); ++p) { int osd = p->first; // throttle? if (last_sent_pg_create.count(osd) && now - g_conf->mon_pg_create_interval < last_sent_pg_create[osd]) continue; if (mon->osdmon()->osdmap.is_up(osd)) send_pg_creates(osd, NULL); } } void PGMonitor::send_pg_creates(int osd, Connection *con) { map >::iterator p = pg_map.creating_pgs_by_osd.find(osd); if (p == pg_map.creating_pgs_by_osd.end()) return; assert(p->second.size() > 0); dout(20) << "send_pg_creates osd." << osd << " pgs " << p->second << dendl; MOSDPGCreate *m = new MOSDPGCreate(mon->osdmon()->osdmap.get_epoch()); for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { m->mkpg[*q] = pg_create_t(pg_map.pg_stat[*q].created, pg_map.pg_stat[*q].parent, pg_map.pg_stat[*q].parent_split_bits); } if (con) { mon->messenger->send_message(m, con); } else { assert(mon->osdmon()->osdmap.is_up(osd)); mon->messenger->send_message(m, mon->osdmon()->osdmap.get_inst(osd)); } last_sent_pg_create[osd] = ceph_clock_now(g_ceph_context); } bool PGMonitor::check_down_pgs() { dout(10) << "check_down_pgs" << dendl; OSDMap *osdmap = &mon->osdmon()->osdmap; bool ret = false; for (ceph::unordered_map::iterator p = pg_map.pg_stat.begin(); p != pg_map.pg_stat.end(); ++p) { if ((p->second.state & PG_STATE_STALE) == 0 && p->second.acting_primary != -1 && osdmap->is_down(p->second.acting_primary)) { dout(10) << " marking pg " << p->first << " stale with acting " << p->second.acting << dendl; map::iterator q = pending_inc.pg_stat_updates.find(p->first); pg_stat_t *stat; if (q == pending_inc.pg_stat_updates.end()) { stat = &pending_inc.pg_stat_updates[p->first]; *stat = p->second; } else { stat = &q->second; } stat->state |= PG_STATE_STALE; stat->last_unstale = ceph_clock_now(g_ceph_context); ret = true; } } need_check_down_pgs = false; return ret; } inline string percentify(const float& a) { stringstream ss; if (a < 0.01) ss << "0"; else ss << std::fixed << std::setprecision(2) << a; return ss.str(); } //void PGMonitor::dump_object_stat_sum(stringstream& ss, Formatter *f, void PGMonitor::dump_object_stat_sum(TextTable &tbl, Formatter *f, object_stat_sum_t &sum, uint64_t avail, bool verbose) { if (f) { f->dump_int("kb_used", SHIFT_ROUND_UP(sum.num_bytes, 10)); f->dump_int("bytes_used", sum.num_bytes); f->dump_unsigned("max_avail", avail); f->dump_int("objects", sum.num_objects); if (verbose) { f->dump_int("dirty", sum.num_objects_dirty); f->dump_int("rd", sum.num_rd); f->dump_int("rd_kb", sum.num_rd_kb); f->dump_int("wr", sum.num_wr); f->dump_int("wr_kb", sum.num_wr_kb); } } else { tbl << stringify(si_t(sum.num_bytes)); int64_t kb_used = SHIFT_ROUND_UP(sum.num_bytes, 10); float used = 0.0; if (pg_map.osd_sum.kb > 0) used = (float)kb_used / pg_map.osd_sum.kb; tbl << percentify(used*100); tbl << si_t(avail); tbl << sum.num_objects; if (verbose) { tbl << stringify(si_t(sum.num_objects_dirty)) << stringify(si_t(sum.num_rd)) << stringify(si_t(sum.num_wr)); } } } int64_t PGMonitor::get_rule_avail(OSDMap& osdmap, int ruleno) { map wm; int r = osdmap.crush->get_rule_weight_osd_map(ruleno, &wm); if (r < 0) return r; if(wm.size() == 0) return 0; int64_t min = -1; for (map::iterator p = wm.begin(); p != wm.end(); ++p) { if (pg_map.osd_stat[p->first].kb == 0) { // osd must be out, hence its stats have been zeroed // (unless we somehow managed to have a disk with size 0...) continue; } int64_t proj = (float)(pg_map.osd_stat[p->first].kb_avail * 1024ull) / (double)p->second; if (min < 0 || proj < min) min = proj; } return min; } void PGMonitor::dump_pool_stats(stringstream &ss, Formatter *f, bool verbose) { TextTable tbl; if (f) { f->open_array_section("pools"); } else { tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT); tbl.define_column("ID", TextTable::LEFT, TextTable::LEFT); if (verbose) tbl.define_column("CATEGORY", TextTable::LEFT, TextTable::LEFT); tbl.define_column("USED", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("%USED", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("MAX AVAIL", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("OBJECTS", TextTable::LEFT, TextTable::RIGHT); if (verbose) { tbl.define_column("DIRTY", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("READ", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("WRITE", TextTable::LEFT, TextTable::RIGHT); } } map avail_by_rule; OSDMap &osdmap = mon->osdmon()->osdmap; for (map::const_iterator p = osdmap.get_pools().begin(); p != osdmap.get_pools().end(); ++p) { int64_t pool_id = p->first; if ((pool_id < 0) || (pg_map.pg_pool_sum.count(pool_id) == 0)) continue; string pool_name = osdmap.get_pool_name(pool_id); pool_stat_t &stat = pg_map.pg_pool_sum[pool_id]; const pg_pool_t *pool = osdmap.get_pg_pool(pool_id); int ruleno = osdmap.crush->find_rule(pool->get_crush_ruleset(), pool->get_type(), pool->get_size()); int64_t avail; if (avail_by_rule.count(ruleno) == 0) { avail = get_rule_avail(osdmap, ruleno); if (avail < 0) avail = 0; avail_by_rule[ruleno] = avail; } else { avail = avail_by_rule[ruleno]; } switch (pool->get_type()) { case pg_pool_t::TYPE_REPLICATED: avail /= pool->get_size(); break; case pg_pool_t::TYPE_ERASURE: { const map& ecp = osdmap.get_erasure_code_profile(pool->erasure_code_profile); map::const_iterator pm = ecp.find("m"); map::const_iterator pk = ecp.find("k"); if (pm != ecp.end() && pk != ecp.end()) { int k = atoi(pk->second.c_str()); int m = atoi(pm->second.c_str()); avail = avail * k / (m + k); } } break; default: assert(0 == "unrecognized pool type"); } if (f) { f->open_object_section("pool"); f->dump_string("name", pool_name); f->dump_int("id", pool_id); f->open_object_section("stats"); } else { tbl << pool_name << pool_id; if (verbose) tbl << "-"; } dump_object_stat_sum(tbl, f, stat.stats.sum, avail, verbose); if (f) f->close_section(); // stats else tbl << TextTable::endrow; if (verbose) { if (f) f->open_array_section("categories"); for (map::iterator it = stat.stats.cat_sum.begin(); it != stat.stats.cat_sum.end(); ++it) { if (f) { f->open_object_section(it->first.c_str()); } else { tbl << "" << "" << it->first; } dump_object_stat_sum(tbl, f, it->second, avail, verbose); if (f) f->close_section(); // category name else tbl << TextTable::endrow; } if (f) f->close_section(); // categories } if (f) f->close_section(); // pool } if (f) f->close_section(); else { ss << "POOLS:\n"; tbl.set_indent(4); ss << tbl; } } void PGMonitor::dump_fs_stats(stringstream &ss, Formatter *f, bool verbose) { if (f) { f->open_object_section("stats"); f->dump_int("total_space", pg_map.osd_sum.kb); f->dump_int("total_used", pg_map.osd_sum.kb_used); f->dump_int("total_avail", pg_map.osd_sum.kb_avail); if (verbose) { f->dump_int("total_objects", pg_map.pg_sum.stats.sum.num_objects); } f->close_section(); } else { TextTable tbl; tbl.define_column("SIZE", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("AVAIL", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("RAW USED", TextTable::LEFT, TextTable::RIGHT); tbl.define_column("%RAW USED", TextTable::LEFT, TextTable::RIGHT); if (verbose) { tbl.define_column("OBJECTS", TextTable::LEFT, TextTable::RIGHT); } tbl << stringify(si_t(pg_map.osd_sum.kb*1024)) << stringify(si_t(pg_map.osd_sum.kb_avail*1024)) << stringify(si_t(pg_map.osd_sum.kb_used*1024)); float used = 0.0; if (pg_map.osd_sum.kb > 0) { used = ((float)pg_map.osd_sum.kb_used / pg_map.osd_sum.kb); } tbl << percentify(used*100); if (verbose) { tbl << stringify(si_t(pg_map.pg_sum.stats.sum.num_objects)); } tbl << TextTable::endrow; ss << "GLOBAL:\n"; tbl.set_indent(4); ss << tbl; } } void PGMonitor::dump_info(Formatter *f) { f->open_object_section("pgmap"); pg_map.dump(f); f->close_section(); f->dump_unsigned("pgmap_first_committed", get_first_committed()); f->dump_unsigned("pgmap_last_committed", get_last_committed()); } bool PGMonitor::preprocess_command(MMonCommand *m) { int r = -1; bufferlist rdata; stringstream ss, ds; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, rdata, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", rdata, get_last_committed()); return true; } // perhaps these would be better in the parsing, but it's weird if (prefix == "pg dump_json") { vector v; v.push_back(string("all")); cmd_putval(g_ceph_context, cmdmap, "format", string("json")); cmd_putval(g_ceph_context, cmdmap, "dumpcontents", v); prefix = "pg dump"; } else if (prefix == "pg dump_pools_json") { vector v; v.push_back(string("pools")); cmd_putval(g_ceph_context, cmdmap, "format", string("json")); cmd_putval(g_ceph_context, cmdmap, "dumpcontents", v); prefix = "pg dump"; } string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); boost::scoped_ptr f(new_formatter(format)); if (prefix == "pg stat") { if (f) { f->open_object_section("pg_map"); pg_map.dump(f.get()); f->close_section(); f->flush(ds); } else { ds << pg_map; } r = 0; } else if (prefix == "pg getmap") { pg_map.encode(rdata); ss << "got pgmap version " << pg_map.version; r = 0; } else if (prefix == "pg map_pg_creates") { map_pg_creates(); ss << "mapped pg creates "; r = 0; } else if (prefix == "pg send_pg_creates") { send_pg_creates(); ss << "sent pg creates "; r = 0; } else if (prefix == "pg dump") { string val; vector dumpcontents; set what; if (cmd_getval(g_ceph_context, cmdmap, "dumpcontents", dumpcontents)) { copy(dumpcontents.begin(), dumpcontents.end(), inserter(what, what.end())); } if (what.empty()) what.insert("all"); if (f) { vector dumpcontents; if (cmd_getval(g_ceph_context, cmdmap, "dumpcontents", dumpcontents)) { copy(dumpcontents.begin(), dumpcontents.end(), inserter(what, what.end())); } if (what.count("all")) { f->open_object_section("pg_map"); pg_map.dump(f.get()); f->close_section(); } else if (what.count("summary") || what.count("sum")) { f->open_object_section("pg_map"); pg_map.dump_basic(f.get()); f->close_section(); } else { if (what.count("pools")) { pg_map.dump_pool_stats(f.get()); } if (what.count("osds")) { pg_map.dump_osd_stats(f.get()); } if (what.count("pgs")) { pg_map.dump_pg_stats(f.get(), false); } if (what.count("pgs_brief")) { pg_map.dump_pg_stats(f.get(), true); } if (what.count("delta")) { f->open_object_section("delta"); pg_map.dump_delta(f.get()); f->close_section(); } } f->flush(ds); } else { // plain format ignores dumpcontents pg_map.dump(ds); } ss << "dumped " << what << " in format " << format; r = 0; } else if (prefix == "pg dump_stuck") { vector stuckop_vec; cmd_getval(g_ceph_context, cmdmap, "stuckops", stuckop_vec); if (stuckop_vec.empty()) stuckop_vec.push_back("unclean"); int64_t threshold; cmd_getval(g_ceph_context, cmdmap, "threshold", threshold, int64_t(g_conf->mon_pg_stuck_threshold)); r = dump_stuck_pg_stats(ds, f.get(), (int)threshold, stuckop_vec); ss << "ok"; r = 0; } else if (prefix == "pg map") { pg_t pgid; string pgidstr; cmd_getval(g_ceph_context, cmdmap, "pgid", pgidstr); if (!pgid.parse(pgidstr.c_str())) { ss << "invalid pgid '" << pgidstr << "'"; r = -EINVAL; goto reply; } vector up, acting; if (!mon->osdmon()->osdmap.have_pg_pool(pgid.pool())) { r = -ENOENT; ss << "pg '" << pgidstr << "' does not exist"; goto reply; } pg_t mpgid = mon->osdmon()->osdmap.raw_pg_to_pg(pgid); mon->osdmon()->osdmap.pg_to_up_acting_osds(pgid, up, acting); if (f) { f->open_object_section("pg_map"); f->dump_stream("epoch") << mon->osdmon()->osdmap.get_epoch(); f->dump_stream("raw_pgid") << pgid; f->dump_stream("pgid") << mpgid; f->open_array_section("up"); for (vector::iterator it = up.begin(); it != up.end(); ++it) f->dump_int("up_osd", *it); f->close_section(); f->open_array_section("acting"); for (vector::iterator it = acting.begin(); it != acting.end(); ++it) f->dump_int("acting_osd", *it); f->close_section(); f->close_section(); f->flush(ds); } else { ds << "osdmap e" << mon->osdmon()->osdmap.get_epoch() << " pg " << pgid << " (" << mpgid << ")" << " -> up " << up << " acting " << acting; } r = 0; } else if (prefix == "pg scrub" || prefix == "pg repair" || prefix == "pg deep-scrub") { string scrubop = prefix.substr(3, string::npos); pg_t pgid; string pgidstr; cmd_getval(g_ceph_context, cmdmap, "pgid", pgidstr); if (!pgid.parse(pgidstr.c_str())) { ss << "invalid pgid '" << pgidstr << "'"; r = -EINVAL; goto reply; } if (!pg_map.pg_stat.count(pgid)) { ss << "pg " << pgid << " dne"; r = -ENOENT; goto reply; } if (pg_map.pg_stat[pgid].acting_primary == -1) { ss << "pg " << pgid << " has no primary osd"; r = -EAGAIN; goto reply; } int osd = pg_map.pg_stat[pgid].acting_primary; if (!mon->osdmon()->osdmap.is_up(osd)) { ss << "pg " << pgid << " primary osd." << osd << " not up"; r = -EAGAIN; goto reply; } vector pgs(1); pgs[0] = pgid; mon->try_send_message(new MOSDScrub(mon->monmap->fsid, pgs, scrubop == "repair", scrubop == "deep-scrub"), mon->osdmon()->osdmap.get_inst(osd)); ss << "instructing pg " << pgid << " on osd." << osd << " to " << scrubop; r = 0; } else if (prefix == "pg debug") { string debugop; cmd_getval(g_ceph_context, cmdmap, "debugop", debugop, string("unfound_objects_exist")); if (debugop == "unfound_objects_exist") { bool unfound_objects_exist = false; ceph::unordered_map::const_iterator end = pg_map.pg_stat.end(); for (ceph::unordered_map::const_iterator s = pg_map.pg_stat.begin(); s != end; ++s) { if (s->second.stats.sum.num_objects_unfound > 0) { unfound_objects_exist = true; break; } } if (unfound_objects_exist) ds << "TRUE"; else ds << "FALSE"; r = 0; } else if (debugop == "degraded_pgs_exist") { bool degraded_pgs_exist = false; ceph::unordered_map::const_iterator end = pg_map.pg_stat.end(); for (ceph::unordered_map::const_iterator s = pg_map.pg_stat.begin(); s != end; ++s) { if (s->second.stats.sum.num_objects_degraded > 0) { degraded_pgs_exist = true; break; } } if (degraded_pgs_exist) ds << "TRUE"; else ds << "FALSE"; r = 0; } } if (r == -1) return false; reply: string rs; getline(ss, rs); rdata.append(ds); mon->reply_command(m, r, rs, rdata, get_last_committed()); return true; } bool PGMonitor::prepare_command(MMonCommand *m) { stringstream ss; pg_t pgid; epoch_t epoch = mon->osdmon()->osdmap.get_epoch(); int r = 0; string rs; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { // ss has reason for failure string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", get_last_committed()); return true; } if (prefix == "pg force_create_pg") { string pgidstr; cmd_getval(g_ceph_context, cmdmap, "pgid", pgidstr); if (!pgid.parse(pgidstr.c_str())) { ss << "pg " << pgidstr << " invalid"; r = -EINVAL; goto reply; } if (!pg_map.pg_stat.count(pgid)) { ss << "pg " << pgid << " dne"; r = -ENOENT; goto reply; } if (pg_map.creating_pgs.count(pgid)) { ss << "pg " << pgid << " already creating"; r = 0; goto reply; } { pg_stat_t& s = pending_inc.pg_stat_updates[pgid]; s.state = PG_STATE_CREATING; s.created = epoch; s.last_change = ceph_clock_now(g_ceph_context); } ss << "pg " << pgidstr << " now creating, ok"; goto update; } else if (prefix == "pg set_full_ratio" || prefix == "pg set_nearfull_ratio") { double n; if (!cmd_getval(g_ceph_context, cmdmap, "ratio", n)) { ss << "unable to parse 'ratio' value '" << cmd_vartype_stringify(cmdmap["who"]) << "'"; r = -EINVAL; goto reply; } string op = prefix.substr(3, string::npos); if (op == "set_full_ratio") pending_inc.full_ratio = n; else if (op == "set_nearfull_ratio") pending_inc.nearfull_ratio = n; goto update; } else { r = -EINVAL; goto reply; } reply: getline(ss, rs); if (r < 0 && rs.length() == 0) rs = cpp_strerror(r); mon->reply_command(m, r, rs, get_last_committed()); return false; update: getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, r, rs, get_last_committed() + 1)); return true; } static void note_stuck_detail(enum PGMap::StuckPG what, ceph::unordered_map& stuck_pgs, list > *detail) { for (ceph::unordered_map::iterator p = stuck_pgs.begin(); p != stuck_pgs.end(); ++p) { ostringstream ss; utime_t since; const char *whatname = 0; switch (what) { case PGMap::STUCK_INACTIVE: since = p->second.last_active; whatname = "inactive"; break; case PGMap::STUCK_UNCLEAN: since = p->second.last_clean; whatname = "unclean"; break; case PGMap::STUCK_STALE: since = p->second.last_unstale; whatname = "stale"; break; default: assert(0); } ss << "pg " << p->first << " is stuck " << whatname; if (since == utime_t()) { ss << " since forever"; }else { utime_t dur = ceph_clock_now(g_ceph_context) - since; ss << " for " << dur; } ss << ", current state " << pg_state_string(p->second.state) << ", last acting " << p->second.acting; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } int PGMonitor::_warn_slow_request_histogram(const pow2_hist_t& h, string suffix, list >& summary, list > *detail) const { unsigned sum = 0; for (unsigned i = h.h.size() - 1; i > 0; --i) { float ub = (float)(1 << i) / 1000.0; if (ub < g_conf->mon_osd_max_op_age) break; ostringstream ss; if (h.h[i]) { ss << h.h[i] << " ops are blocked > " << ub << " sec" << suffix; if (detail) detail->push_back(make_pair(HEALTH_WARN, ss.str())); sum += h.h[i]; } } return sum; } void PGMonitor::get_health(list >& summary, list > *detail) const { map note; ceph::unordered_map::const_iterator p = pg_map.num_pg_by_state.begin(); ceph::unordered_map::const_iterator p_end = pg_map.num_pg_by_state.end(); for (; p != p_end; ++p) { if (p->first & PG_STATE_STALE) note["stale"] += p->second; if (p->first & PG_STATE_DOWN) note["down"] += p->second; if (p->first & PG_STATE_DEGRADED) note["degraded"] += p->second; if (p->first & PG_STATE_INCONSISTENT) note["inconsistent"] += p->second; if (p->first & PG_STATE_PEERING) note["peering"] += p->second; if (p->first & PG_STATE_REPAIR) note["repair"] += p->second; if (p->first & PG_STATE_SPLITTING) note["splitting"] += p->second; if (p->first & PG_STATE_RECOVERING) note["recovering"] += p->second; if (p->first & PG_STATE_RECOVERY_WAIT) note["recovery_wait"] += p->second; if (p->first & PG_STATE_INCOMPLETE) note["incomplete"] += p->second; if (p->first & PG_STATE_BACKFILL_WAIT) note["backfill"] += p->second; if (p->first & PG_STATE_BACKFILL) note["backfilling"] += p->second; if (p->first & PG_STATE_BACKFILL_TOOFULL) note["backfill_toofull"] += p->second; } ceph::unordered_map stuck_pgs; utime_t now(ceph_clock_now(g_ceph_context)); utime_t cutoff = now - utime_t(g_conf->mon_pg_stuck_threshold, 0); pg_map.get_stuck_stats(PGMap::STUCK_INACTIVE, cutoff, stuck_pgs); if (!stuck_pgs.empty()) { note["stuck inactive"] = stuck_pgs.size(); if (detail) note_stuck_detail(PGMap::STUCK_INACTIVE, stuck_pgs, detail); } stuck_pgs.clear(); pg_map.get_stuck_stats(PGMap::STUCK_UNCLEAN, cutoff, stuck_pgs); if (!stuck_pgs.empty()) { note["stuck unclean"] = stuck_pgs.size(); if (detail) note_stuck_detail(PGMap::STUCK_UNCLEAN, stuck_pgs, detail); } stuck_pgs.clear(); pg_map.get_stuck_stats(PGMap::STUCK_STALE, cutoff, stuck_pgs); if (!stuck_pgs.empty()) { note["stuck stale"] = stuck_pgs.size(); if (detail) note_stuck_detail(PGMap::STUCK_STALE, stuck_pgs, detail); } if (!note.empty()) { for (map::iterator p = note.begin(); p != note.end(); ++p) { ostringstream ss; ss << p->second << " pgs " << p->first; summary.push_back(make_pair(HEALTH_WARN, ss.str())); } if (detail) { for (ceph::unordered_map::const_iterator p = pg_map.pg_stat.begin(); p != pg_map.pg_stat.end(); ++p) { if ((p->second.state & (PG_STATE_STALE | PG_STATE_DOWN | PG_STATE_DEGRADED | PG_STATE_INCONSISTENT | PG_STATE_PEERING | PG_STATE_REPAIR | PG_STATE_SPLITTING | PG_STATE_RECOVERING | PG_STATE_RECOVERY_WAIT | PG_STATE_INCOMPLETE | PG_STATE_BACKFILL_WAIT | PG_STATE_BACKFILL | PG_STATE_BACKFILL_TOOFULL)) && stuck_pgs.count(p->first) == 0) { ostringstream ss; ss << "pg " << p->first << " is " << pg_state_string(p->second.state); ss << ", acting " << p->second.acting; if (p->second.stats.sum.num_objects_unfound) ss << ", " << p->second.stats.sum.num_objects_unfound << " unfound"; if (p->second.state & PG_STATE_INCOMPLETE) { const pg_pool_t *pi = mon->osdmon()->osdmap.get_pg_pool(p->first.pool()); if (pi && pi->min_size > 1) { ss << " (reducing pool " << mon->osdmon()->osdmap.get_pool_name(p->first.pool()) << " min_size from " << (int)pi->min_size << " may help; search ceph.com/docs for 'incomplete')"; } } detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } } // slow requests if (g_conf->mon_osd_max_op_age > 0 && pg_map.osd_sum.op_queue_age_hist.upper_bound() > g_conf->mon_osd_max_op_age) { unsigned sum = _warn_slow_request_histogram(pg_map.osd_sum.op_queue_age_hist, "", summary, detail); if (sum > 0) { ostringstream ss; ss << sum << " requests are blocked > " << g_conf->mon_osd_max_op_age << " sec"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) { unsigned num_slow_osds = 0; // do per-osd warnings for (ceph::unordered_map::const_iterator p = pg_map.osd_stat.begin(); p != pg_map.osd_stat.end(); ++p) { if (_warn_slow_request_histogram(p->second.op_queue_age_hist, string(" on osd.") + stringify(p->first), summary, detail)) ++num_slow_osds; } ostringstream ss2; ss2 << num_slow_osds << " osds have slow requests"; summary.push_back(make_pair(HEALTH_WARN, ss2.str())); detail->push_back(make_pair(HEALTH_WARN, ss2.str())); } } } // recovery stringstream rss; pg_map.overall_recovery_summary(NULL, &rss); if (!rss.str().empty()) { summary.push_back(make_pair(HEALTH_WARN, "recovery " + rss.str())); if (detail) detail->push_back(make_pair(HEALTH_WARN, "recovery " + rss.str())); } // full/nearfull check_full_osd_health(summary, detail, pg_map.full_osds, "full", HEALTH_ERR); check_full_osd_health(summary, detail, pg_map.nearfull_osds, "near full", HEALTH_WARN); // near-target max pools const map& pools = mon->osdmon()->osdmap.get_pools(); for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { if ((!p->second.target_max_objects && !p->second.target_max_bytes) || !pg_map.pg_pool_sum.count(p->first)) continue; bool nearfull = false; const char *name = mon->osdmon()->osdmap.get_pool_name(p->first); const pool_stat_t& st = pg_map.get_pg_pool_sum_stat(p->first); uint64_t ratio = p->second.cache_target_full_ratio_micro + ((1000000 - p->second.cache_target_full_ratio_micro) * g_conf->mon_cache_target_full_warn_ratio); if (p->second.target_max_objects && (uint64_t)st.stats.sum.num_objects > p->second.target_max_objects * (ratio / 1000000.0)) { nearfull = true; if (detail) { ostringstream ss; ss << "cache pool '" << name << "' with " << si_t(st.stats.sum.num_objects) << " objects at/near target max " << si_t(p->second.target_max_objects) << " objects"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } if (p->second.target_max_bytes && (uint64_t)st.stats.sum.num_bytes > p->second.target_max_bytes * (ratio / 1000000.0)) { nearfull = true; if (detail) { ostringstream ss; ss << "cache pool '" << mon->osdmon()->osdmap.get_pool_name(p->first) << "' with " << si_t(st.stats.sum.num_bytes) << "B at/near target max " << si_t(p->second.target_max_bytes) << "B"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } if (nearfull) { ostringstream ss; ss << "'" << name << "' at/near target max"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); } } // scrub if (pg_map.pg_sum.stats.sum.num_scrub_errors) { ostringstream ss; ss << pg_map.pg_sum.stats.sum.num_scrub_errors << " scrub errors"; summary.push_back(make_pair(HEALTH_ERR, ss.str())); if (detail) { detail->push_back(make_pair(HEALTH_ERR, ss.str())); } } // pg skew int num_in = mon->osdmon()->osdmap.get_num_in_osds(); if (num_in && g_conf->mon_pg_warn_min_per_osd > 0) { int per = pg_map.pg_stat.size() / num_in; if (per < g_conf->mon_pg_warn_min_per_osd) { ostringstream ss; ss << "too few pgs per osd (" << per << " < min " << g_conf->mon_pg_warn_min_per_osd << ")"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } if (!pg_map.pg_stat.empty()) { for (ceph::unordered_map::const_iterator p = pg_map.pg_pool_sum.begin(); p != pg_map.pg_pool_sum.end(); ++p) { const pg_pool_t *pi = mon->osdmon()->osdmap.get_pg_pool(p->first); if (!pi) continue; // in case osdmap changes haven't propagated to PGMap yet if (pi->get_pg_num() > pi->get_pgp_num()) { ostringstream ss; ss << "pool " << mon->osdmon()->osdmap.get_pool_name(p->first) << " pg_num " << pi->get_pg_num() << " > pgp_num " << pi->get_pgp_num(); summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) detail->push_back(make_pair(HEALTH_WARN, ss.str())); } int average_objects_per_pg = pg_map.pg_sum.stats.sum.num_objects / pg_map.pg_stat.size(); if (average_objects_per_pg > 0 && pg_map.pg_sum.stats.sum.num_objects >= g_conf->mon_pg_warn_min_objects && p->second.stats.sum.num_objects >= g_conf->mon_pg_warn_min_pool_objects) { int objects_per_pg = p->second.stats.sum.num_objects / pi->get_pg_num(); float ratio = (float)objects_per_pg / (float)average_objects_per_pg; if (g_conf->mon_pg_warn_max_object_skew > 0 && ratio > g_conf->mon_pg_warn_max_object_skew) { ostringstream ss; ss << "pool " << mon->osdmon()->osdmap.get_pool_name(p->first) << " has too few pgs"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) { ostringstream ss; ss << "pool " << mon->osdmon()->osdmap.get_pool_name(p->first) << " objects per pg (" << objects_per_pg << ") is more than " << ratio << " times cluster average (" << average_objects_per_pg << ")"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } } } } void PGMonitor::check_full_osd_health(list >& summary, list > *detail, const set& s, const char *desc, health_status_t sev) const { if (!s.empty()) { ostringstream ss; ss << s.size() << " " << desc << " osd(s)"; summary.push_back(make_pair(sev, ss.str())); if (detail) { for (set::const_iterator p = s.begin(); p != s.end(); ++p) { ostringstream ss; const osd_stat_t& os = pg_map.osd_stat.find(*p)->second; int ratio = (int)(((float)os.kb_used) / (float) os.kb * 100.0); ss << "osd." << *p << " is " << desc << " at " << ratio << "%"; detail->push_back(make_pair(sev, ss.str())); } } } } int PGMonitor::dump_stuck_pg_stats(stringstream &ds, Formatter *f, int threshold, vector& args) const { PGMap::StuckPG stuck_type; string type = args[0]; if (type == "inactive") stuck_type = PGMap::STUCK_INACTIVE; else if (type == "unclean") stuck_type = PGMap::STUCK_UNCLEAN; else if (type == "stale") stuck_type = PGMap::STUCK_STALE; else { ds << "Unknown type: " << type << std::endl; return 0; } utime_t now(ceph_clock_now(g_ceph_context)); utime_t cutoff = now - utime_t(threshold, 0); if (!f) { pg_map.dump_stuck_plain(ds, stuck_type, cutoff); } else { pg_map.dump_stuck(f, stuck_type, cutoff); f->flush(ds); } return 0; } void PGMonitor::check_sub(Subscription *sub) { if (sub->type == "osd_pg_creates") { send_pg_creates(sub->session->inst.name.num(), sub->session->con.get()); } } ceph-0.80.11/src/mon/PGMap.cc0000664000175100017510000011236212623076744017535 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "PGMap.h" #define dout_subsys ceph_subsys_mon #include "common/debug.h" #include "common/TextTable.h" #include "include/stringify.h" #include "common/Formatter.h" #include "include/ceph_features.h" #include "mon/MonitorDBStore.h" // -- void PGMap::Incremental::encode(bufferlist &bl, uint64_t features) const { if ((features & CEPH_FEATURE_MONENC) == 0) { __u8 v = 4; ::encode(v, bl); ::encode(version, bl); ::encode(pg_stat_updates, bl); ::encode(osd_stat_updates, bl); ::encode(osd_stat_rm, bl); ::encode(osdmap_epoch, bl); ::encode(pg_scan, bl); ::encode(full_ratio, bl); ::encode(nearfull_ratio, bl); ::encode(pg_remove, bl); return; } ENCODE_START(7, 5, bl); ::encode(version, bl); ::encode(pg_stat_updates, bl); ::encode(osd_stat_updates, bl); ::encode(osd_stat_rm, bl); ::encode(osdmap_epoch, bl); ::encode(pg_scan, bl); ::encode(full_ratio, bl); ::encode(nearfull_ratio, bl); ::encode(pg_remove, bl); ::encode(stamp, bl); ::encode(osd_epochs, bl); ENCODE_FINISH(bl); } void PGMap::Incremental::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(7, 5, 5, bl); ::decode(version, bl); if (struct_v < 3) { pg_stat_updates.clear(); __u32 n; ::decode(n, bl); while (n--) { old_pg_t opgid; ::decode(opgid, bl); pg_t pgid = opgid; ::decode(pg_stat_updates[pgid], bl); } } else { ::decode(pg_stat_updates, bl); } ::decode(osd_stat_updates, bl); ::decode(osd_stat_rm, bl); ::decode(osdmap_epoch, bl); ::decode(pg_scan, bl); if (struct_v >= 2) { ::decode(full_ratio, bl); ::decode(nearfull_ratio, bl); } if (struct_v < 3) { pg_remove.clear(); __u32 n; ::decode(n, bl); while (n--) { old_pg_t opgid; ::decode(opgid, bl); pg_remove.insert(pg_t(opgid)); } } else { ::decode(pg_remove, bl); } if (struct_v < 4 && full_ratio == 0) { full_ratio = -1; } if (struct_v < 4 && nearfull_ratio == 0) { nearfull_ratio = -1; } if (struct_v >= 6) ::decode(stamp, bl); if (struct_v >= 7) { ::decode(osd_epochs, bl); } else { for (map::iterator i = osd_stat_updates.begin(); i != osd_stat_updates.end(); ++i) { // This isn't accurate, but will cause trimming to behave like // previously. osd_epochs.insert(make_pair(i->first, osdmap_epoch)); } } DECODE_FINISH(bl); } void PGMap::Incremental::dump(Formatter *f) const { f->dump_unsigned("version", version); f->dump_stream("stamp") << stamp; f->dump_unsigned("osdmap_epoch", osdmap_epoch); f->dump_unsigned("pg_scan_epoch", pg_scan); f->dump_float("full_ratio", full_ratio); f->dump_float("nearfull_ratio", nearfull_ratio); f->open_array_section("pg_stat_updates"); for (map::const_iterator p = pg_stat_updates.begin(); p != pg_stat_updates.end(); ++p) { f->open_object_section("pg_stat"); f->dump_stream("pgid") << p->first; p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("osd_stat_updates"); for (map::const_iterator p = osd_stat_updates.begin(); p != osd_stat_updates.end(); ++p) { f->open_object_section("osd_stat"); f->dump_int("osd", p->first); p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("osd_stat_removals"); for (set::const_iterator p = osd_stat_rm.begin(); p != osd_stat_rm.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->open_array_section("pg_removals"); for (set::const_iterator p = pg_remove.begin(); p != pg_remove.end(); ++p) f->dump_stream("pgid") << *p; f->close_section(); } void PGMap::Incremental::generate_test_instances(list& o) { o.push_back(new Incremental); o.push_back(new Incremental); o.back()->version = 1; o.back()->stamp = utime_t(123,345); o.push_back(new Incremental); o.back()->version = 2; o.back()->pg_stat_updates[pg_t(1,2,3)] = pg_stat_t(); o.back()->osd_stat_updates[5] = osd_stat_t(); o.back()->osd_epochs[5] = 12; o.push_back(new Incremental); o.back()->version = 3; o.back()->osdmap_epoch = 1; o.back()->pg_scan = 2; o.back()->full_ratio = .2; o.back()->nearfull_ratio = .3; o.back()->pg_stat_updates[pg_t(4,5,6)] = pg_stat_t(); o.back()->osd_stat_updates[6] = osd_stat_t(); o.back()->osd_epochs[6] = 12; o.back()->pg_remove.insert(pg_t(1,2,3)); o.back()->osd_stat_rm.insert(5); } // -- void PGMap::apply_incremental(CephContext *cct, const Incremental& inc) { assert(inc.version == version+1); version++; utime_t delta_t; delta_t = inc.stamp; delta_t -= stamp; stamp = inc.stamp; pool_stat_t pg_sum_old = pg_sum; ceph::unordered_map pg_pool_sum_old; bool ratios_changed = false; if (inc.full_ratio != full_ratio && inc.full_ratio != -1) { full_ratio = inc.full_ratio; ratios_changed = true; } if (inc.nearfull_ratio != nearfull_ratio && inc.nearfull_ratio != -1) { nearfull_ratio = inc.nearfull_ratio; ratios_changed = true; } if (ratios_changed) redo_full_sets(); for (map::const_iterator p = inc.pg_stat_updates.begin(); p != inc.pg_stat_updates.end(); ++p) { const pg_t &update_pg(p->first); const pg_stat_t &update_stat(p->second); if (pg_pool_sum_old.count(update_pg.pool()) == 0) pg_pool_sum_old[update_pg.pool()] = pg_pool_sum[update_pg.pool()]; ceph::unordered_map::iterator t = pg_stat.find(update_pg); if (t == pg_stat.end()) { ceph::unordered_map::value_type v(update_pg, update_stat); pg_stat.insert(v); // did we affect the min? if (min_last_epoch_clean && update_stat.get_effective_last_epoch_clean() < min_last_epoch_clean) min_last_epoch_clean = 0; } else { // did we (or might we) affect the min? epoch_t lec = update_stat.get_effective_last_epoch_clean(); if (min_last_epoch_clean && (lec < min_last_epoch_clean || // we did (lec > min_last_epoch_clean && // we might t->second.get_effective_last_epoch_clean() == min_last_epoch_clean) )) min_last_epoch_clean = 0; stat_pg_sub(update_pg, t->second); t->second = update_stat; } stat_pg_add(update_pg, update_stat); } assert(osd_stat.size() == osd_epochs.size()); for (map::const_iterator p = inc.get_osd_stat_updates().begin(); p != inc.get_osd_stat_updates().end(); ++p) { int osd = p->first; const osd_stat_t &new_stats(p->second); ceph::unordered_map::iterator t = osd_stat.find(osd); if (t == osd_stat.end()) { ceph::unordered_map::value_type v(osd, new_stats); osd_stat.insert(v); } else { stat_osd_sub(t->second); t->second = new_stats; } ceph::unordered_map::iterator i = osd_epochs.find(osd); map::const_iterator j = inc.get_osd_epochs().find(osd); assert(j != inc.get_osd_epochs().end()); // will we potentially affect the min? if (min_last_epoch_clean && (i == osd_epochs.end() || j->second < min_last_epoch_clean || (j->second > min_last_epoch_clean && i->second == min_last_epoch_clean))) min_last_epoch_clean = 0; if (i == osd_epochs.end()) osd_epochs.insert(*j); else i->second = j->second; stat_osd_add(new_stats); // adjust [near]full status register_nearfull_status(osd, new_stats); } set deleted_pools; for (set::const_iterator p = inc.pg_remove.begin(); p != inc.pg_remove.end(); ++p) { const pg_t &removed_pg(*p); ceph::unordered_map::iterator s = pg_stat.find(removed_pg); if (s != pg_stat.end()) { stat_pg_sub(removed_pg, s->second); pg_stat.erase(s); } if (removed_pg.ps() == 0) deleted_pools.insert(removed_pg.pool()); } for (set::iterator p = deleted_pools.begin(); p != deleted_pools.end(); ++p) { dout(20) << " deleted pool " << *p << dendl; deleted_pool(*p); } for (set::iterator p = inc.get_osd_stat_rm().begin(); p != inc.get_osd_stat_rm().end(); ++p) { ceph::unordered_map::iterator t = osd_stat.find(*p); if (t != osd_stat.end()) { stat_osd_sub(t->second); osd_stat.erase(t); } // remove these old osds from full/nearfull set(s), too nearfull_osds.erase(*p); full_osds.erase(*p); } // calculate a delta, and average over the last 2 deltas. pool_stat_t d = pg_sum; d.stats.sub(pg_sum_old.stats); pg_sum_deltas.push_back(make_pair(d, delta_t)); stamp_delta += delta_t; pg_sum_delta.stats.add(d.stats); if (pg_sum_deltas.size() > (std::list< pair >::size_type)MAX(1, cct ? cct->_conf->mon_stat_smooth_intervals : 1)) { pg_sum_delta.stats.sub(pg_sum_deltas.front().first.stats); stamp_delta -= pg_sum_deltas.front().second; pg_sum_deltas.pop_front(); } update_pool_deltas(cct, inc.stamp, pg_pool_sum_old); if (inc.osdmap_epoch) last_osdmap_epoch = inc.osdmap_epoch; if (inc.pg_scan) last_pg_scan = inc.pg_scan; min_last_epoch_clean = 0; // invalidate } void PGMap::redo_full_sets() { full_osds.clear(); nearfull_osds.clear(); for (ceph::unordered_map::iterator i = osd_stat.begin(); i != osd_stat.end(); ++i) { register_nearfull_status(i->first, i->second); } } void PGMap::register_nearfull_status(int osd, const osd_stat_t& s) { float ratio = ((float)s.kb_used) / ((float)s.kb); if (full_ratio > 0 && ratio > full_ratio) { // full full_osds.insert(osd); nearfull_osds.erase(osd); } else if (nearfull_ratio > 0 && ratio > nearfull_ratio) { // nearfull full_osds.erase(osd); nearfull_osds.insert(osd); } else { // ok full_osds.erase(osd); nearfull_osds.erase(osd); } } void PGMap::calc_stats() { num_pg_by_state.clear(); num_pg = 0; num_osd = 0; pg_pool_sum.clear(); pg_sum = pool_stat_t(); osd_sum = osd_stat_t(); for (ceph::unordered_map::iterator p = pg_stat.begin(); p != pg_stat.end(); ++p) { stat_pg_add(p->first, p->second); } for (ceph::unordered_map::iterator p = osd_stat.begin(); p != osd_stat.end(); ++p) stat_osd_add(p->second); redo_full_sets(); calc_min_last_epoch_clean(); } void PGMap::update_pg(pg_t pgid, bufferlist& bl) { bufferlist::iterator p = bl.begin(); ceph::unordered_map::iterator s = pg_stat.find(pgid); epoch_t old_lec = 0; if (s != pg_stat.end()) { old_lec = s->second.get_effective_last_epoch_clean(); stat_pg_sub(pgid, s->second); } pg_stat_t& r = pg_stat[pgid]; ::decode(r, p); stat_pg_add(pgid, r); epoch_t lec = r.get_effective_last_epoch_clean(); if (min_last_epoch_clean && (lec < min_last_epoch_clean || // we did (lec > min_last_epoch_clean && // we might old_lec == min_last_epoch_clean) )) min_last_epoch_clean = 0; } void PGMap::remove_pg(pg_t pgid) { ceph::unordered_map::iterator s = pg_stat.find(pgid); if (s != pg_stat.end()) { if (min_last_epoch_clean && s->second.get_effective_last_epoch_clean() == min_last_epoch_clean) min_last_epoch_clean = 0; stat_pg_sub(pgid, s->second); pg_stat.erase(s); } } void PGMap::update_osd(int osd, bufferlist& bl) { bufferlist::iterator p = bl.begin(); ceph::unordered_map::iterator o = osd_stat.find(osd); epoch_t old_lec = 0; if (o != osd_stat.end()) { ceph::unordered_map::iterator i = osd_epochs.find(osd); if (i != osd_epochs.end()) old_lec = i->second; stat_osd_sub(o->second); } osd_stat_t& r = osd_stat[osd]; ::decode(r, p); stat_osd_add(r); // adjust [near]full status register_nearfull_status(osd, r); // epoch? if (!p.end()) { epoch_t e; ::decode(e, p); if (e < min_last_epoch_clean || (e > min_last_epoch_clean && old_lec == min_last_epoch_clean)) min_last_epoch_clean = 0; } else { // WARNING: we are not refreshing min_last_epoch_clean! must be old store // or old mon running. } } void PGMap::remove_osd(int osd) { ceph::unordered_map::iterator o = osd_stat.find(osd); if (o != osd_stat.end()) { stat_osd_sub(o->second); osd_stat.erase(o); // remove these old osds from full/nearfull set(s), too nearfull_osds.erase(osd); full_osds.erase(osd); } } void PGMap::stat_pg_add(const pg_t &pgid, const pg_stat_t &s) { num_pg++; num_pg_by_state[s.state]++; pg_pool_sum[pgid.pool()].add(s); pg_sum.add(s); if (s.state & PG_STATE_CREATING) { creating_pgs.insert(pgid); if (s.acting_primary >= 0) creating_pgs_by_osd[s.acting_primary].insert(pgid); } } void PGMap::stat_pg_sub(const pg_t &pgid, const pg_stat_t &s) { num_pg--; if (--num_pg_by_state[s.state] == 0) num_pg_by_state.erase(s.state); pool_stat_t& ps = pg_pool_sum[pgid.pool()]; ps.sub(s); if (ps.is_zero()) pg_pool_sum.erase(pgid.pool()); pg_sum.sub(s); if (s.state & PG_STATE_CREATING) { creating_pgs.erase(pgid); if (s.acting_primary >= 0) { creating_pgs_by_osd[s.acting_primary].erase(pgid); if (creating_pgs_by_osd[s.acting_primary].size() == 0) creating_pgs_by_osd.erase(s.acting_primary); } } } void PGMap::stat_osd_add(const osd_stat_t &s) { num_osd++; osd_sum.add(s); } void PGMap::stat_osd_sub(const osd_stat_t &s) { num_osd--; osd_sum.sub(s); } epoch_t PGMap::calc_min_last_epoch_clean() const { if (pg_stat.empty()) return 0; ceph::unordered_map::const_iterator p = pg_stat.begin(); epoch_t min = p->second.get_effective_last_epoch_clean(); for (++p; p != pg_stat.end(); ++p) { epoch_t lec = p->second.get_effective_last_epoch_clean(); if (lec < min) min = lec; } // also scan osd epochs // don't trim past the oldest reported osd epoch for (ceph::unordered_map::const_iterator i = osd_epochs.begin(); i != osd_epochs.end(); ++i) { if (i->second < min) min = i->second; } return min; } void PGMap::encode(bufferlist &bl, uint64_t features) const { if ((features & CEPH_FEATURE_MONENC) == 0) { __u8 v = 3; ::encode(v, bl); ::encode(version, bl); ::encode(pg_stat, bl); ::encode(osd_stat, bl); ::encode(last_osdmap_epoch, bl); ::encode(last_pg_scan, bl); ::encode(full_ratio, bl); ::encode(nearfull_ratio, bl); return; } ENCODE_START(6, 4, bl); ::encode(version, bl); ::encode(pg_stat, bl); ::encode(osd_stat, bl); ::encode(last_osdmap_epoch, bl); ::encode(last_pg_scan, bl); ::encode(full_ratio, bl); ::encode(nearfull_ratio, bl); ::encode(stamp, bl); ::encode(osd_epochs, bl); ENCODE_FINISH(bl); } void PGMap::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 4, 4, bl); ::decode(version, bl); if (struct_v < 3) { pg_stat.clear(); __u32 n; ::decode(n, bl); while (n--) { old_pg_t opgid; ::decode(opgid, bl); pg_t pgid = opgid; ::decode(pg_stat[pgid], bl); } } else { ::decode(pg_stat, bl); } ::decode(osd_stat, bl); ::decode(last_osdmap_epoch, bl); ::decode(last_pg_scan, bl); if (struct_v >= 2) { ::decode(full_ratio, bl); ::decode(nearfull_ratio, bl); } if (struct_v >= 5) ::decode(stamp, bl); if (struct_v >= 6) { ::decode(osd_epochs, bl); } else { for (ceph::unordered_map::iterator i = osd_stat.begin(); i != osd_stat.end(); ++i) { // This isn't accurate, but will cause trimming to behave like // previously. osd_epochs.insert(make_pair(i->first, last_osdmap_epoch)); } } DECODE_FINISH(bl); calc_stats(); } void PGMap::dirty_all(Incremental& inc) { inc.osdmap_epoch = last_osdmap_epoch; inc.pg_scan = last_pg_scan; inc.full_ratio = full_ratio; inc.nearfull_ratio = nearfull_ratio; for (ceph::unordered_map::const_iterator p = pg_stat.begin(); p != pg_stat.end(); ++p) { inc.pg_stat_updates[p->first] = p->second; } for (ceph::unordered_map::const_iterator p = osd_stat.begin(); p != osd_stat.end(); ++p) { assert(osd_epochs.count(p->first)); inc.update_stat(p->first, inc.get_osd_epochs().find(p->first)->second, p->second); } } void PGMap::dump(Formatter *f) const { dump_basic(f); dump_pg_stats(f, false); dump_pool_stats(f); dump_osd_stats(f); } void PGMap::dump_basic(Formatter *f) const { f->dump_unsigned("version", version); f->dump_stream("stamp") << stamp; f->dump_unsigned("last_osdmap_epoch", last_osdmap_epoch); f->dump_unsigned("last_pg_scan", last_pg_scan); f->dump_float("full_ratio", full_ratio); f->dump_float("near_full_ratio", nearfull_ratio); f->open_object_section("pg_stats_sum"); pg_sum.dump(f); f->close_section(); f->open_object_section("osd_stats_sum"); osd_sum.dump(f); f->close_section(); dump_delta(f); } void PGMap::dump_delta(Formatter *f) const { f->open_object_section("pg_stats_delta"); pg_sum_delta.dump(f); f->close_section(); } void PGMap::dump_pg_stats(Formatter *f, bool brief) const { f->open_array_section("pg_stats"); for (ceph::unordered_map::const_iterator i = pg_stat.begin(); i != pg_stat.end(); ++i) { f->open_object_section("pg_stat"); f->dump_stream("pgid") << i->first; if (brief) i->second.dump_brief(f); else i->second.dump(f); f->close_section(); } f->close_section(); } void PGMap::dump_pool_stats(Formatter *f) const { f->open_array_section("pool_stats"); for (ceph::unordered_map::const_iterator p = pg_pool_sum.begin(); p != pg_pool_sum.end(); ++p) { f->open_object_section("pool_stat"); f->dump_int("poolid", p->first); p->second.dump(f); f->close_section(); } f->close_section(); } void PGMap::dump_osd_stats(Formatter *f) const { f->open_array_section("osd_stats"); for (ceph::unordered_map::const_iterator q = osd_stat.begin(); q != osd_stat.end(); ++q) { f->open_object_section("osd_stat"); f->dump_int("osd", q->first); q->second.dump(f); f->close_section(); } f->close_section(); } void PGMap::dump_pg_stats_plain(ostream& ss, const ceph::unordered_map& pg_stats) const { ss << "pg_stat\tobjects\tmip\tdegr\tunf\tbytes\tlog\tdisklog\tstate\tstate_stamp\tv\treported\tup\tup_primary\tacting\tacting_primary\tlast_scrub\tscrub_stamp\tlast_deep_scrub\tdeep_scrub_stamp" << std::endl; for (ceph::unordered_map::const_iterator i = pg_stats.begin(); i != pg_stats.end(); ++i) { const pg_stat_t &st(i->second); ss << i->first << "\t" << st.stats.sum.num_objects //<< "\t" << st.num_object_copies << "\t" << st.stats.sum.num_objects_missing_on_primary << "\t" << st.stats.sum.num_objects_degraded << "\t" << st.stats.sum.num_objects_unfound << "\t" << st.stats.sum.num_bytes << "\t" << st.log_size << "\t" << st.ondisk_log_size << "\t" << pg_state_string(st.state) << "\t" << st.last_change << "\t" << st.version << "\t" << st.reported_epoch << ":" << st.reported_seq << "\t" << st.up << "\t" << st.up_primary << "\t" << st.acting << "\t" << st.acting_primary << "\t" << st.last_scrub << "\t" << st.last_scrub_stamp << "\t" << st.last_deep_scrub << "\t" << st.last_deep_scrub_stamp << std::endl; } } void PGMap::dump(ostream& ss) const { ss << "version " << version << std::endl; ss << "stamp " << stamp << std::endl; ss << "last_osdmap_epoch " << last_osdmap_epoch << std::endl; ss << "last_pg_scan " << last_pg_scan << std::endl; ss << "full_ratio " << full_ratio << std::endl; ss << "nearfull_ratio " << nearfull_ratio << std::endl; dump_pg_stats_plain(ss, pg_stat); for (ceph::unordered_map::const_iterator p = pg_pool_sum.begin(); p != pg_pool_sum.end(); ++p) ss << "pool " << p->first << "\t" << p->second.stats.sum.num_objects //<< "\t" << p->second.num_object_copies << "\t" << p->second.stats.sum.num_objects_missing_on_primary << "\t" << p->second.stats.sum.num_objects_degraded << "\t" << p->second.stats.sum.num_objects_unfound << "\t" << p->second.stats.sum.num_bytes << "\t" << p->second.log_size << "\t" << p->second.ondisk_log_size << std::endl; ss << " sum\t" << pg_sum.stats.sum.num_objects //<< "\t" << pg_sum.num_object_copies << "\t" << pg_sum.stats.sum.num_objects_missing_on_primary << "\t" << pg_sum.stats.sum.num_objects_degraded << "\t" << pg_sum.stats.sum.num_objects_unfound << "\t" << pg_sum.stats.sum.num_bytes << "\t" << pg_sum.log_size << "\t" << pg_sum.ondisk_log_size << std::endl; ss << "osdstat\tkbused\tkbavail\tkb\thb in\thb out" << std::endl; for (ceph::unordered_map::const_iterator p = osd_stat.begin(); p != osd_stat.end(); ++p) ss << p->first << "\t" << p->second.kb_used << "\t" << p->second.kb_avail << "\t" << p->second.kb << "\t" << p->second.hb_in << "\t" << p->second.hb_out << std::endl; ss << " sum\t" << osd_sum.kb_used << "\t" << osd_sum.kb_avail << "\t" << osd_sum.kb << std::endl; } void PGMap::get_stuck_stats(PGMap::StuckPG type, utime_t cutoff, ceph::unordered_map& stuck_pgs) const { for (ceph::unordered_map::const_iterator i = pg_stat.begin(); i != pg_stat.end(); ++i) { utime_t val; switch (type) { case STUCK_INACTIVE: if (i->second.state & PG_STATE_ACTIVE) continue; val = i->second.last_active; break; case STUCK_UNCLEAN: if (i->second.state & PG_STATE_CLEAN) continue; val = i->second.last_clean; break; case STUCK_STALE: if ((i->second.state & PG_STATE_STALE) == 0) continue; val = i->second.last_unstale; break; default: assert(0 == "invalid type"); } if (val < cutoff) { stuck_pgs[i->first] = i->second; } } } void PGMap::dump_stuck(Formatter *f, PGMap::StuckPG type, utime_t cutoff) const { ceph::unordered_map stuck_pg_stats; get_stuck_stats(type, cutoff, stuck_pg_stats); f->open_array_section("stuck_pg_stats"); for (ceph::unordered_map::const_iterator i = stuck_pg_stats.begin(); i != stuck_pg_stats.end(); ++i) { f->open_object_section("pg_stat"); f->dump_stream("pgid") << i->first; i->second.dump(f); f->close_section(); } f->close_section(); } void PGMap::dump_stuck_plain(ostream& ss, PGMap::StuckPG type, utime_t cutoff) const { ceph::unordered_map stuck_pg_stats; get_stuck_stats(type, cutoff, stuck_pg_stats); if (!stuck_pg_stats.empty()) dump_pg_stats_plain(ss, stuck_pg_stats); } void PGMap::dump_osd_perf_stats(Formatter *f) const { f->open_array_section("osd_perf_infos"); for (ceph::unordered_map::const_iterator i = osd_stat.begin(); i != osd_stat.end(); ++i) { f->open_object_section("osd"); f->dump_int("id", i->first); { f->open_object_section("perf_stats"); i->second.fs_perf_stat.dump(f); f->close_section(); } f->close_section(); } f->close_section(); } void PGMap::print_osd_perf_stats(std::ostream *ss) const { TextTable tab; tab.define_column("osdid", TextTable::LEFT, TextTable::RIGHT); tab.define_column("fs_commit_latency(ms)", TextTable::LEFT, TextTable::RIGHT); tab.define_column("fs_apply_latency(ms)", TextTable::LEFT, TextTable::RIGHT); for (ceph::unordered_map::const_iterator i = osd_stat.begin(); i != osd_stat.end(); ++i) { tab << i->first; tab << i->second.fs_perf_stat.filestore_commit_latency; tab << i->second.fs_perf_stat.filestore_apply_latency; tab << TextTable::endrow; } (*ss) << tab; } void PGMap::recovery_summary(Formatter *f, ostream *out, const pool_stat_t& delta_sum) const { bool first = true; if (delta_sum.stats.sum.num_objects_degraded) { double pc = (double)delta_sum.stats.sum.num_objects_degraded / (double)delta_sum.stats.sum.num_object_copies * (double)100.0; char b[20]; snprintf(b, sizeof(b), "%.3lf", pc); if (f) { f->dump_unsigned("degraded_objects", delta_sum.stats.sum.num_objects_degraded); f->dump_unsigned("degraded_total", delta_sum.stats.sum.num_object_copies); f->dump_string("degraded_ratio", b); } else { *out << delta_sum.stats.sum.num_objects_degraded << "/" << delta_sum.stats.sum.num_object_copies << " objects degraded (" << b << "%)"; } first = false; } if (delta_sum.stats.sum.num_objects_unfound) { double pc = (double)delta_sum.stats.sum.num_objects_unfound / (double)delta_sum.stats.sum.num_objects * (double)100.0; char b[20]; snprintf(b, sizeof(b), "%.3lf", pc); if (f) { f->dump_unsigned("unfound_objects", delta_sum.stats.sum.num_objects_unfound); f->dump_unsigned("unfound_total", delta_sum.stats.sum.num_objects); f->dump_string("unfound_ratio", b); } else { if (!first) *out << "; "; *out << delta_sum.stats.sum.num_objects_unfound << "/" << delta_sum.stats.sum.num_objects << " unfound (" << b << "%)"; } first = false; } } void PGMap::recovery_rate_summary(Formatter *f, ostream *out, const pool_stat_t& delta_sum, utime_t delta_stamp) const { // make non-negative; we can get negative values if osds send // uncommitted stats and then "go backward" or if they are just // buggy/wrong. pool_stat_t pos_delta = delta_sum; pos_delta.floor(0); if (pos_delta.stats.sum.num_objects_recovered || pos_delta.stats.sum.num_bytes_recovered || pos_delta.stats.sum.num_keys_recovered) { int64_t objps = pos_delta.stats.sum.num_objects_recovered / (double)delta_stamp; int64_t bps = pos_delta.stats.sum.num_bytes_recovered / (double)delta_stamp; int64_t kps = pos_delta.stats.sum.num_keys_recovered / (double)delta_stamp; if (f) { f->dump_int("recovering_objects_per_sec", objps); f->dump_int("recovering_bytes_per_sec", bps); f->dump_int("recovering_keys_per_sec", kps); } else { *out << pretty_si_t(bps) << "B/s"; if (pos_delta.stats.sum.num_keys_recovered) *out << ", " << pretty_si_t(kps) << "keys/s"; *out << ", " << pretty_si_t(objps) << "objects/s"; } } } void PGMap::overall_recovery_rate_summary(Formatter *f, ostream *out) const { recovery_rate_summary(f, out, pg_sum_delta, stamp_delta); } void PGMap::overall_recovery_summary(Formatter *f, ostream *out) const { recovery_summary(f, out, pg_sum); } void PGMap::pool_recovery_rate_summary(Formatter *f, ostream *out, uint64_t poolid) const { ceph::unordered_map >::const_iterator p = per_pool_sum_delta.find(poolid); if (p == per_pool_sum_delta.end()) return; ceph::unordered_map::const_iterator ts = per_pool_sum_deltas_stamps.find(p->first); assert(ts != per_pool_sum_deltas_stamps.end()); recovery_rate_summary(f, out, p->second.first, ts->second); } void PGMap::pool_recovery_summary(Formatter *f, ostream *out, uint64_t poolid) const { ceph::unordered_map >::const_iterator p = per_pool_sum_delta.find(poolid); if (p == per_pool_sum_delta.end()) return; recovery_summary(f, out, p->second.first); } void PGMap::client_io_rate_summary(Formatter *f, ostream *out, const pool_stat_t& delta_sum, utime_t delta_stamp) const { pool_stat_t pos_delta = delta_sum; pos_delta.floor(0); if (pos_delta.stats.sum.num_rd || pos_delta.stats.sum.num_wr) { if (pos_delta.stats.sum.num_rd) { int64_t rd = (pos_delta.stats.sum.num_rd_kb << 10) / (double)delta_stamp; if (f) { f->dump_int("read_bytes_sec", rd); } else { *out << pretty_si_t(rd) << "B/s rd, "; } } if (pos_delta.stats.sum.num_wr) { int64_t wr = (pos_delta.stats.sum.num_wr_kb << 10) / (double)delta_stamp; if (f) { f->dump_int("write_bytes_sec", wr); } else { *out << pretty_si_t(wr) << "B/s wr, "; } } int64_t iops = (pos_delta.stats.sum.num_rd + pos_delta.stats.sum.num_wr) / (double)delta_stamp; if (f) { f->dump_int("op_per_sec", iops); } else { *out << pretty_si_t(iops) << "op/s"; } } } void PGMap::overall_client_io_rate_summary(Formatter *f, ostream *out) const { client_io_rate_summary(f, out, pg_sum_delta, stamp_delta); } void PGMap::pool_client_io_rate_summary(Formatter *f, ostream *out, uint64_t poolid) const { ceph::unordered_map >::const_iterator p = per_pool_sum_delta.find(poolid); if (p == per_pool_sum_delta.end()) return; ceph::unordered_map::const_iterator ts = per_pool_sum_deltas_stamps.find(p->first); assert(ts != per_pool_sum_deltas_stamps.end()); client_io_rate_summary(f, out, p->second.first, ts->second); } /** * update aggregated delta * * @param cct ceph context * @param ts Timestamp for the stats being delta'ed * @param old_pool_sum Previous stats sum * @param last_ts Last timestamp for pool * @param result_pool_sum Resulting stats * @param result_ts_delta Resulting timestamp delta * @param delta_avg_list List of last N computed deltas, used to average */ void PGMap::update_delta(CephContext *cct, const utime_t ts, const pool_stat_t& old_pool_sum, utime_t *last_ts, const pool_stat_t& current_pool_sum, pool_stat_t *result_pool_delta, utime_t *result_ts_delta, list > *delta_avg_list) { /* @p ts is the timestamp we want to associate with the data * in @p old_pool_sum, and on which we will base ourselves to * calculate the delta, stored in 'delta_t'. */ utime_t delta_t; delta_t = ts; // start with the provided timestamp delta_t -= *last_ts; // take the last timestamp we saw *last_ts = ts; // @p ts becomes the last timestamp we saw // calculate a delta, and average over the last 2 deltas. /* start by taking a copy of our current @p result_pool_sum, and by * taking out the stats from @p old_pool_sum. This generates a stats * delta. Stash this stats delta in @p delta_avg_list, along with the * timestamp delta for these results. */ pool_stat_t d = current_pool_sum; d.stats.sub(old_pool_sum.stats); delta_avg_list->push_back(make_pair(d,delta_t)); *result_ts_delta += delta_t; /* Aggregate current delta, and take out the last seen delta (if any) to * average it out. */ result_pool_delta->stats.add(d.stats); size_t s = MAX(1, cct ? cct->_conf->mon_stat_smooth_intervals : 1); if (delta_avg_list->size() > s) { result_pool_delta->stats.sub(delta_avg_list->front().first.stats); *result_ts_delta -= delta_avg_list->front().second; delta_avg_list->pop_front(); } } /** * update aggregated delta * * @param cct ceph context * @param ts Timestamp * @param pg_sum_old Old pg_sum */ void PGMap::update_global_delta(CephContext *cct, const utime_t ts, const pool_stat_t& pg_sum_old) { update_delta(cct, ts, pg_sum_old, &stamp, pg_sum, &pg_sum_delta, &stamp_delta, &pg_sum_deltas); } /** * Update a given pool's deltas * * @param cct Ceph Context * @param ts Timestamp for the stats being delta'ed * @param pool Pool's id * @param old_pool_sum Previous stats sum */ void PGMap::update_one_pool_delta(CephContext *cct, const utime_t ts, const uint64_t pool, const pool_stat_t& old_pool_sum) { if (per_pool_sum_deltas.count(pool) == 0) { assert(per_pool_sum_deltas_stamps.count(pool) == 0); assert(per_pool_sum_delta.count(pool) == 0); } pair& sum_delta = per_pool_sum_delta[pool]; update_delta(cct, ts, old_pool_sum, &sum_delta.second, pg_pool_sum[pool], &sum_delta.first, &per_pool_sum_deltas_stamps[pool], &per_pool_sum_deltas[pool]); } /** * Update pools' deltas * * @param cct CephContext * @param ts Timestamp for the stats being delta'ed * @param pg_pool_sum_old Map of pool stats for delta calcs. */ void PGMap::update_pool_deltas(CephContext *cct, const utime_t ts, const ceph::unordered_map& pg_pool_sum_old) { for (ceph::unordered_map::const_iterator it = pg_pool_sum_old.begin(); it != pg_pool_sum_old.end(); ++it) { update_one_pool_delta(cct, ts, it->first, it->second); } } void PGMap::clear_delta() { pg_sum_delta = pool_stat_t(); pg_sum_deltas.clear(); stamp_delta = utime_t(); } void PGMap::print_summary(Formatter *f, ostream *out) const { std::stringstream ss; if (f) f->open_array_section("pgs_by_state"); for (ceph::unordered_map::const_iterator p = num_pg_by_state.begin(); p != num_pg_by_state.end(); ++p) { if (f) { f->open_object_section("pgs_by_state_element"); f->dump_string("state_name", pg_state_string(p->first)); f->dump_unsigned("count", p->second); f->close_section(); } else { ss.setf(std::ios::right); ss << " " << std::setw(7) << p->second << " " << pg_state_string(p->first) << "\n"; ss.unsetf(std::ios::right); } } if (f) f->close_section(); if (f) { f->dump_unsigned("version", version); f->dump_unsigned("num_pgs", pg_stat.size()); f->dump_unsigned("data_bytes", pg_sum.stats.sum.num_bytes); f->dump_unsigned("bytes_used", osd_sum.kb_used * 1024ull); f->dump_unsigned("bytes_avail", osd_sum.kb_avail * 1024ull); f->dump_unsigned("bytes_total", osd_sum.kb * 1024ull); } else { *out << " pgmap v" << version << ": " << pg_stat.size() << " pgs, " << pg_pool_sum.size() << " pools, " << prettybyte_t(pg_sum.stats.sum.num_bytes) << " data, " << pretty_si_t(pg_sum.stats.sum.num_objects) << "objects\n"; *out << " " << kb_t(osd_sum.kb_used) << " used, " << kb_t(osd_sum.kb_avail) << " / " << kb_t(osd_sum.kb) << " avail\n"; } std::stringstream ssr; overall_recovery_summary(f, &ssr); if (!f && ssr.str().length()) *out << " " << ssr.str() << "\n"; ssr.clear(); ssr.str(""); if (!f) *out << ss.str(); // pgs by state overall_recovery_rate_summary(f, &ssr); if (!f && ssr.str().length()) *out << "recovery io " << ssr.str() << "\n"; ssr.clear(); ssr.str(""); overall_client_io_rate_summary(f, &ssr); if (!f && ssr.str().length()) *out << " client io " << ssr.str() << "\n"; } void PGMap::print_oneline_summary(ostream *out) const { std::stringstream ss; for (ceph::unordered_map::const_iterator p = num_pg_by_state.begin(); p != num_pg_by_state.end(); ++p) { if (p != num_pg_by_state.begin()) ss << ", "; ss << p->second << " " << pg_state_string(p->first); } string states = ss.str(); *out << "v" << version << ": " << pg_stat.size() << " pgs: " << states << "; " << prettybyte_t(pg_sum.stats.sum.num_bytes) << " data, " << kb_t(osd_sum.kb_used) << " used, " << kb_t(osd_sum.kb_avail) << " / " << kb_t(osd_sum.kb) << " avail"; // make non-negative; we can get negative values if osds send // uncommitted stats and then "go backward" or if they are just // buggy/wrong. pool_stat_t pos_delta = pg_sum_delta; pos_delta.floor(0); if (pos_delta.stats.sum.num_rd || pos_delta.stats.sum.num_wr) { *out << "; "; if (pos_delta.stats.sum.num_rd) { int64_t rd = (pos_delta.stats.sum.num_rd_kb << 10) / (double)stamp_delta; *out << pretty_si_t(rd) << "B/s rd, "; } if (pos_delta.stats.sum.num_wr) { int64_t wr = (pos_delta.stats.sum.num_wr_kb << 10) / (double)stamp_delta; *out << pretty_si_t(wr) << "B/s wr, "; } int64_t iops = (pos_delta.stats.sum.num_rd + pos_delta.stats.sum.num_wr) / (double)stamp_delta; *out << pretty_si_t(iops) << "op/s"; } std::stringstream ssr; overall_recovery_summary(NULL, &ssr); if (ssr.str().length()) *out << "; " << ssr.str(); ssr.clear(); ssr.str(""); overall_recovery_rate_summary(NULL, &ssr); if (ssr.str().length()) *out << "; " << ssr.str() << " recovering"; } void PGMap::generate_test_instances(list& o) { o.push_back(new PGMap); o.push_back(new PGMap); list inc; Incremental::generate_test_instances(inc); inc.pop_front(); while (!inc.empty()) { o.back()->apply_incremental(NULL, *inc.front()); delete inc.front(); inc.pop_front(); } } ceph-0.80.11/src/mon/MonmapMonitor.cc0000664000175100017510000003317612623076744021375 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MonmapMonitor.h" #include "Monitor.h" #include "MonitorDBStore.h" #include "messages/MMonCommand.h" #include "messages/MMonJoin.h" #include "common/Timer.h" #include "common/ceph_argparse.h" #include "common/errno.h" #include "mon/MDSMonitor.h" #include "mon/OSDMonitor.h" #include "mon/PGMonitor.h" #include #include "common/config.h" #include "common/cmdparse.h" #include "include/str_list.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon) static ostream& _prefix(std::ostream *_dout, Monitor *mon) { return *_dout << "mon." << mon->name << "@" << mon->rank << "(" << mon->get_state_name() << ").monmap v" << mon->monmap->epoch << " "; } void MonmapMonitor::create_initial() { dout(10) << "create_initial using current monmap" << dendl; pending_map = *mon->monmap; pending_map.epoch = 1; } void MonmapMonitor::update_from_paxos(bool *need_bootstrap) { version_t version = get_last_committed(); if (version <= mon->monmap->get_epoch()) return; dout(10) << __func__ << " version " << version << ", my v " << mon->monmap->epoch << dendl; if (need_bootstrap && version != mon->monmap->get_epoch()) { dout(10) << " signaling that we need a bootstrap" << dendl; *need_bootstrap = true; } // read and decode monmap_bl.clear(); int ret = get_version(version, monmap_bl); assert(ret == 0); assert(monmap_bl.length()); dout(10) << "update_from_paxos got " << version << dendl; mon->monmap->decode(monmap_bl); if (mon->store->exists("mkfs", "monmap")) { MonitorDBStore::Transaction t; t.erase("mkfs", "monmap"); mon->store->apply_transaction(t); } } void MonmapMonitor::create_pending() { pending_map = *mon->monmap; pending_map.epoch++; pending_map.last_changed = ceph_clock_now(g_ceph_context); dout(10) << "create_pending monmap epoch " << pending_map.epoch << dendl; } void MonmapMonitor::encode_pending(MonitorDBStore::Transaction *t) { dout(10) << "encode_pending epoch " << pending_map.epoch << dendl; assert(mon->monmap->epoch + 1 == pending_map.epoch || pending_map.epoch == 1); // special case mkfs! bufferlist bl; pending_map.encode(bl, mon->get_quorum_features()); put_version(t, pending_map.epoch, bl); put_last_committed(t, pending_map.epoch); // generate a cluster fingerprint, too? if (pending_map.epoch == 1) { mon->prepare_new_fingerprint(t); } } void MonmapMonitor::on_active() { if (get_last_committed() >= 1 && !mon->has_ever_joined) { // make note of the fact that i was, once, part of the quorum. dout(10) << "noting that i was, once, part of an active quorum." << dendl; /* This is some form of nasty in-breeding we have between the MonmapMonitor and the Monitor itself. We should find a way to get rid of it given our new architecture. Until then, stick with it since we are a single-threaded process and, truth be told, no one else relies on this thing besides us. */ MonitorDBStore::Transaction t; t.put(Monitor::MONITOR_NAME, "joined", 1); mon->store->apply_transaction(t); mon->has_ever_joined = true; } if (mon->is_leader()) mon->clog.info() << "monmap " << *mon->monmap << "\n"; } bool MonmapMonitor::preprocess_query(PaxosServiceMessage *m) { switch (m->get_type()) { // READs case MSG_MON_COMMAND: return preprocess_command(static_cast(m)); case MSG_MON_JOIN: return preprocess_join(static_cast(m)); default: assert(0); m->put(); return true; } } void MonmapMonitor::dump_info(Formatter *f) { f->dump_unsigned("monmap_first_committed", get_first_committed()); f->dump_unsigned("monmap_last_committed", get_last_committed()); f->open_object_section("monmap"); mon->monmap->dump(f); f->close_section(); f->open_array_section("quorum"); for (set::iterator q = mon->get_quorum().begin(); q != mon->get_quorum().end(); ++q) f->dump_int("mon", *q); f->close_section(); } bool MonmapMonitor::preprocess_command(MMonCommand *m) { int r = -1; bufferlist rdata; stringstream ss; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, rdata, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", get_last_committed()); return true; } if (prefix == "mon stat") { mon->monmap->print_summary(ss); ss << ", election epoch " << mon->get_epoch() << ", quorum " << mon->get_quorum() << " " << mon->get_quorum_names(); rdata.append(ss); ss.str(""); r = 0; } else if (prefix == "mon getmap" || prefix == "mon dump") { epoch_t epoch; int64_t epochnum; cmd_getval(g_ceph_context, cmdmap, "epoch", epochnum, (int64_t)0); epoch = epochnum; MonMap *p = mon->monmap; if (epoch) { bufferlist bl; r = get_version(epoch, bl); if (r == -ENOENT) { ss << "there is no map for epoch " << epoch; goto reply; } assert(r == 0); assert(bl.length() > 0); p = new MonMap; p->decode(bl); } assert(p != NULL); if (prefix == "mon getmap") { p->encode(rdata, m->get_connection()->get_features()); r = 0; ss << "got monmap epoch " << p->get_epoch(); } else if (prefix == "mon dump") { string format; cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain")); stringstream ds; boost::scoped_ptr f(new_formatter(format)); if (f) { f->open_object_section("monmap"); p->dump(f.get()); f->open_array_section("quorum"); for (set::iterator q = mon->get_quorum().begin(); q != mon->get_quorum().end(); ++q) { f->dump_int("mon", *q); } f->close_section(); f->close_section(); f->flush(ds); r = 0; } else { p->print(ds); r = 0; } rdata.append(ds); ss << "dumped monmap epoch " << p->get_epoch(); } if (p != mon->monmap) delete p; } else if (prefix == "mon add") return false; else if (prefix == "mon remove") return false; reply: if (r != -1) { string rs; getline(ss, rs); mon->reply_command(m, r, rs, rdata, get_last_committed()); return true; } else return false; } bool MonmapMonitor::prepare_update(PaxosServiceMessage *m) { dout(7) << "prepare_update " << *m << " from " << m->get_orig_source_inst() << dendl; switch (m->get_type()) { case MSG_MON_COMMAND: return prepare_command(static_cast(m)); case MSG_MON_JOIN: return prepare_join(static_cast(m)); default: assert(0); m->put(); } return false; } bool MonmapMonitor::prepare_command(MMonCommand *m) { stringstream ss; string rs; int err = -EINVAL; map cmdmap; if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) { string rs = ss.str(); mon->reply_command(m, -EINVAL, rs, get_last_committed()); return true; } string prefix; cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); MonSession *session = m->get_session(); if (!session) { mon->reply_command(m, -EACCES, "access denied", get_last_committed()); return true; } if (prefix == "mon add") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); string addrstr; cmd_getval(g_ceph_context, cmdmap, "addr", addrstr); entity_addr_t addr; bufferlist rdata; if (!addr.parse(addrstr.c_str())) { err = -EINVAL; ss << "addr " << addrstr << "does not parse"; goto out; } if (addr.get_port() == 0) { ss << "port defaulted to " << CEPH_MON_PORT; addr.set_port(CEPH_MON_PORT); } /** * If we have a monitor with the same name and different addr, then EEXIST * If we have a monitor with the same addr and different name, then EEXIST * If we have a monitor with the same addr and same name, then return as if * we had just added the monitor. * If we don't have the monitor, add it. */ err = 0; if (!ss.str().empty()) ss << "; "; do { if (pending_map.contains(addr)) { string n = pending_map.get_name(addr); if (n == name) break; } else if (pending_map.contains(name)) { entity_addr_t tmp_addr = pending_map.get_addr(name); if (tmp_addr == addr) break; } else { break; } err = -EEXIST; ss << "mon." << name << " at " << addr << " already exists"; goto out; } while (false); ss << "added mon." << name << " at " << addr; if (pending_map.contains(name)) { goto out; } pending_map.add(name, addr); pending_map.last_changed = ceph_clock_now(g_ceph_context); getline(ss, rs); wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs, get_last_committed() + 1)); return true; } else if (prefix == "mon remove") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name); if (!pending_map.contains(name)) { err = 0; ss << "mon " << name << " does not exist or has already been removed"; goto out; } if (pending_map.size() == 1) { err = -EINVAL; ss << "error: refusing removal of last monitor " << name; goto out; } entity_addr_t addr = pending_map.get_addr(name); pending_map.remove(name); pending_map.last_changed = ceph_clock_now(g_ceph_context); ss << "removed mon." << name << " at " << addr << ", there are now " << pending_map.size() << " monitors" ; getline(ss, rs); // send reply immediately in case we get removed mon->reply_command(m, 0, rs, get_last_committed()); return true; } else ss << "unknown command " << prefix; out: getline(ss, rs); mon->reply_command(m, err, rs, get_last_committed()); return false; } bool MonmapMonitor::preprocess_join(MMonJoin *join) { dout(10) << "preprocess_join " << join->name << " at " << join->addr << dendl; MonSession *session = join->get_session(); if (!session || !session->is_capable("mon", MON_CAP_W | MON_CAP_X)) { dout(10) << " insufficient caps" << dendl; join->put(); return true; } if (pending_map.contains(join->name) && !pending_map.get_addr(join->name).is_blank_ip()) { dout(10) << " already have " << join->name << dendl; join->put(); return true; } if (pending_map.contains(join->addr) && pending_map.get_name(join->addr) == join->name) { dout(10) << " already have " << join->addr << dendl; join->put(); return true; } return false; } bool MonmapMonitor::prepare_join(MMonJoin *join) { dout(0) << "adding/updating " << join->name << " at " << join->addr << " to monitor cluster" << dendl; if (pending_map.contains(join->name)) pending_map.remove(join->name); if (pending_map.contains(join->addr)) pending_map.remove(pending_map.get_name(join->addr)); pending_map.add(join->name, join->addr); pending_map.last_changed = ceph_clock_now(g_ceph_context); join->put(); return true; } bool MonmapMonitor::should_propose(double& delay) { delay = 0.0; return true; } void MonmapMonitor::tick() { } void MonmapMonitor::get_health(list >& summary, list > *detail) const { int max = mon->monmap->size(); int actual = mon->get_quorum().size(); if (actual < max) { ostringstream ss; ss << (max-actual) << " mons down, quorum " << mon->get_quorum() << " " << mon->get_quorum_names(); summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) { set q = mon->get_quorum(); for (int i=0; imonmap->get_name(i) << " (rank " << i << ") addr " << mon->monmap->get_addr(i) << " is down (out of quorum)"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } } if (g_conf->mon_warn_on_old_mons && !mon->get_classic_mons().empty()) { ostringstream ss; ss << "some monitors are running older code"; summary.push_back(make_pair(HEALTH_WARN, ss.str())); if (detail) { for (set::const_iterator i = mon->get_classic_mons().begin(); i != mon->get_classic_mons().end(); ++i) { ostringstream ss; ss << "mon." << mon->monmap->get_name(*i) << " only supports the \"classic\" command set"; detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } } int MonmapMonitor::get_monmap(bufferlist &bl) { version_t latest_ver = get_last_committed(); dout(10) << __func__ << " ver " << latest_ver << dendl; if (!mon->store->exists(get_service_name(), stringify(latest_ver))) return -ENOENT; int err = get_version(latest_ver, bl); if (err < 0) { dout(1) << __func__ << " error obtaining monmap: " << cpp_strerror(err) << dendl; return err; } return 0; } int MonmapMonitor::get_monmap(MonMap &m) { dout(10) << __func__ << dendl; bufferlist monmap_bl; int err = get_monmap(monmap_bl); if (err < 0) { return err; } m.decode(monmap_bl); return 0; } ceph-0.80.11/src/mon/MonitorDBStore.h0000664000175100017510000003655012623076744021311 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CEPH_MONITOR_DB_STORE_H #define CEPH_MONITOR_DB_STORE_H #include "include/types.h" #include "include/buffer.h" #include #include #include #include #include #include "os/KeyValueDB.h" #include "os/LevelDBStore.h" #include "include/assert.h" #include "common/Formatter.h" #include "common/errno.h" class MonitorDBStore { boost::scoped_ptr db; bool do_dump; int dump_fd; public: struct Op { uint8_t type; string prefix; string key, endkey; bufferlist bl; Op() : type(0) { } Op(int t, string p, string k) : type(t), prefix(p), key(k) { } Op(int t, const string& p, string k, bufferlist& b) : type(t), prefix(p), key(k), bl(b) { } Op(int t, const string& p, string start, string end) : type(t), prefix(p), key(start), endkey(end) { } void encode(bufferlist& encode_bl) const { ENCODE_START(2, 1, encode_bl); ::encode(type, encode_bl); ::encode(prefix, encode_bl); ::encode(key, encode_bl); ::encode(bl, encode_bl); ::encode(endkey, encode_bl); ENCODE_FINISH(encode_bl); } void decode(bufferlist::iterator& decode_bl) { DECODE_START(2, decode_bl); ::decode(type, decode_bl); ::decode(prefix, decode_bl); ::decode(key, decode_bl); ::decode(bl, decode_bl); if (struct_v >= 2) ::decode(endkey, decode_bl); DECODE_FINISH(decode_bl); } void dump(Formatter *f) const { f->dump_int("type", type); f->dump_string("prefix", prefix); f->dump_string("key", key); if (endkey.length()) f->dump_string("endkey", endkey); } static void generate_test_instances(list& ls) { ls.push_back(new Op); // we get coverage here from the Transaction instances } }; struct Transaction { list ops; uint64_t bytes, keys; Transaction() : bytes(0), keys(0) {} enum { OP_PUT = 1, OP_ERASE = 2, OP_COMPACT = 3, }; void put(string prefix, string key, bufferlist& bl) { ops.push_back(Op(OP_PUT, prefix, key, bl)); ++keys; bytes += prefix.length() + key.length() + bl.length(); } void put(string prefix, version_t ver, bufferlist& bl) { ostringstream os; os << ver; put(prefix, os.str(), bl); } void put(string prefix, string key, version_t ver) { bufferlist bl; ::encode(ver, bl); put(prefix, key, bl); } void erase(string prefix, string key) { ops.push_back(Op(OP_ERASE, prefix, key)); ++keys; bytes += prefix.length() + key.length(); } void erase(string prefix, version_t ver) { ostringstream os; os << ver; erase(prefix, os.str()); } void compact_prefix(string prefix) { ops.push_back(Op(OP_COMPACT, prefix, string())); } void compact_range(string prefix, string start, string end) { ops.push_back(Op(OP_COMPACT, prefix, start, end)); } void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(ops, bl); ::encode(bytes, bl); ::encode(keys, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(ops, bl); if (struct_v >= 2) { ::decode(bytes, bl); ::decode(keys, bl); } DECODE_FINISH(bl); } static void generate_test_instances(list& ls) { ls.push_back(new Transaction); ls.push_back(new Transaction); bufferlist bl; bl.append("value"); ls.back()->put("prefix", "key", bl); ls.back()->erase("prefix2", "key2"); ls.back()->compact_prefix("prefix3"); ls.back()->compact_range("prefix4", "from", "to"); } void append(Transaction& other) { ops.splice(ops.end(), other.ops); keys += other.keys; bytes += other.bytes; } void append_from_encoded(bufferlist& bl) { Transaction other; bufferlist::iterator it = bl.begin(); other.decode(it); append(other); } bool empty() { return (size() == 0); } bool size() { return ops.size(); } uint64_t get_keys() const { return keys; } uint64_t get_bytes() const { return bytes; } void dump(ceph::Formatter *f, bool dump_val=false) const { f->open_object_section("transaction"); f->open_array_section("ops"); list::const_iterator it; int op_num = 0; for (it = ops.begin(); it != ops.end(); ++it) { const Op& op = *it; f->open_object_section("op"); f->dump_int("op_num", op_num++); switch (op.type) { case OP_PUT: { f->dump_string("type", "PUT"); f->dump_string("prefix", op.prefix); f->dump_string("key", op.key); f->dump_unsigned("length", op.bl.length()); if (dump_val) { ostringstream os; op.bl.hexdump(os); f->dump_string("bl", os.str()); } } break; case OP_ERASE: { f->dump_string("type", "ERASE"); f->dump_string("prefix", op.prefix); f->dump_string("key", op.key); } break; case OP_COMPACT: { f->dump_string("type", "COMPACT"); f->dump_string("prefix", op.prefix); f->dump_string("start", op.key); f->dump_string("end", op.endkey); } break; default: { f->dump_string("type", "unknown"); f->dump_unsigned("op_code", op.type); break; } } f->close_section(); } f->close_section(); f->dump_unsigned("num_keys", keys); f->dump_unsigned("num_bytes", bytes); f->close_section(); } }; int apply_transaction(const MonitorDBStore::Transaction& t) { KeyValueDB::Transaction dbt = db->get_transaction(); if (do_dump) { bufferlist bl; t.encode(bl); bl.write_fd(dump_fd); } list > > compact; for (list::const_iterator it = t.ops.begin(); it != t.ops.end(); ++it) { const Op& op = *it; switch (op.type) { case Transaction::OP_PUT: dbt->set(op.prefix, op.key, op.bl); break; case Transaction::OP_ERASE: dbt->rmkey(op.prefix, op.key); break; case Transaction::OP_COMPACT: compact.push_back(make_pair(op.prefix, make_pair(op.key, op.endkey))); break; default: derr << __func__ << " unknown op type " << op.type << dendl; ceph_assert(0); break; } } int r = db->submit_transaction_sync(dbt); if (r >= 0) { while (!compact.empty()) { if (compact.front().second.first == string() && compact.front().second.second == string()) db->compact_prefix_async(compact.front().first); else db->compact_range_async(compact.front().first, compact.front().second.first, compact.front().second.second); compact.pop_front(); } } else { assert(0 == "failed to write to db"); } return r; } class StoreIteratorImpl { protected: bool done; pair last_key; bufferlist crc_bl; StoreIteratorImpl() : done(false) { } virtual ~StoreIteratorImpl() { } bool add_chunk_entry(Transaction &tx, string &prefix, string &key, bufferlist &value, uint64_t max) { Transaction tmp; bufferlist tmp_bl; tmp.put(prefix, key, value); tmp.encode(tmp_bl); bufferlist tx_bl; tx.encode(tx_bl); size_t len = tx_bl.length() + tmp_bl.length(); if (!tx.empty() && (len > max)) { return false; } tx.append(tmp); last_key.first = prefix; last_key.second = key; if (g_conf->mon_sync_debug) { ::encode(prefix, crc_bl); ::encode(key, crc_bl); ::encode(value, crc_bl); } return true; } virtual bool _is_valid() = 0; public: __u32 crc() { if (g_conf->mon_sync_debug) return crc_bl.crc32c(0); return 0; } pair get_last_key() { return last_key; }; virtual bool has_next_chunk() { return !done && _is_valid(); } virtual void get_chunk_tx(Transaction &tx, uint64_t max) = 0; virtual pair get_next_key() = 0; }; typedef ceph::shared_ptr Synchronizer; class WholeStoreIteratorImpl : public StoreIteratorImpl { KeyValueDB::WholeSpaceIterator iter; set sync_prefixes; public: WholeStoreIteratorImpl(KeyValueDB::WholeSpaceIterator iter, set &prefixes) : StoreIteratorImpl(), iter(iter), sync_prefixes(prefixes) { } virtual ~WholeStoreIteratorImpl() { } /** * Obtain a chunk of the store * * @param bl Encoded transaction that will recreate the chunk * @param first_key Pair containing the first key to obtain, and that * will contain the first key in the chunk (that may * differ from the one passed on to the function) * @param last_key[out] Last key in the chunk */ virtual void get_chunk_tx(Transaction &tx, uint64_t max) { assert(done == false); assert(iter->valid() == true); while (iter->valid()) { string prefix(iter->raw_key().first); string key(iter->raw_key().second); if (sync_prefixes.count(prefix)) { bufferlist value = iter->value(); if (!add_chunk_entry(tx, prefix, key, value, max)) return; } iter->next(); } assert(iter->valid() == false); done = true; } virtual pair get_next_key() { assert(iter->valid()); for (; iter->valid(); iter->next()) { pair r = iter->raw_key(); if (sync_prefixes.count(r.first) > 0) { iter->next(); return r; } } return pair(); } virtual bool _is_valid() { return iter->valid(); } }; Synchronizer get_synchronizer(pair &key, set &prefixes) { KeyValueDB::WholeSpaceIterator iter; iter = db->get_snapshot_iterator(); if (!key.first.empty() && !key.second.empty()) iter->upper_bound(key.first, key.second); else iter->seek_to_first(); return ceph::shared_ptr( new WholeStoreIteratorImpl(iter, prefixes) ); } KeyValueDB::Iterator get_iterator(const string &prefix) { assert(!prefix.empty()); KeyValueDB::Iterator iter = db->get_snapshot_iterator(prefix); iter->seek_to_first(); return iter; } KeyValueDB::WholeSpaceIterator get_iterator() { KeyValueDB::WholeSpaceIterator iter; iter = db->get_snapshot_iterator(); iter->seek_to_first(); return iter; } int get(const string& prefix, const string& key, bufferlist& bl) { set k; k.insert(key); map out; db->get(prefix, k, &out); if (out.empty()) return -ENOENT; bl.append(out[key]); return 0; } int get(const string& prefix, const version_t ver, bufferlist& bl) { ostringstream os; os << ver; return get(prefix, os.str(), bl); } version_t get(const string& prefix, const string& key) { bufferlist bl; int err = get(prefix, key, bl); if (err < 0) { if (err == -ENOENT) // if key doesn't exist, assume its value is 0 return 0; // we're not expecting any other negative return value, and we can't // just return a negative value if we're returning a version_t generic_dout(0) << "MonitorDBStore::get() error obtaining" << " (" << prefix << ":" << key << "): " << cpp_strerror(err) << dendl; assert(0 == "error obtaining key"); } assert(bl.length()); version_t ver; bufferlist::iterator p = bl.begin(); ::decode(ver, p); return ver; } bool exists(const string& prefix, const string& key) { KeyValueDB::Iterator it = db->get_iterator(prefix); int err = it->lower_bound(key); if (err < 0) return false; return (it->valid() && it->key() == key); } bool exists(const string& prefix, version_t ver) { ostringstream os; os << ver; return exists(prefix, os.str()); } string combine_strings(const string& prefix, const string& value) { string out = prefix; out.push_back('_'); out.append(value); return out; } string combine_strings(const string& prefix, const version_t ver) { ostringstream os; os << ver; return combine_strings(prefix, os.str()); } void clear(set& prefixes) { set::iterator iter; KeyValueDB::Transaction dbt = db->get_transaction(); for (iter = prefixes.begin(); iter != prefixes.end(); ++iter) { dbt->rmkeys_by_prefix((*iter)); } int r = db->submit_transaction_sync(dbt); assert(r >= 0); } void init_options() { db->init(); if (g_conf->mon_leveldb_write_buffer_size) db->options.write_buffer_size = g_conf->mon_leveldb_write_buffer_size; if (g_conf->mon_leveldb_cache_size) db->options.cache_size = g_conf->mon_leveldb_cache_size; if (g_conf->mon_leveldb_block_size) db->options.block_size = g_conf->mon_leveldb_block_size; if (g_conf->mon_leveldb_bloom_size) db->options.bloom_size = g_conf->mon_leveldb_bloom_size; if (g_conf->mon_leveldb_compression) db->options.compression_enabled = g_conf->mon_leveldb_compression; if (g_conf->mon_leveldb_max_open_files) db->options.max_open_files = g_conf->mon_leveldb_max_open_files; if (g_conf->mon_leveldb_paranoid) db->options.paranoid_checks = g_conf->mon_leveldb_paranoid; if (g_conf->mon_leveldb_log.length()) db->options.log_file = g_conf->mon_leveldb_log; } int open(ostream &out) { init_options(); return db->open(out); } int create_and_open(ostream &out) { init_options(); return db->create_and_open(out); } void compact() { db->compact(); } void compact_prefix(const string& prefix) { db->compact_prefix(prefix); } uint64_t get_estimated_size(map &extras) { return db->get_estimated_size(extras); } MonitorDBStore(const string& path) : db(0), do_dump(false), dump_fd(-1) { string::const_reverse_iterator rit; int pos = 0; for (rit = path.rbegin(); rit != path.rend(); ++rit, ++pos) { if (*rit != '/') break; } ostringstream os; os << path.substr(0, path.size() - pos) << "/store.db"; string full_path = os.str(); LevelDBStore *db_ptr = new LevelDBStore(g_ceph_context, full_path); if (!db_ptr) { derr << __func__ << " error initializing level db back storage in " << full_path << dendl; assert(0 != "MonitorDBStore: error initializing level db back storage"); } db.reset(db_ptr); if (g_conf->mon_debug_dump_transactions) { do_dump = true; dump_fd = ::open( g_conf->mon_debug_dump_location.c_str(), O_CREAT|O_APPEND|O_WRONLY, 0644); if (!dump_fd) { dump_fd = -errno; derr << "Could not open log file, got " << cpp_strerror(dump_fd) << dendl; } } } MonitorDBStore(LevelDBStore *db_ptr) : db(0), do_dump(false), dump_fd(-1) { db.reset(db_ptr); } ~MonitorDBStore() { if (do_dump) ::close(dump_fd); } }; WRITE_CLASS_ENCODER(MonitorDBStore::Op); WRITE_CLASS_ENCODER(MonitorDBStore::Transaction); #endif /* CEPH_MONITOR_DB_STORE_H */ ceph-0.80.11/src/mon/MonCap.h0000664000175100017510000001110012623076744017574 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_MONCAP_H #define CEPH_MONCAP_H #include using std::ostream; #include "include/types.h" #include "common/entity_name.h" class CephContext; static const __u8 MON_CAP_R = (1 << 1); // read static const __u8 MON_CAP_W = (1 << 2); // write static const __u8 MON_CAP_X = (1 << 3); // execute static const __u8 MON_CAP_ALL = MON_CAP_R | MON_CAP_W | MON_CAP_X; static const __u8 MON_CAP_ANY = 0xff; // * struct mon_rwxa_t { __u8 val; mon_rwxa_t(__u8 v = 0) : val(v) {} mon_rwxa_t& operator=(__u8 v) { val = v; return *this; } operator __u8() const { return val; } }; ostream& operator<<(ostream& out, mon_rwxa_t p); struct StringConstraint { string value; string prefix; StringConstraint() {} StringConstraint(string a, string b) : value(a), prefix(b) {} }; ostream& operator<<(ostream& out, const StringConstraint& c); struct MonCapGrant { /* * A grant can come in one of four forms: * * - a blanket allow ('allow rw', 'allow *') * - this will match against any service and the read/write/exec flags * in the mon code. semantics of what X means are somewhat ad hoc. * * - a service allow ('allow service mds rw') * - this will match against a specific service and the r/w/x flags. * * - a profile ('allow profile osd') * - this will match against specific monitor-enforced semantics of what * this type of user should need to do. examples include 'osd', 'mds', * 'bootstrap-osd'. * * - a command ('allow command foo', 'allow command bar with arg1=val1 arg2 prefix val2') * this includes the command name (the prefix string), and a set * of key/value pairs that constrain use of that command. if no pairs * are specified, any arguments are allowed; if a pair is specified, that * argument must be present and equal or match a prefix. */ std::string service; std::string profile; std::string command; map command_args; mon_rwxa_t allow; // explicit grants that a profile grant expands to; populated as // needed by expand_profile() (via is_match()) and cached here. mutable list profile_grants; void expand_profile(EntityName name) const; MonCapGrant() : allow(0) {} MonCapGrant(mon_rwxa_t a) : allow(a) {} MonCapGrant(string s, mon_rwxa_t a) : service(s), allow(a) {} MonCapGrant(string c) : command(c) {} MonCapGrant(string c, string a, StringConstraint co) : command(c) { command_args[a] = co; } /** * check if given request parameters match our constraints * * @param cct context * @param name entity name * @param service service (if any) * @param command command (if any) * @param command_args command args (if any) * @return bits we allow */ mon_rwxa_t get_allowed(CephContext *cct, EntityName name, const std::string& service, const std::string& command, const map& command_args) const; bool is_allow_all() const { return allow == MON_CAP_ANY && service.length() == 0 && profile.length() == 0 && command.length() == 0; } }; ostream& operator<<(ostream& out, const MonCapGrant& g); struct MonCap { string text; std::vector grants; MonCap() {} MonCap(std::vector g) : grants(g) {} string get_str() const { return text; } bool is_allow_all() const; void set_allow_all(); bool parse(const std::string& str, ostream *err=NULL); /** * check if we are capable of something * * This method actually checks a description of a particular operation against * what the capability has specified. * * @param service service name * @param command command id * @param command_args * @param op_may_read whether the operation may need to read * @param op_may_write whether the operation may need to write * @param op_may_exec whether the operation may exec * @return true if the operation is allowed, false otherwise */ bool is_capable(CephContext *cct, EntityName name, const string& service, const string& command, const map& command_args, bool op_may_read, bool op_may_write, bool op_may_exec) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(MonCap) ostream& operator<<(ostream& out, const MonCap& cap); #endif ceph-0.80.11/src/mon/Session.h0000664000175100017510000001222112623076744020047 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MON_SESSION_H #define CEPH_MON_SESSION_H #include "include/xlist.h" #include "msg/msg_types.h" #include "auth/AuthServiceHandler.h" #include "osd/OSDMap.h" #include "MonCap.h" struct MonSession; struct Subscription { MonSession *session; string type; xlist::item type_item; version_t next; bool onetime; bool incremental_onetime; // has CEPH_FEATURE_INCSUBOSDMAP Subscription(MonSession *s, const string& t) : session(s), type(t), type_item(this), next(0), onetime(false), incremental_onetime(false) {}; }; struct MonSession : public RefCountedObject { ConnectionRef con; entity_inst_t inst; utime_t until; utime_t time_established; bool closed; xlist::item item; set routed_request_tids; MonCap caps; uint64_t auid; uint64_t global_id; uint64_t notified_global_id; map sub_map; AuthServiceHandler *auth_handler; EntityName entity_name; ConnectionRef proxy_con; uint64_t proxy_tid; MonSession(const entity_inst_t& i, Connection *c) : con(c), inst(i), closed(false), item(this), auid(0), global_id(0), notified_global_id(0), auth_handler(NULL), proxy_con(NULL), proxy_tid(0) { time_established = ceph_clock_now(g_ceph_context); } ~MonSession() { //generic_dout(0) << "~MonSession " << this << dendl; // we should have been removed before we get destructed; see MonSessionMap::remove_session() assert(!item.is_on_list()); assert(sub_map.empty()); delete auth_handler; } bool is_capable(string service, int mask) { map args; return caps.is_capable(g_ceph_context, entity_name, service, "", args, mask & MON_CAP_R, mask & MON_CAP_W, mask & MON_CAP_X); } }; struct MonSessionMap { xlist sessions; map* > subs; multimap by_osd; MonSessionMap() {} ~MonSessionMap() { while (!subs.empty()) { assert(subs.begin()->second->empty()); delete subs.begin()->second; subs.erase(subs.begin()); } } void remove_session(MonSession *s) { assert(!s->closed); for (map::iterator p = s->sub_map.begin(); p != s->sub_map.end(); ++p) { p->second->type_item.remove_myself(); delete p->second; } s->sub_map.clear(); s->item.remove_myself(); if (s->inst.name.is_osd()) { for (multimap::iterator p = by_osd.find(s->inst.name.num()); p->first == s->inst.name.num(); ++p) if (p->second == s) { by_osd.erase(p); break; } } s->closed = true; s->put(); } MonSession *new_session(const entity_inst_t& i, Connection *c) { MonSession *s = new MonSession(i, c); sessions.push_back(&s->item); if (i.name.is_osd()) by_osd.insert(pair(i.name.num(), s)); s->get(); // caller gets a ref return s; } MonSession *get_random_osd_session(OSDMap *osdmap) { // ok, this isn't actually random, but close enough. if (by_osd.empty()) return 0; int n = by_osd.rbegin()->first + 1; int r = rand() % n; multimap::iterator p = by_osd.lower_bound(r); if (p == by_osd.end()) --p; if (!osdmap) { return p->second; } MonSession *s = NULL; multimap::iterator b = p, f = p; bool backward = true, forward = true; while (backward || forward) { if (backward) { if (osdmap->is_up(b->first) && osdmap->get_addr(b->first) == b->second->con->get_peer_addr()) { s = b->second; break; } if (b != by_osd.begin()) --b; else backward = false; } forward = (f != by_osd.end()); if (forward) { if (osdmap->is_up(f->first)) { s = f->second; break; } ++f; } } return s; } void add_update_sub(MonSession *s, const string& what, version_t start, bool onetime, bool incremental_onetime) { Subscription *sub = 0; if (s->sub_map.count(what)) { sub = s->sub_map[what]; } else { sub = new Subscription(s, what); s->sub_map[what] = sub; if (!subs.count(what)) subs[what] = new xlist; subs[what]->push_back(&sub->type_item); } sub->next = start; sub->onetime = onetime; sub->incremental_onetime = onetime && incremental_onetime; } void remove_sub(Subscription *sub) { sub->session->sub_map.erase(sub->type); sub->type_item.remove_myself(); delete sub; } }; inline ostream& operator<<(ostream& out, const MonSession *s) { out << "MonSession: " << s->inst << " is " << (s->closed ? "closed" : "open"); out << s->caps; return out; } #endif ceph-0.80.11/src/json_spirit/0000775000175100017510000000000012623077035020021 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/json_spirit/json_spirit_value.h0000664000175100017510000003771712623076744023756 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_VALUE #define JSON_SPIRIT_VALUE // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include #include #include #include #include #include #include #include #include #include // comment out the value types you don't need to reduce build times and intermediate file sizes #define JSON_SPIRIT_VALUE_ENABLED //#define JSON_SPIRIT_WVALUE_ENABLED #define JSON_SPIRIT_MVALUE_ENABLED //#define JSON_SPIRIT_WMVALUE_ENABLED namespace json_spirit { enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; struct Null{}; template< class Config > // Config determines whether the value uses std::string or std::wstring and // whether JSON Objects are represented as vectors or maps class Value_impl { public: typedef Config Config_type; typedef typename Config::String_type String_type; typedef typename Config::Object_type Object; typedef typename Config::Array_type Array; typedef typename String_type::const_pointer Const_str_ptr; // eg const char* Value_impl(); // creates null value Value_impl( Const_str_ptr value ); Value_impl( const String_type& value ); Value_impl( const Object& value ); Value_impl( const Array& value ); Value_impl( bool value ); Value_impl( int value ); Value_impl( boost::int64_t value ); Value_impl( boost::uint64_t value ); Value_impl( double value ); template< class Iter > Value_impl( Iter first, Iter last ); // constructor from containers, e.g. std::vector or std::list template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ); // constructor for compatible variant types Value_impl( const Value_impl& other ); bool operator==( const Value_impl& lhs ) const; Value_impl& operator=( const Value_impl& lhs ); Value_type type() const; bool is_uint64() const; bool is_null() const; const String_type& get_str() const; const Object& get_obj() const; const Array& get_array() const; bool get_bool() const; int get_int() const; boost::int64_t get_int64() const; boost::uint64_t get_uint64() const; double get_real() const; Object& get_obj(); Array& get_array(); template< typename T > T get_value() const; // example usage: int i = value.get_value< int >(); // or double d = value.get_value< double >(); static const Value_impl null; private: void check_type( const Value_type vtype ) const; typedef boost::variant< boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, String_type, bool, boost::int64_t, double, Null, boost::uint64_t > Variant; Variant v_; class Variant_converter_visitor : public boost::static_visitor< Variant > { public: template< typename T, typename A, template< typename, typename > class Cont > Variant operator()( const Cont< T, A >& cont ) const { return Array( cont.begin(), cont.end() ); } Variant operator()( int i ) const { return static_cast< boost::int64_t >( i ); } template Variant operator()( const T& t ) const { return t; } }; }; // vector objects template< class Config > struct Pair_impl { typedef typename Config::String_type String_type; typedef typename Config::Value_type Value_type; Pair_impl() { } Pair_impl( const String_type& name, const Value_type& value ); bool operator==( const Pair_impl& lhs ) const; String_type name_; Value_type value_; }; #if defined( JSON_SPIRIT_VALUE_ENABLED ) || defined( JSON_SPIRIT_WVALUE_ENABLED ) template< class String > struct Config_vector { typedef String String_type; typedef Value_impl< Config_vector > Value_type; typedef Pair_impl < Config_vector > Pair_type; typedef std::vector< Value_type > Array_type; typedef std::vector< Pair_type > Object_type; static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) { obj.push_back( Pair_type( name , value ) ); return obj.back().value_; } static String_type get_name( const Pair_type& pair ) { return pair.name_; } static Value_type get_value( const Pair_type& pair ) { return pair.value_; } }; #endif // typedefs for ASCII #ifdef JSON_SPIRIT_VALUE_ENABLED typedef Config_vector< std::string > Config; typedef Config::Value_type Value; typedef Config::Pair_type Pair; typedef Config::Object_type Object; typedef Config::Array_type Array; #endif // typedefs for Unicode #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) typedef Config_vector< std::wstring > wConfig; typedef wConfig::Value_type wValue; typedef wConfig::Pair_type wPair; typedef wConfig::Object_type wObject; typedef wConfig::Array_type wArray; #endif // map objects #if defined( JSON_SPIRIT_MVALUE_ENABLED ) || defined( JSON_SPIRIT_WMVALUE_ENABLED ) template< class String > struct Config_map { typedef String String_type; typedef Value_impl< Config_map > Value_type; typedef std::vector< Value_type > Array_type; typedef std::map< String_type, Value_type > Object_type; typedef std::pair< String_type, Value_type > Pair_type; static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) { return obj[ name ] = value; } static String_type get_name( const Pair_type& pair ) { return pair.first; } static Value_type get_value( const Pair_type& pair ) { return pair.second; } }; #endif // typedefs for ASCII #ifdef JSON_SPIRIT_MVALUE_ENABLED typedef Config_map< std::string > mConfig; typedef mConfig::Value_type mValue; typedef mConfig::Object_type mObject; typedef mConfig::Array_type mArray; #endif // typedefs for Unicode #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) typedef Config_map< std::wstring > wmConfig; typedef wmConfig::Value_type wmValue; typedef wmConfig::Object_type wmObject; typedef wmConfig::Array_type wmArray; #endif /////////////////////////////////////////////////////////////////////////////////////////////// // // implementation inline bool operator==( const Null&, const Null& ) { return true; } template< class Config > const Value_impl< Config > Value_impl< Config >::null; template< class Config > Value_impl< Config >::Value_impl() : v_( Null() ) { } template< class Config > Value_impl< Config >::Value_impl( const Const_str_ptr value ) : v_( String_type( value ) ) { } template< class Config > Value_impl< Config >::Value_impl( const String_type& value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( const Object& value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( const Array& value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( bool value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( int value ) : v_( static_cast< boost::int64_t >( value ) ) { } template< class Config > Value_impl< Config >::Value_impl( boost::int64_t value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( boost::uint64_t value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( double value ) : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) : v_( other.v_ ) { } template< class Config > template< class Iter > Value_impl< Config >::Value_impl( Iter first, Iter last ) : v_( Array( first, last ) ) { } template< class Config > template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > Value_impl< Config >::Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ) : v_( boost::apply_visitor( Variant_converter_visitor(), variant) ) { } template< class Config > Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) { Value_impl tmp( lhs ); std::swap( v_, tmp.v_ ); return *this; } template< class Config > bool Value_impl< Config >::operator==( const Value_impl& lhs ) const { if( this == &lhs ) return true; if( type() != lhs.type() ) return false; return v_ == lhs.v_; } template< class Config > Value_type Value_impl< Config >::type() const { if( is_uint64() ) { return int_type; } return static_cast< Value_type >( v_.which() ); } template< class Config > bool Value_impl< Config >::is_uint64() const { return v_.which() == null_type + 1; } template< class Config > bool Value_impl< Config >::is_null() const { return type() == null_type; } template< class Config > void Value_impl< Config >::check_type( const Value_type vtype ) const { if( type() != vtype ) { std::ostringstream os; os << "value type is " << type() << " not " << vtype; throw std::runtime_error( os.str() ); } } template< class Config > const typename Config::String_type& Value_impl< Config >::get_str() const { check_type( str_type ); return *boost::get< String_type >( &v_ ); } template< class Config > const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const { check_type( obj_type ); return *boost::get< Object >( &v_ ); } template< class Config > const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const { check_type( array_type ); return *boost::get< Array >( &v_ ); } template< class Config > bool Value_impl< Config >::get_bool() const { check_type( bool_type ); return boost::get< bool >( v_ ); } template< class Config > int Value_impl< Config >::get_int() const { check_type( int_type ); return static_cast< int >( get_int64() ); } template< class Config > boost::int64_t Value_impl< Config >::get_int64() const { check_type( int_type ); if( is_uint64() ) { return static_cast< boost::int64_t >( get_uint64() ); } return boost::get< boost::int64_t >( v_ ); } template< class Config > boost::uint64_t Value_impl< Config >::get_uint64() const { check_type( int_type ); if( !is_uint64() ) { return static_cast< boost::uint64_t >( get_int64() ); } return boost::get< boost::uint64_t >( v_ ); } template< class Config > double Value_impl< Config >::get_real() const { if( type() == int_type ) { return is_uint64() ? static_cast< double >( get_uint64() ) : static_cast< double >( get_int64() ); } check_type( real_type ); return boost::get< double >( v_ ); } template< class Config > typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() { check_type( obj_type ); return *boost::get< Object >( &v_ ); } template< class Config > typename Value_impl< Config >::Array& Value_impl< Config >::get_array() { check_type( array_type ); return *boost::get< Array >( &v_ ); } template< class Config > Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value ) : name_( name ) , value_( value ) { } template< class Config > bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const { if( this == &lhs ) return true; return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ ); } // converts a C string, ie. 8 bit char array, to a string object // template < class String_type > String_type to_str( const char* c_str ) { String_type result; for( const char* p = c_str; *p != 0; ++p ) { result += *p; } return result; } // namespace internal_ { template< typename T > struct Type_to_type { }; template< class Value > int get_value( const Value& value, Type_to_type< int > ) { return value.get_int(); } template< class Value > boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > ) { return value.get_int64(); } template< class Value > boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > ) { return value.get_uint64(); } template< class Value > double get_value( const Value& value, Type_to_type< double > ) { return value.get_real(); } template< class Value > typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > ) { return value.get_str(); } template< class Value > typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > ) { return value.get_array(); } template< class Value > typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > ) { return value.get_obj(); } template< class Value > bool get_value( const Value& value, Type_to_type< bool > ) { return value.get_bool(); } } template< class Config > template< typename T > T Value_impl< Config >::get_value() const { return internal_::get_value( *this, internal_::Type_to_type< T >() ); } } #endif ceph-0.80.11/src/json_spirit/json_spirit_stream_reader.h0000664000175100017510000000340212623076744025437 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_READ_STREAM #define JSON_SPIRIT_READ_STREAM // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_reader_template.h" namespace json_spirit { // these classes allows you to read multiple top level contiguous values from a stream, // the normal stream read functions have a bug that prevent multiple top level values // from being read unless they are separated by spaces template< class Istream_type, class Value_type > class Stream_reader { public: Stream_reader( Istream_type& is ) : iters_( is ) { } bool read_next( Value_type& value ) { return read_range( iters_.begin_, iters_.end_, value ); } private: typedef Multi_pass_iters< Istream_type > Mp_iters; Mp_iters iters_; }; template< class Istream_type, class Value_type > class Stream_reader_thrower { public: Stream_reader_thrower( Istream_type& is ) : iters_( is ) , posn_begin_( iters_.begin_, iters_.end_ ) , posn_end_( iters_.end_, iters_.end_ ) { } void read_next( Value_type& value ) { posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value ); } private: typedef Multi_pass_iters< Istream_type > Mp_iters; typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t; Mp_iters iters_; Posn_iter_t posn_begin_, posn_end_; }; } #endif ceph-0.80.11/src/json_spirit/json_spirit.h0000664000175100017510000000063512623076744022547 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT #define JSON_SPIRIT // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" #include "json_spirit_reader.h" #include "json_spirit_writer.h" #include "json_spirit_utils.h" #endif ceph-0.80.11/src/json_spirit/json_spirit_reader.h0000664000175100017510000000501312623076744024064 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_READER #define JSON_SPIRIT_READER // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" #include "json_spirit_error_position.h" #include namespace json_spirit { // functions to reads a JSON values #ifdef JSON_SPIRIT_VALUE_ENABLED bool read( const std::string& s, Value& value ); bool read( std::istream& is, Value& value ); bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); void read_or_throw( const std::string& s, Value& value ); void read_or_throw( std::istream& is, Value& value ); void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); #endif #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) bool read( const std::wstring& s, wValue& value ); bool read( std::wistream& is, wValue& value ); bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); void read_or_throw( const std::wstring& s, wValue& value ); void read_or_throw( std::wistream& is, wValue& value ); void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); #endif #ifdef JSON_SPIRIT_MVALUE_ENABLED bool read( const std::string& s, mValue& value ); bool read( std::istream& is, mValue& value ); bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); void read_or_throw( const std::string& s, mValue& value ); void read_or_throw( std::istream& is, mValue& value ); void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); #endif #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) bool read( const std::wstring& s, wmValue& value ); bool read( std::wistream& is, wmValue& value ); bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); void read_or_throw( const std::wstring& s, wmValue& value ); void read_or_throw( std::wistream& is, wmValue& value ); void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); #endif } #endif ceph-0.80.11/src/json_spirit/json_spirit_reader_template.h0000664000175100017510000005335612623076744025774 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_READER_TEMPLATE #define JSON_SPIRIT_READER_TEMPLATE // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" #include "json_spirit_error_position.h" #include "common/utf8.h" #define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread #include #include #include #if BOOST_VERSION >= 103800 #include #include #include #include #include #define spirit_namespace boost::spirit::classic #else #include #include #include #include #include #define spirit_namespace boost::spirit #endif namespace json_spirit { const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); template< class Iter_type > bool is_eq( Iter_type first, Iter_type last, const char* c_str ) { for( Iter_type i = first; i != last; ++i, ++c_str ) { if( *c_str == 0 ) return false; if( *i != *c_str ) return false; } return true; } template< class Char_type > Char_type hex_to_num( const Char_type c ) { if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; return 0; } template< class Char_type, class Iter_type > Char_type hex_str_to_char( Iter_type& begin ) { const Char_type c1( *( ++begin ) ); const Char_type c2( *( ++begin ) ); return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); } template< class String_type, class Iter_type > String_type unicode_str_to_utf8( Iter_type& begin ); template<> std::string unicode_str_to_utf8( std::string::const_iterator & begin ) { typedef std::string::value_type Char_type; const Char_type c1( *( ++begin ) ); const Char_type c2( *( ++begin ) ); const Char_type c3( *( ++begin ) ); const Char_type c4( *( ++begin ) ); unsigned long uc = ( hex_to_num( c1 ) << 12 ) + ( hex_to_num( c2 ) << 8 ) + ( hex_to_num( c3 ) << 4 ) + hex_to_num( c4 ); unsigned char buf[7]; // MAX_UTF8_SZ is 6 (see src/common/utf8.c) int r = encode_utf8(uc, buf); if (r >= 0) { return std::string(reinterpret_cast(buf), r); } return std::string("_"); } template< class String_type > void append_esc_char_and_incr_iter( String_type& s, typename String_type::const_iterator& begin, typename String_type::const_iterator end ) { typedef typename String_type::value_type Char_type; const Char_type c2( *begin ); switch( c2 ) { case 't': s += '\t'; break; case 'b': s += '\b'; break; case 'f': s += '\f'; break; case 'n': s += '\n'; break; case 'r': s += '\r'; break; case '\\': s += '\\'; break; case '/': s += '/'; break; case '"': s += '"'; break; case 'x': { if( end - begin >= 3 ) // expecting "xHH..." { s += hex_str_to_char< Char_type >( begin ); } break; } case 'u': { if( end - begin >= 5 ) // expecting "uHHHH..." { s += unicode_str_to_utf8< String_type >( begin ); } break; } } } template< class String_type > String_type substitute_esc_chars( typename String_type::const_iterator begin, typename String_type::const_iterator end ) { typedef typename String_type::const_iterator Iter_type; if( end - begin < 2 ) return String_type( begin, end ); String_type result; result.reserve( end - begin ); const Iter_type end_minus_1( end - 1 ); Iter_type substr_start = begin; Iter_type i = begin; for( ; i < end_minus_1; ++i ) { if( *i == '\\' ) { result.append( substr_start, i ); ++i; // skip the '\' append_esc_char_and_incr_iter( result, i, end ); substr_start = i + 1; } } result.append( substr_start, end ); return result; } template< class String_type > String_type get_str_( typename String_type::const_iterator begin, typename String_type::const_iterator end ) { assert( end - begin >= 2 ); typedef typename String_type::const_iterator Iter_type; Iter_type str_without_quotes( ++begin ); Iter_type end_without_quotes( --end ); return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); } inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) { return get_str_< std::string >( begin, end ); } // Need this guard else it tries to instantiate unicode_str_to_utf8 with a // std::wstring, which isn't presently implemented #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) { return get_str_< std::wstring >( begin, end ); } #endif template< class String_type, class Iter_type > String_type get_str( Iter_type begin, Iter_type end ) { const String_type tmp( begin, end ); // convert multipass iterators to string iterators return get_str( tmp.begin(), tmp.end() ); } // this class's methods get called by the spirit parse resulting // in the creation of a JSON object or array // // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator // template< class Value_type, class Iter_type > class Semantic_actions { public: typedef typename Value_type::Config_type Config_type; typedef typename Config_type::String_type String_type; typedef typename Config_type::Object_type Object_type; typedef typename Config_type::Array_type Array_type; typedef typename String_type::value_type Char_type; Semantic_actions( Value_type& value ) : value_( value ) , current_p_( 0 ) { } void begin_obj( Char_type c ) { assert( c == '{' ); begin_compound< Object_type >(); } void end_obj( Char_type c ) { assert( c == '}' ); end_compound(); } void begin_array( Char_type c ) { assert( c == '[' ); begin_compound< Array_type >(); } void end_array( Char_type c ) { assert( c == ']' ); end_compound(); } void new_name( Iter_type begin, Iter_type end ) { assert( current_p_->type() == obj_type ); name_ = get_str< String_type >( begin, end ); } void new_str( Iter_type begin, Iter_type end ) { add_to_current( get_str< String_type >( begin, end ) ); } void new_true( Iter_type begin, Iter_type end ) { assert( is_eq( begin, end, "true" ) ); add_to_current( true ); } void new_false( Iter_type begin, Iter_type end ) { assert( is_eq( begin, end, "false" ) ); add_to_current( false ); } void new_null( Iter_type begin, Iter_type end ) { assert( is_eq( begin, end, "null" ) ); add_to_current( Value_type() ); } void new_int( boost::int64_t i ) { add_to_current( i ); } void new_uint64( boost::uint64_t ui ) { add_to_current( ui ); } void new_real( double d ) { add_to_current( d ); } private: Semantic_actions& operator=( const Semantic_actions& ); // to prevent "assignment operator could not be generated" warning Value_type* add_first( const Value_type& value ) { assert( current_p_ == 0 ); value_ = value; current_p_ = &value_; return current_p_; } template< class Array_or_obj > void begin_compound() { if( current_p_ == 0 ) { add_first( Array_or_obj() ); } else { stack_.push_back( current_p_ ); Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place current_p_ = add_to_current( new_array_or_obj ); } } void end_compound() { if( current_p_ != &value_ ) { current_p_ = stack_.back(); stack_.pop_back(); } } Value_type* add_to_current( const Value_type& value ) { if( current_p_ == 0 ) { return add_first( value ); } else if( current_p_->type() == array_type ) { current_p_->get_array().push_back( value ); return ¤t_p_->get_array().back(); } assert( current_p_->type() == obj_type ); return &Config_type::add( current_p_->get_obj(), name_, value ); } Value_type& value_; // this is the object or array that is being created Value_type* current_p_; // the child object or array that is currently being constructed std::vector< Value_type* > stack_; // previous child objects and arrays String_type name_; // of current name/value pair }; template< typename Iter_type > void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) { throw Error_position( i.get_position().line, i.get_position().column, reason ); } template< typename Iter_type > void throw_error( Iter_type i, const std::string& reason ) { throw reason; } // the spirit grammer // template< class Value_type, class Iter_type > class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > { public: typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; Json_grammer( Semantic_actions_t& semantic_actions ) : actions_( semantic_actions ) { } static void throw_not_value( Iter_type begin, Iter_type end ) { throw_error( begin, "not a value" ); } static void throw_not_array( Iter_type begin, Iter_type end ) { throw_error( begin, "not an array" ); } static void throw_not_object( Iter_type begin, Iter_type end ) { throw_error( begin, "not an object" ); } static void throw_not_pair( Iter_type begin, Iter_type end ) { throw_error( begin, "not a pair" ); } static void throw_not_colon( Iter_type begin, Iter_type end ) { throw_error( begin, "no colon in pair" ); } static void throw_not_string( Iter_type begin, Iter_type end ) { throw_error( begin, "not a string" ); } template< typename ScannerT > class definition { public: definition( const Json_grammer& self ) { using namespace spirit_namespace; typedef typename Value_type::String_type::value_type Char_type; // first we convert the semantic action class methods to functors with the // parameter signature expected by spirit typedef boost::function< void( Char_type ) > Char_action; typedef boost::function< void( Iter_type, Iter_type ) > Str_action; typedef boost::function< void( double ) > Real_action; typedef boost::function< void( boost::int64_t ) > Int_action; typedef boost::function< void( boost::uint64_t ) > Uint64_action; Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); // actual grammer json_ = value_ | eps_p[ &throw_not_value ] ; value_ = string_[ new_str ] | number_ | object_ | array_ | str_p( "true" ) [ new_true ] | str_p( "false" )[ new_false ] | str_p( "null" ) [ new_null ] ; object_ = ch_p('{')[ begin_obj ] >> !members_ >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) ; members_ = pair_ >> *( ',' >> pair_ | ch_p(',') ) ; pair_ = string_[ new_name ] >> ( ':' | eps_p[ &throw_not_colon ] ) >> ( value_ | eps_p[ &throw_not_value ] ) ; array_ = ch_p('[')[ begin_array ] >> !elements_ >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) ; elements_ = value_ >> *( ',' >> value_ | ch_p(',') ) ; string_ = lexeme_d // this causes white space inside a string to be retained [ confix_p ( '"', *lex_escape_ch_p, '"' ) ] ; number_ = strict_real_p[ new_real ] | int64_p [ new_int ] | uint64_p [ new_uint64 ] ; } spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_; const spirit_namespace::rule< ScannerT >& start() const { return json_; } }; private: Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning Semantic_actions_t& actions_; }; template< class Iter_type, class Value_type > void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) { typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; const Posn_iter_t posn_begin( begin, end ); const Posn_iter_t posn_end( end, end ); read_range_or_throw( posn_begin, posn_end, value ); } template< class Istream_type > struct Multi_pass_iters { typedef typename Istream_type::char_type Char_type; typedef std::istream_iterator< Char_type, Char_type > istream_iter; typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; Multi_pass_iters( Istream_type& is ) { is.unsetf( std::ios::skipws ); begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); end_ = spirit_namespace::make_multi_pass( istream_iter() ); } Mp_iter begin_; Mp_iter end_; }; // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g. // // string::const_iterator start = str.begin(); // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value ); // // The iterator 'next' will point to the character past the // last one read. // template< class Iter_type, class Value_type > Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) { Semantic_actions< Value_type, Iter_type > semantic_actions( value ); const spirit_namespace::parse_info< Iter_type > info = spirit_namespace::parse( begin, end, Json_grammer< Value_type, Iter_type >( semantic_actions ), spirit_namespace::space_p ); if( !info.hit ) { assert( false ); // in theory exception should already have been thrown throw_error( info.stop, "error" ); } return info.stop; } // reads a JSON Value from a pair of input iterators, e.g. // // string::const_iterator start = str.begin(); // const bool success = read_string( start, str.end(), value ); // // The iterator 'start' will point to the character past the // last one read. // template< class Iter_type, class Value_type > bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) { try { begin = read_range_or_throw( begin, end, value ); return true; } catch( ... ) { return false; } } // reads a JSON Value from a string, e.g. // // const bool success = read_string( str, value ); // template< class String_type, class Value_type > bool read_string( const String_type& s, Value_type& value ) { typename String_type::const_iterator begin = s.begin(); return read_range( begin, s.end(), value ); } // reads a JSON Value from a string throwing an exception on invalid input, e.g. // // read_string_or_throw( is, value ); // template< class String_type, class Value_type > void read_string_or_throw( const String_type& s, Value_type& value ) { add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); } // reads a JSON Value from a stream, e.g. // // const bool success = read_stream( is, value ); // template< class Istream_type, class Value_type > bool read_stream( Istream_type& is, Value_type& value ) { Multi_pass_iters< Istream_type > mp_iters( is ); return read_range( mp_iters.begin_, mp_iters.end_, value ); } // reads a JSON Value from a stream throwing an exception on invalid input, e.g. // // read_stream_or_throw( is, value ); // template< class Istream_type, class Value_type > void read_stream_or_throw( Istream_type& is, Value_type& value ) { const Multi_pass_iters< Istream_type > mp_iters( is ); add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); } } #endif ceph-0.80.11/src/json_spirit/json_spirit_utils.h0000664000175100017510000000325312623076744023766 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_UTILS #define JSON_SPIRIT_UTILS // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" #include namespace json_spirit { template< class Obj_t, class Map_t > void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) { mp_obj.clear(); for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) { mp_obj[ i->name_ ] = i->value_; } } template< class Obj_t, class Map_t > void map_to_obj( const Map_t& mp_obj, Obj_t& obj ) { obj.clear(); for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i ) { obj.push_back( typename Obj_t::value_type( i->first, i->second ) ); } } #ifdef JSON_SPIRIT_VALUE_ENABLED typedef std::map< std::string, Value > Mapped_obj; #endif #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) typedef std::map< std::wstring, wValue > wMapped_obj; #endif template< class Object_type, class String_type > const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name ) { for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i ) { if( i->name_ == name ) { return i->value_; } } return Object_type::value_type::Value_type::null; } } #endif ceph-0.80.11/src/json_spirit/Makefile.am0000664000175100017510000000105412623076744022063 0ustar jenkins-buildjenkins-buildlibjson_spirit_la_SOURCES = \ json_spirit/json_spirit_reader.cpp \ json_spirit/json_spirit_writer.cpp noinst_LTLIBRARIES += libjson_spirit.la noinst_HEADERS += \ json_spirit/json_spirit.h \ json_spirit/json_spirit_error_position.h \ json_spirit/json_spirit_reader.h \ json_spirit/json_spirit_reader_template.h \ json_spirit/json_spirit_stream_reader.h \ json_spirit/json_spirit_utils.h \ json_spirit/json_spirit_value.h \ json_spirit/json_spirit_writer.h \ json_spirit/json_spirit_writer_options.h \ json_spirit/json_spirit_writer_template.h ceph-0.80.11/src/json_spirit/json_spirit_writer.cpp0000664000175100017510000000545412623076744024502 0ustar jenkins-buildjenkins-build// Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #include "json_spirit_writer.h" #include "json_spirit_writer_template.h" using namespace json_spirit; #ifdef JSON_SPIRIT_VALUE_ENABLED void json_spirit::write( const Value& value, std::ostream& os, unsigned int options ) { write_stream( value, os, options ); } std::string json_spirit::write( const Value& value, unsigned int options ) { return write_string( value, options ); } void json_spirit::write_formatted( const Value& value, std::ostream& os ) { write_stream( value, os, pretty_print ); } std::string json_spirit::write_formatted( const Value& value ) { return write_string( value, pretty_print ); } #endif #ifdef JSON_SPIRIT_MVALUE_ENABLED void json_spirit::write( const mValue& value, std::ostream& os, unsigned int options ) { write_stream( value, os, options ); } std::string json_spirit::write( const mValue& value, unsigned int options ) { return write_string( value, options ); } void json_spirit::write_formatted( const mValue& value, std::ostream& os ) { write_stream( value, os, pretty_print ); } std::string json_spirit::write_formatted( const mValue& value ) { return write_string( value, pretty_print ); } #endif #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void json_spirit::write( const wValue& value, std::wostream& os, unsigned int options ) { write_stream( value, os, options ); } std::wstring json_spirit::write( const wValue& value, unsigned int options ) { return write_string( value, options ); } void json_spirit::write_formatted( const wValue& value, std::wostream& os ) { write_stream( value, os, pretty_print ); } std::wstring json_spirit::write_formatted( const wValue& value ) { return write_string( value, pretty_print ); } #endif #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) { write_stream( value, os, pretty_print ); } std::wstring json_spirit::write_formatted( const wmValue& value ) { return write_string( value, pretty_print ); } void json_spirit::write( const wmValue& value, std::wostream& os, unsigned int options ) { write_stream( value, os, options ); } std::wstring json_spirit::write( const wmValue& value, unsigned int options ) { return write_string( value, options ); } #endif ceph-0.80.11/src/json_spirit/json_spirit_writer_template.h0000664000175100017510000002566712623076744026052 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_WRITER_TEMPLATE #define JSON_SPIRIT_WRITER_TEMPLATE // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" #include "json_spirit_writer_options.h" #include #include #include #include namespace json_spirit { inline char to_hex_char( unsigned int c ) { assert( c <= 0xF ); const char ch = static_cast< char >( c ); if( ch < 10 ) return '0' + ch; return 'A' - 10 + ch; } template< class String_type > String_type non_printable_to_string( unsigned int c ) { String_type result( 6, '\\' ); result[1] = 'u'; result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; result[ 2 ] = to_hex_char( c & 0x000F ); return result; } template< typename Char_type, class String_type > bool add_esc_char( Char_type c, String_type& s ) { switch( c ) { case '"': s += to_str< String_type >( "\\\"" ); return true; case '\\': s += to_str< String_type >( "\\\\" ); return true; case '\b': s += to_str< String_type >( "\\b" ); return true; case '\f': s += to_str< String_type >( "\\f" ); return true; case '\n': s += to_str< String_type >( "\\n" ); return true; case '\r': s += to_str< String_type >( "\\r" ); return true; case '\t': s += to_str< String_type >( "\\t" ); return true; } return false; } template< class String_type > String_type add_esc_chars( const String_type& s, bool raw_utf8 ) { typedef typename String_type::const_iterator Iter_type; typedef typename String_type::value_type Char_type; String_type result; const Iter_type end( s.end() ); for( Iter_type i = s.begin(); i != end; ++i ) { const Char_type c( *i ); if( add_esc_char( c, result ) ) continue; if( raw_utf8 ) { result += c; } else { const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); if( iswprint( unsigned_c ) ) { result += c; } else { result += non_printable_to_string< String_type >( unsigned_c ); } } } return result; } template< class Ostream > void append_double( Ostream& os, const double d, const int precision ) { os << std::showpoint << std::setprecision( precision ) << d; } template< class String_type > void erase_and_extract_exponent( String_type& str, String_type& exp ) { const typename String_type::size_type exp_start= str.find( 'e' ); if( exp_start != String_type::npos ) { exp = str.substr( exp_start ); str.erase( exp_start ); } } template< class String_type > typename String_type::size_type find_first_non_zero( const String_type& str ) { typename String_type::size_type result = str.size() - 1; for( ; result != 0; --result ) { if( str[ result ] != '0' ) { break; } } return result; } template< class String_type > void remove_trailing( String_type& str ) { String_type exp; erase_and_extract_exponent( str, exp ); const typename String_type::size_type first_non_zero = find_first_non_zero( str ); if( first_non_zero != 0 ) { const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard str.erase( first_non_zero + offset ); } str += exp; } // this class generates the JSON text, // it keeps track of the indentation level etc. // template< class Value_type, class Ostream_type > class Generator { typedef typename Value_type::Config_type Config_type; typedef typename Config_type::String_type String_type; typedef typename Config_type::Object_type Object_type; typedef typename Config_type::Array_type Array_type; typedef typename String_type::value_type Char_type; typedef typename Object_type::value_type Obj_member_type; public: Generator( const Value_type& value, Ostream_type& os, unsigned int options ) : os_( os ) , indentation_level_( 0 ) , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 ) , raw_utf8_( ( options & raw_utf8 ) != 0 ) , remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 ) , single_line_arrays_( ( options & single_line_arrays ) != 0 ) , ios_saver_( os ) { output( value ); } private: void output( const Value_type& value ) { switch( value.type() ) { case obj_type: output( value.get_obj() ); break; case array_type: output( value.get_array() ); break; case str_type: output( value.get_str() ); break; case bool_type: output( value.get_bool() ); break; case real_type: output( value.get_real() ); break; case int_type: output_int( value ); break; case null_type: os_ << "null"; break; default: assert( false ); } } void output( const Object_type& obj ) { output_array_or_obj( obj, '{', '}' ); } void output( const Obj_member_type& member ) { output( Config_type::get_name( member ) ); space(); os_ << ':'; space(); output( Config_type::get_value( member ) ); } void output_int( const Value_type& value ) { if( value.is_uint64() ) { os_ << value.get_uint64(); } else { os_ << value.get_int64(); } } void output( const String_type& s ) { os_ << '"' << add_esc_chars( s, raw_utf8_ ) << '"'; } void output( bool b ) { os_ << to_str< String_type >( b ? "true" : "false" ); } void output( double d ) { if( remove_trailing_zeros_ ) { std::basic_ostringstream< Char_type > os; append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove, // otherwise, 0.1234 gets converted to "0.12399999..." String_type str = os.str(); remove_trailing( str ); os_ << str; } else { append_double( os_, d, 17 ); } } static bool contains_composite_elements( const Array_type& arr ) { for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) { const Value_type& val = *i; if( val.type() == obj_type || val.type() == array_type ) { return true; } } return false; } template< class Iter > void output_composite_item( Iter i, Iter last ) { output( *i ); if( ++i != last ) { os_ << ','; } } void output( const Array_type& arr ) { if( single_line_arrays_ && !contains_composite_elements( arr ) ) { os_ << '['; space(); for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) { output_composite_item( i, arr.end() ); space(); } os_ << ']'; } else { output_array_or_obj( arr, '[', ']' ); } } template< class T > void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) { os_ << start_char; new_line(); ++indentation_level_; for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) { indent(); output_composite_item( i, t.end() ); new_line(); } --indentation_level_; indent(); os_ << end_char; } void indent() { if( !pretty_ ) return; for( int i = 0; i < indentation_level_; ++i ) { os_ << " "; } } void space() { if( pretty_ ) os_ << ' '; } void new_line() { if( pretty_ ) os_ << '\n'; } Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning Ostream_type& os_; int indentation_level_; bool pretty_; bool raw_utf8_; bool remove_trailing_zeros_; bool single_line_arrays_; boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller }; // writes JSON Value to a stream, e.g. // // write_stream( value, os, pretty_print ); // template< class Value_type, class Ostream_type > void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 ) { os << std::dec; Generator< Value_type, Ostream_type >( value, os, options ); } // writes JSON Value to a stream, e.g. // // const string json_str = write( value, pretty_print ); // template< class Value_type > typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 ) { typedef typename Value_type::String_type::value_type Char_type; std::basic_ostringstream< Char_type > os; write_stream( value, os, options ); return os.str(); } } #endif ceph-0.80.11/src/json_spirit/json_spirit_writer_options.h0000664000175100017510000000253312623076744025715 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_WRITER_OPTIONS #define JSON_SPIRIT_WRITER_OPTIONS // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif namespace json_spirit { enum Output_options{ pretty_print = 0x01, // Add whitespace to format the output nicely. raw_utf8 = 0x02, // This prevents non-printable characters from being escapted using "\uNNNN" notation. // Note, this is an extension to the JSON standard. It disables the escaping of // non-printable characters allowing UTF-8 sequences held in 8 bit char strings // to pass through unaltered. remove_trailing_zeros = 0x04, // outputs e.g. "1.200000000000000" as "1.2" single_line_arrays = 0x08, // pretty printing except that arrays printed on single lines unless they contain // composite elements, i.e. objects or arrays }; } #endif ceph-0.80.11/src/json_spirit/json_spirit_reader.cpp0000664000175100017510000001001212623076744024412 0ustar jenkins-buildjenkins-build// Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #include "json_spirit_reader.h" #include "json_spirit_reader_template.h" using namespace json_spirit; #ifdef JSON_SPIRIT_VALUE_ENABLED bool json_spirit::read( const std::string& s, Value& value ) { return read_string( s, value ); } void json_spirit::read_or_throw( const std::string& s, Value& value ) { read_string_or_throw( s, value ); } bool json_spirit::read( std::istream& is, Value& value ) { return read_stream( is, value ); } void json_spirit::read_or_throw( std::istream& is, Value& value ) { read_stream_or_throw( is, value ); } bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) { return read_range( begin, end, value ); } void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) { begin = read_range_or_throw( begin, end, value ); } #endif #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) bool json_spirit::read( const std::wstring& s, wValue& value ) { return read_string( s, value ); } void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) { read_string_or_throw( s, value ); } bool json_spirit::read( std::wistream& is, wValue& value ) { return read_stream( is, value ); } void json_spirit::read_or_throw( std::wistream& is, wValue& value ) { read_stream_or_throw( is, value ); } bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) { return read_range( begin, end, value ); } void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) { begin = read_range_or_throw( begin, end, value ); } #endif #ifdef JSON_SPIRIT_MVALUE_ENABLED bool json_spirit::read( const std::string& s, mValue& value ) { return read_string( s, value ); } void json_spirit::read_or_throw( const std::string& s, mValue& value ) { read_string_or_throw( s, value ); } bool json_spirit::read( std::istream& is, mValue& value ) { return read_stream( is, value ); } void json_spirit::read_or_throw( std::istream& is, mValue& value ) { read_stream_or_throw( is, value ); } bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) { return read_range( begin, end, value ); } void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) { begin = read_range_or_throw( begin, end, value ); } #endif #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) bool json_spirit::read( const std::wstring& s, wmValue& value ) { return read_string( s, value ); } void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) { read_string_or_throw( s, value ); } bool json_spirit::read( std::wistream& is, wmValue& value ) { return read_stream( is, value ); } void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) { read_stream_or_throw( is, value ); } bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) { return read_range( begin, end, value ); } void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) { begin = read_range_or_throw( begin, end, value ); } #endif ceph-0.80.11/src/json_spirit/json_spirit_writer.h0000664000175100017510000000447412623076744024150 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_WRITER #define JSON_SPIRIT_WRITER // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" #include "json_spirit_writer_options.h" #include namespace json_spirit { // these functions to convert JSON Values to text #ifdef JSON_SPIRIT_VALUE_ENABLED void write( const Value& value, std::ostream& os, unsigned int options = 0 ); std::string write( const Value& value, unsigned int options = 0 ); #endif #ifdef JSON_SPIRIT_MVALUE_ENABLED void write( const mValue& value, std::ostream& os, unsigned int options = 0 ); std::string write( const mValue& value, unsigned int options = 0 ); #endif #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void write( const wValue& value, std::wostream& os, unsigned int options = 0 ); std::wstring write( const wValue& value, unsigned int options = 0 ); #endif #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void write( const wmValue& value, std::wostream& os, unsigned int options = 0 ); std::wstring write( const wmValue& value, unsigned int options = 0 ); #endif // these "formatted" versions of the "write" functions are the equivalent of the above functions // with option "pretty_print" #ifdef JSON_SPIRIT_VALUE_ENABLED void write_formatted( const Value& value, std::ostream& os ); std::string write_formatted( const Value& value ); #endif #ifdef JSON_SPIRIT_MVALUE_ENABLED void write_formatted( const mValue& value, std::ostream& os ); std::string write_formatted( const mValue& value ); #endif #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void write_formatted( const wValue& value, std::wostream& os ); std::wstring write_formatted( const wValue& value ); #endif #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void write_formatted( const wmValue& value, std::wostream& os ); std::wstring write_formatted( const wmValue& value ); #endif } #endif ceph-0.80.11/src/json_spirit/json_spirit_error_position.h0000664000175100017510000000275312623076744025707 0ustar jenkins-buildjenkins-build#ifndef JSON_SPIRIT_ERROR_POSITION #define JSON_SPIRIT_ERROR_POSITION // Copyright John W. Wilkinson 2007 - 2011 // Distributed under the MIT License, see accompanying file LICENSE.txt // json spirit version 4.05 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include namespace json_spirit { // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" // functions that return a bool. // struct Error_position { Error_position(); Error_position( unsigned int line, unsigned int column, const std::string& reason ); bool operator==( const Error_position& lhs ) const; unsigned int line_; unsigned int column_; std::string reason_; }; inline Error_position::Error_position() : line_( 0 ) , column_( 0 ) { } inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) : line_( line ) , column_( column ) , reason_( reason ) { } inline bool Error_position::operator==( const Error_position& lhs ) const { if( this == &lhs ) return true; return ( reason_ == lhs.reason_ ) && ( line_ == lhs.line_ ) && ( column_ == lhs.column_ ); } } #endif ceph-0.80.11/src/Makefile-env.am0000664000175100017510000001051212623076744020305 0ustar jenkins-buildjenkins-buildAUTOMAKE_OPTIONS = gnu subdir-objects SUBDIRS = DIST_SUBDIRS = BUILT_SOURCES = EXTRA_DIST = CLEANFILES = noinst_HEADERS = bin_PROGRAMS = noinst_PROGRAMS = bin_SCRIPTS = sbin_PROGRAMS = sbin_SCRIPTS = su_sbin_PROGRAMS = su_sbin_SCRIPTS = dist_bin_SCRIPTS = lib_LTLIBRARIES = noinst_LTLIBRARIES = noinst_LIBRARIES = radoslib_LTLIBRARIES = # like bin_PROGRAMS, but these targets are only built for debug builds bin_DEBUGPROGRAMS = # like sbin_SCRIPTS but can be used to install to e.g. /usr/sbin ceph_sbindir = $(sbindir) # certain things go straight into /sbin, though! su_sbindir = /sbin # C/C++ tests to build will be appended to this check_PROGRAMS = # tests scripts will be appended to this check_SCRIPTS = # python unit tests need to know where the scripts are located export PYTHONPATH=$(top_srcdir)/src/pybind # when doing a debug build, make sure to make the targets if WITH_DEBUG bin_PROGRAMS += $(bin_DEBUGPROGRAMS) endif ################################## ## automake environment AM_COMMON_CPPFLAGS = \ -D__CEPH__ \ -D_FILE_OFFSET_BITS=64 \ -D_REENTRANT \ -D_THREAD_SAFE \ -D__STDC_FORMAT_MACROS \ -D_GNU_SOURCE \ -DCEPH_LIBDIR=\"${libdir}\" \ -DCEPH_PKGLIBDIR=\"${pkglibdir}\" \ -DGTEST_HAS_TR1_TUPLE=0 AM_COMMON_CFLAGS = \ -Wall \ ${WARN_TYPE_LIMITS} \ ${WARN_IGNORED_QUALIFIERS} \ -Winit-self \ -Wpointer-arith \ -Werror=format-security \ -fno-strict-aliasing \ -fsigned-char if !CLANG AM_COMMON_CFLAGS += -rdynamic endif AM_CFLAGS = $(AM_COMMON_CFLAGS) AM_CPPFLAGS = $(AM_COMMON_CPPFLAGS) AM_CXXFLAGS = \ @AM_CXXFLAGS@ \ $(AM_COMMON_CFLAGS) \ -ftemplate-depth-1024 \ -Wnon-virtual-dtor \ -Wno-invalid-offsetof if !CLANG AM_CXXFLAGS += -Wstrict-null-sentinel endif # note: this is position dependant, it affects the -l options that # come after it on the command line. when you use ${AM_LDFLAGS} in # later rules, take care where you place it. for more information, see # http://blog.flameeyes.eu/2008/11/19/relationship-between-as-needed-and-no-undefined-part-1-what-do-they-do # http://blog.flameeyes.eu/2008/11/20/misguided-link-and-as-needed # http://www.gentoo.org/proj/en/qa/asneeded.xml # http://gcc.gnu.org/ml/gcc-help/2010-12/msg00338.html # http://sigquit.wordpress.com/2011/02/16/why-asneeded-doesnt-work-as-expected-for-your-libraries-on-your-autotools-project/ AM_LDFLAGS = if LINUX AM_LDFLAGS += -Wl,--as-needed endif if USE_BOOST_SPIRIT_OLD_HDR AM_CXXFLAGS += -DUSE_BOOST_SPIRIT_OLD_HDR endif if WITH_LIBATOMIC AM_LDFLAGS += -latomic_ops endif if ENABLE_COVERAGE AM_CFLAGS += -fprofile-arcs -ftest-coverage AM_CXXFLAGS += -fprofile-arcs -ftest-coverage -O0 endif CCAS = ${srcdir}/yasm-wrapper AM_CCASFLAGS = -f elf64 ##################### ## library definitions and dependencies EXTRALIBS = -luuid -lm if FREEBSD EXTRALIBS += -lexecinfo endif # FREEBSD if LINUX EXTRALIBS += -lrt endif # LINUX if WITH_PROFILER EXTRALIBS += -lprofiler endif # PROFILER LIBGLOBAL = libglobal.la LIBCOMMON = libcommon.la LIBARCH = libarch.la LIBPERFGLUE = libperfglue.la LIBAUTH = libauth.la LIBMSG = libmsg.la LIBCRUSH = libcrush.la LIBJSON_SPIRIT = libjson_spirit.la LIBLOG = liblog.la LIBOS = libos.la LIBOS_TYPES = libos_types.la LIBOSD = libosd.la LIBOSD_TYPES = libosd_types.la LIBOSDC = libosdc.la LIBMON = libmon.la LIBMON_TYPES = libmon_types.la LIBMDS = libmds.la LIBCLIENT = libclient.la LIBCLIENT_FUSE = libclient_fuse.la LIBRADOS = librados.la LIBRGW = librgw.la LIBCIVETWEB = libcivetweb.la LIBRBD = librbd.la LIBCEPHFS = libcephfs.la LIBERASURE_CODE = liberasure_code.la if WITH_LIBAIO LIBOS += -laio endif # WITH_LIBAIO if WITH_LIBZFS LIBOS += libos_zfs.a -lzfs endif # WITH_LIBZFS if WITH_TCMALLOC LIBPERFGLUE += -ltcmalloc endif # WITH_TCMALLOC if ENABLE_COVERAGE EXTRALIBS += -lgcov endif # ENABLE_COVERAGE # Libosd always needs osdc and os LIBOSD += $(LIBOSDC) $(LIBOS) # These have references to syms like ceph_using_tcmalloc(), glue libperfglue to them LIBMON += $(LIBPERFGLUE) LIBOSD += $(LIBPERFGLUE) LIBMDS += $(LIBPERFGLUE) # Always use system leveldb LIBOS += -lleveldb -lsnappy # Use this for binaries requiring libglobal CEPH_GLOBAL = $(LIBGLOBAL) $(LIBCOMMON) $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) # This is set by [lib]/Makefile.am and used for build tests LIBCOMMON_DEPS = LIBRADOS_DEPS = LIBRGW_DEPS = # This is used by the dencoder test DENCODER_SOURCES = DENCODER_DEPS = radoslibdir = $(libdir)/rados-classes ceph-0.80.11/src/init-rbdmap0000775000175100017510000000375312623076744017630 0ustar jenkins-buildjenkins-build#!/bin/bash # # rbdmap Ceph RBD Mapping # # chkconfig: 2345 20 80 # description: Ceph RBD Mapping ### BEGIN INIT INFO # Provides: rbdmap # Required-Start: $network $remote_fs # Required-Stop: $network $remote_fs # Should-Start: ceph # Should-Stop: ceph # X-Start-Before: $x-display-manager # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Ceph RBD Mapping # Description: Ceph RBD Mapping ### END INIT INFO DESC="RBD Mapping" RBDMAPFILE="/etc/ceph/rbdmap" . /lib/lsb/init-functions do_map() { if [ ! -f "$RBDMAPFILE" ]; then log_warning_msg "$DESC : No $RBDMAPFILE found." exit 0 fi log_daemon_msg "Starting $DESC" # Read /etc/rbdtab to create non-existant mapping newrbd= RET=0 while read DEV PARAMS; do case "$DEV" in ""|\#*) continue ;; */*) ;; *) DEV=rbd/$DEV ;; esac OIFS=$IFS IFS=',' for PARAM in ${PARAMS[@]}; do CMDPARAMS="$CMDPARAMS --$(echo $PARAM | tr '=' ' ')" done IFS=$OIFS if [ ! -b /dev/rbd/$DEV ]; then log_progress_msg $DEV rbd map $DEV $CMDPARAMS [ $? -ne "0" ] && RET=1 newrbd="yes" fi done < $RBDMAPFILE log_end_msg $RET # Mount new rbd if [ "$newrbd" ]; then log_action_begin_msg "Mounting all filesystems" mount -a log_action_end_msg $? fi } do_unmap() { log_daemon_msg "Stopping $DESC" RET=0 # Recursive umount that depends /dev/rbd* MNTDEP=$(findmnt --mtab | awk '$2 ~ /^\/dev\/rbd[0-9]*$/ {print $1}' | sort -r) for MNT in $MNTDEP; do umount $MNT done # Unmap all rbd device if ls /dev/rbd[0-9]* >/dev/null 2>&1; then for DEV in /dev/rbd[0-9]*; do log_progress_msg $DEV rbd unmap $DEV [ $? -ne "0" ] && RET=1 done fi log_end_msg $RET } case "$1" in start) do_map ;; stop) do_unmap ;; restart|force-reload) $0 stop $0 start ;; reload) do_map ;; status) rbd showmapped ;; *) log_success_msg "Usage: rbdmap {start|stop|restart|force-reload|reload|status}" exit 1 ;; esac exit 0 ceph-0.80.11/src/make_version0000775000175100017510000000053312623076744020075 0ustar jenkins-buildjenkins-build#!/bin/sh echo '$1: '$1 if [ "$1" = "-n" ] ; then cur="no_version" v="Development" else cur=`head -1 $1` v=`tail -1 $1 | cut -c 2-` fi print_all() { echo "#ifndef CEPH_VERSION_H" echo "#define CEPH_VERSION_H" echo echo "#define CEPH_GIT_VER $cur" echo "#define CEPH_GIT_NICE_VER \"$v\"" echo echo "#endif" } print_all > $2 ceph-0.80.11/src/libs3/0000775000175100017510000000000012623077036016473 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/inc/0000775000175100017510000000000012623076753017251 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/inc/response_headers_handler.h0000664000175100017510000000442412623076753024454 0ustar jenkins-buildjenkins-build/** ************************************************************************** * response_headers_handler.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef RESPONSE_HEADERS_HANDLER_H #define RESPONSE_HEADERS_HANDLER_H #include "libs3.h" #include "string_buffer.h" #include "util.h" typedef struct ResponseHeadersHandler { // The structure to pass to the headers callback. This is filled in by // the ResponseHeadersHandler from the headers added to it. S3ResponseProperties responseProperties; // Set to 1 after the done call has been made int done; // copied into here. We allow 128 bytes for each header, plus \0 term. string_multibuffer(responsePropertyStrings, 5 * 129); // responseproperties.metaHeaders strings get copied into here string_multibuffer(responseMetaDataStrings, COMPACTED_METADATA_BUFFER_SIZE); // Response meta data S3NameValue responseMetaData[S3_MAX_METADATA_COUNT]; } ResponseHeadersHandler; void response_headers_handler_initialize(ResponseHeadersHandler *handler); void response_headers_handler_add(ResponseHeadersHandler *handler, char *data, int dataLen); void response_headers_handler_done(ResponseHeadersHandler *handler, CURL *curl); #endif /* RESPONSE_HEADERS_HANDLER_H */ ceph-0.80.11/src/libs3/inc/request_context.h0000664000175100017510000000241212623076753022655 0ustar jenkins-buildjenkins-build/** ************************************************************************** * request_context.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef REQUEST_CONTEXT_H #define REQUEST_CONTEXT_H #include "libs3.h" struct S3RequestContext { CURLM *curlm; struct Request *requests; }; #endif /* REQUEST_CONTEXT_H */ ceph-0.80.11/src/libs3/inc/string_buffer.h0000664000175100017510000001141012623076753022256 0ustar jenkins-buildjenkins-build/** ************************************************************************** * string_buffer.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef STRING_BUFFER_H #define STRING_BUFFER_H #include // Declare a string_buffer with the given name of the given maximum length #define string_buffer(name, len) \ char name[len + 1]; \ int name##Len // Initialize a string_buffer #define string_buffer_initialize(sb) \ do { \ sb[0] = 0; \ sb##Len = 0; \ } while (0) // Append [len] bytes of [str] to [sb], setting [all_fit] to 1 if it fit, and // 0 if it did not #define string_buffer_append(sb, str, len, all_fit) \ do { \ sb##Len += snprintf(&(sb[sb##Len]), sizeof(sb) - sb##Len - 1, \ "%.*s", (int) (len), str); \ if (sb##Len > (int) (sizeof(sb) - 1)) { \ sb##Len = sizeof(sb) - 1; \ all_fit = 0; \ } \ else { \ all_fit = 1; \ } \ } while (0) // Declare a string multibuffer with the given name of the given maximum size #define string_multibuffer(name, size) \ char name[size]; \ int name##Size // Initialize a string_multibuffer #define string_multibuffer_initialize(smb) \ do { \ smb##Size = 0; \ } while (0) // Evaluates to the current string within the string_multibuffer #define string_multibuffer_current(smb) \ &(smb[smb##Size]) // Adds a new string to the string_multibuffer #define string_multibuffer_add(smb, str, len, all_fit) \ do { \ smb##Size += (snprintf(&(smb[smb##Size]), \ sizeof(smb) - smb##Size, \ "%.*s", (int) (len), str) + 1); \ if (smb##Size > (int) sizeof(smb)) { \ smb##Size = sizeof(smb); \ all_fit = 0; \ } \ else { \ all_fit = 1; \ } \ } while (0) // Appends to the current string in the string_multibuffer. There must be a // current string, meaning that string_multibuffer_add must have been called // at least once for this string_multibuffer. #define string_multibuffer_append(smb, str, len, all_fit) \ do { \ smb##Size--; \ string_multibuffer_add(smb, str, len, all_fit); \ } while (0) #endif /* STRING_BUFFER_H */ ceph-0.80.11/src/libs3/inc/simplexml.h0000664000175100017510000000444712623076753021445 0ustar jenkins-buildjenkins-build/** ************************************************************************** * simplexml.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef SIMPLEXML_H #define SIMPLEXML_H #include "libs3.h" // Simple XML callback. // // elementPath: is the full "path" of the element; i.e. // data would have 'data' in the element // foo/bar/baz. // // Return of anything other than S3StatusOK causes the calling // simplexml_add() function to immediately stop and return the status. // // data is passed in as 0 on end of element typedef S3Status (SimpleXmlCallback)(const char *elementPath, const char *data, int dataLen, void *callbackData); typedef struct SimpleXml { void *xmlParser; SimpleXmlCallback *callback; void *callbackData; char elementPath[512]; int elementPathLen; S3Status status; } SimpleXml; // Simple XML parsing // ---------------------------------------------------------------------------- // Always call this, even if the simplexml doesn't end up being used void simplexml_initialize(SimpleXml *simpleXml, SimpleXmlCallback *callback, void *callbackData); S3Status simplexml_add(SimpleXml *simpleXml, const char *data, int dataLen); // Always call this void simplexml_deinitialize(SimpleXml *simpleXml); #endif /* SIMPLEXML_H */ ceph-0.80.11/src/libs3/inc/error_parser.h0000664000175100017510000000512712623076753022134 0ustar jenkins-buildjenkins-build/** ************************************************************************** * error_parser.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef ERROR_PARSER_H #define ERROR_PARSER_H #include "libs3.h" #include "simplexml.h" #include "string_buffer.h" #define EXTRA_DETAILS_SIZE 8 typedef struct ErrorParser { // This is the S3ErrorDetails that this ErrorParser fills in from the // data that it parses S3ErrorDetails s3ErrorDetails; // This is the error XML parser SimpleXml errorXmlParser; // Set to 1 after the first call to add int errorXmlParserInitialized; // Used to buffer the S3 Error Code as it is read in string_buffer(code, 1024); // Used to buffer the S3 Error Message as it is read in string_buffer(message, 1024); // Used to buffer the S3 Error Resource as it is read in string_buffer(resource, 1024); // Used to buffer the S3 Error Further Details as it is read in string_buffer(furtherDetails, 1024); // The extra details; we support up to EXTRA_DETAILS_SIZE of them S3NameValue extraDetails[EXTRA_DETAILS_SIZE]; // This is the buffer from which the names and values used in extraDetails // are allocated string_multibuffer(extraDetailsNamesValues, EXTRA_DETAILS_SIZE * 1024); } ErrorParser; // Always call this void error_parser_initialize(ErrorParser *errorParser); S3Status error_parser_add(ErrorParser *errorParser, char *buffer, int bufferSize); void error_parser_convert_status(ErrorParser *errorParser, S3Status *status); // Always call this void error_parser_deinitialize(ErrorParser *errorParser); #endif /* ERROR_PARSER_H */ ceph-0.80.11/src/libs3/inc/request.h0000664000175100017510000001341312623076753021114 0ustar jenkins-buildjenkins-build/** ************************************************************************** * request.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef REQUEST_H #define REQUEST_H #include "libs3.h" #include "error_parser.h" #include "response_headers_handler.h" #include "util.h" // Describes a type of HTTP request (these are our supported HTTP "verbs") typedef enum { HttpRequestTypeGET, HttpRequestTypeHEAD, HttpRequestTypePUT, HttpRequestTypeCOPY, HttpRequestTypeDELETE } HttpRequestType; // This completely describes a request. A RequestParams is not required to be // allocated from the heap and its lifetime is not assumed to extend beyond // the lifetime of the function to which it has been passed. typedef struct RequestParams { // Request type, affects the HTTP verb used HttpRequestType httpRequestType; // Bucket context for request S3BucketContext bucketContext; // Key, if any const char *key; // Query params - ready to append to URI (i.e. ?p1=v1?p2=v2) const char *queryParams; // sub resource, like ?acl, ?location, ?torrent, ?logging const char *subResource; // If this is a copy operation, this gives the source bucket const char *copySourceBucketName; // If this is a copy operation, this gives the source key const char *copySourceKey; // Get conditions const S3GetConditions *getConditions; // Start byte uint64_t startByte; // Byte count uint64_t byteCount; // Put properties const S3PutProperties *putProperties; // Callback to be made when headers are available. Might not be called. S3ResponsePropertiesCallback *propertiesCallback; // Callback to be made to supply data to send to S3. Might not be called. S3PutObjectDataCallback *toS3Callback; // Number of bytes total that readCallback will supply int64_t toS3CallbackTotalSize; // Callback to be made that supplies data read from S3. // Might not be called. S3GetObjectDataCallback *fromS3Callback; // Callback to be made when request is complete. This will *always* be // called. S3ResponseCompleteCallback *completeCallback; // Data passed to the callbacks void *callbackData; } RequestParams; // This is the stuff associated with a request that needs to be on the heap // (and thus live while a curl_multi is in use). typedef struct Request { // These put the request on a doubly-linked list of requests in a // request context, *if* the request is in a request context (else these // will both be 0) struct Request *prev, *next; // The status of this Request, as will be reported to the user via the // complete callback S3Status status; // The HTTP code returned by the S3 server, if it is known. Would rather // not have to keep track of this but S3 doesn't always indicate its // errors the same way int httpResponseCode; // The HTTP headers to use for the curl request struct curl_slist *headers; // The CURL structure driving the request CURL *curl; // libcurl requires that the uri be stored outside of the curl handle char uri[MAX_URI_SIZE + 1]; // Callback to be made when headers are available. Might not be called. S3ResponsePropertiesCallback *propertiesCallback; // Callback to be made to supply data to send to S3. Might not be called. S3PutObjectDataCallback *toS3Callback; // Number of bytes total that readCallback has left to supply int64_t toS3CallbackBytesRemaining; // Callback to be made that supplies data read from S3. // Might not be called. S3GetObjectDataCallback *fromS3Callback; // Callback to be made when request is complete. This will *always* be // called. S3ResponseCompleteCallback *completeCallback; // Data passed to the callbacks void *callbackData; // Handler of response headers ResponseHeadersHandler responseHeadersHandler; // This is set to nonzero after the properties callback has been made int propertiesCallbackMade; // Parser of errors ErrorParser errorParser; } Request; // Request functions // ---------------------------------------------------------------------------- // Initialize the API S3Status request_api_initialize(const char *userAgentInfo, int flags, const char *hostName); // Deinitialize the API void request_api_deinitialize(); // Perform a request; if context is 0, performs the request immediately; // otherwise, sets it up to be performed by context. void request_perform(const RequestParams *params, S3RequestContext *context); // Called by the internal request code or internal request context code when a // curl has finished the request void request_finish(Request *request); // Convert a CURLE code to an S3Status S3Status request_curl_code_to_status(CURLcode code); #endif /* REQUEST_H */ ceph-0.80.11/src/libs3/inc/mingw/0000775000175100017510000000000012623076753020372 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/inc/mingw/pthread.h0000664000175100017510000000305112623076753022171 0ustar jenkins-buildjenkins-build/** ************************************************************************** * pthread.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef PTHREAD_H #define PTHREAD_H // This is a minimal implementation of pthreads on Windows, implementing just // the APIs needed by libs3 unsigned long pthread_self(); typedef struct { CRITICAL_SECTION criticalSection; } pthread_mutex_t; int pthread_mutex_init(pthread_mutex_t *mutex, void *); int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_destroy(pthread_mutex_t *mutex); #endif /* PTHREAD_H */ ceph-0.80.11/src/libs3/inc/mingw/sys/0000775000175100017510000000000012623076753021210 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/inc/mingw/sys/utsname.h0000664000175100017510000000252112623076753023035 0ustar jenkins-buildjenkins-build/** ************************************************************************** * utsname.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ // This file is used only on a MingW build, and provides an implementation // of POSIX sys/utsname.h #ifndef UTSNAME_H #define UTSNAME_H struct utsname { const char *sysname; const char *machine; }; int uname(struct utsname *); #endif /* UTSNAME_H */ ceph-0.80.11/src/libs3/inc/mingw/sys/select.h0000664000175100017510000000232112623076753022636 0ustar jenkins-buildjenkins-build/** ************************************************************************** * select.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ // This file is used only on a MingW build, and converts an include of // sys/select.h to its Windows equivalent #include ceph-0.80.11/src/libs3/inc/libs3.h0000664000175100017510000024077712623076753020457 0ustar jenkins-buildjenkins-build/** ************************************************************************** * libs3.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef LIBS3_H #define LIBS3_H #include #include #ifdef __cplusplus extern "C" { #endif /** ************************************************************************** * Overview * -------- * * This library provides an API for using Amazon's S3 service (see * http://s3.amazonaws.com). Its design goals are: * * - To provide a simple and straightforward API for accessing all of S3's * functionality * - To not require the developer using libs3 to need to know anything about: * - HTTP * - XML * - SSL * In other words, this API is meant to stand on its own, without requiring * any implicit knowledge of how S3 services are accessed using HTTP * protocols. * - To be usable from multithreaded code * - To be usable by code which wants to process multiple S3 requests * simultaneously from a single thread * - To be usable in the simple, straightforward way using sequentialized * blocking requests * * The general usage pattern of libs3 is: * * - Initialize libs3 once per program by calling S3_initialize() at program * start up time * - Make any number of requests to S3 for getting, putting, or listing * S3 buckets or objects, or modifying the ACLs associated with buckets * or objects, using one of three general approaches: * 1. Simple blocking requests, one at a time * 2. Multiple threads each making simple blocking requests * 3. From a single thread, managing multiple S3 requests simultaneously * using file descriptors and a select()/poll() loop * - Shut down libs3 at program exit time by calling S3_deinitialize() * * All functions which send requests to S3 return their results via a set of * callback functions which must be supplied to libs3 at the time that the * request is initiated. libs3 will call these functions back in the thread * calling the libs3 function if blocking requests are made (i.e., if the * S3RequestContext for the function invocation is passed in as NULL). * If an S3RequestContext is used to drive multiple S3 requests * simultaneously, then the callbacks will be made from the thread which * calls S3_runall_request_context() or S3_runonce_request_context(), or * possibly from the thread which calls S3_destroy_request_context(), if * S3 requests are in progress at the time that this function is called. * * NOTE: Response headers from Amazon S3 are limited to 4K (2K of metas is all * that Amazon supports, and libs3 allows Amazon an additional 2K of headers). * * NOTE: Because HTTP and the S3 REST protocol are highly under-specified, * libs3 must make some assumptions about the maximum length of certain HTTP * elements (such as headers) that it will accept. While efforts have been * made to enforce maximums which are beyond that expected to be needed by any * user of S3, it is always possible that these maximums may be too low in * some rare circumstances. Bug reports should this unlikely situation occur * would be most appreciated. * * Threading Rules * --------------- * * 1. All arguments passed to any function must not be modified directly until * the function returns. * 2. All S3RequestContext and S3Request arguments passed to all functions may * not be passed to any other libs3 function by any other thread until the * function returns. * 3. All functions may be called simultaneously by multiple threads as long * as (1) and (2) are observed, EXCEPT for S3_initialize(), which must be * called from one thread at a time only. * 4. All callbacks will be made in the thread of the caller of the function * which invoked them, so the caller of all libs3 functions should not hold * locks that it would try to re-acquire in a callback, as this may * deadlock. ************************************************************************** **/ /** ************************************************************************** * Constants ************************************************************************** **/ /** * S3_MAX_HOSTNAME_SIZE is the maximum size we allow for a host name **/ #define S3_MAX_HOSTNAME_SIZE 255 /** * This is the default hostname that is being used for the S3 requests **/ #define S3_DEFAULT_HOSTNAME "s3.amazonaws.com" /** * S3_MAX_BUCKET_NAME_SIZE is the maximum size of a bucket name. **/ #define S3_MAX_BUCKET_NAME_SIZE 255 /** * S3_MAX_KEY_SIZE is the maximum size of keys that Amazon S3 supports. **/ #define S3_MAX_KEY_SIZE 1024 /** * S3_MAX_METADATA_SIZE is the maximum number of bytes allowed for * x-amz-meta header names and values in any request passed to Amazon S3 **/ #define S3_MAX_METADATA_SIZE 2048 /** * S3_METADATA_HEADER_NAME_PREFIX is the prefix of an S3 "meta header" **/ #define S3_METADATA_HEADER_NAME_PREFIX "x-amz-meta-" /** * S3_MAX_METADATA_COUNT is the maximum number of x-amz-meta- headers that * could be included in a request to S3. The smallest meta header is * "x-amz-meta-n: v". Since S3 doesn't count the ": " against the total, the * smallest amount of data to count for a header would be the length of * "x-amz-meta-nv". **/ #define S3_MAX_METADATA_COUNT \ (S3_MAX_METADATA_SIZE / (sizeof(S3_METADATA_HEADER_NAME_PREFIX "nv") - 1)) /** * S3_MAX_ACL_GRANT_COUNT is the maximum number of ACL grants that may be * set on a bucket or object at one time. It is also the maximum number of * ACL grants that the XML ACL parsing routine will parse. **/ #define S3_MAX_ACL_GRANT_COUNT 100 /** * This is the maximum number of characters (including terminating \0) that * libs3 supports in an ACL grantee email address. **/ #define S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE 128 /** * This is the maximum number of characters (including terminating \0) that * libs3 supports in an ACL grantee user id. **/ #define S3_MAX_GRANTEE_USER_ID_SIZE 128 /** * This is the maximum number of characters (including terminating \0) that * libs3 supports in an ACL grantee user display name. **/ #define S3_MAX_GRANTEE_DISPLAY_NAME_SIZE 128 /** * This is the maximum number of characters that will be stored in the * return buffer for the utility function which computes an HTTP authenticated * query string **/ #define S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE \ (sizeof("https:///") + S3_MAX_HOSTNAME_SIZE + (S3_MAX_KEY_SIZE * 3) + \ sizeof("?AWSAccessKeyId=") + 32 + sizeof("&Expires=") + 32 + \ sizeof("&Signature=") + 28 + 1) /** * This constant is used by the S3_initialize() function, to specify that * the winsock library should be initialized by libs3; only relevent on * Microsoft Windows platforms. **/ #define S3_INIT_WINSOCK 1 /** * This convenience constant is used by the S3_initialize() function to * indicate that all libraries required by libs3 should be initialized. **/ #define S3_INIT_ALL (S3_INIT_WINSOCK) /** ************************************************************************** * Enumerations ************************************************************************** **/ /** * S3Status is a status code as returned by a libs3 function. The meaning of * each status code is defined in the comments for each function which returns * that status. **/ typedef enum { S3StatusOK , /** * Errors that prevent the S3 request from being issued or response from * being read **/ S3StatusInternalError , S3StatusOutOfMemory , S3StatusInterrupted , S3StatusInvalidBucketNameTooLong , S3StatusInvalidBucketNameFirstCharacter , S3StatusInvalidBucketNameCharacter , S3StatusInvalidBucketNameCharacterSequence , S3StatusInvalidBucketNameTooShort , S3StatusInvalidBucketNameDotQuadNotation , S3StatusQueryParamsTooLong , S3StatusFailedToInitializeRequest , S3StatusMetaDataHeadersTooLong , S3StatusBadMetaData , S3StatusBadContentType , S3StatusContentTypeTooLong , S3StatusBadMD5 , S3StatusMD5TooLong , S3StatusBadCacheControl , S3StatusCacheControlTooLong , S3StatusBadContentDispositionFilename , S3StatusContentDispositionFilenameTooLong , S3StatusBadContentEncoding , S3StatusContentEncodingTooLong , S3StatusBadIfMatchETag , S3StatusIfMatchETagTooLong , S3StatusBadIfNotMatchETag , S3StatusIfNotMatchETagTooLong , S3StatusHeadersTooLong , S3StatusKeyTooLong , S3StatusUriTooLong , S3StatusXmlParseFailure , S3StatusEmailAddressTooLong , S3StatusUserIdTooLong , S3StatusUserDisplayNameTooLong , S3StatusGroupUriTooLong , S3StatusPermissionTooLong , S3StatusTargetBucketTooLong , S3StatusTargetPrefixTooLong , S3StatusTooManyGrants , S3StatusBadGrantee , S3StatusBadPermission , S3StatusXmlDocumentTooLarge , S3StatusNameLookupError , S3StatusFailedToConnect , S3StatusServerFailedVerification , S3StatusConnectionFailed , S3StatusAbortedByCallback , /** * Errors from the S3 service **/ S3StatusErrorAccessDenied , S3StatusErrorAccountProblem , S3StatusErrorAmbiguousGrantByEmailAddress , S3StatusErrorBadDigest , S3StatusErrorBucketAlreadyExists , S3StatusErrorBucketAlreadyOwnedByYou , S3StatusErrorBucketNotEmpty , S3StatusErrorCredentialsNotSupported , S3StatusErrorCrossLocationLoggingProhibited , S3StatusErrorEntityTooSmall , S3StatusErrorEntityTooLarge , S3StatusErrorExpiredToken , S3StatusErrorIncompleteBody , S3StatusErrorIncorrectNumberOfFilesInPostRequest , S3StatusErrorInlineDataTooLarge , S3StatusErrorInternalError , S3StatusErrorInvalidAccessKeyId , S3StatusErrorInvalidAddressingHeader , S3StatusErrorInvalidArgument , S3StatusErrorInvalidBucketName , S3StatusErrorInvalidDigest , S3StatusErrorInvalidLocationConstraint , S3StatusErrorInvalidPayer , S3StatusErrorInvalidPolicyDocument , S3StatusErrorInvalidRange , S3StatusErrorInvalidSecurity , S3StatusErrorInvalidSOAPRequest , S3StatusErrorInvalidStorageClass , S3StatusErrorInvalidTargetBucketForLogging , S3StatusErrorInvalidToken , S3StatusErrorInvalidURI , S3StatusErrorKeyTooLong , S3StatusErrorMalformedACLError , S3StatusErrorMalformedXML , S3StatusErrorMaxMessageLengthExceeded , S3StatusErrorMaxPostPreDataLengthExceededError , S3StatusErrorMetadataTooLarge , S3StatusErrorMethodNotAllowed , S3StatusErrorMissingAttachment , S3StatusErrorMissingContentLength , S3StatusErrorMissingSecurityElement , S3StatusErrorMissingSecurityHeader , S3StatusErrorNoLoggingStatusForKey , S3StatusErrorNoSuchBucket , S3StatusErrorNoSuchKey , S3StatusErrorNotImplemented , S3StatusErrorNotSignedUp , S3StatusErrorOperationAborted , S3StatusErrorPermanentRedirect , S3StatusErrorPreconditionFailed , S3StatusErrorRedirect , S3StatusErrorRequestIsNotMultiPartContent , S3StatusErrorRequestTimeout , S3StatusErrorRequestTimeTooSkewed , S3StatusErrorRequestTorrentOfBucketError , S3StatusErrorSignatureDoesNotMatch , S3StatusErrorSlowDown , S3StatusErrorTemporaryRedirect , S3StatusErrorTokenRefreshRequired , S3StatusErrorTooManyBuckets , S3StatusErrorUnexpectedContent , S3StatusErrorUnresolvableGrantByEmailAddress , S3StatusErrorUserKeyMustBeSpecified , S3StatusErrorUnknown , /** * The following are HTTP errors returned by S3 without enough detail to * distinguish any of the above S3StatusError conditions **/ S3StatusHttpErrorMovedTemporarily , S3StatusHttpErrorBadRequest , S3StatusHttpErrorForbidden , S3StatusHttpErrorNotFound , S3StatusHttpErrorConflict , S3StatusHttpErrorUnknown } S3Status; /** * S3Protocol represents a protocol that may be used for communicating a * request to the Amazon S3 service. * * In general, HTTPS is greatly preferred (and should be the default of any * application using libs3) because it protects any data being sent to or * from S3 using strong encryption. However, HTTPS is much more CPU intensive * than HTTP, and if the caller is absolutely certain that it is OK for the * data to be viewable by anyone in transit, then HTTP can be used. **/ typedef enum { S3ProtocolHTTPS = 0, S3ProtocolHTTP = 1 } S3Protocol; /** * S3UriStyle defines the form that an Amazon S3 URI identifying a bucket or * object can take. They are of these forms: * * Virtual Host: ${protocol}://${bucket}.s3.amazonaws.com/[${key}] * Path: ${protocol}://s3.amazonaws.com/${bucket}/[${key}] * * It is generally better to use the Virual Host URI form, because it ensures * that the bucket name used is compatible with normal HTTP GETs and POSTs of * data to/from the bucket. However, if DNS lookups for the bucket are too * slow or unreliable for some reason, Path URI form may be used. **/ typedef enum { S3UriStyleVirtualHost = 0, S3UriStylePath = 1 } S3UriStyle; /** * S3GranteeType defines the type of Grantee used in an S3 ACL Grant. * Amazon Customer By Email - identifies the Grantee using their Amazon S3 * account email address * Canonical User - identifies the Grantee by S3 User ID and Display Name, * which can only be obtained by making requests to S3, for example, by * listing owned buckets * All AWS Users - identifies all authenticated AWS users * All Users - identifies all users * Log Delivery - identifies the Amazon group responsible for writing * server access logs into buckets **/ typedef enum { S3GranteeTypeAmazonCustomerByEmail = 0, S3GranteeTypeCanonicalUser = 1, S3GranteeTypeAllAwsUsers = 2, S3GranteeTypeAllUsers = 3, S3GranteeTypeLogDelivery = 4 } S3GranteeType; /** * This is an individual permission granted to a grantee in an S3 ACL Grant. * Read permission gives the Grantee the permission to list the bucket, or * read the object or its metadata * Write permission gives the Grantee the permission to create, overwrite, or * delete any object in the bucket, and is not supported for objects * ReadACP permission gives the Grantee the permission to read the ACP for * the bucket or object; the owner of the bucket or object always has * this permission implicitly * WriteACP permission gives the Grantee the permission to overwrite the ACP * for the bucket or object; the owner of the bucket or object always has * this permission implicitly * FullControl permission gives the Grantee all permissions specified by the * Read, Write, ReadACP, and WriteACP permissions **/ typedef enum { S3PermissionRead = 0, S3PermissionWrite = 1, S3PermissionReadACP = 2, S3PermissionWriteACP = 3, S3PermissionFullControl = 4 } S3Permission; /** * S3CannedAcl is an ACL that can be specified when an object is created or * updated. Each canned ACL has a predefined value when expanded to a full * set of S3 ACL Grants. * Private canned ACL gives the owner FULL_CONTROL and no other permissions * are issued * Public Read canned ACL gives the owner FULL_CONTROL and all users Read * permission * Public Read Write canned ACL gives the owner FULL_CONTROL and all users * Read and Write permission * AuthenticatedRead canned ACL gives the owner FULL_CONTROL and authenticated * S3 users Read permission **/ typedef enum { S3CannedAclPrivate = 0, /* private */ S3CannedAclPublicRead = 1, /* public-read */ S3CannedAclPublicReadWrite = 2, /* public-read-write */ S3CannedAclAuthenticatedRead = 3 /* authenticated-read */ } S3CannedAcl; /** ************************************************************************** * Data Types ************************************************************************** **/ /** * An S3RequestContext manages multiple S3 requests simultaneously; see the * S3_XXX_request_context functions below for details **/ typedef struct S3RequestContext S3RequestContext; /** * S3NameValue represents a single Name - Value pair, used to represent either * S3 metadata associated with a key, or S3 error details. **/ typedef struct S3NameValue { /** * The name part of the Name - Value pair **/ const char *name; /** * The value part of the Name - Value pair **/ const char *value; } S3NameValue; /** * S3ResponseProperties is passed to the properties callback function which is * called when the complete response properties have been received. Some of * the fields of this structure are optional and may not be provided in the * response, and some will always be provided in the response. **/ typedef struct S3ResponseProperties { /** * This optional field identifies the request ID and may be used when * reporting problems to Amazon. **/ const char *requestId; /** * This optional field identifies the request ID and may be used when * reporting problems to Amazon. **/ const char *requestId2; /** * This optional field is the content type of the data which is returned * by the request. If not provided, the default can be assumed to be * "binary/octet-stream". **/ const char *contentType; /** * This optional field is the content length of the data which is returned * in the response. A negative value means that this value was not * provided in the response. A value of 0 means that there is no content * provided. A positive value gives the number of bytes in the content of * the response. **/ uint64_t contentLength; /** * This optional field names the server which serviced the request. **/ const char *server; /** * This optional field provides a string identifying the unique contents * of the resource identified by the request, such that the contents can * be assumed not to be changed if the same eTag is returned at a later * time decribing the same resource. This is an MD5 sum of the contents. **/ const char *eTag; /** * This optional field provides the last modified time, relative to the * Unix epoch, of the contents. If this value is < 0, then the last * modified time was not provided in the response. If this value is >= 0, * then the last modified date of the contents are available as a number * of seconds since the UNIX epoch. * **/ int64_t lastModified; /** * This is the number of user-provided meta data associated with the * resource. **/ int metaDataCount; /** * These are the meta data associated with the resource. In each case, * the name will not include any S3-specific header prefixes * (i.e. x-amz-meta- will have been removed from the beginning), and * leading and trailing whitespace will have been stripped from the value. **/ const S3NameValue *metaData; } S3ResponseProperties; /** * S3AclGrant identifies a single grant in the ACL for a bucket or object. An * ACL is composed of any number of grants, which specify a grantee and the * permissions given to that grantee. S3 does not normalize ACLs in any way, * so a redundant ACL specification will lead to a redundant ACL stored in S3. **/ typedef struct S3AclGrant { /** * The granteeType gives the type of grantee specified by this grant. **/ S3GranteeType granteeType; /** * The identifier of the grantee that is set is determined by the * granteeType: * * S3GranteeTypeAmazonCustomerByEmail - amazonCustomerByEmail.emailAddress * S3GranteeTypeCanonicalUser - canonicalUser.id, canonicalUser.displayName * S3GranteeTypeAllAwsUsers - none * S3GranteeTypeAllUsers - none **/ union { /** * This structure is used iff the granteeType is * S3GranteeTypeAmazonCustomerByEmail. **/ struct { /** * This is the email address of the Amazon Customer being granted * permissions by this S3AclGrant. **/ char emailAddress[S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE]; } amazonCustomerByEmail; /** * This structure is used iff the granteeType is * S3GranteeTypeCanonicalUser. **/ struct { /** * This is the CanonicalUser ID of the grantee **/ char id[S3_MAX_GRANTEE_USER_ID_SIZE]; /** * This is the display name of the grantee **/ char displayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE]; } canonicalUser; } grantee; /** * This is the S3Permission to be granted to the grantee **/ S3Permission permission; } S3AclGrant; /** * A context for working with objects within a bucket. A bucket context holds * all information necessary for working with a bucket, and may be used * repeatedly over many consecutive (or simultaneous) calls into libs3 bucket * operation functions. **/ typedef struct S3BucketContext { /** * The name of the host to connect to when making S3 requests. If set to * NULL, the default S3 hostname passed in to S3_initialize will be used. **/ const char *hostName; /** * The name of the bucket to use in the bucket context **/ const char *bucketName; /** * The protocol to use when accessing the bucket **/ S3Protocol protocol; /** * The URI style to use for all URIs sent to Amazon S3 while working with * this bucket context **/ S3UriStyle uriStyle; /** * The Amazon Access Key ID to use for access to the bucket **/ const char *accessKeyId; /** * The Amazon Secret Access Key to use for access to the bucket **/ const char *secretAccessKey; } S3BucketContext; /** * This is a single entry supplied to the list bucket callback by a call to * S3_list_bucket. It identifies a single matching key from the list * operation. **/ typedef struct S3ListBucketContent { /** * This is the next key in the list bucket results. **/ const char *key; /** * This is the number of seconds since UNIX epoch of the last modified * date of the object identified by the key. **/ int64_t lastModified; /** * This gives a tag which gives a signature of the contents of the object, * which is the MD5 of the contents of the object. **/ const char *eTag; /** * This is the size of the object in bytes. **/ uint64_t size; /** * This is the ID of the owner of the key; it is present only if access * permissions allow it to be viewed. **/ const char *ownerId; /** * This is the display name of the owner of the key; it is present only if * access permissions allow it to be viewed. **/ const char *ownerDisplayName; } S3ListBucketContent; /** * S3PutProperties is the set of properties that may optionally be set by the * user when putting objects to S3. Each field of this structure is optional * and may or may not be present. **/ typedef struct S3PutProperties { /** * If present, this is the Content-Type that should be associated with the * object. If not provided, S3 defaults to "binary/octet-stream". **/ const char *contentType; /** * If present, this provides the MD5 signature of the contents, and is * used to validate the contents. This is highly recommended by Amazon * but not required. Its format is as a base64-encoded MD5 sum. **/ const char *md5; /** * If present, this gives a Cache-Control header string to be supplied to * HTTP clients which download this **/ const char *cacheControl; /** * If present, this gives the filename to save the downloaded file to, * whenever the object is downloaded via a web browser. This is only * relevent for objects which are intended to be shared to users via web * browsers and which is additionally intended to be downloaded rather * than viewed. **/ const char *contentDispositionFilename; /** * If present, this identifies the content encoding of the object. This * is only applicable to encoded (usually, compressed) content, and only * relevent if the object is intended to be downloaded via a browser. **/ const char *contentEncoding; /** * If >= 0, this gives an expiration date for the content. This * information is typically only delivered to users who download the * content via a web browser. **/ int64_t expires; /** * This identifies the "canned ACL" that should be used for this object. * The default (0) gives only the owner of the object access to it. **/ S3CannedAcl cannedAcl; /** * This is the number of values in the metaData field. **/ int metaDataCount; /** * These are the meta data to pass to S3. In each case, the name part of * the Name - Value pair should not include any special S3 HTTP header * prefix (i.e., should be of the form 'foo', NOT 'x-amz-meta-foo'). **/ const S3NameValue *metaData; } S3PutProperties; /** * S3GetConditions is used for the get_object operation, and specifies * conditions which the object must meet in order to be successfully returned. **/ typedef struct S3GetConditions { /** * The request will be processed if the Last-Modification header of the * object is greater than or equal to this value, specified as a number of * seconds since Unix epoch. If this value is less than zero, it will not * be used in the conditional. **/ int64_t ifModifiedSince; /** * The request will be processed if the Last-Modification header of the * object is less than this value, specified as a number of seconds since * Unix epoch. If this value is less than zero, it will not be used in * the conditional. **/ int64_t ifNotModifiedSince; /** * If non-NULL, this gives an eTag header value which the object must * match in order to be returned. Note that altough the eTag is simply an * MD5, this must be presented in the S3 eTag form, which typically * includes double-quotes. **/ const char *ifMatchETag; /** * If non-NULL, this gives an eTag header value which the object must not * match in order to be returned. Note that altough the eTag is simply an * MD5, this must be presented in the S3 eTag form, which typically * includes double-quotes. **/ const char *ifNotMatchETag; } S3GetConditions; /** * S3ErrorDetails provides detailed information describing an S3 error. This * is only presented when the error is an S3-generated error (i.e. one of the * S3StatusErrorXXX values). **/ typedef struct S3ErrorDetails { /** * This is the human-readable message that Amazon supplied describing the * error **/ const char *message; /** * This identifies the resource for which the error occurred **/ const char *resource; /** * This gives human-readable further details describing the specifics of * this error **/ const char *furtherDetails; /** * This gives the number of S3NameValue pairs present in the extraDetails * array **/ int extraDetailsCount; /** * S3 can provide extra details in a freeform Name - Value pair format. * Each error can have any number of these, and this array provides these * additional extra details. **/ S3NameValue *extraDetails; } S3ErrorDetails; /** ************************************************************************** * Callback Signatures ************************************************************************** **/ /** * This callback is made whenever the response properties become available for * any request. * * @param properties are the properties that are available from the response * @param callbackData is the callback data as specified when the request * was issued. * @return S3StatusOK to continue processing the request, anything else to * immediately abort the request with a status which will be * passed to the S3ResponseCompleteCallback for this request. * Typically, this will return either S3StatusOK or * S3StatusAbortedByCallback. **/ typedef S3Status (S3ResponsePropertiesCallback) (const S3ResponseProperties *properties, void *callbackData); /** * This callback is made when the response has been completely received, or an * error has occurred which has prematurely aborted the request, or one of the * other user-supplied callbacks returned a value intended to abort the * request. This callback is always made for every request, as the very last * callback made for that request. * * @param status gives the overall status of the response, indicating success * or failure; use S3_status_is_retryable() as a simple way to detect * whether or not the status indicates that the request failed but may * be retried. * @param errorDetails if non-NULL, gives details as returned by the S3 * service, describing the error * @param callbackData is the callback data as specified when the request * was issued. **/ typedef void (S3ResponseCompleteCallback)(S3Status status, const S3ErrorDetails *errorDetails, void *callbackData); /** * This callback is made for each bucket resulting from a list service * operation. * * @param ownerId is the ID of the owner of the bucket * @param ownerDisplayName is the owner display name of the owner of the bucket * @param bucketName is the name of the bucket * @param creationDateSeconds if < 0 indicates that no creation date was * supplied for the bucket; if >= 0 indicates the number of seconds * since UNIX Epoch of the creation date of the bucket * @param callbackData is the callback data as specified when the request * was issued. * @return S3StatusOK to continue processing the request, anything else to * immediately abort the request with a status which will be * passed to the S3ResponseCompleteCallback for this request. * Typically, this will return either S3StatusOK or * S3StatusAbortedByCallback. **/ typedef S3Status (S3ListServiceCallback)(const char *ownerId, const char *ownerDisplayName, const char *bucketName, int64_t creationDateSeconds, void *callbackData); /** * This callback is made repeatedly as a list bucket operation progresses. * The contents reported via this callback are only reported once per list * bucket operation, but multiple calls to this callback may be necessary to * report all items resulting from the list bucket operation. * * @param isTruncated is true if the list bucket request was truncated by the * S3 service, in which case the remainder of the list may be obtained * by querying again using the Marker parameter to start the query * after this set of results * @param nextMarker if present, gives the largest (alphabetically) key * returned in the response, which, if isTruncated is true, may be used * as the marker in a subsequent list buckets operation to continue * listing * @param contentsCount is the number of ListBucketContent structures in the * contents parameter * @param contents is an array of ListBucketContent structures, each one * describing an object in the bucket * @param commonPrefixesCount is the number of common prefixes strings in the * commonPrefixes parameter * @param commonPrefixes is an array of strings, each specifing one of the * common prefixes as returned by S3 * @param callbackData is the callback data as specified when the request * was issued. * @return S3StatusOK to continue processing the request, anything else to * immediately abort the request with a status which will be * passed to the S3ResponseCompleteCallback for this request. * Typically, this will return either S3StatusOK or * S3StatusAbortedByCallback. **/ typedef S3Status (S3ListBucketCallback)(int isTruncated, const char *nextMarker, int contentsCount, const S3ListBucketContent *contents, int commonPrefixesCount, const char **commonPrefixes, void *callbackData); /** * This callback is made during a put object operation, to obtain the next * chunk of data to put to the S3 service as the contents of the object. This * callback is made repeatedly, each time acquiring the next chunk of data to * write to the service, until a negative or 0 value is returned. * * @param bufferSize gives the maximum number of bytes that may be written * into the buffer parameter by this callback * @param buffer gives the buffer to fill with at most bufferSize bytes of * data as the next chunk of data to send to S3 as the contents of this * object * @param callbackData is the callback data as specified when the request * was issued. * @return < 0 to abort the request with the S3StatusAbortedByCallback, which * will be pased to the response complete callback for this request, or * 0 to indicate the end of data, or > 0 to identify the number of * bytes that were written into the buffer by this callback **/ typedef int (S3PutObjectDataCallback)(int bufferSize, char *buffer, void *callbackData); /** * This callback is made during a get object operation, to provide the next * chunk of data available from the S3 service constituting the contents of * the object being fetched. This callback is made repeatedly, each time * providing the next chunk of data read, until the complete object contents * have been passed through the callback in this way, or the callback * returns an error status. * * @param bufferSize gives the number of bytes in buffer * @param buffer is the data being passed into the callback * @param callbackData is the callback data as specified when the request * was issued. * @return S3StatusOK to continue processing the request, anything else to * immediately abort the request with a status which will be * passed to the S3ResponseCompleteCallback for this request. * Typically, this will return either S3StatusOK or * S3StatusAbortedByCallback. **/ typedef S3Status (S3GetObjectDataCallback)(int bufferSize, const char *buffer, void *callbackData); /** ************************************************************************** * Callback Structures ************************************************************************** **/ /** * An S3ResponseHandler defines the callbacks which are made for any * request. **/ typedef struct S3ResponseHandler { /** * The propertiesCallback is made when the response properties have * successfully been returned from S3. This function may not be called * if the response properties were not successfully returned from S3. **/ S3ResponsePropertiesCallback *propertiesCallback; /** * The completeCallback is always called for every request made to S3, * regardless of the outcome of the request. It provides the status of * the request upon its completion, as well as extra error details in the * event of an S3 error. **/ S3ResponseCompleteCallback *completeCallback; } S3ResponseHandler; /** * An S3ListServiceHandler defines the callbacks which are made for * list_service requests. **/ typedef struct S3ListServiceHandler { /** * responseHandler provides the properties and complete callback **/ S3ResponseHandler responseHandler; /** * The listServiceCallback is called as items are reported back from S3 as * responses to the request **/ S3ListServiceCallback *listServiceCallback; } S3ListServiceHandler; /** * An S3ListBucketHandler defines the callbacks which are made for * list_bucket requests. **/ typedef struct S3ListBucketHandler { /** * responseHandler provides the properties and complete callback **/ S3ResponseHandler responseHandler; /** * The listBucketCallback is called as items are reported back from S3 as * responses to the request. This may be called more than one time per * list bucket request, each time providing more items from the list * operation. **/ S3ListBucketCallback *listBucketCallback; } S3ListBucketHandler; /** * An S3PutObjectHandler defines the callbacks which are made for * put_object requests. **/ typedef struct S3PutObjectHandler { /** * responseHandler provides the properties and complete callback **/ S3ResponseHandler responseHandler; /** * The putObjectDataCallback is called to acquire data to send to S3 as * the contents of the put_object request. It is made repeatedly until it * returns a negative number (indicating that the request should be * aborted), or 0 (indicating that all data has been supplied). **/ S3PutObjectDataCallback *putObjectDataCallback; } S3PutObjectHandler; /** * An S3GetObjectHandler defines the callbacks which are made for * get_object requests. **/ typedef struct S3GetObjectHandler { /** * responseHandler provides the properties and complete callback **/ S3ResponseHandler responseHandler; /** * The getObjectDataCallback is called as data is read from S3 as the * contents of the object being read in the get_object request. It is * called repeatedly until there is no more data provided in the request, * or until the callback returns an error status indicating that the * request should be aborted. **/ S3GetObjectDataCallback *getObjectDataCallback; } S3GetObjectHandler; /** ************************************************************************** * General Library Functions ************************************************************************** **/ /** * Initializes libs3 for use. This function must be called before any other * libs3 function is called. It may be called multiple times, with the same * effect as calling it once, as long as S3_deinitialize() is called an * equal number of times when the program has finished. This function is NOT * thread-safe and must only be called by one thread at a time. * * @param userAgentInfo is a string that will be included in the User-Agent * header of every request made to the S3 service. You may provide * NULL or the empty string if you don't care about this. The value * will not be copied by this function and must remain unaltered by the * caller until S3_deinitialize() is called. * @param flags is a bitmask of some combination of S3_INIT_XXX flag, or * S3_INIT_ALL, indicating which of the libraries that libs3 depends * upon should be initialized by S3_initialize(). Only if your program * initializes one of these dependency libraries itself should anything * other than S3_INIT_ALL be passed in for this bitmask. * * You should pass S3_INIT_WINSOCK if and only if your application does * not initialize winsock elsewhere. On non-Microsoft Windows * platforms it has no effect. * * As a convenience, the macro S3_INIT_ALL is provided, which will do * all necessary initialization; however, be warned that things may * break if your application re-initializes the dependent libraries * later. * @param defaultS3Hostname is a string the specifies the default S3 server * hostname to use when making S3 requests; this value is used * whenever the hostName of an S3BucketContext is NULL. If NULL is * passed here then the default of S3_DEFAULT_HOSTNAME will be used. * @return One of: * S3StatusOK on success * S3StatusUriTooLong if the defaultS3HostName is longer than * S3_MAX_HOSTNAME_SIZE * S3StatusInternalError if dependent libraries could not be * initialized * S3StatusOutOfMemory on failure due to out of memory **/ S3Status S3_initialize(const char *userAgentInfo, int flags, const char *defaultS3HostName); /** * Must be called once per program for each call to libs3_initialize(). After * this call is complete, no libs3 function may be called except * S3_initialize(). **/ void S3_deinitialize(); /** * Returns a string with the textual name of an S3Status code * * @param status is S3Status code for which the textual name will be returned * @return a string with the textual name of an S3Status code **/ const char *S3_get_status_name(S3Status status); /** * This function may be used to validate an S3 bucket name as being in the * correct form for use with the S3 service. Amazon S3 limits the allowed * characters in S3 bucket names, as well as imposing some additional rules on * the length of bucket names and their structure. There are actually two * limits; one for bucket names used only in path-style URIs, and a more * strict limit used for bucket names used in virtual-host-style URIs. It is * advisable to use only bucket names which meet the more strict requirements * regardless of how the bucket expected to be used. * * This method does NOT validate that the bucket is available for use in the * S3 service, so the return value of this function cannot be used to decide * whether or not a bucket with the give name already exists in Amazon S3 or * is accessible by the caller. It merely validates that the bucket name is * valid for use with S3. * * @param bucketName is the bucket name to validate * @param uriStyle gives the URI style to validate the bucket name against. * It is advisable to always use S3UriStyleVirtuallHost. * @return One of: * S3StatusOK if the bucket name was validates successfully * S3StatusInvalidBucketNameTooLong if the bucket name exceeded the * length limitation for the URI style, which is 255 bytes for * path style URIs and 63 bytes for virtual host type URIs * S3StatusInvalidBucketNameTooShort if the bucket name is less than * 3 characters * S3StatusInvalidBucketNameFirstCharacter if the bucket name as an * invalid first character, which is anything other than * an alphanumeric character * S3StatusInvalidBucketNameCharacterSequence if the bucket name * includes an invalid character sequence, which for virtual host * style buckets is ".-" or "-." * S3StatusInvalidBucketNameCharacter if the bucket name includes an * invalid character, which is anything other than alphanumeric, * '-', '.', or for path style URIs only, '_'. * S3StatusInvalidBucketNameDotQuadNotation if the bucket name is in * dot-quad notation, i.e. the form of an IP address, which is * not allowed by Amazon S3. **/ S3Status S3_validate_bucket_name(const char *bucketName, S3UriStyle uriStyle); /** * Converts an XML representation of an ACL to a libs3 structured * representation. This method is not strictly necessary for working with * ACLs using libs3, but may be convenient for users of the library who read * ACLs from elsewhere in XML format and need to use these ACLs with libs3. * * @param aclXml is the XML representation of the ACL. This must be a * zero-terminated character string. * @param ownerId will be filled in with the Owner ID specified in the XML. * At most MAX_GRANTEE_USER_ID_SIZE bytes will be stored at this * location. * @param ownerDisplayName will be filled in with the Owner Display Name * specified in the XML. At most MAX_GRANTEE_DISPLAY_NAME_SIZE bytes * will be stored at this location. * @param aclGrantCountReturn returns the number of S3AclGrant structures * returned in the aclGrantsReturned array * @param aclGrants must be passed in as an array of at least S3_ACL_MAXCOUNT * structures, and on return from this function, the first * aclGrantCountReturn structures will be filled in with the ACLs * represented by the input XML. * @return One of: * S3StatusOK on successful conversion of the ACL * S3StatusInternalError on internal error representing a bug in the * libs3 library * S3StatusXmlParseFailure if the XML document was malformed **/ S3Status S3_convert_acl(char *aclXml, char *ownerId, char *ownerDisplayName, int *aclGrantCountReturn, S3AclGrant *aclGrants); /** * Returns nonzero if the status indicates that the request should be * immediately retried, because the status indicates an error of a nature that * is likely due to transient conditions on the local system or S3, such as * network failures, or internal retryable errors reported by S3. Returns * zero otherwise. * * @param status is the status to evaluate * @return nonzero if the status indicates a retryable error, 0 otherwise **/ int S3_status_is_retryable(S3Status status); /** ************************************************************************** * Request Context Management Functions ************************************************************************** **/ /** * An S3RequestContext allows muliple requests to be serviced by the same * thread simultaneously. It is an optional parameter to all libs3 request * functions, and if provided, the request is managed by the S3RequestContext; * if not, the request is handled synchronously and is complete when the libs3 * request function has returned. * * @param requestContextReturn returns the newly-created S3RequestContext * structure, which if successfully returned, must be destroyed via a * call to S3_destroy_request_context when it is no longer needed. If * an error status is returned from this function, then * requestContextReturn will not have been filled in, and * S3_destroy_request_context should not be called on it * @return One of: * S3StatusOK if the request context was successfully created * S3StatusOutOfMemory if the request context could not be created due * to an out of memory error **/ S3Status S3_create_request_context(S3RequestContext **requestContextReturn); /** * Destroys an S3RequestContext which was created with * S3_create_request_context. Any requests which are currently being * processed by the S3RequestContext will immediately be aborted and their * request completed callbacks made with the status S3StatusInterrupted. * * @param requestContext is the S3RequestContext to destroy **/ void S3_destroy_request_context(S3RequestContext *requestContext); /** * Runs the S3RequestContext until all requests within it have completed, * or until an error occurs. * * @param requestContext is the S3RequestContext to run until all requests * within it have completed or until an error occurs * @return One of: * S3Status if all requests were successfully run to completion * S3StatusInternalError if an internal error prevented the * S3RequestContext from running one or more requests * S3StatusOutOfMemory if requests could not be run to completion * due to an out of memory error **/ S3Status S3_runall_request_context(S3RequestContext *requestContext); /** * Does some processing of requests within the S3RequestContext. One or more * requests may have callbacks made on them and may complete. This function * processes any requests which have immediately available I/O, and will not * block waiting for I/O on any request. This function would normally be used * with S3_get_request_context_fdsets. * * @param requestContext is the S3RequestContext to process * @param requestsRemainingReturn returns the number of requests remaining * and not yet completed within the S3RequestContext after this * function returns. * @return One of: * S3StatusOK if request processing proceeded without error * S3StatusInternalError if an internal error prevented the * S3RequestContext from running one or more requests * S3StatusOutOfMemory if requests could not be processed due to * an out of memory error **/ S3Status S3_runonce_request_context(S3RequestContext *requestContext, int *requestsRemainingReturn); /** * This function, in conjunction allows callers to manually manage a set of * requests using an S3RequestContext. This function returns the set of file * descriptors which the caller can watch (typically using select()), along * with any other file descriptors of interest to the caller, and using * whatever timeout (if any) the caller wishes, until one or more file * descriptors in the returned sets become ready for I/O, at which point * S3_runonce_request_context can be called to process requests with available * I/O. * * @param requestContext is the S3RequestContext to get fd_sets from * @param readFdSet is a pointer to an fd_set which will have all file * descriptors to watch for read events for the requests in the * S3RequestContext set into it upon return. Should be zero'd out * (using FD_ZERO) before being passed into this function. * @param writeFdSet is a pointer to an fd_set which will have all file * descriptors to watch for write events for the requests in the * S3RequestContext set into it upon return. Should be zero'd out * (using FD_ZERO) before being passed into this function. * @param exceptFdSet is a pointer to an fd_set which will have all file * descriptors to watch for exception events for the requests in the * S3RequestContext set into it upon return. Should be zero'd out * (using FD_ZERO) before being passed into this function. * @param maxFd returns the highest file descriptor set into any of the * fd_sets, or -1 if no file descriptors were set * @return One of: * S3StatusOK if all fd_sets were successfully set * S3StatusInternalError if an internal error prevented this function * from completing successfully **/ S3Status S3_get_request_context_fdsets(S3RequestContext *requestContext, fd_set *readFdSet, fd_set *writeFdSet, fd_set *exceptFdSet, int *maxFd); /** * This function returns the maximum number of milliseconds that the caller of * S3_runonce_request_context should wait on the fdsets obtained via a call to * S3_get_request_context_fdsets. In other words, this is essentially the * select() timeout that needs to be used (shorter values are OK, but no * longer than this) to ensure that internal timeout code of libs3 can work * properly. This function should be called right before select() each time * select() on the request_context fdsets are to be performed by the libs3 * user. * * @param requestContext is the S3RequestContext to get the timeout from * @return the maximum number of milliseconds to select() on fdsets. Callers * could wait a shorter time if they wish, but not longer. **/ int64_t S3_get_request_context_timeout(S3RequestContext *requestContext); /** ************************************************************************** * S3 Utility Functions ************************************************************************** **/ /** * Generates an HTTP authenticated query string, which may then be used by * a browser (or other web client) to issue the request. The request is * implicitly a GET request; Amazon S3 is documented to only support this type * of authenticated query string request. * * @param buffer is the output buffer for the authenticated query string. * It must be at least S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE bytes in * length. * @param bucketContext gives the bucket and associated parameters for the * request to generate. * @param key gives the key which the authenticated request will GET. * @param expires gives the number of seconds since Unix epoch for the * expiration date of the request; after this time, the request will * no longer be valid. If this value is negative, the largest * expiration date possible is used (currently, Jan 19, 2038). * @param resource gives a sub-resource to be fetched for the request, or NULL * for none. This should be of the form "?", i.e. * "?torrent". * @return One of: * S3StatusUriTooLong if, due to an internal error, the generated URI * is longer than S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE bytes in * length and thus will not fit into the supplied buffer * S3StatusOK on success **/ S3Status S3_generate_authenticated_query_string (char *buffer, const S3BucketContext *bucketContext, const char *key, int64_t expires, const char *resource); /** ************************************************************************** * Service Functions ************************************************************************** **/ /** * Lists all S3 buckets belonging to the access key id. * * @param protocol gives the protocol to use for this request * @param accessKeyId gives the Amazon Access Key ID for which to list owned * buckets * @param secretAccessKey gives the Amazon Secret Access Key for which to list * owned buckets * @param hostName is the S3 host name to use; if NULL is passed in, the * default S3 host as provided to S3_initialize() will be used. * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_list_service(S3Protocol protocol, const char *accessKeyId, const char *secretAccessKey, const char *hostName, S3RequestContext *requestContext, const S3ListServiceHandler *handler, void *callbackData); /** ************************************************************************** * Bucket Functions ************************************************************************** **/ /** * Tests the existence of an S3 bucket, additionally returning the bucket's * location if it exists and is accessible. * * @param protocol gives the protocol to use for this request * @param uriStyle gives the URI style to use for this request * @param accessKeyId gives the Amazon Access Key ID for which to list owned * buckets * @param secretAccessKey gives the Amazon Secret Access Key for which to list * owned buckets * @param hostName is the S3 host name to use; if NULL is passed in, the * default S3 host as provided to S3_initialize() will be used. * @param bucketName is the bucket name to test * @param locationConstraintReturnSize gives the number of bytes in the * locationConstraintReturn parameter * @param locationConstraintReturn provides the location into which to write * the name of the location constraint naming the geographic location * of the S3 bucket. This must have at least as many characters in it * as specified by locationConstraintReturn, and should start out * NULL-terminated. On successful completion of this request, this * will be set to the name of the geographic location of S3 bucket, or * will be left as a zero-length string if no location was available. * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_test_bucket(S3Protocol protocol, S3UriStyle uriStyle, const char *accessKeyId, const char *secretAccessKey, const char *hostName, const char *bucketName, int locationConstraintReturnSize, char *locationConstraintReturn, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Creates a new bucket. * * @param protocol gives the protocol to use for this request * @param accessKeyId gives the Amazon Access Key ID for which to list owned * buckets * @param secretAccessKey gives the Amazon Secret Access Key for which to list * owned buckets * @param hostName is the S3 host name to use; if NULL is passed in, the * default S3 host as provided to S3_initialize() will be used. * @param bucketName is the name of the bucket to be created * @param cannedAcl gives the "REST canned ACL" to use for the created bucket * @param locationConstraint if non-NULL, gives the geographic location for * the bucket to create. * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_create_bucket(S3Protocol protocol, const char *accessKeyId, const char *secretAccessKey, const char *hostName, const char *bucketName, S3CannedAcl cannedAcl, const char *locationConstraint, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Deletes a bucket. The bucket must be empty, or the status * S3StatusErrorBucketNotEmpty will result. * * @param protocol gives the protocol to use for this request * @param uriStyle gives the URI style to use for this request * @param accessKeyId gives the Amazon Access Key ID for which to list owned * buckets * @param secretAccessKey gives the Amazon Secret Access Key for which to list * owned buckets * @param hostName is the S3 host name to use; if NULL is passed in, the * default S3 host as provided to S3_initialize() will be used. * @param bucketName is the name of the bucket to be deleted * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_delete_bucket(S3Protocol protocol, S3UriStyle uriStyle, const char *accessKeyId, const char *secretAccessKey, const char *hostName, const char *bucketName, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Lists keys within a bucket. * * @param bucketContext gives the bucket and associated parameters for this * request * @param prefix if present, gives a prefix for matching keys * @param marker if present, only keys occuring after this value will be * listed * @param delimiter if present, causes keys that contain the same string * between the prefix and the first occurrence of the delimiter to be * rolled up into a single result element * @param maxkeys is the maximum number of keys to return * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_list_bucket(const S3BucketContext *bucketContext, const char *prefix, const char *marker, const char *delimiter, int maxkeys, S3RequestContext *requestContext, const S3ListBucketHandler *handler, void *callbackData); /** ************************************************************************** * Object Functions ************************************************************************** **/ /** * Puts object data to S3. This overwrites any existing object at that key; * note that S3 currently only supports full-object upload. The data to * upload will be acquired by calling the handler's putObjectDataCallback. * * @param bucketContext gives the bucket and associated parameters for this * request * @param key is the key of the object to put to * @param contentLength is required and gives the total number of bytes that * will be put * @param putProperties optionally provides additional properties to apply to * the object that is being put to * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_put_object(const S3BucketContext *bucketContext, const char *key, uint64_t contentLength, const S3PutProperties *putProperties, S3RequestContext *requestContext, const S3PutObjectHandler *handler, void *callbackData); /** * Copies an object from one location to another. The object may be copied * back to itself, which is useful for replacing metadata without changing * the object. * * @param bucketContext gives the source bucket and associated parameters for * this request * @param key is the source key * @param destinationBucket gives the destination bucket into which to copy * the object. If NULL, the source bucket will be used. * @param destinationKey gives the destination key into which to copy the * object. If NULL, the source key will be used. * @param putProperties optionally provides properties to apply to the object * that is being put to. If not supplied (i.e. NULL is passed in), * then the copied object will retain the metadata of the copied * object. * @param lastModifiedReturn returns the last modified date of the copied * object * @param eTagReturnSize specifies the number of bytes provided in the * eTagReturn buffer * @param eTagReturn is a buffer into which the resulting eTag of the copied * object will be written * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_copy_object(const S3BucketContext *bucketContext, const char *key, const char *destinationBucket, const char *destinationKey, const S3PutProperties *putProperties, int64_t *lastModifiedReturn, int eTagReturnSize, char *eTagReturn, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Gets an object from S3. The contents of the object are returned in the * handler's getObjectDataCallback. * * @param bucketContext gives the bucket and associated parameters for this * request * @param key is the key of the object to get * @param getConditions if non-NULL, gives a set of conditions which must be * met in order for the request to succeed * @param startByte gives the start byte for the byte range of the contents * to be returned * @param byteCount gives the number of bytes to return; a value of 0 * indicates that the contents up to the end should be returned * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_get_object(const S3BucketContext *bucketContext, const char *key, const S3GetConditions *getConditions, uint64_t startByte, uint64_t byteCount, S3RequestContext *requestContext, const S3GetObjectHandler *handler, void *callbackData); /** * Gets the response properties for the object, but not the object contents. * * @param bucketContext gives the bucket and associated parameters for this * request * @param key is the key of the object to get the properties of * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_head_object(const S3BucketContext *bucketContext, const char *key, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Deletes an object from S3. * * @param bucketContext gives the bucket and associated parameters for this * request * @param key is the key of the object to delete * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_delete_object(const S3BucketContext *bucketContext, const char *key, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** ************************************************************************** * Access Control List Functions ************************************************************************** **/ /** * Gets the ACL for the given bucket or object. * * @param bucketContext gives the bucket and associated parameters for this * request * @param key is the key of the object to get the ACL of; or NULL to get the * ACL of the bucket * @param ownerId must be supplied as a buffer of at least * S3_MAX_GRANTEE_USER_ID_SIZE bytes, and will be filled in with the * owner ID of the object/bucket * @param ownerDisplayName must be supplied as a buffer of at least * S3_MAX_GRANTEE_DISPLAY_NAME_SIZE bytes, and will be filled in with * the display name of the object/bucket * @param aclGrantCountReturn returns the number of S3AclGrant structures * returned in the aclGrants parameter * @param aclGrants must be passed in as an array of at least * S3_MAX_ACL_GRANT_COUNT S3AclGrant structures, which will be filled * in with the grant information for the ACL * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_get_acl(const S3BucketContext *bucketContext, const char *key, char *ownerId, char *ownerDisplayName, int *aclGrantCountReturn, S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Sets the ACL for the given bucket or object. * * @param bucketContext gives the bucket and associated parameters for this * request * @param key is the key of the object to set the ACL for; or NULL to set the * ACL for the bucket * @param ownerId is the owner ID of the object/bucket. Unfortunately, S3 * requires this to be valid and thus it must have been fetched by a * previous S3 request, such as a list_buckets request. * @param ownerDisplayName is the owner display name of the object/bucket. * Unfortunately, S3 requires this to be valid and thus it must have * been fetched by a previous S3 request, such as a list_buckets * request. * @param aclGrantCount is the number of ACL grants to set for the * object/bucket * @param aclGrants are the ACL grants to set for the object/bucket * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_set_acl(const S3BucketContext *bucketContext, const char *key, const char *ownerId, const char *ownerDisplayName, int aclGrantCount, const S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** ************************************************************************** * Server Access Log Functions ************************************************************************** **/ /** * Gets the service access logging settings for a bucket. The service access * logging settings specify whether or not the S3 service will write service * access logs for requests made for the given bucket, and if so, several * settings controlling how these logs will be written. * * @param bucketContext gives the bucket and associated parameters for this * request; this is the bucket for which service access logging is * being requested * @param targetBucketReturn must be passed in as a buffer of at least * (S3_MAX_BUCKET_NAME_SIZE + 1) bytes in length, and will be filled * in with the target bucket name for access logging for the given * bucket, which is the bucket into which access logs for the specified * bucket will be written. This is returned as an empty string if * service access logging is not enabled for the given bucket. * @param targetPrefixReturn must be passed in as a buffer of at least * (S3_MAX_KEY_SIZE + 1) bytes in length, and will be filled in * with the key prefix for server access logs for the given bucket, * or the empty string if no such prefix is specified. * @param aclGrantCountReturn returns the number of ACL grants that are * associated with the server access logging for the given bucket. * @param aclGrants must be passed in as an array of at least * S3_MAX_ACL_GRANT_COUNT S3AclGrant structures, and these will be * filled in with the target grants associated with the server access * logging for the given bucket, whose number is returned in the * aclGrantCountReturn parameter. These grants will be applied to the * ACL of any server access logging log files generated by the S3 * service for the given bucket. * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_get_server_access_logging(const S3BucketContext *bucketContext, char *targetBucketReturn, char *targetPrefixReturn, int *aclGrantCountReturn, S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); /** * Sets the service access logging settings for a bucket. The service access * logging settings specify whether or not the S3 service will write service * access logs for requests made for the given bucket, and if so, several * settings controlling how these logs will be written. * * @param bucketContext gives the bucket and associated parameters for this * request; this is the bucket for which service access logging is * being set * @param targetBucket gives the target bucket name for access logging for the * given bucket, which is the bucket into which access logs for the * specified bucket will be written. * @param targetPrefix is an option parameter which specifies the key prefix * for server access logs for the given bucket, or NULL if no such * prefix is to be used. * @param aclGrantCount specifies the number of ACL grants that are to be * associated with the server access logging for the given bucket. * @param aclGrants is as an array of S3AclGrant structures, whose number is * given by the aclGrantCount parameter. These grants will be applied * to the ACL of any server access logging log files generated by the * S3 service for the given bucket. * @param requestContext if non-NULL, gives the S3RequestContext to add this * request to, and does not perform the request immediately. If NULL, * performs the request immediately and synchronously. * @param handler gives the callbacks to call as the request is processed and * completed * @param callbackData will be passed in as the callbackData parameter to * all callbacks for this request **/ void S3_set_server_access_logging(const S3BucketContext *bucketContext, const char *targetBucket, const char *targetPrefix, int aclGrantCount, const S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData); #ifdef __cplusplus } #endif #endif /* LIBS3_H */ ceph-0.80.11/src/libs3/inc/util.h0000664000175100017510000000722012623076753020400 0ustar jenkins-buildjenkins-build/** ************************************************************************** * util.h * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #ifndef UTIL_H #define UTIL_H #include #include #include #include "libs3.h" // acl groups #define ACS_URL "http://acs.amazonaws.com/groups/" #define ACS_GROUP_ALL_USERS ACS_URL "global/AllUsers" #define ACS_GROUP_AWS_USERS ACS_URL "global/AuthenticatedUsers" #define ACS_GROUP_LOG_DELIVERY ACS_URL "s3/LogDelivery" // Derived from S3 documentation // This is the maximum number of bytes needed in a "compacted meta header" // buffer, which is a buffer storing all of the compacted meta headers. #define COMPACTED_METADATA_BUFFER_SIZE \ (S3_MAX_METADATA_COUNT * sizeof(S3_METADATA_HEADER_NAME_PREFIX "n: v")) // Maximum url encoded key size; since every single character could require // URL encoding, it's 3 times the size of a key (since each url encoded // character takes 3 characters: %NN) #define MAX_URLENCODED_KEY_SIZE (3 * S3_MAX_KEY_SIZE) // This is the maximum size of a URI that could be passed to S3: // https://s3.amazonaws.com/${BUCKET}/${KEY}?acl // 255 is the maximum bucket length #define MAX_URI_SIZE \ ((sizeof("https:///") - 1) + S3_MAX_HOSTNAME_SIZE + 255 + 1 + \ MAX_URLENCODED_KEY_SIZE + (sizeof("?torrent" - 1)) + 1) // Maximum size of a canonicalized resource #define MAX_CANONICALIZED_RESOURCE_SIZE \ (1 + 255 + 1 + MAX_URLENCODED_KEY_SIZE + (sizeof("?torrent") - 1) + 1) // Utilities ----------------------------------------------------------------- // URL-encodes a string from [src] into [dest]. [dest] must have at least // 3x the number of characters that [source] has. At most [maxSrcSize] bytes // from [src] are encoded; if more are present in [src], 0 is returned from // urlEncode, else nonzero is returned. int urlEncode(char *dest, const char *src, int maxSrcSize); // Returns < 0 on failure >= 0 on success int64_t parseIso8601Time(const char *str); uint64_t parseUnsignedInt(const char *str); // base64 encode bytes. The output buffer must have at least // ((4 * (inLen + 1)) / 3) bytes in it. Returns the number of bytes written // to [out]. int base64Encode(const unsigned char *in, int inLen, char *out); // Compute HMAC-SHA-1 with key [key] and message [message], storing result // in [hmac] void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len, const unsigned char *message, int message_len); // Compute a 64-bit hash values given a set of bytes uint64_t hash(const unsigned char *k, int length); // Because Windows seems to be missing isblank(), use our own; it's a very // easy function to write in any case int is_blank(char c); #endif /* UTIL_H */ ceph-0.80.11/src/libs3/archlinux/0000775000175100017510000000000012623076753020475 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/archlinux/PKGBUILD0000664000175100017510000000114312623076753021620 0ustar jenkins-buildjenkins-build# Contributor: Bryan Ischo pkgname=libs3 pkgver=trunk pkgrel=1 pkgdesc="C Library and Tools for Amazon S3 Access" arch=('i686' 'x86_64') url="http://libs3.ischo.com/index.html" license=('GPL') groups=() depends=('libxml2' 'openssl' 'curl') makedepends=('make' 'libxml2' 'openssl' 'curl') provides=() conflicts=() replaces=() backup=() options=() install= source=(http://libs3.ischo.com/$pkgname-$pkgver.tar.gz) noextract=() md5sums=('source md5') #generate with 'makepkg -g' build() { cd "$srcdir/$pkgname-$pkgver" DESTDIR=$pkgdir/usr make install || return 1 } # vim:set ts=2 sw=2 et: ceph-0.80.11/src/libs3/debian/0000775000175100017510000000000012623076753017722 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/debian/postinst0000775000175100017510000000002412623076753021527 0ustar jenkins-buildjenkins-build#!/bin/sh ldconfig ceph-0.80.11/src/libs3/debian/changelog0000664000175100017510000000025612623076753021577 0ustar jenkins-buildjenkins-buildlibs3 (all) unstable; urgency=low * This file is not maintained. See project source code for changes. -- Bryan Ischo Wed, 06 Aug 2008 09:36:43 -0400 ceph-0.80.11/src/libs3/debian/changelog.Debian0000664000175100017510000000035212623076753022755 0ustar jenkins-buildjenkins-buildlibs3 (all) unstable; urgency=low * libs3 Debian maintainer and upstream author are identical. Therefore see normal changelog file for Debian changes. -- Bryan Ischo Wed, 06 Aug 2008 09:36:43 -0400 ceph-0.80.11/src/libs3/debian/control0000664000175100017510000000073612623076753021333 0ustar jenkins-buildjenkins-buildPackage: libs3 Source: THIS LINE WILL BE REMOVED, dpkg-shlibdepends NEEDS IT Version: LIBS3_VERSION Architecture: DEBIAN_ARCHITECTURE Section: net Priority: extra Maintainer: Bryan Ischo Homepage: http://libs3.ischo.com/index.html Description: C Library and Tools for Amazon S3 Access This package includes the libs3 shared object library, needed to run applications compiled against libs3, and additionally contains the s3 utility for accessing Amazon S3. ceph-0.80.11/src/libs3/debian/control.dev0000664000175100017510000000177112623076753022110 0ustar jenkins-buildjenkins-buildPackage: libs3-dev Version: LIBS3_VERSION Architecture: DEBIAN_ARCHITECTURE Section: libdevel Priority: extra Depends: libs3 (>= LIBS3_VERSION) Maintainer: Bryan Ischo Homepage: http://libs3.ischo.com/index.html Description: C Development Library for Amazon S3 Access This library provides an API for using Amazon's S3 service (see http://s3.amazonaws.com). Its design goals are: . - To provide a simple and straightforward API for accessing all of S3's functionality - To not require the developer using libs3 to need to know anything about: - HTTP - XML - SSL In other words, this API is meant to stand on its own, without requiring any implicit knowledge of how S3 services are accessed using HTTP protocols. - To be usable from multithreaded code - To be usable by code which wants to process multiple S3 requests simultaneously from a single thread - To be usable in the simple, straightforward way using sequentialized blocking requests ceph-0.80.11/src/libs3/GNUmakefile0000664000175100017510000003236212623076753020560 0ustar jenkins-buildjenkins-build# GNUmakefile # # Copyright 2008 Bryan Ischo # # This file is part of libs3. # # libs3 is free software: you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation, version 3 of the License. # # In addition, as a special exception, the copyright holders give # permission to link the code of this library and its programs with the # OpenSSL library, and distribute linked combinations including the two. # # libs3 is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License version 3 # along with libs3, in a file named COPYING. If not, see # . # I tried to use the autoconf/automake/autolocal/etc (i.e. autohell) tools # but I just couldn't stomach them. Since this is a Makefile for POSIX # systems, I will simply do away with autohell completely and use a GNU # Makefile. GNU make ought to be available pretty much everywhere, so I # don't see this being a significant issue for portability. # All commands assume a GNU compiler. For systems which do not use a GNU # compiler, write scripts with the same names as these commands, and taking # the same arguments, and translate the arguments and commands into the # appropriate non-POSIX ones as needed. libs3 assumes a GNU toolchain as # the most portable way to build software possible. Non-POSIX, non-GNU # systems can do the work of supporting this build infrastructure. # -------------------------------------------------------------------------- # Set libs3 version number, unless it is already set. # This is trunk0.trunk0 on the libs3 git master branch; release branches # are created with this set to specific version numbers when releases are # made. LIBS3_VER_MAJOR ?= trunk0 LIBS3_VER_MINOR ?= trunk0 LIBS3_VER := $(LIBS3_VER_MAJOR).$(LIBS3_VER_MINOR) # ----------------------------------------------------------------------------- # Determine verbosity. VERBOSE_SHOW should be prepended to every command which # should only be displayed if VERBOSE is set. QUIET_ECHO may be used to # echo text only if VERBOSE is not set. Typically, a VERBOSE_SHOW command will # be paired with a QUIET_ECHO command, to provide a command which is displayed # in VERBOSE mode, along with text which is displayed in non-VERBOSE mode to # describe the command. # # No matter what VERBOSE is defined to, it ends up as true if it's defined. # This will be weird if you defined VERBOSE=false in the environment, and we # switch it to true here; but the meaning of VERBOSE is, "if it's defined to # any value, then verbosity is turned on". So don't define VERBOSE if you # don't want verbosity in the build process. # ----------------------------------------------------------------------------- ifdef VERBOSE VERBOSE = true VERBOSE_ECHO = @ echo VERBOSE_SHOW = QUIET_ECHO = @ echo > /dev/null else VERBOSE = false VERBOSE_ECHO = @ echo > /dev/null VERBOSE_SHOW = @ QUIET_ECHO = @ echo endif # -------------------------------------------------------------------------- # BUILD directory ifndef BUILD ifdef DEBUG BUILD := build-debug else BUILD := build endif endif # -------------------------------------------------------------------------- # DESTDIR directory ifndef DESTDIR DESTDIR := /usr endif # -------------------------------------------------------------------------- # Acquire configuration information for libraries that libs3 depends upon ifndef CURL_LIBS CURL_LIBS := $(shell curl-config --libs) endif ifndef CURL_CFLAGS CURL_CFLAGS := $(shell curl-config --cflags) endif ifndef LIBXML2_LIBS LIBXML2_LIBS := $(shell xml2-config --libs) endif ifndef LIBXML2_CFLAGS LIBXML2_CFLAGS := $(shell xml2-config --cflags) endif # -------------------------------------------------------------------------- # These CFLAGS assume a GNU compiler. For other compilers, write a script # which converts these arguments into their equivalent for that particular # compiler. ifndef CFLAGS ifdef DEBUG CFLAGS := -g else CFLAGS := -O3 endif endif CFLAGS += -Wall -Werror -Wshadow -Wextra -Iinc \ $(CURL_CFLAGS) $(LIBXML2_CFLAGS) \ -DLIBS3_VER_MAJOR=\"$(LIBS3_VER_MAJOR)\" \ -DLIBS3_VER_MINOR=\"$(LIBS3_VER_MINOR)\" \ -DLIBS3_VER=\"$(LIBS3_VER)\" \ -D__STRICT_ANSI__ \ -D_ISOC99_SOURCE \ -D_POSIX_C_SOURCE=200112L LDFLAGS = $(CURL_LIBS) $(LIBXML2_LIBS) -lpthread # -------------------------------------------------------------------------- # Default targets are everything .PHONY: all all: exported test # -------------------------------------------------------------------------- # Exported targets are the library and driver program .PHONY: exported exported: libs3 s3 headers # -------------------------------------------------------------------------- # Install target # adding empty install target, don't want to install anything when integrated # with ceph .PHONY: install install: # this is the original install target .PHONY: install-all install-all: exported $(QUIET_ECHO) $(DESTDIR)/bin/s3: Installing executable $(VERBOSE_SHOW) install -Dps -m u+rwx,go+rx $(BUILD)/bin/s3 \ $(DESTDIR)/bin/s3 $(QUIET_ECHO) \ $(DESTDIR)/lib/libs3.so.$(LIBS3_VER): Installing shared library $(VERBOSE_SHOW) install -Dps -m u+rw,go+r \ $(BUILD)/lib/libs3.so.$(LIBS3_VER_MAJOR) \ $(DESTDIR)/lib/libs3.so.$(LIBS3_VER) $(QUIET_ECHO) \ $(DESTDIR)/lib/libs3.so.$(LIBS3_VER_MAJOR): Linking shared library $(VERBOSE_SHOW) ln -sf libs3.so.$(LIBS3_VER) \ $(DESTDIR)/lib/libs3.so.$(LIBS3_VER_MAJOR) $(QUIET_ECHO) $(DESTDIR)/lib/libs3.so: Linking shared library $(VERBOSE_SHOW) ln -sf libs3.so.$(LIBS3_VER_MAJOR) $(DESTDIR)/lib/libs3.so $(QUIET_ECHO) $(DESTDIR)/lib/libs3.a: Installing static library $(VERBOSE_SHOW) install -Dp -m u+rw,go+r $(BUILD)/lib/libs3.a \ $(DESTDIR)/lib/libs3.a $(QUIET_ECHO) $(DESTDIR)/include/libs3.h: Installing header $(VERBOSE_SHOW) install -Dp -m u+rw,go+r $(BUILD)/include/libs3.h \ $(DESTDIR)/include/libs3.h # -------------------------------------------------------------------------- # Uninstall target .PHONY: uninstall uninstall: $(QUIET_ECHO) Installed files: Uninstalling $(VERBOSE_SHOW) \ rm -f $(DESTDIR)/bin/s3 \ $(DESTDIR)/include/libs3.h \ $(DESTDIR)/lib/libs3.a \ $(DESTDIR)/lib/libs3.so \ $(DESTDIR)/lib/libs3.so.$(LIBS3_VER_MAJOR) \ $(DESTDIR)/lib/libs3.so.$(LIBS3_VER) # -------------------------------------------------------------------------- # Compile target patterns $(BUILD)/obj/%.o: src/%.c $(QUIET_ECHO) $@: Compiling object @ mkdir -p $(dir $(BUILD)/dep/$<) @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ -o $(BUILD)/dep/$(<:%.c=%.d) -c $< @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc $(CFLAGS) -o $@ -c $< $(BUILD)/obj/%.do: src/%.c $(QUIET_ECHO) $@: Compiling dynamic object @ mkdir -p $(dir $(BUILD)/dep/$<) @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ -o $(BUILD)/dep/$(<:%.c=%.dd) -c $< @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc $(CFLAGS) -fpic -fPIC -o $@ -c $< # -------------------------------------------------------------------------- # libs3 library targets LIBS3_SHARED = $(BUILD)/lib/libs3.so.$(LIBS3_VER_MAJOR) LIBS3_STATIC = $(BUILD)/lib/libs3.a .PHONY: libs3 libs3: $(LIBS3_SHARED) $(LIBS3_STATIC) LIBS3_SOURCES := acl.c bucket.c error_parser.c general.c \ object.c request.c request_context.c \ response_headers_handler.c service_access_logging.c \ service.c simplexml.c util.c $(LIBS3_SHARED): $(LIBS3_SOURCES:%.c=$(BUILD)/obj/%.do) $(QUIET_ECHO) $@: Building shared library @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc -shared -Wl,-soname,libs3.so.$(LIBS3_VER_MAJOR) \ -o $@ $^ $(LDFLAGS) $(LIBS3_STATIC): $(LIBS3_SOURCES:%.c=$(BUILD)/obj/%.o) $(QUIET_ECHO) $@: Building static library @ mkdir -p $(dir $@) $(VERBOSE_SHOW) $(AR) cr $@ $^ # -------------------------------------------------------------------------- # Driver program targets .PHONY: s3 s3: $(BUILD)/bin/s3 $(BUILD)/bin/s3: $(BUILD)/obj/s3.o $(LIBS3_SHARED) $(QUIET_ECHO) $@: Building executable @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc -o $@ $^ $(LDFLAGS) # -------------------------------------------------------------------------- # libs3 header targets .PHONY: headers headers: $(BUILD)/include/libs3.h $(BUILD)/include/libs3.h: inc/libs3.h $(QUIET_ECHO) $@: Linking header @ mkdir -p $(dir $@) $(VERBOSE_SHOW) ln -sf $(abspath $<) $@ # -------------------------------------------------------------------------- # Test targets .PHONY: test test: $(BUILD)/bin/testsimplexml $(BUILD)/bin/testsimplexml: $(BUILD)/obj/testsimplexml.o $(LIBS3_STATIC) $(QUIET_ECHO) $@: Building executable @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc -o $@ $^ $(LIBXML2_LIBS) # -------------------------------------------------------------------------- # Check target check: distdir: dist: # -------------------------------------------------------------------------- # Clean target .PHONY: clean clean: $(QUIET_ECHO) $(BUILD): Cleaning $(VERBOSE_SHOW) rm -rf $(BUILD) .PHONY: distclean distclean: $(QUIET_ECHO) $(BUILD): Cleaning $(VERBOSE_SHOW) rm -rf $(BUILD) # -------------------------------------------------------------------------- # Clean dependencies target .PHONY: cleandeps cleandeps: $(QUIET_ECHO) $(BUILD)/dep: Cleaning dependencies $(VERBOSE_SHOW) rm -rf $(BUILD)/dep # -------------------------------------------------------------------------- # Dependencies ALL_SOURCES := $(LIBS3_SOURCES) s3.c testsimplexml.c $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.d))) $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.dd))) # -------------------------------------------------------------------------- # Debian package target DEBPKG = $(BUILD)/pkg/libs3_$(LIBS3_VER).deb DEBDEVPKG = $(BUILD)/pkg/libs3-dev_$(LIBS3_VER).deb .PHONY: deb deb: $(DEBPKG) $(DEBDEVPKG) $(DEBPKG): DEBARCH = $(shell dpkg-architecture | grep ^DEB_BUILD_ARCH= | \ cut -d '=' -f 2) $(DEBPKG): exported $(BUILD)/deb/DEBIAN/control $(BUILD)/deb/DEBIAN/shlibs \ $(BUILD)/deb/DEBIAN/postinst \ $(BUILD)/deb/usr/share/doc/libs3/changelog.gz \ $(BUILD)/deb/usr/share/doc/libs3/changelog.Debian.gz \ $(BUILD)/deb/usr/share/doc/libs3/copyright DESTDIR=$(BUILD)/deb/usr $(MAKE) install rm -rf $(BUILD)/deb/usr/include rm -f $(BUILD)/deb/usr/lib/libs3.a @mkdir -p $(dir $@) fakeroot dpkg-deb -b $(BUILD)/deb $@ mv $@ $(BUILD)/pkg/libs3_$(LIBS3_VER)_$(DEBARCH).deb $(DEBDEVPKG): DEBARCH = $(shell dpkg-architecture | grep ^DEB_BUILD_ARCH= | \ cut -d '=' -f 2) $(DEBDEVPKG): exported $(BUILD)/deb-dev/DEBIAN/control \ $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.gz \ $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.Debian.gz \ $(BUILD)/deb-dev/usr/share/doc/libs3-dev/copyright DESTDIR=$(BUILD)/deb-dev/usr $(MAKE) install rm -rf $(BUILD)/deb-dev/usr/bin rm -f $(BUILD)/deb-dev/usr/lib/libs3.so* @mkdir -p $(dir $@) fakeroot dpkg-deb -b $(BUILD)/deb-dev $@ mv $@ $(BUILD)/pkg/libs3-dev_$(LIBS3_VER)_$(DEBARCH).deb $(BUILD)/deb/DEBIAN/control: debian/control @mkdir -p $(dir $@) echo -n "Depends: " > $@ dpkg-shlibdeps -Sbuild -O $(BUILD)/lib/libs3.so.$(LIBS3_VER_MAJOR) | \ cut -d '=' -f 2- >> $@ sed -e 's/LIBS3_VERSION/$(LIBS3_VER)/' \ < $< | sed -e 's/DEBIAN_ARCHITECTURE/$(DEBARCH)/' | \ grep -v ^Source: >> $@ $(BUILD)/deb-dev/DEBIAN/control: debian/control.dev @mkdir -p $(dir $@) sed -e 's/LIBS3_VERSION/$(LIBS3_VER)/' \ < $< | sed -e 's/DEBIAN_ARCHITECTURE/$(DEBARCH)/' > $@ $(BUILD)/deb/DEBIAN/shlibs: echo -n "libs3 $(LIBS3_VER_MAJOR) libs3 " > $@ echo "(>= $(LIBS3_VER))" >> $@ $(BUILD)/deb/DEBIAN/postinst: debian/postinst @mkdir -p $(dir $@) cp $< $@ $(BUILD)/deb/usr/share/doc/libs3/copyright: LICENSE @mkdir -p $(dir $@) cp $< $@ @echo >> $@ @echo -n "An alternate location for the GNU General Public " >> $@ @echo "License version 3 on Debian" >> $@ @echo "systems is /usr/share/common-licenses/GPL-3." >> $@ $(BUILD)/deb-dev/usr/share/doc/libs3-dev/copyright: LICENSE @mkdir -p $(dir $@) cp $< $@ @echo >> $@ @echo -n "An alternate location for the GNU General Public " >> $@ @echo "License version 3 on Debian" >> $@ @echo "systems is /usr/share/common-licenses/GPL-3." >> $@ $(BUILD)/deb/usr/share/doc/libs3/changelog.gz: debian/changelog @mkdir -p $(dir $@) gzip --best -c $< > $@ $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.gz: debian/changelog @mkdir -p $(dir $@) gzip --best -c $< > $@ $(BUILD)/deb/usr/share/doc/libs3/changelog.Debian.gz: debian/changelog.Debian @mkdir -p $(dir $@) gzip --best -c $< > $@ $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.Debian.gz: \ debian/changelog.Debian @mkdir -p $(dir $@) gzip --best -c $< > $@ ceph-0.80.11/src/libs3/mswin/0000775000175100017510000000000012623076753017635 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/mswin/rmrf.bat0000664000175100017510000000012512623076753021271 0ustar jenkins-buildjenkins-build@echo off if exist "%1". ( rmdir /S /Q "%1" ) if exist "%1". ( del /Q "%1" ) ceph-0.80.11/src/libs3/mswin/libs3.def0000664000175100017510000000102112623076753021323 0ustar jenkins-buildjenkins-buildEXPORTS S3_convert_acl S3_copy_object S3_create_bucket S3_create_request_context S3_deinitialize S3_delete_bucket S3_delete_object S3_destroy_request_context S3_generate_authenticated_query_string S3_get_acl S3_get_object S3_get_request_context_fdsets S3_get_server_access_logging S3_get_status_name S3_head_object S3_initialize S3_list_bucket S3_list_service S3_put_object S3_runall_request_context S3_runonce_request_context S3_set_acl S3_set_server_access_logging S3_status_is_retryable S3_test_bucket S3_validate_bucket_name ceph-0.80.11/src/libs3/GNUmakefile.osx0000664000175100017510000002370212623076753021366 0ustar jenkins-buildjenkins-build# GNUmakefile.osx # # Copyright 2008 Bryan Ischo # # This file is part of libs3. # # libs3 is free software: you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation, version 3 of the License. # # In addition, as a special exception, the copyright holders give # permission to link the code of this library and its programs with the # OpenSSL library, and distribute linked combinations including the two. # # libs3 is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License version 3 # along with libs3, in a file named COPYING. If not, see # . # I tried to use the autoconf/automake/autolocal/etc (i.e. autohell) tools # but I just couldn't stomach them. Since this is a Makefile for POSIX # systems, I will simply do away with autohell completely and use a GNU # Makefile. GNU make ought to be available pretty much everywhere, so I # don't see this being a significant issue for portability. # All commands assume a GNU compiler. For systems which do not use a GNU # compiler, write scripts with the same names as these commands, and taking # the same arguments, and translate the arguments and commands into the # appropriate non-POSIX ones as needed. libs3 assumes a GNU toolchain as # the most portable way to build software possible. Non-POSIX, non-GNU # systems can do the work of supporting this build infrastructure. # -------------------------------------------------------------------------- # Set libs3 version number, unless it is already set. # This is trunk0.trunk0 on the libs3 git master branch; release branches # are created with this set to specific version numbers when releases are # made. LIBS3_VER_MAJOR ?= trunk0 LIBS3_VER_MINOR ?= trunk0 LIBS3_VER := $(LIBS3_VER_MAJOR).$(LIBS3_VER_MINOR) # ----------------------------------------------------------------------------- # Determine verbosity. VERBOSE_SHOW should be prepended to every command which # should only be displayed if VERBOSE is set. QUIET_ECHO may be used to # echo text only if VERBOSE is not set. Typically, a VERBOSE_SHOW command will # be paired with a QUIET_ECHO command, to provide a command which is displayed # in VERBOSE mode, along with text which is displayed in non-VERBOSE mode to # describe the command. # # No matter what VERBOSE is defined to, it ends up as true if it's defined. # This will be weird if you defined VERBOSE=false in the environment, and we # switch it to true here; but the meaning of VERBOSE is, "if it's defined to # any value, then verbosity is turned on". So don't define VERBOSE if you # don't want verbosity in the build process. # ----------------------------------------------------------------------------- ifdef VERBOSE VERBOSE = true VERBOSE_ECHO = @ echo VERBOSE_SHOW = QUIET_ECHO = @ echo > /dev/null else VERBOSE = false VERBOSE_ECHO = @ echo > /dev/null VERBOSE_SHOW = @ QUIET_ECHO = @ echo endif # -------------------------------------------------------------------------- # BUILD directory ifndef BUILD ifdef DEBUG BUILD := build-debug else BUILD := build endif endif # -------------------------------------------------------------------------- # DESTDIR directory ifndef DESTDIR DESTDIR := /usr endif # -------------------------------------------------------------------------- # Acquire configuration information for libraries that libs3 depends upon ifndef CURL_LIBS CURL_LIBS := $(shell curl-config --libs) endif ifndef CURL_CFLAGS CURL_CFLAGS := $(shell curl-config --cflags) endif ifndef LIBXML2_LIBS LIBXML2_LIBS := $(shell xml2-config --libs) endif ifndef LIBXML2_CFLAGS LIBXML2_CFLAGS := $(shell xml2-config --cflags) endif # -------------------------------------------------------------------------- # These CFLAGS assume a GNU compiler. For other compilers, write a script # which converts these arguments into their equivalent for that particular # compiler. ifndef CFLAGS ifdef DEBUG CFLAGS := -g else CFLAGS := -O3 endif endif CFLAGS += -Wall -Werror -Wshadow -Wextra -Iinc \ $(CURL_CFLAGS) $(LIBXML2_CFLAGS) \ -DLIBS3_VER_MAJOR=\"$(LIBS3_VER_MAJOR)\" \ -DLIBS3_VER_MINOR=\"$(LIBS3_VER_MINOR)\" \ -DLIBS3_VER=\"$(LIBS3_VER)\" \ -D__STRICT_ANSI__ \ -D_ISOC99_SOURCE \ -fno-common LDFLAGS = $(CURL_LIBS) $(LIBXML2_LIBS) -lpthread # -------------------------------------------------------------------------- # Default targets are everything .PHONY: all all: exported test # -------------------------------------------------------------------------- # Exported targets are the library and driver program .PHONY: exported exported: libs3 s3 headers # -------------------------------------------------------------------------- # Install target .PHONY: install install: exported $(QUIET_ECHO) $(DESTDIR)/bin/s3: Installing executable $(VERBOSE_SHOW) install -ps -m u+rwx,go+rx $(BUILD)/bin/s3 \ $(DESTDIR)/bin/s3 $(QUIET_ECHO) \ $(DESTDIR)/lib/libs3.$(LIBS3_VER).dylib: Installing dynamic library $(VERBOSE_SHOW) install -p -m u+rw,go+r \ $(BUILD)/lib/libs3.$(LIBS3_VER_MAJOR).dylib \ $(DESTDIR)/lib/libs3.$(LIBS3_VER).dylib $(QUIET_ECHO) \ $(DESTDIR)/lib/libs3.$(LIBS3_VER_MAJOR).dylib: Linking dynamic library $(VERBOSE_SHOW) ln -sf libs3.$(LIBS3_VER).dylib \ $(DESTDIR)/lib/libs3.$(LIBS3_VER_MAJOR).dylib $(QUIET_ECHO) $(DESTDIR)/lib/libs3.dylib: Linking dynamic library $(VERBOSE_SHOW) ln -sf libs3.$(LIBS3_VER_MAJOR).dylib \ $(DESTDIR)/lib/libs3.dylib $(QUIET_ECHO) $(DESTDIR)/lib/libs3.a: Installing static library $(VERBOSE_SHOW) install -p -m u+rw,go+r $(BUILD)/lib/libs3.a \ $(DESTDIR)/lib/libs3.a $(QUIET_ECHO) $(DESTDIR)/include/libs3.h: Installing header $(VERBOSE_SHOW) install -p -m u+rw,go+r $(BUILD)/include/libs3.h \ $(DESTDIR)/include/libs3.h # -------------------------------------------------------------------------- # Uninstall target .PHONY: uninstall uninstall: $(QUIET_ECHO) Installed files: Uninstalling $(VERBOSE_SHOW) \ rm -f $(DESTDIR)/bin/s3 \ $(DESTDIR)/lib/libs3.dylib \ $(DESTDIR)/lib/libs3.$(LIBS3_VER_MAJOR).dylib \ $(DESTDIR)/lib/libs3.$(LIBS3_VER).dylib \ $(DESTDIR)/lib/libs3.a \ $(DESTDIR)/include/libs3.h # -------------------------------------------------------------------------- # Compile target patterns $(BUILD)/obj/%.o: src/%.c $(QUIET_ECHO) $@: Compiling object @ mkdir -p $(dir $(BUILD)/dep/$<) @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ -o $(BUILD)/dep/$(<:%.c=%.d) -c $< @ mkdir -p $(dir $@) @(VERBOSE_SHOW) gcc $(CFLAGS) -o $@ -c $< $(BUILD)/obj/%.do: src/%.c $(QUIET_ECHO) $@: Compiling dynamic object @ mkdir -p $(dir $(BUILD)/dep/$<) @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ -o $(BUILD)/dep/$(<:%.c=%.dd) -c $< @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc $(CFLAGS) -fpic -fPIC -o $@ -c $< # -------------------------------------------------------------------------- # libs3 library targets LIBS3_SHARED = $(BUILD)/lib/libs3.$(LIBS3_VER_MAJOR).dylib LIBS3_STATIC = $(BUILD)/lib/libs3.a .PHONY: libs3 libs3: $(LIBS3_SHARED) $(LIBS3_SHARED_MAJOR) $(BUILD)/lib/libs3.a LIBS3_SOURCES := src/acl.c src/bucket.c src/error_parser.c src/general.c \ src/object.c src/request.c src/request_context.c \ src/response_headers_handler.c src/service_access_logging.c \ src/service.c src/simplexml.c src/util.c $(LIBS3_SHARED): $(LIBS3_SOURCES:src/%.c=$(BUILD)/obj/%.do) $(QUIET_ECHO) $@: Building shared library @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc -dynamiclib -install_name \ libs3.$(LIBS3_VER_MAJOR).dylib \ -compatibility_version $(LIBS3_VER_MAJOR) \ -current_version $(LIBS3_VER) -o $@ $^ $(LDFLAGS) $(LIBS3_STATIC): $(LIBS3_SOURCES:src/%.c=$(BUILD)/obj/%.o) $(QUIET_ECHO) $@: Building static library @ mkdir -p $(dir $@) $(VERBOSE_SHOW) $(AR) cr $@ $^ # -------------------------------------------------------------------------- # Driver program targets .PHONY: s3 s3: $(BUILD)/bin/s3 $(BUILD)/bin/s3: $(BUILD)/obj/s3.o $(LIBS3_SHARED) $(QUIET_ECHO) $@: Building executable @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc -o $@ $^ $(LDFLAGS) # -------------------------------------------------------------------------- # libs3 header targets .PHONY: headers headers: $(BUILD)/include/libs3.h $(BUILD)/include/libs3.h: inc/libs3.h $(QUIET_ECHO) $@: Linking header @ mkdir -p $(dir $@) $(VERBOSE_SHOW) ln -sf $(abspath $<) $@ # -------------------------------------------------------------------------- # Test targets .PHONY: test test: $(BUILD)/bin/testsimplexml $(BUILD)/bin/testsimplexml: $(BUILD)/obj/testsimplexml.o $(LIBS3_STATIC) $(QUIET_ECHO) $@: Building executable @ mkdir -p $(dir $@) $(VERBOSE_SHOW) gcc -o $@ $^ $(LIBXML2_LIBS) # -------------------------------------------------------------------------- # Clean target .PHONY: clean clean: $(QUIET_ECHO) $(BUILD): Cleaning $(VERBOSE_SHOW) rm -rf $(BUILD) # -------------------------------------------------------------------------- # Clean dependencies target .PHONY: cleandeps cleandeps: $(QUIET_ECHO) $(BUILD)/dep: Cleaning dependencies $(VERBOSE_SHOW) rm -rf $(BUILD)/dep # -------------------------------------------------------------------------- # Dependencies ALL_SOURCES := $(LIBS3_SOURCES) s3.c testsimplexml.c $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.d))) $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.dd))) ceph-0.80.11/src/libs3/INSTALL0000664000175100017510000000456012623076753017536 0ustar jenkins-buildjenkins-build To install libs3 on a POSIX system (except Microsoft Windows): -------------------------------------------------------------- Note that all POSIX builds have prerequisites, such as development libraries that libs3 requires and that must be installed at the time that libs3 is built. The easiest way to find out what those are, is to run the build command and then observe the results. *** For RPM-based systems (Fedora Core, Mandrake, etc) *** * rpmbuild -ta for example: rpmbuild -ta libs3-0.3.tar.gz *** For dpkg-based systems (Debian, Ubuntu, etc) *** * make deb This will produce a Debian package in the build/pkg directory. *** For all other systems *** * make [DESTDIR=destination root] install DESTDIR defaults to /usr To install libs3 on a Microsoft Windows system: ----------------------------------------------- *** Using MingW *** * libs3 can be built on Windows using the MingW compiler. No other tool is needed. However, the following libraries are needed to build libs3: - curl development libraries - libxml2 development libraries, and the libraries that it requires: - iconv - zlib These projects are independent of libs3, and their release schedule and means of distribution would make it very difficult to provide links to the files to download and keep them up-to-date in this file, so no attempt is made here. Development libraries and other files can be placed in: c:\libs3-libs\bin c:\libs3-libs\include If the above locations are used, then the GNUmakefile.mingw will work with no special caveats. If the above locations are not used, then the following environment variables should be set: CURL_LIBS should be set to the MingW compiler flags needed to locate and link in the curl libraries CURL_CFLAGS should be set to the MingW compiler flags needed to locate and include the curl headers LIBXML2_LIBS should be set to the MingW compiler flags needed to locate and link in the libxml2 libraries LIBXML2_CFLAGS should be set to the MingW compiler flags needed to locate and include the libxml2 headers * mingw32-make [DESTDIR=destination] -f GNUmakefile.mingw install DESTDIR defaults to libs3- * DESTDIR can be zipped up into a .zip file for distribution. For best results, the dependent libraries (curl, openssl, etc) should be included, along with their licenses. ceph-0.80.11/src/libs3/libs3.spec0000664000175100017510000000430512623076753020372 0ustar jenkins-buildjenkins-buildSummary: C Library and Tools for Amazon S3 Access Name: libs3 Version: trunk Release: 1 License: GPL Group: Networking/Utilities URL: http://sourceforge.net/projects/reallibs3 Source0: libs3-trunk.tar.gz Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root # Want to include curl dependencies, but older Fedora Core uses curl-devel, # and newer Fedora Core uses libcurl-devel ... have to figure out how to # handle this problem, but for now, just don't check for any curl libraries # Buildrequires: curl-devel Buildrequires: libxml2-devel Buildrequires: openssl-devel Buildrequires: make # Requires: libcurl Requires: libxml2 Requires: openssl %define debug_package %{nil} %description This package includes the libs3 shared object library, needed to run applications compiled against libs3, and additionally contains the s3 utility for accessing Amazon S3. %package devel Summary: Headers and documentation for libs3 Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description devel This library provides an API for using Amazon's S3 service (see http://s3.amazonaws.com). Its design goals are: - To provide a simple and straightforward API for accessing all of S3's functionality - To not require the developer using libs3 to need to know anything about: - HTTP - XML - SSL In other words, this API is meant to stand on its own, without requiring any implicit knowledge of how S3 services are accessed using HTTP protocols. - To be usable from multithreaded code - To be usable by code which wants to process multiple S3 requests simultaneously from a single thread - To be usable in the simple, straightforward way using sequentialized blocking requests %prep %setup -q %build BUILD=$RPM_BUILD_ROOT/build make exported %install BUILD=$RPM_BUILD_ROOT/build DESTDIR=$RPM_BUILD_ROOT/usr make install rm -rf $RPM_BUILD_ROOT/build %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) /usr/bin/s3 /usr/lib/libs3.so* %files devel %defattr(-,root,root,-) /usr/include/libs3.h /usr/lib/libs3.a %changelog * Sat Aug 09 2008 Bryan Ischo - Split into regular and devel packages. * Tue Aug 05 2008 Bryan Ischo - Initial build. ceph-0.80.11/src/libs3/doxyfile0000664000175100017510000010504612623076753020254 0ustar jenkins-buildjenkins-build# Doxyfile 1.2.14 # 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 (" ") #--------------------------------------------------------------------------- # General 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 = libs3 # 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 = trunk # 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 = dox # 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, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, # German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, # Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. OUTPUT_LANGUAGE = English # 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 = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # 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 # 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 class will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = 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 # 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 = NO # 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. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # 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 # 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 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 # users are adviced to set this option to NO. CASE_SENSE_NAMES = YES # 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 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 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 # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # 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 # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = 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 # reimplements. INHERIT_DOCS = 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 = 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 # 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 # 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 # 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 = # 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 consist 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 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 = NO # 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 #--------------------------------------------------------------------------- # 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 # 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. 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 = inc/libs3.h # 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 FILE_PATTERNS = # 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 = YES # 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. 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. INPUT_FILTER = # 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. 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. 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 # 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 #--------------------------------------------------------------------------- # 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 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 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 and frames is required (for instance Mozilla, Netscape 4.0+, # or Internet explorer 4.0+). Note that for large projects the tree generation # can take a very long time. In such cases it is better to disable this feature. # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = YES # 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 # 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 #--------------------------------------------------------------------------- # 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 optimised 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 assigments. 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 = NO # 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. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_XML = NO #--------------------------------------------------------------------------- # 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 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_PREDEFINED 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. PREDEFINED = DOXYGEN # If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY 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 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::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES tag can be used to specify one or more tagfiles. 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 superceded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yield more powerful graphs. CLASS_DIAGRAMS = 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 set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = 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 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 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 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are gif, jpg, and png # If left blank gif will be used. DOT_IMAGE_FORMAT = gif # 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 on 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 # 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 intermedate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions 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 ceph-0.80.11/src/libs3/GNUmakefile.mingw0000664000175100017510000002345412623076753021702 0ustar jenkins-buildjenkins-build# GNUmakefile.mingw # # Copyright 2008 Bryan Ischo # # This file is part of libs3. # # libs3 is free software: you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation, version 3 of the License. # # In addition, as a special exception, the copyright holders give # permission to link the code of this library and its programs with the # OpenSSL library, and distribute linked combinations including the two. # # libs3 is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License version 3 # along with libs3, in a file named COPYING. If not, see # . # I tried to use the autoconf/automake/autolocal/etc (i.e. autohell) tools # but I just couldn't stomach them. Since this is a Makefile for POSIX # systems, I will simply do away with autohell completely and use a GNU # Makefile. GNU make ought to be available pretty much everywhere, so I # don't see this being a significant issue for portability. # All commands assume a GNU compiler. For systems which do not use a GNU # compiler, write scripts with the same names as these commands, and taking # the same arguments, and translate the arguments and commands into the # appropriate non-POSIX ones as needed. libs3 assumes a GNU toolchain as # the most portable way to build software possible. Non-POSIX, non-GNU # systems can do the work of supporting this build infrastructure. # -------------------------------------------------------------------------- # Set libs3 version number, unless it is already set. # This is trunk0.trunk0 on the libs3 git master branch; release branches # are created with this set to specific version numbers when releases are # made. LIBS3_VER_MAJOR ?= trunk0 LIBS3_VER_MINOR ?= trunk0 LIBS3_VER := $(LIBS3_VER_MAJOR).$(LIBS3_VER_MINOR) # ----------------------------------------------------------------------------- # Determine verbosity. VERBOSE_SHOW should be prepended to every command which # should only be displayed if VERBOSE is set. QUIET_ECHO may be used to # echo text only if VERBOSE is not set. Typically, a VERBOSE_SHOW command will # be paired with a QUIET_ECHO command, to provide a command which is displayed # in VERBOSE mode, along with text which is displayed in non-VERBOSE mode to # describe the command. # # No matter what VERBOSE is defined to, it ends up as true if it's defined. # This will be weird if you defined VERBOSE=false in the environment, and we # switch it to true here; but the meaning of VERBOSE is, "if it's defined to # any value, then verbosity is turned on". So don't define VERBOSE if you # don't want verbosity in the build process. # ----------------------------------------------------------------------------- ifdef VERBOSE VERBOSE = true VERBOSE_ECHO = @ echo VERBOSE_SHOW = QUIET_ECHO = @ echo >nul else VERBOSE = false VERBOSE_ECHO = @ echo >nul VERBOSE_SHOW = @ QUIET_ECHO = @ echo endif # -------------------------------------------------------------------------- # BUILD directory ifndef BUILD ifdef DEBUG BUILD := build-debug else BUILD := build endif endif # -------------------------------------------------------------------------- # DESTDIR directory ifndef DESTDIR DESTDIR := libs3-$(LIBS3_VER) endif # -------------------------------------------------------------------------- # Acquire configuration information for libraries that libs3 depends upon ifndef CURL_LIBS CURL_LIBS := -Lc:\libs3-libs\bin -lcurl endif ifndef CURL_CFLAGS CURL_CFLAGS := -Ic:\libs3-libs\include endif ifndef LIBXML2_LIBS LIBXML2_LIBS := -Lc:\libs3-libs\bin -lxml2 endif ifndef LIBXML2_CFLAGS LIBXML2_CFLAGS := -Ic:\libs3-libs\include endif # -------------------------------------------------------------------------- # These CFLAGS assume a GNU compiler. For other compilers, write a script # which converts these arguments into their equivalent for that particular # compiler. ifndef CFLAGS ifdef DEBUG CFLAGS := -g else CFLAGS := -O3 endif endif CFLAGS += -Wall -Werror -Wshadow -Wextra -Iinc \ $(CURL_CFLAGS) $(LIBXML2_CFLAGS) \ -DLIBS3_VER_MAJOR=\"$(LIBS3_VER_MAJOR)\" \ -DLIBS3_VER_MINOR=\"$(LIBS3_VER_MINOR)\" \ -DLIBS3_VER=\"$(LIBS3_VER)\" \ -D__STRICT_ANSI__ \ -D_ISOC99_SOURCE \ -D_POSIX_C_SOURCE=200112L \ -Dsleep=Sleep -DSLEEP_UNITS_PER_SECOND=1000 \ -DFOPEN_EXTRA_FLAGS=\"b\" \ -Iinc/mingw -include windows.h LDFLAGS = $(CURL_LIBS) $(LIBXML2_LIBS) # -------------------------------------------------------------------------- # Default targets are everything .PHONY: all all: exported test # -------------------------------------------------------------------------- # Exported targets are the library and driver program .PHONY: exported exported: libs3 s3 headers # -------------------------------------------------------------------------- # Install target .PHONY: install install: exported $(QUIET_ECHO) $(DESTDIR)/bin/s3.exe: Installing executable - @ mkdir $(DESTDIR)\bin 2>&1 | echo >nul $(VERBOSE_SHOW) copy $(BUILD)\bin\s3.exe $(DESTDIR)\bin\s3.exe >nul $(QUIET_ECHO) $(DESTDIR)/bin/libs3/dll: Installing dynamic library $(VERBOSE_SHOW) copy $(BUILD)\bin\libs3.dll $(DESTDIR)\bin\libs3.dll >nul $(QUIET_ECHO) $(DESTDIR)/lib/libs3.a: Installing static library - @ mkdir $(DESTDIR)\lib 2>&1 | echo >nul $(VERBOSE_SHOW) copy $(BUILD)\lib\libs3.a $(DESTDIR)\lib\libs3.a >nul $(QUIET_ECHO) $(DESTDIR)/lib/libs3.def: Installing def file $(VERBOSE_SHOW) copy mswin\libs3.def $(DESTDIR)\lib\libs3.def >nul - @ mkdir $(DESTDIR)\include 2>&1 | echo >nul $(QUIET_ECHO) $(DESTDIR)/include/libs3.h: Copying header $(VERBOSE_SHOW) copy $(BUILD)\include\libs3.h \ $(DESTDIR)\include\libs3.h >nul $(QUIET_ECHO) $(DESTDIR)/LICENSE: Copying license $(VERBOSE_SHOW) copy LICENSE $(DESTDIR)\LICENSE >nul $(QUIET_ECHO) $(DESTDIR)/COPYING: Copying license $(VERBOSE_SHOW) copy COPYING $(DESTDIR)\COPYING >nul # -------------------------------------------------------------------------- # Uninstall target .PHONY: uninstall uninstall: $(QUIET_ECHO) Installed files: Uninstalling $(VERBOSE_SHOW) \ del $(DESTDIR)\bin\s3.exe \ $(DESTDIR)\bin\libs3.dll \ $(DESTDIR)\lib\libs3.a \ $(DESTDIR)\lib\libs3.def \ $(DESTDIR)\include\libs3.h \ $(DESTDIR)\LICENSE \ $(DESTDIR)\COPYING # -------------------------------------------------------------------------- # Compile target patterns $(BUILD)/obj/%.o: src/%.c $(QUIET_ECHO) $@: Compiling object - @ mkdir $(subst /,\,$(dir $(BUILD)/dep/$<)) 2>&1 | echo >nul @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ -o $(BUILD)/dep/$(<:%.c=%.d) -c $< - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul $(VERBOSE_SHOW) gcc $(CFLAGS) -o $@ -c $< # -------------------------------------------------------------------------- # libs3 library targets LIBS3_SHARED = $(BUILD)/bin/libs3.dll LIBS3_STATIC = $(BUILD)/lib/libs3.a .PHONY: libs3 libs3: $(LIBS3_SHARED) $(BUILD)/lib/libs3.a LIBS3_SOURCES := src/acl.c src/bucket.c src/error_parser.c src/general.c \ src/object.c src/request.c src/request_context.c \ src/response_headers_handler.c src/service_access_logging.c \ src/service.c src/simplexml.c src/util.c src/mingw_functions.c $(LIBS3_SHARED): $(LIBS3_SOURCES:src/%.c=$(BUILD)/obj/%.o) $(QUIET_ECHO) $@: Building dynamic library - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul $(VERBOSE_SHOW) gcc -shared -o $@ $^ $(LDFLAGS) -lws2_32 $(LIBS3_STATIC): $(LIBS3_SHARED) $(QUIET_ECHO) $@: Building static library - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul $(VERBOSE_SHOW) dlltool --def mswin\libs3.def --dllname $(subst /,\,$<) \ --output-lib $(subst /,\,$@) # -------------------------------------------------------------------------- # Driver program targets .PHONY: s3 s3: $(BUILD)/bin/s3.exe $(BUILD)/bin/s3.exe: $(BUILD)/obj/s3.o $(BUILD)/obj/mingw_s3_functions.o \ $(BUILD)/lib/libs3.a $(QUIET_ECHO) $@: Building executable - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul $(VERBOSE_SHOW) gcc -o $@ $^ $(LDFLAGS) -lws2_32 # -------------------------------------------------------------------------- # libs3 header targets .PHONY: headers headers: $(BUILD)\include\libs3.h $(BUILD)\include\libs3.h: inc\libs3.h $(QUIET_ECHO) $@: Copying header - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul $(VERBOSE_SHOW) copy $< $@ # -------------------------------------------------------------------------- # Test targets .PHONY: test test: $(BUILD)/bin/testsimplexml $(BUILD)/bin/testsimplexml: $(BUILD)/obj/testsimplexml.o \ $(BUILD)/obj/simplexml.o $(QUIET_ECHO) $@: Building executable - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul $(VERBOSE_SHOW) gcc -o $@ $^ $(LIBXML2_LIBS) # -------------------------------------------------------------------------- # Clean target .PHONY: clean clean: $(QUIET_ECHO) $(BUILD): Cleaning $(VERBOSE_SHOW) mswin\rmrf.bat $(BUILD) # -------------------------------------------------------------------------- # Clean dependencies target .PHONY: cleandeps cleandeps: $(QUIET_ECHO) $(BUILD)/dep: Cleaning dependencies $(VERBOSE_SHOW) mswin\rmrf.bat $(BUILD)\dep # -------------------------------------------------------------------------- # Dependencies ALL_SOURCES := $(LIBS3_SOURCES) s3.c testsimplexml.c $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.d))) ceph-0.80.11/src/libs3/ChangeLog0000664000175100017510000000121512623076753020251 0ustar jenkins-buildjenkins-buildThu Sep 18 10:03:02 NZST 2008 bryan@ischo.com * This file is no longer maintained, sorry Sat Aug 9 13:44:21 NZST 2008 bryan@ischo.com * Fixed bug wherein keys with non-URI-safe characters did not work correctly because they were not being URI-encoded in the request UR * Split RPM and DEB packages into normal and devel packages Fri Aug 8 22:40:19 NZST 2008 bryan@ischo.com * Branched 0.4 * Created RPM and Debian packaging Tue Aug 5 08:52:33 NZST 2008 bryan@ischo.com * Bumped version number to 0.3 * Moved Makefile to GNUmakefile, added shared library build * Added a bunch of GNU standard files (README, INSTALL, ChangeLog, etc) ceph-0.80.11/src/libs3/src/0000775000175100017510000000000012623076753017267 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/src/mingw_s3_functions.c0000664000175100017510000000241312623076753023251 0ustar jenkins-buildjenkins-build/** ************************************************************************** * mingw_s3_functions.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ int setenv(const char *a, const char *b, int c) { (void) c; return SetEnvironmentVariable(a, b); } int unsetenv(const char *a) { return SetEnvironmentVariable(a, 0); } ceph-0.80.11/src/libs3/src/s3.c0000664000175100017510000025146412623076753017774 0ustar jenkins-buildjenkins-build/** ************************************************************************** * s3.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ /** * This is a 'driver' program that simply converts command-line input into * calls to libs3 functions, and prints the results. **/ #include #include #include #include #include #include #include #include #include #include #include "libs3.h" // Some Windows stuff #ifndef FOPEN_EXTRA_FLAGS #define FOPEN_EXTRA_FLAGS "" #endif // Some Unix stuff (to work around Windows issues) #ifndef SLEEP_UNITS_PER_SECOND #define SLEEP_UNITS_PER_SECOND 1 #endif // Also needed for Windows, because somehow MinGW doesn't define this extern int putenv(char *); // Command-line options, saved as globals ------------------------------------ static int forceG = 0; static int showResponsePropertiesG = 0; static S3Protocol protocolG = S3ProtocolHTTPS; static S3UriStyle uriStyleG = S3UriStylePath; static int retriesG = 5; // Environment variables, saved as globals ---------------------------------- static const char *accessKeyIdG = 0; static const char *secretAccessKeyG = 0; // Request results, saved as globals ----------------------------------------- static int statusG = 0; static char errorDetailsG[4096] = { 0 }; // Other globals ------------------------------------------------------------- static char putenvBufG[256]; // Option prefixes ----------------------------------------------------------- #define LOCATION_PREFIX "location=" #define LOCATION_PREFIX_LEN (sizeof(LOCATION_PREFIX) - 1) #define CANNED_ACL_PREFIX "cannedAcl=" #define CANNED_ACL_PREFIX_LEN (sizeof(CANNED_ACL_PREFIX) - 1) #define PREFIX_PREFIX "prefix=" #define PREFIX_PREFIX_LEN (sizeof(PREFIX_PREFIX) - 1) #define MARKER_PREFIX "marker=" #define MARKER_PREFIX_LEN (sizeof(MARKER_PREFIX) - 1) #define DELIMITER_PREFIX "delimiter=" #define DELIMITER_PREFIX_LEN (sizeof(DELIMITER_PREFIX) - 1) #define MAXKEYS_PREFIX "maxkeys=" #define MAXKEYS_PREFIX_LEN (sizeof(MAXKEYS_PREFIX) - 1) #define FILENAME_PREFIX "filename=" #define FILENAME_PREFIX_LEN (sizeof(FILENAME_PREFIX) - 1) #define CONTENT_LENGTH_PREFIX "contentLength=" #define CONTENT_LENGTH_PREFIX_LEN (sizeof(CONTENT_LENGTH_PREFIX) - 1) #define CACHE_CONTROL_PREFIX "cacheControl=" #define CACHE_CONTROL_PREFIX_LEN (sizeof(CACHE_CONTROL_PREFIX) - 1) #define CONTENT_TYPE_PREFIX "contentType=" #define CONTENT_TYPE_PREFIX_LEN (sizeof(CONTENT_TYPE_PREFIX) - 1) #define MD5_PREFIX "md5=" #define MD5_PREFIX_LEN (sizeof(MD5_PREFIX) - 1) #define CONTENT_DISPOSITION_FILENAME_PREFIX "contentDispositionFilename=" #define CONTENT_DISPOSITION_FILENAME_PREFIX_LEN \ (sizeof(CONTENT_DISPOSITION_FILENAME_PREFIX) - 1) #define CONTENT_ENCODING_PREFIX "contentEncoding=" #define CONTENT_ENCODING_PREFIX_LEN (sizeof(CONTENT_ENCODING_PREFIX) - 1) #define EXPIRES_PREFIX "expires=" #define EXPIRES_PREFIX_LEN (sizeof(EXPIRES_PREFIX) - 1) #define X_AMZ_META_PREFIX "x-amz-meta-" #define X_AMZ_META_PREFIX_LEN (sizeof(X_AMZ_META_PREFIX) - 1) #define IF_MODIFIED_SINCE_PREFIX "ifModifiedSince=" #define IF_MODIFIED_SINCE_PREFIX_LEN (sizeof(IF_MODIFIED_SINCE_PREFIX) - 1) #define IF_NOT_MODIFIED_SINCE_PREFIX "ifNotmodifiedSince=" #define IF_NOT_MODIFIED_SINCE_PREFIX_LEN \ (sizeof(IF_NOT_MODIFIED_SINCE_PREFIX) - 1) #define IF_MATCH_PREFIX "ifMatch=" #define IF_MATCH_PREFIX_LEN (sizeof(IF_MATCH_PREFIX) - 1) #define IF_NOT_MATCH_PREFIX "ifNotMatch=" #define IF_NOT_MATCH_PREFIX_LEN (sizeof(IF_NOT_MATCH_PREFIX) - 1) #define START_BYTE_PREFIX "startByte=" #define START_BYTE_PREFIX_LEN (sizeof(START_BYTE_PREFIX) - 1) #define BYTE_COUNT_PREFIX "byteCount=" #define BYTE_COUNT_PREFIX_LEN (sizeof(BYTE_COUNT_PREFIX) - 1) #define ALL_DETAILS_PREFIX "allDetails=" #define ALL_DETAILS_PREFIX_LEN (sizeof(ALL_DETAILS_PREFIX) - 1) #define NO_STATUS_PREFIX "noStatus=" #define NO_STATUS_PREFIX_LEN (sizeof(NO_STATUS_PREFIX) - 1) #define RESOURCE_PREFIX "resource=" #define RESOURCE_PREFIX_LEN (sizeof(RESOURCE_PREFIX) - 1) #define TARGET_BUCKET_PREFIX "targetBucket=" #define TARGET_BUCKET_PREFIX_LEN (sizeof(TARGET_BUCKET_PREFIX) - 1) #define TARGET_PREFIX_PREFIX "targetPrefix=" #define TARGET_PREFIX_PREFIX_LEN (sizeof(TARGET_PREFIX_PREFIX) - 1) // util ---------------------------------------------------------------------- static void S3_init() { S3Status status; const char *hostname = getenv("S3_HOSTNAME"); if ((status = S3_initialize("s3", S3_INIT_ALL, hostname)) != S3StatusOK) { fprintf(stderr, "Failed to initialize libs3: %s\n", S3_get_status_name(status)); exit(-1); } } static void printError() { if (statusG < S3StatusErrorAccessDenied) { fprintf(stderr, "\nERROR: %s\n", S3_get_status_name(statusG)); } else { fprintf(stderr, "\nERROR: %s\n", S3_get_status_name(statusG)); fprintf(stderr, "%s\n", errorDetailsG); } } static void usageExit(FILE *out) { fprintf(out, "\n Options:\n" "\n" " Command Line:\n" "\n" " -f/--force : force operation despite warnings\n" " -h/--vhost-style : use virtual-host-style URIs (default is " "path-style)\n" " -u/--unencrypted : unencrypted (use HTTP instead of HTTPS)\n" " -s/--show-properties : show response properties on stdout\n" " -r/--retries : retry retryable failures this number of times\n" " (default is 5)\n" "\n" " Environment:\n" "\n" " S3_ACCESS_KEY_ID : S3 access key ID (required)\n" " S3_SECRET_ACCESS_KEY : S3 secret access key (required)\n" " S3_HOSTNAME : specify alternative S3 host (optional)\n" "\n" " Commands (with and [optional parameters]) :\n" "\n" " (NOTE: all command parameters take a value and are specified using the\n" " pattern parameter=value)\n" "\n" " help : Prints this help text\n" "\n" " list : Lists owned buckets\n" " [allDetails] : Show full details\n" "\n" " test : Tests a bucket for existence and accessibility\n" " : Bucket to test\n" "\n" " create : Create a new bucket\n" " : Bucket to create\n" " [cannedAcl] : Canned ACL for the bucket (see Canned ACLs)\n" " [location] : Location for bucket (for example, EU)\n" "\n" " delete : Delete a bucket or key\n" " [/] : Bucket or bucket/key to delete\n" "\n" " list : List bucket contents\n" " : Bucket to list\n" " [prefix] : Prefix for results set\n" " [marker] : Where in results set to start listing\n" " [delimiter] : Delimiter for rolling up results set\n" " [maxkeys] : Maximum number of keys to return in results set\n" " [allDetails] : Show full details for each key\n" "\n" " getacl : Get the ACL of a bucket or key\n" " [/] : Bucket or bucket/key to get the ACL of\n" " [filename] : Output filename for ACL (default is stdout)\n" "\n" " setacl : Set the ACL of a bucket or key\n" " [/] : Bucket or bucket/key to set the ACL of\n" " [filename] : Input filename for ACL (default is stdin)\n" "\n" " getlogging : Get the logging status of a bucket\n" " : Bucket to get the logging status of\n" " [filename] : Output filename for ACL (default is stdout)\n" "\n" " setlogging : Set the logging status of a bucket\n" " : Bucket to set the logging status of\n" " [targetBucket] : Target bucket to log to; if not present, disables\n" " logging\n" " [targetPrefix] : Key prefix to use for logs\n" " [filename] : Input filename for ACL (default is stdin)\n" "\n" " put : Puts an object\n" " / : Bucket/key to put object to\n" " [filename] : Filename to read source data from " "(default is stdin)\n" " [contentLength] : How many bytes of source data to put (required if\n" " source file is stdin)\n" " [cacheControl] : Cache-Control HTTP header string to associate with\n" " object\n" " [contentType] : Content-Type HTTP header string to associate with\n" " object\n" " [md5] : MD5 for validating source data\n" " [contentDispositionFilename] : Content-Disposition filename string to\n" " associate with object\n" " [contentEncoding] : Content-Encoding HTTP header string to associate\n" " with object\n" " [expires] : Expiration date to associate with object\n" " [cannedAcl] : Canned ACL for the object (see Canned ACLs)\n" " [x-amz-meta-...]] : Metadata headers to associate with the object\n" "\n" " copy : Copies an object; if any options are set, the " "entire\n" " metadata of the object is replaced\n" " / : Source bucket/key\n" " / : Destination bucket/key\n" " [cacheControl] : Cache-Control HTTP header string to associate with\n" " object\n" " [contentType] : Content-Type HTTP header string to associate with\n" " object\n" " [contentDispositionFilename] : Content-Disposition filename string to\n" " associate with object\n" " [contentEncoding] : Content-Encoding HTTP header string to associate\n" " with object\n" " [expires] : Expiration date to associate with object\n" " [cannedAcl] : Canned ACL for the object (see Canned ACLs)\n" " [x-amz-meta-...]] : Metadata headers to associate with the object\n" "\n" " get : Gets an object\n" " / : Bucket/key of object to get\n" " [filename] : Filename to write object data to (required if -s\n" " command line parameter was used)\n" " [ifModifiedSince] : Only return the object if it has been modified " "since\n" " this date\n" " [ifNotmodifiedSince] : Only return the object if it has not been " "modified\n" " since this date\n" " [ifMatch] : Only return the object if its ETag header matches\n" " this string\n" " [ifNotMatch] : Only return the object if its ETag header does " "not\n" " match this string\n" " [startByte] : First byte of byte range to return\n" " [byteCount] : Number of bytes of byte range to return\n" "\n" " head : Gets only the headers of an object, implies -s\n" " / : Bucket/key of object to get headers of\n" "\n" " gqs : Generates an authenticated query string\n" " [/] : Bucket or bucket/key to generate query string for\n" " [expires] : Expiration date for query string\n" " [resource] : Sub-resource of key for query string, without a\n" " leading '?', for example, \"torrent\"\n" "\n" " Canned ACLs:\n" "\n" " The following canned ACLs are supported:\n" " private (default), public-read, public-read-write, authenticated-read\n" "\n" " ACL Format:\n" "\n" " For the getacl and setacl commands, the format of the ACL list is:\n" " 1) An initial line giving the owner id in this format:\n" " OwnerID \n" " 2) Optional header lines, giving column headers, starting with the\n" " word \"Type\", or with some number of dashes\n" " 3) Grant lines, of the form:\n" " (whitespace) (whitespace) \n" " where Grant Type is one of: Email, UserID, or Group, and\n" " Grantee is the identification of the grantee based on this type,\n" " and Permission is one of: READ, WRITE, READ_ACP, or FULL_CONTROL.\n" "\n" " Note that the easiest way to modify an ACL is to first get it, saving it\n" " into a file, then modifying the file, and then setting the modified file\n" " back as the new ACL for the bucket/object.\n" "\n" " Date Format:\n" "\n" " The format for dates used in parameters is as ISO 8601 dates, i.e.\n" " YYYY-MM-DDTHH:MM:SS[+/-dd:dd]. Examples:\n" " 2008-07-29T20:36:14\n" " 2008-07-29T20:36:14-06:00\n" " 2008-07-29T20:36:14+11:30\n" "\n"); exit(-1); } static uint64_t convertInt(const char *str, const char *paramName) { uint64_t ret = 0; while (*str) { if (!isdigit(*str)) { fprintf(stderr, "\nERROR: Nondigit in %s parameter: %c\n", paramName, *str); usageExit(stderr); } ret *= 10; ret += (*str++ - '0'); } return ret; } typedef struct growbuffer { // The total number of bytes, and the start byte int size; // The start byte int start; // The blocks char data[64 * 1024]; struct growbuffer *prev, *next; } growbuffer; // returns nonzero on success, zero on out of memory static int growbuffer_append(growbuffer **gb, const char *data, int dataLen) { while (dataLen) { growbuffer *buf = *gb ? (*gb)->prev : 0; if (!buf || (buf->size == sizeof(buf->data))) { buf = (growbuffer *) malloc(sizeof(growbuffer)); if (!buf) { return 0; } buf->size = 0; buf->start = 0; if (*gb) { buf->prev = (*gb)->prev; buf->next = *gb; (*gb)->prev->next = buf; (*gb)->prev = buf; } else { buf->prev = buf->next = buf; *gb = buf; } } int toCopy = (sizeof(buf->data) - buf->size); if (toCopy > dataLen) { toCopy = dataLen; } memcpy(&(buf->data[buf->size]), data, toCopy); buf->size += toCopy, data += toCopy, dataLen -= toCopy; } return 1; } static void growbuffer_read(growbuffer **gb, int amt, int *amtReturn, char *buffer) { *amtReturn = 0; growbuffer *buf = *gb; if (!buf) { return; } *amtReturn = (buf->size > amt) ? amt : buf->size; memcpy(buffer, &(buf->data[buf->start]), *amtReturn); buf->start += *amtReturn, buf->size -= *amtReturn; if (buf->size == 0) { if (buf->next == buf) { *gb = 0; } else { *gb = buf->next; buf->prev->next = buf->next; buf->next->prev = buf->prev; } free(buf); } } static void growbuffer_destroy(growbuffer *gb) { growbuffer *start = gb; while (gb) { growbuffer *next = gb->next; free(gb); gb = (next == start) ? 0 : next; } } // Convenience utility for making the code look nicer. Tests a string // against a format; only the characters specified in the format are // checked (i.e. if the string is longer than the format, the string still // checks out ok). Format characters are: // d - is a digit // anything else - is that character // Returns nonzero the string checks out, zero if it does not. static int checkString(const char *str, const char *format) { while (*format) { if (*format == 'd') { if (!isdigit(*str)) { return 0; } } else if (*str != *format) { return 0; } str++, format++; } return 1; } static int64_t parseIso8601Time(const char *str) { // Check to make sure that it has a valid format if (!checkString(str, "dddd-dd-ddTdd:dd:dd")) { return -1; } #define nextnum() (((*str - '0') * 10) + (*(str + 1) - '0')) // Convert it struct tm stm; memset(&stm, 0, sizeof(stm)); stm.tm_year = (nextnum() - 19) * 100; str += 2; stm.tm_year += nextnum(); str += 3; stm.tm_mon = nextnum() - 1; str += 3; stm.tm_mday = nextnum(); str += 3; stm.tm_hour = nextnum(); str += 3; stm.tm_min = nextnum(); str += 3; stm.tm_sec = nextnum(); str += 2; stm.tm_isdst = -1; // This is hokey but it's the recommended way ... char *tz = getenv("TZ"); snprintf(putenvBufG, sizeof(putenvBufG), "TZ=UTC"); putenv(putenvBufG); int64_t ret = mktime(&stm); snprintf(putenvBufG, sizeof(putenvBufG), "TZ=%s", tz ? tz : ""); putenv(putenvBufG); // Skip the millis if (*str == '.') { str++; while (isdigit(*str)) { str++; } } if (checkString(str, "-dd:dd") || checkString(str, "+dd:dd")) { int sign = (*str++ == '-') ? -1 : 1; int hours = nextnum(); str += 3; int minutes = nextnum(); ret += (-sign * (((hours * 60) + minutes) * 60)); } // Else it should be Z to be a conformant time string, but we just assume // that it is rather than enforcing that return ret; } // Simple ACL format: Lines of this format: // Type - ignored // Starting with a dash - ignored // Email email_address permission // UserID user_id (display_name) permission // Group Authenticated AWS Users permission // Group All Users permission // permission is one of READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL static int convert_simple_acl(char *aclXml, char *ownerId, char *ownerDisplayName, int *aclGrantCountReturn, S3AclGrant *aclGrants) { *aclGrantCountReturn = 0; *ownerId = 0; *ownerDisplayName = 0; #define SKIP_SPACE(require_more) \ do { \ while (isspace(*aclXml)) { \ aclXml++; \ } \ if (require_more && !*aclXml) { \ return 0; \ } \ } while (0) #define COPY_STRING_MAXLEN(field, maxlen) \ do { \ SKIP_SPACE(1); \ int len = 0; \ while ((len < maxlen) && !isspace(*aclXml)) { \ field[len++] = *aclXml++; \ } \ field[len] = 0; \ } while (0) #define COPY_STRING(field) \ COPY_STRING_MAXLEN(field, (int) (sizeof(field) - 1)) while (1) { SKIP_SPACE(0); if (!*aclXml) { break; } // Skip Type lines and dash lines if (!strncmp(aclXml, "Type", sizeof("Type") - 1) || (*aclXml == '-')) { while (*aclXml && ((*aclXml != '\n') && (*aclXml != '\r'))) { aclXml++; } continue; } if (!strncmp(aclXml, "OwnerID", sizeof("OwnerID") - 1)) { aclXml += sizeof("OwnerID") - 1; COPY_STRING_MAXLEN(ownerId, S3_MAX_GRANTEE_USER_ID_SIZE); SKIP_SPACE(1); COPY_STRING_MAXLEN(ownerDisplayName, S3_MAX_GRANTEE_DISPLAY_NAME_SIZE); continue; } if (*aclGrantCountReturn == S3_MAX_ACL_GRANT_COUNT) { return 0; } S3AclGrant *grant = &(aclGrants[(*aclGrantCountReturn)++]); if (!strncmp(aclXml, "Email", sizeof("Email") - 1)) { grant->granteeType = S3GranteeTypeAmazonCustomerByEmail; aclXml += sizeof("Email") - 1; COPY_STRING(grant->grantee.amazonCustomerByEmail.emailAddress); } else if (!strncmp(aclXml, "UserID", sizeof("UserID") - 1)) { grant->granteeType = S3GranteeTypeCanonicalUser; aclXml += sizeof("UserID") - 1; COPY_STRING(grant->grantee.canonicalUser.id); SKIP_SPACE(1); // Now do display name COPY_STRING(grant->grantee.canonicalUser.displayName); } else if (!strncmp(aclXml, "Group", sizeof("Group") - 1)) { aclXml += sizeof("Group") - 1; SKIP_SPACE(1); if (!strncmp(aclXml, "Authenticated AWS Users", sizeof("Authenticated AWS Users") - 1)) { grant->granteeType = S3GranteeTypeAllAwsUsers; aclXml += (sizeof("Authenticated AWS Users") - 1); } else if (!strncmp(aclXml, "All Users", sizeof("All Users") - 1)) { grant->granteeType = S3GranteeTypeAllUsers; aclXml += (sizeof("All Users") - 1); } else if (!strncmp(aclXml, "Log Delivery", sizeof("Log Delivery") - 1)) { grant->granteeType = S3GranteeTypeLogDelivery; aclXml += (sizeof("Log Delivery") - 1); } else { return 0; } } else { return 0; } SKIP_SPACE(1); if (!strncmp(aclXml, "READ_ACP", sizeof("READ_ACP") - 1)) { grant->permission = S3PermissionReadACP; aclXml += (sizeof("READ_ACP") - 1); } else if (!strncmp(aclXml, "READ", sizeof("READ") - 1)) { grant->permission = S3PermissionRead; aclXml += (sizeof("READ") - 1); } else if (!strncmp(aclXml, "WRITE_ACP", sizeof("WRITE_ACP") - 1)) { grant->permission = S3PermissionWriteACP; aclXml += (sizeof("WRITE_ACP") - 1); } else if (!strncmp(aclXml, "WRITE", sizeof("WRITE") - 1)) { grant->permission = S3PermissionWrite; aclXml += (sizeof("WRITE") - 1); } else if (!strncmp(aclXml, "FULL_CONTROL", sizeof("FULL_CONTROL") - 1)) { grant->permission = S3PermissionFullControl; aclXml += (sizeof("FULL_CONTROL") - 1); } } return 1; } static int should_retry() { if (retriesG--) { // Sleep before next retry; start out with a 1 second sleep static int retrySleepInterval = 1 * SLEEP_UNITS_PER_SECOND; sleep(retrySleepInterval); // Next sleep 1 second longer retrySleepInterval++; return 1; } return 0; } static struct option longOptionsG[] = { { "force", no_argument, 0, 'f' }, { "vhost-style", no_argument, 0, 'h' }, { "unencrypted", no_argument, 0, 'u' }, { "show-properties", no_argument, 0, 's' }, { "retries", required_argument, 0, 'r' }, { 0, 0, 0, 0 } }; // response properties callback ---------------------------------------------- // This callback does the same thing for every request type: prints out the // properties if the user has requested them to be so static S3Status responsePropertiesCallback (const S3ResponseProperties *properties, void *callbackData) { (void) callbackData; if (!showResponsePropertiesG) { return S3StatusOK; } #define print_nonnull(name, field) \ do { \ if (properties-> field) { \ printf("%s: %s\n", name, properties-> field); \ } \ } while (0) print_nonnull("Content-Type", contentType); print_nonnull("Request-Id", requestId); print_nonnull("Request-Id-2", requestId2); if (properties->contentLength > 0) { printf("Content-Length: %lld\n", (unsigned long long) properties->contentLength); } print_nonnull("Server", server); print_nonnull("ETag", eTag); if (properties->lastModified > 0) { char timebuf[256]; time_t t = (time_t) properties->lastModified; // gmtime is not thread-safe but we don't care here. strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); printf("Last-Modified: %s\n", timebuf); } int i; for (i = 0; i < properties->metaDataCount; i++) { printf("x-amz-meta-%s: %s\n", properties->metaData[i].name, properties->metaData[i].value); } return S3StatusOK; } // response complete callback ------------------------------------------------ // This callback does the same thing for every request type: saves the status // and error stuff in global variables static void responseCompleteCallback(S3Status status, const S3ErrorDetails *error, void *callbackData) { (void) callbackData; statusG = status; // Compose the error details message now, although we might not use it. // Can't just save a pointer to [error] since it's not guaranteed to last // beyond this callback int len = 0; if (error && error->message) { len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len, " Message: %s\n", error->message); } if (error && error->resource) { len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len, " Resource: %s\n", error->resource); } if (error && error->furtherDetails) { len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len, " Further Details: %s\n", error->furtherDetails); } if (error && error->extraDetailsCount) { len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len, "%s", " Extra Details:\n"); int i; for (i = 0; i < error->extraDetailsCount; i++) { len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len, " %s: %s\n", error->extraDetails[i].name, error->extraDetails[i].value); } } } // list service -------------------------------------------------------------- typedef struct list_service_data { int headerPrinted; int allDetails; } list_service_data; static void printListServiceHeader(int allDetails) { printf("%-56s %-20s", " Bucket", " Created"); if (allDetails) { printf(" %-64s %-12s", " Owner ID", "Display Name"); } printf("\n"); printf("-------------------------------------------------------- " "--------------------"); if (allDetails) { printf(" -------------------------------------------------" "--------------- ------------"); } printf("\n"); } static S3Status listServiceCallback(const char *ownerId, const char *ownerDisplayName, const char *bucketName, int64_t creationDate, void *callbackData) { list_service_data *data = (list_service_data *) callbackData; if (!data->headerPrinted) { data->headerPrinted = 1; printListServiceHeader(data->allDetails); } char timebuf[256]; if (creationDate >= 0) { time_t t = (time_t) creationDate; strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); } else { timebuf[0] = 0; } printf("%-56s %-20s", bucketName, timebuf); if (data->allDetails) { printf(" %-64s %-12s", ownerId ? ownerId : "", ownerDisplayName ? ownerDisplayName : ""); } printf("\n"); return S3StatusOK; } static void list_service(int allDetails) { list_service_data data; data.headerPrinted = 0; data.allDetails = allDetails; S3_init(); S3ListServiceHandler listServiceHandler = { { &responsePropertiesCallback, &responseCompleteCallback }, &listServiceCallback }; do { S3_list_service(protocolG, accessKeyIdG, secretAccessKeyG, 0, 0, &listServiceHandler, &data); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG == S3StatusOK) { if (!data.headerPrinted) { printListServiceHeader(allDetails); } } else { printError(); } S3_deinitialize(); } // test bucket --------------------------------------------------------------- static void test_bucket(int argc, char **argv, int optindex) { // test bucket if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket\n"); usageExit(stderr); } const char *bucketName = argv[optindex++]; if (optindex != argc) { fprintf(stderr, "\nERROR: Extraneous parameter: %s\n", argv[optindex]); usageExit(stderr); } S3_init(); S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; char locationConstraint[64]; do { S3_test_bucket(protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG, 0, bucketName, sizeof(locationConstraint), locationConstraint, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); const char *result; switch (statusG) { case S3StatusOK: // bucket exists result = locationConstraint[0] ? locationConstraint : "USA"; break; case S3StatusErrorNoSuchBucket: result = "Does Not Exist"; break; case S3StatusErrorAccessDenied: result = "Access Denied"; break; default: result = 0; break; } if (result) { printf("%-56s %-20s\n", " Bucket", " Status"); printf("-------------------------------------------------------- " "--------------------\n"); printf("%-56s %-20s\n", bucketName, result); } else { printError(); } S3_deinitialize(); } // create bucket ------------------------------------------------------------- static void create_bucket(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket\n"); usageExit(stderr); } const char *bucketName = argv[optindex++]; if (!forceG && (S3_validate_bucket_name (bucketName, S3UriStyleVirtualHost) != S3StatusOK)) { fprintf(stderr, "\nWARNING: Bucket name is not valid for " "virtual-host style URI access.\n"); fprintf(stderr, "Bucket not created. Use -f option to force the " "bucket to be created despite\n"); fprintf(stderr, "this warning.\n\n"); exit(-1); } const char *locationConstraint = 0; S3CannedAcl cannedAcl = S3CannedAclPrivate; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, LOCATION_PREFIX, LOCATION_PREFIX_LEN)) { locationConstraint = &(param[LOCATION_PREFIX_LEN]); } else if (!strncmp(param, CANNED_ACL_PREFIX, CANNED_ACL_PREFIX_LEN)) { char *val = &(param[CANNED_ACL_PREFIX_LEN]); if (!strcmp(val, "private")) { cannedAcl = S3CannedAclPrivate; } else if (!strcmp(val, "public-read")) { cannedAcl = S3CannedAclPublicRead; } else if (!strcmp(val, "public-read-write")) { cannedAcl = S3CannedAclPublicReadWrite; } else if (!strcmp(val, "authenticated-read")) { cannedAcl = S3CannedAclAuthenticatedRead; } else { fprintf(stderr, "\nERROR: Unknown canned ACL: %s\n", val); usageExit(stderr); } } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } S3_init(); S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_create_bucket(protocolG, accessKeyIdG, secretAccessKeyG, 0, bucketName, cannedAcl, locationConstraint, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG == S3StatusOK) { printf("Bucket successfully created.\n"); } else { printError(); } S3_deinitialize(); } // delete bucket ------------------------------------------------------------- static void delete_bucket(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket\n"); usageExit(stderr); } const char *bucketName = argv[optindex++]; if (optindex != argc) { fprintf(stderr, "\nERROR: Extraneous parameter: %s\n", argv[optindex]); usageExit(stderr); } S3_init(); S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_delete_bucket(protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG, 0, bucketName, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG != S3StatusOK) { printError(); } S3_deinitialize(); } // list bucket --------------------------------------------------------------- typedef struct list_bucket_callback_data { int isTruncated; char nextMarker[1024]; int keyCount; int allDetails; } list_bucket_callback_data; static void printListBucketHeader(int allDetails) { printf("%-50s %-20s %-5s", " Key", " Last Modified", "Size"); if (allDetails) { printf(" %-34s %-64s %-12s", " ETag", " Owner ID", "Display Name"); } printf("\n"); printf("-------------------------------------------------- " "-------------------- -----"); if (allDetails) { printf(" ---------------------------------- " "-------------------------------------------------" "--------------- ------------"); } printf("\n"); } static S3Status listBucketCallback(int isTruncated, const char *nextMarker, int contentsCount, const S3ListBucketContent *contents, int commonPrefixesCount, const char **commonPrefixes, void *callbackData) { list_bucket_callback_data *data = (list_bucket_callback_data *) callbackData; data->isTruncated = isTruncated; // This is tricky. S3 doesn't return the NextMarker if there is no // delimiter. Why, I don't know, since it's still useful for paging // through results. We want NextMarker to be the last content in the // list, so set it to that if necessary. if ((!nextMarker || !nextMarker[0]) && contentsCount) { nextMarker = contents[contentsCount - 1].key; } if (nextMarker) { snprintf(data->nextMarker, sizeof(data->nextMarker), "%s", nextMarker); } else { data->nextMarker[0] = 0; } if (contentsCount && !data->keyCount) { printListBucketHeader(data->allDetails); } int i; for (i = 0; i < contentsCount; i++) { const S3ListBucketContent *content = &(contents[i]); char timebuf[256]; if (0) { time_t t = (time_t) content->lastModified; strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); printf("\nKey: %s\n", content->key); printf("Last Modified: %s\n", timebuf); printf("ETag: %s\n", content->eTag); printf("Size: %llu\n", (unsigned long long) content->size); if (content->ownerId) { printf("Owner ID: %s\n", content->ownerId); } if (content->ownerDisplayName) { printf("Owner Display Name: %s\n", content->ownerDisplayName); } } else { time_t t = (time_t) content->lastModified; strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); char sizebuf[16]; if (content->size < 100000) { sprintf(sizebuf, "%5llu", (unsigned long long) content->size); } else if (content->size < (1024 * 1024)) { sprintf(sizebuf, "%4lluK", ((unsigned long long) content->size) / 1024ULL); } else if (content->size < (10 * 1024 * 1024)) { float f = content->size; f /= (1024 * 1024); sprintf(sizebuf, "%1.2fM", f); } else if (content->size < (1024 * 1024 * 1024)) { sprintf(sizebuf, "%4lluM", ((unsigned long long) content->size) / (1024ULL * 1024ULL)); } else { float f = (content->size / 1024); f /= (1024 * 1024); sprintf(sizebuf, "%1.2fG", f); } printf("%-50s %s %s", content->key, timebuf, sizebuf); if (data->allDetails) { printf(" %-34s %-64s %-12s", content->eTag, content->ownerId ? content->ownerId : "", content->ownerDisplayName ? content->ownerDisplayName : ""); } printf("\n"); } } data->keyCount += contentsCount; for (i = 0; i < commonPrefixesCount; i++) { printf("\nCommon Prefix: %s\n", commonPrefixes[i]); } return S3StatusOK; } static void list_bucket(const char *bucketName, const char *prefix, const char *marker, const char *delimiter, int maxkeys, int allDetails) { S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ListBucketHandler listBucketHandler = { { &responsePropertiesCallback, &responseCompleteCallback }, &listBucketCallback }; list_bucket_callback_data data; snprintf(data.nextMarker, sizeof(data.nextMarker), "%s", marker); data.keyCount = 0; data.allDetails = allDetails; do { data.isTruncated = 0; do { S3_list_bucket(&bucketContext, prefix, data.nextMarker, delimiter, maxkeys, 0, &listBucketHandler, &data); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG != S3StatusOK) { break; } } while (data.isTruncated && (!maxkeys || (data.keyCount < maxkeys))); if (statusG == S3StatusOK) { if (!data.keyCount) { printListBucketHeader(allDetails); } } else { printError(); } S3_deinitialize(); } static void list(int argc, char **argv, int optindex) { if (optindex == argc) { list_service(0); return; } const char *bucketName = 0; const char *prefix = 0, *marker = 0, *delimiter = 0; int maxkeys = 0, allDetails = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, PREFIX_PREFIX, PREFIX_PREFIX_LEN)) { prefix = &(param[PREFIX_PREFIX_LEN]); } else if (!strncmp(param, MARKER_PREFIX, MARKER_PREFIX_LEN)) { marker = &(param[MARKER_PREFIX_LEN]); } else if (!strncmp(param, DELIMITER_PREFIX, DELIMITER_PREFIX_LEN)) { delimiter = &(param[DELIMITER_PREFIX_LEN]); } else if (!strncmp(param, MAXKEYS_PREFIX, MAXKEYS_PREFIX_LEN)) { maxkeys = convertInt(&(param[MAXKEYS_PREFIX_LEN]), "maxkeys"); } else if (!strncmp(param, ALL_DETAILS_PREFIX, ALL_DETAILS_PREFIX_LEN)) { const char *ad = &(param[ALL_DETAILS_PREFIX_LEN]); if (!strcmp(ad, "true") || !strcmp(ad, "TRUE") || !strcmp(ad, "yes") || !strcmp(ad, "YES") || !strcmp(ad, "1")) { allDetails = 1; } } else if (!bucketName) { bucketName = param; } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } if (bucketName) { list_bucket(bucketName, prefix, marker, delimiter, maxkeys, allDetails); } else { list_service(allDetails); } } // delete object ------------------------------------------------------------- static void delete_object(int argc, char **argv, int optindex) { (void) argc; // Split bucket/key char *slash = argv[optindex]; // We know there is a slash in there, put_object is only called if so while (*slash && (*slash != '/')) { slash++; } *slash++ = 0; const char *bucketName = argv[optindex++]; const char *key = slash; S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ResponseHandler responseHandler = { 0, &responseCompleteCallback }; do { S3_delete_object(&bucketContext, key, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if ((statusG != S3StatusOK) && (statusG != S3StatusErrorPreconditionFailed)) { printError(); } S3_deinitialize(); } // put object ---------------------------------------------------------------- typedef struct put_object_callback_data { FILE *infile; growbuffer *gb; uint64_t contentLength, originalContentLength; int noStatus; } put_object_callback_data; static int putObjectDataCallback(int bufferSize, char *buffer, void *callbackData) { put_object_callback_data *data = (put_object_callback_data *) callbackData; int ret = 0; if (data->contentLength) { int toRead = ((data->contentLength > (unsigned) bufferSize) ? (unsigned) bufferSize : data->contentLength); if (data->gb) { growbuffer_read(&(data->gb), toRead, &ret, buffer); } else if (data->infile) { ret = fread(buffer, 1, toRead, data->infile); } } data->contentLength -= ret; if (data->contentLength && !data->noStatus) { // Avoid a weird bug in MingW, which won't print the second integer // value properly when it's in the same call, so print separately printf("%llu bytes remaining ", (unsigned long long) data->contentLength); printf("(%d%% complete) ...\n", (int) (((data->originalContentLength - data->contentLength) * 100) / data->originalContentLength)); } return ret; } static void put_object(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket/key\n"); usageExit(stderr); } // Split bucket/key char *slash = argv[optindex]; while (*slash && (*slash != '/')) { slash++; } if (!*slash || !*(slash + 1)) { fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n", argv[optindex]); usageExit(stderr); } *slash++ = 0; const char *bucketName = argv[optindex++]; const char *key = slash; const char *filename = 0; uint64_t contentLength = 0; const char *cacheControl = 0, *contentType = 0, *md5 = 0; const char *contentDispositionFilename = 0, *contentEncoding = 0; int64_t expires = -1; S3CannedAcl cannedAcl = S3CannedAclPrivate; int metaPropertiesCount = 0; S3NameValue metaProperties[S3_MAX_METADATA_COUNT]; int noStatus = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) { filename = &(param[FILENAME_PREFIX_LEN]); } else if (!strncmp(param, CONTENT_LENGTH_PREFIX, CONTENT_LENGTH_PREFIX_LEN)) { contentLength = convertInt(&(param[CONTENT_LENGTH_PREFIX_LEN]), "contentLength"); if (contentLength > (5LL * 1024 * 1024 * 1024)) { fprintf(stderr, "\nERROR: contentLength must be no greater " "than 5 GB\n"); usageExit(stderr); } } else if (!strncmp(param, CACHE_CONTROL_PREFIX, CACHE_CONTROL_PREFIX_LEN)) { cacheControl = &(param[CACHE_CONTROL_PREFIX_LEN]); } else if (!strncmp(param, CONTENT_TYPE_PREFIX, CONTENT_TYPE_PREFIX_LEN)) { contentType = &(param[CONTENT_TYPE_PREFIX_LEN]); } else if (!strncmp(param, MD5_PREFIX, MD5_PREFIX_LEN)) { md5 = &(param[MD5_PREFIX_LEN]); } else if (!strncmp(param, CONTENT_DISPOSITION_FILENAME_PREFIX, CONTENT_DISPOSITION_FILENAME_PREFIX_LEN)) { contentDispositionFilename = &(param[CONTENT_DISPOSITION_FILENAME_PREFIX_LEN]); } else if (!strncmp(param, CONTENT_ENCODING_PREFIX, CONTENT_ENCODING_PREFIX_LEN)) { contentEncoding = &(param[CONTENT_ENCODING_PREFIX_LEN]); } else if (!strncmp(param, EXPIRES_PREFIX, EXPIRES_PREFIX_LEN)) { expires = parseIso8601Time(&(param[EXPIRES_PREFIX_LEN])); if (expires < 0) { fprintf(stderr, "\nERROR: Invalid expires time " "value; ISO 8601 time format required\n"); usageExit(stderr); } } else if (!strncmp(param, X_AMZ_META_PREFIX, X_AMZ_META_PREFIX_LEN)) { if (metaPropertiesCount == S3_MAX_METADATA_COUNT) { fprintf(stderr, "\nERROR: Too many x-amz-meta- properties, " "limit %lu: %s\n", (unsigned long) S3_MAX_METADATA_COUNT, param); usageExit(stderr); } char *name = &(param[X_AMZ_META_PREFIX_LEN]); char *value = name; while (*value && (*value != '=')) { value++; } if (!*value || !*(value + 1)) { fprintf(stderr, "\nERROR: Invalid parameter: %s\n", param); usageExit(stderr); } *value++ = 0; metaProperties[metaPropertiesCount].name = name; metaProperties[metaPropertiesCount++].value = value; } else if (!strncmp(param, CANNED_ACL_PREFIX, CANNED_ACL_PREFIX_LEN)) { char *val = &(param[CANNED_ACL_PREFIX_LEN]); if (!strcmp(val, "private")) { cannedAcl = S3CannedAclPrivate; } else if (!strcmp(val, "public-read")) { cannedAcl = S3CannedAclPublicRead; } else if (!strcmp(val, "public-read-write")) { cannedAcl = S3CannedAclPublicReadWrite; } else if (!strcmp(val, "authenticated-read")) { cannedAcl = S3CannedAclAuthenticatedRead; } else { fprintf(stderr, "\nERROR: Unknown canned ACL: %s\n", val); usageExit(stderr); } } else if (!strncmp(param, NO_STATUS_PREFIX, NO_STATUS_PREFIX_LEN)) { const char *ns = &(param[NO_STATUS_PREFIX_LEN]); if (!strcmp(ns, "true") || !strcmp(ns, "TRUE") || !strcmp(ns, "yes") || !strcmp(ns, "YES") || !strcmp(ns, "1")) { noStatus = 1; } } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } put_object_callback_data data; data.infile = 0; data.gb = 0; data.noStatus = noStatus; if (filename) { if (!contentLength) { struct stat statbuf; // Stat the file to get its length if (stat(filename, &statbuf) == -1) { fprintf(stderr, "\nERROR: Failed to stat file %s: ", filename); perror(0); exit(-1); } contentLength = statbuf.st_size; } // Open the file if (!(data.infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) { fprintf(stderr, "\nERROR: Failed to open input file %s: ", filename); perror(0); exit(-1); } } else { // Read from stdin. If contentLength is not provided, we have // to read it all in to get contentLength. if (!contentLength) { // Read all if stdin to get the data char buffer[64 * 1024]; while (1) { int amtRead = fread(buffer, 1, sizeof(buffer), stdin); if (amtRead == 0) { break; } if (!growbuffer_append(&(data.gb), buffer, amtRead)) { fprintf(stderr, "\nERROR: Out of memory while reading " "stdin\n"); exit(-1); } contentLength += amtRead; if (amtRead < (int) sizeof(buffer)) { break; } } } else { data.infile = stdin; } } data.contentLength = data.originalContentLength = contentLength; S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3PutProperties putProperties = { contentType, md5, cacheControl, contentDispositionFilename, contentEncoding, expires, cannedAcl, metaPropertiesCount, metaProperties }; S3PutObjectHandler putObjectHandler = { { &responsePropertiesCallback, &responseCompleteCallback }, &putObjectDataCallback }; do { S3_put_object(&bucketContext, key, contentLength, &putProperties, 0, &putObjectHandler, &data); } while (S3_status_is_retryable(statusG) && should_retry()); if (data.infile) { fclose(data.infile); } else if (data.gb) { growbuffer_destroy(data.gb); } if (statusG != S3StatusOK) { printError(); } else if (data.contentLength) { fprintf(stderr, "\nERROR: Failed to read remaining %llu bytes from " "input\n", (unsigned long long) data.contentLength); } S3_deinitialize(); } // copy object --------------------------------------------------------------- static void copy_object(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: source bucket/key\n"); usageExit(stderr); } // Split bucket/key char *slash = argv[optindex]; while (*slash && (*slash != '/')) { slash++; } if (!*slash || !*(slash + 1)) { fprintf(stderr, "\nERROR: Invalid source bucket/key name: %s\n", argv[optindex]); usageExit(stderr); } *slash++ = 0; const char *sourceBucketName = argv[optindex++]; const char *sourceKey = slash; if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: " "destination bucket/key\n"); usageExit(stderr); } // Split bucket/key slash = argv[optindex]; while (*slash && (*slash != '/')) { slash++; } if (!*slash || !*(slash + 1)) { fprintf(stderr, "\nERROR: Invalid destination bucket/key name: %s\n", argv[optindex]); usageExit(stderr); } *slash++ = 0; const char *destinationBucketName = argv[optindex++]; const char *destinationKey = slash; const char *cacheControl = 0, *contentType = 0; const char *contentDispositionFilename = 0, *contentEncoding = 0; int64_t expires = -1; S3CannedAcl cannedAcl = S3CannedAclPrivate; int metaPropertiesCount = 0; S3NameValue metaProperties[S3_MAX_METADATA_COUNT]; int anyPropertiesSet = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, CACHE_CONTROL_PREFIX, CACHE_CONTROL_PREFIX_LEN)) { cacheControl = &(param[CACHE_CONTROL_PREFIX_LEN]); anyPropertiesSet = 1; } else if (!strncmp(param, CONTENT_TYPE_PREFIX, CONTENT_TYPE_PREFIX_LEN)) { contentType = &(param[CONTENT_TYPE_PREFIX_LEN]); anyPropertiesSet = 1; } else if (!strncmp(param, CONTENT_DISPOSITION_FILENAME_PREFIX, CONTENT_DISPOSITION_FILENAME_PREFIX_LEN)) { contentDispositionFilename = &(param[CONTENT_DISPOSITION_FILENAME_PREFIX_LEN]); anyPropertiesSet = 1; } else if (!strncmp(param, CONTENT_ENCODING_PREFIX, CONTENT_ENCODING_PREFIX_LEN)) { contentEncoding = &(param[CONTENT_ENCODING_PREFIX_LEN]); anyPropertiesSet = 1; } else if (!strncmp(param, EXPIRES_PREFIX, EXPIRES_PREFIX_LEN)) { expires = parseIso8601Time(&(param[EXPIRES_PREFIX_LEN])); if (expires < 0) { fprintf(stderr, "\nERROR: Invalid expires time " "value; ISO 8601 time format required\n"); usageExit(stderr); } anyPropertiesSet = 1; } else if (!strncmp(param, X_AMZ_META_PREFIX, X_AMZ_META_PREFIX_LEN)) { if (metaPropertiesCount == S3_MAX_METADATA_COUNT) { fprintf(stderr, "\nERROR: Too many x-amz-meta- properties, " "limit %lu: %s\n", (unsigned long) S3_MAX_METADATA_COUNT, param); usageExit(stderr); } char *name = &(param[X_AMZ_META_PREFIX_LEN]); char *value = name; while (*value && (*value != '=')) { value++; } if (!*value || !*(value + 1)) { fprintf(stderr, "\nERROR: Invalid parameter: %s\n", param); usageExit(stderr); } *value++ = 0; metaProperties[metaPropertiesCount].name = name; metaProperties[metaPropertiesCount++].value = value; anyPropertiesSet = 1; } else if (!strncmp(param, CANNED_ACL_PREFIX, CANNED_ACL_PREFIX_LEN)) { char *val = &(param[CANNED_ACL_PREFIX_LEN]); if (!strcmp(val, "private")) { cannedAcl = S3CannedAclPrivate; } else if (!strcmp(val, "public-read")) { cannedAcl = S3CannedAclPublicRead; } else if (!strcmp(val, "public-read-write")) { cannedAcl = S3CannedAclPublicReadWrite; } else if (!strcmp(val, "authenticated-read")) { cannedAcl = S3CannedAclAuthenticatedRead; } else { fprintf(stderr, "\nERROR: Unknown canned ACL: %s\n", val); usageExit(stderr); } anyPropertiesSet = 1; } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } S3_init(); S3BucketContext bucketContext = { 0, sourceBucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3PutProperties putProperties = { contentType, 0, cacheControl, contentDispositionFilename, contentEncoding, expires, cannedAcl, metaPropertiesCount, metaProperties }; S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; int64_t lastModified; char eTag[256]; do { S3_copy_object(&bucketContext, sourceKey, destinationBucketName, destinationKey, anyPropertiesSet ? &putProperties : 0, &lastModified, sizeof(eTag), eTag, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG == S3StatusOK) { if (lastModified >= 0) { char timebuf[256]; time_t t = (time_t) lastModified; strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); printf("Last-Modified: %s\n", timebuf); } if (eTag[0]) { printf("ETag: %s\n", eTag); } } else { printError(); } S3_deinitialize(); } // get object ---------------------------------------------------------------- static S3Status getObjectDataCallback(int bufferSize, const char *buffer, void *callbackData) { FILE *outfile = (FILE *) callbackData; size_t wrote = fwrite(buffer, 1, bufferSize, outfile); return ((wrote < (size_t) bufferSize) ? S3StatusAbortedByCallback : S3StatusOK); } static void get_object(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket/key\n"); usageExit(stderr); } // Split bucket/key char *slash = argv[optindex]; while (*slash && (*slash != '/')) { slash++; } if (!*slash || !*(slash + 1)) { fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n", argv[optindex]); usageExit(stderr); } *slash++ = 0; const char *bucketName = argv[optindex++]; const char *key = slash; const char *filename = 0; int64_t ifModifiedSince = -1, ifNotModifiedSince = -1; const char *ifMatch = 0, *ifNotMatch = 0; uint64_t startByte = 0, byteCount = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) { filename = &(param[FILENAME_PREFIX_LEN]); } else if (!strncmp(param, IF_MODIFIED_SINCE_PREFIX, IF_MODIFIED_SINCE_PREFIX_LEN)) { // Parse ifModifiedSince ifModifiedSince = parseIso8601Time (&(param[IF_MODIFIED_SINCE_PREFIX_LEN])); if (ifModifiedSince < 0) { fprintf(stderr, "\nERROR: Invalid ifModifiedSince time " "value; ISO 8601 time format required\n"); usageExit(stderr); } } else if (!strncmp(param, IF_NOT_MODIFIED_SINCE_PREFIX, IF_NOT_MODIFIED_SINCE_PREFIX_LEN)) { // Parse ifModifiedSince ifNotModifiedSince = parseIso8601Time (&(param[IF_NOT_MODIFIED_SINCE_PREFIX_LEN])); if (ifNotModifiedSince < 0) { fprintf(stderr, "\nERROR: Invalid ifNotModifiedSince time " "value; ISO 8601 time format required\n"); usageExit(stderr); } } else if (!strncmp(param, IF_MATCH_PREFIX, IF_MATCH_PREFIX_LEN)) { ifMatch = &(param[IF_MATCH_PREFIX_LEN]); } else if (!strncmp(param, IF_NOT_MATCH_PREFIX, IF_NOT_MATCH_PREFIX_LEN)) { ifNotMatch = &(param[IF_NOT_MATCH_PREFIX_LEN]); } else if (!strncmp(param, START_BYTE_PREFIX, START_BYTE_PREFIX_LEN)) { startByte = convertInt (&(param[START_BYTE_PREFIX_LEN]), "startByte"); } else if (!strncmp(param, BYTE_COUNT_PREFIX, BYTE_COUNT_PREFIX_LEN)) { byteCount = convertInt (&(param[BYTE_COUNT_PREFIX_LEN]), "byteCount"); } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } FILE *outfile = 0; if (filename) { // Stat the file, and if it doesn't exist, open it in w mode struct stat buf; if (stat(filename, &buf) == -1) { outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS); } else { // Open in r+ so that we don't truncate the file, just in case // there is an error and we write no bytes, we leave the file // unmodified outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS); } if (!outfile) { fprintf(stderr, "\nERROR: Failed to open output file %s: ", filename); perror(0); exit(-1); } } else if (showResponsePropertiesG) { fprintf(stderr, "\nERROR: get -s requires a filename parameter\n"); usageExit(stderr); } else { outfile = stdout; } S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3GetConditions getConditions = { ifModifiedSince, ifNotModifiedSince, ifMatch, ifNotMatch }; S3GetObjectHandler getObjectHandler = { { &responsePropertiesCallback, &responseCompleteCallback }, &getObjectDataCallback }; do { S3_get_object(&bucketContext, key, &getConditions, startByte, byteCount, 0, &getObjectHandler, outfile); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG != S3StatusOK) { printError(); } fclose(outfile); S3_deinitialize(); } // head object --------------------------------------------------------------- static void head_object(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket/key\n"); usageExit(stderr); } // Head implies showing response properties showResponsePropertiesG = 1; // Split bucket/key char *slash = argv[optindex]; while (*slash && (*slash != '/')) { slash++; } if (!*slash || !*(slash + 1)) { fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n", argv[optindex]); usageExit(stderr); } *slash++ = 0; const char *bucketName = argv[optindex++]; const char *key = slash; if (optindex != argc) { fprintf(stderr, "\nERROR: Extraneous parameter: %s\n", argv[optindex]); usageExit(stderr); } S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_head_object(&bucketContext, key, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if ((statusG != S3StatusOK) && (statusG != S3StatusErrorPreconditionFailed)) { printError(); } S3_deinitialize(); } // generate query string ------------------------------------------------------ static void generate_query_string(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket[/key]\n"); usageExit(stderr); } const char *bucketName = argv[optindex]; const char *key = 0; // Split bucket/key char *slash = argv[optindex++]; while (*slash && (*slash != '/')) { slash++; } if (*slash) { *slash++ = 0; key = slash; } else { key = 0; } int64_t expires = -1; const char *resource = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, EXPIRES_PREFIX, EXPIRES_PREFIX_LEN)) { expires = parseIso8601Time(&(param[EXPIRES_PREFIX_LEN])); if (expires < 0) { fprintf(stderr, "\nERROR: Invalid expires time " "value; ISO 8601 time format required\n"); usageExit(stderr); } } else if (!strncmp(param, RESOURCE_PREFIX, RESOURCE_PREFIX_LEN)) { resource = &(param[RESOURCE_PREFIX_LEN]); } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; char buffer[S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE]; S3Status status = S3_generate_authenticated_query_string (buffer, &bucketContext, key, expires, resource); if (status != S3StatusOK) { printf("Failed to generate authenticated query string: %s\n", S3_get_status_name(status)); } else { printf("%s\n", buffer); } S3_deinitialize(); } // get acl ------------------------------------------------------------------- void get_acl(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket[/key]\n"); usageExit(stderr); } const char *bucketName = argv[optindex]; const char *key = 0; // Split bucket/key char *slash = argv[optindex++]; while (*slash && (*slash != '/')) { slash++; } if (*slash) { *slash++ = 0; key = slash; } else { key = 0; } const char *filename = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) { filename = &(param[FILENAME_PREFIX_LEN]); } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } FILE *outfile = 0; if (filename) { // Stat the file, and if it doesn't exist, open it in w mode struct stat buf; if (stat(filename, &buf) == -1) { outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS); } else { // Open in r+ so that we don't truncate the file, just in case // there is an error and we write no bytes, we leave the file // unmodified outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS); } if (!outfile) { fprintf(stderr, "\nERROR: Failed to open output file %s: ", filename); perror(0); exit(-1); } } else if (showResponsePropertiesG) { fprintf(stderr, "\nERROR: getacl -s requires a filename parameter\n"); usageExit(stderr); } else { outfile = stdout; } int aclGrantCount; S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT]; char ownerId[S3_MAX_GRANTEE_USER_ID_SIZE]; char ownerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE]; S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_get_acl(&bucketContext, key, ownerId, ownerDisplayName, &aclGrantCount, aclGrants, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG == S3StatusOK) { fprintf(outfile, "OwnerID %s %s\n", ownerId, ownerDisplayName); fprintf(outfile, "%-6s %-90s %-12s\n", " Type", " User Identifier", " Permission"); fprintf(outfile, "------ " "------------------------------------------------------------" "------------------------------ ------------\n"); int i; for (i = 0; i < aclGrantCount; i++) { S3AclGrant *grant = &(aclGrants[i]); const char *type; char composedId[S3_MAX_GRANTEE_USER_ID_SIZE + S3_MAX_GRANTEE_DISPLAY_NAME_SIZE + 16]; const char *id; switch (grant->granteeType) { case S3GranteeTypeAmazonCustomerByEmail: type = "Email"; id = grant->grantee.amazonCustomerByEmail.emailAddress; break; case S3GranteeTypeCanonicalUser: type = "UserID"; snprintf(composedId, sizeof(composedId), "%s (%s)", grant->grantee.canonicalUser.id, grant->grantee.canonicalUser.displayName); id = composedId; break; case S3GranteeTypeAllAwsUsers: type = "Group"; id = "Authenticated AWS Users"; break; case S3GranteeTypeAllUsers: type = "Group"; id = "All Users"; break; default: type = "Group"; id = "Log Delivery"; break; } const char *perm; switch (grant->permission) { case S3PermissionRead: perm = "READ"; break; case S3PermissionWrite: perm = "WRITE"; break; case S3PermissionReadACP: perm = "READ_ACP"; break; case S3PermissionWriteACP: perm = "WRITE_ACP"; break; default: perm = "FULL_CONTROL"; break; } fprintf(outfile, "%-6s %-90s %-12s\n", type, id, perm); } } else { printError(); } fclose(outfile); S3_deinitialize(); } // set acl ------------------------------------------------------------------- void set_acl(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket[/key]\n"); usageExit(stderr); } const char *bucketName = argv[optindex]; const char *key = 0; // Split bucket/key char *slash = argv[optindex++]; while (*slash && (*slash != '/')) { slash++; } if (*slash) { *slash++ = 0; key = slash; } else { key = 0; } const char *filename = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) { filename = &(param[FILENAME_PREFIX_LEN]); } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } FILE *infile; if (filename) { if (!(infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) { fprintf(stderr, "\nERROR: Failed to open input file %s: ", filename); perror(0); exit(-1); } } else { infile = stdin; } // Read in the complete ACL char aclBuf[65536]; aclBuf[fread(aclBuf, 1, sizeof(aclBuf), infile)] = 0; char ownerId[S3_MAX_GRANTEE_USER_ID_SIZE]; char ownerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE]; // Parse it int aclGrantCount; S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT]; if (!convert_simple_acl(aclBuf, ownerId, ownerDisplayName, &aclGrantCount, aclGrants)) { fprintf(stderr, "\nERROR: Failed to parse ACLs\n"); fclose(infile); exit(-1); } S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_set_acl(&bucketContext, key, ownerId, ownerDisplayName, aclGrantCount, aclGrants, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG != S3StatusOK) { printError(); } fclose(infile); S3_deinitialize(); } // get logging ---------------------------------------------------------------- void get_logging(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket\n"); usageExit(stderr); } const char *bucketName = argv[optindex++]; const char *filename = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) { filename = &(param[FILENAME_PREFIX_LEN]); } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } FILE *outfile = 0; if (filename) { // Stat the file, and if it doesn't exist, open it in w mode struct stat buf; if (stat(filename, &buf) == -1) { outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS); } else { // Open in r+ so that we don't truncate the file, just in case // there is an error and we write no bytes, we leave the file // unmodified outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS); } if (!outfile) { fprintf(stderr, "\nERROR: Failed to open output file %s: ", filename); perror(0); exit(-1); } } else if (showResponsePropertiesG) { fprintf(stderr, "\nERROR: getlogging -s requires a filename " "parameter\n"); usageExit(stderr); } else { outfile = stdout; } int aclGrantCount; S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT]; char targetBucket[S3_MAX_BUCKET_NAME_SIZE]; char targetPrefix[S3_MAX_KEY_SIZE]; S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_get_server_access_logging(&bucketContext, targetBucket, targetPrefix, &aclGrantCount, aclGrants, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG == S3StatusOK) { if (targetBucket[0]) { printf("Target Bucket: %s\n", targetBucket); if (targetPrefix[0]) { printf("Target Prefix: %s\n", targetPrefix); } fprintf(outfile, "%-6s %-90s %-12s\n", " Type", " User Identifier", " Permission"); fprintf(outfile, "------ " "---------------------------------------------------------" "--------------------------------- ------------\n"); int i; for (i = 0; i < aclGrantCount; i++) { S3AclGrant *grant = &(aclGrants[i]); const char *type; char composedId[S3_MAX_GRANTEE_USER_ID_SIZE + S3_MAX_GRANTEE_DISPLAY_NAME_SIZE + 16]; const char *id; switch (grant->granteeType) { case S3GranteeTypeAmazonCustomerByEmail: type = "Email"; id = grant->grantee.amazonCustomerByEmail.emailAddress; break; case S3GranteeTypeCanonicalUser: type = "UserID"; snprintf(composedId, sizeof(composedId), "%s (%s)", grant->grantee.canonicalUser.id, grant->grantee.canonicalUser.displayName); id = composedId; break; case S3GranteeTypeAllAwsUsers: type = "Group"; id = "Authenticated AWS Users"; break; default: type = "Group"; id = "All Users"; break; } const char *perm; switch (grant->permission) { case S3PermissionRead: perm = "READ"; break; case S3PermissionWrite: perm = "WRITE"; break; case S3PermissionReadACP: perm = "READ_ACP"; break; case S3PermissionWriteACP: perm = "WRITE_ACP"; break; default: perm = "FULL_CONTROL"; break; } fprintf(outfile, "%-6s %-90s %-12s\n", type, id, perm); } } else { printf("Service logging is not enabled for this bucket.\n"); } } else { printError(); } fclose(outfile); S3_deinitialize(); } // set logging ---------------------------------------------------------------- void set_logging(int argc, char **argv, int optindex) { if (optindex == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket\n"); usageExit(stderr); } const char *bucketName = argv[optindex++]; const char *targetBucket = 0, *targetPrefix = 0, *filename = 0; while (optindex < argc) { char *param = argv[optindex++]; if (!strncmp(param, TARGET_BUCKET_PREFIX, TARGET_BUCKET_PREFIX_LEN)) { targetBucket = &(param[TARGET_BUCKET_PREFIX_LEN]); } else if (!strncmp(param, TARGET_PREFIX_PREFIX, TARGET_PREFIX_PREFIX_LEN)) { targetPrefix = &(param[TARGET_PREFIX_PREFIX_LEN]); } else if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) { filename = &(param[FILENAME_PREFIX_LEN]); } else { fprintf(stderr, "\nERROR: Unknown param: %s\n", param); usageExit(stderr); } } int aclGrantCount = 0; S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT]; if (targetBucket) { FILE *infile; if (filename) { if (!(infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) { fprintf(stderr, "\nERROR: Failed to open input file %s: ", filename); perror(0); exit(-1); } } else { infile = stdin; } // Read in the complete ACL char aclBuf[65536]; aclBuf[fread(aclBuf, 1, sizeof(aclBuf), infile)] = 0; char ownerId[S3_MAX_GRANTEE_USER_ID_SIZE]; char ownerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE]; // Parse it if (!convert_simple_acl(aclBuf, ownerId, ownerDisplayName, &aclGrantCount, aclGrants)) { fprintf(stderr, "\nERROR: Failed to parse ACLs\n"); fclose(infile); exit(-1); } fclose(infile); } S3_init(); S3BucketContext bucketContext = { 0, bucketName, protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG }; S3ResponseHandler responseHandler = { &responsePropertiesCallback, &responseCompleteCallback }; do { S3_set_server_access_logging(&bucketContext, targetBucket, targetPrefix, aclGrantCount, aclGrants, 0, &responseHandler, 0); } while (S3_status_is_retryable(statusG) && should_retry()); if (statusG != S3StatusOK) { printError(); } S3_deinitialize(); } // main ---------------------------------------------------------------------- int main(int argc, char **argv) { // Parse args while (1) { int idx = 0; int c = getopt_long(argc, argv, "fhusr:", longOptionsG, &idx); if (c == -1) { // End of options break; } switch (c) { case 'f': forceG = 1; break; case 'h': uriStyleG = S3UriStyleVirtualHost; break; case 'u': protocolG = S3ProtocolHTTP; break; case 's': showResponsePropertiesG = 1; break; case 'r': { const char *v = optarg; retriesG = 0; while (*v) { retriesG *= 10; retriesG += *v - '0'; v++; } break; } default: fprintf(stderr, "\nERROR: Unknown option: -%c\n", c); // Usage exit usageExit(stderr); } } // The first non-option argument gives the operation to perform if (optind == argc) { fprintf(stderr, "\n\nERROR: Missing argument: command\n\n"); usageExit(stderr); } const char *command = argv[optind++]; if (!strcmp(command, "help")) { fprintf(stdout, "\ns3 is a program for performing single requests " "to Amazon S3.\n"); usageExit(stdout); } accessKeyIdG = getenv("S3_ACCESS_KEY_ID"); if (!accessKeyIdG) { fprintf(stderr, "Missing environment variable: S3_ACCESS_KEY_ID\n"); return -1; } secretAccessKeyG = getenv("S3_SECRET_ACCESS_KEY"); if (!secretAccessKeyG) { fprintf(stderr, "Missing environment variable: S3_SECRET_ACCESS_KEY\n"); return -1; } if (!strcmp(command, "list")) { list(argc, argv, optind); } else if (!strcmp(command, "test")) { test_bucket(argc, argv, optind); } else if (!strcmp(command, "create")) { create_bucket(argc, argv, optind); } else if (!strcmp(command, "delete")) { if (optind == argc) { fprintf(stderr, "\nERROR: Missing parameter: bucket or bucket/key\n"); usageExit(stderr); } char *val = argv[optind]; int hasSlash = 0; while (*val) { if (*val++ == '/') { hasSlash = 1; break; } } if (hasSlash) { delete_object(argc, argv, optind); } else { delete_bucket(argc, argv, optind); } } else if (!strcmp(command, "put")) { put_object(argc, argv, optind); } else if (!strcmp(command, "copy")) { copy_object(argc, argv, optind); } else if (!strcmp(command, "get")) { get_object(argc, argv, optind); } else if (!strcmp(command, "head")) { head_object(argc, argv, optind); } else if (!strcmp(command, "gqs")) { generate_query_string(argc, argv, optind); } else if (!strcmp(command, "getacl")) { get_acl(argc, argv, optind); } else if (!strcmp(command, "setacl")) { set_acl(argc, argv, optind); } else if (!strcmp(command, "getlogging")) { get_logging(argc, argv, optind); } else if (!strcmp(command, "setlogging")) { set_logging(argc, argv, optind); } else { fprintf(stderr, "Unknown command: %s\n", command); return -1; } return 0; } ceph-0.80.11/src/libs3/src/request.c0000664000175100017510000014162512623076753021134 0ustar jenkins-buildjenkins-build/** ************************************************************************** * request.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include #include #include #include "request.h" #include "request_context.h" #include "response_headers_handler.h" #include "util.h" #define USER_AGENT_SIZE 256 #define REQUEST_STACK_SIZE 32 static char userAgentG[USER_AGENT_SIZE]; static pthread_mutex_t requestStackMutexG; static Request *requestStackG[REQUEST_STACK_SIZE]; static int requestStackCountG; char defaultHostNameG[S3_MAX_HOSTNAME_SIZE]; typedef struct RequestComputedValues { // All x-amz- headers, in normalized form (i.e. NAME: VALUE, no other ws) char *amzHeaders[S3_MAX_METADATA_COUNT + 2]; // + 2 for acl and date // The number of x-amz- headers int amzHeadersCount; // Storage for amzHeaders (the +256 is for x-amz-acl and x-amz-date) char amzHeadersRaw[COMPACTED_METADATA_BUFFER_SIZE + 256 + 1]; // Canonicalized x-amz- headers string_multibuffer(canonicalizedAmzHeaders, COMPACTED_METADATA_BUFFER_SIZE + 256 + 1); // URL-Encoded key char urlEncodedKey[MAX_URLENCODED_KEY_SIZE + 1]; // Canonicalized resource char canonicalizedResource[MAX_CANONICALIZED_RESOURCE_SIZE + 1]; // Cache-Control header (or empty) char cacheControlHeader[128]; // Content-Type header (or empty) char contentTypeHeader[128]; // Content-MD5 header (or empty) char md5Header[128]; // Content-Disposition header (or empty) char contentDispositionHeader[128]; // Content-Encoding header (or empty) char contentEncodingHeader[128]; // Expires header (or empty) char expiresHeader[128]; // If-Modified-Since header char ifModifiedSinceHeader[128]; // If-Unmodified-Since header char ifUnmodifiedSinceHeader[128]; // If-Match header char ifMatchHeader[128]; // If-None-Match header char ifNoneMatchHeader[128]; // Range header char rangeHeader[128]; // Authorization header char authorizationHeader[128]; } RequestComputedValues; // Called whenever we detect that the request headers have been completely // processed; which happens either when we get our first read/write callback, // or the request is finished being procesed. Returns nonzero on success, // zero on failure. static void request_headers_done(Request *request) { if (request->propertiesCallbackMade) { return; } request->propertiesCallbackMade = 1; // Get the http response code long httpResponseCode; request->httpResponseCode = 0; if (curl_easy_getinfo(request->curl, CURLINFO_RESPONSE_CODE, &httpResponseCode) != CURLE_OK) { // Not able to get the HTTP response code - error request->status = S3StatusInternalError; return; } else { request->httpResponseCode = httpResponseCode; } response_headers_handler_done(&(request->responseHeadersHandler), request->curl); // Only make the callback if it was a successful request; otherwise we're // returning information about the error response itself if (request->propertiesCallback && (request->httpResponseCode >= 200) && (request->httpResponseCode <= 299)) { request->status = (*(request->propertiesCallback)) (&(request->responseHeadersHandler.responseProperties), request->callbackData); } } static size_t curl_header_func(void *ptr, size_t size, size_t nmemb, void *data) { Request *request = (Request *) data; int len = size * nmemb; response_headers_handler_add (&(request->responseHeadersHandler), (char *) ptr, len); return len; } static size_t curl_read_func(void *ptr, size_t size, size_t nmemb, void *data) { Request *request = (Request *) data; int len = size * nmemb; request_headers_done(request); if (request->status != S3StatusOK) { return CURL_READFUNC_ABORT; } // If there is no data callback, or the data callback has already returned // contentLength bytes, return 0; if (!request->toS3Callback || !request->toS3CallbackBytesRemaining) { return 0; } // Don't tell the callback that we are willing to accept more data than we // really are if (len > request->toS3CallbackBytesRemaining) { len = request->toS3CallbackBytesRemaining; } // Otherwise, make the data callback int ret = (*(request->toS3Callback)) (len, (char *) ptr, request->callbackData); if (ret < 0) { request->status = S3StatusAbortedByCallback; return CURL_READFUNC_ABORT; } else { if (ret > request->toS3CallbackBytesRemaining) { ret = request->toS3CallbackBytesRemaining; } request->toS3CallbackBytesRemaining -= ret; return ret; } } static size_t curl_write_func(void *ptr, size_t size, size_t nmemb, void *data) { Request *request = (Request *) data; int len = size * nmemb; request_headers_done(request); if (request->status != S3StatusOK) { return 0; } // On HTTP error, we expect to parse an HTTP error response if ((request->httpResponseCode < 200) || (request->httpResponseCode > 299)) { request->status = error_parser_add (&(request->errorParser), (char *) ptr, len); } // If there was a callback registered, make it else if (request->fromS3Callback) { request->status = (*(request->fromS3Callback)) (len, (char *) ptr, request->callbackData); } // Else, consider this an error - S3 has sent back data when it was not // expected else { request->status = S3StatusInternalError; } return ((request->status == S3StatusOK) ? len : 0); } // This function 'normalizes' all x-amz-meta headers provided in // params->requestHeaders, which means it removes all whitespace from // them such that they all look exactly like this: // x-amz-meta-${NAME}: ${VALUE} // It also adds the x-amz-acl, x-amz-copy-source, and x-amz-metadata-directive // headers if necessary, and always adds the x-amz-date header. It copies the // raw string values into params->amzHeadersRaw, and creates an array of // string pointers representing these headers in params->amzHeaders (and also // sets params->amzHeadersCount to be the count of the total number of x-amz- // headers thus created). static S3Status compose_amz_headers(const RequestParams *params, RequestComputedValues *values) { const S3PutProperties *properties = params->putProperties; values->amzHeadersCount = 0; values->amzHeadersRaw[0] = 0; int len = 0; // Append a header to amzHeaders, trimming whitespace from the end. // Does NOT trim whitespace from the beginning. #define headers_append(isNewHeader, format, ...) \ do { \ if (isNewHeader) { \ values->amzHeaders[values->amzHeadersCount++] = \ &(values->amzHeadersRaw[len]); \ } \ len += snprintf(&(values->amzHeadersRaw[len]), \ sizeof(values->amzHeadersRaw) - len, \ format, __VA_ARGS__); \ if (len >= (int) sizeof(values->amzHeadersRaw)) { \ return S3StatusMetaDataHeadersTooLong; \ } \ while ((len > 0) && (values->amzHeadersRaw[len - 1] == ' ')) { \ len--; \ } \ values->amzHeadersRaw[len++] = 0; \ } while (0) #define header_name_tolower_copy(str, l) \ do { \ values->amzHeaders[values->amzHeadersCount++] = \ &(values->amzHeadersRaw[len]); \ if ((len + l) >= (int) sizeof(values->amzHeadersRaw)) { \ return S3StatusMetaDataHeadersTooLong; \ } \ int todo = l; \ while (todo--) { \ if ((*(str) >= 'A') && (*(str) <= 'Z')) { \ values->amzHeadersRaw[len++] = 'a' + (*(str) - 'A'); \ } \ else { \ values->amzHeadersRaw[len++] = *(str); \ } \ (str)++; \ } \ } while (0) // Check and copy in the x-amz-meta headers if (properties) { int i; for (i = 0; i < properties->metaDataCount; i++) { const S3NameValue *property = &(properties->metaData[i]); char headerName[S3_MAX_METADATA_SIZE - sizeof(": v")]; int l = snprintf(headerName, sizeof(headerName), S3_METADATA_HEADER_NAME_PREFIX "%s", property->name); char *hn = headerName; header_name_tolower_copy(hn, l); // Copy in the value headers_append(0, ": %s", property->value); } // Add the x-amz-acl header, if necessary const char *cannedAclString; switch (params->putProperties->cannedAcl) { case S3CannedAclPrivate: cannedAclString = 0; break; case S3CannedAclPublicRead: cannedAclString = "public-read"; break; case S3CannedAclPublicReadWrite: cannedAclString = "public-read-write"; break; default: // S3CannedAclAuthenticatedRead cannedAclString = "authenticated-read"; break; } if (cannedAclString) { headers_append(1, "x-amz-acl: %s", cannedAclString); } } // Add the x-amz-date header time_t now = time(NULL); char date[64]; strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); headers_append(1, "x-amz-date: %s", date); if (params->httpRequestType == HttpRequestTypeCOPY) { // Add the x-amz-copy-source header if (params->copySourceBucketName && params->copySourceBucketName[0] && params->copySourceKey && params->copySourceKey[0]) { headers_append(1, "x-amz-copy-source: /%s/%s", params->copySourceBucketName, params->copySourceKey); } // And the x-amz-metadata-directive header if (params->putProperties) { headers_append(1, "%s", "x-amz-metadata-directive: REPLACE"); } } return S3StatusOK; } // Composes the other headers static S3Status compose_standard_headers(const RequestParams *params, RequestComputedValues *values) { #define do_put_header(fmt, sourceField, destField, badError, tooLongError) \ do { \ if (params->putProperties && \ params->putProperties-> sourceField && \ params->putProperties-> sourceField[0]) { \ /* Skip whitespace at beginning of val */ \ const char *val = params->putProperties-> sourceField; \ while (*val && is_blank(*val)) { \ val++; \ } \ if (!*val) { \ return badError; \ } \ /* Compose header, make sure it all fit */ \ int len = snprintf(values-> destField, \ sizeof(values-> destField), fmt, val); \ if (len >= (int) sizeof(values-> destField)) { \ return tooLongError; \ } \ /* Now remove the whitespace at the end */ \ while (is_blank(values-> destField[len])) { \ len--; \ } \ values-> destField[len] = 0; \ } \ else { \ values-> destField[0] = 0; \ } \ } while (0) #define do_get_header(fmt, sourceField, destField, badError, tooLongError) \ do { \ if (params->getConditions && \ params->getConditions-> sourceField && \ params->getConditions-> sourceField[0]) { \ /* Skip whitespace at beginning of val */ \ const char *val = params->getConditions-> sourceField; \ while (*val && is_blank(*val)) { \ val++; \ } \ if (!*val) { \ return badError; \ } \ /* Compose header, make sure it all fit */ \ int len = snprintf(values-> destField, \ sizeof(values-> destField), fmt, val); \ if (len >= (int) sizeof(values-> destField)) { \ return tooLongError; \ } \ /* Now remove the whitespace at the end */ \ while (is_blank(values-> destField[len])) { \ len--; \ } \ values-> destField[len] = 0; \ } \ else { \ values-> destField[0] = 0; \ } \ } while (0) // Cache-Control do_put_header("Cache-Control: %s", cacheControl, cacheControlHeader, S3StatusBadCacheControl, S3StatusCacheControlTooLong); // ContentType do_put_header("Content-Type: %s", contentType, contentTypeHeader, S3StatusBadContentType, S3StatusContentTypeTooLong); // MD5 do_put_header("Content-MD5: %s", md5, md5Header, S3StatusBadMD5, S3StatusMD5TooLong); // Content-Disposition do_put_header("Content-Disposition: attachment; filename=\"%s\"", contentDispositionFilename, contentDispositionHeader, S3StatusBadContentDispositionFilename, S3StatusContentDispositionFilenameTooLong); // ContentEncoding do_put_header("Content-Encoding: %s", contentEncoding, contentEncodingHeader, S3StatusBadContentEncoding, S3StatusContentEncodingTooLong); // Expires if (params->putProperties && (params->putProperties->expires >= 0)) { time_t t = (time_t) params->putProperties->expires; strftime(values->expiresHeader, sizeof(values->expiresHeader), "Expires: %a, %d %b %Y %H:%M:%S UTC", gmtime(&t)); } else { values->expiresHeader[0] = 0; } // If-Modified-Since if (params->getConditions && (params->getConditions->ifModifiedSince >= 0)) { time_t t = (time_t) params->getConditions->ifModifiedSince; strftime(values->ifModifiedSinceHeader, sizeof(values->ifModifiedSinceHeader), "If-Modified-Since: %a, %d %b %Y %H:%M:%S UTC", gmtime(&t)); } else { values->ifModifiedSinceHeader[0] = 0; } // If-Unmodified-Since header if (params->getConditions && (params->getConditions->ifNotModifiedSince >= 0)) { time_t t = (time_t) params->getConditions->ifNotModifiedSince; strftime(values->ifUnmodifiedSinceHeader, sizeof(values->ifUnmodifiedSinceHeader), "If-Unmodified-Since: %a, %d %b %Y %H:%M:%S UTC", gmtime(&t)); } else { values->ifUnmodifiedSinceHeader[0] = 0; } // If-Match header do_get_header("If-Match: %s", ifMatchETag, ifMatchHeader, S3StatusBadIfMatchETag, S3StatusIfMatchETagTooLong); // If-None-Match header do_get_header("If-None-Match: %s", ifNotMatchETag, ifNoneMatchHeader, S3StatusBadIfNotMatchETag, S3StatusIfNotMatchETagTooLong); // Range header if (params->startByte || params->byteCount) { if (params->byteCount) { snprintf(values->rangeHeader, sizeof(values->rangeHeader), "Range: bytes=%llu-%llu", (unsigned long long) params->startByte, (unsigned long long) (params->startByte + params->byteCount - 1)); } else { snprintf(values->rangeHeader, sizeof(values->rangeHeader), "Range: bytes=%llu-", (unsigned long long) params->startByte); } } else { values->rangeHeader[0] = 0; } return S3StatusOK; } // URL encodes the params->key value into params->urlEncodedKey static S3Status encode_key(const RequestParams *params, RequestComputedValues *values) { return (urlEncode(values->urlEncodedKey, params->key, S3_MAX_KEY_SIZE) ? S3StatusOK : S3StatusUriTooLong); } // Simple comparison function for comparing two HTTP header names that are // embedded within an HTTP header line, returning true if header1 comes // before header2 alphabetically, false if not static int headerle(const char *header1, const char *header2) { while (1) { if (*header1 == ':') { return (*header2 != ':'); } else if (*header2 == ':') { return 0; } else if (*header2 < *header1) { return 0; } else if (*header2 > *header1) { return 1; } header1++, header2++; } } // Replace this with merge sort eventually, it's the best stable sort. But // since typically the number of elements being sorted is small, it doesn't // matter that much which sort is used, and gnome sort is the world's simplest // stable sort. Added a slight twist to the standard gnome_sort - don't go // forward +1, go forward to the last highest index considered. This saves // all the string comparisons that would be done "going forward", and thus // only does the necessary string comparisons to move values back into their // sorted position. static void header_gnome_sort(const char **headers, int size) { int i = 0, last_highest = 0; while (i < size) { if ((i == 0) || headerle(headers[i - 1], headers[i])) { i = ++last_highest; } else { const char *tmp = headers[i]; headers[i] = headers[i - 1]; headers[--i] = tmp; } } } // Canonicalizes the x-amz- headers into the canonicalizedAmzHeaders buffer static void canonicalize_amz_headers(RequestComputedValues *values) { // Make a copy of the headers that will be sorted const char *sortedHeaders[S3_MAX_METADATA_COUNT]; memcpy(sortedHeaders, values->amzHeaders, (values->amzHeadersCount * sizeof(sortedHeaders[0]))); // Now sort these header_gnome_sort(sortedHeaders, values->amzHeadersCount); // Now copy this sorted list into the buffer, all the while: // - folding repeated headers into single lines, and // - folding multiple lines // - removing the space after the colon int lastHeaderLen = 0, i; char *buffer = values->canonicalizedAmzHeaders; for (i = 0; i < values->amzHeadersCount; i++) { const char *header = sortedHeaders[i]; const char *c = header; // If the header names are the same, append the next value if ((i > 0) && !strncmp(header, sortedHeaders[i - 1], lastHeaderLen)) { // Replacing the previous newline with a comma *(buffer - 1) = ','; // Skip the header name and space c += (lastHeaderLen + 1); } // Else this is a new header else { // Copy in everything up to the space in the ": " while (*c != ' ') { *buffer++ = *c++; } // Save the header len since it's a new header lastHeaderLen = c - header; // Skip the space c++; } // Now copy in the value, folding the lines while (*c) { // If c points to a \r\n[whitespace] sequence, then fold // this newline out if ((*c == '\r') && (*(c + 1) == '\n') && is_blank(*(c + 2))) { c += 3; while (is_blank(*c)) { c++; } // Also, what has most recently been copied into buffer amy // have been whitespace, and since we're folding whitespace // out around this newline sequence, back buffer up over // any whitespace it contains while (is_blank(*(buffer - 1))) { buffer--; } continue; } *buffer++ = *c++; } // Finally, add the newline *buffer++ = '\n'; } // Terminate the buffer *buffer = 0; } // Canonicalizes the resource into params->canonicalizedResource static void canonicalize_resource(const char *bucketName, const char *subResource, const char *urlEncodedKey, char *buffer) { int len = 0; *buffer = 0; #define append(str) len += sprintf(&(buffer[len]), "%s", str) if (bucketName && bucketName[0]) { buffer[len++] = '/'; append(bucketName); } append("/"); if (urlEncodedKey && urlEncodedKey[0]) { append(urlEncodedKey); } if (subResource && subResource[0]) { append("?"); append(subResource); } } // Convert an HttpRequestType to an HTTP Verb string static const char *http_request_type_to_verb(HttpRequestType requestType) { switch (requestType) { case HttpRequestTypeGET: return "GET"; case HttpRequestTypeHEAD: return "HEAD"; case HttpRequestTypePUT: case HttpRequestTypeCOPY: return "PUT"; default: // HttpRequestTypeDELETE return "DELETE"; } } // Composes the Authorization header for the request static S3Status compose_auth_header(const RequestParams *params, RequestComputedValues *values) { // We allow for: // 17 bytes for HTTP-Verb + \n // 129 bytes for Content-MD5 + \n // 129 bytes for Content-Type + \n // 1 byte for empty Date + \n // CanonicalizedAmzHeaders & CanonicalizedResource char signbuf[17 + 129 + 129 + 1 + (sizeof(values->canonicalizedAmzHeaders) - 1) + (sizeof(values->canonicalizedResource) - 1) + 1]; int len = 0; #define signbuf_append(format, ...) \ len += snprintf(&(signbuf[len]), sizeof(signbuf) - len, \ format, __VA_ARGS__) signbuf_append ("%s\n", http_request_type_to_verb(params->httpRequestType)); // For MD5 and Content-Type, use the value in the actual header, because // it's already been trimmed signbuf_append("%s\n", values->md5Header[0] ? &(values->md5Header[sizeof("Content-MD5: ") - 1]) : ""); signbuf_append ("%s\n", values->contentTypeHeader[0] ? &(values->contentTypeHeader[sizeof("Content-Type: ") - 1]) : ""); signbuf_append("%s", "\n"); // Date - we always use x-amz-date signbuf_append("%s", values->canonicalizedAmzHeaders); signbuf_append("%s", values->canonicalizedResource); // Generate an HMAC-SHA-1 of the signbuf unsigned char hmac[20]; HMAC_SHA1(hmac, (unsigned char *) params->bucketContext.secretAccessKey, strlen(params->bucketContext.secretAccessKey), (unsigned char *) signbuf, len); // Now base-64 encode the results char b64[((20 + 1) * 4) / 3]; int b64Len = base64Encode(hmac, 20, b64); snprintf(values->authorizationHeader, sizeof(values->authorizationHeader), "Authorization: AWS %s:%.*s", params->bucketContext.accessKeyId, b64Len, b64); return S3StatusOK; } // Compose the URI to use for the request given the request parameters static S3Status compose_uri(char *buffer, int bufferSize, const S3BucketContext *bucketContext, const char *urlEncodedKey, const char *subResource, const char *queryParams) { int len = 0; #define uri_append(fmt, ...) \ do { \ len += snprintf(&(buffer[len]), bufferSize - len, fmt, __VA_ARGS__); \ if (len >= bufferSize) { \ return S3StatusUriTooLong; \ } \ } while (0) uri_append("http%s://", (bucketContext->protocol == S3ProtocolHTTP) ? "" : "s"); const char *hostName = bucketContext->hostName ? bucketContext->hostName : defaultHostNameG; if (bucketContext->bucketName && bucketContext->bucketName[0]) { if (bucketContext->uriStyle == S3UriStyleVirtualHost) { uri_append("%s.%s", bucketContext->bucketName, hostName); } else { uri_append("%s/%s", hostName, bucketContext->bucketName); } } else { uri_append("%s", hostName); } uri_append("%s", "/"); uri_append("%s", urlEncodedKey); if (subResource && subResource[0]) { uri_append("?%s", subResource); } if (queryParams) { uri_append("%s%s", (subResource && subResource[0]) ? "&" : "?", queryParams); } return S3StatusOK; } // Sets up the curl handle given the completely computed RequestParams static S3Status setup_curl(Request *request, const RequestParams *params, const RequestComputedValues *values) { CURLcode status; #define curl_easy_setopt_safe(opt, val) \ if ((status = curl_easy_setopt \ (request->curl, opt, val)) != CURLE_OK) { \ return S3StatusFailedToInitializeRequest; \ } // Debugging only // curl_easy_setopt_safe(CURLOPT_VERBOSE, 1); // Set private data to request for the benefit of S3RequestContext curl_easy_setopt_safe(CURLOPT_PRIVATE, request); // Set header callback and data curl_easy_setopt_safe(CURLOPT_HEADERDATA, request); curl_easy_setopt_safe(CURLOPT_HEADERFUNCTION, &curl_header_func); // Set read callback, data, and readSize curl_easy_setopt_safe(CURLOPT_READFUNCTION, &curl_read_func); curl_easy_setopt_safe(CURLOPT_READDATA, request); // Set write callback and data curl_easy_setopt_safe(CURLOPT_WRITEFUNCTION, &curl_write_func); curl_easy_setopt_safe(CURLOPT_WRITEDATA, request); // Ask curl to parse the Last-Modified header. This is easier than // parsing it ourselves. curl_easy_setopt_safe(CURLOPT_FILETIME, 1); // Curl docs suggest that this is necessary for multithreaded code. // However, it also points out that DNS timeouts will not be honored // during DNS lookup, which can be worked around by using the c-ares // library, which we do not do yet. curl_easy_setopt_safe(CURLOPT_NOSIGNAL, 1); // Turn off Curl's built-in progress meter curl_easy_setopt_safe(CURLOPT_NOPROGRESS, 1); // xxx todo - support setting the proxy for Curl to use (can't use https // for proxies though) // xxx todo - support setting the network interface for Curl to use // I think this is useful - we don't need interactive performance, we need // to complete large operations quickly curl_easy_setopt_safe(CURLOPT_TCP_NODELAY, 1); // Don't use Curl's 'netrc' feature curl_easy_setopt_safe(CURLOPT_NETRC, CURL_NETRC_IGNORED); // Don't verify S3's certificate, there are known to be issues with // them sometimes // xxx todo - support an option for verifying the S3 CA (default false) curl_easy_setopt_safe(CURLOPT_SSL_VERIFYPEER, 0); // Follow any redirection directives that S3 sends curl_easy_setopt_safe(CURLOPT_FOLLOWLOCATION, 1); // A safety valve in case S3 goes bananas with redirects curl_easy_setopt_safe(CURLOPT_MAXREDIRS, 10); // Set the User-Agent; maybe Amazon will track these? curl_easy_setopt_safe(CURLOPT_USERAGENT, userAgentG); // Set the low speed limit and time; we abort transfers that stay at // less than 1K per second for more than 15 seconds. // xxx todo - make these configurable // xxx todo - allow configurable max send and receive speed curl_easy_setopt_safe(CURLOPT_LOW_SPEED_LIMIT, 1024); curl_easy_setopt_safe(CURLOPT_LOW_SPEED_TIME, 15); // Append standard headers #define append_standard_header(fieldName) \ if (values-> fieldName [0]) { \ request->headers = curl_slist_append(request->headers, \ values-> fieldName); \ } // Would use CURLOPT_INFILESIZE_LARGE, but it is buggy in libcurl if (params->httpRequestType == HttpRequestTypePUT) { char header[256]; snprintf(header, sizeof(header), "Content-Length: %llu", (unsigned long long) params->toS3CallbackTotalSize); request->headers = curl_slist_append(request->headers, header); request->headers = curl_slist_append(request->headers, "Transfer-Encoding:"); } else if (params->httpRequestType == HttpRequestTypeCOPY) { request->headers = curl_slist_append(request->headers, "Transfer-Encoding:"); } append_standard_header(cacheControlHeader); append_standard_header(contentTypeHeader); append_standard_header(md5Header); append_standard_header(contentDispositionHeader); append_standard_header(contentEncodingHeader); append_standard_header(expiresHeader); append_standard_header(ifModifiedSinceHeader); append_standard_header(ifUnmodifiedSinceHeader); append_standard_header(ifMatchHeader); append_standard_header(ifNoneMatchHeader); append_standard_header(rangeHeader); append_standard_header(authorizationHeader); // Append x-amz- headers int i; for (i = 0; i < values->amzHeadersCount; i++) { request->headers = curl_slist_append(request->headers, values->amzHeaders[i]); } // Set the HTTP headers curl_easy_setopt_safe(CURLOPT_HTTPHEADER, request->headers); // Set URI curl_easy_setopt_safe(CURLOPT_URL, request->uri); // Set request type. switch (params->httpRequestType) { case HttpRequestTypeHEAD: curl_easy_setopt_safe(CURLOPT_NOBODY, 1); break; case HttpRequestTypePUT: case HttpRequestTypeCOPY: curl_easy_setopt_safe(CURLOPT_UPLOAD, 1); break; case HttpRequestTypeDELETE: curl_easy_setopt_safe(CURLOPT_CUSTOMREQUEST, "DELETE"); break; default: // HttpRequestTypeGET break; } return S3StatusOK; } static void request_deinitialize(Request *request) { if (request->headers) { curl_slist_free_all(request->headers); } error_parser_deinitialize(&(request->errorParser)); // curl_easy_reset prevents connections from being re-used for some // reason. This makes HTTP Keep-Alive meaningless and is very bad for // performance. But it is necessary to allow curl to work properly. // xxx todo figure out why curl_easy_reset(request->curl); } static S3Status request_get(const RequestParams *params, const RequestComputedValues *values, Request **reqReturn) { Request *request = 0; // Try to get one from the request stack. We hold the lock for the // shortest time possible here. pthread_mutex_lock(&requestStackMutexG); if (requestStackCountG) { request = requestStackG[--requestStackCountG]; } pthread_mutex_unlock(&requestStackMutexG); // If we got one, deinitialize it for re-use if (request) { request_deinitialize(request); } // Else there wasn't one available in the request stack, so create one else { if (!(request = (Request *) malloc(sizeof(Request)))) { return S3StatusOutOfMemory; } if (!(request->curl = curl_easy_init())) { free(request); return S3StatusFailedToInitializeRequest; } } // Initialize the request request->prev = 0; request->next = 0; // Request status is initialized to no error, will be updated whenever // an error occurs request->status = S3StatusOK; S3Status status; // Start out with no headers request->headers = 0; // Compute the URL if ((status = compose_uri (request->uri, sizeof(request->uri), &(params->bucketContext), values->urlEncodedKey, params->subResource, params->queryParams)) != S3StatusOK) { curl_easy_cleanup(request->curl); free(request); return status; } // Set all of the curl handle options if ((status = setup_curl(request, params, values)) != S3StatusOK) { curl_easy_cleanup(request->curl); free(request); return status; } request->propertiesCallback = params->propertiesCallback; request->toS3Callback = params->toS3Callback; request->toS3CallbackBytesRemaining = params->toS3CallbackTotalSize; request->fromS3Callback = params->fromS3Callback; request->completeCallback = params->completeCallback; request->callbackData = params->callbackData; response_headers_handler_initialize(&(request->responseHeadersHandler)); request->propertiesCallbackMade = 0; error_parser_initialize(&(request->errorParser)); *reqReturn = request; return S3StatusOK; } static void request_destroy(Request *request) { request_deinitialize(request); curl_easy_cleanup(request->curl); free(request); } static void request_release(Request *request) { pthread_mutex_lock(&requestStackMutexG); // If the request stack is full, destroy this one if (requestStackCountG == REQUEST_STACK_SIZE) { pthread_mutex_unlock(&requestStackMutexG); request_destroy(request); } // Else put this one at the front of the request stack; we do this because // we want the most-recently-used curl handle to be re-used on the next // request, to maximize our chances of re-using a TCP connection before it // times out else { requestStackG[requestStackCountG++] = request; pthread_mutex_unlock(&requestStackMutexG); } } S3Status request_api_initialize(const char *userAgentInfo, int flags, const char *defaultHostName) { if (curl_global_init(CURL_GLOBAL_ALL & ~((flags & S3_INIT_WINSOCK) ? 0 : CURL_GLOBAL_WIN32)) != CURLE_OK) { return S3StatusInternalError; } if (!defaultHostName) { defaultHostName = S3_DEFAULT_HOSTNAME; } if (snprintf(defaultHostNameG, S3_MAX_HOSTNAME_SIZE, "%s", defaultHostName) >= S3_MAX_HOSTNAME_SIZE) { return S3StatusUriTooLong; } pthread_mutex_init(&requestStackMutexG, 0); requestStackCountG = 0; if (!userAgentInfo || !*userAgentInfo) { userAgentInfo = "Unknown"; } char platform[96]; struct utsname utsn; if (uname(&utsn)) { strncpy(platform, "Unknown", sizeof(platform)); // Because strncpy doesn't always zero terminate platform[sizeof(platform) - 1] = 0; } else { snprintf(platform, sizeof(platform), "%s%s%s", utsn.sysname, utsn.machine[0] ? " " : "", utsn.machine); } snprintf(userAgentG, sizeof(userAgentG), "Mozilla/4.0 (Compatible; %s; libs3 %s.%s; %s)", userAgentInfo, LIBS3_VER_MAJOR, LIBS3_VER_MINOR, platform); return S3StatusOK; } void request_api_deinitialize() { pthread_mutex_destroy(&requestStackMutexG); while (requestStackCountG--) { request_destroy(requestStackG[requestStackCountG]); } } void request_perform(const RequestParams *params, S3RequestContext *context) { Request *request; S3Status status; #define return_status(status) \ (*(params->completeCallback))(status, 0, params->callbackData); \ return // These will hold the computed values RequestComputedValues computed; // Validate the bucket name if (params->bucketContext.bucketName && ((status = S3_validate_bucket_name (params->bucketContext.bucketName, params->bucketContext.uriStyle)) != S3StatusOK)) { return_status(status); } // Compose the amz headers if ((status = compose_amz_headers(params, &computed)) != S3StatusOK) { return_status(status); } // Compose standard headers if ((status = compose_standard_headers (params, &computed)) != S3StatusOK) { return_status(status); } // URL encode the key if ((status = encode_key(params, &computed)) != S3StatusOK) { return_status(status); } // Compute the canonicalized amz headers canonicalize_amz_headers(&computed); // Compute the canonicalized resource canonicalize_resource(params->bucketContext.bucketName, params->subResource, computed.urlEncodedKey, computed.canonicalizedResource); // Compose Authorization header if ((status = compose_auth_header(params, &computed)) != S3StatusOK) { return_status(status); } // Get an initialized Request structure now if ((status = request_get(params, &computed, &request)) != S3StatusOK) { return_status(status); } // If a RequestContext was provided, add the request to the curl multi if (context) { CURLMcode code = curl_multi_add_handle(context->curlm, request->curl); if (code == CURLM_OK) { if (context->requests) { request->prev = context->requests->prev; request->next = context->requests; context->requests->prev->next = request; context->requests->prev = request; } else { context->requests = request->next = request->prev = request; } } else { if (request->status == S3StatusOK) { request->status = (code == CURLM_OUT_OF_MEMORY) ? S3StatusOutOfMemory : S3StatusInternalError; } request_finish(request); } } // Else, perform the request immediately else { CURLcode code = curl_easy_perform(request->curl); if ((code != CURLE_OK) && (request->status == S3StatusOK)) { request->status = request_curl_code_to_status(code); } // Finish the request, ensuring that all callbacks have been made, and // also releases the request request_finish(request); } } void request_finish(Request *request) { // If we haven't detected this already, we now know that the headers are // definitely done being read in request_headers_done(request); // If there was no error processing the request, then possibly there was // an S3 error parsed, which should be converted into the request status if (request->status == S3StatusOK) { error_parser_convert_status(&(request->errorParser), &(request->status)); // If there still was no error recorded, then it is possible that // there was in fact an error but that there was no error XML // detailing the error if ((request->status == S3StatusOK) && ((request->httpResponseCode < 200) || (request->httpResponseCode > 299))) { switch (request->httpResponseCode) { case 0: // This happens if the request never got any HTTP response // headers at all, we call this a ConnectionFailed error request->status = S3StatusConnectionFailed; break; case 100: // Some versions of libcurl erroneously set HTTP // status to this break; case 301: request->status = S3StatusErrorPermanentRedirect; break; case 307: request->status = S3StatusHttpErrorMovedTemporarily; break; case 400: request->status = S3StatusHttpErrorBadRequest; break; case 403: request->status = S3StatusHttpErrorForbidden; break; case 404: request->status = S3StatusHttpErrorNotFound; break; case 405: request->status = S3StatusErrorMethodNotAllowed; break; case 409: request->status = S3StatusHttpErrorConflict; break; case 411: request->status = S3StatusErrorMissingContentLength; break; case 412: request->status = S3StatusErrorPreconditionFailed; break; case 416: request->status = S3StatusErrorInvalidRange; break; case 500: request->status = S3StatusErrorInternalError; break; case 501: request->status = S3StatusErrorNotImplemented; break; case 503: request->status = S3StatusErrorSlowDown; break; default: request->status = S3StatusHttpErrorUnknown; break; } } } (*(request->completeCallback)) (request->status, &(request->errorParser.s3ErrorDetails), request->callbackData); request_release(request); } S3Status request_curl_code_to_status(CURLcode code) { switch (code) { case CURLE_OUT_OF_MEMORY: return S3StatusOutOfMemory; case CURLE_COULDNT_RESOLVE_PROXY: case CURLE_COULDNT_RESOLVE_HOST: return S3StatusNameLookupError; case CURLE_COULDNT_CONNECT: return S3StatusFailedToConnect; case CURLE_WRITE_ERROR: case CURLE_OPERATION_TIMEDOUT: return S3StatusConnectionFailed; case CURLE_PARTIAL_FILE: return S3StatusOK; case CURLE_SSL_CACERT: return S3StatusServerFailedVerification; default: return S3StatusInternalError; } } S3Status S3_generate_authenticated_query_string (char *buffer, const S3BucketContext *bucketContext, const char *key, int64_t expires, const char *resource) { #define MAX_EXPIRES (((int64_t) 1 << 31) - 1) // S3 seems to only accept expiration dates up to the number of seconds // representably by a signed 32-bit integer if (expires < 0) { expires = MAX_EXPIRES; } else if (expires > MAX_EXPIRES) { expires = MAX_EXPIRES; } // xxx todo: rework this so that it can be incorporated into shared code // with request_perform(). It's really unfortunate that this code is not // shared with request_perform(). // URL encode the key char urlEncodedKey[S3_MAX_KEY_SIZE * 3]; if (key) { urlEncode(urlEncodedKey, key, strlen(key)); } else { urlEncodedKey[0] = 0; } // Compute canonicalized resource char canonicalizedResource[MAX_CANONICALIZED_RESOURCE_SIZE]; canonicalize_resource(bucketContext->bucketName, resource, urlEncodedKey, canonicalizedResource); // We allow for: // 17 bytes for HTTP-Verb + \n // 1 byte for empty Content-MD5 + \n // 1 byte for empty Content-Type + \n // 20 bytes for Expires + \n // 0 bytes for CanonicalizedAmzHeaders // CanonicalizedResource char signbuf[17 + 1 + 1 + 1 + 20 + sizeof(canonicalizedResource) + 1]; int len = 0; #define signbuf_append(format, ...) \ len += snprintf(&(signbuf[len]), sizeof(signbuf) - len, \ format, __VA_ARGS__) signbuf_append("%s\n", "GET"); // HTTP-Verb signbuf_append("%s\n", ""); // Content-MD5 signbuf_append("%s\n", ""); // Content-Type signbuf_append("%llu\n", (unsigned long long) expires); signbuf_append("%s", canonicalizedResource); // Generate an HMAC-SHA-1 of the signbuf unsigned char hmac[20]; HMAC_SHA1(hmac, (unsigned char *) bucketContext->secretAccessKey, strlen(bucketContext->secretAccessKey), (unsigned char *) signbuf, len); // Now base-64 encode the results char b64[((20 + 1) * 4) / 3]; int b64Len = base64Encode(hmac, 20, b64); // Now urlEncode that char signature[sizeof(b64) * 3]; urlEncode(signature, b64, b64Len); // Finally, compose the uri, with params: // ?AWSAccessKeyId=xxx[&Expires=]&Signature=xxx char queryParams[sizeof("AWSAccessKeyId=") + 20 + sizeof("&Expires=") + 20 + sizeof("&Signature=") + sizeof(signature) + 1]; sprintf(queryParams, "AWSAccessKeyId=%s&Expires=%ld&Signature=%s", bucketContext->accessKeyId, (long) expires, signature); return compose_uri(buffer, S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE, bucketContext, urlEncodedKey, resource, queryParams); } ceph-0.80.11/src/libs3/src/general.c0000664000175100017510000004134112623076753021053 0ustar jenkins-buildjenkins-build/** ************************************************************************** * general.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "request.h" #include "simplexml.h" #include "util.h" static int initializeCountG = 0; S3Status S3_initialize(const char *userAgentInfo, int flags, const char *defaultS3HostName) { if (initializeCountG++) { return S3StatusOK; } return request_api_initialize(userAgentInfo, flags, defaultS3HostName); } void S3_deinitialize() { if (--initializeCountG) { return; } request_api_deinitialize(); } const char *S3_get_status_name(S3Status status) { switch (status) { #define handlecase(s) \ case S3Status##s: \ return #s handlecase(OK); handlecase(InternalError); handlecase(OutOfMemory); handlecase(Interrupted); handlecase(InvalidBucketNameTooLong); handlecase(InvalidBucketNameFirstCharacter); handlecase(InvalidBucketNameCharacter); handlecase(InvalidBucketNameCharacterSequence); handlecase(InvalidBucketNameTooShort); handlecase(InvalidBucketNameDotQuadNotation); handlecase(QueryParamsTooLong); handlecase(FailedToInitializeRequest); handlecase(MetaDataHeadersTooLong); handlecase(BadMetaData); handlecase(BadContentType); handlecase(ContentTypeTooLong); handlecase(BadMD5); handlecase(MD5TooLong); handlecase(BadCacheControl); handlecase(CacheControlTooLong); handlecase(BadContentDispositionFilename); handlecase(ContentDispositionFilenameTooLong); handlecase(BadContentEncoding); handlecase(ContentEncodingTooLong); handlecase(BadIfMatchETag); handlecase(IfMatchETagTooLong); handlecase(BadIfNotMatchETag); handlecase(IfNotMatchETagTooLong); handlecase(HeadersTooLong); handlecase(KeyTooLong); handlecase(UriTooLong); handlecase(XmlParseFailure); handlecase(EmailAddressTooLong); handlecase(UserIdTooLong); handlecase(UserDisplayNameTooLong); handlecase(GroupUriTooLong); handlecase(PermissionTooLong); handlecase(TargetBucketTooLong); handlecase(TargetPrefixTooLong); handlecase(TooManyGrants); handlecase(BadGrantee); handlecase(BadPermission); handlecase(XmlDocumentTooLarge); handlecase(NameLookupError); handlecase(FailedToConnect); handlecase(ServerFailedVerification); handlecase(ConnectionFailed); handlecase(AbortedByCallback); handlecase(ErrorAccessDenied); handlecase(ErrorAccountProblem); handlecase(ErrorAmbiguousGrantByEmailAddress); handlecase(ErrorBadDigest); handlecase(ErrorBucketAlreadyExists); handlecase(ErrorBucketAlreadyOwnedByYou); handlecase(ErrorBucketNotEmpty); handlecase(ErrorCredentialsNotSupported); handlecase(ErrorCrossLocationLoggingProhibited); handlecase(ErrorEntityTooSmall); handlecase(ErrorEntityTooLarge); handlecase(ErrorExpiredToken); handlecase(ErrorIncompleteBody); handlecase(ErrorIncorrectNumberOfFilesInPostRequest); handlecase(ErrorInlineDataTooLarge); handlecase(ErrorInternalError); handlecase(ErrorInvalidAccessKeyId); handlecase(ErrorInvalidAddressingHeader); handlecase(ErrorInvalidArgument); handlecase(ErrorInvalidBucketName); handlecase(ErrorInvalidDigest); handlecase(ErrorInvalidLocationConstraint); handlecase(ErrorInvalidPayer); handlecase(ErrorInvalidPolicyDocument); handlecase(ErrorInvalidRange); handlecase(ErrorInvalidSecurity); handlecase(ErrorInvalidSOAPRequest); handlecase(ErrorInvalidStorageClass); handlecase(ErrorInvalidTargetBucketForLogging); handlecase(ErrorInvalidToken); handlecase(ErrorInvalidURI); handlecase(ErrorKeyTooLong); handlecase(ErrorMalformedACLError); handlecase(ErrorMalformedXML); handlecase(ErrorMaxMessageLengthExceeded); handlecase(ErrorMaxPostPreDataLengthExceededError); handlecase(ErrorMetadataTooLarge); handlecase(ErrorMethodNotAllowed); handlecase(ErrorMissingAttachment); handlecase(ErrorMissingContentLength); handlecase(ErrorMissingSecurityElement); handlecase(ErrorMissingSecurityHeader); handlecase(ErrorNoLoggingStatusForKey); handlecase(ErrorNoSuchBucket); handlecase(ErrorNoSuchKey); handlecase(ErrorNotImplemented); handlecase(ErrorNotSignedUp); handlecase(ErrorOperationAborted); handlecase(ErrorPermanentRedirect); handlecase(ErrorPreconditionFailed); handlecase(ErrorRedirect); handlecase(ErrorRequestIsNotMultiPartContent); handlecase(ErrorRequestTimeout); handlecase(ErrorRequestTimeTooSkewed); handlecase(ErrorRequestTorrentOfBucketError); handlecase(ErrorSignatureDoesNotMatch); handlecase(ErrorSlowDown); handlecase(ErrorTemporaryRedirect); handlecase(ErrorTokenRefreshRequired); handlecase(ErrorTooManyBuckets); handlecase(ErrorUnexpectedContent); handlecase(ErrorUnresolvableGrantByEmailAddress); handlecase(ErrorUserKeyMustBeSpecified); handlecase(ErrorUnknown); handlecase(HttpErrorMovedTemporarily); handlecase(HttpErrorBadRequest); handlecase(HttpErrorForbidden); handlecase(HttpErrorNotFound); handlecase(HttpErrorConflict); handlecase(HttpErrorUnknown); } return "Unknown"; } S3Status S3_validate_bucket_name(const char *bucketName, S3UriStyle uriStyle) { int virtualHostStyle = (uriStyle == S3UriStyleVirtualHost); int len = 0, maxlen = virtualHostStyle ? 63 : 255; const char *b = bucketName; int hasDot = 0; int hasNonDigit = 0; while (*b) { if (len == maxlen) { return S3StatusInvalidBucketNameTooLong; } else if (isalpha(*b)) { len++, b++; hasNonDigit = 1; } else if (isdigit(*b)) { len++, b++; } else if (len == 0) { return S3StatusInvalidBucketNameFirstCharacter; } else if (*b == '_') { /* Virtual host style bucket names cannot have underscores */ if (virtualHostStyle) { return S3StatusInvalidBucketNameCharacter; } len++, b++; hasNonDigit = 1; } else if (*b == '-') { /* Virtual host style bucket names cannot have .- */ if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '.')) { return S3StatusInvalidBucketNameCharacterSequence; } len++, b++; hasNonDigit = 1; } else if (*b == '.') { /* Virtual host style bucket names cannot have -. */ if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '-')) { return S3StatusInvalidBucketNameCharacterSequence; } len++, b++; hasDot = 1; } else { return S3StatusInvalidBucketNameCharacter; } } if (len < 3) { return S3StatusInvalidBucketNameTooShort; } /* It's not clear from Amazon's documentation exactly what 'IP address style' means. In its strictest sense, it could mean 'could be a valid IP address', which would mean that 255.255.255.255 would be invalid, wherase 256.256.256.256 would be valid. Or it could mean 'has 4 sets of digits separated by dots'. Who knows. Let's just be really conservative here: if it has any dots, and no non-digit characters, then we reject it */ if (hasDot && !hasNonDigit) { return S3StatusInvalidBucketNameDotQuadNotation; } return S3StatusOK; } typedef struct ConvertAclData { char *ownerId; int ownerIdLen; char *ownerDisplayName; int ownerDisplayNameLen; int *aclGrantCountReturn; S3AclGrant *aclGrants; string_buffer(emailAddress, S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE); string_buffer(userId, S3_MAX_GRANTEE_USER_ID_SIZE); string_buffer(userDisplayName, S3_MAX_GRANTEE_DISPLAY_NAME_SIZE); string_buffer(groupUri, 128); string_buffer(permission, 32); } ConvertAclData; static S3Status convertAclXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { ConvertAclData *caData = (ConvertAclData *) callbackData; int fit; if (data) { if (!strcmp(elementPath, "AccessControlPolicy/Owner/ID")) { caData->ownerIdLen += snprintf(&(caData->ownerId[caData->ownerIdLen]), S3_MAX_GRANTEE_USER_ID_SIZE - caData->ownerIdLen - 1, "%.*s", dataLen, data); if (caData->ownerIdLen >= S3_MAX_GRANTEE_USER_ID_SIZE) { return S3StatusUserIdTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/Owner/" "DisplayName")) { caData->ownerDisplayNameLen += snprintf(&(caData->ownerDisplayName [caData->ownerDisplayNameLen]), S3_MAX_GRANTEE_DISPLAY_NAME_SIZE - caData->ownerDisplayNameLen - 1, "%.*s", dataLen, data); if (caData->ownerDisplayNameLen >= S3_MAX_GRANTEE_DISPLAY_NAME_SIZE) { return S3StatusUserDisplayNameTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/Grant/" "Grantee/EmailAddress")) { // AmazonCustomerByEmail string_buffer_append(caData->emailAddress, data, dataLen, fit); if (!fit) { return S3StatusEmailAddressTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/Grant/" "Grantee/ID")) { // CanonicalUser string_buffer_append(caData->userId, data, dataLen, fit); if (!fit) { return S3StatusUserIdTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/Grant/" "Grantee/DisplayName")) { // CanonicalUser string_buffer_append(caData->userDisplayName, data, dataLen, fit); if (!fit) { return S3StatusUserDisplayNameTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/Grant/" "Grantee/URI")) { // Group string_buffer_append(caData->groupUri, data, dataLen, fit); if (!fit) { return S3StatusGroupUriTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/Grant/" "Permission")) { // Permission string_buffer_append(caData->permission, data, dataLen, fit); if (!fit) { return S3StatusPermissionTooLong; } } } else { if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/" "Grant")) { // A grant has just been completed; so add the next S3AclGrant // based on the values read if (*(caData->aclGrantCountReturn) == S3_MAX_ACL_GRANT_COUNT) { return S3StatusTooManyGrants; } S3AclGrant *grant = &(caData->aclGrants [*(caData->aclGrantCountReturn)]); if (caData->emailAddress[0]) { grant->granteeType = S3GranteeTypeAmazonCustomerByEmail; strcpy(grant->grantee.amazonCustomerByEmail.emailAddress, caData->emailAddress); } else if (caData->userId[0] && caData->userDisplayName[0]) { grant->granteeType = S3GranteeTypeCanonicalUser; strcpy(grant->grantee.canonicalUser.id, caData->userId); strcpy(grant->grantee.canonicalUser.displayName, caData->userDisplayName); } else if (caData->groupUri[0]) { if (!strcmp(caData->groupUri, ACS_GROUP_AWS_USERS)) { grant->granteeType = S3GranteeTypeAllAwsUsers; } else if (!strcmp(caData->groupUri, ACS_GROUP_ALL_USERS)) { grant->granteeType = S3GranteeTypeAllUsers; } else if (!strcmp(caData->groupUri, ACS_GROUP_LOG_DELIVERY)) { grant->granteeType = S3GranteeTypeLogDelivery; } else { return S3StatusBadGrantee; } } else { return S3StatusBadGrantee; } if (!strcmp(caData->permission, "READ")) { grant->permission = S3PermissionRead; } else if (!strcmp(caData->permission, "WRITE")) { grant->permission = S3PermissionWrite; } else if (!strcmp(caData->permission, "READ_ACP")) { grant->permission = S3PermissionReadACP; } else if (!strcmp(caData->permission, "WRITE_ACP")) { grant->permission = S3PermissionWriteACP; } else if (!strcmp(caData->permission, "FULL_CONTROL")) { grant->permission = S3PermissionFullControl; } else { return S3StatusBadPermission; } (*(caData->aclGrantCountReturn))++; string_buffer_initialize(caData->emailAddress); string_buffer_initialize(caData->userId); string_buffer_initialize(caData->userDisplayName); string_buffer_initialize(caData->groupUri); string_buffer_initialize(caData->permission); } } return S3StatusOK; } S3Status S3_convert_acl(char *aclXml, char *ownerId, char *ownerDisplayName, int *aclGrantCountReturn, S3AclGrant *aclGrants) { ConvertAclData data; data.ownerId = ownerId; data.ownerIdLen = 0; data.ownerId[0] = 0; data.ownerDisplayName = ownerDisplayName; data.ownerDisplayNameLen = 0; data.ownerDisplayName[0] = 0; data.aclGrantCountReturn = aclGrantCountReturn; data.aclGrants = aclGrants; *aclGrantCountReturn = 0; string_buffer_initialize(data.emailAddress); string_buffer_initialize(data.userId); string_buffer_initialize(data.userDisplayName); string_buffer_initialize(data.groupUri); string_buffer_initialize(data.permission); // Use a simplexml parser SimpleXml simpleXml; simplexml_initialize(&simpleXml, &convertAclXmlCallback, &data); S3Status status = simplexml_add(&simpleXml, aclXml, strlen(aclXml)); simplexml_deinitialize(&simpleXml); return status; } int S3_status_is_retryable(S3Status status) { switch (status) { case S3StatusNameLookupError: case S3StatusFailedToConnect: case S3StatusConnectionFailed: case S3StatusErrorInternalError: case S3StatusErrorOperationAborted: case S3StatusErrorRequestTimeout: return 1; default: return 0; } } ceph-0.80.11/src/libs3/src/service_access_logging.c0000664000175100017510000005176112623076753024134 0ustar jenkins-buildjenkins-build/** ************************************************************************** * server_access_logging.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "libs3.h" #include "request.h" // get server access logging--------------------------------------------------- typedef struct ConvertBlsData { char *targetBucketReturn; int targetBucketReturnLen; char *targetPrefixReturn; int targetPrefixReturnLen; int *aclGrantCountReturn; S3AclGrant *aclGrants; string_buffer(emailAddress, S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE); string_buffer(userId, S3_MAX_GRANTEE_USER_ID_SIZE); string_buffer(userDisplayName, S3_MAX_GRANTEE_DISPLAY_NAME_SIZE); string_buffer(groupUri, 128); string_buffer(permission, 32); } ConvertBlsData; static S3Status convertBlsXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { ConvertBlsData *caData = (ConvertBlsData *) callbackData; int fit; if (data) { if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetBucket")) { caData->targetBucketReturnLen += snprintf(&(caData->targetBucketReturn [caData->targetBucketReturnLen]), 255 - caData->targetBucketReturnLen - 1, "%.*s", dataLen, data); if (caData->targetBucketReturnLen >= 255) { return S3StatusTargetBucketTooLong; } } else if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetPrefix")) { caData->targetPrefixReturnLen += snprintf(&(caData->targetPrefixReturn [caData->targetPrefixReturnLen]), 255 - caData->targetPrefixReturnLen - 1, "%.*s", dataLen, data); if (caData->targetPrefixReturnLen >= 255) { return S3StatusTargetPrefixTooLong; } } else if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetGrants/Grant/Grantee/EmailAddress")) { // AmazonCustomerByEmail string_buffer_append(caData->emailAddress, data, dataLen, fit); if (!fit) { return S3StatusEmailAddressTooLong; } } else if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/Grant/" "Grantee/ID")) { // CanonicalUser string_buffer_append(caData->userId, data, dataLen, fit); if (!fit) { return S3StatusUserIdTooLong; } } else if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetGrants/Grant/Grantee/DisplayName")) { // CanonicalUser string_buffer_append(caData->userDisplayName, data, dataLen, fit); if (!fit) { return S3StatusUserDisplayNameTooLong; } } else if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetGrants/Grant/Grantee/URI")) { // Group string_buffer_append(caData->groupUri, data, dataLen, fit); if (!fit) { return S3StatusGroupUriTooLong; } } else if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetGrants/Grant/Permission")) { // Permission string_buffer_append(caData->permission, data, dataLen, fit); if (!fit) { return S3StatusPermissionTooLong; } } } else { if (!strcmp(elementPath, "BucketLoggingStatus/LoggingEnabled/" "TargetGrants/Grant")) { // A grant has just been completed; so add the next S3AclGrant // based on the values read if (*(caData->aclGrantCountReturn) == S3_MAX_ACL_GRANT_COUNT) { return S3StatusTooManyGrants; } S3AclGrant *grant = &(caData->aclGrants [*(caData->aclGrantCountReturn)]); if (caData->emailAddress[0]) { grant->granteeType = S3GranteeTypeAmazonCustomerByEmail; strcpy(grant->grantee.amazonCustomerByEmail.emailAddress, caData->emailAddress); } else if (caData->userId[0] && caData->userDisplayName[0]) { grant->granteeType = S3GranteeTypeCanonicalUser; strcpy(grant->grantee.canonicalUser.id, caData->userId); strcpy(grant->grantee.canonicalUser.displayName, caData->userDisplayName); } else if (caData->groupUri[0]) { if (!strcmp(caData->groupUri, ACS_GROUP_AWS_USERS)) { grant->granteeType = S3GranteeTypeAllAwsUsers; } else if (!strcmp(caData->groupUri, ACS_GROUP_ALL_USERS)) { grant->granteeType = S3GranteeTypeAllUsers; } else { return S3StatusBadGrantee; } } else { return S3StatusBadGrantee; } if (!strcmp(caData->permission, "READ")) { grant->permission = S3PermissionRead; } else if (!strcmp(caData->permission, "WRITE")) { grant->permission = S3PermissionWrite; } else if (!strcmp(caData->permission, "READ_ACP")) { grant->permission = S3PermissionReadACP; } else if (!strcmp(caData->permission, "WRITE_ACP")) { grant->permission = S3PermissionWriteACP; } else if (!strcmp(caData->permission, "FULL_CONTROL")) { grant->permission = S3PermissionFullControl; } else { return S3StatusBadPermission; } (*(caData->aclGrantCountReturn))++; string_buffer_initialize(caData->emailAddress); string_buffer_initialize(caData->userId); string_buffer_initialize(caData->userDisplayName); string_buffer_initialize(caData->groupUri); string_buffer_initialize(caData->permission); } } return S3StatusOK; } static S3Status convert_bls(char *blsXml, char *targetBucketReturn, char *targetPrefixReturn, int *aclGrantCountReturn, S3AclGrant *aclGrants) { ConvertBlsData data; data.targetBucketReturn = targetBucketReturn; data.targetBucketReturn[0] = 0; data.targetBucketReturnLen = 0; data.targetPrefixReturn = targetPrefixReturn; data.targetPrefixReturn[0] = 0; data.targetPrefixReturnLen = 0; data.aclGrantCountReturn = aclGrantCountReturn; data.aclGrants = aclGrants; *aclGrantCountReturn = 0; string_buffer_initialize(data.emailAddress); string_buffer_initialize(data.userId); string_buffer_initialize(data.userDisplayName); string_buffer_initialize(data.groupUri); string_buffer_initialize(data.permission); // Use a simplexml parser SimpleXml simpleXml; simplexml_initialize(&simpleXml, &convertBlsXmlCallback, &data); S3Status status = simplexml_add(&simpleXml, blsXml, strlen(blsXml)); simplexml_deinitialize(&simpleXml); return status; } // Use a rather arbitrary max size for the document of 64K #define BLS_XML_DOC_MAXSIZE (64 * 1024) typedef struct GetBlsData { SimpleXml simpleXml; S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; char *targetBucketReturn; char *targetPrefixReturn; int *aclGrantCountReturn; S3AclGrant *aclGrants; string_buffer(blsXmlDocument, BLS_XML_DOC_MAXSIZE); } GetBlsData; static S3Status getBlsPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { GetBlsData *gsData = (GetBlsData *) callbackData; return (*(gsData->responsePropertiesCallback)) (responseProperties, gsData->callbackData); } static S3Status getBlsDataCallback(int bufferSize, const char *buffer, void *callbackData) { GetBlsData *gsData = (GetBlsData *) callbackData; int fit; string_buffer_append(gsData->blsXmlDocument, buffer, bufferSize, fit); return fit ? S3StatusOK : S3StatusXmlDocumentTooLarge; } static void getBlsCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { GetBlsData *gsData = (GetBlsData *) callbackData; if (requestStatus == S3StatusOK) { // Parse the document requestStatus = convert_bls (gsData->blsXmlDocument, gsData->targetBucketReturn, gsData->targetPrefixReturn, gsData->aclGrantCountReturn, gsData->aclGrants); } (*(gsData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, gsData->callbackData); free(gsData); } void S3_get_server_access_logging(const S3BucketContext *bucketContext, char *targetBucketReturn, char *targetPrefixReturn, int *aclGrantCountReturn, S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Create the callback data GetBlsData *gsData = (GetBlsData *) malloc(sizeof(GetBlsData)); if (!gsData) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } gsData->responsePropertiesCallback = handler->propertiesCallback; gsData->responseCompleteCallback = handler->completeCallback; gsData->callbackData = callbackData; gsData->targetBucketReturn = targetBucketReturn; gsData->targetPrefixReturn = targetPrefixReturn; gsData->aclGrantCountReturn = aclGrantCountReturn; gsData->aclGrants = aclGrants; string_buffer_initialize(gsData->blsXmlDocument); *aclGrantCountReturn = 0; // Set up the RequestParams RequestParams params = { HttpRequestTypeGET, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey 0, // key 0, // queryParams "logging", // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &getBlsPropertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize &getBlsDataCallback, // fromS3Callback &getBlsCompleteCallback, // completeCallback gsData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // set server access logging--------------------------------------------------- static S3Status generateSalXmlDocument(const char *targetBucket, const char *targetPrefix, int aclGrantCount, const S3AclGrant *aclGrants, int *xmlDocumentLenReturn, char *xmlDocument, int xmlDocumentBufferSize) { *xmlDocumentLenReturn = 0; #define append(fmt, ...) \ do { \ *xmlDocumentLenReturn += snprintf \ (&(xmlDocument[*xmlDocumentLenReturn]), \ xmlDocumentBufferSize - *xmlDocumentLenReturn - 1, \ fmt, __VA_ARGS__); \ if (*xmlDocumentLenReturn >= xmlDocumentBufferSize) { \ return S3StatusXmlDocumentTooLarge; \ } \ } while (0) append("%s", ""); if (targetBucket && targetBucket[0]) { append("%s", targetBucket); append("%s", targetPrefix ? targetPrefix : ""); if (aclGrantCount) { append("%s", ""); int i; for (i = 0; i < aclGrantCount; i++) { append("%s", "granteeType) { case S3GranteeTypeAmazonCustomerByEmail: append("AmazonCustomerByEmail\">%s" "", grant->grantee.amazonCustomerByEmail.emailAddress); break; case S3GranteeTypeCanonicalUser: append("CanonicalUser\">%s%s" "", grant->grantee.canonicalUser.id, grant->grantee.canonicalUser.displayName); break; default: // case S3GranteeTypeAllAwsUsers/S3GranteeTypeAllUsers: append("Group\">%s", (grant->granteeType == S3GranteeTypeAllAwsUsers) ? ACS_GROUP_AWS_USERS : ACS_GROUP_ALL_USERS); break; } append("%s", ((grant->permission == S3PermissionRead) ? "READ" : (grant->permission == S3PermissionWrite) ? "WRITE" : (grant->permission == S3PermissionReadACP) ? "READ_ACP" : (grant->permission == S3PermissionWriteACP) ? "WRITE_ACP" : "FULL_CONTROL")); } append("%s", ""); } append("%s", ""); } append("%s", ""); return S3StatusOK; } typedef struct SetSalData { S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; int salXmlDocumentLen; char salXmlDocument[BLS_XML_DOC_MAXSIZE]; int salXmlDocumentBytesWritten; } SetSalData; static S3Status setSalPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { SetSalData *paData = (SetSalData *) callbackData; return (*(paData->responsePropertiesCallback)) (responseProperties, paData->callbackData); } static int setSalDataCallback(int bufferSize, char *buffer, void *callbackData) { SetSalData *paData = (SetSalData *) callbackData; int remaining = (paData->salXmlDocumentLen - paData->salXmlDocumentBytesWritten); int toCopy = bufferSize > remaining ? remaining : bufferSize; if (!toCopy) { return 0; } memcpy(buffer, &(paData->salXmlDocument [paData->salXmlDocumentBytesWritten]), toCopy); paData->salXmlDocumentBytesWritten += toCopy; return toCopy; } static void setSalCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { SetSalData *paData = (SetSalData *) callbackData; (*(paData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, paData->callbackData); free(paData); } void S3_set_server_access_logging(const S3BucketContext *bucketContext, const char *targetBucket, const char *targetPrefix, int aclGrantCount, const S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { if (aclGrantCount > S3_MAX_ACL_GRANT_COUNT) { (*(handler->completeCallback)) (S3StatusTooManyGrants, 0, callbackData); return; } SetSalData *data = (SetSalData *) malloc(sizeof(SetSalData)); if (!data) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } // Convert aclGrants to XML document S3Status status = generateSalXmlDocument (targetBucket, targetPrefix, aclGrantCount, aclGrants, &(data->salXmlDocumentLen), data->salXmlDocument, sizeof(data->salXmlDocument)); if (status != S3StatusOK) { free(data); (*(handler->completeCallback))(status, 0, callbackData); return; } data->responsePropertiesCallback = handler->propertiesCallback; data->responseCompleteCallback = handler->completeCallback; data->callbackData = callbackData; data->salXmlDocumentBytesWritten = 0; // Set up the RequestParams RequestParams params = { HttpRequestTypePUT, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey 0, // key 0, // queryParams "logging", // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &setSalPropertiesCallback, // propertiesCallback &setSalDataCallback, // toS3Callback data->salXmlDocumentLen, // toS3CallbackTotalSize 0, // fromS3Callback &setSalCompleteCallback, // completeCallback data // callbackData }; // Perform the request request_perform(¶ms, requestContext); } ceph-0.80.11/src/libs3/src/object.c0000664000175100017510000003545012623076753020710 0ustar jenkins-buildjenkins-build/** ************************************************************************** * object.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "libs3.h" #include "request.h" // put object ---------------------------------------------------------------- void S3_put_object(const S3BucketContext *bucketContext, const char *key, uint64_t contentLength, const S3PutProperties *putProperties, S3RequestContext *requestContext, const S3PutObjectHandler *handler, void *callbackData) { // Set up the RequestParams RequestParams params = { HttpRequestTypePUT, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey key, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount putProperties, // putProperties handler->responseHandler.propertiesCallback, // propertiesCallback handler->putObjectDataCallback, // toS3Callback contentLength, // toS3CallbackTotalSize 0, // fromS3Callback handler->responseHandler.completeCallback, // completeCallback callbackData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // copy object --------------------------------------------------------------- typedef struct CopyObjectData { SimpleXml simpleXml; S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; int64_t *lastModifiedReturn; int eTagReturnSize; char *eTagReturn; int eTagReturnLen; string_buffer(lastModified, 256); } CopyObjectData; static S3Status copyObjectXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { CopyObjectData *coData = (CopyObjectData *) callbackData; int fit; if (data) { if (!strcmp(elementPath, "CopyObjectResult/LastModified")) { string_buffer_append(coData->lastModified, data, dataLen, fit); } else if (!strcmp(elementPath, "CopyObjectResult/ETag")) { if (coData->eTagReturnSize && coData->eTagReturn) { coData->eTagReturnLen += snprintf(&(coData->eTagReturn[coData->eTagReturnLen]), coData->eTagReturnSize - coData->eTagReturnLen - 1, "%.*s", dataLen, data); if (coData->eTagReturnLen >= coData->eTagReturnSize) { return S3StatusXmlParseFailure; } } } } /* Avoid compiler error about variable set but not used */ (void) fit; return S3StatusOK; } static S3Status copyObjectPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { CopyObjectData *coData = (CopyObjectData *) callbackData; return (*(coData->responsePropertiesCallback)) (responseProperties, coData->callbackData); } static S3Status copyObjectDataCallback(int bufferSize, const char *buffer, void *callbackData) { CopyObjectData *coData = (CopyObjectData *) callbackData; return simplexml_add(&(coData->simpleXml), buffer, bufferSize); } static void copyObjectCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { CopyObjectData *coData = (CopyObjectData *) callbackData; if (coData->lastModifiedReturn) { time_t lastModified = -1; if (coData->lastModifiedLen) { lastModified = parseIso8601Time(coData->lastModified); } *(coData->lastModifiedReturn) = lastModified; } (*(coData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, coData->callbackData); simplexml_deinitialize(&(coData->simpleXml)); free(coData); } void S3_copy_object(const S3BucketContext *bucketContext, const char *key, const char *destinationBucket, const char *destinationKey, const S3PutProperties *putProperties, int64_t *lastModifiedReturn, int eTagReturnSize, char *eTagReturn, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Create the callback data CopyObjectData *data = (CopyObjectData *) malloc(sizeof(CopyObjectData)); if (!data) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } simplexml_initialize(&(data->simpleXml), ©ObjectXmlCallback, data); data->responsePropertiesCallback = handler->propertiesCallback; data->responseCompleteCallback = handler->completeCallback; data->callbackData = callbackData; data->lastModifiedReturn = lastModifiedReturn; data->eTagReturnSize = eTagReturnSize; data->eTagReturn = eTagReturn; if (data->eTagReturnSize && data->eTagReturn) { data->eTagReturn[0] = 0; } data->eTagReturnLen = 0; string_buffer_initialize(data->lastModified); // Set up the RequestParams RequestParams params = { HttpRequestTypeCOPY, // httpRequestType { bucketContext->hostName, // hostName destinationBucket ? destinationBucket : bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey destinationKey ? destinationKey : key, // key 0, // queryParams 0, // subResource bucketContext->bucketName, // copySourceBucketName key, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount putProperties, // putProperties ©ObjectPropertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize ©ObjectDataCallback, // fromS3Callback ©ObjectCompleteCallback, // completeCallback data // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // get object ---------------------------------------------------------------- void S3_get_object(const S3BucketContext *bucketContext, const char *key, const S3GetConditions *getConditions, uint64_t startByte, uint64_t byteCount, S3RequestContext *requestContext, const S3GetObjectHandler *handler, void *callbackData) { // Set up the RequestParams RequestParams params = { HttpRequestTypeGET, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey key, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey getConditions, // getConditions startByte, // startByte byteCount, // byteCount 0, // putProperties handler->responseHandler.propertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize handler->getObjectDataCallback, // fromS3Callback handler->responseHandler.completeCallback, // completeCallback callbackData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // head object --------------------------------------------------------------- void S3_head_object(const S3BucketContext *bucketContext, const char *key, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Set up the RequestParams RequestParams params = { HttpRequestTypeHEAD, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey key, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties handler->propertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize 0, // fromS3Callback handler->completeCallback, // completeCallback callbackData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // delete object -------------------------------------------------------------- void S3_delete_object(const S3BucketContext *bucketContext, const char *key, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Set up the RequestParams RequestParams params = { HttpRequestTypeDELETE, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey key, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties handler->propertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize 0, // fromS3Callback handler->completeCallback, // completeCallback callbackData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } ceph-0.80.11/src/libs3/src/mingw_functions.c0000664000175100017510000000532612623076753022652 0ustar jenkins-buildjenkins-build/** ************************************************************************** * mingw_functions.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include unsigned long pthread_self() { return (unsigned long) GetCurrentThreadId(); } int pthread_mutex_init(pthread_mutex_t *mutex, void *v) { (void) v; InitializeCriticalSection(&(mutex->criticalSection)); return 0; } int pthread_mutex_lock(pthread_mutex_t *mutex) { EnterCriticalSection(&(mutex->criticalSection)); return 0; } int pthread_mutex_unlock(pthread_mutex_t *mutex) { LeaveCriticalSection(&(mutex->criticalSection)); return 0; } int pthread_mutex_destroy(pthread_mutex_t *mutex) { DeleteCriticalSection(&(mutex->criticalSection)); return 0; } int uname(struct utsname *u) { OSVERSIONINFO info; info.dwOSVersionInfoSize = sizeof(info); if (!GetVersionEx(&info)) { return -1; } u->machine = ""; switch (info.dwMajorVersion) { case 4: switch (info.dwMinorVersion) { case 0: u->sysname = "Microsoft Windows NT 4.0"; break; case 10: u->sysname = "Microsoft Windows 98"; break; case 90: u->sysname = "Microsoft Windows Me"; break; default: return -1; } break; case 5: switch (info.dwMinorVersion) { case 0: u->sysname = "Microsoft Windows 2000"; break; case 1: u->sysname = "Microsoft Windows XP"; break; case 2: u->sysname = "Microsoft Server 2003"; break; default: return -1; } break; default: return -1; } return 0; } ceph-0.80.11/src/libs3/src/util.c0000664000175100017510000003662212623076753020421 0ustar jenkins-buildjenkins-build/** ************************************************************************** * util.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "util.h" // Convenience utility for making the code look nicer. Tests a string // against a format; only the characters specified in the format are // checked (i.e. if the string is longer than the format, the string still // checks out ok). Format characters are: // d - is a digit // anything else - is that character // Returns nonzero the string checks out, zero if it does not. static int checkString(const char *str, const char *format) { while (*format) { if (*format == 'd') { if (!isdigit(*str)) { return 0; } } else if (*str != *format) { return 0; } str++, format++; } return 1; } int urlEncode(char *dest, const char *src, int maxSrcSize) { static const char *hex = "0123456789ABCDEF"; int len = 0; if (src) while (*src) { if (++len > maxSrcSize) { *dest = 0; return 0; } unsigned char c = *src; if (isalnum(c) || (c == '-') || (c == '_') || (c == '.') || (c == '!') || (c == '~') || (c == '*') || (c == '\'') || (c == '(') || (c == ')') || (c == '/')) { *dest++ = c; } else if (*src == ' ') { *dest++ = '+'; } else { *dest++ = '%'; *dest++ = hex[c >> 4]; *dest++ = hex[c & 15]; } src++; } *dest = 0; return 1; } int64_t parseIso8601Time(const char *str) { // Check to make sure that it has a valid format if (!checkString(str, "dddd-dd-ddTdd:dd:dd")) { return -1; } #define nextnum() (((*str - '0') * 10) + (*(str + 1) - '0')) // Convert it struct tm stm; memset(&stm, 0, sizeof(stm)); stm.tm_year = (nextnum() - 19) * 100; str += 2; stm.tm_year += nextnum(); str += 3; stm.tm_mon = nextnum() - 1; str += 3; stm.tm_mday = nextnum(); str += 3; stm.tm_hour = nextnum(); str += 3; stm.tm_min = nextnum(); str += 3; stm.tm_sec = nextnum(); str += 2; stm.tm_isdst = -1; int64_t ret = mktime(&stm); // Skip the millis if (*str == '.') { str++; while (isdigit(*str)) { str++; } } if (checkString(str, "-dd:dd") || checkString(str, "+dd:dd")) { int sign = (*str++ == '-') ? -1 : 1; int hours = nextnum(); str += 3; int minutes = nextnum(); ret += (-sign * (((hours * 60) + minutes) * 60)); } // Else it should be Z to be a conformant time string, but we just assume // that it is rather than enforcing that return ret; } uint64_t parseUnsignedInt(const char *str) { // Skip whitespace while (is_blank(*str)) { str++; } uint64_t ret = 0; while (isdigit(*str)) { ret *= 10; ret += (*str++ - '0'); } return ret; } int base64Encode(const unsigned char *in, int inLen, char *out) { static const char *ENC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *original_out = out; while (inLen) { // first 6 bits of char 1 *out++ = ENC[*in >> 2]; if (!--inLen) { // last 2 bits of char 1, 4 bits of 0 *out++ = ENC[(*in & 0x3) << 4]; *out++ = '='; *out++ = '='; break; } // last 2 bits of char 1, first 4 bits of char 2 *out++ = ENC[((*in & 0x3) << 4) | (*(in + 1) >> 4)]; in++; if (!--inLen) { // last 4 bits of char 2, 2 bits of 0 *out++ = ENC[(*in & 0xF) << 2]; *out++ = '='; break; } // last 4 bits of char 2, first 2 bits of char 3 *out++ = ENC[((*in & 0xF) << 2) | (*(in + 1) >> 6)]; in++; // last 6 bits of char 3 *out++ = ENC[*in & 0x3F]; in++, inLen--; } return (out - original_out); } #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) #define blk0L(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \ | (rol(block->l[i], 8) & 0x00FF00FF)) #define blk0B(i) (block->l[i]) #define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ block->l[(i + 8) & 15] ^ \ block->l[(i + 2) & 15] ^ \ block->l[i & 15], 1)) #define R0_L(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk0L(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R0_B(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk0B(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R1(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R2(v, w, x, y, z, i) \ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ w = rol(w, 30); #define R3(v, w, x, y, z, i) \ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ w = rol(w, 30); #define R4(v, w, x, y, z, i) \ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ w = rol(w, 30); #define R0A_L(i) R0_L(a, b, c, d, e, i) #define R0B_L(i) R0_L(b, c, d, e, a, i) #define R0C_L(i) R0_L(c, d, e, a, b, i) #define R0D_L(i) R0_L(d, e, a, b, c, i) #define R0E_L(i) R0_L(e, a, b, c, d, i) #define R0A_B(i) R0_B(a, b, c, d, e, i) #define R0B_B(i) R0_B(b, c, d, e, a, i) #define R0C_B(i) R0_B(c, d, e, a, b, i) #define R0D_B(i) R0_B(d, e, a, b, c, i) #define R0E_B(i) R0_B(e, a, b, c, d, i) #define R1A(i) R1(a, b, c, d, e, i) #define R1B(i) R1(b, c, d, e, a, i) #define R1C(i) R1(c, d, e, a, b, i) #define R1D(i) R1(d, e, a, b, c, i) #define R1E(i) R1(e, a, b, c, d, i) #define R2A(i) R2(a, b, c, d, e, i) #define R2B(i) R2(b, c, d, e, a, i) #define R2C(i) R2(c, d, e, a, b, i) #define R2D(i) R2(d, e, a, b, c, i) #define R2E(i) R2(e, a, b, c, d, i) #define R3A(i) R3(a, b, c, d, e, i) #define R3B(i) R3(b, c, d, e, a, i) #define R3C(i) R3(c, d, e, a, b, i) #define R3D(i) R3(d, e, a, b, c, i) #define R3E(i) R3(e, a, b, c, d, i) #define R4A(i) R4(a, b, c, d, e, i) #define R4B(i) R4(b, c, d, e, a, i) #define R4C(i) R4(c, d, e, a, b, i) #define R4D(i) R4(d, e, a, b, c, i) #define R4E(i) R4(e, a, b, c, d, i) static void SHA1_transform(uint32_t state[5], const unsigned char buffer[64]) { uint32_t a, b, c, d, e; typedef union { unsigned char c[64]; uint32_t l[16]; } u; unsigned char w[64]; u *block = (u *) w; memcpy(block, buffer, 64); a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; static uint32_t endianness_indicator = 0x1; if (((unsigned char *) &endianness_indicator)[0]) { R0A_L( 0); R0E_L( 1); R0D_L( 2); R0C_L( 3); R0B_L( 4); R0A_L( 5); R0E_L( 6); R0D_L( 7); R0C_L( 8); R0B_L( 9); R0A_L(10); R0E_L(11); R0D_L(12); R0C_L(13); R0B_L(14); R0A_L(15); } else { R0A_B( 0); R0E_B( 1); R0D_B( 2); R0C_B( 3); R0B_B( 4); R0A_B( 5); R0E_B( 6); R0D_B( 7); R0C_B( 8); R0B_B( 9); R0A_B(10); R0E_B(11); R0D_B(12); R0C_B(13); R0B_B(14); R0A_B(15); } R1E(16); R1D(17); R1C(18); R1B(19); R2A(20); R2E(21); R2D(22); R2C(23); R2B(24); R2A(25); R2E(26); R2D(27); R2C(28); R2B(29); R2A(30); R2E(31); R2D(32); R2C(33); R2B(34); R2A(35); R2E(36); R2D(37); R2C(38); R2B(39); R3A(40); R3E(41); R3D(42); R3C(43); R3B(44); R3A(45); R3E(46); R3D(47); R3C(48); R3B(49); R3A(50); R3E(51); R3D(52); R3C(53); R3B(54); R3A(55); R3E(56); R3D(57); R3C(58); R3B(59); R4A(60); R4E(61); R4D(62); R4C(63); R4B(64); R4A(65); R4E(66); R4D(67); R4C(68); R4B(69); R4A(70); R4E(71); R4D(72); R4C(73); R4B(74); R4A(75); R4E(76); R4D(77); R4C(78); R4B(79); state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } typedef struct { uint32_t state[5]; uint32_t count[2]; unsigned char buffer[64]; } SHA1Context; static void SHA1_init(SHA1Context *context) { context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } static void SHA1_update(SHA1Context *context, const unsigned char *data, unsigned int len) { uint32_t i, j; j = (context->count[0] >> 3) & 63; if ((context->count[0] += len << 3) < (len << 3)) { context->count[1]++; } context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&(context->buffer[j]), data, (i = 64 - j)); SHA1_transform(context->state, context->buffer); for ( ; (i + 63) < len; i += 64) { SHA1_transform(context->state, &(data[i])); } j = 0; } else { i = 0; } memcpy(&(context->buffer[j]), &(data[i]), len - i); } static void SHA1_final(unsigned char digest[20], SHA1Context *context) { uint32_t i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); } SHA1_update(context, (unsigned char *) "\200", 1); while ((context->count[0] & 504) != 448) { SHA1_update(context, (unsigned char *) "\0", 1); } SHA1_update(context, finalcount, 8); for (i = 0; i < 20; i++) { digest[i] = (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } memset(context->buffer, 0, 64); memset(context->state, 0, 20); memset(context->count, 0, 8); memset(&finalcount, 0, 8); SHA1_transform(context->state, context->buffer); } // HMAC-SHA-1: // // K - is key padded with zeros to 512 bits // m - is message // OPAD - 0x5c5c5c... // IPAD - 0x363636... // // HMAC(K,m) = SHA1((K ^ OPAD) . SHA1((K ^ IPAD) . m)) void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len, const unsigned char *message, int message_len) { unsigned char kopad[64], kipad[64]; int i; if (key_len > 64) { key_len = 64; } for (i = 0; i < key_len; i++) { kopad[i] = key[i] ^ 0x5c; kipad[i] = key[i] ^ 0x36; } for ( ; i < 64; i++) { kopad[i] = 0 ^ 0x5c; kipad[i] = 0 ^ 0x36; } unsigned char digest[20]; SHA1Context context; SHA1_init(&context); SHA1_update(&context, kipad, 64); SHA1_update(&context, message, message_len); SHA1_final(digest, &context); SHA1_init(&context); SHA1_update(&context, kopad, 64); SHA1_update(&context, digest, 20); SHA1_final(hmac, &context); } #define rot(x,k) (((x) << (k)) | ((x) >> (32 - (k)))) uint64_t hash(const unsigned char *k, int length) { uint32_t a, b, c; a = b = c = 0xdeadbeef + ((uint32_t) length); static uint32_t endianness_indicator = 0x1; if (((unsigned char *) &endianness_indicator)[0]) { while (length > 12) { a += k[0]; a += ((uint32_t) k[1]) << 8; a += ((uint32_t) k[2]) << 16; a += ((uint32_t) k[3]) << 24; b += k[4]; b += ((uint32_t) k[5]) << 8; b += ((uint32_t) k[6]) << 16; b += ((uint32_t) k[7]) << 24; c += k[8]; c += ((uint32_t) k[9]) << 8; c += ((uint32_t) k[10]) << 16; c += ((uint32_t) k[11]) << 24; a -= c; a ^= rot(c, 4); c += b; b -= a; b ^= rot(a, 6); a += c; c -= b; c ^= rot(b, 8); b += a; a -= c; a ^= rot(c, 16); c += b; b -= a; b ^= rot(a, 19); a += c; c -= b; c ^= rot(b, 4); b += a; length -= 12; k += 12; } switch(length) { case 12: c += ((uint32_t) k[11]) << 24; case 11: c += ((uint32_t) k[10]) << 16; case 10: c += ((uint32_t) k[9]) << 8; case 9 : c += k[8]; case 8 : b += ((uint32_t) k[7]) << 24; case 7 : b += ((uint32_t) k[6]) << 16; case 6 : b += ((uint32_t) k[5]) << 8; case 5 : b += k[4]; case 4 : a += ((uint32_t) k[3]) << 24; case 3 : a += ((uint32_t) k[2]) << 16; case 2 : a += ((uint32_t) k[1]) << 8; case 1 : a += k[0]; break; case 0 : goto end; } } else { while (length > 12) { a += ((uint32_t) k[0]) << 24; a += ((uint32_t) k[1]) << 16; a += ((uint32_t) k[2]) << 8; a += ((uint32_t) k[3]); b += ((uint32_t) k[4]) << 24; b += ((uint32_t) k[5]) << 16; b += ((uint32_t) k[6]) << 8; b += ((uint32_t) k[7]); c += ((uint32_t) k[8]) << 24; c += ((uint32_t) k[9]) << 16; c += ((uint32_t) k[10]) << 8; c += ((uint32_t) k[11]); a -= c; a ^= rot(c, 4); c += b; b -= a; b ^= rot(a, 6); a += c; c -= b; c ^= rot(b, 8); b += a; a -= c; a ^= rot(c, 16); c += b; b -= a; b ^= rot(a, 19); a += c; c -= b; c ^= rot(b, 4); b += a; length -= 12; k += 12; } switch(length) { case 12: c += k[11]; case 11: c += ((uint32_t) k[10]) << 8; case 10: c += ((uint32_t) k[9]) << 16; case 9 : c += ((uint32_t) k[8]) << 24; case 8 : b += k[7]; case 7 : b += ((uint32_t) k[6]) << 8; case 6 : b += ((uint32_t) k[5]) << 16; case 5 : b += ((uint32_t) k[4]) << 24; case 4 : a += k[3]; case 3 : a += ((uint32_t) k[2]) << 8; case 2 : a += ((uint32_t) k[1]) << 16; case 1 : a += ((uint32_t) k[0]) << 24; break; case 0 : goto end; } } c ^= b; c -= rot(b, 14); a ^= c; a -= rot(c, 11); b ^= a; b -= rot(a, 25); c ^= b; c -= rot(b, 16); a ^= c; a -= rot(c, 4); b ^= a; b -= rot(a, 14); c ^= b; c -= rot(b, 24); end: return ((((uint64_t) c) << 32) | b); } int is_blank(char c) { return ((c == ' ') || (c == '\t')); } ceph-0.80.11/src/libs3/src/error_parser.c0000664000175100017510000002126512623076753022146 0ustar jenkins-buildjenkins-build/** ************************************************************************** * error_parser.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include "error_parser.h" static S3Status errorXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { // We ignore end of element callbacks because we don't care about them if (!data) { return S3StatusOK; } ErrorParser *errorParser = (ErrorParser *) callbackData; int fit; if (!strcmp(elementPath, "Error")) { // Ignore, this is the Error element itself, we only care about subs } else if (!strcmp(elementPath, "Error/Code")) { string_buffer_append(errorParser->code, data, dataLen, fit); } else if (!strcmp(elementPath, "Error/Message")) { string_buffer_append(errorParser->message, data, dataLen, fit); errorParser->s3ErrorDetails.message = errorParser->message; } else if (!strcmp(elementPath, "Error/Resource")) { string_buffer_append(errorParser->resource, data, dataLen, fit); errorParser->s3ErrorDetails.resource = errorParser->resource; } else if (!strcmp(elementPath, "Error/FurtherDetails")) { string_buffer_append(errorParser->furtherDetails, data, dataLen, fit); errorParser->s3ErrorDetails.furtherDetails = errorParser->furtherDetails; } else { if (strncmp(elementPath, "Error/", sizeof("Error/") - 1)) { // If for some weird reason it's not within the Error element, // ignore it return S3StatusOK; } // It's an unknown error element. See if it matches the most // recent error element. const char *elementName = &(elementPath[sizeof("Error/") - 1]); if (errorParser->s3ErrorDetails.extraDetailsCount && !strcmp(elementName, errorParser->s3ErrorDetails.extraDetails [errorParser->s3ErrorDetails.extraDetailsCount - 1].name)) { // Append the value string_multibuffer_append(errorParser->extraDetailsNamesValues, data, dataLen, fit); // If it didn't fit, remove this extra if (!fit) { errorParser->s3ErrorDetails.extraDetailsCount--; } return S3StatusOK; } // OK, must add another unknown error element, if it will fit. if (errorParser->s3ErrorDetails.extraDetailsCount == sizeof(errorParser->extraDetails)) { // Won't fit. Ignore this one. return S3StatusOK; } // Copy in the name and value char *name = string_multibuffer_current (errorParser->extraDetailsNamesValues); int nameLen = strlen(elementName); string_multibuffer_add(errorParser->extraDetailsNamesValues, elementName, nameLen, fit); if (!fit) { // Name didn't fit; ignore this one. return S3StatusOK; } char *value = string_multibuffer_current (errorParser->extraDetailsNamesValues); string_multibuffer_add(errorParser->extraDetailsNamesValues, data, dataLen, fit); if (!fit) { // Value didn't fit; ignore this one. return S3StatusOK; } S3NameValue *nv = &(errorParser->extraDetails [errorParser->s3ErrorDetails.extraDetailsCount++]); nv->name = name; nv->value = value; } return S3StatusOK; } void error_parser_initialize(ErrorParser *errorParser) { errorParser->s3ErrorDetails.message = 0; errorParser->s3ErrorDetails.resource = 0; errorParser->s3ErrorDetails.furtherDetails = 0; errorParser->s3ErrorDetails.extraDetailsCount = 0; errorParser->s3ErrorDetails.extraDetails = errorParser->extraDetails; errorParser->errorXmlParserInitialized = 0; string_buffer_initialize(errorParser->code); string_buffer_initialize(errorParser->message); string_buffer_initialize(errorParser->resource); string_buffer_initialize(errorParser->furtherDetails); string_multibuffer_initialize(errorParser->extraDetailsNamesValues); } S3Status error_parser_add(ErrorParser *errorParser, char *buffer, int bufferSize) { if (!errorParser->errorXmlParserInitialized) { simplexml_initialize(&(errorParser->errorXmlParser), &errorXmlCallback, errorParser); errorParser->errorXmlParserInitialized = 1; } return simplexml_add(&(errorParser->errorXmlParser), buffer, bufferSize); } void error_parser_convert_status(ErrorParser *errorParser, S3Status *status) { // Convert the error status string into a code if (!errorParser->codeLen) { return; } #define HANDLE_CODE(name) \ do { \ if (!strcmp(errorParser->code, #name)) { \ *status = S3StatusError##name; \ goto code_set; \ } \ } while (0) HANDLE_CODE(AccessDenied); HANDLE_CODE(AccountProblem); HANDLE_CODE(AmbiguousGrantByEmailAddress); HANDLE_CODE(BadDigest); HANDLE_CODE(BucketAlreadyExists); HANDLE_CODE(BucketAlreadyOwnedByYou); HANDLE_CODE(BucketNotEmpty); HANDLE_CODE(CredentialsNotSupported); HANDLE_CODE(CrossLocationLoggingProhibited); HANDLE_CODE(EntityTooSmall); HANDLE_CODE(EntityTooLarge); HANDLE_CODE(ExpiredToken); HANDLE_CODE(IncompleteBody); HANDLE_CODE(IncorrectNumberOfFilesInPostRequest); HANDLE_CODE(InlineDataTooLarge); HANDLE_CODE(InternalError); HANDLE_CODE(InvalidAccessKeyId); HANDLE_CODE(InvalidAddressingHeader); HANDLE_CODE(InvalidArgument); HANDLE_CODE(InvalidBucketName); HANDLE_CODE(InvalidDigest); HANDLE_CODE(InvalidLocationConstraint); HANDLE_CODE(InvalidPayer); HANDLE_CODE(InvalidPolicyDocument); HANDLE_CODE(InvalidRange); HANDLE_CODE(InvalidSecurity); HANDLE_CODE(InvalidSOAPRequest); HANDLE_CODE(InvalidStorageClass); HANDLE_CODE(InvalidTargetBucketForLogging); HANDLE_CODE(InvalidToken); HANDLE_CODE(InvalidURI); HANDLE_CODE(KeyTooLong); HANDLE_CODE(MalformedACLError); HANDLE_CODE(MalformedXML); HANDLE_CODE(MaxMessageLengthExceeded); HANDLE_CODE(MaxPostPreDataLengthExceededError); HANDLE_CODE(MetadataTooLarge); HANDLE_CODE(MethodNotAllowed); HANDLE_CODE(MissingAttachment); HANDLE_CODE(MissingContentLength); HANDLE_CODE(MissingSecurityElement); HANDLE_CODE(MissingSecurityHeader); HANDLE_CODE(NoLoggingStatusForKey); HANDLE_CODE(NoSuchBucket); HANDLE_CODE(NoSuchKey); HANDLE_CODE(NotImplemented); HANDLE_CODE(NotSignedUp); HANDLE_CODE(OperationAborted); HANDLE_CODE(PermanentRedirect); HANDLE_CODE(PreconditionFailed); HANDLE_CODE(Redirect); HANDLE_CODE(RequestIsNotMultiPartContent); HANDLE_CODE(RequestTimeout); HANDLE_CODE(RequestTimeTooSkewed); HANDLE_CODE(RequestTorrentOfBucketError); HANDLE_CODE(SignatureDoesNotMatch); HANDLE_CODE(SlowDown); HANDLE_CODE(TemporaryRedirect); HANDLE_CODE(TokenRefreshRequired); HANDLE_CODE(TooManyBuckets); HANDLE_CODE(UnexpectedContent); HANDLE_CODE(UnresolvableGrantByEmailAddress); HANDLE_CODE(UserKeyMustBeSpecified); *status = S3StatusErrorUnknown; code_set: return; } // Always call this void error_parser_deinitialize(ErrorParser *errorParser) { if (errorParser->errorXmlParserInitialized) { simplexml_deinitialize(&(errorParser->errorXmlParser)); } } ceph-0.80.11/src/libs3/src/request_context.c0000664000175100017510000001471712623076753022701 0ustar jenkins-buildjenkins-build/** ************************************************************************** * request_context.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include #include "request.h" #include "request_context.h" S3Status S3_create_request_context(S3RequestContext **requestContextReturn) { *requestContextReturn = (S3RequestContext *) malloc(sizeof(S3RequestContext)); if (!*requestContextReturn) { return S3StatusOutOfMemory; } if (!((*requestContextReturn)->curlm = curl_multi_init())) { free(*requestContextReturn); return S3StatusOutOfMemory; } (*requestContextReturn)->requests = 0; return S3StatusOK; } void S3_destroy_request_context(S3RequestContext *requestContext) { curl_multi_cleanup(requestContext->curlm); // For each request in the context, call back its done method with // 'interrupted' status Request *r = requestContext->requests, *rFirst = r; if (r) do { r->status = S3StatusInterrupted; Request *rNext = r->next; request_finish(r); r = rNext; } while (r != rFirst); free(requestContext); } S3Status S3_runall_request_context(S3RequestContext *requestContext) { int requestsRemaining; do { fd_set readfds, writefds, exceptfds; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); int maxfd; S3Status status = S3_get_request_context_fdsets (requestContext, &readfds, &writefds, &exceptfds, &maxfd); if (status != S3StatusOK) { return status; } // curl will return -1 if it hasn't even created any fds yet because // none of the connections have started yet. In this case, don't // do the select at all, because it will wait forever; instead, just // skip it and go straight to running the underlying CURL handles if (maxfd != -1) { int64_t timeout = S3_get_request_context_timeout(requestContext); struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; select(maxfd + 1, &readfds, &writefds, &exceptfds, (timeout == -1) ? 0 : &tv); } status = S3_runonce_request_context(requestContext, &requestsRemaining); if (status != S3StatusOK) { return status; } } while (requestsRemaining); return S3StatusOK; } S3Status S3_runonce_request_context(S3RequestContext *requestContext, int *requestsRemainingReturn) { CURLMcode status; do { status = curl_multi_perform(requestContext->curlm, requestsRemainingReturn); switch (status) { case CURLM_OK: case CURLM_CALL_MULTI_PERFORM: break; case CURLM_OUT_OF_MEMORY: return S3StatusOutOfMemory; default: return S3StatusInternalError; } CURLMsg *msg; int junk; while ((msg = curl_multi_info_read(requestContext->curlm, &junk))) { if (msg->msg != CURLMSG_DONE) { return S3StatusInternalError; } Request *request; if (curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **) (char *) &request) != CURLE_OK) { return S3StatusInternalError; } // Remove the request from the list of requests if (request->prev == request->next) { // It was the only one on the list requestContext->requests = 0; } else { // It doesn't matter what the order of them are, so just in // case request was at the head of the list, put the one after // request to the head of the list requestContext->requests = request->next; request->prev->next = request->next; request->next->prev = request->prev; } if ((msg->data.result != CURLE_OK) && (request->status == S3StatusOK)) { request->status = request_curl_code_to_status (msg->data.result); } if (curl_multi_remove_handle(requestContext->curlm, msg->easy_handle) != CURLM_OK) { return S3StatusInternalError; } // Finish the request, ensuring that all callbacks have been made, // and also releases the request request_finish(request); // Now, since a callback was made, there may be new requests // queued up to be performed immediately, so do so status = CURLM_CALL_MULTI_PERFORM; } } while (status == CURLM_CALL_MULTI_PERFORM); return S3StatusOK; } S3Status S3_get_request_context_fdsets(S3RequestContext *requestContext, fd_set *readFdSet, fd_set *writeFdSet, fd_set *exceptFdSet, int *maxFd) { return ((curl_multi_fdset(requestContext->curlm, readFdSet, writeFdSet, exceptFdSet, maxFd) == CURLM_OK) ? S3StatusOK : S3StatusInternalError); } int64_t S3_get_request_context_timeout(S3RequestContext *requestContext) { long timeout; if (curl_multi_timeout(requestContext->curlm, &timeout) != CURLM_OK) { timeout = 0; } return timeout; } ceph-0.80.11/src/libs3/src/service.c0000664000175100017510000001572412623076753021104 0ustar jenkins-buildjenkins-build/** ************************************************************************** * service.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include #include #include "request.h" typedef struct XmlCallbackData { SimpleXml simpleXml; S3ResponsePropertiesCallback *responsePropertiesCallback; S3ListServiceCallback *listServiceCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; string_buffer(ownerId, 256); string_buffer(ownerDisplayName, 256); string_buffer(bucketName, 256); string_buffer(creationDate, 128); } XmlCallbackData; static S3Status xmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { XmlCallbackData *cbData = (XmlCallbackData *) callbackData; int fit; if (data) { if (!strcmp(elementPath, "ListAllMyBucketsResult/Owner/ID")) { string_buffer_append(cbData->ownerId, data, dataLen, fit); } else if (!strcmp(elementPath, "ListAllMyBucketsResult/Owner/DisplayName")) { string_buffer_append(cbData->ownerDisplayName, data, dataLen, fit); } else if (!strcmp(elementPath, "ListAllMyBucketsResult/Buckets/Bucket/Name")) { string_buffer_append(cbData->bucketName, data, dataLen, fit); } else if (!strcmp (elementPath, "ListAllMyBucketsResult/Buckets/Bucket/CreationDate")) { string_buffer_append(cbData->creationDate, data, dataLen, fit); } } else { if (!strcmp(elementPath, "ListAllMyBucketsResult/Buckets/Bucket")) { // Parse date. Assume ISO-8601 date format. time_t creationDate = parseIso8601Time(cbData->creationDate); // Make the callback - a bucket just finished S3Status status = (*(cbData->listServiceCallback)) (cbData->ownerId, cbData->ownerDisplayName, cbData->bucketName, creationDate, cbData->callbackData); string_buffer_initialize(cbData->bucketName); string_buffer_initialize(cbData->creationDate); return status; } } /* Avoid compiler error about variable set but not used */ (void) fit; return S3StatusOK; } static S3Status propertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { XmlCallbackData *cbData = (XmlCallbackData *) callbackData; return (*(cbData->responsePropertiesCallback)) (responseProperties, cbData->callbackData); } static S3Status dataCallback(int bufferSize, const char *buffer, void *callbackData) { XmlCallbackData *cbData = (XmlCallbackData *) callbackData; return simplexml_add(&(cbData->simpleXml), buffer, bufferSize); } static void completeCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { XmlCallbackData *cbData = (XmlCallbackData *) callbackData; (*(cbData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, cbData->callbackData); simplexml_deinitialize(&(cbData->simpleXml)); free(cbData); } void S3_list_service(S3Protocol protocol, const char *accessKeyId, const char *secretAccessKey, const char *hostName, S3RequestContext *requestContext, const S3ListServiceHandler *handler, void *callbackData) { // Create and set up the callback data XmlCallbackData *data = (XmlCallbackData *) malloc(sizeof(XmlCallbackData)); if (!data) { (*(handler->responseHandler.completeCallback)) (S3StatusOutOfMemory, 0, callbackData); return; } simplexml_initialize(&(data->simpleXml), &xmlCallback, data); data->responsePropertiesCallback = handler->responseHandler.propertiesCallback; data->listServiceCallback = handler->listServiceCallback; data->responseCompleteCallback = handler->responseHandler.completeCallback; data->callbackData = callbackData; string_buffer_initialize(data->ownerId); string_buffer_initialize(data->ownerDisplayName); string_buffer_initialize(data->bucketName); string_buffer_initialize(data->creationDate); // Set up the RequestParams RequestParams params = { HttpRequestTypeGET, // httpRequestType { hostName, // hostName 0, // bucketName protocol, // protocol S3UriStylePath, // uriStyle accessKeyId, // accessKeyId secretAccessKey }, // secretAccessKey 0, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // requestProperties &propertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize &dataCallback, // fromS3Callback &completeCallback, // completeCallback data // callbackData }; // Perform the request request_perform(¶ms, requestContext); } ceph-0.80.11/src/libs3/src/bucket.c0000664000175100017510000007117012623076753020716 0ustar jenkins-buildjenkins-build/** ************************************************************************** * bucket.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "libs3.h" #include "request.h" #include "simplexml.h" // test bucket --------------------------------------------------------------- typedef struct TestBucketData { SimpleXml simpleXml; S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; int locationConstraintReturnSize; char *locationConstraintReturn; string_buffer(locationConstraint, 256); } TestBucketData; static S3Status testBucketXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { TestBucketData *tbData = (TestBucketData *) callbackData; int fit; if (data && !strcmp(elementPath, "LocationConstraint")) { string_buffer_append(tbData->locationConstraint, data, dataLen, fit); } /* Avoid compiler error about variable set but not used */ (void) fit; return S3StatusOK; } static S3Status testBucketPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { TestBucketData *tbData = (TestBucketData *) callbackData; return (*(tbData->responsePropertiesCallback)) (responseProperties, tbData->callbackData); } static S3Status testBucketDataCallback(int bufferSize, const char *buffer, void *callbackData) { TestBucketData *tbData = (TestBucketData *) callbackData; return simplexml_add(&(tbData->simpleXml), buffer, bufferSize); } static void testBucketCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { TestBucketData *tbData = (TestBucketData *) callbackData; // Copy the location constraint into the return buffer snprintf(tbData->locationConstraintReturn, tbData->locationConstraintReturnSize, "%s", tbData->locationConstraint); (*(tbData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, tbData->callbackData); simplexml_deinitialize(&(tbData->simpleXml)); free(tbData); } void S3_test_bucket(S3Protocol protocol, S3UriStyle uriStyle, const char *accessKeyId, const char *secretAccessKey, const char *hostName, const char *bucketName, int locationConstraintReturnSize, char *locationConstraintReturn, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Create the callback data TestBucketData *tbData = (TestBucketData *) malloc(sizeof(TestBucketData)); if (!tbData) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } simplexml_initialize(&(tbData->simpleXml), &testBucketXmlCallback, tbData); tbData->responsePropertiesCallback = handler->propertiesCallback; tbData->responseCompleteCallback = handler->completeCallback; tbData->callbackData = callbackData; tbData->locationConstraintReturnSize = locationConstraintReturnSize; tbData->locationConstraintReturn = locationConstraintReturn; string_buffer_initialize(tbData->locationConstraint); // Set up the RequestParams RequestParams params = { HttpRequestTypeGET, // httpRequestType { hostName, // hostName bucketName, // bucketName protocol, // protocol uriStyle, // uriStyle accessKeyId, // accessKeyId secretAccessKey }, // secretAccessKey 0, // key 0, // queryParams "location", // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &testBucketPropertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize &testBucketDataCallback, // fromS3Callback &testBucketCompleteCallback, // completeCallback tbData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // create bucket ------------------------------------------------------------- typedef struct CreateBucketData { S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; char doc[1024]; int docLen, docBytesWritten; } CreateBucketData; static S3Status createBucketPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { CreateBucketData *cbData = (CreateBucketData *) callbackData; return (*(cbData->responsePropertiesCallback)) (responseProperties, cbData->callbackData); } static int createBucketDataCallback(int bufferSize, char *buffer, void *callbackData) { CreateBucketData *cbData = (CreateBucketData *) callbackData; if (!cbData->docLen) { return 0; } int remaining = (cbData->docLen - cbData->docBytesWritten); int toCopy = bufferSize > remaining ? remaining : bufferSize; if (!toCopy) { return 0; } memcpy(buffer, &(cbData->doc[cbData->docBytesWritten]), toCopy); cbData->docBytesWritten += toCopy; return toCopy; } static void createBucketCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { CreateBucketData *cbData = (CreateBucketData *) callbackData; (*(cbData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, cbData->callbackData); free(cbData); } void S3_create_bucket(S3Protocol protocol, const char *accessKeyId, const char *secretAccessKey, const char *hostName, const char *bucketName, S3CannedAcl cannedAcl, const char *locationConstraint, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Create the callback data CreateBucketData *cbData = (CreateBucketData *) malloc(sizeof(CreateBucketData)); if (!cbData) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } cbData->responsePropertiesCallback = handler->propertiesCallback; cbData->responseCompleteCallback = handler->completeCallback; cbData->callbackData = callbackData; if (locationConstraint) { cbData->docLen = snprintf(cbData->doc, sizeof(cbData->doc), "" "%s", locationConstraint); cbData->docBytesWritten = 0; } else { cbData->docLen = 0; } // Set up S3PutProperties S3PutProperties properties = { 0, // contentType 0, // md5 0, // cacheControl 0, // contentDispositionFilename 0, // contentEncoding 0, // expires cannedAcl, // cannedAcl 0, // metaDataCount 0 // metaData }; // Set up the RequestParams RequestParams params = { HttpRequestTypePUT, // httpRequestType { hostName, // hostName bucketName, // bucketName protocol, // protocol S3UriStylePath, // uriStyle accessKeyId, // accessKeyId secretAccessKey }, // secretAccessKey 0, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount &properties, // putProperties &createBucketPropertiesCallback, // propertiesCallback &createBucketDataCallback, // toS3Callback cbData->docLen, // toS3CallbackTotalSize 0, // fromS3Callback &createBucketCompleteCallback, // completeCallback cbData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // delete bucket ------------------------------------------------------------- typedef struct DeleteBucketData { S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; } DeleteBucketData; static S3Status deleteBucketPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { DeleteBucketData *dbData = (DeleteBucketData *) callbackData; return (*(dbData->responsePropertiesCallback)) (responseProperties, dbData->callbackData); } static void deleteBucketCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { DeleteBucketData *dbData = (DeleteBucketData *) callbackData; (*(dbData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, dbData->callbackData); free(dbData); } void S3_delete_bucket(S3Protocol protocol, S3UriStyle uriStyle, const char *accessKeyId, const char *secretAccessKey, const char *hostName, const char *bucketName, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Create the callback data DeleteBucketData *dbData = (DeleteBucketData *) malloc(sizeof(DeleteBucketData)); if (!dbData) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } dbData->responsePropertiesCallback = handler->propertiesCallback; dbData->responseCompleteCallback = handler->completeCallback; dbData->callbackData = callbackData; // Set up the RequestParams RequestParams params = { HttpRequestTypeDELETE, // httpRequestType { hostName, // hostName bucketName, // bucketName protocol, // protocol uriStyle, // uriStyle accessKeyId, // accessKeyId secretAccessKey }, // secretAccessKey 0, // key 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &deleteBucketPropertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize 0, // fromS3Callback &deleteBucketCompleteCallback, // completeCallback dbData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // list bucket ---------------------------------------------------------------- typedef struct ListBucketContents { string_buffer(key, 1024); string_buffer(lastModified, 256); string_buffer(eTag, 256); string_buffer(size, 24); string_buffer(ownerId, 256); string_buffer(ownerDisplayName, 256); } ListBucketContents; static void initialize_list_bucket_contents(ListBucketContents *contents) { string_buffer_initialize(contents->key); string_buffer_initialize(contents->lastModified); string_buffer_initialize(contents->eTag); string_buffer_initialize(contents->size); string_buffer_initialize(contents->ownerId); string_buffer_initialize(contents->ownerDisplayName); } // We read up to 32 Contents at a time #define MAX_CONTENTS 32 // We read up to 8 CommonPrefixes at a time #define MAX_COMMON_PREFIXES 8 typedef struct ListBucketData { SimpleXml simpleXml; S3ResponsePropertiesCallback *responsePropertiesCallback; S3ListBucketCallback *listBucketCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; string_buffer(isTruncated, 64); string_buffer(nextMarker, 1024); int contentsCount; ListBucketContents contents[MAX_CONTENTS]; int commonPrefixesCount; char commonPrefixes[MAX_COMMON_PREFIXES][1024]; int commonPrefixLens[MAX_COMMON_PREFIXES]; } ListBucketData; static void initialize_list_bucket_data(ListBucketData *lbData) { lbData->contentsCount = 0; initialize_list_bucket_contents(lbData->contents); lbData->commonPrefixesCount = 0; lbData->commonPrefixes[0][0] = 0; lbData->commonPrefixLens[0] = 0; } static S3Status make_list_bucket_callback(ListBucketData *lbData) { int i; // Convert IsTruncated int isTruncated = (!strcmp(lbData->isTruncated, "true") || !strcmp(lbData->isTruncated, "1")) ? 1 : 0; // Convert the contents S3ListBucketContent contents[lbData->contentsCount]; int contentsCount = lbData->contentsCount; for (i = 0; i < contentsCount; i++) { S3ListBucketContent *contentDest = &(contents[i]); ListBucketContents *contentSrc = &(lbData->contents[i]); contentDest->key = contentSrc->key; contentDest->lastModified = parseIso8601Time(contentSrc->lastModified); contentDest->eTag = contentSrc->eTag; contentDest->size = parseUnsignedInt(contentSrc->size); contentDest->ownerId = contentSrc->ownerId[0] ?contentSrc->ownerId : 0; contentDest->ownerDisplayName = (contentSrc->ownerDisplayName[0] ? contentSrc->ownerDisplayName : 0); } // Make the common prefixes array int commonPrefixesCount = lbData->commonPrefixesCount; char *commonPrefixes[commonPrefixesCount]; for (i = 0; i < commonPrefixesCount; i++) { commonPrefixes[i] = lbData->commonPrefixes[i]; } return (*(lbData->listBucketCallback)) (isTruncated, lbData->nextMarker, contentsCount, contents, commonPrefixesCount, (const char **) commonPrefixes, lbData->callbackData); } static S3Status listBucketXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { ListBucketData *lbData = (ListBucketData *) callbackData; int fit; if (data) { if (!strcmp(elementPath, "ListBucketResult/IsTruncated")) { string_buffer_append(lbData->isTruncated, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/NextMarker")) { string_buffer_append(lbData->nextMarker, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/Contents/Key")) { ListBucketContents *contents = &(lbData->contents[lbData->contentsCount]); string_buffer_append(contents->key, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/Contents/LastModified")) { ListBucketContents *contents = &(lbData->contents[lbData->contentsCount]); string_buffer_append(contents->lastModified, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/Contents/ETag")) { ListBucketContents *contents = &(lbData->contents[lbData->contentsCount]); string_buffer_append(contents->eTag, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/Contents/Size")) { ListBucketContents *contents = &(lbData->contents[lbData->contentsCount]); string_buffer_append(contents->size, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/Contents/Owner/ID")) { ListBucketContents *contents = &(lbData->contents[lbData->contentsCount]); string_buffer_append(contents->ownerId, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/Contents/Owner/DisplayName")) { ListBucketContents *contents = &(lbData->contents[lbData->contentsCount]); string_buffer_append (contents->ownerDisplayName, data, dataLen, fit); } else if (!strcmp(elementPath, "ListBucketResult/CommonPrefixes/Prefix")) { int which = lbData->commonPrefixesCount; lbData->commonPrefixLens[which] += snprintf(lbData->commonPrefixes[which], sizeof(lbData->commonPrefixes[which]) - lbData->commonPrefixLens[which] - 1, "%.*s", dataLen, data); if (lbData->commonPrefixLens[which] >= (int) sizeof(lbData->commonPrefixes[which])) { return S3StatusXmlParseFailure; } } } else { if (!strcmp(elementPath, "ListBucketResult/Contents")) { // Finished a Contents lbData->contentsCount++; if (lbData->contentsCount == MAX_CONTENTS) { // Make the callback S3Status status = make_list_bucket_callback(lbData); if (status != S3StatusOK) { return status; } initialize_list_bucket_data(lbData); } else { // Initialize the next one initialize_list_bucket_contents (&(lbData->contents[lbData->contentsCount])); } } else if (!strcmp(elementPath, "ListBucketResult/CommonPrefixes/Prefix")) { // Finished a Prefix lbData->commonPrefixesCount++; if (lbData->commonPrefixesCount == MAX_COMMON_PREFIXES) { // Make the callback S3Status status = make_list_bucket_callback(lbData); if (status != S3StatusOK) { return status; } initialize_list_bucket_data(lbData); } else { // Initialize the next one lbData->commonPrefixes[lbData->commonPrefixesCount][0] = 0; lbData->commonPrefixLens[lbData->commonPrefixesCount] = 0; } } } /* Avoid compiler error about variable set but not used */ (void) fit; return S3StatusOK; } static S3Status listBucketPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { ListBucketData *lbData = (ListBucketData *) callbackData; return (*(lbData->responsePropertiesCallback)) (responseProperties, lbData->callbackData); } static S3Status listBucketDataCallback(int bufferSize, const char *buffer, void *callbackData) { ListBucketData *lbData = (ListBucketData *) callbackData; return simplexml_add(&(lbData->simpleXml), buffer, bufferSize); } static void listBucketCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { ListBucketData *lbData = (ListBucketData *) callbackData; // Make the callback if there is anything if (lbData->contentsCount || lbData->commonPrefixesCount) { make_list_bucket_callback(lbData); } (*(lbData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, lbData->callbackData); simplexml_deinitialize(&(lbData->simpleXml)); free(lbData); } void S3_list_bucket(const S3BucketContext *bucketContext, const char *prefix, const char *marker, const char *delimiter, int maxkeys, S3RequestContext *requestContext, const S3ListBucketHandler *handler, void *callbackData) { // Compose the query params string_buffer(queryParams, 4096); string_buffer_initialize(queryParams); #define safe_append(name, value) \ do { \ int fit; \ if (amp) { \ string_buffer_append(queryParams, "&", 1, fit); \ if (!fit) { \ (*(handler->responseHandler.completeCallback)) \ (S3StatusQueryParamsTooLong, 0, callbackData); \ return; \ } \ } \ string_buffer_append(queryParams, name "=", \ sizeof(name "=") - 1, fit); \ if (!fit) { \ (*(handler->responseHandler.completeCallback)) \ (S3StatusQueryParamsTooLong, 0, callbackData); \ return; \ } \ amp = 1; \ char encoded[3 * 1024]; \ if (!urlEncode(encoded, value, 1024)) { \ (*(handler->responseHandler.completeCallback)) \ (S3StatusQueryParamsTooLong, 0, callbackData); \ return; \ } \ string_buffer_append(queryParams, encoded, strlen(encoded), \ fit); \ if (!fit) { \ (*(handler->responseHandler.completeCallback)) \ (S3StatusQueryParamsTooLong, 0, callbackData); \ return; \ } \ } while (0) int amp = 0; if (prefix) { safe_append("prefix", prefix); } if (marker) { safe_append("marker", marker); } if (delimiter) { safe_append("delimiter", delimiter); } if (maxkeys) { char maxKeysString[64]; snprintf(maxKeysString, sizeof(maxKeysString), "%d", maxkeys); safe_append("max-keys", maxKeysString); } ListBucketData *lbData = (ListBucketData *) malloc(sizeof(ListBucketData)); if (!lbData) { (*(handler->responseHandler.completeCallback)) (S3StatusOutOfMemory, 0, callbackData); return; } simplexml_initialize(&(lbData->simpleXml), &listBucketXmlCallback, lbData); lbData->responsePropertiesCallback = handler->responseHandler.propertiesCallback; lbData->listBucketCallback = handler->listBucketCallback; lbData->responseCompleteCallback = handler->responseHandler.completeCallback; lbData->callbackData = callbackData; string_buffer_initialize(lbData->isTruncated); string_buffer_initialize(lbData->nextMarker); initialize_list_bucket_data(lbData); // Set up the RequestParams RequestParams params = { HttpRequestTypeGET, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey 0, // key queryParams[0] ? queryParams : 0, // queryParams 0, // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &listBucketPropertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize &listBucketDataCallback, // fromS3Callback &listBucketCompleteCallback, // completeCallback lbData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } ceph-0.80.11/src/libs3/src/acl.c0000664000175100017510000003162412623076753020200 0ustar jenkins-buildjenkins-build/** ************************************************************************** * acl.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "libs3.h" #include "request.h" // Use a rather arbitrary max size for the document of 64K #define ACL_XML_DOC_MAXSIZE (64 * 1024) // get acl ------------------------------------------------------------------- typedef struct GetAclData { SimpleXml simpleXml; S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; int *aclGrantCountReturn; S3AclGrant *aclGrants; char *ownerId; char *ownerDisplayName; string_buffer(aclXmlDocument, ACL_XML_DOC_MAXSIZE); } GetAclData; static S3Status getAclPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { GetAclData *gaData = (GetAclData *) callbackData; return (*(gaData->responsePropertiesCallback)) (responseProperties, gaData->callbackData); } static S3Status getAclDataCallback(int bufferSize, const char *buffer, void *callbackData) { GetAclData *gaData = (GetAclData *) callbackData; int fit; string_buffer_append(gaData->aclXmlDocument, buffer, bufferSize, fit); return fit ? S3StatusOK : S3StatusXmlDocumentTooLarge; } static void getAclCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { GetAclData *gaData = (GetAclData *) callbackData; if (requestStatus == S3StatusOK) { // Parse the document requestStatus = S3_convert_acl (gaData->aclXmlDocument, gaData->ownerId, gaData->ownerDisplayName, gaData->aclGrantCountReturn, gaData->aclGrants); } (*(gaData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, gaData->callbackData); free(gaData); } void S3_get_acl(const S3BucketContext *bucketContext, const char *key, char *ownerId, char *ownerDisplayName, int *aclGrantCountReturn, S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { // Create the callback data GetAclData *gaData = (GetAclData *) malloc(sizeof(GetAclData)); if (!gaData) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } gaData->responsePropertiesCallback = handler->propertiesCallback; gaData->responseCompleteCallback = handler->completeCallback; gaData->callbackData = callbackData; gaData->aclGrantCountReturn = aclGrantCountReturn; gaData->aclGrants = aclGrants; gaData->ownerId = ownerId; gaData->ownerDisplayName = ownerDisplayName; string_buffer_initialize(gaData->aclXmlDocument); *aclGrantCountReturn = 0; // Set up the RequestParams RequestParams params = { HttpRequestTypeGET, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey key, // key 0, // queryParams "acl", // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &getAclPropertiesCallback, // propertiesCallback 0, // toS3Callback 0, // toS3CallbackTotalSize &getAclDataCallback, // fromS3Callback &getAclCompleteCallback, // completeCallback gaData // callbackData }; // Perform the request request_perform(¶ms, requestContext); } // set acl ------------------------------------------------------------------- static S3Status generateAclXmlDocument(const char *ownerId, const char *ownerDisplayName, int aclGrantCount, const S3AclGrant *aclGrants, int *xmlDocumentLenReturn, char *xmlDocument, int xmlDocumentBufferSize) { *xmlDocumentLenReturn = 0; #define append(fmt, ...) \ do { \ *xmlDocumentLenReturn += snprintf \ (&(xmlDocument[*xmlDocumentLenReturn]), \ xmlDocumentBufferSize - *xmlDocumentLenReturn - 1, \ fmt, __VA_ARGS__); \ if (*xmlDocumentLenReturn >= xmlDocumentBufferSize) { \ return S3StatusXmlDocumentTooLarge; \ } \ } while (0) append("%s%s" "", ownerId, ownerDisplayName); int i; for (i = 0; i < aclGrantCount; i++) { append("%s", "granteeType) { case S3GranteeTypeAmazonCustomerByEmail: append("AmazonCustomerByEmail\">%s", grant->grantee.amazonCustomerByEmail.emailAddress); break; case S3GranteeTypeCanonicalUser: append("CanonicalUser\">%s%s", grant->grantee.canonicalUser.id, grant->grantee.canonicalUser.displayName); break; default: { // case S3GranteeTypeAllAwsUsers/S3GranteeTypeAllUsers: const char *grantee; switch (grant->granteeType) { case S3GranteeTypeAllAwsUsers: grantee = ACS_GROUP_AWS_USERS; break; case S3GranteeTypeAllUsers: grantee = ACS_GROUP_ALL_USERS; break; default: grantee = ACS_GROUP_LOG_DELIVERY; break; } append("Group\">%s", grantee); } break; } append("%s", ((grant->permission == S3PermissionRead) ? "READ" : (grant->permission == S3PermissionWrite) ? "WRITE" : (grant->permission == S3PermissionReadACP) ? "READ_ACP" : (grant->permission == S3PermissionWriteACP) ? "WRITE_ACP" : "FULL_CONTROL")); } append("%s", ""); return S3StatusOK; } typedef struct SetAclData { S3ResponsePropertiesCallback *responsePropertiesCallback; S3ResponseCompleteCallback *responseCompleteCallback; void *callbackData; int aclXmlDocumentLen; char aclXmlDocument[ACL_XML_DOC_MAXSIZE]; int aclXmlDocumentBytesWritten; } SetAclData; static S3Status setAclPropertiesCallback (const S3ResponseProperties *responseProperties, void *callbackData) { SetAclData *paData = (SetAclData *) callbackData; return (*(paData->responsePropertiesCallback)) (responseProperties, paData->callbackData); } static int setAclDataCallback(int bufferSize, char *buffer, void *callbackData) { SetAclData *paData = (SetAclData *) callbackData; int remaining = (paData->aclXmlDocumentLen - paData->aclXmlDocumentBytesWritten); int toCopy = bufferSize > remaining ? remaining : bufferSize; if (!toCopy) { return 0; } memcpy(buffer, &(paData->aclXmlDocument [paData->aclXmlDocumentBytesWritten]), toCopy); paData->aclXmlDocumentBytesWritten += toCopy; return toCopy; } static void setAclCompleteCallback(S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails, void *callbackData) { SetAclData *paData = (SetAclData *) callbackData; (*(paData->responseCompleteCallback)) (requestStatus, s3ErrorDetails, paData->callbackData); free(paData); } void S3_set_acl(const S3BucketContext *bucketContext, const char *key, const char *ownerId, const char *ownerDisplayName, int aclGrantCount, const S3AclGrant *aclGrants, S3RequestContext *requestContext, const S3ResponseHandler *handler, void *callbackData) { if (aclGrantCount > S3_MAX_ACL_GRANT_COUNT) { (*(handler->completeCallback)) (S3StatusTooManyGrants, 0, callbackData); return; } SetAclData *data = (SetAclData *) malloc(sizeof(SetAclData)); if (!data) { (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); return; } // Convert aclGrants to XML document S3Status status = generateAclXmlDocument (ownerId, ownerDisplayName, aclGrantCount, aclGrants, &(data->aclXmlDocumentLen), data->aclXmlDocument, sizeof(data->aclXmlDocument)); if (status != S3StatusOK) { free(data); (*(handler->completeCallback))(status, 0, callbackData); return; } data->responsePropertiesCallback = handler->propertiesCallback; data->responseCompleteCallback = handler->completeCallback; data->callbackData = callbackData; data->aclXmlDocumentBytesWritten = 0; // Set up the RequestParams RequestParams params = { HttpRequestTypePUT, // httpRequestType { bucketContext->hostName, // hostName bucketContext->bucketName, // bucketName bucketContext->protocol, // protocol bucketContext->uriStyle, // uriStyle bucketContext->accessKeyId, // accessKeyId bucketContext->secretAccessKey }, // secretAccessKey key, // key 0, // queryParams "acl", // subResource 0, // copySourceBucketName 0, // copySourceKey 0, // getConditions 0, // startByte 0, // byteCount 0, // putProperties &setAclPropertiesCallback, // propertiesCallback &setAclDataCallback, // toS3Callback data->aclXmlDocumentLen, // toS3CallbackTotalSize 0, // fromS3Callback &setAclCompleteCallback, // completeCallback data // callbackData }; // Perform the request request_perform(¶ms, requestContext); } ceph-0.80.11/src/libs3/src/simplexml.c0000664000175100017510000001432312623076753021450 0ustar jenkins-buildjenkins-build/** ************************************************************************** * simplexml.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "simplexml.h" // Use libxml2 for parsing XML. XML is severely overused in modern // computing. It is useful for only a very small subset of tasks, but // software developers who don't know better and are afraid to go against the // grain use it for everything, and in most cases, it is completely // inappropriate. Usually, the document structure is severely under-specified // as well, as is the case with S3. We do our best by just caring about the // most important aspects of the S3 "XML document" responses: the elements and // their values. The SAX API (just about the lamest API ever devised and // proof that XML sucks - well, the real proof is how crappy all of the XML // parsing libraries are, including libxml2 - but I digress) is used here // because we don't need much from the parser and SAX is fast and low memory. // // Note that for simplicity we assume all ASCII here. No attempts are made to // detect non-ASCII sequences in utf-8 and convert them into ASCII in any way. // S3 appears to only use ASCII anyway. static xmlEntityPtr saxGetEntity(void *user_data, const xmlChar *name) { (void) user_data; return xmlGetPredefinedEntity(name); } static void saxStartElement(void *user_data, const xmlChar *nameUtf8, const xmlChar **attr) { (void) attr; SimpleXml *simpleXml = (SimpleXml *) user_data; if (simpleXml->status != S3StatusOK) { return; } // Assume that name has no non-ASCII in it char *name = (char *) nameUtf8; // Append the element to the element path int len = strlen(name); if ((simpleXml->elementPathLen + len + 1) >= (int) sizeof(simpleXml->elementPath)) { // Cannot handle this element, stop! simpleXml->status = S3StatusXmlParseFailure; return; } if (simpleXml->elementPathLen) { simpleXml->elementPath[simpleXml->elementPathLen++] = '/'; } strcpy(&(simpleXml->elementPath[simpleXml->elementPathLen]), name); simpleXml->elementPathLen += len; } static void saxEndElement(void *user_data, const xmlChar *name) { (void) name; SimpleXml *simpleXml = (SimpleXml *) user_data; if (simpleXml->status != S3StatusOK) { return; } // Call back with 0 data simpleXml->status = (*(simpleXml->callback)) (simpleXml->elementPath, 0, 0, simpleXml->callbackData); while ((simpleXml->elementPathLen > 0) && (simpleXml->elementPath[simpleXml->elementPathLen] != '/')) { simpleXml->elementPathLen--; } simpleXml->elementPath[simpleXml->elementPathLen] = 0; } static void saxCharacters(void *user_data, const xmlChar *ch, int len) { SimpleXml *simpleXml = (SimpleXml *) user_data; if (simpleXml->status != S3StatusOK) { return; } simpleXml->status = (*(simpleXml->callback)) (simpleXml->elementPath, (char *) ch, len, simpleXml->callbackData); } static void saxError(void *user_data, const char *msg, ...) { (void) msg; SimpleXml *simpleXml = (SimpleXml *) user_data; if (simpleXml->status != S3StatusOK) { return; } simpleXml->status = S3StatusXmlParseFailure; } static struct _xmlSAXHandler saxHandlerG = { 0, // internalSubsetSAXFunc 0, // isStandaloneSAXFunc 0, // hasInternalSubsetSAXFunc 0, // hasExternalSubsetSAXFunc 0, // resolveEntitySAXFunc &saxGetEntity, // getEntitySAXFunc 0, // entityDeclSAXFunc 0, // notationDeclSAXFunc 0, // attributeDeclSAXFunc 0, // elementDeclSAXFunc 0, // unparsedEntityDeclSAXFunc 0, // setDocumentLocatorSAXFunc 0, // startDocumentSAXFunc 0, // endDocumentSAXFunc &saxStartElement, // startElementSAXFunc &saxEndElement, // endElementSAXFunc 0, // referenceSAXFunc &saxCharacters, // charactersSAXFunc 0, // ignorableWhitespaceSAXFunc 0, // processingInstructionSAXFunc 0, // commentSAXFunc 0, // warningSAXFunc &saxError, // errorSAXFunc &saxError, // fatalErrorSAXFunc 0, // getParameterEntitySAXFunc &saxCharacters, // cdataBlockSAXFunc 0, // externalSubsetSAXFunc 0, // initialized 0, // _private 0, // startElementNsSAX2Func 0, // endElementNsSAX2Func 0 // xmlStructuredErrorFunc serror; }; void simplexml_initialize(SimpleXml *simpleXml, SimpleXmlCallback *callback, void *callbackData) { simpleXml->callback = callback; simpleXml->callbackData = callbackData; simpleXml->elementPathLen = 0; simpleXml->status = S3StatusOK; simpleXml->xmlParser = 0; } void simplexml_deinitialize(SimpleXml *simpleXml) { if (simpleXml->xmlParser) { xmlFreeParserCtxt(simpleXml->xmlParser); } } S3Status simplexml_add(SimpleXml *simpleXml, const char *data, int dataLen) { if (!simpleXml->xmlParser && (!(simpleXml->xmlParser = xmlCreatePushParserCtxt (&saxHandlerG, simpleXml, 0, 0, 0)))) { return S3StatusInternalError; } if (xmlParseChunk((xmlParserCtxtPtr) simpleXml->xmlParser, data, dataLen, 0)) { return S3StatusXmlParseFailure; } return simpleXml->status; } ceph-0.80.11/src/libs3/src/testsimplexml.c0000664000175100017510000000504412623076753022350 0ustar jenkins-buildjenkins-build/** ************************************************************************** * testsimplexml.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include #include #include "simplexml.h" static S3Status simpleXmlCallback(const char *elementPath, const char *data, int dataLen, void *callbackData) { (void) callbackData; printf("[%s]: [%.*s]\n", elementPath, dataLen, data); return S3StatusOK; } // The only argument allowed is a specification of the random seed to use int main(int argc, char **argv) { if (argc > 1) { char *arg = argv[1]; int seed = 0; while (*arg) { seed *= 10; seed += (*arg++ - '0'); } srand(seed); } else { srand(time(0)); } SimpleXml simpleXml; simplexml_initialize(&simpleXml, &simpleXmlCallback, 0); // Read chunks of 10K from stdin, and then feed them in random chunks // to simplexml_add char inbuf[10000]; int amt_read; while ((amt_read = fread(inbuf, 1, sizeof(inbuf), stdin)) > 0) { char *buf = inbuf; while (amt_read) { int amt = (rand() % amt_read) + 1; S3Status status = simplexml_add(&simpleXml, buf, amt); if (status != S3StatusOK) { fprintf(stderr, "ERROR: Parse failure: %d\n", status); simplexml_deinitialize(&simpleXml); return -1; } buf += amt, amt_read -= amt; } } simplexml_deinitialize(&simpleXml); return 0; } ceph-0.80.11/src/libs3/src/response_headers_handler.c0000664000175100017510000001612112623076753024462 0ustar jenkins-buildjenkins-build/** ************************************************************************** * response_headers_handler.c * * Copyright 2008 Bryan Ischo * * This file is part of libs3. * * libs3 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 3 of the License. * * In addition, as a special exception, the copyright holders give * permission to link the code of this library and its programs with the * OpenSSL library, and distribute linked combinations including the two. * * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License version 3 * along with libs3, in a file named COPYING. If not, see * . * ************************************************************************** **/ #include #include #include "response_headers_handler.h" void response_headers_handler_initialize(ResponseHeadersHandler *handler) { handler->responseProperties.requestId = 0; handler->responseProperties.requestId2 = 0; handler->responseProperties.contentType = 0; handler->responseProperties.contentLength = 0; handler->responseProperties.server = 0; handler->responseProperties.eTag = 0; handler->responseProperties.lastModified = -1; handler->responseProperties.metaDataCount = 0; handler->responseProperties.metaData = 0; handler->done = 0; string_multibuffer_initialize(handler->responsePropertyStrings); string_multibuffer_initialize(handler->responseMetaDataStrings); } void response_headers_handler_add(ResponseHeadersHandler *handler, char *header, int len) { S3ResponseProperties *responseProperties = &(handler->responseProperties); char *end = &(header[len]); // Curl might call back the header function after the body has been // received, for 'chunked encoded' contents. We don't handle this as of // yet, and it's not clear that it would ever be useful. if (handler->done) { return; } // If we've already filled up the response headers, ignore this data. // This sucks, but it shouldn't happen - S3 should not be sending back // really long headers. if (handler->responsePropertyStringsSize == (sizeof(handler->responsePropertyStrings) - 1)) { return; } // It should not be possible to have a header line less than 3 long if (len < 3) { return; } // Skip whitespace at beginning of header; there never should be any, // but just to be safe while (is_blank(*header)) { header++; } // The header must end in \r\n, so skip back over it, and also over any // trailing whitespace end -= 3; while ((end > header) && is_blank(*end)) { end--; } if (!is_blank(*end)) { end++; } if (end == header) { // totally bogus return; } *end = 0; // Find the colon to split the header up char *c = header; while (*c && (*c != ':')) { c++; } int namelen = c - header; // Now walk c past the colon c++; // Now skip whitespace to the beginning of the value while (is_blank(*c)) { c++; } int valuelen = (end - c) + 1, fit; if (!strncmp(header, "x-amz-request-id", namelen)) { responseProperties->requestId = string_multibuffer_current(handler->responsePropertyStrings); string_multibuffer_add(handler->responsePropertyStrings, c, valuelen, fit); } else if (!strncmp(header, "x-amz-id-2", namelen)) { responseProperties->requestId2 = string_multibuffer_current(handler->responsePropertyStrings); string_multibuffer_add(handler->responsePropertyStrings, c, valuelen, fit); } else if (!strncmp(header, "Content-Type", namelen)) { responseProperties->contentType = string_multibuffer_current(handler->responsePropertyStrings); string_multibuffer_add(handler->responsePropertyStrings, c, valuelen, fit); } else if (!strncmp(header, "Content-Length", namelen)) { handler->responseProperties.contentLength = 0; while (*c) { handler->responseProperties.contentLength *= 10; handler->responseProperties.contentLength += (*c++ - '0'); } } else if (!strncmp(header, "Server", namelen)) { responseProperties->server = string_multibuffer_current(handler->responsePropertyStrings); string_multibuffer_add(handler->responsePropertyStrings, c, valuelen, fit); } else if (!strncmp(header, "ETag", namelen)) { responseProperties->eTag = string_multibuffer_current(handler->responsePropertyStrings); string_multibuffer_add(handler->responsePropertyStrings, c, valuelen, fit); } else if (!strncmp(header, S3_METADATA_HEADER_NAME_PREFIX, sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)) { // Make sure there is room for another x-amz-meta header if (handler->responseProperties.metaDataCount == sizeof(handler->responseMetaData)) { return; } // Copy the name in char *metaName = &(header[sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1]); int metaNameLen = (namelen - (sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)); char *copiedName = string_multibuffer_current(handler->responseMetaDataStrings); string_multibuffer_add(handler->responseMetaDataStrings, metaName, metaNameLen, fit); if (!fit) { return; } // Copy the value in char *copiedValue = string_multibuffer_current(handler->responseMetaDataStrings); string_multibuffer_add(handler->responseMetaDataStrings, c, valuelen, fit); if (!fit) { return; } if (!handler->responseProperties.metaDataCount) { handler->responseProperties.metaData = handler->responseMetaData; } S3NameValue *metaHeader = &(handler->responseMetaData [handler->responseProperties.metaDataCount++]); metaHeader->name = copiedName; metaHeader->value = copiedValue; } } void response_headers_handler_done(ResponseHeadersHandler *handler, CURL *curl) { // Now get the last modification time from curl, since it's easiest to let // curl parse it time_t lastModified; if (curl_easy_getinfo (curl, CURLINFO_FILETIME, &lastModified) == CURLE_OK) { handler->responseProperties.lastModified = lastModified; } handler->done = 1; } ceph-0.80.11/src/libs3/TODO0000664000175100017510000000012712623076753017170 0ustar jenkins-buildjenkins-build* Implement functions for generating form stuff for posting to s3 * Write s3 man page ceph-0.80.11/src/libs3/test/0000775000175100017510000000000012623076753017457 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/libs3/test/test.sh0000775000175100017510000001164212623076753021001 0ustar jenkins-buildjenkins-build#!/bin/sh # Environment: # S3_ACCESS_KEY_ID - must be set to S3 Access Key ID # S3_SECRET_ACCESS_KEY - must be set to S3 Secret Access Key # TEST_BUCKET_PREFIX - must be set to the test bucket prefix to use # S3_COMMAND - may be set to s3 command to use (i.e. valgrind s3); defaults # to "s3" if [ -z "$S3_ACCESS_KEY_ID" ]; then echo "S3_ACCESS_KEY_ID required" exit -1; fi if [ -z "$S3_SECRET_ACCESS_KEY" ]; then echo "S3_SECRET_ACCESS_KEY required" exit -1; fi if [ -z "$TEST_BUCKET_PREFIX" ]; then echo "TEST_BUCKET_PREFIX required" exit -1; fi if [ -z "$S3_COMMAND" ]; then S3_COMMAND=s3 fi TEST_BUCKET=${TEST_BUCKET_PREFIX}.testbucket # Create the test bucket in EU echo "$S3_COMMAND create $TEST_BUCKET locationConstraint=EU" $S3_COMMAND create $TEST_BUCKET # List to find it echo "$S3_COMMAND list | grep $TEST_BUCKET" $S3_COMMAND list | grep $TEST_BUCKET # Test it echo "$S3_COMMAND test $TEST_BUCKET" $S3_COMMAND test $TEST_BUCKET # List to ensure that it is empty echo "$S3_COMMAND list $TEST_BUCKET" $S3_COMMAND list $TEST_BUCKET # Put some data rm -f seqdata seq 1 10000 > seqdata echo "$S3_COMMAND put $TEST_BUCKET/testkey filename=seqdata noStatus=1" $S3_COMMAND put $TEST_BUCKET/testkey filename=seqdata noStatus=1 rm -f testkey # Get the data and make sure that it matches echo "$S3_COMMAND get $TEST_BUCKET/testkey filename=testkey" $S3_COMMAND get $TEST_BUCKET/testkey filename=testkey diff seqdata testkey rm -f seqdata testkey # Delete the file echo "$S3_COMMAND delete $TEST_BUCKET/testkey" $S3_COMMAND delete $TEST_BUCKET/testkey # Remove the test bucket echo "$S3_COMMAND delete $TEST_BUCKET" $S3_COMMAND delete $TEST_BUCKET # Make sure it's not there echo "$S3_COMMAND list | grep $TEST_BUCKET" $S3_COMMAND list | grep $TEST_BUCKET # Now create it again echo "$S3_COMMAND create $TEST_BUCKET" $S3_COMMAND create $TEST_BUCKET # Put 10 files in it for i in `seq 0 9`; do echo "echo \"Hello\" | $S3_COMMAND put $TEST_BUCKET/key_$i" echo "Hello" | $S3_COMMAND put $TEST_BUCKET/key_$i done # List with all details echo "$S3_COMMAND list $TEST_BUCKET allDetails=1" $S3_COMMAND list $TEST_BUCKET allDetails=1 COPY_BUCKET=${TEST_BUCKET_PREFIX}.copybucket # Create another test bucket and copy a file into it echo "$S3_COMMAND create $COPY_BUCKET" $S3_COMMAND create $COPY_BUCKET echo <> acl Group Authenticated AWS Users READ EOF echo <> acl Group All Users READ_ACP EOF echo "$S3_COMMAND setacl $TEST_BUCKET filename=acl" $S3_COMMAND setacl $TEST_BUCKET filename=acl # Test to make sure that it worked rm -f acl_new echo "$S3_COMMAND getacl $TEST_BUCKET filename=acl_new allDetails=1" $S3_COMMAND getacl $TEST_BUCKET filename=acl_new allDetails=1 diff acl acl_new rm -f acl acl_new # Get the key acl rm -f acl echo "$S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl allDetails=1" $S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl allDetails=1 # Add READ for all AWS users, and READ_ACP for everyone echo <> acl Group Authenticated AWS Users READ EOF echo <> acl Group All Users READ_ACP EOF echo "$S3_COMMAND setacl $TEST_BUCKET/aclkey filename=acl" $S3_COMMAND setacl $TEST_BUCKET/aclkey filename=acl # Test to make sure that it worked rm -f acl_new echo "$S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl_new allDetails=1" $S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl_new allDetails=1 diff acl acl_new rm -f acl acl_new # Remove the test file echo "$S3_COMMAND delete $TEST_BUCKET/aclkey" $S3_COMMAND delete $TEST_BUCKET/aclkey echo "$S3_COMMAND delete $TEST_BUCKET" $S3_COMMAND delete $TEST_BUCKET ceph-0.80.11/src/libs3/test/goodxml_01.xml0000664000175100017510000000042212623076753022150 0ustar jenkins-buildjenkins-build NoSuchKey The resource & then]]> you requested does not exist & so there /mybucket/myfoto.jpg 4442587FB7D0A2F9 ceph-0.80.11/src/libs3/test/badxml_01.xml0000664000175100017510000000256712623076753021762 0ustar jenkins-buildjenkins-build Data ceph-0.80.11/src/libs3/test/goodxml_02.xml0000664000175100017510000000256512623076753022163 0ustar jenkins-buildjenkins-build Data ceph-0.80.11/src/libs3/test/goodxml_03.xml0000664000175100017510000004715012623076753022163 0ustar jenkins-buildjenkins-build 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ceph-0.80.11/src/libs3/COPYING0000664000175100017510000010451312623076753017537 0ustar jenkins-buildjenkins-build GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ceph-0.80.11/src/libs3/LICENSE0000664000175100017510000000150212623076753017503 0ustar jenkins-buildjenkins-buildCopyright 2008 Bryan Ischo libs3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. In addition, as a special exception, the copyright holders give permission to link the code of this library and its programs with the OpenSSL library, and distribute linked combinations including the two. libs3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License version 3 along with libs3, in a file named COPYING. If not, see . ceph-0.80.11/src/libs3/README0000664000175100017510000000017612623076753017364 0ustar jenkins-buildjenkins-buildThis directory contains the libs3 library. The libs3 library is free software. See the file LICENSE for copying permission. ceph-0.80.11/src/ceph_osd.cc0000664000175100017510000004026412623076744017565 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include using namespace std; #include "osd/OSD.h" #include "os/ObjectStore.h" #include "mon/MonClient.h" #include "include/ceph_features.h" #include "common/config.h" #include "mon/MonMap.h" #include "msg/Messenger.h" #include "common/Timer.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "global/signal_handler.h" #include "include/color.h" #include "common/errno.h" #include "common/pick_address.h" #include "perfglue/heap_profiler.h" #include "include/assert.h" #include "erasure-code/ErasureCodePlugin.h" #define dout_subsys ceph_subsys_osd OSD *osd = NULL; void handle_osd_signal(int signum) { if (osd) osd->handle_signal(signum); } void usage() { derr << "usage: ceph-osd -i osdid [--osd-data=path] [--osd-journal=path] " << "[--mkfs] [--mkjournal] [--convert-filestore]" << dendl; derr << " --debug_osd N set debug level (e.g. 10)" << dendl; generic_server_usage(); } int preload_erasure_code() { string directory = g_conf->osd_pool_default_erasure_code_directory; string plugins = g_conf->osd_erasure_code_plugins; stringstream ss; int r = ErasureCodePluginRegistry::instance().preload(plugins, directory, ss); if (r) derr << ss.str() << dendl; else dout(10) << ss.str() << dendl; return r; } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_OSD, CODE_ENVIRONMENT_DAEMON, 0); ceph_heap_profiler_init(); // osd specific args bool mkfs = false; bool mkjournal = false; bool mkkey = false; bool flushjournal = false; bool dump_journal = false; bool convertfilestore = false; bool get_journal_fsid = false; bool get_osd_fsid = false; bool get_cluster_fsid = false; std::string dump_pg_log; std::string val; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); exit(0); } else if (ceph_argparse_flag(args, i, "--mkfs", (char*)NULL)) { mkfs = true; } else if (ceph_argparse_flag(args, i, "--mkjournal", (char*)NULL)) { mkjournal = true; } else if (ceph_argparse_flag(args, i, "--mkkey", (char*)NULL)) { mkkey = true; } else if (ceph_argparse_flag(args, i, "--flush-journal", (char*)NULL)) { flushjournal = true; } else if (ceph_argparse_flag(args, i, "--convert-filestore", (char*)NULL)) { convertfilestore = true; } else if (ceph_argparse_witharg(args, i, &val, "--dump-pg-log", (char*)NULL)) { dump_pg_log = val; } else if (ceph_argparse_flag(args, i, "--dump-journal", (char*)NULL)) { dump_journal = true; } else if (ceph_argparse_flag(args, i, "--get-cluster-fsid", (char*)NULL)) { get_cluster_fsid = true; } else if (ceph_argparse_flag(args, i, "--get-osd-fsid", "--get-osd-uuid", (char*)NULL)) { get_osd_fsid = true; } else if (ceph_argparse_flag(args, i, "--get-journal-fsid", "--get-journal-uuid", (char*)NULL)) { get_journal_fsid = true; } else { ++i; } } if (!args.empty()) { derr << "unrecognized arg " << args[0] << dendl; usage(); } if (!dump_pg_log.empty()) { common_init_finish(g_ceph_context); bufferlist bl; std::string error; int r = bl.read_file(dump_pg_log.c_str(), &error); if (r >= 0) { pg_log_entry_t e; bufferlist::iterator p = bl.begin(); while (!p.end()) { uint64_t pos = p.get_off(); try { ::decode(e, p); } catch (const buffer::error &e) { derr << "failed to decode LogEntry at offset " << pos << dendl; return 1; } derr << pos << ":\t" << e << dendl; } } else { derr << "unable to open " << dump_pg_log << ": " << error << dendl; } return 0; } // whoami char *end; const char *id = g_conf->name.get_id().c_str(); int whoami = strtol(id, &end, 10); if (*end || end == id || whoami < 0) { derr << "must specify '-i #' where # is the osd number" << dendl; usage(); } if (g_conf->osd_data.empty()) { derr << "must specify '--osd-data=foo' data path" << dendl; usage(); } // the store ObjectStore *store = ObjectStore::create(g_ceph_context, g_conf->osd_objectstore, g_conf->osd_data, g_conf->osd_journal); if (!store) { derr << "unable to create object store" << dendl; return -ENODEV; } if (mkfs) { common_init_finish(g_ceph_context); MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) return -1; if (mc.get_monmap_privately() < 0) return -1; int err = OSD::mkfs(g_ceph_context, store, g_conf->osd_data, mc.monmap.fsid, whoami); if (err < 0) { derr << TEXT_RED << " ** ERROR: error creating empty object store in " << g_conf->osd_data << ": " << cpp_strerror(-err) << TEXT_NORMAL << dendl; exit(1); } derr << "created object store " << g_conf->osd_data; if (!g_conf->osd_journal.empty()) *_dout << " journal " << g_conf->osd_journal; *_dout << " for osd." << whoami << " fsid " << mc.monmap.fsid << dendl; } if (mkkey) { common_init_finish(g_ceph_context); KeyRing *keyring = KeyRing::create_empty(); if (!keyring) { derr << "Unable to get a Ceph keyring." << dendl; return 1; } EntityName ename(g_conf->name); EntityAuth eauth; int ret = keyring->load(g_ceph_context, g_conf->keyring); if (ret == 0 && keyring->get_auth(ename, eauth)) { derr << "already have key in keyring " << g_conf->keyring << dendl; } else { eauth.key.create(g_ceph_context, CEPH_CRYPTO_AES); keyring->add(ename, eauth); bufferlist bl; keyring->encode_plaintext(bl); int r = bl.write_file(g_conf->keyring.c_str(), 0600); if (r) derr << TEXT_RED << " ** ERROR: writing new keyring to " << g_conf->keyring << ": " << cpp_strerror(r) << TEXT_NORMAL << dendl; else derr << "created new key in keyring " << g_conf->keyring << dendl; } } if (mkfs || mkkey) exit(0); if (mkjournal) { common_init_finish(g_ceph_context); int err = store->mkjournal(); if (err < 0) { derr << TEXT_RED << " ** ERROR: error creating fresh journal " << g_conf->osd_journal << " for object store " << g_conf->osd_data << ": " << cpp_strerror(-err) << TEXT_NORMAL << dendl; exit(1); } derr << "created new journal " << g_conf->osd_journal << " for object store " << g_conf->osd_data << dendl; exit(0); } if (flushjournal) { common_init_finish(g_ceph_context); int err = store->mount(); if (err < 0) { derr << TEXT_RED << " ** ERROR: error flushing journal " << g_conf->osd_journal << " for object store " << g_conf->osd_data << ": " << cpp_strerror(-err) << TEXT_NORMAL << dendl; exit(1); } store->sync_and_flush(); store->umount(); derr << "flushed journal " << g_conf->osd_journal << " for object store " << g_conf->osd_data << dendl; exit(0); } if (dump_journal) { common_init_finish(g_ceph_context); int err = store->dump_journal(cout); if (err < 0) { derr << TEXT_RED << " ** ERROR: error dumping journal " << g_conf->osd_journal << " for object store " << g_conf->osd_data << ": " << cpp_strerror(-err) << TEXT_NORMAL << dendl; exit(1); } derr << "dumped journal " << g_conf->osd_journal << " for object store " << g_conf->osd_data << dendl; exit(0); } if (convertfilestore) { int err = OSD::do_convertfs(store); if (err < 0) { derr << TEXT_RED << " ** ERROR: error converting store " << g_conf->osd_data << ": " << cpp_strerror(-err) << TEXT_NORMAL << dendl; exit(1); } exit(0); } if (get_journal_fsid) { uuid_d fsid; int r = store->peek_journal_fsid(&fsid); if (r == 0) cout << fsid << std::endl; exit(r); } string magic; uuid_d cluster_fsid, osd_fsid; int w; int r = OSD::peek_meta(store, magic, cluster_fsid, osd_fsid, w); if (r < 0) { derr << TEXT_RED << " ** ERROR: unable to open OSD superblock on " << g_conf->osd_data << ": " << cpp_strerror(-r) << TEXT_NORMAL << dendl; if (r == -ENOTSUP) { derr << TEXT_RED << " ** please verify that underlying storage " << "supports xattrs" << TEXT_NORMAL << dendl; } exit(1); } if (w != whoami) { derr << "OSD id " << w << " != my id " << whoami << dendl; exit(1); } if (strcmp(magic.c_str(), CEPH_OSD_ONDISK_MAGIC)) { derr << "OSD magic " << magic << " != my " << CEPH_OSD_ONDISK_MAGIC << dendl; exit(1); } if (get_cluster_fsid) { cout << cluster_fsid << std::endl; exit(0); } if (get_osd_fsid) { cout << osd_fsid << std::endl; exit(0); } pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC |CEPH_PICK_ADDRESS_CLUSTER); if (g_conf->public_addr.is_blank_ip() && !g_conf->cluster_addr.is_blank_ip()) { derr << TEXT_YELLOW << " ** WARNING: specified cluster addr but not public addr; we recommend **\n" << " ** you specify neither or both. **" << TEXT_NORMAL << dendl; } Messenger *ms_public = Messenger::create(g_ceph_context, entity_name_t::OSD(whoami), "client", getpid()); Messenger *ms_cluster = Messenger::create(g_ceph_context, entity_name_t::OSD(whoami), "cluster", getpid()); Messenger *ms_hbclient = Messenger::create(g_ceph_context, entity_name_t::OSD(whoami), "hbclient", getpid()); Messenger *ms_hb_back_server = Messenger::create(g_ceph_context, entity_name_t::OSD(whoami), "hb_back_server", getpid()); Messenger *ms_hb_front_server = Messenger::create(g_ceph_context, entity_name_t::OSD(whoami), "hb_front_server", getpid()); Messenger *ms_objecter = Messenger::create(g_ceph_context, entity_name_t::OSD(whoami), "ms_objecter", getpid()); ms_cluster->set_cluster_protocol(CEPH_OSD_PROTOCOL); ms_hbclient->set_cluster_protocol(CEPH_OSD_PROTOCOL); ms_hb_back_server->set_cluster_protocol(CEPH_OSD_PROTOCOL); ms_hb_front_server->set_cluster_protocol(CEPH_OSD_PROTOCOL); cout << "starting osd." << whoami << " at " << ms_public->get_myaddr() << " osd_data " << g_conf->osd_data << " " << ((g_conf->osd_journal.empty()) ? "(no journal)" : g_conf->osd_journal) << std::endl; boost::scoped_ptr client_byte_throttler( new Throttle(g_ceph_context, "osd_client_bytes", g_conf->osd_client_message_size_cap)); boost::scoped_ptr client_msg_throttler( new Throttle(g_ceph_context, "osd_client_messages", g_conf->osd_client_message_cap)); uint64_t supported = CEPH_FEATURE_UID | CEPH_FEATURE_NOSRCADDR | CEPH_FEATURE_PGID64 | CEPH_FEATURE_MSG_AUTH | CEPH_FEATURE_OSD_ERASURE_CODES; ms_public->set_default_policy(Messenger::Policy::stateless_server(supported, 0)); ms_public->set_policy_throttlers(entity_name_t::TYPE_CLIENT, client_byte_throttler.get(), client_msg_throttler.get()); ms_public->set_policy(entity_name_t::TYPE_MON, Messenger::Policy::lossy_client(supported, CEPH_FEATURE_UID | CEPH_FEATURE_PGID64 | CEPH_FEATURE_OSDENC)); //try to poison pill any OSD connections on the wrong address ms_public->set_policy(entity_name_t::TYPE_OSD, Messenger::Policy::stateless_server(0,0)); ms_cluster->set_default_policy(Messenger::Policy::stateless_server(0, 0)); ms_cluster->set_policy(entity_name_t::TYPE_MON, Messenger::Policy::lossy_client(0,0)); ms_cluster->set_policy(entity_name_t::TYPE_OSD, Messenger::Policy::lossless_peer(supported, CEPH_FEATURE_UID | CEPH_FEATURE_PGID64 | CEPH_FEATURE_OSDENC)); ms_cluster->set_policy(entity_name_t::TYPE_CLIENT, Messenger::Policy::stateless_server(0, 0)); ms_hbclient->set_policy(entity_name_t::TYPE_OSD, Messenger::Policy::lossy_client(0, 0)); ms_hb_back_server->set_policy(entity_name_t::TYPE_OSD, Messenger::Policy::stateless_server(0, 0)); ms_hb_front_server->set_policy(entity_name_t::TYPE_OSD, Messenger::Policy::stateless_server(0, 0)); ms_objecter->set_default_policy(Messenger::Policy::lossy_client(0, CEPH_FEATURE_OSDREPLYMUX)); r = ms_public->bind(g_conf->public_addr); if (r < 0) exit(1); r = ms_cluster->bind(g_conf->cluster_addr); if (r < 0) exit(1); // hb back should bind to same ip as cluster_addr (if specified) entity_addr_t hb_back_addr = g_conf->osd_heartbeat_addr; if (hb_back_addr.is_blank_ip()) { hb_back_addr = g_conf->cluster_addr; if (hb_back_addr.is_ip()) hb_back_addr.set_port(0); } r = ms_hb_back_server->bind(hb_back_addr); if (r < 0) exit(1); // hb front should bind to same ip as public_addr entity_addr_t hb_front_addr = g_conf->public_addr; if (hb_front_addr.is_ip()) hb_front_addr.set_port(0); r = ms_hb_front_server->bind(hb_front_addr); if (r < 0) exit(1); ms_objecter->bind(g_conf->public_addr); // Set up crypto, daemonize, etc. global_init_daemonize(g_ceph_context, 0); common_init_finish(g_ceph_context); if (g_conf->filestore_update_to >= (int)store->get_target_version()) { int err = OSD::do_convertfs(store); if (err < 0) { derr << TEXT_RED << " ** ERROR: error converting store " << g_conf->osd_data << ": " << cpp_strerror(-err) << TEXT_NORMAL << dendl; exit(1); } } MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) return -1; global_init_chdir(g_ceph_context); if (preload_erasure_code() < -1) return -1; osd = new OSD(g_ceph_context, store, whoami, ms_cluster, ms_public, ms_hbclient, ms_hb_front_server, ms_hb_back_server, ms_objecter, &mc, g_conf->osd_data, g_conf->osd_journal); int err = osd->pre_init(); if (err < 0) { derr << TEXT_RED << " ** ERROR: osd pre_init failed: " << cpp_strerror(-err) << TEXT_NORMAL << dendl; return 1; } // Now close the standard file descriptors global_init_shutdown_stderr(g_ceph_context); ms_public->start(); ms_hbclient->start(); ms_hb_front_server->start(); ms_hb_back_server->start(); ms_cluster->start(); ms_objecter->start(); // start osd err = osd->init(); if (err < 0) { derr << TEXT_RED << " ** ERROR: osd init failed: " << cpp_strerror(-err) << TEXT_NORMAL << dendl; return 1; } // install signal handlers init_async_signal_handler(); register_async_signal_handler(SIGHUP, sighup_handler); register_async_signal_handler_oneshot(SIGINT, handle_osd_signal); register_async_signal_handler_oneshot(SIGTERM, handle_osd_signal); osd->final_init(); if (g_conf->inject_early_sigterm) kill(getpid(), SIGTERM); ms_public->wait(); ms_hbclient->wait(); ms_hb_front_server->wait(); ms_hb_back_server->wait(); ms_cluster->wait(); ms_objecter->wait(); unregister_async_signal_handler(SIGHUP, sighup_handler); unregister_async_signal_handler(SIGINT, handle_osd_signal); unregister_async_signal_handler(SIGTERM, handle_osd_signal); shutdown_async_signal_handler(); // done delete osd; delete ms_public; delete ms_hbclient; delete ms_hb_front_server; delete ms_hb_back_server; delete ms_cluster; delete ms_objecter; client_byte_throttler.reset(); client_msg_throttler.reset(); g_ceph_context->put(); // cd on exit, so that gmon.out (if any) goes into a separate directory for each node. char s[20]; snprintf(s, sizeof(s), "gmon/%d", getpid()); if ((mkdir(s, 0755) == 0) && (chdir(s) == 0)) { dout(0) << "ceph-osd: gmon.out should be in " << s << dendl; } return 0; } ceph-0.80.11/src/objclass/0000775000175100017510000000000012623077035017256 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/objclass/objclass.h0000664000175100017510000001402512623076744021237 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_OBJCLASS_H #define CEPH_OBJCLASS_H #ifdef __cplusplus #include "../include/types.h" #include "msg/msg_types.h" extern "C" { #endif #define CLS_VER(maj,min) \ int __cls_ver__## maj ## _ ##min = 0; \ int __cls_ver_maj = maj; \ int __cls_ver_min = min; #define CLS_NAME(name) \ int __cls_name__## name = 0; \ const char *__cls_name = #name; #define CLS_METHOD_RD 0x1 #define CLS_METHOD_WR 0x2 #define CLS_METHOD_PUBLIC 0x4 #define CLS_LOG(level, fmt, ...) \ cls_log(level, " %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #define CLS_ERR(fmt, ...) CLS_LOG(0, fmt, ##__VA_ARGS__) void __cls_init(); typedef void *cls_handle_t; typedef void *cls_method_handle_t; typedef void *cls_method_context_t; typedef int (*cls_method_call_t)(cls_method_context_t ctx, char *indata, int datalen, char **outdata, int *outdatalen); typedef struct { const char *name; const char *ver; } cls_deps_t; /* class utils */ extern int cls_log(int level, const char *format, ...) __attribute__((__format__(printf, 2, 3))); extern void *cls_alloc(size_t size); extern void cls_free(void *p); extern int cls_read(cls_method_context_t hctx, int ofs, int len, char **outdata, int *outdatalen); extern int cls_call(cls_method_context_t hctx, const char *cls, const char *method, char *indata, int datalen, char **outdata, int *outdatalen); extern int cls_getxattr(cls_method_context_t hctx, const char *name, char **outdata, int *outdatalen); extern int cls_setxattr(cls_method_context_t hctx, const char *name, const char *value, int val_len); /** This will fill in the passed origin pointer with the origin of the * request which activated your class call. */ extern int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin); /* class registration api */ extern int cls_register(const char *name, cls_handle_t *handle); extern int cls_unregister(cls_handle_t); extern int cls_register_method(cls_handle_t hclass, const char *method, int flags, cls_method_call_t class_call, cls_method_handle_t *handle); extern int cls_unregister_method(cls_method_handle_t handle); /* triggers */ #define OBJ_READ 0x1 #define OBJ_WRITE 0x2 typedef int cls_trigger_t; extern int cls_link(cls_method_handle_t handle, int priority, cls_trigger_t trigger); extern int cls_unlink(cls_method_handle_t handle); /* should be defined by the class implementation defined here inorder to get it compiled without C++ mangling */ extern void class_init(void); extern void class_fini(void); #ifdef __cplusplus } typedef int (*cls_method_cxx_call_t)(cls_method_context_t ctx, class buffer::list *inbl, class buffer::list *outbl); extern int cls_register_cxx_method(cls_handle_t hclass, const char *method, int flags, cls_method_cxx_call_t class_call, cls_method_handle_t *handle); extern int cls_cxx_create(cls_method_context_t hctx, bool exclusive); extern int cls_cxx_remove(cls_method_context_t hctx); extern int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime); extern int cls_cxx_read(cls_method_context_t hctx, int ofs, int len, bufferlist *bl); extern int cls_cxx_write(cls_method_context_t hctx, int ofs, int len, bufferlist *bl); extern int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *bl); extern int cls_cxx_getxattr(cls_method_context_t hctx, const char *name, bufferlist *outbl); extern int cls_cxx_getxattrs(cls_method_context_t hctx, map *attrset); extern int cls_cxx_setxattr(cls_method_context_t hctx, const char *name, bufferlist *inbl); extern int cls_cxx_replace(cls_method_context_t hctx, int ofs, int len, bufferlist *bl); extern int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid); extern int cls_cxx_map_clear(cls_method_context_t hctx); extern int cls_cxx_map_get_all_vals(cls_method_context_t hctx, std::map *vals); extern int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_after, uint64_t max_to_get, std::set *keys); extern int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_after, const string &filter_prefix, uint64_t max_to_get, std::map *vals); extern int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl); extern int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key, bufferlist *outbl); extern int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key, bufferlist *inbl); extern int cls_cxx_map_set_vals(cls_method_context_t hctx, const std::map *map); extern int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl); extern int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key); extern int cls_cxx_map_update(cls_method_context_t hctx, bufferlist *inbl); /* utility functions */ extern int cls_gen_random_bytes(char *buf, int size); extern int cls_gen_rand_base64(char *dest, int size); /* size should be the required string size + 1 */ /* environment */ extern uint64_t cls_current_version(cls_method_context_t hctx); extern int cls_current_subop_num(cls_method_context_t hctx); /* helpers */ extern void cls_cxx_subop_version(cls_method_context_t hctx, string *s); /* These are also defined in rados.h and librados.h. Keep them in sync! */ #define CEPH_OSD_TMAP_HDR 'h' #define CEPH_OSD_TMAP_SET 's' #define CEPH_OSD_TMAP_CREATE 'c' #define CEPH_OSD_TMAP_RM 'r' #endif #endif ceph-0.80.11/src/objclass/class_api.cc0000664000175100017510000003671512623076744021545 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/config.h" #include "common/debug.h" #include "objclass/objclass.h" #include "osd/ReplicatedPG.h" #include "osd/ClassHandler.h" #include "auth/Crypto.h" #include "common/armor.h" static ClassHandler *ch; #define dout_subsys ceph_subsys_objclass void cls_initialize(ClassHandler *h) { ch = h; } void cls_finalize() { ch = NULL; } void *cls_alloc(size_t size) { return malloc(size); } void cls_free(void *p) { free(p); } int cls_register(const char *name, cls_handle_t *handle) { ClassHandler::ClassData *cls = ch->register_class(name); *handle = (cls_handle_t)cls; return (cls != NULL); } int cls_unregister(cls_handle_t handle) { ClassHandler::ClassData *cls = (ClassHandler::ClassData *)handle; ch->unregister_class(cls); return 1; } int cls_register_method(cls_handle_t hclass, const char *method, int flags, cls_method_call_t class_call, cls_method_handle_t *handle) { if (!(flags & (CLS_METHOD_RD | CLS_METHOD_WR))) return -EINVAL; ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass; cls_method_handle_t hmethod =(cls_method_handle_t)cls->register_method(method, flags, class_call); if (handle) *handle = hmethod; return (hmethod != NULL); } int cls_register_cxx_method(cls_handle_t hclass, const char *method, int flags, cls_method_cxx_call_t class_call, cls_method_handle_t *handle) { ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass; cls_method_handle_t hmethod = (cls_method_handle_t)cls->register_cxx_method(method, flags, class_call); if (handle) *handle = hmethod; return (hmethod != NULL); } int cls_unregister_method(cls_method_handle_t handle) { ClassHandler::ClassMethod *method = (ClassHandler::ClassMethod *)handle; method->unregister(); return 1; } int cls_call(cls_method_context_t hctx, const char *cls, const char *method, char *indata, int datalen, char **outdata, int *outdatalen) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; bufferlist idata; vector nops(1); OSDOp& op = nops[0]; int r; op.op.op = CEPH_OSD_OP_CALL; op.op.cls.class_len = strlen(cls); op.op.cls.method_len = strlen(method); op.op.cls.indata_len = datalen; op.indata.append(cls, op.op.cls.class_len); op.indata.append(method, op.op.cls.method_len); op.indata.append(indata, datalen); r = (*pctx)->pg->do_osd_ops(*pctx, nops); *outdata = (char *)malloc(op.outdata.length()); if (!*outdata) return -ENOMEM; memcpy(*outdata, op.outdata.c_str(), op.outdata.length()); *outdatalen = op.outdata.length(); return r; } int cls_getxattr(cls_method_context_t hctx, const char *name, char **outdata, int *outdatalen) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; bufferlist name_data; vector nops(1); OSDOp& op = nops[0]; int r; op.op.op = CEPH_OSD_OP_GETXATTR; op.indata.append(name); op.op.xattr.name_len = strlen(name); r = (*pctx)->pg->do_osd_ops(*pctx, nops); *outdata = (char *)malloc(op.outdata.length()); if (!*outdata) return -ENOMEM; memcpy(*outdata, op.outdata.c_str(), op.outdata.length()); *outdatalen = op.outdata.length(); return r; } int cls_setxattr(cls_method_context_t hctx, const char *name, const char *value, int val_len) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; bufferlist name_data; vector nops(1); OSDOp& op = nops[0]; int r; op.op.op = CEPH_OSD_OP_SETXATTR; op.indata.append(name); op.indata.append(value); op.op.xattr.name_len = strlen(name); op.op.xattr.value_len = val_len; r = (*pctx)->pg->do_osd_ops(*pctx, nops); return r; } int cls_read(cls_method_context_t hctx, int ofs, int len, char **outdata, int *outdatalen) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); ops[0].op.op = CEPH_OSD_OP_SYNC_READ; ops[0].op.extent.offset = ofs; ops[0].op.extent.length = len; int r = (*pctx)->pg->do_osd_ops(*pctx, ops); *outdata = (char *)malloc(ops[0].outdata.length()); if (!*outdata) return -ENOMEM; memcpy(*outdata, ops[0].outdata.c_str(), ops[0].outdata.length()); *outdatalen = ops[0].outdata.length(); if (r < 0) return r; return *outdatalen; } int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin) { ReplicatedPG::OpContext **pctx = static_cast(hctx); *origin = (*pctx)->op->get_req()->get_orig_source_inst(); return 0; } int cls_cxx_create(cls_method_context_t hctx, bool exclusive) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); ops[0].op.op = CEPH_OSD_OP_CREATE; ops[0].op.flags = (exclusive ? CEPH_OSD_OP_FLAG_EXCL : 0); return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_remove(cls_method_context_t hctx) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); ops[0].op.op = CEPH_OSD_OP_DELETE; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); int ret; ops[0].op.op = CEPH_OSD_OP_STAT; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; bufferlist::iterator iter = ops[0].outdata.begin(); utime_t ut; uint64_t s; try { ::decode(s, iter); ::decode(ut, iter); } catch (buffer::error& err) { return -EIO; } if (size) *size = s; if (mtime) *mtime = ut.sec(); return 0; } int cls_cxx_read(cls_method_context_t hctx, int ofs, int len, bufferlist *outbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); int ret; ops[0].op.op = CEPH_OSD_OP_SYNC_READ; ops[0].op.extent.offset = ofs; ops[0].op.extent.length = len; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; outbl->claim(ops[0].outdata); return outbl->length(); } int cls_cxx_write(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); ops[0].op.op = CEPH_OSD_OP_WRITE; ops[0].op.extent.offset = ofs; ops[0].op.extent.length = len; ops[0].indata = *inbl; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *inbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); ops[0].op.op = CEPH_OSD_OP_WRITEFULL; ops[0].op.extent.offset = 0; ops[0].op.extent.length = inbl->length(); ops[0].indata = *inbl; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_replace(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(2); ops[0].op.op = CEPH_OSD_OP_TRUNCATE; ops[0].op.extent.offset = 0; ops[0].op.extent.length = 0; ops[1].op.op = CEPH_OSD_OP_WRITE; ops[1].op.extent.offset = ofs; ops[1].op.extent.length = len; ops[1].indata = *inbl; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_getxattr(cls_method_context_t hctx, const char *name, bufferlist *outbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; bufferlist name_data; vector nops(1); OSDOp& op = nops[0]; int r; op.op.op = CEPH_OSD_OP_GETXATTR; op.indata.append(name); op.op.xattr.name_len = strlen(name); r = (*pctx)->pg->do_osd_ops(*pctx, nops); if (r < 0) return r; outbl->claim(op.outdata); return outbl->length(); } int cls_cxx_getxattrs(cls_method_context_t hctx, map *attrset) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector nops(1); OSDOp& op = nops[0]; int r; op.op.op = CEPH_OSD_OP_GETXATTRS; r = (*pctx)->pg->do_osd_ops(*pctx, nops); if (r < 0) return r; bufferlist::iterator iter = op.outdata.begin(); try { ::decode(*attrset, iter); } catch (buffer::error& err) { return -EIO; } return 0; } int cls_cxx_setxattr(cls_method_context_t hctx, const char *name, bufferlist *inbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; bufferlist name_data; vector nops(1); OSDOp& op = nops[0]; int r; op.op.op = CEPH_OSD_OP_SETXATTR; op.indata.append(name); op.indata.append(*inbl); op.op.xattr.name_len = strlen(name); op.op.xattr.value_len = inbl->length(); r = (*pctx)->pg->do_osd_ops(*pctx, nops); return r; } int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); ops[0].op.op = CEPH_OSD_OP_ROLLBACK; ops[0].op.snap.snapid = snapid; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_map_get_all_vals(cls_method_context_t hctx, map* vals) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; int ret; string start_after; string filter_prefix; uint64_t max = (uint64_t)-1; bufferlist inbl; ::encode(start_after, op.indata); ::encode(max, op.indata); ::encode(filter_prefix, op.indata); op.op.op = CEPH_OSD_OP_OMAPGETVALS; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; bufferlist::iterator iter = op.outdata.begin(); try { ::decode(*vals, iter); } catch (buffer::error& err) { return -EIO; } return vals->size(); } int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_obj, uint64_t max_to_get, set *keys) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; int ret; ::encode(start_obj, op.indata); ::encode(max_to_get, op.indata); op.op.op = CEPH_OSD_OP_OMAPGETKEYS; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; bufferlist::iterator iter = op.outdata.begin(); try { ::decode(*keys, iter); } catch (buffer::error& err) { return -EIO; } return keys->size(); } int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_obj, const string &filter_prefix, uint64_t max_to_get, map *vals) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; int ret; bufferlist inbl; ::encode(start_obj, op.indata); ::encode(max_to_get, op.indata); ::encode(filter_prefix, op.indata); op.op.op = CEPH_OSD_OP_OMAPGETVALS; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; bufferlist::iterator iter = op.outdata.begin(); try { ::decode(*vals, iter); } catch (buffer::error& err) { return -EIO; } return vals->size(); } int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; int ret; op.op.op = CEPH_OSD_OP_OMAPGETHEADER; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; outbl->claim(op.outdata); return 0; } int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key, bufferlist *outbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; int ret; set k; k.insert(key); ::encode(k, op.indata); op.op.op = CEPH_OSD_OP_OMAPGETVALSBYKEYS; ret = (*pctx)->pg->do_osd_ops(*pctx, ops); if (ret < 0) return ret; bufferlist::iterator iter = op.outdata.begin(); try { map m; ::decode(m, iter); map::iterator iter = m.begin(); if (iter == m.end()) return -ENOENT; *outbl = iter->second; } catch (buffer::error& e) { return -EIO; } return 0; } int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key, bufferlist *inbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; bufferlist& update_bl = op.indata; map m; m[key] = *inbl; ::encode(m, update_bl); op.op.op = CEPH_OSD_OP_OMAPSETVALS; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_map_set_vals(cls_method_context_t hctx, const std::map *map) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; bufferlist& update_bl = op.indata; ::encode(*map, update_bl); op.op.op = CEPH_OSD_OP_OMAPSETVALS; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_map_clear(cls_method_context_t hctx) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; op.op.op = CEPH_OSD_OP_OMAPCLEAR; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; op.indata.claim(*inbl); op.op.op = CEPH_OSD_OP_OMAPSETHEADER; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) { ReplicatedPG::OpContext **pctx = (ReplicatedPG::OpContext **)hctx; vector ops(1); OSDOp& op = ops[0]; bufferlist& update_bl = op.indata; set to_rm; to_rm.insert(key); ::encode(to_rm, update_bl); op.op.op = CEPH_OSD_OP_OMAPRMKEYS; return (*pctx)->pg->do_osd_ops(*pctx, ops); } int cls_gen_random_bytes(char *buf, int size) { return get_random_bytes(buf, size); } int cls_gen_rand_base64(char *dest, int size) /* size should be the required string size + 1 */ { char buf[size]; char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */ int ret; ret = cls_gen_random_bytes(buf, sizeof(buf)); if (ret < 0) { generic_derr << "cannot get random bytes: " << ret << dendl; return -1; } ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)], (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4); if (ret < 0) { generic_derr << "ceph_armor failed" << dendl; return -1; } tmp_dest[ret] = '\0'; memcpy(dest, tmp_dest, size); dest[size] = '\0'; return 0; } uint64_t cls_current_version(cls_method_context_t hctx) { ReplicatedPG::OpContext *ctx = *(ReplicatedPG::OpContext **)hctx; return ctx->pg->info.last_user_version; } int cls_current_subop_num(cls_method_context_t hctx) { ReplicatedPG::OpContext *ctx = *(ReplicatedPG::OpContext **)hctx; return ctx->current_osd_subop_num; } void cls_cxx_subop_version(cls_method_context_t hctx, string *s) { if (!s) return; char buf[32]; uint64_t ver = cls_current_version(hctx); int subop_num = cls_current_subop_num(hctx); snprintf(buf, sizeof(buf), "%lld.%d", (long long)ver, subop_num); *s = buf; } int cls_log(int level, const char *format, ...) { int size = 256; va_list ap; while (1) { char buf[size]; va_start(ap, format); int n = vsnprintf(buf, size, format, ap); va_end(ap); #define MAX_SIZE 8196 if ((n > -1 && n < size) || size > MAX_SIZE) { dout(level) << buf << dendl; return n; } size *= 2; } } ceph-0.80.11/src/rbdmap0000664000175100017510000000013412623076744016652 0ustar jenkins-buildjenkins-build# RbdDevice Parameters #poolname/imagename id=client,keyring=/etc/ceph/ceph.client.keyring ceph-0.80.11/src/sample.ceph.conf0000664000175100017510000003257512623076744020546 0ustar jenkins-buildjenkins-build## # Sample ceph ceph.conf file. ## # This file defines cluster membership, the various locations # that Ceph stores data, and any other runtime options. # If a 'host' is defined for a daemon, the init.d start/stop script will # verify that it matches the hostname (or else ignore it). If it is # not defined, it is assumed that the daemon is intended to start on # the current host (e.g., in a setup with a startup.conf on each # node). ## Metavariables # $cluster ; Expands to the Ceph Storage Cluster name. Useful # ; when running multiple Ceph Storage Clusters # ; on the same hardware. # ; Example: /etc/ceph/$cluster.keyring # ; (Default: ceph) # # $type ; Expands to one of mds, osd, or mon, depending on # ; the type of the instant daemon. # ; Example: /var/lib/ceph/$type # # $id ; Expands to the daemon identifier. For osd.0, this # ; would be 0; for mds.a, it would be a. # ; Example: /var/lib/ceph/$type/$cluster-$id # # $host ; Expands to the host name of the instant daemon. # # $name ; Expands to $type.$id. # ; Example: /var/run/ceph/$cluster-$name.asok [global] ### http://ceph.com/docs/master/rados/configuration/general-config-ref/ ;fsid = {UUID} # use `uuidgen` to generate your own UUID ;public network = 192.168.0.0/24 ;cluster network = 192.168.0.0/24 # Each running Ceph daemon has a running process identifier (PID) file. # The PID file is generated upon start-up. # Type: String (optional) # (Default: N/A). The default path is /var/run/$cluster/$name.pid. pid file = /var/run/ceph/$name.pid # If set, when the Ceph Storage Cluster starts, Ceph sets the max open fds # at the OS level (i.e., the max # of file descriptors). # It helps prevents Ceph OSD Daemons from running out of file descriptors. # Type: 64-bit Integer (optional) # (Default: 0) ;max open files = 131072 ### http://ceph.com/docs/master/rados/operations/authentication ### http://ceph.com/docs/master/rados/configuration/auth-config-ref/ # If enabled, the Ceph Storage Cluster daemons (i.e., ceph-mon, ceph-osd, # and ceph-mds) must authenticate with each other. # Type: String (optional); Valid settings are "cephx" or "none". # (Default: cephx) auth cluster required = cephx # If enabled, the Ceph Storage Cluster daemons require Ceph Clients to # authenticate with the Ceph Storage Cluster in order to access Ceph # services. # Type: String (optional); Valid settings are "cephx" or "none". # (Default: cephx) auth service required = cephx # If enabled, the Ceph Client requires the Ceph Storage Cluster to # authenticate with the Ceph Client. # Type: String (optional); Valid settings are "cephx" or "none". # (Default: cephx) auth client required = cephx # If set to true, Ceph requires signatures on all message traffic between # the Ceph Client and the Ceph Storage Cluster, and between daemons # comprising the Ceph Storage Cluster. # Type: Boolean (optional) # (Default: false) cephx require signatures = true ; everywhere possible # The path to the keyring file. # Type: String (optional) # Default: /etc/ceph/$cluster.$name.keyring,/etc/ceph/$cluster.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin ;keyring = /etc/ceph/$cluster.$name.keyring ### http://ceph.com/docs/master/rados/configuration/pool-pg-config-ref/ ## Replication level, number of data copies. # Type: 32-bit Integer # (Default: 2) ;osd pool default size = 2 ## Replication level in degraded state, less than 'osd pool default size' value. # Sets the minimum number of written replicas for objects in the # pool in order to acknowledge a write operation to the client. If # minimum is not met, Ceph will not acknowledge the write to the # client. This setting ensures a minimum number of replicas when # operating in degraded mode. # Type: 32-bit Integer # (Default: 0), which means no particular minimum. If 0, minimum is size - (size / 2). ;osd pool default min size = 1 ## Ensure you have a realistic number of placement groups. We recommend ## approximately 100 per OSD. E.g., total number of OSDs multiplied by 100 ## divided by the number of replicas (i.e., osd pool default size). So for ## 10 OSDs and osd pool default size = 3, we'd recommend approximately ## (100 * 10) / 3 = 333 # Description: The default number of placement groups for a pool. The # default value is the same as pg_num with mkpool. # Type: 32-bit Integer # (Default: 8) ;osd pool default pg num = 100 # Description: The default number of placement groups for placement for a # pool. The default value is the same as pgp_num with mkpool. # PG and PGP should be equal (for now). # Type: 32-bit Integer # (Default: 8) ;osd pool default pgp num = 100 # The default CRUSH ruleset to use when creating a pool # Type: 32-bit Integer # (Default: 0) ;osd pool default crush rule = 0 # The bucket type to use for chooseleaf in a CRUSH rule. # Uses ordinal rank rather than name. # Type: 32-bit Integer # (Default: 1) Typically a host containing one or more Ceph OSD Daemons. ;osd crush chooseleaf type = 1 ### http://ceph.com/docs/bobtail/rados/configuration/log-and-debug-ref/ # Default: /var/log/ceph/$cluster-$name.log ;log file = /var/log/ceph/$cluster-$name.log ;log to syslog = true ### http://ceph.com/docs/master/rados/configuration/ms-ref/ # Enable if you want your daemons to bind to IPv6 address instead of # IPv4 ones. (Not required if you specify a daemon or cluster IP.) # Type: Boolean # (Default: false) ;ms bind ipv6 = true ### http://ceph.com/docs/master/rados/configuration/filestore-config-ref/ # The maximum interval in seconds for synchronizing the filestore. # Type: Double (optional) # (Default: 5) ;filestore max sync interval = 5 # Use object map for XATTRS. Set to true for ext4 file systems only. # Type: Boolean (optional) # (Default: false) ;filestore xattr use omap = true ### http://ceph.com/docs/master/rados/configuration/journal-ref/ ################## ## Monitors ## You need at least one. You need at least three if you want to ## tolerate any node failures. Always create an odd number. [mon] ### http://ceph.com/docs/argonaut/config-ref/mon-config/ ### http://ceph.com/docs/master/rados/configuration/mon-config-ref/ ### http://ceph.com/docs/dumpling/rados/configuration/mon-osd-interaction/ # The IDs of initial monitors in a cluster during startup. # If specified, Ceph requires an odd number of monitors to form an # initial quorum (e.g., 3). # Type: String # (Default: None) ;mon initial members = mycephhost ;mon host = cephhost01,cephhost02 ;mon addr = 192.168.0.101,192.168.0.102 # The monitor’s data location # Default: /var/lib/ceph/mon/$cluster-$id ;mon data = /var/lib/ceph/mon/$name # The clock drift in seconds allowed between monitors. # Type: Float # (Default: .050) ;mon clock drift allowed = .15 # Exponential backoff for clock drift warnings # Type: Float # (Default: 5) ;mon clock drift warn backoff = 30 ; Tell the monitor to backoff from this warning for 30 seconds # The percentage of disk space used before an OSD is considered full. # Type: Float # (Default: .95) ;mon osd full ratio = .95 # The percentage of disk space used before an OSD is considered nearfull. # Type: Float # (Default: .85) ;mon osd nearfull ratio = .85 ### http://ceph.com/docs/next/rados/troubleshooting/log-and-debug/ # logging, for debugging monitor crashes, in order of # their likelihood of being helpful :) ;debug ms = 1 ;debug mon = 20 ;debug paxos = 20 ;debug auth = 20 ;[mon.alpha] ; host = alpha ; mon addr = 192.168.0.10:6789 ;[mon.beta] ; host = beta ; mon addr = 192.168.0.11:6789 ;[mon.gamma] ; host = gamma ; mon addr = 192.168.0.12:6789 ################## ## Metadata servers # You must deploy at least one metadata server to use CephFS. There is # experimental support for running multiple metadata servers. Do not run # multiple metadata servers in production. [mds] ### http://ceph.com/docs/argonaut/config-ref/mds-config/ ### http://ceph.com/docs/master/cephfs/mds-config-ref/ # where the mds keeps it's secret encryption keys ;keyring = /var/lib/ceph/mds/$name/keyring ; mds logging to debug issues. ;debug ms = 1 ;debug mds = 20 ;[mds.alpha] ; host = alpha ;[mds.beta] ; host = beta ################## ## osd # You need at least one. Two or more if you want data to be replicated. # Define as many as you like. [osd] ### http://ceph.com/docs/argonaut/config-ref/osd-config/ ### http://ceph.com/docs/bobtail/rados/configuration/osd-config-ref/ # The path to the OSDs data. # You must create the directory when deploying Ceph. # You should mount a drive for OSD data at this mount point. # We do not recommend changing the default. # Type: String # Default: /var/lib/ceph/osd/$cluster-$id ;osd data = /var/lib/ceph/osd/$name ## You can change the number of recovery operations to speed up recovery ## or slow it down if your machines can't handle it # The number of active recovery requests per OSD at one time. # More requests will accelerate recovery, but the requests # places an increased load on the cluster. # Type: 32-bit Integer # (Default: 5) ;osd recovery max active = 3 # You may add settings for mkcephfs so that it will create and mount # the file system for you. Remove the comment `#` character for # the following settings and replace the values in parenthesis # with appropriate values, or leave the following settings commented # out to accept the default values. You must specify the --mkfs # option with mkcephfs in order for the deployment script to # utilize the following settings, and you must define the 'devs' # option for each osd instance; see below. #osd mkfs type = {fs-type} #osd mkfs options {fs-type} = {mkfs options} # default for xfs is "-f" #osd mount options {fs-type} = {mount options} # default mount option is "rw, noatime" ;osd mkfs type = btrfs ;osd mount options btrfs = noatime,nodiratime ## Ideally, make this a separate disk or partition. A few ## hundred MB should be enough; more if you have fast or many ## disks. You can use a file under the osd data dir if need be ## (e.g. /data/$name/journal), but it will be slower than a ## separate disk or partition. # The path to the OSD’s journal. This may be a path to a file or a block # device (such as a partition of an SSD). If it is a file, you must # create the directory to contain it. # We recommend using a drive separate from the osd data drive. # Type: String # Default: /var/lib/ceph/osd/$cluster-$id/journal ;osd journal = /var/lib/ceph/osd/$name/journal ### http://ceph.com/docs/master/rados/configuration/journal-ref/ # The size of the journal in megabytes. If this is 0, # and the journal is a block device, the entire block device is used. # Since v0.54, this is ignored if the journal is a block device, # and the entire block device is used. # Type: 32-bit Integer # (Default: 5120) # Recommended: Begin with 1GB. Should be at least twice the product # of the expected speed multiplied by "filestore max sync interval". ;osd journal size = 1000 ; journal size, in megabytes ## If you want to run the journal on a tmpfs, disable DirectIO # Enables direct i/o to the journal. # Requires journal block align set to true. # Type: Boolean # Required: Yes when using aio. # (Default: true) ;journal dio = false # Check log files for corruption. Can be computationally expensive. # Type: Boolean # (Default: false) ;osd check for log corruption = true # osd logging to debug osd issues, in order of likelihood of being helpful ;debug ms = 1 ;debug osd = 20 ;debug filestore = 20 ;debug journal = 20 ;[osd.0] ; host = delta # If 'devs' is not specified, you're responsible for # setting up the 'osd data' dir (e.g. `mkdir /var/lib/ceph/osd/ceph-0`) ;devs = /dev/sdx ;[osd.1] ; host = epsilon ; devs = /dev/sdy ;[osd.2] ; host = zeta ; devs = /dev/sdx ;[osd.3] ; host = eta ; devs = /dev/sdy ceph-0.80.11/src/verify-mds-journal.sh0000775000175100017510000000022312623076744021555 0ustar jenkins-buildjenkins-build#!/bin/bash while [ 1 ] do ./ceph-mds -f --debug_mds 20 --debug_ms 1 --standby_replay_for 0 || exit 1 echo replay ok, sleeping sleep 30 doneceph-0.80.11/src/libcephfs.cc0000664000175100017510000011314512623076744017737 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "auth/Crypto.h" #include "client/Client.h" #include "include/cephfs/libcephfs.h" #include "common/Mutex.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/config.h" #include "common/version.h" #include "mon/MonClient.h" #include "include/str_list.h" #include "messages/MMonMap.h" #include "msg/Messenger.h" #include "include/assert.h" struct ceph_mount_info { public: ceph_mount_info(CephContext *cct_) : mounted(false), inited(false), client(NULL), monclient(NULL), messenger(NULL), cct(cct_) { } ~ceph_mount_info() { try { shutdown(); if (cct) { cct->put(); cct = NULL; } } catch (const std::exception& e) { // we shouldn't get here, but if we do, we want to know about it. lderr(cct) << "ceph_mount_info::~ceph_mount_info: caught exception: " << e.what() << dendl; } catch (...) { // ignore } } int mount(const std::string &mount_root) { int ret; if (mounted) return -EISCONN; common_init_finish(cct); //monmap monclient = new MonClient(cct); ret = -1000; if (monclient->build_initial_monmap() < 0) goto fail; //network connection messenger = Messenger::create_client_messenger(cct, "client"); //at last the client ret = -1002; client = new Client(messenger, monclient); if (!client) goto fail; ret = -1003; if (messenger->start() != 0) goto fail; ret = client->init(); if (ret) goto fail; inited = true; ret = client->mount(mount_root); if (ret) goto fail; mounted = true; return 0; fail: shutdown(); return ret; } int unmount() { if (!mounted) return -ENOTCONN; shutdown(); return 0; } void shutdown() { if (mounted) { client->unmount(); mounted = false; } if (inited) { client->shutdown(); inited = false; } if (messenger) { messenger->shutdown(); messenger->wait(); delete messenger; messenger = NULL; } if (monclient) { delete monclient; monclient = NULL; } if (client) { delete client; client = NULL; } } bool is_mounted() { return mounted; } int conf_read_file(const char *path_list) { std::deque parse_errors; int ret = cct->_conf->parse_config_files(path_list, &parse_errors, NULL, 0); if (ret) return ret; cct->_conf->apply_changes(NULL); complain_about_parse_errors(cct, &parse_errors); return 0; } int conf_parse_argv(int argc, const char **argv) { int ret; vector args; argv_to_vec(argc, argv, args); ret = cct->_conf->parse_argv(args); if (ret) return ret; cct->_conf->apply_changes(NULL); return 0; } int conf_parse_env(const char *name) { md_config_t *conf = cct->_conf; vector args; env_to_vec(args, name); int ret = conf->parse_argv(args); if (ret) return ret; conf->apply_changes(NULL); return 0; } int conf_set(const char *option, const char *value) { int ret = cct->_conf->set_val(option, value); if (ret) return ret; cct->_conf->apply_changes(NULL); return 0; } int conf_get(const char *option, char *buf, size_t len) { char *tmp = buf; return cct->_conf->get_val(option, &tmp, len); } Client *get_client() { return client; } const char *get_cwd() { client->getcwd(cwd); return cwd.c_str(); } CephContext *get_ceph_context() const { return cct; } private: bool mounted; bool inited; Client *client; MonClient *monclient; Messenger *messenger; CephContext *cct; std::string cwd; }; extern "C" const char *ceph_version(int *pmajor, int *pminor, int *ppatch) { int major, minor, patch; const char *v = ceph_version_to_str(); int n = sscanf(v, "%d.%d.%d", &major, &minor, &patch); if (pmajor) *pmajor = (n >= 1) ? major : 0; if (pminor) *pminor = (n >= 2) ? minor : 0; if (ppatch) *ppatch = (n >= 3) ? patch : 0; return VERSION; } extern "C" int ceph_create_with_context(struct ceph_mount_info **cmount, CephContext *cct) { *cmount = new struct ceph_mount_info(cct); return 0; } extern "C" int ceph_create(struct ceph_mount_info **cmount, const char * const id) { CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT); if (id) { iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id); } CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0); cct->_conf->parse_env(); // environment variables coverride cct->_conf->apply_changes(NULL); return ceph_create_with_context(cmount, cct); } extern "C" int ceph_unmount(struct ceph_mount_info *cmount) { return cmount->unmount(); } extern "C" int ceph_release(struct ceph_mount_info *cmount) { if (cmount->is_mounted()) return -EISCONN; delete cmount; return 0; } extern "C" void ceph_shutdown(struct ceph_mount_info *cmount) { cmount->shutdown(); delete cmount; } extern "C" int ceph_conf_read_file(struct ceph_mount_info *cmount, const char *path) { return cmount->conf_read_file(path); } extern "C" int ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc, const char **argv) { return cmount->conf_parse_argv(argc, argv); } extern "C" int ceph_conf_parse_env(struct ceph_mount_info *cmount, const char *name) { return cmount->conf_parse_env(name); } extern "C" int ceph_conf_set(struct ceph_mount_info *cmount, const char *option, const char *value) { return cmount->conf_set(option, value); } extern "C" int ceph_conf_get(struct ceph_mount_info *cmount, const char *option, char *buf, size_t len) { if (buf == NULL) { return -EINVAL; } return cmount->conf_get(option, buf, len); } extern "C" int ceph_mount(struct ceph_mount_info *cmount, const char *root) { std::string mount_root; if (root) mount_root = root; return cmount->mount(mount_root); } extern "C" int ceph_is_mounted(struct ceph_mount_info *cmount) { return cmount->is_mounted() ? 1 : 0; } extern "C" int ceph_statfs(struct ceph_mount_info *cmount, const char *path, struct statvfs *stbuf) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->statfs(path, stbuf); } extern "C" int ceph_get_local_osd(struct ceph_mount_info *cmount) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->get_local_osd(); } extern "C" const char* ceph_getcwd(struct ceph_mount_info *cmount) { return cmount->get_cwd(); } extern "C" int ceph_chdir (struct ceph_mount_info *cmount, const char *s) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->chdir(s); } extern "C" int ceph_opendir(struct ceph_mount_info *cmount, const char *name, struct ceph_dir_result **dirpp) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->opendir(name, (dir_result_t **)dirpp); } extern "C" int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->closedir((dir_result_t*)dirp); } extern "C" struct dirent * ceph_readdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp) { if (!cmount->is_mounted()) { /* Client::readdir also sets errno to signal errors. */ errno = -ENOTCONN; return NULL; } return cmount->get_client()->readdir((dir_result_t*)dirp); } extern "C" int ceph_readdir_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->readdir_r((dir_result_t*)dirp, de); } extern "C" int ceph_readdirplus_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de, struct stat *st, int *stmask) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->readdirplus_r((dir_result_t*)dirp, de, st, stmask); } extern "C" int ceph_getdents(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, char *buf, int buflen) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->getdents((dir_result_t*)dirp, buf, buflen); } extern "C" int ceph_getdnames(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, char *buf, int buflen) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->getdnames((dir_result_t*)dirp, buf, buflen); } extern "C" void ceph_rewinddir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp) { if (!cmount->is_mounted()) return; cmount->get_client()->rewinddir((dir_result_t*)dirp); } extern "C" int64_t ceph_telldir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->telldir((dir_result_t*)dirp); } extern "C" void ceph_seekdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, int64_t offset) { if (!cmount->is_mounted()) return; cmount->get_client()->seekdir((dir_result_t*)dirp, offset); } extern "C" int ceph_link (struct ceph_mount_info *cmount, const char *existing, const char *newname) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->link(existing, newname); } extern "C" int ceph_unlink(struct ceph_mount_info *cmount, const char *path) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->unlink(path); } extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from, const char *to) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->rename(from, to); } // dirs extern "C" int ceph_mkdir(struct ceph_mount_info *cmount, const char *path, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->mkdir(path, mode); } extern "C" int ceph_mkdirs(struct ceph_mount_info *cmount, const char *path, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->mkdirs(path, mode); } extern "C" int ceph_rmdir(struct ceph_mount_info *cmount, const char *path) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->rmdir(path); } // symlinks extern "C" int ceph_readlink(struct ceph_mount_info *cmount, const char *path, char *buf, int64_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->readlink(path, buf, size); } extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing, const char *newname) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->symlink(existing, newname); } // inode stuff extern "C" int ceph_stat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->stat(path, stbuf); } extern "C" int ceph_lstat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->lstat(path, stbuf); } extern "C" int ceph_setattr(struct ceph_mount_info *cmount, const char *relpath, struct stat *attr, int mask) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->setattr(relpath, attr, mask); } // *xattr() calls supporting samba/vfs extern "C" int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->getxattr(path, name, value, size); } extern "C" int ceph_lgetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->lgetxattr(path, name, value, size); } extern "C" int ceph_listxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->listxattr(path, list, size); } extern "C" int ceph_llistxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->llistxattr(path, list, size); } extern "C" int ceph_removexattr(struct ceph_mount_info *cmount, const char *path, const char *name) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->removexattr(path, name); } extern "C" int ceph_lremovexattr(struct ceph_mount_info *cmount, const char *path, const char *name) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->lremovexattr(path, name); } extern "C" int ceph_setxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->setxattr(path, name, value, size, flags); } extern "C" int ceph_lsetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->lsetxattr(path, name, value, size, flags); } /* end xattr support */ extern "C" int ceph_chmod(struct ceph_mount_info *cmount, const char *path, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->chmod(path, mode); } extern "C" int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->fchmod(fd, mode); } extern "C" int ceph_chown(struct ceph_mount_info *cmount, const char *path, int uid, int gid) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->chown(path, uid, gid); } extern "C" int ceph_fchown(struct ceph_mount_info *cmount, int fd, int uid, int gid) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->fchown(fd, uid, gid); } extern "C" int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int gid) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->lchown(path, uid, gid); } extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path, struct utimbuf *buf) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->utime(path, buf); } extern "C" int ceph_truncate(struct ceph_mount_info *cmount, const char *path, int64_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->truncate(path, size); } // file ops extern "C" int ceph_mknod(struct ceph_mount_info *cmount, const char *path, mode_t mode, dev_t rdev) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->mknod(path, mode, rdev); } extern "C" int ceph_open(struct ceph_mount_info *cmount, const char *path, int flags, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->open(path, flags, mode); } extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags, mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->open(path, flags, mode, stripe_unit, stripe_count, object_size, data_pool); } extern "C" int ceph_close(struct ceph_mount_info *cmount, int fd) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->close(fd); } extern "C" int64_t ceph_lseek(struct ceph_mount_info *cmount, int fd, int64_t offset, int whence) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->lseek(fd, offset, whence); } extern "C" int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf, int64_t size, int64_t offset) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->read(fd, buf, size, offset); } extern "C" int ceph_write(struct ceph_mount_info *cmount, int fd, const char *buf, int64_t size, int64_t offset) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->write(fd, buf, size, offset); } extern "C" int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t size) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->ftruncate(fd, size); } extern "C" int ceph_fsync(struct ceph_mount_info *cmount, int fd, int syncdataonly) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->fsync(fd, syncdataonly); } extern "C" int ceph_fallocate(struct ceph_mount_info *cmount, int fd, int mode, int64_t offset, int64_t length) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->fallocate(fd, mode, offset, length); } extern "C" int ceph_fstat(struct ceph_mount_info *cmount, int fd, struct stat *stbuf) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->fstat(fd, stbuf); } extern "C" int ceph_sync_fs(struct ceph_mount_info *cmount) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->sync_fs(); } extern "C" int ceph_get_file_stripe_unit(struct ceph_mount_info *cmount, int fh) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; return l.fl_stripe_unit; } extern "C" int ceph_get_path_stripe_unit(struct ceph_mount_info *cmount, const char *path) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; return l.fl_stripe_unit; } extern "C" int ceph_get_file_stripe_count(struct ceph_mount_info *cmount, int fh) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; return l.fl_stripe_count; } extern "C" int ceph_get_path_stripe_count(struct ceph_mount_info *cmount, const char *path) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; return l.fl_stripe_count; } extern "C" int ceph_get_file_object_size(struct ceph_mount_info *cmount, int fh) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; return l.fl_object_size; } extern "C" int ceph_get_path_object_size(struct ceph_mount_info *cmount, const char *path) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; return l.fl_object_size; } extern "C" int ceph_get_file_pool(struct ceph_mount_info *cmount, int fh) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; return l.fl_pg_pool; } extern "C" int ceph_get_path_pool(struct ceph_mount_info *cmount, const char *path) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; return l.fl_pg_pool; } extern "C" int ceph_get_file_pool_name(struct ceph_mount_info *cmount, int fh, char *buf, size_t len) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; string name = cmount->get_client()->get_pool_name(l.fl_pg_pool); if (len == 0) return name.length(); if (name.length() > len) return -ERANGE; strncpy(buf, name.c_str(), len); return name.length(); } extern "C" int ceph_get_pool_name(struct ceph_mount_info *cmount, int pool, char *buf, size_t len) { if (!cmount->is_mounted()) return -ENOTCONN; string name = cmount->get_client()->get_pool_name(pool); if (len == 0) return name.length(); if (name.length() > len) return -ERANGE; strncpy(buf, name.c_str(), len); return name.length(); } extern "C" int ceph_get_path_pool_name(struct ceph_mount_info *cmount, const char *path, char *buf, size_t len) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; string name = cmount->get_client()->get_pool_name(l.fl_pg_pool); if (len == 0) return name.length(); if (name.length() > len) return -ERANGE; strncpy(buf, name.c_str(), len); return name.length(); } extern "C" int ceph_get_file_layout(struct ceph_mount_info *cmount, int fh, int *stripe_unit, int *stripe_count, int *object_size, int *pg_pool) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; if (stripe_unit) *stripe_unit = l.fl_stripe_unit; if (stripe_count) *stripe_count = l.fl_stripe_count; if (object_size) *object_size = l.fl_object_size; if (pg_pool) *pg_pool = l.fl_pg_pool; return 0; } extern "C" int ceph_get_path_layout(struct ceph_mount_info *cmount, const char *path, int *stripe_unit, int *stripe_count, int *object_size, int *pg_pool) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; if (stripe_unit) *stripe_unit = l.fl_stripe_unit; if (stripe_count) *stripe_count = l.fl_stripe_count; if (object_size) *object_size = l.fl_object_size; if (pg_pool) *pg_pool = l.fl_pg_pool; return 0; } extern "C" int ceph_get_file_replication(struct ceph_mount_info *cmount, int fh) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->fdescribe_layout(fh, &l); if (r < 0) return r; int rep = cmount->get_client()->get_pool_replication(l.fl_pg_pool); return rep; } extern "C" int ceph_get_path_replication(struct ceph_mount_info *cmount, const char *path) { struct ceph_file_layout l; int r; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->describe_layout(path, &l); if (r < 0) return r; int rep = cmount->get_client()->get_pool_replication(l.fl_pg_pool); return rep; } extern "C" int ceph_set_default_file_stripe_unit(struct ceph_mount_info *cmount, int stripe) { // this option no longer exists return -EOPNOTSUPP; } extern "C" int ceph_set_default_file_stripe_count(struct ceph_mount_info *cmount, int count) { // this option no longer exists return -EOPNOTSUPP; } extern "C" int ceph_set_default_object_size(struct ceph_mount_info *cmount, int size) { // this option no longer exists return -EOPNOTSUPP; } extern "C" int ceph_set_default_file_replication(struct ceph_mount_info *cmount, int replication) { // this option no longer exists return -EOPNOTSUPP; } extern "C" int ceph_set_default_preferred_pg(struct ceph_mount_info *cmount, int osd) { // this option no longer exists return -EOPNOTSUPP; } extern "C" int ceph_get_file_extent_osds(struct ceph_mount_info *cmount, int fh, int64_t offset, int64_t *length, int *osds, int nosds) { if (nosds < 0) return -EINVAL; if (!cmount->is_mounted()) return -ENOTCONN; vector vosds; int ret = cmount->get_client()->get_file_extent_osds(fh, offset, length, vosds); if (ret < 0) return ret; if (!nosds) return vosds.size(); if ((int)vosds.size() > nosds) return -ERANGE; for (int i = 0; i < (int)vosds.size(); i++) osds[i] = vosds[i]; return vosds.size(); } extern "C" int ceph_get_osd_crush_location(struct ceph_mount_info *cmount, int osd, char *path, size_t len) { if (!cmount->is_mounted()) return -ENOTCONN; if (!path && len) return -EINVAL; vector > loc; int ret = cmount->get_client()->get_osd_crush_location(osd, loc); if (ret) return ret; size_t needed = 0; size_t cur = 0; vector >::iterator it; for (it = loc.begin(); it != loc.end(); ++it) { string& type = it->first; string& name = it->second; needed += type.size() + name.size() + 2; if (needed <= len) { strcpy(path + cur, type.c_str()); cur += type.size() + 1; strcpy(path + cur, name.c_str()); cur += name.size() + 1; } } if (len == 0) return needed; if (needed > len) return -ERANGE; return needed; } extern "C" int ceph_get_osd_addr(struct ceph_mount_info *cmount, int osd, struct sockaddr_storage *addr) { if (!cmount->is_mounted()) return -ENOTCONN; if (!addr) return -EINVAL; entity_addr_t address; int ret = cmount->get_client()->get_osd_addr(osd, address); if (ret < 0) return ret; memcpy(addr, &address.ss_addr(), sizeof(*addr)); return 0; } extern "C" int ceph_get_file_stripe_address(struct ceph_mount_info *cmount, int fh, int64_t offset, struct sockaddr_storage *addr, int naddr) { vector address; unsigned i; int r; if (naddr < 0) return -EINVAL; if (!cmount->is_mounted()) return -ENOTCONN; r = cmount->get_client()->get_file_stripe_address(fh, offset, address); if (r < 0) return r; for (i = 0; i < (unsigned)naddr && i < address.size(); i++) memcpy(&addr[i], &address[i].ss_addr(), sizeof(*addr)); /* naddr == 0: drop through and return actual size */ if (naddr && (address.size() > (unsigned)naddr)) return -ERANGE; return address.size(); } extern "C" int ceph_localize_reads(struct ceph_mount_info *cmount, int val) { if (!cmount->is_mounted()) return -ENOTCONN; if (!val) cmount->get_client()->clear_filer_flags(CEPH_OSD_FLAG_LOCALIZE_READS); else cmount->get_client()->set_filer_flags(CEPH_OSD_FLAG_LOCALIZE_READS); return 0; } extern "C" CephContext *ceph_get_mount_context(struct ceph_mount_info *cmount) { return cmount->get_ceph_context(); } extern "C" int ceph_debug_get_fd_caps(struct ceph_mount_info *cmount, int fd) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->get_caps_issued(fd); } extern "C" int ceph_debug_get_file_caps(struct ceph_mount_info *cmount, const char *path) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->get_caps_issued(path); } extern "C" int ceph_get_stripe_unit_granularity(struct ceph_mount_info *cmount) { if (!cmount->is_mounted()) return -ENOTCONN; return CEPH_MIN_STRIPE_UNIT; } extern "C" int ceph_get_pool_id(struct ceph_mount_info *cmount, const char *pool_name) { if (!cmount->is_mounted()) return -ENOTCONN; if (!pool_name || !pool_name[0]) return -EINVAL; /* negative range reserved for errors */ int64_t pool_id = cmount->get_client()->get_pool_id(pool_name); if (pool_id > 0x7fffffff) return -ERANGE; /* get_pool_id error codes fit in int */ return (int)pool_id; } extern "C" int ceph_get_pool_replication(struct ceph_mount_info *cmount, int pool_id) { if (!cmount->is_mounted()) return -ENOTCONN; return cmount->get_client()->get_pool_replication(pool_id); } /* Low-level exports */ extern "C" int ceph_ll_lookup_root(struct ceph_mount_info *cmount, Inode **parent) { *parent = cmount->get_client()->get_root(); if (*parent) return 0; return EFAULT; } extern "C" struct Inode *ceph_ll_get_inode(class ceph_mount_info *cmount, vinodeno_t vino) { return (cmount->get_client())->ll_get_inode(vino); } /** * Populates the client cache with the requested inode, and its * parent dentry. */ extern "C" int ceph_ll_lookup_inode( struct ceph_mount_info *cmount, struct inodeno_t ino, Inode **inode) { int r = (cmount->get_client())->lookup_ino(ino, inode); if (r) { return r; } if (inode) { assert(*inode != NULL); } // Request the parent inode, so that we can look up the name Inode *parent; r = (cmount->get_client())->lookup_parent(*inode, &parent); if (r && r != -EINVAL) { // Unexpected error (cmount->get_client())->ll_forget(*inode, 1); return r; } else if (r == -EINVAL) { // EINVAL indicates node without parents (root), drop out now // and don't try to look up the non-existent dentry. return 0; } assert(parent != NULL); // Finally, get the name (dentry) of the requested inode r = (cmount->get_client())->lookup_name(*inode, parent); if (r) { // Unexpected error (cmount->get_client())->ll_forget(parent, 1); (cmount->get_client())->ll_forget(*inode, 1); return r; } (cmount->get_client())->ll_forget(parent, 1); return 0; } extern "C" int ceph_ll_lookup(class ceph_mount_info *cmount, struct Inode *parent, const char *name, struct stat *attr, Inode **out, int uid, int gid) { return (cmount->get_client())->ll_lookup(parent, name, attr, out, uid, gid); } extern "C" int ceph_ll_put(class ceph_mount_info *cmount, Inode *in) { return (cmount->get_client()->ll_put(in)); } extern "C" int ceph_ll_forget(class ceph_mount_info *cmount, Inode *in, int count) { return (cmount->get_client()->ll_forget(in, count)); } extern "C" int ceph_ll_walk(class ceph_mount_info *cmount, const char *name, struct Inode **i, struct stat *attr) { return(cmount->get_client()->ll_walk(name, i, attr)); } extern "C" int ceph_ll_getattr(class ceph_mount_info *cmount, Inode *in, struct stat *attr, int uid, int gid) { return (cmount->get_client()->ll_getattr(in, attr, uid, gid)); } extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount, Inode *in, struct stat *st, int mask, int uid, int gid) { return (cmount->get_client()->ll_setattr(in, st, mask, uid, gid)); } extern "C" int ceph_ll_open(class ceph_mount_info *cmount, Inode *in, int flags, Fh **fh, int uid, int gid) { return (cmount->get_client()->ll_open(in, flags, fh, uid, gid)); } extern "C" int ceph_ll_read(class ceph_mount_info *cmount, Fh* filehandle, int64_t off, uint64_t len, char* buf) { bufferlist bl; int r = 0; r = cmount->get_client()->ll_read(filehandle, off, len, &bl); if (r >= 0) { bl.copy(0, bl.length(), buf); r = bl.length(); } return r; } extern "C" int ceph_ll_read_block(class ceph_mount_info *cmount, Inode *in, uint64_t blockid, char* buf, uint64_t offset, uint64_t length, struct ceph_file_layout* layout) { return (cmount->get_client()->ll_read_block(in, blockid, buf, offset, length, layout)); } extern "C" int ceph_ll_write_block(class ceph_mount_info *cmount, Inode *in, uint64_t blockid, char *buf, uint64_t offset, uint64_t length, struct ceph_file_layout *layout, uint64_t snapseq, uint32_t sync) { return (cmount->get_client()->ll_write_block(in, blockid, buf, offset, length, layout, snapseq, sync)); } extern "C" int ceph_ll_commit_blocks(class ceph_mount_info *cmount, Inode *in, uint64_t offset, uint64_t range) { return (cmount->get_client()->ll_commit_blocks(in, offset, range)); } extern "C" int ceph_ll_fsync(class ceph_mount_info *cmount, Fh *fh, int syncdataonly) { return (cmount->get_client()->ll_fsync(fh, syncdataonly)); } extern "C" loff_t ceph_ll_lseek(class ceph_mount_info *cmount, Fh *fh, loff_t offset, int whence) { return (cmount->get_client()->ll_lseek(fh, offset, whence)); } extern "C" int ceph_ll_write(class ceph_mount_info *cmount, Fh *fh, int64_t off, uint64_t len, const char *data) { return (cmount->get_client()->ll_write(fh, off, len, data)); } extern "C" int64_t ceph_ll_readv(class ceph_mount_info *cmount, struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off) { return -1; // TODO: implement } extern "C" int64_t ceph_ll_writev(class ceph_mount_info *cmount, struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off) { return -1; // TODO: implement } extern "C" int ceph_ll_close(class ceph_mount_info *cmount, Fh* fh) { return (cmount->get_client()->ll_release(fh)); } extern "C" int ceph_ll_create(class ceph_mount_info *cmount, struct Inode *parent, const char *name, mode_t mode, int flags, struct stat *attr, struct Inode **out, Fh **fhp, int uid, int gid) { return (cmount->get_client())->ll_create(parent, name, mode, flags, attr, out, fhp, uid, gid); } extern "C" int ceph_ll_mkdir(class ceph_mount_info *cmount, Inode *parent, const char *name, mode_t mode, struct stat *attr, Inode **out, int uid, int gid) { return (cmount->get_client()->ll_mkdir(parent, name, mode, attr, out, uid, gid)); } extern "C" int ceph_ll_link(class ceph_mount_info *cmount, Inode *in, Inode *newparent, const char *name, struct stat *attr, int uid, int gid) { return (cmount->get_client()->ll_link(in, newparent, name, attr, uid, gid)); } extern "C" int ceph_ll_truncate(class ceph_mount_info *cmount, Inode *in, uint64_t length, int uid, int gid) { struct stat st; st.st_size=length; return(cmount->get_client()->ll_setattr(in, &st, CEPH_SETATTR_SIZE, uid, gid)); } extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount, Inode *in, struct ceph_dir_result **dirpp, int uid, int gid) { return (cmount->get_client()->ll_opendir(in, (dir_result_t**) dirpp, uid, gid)); } extern "C" int ceph_ll_releasedir(class ceph_mount_info *cmount, ceph_dir_result *dir) { (void) cmount->get_client()->ll_releasedir((dir_result_t*) dir); return (0); } extern "C" int ceph_ll_rename(class ceph_mount_info *cmount, Inode *parent, const char *name, Inode *newparent, const char *newname, int uid, int gid) { return (cmount->get_client()->ll_rename(parent, name, newparent, newname, uid, gid)); } extern "C" int ceph_ll_unlink(class ceph_mount_info *cmount, Inode *in, const char *name, int uid, int gid) { return (cmount->get_client()->ll_unlink(in, name, uid, gid)); } extern "C" int ceph_ll_statfs(class ceph_mount_info *cmount, Inode *in, struct statvfs *stbuf) { return (cmount->get_client()->ll_statfs(in, stbuf)); } extern "C" int ceph_ll_readlink(class ceph_mount_info *cmount, Inode *in, char *buf, size_t bufsiz, int uid, int gid) { return (cmount->get_client()->ll_readlink(in, buf, bufsiz, uid, gid)); } extern "C" int ceph_ll_symlink(class ceph_mount_info *cmount, Inode *in, const char *name, const char *value, struct stat *attr, Inode **out, int uid, int gid) { return (cmount->get_client()->ll_symlink(in, name, value, attr, out, uid, gid)); } extern "C" int ceph_ll_rmdir(class ceph_mount_info *cmount, Inode *in, const char *name, int uid, int gid) { return (cmount->get_client()->ll_rmdir(in, name, uid, gid)); } extern "C" int ceph_ll_getxattr(class ceph_mount_info *cmount, Inode *in, const char *name, void *value, size_t size, int uid, int gid) { return (cmount->get_client()->ll_getxattr(in, name, value, size, uid, gid)); } extern "C" int ceph_ll_listxattr(struct ceph_mount_info *cmount, Inode *in, char *list, size_t buf_size, size_t *list_size, int uid, int gid) { int res = cmount->get_client()->ll_listxattr(in, list, buf_size, uid, gid); if (res >= 0) { *list_size = (size_t)res; return 0; } return res; } extern "C" int ceph_ll_setxattr(class ceph_mount_info *cmount, Inode *in, const char *name, const void *value, size_t size, int flags, int uid, int gid) { return (cmount->get_client()->ll_setxattr(in, name, value, size, flags, uid, gid)); } extern "C" int ceph_ll_removexattr(class ceph_mount_info *cmount, Inode *in, const char *name, int uid, int gid) { return (cmount->get_client()->ll_removexattr(in, name, uid, gid)); } extern "C" uint32_t ceph_ll_stripe_unit(class ceph_mount_info *cmount, Inode *in) { return (cmount->get_client()->ll_stripe_unit(in)); } extern "C" uint32_t ceph_ll_file_layout(class ceph_mount_info *cmount, Inode *in, struct ceph_file_layout *layout) { return (cmount->get_client()->ll_file_layout(in, layout)); } uint64_t ceph_ll_snap_seq(class ceph_mount_info *cmount, Inode *in) { return (cmount->get_client()->ll_snap_seq(in)); } extern "C" int ceph_ll_get_stripe_osd(class ceph_mount_info *cmount, Inode *in, uint64_t blockno, struct ceph_file_layout* layout) { return (cmount->get_client()->ll_get_stripe_osd(in, blockno, layout)); } extern "C" int ceph_ll_num_osds(class ceph_mount_info *cmount) { return (cmount->get_client()->ll_num_osds()); } extern "C" int ceph_ll_osdaddr(class ceph_mount_info *cmount, int osd, uint32_t *addr) { return (cmount->get_client()->ll_osdaddr(osd, addr)); } extern "C" uint64_t ceph_ll_get_internal_offset(class ceph_mount_info *cmount, Inode *in, uint64_t blockno) { return (cmount->get_client()->ll_get_internal_offset(in, blockno)); } ceph-0.80.11/src/ceph-disk-activate0000775000175100017510000000006612623076744021061 0ustar jenkins-buildjenkins-build#!/bin/sh dir=`dirname $0` $dir/ceph-disk activate $* ceph-0.80.11/src/librados-config.cc0000664000175100017510000000350512623076744021040 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/config.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "global/global_context.h" #include "include/rados/librados.h" void usage() { cout << "usage: librados-config [option]\n" << "where options are:\n" << " --version library version\n" << " --vernum library version code\n"; } void usage_exit() { usage(); exit(1); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); bool opt_version = false; bool opt_vernum = false; global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (strcmp(*i, "--") == 0) { break; } else if (strcmp(*i, "--version") == 0) { opt_version = true; i = args.erase(i); } else if (strcmp(*i, "--vernum") == 0) { opt_vernum = true; i = args.erase(i); } else ++i; } if (!opt_version && !opt_vernum) usage_exit(); if (opt_version) { int maj, min, ext; rados_version(&maj, &min, &ext); cout << maj << "." << min << "." << ext << std::endl; } else if (opt_vernum) { cout << hex << LIBRADOS_VERSION_CODE << dec << std::endl; } return 0; } ceph-0.80.11/src/cls_acl.cc0000664000175100017510000000214412623076744017374 0ustar jenkins-buildjenkins-build #include #include #include #include #include #include #include "include/types.h" #include "objclass/objclass.h" CLS_VER(1,0) CLS_NAME(acl) cls_handle_t h_class; cls_method_handle_t h_get; cls_method_handle_t h_set; int get_method(cls_method_context_t ctx, char *indata, int datalen, char **outdata, int *outdatalen) { MD5_CTX c; cls_log("acl test method"); cls_log("indata=%.*s data_len=%d", datalen, indata, datalen); cls_getxattr(ctx, "acls", outdata, outdatalen); return 0; } int set_method(cls_method_context_t ctx, char *indata, int datalen, char **outdata, int *outdatalen) { MD5_CTX c; cls_log("acl test method"); cls_log("indata=%.*s data_len=%d", datalen, indata, datalen); cls_setxattr(ctx, "acls", indata, datalen); return 0; } void __cls_init() { cls_log("Loaded acl class!"); cls_register("acl", &h_class); cls_register_method(h_class, "get", CLS_METHOD_RD, get_method, &h_get); cls_register_method(h_class, "set", CLS_METHOD_WR, set_method, &h_set); return; } ceph-0.80.11/src/key_value_store/0000775000175100017510000000000012623077035020656 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/key_value_store/cls_kvs.cc0000664000175100017510000004605112623076744022645 0ustar jenkins-buildjenkins-build/* * OSD classes for the key value store * * Created on: Aug 10, 2012 * Author: Eleanor Cawthon */ #include "objclass/objclass.h" #include #include "key_value_store/kvs_arg_types.h" #include "include/types.h" #include #include cls_handle_t h_class; cls_method_handle_t h_get_idata_from_key; cls_method_handle_t h_get_next_idata; cls_method_handle_t h_get_prev_idata; cls_method_handle_t h_read_many; cls_method_handle_t h_check_writable; cls_method_handle_t h_assert_size_in_bound; cls_method_handle_t h_omap_insert; cls_method_handle_t h_create_with_omap; cls_method_handle_t h_omap_remove; cls_method_handle_t h_maybe_read_for_balance; /** * finds the index_data where a key belongs. * * @param key: the key to search for * @param idata: the index_data for the first index value such that idata.key * is greater than key. * @param next_idata: the index_data for the next index entry after idata * @pre: key is not encoded * @post: idata contains complete information * stored */ static int get_idata_from_key(cls_method_context_t hctx, const string &key, index_data &idata, index_data &next_idata) { bufferlist raw_val; int r = 0; std::map kvmap; r = cls_cxx_map_get_vals(hctx, key_data(key).encoded(), "", 2, &kvmap); if (r < 0) { CLS_LOG(20, "error reading index for range %s: %d", key.c_str(), r); return r; } r = cls_cxx_map_get_val(hctx, key_data(key).encoded(), &raw_val); if (r == 0){ CLS_LOG(20, "%s is already in the index: %d", key.c_str(), r); bufferlist::iterator b = raw_val.begin(); idata.decode(b); if (!kvmap.empty()) { bufferlist::iterator b = kvmap.begin()->second.begin(); next_idata.decode(b); } return r; } else if (r == -ENOENT || r == -ENODATA) { bufferlist::iterator b = kvmap.begin()->second.begin(); idata.decode(b); if (idata.kdata.prefix != "1") { bufferlist::iterator nb = (++kvmap.begin())->second.begin(); next_idata.decode(nb); } r = 0; } else if (r < 0) { CLS_LOG(20, "error reading index for duplicates %s: %d", key.c_str(), r); return r; } CLS_LOG(20, "idata is %s", idata.str().c_str()); return 0; } static int get_idata_from_key_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "get_idata_from_key_op"); idata_from_key_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { CLS_LOG(20, "error decoding idata_from_key_args."); return -EINVAL; } int r = get_idata_from_key(hctx, op.key, op.idata, op.next_idata); if (r < 0) { return r; } else { ::encode(op, *out); return 0; } } /** * finds the object in the index with the lowest key value that is greater * than idata.key. If idata.key is the max key, returns -EOVERFLOW. If * idata has a prefix and has timed out, cleans up. * * @param idata: idata for the object to search for. * @param out_data: the idata for the next object. * * @pre: idata must contain a key. * @post: out_data contains complete information */ static int get_next_idata(cls_method_context_t hctx, const index_data &idata, index_data &out_data) { int r = 0; std::map kvs; r = cls_cxx_map_get_vals(hctx, idata.kdata.encoded(), "", 1, &kvs); if (r < 0){ CLS_LOG(20, "getting kvs failed with error %d", r); return r; } if (!kvs.empty()) { out_data.kdata.parse(kvs.begin()->first); bufferlist::iterator b = kvs.begin()->second.begin(); out_data.decode(b); } else { r = -EOVERFLOW; } return r; } static int get_next_idata_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "get_next_idata_op"); idata_from_idata_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { return -EINVAL; } int r = get_next_idata(hctx, op.idata, op.next_idata); if (r < 0) { return r; } else { op.encode(*out); return 0; } } /** * finds the object in the index with the highest key value that is less * than idata.key. If idata.key is the lowest key, returns -ERANGE If * idata has a prefix and has timed out, cleans up. * * @param idata: idata for the object to search for. * @param out_data: the idata for the next object. * * @pre: idata must contain a key. * @ost: out_data contains complete information */ static int get_prev_idata(cls_method_context_t hctx, const index_data &idata, index_data &out_data) { int r = 0; std::map kvs; r = cls_cxx_map_get_vals(hctx, "", "", LONG_MAX, &kvs); if (r < 0){ CLS_LOG(20, "getting kvs failed with error %d", r); return r; } std::map::iterator it = kvs.lower_bound(idata.kdata.encoded()); if (it->first != idata.kdata.encoded()) { CLS_LOG(20, "object %s not found in the index (expected %s, found %s)", idata.str().c_str(), idata.kdata.encoded().c_str(), it->first.c_str()); return -ENODATA; } if (it == kvs.begin()) { //it is the first object, there is no previous. return -ERANGE; } else { --it; } out_data.kdata.parse(it->first); bufferlist::iterator b = it->second.begin(); out_data.decode(b); return 0; } static int get_prev_idata_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "get_next_idata_op"); idata_from_idata_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { return -EINVAL; } int r = get_prev_idata(hctx, op.idata, op.next_idata); if (r < 0) { return r; } else { op.encode(*out); return 0; } } /** * Read all of the index entries where any keys in the map go */ static int read_many(cls_method_context_t hctx, const set &keys, map * out) { int r = 0; CLS_ERR("reading from a map of size %d, first key encoded is %s", (int)keys.size(), key_data(*keys.begin()).encoded().c_str()); r = cls_cxx_map_get_vals(hctx, key_data(*keys.begin()).encoded().c_str(), "", LONG_MAX, out); if (r < 0) { CLS_ERR("getting omap vals failed with error %d", r); } CLS_ERR("got map of size %d ", (int)out->size()); if (out->size() > 1) { out->erase(out->upper_bound(key_data(*keys.rbegin()).encoded().c_str()), out->end()); } CLS_ERR("returning map of size %d", (int)out->size()); return r; } static int read_many_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "read_many_op"); set op; map outmap; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error & err) { return -EINVAL; } int r = read_many(hctx, op, &outmap); if (r < 0) { return r; } else { encode(outmap, *out); return 0; } } /** * Checks the unwritable xattr. If it is "1" (i.e., it is unwritable), returns * -EACCES. otherwise, returns 0. */ static int check_writable(cls_method_context_t hctx) { bufferlist bl; int r = cls_cxx_getxattr(hctx, "unwritable", &bl); if (r < 0) { CLS_LOG(20, "error reading xattr %s: %d", "unwritable", r); return r; } if (string(bl.c_str(), bl.length()) == "1") { return -EACCES; } else{ return 0; } } static int check_writable_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "check_writable_op"); return check_writable(hctx); } /** * returns -EKEYREJECTED if size is outside of bound, according to comparator. * * @bound: the limit to test * @comparator: should be CEPH_OSD_CMPXATTR_OP_[EQ|GT|LT] */ static int assert_size_in_bound(cls_method_context_t hctx, int bound, int comparator) { //determine size bufferlist size_bl; int r = cls_cxx_getxattr(hctx, "size", &size_bl); if (r < 0) { CLS_LOG(20, "error reading xattr %s: %d", "size", r); return r; } int size = atoi(string(size_bl.c_str(), size_bl.length()).c_str()); CLS_LOG(20, "size is %d, bound is %d", size, bound); //compare size to comparator switch (comparator) { case CEPH_OSD_CMPXATTR_OP_EQ: if (size != bound) { return -EKEYREJECTED; } break; case CEPH_OSD_CMPXATTR_OP_LT: if (size >= bound) { return -EKEYREJECTED; } break; case CEPH_OSD_CMPXATTR_OP_GT: if (size <= bound) { return -EKEYREJECTED; } break; default: CLS_LOG(20, "invalid argument passed to assert_size_in_bound: %d", comparator); return -EINVAL; } return 0; } static int assert_size_in_bound_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "assert_size_in_bound_op"); assert_size_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { return -EINVAL; } return assert_size_in_bound(hctx, op.bound, op.comparator); } /** * Attempts to insert omap into this object's omap. * * @return: * if unwritable, returns -EACCES. * if size > bound and key doesn't already exist in the omap, returns -EBALANCE. * if exclusive is true, returns -EEXIST if any keys already exist. * * @post: object has omap entries inserted, and size xattr is updated */ static int omap_insert(cls_method_context_t hctx, const map &omap, int bound, bool exclusive) { uint64_t size; time_t time; int r = cls_cxx_stat(hctx, &size, &time); if (r < 0) { return r; } CLS_LOG(20, "inserting %s", omap.begin()->first.c_str()); r = check_writable(hctx); if (r < 0) { CLS_LOG(20, "omap_insert: this object is unwritable: %d", r); return r; } int assert_bound = bound; //if this is an exclusive insert, make sure the key doesn't already exist. for (map::const_iterator it = omap.begin(); it != omap.end(); ++it) { bufferlist bl; r = cls_cxx_map_get_val(hctx, it->first, &bl); if (r == 0 && string(bl.c_str(), bl.length()) != ""){ if (exclusive) { CLS_LOG(20, "error: this is an exclusive insert and %s exists.", it->first.c_str()); return -EEXIST; } assert_bound++; CLS_LOG(20, "increased assert_bound to %d", assert_bound); } else if (r != -ENODATA && r != -ENOENT) { CLS_LOG(20, "error reading omap val for %s: %d", it->first.c_str(), r); return r; } } r = 0; bufferlist old_size; r = cls_cxx_getxattr(hctx, "size", &old_size); if (r < 0) { CLS_LOG(20, "error reading xattr %s: %d", "size", r); return r; } int old_size_int = atoi(string(old_size.c_str(), old_size.length()).c_str()); CLS_LOG(20, "asserting size is less than %d (bound is %d)", assert_bound, bound); if (old_size_int >= assert_bound) { return -EKEYREJECTED; } int new_size_int = old_size_int + omap.size() - (assert_bound - bound); CLS_LOG(20, "old size is %d, new size is %d", old_size_int, new_size_int); bufferlist new_size; stringstream s; s << new_size_int; new_size.append(s.str()); r = cls_cxx_map_set_vals(hctx, &omap); if (r < 0) { CLS_LOG(20, "error setting omap: %d", r); return r; } r = cls_cxx_setxattr(hctx, "size", &new_size); if (r < 0) { CLS_LOG(20, "error setting xattr %s: %d", "size", r); return r; } CLS_LOG(20, "successfully inserted %s", omap.begin()->first.c_str()); return 0; } static int omap_insert_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "omap_insert"); omap_set_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { return -EINVAL; } return omap_insert(hctx, op.omap, op.bound, op.exclusive); } static int create_with_omap(cls_method_context_t hctx, const map &omap) { CLS_LOG(20, "creating with omap: %s", omap.begin()->first.c_str()); //first make sure the object is writable int r = cls_cxx_create(hctx, true); if (r < 0) { CLS_LOG(20, "omap create: creating failed: %d", r); return r; } int new_size_int = omap.size(); CLS_LOG(20, "omap insert: new size is %d", new_size_int); bufferlist new_size; stringstream s; s << new_size_int; new_size.append(s.str()); r = cls_cxx_map_set_vals(hctx, &omap); if (r < 0) { CLS_LOG(20, "omap create: error setting omap: %d", r); return r; } r = cls_cxx_setxattr(hctx, "size", &new_size); if (r < 0) { CLS_LOG(20, "omap create: error setting xattr %s: %d", "size", r); return r; } bufferlist u; u.append("0"); r = cls_cxx_setxattr(hctx, "unwritable", &u); if (r < 0) { CLS_LOG(20, "omap create: error setting xattr %s: %d", "unwritable", r); return r; } CLS_LOG(20, "successfully created %s", omap.begin()->first.c_str()); return 0; } static int create_with_omap_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "omap_insert"); map omap; bufferlist::iterator it = in->begin(); try { ::decode(omap, it); } catch (buffer::error& err) { return -EINVAL; } return create_with_omap(hctx, omap); } /** * Attempts to remove omap from this object's omap. * * @return: * if unwritable, returns -EACCES. * if size < bound and key doesn't already exist in the omap, returns -EBALANCE. * if any of the keys are not in this object, returns -ENODATA. * * @post: object has omap entries removed, and size xattr is updated */ static int omap_remove(cls_method_context_t hctx, const std::set &omap, int bound) { int r; uint64_t size; time_t time; r = cls_cxx_stat(hctx, &size, &time); if (r < 0) { return r; } //first make sure the object is writable r = check_writable(hctx); if (r < 0) { return r; } //check for existance of the key first for (set::const_iterator it = omap.begin(); it != omap.end(); ++it) { bufferlist bl; r = cls_cxx_map_get_val(hctx, *it, &bl); if (r == -ENOENT || r == -ENODATA || string(bl.c_str(), bl.length()) == ""){ return -ENODATA; } else if (r < 0) { CLS_LOG(20, "error reading omap val for %s: %d", it->c_str(), r); return r; } } //fail if removing from an object with only bound entries. bufferlist old_size; r = cls_cxx_getxattr(hctx, "size", &old_size); if (r < 0) { CLS_LOG(20, "error reading xattr %s: %d", "size", r); return r; } int old_size_int = atoi(string(old_size.c_str(), old_size.length()).c_str()); CLS_LOG(20, "asserting size is greater than %d", bound); if (old_size_int <= bound) { return -EKEYREJECTED; } int new_size_int = old_size_int - omap.size(); CLS_LOG(20, "old size is %d, new size is %d", old_size_int, new_size_int); bufferlist new_size; stringstream s; s << new_size_int; new_size.append(s.str()); r = cls_cxx_setxattr(hctx, "size", &new_size); if (r < 0) { CLS_LOG(20, "error setting xattr %s: %d", "unwritable", r); return r; } for (std::set::const_iterator it = omap.begin(); it != omap.end(); ++it) { r = cls_cxx_map_remove_key(hctx, *it); if (r < 0) { CLS_LOG(20, "error removing omap: %d", r); return r; } } return 0; } static int omap_remove_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "omap_remove"); omap_rm_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { return -EINVAL; } return omap_remove(hctx, op.omap, op.bound); } /** * checks to see if this object needs to be split or rebalanced. if so, reads * information about it. * * @post: if assert_size_in_bound(hctx, bound, comparator) succeeds, * odata contains the size, omap, and unwritable attributes for this object. * Otherwise, odata contains the size and unwritable attribute. */ static int maybe_read_for_balance(cls_method_context_t hctx, object_data &odata, int bound, int comparator) { CLS_LOG(20, "rebalance reading"); //if unwritable, return int r = check_writable(hctx); if (r < 0) { odata.unwritable = true; CLS_LOG(20, "rebalance read: error getting xattr %s: %d", "unwritable", r); return r; } else { odata.unwritable = false; } //get the size attribute bufferlist size; r = cls_cxx_getxattr(hctx, "size", &size); if (r < 0) { CLS_LOG(20, "rebalance read: error getting xattr %s: %d", "size", r); return r; } odata.size = atoi(string(size.c_str(), size.length()).c_str()); //check if it needs to be balanced r = assert_size_in_bound(hctx, bound, comparator); if (r < 0) { CLS_LOG(20, "rebalance read: error on asserting size: %d", r); return -EBALANCE; } //if the assert succeeded, it needs to be balanced r = cls_cxx_map_get_vals(hctx, "", "", LONG_MAX, &odata.omap); if (r < 0){ CLS_LOG(20, "rebalance read: getting kvs failed with error %d", r); return r; } CLS_LOG(20, "rebalance read: size xattr is %llu, omap size is %llu", (unsigned long long)odata.size, (unsigned long long)odata.omap.size()); return 0; } static int maybe_read_for_balance_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "maybe_read_for_balance"); rebalance_args op; bufferlist::iterator it = in->begin(); try { ::decode(op, it); } catch (buffer::error& err) { return -EINVAL; } int r = maybe_read_for_balance(hctx, op.odata, op.bound, op.comparator); if (r < 0) { return r; } else { op.encode(*out); return 0; } } void __cls_init() { CLS_LOG(20, "Loaded assert condition class!"); cls_register("kvs", &h_class); cls_register_cxx_method(h_class, "get_idata_from_key", CLS_METHOD_RD, get_idata_from_key_op, &h_get_idata_from_key); cls_register_cxx_method(h_class, "get_next_idata", CLS_METHOD_RD, get_next_idata_op, &h_get_next_idata); cls_register_cxx_method(h_class, "get_prev_idata", CLS_METHOD_RD, get_prev_idata_op, &h_get_prev_idata); cls_register_cxx_method(h_class, "read_many", CLS_METHOD_RD, read_many_op, &h_read_many); cls_register_cxx_method(h_class, "check_writable", CLS_METHOD_RD | CLS_METHOD_WR, check_writable_op, &h_check_writable); cls_register_cxx_method(h_class, "assert_size_in_bound", CLS_METHOD_WR, assert_size_in_bound_op, &h_assert_size_in_bound); cls_register_cxx_method(h_class, "omap_insert", CLS_METHOD_WR, omap_insert_op, &h_omap_insert); cls_register_cxx_method(h_class, "create_with_omap", CLS_METHOD_WR, create_with_omap_op, &h_create_with_omap); cls_register_cxx_method(h_class, "omap_remove", CLS_METHOD_WR, omap_remove_op, &h_omap_remove); cls_register_cxx_method(h_class, "maybe_read_for_balance", CLS_METHOD_RD, maybe_read_for_balance_op, &h_maybe_read_for_balance); return; } ceph-0.80.11/src/key_value_store/kv_flat_btree_async.cc0000664000175100017510000022203512623076744025203 0ustar jenkins-buildjenkins-build/* * Key-value store using librados * * September 2, 2012 * Eleanor Cawthon * eleanor.cawthon@inktank.com * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include "key_value_store/key_value_structure.h" #include "key_value_store/kv_flat_btree_async.h" #include "key_value_store/kvs_arg_types.h" #include "include/rados/librados.hpp" #include "/usr/include/asm-generic/errno.h" #include "/usr/include/asm-generic/errno-base.h" #include "common/ceph_context.h" #include "global/global_context.h" #include "common/Clock.h" #include "include/types.h" #include #include #include #include #include #include #include #include using namespace std; using ceph::bufferlist; bool index_data::is_timed_out(utime_t now, utime_t timeout) const { return prefix != "" && now - ts > timeout; } void IndexCache::clear() { k2itmap.clear(); t2kmap.clear(); } void IndexCache::push(const string &key, const index_data &idata) { if (cache_size == 0) { return; } index_data old_idata; map >::iterator old_it = k2itmap.lower_bound(key_data(key)); if (old_it != k2itmap.end()) { t2kmap.erase(old_it->second.second); k2itmap.erase(old_it); } map >::iterator new_it = k2itmap.find(idata.kdata); if (new_it != k2itmap.end()) { utime_t old_time = new_it->second.second; t2kmap.erase(old_time); } utime_t time = ceph_clock_now(g_ceph_context); k2itmap[idata.kdata] = make_pair(idata, time); t2kmap[time] = idata.kdata; if ((int)k2itmap.size() > cache_size) { pop(); } } void IndexCache::push(const index_data &idata) { if (cache_size == 0) { return; } if (k2itmap.count(idata.kdata) > 0) { utime_t old_time = k2itmap[idata.kdata].second; t2kmap.erase(old_time); k2itmap.erase(idata.kdata); } utime_t time = ceph_clock_now(g_ceph_context); k2itmap[idata.kdata] = make_pair(idata, time); t2kmap[time] = idata.kdata; if ((int)k2itmap.size() > cache_size) { pop(); } } void IndexCache::pop() { if (cache_size == 0) { return; } map::iterator it = t2kmap.begin(); utime_t time = it->first; key_data kdata = it->second; k2itmap.erase(kdata); t2kmap.erase(time); } void IndexCache::erase(key_data kdata) { if (cache_size == 0) { return; } if (k2itmap.count(kdata) > 0) { utime_t c = k2itmap[kdata].second; k2itmap.erase(kdata); t2kmap.erase(c); } } int IndexCache::get(const string &key, index_data *idata) const { if (cache_size == 0) { return -ENODATA; } if ((int)k2itmap.size() == 0) { return -ENODATA; } map >::const_iterator it = k2itmap.lower_bound(key_data(key)); if (it == k2itmap.end() || !(it->second.first.min_kdata < key_data(key))) { return -ENODATA; } else { *idata = it->second.first; } return 0; } int IndexCache::get(const string &key, index_data *idata, index_data *next_idata) const { if (cache_size == 0) { return -ENODATA; } map >::const_iterator it = k2itmap.lower_bound(key_data(key)); if (it == k2itmap.end() || ++it == k2itmap.end()) { return -ENODATA; } else { --it; if (!(it->second.first.min_kdata < key_data(key))){ //stale, should be reread. return -ENODATA; } else { *idata = it->second.first; ++it; if (it != k2itmap.end()) { *next_idata = it->second.first; } } } return 0; } int KvFlatBtreeAsync::nothing() { return 0; } int KvFlatBtreeAsync::wait() { if (rand() % 10 == 0) { usleep(wait_ms); } return 0; } int KvFlatBtreeAsync::suicide() { if (rand() % 10 == 0) { if (verbose) cout << client_name << " is suiciding" << std::endl; return 1; } return 0; } int KvFlatBtreeAsync::next(const index_data &idata, index_data * out_data) { if (verbose) cout << "\t\t" << client_name << "-next: finding next of " << idata.str() << std::endl; int err = 0; librados::ObjectReadOperation oro; std::map kvs; oro.omap_get_vals(idata.kdata.encoded(),1,&kvs,&err); err = io_ctx.operate(index_name, &oro, NULL); if (err < 0){ if (verbose) cout << "\t\t\t" << client_name << "-next: getting index failed with error " << err << std::endl; return err; } if (!kvs.empty()) { out_data->kdata.parse(kvs.begin()->first); bufferlist::iterator b = kvs.begin()->second.begin(); out_data->decode(b); if (idata.is_timed_out(ceph_clock_now(g_ceph_context),timeout)) { if (verbose) cout << client_name << " THINKS THE OTHER CLIENT DIED." << std::endl; //the client died after deleting the object. clean up. cleanup(idata, err); } } else { err = -EOVERFLOW; } return err; } int KvFlatBtreeAsync::prev(const index_data &idata, index_data * out_data) { if (verbose) cout << "\t\t" << client_name << "-prev: finding prev of " << idata.str() << std::endl; int err = 0; bufferlist inbl; idata_from_idata_args in_args; in_args.idata = idata; in_args.encode(inbl); bufferlist outbl; err = io_ctx.exec(index_name,"kvs", "get_prev_idata", inbl, outbl); if (err < 0){ if (verbose) cout << "\t\t\t" << client_name << "-prev: getting index failed with error " << err << std::endl; if (idata.is_timed_out(ceph_clock_now(g_ceph_context),timeout)) { if (verbose) cout << client_name << " THINKS THE OTHER CLIENT DIED." << std::endl; //the client died after deleting the object. clean up. err = cleanup(idata, err); if (err == -ESUICIDE) { return err; } else { err = 0; } } return err; } bufferlist::iterator it = outbl.begin(); in_args.decode(it); *out_data = in_args.next_idata; if (verbose) cout << "\t\t" << client_name << "-prev: prev is " << out_data->str() << std::endl; return err; } int KvFlatBtreeAsync::read_index(const string &key, index_data * idata, index_data * next_idata, bool force_update) { int err = 0; if (!force_update) { if (verbose) cout << "\t" << client_name << "-read_index: getting index_data for " << key << " from cache" << std::endl; icache_lock.Lock(); if (next_idata != NULL) { err = icache.get(key, idata, next_idata); } else { err = icache.get(key, idata); } icache_lock.Unlock(); if (err == 0) { //if (verbose) cout << "CACHE SUCCESS" << std::endl; return err; } else { if (verbose) cout << "NOT IN CACHE" << std::endl; } } if (verbose) cout << "\t" << client_name << "-read_index: getting index_data for " << key << " from object" << std::endl; librados::ObjectReadOperation oro; bufferlist raw_val; std::set key_set; key_set.insert(key_data(key).encoded()); std::map kvmap; std::map dupmap; oro.omap_get_vals_by_keys(key_set, &dupmap, &err); oro.omap_get_vals(key_data(key).encoded(), (cache_size / cache_refresh >= 2? cache_size / cache_refresh: 2), &kvmap,&err); err = io_ctx.operate(index_name, &oro, NULL); utime_t mytime = ceph_clock_now(g_ceph_context); if (err < 0){ cerr << "\t" << client_name << "-read_index: getting keys failed with " << err << std::endl; assert(0 == client_name + "-read_index: reading index failed"); return err; } kvmap.insert(dupmap.begin(), dupmap.end()); for (map::iterator it = ++kvmap.begin(); it != kvmap.end(); ++it) { bufferlist bl = it->second; bufferlist::iterator blit = bl.begin(); index_data this_idata; this_idata.decode(blit); if (this_idata.is_timed_out(mytime, timeout)) { if (verbose) cout << client_name << " THINKS THE OTHER CLIENT DIED. (mytime is " << mytime.sec() << "." << mytime.usec() << ", idata.ts is " << this_idata.ts.sec() << "." << this_idata.ts.usec() << ", it has been " << (mytime - this_idata.ts).sec() << '.' << (mytime - this_idata.ts).usec() << ", timeout is " << timeout << ")" << std::endl; //the client died after deleting the object. clean up. if (cleanup(this_idata, -EPREFIX) == -ESUICIDE) { return -ESUICIDE; } return read_index(key, idata, next_idata, force_update); } icache_lock.Lock(); icache.push(this_idata); icache_lock.Unlock(); } bufferlist::iterator b = kvmap.begin()->second.begin(); idata->decode(b); idata->kdata.parse(kvmap.begin()->first); if (verbose) cout << "\t" << client_name << "-read_index: kvmap_size is " << kvmap.size() << ", idata is " << idata->str() << std::endl; assert(idata->obj != ""); icache_lock.Lock(); icache.push(key, *idata); icache_lock.Unlock(); if (next_idata != NULL && idata->kdata.prefix != "1") { next_idata->kdata.parse((++kvmap.begin())->first); bufferlist::iterator nb = (++kvmap.begin())->second.begin(); next_idata->decode(nb); icache_lock.Lock(); icache.push(*next_idata); icache_lock.Unlock(); } return err; } int KvFlatBtreeAsync::split(const index_data &idata) { int err = 0; opmap['l']++; if (idata.prefix != "") { return -EPREFIX; } rebalance_args args; args.bound = 2 * k - 1; args.comparator = CEPH_OSD_CMPXATTR_OP_GT; err = read_object(idata.obj, &args); args.odata.max_kdata = idata.kdata; if (err < 0) { if (verbose) cout << "\t\t" << client_name << "-split: read object " << args.odata.name << " got " << err << std::endl; return err; } if (verbose) cout << "\t\t" << client_name << "-split: splitting " << idata.obj << ", which has size " << args.odata.size << " and actual size " << args.odata.omap.size() << std::endl; ///////preparations that happen outside the critical section //for prefix index vector to_create; vector to_delete; to_delete.push_back(object_data(idata.min_kdata, args.odata.max_kdata, args.odata.name, args.odata.version)); //for lower half object map::const_iterator it = args.odata.omap.begin(); client_index_lock.Lock(); to_create.push_back(object_data(to_string(client_name, client_index++))); client_index_lock.Unlock(); for (int i = 0; i < k; i++) { to_create[0].omap.insert(*it); ++it; } to_create[0].min_kdata = idata.min_kdata; to_create[0].max_kdata = key_data(to_create[0].omap.rbegin()->first); //for upper half object client_index_lock.Lock(); to_create.push_back(object_data(to_create[0].max_kdata, args.odata.max_kdata, to_string(client_name, client_index++))); client_index_lock.Unlock(); to_create[1].omap.insert( ++args.odata.omap.find(to_create[0].omap.rbegin()->first), args.odata.omap.end()); //setting up operations librados::ObjectWriteOperation owos[6]; vector, librados::ObjectWriteOperation*> > ops; index_data out_data; set_up_prefix_index(to_create, to_delete, &owos[0], &out_data, &err); ops.push_back(make_pair( pair(ADD_PREFIX, index_name), &owos[0])); for (int i = 1; i < 6; i++) { ops.push_back(make_pair(make_pair(0,""), &owos[i])); } set_up_ops(to_create, to_delete, &ops, out_data, &err); /////BEGIN CRITICAL SECTION///// //put prefix on index entry for idata.val err = perform_ops("\t\t" + client_name + "-split:", out_data, &ops); if (err < 0) { return err; } if (verbose) cout << "\t\t" << client_name << "-split: done splitting." << std::endl; /////END CRITICAL SECTION///// icache_lock.Lock(); for (vector::iterator it = out_data.to_delete.begin(); it != out_data.to_delete.end(); ++it) { icache.erase(it->max); } for (vector::iterator it = out_data.to_create.begin(); it != out_data.to_create.end(); ++it) { icache.push(index_data(*it)); } icache_lock.Unlock(); return err; } int KvFlatBtreeAsync::rebalance(const index_data &idata1, const index_data &next_idata){ opmap['m']++; int err = 0; if (idata1.prefix != "") { return -EPREFIX; } rebalance_args args1; args1.bound = k + 1; args1.comparator = CEPH_OSD_CMPXATTR_OP_LT; index_data idata2 = next_idata; rebalance_args args2; args2.bound = k + 1; args2.comparator = CEPH_OSD_CMPXATTR_OP_LT; if (idata1.kdata.prefix == "1") { //this is the highest key in the index, so it doesn't have a next. //read the index for the previous entry err = prev(idata1, &idata2); if (err == -ERANGE) { if (verbose) cout << "\t\t" << client_name << "-rebalance: this is the only node, " << "so aborting" << std::endl; return -EUCLEAN; } else if (err < 0) { return err; } //read the first object err = read_object(idata1.obj, &args2); if (err < 0) { if (verbose) cout << "reading " << idata1.obj << " failed with " << err << std::endl; if (err == -ENOENT) { return -ECANCELED; } return err; } args2.odata.min_kdata = idata1.min_kdata; args2.odata.max_kdata = idata1.kdata; //read the second object args1.bound = 2 * k + 1; err = read_object(idata2.obj, &args1); if (err < 0) { if (verbose) cout << "reading " << idata1.obj << " failed with " << err << std::endl; return err; } args1.odata.min_kdata = idata2.min_kdata; args1.odata.max_kdata = idata2.kdata; if (verbose) cout << "\t\t" << client_name << "-rebalance: read " << idata2.obj << ". size: " << args1.odata.size << " version: " << args1.odata.version << std::endl; } else { assert (next_idata.obj != ""); //there is a next key, so get it. err = read_object(idata1.obj, &args1); if (err < 0) { if (verbose) cout << "reading " << idata1.obj << " failed with " << err << std::endl; return err; } args1.odata.min_kdata = idata1.min_kdata; args1.odata.max_kdata = idata1.kdata; args2.bound = 2 * k + 1; err = read_object(idata2.obj, &args2); if (err < 0) { if (verbose) cout << "reading " << idata1.obj << " failed with " << err << std::endl; if (err == -ENOENT) { return -ECANCELED; } return err; } args2.odata.min_kdata = idata2.min_kdata; args2.odata.max_kdata = idata2.kdata; if (verbose) cout << "\t\t" << client_name << "-rebalance: read " << idata2.obj << ". size: " << args2.odata.size << " version: " << args2.odata.version << std::endl; } if (verbose) cout << "\t\t" << client_name << "-rebalance: o1 is " << args1.odata.max_kdata.encoded() << "," << args1.odata.name << " with size " << args1.odata.size << " , o2 is " << args2.odata.max_kdata.encoded() << "," << args2.odata.name << " with size " << args2.odata.size << std::endl; //calculations if ((int)args1.odata.size > k && (int)args1.odata.size <= 2*k && (int)args2.odata.size > k && (int)args2.odata.size <= 2*k) { //nothing to do if (verbose) cout << "\t\t" << client_name << "-rebalance: both sizes in range, so" << " aborting " << std::endl; return -EBALANCE; } else if (idata1.prefix != "" || idata2.prefix != "") { return -EPREFIX; } //this is the high object. it gets created regardless of rebalance or merge. client_index_lock.Lock(); string o2w = to_string(client_name, client_index++); client_index_lock.Unlock(); index_data idata; vector to_create; vector to_delete; librados::ObjectWriteOperation create[2];//possibly only 1 will be used librados::ObjectWriteOperation other_ops[6]; vector, librados::ObjectWriteOperation*> > ops; ops.push_back(make_pair( pair(ADD_PREFIX, index_name), &other_ops[0])); if ((int)args1.odata.size + (int)args2.odata.size <= 2*k) { //merge if (verbose) cout << "\t\t" << client_name << "-rebalance: merging " << args1.odata.name << " and " << args2.odata.name << " to get " << o2w << std::endl; map write2_map; write2_map.insert(args1.odata.omap.begin(), args1.odata.omap.end()); write2_map.insert(args2.odata.omap.begin(), args2.odata.omap.end()); to_create.push_back(object_data(args1.odata.min_kdata, args2.odata.max_kdata, o2w, write2_map)); ops.push_back(make_pair( pair(MAKE_OBJECT, o2w), &create[0])); assert((int)write2_map.size() <= 2*k); } else { //rebalance if (verbose) cout << "\t\t" << client_name << "-rebalance: rebalancing " << args1.odata.name << " and " << args2.odata.name << std::endl; map write1_map; map write2_map; map::iterator it; client_index_lock.Lock(); string o1w = to_string(client_name, client_index++); client_index_lock.Unlock(); int target_size_1 = ceil(((int)args1.odata.size + (int)args2.odata.size) / 2.0); if (args1.odata.max_kdata != idata1.kdata) { //this should be true if idata1 is the high object target_size_1 = floor(((int)args1.odata.size + (int)args2.odata.size) / 2.0); } for (it = args1.odata.omap.begin(); it != args1.odata.omap.end() && (int)write1_map.size() < target_size_1; ++it) { write1_map.insert(*it); } if (it != args1.odata.omap.end()){ //write1_map is full, so put the rest in write2_map write2_map.insert(it, args1.odata.omap.end()); write2_map.insert(args2.odata.omap.begin(), args2.odata.omap.end()); } else { //args1.odata.omap was small, and write2_map still needs more map::iterator it2; for(it2 = args2.odata.omap.begin(); (it2 != args2.odata.omap.end()) && ((int)write1_map.size() < target_size_1); ++it2) { write1_map.insert(*it2); } write2_map.insert(it2, args2.odata.omap.end()); } if (verbose) cout << "\t\t" << client_name << "-rebalance: write1_map has size " << write1_map.size() << ", write2_map.size() is " << write2_map.size() << std::endl; //at this point, write1_map and write2_map should have the correct pairs to_create.push_back(object_data(args1.odata.min_kdata, key_data(write1_map.rbegin()->first), o1w,write1_map)); to_create.push_back(object_data( key_data(write1_map.rbegin()->first), args2.odata.max_kdata, o2w, write2_map)); ops.push_back(make_pair( pair(MAKE_OBJECT, o1w), &create[0])); ops.push_back(make_pair( pair(MAKE_OBJECT, o2w), &create[1])); } to_delete.push_back(object_data(args1.odata.min_kdata, args1.odata.max_kdata, args1.odata.name, args1.odata.version)); to_delete.push_back(object_data(args2.odata.min_kdata, args2.odata.max_kdata, args2.odata.name, args2.odata.version)); for (int i = 1; i < 6; i++) { ops.push_back(make_pair(make_pair(0,""), &other_ops[i])); } index_data out_data; set_up_prefix_index(to_create, to_delete, &other_ops[0], &out_data, &err); set_up_ops(to_create, to_delete, &ops, out_data, &err); //at this point, all operations should be completely set up. /////BEGIN CRITICAL SECTION///// err = perform_ops("\t\t" + client_name + "-rebalance:", out_data, &ops); if (err < 0) { return err; } icache_lock.Lock(); for (vector::iterator it = out_data.to_delete.begin(); it != out_data.to_delete.end(); ++it) { icache.erase(it->max); } for (vector::iterator it = out_data.to_create.begin(); it != out_data.to_create.end(); ++it) { icache.push(index_data(*it)); } icache_lock.Unlock(); if (verbose) cout << "\t\t" << client_name << "-rebalance: done rebalancing." << std::endl; /////END CRITICAL SECTION///// return err; } int KvFlatBtreeAsync::read_object(const string &obj, object_data * odata) { librados::ObjectReadOperation get_obj; librados::AioCompletion * obj_aioc = rados.aio_create_completion(); int err; bufferlist unw_bl; odata->name = obj; get_obj.omap_get_vals("", LONG_MAX, &odata->omap, &err); get_obj.getxattr("unwritable", &unw_bl, &err); io_ctx.aio_operate(obj, obj_aioc, &get_obj, NULL); obj_aioc->wait_for_safe(); err = obj_aioc->get_return_value(); if (err < 0){ //possibly -ENOENT, meaning someone else deleted it. obj_aioc->release(); return err; } odata->unwritable = string(unw_bl.c_str(), unw_bl.length()) == "1"; odata->version = obj_aioc->get_version64(); odata->size = odata->omap.size(); obj_aioc->release(); return 0; } int KvFlatBtreeAsync::read_object(const string &obj, rebalance_args * args) { bufferlist inbl; args->encode(inbl); bufferlist outbl; int err; librados::AioCompletion * a = rados.aio_create_completion(); io_ctx.aio_exec(obj, a, "kvs", "maybe_read_for_balance", inbl, &outbl); a->wait_for_safe(); err = a->get_return_value(); if (err < 0) { if (verbose) cout << "\t\t" << client_name << "-read_object: reading failed with " << err << std::endl; a->release(); return err; } bufferlist::iterator it = outbl.begin(); args->decode(it); args->odata.name = obj; args->odata.version = a->get_version64(); a->release(); return err; } void KvFlatBtreeAsync::set_up_prefix_index( const vector &to_create, const vector &to_delete, librados::ObjectWriteOperation * owo, index_data * idata, int * err) { std::map > assertions; map to_insert; idata->prefix = "1"; idata->ts = ceph_clock_now(g_ceph_context); for(vector::const_iterator it = to_create.begin(); it != to_create.end(); ++it) { create_data c(it->min_kdata, it->max_kdata, it->name); idata->to_create.push_back(c); } for(vector::const_iterator it = to_delete.begin(); it != to_delete.end(); ++it) { delete_data d(it->min_kdata, it->max_kdata, it->name, it->version); idata->to_delete.push_back(d); } for(vector::const_iterator it = to_delete.begin(); it != to_delete.end(); ++it) { idata->obj = it->name; idata->min_kdata = it->min_kdata; idata->kdata = it->max_kdata; bufferlist insert; idata->encode(insert); to_insert[it->max_kdata.encoded()] = insert; index_data this_entry; this_entry.min_kdata = idata->min_kdata; this_entry.kdata = idata->kdata; this_entry.obj = idata->obj; assertions[it->max_kdata.encoded()] = pair (to_bl(this_entry), CEPH_OSD_CMPXATTR_OP_EQ); if (verbose) cout << "\t\t\t" << client_name << "-setup_prefix: will assert " << this_entry.str() << std::endl; } assert(*err == 0); owo->omap_cmp(assertions, err); if (to_create.size() <= 2) { owo->omap_set(to_insert); } } //some args can be null if there are no corresponding entries in p void KvFlatBtreeAsync::set_up_ops( const vector &create_vector, const vector &delete_vector, vector, librados::ObjectWriteOperation*> > * ops, const index_data &idata, int * err) { vector, librados::ObjectWriteOperation* > >::iterator it; //skip the prefixing part for(it = ops->begin(); it->first.first == ADD_PREFIX; ++it) {} map to_insert; std::set to_remove; map > assertions; if (create_vector.size() > 0) { for (int i = 0; i < (int)idata.to_delete.size(); ++i) { it->first = pair(UNWRITE_OBJECT, idata.to_delete[i].obj); set_up_unwrite_object(delete_vector[i].version, it->second); ++it; } } for (int i = 0; i < (int)idata.to_create.size(); ++i) { index_data this_entry(idata.to_create[i].max, idata.to_create[i].min, idata.to_create[i].obj); to_insert[idata.to_create[i].max.encoded()] = to_bl(this_entry); if (idata.to_create.size() <= 2) { it->first = pair(MAKE_OBJECT, idata.to_create[i].obj); } else { it->first = pair(AIO_MAKE_OBJECT, idata.to_create[i].obj); } set_up_make_object(create_vector[i].omap, it->second); ++it; } for (int i = 0; i < (int)idata.to_delete.size(); ++i) { index_data this_entry = idata; this_entry.obj = idata.to_delete[i].obj; this_entry.min_kdata = idata.to_delete[i].min; this_entry.kdata = idata.to_delete[i].max; if (verbose) cout << "\t\t\t" << client_name << "-setup_ops: will assert " << this_entry.str() << std::endl; assertions[idata.to_delete[i].max.encoded()] = pair( to_bl(this_entry), CEPH_OSD_CMPXATTR_OP_EQ); to_remove.insert(idata.to_delete[i].max.encoded()); it->first = pair(REMOVE_OBJECT, idata.to_delete[i].obj); set_up_delete_object(it->second); ++it; } if ((int)idata.to_create.size() <= 2) { it->second->omap_cmp(assertions, err); } it->second->omap_rm_keys(to_remove); it->second->omap_set(to_insert); it->first = pair(REMOVE_PREFIX, index_name); } void KvFlatBtreeAsync::set_up_make_object( const map &to_set, librados::ObjectWriteOperation *owo) { bufferlist inbl; ::encode(to_set, inbl); owo->exec("kvs", "create_with_omap", inbl); } void KvFlatBtreeAsync::set_up_unwrite_object( const int &ver, librados::ObjectWriteOperation *owo) { if (ver > 0) { owo->assert_version(ver); } owo->cmpxattr("unwritable", CEPH_OSD_CMPXATTR_OP_EQ, to_bl("0")); owo->setxattr("unwritable", to_bl("1")); } void KvFlatBtreeAsync::set_up_restore_object( librados::ObjectWriteOperation *owo) { owo->cmpxattr("unwritable", CEPH_OSD_CMPXATTR_OP_EQ, to_bl("1")); owo->setxattr("unwritable", to_bl("0")); } void KvFlatBtreeAsync::set_up_delete_object( librados::ObjectWriteOperation *owo) { owo->cmpxattr("unwritable", CEPH_OSD_CMPXATTR_OP_EQ, to_bl("1")); owo->remove(); } int KvFlatBtreeAsync::perform_ops(const string &debug_prefix, const index_data &idata, vector, librados::ObjectWriteOperation*> > *ops) { int err = 0; vector aiocs(idata.to_create.size()); int count = 0; for (vector, librados::ObjectWriteOperation*> >::iterator it = ops->begin(); it != ops->end(); ++it) { if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } switch (it->first.first) { case ADD_PREFIX://prefixing if (verbose) cout << debug_prefix << " adding prefix" << std::endl; err = io_ctx.operate(index_name, it->second); if (err < 0) { if (verbose) cout << debug_prefix << " prefixing the index failed with " << err << std::endl; return -EPREFIX; } if (verbose) cout << debug_prefix << " prefix added." << std::endl; break; case UNWRITE_OBJECT://marking if (verbose) cout << debug_prefix << " marking " << it->first.second << std::endl; err = io_ctx.operate(it->first.second, it->second); if (err < 0) { //most likely because it changed, in which case it will be -ERANGE if (verbose) cout << debug_prefix << " marking " << it->first.second << "failed with code" << err << std::endl; if (it->first.second == (*idata.to_delete.begin()).max.encoded()) { if (cleanup(idata, -EFIRSTOBJ) == -ESUICIDE) { return -ESUICIDE; } } else { if (cleanup(idata, -ERANGE) == -ESUICIDE) { return -ESUICIDE; } } return err; } if (verbose) cout << debug_prefix << " marked " << it->first.second << std::endl; break; case MAKE_OBJECT://creating if (verbose) cout << debug_prefix << " creating " << it->first.second << std::endl; err = io_ctx.operate(it->first.second, it->second); if (err < 0) { //this can happen if someone else was cleaning up after us. if (verbose) cout << debug_prefix << " creating " << it->first.second << " failed" << " with code " << err << std::endl; if (err == -EEXIST) { //someone thinks we died, so die if (verbose) cout << client_name << " is suiciding!" << std::endl; return -ESUICIDE; } else { assert(false); } return err; } if (verbose || idata.to_create.size() > 2) { cout << debug_prefix << " created object " << it->first.second << std::endl; } break; case AIO_MAKE_OBJECT: cout << debug_prefix << " launching asynchronous create " << it->first.second << std::endl; aiocs[count] = rados.aio_create_completion(); io_ctx.aio_operate(it->first.second, aiocs[count], it->second); count++; if ((int)idata.to_create.size() == count) { cout << "starting aiowrite waiting loop" << std::endl; for (count -= 1; count >= 0; count--) { aiocs[count]->wait_for_safe(); err = aiocs[count]->get_return_value(); if (err < 0) { //this can happen if someone else was cleaning up after us. cerr << debug_prefix << " a create failed" << " with code " << err << std::endl; if (err == -EEXIST) { //someone thinks we died, so die cerr << client_name << " is suiciding!" << std::endl; return -ESUICIDE; } else { assert(false); } return err; } if (verbose || idata.to_create.size() > 2) { cout << debug_prefix << " completed aio " << aiocs.size() - count << "/" << aiocs.size() << std::endl; } } } break; case REMOVE_OBJECT://deleting if (verbose) cout << debug_prefix << " deleting " << it->first.second << std::endl; err = io_ctx.operate(it->first.second, it->second); if (err < 0) { //if someone else called cleanup on this prefix first if (verbose) cout << debug_prefix << " deleting " << it->first.second << "failed with code" << err << std::endl; } if (verbose) cout << debug_prefix << " deleted " << it->first.second << std::endl; break; case REMOVE_PREFIX://rewriting index if (verbose) cout << debug_prefix << " updating index " << std::endl; err = io_ctx.operate(index_name, it->second); if (err < 0) { if (verbose) cout << debug_prefix << " rewriting the index failed with code " << err << ". someone else must have thought we died, so dying" << std::endl; return -ETIMEDOUT; } if (verbose) cout << debug_prefix << " updated index." << std::endl; break; case RESTORE_OBJECT: if (verbose) cout << debug_prefix << " restoring " << it->first.second << std::endl; err = io_ctx.operate(it->first.second, it->second); if (err < 0) { if (verbose) cout << debug_prefix << "restoring " << it->first.second << " failed" << " with " << err << std::endl; return err; } if (verbose) cout << debug_prefix << " restored " << it->first.second << std::endl; break; default: if (verbose) cout << debug_prefix << " performing unknown op on " << it->first.second << std::endl; err = io_ctx.operate(index_name, it->second); if (err < 0) { if (verbose) cout << debug_prefix << " unknown op on " << it->first.second << " failed with " << err << std::endl; return err; } if (verbose) cout << debug_prefix << " unknown op on " << it->first.second << " succeeded." << std::endl; break; } } return err; } int KvFlatBtreeAsync::cleanup(const index_data &idata, const int &error) { if (verbose) cout << "\t\t" << client_name << ": cleaning up after " << idata.str() << std::endl; int err = 0; assert(idata.prefix != ""); map new_index; map > assertions; switch (error) { case -EFIRSTOBJ: { //this happens if the split or rebalance failed to mark the first object, //meaning only the index needs to be changed. //restore objects that had been marked unwritable. for(vector::const_iterator it = idata.to_delete.begin(); it != idata.to_delete.end(); ++it) { index_data this_entry; this_entry.obj = (*it).obj; this_entry.min_kdata = it->min; this_entry.kdata = it->max; new_index[it->max.encoded()] = to_bl(this_entry); this_entry = idata; this_entry.obj = it->obj; this_entry.min_kdata = it->min; this_entry.kdata = it->max; if (verbose) cout << "\t\t\t" << client_name << "-cleanup: will assert index contains " << this_entry.str() << std::endl; assertions[it->max.encoded()] = pair(to_bl(this_entry), CEPH_OSD_CMPXATTR_OP_EQ); } //update the index librados::ObjectWriteOperation update_index; update_index.omap_cmp(assertions, &err); update_index.omap_set(new_index); if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updating index" << std::endl; if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } err = io_ctx.operate(index_name, &update_index); if (err < 0) { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: rewriting failed with " << err << ". returning -ECANCELED" << std::endl; return -ECANCELED; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updated index. cleanup done." << std::endl; break; } case -ERANGE: { //this happens if a split or rebalance fails to mark an object. It is a //special case of rolling back that does not have to deal with new objects. //restore objects that had been marked unwritable. vector::const_iterator it; for(it = idata.to_delete.begin(); it != idata.to_delete.end(); ++it) { index_data this_entry; this_entry.obj = (*it).obj; this_entry.min_kdata = it->min; this_entry.kdata = it->max; new_index[it->max.encoded()] = to_bl(this_entry); this_entry = idata; this_entry.obj = it->obj; this_entry.min_kdata = it->min; this_entry.kdata = it->max; if (verbose) cout << "\t\t\t" << client_name << "-cleanup: will assert index contains " << this_entry.str() << std::endl; assertions[it->max.encoded()] = pair(to_bl(this_entry), CEPH_OSD_CMPXATTR_OP_EQ); } it = idata.to_delete.begin(); librados::ObjectWriteOperation restore; set_up_restore_object(&restore); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restoring " << it->obj << std::endl; err = io_ctx.operate(it->obj, &restore); if (err < 0) { //i.e., -ECANCELED because the object was already restored by someone //else if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restoring " << it->obj << " failed with " << err << std::endl; } else { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restored " << it->obj << std::endl; } //update the index librados::ObjectWriteOperation update_index; update_index.omap_cmp(assertions, &err); update_index.omap_set(new_index); if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updating index" << std::endl; if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } err = io_ctx.operate(index_name, &update_index); if (err < 0) { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: rewriting failed with " << err << ". returning -ECANCELED" << std::endl; return -ECANCELED; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updated index. cleanup done." << std::endl; break; } case -ENOENT: { if (verbose) cout << "\t\t" << client_name << "-cleanup: rolling forward" << std::endl; //all changes were created except for updating the index and possibly //deleting the objects. roll forward. vector, librados::ObjectWriteOperation*> > ops; librados::ObjectWriteOperation owos[idata.to_delete.size() + 1]; for (int i = 0; i <= (int)idata.to_delete.size(); ++i) { ops.push_back(make_pair(pair(0, ""), &owos[i])); } set_up_ops(vector(), vector(), &ops, idata, &err); err = perform_ops("\t\t" + client_name + "-cleanup:", idata, &ops); if (err < 0) { if (err == -ESUICIDE) { return -ESUICIDE; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: rewriting failed with " << err << ". returning -ECANCELED" << std::endl; return -ECANCELED; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updated index" << std::endl; break; } default: { //roll back all changes. if (verbose) cout << "\t\t" << client_name << "-cleanup: rolling back" << std::endl; map new_index; std::set to_remove; map > assertions; //mark the objects to be created. if someone else already has, die. for(vector::const_reverse_iterator it = idata.to_create.rbegin(); it != idata.to_create.rend(); ++it) { librados::ObjectWriteOperation rm; set_up_unwrite_object(0, &rm); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: marking " << it->obj << std::endl; err = io_ctx.operate(it->obj, &rm); if (err < 0) { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: marking " << it->obj << " failed with " << err << std::endl; } else { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: marked " << it->obj << std::endl; } } //restore objects that had been marked unwritable. for(vector::const_iterator it = idata.to_delete.begin(); it != idata.to_delete.end(); ++it) { index_data this_entry; this_entry.obj = (*it).obj; this_entry.min_kdata = it->min; this_entry.kdata = it->max; new_index[it->max.encoded()] = to_bl(this_entry); this_entry = idata; this_entry.obj = it->obj; this_entry.min_kdata = it->min; this_entry.kdata = it->max; if (verbose) cout << "\t\t\t" << client_name << "-cleanup: will assert index contains " << this_entry.str() << std::endl; assertions[it->max.encoded()] = pair(to_bl(this_entry), CEPH_OSD_CMPXATTR_OP_EQ); librados::ObjectWriteOperation restore; set_up_restore_object(&restore); if (verbose) cout << "\t\t\t" << client_name << "-cleanup: will assert index contains " << this_entry.str() << std::endl; if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restoring " << it->obj << std::endl; err = io_ctx.operate(it->obj, &restore); if (err == -ENOENT) { //it had gotten far enough to be rolled forward - unmark the objects //and roll forward. if (verbose) cout << "\t\t\t" << client_name << "-cleanup: roll forward instead" << std::endl; for(vector::const_iterator cit = idata.to_create.begin(); cit != idata.to_create.end(); ++cit) { librados::ObjectWriteOperation res; set_up_restore_object(&res); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ECANCELED; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restoring " << cit->obj << std::endl; err = io_ctx.operate(cit->obj, &res); if (err < 0) { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restoring " << cit->obj << " failed with " << err << std::endl; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restored " << cit->obj << std::endl; } return cleanup(idata, -ENOENT); } else if (err < 0) { //i.e., -ECANCELED because the object was already restored by someone //else if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restoring " << it->obj << " failed with " << err << std::endl; } else { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: restored " << it->obj << std::endl; } } //remove the new objects for(vector::const_reverse_iterator it = idata.to_create.rbegin(); it != idata.to_create.rend(); ++it) { to_remove.insert(it->max.encoded()); librados::ObjectWriteOperation rm; rm.remove(); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: removing " << it->obj << std::endl; err = io_ctx.operate(it->obj, &rm); if (err < 0) { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: failed to remove " << it->obj << std::endl; } else { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: removed " << it->obj << std::endl; } } //update the index librados::ObjectWriteOperation update_index; update_index.omap_cmp(assertions, &err); update_index.omap_rm_keys(to_remove); update_index.omap_set(new_index); if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updating index" << std::endl; if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } err = io_ctx.operate(index_name, &update_index); if (err < 0) { if (verbose) cout << "\t\t\t" << client_name << "-cleanup: rewriting failed with " << err << ". returning -ECANCELED" << std::endl; return -ECANCELED; } if (verbose) cout << "\t\t\t" << client_name << "-cleanup: updated index. cleanup done." << std::endl; break; } } return err; } string KvFlatBtreeAsync::to_string(string s, int i) { stringstream ret; ret << s << i; return ret.str(); } string KvFlatBtreeAsync::get_name() { return rados_id; } void KvFlatBtreeAsync::set_inject(injection_t inject, int wait_time) { interrupt = inject; wait_ms = wait_time; } int KvFlatBtreeAsync::setup(int argc, const char** argv) { int r = rados.init(rados_id.c_str()); if (r < 0) { cerr << "error during init" << r << std::endl; return r; } r = rados.conf_parse_argv(argc, argv); if (r < 0) { cerr << "error during parsing args" << r << std::endl; return r; } r = rados.conf_parse_env(NULL); if (r < 0) { cerr << "error during parsing env" << r << std::endl; return r; } r = rados.conf_read_file(NULL); if (r < 0) { cerr << "error during read file: " << r << std::endl; return r; } r = rados.connect(); if (r < 0) { cerr << "error during connect: " << r << std::endl; return r; } r = rados.ioctx_create(pool_name.c_str(), io_ctx); if (r < 0) { cerr << "error creating io ctx: " << r << std::endl; rados.shutdown(); return r; } librados::ObjectWriteOperation make_index; make_index.create(true); map index_map; index_data idata; idata.obj = client_name; idata.min_kdata.raw_key = ""; idata.kdata = key_data(""); index_map["1"] = to_bl(idata); make_index.omap_set(index_map); r = io_ctx.operate(index_name, &make_index); if (r < 0) { if (verbose) cout << client_name << ": Making the index failed with code " << r << std::endl; return 0; } if (verbose) cout << client_name << ": created index object" << std::endl; librados::ObjectWriteOperation make_max_obj; make_max_obj.create(true); make_max_obj.setxattr("unwritable", to_bl("0")); make_max_obj.setxattr("size", to_bl("0")); r = io_ctx.operate(client_name, &make_max_obj); if (r < 0) { if (verbose) cout << client_name << ": Setting xattr failed with code " << r << std::endl; } return 0; } int KvFlatBtreeAsync::set(const string &key, const bufferlist &val, bool update_on_existing) { if (verbose) cout << client_name << " is " << (update_on_existing? "updating " : "setting ") << key << std::endl; int err = 0; utime_t mytime; index_data idata(key); if (verbose) cout << "\t" << client_name << ": finding oid" << std::endl; err = read_index(key, &idata, NULL, false); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } if (verbose) cout << "\t" << client_name << ": index data is " << idata.str() << ", object is " << idata.obj << std::endl; err = set_op(key, val, update_on_existing, idata); if (verbose) cout << "\t" << client_name << ": finished set with " << err << std::endl; return err; } int KvFlatBtreeAsync::set_op(const string &key, const bufferlist &val, bool update_on_existing, index_data &idata) { //write bufferlist inbl; omap_set_args args; args.bound = 2 * k; args.exclusive = !update_on_existing; args.omap[key] = val; args.encode(inbl); librados::ObjectWriteOperation owo; owo.exec("kvs", "omap_insert", inbl); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { if (verbose) cout << client_name << " IS SUICIDING!" << std::endl; return -ESUICIDE; } if (verbose) cout << "\t" << client_name << ": inserting " << key << " into object " << idata.obj << std::endl; int err = io_ctx.operate(idata.obj, &owo); if (err < 0) { switch (err) { case -EEXIST: { //the key already exists and this is an exclusive insert. cerr << "\t" << client_name << ": writing key failed with " << err << std::endl; return err; } case -EKEYREJECTED: { //the object needs to be split. do { if (verbose) cout << "\t" << client_name << ": running split on " << idata.obj << std::endl; err = read_index(key, &idata, NULL, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } err = split(idata); if (err < 0 && err != -ENOENT && err != -EBALANCE) { if (verbose) cerr << "\t" << client_name << ": split failed with " << err << std::endl; int ret = handle_set_rm_errors(err, idata.obj, key, &idata, NULL); switch (ret) { case -ESUICIDE: if (verbose) cout << client_name << " IS SUICIDING!" << std::endl; return ret; break; case 1: return set_op(key, val, update_on_existing, idata); break; case 2: return err; break; } } } while (err < 0 && err != -EBALANCE && err != -ENOENT); err = read_index(key, &idata, NULL, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } return set_op(key, val, update_on_existing, idata); break; } default: if (verbose) cerr << "\t" << client_name << ": writing obj failed with " << err << std::endl; if (err == -ENOENT || err == -EACCES) { if (err == -ENOENT) { if (verbose) cout << "CACHE FAILURE" << std::endl; } err = read_index(key, &idata, NULL, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } if (verbose) cout << "\t" << client_name << ": index data is " << idata.str() << ", object is " << idata.obj << std::endl; return set_op(key, val, update_on_existing, idata); } else { return err; } } } return 0; } int KvFlatBtreeAsync::remove(const string &key) { if (verbose) cout << client_name << ": removing " << key << std::endl; int err = 0; string obj; utime_t mytime; index_data idata; index_data next_idata; if (verbose) cout << "\t" << client_name << ": finding oid" << std::endl; err = read_index(key, &idata, &next_idata, false); if (err < 0) { if (verbose) cout << "getting oid failed with code " << err << std::endl; return err; } obj = idata.obj; if (verbose) cout << "\t" << client_name << ": idata is " << idata.str() << ", next_idata is " << next_idata.str() << ", obj is " << obj << std::endl; err = remove_op(key, idata, next_idata); if (verbose) cout << "\t" << client_name << ": finished remove with " << err << " and exiting" << std::endl; return err; } int KvFlatBtreeAsync::remove_op(const string &key, index_data &idata, index_data &next_idata) { //write bufferlist inbl; omap_rm_args args; args.bound = k; args.omap.insert(key); args.encode(inbl); librados::ObjectWriteOperation owo; owo.exec("kvs", "omap_remove", inbl); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { if (verbose) cout << client_name << " IS SUICIDING!" << std::endl; return -ESUICIDE; } if (verbose) cout << "\t" << client_name << ": removing " << key << " from " << idata.obj << std::endl; int err = io_ctx.operate(idata.obj, &owo); if (err < 0) { if (verbose) cout << "\t" << client_name << ": writing obj failed with " << err << std::endl; switch (err) { case -ENODATA: { //the key does not exist in the object return err; } case -EKEYREJECTED: { //the object needs to be split. do { if (verbose) cerr << "\t" << client_name << ": running rebalance on " << idata.obj << std::endl; err = read_index(key, &idata, &next_idata, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } err = rebalance(idata, next_idata); if (err < 0 && err != -ENOENT && err != -EBALANCE) { if (verbose) cerr << "\t" << client_name << ": rebalance returned " << err << std::endl; int ret = handle_set_rm_errors(err, idata.obj, key, &idata, &next_idata); switch (ret) { case -ESUICIDE: if (verbose) cout << client_name << " IS SUICIDING!" << std::endl; return err; break; case 1: return remove_op(key, idata, next_idata); break; case 2: return err; break; case -EUCLEAN: //this is the only node, so it's ok to go below k. librados::ObjectWriteOperation owo; bufferlist inbl; omap_rm_args args; args.bound = 0; args.omap.insert(key); args.encode(inbl); owo.exec("kvs", "omap_remove", inbl); if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { if (verbose) cout << client_name << " IS SUICIDING!" << std::endl; return -ESUICIDE; } if (verbose) cout << "\t" << client_name << ": removing " << key << " from " << idata.obj << std::endl; int err = io_ctx.operate(idata.obj, &owo); if (err == 0) { return 0; } } } } while (err < 0 && err != -EBALANCE && err != -ENOENT); err = read_index(key, &idata, &next_idata, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } return remove(key); } default: if (err == -ENOENT || err == -EACCES) { err = read_index(key, &idata, &next_idata, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } if (verbose) cout << "\t" << client_name << ": index data is " << idata.str() << ", object is " << idata.obj << std::endl; //idea: we read the time every time we read the index anyway - store it. return remove_op(key, idata, next_idata); } else { return err; } } } return 0; } int KvFlatBtreeAsync::handle_set_rm_errors(int &err, string obj, string key, index_data * idata, index_data * next_idata) { if (err == -ESUICIDE) { return err; } else if (err == -ECANCELED //if an object was unwritable or index changed || err == -EPREFIX //if there is currently a prefix || err == -ETIMEDOUT// if the index changes during the op - i.e. cleanup || err == -EACCES) //possible if we were acting on old index data { err = read_index(key, idata, next_idata, true); if (err < 0) { return err; } if (verbose) cout << "\t" << client_name << ": prefix is " << idata->str() << std::endl; if (idata->obj != obj) { //someone else has split or cleaned up or something. start over. return 1;//meaning repeat } } else if (err != -ETIMEDOUT && err != -ERANGE && err != -EACCES && err != -EUCLEAN){ if (verbose) cout << "\t" << client_name << ": split encountered an unexpected error: " << err << std::endl; return 2; } return err; } int KvFlatBtreeAsync::get(const string &key, bufferlist *val) { opmap['g']++; if (verbose) cout << client_name << ": getting " << key << std::endl; int err = 0; index_data idata; utime_t mytime; if ((((KeyValueStructure *)this)->*KvFlatBtreeAsync::interrupt)() == 1 ) { return -ESUICIDE; } err = read_index(key, &idata, NULL, false); mytime = ceph_clock_now(g_ceph_context); if (err < 0) { if (verbose) cout << "getting oid failed with code " << err << std::endl; return err; } err = get_op(key, val, idata); if (verbose) cout << client_name << ": got " << key << " with " << err << std::endl; return err; } int KvFlatBtreeAsync::get_op(const string &key, bufferlist *val, index_data &idata) { int err = 0; std::set key_set; key_set.insert(key); map omap; librados::ObjectReadOperation read; read.omap_get_vals_by_keys(key_set, &omap, &err); err = io_ctx.operate(idata.obj, &read, NULL); if (err < 0) { if (err == -ENOENT) { err = read_index(key, &idata, NULL, true); if (err < 0) { if (verbose) cout << "\t" << client_name << ": getting oid failed with code " << err << std::endl; return err; } if (verbose) cout << "\t" << client_name << ": index data is " << idata.str() << ", object is " << idata.obj << std::endl; return get_op(key, val, idata); } else { if (verbose) cout << client_name << ": get encountered an unexpected error: " << err << std::endl; return err; } } *val = omap[key]; return err; } void *KvFlatBtreeAsync::pset(void *ptr) { struct aio_set_args *args = (struct aio_set_args *)ptr; *args->err = args->kvba->KvFlatBtreeAsync::set((string)args->key, (bufferlist)args->val, (bool)args->exc); args->cb(args->err, args->cb_args); delete args; return NULL; } void KvFlatBtreeAsync::aio_set(const string &key, const bufferlist &val, bool exclusive, callback cb, void * cb_args, int * err) { aio_set_args *args = new aio_set_args(); args->kvba = this; args->key = key; args->val = val; args->exc = exclusive; args->cb = cb; args->cb_args = cb_args; args->err = err; pthread_t t; int r = pthread_create(&t, NULL, pset, (void*)args); if (r < 0) { *args->err = r; return; } pthread_detach(t); } void *KvFlatBtreeAsync::prm(void *ptr) { struct aio_rm_args *args = (struct aio_rm_args *)ptr; *args->err = args->kvba->KvFlatBtreeAsync::remove((string)args->key); args->cb(args->err, args->cb_args); delete args; return NULL; } void KvFlatBtreeAsync::aio_remove(const string &key, callback cb, void * cb_args, int * err) { aio_rm_args * args = new aio_rm_args(); args->kvba = this; args->key = key; args->cb = cb; args->cb_args = cb_args; args->err = err; pthread_t t; int r = pthread_create(&t, NULL, prm, (void*)args); if (r < 0) { *args->err = r; return; } pthread_detach(t); } void *KvFlatBtreeAsync::pget(void *ptr) { struct aio_get_args *args = (struct aio_get_args *)ptr; *args->err = args->kvba->KvFlatBtreeAsync::get((string)args->key, (bufferlist *)args->val); args->cb(args->err, args->cb_args); delete args; return NULL; } void KvFlatBtreeAsync::aio_get(const string &key, bufferlist *val, callback cb, void * cb_args, int * err) { aio_get_args * args = new aio_get_args(); args->kvba = this; args->key = key; args->val = val; args->cb = cb; args->cb_args = cb_args; args->err = err; pthread_t t; int r = pthread_create(&t, NULL, pget, (void*)args); if (r < 0) { *args->err = r; return; } pthread_detach(t); } int KvFlatBtreeAsync::set_many(const map &in_map) { int err = 0; bufferlist inbl; bufferlist outbl; std::set keys; map big_map; for (map::const_iterator it = in_map.begin(); it != in_map.end(); ++it) { keys.insert(it->first); big_map.insert(*it); } if (verbose) cout << "created key set and big_map" << std::endl; ::encode(keys, inbl); librados::AioCompletion * aioc = rados.aio_create_completion(); io_ctx.aio_exec(index_name, aioc, "kvs", "read_many", inbl, &outbl); aioc->wait_for_safe(); err = aioc->get_return_value(); aioc->release(); if (err < 0) { cerr << "getting index failed with " << err << std::endl; return err; } map imap;//read from the index bufferlist::iterator blit = outbl.begin(); ::decode(imap, blit); if (verbose) cout << "finished reading index for objects. there are " << imap.size() << " entries that need to be changed. " << std::endl; vector to_delete; vector to_create; if (verbose) cout << "setting up to_delete and to_create vectors from index " << "map" << std::endl; //set up to_delete from index map for (map::iterator it = imap.begin(); it != imap.end(); ++it){ index_data idata; blit = it->second.begin(); idata.decode(blit); to_delete.push_back(object_data(idata.min_kdata, idata.kdata, idata.obj)); err = read_object(idata.obj, &to_delete[to_delete.size() - 1]); if (err < 0) { if (verbose) cout << "reading " << idata.obj << " failed with " << err << std::endl; return set_many(in_map); } big_map.insert(to_delete[to_delete.size() - 1].omap.begin(), to_delete[to_delete.size() - 1].omap.end()); } to_create.push_back(object_data( to_string(client_name, client_index++))); to_create[0].min_kdata = to_delete[0].min_kdata; for(map::iterator it = big_map.begin(); it != big_map.end(); ++it) { if (to_create[to_create.size() - 1].omap.size() == 1.5 * k) { to_create[to_create.size() - 1].max_kdata = key_data(to_create[to_create.size() - 1] .omap.rbegin()->first); to_create.push_back(object_data( to_string(client_name, client_index++))); to_create[to_create.size() - 1].min_kdata = to_create[to_create.size() - 2].max_kdata; } to_create[to_create.size() - 1].omap.insert(*it); } to_create[to_create.size() - 1].max_kdata = to_delete[to_delete.size() - 1].max_kdata; librados::ObjectWriteOperation owos[2 + 2 * to_delete.size() + to_create.size()]; vector, librados::ObjectWriteOperation*> > ops; index_data idata; set_up_prefix_index(to_create, to_delete, &owos[0], &idata, &err); if (verbose) cout << "finished making to_create and to_delete. " << std::endl; ops.push_back(make_pair( pair(ADD_PREFIX, index_name), &owos[0])); for (int i = 1; i < 2 + 2 * (int)to_delete.size() + (int)to_create.size(); i++) { ops.push_back(make_pair(make_pair(0,""), &owos[i])); } set_up_ops(to_create, to_delete, &ops, idata, &err); cout << "finished setting up ops. Starting critical section..." << std::endl; /////BEGIN CRITICAL SECTION///// //put prefix on index entry for idata.val err = perform_ops("\t\t" + client_name + "-set_many:", idata, &ops); if (err < 0) { return set_many(in_map); } if (verbose) cout << "\t\t" << client_name << "-split: done splitting." << std::endl; /////END CRITICAL SECTION///// icache_lock.Lock(); for (vector::iterator it = idata.to_delete.begin(); it != idata.to_delete.end(); ++it) { icache.erase(it->max); } for (vector::iterator it = idata.to_create.begin(); it != idata.to_create.end(); ++it) { icache.push(index_data(*it)); } icache_lock.Unlock(); return err; } int KvFlatBtreeAsync::remove_all() { if (verbose) cout << client_name << ": removing all" << std::endl; int err = 0; librados::ObjectReadOperation oro; librados::AioCompletion * oro_aioc = rados.aio_create_completion(); std::map index_set; oro.omap_get_vals("",LONG_MAX,&index_set,&err); err = io_ctx.aio_operate(index_name, oro_aioc, &oro, NULL); if (err < 0){ if (err == -ENOENT) { return 0; } if (verbose) cout << "getting keys failed with error " << err << std::endl; return err; } oro_aioc->wait_for_safe(); oro_aioc->release(); librados::ObjectWriteOperation rm_index; librados::AioCompletion * rm_index_aioc = rados.aio_create_completion(); map new_index; new_index["1"] = index_set["1"]; rm_index.omap_clear(); rm_index.omap_set(new_index); io_ctx.aio_operate(index_name, rm_index_aioc, &rm_index); err = rm_index_aioc->get_return_value(); rm_index_aioc->release(); if (err < 0) { if (verbose) cout << "rm index aioc failed with " << err << std::endl; return err; } if (!index_set.empty()) { for (std::map::iterator it = index_set.begin(); it != index_set.end(); ++it){ librados::ObjectWriteOperation sub; if (it->first == "1") { sub.omap_clear(); } else { sub.remove(); } index_data idata; bufferlist::iterator b = it->second.begin(); idata.decode(b); io_ctx.operate(idata.obj, &sub); } } icache.clear(); return 0; } int KvFlatBtreeAsync::get_all_keys(std::set *keys) { if (verbose) cout << client_name << ": getting all keys" << std::endl; int err = 0; librados::ObjectReadOperation oro; std::map index_set; oro.omap_get_vals("",LONG_MAX,&index_set,&err); io_ctx.operate(index_name, &oro, NULL); if (err < 0){ if (verbose) cout << "getting keys failed with error " << err << std::endl; return err; } for (std::map::iterator it = index_set.begin(); it != index_set.end(); ++it){ librados::ObjectReadOperation sub; std::set ret; sub.omap_get_keys("",LONG_MAX,&ret,&err); index_data idata; bufferlist::iterator b = it->second.begin(); idata.decode(b); io_ctx.operate(idata.obj, &sub, NULL); keys->insert(ret.begin(), ret.end()); } return err; } int KvFlatBtreeAsync::get_all_keys_and_values( map *kv_map) { if (verbose) cout << client_name << ": getting all keys and values" << std::endl; int err = 0; librados::ObjectReadOperation first_read; std::set index_set; first_read.omap_get_keys("",LONG_MAX,&index_set,&err); io_ctx.operate(index_name, &first_read, NULL); if (err < 0){ if (verbose) cout << "getting keys failed with error " << err << std::endl; return err; } for (std::set::iterator it = index_set.begin(); it != index_set.end(); ++it){ librados::ObjectReadOperation sub; map ret; sub.omap_get_vals("",LONG_MAX,&ret,&err); io_ctx.operate(*it, &sub, NULL); kv_map->insert(ret.begin(), ret.end()); } return err; } bool KvFlatBtreeAsync::is_consistent() { int err; bool ret = true; if (verbose) cout << client_name << ": checking consistency" << std::endl; std::map index; map > sub_objs; librados::ObjectReadOperation oro; oro.omap_get_vals("",LONG_MAX,&index,&err); io_ctx.operate(index_name, &oro, NULL); if (err < 0){ //probably because the index doesn't exist - this might be ok. for (librados::ObjectIterator oit = io_ctx.objects_begin(); oit != io_ctx.objects_end(); ++oit) { //if this executes, there are floating objects. cerr << "Not consistent! found floating object " << oit->first << std::endl; ret = false; } return ret; } std::map parsed_index; std::set onames; std::set special_names; for (map::iterator it = index.begin(); it != index.end(); ++it) { if (it->first != "") { index_data idata; bufferlist::iterator b = it->second.begin(); idata.decode(b); if (idata.prefix != "") { for(vector::iterator dit = idata.to_delete.begin(); dit != idata.to_delete.end(); ++dit) { librados::ObjectReadOperation oro; librados::AioCompletion * aioc = rados.aio_create_completion(); bufferlist un; oro.getxattr("unwritable", &un, &err); io_ctx.aio_operate(dit->obj, aioc, &oro, NULL); aioc->wait_for_safe(); err = aioc->get_return_value(); if (ceph_clock_now(g_ceph_context) - idata.ts > timeout) { if (err < 0) { aioc->release(); if (err == -ENOENT) { continue; } else { cerr << "Not consistent! reading object " << dit->obj << "returned " << err << std::endl; ret = false; break; } } if (atoi(string(un.c_str(), un.length()).c_str()) != 1 && aioc->get_version64() != dit->version) { cerr << "Not consistent! object " << dit->obj << " has been " << " modified since the client died was not cleaned up." << std::endl; ret = false; } } special_names.insert(dit->obj); aioc->release(); } for(vector::iterator cit = idata.to_create.begin(); cit != idata.to_create.end(); ++cit) { special_names.insert(cit->obj); } } parsed_index.insert(make_pair(it->first, idata.obj)); onames.insert(idata.obj); } } //make sure that an object exists iff it either is the index //or is listed in the index for (librados::ObjectIterator oit = io_ctx.objects_begin(); oit != io_ctx.objects_end(); ++oit) { string name = oit->first; if (name != index_name && onames.count(name) == 0 && special_names.count(name) == 0) { cerr << "Not consistent! found floating object " << name << std::endl; ret = false; } } //check objects string prev = ""; for (std::map::iterator it = parsed_index.begin(); it != parsed_index.end(); ++it) { librados::ObjectReadOperation read; read.omap_get_keys("", LONG_MAX, &sub_objs[it->second], &err); err = io_ctx.operate(it->second, &read, NULL); int size_int = (int)sub_objs[it->second].size(); //check that size is in the right range if (it->first != "1" && special_names.count(it->second) == 0 && err != -ENOENT && (size_int > 2*k|| size_int < k) && parsed_index.size() > 1) { cerr << "Not consistent! Object " << *it << " has size " << size_int << ", which is outside the acceptable range." << std::endl; ret = false; } //check that all keys belong in that object for(std::set::iterator subit = sub_objs[it->second].begin(); subit != sub_objs[it->second].end(); ++subit) { if ((it->first != "1" && *subit > it->first.substr(1,it->first.length())) || *subit <= prev) { cerr << "Not consistent! key " << *subit << " does not belong in " << *it << std::endl; cerr << "not last element, i.e. " << it->first << " not equal to 1? " << (it->first != "1") << std::endl << "greater than " << it->first.substr(1,it->first.length()) <<"? " << (*subit > it->first.substr(1,it->first.length())) << std::endl << "less than or equal to " << prev << "? " << (*subit <= prev) << std::endl; ret = false; } } prev = it->first.substr(1,it->first.length()); } if (!ret) { if (verbose) cout << "failed consistency test - see error log" << std::endl; cerr << str(); } else { if (verbose) cout << "passed consistency test" << std::endl; } return ret; } string KvFlatBtreeAsync::str() { stringstream ret; ret << "Top-level map:" << std::endl; int err = 0; std::set keys; std::map index; librados::ObjectReadOperation oro; librados::AioCompletion * top_aioc = rados.aio_create_completion(); oro.omap_get_vals("",LONG_MAX,&index,&err); io_ctx.aio_operate(index_name, top_aioc, &oro, NULL); top_aioc->wait_for_safe(); err = top_aioc->get_return_value(); top_aioc->release(); if (err < 0 && err != -5){ if (verbose) cout << "getting keys failed with error " << err << std::endl; return ret.str(); } if(index.empty()) { ret << "There are no objects!" << std::endl; return ret.str(); } for (map::iterator it = index.begin(); it != index.end(); ++it) { keys.insert(string(it->second.c_str(), it->second.length()) .substr(1,it->second.length())); } vector all_names; vector all_sizes(index.size()); vector all_versions(index.size()); vector all_unwrit(index.size()); vector > all_maps(keys.size()); vector::iterator> its(keys.size()); unsigned done = 0; vector dones(keys.size()); ret << std::endl << string(150,'-') << std::endl; for (map::iterator it = index.begin(); it != index.end(); ++it){ index_data idata; bufferlist::iterator b = it->second.begin(); idata.decode(b); string s = idata.str(); ret << "|" << string((148 - ((*it).first.length()+s.length()+3))/2,' '); ret << (*it).first; ret << " | "; ret << string(idata.str()); ret << string((148 - ((*it).first.length()+s.length()+3))/2,' '); ret << "|\t"; all_names.push_back(idata.obj); ret << std::endl << string(150,'-') << std::endl; } int indexer = 0; //get the object names and sizes for(vector::iterator it = all_names.begin(); it != all_names.end(); ++it) { librados::ObjectReadOperation oro; librados::AioCompletion *aioc = rados.aio_create_completion(); oro.omap_get_vals("", LONG_MAX, &all_maps[indexer], &err); oro.getxattr("unwritable", &all_unwrit[indexer], &err); io_ctx.aio_operate(*it, aioc, &oro, NULL); aioc->wait_for_safe(); if (aioc->get_return_value() < 0) { ret << "reading" << *it << "failed: " << err << std::endl; //return ret.str(); } all_sizes[indexer] = all_maps[indexer].size(); all_versions[indexer] = aioc->get_version64(); indexer++; aioc->release(); } ret << "///////////////////OBJECT NAMES////////////////" << std::endl; //HEADERS ret << std::endl; for (int i = 0; i < indexer; i++) { ret << "---------------------------\t"; } ret << std::endl; for (int i = 0; i < indexer; i++) { ret << "|" << string((25 - (string("Bucket: ").length() + all_names[i].length()))/2, ' '); ret << "Bucket: " << all_names[i]; ret << string((25 - (string("Bucket: ").length() + all_names[i].length()))/2, ' ') << "|\t"; } ret << std::endl; for (int i = 0; i < indexer; i++) { its[i] = all_maps[i].begin(); ret << "|" << string((25 - (string("size: ").length() + to_string("",all_sizes[i]).length()))/2, ' '); ret << "size: " << all_sizes[i]; ret << string((25 - (string("size: ").length() + to_string("",all_sizes[i]).length()))/2, ' ') << "|\t"; } ret << std::endl; for (int i = 0; i < indexer; i++) { its[i] = all_maps[i].begin(); ret << "|" << string((25 - (string("version: ").length() + to_string("",all_versions[i]).length()))/2, ' '); ret << "version: " << all_versions[i]; ret << string((25 - (string("version: ").length() + to_string("",all_versions[i]).length()))/2, ' ') << "|\t"; } ret << std::endl; for (int i = 0; i < indexer; i++) { its[i] = all_maps[i].begin(); ret << "|" << string((25 - (string("unwritable? ").length() + 1))/2, ' '); ret << "unwritable? " << string(all_unwrit[i].c_str(), all_unwrit[i].length()); ret << string((25 - (string("unwritable? ").length() + 1))/2, ' ') << "|\t"; } ret << std::endl; for (int i = 0; i < indexer; i++) { ret << "---------------------------\t"; } ret << std::endl; ret << "///////////////////THE ACTUAL BLOCKS////////////////" << std::endl; ret << std::endl; for (int i = 0; i < indexer; i++) { ret << "---------------------------\t"; } ret << std::endl; //each time through this part is two lines while(done < keys.size()) { for(int i = 0; i < indexer; i++) { if(dones[i]){ ret << " \t"; } else { if (its[i] == all_maps[i].end()){ done++; dones[i] = true; ret << " \t"; } else { ret << "|" << string((25 - ((*its[i]).first.length()+its[i]->second.length()+3))/2,' '); ret << (*its[i]).first; ret << " | "; ret << string(its[i]->second.c_str(), its[i]->second.length()); ret << string((25 - ((*its[i]).first.length()+its[i]->second.length()+3))/2,' '); ret << "|\t"; ++(its[i]); } } } ret << std::endl; for (int i = 0; i < indexer; i++) { if(dones[i]){ ret << " \t"; } else { ret << "---------------------------\t"; } } ret << std::endl; } return ret.str(); } ceph-0.80.11/src/key_value_store/kv_flat_btree_async.h0000664000175100017510000005731612623076744025055 0ustar jenkins-buildjenkins-build/* * Uses a two-level B-tree to store a set of key-value pairs. * * September 2, 2012 * Eleanor Cawthon * eleanor.cawthon@inktank.com * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef KVFLATBTREEASYNC_H_ #define KVFLATBTREEASYNC_H_ #define ESUICIDE 134 #define EPREFIX 136 #define EFIRSTOBJ 138 #include "key_value_store/key_value_structure.h" #include "include/utime.h" #include "include/types.h" #include "include/encoding.h" #include "common/Mutex.h" #include "common/Clock.h" #include "common/Formatter.h" #include "global/global_context.h" #include "include/rados/librados.hpp" #include #include #include #include using namespace std; using ceph::bufferlist; enum { ADD_PREFIX = 1, MAKE_OBJECT = 2, UNWRITE_OBJECT = 3, RESTORE_OBJECT = 4, REMOVE_OBJECT = 5, REMOVE_PREFIX = 6, AIO_MAKE_OBJECT = 7 }; struct rebalance_args; /** * stores information about a key in the index. * * prefix is "0" unless key is "", in which case it is "1". This ensures that * the object with key "" will always be the highest key in the index. */ struct key_data { string raw_key; string prefix; key_data() {} /** * @pre: key is a raw key (does not contain a prefix) */ key_data(string key) : raw_key(key) { raw_key == "" ? prefix = "1" : prefix = "0"; } bool operator==(key_data k) const { return ((raw_key == k.raw_key) && (prefix == k.prefix)); } bool operator!=(key_data k) const { return ((raw_key != k.raw_key) || (prefix != k.prefix)); } bool operator<(key_data k) const { return this->encoded() < k.encoded(); } bool operator>(key_data k) const { return this->encoded() > k.encoded(); } /** * parses the prefix from encoded and stores the data in this. * * @pre: encoded has a prefix */ void parse(string encoded) { prefix = encoded[0]; raw_key = encoded.substr(1,encoded.length()); } /** * returns a string containing the encoded (prefixed) key */ string encoded() const { return prefix + raw_key; } void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(raw_key, bl); ::encode(prefix, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(raw_key, p); ::decode(prefix, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(key_data) /** * Stores information read from a librados object. */ struct object_data { key_data min_kdata; //the max key from the previous index entry key_data max_kdata; //the max key, from the index string name; //the object's name map omap; // the omap of the object bool unwritable; // an xattr that, if false, means an op is in // progress and other clients should not write to it. uint64_t version; //the version at time of read uint64_t size; //the number of elements in the omap object_data() {} object_data(string the_name) : name(the_name) {} object_data(key_data min, key_data kdat, string the_name) : min_kdata(min), max_kdata(kdat), name(the_name) {} object_data(key_data min, key_data kdat, string the_name, map the_omap) : min_kdata(min), max_kdata(kdat), name(the_name), omap(the_omap) {} object_data(key_data min, key_data kdat, string the_name, int the_version) : min_kdata(min), max_kdata(kdat), name(the_name), version(the_version) {} void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(min_kdata, bl); ::encode(max_kdata, bl); ::encode(name, bl); ::encode(omap, bl); ::encode(unwritable, bl); ::encode(version, bl); ::encode(size, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(min_kdata, p); ::decode(max_kdata, p); ::decode(name, p); ::decode(omap, p); ::decode(unwritable, p); ::decode(version, p); ::decode(size, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(object_data) /** * information about objects to be created by a split or merge - stored in the * index_data. */ struct create_data { key_data min; key_data max; string obj; create_data() {} create_data(key_data n, key_data x, string o) : min(n), max(x), obj(o) {} create_data(object_data o) : min(o.min_kdata), max(o.max_kdata), obj(o.name) {} create_data & operator=(const create_data &c) { min = c.min; max = c.max; obj = c.obj; return *this; } void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(min, bl); ::encode(max, bl); ::encode(obj, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(min, p); ::decode(max, p); ::decode(obj, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(create_data) /** * information about objects to be deleted by a split or merge - stored in the * index_data. */ struct delete_data { key_data min; key_data max; string obj; uint64_t version; delete_data() {} delete_data(key_data n, key_data x, string o, uint64_t v) : min(n), max(x), obj(o), version(v) {} delete_data & operator=(const delete_data &d) { min = d.min; max = d.max; obj = d.obj; version = d.version; return *this; } void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(min, bl); ::encode(max, bl); ::encode(obj, bl); ::encode(version, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(min, p); ::decode(max, p); ::decode(obj, p); ::decode(version, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(delete_data) /** * The index object is a key value map that stores * the highest key stored in an object as keys, and an index_data * as the corresponding value. The index_data contains the encoded * high and low keys (where keys in this object are > min_kdata and * <= kdata), the name of the librados object where keys containing * that range of keys are located, and information about split and * merge operations that may need to be cleaned up if a client dies. */ struct index_data { //the encoded key corresponding to the object key_data kdata; //"1" if there is a prefix (because a split or merge is //in progress), otherwise "" string prefix; //the kdata of the previous index entry key_data min_kdata; utime_t ts; //time that a split/merge started //objects to be created vector to_create; //objects to be deleted vector to_delete; //the name of the object where the key range is located. string obj; index_data() {} index_data(string raw_key) : kdata(raw_key) {} index_data(key_data max, key_data min, string o) : kdata(max), min_kdata(min), obj(o) {} index_data(create_data c) : kdata(c.max), min_kdata(c.min), obj(c.obj) {} bool operator<(const index_data &other) const { return (kdata.encoded() < other.kdata.encoded()); } //true if there is a prefix and now - ts > timeout. bool is_timed_out(utime_t now, utime_t timeout) const; void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(prefix, bl); ::encode(min_kdata, bl); ::encode(kdata, bl); ::encode(ts, bl); ::encode(to_create, bl); ::encode(to_delete, bl); ::encode(obj, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(prefix, p); ::decode(min_kdata, p); ::decode(kdata, p); ::decode(ts, p); ::decode(to_create, p); ::decode(to_delete, p); ::decode(obj, p); DECODE_FINISH(p); } /* * Prints a string representation of the information, in the following format: * (min_kdata/ * kdata, * prefix * ts * elements of to_create, organized into (high key| obj name) * ; * elements of to_delete, organized into (high key| obj name | version number) * : * val) */ string str() const { stringstream strm; strm << '(' << min_kdata.encoded() << "/" << kdata.encoded() << ',' << prefix; if (prefix == "1") { strm << ts.sec() << '.' << ts.usec(); for(vector::const_iterator it = to_create.begin(); it != to_create.end(); ++it) { strm << '(' << it->min.encoded() << '/' << it->max.encoded() << '|' << it->obj << ')'; } strm << ';'; for(vector::const_iterator it = to_delete.begin(); it != to_delete.end(); ++it) { strm << '(' << it->min.encoded() << '/' << it->max.encoded() << '|' << it->obj << '|' << it->version << ')'; } strm << ':'; } strm << obj << ')'; return strm.str(); } }; WRITE_CLASS_ENCODER(index_data) /** * Structure to store information read from the index for reuse. */ class IndexCache { protected: map > k2itmap; map t2kmap; int cache_size; public: IndexCache(int n) : cache_size(n) {} /** * Inserts idata into the cache and removes whatever key mapped to before. * If the cache is full, pops the oldest entry. */ void push(const string &key, const index_data &idata); /** * Inserts idata into the cache. If idata.kdata is already in the cache, * replaces the old one. Pops the oldest entry if the cache is full. */ void push(const index_data &idata); /** * Removes the oldest entry from the cache */ void pop(); /** * Removes the value associated with kdata from both maps */ void erase(key_data kdata); /** * gets the idata where key belongs. If none, returns -ENODATA. */ int get(const string &key, index_data *idata) const; /** * Gets the idata where key goes and the one after it. If there are not * valid entries for both of them, returns -ENODATA. */ int get(const string &key, index_data *idata, index_data * next_idata) const; void clear(); }; class KvFlatBtreeAsync; /** * These are used internally to translate aio operations into useful thread * arguments. */ struct aio_set_args { KvFlatBtreeAsync * kvba; string key; bufferlist val; bool exc; callback cb; void * cb_args; int * err; }; struct aio_rm_args { KvFlatBtreeAsync * kvba; string key; callback cb; void * cb_args; int * err; }; struct aio_get_args { KvFlatBtreeAsync * kvba; string key; bufferlist * val; bool exc; callback cb; void * cb_args; int * err; }; class KvFlatBtreeAsync : public KeyValueStructure { protected: //don't change these once operations start being called - they are not //protected with mutexes! int k; string index_name; librados::IoCtx io_ctx; string rados_id; string client_name; librados::Rados rados; string pool_name; injection_t interrupt; int wait_ms; utime_t timeout; //declare a client dead if it goes this long without //finishing a split/merge int cache_size; double cache_refresh; //read cache_size / cache_refresh entries each time the //index is read bool verbose;//if true, display lots of debug output //shared variables protected with mutexes Mutex client_index_lock; int client_index; //names of new objects are client_name.client_index Mutex icache_lock; IndexCache icache; friend struct index_data; /** * finds the object in the index with the lowest key value that is greater * than idata.kdata. If idata.kdata is the max key, returns -EOVERFLOW. If * idata has a prefix and has timed out, cleans up. * * @param idata: idata for the object to search for. * @param out_data: the idata for the next object. * * @pre: idata must contain a key_data. * @post: out_data contains complete information */ int next(const index_data &idata, index_data * out_data); /** * finds the object in the index with the lowest key value that is greater * than idata.kdata. If idata.kdata is the lowest key, returns -ERANGE If * idata has a prefix and has timed out, cleans up. * * @param idata: idata for the object to search for. * @param out_data: the idata for the next object. * * @pre: idata must contain a key_data. * @post: out_data contains complete information */ int prev(const index_data &idata, index_data * out_data); /** * finds the index_data where a key belongs, from cache if possible. If it * reads the index object, it will read the first cache_size entries after * key and put them in the cache. * * @param key: the key to search for * @param idata: the index_data for the first index value such that idata.key * is greater than key. * @param next_idata: if not NULL, this will be set to the idata after idata * @param force_update: if false, will try to read from cache first. * * @pre: key is not encoded * @post: idata contains complete information * stored */ int read_index(const string &key, index_data * idata, index_data * next_idata, bool force_update); /** * Reads obj and generates information about it. Iff the object has >= 2k * entries, reads the whole omap and then splits it. * * @param idata: index data for the object being split * @pre: idata contains a key and an obj * @post: idata.obj has been split and icache has been updated * @return -EBALANCE if obj does not need to be split, 0 if split successful, * error from read_object or perform_ops if there is one. */ int split(const index_data &idata); /** * reads o1 and the next object after o1 and, if necessary, rebalances them. * if hk1 is the highest key in the index, calls rebalance on the next highest * key. * * @param idata: index data for the object being rebalanced * @param next_idata: index data for the next object. If blank, will read. * @pre: idata contains a key and an obj * @post: idata.obj has been rebalanced and icache has been updated * @return -EBALANCE if no change needed, -ENOENT if o1 does not exist, * -ECANCELED if second object does not exist, otherwise, error from * perform_ops */ int rebalance(const index_data &idata1, const index_data &next_idata); /** * performs an ObjectReadOperation to populate odata * * @post: odata has all information about obj except for key (which is "") */ int read_object(const string &obj, object_data * odata); /** * performs a maybe_read_for_balance ObjectOperation so the omap is only * read if the object is out of bounds. */ int read_object(const string &obj, rebalance_args * args); /** * sets up owo to change the index in preparation for a split/merge. * * @param to_create: vector of object_data to be created. * @param to_delete: vector of object_data to be deleted. * @param owo: the ObjectWriteOperation to set up * @param idata: will be populated by index data for this op. * @param err: error code reference to pass to omap_cmp * @pre: entries in to_create and to_delete must have keys and names. */ void set_up_prefix_index( const vector &to_create, const vector &to_delete, librados::ObjectWriteOperation * owo, index_data * idata, int * err); /** * sets up all make, mark, restore, and delete ops, as well as the remove * prefix op, based on idata. * * @param create_vector: vector of data about the objects to be created. * @pre: entries in create_data must have names and omaps and be in idata * order * @param delete_vector: vector of data about the objects to be deleted * @pre: entries in to_delete must have versions and be in idata order * @param ops: the owos to set up. the pair is a pair of op identifiers * and names of objects - set_up_ops fills these in. * @pre: ops must be the correct size and the ObjectWriteOperation pointers * must be valid. * @param idata: the idata with information about how to set up the ops * @pre: idata has valid to_create and to_delete * @param err: the int to get the error value for omap_cmp */ void set_up_ops( const vector &create_vector, const vector &delete_vector, vector, librados::ObjectWriteOperation*> > * ops, const index_data &idata, int * err); /** * sets up owo to exclusive create, set omap to to_set, and set * unwritable to "0" */ void set_up_make_object( const map &to_set, librados::ObjectWriteOperation *owo); /** * sets up owo to assert object version and that object version is * writable, * then mark it unwritable. * * @param ver: if this is 0, no version is asserted. */ void set_up_unwrite_object( const int &ver, librados::ObjectWriteOperation *owo); /** * sets up owo to assert that an object is unwritable and then mark it * writable */ void set_up_restore_object( librados::ObjectWriteOperation *owo); /** * sets up owo to assert that the object is unwritable and then remove it */ void set_up_delete_object( librados::ObjectWriteOperation *owo); /** * perform the operations in ops and handles errors. * * @param debug_prefix: what to print at the beginning of debug output * @param idata: the idata for the object being operated on, to be * passed to cleanup if necessary * @param ops: this contains an int identifying the type of op, * a string that is the name of the object to operate on, and a pointer * to the ObjectWriteOperation to use. All of this must be complete. * @post: all operations are performed and most errors are handled * (e.g., cleans up if an assertion fails). If an unknown error is found, * returns it. */ int perform_ops( const string &debug_prefix, const index_data &idata, vector, librados::ObjectWriteOperation*> > * ops); /** * Called when a client discovers that another client has died during a * split or a merge. cleans up after that client. * * @param idata: the index data parsed from the index entry left by the dead * client. * @param errno: the error that caused the client to realize the other client * died (should be -ENOENT or -ETIMEDOUT) * @post: rolls forward if -ENOENT, otherwise rolls back. */ int cleanup(const index_data &idata, const int &error); /** * does the ObjectWriteOperation and splits, reads the index, and/or retries * until success. */ int set_op(const string &key, const bufferlist &val, bool update_on_existing, index_data &idata); /** * does the ObjectWriteOperation and merges, reads the index, and/or retries * until success. */ int remove_op(const string &key, index_data &idata, index_data &next_idata); /** * does the ObjectWriteOperation and reads the index and/or retries * until success. */ int get_op(const string &key, bufferlist * val, index_data &idata); /** * does the ObjectWriteOperation and splits, reads the index, and/or retries * until success. */ int handle_set_rm_errors(int &err, string key, string obj, index_data * idata, index_data * next_idata); /** * called by aio_set, aio_remove, and aio_get, respectively. */ static void* pset(void *ptr); static void* prm(void *ptr); static void* pget(void *ptr); public: //interruption methods, for correctness testing /** * returns 0 */ int nothing(); /** * 10% chance of waiting wait_ms seconds */ int wait(); /** * 10% chance of killing the client. */ int suicide(); KvFlatBtreeAsync(int k_val, string name, int cache, double cache_r, bool verb) : k(k_val), index_name("index_object"), rados_id(name), client_name(string(name).append(".")), pool_name("data"), interrupt(&KeyValueStructure::nothing), timeout(100000,0), cache_size(cache), cache_refresh(cache_r), verbose(verb), client_index_lock("client_index_lock"), client_index(0), icache_lock("icache_lock"), icache(cache) {} /** * creates a string with an int at the end. * * @param s: the string on the left * @param i: the int to be appended to the string * @return the string */ static string to_string(string s, int i); /** * returns in encoded */ static bufferlist to_bl(const string &in) { bufferlist bl; bl.append(in); return bl; } /** * returns idata encoded; */ static bufferlist to_bl(const index_data &idata) { bufferlist bl; idata.encode(bl); return bl; } /** * returns the rados_id of this KvFlatBtreeAsync */ string get_name(); /** * sets this kvba to call inject before every ObjectWriteOperation. * If inject is wait and wait_time is set, wait will have a 10% chance of * sleeping for waite_time miliseconds. */ void set_inject(injection_t inject, int wait_time); /** * sets up the rados and io_ctx of this KvFlatBtreeAsync. If the don't already * exist, creates the index and max object. */ int setup(int argc, const char** argv); int set(const string &key, const bufferlist &val, bool update_on_existing); int remove(const string &key); /** * returns true if all of the following are true: * * all objects are accounted for in the index or a prefix * (i.e., no floating objects) * all objects have k <= size <= 2k * all keys in an object are within the specified predicted by the index * * if any of those fails, states that the problem(s) are, and prints str(). * * @pre: no operations are in progress */ bool is_consistent(); /** * returns an ASCII representation of the index and sub objects, showing * stats about each object and all omaps. Don't use if you have more than * about 10 objects. */ string str(); int get(const string &key, bufferlist *val); //async versions of these methods void aio_get(const string &key, bufferlist *val, callback cb, void *cb_args, int * err); void aio_set(const string &key, const bufferlist &val, bool exclusive, callback cb, void * cb_args, int * err); void aio_remove(const string &key, callback cb, void *cb_args, int * err); //these methods that deal with multiple keys at once are efficient, but make //no guarantees about atomicity! /** * Removes all objects and resets the store as if setup had just run. Makes no * attempt to do this safely - make sure this is the only operation running * when it is called! */ int remove_all(); /** * This does not add prefixes to the index and therefore DOES NOT guarantee * consistency! It is ONLY safe if there is only one instance at a time. * It follows the same general logic as a rebalance, but * with all objects that contain any of the keys in in_map. It is O(n), where * n is the number of librados objects it has to change. Higher object sizes * (i.e., k values) also decrease the efficiency of this method because it * copies all of the entries in each object it modifies. Writing new objects * is done in parallel. * * This is efficient if: * * other clients are very unlikely to be modifying any of the objects while * this operation is in progress * * The entries in in_map are close together * * It is especially efficient for initially entering lots of entries into * an empty structure. * * It is very inefficient compared to setting one key and/or will starve if: * * other clients are modifying the objects it tries to modify * * The keys are distributed across the range of keys in the store * * there is a small number of keys compared to k */ int set_many(const map &in_map); int get_all_keys(std::set *keys); int get_all_keys_and_values(map *kv_map); }; #endif /* KVFLATBTREEASYNC_H_ */ ceph-0.80.11/src/key_value_store/Makefile.am0000664000175100017510000000061512623076744022722 0ustar jenkins-buildjenkins-buildif LINUX libcls_kvs_la_SOURCES = key_value_store/cls_kvs.cc libcls_kvs_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_kvs_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_kvs.la endif noinst_HEADERS += \ key_value_store/key_value_structure.h \ key_value_store/kv_flat_btree_async.h \ key_value_store/kvs_arg_types.h ceph-0.80.11/src/key_value_store/kvs_arg_types.h0000664000175100017510000000575712623076744023733 0ustar jenkins-buildjenkins-build/* * Argument types used by cls_kvs.cc * * Created on: Aug 10, 2012 * Author: eleanor */ #ifndef CLS_KVS_H_ #define CLS_KVS_H_ #define EBALANCE 137 #include "include/encoding.h" #include "key_value_store/kv_flat_btree_async.h" using namespace std; using ceph::bufferlist; struct assert_size_args { uint64_t bound; //the size to compare to - should be k or 2k uint64_t comparator; //should be CEPH_OSD_CMPXATTR_OP_EQ, //CEPH_OSD_CMPXATTR_OP_LT, or //CEPH_OSD_CMPXATTR_OP_GT void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(bound, bl); ::encode(comparator, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(bound, p); ::decode(comparator, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(assert_size_args) struct idata_from_key_args { string key; index_data idata; index_data next_idata; void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(key, bl); ::encode(idata, bl); ::encode(next_idata, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(key, p); ::decode(idata, p); ::decode(next_idata, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(idata_from_key_args) struct idata_from_idata_args { index_data idata; index_data next_idata; void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(idata, bl); ::encode(next_idata, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(idata, p); ::decode(next_idata, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(idata_from_idata_args) struct omap_set_args { map omap; uint64_t bound; bool exclusive; void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(omap, bl); ::encode(bound, bl); ::encode(exclusive, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(omap, p); ::decode(bound, p); ::decode(exclusive, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(omap_set_args) struct omap_rm_args { std::set omap; uint64_t bound; void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(omap, bl); ::encode(bound, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(omap, p); ::decode(bound, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(omap_rm_args) struct rebalance_args { object_data odata; uint64_t bound; uint64_t comparator; void encode(bufferlist &bl) const { ENCODE_START(1,1,bl); ::encode(odata, bl); ::encode(bound, bl); ::encode(comparator, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START(1, p); ::decode(odata,p); ::decode(bound, p); ::decode(comparator, p); DECODE_FINISH(p); } }; WRITE_CLASS_ENCODER(rebalance_args) #endif /* CLS_KVS_H_ */ ceph-0.80.11/src/key_value_store/key_value_structure.h0000664000175100017510000000745412623076744025153 0ustar jenkins-buildjenkins-build/* * Interface for key-value store using librados * * September 2, 2012 * Eleanor Cawthon * eleanor.cawthon@inktank.com * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef KEY_VALUE_STRUCTURE_HPP_ #define KEY_VALUE_STRUCTURE_HPP_ #include "include/rados/librados.hpp" #include "include/utime.h" #include using std::string; using std::map; using std::set; using ceph::bufferlist; class KeyValueStructure; /**An injection_t is a function that is called before every * ObjectWriteOperation to test concurrency issues. For example, * one injection_t might cause the client to have a greater chance of dying * mid-split/merge. */ typedef int (KeyValueStructure::*injection_t)(); /** * Passed to aio methods to be called when the operation completes */ typedef void (*callback)(int * err, void *arg); class KeyValueStructure{ public: map opmap; //these are injection methods. By default, nothing is called at each //interruption point. /** * returns 0 */ virtual int nothing() = 0; /** * 10% chance of waiting wait_ms seconds */ virtual int wait() = 0; /** * 10% chance of killing the client. */ virtual int suicide() = 0; ////////////////DESTRUCTOR///////////////// virtual ~KeyValueStructure() {}; ////////////////UPDATERS/////////////////// /** * set up the KeyValueStructure (i.e., initialize rados/io_ctx, etc.) */ virtual int setup(int argc, const char** argv) = 0; /** * set the method that gets called before each ObjectWriteOperation. * If waite_time is set and the method passed involves waiting, it will wait * for that many miliseconds. */ virtual void set_inject(injection_t inject, int wait_time) = 0; /** * if update_on_existing is false, returns an error if * key already exists in the structure */ virtual int set(const string &key, const bufferlist &val, bool update_on_existing) = 0; /** * efficiently insert the contents of in_map into the structure */ virtual int set_many(const map &in_map) = 0; /** * removes the key-value for key. returns an error if key does not exist */ virtual int remove(const string &key) = 0; /** * removes all keys and values */ virtual int remove_all() = 0; /** * launches a thread to get the value of key. When complete, calls cb(cb_args) */ virtual void aio_get(const string &key, bufferlist *val, callback cb, void *cb_args, int * err) = 0; /** * launches a thread to set key to val. When complete, calls cb(cb_args) */ virtual void aio_set(const string &key, const bufferlist &val, bool exclusive, callback cb, void * cb_args, int * err) = 0; /** * launches a thread to remove key. When complete, calls cb(cb_args) */ virtual void aio_remove(const string &key, callback cb, void *cb_args, int * err) = 0; ////////////////READERS//////////////////// /** * gets the val associated with key. * * @param key the key to get * @param val the value is stored in this * @return error code */ virtual int get(const string &key, bufferlist *val) = 0; /** * stores all keys in keys. set should put them in order by key. */ virtual int get_all_keys(std::set *keys) = 0; /** * stores all keys and values in kv_map. map should put them in order by key. */ virtual int get_all_keys_and_values(map *kv_map) = 0; /** * True if the structure meets its own requirements for consistency. */ virtual bool is_consistent() = 0; /** * prints a string representation of the structure */ virtual string str() = 0; }; #endif /* KEY_VALUE_STRUCTURE_HPP_ */ ceph-0.80.11/src/brag/0000775000175100017510000000000012623077036016372 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/README.md0000664000175100017510000001105012623076744017653 0ustar jenkins-buildjenkins-build# Ceph-brag `ceph-brag` is going to be an anonymized cluster reporting tool designed to collect a "registry" of Ceph clusters for community knowledge. This data will be displayed on a public web page using UUID by default, but users can claim their cluster and publish information about ownership if they so desire. For more information please visit: * [Blueprint](http://wiki.ceph.com/Planning/Blueprints/Firefly/Ceph-Brag) * [CDS Etherpad](http://pad.ceph.com/p/cdsfirefly-ceph-brag) # Client ## How to use: ### Pre-requisites: ceph-brag uses 'ceph' python script. Hence, before executing ceph-brag script ensure that ceph services are all running and 'ceph' script is in 'PATH' environment ### Runtime instructions: Run 'ceph-brag -h' to get the usage information of this tool. ### Sample output: { "cluster_creation_date": "2014-01-16 13:38:41.928551", "uuid": "20679d0e-04b1-4004-8ee9-45ac271510e9", "components_count": { "num_data_bytes": 0, "num_bytes_total": 1209312904, "num_osds": 1, "num_objects": 0, "num_pgs": 192, "num_pools": 3, "num_mdss": 1, "num_mons": 1 }, "crush_types": [ { "type": "osd" "count": 2, }, { "type": "rack" "count": 1, }, { "type": "host" "count": 1, }, { "type": "root" "count": 1, } ], "ownership": { "organization": "eNovance", "description": "Use case1", "email": "mail@enovance.com", "name": "Cluster1" }, "pool_metadata": [ { "size": 3, "id": 0, "type": 1 }, { "size": 3, "id": 1, "type": 1 }, { "size": 3, "id": 2, "name": 1 } ], "sysinfo": { "kernel_types": [ { "count": 1, "type": "#36-Ubuntu SMP Tue Apr 10 22:29:03 UTC 2012" } ], "cpu_archs": [ { "count": 1, "arch": "x86_64" } ], "cpus": [ { "count": 1, "cpu": "Intel Xeon E312xx (Sandy Bridge)" } ], "kernel_versions": [ { "count": 1, "version": "3.2.0-23-virtual" } ], "ceph_versions": [ { "count": 1, "version": "0.75-229-g4050eae(4050eae32cd77a1c210ca11d0f12c74daecb1bd3)" } ], "os_info": [ { "count": 1, "os": "Linux" } ], "distros": [ { "count": 1, "distro": "Ubuntu 12.04 precise (Ubuntu 12.04 LTS)" } ] } } # Server ## Info The ceph-brag server code is a python based web application. ## How to use ### Prerequisites * [pecan](http://pecanpy.org) is the web framework that is used by this application. * [sqlalchemy](www.sqlalchemy.org) is the ORM that is used by this application ### How to deploy * [Common recipes to deploy](http://pecan.readthedocs.org/en/latest/deployment.html#common-recipes) * Modify server/config.py:sqlalchemy['url'] to point the correct database connection ## URLs Following are the REST urls that are implemented with 'url-prefix' being the mount point for the WSGI script ### GET ##### * GET /url-prefix/ Returns the list of clusters that are registered so far. Outputs - On success application/json of the following format is returned [ { "num_versions": 3, "cluster_creation_date": "2014-01-16 13:38:41.928551", "uuid": "20679d0e-04b1-4004-8ee9-45ac271510e9", "cluster_name": "Cluster1", "organization": "eNovance", "email": "mail@enovance.com" }, ... ] ##### * GET /url-prefix/UUID Returns the list of version information for a particular UUID. Outputs - On success application/json of the following format is returned [ { "version_number": 1, "version_date": "2014-02-10 10:17:56.283499" }, ... ] ##### * GET /url-prefix/UUID/version\_number Returns the entire brag report as mentioned in client's sample output for a particular version of a UUID ### PUT ##### * PUT /url-prefix Uploads the brag report and creates a new version for the UUID mentioned in the payload ### DELETE ##### * DELETE /url-prefix?uuid=xxxx Deletes all the versions of a cluster whose UUID is sent as a parameter ceph-0.80.11/src/brag/client/0000775000175100017510000000000012623076744017655 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/client/ceph-brag0000775000175100017510000003611412623076744021440 0ustar jenkins-buildjenkins-build#!/usr/bin/env python import subprocess import uuid import re import json import sys import ast import requests from operator import itemgetter from heapq import nlargest from itertools import repeat, ifilter CLUSTER_UUID_NAME='cluster-uuid' CLUSTER_OWNERSHIP_NAME='cluster-ownership' class Counter(dict): '''Dict subclass for counting hashable objects. Sometimes called a bag or multiset. Elements are stored as dictionary keys and their counts are stored as dictionary values. >>> Counter('zyzygy') Counter({'y': 3, 'z': 2, 'g': 1}) ''' def __init__(self, iterable=None, **kwds): '''Create a new, empty Counter object. And if given, count elements from an input iterable. Or, initialize the count from another mapping of elements to their counts. >>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' self.update(iterable, **kwds) def __missing__(self, key): return 0 def most_common(self, n=None): '''List the n most common elements and their counts from the most common to the least. If n is None, then list all element counts. >>> Counter('abracadabra').most_common(3) [('a', 5), ('r', 2), ('b', 2)] ''' if n is None: return sorted(self.iteritems(), key=itemgetter(1), reverse=True) return nlargest(n, self.iteritems(), key=itemgetter(1)) def elements(self): '''Iterator over elements repeating each as many times as its count. >>> c = Counter('ABCABC') >>> sorted(c.elements()) ['A', 'A', 'B', 'B', 'C', 'C'] If an element's count has been set to zero or is a negative number, elements() will ignore it. ''' for elem, count in self.iteritems(): for _ in repeat(None, count): yield elem # Override dict methods where the meaning changes for Counter objects. @classmethod def fromkeys(cls, iterable, v=None): raise NotImplementedError( 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') def update(self, iterable=None, **kwds): '''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. >>> c = Counter('which') >>> c.update('witch') # add elements from another iterable >>> d = Counter('watch') >>> c.update(d) # add elements from another counter >>> c['h'] # four 'h' in which, witch, and watch 4 ''' if iterable is not None: if hasattr(iterable, 'iteritems'): if self: self_get = self.get for elem, count in iterable.iteritems(): self[elem] = self_get(elem, 0) + count else: dict.update(self, iterable) # fast path when counter is empty else: self_get = self.get for elem in iterable: self[elem] = self_get(elem, 0) + 1 if kwds: self.update(kwds) def copy(self): 'Like dict.copy() but returns a Counter instance instead of a dict.' return Counter(self) def __delitem__(self, elem): 'Like dict.__delitem__() but does not raise KeyError for missing values.' if elem in self: dict.__delitem__(self, elem) def __repr__(self): if not self: return '%s()' % self.__class__.__name__ items = ', '.join(map('%r: %r'.__mod__, self.most_common())) return '%s({%s})' % (self.__class__.__name__, items) # Multiset-style mathematical operations discussed in: # Knuth TAOCP Volume II section 4.6.3 exercise 19 # and at http://en.wikipedia.org/wiki/Multiset # # Outputs guaranteed to only include positive counts. # # To strip negative and zero counts, add-in an empty counter: # c += Counter() def __add__(self, other): '''Add counts from two counters. >>> Counter('abbb') + Counter('bcc') Counter({'b': 4, 'c': 2, 'a': 1}) ''' if not isinstance(other, Counter): return NotImplemented result = Counter() for elem in set(self) | set(other): newcount = self[elem] + other[elem] if newcount > 0: result[elem] = newcount return result def __sub__(self, other): ''' Subtract count, but keep only results with positive counts. >>> Counter('abbbc') - Counter('bccd') Counter({'b': 2, 'a': 1}) ''' if not isinstance(other, Counter): return NotImplemented result = Counter() for elem in set(self) | set(other): newcount = self[elem] - other[elem] if newcount > 0: result[elem] = newcount return result def __or__(self, other): '''Union is the maximum of value in either of the input counters. >>> Counter('abbb') | Counter('bcc') Counter({'b': 3, 'c': 2, 'a': 1}) ''' if not isinstance(other, Counter): return NotImplemented _max = max result = Counter() for elem in set(self) | set(other): newcount = _max(self[elem], other[elem]) if newcount > 0: result[elem] = newcount return result def __and__(self, other): ''' Intersection is the minimum of corresponding counts. >>> Counter('abbb') & Counter('bcc') Counter({'b': 1}) ''' if not isinstance(other, Counter): return NotImplemented _min = min result = Counter() if len(self) < len(other): self, other = other, self for elem in ifilter(self.__contains__, other): newcount = _min(self[elem], other[elem]) if newcount > 0: result[elem] = newcount return result def run_command(cmd): child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (o, e) = child.communicate() return (child.returncode, o, e) def get_uuid(): (rc,uid,e) = run_command(['ceph', 'config-key', 'get', CLUSTER_UUID_NAME]) if rc is not 0: #uuid is not yet set. uid = str(uuid.uuid4()) (rc, o, e) = run_command(['ceph', 'config-key', 'put', CLUSTER_UUID_NAME, uid]) if rc is not 0: raise RuntimeError("\'ceph config-key put\' failed -" + e) return uid def bytes_pretty_to_raw(byte_count, byte_scale): if byte_scale == 'kB': return byte_count >> 10 if byte_scale == 'MB': return byte_count >> 20 if byte_scale == 'GB': return byte_count >> 30 if byte_scale == 'TB': return byte_count >> 40 if byte_scale == 'PB': return byte_count >> 50 if byte_scale == 'EB': return byte_count >> 60 return byte_count def get_nums(): (rc, o, e) = run_command(['ceph', '-s', '-f', 'json']) if rc is not 0: raise RuntimeError("\'ceph -s\' failed - " + e) oj = json.loads(o) num_mons = len(oj['monmap']['mons']) num_osds = int(oj['osdmap']['osdmap']['num_in_osds']) num_mdss = oj['mdsmap']['in'] pgmap = oj['pgmap'] num_pgs = pgmap['num_pgs'] num_data_bytes = pgmap['data_bytes'] num_bytes_total = pgmap['bytes_total'] (rc, o, e) = run_command(['ceph', 'pg', 'dump', 'pools', '-f', 'json-pretty']) if rc is not 0: raise RuntimeError("\'ceph pg dump pools\' failed - " + e) pools = json.loads(o) num_pools = len(pools) num_objs = 0 for p in pools: num_objs += p['stat_sum']['num_objects'] nums = {'num_mons':num_mons, 'num_osds':num_osds, 'num_mdss':num_mdss, 'num_pgs':num_pgs, 'num_data_bytes':num_data_bytes, 'num_bytes_total':num_bytes_total, 'num_pools':num_pools, 'num_objects':num_objs} return nums def get_crush_types(): (rc, o, e) = run_command(['ceph', 'osd', 'crush', 'dump']) if rc is not 0: raise RuntimeError("\'ceph osd crush dump\' failed - " + e) crush_dump = json.loads(o) if crush_dump['types'] is None: raise RuntimeError("\'types\' item missing in \'ceph osd crush dump\'") crush_types = {} for t in crush_dump['types']: crush_types[t['type_id']] = t['name'] types_list = [] for bucket in crush_dump['buckets']: types_list.append(bucket['type_id']) crush_map = [] types_counter = Counter(types_list) append = lambda t,c: crush_map.append({'type':t, 'count':c}) for id,count in types_counter.items(): append(crush_types[id], count) if 'devices' in crush_dump: append('devices', len(crush_dump['devices'])) return crush_map def get_osd_dump_info(): (rc, o, e) = run_command(['ceph', 'osd', 'dump', '-f', 'json']) if rc is not 0: raise RuntimeError("\'ceph osd dump\' failed - " + e) pool_meta = [] oj = json.loads(o) proc = lambda x: {'id':x['pool'], 'type':x['type'], 'size':x['size']} for p in oj['pools']: pool_meta.append(proc(p)) return oj['created'], pool_meta def get_sysinfo(max_osds): count = 0 osd_metadata_available = False os = {} kern_version = {} kern_description = {} distro = {} cpu = {} arch = {} ceph_version = {} incr = lambda a,k: 1 if k not in a else a[k]+1 while count < max_osds: meta = {'id':count} (rc, o, e) = run_command(['ceph', 'osd', 'metadata', str(count)]) if rc is 0: if osd_metadata_available is False: osd_metadata_available = True jmeta = json.loads(o) version = jmeta['ceph_version'].split() cv = version[2] if (len(version) > 3): cv += version[3] ceph_version[cv] = incr(ceph_version, cv) os[jmeta['os']] = incr(os, jmeta['os']) kern_version[jmeta['kernel_version']] = \ incr(kern_version, jmeta['kernel_version']) kern_description[jmeta['kernel_description']] = \ incr(kern_description, jmeta['kernel_description']) try: dstr = jmeta['distro'] + ' ' dstr += jmeta['distro_version'] + ' ' dstr += jmeta['distro_codename'] + ' (' dstr += jmeta['distro_description'] + ')' distro[dstr] = incr(distro, dstr) except KeyError as ke: pass cpu[jmeta['cpu']] = incr(cpu, jmeta['cpu']) arch[jmeta['arch']] = incr(arch, jmeta['arch']) count = count + 1 sysinfo = {} if osd_metadata_available is False: print >> sys.stderr, "'ceph osd metadata' is not available at all" return sysinfo def jsonify(type_count, name, type_name): tmp = [] for k, v in type_count.items(): tmp.append({type_name:k, 'count':v}) sysinfo[name] = tmp jsonify(os, 'os_info', 'os') jsonify(kern_version, 'kernel_versions', 'version') jsonify(kern_description, 'kernel_types', 'type') jsonify(distro, 'distros', 'distro') jsonify(cpu, 'cpus', 'cpu') jsonify(arch, 'cpu_archs', 'arch') jsonify(ceph_version, 'ceph_versions', 'version') return sysinfo def get_ownership_info(): (rc, o, e) = run_command(['ceph', 'config-key', 'get', CLUSTER_OWNERSHIP_NAME]) if rc is not 0: return {} return ast.literal_eval(o) def output_json(): out = {} url = None out['uuid'] = get_uuid() nums = get_nums() num_osds = int(nums['num_osds']) out['components_count'] = nums out['crush_types'] = get_crush_types() out['cluster_creation_date'], out['pool_metadata'] = get_osd_dump_info() out['sysinfo'] = get_sysinfo(num_osds) owner = get_ownership_info() if owner is not None: out['ownership'] = owner if 'url' in owner: url = owner.pop('url') return json.dumps(out, indent=2, separators=(',', ': ')), url def describe_usage(): print >> sys.stderr, "Usage:" print >> sys.stderr, "======\n" print >> sys.stderr, sys.argv[0] + " [command-options]\n" print >> sys.stderr, "commands:" print >> sys.stderr, "publish - publish the brag report to the server" print >> sys.stderr, "update-metadata - Update" print >> sys.stderr, " ownership information for bragging" print >> sys.stderr, "clear-metadata - Clear information set by update-metadata" print >> sys.stderr, "unpublish --yes-i-am-shy - delete the brag report from the server" print >> sys.stderr, "" print >> sys.stderr, "update-metadata options:" print >> sys.stderr, "--name= - Name of the cluster" print >> sys.stderr, "--organization= - Name of the organization" print >> sys.stderr, "--email= - Email contact address" print >> sys.stderr, "--description= - Reporting use-case" print >> sys.stderr, "--url= - The URL that is used to publish and unpublish" print >> sys.stderr, "" def update_metadata(): info = {} possibles = ['name', 'organization', 'email', 'description', 'url'] #get the existing values info = get_ownership_info(); for index in range(2, len(sys.argv)): mo = re.search("--(\S+)=(.*)", sys.argv[index]) if not mo: describe_usage() return 22 k = mo.group(1) v = mo.group(2) if k in possibles: info[k] = v else: print >> sys.stderr, "Unexpect option --" + k describe_usage() return 22 (rc, o, e) = run_command(['ceph', 'config-key', 'put', CLUSTER_OWNERSHIP_NAME, str(info)]) return rc def clear_metadata(): (rc, o, e) = run_command(['ceph', 'config-key', 'del', CLUSTER_OWNERSHIP_NAME]) return rc def publish(): data, url = output_json() if url is None: print >> sys.stderr, "Cannot publish until a URL is set using update-metadata" return 1 req = requests.put(url, data=data) if req.status_code is not 201: print >> sys.stderr, "Failed to publish, server responded with code " + str(req.status_code) print >> sys.stderr, req.text return 1 return 0 def unpublish(): if len(sys.argv) <= 2 or sys.argv[2] != '--yes-i-am-shy': print >> sys.stderr, "unpublish should be followed by --yes-i-am-shy" return 22 fail = False owner = get_ownership_info() if owner is None: fail = True try: url = owner['url'] except KeyError as e: fail = True if fail: print >> sys.stderr, "URL is not updated yet" return 1 uuid = get_uuid() params = {'uuid':uuid} req = requests.delete(url, params=params) if req.status_code is not 200: print >> sys.stderr, "Failed to unpublish, server responsed with code " + str(req.status_code) return 1 return 0 def main(): if len(sys.argv) is 1: print output_json()[0] return 0 elif sys.argv[1] == 'update-metadata': return update_metadata() elif sys.argv[1] == 'clear-metadata': return clear_metadata() elif sys.argv[1] == 'publish': return publish() elif sys.argv[1] == 'unpublish': return unpublish() else: describe_usage() return 22 if __name__ == '__main__': sys.exit(main()) ceph-0.80.11/src/brag/server/0000775000175100017510000000000012623076744017705 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/MANIFEST.in0000664000175100017510000000003312623076744021437 0ustar jenkins-buildjenkins-buildrecursive-include public * ceph-0.80.11/src/brag/server/app.wsgi0000664000175100017510000000017612623076744021364 0ustar jenkins-buildjenkins-buildimport os from pecan.deploy import deploy cur_path = os.path.dirname(__file__) application = deploy(cur_path + '/config.py') ceph-0.80.11/src/brag/server/setup.py0000664000175100017510000000075012623076744021421 0ustar jenkins-buildjenkins-build# -*- coding: utf-8 -*- try: from setuptools import setup, find_packages except ImportError: from ez_setup import use_setuptools use_setuptools() from setuptools import setup, find_packages setup( name='ceph_brag', version='0.1', description='', author='', author_email='', install_requires=[ "pecan", ], test_suite='ceph_brag', zip_safe=False, include_package_data=True, packages=find_packages(exclude=['ez_setup']) ) ceph-0.80.11/src/brag/server/setup.cfg0000664000175100017510000000013212623076744021522 0ustar jenkins-buildjenkins-build[nosetests] match=^test where=ceph_brag nocapture=1 cover-package=ceph_brag cover-erase=1 ceph-0.80.11/src/brag/server/sample.json0000664000175100017510000000316512623076744022066 0ustar jenkins-buildjenkins-build{ "cluster_creation_date": "2014-01-16 13:38:41.928551", "uuid": "20679d0e-04b1-4004-8ee9-45ac271510e9", "components_count": { "num_pgs": 192, "num_mdss": 1, "num_osds": 1, "num_bytes": 0, "num_pools": 3, "num_mons": 1, "num_objects": 0 }, "crush_types": [ { "count": 1, "type": "osd" }, { "count": 1, "type": "rack" }, { "count": 1, "type": "host" }, { "count": 1, "type": "root" } ], "ownership": { "organization": "eNovance", "description": "Use case1", "name": "Cluster1", "email": "mail@enovance.com" }, "pool_metadata": [ { "type": 1, "id": 0, "size": 3 }, { "type": 1, "id": 1, "size": 3 }, { "type": 1, "id": 2, "size": 3 } ], "sysinfo": { "kernel_types": [ { "count": 1, "type": "#36-Ubuntu SMP Tue Apr 10 22:29:03 UTC 2012" } ], "cpu_archs": [ { "count": 1, "arch": "x86_64" } ], "cpus": [ { "count": 1, "cpu": "Intel Xeon E312xx (Sandy Bridge)" } ], "kernel_versions": [ { "count": 1, "version": "3.2.0-23-virtual" } ], "ceph_versions": [ { "count": 1, "version": "0.75-229-g4050eae(4050eae32cd77a1c210ca11d0f12c74daecb1bd3)" } ], "os_info": [ { "count": 1, "os": "Linux" } ], "distros": [ { "count": 1, "distro": "Ubuntu 12.04 precise (Ubuntu 12.04 LTS)" } ] } } ceph-0.80.11/src/brag/server/ceph_brag/0000775000175100017510000000000012623076744021617 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag/json.py0000664000175100017510000000652012623076744023145 0ustar jenkins-buildjenkins-buildfrom pecan.jsonify import jsonify from ceph_brag.model import db @jsonify.register(db.version_info) def jsonify_version(vi): return dict( version_number=vi.version_number, version_date=str(vi.version_date) ) @jsonify.register(db.cluster_info) def jsonify_cluster_info(ci): return dict( uuid=ci.uuid, organization=ci.organization, email=ci.contact_email, cluster_name=ci.cluster_name, cluster_creation_date=str(ci.cluster_creation_date), num_versions=ci.num_versions ) @jsonify.register(db.components_info) def jsonify_components_info(comps): return dict( num_data_bytes=comps.num_data_bytes, num_bytes_total=comps.num_bytes_total, num_osds=comps.num_osds, num_objects=comps.num_objects, num_pgs=comps.num_pgs, num_pools=comps.num_pools, num_mdss=comps.num_mdss, num_mons=comps.num_mons) @jsonify.register(db.crush_types) def jsonify_crush_types(crush): return dict(type=crush.crush_type, count=crush.crush_count) @jsonify.register(db.pools_info) def jsonify_pools_info(pool): return dict(size=pool.pool_rep_size, type=pool.pool_type, id=pool.pool_id) @jsonify.register(db.os_info) def jsonify_os_info(value): return dict(os=value.os, count=value.count) @jsonify.register(db.kernel_versions) def jsonify_kernel_versions(value): return dict(version=value.version, count=value.count) @jsonify.register(db.kernel_types) def jsonify_kernel_types(value): return dict(type=value.type, count=value.count) @jsonify.register(db.distros) def jsonify_distros(value): return dict(distro=value.distro, count=value.count) @jsonify.register(db.cpus) def jsonify_cpus(value): return dict(cpu=value.cpu, count=value.count) @jsonify.register(db.cpu_archs) def jsonify_cpu_archs(value): return dict(arch=value.arch, count=value.count) @jsonify.register(db.ceph_versions) def jsonify_ceph_versions(value): return dict(version=value.version, count=value.count) @jsonify.register(db.sysinfo) def jsonify_sysinfo(value): retval = {} if value.os: retval['os_info'] = value.os if value.kern_vers: retval['kernel_versions'] = value.kern_vers if value.kern_types: retval['kernel_types'] = value.kern_types if value.distros: retval['distros'] = value.distros if value.cpus: retval['cpus'] = value.cpus if value.cpu_archs: retval['cpu_archs'] = value.cpu_archs if value.ceph_vers: retval['ceph_versions'] = value.ceph_vers return retval @jsonify.register(db.brag) def jsonify_brag(b): ownership = {'organization':b.ci.organization, 'description':b.ci.description, 'email':b.ci.contact_email, 'name':b.ci.cluster_name } return dict(uuid=b.ci.uuid, cluster_creation_date=str(b.ci.cluster_creation_date), components_count=b.comps, crush_types=b.crush, ownership=ownership, pool_metadata=b.pools, sysinfo=b.sysinfo ) ceph-0.80.11/src/brag/server/ceph_brag/tests/0000775000175100017510000000000012623076744022761 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag/tests/test_units.py0000664000175100017510000000016112623076744025532 0ustar jenkins-buildjenkins-buildfrom unittest import TestCase class TestUnits(TestCase): def test_units(self): assert 5 * 5 == 25 ceph-0.80.11/src/brag/server/ceph_brag/tests/config.py0000664000175100017510000000237312623076744024605 0ustar jenkins-buildjenkins-build# Server Specific Configurations server = { 'port': '8080', 'host': '0.0.0.0' } # Pecan Application Configurations app = { 'root': 'ceph_brag.controllers.root.RootController', 'modules': ['ceph_brag'], 'static_root': '%(confdir)s/public', 'template_path': '%(confdir)s/ceph_brag/templates', 'debug': True, 'errors': { 404: '/error/404', '__force_dict__': True } } logging = { 'loggers': { 'root': {'level': 'INFO', 'handlers': ['console']}, 'ceph_brag': {'level': 'DEBUG', 'handlers': ['console']}, 'py.warnings': {'handlers': ['console']}, '__force_dict__': True }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'simple' } }, 'formatters': { 'simple': { 'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]' '[%(threadName)s] %(message)s') } } } sqlalchemy = { 'url' : 'sqlite:////tmp/test.db', 'echo' : False, 'encoding' : 'utf-8' } # Custom Configurations must be in Python dictionary format:: # # foo = {'bar':'baz'} # # All configurations are accessible at:: # pecan.conf ceph-0.80.11/src/brag/server/ceph_brag/tests/test_functional.py0000664000175100017510000000460312623076744026537 0ustar jenkins-buildjenkins-buildfrom unittest import TestCase from webtest import TestApp from ceph_brag.tests import FunctionalTest import json, sys from pecan import request class TestRootController(FunctionalTest): def test_1_get_invalid_url_format(self): response = self.app.get('/1/2/3', expect_errors=True) assert response.status_int == 400 def test_2_put(self): with open ("sample.json", "r") as myfile: data=myfile.read().replace('\n', '') response = self.app.request('/', method='PUT', body=data) assert response.status_int == 201 def test_3_put_invalid_json(self): response = self.app.request('/', method='PUT', body='{asdfg', expect_errors=True) assert response.status_int == 422 def test_4_put_invalid_entries_1(self): response = self.app.request('/', method='PUT', body='{}', expect_errors=True) assert response.status_int == 422 def test_5_put_incomplete_json(self): response = self.app.request('/', method='PUT', body='{\"uuid\":\"adfs-12312ad\"}', expect_errors=True) assert response.status_int == 422 def test_6_get(self): response = self.app.get('/') js = json.loads(response.body) for entry in js: ci = entry break response = self.app.get('/'+ci['uuid']+'/'+str(ci['num_versions'])) assert response.status_int == 200 def test_7_get_invalid_uuid(self): response = self.app.get('/xxxxxx', expect_errors=True) assert response.status_int == 400 def test_8_get_invalid_version(self): response = self.app.get('/') js = json.loads(response.body) for entry in js: ci = entry break response = self.app.get('/'+ci['uuid']+'/'+str(0), expect_errors=True) assert response.status_int == 400 def test_9_delete_invalid_parameters(self): response = self.app.delete('/', expect_errors=True) assert response.status_int == 400 def test_91_delete_wrong_uuid(self): response = self.app.delete('/?uuid=xxxx', expect_errors=True) assert response.status_int == 400 def test_92_delete(self): response = self.app.get('/') js = json.loads(response.body) for entry in js: response = self.app.delete('/?uuid='+entry['uuid']) assert response.status_int == 200 ceph-0.80.11/src/brag/server/ceph_brag/tests/__init__.py0000664000175100017510000000100612623076744025067 0ustar jenkins-buildjenkins-buildimport os from unittest import TestCase from pecan import set_config from pecan.testing import load_test_app __all__ = ['FunctionalTest'] class FunctionalTest(TestCase): """ Used for functional tests where you need to test your literal application and its integration with the framework. """ def setUp(self): self.app = load_test_app(os.path.join( os.path.dirname(__file__), 'config.py' )) def tearDown(self): set_config({}, overwrite=True) ceph-0.80.11/src/brag/server/ceph_brag/app.py0000664000175100017510000000102512623076744022747 0ustar jenkins-buildjenkins-buildfrom pecan import make_app from ceph_brag import model, json from pecan.hooks import TransactionHook def setup_app(config): model.init_model() app_conf = dict(config.app) return make_app( app_conf.pop('root'), logging=getattr(config, 'logging', {}), hooks=[TransactionHook(model.start, model.start, model.commit, model.rollback, model.clear)], **app_conf ) ceph-0.80.11/src/brag/server/ceph_brag/__init__.py0000664000175100017510000000000012623076744023716 0ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag/controllers/0000775000175100017510000000000012623076744024165 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag/controllers/root.py0000664000175100017510000000501512623076744025523 0ustar jenkins-buildjenkins-buildfrom pecan import expose, request, abort, response from webob import exc from pecan.rest import RestController from ceph_brag.model import db import sys, traceback class RootController(RestController): def fail(self, status_code=200, msg="OK"): response.status = status_code return msg @expose('json') def get(self, *args, **kwargs): if len(args) is 0: #return the list of uuids try: result = db.get_uuids() except Exception as e: return self.fail(500, msg="Internal Server Error") elif len(args) is 1 or len(args) is 2 and args[1] == '': #/uuid try: result = db.get_versions(args[0]) except Exception as e: return self.fail(status_code=500, msg="Internal Server Error") if result is None: return self.fail(400, msg="Invalid UUID") elif len(args) is 2 or len(args) is 3 and args[2] == '': #/uuid/version_number try: result = db.get_brag(args[0], args[1]) except Exception as e: return self.fail(status_code=500, msg="Internal Server Error") if result is None: return self.fail(status_code=400, msg="Invalid UUID,version combination") else: return self.fail(status_code=400, msg="Invalid args") return result @expose(content_type='application/json') def put(self, *args, **kwargs): try: db.put_new_version(request.body) except ValueError as ve: return self.fail(status_code=422, msg="Improper payload") except KeyError as ke: msg = "Payload not as expected, some keys are missing" return self.fail(status_code=422, msg=msg) except Exception as e: return self.fail(status_code=500, msg="Internal Server Error") response.status = 201 return "CREATED" @expose() def delete(self, *args, **kwargs): if 'uuid' not in kwargs: return self.fail(status_code=400, msg="Required uuid parameter") uuid = kwargs['uuid'] try: status = db.delete_uuid(uuid) except Exception as e: return self.fail(status_code=500, msg="Internal Server Error") if status is not None: return self.fail(status_code=status['status'], msg=status['msg']) response.status=200 return "DELETED" ceph-0.80.11/src/brag/server/ceph_brag/controllers/__init__.py0000664000175100017510000000000012623076744026264 0ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag/model/0000775000175100017510000000000012623076744022717 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag/model/db.py0000664000175100017510000002277612623076744023674 0ustar jenkins-buildjenkins-buildimport json from datetime import datetime from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy import Column, Integer, String, \ DateTime, ForeignKey, BigInteger from sqlalchemy import PrimaryKeyConstraint from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declared_attr Base = declarative_base() Session = scoped_session(sessionmaker()) class cluster_info(Base): __tablename__ = 'cluster_info' index = Column(Integer, primary_key=True) uuid = Column(String(36), unique=True) organization = Column(String(64)) contact_email = Column(String(32)) cluster_name = Column(String(32)) cluster_creation_date = Column(DateTime) description = Column(String(32)) num_versions = Column(Integer) class version_info(Base): __tablename__ = 'version_info' index = Column(Integer, primary_key=True) cluster_id = Column(ForeignKey('cluster_info.index')) version_number = Column(Integer) version_date = Column(DateTime) class components_info(Base): __tablename__ = 'components_info' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) num_data_bytes = Column(BigInteger) num_bytes_total = Column(BigInteger) num_osds = Column(Integer) num_objects = Column(Integer) num_pgs = Column(Integer) num_pools = Column(Integer) num_mdss = Column(Integer) num_mons = Column(Integer) class crush_types(Base): __tablename__ = 'crush_types' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) crush_type = Column(String(16)) crush_count = Column(Integer) class pools_info(Base): __tablename__ = 'pools_info' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) pool_id = Column(Integer) pool_type = Column(Integer) pool_rep_size = Column(Integer) class os_info(Base): __tablename__ = 'os_info' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) os = Column(String(16)) count = Column(Integer) class kernel_versions(Base): __tablename__ = 'kernel_versions' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) version = Column(String(16)) count = Column(Integer) class kernel_types(Base): __tablename__ = 'kernel_types' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) type = Column(String(64)) count = Column(Integer) class distros(Base): __tablename__ = 'distros' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) distro = Column(String(64)) count = Column(Integer) class cpus(Base): __tablename__ = 'cpus' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) cpu = Column(String(16)) count = Column(Integer) class cpu_archs(Base): __tablename__ = 'cpu_archs' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) arch = Column(String(16)) count = Column(Integer) class ceph_versions(Base): __tablename__ = 'ceph_versions' index = Column(Integer, primary_key=True) vid = Column(ForeignKey('version_info.index')) version = Column(String(16)) count = Column(Integer) class sysinfo(object): def __init__(self, vindex): self.os = Session.query(os_info).filter_by(vid=vindex).all() self.kern_vers = Session.query(kernel_versions).filter_by(vid=vindex).all() self.kern_types = Session.query(kernel_types).filter_by(vid=vindex).all() self.distros = Session.query(distros).filter_by(vid=vindex).all() self.cpus = Session.query(cpus).filter_by(vid=vindex).all() self.cpu_archs = Session.query(cpu_archs).filter_by(vid=vindex).all() self.ceph_vers = Session.query(ceph_versions).filter_by(vid=vindex).all() class brag(object): def __init__(self, uuid, version_number): self.ci = Session.query(cluster_info).filter_by(uuid=uuid).first() if self.ci is not None: self.vi = Session.query(version_info).filter_by(cluster_id=self.ci.index, version_number=version_number).first() if self.ci is not None and self.vi is not None: self.comps = Session.query(components_info).filter_by(vid=self.vi.index).first() self.crush = Session.query(crush_types).filter_by(vid=self.vi.index).all() self.pools = Session.query(pools_info).filter_by(vid=self.vi.index).all() self.sysinfo = sysinfo(self.vi.index) def put_new_version(data): info = json.loads(data) def add_cluster_info(): ci = Session.query(cluster_info).filter_by(uuid=info['uuid']).first() if ci is None: dt = datetime.strptime(info['cluster_creation_date'], "%Y-%m-%d %H:%M:%S.%f") ci = cluster_info(uuid=info['uuid'], organization=info['ownership']['organization'], contact_email=info['ownership']['email'], cluster_name=info['ownership']['name'], description=info['ownership']['description'], cluster_creation_date=dt, num_versions=1) Session.add(ci) Session.commit() else: ci.num_versions += 1 return ci def add_version_info(ci): vi = version_info(cluster_id=ci.index, version_number=ci.num_versions, version_date=datetime.now()) Session.add(vi) return vi def add_components_info(vi): comps_count= info['components_count'] comps_info = components_info(vid=vi.index, num_data_bytes=comps_count['num_data_bytes'], num_bytes_total=comps_count['num_bytes_total'], num_osds=comps_count['num_osds'], num_objects=comps_count['num_objects'], num_pgs=comps_count['num_pgs'], num_pools=comps_count['num_pools'], num_mdss=comps_count['num_mdss'], num_mons=comps_count['num_mons']) Session.add(comps_info) def add_crush_types(vi): for c in info['crush_types']: Session.add(crush_types(vid=vi.index, crush_type=c['type'], crush_count=c['count'])) def add_pools_info(vi): pools = info['pool_metadata'] for p in pools: Session.add(pools_info(vid=vi.index, pool_id=p['id'], pool_type=p['type'], pool_rep_size=p['size'])) def add_sys_info(vi): si = info['sysinfo'] while si: k,v = si.popitem() if k == 'os_info': for o in v: Session.add(os_info(vid=vi.index, os=o['os'], count=o['count'])) elif k == 'kernel_versions': for k in v: Session.add(kernel_versions(vid=vi.index, version=k['version'], count=k['count'])) elif k == 'kernel_types': for k in v: Session.add(kernel_types(vid=vi.index, type=k['type'], count=k['count'])) elif k == 'distros': for d in v: Session.add(distros(vid=vi.index, distro=d['distro'], count=d['count'])) elif k == 'cpus': for c in v: Session.add(cpus(vid=vi.index, cpu=c['cpu'], count=c['count'])) elif k == 'cpu_archs': for c in v: Session.add(cpu_archs(vid=vi.index, arch=c['arch'], count=c['count'])) elif k == 'ceph_versions': for c in v: Session.add(ceph_versions(vid=vi.index, version=c['version'], count=c['count'])) ci = add_cluster_info() add_version_info(ci) vi = Session.query(version_info).filter_by(cluster_id=ci.index, version_number=ci.num_versions).first() add_components_info(vi) add_crush_types(vi) add_pools_info(vi) add_sys_info(vi) def delete_uuid(uuid): ci = Session.query(cluster_info).filter_by(uuid=uuid).first() if ci is None: return {'status':400, 'msg':'No information for this UUID'} for v in Session.query(version_info).filter_by(cluster_id=ci.index).all(): Session.query(components_info).filter_by(vid=v.index).delete() Session.query(crush_types).filter_by(vid=v.index).delete() Session.query(pools_info).filter_by(vid=v.index).delete() Session.query(os_info).filter_by(vid=v.index).delete() Session.query(kernel_versions).filter_by(vid=v.index).delete() Session.query(kernel_types).filter_by(vid=v.index).delete() Session.query(distros).filter_by(vid=v.index).delete() Session.query(cpus).filter_by(vid=v.index).delete() Session.query(cpu_archs).filter_by(vid=v.index).delete() Session.query(ceph_versions).filter_by(vid=v.index).delete() Session.flush() Session.delete(v) Session.flush() Session.delete(ci) return None def get_uuids(): return Session.query(cluster_info).all() def get_versions(uuid): ci = Session.query(cluster_info).filter_by(uuid=uuid).first() if ci is None: return None return Session.query(version_info).filter_by(cluster_id=ci.index).all() def get_brag(uuid, version_id): b = brag(uuid, version_id) if b.ci is None or b.vi is None: return None return b ceph-0.80.11/src/brag/server/ceph_brag/model/__init__.py0000664000175100017510000000111712623076744025030 0ustar jenkins-buildjenkins-buildfrom sqlalchemy import create_engine from pecan import conf # noqa from db import Session, Base import sys def create_from_conf(): configs = dict(conf.sqlalchemy) url = configs.pop('url') return create_engine(url, **configs) def init_model(): engine = create_from_conf() conf.sqlalchemy.engine = engine engine.connect() #create the tables if not existing Base.metadata.create_all(engine) def start(): Session.bind = conf.sqlalchemy.engine def commit(): Session.commit() def rollback(): Session.rollback() def clear(): Session.remove() ceph-0.80.11/src/brag/server/ceph_brag.egg-info/0000775000175100017510000000000012623076744023311 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/brag/server/ceph_brag.egg-info/PKG-INFO0000664000175100017510000000026512623076744024411 0ustar jenkins-buildjenkins-buildMetadata-Version: 1.0 Name: ceph-brag Version: 0.1 Summary: UNKNOWN Home-page: UNKNOWN Author: UNKNOWN Author-email: UNKNOWN License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN ceph-0.80.11/src/brag/server/ceph_brag.egg-info/requires.txt0000664000175100017510000000000512623076744025704 0ustar jenkins-buildjenkins-buildpecanceph-0.80.11/src/brag/server/ceph_brag.egg-info/not-zip-safe0000664000175100017510000000000112623076744025537 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/brag/server/ceph_brag.egg-info/SOURCES.txt0000664000175100017510000000101612623076744025173 0ustar jenkins-buildjenkins-buildMANIFEST.in config.py setup.cfg setup.py ceph_brag/__init__.py ceph_brag/app.py ceph_brag/json.py ceph_brag.egg-info/PKG-INFO ceph_brag.egg-info/SOURCES.txt ceph_brag.egg-info/dependency_links.txt ceph_brag.egg-info/not-zip-safe ceph_brag.egg-info/requires.txt ceph_brag.egg-info/top_level.txt ceph_brag/controllers/__init__.py ceph_brag/controllers/root.py ceph_brag/model/__init__.py ceph_brag/model/db.py ceph_brag/tests/__init__.py ceph_brag/tests/config.py ceph_brag/tests/test_functional.py ceph_brag/tests/test_units.pyceph-0.80.11/src/brag/server/ceph_brag.egg-info/dependency_links.txt0000664000175100017510000000000112623076744027357 0ustar jenkins-buildjenkins-build ceph-0.80.11/src/brag/server/ceph_brag.egg-info/top_level.txt0000664000175100017510000000001212623076744026034 0ustar jenkins-buildjenkins-buildceph_brag ceph-0.80.11/src/brag/server/config.py0000664000175100017510000000223212623076744021523 0ustar jenkins-buildjenkins-build# Server Specific Configurations server = { 'port': '8080', 'host': '0.0.0.0' } # Pecan Application Configurations app = { 'root': 'ceph_brag.controllers.root.RootController', 'modules': ['ceph_brag'], 'debug': True, 'errors': { 404: '/error/404', '__force_dict__': True } } logging = { 'loggers': { 'root': {'level': 'INFO', 'handlers': ['console']}, 'ceph_brag': {'level': 'DEBUG', 'handlers': ['console']}, 'py.warnings': {'handlers': ['console']}, '__force_dict__': True }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'simple' } }, 'formatters': { 'simple': { 'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]' '[%(threadName)s] %(message)s') } } } sqlalchemy = { 'url' : 'sqlite:////tmp/test.db', 'echo' : False, 'encoding' : 'utf-8' } # Custom Configurations must be in Python dictionary format:: # # foo = {'bar':'baz'} # # All configurations are accessible at:: # pecan.conf ceph-0.80.11/src/brag/Makefile.am0000664000175100017510000000013312623076744020430 0ustar jenkins-buildjenkins-build bin_SCRIPTS += brag/client/ceph-brag EXTRA_DIST += brag/server brag/README.md brag/client ceph-0.80.11/src/client/0000775000175100017510000000000012623077036016735 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/client/Fh.h0000664000175100017510000000147312623076744017455 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLIENT_FH_H #define CEPH_CLIENT_FH_H #include "include/types.h" class Inode; class Cond; class ceph_lock_state_t; // file handle for any open file state struct Fh { Inode *inode; loff_t pos; int mds; // have to talk to mds we opened with (for now) int mode; // the mode i opened the file with int flags; bool pos_locked; // pos is currently in use list pos_waiters; // waiters for pos // readahead state loff_t last_pos; loff_t consec_read_bytes; int nr_consec_read; // file lock ceph_lock_state_t *fcntl_locks; ceph_lock_state_t *flock_locks; Fh() : inode(0), pos(0), mds(0), mode(0), flags(0), pos_locked(false), last_pos(0), consec_read_bytes(0), nr_consec_read(0), fcntl_locks(NULL), flock_locks(NULL) {} }; #endif ceph-0.80.11/src/client/Inode.cc0000664000175100017510000003163112623076744020313 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "MetaSession.h" #include "Inode.h" #include "Dentry.h" #include "Dir.h" #include "ClientSnapRealm.h" ostream& operator<<(ostream &out, Inode &in) { out << in.vino() << "(" << "ref=" << in._ref << " cap_refs=" << in.cap_refs << " open=" << in.open_by_mode << " mode=" << oct << in.mode << dec << " size=" << in.size << "/" << in.max_size << " mtime=" << in.mtime << " caps=" << ccap_string(in.caps_issued()); if (!in.caps.empty()) { out << "("; for (map::iterator p = in.caps.begin(); p != in.caps.end(); ++p) { if (p != in.caps.begin()) out << ','; out << p->first << '=' << ccap_string(p->second->issued); } out << ")"; } if (in.dirty_caps) out << " dirty_caps=" << ccap_string(in.dirty_caps); if (in.flushing_caps) out << " flushing_caps=" << ccap_string(in.flushing_caps); if (in.flags & I_COMPLETE) out << " COMPLETE"; if (in.is_file()) out << " " << in.oset; if (!in.dn_set.empty()) out << " parents=" << in.dn_set; if (in.is_dir() && in.has_dir_layout()) out << " has_dir_layout"; out << ' ' << &in << ")"; return out; } void Inode::make_long_path(filepath& p) { if (!dn_set.empty()) { assert((*dn_set.begin())->dir && (*dn_set.begin())->dir->parent_inode); (*dn_set.begin())->dir->parent_inode->make_long_path(p); p.push_dentry((*dn_set.begin())->name); } else if (snapdir_parent) { snapdir_parent->make_nosnap_relative_path(p); string empty; p.push_dentry(empty); } else p = filepath(ino); } /* * make a filepath suitable for an mds request: * - if we are non-snapped/live, the ino is sufficient, e.g. #1234 * - if we are snapped, make filepath relative to first non-snapped parent. */ void Inode::make_nosnap_relative_path(filepath& p) { if (snapid == CEPH_NOSNAP) { p = filepath(ino); } else if (snapdir_parent) { snapdir_parent->make_nosnap_relative_path(p); string empty; p.push_dentry(empty); } else if (!dn_set.empty()) { assert((*dn_set.begin())->dir && (*dn_set.begin())->dir->parent_inode); (*dn_set.begin())->dir->parent_inode->make_nosnap_relative_path(p); p.push_dentry((*dn_set.begin())->name); } else { p = filepath(ino); } } void Inode::get_open_ref(int mode) { open_by_mode[mode]++; } bool Inode::put_open_ref(int mode) { //cout << "open_by_mode[" << mode << "] " << open_by_mode[mode] << " -> " << (open_by_mode[mode]-1) << std::endl; if (--open_by_mode[mode] == 0) return true; return false; } void Inode::get_cap_ref(int cap) { int n = 0; while (cap) { if (cap & 1) { int c = 1 << n; cap_refs[c]++; //cout << "inode " << *this << " get " << cap_string(c) << " " << (cap_refs[c]-1) << " -> " << cap_refs[c] << std::endl; } cap >>= 1; n++; } } int Inode::put_cap_ref(int cap) { // if cap is always a single bit (which it seems to be) // all this logic is equivalent to: // if (--cap_refs[c]) return false; else return true; int last = 0; int n = 0; while (cap) { if (cap & 1) { int c = 1 << n; if (cap_refs[c] <= 0) { lderr(cct) << "put_cap_ref " << ccap_string(c) << " went negative on " << *this << dendl; assert(cap_refs[c] > 0); } if (--cap_refs[c] == 0) last |= c; //cout << "inode " << *this << " put " << cap_string(c) << " " << (cap_refs[c]+1) << " -> " << cap_refs[c] << std::endl; } cap >>= 1; n++; } return last; } bool Inode::is_any_caps() { return caps.size(); } bool Inode::cap_is_valid(Cap* cap) { /*cout << "cap_gen " << cap->session-> cap_gen << std::endl << "session gen " << cap->gen << std::endl << "cap expire " << cap->session->cap_ttl << std::endl << "cur time " << ceph_clock_now(cct) << std::endl;*/ if ((cap->session->cap_gen <= cap->gen) && (ceph_clock_now(cct) < cap->session->cap_ttl)) { return true; } return true; } int Inode::caps_issued(int *implemented) { int c = snap_caps; int i = 0; for (map::iterator it = caps.begin(); it != caps.end(); ++it) if (cap_is_valid(it->second)) { c |= it->second->issued; i |= it->second->implemented; } if (implemented) *implemented = i; return c; } void Inode::touch_cap(Cap *cap) { // move to back of LRU cap->session->caps.push_back(&cap->cap_item); } void Inode::try_touch_cap(int mds) { if (caps.count(mds)) touch_cap(caps[mds]); } bool Inode::caps_issued_mask(unsigned mask) { int c = snap_caps; if ((c & mask) == mask) return true; // prefer auth cap if (auth_cap && cap_is_valid(auth_cap) && (auth_cap->issued & mask) == mask) { touch_cap(auth_cap); return true; } // try any cap for (map::iterator it = caps.begin(); it != caps.end(); ++it) { if (cap_is_valid(it->second)) { if ((it->second->issued & mask) == mask) { touch_cap(it->second); return true; } c |= it->second->issued; } } if ((c & mask) == mask) { // bah.. touch them all for (map::iterator it = caps.begin(); it != caps.end(); ++it) touch_cap(it->second); return true; } return false; } int Inode::caps_used() { int w = 0; for (map::iterator p = cap_refs.begin(); p != cap_refs.end(); ++p) if (p->second) w |= p->first; return w; } int Inode::caps_file_wanted() { int want = 0; for (map::iterator p = open_by_mode.begin(); p != open_by_mode.end(); ++p) if (p->second) want |= ceph_caps_for_mode(p->first); return want; } int Inode::caps_wanted() { int want = caps_file_wanted() | caps_used(); if (want & CEPH_CAP_FILE_BUFFER) want |= CEPH_CAP_FILE_EXCL; return want; } int Inode::caps_dirty() { return dirty_caps | flushing_caps; } bool Inode::have_valid_size() { // RD+RDCACHE or WR+WRBUFFER => valid size if (caps_issued() & (CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL)) return true; return false; } // open Dir for an inode. if it's not open, allocated it (and pin dentry in memory). Dir *Inode::open_dir() { if (!dir) { dir = new Dir(this); lsubdout(cct, mds, 15) << "open_dir " << dir << " on " << this << dendl; assert(dn_set.size() < 2); // dirs can't be hard-linked if (!dn_set.empty()) (*dn_set.begin())->get(); // pin dentry get(); // pin inode } return dir; } bool Inode::check_mode(uid_t ruid, gid_t rgid, gid_t *sgids, int sgids_count, uint32_t rflags) { unsigned fmode = 0; if ((rflags & O_ACCMODE) == O_WRONLY) fmode = 2; else if ((rflags & O_ACCMODE) == O_RDWR) fmode = 6; else if ((rflags & O_ACCMODE) == O_RDONLY) fmode = 4; // if uid is owner, owner entry determines access if (uid == ruid) { fmode = fmode << 6; } else if (gid == rgid) { // if a gid or sgid matches the owning group, group entry determines access fmode = fmode << 3; } else { int i = 0; for (; i < sgids_count; ++i) { if (sgids[i] == gid) { fmode = fmode << 3; break; } } } return (mode & fmode) == fmode; } void Inode::dump(Formatter *f) const { f->dump_stream("ino") << ino; f->dump_stream("snapid") << snapid; if (rdev) f->dump_unsigned("rdev", rdev); f->dump_stream("ctime") << ctime; f->dump_stream("mode") << '0' << std::oct << mode << std::dec; f->dump_unsigned("uid", uid); f->dump_unsigned("gid", gid); f->dump_unsigned("nlink", nlink); f->dump_int("size", size); f->dump_int("max_size", max_size); f->dump_int("truncate_seq", truncate_seq); f->dump_int("truncate_size", truncate_size); f->dump_stream("mtime") << mtime; f->dump_stream("atime") << atime; f->dump_int("time_warp_seq", time_warp_seq); f->open_object_section("layout"); ::dump(layout, f); f->close_section(); if (is_dir()) { f->open_object_section("dir_layout"); ::dump(dir_layout, f); f->close_section(); /* FIXME when wip-mds-encoding is merged *** f->open_object_section("dir_stat"); dirstat.dump(f); f->close_section(); f->open_object_section("rstat"); rstat.dump(f); f->close_section(); */ } f->dump_unsigned("version", version); f->dump_unsigned("xattr_version", xattr_version); f->dump_unsigned("flags", flags); if (is_dir()) { if (!dir_contacts.empty()) { f->open_object_section("dir_contants"); for (set::iterator p = dir_contacts.begin(); p != dir_contacts.end(); ++p) f->dump_int("mds", *p); f->close_section(); } f->dump_int("dir_hashed", (int)dir_hashed); f->dump_int("dir_replicated", (int)dir_replicated); } f->open_array_section("caps"); for (map::const_iterator p = caps.begin(); p != caps.end(); ++p) { f->open_object_section("cap"); f->dump_int("mds", p->first); if (p->second == auth_cap) f->dump_int("auth", 1); p->second->dump(f); f->close_section(); } f->close_section(); if (auth_cap) f->dump_int("auth_cap", auth_cap->session->mds_num); f->dump_stream("dirty_caps") << ccap_string(dirty_caps); if (flushing_caps) { f->dump_stream("flushings_caps") << ccap_string(flushing_caps); f->dump_unsigned("flushing_cap_seq", flushing_cap_seq); f->open_object_section("flushing_cap_tid"); for (unsigned bit = 0; bit < CEPH_CAP_BITS; bit++) { if (flushing_caps & (1 << bit)) { string n(ccap_string(1 << bit)); f->dump_unsigned(n.c_str(), flushing_cap_tid[bit]); } } f->close_section(); } f->dump_int("shared_gen", shared_gen); f->dump_int("cache_gen", cache_gen); if (snap_caps) { f->dump_int("snap_caps", snap_caps); f->dump_int("snap_cap_refs", snap_cap_refs); } f->dump_stream("hold_caps_until") << hold_caps_until; f->dump_unsigned("last_flush_tid", last_flush_tid); if (snaprealm) { f->open_object_section("snaprealm"); snaprealm->dump(f); f->close_section(); } if (!cap_snaps.empty()) { for (map::const_iterator p = cap_snaps.begin(); p != cap_snaps.end(); ++p) { f->open_object_section("cap_snap"); f->dump_stream("follows") << p->first; p->second->dump(f); f->close_section(); } } // open if (!open_by_mode.empty()) { f->open_array_section("open_by_mode"); for (map::const_iterator p = open_by_mode.begin(); p != open_by_mode.end(); ++p) { f->open_object_section("ref"); f->dump_unsigned("mode", p->first); f->dump_unsigned("refs", p->second); f->close_section(); } f->close_section(); } if (!cap_refs.empty()) { f->open_array_section("cap_refs"); for (map::const_iterator p = cap_refs.begin(); p != cap_refs.end(); ++p) { f->open_object_section("cap_ref"); f->dump_stream("cap") << ccap_string(p->first); f->dump_int("refs", p->second); f->close_section(); } f->close_section(); } f->dump_unsigned("reported_size", reported_size); if (wanted_max_size != max_size) f->dump_unsigned("wanted_max_size", wanted_max_size); if (requested_max_size != max_size) f->dump_unsigned("requested_max_size", requested_max_size); f->dump_int("ref", _ref); f->dump_int("ll_ref", ll_ref); if (!dn_set.empty()) { f->open_array_section("parents"); for (set::const_iterator p = dn_set.begin(); p != dn_set.end(); ++p) { f->open_object_section("dentry"); f->dump_stream("dir_ino") << (*p)->dir->parent_inode->ino; f->dump_string("name", (*p)->name); f->close_section(); } f->close_section(); } } void Cap::dump(Formatter *f) const { f->dump_int("mds", session->mds_num); f->dump_stream("ino") << inode->ino; f->dump_unsigned("cap_id", cap_id); f->dump_stream("issued") << ccap_string(issued); if (implemented != issued) f->dump_stream("implemented") << ccap_string(implemented); f->dump_stream("wanted") << ccap_string(wanted); f->dump_unsigned("seq", seq); f->dump_unsigned("issue_seq", issue_seq); f->dump_unsigned("mseq", mseq); f->dump_unsigned("gen", gen); } void CapSnap::dump(Formatter *f) const { f->dump_stream("ino") << in->ino; f->dump_stream("issued") << ccap_string(issued); f->dump_stream("dirty") << ccap_string(dirty); f->dump_unsigned("size", size); f->dump_stream("ctime") << ctime; f->dump_stream("mtime") << mtime; f->dump_stream("atime") << atime; f->dump_int("time_warp_seq", time_warp_seq); f->dump_stream("mode") << '0' << std::oct << mode << std::dec; f->dump_unsigned("uid", uid); f->dump_unsigned("gid", gid); if (!xattrs.empty()) { f->open_object_section("xattr_lens"); for (map::const_iterator p = xattrs.begin(); p != xattrs.end(); ++p) f->dump_int(p->first.c_str(), p->second.length()); f->close_section(); } f->dump_unsigned("xattr_version", xattr_version); f->dump_int("writing", (int)writing); f->dump_int("dirty_data", (int)dirty_data); f->dump_unsigned("flush_tid", flush_tid); } ceph-0.80.11/src/client/ClientSnapRealm.h0000664000175100017510000000262212623076744022136 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLIENT_SNAPREALM_H #define CEPH_CLIENT_SNAPREALM_H #include "include/types.h" #include "common/snap_types.h" #include "include/xlist.h" class Inode; struct SnapRealm { inodeno_t ino; int nref; snapid_t created; snapid_t seq; inodeno_t parent; snapid_t parent_since; vector prior_parent_snaps; // snaps prior to parent_since vector my_snaps; SnapRealm *pparent; set pchildren; private: SnapContext cached_snap_context; // my_snaps + parent snaps + past_parent_snaps friend ostream& operator<<(ostream& out, const SnapRealm& r); public: xlist inodes_with_caps; SnapRealm(inodeno_t i) : ino(i), nref(0), created(0), seq(0), pparent(NULL) { } void build_snap_context(); void invalidate_cache() { cached_snap_context.clear(); } const SnapContext& get_snap_context() { if (cached_snap_context.seq == 0) build_snap_context(); return cached_snap_context; } void dump(Formatter *f) const; }; inline ostream& operator<<(ostream& out, const SnapRealm& r) { return out << "snaprealm(" << r.ino << " nref=" << r.nref << " c=" << r.created << " seq=" << r.seq << " parent=" << r.parent << " my_snaps=" << r.my_snaps << " cached_snapc=" << r.cached_snap_context << ")"; } #endif ceph-0.80.11/src/client/Trace.cc0000664000175100017510000000327712623076744020320 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Trace.h" #include "common/debug.h" #include #include #include "common/Mutex.h" #include "common/config.h" #include #include #include void Trace::start() { //cout << "start" << std::endl; delete fs; fs = new ifstream(); fs->open(filename); if (!fs->is_open()) { //generic_dout(0) << "** unable to open trace file " << filename << dendl; assert(0); } //generic_dout(2) << "opened traced file '" << filename << "'" << dendl; // read first line getline(*fs, line); //cout << "first line is " << line << std::endl; _line = 1; } const char *Trace::peek_string(char *buf, const char *prefix) { //if (prefix) cout << "prefix '" << prefix << "' line '" << line << "'" << std::endl; if (prefix && strstr(line.c_str(), "/prefix") == line.c_str()) { strcpy(buf, prefix); strcpy(buf + strlen(prefix), line.c_str() + strlen("/prefix")); } else { strcpy(buf, line.c_str()); } return buf; } const char *Trace::get_string(char *buf, const char *prefix) { peek_string(buf, prefix); //cout << "buf is " << buf << std::endl; // read next line (and detect eof early) _line++; getline(*fs, line); //cout << "next line is " << line << std::endl; return buf; } ceph-0.80.11/src/client/Dir.h0000664000175100017510000000061312623076744017631 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLIENT_DIR_H #define CEPH_CLIENT_DIR_H class Inode; class Dir { public: Inode *parent_inode; // my inode ceph::unordered_map dentries; map dentry_map; uint64_t release_count; uint64_t max_offset; Dir(Inode* in) : release_count(0), max_offset(2) { parent_inode = in; } bool is_empty() { return dentries.empty(); } }; #endif ceph-0.80.11/src/client/Trace.h0000664000175100017510000000247312623076744020157 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CLIENT_TRACE_H #define CEPH_CLIENT_TRACE_H #include #include #include #include using std::list; using std::string; using std::ifstream; /* this class is more like an iterator over a constant tokenlist (which is protected by a mutex, see Trace.cc) */ class Trace { int _line; const char *filename; ifstream *fs; string line; public: Trace(const char* f) : _line(0), filename(f), fs(0) {} ~Trace() { delete fs; } Trace(const Trace& other); const Trace& operator=(const Trace& other); int get_line() { return _line; } void start(); const char *peek_string(char *buf, const char *prefix); const char *get_string(char *buf, const char *prefix); __int64_t get_int() { char buf[20]; return atoll(get_string(buf, 0)); } bool end() { return !fs || fs->eof(); //return _cur == _end; } }; #endif ceph-0.80.11/src/client/MetaRequest.cc0000664000175100017510000000555612623076744021523 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "client/MetaRequest.h" #include "client/Dentry.h" #include "client/Inode.h" #include "messages/MClientReply.h" #include "common/Formatter.h" void MetaRequest::dump(Formatter *f) const { f->dump_unsigned("tid", tid); f->dump_string("op", ceph_mds_op_name(head.op)); f->dump_stream("path") << path; f->dump_stream("path2") << path2; if (_inode) f->dump_stream("ino") << _inode->ino; if (_old_inode) f->dump_stream("old_ino") << _old_inode->ino; if (_other_inode) f->dump_stream("other_ino") << _other_inode->ino; if (target) f->dump_stream("target_ino") << target->ino; if (_dentry) f->dump_string("dentry", _dentry->name); if (_old_dentry) f->dump_string("old_dentry", _old_dentry->name); f->dump_stream("hint_ino") << inodeno_t(head.ino); f->dump_stream("sent_stamp") << sent_stamp; f->dump_int("mds", mds); f->dump_int("resend_mds", resend_mds); f->dump_int("send_to_auth", send_to_auth); f->dump_unsigned("sent_on_mseq", sent_on_mseq); f->dump_int("retry_attempt", retry_attempt); f->dump_int("got_unsafe", got_unsafe); if (head.op == CEPH_MDS_OP_READDIR || head.op == CEPH_MDS_OP_LSSNAP) { f->dump_stream("readdir_frag") << readdir_frag; f->dump_string("readdir_start", readdir_start); f->dump_unsigned("readdir_offset", readdir_offset); } f->dump_unsigned("uid", head.caller_uid); f->dump_unsigned("gid", head.caller_gid); f->dump_unsigned("oldest_client_tid", head.oldest_client_tid); f->dump_unsigned("mdsmap_epoch", head.mdsmap_epoch); f->dump_unsigned("flags", head.flags); f->dump_unsigned("num_retry", head.num_retry); f->dump_unsigned("num_fwd", head.num_fwd); f->dump_unsigned("num_releases", head.num_releases); } MetaRequest::~MetaRequest() { assert(!_inode); assert(!_old_inode); assert(!_other_inode); if (_dentry) _dentry->put(); if (_old_dentry) _old_dentry->put(); if (reply) reply->put(); } void MetaRequest::set_inode(Inode *in) { assert(_inode == NULL); _inode = in; _inode->get(); } Inode *MetaRequest::inode() { return _inode; } void MetaRequest::set_old_inode(Inode *in) { assert(_old_inode == NULL); _old_inode = in; _old_inode->get(); } Inode *MetaRequest::old_inode() { return _old_inode; } void MetaRequest::set_other_inode(Inode *in) { assert(_other_inode == NULL); _other_inode = in; _other_inode->get(); } Inode *MetaRequest::other_inode() { return _other_inode; } void MetaRequest::set_dentry(Dentry *d) { assert(_dentry == NULL); _dentry = d; _dentry->get(); } Dentry *MetaRequest::dentry() { return _dentry; } void MetaRequest::set_old_dentry(Dentry *d) { assert(_old_dentry == NULL); _old_dentry = d; _old_dentry->get(); } Dentry *MetaRequest::old_dentry() { return _old_dentry; } ceph-0.80.11/src/client/MetaSession.h0000664000175100017510000000235512623076744021352 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLIENT_METASESSION_H #define CEPH_CLIENT_METASESSION_H #include "include/types.h" #include "include/utime.h" #include "msg/msg_types.h" #include "include/xlist.h" #include "messages/MClientCapRelease.h" struct Cap; class Inode; struct CapSnap; struct MetaRequest; class MClientCapRelease; struct MetaSession { int mds_num; ConnectionRef con; version_t seq; uint64_t cap_gen; utime_t cap_ttl, last_cap_renew_request; uint64_t cap_renew_seq; int num_caps; entity_inst_t inst; enum { STATE_NEW, STATE_OPENING, STATE_OPEN, STATE_CLOSING, STATE_CLOSED, STATE_STALE, } state; list waiting_for_open; xlist caps; xlist flushing_caps; xlist flushing_capsnaps; xlist requests; xlist unsafe_requests; Cap *s_cap_iterator; MClientCapRelease *release; MetaSession() : mds_num(-1), con(NULL), seq(0), cap_gen(0), cap_renew_seq(0), num_caps(0), state(STATE_NEW), s_cap_iterator(NULL), release(NULL) {} ~MetaSession(); const char *get_state_name() const; void dump(Formatter *f) const; }; #endif ceph-0.80.11/src/client/ObjecterWriteback.h0000664000175100017510000000272512623076744022512 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_OSDC_OBJECTERWRITEBACKHANDLER_H #define CEPH_OSDC_OBJECTERWRITEBACKHANDLER_H #include "osdc/Objecter.h" #include "osdc/WritebackHandler.h" class ObjecterWriteback : public WritebackHandler { public: ObjecterWriteback(Objecter *o) : m_objecter(o) {} virtual ~ObjecterWriteback() {} virtual void read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snapid, bufferlist *pbl, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) { m_objecter->read_trunc(oid, oloc, off, len, snapid, pbl, 0, trunc_size, trunc_seq, onfinish); } virtual bool may_copy_on_write(const object_t& oid, uint64_t read_off, uint64_t read_len, snapid_t snapid) { return false; } virtual ceph_tid_t write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, uint64_t trunc_size, __u32 trunc_seq, Context *oncommit) { return m_objecter->write_trunc(oid, oloc, off, len, snapc, bl, mtime, 0, trunc_size, trunc_seq, NULL, oncommit); } virtual ceph_tid_t lock(const object_t& oid, const object_locator_t& oloc, int op, int flags, Context *onack, Context *oncommit) { return m_objecter->lock(oid, oloc, op, flags, onack, oncommit); } private: Objecter *m_objecter; }; #endif ceph-0.80.11/src/client/MetaSession.cc0000664000175100017510000000176212623076744021511 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "MetaSession.h" #include "common/Formatter.h" const char *MetaSession::get_state_name() const { switch (state) { case STATE_NEW: return "new"; case STATE_OPENING: return "opening"; case STATE_OPEN: return "open"; case STATE_CLOSING: return "closing"; case STATE_CLOSED: return "closed"; case STATE_STALE: return "stale"; default: return "unknown"; } } void MetaSession::dump(Formatter *f) const { f->dump_int("mds", mds_num); f->dump_stream("addr") << inst.addr; f->dump_unsigned("seq", seq); f->dump_unsigned("cap_gen", cap_gen); f->dump_stream("cap_ttl") << cap_ttl; f->dump_stream("last_cap_renew_request") << last_cap_renew_request; f->dump_unsigned("cap_renew_seq", cap_renew_seq); f->dump_int("num_caps", num_caps); f->dump_string("state", get_state_name()); } MetaSession::~MetaSession() { if (release) release->put(); } ceph-0.80.11/src/client/test_ioctls.c0000664000175100017510000000715312623076744021450 0ustar jenkins-buildjenkins-build #include #include #include #include #include #include #include #include #include #include #include #include "ioctl.h" char new_file_name[PATH_MAX]; int main(int argc, char **argv) { char *fn; int fd, err; struct ceph_ioctl_layout l; struct ceph_ioctl_dataloc dl; if (argc < 3) { printf("usage: ceph_test_ioctls \n"); return 1; } fn = argv[1]; fd = open(fn, O_CREAT|O_RDWR, 0644); if (fd < 0) { perror("couldn't open file"); return 1; } /* get layout */ err = ioctl(fd, CEPH_IOC_GET_LAYOUT, (unsigned long)&l); if (err < 0) { perror("ioctl IOC_GET_LAYOUT error"); return 1; } printf("layout:\n stripe_unit %lld\n stripe_count %lld\n object_size %lld\n data_pool %lld\n", (long long)l.stripe_unit, (long long)l.stripe_count, (long long)l.object_size, (long long)l.data_pool); /* set layout */ l.stripe_unit = 1048576; l.stripe_count = 2; err = ioctl(fd, CEPH_IOC_SET_LAYOUT, (unsigned long)&l); if (err < 0) { perror("ioctl IOC_SET_LAYOUT error"); return 1; } printf("set layout, writing to file\n"); printf("file %s\n", fn); /* get layout again */ err = ioctl(fd, CEPH_IOC_GET_LAYOUT, (unsigned long)&l); if (err < 0) { perror("ioctl IOC_GET_LAYOUT error"); return 1; } printf("layout:\n stripe_unit %lld\n stripe_count %lld\n object_size %lld\n data_pool %lld\n", (long long)l.stripe_unit, (long long)l.stripe_count, (long long)l.object_size, (long long)l.data_pool); /* dataloc */ dl.file_offset = atoll(argv[2]); err = ioctl(fd, CEPH_IOC_GET_DATALOC, (unsigned long)&dl); if (err < 0) { perror("ioctl IOC_GET_DATALOC error"); return 1; } printf("dataloc:\n"); printf(" file_offset %lld (of object start)\n", (long long)dl.file_offset); printf(" object '%s'\n object_offset %lld\n object_size %lld object_no %lld\n", dl.object_name, (long long)dl.object_offset, (long long)dl.object_size, (long long)dl.object_no); printf(" block_offset %lld\n block_size %lld\n", (long long)dl.block_offset, (long long)dl.block_size); char buf[80]; getnameinfo((struct sockaddr *)&dl.osd_addr, sizeof(dl.osd_addr), buf, sizeof(buf), 0, 0, NI_NUMERICHOST); printf(" osd%lld %s\n", (long long)dl.osd, buf); if (argc < 4) return 0; /* set dir default layout */ printf("testing dir policy setting\n"); fd = open(argv[3], O_RDONLY); if (fd < 0) { perror("couldn't open dir"); return 1; } l.object_size = 1048576; l.stripe_count = 1; err = ioctl(fd, CEPH_IOC_SET_LAYOUT_POLICY, (unsigned long)&l); if (err < 0) { perror("ioctl IOC_SET_LAYOUT_POLICY error"); return 1; } printf("set layout, creating file\n"); snprintf(new_file_name, sizeof(new_file_name), "%s/testfile", argv[3]); fd = open(new_file_name, O_CREAT | O_RDWR, 0644); if (fd < 0) { perror("couldn't open file"); return 1; } err = ioctl(fd, CEPH_IOC_GET_LAYOUT, (unsigned long)&l); if (err < 0) { perror("ioctl IOC_GET_LAYOUT error"); return 1; } printf("layout:\n stripe_unit %lld\n stripe_count %lld\n object_size %lld\n data_pool %lld\n", (long long)l.stripe_unit, (long long)l.stripe_count, (long long)l.object_size, (long long)l.data_pool); return 0; } ceph-0.80.11/src/client/MetaRequest.h0000664000175100017510000001217212623076744021355 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLIENT_METAREQUEST_H #define CEPH_CLIENT_METAREQUEST_H #include "include/types.h" #include "msg/msg_types.h" #include "include/xlist.h" #include "include/filepath.h" #include "include/atomic.h" #include "mds/mdstypes.h" #include "common/Mutex.h" #include "messages/MClientRequest.h" class MClientReply; class Inode; class Dentry; struct MetaRequest { private: Inode *_inode; Inode *_old_inode, *_other_inode; Dentry *_dentry; //associated with path Dentry *_old_dentry; //associated with path2 public: uint64_t tid; ceph_mds_request_head head; filepath path, path2; bufferlist data; int inode_drop; //the inode caps this operation will drop int inode_unless; //unless we have these caps already int old_inode_drop, old_inode_unless; int dentry_drop, dentry_unless; int old_dentry_drop, old_dentry_unless; int other_inode_drop, other_inode_unless; vector cap_releases; int regetattr_mask; // getattr mask if i need to re-stat after a traceless reply utime_t sent_stamp; int mds; // who i am asking int resend_mds; // someone wants you to (re)send the request here bool send_to_auth; // must send to auth mds __u32 sent_on_mseq; // mseq at last submission of this request int num_fwd; // # of times i've been forwarded int retry_attempt; atomic_t ref; MClientReply *reply; // the reply bool kick; // readdir result frag_t readdir_frag; string readdir_start; // starting _after_ this name uint64_t readdir_offset; frag_t readdir_reply_frag; vector > readdir_result; bool readdir_end; int readdir_num; string readdir_last_name; //possible responses bool got_unsafe; xlist::item item; xlist::item unsafe_item; Mutex lock; //for get/set sync Cond *caller_cond; // who to take up Cond *dispatch_cond; // who to kick back Inode *target; MetaRequest(int op) : _inode(NULL), _old_inode(NULL), _other_inode(NULL), _dentry(NULL), _old_dentry(NULL), tid(0), inode_drop(0), inode_unless(0), old_inode_drop(0), old_inode_unless(0), dentry_drop(0), dentry_unless(0), old_dentry_drop(0), old_dentry_unless(0), other_inode_drop(0), other_inode_unless(0), regetattr_mask(0), mds(-1), resend_mds(-1), send_to_auth(false), sent_on_mseq(0), num_fwd(0), retry_attempt(0), ref(1), reply(0), kick(false), readdir_offset(0), readdir_end(false), readdir_num(0), got_unsafe(false), item(this), unsafe_item(this), lock("MetaRequest lock"), caller_cond(0), dispatch_cond(0), target(0) { memset(&head, 0, sizeof(ceph_mds_request_head)); head.op = op; } ~MetaRequest(); void set_inode(Inode *in); Inode *inode(); Inode *take_inode() { Inode *i = _inode; _inode = 0; return i; } void set_old_inode(Inode *in); Inode *old_inode(); Inode *take_old_inode() { Inode *i = _old_inode; _old_inode = NULL; return i; } void set_other_inode(Inode *in); Inode *other_inode(); Inode *take_other_inode() { Inode *i = _other_inode; _other_inode = 0; return i; } void set_dentry(Dentry *d); Dentry *dentry(); void set_old_dentry(Dentry *d); Dentry *old_dentry(); MetaRequest* get() { ref.inc(); return this; } /// psuedo-private put method; use Client::put_request() bool _put() { int v = ref.dec(); return v == 0; } // normal fields void set_tid(ceph_tid_t t) { tid = t; } void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; } void inc_num_fwd() { head.num_fwd = head.num_fwd + 1; } void set_retry_attempt(int a) { head.num_retry = a; } void set_filepath(const filepath& fp) { path = fp; } void set_filepath2(const filepath& fp) { path2 = fp; } void set_string2(const char *s) { path2.set_path(s, 0); } void set_caller_uid(unsigned u) { head.caller_uid = u; } void set_caller_gid(unsigned g) { head.caller_gid = g; } void set_data(const bufferlist &d) { data = d; } void set_dentry_wanted() { head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY; } int get_op() { return head.op; } ceph_tid_t get_tid() { return tid; } filepath& get_filepath() { return path; } filepath& get_filepath2() { return path2; } bool is_write() { return (head.op & CEPH_MDS_OP_WRITE) || (head.op == CEPH_MDS_OP_OPEN && !(head.args.open.flags & (O_CREAT|O_TRUNC))) || (head.op == CEPH_MDS_OP_CREATE && !(head.args.open.flags & (O_CREAT|O_TRUNC))); } bool can_forward() { if (is_write() || head.op == CEPH_MDS_OP_OPEN || // do not forward _any_ open request. head.op == CEPH_MDS_OP_CREATE) // do not forward _any_ open request. return false; return true; } bool auth_is_best() { if (is_write()) return true; if (head.op == CEPH_MDS_OP_OPEN || head.op == CEPH_MDS_OP_CREATE || head.op == CEPH_MDS_OP_READDIR) return true; return false; } void dump(Formatter *f) const; }; #endif ceph-0.80.11/src/client/SyntheticClient.h0000664000175100017510000001552212623076744022231 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SYNTHETICCLIENT_H #define CEPH_SYNTHETICCLIENT_H #include #include "Client.h" #include "include/Distribution.h" #include "Trace.h" #define SYNCLIENT_FIRST_POOL 0 #define SYNCLIENT_MODE_RANDOMWALK 1 #define SYNCLIENT_MODE_FULLWALK 2 #define SYNCLIENT_MODE_REPEATWALK 3 #define SYNCLIENT_MODE_MAKEDIRMESS 7 #define SYNCLIENT_MODE_MAKEDIRS 8 // dirs files depth #define SYNCLIENT_MODE_STATDIRS 9 // dirs files depth #define SYNCLIENT_MODE_READDIRS 10 // dirs files depth #define SYNCLIENT_MODE_MAKEFILES 11 // num count private #define SYNCLIENT_MODE_MAKEFILES2 12 // num count private #define SYNCLIENT_MODE_CREATESHARED 13 // num #define SYNCLIENT_MODE_OPENSHARED 14 // num count #define SYNCLIENT_MODE_RMFILE 19 #define SYNCLIENT_MODE_WRITEFILE 20 #define SYNCLIENT_MODE_READFILE 21 #define SYNCLIENT_MODE_WRITEBATCH 22 #define SYNCLIENT_MODE_WRSHARED 23 #define SYNCLIENT_MODE_READSHARED 24 #define SYNCLIENT_MODE_RDWRRANDOM 25 #define SYNCLIENT_MODE_RDWRRANDOM_EX 26 #define SYNCLIENT_MODE_LINKTEST 27 #define SYNCLIENT_MODE_OVERLOAD_OSD_0 28 // two args #define SYNCLIENT_MODE_DROPCACHE 29 #define SYNCLIENT_MODE_TRACE 30 #define SYNCLIENT_MODE_CREATEOBJECTS 35 #define SYNCLIENT_MODE_OBJECTRW 36 #define SYNCLIENT_MODE_OPENTEST 40 #define SYNCLIENT_MODE_OPTEST 41 #define SYNCLIENT_MODE_ONLY 50 #define SYNCLIENT_MODE_ONLYRANGE 51 #define SYNCLIENT_MODE_EXCLUDE 52 #define SYNCLIENT_MODE_EXCLUDERANGE 53 #define SYNCLIENT_MODE_UNTIL 55 #define SYNCLIENT_MODE_SLEEPUNTIL 56 #define SYNCLIENT_MODE_RANDOMSLEEP 61 #define SYNCLIENT_MODE_SLEEP 62 #define SYNCLIENT_MODE_DUMP 63 #define SYNCLIENT_MODE_LOOKUPHASH 70 #define SYNCLIENT_MODE_LOOKUPINO 71 #define SYNCLIENT_MODE_TRUNCATE 200 #define SYNCLIENT_MODE_FOO 100 #define SYNCLIENT_MODE_THRASHLINKS 101 #define SYNCLIENT_MODE_IMPORTFIND 300 #define SYNCLIENT_MODE_CHUNK 400 #define SYNCLIENT_MODE_MKSNAP 1000 #define SYNCLIENT_MODE_RMSNAP 1001 #define SYNCLIENT_MODE_MKSNAPFILE 1002 void parse_syn_options(vector& args); class SyntheticClient { Client *client; int whoami; pthread_t thread_id; Distribution op_dist; void init_op_dist(); int get_op(); filepath cwd; map contents; set subdirs; bool did_readdir; set open_files; void up(); void clear_dir() { contents.clear(); subdirs.clear(); did_readdir = false; } int get_random_fh() { int r = rand() % open_files.size(); set::iterator it = open_files.begin(); while (r--) ++it; return *it; } filepath n1; const char *get_random_subdir() { assert(!subdirs.empty()); int r = ((rand() % subdirs.size()) + (rand() % subdirs.size())) / 2; // non-uniform distn set::iterator it = subdirs.begin(); while (r--) ++it; n1 = cwd; n1.push_dentry( *it ); return n1.get_path().c_str(); } filepath n2; const char *get_random_sub() { assert(!contents.empty()); int r = ((rand() % contents.size()) + (rand() % contents.size())) / 2; // non-uniform distn if (cwd.depth() && cwd.last_dentry().length()) r += cwd.last_dentry().c_str()[0]; // slightly permuted r %= contents.size(); map::iterator it = contents.begin(); while (r--) ++it; n2 = cwd; n2.push_dentry( it->first ); return n2.get_path().c_str(); } filepath sub; char sub_s[50]; const char *make_sub(const char *base) { snprintf(sub_s, sizeof(sub_s), "%s.%d", base, rand() % 100); string f = sub_s; sub = cwd; sub.push_dentry(f); return sub.c_str(); } public: SyntheticClient(Client *client, int w = -1); int start_thread(); int join_thread(); int run(); bool run_me() { if (run_only >= 0) { if (run_only == client->get_nodeid()) return true; else return false; } return true; } void did_run_me() { run_only = -1; run_until = utime_t(); } // run() will do one of these things: list modes; list sargs; list iargs; utime_t run_start; utime_t run_until; client_t run_only; client_t exclude; string get_sarg(int seq); int get_iarg() { int i = iargs.front(); iargs.pop_front(); return i; } bool time_to_stop() { utime_t now = ceph_clock_now(client->cct); if (0) cout << "time_to_stop .. now " << now << " until " << run_until << " start " << run_start << std::endl; if (run_until.sec() && now > run_until) return true; else return false; } string compose_path(string& prefix, char *rest) { return prefix + rest; } int full_walk(string& fromdir); int random_walk(int n); int dump_placement(string& fn); int make_dirs(const char *basedir, int dirs, int files, int depth); int stat_dirs(const char *basedir, int dirs, int files, int depth); int read_dirs(const char *basedir, int dirs, int files, int depth); int make_files(int num, int count, int priv, bool more); int link_test(); int create_shared(int num); int open_shared(int num, int count); int rm_file(string& fn); int write_file(string& fn, int mb, loff_t chunk); int write_fd(int fd, int size, int wrsize); int write_batch(int nfile, int mb, int chunk); int read_file(const std::string& fn, int mb, int chunk, bool ignoreprint=false); int create_objects(int nobj, int osize, int inflight); int object_rw(int nobj, int osize, int wrpc, int overlap, double rskew, double wskew); int read_random(string& fn, int mb, int chunk); int read_random_ex(string& fn, int mb, int chunk); int overload_osd_0(int n, int sie, int wrsize); int check_first_primary(int fd); int clean_dir(string& basedir); int play_trace(Trace& t, string& prefix, bool metadata_only=false); void make_dir_mess(const char *basedir, int n); void foo(); int thrash_links(const char *basedir, int dirs, int files, int depth, int n); void import_find(const char *basedir, const char *find, bool writedata); int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name); int lookup_ino(inodeno_t ino); int chunk_file(string &filename); void mksnap(const char *base, const char *name); void rmsnap(const char *base, const char *name); void mksnapfile(const char *dir); }; #endif ceph-0.80.11/src/client/Makefile.am0000664000175100017510000000146012623076744020777 0ustar jenkins-buildjenkins-buildlibclient_la_SOURCES = \ client/Client.cc \ client/Inode.cc \ client/Dentry.cc \ client/MetaRequest.cc \ client/ClientSnapRealm.cc \ client/MetaSession.cc \ client/Trace.cc libclient_la_LIBADD = $(LIBOSDC) $(LIBEDIT_LIBS) noinst_LTLIBRARIES += libclient.la noinst_HEADERS += \ client/Client.h \ client/Dentry.h \ client/Dir.h \ client/Fh.h \ client/Inode.h \ client/MetaRequest.h \ client/MetaSession.h \ client/ClientSnapRealm.h \ client/SyntheticClient.h \ client/Trace.h \ client/ioctl.h \ client/ObjecterWriteback.h if WITH_FUSE libclient_fuse_la_SOURCES = client/fuse_ll.cc libclient_fuse_la_LIBADD = libclient.la -lfuse noinst_LTLIBRARIES += libclient_fuse.la noinst_HEADERS += client/fuse_ll.h endif ceph_test_ioctls_SOURCES = client/test_ioctls.c bin_DEBUGPROGRAMS += ceph_test_ioctls ceph-0.80.11/src/client/ioctl.h0000664000175100017510000000266412623076744020235 0ustar jenkins-buildjenkins-build#ifndef FS_CEPH_IOCTL_H #define FS_CEPH_IOCTL_H #include "include/int_types.h" #if defined(__linux__) #include #include #elif defined(__FreeBSD__) #include #include #endif #define CEPH_IOCTL_MAGIC 0x97 /* just use u64 to align sanely on all archs */ struct ceph_ioctl_layout { __u64 stripe_unit, stripe_count, object_size; __u64 data_pool; __s64 unused; }; #define CEPH_IOC_GET_LAYOUT _IOR(CEPH_IOCTL_MAGIC, 1, \ struct ceph_ioctl_layout) #define CEPH_IOC_SET_LAYOUT _IOW(CEPH_IOCTL_MAGIC, 2, \ struct ceph_ioctl_layout) #define CEPH_IOC_SET_LAYOUT_POLICY _IOW(CEPH_IOCTL_MAGIC, 5, \ struct ceph_ioctl_layout) /* * Extract identity, address of the OSD and object storing a given * file offset. */ struct ceph_ioctl_dataloc { __u64 file_offset; /* in+out: file offset */ __u64 object_offset; /* out: offset in object */ __u64 object_no; /* out: object # */ __u64 object_size; /* out: object size */ char object_name[64]; /* out: object name */ __u64 block_offset; /* out: offset in block */ __u64 block_size; /* out: block length */ __s64 osd; /* out: osd # */ struct sockaddr_storage osd_addr; /* out: osd address */ }; #define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3, \ struct ceph_ioctl_dataloc) #define CEPH_IOC_LAZYIO _IO(CEPH_IOCTL_MAGIC, 4) #endif ceph-0.80.11/src/client/Client.cc0000664000175100017510000075766112623076744020515 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ // unix-ey fs stuff #include #include #include #include #include #include #include #if defined(__linux__) #include #endif #include #include using namespace std; #include "common/config.h" // ceph stuff #include "messages/MMonMap.h" #include "messages/MClientSession.h" #include "messages/MClientReconnect.h" #include "messages/MClientRequest.h" #include "messages/MClientRequestForward.h" #include "messages/MClientReply.h" #include "messages/MClientCaps.h" #include "messages/MClientCapRelease.h" #include "messages/MClientLease.h" #include "messages/MClientSnap.h" #include "messages/MGenericMessage.h" #include "messages/MMDSMap.h" #include "mon/MonClient.h" #include "mds/flock.h" #include "osd/OSDMap.h" #include "mon/MonMap.h" #include "osdc/Filer.h" #include "osdc/WritebackHandler.h" #include "common/Cond.h" #include "common/Mutex.h" #include "common/perf_counters.h" #include "common/admin_socket.h" #include "common/errno.h" #define dout_subsys ceph_subsys_client #include "include/lru.h" #include "include/compat.h" #include "Client.h" #include "Inode.h" #include "Dentry.h" #include "Dir.h" #include "ClientSnapRealm.h" #include "Fh.h" #include "MetaSession.h" #include "MetaRequest.h" #include "ObjecterWriteback.h" #include "include/assert.h" #include "include/stat.h" #undef dout_prefix #define dout_prefix *_dout << "client." << whoami << " " #define tout(cct) if (!cct->_conf->client_trace.empty()) traceout void client_flush_set_callback(void *p, ObjectCacher::ObjectSet *oset) { Client *client = static_cast(p); client->flush_set_callback(oset); } // ------------- Client::CommandHook::CommandHook(Client *client) : m_client(client) { } bool Client::CommandHook::call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out) { Formatter *f = new_formatter(format); if (!f) f = new_formatter("json-pretty"); f->open_object_section("result"); m_client->client_lock.Lock(); if (command == "mds_requests") m_client->dump_mds_requests(f); else if (command == "mds_sessions") m_client->dump_mds_sessions(f); else if (command == "dump_cache") m_client->dump_cache(f); else if (command == "kick_stale_sessions") m_client->_kick_stale_sessions(); else assert(0 == "bad command registered"); m_client->client_lock.Unlock(); f->close_section(); f->flush(out); delete f; return true; } // ------------- dir_result_t::dir_result_t(Inode *in) : inode(in), offset(0), this_offset(2), next_offset(2), release_count(0), start_shared_gen(0), buffer(0) { inode->get(); } // cons/des Client::Client(Messenger *m, MonClient *mc) : Dispatcher(m->cct), cct(m->cct), logger(NULL), m_command_hook(this), timer(m->cct, client_lock), switch_interrupt_cb(NULL), ino_invalidate_cb(NULL), ino_invalidate_cb_handle(NULL), dentry_invalidate_cb(NULL), dentry_invalidate_cb_handle(NULL), getgroups_cb(NULL), getgroups_cb_handle(NULL), async_ino_invalidator(m->cct), async_dentry_invalidator(m->cct), interrupt_finisher(m->cct), tick_event(NULL), monclient(mc), messenger(m), whoami(m->get_myname().num()), initialized(false), mounted(false), unmounting(false), local_osd(-1), local_osd_epoch(0), unsafe_sync_write(0), client_lock("Client::client_lock") { monclient->set_messenger(m); last_tid = 0; last_flush_seq = 0; cwd = NULL; // root = 0; num_flushing_caps = 0; lru.lru_set_max(cct->_conf->client_cache_size); lru.lru_set_midpoint(cct->_conf->client_cache_mid); // file handles free_fd_set.insert(10, 1<<30); // set up messengers messenger = m; // osd interfaces osdmap = new OSDMap; // initially blank.. see mount() mdsmap = new MDSMap; objecter = new Objecter(cct, messenger, monclient, osdmap, client_lock, timer, 0, 0); objecter->set_client_incarnation(0); // client always 0, for now. writeback_handler = new ObjecterWriteback(objecter); objectcacher = new ObjectCacher(cct, "libcephfs", *writeback_handler, client_lock, client_flush_set_callback, // all commit callback (void*)this, cct->_conf->client_oc_size, cct->_conf->client_oc_max_objects, cct->_conf->client_oc_max_dirty, cct->_conf->client_oc_target_dirty, cct->_conf->client_oc_max_dirty_age, true); filer = new Filer(objecter); } Client::~Client() { assert(!client_lock.is_locked()); tear_down_cache(); delete objectcacher; delete writeback_handler; delete filer; delete objecter; delete osdmap; delete mdsmap; delete logger; } void Client::tear_down_cache() { // fd's for (ceph::unordered_map::iterator it = fd_map.begin(); it != fd_map.end(); ++it) { Fh *fh = it->second; ldout(cct, 1) << "tear_down_cache forcing close of fh " << it->first << " ino " << fh->inode->ino << dendl; put_inode(fh->inode); delete fh; } fd_map.clear(); // caps! // *** FIXME *** // empty lru lru.lru_set_max(0); trim_cache(); assert(lru.lru_get_size() == 0); // close root ino assert(inode_map.size() <= 1); if (root && inode_map.size() == 1) { delete root; root = 0; inode_map.clear(); } assert(inode_map.empty()); } inodeno_t Client::get_root_ino() { return root->ino; } Inode *Client::get_root() { root->ll_get(); return root; } // debug crapola void Client::dump_inode(Formatter *f, Inode *in, set& did, bool disconnected) { filepath path; in->make_long_path(path); ldout(cct, 1) << "dump_inode: " << (disconnected ? "DISCONNECTED ":"") << "inode " << in->ino << " " << path << " ref " << in->get_num_ref() << *in << dendl; if (f) { f->open_object_section("inode"); f->dump_stream("path") << path; if (disconnected) f->dump_int("disconnected", 1); in->dump(f); f->close_section(); } did.insert(in); if (in->dir) { ldout(cct, 1) << " dir " << in->dir << " size " << in->dir->dentries.size() << dendl; for (ceph::unordered_map::iterator it = in->dir->dentries.begin(); it != in->dir->dentries.end(); ++it) { ldout(cct, 1) << " " << in->ino << " dn " << it->first << " " << it->second << " ref " << it->second->ref << dendl; if (f) { f->open_object_section("dentry"); it->second->dump(f); f->close_section(); } if (it->second->inode) dump_inode(f, it->second->inode, did, false); } } } void Client::dump_cache(Formatter *f) { set did; ldout(cct, 1) << "dump_cache" << dendl; if (f) f->open_array_section("cache"); if (root) dump_inode(f, root, did, true); // make a second pass to catch anything disconnected for (ceph::unordered_map::iterator it = inode_map.begin(); it != inode_map.end(); ++it) { if (did.count(it->second)) continue; dump_inode(f, it->second, did, true); } if (f) f->close_section(); } int Client::init() { client_lock.Lock(); assert(!initialized); timer.init(); objectcacher->start(); // ok! messenger->add_dispatcher_head(this); int r = monclient->init(); if (r < 0) { // need to do cleanup because we're in an intermediate init state timer.shutdown(); client_lock.Unlock(); objectcacher->stop(); monclient->shutdown(); return r; } client_lock.Unlock(); objecter->init_unlocked(); client_lock.Lock(); objecter->init_locked(); monclient->set_want_keys(CEPH_ENTITY_TYPE_MDS | CEPH_ENTITY_TYPE_OSD); monclient->sub_want("mdsmap", 0, 0); monclient->sub_want("osdmap", 0, CEPH_SUBSCRIBE_ONETIME); monclient->renew_subs(); // logger PerfCountersBuilder plb(cct, "client", l_c_first, l_c_last); plb.add_time_avg(l_c_reply, "reply"); plb.add_time_avg(l_c_lat, "lat"); plb.add_time_avg(l_c_wrlat, "wrlat"); plb.add_time_avg(l_c_owrlat, "owrlat"); plb.add_time_avg(l_c_ordlat, "ordlat"); logger = plb.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); client_lock.Unlock(); AdminSocket* admin_socket = cct->get_admin_socket(); int ret = admin_socket->register_command("mds_requests", "mds_requests", &m_command_hook, "show in-progress mds requests"); if (ret < 0) { lderr(cct) << "error registering admin socket command: " << cpp_strerror(-ret) << dendl; } ret = admin_socket->register_command("mds_sessions", "mds_sessions", &m_command_hook, "show mds session state"); if (ret < 0) { lderr(cct) << "error registering admin socket command: " << cpp_strerror(-ret) << dendl; } ret = admin_socket->register_command("dump_cache", "dump_cache", &m_command_hook, "show in-memory metadata cache contents"); if (ret < 0) { lderr(cct) << "error registering admin socket command: " << cpp_strerror(-ret) << dendl; } ret = admin_socket->register_command("kick_stale_sessions", "kick_stale_sessions", &m_command_hook, "kick sessions that were remote reset"); if (ret < 0) { lderr(cct) << "error registering admin socket command: " << cpp_strerror(-ret) << dendl; } client_lock.Lock(); initialized = true; client_lock.Unlock(); return r; } void Client::shutdown() { ldout(cct, 1) << "shutdown" << dendl; AdminSocket* admin_socket = cct->get_admin_socket(); admin_socket->unregister_command("mds_requests"); admin_socket->unregister_command("mds_sessions"); admin_socket->unregister_command("dump_cache"); admin_socket->unregister_command("kick_stale_sessions"); if (ino_invalidate_cb) { ldout(cct, 10) << "shutdown stopping cache invalidator finisher" << dendl; async_ino_invalidator.wait_for_empty(); async_ino_invalidator.stop(); } if (dentry_invalidate_cb) { ldout(cct, 10) << "shutdown stopping dentry invalidator finisher" << dendl; async_dentry_invalidator.wait_for_empty(); async_dentry_invalidator.stop(); } if (switch_interrupt_cb) { ldout(cct, 10) << "shutdown stopping interrupt finisher" << dendl; interrupt_finisher.wait_for_empty(); interrupt_finisher.stop(); } objectcacher->stop(); // outside of client_lock! this does a join. client_lock.Lock(); assert(initialized); initialized = false; timer.shutdown(); objecter->shutdown_locked(); client_lock.Unlock(); objecter->shutdown_unlocked(); monclient->shutdown(); if (logger) { cct->get_perfcounters_collection()->remove(logger); delete logger; logger = NULL; } } // =================== // metadata cache stuff void Client::trim_cache() { ldout(cct, 20) << "trim_cache size " << lru.lru_get_size() << " max " << lru.lru_get_max() << dendl; unsigned last = 0; while (lru.lru_get_size() != last) { last = lru.lru_get_size(); if (lru.lru_get_size() <= lru.lru_get_max()) break; // trim! Dentry *dn = static_cast(lru.lru_expire()); if (!dn) break; // done trim_dentry(dn); } // hose root? if (lru.lru_get_size() == 0 && root && root->get_num_ref() == 0 && inode_map.size() == 1) { ldout(cct, 15) << "trim_cache trimmed root " << root << dendl; delete root; root = 0; inode_map.clear(); } } void Client::trim_dentry(Dentry *dn) { ldout(cct, 15) << "trim_dentry unlinking dn " << dn->name << " in dir " << hex << dn->dir->parent_inode->ino << dendl; if (dn->dir->parent_inode->flags & I_COMPLETE) { ldout(cct, 10) << " clearing I_COMPLETE on " << *dn->dir->parent_inode << dendl; dn->dir->parent_inode->flags &= ~I_COMPLETE; dn->dir->release_count++; } unlink(dn, false); } void Client::update_inode_file_bits(Inode *in, uint64_t truncate_seq, uint64_t truncate_size, uint64_t size, uint64_t time_warp_seq, utime_t ctime, utime_t mtime, utime_t atime, version_t inline_version, bufferlist& inline_data, int issued) { bool warn = false; ldout(cct, 10) << "update_inode_file_bits " << *in << " " << ccap_string(issued) << " mtime " << mtime << dendl; ldout(cct, 25) << "truncate_seq: mds " << truncate_seq << " local " << in->truncate_seq << " time_warp_seq: mds " << time_warp_seq << " local " << in->time_warp_seq << dendl; uint64_t prior_size = in->size; if (inline_version > in->inline_version) { in->inline_data = inline_data; in->inline_version = inline_version; } if (truncate_seq > in->truncate_seq || (truncate_seq == in->truncate_seq && size > in->size)) { ldout(cct, 10) << "size " << in->size << " -> " << size << dendl; in->size = size; in->reported_size = size; if (truncate_seq != in->truncate_seq) { ldout(cct, 10) << "truncate_seq " << in->truncate_seq << " -> " << truncate_seq << dendl; in->truncate_seq = truncate_seq; in->oset.truncate_seq = truncate_seq; // truncate cached file data if (prior_size > size) { _invalidate_inode_cache(in, truncate_size, prior_size - truncate_size); } } // truncate inline data if (in->inline_version < CEPH_INLINE_NONE) { uint32_t len = in->inline_data.length(); if (size < len) in->inline_data.splice(size, len - size); } } if (truncate_seq >= in->truncate_seq && in->truncate_size != truncate_size) { if (in->is_file()) { ldout(cct, 10) << "truncate_size " << in->truncate_size << " -> " << truncate_size << dendl; in->truncate_size = truncate_size; in->oset.truncate_size = truncate_size; } else { ldout(cct, 0) << "Hmmm, truncate_seq && truncate_size changed on non-file inode!" << dendl; } } // be careful with size, mtime, atime if (issued & (CEPH_CAP_FILE_EXCL| CEPH_CAP_FILE_WR| CEPH_CAP_FILE_BUFFER| CEPH_CAP_AUTH_EXCL| CEPH_CAP_XATTR_EXCL)) { ldout(cct, 30) << "Yay have enough caps to look at our times" << dendl; if (ctime > in->ctime) in->ctime = ctime; if (time_warp_seq > in->time_warp_seq) { ldout(cct, 10) << "mds time_warp_seq " << time_warp_seq << " on inode " << *in << " is higher than local time_warp_seq " << in->time_warp_seq << dendl; //the mds updated times, so take those! in->mtime = mtime; in->atime = atime; in->time_warp_seq = time_warp_seq; } else if (time_warp_seq == in->time_warp_seq) { //take max times if (mtime > in->mtime) in->mtime = mtime; if (atime > in->atime) in->atime = atime; } else if (issued & CEPH_CAP_FILE_EXCL) { //ignore mds values as we have a higher seq } else warn = true; } else { ldout(cct, 30) << "Don't have enough caps, just taking mds' time values" << dendl; if (time_warp_seq >= in->time_warp_seq) { in->ctime = ctime; in->mtime = mtime; in->atime = atime; in->time_warp_seq = time_warp_seq; } else warn = true; } if (warn) { ldout(cct, 0) << "WARNING: " << *in << " mds time_warp_seq " << time_warp_seq << " is lower than local time_warp_seq " << in->time_warp_seq << dendl; } } void Client::_fragmap_remove_non_leaves(Inode *in) { for (map::iterator p = in->fragmap.begin(); p != in->fragmap.end(); ) if (!in->dirfragtree.is_leaf(p->first)) in->fragmap.erase(p++); else ++p; } Inode * Client::add_update_inode(InodeStat *st, utime_t from, MetaSession *session) { Inode *in; bool was_new = false; if (inode_map.count(st->vino)) { in = inode_map[st->vino]; ldout(cct, 12) << "add_update_inode had " << *in << " caps " << ccap_string(st->cap.caps) << dendl; } else { in = new Inode(cct, st->vino, &st->layout); inode_map[st->vino] = in; if (!root) { root = in; cwd = root; cwd->get(); } // immutable bits in->ino = st->vino.ino; in->snapid = st->vino.snapid; in->mode = st->mode & S_IFMT; was_new = true; } in->rdev = st->rdev; if (in->is_symlink()) in->symlink = st->symlink; if (was_new) ldout(cct, 12) << "add_update_inode adding " << *in << " caps " << ccap_string(st->cap.caps) << dendl; if (!st->cap.caps) return in; // as with readdir returning indoes in different snaprealms (no caps!) // only update inode if mds info is strictly newer, or it is the same and projected (odd). bool updating_inode = false; int issued = 0; if (st->version == 0 || (in->version & ~1) < st->version) { updating_inode = true; int implemented = 0; issued = in->caps_issued(&implemented) | in->caps_dirty(); issued |= implemented; in->version = st->version; if ((issued & CEPH_CAP_AUTH_EXCL) == 0) { in->mode = st->mode; in->uid = st->uid; in->gid = st->gid; } if ((issued & CEPH_CAP_LINK_EXCL) == 0) { in->nlink = st->nlink; } if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && st->xattrbl.length() && st->xattr_version > in->xattr_version) { bufferlist::iterator p = st->xattrbl.begin(); ::decode(in->xattrs, p); in->xattr_version = st->xattr_version; } in->dirstat = st->dirstat; in->rstat = st->rstat; if (in->is_dir()) { in->dir_layout = st->dir_layout; ldout(cct, 20) << " dir hash is " << (int)in->dir_layout.dl_dir_hash << dendl; } in->layout = st->layout; update_inode_file_bits(in, st->truncate_seq, st->truncate_size, st->size, st->time_warp_seq, st->ctime, st->mtime, st->atime, st->inline_version, st->inline_data, issued); } else if (st->inline_version > in->inline_version) { in->inline_data = st->inline_data; in->inline_version = st->inline_version; } // move me if/when version reflects fragtree changes. if (in->dirfragtree != st->dirfragtree) { in->dirfragtree = st->dirfragtree; _fragmap_remove_non_leaves(in); } if (in->snapid == CEPH_NOSNAP) { add_update_cap(in, session, st->cap.cap_id, st->cap.caps, st->cap.seq, st->cap.mseq, inodeno_t(st->cap.realm), st->cap.flags); if (in->auth_cap && in->auth_cap->session == session) in->max_size = st->max_size; } else in->snap_caps |= st->cap.caps; // setting I_COMPLETE needs to happen after adding the cap if (updating_inode && in->is_dir() && (st->cap.caps & CEPH_CAP_FILE_SHARED) && (issued & CEPH_CAP_FILE_EXCL) == 0 && in->dirstat.nfiles == 0 && in->dirstat.nsubdirs == 0) { ldout(cct, 10) << " marking I_COMPLETE on empty dir " << *in << dendl; in->flags |= I_COMPLETE; if (in->dir) { ldout(cct, 10) << " dir is open on empty dir " << in->ino << " with " << in->dir->dentry_map.size() << " entries, tearing down" << dendl; while (!in->dir->dentry_map.empty()) unlink(in->dir->dentry_map.begin()->second, true); close_dir(in->dir); } } return in; } /* * insert_dentry_inode - insert + link a single dentry + inode into the metadata cache. */ Dentry *Client::insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease, Inode *in, utime_t from, MetaSession *session, bool set_offset, Dentry *old_dentry) { Dentry *dn = NULL; if (dir->dentries.count(dname)) dn = dir->dentries[dname]; ldout(cct, 12) << "insert_dentry_inode '" << dname << "' vino " << in->vino() << " in dir " << dir->parent_inode->vino() << " dn " << dn << dendl; if (dn && dn->inode) { if (dn->inode->vino() == in->vino()) { touch_dn(dn); ldout(cct, 12) << " had dentry " << dname << " with correct vino " << dn->inode->vino() << dendl; } else { ldout(cct, 12) << " had dentry " << dname << " with WRONG vino " << dn->inode->vino() << dendl; unlink(dn, true); dn = NULL; } } if (!dn || dn->inode == 0) { in->get(); if (old_dentry && old_dentry->dir) unlink(old_dentry, dir == old_dentry->dir); // keep dir open if its the same dir dn = link(dir, dname, in, dn); put_inode(in); if (set_offset) { ldout(cct, 15) << " setting dn offset to " << dir->max_offset << dendl; dn->offset = dir->max_offset++; } } update_dentry_lease(dn, dlease, from, session); return dn; } void Client::update_dentry_lease(Dentry *dn, LeaseStat *dlease, utime_t from, MetaSession *session) { utime_t dttl = from; dttl += (float)dlease->duration_ms / 1000.0; assert(dn && dn->inode); if (dlease->mask & CEPH_LOCK_DN) { if (dttl > dn->lease_ttl) { ldout(cct, 10) << "got dentry lease on " << dn->name << " dur " << dlease->duration_ms << "ms ttl " << dttl << dendl; dn->lease_ttl = dttl; dn->lease_mds = session->mds_num; dn->lease_seq = dlease->seq; dn->lease_gen = session->cap_gen; } } dn->cap_shared_gen = dn->dir->parent_inode->shared_gen; } /* * update MDS location cache for a single inode */ void Client::update_dir_dist(Inode *in, DirStat *dst) { // auth ldout(cct, 20) << "got dirfrag map for " << in->ino << " frag " << dst->frag << " to mds " << dst->auth << dendl; if (dst->auth >= 0) { in->fragmap[dst->frag] = dst->auth; } else { in->fragmap.erase(dst->frag); } if (!in->dirfragtree.is_leaf(dst->frag)) { in->dirfragtree.force_to_leaf(cct, dst->frag); _fragmap_remove_non_leaves(in); } // replicated in->dir_replicated = !dst->dist.empty(); // FIXME that's just one frag! // dist /* if (!st->dirfrag_dist.empty()) { // FIXME set dist = st->dirfrag_dist.begin()->second; if (dist.empty() && !in->dir_contacts.empty()) ldout(cct, 9) << "lost dist spec for " << in->ino << " " << dist << dendl; if (!dist.empty() && in->dir_contacts.empty()) ldout(cct, 9) << "got dist spec for " << in->ino << " " << dist << dendl; in->dir_contacts = dist; } */ } /* * insert results from readdir or lssnap into the metadata cache. */ void Client::insert_readdir_results(MetaRequest *request, MetaSession *session, Inode *diri) { MClientReply *reply = request->reply; ConnectionRef con = request->reply->get_connection(); uint64_t features = con->get_features(); assert(request->readdir_result.empty()); // the extra buffer list is only set for readdir and lssnap replies bufferlist::iterator p = reply->get_extra_bl().begin(); if (!p.end()) { // snapdir? if (request->head.op == CEPH_MDS_OP_LSSNAP) { assert(diri); diri = open_snapdir(diri); } // only open dir if we're actually adding stuff to it! Dir *dir = diri->open_dir(); assert(dir); // dirstat DirStat dst(p); __u32 numdn; __u8 complete, end; ::decode(numdn, p); ::decode(end, p); ::decode(complete, p); frag_t fg = request->readdir_frag; uint64_t readdir_offset = request->readdir_offset; string readdir_start = request->readdir_start; if (fg != dst.frag) { ldout(cct, 10) << "insert_trace got new frag " << fg << " -> " << dst.frag << dendl; fg = dst.frag; if (fg.is_leftmost()) readdir_offset = 2; else readdir_offset = 0; readdir_start.clear(); } ldout(cct, 10) << "insert_trace " << numdn << " readdir items, end=" << (int)end << ", offset " << readdir_offset << ", readdir_start " << readdir_start << dendl; request->readdir_reply_frag = fg; request->readdir_end = end; request->readdir_num = numdn; map::iterator pd = dir->dentry_map.upper_bound(readdir_start); string dname; LeaseStat dlease; for (unsigned i=0; identry_map.end() && pd->first < dname) { if (pd->first < dname && fg.contains(diri->hash_dentry_name(pd->first))) { // do not remove items in earlier frags ldout(cct, 15) << "insert_trace unlink '" << pd->first << "'" << dendl; Dentry *dn = pd->second; ++pd; unlink(dn, true); } else { ++pd; } } if (pd == dir->dentry_map.end()) ldout(cct, 15) << " pd is at end" << dendl; else ldout(cct, 15) << " pd is '" << pd->first << "' dn " << pd->second << dendl; Inode *in = add_update_inode(&ist, request->sent_stamp, session); Dentry *dn; if (pd != dir->dentry_map.end() && pd->first == dname) { Dentry *olddn = pd->second; if (pd->second->inode != in) { // replace incorrect dentry ++pd; // we are about to unlink this guy, move past it. unlink(olddn, true); dn = link(dir, dname, in, NULL); } else { // keep existing dn dn = olddn; touch_dn(dn); ++pd; // move past the dentry we just touched. } } else { // new dn dn = link(dir, dname, in, NULL); } update_dentry_lease(dn, &dlease, request->sent_stamp, session); dn->offset = dir_result_t::make_fpos(fg, i + readdir_offset); // add to cached result list in->get(); request->readdir_result.push_back(pair(dname, in)); ldout(cct, 15) << "insert_trace " << hex << dn->offset << dec << ": '" << dname << "' -> " << in->ino << dendl; } request->readdir_last_name = dname; // remove trailing names if (end) { while (pd != dir->dentry_map.end()) { if (fg.contains(diri->hash_dentry_name(pd->first))) { ldout(cct, 15) << "insert_trace unlink '" << pd->first << "'" << dendl; Dentry *dn = pd->second; ++pd; unlink(dn, true); } else ++pd; } } if (dir->is_empty()) close_dir(dir); } } /** insert_trace * * insert a trace from a MDS reply into the cache. */ Inode* Client::insert_trace(MetaRequest *request, MetaSession *session) { MClientReply *reply = request->reply; ldout(cct, 10) << "insert_trace from " << request->sent_stamp << " mds." << session->mds_num << " is_target=" << (int)reply->head.is_target << " is_dentry=" << (int)reply->head.is_dentry << dendl; bufferlist::iterator p = reply->get_trace_bl().begin(); if (p.end()) { ldout(cct, 10) << "insert_trace -- no trace" << dendl; Dentry *d = request->dentry(); if (d && d->dir && (d->dir->parent_inode->flags & I_COMPLETE)) { ldout(cct, 10) << " clearing I_COMPLETE on " << *d->dir->parent_inode << dendl; d->dir->parent_inode->flags &= ~I_COMPLETE; d->dir->release_count++; } return NULL; } ConnectionRef con = request->reply->get_connection(); uint64_t features = con->get_features(); ldout(cct, 10) << " features 0x" << hex << features << dec << dendl; // snap trace if (reply->snapbl.length()) update_snap_trace(reply->snapbl); ldout(cct, 10) << " hrm " << " is_target=" << (int)reply->head.is_target << " is_dentry=" << (int)reply->head.is_dentry << dendl; InodeStat dirst; DirStat dst; string dname; LeaseStat dlease; InodeStat ist; if (reply->head.is_dentry) { dirst.decode(p, features); dst.decode(p); ::decode(dname, p); ::decode(dlease, p); } Inode *in = 0; if (reply->head.is_target) { ist.decode(p, features); in = add_update_inode(&ist, request->sent_stamp, session); } if (reply->head.is_dentry) { Inode *diri = add_update_inode(&dirst, request->sent_stamp, session); update_dir_dist(diri, &dst); // dir stat info is attached to .. if (in) { Dir *dir = diri->open_dir(); insert_dentry_inode(dir, dname, &dlease, in, request->sent_stamp, session, true, ((request->head.op == CEPH_MDS_OP_RENAME) ? request->old_dentry() : NULL)); } else { if (diri->dir && diri->dir->dentries.count(dname)) { Dentry *dn = diri->dir->dentries[dname]; if (dn->inode) unlink(dn, false); } } } else if (reply->head.op == CEPH_MDS_OP_LOOKUPSNAP || reply->head.op == CEPH_MDS_OP_MKSNAP) { ldout(cct, 10) << " faking snap lookup weirdness" << dendl; // fake it for snap lookup vinodeno_t vino = ist.vino; vino.snapid = CEPH_SNAPDIR; assert(inode_map.count(vino)); Inode *diri = inode_map[vino]; string dname = request->path.last_dentry(); LeaseStat dlease; dlease.duration_ms = 0; if (in) { Dir *dir = diri->open_dir(); insert_dentry_inode(dir, dname, &dlease, in, request->sent_stamp, session, true); } else { if (diri->dir && diri->dir->dentries.count(dname)) { Dentry *dn = diri->dir->dentries[dname]; if (dn->inode) unlink(dn, false); } } } if (in && (reply->head.op == CEPH_MDS_OP_READDIR || reply->head.op == CEPH_MDS_OP_LSSNAP)) { insert_readdir_results(request, session, in); } request->target = in; return in; } // ------- int Client::choose_target_mds(MetaRequest *req) { int mds = -1; __u32 hash = 0; bool is_hash = false; Inode *in = NULL; Dentry *de = NULL; Cap *cap = NULL; if (req->resend_mds >= 0) { mds = req->resend_mds; req->resend_mds = -1; ldout(cct, 10) << "choose_target_mds resend_mds specified as mds." << mds << dendl; goto out; } if (cct->_conf->client_use_random_mds) goto random_mds; in = req->inode(); de = req->dentry(); if (in) { ldout(cct, 20) << "choose_target_mds starting with req->inode " << *in << dendl; if (req->path.depth()) { hash = in->hash_dentry_name(req->path[0]); ldout(cct, 20) << "choose_target_mds inode dir hash is " << (int)in->dir_layout.dl_dir_hash << " on " << req->path[0] << " => " << hash << dendl; is_hash = true; } } else if (de) { if (de->inode) { in = de->inode; ldout(cct, 20) << "choose_target_mds starting with req->dentry inode " << *in << dendl; } else { in = de->dir->parent_inode; hash = in->hash_dentry_name(de->name); ldout(cct, 20) << "choose_target_mds dentry dir hash is " << (int)in->dir_layout.dl_dir_hash << " on " << de->name << " => " << hash << dendl; is_hash = true; } } if (in && in->snapid != CEPH_NOSNAP) { ldout(cct, 10) << "choose_target_mds " << *in << " is snapped, using nonsnap parent" << dendl; while (in->snapid != CEPH_NOSNAP) { if (in->snapid == CEPH_SNAPDIR) in = in->snapdir_parent; else if (!in->dn_set.empty()) /* In most cases there will only be one dentry, so getting it * will be the correct action. If there are multiple hard links, * I think the MDS should be able to redirect as needed*/ in = in->get_first_parent()->dir->parent_inode; else { ldout(cct, 10) << "got unlinked inode, can't look at parent" << dendl; break; } } is_hash = false; } if (!in) goto random_mds; ldout(cct, 20) << "choose_target_mds " << *in << " is_hash=" << is_hash << " hash=" << hash << dendl; if (is_hash && S_ISDIR(in->mode) && !in->dirfragtree.empty()) { frag_t fg = in->dirfragtree[hash]; if (in->fragmap.count(fg)) { mds = in->fragmap[fg]; ldout(cct, 10) << "choose_target_mds from dirfragtree hash" << dendl; goto out; } } if (req->auth_is_best()) cap = in->auth_cap; if (!cap && !in->caps.empty()) cap = in->caps.begin()->second; if (!cap) goto random_mds; mds = cap->session->mds_num; ldout(cct, 10) << "choose_target_mds from caps on inode " << *in << dendl; goto out; random_mds: if (mds < 0) { mds = mdsmap->get_random_up_mds(); ldout(cct, 10) << "did not get mds through better means, so chose random mds " << mds << dendl; } out: ldout(cct, 20) << "mds is " << mds << dendl; return mds; } void Client::connect_mds_targets(int mds) { ldout(cct, 10) << "connect_mds_targets for mds." << mds << dendl; assert(mds_sessions.count(mds)); const MDSMap::mds_info_t& info = mdsmap->get_mds_info(mds); for (set::const_iterator q = info.export_targets.begin(); q != info.export_targets.end(); ++q) { if (mds_sessions.count(*q) == 0 && mdsmap->is_clientreplay_or_active_or_stopping(*q)) { ldout(cct, 10) << "check_mds_sessions opening mds." << mds << " export target mds." << *q << dendl; _open_mds_session(*q); } } } void Client::dump_mds_sessions(Formatter *f) { f->open_array_section("sessions"); for (map::const_iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { f->open_object_section("session"); p->second->dump(f); f->close_section(); } f->close_section(); f->dump_int("mdsmap_epoch", mdsmap->get_epoch()); } void Client::dump_mds_requests(Formatter *f) { for (map::iterator p = mds_requests.begin(); p != mds_requests.end(); ++p) { f->open_object_section("request"); p->second->dump(f); f->close_section(); } } int Client::verify_reply_trace(int r, MetaRequest *request, MClientReply *reply, Inode **ptarget, bool *pcreated, int uid, int gid) { // check whether this request actually did the create, and set created flag bufferlist extra_bl; inodeno_t created_ino; bool got_created_ino = false; ceph::unordered_map::iterator p; extra_bl.claim(reply->get_extra_bl()); if (extra_bl.length() >= 8) { // if the extra bufferlist has a buffer, we assume its the created inode // and that this request to create succeeded in actually creating // the inode (won the race with other create requests) ::decode(created_ino, extra_bl); got_created_ino = true; ldout(cct, 10) << "make_request created ino " << created_ino << dendl; } if (pcreated) *pcreated = got_created_ino; if (request->target) { *ptarget = request->target; ldout(cct, 20) << "make_request target is " << *request->target << dendl; } else { if (got_created_ino && (p = inode_map.find(vinodeno_t(created_ino, CEPH_NOSNAP))) != inode_map.end()) { (*ptarget) = p->second; ldout(cct, 20) << "make_request created, target is " << **ptarget << dendl; } else { // we got a traceless reply, and need to look up what we just // created. for now, do this by name. someday, do this by the // ino... which we know! FIXME. Inode *target = 0; // ptarget may be NULL Dentry *d = request->dentry(); if (d) { // rename is special: we handle old_dentry unlink explicitly in insert_dentry_inode(), so // we need to compensate and do the same here. Dentry *od = request->old_dentry(); if (od) { unlink(od, false); } ldout(cct, 10) << "make_request got traceless reply, looking up #" << d->dir->parent_inode->ino << "/" << d->name << " got_ino " << got_created_ino << " ino " << created_ino << dendl; r = _do_lookup(d->dir->parent_inode, d->name, &target); } else { Inode *in = request->inode(); ldout(cct, 10) << "make_request got traceless reply, forcing getattr on #" << in->ino << dendl; r = _getattr(in, request->regetattr_mask, uid, gid, true); target = in; } if (r >= 0) { if (ptarget) *ptarget = target; // verify ino returned in reply and trace_dist are the same if (got_created_ino && created_ino.val != target->ino.val) { ldout(cct, 5) << "create got ino " << created_ino << " but then failed on lookup; EINTR?" << dendl; r = -EINTR; } } } } return r; } /** * make a request * * Blocking helper to make an MDS request. * * If the ptarget flag is set, behavior changes slightly: the caller * expects to get a pointer to the inode we are creating or operating * on. As a result, we will follow up any traceless mutation reply * with a getattr or lookup to transparently handle a traceless reply * from the MDS (as when the MDS restarts and the client has to replay * a request). * * @param request the MetaRequest to execute * @param uid uid to execute as * @param gid gid to execute as * @param ptarget [optional] address to store a pointer to the target inode we want to create or operate on * @param pcreated [optional; required if ptarget] where to store a bool of whether our create atomically created a file * @param use_mds [optional] prefer a specific mds (-1 for default) * @param pdirbl [optional; disallowed if ptarget] where to pass extra reply payload to the caller */ int Client::make_request(MetaRequest *request, int uid, int gid, Inode **ptarget, bool *pcreated, int use_mds, bufferlist *pdirbl) { int r = 0; // assign a unique tid ceph_tid_t tid = ++last_tid; request->set_tid(tid); // make note mds_requests[tid] = request->get(); if (uid < 0) { uid = geteuid(); gid = getegid(); } request->set_caller_uid(uid); request->set_caller_gid(gid); if (!mds_requests.empty()) request->set_oldest_client_tid(mds_requests.begin()->first); else request->set_oldest_client_tid(tid); // this one is the oldest. // hack target mds? if (use_mds >= 0) request->resend_mds = use_mds; while (1) { // set up wait cond Cond caller_cond; request->caller_cond = &caller_cond; // choose mds int mds = choose_target_mds(request); if (mds < 0 || !mdsmap->is_active_or_stopping(mds)) { ldout(cct, 10) << " target mds." << mds << " not active, waiting for new mdsmap" << dendl; wait_on_list(waiting_for_mdsmap); continue; } // open a session? MetaSession *session = NULL; if (!have_open_session(mds)) { if (!mdsmap->is_active_or_stopping(mds)) { ldout(cct, 10) << "no address for mds." << mds << ", waiting for new mdsmap" << dendl; wait_on_list(waiting_for_mdsmap); if (!mdsmap->is_active_or_stopping(mds)) { ldout(cct, 10) << "hmm, still have no address for mds." << mds << ", trying a random mds" << dendl; request->resend_mds = mdsmap->get_random_up_mds(); continue; } } session = _get_or_open_mds_session(mds); // wait if (session->state == MetaSession::STATE_OPENING) { ldout(cct, 10) << "waiting for session to mds." << mds << " to open" << dendl; wait_on_context_list(session->waiting_for_open); continue; } if (!have_open_session(mds)) continue; } else { session = mds_sessions[mds]; } // send request. send_request(request, session); // wait for signal ldout(cct, 20) << "awaiting reply|forward|kick on " << &caller_cond << dendl; request->kick = false; while (!request->reply && // reply request->resend_mds < 0 && // forward !request->kick) caller_cond.Wait(client_lock); request->caller_cond = NULL; // did we get a reply? if (request->reply) break; } // got it! MClientReply *reply = request->reply; request->reply = NULL; r = reply->get_result(); // kick dispatcher (we've got it!) assert(request->dispatch_cond); request->dispatch_cond->Signal(); ldout(cct, 20) << "sendrecv kickback on tid " << tid << " " << request->dispatch_cond << dendl; request->dispatch_cond = 0; if (r >= 0 && ptarget) r = verify_reply_trace(r, request, reply, ptarget, pcreated, uid, gid); if (pdirbl) pdirbl->claim(reply->get_extra_bl()); // -- log times -- utime_t lat = ceph_clock_now(cct); lat -= request->sent_stamp; ldout(cct, 20) << "lat " << lat << dendl; logger->tinc(l_c_lat, lat); logger->tinc(l_c_reply, lat); put_request(request); reply->put(); return r; } void Client::put_request(MetaRequest *request) { if (request->_put()) { if (request->inode()) put_inode(request->take_inode()); if (request->old_inode()) put_inode(request->take_old_inode()); if (request->other_inode()) put_inode(request->take_other_inode()); delete request; } } int Client::encode_inode_release(Inode *in, MetaRequest *req, int mds, int drop, int unless, int force) { ldout(cct, 20) << "encode_inode_release enter(in:" << *in << ", req:" << req << " mds:" << mds << ", drop:" << drop << ", unless:" << unless << ", have:" << ", force:" << force << ")" << dendl; int released = 0; if (in->caps.count(mds)) { Cap *caps = in->caps[mds]; drop &= ~(in->dirty_caps | get_caps_used(in)); if ((drop & caps->issued) && !(unless & caps->issued)) { ldout(cct, 25) << "Dropping caps. Initial " << ccap_string(caps->issued) << dendl; caps->issued &= ~drop; caps->implemented &= ~drop; released = 1; force = 1; ldout(cct, 25) << "Now have: " << ccap_string(caps->issued) << dendl; } if (force) { ceph_mds_request_release rel; rel.ino = in->ino; rel.cap_id = caps->cap_id; rel.seq = caps->seq; rel.issue_seq = caps->issue_seq; rel.mseq = caps->mseq; rel.caps = caps->implemented; rel.wanted = caps->wanted; rel.dname_len = 0; rel.dname_seq = 0; req->cap_releases.push_back(MClientRequest::Release(rel,"")); } } ldout(cct, 25) << "encode_inode_release exit(in:" << *in << ") released:" << released << dendl; return released; } void Client::encode_dentry_release(Dentry *dn, MetaRequest *req, int mds, int drop, int unless) { ldout(cct, 20) << "encode_dentry_release enter(dn:" << dn << ")" << dendl; int released = 0; if (dn->dir) released = encode_inode_release(dn->dir->parent_inode, req, mds, drop, unless, 1); if (released && dn->lease_mds == mds) { ldout(cct, 25) << "preemptively releasing dn to mds" << dendl; MClientRequest::Release& rel = req->cap_releases.back(); rel.item.dname_len = dn->name.length(); rel.item.dname_seq = dn->lease_seq; rel.dname = dn->name; } ldout(cct, 25) << "encode_dentry_release exit(dn:" << dn << ")" << dendl; } /* * This requires the MClientRequest *request member to be set. * It will error out horribly without one. * Additionally, if you set any *drop member, you'd better have * set the corresponding dentry! */ void Client::encode_cap_releases(MetaRequest *req, int mds) { ldout(cct, 20) << "encode_cap_releases enter (req: " << req << ", mds: " << mds << ")" << dendl; if (req->inode_drop && req->inode()) encode_inode_release(req->inode(), req, mds, req->inode_drop, req->inode_unless); if (req->old_inode_drop && req->old_inode()) encode_inode_release(req->old_inode(), req, mds, req->old_inode_drop, req->old_inode_unless); if (req->other_inode_drop && req->other_inode()) encode_inode_release(req->other_inode(), req, mds, req->other_inode_drop, req->other_inode_unless); if (req->dentry_drop && req->dentry()) encode_dentry_release(req->dentry(), req, mds, req->dentry_drop, req->dentry_unless); if (req->old_dentry_drop && req->old_dentry()) encode_dentry_release(req->old_dentry(), req, mds, req->old_dentry_drop, req->old_dentry_unless); ldout(cct, 25) << "encode_cap_releases exit (req: " << req << ", mds " << mds <state == MetaSession::STATE_OPEN || mds_sessions[mds]->state == MetaSession::STATE_STALE); } MetaSession *Client::_get_mds_session(int mds, Connection *con) { if (mds_sessions.count(mds) == 0) return NULL; MetaSession *s = mds_sessions[mds]; if (s->con != con) return NULL; return s; } MetaSession *Client::_get_or_open_mds_session(int mds) { if (mds_sessions.count(mds)) return mds_sessions[mds]; return _open_mds_session(mds); } MetaSession *Client::_open_mds_session(int mds) { ldout(cct, 10) << "_open_mds_session mds." << mds << dendl; assert(mds_sessions.count(mds) == 0); MetaSession *session = new MetaSession; session->mds_num = mds; session->seq = 0; session->inst = mdsmap->get_inst(mds); session->con = messenger->get_connection(session->inst); session->state = MetaSession::STATE_OPENING; mds_sessions[mds] = session; messenger->send_message(new MClientSession(CEPH_SESSION_REQUEST_OPEN), session->con); return session; } void Client::_close_mds_session(MetaSession *s) { ldout(cct, 2) << "_close_mds_session mds." << s->mds_num << " seq " << s->seq << dendl; s->state = MetaSession::STATE_CLOSING; messenger->send_message(new MClientSession(CEPH_SESSION_REQUEST_CLOSE, s->seq), s->con); } void Client::_closed_mds_session(MetaSession *s) { s->state = MetaSession::STATE_CLOSED; messenger->mark_down(s->con); signal_context_list(s->waiting_for_open); mount_cond.Signal(); remove_session_caps(s); kick_requests_closed(s); mds_sessions.erase(s->mds_num); delete s; } void Client::handle_client_session(MClientSession *m) { int from = m->get_source().num(); ldout(cct, 10) << "handle_client_session " << *m << " from mds." << from << dendl; MetaSession *session = _get_mds_session(from, m->get_connection().get()); if (!session) { ldout(cct, 10) << " discarding session message from sessionless mds " << m->get_source_inst() << dendl; m->put(); return; } switch (m->get_op()) { case CEPH_SESSION_OPEN: renew_caps(session); session->state = MetaSession::STATE_OPEN; if (unmounting) mount_cond.Signal(); else connect_mds_targets(from); signal_context_list(session->waiting_for_open); break; case CEPH_SESSION_CLOSE: _closed_mds_session(session); break; case CEPH_SESSION_RENEWCAPS: if (session->cap_renew_seq == m->get_seq()) { session->cap_ttl = session->last_cap_renew_request + mdsmap->get_session_timeout(); wake_inode_waiters(session); } break; case CEPH_SESSION_STALE: renew_caps(session); break; case CEPH_SESSION_RECALL_STATE: trim_caps(session, m->get_max_caps()); break; case CEPH_SESSION_FLUSHMSG: messenger->send_message(new MClientSession(CEPH_SESSION_FLUSHMSG_ACK, m->get_seq()), session->con); break; default: assert(0); } m->put(); } void Client::_kick_stale_sessions() { ldout(cct, 1) << "kick_stale_sessions" << dendl; for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ) { MetaSession *s = p->second; ++p; if (s->state == MetaSession::STATE_STALE) _closed_mds_session(s); } } void Client::send_request(MetaRequest *request, MetaSession *session) { // make the request int mds = session->mds_num; ldout(cct, 10) << "send_request rebuilding request " << request->get_tid() << " for mds." << mds << dendl; MClientRequest *r = build_client_request(request); if (request->dentry()) { r->set_dentry_wanted(); } if (request->got_unsafe) { r->set_replayed_op(); } else { encode_cap_releases(request, mds); r->releases.swap(request->cap_releases); } r->set_mdsmap_epoch(mdsmap->get_epoch()); if (request->mds == -1) { request->sent_stamp = ceph_clock_now(cct); ldout(cct, 20) << "send_request set sent_stamp to " << request->sent_stamp << dendl; } request->mds = mds; Inode *in = request->inode(); if (in && in->caps.count(mds)) request->sent_on_mseq = in->caps[mds]->mseq; session->requests.push_back(&request->item); ldout(cct, 10) << "send_request " << *r << " to mds." << mds << dendl; messenger->send_message(r, session->con); } MClientRequest* Client::build_client_request(MetaRequest *request) { MClientRequest *req = new MClientRequest(request->get_op()); req->set_tid(request->tid); memcpy(&req->head, &request->head, sizeof(ceph_mds_request_head)); // if the filepath's haven't been set, set them! if (request->path.empty()) { Inode *in = request->inode(); Dentry *de = request->dentry(); if (in) in->make_nosnap_relative_path(request->path); else if (de) { if (de->inode) de->inode->make_nosnap_relative_path(request->path); else if (de->dir) { de->dir->parent_inode->make_nosnap_relative_path(request->path); request->path.push_dentry(de->name); } else ldout(cct, 1) << "Warning -- unable to construct a filepath!" << " No path, inode, or appropriately-endowed dentry given!" << dendl; } else ldout(cct, 1) << "Warning -- unable to construct a filepath!" << " No path, inode, or dentry given!" << dendl; } req->set_filepath(request->get_filepath()); req->set_filepath2(request->get_filepath2()); req->set_data(request->data); req->set_retry_attempt(request->retry_attempt); req->head.num_fwd = request->num_fwd; return req; } void Client::handle_client_request_forward(MClientRequestForward *fwd) { int mds = fwd->get_source().num(); MetaSession *session = _get_mds_session(mds, fwd->get_connection().get()); if (!session) { fwd->put(); return; } ceph_tid_t tid = fwd->get_tid(); if (mds_requests.count(tid) == 0) { ldout(cct, 10) << "handle_client_request_forward no pending request on tid " << tid << dendl; fwd->put(); return; } MetaRequest *request = mds_requests[tid]; assert(request); // reset retry counter request->retry_attempt = 0; // request not forwarded, or dest mds has no session. // resend. ldout(cct, 10) << "handle_client_request tid " << tid << " fwd " << fwd->get_num_fwd() << " to mds." << fwd->get_dest_mds() << ", resending to " << fwd->get_dest_mds() << dendl; request->mds = -1; request->num_fwd = fwd->get_num_fwd(); request->resend_mds = fwd->get_dest_mds(); request->caller_cond->Signal(); fwd->put(); } void Client::handle_client_reply(MClientReply *reply) { int mds_num = reply->get_source().num(); MetaSession *session = _get_mds_session(mds_num, reply->get_connection().get()); if (!session) { reply->put(); return; } ceph_tid_t tid = reply->get_tid(); bool is_safe = reply->is_safe(); if (mds_requests.count(tid) == 0) { lderr(cct) << "handle_client_reply no pending request on tid " << tid << " safe is:" << is_safe << dendl; reply->put(); return; } ldout(cct, 20) << "handle_client_reply got a reply. Safe:" << is_safe << " tid " << tid << dendl; MetaRequest *request = mds_requests[tid]; if (!request) { ldout(cct, 0) << "got an unknown reply (probably duplicate) on tid " << tid << " from mds " << mds_num << " safe: " << is_safe << dendl; reply->put(); return; } if (request->got_unsafe && !is_safe) { //duplicate response ldout(cct, 0) << "got a duplicate reply on tid " << tid << " from mds " << mds_num << " safe:" << is_safe << dendl; reply->put(); return; } if (-ESTALE == reply->get_result()) { // see if we can get to proper MDS ldout(cct, 20) << "got ESTALE on tid " << request->tid << " from mds." << request->mds << dendl; request->send_to_auth = true; request->resend_mds = choose_target_mds(request); Inode *in = request->inode(); if (request->resend_mds >= 0 && request->resend_mds == request->mds && (in == NULL || in->caps.count(request->resend_mds) == 0 || request->sent_on_mseq == in->caps[request->resend_mds]->mseq)) { // have to return ESTALE } else { request->caller_cond->Signal(); return; } ldout(cct, 20) << "have to return ESTALE" << dendl; } assert(request->reply == NULL); request->reply = reply; insert_trace(request, session); // Handle unsafe reply if (!is_safe) { request->got_unsafe = true; session->unsafe_requests.push_back(&request->unsafe_item); } // Only signal the caller once (on the first reply): // Either its an unsafe reply, or its a safe reply and no unsafe reply was sent. if (!is_safe || !request->got_unsafe) { Cond cond; request->dispatch_cond = &cond; // wake up waiter ldout(cct, 20) << "handle_client_reply signalling caller " << (void*)request->caller_cond << dendl; request->caller_cond->Signal(); // wake for kick back while (request->dispatch_cond) { ldout(cct, 20) << "handle_client_reply awaiting kickback on tid " << tid << " " << &cond << dendl; cond.Wait(client_lock); } } if (is_safe) { // the filesystem change is committed to disk // we're done, clean up if (request->got_unsafe) { request->unsafe_item.remove_myself(); } request->item.remove_myself(); mds_requests.erase(tid); put_request(request); } if (unmounting) mount_cond.Signal(); } // ------------------------ // incoming messages bool Client::ms_dispatch(Message *m) { Mutex::Locker l(client_lock); if (!initialized) { ldout(cct, 10) << "inactive, discarding " << *m << dendl; m->put(); return true; } switch (m->get_type()) { // osd case CEPH_MSG_OSD_OPREPLY: objecter->handle_osd_op_reply((MOSDOpReply*)m); break; case CEPH_MSG_OSD_MAP: objecter->handle_osd_map((class MOSDMap*)m); break; case CEPH_MSG_STATFS_REPLY: objecter->handle_fs_stats_reply((MStatfsReply*)m); break; // mounting and mds sessions case CEPH_MSG_MDS_MAP: handle_mds_map(static_cast(m)); break; case CEPH_MSG_CLIENT_SESSION: handle_client_session(static_cast(m)); break; // requests case CEPH_MSG_CLIENT_REQUEST_FORWARD: handle_client_request_forward(static_cast(m)); break; case CEPH_MSG_CLIENT_REPLY: handle_client_reply(static_cast(m)); break; case CEPH_MSG_CLIENT_SNAP: handle_snap(static_cast(m)); break; case CEPH_MSG_CLIENT_CAPS: handle_caps(static_cast(m)); break; case CEPH_MSG_CLIENT_LEASE: handle_lease(static_cast(m)); break; default: return false; } // unmounting? if (unmounting) { ldout(cct, 10) << "unmounting: trim pass, size was " << lru.lru_get_size() << "+" << inode_map.size() << dendl; long unsigned size = lru.lru_get_size() + inode_map.size(); trim_cache(); if (size < lru.lru_get_size() + inode_map.size()) { ldout(cct, 10) << "unmounting: trim pass, cache shrank, poking unmount()" << dendl; mount_cond.Signal(); } else { ldout(cct, 10) << "unmounting: trim pass, size still " << lru.lru_get_size() << "+" << inode_map.size() << dendl; } } return true; } void Client::handle_mds_map(MMDSMap* m) { if (m->get_epoch() < mdsmap->get_epoch()) { ldout(cct, 1) << "handle_mds_map epoch " << m->get_epoch() << " is older than our " << mdsmap->get_epoch() << dendl; m->put(); return; } ldout(cct, 1) << "handle_mds_map epoch " << m->get_epoch() << dendl; MDSMap *oldmap = mdsmap; mdsmap = new MDSMap; mdsmap->decode(m->get_encoded()); // reset session for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { int oldstate = oldmap->get_state(p->first); int newstate = mdsmap->get_state(p->first); if (!mdsmap->is_up(p->first) || mdsmap->get_inst(p->first) != p->second->inst) { messenger->mark_down(p->second->con); if (mdsmap->is_up(p->first)) p->second->inst = mdsmap->get_inst(p->first); } else if (oldstate == newstate) continue; // no change if (newstate == MDSMap::STATE_RECONNECT && mds_sessions.count(p->first)) { MetaSession *session = mds_sessions[p->first]; session->inst = mdsmap->get_inst(p->first); session->con = messenger->get_connection(session->inst); send_reconnect(session); } if (newstate >= MDSMap::STATE_ACTIVE) { if (oldstate < MDSMap::STATE_ACTIVE) { kick_requests(p->second); kick_flushing_caps(p->second); signal_context_list(p->second->waiting_for_open); kick_maxsize_requests(p->second); wake_inode_waiters(p->second); } connect_mds_targets(p->first); } } // kick any waiting threads signal_cond_list(waiting_for_mdsmap); delete oldmap; m->put(); monclient->sub_got("mdsmap", mdsmap->get_epoch()); } void Client::send_reconnect(MetaSession *session) { int mds = session->mds_num; ldout(cct, 10) << "send_reconnect to mds." << mds << dendl; MClientReconnect *m = new MClientReconnect; // i have an open session. ceph::unordered_set did_snaprealm; for (ceph::unordered_map::iterator p = inode_map.begin(); p != inode_map.end(); ++p) { Inode *in = p->second; if (in->caps.count(mds)) { ldout(cct, 10) << " caps on " << p->first << " " << ccap_string(in->caps[mds]->issued) << " wants " << ccap_string(in->caps_wanted()) << dendl; filepath path; in->make_long_path(path); ldout(cct, 10) << " path " << path << dendl; bufferlist flockbl; _encode_filelocks(in, flockbl); in->caps[mds]->seq = 0; // reset seq. in->caps[mds]->issue_seq = 0; // reset seq. in->caps[mds]->mseq = 0; // reset seq. m->add_cap(p->first.ino, in->caps[mds]->cap_id, path.get_ino(), path.get_path(), // ino in->caps_wanted(), // wanted in->caps[mds]->issued, // issued in->snaprealm->ino, flockbl); if (did_snaprealm.count(in->snaprealm->ino) == 0) { ldout(cct, 10) << " snaprealm " << *in->snaprealm << dendl; m->add_snaprealm(in->snaprealm->ino, in->snaprealm->seq, in->snaprealm->parent); did_snaprealm.insert(in->snaprealm->ino); } } } // reset my cap seq number session->seq = 0; //connect to the mds' offload targets connect_mds_targets(mds); //make sure unsafe requests get saved resend_unsafe_requests(session); messenger->send_message(m, session->con); mount_cond.Signal(); } void Client::kick_requests(MetaSession *session) { ldout(cct, 10) << "kick_requests for mds." << session->mds_num << dendl; for (map::iterator p = mds_requests.begin(); p != mds_requests.end(); ++p) { if (p->second->mds == session->mds_num) { send_request(p->second, session); } } } void Client::resend_unsafe_requests(MetaSession *session) { for (xlist::iterator iter = session->unsafe_requests.begin(); !iter.end(); ++iter) send_request(*iter, session); } void Client::kick_requests_closed(MetaSession *session) { ldout(cct, 10) << "kick_requests_closed for mds." << session->mds_num << dendl; for (map::iterator p = mds_requests.begin(); p != mds_requests.end(); ++p) { if (p->second->mds == session->mds_num) { if (p->second->caller_cond) { p->second->kick = true; p->second->caller_cond->Signal(); } p->second->item.remove_myself(); p->second->unsafe_item.remove_myself(); } } assert(session->requests.empty()); assert(session->unsafe_requests.empty()); } /************ * leases */ void Client::got_mds_push(MetaSession *s) { s->seq++; ldout(cct, 10) << " mds." << s->mds_num << " seq now " << s->seq << dendl; if (s->state == MetaSession::STATE_CLOSING) { messenger->send_message(new MClientSession(CEPH_SESSION_REQUEST_CLOSE, s->seq), s->con); } } void Client::handle_lease(MClientLease *m) { ldout(cct, 10) << "handle_lease " << *m << dendl; assert(m->get_action() == CEPH_MDS_LEASE_REVOKE); int mds = m->get_source().num(); MetaSession *session = _get_mds_session(mds, m->get_connection().get()); if (!session) { m->put(); return; } got_mds_push(session); ceph_seq_t seq = m->get_seq(); Inode *in; vinodeno_t vino(m->get_ino(), CEPH_NOSNAP); if (inode_map.count(vino) == 0) { ldout(cct, 10) << " don't have vino " << vino << dendl; goto revoke; } in = inode_map[vino]; if (m->get_mask() & CEPH_LOCK_DN) { if (!in->dir || in->dir->dentries.count(m->dname) == 0) { ldout(cct, 10) << " don't have dir|dentry " << m->get_ino() << "/" << m->dname <dir->dentries[m->dname]; ldout(cct, 10) << " revoked DN lease on " << dn << dendl; dn->lease_mds = -1; } revoke: messenger->send_message(new MClientLease(CEPH_MDS_LEASE_RELEASE, seq, m->get_mask(), m->get_ino(), m->get_first(), m->get_last(), m->dname), m->get_source_inst()); m->put(); } void Client::put_inode(Inode *in, int n) { ldout(cct, 10) << "put_inode on " << *in << dendl; int left = in->_put(n); if (left == 0) { // release any caps remove_all_caps(in); ldout(cct, 10) << "put_inode deleting " << *in << dendl; bool unclean = objectcacher->release_set(&in->oset); assert(!unclean); if (in->snapdir_parent) put_inode(in->snapdir_parent); inode_map.erase(in->vino()); in->cap_item.remove_myself(); in->snaprealm_item.remove_myself(); if (in == root) root = 0; delete in->fcntl_locks; delete in->flock_locks; delete in; } } void Client::close_dir(Dir *dir) { Inode *in = dir->parent_inode; ldout(cct, 15) << "close_dir dir " << dir << " on " << in << dendl; assert(dir->is_empty()); assert(in->dir == dir); assert(in->dn_set.size() < 2); // dirs can't be hard-linked if (!in->dn_set.empty()) in->get_first_parent()->put(); // unpin dentry delete in->dir; in->dir = 0; put_inode(in); // unpin inode } /** * Don't call this with in==NULL, use get_or_create for that * leave dn set to default NULL unless you're trying to add * a new inode to a pre-created Dentry */ Dentry* Client::link(Dir *dir, const string& name, Inode *in, Dentry *dn) { if (!dn) { // create a new Dentry dn = new Dentry; dn->name = name; // link to dir dn->dir = dir; dir->dentries[dn->name] = dn; dir->dentry_map[dn->name] = dn; lru.lru_insert_mid(dn); // mid or top? ldout(cct, 15) << "link dir " << dir->parent_inode << " '" << name << "' to inode " << in << " dn " << dn << " (new dn)" << dendl; } else { ldout(cct, 15) << "link dir " << dir->parent_inode << " '" << name << "' to inode " << in << " dn " << dn << " (old dn)" << dendl; } if (in) { // link to inode dn->inode = in; in->get(); if (in->is_dir()) { if (in->dir) dn->get(); // dir -> dn pin if (in->ll_ref) dn->get(); // ll_ref -> dn pin } assert(in->dn_set.count(dn) == 0); // only one parent for directories! if (in->is_dir() && !in->dn_set.empty()) { Dentry *olddn = in->get_first_parent(); assert(olddn->dir != dir || olddn->name != name); unlink(olddn, false); } in->dn_set.insert(dn); ldout(cct, 20) << "link inode " << in << " parents now " << in->dn_set << dendl; } return dn; } void Client::unlink(Dentry *dn, bool keepdir) { Inode *in = dn->inode; ldout(cct, 15) << "unlink dir " << dn->dir->parent_inode << " '" << dn->name << "' dn " << dn << " inode " << dn->inode << dendl; // unlink from inode if (in) { if (in->is_dir()) { if (in->dir) dn->put(); // dir -> dn pin if (in->ll_ref) dn->put(); // ll_ref -> dn pin } dn->inode = 0; assert(in->dn_set.count(dn)); in->dn_set.erase(dn); ldout(cct, 20) << "unlink inode " << in << " parents now " << in->dn_set << dendl; put_inode(in); } // unlink from dir dn->dir->dentries.erase(dn->name); dn->dir->dentry_map.erase(dn->name); if (dn->dir->is_empty() && !keepdir) close_dir(dn->dir); dn->dir = 0; // delete den lru.lru_remove(dn); dn->put(); } /**** * caps */ void Client::get_cap_ref(Inode *in, int cap) { if ((cap & CEPH_CAP_FILE_BUFFER) && in->cap_refs[CEPH_CAP_FILE_BUFFER] == 0) { ldout(cct, 5) << "get_cap_ref got first FILE_BUFFER ref on " << *in << dendl; in->get(); } if ((cap & CEPH_CAP_FILE_CACHE) && in->cap_refs[CEPH_CAP_FILE_CACHE] == 0) { ldout(cct, 5) << "get_cap_ref got first FILE_CACHE ref on " << *in << dendl; in->get(); } in->get_cap_ref(cap); } void Client::put_cap_ref(Inode *in, int cap) { int last = in->put_cap_ref(cap); if (last) { int put_nref = 0; int drop = last & ~in->caps_issued(); if (in->snapid == CEPH_NOSNAP) { if ((last & CEPH_CAP_FILE_WR) && !in->cap_snaps.empty() && in->cap_snaps.rbegin()->second->writing) { ldout(cct, 10) << "put_cap_ref finishing pending cap_snap on " << *in << dendl; in->cap_snaps.rbegin()->second->writing = 0; finish_cap_snap(in, in->cap_snaps.rbegin()->second, get_caps_used(in)); signal_cond_list(in->waitfor_caps); // wake up blocked sync writers } if (last & CEPH_CAP_FILE_BUFFER) { for (map::iterator p = in->cap_snaps.begin(); p != in->cap_snaps.end(); ++p) p->second->dirty_data = 0; signal_cond_list(in->waitfor_commit); ldout(cct, 5) << "put_cap_ref dropped last FILE_BUFFER ref on " << *in << dendl; ++put_nref; } } if (last & CEPH_CAP_FILE_CACHE) { ldout(cct, 5) << "put_cap_ref dropped last FILE_CACHE ref on " << *in << dendl; ++put_nref; // release clean pages too, if we dont want RDCACHE if (!(in->caps_wanted() & CEPH_CAP_FILE_CACHE)) drop |= CEPH_CAP_FILE_CACHE; } if (drop) { if (drop & CEPH_CAP_FILE_CACHE) _invalidate_inode_cache(in); else check_caps(in, false); } if (put_nref) put_inode(in, put_nref); } } int Client::get_caps(Inode *in, int need, int want, int *phave, loff_t endoff) { while (1) { if (endoff > 0 && (endoff >= (loff_t)in->max_size || endoff > (loff_t)(in->size << 1)) && endoff > (loff_t)in->wanted_max_size) { ldout(cct, 10) << "wanted_max_size " << in->wanted_max_size << " -> " << endoff << dendl; in->wanted_max_size = endoff; check_caps(in, false); } if (endoff >= 0 && endoff > (loff_t)in->max_size) { ldout(cct, 10) << "waiting on max_size, endoff " << endoff << " max_size " << in->max_size << " on " << *in << dendl; } else if (!in->cap_snaps.empty() && in->cap_snaps.rbegin()->second->writing) { ldout(cct, 10) << "waiting on cap_snap write to complete" << dendl; } else { int implemented; int have = in->caps_issued(&implemented); if ((have & need) == need) { int butnot = want & ~(have & need); int revoking = implemented & ~have; ldout(cct, 10) << "get_caps " << *in << " have " << ccap_string(have) << " need " << ccap_string(need) << " want " << ccap_string(want) << " but not " << ccap_string(butnot) << " revoking " << ccap_string(revoking) << dendl; if ((revoking & butnot) == 0) { *phave = need | (have & want); in->get_cap_ref(need); return 0; } } ldout(cct, 10) << "waiting for caps need " << ccap_string(need) << " want " << ccap_string(want) << dendl; } wait_on_list(in->waitfor_caps); } } int Client::get_caps_used(Inode *in) { unsigned used = in->caps_used(); if (!(used & CEPH_CAP_FILE_CACHE) && !objectcacher->set_is_empty(&in->oset)) used |= CEPH_CAP_FILE_CACHE; return used; } void Client::cap_delay_requeue(Inode *in) { ldout(cct, 10) << "cap_delay_requeue on " << *in << dendl; in->hold_caps_until = ceph_clock_now(cct); in->hold_caps_until += cct->_conf->client_caps_release_delay; delayed_caps.push_back(&in->cap_item); } void Client::send_cap(Inode *in, MetaSession *session, Cap *cap, int used, int want, int retain, int flush) { int held = cap->issued | cap->implemented; int revoking = cap->implemented & ~cap->issued; retain &= ~revoking; int dropping = cap->issued & ~retain; int op = CEPH_CAP_OP_UPDATE; ldout(cct, 10) << "send_cap " << *in << " mds." << session->mds_num << " seq " << cap->seq << " used " << ccap_string(used) << " want " << ccap_string(want) << " flush " << ccap_string(flush) << " retain " << ccap_string(retain) << " held "<< ccap_string(held) << " revoking " << ccap_string(revoking) << " dropping " << ccap_string(dropping) << dendl; cap->issued &= retain; cap->implemented &= cap->issued | used; uint64_t flush_tid = 0; snapid_t follows = 0; if (flush) { flush_tid = ++in->last_flush_tid; for (int i = 0; i < CEPH_CAP_BITS; ++i) { if (flush & (1<flushing_cap_tid[i] = flush_tid; } follows = in->snaprealm->get_snap_context().seq; } MClientCaps *m = new MClientCaps(op, in->ino, 0, cap->cap_id, cap->seq, cap->implemented, want, flush, cap->mseq); m->head.issue_seq = cap->issue_seq; m->set_tid(flush_tid); m->head.uid = in->uid; m->head.gid = in->gid; m->head.mode = in->mode; m->head.nlink = in->nlink; if (flush & CEPH_CAP_XATTR_EXCL) { ::encode(in->xattrs, m->xattrbl); m->head.xattr_version = in->xattr_version; } m->head.layout = in->layout; m->head.size = in->size; m->head.max_size = in->max_size; m->head.truncate_seq = in->truncate_seq; m->head.truncate_size = in->truncate_size; in->mtime.encode_timeval(&m->head.mtime); in->atime.encode_timeval(&m->head.atime); in->ctime.encode_timeval(&m->head.ctime); m->head.time_warp_seq = in->time_warp_seq; if (flush & CEPH_CAP_FILE_WR) { m->inline_version = in->inline_version; m->inline_data = in->inline_data; } in->reported_size = in->size; m->set_snap_follows(follows); cap->wanted = want; if (cap == in->auth_cap) { m->set_max_size(in->wanted_max_size); in->requested_max_size = in->wanted_max_size; ldout(cct, 15) << "auth cap, setting max_size = " << in->requested_max_size << dendl; } messenger->send_message(m, session->con); } void Client::check_caps(Inode *in, bool is_delayed) { unsigned wanted = in->caps_wanted(); unsigned used = get_caps_used(in); unsigned cap_used; int retain = wanted | used | CEPH_CAP_PIN; if (!unmounting) { if (wanted) retain |= CEPH_CAP_ANY; else retain |= CEPH_CAP_ANY_SHARED; } ldout(cct, 10) << "check_caps on " << *in << " wanted " << ccap_string(wanted) << " used " << ccap_string(used) << " is_delayed=" << is_delayed << dendl; if (in->snapid != CEPH_NOSNAP) return; //snap caps last forever, can't write if (in->caps.empty()) return; // guard if at end of func if (!in->cap_snaps.empty()) flush_snaps(in); if (!is_delayed) cap_delay_requeue(in); else in->hold_caps_until = utime_t(); utime_t now = ceph_clock_now(cct); map::iterator it = in->caps.begin(); while (it != in->caps.end()) { int mds = it->first; Cap *cap = it->second; ++it; MetaSession *session = mds_sessions[mds]; assert(session); cap_used = used; if (in->auth_cap && cap != in->auth_cap) cap_used &= ~in->auth_cap->issued; int revoking = cap->implemented & ~cap->issued; ldout(cct, 10) << " cap mds." << mds << " issued " << ccap_string(cap->issued) << " implemented " << ccap_string(cap->implemented) << " revoking " << ccap_string(revoking) << dendl; if (in->wanted_max_size > in->max_size && in->wanted_max_size > in->requested_max_size && cap == in->auth_cap) goto ack; /* approaching file_max? */ if ((cap->issued & CEPH_CAP_FILE_WR) && (in->size << 1) >= in->max_size && (in->reported_size << 1) < in->max_size && cap == in->auth_cap) { ldout(cct, 10) << "size " << in->size << " approaching max_size " << in->max_size << ", reported " << in->reported_size << dendl; goto ack; } /* completed revocation? */ if (revoking && (revoking & cap_used) == 0) { ldout(cct, 10) << "completed revocation of " << ccap_string(cap->implemented & ~cap->issued) << dendl; goto ack; } /* want more caps from mds? */ if (wanted & ~(cap->wanted | cap->issued)) goto ack; if (!revoking && unmounting && (cap_used == 0)) goto ack; if (wanted == cap->wanted && // mds knows what we want. ((cap->issued & ~retain) == 0) &&// and we don't have anything we wouldn't like !in->dirty_caps) // and we have no dirty caps continue; if (now < in->hold_caps_until) { ldout(cct, 10) << "delaying cap release" << dendl; continue; } ack: int flushing; if (in->auth_cap == cap && in->dirty_caps) flushing = mark_caps_flushing(in); else flushing = 0; send_cap(in, session, cap, cap_used, wanted, retain, flushing); } } struct C_SnapFlush : public Context { Client *client; Inode *in; snapid_t seq; C_SnapFlush(Client *c, Inode *i, snapid_t s) : client(c), in(i), seq(s) {} void finish(int r) { client->_flushed_cap_snap(in, seq); } }; void Client::queue_cap_snap(Inode *in, snapid_t seq) { int used = get_caps_used(in); int dirty = in->caps_dirty(); ldout(cct, 10) << "queue_cap_snap " << *in << " seq " << seq << " used " << ccap_string(used) << dendl; if (in->cap_snaps.size() && in->cap_snaps.rbegin()->second->writing) { ldout(cct, 10) << "queue_cap_snap already have pending cap_snap on " << *in << dendl; return; } else if (in->caps_dirty() || (used & CEPH_CAP_FILE_WR) || (dirty & CEPH_CAP_ANY_WR)) { in->get(); CapSnap *capsnap = new CapSnap(in); in->cap_snaps[seq] = capsnap; capsnap->context = in->snaprealm->get_snap_context(); capsnap->issued = in->caps_issued(); capsnap->dirty = in->caps_dirty(); // a bit conservative? capsnap->dirty_data = (used & CEPH_CAP_FILE_BUFFER); capsnap->uid = in->uid; capsnap->gid = in->gid; capsnap->mode = in->mode; capsnap->xattrs = in->xattrs; capsnap->xattr_version = in->xattr_version; if (used & CEPH_CAP_FILE_WR) { ldout(cct, 10) << "queue_cap_snap WR used on " << *in << dendl; capsnap->writing = 1; } else { finish_cap_snap(in, capsnap, used); } } else { ldout(cct, 10) << "queue_cap_snap not dirty|writing on " << *in << dendl; } } void Client::finish_cap_snap(Inode *in, CapSnap *capsnap, int used) { ldout(cct, 10) << "finish_cap_snap " << *in << " capsnap " << (void*)capsnap << " used " << ccap_string(used) << dendl; capsnap->size = in->size; capsnap->mtime = in->mtime; capsnap->atime = in->atime; capsnap->ctime = in->ctime; capsnap->time_warp_seq = in->time_warp_seq; if (used & CEPH_CAP_FILE_BUFFER) { ldout(cct, 10) << "finish_cap_snap " << *in << " cap_snap " << capsnap << " used " << used << " WRBUFFER, delaying" << dendl; } else { capsnap->dirty_data = 0; flush_snaps(in); } } void Client::_flushed_cap_snap(Inode *in, snapid_t seq) { ldout(cct, 10) << "_flushed_cap_snap seq " << seq << " on " << *in << dendl; assert(in->cap_snaps.count(seq)); in->cap_snaps[seq]->dirty_data = 0; flush_snaps(in); } void Client::flush_snaps(Inode *in, bool all_again, CapSnap *again) { ldout(cct, 10) << "flush_snaps on " << *in << " all_again " << all_again << " again " << again << dendl; assert(in->cap_snaps.size()); // pick auth mds assert(in->auth_cap); MetaSession *session = in->auth_cap->session; int mseq = in->auth_cap->mseq; for (map::iterator p = in->cap_snaps.begin(); p != in->cap_snaps.end(); ++p) { CapSnap *capsnap = p->second; if (again) { // only one capsnap if (again != capsnap) continue; } else if (!all_again) { // only flush once per session if (capsnap->flushing_item.is_on_list()) continue; } ldout(cct, 10) << "flush_snaps mds." << session->mds_num << " follows " << p->first << " size " << capsnap->size << " mtime " << capsnap->mtime << " dirty_data=" << capsnap->dirty_data << " writing=" << capsnap->writing << " on " << *in << dendl; if (capsnap->dirty_data || capsnap->writing) continue; in->auth_cap->session->flushing_capsnaps.push_back(&capsnap->flushing_item); capsnap->flush_tid = ++in->last_flush_tid; MClientCaps *m = new MClientCaps(CEPH_CAP_OP_FLUSHSNAP, in->ino, in->snaprealm->ino, 0, mseq); m->set_client_tid(capsnap->flush_tid); m->head.snap_follows = p->first; m->head.caps = capsnap->issued; m->head.dirty = capsnap->dirty; m->head.uid = capsnap->uid; m->head.gid = capsnap->gid; m->head.mode = capsnap->mode; m->head.size = capsnap->size; m->head.xattr_version = capsnap->xattr_version; ::encode(capsnap->xattrs, m->xattrbl); capsnap->ctime.encode_timeval(&m->head.ctime); capsnap->mtime.encode_timeval(&m->head.mtime); capsnap->atime.encode_timeval(&m->head.atime); m->head.time_warp_seq = capsnap->time_warp_seq; messenger->send_message(m, session->con); } } void Client::wait_on_list(list& ls) { Cond cond; ls.push_back(&cond); cond.Wait(client_lock); ls.remove(&cond); } void Client::signal_cond_list(list& ls) { for (list::iterator it = ls.begin(); it != ls.end(); ++it) (*it)->Signal(); } void Client::wait_on_context_list(list& ls) { Cond cond; bool done = false; int r; ls.push_back(new C_Cond(&cond, &done, &r)); while (!done) cond.Wait(client_lock); } void Client::signal_context_list(list& ls) { while (!ls.empty()) { ls.front()->complete(0); ls.pop_front(); } } void Client::wake_inode_waiters(MetaSession *s) { xlist::iterator iter = s->caps.begin(); while (!iter.end()){ signal_cond_list((*iter)->inode->waitfor_caps); ++iter; } } // flush dirty data (from objectcache) class C_Client_CacheInvalidate : public Context { private: Client *client; Inode *inode; int64_t offset, length; bool keep_caps; public: C_Client_CacheInvalidate(Client *c, Inode *in, int64_t off, int64_t len, bool keep) : client(c), inode(in), offset(off), length(len), keep_caps(keep) { inode->get(); } void finish(int r) { client->_async_invalidate(inode, offset, length, keep_caps); } }; void Client::_async_invalidate(Inode *in, int64_t off, int64_t len, bool keep_caps) { ldout(cct, 10) << "_async_invalidate " << off << "~" << len << (keep_caps ? " keep_caps" : "") << dendl; ino_invalidate_cb(ino_invalidate_cb_handle, in->vino(), off, len); client_lock.Lock(); if (!keep_caps) check_caps(in, false); put_inode(in); client_lock.Unlock(); ldout(cct, 10) << "_async_invalidate " << off << "~" << len << (keep_caps ? " keep_caps" : "") << " done" << dendl; } void Client::_schedule_invalidate_callback(Inode *in, int64_t off, int64_t len, bool keep_caps) { if (ino_invalidate_cb) // we queue the invalidate, which calls the callback and decrements the ref async_ino_invalidator.queue(new C_Client_CacheInvalidate(this, in, off, len, keep_caps)); else if (!keep_caps) check_caps(in, false); } void Client::_invalidate_inode_cache(Inode *in) { ldout(cct, 10) << "_invalidate_inode_cache " << *in << dendl; // invalidate our userspace inode cache if (cct->_conf->client_oc) objectcacher->release_set(&in->oset); _schedule_invalidate_callback(in, 0, 0, false); } void Client::_invalidate_inode_cache(Inode *in, int64_t off, int64_t len) { ldout(cct, 10) << "_invalidate_inode_cache " << *in << " " << off << "~" << len << dendl; // invalidate our userspace inode cache if (cct->_conf->client_oc) { vector ls; Striper::file_to_extents(cct, in->ino, &in->layout, off, len, in->truncate_size, ls); objectcacher->discard_set(&in->oset, ls); } _schedule_invalidate_callback(in, off, len, true); } void Client::_release(Inode *in) { ldout(cct, 20) << "_release " << *in << dendl; if (in->cap_refs[CEPH_CAP_FILE_CACHE] == 0) { _invalidate_inode_cache(in); } } class C_Client_PutInode : public Context { Client *client; Inode *in; public: C_Client_PutInode(Client *c, Inode *i) : client(c), in(i) { in->get(); } void finish(int) { client->put_inode(in); } }; bool Client::_flush(Inode *in, Context *onfinish) { ldout(cct, 10) << "_flush " << *in << dendl; if (!in->oset.dirty_or_tx) { ldout(cct, 10) << " nothing to flush" << dendl; if (onfinish) onfinish->complete(0); return true; } if (!onfinish) { onfinish = new C_Client_PutInode(this, in); } return objectcacher->flush_set(&in->oset, onfinish); } void Client::_flush_range(Inode *in, int64_t offset, uint64_t size) { assert(client_lock.is_locked()); if (!in->oset.dirty_or_tx) { ldout(cct, 10) << " nothing to flush" << dendl; return; } Mutex flock("Client::_flush_range flock"); Cond cond; bool safe = false; Context *onflush = new C_SafeCond(&flock, &cond, &safe); bool ret = objectcacher->file_flush(&in->oset, &in->layout, in->snaprealm->get_snap_context(), offset, size, onflush); if (!ret) { // wait for flush client_lock.Unlock(); flock.Lock(); while (!safe) cond.Wait(flock); flock.Unlock(); client_lock.Lock(); } } void Client::flush_set_callback(ObjectCacher::ObjectSet *oset) { // Mutex::Locker l(client_lock); assert(client_lock.is_locked()); // will be called via dispatch() -> objecter -> ... Inode *in = static_cast(oset->parent); assert(in); _flushed(in); } void Client::_flushed(Inode *in) { ldout(cct, 10) << "_flushed " << *in << dendl; put_cap_ref(in, CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_BUFFER); } // checks common to add_update_cap, handle_cap_grant void Client::check_cap_issue(Inode *in, Cap *cap, unsigned issued) { unsigned had = in->caps_issued(); if ((issued & CEPH_CAP_FILE_CACHE) && !(had & CEPH_CAP_FILE_CACHE)) in->cache_gen++; if ((issued & CEPH_CAP_FILE_SHARED) && !(had & CEPH_CAP_FILE_SHARED)) { in->shared_gen++; if (in->is_dir() && (in->flags & I_COMPLETE)) { ldout(cct, 10) << " clearing I_COMPLETE on " << *in << dendl; in->flags &= ~I_COMPLETE; } } } void Client::add_update_cap(Inode *in, MetaSession *mds_session, uint64_t cap_id, unsigned issued, unsigned seq, unsigned mseq, inodeno_t realm, int flags) { Cap *cap = 0; int mds = mds_session->mds_num; if (in->caps.count(mds)) { cap = in->caps[mds]; /* * auth mds of the inode changed. we received the cap export * message, but still haven't received the cap import message. * handle_cap_export() updated the new auth MDS' cap. * * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing * a message that was send before the cap import message. So * don't remove caps. */ if (ceph_seq_cmp(seq, cap->seq) <= 0) { assert(cap == in->auth_cap); assert(cap->cap_id == cap_id); seq = cap->seq; mseq = cap->mseq; issued |= cap->issued; flags |= CEPH_CAP_FLAG_AUTH; } } else { mds_session->num_caps++; if (!in->is_any_caps()) { assert(in->snaprealm == 0); in->snaprealm = get_snap_realm(realm); in->snaprealm->inodes_with_caps.push_back(&in->snaprealm_item); ldout(cct, 15) << "add_update_cap first one, opened snaprealm " << in->snaprealm << dendl; } in->caps[mds] = cap = new Cap; mds_session->caps.push_back(&cap->cap_item); cap->session = mds_session; cap->inode = in; cap->gen = mds_session->cap_gen; cap_list.push_back(&in->cap_item); } check_cap_issue(in, cap, issued); if (flags & CEPH_CAP_FLAG_AUTH) { if (in->auth_cap != cap && (!in->auth_cap || ceph_seq_cmp(in->auth_cap->mseq, mseq) < 0)) { if (in->auth_cap && in->flushing_cap_item.is_on_list()) { ldout(cct, 10) << "add_update_cap changing auth cap: " << "add myself to new auth MDS' flushing caps list" << dendl; mds_session->flushing_caps.push_back(&in->flushing_cap_item); } in->auth_cap = cap; } } unsigned old_caps = cap->issued; cap->cap_id = cap_id; cap->issued |= issued; cap->implemented |= issued; cap->seq = seq; cap->issue_seq = seq; cap->mseq = mseq; ldout(cct, 10) << "add_update_cap issued " << ccap_string(old_caps) << " -> " << ccap_string(cap->issued) << " from mds." << mds << " on " << *in << dendl; if ((issued & ~old_caps) && in->auth_cap == cap) { // non-auth MDS is revoking the newly grant caps ? for (map::iterator it = in->caps.begin(); it != in->caps.end(); ++it) { if (it->second == cap) continue; if (it->second->implemented & ~it->second->issued & issued) { check_caps(in, true); break; } } } if (issued & ~old_caps) signal_cond_list(in->waitfor_caps); } void Client::remove_cap(Cap *cap, bool queue_release) { Inode *in = cap->inode; MetaSession *session = cap->session; int mds = cap->session->mds_num; ldout(cct, 10) << "remove_cap mds." << mds << " on " << *in << dendl; if (queue_release) { if (!session->release) session->release = new MClientCapRelease; ceph_mds_cap_item i; i.ino = in->ino; i.cap_id = cap->cap_id; i.seq = cap->issue_seq; i.migrate_seq = cap->mseq; session->release->caps.push_back(i); } if (in->auth_cap == cap) { if (in->flushing_cap_item.is_on_list()) { ldout(cct, 10) << " removing myself from flushing_cap list" << dendl; in->flushing_cap_item.remove_myself(); } in->auth_cap = NULL; } assert(in->caps.count(mds)); in->caps.erase(mds); if (cap == session->s_cap_iterator) { cap->inode = NULL; } else { cap->cap_item.remove_myself(); delete cap; } if (!in->is_any_caps()) { ldout(cct, 15) << "remove_cap last one, closing snaprealm " << in->snaprealm << dendl; in->snaprealm_item.remove_myself(); put_snap_realm(in->snaprealm); in->snaprealm = 0; } } void Client::remove_all_caps(Inode *in) { while (!in->caps.empty()) remove_cap(in->caps.begin()->second, true); } void Client::remove_session_caps(MetaSession *mds) { while (mds->caps.size()) { Cap *cap = *mds->caps.begin(); remove_cap(cap, false); } } void Client::trim_caps(MetaSession *s, int max) { int mds = s->mds_num; ldout(cct, 10) << "trim_caps mds." << mds << " max " << max << dendl; int trimmed = 0; xlist::iterator p = s->caps.begin(); while (s->caps.size() > max && !p.end()) { Cap *cap = *p; s->s_cap_iterator = cap; Inode *in = cap->inode; if (in->caps.size() > 1 && cap != in->auth_cap) { int mine = cap->issued | cap->implemented; int oissued = in->auth_cap ? in->auth_cap->issued : 0; // disposable non-auth cap if (!(get_caps_used(in) & ~oissued & mine)) { ldout(cct, 20) << " removing unused, unneeded non-auth cap on " << *in << dendl; remove_cap(cap, true); trimmed++; } } else { ldout(cct, 20) << " trying to trim dentries for " << *in << dendl; bool all = true; set::iterator q = in->dn_set.begin(); while (q != in->dn_set.end()) { Dentry *dn = *q++; if (dn->lru_is_expireable()) trim_dentry(dn); else all = false; } if (all) trimmed++; } ++p; if (!cap->inode) { cap->cap_item.remove_myself(); delete cap; } } s->s_cap_iterator = NULL; // notify kernel to invalidate top level directory entries. As a side effect, // unused inodes underneath these entries get pruned. if (dentry_invalidate_cb && s->caps.size() > max) { for (ceph::unordered_map::iterator p = root->dir->dentries.begin(); p != root->dir->dentries.end(); ++p) { if (p->second->inode) _schedule_invalidate_dentry_callback(p->second, false); } } } void Client::mark_caps_dirty(Inode *in, int caps) { ldout(cct, 10) << "mark_caps_dirty " << *in << " " << ccap_string(in->dirty_caps) << " -> " << ccap_string(in->dirty_caps | caps) << dendl; if (caps && !in->caps_dirty()) in->get(); in->dirty_caps |= caps; } int Client::mark_caps_flushing(Inode *in) { MetaSession *session = in->auth_cap->session; int flushing = in->dirty_caps; assert(flushing); if (flushing && !in->flushing_caps) { ldout(cct, 10) << "mark_caps_flushing " << ccap_string(flushing) << " " << *in << dendl; num_flushing_caps++; } else { ldout(cct, 10) << "mark_caps_flushing (more) " << ccap_string(flushing) << " " << *in << dendl; } in->flushing_caps |= flushing; in->dirty_caps = 0; in->flushing_cap_seq = ++last_flush_seq; session->flushing_caps.push_back(&in->flushing_cap_item); return flushing; } void Client::flush_caps() { ldout(cct, 10) << "flush_caps" << dendl; xlist::iterator p = delayed_caps.begin(); while (!p.end()) { Inode *in = *p; ++p; delayed_caps.pop_front(); check_caps(in, true); } // other caps, too p = cap_list.begin(); while (!p.end()) { Inode *in = *p; ++p; check_caps(in, true); } } void Client::flush_caps(Inode *in, MetaSession *session) { ldout(cct, 10) << "flush_caps " << in << " mds." << session->mds_num << dendl; Cap *cap = in->auth_cap; assert(cap->session == session); send_cap(in, session, cap, get_caps_used(in), in->caps_wanted(), (cap->issued | cap->implemented), in->flushing_caps); } void Client::wait_sync_caps(uint64_t want) { retry: ldout(cct, 10) << "wait_sync_caps want " << want << " (last is " << last_flush_seq << ", " << num_flushing_caps << " total flushing)" << dendl; for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { if (p->second->flushing_caps.empty()) continue; Inode *in = p->second->flushing_caps.front(); if (in->flushing_cap_seq <= want) { ldout(cct, 10) << " waiting on mds." << p->first << " tid " << in->flushing_cap_seq << " (want " << want << ")" << dendl; sync_cond.Wait(client_lock); goto retry; } } } void Client::kick_flushing_caps(MetaSession *session) { int mds = session->mds_num; ldout(cct, 10) << "kick_flushing_caps mds." << mds << dendl; for (xlist::iterator p = session->flushing_capsnaps.begin(); !p.end(); ++p) { CapSnap *capsnap = *p; Inode *in = capsnap->in; ldout(cct, 20) << " reflushing capsnap " << capsnap << " on " << *in << " to mds." << mds << dendl; flush_snaps(in, false, capsnap); } for (xlist::iterator p = session->flushing_caps.begin(); !p.end(); ++p) { Inode *in = *p; ldout(cct, 20) << " reflushing caps on " << *in << " to mds." << mds << dendl; if (in->flushing_caps) flush_caps(in, session); } } void Client::kick_maxsize_requests(MetaSession *session) { xlist::iterator iter = session->caps.begin(); while (!iter.end()){ (*iter)->inode->requested_max_size = 0; (*iter)->inode->wanted_max_size = 0; signal_cond_list((*iter)->inode->waitfor_caps); ++iter; } } void SnapRealm::build_snap_context() { set snaps; snapid_t max_seq = seq; // start with prior_parents? for (unsigned i=0; iget_snap_context(); for (unsigned i=0; i= parent_since) snaps.insert(psnapc.snaps[i]); if (psnapc.seq > max_seq) max_seq = psnapc.seq; } // my snaps for (unsigned i=0; i::reverse_iterator p = snaps.rbegin(); p != snaps.rend(); ++p) cached_snap_context.snaps.push_back(*p); } void Client::invalidate_snaprealm_and_children(SnapRealm *realm) { list q; q.push_back(realm); while (!q.empty()) { realm = q.front(); q.pop_front(); ldout(cct, 10) << "invalidate_snaprealm_and_children " << *realm << dendl; realm->invalidate_cache(); for (set::iterator p = realm->pchildren.begin(); p != realm->pchildren.end(); ++p) q.push_back(*p); } } SnapRealm *Client::get_snap_realm(inodeno_t r) { SnapRealm *realm = snap_realms[r]; if (!realm) snap_realms[r] = realm = new SnapRealm(r); ldout(cct, 20) << "get_snap_realm " << r << " " << realm << " " << realm->nref << " -> " << (realm->nref + 1) << dendl; realm->nref++; return realm; } SnapRealm *Client::get_snap_realm_maybe(inodeno_t r) { if (snap_realms.count(r) == 0) { ldout(cct, 20) << "get_snap_realm_maybe " << r << " fail" << dendl; return NULL; } SnapRealm *realm = snap_realms[r]; ldout(cct, 20) << "get_snap_realm_maybe " << r << " " << realm << " " << realm->nref << " -> " << (realm->nref + 1) << dendl; realm->nref++; return realm; } void Client::put_snap_realm(SnapRealm *realm) { ldout(cct, 20) << "put_snap_realm " << realm->ino << " " << realm << " " << realm->nref << " -> " << (realm->nref - 1) << dendl; if (--realm->nref == 0) { snap_realms.erase(realm->ino); delete realm; } } bool Client::adjust_realm_parent(SnapRealm *realm, inodeno_t parent) { if (realm->parent != parent) { ldout(cct, 10) << "adjust_realm_parent " << *realm << " " << realm->parent << " -> " << parent << dendl; realm->parent = parent; if (realm->pparent) { realm->pparent->pchildren.erase(realm); put_snap_realm(realm->pparent); } realm->pparent = get_snap_realm(parent); realm->pparent->pchildren.insert(realm); return true; } return false; } inodeno_t Client::update_snap_trace(bufferlist& bl, bool flush) { inodeno_t first_realm = 0; ldout(cct, 10) << "update_snap_trace len " << bl.length() << dendl; bufferlist::iterator p = bl.begin(); while (!p.end()) { SnapRealmInfo info; ::decode(info, p); if (first_realm == 0) first_realm = info.ino(); SnapRealm *realm = get_snap_realm(info.ino()); if (info.seq() > realm->seq) { ldout(cct, 10) << "update_snap_trace " << *realm << " seq " << info.seq() << " > " << realm->seq << dendl; if (flush) { // writeback any dirty caps _before_ updating snap list (i.e. with old snap info) // flush me + children list q; q.push_back(realm); while (!q.empty()) { SnapRealm *realm = q.front(); q.pop_front(); ldout(cct, 10) << " flushing caps on " << *realm << dendl; xlist::iterator p = realm->inodes_with_caps.begin(); while (!p.end()) { Inode *in = *p; ++p; queue_cap_snap(in, realm->get_snap_context().seq); } for (set::iterator p = realm->pchildren.begin(); p != realm->pchildren.end(); ++p) q.push_back(*p); } } } // _always_ verify parent bool invalidate = adjust_realm_parent(realm, info.parent()); if (info.seq() > realm->seq) { // update realm->seq = info.seq(); realm->created = info.created(); realm->parent_since = info.parent_since(); realm->prior_parent_snaps = info.prior_parent_snaps; realm->my_snaps = info.my_snaps; invalidate = true; } if (invalidate) { invalidate_snaprealm_and_children(realm); ldout(cct, 15) << "update_snap_trace " << *realm << " self|parent updated" << dendl; ldout(cct, 15) << " snapc " << realm->get_snap_context() << dendl; } else { ldout(cct, 10) << "update_snap_trace " << *realm << " seq " << info.seq() << " <= " << realm->seq << " and same parent, SKIPPING" << dendl; } put_snap_realm(realm); } return first_realm; } void Client::handle_snap(MClientSnap *m) { ldout(cct, 10) << "handle_snap " << *m << dendl; int mds = m->get_source().num(); MetaSession *session = _get_mds_session(mds, m->get_connection().get()); if (!session) { m->put(); return; } got_mds_push(session); list to_move; SnapRealm *realm = 0; if (m->head.op == CEPH_SNAP_OP_SPLIT) { assert(m->head.split); SnapRealmInfo info; bufferlist::iterator p = m->bl.begin(); ::decode(info, p); assert(info.ino() == m->head.split); // flush, then move, ino's. realm = get_snap_realm(info.ino()); ldout(cct, 10) << " splitting off " << *realm << dendl; for (vector::iterator p = m->split_inos.begin(); p != m->split_inos.end(); ++p) { vinodeno_t vino(*p, CEPH_NOSNAP); if (inode_map.count(vino)) { Inode *in = inode_map[vino]; if (!in->snaprealm || in->snaprealm == realm) continue; if (in->snaprealm->created > info.created()) { ldout(cct, 10) << " NOT moving " << *in << " from _newer_ realm " << *in->snaprealm << dendl; continue; } ldout(cct, 10) << " moving " << *in << " from " << *in->snaprealm << dendl; // queue for snap writeback queue_cap_snap(in, in->snaprealm->get_snap_context().seq); in->snaprealm_item.remove_myself(); put_snap_realm(in->snaprealm); to_move.push_back(in); } } // move child snaprealms, too for (vector::iterator p = m->split_realms.begin(); p != m->split_realms.end(); ++p) { ldout(cct, 10) << "adjusting snaprealm " << *p << " parent" << dendl; SnapRealm *child = get_snap_realm_maybe(*p); if (!child) continue; adjust_realm_parent(child, realm->ino); put_snap_realm(child); } } update_snap_trace(m->bl, m->head.op != CEPH_SNAP_OP_DESTROY); if (realm) { for (list::iterator p = to_move.begin(); p != to_move.end(); ++p) { Inode *in = *p; in->snaprealm = realm; realm->inodes_with_caps.push_back(&in->snaprealm_item); realm->nref++; } put_snap_realm(realm); } m->put(); } void Client::handle_caps(MClientCaps *m) { int mds = m->get_source().num(); MetaSession *session = _get_mds_session(mds, m->get_connection().get()); if (!session) { m->put(); return; } got_mds_push(session); m->clear_payload(); // for if/when we send back to MDS Inode *in = 0; vinodeno_t vino(m->get_ino(), CEPH_NOSNAP); if (inode_map.count(vino)) in = inode_map[vino]; if (!in) { if (m->get_op() == CEPH_CAP_OP_IMPORT) { ldout(cct, 5) << "handle_caps don't have vino " << vino << " on IMPORT, immediately releasing" << dendl; if (!session->release) session->release = new MClientCapRelease; ceph_mds_cap_item i; i.ino = m->get_ino(); i.cap_id = m->get_cap_id(); i.seq = m->get_seq(); i.migrate_seq = m->get_mseq(); session->release->caps.push_back(i); } else { ldout(cct, 5) << "handle_caps don't have vino " << vino << ", dropping" << dendl; } m->put(); // in case the mds is waiting on e.g. a revocation flush_cap_releases(); return; } switch (m->get_op()) { case CEPH_CAP_OP_EXPORT: return handle_cap_export(session, in, m); case CEPH_CAP_OP_FLUSHSNAP_ACK: return handle_cap_flushsnap_ack(session, in, m); case CEPH_CAP_OP_IMPORT: handle_cap_import(session, in, m); } if (in->caps.count(mds) == 0) { ldout(cct, 5) << "handle_caps don't have " << *in << " cap on mds." << mds << dendl; m->put(); return; } Cap *cap = in->caps[mds]; switch (m->get_op()) { case CEPH_CAP_OP_TRUNC: return handle_cap_trunc(session, in, m); case CEPH_CAP_OP_IMPORT: case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: return handle_cap_grant(session, in, cap, m); case CEPH_CAP_OP_FLUSH_ACK: return handle_cap_flush_ack(session, in, cap, m); default: m->put(); } } void Client::handle_cap_import(MetaSession *session, Inode *in, MClientCaps *m) { int mds = session->mds_num; ldout(cct, 5) << "handle_cap_import ino " << m->get_ino() << " mseq " << m->get_mseq() << " IMPORT from mds." << mds << dendl; // add/update it update_snap_trace(m->snapbl); add_update_cap(in, session, m->get_cap_id(), m->get_caps(), m->get_seq(), m->get_mseq(), m->get_realm(), CEPH_CAP_FLAG_AUTH); if (m->peer.cap_id && in->caps.count(m->peer.mds)) { Cap *cap = in->caps[m->peer.mds]; if (cap && cap->cap_id == m->peer.cap_id) remove_cap(cap, (m->peer.flags & CEPH_CAP_FLAG_RELEASE)); } if (in->auth_cap && in->auth_cap->session->mds_num == mds) { // reflush any/all caps (if we are now the auth_cap) if (in->cap_snaps.size()) flush_snaps(in, true); if (in->flushing_caps) flush_caps(in, session); } } void Client::handle_cap_export(MetaSession *session, Inode *in, MClientCaps *m) { int mds = session->mds_num; ldout(cct, 5) << "handle_cap_export ino " << m->get_ino() << " mseq " << m->get_mseq() << " EXPORT from mds." << mds << dendl; Cap *cap = NULL; if (in->caps.count(mds)) cap = in->caps[mds]; if (cap && cap->cap_id == m->get_cap_id()) { if (m->peer.cap_id) { MetaSession *tsession = _get_or_open_mds_session(m->peer.mds); if (in->caps.count(m->peer.mds)) { Cap *tcap = in->caps[m->peer.mds]; if (tcap->cap_id != m->peer.cap_id || ceph_seq_cmp(tcap->seq, m->peer.seq) < 0) { tcap->cap_id = m->peer.cap_id; tcap->seq = m->peer.seq - 1; tcap->issue_seq = tcap->seq; tcap->mseq = m->peer.mseq; tcap->issued |= cap->issued; tcap->implemented |= cap->issued; if (cap == in->auth_cap) in->auth_cap = tcap; if (in->auth_cap == tcap && in->flushing_cap_item.is_on_list()) tsession->flushing_caps.push_back(&in->flushing_cap_item); } } else { add_update_cap(in, tsession, m->peer.cap_id, cap->issued, m->peer.seq - 1, m->peer.mseq, (uint64_t)-1, cap == in->auth_cap ? CEPH_CAP_FLAG_AUTH : 0); } } remove_cap(cap, false); } m->put(); } void Client::handle_cap_trunc(MetaSession *session, Inode *in, MClientCaps *m) { int mds = session->mds_num; assert(in->caps[mds]); ldout(cct, 10) << "handle_cap_trunc on ino " << *in << " size " << in->size << " -> " << m->get_size() << dendl; int implemented = 0; int issued = in->caps_issued(&implemented) | in->caps_dirty(); issued |= implemented; update_inode_file_bits(in, m->get_truncate_seq(), m->get_truncate_size(), m->get_size(), m->get_time_warp_seq(), m->get_ctime(), m->get_mtime(), m->get_atime(), m->inline_version, m->inline_data, issued); m->put(); } void Client::handle_cap_flush_ack(MetaSession *session, Inode *in, Cap *cap, MClientCaps *m) { int mds = session->mds_num; int dirty = m->get_dirty(); int cleaned = 0; uint16_t flush_ack_tid = static_cast(m->get_client_tid()); for (int i = 0; i < CEPH_CAP_BITS; ++i) { if ((dirty & (1 << i)) && (flush_ack_tid == in->flushing_cap_tid[i])) cleaned |= 1 << i; } ldout(cct, 5) << "handle_cap_flush_ack mds." << mds << " cleaned " << ccap_string(cleaned) << " on " << *in << " with " << ccap_string(dirty) << dendl; if (!cleaned) { ldout(cct, 10) << " tid " << m->get_client_tid() << " != any cap bit tids" << dendl; } else { if (in->flushing_caps) { ldout(cct, 5) << " flushing_caps " << ccap_string(in->flushing_caps) << " -> " << ccap_string(in->flushing_caps & ~cleaned) << dendl; in->flushing_caps &= ~cleaned; if (in->flushing_caps == 0) { ldout(cct, 10) << " " << *in << " !flushing" << dendl; in->flushing_cap_item.remove_myself(); num_flushing_caps--; sync_cond.Signal(); } if (!in->caps_dirty()) put_inode(in); } } m->put(); } void Client::handle_cap_flushsnap_ack(MetaSession *session, Inode *in, MClientCaps *m) { int mds = session->mds_num; assert(in->caps[mds]); snapid_t follows = m->get_snap_follows(); if (in->cap_snaps.count(follows)) { CapSnap *capsnap = in->cap_snaps[follows]; if (m->get_client_tid() != capsnap->flush_tid) { ldout(cct, 10) << " tid " << m->get_client_tid() << " != " << capsnap->flush_tid << dendl; } else { ldout(cct, 5) << "handle_cap_flushedsnap mds." << mds << " flushed snap follows " << follows << " on " << *in << dendl; capsnap->flushing_item.remove_myself(); delete capsnap; in->cap_snaps.erase(follows); put_inode(in); } } else { ldout(cct, 5) << "handle_cap_flushedsnap DUP(?) mds." << mds << " flushed snap follows " << follows << " on " << *in << dendl; // we may not have it if we send multiple FLUSHSNAP requests and (got multiple FLUSHEDSNAPs back) } m->put(); } class C_Client_DentryInvalidate : public Context { private: Client *client; vinodeno_t dirino; vinodeno_t ino; string name; public: C_Client_DentryInvalidate(Client *c, Dentry *dn, bool del) : client(c), name(dn->name) { dirino = dn->dir->parent_inode->vino(); if (del) ino = dn->inode->vino(); else ino.ino = inodeno_t(); } void finish(int r) { client->_async_dentry_invalidate(dirino, ino, name); } }; void Client::_async_dentry_invalidate(vinodeno_t dirino, vinodeno_t ino, string& name) { ldout(cct, 10) << "_async_dentry_invalidate '" << name << "' ino " << ino << " in dir " << dirino << dendl; dentry_invalidate_cb(dentry_invalidate_cb_handle, dirino, ino, name); } void Client::_schedule_invalidate_dentry_callback(Dentry *dn, bool del) { if (dentry_invalidate_cb && dn->inode->ll_ref > 0) async_dentry_invalidator.queue(new C_Client_DentryInvalidate(this, dn, del)); } void Client::_invalidate_inode_parents(Inode *in) { set::iterator q = in->dn_set.begin(); while (q != in->dn_set.end()) { Dentry *dn = *q++; // FIXME: we play lots of unlink/link tricks when handling MDS replies, // so in->dn_set doesn't always reflect the state of kernel's dcache. _schedule_invalidate_dentry_callback(dn, true); unlink(dn, false); } } void Client::handle_cap_grant(MetaSession *session, Inode *in, Cap *cap, MClientCaps *m) { int mds = session->mds_num; int used = get_caps_used(in); int wanted = in->caps_wanted(); const int old_caps = cap->issued; const int new_caps = m->get_caps(); ldout(cct, 5) << "handle_cap_grant on in " << m->get_ino() << " mds." << mds << " seq " << m->get_seq() << " caps now " << ccap_string(new_caps) << " was " << ccap_string(old_caps) << dendl; cap->seq = m->get_seq(); in->layout = m->get_layout(); // update inode int implemented = 0; int issued = in->caps_issued(&implemented) | in->caps_dirty(); issued |= implemented; if ((issued & CEPH_CAP_AUTH_EXCL) == 0) { in->mode = m->head.mode; in->uid = m->head.uid; in->gid = m->head.gid; } bool deleted_inode = false; if ((issued & CEPH_CAP_LINK_EXCL) == 0 && in->nlink != (int32_t)m->head.nlink) { in->nlink = m->head.nlink; if (in->nlink == 0 && (new_caps & (CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL))) deleted_inode = true; } if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && m->xattrbl.length() && m->head.xattr_version > in->xattr_version) { bufferlist::iterator p = m->xattrbl.begin(); ::decode(in->xattrs, p); in->xattr_version = m->head.xattr_version; } update_inode_file_bits(in, m->get_truncate_seq(), m->get_truncate_size(), m->get_size(), m->get_time_warp_seq(), m->get_ctime(), m->get_mtime(), m->get_atime(), m->inline_version, m->inline_data, issued); // max_size if (cap == in->auth_cap && m->get_max_size() != in->max_size) { ldout(cct, 10) << "max_size " << in->max_size << " -> " << m->get_max_size() << dendl; in->max_size = m->get_max_size(); if (in->max_size > in->wanted_max_size) { in->wanted_max_size = 0; in->requested_max_size = 0; } } bool check = false; if (m->get_op() == CEPH_CAP_OP_IMPORT && m->get_wanted() != wanted) check = true; check_cap_issue(in, cap, issued); // update caps if (old_caps & ~new_caps) { ldout(cct, 10) << " revocation of " << ccap_string(~new_caps & old_caps) << dendl; cap->issued = new_caps; cap->implemented |= new_caps; if (((used & ~new_caps) & CEPH_CAP_FILE_BUFFER) && !_flush(in)) { // waitin' for flush } else if ((old_caps & ~new_caps) & CEPH_CAP_FILE_CACHE) { _release(in); } else { cap->wanted = 0; // don't let check_caps skip sending a response to MDS check = true; } } else if (old_caps == new_caps) { ldout(cct, 10) << " caps unchanged at " << ccap_string(old_caps) << dendl; } else { ldout(cct, 10) << " grant, new caps are " << ccap_string(new_caps & ~old_caps) << dendl; cap->issued = new_caps; cap->implemented |= new_caps; if (cap == in->auth_cap) { // non-auth MDS is revoking the newly grant caps ? for (map::iterator it = in->caps.begin(); it != in->caps.end(); ++it) { if (it->second == cap) continue; if (it->second->implemented & ~it->second->issued & new_caps) { check = true; break; } } } } if (check) check_caps(in, false); // wake up waiters if (new_caps) signal_cond_list(in->waitfor_caps); // may drop inode's last ref if (deleted_inode) _invalidate_inode_parents(in); m->put(); } int Client::check_permissions(Inode *in, int flags, int uid, int gid) { gid_t *sgids = NULL; int sgid_count = 0; if (getgroups_cb) { sgid_count = getgroups_cb(getgroups_cb_handle, uid, &sgids); if (sgid_count < 0) { ldout(cct, 3) << "getgroups failed!" << dendl; return sgid_count; } } // check permissions before doing anything else if (uid != 0 && !in->check_mode(uid, gid, sgids, sgid_count, flags)) { return -EACCES; } return 0; } vinodeno_t Client::_get_vino(Inode *in) { /* The caller must hold the client lock */ return vinodeno_t(in->ino, in->snapid); } inodeno_t Client::_get_inodeno(Inode *in) { /* The caller must hold the client lock */ return in->ino; } // ------------------- // MOUNT int Client::mount(const std::string &mount_root) { Mutex::Locker lock(client_lock); if (mounted) { ldout(cct, 5) << "already mounted" << dendl;; return 0; } client_lock.Unlock(); int r = monclient->authenticate(cct->_conf->client_mount_timeout); client_lock.Lock(); if (r < 0) return r; whoami = monclient->get_global_id(); messenger->set_myname(entity_name_t::CLIENT(whoami.v)); mounted = true; tick(); // start tick ldout(cct, 2) << "mounted: have osdmap " << osdmap->get_epoch() << " and mdsmap " << mdsmap->get_epoch() << dendl; // hack: get+pin root inode. // fuse assumes it's always there. MetaRequest *req = new MetaRequest(CEPH_MDS_OP_GETATTR); filepath fp(CEPH_INO_ROOT); if (!mount_root.empty()) fp = filepath(mount_root.c_str()); req->set_filepath(fp); req->head.args.getattr.mask = CEPH_STAT_CAP_INODE_ALL; int res = make_request(req, -1, -1); ldout(cct, 10) << "root getattr result=" << res << dendl; if (res < 0) return res; assert(root); _ll_get(root); // trace? if (!cct->_conf->client_trace.empty()) { traceout.open(cct->_conf->client_trace.c_str()); if (traceout.is_open()) { ldout(cct, 1) << "opened trace file '" << cct->_conf->client_trace << "'" << dendl; } else { ldout(cct, 1) << "FAILED to open trace file '" << cct->_conf->client_trace << "'" << dendl; } } /* ldout(cct, 3) << "op: // client trace data structs" << dendl; ldout(cct, 3) << "op: struct stat st;" << dendl; ldout(cct, 3) << "op: struct utimbuf utim;" << dendl; ldout(cct, 3) << "op: int readlinkbuf_len = 1000;" << dendl; ldout(cct, 3) << "op: char readlinkbuf[readlinkbuf_len];" << dendl; ldout(cct, 3) << "op: map dir_contents;" << dendl; ldout(cct, 3) << "op: map open_files;" << dendl; ldout(cct, 3) << "op: int fd;" << dendl; */ return 0; } // UNMOUNT void Client::unmount() { Mutex::Locker lock(client_lock); assert(mounted); // caller is confused? ldout(cct, 2) << "unmounting" << dendl; unmounting = true; while (!mds_requests.empty()) { ldout(cct, 10) << "waiting on " << mds_requests.size() << " requests" << dendl; mount_cond.Wait(client_lock); } if (tick_event) timer.cancel_event(tick_event); tick_event = 0; if (cwd) put_inode(cwd); cwd = NULL; // clean up any unclosed files while (!fd_map.empty()) { Fh *fh = fd_map.begin()->second; fd_map.erase(fd_map.begin()); ldout(cct, 0) << " destroying lost open file " << fh << " on " << *fh->inode << dendl; _release_fh(fh); } _ll_drop_pins(); while (unsafe_sync_write > 0) { ldout(cct, 0) << unsafe_sync_write << " unsafe_sync_writes, waiting" << dendl; mount_cond.Wait(client_lock); } if (cct->_conf->client_oc) { // flush/release all buffered data ceph::unordered_map::iterator next; for (ceph::unordered_map::iterator p = inode_map.begin(); p != inode_map.end(); p = next) { next = p; ++next; Inode *in = p->second; if (!in) { ldout(cct, 0) << "null inode_map entry ino " << p->first << dendl; assert(in); } if (!in->caps.empty()) { in->get(); _release(in); _flush(in); put_inode(in); } } } flush_caps(); wait_sync_caps(last_flush_seq); // empty lru cache lru.lru_set_max(0); trim_cache(); while (lru.lru_get_size() > 0 || !inode_map.empty()) { ldout(cct, 2) << "cache still has " << lru.lru_get_size() << "+" << inode_map.size() << " items" << ", waiting (for caps to release?)" << dendl; utime_t until = ceph_clock_now(cct) + utime_t(5, 0); int r = mount_cond.WaitUntil(client_lock, until); if (r == ETIMEDOUT) { dump_cache(NULL); } } assert(lru.lru_get_size() == 0); assert(inode_map.empty()); // stop tracing if (!cct->_conf->client_trace.empty()) { ldout(cct, 1) << "closing trace file '" << cct->_conf->client_trace << "'" << dendl; traceout.close(); } while (!mds_sessions.empty()) { // send session closes! for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { if (p->second->state != MetaSession::STATE_CLOSING) { _close_mds_session(p->second); } } // wait for sessions to close ldout(cct, 2) << "waiting for " << mds_sessions.size() << " mds sessions to close" << dendl; mount_cond.Wait(client_lock); } mounted = false; ldout(cct, 2) << "unmounted." << dendl; } class C_C_Tick : public Context { Client *client; public: C_C_Tick(Client *c) : client(c) {} void finish(int r) { client->tick(); } }; void Client::flush_cap_releases() { // send any cap releases for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { if (p->second->release && mdsmap->is_clientreplay_or_active_or_stopping(p->first)) { messenger->send_message(p->second->release, p->second->con); p->second->release = 0; } } } void Client::tick() { if (cct->_conf->client_debug_inject_tick_delay > 0) { sleep(cct->_conf->client_debug_inject_tick_delay); assert(0 == cct->_conf->set_val("client_debug_inject_tick_delay", "0")); cct->_conf->apply_changes(NULL); } ldout(cct, 21) << "tick" << dendl; tick_event = new C_C_Tick(this); timer.add_event_after(cct->_conf->client_tick_interval, tick_event); utime_t now = ceph_clock_now(cct); if (mdsmap->get_epoch()) { // renew caps? utime_t el = now - last_cap_renew; if (el > mdsmap->get_session_timeout() / 3.0) renew_caps(); flush_cap_releases(); } // delayed caps xlist::iterator p = delayed_caps.begin(); while (!p.end()) { Inode *in = *p; ++p; if (in->hold_caps_until > now) break; delayed_caps.pop_front(); cap_list.push_back(&in->cap_item); check_caps(in, true); } } void Client::renew_caps() { ldout(cct, 10) << "renew_caps()" << dendl; last_cap_renew = ceph_clock_now(cct); for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { ldout(cct, 15) << "renew_caps requesting from mds." << p->first << dendl; if (mdsmap->get_state(p->first) >= MDSMap::STATE_REJOIN) renew_caps(p->second); } } void Client::renew_caps(MetaSession *session) { ldout(cct, 10) << "renew_caps mds." << session->mds_num << dendl; session->last_cap_renew_request = ceph_clock_now(cct); uint64_t seq = ++session->cap_renew_seq; messenger->send_message(new MClientSession(CEPH_SESSION_REQUEST_RENEWCAPS, seq), session->con); } // =============================================================== // high level (POSIXy) interface int Client::_do_lookup(Inode *dir, const string& name, Inode **target) { int op = dir->snapid == CEPH_SNAPDIR ? CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP; MetaRequest *req = new MetaRequest(op); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); req->set_inode(dir); req->head.args.getattr.mask = 0; ldout(cct, 10) << "_do_lookup on " << path << dendl; int r = make_request(req, 0, 0, target); ldout(cct, 10) << "_do_lookup res is " << r << dendl; return r; } int Client::_lookup(Inode *dir, const string& dname, Inode **target) { int r = 0; if (!dir->is_dir()) { r = -ENOTDIR; goto done; } if (dname == "..") { if (dir->dn_set.empty()) r = -ENOENT; else *target = dir->get_first_parent()->dir->parent_inode; //dirs can't be hard-linked goto done; } if (dname == ".") { *target = dir; goto done; } if (dname.length() > NAME_MAX) { r = -ENAMETOOLONG; goto done; } if (dname == cct->_conf->client_snapdir && dir->snapid == CEPH_NOSNAP) { *target = open_snapdir(dir); goto done; } if (dir->dir && dir->dir->dentries.count(dname)) { Dentry *dn = dir->dir->dentries[dname]; ldout(cct, 20) << "_lookup have dn " << dname << " mds." << dn->lease_mds << " ttl " << dn->lease_ttl << " seq " << dn->lease_seq << dendl; if (!dn->inode || dn->inode->is_any_caps()) { // is dn lease valid? utime_t now = ceph_clock_now(cct); if (dn->lease_mds >= 0 && dn->lease_ttl > now && mds_sessions.count(dn->lease_mds)) { MetaSession *s = mds_sessions[dn->lease_mds]; if (s->cap_ttl > now && s->cap_gen == dn->lease_gen) { *target = dn->inode; // touch this mds's dir cap too, even though we don't _explicitly_ use it here, to // make trim_caps() behave. dir->try_touch_cap(dn->lease_mds); touch_dn(dn); goto done; } ldout(cct, 20) << " bad lease, cap_ttl " << s->cap_ttl << ", cap_gen " << s->cap_gen << " vs lease_gen " << dn->lease_gen << dendl; } // dir lease? if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED) && dn->cap_shared_gen == dir->shared_gen) { *target = dn->inode; touch_dn(dn); goto done; } } else { ldout(cct, 20) << " no cap on " << dn->inode->vino() << dendl; } } else { // can we conclude ENOENT locally? if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED) && (dir->flags & I_COMPLETE)) { ldout(cct, 10) << "_lookup concluded ENOENT locally for " << *dir << " dn '" << dname << "'" << dendl; return -ENOENT; } } r = _do_lookup(dir, dname, target); done: if (r < 0) ldout(cct, 10) << "_lookup " << *dir << " " << dname << " = " << r << dendl; else ldout(cct, 10) << "_lookup " << *dir << " " << dname << " = " << **target << dendl; return r; } int Client::get_or_create(Inode *dir, const char* name, Dentry **pdn, bool expect_null) { // lookup ldout(cct, 20) << "get_or_create " << *dir << " name " << name << dendl; dir->open_dir(); if (dir->dir->dentries.count(name)) { Dentry *dn = dir->dir->dentries[name]; // is dn lease valid? utime_t now = ceph_clock_now(cct); if (dn->inode && dn->lease_mds >= 0 && dn->lease_ttl > now && mds_sessions.count(dn->lease_mds)) { MetaSession *s = mds_sessions[dn->lease_mds]; if (s->cap_ttl > now && s->cap_gen == dn->lease_gen) { if (expect_null) return -EEXIST; } } *pdn = dn; } else { // otherwise link up a new one *pdn = link(dir->dir, name, NULL, NULL); } // success return 0; } int Client::path_walk(const filepath& origpath, Inode **final, bool followsym) { filepath path = origpath; Inode *cur; if (origpath.absolute()) cur = root; else cur = cwd; assert(cur); ldout(cct, 10) << "path_walk " << path << dendl; int symlinks = 0; unsigned i=0; while (i < path.depth() && cur) { const string &dname = path[i]; ldout(cct, 10) << " " << i << " " << *cur << " " << dname << dendl; ldout(cct, 20) << " (path is " << path << ")" << dendl; Inode *next; int r = _lookup(cur, dname, &next); if (r < 0) return r; // only follow trailing symlink if followsym. always follow // 'directory' symlinks. if (next && next->is_symlink()) { symlinks++; ldout(cct, 20) << " symlink count " << symlinks << ", value is '" << next->symlink << "'" << dendl; if (symlinks > MAXSYMLINKS) { return -ELOOP; } if (i < path.depth() - 1) { // dir symlink // replace consumed components of path with symlink dir target filepath resolved(next->symlink.c_str()); resolved.append(path.postfixpath(i + 1)); path = resolved; i = 0; if (next->symlink[0] == '/') { cur = root; } continue; } else if (followsym) { if (next->symlink[0] == '/') { path = next->symlink.c_str(); i = 0; // reset position cur = root; } else { filepath more(next->symlink.c_str()); // we need to remove the symlink component from off of the path // before adding the target that the symlink points to. remain // at the same position in the path. path.pop_dentry(); path.append(more); } continue; } } cur = next; i++; } if (!cur) return -ENOENT; if (final) *final = cur; return 0; } // namespace ops int Client::link(const char *relexisting, const char *relpath) { Mutex::Locker lock(client_lock); tout(cct) << "link" << std::endl; tout(cct) << relexisting << std::endl; tout(cct) << relpath << std::endl; filepath existing(relexisting); filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); Inode *in, *dir; int r; r = path_walk(existing, &in); if (r < 0) goto out; in->get(); r = path_walk(path, &dir); if (r < 0) goto out_unlock; r = _link(in, dir, name.c_str()); out_unlock: put_inode(in); out: return r; } int Client::unlink(const char *relpath) { Mutex::Locker lock(client_lock); tout(cct) << "unlink" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); Inode *dir; int r = path_walk(path, &dir); if (r < 0) return r; return _unlink(dir, name.c_str()); } int Client::rename(const char *relfrom, const char *relto) { Mutex::Locker lock(client_lock); tout(cct) << "rename" << std::endl; tout(cct) << relfrom << std::endl; tout(cct) << relto << std::endl; filepath from(relfrom); filepath to(relto); string fromname = from.last_dentry(); from.pop_dentry(); string toname = to.last_dentry(); to.pop_dentry(); Inode *fromdir, *todir; int r; r = path_walk(from, &fromdir); if (r < 0) goto out; fromdir->get(); r = path_walk(to, &todir); if (r < 0) goto out_unlock; todir->get(); r = _rename(fromdir, fromname.c_str(), todir, toname.c_str()); put_inode(todir); out_unlock: put_inode(fromdir); out: return r; } // dirs int Client::mkdir(const char *relpath, mode_t mode) { Mutex::Locker lock(client_lock); tout(cct) << "mkdir" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << mode << std::endl; ldout(cct, 10) << "mkdir: " << relpath << dendl; filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); Inode *dir; int r = path_walk(path, &dir); if (r < 0) { return r; } return _mkdir(dir, name.c_str(), mode); } int Client::mkdirs(const char *relpath, mode_t mode) { Mutex::Locker lock(client_lock); ldout(cct, 10) << "Client::mkdirs " << relpath << dendl; tout(cct) << "mkdirs" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << mode << std::endl; //get through existing parts of path filepath path(relpath); unsigned int i; int r=0; Inode *cur = cwd; Inode *next; for (i=0; iino).get_path() << dendl; } return 0; } int Client::rmdir(const char *relpath) { Mutex::Locker lock(client_lock); tout(cct) << "rmdir" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); Inode *dir; int r = path_walk(path, &dir); if (r < 0) return r; return _rmdir(dir, name.c_str()); } int Client::mknod(const char *relpath, mode_t mode, dev_t rdev) { Mutex::Locker lock(client_lock); tout(cct) << "mknod" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << mode << std::endl; tout(cct) << rdev << std::endl; filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; return _mknod(in, name.c_str(), mode, rdev); } // symlinks int Client::symlink(const char *target, const char *relpath) { Mutex::Locker lock(client_lock); tout(cct) << "symlink" << std::endl; tout(cct) << target << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); Inode *dir; int r = path_walk(path, &dir); if (r < 0) return r; return _symlink(dir, name.c_str(), target); } int Client::readlink(const char *relpath, char *buf, loff_t size) { Mutex::Locker lock(client_lock); tout(cct) << "readlink" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in, false); if (r < 0) return r; return _readlink(in, buf, size); } int Client::_readlink(Inode *in, char *buf, size_t size) { if (!in->is_symlink()) return -EINVAL; // copy into buf (at most size bytes) int r = in->symlink.length(); if (r > (int)size) r = size; memcpy(buf, in->symlink.c_str(), r); return r; } // inode stuff int Client::_getattr(Inode *in, int mask, int uid, int gid, bool force) { bool yes = in->caps_issued_mask(mask); ldout(cct, 10) << "_getattr mask " << ccap_string(mask) << " issued=" << yes << dendl; if (yes && !force) return 0; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_GETATTR); filepath path; in->make_nosnap_relative_path(path); req->set_filepath(path); req->set_inode(in); req->head.args.getattr.mask = mask; int res = make_request(req, uid, gid); ldout(cct, 10) << "_getattr result=" << res << dendl; return res; } int Client::_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid, Inode **inp) { int issued = in->caps_issued(); ldout(cct, 10) << "_setattr mask " << mask << " issued " << ccap_string(issued) << dendl; if (in->snapid != CEPH_NOSNAP) { return -EROFS; } // make the change locally? if (!mask) { // caller just needs us to bump the ctime in->ctime = ceph_clock_now(cct); if (issued & CEPH_CAP_AUTH_EXCL) mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); else if (issued & CEPH_CAP_FILE_EXCL) mark_caps_dirty(in, CEPH_CAP_FILE_EXCL); else if (issued & CEPH_CAP_XATTR_EXCL) mark_caps_dirty(in, CEPH_CAP_XATTR_EXCL); else mask |= CEPH_SETATTR_CTIME; } if (in->caps_issued_mask(CEPH_CAP_AUTH_EXCL)) { if (mask & CEPH_SETATTR_MODE) { in->ctime = ceph_clock_now(cct); in->mode = (in->mode & ~07777) | (attr->st_mode & 07777); mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_MODE; } if (mask & CEPH_SETATTR_UID) { in->ctime = ceph_clock_now(cct); in->uid = attr->st_uid; mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_UID; } if (mask & CEPH_SETATTR_GID) { in->ctime = ceph_clock_now(cct); in->gid = attr->st_gid; mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_GID; } } if (in->caps_issued_mask(CEPH_CAP_FILE_EXCL)) { if (mask & (CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME)) { if (mask & CEPH_SETATTR_MTIME) in->mtime = utime_t(stat_get_mtime_sec(attr), stat_get_mtime_nsec(attr)); if (mask & CEPH_SETATTR_ATIME) in->atime = utime_t(stat_get_atime_sec(attr), stat_get_atime_nsec(attr)); in->ctime = ceph_clock_now(cct); in->time_warp_seq++; mark_caps_dirty(in, CEPH_CAP_FILE_EXCL); mask &= ~(CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME); } } if (!mask) return 0; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_SETATTR); filepath path; in->make_nosnap_relative_path(path); req->set_filepath(path); req->set_inode(in); if (mask & CEPH_SETATTR_MODE) { req->head.args.setattr.mode = attr->st_mode; req->inode_drop |= CEPH_CAP_AUTH_SHARED; } if (mask & CEPH_SETATTR_UID) { req->head.args.setattr.uid = attr->st_uid; req->inode_drop |= CEPH_CAP_AUTH_SHARED; } if (mask & CEPH_SETATTR_GID) { req->head.args.setattr.gid = attr->st_gid; req->inode_drop |= CEPH_CAP_AUTH_SHARED; } if (mask & CEPH_SETATTR_MTIME) { utime_t mtime = utime_t(stat_get_mtime_sec(attr), stat_get_mtime_nsec(attr)); req->head.args.setattr.mtime = mtime; req->inode_drop |= CEPH_CAP_AUTH_SHARED | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR; } if (mask & CEPH_SETATTR_ATIME) { utime_t atime = utime_t(stat_get_atime_sec(attr), stat_get_atime_nsec(attr)); req->head.args.setattr.atime = atime; req->inode_drop |= CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR; } if (mask & CEPH_SETATTR_SIZE) { if ((unsigned long)attr->st_size < mdsmap->get_max_filesize()) req->head.args.setattr.size = attr->st_size; else { //too big! put_request(req); return -EFBIG; } req->inode_drop |= CEPH_CAP_AUTH_SHARED | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR; } req->head.args.setattr.mask = mask; req->regetattr_mask = mask; int res = make_request(req, uid, gid, inp); ldout(cct, 10) << "_setattr result=" << res << dendl; return res; } int Client::setattr(const char *relpath, struct stat *attr, int mask) { Mutex::Locker lock(client_lock); tout(cct) << "setattr" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << mask << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; return _setattr(in, attr, mask); } int Client::fsetattr(int fd, struct stat *attr, int mask) { Mutex::Locker lock(client_lock); tout(cct) << "fsetattr" << std::endl; tout(cct) << fd << std::endl; tout(cct) << mask << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; return _setattr(f->inode, attr, mask); } int Client::stat(const char *relpath, struct stat *stbuf, frag_info_t *dirstat, int mask) { ldout(cct, 3) << "stat enter (relpath" << relpath << " mask " << mask << ")" << dendl; Mutex::Locker lock(client_lock); tout(cct) << "stat" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; r = _getattr(in, mask); if (r < 0) { ldout(cct, 3) << "stat exit on error!" << dendl; return r; } fill_stat(in, stbuf, dirstat); ldout(cct, 3) << "stat exit (relpath" << relpath << " mask " << mask << ")" << dendl; return r; } int Client::lstat(const char *relpath, struct stat *stbuf, frag_info_t *dirstat, int mask) { ldout(cct, 3) << "lstat enter (relpath" << relpath << " mask " << mask << ")" << dendl; Mutex::Locker lock(client_lock); tout(cct) << "lstat" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); Inode *in; // don't follow symlinks int r = path_walk(path, &in, false); if (r < 0) return r; r = _getattr(in, mask); if (r < 0) { ldout(cct, 3) << "lstat exit on error!" << dendl; return r; } fill_stat(in, stbuf, dirstat); ldout(cct, 3) << "lstat exit (relpath" << relpath << " mask " << mask << ")" << dendl; return r; } int Client::fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat, nest_info_t *rstat) { ldout(cct, 10) << "fill_stat on " << in->ino << " snap/dev" << in->snapid << " mode 0" << oct << in->mode << dec << " mtime " << in->mtime << " ctime " << in->ctime << dendl; memset(st, 0, sizeof(struct stat)); st->st_ino = in->ino; st->st_dev = in->snapid; st->st_mode = in->mode; st->st_rdev = in->rdev; st->st_nlink = in->nlink; st->st_uid = in->uid; st->st_gid = in->gid; if (in->ctime.sec() > in->mtime.sec()) { stat_set_ctime_sec(st, in->ctime.sec()); stat_set_ctime_nsec(st, in->ctime.nsec()); } else { stat_set_ctime_sec(st, in->mtime.sec()); stat_set_ctime_nsec(st, in->mtime.nsec()); } stat_set_atime_sec(st, in->atime.sec()); stat_set_atime_nsec(st, in->atime.nsec()); stat_set_mtime_sec(st, in->mtime.sec()); stat_set_mtime_nsec(st, in->mtime.nsec()); if (in->is_dir()) { //st->st_size = in->dirstat.size(); st->st_size = in->rstat.rbytes; st->st_blocks = 1; } else { st->st_size = in->size; st->st_blocks = (in->size + 511) >> 9; } st->st_blksize = MAX(in->layout.fl_stripe_unit, 4096); if (dirstat) *dirstat = in->dirstat; if (rstat) *rstat = in->rstat; return in->caps_issued(); } void Client::touch_dn(Dentry *dn) { lru.lru_touch(dn); } int Client::chmod(const char *relpath, mode_t mode) { Mutex::Locker lock(client_lock); tout(cct) << "chmod" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << mode << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; struct stat attr; attr.st_mode = mode; return _setattr(in, &attr, CEPH_SETATTR_MODE); } int Client::fchmod(int fd, mode_t mode) { Mutex::Locker lock(client_lock); tout(cct) << "fchmod" << std::endl; tout(cct) << fd << std::endl; tout(cct) << mode << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; struct stat attr; attr.st_mode = mode; return _setattr(f->inode, &attr, CEPH_SETATTR_MODE); } int Client::lchmod(const char *relpath, mode_t mode) { Mutex::Locker lock(client_lock); tout(cct) << "lchmod" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << mode << std::endl; filepath path(relpath); Inode *in; // don't follow symlinks int r = path_walk(path, &in, false); if (r < 0) return r; struct stat attr; attr.st_mode = mode; return _setattr(in, &attr, CEPH_SETATTR_MODE); } int Client::chown(const char *relpath, int uid, int gid) { Mutex::Locker lock(client_lock); tout(cct) << "chown" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << uid << std::endl; tout(cct) << gid << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; struct stat attr; attr.st_uid = uid; attr.st_gid = gid; int mask = 0; if (uid != -1) mask |= CEPH_SETATTR_UID; if (gid != -1) mask |= CEPH_SETATTR_GID; return _setattr(in, &attr, mask); } int Client::fchown(int fd, int uid, int gid) { Mutex::Locker lock(client_lock); tout(cct) << "fchown" << std::endl; tout(cct) << fd << std::endl; tout(cct) << uid << std::endl; tout(cct) << gid << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; struct stat attr; attr.st_uid = uid; attr.st_gid = gid; int mask = 0; if (uid != -1) mask |= CEPH_SETATTR_UID; if (gid != -1) mask |= CEPH_SETATTR_GID; return _setattr(f->inode, &attr, mask); } int Client::lchown(const char *relpath, int uid, int gid) { Mutex::Locker lock(client_lock); tout(cct) << "lchown" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << uid << std::endl; tout(cct) << gid << std::endl; filepath path(relpath); Inode *in; // don't follow symlinks int r = path_walk(path, &in, false); if (r < 0) return r; struct stat attr; attr.st_uid = uid; attr.st_gid = gid; int mask = 0; if (uid != -1) mask |= CEPH_SETATTR_UID; if (gid != -1) mask |= CEPH_SETATTR_GID; return _setattr(in, &attr, mask); } int Client::utime(const char *relpath, struct utimbuf *buf) { Mutex::Locker lock(client_lock); tout(cct) << "utime" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << buf->modtime << std::endl; tout(cct) << buf->actime << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; struct stat attr; stat_set_mtime_sec(&attr, buf->modtime); stat_set_mtime_nsec(&attr, 0); stat_set_atime_sec(&attr, buf->actime); stat_set_atime_nsec(&attr, 0); return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME); } int Client::lutime(const char *relpath, struct utimbuf *buf) { Mutex::Locker lock(client_lock); tout(cct) << "lutime" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << buf->modtime << std::endl; tout(cct) << buf->actime << std::endl; filepath path(relpath); Inode *in; // don't follow symlinks int r = path_walk(path, &in, false); if (r < 0) return r; struct stat attr; stat_set_mtime_sec(&attr, buf->modtime); stat_set_mtime_nsec(&attr, 0); stat_set_atime_sec(&attr, buf->actime); stat_set_atime_nsec(&attr, 0); return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME); } int Client::opendir(const char *relpath, dir_result_t **dirpp) { Mutex::Locker lock(client_lock); tout(cct) << "opendir" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; r = _opendir(in, dirpp); tout(cct) << (unsigned long)*dirpp << std::endl; return r; } int Client::_opendir(Inode *in, dir_result_t **dirpp, int uid, int gid) { if (!in->is_dir()) return -ENOTDIR; *dirpp = new dir_result_t(in); (*dirpp)->set_frag(in->dirfragtree[0]); if (in->dir) (*dirpp)->release_count = in->dir->release_count; (*dirpp)->start_shared_gen = in->shared_gen; ldout(cct, 10) << "_opendir " << in->ino << ", our cache says the first dirfrag is " << (*dirpp)->frag() << dendl; ldout(cct, 3) << "_opendir(" << in->ino << ") = " << 0 << " (" << *dirpp << ")" << dendl; return 0; } int Client::closedir(dir_result_t *dir) { Mutex::Locker lock(client_lock); tout(cct) << "closedir" << std::endl; tout(cct) << (unsigned long)dir << std::endl; ldout(cct, 3) << "closedir(" << dir << ") = 0" << dendl; _closedir(dir); return 0; } void Client::_closedir(dir_result_t *dirp) { ldout(cct, 10) << "_closedir(" << dirp << ")" << dendl; if (dirp->inode) { ldout(cct, 10) << "_closedir detaching inode " << dirp->inode << dendl; put_inode(dirp->inode); dirp->inode = 0; } _readdir_drop_dirp_buffer(dirp); delete dirp; } void Client::rewinddir(dir_result_t *dirp) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "rewinddir(" << dirp << ")" << dendl; dir_result_t *d = static_cast(dirp); _readdir_drop_dirp_buffer(d); d->reset(); } loff_t Client::telldir(dir_result_t *dirp) { dir_result_t *d = static_cast(dirp); ldout(cct, 3) << "telldir(" << dirp << ") = " << d->offset << dendl; return d->offset; } void Client::seekdir(dir_result_t *dirp, loff_t offset) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "seekdir(" << dirp << ", " << offset << ")" << dendl; dir_result_t *d = static_cast(dirp); if (offset == 0 || dir_result_t::fpos_frag(offset) != d->frag() || dir_result_t::fpos_off(offset) < d->fragpos()) { _readdir_drop_dirp_buffer(d); d->reset(); } if (offset > d->offset) d->release_count--; // bump if we do a forward seek d->offset = offset; if (!d->frag().is_leftmost() && d->next_offset == 2) d->next_offset = 0; // not 2 on non-leftmost frags! } //struct dirent { // ino_t d_ino; /* inode number */ // off_t d_off; /* offset to the next dirent */ // unsigned short d_reclen; /* length of this record */ // unsigned char d_type; /* type of file */ // char d_name[256]; /* filename */ //}; void Client::fill_dirent(struct dirent *de, const char *name, int type, uint64_t ino, loff_t next_off) { strncpy(de->d_name, name, 255); de->d_name[255] = '\0'; #ifndef __CYGWIN__ de->d_ino = ino; #if !defined(DARWIN) && !defined(__FreeBSD__) de->d_off = next_off; #endif de->d_reclen = 1; de->d_type = IFTODT(type); ldout(cct, 10) << "fill_dirent '" << de->d_name << "' -> " << inodeno_t(de->d_ino) << " type " << (int)de->d_type << " w/ next_off " << hex << next_off << dec << dendl; #endif } void Client::_readdir_next_frag(dir_result_t *dirp) { frag_t fg = dirp->frag(); // advance dirp->next_frag(); if (dirp->at_end()) { ldout(cct, 10) << "_readdir_next_frag advance from " << fg << " to END" << dendl; } else { ldout(cct, 10) << "_readdir_next_frag advance from " << fg << " to " << dirp->frag() << dendl; _readdir_rechoose_frag(dirp); } } void Client::_readdir_rechoose_frag(dir_result_t *dirp) { assert(dirp->inode); frag_t cur = dirp->frag(); frag_t f = dirp->inode->dirfragtree[cur.value()]; if (f != cur) { ldout(cct, 10) << "_readdir_rechoose_frag frag " << cur << " maps to " << f << dendl; dirp->set_frag(f); } } void Client::_readdir_drop_dirp_buffer(dir_result_t *dirp) { ldout(cct, 10) << "_readdir_drop_dirp_buffer " << dirp << dendl; if (dirp->buffer) { for (unsigned i = 0; i < dirp->buffer->size(); i++) put_inode((*dirp->buffer)[i].second); delete dirp->buffer; dirp->buffer = NULL; } } int Client::_readdir_get_frag(dir_result_t *dirp) { assert(dirp); assert(dirp->inode); // get the current frag. frag_t fg = dirp->frag(); ldout(cct, 10) << "_readdir_get_frag " << dirp << " on " << dirp->inode->ino << " fg " << fg << " next_offset " << dirp->next_offset << dendl; int op = CEPH_MDS_OP_READDIR; if (dirp->inode && dirp->inode->snapid == CEPH_SNAPDIR) op = CEPH_MDS_OP_LSSNAP; Inode *diri = dirp->inode; MetaRequest *req = new MetaRequest(op); filepath path; diri->make_nosnap_relative_path(path); req->set_filepath(path); req->set_inode(diri); req->head.args.readdir.frag = fg; if (dirp->last_name.length()) { req->path2.set_path(dirp->last_name.c_str()); req->readdir_start = dirp->last_name; } req->readdir_offset = dirp->next_offset; req->readdir_frag = fg; bufferlist dirbl; int res = make_request(req, -1, -1, NULL, NULL, -1, &dirbl); if (res == -EAGAIN) { ldout(cct, 10) << "_readdir_get_frag got EAGAIN, retrying" << dendl; _readdir_rechoose_frag(dirp); return _readdir_get_frag(dirp); } if (res == 0) { // stuff dir contents to cache, dir_result_t assert(diri); _readdir_drop_dirp_buffer(dirp); dirp->buffer = new vector >; dirp->buffer->swap(req->readdir_result); if (fg != req->readdir_reply_frag) { fg = req->readdir_reply_frag; if (fg.is_leftmost()) dirp->next_offset = 2; else dirp->next_offset = 0; dirp->offset = dir_result_t::make_fpos(fg, dirp->next_offset); } dirp->buffer_frag = fg; dirp->this_offset = dirp->next_offset; ldout(cct, 10) << "_readdir_get_frag " << dirp << " got frag " << dirp->buffer_frag << " this_offset " << dirp->this_offset << " size " << dirp->buffer->size() << dendl; if (req->readdir_end) { dirp->last_name.clear(); if (fg.is_rightmost()) dirp->next_offset = 2; else dirp->next_offset = 0; } else { dirp->last_name = req->readdir_last_name; dirp->next_offset += req->readdir_num; } } else { ldout(cct, 10) << "_readdir_get_frag got error " << res << ", setting end flag" << dendl; dirp->set_end(); } return res; } int Client::_readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p) { assert(client_lock.is_locked()); ldout(cct, 10) << "_readdir_cache_cb " << dirp << " on " << dirp->inode->ino << " at_cache_name " << dirp->at_cache_name << " offset " << hex << dirp->offset << dec << dendl; Dir *dir = dirp->inode->dir; if (!dir) { ldout(cct, 10) << " dir is empty" << dendl; dirp->set_end(); return 0; } map::iterator pd; if (dirp->at_cache_name.length()) { pd = dir->dentry_map.find(dirp->at_cache_name); if (pd == dir->dentry_map.end()) return -EAGAIN; // weird, i give up ++pd; } else { pd = dir->dentry_map.begin(); } string prev_name; while (pd != dir->dentry_map.end()) { Dentry *dn = pd->second; if (dn->inode == NULL) { ldout(cct, 15) << " skipping null '" << pd->first << "'" << dendl; ++pd; continue; } struct stat st; struct dirent de; int stmask = fill_stat(dn->inode, &st); fill_dirent(&de, pd->first.c_str(), st.st_mode, st.st_ino, dirp->offset + 1); uint64_t next_off = dn->offset + 1; ++pd; if (pd == dir->dentry_map.end()) next_off = dir_result_t::END; client_lock.Unlock(); int r = cb(p, &de, &st, stmask, next_off); // _next_ offset client_lock.Lock(); ldout(cct, 15) << " de " << de.d_name << " off " << hex << dn->offset << dec << " = " << r << dendl; if (r < 0) { dirp->next_offset = dn->offset; dirp->at_cache_name = prev_name; return r; } prev_name = dn->name; dirp->offset = next_off; if (r > 0) return r; } ldout(cct, 10) << "_readdir_cache_cb " << dirp << " on " << dirp->inode->ino << " at end" << dendl; dirp->set_end(); return 0; } int Client::readdir_r_cb(dir_result_t *d, add_dirent_cb_t cb, void *p) { Mutex::Locker lock(client_lock); dir_result_t *dirp = static_cast(d); ldout(cct, 10) << "readdir_r_cb " << *dirp->inode << " offset " << hex << dirp->offset << dec << " frag " << dirp->frag() << " fragpos " << hex << dirp->fragpos() << dec << " at_end=" << dirp->at_end() << dendl; struct dirent de; struct stat st; memset(&de, 0, sizeof(de)); memset(&st, 0, sizeof(st)); frag_t fg = dirp->frag(); uint32_t off = dirp->fragpos(); Inode *diri = dirp->inode; if (dirp->at_end()) return 0; if (dirp->offset == 0) { ldout(cct, 15) << " including ." << dendl; assert(diri->dn_set.size() < 2); // can't have multiple hard-links to a dir uint64_t next_off = 1; fill_dirent(&de, ".", S_IFDIR, diri->ino, next_off); fill_stat(diri, &st); client_lock.Unlock(); int r = cb(p, &de, &st, -1, next_off); client_lock.Lock(); if (r < 0) return r; dirp->offset = next_off; off = next_off; if (r > 0) return r; } if (dirp->offset == 1) { ldout(cct, 15) << " including .." << dendl; if (!diri->dn_set.empty()) { Inode* in = diri->get_first_parent()->inode; fill_dirent(&de, "..", S_IFDIR, in->ino, 2); fill_stat(in, &st); } else { /* must be at the root (no parent), * so we add the dotdot with a special inode (3) */ fill_dirent(&de, "..", S_IFDIR, CEPH_INO_DOTDOT, 2); } client_lock.Unlock(); int r = cb(p, &de, &st, -1, 2); client_lock.Lock(); if (r < 0) return r; dirp->offset = 2; off = 2; if (r > 0) return r; } // can we read from our cache? ldout(cct, 10) << "offset " << hex << dirp->offset << dec << " at_cache_name " << dirp->at_cache_name << " snapid " << dirp->inode->snapid << " complete " << (bool)(dirp->inode->flags & I_COMPLETE) << " issued " << ccap_string(dirp->inode->caps_issued()) << dendl; if ((dirp->offset == 2 || dirp->at_cache_name.length()) && dirp->inode->snapid != CEPH_SNAPDIR && (dirp->inode->flags & I_COMPLETE) && dirp->inode->caps_issued_mask(CEPH_CAP_FILE_SHARED)) { int err = _readdir_cache_cb(dirp, cb, p); if (err != -EAGAIN) return err; } if (dirp->at_cache_name.length()) { dirp->last_name = dirp->at_cache_name; dirp->at_cache_name.clear(); } while (1) { if (dirp->at_end()) return 0; if (dirp->buffer_frag != dirp->frag() || dirp->buffer == NULL) { int r = _readdir_get_frag(dirp); if (r) return r; // _readdir_get_frag () may updates dirp->offset if the replied dirfrag is // different than the requested one. (our dirfragtree was outdated) fg = dirp->buffer_frag; off = dirp->fragpos(); } ldout(cct, 10) << "off " << off << " this_offset " << hex << dirp->this_offset << dec << " size " << dirp->buffer->size() << " frag " << fg << dendl; dirp->offset = dir_result_t::make_fpos(fg, off); while (off >= dirp->this_offset && off - dirp->this_offset < dirp->buffer->size()) { pair& ent = (*dirp->buffer)[off - dirp->this_offset]; int stmask = fill_stat(ent.second, &st); fill_dirent(&de, ent.first.c_str(), st.st_mode, st.st_ino, dirp->offset + 1); client_lock.Unlock(); int r = cb(p, &de, &st, stmask, dirp->offset + 1); // _next_ offset client_lock.Lock(); ldout(cct, 15) << " de " << de.d_name << " off " << hex << dirp->offset << dec << " = " << r << dendl; if (r < 0) return r; off++; dirp->offset++; if (r > 0) return r; } if (dirp->last_name.length()) { ldout(cct, 10) << " fetching next chunk of this frag" << dendl; _readdir_drop_dirp_buffer(dirp); continue; // more! } if (!fg.is_rightmost()) { // next frag! _readdir_next_frag(dirp); ldout(cct, 10) << " advancing to next frag: " << fg << " -> " << dirp->frag() << dendl; fg = dirp->frag(); off = 0; continue; } if (diri->dir && diri->dir->release_count == dirp->release_count && diri->shared_gen == dirp->start_shared_gen) { ldout(cct, 10) << " marking I_COMPLETE on " << *diri << dendl; diri->flags |= I_COMPLETE; if (diri->dir) diri->dir->max_offset = dirp->offset; } dirp->set_end(); return 0; } assert(0); return 0; } int Client::readdir_r(dir_result_t *d, struct dirent *de) { return readdirplus_r(d, de, 0, 0); } /* * readdirplus_r * * returns * 1 if we got a dirent * 0 for end of directory * <0 on error */ struct single_readdir { struct dirent *de; struct stat *st; int *stmask; bool full; }; static int _readdir_single_dirent_cb(void *p, struct dirent *de, struct stat *st, int stmask, off_t off) { single_readdir *c = static_cast(p); if (c->full) return -1; // already filled this dirent *c->de = *de; if (c->st) *c->st = *st; if (c->stmask) *c->stmask = stmask; c->full = true; return 1; } struct dirent *Client::readdir(dir_result_t *d) { int ret; static int stmask; static struct dirent de; static struct stat st; single_readdir sr; sr.de = &de; sr.st = &st; sr.stmask = &stmask; sr.full = false; // our callback fills the dirent and sets sr.full=true on first // call, and returns -1 the second time around. ret = readdir_r_cb(d, _readdir_single_dirent_cb, (void *)&sr); if (ret < -1) { errno = -ret; // this sucks. return (dirent *) NULL; } if (sr.full) { return &de; } return (dirent *) NULL; } int Client::readdirplus_r(dir_result_t *d, struct dirent *de, struct stat *st, int *stmask) { single_readdir sr; sr.de = de; sr.st = st; sr.stmask = stmask; sr.full = false; // our callback fills the dirent and sets sr.full=true on first // call, and returns -1 the second time around. int r = readdir_r_cb(d, _readdir_single_dirent_cb, (void *)&sr); if (r < -1) return r; if (sr.full) return 1; return 0; } /* getdents */ struct getdents_result { char *buf; int buflen; int pos; bool fullent; }; static int _readdir_getdent_cb(void *p, struct dirent *de, struct stat *st, int stmask, off_t off) { struct getdents_result *c = static_cast(p); int dlen; if (c->fullent) dlen = sizeof(*de); else dlen = strlen(de->d_name) + 1; if (c->pos + dlen > c->buflen) return -1; // doesn't fit if (c->fullent) { memcpy(c->buf + c->pos, de, sizeof(*de)); } else { memcpy(c->buf + c->pos, de->d_name, dlen); } c->pos += dlen; return 0; } int Client::_getdents(dir_result_t *dir, char *buf, int buflen, bool fullent) { getdents_result gr; gr.buf = buf; gr.buflen = buflen; gr.fullent = fullent; gr.pos = 0; int r = readdir_r_cb(dir, _readdir_getdent_cb, (void *)&gr); if (r < 0) { // some error if (r == -1) { // buffer ran out of space if (gr.pos) { // but we got some entries already! return gr.pos; } // or we need a larger buffer return -ERANGE; } else { // actual error, return it return r; } } return gr.pos; } /* getdir */ struct getdir_result { list *contents; int num; }; static int _getdir_cb(void *p, struct dirent *de, struct stat *st, int stmask, off_t off) { getdir_result *r = static_cast(p); r->contents->push_back(de->d_name); r->num++; return 0; } int Client::getdir(const char *relpath, list& contents) { ldout(cct, 3) << "getdir(" << relpath << ")" << dendl; { Mutex::Locker lock(client_lock); tout(cct) << "getdir" << std::endl; tout(cct) << relpath << std::endl; } dir_result_t *d; int r = opendir(relpath, &d); if (r < 0) return r; getdir_result gr; gr.contents = &contents; gr.num = 0; r = readdir_r_cb(d, _getdir_cb, (void *)&gr); closedir(d); if (r < 0) return r; return gr.num; } /****** file i/o **********/ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool) { ldout(cct, 3) << "open enter(" << relpath << ", " << flags << "," << mode << ") = " << dendl; Mutex::Locker lock(client_lock); tout(cct) << "open" << std::endl; tout(cct) << relpath << std::endl; tout(cct) << flags << std::endl; Fh *fh = NULL; filepath path(relpath); Inode *in; bool created = false; int r = path_walk(path, &in); if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL)) return -EEXIST; if (r == -ENOENT && (flags & O_CREAT)) { filepath dirpath = path; string dname = dirpath.last_dentry(); dirpath.pop_dentry(); Inode *dir; r = path_walk(dirpath, &dir); if (r < 0) return r; r = _create(dir, dname.c_str(), flags, mode, &in, &fh, stripe_unit, stripe_count, object_size, data_pool, &created); } if (r < 0) goto out; if (!created) { // posix says we can only check permissions of existing files uid_t uid = geteuid(); gid_t gid = getegid(); r = check_permissions(in, flags, uid, gid); if (r < 0) goto out; } if (!fh) r = _open(in, flags, mode, &fh); if (r >= 0) { // allocate a integer file descriptor assert(fh); assert(in); r = get_fd(); assert(fd_map.count(r) == 0); fd_map[r] = fh; } out: tout(cct) << r << std::endl; ldout(cct, 3) << "open exit(" << path << ", " << flags << ") = " << r << dendl; return r; } int Client::open(const char *relpath, int flags, mode_t mode) { /* Use default file striping parameters */ return open(relpath, flags, mode, 0, 0, 0, NULL); } int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_hash enter(" << ino << ", #" << dirino << "/" << name << ") = " << dendl; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPHASH); filepath path(ino); req->set_filepath(path); uint32_t h = ceph_str_hash(CEPH_STR_HASH_RJENKINS, name, strlen(name)); char f[30]; sprintf(f, "%u", h); filepath path2(dirino); path2.push_dentry(string(f)); req->set_filepath2(path2); int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); ldout(cct, 3) << "lookup_hash exit(" << ino << ", #" << dirino << "/" << name << ") = " << r << dendl; return r; } /** * Load inode into local cache. * * If inode pointer is non-NULL, and take a reference on * the resulting Inode object in one operation, so that caller * can safely assume inode will still be there after return. */ int Client::lookup_ino(inodeno_t ino, Inode **inode) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_ino enter(" << ino << ") = " << dendl; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPINO); filepath path(ino); req->set_filepath(path); int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); if (r == 0 && inode != NULL) { vinodeno_t vino(ino, CEPH_NOSNAP); unordered_map::iterator p = inode_map.find(vino); assert(p != inode_map.end()); *inode = p->second; _ll_get(*inode); } ldout(cct, 3) << "lookup_ino exit(" << ino << ") = " << r << dendl; return r; } /** * Find the parent inode of `ino` and insert it into * our cache. Conditionally also set `parent` to a referenced * Inode* if caller provides non-NULL value. */ int Client::lookup_parent(Inode *ino, Inode **parent) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_parent enter(" << ino->ino << ") = " << dendl; if (!ino->dn_set.empty()) { ldout(cct, 3) << "lookup_parent dentry already present" << dendl; return 0; } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPPARENT); filepath path(ino->ino); req->set_filepath(path); req->set_inode(ino); int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); // Give caller a reference to the parent ino if they provided a pointer. if (parent != NULL) { if (r == 0) { *parent = req->target; _ll_get(*parent); ldout(cct, 3) << "lookup_parent found parent " << (*parent)->ino << dendl; } else { *parent = NULL; } } ldout(cct, 3) << "lookup_parent exit(" << ino->ino << ") = " << r << dendl; return r; } /** * Populate the parent dentry for `ino`, provided it is * a child of `parent`. */ int Client::lookup_name(Inode *ino, Inode *parent) { assert(parent->is_dir()); Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_name enter(" << ino->ino << ") = " << dendl; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPNAME); req->set_filepath2(filepath(parent->ino)); req->set_filepath(filepath(ino->ino)); req->set_inode(ino); int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); ldout(cct, 3) << "lookup_name exit(" << ino->ino << ") = " << r << dendl; return r; } Fh *Client::_create_fh(Inode *in, int flags, int cmode) { // yay Fh *f = new Fh; f->mode = cmode; f->flags = flags; // inode assert(in); f->inode = in; f->inode->get(); ldout(cct, 10) << "_create_fh " << in->ino << " mode " << cmode << dendl; if (in->snapid != CEPH_NOSNAP) { in->snap_cap_refs++; ldout(cct, 5) << "open success, fh is " << f << " combined IMMUTABLE SNAP caps " << ccap_string(in->caps_issued()) << dendl; } return f; } int Client::_release_fh(Fh *f) { //ldout(cct, 3) << "op: client->close(open_files[ " << fh << " ]);" << dendl; //ldout(cct, 3) << "op: open_files.erase( " << fh << " );" << dendl; Inode *in = f->inode; ldout(cct, 5) << "_release_fh " << f << " mode " << f->mode << " on " << *in << dendl; if (in->snapid == CEPH_NOSNAP) { if (in->put_open_ref(f->mode)) { _flush(in); // release clean pages too, if we dont want RDCACHE if (in->cap_refs[CEPH_CAP_FILE_CACHE] == 0 && !(in->caps_wanted() & CEPH_CAP_FILE_CACHE) && !objectcacher->set_is_empty(&in->oset)) _invalidate_inode_cache(in); else check_caps(in, false); } } else { assert(in->snap_cap_refs > 0); in->snap_cap_refs--; } _release_filelocks(f); put_inode(in); delete f; return 0; } int Client::_open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid) { int cmode = ceph_flags_to_mode(flags); if (cmode < 0) return -EINVAL; int want = ceph_caps_for_mode(cmode); int result = 0; if (in->snapid != CEPH_NOSNAP && (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC | O_APPEND))) { return -EROFS; } in->get_open_ref(cmode); // make note of pending open, since it effects _wanted_ caps. if ((flags & O_TRUNC) == 0 && in->caps_issued_mask(want)) { // update wanted? check_caps(in, true); } else { MetaRequest *req = new MetaRequest(CEPH_MDS_OP_OPEN); filepath path; in->make_nosnap_relative_path(path); req->set_filepath(path); req->head.args.open.flags = flags & ~O_CREAT; req->head.args.open.mode = mode; req->head.args.open.pool = -1; req->head.args.open.old_size = in->size; // for O_TRUNC req->set_inode(in); result = make_request(req, uid, gid); } // success? if (result >= 0) { if (fhp) *fhp = _create_fh(in, flags, cmode); } else { in->put_open_ref(cmode); } trim_cache(); return result; } int Client::close(int fd) { ldout(cct, 3) << "close enter(" << fd << ")" << dendl; Mutex::Locker lock(client_lock); tout(cct) << "close" << std::endl; tout(cct) << fd << std::endl; Fh *fh = get_filehandle(fd); if (!fh) return -EBADF; _release_fh(fh); fd_map.erase(fd); ldout(cct, 3) << "close exit(" << fd << ")" << dendl; return 0; } // ------------ // read, write loff_t Client::lseek(int fd, loff_t offset, int whence) { Mutex::Locker lock(client_lock); tout(cct) << "lseek" << std::endl; tout(cct) << fd << std::endl; tout(cct) << offset << std::endl; tout(cct) << whence << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; return _lseek(f, offset, whence); } loff_t Client::_lseek(Fh *f, loff_t offset, int whence) { Inode *in = f->inode; int r; switch (whence) { case SEEK_SET: f->pos = offset; break; case SEEK_CUR: f->pos += offset; break; case SEEK_END: r = _getattr(in, CEPH_STAT_CAP_SIZE); if (r < 0) return r; f->pos = in->size + offset; break; default: assert(0); } ldout(cct, 3) << "_lseek(" << f << ", " << offset << ", " << whence << ") = " << f->pos << dendl; return f->pos; } void Client::lock_fh_pos(Fh *f) { ldout(cct, 10) << "lock_fh_pos " << f << dendl; if (f->pos_locked || !f->pos_waiters.empty()) { Cond cond; f->pos_waiters.push_back(&cond); ldout(cct, 10) << "lock_fh_pos BLOCKING on " << f << dendl; while (f->pos_locked || f->pos_waiters.front() != &cond) cond.Wait(client_lock); ldout(cct, 10) << "lock_fh_pos UNBLOCKING on " << f << dendl; assert(f->pos_waiters.front() == &cond); f->pos_waiters.pop_front(); } f->pos_locked = true; } void Client::unlock_fh_pos(Fh *f) { ldout(cct, 10) << "unlock_fh_pos " << f << dendl; f->pos_locked = false; } int Client::uninline_data(Inode *in, Context *onfinish) { if (!in->inline_data.length()) { onfinish->complete(0); return 0; } char oid_buf[32]; snprintf(oid_buf, sizeof(oid_buf), "%llx.00000000", (long long unsigned)in->ino); object_t oid = oid_buf; ObjectOperation create_ops; create_ops.create(false); objecter->mutate(oid, OSDMap::file_to_object_locator(in->layout), create_ops, in->snaprealm->get_snap_context(), ceph_clock_now(cct), 0, NULL, NULL); bufferlist inline_version_bl; ::encode(in->inline_version, inline_version_bl); ObjectOperation uninline_ops; uninline_ops.cmpxattr("inline_version", CEPH_OSD_CMPXATTR_OP_GT, CEPH_OSD_CMPXATTR_MODE_U64, inline_version_bl); bufferlist inline_data = in->inline_data; uninline_ops.write(0, inline_data, in->truncate_size, in->truncate_seq); uninline_ops.setxattr("inline_version", inline_version_bl); objecter->mutate(oid, OSDMap::file_to_object_locator(in->layout), uninline_ops, in->snaprealm->get_snap_context(), ceph_clock_now(cct), 0, NULL, onfinish); return 0; } // // blocking osd interface int Client::read(int fd, char *buf, loff_t size, loff_t offset) { Mutex::Locker lock(client_lock); tout(cct) << "read" << std::endl; tout(cct) << fd << std::endl; tout(cct) << size << std::endl; tout(cct) << offset << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; bufferlist bl; int r = _read(f, offset, size, &bl); ldout(cct, 3) << "read(" << fd << ", " << (void*)buf << ", " << size << ", " << offset << ") = " << r << dendl; if (r >= 0) { bl.copy(0, bl.length(), buf); r = bl.length(); } return r; } int Client::_read(Fh *f, int64_t offset, uint64_t size, bufferlist *bl) { const md_config_t *conf = cct->_conf; Inode *in = f->inode; //bool lazy = f->mode == CEPH_FILE_MODE_LAZY; bool movepos = false; if (offset < 0) { lock_fh_pos(f); offset = f->pos; movepos = true; } loff_t start_pos = offset; if (in->inline_version == 0) { int r = _getattr(in, CEPH_STAT_CAP_INLINE_DATA, -1, -1, true); if (r < 0) return r; assert(in->inline_version > 0); } retry: int have; int r = get_caps(in, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE, &have, -1); if (r < 0) return r; Mutex uninline_flock("Clinet::_read_uninline_data flock"); Cond uninline_cond; bool uninline_done = false; int uninline_ret = 0; Context *onuninline = NULL; if (in->inline_version < CEPH_INLINE_NONE) { if (!(have & CEPH_CAP_FILE_CACHE)) { onuninline = new C_SafeCond(&uninline_flock, &uninline_cond, &uninline_done, &uninline_ret); uninline_data(in, onuninline); } else { uint32_t len = in->inline_data.length(); uint64_t endoff = offset + size; if (endoff > in->size) endoff = in->size; if (offset < len) { if (endoff <= len) { bl->substr_of(in->inline_data, offset, endoff - offset); } else { bl->substr_of(in->inline_data, offset, len - offset); bl->append_zero(endoff - len); } } else if ((uint64_t)offset < endoff) { bl->append_zero(endoff - offset); } goto success; } } if (!conf->client_debug_force_sync_read && (cct->_conf->client_oc && (have & CEPH_CAP_FILE_CACHE))) { if (f->flags & O_RSYNC) { _flush_range(in, offset, size); } r = _read_async(f, offset, size, bl); if (r < 0) goto done; } else { bool checkeof = false; r = _read_sync(f, offset, size, bl, &checkeof); if (r < 0) goto done; if (checkeof) { offset += r; size -= r; put_cap_ref(in, CEPH_CAP_FILE_RD); have = 0; // reverify size r = _getattr(in, CEPH_STAT_CAP_SIZE); if (r < 0) goto done; // eof? short read. if ((uint64_t)offset < in->size) goto retry; } } success: // adjust readahead state if (f->last_pos != start_pos) { f->nr_consec_read = f->consec_read_bytes = 0; } else { f->nr_consec_read++; } f->consec_read_bytes += bl->length(); ldout(cct, 10) << "readahead nr_consec_read " << f->nr_consec_read << " for " << f->consec_read_bytes << " bytes" << " .. last_pos " << f->last_pos << " .. offset " << start_pos << dendl; f->last_pos = start_pos + bl->length(); if (movepos) { // adjust fd pos f->pos = f->last_pos; unlock_fh_pos(f); } done: // done! if (onuninline) { client_lock.Unlock(); uninline_flock.Lock(); while (!uninline_done) uninline_cond.Wait(uninline_flock); uninline_flock.Unlock(); client_lock.Lock(); if (uninline_ret >= 0 || uninline_ret == -ECANCELED) { in->inline_data.clear(); in->inline_version = CEPH_INLINE_NONE; mark_caps_dirty(in, CEPH_CAP_FILE_WR); check_caps(in, false); } else r = uninline_ret; } if (have) put_cap_ref(in, CEPH_CAP_FILE_RD); return r < 0 ? r : bl->length(); } int Client::_read_async(Fh *f, uint64_t off, uint64_t len, bufferlist *bl) { const md_config_t *conf = cct->_conf; Inode *in = f->inode; bool readahead = true; ldout(cct, 10) << "_read_async " << *in << " " << off << "~" << len << dendl; // trim read based on file size? if (off >= in->size) return 0; if (off + len > in->size) { len = in->size - off; readahead = false; } ldout(cct, 10) << "readahead=" << readahead << " nr_consec=" << f->nr_consec_read << " max_byes=" << conf->client_readahead_max_bytes << " max_periods=" << conf->client_readahead_max_periods << dendl; // readahead? if (readahead && f->nr_consec_read && (conf->client_readahead_max_bytes || conf->client_readahead_max_periods)) { loff_t l = f->consec_read_bytes * 2; if (conf->client_readahead_min) l = MAX(l, conf->client_readahead_min); if (conf->client_readahead_max_bytes) l = MIN(l, conf->client_readahead_max_bytes); loff_t p = in->layout.fl_stripe_count * in->layout.fl_object_size; if (conf->client_readahead_max_periods) l = MIN(l, conf->client_readahead_max_periods * p); if (l >= 2*p) // align large readahead with period l -= (off+l) % p; else { // align readahead with stripe unit if we cross su boundary int su = in->layout.fl_stripe_unit; if ((off+l)/su != off/su) l -= (off+l) % su; } // don't read past end of file if (off+l > in->size) l = in->size - off; loff_t min = MIN((loff_t)len, l/2); ldout(cct, 20) << "readahead " << f->nr_consec_read << " reads " << f->consec_read_bytes << " bytes ... readahead " << off << "~" << l << " min " << min << " (caller wants " << off << "~" << len << ")" << dendl; if (l > (loff_t)len) { if (objectcacher->file_is_cached(&in->oset, &in->layout, in->snapid, off, min)) ldout(cct, 20) << "readahead already have min" << dendl; else { Context *onfinish = new C_Readahead(this, in); int r = objectcacher->file_read(&in->oset, &in->layout, in->snapid, off, l, NULL, 0, onfinish); if (r == 0) { ldout(cct, 20) << "readahead initiated, c " << onfinish << dendl; get_cap_ref(in, CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE); } else { ldout(cct, 20) << "readahead was no-op, already cached" << dendl; delete onfinish; } } } } // read (and possibly block) int r, rvalue = 0; Mutex flock("Client::_read_async flock"); Cond cond; bool done = false; Context *onfinish = new C_SafeCond(&flock, &cond, &done, &rvalue); r = objectcacher->file_read(&in->oset, &in->layout, in->snapid, off, len, bl, 0, onfinish); if (r == 0) { get_cap_ref(in, CEPH_CAP_FILE_CACHE); client_lock.Unlock(); flock.Lock(); while (!done) cond.Wait(flock); flock.Unlock(); client_lock.Lock(); put_cap_ref(in, CEPH_CAP_FILE_CACHE); r = rvalue; } else { // it was cached. delete onfinish; } return r; } int Client::_read_sync(Fh *f, uint64_t off, uint64_t len, bufferlist *bl, bool *checkeof) { Inode *in = f->inode; uint64_t pos = off; int left = len; int read = 0; ldout(cct, 10) << "_read_sync " << *in << " " << off << "~" << len << dendl; Mutex flock("Client::_read_sync flock"); Cond cond; while (left > 0) { int r = 0; bool done = false; Context *onfinish = new C_SafeCond(&flock, &cond, &done, &r); bufferlist tbl; int wanted = left; filer->read_trunc(in->ino, &in->layout, in->snapid, pos, left, &tbl, 0, in->truncate_size, in->truncate_seq, onfinish); client_lock.Unlock(); flock.Lock(); while (!done) cond.Wait(flock); flock.Unlock(); client_lock.Lock(); // if we get ENOENT from OSD, assume 0 bytes returned if (r == -ENOENT) r = 0; if (r < 0) return r; if (tbl.length()) { r = tbl.length(); read += r; pos += r; left -= r; bl->claim_append(tbl); } // short read? if (r >= 0 && r < wanted) { if (pos < in->size) { // zero up to known EOF int64_t some = in->size - pos; if (some > left) some = left; bufferptr z(some); z.zero(); bl->push_back(z); read += some; pos += some; left -= some; if (left == 0) return read; } *checkeof = true; return read; } } return read; } /* * we keep count of uncommitted sync writes on the inode, so that * fsync can DDRT. */ class C_Client_SyncCommit : public Context { Client *cl; Inode *in; public: C_Client_SyncCommit(Client *c, Inode *i) : cl(c), in(i) { in->get(); } void finish(int) { cl->sync_write_commit(in); } }; void Client::sync_write_commit(Inode *in) { assert(unsafe_sync_write > 0); unsafe_sync_write--; put_cap_ref(in, CEPH_CAP_FILE_BUFFER); ldout(cct, 15) << "sync_write_commit unsafe_sync_write = " << unsafe_sync_write << dendl; if (unsafe_sync_write == 0 && unmounting) { ldout(cct, 10) << "sync_write_comit -- no more unsafe writes, unmount can proceed" << dendl; mount_cond.Signal(); } put_inode(in); } int Client::write(int fd, const char *buf, loff_t size, loff_t offset) { Mutex::Locker lock(client_lock); tout(cct) << "write" << std::endl; tout(cct) << fd << std::endl; tout(cct) << size << std::endl; tout(cct) << offset << std::endl; Fh *fh = get_filehandle(fd); if (!fh) return -EBADF; int r = _write(fh, offset, size, buf); ldout(cct, 3) << "write(" << fd << ", \"...\", " << size << ", " << offset << ") = " << r << dendl; return r; } int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf) { if ((uint64_t)(offset+size) > mdsmap->get_max_filesize()) //too large! return -EFBIG; if (osdmap->test_flag(CEPH_OSDMAP_FULL)) return -ENOSPC; //ldout(cct, 7) << "write fh " << fh << " size " << size << " offset " << offset << dendl; Inode *in = f->inode; assert(in->snapid == CEPH_NOSNAP); // was Fh opened as writeable? if ((f->mode & CEPH_FILE_MODE_WR) == 0) return -EBADF; // use/adjust fd pos? if (offset < 0) { lock_fh_pos(f); /* * FIXME: this is racy in that we may block _after_ this point waiting for caps, and size may * change out from under us. */ if (f->flags & O_APPEND) _lseek(f, 0, SEEK_END); offset = f->pos; f->pos = offset+size; unlock_fh_pos(f); } //bool lazy = f->mode == CEPH_FILE_MODE_LAZY; ldout(cct, 10) << "cur file size is " << in->size << dendl; // time it. utime_t start = ceph_clock_now(cct); if (in->inline_version == 0) { int r = _getattr(in, CEPH_STAT_CAP_INLINE_DATA, -1, -1, true); if (r < 0) return r; assert(in->inline_version > 0); } // copy into fresh buffer (since our write may be resub, async) bufferptr bp; if (size > 0) bp = buffer::copy(buf, size); bufferlist bl; bl.push_back( bp ); utime_t lat; uint64_t totalwritten; uint64_t endoff = offset + size; int have; int r = get_caps(in, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER, &have, endoff); if (r < 0) return r; ldout(cct, 10) << " snaprealm " << *in->snaprealm << dendl; Mutex uninline_flock("Clinet::_write_uninline_data flock"); Cond uninline_cond; bool uninline_done = false; int uninline_ret = 0; Context *onuninline = NULL; if (in->inline_version < CEPH_INLINE_NONE) { if (endoff > cct->_conf->client_max_inline_size || endoff > CEPH_INLINE_MAX_SIZE || !(have & CEPH_CAP_FILE_BUFFER)) { onuninline = new C_SafeCond(&uninline_flock, &uninline_cond, &uninline_done, &uninline_ret); uninline_data(in, onuninline); } else { get_cap_ref(in, CEPH_CAP_FILE_BUFFER); uint32_t len = in->inline_data.length(); if (endoff < len) in->inline_data.copy(endoff, len - endoff, bl); if (offset < len) in->inline_data.splice(offset, len - offset); else if (offset > len) in->inline_data.append_zero(offset - len); in->inline_data.append(bl); in->inline_version++; put_cap_ref(in, CEPH_CAP_FILE_BUFFER); goto success; } } if (cct->_conf->client_oc && (have & CEPH_CAP_FILE_BUFFER)) { // do buffered write if (!in->oset.dirty_or_tx) get_cap_ref(in, CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_BUFFER); get_cap_ref(in, CEPH_CAP_FILE_BUFFER); // async, caching, non-blocking. r = objectcacher->file_write(&in->oset, &in->layout, in->snaprealm->get_snap_context(), offset, size, bl, ceph_clock_now(cct), 0, client_lock); put_cap_ref(in, CEPH_CAP_FILE_BUFFER); if (r < 0) goto done; // flush cached write if O_SYNC is set on file fh // O_DSYNC == O_SYNC on linux < 2.6.33 // O_SYNC = __O_SYNC | O_DSYNC on linux >= 2.6.33 if ((f->flags & O_SYNC) || (f->flags & O_DSYNC)) { _flush_range(in, offset, size); } } else { // simple, non-atomic sync write Mutex flock("Client::_write flock"); Cond cond; bool done = false; Context *onfinish = new C_SafeCond(&flock, &cond, &done); Context *onsafe = new C_Client_SyncCommit(this, in); unsafe_sync_write++; get_cap_ref(in, CEPH_CAP_FILE_BUFFER); // released by onsafe callback r = filer->write_trunc(in->ino, &in->layout, in->snaprealm->get_snap_context(), offset, size, bl, ceph_clock_now(cct), 0, in->truncate_size, in->truncate_seq, onfinish, onsafe); if (r < 0) goto done; client_lock.Unlock(); flock.Lock(); while (!done) cond.Wait(flock); flock.Unlock(); client_lock.Lock(); } // if we get here, write was successful, update client metadata success: // time lat = ceph_clock_now(cct); lat -= start; logger->tinc(l_c_wrlat, lat); totalwritten = size; r = (int)totalwritten; // extend file? if (totalwritten + offset > in->size) { in->size = totalwritten + offset; mark_caps_dirty(in, CEPH_CAP_FILE_WR); if ((in->size << 1) >= in->max_size && (in->reported_size << 1) < in->max_size) check_caps(in, false); ldout(cct, 7) << "wrote to " << totalwritten+offset << ", extending file size" << dendl; } else { ldout(cct, 7) << "wrote to " << totalwritten+offset << ", leaving file size at " << in->size << dendl; } // mtime in->mtime = ceph_clock_now(cct); mark_caps_dirty(in, CEPH_CAP_FILE_WR); done: if (onuninline) { client_lock.Unlock(); uninline_flock.Lock(); while (!uninline_done) uninline_cond.Wait(uninline_flock); uninline_flock.Unlock(); client_lock.Lock(); if (uninline_ret >= 0 || uninline_ret == -ECANCELED) { in->inline_data.clear(); in->inline_version = CEPH_INLINE_NONE; mark_caps_dirty(in, CEPH_CAP_FILE_WR); check_caps(in, false); } else r = uninline_ret; } put_cap_ref(in, CEPH_CAP_FILE_WR); return r; } int Client::_flush(Fh *f) { // no-op, for now. hrm. return 0; } int Client::truncate(const char *relpath, loff_t length) { struct stat attr; attr.st_size = length; return setattr(relpath, &attr, CEPH_SETATTR_SIZE); } int Client::ftruncate(int fd, loff_t length) { Mutex::Locker lock(client_lock); tout(cct) << "ftruncate" << std::endl; tout(cct) << fd << std::endl; tout(cct) << length << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; struct stat attr; attr.st_size = length; return _setattr(f->inode, &attr, CEPH_SETATTR_SIZE); } int Client::fsync(int fd, bool syncdataonly) { Mutex::Locker lock(client_lock); tout(cct) << "fsync" << std::endl; tout(cct) << fd << std::endl; tout(cct) << syncdataonly << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; int r = _fsync(f, syncdataonly); ldout(cct, 3) << "fsync(" << fd << ", " << syncdataonly << ") = " << r << dendl; return r; } int Client::_fsync(Fh *f, bool syncdataonly) { int r = 0; Inode *in = f->inode; ceph_tid_t wait_on_flush = 0; bool flushed_metadata = false; Mutex lock("Client::_fsync::lock"); Cond cond; bool done = false; C_SafeCond *object_cacher_completion = NULL; ldout(cct, 3) << "_fsync(" << f << ", " << (syncdataonly ? "dataonly)":"data+metadata)") << dendl; if (cct->_conf->client_oc) { object_cacher_completion = new C_SafeCond(&lock, &cond, &done, &r); in->get(); // take a reference; C_SafeCond doesn't and _flush won't either _flush(in, object_cacher_completion); ldout(cct, 15) << "using return-valued form of _fsync" << dendl; } if (!syncdataonly && (in->dirty_caps & ~CEPH_CAP_ANY_FILE_WR)) { for (map::iterator iter = in->caps.begin(); iter != in->caps.end(); ++iter) { if (iter->second->implemented & ~CEPH_CAP_ANY_FILE_WR) { MetaSession *session = mds_sessions[iter->first]; assert(session); flush_caps(in, session); } } wait_on_flush = in->last_flush_tid; flushed_metadata = true; } else ldout(cct, 10) << "no metadata needs to commit" << dendl; if (object_cacher_completion) { // wait on a real reply instead of guessing client_lock.Unlock(); lock.Lock(); ldout(cct, 15) << "waiting on data to flush" << dendl; while (!done) cond.Wait(lock); lock.Unlock(); client_lock.Lock(); put_inode(in); ldout(cct, 15) << "got " << r << " from flush writeback" << dendl; } else { // FIXME: this can starve while (in->cap_refs[CEPH_CAP_FILE_BUFFER] > 0) { ldout(cct, 10) << "ino " << in->ino << " has " << in->cap_refs[CEPH_CAP_FILE_BUFFER] << " uncommitted, waiting" << dendl; wait_on_list(in->waitfor_commit); } } if (!r) { if (flushed_metadata) wait_sync_caps(wait_on_flush); // this could wait longer than strictly necessary, // but on a sync the user can put up with it ldout(cct, 10) << "ino " << in->ino << " has no uncommitted writes" << dendl; } else { ldout(cct, 1) << "ino " << in->ino << " failed to commit to disk! " << cpp_strerror(-r) << dendl; } return r; } int Client::fstat(int fd, struct stat *stbuf) { Mutex::Locker lock(client_lock); tout(cct) << "fstat" << std::endl; tout(cct) << fd << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; int r = _getattr(f->inode, -1); if (r < 0) return r; fill_stat(f->inode, stbuf, NULL); ldout(cct, 3) << "fstat(" << fd << ", " << stbuf << ") = " << r << dendl; return r; } // not written yet, but i want to link! int Client::chdir(const char *relpath) { Mutex::Locker lock(client_lock); tout(cct) << "chdir" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; if (cwd != in) { in->get(); put_inode(cwd); cwd = in; } ldout(cct, 3) << "chdir(" << relpath << ") cwd now " << cwd->ino << dendl; return 0; } void Client::getcwd(string& dir) { filepath path; ldout(cct, 10) << "getcwd " << *cwd << dendl; Inode *in = cwd; while (in != root) { assert(in->dn_set.size() < 2); // dirs can't be hard-linked Dentry *dn = in->get_first_parent(); if (!dn) { // look it up ldout(cct, 10) << "getcwd looking up parent for " << *in << dendl; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPNAME); filepath path(in->ino); req->set_filepath(path); req->set_inode(in); int res = make_request(req, -1, -1); if (res < 0) break; // start over path = filepath(); in = cwd; continue; } path.push_front_dentry(dn->name); in = dn->dir->parent_inode; } dir = "/"; dir += path.get_path(); } int Client::statfs(const char *path, struct statvfs *stbuf) { Mutex::Locker l(client_lock); tout(cct) << "statfs" << std::endl; ceph_statfs stats; Mutex lock("Client::statfs::lock"); Cond cond; bool done; int rval; objecter->get_fs_stats(stats, new C_SafeCond(&lock, &cond, &done, &rval)); client_lock.Unlock(); lock.Lock(); while (!done) cond.Wait(lock); lock.Unlock(); client_lock.Lock(); memset(stbuf, 0, sizeof(*stbuf)); /* * we're going to set a block size of 4MB so we can represent larger * FSes without overflowing. Additionally convert the space * measurements from KB to bytes while making them in terms of * blocks. We use 4MB only because it is big enough, and because it * actually *is* the (ceph) default block size. */ const int CEPH_BLOCK_SHIFT = 22; stbuf->f_frsize = 1 << CEPH_BLOCK_SHIFT; stbuf->f_bsize = 1 << CEPH_BLOCK_SHIFT; stbuf->f_blocks = stats.kb >> (CEPH_BLOCK_SHIFT - 10); stbuf->f_bfree = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10); stbuf->f_bavail = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10); stbuf->f_files = stats.num_objects; stbuf->f_ffree = -1; stbuf->f_favail = -1; stbuf->f_fsid = -1; // ?? stbuf->f_flag = 0; // ?? stbuf->f_namemax = NAME_MAX; return rval; } int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, struct flock *fl, uint64_t owner, void *fuse_req) { ldout(cct, 10) << "_do_filelock ino " << in->ino << (lock_type == CEPH_LOCK_FCNTL ? " fcntl" : " flock") << " type " << fl->l_type << " owner " << owner << " " << fl->l_start << "~" << fl->l_len << dendl; int lock_cmd; if (F_RDLCK == fl->l_type) lock_cmd = CEPH_LOCK_SHARED; else if (F_WRLCK == fl->l_type) lock_cmd = CEPH_LOCK_EXCL; else if (F_UNLCK == fl->l_type) lock_cmd = CEPH_LOCK_UNLOCK; else return -EIO; if (op != CEPH_MDS_OP_SETFILELOCK || lock_cmd == CEPH_LOCK_UNLOCK) sleep = 0; /* * Set the most significant bit, so that MDS knows the 'owner' * is sufficient to identify the owner of lock. (old code uses * both 'owner' and 'pid') */ owner |= (1ULL << 63); MetaRequest *req = new MetaRequest(op); filepath path; in->make_nosnap_relative_path(path); req->set_filepath(path); req->set_inode(in); req->head.args.filelock_change.rule = lock_type; req->head.args.filelock_change.type = lock_cmd; req->head.args.filelock_change.owner = owner; req->head.args.filelock_change.pid = fl->l_pid; req->head.args.filelock_change.start = fl->l_start; req->head.args.filelock_change.length = fl->l_len; req->head.args.filelock_change.wait = sleep; int ret; bufferlist bl; if (sleep && switch_interrupt_cb && fuse_req) { // enable interrupt switch_interrupt_cb(fuse_req, req->get()); ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); // disable interrupt switch_interrupt_cb(fuse_req, NULL); put_request(req); } else { ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); } if (ret == 0) { if (op == CEPH_MDS_OP_GETFILELOCK) { ceph_filelock filelock; bufferlist::iterator p = bl.begin(); ::decode(filelock, p); if (CEPH_LOCK_SHARED == filelock.type) fl->l_type = F_RDLCK; else if (CEPH_LOCK_EXCL == filelock.type) fl->l_type = F_WRLCK; else fl->l_type = F_UNLCK; fl->l_whence = SEEK_SET; fl->l_start = filelock.start; fl->l_len = filelock.length; fl->l_pid = filelock.pid; } else if (op == CEPH_MDS_OP_SETFILELOCK) { ceph_lock_state_t *lock_state; if (lock_type == CEPH_LOCK_FCNTL) { if (!in->fcntl_locks) in->fcntl_locks = new ceph_lock_state_t(cct); lock_state = in->fcntl_locks; } else if (lock_type == CEPH_LOCK_FLOCK) { if (!in->flock_locks) in->flock_locks = new ceph_lock_state_t(cct); lock_state = in->flock_locks; } else assert(0); _update_lock_state(fl, owner, lock_state); if (fh) { if (lock_type == CEPH_LOCK_FCNTL) { if (!fh->fcntl_locks) fh->fcntl_locks = new ceph_lock_state_t(cct); lock_state = fh->fcntl_locks; } else { if (!fh->flock_locks) fh->flock_locks = new ceph_lock_state_t(cct); lock_state = fh->flock_locks; } _update_lock_state(fl, owner, lock_state); } } else assert(0); } return ret; } int Client::_interrupt_filelock(MetaRequest *req) { Inode *in = req->inode(); int lock_type; if (req->head.args.filelock_change.rule == CEPH_LOCK_FLOCK) lock_type = CEPH_LOCK_FLOCK_INTR; else if (req->head.args.filelock_change.rule == CEPH_LOCK_FCNTL) lock_type = CEPH_LOCK_FCNTL_INTR; else assert(0); MetaRequest *intr_req = new MetaRequest(CEPH_MDS_OP_SETFILELOCK); filepath path; in->make_nosnap_relative_path(path); intr_req->set_filepath(path); intr_req->set_inode(in); intr_req->head.args.filelock_change = req->head.args.filelock_change; intr_req->head.args.filelock_change.rule = lock_type; intr_req->head.args.filelock_change.type = CEPH_LOCK_UNLOCK; return make_request(intr_req, -1, -1, NULL, NULL, -1); } void Client::_encode_filelocks(Inode *in, bufferlist& bl) { if (!in->fcntl_locks && !in->flock_locks) return; unsigned nr_fcntl_locks = in->fcntl_locks ? in->fcntl_locks->held_locks.size() : 0; ::encode(nr_fcntl_locks, bl); if (nr_fcntl_locks) { ceph_lock_state_t* lock_state = in->fcntl_locks; for(multimap::iterator p = lock_state->held_locks.begin(); p != lock_state->held_locks.end(); ++p) ::encode(p->second, bl); } unsigned nr_flock_locks = in->flock_locks ? in->flock_locks->held_locks.size() : 0; ::encode(nr_flock_locks, bl); if (nr_flock_locks) { ceph_lock_state_t* lock_state = in->flock_locks; for(multimap::iterator p = lock_state->held_locks.begin(); p != lock_state->held_locks.end(); ++p) ::encode(p->second, bl); } ldout(cct, 10) << "_encode_filelocks ino " << in->ino << ", " << nr_fcntl_locks << " fcntl locks, " << nr_flock_locks << " flock locks" << dendl; } void Client::_release_filelocks(Fh *fh) { if (!fh->fcntl_locks && !fh->flock_locks) return; Inode *in = fh->inode; ldout(cct, 10) << "_release_filelocks " << fh << " ino " << in->ino << dendl; list > to_release; if (fh->fcntl_locks) { ceph_lock_state_t* lock_state = fh->fcntl_locks; for(multimap::iterator p = lock_state->held_locks.begin(); p != lock_state->held_locks.end(); ++p) to_release.push_back(pair(CEPH_LOCK_FCNTL, p->second)); delete fh->fcntl_locks; } if (fh->flock_locks) { ceph_lock_state_t* lock_state = fh->flock_locks; for(multimap::iterator p = lock_state->held_locks.begin(); p != lock_state->held_locks.end(); ++p) to_release.push_back(pair(CEPH_LOCK_FLOCK, p->second)); delete fh->flock_locks; } if (to_release.empty()) return; struct flock fl; memset(&fl, 0, sizeof(fl)); fl.l_whence = SEEK_SET; fl.l_type = F_UNLCK; for (list >::iterator p = to_release.begin(); p != to_release.end(); ++p) { fl.l_start = p->second.start; fl.l_len = p->second.length; fl.l_pid = p->second.pid; _do_filelock(in, NULL, p->first, CEPH_MDS_OP_SETFILELOCK, 0, &fl, p->second.owner); } } void Client::_update_lock_state(struct flock *fl, uint64_t owner, ceph_lock_state_t *lock_state) { int lock_cmd; if (F_RDLCK == fl->l_type) lock_cmd = CEPH_LOCK_SHARED; else if (F_WRLCK == fl->l_type) lock_cmd = CEPH_LOCK_EXCL; else lock_cmd = CEPH_LOCK_UNLOCK;; ceph_filelock filelock; filelock.start = fl->l_start; filelock.length = fl->l_len; filelock.client = 0; // see comment in _do_filelock() filelock.owner = owner | (1ULL << 63); filelock.pid = fl->l_pid; filelock.type = lock_cmd; if (filelock.type == CEPH_LOCK_UNLOCK) { list activated_locks; lock_state->remove_lock(filelock, activated_locks); } else { bool r = lock_state->add_lock(filelock, false, false); assert(r); } } int Client::_getlk(Fh *fh, struct flock *fl, uint64_t owner) { Inode *in = fh->inode; ldout(cct, 10) << "_getlk " << fh << " ino " << in->ino << dendl; int ret = _do_filelock(in, fh, CEPH_LOCK_FCNTL, CEPH_MDS_OP_GETFILELOCK, 0, fl, owner); return ret; } int Client::_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req) { Inode *in = fh->inode; ldout(cct, 10) << "_setlk " << fh << " ino " << in->ino << dendl; int ret = _do_filelock(in, fh, CEPH_LOCK_FCNTL, CEPH_MDS_OP_SETFILELOCK, sleep, fl, owner, fuse_req); ldout(cct, 10) << "_setlk " << fh << " ino " << in->ino << " result=" << ret << dendl; return ret; } int Client::_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req) { Inode *in = fh->inode; ldout(cct, 10) << "_flock " << fh << " ino " << in->ino << dendl; int sleep = !(cmd & LOCK_NB); cmd &= ~LOCK_NB; int type; switch (cmd) { case LOCK_SH: type = F_RDLCK; break; case LOCK_EX: type = F_WRLCK; break; case LOCK_UN: type = F_UNLCK; break; default: return -EINVAL; } struct flock fl; memset(&fl, 0, sizeof(fl)); fl.l_type = type; fl.l_whence = SEEK_SET; int ret = _do_filelock(in, fh, CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, sleep, &fl, owner, fuse_req); ldout(cct, 10) << "_flock " << fh << " ino " << in->ino << " result=" << ret << dendl; return ret; } int Client::ll_statfs(Inode *in, struct statvfs *stbuf) { /* Since the only thing this does is wrap a call to statfs, and statfs takes a lock, it doesn't seem we have a need to split it out. */ return statfs(0, stbuf); } void Client::ll_register_ino_invalidate_cb(client_ino_callback_t cb, void *handle) { Mutex::Locker l(client_lock); ldout(cct, 10) << "ll_register_ino_invalidate_cb cb " << (void*)cb << " p " << (void*)handle << dendl; if (cb == NULL) return; ino_invalidate_cb = cb; ino_invalidate_cb_handle = handle; async_ino_invalidator.start(); } void Client::ll_register_dentry_invalidate_cb(client_dentry_callback_t cb, void *handle) { Mutex::Locker l(client_lock); ldout(cct, 10) << "ll_register_dentry_invalidate_cb cb " << (void*)cb << " p " << (void*)handle << dendl; if (cb == NULL) return; dentry_invalidate_cb = cb; dentry_invalidate_cb_handle = handle; async_dentry_invalidator.start(); } void Client::ll_register_switch_interrupt_cb(client_switch_interrupt_callback_t cb) { Mutex::Locker l(client_lock); ldout(cct, 10) << "ll_register_switch_interrupt_cb cb " << (void*)cb << dendl; if (cb == NULL) return; switch_interrupt_cb = cb; interrupt_finisher.start(); } void Client::ll_register_getgroups_cb(client_getgroups_callback_t cb, void *handle) { Mutex::Locker l(client_lock); getgroups_cb = cb; getgroups_cb_handle = handle; } int Client::_sync_fs() { ldout(cct, 10) << "_sync_fs" << dendl; // wait for unsafe mds requests // FIXME // flush caps flush_caps(); wait_sync_caps(last_flush_seq); // flush file data // FIXME return 0; } int Client::sync_fs() { Mutex::Locker l(client_lock); return _sync_fs(); } int64_t Client::drop_caches() { Mutex::Locker l(client_lock); return objectcacher->release_all(); } int Client::lazyio_propogate(int fd, loff_t offset, size_t count) { Mutex::Locker l(client_lock); ldout(cct, 3) << "op: client->lazyio_propogate(" << fd << ", " << offset << ", " << count << ")" << dendl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; // for now _fsync(f, true); return 0; } int Client::lazyio_synchronize(int fd, loff_t offset, size_t count) { Mutex::Locker l(client_lock); ldout(cct, 3) << "op: client->lazyio_synchronize(" << fd << ", " << offset << ", " << count << ")" << dendl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; Inode *in = f->inode; _fsync(f, true); _release(in); return 0; } // ============================= // snaps int Client::mksnap(const char *relpath, const char *name) { Mutex::Locker l(client_lock); filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; Inode *snapdir = open_snapdir(in); return _mkdir(snapdir, name, 0); } int Client::rmsnap(const char *relpath, const char *name) { Mutex::Locker l(client_lock); filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; Inode *snapdir = open_snapdir(in); return _rmdir(snapdir, name); } // ============================= // expose caps int Client::get_caps_issued(int fd) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; return f->inode->caps_issued(); } int Client::get_caps_issued(const char *path) { Mutex::Locker lock(client_lock); filepath p(path); Inode *in; int r = path_walk(p, &in, true); if (r < 0) return r; return in->caps_issued(); } // ========================================= // low level Inode *Client::open_snapdir(Inode *diri) { Inode *in; vinodeno_t vino(diri->ino, CEPH_SNAPDIR); if (!inode_map.count(vino)) { in = new Inode(cct, vino, &diri->layout); in->ino = diri->ino; in->snapid = CEPH_SNAPDIR; in->mode = diri->mode; in->uid = diri->uid; in->gid = diri->gid; in->mtime = diri->mtime; in->ctime = diri->ctime; in->size = diri->size; in->dirfragtree.clear(); inode_map[vino] = in; in->snapdir_parent = diri; diri->get(); ldout(cct, 10) << "open_snapdir created snapshot inode " << *in << dendl; } else { in = inode_map[vino]; ldout(cct, 10) << "open_snapdir had snapshot inode " << *in << dendl; } return in; } int Client::ll_lookup(Inode *parent, const char *name, struct stat *attr, Inode **out, int uid, int gid) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_lookup " << parent << " " << name << dendl; tout(cct) << "ll_lookup" << std::endl; tout(cct) << name << std::endl; string dname(name); Inode *in; int r = 0; r = _lookup(parent, dname, &in); if (r < 0) { attr->st_ino = 0; goto out; } assert(in); fill_stat(in, attr); _ll_get(in); out: ldout(cct, 3) << "ll_lookup " << parent << " " << name << " -> " << r << " (" << hex << attr->st_ino << dec << ")" << dendl; tout(cct) << attr->st_ino << std::endl; *out = in; return r; } int Client::ll_walk(const char* name, Inode **i, struct stat *attr) { Mutex::Locker lock(client_lock); filepath fp(name, 0); Inode *destination = NULL; int rc; ldout(cct, 3) << "ll_walk" << name << dendl; tout(cct) << "ll_walk" << std::endl; tout(cct) << name << std::endl; rc = path_walk(fp, &destination, false); if (rc < 0) { attr->st_ino = 0; *i = NULL; return rc; } else { fill_stat(destination, attr); *i = destination; return 0; } } void Client::_ll_get(Inode *in) { if (in->ll_ref == 0) { in->get(); if (in->is_dir() && !in->dn_set.empty()) { assert(in->dn_set.size() == 1); // dirs can't be hard-linked in->get_first_parent()->get(); // pin dentry } } in->ll_get(); ldout(cct, 20) << "_ll_get " << in << " " << in->ino << " -> " << in->ll_ref << dendl; } int Client::_ll_put(Inode *in, int num) { in->ll_put(num); ldout(cct, 20) << "_ll_put " << in << " " << in->ino << " " << num << " -> " << in->ll_ref << dendl; if (in->ll_ref == 0) { if (in->is_dir() && !in->dn_set.empty()) { assert(in->dn_set.size() == 1); // dirs can't be hard-linked in->get_first_parent()->put(); // unpin dentry } put_inode(in); return 0; } else { return in->ll_ref; } } void Client::_ll_drop_pins() { ldout(cct, 10) << "_ll_drop_pins" << dendl; ceph::unordered_map::iterator next; for (ceph::unordered_map::iterator it = inode_map.begin(); it != inode_map.end(); it = next) { Inode *in = it->second; next = it; ++next; if (in->ll_ref) _ll_put(in, in->ll_ref); } } bool Client::ll_forget(Inode *in, int count) { Mutex::Locker lock(client_lock); inodeno_t ino = _get_inodeno(in); ldout(cct, 3) << "ll_forget " << ino << " " << count << dendl; tout(cct) << "ll_forget" << std::endl; tout(cct) << ino.val << std::endl; tout(cct) << count << std::endl; if (ino == 1) return true; // ignore forget on root. bool last = false; if (in->ll_ref < count) { ldout(cct, 1) << "WARNING: ll_forget on " << ino << " " << count << ", which only has ll_ref=" << in->ll_ref << dendl; _ll_put(in, in->ll_ref); last = true; } else { if (_ll_put(in, count) == 0) last = true; } return last; } bool Client::ll_put(Inode *in) { /* ll_forget already takes the lock */ return ll_forget(in, 1); } snapid_t Client::ll_get_snapid(Inode *in) { Mutex::Locker lock(client_lock); return in->snapid; } Inode *Client::ll_get_inode(vinodeno_t vino) { Mutex::Locker lock(client_lock); unordered_map::iterator p = inode_map.find(vino); if (p == inode_map.end()) return NULL; Inode *in = p->second; _ll_get(in); return in; } int Client::ll_getattr(Inode *in, struct stat *attr, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_getattr " << vino << dendl; tout(cct) << "ll_getattr" << std::endl; tout(cct) << vino.ino.val << std::endl; /* special case for dotdot (..) */ if (vino.ino.val == CEPH_INO_DOTDOT) { attr->st_mode = S_IFDIR | 0755; attr->st_nlink = 2; return 0; } int res; if (vino.snapid < CEPH_NOSNAP) res = 0; else res = _getattr(in, CEPH_STAT_CAP_INODE_ALL, uid, gid); if (res == 0) fill_stat(in, attr); ldout(cct, 3) << "ll_getattr " << vino << " = " << res << dendl; return res; } int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_setattr " << vino << " mask " << hex << mask << dec << dendl; tout(cct) << "ll_setattr" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << attr->st_mode << std::endl; tout(cct) << attr->st_uid << std::endl; tout(cct) << attr->st_gid << std::endl; tout(cct) << attr->st_size << std::endl; tout(cct) << attr->st_mtime << std::endl; tout(cct) << attr->st_atime << std::endl; tout(cct) << mask << std::endl; Inode *target = in; int res = _setattr(in, attr, mask, uid, gid, &target); if (res == 0) { assert(in == target); fill_stat(in, attr); } ldout(cct, 3) << "ll_setattr " << vino << " = " << res << dendl; return res; } // ---------- // xattrs int Client::getxattr(const char *path, const char *name, void *value, size_t size) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, true); if (r < 0) return r; return Client::_getxattr(ceph_inode, name, value, size, getuid(), getgid()); } int Client::lgetxattr(const char *path, const char *name, void *value, size_t size) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, false); if (r < 0) return r; return Client::_getxattr(ceph_inode, name, value, size, getuid(), getgid()); } int Client::listxattr(const char *path, char *list, size_t size) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, true); if (r < 0) return r; return Client::_listxattr(ceph_inode, list, size, getuid(), getgid()); } int Client::llistxattr(const char *path, char *list, size_t size) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, false); if (r < 0) return r; return Client::_listxattr(ceph_inode, list, size, getuid(), getgid()); } int Client::removexattr(const char *path, const char *name) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, true); if (r < 0) return r; return Client::_removexattr(ceph_inode, name, getuid(), getgid()); } int Client::lremovexattr(const char *path, const char *name) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, false); if (r < 0) return r; return Client::_removexattr(ceph_inode, name, getuid(), getgid()); } int Client::setxattr(const char *path, const char *name, const void *value, size_t size, int flags) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, true); if (r < 0) return r; return Client::_setxattr(ceph_inode, name, value, size, flags, getuid(), getgid()); } int Client::lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) { Mutex::Locker lock(client_lock); Inode *ceph_inode; int r = Client::path_walk(path, &ceph_inode, false); if (r < 0) return r; return Client::_setxattr(ceph_inode, name, value, size, flags, getuid(), getgid()); } int Client::_getxattr(Inode *in, const char *name, void *value, size_t size, int uid, int gid) { int r; if (strncmp(name, "ceph.", 5) == 0) { string n(name); char buf[256]; r = -ENODATA; if ((in->is_file() && n.find("ceph.file.layout") == 0) || (in->is_dir() && in->has_dir_layout() && n.find("ceph.dir.layout") == 0)) { string rest = n.substr(n.find("layout")); if (rest == "layout") { r = snprintf(buf, sizeof(buf), "stripe_unit=%lu stripe_count=%lu object_size=%lu pool=", (long unsigned)in->layout.fl_stripe_unit, (long unsigned)in->layout.fl_stripe_count, (long unsigned)in->layout.fl_object_size); if (osdmap->have_pg_pool(in->layout.fl_pg_pool)) r += snprintf(buf + r, sizeof(buf) - r, "%s", osdmap->get_pool_name(in->layout.fl_pg_pool)); else r += snprintf(buf + r, sizeof(buf) - r, "%lu", (long unsigned)in->layout.fl_pg_pool); } else if (rest == "layout.stripe_unit") { r = snprintf(buf, sizeof(buf), "%lu", (long unsigned)in->layout.fl_stripe_unit); } else if (rest == "layout.stripe_count") { r = snprintf(buf, sizeof(buf), "%lu", (long unsigned)in->layout.fl_stripe_count); } else if (rest == "layout.object_size") { r = snprintf(buf, sizeof(buf), "%lu", (long unsigned)in->layout.fl_object_size); } else if (rest == "layout.pool") { if (osdmap->have_pg_pool(in->layout.fl_pg_pool)) r = snprintf(buf, sizeof(buf), "%s", osdmap->get_pool_name(in->layout.fl_pg_pool)); else r = snprintf(buf, sizeof(buf), "%lu", (long unsigned)in->layout.fl_pg_pool); } } if (size != 0) { if (r > (int)size) { r = -ERANGE; } else if (r > 0) { memcpy(value, buf, r); } } goto out; } r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid); if (r == 0) { string n(name); r = -ENODATA; if (in->xattrs.count(n)) { r = in->xattrs[n].length(); if (size != 0) { if (size >= (unsigned)r) memcpy(value, in->xattrs[n].c_str(), r); else r = -ERANGE; } } } out: ldout(cct, 3) << "_getxattr(" << in->ino << ", \"" << name << "\", " << size << ") = " << r << dendl; return r; } int Client::ll_getxattr(Inode *in, const char *name, void *value, size_t size, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_getxattr " << vino << " " << name << " size " << size << dendl; tout(cct) << "ll_getxattr" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; return _getxattr(in, name, value, size, uid, gid); } int Client::_listxattr(Inode *in, char *name, size_t size, int uid, int gid) { int r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid); if (r == 0) { for (map::iterator p = in->xattrs.begin(); p != in->xattrs.end(); ++p) r += p->first.length() + 1; if (size != 0) { if (size >= (unsigned)r) { for (map::iterator p = in->xattrs.begin(); p != in->xattrs.end(); ++p) { memcpy(name, p->first.c_str(), p->first.length()); name += p->first.length(); *name = '\0'; name++; } } else r = -ERANGE; } } ldout(cct, 3) << "_listxattr(" << in->ino << ", " << size << ") = " << r << dendl; return r; } int Client::ll_listxattr(Inode *in, char *names, size_t size, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_listxattr " << vino << " size " << size << dendl; tout(cct) << "ll_listxattr" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << size << std::endl; return _listxattr(in, names, size, uid, gid); } int Client::_setxattr(Inode *in, const char *name, const void *value, size_t size, int flags, int uid, int gid) { if (in->snapid != CEPH_NOSNAP) { return -EROFS; } // same xattrs supported by kernel client if (strncmp(name, "user.", 5) && strncmp(name, "security.", 9) && strncmp(name, "trusted.", 8) && strncmp(name, "ceph.", 5)) return -EOPNOTSUPP; if (!value) flags |= CEPH_XATTR_REMOVE; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_SETXATTR); filepath path; in->make_nosnap_relative_path(path); req->set_filepath(path); req->set_string2(name); req->set_inode(in); req->head.args.setxattr.flags = flags; bufferlist bl; bl.append((const char*)value, size); req->set_data(bl); int res = make_request(req, uid, gid); trim_cache(); ldout(cct, 3) << "_setxattr(" << in->ino << ", \"" << name << "\") = " << res << dendl; return res; } int Client::ll_setxattr(Inode *in, const char *name, const void *value, size_t size, int flags, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_setxattr " << vino << " " << name << " size " << size << dendl; tout(cct) << "ll_setxattr" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; return _setxattr(in, name, value, size, flags, uid, gid); } int Client::_removexattr(Inode *in, const char *name, int uid, int gid) { if (in->snapid != CEPH_NOSNAP) { return -EROFS; } // same xattrs supported by kernel client if (strncmp(name, "user.", 5) && strncmp(name, "security.", 9) && strncmp(name, "trusted.", 8) && strncmp(name, "ceph.", 5)) return -EOPNOTSUPP; MetaRequest *req = new MetaRequest(CEPH_MDS_OP_RMXATTR); filepath path; in->make_nosnap_relative_path(path); req->set_filepath(path); req->set_filepath2(name); req->set_inode(in); int res = make_request(req, uid, gid); trim_cache(); ldout(cct, 3) << "_removexattr(" << in->ino << ", \"" << name << "\") = " << res << dendl; return res; } int Client::ll_removexattr(Inode *in, const char *name, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_removexattr " << vino << " " << name << dendl; tout(cct) << "ll_removexattr" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; return _removexattr(in, name, uid, gid); } int Client::ll_readlink(Inode *in, char *buf, size_t buflen, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_readlink " << vino << dendl; tout(cct) << "ll_readlink" << std::endl; tout(cct) << vino.ino.val << std::endl; set::iterator dn = in->dn_set.begin(); while (dn != in->dn_set.end()) { touch_dn(*dn); ++dn; } int r = _readlink(in, buf, buflen); ldout(cct, 3) << "ll_readlink " << vino << " = " << r << dendl; return r; } int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int uid, int gid, Inode **inp) { ldout(cct, 3) << "_mknod(" << dir->ino << " " << name << ", 0" << oct << mode << dec << ", " << rdev << ", uid " << uid << ", gid " << gid << ")" << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_MKNOD); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); req->set_inode(dir); req->head.args.mknod.mode = mode; req->head.args.mknod.rdev = rdev; req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; Dentry *de; int res = get_or_create(dir, name, &de); if (res < 0) goto fail; req->set_dentry(de); res = make_request(req, uid, gid, inp); trim_cache(); ldout(cct, 3) << "mknod(" << path << ", 0" << oct << mode << dec << ") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_mknod(Inode *parent, const char *name, mode_t mode, dev_t rdev, struct stat *attr, Inode **out, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vparent = _get_vino(parent); ldout(cct, 3) << "ll_mknod " << vparent << " " << name << dendl; tout(cct) << "ll_mknod" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << name << std::endl; tout(cct) << mode << std::endl; tout(cct) << rdev << std::endl; Inode *in = NULL; int r = _mknod(parent, name, mode, rdev, uid, gid, &in); if (r == 0) { fill_stat(in, attr); _ll_get(in); } tout(cct) << attr->st_ino << std::endl; ldout(cct, 3) << "ll_mknod " << vparent << " " << name << " = " << r << " (" << hex << attr->st_ino << dec << ")" << dendl; *out = in; return r; } int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, Inode **inp, Fh **fhp, int stripe_unit, int stripe_count, int object_size, const char *data_pool, bool *created, int uid, int gid) { ldout(cct, 3) << "_create(" << dir->ino << " " << name << ", 0" << oct << mode << dec << ")" << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } int cmode = ceph_flags_to_mode(flags); if (cmode < 0) return -EINVAL; int64_t pool_id = -1; if (data_pool && *data_pool) { pool_id = osdmap->lookup_pg_pool_name(data_pool); if (pool_id < 0) return -EINVAL; if (pool_id > 0xffffffffll) return -ERANGE; // bummer! } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_CREATE); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); req->set_inode(dir); req->head.args.open.flags = flags | O_CREAT; req->head.args.open.mode = mode; req->head.args.open.stripe_unit = stripe_unit; req->head.args.open.stripe_count = stripe_count; req->head.args.open.object_size = object_size; req->head.args.open.pool = pool_id; req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; bufferlist extra_bl; inodeno_t created_ino; Dentry *de; int res = get_or_create(dir, name, &de); if (res < 0) goto fail; req->set_dentry(de); res = make_request(req, uid, gid, inp, created); if (res < 0) { goto reply_error; } /* If the caller passed a value in fhp, do the open */ if(fhp) { (*inp)->get_open_ref(cmode); *fhp = _create_fh(*inp, flags, cmode); } reply_error: trim_cache(); ldout(cct, 3) << "create(" << path << ", 0" << oct << mode << dec << " layout " << stripe_unit << ' ' << stripe_count << ' ' << object_size <<") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid, Inode **inp) { ldout(cct, 3) << "_mkdir(" << dir->ino << " " << name << ", 0" << oct << mode << dec << ", uid " << uid << ", gid " << gid << ")" << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; if (dir->snapid != CEPH_NOSNAP && dir->snapid != CEPH_SNAPDIR) { return -EROFS; } MetaRequest *req = new MetaRequest(dir->snapid == CEPH_SNAPDIR ? CEPH_MDS_OP_MKSNAP : CEPH_MDS_OP_MKDIR); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); req->set_inode(dir); req->head.args.mkdir.mode = mode; req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; Dentry *de; int res = get_or_create(dir, name, &de); if (res < 0) goto fail; req->set_dentry(de); ldout(cct, 10) << "_mkdir: making request" << dendl; res = make_request(req, uid, gid, inp); ldout(cct, 10) << "_mkdir result is " << res << dendl; trim_cache(); ldout(cct, 3) << "_mkdir(" << path << ", 0" << oct << mode << dec << ") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode, struct stat *attr, Inode **out, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vparent = _get_vino(parent); ldout(cct, 3) << "ll_mkdir " << vparent << " " << name << dendl; tout(cct) << "ll_mkdir" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << name << std::endl; tout(cct) << mode << std::endl; Inode *in = NULL; int r = _mkdir(parent, name, mode, uid, gid, &in); if (r == 0) { fill_stat(in, attr); _ll_get(in); } tout(cct) << attr->st_ino << std::endl; ldout(cct, 3) << "ll_mkdir " << vparent << " " << name << " = " << r << " (" << hex << attr->st_ino << dec << ")" << dendl; *out = in; return r; } int Client::_symlink(Inode *dir, const char *name, const char *target, int uid, int gid, Inode **inp) { ldout(cct, 3) << "_symlink(" << dir->ino << " " << name << ", " << target << ", uid " << uid << ", gid " << gid << ")" << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_SYMLINK); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); req->set_inode(dir); req->set_string2(target); req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; Dentry *de; int res = get_or_create(dir, name, &de); if (res < 0) goto fail; req->set_dentry(de); res = make_request(req, uid, gid, inp); trim_cache(); ldout(cct, 3) << "_symlink(\"" << path << "\", \"" << target << "\") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_symlink(Inode *parent, const char *name, const char *value, struct stat *attr, Inode **out, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vparent = _get_vino(parent); ldout(cct, 3) << "ll_symlink " << vparent << " " << name << " -> " << value << dendl; tout(cct) << "ll_symlink" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << name << std::endl; tout(cct) << value << std::endl; Inode *in = NULL; int r = _symlink(parent, name, value, uid, gid, &in); if (r == 0) { fill_stat(in, attr); _ll_get(in); } tout(cct) << attr->st_ino << std::endl; ldout(cct, 3) << "ll_symlink " << vparent << " " << name << " = " << r << " (" << hex << attr->st_ino << dec << ")" << dendl; *out = in; return r; } int Client::_unlink(Inode *dir, const char *name, int uid, int gid) { ldout(cct, 3) << "_unlink(" << dir->ino << " " << name << " uid " << uid << " gid " << gid << ")" << dendl; if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_UNLINK); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); Dentry *de; int res = get_or_create(dir, name, &de); if (res < 0) goto fail; req->set_dentry(de); req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; Inode *otherin; res = _lookup(dir, name, &otherin); if (res < 0) goto fail; req->set_other_inode(otherin); req->other_inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL; req->set_inode(dir); res = make_request(req, uid, gid); if (res == 0) { if (dir->dir && dir->dir->dentries.count(name)) { Dentry *dn = dir->dir->dentries[name]; unlink(dn, false); } } ldout(cct, 10) << "unlink result is " << res << dendl; trim_cache(); ldout(cct, 3) << "unlink(" << path << ") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_unlink(Inode *in, const char *name, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_unlink " << vino << " " << name << dendl; tout(cct) << "ll_unlink" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; return _unlink(in, name, uid, gid); } int Client::_rmdir(Inode *dir, const char *name, int uid, int gid) { ldout(cct, 3) << "_rmdir(" << dir->ino << " " << name << " uid " << uid << " gid " << gid << ")" << dendl; if (dir->snapid != CEPH_NOSNAP && dir->snapid != CEPH_SNAPDIR) { return -EROFS; } MetaRequest *req = new MetaRequest(dir->snapid == CEPH_SNAPDIR ? CEPH_MDS_OP_RMSNAP:CEPH_MDS_OP_RMDIR); filepath path; dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; req->inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL; Dentry *de; int res = get_or_create(dir, name, &de); if (res < 0) goto fail; req->set_dentry(de); Inode *in; res = _lookup(dir, name, &in); if (res < 0) goto fail; req->set_inode(in); res = make_request(req, uid, gid); if (res == 0) { if (dir->dir && dir->dir->dentries.count(name) ) { Dentry *dn = dir->dir->dentries[name]; if (dn->inode->dir && dn->inode->dir->is_empty() && (dn->inode->dn_set.size() == 1)) close_dir(dn->inode->dir); // FIXME: maybe i shoudl proactively hose the whole subtree from cache? unlink(dn, false); } } trim_cache(); ldout(cct, 3) << "rmdir(" << path << ") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_rmdir(Inode *in, const char *name, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_rmdir " << vino << " " << name << dendl; tout(cct) << "ll_rmdir" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; return _rmdir(in, name, uid, gid); } int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const char *toname, int uid, int gid) { ldout(cct, 3) << "_rename(" << fromdir->ino << " " << fromname << " to " << todir->ino << " " << toname << " uid " << uid << " gid " << gid << ")" << dendl; if (fromdir->snapid != CEPH_NOSNAP || todir->snapid != CEPH_NOSNAP) { return -EROFS; } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_RENAME); filepath from; fromdir->make_nosnap_relative_path(from); from.push_dentry(fromname); filepath to; todir->make_nosnap_relative_path(to); to.push_dentry(toname); req->set_filepath(to); req->set_filepath2(from); Dentry *oldde; int res = get_or_create(fromdir, fromname, &oldde); if (res < 0) goto fail; req->set_old_dentry(oldde); req->old_dentry_drop = CEPH_CAP_FILE_SHARED; req->old_dentry_unless = CEPH_CAP_FILE_EXCL; Dentry *de; res = get_or_create(todir, toname, &de); if (res < 0) goto fail; req->set_dentry(de); req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; Inode *oldin; res = _lookup(fromdir, fromname, &oldin); if (res < 0) goto fail; req->set_old_inode(oldin); req->old_inode_drop = CEPH_CAP_LINK_SHARED; Inode *otherin; res = _lookup(todir, toname, &otherin); if (res != 0 && res != -ENOENT) { goto fail; } else if (res == 0) { req->set_other_inode(otherin); req->other_inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL; } req->set_inode(todir); Inode *target; res = make_request(req, uid, gid, &target); ldout(cct, 10) << "rename result is " << res << dendl; // renamed item from our cache trim_cache(); ldout(cct, 3) << "_rename(" << from << ", " << to << ") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_rename(Inode *parent, const char *name, Inode *newparent, const char *newname, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vparent = _get_vino(parent); vinodeno_t vnewparent = _get_vino(newparent); ldout(cct, 3) << "ll_rename " << vparent << " " << name << " to " << vnewparent << " " << newname << dendl; tout(cct) << "ll_rename" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << name << std::endl; tout(cct) << vnewparent.ino.val << std::endl; tout(cct) << newname << std::endl; return _rename(parent, name, newparent, newname, uid, gid); } int Client::_link(Inode *in, Inode *dir, const char *newname, int uid, int gid, Inode **inp) { ldout(cct, 3) << "_link(" << in->ino << " to " << dir->ino << " " << newname << " uid " << uid << " gid " << gid << ")" << dendl; if (strlen(newname) > NAME_MAX) return -ENAMETOOLONG; if (in->snapid != CEPH_NOSNAP || dir->snapid != CEPH_NOSNAP) { return -EROFS; } MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LINK); filepath path(newname, dir->ino); req->set_filepath(path); filepath existing(in->ino); req->set_filepath2(existing); req->set_inode(dir); req->inode_drop = CEPH_CAP_FILE_SHARED; req->inode_unless = CEPH_CAP_FILE_EXCL; Dentry *de; int res = get_or_create(dir, newname, &de); if (res < 0) goto fail; req->set_dentry(de); res = make_request(req, uid, gid, inp); ldout(cct, 10) << "link result is " << res << dendl; trim_cache(); ldout(cct, 3) << "link(" << existing << ", " << path << ") = " << res << dendl; return res; fail: put_request(req); return res; } int Client::ll_link(Inode *parent, Inode *newparent, const char *newname, struct stat *attr, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vparent = _get_vino(parent); vinodeno_t vnewparent = _get_vino(newparent); ldout(cct, 3) << "ll_link " << parent << " to " << vnewparent << " " << newname << dendl; tout(cct) << "ll_link" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << vnewparent << std::endl; tout(cct) << newname << std::endl; int r = _link(parent, newparent, newname, uid, gid, &parent); if (r == 0) { fill_stat(parent, attr); _ll_get(parent); } return r; } int Client::ll_num_osds(void) { Mutex::Locker lock(client_lock); return osdmap->get_num_osds(); } int Client::ll_osdaddr(int osd, uint32_t *addr) { Mutex::Locker lock(client_lock); entity_addr_t g = osdmap->get_addr(osd); uint32_t nb_addr = (g.in4_addr()).sin_addr.s_addr; if (!(osdmap->exists(osd))) { return -1; } *addr = ntohl(nb_addr); return 0; } uint32_t Client::ll_stripe_unit(Inode *in) { Mutex::Locker lock(client_lock); return in->layout.fl_stripe_unit; } uint64_t Client::ll_snap_seq(Inode *in) { Mutex::Locker lock(client_lock); return in->snaprealm->seq; } int Client::ll_file_layout(Inode *in, ceph_file_layout *layout) { Mutex::Locker lock(client_lock); *layout = in->layout; return 0; } /* Currently we cannot take advantage of redundancy in reads, since we would have to go through all possible placement groups (a potentially quite large number determined by a hash), and use CRUSH to calculate the appropriate set of OSDs for each placement group, then index into that. An array with one entry per OSD is much more tractable and works for demonstration purposes. */ int Client::ll_get_stripe_osd(Inode *in, uint64_t blockno, ceph_file_layout* layout) { Mutex::Locker lock(client_lock); inodeno_t ino = ll_get_inodeno(in); uint32_t object_size = layout->fl_object_size; uint32_t su = layout->fl_stripe_unit; uint32_t stripe_count = layout->fl_stripe_count; uint64_t stripes_per_object = object_size / su; uint64_t stripeno = blockno / stripe_count; // which horizontal stripe (Y) uint64_t stripepos = blockno % stripe_count; // which object in the object set (X) uint64_t objectsetno = stripeno / stripes_per_object; // which object set uint64_t objectno = objectsetno * stripe_count + stripepos; // object id object_t oid = file_object_t(ino, objectno); ceph_object_layout olayout = objecter->osdmap->file_to_object_layout(oid, *layout, ""); pg_t pg = (pg_t)olayout.ol_pgid; vector osds; int primary; osdmap->pg_to_osds(pg, &osds, &primary); return osds[0]; } /* Return the offset of the block, internal to the object */ uint64_t Client::ll_get_internal_offset(Inode *in, uint64_t blockno) { Mutex::Locker lock(client_lock); ceph_file_layout *layout=&(in->layout); uint32_t object_size = layout->fl_object_size; uint32_t su = layout->fl_stripe_unit; uint64_t stripes_per_object = object_size / su; return (blockno % stripes_per_object) * su; } int Client::ll_opendir(Inode *in, dir_result_t** dirpp, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_opendir " << vino << dendl; tout(cct) << "ll_opendir" << std::endl; tout(cct) << vino.ino.val << std::endl; int r = 0; if (vino.snapid == CEPH_SNAPDIR) { *dirpp = new dir_result_t(in); } else { r = _opendir(in, dirpp); } tout(cct) << (unsigned long)*dirpp << std::endl; ldout(cct, 3) << "ll_opendir " << vino << " = " << r << " (" << *dirpp << ")" << dendl; return r; } int Client::ll_releasedir(dir_result_t *dirp) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_releasedir " << dirp << dendl; tout(cct) << "ll_releasedir" << std::endl; tout(cct) << (unsigned long)dirp << std::endl; _closedir(dirp); return 0; } int Client::ll_open(Inode *in, int flags, Fh **fhp, int uid, int gid) { assert(!(flags & O_CREAT)); Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); ldout(cct, 3) << "ll_open " << vino << " " << flags << dendl; tout(cct) << "ll_open" << std::endl; tout(cct) << vino.ino.val << std::endl; tout(cct) << flags << std::endl; int r; if (uid < 0) { uid = geteuid(); gid = getegid(); } r = check_permissions(in, flags, uid, gid); if (r < 0) goto out; r = _open(in, flags, 0, fhp /* may be NULL */, uid, gid); out: Fh *fhptr = fhp ? *fhp : NULL; tout(cct) << (unsigned long)fhptr << std::endl; ldout(cct, 3) << "ll_open " << vino << " " << flags << " = " << r << " (" << fhptr << ")" << dendl; return r; } int Client::ll_create(Inode *parent, const char *name, mode_t mode, int flags, struct stat *attr, Inode **outp, Fh **fhp, int uid, int gid) { Mutex::Locker lock(client_lock); vinodeno_t vparent = _get_vino(parent); ldout(cct, 3) << "ll_create " << vparent << " " << name << " 0" << oct << mode << dec << " " << flags << ", uid " << uid << ", gid " << gid << dendl; tout(cct) << "ll_create" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << name << std::endl; tout(cct) << mode << std::endl; tout(cct) << flags << std::endl; bool created = false; Inode *in = NULL; int r = _lookup(parent, name, &in); if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL)) return -EEXIST; if (r == -ENOENT && (flags & O_CREAT)) { r = _create(parent, name, flags, mode, &in, fhp /* may be NULL */, 0, 0, 0, NULL, &created, uid, gid); if (r < 0) goto out; if ((!in) && fhp) in = (*fhp)->inode; } if (r < 0) goto out; assert(in); fill_stat(in, attr); ldout(cct, 20) << "ll_create created = " << created << dendl; if (!created) { r = check_permissions(in, flags, uid, gid); if (r < 0) { if (fhp && *fhp) { _release_fh(*fhp); } goto out; } if (fhp && (*fhp == NULL)) { r = _open(in, flags, mode, fhp); if (r < 0) goto out; } } out: if (r < 0) attr->st_ino = 0; Fh *fhptr = fhp ? *fhp : NULL; tout(cct) << (unsigned long)fhptr << std::endl; tout(cct) << attr->st_ino << std::endl; ldout(cct, 3) << "ll_create " << parent << " " << name << " 0" << oct << mode << dec << " " << flags << " = " << r << " (" << fhptr << " " << hex << attr->st_ino << dec << ")" << dendl; // passing an Inode in outp requires an additional ref if (outp) { if (in) _ll_get(in); *outp = in; } return r; } loff_t Client::ll_lseek(Fh *fh, loff_t offset, int whence) { Mutex::Locker lock(client_lock); tout(cct) << "ll_lseek" << std::endl; tout(cct) << offset << std::endl; tout(cct) << whence << std::endl; return _lseek(fh, offset, whence); } int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_read " << fh << " " << fh->inode->ino << " " << " " << off << "~" << len << dendl; tout(cct) << "ll_read" << std::endl; tout(cct) << (unsigned long)fh << std::endl; tout(cct) << off << std::endl; tout(cct) << len << std::endl; return _read(fh, off, len, bl); } int Client::ll_read_block(Inode *in, uint64_t blockid, char *buf, uint64_t offset, uint64_t length, ceph_file_layout* layout) { Mutex::Locker lock(client_lock); Mutex flock("Client::ll_read_block flock"); Cond cond; vinodeno_t vino = ll_get_vino(in); object_t oid = file_object_t(vino.ino, blockid); int r = 0; bool done = false; Context *onfinish = new C_SafeCond(&flock, &cond, &done, &r); bufferlist bl; objecter->read(oid, object_locator_t(layout->fl_pg_pool), offset, length, vino.snapid, &bl, CEPH_OSD_FLAG_READ, onfinish); while (!done) cond.Wait(client_lock); if (r >= 0) { bl.copy(0, bl.length(), buf); r = bl.length(); } return r; } /* It appears that the OSD doesn't return success unless the entire buffer was written, return the write length on success. */ int Client::ll_write_block(Inode *in, uint64_t blockid, char* buf, uint64_t offset, uint64_t length, ceph_file_layout* layout, uint64_t snapseq, uint32_t sync) { Mutex flock("Client::ll_write_block flock"); vinodeno_t vino = ll_get_vino(in); Cond cond; bool done; int r = 0; Context *onack; Context *onsafe; if (length == 0) { return -EINVAL; } if (true || sync) { /* if write is stable, the epilogue is waiting on * flock */ onack = new C_NoopContext; onsafe = new C_SafeCond(&flock, &cond, &done, &r); done = false; } else { /* if write is unstable, we just place a barrier for * future commits to wait on */ onack = new C_NoopContext; /*onsafe = new C_Block_Sync(this, vino.ino, barrier_interval(offset, offset + length), &r); */ done = true; } object_t oid = file_object_t(vino.ino, blockid); SnapContext fakesnap; bufferptr bp; if (length > 0) bp = buffer::copy(buf, length); bufferlist bl; bl.push_back(bp); ldout(cct, 1) << "ll_block_write for " << vino.ino << "." << blockid << dendl; fakesnap.seq = snapseq; /* lock just in time */ client_lock.Lock(); objecter->write(oid, object_locator_t(layout->fl_pg_pool), offset, length, fakesnap, bl, ceph_clock_now(cct), 0, onack, onsafe); client_lock.Unlock(); if (!done /* also !sync */) { flock.Lock(); while (! done) cond.Wait(flock); flock.Unlock(); } if (r < 0) { return r; } else { return length; } } int Client::ll_commit_blocks(Inode *in, uint64_t offset, uint64_t length) { Mutex::Locker lock(client_lock); /* BarrierContext *bctx; vinodeno_t vino = ll_get_vino(in); uint64_t ino = vino.ino; ldout(cct, 1) << "ll_commit_blocks for " << vino.ino << " from " << offset << " to " << length << dendl; if (length == 0) { return -EINVAL; } map::iterator p = barriers.find(ino); if (p != barriers.end()) { barrier_interval civ(offset, offset + length); p->second->commit_barrier(civ); } */ return 0; } int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_write " << fh << " " << fh->inode->ino << " " << off << "~" << len << dendl; tout(cct) << "ll_write" << std::endl; tout(cct) << (unsigned long)fh << std::endl; tout(cct) << off << std::endl; tout(cct) << len << std::endl; int r = _write(fh, off, len, data); ldout(cct, 3) << "ll_write " << fh << " " << off << "~" << len << " = " << r << dendl; return r; } int Client::ll_flush(Fh *fh) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_flush " << fh << " " << fh->inode->ino << " " << dendl; tout(cct) << "ll_flush" << std::endl; tout(cct) << (unsigned long)fh << std::endl; return _flush(fh); } int Client::ll_fsync(Fh *fh, bool syncdataonly) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_fsync " << fh << " " << fh->inode->ino << " " << dendl; tout(cct) << "ll_fsync" << std::endl; tout(cct) << (unsigned long)fh << std::endl; return _fsync(fh, syncdataonly); } #ifdef FALLOC_FL_PUNCH_HOLE int Client::_fallocate(Fh *fh, int mode, int64_t offset, int64_t length) { if (offset < 0 || length <= 0) return -EINVAL; if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) return -EOPNOTSUPP; if ((mode & FALLOC_FL_PUNCH_HOLE) && !(mode & FALLOC_FL_KEEP_SIZE)) return -EOPNOTSUPP; if (osdmap->test_flag(CEPH_OSDMAP_FULL) && !(mode & FALLOC_FL_PUNCH_HOLE)) return -ENOSPC; Inode *in = fh->inode; if (in->snapid != CEPH_NOSNAP) return -EROFS; if ((fh->mode & CEPH_FILE_MODE_WR) == 0) return -EBADF; int have; int r = get_caps(in, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER, &have, -1); if (r < 0) return r; Mutex uninline_flock("Clinet::_fallocate_uninline_data flock"); Cond uninline_cond; bool uninline_done = false; int uninline_ret = 0; Context *onuninline = NULL; if (mode & FALLOC_FL_PUNCH_HOLE) { if (in->inline_version < CEPH_INLINE_NONE && (have & CEPH_CAP_FILE_BUFFER)) { bufferlist bl; int len = in->inline_data.length(); if (offset < len) { if (offset > 0) in->inline_data.copy(0, offset, bl); int size = length; if (offset + size > len) size = len - offset; if (size > 0) bl.append_zero(size); if (offset + size < len) in->inline_data.copy(offset + size, len - offset - size, bl); in->inline_data = bl; in->inline_version++; } in->mtime = ceph_clock_now(cct); mark_caps_dirty(in, CEPH_CAP_FILE_WR); } else { if (in->inline_version < CEPH_INLINE_NONE) { onuninline = new C_SafeCond(&uninline_flock, &uninline_cond, &uninline_done, &uninline_ret); uninline_data(in, onuninline); } Mutex flock("Client::_punch_hole flock"); Cond cond; bool done = false; Context *onfinish = new C_SafeCond(&flock, &cond, &done); Context *onsafe = new C_Client_SyncCommit(this, in); unsafe_sync_write++; get_cap_ref(in, CEPH_CAP_FILE_BUFFER); _invalidate_inode_cache(in, offset, length); r = filer->zero(in->ino, &in->layout, in->snaprealm->get_snap_context(), offset, length, ceph_clock_now(cct), 0, true, onfinish, onsafe); if (r < 0) goto done; in->mtime = ceph_clock_now(cct); mark_caps_dirty(in, CEPH_CAP_FILE_WR); client_lock.Unlock(); flock.Lock(); while (!done) cond.Wait(flock); flock.Unlock(); client_lock.Lock(); } } else if (!(mode & FALLOC_FL_KEEP_SIZE)) { uint64_t size = offset + length; if (size > in->size) { in->size = size; in->mtime = ceph_clock_now(cct); mark_caps_dirty(in, CEPH_CAP_FILE_WR); if ((in->size << 1) >= in->max_size && (in->reported_size << 1) < in->max_size) check_caps(in, false); } } done: if (onuninline) { client_lock.Unlock(); uninline_flock.Lock(); while (!uninline_done) uninline_cond.Wait(uninline_flock); uninline_flock.Unlock(); client_lock.Lock(); if (uninline_ret >= 0 || uninline_ret == -ECANCELED) { in->inline_data.clear(); in->inline_version = CEPH_INLINE_NONE; mark_caps_dirty(in, CEPH_CAP_FILE_WR); check_caps(in, false); } else r = uninline_ret; } put_cap_ref(in, CEPH_CAP_FILE_WR); return r; } #else int Client::_fallocate(Fh *fh, int mode, int64_t offset, int64_t length) { return -EOPNOTSUPP; } #endif int Client::ll_fallocate(Fh *fh, int mode, loff_t offset, loff_t length) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_fallocate " << fh << " " << fh->inode->ino << " " << dendl; tout(cct) << "ll_fallocate " << mode << " " << offset << " " << length << std::endl; tout(cct) << (unsigned long)fh << std::endl; return _fallocate(fh, mode, offset, length); } int Client::fallocate(int fd, int mode, loff_t offset, loff_t length) { Mutex::Locker lock(client_lock); tout(cct) << "fallocate " << " " << fd << mode << " " << offset << " " << length << std::endl; Fh *fh = get_filehandle(fd); if (!fh) return -EBADF; return _fallocate(fh, mode, offset, length); } int Client::ll_release(Fh *fh) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_release (fh)" << fh << " " << fh->inode->ino << " " << dendl; tout(cct) << "ll_release (fh)" << std::endl; tout(cct) << (unsigned long)fh << std::endl; _release_fh(fh); return 0; } int Client::ll_getlk(Fh *fh, struct flock *fl, uint64_t owner) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_getlk (fh)" << fh << " " << fh->inode->ino << dendl; tout(cct) << "ll_getk (fh)" << (unsigned long)fh << std::endl; return _getlk(fh, fl, owner); } int Client::ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_setlk (fh) " << fh << " " << fh->inode->ino << dendl; tout(cct) << "ll_setk (fh)" << (unsigned long)fh << std::endl; return _setlk(fh, fl, owner, sleep, fuse_req); } int Client::ll_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_flock (fh) " << fh << " " << fh->inode->ino << dendl; tout(cct) << "ll_flock (fh)" << (unsigned long)fh << std::endl; return _flock(fh, cmd, owner, fuse_req); } class C_Client_RequestInterrupt : public Context { private: Client *client; MetaRequest *req; public: C_Client_RequestInterrupt(Client *c, MetaRequest *r) : client(c), req(r) { req->get(); } void finish(int r) { Mutex::Locker l(client->client_lock); assert(req->head.op == CEPH_MDS_OP_SETFILELOCK); client->_interrupt_filelock(req); client->put_request(req); } }; void Client::ll_interrupt(void *d) { MetaRequest *req = static_cast(d); ldout(cct, 3) << "ll_interrupt tid " << req->get_tid() << dendl; tout(cct) << "ll_interrupt tid " << req->get_tid() << std::endl; interrupt_finisher.queue(new C_Client_RequestInterrupt(this, req)); } // ========================================= // layout // expose file layouts int Client::describe_layout(const char *relpath, ceph_file_layout *lp) { Mutex::Locker lock(client_lock); filepath path(relpath); Inode *in; int r = path_walk(path, &in); if (r < 0) return r; *lp = in->layout; ldout(cct, 3) << "describe_layout(" << relpath << ") = 0" << dendl; return 0; } int Client::fdescribe_layout(int fd, ceph_file_layout *lp) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; Inode *in = f->inode; *lp = in->layout; ldout(cct, 3) << "fdescribe_layout(" << fd << ") = 0" << dendl; return 0; } // expose osdmap int64_t Client::get_pool_id(const char *pool_name) { Mutex::Locker lock(client_lock); return osdmap->lookup_pg_pool_name(pool_name); } string Client::get_pool_name(int64_t pool) { Mutex::Locker lock(client_lock); if (!osdmap->have_pg_pool(pool)) return string(); return osdmap->get_pool_name(pool); } int Client::get_pool_replication(int64_t pool) { Mutex::Locker lock(client_lock); if (!osdmap->have_pg_pool(pool)) return -ENOENT; return osdmap->get_pg_pool(pool)->get_size(); } int Client::get_file_extent_osds(int fd, loff_t off, loff_t *len, vector& osds) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; Inode *in = f->inode; vector extents; Striper::file_to_extents(cct, in->ino, &in->layout, off, 1, in->truncate_size, extents); assert(extents.size() == 1); pg_t pg = osdmap->object_locator_to_pg(extents[0].oid, extents[0].oloc); osdmap->pg_to_acting_osds(pg, osds); if (osds.empty()) return -EINVAL; /* * Return the remainder of the extent (stripe unit) * * If length = 1 is passed to Striper::file_to_extents we get a single * extent back, but its length is one so we still need to compute the length * to the end of the stripe unit. * * If length = su then we may get 1 or 2 objects back in the extents vector * which would have to be examined. Even then, the offsets are local to the * object, so matching up to the file offset is extra work. * * It seems simpler to stick with length = 1 and manually compute the * remainder. */ if (len) { uint64_t su = in->layout.fl_stripe_unit; *len = su - (off % su); } return 0; } int Client::get_osd_crush_location(int id, vector >& path) { Mutex::Locker lock(client_lock); if (id < 0) return -EINVAL; return osdmap->crush->get_full_location_ordered(id, path); } int Client::get_file_stripe_address(int fd, loff_t offset, vector& address) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; Inode *in = f->inode; // which object? vector extents; Striper::file_to_extents(cct, in->ino, &in->layout, offset, 1, in->truncate_size, extents); assert(extents.size() == 1); // now we have the object and its 'layout' pg_t pg = osdmap->object_locator_to_pg(extents[0].oid, extents[0].oloc); vector osds; osdmap->pg_to_acting_osds(pg, osds); if (osds.empty()) return -EINVAL; for (unsigned i = 0; i < osds.size(); i++) { entity_addr_t addr = osdmap->get_addr(osds[i]); address.push_back(addr); } return 0; } int Client::get_osd_addr(int osd, entity_addr_t& addr) { Mutex::Locker lock(client_lock); if (!osdmap->exists(osd)) return -ENOENT; addr = osdmap->get_addr(osd); return 0; } int Client::enumerate_layout(int fd, vector& result, loff_t length, loff_t offset) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; Inode *in = f->inode; // map to a list of extents Striper::file_to_extents(cct, in->ino, &in->layout, offset, length, in->truncate_size, result); ldout(cct, 3) << "enumerate_layout(" << fd << ", " << length << ", " << offset << ") = 0" << dendl; return 0; } /* * find an osd with the same ip. -1 if none. */ int Client::get_local_osd() { Mutex::Locker lock(client_lock); if (osdmap->get_epoch() != local_osd_epoch) { local_osd = osdmap->find_osd_on_ip(messenger->get_myaddr()); local_osd_epoch = osdmap->get_epoch(); } return local_osd; } // =============================== void Client::ms_handle_connect(Connection *con) { ldout(cct, 10) << "ms_handle_connect on " << con->get_peer_addr() << dendl; Mutex::Locker l(client_lock); objecter->ms_handle_connect(con); } bool Client::ms_handle_reset(Connection *con) { ldout(cct, 0) << "ms_handle_reset on " << con->get_peer_addr() << dendl; Mutex::Locker l(client_lock); objecter->ms_handle_reset(con); return false; } void Client::ms_handle_remote_reset(Connection *con) { ldout(cct, 0) << "ms_handle_remote_reset on " << con->get_peer_addr() << dendl; Mutex::Locker l(client_lock); switch (con->get_peer_type()) { case CEPH_ENTITY_TYPE_OSD: objecter->ms_handle_remote_reset(con); break; case CEPH_ENTITY_TYPE_MDS: { // kludge to figure out which mds this is; fixme with a Connection* state int mds = -1; MetaSession *s = NULL; for (map::iterator p = mds_sessions.begin(); p != mds_sessions.end(); ++p) { if (mdsmap->get_addr(p->first) == con->get_peer_addr()) { mds = p->first; s = p->second; } } if (mds >= 0) { switch (s->state) { case MetaSession::STATE_CLOSING: ldout(cct, 1) << "reset from mds we were closing; we'll call that closed" << dendl; _closed_mds_session(s); break; case MetaSession::STATE_OPENING: { ldout(cct, 1) << "reset from mds we were opening; retrying" << dendl; list waiters; waiters.swap(s->waiting_for_open); _closed_mds_session(s); MetaSession *news = _get_or_open_mds_session(mds); news->waiting_for_open.swap(waiters); } break; case MetaSession::STATE_OPEN: ldout(cct, 1) << "reset from mds we were open; mark session as stale" << dendl; s->state = MetaSession::STATE_STALE; break; case MetaSession::STATE_NEW: case MetaSession::STATE_CLOSED: default: break; } } } break; } } bool Client::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) { if (dest_type == CEPH_ENTITY_TYPE_MON) return true; *authorizer = monclient->auth->build_authorizer(dest_type); return true; } void Client::set_filer_flags(int flags) { Mutex::Locker l(client_lock); assert(flags == 0 || flags == CEPH_OSD_FLAG_LOCALIZE_READS); objecter->add_global_op_flags(flags); } void Client::clear_filer_flags(int flags) { Mutex::Locker l(client_lock); assert(flags == CEPH_OSD_FLAG_LOCALIZE_READS); objecter->clear_global_op_flag(flags); } ceph-0.80.11/src/client/ClientSnapRealm.cc0000664000175100017510000000177112623076744022300 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "ClientSnapRealm.h" #include "common/Formatter.h" void SnapRealm::dump(Formatter *f) const { f->dump_stream("ino") << ino; f->dump_int("nref", nref); f->dump_stream("created") << created; f->dump_stream("seq") << seq; f->dump_stream("parent_ino") << parent; f->dump_stream("parent_since") << parent_since; f->open_array_section("prior_parent_snaps"); for (vector::const_iterator p = prior_parent_snaps.begin(); p != prior_parent_snaps.end(); ++p) f->dump_stream("snapid") << *p; f->close_section(); f->open_array_section("my_snaps"); for (vector::const_iterator p = my_snaps.begin(); p != my_snaps.end(); ++p) f->dump_stream("snapid") << *p; f->close_section(); f->open_array_section("children"); for (set::const_iterator p = pchildren.begin(); p != pchildren.end(); ++p) f->dump_stream("child") << (*p)->ino; f->close_section(); } ceph-0.80.11/src/client/Dentry.h0000664000175100017510000000212412623076744020357 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLIENT_DENTRY_H #define CEPH_CLIENT_DENTRY_H #include "include/lru.h" class Dir; class Inode; class Dentry : public LRUObject { public: string name; // sort of lame //const char *name; Dir *dir; Inode *inode; int ref; // 1 if there's a dir beneath me. uint64_t offset; int lease_mds; utime_t lease_ttl; uint64_t lease_gen; ceph_seq_t lease_seq; int cap_shared_gen; /* * ref==1 -> cached, unused * ref >1 -> pinned in lru */ void get() { assert(ref > 0); if (++ref == 2) lru_pin(); //cout << "dentry.get on " << this << " " << name << " now " << ref << std::endl; } void put() { assert(ref > 0); if (--ref == 1) lru_unpin(); //cout << "dentry.put on " << this << " " << name << " now " << ref << std::endl; if (ref == 0) delete this; } void dump(Formatter *f) const; Dentry() : dir(0), inode(0), ref(1), offset(0), lease_mds(-1), lease_gen(0), lease_seq(0), cap_shared_gen(0) { } private: ~Dentry() { assert(ref == 0); } }; #endif ceph-0.80.11/src/client/fuse_ll.cc0000664000175100017510000006636512623076744020722 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #define FUSE_USE_VERSION 30 #include #include #include #include #include #include #include #include #include // ceph #include "common/errno.h" #include "common/safe_io.h" #include "include/types.h" #include "Client.h" #include "Fh.h" #include "ioctl.h" #include "common/config.h" #include "include/assert.h" #include "fuse_ll.h" #define FINO_INO(x) ((x) & ((1ull<<48)-1ull)) #define FINO_STAG(x) ((x) >> 48) #define MAKE_FINO(i,s) ((i) | ((s) << 48)) #define MINORBITS 20 #define MINORMASK ((1U << MINORBITS) - 1) #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) static uint32_t new_encode_dev(dev_t dev) { unsigned major = MAJOR(dev); unsigned minor = MINOR(dev); return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); } static dev_t new_decode_dev(uint32_t dev) { unsigned major = (dev & 0xfff00) >> 8; unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00); return MKDEV(major, minor); } class CephFuse::Handle { public: Handle(Client *c, int fd); int init(int argc, const char *argv[]); int loop(); void finalize(); uint64_t fino_snap(uint64_t fino); vinodeno_t fino_vino(inodeno_t fino); uint64_t make_fake_ino(inodeno_t ino, snapid_t snapid); Inode * iget(inodeno_t fino); void iput(Inode *in); int fd_on_success; Client *client; struct fuse_chan *ch; struct fuse_session *se; char *mountpoint; Mutex stag_lock; int last_stag; ceph::unordered_map snap_stag_map; ceph::unordered_map stag_snap_map; }; static void fuse_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); struct fuse_entry_param fe; Inode *i2, *i1 = cfuse->iget(parent); // see below int r; memset(&fe, 0, sizeof(fe)); r = cfuse->client->ll_lookup(i1, name, &fe.attr, &i2, ctx->uid, ctx->gid); if (r >= 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); } // XXX NB, we dont iput(i2) because FUSE will do so in a matching // fuse_ll_forget() cfuse->iput(i1); } static void fuse_ll_forget(fuse_req_t req, fuse_ino_t ino, long unsigned nlookup) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); cfuse->client->ll_forget(cfuse->iget(ino), nlookup+1); fuse_reply_none(req); } static void fuse_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); struct stat stbuf; (void) fi; // XXX if (cfuse->client->ll_getattr(in, &stbuf, ctx->uid, ctx->gid) == 0) { stbuf.st_ino = cfuse->make_fake_ino(stbuf.st_ino, stbuf.st_dev); stbuf.st_rdev = new_encode_dev(stbuf.st_rdev); fuse_reply_attr(req, &stbuf, 0); } else fuse_reply_err(req, ENOENT); cfuse->iput(in); // iput required } static void fuse_ll_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); int mask = 0; if (to_set & FUSE_SET_ATTR_MODE) mask |= CEPH_SETATTR_MODE; if (to_set & FUSE_SET_ATTR_UID) mask |= CEPH_SETATTR_UID; if (to_set & FUSE_SET_ATTR_GID) mask |= CEPH_SETATTR_GID; if (to_set & FUSE_SET_ATTR_MTIME) mask |= CEPH_SETATTR_MTIME; if (to_set & FUSE_SET_ATTR_ATIME) mask |= CEPH_SETATTR_ATIME; if (to_set & FUSE_SET_ATTR_SIZE) mask |= CEPH_SETATTR_SIZE; int r = cfuse->client->ll_setattr(in, attr, mask, ctx->uid, ctx->gid); if (r == 0) fuse_reply_attr(req, attr, 0); else fuse_reply_err(req, -r); cfuse->iput(in); // iput required } // XATTRS static void fuse_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); int r = cfuse->client->ll_setxattr(in, name, value, size, flags, ctx->uid, ctx->gid); fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); char buf[size]; int r = cfuse->client->ll_listxattr(in, buf, size, ctx->uid, ctx->gid); if (size == 0 && r >= 0) fuse_reply_xattr(req, r); else if (r >= 0) fuse_reply_buf(req, buf, r); else fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); char buf[size]; int r = cfuse->client->ll_getxattr(in, name, buf, size, ctx->uid, ctx->gid); if (size == 0 && r >= 0) fuse_reply_xattr(req, r); else if (r >= 0) fuse_reply_buf(req, buf, r); else fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); int r = cfuse->client->ll_removexattr(in, name, ctx->uid, ctx->gid); fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); void *dirp; int r = cfuse->client->ll_opendir(in, (dir_result_t **) &dirp, ctx->uid, ctx->gid); if (r >= 0) { fi->fh = (long)dirp; fuse_reply_open(req, fi); } else { fuse_reply_err(req, -r); } cfuse->iput(in); // iput required } static void fuse_ll_readlink(fuse_req_t req, fuse_ino_t ino) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); char buf[PATH_MAX + 1]; // leave room for a null terminator int r = cfuse->client->ll_readlink(in, buf, sizeof(buf) - 1, ctx->uid, ctx->gid); if (r >= 0) { buf[r] = '\0'; fuse_reply_readlink(req, buf); } else { fuse_reply_err(req, -r); } cfuse->iput(in); // iput required } static void fuse_ll_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i2, *i1 = cfuse->iget(parent); struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); int r = cfuse->client->ll_mknod(i1, name, mode, new_decode_dev(rdev), &fe.attr, &i2, ctx->uid, ctx->gid); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); } // XXX NB, we dont iput(i2) because FUSE will do so in a matching // fuse_ll_forget() cfuse->iput(i1); // iput required } static void fuse_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i2, *i1 = cfuse->iget(parent); struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); int r = cfuse->client->ll_mkdir(i1, name, mode, &fe.attr, &i2, ctx->uid, ctx->gid); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); } // XXX NB, we dont iput(i2) because FUSE will do so in a matching // fuse_ll_forget() cfuse->iput(i1); // iput required } static void fuse_ll_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(parent); int r = cfuse->client->ll_unlink(in, name, ctx->uid, ctx->gid); fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(parent); int r = cfuse->client->ll_rmdir(in, name, ctx->uid, ctx->gid); fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_symlink(fuse_req_t req, const char *existing, fuse_ino_t parent, const char *name) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i2, *i1 = cfuse->iget(parent); struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); int r = cfuse->client->ll_symlink(i1, name, existing, &fe.attr, &i2, ctx->uid, ctx->gid); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); } // XXX NB, we dont iput(i2) because FUSE will do so in a matching // fuse_ll_forget() cfuse->iput(i1); // iput required } static void fuse_ll_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(parent); Inode *nin = cfuse->iget(newparent); int r = cfuse->client->ll_rename(in, name, nin, newname, ctx->uid, ctx->gid); fuse_reply_err(req, -r); cfuse->iput(in); // iputs required cfuse->iput(nin); } static void fuse_ll_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); Inode *nin = cfuse->iget(newparent); struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); int r = cfuse->client->ll_link(in, nin, newname, &fe.attr, ctx->uid, ctx->gid); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); } cfuse->iput(in); // iputs required cfuse->iput(nin); } static void fuse_ll_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); Fh *fh = NULL; int r = cfuse->client->ll_open(in, fi->flags, &fh, ctx->uid, ctx->gid); if (r == 0) { fi->fh = (long)fh; #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) if (cfuse->client->cct->_conf->fuse_use_invalidate_cb) fi->keep_cache = 1; #endif fuse_reply_open(req, fi); } else { fuse_reply_err(req, -r); } cfuse->iput(in); // iput required } static void fuse_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; bufferlist bl; int r = cfuse->client->ll_read(fh, off, size, &bl); if (r >= 0) fuse_reply_buf(req, bl.c_str(), bl.length()); else fuse_reply_err(req, -r); } static void fuse_ll_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; int r = cfuse->client->ll_write(fh, off, size, buf); if (r >= 0) fuse_reply_write(req, r); else fuse_reply_err(req, -r); } static void fuse_ll_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { // NOOP fuse_reply_err(req, 0); } #ifdef FUSE_IOCTL_COMPAT static void fuse_ll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); if (flags & FUSE_IOCTL_COMPAT) { fuse_reply_err(req, ENOSYS); return; } switch(cmd) { case CEPH_IOC_GET_LAYOUT: { struct ceph_file_layout layout; struct ceph_ioctl_layout l; Fh *fh = (Fh*)fi->fh; cfuse->client->ll_file_layout(fh->inode, &layout); l.stripe_unit = layout.fl_stripe_unit; l.stripe_count = layout.fl_stripe_count; l.object_size = layout.fl_object_size; l.data_pool = layout.fl_pg_pool; fuse_reply_ioctl(req, 0, &l, sizeof(struct ceph_ioctl_layout)); } break; default: fuse_reply_err(req, EINVAL); } } #endif #if FUSE_VERSION > FUSE_MAKE_VERSION(2, 9) static void fuse_ll_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; int r = cfuse->client->ll_fallocate(fh, mode, offset, length); fuse_reply_err(req, -r); } #endif static void fuse_ll_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; int r = cfuse->client->ll_release(fh); fuse_reply_err(req, -r); } static void fuse_ll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; int r = cfuse->client->ll_fsync(fh, datasync); fuse_reply_err(req, -r); } struct readdir_context { fuse_req_t req; char *buf; size_t size; size_t pos; /* in buf */ uint64_t snap; }; /* * return 0 on success, -1 if out of space */ static int fuse_ll_add_dirent(void *p, struct dirent *de, struct stat *st, int stmask, off_t next_off) { struct readdir_context *c = (struct readdir_context *)p; CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(c->req); st->st_ino = cfuse->make_fake_ino(de->d_ino, c->snap); st->st_mode = DTTOIF(de->d_type); st->st_rdev = new_encode_dev(st->st_rdev); size_t room = c->size - c->pos; size_t entrysize = fuse_add_direntry(c->req, c->buf + c->pos, room, de->d_name, st, next_off); if (entrysize > room) return -ENOSPC; /* success */ c->pos += entrysize; return 0; } static void fuse_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); dir_result_t *dirp = (dir_result_t*)fi->fh; cfuse->client->seekdir(dirp, off); struct readdir_context rc; rc.req = req; rc.buf = new char[size]; rc.size = size; rc.pos = 0; rc.snap = cfuse->fino_snap(ino); int r = cfuse->client->readdir_r_cb(dirp, fuse_ll_add_dirent, &rc); if (r == 0 || r == -ENOSPC) /* ignore ENOSPC from our callback */ fuse_reply_buf(req, rc.buf, rc.pos); else fuse_reply_err(req, -r); delete[] rc.buf; } static void fuse_ll_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); dir_result_t *dirp = (dir_result_t*)fi->fh; cfuse->client->ll_releasedir(dirp); fuse_reply_err(req, 0); } static void fuse_ll_access(fuse_req_t req, fuse_ino_t ino, int mask) { fuse_reply_err(req, 0); } static void fuse_ll_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i1 = cfuse->iget(parent), *i2; struct fuse_entry_param fe; Fh *fh = NULL; memset(&fe, 0, sizeof(fe)); // pass &i2 for the created inode so that ll_create takes an initial ll_ref int r = cfuse->client->ll_create(i1, name, mode, fi->flags, &fe.attr, &i2, &fh, ctx->uid, ctx->gid); if (r == 0) { fi->fh = (long)fh; fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fuse_reply_create(req, &fe, fi); } else fuse_reply_err(req, -r); // XXX NB, we dont iput(i2) because FUSE will do so in a matching // fuse_ll_forget() cfuse->iput(i1); // iput required } static void fuse_ll_statfs(fuse_req_t req, fuse_ino_t ino) { struct statvfs stbuf; CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Inode *in = cfuse->iget(ino); int r = cfuse->client->ll_statfs(in, &stbuf); if (r == 0) fuse_reply_statfs(req, &stbuf); else fuse_reply_err(req, -r); cfuse->iput(in); // iput required } static void fuse_ll_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; int r = cfuse->client->ll_getlk(fh, lock, fi->lock_owner); if (r == 0) fuse_reply_lock(req, lock); else fuse_reply_err(req, -r); } static void fuse_ll_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; // must use multithread if operation may block if (!cfuse->client->cct->_conf->fuse_multithreaded && sleep && lock->l_type != F_UNLCK) { fuse_reply_err(req, EDEADLK); return; } int r = cfuse->client->ll_setlk(fh, lock, fi->lock_owner, sleep, req); fuse_reply_err(req, -r); } static void fuse_ll_interrupt(fuse_req_t req, void* data) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); cfuse->client->ll_interrupt(data); } static void switch_interrupt_cb(void *req, void* data) { if (data) fuse_req_interrupt_func((fuse_req_t)req, fuse_ll_interrupt, data); else fuse_req_interrupt_func((fuse_req_t)req, NULL, NULL); } #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) static void fuse_ll_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int cmd) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); Fh *fh = (Fh*)fi->fh; // must use multithread if operation may block if (!cfuse->client->cct->_conf->fuse_multithreaded && !(cmd & (LOCK_NB | LOCK_UN))) { fuse_reply_err(req, EDEADLK); return; } int r = cfuse->client->ll_flock(fh, cmd, fi->lock_owner, req); fuse_reply_err(req, -r); } #endif #if 0 static int getgroups_cb(void *handle, uid_t uid, gid_t **sgids) { #ifdef HAVE_FUSE_GETGROUPS assert(sgids); int c = fuse_getgroups(0, NULL); if (c < 0) { return c; } if (c == 0) { return 0; } *sgids = (gid_t*)malloc(c*sizeof(**sgids)); if (!*sgids) { return -ENOMEM; } c = fuse_getgroups(c, *sgids); if (c < 0) { free(*sgids); return c; } return c; #endif return 0; } #endif static void ino_invalidate_cb(void *handle, vinodeno_t vino, int64_t off, int64_t len) { #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) CephFuse::Handle *cfuse = (CephFuse::Handle *)handle; fuse_ino_t fino = cfuse->make_fake_ino(vino.ino, vino.snapid); fuse_lowlevel_notify_inval_inode(cfuse->ch, fino, off, len); #endif } static void dentry_invalidate_cb(void *handle, vinodeno_t dirino, vinodeno_t ino, string& name) { CephFuse::Handle *cfuse = (CephFuse::Handle *)handle; fuse_ino_t fdirino = cfuse->make_fake_ino(dirino.ino, dirino.snapid); #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) fuse_ino_t fino = 0; if (ino.ino != inodeno_t()) fino = cfuse->make_fake_ino(ino.ino, ino.snapid); fuse_lowlevel_notify_delete(cfuse->ch, fdirino, fino, name.c_str(), name.length()); #elif FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) fuse_lowlevel_notify_inval_entry(cfuse->ch, fdirino, name.c_str(), name.length()); #endif } static void do_init(void *data, fuse_conn_info *bar) { CephFuse::Handle *cfuse = (CephFuse::Handle *)data; if (cfuse->fd_on_success) { //cout << "fuse init signaling on fd " << fd_on_success << std::endl; uint32_t r = 0; int err = safe_write(cfuse->fd_on_success, &r, sizeof(r)); if (err) { derr << "fuse_ll: do_init: safe_write failed with error " << cpp_strerror(err) << dendl; ceph_abort(); } //cout << "fuse init done signaling on fd " << fd_on_success << std::endl; // close stdout, etc. ::close(0); ::close(1); ::close(2); } } const static struct fuse_lowlevel_ops fuse_ll_oper = { init: do_init, destroy: 0, lookup: fuse_ll_lookup, forget: fuse_ll_forget, getattr: fuse_ll_getattr, setattr: fuse_ll_setattr, readlink: fuse_ll_readlink, mknod: fuse_ll_mknod, mkdir: fuse_ll_mkdir, unlink: fuse_ll_unlink, rmdir: fuse_ll_rmdir, symlink: fuse_ll_symlink, rename: fuse_ll_rename, link: fuse_ll_link, open: fuse_ll_open, read: fuse_ll_read, write: fuse_ll_write, flush: fuse_ll_flush, release: fuse_ll_release, fsync: fuse_ll_fsync, opendir: fuse_ll_opendir, readdir: fuse_ll_readdir, releasedir: fuse_ll_releasedir, fsyncdir: 0, statfs: fuse_ll_statfs, setxattr: fuse_ll_setxattr, getxattr: fuse_ll_getxattr, listxattr: fuse_ll_listxattr, removexattr: fuse_ll_removexattr, access: fuse_ll_access, create: fuse_ll_create, getlk: fuse_ll_getlk, setlk: fuse_ll_setlk, bmap: 0, #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) #ifdef FUSE_IOCTL_COMPAT ioctl: fuse_ll_ioctl, #else ioctl: 0, #endif poll: 0, #endif #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) write_buf: 0, retrieve_reply: 0, forget_multi: 0, flock: fuse_ll_flock, #endif #if FUSE_VERSION > FUSE_MAKE_VERSION(2, 9) fallocate: fuse_ll_fallocate #endif }; CephFuse::Handle::Handle(Client *c, int fd) : fd_on_success(fd), client(c), ch(NULL), se(NULL), mountpoint(NULL), stag_lock("fuse_ll.cc stag_lock"), last_stag(0) { snap_stag_map[CEPH_NOSNAP] = 0; stag_snap_map[0] = CEPH_NOSNAP; } void CephFuse::Handle::finalize() { client->ll_register_ino_invalidate_cb(NULL, NULL); if (se) fuse_remove_signal_handlers(se); if (ch) fuse_session_remove_chan(ch); if (se) fuse_session_destroy(se); if (ch) fuse_unmount(mountpoint, ch); } int CephFuse::Handle::init(int argc, const char *argv[]) { // set up fuse argc/argv int newargc = 0; const char **newargv = (const char **) malloc((argc + 10) * sizeof(char *)); if(!newargv) return ENOMEM; newargv[newargc++] = argv[0]; newargv[newargc++] = "-f"; // stay in foreground if (client->cct->_conf->fuse_allow_other) { newargv[newargc++] = "-o"; newargv[newargc++] = "allow_other"; } if (client->cct->_conf->fuse_default_permissions) { newargv[newargc++] = "-o"; newargv[newargc++] = "default_permissions"; } if (client->cct->_conf->fuse_big_writes) { newargv[newargc++] = "-o"; newargv[newargc++] = "big_writes"; } if (client->cct->_conf->fuse_atomic_o_trunc) { newargv[newargc++] = "-o"; newargv[newargc++] = "atomic_o_trunc"; } if (client->cct->_conf->fuse_debug) newargv[newargc++] = "-d"; for (int argctr = 1; argctr < argc; argctr++) newargv[newargc++] = argv[argctr]; struct fuse_args args = FUSE_ARGS_INIT(newargc, (char**)newargv); int ret = 0; char *mountpoint; if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) == -1) { derr << "fuse_parse_cmdline failed." << dendl; ret = EINVAL; goto done; } ch = fuse_mount(mountpoint, &args); if (!ch) { derr << "fuse_mount(mountpoint=" << mountpoint << ") failed." << dendl; ret = EIO; goto done; } se = fuse_lowlevel_new(&args, &fuse_ll_oper, sizeof(fuse_ll_oper), this); if (!se) { derr << "fuse_lowlevel_new failed" << dendl; ret = EDOM; goto done; } signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); if (fuse_set_signal_handlers(se) == -1) { derr << "fuse_set_signal_handlers failed" << dendl; ret = ENOSYS; goto done; } fuse_session_add_chan(se, ch); client->ll_register_switch_interrupt_cb(switch_interrupt_cb); /* * this is broken: * * - the cb needs the request handle to be useful; we should get the * gids in the method here in fuse_ll.c and pass the gid list in, * not use a callback. * - the callback mallocs the list but it is not free()'d * * so disable it for now... client->ll_register_getgroups_cb(getgroups_cb, this); */ client->ll_register_dentry_invalidate_cb(dentry_invalidate_cb, this); if (client->cct->_conf->fuse_use_invalidate_cb) client->ll_register_ino_invalidate_cb(ino_invalidate_cb, this); done: fuse_opt_free_args(&args); free(newargv); return ret; } int CephFuse::Handle::loop() { if (client->cct->_conf->fuse_multithreaded) { return fuse_session_loop_mt(se); } else { return fuse_session_loop(se); } } uint64_t CephFuse::Handle::fino_snap(uint64_t fino) { Mutex::Locker l(stag_lock); uint64_t stag = FINO_STAG(fino); assert(stag_snap_map.count(stag)); return stag_snap_map[stag]; } vinodeno_t CephFuse::Handle::fino_vino(inodeno_t fino) { if (fino.val == 1) { fino = inodeno_t(client->get_root_ino()); } vinodeno_t vino(FINO_INO(fino), fino_snap(fino)); //cout << "fino_vino " << fino << " -> " << vino << std::endl; return vino; } Inode * CephFuse::Handle::iget(inodeno_t fino) { Inode *in = client->ll_get_inode(fino_vino(fino)); return in; } void CephFuse::Handle::iput(Inode *in) { client->ll_put(in); } uint64_t CephFuse::Handle::make_fake_ino(inodeno_t ino, snapid_t snapid) { Mutex::Locker l(stag_lock); uint64_t stag; if (snap_stag_map.count(snapid) == 0) { stag = ++last_stag; snap_stag_map[snapid] = stag; stag_snap_map[stag] = snapid; } else stag = snap_stag_map[snapid]; inodeno_t fino = MAKE_FINO(ino, stag); //cout << "make_fake_ino " << ino << "." << snapid << " -> " << fino << std::endl; return fino; } CephFuse::CephFuse(Client *c, int fd) : _handle(new CephFuse::Handle(c, fd)) { } CephFuse::~CephFuse() { delete _handle; } int CephFuse::init(int argc, const char *argv[]) { return _handle->init(argc, argv); } int CephFuse::loop() { return _handle->loop(); } void CephFuse::finalize() { return _handle->finalize(); } ceph-0.80.11/src/client/Client.h0000664000175100017510000007242512623076744020343 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CLIENT_H #define CEPH_CLIENT_H #include "include/types.h" // stl #include #include #include #include #include #include using std::set; using std::map; using std::fstream; #include "include/unordered_map.h" #include "include/filepath.h" #include "include/interval_set.h" #include "include/lru.h" //#include "barrier.h" #include "mds/mdstypes.h" #include "msg/Message.h" #include "msg/Dispatcher.h" #include "msg/Messenger.h" #include "common/Mutex.h" #include "common/Timer.h" #include "common/Finisher.h" #include "common/compiler_extensions.h" #include "common/cmdparse.h" #include "osdc/ObjectCacher.h" class MDSMap; class OSDMap; class MonClient; class CephContext; class MClientReply; class MClientRequest; class MClientSession; class MClientRequest; class MClientRequestForward; struct MClientLease; class MClientCaps; class MClientCapRelease; struct DirStat; struct LeaseStat; struct InodeStat; class Filer; class Objecter; class WritebackHandler; class PerfCounters; enum { l_c_first = 20000, l_c_reply, l_c_lat, l_c_owrlat, l_c_ordlat, l_c_wrlat, l_c_last, }; // ============================================ // types for my local metadata cache /* basic structure: - Dentries live in an LRU loop. they get expired based on last access. see include/lru.h. items can be bumped to "mid" or "top" of list, etc. - Inode has ref count for each Fh, Dir, or Dentry that points to it. - when Inode ref goes to 0, it's expired. - when Dir is empty, it's removed (and it's Inode ref--) */ /* getdir result */ struct DirEntry { string d_name; struct stat st; int stmask; DirEntry(const string &s) : d_name(s), stmask(0) {} DirEntry(const string &n, struct stat& s, int stm) : d_name(n), st(s), stmask(stm) {} }; class Inode; struct Cap; class Dir; class Dentry; struct SnapRealm; struct Fh; struct CapSnap; struct MetaSession; struct MetaRequest; class ceph_lock_state_t; typedef void (*client_ino_callback_t)(void *handle, vinodeno_t ino, int64_t off, int64_t len); typedef void (*client_dentry_callback_t)(void *handle, vinodeno_t dirino, vinodeno_t ino, string& name); typedef int (*client_getgroups_callback_t)(void *handle, uid_t uid, gid_t **sgids); typedef void(*client_switch_interrupt_callback_t)(void *req, void *data); // ======================================================== // client interface struct dir_result_t { static const int SHIFT = 28; static const int64_t MASK = (1 << SHIFT) - 1; static const loff_t END = 1ULL << (SHIFT + 32); static uint64_t make_fpos(unsigned frag, unsigned off) { return ((uint64_t)frag << SHIFT) | (uint64_t)off; } static unsigned fpos_frag(uint64_t p) { return (p & ~END) >> SHIFT; } static unsigned fpos_off(uint64_t p) { return p & MASK; } Inode *inode; int64_t offset; // high bits: frag_t, low bits: an offset uint64_t this_offset; // offset of last chunk, adjusted for . and .. uint64_t next_offset; // offset of next chunk (last_name's + 1) string last_name; // last entry in previous chunk uint64_t release_count; int start_shared_gen; // dir shared_gen at start of readdir frag_t buffer_frag; vector > *buffer; string at_cache_name; // last entry we successfully returned dir_result_t(Inode *in); frag_t frag() { return frag_t(offset >> SHIFT); } unsigned fragpos() { return offset & MASK; } void next_frag() { frag_t fg = offset >> SHIFT; if (fg.is_rightmost()) set_end(); else set_frag(fg.next()); } void set_frag(frag_t f) { offset = (uint64_t)f << SHIFT; assert(sizeof(offset) == 8); } void set_end() { offset |= END; } bool at_end() { return (offset & END); } void reset() { last_name.clear(); at_cache_name.clear(); next_offset = 2; this_offset = 0; offset = 0; delete buffer; buffer = 0; } }; class Client : public Dispatcher { public: CephContext *cct; PerfCounters *logger; class CommandHook : public AdminSocketHook { Client *m_client; public: CommandHook(Client *client); bool call(std::string command, cmdmap_t &cmdmap, std::string format, bufferlist& out); }; CommandHook m_command_hook; // cluster descriptors MDSMap *mdsmap; OSDMap *osdmap; SafeTimer timer; client_switch_interrupt_callback_t switch_interrupt_cb; client_ino_callback_t ino_invalidate_cb; void *ino_invalidate_cb_handle; client_dentry_callback_t dentry_invalidate_cb; void *dentry_invalidate_cb_handle; client_getgroups_callback_t getgroups_cb; void *getgroups_cb_handle; Finisher async_ino_invalidator; Finisher async_dentry_invalidator; Finisher interrupt_finisher; Context *tick_event; utime_t last_cap_renew; void renew_caps(); void renew_caps(MetaSession *session); void flush_cap_releases(); public: void tick(); protected: MonClient *monclient; Messenger *messenger; client_t whoami; // mds sessions map mds_sessions; // mds -> push seq list waiting_for_mdsmap; bool have_open_session(int mds); void got_mds_push(MetaSession *s); MetaSession *_get_mds_session(int mds, Connection *con); ///< return session for mds *and* con; null otherwise MetaSession *_get_or_open_mds_session(int mds); MetaSession *_open_mds_session(int mds); void _close_mds_session(MetaSession *s); void _closed_mds_session(MetaSession *s); void _kick_stale_sessions(); void handle_client_session(MClientSession *m); void send_reconnect(MetaSession *s); void resend_unsafe_requests(MetaSession *s); // mds requests ceph_tid_t last_tid, last_flush_seq; map mds_requests; set failed_mds; void dump_mds_requests(Formatter *f); void dump_mds_sessions(Formatter *f); int make_request(MetaRequest *req, int uid, int gid, //MClientRequest *req, int uid, int gid, Inode **ptarget = 0, bool *pcreated = 0, int use_mds=-1, bufferlist *pdirbl=0); void put_request(MetaRequest *request); int verify_reply_trace(int r, MetaRequest *request, MClientReply *reply, Inode **ptarget, bool *pcreated, int uid, int gid); void encode_cap_releases(MetaRequest *request, int mds); int encode_inode_release(Inode *in, MetaRequest *req, int mds, int drop, int unless,int force=0); void encode_dentry_release(Dentry *dn, MetaRequest *req, int mds, int drop, int unless); int choose_target_mds(MetaRequest *req); void connect_mds_targets(int mds); void send_request(MetaRequest *request, MetaSession *session); MClientRequest *build_client_request(MetaRequest *request); void kick_requests(MetaSession *session); void kick_requests_closed(MetaSession *session); void handle_client_request_forward(MClientRequestForward *reply); void handle_client_reply(MClientReply *reply); bool initialized; bool mounted; bool unmounting; int local_osd; epoch_t local_osd_epoch; int unsafe_sync_write; public: entity_name_t get_myname() { return messenger->get_myname(); } void sync_write_commit(Inode *in); protected: Filer *filer; ObjectCacher *objectcacher; Objecter *objecter; // (non-blocking) osd interface WritebackHandler *writeback_handler; // cache ceph::unordered_map inode_map; Inode* root; LRU lru; // lru list of Dentry's in our local metadata cache. // all inodes with caps sit on either cap_list or delayed_caps. xlist delayed_caps, cap_list; int num_flushing_caps; ceph::unordered_map snap_realms; /* async block write barrier support */ //map barriers; SnapRealm *get_snap_realm(inodeno_t r); SnapRealm *get_snap_realm_maybe(inodeno_t r); void put_snap_realm(SnapRealm *realm); bool adjust_realm_parent(SnapRealm *realm, inodeno_t parent); inodeno_t update_snap_trace(bufferlist& bl, bool must_flush=true); inodeno_t _update_snap_trace(vector& trace); void invalidate_snaprealm_and_children(SnapRealm *realm); Inode *open_snapdir(Inode *diri); // file handles, etc. interval_set free_fd_set; // unused fds ceph::unordered_map fd_map; int get_fd() { int fd = free_fd_set.range_start(); free_fd_set.erase(fd, 1); return fd; } void put_fd(int fd) { free_fd_set.insert(fd, 1); } /* * Resolve file descriptor, or return NULL. */ Fh *get_filehandle(int fd) { ceph::unordered_map::iterator p = fd_map.find(fd); if (p == fd_map.end()) return NULL; return p->second; } // global client lock // - protects Client and buffer cache both! Mutex client_lock; // helpers void wake_inode_waiters(MetaSession *s); void wait_on_list(list& ls); void signal_cond_list(list& ls); void wait_on_context_list(list& ls); void signal_context_list(list& ls); // -- metadata cache stuff // decrease inode ref. delete if dangling. void put_inode(Inode *in, int n=1); void close_dir(Dir *dir); friend class C_Client_PutInode; // calls put_inode() friend class C_Client_CacheInvalidate; // calls ino_invalidate_cb friend class C_Client_DentryInvalidate; // calls dentry_invalidate_cb friend class C_Block_Sync; // Calls block map and protected helpers friend class C_Client_RequestInterrupt; //int get_cache_size() { return lru.lru_get_size(); } //void set_cache_size(int m) { lru.lru_set_max(m); } /** * Don't call this with in==NULL, use get_or_create for that * leave dn set to default NULL unless you're trying to add * a new inode to a pre-created Dentry */ Dentry* link(Dir *dir, const string& name, Inode *in, Dentry *dn); void unlink(Dentry *dn, bool keepdir); // path traversal for high-level interface Inode *cwd; int path_walk(const filepath& fp, Inode **end, bool followsym=true); int fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0); void touch_dn(Dentry *dn); // trim cache. void trim_cache(); void trim_dentry(Dentry *dn); void trim_caps(MetaSession *s, int max); void dump_inode(Formatter *f, Inode *in, set& did, bool disconnected); void dump_cache(Formatter *f); // debug // trace generation ofstream traceout; Cond mount_cond, sync_cond; // friends friend class SyntheticClient; bool ms_dispatch(Message *m); void ms_handle_connect(Connection *con); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con); bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); public: void set_filer_flags(int flags); void clear_filer_flags(int flags); Client(Messenger *m, MonClient *mc); ~Client(); void tear_down_cache(); client_t get_nodeid() { return whoami; } inodeno_t get_root_ino(); Inode *get_root(); int init() WARN_UNUSED_RESULT; void shutdown(); // messaging void handle_mds_map(class MMDSMap *m); void handle_lease(MClientLease *m); // inline data int uninline_data(Inode *in, Context *onfinish); // file caps void check_cap_issue(Inode *in, Cap *cap, unsigned issued); void add_update_cap(Inode *in, MetaSession *session, uint64_t cap_id, unsigned issued, unsigned seq, unsigned mseq, inodeno_t realm, int flags); void remove_cap(Cap *cap, bool queue_release); void remove_all_caps(Inode *in); void remove_session_caps(MetaSession *session); void mark_caps_dirty(Inode *in, int caps); int mark_caps_flushing(Inode *in); void flush_caps(); void flush_caps(Inode *in, MetaSession *session); void kick_flushing_caps(MetaSession *session); void kick_maxsize_requests(MetaSession *session); int get_caps(Inode *in, int need, int want, int *have, loff_t endoff); int get_caps_used(Inode *in); void maybe_update_snaprealm(SnapRealm *realm, snapid_t snap_created, snapid_t snap_highwater, vector& snaps); void handle_snap(struct MClientSnap *m); void handle_caps(class MClientCaps *m); void handle_cap_import(MetaSession *session, Inode *in, class MClientCaps *m); void handle_cap_export(MetaSession *session, Inode *in, class MClientCaps *m); void handle_cap_trunc(MetaSession *session, Inode *in, class MClientCaps *m); void handle_cap_flush_ack(MetaSession *session, Inode *in, Cap *cap, class MClientCaps *m); void handle_cap_flushsnap_ack(MetaSession *session, Inode *in, class MClientCaps *m); void handle_cap_grant(MetaSession *session, Inode *in, Cap *cap, class MClientCaps *m); void cap_delay_requeue(Inode *in); void send_cap(Inode *in, MetaSession *session, Cap *cap, int used, int want, int retain, int flush); void check_caps(Inode *in, bool is_delayed); void get_cap_ref(Inode *in, int cap); void put_cap_ref(Inode *in, int cap); void flush_snaps(Inode *in, bool all_again=false, CapSnap *again=0); void wait_sync_caps(uint64_t want); void queue_cap_snap(Inode *in, snapid_t seq=0); void finish_cap_snap(Inode *in, CapSnap *capsnap, int used); void _flushed_cap_snap(Inode *in, snapid_t seq); void _schedule_invalidate_dentry_callback(Dentry *dn, bool del); void _async_dentry_invalidate(vinodeno_t dirino, vinodeno_t ino, string& name); void _invalidate_inode_parents(Inode *in); void _schedule_invalidate_callback(Inode *in, int64_t off, int64_t len, bool keep_caps); void _invalidate_inode_cache(Inode *in); void _invalidate_inode_cache(Inode *in, int64_t off, int64_t len); void _async_invalidate(Inode *in, int64_t off, int64_t len, bool keep_caps); void _release(Inode *in); /** * Initiate a flush of the data associated with the given inode. * If you specify a Context, you are responsible for holding an inode * reference for the duration of the flush. If not, _flush() will * take the reference for you. * @param in The Inode whose data you wish to flush. * @param c The Context you wish us to complete once the data is * flushed. If already flushed, this will be called in-line. * * @returns true if the data was already flushed, false otherwise. */ bool _flush(Inode *in, Context *c=NULL); void _flush_range(Inode *in, int64_t off, uint64_t size); void _flushed(Inode *in); void flush_set_callback(ObjectCacher::ObjectSet *oset); void close_release(Inode *in); void close_safe(Inode *in); void lock_fh_pos(Fh *f); void unlock_fh_pos(Fh *f); // metadata cache void update_dir_dist(Inode *in, DirStat *st); void insert_readdir_results(MetaRequest *request, MetaSession *session, Inode *diri); Inode* insert_trace(MetaRequest *request, MetaSession *session); void update_inode_file_bits(Inode *in, uint64_t truncate_seq, uint64_t truncate_size, uint64_t size, uint64_t time_warp_seq, utime_t ctime, utime_t mtime, utime_t atime, version_t inline_version, bufferlist& inline_data, int issued); Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session); Dentry *insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease, Inode *in, utime_t from, MetaSession *session, bool set_offset, Dentry *old_dentry = NULL); void update_dentry_lease(Dentry *dn, LeaseStat *dlease, utime_t from, MetaSession *session); // ---------------------- // fs ops. private: void fill_dirent(struct dirent *de, const char *name, int type, uint64_t ino, loff_t next_off); // some readdir helpers typedef int (*add_dirent_cb_t)(void *p, struct dirent *de, struct stat *st, int stmask, off_t off); int _opendir(Inode *in, dir_result_t **dirpp, int uid=-1, int gid=-1); void _readdir_drop_dirp_buffer(dir_result_t *dirp); bool _readdir_have_frag(dir_result_t *dirp); void _readdir_next_frag(dir_result_t *dirp); void _readdir_rechoose_frag(dir_result_t *dirp); int _readdir_get_frag(dir_result_t *dirp); int _readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p); void _closedir(dir_result_t *dirp); // other helpers void _fragmap_remove_non_leaves(Inode *in); void _ll_get(Inode *in); int _ll_put(Inode *in, int num); void _ll_drop_pins(); Fh *_create_fh(Inode *in, int flags, int cmode); int _release_fh(Fh *fh); struct C_Readahead : public Context { Client *client; Inode *inode; C_Readahead(Client *c, Inode *i) : client(c), inode(i) { } void finish(int r) { lsubdout(client->cct, client, 20) << "C_Readahead on " << inode << dendl; client->put_cap_ref(inode, CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE); } }; int _read_sync(Fh *f, uint64_t off, uint64_t len, bufferlist *bl, bool *checkeof); int _read_async(Fh *f, uint64_t off, uint64_t len, bufferlist *bl); // internal interface // call these with client_lock held! int _do_lookup(Inode *dir, const string& name, Inode **target); int _lookup(Inode *dir, const string& dname, Inode **target); int _link(Inode *in, Inode *dir, const char *name, int uid=-1, int gid=-1, Inode **inp = 0); int _unlink(Inode *dir, const char *name, int uid=-1, int gid=-1); int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, int uid=-1, int gid=-1); int _mkdir(Inode *dir, const char *name, mode_t mode, int uid=-1, int gid=-1, Inode **inp = 0); int _rmdir(Inode *dir, const char *name, int uid=-1, int gid=-1); int _symlink(Inode *dir, const char *name, const char *target, int uid=-1, int gid=-1, Inode **inp = 0); int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int uid=-1, int gid=-1, Inode **inp = 0); int _setattr(Inode *in, struct stat *attr, int mask, int uid=-1, int gid=-1, Inode **inp = 0); int _getattr(Inode *in, int mask, int uid=-1, int gid=-1, bool force=false); int _readlink(Inode *in, char *buf, size_t size); int _getxattr(Inode *in, const char *name, void *value, size_t len, int uid=-1, int gid=-1); int _listxattr(Inode *in, char *names, size_t len, int uid=-1, int gid=-1); int _setxattr(Inode *in, const char *name, const void *value, size_t len, int flags, int uid=-1, int gid=-1); int _removexattr(Inode *in, const char *nm, int uid=-1, int gid=-1); int _open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid=-1, int gid=-1); int _create(Inode *in, const char *name, int flags, mode_t mode, Inode **inp, Fh **fhp, int stripe_unit, int stripe_count, int object_size, const char *data_pool, bool *created = NULL, int uid=-1, int gid=-1); loff_t _lseek(Fh *fh, loff_t offset, int whence); int _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl); int _write(Fh *fh, int64_t offset, uint64_t size, const char *buf); int _flush(Fh *fh); int _fsync(Fh *fh, bool syncdataonly); int _sync_fs(); int _fallocate(Fh *fh, int mode, int64_t offset, int64_t length); int _getlk(Fh *fh, struct flock *fl, uint64_t owner); int _setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req=NULL); int _flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req=NULL); int get_or_create(Inode *dir, const char* name, Dentry **pdn, bool expect_null=false); int check_permissions(Inode *in, int flags, int uid, int gid); vinodeno_t _get_vino(Inode *in); inodeno_t _get_inodeno(Inode *in); int _do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, struct flock *fl, uint64_t owner, void *fuse_req=NULL); int _interrupt_filelock(MetaRequest *req); void _encode_filelocks(Inode *in, bufferlist& bl); void _release_filelocks(Fh *fh); void _update_lock_state(struct flock *fl, uint64_t owner, ceph_lock_state_t *lock_state); public: int mount(const std::string &mount_root); void unmount(); // these shoud (more or less) mirror the actual system calls. int statfs(const char *path, struct statvfs *stbuf); // crap int chdir(const char *s); void getcwd(std::string& cwd); // namespace ops int opendir(const char *name, dir_result_t **dirpp); int closedir(dir_result_t *dirp); /** * Fill a directory listing from dirp, invoking cb for each entry * with the given pointer, the dirent, the struct stat, the stmask, * and the offset. * * Returns 0 if it reached the end of the directory. * If @a cb returns a negative error code, stop and return that. */ int readdir_r_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p); struct dirent * readdir(dir_result_t *d); int readdir_r(dir_result_t *dirp, struct dirent *de); int readdirplus_r(dir_result_t *dirp, struct dirent *de, struct stat *st, int *stmask); int getdir(const char *relpath, list& names); // get the whole dir at once. /** * Returns the length of the buffer that got filled in, or -errno. * If it returns -ERANGE you just need to increase the size of the * buffer and try again. */ int _getdents(dir_result_t *dirp, char *buf, int buflen, bool ful); // get a bunch of dentries at once int getdents(dir_result_t *dirp, char *buf, int buflen) { return _getdents(dirp, buf, buflen, true); } int getdnames(dir_result_t *dirp, char *buf, int buflen) { return _getdents(dirp, buf, buflen, false); } void rewinddir(dir_result_t *dirp); loff_t telldir(dir_result_t *dirp); void seekdir(dir_result_t *dirp, loff_t offset); int link(const char *existing, const char *newname); int unlink(const char *path); int rename(const char *from, const char *to); // dirs int mkdir(const char *path, mode_t mode); int mkdirs(const char *path, mode_t mode); int rmdir(const char *path); // symlinks int readlink(const char *path, char *buf, loff_t size); int symlink(const char *existing, const char *newname); // inode stuff int stat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL); int lstat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL); int lstatlite(const char *path, struct statlite *buf); int setattr(const char *relpath, struct stat *attr, int mask); int fsetattr(int fd, struct stat *attr, int mask); int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); int lchmod(const char *path, mode_t mode); int chown(const char *path, int uid, int gid); int fchown(int fd, int uid, int gid); int lchown(const char *path, int uid, int gid); int utime(const char *path, struct utimbuf *buf); int lutime(const char *path, struct utimbuf *buf); int truncate(const char *path, loff_t size); // file ops int mknod(const char *path, mode_t mode, dev_t rdev=0); int open(const char *path, int flags, mode_t mode=0); int open(const char *path, int flags, mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool); int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name); int lookup_ino(inodeno_t ino, Inode **inode=NULL); int lookup_parent(Inode *in, Inode **parent=NULL); int lookup_name(Inode *in, Inode *parent); int close(int fd); loff_t lseek(int fd, loff_t offset, int whence); int read(int fd, char *buf, loff_t size, loff_t offset=-1); int write(int fd, const char *buf, loff_t size, loff_t offset=-1); int fake_write_size(int fd, loff_t size); int ftruncate(int fd, loff_t size); int fsync(int fd, bool syncdataonly); int fstat(int fd, struct stat *stbuf); int fallocate(int fd, int mode, loff_t offset, loff_t length); // full path xattr ops int getxattr(const char *path, const char *name, void *value, size_t size); int lgetxattr(const char *path, const char *name, void *value, size_t size); int listxattr(const char *path, char *list, size_t size); int llistxattr(const char *path, char *list, size_t size); int removexattr(const char *path, const char *name); int lremovexattr(const char *path, const char *name); int setxattr(const char *path, const char *name, const void *value, size_t size, int flags); int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags); int sync_fs(); int64_t drop_caches(); // hpc lazyio int lazyio_propogate(int fd, loff_t offset, size_t count); int lazyio_synchronize(int fd, loff_t offset, size_t count); // expose file layout int describe_layout(const char *path, ceph_file_layout* layout); int fdescribe_layout(int fd, ceph_file_layout* layout); int get_file_stripe_address(int fd, loff_t offset, vector& address); int get_file_extent_osds(int fd, loff_t off, loff_t *len, vector& osds); int get_osd_addr(int osd, entity_addr_t& addr); // expose osdmap int get_local_osd(); int get_pool_replication(int64_t pool); int64_t get_pool_id(const char *pool_name); string get_pool_name(int64_t pool); int get_osd_crush_location(int id, vector >& path); int enumerate_layout(int fd, vector& result, loff_t length, loff_t offset); int mksnap(const char *path, const char *name); int rmsnap(const char *path, const char *name); // expose caps int get_caps_issued(int fd); int get_caps_issued(const char *path); // low-level interface v2 inodeno_t ll_get_inodeno(Inode *in) { Mutex::Locker lock(client_lock); return _get_inodeno(in); } snapid_t ll_get_snapid(Inode *in); vinodeno_t ll_get_vino(Inode *in) { Mutex::Locker lock(client_lock); return _get_vino(in); } Inode *ll_get_inode(vinodeno_t vino); int ll_lookup(Inode *parent, const char *name, struct stat *attr, Inode **out, int uid = -1, int gid = -1); bool ll_forget(Inode *in, int count); bool ll_put(Inode *in); int ll_getattr(Inode *in, struct stat *st, int uid = -1, int gid = -1); int ll_setattr(Inode *in, struct stat *st, int mask, int uid = -1, int gid = -1); int ll_getxattr(Inode *in, const char *name, void *value, size_t size, int uid=-1, int gid=-1); int ll_setxattr(Inode *in, const char *name, const void *value, size_t size, int flags, int uid=-1, int gid=-1); int ll_removexattr(Inode *in, const char *name, int uid=-1, int gid=-1); int ll_listxattr(Inode *in, char *list, size_t size, int uid=-1, int gid=-1); int ll_opendir(Inode *in, dir_result_t **dirpp, int uid = -1, int gid = -1); int ll_releasedir(dir_result_t* dirp); int ll_readlink(Inode *in, char *buf, size_t bufsize, int uid = -1, int gid = -1); int ll_mknod(Inode *in, const char *name, mode_t mode, dev_t rdev, struct stat *attr, Inode **out, int uid = -1, int gid = -1); int ll_mkdir(Inode *in, const char *name, mode_t mode, struct stat *attr, Inode **out, int uid = -1, int gid = -1); int ll_symlink(Inode *in, const char *name, const char *value, struct stat *attr, Inode **out, int uid = -1, int gid = -1); int ll_unlink(Inode *in, const char *name, int uid = -1, int gid = -1); int ll_rmdir(Inode *in, const char *name, int uid = -1, int gid = -1); int ll_rename(Inode *parent, const char *name, Inode *newparent, const char *newname, int uid = -1, int gid = -1); int ll_link(Inode *in, Inode *newparent, const char *newname, struct stat *attr, int uid = -1, int gid = -1); int ll_open(Inode *in, int flags, Fh **fh, int uid = -1, int gid = -1); int ll_create(Inode *parent, const char *name, mode_t mode, int flags, struct stat *attr, Inode **out, Fh **fhp, int uid = -1, int gid = -1); int ll_read_block(Inode *in, uint64_t blockid, char *buf, uint64_t offset, uint64_t length, ceph_file_layout* layout); int ll_write_block(Inode *in, uint64_t blockid, char* buf, uint64_t offset, uint64_t length, ceph_file_layout* layout, uint64_t snapseq, uint32_t sync); int ll_commit_blocks(Inode *in, uint64_t offset, uint64_t length); int ll_statfs(Inode *in, struct statvfs *stbuf); int ll_walk(const char* name, Inode **i, struct stat *attr); // XXX in? int ll_listxattr_chunks(Inode *in, char *names, size_t size, int *cookie, int *eol, int uid, int gid); uint32_t ll_stripe_unit(Inode *in); int ll_file_layout(Inode *in, ceph_file_layout *layout); uint64_t ll_snap_seq(Inode *in); int ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl); int ll_write(Fh *fh, loff_t off, loff_t len, const char *data); loff_t ll_lseek(Fh *fh, loff_t offset, int whence); int ll_flush(Fh *fh); int ll_fsync(Fh *fh, bool syncdataonly); int ll_fallocate(Fh *fh, int mode, loff_t offset, loff_t length); int ll_release(Fh *fh); int ll_getlk(Fh *fh, struct flock *fl, uint64_t owner); int ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req); int ll_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req); void ll_interrupt(void *d); int ll_get_stripe_osd(struct Inode *in, uint64_t blockno, ceph_file_layout* layout); uint64_t ll_get_internal_offset(struct Inode *in, uint64_t blockno); int ll_num_osds(void); int ll_osdaddr(int osd, uint32_t *addr); int ll_osdaddr(int osd, char* buf, size_t size); void ll_register_ino_invalidate_cb(client_ino_callback_t cb, void *handle); void ll_register_dentry_invalidate_cb(client_dentry_callback_t cb, void *handle); void ll_register_getgroups_cb(client_getgroups_callback_t cb, void *handle); void ll_register_switch_interrupt_cb(client_switch_interrupt_callback_t cb); }; #endif ceph-0.80.11/src/client/Dentry.cc0000664000175100017510000000133412623076744020517 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "include/utime.h" #include "Dentry.h" #include "Dir.h" #include "Inode.h" #include "common/Formatter.h" void Dentry::dump(Formatter *f) const { f->dump_string("name", name); f->dump_stream("dir") << dir->parent_inode->ino; if (inode) f->dump_stream("ino") << inode->ino; f->dump_int("ref", ref); f->dump_unsigned("offset", offset); if (lease_mds >= 0) { f->dump_int("lease_mds", lease_mds); f->dump_stream("lease_ttl") << lease_ttl; f->dump_int("lease_gen", lease_gen); f->dump_int("lease_seq", lease_seq); } f->dump_int("cap_shared_gen", cap_shared_gen); } ceph-0.80.11/src/client/SyntheticClient.cc0000664000175100017510000027134412623076744022375 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include using namespace std; #include "common/config.h" #include "SyntheticClient.h" #include "osdc/Objecter.h" #include "osdc/Filer.h" #include "include/filepath.h" #include "common/perf_counters.h" #include #include #include #include #include #include #include "common/errno.h" #include "include/assert.h" #define dout_subsys ceph_subsys_client #undef dout_prefix #define dout_prefix *_dout << "client." << (whoami >= 0 ? whoami:client->get_nodeid()) << " " // traces //void trace_include(SyntheticClient *syn, Client *cl, string& prefix); //void trace_openssh(SyntheticClient *syn, Client *cl, string& prefix); list syn_modes; list syn_iargs; list syn_sargs; int syn_filer_flags = 0; void parse_syn_options(vector& args) { vector nargs; for (unsigned i=0; iclient = client; whoami = w; thread_id = 0; did_readdir = false; run_only = -1; exclude = -1; this->modes = syn_modes; this->iargs = syn_iargs; this->sargs = syn_sargs; run_start = ceph_clock_now(client->cct); } #define DBL 2 void *synthetic_client_thread_entry(void *ptr) { SyntheticClient *sc = static_cast(ptr); //int r = sc->run(); return 0;//(void*)r; } string SyntheticClient::get_sarg(int seq) { string a; if (!sargs.empty()) { a = sargs.front(); sargs.pop_front(); } if (a.length() == 0 || a == "~") { char s[30]; snprintf(s, sizeof(s), "syn.%lld.%d", (long long)client->whoami.v, seq); a = s; } return a; } int SyntheticClient::run() { dout(15) << "initing" << dendl; int err = client->init(); if (err < 0) { dout(0) << "failed to initialize: " << cpp_strerror(err) << dendl; return -1; } dout(15) << "mounting" << dendl; err = client->mount(""); if (err < 0) { dout(0) << "failed to mount: " << cpp_strerror(err) << dendl; client->shutdown(); return -1; } //run_start = ceph_clock_now(client->cct); run_until = utime_t(0,0); dout(5) << "run" << dendl; int seq = 0; for (list::iterator it = modes.begin(); it != modes.end(); ++it) { int mode = *it; dout(3) << "mode " << mode << dendl; switch (mode) { // WHO? case SYNCLIENT_MODE_ONLY: { run_only = iargs.front(); iargs.pop_front(); if (run_only == client->get_nodeid()) dout(2) << "only " << run_only << dendl; } break; case SYNCLIENT_MODE_ONLYRANGE: { int first = iargs.front(); iargs.pop_front(); int last = iargs.front(); iargs.pop_front(); if (first <= client->get_nodeid() && last > client->get_nodeid()) { run_only = client->get_nodeid(); dout(2) << "onlyrange [" << first << ", " << last << ") includes me" << dendl; } else run_only = client->get_nodeid().v+1; // not me } break; case SYNCLIENT_MODE_EXCLUDE: { exclude = iargs.front(); iargs.pop_front(); if (exclude == client->get_nodeid()) { run_only = client->get_nodeid().v + 1; dout(2) << "not running " << exclude << dendl; } else run_only = -1; } break; // HOW LONG? case SYNCLIENT_MODE_UNTIL: { int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { if (iarg1) { dout(2) << "until " << iarg1 << dendl; utime_t dur(iarg1,0); run_until = run_start + dur; } else { dout(2) << "until " << iarg1 << " (no limit)" << dendl; run_until = utime_t(0,0); } } } break; // ... case SYNCLIENT_MODE_FOO: if (run_me()) { foo(); } did_run_me(); break; case SYNCLIENT_MODE_RANDOMSLEEP: { int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { srand(time(0) + getpid() + client->whoami.v); sleep(rand() % iarg1); } did_run_me(); } break; case SYNCLIENT_MODE_SLEEP: { int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "sleep " << iarg1 << dendl; sleep(iarg1); } did_run_me(); } break; case SYNCLIENT_MODE_SLEEPUNTIL: { int iarg1 = iargs.front(); iargs.pop_front(); if (iarg1 && run_me()) { dout(2) << "sleepuntil " << iarg1 << dendl; utime_t at = ceph_clock_now(client->cct) - run_start; if (at.sec() < iarg1) sleep(iarg1 - at.sec()); } did_run_me(); } break; case SYNCLIENT_MODE_RANDOMWALK: { int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "randomwalk " << iarg1 << dendl; random_walk(iarg1); } did_run_me(); } break; case SYNCLIENT_MODE_DROPCACHE: { client->sync_fs(); client->drop_caches(); } break; case SYNCLIENT_MODE_DUMP: { string sarg1 = get_sarg(0); if (run_me()) { dout(2) << "placement dump " << sarg1 << dendl; dump_placement(sarg1); } did_run_me(); } break; case SYNCLIENT_MODE_MAKEDIRMESS: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "makedirmess " << sarg1 << " " << iarg1 << dendl; make_dir_mess(sarg1.c_str(), iarg1); } did_run_me(); } break; case SYNCLIENT_MODE_MAKEDIRS: { string sarg1 = get_sarg(seq++); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); int iarg3 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "makedirs " << sarg1 << " " << iarg1 << " " << iarg2 << " " << iarg3 << dendl; make_dirs(sarg1.c_str(), iarg1, iarg2, iarg3); } did_run_me(); } break; case SYNCLIENT_MODE_STATDIRS: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); int iarg3 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "statdirs " << sarg1 << " " << iarg1 << " " << iarg2 << " " << iarg3 << dendl; stat_dirs(sarg1.c_str(), iarg1, iarg2, iarg3); } did_run_me(); } break; case SYNCLIENT_MODE_READDIRS: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); int iarg3 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "readdirs " << sarg1 << " " << iarg1 << " " << iarg2 << " " << iarg3 << dendl; read_dirs(sarg1.c_str(), iarg1, iarg2, iarg3); } did_run_me(); } break; case SYNCLIENT_MODE_THRASHLINKS: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); int iarg3 = iargs.front(); iargs.pop_front(); int iarg4 = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "thrashlinks " << sarg1 << " " << iarg1 << " " << iarg2 << " " << iarg3 << dendl; thrash_links(sarg1.c_str(), iarg1, iarg2, iarg3, iarg4); } did_run_me(); } break; case SYNCLIENT_MODE_LINKTEST: { if (run_me()) { link_test(); } did_run_me(); } break; case SYNCLIENT_MODE_MAKEFILES: { int num = iargs.front(); iargs.pop_front(); int count = iargs.front(); iargs.pop_front(); int priv = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "makefiles " << num << " " << count << " " << priv << dendl; make_files(num, count, priv, false); } did_run_me(); } break; case SYNCLIENT_MODE_MAKEFILES2: { int num = iargs.front(); iargs.pop_front(); int count = iargs.front(); iargs.pop_front(); int priv = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "makefiles2 " << num << " " << count << " " << priv << dendl; make_files(num, count, priv, true); } did_run_me(); } break; case SYNCLIENT_MODE_CREATESHARED: { string sarg1 = get_sarg(0); int num = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "createshared " << num << dendl; create_shared(num); } did_run_me(); } break; case SYNCLIENT_MODE_OPENSHARED: { string sarg1 = get_sarg(0); int num = iargs.front(); iargs.pop_front(); int count = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "openshared " << num << dendl; open_shared(num, count); } did_run_me(); } break; case SYNCLIENT_MODE_CREATEOBJECTS: { int count = iargs.front(); iargs.pop_front(); int size = iargs.front(); iargs.pop_front(); int inflight = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "createobjects " << cout << " of " << size << " bytes" << ", " << inflight << " in flight" << dendl; create_objects(count, size, inflight); } did_run_me(); } break; case SYNCLIENT_MODE_OBJECTRW: { int count = iargs.front(); iargs.pop_front(); int size = iargs.front(); iargs.pop_front(); int wrpc = iargs.front(); iargs.pop_front(); int overlap = iargs.front(); iargs.pop_front(); int rskew = iargs.front(); iargs.pop_front(); int wskew = iargs.front(); iargs.pop_front(); if (run_me()) { dout(2) << "objectrw " << cout << " " << size << " " << wrpc << " " << overlap << " " << rskew << " " << wskew << dendl; object_rw(count, size, wrpc, overlap, rskew, wskew); } did_run_me(); } break; case SYNCLIENT_MODE_FULLWALK: { string sarg1;// = get_sarg(0); if (run_me()) { dout(2) << "fullwalk" << sarg1 << dendl; full_walk(sarg1); } did_run_me(); } break; case SYNCLIENT_MODE_REPEATWALK: { string sarg1 = get_sarg(0); if (run_me()) { dout(2) << "repeatwalk " << sarg1 << dendl; while (full_walk(sarg1) == 0) ; } did_run_me(); } break; case SYNCLIENT_MODE_RMFILE: { string sarg1 = get_sarg(0); if (run_me()) { rm_file(sarg1); } did_run_me(); } break; case SYNCLIENT_MODE_WRITEFILE: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); dout(1) << "WRITING SYN CLIENT" << dendl; if (run_me()) { write_file(sarg1, iarg1, iarg2); } did_run_me(); } break; case SYNCLIENT_MODE_CHUNK: if (run_me()) { string sarg1 = get_sarg(0); chunk_file(sarg1); } did_run_me(); break; case SYNCLIENT_MODE_OVERLOAD_OSD_0: { dout(1) << "OVERLOADING OSD 0" << dendl; int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); int iarg3 = iargs.front(); iargs.pop_front(); if (run_me()) { overload_osd_0(iarg1, iarg2, iarg3); } did_run_me(); } break; case SYNCLIENT_MODE_WRSHARED: { string sarg1 = "shared"; int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); if (run_me()) { write_file(sarg1, iarg1, iarg2); } did_run_me(); } break; case SYNCLIENT_MODE_READSHARED: { string sarg1 = "shared"; int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); if (run_me()) { read_file(sarg1, iarg1, iarg2, true); } did_run_me(); } break; case SYNCLIENT_MODE_WRITEBATCH: { int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); int iarg3 = iargs.front(); iargs.pop_front(); if (run_me()) { write_batch(iarg1, iarg2, iarg3); } did_run_me(); } break; case SYNCLIENT_MODE_READFILE: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); dout(1) << "READING SYN CLIENT" << dendl; if (run_me()) { read_file(sarg1, iarg1, iarg2); } did_run_me(); } break; case SYNCLIENT_MODE_RDWRRANDOM: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); dout(1) << "RANDOM READ WRITE SYN CLIENT" << dendl; if (run_me()) { read_random(sarg1, iarg1, iarg2); } did_run_me(); } break; case SYNCLIENT_MODE_RDWRRANDOM_EX: { string sarg1 = get_sarg(0); int iarg1 = iargs.front(); iargs.pop_front(); int iarg2 = iargs.front(); iargs.pop_front(); dout(1) << "RANDOM READ WRITE SYN CLIENT" << dendl; if (run_me()) { read_random_ex(sarg1, iarg1, iarg2); } did_run_me(); } break; case SYNCLIENT_MODE_TRACE: { string tfile = get_sarg(0); sargs.push_front(string("~")); int iarg1 = iargs.front(); iargs.pop_front(); int playdata = iargs.front(); iargs.pop_front(); string prefix = get_sarg(0); char realtfile[100]; snprintf(realtfile, sizeof(realtfile), tfile.c_str(), (int)client->get_nodeid().v); if (run_me()) { dout(0) << "trace " << tfile << " prefix=" << prefix << " count=" << iarg1 << " data=" << playdata << dendl; Trace t(realtfile); if (iarg1 == 0) iarg1 = 1; // play trace at least once! for (int i=0; icct); if (time_to_stop()) break; play_trace(t, prefix, !playdata); if (time_to_stop()) break; if (iarg1 > 1) clean_dir(prefix); // clean only if repeat utime_t lat = ceph_clock_now(client->cct); lat -= start; dout(0) << " trace " << tfile << " loop " << (i+1) << "/" << iarg1 << " done in " << (double)lat << " seconds" << dendl; if (client->logger && i > 0 && i < iarg1-1 ) { //client->logger->finc("trsum", (double)lat); //client->logger->inc("trnum"); } } dout(1) << "done " << dendl; } did_run_me(); } break; case SYNCLIENT_MODE_OPENTEST: { int count = iargs.front(); iargs.pop_front(); if (run_me()) { for (int i=0; iopen("test", (rand()%2) ? (O_WRONLY|O_CREAT) : O_RDONLY); if (fd > 0) client->close(fd); } } did_run_me(); } break; case SYNCLIENT_MODE_OPTEST: { int count = iargs.front(); iargs.pop_front(); if (run_me()) { client->mknod("test", 0777); struct stat st; for (int i=0; ilstat("test", &st); client->chmod("test", 0777); } } did_run_me(); } break; case SYNCLIENT_MODE_TRUNCATE: { string file = get_sarg(0); sargs.push_front(file); int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { client->truncate(file.c_str(), iarg1); } did_run_me(); } break; case SYNCLIENT_MODE_IMPORTFIND: { string base = get_sarg(0); string find = get_sarg(0); int data = get_iarg(); if (run_me()) { import_find(base.c_str(), find.c_str(), data); } did_run_me(); } break; case SYNCLIENT_MODE_LOOKUPHASH: { inodeno_t ino; string iname = get_sarg(0); sscanf(iname.c_str(), "%llx", (long long unsigned*)&ino.val); inodeno_t dirino; string diname = get_sarg(0); sscanf(diname.c_str(), "%llx", (long long unsigned*)&dirino.val); string name = get_sarg(0); if (run_me()) { lookup_hash(ino, dirino, name.c_str()); } } break; case SYNCLIENT_MODE_LOOKUPINO: { inodeno_t ino; string iname = get_sarg(0); sscanf(iname.c_str(), "%llx", (long long unsigned*)&ino.val); if (run_me()) { lookup_ino(ino); } } break; case SYNCLIENT_MODE_MKSNAP: { string base = get_sarg(0); string name = get_sarg(0); if (run_me()) mksnap(base.c_str(), name.c_str()); did_run_me(); } break; case SYNCLIENT_MODE_RMSNAP: { string base = get_sarg(0); string name = get_sarg(0); if (run_me()) rmsnap(base.c_str(), name.c_str()); did_run_me(); } break; case SYNCLIENT_MODE_MKSNAPFILE: { string base = get_sarg(0); if (run_me()) mksnapfile(base.c_str()); did_run_me(); } break; default: assert(0); } } dout(1) << "syn done, unmounting " << dendl; client->unmount(); client->shutdown(); return 0; } int SyntheticClient::start_thread() { assert(!thread_id); pthread_create(&thread_id, NULL, synthetic_client_thread_entry, this); assert(thread_id); return 0; } int SyntheticClient::join_thread() { assert(thread_id); void *rv; pthread_join(thread_id, &rv); return 0; } bool roll_die(float p) { float r = (float)(rand() % 100000) / 100000.0; if (r < p) return true; else return false; } void SyntheticClient::init_op_dist() { op_dist.clear(); #if 0 op_dist.add( CEPH_MDS_OP_STAT, 610 ); op_dist.add( CEPH_MDS_OP_UTIME, 0 ); op_dist.add( CEPH_MDS_OP_CHMOD, 1 ); op_dist.add( CEPH_MDS_OP_CHOWN, 1 ); #endif op_dist.add( CEPH_MDS_OP_READDIR, 2 ); op_dist.add( CEPH_MDS_OP_MKNOD, 30 ); op_dist.add( CEPH_MDS_OP_LINK, 0 ); op_dist.add( CEPH_MDS_OP_UNLINK, 20 ); op_dist.add( CEPH_MDS_OP_RENAME, 40 ); op_dist.add( CEPH_MDS_OP_MKDIR, 10 ); op_dist.add( CEPH_MDS_OP_RMDIR, 20 ); op_dist.add( CEPH_MDS_OP_SYMLINK, 20 ); op_dist.add( CEPH_MDS_OP_OPEN, 200 ); //op_dist.add( CEPH_MDS_OP_READ, 0 ); //op_dist.add( CEPH_MDS_OP_WRITE, 0 ); //op_dist.add( CEPH_MDS_OP_TRUNCATE, 0 ); //op_dist.add( CEPH_MDS_OP_FSYNC, 0 ); //op_dist.add( CEPH_MDS_OP_RELEASE, 200 ); op_dist.normalize(); } void SyntheticClient::up() { cwd = cwd.prefixpath(cwd.depth()-1); dout(DBL) << "cd .. -> " << cwd << dendl; clear_dir(); } int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) { dout(4) << "play trace prefix '" << prefix << "'" << dendl; t.start(); char buf[1024]; char buf2[1024]; utime_t start = ceph_clock_now(client->cct); ceph::unordered_map open_files; ceph::unordered_map open_dirs; ceph::unordered_map ll_files; ceph::unordered_map ll_dirs; ceph::unordered_map ll_inos; Inode *i1, *i2; ll_inos[1] = 1; // root inode is known. // prefix? const char *p = prefix.c_str(); if (prefix.length()) { client->mkdir(prefix.c_str(), 0755); struct stat attr; i1 = client->ll_get_inode(vinodeno_t(1, CEPH_NOSNAP)); if (client->ll_lookup(i1, prefix.c_str(), &attr, &i2) == 0) { ll_inos[1] = attr.st_ino; dout(5) << "'root' ino is " << inodeno_t(attr.st_ino) << dendl; client->ll_put(i1); } else { dout(0) << "warning: play_trace couldn't lookup up my per-client directory" << dendl; } } else (void) client->ll_get_inode(vinodeno_t(1, CEPH_NOSNAP)); utime_t last_status = start; int n = 0; // for object traces Mutex lock("synclient foo"); Cond cond; bool ack; bool safe; C_GatherBuilder safeg(client->cct, new C_SafeCond(&lock, &cond, &safe)); Context *safegref = safeg.new_sub(); // take a ref while (!t.end()) { if (++n == 100) { n = 00; utime_t now = last_status; if (now - last_status > 1.0) { last_status = now; dout(1) << "play_trace at line " << t.get_line() << dendl; } } if (time_to_stop()) break; // op const char *op = t.get_string(buf, 0); dout(4) << (t.get_line()-1) << ": trace op " << op << dendl; if (op[0] == '@') { // timestamp... ignore it! t.get_int(); // sec t.get_int(); // usec op = t.get_string(buf, 0); } // high level ops --------------------- if (strcmp(op, "link") == 0) { const char *a = t.get_string(buf, p); const char *b = t.get_string(buf2, p); client->link(a,b); } else if (strcmp(op, "unlink") == 0) { const char *a = t.get_string(buf, p); client->unlink(a); } else if (strcmp(op, "rename") == 0) { const char *a = t.get_string(buf, p); const char *b = t.get_string(buf2, p); client->rename(a,b); } else if (strcmp(op, "mkdir") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); client->mkdir(a, b); } else if (strcmp(op, "rmdir") == 0) { const char *a = t.get_string(buf, p); client->rmdir(a); } else if (strcmp(op, "symlink") == 0) { const char *a = t.get_string(buf, p); const char *b = t.get_string(buf2, p); client->symlink(a,b); } else if (strcmp(op, "readlink") == 0) { const char *a = t.get_string(buf, p); char buf[100]; client->readlink(a, buf, 100); } else if (strcmp(op, "lstat") == 0) { struct stat st; const char *a = t.get_string(buf, p); if (strcmp(a, p) != 0 && strcmp(a, "/") != 0 && strcmp(a, "/lib") != 0 && // or /lib.. that would be a lookup. hack. a[0] != 0) // stop stating the root directory already client->lstat(a, &st); } else if (strcmp(op, "chmod") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); client->chmod(a, b); } else if (strcmp(op, "chown") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t c = t.get_int(); client->chown(a, b, c); } else if (strcmp(op, "utime") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t c = t.get_int(); struct utimbuf u; u.actime = b; u.modtime = c; client->utime(a, &u); } else if (strcmp(op, "mknod") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t c = t.get_int(); client->mknod(a, b, c); } else if (strcmp(op, "oldmknod") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); client->mknod(a, b, 0); } else if (strcmp(op, "getdir") == 0) { const char *a = t.get_string(buf, p); list contents; client->getdir(a, contents); } else if (strcmp(op, "getdir") == 0) { const char *a = t.get_string(buf, p); list contents; client->getdir(a, contents); } else if (strcmp(op, "opendir") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); dir_result_t *dirp; client->opendir(a, &dirp); if (dirp) open_dirs[b] = dirp; } else if (strcmp(op, "closedir") == 0) { int64_t a = t.get_int(); client->closedir(open_dirs[a]); open_dirs.erase(a); } else if (strcmp(op, "open") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t c = t.get_int(); int64_t d = t.get_int(); int64_t fd = client->open(a, b, c); if (fd > 0) open_files[d] = fd; } else if (strcmp(op, "oldopen") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t d = t.get_int(); int64_t fd = client->open(a, b, 0755); if (fd > 0) open_files[d] = fd; } else if (strcmp(op, "close") == 0) { int64_t id = t.get_int(); int64_t fh = open_files[id]; if (fh > 0) client->close(fh); open_files.erase(id); } else if (strcmp(op, "lseek") == 0) { int64_t f = t.get_int(); int fd = open_files[f]; int64_t off = t.get_int(); int64_t whence = t.get_int(); client->lseek(fd, off, whence); } else if (strcmp(op, "read") == 0) { int64_t f = t.get_int(); int64_t size = t.get_int(); int64_t off = t.get_int(); int64_t fd = open_files[f]; if (!metadata_only) { char *b = new char[size]; client->read(fd, b, size, off); delete[] b; } } else if (strcmp(op, "write") == 0) { int64_t f = t.get_int(); int64_t fd = open_files[f]; int64_t size = t.get_int(); int64_t off = t.get_int(); if (!metadata_only) { char *b = new char[size]; memset(b, 1, size); // let's write 1's! client->write(fd, b, size, off); delete[] b; } else { client->write(fd, NULL, 0, size+off); } } else if (strcmp(op, "truncate") == 0) { const char *a = t.get_string(buf, p); int64_t l = t.get_int(); client->truncate(a, l); } else if (strcmp(op, "ftruncate") == 0) { int64_t f = t.get_int(); int fd = open_files[f]; int64_t l = t.get_int(); client->ftruncate(fd, l); } else if (strcmp(op, "fsync") == 0) { int64_t f = t.get_int(); int64_t b = t.get_int(); int fd = open_files[f]; client->fsync(fd, b); } else if (strcmp(op, "chdir") == 0) { const char *a = t.get_string(buf, p); client->chdir(a); } else if (strcmp(op, "statfs") == 0) { struct statvfs stbuf; client->statfs("/", &stbuf); } // low level ops --------------------- else if (strcmp(op, "ll_lookup") == 0) { int64_t i = t.get_int(); const char *name = t.get_string(buf, p); int64_t r = t.get_int(); struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_lookup(i1, name, &attr, &i2) == 0) ll_inos[r] = attr.st_ino; client->ll_put(i1); } } else if (strcmp(op, "ll_forget") == 0) { int64_t i = t.get_int(); int64_t n = t.get_int(); if (ll_inos.count(i) && client->ll_forget( client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)), n)) ll_inos.erase(i); } else if (strcmp(op, "ll_getattr") == 0) { int64_t i = t.get_int(); struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); client->ll_getattr(i1, &attr); client->ll_put(i1); } } else if (strcmp(op, "ll_setattr") == 0) { int64_t i = t.get_int(); struct stat attr; memset(&attr, 0, sizeof(attr)); attr.st_mode = t.get_int(); attr.st_uid = t.get_int(); attr.st_gid = t.get_int(); attr.st_size = t.get_int(); attr.st_mtime = t.get_int(); attr.st_atime = t.get_int(); int mask = t.get_int(); if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); client->ll_setattr(i1, &attr, mask); client->ll_put(i1); } } else if (strcmp(op, "ll_readlink") == 0) { int64_t i = t.get_int(); if (ll_inos.count(i)) { char buf[PATH_MAX]; i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); client->ll_readlink(i1, buf, sizeof(buf)); client->ll_put(i1); } } else if (strcmp(op, "ll_mknod") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); int m = t.get_int(); int r = t.get_int(); int64_t ri = t.get_int(); struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_mknod(i1, n, m, r, &attr, &i2) == 0) ll_inos[ri] = attr.st_ino; client->ll_put(i1); } } else if (strcmp(op, "ll_mkdir") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); int m = t.get_int(); int64_t ri = t.get_int(); struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_mkdir(i1, n, m, &attr, &i2) == 0) ll_inos[ri] = attr.st_ino; client->ll_put(i1); } } else if (strcmp(op, "ll_symlink") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); const char *v = t.get_string(buf2, p); int64_t ri = t.get_int(); struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_symlink(i1, n, v, &attr, &i2) == 0) ll_inos[ri] = attr.st_ino; client->ll_put(i1); } } else if (strcmp(op, "ll_unlink") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); client->ll_unlink(i1, n); client->ll_put(i1); } } else if (strcmp(op, "ll_rmdir") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); client->ll_rmdir(i1, n); client->ll_put(i1); } } else if (strcmp(op, "ll_rename") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); int64_t ni = t.get_int(); const char *nn = t.get_string(buf2, p); if (ll_inos.count(i) && ll_inos.count(ni)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); i2 = client->ll_get_inode(vinodeno_t(ll_inos[ni],CEPH_NOSNAP)); client->ll_rename(i1, n, i2, nn); client->ll_put(i1); client->ll_put(i2); } } else if (strcmp(op, "ll_link") == 0) { int64_t i = t.get_int(); int64_t ni = t.get_int(); const char *nn = t.get_string(buf, p); struct stat attr; if (ll_inos.count(i) && ll_inos.count(ni)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); i2 = client->ll_get_inode(vinodeno_t(ll_inos[ni],CEPH_NOSNAP)); client->ll_link(i1, i2, nn, &attr); client->ll_put(i1); client->ll_put(i2); } } else if (strcmp(op, "ll_opendir") == 0) { int64_t i = t.get_int(); int64_t r = t.get_int(); dir_result_t *dirp; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_opendir(i1, &dirp) == 0) ll_dirs[r] = dirp; client->ll_put(i1); } } else if (strcmp(op, "ll_releasedir") == 0) { int64_t f = t.get_int(); if (ll_dirs.count(f)) { client->ll_releasedir(ll_dirs[f]); ll_dirs.erase(f); } } else if (strcmp(op, "ll_open") == 0) { int64_t i = t.get_int(); int64_t f = t.get_int(); int64_t r = t.get_int(); Fh *fhp; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_open(i1, f, &fhp) == 0) ll_files[r] = fhp; client->ll_put(i1); } } else if (strcmp(op, "ll_create") == 0) { int64_t i = t.get_int(); const char *n = t.get_string(buf, p); int64_t m = t.get_int(); int64_t f = t.get_int(); int64_t r = t.get_int(); int64_t ri = t.get_int(); struct stat attr; if (ll_inos.count(i)) { Fh *fhp; i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); if (client->ll_create(i1, n, m, f, &attr, NULL, &fhp) == 0) { ll_inos[ri] = attr.st_ino; ll_files[r] = fhp; } client->ll_put(i1); } } else if (strcmp(op, "ll_read") == 0) { int64_t f = t.get_int(); int64_t off = t.get_int(); int64_t size = t.get_int(); if (ll_files.count(f) && !metadata_only) { bufferlist bl; client->ll_read(ll_files[f], off, size, &bl); } } else if (strcmp(op, "ll_write") == 0) { int64_t f = t.get_int(); int64_t off = t.get_int(); int64_t size = t.get_int(); if (ll_files.count(f)) { if (!metadata_only) { bufferlist bl; bufferptr bp(size); bl.push_back(bp); bp.zero(); client->ll_write(ll_files[f], off, size, bl.c_str()); } else { client->ll_write(ll_files[f], off+size, 0, NULL); } } } else if (strcmp(op, "ll_flush") == 0) { int64_t f = t.get_int(); if (!metadata_only && ll_files.count(f)) client->ll_flush(ll_files[f]); } else if (strcmp(op, "ll_fsync") == 0) { int64_t f = t.get_int(); if (!metadata_only && ll_files.count(f)) client->ll_fsync(ll_files[f], false); // FIXME dataonly param } else if (strcmp(op, "ll_release") == 0) { int64_t f = t.get_int(); if (ll_files.count(f)) { client->ll_release(ll_files[f]); ll_files.erase(f); } } else if (strcmp(op, "ll_statfs") == 0) { int64_t i = t.get_int(); if (ll_inos.count(i)) {} //client->ll_statfs(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); } // object-level traces else if (strcmp(op, "o_stat") == 0) { int64_t oh = t.get_int(); int64_t ol = t.get_int(); object_t oid = file_object_t(oh, ol); lock.Lock(); object_locator_t oloc(SYNCLIENT_FIRST_POOL); uint64_t size; utime_t mtime; client->objecter->stat(oid, oloc, CEPH_NOSNAP, &size, &mtime, 0, new C_SafeCond(&lock, &cond, &ack)); while (!ack) cond.Wait(lock); lock.Unlock(); } else if (strcmp(op, "o_read") == 0) { int64_t oh = t.get_int(); int64_t ol = t.get_int(); int64_t off = t.get_int(); int64_t len = t.get_int(); object_t oid = file_object_t(oh, ol); object_locator_t oloc(SYNCLIENT_FIRST_POOL); lock.Lock(); bufferlist bl; client->objecter->read(oid, oloc, off, len, CEPH_NOSNAP, &bl, 0, new C_SafeCond(&lock, &cond, &ack)); while (!ack) cond.Wait(lock); lock.Unlock(); } else if (strcmp(op, "o_write") == 0) { int64_t oh = t.get_int(); int64_t ol = t.get_int(); int64_t off = t.get_int(); int64_t len = t.get_int(); object_t oid = file_object_t(oh, ol); object_locator_t oloc(SYNCLIENT_FIRST_POOL); lock.Lock(); bufferptr bp(len); bufferlist bl; bl.push_back(bp); SnapContext snapc; client->objecter->write(oid, oloc, off, len, snapc, bl, ceph_clock_now(client->cct), 0, new C_SafeCond(&lock, &cond, &ack), safeg.new_sub()); safeg.activate(); while (!ack) cond.Wait(lock); lock.Unlock(); } else if (strcmp(op, "o_zero") == 0) { int64_t oh = t.get_int(); int64_t ol = t.get_int(); int64_t off = t.get_int(); int64_t len = t.get_int(); object_t oid = file_object_t(oh, ol); object_locator_t oloc(SYNCLIENT_FIRST_POOL); lock.Lock(); SnapContext snapc; client->objecter->zero(oid, oloc, off, len, snapc, ceph_clock_now(client->cct), 0, new C_SafeCond(&lock, &cond, &ack), safeg.new_sub()); safeg.activate(); while (!ack) cond.Wait(lock); lock.Unlock(); } else { dout(0) << (t.get_line()-1) << ": *** trace hit unrecognized symbol '" << op << "' " << dendl; assert(0); } } dout(10) << "trace finished on line " << t.get_line() << dendl; // wait for safe after an object trace safegref->complete(0); lock.Lock(); while (!safe) { dout(10) << "waiting for safe" << dendl; cond.Wait(lock); } lock.Unlock(); // close open files for (ceph::unordered_map::iterator fi = open_files.begin(); fi != open_files.end(); ++fi) { dout(1) << "leftover close " << fi->second << dendl; if (fi->second > 0) client->close(fi->second); } for (ceph::unordered_map::iterator fi = open_dirs.begin(); fi != open_dirs.end(); ++fi) { dout(1) << "leftover closedir " << fi->second << dendl; if (fi->second != 0) client->closedir(fi->second); } for (ceph::unordered_map::iterator fi = ll_files.begin(); fi != ll_files.end(); ++fi) { dout(1) << "leftover ll_release " << fi->second << dendl; if (fi->second) client->ll_release(fi->second); } for (ceph::unordered_map::iterator fi = ll_dirs.begin(); fi != ll_dirs.end(); ++fi) { dout(1) << "leftover ll_releasedir " << fi->second << dendl; if (fi->second) client->ll_releasedir(fi->second); } return 0; } int SyntheticClient::clean_dir(string& basedir) { // read dir list contents; int r = client->getdir(basedir.c_str(), contents); if (r < 0) { dout(1) << "readdir on " << basedir << " returns " << r << dendl; return r; } for (list::iterator it = contents.begin(); it != contents.end(); ++it) { if (*it == ".") continue; if (*it == "..") continue; string file = basedir + "/" + *it; if (time_to_stop()) break; struct stat st; int r = client->lstat(file.c_str(), &st); if (r < 0) { dout(1) << "stat error on " << file << " r=" << r << dendl; continue; } if ((st.st_mode & S_IFMT) == S_IFDIR) { clean_dir(file); client->rmdir(file.c_str()); } else { client->unlink(file.c_str()); } } return 0; } int SyntheticClient::full_walk(string& basedir) { if (time_to_stop()) return -1; list dirq; list statq; dirq.push_back(basedir); frag_info_t empty; memset(&empty, 0, sizeof(empty)); statq.push_back(empty); ceph::unordered_map nlink; ceph::unordered_map nlink_seen; while (!dirq.empty()) { string dir = dirq.front(); frag_info_t expect = statq.front(); dirq.pop_front(); statq.pop_front(); frag_info_t actual = empty; // read dir list contents; int r = client->getdir(dir.c_str(), contents); if (r < 0) { dout(1) << "readdir on " << dir << " returns " << r << dendl; continue; } for (list::iterator it = contents.begin(); it != contents.end(); ++it) { if (*it == "." || *it == "..") continue; string file = dir + "/" + *it; struct stat st; frag_info_t dirstat; int r = client->lstat(file.c_str(), &st, &dirstat); if (r < 0) { dout(1) << "stat error on " << file << " r=" << r << dendl; continue; } nlink_seen[st.st_ino]++; nlink[st.st_ino] = st.st_nlink; if (S_ISDIR(st.st_mode)) actual.nsubdirs++; else actual.nfiles++; // print char *tm = ctime(&st.st_mtime); tm[strlen(tm)-1] = 0; printf("%llx %c%c%c%c%c%c%c%c%c%c %2d %5d %5d %8llu %12s %s\n", (long long)st.st_ino, S_ISDIR(st.st_mode) ? 'd':'-', (st.st_mode & 0400) ? 'r':'-', (st.st_mode & 0200) ? 'w':'-', (st.st_mode & 0100) ? 'x':'-', (st.st_mode & 040) ? 'r':'-', (st.st_mode & 020) ? 'w':'-', (st.st_mode & 010) ? 'x':'-', (st.st_mode & 04) ? 'r':'-', (st.st_mode & 02) ? 'w':'-', (st.st_mode & 01) ? 'x':'-', (int)st.st_nlink, (int)st.st_uid, (int)st.st_gid, (long long unsigned)st.st_size, tm, file.c_str()); if ((st.st_mode & S_IFMT) == S_IFDIR) { dirq.push_back(file); statq.push_back(dirstat); } } if (dir != "" && (actual.nsubdirs != expect.nsubdirs || actual.nfiles != expect.nfiles)) { dout(0) << dir << ": expected " << expect << dendl; dout(0) << dir << ": got " << actual << dendl; } } for (ceph::unordered_map::iterator p = nlink.begin(); p != nlink.end(); ++p) { if (nlink_seen[p->first] != p->second) dout(0) << p->first << " nlink " << p->second << " != " << nlink_seen[p->first] << "seen" << dendl; } return 0; } int SyntheticClient::dump_placement(string& fn) { // open file int fd = client->open(fn.c_str(), O_RDONLY); dout(5) << "reading from " << fn << " fd " << fd << dendl; if (fd < 0) return fd; // How big is it? struct stat stbuf; int lstat_result = client->lstat(fn.c_str(), &stbuf); if (lstat_result < 0) { dout(0) << "lstat error for file " << fn << dendl; return lstat_result; } off_t filesize = stbuf.st_size; // grab the placement info vector extents; off_t offset = 0; client->enumerate_layout(fd, extents, filesize, offset); client->close(fd); // run through all the object extents dout(0) << "file size is " << filesize << dendl; dout(0) << "(osd, start, length) tuples for file " << fn << dendl; for (vector::iterator i = extents.begin(); i != extents.end(); ++i) { int osd = client->osdmap->get_pg_acting_primary(client->osdmap->object_locator_to_pg(i->oid, i->oloc)); // run through all the buffer extents for (vector >::iterator j = i->buffer_extents.begin(); j != i->buffer_extents.end(); ++j) { dout(0) << "OSD " << osd << ", offset " << (*j).first << ", length " << (*j).second << dendl; } } return 0; } int SyntheticClient::make_dirs(const char *basedir, int dirs, int files, int depth) { if (time_to_stop()) return 0; // make sure base dir exists int r = client->mkdir(basedir, 0755); if (r != 0) { dout(1) << "can't make base dir? " << basedir << dendl; //return -1; } // children char d[500]; dout(3) << "make_dirs " << basedir << " dirs " << dirs << " files " << files << " depth " << depth << dendl; for (int i=0; imknod(d, 0644); } if (depth == 0) return 0; for (int i=0; ilstat(basedir, &st); if (r != 0) { dout(1) << "can't make base dir? " << basedir << dendl; return -1; } // children char d[500]; dout(3) << "stat_dirs " << basedir << " dirs " << dirs << " files " << files << " depth " << depth << dendl; for (int i=0; ilstat(d, &st); } if (depth == 0) return 0; for (int i=0; i contents; utime_t s = ceph_clock_now(client->cct); int r = client->getdir(basedir, contents); utime_t e = ceph_clock_now(client->cct); e -= s; if (r < 0) { dout(0) << "read_dirs couldn't readdir " << basedir << ", stopping" << dendl; return -1; } for (int i=0; icct); if (client->lstat(d, &st) < 0) { dout(2) << "read_dirs failed stat on " << d << ", stopping" << dendl; return -1; } utime_t e = ceph_clock_now(client->cct); e -= s; } if (depth > 0) for (int i=0; iget_nodeid().v; char d[255]; if (priv) { for (int c=0; cmkdir(d, 0755); } } else { // shared if (true || whoami == 0) { for (int c=0; cmkdir(d, 0755); } } else { sleep(2); } } // files struct stat st; utime_t start = ceph_clock_now(client->cct); for (int c=0; cmknod(d, 0644); if (more) { client->lstat(d, &st); int fd = client->open(d, O_RDONLY); client->unlink(d); client->close(fd); } if (time_to_stop()) return 0; } } utime_t end = ceph_clock_now(client->cct); end -= start; dout(0) << "makefiles time is " << end << " or " << ((double)end / (double)num) <<" per file" << dendl; return 0; } int SyntheticClient::link_test() { char d[255]; char e[255]; // create files int num = 200; client->mkdir("orig", 0755); client->mkdir("copy", 0755); utime_t start = ceph_clock_now(client->cct); for (int i=0; imknod(d, 0755); } utime_t end = ceph_clock_now(client->cct); end -= start; dout(0) << "orig " << end << dendl; // link start = ceph_clock_now(client->cct); for (int i=0; ilink(d, e); } end = ceph_clock_now(client->cct); end -= start; dout(0) << "copy " << end << dendl; return 0; } int SyntheticClient::create_shared(int num) { // files char d[255]; client->mkdir("test", 0755); for (int n=0; nmknod(d, 0644); } return 0; } int SyntheticClient::open_shared(int num, int count) { // files char d[255]; for (int c=0; c fds; for (int n=0; nopen(d,O_RDONLY); if (fd > 0) fds.push_back(fd); } if (false && client->get_nodeid() == 0) for (int n=0; nunlink(d); } while (!fds.empty()) { int fd = fds.front(); fds.pop_front(); client->close(fd); } } return 0; } // Hits OSD 0 with writes to various files with OSD 0 as the primary. int SyntheticClient::overload_osd_0(int n, int size, int wrsize) { // collect a bunch of files starting on OSD 0 int left = n; int tried = 0; while (left < 0) { // pull open a file dout(0) << "in OSD overload" << dendl; string filename = get_sarg(tried); dout(1) << "OSD Overload workload: trying file " << filename << dendl; int fd = client->open(filename.c_str(), O_RDWR|O_CREAT); ++tried; // only use the file if its first primary is OSD 0 int primary_osd = check_first_primary(fd); if (primary_osd != 0) { client->close(fd); dout(1) << "OSD Overload workload: SKIPPING file " << filename << " with OSD " << primary_osd << " as first primary. " << dendl; continue; } dout(1) << "OSD Overload workload: USING file " << filename << " with OSD 0 as first primary. " << dendl; --left; // do whatever operation we want to do on the file. How about a write? write_fd(fd, size, wrsize); } return 0; } // See what the primary is for the first object in this file. int SyntheticClient::check_first_primary(int fh) { vector extents; client->enumerate_layout(fh, extents, 1, 0); return client->osdmap->get_pg_acting_primary(client->osdmap->object_locator_to_pg(extents.begin()->oid, extents.begin()->oloc)); } int SyntheticClient::rm_file(string& fn) { return client->unlink(fn.c_str()); } int SyntheticClient::write_file(string& fn, int size, loff_t wrsize) // size is in MB, wrsize in bytes { //uint64_t wrsize = 1024*256; char *buf = new char[wrsize+100]; // 1 MB memset(buf, 7, wrsize); int64_t chunks = (uint64_t)size * (uint64_t)(1024*1024) / (uint64_t)wrsize; int fd = client->open(fn.c_str(), O_RDWR|O_CREAT); dout(5) << "writing to " << fn << " fd " << fd << dendl; if (fd < 0) { delete[] buf; return fd; } utime_t from = ceph_clock_now(client->cct); utime_t start = from; uint64_t bytes = 0, total = 0; for (loff_t i=0; iget_nodeid().v; p++; } client->write(fd, buf, wrsize, i*wrsize); bytes += wrsize; total += wrsize; utime_t now = ceph_clock_now(client->cct); if (now - from >= 1.0) { double el = now - from; dout(0) << "write " << (bytes / el / 1048576.0) << " MB/sec" << dendl; from = now; bytes = 0; } } client->fsync(fd, true); utime_t stop = ceph_clock_now(client->cct); double el = stop - start; dout(0) << "write total " << (total / el / 1048576.0) << " MB/sec (" << total << " bytes in " << el << " seconds)" << dendl; client->close(fd); delete[] buf; return 0; } int SyntheticClient::write_fd(int fd, int size, int wrsize) // size is in MB, wrsize in bytes { //uint64_t wrsize = 1024*256; char *buf = new char[wrsize+100]; // 1 MB memset(buf, 7, wrsize); uint64_t chunks = (uint64_t)size * (uint64_t)(1024*1024) / (uint64_t)wrsize; //dout(5) << "SyntheticClient::write_fd: writing to fd " << fd << dendl; if (fd < 0) { delete[] buf; return fd; } for (unsigned i=0; iget_nodeid().v; p++; } client->write(fd, buf, wrsize, i*wrsize); } client->close(fd); delete[] buf; return 0; } int SyntheticClient::write_batch(int nfile, int size, int wrsize) { for (int i=0; iopen(fn.c_str(), O_RDONLY); dout(5) << "reading from " << fn << " fd " << fd << dendl; if (fd < 0) { delete[] buf; return fd; } utime_t from = ceph_clock_now(client->cct); utime_t start = from; uint64_t bytes = 0, total = 0; for (unsigned i=0; iread(fd, buf, rdsize, i*rdsize); if (r < rdsize) { dout(1) << "read_file got r = " << r << ", probably end of file" << dendl; break; } bytes += rdsize; total += rdsize; utime_t now = ceph_clock_now(client->cct); if (now - from >= 1.0) { double el = now - from; dout(0) << "read " << (bytes / el / 1048576.0) << " MB/sec" << dendl; from = now; bytes = 0; } // verify fingerprint int bad = 0; uint64_t *p = (uint64_t*)buf; uint64_t readoff; int64_t readclient; while ((char*)p + 32 < buf + rdsize) { readoff = *p; uint64_t wantoff = (uint64_t)i*(uint64_t)rdsize + (uint64_t)((char*)p - buf); p++; readclient = *p; p++; if (readoff != wantoff || readclient != client->get_nodeid()) { if (!bad && !ignoreprint) dout(0) << "WARNING: wrong data from OSD, block says fileoffset=" << readoff << " client=" << readclient << ", should be offset " << wantoff << " clietn " << client->get_nodeid() << dendl; bad++; } } if (bad && !ignoreprint) dout(0) << " + " << (bad-1) << " other bad 16-byte bits in this block" << dendl; } utime_t stop = ceph_clock_now(client->cct); double el = stop - start; dout(0) << "read total " << (total / el / 1048576.0) << " MB/sec (" << total << " bytes in " << el << " seconds)" << dendl; client->close(fd); delete[] buf; return 0; } class C_Ref : public Context { Mutex& lock; Cond& cond; int *ref; public: C_Ref(Mutex &l, Cond &c, int *r) : lock(l), cond(c), ref(r) { lock.Lock(); (*ref)++; lock.Unlock(); } void finish(int) { lock.Lock(); (*ref)--; cond.Signal(); lock.Unlock(); } }; int SyntheticClient::create_objects(int nobj, int osize, int inflight) { // divy up int numc = client->cct->_conf->num_client ? client->cct->_conf->num_client : 1; int start, inc, end; if (1) { // strided start = client->get_nodeid().v; //nobjs % numc; inc = numc; end = start + nobj; } else { // segments start = nobj * client->get_nodeid().v / numc; inc = 1; end = nobj * (client->get_nodeid().v+1) / numc; } dout(5) << "create_objects " << nobj << " size=" << osize << " .. doing [" << start << "," << end << ") inc " << inc << dendl; bufferptr bp(osize); bp.zero(); bufferlist bl; bl.push_back(bp); Mutex lock("create_objects lock"); Cond cond; int unack = 0; int unsafe = 0; list starts; for (int i=start; icct)); client->client_lock.Lock(); client->objecter->write(oid, oloc, 0, osize, snapc, bl, ceph_clock_now(client->cct), 0, new C_Ref(lock, cond, &unack), new C_Ref(lock, cond, &unsafe)); client->client_lock.Unlock(); lock.Lock(); while (unack > inflight) { dout(20) << "waiting for " << unack << " unack" << dendl; cond.Wait(lock); } lock.Unlock(); utime_t lat = ceph_clock_now(client->cct); lat -= starts.front(); starts.pop_front(); } lock.Lock(); while (unack > 0) { dout(20) << "waiting for " << unack << " unack" << dendl; cond.Wait(lock); } while (unsafe > 0) { dout(10) << "waiting for " << unsafe << " unsafe" << dendl; cond.Wait(lock); } lock.Unlock(); dout(5) << "create_objects done" << dendl; return 0; } int SyntheticClient::object_rw(int nobj, int osize, int wrpc, int overlappc, double rskew, double wskew) { dout(5) << "object_rw " << nobj << " size=" << osize << " with " << wrpc << "% writes" << ", " << overlappc << "% overlap" << ", rskew = " << rskew << ", wskew = " << wskew << dendl; bufferptr bp(osize); bp.zero(); bufferlist bl; bl.push_back(bp); bool do_sync = false; // start with odd number > nobj rjhash h; unsigned prime = nobj + 1; // this is the minimum! prime += h(nobj) % (3*nobj); // bump it up some prime |= 1; // make it odd while (true) { unsigned j; for (j=2; j*j<=prime; j++) if (prime % j == 0) break; if (j*j > prime) { break; //cout << "prime " << prime << endl; } prime += 2; } Mutex lock("lock"); Cond cond; int unack = 0; int unsafe = 0; while (1) { if (time_to_stop()) break; // read or write? bool write = (rand() % 100) < wrpc; // choose object double r = drand48(); // [0..1) long o; if (write) { o = (long)trunc(pow(r, wskew) * (double)nobj); // exponentially skew towards 0 int pnoremap = (long)(r * 100.0); if (pnoremap >= overlappc) o = (o*prime) % nobj; // remap } else { o = (long)trunc(pow(r, rskew) * (double)nobj); // exponentially skew towards 0 } object_t oid = file_object_t(999, o); object_locator_t oloc(SYNCLIENT_FIRST_POOL); SnapContext snapc; client->client_lock.Lock(); utime_t start = ceph_clock_now(client->cct); if (write) { dout(10) << "write to " << oid << dendl; ObjectOperation m; OSDOp op; op.op.op = CEPH_OSD_OP_WRITE; op.op.extent.offset = 0; op.op.extent.length = osize; op.indata = bl; m.ops.push_back(op); if (do_sync) { OSDOp op; op.op.op = CEPH_OSD_OP_STARTSYNC; m.ops.push_back(op); } client->objecter->mutate(oid, oloc, m, snapc, ceph_clock_now(client->cct), 0, NULL, new C_Ref(lock, cond, &unack)); /*client->objecter->write(oid, layout, 0, osize, snapc, bl, 0, new C_Ref(lock, cond, &unack), new C_Ref(lock, cond, &unsafe));*/ } else { dout(10) << "read from " << oid << dendl; bufferlist inbl; client->objecter->read(oid, oloc, 0, osize, CEPH_NOSNAP, &inbl, 0, new C_Ref(lock, cond, &unack)); } client->client_lock.Unlock(); lock.Lock(); while (unack > 0) { dout(20) << "waiting for " << unack << " unack" << dendl; cond.Wait(lock); } lock.Unlock(); utime_t lat = ceph_clock_now(client->cct); lat -= start; if (client->logger) { if (write) client->logger->tset(l_c_owrlat, lat); else client->logger->tset(l_c_ordlat, lat); } } lock.Lock(); while (unsafe > 0) { dout(10) << "waiting for " << unsafe << " unsafe" << dendl; cond.Wait(lock); } lock.Unlock(); return 0; } int SyntheticClient::read_random(string& fn, int size, int rdsize) // size is in MB, wrsize in bytes { __uint64_t chunks = (__uint64_t)size * (__uint64_t)(1024*1024) / (__uint64_t)rdsize; int fd = client->open(fn.c_str(), O_RDWR); dout(5) << "reading from " << fn << " fd " << fd << dendl; // dout(0) << "READING FROM " << fn << " fd " << fd << dendl; // dout(0) << "filename " << fn << " size:" << size << " read size|" << rdsize << "|" << "\ chunks: |" << chunks <<"|" << dendl; if (fd < 0) return fd; int offset = 0; char * buf = NULL; for (unsigned i=0; i<2000; i++) { if (time_to_stop()) break; bool read=false; time_t seconds; time( &seconds); srand(seconds); // use rand instead ?? double x = drand48(); //dout(0) << "RANDOM NUMBER RETURN |" << x << "|" << dendl; // cleanup before call 'new' if (buf != NULL) { delete[] buf; buf = NULL; } if ( x < 0.5) { //dout(0) << "DECIDED TO READ " << x << dendl; buf = new char[rdsize]; memset(buf, 1, rdsize); read=true; } else { // dout(0) << "DECIDED TO WRITE " << x << dendl; buf = new char[rdsize+100]; // 1 MB memset(buf, 7, rdsize); } //double y = drand48() ; //dout(0) << "OFFSET is |" << offset << "| chunks |" << chunks<< dendl; if ( read) { offset=(rand())%(chunks+1); dout(2) << "reading block " << offset << "/" << chunks << dendl; int r = client->read(fd, buf, rdsize, offset*rdsize); if (r < rdsize) { dout(1) << "read_file got r = " << r << ", probably end of file" << dendl; } } else { dout(2) << "writing block " << offset << "/" << chunks << dendl; // fill buf with a 16 byte fingerprint // 64 bits : file offset // 64 bits : client id // = 128 bits (16 bytes) //if (true ) //{ //int count = rand()%10; //for ( int j=0;jget_nodeid().v; p++; } client->write(fd, buf, rdsize, offset*rdsize); //} //} } // verify fingerprint if ( read ) { int bad = 0; __int64_t *p = (__int64_t*)buf; __int64_t readoff, readclient; while ((char*)p + 32 < buf + rdsize) { readoff = *p; __int64_t wantoff = offset*rdsize + (__int64_t)((char*)p - buf); p++; readclient = *p; p++; if (readoff != wantoff || readclient != client->get_nodeid()) { if (!bad) dout(0) << "WARNING: wrong data from OSD, block says fileoffset=" << readoff << " client=" << readclient << ", should be offset " << wantoff << " clietn " << client->get_nodeid() << dendl; bad++; } } if (bad) dout(0) << " + " << (bad-1) << " other bad 16-byte bits in this block" << dendl; } } client->close(fd); delete[] buf; return 0; } //#include //#include int normdist(int min, int max, int stdev) /* specifies input values */; //main() //{ // for ( int i=0; i < 10; i++ ) // normdist ( 0 , 10, 1 ); //} int normdist(int min, int max, int stdev) /* specifies input values */ { /* min: Minimum value; max: Maximum value; stdev: degree of deviation */ //int min, max, stdev; { time_t seconds; time( &seconds); srand(seconds); int range, iterate, result; /* declare range, iterate and result as integers, to avoid the need for floating point math*/ result = 0; /* ensure result is initialized to 0 */ range = max -min; /* calculate range of possible values between the max and min values */ iterate = range / stdev; /* this number of iterations ensures the proper shape of the resulting curve */ stdev += 1; /* compensation for integer vs. floating point math */ for (int c = iterate; c != 0; c--) /* loop through iterations */ { // result += (uniform (1, 100) * stdev) / 100; /* calculate and result += ( (rand()%100 + 1) * stdev) / 100; // printf("result=%d\n", result ); } printf("\n final result=%d\n", result ); return result + min; /* send final result back */ } int SyntheticClient::read_random_ex(string& fn, int size, int rdsize) // size is in MB, wrsize in bytes { __uint64_t chunks = (__uint64_t)size * (__uint64_t)(1024*1024) / (__uint64_t)rdsize; int fd = client->open(fn.c_str(), O_RDWR); dout(5) << "reading from " << fn << " fd " << fd << dendl; // dout(0) << "READING FROM " << fn << " fd " << fd << dendl; // dout(0) << "filename " << fn << " size:" << size << " read size|" << rdsize << "|" << "\ chunks: |" << chunks <<"|" << dendl; if (fd < 0) return fd; int offset = 0; char * buf = NULL; for (unsigned i=0; i<2000; i++) { if (time_to_stop()) break; bool read=false; time_t seconds; time( &seconds); srand(seconds); // use rand instead ?? double x = drand48(); //dout(0) << "RANDOM NUMBER RETURN |" << x << "|" << dendl; // cleanup before call 'new' if (buf != NULL) { delete[] buf; buf = NULL; } if ( x < 0.5) { //dout(0) << "DECIDED TO READ " << x << dendl; buf = new char[rdsize]; memset(buf, 1, rdsize); read=true; } else { // dout(0) << "DECIDED TO WRITE " << x << dendl; buf = new char[rdsize+100]; // 1 MB memset(buf, 7, rdsize); } //double y = drand48() ; //dout(0) << "OFFSET is |" << offset << "| chunks |" << chunks<< dendl; if ( read) { //offset=(rand())%(chunks+1); /* if ( chunks > 10000 ) offset= normdist( 0 , chunks/1000 , 5 )*1000; else if ( chunks > 1000 ) offset= normdist( 0 , chunks/100 , 5 )*100; else if ( chunks > 100 ) offset= normdist( 0 , chunks/20 , 5 )*20;*/ dout(2) << "reading block " << offset << "/" << chunks << dendl; int r = client->read(fd, buf, rdsize, offset*rdsize); if (r < rdsize) { dout(1) << "read_file got r = " << r << ", probably end of file" << dendl; } } else { dout(2) << "writing block " << offset << "/" << chunks << dendl; // fill buf with a 16 byte fingerprint // 64 bits : file offset // 64 bits : client id // = 128 bits (16 bytes) //if (true ) //{ int count = rand()%10; for ( int j=0;jget_nodeid().v; p++; } client->write(fd, buf, rdsize, offset*rdsize); } //} } // verify fingerprint if ( read ) { int bad = 0; __int64_t *p = (__int64_t*)buf; __int64_t readoff, readclient; while ((char*)p + 32 < buf + rdsize) { readoff = *p; __int64_t wantoff = offset*rdsize + (__int64_t)((char*)p - buf); p++; readclient = *p; p++; if (readoff != wantoff || readclient != client->get_nodeid()) { if (!bad) dout(0) << "WARNING: wrong data from OSD, block says fileoffset=" << readoff << " client=" << readclient << ", should be offset " << wantoff << " clietn " << client->get_nodeid() << dendl; bad++; } } if (bad) dout(0) << " + " << (bad-1) << " other bad 16-byte bits in this block" << dendl; } } client->close(fd); delete[] buf; return 0; } int SyntheticClient::random_walk(int num_req) { int left = num_req; //dout(1) << "random_walk() will do " << left << " ops" << dendl; init_op_dist(); // set up metadata op distribution while (left > 0) { left--; if (time_to_stop()) break; // ascend? if (cwd.depth() && !roll_die(::pow((double).9, (double)cwd.depth()))) { dout(DBL) << "die says up" << dendl; up(); continue; } // descend? if (.9*roll_die(::pow((double).9,(double)cwd.depth())) && !subdirs.empty()) { string s = get_random_subdir(); cwd.push_dentry( s ); dout(DBL) << "cd " << s << " -> " << cwd << dendl; clear_dir(); continue; } int op = 0; filepath path; if (contents.empty() && roll_die(.3)) { if (did_readdir) { dout(DBL) << "empty dir, up" << dendl; up(); } else op = CEPH_MDS_OP_READDIR; } else { op = op_dist.sample(); } //dout(DBL) << "op is " << op << dendl; int r = 0; // do op if (op == CEPH_MDS_OP_UNLINK) { if (contents.empty()) op = CEPH_MDS_OP_READDIR; else r = client->unlink( get_random_sub() ); // will fail on dirs } if (op == CEPH_MDS_OP_RENAME) { if (contents.empty()) op = CEPH_MDS_OP_READDIR; else { r = client->rename( get_random_sub(), make_sub("ren") ); } } if (op == CEPH_MDS_OP_MKDIR) { r = client->mkdir( make_sub("mkdir"), 0755); } if (op == CEPH_MDS_OP_RMDIR) { if (!subdirs.empty()) r = client->rmdir( get_random_subdir() ); else r = client->rmdir( cwd.c_str() ); // will pbly fail } if (op == CEPH_MDS_OP_SYMLINK) { } /* if (op == CEPH_MDS_OP_CHMOD) { if (contents.empty()) op = CEPH_MDS_OP_READDIR; else r = client->chmod( get_random_sub(), rand() & 0755 ); } if (op == CEPH_MDS_OP_CHOWN) { if (contents.empty()) r = client->chown( cwd.c_str(), rand(), rand() ); else r = client->chown( get_random_sub(), rand(), rand() ); } if (op == CEPH_MDS_OP_UTIME) { struct utimbuf b; memset(&b, 1, sizeof(b)); if (contents.empty()) r = client->utime( cwd.c_str(), &b ); else r = client->utime( get_random_sub(), &b ); } */ if (op == CEPH_MDS_OP_LINK) { } if (op == CEPH_MDS_OP_MKNOD) { r = client->mknod( make_sub("mknod"), 0644); } if (op == CEPH_MDS_OP_OPEN) { if (contents.empty()) op = CEPH_MDS_OP_READDIR; else { r = client->open( get_random_sub(), O_RDONLY ); if (r > 0) { assert(open_files.count(r) == 0); open_files.insert(r); } } } /*if (op == CEPH_MDS_OP_RELEASE) { // actually, close if (open_files.empty()) op = CEPH_MDS_OP_STAT; else { int fh = get_random_fh(); r = client->close( fh ); if (r == 0) open_files.erase(fh); } } */ if (op == CEPH_MDS_OP_GETATTR) { struct stat st; if (contents.empty()) { if (did_readdir) { if (roll_die(.1)) { dout(DBL) << "stat in empty dir, up" << dendl; up(); } else { op = CEPH_MDS_OP_MKNOD; } } else op = CEPH_MDS_OP_READDIR; } else r = client->lstat(get_random_sub(), &st); } if (op == CEPH_MDS_OP_READDIR) { clear_dir(); list c; r = client->getdir( cwd.c_str(), c ); for (list::iterator it = c.begin(); it != c.end(); ++it) { //dout(DBL) << " got " << *it << dendl; assert(0); /*contents[*it] = it->second; if (it->second && S_ISDIR(it->second->st_mode)) subdirs.insert(*it); */ } did_readdir = true; } // errors? if (r < 0) { // reevaluate cwd. //while (cwd.depth()) { //if (client->lookup(cwd)) break; // it's in the cache //dout(DBL) << "r = " << r << ", client doesn't have " << cwd << ", cd .." << dendl; dout(DBL) << "r = " << r << ", client may not have " << cwd << ", cd .." << dendl; up(); //} } } // close files dout(DBL) << "closing files" << dendl; while (!open_files.empty()) { int fh = get_random_fh(); int r = client->close( fh ); if (r == 0) open_files.erase(fh); } dout(DBL) << "done" << dendl; return 0; } void SyntheticClient::make_dir_mess(const char *basedir, int n) { vector dirs; dirs.push_back(basedir); dirs.push_back(basedir); client->mkdir(basedir, 0755); // motivation: // P(dir) ~ subdirs_of(dir) + 2 // from 5-year metadata workload paper in fast'07 // create dirs for (int i=0; imkdir(dir.c_str(), 0755); } } void SyntheticClient::foo() { if (1) { // make 2 parallel dirs, link/unlink between them. char a[100], b[100]; client->mkdir("/a", 0755); client->mkdir("/b", 0755); for (int i=0; i<10; i++) { snprintf(a, sizeof(a), "/a/%d", i); client->mknod(a, 0644); } while (1) { for (int i=0; i<10; i++) { snprintf(a, sizeof(a), "/a/%d", i); snprintf(b, sizeof(b), "/b/%d", i); client->link(a, b); } for (int i=0; i<10; i++) { snprintf(b, sizeof(b), "/b/%d", i); client->unlink(b); } } return; } if (1) { // bug1.cpp const char *fn = "blah"; char buffer[8192]; client->unlink(fn); int handle = client->open(fn,O_CREAT|O_RDWR,S_IRWXU); assert(handle>=0); int r=client->write(handle,buffer,8192); assert(r>=0); r=client->close(handle); assert(r>=0); handle = client->open(fn,O_RDWR); // open the same file, it must have some data already assert(handle>=0); r=client->read(handle,buffer,8192); assert(r==8192); // THIS ASSERTION FAILS with disabled cache r=client->close(handle); assert(r>=0); return; } if (1) { dout(0) << "first" << dendl; int fd = client->open("tester", O_WRONLY|O_CREAT); client->write(fd, "hi there", 0, 8); client->close(fd); dout(0) << "sleep" << dendl; sleep(10); dout(0) << "again" << dendl; fd = client->open("tester", O_WRONLY|O_CREAT); client->write(fd, "hi there", 0, 8); client->close(fd); return; } if (1) { // open some files srand(0); for (int i=0; i<20; i++) { int s = 5; int a = rand() % s; int b = rand() % s; int c = rand() % s; char src[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); //int fd = client->open(src, O_RDONLY); } return; } if (0) { // rename fun for (int i=0; i<100; i++) { int s = 5; int a = rand() % s; int b = rand() % s; int c = rand() % s; int d = rand() % s; int e = rand() % s; int f = rand() % s; char src[80]; char dst[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); snprintf(dst, sizeof(dst), "syn.0.0/dir.%d/dir.%d/file.%d", d, e, f); client->rename(src, dst); } return; } if (1) { // link fun srand(0); for (int i=0; i<100; i++) { int s = 5; int a = rand() % s; int b = rand() % s; int c = rand() % s; int d = rand() % s; int e = rand() % s; int f = rand() % s; char src[80]; char dst[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); snprintf(dst, sizeof(dst), "syn.0.0/dir.%d/dir.%d/newlink.%d", d, e, f); client->link(src, dst); } srand(0); for (int i=0; i<100; i++) { int s = 5; int a = rand() % s; int b = rand() % s; int c = rand() % s; int d = rand() % s; int e = rand() % s; int f = rand() % s; char src[80]; char dst[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); snprintf(dst, sizeof(dst), "syn.0.0/dir.%d/dir.%d/newlink.%d", d, e, f); client->unlink(dst); } return; } // link fun client->mknod("one", 0755); client->mknod("two", 0755); client->link("one", "three"); client->mkdir("dir", 0755); client->link("two", "/dir/twolink"); client->link("dir/twolink", "four"); // unlink fun client->mknod("a", 0644); client->unlink("a"); client->mknod("b", 0644); client->link("b", "c"); client->unlink("c"); client->mkdir("d", 0755); client->unlink("d"); client->rmdir("d"); // rename fun client->mknod("p1", 0644); client->mknod("p2", 0644); client->rename("p1","p2"); client->mknod("p3", 0644); client->rename("p3","p4"); // check dest dir ambiguity thing client->mkdir("dir1", 0755); client->mkdir("dir2", 0755); client->rename("p2","dir1/p2"); client->rename("dir1/p2","dir2/p2"); client->rename("dir2/p2","/p2"); // check primary+remote link merging client->link("p2","p2.l"); client->link("p4","p4.l"); client->rename("p2.l","p2"); client->rename("p4","p4.l"); // check anchor updates client->mknod("dir1/a", 0644); client->link("dir1/a", "da1"); client->link("dir1/a", "da2"); client->link("da2","da3"); client->rename("dir1/a","dir2/a"); client->rename("dir2/a","da2"); client->rename("da1","da2"); client->rename("da2","da3"); // check directory renames client->mkdir("dir3", 0755); client->mknod("dir3/asdf", 0644); client->mkdir("dir4", 0755); client->mkdir("dir5", 0755); client->mknod("dir5/asdf", 0644); client->rename("dir3","dir4"); // ok client->rename("dir4","dir5"); // fail } int SyntheticClient::thrash_links(const char *basedir, int dirs, int files, int depth, int n) { dout(1) << "thrash_links " << basedir << " " << dirs << " " << files << " " << depth << " links " << n << dendl; if (time_to_stop()) return 0; srand(0); if (1) { bool renames = true; // thrash renames too? for (int k=0; krename(dst.c_str(), "/tmp") == 0) { client->rename(src.c_str(), dst.c_str()); client->rename("/tmp", src.c_str()); } continue; } // pick a dest dir string src = basedir; { char t[80]; for (int d=0; dmknod(src.c_str(), 0755); if (renames) client->rename(src.c_str(), dst.c_str()); break; case 1: client->mknod(src.c_str(), 0755); client->unlink(dst.c_str()); client->link(src.c_str(), dst.c_str()); break; case 2: client->unlink(src.c_str()); break; case 3: client->unlink(dst.c_str()); break; //case 4: client->mknod(src.c_str(), 0755); break; //case 5: client->mknod(dst.c_str(), 0755); break; } } return 0; } if (1) { // now link shit up for (int i=0; ilink(file.c_str(), ln.c_str()); } } return 0; } void SyntheticClient::import_find(const char *base, const char *find, bool data) { dout(1) << "import_find " << base << " from " << find << " data=" << data << dendl; /* use this to gather the static trace: * * find . -exec ls -dilsn --time-style=+%s \{\} \; * or if it's wafl, * find . -path ./.snapshot -prune -o -exec ls -dilsn --time-style=+%s \{\} \; * */ if (base[0] != '-') client->mkdir(base, 0755); ifstream f(find); assert(f.is_open()); int dirnum = 0; while (!f.eof()) { uint64_t ino; int dunno, nlink; string modestring; int uid, gid; off_t size; time_t mtime; string filename; f >> ino; if (f.eof()) break; f >> dunno; f >> modestring; f >> nlink; f >> uid; f >> gid; f >> size; f >> mtime; f.seekg(1, ios::cur); getline(f, filename); // ignore "." if (filename == ".") continue; // remove leading ./ assert(filename[0] == '.' && filename[1] == '/'); filename = filename.substr(2); // new leading dir? int sp = filename.find("/"); if (sp < 0) dirnum++; //dout(0) << "leading dir " << filename << " " << dirnum << dendl; if (dirnum % client->cct->_conf->num_client != client->get_nodeid()) { dout(20) << "skipping leading dir " << dirnum << " " << filename << dendl; continue; } // parse the mode assert(modestring.length() == 10); mode_t mode = 0; switch (modestring[0]) { case 'd': mode |= S_IFDIR; break; case 'l': mode |= S_IFLNK; break; default: case '-': mode |= S_IFREG; break; } if (modestring[1] == 'r') mode |= 0400; if (modestring[2] == 'w') mode |= 0200; if (modestring[3] == 'x') mode |= 0100; if (modestring[4] == 'r') mode |= 040; if (modestring[5] == 'w') mode |= 020; if (modestring[6] == 'x') mode |= 010; if (modestring[7] == 'r') mode |= 04; if (modestring[8] == 'w') mode |= 02; if (modestring[9] == 'x') mode |= 01; dout(20) << " mode " << modestring << " to " << oct << mode << dec << dendl; if (S_ISLNK(mode)) { // target vs destination int pos = filename.find(" -> "); assert(pos > 0); string link; if (base[0] != '-') { link = base; link += "/"; } link += filename.substr(0, pos); string target; if (filename[pos+4] == '/') { if (base[0] != '-') target = base; target += filename.substr(pos + 4); } else { target = filename.substr(pos + 4); } dout(10) << "symlink from '" << link << "' -> '" << target << "'" << dendl; client->symlink(target.c_str(), link.c_str()); } else { string f; if (base[0] != '-') { f = base; f += "/"; } f += filename; if (S_ISDIR(mode)) { client->mkdir(f.c_str(), mode); } else { int fd = client->open(f.c_str(), O_WRONLY|O_CREAT, mode & 0777); assert(fd > 0); if (data) { client->write(fd, "", 0, size); } else { client->truncate(f.c_str(), size); } client->close(fd); //client->chmod(f.c_str(), mode & 0777); client->chown(f.c_str(), uid, gid); struct utimbuf ut; ut.modtime = mtime; ut.actime = mtime; client->utime(f.c_str(), &ut); } } } } int SyntheticClient::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name) { int r = client->lookup_hash(ino, dirino, name); dout(0) << "lookup_hash(" << ino << ", #" << dirino << "/" << name << ") = " << r << dendl; return r; } int SyntheticClient::lookup_ino(inodeno_t ino) { int r = client->lookup_ino(ino); dout(0) << "lookup_ino(" << ino << ") = " << r << dendl; return r; } int SyntheticClient::chunk_file(string &filename) { int fd = client->open(filename.c_str(), O_RDONLY); int ret; struct stat st; client->fstat(fd, &st); uint64_t size = st.st_size; dout(0) << "file " << filename << " size is " << size << dendl; Filer *filer = client->filer; inode_t inode; memset(&inode, 0, sizeof(inode)); inode.ino = st.st_ino; ret = client->fdescribe_layout(fd, &inode.layout); if (ret < 0) return ret; uint64_t pos = 0; bufferlist from_before; while (pos < size) { int get = MIN(size-pos, 1048576); Mutex flock("synclient chunk_file lock"); Cond cond; bool done; bufferlist bl; flock.Lock(); Context *onfinish = new C_SafeCond(&flock, &cond, &done); filer->read(inode.ino, &inode.layout, CEPH_NOSNAP, pos, get, &bl, 0, onfinish); while (!done) cond.Wait(flock); flock.Unlock(); dout(0) << "got " << bl.length() << " bytes at " << pos << dendl; if (from_before.length()) { dout(0) << " including bit from previous block" << dendl; pos -= from_before.length(); from_before.claim_append(bl); bl.swap(from_before); } // .... // keep last 32 bytes around from_before.clear(); from_before.substr_of(bl, bl.length()-32, 32); pos += bl.length(); } client->close(fd); return 0; } void SyntheticClient::mksnap(const char *base, const char *name) { client->mksnap(base, name); } void SyntheticClient::rmsnap(const char *base, const char *name) { client->rmsnap(base, name); } void SyntheticClient::mksnapfile(const char *dir) { client->mkdir(dir, 0755); string f = dir; f += "/foo"; int fd = client->open(f.c_str(), O_WRONLY|O_CREAT|O_TRUNC); char buf[1048576*4]; client->write(fd, buf, sizeof(buf), 0); client->fsync(fd, true); client->close(fd); string s = dir; s += "/.snap/1"; client->mkdir(s.c_str(), 0755); fd = client->open(f.c_str(), O_WRONLY); client->write(fd, buf, 1048576*2, 1048576); client->fsync(fd, true); client->close(fd); } ceph-0.80.11/src/client/fuse_ll.h0000664000175100017510000000117012623076744020543 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ class CephFuse { public: CephFuse(Client *c, int fd); ~CephFuse(); int init(int argc, const char *argv[]); int loop(); void finalize(); class Handle; private: CephFuse::Handle *_handle; }; ceph-0.80.11/src/client/Inode.h0000664000175100017510000001623412623076744020157 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLIENT_INODE_H #define CEPH_CLIENT_INODE_H #include "include/types.h" #include "include/xlist.h" #include "include/filepath.h" #include "mds/mdstypes.h" // hrm #include "osdc/ObjectCacher.h" #include "include/assert.h" struct MetaSession; class Dentry; class Dir; struct SnapRealm; struct Inode; class ceph_lock_state_t; struct Cap { MetaSession *session; Inode *inode; xlist::item cap_item; uint64_t cap_id; unsigned issued; unsigned implemented; unsigned wanted; // as known to mds. uint64_t seq, issue_seq; __u32 mseq; // migration seq __u32 gen; Cap() : session(NULL), inode(NULL), cap_item(this), cap_id(0), issued(0), implemented(0), wanted(0), seq(0), issue_seq(0), mseq(0), gen(0) {} void dump(Formatter *f) const; }; struct CapSnap { //snapid_t follows; // map key Inode *in; SnapContext context; int issued, dirty; uint64_t size; utime_t ctime, mtime, atime; version_t time_warp_seq; uint32_t mode; uid_t uid; gid_t gid; map xattrs; version_t xattr_version; bool writing, dirty_data; uint64_t flush_tid; xlist::item flushing_item; CapSnap(Inode *i) : in(i), issued(0), dirty(0), size(0), time_warp_seq(0), mode(0), uid(0), gid(0), xattr_version(0), writing(false), dirty_data(false), flush_tid(0), flushing_item(this) {} void dump(Formatter *f) const; }; // inode flags #define I_COMPLETE 1 class Inode { public: CephContext *cct; // -- the actual inode -- inodeno_t ino; snapid_t snapid; uint32_t rdev; // if special file // affected by any inode change... utime_t ctime; // inode change time // perm (namespace permissions) uint32_t mode; uid_t uid; gid_t gid; // nlink int32_t nlink; // file (data access) ceph_dir_layout dir_layout; ceph_file_layout layout; uint64_t size; // on directory, # dentries uint32_t truncate_seq; uint64_t truncate_size; utime_t mtime; // file data modify time. utime_t atime; // file data access time. uint32_t time_warp_seq; // count of (potential) mtime/atime timewarps (i.e., utimes()) uint64_t max_size; // max size we can write to // dirfrag, recursive accountin frag_info_t dirstat; nest_info_t rstat; // special stuff version_t version; // auth only version_t xattr_version; // inline data version_t inline_version; bufferlist inline_data; bool is_symlink() const { return (mode & S_IFMT) == S_IFLNK; } bool is_dir() const { return (mode & S_IFMT) == S_IFDIR; } bool is_file() const { return (mode & S_IFMT) == S_IFREG; } bool has_dir_layout() const { for (unsigned c = 0; c < sizeof(layout); c++) if (*((const char *)&layout + c)) return true; return false; } __u32 hash_dentry_name(const string &dn) { int which = dir_layout.dl_dir_hash; if (!which) which = CEPH_STR_HASH_LINUX; return ceph_str_hash(which, dn.data(), dn.length()); } unsigned flags; // about the dir (if this is one!) set dir_contacts; bool dir_hashed, dir_replicated; // per-mds caps map caps; // mds -> Cap Cap *auth_cap; unsigned dirty_caps, flushing_caps; uint64_t flushing_cap_seq; __u16 flushing_cap_tid[CEPH_CAP_BITS]; int shared_gen, cache_gen; int snap_caps, snap_cap_refs; utime_t hold_caps_until; xlist::item cap_item, flushing_cap_item; ceph_tid_t last_flush_tid; SnapRealm *snaprealm; xlist::item snaprealm_item; Inode *snapdir_parent; // only if we are a snapdir inode map cap_snaps; // pending flush to mds //int open_by_mode[CEPH_FILE_MODE_NUM]; map open_by_mode; map cap_refs; ObjectCacher::ObjectSet oset; uint64_t reported_size, wanted_max_size, requested_max_size; int _ref; // ref count. 1 for each dentry, fh that links to me. int ll_ref; // separate ref count for ll client Dir *dir; // if i'm a dir. set dn_set; // if i'm linked to a dentry. string symlink; // symlink content, if it's a symlink fragtree_t dirfragtree; map xattrs; map fragmap; // known frag -> mds mappings list waitfor_caps; list waitfor_commit; Dentry *get_first_parent() { assert(!dn_set.empty()); return *dn_set.begin(); } void make_long_path(filepath& p); void make_nosnap_relative_path(filepath& p); void get() { _ref++; lsubdout(cct, mds, 15) << "inode.get on " << this << " " << ino << '.' << snapid << " now " << _ref << dendl; } /// private method to put a reference; see Client::put_inode() int _put(int n=1) { _ref -= n; lsubdout(cct, mds, 15) << "inode.put on " << this << " " << ino << '.' << snapid << " now " << _ref << dendl; assert(_ref >= 0); return _ref; } int get_num_ref() { return _ref; } void ll_get() { ll_ref++; } void ll_put(int n=1) { assert(ll_ref >= n); ll_ref -= n; } // file locks ceph_lock_state_t *fcntl_locks; ceph_lock_state_t *flock_locks; Inode(CephContext *cct_, vinodeno_t vino, ceph_file_layout *newlayout) : cct(cct_), ino(vino.ino), snapid(vino.snapid), rdev(0), mode(0), uid(0), gid(0), nlink(0), size(0), truncate_seq(1), truncate_size(-1), time_warp_seq(0), max_size(0), version(0), xattr_version(0), inline_version(0), flags(0), dir_hashed(false), dir_replicated(false), auth_cap(NULL), dirty_caps(0), flushing_caps(0), flushing_cap_seq(0), shared_gen(0), cache_gen(0), snap_caps(0), snap_cap_refs(0), cap_item(this), flushing_cap_item(this), last_flush_tid(0), snaprealm(0), snaprealm_item(this), snapdir_parent(0), oset((void *)this, newlayout->fl_pg_pool, ino), reported_size(0), wanted_max_size(0), requested_max_size(0), _ref(0), ll_ref(0), dir(0), dn_set(), fcntl_locks(NULL), flock_locks(NULL) { memset(&dir_layout, 0, sizeof(dir_layout)); memset(&layout, 0, sizeof(layout)); memset(&flushing_cap_tid, 0, sizeof(__u16)*CEPH_CAP_BITS); } ~Inode() { } vinodeno_t vino() { return vinodeno_t(ino, snapid); } struct Compare { bool operator() (Inode* const & left, Inode* const & right) { if (left->ino.val < right->ino.val) { return (left->snapid.val < right->snapid.val); } return false; } }; bool check_mode(uid_t uid, gid_t gid, gid_t *sgids, int sgid_count, uint32_t flags); // CAPS -------- void get_open_ref(int mode); bool put_open_ref(int mode); void get_cap_ref(int cap); int put_cap_ref(int cap); bool is_any_caps(); bool cap_is_valid(Cap* cap); int caps_issued(int *implemented = 0); void touch_cap(Cap *cap); void try_touch_cap(int mds); bool caps_issued_mask(unsigned mask); int caps_used(); int caps_file_wanted(); int caps_wanted(); int caps_dirty(); bool have_valid_size(); Dir *open_dir(); void dump(Formatter *f) const; }; ostream& operator<<(ostream &out, Inode &in); #endif ceph-0.80.11/src/rgw/0000775000175100017510000000000012623077036016256 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/rgw/rgw_civetweb.cc0000664000175100017510000001016112623076744021260 0ustar jenkins-buildjenkins-build #include #include "civetweb/civetweb.h" #include "rgw_civetweb.h" #define dout_subsys ceph_subsys_rgw int RGWMongoose::write_data(const char *buf, int len) { if (!header_done) { header_data.append(buf, len); return len; } if (!sent_header) { data.append(buf, len); return len; } int r = mg_write(conn, buf, len); if (r == 0) { /* didn't send anything, error out */ return -EIO; } return r; } RGWMongoose::RGWMongoose(mg_connection *_conn, int _port) : conn(_conn), port(_port), header_done(false), sent_header(false), has_content_length(false), explicit_keepalive(false) { } int RGWMongoose::read_data(char *buf, int len) { return mg_read(conn, buf, len); } void RGWMongoose::flush() { } int RGWMongoose::complete_request() { if (!sent_header) { if (!has_content_length) { header_done = false; /* let's go back to writing the header */ if (0 && data.length() == 0) { has_content_length = true; print("Transfer-Enconding: %s\r\n", "chunked"); data.append("0\r\n\r\n", sizeof("0\r\n\r\n")-1); } else { int r = send_content_length(data.length()); if (r < 0) return r; } } complete_header(); } if (data.length()) { int r = write_data(data.c_str(), data.length()); if (r < 0) return r; data.clear(); } return 0; } void RGWMongoose::init_env(CephContext *cct) { env.init(cct); struct mg_request_info *info = mg_get_request_info(conn); if (!info) return; for (int i = 0; i < info->num_headers; i++) { struct mg_request_info::mg_header *header = &info->http_headers[i]; if (strcasecmp(header->name, "content-length") == 0) { env.set("CONTENT_LENGTH", header->value); continue; } if (strcasecmp(header->name, "content-type") == 0) { env.set("CONTENT_TYPE", header->value); continue; } if (strcasecmp(header->name, "connection") == 0) { explicit_keepalive = (strcasecmp(header->value, "keep-alive") == 0); } int len = strlen(header->name) + 5; /* HTTP_ prepended */ char buf[len + 1]; memcpy(buf, "HTTP_", 5); const char *src = header->name; char *dest = &buf[5]; for (; *src; src++, dest++) { char c = *src; switch (c) { case '-': c = '_'; break; default: c = toupper(c); break; } *dest = c; } *dest = '\0'; env.set(buf, header->value); } env.set("REQUEST_METHOD", info->request_method); env.set("REQUEST_URI", info->uri); env.set("QUERY_STRING", info->query_string); env.set("REMOTE_USER", info->remote_user); env.set("SCRIPT_URI", info->uri); /* FIXME */ char port_buf[16]; snprintf(port_buf, sizeof(port_buf), "%d", port); env.set("SERVER_PORT", port_buf); } int RGWMongoose::send_status(const char *status, const char *status_name) { char buf[128]; if (!status_name) status_name = ""; snprintf(buf, sizeof(buf), "HTTP/1.1 %s %s\r\n", status, status_name); bufferlist bl; bl.append(buf); bl.append(header_data); header_data = bl; return 0; } int RGWMongoose::send_100_continue() { char buf[] = "HTTP/1.1 100 CONTINUE\r\n\r\n"; return mg_write(conn, buf, sizeof(buf) - 1); } static void dump_date_header(bufferlist &out) { char timestr[TIME_BUF_SIZE]; const time_t gtime = time(NULL); struct tm result; struct tm const * const tmp = gmtime_r(>ime, &result); if (tmp == NULL) return; if (strftime(timestr, sizeof(timestr), "Date: %a, %d %b %Y %H:%M:%S %Z\r\n", tmp)) out.append(timestr); } int RGWMongoose::complete_header() { header_done = true; if (!has_content_length) { return 0; } dump_date_header(header_data); if (explicit_keepalive) header_data.append("Connection: Keep-Alive\r\n"); header_data.append("\r\n"); sent_header = true; return write_data(header_data.c_str(), header_data.length()); } int RGWMongoose::send_content_length(uint64_t len) { has_content_length = true; char buf[21]; snprintf(buf, sizeof(buf), "%"PRIu64, len); return print("Content-Length: %s\r\n", buf); } ceph-0.80.11/src/rgw/rgw_fcgi.h0000664000175100017510000000107012623076744020221 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_FCGI_H #define CEPH_RGW_FCGI_H #include "rgw_client_io.h" struct FCGX_Request; class RGWFCGX : public RGWClientIO { FCGX_Request *fcgx; protected: void init_env(CephContext *cct); int write_data(const char *buf, int len); int read_data(char *buf, int len); int send_status(const char *status, const char *status_name); int send_100_continue(); int complete_header(); int complete_request() { return 0; } int send_content_length(uint64_t len); public: RGWFCGX(FCGX_Request *_fcgx) : fcgx(_fcgx) {} void flush(); }; #endif ceph-0.80.11/src/rgw/rgw_log.cc0000664000175100017510000002410412623076744020233 0ustar jenkins-buildjenkins-build#include "common/Clock.h" #include "common/Timer.h" #include "common/utf8.h" #include "common/OutputDataSocket.h" #include "common/Formatter.h" #include "rgw_log.h" #include "rgw_acl.h" #include "rgw_rados.h" #include "rgw_client_io.h" #define dout_subsys ceph_subsys_rgw static void set_param_str(struct req_state *s, const char *name, string& str) { const char *p = s->info.env->get(name); if (p) str = p; } string render_log_object_name(const string& format, struct tm *dt, string& bucket_id, const string& bucket_name) { string o; for (unsigned i=0; itm_year + 1900); break; case 'y': sprintf(buf, "%.2d", dt->tm_year % 100); break; case 'm': sprintf(buf, "%.2d", dt->tm_mon + 1); break; case 'd': sprintf(buf, "%.2d", dt->tm_mday); break; case 'H': sprintf(buf, "%.2d", dt->tm_hour); break; case 'I': sprintf(buf, "%.2d", (dt->tm_hour % 12) + 1); break; case 'k': sprintf(buf, "%d", dt->tm_hour); break; case 'l': sprintf(buf, "%d", (dt->tm_hour % 12) + 1); break; case 'M': sprintf(buf, "%.2d", dt->tm_min); break; case 'i': o += bucket_id; continue; case 'n': o += bucket_name; continue; default: // unknown code sprintf(buf, "%%%c", format[i]); break; } o += buf; continue; } o += format[i]; } return o; } /* usage logger */ class UsageLogger { CephContext *cct; RGWRados *store; map usage_map; Mutex lock; int32_t num_entries; Mutex timer_lock; SafeTimer timer; utime_t round_timestamp; class C_UsageLogTimeout : public Context { UsageLogger *logger; public: C_UsageLogTimeout(UsageLogger *_l) : logger(_l) {} void finish(int r) { logger->flush(); logger->set_timer(); } }; void set_timer() { timer.add_event_after(cct->_conf->rgw_usage_log_tick_interval, new C_UsageLogTimeout(this)); } public: UsageLogger(CephContext *_cct, RGWRados *_store) : cct(_cct), store(_store), lock("UsageLogger"), num_entries(0), timer_lock("UsageLogger::timer_lock"), timer(cct, timer_lock) { timer.init(); Mutex::Locker l(timer_lock); set_timer(); utime_t ts = ceph_clock_now(cct); recalc_round_timestamp(ts); } ~UsageLogger() { Mutex::Locker l(timer_lock); flush(); timer.cancel_all_events(); timer.shutdown(); } void recalc_round_timestamp(utime_t& ts) { round_timestamp = ts.round_to_hour(); } void insert(utime_t& timestamp, rgw_usage_log_entry& entry) { lock.Lock(); if (timestamp.sec() > round_timestamp + 3600) recalc_round_timestamp(timestamp); entry.epoch = round_timestamp.sec(); bool account; rgw_user_bucket ub(entry.owner, entry.bucket); usage_map[ub].insert(round_timestamp, entry, &account); if (account) num_entries++; bool need_flush = (num_entries > cct->_conf->rgw_usage_log_flush_threshold); lock.Unlock(); if (need_flush) { Mutex::Locker l(timer_lock); flush(); } } void flush() { map old_map; lock.Lock(); old_map.swap(usage_map); num_entries = 0; lock.Unlock(); store->log_usage(old_map); } }; static UsageLogger *usage_logger = NULL; void rgw_log_usage_init(CephContext *cct, RGWRados *store) { usage_logger = new UsageLogger(cct, store); } void rgw_log_usage_finalize() { delete usage_logger; usage_logger = NULL; } static void log_usage(struct req_state *s, const string& op_name) { if (s->system_request) /* don't log system user operations */ return; if (!usage_logger) return; string user; if (!s->bucket_name_str.empty()) user = s->bucket_owner.get_id(); else user = s->user.user_id; rgw_usage_log_entry entry(user, s->bucket.name); uint64_t bytes_sent = s->cio->get_bytes_sent(); uint64_t bytes_received = s->cio->get_bytes_received(); rgw_usage_data data(bytes_sent, bytes_received); data.ops = 1; if (!s->err.is_err()) data.successful_ops = 1; entry.add(op_name, data); utime_t ts = ceph_clock_now(s->cct); usage_logger->insert(ts, entry); } void rgw_format_ops_log_entry(struct rgw_log_entry& entry, Formatter *formatter) { formatter->open_object_section("log_entry"); formatter->dump_string("bucket", entry.bucket); entry.time.gmtime(formatter->dump_stream("time")); // UTC entry.time.localtime(formatter->dump_stream("time_local")); formatter->dump_string("remote_addr", entry.remote_addr); if (entry.object_owner.length()) formatter->dump_string("object_owner", entry.object_owner); formatter->dump_string("user", entry.user); formatter->dump_string("operation", entry.op); formatter->dump_string("uri", entry.uri); formatter->dump_string("http_status", entry.http_status); formatter->dump_string("error_code", entry.error_code); formatter->dump_int("bytes_sent", entry.bytes_sent); formatter->dump_int("bytes_received", entry.bytes_received); formatter->dump_int("object_size", entry.obj_size); uint64_t total_time = entry.total_time.sec() * 1000000LL * entry.total_time.usec(); formatter->dump_int("total_time", total_time); formatter->dump_string("user_agent", entry.user_agent); formatter->dump_string("referrer", entry.referrer); formatter->close_section(); } void OpsLogSocket::formatter_to_bl(bufferlist& bl) { stringstream ss; formatter->flush(ss); const string& s = ss.str(); bl.append(s); } void OpsLogSocket::init_connection(bufferlist& bl) { bl.append("["); } OpsLogSocket::OpsLogSocket(CephContext *cct, uint64_t _backlog) : OutputDataSocket(cct, _backlog), lock("OpsLogSocket") { formatter = new JSONFormatter; delim.append(",\n"); } OpsLogSocket::~OpsLogSocket() { delete formatter; } void OpsLogSocket::log(struct rgw_log_entry& entry) { bufferlist bl; lock.Lock(); rgw_format_ops_log_entry(entry, formatter); formatter_to_bl(bl); lock.Unlock(); append_output(bl); } int rgw_log_op(RGWRados *store, struct req_state *s, const string& op_name, OpsLogSocket *olog) { struct rgw_log_entry entry; string bucket_id; if (s->enable_usage_log) log_usage(s, op_name); if (!s->enable_ops_log) return 0; if (s->bucket_name_str.empty()) { ldout(s->cct, 5) << "nothing to log for operation" << dendl; return -EINVAL; } if (s->err.ret == -ERR_NO_SUCH_BUCKET) { if (!s->cct->_conf->rgw_log_nonexistent_bucket) { ldout(s->cct, 5) << "bucket " << s->bucket << " doesn't exist, not logging" << dendl; return 0; } bucket_id = ""; } else { bucket_id = s->bucket.bucket_id; } entry.bucket = s->bucket_name_str; if (check_utf8(s->bucket_name_str.c_str(), entry.bucket.size()) != 0) { ldout(s->cct, 5) << "not logging op on bucket with non-utf8 name" << dendl; return 0; } if (s->object) entry.obj = s->object; else entry.obj = "-"; entry.obj_size = s->obj_size; if (s->cct->_conf->rgw_remote_addr_param.length()) set_param_str(s, s->cct->_conf->rgw_remote_addr_param.c_str(), entry.remote_addr); else set_param_str(s, "REMOTE_ADDR", entry.remote_addr); set_param_str(s, "HTTP_USER_AGENT", entry.user_agent); set_param_str(s, "HTTP_REFERRER", entry.referrer); set_param_str(s, "REQUEST_URI", entry.uri); set_param_str(s, "REQUEST_METHOD", entry.op); entry.user = s->user.user_id; if (s->object_acl) entry.object_owner = s->object_acl->get_owner().get_id(); entry.bucket_owner = s->bucket_owner.get_id(); uint64_t bytes_sent = s->cio->get_bytes_sent(); uint64_t bytes_received = s->cio->get_bytes_received(); entry.time = s->time; entry.total_time = ceph_clock_now(s->cct) - s->time; entry.bytes_sent = bytes_sent; entry.bytes_received = bytes_received; if (s->err.http_ret) { char buf[16]; snprintf(buf, sizeof(buf), "%d", s->err.http_ret); entry.http_status = buf; } else entry.http_status = "200"; // default entry.error_code = s->err.s3_code; entry.bucket_id = bucket_id; bufferlist bl; ::encode(entry, bl); struct tm bdt; time_t t = entry.time.sec(); if (s->cct->_conf->rgw_log_object_name_utc) gmtime_r(&t, &bdt); else localtime_r(&t, &bdt); int ret = 0; if (s->cct->_conf->rgw_ops_log_rados) { string oid = render_log_object_name(s->cct->_conf->rgw_log_object_name, &bdt, s->bucket.bucket_id, entry.bucket); rgw_obj obj(store->zone.log_pool, oid); ret = store->append_async(obj, bl.length(), bl); if (ret == -ENOENT) { ret = store->create_pool(store->zone.log_pool); if (ret < 0) goto done; // retry ret = store->append_async(obj, bl.length(), bl); } } if (olog) { olog->log(entry); } done: if (ret < 0) ldout(s->cct, 0) << "ERROR: failed to log entry" << dendl; return ret; } int rgw_log_intent(RGWRados *store, rgw_obj& obj, RGWIntentEvent intent, const utime_t& timestamp, bool utc) { rgw_bucket intent_log_bucket(store->zone.intent_log_pool); rgw_intent_log_entry entry; entry.obj = obj; entry.intent = (uint32_t)intent; entry.op_time = timestamp; struct tm bdt; time_t t = timestamp.sec(); if (utc) gmtime_r(&t, &bdt); else localtime_r(&t, &bdt); struct rgw_bucket& bucket = obj.bucket; char buf[bucket.name.size() + bucket.bucket_id.size() + 16]; sprintf(buf, "%.4d-%.2d-%.2d-%s-%s", (bdt.tm_year+1900), (bdt.tm_mon+1), bdt.tm_mday, bucket.bucket_id.c_str(), obj.bucket.name.c_str()); string oid(buf); rgw_obj log_obj(intent_log_bucket, oid); bufferlist bl; ::encode(entry, bl); int ret = store->append_async(log_obj, bl.length(), bl); if (ret == -ENOENT) { ret = store->create_pool(intent_log_bucket); if (ret < 0) goto done; ret = store->append_async(log_obj, bl.length(), bl); } done: return ret; } int rgw_log_intent(RGWRados *store, struct req_state *s, rgw_obj& obj, RGWIntentEvent intent) { return rgw_log_intent(store, obj, intent, s->time, s->cct->_conf->rgw_intent_log_object_name_utc); } ceph-0.80.11/src/rgw/rgw_admin.cc0000664000175100017510000022720512623076744020551 0ustar jenkins-buildjenkins-build#include #include #include #include using namespace std; #include "common/ceph_json.h" #include "common/config.h" #include "common/ceph_argparse.h" #include "common/Formatter.h" #include "common/ceph_json.h" #include "global/global_init.h" #include "common/errno.h" #include "include/utime.h" #include "include/str_list.h" #include "common/armor.h" #include "rgw_user.h" #include "rgw_bucket.h" #include "rgw_rados.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" #include "rgw_log.h" #include "rgw_formats.h" #include "rgw_usage.h" #include "rgw_replica_log.h" #include "auth/Crypto.h" #define dout_subsys ceph_subsys_rgw #define SECRET_KEY_LEN 40 #define PUBLIC_ID_LEN 20 static RGWRados *store = NULL; void _usage() { cerr << "usage: radosgw-admin [options...]" << std::endl; cerr << "commands:\n"; cerr << " user create create a new user\n" ; cerr << " user modify modify user\n"; cerr << " user info get user info\n"; cerr << " user rm remove user\n"; cerr << " user suspend suspend a user\n"; cerr << " user enable re-enable user after suspension\n"; cerr << " user check check user info\n"; cerr << " user stats show user stats as accounted by quota subsystem\n"; cerr << " caps add add user capabilities\n"; cerr << " caps rm remove user capabilities\n"; cerr << " subuser create create a new subuser\n" ; cerr << " subuser modify modify subuser\n"; cerr << " subuser rm remove subuser\n"; cerr << " key create create access key\n"; cerr << " key rm remove access key\n"; cerr << " bucket list list buckets\n"; cerr << " bucket link link bucket to specified user\n"; cerr << " bucket unlink unlink bucket from specified user\n"; cerr << " bucket stats returns bucket statistics\n"; cerr << " bucket rm remove bucket\n"; cerr << " bucket check check bucket index\n"; cerr << " object rm remove object\n"; cerr << " object unlink unlink object from bucket index\n"; cerr << " quota set set quota params\n"; cerr << " quota enable enable quota\n"; cerr << " quota disable disable quota\n"; cerr << " region get show region info\n"; cerr << " regions list list all regions set on this cluster\n"; cerr << " region set set region info (requires infile)\n"; cerr << " region default set default region\n"; cerr << " region-map get show region-map\n"; cerr << " region-map set set region-map (requires infile)\n"; cerr << " zone get show zone cluster params\n"; cerr << " zone set set zone cluster params (requires infile)\n"; cerr << " zone list list all zones set on this cluster\n"; cerr << " pool add add an existing pool for data placement\n"; cerr << " pool rm remove an existing pool from data placement set\n"; cerr << " pools list list placement active set\n"; cerr << " policy read bucket/object policy\n"; cerr << " log list list log objects\n"; cerr << " log show dump a log from specific object or (bucket + date\n"; cerr << " + bucket-id)\n"; cerr << " log rm remove log object\n"; cerr << " usage show show usage (by user, date range)\n"; cerr << " usage trim trim usage (by user, date range)\n"; cerr << " temp remove remove temporary objects that were created up to\n"; cerr << " specified date (and optional time)\n"; cerr << " gc list dump expired garbage collection objects (specify\n"; cerr << " --include-all to list all entries, including unexpired)\n"; cerr << " gc process manually process garbage\n"; cerr << " metadata get get metadata info\n"; cerr << " metadata put put metadata info\n"; cerr << " metadata rm remove metadata info\n"; cerr << " metadata list list metadata info\n"; cerr << " mdlog list list metadata log\n"; cerr << " mdlog trim trim metadata log\n"; cerr << " bilog list list bucket index log\n"; cerr << " bilog trim trim bucket index log (use start-marker, end-marker)\n"; cerr << " datalog list list data log\n"; cerr << " datalog trim trim data log\n"; cerr << " opstate list list stateful operations entries (use client_id,\n"; cerr << " op_id, object)\n"; cerr << " opstate set set state on an entry (use client_id, op_id, object, state)\n"; cerr << " opstate renew renew state on an entry (use client_id, op_id, object)\n"; cerr << " opstate rm remove entry (use client_id, op_id, object)\n"; cerr << " replicalog get get replica metadata log entry\n"; cerr << " replicalog delete delete replica metadata log entry\n"; cerr << "options:\n"; cerr << " --uid= user id\n"; cerr << " --subuser= subuser name\n"; cerr << " --access-key= S3 access key\n"; cerr << " --email=\n"; cerr << " --secret= specify secret key\n"; cerr << " --gen-access-key generate random access key (for S3)\n"; cerr << " --gen-secret generate random secret key\n"; cerr << " --key-type= key type, options are: swift, s3\n"; cerr << " --temp-url-key[-2]= temp url key\n"; cerr << " --access= Set access permissions for sub-user, should be one\n"; cerr << " of read, write, readwrite, full\n"; cerr << " --display-name=\n"; cerr << " --system set the system flag on the user\n"; cerr << " --bucket=\n"; cerr << " --pool=\n"; cerr << " --object=\n"; cerr << " --date=\n"; cerr << " --start-date=\n"; cerr << " --end-date=\n"; cerr << " --bucket-id=\n"; cerr << " --shard-id= optional for mdlog list\n"; cerr << " required for: \n"; cerr << " mdlog trim\n"; cerr << " replica mdlog get/delete\n"; cerr << " replica datalog get/delete\n"; cerr << " --metadata-key= key to retrieve metadata from with metadata get\n"; cerr << " --rgw-region= region in which radosgw is running\n"; cerr << " --rgw-zone= zone in which radosgw is running\n"; cerr << " --fix besides checking bucket index, will also fix it\n"; cerr << " --check-objects bucket check: rebuilds bucket index according to\n"; cerr << " actual objects state\n"; cerr << " --format= specify output format for certain operations: xml,\n"; cerr << " json\n"; cerr << " --purge-data when specified, user removal will also purge all the\n"; cerr << " user data\n"; cerr << " --purge-keys when specified, subuser removal will also purge all the\n"; cerr << " subuser keys\n"; cerr << " --purge-objects remove a bucket's objects before deleting it\n"; cerr << " (NOTE: required to delete a non-empty bucket)\n"; cerr << " --sync-stats option to 'user stats', update user stats with current\n"; cerr << " stats reported by user's buckets indexes\n"; cerr << " --show-log-entries= enable/disable dump of log entries on log show\n"; cerr << " --show-log-sum= enable/disable dump of log summation on log show\n"; cerr << " --skip-zero-entries log show only dumps entries that don't have zero value\n"; cerr << " in one of the numeric field\n"; cerr << " --infile specify a file to read in when setting data\n"; cerr << " --state= specify a state for the opstate set command\n"; cerr << " --replica-log-type replica log type (metadata, data, bucket), required for\n"; cerr << " replica log operations\n"; cerr << " --categories= comma separated list of categories, used in usage show\n"; cerr << " --caps= list of caps (e.g., \"usage=read, write; user=read\"\n"; cerr << " --yes-i-really-mean-it required for certain operations\n"; cerr << "\n"; cerr << " := \"YYYY-MM-DD[ hh:mm:ss]\"\n"; cerr << "\nQuota options:\n"; cerr << " --bucket specified bucket for quota command\n"; cerr << " --max-objects specify max objects (negative value to disable)\n"; cerr << " --max-size specify max size (in bytes, negative value to disable)\n"; cerr << " --quota-scope scope of quota (bucket, user)\n"; cerr << "\n"; generic_client_usage(); } int usage() { _usage(); return 1; } void usage_exit() { _usage(); exit(1); } enum { OPT_NO_CMD = 0, OPT_USER_CREATE, OPT_USER_INFO, OPT_USER_MODIFY, OPT_USER_RM, OPT_USER_SUSPEND, OPT_USER_ENABLE, OPT_USER_CHECK, OPT_USER_STATS, OPT_SUBUSER_CREATE, OPT_SUBUSER_MODIFY, OPT_SUBUSER_RM, OPT_KEY_CREATE, OPT_KEY_RM, OPT_BUCKETS_LIST, OPT_BUCKET_LINK, OPT_BUCKET_UNLINK, OPT_BUCKET_STATS, OPT_BUCKET_CHECK, OPT_BUCKET_RM, OPT_POLICY, OPT_POOL_ADD, OPT_POOL_RM, OPT_POOLS_LIST, OPT_LOG_LIST, OPT_LOG_SHOW, OPT_LOG_RM, OPT_USAGE_SHOW, OPT_USAGE_TRIM, OPT_TEMP_REMOVE, OPT_OBJECT_RM, OPT_OBJECT_UNLINK, OPT_OBJECT_STAT, OPT_QUOTA_SET, OPT_QUOTA_ENABLE, OPT_QUOTA_DISABLE, OPT_GC_LIST, OPT_GC_PROCESS, OPT_REGION_GET, OPT_REGION_LIST, OPT_REGION_SET, OPT_REGION_DEFAULT, OPT_REGIONMAP_GET, OPT_REGIONMAP_SET, OPT_REGIONMAP_UPDATE, OPT_ZONE_GET, OPT_ZONE_SET, OPT_ZONE_LIST, OPT_CAPS_ADD, OPT_CAPS_RM, OPT_METADATA_GET, OPT_METADATA_PUT, OPT_METADATA_RM, OPT_METADATA_LIST, OPT_MDLOG_LIST, OPT_MDLOG_TRIM, OPT_BILOG_LIST, OPT_BILOG_TRIM, OPT_DATALOG_LIST, OPT_DATALOG_TRIM, OPT_OPSTATE_LIST, OPT_OPSTATE_SET, OPT_OPSTATE_RENEW, OPT_OPSTATE_RM, OPT_REPLICALOG_GET, OPT_REPLICALOG_DELETE, }; static int get_cmd(const char *cmd, const char *prev_cmd, bool *need_more) { *need_more = false; // NOTE: please keep the checks in alphabetical order !!! if (strcmp(cmd, "bilog") == 0 || strcmp(cmd, "bucket") == 0 || strcmp(cmd, "buckets") == 0 || strcmp(cmd, "caps") == 0 || strcmp(cmd, "datalog") == 0 || strcmp(cmd, "gc") == 0 || strcmp(cmd, "key") == 0 || strcmp(cmd, "log") == 0 || strcmp(cmd, "mdlog") == 0 || strcmp(cmd, "metadata") == 0 || strcmp(cmd, "object") == 0 || strcmp(cmd, "opstate") == 0 || strcmp(cmd, "pool") == 0 || strcmp(cmd, "pools") == 0 || strcmp(cmd, "quota") == 0 || strcmp(cmd, "region") == 0 || strcmp(cmd, "regions") == 0 || strcmp(cmd, "region-map") == 0 || strcmp(cmd, "regionmap") == 0 || strcmp(cmd, "replicalog") == 0 || strcmp(cmd, "subuser") == 0 || strcmp(cmd, "temp") == 0 || strcmp(cmd, "usage") == 0 || strcmp(cmd, "user") == 0 || strcmp(cmd, "zone") == 0) { *need_more = true; return 0; } if (strcmp(cmd, "policy") == 0) return OPT_POLICY; if (!prev_cmd) return -EINVAL; if (strcmp(prev_cmd, "user") == 0) { if (strcmp(cmd, "create") == 0) return OPT_USER_CREATE; if (strcmp(cmd, "info") == 0) return OPT_USER_INFO; if (strcmp(cmd, "modify") == 0) return OPT_USER_MODIFY; if (strcmp(cmd, "rm") == 0) return OPT_USER_RM; if (strcmp(cmd, "suspend") == 0) return OPT_USER_SUSPEND; if (strcmp(cmd, "enable") == 0) return OPT_USER_ENABLE; if (strcmp(cmd, "check") == 0) return OPT_USER_CHECK; if (strcmp(cmd, "stats") == 0) return OPT_USER_STATS; } else if (strcmp(prev_cmd, "subuser") == 0) { if (strcmp(cmd, "create") == 0) return OPT_SUBUSER_CREATE; if (strcmp(cmd, "modify") == 0) return OPT_SUBUSER_MODIFY; if (strcmp(cmd, "rm") == 0) return OPT_SUBUSER_RM; } else if (strcmp(prev_cmd, "key") == 0) { if (strcmp(cmd, "create") == 0) return OPT_KEY_CREATE; if (strcmp(cmd, "rm") == 0) return OPT_KEY_RM; } else if (strcmp(prev_cmd, "buckets") == 0) { if (strcmp(cmd, "list") == 0) return OPT_BUCKETS_LIST; } else if (strcmp(prev_cmd, "bucket") == 0) { if (strcmp(cmd, "list") == 0) return OPT_BUCKETS_LIST; if (strcmp(cmd, "link") == 0) return OPT_BUCKET_LINK; if (strcmp(cmd, "unlink") == 0) return OPT_BUCKET_UNLINK; if (strcmp(cmd, "stats") == 0) return OPT_BUCKET_STATS; if (strcmp(cmd, "rm") == 0) return OPT_BUCKET_RM; if (strcmp(cmd, "check") == 0) return OPT_BUCKET_CHECK; } else if (strcmp(prev_cmd, "log") == 0) { if (strcmp(cmd, "list") == 0) return OPT_LOG_LIST; if (strcmp(cmd, "show") == 0) return OPT_LOG_SHOW; if (strcmp(cmd, "rm") == 0) return OPT_LOG_RM; } else if (strcmp(prev_cmd, "usage") == 0) { if (strcmp(cmd, "show") == 0) return OPT_USAGE_SHOW; if (strcmp(cmd, "trim") == 0) return OPT_USAGE_TRIM; } else if (strcmp(prev_cmd, "temp") == 0) { if (strcmp(cmd, "remove") == 0) return OPT_TEMP_REMOVE; } else if (strcmp(prev_cmd, "caps") == 0) { if (strcmp(cmd, "add") == 0) return OPT_CAPS_ADD; if (strcmp(cmd, "rm") == 0) return OPT_CAPS_RM; } else if (strcmp(prev_cmd, "pool") == 0) { if (strcmp(cmd, "add") == 0) return OPT_POOL_ADD; if (strcmp(cmd, "rm") == 0) return OPT_POOL_RM; if (strcmp(cmd, "list") == 0) return OPT_POOLS_LIST; } else if (strcmp(prev_cmd, "pools") == 0) { if (strcmp(cmd, "list") == 0) return OPT_POOLS_LIST; } else if (strcmp(prev_cmd, "object") == 0) { if (strcmp(cmd, "rm") == 0) return OPT_OBJECT_RM; if (strcmp(cmd, "unlink") == 0) return OPT_OBJECT_UNLINK; if (strcmp(cmd, "stat") == 0) return OPT_OBJECT_STAT; } else if (strcmp(prev_cmd, "region") == 0) { if (strcmp(cmd, "get") == 0) return OPT_REGION_GET; if (strcmp(cmd, "list") == 0) return OPT_REGION_LIST; if (strcmp(cmd, "set") == 0) return OPT_REGION_SET; if (strcmp(cmd, "default") == 0) return OPT_REGION_DEFAULT; } else if (strcmp(prev_cmd, "quota") == 0) { if (strcmp(cmd, "set") == 0) return OPT_QUOTA_SET; if (strcmp(cmd, "enable") == 0) return OPT_QUOTA_ENABLE; if (strcmp(cmd, "disable") == 0) return OPT_QUOTA_DISABLE; } else if (strcmp(prev_cmd, "regions") == 0) { if (strcmp(cmd, "list") == 0) return OPT_REGION_LIST; } else if (strcmp(prev_cmd, "region-map") == 0 || strcmp(prev_cmd, "regionmap") == 0) { if (strcmp(cmd, "get") == 0) return OPT_REGIONMAP_GET; if (strcmp(cmd, "set") == 0) return OPT_REGIONMAP_SET; if (strcmp(cmd, "update") == 0) return OPT_REGIONMAP_UPDATE; } else if (strcmp(prev_cmd, "zone") == 0) { if (strcmp(cmd, "get") == 0) return OPT_ZONE_GET; if (strcmp(cmd, "set") == 0) return OPT_ZONE_SET; if (strcmp(cmd, "list") == 0) return OPT_ZONE_LIST; } else if (strcmp(prev_cmd, "zones") == 0) { if (strcmp(cmd, "list") == 0) return OPT_ZONE_LIST; } else if (strcmp(prev_cmd, "gc") == 0) { if (strcmp(cmd, "list") == 0) return OPT_GC_LIST; if (strcmp(cmd, "process") == 0) return OPT_GC_PROCESS; } else if (strcmp(prev_cmd, "metadata") == 0) { if (strcmp(cmd, "get") == 0) return OPT_METADATA_GET; if (strcmp(cmd, "put") == 0) return OPT_METADATA_PUT; if (strcmp(cmd, "rm") == 0) return OPT_METADATA_RM; if (strcmp(cmd, "list") == 0) return OPT_METADATA_LIST; } else if (strcmp(prev_cmd, "mdlog") == 0) { if (strcmp(cmd, "list") == 0) return OPT_MDLOG_LIST; if (strcmp(cmd, "trim") == 0) return OPT_MDLOG_TRIM; } else if (strcmp(prev_cmd, "bilog") == 0) { if (strcmp(cmd, "list") == 0) return OPT_BILOG_LIST; if (strcmp(cmd, "trim") == 0) return OPT_BILOG_TRIM; } else if (strcmp(prev_cmd, "datalog") == 0) { if (strcmp(cmd, "list") == 0) return OPT_DATALOG_LIST; if (strcmp(cmd, "trim") == 0) return OPT_DATALOG_TRIM; } else if (strcmp(prev_cmd, "opstate") == 0) { if (strcmp(cmd, "list") == 0) return OPT_OPSTATE_LIST; if (strcmp(cmd, "set") == 0) return OPT_OPSTATE_SET; if (strcmp(cmd, "renew") == 0) return OPT_OPSTATE_RENEW; if (strcmp(cmd, "rm") == 0) return OPT_OPSTATE_RM; } else if (strcmp(prev_cmd, "replicalog") == 0) { if (strcmp(cmd, "get") == 0) return OPT_REPLICALOG_GET; if (strcmp(cmd, "delete") == 0) return OPT_REPLICALOG_DELETE; } return -EINVAL; } enum ReplicaLogType { ReplicaLog_Invalid = 0, ReplicaLog_Metadata, ReplicaLog_Data, ReplicaLog_Bucket, }; ReplicaLogType get_replicalog_type(const string& name) { if (name == "md" || name == "meta" || name == "metadata") return ReplicaLog_Metadata; if (name == "data") return ReplicaLog_Data; if (name == "bucket") return ReplicaLog_Bucket; return ReplicaLog_Invalid; } static void show_user_info(RGWUserInfo& info, Formatter *formatter) { encode_json("user_info", info, formatter); formatter->flush(cout); cout << std::endl; } static void dump_bucket_usage(map& stats, Formatter *formatter) { map::iterator iter; formatter->open_object_section("usage"); for (iter = stats.begin(); iter != stats.end(); ++iter) { RGWStorageStats& s = iter->second; const char *cat_name = rgw_obj_category_name(iter->first); formatter->open_object_section(cat_name); formatter->dump_int("size_kb", s.num_kb); formatter->dump_int("size_kb_actual", s.num_kb_rounded); formatter->dump_int("num_objects", s.num_objects); formatter->close_section(); formatter->flush(cout); } formatter->close_section(); } int bucket_stats(rgw_bucket& bucket, Formatter *formatter) { RGWBucketInfo bucket_info; time_t mtime; int r = store->get_bucket_info(NULL, bucket.name, bucket_info, &mtime); if (r < 0) return r; map stats; uint64_t bucket_ver, master_ver; string max_marker; int ret = store->get_bucket_stats(bucket, &bucket_ver, &master_ver, stats, &max_marker); if (ret < 0) { cerr << "error getting bucket stats ret=" << ret << std::endl; return ret; } formatter->open_object_section("stats"); formatter->dump_string("bucket", bucket.name); formatter->dump_string("pool", bucket.data_pool); formatter->dump_string("index_pool", bucket.index_pool); formatter->dump_string("id", bucket.bucket_id); formatter->dump_string("marker", bucket.marker); formatter->dump_string("owner", bucket_info.owner); formatter->dump_int("mtime", mtime); formatter->dump_int("ver", bucket_ver); formatter->dump_int("master_ver", master_ver); formatter->dump_string("max_marker", max_marker); dump_bucket_usage(stats, formatter); formatter->close_section(); return 0; } class StoreDestructor { RGWRados *store; public: StoreDestructor(RGWRados *_s) : store(_s) {} ~StoreDestructor() { RGWStoreManager::close_storage(store); } }; static int init_bucket(string& bucket_name, RGWBucketInfo& bucket_info, rgw_bucket& bucket) { if (!bucket_name.empty()) { int r = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL); if (r < 0) { cerr << "could not get bucket info for bucket=" << bucket_name << std::endl; return r; } bucket = bucket_info.bucket; } return 0; } static int read_input(const string& infile, bufferlist& bl) { int fd = 0; if (infile.size()) { fd = open(infile.c_str(), O_RDONLY); if (fd < 0) { int err = -errno; cerr << "error reading input file " << infile << std::endl; return err; } } #define READ_CHUNK 8196 int r; int err; do { char buf[READ_CHUNK]; r = read(fd, buf, READ_CHUNK); if (r < 0) { err = -errno; cerr << "error while reading input" << std::endl; goto out; } bl.append(buf, r); } while (r > 0); err = 0; out: if (infile.size()) { close(fd); } return err; } template static int read_decode_json(const string& infile, T& t) { bufferlist bl; int ret = read_input(infile, bl); if (ret < 0) { cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl; return ret; } JSONParser p; ret = p.parse(bl.c_str(), bl.length()); if (ret < 0) { cout << "failed to parse JSON" << std::endl; return ret; } try { t.decode_json(&p); } catch (JSONDecoder::err& e) { cout << "failed to decode JSON input: " << e.message << std::endl; return -EINVAL; } return 0; } static int parse_date_str(const string& date_str, utime_t& ut) { uint64_t epoch = 0; uint64_t nsec = 0; if (!date_str.empty()) { int ret = utime_t::parse_date(date_str, &epoch, &nsec); if (ret < 0) { cerr << "ERROR: failed to parse date: " << date_str << std::endl; return -EINVAL; } } ut = utime_t(epoch, nsec); return 0; } template static bool decode_dump(const char *field_name, bufferlist& bl, Formatter *f) { T t; bufferlist::iterator iter = bl.begin(); try { ::decode(t, iter); } catch (buffer::error& err) { return false; } encode_json(field_name, t, f); return true; } static bool dump_string(const char *field_name, bufferlist& bl, Formatter *f) { string val; if (bl.length() > 0) { val.assign(bl.c_str(), bl.length()); } f->dump_string(field_name, val); return true; } void set_quota_info(RGWQuotaInfo& quota, int opt_cmd, int64_t max_size, int64_t max_objects, bool have_max_size, bool have_max_objects) { switch (opt_cmd) { case OPT_QUOTA_ENABLE: quota.enabled = true; // falling through on purpose case OPT_QUOTA_SET: if (have_max_objects) { quota.max_objects = max_objects; } if (have_max_size) { if (max_size < 0) { quota.max_size_kb = -1; } else { quota.max_size_kb = rgw_rounded_kb(max_size); } } break; case OPT_QUOTA_DISABLE: quota.enabled = false; break; } } int set_bucket_quota(RGWRados *store, int opt_cmd, string& bucket_name, int64_t max_size, int64_t max_objects, bool have_max_size, bool have_max_objects) { RGWBucketInfo bucket_info; map attrs; int r = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL, &attrs); if (r < 0) { cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl; return -r; } set_quota_info(bucket_info.quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects); r = store->put_bucket_instance_info(bucket_info, false, 0, &attrs); if (r < 0) { cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl; return -r; } return 0; } int set_user_bucket_quota(int opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects, bool have_max_size, bool have_max_objects) { RGWUserInfo& user_info = op_state.get_user_info(); set_quota_info(user_info.bucket_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects); op_state.set_bucket_quota(user_info.bucket_quota); string err; int r = user.modify(op_state, &err); if (r < 0) { cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl; return -r; } return 0; } int set_user_quota(int opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects, bool have_max_size, bool have_max_objects) { RGWUserInfo& user_info = op_state.get_user_info(); set_quota_info(user_info.user_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects); op_state.set_user_quota(user_info.user_quota); string err; int r = user.modify(op_state, &err); if (r < 0) { cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl; return -r; } return 0; } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); std::string user_id, access_key, secret_key, user_email, display_name; std::string bucket_name, pool_name, object; std::string date, subuser, access, format; std::string start_date, end_date; std::string key_type_str; int key_type = KEY_TYPE_UNDEFINED; rgw_bucket bucket; uint32_t perm_mask = 0; RGWUserInfo info; int opt_cmd = OPT_NO_CMD; bool need_more; int gen_access_key = 0; int gen_secret_key = 0; bool set_perm = false; bool set_temp_url_key = false; map temp_url_keys; string bucket_id; Formatter *formatter = NULL; int purge_data = false; RGWBucketInfo bucket_info; int pretty_format = false; int show_log_entries = true; int show_log_sum = true; int skip_zero_entries = false; // log show int purge_keys = false; int yes_i_really_mean_it = false; int delete_child_objects = false; int fix = false; int max_buckets = -1; map categories; string caps; int check_objects = false; RGWUserAdminOpState user_op; RGWBucketAdminOpState bucket_op; string infile; string metadata_key; RGWObjVersionTracker objv_tracker; string marker; string start_marker; string end_marker; int max_entries = -1; int system = false; bool system_specified = false; int shard_id = -1; bool specified_shard_id = false; string daemon_id; bool specified_daemon_id = false; string client_id; string op_id; string state_str; string replica_log_type_str; ReplicaLogType replica_log_type = ReplicaLog_Invalid; string op_mask_str; string quota_scope; int64_t max_objects = -1; int64_t max_size = -1; bool have_max_objects = false; bool have_max_size = false; int include_all = false; int sync_stats = false; std::string val; std::ostringstream errs; string err; long long tmp = 0; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); return 0; } else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) { user_id = val; } else if (ceph_argparse_witharg(args, i, &val, "--access-key", (char*)NULL)) { access_key = val; } else if (ceph_argparse_witharg(args, i, &val, "--subuser", (char*)NULL)) { subuser = val; } else if (ceph_argparse_witharg(args, i, &val, "--secret", (char*)NULL)) { secret_key = val; } else if (ceph_argparse_witharg(args, i, &val, "-e", "--email", (char*)NULL)) { user_email = val; } else if (ceph_argparse_witharg(args, i, &val, "-n", "--display-name", (char*)NULL)) { display_name = val; } else if (ceph_argparse_witharg(args, i, &val, "-b", "--bucket", (char*)NULL)) { bucket_name = val; } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { pool_name = val; } else if (ceph_argparse_witharg(args, i, &val, "-o", "--object", (char*)NULL)) { object = val; } else if (ceph_argparse_witharg(args, i, &val, "--client-id", (char*)NULL)) { client_id = val; } else if (ceph_argparse_witharg(args, i, &val, "--op-id", (char*)NULL)) { op_id = val; } else if (ceph_argparse_witharg(args, i, &val, "--state", (char*)NULL)) { state_str = val; } else if (ceph_argparse_witharg(args, i, &val, "--op-mask", (char*)NULL)) { op_mask_str = val; } else if (ceph_argparse_witharg(args, i, &val, "--key-type", (char*)NULL)) { key_type_str = val; if (key_type_str.compare("swift") == 0) { key_type = KEY_TYPE_SWIFT; } else if (key_type_str.compare("s3") == 0) { key_type = KEY_TYPE_S3; } else { cerr << "bad key type: " << key_type_str << std::endl; return usage(); } } else if (ceph_argparse_binary_flag(args, i, &gen_access_key, NULL, "--gen-access-key", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &gen_secret_key, NULL, "--gen-secret", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show_log_entries", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show_log_sum", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &skip_zero_entries, NULL, "--skip_zero_entries", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &system, NULL, "--system", (char*)NULL)) { system_specified = true; } else if (ceph_argparse_withlonglong(args, i, &tmp, &errs, "-a", "--auth-uid", (char*)NULL)) { if (!errs.str().empty()) { cerr << errs.str() << std::endl; exit(EXIT_FAILURE); } } else if (ceph_argparse_witharg(args, i, &val, "--max-buckets", (char*)NULL)) { max_buckets = atoi(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--max-entries", (char*)NULL)) { max_entries = atoi(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--max-size", (char*)NULL)) { max_size = (int64_t)strict_strtoll(val.c_str(), 10, &err); if (!err.empty()) { cerr << "ERROR: failed to parse max size: " << err << std::endl; return EINVAL; } have_max_size = true; } else if (ceph_argparse_witharg(args, i, &val, "--max-objects", (char*)NULL)) { max_objects = (int64_t)strict_strtoll(val.c_str(), 10, &err); if (!err.empty()) { cerr << "ERROR: failed to parse max objects: " << err << std::endl; return EINVAL; } have_max_objects = true; } else if (ceph_argparse_witharg(args, i, &val, "--date", "--time", (char*)NULL)) { date = val; if (end_date.empty()) end_date = date; } else if (ceph_argparse_witharg(args, i, &val, "--start-date", "--start-time", (char*)NULL)) { start_date = val; } else if (ceph_argparse_witharg(args, i, &val, "--end-date", "--end-time", (char*)NULL)) { end_date = val; } else if (ceph_argparse_witharg(args, i, &val, "--shard-id", (char*)NULL)) { shard_id = atoi(val.c_str()); specified_shard_id = true; } else if (ceph_argparse_witharg(args, i, &val, "--daemon-id", (char*)NULL)) { daemon_id = val; specified_daemon_id = true; } else if (ceph_argparse_witharg(args, i, &val, "--access", (char*)NULL)) { access = val; perm_mask = rgw_str_to_perm(access.c_str()); set_perm = true; } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key", (char*)NULL)) { temp_url_keys[0] = val; set_temp_url_key = true; } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key2", "--temp-url-key-2", (char*)NULL)) { temp_url_keys[1] = val; set_temp_url_key = true; } else if (ceph_argparse_witharg(args, i, &val, "--bucket-id", (char*)NULL)) { bucket_id = val; if (bucket_id.empty()) { cerr << "bad bucket-id" << std::endl; return usage(); } } else if (ceph_argparse_witharg(args, i, &val, "--format", (char*)NULL)) { format = val; } else if (ceph_argparse_witharg(args, i, &val, "--categories", (char*)NULL)) { string cat_str = val; list cat_list; list::iterator iter; get_str_list(cat_str, cat_list); for (iter = cat_list.begin(); iter != cat_list.end(); ++iter) { categories[*iter] = true; } } else if (ceph_argparse_binary_flag(args, i, &delete_child_objects, NULL, "--purge-objects", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &pretty_format, NULL, "--pretty-format", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &purge_data, NULL, "--purge-data", (char*)NULL)) { delete_child_objects = purge_data; } else if (ceph_argparse_binary_flag(args, i, &purge_keys, NULL, "--purge-keys", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &yes_i_really_mean_it, NULL, "--yes-i-really-mean-it", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &fix, NULL, "--fix", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &check_objects, NULL, "--check-objects", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &sync_stats, NULL, "--sync-stats", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &include_all, NULL, "--include-all", (char*)NULL)) { // do nothing } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) { caps = val; } else if (ceph_argparse_witharg(args, i, &val, "-i", "--infile", (char*)NULL)) { infile = val; } else if (ceph_argparse_witharg(args, i, &val, "--metadata-key", (char*)NULL)) { metadata_key = val; } else if (ceph_argparse_witharg(args, i, &val, "--marker", (char*)NULL)) { marker = val; } else if (ceph_argparse_witharg(args, i, &val, "--start-marker", (char*)NULL)) { start_marker = val; } else if (ceph_argparse_witharg(args, i, &val, "--end-marker", (char*)NULL)) { end_marker = val; } else if (ceph_argparse_witharg(args, i, &val, "--quota-scope", (char*)NULL)) { quota_scope = val; } else if (ceph_argparse_witharg(args, i, &val, "--replica-log-type", (char*)NULL)) { replica_log_type_str = val; replica_log_type = get_replicalog_type(replica_log_type_str); if (replica_log_type == ReplicaLog_Invalid) { cerr << "ERROR: invalid replica log type" << std::endl; return EINVAL; } } else if (strncmp(*i, "-", 1) == 0) { cerr << "ERROR: invalid flag " << *i << std::endl; return EINVAL; } else { ++i; } } if (args.empty()) { return usage(); } else { const char *prev_cmd = NULL; std::vector::iterator i ; for (i = args.begin(); i != args.end(); ++i) { opt_cmd = get_cmd(*i, prev_cmd, &need_more); if (opt_cmd < 0) { cerr << "unrecognized arg " << *i << std::endl; return usage(); } if (!need_more) { ++i; break; } prev_cmd = *i; } if (opt_cmd == OPT_NO_CMD) return usage(); /* some commands may have an optional extra param */ if (i != args.end()) { switch (opt_cmd) { case OPT_METADATA_GET: case OPT_METADATA_PUT: case OPT_METADATA_RM: case OPT_METADATA_LIST: metadata_key = *i; break; default: break; } } } // default to pretty json if (format.empty()) { format = "json"; pretty_format = true; } if (format == "xml") formatter = new XMLFormatter(pretty_format); else if (format == "json") formatter = new JSONFormatter(pretty_format); else { cerr << "unrecognized format: " << format << std::endl; return usage(); } RGWStreamFlusher f(formatter, cout); bool raw_storage_op = (opt_cmd == OPT_REGION_GET || opt_cmd == OPT_REGION_LIST || opt_cmd == OPT_REGION_SET || opt_cmd == OPT_REGION_DEFAULT || opt_cmd == OPT_REGIONMAP_GET || opt_cmd == OPT_REGIONMAP_SET || opt_cmd == OPT_REGIONMAP_UPDATE || opt_cmd == OPT_ZONE_GET || opt_cmd == OPT_ZONE_SET || opt_cmd == OPT_ZONE_LIST); if (raw_storage_op) { store = RGWStoreManager::get_raw_storage(g_ceph_context); } else { store = RGWStoreManager::get_storage(g_ceph_context, false, false); } if (!store) { cerr << "couldn't init storage provider" << std::endl; return 5; //EIO } rgw_user_init(store->meta_mgr); rgw_bucket_init(store->meta_mgr); StoreDestructor store_destructor(store); if (raw_storage_op) { if (opt_cmd == OPT_REGION_GET) { RGWRegion region; int ret = region.init(g_ceph_context, store); if (ret < 0) { cerr << "failed to init region: " << cpp_strerror(-ret) << std::endl; return -ret; } encode_json("region", region, formatter); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_REGION_LIST) { RGWRegion region; int ret = region.init(g_ceph_context, store, false); if (ret < 0) { cerr << "failed to init region: " << cpp_strerror(-ret) << std::endl; return -ret; } list regions; ret = store->list_regions(regions); if (ret < 0) { cerr << "failed to list regions: " << cpp_strerror(-ret) << std::endl; return -ret; } RGWDefaultRegionInfo default_region; ret = region.read_default(default_region); if (ret < 0 && ret != -ENOENT) { cerr << "could not determine default region: " << cpp_strerror(-ret) << std::endl; } formatter->open_object_section("regions_list"); encode_json("default_info", default_region, formatter); encode_json("regions", regions, formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_REGION_SET) { RGWRegion region; int ret = region.init(g_ceph_context, store, false); if (ret < 0) { cerr << "failed to init region: " << cpp_strerror(-ret) << std::endl; return -ret; } ret = read_decode_json(infile, region); if (ret < 0) { return 1; } ret = region.store_info(false); if (ret < 0) { cerr << "ERROR: couldn't store zone info: " << cpp_strerror(-ret) << std::endl; return 1; } encode_json("region", region, formatter); formatter->flush(cout); } if (opt_cmd == OPT_REGION_DEFAULT) { RGWRegion region; int ret = region.init(g_ceph_context, store); if (ret < 0) { cerr << "failed to init region: " << cpp_strerror(-ret) << std::endl; return -ret; } ret = region.set_as_default(); if (ret < 0) { cerr << "failed to set region as default: " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_REGIONMAP_GET) { RGWRegionMap regionmap; int ret = regionmap.read(g_ceph_context, store); if (ret < 0) { cerr << "failed to read region map: " << cpp_strerror(-ret) << std::endl; return -ret; } encode_json("region-map", regionmap, formatter); formatter->flush(cout); } if (opt_cmd == OPT_REGIONMAP_SET) { RGWRegionMap regionmap; int ret = read_decode_json(infile, regionmap); if (ret < 0) { return 1; } ret = regionmap.store(g_ceph_context, store); if (ret < 0) { cerr << "ERROR: couldn't store region map info: " << cpp_strerror(-ret) << std::endl; return 1; } encode_json("region-map", regionmap, formatter); formatter->flush(cout); } if (opt_cmd == OPT_REGIONMAP_UPDATE) { RGWRegionMap regionmap; int ret = regionmap.read(g_ceph_context, store); if (ret < 0 && ret != -ENOENT) { cerr << "failed to read region map: " << cpp_strerror(-ret) << std::endl; return -ret; } RGWRegion region; ret = region.init(g_ceph_context, store, false); if (ret < 0) { cerr << "failed to init region: " << cpp_strerror(-ret) << std::endl; return -ret; } list regions; ret = store->list_regions(regions); if (ret < 0) { cerr << "failed to list regions: " << cpp_strerror(-ret) << std::endl; return -ret; } for (list::iterator iter = regions.begin(); iter != regions.end(); ++iter) { ret = region.read_info(*iter); if (ret < 0) { cerr << "failed to read region info (name=" << *iter << "): " << cpp_strerror(-ret) << std::endl; return -ret; } regionmap.update(region); } ret = regionmap.store(g_ceph_context, store); if (ret < 0) { cerr << "ERROR: couldn't store region map info: " << cpp_strerror(-ret) << std::endl; return 1; } encode_json("region-map", regionmap, formatter); formatter->flush(cout); } if (opt_cmd == OPT_ZONE_GET) { RGWRegion region; int ret = region.init(g_ceph_context, store); if (ret < 0) { cerr << "WARNING: failed to initialize region" << std::endl; } RGWZoneParams zone; ret = zone.init(g_ceph_context, store, region); if (ret < 0) { cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl; return -ret; } encode_json("zone", zone, formatter); formatter->flush(cout); } if (opt_cmd == OPT_ZONE_SET) { RGWRegion region; int ret = region.init(g_ceph_context, store); if (ret < 0) { cerr << "WARNING: failed to initialize region" << std::endl; } RGWZoneParams zone; zone.init_default(store); ret = read_decode_json(infile, zone); if (ret < 0) { return 1; } ret = zone.store_info(g_ceph_context, store, region); if (ret < 0) { cerr << "ERROR: couldn't store zone info: " << cpp_strerror(-ret) << std::endl; return 1; } encode_json("zone", zone, formatter); formatter->flush(cout); } if (opt_cmd == OPT_ZONE_LIST) { list zones; int ret = store->list_zones(zones); if (ret < 0) { cerr << "failed to list zones: " << cpp_strerror(-ret) << std::endl; return -ret; } formatter->open_object_section("zones_list"); encode_json("zones", zones, formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; } return 0; } if (!user_id.empty()) { user_op.set_user_id(user_id); bucket_op.set_user_id(user_id); } if (!display_name.empty()) user_op.set_display_name(display_name); if (!user_email.empty()) user_op.set_user_email(user_email); if (!access_key.empty()) user_op.set_access_key(access_key); if (!secret_key.empty()) user_op.set_secret_key(secret_key); if (!subuser.empty()) user_op.set_subuser(subuser); if (!caps.empty()) user_op.set_caps(caps); user_op.set_purge_data(purge_data); if (purge_keys) user_op.set_purge_keys(); if (gen_access_key) user_op.set_generate_key(); if (gen_secret_key) user_op.set_gen_secret(); // assume that a key pair should be created if (max_buckets >= 0) user_op.set_max_buckets(max_buckets); if (system_specified) user_op.set_system(system); if (set_perm) user_op.set_perm(perm_mask); if (set_temp_url_key) { map::iterator iter = temp_url_keys.begin(); for (; iter != temp_url_keys.end(); ++iter) { user_op.set_temp_url_key(iter->second, iter->first); } } if (!op_mask_str.empty()) { uint32_t op_mask; int ret = rgw_parse_op_type_list(op_mask_str, &op_mask); if (ret < 0) { cerr << "failed to parse op_mask: " << cpp_strerror(-ret) << std::endl; return -ret; } user_op.set_op_mask(op_mask); } if (key_type != KEY_TYPE_UNDEFINED) user_op.set_key_type(key_type); // set suspension operation parameters if (opt_cmd == OPT_USER_ENABLE) user_op.set_suspension(false); else if (opt_cmd == OPT_USER_SUSPEND) user_op.set_suspension(true); // RGWUser to use for user operations RGWUser user; int ret = 0; if (!user_id.empty() || !subuser.empty()) { ret = user.init(store, user_op); if (ret < 0) { cerr << "user.init failed: " << cpp_strerror(-ret) << std::endl; return -ret; } } /* populate bucket operation */ bucket_op.set_bucket_name(bucket_name); bucket_op.set_object(object); bucket_op.set_check_objects(check_objects); bucket_op.set_delete_children(delete_child_objects); // required to gather errors from operations std::string err_msg; bool output_user_info = true; switch (opt_cmd) { case OPT_USER_INFO: break; case OPT_USER_CREATE: if (!user_op.has_existing_user()) { user_op.set_generate_key(); // generate a new key by default } ret = user.add(user_op, &err_msg); if (ret < 0) { cerr << "could not create user: " << err_msg << std::endl; return -ret; } if (!subuser.empty()) { ret = user.subusers.add(user_op, &err_msg); if (ret < 0) { cerr << "could not create subuser: " << err_msg << std::endl; return -ret; } } break; case OPT_USER_RM: ret = user.remove(user_op, &err_msg); if (ret < 0) { cerr << "could not remove user: " << err_msg << std::endl; return -ret; } output_user_info = false; break; case OPT_USER_ENABLE: case OPT_USER_SUSPEND: case OPT_USER_MODIFY: ret = user.modify(user_op, &err_msg); if (ret < 0) { cerr << "could not modify user: " << err_msg << std::endl; return -ret; } break; case OPT_SUBUSER_CREATE: ret = user.subusers.add(user_op, &err_msg); if (ret < 0) { cerr << "could not create subuser: " << err_msg << std::endl; return -ret; } break; case OPT_SUBUSER_MODIFY: ret = user.subusers.modify(user_op, &err_msg); if (ret < 0) { cerr << "could not modify subuser: " << err_msg << std::endl; return -ret; } ret = user.info(info, &err_msg); if (ret < 0) { cerr << "could not fetch user info: " << err_msg << std::endl; return -ret; } show_user_info(info, formatter); break; case OPT_SUBUSER_RM: ret = user.subusers.remove(user_op, &err_msg); if (ret < 0) { cerr << "could not remove subuser: " << err_msg << std::endl; return -ret; } break; case OPT_CAPS_ADD: ret = user.caps.add(user_op, &err_msg); if (ret < 0) { cerr << "could not add caps: " << err_msg << std::endl; return -ret; } break; case OPT_CAPS_RM: ret = user.caps.remove(user_op, &err_msg); if (ret < 0) { cerr << "could not add remove caps: " << err_msg << std::endl; return -ret; } break; case OPT_KEY_CREATE: ret = user.keys.add(user_op, &err_msg); if (ret < 0) { cerr << "could not create key: " << err_msg << std::endl; return -ret; } break; case OPT_KEY_RM: ret = user.keys.remove(user_op, &err_msg); if (ret < 0) { cerr << "could not remove key: " << err_msg << std::endl; return -ret; } break; default: output_user_info = false; } // output the result of a user operation if (output_user_info) { ret = user.info(info, &err_msg); if (ret < 0) { cerr << "could not fetch user info: " << err_msg << std::endl; return -ret; } show_user_info(info, formatter); } if (opt_cmd == OPT_POLICY) { int ret = RGWBucketAdminOp::get_policy(store, bucket_op, cout); if (ret >= 0) { cout << std::endl; } } if (opt_cmd == OPT_BUCKETS_LIST) { if (bucket_name.empty()) { RGWBucketAdminOp::info(store, bucket_op, f); } else { RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } formatter->open_array_section("entries"); bool truncated; int count = 0; if (max_entries < 0) max_entries = 1000; string prefix; string delim; vector result; map common_prefixes; string ns; do { list entries; ret = store->list_objects(bucket, max_entries - count, prefix, delim, marker, NULL, result, common_prefixes, true, ns, false, &truncated, NULL); if (ret < 0) { cerr << "ERROR: store->list_objects(): " << cpp_strerror(-ret) << std::endl; return -ret; } count += result.size(); for (vector::iterator iter = result.begin(); iter != result.end(); ++iter) { RGWObjEnt& entry = *iter; encode_json("entry", entry, formatter); marker = entry.name; } formatter->flush(cout); } while (truncated && count < max_entries); formatter->close_section(); formatter->flush(cout); } } if (opt_cmd == OPT_BUCKET_STATS) { bucket_op.set_fetch_stats(true); RGWBucketAdminOp::info(store, bucket_op, f); } if (opt_cmd == OPT_BUCKET_LINK) { int r = RGWBucketAdminOp::link(store, bucket_op); if (r < 0) { cerr << "failure: " << cpp_strerror(-r) << std::endl; return -r; } } if (opt_cmd == OPT_BUCKET_UNLINK) { int r = RGWBucketAdminOp::unlink(store, bucket_op); if (r < 0) { cerr << "failure: " << cpp_strerror(-r) << std::endl; return -r; } } if (opt_cmd == OPT_TEMP_REMOVE) { if (date.empty()) { cerr << "date wasn't specified" << std::endl; return usage(); } string parsed_date, parsed_time; int r = utime_t::parse_date(date, NULL, NULL, &parsed_date, &parsed_time); if (r < 0) { cerr << "failure parsing date: " << cpp_strerror(r) << std::endl; return 1; } r = store->remove_temp_objects(parsed_date, parsed_time); if (r < 0) { cerr << "failure removing temp objects: " << cpp_strerror(r) << std::endl; return 1; } } if (opt_cmd == OPT_LOG_LIST) { // filter by date? if (date.size() && date.size() != 10) { cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl; return -EINVAL; } formatter->reset(); formatter->open_array_section("logs"); RGWAccessHandle h; int r = store->log_list_init(date, &h); if (r == -ENOENT) { // no logs. } else { if (r < 0) { cerr << "log list: error " << r << std::endl; return r; } while (true) { string name; int r = store->log_list_next(h, &name); if (r == -ENOENT) break; if (r < 0) { cerr << "log list: error " << r << std::endl; return r; } formatter->dump_string("object", name); } } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_LOG_SHOW || opt_cmd == OPT_LOG_RM) { if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id.empty())) { cerr << "specify an object or a date, bucket and bucket-id" << std::endl; return usage(); } string oid; if (!object.empty()) { oid = object; } else { oid = date; oid += "-"; oid += bucket_id; oid += "-"; oid += string(bucket.name); } if (opt_cmd == OPT_LOG_SHOW) { RGWAccessHandle h; int r = store->log_show_init(oid, &h); if (r < 0) { cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } formatter->reset(); formatter->open_object_section("log"); struct rgw_log_entry entry; // peek at first entry to get bucket metadata r = store->log_show_next(h, &entry); if (r < 0) { cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } formatter->dump_string("bucket_id", entry.bucket_id); formatter->dump_string("bucket_owner", entry.bucket_owner); formatter->dump_string("bucket", entry.bucket); uint64_t agg_time = 0; uint64_t agg_bytes_sent = 0; uint64_t agg_bytes_received = 0; uint64_t total_entries = 0; if (show_log_entries) formatter->open_array_section("log_entries"); do { uint64_t total_time = entry.total_time.sec() * 1000000LL * entry.total_time.usec(); agg_time += total_time; agg_bytes_sent += entry.bytes_sent; agg_bytes_received += entry.bytes_received; total_entries++; if (skip_zero_entries && entry.bytes_sent == 0 && entry.bytes_received == 0) goto next; if (show_log_entries) { rgw_format_ops_log_entry(entry, formatter); formatter->flush(cout); } next: r = store->log_show_next(h, &entry); } while (r > 0); if (r < 0) { cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } if (show_log_entries) formatter->close_section(); if (show_log_sum) { formatter->open_object_section("log_sum"); formatter->dump_int("bytes_sent", agg_bytes_sent); formatter->dump_int("bytes_received", agg_bytes_received); formatter->dump_int("total_time", agg_time); formatter->dump_int("total_entries", total_entries); formatter->close_section(); } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_LOG_RM) { int r = store->log_remove(oid); if (r < 0) { cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } } } if (opt_cmd == OPT_POOL_ADD) { if (pool_name.empty()) { cerr << "need to specify pool to add!" << std::endl; return usage(); } int ret = store->add_bucket_placement(pool_name); if (ret < 0) cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl; } if (opt_cmd == OPT_POOL_RM) { if (pool_name.empty()) { cerr << "need to specify pool to remove!" << std::endl; return usage(); } int ret = store->remove_bucket_placement(pool_name); if (ret < 0) cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl; } if (opt_cmd == OPT_POOLS_LIST) { set pools; int ret = store->list_placement_set(pools); if (ret < 0) { cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl; return ret; } formatter->reset(); formatter->open_array_section("pools"); set::iterator siter; for (siter = pools.begin(); siter != pools.end(); ++siter) { formatter->open_object_section("pool"); formatter->dump_string("name", *siter); formatter->close_section(); } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_USAGE_SHOW) { uint64_t start_epoch = 0; uint64_t end_epoch = (uint64_t)-1; int ret; if (!start_date.empty()) { ret = utime_t::parse_date(start_date, &start_epoch, NULL); if (ret < 0) { cerr << "ERROR: failed to parse start date" << std::endl; return 1; } } if (!end_date.empty()) { ret = utime_t::parse_date(end_date, &end_epoch, NULL); if (ret < 0) { cerr << "ERROR: failed to parse end date" << std::endl; return 1; } } ret = RGWUsage::show(store, user_id, start_epoch, end_epoch, show_log_entries, show_log_sum, &categories, f); if (ret < 0) { cerr << "ERROR: failed to show usage" << std::endl; return 1; } } if (opt_cmd == OPT_USAGE_TRIM) { if (user_id.empty() && !yes_i_really_mean_it) { cerr << "usage trim without user specified will remove *all* users data" << std::endl; cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl; return 1; } int ret; uint64_t start_epoch = 0; uint64_t end_epoch = (uint64_t)-1; if (!start_date.empty()) { ret = utime_t::parse_date(start_date, &start_epoch, NULL); if (ret < 0) { cerr << "ERROR: failed to parse start date" << std::endl; return 1; } } if (!end_date.empty()) { ret = utime_t::parse_date(end_date, &end_epoch, NULL); if (ret < 0) { cerr << "ERROR: failed to parse end date" << std::endl; return 1; } } ret = RGWUsage::trim(store, user_id, start_epoch, end_epoch); if (ret < 0) { cerr << "ERROR: read_usage() returned ret=" << ret << std::endl; return 1; } } if (opt_cmd == OPT_OBJECT_RM) { RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } ret = rgw_remove_object(store, bucket_info.owner, bucket, object); if (ret < 0) { cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_OBJECT_UNLINK) { RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } list oid_list; oid_list.push_back(object); ret = store->remove_objs_from_index(bucket, oid_list); if (ret < 0) { cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl; return 1; } } if (opt_cmd == OPT_OBJECT_STAT) { RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } rgw_obj obj(bucket, object); void *handle; uint64_t obj_size; map attrs; void *obj_ctx = store->create_context(NULL); ret = store->prepare_get_obj(obj_ctx, obj, NULL, NULL, &attrs, NULL, NULL, NULL, NULL, NULL, NULL, &obj_size, NULL, &handle, NULL); store->finish_get_obj(&handle); store->destroy_context(obj_ctx); if (ret < 0) { cerr << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << std::endl; return 1; } formatter->open_object_section("object_metadata"); formatter->dump_string("name", object); formatter->dump_unsigned("size", obj_size); map::iterator iter; map other_attrs; for (iter = attrs.begin(); iter != attrs.end(); ++iter) { bufferlist& bl = iter->second; bool handled = false; if (iter->first == RGW_ATTR_MANIFEST) { handled = decode_dump("manifest", bl, formatter); } else if (iter->first == RGW_ATTR_ACL) { handled = decode_dump("policy", bl, formatter); } else if (iter->first == RGW_ATTR_ID_TAG) { handled = dump_string("tag", bl, formatter); } else if (iter->first == RGW_ATTR_ETAG) { handled = dump_string("etag", bl, formatter); } if (!handled) other_attrs[iter->first] = bl; } formatter->open_object_section("attrs"); for (iter = other_attrs.begin(); iter != other_attrs.end(); ++iter) { dump_string(iter->first.c_str(), iter->second, formatter); } formatter->close_section(); formatter->close_section(); formatter->flush(cout); } if (opt_cmd == OPT_BUCKET_CHECK) { RGWBucketAdminOp::check_index(store, bucket_op, f); } if (opt_cmd == OPT_BUCKET_RM) { RGWBucketAdminOp::remove_bucket(store, bucket_op); } if (opt_cmd == OPT_GC_LIST) { int index = 0; bool truncated; formatter->open_array_section("entries"); do { list result; int ret = store->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated); if (ret < 0) { cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl; return 1; } list::iterator iter; for (iter = result.begin(); iter != result.end(); ++iter) { cls_rgw_gc_obj_info& info = *iter; formatter->open_object_section("chain_info"); formatter->dump_string("tag", info.tag); formatter->dump_stream("time") << info.time; formatter->open_array_section("objs"); list::iterator liter; cls_rgw_obj_chain& chain = info.chain; for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) { cls_rgw_obj& obj = *liter; encode_json("obj", obj, formatter); } formatter->close_section(); // objs formatter->close_section(); // obj_chain formatter->flush(cout); } } while (truncated); formatter->close_section(); formatter->flush(cout); } if (opt_cmd == OPT_GC_PROCESS) { int ret = store->process_gc(); if (ret < 0) { cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl; return 1; } } if (opt_cmd == OPT_USER_CHECK) { check_bad_user_bucket_mapping(store, user_id, fix); } if (opt_cmd == OPT_USER_STATS) { if (sync_stats) { if (!bucket_name.empty()) { int ret = rgw_bucket_sync_user_stats(store, bucket_name); if (ret < 0) { cerr << "ERROR: could not sync bucket stats: " << cpp_strerror(-ret) << std::endl; return -ret; } } else { int ret = rgw_user_sync_all_stats(store, user_id); if (ret < 0) { cerr << "ERROR: failed to sync user stats: " << cpp_strerror(-ret) << std::endl; return -ret; } } } if (user_id.empty()) { cerr << "ERROR: uid not specified" << std::endl; return EINVAL; } cls_user_header header; int ret = store->cls_user_get_header(user_id, &header); if (ret < 0) { cerr << "ERROR: can't read user header: " << cpp_strerror(-ret) << std::endl; return -ret; } encode_json("header", header, formatter); formatter->flush(cout); } if (opt_cmd == OPT_METADATA_GET) { int ret = store->meta_mgr->get(metadata_key, formatter); if (ret < 0) { cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl; return -ret; } formatter->flush(cout); } if (opt_cmd == OPT_METADATA_PUT) { bufferlist bl; int ret = read_input(infile, bl); if (ret < 0) { cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl; return ret; } ret = store->meta_mgr->put(metadata_key, bl, RGWMetadataHandler::APPLY_ALWAYS); if (ret < 0) { cerr << "ERROR: can't put key: " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_METADATA_RM) { int ret = store->meta_mgr->remove(metadata_key); if (ret < 0) { cerr << "ERROR: can't remove key: " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_METADATA_LIST) { void *handle; int max = 1000; int ret = store->meta_mgr->list_keys_init(metadata_key, &handle); if (ret < 0) { cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl; return -ret; } bool truncated; formatter->open_array_section("keys"); do { list keys; ret = store->meta_mgr->list_keys_next(handle, max, keys, &truncated); if (ret < 0) { cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl; return -ret; } for (list::iterator iter = keys.begin(); iter != keys.end(); ++iter) { formatter->dump_string("key", *iter); } formatter->flush(cout); } while (truncated); formatter->close_section(); formatter->flush(cout); store->meta_mgr->list_keys_complete(handle); } if (opt_cmd == OPT_MDLOG_LIST) { utime_t start_time, end_time; int ret = parse_date_str(start_date, start_time); if (ret < 0) return -ret; ret = parse_date_str(end_date, end_time); if (ret < 0) return -ret; int i = (specified_shard_id ? shard_id : 0); formatter->open_array_section("entries"); for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) { RGWMetadataLog *meta_log = store->meta_mgr->get_log(); void *handle; list entries; meta_log->init_list_entries(i, start_time, end_time, marker, &handle); bool truncated; do { int ret = meta_log->list_entries(handle, 1000, entries, NULL, &truncated); if (ret < 0) { cerr << "ERROR: meta_log->list_entries(): " << cpp_strerror(-ret) << std::endl; return -ret; } for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { cls_log_entry& entry = *iter; store->meta_mgr->dump_log_entry(entry, formatter); } formatter->flush(cout); } while (truncated); meta_log->complete_list_entries(handle); if (specified_shard_id) break; } formatter->close_section(); formatter->flush(cout); } if (opt_cmd == OPT_MDLOG_TRIM) { utime_t start_time, end_time; if (!specified_shard_id) { cerr << "ERROR: shard-id must be specified for trim operation" << std::endl; return EINVAL; } int ret = parse_date_str(start_date, start_time); if (ret < 0) return -ret; ret = parse_date_str(end_date, end_time); if (ret < 0) return -ret; RGWMetadataLog *meta_log = store->meta_mgr->get_log(); ret = meta_log->trim(shard_id, start_time, end_time, start_marker, end_marker); if (ret < 0) { cerr << "ERROR: meta_log->trim(): " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_BILOG_LIST) { if (bucket_name.empty()) { cerr << "ERROR: bucket not specified" << std::endl; return -EINVAL; } RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } formatter->open_array_section("entries"); bool truncated; int count = 0; if (max_entries < 0) max_entries = 1000; do { list entries; ret = store->list_bi_log_entries(bucket, marker, max_entries - count, entries, &truncated); if (ret < 0) { cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl; return -ret; } count += entries.size(); for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { rgw_bi_log_entry& entry = *iter; encode_json("entry", entry, formatter); marker = entry.id; } formatter->flush(cout); } while (truncated && count < max_entries); formatter->close_section(); formatter->flush(cout); } if (opt_cmd == OPT_BILOG_TRIM) { if (bucket_name.empty()) { cerr << "ERROR: bucket not specified" << std::endl; return -EINVAL; } RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } ret = store->trim_bi_log_entries(bucket, start_marker, end_marker); if (ret < 0) { cerr << "ERROR: trim_bi_log_entries(): " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_DATALOG_LIST) { formatter->open_array_section("entries"); bool truncated; int count = 0; if (max_entries < 0) max_entries = 1000; utime_t start_time, end_time; int ret = parse_date_str(start_date, start_time); if (ret < 0) return -ret; ret = parse_date_str(end_date, end_time); if (ret < 0) return -ret; RGWDataChangesLog *log = store->data_log; RGWDataChangesLog::LogMarker marker; do { list entries; ret = log->list_entries(start_time, end_time, max_entries - count, entries, marker, &truncated); if (ret < 0) { cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl; return -ret; } count += entries.size(); for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { rgw_data_change& entry = *iter; encode_json("entry", entry, formatter); } formatter->flush(cout); } while (truncated && count < max_entries); formatter->close_section(); formatter->flush(cout); } if (opt_cmd == OPT_DATALOG_TRIM) { utime_t start_time, end_time; int ret = parse_date_str(start_date, start_time); if (ret < 0) return -ret; ret = parse_date_str(end_date, end_time); if (ret < 0) return -ret; RGWDataChangesLog *log = store->data_log; ret = log->trim_entries(start_time, end_time, start_marker, end_marker); if (ret < 0) { cerr << "ERROR: trim_entries(): " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_OPSTATE_LIST) { RGWOpState oc(store); int max = 1000; void *handle; oc.init_list_entries(client_id, op_id, object, &handle); list entries; bool done; formatter->open_array_section("entries"); do { int ret = oc.list_entries(handle, max, entries, &done); if (ret < 0) { cerr << "oc.list_entries returned " << cpp_strerror(-ret) << std::endl; oc.finish_list_entries(handle); return -ret; } for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { oc.dump_entry(*iter, formatter); } formatter->flush(cout); } while (!done); formatter->close_section(); formatter->flush(cout); oc.finish_list_entries(handle); } if (opt_cmd == OPT_OPSTATE_SET || opt_cmd == OPT_OPSTATE_RENEW) { RGWOpState oc(store); RGWOpState::OpState state; if (object.empty() || client_id.empty() || op_id.empty()) { cerr << "ERROR: need to specify client_id, op_id, and object" << std::endl; return EINVAL; } if (state_str.empty()) { cerr << "ERROR: state was not specified" << std::endl; return EINVAL; } int ret = oc.state_from_str(state_str, &state); if (ret < 0) { cerr << "ERROR: invalid state: " << state_str << std::endl; return -ret; } if (opt_cmd == OPT_OPSTATE_SET) { ret = oc.set_state(client_id, op_id, object, state); if (ret < 0) { cerr << "ERROR: failed to set state: " << cpp_strerror(-ret) << std::endl; return -ret; } } else { ret = oc.renew_state(client_id, op_id, object, state); if (ret < 0) { cerr << "ERROR: failed to renew state: " << cpp_strerror(-ret) << std::endl; return -ret; } } } if (opt_cmd == OPT_OPSTATE_RM) { RGWOpState oc(store); if (object.empty() || client_id.empty() || op_id.empty()) { cerr << "ERROR: need to specify client_id, op_id, and object" << std::endl; return EINVAL; } ret = oc.remove_entry(client_id, op_id, object); if (ret < 0) { cerr << "ERROR: failed to set state: " << cpp_strerror(-ret) << std::endl; return -ret; } } if (opt_cmd == OPT_REPLICALOG_GET || opt_cmd == OPT_REPLICALOG_DELETE) { if (replica_log_type_str.empty()) { cerr << "ERROR: need to specify --replica-log-type=" << std::endl; return EINVAL; } } if (opt_cmd == OPT_REPLICALOG_GET) { RGWReplicaBounds bounds; if (replica_log_type == ReplicaLog_Metadata) { if (!specified_shard_id) { cerr << "ERROR: shard-id must be specified for get operation" << std::endl; return EINVAL; } RGWReplicaObjectLogger logger(store, pool_name, META_REPLICA_LOG_OBJ_PREFIX); int ret = logger.get_bounds(shard_id, bounds); if (ret < 0) return -ret; } else if (replica_log_type == ReplicaLog_Data) { if (!specified_shard_id) { cerr << "ERROR: shard-id must be specified for get operation" << std::endl; return EINVAL; } RGWReplicaObjectLogger logger(store, pool_name, DATA_REPLICA_LOG_OBJ_PREFIX); int ret = logger.get_bounds(shard_id, bounds); if (ret < 0) return -ret; } else if (replica_log_type == ReplicaLog_Bucket) { if (bucket_name.empty()) { cerr << "ERROR: bucket not specified" << std::endl; return -EINVAL; } RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } RGWReplicaBucketLogger logger(store); ret = logger.get_bounds(bucket, bounds); if (ret < 0) return -ret; } else { // shouldn't get here assert(0); } encode_json("bounds", bounds, formatter); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_REPLICALOG_DELETE) { if (replica_log_type == ReplicaLog_Metadata) { if (!specified_shard_id) { cerr << "ERROR: shard-id must be specified for delete operation" << std::endl; return EINVAL; } if (!specified_daemon_id) { cerr << "ERROR: daemon-id must be specified for delete operation" << std::endl; return EINVAL; } RGWReplicaObjectLogger logger(store, pool_name, META_REPLICA_LOG_OBJ_PREFIX); int ret = logger.delete_bound(shard_id, daemon_id); if (ret < 0) return -ret; } else if (replica_log_type == ReplicaLog_Data) { if (!specified_shard_id) { cerr << "ERROR: shard-id must be specified for delete operation" << std::endl; return EINVAL; } if (!specified_daemon_id) { cerr << "ERROR: daemon-id must be specified for delete operation" << std::endl; return EINVAL; } RGWReplicaObjectLogger logger(store, pool_name, DATA_REPLICA_LOG_OBJ_PREFIX); int ret = logger.delete_bound(shard_id, daemon_id); if (ret < 0) return -ret; } else if (replica_log_type == ReplicaLog_Bucket) { if (bucket_name.empty()) { cerr << "ERROR: bucket not specified" << std::endl; return -EINVAL; } RGWBucketInfo bucket_info; int ret = init_bucket(bucket_name, bucket_info, bucket); if (ret < 0) { cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl; return -ret; } RGWReplicaBucketLogger logger(store); ret = logger.delete_bound(bucket, daemon_id); if (ret < 0) return -ret; } } bool quota_op = (opt_cmd == OPT_QUOTA_SET || opt_cmd == OPT_QUOTA_ENABLE || opt_cmd == OPT_QUOTA_DISABLE); if (quota_op) { if (bucket_name.empty() && user_id.empty()) { cerr << "ERROR: bucket name or uid is required for quota operation" << std::endl; return EINVAL; } if (!bucket_name.empty()) { if (!quota_scope.empty() && quota_scope != "bucket") { cerr << "ERROR: invalid quota scope specification." << std::endl; return EINVAL; } set_bucket_quota(store, opt_cmd, bucket_name, max_size, max_objects, have_max_size, have_max_objects); } else if (!user_id.empty()) { if (quota_scope == "bucket") { set_user_bucket_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects); } else if (quota_scope == "user") { set_user_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects); } else { cerr << "ERROR: invalid quota scope specification. Please specify either --quota-scope=bucket, or --quota-scope=user" << std::endl; return EINVAL; } } } return 0; } ceph-0.80.11/src/rgw/rgw_resolve.cc0000664000175100017510000000671512623076744021141 0ustar jenkins-buildjenkins-build#include #include #include #include #include "acconfig.h" #ifdef HAVE_ARPA_NAMESER_COMPAT_H #include #endif #include "rgw_common.h" #include "rgw_resolve.h" #define dout_subsys ceph_subsys_rgw class RGWDNSResolver { list states; Mutex lock; int get_state(res_state *ps); void put_state(res_state s); public: ~RGWDNSResolver(); RGWDNSResolver() : lock("RGWDNSResolver") {} int resolve_cname(const string& hostname, string& cname, bool *found); }; RGWDNSResolver::~RGWDNSResolver() { list::iterator iter; for (iter = states.begin(); iter != states.end(); ++iter) { struct __res_state *s = *iter; delete s; } } int RGWDNSResolver::get_state(res_state *ps) { lock.Lock(); if (!states.empty()) { res_state s = states.front(); states.pop_front(); lock.Unlock(); *ps = s; return 0; } lock.Unlock(); struct __res_state *s = new struct __res_state; s->options = 0; if (res_ninit(s) < 0) { delete s; dout(0) << "ERROR: failed to call res_ninit()" << dendl; return -EINVAL; } *ps = s; return 0; } void RGWDNSResolver::put_state(res_state s) { Mutex::Locker l(lock); states.push_back(s); } int RGWDNSResolver::resolve_cname(const string& hostname, string& cname, bool *found) { res_state res; *found = false; int r = get_state(&res); if (r < 0) { return r; } int ret; #define LARGE_ENOUGH_DNS_BUFSIZE 1024 unsigned char buf[LARGE_ENOUGH_DNS_BUFSIZE]; #define MAX_FQDN_SIZE 255 char host[MAX_FQDN_SIZE + 1]; const char *origname = hostname.c_str(); unsigned char *pt, *answer; unsigned char *answend; int len = res_nquery(res, origname, C_IN, T_CNAME, buf, sizeof(buf)); if (len < 0) { dout(20) << "res_query() failed" << dendl; ret = 0; goto done; } answer = buf; pt = answer + sizeof(HEADER); answend = answer + len; /* read query */ if ((len = dn_expand(answer, answend, pt, host, sizeof(host))) < 0) { dout(0) << "ERROR: dn_expand() failed" << dendl; ret = -EINVAL; goto done; } pt += len; if (pt + 4 > answend) { dout(0) << "ERROR: bad reply" << dendl; ret = -EIO; goto done; } int type; GETSHORT(type, pt); if (type != T_CNAME) { dout(0) << "ERROR: failed response type: type=%d (was expecting " << T_CNAME << ")" << dendl; ret = -EIO; goto done; } pt += INT16SZ; /* class */ /* read answer */ if ((len = dn_expand(answer, answend, pt, host, sizeof(host))) < 0) { ret = 0; goto done; } pt += len; dout(20) << "name=" << host << dendl; if (pt + 10 > answend) { dout(0) << "ERROR: bad reply" << dendl; ret = -EIO; goto done; } GETSHORT(type, pt); pt += INT16SZ; /* class */ pt += INT32SZ; /* ttl */ pt += INT16SZ; /* size */ if ((len = dn_expand(answer, answend, pt, host, sizeof(host))) < 0) { ret = 0; goto done; } dout(20) << "cname host=" << host << dendl; cname = host; *found = true; ret = 0; done: put_state(res); return ret; } RGWResolver::~RGWResolver() { delete resolver; } RGWResolver::RGWResolver() { resolver = new RGWDNSResolver; } int RGWResolver::resolve_cname(const string& hostname, string& cname, bool *found) { return resolver->resolve_cname(hostname, cname, found); }; RGWResolver *rgw_resolver; void rgw_init_resolver() { rgw_resolver = new RGWResolver(); } void rgw_shutdown_resolver() { delete rgw_resolver; } ceph-0.80.11/src/rgw/logrotate.conf0000664000175100017510000000174712623076744021143 0ustar jenkins-buildjenkins-build/var/log/radosgw/*.log { rotate 7 daily compress sharedscripts postrotate if which invoke-rc.d > /dev/null 2>&1 && [ -x `which invoke-rc.d` ]; then invoke-rc.d radosgw reload >/dev/null elif which service > /dev/null 2>&1 && [ -x `which service` ]; then service ceph-radosgw reload >/dev/null fi # Possibly reload twice, but depending on ceph.conf the reload above may be a no-op if which initctl > /dev/null 2>&1 && [ -x `which initctl` ]; then find -L /var/lib/ceph/radosgw/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -printf '%P\n' \ | while read f; do if [ -e "/var/lib/ceph/radosgw/$f/done" ]; then cluster="${f%%-*}" id="${f#*-}" initctl reload radosgw cluster="$cluster" id="$id" 2>/dev/null || : fi done fi endscript missingok notifempty } ceph-0.80.11/src/rgw/rgw_auth_s3.h0000664000175100017510000000107112623076744020660 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_AUTH_S3_H #define CEPH_RGW_AUTH_S3_H #include "rgw_common.h" void rgw_create_s3_canonical_header(const char *method, const char *content_md5, const char *content_type, const char *date, map& meta_map, const char *request_uri, map& sub_resources, string& dest_str); bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time, string& dest, bool qsr); int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& dest); #endif ceph-0.80.11/src/rgw/rgw_rest_replica_log.h0000664000175100017510000000716412623076744022640 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_REST_REPLICA_LOG_H #define CEPH_RGW_REST_REPLICA_LOG_H class RGWOp_OBJLog_GetBounds : public RGWRESTOp { string prefix; string obj_type; RGWReplicaBounds bounds; public: RGWOp_OBJLog_GetBounds(const char *_prefix, const char *type) : prefix(_prefix), obj_type(type){} ~RGWOp_OBJLog_GetBounds() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap(obj_type.c_str(), RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { string s = "replica"; s.append(obj_type); s.append("_getbounds"); return s; } }; class RGWOp_OBJLog_SetBounds : public RGWRESTOp { string prefix; string obj_type; public: RGWOp_OBJLog_SetBounds(const char *_prefix, const char *type) : prefix(_prefix), obj_type(type){} ~RGWOp_OBJLog_SetBounds() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap(obj_type.c_str(), RGW_CAP_WRITE); } void execute(); virtual const string name() { string s = "replica"; s.append(obj_type); s.append("_updatebounds"); return s; } }; class RGWOp_OBJLog_DeleteBounds : public RGWRESTOp { string prefix; string obj_type; public: RGWOp_OBJLog_DeleteBounds(const char *_prefix, const char *type) : prefix(_prefix), obj_type(type){} ~RGWOp_OBJLog_DeleteBounds() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap(obj_type.c_str(), RGW_CAP_WRITE); } void execute(); virtual const string name() { string s = "replica"; s.append(obj_type); s.append("_deletebound"); return s; } }; class RGWOp_BILog_GetBounds : public RGWRESTOp { RGWReplicaBounds bounds; public: RGWOp_BILog_GetBounds() {} ~RGWOp_BILog_GetBounds() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("bilog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "replicabilog_getbounds"; } }; class RGWOp_BILog_SetBounds : public RGWRESTOp { public: RGWOp_BILog_SetBounds() {} ~RGWOp_BILog_SetBounds() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("bilog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "replicabilog_updatebounds"; } }; class RGWOp_BILog_DeleteBounds : public RGWRESTOp { public: RGWOp_BILog_DeleteBounds() {} ~RGWOp_BILog_DeleteBounds() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("bilog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "replicabilog_deletebound"; } }; class RGWHandler_ReplicaLog : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); RGWOp *op_delete(); RGWOp *op_post(); int read_permissions(RGWOp*) { return 0; } public: RGWHandler_ReplicaLog() : RGWHandler_Auth_S3() {} virtual ~RGWHandler_ReplicaLog() {} }; class RGWRESTMgr_ReplicaLog : public RGWRESTMgr { public: RGWRESTMgr_ReplicaLog() {} virtual ~RGWRESTMgr_ReplicaLog() {} virtual RGWHandler *get_handler(struct req_state *s){ return new RGWHandler_ReplicaLog; } }; #endif /*!CEPH_RGW_REST_REPLICA_LOG_H*/ ceph-0.80.11/src/rgw/rgw_http_errors.h0000664000175100017510000001025112623076744021665 0ustar jenkins-buildjenkins-build#ifndef RGW_HTTP_ERRORS_H_ #define RGW_HTTP_ERRORS_H_ #include "rgw_common.h" struct rgw_http_errors { int err_no; int http_ret; const char *s3_code; }; const static struct rgw_http_errors RGW_HTTP_ERRORS[] = { { 0, 200, "" }, { STATUS_CREATED, 201, "Created" }, { STATUS_ACCEPTED, 202, "Accepted" }, { STATUS_NO_CONTENT, 204, "NoContent" }, { STATUS_PARTIAL_CONTENT, 206, "" }, { ERR_PERMANENT_REDIRECT, 301, "PermanentRedirect" }, { STATUS_REDIRECT, 303, "" }, { ERR_NOT_MODIFIED, 304, "NotModified" }, { EINVAL, 400, "InvalidArgument" }, { ERR_INVALID_REQUEST, 400, "InvalidRequest" }, { ERR_INVALID_DIGEST, 400, "InvalidDigest" }, { ERR_BAD_DIGEST, 400, "BadDigest" }, { ERR_INVALID_BUCKET_NAME, 400, "InvalidBucketName" }, { ERR_INVALID_OBJECT_NAME, 400, "InvalidObjectName" }, { ERR_UNRESOLVABLE_EMAIL, 400, "UnresolvableGrantByEmailAddress" }, { ERR_INVALID_PART, 400, "InvalidPart" }, { ERR_INVALID_PART_ORDER, 400, "InvalidPartOrder" }, { ERR_REQUEST_TIMEOUT, 400, "RequestTimeout" }, { ERR_TOO_LARGE, 400, "EntityTooLarge" }, { ERR_TOO_SMALL, 400, "EntityTooSmall" }, { ERR_TOO_MANY_BUCKETS, 400, "TooManyBuckets" }, { ERR_LENGTH_REQUIRED, 411, "MissingContentLength" }, { EACCES, 403, "AccessDenied" }, { EPERM, 403, "AccessDenied" }, { ERR_USER_SUSPENDED, 403, "UserSuspended" }, { ERR_REQUEST_TIME_SKEWED, 403, "RequestTimeTooSkewed" }, { ERR_QUOTA_EXCEEDED, 403, "QuotaExceeded" }, { ENOENT, 404, "NoSuchKey" }, { ERR_NO_SUCH_BUCKET, 404, "NoSuchBucket" }, { ERR_NO_SUCH_UPLOAD, 404, "NoSuchUpload" }, { ERR_NOT_FOUND, 404, "Not Found"}, { ERR_METHOD_NOT_ALLOWED, 405, "MethodNotAllowed" }, { ETIMEDOUT, 408, "RequestTimeout" }, { EEXIST, 409, "BucketAlreadyExists" }, { ENOTEMPTY, 409, "BucketNotEmpty" }, { ERR_PRECONDITION_FAILED, 412, "PreconditionFailed" }, { ERANGE, 416, "InvalidRange" }, { ERR_UNPROCESSABLE_ENTITY, 422, "UnprocessableEntity" }, { ERR_LOCKED, 423, "Locked" }, { ERR_INTERNAL_ERROR, 500, "InternalError" }, }; const static struct rgw_http_errors RGW_HTTP_SWIFT_ERRORS[] = { { EACCES, 401, "AccessDenied" }, { EPERM, 401, "AccessDenied" }, { ERR_USER_SUSPENDED, 401, "UserSuspended" }, { ERR_INVALID_UTF8, 412, "Invalid UTF8" }, { ERR_BAD_URL, 412, "Bad URL" }, }; struct rgw_http_status_code { int code; const char *name; }; const static struct rgw_http_status_code http_codes[] = { { 100, "Continue" }, { 200, "OK" }, { 201, "Created" }, { 202, "Accepted" }, { 204, "No Content" }, { 205, "Reset Content" }, { 206, "Partial Content" }, { 207, "Multi Status" }, { 208, "Already Reported" }, { 300, "Multiple Choices" }, { 302, "Found" }, { 303, "See Other" }, { 304, "Not Modified" }, { 305, "User Proxy" }, { 306, "Switch Proxy" }, { 307, "Temporary Redirect" }, { 308, "Permanent Redirect" }, { 400, "Bad Request" }, { 401, "Unauthorized" }, { 402, "Payment Required" }, { 403, "Forbidden" }, { 404, "Not Found" }, { 405, "Method Not Allowed" }, { 406, "Not Acceptable" }, { 407, "Proxy Authentication Required" }, { 408, "Request Timeout" }, { 409, "Conflict" }, { 410, "Gone" }, { 411, "Length Required" }, { 412, "Precondition Failed" }, { 413, "Request Entity Too Large" }, { 414, "Request-URI Too Long" }, { 415, "Unsupported Media Type" }, { 416, "Requested Range Not Satisfiable" }, { 417, "Expectation Failed" }, { 422, "Unprocessable Entity" }, { 500, "Internal Server Error" }, { 0, NULL }, }; #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) static inline const struct rgw_http_errors *search_err(int err_no, const struct rgw_http_errors *errs, int len) { for (int i = 0; i < len; ++i, ++errs) { if (err_no == errs->err_no) return errs; } return NULL; } static inline int rgw_http_error_to_errno(int http_err) { if (http_err >= 200 && http_err <= 299) return 0; switch (http_err) { case 400: return -EINVAL; case 401: return -EPERM; case 403: return -EACCES; case 404: return -ENOENT; default: return -EIO; } return 0; /* unreachable */ } #endif ceph-0.80.11/src/rgw/rgw_rest_config.h0000664000175100017510000000233312623076744021616 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_REST_CONFIG_H #define CEPH_RGW_REST_CONFIG_H class RGWOp_RegionMap_Get : public RGWRESTOp { RGWRegionMap regionmap; public: RGWOp_RegionMap_Get() {} ~RGWOp_RegionMap_Get() {} int verify_permission() { return 0; } void execute(); virtual void send_response(); virtual const string name() { return "get_region_map"; } }; class RGWHandler_Config : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); int read_permissions(RGWOp*) { return 0; } public: RGWHandler_Config() : RGWHandler_Auth_S3() {} virtual ~RGWHandler_Config() {} }; class RGWRESTMgr_Config : public RGWRESTMgr { public: RGWRESTMgr_Config() {} virtual ~RGWRESTMgr_Config() {} virtual RGWHandler *get_handler(struct req_state *s){ return new RGWHandler_Config; } }; #endif ceph-0.80.11/src/rgw/rgw_loadgen.cc0000664000175100017510000000463112623076744021066 0ustar jenkins-buildjenkins-build #include #include "rgw_loadgen.h" #include "rgw_auth_s3.h" #define dout_subsys ceph_subsys_rgw void RGWLoadGenRequestEnv::set_date(utime_t& tm) { stringstream s; tm.asctime(s); date_str = s.str(); } int RGWLoadGenRequestEnv::sign(RGWAccessKey& access_key) { map meta_map; map sub_resources; string canonical_header; string digest; rgw_create_s3_canonical_header(request_method.c_str(), NULL, /* const char *content_md5 */ content_type.c_str(), date_str.c_str(), meta_map, uri.c_str(), sub_resources, canonical_header); int ret = rgw_get_s3_header_digest(canonical_header, access_key.key, digest); if (ret < 0) { return ret; } headers["HTTP_DATE"] = date_str; headers["HTTP_AUTHORIZATION"] = string("AWS ") + access_key.id + ":" + digest; return 0; } int RGWLoadGenIO::write_data(const char *buf, int len) { return len; } int RGWLoadGenIO::read_data(char *buf, int len) { int read_len = MIN(left_to_read, (uint64_t)len); left_to_read -= read_len; return read_len; } void RGWLoadGenIO::flush() { } int RGWLoadGenIO::complete_request() { return 0; } void RGWLoadGenIO::init_env(CephContext *cct) { env.init(cct); left_to_read = req->content_length; char buf[32]; snprintf(buf, sizeof(buf), "%lld", (long long)req->content_length); env.set("CONTENT_LENGTH", buf); env.set("CONTENT_TYPE", req->content_type.c_str()); env.set("HTTP_DATE", req->date_str.c_str()); for (map::iterator iter = req->headers.begin(); iter != req->headers.end(); ++iter) { env.set(iter->first.c_str(), iter->second.c_str()); } env.set("REQUEST_METHOD", req->request_method.c_str()); env.set("REQUEST_URI", req->uri.c_str()); env.set("QUERY_STRING", req->query_string.c_str()); env.set("SCRIPT_URI", req->uri.c_str()); char port_buf[16]; snprintf(port_buf, sizeof(port_buf), "%d", req->port); env.set("SERVER_PORT", port_buf); } int RGWLoadGenIO::send_status(const char *status, const char *status_name) { return 0; } int RGWLoadGenIO::send_100_continue() { return 0; } int RGWLoadGenIO::complete_header() { return 0; } int RGWLoadGenIO::send_content_length(uint64_t len) { return 0; } ceph-0.80.11/src/rgw/rgw_json_enc.cc0000664000175100017510000005702712623076744021262 0ustar jenkins-buildjenkins-build #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_log.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" #include "rgw_cache.h" #include "rgw_bucket.h" #include "rgw_keystone.h" #include "common/ceph_json.h" #include "common/Formatter.h" void encode_json(const char *name, const obj_version& v, Formatter *f) { f->open_object_section(name); f->dump_string("tag", v.tag); f->dump_unsigned("ver", v.ver); f->close_section(); } void decode_json_obj(obj_version& v, JSONObj *obj) { JSONDecoder::decode_json("tag", v.tag, obj); JSONDecoder::decode_json("ver", v.ver, obj); } void encode_json(const char *name, const RGWUserCaps& val, Formatter *f) { val.dump(f, name); } void RGWObjManifestPart::dump(Formatter *f) const { f->open_object_section("loc"); loc.dump(f); f->close_section(); f->dump_unsigned("loc_ofs", loc_ofs); f->dump_unsigned("size", size); } void RGWObjManifestRule::dump(Formatter *f) const { encode_json("start_part_num", start_part_num, f); encode_json("start_ofs", start_ofs, f); encode_json("part_size", part_size, f); encode_json("stripe_max_size", stripe_max_size, f); encode_json("override_prefix", override_prefix, f); } void RGWObjManifest::dump(Formatter *f) const { map::const_iterator iter = objs.begin(); f->open_array_section("objs"); for (; iter != objs.end(); ++iter) { f->dump_unsigned("ofs", iter->first); f->open_object_section("part"); iter->second.dump(f); f->close_section(); } f->close_section(); f->dump_unsigned("obj_size", obj_size); ::encode_json("explicit_objs", explicit_objs, f); ::encode_json("head_obj", head_obj, f); ::encode_json("head_size", head_size, f); ::encode_json("max_head_size", max_head_size, f); ::encode_json("prefix", prefix, f); ::encode_json("tail_bucket", tail_bucket, f); ::encode_json("rules", rules, f); } void rgw_log_entry::dump(Formatter *f) const { f->dump_string("object_owner", object_owner); f->dump_string("bucket_owner", bucket_owner); f->dump_string("bucket", bucket); f->dump_stream("time") << time; f->dump_string("remote_addr", remote_addr); f->dump_string("user", user); f->dump_string("obj", obj); f->dump_string("op", op); f->dump_string("uri", uri); f->dump_string("http_status", http_status); f->dump_string("error_code", error_code); f->dump_unsigned("bytes_sent", bytes_sent); f->dump_unsigned("bytes_received", bytes_received); f->dump_unsigned("obj_size", obj_size); f->dump_stream("total_time") << total_time; f->dump_string("user_agent", user_agent); f->dump_string("referrer", referrer); f->dump_string("bucket_id", bucket_id); } void rgw_intent_log_entry::dump(Formatter *f) const { f->open_object_section("obj"); obj.dump(f); f->close_section(); f->dump_stream("op_time") << op_time; f->dump_unsigned("intent", intent); } void ACLPermission::dump(Formatter *f) const { f->dump_int("flags", flags); } void ACLGranteeType::dump(Formatter *f) const { f->dump_unsigned("type", type); } void ACLGrant::dump(Formatter *f) const { f->open_object_section("type"); type.dump(f); f->close_section(); f->dump_string("id", id); f->dump_string("email", email); f->open_object_section("permission"); permission.dump(f); f->close_section(); f->dump_string("name", name); f->dump_int("group", (int)group); } void RGWAccessControlList::dump(Formatter *f) const { map::const_iterator acl_user_iter = acl_user_map.begin(); f->open_array_section("acl_user_map"); for (; acl_user_iter != acl_user_map.end(); ++acl_user_iter) { f->open_object_section("entry"); f->dump_string("user", acl_user_iter->first); f->dump_int("acl", acl_user_iter->second); f->close_section(); } f->close_section(); map::const_iterator acl_group_iter = acl_group_map.begin(); f->open_array_section("acl_group_map"); for (; acl_group_iter != acl_group_map.end(); ++acl_group_iter) { f->open_object_section("entry"); f->dump_unsigned("group", acl_group_iter->first); f->dump_int("acl", acl_group_iter->second); f->close_section(); } f->close_section(); multimap::const_iterator giter = grant_map.begin(); f->open_array_section("grant_map"); for (; giter != grant_map.end(); ++giter) { f->open_object_section("entry"); f->dump_string("id", giter->first); f->open_object_section("grant"); giter->second.dump(f); f->close_section(); f->close_section(); } f->close_section(); } void ACLOwner::dump(Formatter *f) const { encode_json("id", id, f); encode_json("display_name", display_name, f); } void RGWAccessControlPolicy::dump(Formatter *f) const { encode_json("acl", acl, f); encode_json("owner", owner, f); } void ObjectMetaInfo::dump(Formatter *f) const { encode_json("size", size, f); encode_json("mtime", mtime, f); } void ObjectCacheInfo::dump(Formatter *f) const { encode_json("status", status, f); encode_json("flags", flags, f); encode_json("data", data, f); encode_json_map("xattrs", "name", "value", "length", xattrs, f); encode_json_map("rm_xattrs", "name", "value", "length", rm_xattrs, f); encode_json("meta", meta, f); } void RGWCacheNotifyInfo::dump(Formatter *f) const { encode_json("op", op, f); encode_json("obj", obj, f); encode_json("obj_info", obj_info, f); encode_json("ofs", ofs, f); encode_json("ns", ns, f); } void RGWAccessKey::dump(Formatter *f) const { encode_json("access_key", id, f); encode_json("secret_key", key, f); encode_json("subuser", subuser, f); } void RGWAccessKey::dump_plain(Formatter *f) const { encode_json("access_key", id, f); encode_json("secret_key", key, f); } void encode_json_plain(const char *name, const RGWAccessKey& val, Formatter *f) { f->open_object_section(name); val.dump_plain(f); f->close_section(); } void RGWAccessKey::dump(Formatter *f, const string& user, bool swift) const { string u = user; if (!subuser.empty()) { u.append(":"); u.append(subuser); } encode_json("user", u, f); if (!swift) { encode_json("access_key", id, f); } encode_json("secret_key", key, f); } void RGWAccessKey::decode_json(JSONObj *obj) { JSONDecoder::decode_json("access_key", id, obj, true); JSONDecoder::decode_json("secret_key", key, obj, true); if (!JSONDecoder::decode_json("subuser", subuser, obj)) { string user; JSONDecoder::decode_json("user", user, obj); int pos = user.find(':'); if (pos >= 0) { subuser = user.substr(pos + 1); } } } void RGWAccessKey::decode_json(JSONObj *obj, bool swift) { if (!swift) { decode_json(obj); return; } if (!JSONDecoder::decode_json("subuser", subuser, obj)) { JSONDecoder::decode_json("user", id, obj, true); int pos = id.find(':'); if (pos >= 0) { subuser = id.substr(pos + 1); } } JSONDecoder::decode_json("secret_key", key, obj, true); } struct rgw_flags_desc { uint32_t mask; const char *str; }; static struct rgw_flags_desc rgw_perms[] = { { RGW_PERM_FULL_CONTROL, "full-control" }, { RGW_PERM_READ | RGW_PERM_WRITE, "read-write" }, { RGW_PERM_READ, "read" }, { RGW_PERM_WRITE, "write" }, { RGW_PERM_READ_ACP, "read-acp" }, { RGW_PERM_WRITE_ACP, "read-acp" }, { 0, NULL } }; static void mask_to_str(rgw_flags_desc *mask_list, uint32_t mask, char *buf, int len) { const char *sep = ""; int pos = 0; if (!mask) { snprintf(buf, len, ""); return; } while (mask) { uint32_t orig_mask = mask; for (int i = 0; mask_list[i].mask; i++) { struct rgw_flags_desc *desc = &mask_list[i]; if ((mask & desc->mask) == desc->mask) { pos += snprintf(buf + pos, len - pos, "%s%s", sep, desc->str); if (pos == len) return; sep = ", "; mask &= ~desc->mask; if (!mask) return; } } if (mask == orig_mask) // no change break; } } static void perm_to_str(uint32_t mask, char *buf, int len) { return mask_to_str(rgw_perms, mask, buf, len); } static struct rgw_flags_desc op_type_flags[] = { { RGW_OP_TYPE_READ, "read" }, { RGW_OP_TYPE_WRITE, "write" }, { RGW_OP_TYPE_DELETE, "delete" }, { 0, NULL } }; static void op_type_to_str(uint32_t mask, char *buf, int len) { return mask_to_str(op_type_flags, mask, buf, len); } void RGWSubUser::dump(Formatter *f) const { encode_json("id", name, f); char buf[256]; perm_to_str(perm_mask, buf, sizeof(buf)); encode_json("permissions", (const char *)buf, f); } void RGWSubUser::dump(Formatter *f, const string& user) const { string s = user; s.append(":"); s.append(name); encode_json("id", s, f); char buf[256]; perm_to_str(perm_mask, buf, sizeof(buf)); encode_json("permissions", (const char *)buf, f); } static uint32_t str_to_perm(const string& s) { if (s.compare("read") == 0) return RGW_PERM_READ; else if (s.compare("write") == 0) return RGW_PERM_WRITE; else if (s.compare("read-write") == 0) return RGW_PERM_READ | RGW_PERM_WRITE; else if (s.compare("full-control") == 0) return RGW_PERM_FULL_CONTROL; return 0; } void RGWSubUser::decode_json(JSONObj *obj) { string uid; JSONDecoder::decode_json("id", uid, obj); int pos = uid.find(':'); if (pos >= 0) name = uid.substr(pos + 1); string perm_str; JSONDecoder::decode_json("permissions", perm_str, obj); perm_mask = str_to_perm(perm_str); } static void user_info_dump_subuser(const char *name, const RGWSubUser& subuser, Formatter *f, void *parent) { RGWUserInfo *info = static_cast(parent); subuser.dump(f, info->user_id); } static void user_info_dump_key(const char *name, const RGWAccessKey& key, Formatter *f, void *parent) { RGWUserInfo *info = static_cast(parent); key.dump(f, info->user_id, false); } static void user_info_dump_swift_key(const char *name, const RGWAccessKey& key, Formatter *f, void *parent) { RGWUserInfo *info = static_cast(parent); key.dump(f, info->user_id, true); } void RGWUserInfo::dump(Formatter *f) const { encode_json("user_id", user_id, f); encode_json("display_name", display_name, f); encode_json("email", user_email, f); encode_json("suspended", (int)suspended, f); encode_json("max_buckets", (int)max_buckets, f); encode_json("auid", auid, f); encode_json_map("subusers", NULL, "subuser", NULL, user_info_dump_subuser,(void *)this, subusers, f); encode_json_map("keys", NULL, "key", NULL, user_info_dump_key,(void *)this, access_keys, f); encode_json_map("swift_keys", NULL, "key", NULL, user_info_dump_swift_key,(void *)this, swift_keys, f); encode_json("caps", caps, f); char buf[256]; op_type_to_str(op_mask, buf, sizeof(buf)); encode_json("op_mask", (const char *)buf, f); if (system) { /* no need to show it for every user */ encode_json("system", (bool)system, f); } encode_json("default_placement", default_placement, f); encode_json("placement_tags", placement_tags, f); encode_json("bucket_quota", bucket_quota, f); encode_json("user_quota", user_quota, f); encode_json("temp_url_keys", temp_url_keys, f); } static void decode_access_keys(map& m, JSONObj *o) { RGWAccessKey k; k.decode_json(o); m[k.id] = k; } static void decode_swift_keys(map& m, JSONObj *o) { RGWAccessKey k; k.decode_json(o, true); m[k.id] = k; } static void decode_subusers(map& m, JSONObj *o) { RGWSubUser u; u.decode_json(o); m[u.name] = u; } void RGWUserInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("user_id", user_id, obj, true); JSONDecoder::decode_json("display_name", display_name, obj); JSONDecoder::decode_json("email", user_email, obj); bool susp = false; JSONDecoder::decode_json("suspended", susp, obj); suspended = (__u8)susp; JSONDecoder::decode_json("max_buckets", max_buckets, obj); JSONDecoder::decode_json("auid", auid, obj); JSONDecoder::decode_json("keys", access_keys, decode_access_keys, obj); JSONDecoder::decode_json("swift_keys", swift_keys, decode_swift_keys, obj); JSONDecoder::decode_json("subusers", subusers, decode_subusers, obj); JSONDecoder::decode_json("caps", caps, obj); string mask_str; JSONDecoder::decode_json("op_mask", mask_str, obj); rgw_parse_op_type_list(mask_str, &op_mask); bool sys = false; JSONDecoder::decode_json("system", sys, obj); system = (__u8)sys; JSONDecoder::decode_json("default_placement", default_placement, obj); JSONDecoder::decode_json("placement_tags", placement_tags, obj); JSONDecoder::decode_json("bucket_quota", bucket_quota, obj); JSONDecoder::decode_json("user_quota", user_quota, obj); JSONDecoder::decode_json("temp_url_keys", temp_url_keys, obj); } void RGWQuotaInfo::dump(Formatter *f) const { f->dump_bool("enabled", enabled); f->dump_int("max_size_kb", max_size_kb); f->dump_int("max_objects", max_objects); } void RGWQuotaInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("max_size_kb", max_size_kb, obj); JSONDecoder::decode_json("max_objects", max_objects, obj); JSONDecoder::decode_json("enabled", enabled, obj); } void rgw_bucket::dump(Formatter *f) const { encode_json("name", name, f); encode_json("pool", data_pool, f); encode_json("data_extra_pool", data_extra_pool, f); encode_json("index_pool", index_pool, f); encode_json("marker", marker, f); encode_json("bucket_id", bucket_id, f); } void rgw_bucket::decode_json(JSONObj *obj) { JSONDecoder::decode_json("name", name, obj); JSONDecoder::decode_json("pool", data_pool, obj); JSONDecoder::decode_json("data_extra_pool", data_extra_pool, obj); JSONDecoder::decode_json("index_pool", index_pool, obj); JSONDecoder::decode_json("marker", marker, obj); JSONDecoder::decode_json("bucket_id", bucket_id, obj); } void RGWBucketEntryPoint::dump(Formatter *f) const { encode_json("bucket", bucket, f); encode_json("owner", owner, f); encode_json("creation_time", creation_time, f); encode_json("linked", linked, f); encode_json("has_bucket_info", has_bucket_info, f); if (has_bucket_info) { encode_json("old_bucket_info", old_bucket_info, f); } } void RGWBucketEntryPoint::decode_json(JSONObj *obj) { JSONDecoder::decode_json("bucket", bucket, obj); JSONDecoder::decode_json("owner", owner, obj); JSONDecoder::decode_json("creation_time", creation_time, obj); JSONDecoder::decode_json("linked", linked, obj); JSONDecoder::decode_json("has_bucket_info", has_bucket_info, obj); if (has_bucket_info) { JSONDecoder::decode_json("old_bucket_info", old_bucket_info, obj); } } void RGWBucketInfo::dump(Formatter *f) const { encode_json("bucket", bucket, f); encode_json("creation_time", creation_time, f); encode_json("owner", owner, f); encode_json("flags", flags, f); encode_json("region", region, f); encode_json("placement_rule", placement_rule, f); encode_json("has_instance_obj", has_instance_obj, f); encode_json("quota", quota, f); } void RGWBucketInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("bucket", bucket, obj); JSONDecoder::decode_json("creation_time", creation_time, obj); JSONDecoder::decode_json("owner", owner, obj); JSONDecoder::decode_json("flags", flags, obj); JSONDecoder::decode_json("region", region, obj); JSONDecoder::decode_json("placement_rule", placement_rule, obj); JSONDecoder::decode_json("has_instance_obj", has_instance_obj, obj); JSONDecoder::decode_json("quota", quota, obj); } void RGWObjEnt::dump(Formatter *f) const { encode_json("name", name, f); encode_json("namespace", ns, f); encode_json("owner", owner, f); encode_json("owner_display_name", owner_display_name, f); encode_json("size", size, f); encode_json("mtime", mtime, f); encode_json("etag", etag, f); encode_json("content_type", content_type, f); encode_json("tag", tag, f); } void RGWBucketEnt::dump(Formatter *f) const { encode_json("bucket", bucket, f); encode_json("size", size, f); encode_json("size_rounded", size_rounded, f); encode_json("mtime", creation_time, f); /* mtime / creation time discrepency needed for backward compatibility */ encode_json("count", count, f); } void RGWUploadPartInfo::dump(Formatter *f) const { encode_json("num", num, f); encode_json("size", size, f); encode_json("etag", etag, f); encode_json("modified", modified, f); } void rgw_obj::dump(Formatter *f) const { encode_json("bucket", bucket, f); encode_json("key", key, f); encode_json("ns", ns, f); encode_json("object", object, f); } void RGWZoneParams::dump(Formatter *f) const { encode_json("domain_root", domain_root.data_pool, f); encode_json("control_pool", control_pool.data_pool, f); encode_json("gc_pool", gc_pool.data_pool, f); encode_json("log_pool", log_pool.data_pool, f); encode_json("intent_log_pool", intent_log_pool.data_pool, f); encode_json("usage_log_pool", usage_log_pool.data_pool, f); encode_json("user_keys_pool", user_keys_pool.data_pool, f); encode_json("user_email_pool", user_email_pool.data_pool, f); encode_json("user_swift_pool", user_swift_pool.data_pool, f); encode_json("user_uid_pool", user_uid_pool.data_pool, f); encode_json_plain("system_key", system_key, f); encode_json("placement_pools", placement_pools, f); } static void decode_json(const char *field, rgw_bucket& bucket, JSONObj *obj) { string pool; JSONDecoder::decode_json(field, pool, obj); if (pool[0] != '.') { pool = string(".") + pool; } bucket = rgw_bucket(pool.c_str()); } void RGWZonePlacementInfo::dump(Formatter *f) const { encode_json("index_pool", index_pool, f); encode_json("data_pool", data_pool, f); encode_json("data_extra_pool", data_extra_pool, f); } void RGWZonePlacementInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("index_pool", index_pool, obj); JSONDecoder::decode_json("data_pool", data_pool, obj); JSONDecoder::decode_json("data_extra_pool", data_extra_pool, obj); } void RGWZoneParams::decode_json(JSONObj *obj) { ::decode_json("domain_root", domain_root, obj); ::decode_json("control_pool", control_pool, obj); ::decode_json("gc_pool", gc_pool, obj); ::decode_json("log_pool", log_pool, obj); ::decode_json("intent_log_pool", intent_log_pool, obj); ::decode_json("usage_log_pool", usage_log_pool, obj); ::decode_json("user_keys_pool", user_keys_pool, obj); ::decode_json("user_email_pool", user_email_pool, obj); ::decode_json("user_uid_pool", user_uid_pool, obj); ::decode_json("user_swift_pool", user_swift_pool, obj); JSONDecoder::decode_json("system_key", system_key, obj); JSONDecoder::decode_json("placement_pools", placement_pools, obj); } void RGWZone::dump(Formatter *f) const { encode_json("name", name, f); encode_json("endpoints", endpoints, f); encode_json("log_meta", log_meta, f); encode_json("log_data", log_data, f); } void RGWZone::decode_json(JSONObj *obj) { JSONDecoder::decode_json("name", name, obj); JSONDecoder::decode_json("endpoints", endpoints, obj); JSONDecoder::decode_json("log_meta", log_meta, obj); JSONDecoder::decode_json("log_data", log_data, obj); } void RGWRegionPlacementTarget::dump(Formatter *f) const { encode_json("name", name, f); encode_json("tags", tags, f); } void RGWRegionPlacementTarget::decode_json(JSONObj *obj) { JSONDecoder::decode_json("name", name, obj); JSONDecoder::decode_json("tags", tags, obj); } void RGWRegion::dump(Formatter *f) const { encode_json("name", name, f); encode_json("api_name", api_name, f); encode_json("is_master", is_master, f); encode_json("endpoints", endpoints, f); encode_json("master_zone", master_zone, f); encode_json_map("zones", zones, f); /* more friendly representation */ encode_json_map("placement_targets", placement_targets, f); /* more friendly representation */ encode_json("default_placement", default_placement, f); } static void decode_zones(map& zones, JSONObj *o) { RGWZone z; z.decode_json(o); zones[z.name] = z; } static void decode_placement_targets(map& targets, JSONObj *o) { RGWRegionPlacementTarget t; t.decode_json(o); targets[t.name] = t; } void RGWRegion::decode_json(JSONObj *obj) { JSONDecoder::decode_json("name", name, obj); JSONDecoder::decode_json("api_name", api_name, obj); JSONDecoder::decode_json("is_master", is_master, obj); JSONDecoder::decode_json("endpoints", endpoints, obj); JSONDecoder::decode_json("master_zone", master_zone, obj); JSONDecoder::decode_json("zones", zones, decode_zones, obj); JSONDecoder::decode_json("placement_targets", placement_targets, decode_placement_targets, obj); JSONDecoder::decode_json("default_placement", default_placement, obj); } void RGWRegionMap::dump(Formatter *f) const { encode_json("regions", regions, f); encode_json("master_region", master_region, f); encode_json("bucket_quota", bucket_quota, f); encode_json("user_quota", user_quota, f); } void RGWRegionMap::decode_json(JSONObj *obj) { JSONDecoder::decode_json("regions", regions, obj); JSONDecoder::decode_json("master_region", master_region, obj); JSONDecoder::decode_json("user_quota", user_quota, obj); } void RGWMetadataLogInfo::dump(Formatter *f) const { encode_json("marker", marker, f); encode_json("last_update", last_update, f); } void RGWMetadataLogInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("marker", marker, obj); JSONDecoder::decode_json("last_update", last_update, obj); } void RGWDataChangesLogInfo::dump(Formatter *f) const { encode_json("marker", marker, f); encode_json("last_update", last_update, f); } void RGWDataChangesLogInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("marker", marker, obj); JSONDecoder::decode_json("last_update", last_update, obj); } void KeystoneToken::Metadata::decode_json(JSONObj *obj) { JSONDecoder::decode_json("is_admin", is_admin, obj); } void KeystoneToken::Service::Endpoint::decode_json(JSONObj *obj) { JSONDecoder::decode_json("id", id, obj); JSONDecoder::decode_json("adminURL", admin_url, obj); JSONDecoder::decode_json("publicURL", public_url, obj); JSONDecoder::decode_json("internalURL", internal_url, obj); JSONDecoder::decode_json("region", region, obj); } void KeystoneToken::Service::decode_json(JSONObj *obj) { JSONDecoder::decode_json("type", type, obj, true); JSONDecoder::decode_json("name", name, obj, true); JSONDecoder::decode_json("endpoints", endpoints, obj); } void KeystoneToken::Token::Tenant::decode_json(JSONObj *obj) { JSONDecoder::decode_json("id", id, obj, true); JSONDecoder::decode_json("name", name, obj, true); JSONDecoder::decode_json("description", description, obj); JSONDecoder::decode_json("enabled", enabled, obj); } void KeystoneToken::Token::decode_json(JSONObj *obj) { string expires_iso8601; struct tm t; JSONDecoder::decode_json("id", id, obj, true); JSONDecoder::decode_json("tenant", tenant, obj, true); JSONDecoder::decode_json("expires", expires_iso8601, obj, true); if (parse_iso8601(expires_iso8601.c_str(), &t)) { expires = timegm(&t); } else { expires = 0; throw JSONDecoder::err("Failed to parse ISO8601 expiration date from Keystone response."); } } void KeystoneToken::User::Role::decode_json(JSONObj *obj) { JSONDecoder::decode_json("id", id, obj); JSONDecoder::decode_json("name", name, obj); } void KeystoneToken::User::decode_json(JSONObj *obj) { JSONDecoder::decode_json("id", id, obj, true); JSONDecoder::decode_json("name", name, obj); JSONDecoder::decode_json("username", user_name, obj, true); JSONDecoder::decode_json("roles", roles, obj); } void KeystoneToken::decode_json(JSONObj *access_obj) { JSONDecoder::decode_json("metadata", metadata, access_obj); JSONDecoder::decode_json("token", token, access_obj, true); JSONDecoder::decode_json("user", user, access_obj, true); JSONDecoder::decode_json("serviceCatalog", service_catalog, access_obj); } ceph-0.80.11/src/rgw/rgw_tools.h0000664000175100017510000000140712623076744020455 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_TOOLS_H #define CEPH_RGW_TOOLS_H #include #include "include/types.h" #include "rgw_common.h" class RGWRados; struct RGWObjVersionTracker; struct obj_version; int rgw_put_system_obj(RGWRados *rgwstore, rgw_bucket& bucket, string& oid, const char *data, size_t size, bool exclusive, RGWObjVersionTracker *objv_tracker, time_t set_mtime, map *pattrs = NULL); int rgw_get_system_obj(RGWRados *rgwstore, void *ctx, rgw_bucket& bucket, const string& key, bufferlist& bl, RGWObjVersionTracker *objv_tracker, time_t *pmtime, map *pattrs = NULL); int rgw_tools_init(CephContext *cct); void rgw_tools_cleanup(); const char *rgw_find_mime_by_ext(string& ext); #endif ceph-0.80.11/src/rgw/rgw_replica_log.cc0000664000175100017510000000673112623076744021740 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * Copyright 2013 Inktank */ #include "common/ceph_json.h" #include "rgw_replica_log.h" #include "cls/replica_log/cls_replica_log_client.h" #include "rgw_rados.h" void RGWReplicaBounds::dump(Formatter *f) const { encode_json("marker", marker, f); encode_json("oldest_time", oldest_time, f); encode_json("markers", markers, f); } void RGWReplicaBounds::decode_json(JSONObj *obj) { JSONDecoder::decode_json("marker", marker, obj); JSONDecoder::decode_json("oldest_time", oldest_time, obj); JSONDecoder::decode_json("markers", markers, obj); } RGWReplicaLogger::RGWReplicaLogger(RGWRados *_store) : cct(_store->cct), store(_store) {} int RGWReplicaLogger::open_ioctx(librados::IoCtx& ctx, const string& pool) { int r = store->rados->ioctx_create(pool.c_str(), ctx); if (r == -ENOENT) { rgw_bucket p(pool.c_str()); r = store->create_pool(p); if (r < 0) return r; // retry r = store->rados->ioctx_create(pool.c_str(), ctx); } if (r < 0) { lderr(cct) << "ERROR: could not open rados pool " << pool << dendl; } return r; } int RGWReplicaLogger::update_bound(const string& oid, const string& pool, const string& daemon_id, const string& marker, const utime_t& time, const list *entries) { cls_replica_log_progress_marker progress; progress.entity_id = daemon_id; progress.position_marker = marker; progress.position_time = time; progress.items = *entries; librados::IoCtx ioctx; int r = open_ioctx(ioctx, pool); if (r < 0) { return r; } librados::ObjectWriteOperation opw; cls_replica_log_update_bound(opw, progress); return ioctx.operate(oid, &opw); } int RGWReplicaLogger::delete_bound(const string& oid, const string& pool, const string& daemon_id) { librados::IoCtx ioctx; int r = open_ioctx(ioctx, pool); if (r < 0) { return r; } librados::ObjectWriteOperation opw; cls_replica_log_delete_bound(opw, daemon_id); return ioctx.operate(oid, &opw); } int RGWReplicaLogger::get_bounds(const string& oid, const string& pool, RGWReplicaBounds& bounds) { librados::IoCtx ioctx; int r = open_ioctx(ioctx, pool); if (r < 0) { return r; } return cls_replica_log_get_bounds(ioctx, oid, bounds.marker, bounds.oldest_time, bounds.markers); } RGWReplicaObjectLogger:: RGWReplicaObjectLogger(RGWRados *_store, const string& _pool, const string& _prefix) : RGWReplicaLogger(_store), pool(_pool), prefix(_prefix) { if (pool.empty()) store->get_log_pool_name(pool); } int RGWReplicaObjectLogger::create_log_objects(int shards) { librados::IoCtx ioctx; int r = open_ioctx(ioctx, pool); if (r < 0) { return r; } for (int i = 0; i < shards; ++i) { string oid; get_shard_oid(i, oid); r = ioctx.create(oid, false); if (r < 0) return r; } return r; } RGWReplicaBucketLogger::RGWReplicaBucketLogger(RGWRados *_store) : RGWReplicaLogger(_store) { store->get_log_pool_name(pool); prefix = _store->ctx()->_conf->rgw_replica_log_obj_prefix; prefix.append("."); } ceph-0.80.11/src/rgw/rgw_xml.h0000664000175100017510000000355712623076744020125 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_XML_H #define CEPH_RGW_XML_H #include #include #include #include #include using namespace std; class XMLObj; class XMLObjIter { typedef map::iterator map_iter_t; map_iter_t cur; map_iter_t end; public: XMLObjIter(); ~XMLObjIter(); void set(const XMLObjIter::map_iter_t &_cur, const XMLObjIter::map_iter_t &_end); XMLObj *get_next(); }; /** * Represents a block of XML. * Give the class an XML blob, and it will parse the blob into * an attr_name->value map. * This really ought to be an abstract class or something; it * shouldn't be the startpoint for any parsing. Look at RGWXMLParser for that. */ class XMLObj { XMLObj *parent; string obj_type; protected: string data; multimap children; map attr_map; public: XMLObj() : parent(NULL) {} virtual ~XMLObj(); bool xml_start(XMLObj *parent, const char *el, const char **attr); virtual bool xml_end(const char *el); virtual void xml_handle_data(const char *s, int len); string& get_data(); XMLObj *get_parent(); void add_child(string el, XMLObj *obj); bool get_attr(string name, string& attr); XMLObjIter find(string name); XMLObj *find_first(string name); friend ostream& operator<<(ostream& out, XMLObj& obj); }; class RGWXMLParser : public XMLObj { XML_Parser p; char *buf; int buf_len; XMLObj *cur_obj; vector objs; protected: virtual XMLObj *alloc_obj(const char *el) = 0; public: RGWXMLParser(); virtual ~RGWXMLParser(); bool init(); bool xml_start(const char *el, const char **attr); bool xml_end(const char *el); void handle_data(const char *s, int len); bool parse(const char *buf, int len, int done); const char *get_xml() { return buf; } void set_failure() { success = false; } private: bool success; }; #endif ceph-0.80.11/src/rgw/rgw_common.cc0000664000175100017510000005660512623076744020755 0ustar jenkins-buildjenkins-build#include #include "json_spirit/json_spirit.h" #include "common/ceph_json.h" #include "rgw_common.h" #include "rgw_acl.h" #include "rgw_string.h" #include "common/ceph_crypto.h" #include "common/armor.h" #include "common/errno.h" #include "common/Clock.h" #include "common/Formatter.h" #include "common/perf_counters.h" #include "common/strtol.h" #include "include/str_list.h" #include "auth/Crypto.h" #include #define dout_subsys ceph_subsys_rgw PerfCounters *perfcounter = NULL; int rgw_perf_start(CephContext *cct) { PerfCountersBuilder plb(cct, cct->_conf->name.to_str(), l_rgw_first, l_rgw_last); plb.add_u64_counter(l_rgw_req, "req"); plb.add_u64_counter(l_rgw_failed_req, "failed_req"); plb.add_u64_counter(l_rgw_get, "get"); plb.add_u64_counter(l_rgw_get_b, "get_b"); plb.add_time_avg(l_rgw_get_lat, "get_initial_lat"); plb.add_u64_counter(l_rgw_put, "put"); plb.add_u64_counter(l_rgw_put_b, "put_b"); plb.add_time_avg(l_rgw_put_lat, "put_initial_lat"); plb.add_u64(l_rgw_qlen, "qlen"); plb.add_u64(l_rgw_qactive, "qactive"); plb.add_u64_counter(l_rgw_cache_hit, "cache_hit"); plb.add_u64_counter(l_rgw_cache_miss, "cache_miss"); plb.add_u64_counter(l_rgw_keystone_token_cache_hit, "keystone_token_cache_hit"); plb.add_u64_counter(l_rgw_keystone_token_cache_miss, "keystone_token_cache_miss"); perfcounter = plb.create_perf_counters(); cct->get_perfcounters_collection()->add(perfcounter); return 0; } void rgw_perf_stop(CephContext *cct) { assert(perfcounter); cct->get_perfcounters_collection()->remove(perfcounter); delete perfcounter; } using namespace ceph::crypto; rgw_err:: rgw_err() { clear(); } rgw_err:: rgw_err(int http, const std::string& s3) : http_ret(http), ret(0), s3_code(s3) { } void rgw_err:: clear() { http_ret = 200; ret = 0; s3_code.clear(); } bool rgw_err:: is_clear() const { return (http_ret == 200); } bool rgw_err:: is_err() const { return !(http_ret >= 200 && http_ret <= 399); } req_info::req_info(CephContext *cct, class RGWEnv *e) : env(e) { method = env->get("REQUEST_METHOD"); script_uri = env->get("SCRIPT_URI", cct->_conf->rgw_script_uri.c_str()); request_uri = env->get("REQUEST_URI", cct->_conf->rgw_request_uri.c_str()); int pos = request_uri.find('?'); if (pos >= 0) { request_params = request_uri.substr(pos + 1); request_uri = request_uri.substr(0, pos); } else { request_params = env->get("QUERY_STRING", ""); } host = env->get("HTTP_HOST"); } void req_info::rebuild_from(req_info& src) { method = src.method; script_uri = src.script_uri; if (src.effective_uri.empty()) { request_uri = src.request_uri; } else { request_uri = src.effective_uri; } effective_uri.clear(); host = src.host; x_meta_map = src.x_meta_map; x_meta_map.erase("x-amz-date"); } req_state::req_state(CephContext *_cct, class RGWEnv *e) : cct(_cct), cio(NULL), op(OP_UNKNOWN), has_acl_header(false), os_auth_token(NULL), info(_cct, e) { enable_ops_log = e->conf->enable_ops_log; enable_usage_log = e->conf->enable_usage_log; defer_to_bucket_acls = e->conf->defer_to_bucket_acls; content_started = false; format = 0; formatter = NULL; bucket_acl = NULL; object_acl = NULL; expect_cont = false; object = NULL; header_ended = false; obj_size = 0; prot_flags = 0; system_request = false; os_auth_token = NULL; time = ceph_clock_now(cct); perm_mask = 0; content_length = 0; object = NULL; bucket_exists = false; has_bad_meta = false; length = NULL; copy_source = NULL; http_auth = NULL; local_source = false; obj_ctx = NULL; } req_state::~req_state() { delete formatter; delete bucket_acl; delete object_acl; free((void *)object); } struct str_len { const char *str; int len; }; #define STR_LEN_ENTRY(s) { s, sizeof(s) - 1 } struct str_len meta_prefixes[] = { STR_LEN_ENTRY("HTTP_X_AMZ"), STR_LEN_ENTRY("HTTP_X_GOOG"), STR_LEN_ENTRY("HTTP_X_DHO"), STR_LEN_ENTRY("HTTP_X_RGW"), STR_LEN_ENTRY("HTTP_X_OBJECT"), STR_LEN_ENTRY("HTTP_X_CONTAINER"), {NULL, 0} }; void req_info::init_meta_info(bool *found_bad_meta) { x_meta_map.clear(); map& m = env->get_map(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { const char *prefix; const string& header_name = iter->first; const string& val = iter->second; for (int prefix_num = 0; (prefix = meta_prefixes[prefix_num].str) != NULL; prefix_num++) { int len = meta_prefixes[prefix_num].len; const char *p = header_name.c_str(); if (strncmp(p, prefix, len) == 0) { dout(10) << "meta>> " << p << dendl; const char *name = p+len; /* skip the prefix */ int name_len = header_name.size() - len; if (found_bad_meta && strncmp(name, "_META_", name_len) == 0) *found_bad_meta = true; char name_low[meta_prefixes[0].len + name_len + 1]; snprintf(name_low, meta_prefixes[0].len - 5 + name_len + 1, "%s%s", meta_prefixes[0].str + 5 /* skip HTTP_ */, name); // normalize meta prefix int j; for (j = 0; name_low[j]; j++) { if (name_low[j] != '_') name_low[j] = tolower(name_low[j]); else name_low[j] = '-'; } name_low[j] = 0; map::iterator iter; iter = x_meta_map.find(name_low); if (iter != x_meta_map.end()) { string old = iter->second; int pos = old.find_last_not_of(" \t"); /* get rid of any whitespaces after the value */ old = old.substr(0, pos + 1); old.append(","); old.append(val); x_meta_map[name_low] = old; } else { x_meta_map[name_low] = val; } } } } for (iter = x_meta_map.begin(); iter != x_meta_map.end(); ++iter) { dout(10) << "x>> " << iter->first << ":" << iter->second << dendl; } } std::ostream& operator<<(std::ostream& oss, const rgw_err &err) { oss << "rgw_err(http_ret=" << err.http_ret << ", s3='" << err.s3_code << "') "; return oss; } string rgw_string_unquote(const string& s) { if (s[0] != '"' || s.size() < 2) return s; int len; for (len = s.size(); len > 2; --len) { if (s[len - 1] != ' ') break; } if (s[len-1] != '"') return s; return s.substr(1, len - 2); } static void trim_whitespace(const string& src, string& dst) { const char *spacestr = " \t\n\r\f\v"; int start = src.find_first_not_of(spacestr); if (start < 0) return; int end = src.find_last_not_of(spacestr); dst = src.substr(start, end - start + 1); } static bool check_str_end(const char *s) { if (!s) return false; while (*s) { if (!isspace(*s)) return false; s++; } return true; } static bool check_gmt_end(const char *s) { if (!s || !*s) return false; while (isspace(*s)) { ++s; } /* check for correct timezone */ if ((strncmp(s, "GMT", 3) != 0) && (strncmp(s, "UTC", 3) != 0)) { return false; } return true; } static bool parse_rfc850(const char *s, struct tm *t) { memset(t, 0, sizeof(*t)); return check_gmt_end(strptime(s, "%A, %d-%b-%y %H:%M:%S ", t)); } static bool parse_asctime(const char *s, struct tm *t) { memset(t, 0, sizeof(*t)); return check_str_end(strptime(s, "%a %b %d %H:%M:%S %Y", t)); } static bool parse_rfc1123(const char *s, struct tm *t) { memset(t, 0, sizeof(*t)); return check_gmt_end(strptime(s, "%a, %d %b %Y %H:%M:%S ", t)); } static bool parse_rfc1123_alt(const char *s, struct tm *t) { memset(t, 0, sizeof(*t)); return check_str_end(strptime(s, "%a, %d %b %Y %H:%M:%S %z", t)); } bool parse_rfc2616(const char *s, struct tm *t) { return parse_rfc850(s, t) || parse_asctime(s, t) || parse_rfc1123(s, t) || parse_rfc1123_alt(s,t); } bool parse_iso8601(const char *s, struct tm *t) { memset(t, 0, sizeof(*t)); const char *p = strptime(s, "%Y-%m-%dT%T", t); if (!p) { dout(0) << "parse_iso8601 failed" << dendl; return false; } string str; trim_whitespace(p, str); if (str.size() == 1 && str[0] == 'Z') return true; if (str.size() != 5) { return false; } if (str[0] != '.' || str[str.size() - 1] != 'Z') return false; uint32_t ms; int r = stringtoul(str.substr(1, 3), &ms); if (r < 0) return false; return true; } int parse_key_value(string& in_str, const char *delim, string& key, string& val) { if (delim == NULL) return -EINVAL; int pos = in_str.find(delim); if (pos < 0) return -EINVAL; trim_whitespace(in_str.substr(0, pos), key); pos++; trim_whitespace(in_str.substr(pos), val); return 0; } int parse_key_value(string& in_str, string& key, string& val) { return parse_key_value(in_str, "=", key,val); } int parse_time(const char *time_str, time_t *time) { struct tm tm; if (!parse_rfc2616(time_str, &tm)) return -EINVAL; *time = timegm(&tm); return 0; } /* * calculate the sha1 value of a given msg and key */ void calc_hmac_sha1(const char *key, int key_len, const char *msg, int msg_len, char *dest) /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */ { HMACSHA1 hmac((const unsigned char *)key, key_len); hmac.Update((const unsigned char *)msg, msg_len); hmac.Final((unsigned char *)dest); char hex_str[(CEPH_CRYPTO_HMACSHA1_DIGESTSIZE * 2) + 1]; buf_to_hex((unsigned char *)dest, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE, hex_str); } int gen_rand_base64(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */ { char buf[size]; char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */ int ret; ret = get_random_bytes(buf, sizeof(buf)); if (ret < 0) { lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl; return -1; } ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)], (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4); if (ret < 0) { lderr(cct) << "ceph_armor failed" << dendl; return -1; } tmp_dest[ret] = '\0'; memcpy(dest, tmp_dest, size); dest[size] = '\0'; return 0; } static const char alphanum_upper_table[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int gen_rand_alphanumeric_upper(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */ { int ret = get_random_bytes(dest, size); if (ret < 0) { lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl; return -1; } int i; for (i=0; i= 0) { string& name = nv.get_name(); string& val = nv.get_val(); if (name.compare(0, sizeof(RGW_SYS_PARAM_PREFIX) - 1, RGW_SYS_PARAM_PREFIX) == 0) { sys_val_map[name] = val; } else { val_map[name] = val; } if ((name.compare("acl") == 0) || (name.compare("cors") == 0) || (name.compare("location") == 0) || (name.compare("logging") == 0) || (name.compare("delete") == 0) || (name.compare("uploads") == 0) || (name.compare("partNumber") == 0) || (name.compare("uploadId") == 0) || (name.compare("versionId") == 0) || (name.compare("torrent") == 0)) { sub_resources[name] = val; } else if (name[0] == 'r') { // root of all evil if ((name.compare("response-content-type") == 0) || (name.compare("response-content-language") == 0) || (name.compare("response-expires") == 0) || (name.compare("response-cache-control") == 0) || (name.compare("response-content-disposition") == 0) || (name.compare("response-content-encoding") == 0)) { sub_resources[name] = val; has_resp_modifier = true; } } else if ((name.compare("subuser") == 0) || (name.compare("key") == 0) || (name.compare("caps") == 0) || (name.compare("index") == 0) || (name.compare("policy") == 0) || (name.compare("quota") == 0) || (name.compare("object") == 0)) { if (!admin_subresource_added) { sub_resources[name] = ""; admin_subresource_added = true; } } } pos = fpos + 1; } return 0; } string& XMLArgs::get(const string& name, bool *exists) { map::iterator iter; iter = val_map.find(name); bool e = (iter != val_map.end()); if (exists) *exists = e; if (e) return iter->second; return empty_str; } string& XMLArgs::get(const char *name, bool *exists) { string s(name); return get(s, exists); } int XMLArgs::get_bool(const string& name, bool *val, bool *exists) { map::iterator iter; iter = val_map.find(name); bool e = (iter != val_map.end()); if (exists) *exists = e; if (e) { const char *s = iter->second.c_str(); if (strcasecmp(s, "false") == 0) { *val = false; } else if (strcasecmp(s, "true") == 0) { *val = true; } else { return -EINVAL; } } return 0; } int XMLArgs::get_bool(const char *name, bool *val, bool *exists) { string s(name); return get_bool(s, val, exists); } bool verify_bucket_permission(struct req_state *s, int perm) { if (!s->bucket_acl) return false; if ((perm & (int)s->perm_mask) != perm) return false; return s->bucket_acl->verify_permission(s->user.user_id, perm, perm); } static inline bool check_deferred_bucket_acl(struct req_state *s, uint8_t deferred_check, int perm) { return (s->defer_to_bucket_acls == deferred_check && verify_bucket_permission(s, perm)); } bool verify_object_permission(struct req_state *s, RGWAccessControlPolicy *bucket_acl, RGWAccessControlPolicy *object_acl, int perm) { if (check_deferred_bucket_acl(s, RGW_DEFER_TO_BUCKET_ACLS_RECURSE, perm) || check_deferred_bucket_acl(s, RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, RGW_PERM_FULL_CONTROL)) { return true; } if (!object_acl) return false; bool ret = object_acl->verify_permission(s->user.user_id, s->perm_mask, perm); if (ret) return true; if (!s->cct->_conf->rgw_enforce_swift_acls) return ret; if ((perm & (int)s->perm_mask) != perm) return false; int swift_perm = 0; if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP)) swift_perm |= RGW_PERM_READ_OBJS; if (perm & RGW_PERM_WRITE) swift_perm |= RGW_PERM_WRITE_OBJS; if (!swift_perm) return false; /* we already verified the user mask above, so we pass swift_perm as the mask here, otherwise the mask might not cover the swift permissions bits */ return bucket_acl->verify_permission(s->user.user_id, swift_perm, swift_perm); } bool verify_object_permission(struct req_state *s, int perm) { return verify_object_permission(s, s->bucket_acl, s->object_acl, perm); } class HexTable { char table[256]; public: HexTable() { memset(table, -1, sizeof(table)); int i; for (i = '0'; i<='9'; i++) table[i] = i - '0'; for (i = 'A'; i<='F'; i++) table[i] = i - 'A' + 0xa; for (i = 'a'; i<='f'; i++) table[i] = i - 'a' + 0xa; } char to_num(char c) { return table[(int)c]; } }; static char hex_to_num(char c) { static HexTable hex_table; return hex_table.to_num(c); } bool url_decode(string& src_str, string& dest_str, bool in_query) { const char *src = src_str.c_str(); char dest[src_str.size() + 1]; int pos = 0; char c; while (*src) { if (*src != '%') { if (!in_query || *src != '+') { if (*src == '?') in_query = true; dest[pos++] = *src++; } else { dest[pos++] = ' '; ++src; } } else { src++; if (!*src) break; char c1 = hex_to_num(*src++); if (!*src) break; c = c1 << 4; if (c1 < 0) return false; c1 = hex_to_num(*src++); if (c1 < 0) return false; c |= c1; dest[pos++] = c; } } dest[pos] = 0; dest_str = dest; return true; } static void escape_char(char c, string& dst) { char buf[16]; snprintf(buf, sizeof(buf), "%%%.2X", (int)(unsigned char)c); dst.append(buf); } static bool char_needs_url_encoding(char c) { if (c <= 0x20 || c >= 0x7f) return true; switch (c) { case 0x22: case 0x23: case 0x25: case 0x26: case 0x2B: case 0x2C: case 0x2F: case 0x3A: case 0x3B: case 0x3C: case 0x3E: case 0x3D: case 0x3F: case 0x40: case 0x5B: case 0x5D: case 0x5C: case 0x5E: case 0x60: case 0x7B: case 0x7D: return true; } return false; } void url_encode(const string& src, string& dst) { const char *p = src.c_str(); for (unsigned i = 0; i < src.size(); i++, p++) { if (char_needs_url_encoding(*p)) { escape_char(*p, dst); continue; } dst.append(p, 1); } } string rgw_trim_whitespace(const string& src) { if (src.empty()) { return string(); } int start = 0; for (; start != (int)src.size(); start++) { if (!isspace(src[start])) break; } int end = src.size() - 1; if (end < start) { return string(); } for (; end > start; end--) { if (!isspace(src[end])) break; } return src.substr(start, end - start + 1); } string rgw_trim_quotes(const string& val) { string s = rgw_trim_whitespace(val); if (s.size() < 2) return s; int start = 0; int end = s.size() - 1; int quotes_count = 0; if (s[start] == '"') { start++; quotes_count++; } if (s[end] == '"') { end--; quotes_count++; } if (quotes_count == 2) { return s.substr(start, end - start + 1); } return s; } struct rgw_name_to_flag { const char *type_name; uint32_t flag; }; static int parse_list_of_flags(struct rgw_name_to_flag *mapping, const string& str, uint32_t *perm) { list strs; get_str_list(str, strs); list::iterator iter; uint32_t v = 0; for (iter = strs.begin(); iter != strs.end(); ++iter) { string& s = *iter; for (int i = 0; mapping[i].type_name; i++) { if (s.compare(mapping[i].type_name) == 0) v |= mapping[i].flag; } } *perm = v; return 0; } static struct rgw_name_to_flag cap_names[] = { {"*", RGW_CAP_ALL}, {"read", RGW_CAP_READ}, {"write", RGW_CAP_WRITE}, {NULL, 0} }; int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm) { return parse_list_of_flags(cap_names, str, perm); } int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm) { int pos = cap.find('='); if (pos >= 0) { trim_whitespace(cap.substr(0, pos), type); } if (type.size() == 0) return -EINVAL; string cap_perm; uint32_t perm = 0; if (pos < (int)cap.size() - 1) { cap_perm = cap.substr(pos + 1); int r = RGWUserCaps::parse_cap_perm(cap_perm, &perm); if (r < 0) return r; } *pperm = perm; return 0; } int RGWUserCaps::add_cap(const string& cap) { uint32_t perm; string type; int r = get_cap(cap, type, &perm); if (r < 0) return r; caps[type] |= perm; return 0; } int RGWUserCaps::remove_cap(const string& cap) { uint32_t perm; string type; int r = get_cap(cap, type, &perm); if (r < 0) return r; map::iterator iter = caps.find(type); if (iter == caps.end()) return 0; uint32_t& old_perm = iter->second; old_perm &= ~perm; if (!old_perm) caps.erase(iter); return 0; } int RGWUserCaps::add_from_string(const string& str) { int start = 0; do { int end = str.find(';', start); if (end < 0) end = str.size(); int r = add_cap(str.substr(start, end - start)); if (r < 0) return r; start = end + 1; } while (start < (int)str.size()); return 0; } int RGWUserCaps::remove_from_string(const string& str) { int start = 0; do { int end = str.find(';', start); if (end < 0) end = str.size(); int r = remove_cap(str.substr(start, end - start)); if (r < 0) return r; start = end + 1; } while (start < (int)str.size()); return 0; } void RGWUserCaps::dump(Formatter *f) const { dump(f, "caps"); } void RGWUserCaps::dump(Formatter *f, const char *name) const { f->open_array_section(name); map::const_iterator iter; for (iter = caps.begin(); iter != caps.end(); ++iter) { f->open_object_section("cap"); f->dump_string("type", iter->first); uint32_t perm = iter->second; string perm_str; for (int i=0; cap_names[i].type_name; i++) { if ((perm & cap_names[i].flag) == cap_names[i].flag) { if (perm_str.size()) perm_str.append(", "); perm_str.append(cap_names[i].type_name); perm &= ~cap_names[i].flag; } } if (perm_str.empty()) perm_str = ""; f->dump_string("perm", perm_str); f->close_section(); } f->close_section(); } struct RGWUserCap { string type; uint32_t perm; void decode_json(JSONObj *obj) { JSONDecoder::decode_json("type", type, obj); string perm_str; JSONDecoder::decode_json("perm", perm_str, obj); if (RGWUserCaps::parse_cap_perm(perm_str, &perm) < 0) { throw JSONDecoder::err("failed to parse permissions"); } } }; void RGWUserCaps::decode_json(JSONObj *obj) { list caps_list; decode_json_obj(caps_list, obj); list::iterator iter; for (iter = caps_list.begin(); iter != caps_list.end(); ++iter) { RGWUserCap& cap = *iter; caps[cap.type] = cap.perm; } } int RGWUserCaps::check_cap(const string& cap, uint32_t perm) { map::iterator iter = caps.find(cap); if ((iter == caps.end()) || (iter->second & perm) != perm) { return -EPERM; } return 0; } static struct rgw_name_to_flag op_type_mapping[] = { {"*", RGW_OP_TYPE_ALL}, {"read", RGW_OP_TYPE_READ}, {"write", RGW_OP_TYPE_WRITE}, {"delete", RGW_OP_TYPE_DELETE}, {NULL, 0} }; int rgw_parse_op_type_list(const string& str, uint32_t *perm) { return parse_list_of_flags(op_type_mapping, str, perm); } ceph-0.80.11/src/rgw/rgw_dencoder.cc0000664000175100017510000002654712623076744021252 0ustar jenkins-buildjenkins-build #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_log.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" #include "rgw_cache.h" #include "common/Formatter.h" static string shadow_ns = RGW_OBJ_NS_SHADOW; void RGWObjManifestPart::generate_test_instances(std::list& o) { o.push_back(new RGWObjManifestPart); RGWObjManifestPart *p = new RGWObjManifestPart; rgw_bucket b("bucket", ".pool", ".index_pool", "marker_", "12", "region"); p->loc = rgw_obj(b, "object"); p->loc_ofs = 512 * 1024; p->size = 128 * 1024; o.push_back(p); } void RGWObjManifest::obj_iterator::seek(uint64_t o) { ofs = o; if (manifest->explicit_objs) { explicit_iter = manifest->objs.upper_bound(ofs); if (explicit_iter != manifest->objs.begin()) { --explicit_iter; } if (ofs >= manifest->obj_size) { ofs = manifest->obj_size; return; } update_explicit_pos(); update_location(); return; } if (o < manifest->get_head_size()) { rule_iter = manifest->rules.begin(); stripe_ofs = 0; stripe_size = manifest->get_head_size(); if (rule_iter != manifest->rules.end()) { cur_part_id = rule_iter->second.start_part_num; cur_override_prefix = rule_iter->second.override_prefix; } update_location(); return; } rule_iter = manifest->rules.upper_bound(ofs); next_rule_iter = rule_iter; if (rule_iter != manifest->rules.begin()) { --rule_iter; } if (rule_iter == manifest->rules.end()) { update_location(); return; } RGWObjManifestRule& rule = rule_iter->second; if (rule.part_size > 0) { cur_part_id = rule.start_part_num + (ofs - rule.start_ofs) / rule.part_size; } else { cur_part_id = rule.start_part_num; } part_ofs = rule.start_ofs + (cur_part_id - rule.start_part_num) * rule.part_size; if (rule.stripe_max_size > 0) { cur_stripe = (ofs - part_ofs) / rule.stripe_max_size; stripe_ofs = part_ofs + cur_stripe * rule.stripe_max_size; if (!cur_part_id && manifest->get_head_size() > 0) { cur_stripe++; } } else { cur_stripe = 0; stripe_ofs = part_ofs; } if (!rule.part_size) { stripe_size = rule.stripe_max_size; stripe_size = MIN(manifest->get_obj_size() - stripe_ofs, stripe_size); } else { uint64_t next = MIN(stripe_ofs + rule.stripe_max_size, part_ofs + rule.part_size); stripe_size = next - stripe_ofs; } cur_override_prefix = rule.override_prefix; update_location(); } void RGWObjManifest::obj_iterator::update_location() { if (manifest->explicit_objs) { location = explicit_iter->second.loc; return; } const rgw_obj& head = manifest->get_head(); if (ofs < manifest->get_head_size()) { location = head; return; } manifest->get_implicit_location(cur_part_id, cur_stripe, ofs, &cur_override_prefix, &location); } void RGWObjManifest::obj_iterator::update_explicit_pos() { ofs = explicit_iter->first; stripe_ofs = ofs; map::iterator next_iter = explicit_iter; ++next_iter; if (next_iter != manifest->objs.end()) { stripe_size = next_iter->first - ofs; } else { stripe_size = manifest->obj_size - ofs; } } void RGWObjManifest::generate_test_instances(std::list& o) { RGWObjManifest *m = new RGWObjManifest; for (int i = 0; i<10; i++) { RGWObjManifestPart p; rgw_bucket b("bucket", ".pool", ".index_pool", "marker_", "12", "region"); p.loc = rgw_obj(b, "object"); p.loc_ofs = 0; p.size = 512 * 1024; m->objs[(uint64_t)i * 512 * 1024] = p; } m->obj_size = 5 * 1024 * 1024; o.push_back(m); o.push_back(new RGWObjManifest); } void RGWObjManifest::get_implicit_location(uint64_t cur_part_id, uint64_t cur_stripe, uint64_t ofs, string *override_prefix, rgw_obj *location) { string oid; if (!override_prefix || override_prefix->empty()) { oid = prefix; } else { oid = *override_prefix; } string ns; if (!cur_part_id) { if (ofs < max_head_size) { *location = head_obj; return; } else { char buf[16]; snprintf(buf, sizeof(buf), "%d", (int)cur_stripe); oid += buf; ns = shadow_ns; } } else { char buf[32]; if (cur_stripe == 0) { snprintf(buf, sizeof(buf), ".%d", (int)cur_part_id); oid += buf; ns= RGW_OBJ_NS_MULTIPART; } else { snprintf(buf, sizeof(buf), ".%d_%d", (int)cur_part_id, (int)cur_stripe); oid += buf; ns = shadow_ns; } } rgw_bucket *bucket; if (!tail_bucket.name.empty()) { bucket = &tail_bucket; } else { bucket = &head_obj.bucket; } location->init_ns(*bucket, oid, ns); } void rgw_log_entry::generate_test_instances(list& o) { rgw_log_entry *e = new rgw_log_entry; e->object_owner = "object_owner"; e->bucket_owner = "bucket_owner"; e->bucket = "bucket"; e->remote_addr = "1.2.3.4"; e->user = "user"; e->obj = "obj"; e->uri = "http://uri/bucket/obj"; e->http_status = "200"; e->error_code = "error_code"; e->bytes_sent = 1024; e->bytes_received = 512; e->obj_size = 2048; e->user_agent = "user_agent"; e->referrer = "referrer"; e->bucket_id = "10"; o.push_back(e); o.push_back(new rgw_log_entry); } void rgw_intent_log_entry::generate_test_instances(list& o) { rgw_intent_log_entry *e = new rgw_intent_log_entry; rgw_bucket b("bucket", "pool", ".index_pool", "marker", "10", "region"); e->obj = rgw_obj(b, "object"); e->intent = DEL_OBJ; o.push_back(e); o.push_back(new rgw_intent_log_entry); } void ACLPermission::generate_test_instances(list& o) { ACLPermission *p = new ACLPermission; p->set_permissions(RGW_PERM_WRITE_ACP); o.push_back(p); o.push_back(new ACLPermission); } void ACLGranteeType::generate_test_instances(list& o) { ACLGranteeType *t = new ACLGranteeType; t->set(ACL_TYPE_CANON_USER); o.push_back(t); o.push_back(new ACLGranteeType); } /* the following is copied here from rgw_acl_s3.cc, to avoid having to have excessive linking with everything it needs */ #define RGW_URI_ALL_USERS "http://acs.amazonaws.com/groups/global/AllUsers" #define RGW_URI_AUTH_USERS "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" static string rgw_uri_all_users = RGW_URI_ALL_USERS; static string rgw_uri_auth_users = RGW_URI_AUTH_USERS; ACLGroupTypeEnum ACLGrant::uri_to_group(string& uri) { // this is required for backward compatibility return ACLGrant_S3::uri_to_group(uri); } ACLGroupTypeEnum ACLGrant_S3::uri_to_group(string& uri) { if (uri.compare(rgw_uri_all_users) == 0) return ACL_GROUP_ALL_USERS; else if (uri.compare(rgw_uri_auth_users) == 0) return ACL_GROUP_AUTHENTICATED_USERS; return ACL_GROUP_NONE; } void ACLGrant::generate_test_instances(list& o) { string id, name, email; id = "rgw"; name = "Mr. RGW"; email = "r@gw"; ACLGrant *g1 = new ACLGrant; g1->set_canon(id, name, RGW_PERM_READ); g1->email = email; o.push_back(g1); ACLGrant *g2 = new ACLGrant; g1->set_group(ACL_GROUP_AUTHENTICATED_USERS, RGW_PERM_WRITE); o.push_back(g2); o.push_back(new ACLGrant); } void RGWAccessControlList::generate_test_instances(list& o) { RGWAccessControlList *acl = new RGWAccessControlList(NULL); list glist; list::iterator iter; ACLGrant::generate_test_instances(glist); for (iter = glist.begin(); iter != glist.end(); ++iter) { ACLGrant *grant = *iter; acl->add_grant(grant); delete grant; } o.push_back(acl); o.push_back(new RGWAccessControlList(NULL)); } void ACLOwner::generate_test_instances(list& o) { ACLOwner *owner = new ACLOwner; owner->id = "rgw"; owner->display_name = "Mr. RGW"; o.push_back(owner); o.push_back(new ACLOwner); } void RGWAccessControlPolicy::generate_test_instances(list& o) { list acl_list; list::iterator iter; for (iter = acl_list.begin(); iter != acl_list.end(); ++iter) { RGWAccessControlList::generate_test_instances(acl_list); iter = acl_list.begin(); RGWAccessControlPolicy *p = new RGWAccessControlPolicy(NULL); RGWAccessControlList *l = *iter; p->acl = *l; string name = "radosgw"; string id = "rgw"; p->owner.set_name(name); p->owner.set_id(id); o.push_back(p); delete l; } o.push_back(new RGWAccessControlPolicy(NULL)); } void ObjectMetaInfo::generate_test_instances(list& o) { ObjectMetaInfo *m = new ObjectMetaInfo; m->size = 1024 * 1024; o.push_back(m); o.push_back(new ObjectMetaInfo); } void ObjectCacheInfo::generate_test_instances(list& o) { ObjectCacheInfo *i = new ObjectCacheInfo; i->status = 0; i->flags = CACHE_FLAG_MODIFY_XATTRS; string s = "this is a string"; string s2 = "this is a another string"; bufferlist data, data2; ::encode(s, data); ::encode(s2, data2); i->data = data; i->xattrs["x1"] = data; i->xattrs["x2"] = data2; i->rm_xattrs["r2"] = data2; i->rm_xattrs["r3"] = data; i->meta.size = 512 * 1024; o.push_back(i); o.push_back(new ObjectCacheInfo); } void RGWCacheNotifyInfo::generate_test_instances(list& o) { o.push_back(new RGWCacheNotifyInfo); } void RGWAccessKey::generate_test_instances(list& o) { RGWAccessKey *k = new RGWAccessKey; k->id = "id"; k->key = "key"; k->subuser = "subuser"; o.push_back(k); o.push_back(new RGWAccessKey); } void RGWSubUser::generate_test_instances(list& o) { RGWSubUser *u = new RGWSubUser; u->name = "name"; u->perm_mask = 0xf; o.push_back(u); o.push_back(new RGWSubUser); } void RGWUserInfo::generate_test_instances(list& o) { RGWUserInfo *i = new RGWUserInfo; i->auid = 1; i->user_id = "user_id"; i->display_name = "display_name"; i->user_email = "user@email"; RGWAccessKey k1, k2; k1.id = "id1"; k1.key = "key1"; k2.id = "id2"; k2.subuser = "subuser"; RGWSubUser u; u.name = "id2"; u.perm_mask = 0x1; i->access_keys[k1.id] = k1; i->swift_keys[k2.id] = k2; i->subusers[u.name] = u; o.push_back(i); o.push_back(new RGWUserInfo); } void rgw_bucket::generate_test_instances(list& o) { rgw_bucket *b = new rgw_bucket("name", "pool", ".index_pool", "marker", "123", "region"); o.push_back(b); o.push_back(new rgw_bucket); } void RGWBucketInfo::generate_test_instances(list& o) { RGWBucketInfo *i = new RGWBucketInfo; i->bucket = rgw_bucket("bucket", "pool", ".index_pool", "marker", "10", "region"); i->owner = "owner"; i->flags = BUCKET_SUSPENDED; o.push_back(i); o.push_back(new RGWBucketInfo); } void RGWBucketEnt::generate_test_instances(list& o) { RGWBucketEnt *e = new RGWBucketEnt; e->bucket = rgw_bucket("bucket", "pool", ".index_pool", "marker", "10", "region"); e->size = 1024; e->size_rounded = 4096; e->count = 1; o.push_back(e); o.push_back(new RGWBucketEnt); } void RGWUploadPartInfo::generate_test_instances(list& o) { RGWUploadPartInfo *i = new RGWUploadPartInfo; i->num = 1; i->size = 10 * 1024 * 1024; i->etag = "etag"; o.push_back(i); o.push_back(new RGWUploadPartInfo); } void rgw_obj::generate_test_instances(list& o) { rgw_bucket b = rgw_bucket("bucket", "pool", ".index_pool", "marker", "10", "region"); rgw_obj *obj = new rgw_obj(b, "object"); o.push_back(obj); o.push_back(new rgw_obj); } ceph-0.80.11/src/rgw/rgw_rest_s3.cc0000664000175100017510000017077212623076744021051 0ustar jenkins-buildjenkins-build#include #include #include "common/ceph_crypto.h" #include "common/Formatter.h" #include "common/utf8.h" #include "common/ceph_json.h" #include "rgw_rest.h" #include "rgw_rest_s3.h" #include "rgw_auth_s3.h" #include "rgw_acl.h" #include "rgw_policy_s3.h" #include "rgw_user.h" #include "rgw_cors.h" #include "rgw_cors_s3.h" #include "rgw_client_io.h" #define dout_subsys ceph_subsys_rgw using namespace ceph::crypto; void list_all_buckets_start(struct req_state *s) { s->formatter->open_array_section_in_ns("ListAllMyBucketsResult", "http://s3.amazonaws.com/doc/2006-03-01/"); } void list_all_buckets_end(struct req_state *s) { s->formatter->close_section(); } void dump_bucket(struct req_state *s, RGWBucketEnt& obj) { s->formatter->open_object_section("Bucket"); s->formatter->dump_string("Name", obj.bucket.name); dump_time(s, "CreationDate", &obj.creation_time); s->formatter->close_section(); } void rgw_get_errno_s3(rgw_http_errors *e , int err_no) { const struct rgw_http_errors *r; r = search_err(err_no, RGW_HTTP_ERRORS, ARRAY_LEN(RGW_HTTP_ERRORS)); if (r) { e->http_ret = r->http_ret; e->s3_code = r->s3_code; } else { e->http_ret = 500; e->s3_code = "UnknownError"; } } struct response_attr_param { const char *param; const char *http_attr; }; static struct response_attr_param resp_attr_params[] = { {"response-content-type", "Content-Type"}, {"response-content-language", "Content-Language"}, {"response-expires", "Expires"}, {"response-cache-control", "Cache-Control"}, {"response-content-disposition", "Content-Disposition"}, {"response-content-encoding", "Content-Encoding"}, {NULL, NULL}, }; int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) { const char *content_type = NULL; string content_type_str; map response_attrs; map::iterator riter; bufferlist metadata_bl; if (ret) goto done; if (sent_header) goto send_data; if (range_str) dump_range(s, start, end, s->obj_size); if (s->system_request && s->info.args.exists(RGW_SYS_PARAM_PREFIX "prepend-metadata")) { /* JSON encode object metadata */ JSONFormatter jf; jf.open_object_section("obj_metadata"); encode_json("attrs", attrs, &jf); encode_json("mtime", lastmod, &jf); jf.close_section(); stringstream ss; jf.flush(ss); metadata_bl.append(ss.str()); s->cio->print("Rgwx-Embedded-Metadata-Len: %lld\r\n", (long long)metadata_bl.length()); total_len += metadata_bl.length(); } if (s->system_request && lastmod) { /* we end up dumping mtime in two different methods, a bit redundant */ dump_epoch_header(s, "Rgwx-Mtime", lastmod); } dump_content_length(s, total_len); dump_last_modified(s, lastmod); if (!ret) { map::iterator iter = attrs.find(RGW_ATTR_ETAG); if (iter != attrs.end()) { bufferlist& bl = iter->second; if (bl.length()) { char *etag = bl.c_str(); dump_etag(s, etag); } } for (struct response_attr_param *p = resp_attr_params; p->param; p++) { bool exists; string val = s->info.args.get(p->param, &exists); if (exists) { if (strcmp(p->param, "response-content-type") != 0) { response_attrs[p->http_attr] = val; } else { content_type_str = val; content_type = content_type_str.c_str(); } } } for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const char *name = iter->first.c_str(); map::iterator aiter = rgw_to_http_attrs.find(name); if (aiter != rgw_to_http_attrs.end()) { if (response_attrs.count(aiter->second) > 0) // was already overridden by a response param continue; if (aiter->first.compare(RGW_ATTR_CONTENT_TYPE) == 0) { // special handling for content_type if (!content_type) content_type = iter->second.c_str(); continue; } response_attrs[aiter->second] = iter->second.c_str(); } else { if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) { name += sizeof(RGW_ATTR_PREFIX) - 1; s->cio->print("%s: %s\r\n", name, iter->second.c_str()); } } } } done: set_req_state_err(s, (partial_content && !ret) ? STATUS_PARTIAL_CONTENT : ret); dump_errno(s); for (riter = response_attrs.begin(); riter != response_attrs.end(); ++riter) { s->cio->print("%s: %s\r\n", riter->first.c_str(), riter->second.c_str()); } if (!content_type) content_type = "binary/octet-stream"; end_header(s, this, content_type); if (metadata_bl.length()) { s->cio->write(metadata_bl.c_str(), metadata_bl.length()); } sent_header = true; send_data: if (get_data && !ret) { int r = s->cio->write(bl.c_str() + bl_ofs, bl_len); if (r < 0) return r; } return 0; } void RGWListBuckets_ObjStore_S3::send_response_begin(bool has_buckets) { if (ret) set_req_state_err(s, ret); dump_errno(s); dump_start(s); end_header(s, NULL, "application/xml"); if (!ret) { list_all_buckets_start(s); dump_owner(s, s->user.user_id, s->user.display_name); s->formatter->open_array_section("Buckets"); sent_data = true; } } void RGWListBuckets_ObjStore_S3::send_response_data(RGWUserBuckets& buckets) { if (!sent_data) return; map& m = buckets.get_buckets(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt obj = iter->second; dump_bucket(s, obj); } rgw_flush_formatter(s, s->formatter); } void RGWListBuckets_ObjStore_S3::send_response_end() { if (sent_data) { s->formatter->close_section(); list_all_buckets_end(s); rgw_flush_formatter_and_reset(s, s->formatter); } } int RGWListBucket_ObjStore_S3::get_params() { prefix = s->info.args.get("prefix"); marker = s->info.args.get("marker"); max_keys = s->info.args.get("max-keys"); ret = parse_max_keys(); if (ret < 0) { return ret; } delimiter = s->info.args.get("delimiter"); return 0; } void RGWListBucket_ObjStore_S3::send_response() { if (ret < 0) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); dump_start(s); if (ret < 0) return; s->formatter->open_object_section_in_ns("ListBucketResult", "http://s3.amazonaws.com/doc/2006-03-01/"); s->formatter->dump_string("Name", s->bucket_name_str); s->formatter->dump_string("Prefix", prefix); s->formatter->dump_string("Marker", marker); if (is_truncated && !next_marker.empty()) s->formatter->dump_string("NextMarker", next_marker); s->formatter->dump_int("MaxKeys", max); if (!delimiter.empty()) s->formatter->dump_string("Delimiter", delimiter); s->formatter->dump_string("IsTruncated", (max && is_truncated ? "true" : "false")); if (ret >= 0) { vector::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { s->formatter->open_array_section("Contents"); s->formatter->dump_string("Key", iter->name); time_t mtime = iter->mtime.sec(); dump_time(s, "LastModified", &mtime); s->formatter->dump_format("ETag", "\"%s\"", iter->etag.c_str()); s->formatter->dump_int("Size", iter->size); s->formatter->dump_string("StorageClass", "STANDARD"); dump_owner(s, iter->owner, iter->owner_display_name); s->formatter->close_section(); } if (common_prefixes.size() > 0) { map::iterator pref_iter; for (pref_iter = common_prefixes.begin(); pref_iter != common_prefixes.end(); ++pref_iter) { s->formatter->open_array_section("CommonPrefixes"); s->formatter->dump_string("Prefix", pref_iter->first); s->formatter->close_section(); } } } s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } void RGWGetBucketLogging_ObjStore_S3::send_response() { dump_errno(s); end_header(s, this, "application/xml"); dump_start(s); s->formatter->open_object_section_in_ns("BucketLoggingStatus", "http://doc.s3.amazonaws.com/doc/2006-03-01/"); s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } static void dump_bucket_metadata(struct req_state *s, RGWBucketEnt& bucket) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", (long long)bucket.count); s->cio->print("X-RGW-Object-Count: %s\r\n", buf); snprintf(buf, sizeof(buf), "%lld", (long long)bucket.size); s->cio->print("X-RGW-Bytes-Used: %s\r\n", buf); } void RGWStatBucket_ObjStore_S3::send_response() { if (ret >= 0) { dump_bucket_metadata(s, bucket); } set_req_state_err(s, ret); dump_errno(s); end_header(s, this); dump_start(s); } static int create_s3_policy(struct req_state *s, RGWRados *store, RGWAccessControlPolicy_S3& s3policy, ACLOwner& owner) { if (s->has_acl_header) { if (!s->canned_acl.empty()) return -ERR_INVALID_REQUEST; return s3policy.create_from_headers(store, s->info.env, owner); } return s3policy.create_canned(owner, s->bucket_owner, s->canned_acl); } class RGWLocationConstraint : public XMLObj { public: RGWLocationConstraint() {} ~RGWLocationConstraint() {} bool xml_end(const char *el) { if (!el) return false; location_constraint = get_data(); return true; } string location_constraint; }; class RGWCreateBucketConfig : public XMLObj { public: RGWCreateBucketConfig() {} ~RGWCreateBucketConfig() {} }; class RGWCreateBucketParser : public RGWXMLParser { XMLObj *alloc_obj(const char *el) { return new XMLObj; } public: RGWCreateBucketParser() {} ~RGWCreateBucketParser() {} bool get_location_constraint(string& region) { XMLObj *config = find_first("CreateBucketConfiguration"); if (!config) return false; XMLObj *constraint = config->find_first("LocationConstraint"); if (!constraint) return false; region = constraint->get_data(); return true; } }; int RGWCreateBucket_ObjStore_S3::get_params() { RGWAccessControlPolicy_S3 s3policy(s->cct); int r = create_s3_policy(s, store, s3policy, s->owner); if (r < 0) return r; policy = s3policy; int len = 0; char *data; #define CREATE_BUCKET_MAX_REQ_LEN (512 * 1024) /* this is way more than enough */ ret = rgw_rest_read_all_input(s, &data, &len, CREATE_BUCKET_MAX_REQ_LEN); if ((ret < 0) && (ret != -ERR_LENGTH_REQUIRED)) return ret; bufferptr in_ptr(data, len); in_data.append(in_ptr); if (len) { RGWCreateBucketParser parser; if (!parser.init()) { ldout(s->cct, 0) << "ERROR: failed to initialize parser" << dendl; return -EIO; } bool success = parser.parse(data, len, 1); ldout(s->cct, 20) << "create bucket input data=" << data << dendl; if (!success) { ldout(s->cct, 0) << "failed to parse input: " << data << dendl; free(data); return -EINVAL; } free(data); if (!parser.get_location_constraint(location_constraint)) { ldout(s->cct, 0) << "provided input did not specify location constraint correctly" << dendl; return -EINVAL; } ldout(s->cct, 10) << "create bucket location constraint: " << location_constraint << dendl; } int pos = location_constraint.find(':'); if (pos >= 0) { placement_rule = location_constraint.substr(pos + 1); location_constraint = location_constraint.substr(0, pos); } return 0; } void RGWCreateBucket_ObjStore_S3::send_response() { if (ret == -ERR_BUCKET_EXISTS) ret = 0; if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s); if (ret < 0) return; if (s->system_request) { JSONFormatter f; /* use json formatter for system requests output */ f.open_object_section("info"); encode_json("entry_point_object_ver", ep_objv, &f); encode_json("object_ver", info.objv_tracker.read_version, &f); encode_json("bucket_info", info, &f); f.close_section(); rgw_flush_formatter_and_reset(s, &f); } } void RGWDeleteBucket_ObjStore_S3::send_response() { int r = ret; if (!r) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, this); if (s->system_request) { JSONFormatter f; /* use json formatter for system requests output */ f.open_object_section("info"); encode_json("object_ver", objv_tracker.read_version, &f); f.close_section(); rgw_flush_formatter_and_reset(s, &f); } } int RGWPutObj_ObjStore_S3::get_params() { RGWAccessControlPolicy_S3 s3policy(s->cct); if (!s->length) return -ERR_LENGTH_REQUIRED; int r = create_s3_policy(s, store, s3policy, s->owner); if (r < 0) return r; policy = s3policy; return RGWPutObj_ObjStore::get_params(); } static int get_success_retcode(int code) { switch (code) { case 201: return STATUS_CREATED; case 204: return STATUS_NO_CONTENT; } return 0; } void RGWPutObj_ObjStore_S3::send_response() { if (ret) { set_req_state_err(s, ret); } else { if (s->cct->_conf->rgw_s3_success_create_obj_status) { ret = get_success_retcode(s->cct->_conf->rgw_s3_success_create_obj_status); set_req_state_err(s, ret); } dump_etag(s, etag.c_str()); dump_content_length(s, 0); } if (s->system_request && mtime) { dump_epoch_header(s, "Rgwx-Mtime", mtime); } dump_errno(s); end_header(s, this); } /* * parses params in the format: 'first; param1=foo; param2=bar' */ static void parse_params(const string& params_str, string& first, map& params) { int pos = params_str.find(';'); if (pos < 0) { first = rgw_trim_whitespace(params_str); return; } first = rgw_trim_whitespace(params_str.substr(0, pos)); pos++; while (pos < (int)params_str.size()) { ssize_t end = params_str.find(';', pos); if (end < 0) end = params_str.size(); string param = params_str.substr(pos, end - pos); int eqpos = param.find('='); if (eqpos > 0) { string param_name = rgw_trim_whitespace(param.substr(0, eqpos)); string val = rgw_trim_quotes(param.substr(eqpos + 1)); params[param_name] = val; } else { params[rgw_trim_whitespace(param)] = ""; } pos = end + 1; } } static int parse_part_field(const string& line, string& field_name, struct post_part_field& field) { int pos = line.find(':'); if (pos < 0) return -EINVAL; field_name = line.substr(0, pos); if (pos >= (int)line.size() - 1) return 0; parse_params(line.substr(pos + 1), field.val, field.params); return 0; } bool is_crlf(const char *s) { return (*s == '\r' && *(s + 1) == '\n'); } /* * find the index of the boundary, if exists, or optionally the next end of line * also returns how many bytes to skip */ static int index_of(bufferlist& bl, int max_len, const string& str, bool check_crlf, bool *reached_boundary, int *skip) { *reached_boundary = false; *skip = 0; if (str.size() < 2) // we assume boundary is at least 2 chars (makes it easier with crlf checks) return -EINVAL; if (bl.length() < str.size()) return -1; const char *buf = bl.c_str(); const char *s = str.c_str(); if (max_len > (int)bl.length()) max_len = bl.length(); int i; for (i = 0; i < max_len; i++, buf++) { if (check_crlf && i >= 1 && is_crlf(buf - 1)) { return i + 1; // skip the crlf } if ((i < max_len - (int)str.size() + 1) && (buf[0] == s[0] && buf[1] == s[1]) && (strncmp(buf, s, str.size()) == 0)) { *reached_boundary = true; *skip = str.size(); /* oh, great, now we need to swallow the preceding crlf * if exists */ if ((i >= 2) && is_crlf(buf - 2)) { i -= 2; *skip += 2; } return i; } } return -1; } int RGWPostObj_ObjStore_S3::read_with_boundary(bufferlist& bl, uint64_t max, bool check_crlf, bool *reached_boundary, bool *done) { uint64_t cl = max + 2 + boundary.size(); if (max > in_data.length()) { uint64_t need_to_read = cl - in_data.length(); bufferptr bp(need_to_read); int read_len; s->cio->read(bp.c_str(), need_to_read, &read_len); in_data.append(bp, 0, read_len); } *done = false; int skip; int index = index_of(in_data, cl, boundary, check_crlf, reached_boundary, &skip); if (index >= 0) max = index; if (max > in_data.length()) max = in_data.length(); bl.substr_of(in_data, 0, max); bufferlist new_read_data; /* * now we need to skip boundary for next time, also skip any crlf, or * check to see if it's the last final boundary (marked with "--" at the end */ if (*reached_boundary) { int left = in_data.length() - max; if (left < skip + 2) { int need = skip + 2 - left; bufferptr boundary_bp(need); int actual; s->cio->read(boundary_bp.c_str(), need, &actual); in_data.append(boundary_bp); } max += skip; // skip boundary for next time if (in_data.length() >= max + 2) { const char *data = in_data.c_str(); if (is_crlf(data + max)) { max += 2; } else { if (*(data + max) == '-' && *(data + max + 1) == '-') { *done = true; max += 2; } } } } new_read_data.substr_of(in_data, max, in_data.length() - max); in_data = new_read_data; return 0; } int RGWPostObj_ObjStore_S3::read_line(bufferlist& bl, uint64_t max, bool *reached_boundary, bool *done) { return read_with_boundary(bl, max, true, reached_boundary, done); } int RGWPostObj_ObjStore_S3::read_data(bufferlist& bl, uint64_t max, bool *reached_boundary, bool *done) { return read_with_boundary(bl, max, false, reached_boundary, done); } int RGWPostObj_ObjStore_S3::read_form_part_header(struct post_form_part *part, bool *done) { bufferlist bl; bool reached_boundary; uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; int r = read_line(bl, chunk_size, &reached_boundary, done); if (r < 0) return r; if (*done) { return 0; } if (reached_boundary) { // skip the first boundary r = read_line(bl, chunk_size, &reached_boundary, done); if (r < 0) return r; if (*done) return 0; } while (true) { /* * iterate through fields */ string line = rgw_trim_whitespace(string(bl.c_str(), bl.length())); if (line.empty()) break; struct post_part_field field; string field_name; r = parse_part_field(line, field_name, field); if (r < 0) return r; part->fields[field_name] = field; if (stringcasecmp(field_name, "Content-Disposition") == 0) { part->name = field.params["name"]; } if (reached_boundary) break; r = read_line(bl, chunk_size, &reached_boundary, done); } return 0; } bool RGWPostObj_ObjStore_S3::part_str(const string& name, string *val) { map::iterator iter = parts.find(name); if (iter == parts.end()) return false; bufferlist& data = iter->second.data; string str = string(data.c_str(), data.length()); *val = rgw_trim_whitespace(str); return true; } bool RGWPostObj_ObjStore_S3::part_bl(const string& name, bufferlist *pbl) { map::iterator iter = parts.find(name); if (iter == parts.end()) return false; *pbl = iter->second.data; return true; } void RGWPostObj_ObjStore_S3::rebuild_key(string& key) { static string var = "${filename}"; int pos = key.find(var); if (pos < 0) return; string new_key = key.substr(0, pos); new_key.append(filename); new_key.append(key.substr(pos + var.size())); key = new_key; } int RGWPostObj_ObjStore_S3::get_params() { // get the part boundary string req_content_type_str = s->info.env->get("CONTENT_TYPE", ""); string req_content_type; map params; if (s->expect_cont) { /* ok, here it really gets ugly. With POST, the params are embedded in the * request body, so we need to continue before being able to actually look * at them. This diverts from the usual request flow. */ dump_continue(s); s->expect_cont = false; } parse_params(req_content_type_str, req_content_type, params); if (req_content_type.compare("multipart/form-data") != 0) { err_msg = "Request Content-Type is not multipart/form-data"; return -EINVAL; } if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) { ldout(s->cct, 20) << "request content_type_str=" << req_content_type_str << dendl; ldout(s->cct, 20) << "request content_type params:" << dendl; map::iterator iter; for (iter = params.begin(); iter != params.end(); ++iter) { ldout(s->cct, 20) << " " << iter->first << " -> " << iter->second << dendl; } } ldout(s->cct, 20) << "adding bucket to policy env: " << s->bucket.name << dendl; env.add_var("bucket", s->bucket.name); map::iterator iter = params.find("boundary"); if (iter == params.end()) { err_msg = "Missing multipart boundary specification"; return -EINVAL; } // create the boundary boundary = "--"; boundary.append(iter->second); bool done; do { struct post_form_part part; int r = read_form_part_header(&part, &done); if (r < 0) return r; if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) { map::iterator piter; for (piter = part.fields.begin(); piter != part.fields.end(); ++piter) { ldout(s->cct, 20) << "read part header: name=" << part.name << " content_type=" << part.content_type << dendl; ldout(s->cct, 20) << "name=" << piter->first << dendl; ldout(s->cct, 20) << "val=" << piter->second.val << dendl; ldout(s->cct, 20) << "params:" << dendl; map& params = piter->second.params; for (iter = params.begin(); iter != params.end(); ++iter) { ldout(s->cct, 20) << " " << iter->first << " -> " << iter->second << dendl; } } } if (done) { /* unexpected here */ err_msg = "Malformed request"; return -EINVAL; } if (stringcasecmp(part.name, "file") == 0) { /* beginning of data transfer */ struct post_part_field& field = part.fields["Content-Disposition"]; map::iterator iter = field.params.find("filename"); if (iter != field.params.end()) { filename = iter->second; } parts[part.name] = part; data_pending = true; break; } bool boundary; uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; r = read_data(part.data, chunk_size, &boundary, &done); if (!boundary) { err_msg = "Couldn't find boundary"; return -EINVAL; } parts[part.name] = part; string part_str(part.data.c_str(), part.data.length()); env.add_var(part.name, part_str); } while (!done); if (!part_str("key", &s->object_str)) { err_msg = "Key not specified"; return -EINVAL; } rebuild_key(s->object_str); if (s->object_str.empty()) { err_msg = "Empty object name"; return -EINVAL; } env.add_var("key", s->object_str); part_str("Content-Type", &content_type); env.add_var("Content-Type", content_type); map::iterator piter = parts.upper_bound(RGW_AMZ_META_PREFIX); for (; piter != parts.end(); ++piter) { string n = piter->first; if (strncasecmp(n.c_str(), RGW_AMZ_META_PREFIX, sizeof(RGW_AMZ_META_PREFIX) - 1) != 0) break; string attr_name = RGW_ATTR_PREFIX; attr_name.append(n); /* need to null terminate it */ bufferlist& data = piter->second.data; string str = string(data.c_str(), data.length()); bufferlist attr_bl; attr_bl.append(str.c_str(), str.size() + 1); attrs[attr_name] = attr_bl; } int r = get_policy(); if (r < 0) return r; min_len = post_policy.min_length; max_len = post_policy.max_length; return 0; } int RGWPostObj_ObjStore_S3::get_policy() { bufferlist encoded_policy; if (part_bl("policy", &encoded_policy)) { // check that the signature matches the encoded policy string s3_access_key; if (!part_str("AWSAccessKeyId", &s3_access_key)) { ldout(s->cct, 0) << "No S3 access key found!" << dendl; err_msg = "Missing access key"; return -EINVAL; } string received_signature_str; if (!part_str("signature", &received_signature_str)) { ldout(s->cct, 0) << "No signature found!" << dendl; err_msg = "Missing signature"; return -EINVAL; } RGWUserInfo user_info; ret = rgw_get_user_info_by_access_key(store, s3_access_key, user_info); if (ret < 0) { // Try keystone authentication as well int keystone_result = -EINVAL; if (!store->ctx()->_conf->rgw_s3_auth_use_keystone || store->ctx()->_conf->rgw_keystone_url.empty()) { return -EACCES; } dout(20) << "s3 keystone: trying keystone auth" << dendl; RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx()); keystone_result = keystone_validator.validate_s3token(s3_access_key,string(encoded_policy.c_str(),encoded_policy.length()),received_signature_str); if (keystone_result < 0) { ldout(s->cct, 0) << "User lookup failed!" << dendl; err_msg = "Bad access key / signature"; return -EACCES; } user_info.user_id = keystone_validator.response.token.tenant.id; user_info.display_name = keystone_validator.response.token.tenant.name; /* try to store user if it not already exists */ if (rgw_get_user_info_by_uid(store, keystone_validator.response.token.tenant.id, user_info) < 0) { int ret = rgw_store_user_info(store, user_info, NULL, NULL, 0, true); if (ret < 0) { dout(10) << "NOTICE: failed to store new user's info: ret=" << ret << dendl; } s->perm_mask = RGW_PERM_FULL_CONTROL; } } else { map access_keys = user_info.access_keys; map::const_iterator iter = access_keys.find(s3_access_key); // We know the key must exist, since the user was returned by // rgw_get_user_info_by_access_key, but it doesn't hurt to check! if (iter == access_keys.end()) { ldout(s->cct, 0) << "Secret key lookup failed!" << dendl; err_msg = "No secret key for matching access key"; return -EACCES; } string s3_secret_key = (iter->second).key; char expected_signature_char[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; calc_hmac_sha1(s3_secret_key.c_str(), s3_secret_key.size(), encoded_policy.c_str(), encoded_policy.length(), expected_signature_char); bufferlist expected_signature_hmac_raw; bufferlist expected_signature_hmac_encoded; expected_signature_hmac_raw.append(expected_signature_char, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); expected_signature_hmac_raw.encode_base64(expected_signature_hmac_encoded); expected_signature_hmac_encoded.append((char)0); /* null terminate */ if (received_signature_str.compare(expected_signature_hmac_encoded.c_str()) != 0) { ldout(s->cct, 0) << "Signature verification failed!" << dendl; ldout(s->cct, 0) << "received: " << received_signature_str.c_str() << dendl; ldout(s->cct, 0) << "expected: " << expected_signature_hmac_encoded.c_str() << dendl; err_msg = "Bad access key / signature"; return -EACCES; } } ldout(s->cct, 0) << "Successful Signature Verification!" << dendl; bufferlist decoded_policy; try { decoded_policy.decode_base64(encoded_policy); } catch (buffer::error& err) { ldout(s->cct, 0) << "failed to decode_base64 policy" << dendl; err_msg = "Could not decode policy"; return -EINVAL; } decoded_policy.append('\0'); // NULL terminate ldout(s->cct, 0) << "POST policy: " << decoded_policy.c_str() << dendl; int r = post_policy.from_json(decoded_policy, err_msg); if (r < 0) { if (err_msg.empty()) { err_msg = "Failed to parse policy"; } ldout(s->cct, 0) << "failed to parse policy" << dendl; return -EINVAL; } post_policy.set_var_checked("AWSAccessKeyId"); post_policy.set_var_checked("policy"); post_policy.set_var_checked("signature"); r = post_policy.check(&env, err_msg); if (r < 0) { if (err_msg.empty()) { err_msg = "Policy check failed"; } ldout(s->cct, 0) << "policy check failed" << dendl; return r; } s->user = user_info; s->owner.set_id(user_info.user_id); s->owner.set_name(user_info.display_name); } else { ldout(s->cct, 0) << "No attached policy found!" << dendl; } string canned_acl; part_str("acl", &canned_acl); RGWAccessControlPolicy_S3 s3policy(s->cct); ldout(s->cct, 20) << "canned_acl=" << canned_acl << dendl; if (s3policy.create_canned(s->owner, s->bucket_owner, canned_acl) < 0) { err_msg = "Bad canned ACLs"; return -EINVAL; } policy = s3policy; return 0; } int RGWPostObj_ObjStore_S3::complete_get_params() { bool done; do { struct post_form_part part; int r = read_form_part_header(&part, &done); if (r < 0) return r; bufferlist part_data; bool boundary; uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; r = read_data(part.data, chunk_size, &boundary, &done); if (!boundary) { return -EINVAL; } parts[part.name] = part; } while (!done); return 0; } int RGWPostObj_ObjStore_S3::get_data(bufferlist& bl) { bool boundary; bool done; uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; int r = read_data(bl, chunk_size, &boundary, &done); if (r < 0) return r; if (boundary) { data_pending = false; if (!done) { /* reached end of data, let's drain the rest of the params */ r = complete_get_params(); if (r < 0) return r; } } return bl.length(); } void RGWPostObj_ObjStore_S3::send_response() { if (ret == 0 && parts.count("success_action_redirect")) { string redirect; part_str("success_action_redirect", &redirect); string bucket; string key; string etag_str = "\""; etag_str.append(etag); etag_str.append("\""); string etag_url; url_encode(s->bucket_name_str, bucket); url_encode(s->object_str, key); url_encode(etag_str, etag_url); redirect.append("?bucket="); redirect.append(bucket); redirect.append("&key="); redirect.append(key); redirect.append("&etag="); redirect.append(etag_url); int r = check_utf8(redirect.c_str(), redirect.size()); if (r < 0) { ret = r; goto done; } dump_redirect(s, redirect); ret = STATUS_REDIRECT; } else if (ret == 0 && parts.count("success_action_status")) { string status_string; uint32_t status_int; part_str("success_action_status", &status_string); int r = stringtoul(status_string, &status_int); if (r < 0) { ret = r; goto done; } switch (status_int) { case 200: break; case 201: ret = STATUS_CREATED; break; default: ret = STATUS_NO_CONTENT; break; } } else if (!ret) { ret = STATUS_NO_CONTENT; } done: if (ret == STATUS_CREATED) { s->formatter->open_object_section("PostResponse"); if (g_conf->rgw_dns_name.length()) s->formatter->dump_format("Location", "%s/%s", s->info.script_uri.c_str(), s->object_str.c_str()); s->formatter->dump_string("Bucket", s->bucket_name_str); s->formatter->dump_string("Key", s->object_str); s->formatter->close_section(); } s->err.message = err_msg; set_req_state_err(s, ret); dump_errno(s); if (ret >= 0) { dump_content_length(s, s->formatter->get_len()); } end_header(s, this); if (ret != STATUS_CREATED) return; rgw_flush_formatter_and_reset(s, s->formatter); } void RGWDeleteObj_ObjStore_S3::send_response() { int r = ret; if (r == -ENOENT) r = 0; if (!r) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, this); } int RGWCopyObj_ObjStore_S3::init_dest_policy() { RGWAccessControlPolicy_S3 s3policy(s->cct); /* build a policy for the target object */ int r = create_s3_policy(s, store, s3policy, s->owner); if (r < 0) return r; dest_policy = s3policy; return 0; } int RGWCopyObj_ObjStore_S3::get_params() { if_mod = s->info.env->get("HTTP_X_AMZ_COPY_IF_MODIFIED_SINCE"); if_unmod = s->info.env->get("HTTP_X_AMZ_COPY_IF_UNMODIFIED_SINCE"); if_match = s->info.env->get("HTTP_X_AMZ_COPY_IF_MATCH"); if_nomatch = s->info.env->get("HTTP_X_AMZ_COPY_IF_NONE_MATCH"); src_bucket_name = s->src_bucket_name; src_object = s->src_object; dest_bucket_name = s->bucket.name; dest_object = s->object_str; if (s->system_request) { source_zone = s->info.args.get(RGW_SYS_PARAM_PREFIX "source-zone"); if (!source_zone.empty()) { client_id = s->info.args.get(RGW_SYS_PARAM_PREFIX "client-id"); op_id = s->info.args.get(RGW_SYS_PARAM_PREFIX "op-id"); if (client_id.empty() || op_id.empty()) { ldout(s->cct, 0) << RGW_SYS_PARAM_PREFIX "client-id or " RGW_SYS_PARAM_PREFIX "op-id were not provided, required for intra-region copy" << dendl; return -EINVAL; } } } const char *md_directive = s->info.env->get("HTTP_X_AMZ_METADATA_DIRECTIVE"); if (md_directive) { if (strcasecmp(md_directive, "COPY") == 0) { replace_attrs = false; } else if (strcasecmp(md_directive, "REPLACE") == 0) { replace_attrs = true; } else if (!source_zone.empty()) { replace_attrs = false; // default for intra-region copy } else { ldout(s->cct, 0) << "invalid metadata directive" << dendl; return -EINVAL; } } if (source_zone.empty() && (dest_bucket_name.compare(src_bucket_name) == 0) && (dest_object.compare(src_object) == 0) && !replace_attrs) { /* can only copy object into itself if replacing attrs */ ldout(s->cct, 0) << "can't copy object into itself if not replacing attrs" << dendl; return -ERR_INVALID_REQUEST; } return 0; } void RGWCopyObj_ObjStore_S3::send_partial_response(off_t ofs) { if (!sent_header) { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); if (ret == 0) { s->formatter->open_object_section("CopyObjectResult"); } sent_header = true; } else { /* Send progress field. Note that this diverge from the original S3 * spec. We do this in order to keep connection alive. */ s->formatter->dump_int("Progress", (uint64_t)ofs); } rgw_flush_formatter(s, s->formatter); } void RGWCopyObj_ObjStore_S3::send_response() { if (!sent_header) send_partial_response(0); if (ret == 0) { dump_time(s, "LastModified", &mtime); if (!etag.empty()) { s->formatter->dump_string("ETag", etag); } s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } } void RGWGetACLs_ObjStore_S3::send_response() { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); dump_start(s); rgw_flush_formatter(s, s->formatter); s->cio->write(acls.c_str(), acls.size()); } int RGWPutACLs_ObjStore_S3::get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss) { RGWAccessControlPolicy_S3 s3policy(s->cct); // bucket-* canned acls do not apply to bucket if (s->object_str.empty()) { if (s->canned_acl.find("bucket") != string::npos) s->canned_acl.clear(); } int r = create_s3_policy(s, store, s3policy, owner); if (r < 0) return r; s3policy.to_xml(ss); return 0; } void RGWPutACLs_ObjStore_S3::send_response() { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); dump_start(s); } void RGWGetCORS_ObjStore_S3::send_response() { if (ret) { if (ret == -ENOENT) set_req_state_err(s, ERR_NOT_FOUND); else set_req_state_err(s, ret); } dump_errno(s); end_header(s, NULL, "application/xml"); dump_start(s); if (!ret) { string cors; RGWCORSConfiguration_S3 *s3cors = static_cast(&bucket_cors); stringstream ss; s3cors->to_xml(ss); cors = ss.str(); s->cio->write(cors.c_str(), cors.size()); } } int RGWPutCORS_ObjStore_S3::get_params() { int r; char *data = NULL; int len = 0; size_t cl = 0; RGWCORSXMLParser_S3 parser(s->cct); RGWCORSConfiguration_S3 *cors_config; if (s->length) cl = atoll(s->length); if (cl) { data = (char *)malloc(cl + 1); if (!data) { r = -ENOMEM; goto done_err; } int read_len; r = s->cio->read(data, cl, &read_len); len = read_len; if (r < 0) goto done_err; data[len] = '\0'; } else { len = 0; } if (!parser.init()) { r = -EINVAL; goto done_err; } if (!data || !parser.parse(data, len, 1)) { r = -EINVAL; goto done_err; } cors_config = static_cast(parser.find_first("CORSConfiguration")); if (!cors_config) { r = -EINVAL; goto done_err; } if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) { ldout(s->cct, 15) << "CORSConfiguration"; cors_config->to_xml(*_dout); *_dout << dendl; } cors_config->encode(cors_bl); free(data); return 0; done_err: free(data); return r; } void RGWPutCORS_ObjStore_S3::send_response() { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, NULL, "application/xml"); dump_start(s); } void RGWDeleteCORS_ObjStore_S3::send_response() { int r = ret; if (!r || r == -ENOENT) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, NULL); } void RGWOptionsCORS_ObjStore_S3::send_response() { string hdrs, exp_hdrs; uint32_t max_age = CORS_MAX_AGE_INVALID; /*EACCES means, there is no CORS registered yet for the bucket *ENOENT means, there is no match of the Origin in the list of CORSRule */ if (ret == -ENOENT) ret = -EACCES; if (ret < 0) { set_req_state_err(s, ret); dump_errno(s); end_header(s, NULL); return; } get_response_params(hdrs, exp_hdrs, &max_age); dump_errno(s); dump_access_control(s, origin, req_meth, hdrs.c_str(), exp_hdrs.c_str(), max_age); end_header(s, NULL); } int RGWInitMultipart_ObjStore_S3::get_params() { RGWAccessControlPolicy_S3 s3policy(s->cct); ret = create_s3_policy(s, store, s3policy, s->owner); if (ret < 0) return ret; policy = s3policy; return 0; } void RGWInitMultipart_ObjStore_S3::send_response() { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); if (ret == 0) { dump_start(s); s->formatter->open_object_section_in_ns("InitiateMultipartUploadResult", "http://s3.amazonaws.com/doc/2006-03-01/"); s->formatter->dump_string("Bucket", s->bucket_name_str); s->formatter->dump_string("Key", s->object); s->formatter->dump_string("UploadId", upload_id); s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } } void RGWCompleteMultipart_ObjStore_S3::send_response() { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); if (ret == 0) { dump_start(s); s->formatter->open_object_section_in_ns("CompleteMultipartUploadResult", "http://s3.amazonaws.com/doc/2006-03-01/"); if (g_conf->rgw_dns_name.length()) s->formatter->dump_format("Location", "%s.%s", s->bucket_name_str.c_str(), g_conf->rgw_dns_name.c_str()); s->formatter->dump_string("Bucket", s->bucket_name_str); s->formatter->dump_string("Key", s->object); s->formatter->dump_string("ETag", etag); s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } } void RGWAbortMultipart_ObjStore_S3::send_response() { int r = ret; if (!r) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, this); } void RGWListMultipart_ObjStore_S3::send_response() { if (ret) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); if (ret == 0) { dump_start(s); s->formatter->open_object_section_in_ns("ListMultipartUploadResult", "http://s3.amazonaws.com/doc/2006-03-01/"); map::iterator iter; map::reverse_iterator test_iter; int cur_max = 0; iter = parts.begin(); test_iter = parts.rbegin(); if (test_iter != parts.rend()) { cur_max = test_iter->first; } s->formatter->dump_string("Bucket", s->bucket_name_str); s->formatter->dump_string("Key", s->object); s->formatter->dump_string("UploadId", upload_id); s->formatter->dump_string("StorageClass", "STANDARD"); s->formatter->dump_int("PartNumberMarker", marker); s->formatter->dump_int("NextPartNumberMarker", cur_max); s->formatter->dump_int("MaxParts", max_parts); s->formatter->dump_string("IsTruncated", (truncated ? "true" : "false")); ACLOwner& owner = policy.get_owner(); dump_owner(s, owner.get_id(), owner.get_display_name()); for (; iter != parts.end(); ++iter) { RGWUploadPartInfo& info = iter->second; time_t sec = info.modified.sec(); struct tm tmp; gmtime_r(&sec, &tmp); char buf[TIME_BUF_SIZE]; s->formatter->open_object_section("Part"); if (strftime(buf, sizeof(buf), "%Y-%m-%dT%T.000Z", &tmp) > 0) { s->formatter->dump_string("LastModified", buf); } s->formatter->dump_unsigned("PartNumber", info.num); s->formatter->dump_string("ETag", info.etag); s->formatter->dump_unsigned("Size", info.size); s->formatter->close_section(); } s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } } void RGWListBucketMultiparts_ObjStore_S3::send_response() { if (ret < 0) set_req_state_err(s, ret); dump_errno(s); end_header(s, this, "application/xml"); dump_start(s); if (ret < 0) return; s->formatter->open_object_section("ListMultipartUploadsResult"); s->formatter->dump_string("Bucket", s->bucket_name_str); if (!prefix.empty()) s->formatter->dump_string("ListMultipartUploadsResult.Prefix", prefix); string& key_marker = marker.get_key(); if (!key_marker.empty()) s->formatter->dump_string("KeyMarker", key_marker); string& upload_id_marker = marker.get_upload_id(); if (!upload_id_marker.empty()) s->formatter->dump_string("UploadIdMarker", upload_id_marker); string next_key = next_marker.mp.get_key(); if (!next_key.empty()) s->formatter->dump_string("NextKeyMarker", next_key); string next_upload_id = next_marker.mp.get_upload_id(); if (!next_upload_id.empty()) s->formatter->dump_string("NextUploadIdMarker", next_upload_id); s->formatter->dump_int("MaxUploads", max_uploads); if (!delimiter.empty()) s->formatter->dump_string("Delimiter", delimiter); s->formatter->dump_string("IsTruncated", (is_truncated ? "true" : "false")); if (ret >= 0) { vector::iterator iter; for (iter = uploads.begin(); iter != uploads.end(); ++iter) { RGWMPObj& mp = iter->mp; s->formatter->open_array_section("Upload"); s->formatter->dump_string("Key", mp.get_key()); s->formatter->dump_string("UploadId", mp.get_upload_id()); dump_owner(s, s->user.user_id, s->user.display_name, "Initiator"); dump_owner(s, s->user.user_id, s->user.display_name); s->formatter->dump_string("StorageClass", "STANDARD"); time_t mtime = iter->obj.mtime.sec(); dump_time(s, "Initiated", &mtime); s->formatter->close_section(); } if (common_prefixes.size() > 0) { s->formatter->open_array_section("CommonPrefixes"); map::iterator pref_iter; for (pref_iter = common_prefixes.begin(); pref_iter != common_prefixes.end(); ++pref_iter) { s->formatter->dump_string("CommonPrefixes.Prefix", pref_iter->first); } s->formatter->close_section(); } } s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } void RGWDeleteMultiObj_ObjStore_S3::send_status() { if (!status_dumped) { if (ret < 0) set_req_state_err(s, ret); dump_errno(s); status_dumped = true; } } void RGWDeleteMultiObj_ObjStore_S3::begin_response() { if (!status_dumped) { send_status(); } dump_start(s); end_header(s, this, "application/xml"); s->formatter->open_object_section_in_ns("DeleteResult", "http://s3.amazonaws.com/doc/2006-03-01/"); rgw_flush_formatter(s, s->formatter); } void RGWDeleteMultiObj_ObjStore_S3::send_partial_response(pair& result) { if (!result.first.empty()) { if (result.second == 0 && !quiet) { s->formatter->open_object_section("Deleted"); s->formatter->dump_string("Key", result.first); s->formatter->close_section(); } else if (result.second < 0) { struct rgw_http_errors r; int err_no; s->formatter->open_object_section("Error"); err_no = -(result.second); rgw_get_errno_s3(&r, err_no); s->formatter->dump_string("Key", result.first); s->formatter->dump_int("Code", r.http_ret); s->formatter->dump_string("Message", r.s3_code); s->formatter->close_section(); } rgw_flush_formatter(s, s->formatter); } } void RGWDeleteMultiObj_ObjStore_S3::end_response() { s->formatter->close_section(); rgw_flush_formatter_and_reset(s, s->formatter); } RGWOp *RGWHandler_ObjStore_Service_S3::op_get() { return new RGWListBuckets_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Service_S3::op_head() { return new RGWListBuckets_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Bucket_S3::get_obj_op(bool get_data) { if (get_data) return new RGWListBucket_ObjStore_S3; else return new RGWStatBucket_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Bucket_S3::op_get() { if (s->info.args.sub_resource_exists("logging")) return new RGWGetBucketLogging_ObjStore_S3; if (is_acl_op()) { return new RGWGetACLs_ObjStore_S3; } else if (is_cors_op()) { return new RGWGetCORS_ObjStore_S3; } else if (s->info.args.exists("uploads")) { return new RGWListBucketMultiparts_ObjStore_S3; } return get_obj_op(true); } RGWOp *RGWHandler_ObjStore_Bucket_S3::op_head() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_S3; } else if (s->info.args.exists("uploads")) { return new RGWListBucketMultiparts_ObjStore_S3; } return get_obj_op(false); } RGWOp *RGWHandler_ObjStore_Bucket_S3::op_put() { if (s->info.args.sub_resource_exists("logging")) return NULL; if (is_acl_op()) { return new RGWPutACLs_ObjStore_S3; } else if (is_cors_op()) { return new RGWPutCORS_ObjStore_S3; } return new RGWCreateBucket_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Bucket_S3::op_delete() { if (is_cors_op()) { return new RGWDeleteCORS_ObjStore_S3; } return new RGWDeleteBucket_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Bucket_S3::op_post() { if ( s->info.request_params == "delete" ) { return new RGWDeleteMultiObj_ObjStore_S3; } return new RGWPostObj_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Bucket_S3::op_options() { return new RGWOptionsCORS_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Obj_S3::get_obj_op(bool get_data) { if (is_acl_op()) { return new RGWGetACLs_ObjStore_S3; } RGWGetObj_ObjStore_S3 *get_obj_op = new RGWGetObj_ObjStore_S3; get_obj_op->set_get_data(get_data); return get_obj_op; } RGWOp *RGWHandler_ObjStore_Obj_S3::op_get() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_S3; } else if (s->info.args.exists("uploadId")) { return new RGWListMultipart_ObjStore_S3; } return get_obj_op(true); } RGWOp *RGWHandler_ObjStore_Obj_S3::op_head() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_S3; } else if (s->info.args.exists("uploadId")) { return new RGWListMultipart_ObjStore_S3; } return get_obj_op(false); } RGWOp *RGWHandler_ObjStore_Obj_S3::op_put() { if (is_acl_op()) { return new RGWPutACLs_ObjStore_S3; } if (!s->copy_source) return new RGWPutObj_ObjStore_S3; else return new RGWCopyObj_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Obj_S3::op_delete() { string upload_id = s->info.args.get("uploadId"); if (upload_id.empty()) return new RGWDeleteObj_ObjStore_S3; else return new RGWAbortMultipart_ObjStore_S3; } RGWOp *RGWHandler_ObjStore_Obj_S3::op_post() { if (s->info.args.exists("uploadId")) return new RGWCompleteMultipart_ObjStore_S3; if (s->info.args.exists("uploads")) return new RGWInitMultipart_ObjStore_S3; return NULL; } RGWOp *RGWHandler_ObjStore_Obj_S3::op_options() { return new RGWOptionsCORS_ObjStore_S3; } int RGWHandler_ObjStore_S3::init_from_header(struct req_state *s, int default_formatter, bool configurable_format) { string req; string first; const char *req_name = s->relative_uri.c_str(); const char *p; if (*req_name == '?') { p = req_name; } else { p = s->info.request_params.c_str(); } s->info.args.set(p); s->info.args.parse(); /* must be called after the args parsing */ int ret = allocate_formatter(s, default_formatter, configurable_format); if (ret < 0) return ret; if (*req_name != '/') return 0; req_name++; if (!*req_name) return 0; req = req_name; int pos = req.find('/'); if (pos >= 0) { first = req.substr(0, pos); } else { first = req; } if (s->bucket_name_str.empty()) { s->bucket_name_str = first; if (pos >= 0) { string encoded_obj_str = req.substr(pos+1); s->object_str = encoded_obj_str; if (s->object_str.size() > 0) { s->object = strdup(s->object_str.c_str()); } } } else { s->object_str = req_name; s->object = strdup(s->object_str.c_str()); } return 0; } static bool looks_like_ip_address(const char *bucket) { int num_periods = 0; bool expect_period = false; for (const char *b = bucket; *b; ++b) { if (*b == '.') { if (!expect_period) return false; ++num_periods; if (num_periods > 3) return false; expect_period = false; } else if (isdigit(*b)) { expect_period = true; } else { return false; } } return (num_periods == 3); } int RGWHandler_ObjStore_S3::validate_bucket_name(const string& bucket, bool relaxed_names) { int ret = RGWHandler_ObjStore::validate_bucket_name(bucket); if (ret < 0) return ret; if (bucket.size() == 0) return 0; // bucket names must start with a number, letter, or underscore if (!(isalpha(bucket[0]) || isdigit(bucket[0]))) { if (!relaxed_names) return -ERR_INVALID_BUCKET_NAME; else if (!(bucket[0] == '_' || bucket[0] == '.' || bucket[0] == '-')) return -ERR_INVALID_BUCKET_NAME; } for (const char *s = bucket.c_str(); *s; ++s) { char c = *s; if (isdigit(c) || (c == '.')) continue; if (isalpha(c)) continue; if ((c == '-') || (c == '_')) continue; // Invalid character return -ERR_INVALID_BUCKET_NAME; } if (looks_like_ip_address(bucket.c_str())) return -ERR_INVALID_BUCKET_NAME; return 0; } int RGWHandler_ObjStore_S3::init(RGWRados *store, struct req_state *s, RGWClientIO *cio) { dout(10) << "s->object=" << (s->object ? s->object : "") << " s->bucket=" << (!s->bucket_name_str.empty() ? s->bucket_name_str : "") << dendl; bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names; int ret = validate_bucket_name(s->bucket_name_str, relaxed_names); if (ret) return ret; ret = validate_object_name(s->object_str); if (ret) return ret; const char *cacl = s->info.env->get("HTTP_X_AMZ_ACL"); if (cacl) s->canned_acl = cacl; s->has_acl_header = s->info.env->exists_prefix("HTTP_X_AMZ_GRANT"); s->copy_source = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE"); if (s->copy_source) { ret = RGWCopyObj::parse_copy_location(s->copy_source, s->src_bucket_name, s->src_object); if (!ret) { ldout(s->cct, 0) << "failed to parse copy location" << dendl; return -EINVAL; } } s->dialect = "s3"; return RGWHandler_ObjStore::init(store, s, cio); } /* * Try to validate S3 auth against keystone s3token interface */ int RGW_Auth_S3_Keystone_ValidateToken::validate_s3token(const string& auth_id, const string& auth_token, const string& auth_sign) { /* prepare keystone url */ string keystone_url = cct->_conf->rgw_keystone_url; if (keystone_url[keystone_url.size() - 1] != '/') keystone_url.append("/"); keystone_url.append("v2.0/s3tokens"); /* set required headers for keystone request */ append_header("X-Auth-Token", cct->_conf->rgw_keystone_admin_token); append_header("Content-Type", "application/json"); /* encode token */ bufferlist token_buff; bufferlist token_encoded; token_buff.append(auth_token); token_buff.encode_base64(token_encoded); token_encoded.append((char)0); /* create json credentials request body */ JSONFormatter credentials(false); credentials.open_object_section(""); credentials.open_object_section("credentials"); credentials.dump_string("access", auth_id); credentials.dump_string("token", token_encoded.c_str()); credentials.dump_string("signature", auth_sign); credentials.close_section(); credentials.close_section(); std::stringstream os; credentials.flush(os); set_tx_buffer(os.str()); /* send request */ int ret = process("POST", keystone_url.c_str()); if (ret < 0) { dout(2) << "s3 keystone: token validation ERROR: " << rx_buffer.c_str() << dendl; return -EPERM; } /* now parse response */ if (response.parse(cct, rx_buffer) < 0) { dout(2) << "s3 keystone: token parsing failed" << dendl; return -EPERM; } /* check if we have a valid role */ bool found = false; list::iterator iter; for (iter = roles_list.begin(); iter != roles_list.end(); ++iter) { if ((found=response.user.has_role(*iter))==true) break; } if (!found) { ldout(cct, 5) << "s3 keystone: user does not hold a matching role; required roles: " << cct->_conf->rgw_keystone_accepted_roles << dendl; return -EPERM; } /* everything seems fine, continue with this user */ ldout(cct, 5) << "s3 keystone: validated token: " << response.token.tenant.name << ":" << response.user.name << " expires: " << response.token.expires << dendl; return 0; } static void init_anon_user(struct req_state *s) { rgw_get_anon_user(s->user); s->perm_mask = RGW_PERM_FULL_CONTROL; } /* * verify that a signed request comes from the keyholder * by checking the signature against our locally-computed version */ int RGW_Auth_S3::authorize(RGWRados *store, struct req_state *s) { bool qsr = false; string auth_id; string auth_sign; time_t now; time(&now); /* neither keystone and rados enabled; warn and exit! */ if (!store->ctx()->_conf->rgw_s3_auth_use_rados && !store->ctx()->_conf->rgw_s3_auth_use_keystone) { dout(0) << "WARNING: no authorization backend enabled! Users will never authenticate." << dendl; return -EPERM; } if (s->op == OP_OPTIONS) { init_anon_user(s); return 0; } if (!s->http_auth || !(*s->http_auth)) { auth_id = s->info.args.get("AWSAccessKeyId"); if (auth_id.size()) { auth_sign = s->info.args.get("Signature"); string date = s->info.args.get("Expires"); time_t exp = atoll(date.c_str()); if (now >= exp) return -EPERM; qsr = true; } else { /* anonymous access */ init_anon_user(s); return 0; } } else { if (strncmp(s->http_auth, "AWS ", 4)) return -EINVAL; string auth_str(s->http_auth + 4); int pos = auth_str.find(':'); if (pos < 0) return -EINVAL; auth_id = auth_str.substr(0, pos); auth_sign = auth_str.substr(pos + 1); } /* try keystone auth first */ int keystone_result = -EINVAL; if (store->ctx()->_conf->rgw_s3_auth_use_keystone && !store->ctx()->_conf->rgw_keystone_url.empty()) { dout(20) << "s3 keystone: trying keystone auth" << dendl; RGW_Auth_S3_Keystone_ValidateToken keystone_validator(store->ctx()); string token; if (!rgw_create_s3_canonical_header(s->info, &s->header_time, token, qsr)) { dout(10) << "failed to create auth header\n" << token << dendl; } else { keystone_result = keystone_validator.validate_s3token(auth_id, token, auth_sign); if (keystone_result == 0) { // Check for time skew first time_t req_sec = s->header_time.sec(); if ((req_sec < now - RGW_AUTH_GRACE_MINS * 60 || req_sec > now + RGW_AUTH_GRACE_MINS * 60) && !qsr) { dout(10) << "req_sec=" << req_sec << " now=" << now << "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60 << "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60 << dendl; dout(0) << "NOTICE: request time skew too big now=" << utime_t(now, 0) << " req_time=" << s->header_time << dendl; return -ERR_REQUEST_TIME_SKEWED; } s->user.user_id = keystone_validator.response.token.tenant.id; s->user.display_name = keystone_validator.response.token.tenant.name; // wow. /* try to store user if it not already exists */ if (rgw_get_user_info_by_uid(store, keystone_validator.response.token.tenant.id, s->user) < 0) { int ret = rgw_store_user_info(store, s->user, NULL, NULL, 0, true); if (ret < 0) dout(10) << "NOTICE: failed to store new user's info: ret=" << ret << dendl; } s->perm_mask = RGW_PERM_FULL_CONTROL; } } } /* keystone failed (or not enabled); check if we want to use rados backend */ if (!store->ctx()->_conf->rgw_s3_auth_use_rados && keystone_result < 0) return keystone_result; /* now try rados backend, but only if keystone did not succeed */ if (keystone_result < 0) { /* get the user info */ if (rgw_get_user_info_by_access_key(store, auth_id, s->user) < 0) { dout(5) << "error reading user info, uid=" << auth_id << " can't authenticate" << dendl; return -EPERM; } /* now verify signature */ string auth_hdr; if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr, qsr)) { dout(10) << "failed to create auth header\n" << auth_hdr << dendl; return -EPERM; } dout(10) << "auth_hdr:\n" << auth_hdr << dendl; time_t req_sec = s->header_time.sec(); if ((req_sec < now - RGW_AUTH_GRACE_MINS * 60 || req_sec > now + RGW_AUTH_GRACE_MINS * 60) && !qsr) { dout(10) << "req_sec=" << req_sec << " now=" << now << "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60 << "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60 << dendl; dout(0) << "NOTICE: request time skew too big now=" << utime_t(now, 0) << " req_time=" << s->header_time << dendl; return -ERR_REQUEST_TIME_SKEWED; } map::iterator iter = s->user.access_keys.find(auth_id); if (iter == s->user.access_keys.end()) { dout(0) << "ERROR: access key not encoded in user info" << dendl; return -EPERM; } RGWAccessKey& k = iter->second; if (!k.subuser.empty()) { map::iterator uiter = s->user.subusers.find(k.subuser); if (uiter == s->user.subusers.end()) { dout(0) << "NOTICE: could not find subuser: " << k.subuser << dendl; return -EPERM; } RGWSubUser& subuser = uiter->second; s->perm_mask = subuser.perm_mask; } else s->perm_mask = RGW_PERM_FULL_CONTROL; string digest; int ret = rgw_get_s3_header_digest(auth_hdr, k.key, digest); if (ret < 0) { return -EPERM; } dout(15) << "calculated digest=" << digest << dendl; dout(15) << "auth_sign=" << auth_sign << dendl; dout(15) << "compare=" << auth_sign.compare(digest) << dendl; if (auth_sign != digest) return -EPERM; if (s->user.system) { s->system_request = true; dout(20) << "system request" << dendl; s->info.args.set_system(); string effective_uid = s->info.args.get(RGW_SYS_PARAM_PREFIX "uid"); RGWUserInfo effective_user; if (!effective_uid.empty()) { ret = rgw_get_user_info_by_uid(store, effective_uid, effective_user); if (ret < 0) { ldout(s->cct, 0) << "User lookup failed!" << dendl; return -ENOENT; } s->user = effective_user; } } } /* if keystone_result < 0 */ // populate the owner info s->owner.set_id(s->user.user_id); s->owner.set_name(s->user.display_name); return 0; } int RGWHandler_Auth_S3::init(RGWRados *store, struct req_state *state, RGWClientIO *cio) { int ret = RGWHandler_ObjStore_S3::init_from_header(state, RGW_FORMAT_JSON, true); if (ret < 0) return ret; return RGWHandler_ObjStore::init(store, state, cio); } RGWHandler *RGWRESTMgr_S3::get_handler(struct req_state *s) { int ret = RGWHandler_ObjStore_S3::init_from_header(s, RGW_FORMAT_XML, false); if (ret < 0) return NULL; if (s->bucket_name_str.empty()) return new RGWHandler_ObjStore_Service_S3; if (!s->object) return new RGWHandler_ObjStore_Bucket_S3; return new RGWHandler_ObjStore_Obj_S3; } ceph-0.80.11/src/rgw/rgw_jsonparser.cc0000664000175100017510000000534712623076744021650 0ustar jenkins-buildjenkins-build#include #include #include #include #include "include/types.h" #include "common/Formatter.h" #include "common/ceph_json.h" #include "rgw_common.h" #define dout_subsys ceph_subsys_rgw using namespace std; void dump_array(JSONObj *obj) { JSONObjIter iter = obj->find_first(); for (; !iter.end(); ++iter) { JSONObj *o = *iter; cout << "data=" << o->get_data() << std::endl; } } struct Key { string user; string access_key; string secret_key; void decode_json(JSONObj *obj) { JSONDecoder::decode_json("user", user, obj); JSONDecoder::decode_json("access_key", access_key, obj); JSONDecoder::decode_json("secret_key", secret_key, obj); } }; struct UserInfo { string uid; string display_name; int max_buckets; list keys; void decode_json(JSONObj *obj) { JSONDecoder::decode_json("user_id", uid, obj); JSONDecoder::decode_json("display_name", display_name, obj); JSONDecoder::decode_json("max_buckets", max_buckets, obj); JSONDecoder::decode_json("keys", keys, obj); } }; int main(int argc, char **argv) { JSONParser parser; char buf[1024]; bufferlist bl; for (;;) { int done; int len; len = fread(buf, 1, sizeof(buf), stdin); if (ferror(stdin)) { cerr << "read error" << std::endl; exit(-1); } done = feof(stdin); bool ret = parser.parse(buf, len); if (!ret) cerr << "parse error" << std::endl; if (done) { bl.append(buf, len); break; } } JSONObjIter iter = parser.find_first(); for (; !iter.end(); ++iter) { JSONObj *obj = *iter; cout << "is_object=" << obj->is_object() << std::endl; cout << "is_array=" << obj->is_array() << std::endl; cout << "name=" << obj->get_name() << std::endl; cout << "data=" << obj->get_data() << std::endl; } iter = parser.find_first("conditions"); if (!iter.end()) { JSONObj *obj = *iter; JSONObjIter iter2 = obj->find_first(); for (; !iter2.end(); ++iter2) { JSONObj *child = *iter2; cout << "is_object=" << child->is_object() << std::endl; cout << "is_array=" << child->is_array() << std::endl; if (child->is_array()) { dump_array(child); } cout << "name=" << child->get_name() < * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/page.h" #include "rgw_rest.h" #include "rgw_op.h" #include "rgw_rest_s3.h" #include "rgw_rest_metadata.h" #include "rgw_client_io.h" #include "common/errno.h" #include "common/strtol.h" #define dout_subsys ceph_subsys_rgw const string RGWOp_Metadata_Get::name() { return "get_metadata"; } static inline void frame_metadata_key(req_state *s, string& out) { bool exists; string key = s->info.args.get("key", &exists); string section; if (!s->bucket_name_str.empty()) { section = s->bucket_name_str; } else { section = key; key.clear(); } out = section; if (!key.empty()) { out += string(":") + key; } } void RGWOp_Metadata_Get::execute() { string metadata_key; frame_metadata_key(s, metadata_key); /* Get keys */ http_ret = store->meta_mgr->get(metadata_key, s->formatter); if (http_ret < 0) { dout(5) << "ERROR: can't get key: " << cpp_strerror(http_ret) << dendl; return; } http_ret = 0; } const string RGWOp_Metadata_List::name() { return "list_metadata"; } void RGWOp_Metadata_List::execute() { string metadata_key; frame_metadata_key(s, metadata_key); /* List keys */ void *handle; int max = 1000; http_ret = store->meta_mgr->list_keys_init(metadata_key, &handle); if (http_ret < 0) { dout(5) << "ERROR: can't get key: " << cpp_strerror(http_ret) << dendl; return; } bool truncated; s->formatter->open_array_section("keys"); do { list keys; http_ret = store->meta_mgr->list_keys_next(handle, max, keys, &truncated); if (http_ret < 0) { dout(5) << "ERROR: lists_keys_next(): " << cpp_strerror(http_ret) << dendl; return; } for (list::iterator iter = keys.begin(); iter != keys.end(); ++iter) { s->formatter->dump_string("key", *iter); } } while (truncated); s->formatter->close_section(); store->meta_mgr->list_keys_complete(handle); http_ret = 0; } int RGWOp_Metadata_Put::get_data(bufferlist& bl) { size_t cl = 0; char *data; int read_len; if (s->length) cl = atoll(s->length); if (cl) { data = (char *)malloc(cl + 1); if (!data) { return -ENOMEM; } int r = s->cio->read(data, cl, &read_len); if (cl != (size_t)read_len) { dout(10) << "cio->read incomplete" << dendl; } if (r < 0) { free(data); return r; } bl.append(data, read_len); } else { int chunk_size = CEPH_PAGE_SIZE; const char *enc = s->info.env->get("HTTP_TRANSFER_ENCODING"); if (!enc || strcmp(enc, "chunked")) { return -ERR_LENGTH_REQUIRED; } data = (char *)malloc(chunk_size); if (!data) { return -ENOMEM; } do { int r = s->cio->read(data, chunk_size, &read_len); if (r < 0) { free(data); return r; } bl.append(data, read_len); } while ((read_len == chunk_size)); } free(data); return 0; } void RGWOp_Metadata_Put::execute() { bufferlist bl; string metadata_key; http_ret = get_data(bl); if (http_ret < 0) { return; } frame_metadata_key(s, metadata_key); RGWMetadataHandler::sync_type_t sync_type = RGWMetadataHandler::APPLY_ALWAYS; bool mode_exists = false; string mode_string = s->info.args.get("update-type", &mode_exists); if (mode_exists) { bool parsed = RGWMetadataHandler::string_to_sync_type(mode_string, sync_type); if (!parsed) { http_ret = -EINVAL; return; } } http_ret = store->meta_mgr->put(metadata_key, bl, sync_type, &ondisk_version); if (http_ret < 0) { dout(5) << "ERROR: can't put key: " << cpp_strerror(http_ret) << dendl; return; } // translate internal codes into return header if (http_ret == STATUS_NO_APPLY) update_status = "skipped"; else if (http_ret == STATUS_APPLIED) update_status = "applied"; } void RGWOp_Metadata_Put::send_response() { int http_return_code = http_ret; if ((http_ret == STATUS_NO_APPLY) || (http_ret == STATUS_APPLIED)) http_return_code = STATUS_NO_CONTENT; set_req_state_err(s, http_return_code); dump_errno(s); stringstream ver_stream; ver_stream << "ver:" << ondisk_version.ver <<",tag:" << ondisk_version.tag; dump_pair(s, "RGWX_UPDATE_STATUS", update_status.c_str()); dump_pair(s, "RGWX_UPDATE_VERSION", ver_stream.str().c_str()); end_header(s); } void RGWOp_Metadata_Delete::execute() { string metadata_key; frame_metadata_key(s, metadata_key); http_ret = store->meta_mgr->remove(metadata_key); if (http_ret < 0) { dout(5) << "ERROR: can't remove key: " << cpp_strerror(http_ret) << dendl; return; } http_ret = 0; } void RGWOp_Metadata_Lock::execute() { string duration_str, lock_id; string metadata_key; frame_metadata_key(s, metadata_key); http_ret = 0; duration_str = s->info.args.get("length"); lock_id = s->info.args.get("lock_id"); if ((!s->info.args.exists("key")) || (duration_str.empty()) || lock_id.empty()) { dout(5) << "Error invalid parameter list" << dendl; http_ret = -EINVAL; return; } int dur; string err; dur = strict_strtol(duration_str.c_str(), 10, &err); if (!err.empty() || dur <= 0) { dout(5) << "invalid length param " << duration_str << dendl; http_ret = -EINVAL; return; } utime_t time(dur, 0); http_ret = store->meta_mgr->lock_exclusive(metadata_key, time, lock_id); if (http_ret == -EBUSY) http_ret = -ERR_LOCKED; } void RGWOp_Metadata_Unlock::execute() { string lock_id; string metadata_key; frame_metadata_key(s, metadata_key); http_ret = 0; lock_id = s->info.args.get("lock_id"); if ((!s->info.args.exists("key")) || lock_id.empty()) { dout(5) << "Error invalid parameter list" << dendl; http_ret = -EINVAL; return; } http_ret = store->meta_mgr->unlock(metadata_key, lock_id); } RGWOp *RGWHandler_Metadata::op_get() { if (s->info.args.exists("key")) return new RGWOp_Metadata_Get; else return new RGWOp_Metadata_List; } RGWOp *RGWHandler_Metadata::op_put() { return new RGWOp_Metadata_Put; } RGWOp *RGWHandler_Metadata::op_delete() { return new RGWOp_Metadata_Delete; } RGWOp *RGWHandler_Metadata::op_post() { if (s->info.args.exists("lock")) return new RGWOp_Metadata_Lock; else if (s->info.args.exists("unlock")) return new RGWOp_Metadata_Unlock; return NULL; } ceph-0.80.11/src/rgw/rgw_main.cc0000664000175100017510000007477512623076744020421 0ustar jenkins-buildjenkins-build#include #include #include #include #include #include #include #include #include #include #include "acconfig.h" #ifdef FASTCGI_INCLUDE_DIR # include "fastcgi/fcgiapp.h" #else # include "fcgiapp.h" #endif #include "rgw_fcgi.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "global/signal_handler.h" #include "common/config.h" #include "common/errno.h" #include "common/WorkQueue.h" #include "common/Timer.h" #include "common/Throttle.h" #include "common/safe_io.h" #include "include/str_list.h" #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_acl.h" #include "rgw_user.h" #include "rgw_op.h" #include "rgw_rest.h" #include "rgw_rest_s3.h" #include "rgw_rest_swift.h" #include "rgw_rest_admin.h" #include "rgw_rest_usage.h" #include "rgw_rest_user.h" #include "rgw_rest_bucket.h" #include "rgw_rest_metadata.h" #include "rgw_rest_log.h" #include "rgw_rest_opstate.h" #include "rgw_replica_log.h" #include "rgw_rest_replica_log.h" #include "rgw_rest_config.h" #include "rgw_swift_auth.h" #include "rgw_swift.h" #include "rgw_log.h" #include "rgw_tools.h" #include "rgw_resolve.h" #include "rgw_loadgen.h" #include "rgw_civetweb.h" #include "rgw_civetweb_log.h" #include "civetweb/civetweb.h" #include #include #include #include #include #include "include/types.h" #include "common/BackTrace.h" #define dout_subsys ceph_subsys_rgw using namespace std; static sig_t sighandler_alrm; class RGWProcess; static int signal_fd[2] = {0, 0}; static atomic_t disable_signal_fd; static void signal_shutdown(); #define SOCKET_BACKLOG 1024 struct RGWRequest { uint64_t id; struct req_state *s; string req_str; RGWOp *op; utime_t ts; RGWRequest(uint64_t id) : id(id), s(NULL), op(NULL) { } virtual ~RGWRequest() {} void init_state(req_state *_s) { s = _s; } void log_format(struct req_state *s, const char *fmt, ...) { #define LARGE_SIZE 1024 char buf[LARGE_SIZE]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); log(s, buf); } void log_init() { ts = ceph_clock_now(g_ceph_context); } void log(struct req_state *s, const char *msg) { if (s->info.method && req_str.size() == 0) { req_str = s->info.method; req_str.append(" "); req_str.append(s->info.request_uri); } utime_t t = ceph_clock_now(g_ceph_context) - ts; dout(2) << "req " << id << ":" << t << ":" << s->dialect << ":" << req_str << ":" << (op ? op->name() : "") << ":" << msg << dendl; } }; class RGWFrontendConfig { string config; map config_map; int parse_config(const string& config, map& config_map); string framework; public: RGWFrontendConfig(const string& _conf) : config(_conf) {} int init() { int ret = parse_config(config, config_map); if (ret < 0) return ret; return 0; } bool get_val(const string& key, const string& def_val, string *out); bool get_val(const string& key, int def_val, int *out); map& get_config_map() { return config_map; } string get_framework() { return framework; } }; struct RGWFCGXRequest : public RGWRequest { FCGX_Request fcgx; RGWFCGXRequest(uint64_t req_id) : RGWRequest(req_id) {} }; struct RGWProcessEnv { RGWRados *store; RGWREST *rest; OpsLogSocket *olog; int port; }; class RGWProcess { deque m_req_queue; protected: RGWRados *store; OpsLogSocket *olog; ThreadPool m_tp; Throttle req_throttle; RGWREST *rest; RGWFrontendConfig *conf; int sock_fd; struct RGWWQ : public ThreadPool::WorkQueue { RGWProcess *process; RGWWQ(RGWProcess *p, time_t timeout, time_t suicide_timeout, ThreadPool *tp) : ThreadPool::WorkQueue("RGWWQ", timeout, suicide_timeout, tp), process(p) {} bool _enqueue(RGWRequest *req) { process->m_req_queue.push_back(req); perfcounter->inc(l_rgw_qlen); dout(20) << "enqueued request req=" << hex << req << dec << dendl; _dump_queue(); return true; } void _dequeue(RGWRequest *req) { assert(0); } bool _empty() { return process->m_req_queue.empty(); } RGWRequest *_dequeue() { if (process->m_req_queue.empty()) return NULL; RGWRequest *req = process->m_req_queue.front(); process->m_req_queue.pop_front(); dout(20) << "dequeued request req=" << hex << req << dec << dendl; _dump_queue(); perfcounter->inc(l_rgw_qlen, -1); return req; } void _process(RGWRequest *req) { perfcounter->inc(l_rgw_qactive); process->handle_request(req); process->req_throttle.put(1); perfcounter->inc(l_rgw_qactive, -1); } void _dump_queue() { deque::iterator iter; if (process->m_req_queue.empty()) { dout(20) << "RGWWQ: empty" << dendl; return; } dout(20) << "RGWWQ:" << dendl; for (iter = process->m_req_queue.begin(); iter != process->m_req_queue.end(); ++iter) { dout(20) << "req: " << hex << *iter << dec << dendl; } } void _clear() { assert(process->m_req_queue.empty()); } } req_wq; public: RGWProcess(CephContext *cct, RGWProcessEnv *pe, int num_threads, RGWFrontendConfig *_conf) : store(pe->store), olog(pe->olog), m_tp(cct, "RGWProcess::m_tp", num_threads), req_throttle(cct, "rgw_ops", num_threads * 2), rest(pe->rest), conf(_conf), sock_fd(-1), req_wq(this, g_conf->rgw_op_thread_timeout, g_conf->rgw_op_thread_suicide_timeout, &m_tp) {} virtual ~RGWProcess() {} virtual void run() = 0; virtual void handle_request(RGWRequest *req) = 0; void close_fd() { if (sock_fd >= 0) { ::close(sock_fd); sock_fd = -1; } } }; class RGWFCGXProcess : public RGWProcess { public: RGWFCGXProcess(CephContext *cct, RGWProcessEnv *pe, int num_threads, RGWFrontendConfig *_conf) : RGWProcess(cct, pe, num_threads, _conf) {} void run(); void handle_request(RGWRequest *req); }; void RGWFCGXProcess::run() { string socket_path; string socket_port; string socket_host; conf->get_val("socket_path", "", &socket_path); conf->get_val("socket_port", g_conf->rgw_port, &socket_port); conf->get_val("socket_host", g_conf->rgw_host, &socket_host); if (socket_path.empty() && socket_port.empty() && socket_host.empty()) { socket_path = g_conf->rgw_socket_path; if (socket_path.empty()) { dout(0) << "ERROR: no socket server point defined, cannot start fcgi frontend" << dendl; return; } } if (!socket_path.empty()) { string path_str = socket_path; /* this is necessary, as FCGX_OpenSocket might not return an error, but rather ungracefully exit */ int fd = open(path_str.c_str(), O_CREAT, 0644); if (fd < 0) { int err = errno; /* ENXIO is actually expected, we'll get that if we try to open a unix domain socket */ if (err != ENXIO) { dout(0) << "ERROR: cannot create socket: path=" << path_str << " error=" << cpp_strerror(err) << dendl; return; } } else { close(fd); } const char *path = path_str.c_str(); sock_fd = FCGX_OpenSocket(path, SOCKET_BACKLOG); if (sock_fd < 0) { dout(0) << "ERROR: FCGX_OpenSocket (" << path << ") returned " << sock_fd << dendl; return; } if (chmod(path, 0777) < 0) { dout(0) << "WARNING: couldn't set permissions on unix domain socket" << dendl; } } else if (!socket_port.empty()) { string bind = socket_host + ":" + socket_port; sock_fd = FCGX_OpenSocket(bind.c_str(), SOCKET_BACKLOG); if (sock_fd < 0) { dout(0) << "ERROR: FCGX_OpenSocket (" << bind.c_str() << ") returned " << sock_fd << dendl; return; } } m_tp.start(); for (;;) { RGWFCGXRequest *req = new RGWFCGXRequest(store->get_new_req_id()); dout(10) << "allocated request req=" << hex << req << dec << dendl; FCGX_InitRequest(&req->fcgx, sock_fd, 0); req_throttle.get(1); int ret = FCGX_Accept_r(&req->fcgx); if (ret < 0) { delete req; dout(0) << "ERROR: FCGX_Accept_r returned " << ret << dendl; req_throttle.put(1); break; } req_wq.queue(req); } m_tp.drain(&req_wq); m_tp.stop(); } struct RGWLoadGenRequest : public RGWRequest { string method; string resource; int content_length; atomic_t *fail_flag; RGWLoadGenRequest(uint64_t req_id, const string& _m, const string& _r, int _cl, atomic_t *ff) : RGWRequest(req_id), method(_m), resource(_r), content_length(_cl), fail_flag(ff) {} }; class RGWLoadGenProcess : public RGWProcess { RGWAccessKey access_key; public: RGWLoadGenProcess(CephContext *cct, RGWProcessEnv *pe, int num_threads, RGWFrontendConfig *_conf) : RGWProcess(cct, pe, num_threads, _conf) {} void run(); void checkpoint(); void handle_request(RGWRequest *req); void gen_request(const string& method, const string& resource, int content_length, atomic_t *fail_flag); void set_access_key(RGWAccessKey& key) { access_key = key; } }; void RGWLoadGenProcess::checkpoint() { m_tp.drain(&req_wq); } void RGWLoadGenProcess::run() { m_tp.start(); /* start thread pool */ int i; int num_objs; conf->get_val("num_objs", 1000, &num_objs); int num_buckets; conf->get_val("num_buckets", 1, &num_buckets); vector buckets(num_buckets); atomic_t failed; for (i = 0; i < num_buckets; i++) { buckets[i] = "/loadgen"; string& bucket = buckets[i]; append_rand_alpha(NULL, bucket, bucket, 16); /* first create a bucket */ gen_request("PUT", bucket, 0, &failed); checkpoint(); } string *objs = new string[num_objs]; if (failed.read()) { derr << "ERROR: bucket creation failed" << dendl; goto done; } for (i = 0; i < num_objs; i++) { char buf[16 + 1]; gen_rand_alphanumeric(NULL, buf, sizeof(buf)); buf[16] = '\0'; objs[i] = buckets[i % num_buckets] + "/" + buf; } for (i = 0; i < num_objs; i++) { gen_request("PUT", objs[i], 4096, &failed); } checkpoint(); if (failed.read()) { derr << "ERROR: bucket creation failed" << dendl; goto done; } for (i = 0; i < num_objs; i++) { gen_request("GET", objs[i], 4096, NULL); } checkpoint(); for (i = 0; i < num_objs; i++) { gen_request("DELETE", objs[i], 0, NULL); } checkpoint(); for (i = 0; i < num_buckets; i++) { gen_request("DELETE", buckets[i], 0, NULL); } done: checkpoint(); m_tp.stop(); delete[] objs; signal_shutdown(); } void RGWLoadGenProcess::gen_request(const string& method, const string& resource, int content_length, atomic_t *fail_flag) { RGWLoadGenRequest *req = new RGWLoadGenRequest(store->get_new_req_id(), method, resource, content_length, fail_flag); dout(10) << "allocated request req=" << hex << req << dec << dendl; req_throttle.get(1); req_wq.queue(req); } static void signal_shutdown() { if (!disable_signal_fd.read()) { int val = 0; int ret = write(signal_fd[0], (char *)&val, sizeof(val)); if (ret < 0) { int err = -errno; derr << "ERROR: " << __func__ << ": write() returned " << cpp_strerror(-err) << dendl; } } } static void wait_shutdown() { int val; int r = safe_read_exact(signal_fd[1], &val, sizeof(val)); if (r < 0) { derr << "safe_read_exact returned with error" << dendl; } } int signal_fd_init() { return socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fd); } static void signal_fd_finalize() { close(signal_fd[0]); close(signal_fd[1]); } static void handle_sigterm(int signum) { dout(1) << __func__ << dendl; FCGX_ShutdownPending(); // send a signal to make fcgi's accept(2) wake up. unfortunately the // initial signal often isn't sufficient because we race with accept's // check of the flag wet by ShutdownPending() above. if (signum != SIGUSR1) { signal_shutdown(); // safety net in case we get stuck doing an orderly shutdown. uint64_t secs = g_ceph_context->_conf->rgw_exit_timeout_secs; if (secs) alarm(secs); dout(1) << __func__ << " set alarm for " << secs << dendl; } } static void godown_alarm(int signum) { _exit(0); } static int call_log_intent(RGWRados *store, void *ctx, rgw_obj& obj, RGWIntentEvent intent) { struct req_state *s = (struct req_state *)ctx; return rgw_log_intent(store, s, obj, intent); } static int process_request(RGWRados *store, RGWREST *rest, RGWRequest *req, RGWClientIO *client_io, OpsLogSocket *olog) { int ret = 0; client_io->init(g_ceph_context); req->log_init(); dout(1) << "====== starting new request req=" << hex << req << dec << " =====" << dendl; perfcounter->inc(l_rgw_req); RGWEnv& rgw_env = client_io->get_env(); struct req_state rstate(g_ceph_context, &rgw_env); struct req_state *s = &rstate; RGWRadosCtx rados_ctx(store, s); s->obj_ctx = &rados_ctx; store->set_intent_cb(s->obj_ctx, call_log_intent); s->req_id = store->unique_id(req->id); req->log(s, "initializing"); RGWOp *op = NULL; int init_error = 0; bool should_log = false; RGWRESTMgr *mgr; RGWHandler *handler = rest->get_handler(store, s, client_io, &mgr, &init_error); if (init_error != 0) { abort_early(s, NULL, init_error); goto done; } should_log = mgr->get_logging(); req->log(s, "getting op"); op = handler->get_op(store); if (!op) { abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED); goto done; } req->op = op; req->log(s, "authorizing"); ret = handler->authorize(); if (ret < 0) { dout(10) << "failed to authorize request" << dendl; abort_early(s, op, ret); goto done; } if (s->user.suspended) { dout(10) << "user is suspended, uid=" << s->user.user_id << dendl; abort_early(s, op, -ERR_USER_SUSPENDED); goto done; } req->log(s, "reading permissions"); ret = handler->read_permissions(op); if (ret < 0) { abort_early(s, op, ret); goto done; } req->log(s, "init op"); ret = op->init_processing(); if (ret < 0) { abort_early(s, op, ret); goto done; } req->log(s, "verifying op mask"); ret = op->verify_op_mask(); if (ret < 0) { abort_early(s, op, ret); goto done; } req->log(s, "verifying op permissions"); ret = op->verify_permission(); if (ret < 0) { if (s->system_request) { dout(2) << "overriding permissions due to system operation" << dendl; } else { abort_early(s, op, ret); goto done; } } req->log(s, "verifying op params"); ret = op->verify_params(); if (ret < 0) { abort_early(s, op, ret); goto done; } req->log(s, "executing"); op->pre_exec(); op->execute(); op->complete(); done: int r = client_io->complete_request(); if (r < 0) { dout(0) << "ERROR: client_io->complete_request() returned " << r << dendl; } if (should_log) { rgw_log_op(store, s, (op ? op->name() : "unknown"), olog); } int http_ret = s->err.http_ret; req->log_format(s, "http status=%d", http_ret); if (handler) handler->put_op(op); rest->put_handler(handler); dout(1) << "====== req done req=" << hex << req << dec << " http_status=" << http_ret << " ======" << dendl; return (ret < 0 ? ret : s->err.ret); } void RGWFCGXProcess::handle_request(RGWRequest *r) { RGWFCGXRequest *req = static_cast(r); FCGX_Request *fcgx = &req->fcgx; RGWFCGX client_io(fcgx); int ret = process_request(store, rest, req, &client_io, olog); if (ret < 0) { /* we don't really care about return code */ dout(20) << "process_request() returned " << ret << dendl; } FCGX_Finish_r(fcgx); if (store->ctx()->_conf->rgw_fcgi_explicit_free) { FCGX_Free(fcgx, 1); } delete req; } void RGWLoadGenProcess::handle_request(RGWRequest *r) { RGWLoadGenRequest *req = static_cast(r); RGWLoadGenRequestEnv env; utime_t tm = ceph_clock_now(NULL); env.port = 80; env.content_length = req->content_length; env.content_type = "binary/octet-stream"; env.request_method = req->method; env.uri = req->resource; env.set_date(tm); env.sign(access_key); RGWLoadGenIO client_io(&env); int ret = process_request(store, rest, req, &client_io, olog); if (ret < 0) { /* we don't really care about return code */ dout(20) << "process_request() returned " << ret << dendl; if (req->fail_flag) { req->fail_flag->inc(); } } delete req; } static int civetweb_callback(struct mg_connection *conn) { struct mg_request_info *req_info = mg_get_request_info(conn); RGWProcessEnv *pe = (RGWProcessEnv *)req_info->user_data; RGWRados *store = pe->store; RGWREST *rest = pe->rest; OpsLogSocket *olog = pe->olog; RGWRequest *req = new RGWRequest(store->get_new_req_id()); RGWMongoose client_io(conn, pe->port); client_io.init(g_ceph_context); int ret = process_request(store, rest, req, &client_io, olog); if (ret < 0) { /* we don't really care about return code */ dout(20) << "process_request() returned " << ret << dendl; } delete req; // Mark as processed return 1; } #ifdef HAVE_CURL_MULTI_WAIT static void check_curl() { } #else static void check_curl() { derr << "WARNING: libcurl doesn't support curl_multi_wait()" << dendl; derr << "WARNING: cross zone / region transfer performance may be affected" << dendl; } #endif class C_InitTimeout : public Context { public: C_InitTimeout() {} void finish(int r) { derr << "Initialization timeout, failed to initialize" << dendl; exit(1); } }; int usage() { cerr << "usage: radosgw [options...]" << std::endl; cerr << "options:\n"; cerr << " --rgw-region= region in which radosgw runs\n"; cerr << " --rgw-zone= zone in which radosgw runs\n"; generic_server_usage(); return 0; } static RGWRESTMgr *set_logging(RGWRESTMgr *mgr) { mgr->set_logging(true); return mgr; } int RGWFrontendConfig::parse_config(const string& config, map& config_map) { list config_list; get_str_list(config, " ", config_list); list::iterator iter; for (iter = config_list.begin(); iter != config_list.end(); ++iter) { string& entry = *iter; string key; string val; if (framework.empty()) { framework = entry; dout(0) << "framework: " << framework << dendl; continue; } ssize_t pos = entry.find('='); if (pos < 0) { dout(0) << "framework conf key: " << entry << dendl; config_map[entry] = ""; continue; } int ret = parse_key_value(entry, key, val); if (ret < 0) { cerr << "ERROR: can't parse " << entry << std::endl; return ret; } dout(0) << "framework conf key: " << key << ", val: " << val << dendl; config_map[key] = val; } return 0; } bool RGWFrontendConfig::get_val(const string& key, const string& def_val, string *out) { map::iterator iter = config_map.find(key); if (iter == config_map.end()) { *out = def_val; return false; } *out = iter->second; return true; } bool RGWFrontendConfig::get_val(const string& key, int def_val, int *out) { string str; bool found = get_val(key, "", &str); if (!found) { *out = def_val; return false; } string err; *out = strict_strtol(str.c_str(), 10, &err); if (!err.empty()) { cerr << "error parsing int: " << str << ": " << err << std::endl; return -EINVAL; } return 0; } class RGWFrontend { public: virtual ~RGWFrontend() {} virtual int init() = 0; virtual int run() = 0; virtual void stop() = 0; virtual void join() = 0; }; class RGWProcessControlThread : public Thread { RGWProcess *pprocess; public: RGWProcessControlThread(RGWProcess *_pprocess) : pprocess(_pprocess) {} void *entry() { pprocess->run(); return NULL; }; }; class RGWProcessFrontend : public RGWFrontend { protected: RGWFrontendConfig *conf; RGWProcess *pprocess; RGWProcessEnv env; RGWProcessControlThread *thread; public: RGWProcessFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : conf(_conf), pprocess(NULL), env(pe), thread(NULL) { } ~RGWProcessFrontend() { delete thread; delete pprocess; } int run() { assert(pprocess); /* should have initialized by init() */ thread = new RGWProcessControlThread(pprocess); thread->create(); return 0; } void stop() { pprocess->close_fd(); thread->kill(SIGUSR1); } void join() { thread->join(); } }; class RGWFCGXFrontend : public RGWProcessFrontend { public: RGWFCGXFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : RGWProcessFrontend(pe, _conf) {} int init() { pprocess = new RGWFCGXProcess(g_ceph_context, &env, g_conf->rgw_thread_pool_size, conf); return 0; } }; class RGWLoadGenFrontend : public RGWProcessFrontend { public: RGWLoadGenFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : RGWProcessFrontend(pe, _conf) {} int init() { int num_threads; conf->get_val("num_threads", g_conf->rgw_thread_pool_size, &num_threads); RGWLoadGenProcess *pp = new RGWLoadGenProcess(g_ceph_context, &env, num_threads, conf); pprocess = pp; string uid; conf->get_val("uid", "", &uid); if (uid.empty()) { derr << "ERROR: uid param must be specified for loadgen frontend" << dendl; return EINVAL; } RGWUserInfo user_info; int ret = rgw_get_user_info_by_uid(env.store, uid, user_info, NULL); if (ret < 0) { derr << "ERROR: failed reading user info: uid=" << uid << " ret=" << ret << dendl; return ret; } map::iterator aiter = user_info.access_keys.begin(); if (aiter == user_info.access_keys.end()) { derr << "ERROR: user has no S3 access keys set" << dendl; return -EINVAL; } pp->set_access_key(aiter->second); return 0; } }; class RGWMongooseFrontend : public RGWFrontend { RGWFrontendConfig *conf; struct mg_context *ctx; RGWProcessEnv env; void set_conf_default(map& m, const string& key, const string& def_val) { if (m.find(key) == m.end()) { m[key] = def_val; } } public: RGWMongooseFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : conf(_conf), ctx(NULL), env(pe) { } int init() { return 0; } int run() { char thread_pool_buf[32]; snprintf(thread_pool_buf, sizeof(thread_pool_buf), "%d", (int)g_conf->rgw_thread_pool_size); string port_str; map conf_map = conf->get_config_map(); conf->get_val("port", "80", &port_str); conf_map.erase("port"); conf_map["listening_ports"] = port_str; set_conf_default(conf_map, "enable_keep_alive", "yes"); set_conf_default(conf_map, "num_threads", thread_pool_buf); set_conf_default(conf_map, "decode_url", "no"); const char *options[conf_map.size() * 2 + 1]; int i = 0; for (map::iterator iter = conf_map.begin(); iter != conf_map.end(); ++iter) { options[i] = iter->first.c_str(); options[i + 1] = iter->second.c_str(); dout(20)<< "civetweb config: " << options[i] << ": " << (options[i + 1] ? options[i + 1] : "") << dendl; i += 2; } options[i] = NULL; struct mg_callbacks cb; memset((void *)&cb, 0, sizeof(cb)); cb.begin_request = civetweb_callback; cb.log_message = rgw_civetweb_log_callback; ctx = mg_start(&cb, &env, (const char **)&options); if (!ctx) { return -EIO; } return 0; } void stop() { if (ctx) { mg_stop(ctx); } } void join() { } }; /* * start up the RADOS connection and then handle HTTP messages as they come in */ int main(int argc, const char **argv) { // dout() messages will be sent to stderr, but FCGX wants messages on stdout // Redirect stderr to stdout. TEMP_FAILURE_RETRY(close(STDERR_FILENO)); if (TEMP_FAILURE_RETRY(dup2(STDOUT_FILENO, STDERR_FILENO) < 0)) { int err = errno; cout << "failed to redirect stderr to stdout: " << cpp_strerror(err) << std::endl; return ENOSYS; } /* alternative default for module */ vector def_args; def_args.push_back("--debug-rgw=1/5"); def_args.push_back("--keyring=$rgw_data/keyring"); def_args.push_back("--log-file=/var/log/radosgw/$cluster-$name.log"); vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_DAEMON, CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS); for (std::vector::iterator i = args.begin(); i != args.end(); ++i) { if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); return 0; } } check_curl(); if (g_conf->daemonize) { global_init_daemonize(g_ceph_context, 0); } Mutex mutex("main"); SafeTimer init_timer(g_ceph_context, mutex); init_timer.init(); mutex.Lock(); init_timer.add_event_after(g_conf->rgw_init_timeout, new C_InitTimeout); mutex.Unlock(); common_init_finish(g_ceph_context); rgw_tools_init(g_ceph_context); rgw_init_resolver(); rgw_rest_init(g_ceph_context); curl_global_init(CURL_GLOBAL_ALL); FCGX_Init(); int r = 0; RGWRados *store = RGWStoreManager::get_storage(g_ceph_context, true, true); if (!store) { derr << "Couldn't init storage provider (RADOS)" << dendl; r = EIO; } if (!r) r = rgw_perf_start(g_ceph_context); mutex.Lock(); init_timer.cancel_all_events(); init_timer.shutdown(); mutex.Unlock(); if (r) return 1; rgw_user_init(store->meta_mgr); rgw_bucket_init(store->meta_mgr); rgw_log_usage_init(g_ceph_context, store); RGWREST rest; list apis; bool do_swift = false; get_str_list(g_conf->rgw_enable_apis, apis); map apis_map; for (list::iterator li = apis.begin(); li != apis.end(); ++li) { apis_map[*li] = true; } if (apis_map.count("s3") > 0) rest.register_default_mgr(set_logging(new RGWRESTMgr_S3)); if (apis_map.count("swift") > 0) { do_swift = true; swift_init(g_ceph_context); rest.register_resource(g_conf->rgw_swift_url_prefix, set_logging(new RGWRESTMgr_SWIFT)); } if (apis_map.count("swift_auth") > 0) rest.register_resource(g_conf->rgw_swift_auth_entry, set_logging(new RGWRESTMgr_SWIFT_Auth)); if (apis_map.count("admin") > 0) { RGWRESTMgr_Admin *admin_resource = new RGWRESTMgr_Admin; admin_resource->register_resource("usage", new RGWRESTMgr_Usage); admin_resource->register_resource("user", new RGWRESTMgr_User); admin_resource->register_resource("bucket", new RGWRESTMgr_Bucket); /*Registering resource for /admin/metadata */ admin_resource->register_resource("metadata", new RGWRESTMgr_Metadata); admin_resource->register_resource("log", new RGWRESTMgr_Log); admin_resource->register_resource("opstate", new RGWRESTMgr_Opstate); admin_resource->register_resource("replica_log", new RGWRESTMgr_ReplicaLog); admin_resource->register_resource("config", new RGWRESTMgr_Config); rest.register_resource(g_conf->rgw_admin_entry, admin_resource); } OpsLogSocket *olog = NULL; if (!g_conf->rgw_ops_log_socket_path.empty()) { olog = new OpsLogSocket(g_ceph_context, g_conf->rgw_ops_log_data_backlog); olog->init(g_conf->rgw_ops_log_socket_path); } r = signal_fd_init(); if (r < 0) { derr << "ERROR: unable to initialize signal fds" << dendl; exit(1); } init_async_signal_handler(); register_async_signal_handler(SIGHUP, sighup_handler); register_async_signal_handler(SIGTERM, handle_sigterm); register_async_signal_handler(SIGINT, handle_sigterm); register_async_signal_handler(SIGUSR1, handle_sigterm); sighandler_alrm = signal(SIGALRM, godown_alarm); string frontend_frameworks = g_conf->rgw_frontends; list frontends; get_str_list(g_conf->rgw_frontends, ",", frontends); multimap fe_map; list configs; if (frontends.empty()) { frontends.push_back("fastcgi"); } for (list::iterator iter = frontends.begin(); iter != frontends.end(); ++iter) { string& f = *iter; RGWFrontendConfig *config = new RGWFrontendConfig(f); int r = config->init(); if (r < 0) { cerr << "ERROR: failed to init config: " << f << std::endl; return EINVAL; } configs.push_back(config); string framework = config->get_framework(); fe_map.insert(make_pair(framework, config)); } list fes; for (multimap::iterator fiter = fe_map.begin(); fiter != fe_map.end(); ++fiter) { RGWFrontendConfig *config = fiter->second; string framework = config->get_framework(); RGWFrontend *fe; if (framework == "fastcgi" || framework == "fcgi") { RGWProcessEnv fcgi_pe = { store, &rest, olog, 0 }; fe = new RGWFCGXFrontend(fcgi_pe, config); } else if (framework == "civetweb" || framework == "mongoose") { string err; int port; config->get_val("port", 80, &port); RGWProcessEnv env = { store, &rest, olog, port }; fe = new RGWMongooseFrontend(env, config); } else if (framework == "loadgen") { int port; config->get_val("port", 80, &port); RGWProcessEnv env = { store, &rest, olog, port }; fe = new RGWLoadGenFrontend(env, config); } else { dout(0) << "WARNING: skipping unknown framework: " << framework << dendl; continue; } dout(0) << "starting handler: " << fiter->first << dendl; int r = fe->init(); if (r < 0) { derr << "ERROR: failed initializing frontend" << dendl; return -r; } fe->run(); fes.push_back(fe); } wait_shutdown(); derr << "shutting down" << dendl; for (list::iterator liter = fes.begin(); liter != fes.end(); ++liter) { RGWFrontend *fe = *liter; fe->stop(); } for (list::iterator liter = fes.begin(); liter != fes.end(); ++liter) { RGWFrontend *fe = *liter; fe->join(); delete fe; } for (list::iterator liter = configs.begin(); liter != configs.end(); ++liter) { RGWFrontendConfig *fec = *liter; delete fec; } unregister_async_signal_handler(SIGHUP, sighup_handler); unregister_async_signal_handler(SIGTERM, handle_sigterm); unregister_async_signal_handler(SIGINT, handle_sigterm); unregister_async_signal_handler(SIGUSR1, handle_sigterm); shutdown_async_signal_handler(); if (do_swift) { swift_finalize(); } rgw_log_usage_finalize(); delete olog; rgw_perf_stop(g_ceph_context); RGWStoreManager::close_storage(store); rgw_tools_cleanup(); rgw_shutdown_resolver(); curl_global_cleanup(); dout(1) << "final shutdown" << dendl; g_ceph_context->put(); ceph::crypto::shutdown(); signal_fd_finalize(); return 0; } ceph-0.80.11/src/rgw/rgw_policy_s3.h0000664000175100017510000000264112623076744021222 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_POLICY_H #define CEPH_RGW_POLICY_H #include #include #include #include #include "include/utime.h" #include "rgw_string.h" class RGWPolicyEnv { std::map vars; public: void add_var(const string& name, const string& value); bool get_var(const string& name, string& val); bool get_value(const string& s, string& val, std::map& checked_vars); bool match_policy_vars(map& policy_vars, string& err_msg); }; class RGWPolicyCondition; class RGWPolicy { uint64_t expires; string expiration_str; std::list conditions; std::list > var_checks; std::map checked_vars; public: off_t min_length; off_t max_length; RGWPolicy() : expires(0), min_length(0), max_length(LLONG_MAX) {} ~RGWPolicy(); int set_expires(const string& e); void set_var_checked(const std::string& var) { checked_vars[var] = true; } int add_condition(const std::string& op, const std::string& first, const std::string& second, string& err_msg); void add_simple_check(const std::string& var, const std::string& value) { var_checks.push_back(pair(var, value)); } int check(RGWPolicyEnv *env, string& err_msg); int from_json(bufferlist& bl, string& err_msg); }; #endif ceph-0.80.11/src/rgw/rgw_civetweb_log.cc0000664000175100017510000000044612623076744022126 0ustar jenkins-buildjenkins-build#include "common/config.h" #include "rgw_common.h" #include "civetweb/civetweb.h" #define dout_subsys ceph_subsys_civetweb int rgw_civetweb_log_callback(const struct mg_connection *conn, const char *buf) { dout(10) << "civetweb: " << (void *)conn << ": " << buf << dendl; return 0; } ceph-0.80.11/src/rgw/rgw_policy_s3.cc0000664000175100017510000001724412623076744021365 0ustar jenkins-buildjenkins-build #include #include "common/ceph_json.h" #include "rgw_policy_s3.h" #include "rgw_common.h" #define dout_subsys ceph_subsys_rgw class RGWPolicyCondition { protected: string v1; string v2; virtual bool check(const string& first, const string& second, string& err_msg) = 0; public: virtual ~RGWPolicyCondition() {} void set_vals(const string& _v1, const string& _v2) { v1 = _v1; v2 = _v2; } bool check(RGWPolicyEnv *env, map& checked_vars, string& err_msg) { string first, second; env->get_value(v1, first, checked_vars); env->get_value(v2, second, checked_vars); dout(1) << "policy condition check " << v1 << " [" << first << "] " << v2 << " [" << second << "]" << dendl; bool ret = check(first, second, err_msg); if (!ret) { err_msg.append(": "); err_msg.append(v1); err_msg.append(", "); err_msg.append(v2); } return ret; } }; class RGWPolicyCondition_StrEqual : public RGWPolicyCondition { protected: bool check(const string& first, const string& second, string& msg) { bool ret = first.compare(second) == 0; if (!ret) { msg = "Policy condition failed: eq"; } return ret; } }; class RGWPolicyCondition_StrStartsWith : public RGWPolicyCondition { protected: bool check(const string& first, const string& second, string& msg) { bool ret = first.compare(0, second.size(), second) == 0; if (!ret) { msg = "Policy condition failed: starts-with"; } return ret; } }; void RGWPolicyEnv::add_var(const string& name, const string& value) { vars[name] = value; } bool RGWPolicyEnv::get_var(const string& name, string& val) { map::iterator iter = vars.find(name); if (iter == vars.end()) return false; val = iter->second; return true; } bool RGWPolicyEnv::get_value(const string& s, string& val, map& checked_vars) { if (s.empty() || s[0] != '$') { val = s; return true; } const string& var = s.substr(1); checked_vars[var] = true; return get_var(var, val); } bool RGWPolicyEnv::match_policy_vars(map& policy_vars, string& err_msg) { map::iterator iter; string ignore_prefix = "x-ignore-"; for (iter = vars.begin(); iter != vars.end(); ++iter) { const string& var = iter->first; if (strncasecmp(ignore_prefix.c_str(), var.c_str(), ignore_prefix.size()) == 0) continue; if (policy_vars.count(var) == 0) { err_msg = "Policy missing condition: "; err_msg.append(iter->first); dout(1) << "env var missing in policy: " << iter->first << dendl; return false; } } return true; } RGWPolicy::~RGWPolicy() { list::iterator citer; for (citer = conditions.begin(); citer != conditions.end(); ++citer) { RGWPolicyCondition *cond = *citer; delete cond; } } int RGWPolicy::set_expires(const string& e) { struct tm t; if (!parse_iso8601(e.c_str(), &t)) return -EINVAL; expires = timegm(&t); return 0; } int RGWPolicy::add_condition(const string& op, const string& first, const string& second, string& err_msg) { RGWPolicyCondition *cond = NULL; if (stringcasecmp(op, "eq") == 0) { cond = new RGWPolicyCondition_StrEqual; } else if (stringcasecmp(op, "starts-with") == 0) { cond = new RGWPolicyCondition_StrStartsWith; } else if (stringcasecmp(op, "content-length-range") == 0) { off_t min, max; int r = stringtoll(first, &min); if (r < 0) { err_msg = "Bad content-length-range param"; dout(0) << "bad content-length-range param: " << first << dendl; return r; } r = stringtoll(second, &max); if (r < 0) { err_msg = "Bad content-length-range param"; dout(0) << "bad content-length-range param: " << second << dendl; return r; } if (min > min_length) min_length = min; if (max < max_length) max_length = max; return 0; } if (!cond) { err_msg = "Invalid condition: "; err_msg.append(op); dout(0) << "invalid condition: " << op << dendl; return -EINVAL; } cond->set_vals(first, second); conditions.push_back(cond); return 0; } int RGWPolicy::check(RGWPolicyEnv *env, string& err_msg) { uint64_t now = ceph_clock_now(NULL).sec(); if (expires <= now) { dout(0) << "NOTICE: policy calculated as expired: " << expiration_str << dendl; err_msg = "Policy expired"; return -EACCES; // change to condition about expired policy following S3 } list >::iterator viter; for (viter = var_checks.begin(); viter != var_checks.end(); ++viter) { pair& p = *viter; const string& name = p.first; const string& check_val = p.second; string val; if (!env->get_var(name, val)) { dout(20) << " policy check failed, variable not found: '" << name << "'" << dendl; err_msg = "Policy check failed, variable not found: "; err_msg.append(name); return -EACCES; } set_var_checked(name); dout(20) << "comparing " << name << " [" << val << "], " << check_val << dendl; if (val.compare(check_val) != 0) { err_msg = "Policy check failed, variable not met condition: "; err_msg.append(name); dout(1) << "policy check failed, val=" << val << " != " << check_val << dendl; return -EACCES; } } list::iterator citer; for (citer = conditions.begin(); citer != conditions.end(); ++citer) { RGWPolicyCondition *cond = *citer; if (!cond->check(env, checked_vars, err_msg)) { return -EACCES; } } if (!env->match_policy_vars(checked_vars, err_msg)) { dout(1) << "missing policy condition" << dendl; return -EACCES; } return 0; } int RGWPolicy::from_json(bufferlist& bl, string& err_msg) { JSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { err_msg = "Malformed JSON"; dout(0) << "malformed json" << dendl; return -EINVAL; } // as no time was included in the request, we hope that the user has included a short timeout JSONObjIter iter = parser.find_first("expiration"); if (iter.end()) { err_msg = "Policy missing expiration"; dout(0) << "expiration not found" << dendl; return -EINVAL; // change to a "no expiration" error following S3 } JSONObj *obj = *iter; expiration_str = obj->get_data(); int r = set_expires(expiration_str); if (r < 0) { err_msg = "Failed to parse policy expiration"; return r; } iter = parser.find_first("conditions"); if (iter.end()) { err_msg = "Policy missing conditions"; dout(0) << "conditions not found" << dendl; return -EINVAL; // change to a "no conditions" error following S3 } obj = *iter; iter = obj->find_first(); for (; !iter.end(); ++iter) { JSONObj *child = *iter; dout(20) << "data=" << child->get_data() << dendl; dout(20) << "is_object=" << child->is_object() << dendl; dout(20) << "is_array=" << child->is_array() << dendl; JSONObjIter citer = child->find_first(); if (child->is_array()) { vector v; int i; for (i = 0; !citer.end() && i < 3; ++citer, ++i) { JSONObj *o = *citer; v.push_back(o->get_data()); } if (i != 3 || !citer.end()) { /* we expect exactly 3 arguments here */ err_msg = "Bad condition array, expecting 3 arguments"; return -EINVAL; } int r = add_condition(v[0], v[1], v[2], err_msg); if (r < 0) return r; } else { JSONObj *c = *citer; dout(0) << "adding simple_check: " << c->get_name() << " : " << c->get_data() << dendl; add_simple_check(c->get_name(), c->get_data()); } } return 0; } ceph-0.80.11/src/rgw/rgw_user.h0000664000175100017510000004462612623076744020305 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_USER_H #define CEPH_RGW_USER_H #include #include "include/types.h" #include "rgw_common.h" #include "rgw_tools.h" #include "rgw_rados.h" #include "rgw_string.h" #include "common/Formatter.h" #include "rgw_formats.h" using namespace std; #define RGW_USER_ANON_ID "anonymous" #define SECRET_KEY_LEN 40 #define PUBLIC_ID_LEN 20 #define RAND_SUBUSER_LEN 5 /** * A string wrapper that includes encode/decode functions * for easily accessing a UID in all forms */ struct RGWUID { string user_id; void encode(bufferlist& bl) const { ::encode(user_id, bl); } void decode(bufferlist::iterator& bl) { ::decode(user_id, bl); } }; WRITE_CLASS_ENCODER(RGWUID) extern int rgw_user_sync_all_stats(RGWRados *store, const string& user_id); /** * Get the anonymous (ie, unauthenticated) user info. */ extern void rgw_get_anon_user(RGWUserInfo& info); /** * verify that user is an actual user, and not the anonymous user */ extern bool rgw_user_is_authenticated(RGWUserInfo& info); /** * Save the given user information to storage. * Returns: 0 on success, -ERR# on failure. */ extern int rgw_store_user_info(RGWRados *store, RGWUserInfo& info, RGWUserInfo *old_info, RGWObjVersionTracker *objv_tracker, time_t mtime, bool exclusive); /** * Given an email, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ extern int rgw_get_user_info_by_uid(RGWRados *store, string& user_id, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker = NULL, time_t *pmtime = NULL); /** * Given an swift username, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ extern int rgw_get_user_info_by_email(RGWRados *store, string& email, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker = NULL, time_t *pmtime = NULL); /** * Given an swift username, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ extern int rgw_get_user_info_by_swift(RGWRados *store, string& swift_name, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker = NULL, time_t *pmtime = NULL); /** * Given an access key, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ extern int rgw_get_user_info_by_access_key(RGWRados *store, string& access_key, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker = NULL, time_t *pmtime = NULL); /** * Given an RGWUserInfo, deletes the user and its bucket ACLs. */ extern int rgw_delete_user(RGWRados *store, RGWUserInfo& user, RGWObjVersionTracker& objv_tracker); /** * Store a list of the user's buckets, with associated functinos. */ /* * remove the different indexes */ extern int rgw_remove_key_index(RGWRados *store, RGWAccessKey& access_key); extern int rgw_remove_uid_index(RGWRados *store, string& uid); extern int rgw_remove_email_index(RGWRados *store, string& email); extern int rgw_remove_swift_name_index(RGWRados *store, string& swift_name); /* * An RGWUser class along with supporting classes created * to support the creation of an RESTful administrative API */ extern void rgw_perm_to_str(uint32_t mask, char *buf, int len); extern uint32_t rgw_str_to_perm(const char *str); enum ObjectKeyType { KEY_TYPE_SWIFT, KEY_TYPE_S3, KEY_TYPE_UNDEFINED }; enum RGWKeyPoolOp { GENERATE_KEY, MODIFY_KEY }; enum RGWUserId { RGW_USER_ID, RGW_SWIFT_USERNAME, RGW_USER_EMAIL, RGW_ACCESS_KEY, }; struct RGWUserAdminOpState { // user attributes RGWUserInfo info; std::string user_id; std::string user_email; std::string display_name; uint32_t max_buckets; __u8 suspended; __u8 system; std::string caps; RGWObjVersionTracker objv; uint32_t op_mask; map temp_url_keys; // subuser attributes std::string subuser; uint32_t perm_mask; // key_attributes std::string id; // access key std::string key; // secret key int32_t key_type; // operation attributes bool existing_user; bool existing_key; bool existing_subuser; bool existing_email; bool subuser_specified; bool gen_secret; bool gen_access; bool gen_subuser; bool id_specified; bool key_specified; bool type_specified; bool purge_data; bool purge_keys; bool display_name_specified; bool user_email_specified; bool max_buckets_specified; bool perm_specified; bool op_mask_specified; bool caps_specified; bool suspension_op; bool system_specified; bool key_op; bool temp_url_key_specified; // req parameters bool populated; bool initialized; bool key_params_checked; bool subuser_params_checked; bool user_params_checked; bool bucket_quota_specified; bool user_quota_specified; RGWQuotaInfo bucket_quota; RGWQuotaInfo user_quota; void set_access_key(std::string& access_key) { if (access_key.empty()) return; id = access_key; id_specified = true; gen_access = false; key_op = true; } void set_secret_key(std::string& secret_key) { if (secret_key.empty()) return; key = secret_key; key_specified = true; gen_secret = false; key_op = true; } void set_user_id(std::string& id) { if (id.empty()) return; user_id = id; } void set_user_email(std::string& email) { if (email.empty()) return; user_email = email; user_email_specified = true; } void set_display_name(std::string& name) { if (name.empty()) return; display_name = name; display_name_specified = true; } void set_subuser(std::string& _subuser) { if (_subuser.empty()) return; size_t pos = _subuser.find(":"); if (pos != string::npos) { user_id = _subuser.substr(0, pos); subuser = _subuser.substr(pos+1); } else { subuser = _subuser; } subuser_specified = true; } void set_caps(std::string& _caps) { if (_caps.empty()) return; caps = _caps; caps_specified = true; } void set_perm(uint32_t perm) { perm_mask = perm; perm_specified = true; } void set_op_mask(uint32_t mask) { op_mask = mask; op_mask_specified = true; } void set_temp_url_key(const string& key, int index) { temp_url_keys[index] = key; temp_url_key_specified = true; } void set_key_type(int32_t type) { key_type = type; type_specified = true; } void set_suspension(__u8 is_suspended) { suspended = is_suspended; suspension_op = true; } void set_system(__u8 is_system) { system = is_system; system_specified = true; } void set_user_info(RGWUserInfo& user_info) { user_id = user_info.user_id; info = user_info; } void set_max_buckets(uint32_t mb) { max_buckets = mb; max_buckets_specified = true; } void set_gen_access() { gen_access = true; key_op = true; } void set_gen_secret() { gen_secret = true; key_op = true; } void set_generate_key() { if (id.empty()) gen_access = true; if (key.empty()) gen_secret = true; key_op = true; } void clear_generate_key() { gen_access = false; gen_secret = false; } void set_purge_keys() { purge_keys = true; key_op = true; } void set_bucket_quota(RGWQuotaInfo& quota) { bucket_quota = quota; bucket_quota_specified = true; } void set_user_quota(RGWQuotaInfo& quota) { user_quota = quota; user_quota_specified = true; } bool is_populated() { return populated; }; bool is_initialized() { return initialized; }; bool has_existing_user() { return existing_user; }; bool has_existing_key() { return existing_key; }; bool has_existing_subuser() { return existing_subuser; }; bool has_existing_email() { return existing_email; }; bool has_subuser() { return subuser_specified; }; bool has_key_op() { return key_op; }; bool has_caps_op() { return caps_specified; }; bool has_suspension_op() { return suspension_op; }; bool has_subuser_perm() { return perm_specified; }; bool has_op_mask() { return op_mask_specified; }; bool will_gen_access() { return gen_access; }; bool will_gen_secret() { return gen_secret; }; bool will_gen_subuser() { return gen_subuser; }; bool will_purge_keys() { return purge_keys; }; bool will_purge_data() { return purge_data; }; bool will_generate_subuser() { return gen_subuser; }; bool has_bucket_quota() { return bucket_quota_specified; } bool has_user_quota() { return user_quota_specified; } void set_populated() { populated = true; }; void clear_populated() { populated = false; }; void set_initialized() { initialized = true; }; void set_existing_user(bool flag) { existing_user = flag; }; void set_existing_key(bool flag) { existing_key = flag; }; void set_existing_subuser(bool flag) { existing_subuser = flag; }; void set_existing_email(bool flag) { existing_email = flag; }; void set_purge_data(bool flag) { purge_data = flag; }; void set_generate_subuser(bool flag) { gen_subuser = flag; }; __u8 get_suspension_status() { return suspended; }; int32_t get_key_type() {return key_type; }; uint32_t get_subuser_perm() { return perm_mask; }; uint32_t get_max_buckets() { return max_buckets; }; uint32_t get_op_mask() { return op_mask; }; RGWQuotaInfo& get_bucket_quota() { return bucket_quota; } RGWQuotaInfo& get_user_quota() { return user_quota; } std::string get_user_id() { return user_id; }; std::string get_subuser() { return subuser; }; std::string get_access_key() { return id; }; std::string get_secret_key() { return key; }; std::string get_caps() { return caps; }; std::string get_user_email() { return user_email; }; std::string get_display_name() { return display_name; }; map& get_temp_url_keys() { return temp_url_keys; }; RGWUserInfo& get_user_info() { return info; }; map *get_swift_keys() { return &info.swift_keys; }; map *get_access_keys() { return &info.access_keys; }; map *get_subusers() { return &info.subusers; }; RGWUserCaps *get_caps_obj() { return &info.caps; }; std::string build_default_swift_kid() { if (user_id.empty() || subuser.empty()) return ""; std::string kid = user_id; kid.append(":"); kid.append(subuser); return kid; } std::string generate_subuser() { if (user_id.empty()) return ""; std::string generated_subuser = user_id; std::string rand_suffix; int sub_buf_size = RAND_SUBUSER_LEN + 1; char sub_buf[RAND_SUBUSER_LEN + 1]; if (gen_rand_alphanumeric_upper(g_ceph_context, sub_buf, sub_buf_size) < 0) return ""; rand_suffix = sub_buf; if (rand_suffix.empty()) return ""; generated_subuser.append(rand_suffix); subuser = generated_subuser; return generated_subuser; } RGWUserAdminOpState() : user_id(RGW_USER_ANON_ID), user_email(""), display_name(""), id(""), key ("") { max_buckets = RGW_DEFAULT_MAX_BUCKETS; key_type = -1; perm_mask = 0; suspended = 0; system = 0; op_mask = 0; existing_user = false; existing_key = false; existing_subuser = false; existing_email = false; subuser_specified = false; caps_specified = false; purge_keys = false; gen_secret = false; gen_access = false; gen_subuser = false; id_specified = false; key_specified = false; type_specified = false; purge_data = false; display_name_specified = false; user_email_specified = false; max_buckets_specified = false; perm_specified = false; op_mask_specified = false; suspension_op = false; system_specified = false; key_op = false; populated = false; initialized = false; key_params_checked = false; subuser_params_checked = false; user_params_checked = false; bucket_quota_specified = false; temp_url_key_specified = false; user_quota_specified = false; } }; class RGWUser; class RGWAccessKeyPool { RGWUser *user; std::map key_type_map; std::string user_id; RGWRados *store; map *swift_keys; map *access_keys; // we don't want to allow keys for the anonymous user or a null user bool keys_allowed; private: int create_key(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int generate_key(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int modify_key(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int check_key_owner(RGWUserAdminOpState& op_state); bool check_existing_key(RGWUserAdminOpState& op_state); int check_op(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); /* API Contract Fulfilment */ int execute_add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); public: RGWAccessKeyPool(RGWUser* usr); ~RGWAccessKeyPool(); int init(RGWUserAdminOpState& op_state); /* API Contracted Methods */ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); friend class RGWUser; friend class RGWSubUserPool; }; class RGWSubUserPool { RGWUser *user; string user_id; RGWRados *store; bool subusers_allowed; map *subuser_map; private: int check_op(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); /* API Contract Fulfillment */ int execute_add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); public: RGWSubUserPool(RGWUser *user); ~RGWSubUserPool(); bool exists(std::string subuser); int init(RGWUserAdminOpState& op_state); /* API contracted methods */ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int modify(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); friend class RGWUser; }; class RGWUserCapPool { RGWUserCaps *caps; bool caps_allowed; RGWUser *user; private: int add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); int remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save); public: RGWUserCapPool(RGWUser *user); ~RGWUserCapPool(); int init(RGWUserAdminOpState& op_state); /* API contracted methods */ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); friend class RGWUser; }; class RGWUser { private: RGWUserInfo old_info; RGWRados *store; string user_id; bool info_stored; void set_populated() { info_stored = true; }; void clear_populated() { info_stored = false; }; bool is_populated() { return info_stored; }; int check_op(RGWUserAdminOpState& req, std::string *err_msg); int update(RGWUserAdminOpState& op_state, std::string *err_msg); void clear_members(); void init_default(); /* API Contract Fulfillment */ int execute_add(RGWUserAdminOpState& op_state, std::string *err_msg); int execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg); int execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg); public: RGWUser(); ~RGWUser(); int init(RGWRados *storage, RGWUserAdminOpState& op_state); int init_storage(RGWRados *storage); int init(RGWUserAdminOpState& op_state); int init_members(RGWUserAdminOpState& op_state); RGWRados *get_store() { return store; }; /* API Contracted Members */ RGWUserCapPool caps; RGWAccessKeyPool keys; RGWSubUserPool subusers; /* API Contracted Methods */ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); /* remove an already populated RGWUser */ int remove(std::string *err_msg = NULL); int modify(RGWUserAdminOpState& op_state, std::string *err_msg = NULL); /* retrieve info from an existing user in the RGW system */ int info(RGWUserAdminOpState& op_state, RGWUserInfo& fetched_info, std::string *err_msg = NULL); /* info from an already populated RGWUser */ int info (RGWUserInfo& fetched_info, std::string *err_msg = NULL); friend class RGWAccessKeyPool; friend class RGWSubUserPool; friend class RGWUserCapPool; }; /* Wrapers for admin API functionality */ class RGWUserAdminOp_User { public: static int info(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int create(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int modify(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); }; class RGWUserAdminOp_Subuser { public: static int create(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int modify(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); }; class RGWUserAdminOp_Key { public: static int create(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); }; class RGWUserAdminOp_Caps { public: static int add(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); static int remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); }; class RGWMetadataManager; extern void rgw_user_init(RGWMetadataManager *mm); #endif ceph-0.80.11/src/rgw/rgw_rest_bucket.cc0000664000175100017510000001225212623076744021765 0ustar jenkins-buildjenkins-build#include "rgw_op.h" #include "rgw_bucket.h" #include "rgw_rest_bucket.h" #include "include/str_list.h" #define dout_subsys ceph_subsys_rgw class RGWOp_Bucket_Info : public RGWRESTOp { public: RGWOp_Bucket_Info() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_READ); } void execute(); virtual const string name() { return "get_bucket_info"; } }; void RGWOp_Bucket_Info::execute() { RGWBucketAdminOpState op_state; bool fetch_stats; std::string uid; std::string bucket; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "bucket", bucket, &bucket); RESTArgs::get_bool(s, "stats", false, &fetch_stats); op_state.set_user_id(uid); op_state.set_bucket_name(bucket); op_state.set_fetch_stats(fetch_stats); http_ret = RGWBucketAdminOp::info(store, op_state, flusher); } class RGWOp_Get_Policy : public RGWRESTOp { public: RGWOp_Get_Policy() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_READ); } void execute(); virtual const string name() { return "get_policy"; } }; void RGWOp_Get_Policy::execute() { RGWBucketAdminOpState op_state; std::string bucket; std::string object; RESTArgs::get_string(s, "bucket", bucket, &bucket); RESTArgs::get_string(s, "object", object, &object); op_state.set_bucket_name(bucket); op_state.set_object(object); http_ret = RGWBucketAdminOp::get_policy(store, op_state, flusher); } class RGWOp_Check_Bucket_Index : public RGWRESTOp { public: RGWOp_Check_Bucket_Index() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "check_bucket_index"; } }; void RGWOp_Check_Bucket_Index::execute() { std::string bucket; bool fix_index; bool check_objects; RGWBucketAdminOpState op_state; RESTArgs::get_string(s, "bucket", bucket, &bucket); RESTArgs::get_bool(s, "fix", false, &fix_index); RESTArgs::get_bool(s, "check-objects", false, &check_objects); op_state.set_bucket_name(bucket); op_state.set_fix_index(fix_index); op_state.set_check_objects(check_objects); http_ret = RGWBucketAdminOp::check_index(store, op_state, flusher); } class RGWOp_Bucket_Link : public RGWRESTOp { public: RGWOp_Bucket_Link() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "link_bucket"; } }; void RGWOp_Bucket_Link::execute() { std::string uid; std::string bucket; RGWBucketAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "bucket", bucket, &bucket); op_state.set_user_id(uid); op_state.set_bucket_name(bucket); http_ret = RGWBucketAdminOp::link(store, op_state); } class RGWOp_Bucket_Unlink : public RGWRESTOp { public: RGWOp_Bucket_Unlink() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "unlink_bucket"; } }; void RGWOp_Bucket_Unlink::execute() { std::string uid; std::string bucket; RGWBucketAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "bucket", bucket, &bucket); op_state.set_user_id(uid); op_state.set_bucket_name(bucket); http_ret = RGWBucketAdminOp::unlink(store, op_state); } class RGWOp_Bucket_Remove : public RGWRESTOp { public: RGWOp_Bucket_Remove() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_bucket"; } }; void RGWOp_Bucket_Remove::execute() { std::string bucket; bool delete_children; RGWBucketAdminOpState op_state; RESTArgs::get_string(s, "bucket", bucket, &bucket); RESTArgs::get_bool(s, "purge-objects", false, &delete_children); op_state.set_bucket_name(bucket); op_state.set_delete_children(delete_children); http_ret = RGWBucketAdminOp::remove_bucket(store, op_state); } class RGWOp_Object_Remove: public RGWRESTOp { public: RGWOp_Object_Remove() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("buckets", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_object"; } }; void RGWOp_Object_Remove::execute() { std::string bucket; std::string object; RGWBucketAdminOpState op_state; RESTArgs::get_string(s, "bucket", bucket, &bucket); RESTArgs::get_string(s, "object", object, &object); op_state.set_bucket_name(bucket); op_state.set_object(object); http_ret = RGWBucketAdminOp::remove_object(store, op_state); } RGWOp *RGWHandler_Bucket::op_get() { if (s->info.args.sub_resource_exists("policy")) return new RGWOp_Get_Policy; if (s->info.args.sub_resource_exists("index")) return new RGWOp_Check_Bucket_Index; return new RGWOp_Bucket_Info; }; RGWOp *RGWHandler_Bucket::op_put() { return new RGWOp_Bucket_Link; }; RGWOp *RGWHandler_Bucket::op_post() { return new RGWOp_Bucket_Unlink; }; RGWOp *RGWHandler_Bucket::op_delete() { if (s->info.args.sub_resource_exists("object")) return new RGWOp_Object_Remove; return new RGWOp_Bucket_Remove; }; ceph-0.80.11/src/rgw/rgw_rest_usage.h0000664000175100017510000000104112623076744021450 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_USAGE_H #define CEPH_RGW_REST_USAGE_H #include "rgw_rest.h" #include "rgw_rest_s3.h" class RGWHandler_Usage : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); RGWOp *op_delete(); public: RGWHandler_Usage() {} virtual ~RGWHandler_Usage() {} int read_permissions(RGWOp*) { return 0; } }; class RGWRESTMgr_Usage : public RGWRESTMgr { public: RGWRESTMgr_Usage() {} virtual ~RGWRESTMgr_Usage() {} RGWHandler *get_handler(struct req_state *s) { return new RGWHandler_Usage; } }; #endif ceph-0.80.11/src/rgw/rgw_multi.h0000664000175100017510000000152512623076744020450 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_MULTI_H #define CEPH_RGW_MULTI_H #include #include "rgw_xml.h" class RGWMultiCompleteUpload : public XMLObj { public: RGWMultiCompleteUpload() {} ~RGWMultiCompleteUpload() {} bool xml_end(const char *el); std::map parts; }; class RGWMultiPart : public XMLObj { string etag; int num; public: RGWMultiPart() : num(0) {} ~RGWMultiPart() {} bool xml_end(const char *el); string& get_etag() { return etag; } int get_num() { return num; } }; class RGWMultiPartNumber : public XMLObj { public: RGWMultiPartNumber() {} ~RGWMultiPartNumber() {} }; class RGWMultiETag : public XMLObj { public: RGWMultiETag() {} ~RGWMultiETag() {} }; class RGWMultiXMLParser : public RGWXMLParser { XMLObj *alloc_obj(const char *el); public: RGWMultiXMLParser() {} ~RGWMultiXMLParser() {} }; #endif ceph-0.80.11/src/rgw/librgw.cc0000664000175100017510000000624312623076744020065 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "include/rados/librgw.h" #include "rgw/rgw_acl_s3.h" #include "rgw_acl.h" #include "common/ceph_argparse.h" #include "common/ceph_context.h" #include "common/common_init.h" #include "common/dout.h" #include #include #include #define dout_subsys ceph_subsys_rgw int librgw_create(librgw_t *rgw, const char * const id) { CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT); if (id) { iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id); } CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0); cct->_conf->set_val("log_to_stderr", "false"); // quiet by default cct->_conf->set_val("err_to_stderr", "true"); // quiet by default cct->_conf->parse_env(); // environment variables override cct->_conf->apply_changes(NULL); common_init_finish(cct); *rgw = cct; return 0; } int librgw_acl_bin2xml(librgw_t rgw, const char *bin, int bin_len, char **xml) { try { // convert to bufferlist bufferlist bl; bl.append(bin, bin_len); // convert to RGWAccessControlPolicy RGWAccessControlPolicy_S3 acl((CephContext *)rgw); bufferlist::iterator bli(bl.begin()); acl.decode(bli); // convert to XML stringstream stringstream ss; acl.to_xml(ss); // convert to XML C string *xml = strdup(ss.str().c_str()); if (!*xml) return -ENOBUFS; return 0; } catch (const std::exception &e) { lderr(rgw) << "librgw_acl_bin2xml: caught exception " << e.what() << dendl; return -2000; } catch (...) { lderr(rgw) << "librgw_acl_bin2xml: caught unknown exception " << dendl; return -2000; } } void librgw_free_xml(librgw_t rgw, char *xml) { free(xml); } int librgw_acl_xml2bin(librgw_t rgw, const char *xml, char **bin, int *bin_len) { char *bin_ = NULL; try { RGWACLXMLParser_S3 parser((CephContext *)rgw); if (!parser.init()) { return -1000; } if (!parser.parse(xml, strlen(xml), true)) { return -EINVAL; } RGWAccessControlPolicy_S3 *policy = (RGWAccessControlPolicy_S3 *)parser.find_first("AccessControlPolicy"); if (!policy) { return -1001; } bufferlist bl; policy->encode(bl); bin_ = (char*)malloc(bl.length()); if (!bin_) { return -ENOBUFS; } int bin_len_ = bl.length(); bl.copy(0, bin_len_, bin_); *bin = bin_; *bin_len = bin_len_; return 0; } catch (const std::exception &e) { lderr(rgw) << "librgw_acl_bin2xml: caught exception " << e.what() << dendl; } catch (...) { lderr(rgw) << "librgw_acl_bin2xml: caught unknown exception " << dendl; } if (!bin_) free(bin_); bin_ = NULL; return -2000; } void librgw_free_bin(librgw_t rgw, char *bin) { free(bin); } void librgw_shutdown(librgw_t rgw) { rgw->put(); } ceph-0.80.11/src/rgw/rgw_rest_usage.cc0000664000175100017510000000411312623076744021611 0ustar jenkins-buildjenkins-build#include "rgw_op.h" #include "rgw_usage.h" #include "rgw_rest_usage.h" #include "include/str_list.h" #define dout_subsys ceph_subsys_rgw class RGWOp_Usage_Get : public RGWRESTOp { public: RGWOp_Usage_Get() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("usage", RGW_CAP_READ); } void execute(); virtual const string name() { return "get_usage"; } }; void RGWOp_Usage_Get::execute() { map categories; string uid; uint64_t start, end; bool show_entries; bool show_summary; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_epoch(s, "start", 0, &start); RESTArgs::get_epoch(s, "end", (uint64_t)-1, &end); RESTArgs::get_bool(s, "show-entries", true, &show_entries); RESTArgs::get_bool(s, "show-summary", true, &show_summary); string cat_str; RESTArgs::get_string(s, "categories", cat_str, &cat_str); if (!cat_str.empty()) { list cat_list; list::iterator iter; get_str_list(cat_str, cat_list); for (iter = cat_list.begin(); iter != cat_list.end(); ++iter) { categories[*iter] = true; } } http_ret = RGWUsage::show(store, uid, start, end, show_entries, show_summary, &categories, flusher); } class RGWOp_Usage_Delete : public RGWRESTOp { public: RGWOp_Usage_Delete() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("usage", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "trim_usage"; } }; void RGWOp_Usage_Delete::execute() { string uid; uint64_t start, end; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_epoch(s, "start", 0, &start); RESTArgs::get_epoch(s, "end", (uint64_t)-1, &end); if (uid.empty() && !start && end == (uint64_t)-1) { bool remove_all; RESTArgs::get_bool(s, "remove-all", false, &remove_all); if (!remove_all) { http_ret = -EINVAL; return; } } http_ret = RGWUsage::trim(store, uid, start, end); } RGWOp *RGWHandler_Usage::op_get() { return new RGWOp_Usage_Get; }; RGWOp *RGWHandler_Usage::op_delete() { return new RGWOp_Usage_Delete; }; ceph-0.80.11/src/rgw/rgw_keystone.cc0000664000175100017510000000522712623076744021320 0ustar jenkins-buildjenkins-build#include #include #include "common/errno.h" #include "common/ceph_json.h" #include "include/types.h" #include "include/str_list.h" #include "rgw_common.h" #include "rgw_keystone.h" #define dout_subsys ceph_subsys_rgw bool KeystoneToken::User::has_role(const string& r) { list::iterator iter; for (iter = roles.begin(); iter != roles.end(); ++iter) { if (fnmatch(r.c_str(), ((*iter).name.c_str()), 0) == 0) { return true; } } return false; } int KeystoneToken::parse(CephContext *cct, bufferlist& bl) { JSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { ldout(cct, 0) << "Keystone token parse error: malformed json" << dendl; return -EINVAL; } try { JSONDecoder::decode_json("access", *this, &parser); } catch (JSONDecoder::err& err) { ldout(cct, 0) << "Keystone token parse error: " << err.message << dendl; return -EINVAL; } return 0; } bool RGWKeystoneTokenCache::find(const string& token_id, KeystoneToken& token) { lock.Lock(); map::iterator iter = tokens.find(token_id); if (iter == tokens.end()) { lock.Unlock(); if (perfcounter) perfcounter->inc(l_rgw_keystone_token_cache_miss); return false; } token_entry& entry = iter->second; tokens_lru.erase(entry.lru_iter); if (entry.token.expired()) { tokens.erase(iter); lock.Unlock(); if (perfcounter) perfcounter->inc(l_rgw_keystone_token_cache_hit); return false; } token = entry.token; tokens_lru.push_front(token_id); entry.lru_iter = tokens_lru.begin(); lock.Unlock(); if (perfcounter) perfcounter->inc(l_rgw_keystone_token_cache_hit); return true; } void RGWKeystoneTokenCache::add(const string& token_id, KeystoneToken& token) { lock.Lock(); map::iterator iter = tokens.find(token_id); if (iter != tokens.end()) { token_entry& e = iter->second; tokens_lru.erase(e.lru_iter); } tokens_lru.push_front(token_id); token_entry& entry = tokens[token_id]; entry.token = token; entry.lru_iter = tokens_lru.begin(); while (tokens_lru.size() > max) { list::reverse_iterator riter = tokens_lru.rbegin(); iter = tokens.find(*riter); assert(iter != tokens.end()); tokens.erase(iter); tokens_lru.pop_back(); } lock.Unlock(); } void RGWKeystoneTokenCache::invalidate(const string& token_id) { Mutex::Locker l(lock); map::iterator iter = tokens.find(token_id); if (iter == tokens.end()) return; ldout(cct, 20) << "invalidating revoked token id=" << token_id << dendl; token_entry& e = iter->second; tokens_lru.erase(e.lru_iter); tokens.erase(iter); } ceph-0.80.11/src/rgw/rgw_quota.h0000664000175100017510000000363212623076744020450 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_QUOTA_H #define CEPH_RGW_QUOTA_H #include "include/utime.h" #include "include/atomic.h" #include "common/lru_map.h" class RGWRados; class JSONObj; struct RGWQuotaInfo { int64_t max_size_kb; int64_t max_objects; bool enabled; int64_t max_size_soft_threshold; int64_t max_objs_soft_threshold; RGWQuotaInfo() : max_size_kb(-1), max_objects(-1), enabled(false), max_size_soft_threshold(-1), max_objs_soft_threshold(-1) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(max_size_kb, bl); ::encode(max_objects, bl); ::encode(enabled, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(max_size_kb, bl); ::decode(max_objects, bl); ::decode(enabled, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWQuotaInfo) class rgw_bucket; class RGWQuotaHandler { public: RGWQuotaHandler() {} virtual ~RGWQuotaHandler() { } virtual int check_quota(const string& bucket_owner, rgw_bucket& bucket, RGWQuotaInfo& user_quota, RGWQuotaInfo& bucket_quota, uint64_t num_objs, uint64_t size) = 0; virtual void update_stats(const string& bucket_owner, rgw_bucket& bucket, int obj_delta, uint64_t added_bytes, uint64_t removed_bytes) = 0; static RGWQuotaHandler *generate_handler(RGWRados *store, bool quota_threads); static void free_handler(RGWQuotaHandler *handler); }; #endif ceph-0.80.11/src/rgw/rgw_gc.h0000664000175100017510000000300212623076744017677 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_GC_H #define CEPH_RGW_GC_H #include "include/types.h" #include "include/atomic.h" #include "include/rados/librados.hpp" #include "common/Mutex.h" #include "common/Cond.h" #include "common/Thread.h" #include "rgw_common.h" #include "rgw_rados.h" #include "cls/rgw/cls_rgw_types.h" class RGWGC { CephContext *cct; RGWRados *store; int max_objs; string *obj_names; atomic_t down_flag; int tag_index(const string& tag); class GCWorker : public Thread { CephContext *cct; RGWGC *gc; Mutex lock; Cond cond; public: GCWorker(CephContext *_cct, RGWGC *_gc) : cct(_cct), gc(_gc), lock("GCWorker") {} void *entry(); void stop(); }; GCWorker *worker; public: RGWGC() : cct(NULL), store(NULL), max_objs(0), obj_names(NULL), worker(NULL) {} ~RGWGC() { stop_processor(); finalize(); } void add_chain(librados::ObjectWriteOperation& op, cls_rgw_obj_chain& chain, const string& tag); int send_chain(cls_rgw_obj_chain& chain, const string& tag, bool sync); int defer_chain(const string& tag, bool sync); int remove(int index, const std::list& tags); void initialize(CephContext *_cct, RGWRados *_store); void finalize(); int list(int *index, string& marker, uint32_t max, bool expired_only, std::list& result, bool *truncated); void list_init(int *index) { *index = 0; } int process(int index, int process_max_secs); int process(); bool going_down(); void start_processor(); void stop_processor(); }; #endif ceph-0.80.11/src/rgw/rgw_swift.h0000664000175100017510000000347012623076744020453 0ustar jenkins-buildjenkins-build #ifndef CEPH_RGW_SWIFT_H #define CEPH_RGW_SWIFT_H #include "rgw_common.h" #include "common/Cond.h" class RGWRados; class KeystoneToken; struct rgw_swift_auth_info { int status; string auth_groups; string user; string display_name; long long ttl; rgw_swift_auth_info() : status(0), ttl(0) {} }; class RGWSwift { CephContext *cct; atomic_t down_flag; int validate_token(const char *token, struct rgw_swift_auth_info *info); int validate_keystone_token(RGWRados *store, const string& token, struct rgw_swift_auth_info *info, RGWUserInfo& rgw_user); int parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info, KeystoneToken& t); int update_user_info(RGWRados *store, struct rgw_swift_auth_info *info, RGWUserInfo& user_info); int get_keystone_url(std::string& url); int get_keystone_admin_token(std::string& token); class KeystoneRevokeThread : public Thread { CephContext *cct; RGWSwift *swift; Mutex lock; Cond cond; public: KeystoneRevokeThread(CephContext *_cct, RGWSwift *_swift) : cct(_cct), swift(_swift), lock("KeystoneRevokeThread") {} void *entry(); void stop(); }; KeystoneRevokeThread *keystone_revoke_thread; void init(); void finalize(); void init_keystone(); void finalize_keystone(); bool supports_keystone() { return !cct->_conf->rgw_keystone_url.empty(); } bool do_verify_swift_token(RGWRados *store, req_state *s); protected: int check_revoked(); public: RGWSwift(CephContext *_cct) : cct(_cct), keystone_revoke_thread(NULL) { init(); } ~RGWSwift() { finalize(); } bool verify_swift_token(RGWRados *store, req_state *s); bool going_down(); }; extern RGWSwift *rgw_swift; void swift_init(CephContext *cct); void swift_finalize(); #endif ceph-0.80.11/src/rgw/rgw_multi_del.cc0000664000175100017510000000265512623076744021437 0ustar jenkins-buildjenkins-build#include #include #include "include/types.h" #include "rgw_xml.h" #include "rgw_multi_del.h" #define dout_subsys ceph_subsys_rgw using namespace std; bool RGWMultiDelObject::xml_end(const char *el) { RGWMultiDelKey *key_obj = static_cast(find_first("Key")); if (!key_obj) return false; string s = key_obj->get_data(); if (s.empty()) return false; key = s; return true; } bool RGWMultiDelDelete::xml_end(const char *el) { RGWMultiDelQuiet *quiet_set = static_cast(find_first("Quiet")); if (quiet_set) { string quiet_val = quiet_set->get_data(); quiet = (strcasecmp(quiet_val.c_str(), "true") == 0); } XMLObjIter iter = find("Object"); RGWMultiDelObject *object = static_cast(iter.get_next()); while (object) { string key = object->get_key(); objects.push_back(key); object = static_cast(iter.get_next()); } return true; } XMLObj *RGWMultiDelXMLParser::alloc_obj(const char *el) { XMLObj *obj = NULL; if (strcmp(el, "Delete") == 0) { obj = new RGWMultiDelDelete(); } else if (strcmp(el, "Quiet") == 0) { obj = new RGWMultiDelQuiet(); } else if (strcmp(el, "Object") == 0) { obj = new RGWMultiDelObject (); } else if (strcmp(el, "Key") == 0) { obj = new RGWMultiDelKey(); } else if (strcmp(el, "VersionID") == 0) { /*do nothing*/ } return obj; } ceph-0.80.11/src/rgw/rgw_rest_metadata.h0000664000175100017510000000541712623076744022137 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_REST_METADATA_H #define CEPH_RGW_REST_METADATA_H class RGWOp_Metadata_List : public RGWRESTOp { public: RGWOp_Metadata_List() {} ~RGWOp_Metadata_List() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("metadata", RGW_CAP_READ); } void execute(); virtual const string name(); }; class RGWOp_Metadata_Get : public RGWRESTOp { public: RGWOp_Metadata_Get() {} ~RGWOp_Metadata_Get() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("metadata", RGW_CAP_READ); } void execute(); virtual const string name(); }; class RGWOp_Metadata_Put : public RGWRESTOp { int get_data(bufferlist& bl); string update_status; obj_version ondisk_version; public: RGWOp_Metadata_Put() {} ~RGWOp_Metadata_Put() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("metadata", RGW_CAP_WRITE); } void execute(); void send_response(); virtual const string name() { return "set_metadata"; } }; class RGWOp_Metadata_Delete : public RGWRESTOp { public: RGWOp_Metadata_Delete() {} ~RGWOp_Metadata_Delete() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("metadata", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_metadata"; } }; class RGWOp_Metadata_Lock : public RGWRESTOp { public: RGWOp_Metadata_Lock() {} ~RGWOp_Metadata_Lock() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("metadata", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "lock_metadata_object"; } }; class RGWOp_Metadata_Unlock : public RGWRESTOp { public: RGWOp_Metadata_Unlock() {} ~RGWOp_Metadata_Unlock() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("metadata", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "unlock_metadata_object"; } }; class RGWHandler_Metadata : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); RGWOp *op_put(); RGWOp *op_delete(); RGWOp *op_post(); int read_permissions(RGWOp*) { return 0; } public: RGWHandler_Metadata() : RGWHandler_Auth_S3() {} virtual ~RGWHandler_Metadata() {} }; class RGWRESTMgr_Metadata : public RGWRESTMgr { public: RGWRESTMgr_Metadata() {} virtual ~RGWRESTMgr_Metadata() {} virtual RGWHandler *get_handler(struct req_state *s){ return new RGWHandler_Metadata; } }; #endif ceph-0.80.11/src/rgw/rgw_env.cc0000664000175100017510000000543312623076744020246 0ustar jenkins-buildjenkins-build#include "rgw_common.h" #include "rgw_log.h" #include #include #define dout_subsys ceph_subsys_rgw RGWEnv::RGWEnv() { conf = new RGWConf; } RGWEnv::~RGWEnv() { delete conf; } void RGWEnv::init(CephContext *cct) { conf->init(cct, this); } void RGWEnv::set(const char *name, const char *val) { if (!val) val = ""; env_map[name] = val; dout(20) << "RGWEnv::set(): " << name << ": " << val << dendl; } void RGWEnv::init(CephContext *cct, char **envp) { const char *p; env_map.clear(); for (int i=0; (p = envp[i]); ++i) { string s(p); int pos = s.find('='); if (pos <= 0) // should never be 0 continue; string name = s.substr(0, pos); string val = s.substr(pos + 1); env_map[name] = val; } init(cct); } const char *RGWEnv::get(const char *name, const char *def_val) { map::iterator iter = env_map.find(name); if (iter == env_map.end()) return def_val; return iter->second.c_str(); } int RGWEnv::get_int(const char *name, int def_val) { map::iterator iter = env_map.find(name); if (iter == env_map.end()) return def_val; const char *s = iter->second.c_str(); return atoi(s); } bool RGWEnv::get_bool(const char *name, bool def_val) { map::iterator iter = env_map.find(name); if (iter == env_map.end()) return def_val; const char *s = iter->second.c_str(); return rgw_str_to_bool(s, def_val); } size_t RGWEnv::get_size(const char *name, size_t def_val) { map::iterator iter = env_map.find(name); if (iter == env_map.end()) return def_val; const char *s = iter->second.c_str(); return atoll(s); } bool RGWEnv::exists(const char *name) { map::iterator iter = env_map.find(name); return (iter != env_map.end()); } bool RGWEnv::exists_prefix(const char *prefix) { if (env_map.empty() || prefix == NULL) return false; map::iterator iter = env_map.lower_bound(prefix); if (iter == env_map.end()) return false; return (strncmp(iter->first.c_str(), prefix, strlen(prefix)) == 0); } void RGWEnv::remove(const char *name) { map::iterator iter = env_map.find(name); if (iter != env_map.end()) env_map.erase(iter); } void RGWConf::init(CephContext *cct, RGWEnv *env) { enable_ops_log = cct->_conf->rgw_enable_ops_log; enable_usage_log = cct->_conf->rgw_enable_usage_log; defer_to_bucket_acls = 0; // default if (cct->_conf->rgw_defer_to_bucket_acls == "recurse") { defer_to_bucket_acls = RGW_DEFER_TO_BUCKET_ACLS_RECURSE; } else if (cct->_conf->rgw_defer_to_bucket_acls == "full_control") { defer_to_bucket_acls = RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL; } } ceph-0.80.11/src/rgw/rgw_swift_auth.h0000664000175100017510000000237512623076744021477 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_SWIFT_AUTH_H #define CEPH_RGW_SWIFT_AUTH_H #include "rgw_op.h" #include "rgw_rest.h" #define RGW_SWIFT_TOKEN_EXPIRATION (15 * 60) extern int rgw_swift_verify_signed_token(CephContext *cct, RGWRados *store, const char *token, RGWUserInfo& info, string *pswift_user); class RGW_SWIFT_Auth_Get : public RGWOp { public: RGW_SWIFT_Auth_Get() {} ~RGW_SWIFT_Auth_Get() {} int verify_permission() { return 0; } void execute(); virtual const string name() { return "swift_auth_get"; } }; class RGWHandler_SWIFT_Auth : public RGWHandler { public: RGWHandler_SWIFT_Auth() {} ~RGWHandler_SWIFT_Auth() {} RGWOp *op_get(); int init(RGWRados *store, struct req_state *state, RGWClientIO *cio); int authorize(); int read_permissions(RGWOp *op) { return 0; } virtual RGWAccessControlPolicy *alloc_policy() { return NULL; } virtual void free_policy(RGWAccessControlPolicy *policy) {} }; class RGWRESTMgr_SWIFT_Auth : public RGWRESTMgr { public: RGWRESTMgr_SWIFT_Auth() {} virtual ~RGWRESTMgr_SWIFT_Auth() {} virtual RGWRESTMgr *get_resource_mgr(struct req_state *s, const string& uri, string *out_uri) { return this; } virtual RGWHandler *get_handler(struct req_state *s) { return new RGWHandler_SWIFT_Auth; } }; #endif ceph-0.80.11/src/rgw/rgw_common.h0000664000175100017510000010267312623076744020614 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_COMMON_H #define CEPH_RGW_COMMON_H #include "common/ceph_crypto.h" #include "common/debug.h" #include "common/perf_counters.h" #include "acconfig.h" #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "rgw_acl.h" #include "rgw_cors.h" #include "rgw_quota.h" #include "rgw_string.h" #include "cls/version/cls_version_types.h" #include "cls/user/cls_user_types.h" #include "include/rados/librados.hpp" using namespace std; namespace ceph { class Formatter; } using ceph::crypto::MD5; #define RGW_ATTR_PREFIX "user.rgw." #define RGW_HTTP_RGWX_ATTR_PREFIX "RGWX_ATTR_" #define RGW_HTTP_RGWX_ATTR_PREFIX_OUT "Rgwx-Attr-" #define RGW_AMZ_META_PREFIX "x-amz-meta-" #define RGW_SYS_PARAM_PREFIX "rgwx-" #define RGW_ATTR_ACL RGW_ATTR_PREFIX "acl" #define RGW_ATTR_CORS RGW_ATTR_PREFIX "cors" #define RGW_ATTR_ETAG RGW_ATTR_PREFIX "etag" #define RGW_ATTR_BUCKETS RGW_ATTR_PREFIX "buckets" #define RGW_ATTR_META_PREFIX RGW_ATTR_PREFIX RGW_AMZ_META_PREFIX #define RGW_ATTR_CONTENT_TYPE RGW_ATTR_PREFIX "content_type" #define RGW_ATTR_CACHE_CONTROL RGW_ATTR_PREFIX "cache_control" #define RGW_ATTR_CONTENT_DISP RGW_ATTR_PREFIX "content_disposition" #define RGW_ATTR_CONTENT_ENC RGW_ATTR_PREFIX "content_encoding" #define RGW_ATTR_CONTENT_LANG RGW_ATTR_PREFIX "content_language" #define RGW_ATTR_EXPIRES RGW_ATTR_PREFIX "expires" #define RGW_ATTR_ID_TAG RGW_ATTR_PREFIX "idtag" #define RGW_ATTR_SHADOW_OBJ RGW_ATTR_PREFIX "shadow_name" #define RGW_ATTR_MANIFEST RGW_ATTR_PREFIX "manifest" #define RGW_ATTR_USER_MANIFEST RGW_ATTR_PREFIX "user_manifest" #define RGW_BUCKETS_OBJ_SUFFIX ".buckets" #define RGW_MAX_PENDING_CHUNKS 16 #define RGW_MAX_PUT_SIZE (5ULL*1024*1024*1024) #define RGW_MIN_MULTIPART_SIZE (5ULL*1024*1024) #define RGW_FORMAT_PLAIN 0 #define RGW_FORMAT_XML 1 #define RGW_FORMAT_JSON 2 #define RGW_CAP_READ 0x1 #define RGW_CAP_WRITE 0x2 #define RGW_CAP_ALL (RGW_CAP_READ | RGW_CAP_WRITE) #define RGW_REST_SWIFT 0x1 #define RGW_REST_SWIFT_AUTH 0x2 #define RGW_SUSPENDED_USER_AUID (uint64_t)-2 #define RGW_OP_TYPE_READ 0x01 #define RGW_OP_TYPE_WRITE 0x02 #define RGW_OP_TYPE_DELETE 0x04 #define RGW_OP_TYPE_MODIFY (RGW_OP_TYPE_WRITE | RGW_OP_TYPE_DELETE) #define RGW_OP_TYPE_ALL (RGW_OP_TYPE_READ | RGW_OP_TYPE_WRITE | RGW_OP_TYPE_DELETE) #define RGW_DEFAULT_MAX_BUCKETS 1000 #define RGW_DEFER_TO_BUCKET_ACLS_RECURSE 1 #define RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL 2 #define STATUS_CREATED 1900 #define STATUS_ACCEPTED 1901 #define STATUS_NO_CONTENT 1902 #define STATUS_PARTIAL_CONTENT 1903 #define STATUS_REDIRECT 1904 #define STATUS_NO_APPLY 1905 #define STATUS_APPLIED 1906 #define ERR_INVALID_BUCKET_NAME 2000 #define ERR_INVALID_OBJECT_NAME 2001 #define ERR_NO_SUCH_BUCKET 2002 #define ERR_METHOD_NOT_ALLOWED 2003 #define ERR_INVALID_DIGEST 2004 #define ERR_BAD_DIGEST 2005 #define ERR_UNRESOLVABLE_EMAIL 2006 #define ERR_INVALID_PART 2007 #define ERR_INVALID_PART_ORDER 2008 #define ERR_NO_SUCH_UPLOAD 2009 #define ERR_REQUEST_TIMEOUT 2010 #define ERR_LENGTH_REQUIRED 2011 #define ERR_REQUEST_TIME_SKEWED 2012 #define ERR_BUCKET_EXISTS 2013 #define ERR_BAD_URL 2014 #define ERR_PRECONDITION_FAILED 2015 #define ERR_NOT_MODIFIED 2016 #define ERR_INVALID_UTF8 2017 #define ERR_UNPROCESSABLE_ENTITY 2018 #define ERR_TOO_LARGE 2019 #define ERR_TOO_MANY_BUCKETS 2020 #define ERR_INVALID_REQUEST 2021 #define ERR_TOO_SMALL 2022 #define ERR_NOT_FOUND 2023 #define ERR_PERMANENT_REDIRECT 2024 #define ERR_LOCKED 2025 #define ERR_QUOTA_EXCEEDED 2026 #define ERR_USER_SUSPENDED 2100 #define ERR_INTERNAL_ERROR 2200 typedef void *RGWAccessHandle; /* perf counter */ extern PerfCounters *perfcounter; extern int rgw_perf_start(CephContext *cct); extern void rgw_perf_stop(CephContext *cct); enum { l_rgw_first = 15000, l_rgw_req, l_rgw_failed_req, l_rgw_get, l_rgw_get_b, l_rgw_get_lat, l_rgw_put, l_rgw_put_b, l_rgw_put_lat, l_rgw_qlen, l_rgw_qactive, l_rgw_cache_hit, l_rgw_cache_miss, l_rgw_keystone_token_cache_hit, l_rgw_keystone_token_cache_miss, l_rgw_last, }; /* size should be the required string size + 1 */ extern int gen_rand_base64(CephContext *cct, char *dest, int size); extern int gen_rand_alphanumeric(CephContext *cct, char *dest, int size); extern int gen_rand_alphanumeric_upper(CephContext *cct, char *dest, int size); enum RGWIntentEvent { DEL_OBJ = 0, DEL_DIR = 1, }; enum RGWObjCategory { RGW_OBJ_CATEGORY_NONE = 0, RGW_OBJ_CATEGORY_MAIN = 1, RGW_OBJ_CATEGORY_SHADOW = 2, RGW_OBJ_CATEGORY_MULTIMETA = 3, }; /** Store error returns for output at a different point in the program */ struct rgw_err { rgw_err(); rgw_err(int http, const std::string &s3); void clear(); bool is_clear() const; bool is_err() const; friend std::ostream& operator<<(std::ostream& oss, const rgw_err &err); int http_ret; int ret; std::string s3_code; std::string message; }; /* Helper class used for XMLArgs parsing */ class NameVal { string str; string name; string val; public: NameVal(string nv) : str(nv) {} int parse(); string& get_name() { return name; } string& get_val() { return val; } }; /** Stores the XML arguments associated with the HTTP request in req_state*/ class XMLArgs { string str, empty_str; map val_map; map sys_val_map; map sub_resources; bool has_resp_modifier; public: XMLArgs() : has_resp_modifier(false) {} /** Set the arguments; as received */ void set(string s) { has_resp_modifier = false; val_map.clear(); sub_resources.clear(); str = s; } /** parse the received arguments */ int parse(); /** Get the value for a specific argument parameter */ string& get(const string& name, bool *exists = NULL); string& get(const char *name, bool *exists = NULL); int get_bool(const string& name, bool *val, bool *exists); int get_bool(const char *name, bool *val, bool *exists); /** see if a parameter is contained in this XMLArgs */ bool exists(const char *name) { map::iterator iter = val_map.find(name); return (iter != val_map.end()); } bool sub_resource_exists(const char *name) { map::iterator iter = sub_resources.find(name); return (iter != sub_resources.end()); } map& get_params() { return val_map; } map& get_sub_resources() { return sub_resources; } unsigned get_num_params() { return val_map.size(); } bool has_response_modifier() { return has_resp_modifier; } void set_system() { /* make all system params visible */ map::iterator iter; for (iter = sys_val_map.begin(); iter != sys_val_map.end(); ++iter) { val_map[iter->first] = iter->second; } } }; class RGWConf; class RGWEnv { std::map env_map; public: RGWConf *conf; RGWEnv(); ~RGWEnv(); void init(CephContext *cct); void init(CephContext *cct, char **envp); void set(const char *name, const char *val); const char *get(const char *name, const char *def_val = NULL); int get_int(const char *name, int def_val = 0); bool get_bool(const char *name, bool def_val = 0); size_t get_size(const char *name, size_t def_val = 0); bool exists(const char *name); bool exists_prefix(const char *prefix); void remove(const char *name); std::map& get_map() { return env_map; } }; class RGWConf { friend class RGWEnv; protected: void init(CephContext *cct, RGWEnv * env); public: RGWConf() : enable_ops_log(1), enable_usage_log(1), defer_to_bucket_acls(0) {} int enable_ops_log; int enable_usage_log; uint8_t defer_to_bucket_acls; }; enum http_op { OP_GET, OP_PUT, OP_DELETE, OP_HEAD, OP_POST, OP_COPY, OP_OPTIONS, OP_UNKNOWN, }; class RGWAccessControlPolicy; class JSONObj; struct RGWAccessKey { string id; // AccessKey string key; // SecretKey string subuser; RGWAccessKey() {} void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(id, bl); ::encode(key, bl); ::encode(subuser, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN_32(2, 2, 2, bl); ::decode(id, bl); ::decode(key, bl); ::decode(subuser, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void dump_plain(Formatter *f) const; void dump(Formatter *f, const string& user, bool swift) const; static void generate_test_instances(list& o); void decode_json(JSONObj *obj); void decode_json(JSONObj *obj, bool swift); }; WRITE_CLASS_ENCODER(RGWAccessKey); struct RGWSubUser { string name; uint32_t perm_mask; RGWSubUser() : perm_mask(0) {} void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(name, bl); ::encode(perm_mask, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN_32(2, 2, 2, bl); ::decode(name, bl); ::decode(perm_mask, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void dump(Formatter *f, const string& user) const; static void generate_test_instances(list& o); void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWSubUser); class RGWUserCaps { map caps; int get_cap(const string& cap, string& type, uint32_t *perm); int add_cap(const string& cap); int remove_cap(const string& cap); public: static int parse_cap_perm(const string& str, uint32_t *perm); int add_from_string(const string& str); int remove_from_string(const string& str); void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(caps, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(caps, bl); DECODE_FINISH(bl); } int check_cap(const string& cap, uint32_t perm); void dump(Formatter *f) const; void dump(Formatter *f, const char *name) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWUserCaps); void encode_json(const char *name, const obj_version& v, Formatter *f); void encode_json(const char *name, const RGWUserCaps& val, Formatter *f); void decode_json_obj(obj_version& v, JSONObj *obj); struct RGWUserInfo { uint64_t auid; string user_id; string display_name; string user_email; map access_keys; map swift_keys; map subusers; __u8 suspended; uint32_t max_buckets; uint32_t op_mask; RGWUserCaps caps; __u8 system; string default_placement; list placement_tags; RGWQuotaInfo bucket_quota; map temp_url_keys; RGWQuotaInfo user_quota; RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), op_mask(RGW_OP_TYPE_ALL), system(0) {} void encode(bufferlist& bl) const { ENCODE_START(16, 9, bl); ::encode(auid, bl); string access_key; string secret_key; if (!access_keys.empty()) { map::const_iterator iter = access_keys.begin(); const RGWAccessKey& k = iter->second; access_key = k.id; secret_key = k.key; } ::encode(access_key, bl); ::encode(secret_key, bl); ::encode(display_name, bl); ::encode(user_email, bl); string swift_name; string swift_key; if (!swift_keys.empty()) { map::const_iterator iter = swift_keys.begin(); const RGWAccessKey& k = iter->second; swift_name = k.id; swift_key = k.key; } ::encode(swift_name, bl); ::encode(swift_key, bl); ::encode(user_id, bl); ::encode(access_keys, bl); ::encode(subusers, bl); ::encode(suspended, bl); ::encode(swift_keys, bl); ::encode(max_buckets, bl); ::encode(caps, bl); ::encode(op_mask, bl); ::encode(system, bl); ::encode(default_placement, bl); ::encode(placement_tags, bl); ::encode(bucket_quota, bl); ::encode(temp_url_keys, bl); ::encode(user_quota, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN_32(16, 9, 9, bl); if (struct_v >= 2) ::decode(auid, bl); else auid = CEPH_AUTH_UID_DEFAULT; string access_key; string secret_key; ::decode(access_key, bl); ::decode(secret_key, bl); if (struct_v < 6) { RGWAccessKey k; k.id = access_key; k.key = secret_key; access_keys[access_key] = k; } ::decode(display_name, bl); ::decode(user_email, bl); string swift_name; string swift_key; if (struct_v >= 3) ::decode(swift_name, bl); if (struct_v >= 4) ::decode(swift_key, bl); if (struct_v >= 5) ::decode(user_id, bl); else user_id = access_key; if (struct_v >= 6) { ::decode(access_keys, bl); ::decode(subusers, bl); } suspended = 0; if (struct_v >= 7) { ::decode(suspended, bl); } if (struct_v >= 8) { ::decode(swift_keys, bl); } if (struct_v >= 10) { ::decode(max_buckets, bl); } else { max_buckets = RGW_DEFAULT_MAX_BUCKETS; } if (struct_v >= 11) { ::decode(caps, bl); } if (struct_v >= 12) { ::decode(op_mask, bl); } else { op_mask = RGW_OP_TYPE_ALL; } system = 0; if (struct_v >= 13) { ::decode(system, bl); ::decode(default_placement, bl); ::decode(placement_tags, bl); /* tags of allowed placement rules */ } if (struct_v >= 14) { ::decode(bucket_quota, bl); } if (struct_v >= 15) { ::decode(temp_url_keys, bl); } if (struct_v >= 16) { ::decode(user_quota, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); void decode_json(JSONObj *obj); void clear() { user_id.clear(); display_name.clear(); user_email.clear(); auid = CEPH_AUTH_UID_DEFAULT; access_keys.clear(); suspended = 0; } }; WRITE_CLASS_ENCODER(RGWUserInfo) struct rgw_bucket { std::string name; std::string data_pool; std::string data_extra_pool; /* if not set, then we should use data_pool instead */ std::string index_pool; std::string marker; std::string bucket_id; std::string oid; /* * runtime in-memory only info. If not empty, points to the bucket instance object */ rgw_bucket() { } rgw_bucket(const cls_user_bucket& b) { name = b.name; data_pool = b.data_pool; data_extra_pool = b.data_extra_pool; index_pool = b.index_pool; marker = b.marker; bucket_id = b.bucket_id; } rgw_bucket(const char *n) : name(n) { assert(*n == '.'); // only rgw private buckets should be initialized without pool data_pool = index_pool = n; marker = ""; } rgw_bucket(const char *n, const char *dp, const char *ip, const char *m, const char *id, const char *h) : name(n), data_pool(dp), index_pool(ip), marker(m), bucket_id(id) {} void convert(cls_user_bucket *b) { b->name = name; b->data_pool = data_pool; b->data_extra_pool = data_extra_pool; b->index_pool = index_pool; b->marker = marker; b->bucket_id = bucket_id; } void encode(bufferlist& bl) const { ENCODE_START(7, 3, bl); ::encode(name, bl); ::encode(data_pool, bl); ::encode(marker, bl); ::encode(bucket_id, bl); ::encode(index_pool, bl); ::encode(data_extra_pool, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(7, 3, 3, bl); ::decode(name, bl); ::decode(data_pool, bl); if (struct_v >= 2) { ::decode(marker, bl); if (struct_v <= 3) { uint64_t id; ::decode(id, bl); char buf[16]; snprintf(buf, sizeof(buf), "%llu", (long long)id); bucket_id = buf; } else { ::decode(bucket_id, bl); } } if (struct_v >= 5) { ::decode(index_pool, bl); } else { index_pool = data_pool; } if (struct_v >= 7) { ::decode(data_extra_pool, bl); } DECODE_FINISH(bl); } const string& get_data_extra_pool() { if (data_extra_pool.empty()) { return data_pool; } return data_extra_pool; } void dump(Formatter *f) const; void decode_json(JSONObj *obj); static void generate_test_instances(list& o); bool operator<(const rgw_bucket& b) const { return name.compare(b.name) < 0; } }; WRITE_CLASS_ENCODER(rgw_bucket) inline ostream& operator<<(ostream& out, const rgw_bucket &b) { out << b.name; if (b.name.compare(b.data_pool)) { out << "(@"; string s; if (!b.index_pool.empty() && b.data_pool.compare(b.index_pool)) s = "i=" + b.index_pool; if (!b.data_extra_pool.empty() && b.data_pool.compare(b.data_extra_pool)) { if (!s.empty()) { s += ","; } s += "e=" + b.data_extra_pool; } if (!s.empty()) { out << "{" << s << "}"; } out << b.data_pool << "[" << b.marker << "])"; } return out; } struct RGWObjVersionTracker { obj_version read_version; obj_version write_version; obj_version *version_for_read() { return &read_version; } obj_version *version_for_write() { if (write_version.ver == 0) return NULL; return &write_version; } obj_version *version_for_check() { if (read_version.ver == 0) return NULL; return &read_version; } void prepare_op_for_read(librados::ObjectReadOperation *op); void prepare_op_for_write(librados::ObjectWriteOperation *op); void apply_write() { read_version = write_version; write_version = obj_version(); } void clear() { read_version = obj_version(); write_version = obj_version(); } void generate_new_write_ver(CephContext *cct); }; enum RGWBucketFlags { BUCKET_SUSPENDED = 0x1, }; struct RGWBucketInfo { rgw_bucket bucket; string owner; uint32_t flags; string region; time_t creation_time; string placement_rule; bool has_instance_obj; RGWObjVersionTracker objv_tracker; /* we don't need to serialize this, for runtime tracking */ obj_version ep_objv; /* entry point object version, for runtime tracking only */ RGWQuotaInfo quota; void encode(bufferlist& bl) const { ENCODE_START(9, 4, bl); ::encode(bucket, bl); ::encode(owner, bl); ::encode(flags, bl); ::encode(region, bl); uint64_t ct = (uint64_t)creation_time; ::encode(ct, bl); ::encode(placement_rule, bl); ::encode(has_instance_obj, bl); ::encode(quota, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN_32(6, 4, 4, bl); ::decode(bucket, bl); if (struct_v >= 2) ::decode(owner, bl); if (struct_v >= 3) ::decode(flags, bl); if (struct_v >= 5) ::decode(region, bl); if (struct_v >= 6) { uint64_t ct; ::decode(ct, bl); creation_time = (time_t)ct; } if (struct_v >= 7) ::decode(placement_rule, bl); if (struct_v >= 8) ::decode(has_instance_obj, bl); if (struct_v >= 9) ::decode(quota, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); void decode_json(JSONObj *obj); RGWBucketInfo() : flags(0), creation_time(0), has_instance_obj(false) {} }; WRITE_CLASS_ENCODER(RGWBucketInfo) struct RGWBucketEntryPoint { rgw_bucket bucket; string owner; time_t creation_time; bool linked; bool has_bucket_info; RGWBucketInfo old_bucket_info; RGWBucketEntryPoint() : creation_time(0), linked(false), has_bucket_info(false) {} void encode(bufferlist& bl) const { ENCODE_START(8, 8, bl); ::encode(bucket, bl); ::encode(owner, bl); ::encode(linked, bl); uint64_t ctime = (uint64_t)creation_time; ::encode(ctime, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { bufferlist::iterator orig_iter = bl; DECODE_START_LEGACY_COMPAT_LEN_32(8, 4, 4, bl); if (struct_v < 8) { /* ouch, old entry, contains the bucket info itself */ old_bucket_info.decode(orig_iter); has_bucket_info = true; return; } has_bucket_info = false; ::decode(bucket, bl); ::decode(owner, bl); ::decode(linked, bl); uint64_t ctime; ::decode(ctime, bl); creation_time = (uint64_t)ctime; DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWBucketEntryPoint) struct RGWStorageStats { RGWObjCategory category; uint64_t num_kb; uint64_t num_kb_rounded; uint64_t num_objects; RGWStorageStats() : category(RGW_OBJ_CATEGORY_NONE), num_kb(0), num_kb_rounded(0), num_objects(0) {} }; struct req_state; class RGWEnv; class RGWClientIO; struct req_info { RGWEnv *env; XMLArgs args; map x_meta_map; const char *host; const char *method; string script_uri; string request_uri; string effective_uri; string request_params; req_info(CephContext *cct, RGWEnv *_env); void rebuild_from(req_info& src); void init_meta_info(bool *found_bad_meta); }; /** Store all the state necessary to complete and respond to an HTTP request*/ struct req_state { CephContext *cct; RGWClientIO *cio; http_op op; bool content_started; int format; ceph::Formatter *formatter; string decoded_uri; string relative_uri; const char *length; int64_t content_length; map generic_attrs; struct rgw_err err; bool expect_cont; bool header_ended; uint64_t obj_size; bool enable_ops_log; bool enable_usage_log; uint8_t defer_to_bucket_acls; uint32_t perm_mask; utime_t header_time; const char *object; rgw_bucket bucket; string bucket_name_str; string object_str; string src_bucket_name; string src_object; ACLOwner bucket_owner; ACLOwner owner; string bucket_instance_id; RGWBucketInfo bucket_info; map bucket_attrs; bool bucket_exists; bool has_bad_meta; RGWUserInfo user; RGWAccessControlPolicy *bucket_acl; RGWAccessControlPolicy *object_acl; bool system_request; string canned_acl; bool has_acl_header; const char *copy_source; const char *http_auth; bool local_source; /* source is local */ int prot_flags; const char *os_auth_token; string swift_user; string swift_groups; utime_t time; void *obj_ctx; string dialect; string req_id; req_info info; req_state(CephContext *_cct, class RGWEnv *e); ~req_state(); }; /** Store basic data on an object */ struct RGWObjEnt { std::string name; std::string ns; std::string owner; std::string owner_display_name; uint64_t size; utime_t mtime; string etag; string content_type; string tag; RGWObjEnt() : size(0) {} void dump(Formatter *f) const; }; /** Store basic data on bucket */ struct RGWBucketEnt { rgw_bucket bucket; size_t size; size_t size_rounded; time_t creation_time; uint64_t count; RGWBucketEnt() : size(0), size_rounded(0), creation_time(0), count(0) {} RGWBucketEnt(const cls_user_bucket_entry& e) { bucket = e.bucket; size = e.size; size_rounded = e.size_rounded; creation_time = e.creation_time; count = e.count; } void convert(cls_user_bucket_entry *b) { bucket.convert(&b->bucket); b->size = size; b->size_rounded = size_rounded; b->creation_time = creation_time; b->count = count; } void encode(bufferlist& bl) const { ENCODE_START(5, 5, bl); uint64_t s = size; __u32 mt = creation_time; string empty_str; // originally had the bucket name here, but we encode bucket later ::encode(empty_str, bl); ::encode(s, bl); ::encode(mt, bl); ::encode(count, bl); ::encode(bucket, bl); s = size_rounded; ::encode(s, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 5, 5, bl); __u32 mt; uint64_t s; string empty_str; // backward compatibility ::decode(empty_str, bl); ::decode(s, bl); ::decode(mt, bl); size = s; creation_time = mt; if (struct_v >= 2) ::decode(count, bl); if (struct_v >= 3) ::decode(bucket, bl); if (struct_v >= 4) ::decode(s, bl); size_rounded = s; DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(RGWBucketEnt) class rgw_obj { std::string orig_obj; std::string orig_key; public: rgw_bucket bucket; std::string key; std::string ns; std::string object; bool in_extra_data; /* in-memory only member, does not serialize */ rgw_obj() : in_extra_data(false) {} rgw_obj(const char *b, const char *o) : in_extra_data(false) { rgw_bucket _b(b); std::string _o(o); init(_b, _o); } rgw_obj(rgw_bucket& b, const char *o) : in_extra_data(false) { std::string _o(o); init(b, _o); } rgw_obj(rgw_bucket& b, const std::string& o) : in_extra_data(false) { init(b, o); } rgw_obj(rgw_bucket& b, const std::string& o, const std::string& k) : in_extra_data(false) { init(b, o, k); } rgw_obj(rgw_bucket& b, const std::string& o, const std::string& k, const std::string& n) : in_extra_data(false) { init(b, o, k, n); } void init(rgw_bucket& b, const std::string& o, const std::string& k, const std::string& n) { bucket = b; set_ns(n); set_obj(o); set_key(k); } void init(rgw_bucket& b, const std::string& o, const std::string& k) { bucket = b; set_obj(o); set_key(k); } void init(rgw_bucket& b, const std::string& o) { bucket = b; set_obj(o); orig_key = key = o; } void init_ns(rgw_bucket& b, const std::string& o, const std::string& n) { bucket = b; set_ns(n); set_obj(o); reset_key(); } int set_ns(const char *n) { if (!n) return -EINVAL; string ns_str(n); return set_ns(ns_str); } int set_ns(const string& n) { if (n[0] == '_') return -EINVAL; ns = n; set_obj(orig_obj); return 0; } void set_key(const string& k) { orig_key = k; key = k; } void reset_key() { orig_key.clear(); key.clear(); } void set_obj(const string& o) { orig_obj = o; if (ns.empty()) { if (o.empty()) return; if (o.size() < 1 || o[0] != '_') { object = o; return; } object = "_"; object.append(o); } else { object = "_"; object.append(ns); object.append("_"); object.append(o); } if (orig_key.size()) set_key(orig_key); else set_key(orig_obj); } string loc() { if (orig_key.empty()) return orig_obj; else return orig_key; } /** * Translate a namespace-mangled object name to the user-facing name * existing in the given namespace. * * If the object is part of the given namespace, it returns true * and cuts down the name to the unmangled version. If it is not * part of the given namespace, it returns false. */ static bool translate_raw_obj_to_obj_in_ns(string& obj, string& ns) { if (ns.empty()) { if (obj[0] != '_') return true; if (obj.size() >= 2 && obj[1] == '_') { obj = obj.substr(1); return true; } return false; } if (obj[0] != '_' || obj.size() < 3) // for namespace, min size would be 3: _x_ return false; int pos = obj.find('_', 1); if (pos <= 1) // if it starts with __, it's not in our namespace return false; string obj_ns = obj.substr(1, pos - 1); if (obj_ns.compare(ns) != 0) return false; obj = obj.substr(pos + 1); return true; } /** * Given a mangled object name and an empty namespace string, this * function extracts the namespace into the string and sets the object * name to be the unmangled version. * * It returns true after successfully doing so, or * false if it fails. */ static bool strip_namespace_from_object(string& obj, string& ns) { ns.clear(); if (obj[0] != '_') { return true; } size_t pos = obj.find('_', 1); if (pos == string::npos) { return false; } size_t period_pos = obj.find('.'); if (period_pos < pos) { return false; } ns = obj.substr(1, pos-1); obj = obj.substr(pos+1, string::npos); return true; } void set_in_extra_data(bool val) { in_extra_data = val; } bool is_in_extra_data() const { return in_extra_data; } void encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(bucket.name, bl); ::encode(key, bl); ::encode(ns, bl); ::encode(object, bl); ::encode(bucket, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); ::decode(bucket.name, bl); ::decode(key, bl); ::decode(ns, bl); ::decode(object, bl); if (struct_v >= 2) ::decode(bucket, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); bool operator==(const rgw_obj& o) const { return (object.compare(o.object) == 0) && (bucket.name.compare(o.bucket.name) == 0) && (ns.compare(o.ns) == 0); } bool operator<(const rgw_obj& o) const { int r = bucket.name.compare(o.bucket.name); if (r == 0) { r = object.compare(o.object); if (r == 0) { r = ns.compare(o.ns); } } return (r < 0); } }; WRITE_CLASS_ENCODER(rgw_obj) inline ostream& operator<<(ostream& out, const rgw_obj &o) { return out << o.bucket.name << ":" << o.object; } static inline bool str_startswith(const string& str, const string& prefix) { return (str.compare(0, prefix.size(), prefix) == 0); } static inline void buf_to_hex(const unsigned char *buf, int len, char *str) { int i; str[0] = '\0'; for (i = 0; i < len; i++) { sprintf(&str[i*2], "%02x", (int)buf[i]); } } static inline int hexdigit(char c) { if (c >= '0' && c <= '9') return (c - '0'); c = toupper(c); if (c >= 'A' && c <= 'F') return c - 'A' + 0xa; return -EINVAL; } static inline int hex_to_buf(const char *hex, char *buf, int len) { int i = 0; const char *p = hex; while (*p) { if (i >= len) return -EINVAL; buf[i] = 0; int d = hexdigit(*p); if (d < 0) return d; buf[i] = d << 4; p++; if (!*p) return -EINVAL; d = hexdigit(*p); if (d < 0) return -d; buf[i] += d; i++; p++; } return i; } static inline int rgw_str_to_bool(const char *s, int def_val) { if (!s) return def_val; return (strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "1") == 0); } static inline void append_rand_alpha(CephContext *cct, string& src, string& dest, int len) { dest = src; char buf[len + 1]; gen_rand_alphanumeric(cct, buf, len); dest.append("_"); dest.append(buf); } static inline const char *rgw_obj_category_name(RGWObjCategory category) { switch (category) { case RGW_OBJ_CATEGORY_NONE: return "rgw.none"; case RGW_OBJ_CATEGORY_MAIN: return "rgw.main"; case RGW_OBJ_CATEGORY_SHADOW: return "rgw.shadow"; case RGW_OBJ_CATEGORY_MULTIMETA: return "rgw.multimeta"; } return "unknown"; } static inline uint64_t rgw_rounded_kb(uint64_t bytes) { return (bytes + 1023) / 1024; } static inline uint64_t rgw_rounded_objsize_kb(uint64_t bytes) { return ((bytes + 4095) & ~4095) / 1024; } extern string rgw_string_unquote(const string& s); extern void parse_csv_string(const string& ival, vector& ovals); extern int parse_key_value(string& in_str, string& key, string& val); extern int parse_key_value(string& in_str, const char *delim, string& key, string& val); /** time parsing */ extern int parse_time(const char *time_str, time_t *time); extern bool parse_rfc2616(const char *s, struct tm *t); extern bool parse_iso8601(const char *s, struct tm *t); extern string rgw_trim_whitespace(const string& src); extern string rgw_trim_quotes(const string& val); /** Check if the req_state's user has the necessary permissions * to do the requested action */ extern bool verify_bucket_permission(struct req_state *s, int perm); extern bool verify_object_permission(struct req_state *s, RGWAccessControlPolicy *bucket_acl, RGWAccessControlPolicy *object_acl, int perm); extern bool verify_object_permission(struct req_state *s, int perm); /** Convert an input URL into a sane object name * by converting %-escaped strings into characters, etc*/ extern bool url_decode(string& src_str, string& dest_str, bool in_query = false); extern void url_encode(const string& src, string& dst); extern void calc_hmac_sha1(const char *key, int key_len, const char *msg, int msg_len, char *dest); /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */ extern int rgw_parse_op_type_list(const string& str, uint32_t *perm); #endif ceph-0.80.11/src/rgw/rgw_http_client.cc0000664000175100017510000001754612623076744022003 0ustar jenkins-buildjenkins-build#include #include #include #include "rgw_common.h" #include "rgw_http_client.h" #define dout_subsys ceph_subsys_rgw static size_t receive_http_header(void *ptr, size_t size, size_t nmemb, void *_info) { RGWHTTPClient *client = static_cast(_info); size_t len = size * nmemb; int ret = client->receive_header(ptr, size * nmemb); if (ret < 0) { dout(0) << "WARNING: client->receive_header() returned ret=" << ret << dendl; } return len; } static size_t receive_http_data(void *ptr, size_t size, size_t nmemb, void *_info) { RGWHTTPClient *client = static_cast(_info); size_t len = size * nmemb; int ret = client->receive_data(ptr, size * nmemb); if (ret < 0) { dout(0) << "WARNING: client->receive_data() returned ret=" << ret << dendl; } return len; } static size_t send_http_data(void *ptr, size_t size, size_t nmemb, void *_info) { RGWHTTPClient *client = static_cast(_info); int ret = client->send_data(ptr, size * nmemb); if (ret < 0) { dout(0) << "WARNING: client->receive_data() returned ret=" << ret << dendl; } return ret; } static curl_slist *headers_to_slist(list >& headers) { curl_slist *h = NULL; list >::iterator iter; for (iter = headers.begin(); iter != headers.end(); ++iter) { pair& p = *iter; string val = p.first; if (strncmp(val.c_str(), "HTTP_", 5) == 0) { val = val.substr(5); } /* we need to convert all underscores into dashes as some web servers forbid them * in the http header field names */ for (size_t i = 0; i < val.size(); i++) { if (val[i] == '_') { val[i] = '-'; } } val.append(": "); val.append(p.second); h = curl_slist_append(h, val.c_str()); } return h; } int RGWHTTPClient::process(const char *method, const char *url) { int ret = 0; CURL *curl_handle; char error_buf[CURL_ERROR_SIZE]; curl_handle = curl_easy_init(); dout(20) << "sending request to " << url << dendl; curl_slist *h = headers_to_slist(headers); curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, method); curl_easy_setopt(curl_handle, CURLOPT_URL, url); curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, receive_http_header); curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *)this); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, receive_http_data); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)this); curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, (void *)error_buf); if (h) { curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, (void *)h); } curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, send_http_data); curl_easy_setopt(curl_handle, CURLOPT_READDATA, (void *)this); curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1L); if (has_send_len) { curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE, (void *)send_len); } CURLcode status = curl_easy_perform(curl_handle); if (status) { dout(0) << "curl_easy_performed returned error: " << error_buf << dendl; ret = -EINVAL; } curl_easy_cleanup(curl_handle); curl_slist_free_all(h); return ret; } struct multi_req_data { CURL *easy_handle; CURLM *multi_handle; curl_slist *h; multi_req_data() : easy_handle(NULL), multi_handle(NULL), h(NULL) {} ~multi_req_data() { if (multi_handle) curl_multi_cleanup(multi_handle); if (easy_handle) curl_easy_cleanup(easy_handle); if (h) curl_slist_free_all(h); } }; int RGWHTTPClient::init_async(const char *method, const char *url, void **handle) { CURL *easy_handle; CURLM *multi_handle; multi_req_data *req_data = new multi_req_data; *handle = (void *)req_data; char error_buf[CURL_ERROR_SIZE]; multi_handle = curl_multi_init(); easy_handle = curl_easy_init(); req_data->multi_handle = multi_handle; req_data->easy_handle = easy_handle; CURLMcode mstatus = curl_multi_add_handle(multi_handle, easy_handle); if (mstatus) { dout(0) << "ERROR: failed on curl_multi_add_handle, status=" << mstatus << dendl; delete req_data; return -EIO; } dout(20) << "sending request to " << url << dendl; curl_slist *h = headers_to_slist(headers); req_data->h = h; curl_easy_setopt(easy_handle, CURLOPT_CUSTOMREQUEST, method); curl_easy_setopt(easy_handle, CURLOPT_URL, url); curl_easy_setopt(easy_handle, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(easy_handle, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(easy_handle, CURLOPT_HEADERFUNCTION, receive_http_header); curl_easy_setopt(easy_handle, CURLOPT_WRITEHEADER, (void *)this); curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, receive_http_data); curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *)this); curl_easy_setopt(easy_handle, CURLOPT_ERRORBUFFER, (void *)error_buf); if (h) { curl_easy_setopt(easy_handle, CURLOPT_HTTPHEADER, (void *)h); } curl_easy_setopt(easy_handle, CURLOPT_READFUNCTION, send_http_data); curl_easy_setopt(easy_handle, CURLOPT_READDATA, (void *)this); curl_easy_setopt(easy_handle, CURLOPT_UPLOAD, 1L); if (has_send_len) { curl_easy_setopt(easy_handle, CURLOPT_INFILESIZE, (void *)send_len); } return 0; } #if HAVE_CURL_MULTI_WAIT static int do_curl_wait(CephContext *cct, CURLM *handle) { int num_fds; int ret = curl_multi_wait(handle, NULL, 0, cct->_conf->rgw_curl_wait_timeout_ms, &num_fds); if (ret) { dout(0) << "ERROR: curl_multi_wait() returned " << ret << dendl; return -EIO; } return 0; } #else static int do_curl_wait(CephContext *cct, CURLM *handle) { fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* get file descriptors from the transfers */ int ret = curl_multi_fdset(handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (ret) { dout(0) << "ERROR: curl_multi_fdset returned " << ret << dendl; return -EIO; } /* forcing a strict timeout, as the returned fdsets might not reference all fds we wait on */ uint64_t to = cct->_conf->rgw_curl_wait_timeout_ms; #define RGW_CURL_TIMEOUT 1000 if (!to) to = RGW_CURL_TIMEOUT; struct timeval timeout; timeout.tv_sec = to / 1000; timeout.tv_usec = to % 1000; ret = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); if (ret < 0) { ret = -errno; dout(0) << "ERROR: select returned " << ret << dendl; return ret; } return 0; } #endif int RGWHTTPClient::process_request(void *handle, bool wait_for_data, bool *done) { multi_req_data *req_data = static_cast(handle); int still_running; int mstatus; do { if (wait_for_data) { int ret = do_curl_wait(cct, req_data->multi_handle); if (ret < 0) { return ret; } } mstatus = curl_multi_perform(req_data->multi_handle, &still_running); dout(20) << "curl_multi_perform returned: " << mstatus << dendl; switch (mstatus) { case CURLM_OK: case CURLM_CALL_MULTI_PERFORM: break; default: return -EINVAL; } int msgs_left; CURLMsg *msg; while ((msg = curl_multi_info_read(req_data->multi_handle, &msgs_left))) { if (msg->msg == CURLMSG_DONE) { switch (msg->data.result) { case CURLE_OK: break; default: dout(20) << "ERROR: msg->data.result=" << msg->data.result << dendl; return -EIO; } } } } while (mstatus == CURLM_CALL_MULTI_PERFORM); *done = (still_running == 0); return 0; } int RGWHTTPClient::complete_request(void *handle) { bool done; int ret; do { ret = process_request(handle, true, &done); } while (!done && !ret); multi_req_data *req_data = static_cast(handle); delete req_data; return ret; } ceph-0.80.11/src/rgw/rgw_gc.cc0000664000175100017510000001654412623076744020054 0ustar jenkins-buildjenkins-build #include "rgw_gc.h" #include "include/rados/librados.hpp" #include "cls/rgw/cls_rgw_client.h" #include "cls/refcount/cls_refcount_client.h" #include "cls/lock/cls_lock_client.h" #include "auth/Crypto.h" #include #define dout_subsys ceph_subsys_rgw using namespace std; using namespace librados; static string gc_oid_prefix = "gc"; static string gc_index_lock_name = "gc_process"; #define HASH_PRIME 7877 void RGWGC::initialize(CephContext *_cct, RGWRados *_store) { cct = _cct; store = _store; max_objs = cct->_conf->rgw_gc_max_objs; if (max_objs > HASH_PRIME) max_objs = HASH_PRIME; obj_names = new string[max_objs]; for (int i = 0; i < max_objs; i++) { obj_names[i] = gc_oid_prefix; char buf[32]; snprintf(buf, 32, ".%d", i); obj_names[i].append(buf); } } void RGWGC::finalize() { delete[] obj_names; } int RGWGC::tag_index(const string& tag) { return ceph_str_hash_linux(tag.c_str(), tag.size()) % HASH_PRIME % max_objs; } void RGWGC::add_chain(ObjectWriteOperation& op, cls_rgw_obj_chain& chain, const string& tag) { cls_rgw_gc_obj_info info; info.chain = chain; info.tag = tag; cls_rgw_gc_set_entry(op, cct->_conf->rgw_gc_obj_min_wait, info); } int RGWGC::send_chain(cls_rgw_obj_chain& chain, const string& tag, bool sync) { ObjectWriteOperation op; add_chain(op, chain, tag); int i = tag_index(tag); if (sync) return store->gc_operate(obj_names[i], &op); return store->gc_aio_operate(obj_names[i], &op); } int RGWGC::defer_chain(const string& tag, bool sync) { ObjectWriteOperation op; cls_rgw_gc_defer_entry(op, cct->_conf->rgw_gc_obj_min_wait, tag); int i = tag_index(tag); if (sync) return store->gc_operate(obj_names[i], &op); return store->gc_aio_operate(obj_names[i], &op); } int RGWGC::remove(int index, const std::list& tags) { ObjectWriteOperation op; cls_rgw_gc_remove(op, tags); return store->gc_operate(obj_names[index], &op); } int RGWGC::list(int *index, string& marker, uint32_t max, bool expired_only, std::list& result, bool *truncated) { result.clear(); for (; *index < cct->_conf->rgw_gc_max_objs && result.size() < max; (*index)++, marker.clear()) { std::list entries; int ret = cls_rgw_gc_list(store->gc_pool_ctx, obj_names[*index], marker, max - result.size(), expired_only, entries, truncated); if (ret == -ENOENT) continue; if (ret < 0) return ret; std::list::iterator iter; for (iter = entries.begin(); iter != entries.end(); ++iter) { result.push_back(*iter); } if (*index == cct->_conf->rgw_gc_max_objs - 1) { /* we cut short here, truncated will hold the correct value */ return 0; } if (result.size() == max) { /* close approximation, it might be that the next of the objects don't hold * anything, in this case truncated should have been false, but we can find * that out on the next iteration */ *truncated = true; return 0; } } *truncated = false; return 0; } int RGWGC::process(int index, int max_secs) { rados::cls::lock::Lock l(gc_index_lock_name); utime_t end = ceph_clock_now(g_ceph_context); std::list remove_tags; /* max_secs should be greater than zero. We don't want a zero max_secs * to be translated as no timeout, since we'd then need to break the * lock and that would require a manual intervention. In this case * we can just wait it out. */ if (max_secs <= 0) return -EAGAIN; end += max_secs; utime_t time(max_secs, 0); l.set_duration(time); int ret = l.lock_exclusive(&store->gc_pool_ctx, obj_names[index]); if (ret == -EBUSY) { /* already locked by another gc processor */ dout(0) << "RGWGC::process() failed to acquire lock on " << obj_names[index] << dendl; return 0; } if (ret < 0) return ret; string marker; bool truncated; IoCtx *ctx = NULL; do { int max = 100; std::list entries; ret = cls_rgw_gc_list(store->gc_pool_ctx, obj_names[index], marker, max, true, entries, &truncated); if (ret == -ENOENT) { ret = 0; goto done; } if (ret < 0) goto done; string last_pool; ctx = new IoCtx; std::list::iterator iter; for (iter = entries.begin(); iter != entries.end(); ++iter) { bool remove_tag; cls_rgw_gc_obj_info& info = *iter; std::list::iterator liter; cls_rgw_obj_chain& chain = info.chain; utime_t now = ceph_clock_now(g_ceph_context); if (now >= end) goto done; remove_tag = true; for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) { cls_rgw_obj& obj = *liter; if (obj.pool != last_pool) { delete ctx; ctx = new IoCtx; ret = store->rados->ioctx_create(obj.pool.c_str(), *ctx); if (ret < 0) { dout(0) << "ERROR: failed to create ioctx pool=" << obj.pool << dendl; continue; } last_pool = obj.pool; } ctx->locator_set_key(obj.key); dout(0) << "gc::process: removing " << obj.pool << ":" << obj.oid << dendl; ObjectWriteOperation op; cls_refcount_put(op, info.tag, true); ret = ctx->operate(obj.oid, &op); if (ret == -ENOENT) ret = 0; if (ret < 0) { remove_tag = false; dout(0) << "failed to remove " << obj.pool << ":" << obj.oid << "@" << obj.key << dendl; } if (going_down()) // leave early, even if tag isn't removed, it's ok goto done; } if (remove_tag) { remove_tags.push_back(info.tag); #define MAX_REMOVE_CHUNK 16 if (remove_tags.size() > MAX_REMOVE_CHUNK) { remove(index, remove_tags); remove_tags.clear(); } } } } while (truncated); done: if (!remove_tags.empty()) remove(index, remove_tags); l.unlock(&store->gc_pool_ctx, obj_names[index]); delete ctx; return 0; } int RGWGC::process() { int max_objs = cct->_conf->rgw_gc_max_objs; int max_secs = cct->_conf->rgw_gc_processor_max_time; unsigned start; int ret = get_random_bytes((char *)&start, sizeof(start)); if (ret < 0) return ret; for (int i = 0; i < max_objs; i++) { int index = (i + start) % max_objs; ret = process(index, max_secs); if (ret < 0) return ret; } return 0; } bool RGWGC::going_down() { return (down_flag.read() != 0); } void RGWGC::start_processor() { worker = new GCWorker(cct, this); worker->create(); } void RGWGC::stop_processor() { down_flag.set(1); if (worker) { worker->stop(); worker->join(); } delete worker; worker = NULL; } void *RGWGC::GCWorker::entry() { do { utime_t start = ceph_clock_now(cct); dout(2) << "garbage collection: start" << dendl; int r = gc->process(); if (r < 0) { dout(0) << "ERROR: garbage collection process() returned error r=" << r << dendl; } dout(2) << "garbage collection: stop" << dendl; if (gc->going_down()) break; utime_t end = ceph_clock_now(cct); end -= start; int secs = cct->_conf->rgw_gc_processor_period; if (secs <= end.sec()) continue; // next round secs -= end.sec(); lock.Lock(); cond.WaitInterval(cct, lock, utime_t(secs, 0)); lock.Unlock(); } while (!gc->going_down()); return NULL; } void RGWGC::GCWorker::stop() { Mutex::Locker l(lock); cond.Signal(); } ceph-0.80.11/src/rgw/rgw_metadata.cc0000664000175100017510000003660412623076744021242 0ustar jenkins-buildjenkins-build #include "common/ceph_json.h" #include "rgw_metadata.h" #include "cls/version/cls_version_types.h" #include "rgw_rados.h" #include "rgw_tools.h" #define dout_subsys ceph_subsys_rgw struct LogStatusDump { RGWMDLogStatus status; LogStatusDump(RGWMDLogStatus _status) : status(_status) {} void dump(Formatter *f) const { string s; switch (status) { case MDLOG_STATUS_WRITE: s = "write"; break; case MDLOG_STATUS_SETATTRS: s = "set_attrs"; break; case MDLOG_STATUS_REMOVE: s = "remove"; break; case MDLOG_STATUS_COMPLETE: s = "complete"; break; case MDLOG_STATUS_ABORT: s = "abort"; break; default: s = "unknown"; break; } encode_json("status", s, f); } }; struct RGWMetadataLogData { obj_version read_version; obj_version write_version; RGWMDLogStatus status; RGWMetadataLogData() : status(MDLOG_STATUS_UNKNOWN) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(read_version, bl); ::encode(write_version, bl); uint32_t s = (uint32_t)status; ::encode(s, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(read_version, bl); ::decode(write_version, bl); uint32_t s; ::decode(s, bl); status = (RGWMDLogStatus)s; DECODE_FINISH(bl); } void dump(Formatter *f) const { encode_json("read_version", read_version, f); encode_json("write_version", write_version, f); encode_json("status", LogStatusDump(status), f); }; }; WRITE_CLASS_ENCODER(RGWMetadataLogData); int RGWMetadataLog::add_entry(RGWRados *store, RGWMetadataHandler *handler, const string& section, const string& key, bufferlist& bl) { if (!store->need_to_log_metadata()) return 0; string oid; string hash_key; handler->get_hash_key(section, key, hash_key); store->shard_name(prefix, cct->_conf->rgw_md_log_max_shards, hash_key, oid); utime_t now = ceph_clock_now(cct); return store->time_log_add(oid, now, section, key, bl); } void RGWMetadataLog::init_list_entries(int shard_id, utime_t& from_time, utime_t& end_time, string& marker, void **handle) { LogListCtx *ctx = new LogListCtx(); ctx->cur_shard = shard_id; ctx->from_time = from_time; ctx->end_time = end_time; ctx->marker = marker; get_shard_oid(ctx->cur_shard, ctx->cur_oid); *handle = (void *)ctx; } void RGWMetadataLog::complete_list_entries(void *handle) { LogListCtx *ctx = static_cast(handle); delete ctx; } int RGWMetadataLog::list_entries(void *handle, int max_entries, list& entries, string *last_marker, bool *truncated) { LogListCtx *ctx = static_cast(handle); if (!max_entries) { *truncated = false; return 0; } int ret = store->time_log_list(ctx->cur_oid, ctx->from_time, ctx->end_time, max_entries, entries, ctx->marker, last_marker, truncated); if ((ret < 0) && (ret != -ENOENT)) return ret; if (ret == -ENOENT) *truncated = false; return 0; } int RGWMetadataLog::get_info(int shard_id, RGWMetadataLogInfo *info) { string oid; get_shard_oid(shard_id, oid); cls_log_header header; int ret = store->time_log_info(oid, &header); if ((ret < 0) && (ret != -ENOENT)) return ret; info->marker = header.max_marker; info->last_update = header.max_time; return 0; } int RGWMetadataLog::trim(int shard_id, const utime_t& from_time, const utime_t& end_time, const string& start_marker, const string& end_marker) { string oid; get_shard_oid(shard_id, oid); int ret; ret = store->time_log_trim(oid, from_time, end_time, start_marker, end_marker); if (ret == -ENOENT) ret = 0; return ret; } int RGWMetadataLog::lock_exclusive(int shard_id, utime_t& duration, string& zone_id, string& owner_id) { string oid; get_shard_oid(shard_id, oid); return store->lock_exclusive(store->zone.log_pool, oid, duration, zone_id, owner_id); } int RGWMetadataLog::unlock(int shard_id, string& zone_id, string& owner_id) { string oid; get_shard_oid(shard_id, oid); return store->unlock(store->zone.log_pool, oid, zone_id, owner_id); } obj_version& RGWMetadataObject::get_version() { return objv; } class RGWMetadataTopHandler : public RGWMetadataHandler { struct iter_data { list sections; list::iterator iter; }; public: RGWMetadataTopHandler() {} virtual string get_type() { return string(); } virtual int get(RGWRados *store, string& entry, RGWMetadataObject **obj) { return -ENOTSUP; } virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj, sync_type_t sync_type) { return -ENOTSUP; } virtual void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) {} virtual int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) { return -ENOTSUP; } virtual int list_keys_init(RGWRados *store, void **phandle) { iter_data *data = new iter_data; store->meta_mgr->get_sections(data->sections); data->iter = data->sections.begin(); *phandle = data; return 0; } virtual int list_keys_next(void *handle, int max, list& keys, bool *truncated) { iter_data *data = static_cast(handle); for (int i = 0; i < max && data->iter != data->sections.end(); ++i, ++(data->iter)) { keys.push_back(*data->iter); } *truncated = (data->iter != data->sections.end()); return 0; } virtual void list_keys_complete(void *handle) { iter_data *data = static_cast(handle); delete data; } }; static RGWMetadataTopHandler md_top_handler; RGWMetadataManager::RGWMetadataManager(CephContext *_cct, RGWRados *_store) : cct(_cct), store(_store) { md_log = new RGWMetadataLog(_cct, _store); } RGWMetadataManager::~RGWMetadataManager() { map::iterator iter; for (iter = handlers.begin(); iter != handlers.end(); ++iter) { delete iter->second; } handlers.clear(); delete md_log; } int RGWMetadataManager::register_handler(RGWMetadataHandler *handler) { string type = handler->get_type(); if (handlers.find(type) != handlers.end()) return -EINVAL; handlers[type] = handler; return 0; } RGWMetadataHandler *RGWMetadataManager::get_handler(const char *type) { map::iterator iter = handlers.find(type); if (iter == handlers.end()) return NULL; return iter->second; } void RGWMetadataManager::parse_metadata_key(const string& metadata_key, string& type, string& entry) { int pos = metadata_key.find(':'); if (pos < 0) { type = metadata_key; } type = metadata_key.substr(0, pos); entry = metadata_key.substr(pos + 1); } int RGWMetadataManager::find_handler(const string& metadata_key, RGWMetadataHandler **handler, string& entry) { string type; parse_metadata_key(metadata_key, type, entry); if (type.empty()) { *handler = &md_top_handler; return 0; } map::iterator iter = handlers.find(type); if (iter == handlers.end()) return -ENOENT; *handler = iter->second; return 0; } int RGWMetadataManager::get(string& metadata_key, Formatter *f) { RGWMetadataHandler *handler; string entry; int ret = find_handler(metadata_key, &handler, entry); if (ret < 0) { return ret; } RGWMetadataObject *obj; ret = handler->get(store, entry, &obj); if (ret < 0) { return ret; } f->open_object_section("metadata_info"); encode_json("key", metadata_key, f); encode_json("ver", obj->get_version(), f); time_t mtime = obj->get_mtime(); if (mtime > 0) { encode_json("mtime", mtime, f); } encode_json("data", *obj, f); f->close_section(); delete obj; return 0; } int RGWMetadataManager::put(string& metadata_key, bufferlist& bl, RGWMetadataHandler::sync_type_t sync_type, obj_version *existing_version) { RGWMetadataHandler *handler; string entry; int ret = find_handler(metadata_key, &handler, entry); if (ret < 0) return ret; JSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { return -EINVAL; } RGWObjVersionTracker objv_tracker; obj_version *objv = &objv_tracker.write_version; time_t mtime = 0; JSONDecoder::decode_json("key", metadata_key, &parser); JSONDecoder::decode_json("ver", *objv, &parser); JSONDecoder::decode_json("mtime", mtime, &parser); JSONObj *jo = parser.find_obj("data"); if (!jo) { return -EINVAL; } ret = handler->put(store, entry, objv_tracker, mtime, jo, sync_type); if (existing_version) { *existing_version = objv_tracker.read_version; } return ret; } int RGWMetadataManager::remove(string& metadata_key) { RGWMetadataHandler *handler; string entry; int ret = find_handler(metadata_key, &handler, entry); if (ret < 0) return ret; RGWMetadataObject *obj; ret = handler->get(store, entry, &obj); if (ret < 0) { return ret; } RGWObjVersionTracker objv_tracker; objv_tracker.read_version = obj->get_version(); delete obj; return handler->remove(store, entry, objv_tracker); } int RGWMetadataManager::lock_exclusive(string& metadata_key, utime_t duration, string& owner_id) { RGWMetadataHandler *handler; string entry; string zone_id; int ret = find_handler(metadata_key, &handler, entry); if (ret < 0) return ret; rgw_bucket pool; string oid; handler->get_pool_and_oid(store, entry, pool, oid); return store->lock_exclusive(pool, oid, duration, zone_id, owner_id); } int RGWMetadataManager::unlock(string& metadata_key, string& owner_id) { librados::IoCtx io_ctx; RGWMetadataHandler *handler; string entry; string zone_id; int ret = find_handler(metadata_key, &handler, entry); if (ret < 0) return ret; rgw_bucket pool; string oid; handler->get_pool_and_oid(store, entry, pool, oid); return store->unlock(pool, oid, zone_id, owner_id); } struct list_keys_handle { void *handle; RGWMetadataHandler *handler; }; int RGWMetadataManager::list_keys_init(string& section, void **handle) { string entry; RGWMetadataHandler *handler; int ret; ret = find_handler(section, &handler, entry); if (ret < 0) { return -ENOENT; } list_keys_handle *h = new list_keys_handle; h->handler = handler; ret = handler->list_keys_init(store, &h->handle); if (ret < 0) { delete h; return ret; } *handle = (void *)h; return 0; } int RGWMetadataManager::list_keys_next(void *handle, int max, list& keys, bool *truncated) { list_keys_handle *h = static_cast(handle); RGWMetadataHandler *handler = h->handler; return handler->list_keys_next(h->handle, max, keys, truncated); } void RGWMetadataManager::list_keys_complete(void *handle) { list_keys_handle *h = static_cast(handle); RGWMetadataHandler *handler = h->handler; handler->list_keys_complete(h->handle); delete h; } void RGWMetadataManager::dump_log_entry(cls_log_entry& entry, Formatter *f) { f->open_object_section("entry"); f->dump_string("id", entry.id); f->dump_string("section", entry.section); f->dump_string("name", entry.name); entry.timestamp.gmtime(f->dump_stream("timestamp")); try { RGWMetadataLogData log_data; bufferlist::iterator iter = entry.data.begin(); ::decode(log_data, iter); encode_json("data", log_data, f); } catch (buffer::error& err) { lderr(cct) << "failed to decode log entry: " << entry.section << ":" << entry.name<< " ts=" << entry.timestamp << dendl; } f->close_section(); } void RGWMetadataManager::get_sections(list& sections) { for (map::iterator iter = handlers.begin(); iter != handlers.end(); ++iter) { sections.push_back(iter->first); } } int RGWMetadataManager::pre_modify(RGWMetadataHandler *handler, string& section, const string& key, RGWMetadataLogData& log_data, RGWObjVersionTracker *objv_tracker, RGWMDLogStatus op_type) { section = handler->get_type(); /* if write version has not been set, and there's a read version, set it so that we can * log it */ if (objv_tracker) { if (objv_tracker->read_version.ver && !objv_tracker->write_version.ver) { objv_tracker->write_version = objv_tracker->read_version; objv_tracker->write_version.ver++; } log_data.read_version = objv_tracker->read_version; log_data.write_version = objv_tracker->write_version; } log_data.status = op_type; bufferlist logbl; ::encode(log_data, logbl); int ret = md_log->add_entry(store, handler, section, key, logbl); if (ret < 0) return ret; return 0; } int RGWMetadataManager::post_modify(RGWMetadataHandler *handler, const string& section, const string& key, RGWMetadataLogData& log_data, RGWObjVersionTracker *objv_tracker, int ret) { if (ret >= 0) log_data.status = MDLOG_STATUS_COMPLETE; else log_data.status = MDLOG_STATUS_ABORT; bufferlist logbl; ::encode(log_data, logbl); int r = md_log->add_entry(store, handler, section, key, logbl); if (ret < 0) return ret; if (r < 0) return r; return 0; } int RGWMetadataManager::put_entry(RGWMetadataHandler *handler, const string& key, bufferlist& bl, bool exclusive, RGWObjVersionTracker *objv_tracker, time_t mtime, map *pattrs) { string section; RGWMetadataLogData log_data; int ret = pre_modify(handler, section, key, log_data, objv_tracker, MDLOG_STATUS_WRITE); if (ret < 0) return ret; string oid; rgw_bucket bucket; handler->get_pool_and_oid(store, key, bucket, oid); ret = rgw_put_system_obj(store, bucket, oid, bl.c_str(), bl.length(), exclusive, objv_tracker, mtime, pattrs); /* cascading ret into post_modify() */ ret = post_modify(handler, section, key, log_data, objv_tracker, ret); if (ret < 0) return ret; return 0; } int RGWMetadataManager::remove_entry(RGWMetadataHandler *handler, string& key, RGWObjVersionTracker *objv_tracker) { string section; RGWMetadataLogData log_data; int ret = pre_modify(handler, section, key, log_data, objv_tracker, MDLOG_STATUS_REMOVE); if (ret < 0) return ret; string oid; rgw_bucket bucket; handler->get_pool_and_oid(store, key, bucket, oid); rgw_obj obj(bucket, oid); ret = store->delete_system_obj(NULL, obj, objv_tracker); /* cascading ret into post_modify() */ ret = post_modify(handler, section, key, log_data, objv_tracker, ret); if (ret < 0) return ret; return 0; } int RGWMetadataManager::set_attrs(RGWMetadataHandler *handler, string& key, rgw_obj& obj, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker) { string section; RGWMetadataLogData log_data; int ret = pre_modify(handler, section, key, log_data, objv_tracker, MDLOG_STATUS_SETATTRS); if (ret < 0) return ret; ret = store->set_attrs(NULL, obj, attrs, rmattrs, objv_tracker); /* cascading ret into post_modify() */ ret = post_modify(handler, section, key, log_data, objv_tracker, ret); if (ret < 0) return ret; return 0; } ceph-0.80.11/src/rgw/rgw_fcgi.cc0000664000175100017510000000166112623076744020365 0ustar jenkins-buildjenkins-build #include "rgw_fcgi.h" #include "acconfig.h" #ifdef FASTCGI_INCLUDE_DIR # include "fastcgi/fcgiapp.h" #else # include "fcgiapp.h" #endif int RGWFCGX::write_data(const char *buf, int len) { return FCGX_PutStr(buf, len, fcgx->out); } int RGWFCGX::read_data(char *buf, int len) { return FCGX_GetStr(buf, len, fcgx->in); } void RGWFCGX::flush() { FCGX_FFlush(fcgx->out); } void RGWFCGX::init_env(CephContext *cct) { env.init(cct, (char **)fcgx->envp); } int RGWFCGX::send_status(const char *status, const char *status_name) { return print("Status: %s %s\r\n", status, status_name); } int RGWFCGX::send_100_continue() { int r = send_status("100", "Continue"); if (r >= 0) { flush(); } return r; } int RGWFCGX::send_content_length(uint64_t len) { char buf[21]; snprintf(buf, sizeof(buf), "%"PRIu64, len); return print("Content-Length: %s\r\n", buf); } int RGWFCGX::complete_header() { return print("\r\n"); } ceph-0.80.11/src/rgw/rgw_xml.cc0000664000175100017510000001024012623076744020246 0ustar jenkins-buildjenkins-build#include #include #include #include "include/types.h" #include "rgw_common.h" #include "rgw_xml.h" #define dout_subsys ceph_subsys_rgw using namespace std; XMLObjIter:: XMLObjIter() { } XMLObjIter:: ~XMLObjIter() { } void XMLObjIter:: set(const XMLObjIter::map_iter_t &_cur, const XMLObjIter::map_iter_t &_end) { cur = _cur; end = _end; } XMLObj *XMLObjIter:: get_next() { XMLObj *obj = NULL; if (cur != end) { obj = cur->second; ++cur; } return obj; }; ostream& operator<<(ostream& out, XMLObj& obj) { out << obj.obj_type << ": " << obj.data; return out; } XMLObj:: ~XMLObj() { } bool XMLObj:: xml_start(XMLObj *parent, const char *el, const char **attr) { this->parent = parent; obj_type = el; for (int i = 0; attr[i]; i += 2) { attr_map[attr[i]] = string(attr[i + 1]); } return true; } bool XMLObj:: xml_end(const char *el) { return true; } void XMLObj:: xml_handle_data(const char *s, int len) { data.append(s, len); } string& XMLObj:: XMLObj::get_data() { return data; } XMLObj *XMLObj:: XMLObj::get_parent() { return parent; } void XMLObj:: add_child(string el, XMLObj *obj) { children.insert(pair(el, obj)); } bool XMLObj:: get_attr(string name, string& attr) { map::iterator iter = attr_map.find(name); if (iter == attr_map.end()) return false; attr = iter->second; return true; } XMLObjIter XMLObj:: find(string name) { XMLObjIter iter; map::iterator first; map::iterator last; first = children.find(name); if (first != children.end()) { last = children.upper_bound(name); }else last = children.end(); iter.set(first, last); return iter; } XMLObj *XMLObj:: find_first(string name) { XMLObjIter iter; map::iterator first; first = children.find(name); if (first != children.end()) return first->second; return NULL; } static void xml_start(void *data, const char *el, const char **attr) { RGWXMLParser *handler = static_cast(data); if (!handler->xml_start(el, attr)) handler->set_failure(); } RGWXMLParser:: RGWXMLParser() : buf(NULL), buf_len(0), cur_obj(NULL), success(true) { p = XML_ParserCreate(NULL); } RGWXMLParser:: ~RGWXMLParser() { XML_ParserFree(p); free(buf); vector::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { XMLObj *obj = *iter; delete obj; } } bool RGWXMLParser::xml_start(const char *el, const char **attr) { XMLObj * obj = alloc_obj(el); if (!obj) { obj = new XMLObj(); } if (!obj->xml_start(cur_obj, el, attr)) return false; if (cur_obj) { cur_obj->add_child(el, obj); } else { children.insert(pair(el, obj)); } cur_obj = obj; objs.push_back(obj); return true; } static void xml_end(void *data, const char *el) { RGWXMLParser *handler = static_cast(data); if (!handler->xml_end(el)) handler->set_failure(); } bool RGWXMLParser::xml_end(const char *el) { XMLObj *parent_obj = cur_obj->get_parent(); if (!cur_obj->xml_end(el)) return false; cur_obj = parent_obj; return true; } static void handle_data(void *data, const char *s, int len) { RGWXMLParser *handler = static_cast(data); handler->handle_data(s, len); } void RGWXMLParser::handle_data(const char *s, int len) { cur_obj->xml_handle_data(s, len); } bool RGWXMLParser::init() { if (!p) { return false; } XML_SetElementHandler(p, ::xml_start, ::xml_end); XML_SetCharacterDataHandler(p, ::handle_data); XML_SetUserData(p, (void *)this); return true; } bool RGWXMLParser::parse(const char *_buf, int len, int done) { int pos = buf_len; char *tmp_buf; tmp_buf = (char *)realloc(buf, buf_len + len); if (tmp_buf == NULL){ free(buf); buf = NULL; return false; } else { buf = tmp_buf; } memcpy(&buf[buf_len], _buf, len); buf_len += len; success = true; if (!XML_Parse(p, &buf[pos], len, done)) { fprintf(stderr, "Parse error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p))); success = false; } return success; } ceph-0.80.11/src/rgw/rgw_client_io.h0000664000175100017510000000220112623076744021253 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_CLIENT_IO_H #define CEPH_RGW_CLIENT_IO_H #include #include "include/types.h" #include "rgw_common.h" class RGWClientIO { bool account; size_t bytes_sent; size_t bytes_received; protected: RGWEnv env; virtual void init_env(CephContext *cct) = 0; virtual int write_data(const char *buf, int len) = 0; virtual int read_data(char *buf, int max) = 0; public: virtual ~RGWClientIO() {} RGWClientIO() : account(false), bytes_sent(0), bytes_received(0) {} void init(CephContext *cct); int print(const char *format, ...); int write(const char *buf, int len); virtual void flush() = 0; int read(char *buf, int max, int *actual); virtual int send_status(const char *status, const char *status_name) = 0; virtual int send_100_continue() = 0; virtual int complete_header() = 0; virtual int complete_request() = 0; virtual int send_content_length(uint64_t len) = 0; RGWEnv& get_env() { return env; } void set_account(bool _account) { account = _account; } uint64_t get_bytes_sent() { return bytes_sent; } uint64_t get_bytes_received() { return bytes_received; } }; #endif ceph-0.80.11/src/rgw/rgw_rest_opstate.h0000664000175100017510000000471012623076744022031 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_REST_OPSTATE_H #define CEPH_RGW_REST_OPSTATE_H class RGWOp_Opstate_List : public RGWRESTOp { bool sent_header; public: RGWOp_Opstate_List() : sent_header(false) {} ~RGWOp_Opstate_List() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("opstate", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual void send_response(list entries); virtual void send_response_end(); virtual const string name() { return "opstate_list"; } }; class RGWOp_Opstate_Set : public RGWRESTOp { public: RGWOp_Opstate_Set() {} ~RGWOp_Opstate_Set() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("opstate", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "set_opstate"; } }; class RGWOp_Opstate_Renew : public RGWRESTOp { public: RGWOp_Opstate_Renew() {} ~RGWOp_Opstate_Renew() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("opstate", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "renew_opstate"; } }; class RGWOp_Opstate_Delete : public RGWRESTOp { public: RGWOp_Opstate_Delete() {} ~RGWOp_Opstate_Delete() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("opstate", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "delete_opstate"; } }; class RGWHandler_Opstate : public RGWHandler_Auth_S3 { protected: RGWOp *op_get() { return new RGWOp_Opstate_List; } RGWOp *op_delete() { return new RGWOp_Opstate_Delete; } RGWOp *op_post(); int read_permissions(RGWOp*) { return 0; } public: RGWHandler_Opstate() : RGWHandler_Auth_S3() {} virtual ~RGWHandler_Opstate() {} }; class RGWRESTMgr_Opstate : public RGWRESTMgr { public: RGWRESTMgr_Opstate() {} virtual ~RGWRESTMgr_Opstate() {} virtual RGWHandler *get_handler(struct req_state *s){ return new RGWHandler_Opstate; } }; #endif /*!CEPH_RGW_REST_OPSTATE_H*/ ceph-0.80.11/src/rgw/rgw_rest_user.cc0000664000175100017510000005206512623076744021474 0ustar jenkins-buildjenkins-build#include "common/ceph_json.h" #include "rgw_op.h" #include "rgw_user.h" #include "rgw_rest_user.h" #include "include/str_list.h" #define dout_subsys ceph_subsys_rgw class RGWOp_User_Info : public RGWRESTOp { public: RGWOp_User_Info() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_READ); } void execute(); virtual const string name() { return "get_user_info"; } }; void RGWOp_User_Info::execute() { RGWUserAdminOpState op_state; std::string uid; RESTArgs::get_string(s, "uid", uid, &uid); op_state.set_user_id(uid); http_ret = RGWUserAdminOp_User::info(store, op_state, flusher); } class RGWOp_User_Create : public RGWRESTOp { public: RGWOp_User_Create() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "create_user"; } }; void RGWOp_User_Create::execute() { std::string uid; std::string display_name; std::string email; std::string access_key; std::string secret_key; std::string key_type_str; std::string caps; bool gen_key; bool suspended; bool system; uint32_t max_buckets; int32_t key_type = KEY_TYPE_UNDEFINED; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "display-name", display_name, &display_name); RESTArgs::get_string(s, "email", email, &email); RESTArgs::get_string(s, "access-key", access_key, &access_key); RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); RESTArgs::get_string(s, "user-caps", caps, &caps); RESTArgs::get_bool(s, "generate-key", true, &gen_key); RESTArgs::get_bool(s, "suspended", false, &suspended); RESTArgs::get_uint32(s, "max-buckets", RGW_DEFAULT_MAX_BUCKETS, &max_buckets); RESTArgs::get_bool(s, "system", false, &system); if (!s->user.system && system) { ldout(s->cct, 0) << "cannot set system flag by non-system user" << dendl; http_ret = -EINVAL; return; } // FIXME: don't do double argument checking if (!uid.empty()) op_state.set_user_id(uid); if (!display_name.empty()) op_state.set_display_name(display_name); if (!email.empty()) op_state.set_user_email(email); if (!caps.empty()) op_state.set_caps(caps); if (!access_key.empty()) op_state.set_access_key(access_key); if (!secret_key.empty()) op_state.set_secret_key(secret_key); if (!key_type_str.empty()) { if (key_type_str.compare("swift") == 0) key_type = KEY_TYPE_SWIFT; else if (key_type_str.compare("s3") == 0) key_type = KEY_TYPE_S3; op_state.set_key_type(key_type); } if (max_buckets != RGW_DEFAULT_MAX_BUCKETS) op_state.set_max_buckets(max_buckets); if (s->info.args.exists("suspended")) op_state.set_suspension(suspended); if (s->info.args.exists("system")) op_state.set_system(system); if (gen_key) op_state.set_generate_key(); http_ret = RGWUserAdminOp_User::create(store, op_state, flusher); } class RGWOp_User_Modify : public RGWRESTOp { public: RGWOp_User_Modify() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "modify_user"; } }; void RGWOp_User_Modify::execute() { std::string uid; std::string display_name; std::string email; std::string access_key; std::string secret_key; std::string key_type_str; std::string caps; bool gen_key; bool suspended; bool system; uint32_t max_buckets; int32_t key_type = KEY_TYPE_UNDEFINED; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "display-name", display_name, &display_name); RESTArgs::get_string(s, "email", email, &email); RESTArgs::get_string(s, "access-key", access_key, &access_key); RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); RESTArgs::get_string(s, "user-caps", caps, &caps); RESTArgs::get_bool(s, "generate-key", false, &gen_key); RESTArgs::get_bool(s, "suspended", false, &suspended); RESTArgs::get_uint32(s, "max-buckets", RGW_DEFAULT_MAX_BUCKETS, &max_buckets); RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); RESTArgs::get_bool(s, "system", false, &system); if (!s->user.system && system) { ldout(s->cct, 0) << "cannot set system flag by non-system user" << dendl; http_ret = -EINVAL; return; } if (!uid.empty()) op_state.set_user_id(uid); if (!display_name.empty()) op_state.set_display_name(display_name); if (!email.empty()) op_state.set_user_email(email); if (!caps.empty()) op_state.set_caps(caps); if (!access_key.empty()) op_state.set_access_key(access_key); if (!secret_key.empty()) op_state.set_secret_key(secret_key); if (max_buckets != RGW_DEFAULT_MAX_BUCKETS) op_state.set_max_buckets(max_buckets); if (gen_key) op_state.set_generate_key(); if (!key_type_str.empty()) { if (key_type_str.compare("swift") == 0) key_type = KEY_TYPE_SWIFT; else if (key_type_str.compare("s3") == 0) key_type = KEY_TYPE_S3; op_state.set_key_type(key_type); } if (s->info.args.exists("suspended")) op_state.set_suspension(suspended); if (s->info.args.exists("system")) op_state.set_system(system); http_ret = RGWUserAdminOp_User::modify(store, op_state, flusher); } class RGWOp_User_Remove : public RGWRESTOp { public: RGWOp_User_Remove() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_user"; } }; void RGWOp_User_Remove::execute() { std::string uid; bool purge_data; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_bool(s, "purge-data", false, &purge_data); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); op_state.set_purge_data(purge_data); http_ret = RGWUserAdminOp_User::remove(store, op_state, flusher); } class RGWOp_Subuser_Create : public RGWRESTOp { public: RGWOp_Subuser_Create() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "create_subuser"; } }; void RGWOp_Subuser_Create::execute() { std::string uid; std::string subuser; std::string secret_key; std::string perm_str; std::string key_type_str; bool gen_subuser = false; // FIXME placeholder bool gen_secret; uint32_t perm_mask = 0; int32_t key_type = KEY_TYPE_SWIFT; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "subuser", subuser, &subuser); RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); RESTArgs::get_string(s, "access", perm_str, &perm_str); RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); //RESTArgs::get_bool(s, "generate-subuser", false, &gen_subuser); RESTArgs::get_bool(s, "generate-secret", false, &gen_secret); perm_mask = rgw_str_to_perm(perm_str.c_str()); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!subuser.empty()) op_state.set_subuser(subuser); if (!secret_key.empty()) op_state.set_secret_key(secret_key); if (perm_mask != 0) op_state.set_perm(perm_mask); op_state.set_generate_subuser(gen_subuser); if (gen_secret) op_state.set_gen_secret(); if (!key_type_str.empty()) { if (key_type_str.compare("swift") == 0) key_type = KEY_TYPE_SWIFT; else if (key_type_str.compare("s3") == 0) key_type = KEY_TYPE_S3; } op_state.set_key_type(key_type); http_ret = RGWUserAdminOp_Subuser::create(store, op_state, flusher); } class RGWOp_Subuser_Modify : public RGWRESTOp { public: RGWOp_Subuser_Modify() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "modify_subuser"; } }; void RGWOp_Subuser_Modify::execute() { std::string uid; std::string subuser; std::string secret_key; std::string key_type_str; std::string perm_str; RGWUserAdminOpState op_state; uint32_t perm_mask; int32_t key_type = KEY_TYPE_SWIFT; bool gen_secret; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "subuser", subuser, &subuser); RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); RESTArgs::get_string(s, "access", perm_str, &perm_str); RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); RESTArgs::get_bool(s, "generate-secret", false, &gen_secret); perm_mask = rgw_str_to_perm(perm_str.c_str()); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!subuser.empty()) op_state.set_subuser(subuser); if (!secret_key.empty()) op_state.set_secret_key(secret_key); if (gen_secret) op_state.set_gen_secret(); if (perm_mask != 0) op_state.set_perm(perm_mask); if (!key_type_str.empty()) { if (key_type_str.compare("swift") == 0) key_type = KEY_TYPE_SWIFT; else if (key_type_str.compare("s3") == 0) key_type = KEY_TYPE_S3; } op_state.set_key_type(key_type); http_ret = RGWUserAdminOp_Subuser::modify(store, op_state, flusher); } class RGWOp_Subuser_Remove : public RGWRESTOp { public: RGWOp_Subuser_Remove() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_subuser"; } }; void RGWOp_Subuser_Remove::execute() { std::string uid; std::string subuser; bool purge_keys; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "subuser", subuser, &subuser); RESTArgs::get_bool(s, "purge-keys", true, &purge_keys); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!subuser.empty()) op_state.set_subuser(subuser); if (purge_keys) op_state.set_purge_keys(); http_ret = RGWUserAdminOp_Subuser::remove(store, op_state, flusher); } class RGWOp_Key_Create : public RGWRESTOp { public: RGWOp_Key_Create() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "create_access_key"; } }; void RGWOp_Key_Create::execute() { std::string uid; std::string subuser; std::string access_key; std::string secret_key; std::string key_type_str; int32_t key_type = KEY_TYPE_UNDEFINED; bool gen_key; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "subuser", subuser, &subuser); RESTArgs::get_string(s, "access-key", access_key, &access_key); RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); RESTArgs::get_bool(s, "generate-key", true, &gen_key); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!subuser.empty()) op_state.set_subuser(subuser); if (!access_key.empty()) op_state.set_access_key(access_key); if (!secret_key.empty()) op_state.set_secret_key(secret_key); if (gen_key) op_state.set_generate_key(); if (!key_type_str.empty()) { if (key_type_str.compare("swift") == 0) key_type = KEY_TYPE_SWIFT; else if (key_type_str.compare("s3") == 0) key_type = KEY_TYPE_S3; op_state.set_key_type(key_type); } http_ret = RGWUserAdminOp_Key::create(store, op_state, flusher); } class RGWOp_Key_Remove : public RGWRESTOp { public: RGWOp_Key_Remove() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_access_key"; } }; void RGWOp_Key_Remove::execute() { std::string uid; std::string subuser; std::string access_key; std::string key_type_str; int32_t key_type = KEY_TYPE_UNDEFINED; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "subuser", subuser, &subuser); RESTArgs::get_string(s, "access-key", access_key, &access_key); RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!subuser.empty()) op_state.set_subuser(subuser); if (!access_key.empty()) op_state.set_access_key(access_key); if (!key_type_str.empty()) { if (key_type_str.compare("swift") == 0) key_type = KEY_TYPE_SWIFT; else if (key_type_str.compare("s3") == 0) key_type = KEY_TYPE_S3; op_state.set_key_type(key_type); } http_ret = RGWUserAdminOp_Key::remove(store, op_state, flusher); } class RGWOp_Caps_Add : public RGWRESTOp { public: RGWOp_Caps_Add() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "add_user_caps"; } }; void RGWOp_Caps_Add::execute() { std::string uid; std::string caps; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "user-caps", caps, &caps); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!caps.empty()) op_state.set_caps(caps); http_ret = RGWUserAdminOp_Caps::add(store, op_state, flusher); } class RGWOp_Caps_Remove : public RGWRESTOp { public: RGWOp_Caps_Remove() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "remove_user_caps"; } }; void RGWOp_Caps_Remove::execute() { std::string uid; std::string caps; RGWUserAdminOpState op_state; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "user-caps", caps, &caps); // FIXME: no double checking if (!uid.empty()) op_state.set_user_id(uid); if (!caps.empty()) op_state.set_caps(caps); http_ret = RGWUserAdminOp_Caps::remove(store, op_state, flusher); } struct UserQuotas { RGWQuotaInfo bucket_quota; RGWQuotaInfo user_quota; UserQuotas() {} UserQuotas(RGWUserInfo& info) { bucket_quota = info.bucket_quota; user_quota = info.user_quota; } void dump(Formatter *f) const { encode_json("bucket_quota", bucket_quota, f); encode_json("user_quota", user_quota, f); } void decode_json(JSONObj *obj) { JSONDecoder::decode_json("bucket_quota", bucket_quota, obj); JSONDecoder::decode_json("user_quota", user_quota, obj); } }; class RGWOp_Quota_Info : public RGWRESTOp { public: RGWOp_Quota_Info() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_READ); } void execute(); virtual const string name() { return "get_quota_info"; } }; void RGWOp_Quota_Info::execute() { RGWUserAdminOpState op_state; std::string uid; std::string quota_type; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "quota-type", quota_type, "a_type); if (uid.empty()) { http_ret = -EINVAL; return; } bool show_all = quota_type.empty(); bool show_bucket = show_all || (quota_type == "bucket"); bool show_user = show_all || (quota_type == "user"); if (!(show_all || show_bucket || show_user)) { http_ret = -EINVAL; return; } op_state.set_user_id(uid); RGWUser user; http_ret = user.init(store, op_state); if (http_ret < 0) return; RGWUserInfo info; string err_msg; http_ret = user.info(info, &err_msg); if (http_ret < 0) return; if (show_all) { UserQuotas quotas(info); encode_json("quota", quotas, s->formatter); } else if (show_user) { encode_json("user_quota", info.user_quota, s->formatter); } else { encode_json("bucket_quota", info.bucket_quota, s->formatter); } flusher.flush(); } class RGWOp_Quota_Set : public RGWRESTOp { public: RGWOp_Quota_Set() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("users", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "set_quota_info"; } }; /** * set quota * * two different ways to set the quota info: as json struct in the message body or via http params. * * as json: * * PUT /admin/user?uid=["a-type=] * * whereas quota-type is optional and is either user, or bucket * * if quota-type is not specified then we expect to get a structure that contains both quotas, * otherwise we'll only get the relevant configuration. * * E.g., if quota type not specified: * { * "user_quota" : { * "max_size_kb" : 4096, * "max_objects" : -1, * "enabled" : false * }, * "bucket_quota" : { * "max_size_kb" : 1024, * "max_objects" : -1, * "enabled" : true * } * } * * * or if quota type is specified: * { * "max_size_kb" : 4096, * "max_objects" : -1, * "enabled" : false * } * * Another option is not to pass any body and set the following http params: * * * max-size-kb= * max-objects= * enabled[={true,false}] * * all params are optionals and default to the current settings. With this type of configuration the * quota-type param is mandatory. * */ void RGWOp_Quota_Set::execute() { RGWUserAdminOpState op_state; std::string uid; std::string quota_type; RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "quota-type", quota_type, "a_type); if (uid.empty()) { http_ret = -EINVAL; return; } bool set_all = quota_type.empty(); bool set_bucket = set_all || (quota_type == "bucket"); bool set_user = set_all || (quota_type == "user"); if (!(set_all || set_bucket || set_user)) { ldout(store->ctx(), 20) << "invalid quota type" << dendl; http_ret = -EINVAL; return; } bool use_http_params; if (s->content_length > 0) { use_http_params = false; } else { const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING"); use_http_params = (!encoding || strcmp(encoding, "chunked") != 0); } if (use_http_params && set_all) { ldout(store->ctx(), 20) << "quota type was not specified, can't set all quotas via http headers" << dendl; http_ret = -EINVAL; return; } op_state.set_user_id(uid); RGWUser user; http_ret = user.init(store, op_state); if (http_ret < 0) { ldout(store->ctx(), 20) << "failed initializing user info: " << http_ret << dendl; return; } #define QUOTA_INPUT_MAX_LEN 1024 if (set_all) { UserQuotas quotas; if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, quotas, QUOTA_INPUT_MAX_LEN, NULL)) < 0) { ldout(store->ctx(), 20) << "failed to retrieve input" << dendl; return; } op_state.set_user_quota(quotas.user_quota); op_state.set_bucket_quota(quotas.bucket_quota); } else { RGWQuotaInfo quota; if (!use_http_params) { bool empty; http_ret = rgw_rest_get_json_input(store->ctx(), s, quota, QUOTA_INPUT_MAX_LEN, &empty); if (http_ret < 0) { ldout(store->ctx(), 20) << "failed to retrieve input" << dendl; if (!empty) return; /* was probably chunked input, but no content provided, configure via http params */ use_http_params = true; } } if (use_http_params) { RGWUserInfo info; string err_msg; http_ret = user.info(info, &err_msg); if (http_ret < 0) { ldout(store->ctx(), 20) << "failed to get user info: " << http_ret << dendl; return; } RGWQuotaInfo *old_quota; if (set_user) { old_quota = &info.user_quota; } else { old_quota = &info.bucket_quota; } RESTArgs::get_int64(s, "max-objects", old_quota->max_objects, "a.max_objects); RESTArgs::get_int64(s, "max-size-kb", old_quota->max_size_kb, "a.max_size_kb); RESTArgs::get_bool(s, "enabled", old_quota->enabled, "a.enabled); } if (set_user) { op_state.set_user_quota(quota); } else { op_state.set_bucket_quota(quota); } } string err; http_ret = user.modify(op_state, &err); if (http_ret < 0) { ldout(store->ctx(), 20) << "failed updating user info: " << http_ret << ": " << err << dendl; return; } } RGWOp *RGWHandler_User::op_get() { if (s->info.args.sub_resource_exists("quota")) return new RGWOp_Quota_Info; return new RGWOp_User_Info; }; RGWOp *RGWHandler_User::op_put() { if (s->info.args.sub_resource_exists("subuser")) return new RGWOp_Subuser_Create; if (s->info.args.sub_resource_exists("key")) return new RGWOp_Key_Create; if (s->info.args.sub_resource_exists("caps")) return new RGWOp_Caps_Add; if (s->info.args.sub_resource_exists("quota")) return new RGWOp_Quota_Set; return new RGWOp_User_Create; }; RGWOp *RGWHandler_User::op_post() { if (s->info.args.sub_resource_exists("subuser")) return new RGWOp_Subuser_Modify; return new RGWOp_User_Modify; }; RGWOp *RGWHandler_User::op_delete() { if (s->info.args.sub_resource_exists("subuser")) return new RGWOp_Subuser_Remove; if (s->info.args.sub_resource_exists("key")) return new RGWOp_Key_Remove; if (s->info.args.sub_resource_exists("caps")) return new RGWOp_Caps_Remove; return new RGWOp_User_Remove; }; ceph-0.80.11/src/rgw/rgw_rest_conn.h0000664000175100017510000000207012623076744021304 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_CONN_H #define CEPH_RGW_REST_CONN_H #include "rgw_rest_client.h" class CephContext; class RGWRados; class RGWGetObjData; class RGWRESTConn { CephContext *cct; map endpoints; RGWAccessKey key; string region; atomic_t counter; public: RGWRESTConn(CephContext *_cct, RGWRados *store, list& endpoints); int get_url(string& endpoint); /* sync request */ int forward(const string& uid, req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl); /* async request */ int put_obj_init(const string& uid, rgw_obj& obj, uint64_t obj_size, map& attrs, RGWRESTStreamWriteRequest **req); int complete_request(RGWRESTStreamWriteRequest *req, string& etag, time_t *mtime); int get_obj(const string& uid, req_info *info /* optional */, rgw_obj& obj, bool prepend_metadata, RGWGetDataCB *cb, RGWRESTStreamReadRequest **req); int complete_request(RGWRESTStreamReadRequest *req, string& etag, time_t *mtime, map& attrs); }; #endif ceph-0.80.11/src/rgw/rgw_formats.h0000664000175100017510000000470212623076744020771 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_FORMATS_H #define CEPH_RGW_FORMATS_H #include "common/Formatter.h" #include #include #include struct plain_stack_entry { int size; bool is_array; }; /* FIXME: this class is mis-named. * FIXME: This was a hack to send certain swift messages. * There is a much better way to do this. */ class RGWFormatter_Plain : public Formatter { void reset_buf(); public: RGWFormatter_Plain(); virtual ~RGWFormatter_Plain(); virtual void flush(ostream& os); virtual void reset(); virtual void open_array_section(const char *name); virtual void open_array_section_in_ns(const char *name, const char *ns); virtual void open_object_section(const char *name); virtual void open_object_section_in_ns(const char *name, const char *ns); virtual void close_section(); virtual void dump_unsigned(const char *name, uint64_t u); virtual void dump_int(const char *name, int64_t u); virtual void dump_float(const char *name, double d); virtual void dump_string(const char *name, std::string s); virtual std::ostream& dump_stream(const char *name); virtual void dump_format(const char *name, const char *fmt, ...); virtual void dump_format_unquoted(const char *name, const char *fmt, ...) { assert(0 == "not implemented"); } virtual int get_len() const; virtual void write_raw_data(const char *data); private: void write_data(const char *fmt, ...); void dump_value_int(const char *name, const char *fmt, ...); char *buf; int len; int max_len; std::list stack; size_t min_stack_level; }; class RGWFormatterFlusher { protected: Formatter *formatter; bool flushed; bool started; virtual void do_flush() = 0; virtual void do_start(int ret) {} void set_formatter(Formatter *f) { formatter = f; } public: RGWFormatterFlusher(Formatter *f) : formatter(f), flushed(false), started(false) {} virtual ~RGWFormatterFlusher() {} void flush() { do_flush(); flushed = true; } virtual void start(int client_ret) { if (!started) do_start(client_ret); started = true; } Formatter *get_formatter() { return formatter; } bool did_flush() { return flushed; } bool did_start() { return started; } }; class RGWStreamFlusher : public RGWFormatterFlusher { ostream& os; protected: virtual void do_flush() { formatter->flush(os); } public: RGWStreamFlusher(Formatter *f, ostream& _os) : RGWFormatterFlusher(f), os(_os) {} }; #endif ceph-0.80.11/src/rgw/rgw_rest_s3.h0000664000175100017510000002324112623076744020677 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_S3_H #define CEPH_RGW_REST_S3_H #define TIME_BUF_SIZE 128 #include "rgw_op.h" #include "rgw_http_errors.h" #include "rgw_acl_s3.h" #include "rgw_policy_s3.h" #include "rgw_keystone.h" #define RGW_AUTH_GRACE_MINS 15 void rgw_get_errno_s3(struct rgw_http_errors *e, int err_no); class RGWGetObj_ObjStore_S3 : public RGWGetObj_ObjStore { public: RGWGetObj_ObjStore_S3() {} ~RGWGetObj_ObjStore_S3() {} int send_response_data(bufferlist& bl, off_t ofs, off_t len); }; class RGWListBuckets_ObjStore_S3 : public RGWListBuckets_ObjStore { public: RGWListBuckets_ObjStore_S3() {} ~RGWListBuckets_ObjStore_S3() {} int get_params() { limit = 0; /* no limit */ return 0; } virtual void send_response_begin(bool has_buckets); virtual void send_response_data(RGWUserBuckets& buckets); virtual void send_response_end(); }; class RGWListBucket_ObjStore_S3 : public RGWListBucket_ObjStore { public: RGWListBucket_ObjStore_S3() { default_max = 1000; } ~RGWListBucket_ObjStore_S3() {} int get_params(); void send_response(); }; class RGWGetBucketLogging_ObjStore_S3 : public RGWGetBucketLogging { public: RGWGetBucketLogging_ObjStore_S3() {} ~RGWGetBucketLogging_ObjStore_S3() {} void send_response(); }; class RGWStatBucket_ObjStore_S3 : public RGWStatBucket_ObjStore { public: RGWStatBucket_ObjStore_S3() {} ~RGWStatBucket_ObjStore_S3() {} void send_response(); }; class RGWCreateBucket_ObjStore_S3 : public RGWCreateBucket_ObjStore { public: RGWCreateBucket_ObjStore_S3() {} ~RGWCreateBucket_ObjStore_S3() {} int get_params(); void send_response(); }; class RGWDeleteBucket_ObjStore_S3 : public RGWDeleteBucket_ObjStore { public: RGWDeleteBucket_ObjStore_S3() {} ~RGWDeleteBucket_ObjStore_S3() {} void send_response(); }; class RGWPutObj_ObjStore_S3 : public RGWPutObj_ObjStore { public: RGWPutObj_ObjStore_S3() {} ~RGWPutObj_ObjStore_S3() {} int get_params(); void send_response(); }; struct post_part_field { string val; map params; }; struct post_form_part { string name; string content_type; map fields; bufferlist data; }; class RGWPostObj_ObjStore_S3 : public RGWPostObj_ObjStore { string boundary; string filename; bufferlist in_data; map parts; RGWPolicyEnv env; RGWPolicy post_policy; string err_msg; int read_with_boundary(bufferlist& bl, uint64_t max, bool check_eol, bool *reached_boundary, bool *done); int read_line(bufferlist& bl, uint64_t max, bool *reached_boundary, bool *done); int read_data(bufferlist& bl, uint64_t max, bool *reached_boundary, bool *done); int read_form_part_header(struct post_form_part *part, bool *done); bool part_str(const string& name, string *val); bool part_bl(const string& name, bufferlist *pbl); int get_policy(); void rebuild_key(string& key); public: RGWPostObj_ObjStore_S3() {} ~RGWPostObj_ObjStore_S3() {} int get_params(); int complete_get_params(); void send_response(); int get_data(bufferlist& bl); }; class RGWDeleteObj_ObjStore_S3 : public RGWDeleteObj_ObjStore { public: RGWDeleteObj_ObjStore_S3() {} ~RGWDeleteObj_ObjStore_S3() {} void send_response(); }; class RGWCopyObj_ObjStore_S3 : public RGWCopyObj_ObjStore { bool sent_header; public: RGWCopyObj_ObjStore_S3() : sent_header(false) {} ~RGWCopyObj_ObjStore_S3() {} int init_dest_policy(); int get_params(); void send_partial_response(off_t ofs); void send_response(); }; class RGWGetACLs_ObjStore_S3 : public RGWGetACLs_ObjStore { public: RGWGetACLs_ObjStore_S3() {} ~RGWGetACLs_ObjStore_S3() {} void send_response(); }; class RGWPutACLs_ObjStore_S3 : public RGWPutACLs_ObjStore { public: RGWPutACLs_ObjStore_S3() {} ~RGWPutACLs_ObjStore_S3() {} int get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss); void send_response(); }; class RGWGetCORS_ObjStore_S3 : public RGWGetCORS_ObjStore { public: RGWGetCORS_ObjStore_S3() {} ~RGWGetCORS_ObjStore_S3() {} void send_response(); }; class RGWPutCORS_ObjStore_S3 : public RGWPutCORS_ObjStore { public: RGWPutCORS_ObjStore_S3() {} ~RGWPutCORS_ObjStore_S3() {} int get_params(); void send_response(); }; class RGWDeleteCORS_ObjStore_S3 : public RGWDeleteCORS_ObjStore { public: RGWDeleteCORS_ObjStore_S3() {} ~RGWDeleteCORS_ObjStore_S3() {} void send_response(); }; class RGWOptionsCORS_ObjStore_S3 : public RGWOptionsCORS_ObjStore { public: RGWOptionsCORS_ObjStore_S3() {} ~RGWOptionsCORS_ObjStore_S3() {} void send_response(); }; class RGWInitMultipart_ObjStore_S3 : public RGWInitMultipart_ObjStore { public: RGWInitMultipart_ObjStore_S3() {} ~RGWInitMultipart_ObjStore_S3() {} int get_params(); void send_response(); }; class RGWCompleteMultipart_ObjStore_S3 : public RGWCompleteMultipart_ObjStore { public: RGWCompleteMultipart_ObjStore_S3() {} ~RGWCompleteMultipart_ObjStore_S3() {} void send_response(); }; class RGWAbortMultipart_ObjStore_S3 : public RGWAbortMultipart_ObjStore { public: RGWAbortMultipart_ObjStore_S3() {} ~RGWAbortMultipart_ObjStore_S3() {} void send_response(); }; class RGWListMultipart_ObjStore_S3 : public RGWListMultipart_ObjStore { public: RGWListMultipart_ObjStore_S3() {} ~RGWListMultipart_ObjStore_S3() {} void send_response(); }; class RGWListBucketMultiparts_ObjStore_S3 : public RGWListBucketMultiparts_ObjStore { public: RGWListBucketMultiparts_ObjStore_S3() { default_max = 1000; } ~RGWListBucketMultiparts_ObjStore_S3() {} void send_response(); }; class RGWDeleteMultiObj_ObjStore_S3 : public RGWDeleteMultiObj_ObjStore { public: RGWDeleteMultiObj_ObjStore_S3() {} ~RGWDeleteMultiObj_ObjStore_S3() {} void send_status(); void begin_response(); void send_partial_response(pair& result); void end_response(); }; class RGW_Auth_S3_Keystone_ValidateToken : public RGWHTTPClient { private: bufferlist rx_buffer; bufferlist tx_buffer; bufferlist::iterator tx_buffer_it; list roles_list; public: KeystoneToken response; private: void set_tx_buffer(const string& d) { tx_buffer.clear(); tx_buffer.append(d); tx_buffer_it = tx_buffer.begin(); set_send_length(tx_buffer.length()); } public: RGW_Auth_S3_Keystone_ValidateToken(CephContext *_cct) : RGWHTTPClient(_cct) { get_str_list(cct->_conf->rgw_keystone_accepted_roles, roles_list); } int receive_header(void *ptr, size_t len) { return 0; } int receive_data(void *ptr, size_t len) { rx_buffer.append((char *)ptr, len); return 0; } int send_data(void *ptr, size_t len) { if (!tx_buffer_it.get_remaining()) return 0; // nothing left to send int l = MIN(tx_buffer_it.get_remaining(), len); memcpy(ptr, tx_buffer_it.get_current_ptr().c_str(), l); try { tx_buffer_it.advance(l); } catch (buffer::end_of_buffer &e) { assert(0); } return l; } int validate_s3token(const string& auth_id, const string& auth_token, const string& auth_sign); }; class RGW_Auth_S3 { public: static int authorize(RGWRados *store, struct req_state *s); }; class RGWHandler_Auth_S3 : public RGWHandler_ObjStore { friend class RGWRESTMgr_S3; public: RGWHandler_Auth_S3() : RGWHandler_ObjStore() {} virtual ~RGWHandler_Auth_S3() {} virtual int validate_bucket_name(const string& bucket) { return 0; } virtual int validate_object_name(const string& bucket) { return 0; } virtual int init(RGWRados *store, struct req_state *state, RGWClientIO *cio); virtual int authorize() { return RGW_Auth_S3::authorize(store, s); } }; class RGWHandler_ObjStore_S3 : public RGWHandler_ObjStore { friend class RGWRESTMgr_S3; public: static int init_from_header(struct req_state *s, int default_formatter, bool configurable_format); RGWHandler_ObjStore_S3() : RGWHandler_ObjStore() {} virtual ~RGWHandler_ObjStore_S3() {} int validate_bucket_name(const string& bucket, bool relaxed_names); virtual int init(RGWRados *store, struct req_state *state, RGWClientIO *cio); virtual int authorize() { return RGW_Auth_S3::authorize(store, s); } }; class RGWHandler_ObjStore_Service_S3 : public RGWHandler_ObjStore_S3 { protected: RGWOp *op_get(); RGWOp *op_head(); public: RGWHandler_ObjStore_Service_S3() {} virtual ~RGWHandler_ObjStore_Service_S3() {} }; class RGWHandler_ObjStore_Bucket_S3 : public RGWHandler_ObjStore_S3 { protected: bool is_acl_op() { return s->info.args.exists("acl"); } bool is_cors_op() { return s->info.args.exists("cors"); } bool is_obj_update_op() { return is_acl_op() || is_cors_op(); } RGWOp *get_obj_op(bool get_data); RGWOp *op_get(); RGWOp *op_head(); RGWOp *op_put(); RGWOp *op_delete(); RGWOp *op_post(); RGWOp *op_options(); public: RGWHandler_ObjStore_Bucket_S3() {} virtual ~RGWHandler_ObjStore_Bucket_S3() {} }; class RGWHandler_ObjStore_Obj_S3 : public RGWHandler_ObjStore_S3 { protected: bool is_acl_op() { return s->info.args.exists("acl"); } bool is_cors_op() { return s->info.args.exists("cors"); } bool is_obj_update_op() { return is_acl_op(); } RGWOp *get_obj_op(bool get_data); RGWOp *op_get(); RGWOp *op_head(); RGWOp *op_put(); RGWOp *op_delete(); RGWOp *op_post(); RGWOp *op_options(); public: RGWHandler_ObjStore_Obj_S3() {} virtual ~RGWHandler_ObjStore_Obj_S3() {} }; class RGWRESTMgr_S3 : public RGWRESTMgr { public: RGWRESTMgr_S3() {} virtual ~RGWRESTMgr_S3() {} virtual RGWRESTMgr *get_resource_mgr(struct req_state *s, const string& uri) { return this; } virtual RGWHandler *get_handler(struct req_state *s); }; #endif ceph-0.80.11/src/rgw/rgw_formats.cc0000664000175100017510000001164712623076744021135 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/escape.h" #include "common/Formatter.h" #include "rgw/rgw_common.h" #include "rgw/rgw_formats.h" #define LARGE_SIZE 8192 #define dout_subsys ceph_subsys_rgw RGWFormatter_Plain::RGWFormatter_Plain() : buf(NULL), len(0), max_len(0), min_stack_level(0) { } RGWFormatter_Plain::~RGWFormatter_Plain() { free(buf); } void RGWFormatter_Plain::flush(ostream& os) { if (!buf) return; if (len) { os << buf << "\n"; os.flush(); } reset_buf(); } void RGWFormatter_Plain::reset_buf() { free(buf); buf = NULL; len = 0; max_len = 0; } void RGWFormatter_Plain::reset() { reset_buf(); stack.clear(); min_stack_level = 0; } void RGWFormatter_Plain::open_array_section(const char *name) { struct plain_stack_entry new_entry; new_entry.is_array = true; new_entry.size = 0; stack.push_back(new_entry); } void RGWFormatter_Plain::open_array_section_in_ns(const char *name, const char *ns) { ostringstream oss; oss << name << " " << ns; open_array_section(oss.str().c_str()); } void RGWFormatter_Plain::open_object_section(const char *name) { struct plain_stack_entry new_entry; new_entry.is_array = false; new_entry.size = 0; stack.push_back(new_entry); } void RGWFormatter_Plain::open_object_section_in_ns(const char *name, const char *ns) { ostringstream oss; oss << name << " " << ns; open_object_section(oss.str().c_str()); } void RGWFormatter_Plain::close_section() { stack.pop_back(); } void RGWFormatter_Plain::dump_unsigned(const char *name, uint64_t u) { dump_value_int(name, "%"PRIu64, u); } void RGWFormatter_Plain::dump_int(const char *name, int64_t u) { dump_value_int(name, "%"PRId64, u); } void RGWFormatter_Plain::dump_float(const char *name, double d) { dump_value_int(name, "%f", d); } void RGWFormatter_Plain::dump_string(const char *name, std::string s) { dump_format(name, "%s", s.c_str()); } std::ostream& RGWFormatter_Plain::dump_stream(const char *name) { // TODO: implement this! assert(0); } void RGWFormatter_Plain::dump_format(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; const char *format; struct plain_stack_entry& entry = stack.back(); if (!min_stack_level) min_stack_level = stack.size(); bool should_print = (stack.size() == min_stack_level && !entry.size); entry.size++; if (!should_print) return; va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); if (len) format = "\n%s"; else format = "%s"; write_data(format, buf); } int RGWFormatter_Plain::get_len() const { // don't include null termination in length return (len ? len - 1 : 0); } void RGWFormatter_Plain::write_raw_data(const char *data) { write_data("%s", data); } void RGWFormatter_Plain::write_data(const char *fmt, ...) { #define LARGE_ENOUGH_LEN 128 int n, size = LARGE_ENOUGH_LEN; char s[size + 8]; char *p, *np; bool p_on_stack; va_list ap; int pos; p = s; p_on_stack = true; while (1) { va_start(ap, fmt); n = vsnprintf(p, size, fmt, ap); va_end(ap); if (n > -1 && n < size) goto done; /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n+1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if (p_on_stack) np = (char *)malloc(size + 8); else np = (char *)realloc(p, size + 8); if (!np) goto done_free; p = np; p_on_stack = false; } done: #define LARGE_ENOUGH_BUF 4096 if (!buf) { max_len = max(LARGE_ENOUGH_BUF, size); buf = (char *)malloc(max_len); } if (len + size > max_len) { max_len = len + size + LARGE_ENOUGH_BUF; buf = (char *)realloc(buf, max_len); } if (!buf) { cerr << "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len << " bytes" << std::endl; goto done_free; } pos = len; if (len) pos--; // squash null termination strcpy(buf + pos, p); len = pos + strlen(p) + 1; done_free: if (!p_on_stack) free(p); } void RGWFormatter_Plain::dump_value_int(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; if (!min_stack_level) min_stack_level = stack.size(); struct plain_stack_entry& entry = stack.back(); bool should_print = (stack.size() == min_stack_level && !entry.size); entry.size++; if (!should_print) return; va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); const char *eol; if (len) eol = "\n"; else eol = ""; write_data("%s%s", eol, buf); } ceph-0.80.11/src/rgw/rgw_rest_bucket.h0000664000175100017510000000112012623076744021617 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_BUCKET_H #define CEPH_RGW_REST_BUCKET_H #include "rgw_rest.h" #include "rgw_rest_s3.h" class RGWHandler_Bucket : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); RGWOp *op_put(); RGWOp *op_post(); RGWOp *op_delete(); public: RGWHandler_Bucket() {} virtual ~RGWHandler_Bucket() {} int read_permissions(RGWOp*) { return 0; } }; class RGWRESTMgr_Bucket : public RGWRESTMgr { public: RGWRESTMgr_Bucket() {} virtual ~RGWRESTMgr_Bucket() {} RGWHandler *get_handler(struct req_state *s) { return new RGWHandler_Bucket; } }; #endif ceph-0.80.11/src/rgw/rgw_rest_admin.h0000664000175100017510000000027012623076744021437 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_ADMIN_H #define CEPH_RGW_REST_ADMIN_H class RGWRESTMgr_Admin : public RGWRESTMgr { public: RGWRESTMgr_Admin() {} virtual ~RGWRESTMgr_Admin() {} }; #endif ceph-0.80.11/src/rgw/rgw_cors_s3.h0000664000175100017510000000243012623076744020665 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_CORS_S3_H #define CEPH_RGW_CORS_S3_H #include #include #include #include #include #include #include "rgw_xml.h" #include "rgw_cors.h" using namespace std; class RGWCORSRule_S3 : public RGWCORSRule, public XMLObj { public: RGWCORSRule_S3() {} ~RGWCORSRule_S3() {} bool xml_end(const char *el); void to_xml(XMLFormatter& f); }; class RGWCORSConfiguration_S3 : public RGWCORSConfiguration, public XMLObj { public: RGWCORSConfiguration_S3() {} ~RGWCORSConfiguration_S3() {} bool xml_end(const char *el); void to_xml(ostream& out); }; class RGWCORSXMLParser_S3 : public RGWXMLParser { CephContext *cct; XMLObj *alloc_obj(const char *el); public: RGWCORSXMLParser_S3(CephContext *_cct) : cct(_cct) {} }; #endif /*CEPH_RGW_CORS_S3_H*/ ceph-0.80.11/src/rgw/rgw_rest_log.h0000664000175100017510000001541112623076744021133 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_REST_LOG_H #define CEPH_RGW_REST_LOG_H #include "rgw_metadata.h" class RGWOp_BILog_List : public RGWRESTOp { bool sent_header; public: RGWOp_BILog_List() : sent_header(false) {} ~RGWOp_BILog_List() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("bilog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } virtual void send_response(); virtual void send_response(list& entries, string& marker); virtual void send_response_end(); void execute(); virtual const string name() { return "list_bucket_index_log"; } }; class RGWOp_BILog_Info : public RGWRESTOp { uint64_t bucket_ver; uint64_t master_ver; string max_marker; public: RGWOp_BILog_Info() : bucket_ver(0), master_ver(0) {} ~RGWOp_BILog_Info() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("bilog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } virtual void send_response(); void execute(); virtual const string name() { return "bucket_index_log_info"; } }; class RGWOp_BILog_Delete : public RGWRESTOp { public: RGWOp_BILog_Delete() {} ~RGWOp_BILog_Delete() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("bilog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "trim_bucket_index_log"; } }; class RGWOp_MDLog_List : public RGWRESTOp { list entries; string last_marker; bool truncated; int http_ret; public: RGWOp_MDLog_List() : truncated(false), http_ret(0) {} ~RGWOp_MDLog_List() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("mdlog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "list_metadata_log"; } }; class RGWOp_MDLog_Info : public RGWRESTOp { unsigned num_objects; int http_ret; public: RGWOp_MDLog_Info() : num_objects(0), http_ret(0) {} ~RGWOp_MDLog_Info() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("mdlog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "get_metadata_log_info"; } }; class RGWOp_MDLog_ShardInfo : public RGWRESTOp { RGWMetadataLogInfo info; public: RGWOp_MDLog_ShardInfo() {} ~RGWOp_MDLog_ShardInfo() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("mdlog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "get_metadata_log_shard_info"; } }; class RGWOp_MDLog_Lock : public RGWRESTOp { public: RGWOp_MDLog_Lock() {} ~RGWOp_MDLog_Lock() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("mdlog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "lock_mdlog_object"; } }; class RGWOp_MDLog_Unlock : public RGWRESTOp { public: RGWOp_MDLog_Unlock() {} ~RGWOp_MDLog_Unlock() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("mdlog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "unlock_mdlog_object"; } }; class RGWOp_MDLog_Delete : public RGWRESTOp { public: RGWOp_MDLog_Delete() {} ~RGWOp_MDLog_Delete() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("mdlog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "trim_metadata_log"; } }; class RGWOp_DATALog_List : public RGWRESTOp { list entries; string last_marker; bool truncated; int http_ret; public: RGWOp_DATALog_List() : truncated(false), http_ret(0) {} ~RGWOp_DATALog_List() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("datalog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "list_data_changes_log"; } }; class RGWOp_DATALog_Info : public RGWRESTOp { unsigned num_objects; int http_ret; public: RGWOp_DATALog_Info() : num_objects(0), http_ret(0) {} ~RGWOp_DATALog_Info() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("datalog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "get_data_changes_log_info"; } }; class RGWOp_DATALog_ShardInfo : public RGWRESTOp { RGWDataChangesLogInfo info; public: RGWOp_DATALog_ShardInfo() {} ~RGWOp_DATALog_ShardInfo() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("datalog", RGW_CAP_READ); } int verify_permission() { return check_caps(s->user.caps); } void execute(); virtual void send_response(); virtual const string name() { return "get_data_changes_log_shard_info"; } }; class RGWOp_DATALog_Lock : public RGWRESTOp { public: RGWOp_DATALog_Lock() {} ~RGWOp_DATALog_Lock() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("datalog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "lock_datalog_object"; } }; class RGWOp_DATALog_Unlock : public RGWRESTOp { public: RGWOp_DATALog_Unlock() {} ~RGWOp_DATALog_Unlock() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("datalog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "unlock_datalog_object"; } }; class RGWOp_DATALog_Delete : public RGWRESTOp { public: RGWOp_DATALog_Delete() {} ~RGWOp_DATALog_Delete() {} int check_caps(RGWUserCaps& caps) { return caps.check_cap("datalog", RGW_CAP_WRITE); } void execute(); virtual const string name() { return "trim_data_changes_log"; } }; class RGWHandler_Log : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); RGWOp *op_delete(); RGWOp *op_post(); int read_permissions(RGWOp*) { return 0; } public: RGWHandler_Log() : RGWHandler_Auth_S3() {} virtual ~RGWHandler_Log() {} }; class RGWRESTMgr_Log : public RGWRESTMgr { public: RGWRESTMgr_Log() {} virtual ~RGWRESTMgr_Log() {} virtual RGWHandler *get_handler(struct req_state *s){ return new RGWHandler_Log; } }; #endif ceph-0.80.11/src/rgw/rgw_metadata.h0000664000175100017510000001531112623076744021074 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_METADATA_H #define CEPH_RGW_METADATA_H #include #include "include/types.h" #include "rgw_common.h" #include "cls/version/cls_version_types.h" #include "cls/log/cls_log_types.h" class RGWRados; class JSONObj; struct RGWObjVersionTracker; struct obj_version; enum RGWMDLogStatus { MDLOG_STATUS_UNKNOWN, MDLOG_STATUS_WRITE, MDLOG_STATUS_SETATTRS, MDLOG_STATUS_REMOVE, MDLOG_STATUS_COMPLETE, MDLOG_STATUS_ABORT, }; class RGWMetadataObject { protected: obj_version objv; time_t mtime; public: RGWMetadataObject() : mtime(0) {} virtual ~RGWMetadataObject() {} obj_version& get_version(); time_t get_mtime() { return mtime; } virtual void dump(Formatter *f) const = 0; }; class RGWMetadataManager; class RGWMetadataHandler { friend class RGWMetadataManager; public: enum sync_type_t { APPLY_ALWAYS, APPLY_UPDATES, APPLY_NEWER }; static bool string_to_sync_type(const string& sync_string, sync_type_t& type) { if (sync_string.compare("update-by-version") == 0) type = APPLY_UPDATES; else if (sync_string.compare("update-by-timestamp") == 0) type = APPLY_NEWER; else if (sync_string.compare("always") == 0) type = APPLY_ALWAYS; else return false; return true; } virtual ~RGWMetadataHandler() {} virtual string get_type() = 0; virtual int get(RGWRados *store, string& entry, RGWMetadataObject **obj) = 0; virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj, sync_type_t type) = 0; virtual int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) = 0; virtual int list_keys_init(RGWRados *store, void **phandle) = 0; virtual int list_keys_next(void *handle, int max, list& keys, bool *truncated) = 0; virtual void list_keys_complete(void *handle) = 0; /* key to use for hashing entries for log shard placement */ virtual void get_hash_key(const string& section, const string& key, string& hash_key) { hash_key = section + ":" + key; } protected: virtual void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) = 0; /** * Compare an incoming versus on-disk tag/version+mtime combo against * the sync mode to see if the new one should replace the on-disk one. * * @return true if the update should proceed, false otherwise. */ bool check_versions(const obj_version& ondisk, const time_t& ondisk_time, const obj_version& incoming, const time_t& incoming_time, sync_type_t sync_mode) { switch (sync_mode) { case APPLY_UPDATES: if ((ondisk.tag != incoming.tag) || (ondisk.ver >= incoming.ver)) return false; break; case APPLY_NEWER: if (ondisk_time >= incoming_time) return false; break; case APPLY_ALWAYS: //deliberate fall-thru -- we always apply! default: break; } return true; } }; #define META_LOG_OBJ_PREFIX "meta.log." struct RGWMetadataLogInfo { string marker; utime_t last_update; void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; class RGWMetadataLog { CephContext *cct; RGWRados *store; string prefix; void get_shard_oid(int id, string& oid) { char buf[16]; snprintf(buf, sizeof(buf), "%d", id); oid = prefix + buf; } public: RGWMetadataLog(CephContext *_cct, RGWRados *_store) : cct(_cct), store(_store), prefix(META_LOG_OBJ_PREFIX) {} int add_entry(RGWRados *store, RGWMetadataHandler *handler, const string& section, const string& key, bufferlist& bl); struct LogListCtx { int cur_shard; string marker; utime_t from_time; utime_t end_time; string cur_oid; bool done; LogListCtx() : cur_shard(0), done(false) {} }; void init_list_entries(int shard_id, utime_t& from_time, utime_t& end_time, string& marker, void **handle); void complete_list_entries(void *handle); int list_entries(void *handle, int max_entries, list& entries, string *out_marker, bool *truncated); int trim(int shard_id, const utime_t& from_time, const utime_t& end_time, const string& start_marker, const string& end_marker); int get_info(int shard_id, RGWMetadataLogInfo *info); int lock_exclusive(int shard_id, utime_t& duration, string&zone_id, string& owner_id); int unlock(int shard_id, string& zone_id, string& owner_id); }; struct RGWMetadataLogData; class RGWMetadataManager { map handlers; CephContext *cct; RGWRados *store; RGWMetadataLog *md_log; void parse_metadata_key(const string& metadata_key, string& type, string& entry); int find_handler(const string& metadata_key, RGWMetadataHandler **handler, string& entry); int pre_modify(RGWMetadataHandler *handler, string& section, const string& key, RGWMetadataLogData& log_data, RGWObjVersionTracker *objv_tracker, RGWMDLogStatus op_type); int post_modify(RGWMetadataHandler *handler, const string& section, const string& key, RGWMetadataLogData& log_data, RGWObjVersionTracker *objv_tracker, int ret); public: RGWMetadataManager(CephContext *_cct, RGWRados *_store); ~RGWMetadataManager(); int register_handler(RGWMetadataHandler *handler); RGWMetadataHandler *get_handler(const char *type); int put_entry(RGWMetadataHandler *handler, const string& key, bufferlist& bl, bool exclusive, RGWObjVersionTracker *objv_tracker, time_t mtime, map *pattrs = NULL); int remove_entry(RGWMetadataHandler *handler, string& key, RGWObjVersionTracker *objv_tracker); int set_attr(RGWMetadataHandler *handler, string& key, rgw_obj& obj, string& attr, bufferlist& bl, RGWObjVersionTracker *objv_tracker); int set_attrs(RGWMetadataHandler *handler, string& key, rgw_obj& obj, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker); int get(string& metadata_key, Formatter *f); int put(string& metadata_key, bufferlist& bl, RGWMetadataHandler::sync_type_t sync_mode, obj_version *existing_version = NULL); int remove(string& metadata_key); int list_keys_init(string& section, void **phandle); int list_keys_next(void *handle, int max, list& keys, bool *truncated); void list_keys_complete(void *handle); void dump_log_entry(cls_log_entry& entry, Formatter *f); void get_sections(list& sections); int lock_exclusive(string& metadata_key, utime_t duration, string& owner_id); int unlock(string& metadata_key, string& owner_id); RGWMetadataLog *get_log() { return md_log; } }; #endif ceph-0.80.11/src/rgw/rgw_cache.cc0000664000175100017510000001150012623076744020511 0ustar jenkins-buildjenkins-build#include "rgw_cache.h" #include #define dout_subsys ceph_subsys_rgw using namespace std; int ObjectCache::get(string& name, ObjectCacheInfo& info, uint32_t mask) { RWLock::RLocker l(lock); map::iterator iter = cache_map.find(name); if (iter == cache_map.end()) { ldout(cct, 10) << "cache get: name=" << name << " : miss" << dendl; if(perfcounter) perfcounter->inc(l_rgw_cache_miss); return -ENOENT; } ObjectCacheEntry& entry = iter->second; if (lru_counter - entry.lru_promotion_ts > lru_window) { ldout(cct, 20) << "cache get: touching lru, lru_counter=" << lru_counter << " promotion_ts=" << entry.lru_promotion_ts << dendl; lock.unlock(); lock.get_write(); /* promote lock to writer */ /* check again, we might have lost a race here */ if (lru_counter - entry.lru_promotion_ts > lru_window) { touch_lru(name, entry, iter->second.lru_iter); } } ObjectCacheInfo& src = iter->second.info; if ((src.flags & mask) != mask) { ldout(cct, 10) << "cache get: name=" << name << " : type miss (requested=" << mask << ", cached=" << src.flags << ")" << dendl; if(perfcounter) perfcounter->inc(l_rgw_cache_miss); return -ENOENT; } ldout(cct, 10) << "cache get: name=" << name << " : hit" << dendl; info = src; if(perfcounter) perfcounter->inc(l_rgw_cache_hit); return 0; } void ObjectCache::put(string& name, ObjectCacheInfo& info) { RWLock::WLocker l(lock); ldout(cct, 10) << "cache put: name=" << name << dendl; map::iterator iter = cache_map.find(name); if (iter == cache_map.end()) { ObjectCacheEntry entry; entry.lru_iter = lru.end(); cache_map.insert(pair(name, entry)); iter = cache_map.find(name); } ObjectCacheEntry& entry = iter->second; ObjectCacheInfo& target = entry.info; touch_lru(name, entry, entry.lru_iter); target.status = info.status; if (info.status < 0) { target.flags = 0; target.xattrs.clear(); target.data.clear(); return; } target.flags |= info.flags; if (info.flags & CACHE_FLAG_META) target.meta = info.meta; else if (!(info.flags & CACHE_FLAG_MODIFY_XATTRS)) target.flags &= ~CACHE_FLAG_META; // non-meta change should reset meta if (info.flags & CACHE_FLAG_XATTRS) { target.xattrs = info.xattrs; map::iterator iter; for (iter = target.xattrs.begin(); iter != target.xattrs.end(); ++iter) { ldout(cct, 10) << "updating xattr: name=" << iter->first << " bl.length()=" << iter->second.length() << dendl; } } else if (info.flags & CACHE_FLAG_MODIFY_XATTRS) { map::iterator iter; for (iter = info.rm_xattrs.begin(); iter != info.rm_xattrs.end(); ++iter) { ldout(cct, 10) << "removing xattr: name=" << iter->first << dendl; target.xattrs.erase(iter->first); } for (iter = info.xattrs.begin(); iter != info.xattrs.end(); ++iter) { ldout(cct, 10) << "appending xattr: name=" << iter->first << " bl.length()=" << iter->second.length() << dendl; target.xattrs[iter->first] = iter->second; } } if (info.flags & CACHE_FLAG_DATA) target.data = info.data; if (info.flags & CACHE_FLAG_OBJV) target.version = info.version; } void ObjectCache::remove(string& name) { RWLock::WLocker l(lock); map::iterator iter = cache_map.find(name); if (iter == cache_map.end()) return; ldout(cct, 10) << "removing " << name << " from cache" << dendl; remove_lru(name, iter->second.lru_iter); cache_map.erase(iter); } void ObjectCache::touch_lru(string& name, ObjectCacheEntry& entry, std::list::iterator& lru_iter) { while (lru_size > (size_t)cct->_conf->rgw_cache_lru_size) { list::iterator iter = lru.begin(); if ((*iter).compare(name) == 0) { /* * if the entry we're touching happens to be at the lru end, don't remove it, * lru shrinking can wait for next time */ break; } map::iterator map_iter = cache_map.find(*iter); ldout(cct, 10) << "removing entry: name=" << *iter << " from cache LRU" << dendl; if (map_iter != cache_map.end()) cache_map.erase(map_iter); lru.pop_front(); lru_size--; } if (lru_iter == lru.end()) { lru.push_back(name); lru_size++; lru_iter--; ldout(cct, 10) << "adding " << name << " to cache LRU end" << dendl; } else { ldout(cct, 10) << "moving " << name << " to cache LRU end" << dendl; lru.erase(lru_iter); lru.push_back(name); lru_iter = lru.end(); --lru_iter; } lru_counter++; entry.lru_promotion_ts = lru_counter; } void ObjectCache::remove_lru(string& name, std::list::iterator& lru_iter) { if (lru_iter == lru.end()) return; lru.erase(lru_iter); lru_size--; lru_iter = lru.end(); } ceph-0.80.11/src/rgw/rgw_tools.cc0000664000175100017510000000754312623076744020622 0ustar jenkins-buildjenkins-build#include #include "common/errno.h" #include "include/types.h" #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_tools.h" #define dout_subsys ceph_subsys_rgw #define READ_CHUNK_LEN (512 * 1024) static map ext_mime_map; int rgw_put_system_obj(RGWRados *rgwstore, rgw_bucket& bucket, string& oid, const char *data, size_t size, bool exclusive, RGWObjVersionTracker *objv_tracker, time_t set_mtime, map *pattrs) { map no_attrs; if (!pattrs) pattrs = &no_attrs; rgw_obj obj(bucket, oid); int ret = rgwstore->put_system_obj(NULL, obj, data, size, exclusive, NULL, *pattrs, objv_tracker, set_mtime); if (ret == -ENOENT) { ret = rgwstore->create_pool(bucket); if (ret >= 0) ret = rgwstore->put_system_obj(NULL, obj, data, size, exclusive, NULL, *pattrs, objv_tracker, set_mtime); } return ret; } int rgw_get_system_obj(RGWRados *rgwstore, void *ctx, rgw_bucket& bucket, const string& key, bufferlist& bl, RGWObjVersionTracker *objv_tracker, time_t *pmtime, map *pattrs) { struct rgw_err err; void *handle = NULL; bufferlist::iterator iter; int request_len = READ_CHUNK_LEN; rgw_obj obj(bucket, key); do { int ret = rgwstore->prepare_get_obj(ctx, obj, NULL, NULL, pattrs, NULL, NULL, pmtime, NULL, NULL, NULL, NULL, objv_tracker, &handle, &err); if (ret < 0) return ret; ret = rgwstore->get_obj(ctx, objv_tracker, &handle, obj, bl, 0, request_len - 1); rgwstore->finish_get_obj(&handle); if (ret < 0) return ret; if (ret < request_len) break; bl.clear(); request_len *= 2; } while (true); return 0; } void parse_mime_map_line(const char *start, const char *end) { char line[end - start + 1]; strncpy(line, start, end - start); line[end - start] = '\0'; char *l = line; #define DELIMS " \t\n\r" while (isspace(*l)) l++; char *mime = strsep(&l, DELIMS); if (!mime) return; char *ext; do { ext = strsep(&l, DELIMS); if (ext && *ext) { ext_mime_map[ext] = mime; } } while (ext); } void parse_mime_map(const char *buf) { const char *start = buf, *end = buf; while (*end) { while (*end && *end != '\n') { end++; } parse_mime_map_line(start, end); end++; start = end; } } static int ext_mime_map_init(CephContext *cct, const char *ext_map) { int fd = open(ext_map, O_RDONLY); char *buf = NULL; int ret; if (fd < 0) { ret = -errno; ldout(cct, 0) << "ext_mime_map_init(): failed to open file=" << ext_map << " ret=" << ret << dendl; return ret; } struct stat st; ret = fstat(fd, &st); if (ret < 0) { ret = -errno; ldout(cct, 0) << "ext_mime_map_init(): failed to stat file=" << ext_map << " ret=" << ret << dendl; goto done; } buf = (char *)malloc(st.st_size + 1); if (!buf) { ret = -ENOMEM; ldout(cct, 0) << "ext_mime_map_init(): failed to allocate buf" << dendl; goto done; } ret = read(fd, buf, st.st_size + 1); if (ret != st.st_size) { // huh? file size has changed, what are the odds? ldout(cct, 0) << "ext_mime_map_init(): raced! will retry.." << dendl; free(buf); close(fd); return ext_mime_map_init(cct, ext_map); } buf[st.st_size] = '\0'; parse_mime_map(buf); ret = 0; done: free(buf); close(fd); return ret; } const char *rgw_find_mime_by_ext(string& ext) { map::iterator iter = ext_mime_map.find(ext); if (iter == ext_mime_map.end()) return NULL; return iter->second.c_str(); } int rgw_tools_init(CephContext *cct) { int ret = ext_mime_map_init(cct, cct->_conf->rgw_mime_types_file.c_str()); if (ret < 0) return ret; return 0; } void rgw_tools_cleanup() { ext_mime_map.clear(); } ceph-0.80.11/src/rgw/rgw_rest_conn.cc0000664000175100017510000000754012623076744021451 0ustar jenkins-buildjenkins-build#include "rgw_rados.h" #include "rgw_rest_conn.h" #define dout_subsys ceph_subsys_rgw RGWRESTConn::RGWRESTConn(CephContext *_cct, RGWRados *store, list& remote_endpoints) : cct(_cct) { list::iterator iter; int i; for (i = 0, iter = remote_endpoints.begin(); iter != remote_endpoints.end(); ++iter, ++i) { endpoints[i] = *iter; } key = store->zone.system_key; region = store->region.name; } int RGWRESTConn::get_url(string& endpoint) { if (endpoints.empty()) { ldout(cct, 0) << "ERROR: endpoints not configured for upstream zone" << dendl; return -EIO; } int i = counter.inc(); endpoint = endpoints[i % endpoints.size()]; return 0; } int RGWRESTConn::forward(const string& uid, req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl) { string url; int ret = get_url(url); if (ret < 0) return ret; list > params; params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "uid", uid)); params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "region", region)); if (objv) { params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "tag", objv->tag)); char buf[16]; snprintf(buf, sizeof(buf), "%lld", (long long)objv->ver); params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "ver", buf)); } RGWRESTSimpleRequest req(cct, url, NULL, ¶ms); return req.forward_request(key, info, max_response, inbl, outbl); } class StreamObjData : public RGWGetDataCB { rgw_obj obj; public: StreamObjData(rgw_obj& _obj) : obj(_obj) {} }; int RGWRESTConn::put_obj_init(const string& uid, rgw_obj& obj, uint64_t obj_size, map& attrs, RGWRESTStreamWriteRequest **req) { string url; int ret = get_url(url); if (ret < 0) return ret; list > params; params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "uid", uid)); params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "region", region)); *req = new RGWRESTStreamWriteRequest(cct, url, NULL, ¶ms); return (*req)->put_obj_init(key, obj, obj_size, attrs); } int RGWRESTConn::complete_request(RGWRESTStreamWriteRequest *req, string& etag, time_t *mtime) { int ret = req->complete(etag, mtime); delete req; return ret; } int RGWRESTConn::get_obj(const string& uid, req_info *info /* optional */, rgw_obj& obj, bool prepend_metadata, RGWGetDataCB *cb, RGWRESTStreamReadRequest **req) { string url; int ret = get_url(url); if (ret < 0) return ret; list > params; params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "uid", uid)); params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "region", region)); if (prepend_metadata) { params.push_back(make_pair(RGW_SYS_PARAM_PREFIX "prepend-metadata", region)); } *req = new RGWRESTStreamReadRequest(cct, url, cb, NULL, ¶ms); map extra_headers; if (info) { map& orig_map = info->env->get_map(); /* add original headers that start with HTTP_X_AMZ_ */ #define SEARCH_AMZ_PREFIX "HTTP_X_AMZ_" for (map::iterator iter = orig_map.lower_bound(SEARCH_AMZ_PREFIX); iter != orig_map.end(); ++iter) { const string& name = iter->first; if (name == "HTTP_X_AMZ_DATE") /* dont forward date from original request */ continue; if (name.compare(0, sizeof(SEARCH_AMZ_PREFIX) - 1, "HTTP_X_AMZ_") != 0) break; extra_headers[iter->first] = iter->second; } } return (*req)->get_obj(key, extra_headers, obj); } int RGWRESTConn::complete_request(RGWRESTStreamReadRequest *req, string& etag, time_t *mtime, map& attrs) { int ret = req->complete(etag, mtime, attrs); delete req; return ret; } ceph-0.80.11/src/rgw/rgw_acl.h0000664000175100017510000002031312623076744020051 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_ACL_H #define CEPH_RGW_ACL_H #include #include #include #include #include "common/debug.h" using namespace std; #define RGW_PERM_READ 0x01 #define RGW_PERM_WRITE 0x02 #define RGW_PERM_READ_ACP 0x04 #define RGW_PERM_WRITE_ACP 0x08 #define RGW_PERM_READ_OBJS 0x10 #define RGW_PERM_WRITE_OBJS 0x20 #define RGW_PERM_FULL_CONTROL ( RGW_PERM_READ | RGW_PERM_WRITE | \ RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP ) #define RGW_PERM_ALL_S3 RGW_PERM_FULL_CONTROL enum ACLGranteeTypeEnum { /* numbers are encoded, should not change */ ACL_TYPE_CANON_USER = 0, ACL_TYPE_EMAIL_USER = 1, ACL_TYPE_GROUP = 2, ACL_TYPE_UNKNOWN = 3, }; enum ACLGroupTypeEnum { /* numbers are encoded should not change */ ACL_GROUP_NONE = 0, ACL_GROUP_ALL_USERS = 1, ACL_GROUP_AUTHENTICATED_USERS = 2, }; class ACLPermission { protected: int flags; public: ACLPermission() : flags(0) {} ~ACLPermission() {} int get_permissions() { return flags; } void set_permissions(int perm) { flags = perm; } void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(flags, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(flags, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ACLPermission) class ACLGranteeType { protected: __u32 type; public: ACLGranteeType() : type(ACL_TYPE_UNKNOWN) {} virtual ~ACLGranteeType() {} // virtual const char *to_string() = 0; ACLGranteeTypeEnum get_type() { return (ACLGranteeTypeEnum)type; } void set(ACLGranteeTypeEnum t) { type = t; } // virtual void set(const char *s) = 0; void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(type, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(type, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ACLGranteeType) class ACLGrantee { public: ACLGrantee() {} ~ACLGrantee() {} }; class ACLGrant { protected: ACLGranteeType type; string id; string email; ACLPermission permission; string name; ACLGroupTypeEnum group; public: ACLGrant() : group(ACL_GROUP_NONE) {} virtual ~ACLGrant() {} /* there's an assumption here that email/uri/id encodings are different and there can't be any overlap */ bool get_id(string& _id) { switch(type.get_type()) { case ACL_TYPE_EMAIL_USER: _id = email; return true; case ACL_TYPE_GROUP: return false; default: _id = id; return true; } } ACLGranteeType& get_type() { return type; } ACLPermission& get_permission() { return permission; } ACLGroupTypeEnum get_group() { return group; } void encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(type, bl); ::encode(id, bl); string uri; ::encode(uri, bl); ::encode(email, bl); ::encode(permission, bl); ::encode(name, bl); __u32 g = (__u32)group; ::encode(g, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); ::decode(type, bl); ::decode(id, bl); string uri; ::decode(uri, bl); ::decode(email, bl); ::decode(permission, bl); ::decode(name, bl); if (struct_v > 1) { __u32 g; ::decode(g, bl); group = (ACLGroupTypeEnum)g; } else { group = uri_to_group(uri); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); ACLGroupTypeEnum uri_to_group(string& uri); void set_canon(string& _id, string& _name, int perm) { type.set(ACL_TYPE_CANON_USER); id = _id; name = _name; permission.set_permissions(perm); } void set_group(ACLGroupTypeEnum _group, int perm) { type.set(ACL_TYPE_GROUP); group = _group; permission.set_permissions(perm); } }; WRITE_CLASS_ENCODER(ACLGrant) class RGWAccessControlList { protected: CephContext *cct; map acl_user_map; map acl_group_map; multimap grant_map; void _add_grant(ACLGrant *grant); public: RGWAccessControlList(CephContext *_cct) : cct(_cct) {} RGWAccessControlList() : cct(NULL) {} void set_ctx(CephContext *ctx) { cct = ctx; } virtual ~RGWAccessControlList() {} int get_perm(string& id, int perm_mask); int get_group_perm(ACLGroupTypeEnum group, int perm_mask); void encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); bool maps_initialized = true; ::encode(maps_initialized, bl); ::encode(acl_user_map, bl); ::encode(grant_map, bl); ::encode(acl_group_map, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); bool maps_initialized; ::decode(maps_initialized, bl); ::decode(acl_user_map, bl); ::decode(grant_map, bl); if (struct_v >= 2) { ::decode(acl_group_map, bl); } else if (!maps_initialized) { multimap::iterator iter; for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) { ACLGrant& grant = iter->second; _add_grant(&grant); } } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); void add_grant(ACLGrant *grant); multimap& get_grant_map() { return grant_map; } void create_default(string id, string name) { acl_user_map.clear(); acl_group_map.clear(); ACLGrant grant; grant.set_canon(id, name, RGW_PERM_FULL_CONTROL); add_grant(&grant); } }; WRITE_CLASS_ENCODER(RGWAccessControlList) class ACLOwner { protected: string id; string display_name; public: ACLOwner() {} ~ACLOwner() {} void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(id, bl); ::encode(display_name, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(id, bl); ::decode(display_name, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); void set_id(const string& _id) { id = _id; } void set_name(string& name) { display_name = name; } string& get_id() { return id; } string& get_display_name() { return display_name; } }; WRITE_CLASS_ENCODER(ACLOwner) class RGWAccessControlPolicy { protected: CephContext *cct; RGWAccessControlList acl; ACLOwner owner; public: RGWAccessControlPolicy(CephContext *_cct) : cct(_cct), acl(_cct) {} RGWAccessControlPolicy() : cct(NULL), acl(NULL) {} virtual ~RGWAccessControlPolicy() {} void set_ctx(CephContext *ctx) { cct = ctx; acl.set_ctx(ctx); } int get_perm(string& id, int perm_mask); int get_group_perm(ACLGroupTypeEnum group, int perm_mask); bool verify_permission(string& uid, int user_perm_mask, int perm); void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(owner, bl); ::encode(acl, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(owner, bl); ::decode(acl, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); void decode_owner(bufferlist::iterator& bl) { // sometimes we only need that, should be faster DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(owner, bl); DECODE_FINISH(bl); } void set_owner(ACLOwner& o) { owner = o; } ACLOwner& get_owner() { return owner; } void create_default(string& id, string& name) { acl.create_default(id, name); owner.set_id(id); owner.set_name(name); } RGWAccessControlList& get_acl() { return acl; } virtual bool compare_group_name(string& id, ACLGroupTypeEnum group) { return false; } }; WRITE_CLASS_ENCODER(RGWAccessControlPolicy) #endif ceph-0.80.11/src/rgw/rgw_cors_s3.cc0000664000175100017510000001560212623076744021030 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "include/types.h" #include "rgw_cors_s3.h" #include "rgw_user.h" #define dout_subsys ceph_subsys_rgw using namespace std; void RGWCORSRule_S3::to_xml(XMLFormatter& f) { f.open_object_section("CORSRule"); /*ID if present*/ if (id.length() > 0) { f.dump_string("ID", id);; } /*AllowedMethods*/ if (allowed_methods & RGW_CORS_GET) f.dump_string("AllowedMethod", "GET"); if (allowed_methods & RGW_CORS_PUT) f.dump_string("AllowedMethod", "PUT"); if (allowed_methods & RGW_CORS_DELETE) f.dump_string("AllowedMethod", "DELETE"); if (allowed_methods & RGW_CORS_HEAD) f.dump_string("AllowedMethod", "HEAD"); if (allowed_methods & RGW_CORS_POST) f.dump_string("AllowedMethod", "POST"); if (allowed_methods & RGW_CORS_COPY) f.dump_string("AllowedMethod", "COPY"); /*AllowedOrigins*/ for(set::iterator it = allowed_origins.begin(); it != allowed_origins.end(); ++it) { string host = *it; f.dump_string("AllowedOrigin", host); } /*AllowedHeader*/ for(set::iterator it = allowed_hdrs.begin(); it != allowed_hdrs.end(); ++it) { f.dump_string("AllowedHeader", *it); } /*MaxAgeSeconds*/ if (max_age != CORS_MAX_AGE_INVALID) { f.dump_unsigned("MaxAgeSeconds", max_age); } /*ExposeHeader*/ for(list::iterator it = exposable_hdrs.begin(); it != exposable_hdrs.end(); ++it) { f.dump_string("ExposeHeader", *it); } f.close_section(); } bool RGWCORSRule_S3::xml_end(const char *el) { XMLObjIter iter = find("AllowedMethod"); XMLObj *obj; /*Check all the allowedmethods*/ obj = iter.get_next(); if (obj) { for( ; obj; obj = iter.get_next()) { const char *s = obj->get_data().c_str(); dout(10) << "RGWCORSRule::xml_end, el : " << el << ", data : " << s << dendl; if (strcasecmp(s, "GET") == 0) { allowed_methods |= RGW_CORS_GET; } else if (strcasecmp(s, "POST") == 0) { allowed_methods |= RGW_CORS_POST; } else if (strcasecmp(s, "DELETE") == 0) { allowed_methods |= RGW_CORS_DELETE; } else if (strcasecmp(s, "HEAD") == 0) { allowed_methods |= RGW_CORS_HEAD; } else if (strcasecmp(s, "PUT") == 0) { allowed_methods |= RGW_CORS_PUT; } else if (strcasecmp(s, "COPY") == 0) { allowed_methods |= RGW_CORS_COPY; } else { return false; } } } /*Check the id's len, it should be less than 255*/ XMLObj *xml_id = find_first("ID"); if (xml_id != NULL) { string data = xml_id->get_data(); if (data.length() > 255) { dout(0) << "RGWCORSRule has id of length greater than 255" << dendl; return false; } dout(10) << "RGWCORRule id : " << data << dendl; id = data; } /*Check if there is atleast one AllowedOrigin*/ iter = find("AllowedOrigin"); if (!(obj = iter.get_next())) { dout(0) << "RGWCORSRule does not have even one AllowedOrigin" << dendl; return false; } for( ; obj; obj = iter.get_next()) { dout(10) << "RGWCORSRule - origin : " << obj->get_data() << dendl; /*Just take the hostname*/ string host = obj->get_data(); if (validate_name_string(host) != 0) return false; allowed_origins.insert(allowed_origins.end(), host); } /*Check of max_age*/ iter = find("MaxAgeSeconds"); if ((obj = iter.get_next())) { char *end = NULL; unsigned long long ull = strtoull(obj->get_data().c_str(), &end, 10); if (ull >= 0x100000000ull) { max_age = CORS_MAX_AGE_INVALID; } else { max_age = (uint32_t)ull; } dout(10) << "RGWCORSRule : max_age : " << max_age << dendl; } /*Check and update ExposeHeader*/ iter = find("ExposeHeader"); if ((obj = iter.get_next())) { for(; obj; obj = iter.get_next()) { dout(10) << "RGWCORSRule - exp_hdr : " << obj->get_data() << dendl; exposable_hdrs.push_back(obj->get_data()); } } /*Check and update AllowedHeader*/ iter = find("AllowedHeader"); if ((obj = iter.get_next())) { for(; obj; obj = iter.get_next()) { dout(10) << "RGWCORSRule - allowed_hdr : " << obj->get_data() << dendl; string s = obj->get_data(); if (validate_name_string(s) != 0) return false; allowed_hdrs.insert(allowed_hdrs.end(), s); } } return true; } void RGWCORSConfiguration_S3::to_xml(ostream& out) { XMLFormatter f; f.open_object_section("CORSConfiguration"); for(list::iterator it = rules.begin(); it != rules.end(); ++it) { (static_cast(*it)).to_xml(f); } f.close_section(); f.flush(out); } bool RGWCORSConfiguration_S3::xml_end(const char *el) { XMLObjIter iter = find("CORSRule"); RGWCORSRule_S3 *obj; if (!(obj = static_cast(iter.get_next()))) { dout(0) << "CORSConfiguration should have atleast one CORSRule" << dendl; return false; } for(; obj; obj = static_cast(iter.get_next())) { rules.push_back(*obj); } return true; } class CORSRuleID_S3 : public XMLObj { public: CORSRuleID_S3() {} ~CORSRuleID_S3() {} }; class CORSRuleAllowedOrigin_S3 : public XMLObj { public: CORSRuleAllowedOrigin_S3() {} ~CORSRuleAllowedOrigin_S3() {} }; class CORSRuleAllowedMethod_S3 : public XMLObj { public: CORSRuleAllowedMethod_S3() {} ~CORSRuleAllowedMethod_S3() {} }; class CORSRuleAllowedHeader_S3 : public XMLObj { public: CORSRuleAllowedHeader_S3() {} ~CORSRuleAllowedHeader_S3() {} }; class CORSRuleMaxAgeSeconds_S3 : public XMLObj { public: CORSRuleMaxAgeSeconds_S3() {} ~CORSRuleMaxAgeSeconds_S3() {} }; class CORSRuleExposeHeader_S3 : public XMLObj { public: CORSRuleExposeHeader_S3() {} ~CORSRuleExposeHeader_S3() {} }; XMLObj *RGWCORSXMLParser_S3::alloc_obj(const char *el) { if (strcmp(el, "CORSConfiguration") == 0) { return new RGWCORSConfiguration_S3; } else if (strcmp(el, "CORSRule") == 0) { return new RGWCORSRule_S3; } else if (strcmp(el, "ID") == 0) { return new CORSRuleID_S3; } else if (strcmp(el, "AllowedOrigin") == 0) { return new CORSRuleAllowedOrigin_S3; } else if (strcmp(el, "AllowedMethod") == 0) { return new CORSRuleAllowedMethod_S3; } else if (strcmp(el, "AllowedHeader") == 0) { return new CORSRuleAllowedHeader_S3; } else if (strcmp(el, "MaxAgeSeconds") == 0) { return new CORSRuleMaxAgeSeconds_S3; } else if (strcmp(el, "ExposeHeader") == 0) { return new CORSRuleExposeHeader_S3; } return NULL; } ceph-0.80.11/src/rgw/rgw_acl_s3.cc0000664000175100017510000003623612623076744020627 0ustar jenkins-buildjenkins-build#include #include #include #include "include/types.h" #include "rgw_acl_s3.h" #include "rgw_user.h" #define dout_subsys ceph_subsys_rgw using namespace std; #define RGW_URI_ALL_USERS "http://acs.amazonaws.com/groups/global/AllUsers" #define RGW_URI_AUTH_USERS "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" static string rgw_uri_all_users = RGW_URI_ALL_USERS; static string rgw_uri_auth_users = RGW_URI_AUTH_USERS; void ACLPermission_S3::to_xml(ostream& out) { if ((flags & RGW_PERM_FULL_CONTROL) == RGW_PERM_FULL_CONTROL) { out << "FULL_CONTROL"; } else { if (flags & RGW_PERM_READ) out << "READ"; if (flags & RGW_PERM_WRITE) out << "WRITE"; if (flags & RGW_PERM_READ_ACP) out << "READ_ACP"; if (flags & RGW_PERM_WRITE_ACP) out << "WRITE_ACP"; } } bool ACLPermission_S3:: xml_end(const char *el) { const char *s = data.c_str(); if (strcasecmp(s, "READ") == 0) { flags |= RGW_PERM_READ; return true; } else if (strcasecmp(s, "WRITE") == 0) { flags |= RGW_PERM_WRITE; return true; } else if (strcasecmp(s, "READ_ACP") == 0) { flags |= RGW_PERM_READ_ACP; return true; } else if (strcasecmp(s, "WRITE_ACP") == 0) { flags |= RGW_PERM_WRITE_ACP; return true; } else if (strcasecmp(s, "FULL_CONTROL") == 0) { flags |= RGW_PERM_FULL_CONTROL; return true; } return false; } class ACLGranteeType_S3 { public: static const char *to_string(ACLGranteeType& type) { switch (type.get_type()) { case ACL_TYPE_CANON_USER: return "CanonicalUser"; case ACL_TYPE_EMAIL_USER: return "AmazonCustomerByEmail"; case ACL_TYPE_GROUP: return "Group"; default: return "unknown"; } } static void set(const char *s, ACLGranteeType& type) { if (!s) { type.set(ACL_TYPE_UNKNOWN); return; } if (strcmp(s, "CanonicalUser") == 0) type.set(ACL_TYPE_CANON_USER); else if (strcmp(s, "AmazonCustomerByEmail") == 0) type.set(ACL_TYPE_EMAIL_USER); else if (strcmp(s, "Group") == 0) type.set(ACL_TYPE_GROUP); else type.set(ACL_TYPE_UNKNOWN); } }; class ACLID_S3 : public XMLObj { public: ACLID_S3() {} ~ACLID_S3() {} string& to_str() { return data; } }; class ACLURI_S3 : public XMLObj { public: ACLURI_S3() {} ~ACLURI_S3() {} }; class ACLEmail_S3 : public XMLObj { public: ACLEmail_S3() {} ~ACLEmail_S3() {} }; class ACLDisplayName_S3 : public XMLObj { public: ACLDisplayName_S3() {} ~ACLDisplayName_S3() {} }; bool ACLOwner_S3::xml_end(const char *el) { ACLID_S3 *acl_id = static_cast(find_first("ID")); ACLID_S3 *acl_name = static_cast(find_first("DisplayName")); // ID is mandatory if (!acl_id) return false; id = acl_id->get_data(); // DisplayName is optional if (acl_name) display_name = acl_name->get_data(); else display_name = ""; return true; } bool ACLGrant_S3::xml_end(const char *el) { ACLGrantee_S3 *acl_grantee; ACLID_S3 *acl_id; ACLURI_S3 *acl_uri; ACLEmail_S3 *acl_email; ACLPermission_S3 *acl_permission; ACLDisplayName_S3 *acl_name; string uri; acl_grantee = static_cast(find_first("Grantee")); if (!acl_grantee) return false; string type_str; if (!acl_grantee->get_attr("xsi:type", type_str)) return false; ACLGranteeType_S3::set(type_str.c_str(), type); acl_permission = static_cast(find_first("Permission")); if (!acl_permission) return false; permission = *acl_permission; id.clear(); name.clear(); email.clear(); switch (type.get_type()) { case ACL_TYPE_CANON_USER: acl_id = static_cast(acl_grantee->find_first("ID")); if (!acl_id) return false; id = acl_id->to_str(); acl_name = static_cast(acl_grantee->find_first("DisplayName")); if (acl_name) name = acl_name->get_data(); break; case ACL_TYPE_GROUP: acl_uri = static_cast(acl_grantee->find_first("URI")); if (!acl_uri) return false; uri = acl_uri->get_data(); group = uri_to_group(uri); break; case ACL_TYPE_EMAIL_USER: acl_email = static_cast(acl_grantee->find_first("EmailAddress")); if (!acl_email) return false; email = acl_email->get_data(); break; default: // unknown user type return false; }; return true; } void ACLGrant_S3::to_xml(CephContext *cct, ostream& out) { ACLPermission_S3& perm = static_cast(permission); /* only show s3 compatible permissions */ if (!(perm.get_permissions() & RGW_PERM_ALL_S3)) return; string uri; out << "" << ""; switch (type.get_type()) { case ACL_TYPE_CANON_USER: out << "" << id << ""; if (name.size()) { out << "" << name << ""; } break; case ACL_TYPE_EMAIL_USER: out << "" << email << ""; break; case ACL_TYPE_GROUP: if (!group_to_uri(group, uri)) { ldout(cct, 0) << "ERROR: group_to_uri failed with group=" << (int)group << dendl; break; } out << "" << uri << ""; break; default: break; } out << ""; perm.to_xml(out); out << ""; } bool ACLGrant_S3::group_to_uri(ACLGroupTypeEnum group, string& uri) { switch (group) { case ACL_GROUP_ALL_USERS: uri = rgw_uri_all_users; return true; case ACL_GROUP_AUTHENTICATED_USERS: uri = rgw_uri_auth_users; return true; default: return false; } } bool RGWAccessControlList_S3::xml_end(const char *el) { XMLObjIter iter = find("Grant"); ACLGrant_S3 *grant = static_cast(iter.get_next()); while (grant) { add_grant(grant); grant = static_cast(iter.get_next()); } return true; } struct s3_acl_header { int rgw_perm; const char *http_header; }; static const char *get_acl_header(RGWEnv *env, const struct s3_acl_header *perm) { const char *header = perm->http_header; return env->get(header, NULL); } static int parse_grantee_str(RGWRados *store, string& grantee_str, const struct s3_acl_header *perm, ACLGrant& grant) { string id_type, id_val_quoted; int rgw_perm = perm->rgw_perm; int ret; RGWUserInfo info; ret = parse_key_value(grantee_str, id_type, id_val_quoted); if (ret < 0) return ret; string id_val = rgw_trim_quotes(id_val_quoted); if (strcasecmp(id_type.c_str(), "emailAddress") == 0) { ret = rgw_get_user_info_by_email(store, id_val, info); if (ret < 0) return ret; grant.set_canon(info.user_id, info.display_name, rgw_perm); } else if (strcasecmp(id_type.c_str(), "id") == 0) { ret = rgw_get_user_info_by_uid(store, id_val, info); if (ret < 0) return ret; grant.set_canon(info.user_id, info.display_name, rgw_perm); } else if (strcasecmp(id_type.c_str(), "uri") == 0) { ACLGroupTypeEnum gid = grant.uri_to_group(id_val); if (gid == ACL_GROUP_NONE) return -EINVAL; grant.set_group(gid, rgw_perm); } else { return -EINVAL; } return 0; } static int parse_acl_header(RGWRados *store, RGWEnv *env, const struct s3_acl_header *perm, std::list& _grants) { std::list grantees; std::string hacl_str; const char *hacl = get_acl_header(env, perm); if (hacl == NULL) return 0; hacl_str = hacl; get_str_list(hacl_str, ",", grantees); for (list::iterator it = grantees.begin(); it != grantees.end(); ++it) { ACLGrant grant; int ret = parse_grantee_str(store, *it, perm, grant); if (ret < 0) return ret; _grants.push_back(grant); } return 0; } int RGWAccessControlList_S3::create_canned(ACLOwner& owner, ACLOwner& bucket_owner, const string& canned_acl) { acl_user_map.clear(); grant_map.clear(); ACLGrant owner_grant; string bid = bucket_owner.get_id(); string bname = bucket_owner.get_display_name(); /* owner gets full control */ owner_grant.set_canon(owner.get_id(), owner.get_display_name(), RGW_PERM_FULL_CONTROL); add_grant(&owner_grant); if (canned_acl.size() == 0 || canned_acl.compare("private") == 0) { return 0; } ACLGrant bucket_owner_grant; ACLGrant group_grant; if (canned_acl.compare("public-read") == 0) { group_grant.set_group(ACL_GROUP_ALL_USERS, RGW_PERM_READ); add_grant(&group_grant); } else if (canned_acl.compare("public-read-write") == 0) { group_grant.set_group(ACL_GROUP_ALL_USERS, RGW_PERM_READ); add_grant(&group_grant); group_grant.set_group(ACL_GROUP_ALL_USERS, RGW_PERM_WRITE); add_grant(&group_grant); } else if (canned_acl.compare("authenticated-read") == 0) { group_grant.set_group(ACL_GROUP_AUTHENTICATED_USERS, RGW_PERM_READ); add_grant(&group_grant); } else if (canned_acl.compare("bucket-owner-read") == 0) { bucket_owner_grant.set_canon(bid, bname, RGW_PERM_READ); if (bid.compare(owner.get_id()) != 0) add_grant(&bucket_owner_grant); } else if (canned_acl.compare("bucket-owner-full-control") == 0) { bucket_owner_grant.set_canon(bid, bname, RGW_PERM_FULL_CONTROL); if (bid.compare(owner.get_id()) != 0) add_grant(&bucket_owner_grant); } else { return -EINVAL; } return 0; } int RGWAccessControlList_S3::create_from_grants(std::list& grants) { if (grants.empty()) return -EINVAL; acl_user_map.clear(); grant_map.clear(); for (std::list::iterator it = grants.begin(); it != grants.end(); ++it) { ACLGrant g = *it; add_grant(&g); } return 0; } bool RGWAccessControlPolicy_S3::xml_end(const char *el) { RGWAccessControlList_S3 *s3acl = static_cast(find_first("AccessControlList")); if (!s3acl) return false; acl = *s3acl; ACLOwner *owner_p = static_cast(find_first("Owner")); if (!owner_p) return false; owner = *owner_p; return true; } static const s3_acl_header acl_header_perms[] = { {RGW_PERM_READ, "HTTP_X_AMZ_GRANT_READ"}, {RGW_PERM_WRITE, "HTTP_X_AMZ_GRANT_WRITE"}, {RGW_PERM_READ_ACP,"HTTP_X_AMZ_GRANT_READ_ACP"}, {RGW_PERM_WRITE_ACP, "HTTP_X_AMZ_GRANT_WRITE_ACP"}, {RGW_PERM_FULL_CONTROL, "HTTP_X_AMZ_GRANT_FULL_CONTROL"}, {0, NULL} }; int RGWAccessControlPolicy_S3::create_from_headers(RGWRados *store, RGWEnv *env, ACLOwner& _owner) { std::list grants; for (const struct s3_acl_header *p = acl_header_perms; p->rgw_perm; p++) { if (parse_acl_header(store, env, p, grants) < 0) return false; } RGWAccessControlList_S3& _acl = static_cast(acl); int r = _acl.create_from_grants(grants); owner = _owner; return r; } /* can only be called on object that was parsed */ int RGWAccessControlPolicy_S3::rebuild(RGWRados *store, ACLOwner *owner, RGWAccessControlPolicy& dest) { if (!owner) return -EINVAL; ACLOwner *requested_owner = static_cast(find_first("Owner")); if (requested_owner) { const string& requested_id = requested_owner->get_id(); if (!requested_id.empty() && requested_id.compare(owner->get_id()) != 0) return -EPERM; } RGWUserInfo owner_info; if (rgw_get_user_info_by_uid(store, owner->get_id(), owner_info) < 0) { ldout(cct, 10) << "owner info does not exist" << dendl; return -EINVAL; } ACLOwner& dest_owner = dest.get_owner(); dest_owner.set_id(owner->get_id()); dest_owner.set_name(owner_info.display_name); ldout(cct, 20) << "owner id=" << owner->get_id() << dendl; ldout(cct, 20) << "dest owner id=" << dest.get_owner().get_id() << dendl; RGWAccessControlList& dst_acl = dest.get_acl(); multimap& grant_map = acl.get_grant_map(); multimap::iterator iter; for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) { ACLGrant& src_grant = iter->second; ACLGranteeType& type = src_grant.get_type(); ACLGrant new_grant; bool grant_ok = false; string uid; RGWUserInfo grant_user; switch (type.get_type()) { case ACL_TYPE_EMAIL_USER: { string email; if (!src_grant.get_id(email)) { ldout(cct, 0) << "ERROR: src_grant.get_id() failed" << dendl; return -EINVAL; } ldout(cct, 10) << "grant user email=" << email << dendl; if (rgw_get_user_info_by_email(store, email, grant_user) < 0) { ldout(cct, 10) << "grant user email not found or other error" << dendl; return -ERR_UNRESOLVABLE_EMAIL; } uid = grant_user.user_id; } case ACL_TYPE_CANON_USER: { if (type.get_type() == ACL_TYPE_CANON_USER) { if (!src_grant.get_id(uid)) { ldout(cct, 0) << "ERROR: src_grant.get_id() failed" << dendl; return -EINVAL; } } if (grant_user.user_id.empty() && rgw_get_user_info_by_uid(store, uid, grant_user) < 0) { ldout(cct, 10) << "grant user does not exist:" << uid << dendl; return -EINVAL; } else { ACLPermission& perm = src_grant.get_permission(); new_grant.set_canon(uid, grant_user.display_name, perm.get_permissions()); grant_ok = true; string new_id; new_grant.get_id(new_id); ldout(cct, 10) << "new grant: " << new_id << ":" << grant_user.display_name << dendl; } } break; case ACL_TYPE_GROUP: { string uri; if (ACLGrant_S3::group_to_uri(src_grant.get_group(), uri)) { new_grant = src_grant; grant_ok = true; ldout(cct, 10) << "new grant: " << uri << dendl; } else { ldout(cct, 10) << "bad grant group:" << (int)src_grant.get_group() << dendl; return -EINVAL; } } default: break; } if (grant_ok) { dst_acl.add_grant(&new_grant); } } return 0; } bool RGWAccessControlPolicy_S3::compare_group_name(string& id, ACLGroupTypeEnum group) { switch (group) { case ACL_GROUP_ALL_USERS: return (id.compare(rgw_uri_all_users) == 0); case ACL_GROUP_AUTHENTICATED_USERS: return (id.compare(rgw_uri_auth_users) == 0); default: return id.empty(); } // shouldn't get here return false; } XMLObj *RGWACLXMLParser_S3::alloc_obj(const char *el) { XMLObj * obj = NULL; if (strcmp(el, "AccessControlPolicy") == 0) { obj = new RGWAccessControlPolicy_S3(cct); } else if (strcmp(el, "Owner") == 0) { obj = new ACLOwner_S3(); } else if (strcmp(el, "AccessControlList") == 0) { obj = new RGWAccessControlList_S3(cct); } else if (strcmp(el, "ID") == 0) { obj = new ACLID_S3(); } else if (strcmp(el, "DisplayName") == 0) { obj = new ACLDisplayName_S3(); } else if (strcmp(el, "Grant") == 0) { obj = new ACLGrant_S3(); } else if (strcmp(el, "Grantee") == 0) { obj = new ACLGrantee_S3(); } else if (strcmp(el, "Permission") == 0) { obj = new ACLPermission_S3(); } else if (strcmp(el, "URI") == 0) { obj = new ACLURI_S3(); } else if (strcmp(el, "EmailAddress") == 0) { obj = new ACLEmail_S3(); } return obj; } ceph-0.80.11/src/rgw/rgw_multiparser.cc0000664000175100017510000000125412623076744022022 0ustar jenkins-buildjenkins-build#include #include #include #include "include/types.h" #include "rgw_multi.h" #define dout_subsys ceph_subsys_rgw using namespace std; int main(int argc, char **argv) { RGWMultiXMLParser parser; if (!parser.init()) exit(1); char buf[1024]; for (;;) { int done; int len; len = fread(buf, 1, sizeof(buf), stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); exit(-1); } done = feof(stdin); bool result = parser.parse(buf, len, done); if (!result) { cerr << "failed to parse!" << std::endl; } if (done) break; } exit(0); } ceph-0.80.11/src/rgw/rgw_replica_log.h0000664000175100017510000000706712623076744021605 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef RGW_REPLICA_LOG_H_ #define RGW_REPLICA_LOG_H_ #include #include "cls/replica_log/cls_replica_log_types.h" #include "include/types.h" #include "include/utime.h" #include "include/rados/librados.hpp" #include "rgw_common.h" class RGWRados; class CephContext; using namespace std; #define META_REPLICA_LOG_OBJ_PREFIX "meta.replicalog." #define DATA_REPLICA_LOG_OBJ_PREFIX "data.replicalog." typedef cls_replica_log_item_marker RGWReplicaItemMarker; typedef cls_replica_log_progress_marker RGWReplicaProgressMarker; struct RGWReplicaBounds { string marker; utime_t oldest_time; list markers; void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; class RGWReplicaLogger { protected: CephContext *cct; RGWRados *store; int open_ioctx(librados::IoCtx& ctx, const string& pool); RGWReplicaLogger(RGWRados *_store); int update_bound(const string& oid, const string& pool, const string& daemon_id, const string& marker, const utime_t& time, const list *entries); int delete_bound(const string& oid, const string& pool, const string& daemon_id); int get_bounds(const string& oid, const string& pool, RGWReplicaBounds& bounds); }; class RGWReplicaObjectLogger : private RGWReplicaLogger { string pool; string prefix; void get_shard_oid(int id, string& oid) { char buf[16]; snprintf(buf, sizeof(buf), "%d", id); oid = prefix + buf; } public: RGWReplicaObjectLogger(RGWRados *_store, const string& _pool, const string& _prefix); int create_log_objects(int shards); int update_bound(int shard, const string& daemon_id, const string& marker, const utime_t& time, const list *entries) { string oid; get_shard_oid(shard, oid); return RGWReplicaLogger::update_bound(oid, pool, daemon_id, marker, time, entries); } int delete_bound(int shard, const string& daemon_id) { string oid; get_shard_oid(shard, oid); return RGWReplicaLogger::delete_bound(oid, pool, daemon_id); } int get_bounds(int shard, RGWReplicaBounds& bounds) { string oid; get_shard_oid(shard, oid); return RGWReplicaLogger::get_bounds(oid, pool, bounds); } }; class RGWReplicaBucketLogger : private RGWReplicaLogger { string pool; string prefix; public: RGWReplicaBucketLogger(RGWRados *_store); int update_bound(const rgw_bucket& bucket, const string& daemon_id, const string& marker, const utime_t& time, const list *entries) { return RGWReplicaLogger::update_bound(prefix+bucket.name, pool, daemon_id, marker, time, entries); } int delete_bound(const rgw_bucket& bucket, const string& daemon_id) { return RGWReplicaLogger::delete_bound(prefix+bucket.name, pool, daemon_id); } int get_bounds(const rgw_bucket& bucket, RGWReplicaBounds& bounds) { return RGWReplicaLogger::get_bounds(prefix+bucket.name, pool, bounds); } }; #endif /* RGW_REPLICA_LOG_H_ */ ceph-0.80.11/src/rgw/rgw_cors_swift.h0000664000175100017510000000405412623076744021500 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_CORS_SWIFT3_H #define CEPH_RGW_CORS_SWIFT3_H #include #include #include #include #include #include #include "rgw_cors.h" using namespace std; class RGWCORSConfiguration_SWIFT : public RGWCORSConfiguration { public: RGWCORSConfiguration_SWIFT() {} ~RGWCORSConfiguration_SWIFT() {} int create_update(const char *allow_origins, const char *allow_headers, const char *expose_headers, const char *max_age) { set o, h, oc; list e; unsigned long a = CORS_MAX_AGE_INVALID; uint8_t flags = RGW_CORS_ALL; string ao = allow_origins; get_str_set(ao, oc); if (oc.empty()) return -EINVAL; for(set::iterator it = oc.begin(); it != oc.end(); ++it) { string host = *it; if (validate_name_string(host) != 0) return -EINVAL; o.insert(o.end(), host); } if (allow_headers) { string ah = allow_headers; get_str_set(ah, h); for(set::iterator it = h.begin(); it != h.end(); ++it) { string s = (*it); if (validate_name_string(s) != 0) return -EINVAL; } } if (expose_headers) { string eh = expose_headers; get_str_list(eh, e); } if (max_age) { char *end = NULL; a = strtoul(max_age, &end, 10); if (a == ULONG_MAX) a = CORS_MAX_AGE_INVALID; } RGWCORSRule rule(o, h, e, flags, a); stack_rule(rule); return 0; } }; #endif /*CEPH_RGW_CORS_SWIFT3_H*/ ceph-0.80.11/src/rgw/rgw_log.h0000664000175100017510000000705512623076744020103 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_LOG_H #define CEPH_RGW_LOG_H #include "rgw_common.h" #include "include/utime.h" #include "common/Formatter.h" #include "common/OutputDataSocket.h" class RGWRados; struct rgw_log_entry { string object_owner; string bucket_owner; string bucket; utime_t time; string remote_addr; string user; string obj; string op; string uri; string http_status; string error_code; uint64_t bytes_sent; uint64_t bytes_received; uint64_t obj_size; utime_t total_time; string user_agent; string referrer; string bucket_id; void encode(bufferlist &bl) const { ENCODE_START(6, 5, bl); ::encode(object_owner, bl); ::encode(bucket_owner, bl); ::encode(bucket, bl); ::encode(time, bl); ::encode(remote_addr, bl); ::encode(user, bl); ::encode(obj, bl); ::encode(op, bl); ::encode(uri, bl); ::encode(http_status, bl); ::encode(error_code, bl); ::encode(bytes_sent, bl); ::encode(obj_size, bl); ::encode(total_time, bl); ::encode(user_agent, bl); ::encode(referrer, bl); ::encode(bytes_received, bl); ::encode(bucket_id, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START_LEGACY_COMPAT_LEN(6, 5, 5, p); ::decode(object_owner, p); if (struct_v > 3) ::decode(bucket_owner, p); ::decode(bucket, p); ::decode(time, p); ::decode(remote_addr, p); ::decode(user, p); ::decode(obj, p); ::decode(op, p); ::decode(uri, p); ::decode(http_status, p); ::decode(error_code, p); ::decode(bytes_sent, p); ::decode(obj_size, p); ::decode(total_time, p); ::decode(user_agent, p); ::decode(referrer, p); if (struct_v >= 2) ::decode(bytes_received, p); else bytes_received = 0; if (struct_v >= 3) { if (struct_v <= 5) { uint64_t id; ::decode(id, p); char buf[32]; snprintf(buf, sizeof(buf), "%llu", (long long)id); bucket_id = buf; } else { ::decode(bucket_id, p); } } else bucket_id = ""; DECODE_FINISH(p); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_log_entry) struct rgw_intent_log_entry { rgw_obj obj; utime_t op_time; uint32_t intent; void encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(obj, bl); ::encode(op_time, bl); ::encode(intent, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &p) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, p); ::decode(obj, p); ::decode(op_time, p); ::decode(intent, p); DECODE_FINISH(p); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_intent_log_entry) class OpsLogSocket : public OutputDataSocket { Formatter *formatter; Mutex lock; void formatter_to_bl(bufferlist& bl); protected: void init_connection(bufferlist& bl); public: OpsLogSocket(CephContext *cct, uint64_t _backlog); ~OpsLogSocket(); void log(struct rgw_log_entry& entry); }; int rgw_log_op(RGWRados *store, struct req_state *s, const string& op_name, OpsLogSocket *olog); int rgw_log_intent(RGWRados *store, rgw_obj& obj, RGWIntentEvent intent, const utime_t& timestamp, bool utc); int rgw_log_intent(RGWRados *store, struct req_state *s, rgw_obj& obj, RGWIntentEvent intent); void rgw_log_usage_init(CephContext *cct, RGWRados *store); void rgw_log_usage_finalize(); void rgw_format_ops_log_entry(struct rgw_log_entry& entry, Formatter *formatter); #endif ceph-0.80.11/src/rgw/rgw_acl_s3.h0000664000175100017510000000656612623076744020474 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_ACL_S3_H #define CEPH_RGW_ACL_S3_H #include #include #include #include #include #include "include/str_list.h" #include "rgw_xml.h" #include "rgw_acl.h" using namespace std; class RGWRados; class ACLPermission_S3 : public ACLPermission, public XMLObj { public: ACLPermission_S3() {} ~ACLPermission_S3() {} bool xml_end(const char *el); void to_xml(ostream& out); }; class ACLGrantee_S3 : public ACLGrantee, public XMLObj { public: ACLGrantee_S3() {} ~ACLGrantee_S3() {} bool xml_start(const char *el, const char **attr); }; class ACLGrant_S3 : public ACLGrant, public XMLObj { public: ACLGrant_S3() {} ~ACLGrant_S3() {} void to_xml(CephContext *cct, ostream& out); bool xml_end(const char *el); bool xml_start(const char *el, const char **attr); static ACLGroupTypeEnum uri_to_group(string& uri); static bool group_to_uri(ACLGroupTypeEnum group, string& uri); }; class RGWAccessControlList_S3 : public RGWAccessControlList, public XMLObj { public: RGWAccessControlList_S3(CephContext *_cct) : RGWAccessControlList(_cct) {} ~RGWAccessControlList_S3() {} bool xml_end(const char *el); void to_xml(ostream& out) { multimap::iterator iter; out << ""; for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) { ACLGrant_S3& grant = static_cast(iter->second); grant.to_xml(cct, out); } out << ""; } int create_canned(ACLOwner& owner, ACLOwner& bucket_owner, const string& canned_acl); int create_from_grants(std::list& grants); }; class ACLOwner_S3 : public ACLOwner, public XMLObj { public: ACLOwner_S3() {} ~ACLOwner_S3() {} bool xml_end(const char *el); void to_xml(ostream& out) { if (id.empty()) return; out << "" << "" << id << ""; if (!display_name.empty()) out << "" << display_name << ""; out << ""; } }; class RGWEnv; class RGWAccessControlPolicy_S3 : public RGWAccessControlPolicy, public XMLObj { public: RGWAccessControlPolicy_S3(CephContext *_cct) : RGWAccessControlPolicy(_cct) {} ~RGWAccessControlPolicy_S3() {} bool xml_end(const char *el); void to_xml(ostream& out) { out << ""; ACLOwner_S3& _owner = static_cast(owner); RGWAccessControlList_S3& _acl = static_cast(acl); _owner.to_xml(out); _acl.to_xml(out); out << ""; } int rebuild(RGWRados *store, ACLOwner *owner, RGWAccessControlPolicy& dest); bool compare_group_name(string& id, ACLGroupTypeEnum group); virtual int create_canned(ACLOwner& _owner, ACLOwner& bucket_owner, string canned_acl) { RGWAccessControlList_S3& _acl = static_cast(acl); int ret = _acl.create_canned(_owner, bucket_owner, canned_acl); owner = _owner; return ret; } int create_from_headers(RGWRados *store, RGWEnv *env, ACLOwner& _owner); }; /** * Interfaces with the webserver's XML handling code * to parse it in a way that makes sense for the rgw. */ class RGWACLXMLParser_S3 : public RGWXMLParser { CephContext *cct; XMLObj *alloc_obj(const char *el); public: RGWACLXMLParser_S3(CephContext *_cct) : cct(_cct) {} }; #endif ceph-0.80.11/src/rgw/rgw_op.cc0000664000175100017510000024042512623076744020076 0ustar jenkins-buildjenkins-build #include #include #include #include "common/Clock.h" #include "common/armor.h" #include "common/mime.h" #include "common/utf8.h" #include "common/ceph_json.h" #include "rgw_rados.h" #include "rgw_op.h" #include "rgw_rest.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" #include "rgw_user.h" #include "rgw_bucket.h" #include "rgw_log.h" #include "rgw_multi.h" #include "rgw_multi_del.h" #include "rgw_cors.h" #include "rgw_cors_s3.h" #include "rgw_client_io.h" #define dout_subsys ceph_subsys_rgw using namespace std; using ceph::crypto::MD5; static string mp_ns = RGW_OBJ_NS_MULTIPART; static string shadow_ns = RGW_OBJ_NS_SHADOW; #define MULTIPART_UPLOAD_ID_PREFIX_LEGACY "2/" #define MULTIPART_UPLOAD_ID_PREFIX "2~" // must contain a unique char that may not come up in gen_rand_alpha() class MultipartMetaFilter : public RGWAccessListFilter { public: MultipartMetaFilter() {} bool filter(string& name, string& key) { int len = name.size(); if (len < 6) return false; int pos = name.find(MP_META_SUFFIX, len - 5); if (pos <= 0) return false; pos = name.rfind('.', pos - 1); if (pos < 0) return false; key = name.substr(0, pos); return true; } }; static MultipartMetaFilter mp_filter; static int parse_range(const char *range, off_t& ofs, off_t& end, bool *partial_content) { int r = -ERANGE; string s(range); string ofs_str; string end_str; *partial_content = false; int pos = s.find("bytes="); if (pos < 0) { pos = 0; while (isspace(s[pos])) pos++; int end = pos; while (isalpha(s[end])) end++; if (strncasecmp(s.c_str(), "bytes", end - pos) != 0) return 0; while (isspace(s[end])) end++; if (s[end] != '=') return 0; s = s.substr(end + 1); } else { s = s.substr(pos + 6); /* size of("bytes=") */ } pos = s.find('-'); if (pos < 0) goto done; *partial_content = true; ofs_str = s.substr(0, pos); end_str = s.substr(pos + 1); if (end_str.length()) { end = atoll(end_str.c_str()); if (end < 0) goto done; } if (ofs_str.length()) { ofs = atoll(ofs_str.c_str()); } else { // RFC2616 suffix-byte-range-spec ofs = -end; end = -1; } if (end >= 0 && end < ofs) goto done; r = 0; done: return r; } static void format_xattr(std::string &xattr) { /* If the extended attribute is not valid UTF-8, we encode it using quoted-printable * encoding. */ if ((check_utf8(xattr.c_str(), xattr.length()) != 0) || (check_for_control_characters(xattr.c_str(), xattr.length()) != 0)) { static const char MIME_PREFIX_STR[] = "=?UTF-8?Q?"; static const int MIME_PREFIX_LEN = sizeof(MIME_PREFIX_STR) - 1; static const char MIME_SUFFIX_STR[] = "?="; static const int MIME_SUFFIX_LEN = sizeof(MIME_SUFFIX_STR) - 1; int mlen = mime_encode_as_qp(xattr.c_str(), NULL, 0); char *mime = new char[MIME_PREFIX_LEN + mlen + MIME_SUFFIX_LEN + 1]; strcpy(mime, MIME_PREFIX_STR); mime_encode_as_qp(xattr.c_str(), mime + MIME_PREFIX_LEN, mlen); strcpy(mime + MIME_PREFIX_LEN + (mlen - 1), MIME_SUFFIX_STR); xattr.assign(mime); delete [] mime; } } /** * Get the HTTP request metadata out of the req_state as a * map(, where attr_name is RGW_ATTR_PREFIX.HTTP_NAME) * s: The request state * attrs: will be filled up with attrs mapped as * */ static void rgw_get_request_metadata(CephContext *cct, struct req_info& info, map& attrs) { map::iterator iter; for (iter = info.x_meta_map.begin(); iter != info.x_meta_map.end(); ++iter) { const string &name(iter->first); string &xattr(iter->second); ldout(cct, 10) << "x>> " << name << ":" << xattr << dendl; format_xattr(xattr); string attr_name(RGW_ATTR_PREFIX); attr_name.append(name); map::value_type v(attr_name, bufferlist()); std::pair < map::iterator, bool > rval(attrs.insert(v)); bufferlist& bl(rval.first->second); bl.append(xattr.c_str(), xattr.size() + 1); } } static int decode_policy(CephContext *cct, bufferlist& bl, RGWAccessControlPolicy *policy) { bufferlist::iterator iter = bl.begin(); try { policy->decode(iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl; return -EIO; } if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) { RGWAccessControlPolicy_S3 *s3policy = static_cast(policy); ldout(cct, 15) << "Read AccessControlPolicy"; s3policy->to_xml(*_dout); *_dout << dendl; } return 0; } static int get_bucket_policy_from_attr(CephContext *cct, RGWRados *store, void *ctx, RGWBucketInfo& bucket_info, map& bucket_attrs, RGWAccessControlPolicy *policy, rgw_obj& obj) { map::iterator aiter = bucket_attrs.find(RGW_ATTR_ACL); if (aiter != bucket_attrs.end()) { int ret = decode_policy(cct, aiter->second, policy); if (ret < 0) return ret; } else { ldout(cct, 0) << "WARNING: couldn't find acl header for bucket, generating default" << dendl; RGWUserInfo uinfo; /* object exists, but policy is broken */ int r = rgw_get_user_info_by_uid(store, bucket_info.owner, uinfo); if (r < 0) return r; policy->create_default(bucket_info.owner, uinfo.display_name); } return 0; } static int get_obj_policy_from_attr(CephContext *cct, RGWRados *store, void *ctx, RGWBucketInfo& bucket_info, map& bucket_attrs, RGWAccessControlPolicy *policy, rgw_obj& obj) { bufferlist bl; int ret = 0; ret = store->get_attr(ctx, obj, RGW_ATTR_ACL, bl); if (ret >= 0) { ret = decode_policy(cct, bl, policy); if (ret < 0) return ret; } else if (ret == -ENODATA) { /* object exists, but policy is broken */ ldout(cct, 0) << "WARNING: couldn't find acl header for object, generating default" << dendl; RGWUserInfo uinfo; ret = rgw_get_user_info_by_uid(store, bucket_info.owner, uinfo); if (ret < 0) return ret; policy->create_default(bucket_info.owner, uinfo.display_name); } return ret; } /** * Get the AccessControlPolicy for an object off of disk. * policy: must point to a valid RGWACL, and will be filled upon return. * bucket: name of the bucket containing the object. * object: name of the object to get the ACL for. * Returns: 0 on success, -ERR# otherwise. */ static int get_policy_from_attr(CephContext *cct, RGWRados *store, void *ctx, RGWBucketInfo& bucket_info, map& bucket_attrs, RGWAccessControlPolicy *policy, rgw_obj& obj) { if (obj.bucket.name.empty()) { return 0; } if (obj.object.empty()) { rgw_obj instance_obj; store->get_bucket_instance_obj(bucket_info.bucket, instance_obj); return get_bucket_policy_from_attr(cct, store, ctx, bucket_info, bucket_attrs, policy, instance_obj); } return get_obj_policy_from_attr(cct, store, ctx, bucket_info, bucket_attrs, policy, obj); } static int get_obj_attrs(RGWRados *store, struct req_state *s, rgw_obj& obj, map& attrs, uint64_t *obj_size, RGWObjVersionTracker *objv_tracker) { void *handle; int ret = store->prepare_get_obj(s->obj_ctx, obj, NULL, NULL, &attrs, NULL, NULL, NULL, NULL, NULL, NULL, obj_size, objv_tracker, &handle, &s->err); store->finish_get_obj(&handle); return ret; } static int read_policy(RGWRados *store, struct req_state *s, RGWBucketInfo& bucket_info, map& bucket_attrs, RGWAccessControlPolicy *policy, rgw_bucket& bucket, string& object) { string upload_id; upload_id = s->info.args.get("uploadId"); string oid = object; rgw_obj obj; if (!s->system_request && bucket_info.flags & BUCKET_SUSPENDED) { ldout(s->cct, 0) << "NOTICE: bucket " << bucket_info.bucket.name << " is suspended" << dendl; return -ERR_USER_SUSPENDED; } if (!oid.empty() && !upload_id.empty()) { RGWMPObj mp(oid, upload_id); oid = mp.get_meta(); obj.init_ns(bucket, oid, mp_ns); obj.set_in_extra_data(true); } else { obj.init(bucket, oid); } int ret = get_policy_from_attr(s->cct, store, s->obj_ctx, bucket_info, bucket_attrs, policy, obj); if (ret == -ENOENT && object.size()) { /* object does not exist checking the bucket's ACL to make sure that we send a proper error code */ RGWAccessControlPolicy bucket_policy(s->cct); string no_object; rgw_obj no_obj(bucket, no_object); ret = get_policy_from_attr(s->cct, store, s->obj_ctx, bucket_info, bucket_attrs, &bucket_policy, no_obj); if (ret < 0) return ret; string& owner = bucket_policy.get_owner().get_id(); if (!s->system_request && owner.compare(s->user.user_id) != 0 && !bucket_policy.verify_permission(s->user.user_id, s->perm_mask, RGW_PERM_READ)) ret = -EACCES; else ret = -ENOENT; } else if (ret == -ENOENT) { ret = -ERR_NO_SUCH_BUCKET; } return ret; } /** * Get the AccessControlPolicy for a bucket or object off of disk. * s: The req_state to draw information from. * only_bucket: If true, reads the bucket ACL rather than the object ACL. * Returns: 0 on success, -ERR# otherwise. */ static int rgw_build_policies(RGWRados *store, struct req_state *s, bool only_bucket, bool prefetch_data) { int ret = 0; string obj_str; RGWUserInfo bucket_owner_info; s->bucket_instance_id = s->info.args.get(RGW_SYS_PARAM_PREFIX "bucket-instance"); s->bucket_acl = new RGWAccessControlPolicy(s->cct); if (s->copy_source) { /* check if copy source is within the current domain */ const char *src = s->copy_source; if (*src == '/') ++src; string copy_source_str(src); int pos = copy_source_str.find('/'); if (pos > 0) copy_source_str = copy_source_str.substr(0, pos); RGWBucketInfo source_info; ret = store->get_bucket_info(s->obj_ctx, copy_source_str, source_info, NULL); if (ret == 0) { string& region = source_info.region; s->local_source = store->region.equals(region); } } if (!s->bucket_name_str.empty()) { s->bucket_exists = true; if (s->bucket_instance_id.empty()) { ret = store->get_bucket_info(s->obj_ctx, s->bucket_name_str, s->bucket_info, NULL, &s->bucket_attrs); } else { ret = store->get_bucket_instance_info(s->obj_ctx, s->bucket_instance_id, s->bucket_info, NULL, &s->bucket_attrs); } if (ret < 0) { if (ret != -ENOENT) { ldout(s->cct, 0) << "NOTICE: couldn't get bucket from bucket_name (name=" << s->bucket_name_str << ")" << dendl; return ret; } s->bucket_exists = false; } s->bucket = s->bucket_info.bucket; if (s->bucket_exists) { string no_obj; ret = read_policy(store, s, s->bucket_info, s->bucket_attrs, s->bucket_acl, s->bucket, no_obj); } else { s->bucket_acl->create_default(s->user.user_id, s->user.display_name); ret = -ERR_NO_SUCH_BUCKET; } s->bucket_owner = s->bucket_acl->get_owner(); string& region = s->bucket_info.region; if (s->bucket_exists && !store->region.equals(region)) { ldout(s->cct, 0) << "NOTICE: request for data in a different region (" << region << " != " << store->region.name << ")" << dendl; /* we now need to make sure that the operation actually requires copy source, that is * it's a copy operation */ if (store->region.is_master && s->op == OP_DELETE && s->system_request) { /*If the operation is delete and if this is the master, don't redirect*/ } else if (!s->local_source || (s->op != OP_PUT && s->op != OP_COPY) || s->object_str.empty()) { return -ERR_PERMANENT_REDIRECT; } } } /* we're passed only_bucket = true when we specifically need the bucket's acls, that happens on write operations */ if (!only_bucket && !s->object_str.empty()) { if (!s->bucket_exists) { return -ERR_NO_SUCH_BUCKET; } s->object_acl = new RGWAccessControlPolicy(s->cct); obj_str = s->object_str; rgw_obj obj(s->bucket, obj_str); store->set_atomic(s->obj_ctx, obj); if (prefetch_data) { store->set_prefetch_data(s->obj_ctx, obj); } ret = read_policy(store, s, s->bucket_info, s->bucket_attrs, s->object_acl, s->bucket, obj_str); } return ret; } static void rgw_bucket_object_pre_exec(struct req_state *s) { if (s->expect_cont) dump_continue(s); dump_bucket_from_state(s); } int RGWGetObj::verify_permission() { obj.init(s->bucket, s->object_str); store->set_atomic(s->obj_ctx, obj); store->set_prefetch_data(s->obj_ctx, obj); if (!verify_object_permission(s, RGW_PERM_READ)) return -EACCES; return 0; } int RGWOp::verify_op_mask() { uint32_t required_mask = op_mask(); ldout(s->cct, 20) << "required_mask= " << required_mask << " user.op_mask=" << s->user.op_mask << dendl; if ((s->user.op_mask & required_mask) != required_mask) { return -EPERM; } if (!s->system_request && (required_mask & RGW_OP_TYPE_MODIFY) && !store->zone.is_master) { ldout(s->cct, 5) << "NOTICE: modify request to a non-master zone by a non-system user, permission denied" << dendl; return -EPERM; } return 0; } int RGWOp::init_quota() { /* no quota enforcement for system requests */ if (s->system_request) return 0; /* init quota related stuff */ if (!(s->user.op_mask & RGW_OP_TYPE_MODIFY)) { return 0; } /* only interested in object related ops */ if (s->object_str.empty()) { return 0; } RGWUserInfo owner_info; RGWUserInfo *uinfo; if (s->user.user_id == s->bucket_owner.get_id()) { uinfo = &s->user; } else { int r = rgw_get_user_info_by_uid(store, s->bucket_info.owner, owner_info); if (r < 0) return r; uinfo = &owner_info; } if (s->bucket_info.quota.enabled) { bucket_quota = s->bucket_info.quota; } else if (uinfo->bucket_quota.enabled) { bucket_quota = uinfo->bucket_quota; } else { bucket_quota = store->region_map.bucket_quota; } if (uinfo->user_quota.enabled) { user_quota = uinfo->user_quota; } else { user_quota = store->region_map.user_quota; } return 0; } static bool validate_cors_rule_method(RGWCORSRule *rule, const char *req_meth) { uint8_t flags = 0; if (strcmp(req_meth, "GET") == 0) flags = RGW_CORS_GET; else if (strcmp(req_meth, "POST") == 0) flags = RGW_CORS_POST; else if (strcmp(req_meth, "PUT") == 0) flags = RGW_CORS_PUT; else if (strcmp(req_meth, "DELETE") == 0) flags = RGW_CORS_DELETE; else if (strcmp(req_meth, "HEAD") == 0) flags = RGW_CORS_HEAD; if ((rule->get_allowed_methods() & flags) == flags) { dout(10) << "Method " << req_meth << " is supported" << dendl; } else { dout(5) << "Method " << req_meth << " is not supported" << dendl; return false; } return true; } int RGWOp::read_bucket_cors() { bufferlist bl; map::iterator aiter = s->bucket_attrs.find(RGW_ATTR_CORS); if (aiter == s->bucket_attrs.end()) { ldout(s->cct, 20) << "no CORS configuration attr found" << dendl; cors_exist = false; return 0; /* no CORS configuration found */ } cors_exist = true; bl = aiter->second; bufferlist::iterator iter = bl.begin(); try { bucket_cors.decode(iter); } catch (buffer::error& err) { ldout(s->cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl; return -EIO; } if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) { RGWCORSConfiguration_S3 *s3cors = static_cast(&bucket_cors); ldout(s->cct, 15) << "Read RGWCORSConfiguration"; s3cors->to_xml(*_dout); *_dout << dendl; } return 0; } /** CORS 6.2.6. * If any of the header field-names is not a ASCII case-insensitive match for * any of the values in list of headers do not set any additional headers and * terminate this set of steps. * */ static void get_cors_response_headers(RGWCORSRule *rule, const char *req_hdrs, string& hdrs, string& exp_hdrs, unsigned *max_age) { if (req_hdrs) { list hl; get_str_list(req_hdrs, hl); for(list::iterator it = hl.begin(); it != hl.end(); ++it) { if (!rule->is_header_allowed((*it).c_str(), (*it).length())) { dout(5) << "Header " << (*it) << " is not registered in this rule" << dendl; } else { if (hdrs.length() > 0) hdrs.append(","); hdrs.append((*it)); } } } rule->format_exp_headers(exp_hdrs); *max_age = rule->get_max_age(); } /** * Generate the CORS header response * * This is described in the CORS standard, section 6.2. */ bool RGWOp::generate_cors_headers(string& origin, string& method, string& headers, string& exp_headers, unsigned *max_age) { /* CORS 6.2.1. */ const char *orig = s->info.env->get("HTTP_ORIGIN"); if (!orig) { return false; } /* Custom: */ origin = orig; int ret = read_bucket_cors(); if (ret < 0) { return false; } if (!cors_exist) { dout(2) << "No CORS configuration set yet for this bucket" << dendl; return false; } /* CORS 6.2.2. */ RGWCORSRule *rule = bucket_cors.host_name_rule(orig); if (!rule) return false; /* CORS 6.2.3. */ const char *req_meth = s->info.env->get("HTTP_ACCESS_CONTROL_REQUEST_METHOD"); if (!req_meth) { req_meth = s->info.method; } if (req_meth) method = req_meth; /* CORS 6.2.5. */ if (!validate_cors_rule_method(rule, req_meth)) { return false; } /* CORS 6.2.4. */ const char *req_hdrs = s->info.env->get("HTTP_ACCESS_CONTROL_REQUEST_HEADERS"); /* CORS 6.2.6. */ get_cors_response_headers(rule, req_hdrs, headers, exp_headers, max_age); return true; } int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket, RGWObjEnt& ent, RGWAccessControlPolicy *bucket_policy, off_t start_ofs, off_t end_ofs) { ldout(s->cct, 0) << "user manifest obj=" << ent.name << dendl; void *handle = NULL; off_t cur_ofs = start_ofs; off_t cur_end = end_ofs; utime_t start_time = s->time; rgw_obj part(bucket, ent.name); map attrs; uint64_t obj_size; void *obj_ctx = store->create_context(s); RGWAccessControlPolicy obj_policy(s->cct); ldout(s->cct, 20) << "reading obj=" << part << " ofs=" << cur_ofs << " end=" << cur_end << dendl; store->set_atomic(obj_ctx, part); store->set_prefetch_data(obj_ctx, part); ret = store->prepare_get_obj(obj_ctx, part, &cur_ofs, &cur_end, &attrs, NULL, NULL, NULL, NULL, NULL, NULL, &obj_size, NULL, &handle, &s->err); if (ret < 0) goto done_err; if (obj_size != ent.size) { // hmm.. something wrong, object not as expected, abort! ldout(s->cct, 0) << "ERROR: expected obj_size=" << obj_size << ", actual read size=" << ent.size << dendl; ret = -EIO; goto done_err; } ret = rgw_policy_from_attrset(s->cct, attrs, &obj_policy); if (ret < 0) goto done_err; if (!verify_object_permission(s, bucket_policy, &obj_policy, RGW_PERM_READ)) { ret = -EPERM; goto done_err; } perfcounter->inc(l_rgw_get_b, cur_end - cur_ofs); while (cur_ofs <= cur_end) { bufferlist bl; ret = store->get_obj(obj_ctx, NULL, &handle, part, bl, cur_ofs, cur_end); if (ret < 0) goto done_err; off_t len = bl.length(); cur_ofs += len; ofs += len; ret = 0; perfcounter->tinc(l_rgw_get_lat, (ceph_clock_now(s->cct) - start_time)); send_response_data(bl, 0, len); start_time = ceph_clock_now(s->cct); } store->destroy_context(obj_ctx); obj_ctx = NULL; store->finish_get_obj(&handle); return 0; done_err: if (obj_ctx) store->destroy_context(obj_ctx); return ret; } static int iterate_user_manifest_parts(CephContext *cct, RGWRados *store, off_t ofs, off_t end, rgw_bucket& bucket, string& obj_prefix, RGWAccessControlPolicy *bucket_policy, uint64_t *ptotal_len, int (*cb)(rgw_bucket& bucket, RGWObjEnt& ent, RGWAccessControlPolicy *bucket_policy, off_t start_ofs, off_t end_ofs, void *param), void *cb_param) { uint64_t obj_ofs = 0, len_count = 0; bool found_start = false, found_end = false; string delim; string marker; bool is_truncated; string no_ns; map common_prefixes; vector objs; utime_t start_time = ceph_clock_now(cct); do { #define MAX_LIST_OBJS 100 int r = store->list_objects(bucket, MAX_LIST_OBJS, obj_prefix, delim, marker, NULL, objs, common_prefixes, true, no_ns, true, &is_truncated, NULL); if (r < 0) return r; vector::iterator viter; for (viter = objs.begin(); viter != objs.end() && !found_end; ++viter) { RGWObjEnt& ent = *viter; uint64_t cur_total_len = obj_ofs; uint64_t start_ofs = 0, end_ofs = ent.size; if (!found_start && cur_total_len + ent.size > (uint64_t)ofs) { start_ofs = ofs - obj_ofs; found_start = true; } obj_ofs += ent.size; if (!found_end && obj_ofs > (uint64_t)end) { end_ofs = end - cur_total_len + 1; found_end = true; } perfcounter->tinc(l_rgw_get_lat, (ceph_clock_now(cct) - start_time)); if (found_start) { len_count += end_ofs - start_ofs; if (cb) { r = cb(bucket, ent, bucket_policy, start_ofs, end_ofs, cb_param); if (r < 0) return r; } } marker = ent.name; start_time = ceph_clock_now(cct); } } while (is_truncated && !found_end); if (ptotal_len) *ptotal_len = len_count; return 0; } static int get_obj_user_manifest_iterate_cb(rgw_bucket& bucket, RGWObjEnt& ent, RGWAccessControlPolicy *bucket_policy, off_t start_ofs, off_t end_ofs, void *param) { RGWGetObj *op = (RGWGetObj *)param; return op->read_user_manifest_part(bucket, ent, bucket_policy, start_ofs, end_ofs); } int RGWGetObj::handle_user_manifest(const char *prefix) { ldout(s->cct, 2) << "RGWGetObj::handle_user_manifest() prefix=" << prefix << dendl; string prefix_str = prefix; int pos = prefix_str.find('/'); if (pos < 0) return -EINVAL; string bucket_name = prefix_str.substr(0, pos); string obj_prefix = prefix_str.substr(pos + 1); rgw_bucket bucket; RGWAccessControlPolicy _bucket_policy(s->cct); RGWAccessControlPolicy *bucket_policy; if (bucket_name.compare(s->bucket.name) != 0) { RGWBucketInfo bucket_info; map bucket_attrs; int r = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL, &bucket_attrs); if (r < 0) { ldout(s->cct, 0) << "could not get bucket info for bucket=" << bucket_name << dendl; return r; } bucket = bucket_info.bucket; string no_obj; bucket_policy = &_bucket_policy; r = read_policy(store, s, bucket_info, bucket_attrs, bucket_policy, bucket, no_obj); if (r < 0) { ldout(s->cct, 0) << "failed to read bucket policy" << dendl; return r; } } else { bucket = s->bucket; bucket_policy = s->bucket_acl; } /* dry run to find out total length */ int r = iterate_user_manifest_parts(s->cct, store, ofs, end, bucket, obj_prefix, bucket_policy, &total_len, NULL, NULL); if (r < 0) return r; s->obj_size = total_len; r = iterate_user_manifest_parts(s->cct, store, ofs, end, bucket, obj_prefix, bucket_policy, NULL, get_obj_user_manifest_iterate_cb, (void *)this); if (r < 0) return r; return 0; } class RGWGetObj_CB : public RGWGetDataCB { RGWGetObj *op; public: RGWGetObj_CB(RGWGetObj *_op) : op(_op) {} virtual ~RGWGetObj_CB() {} int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) { return op->get_data_cb(bl, bl_ofs, bl_len); } }; int RGWGetObj::get_data_cb(bufferlist& bl, off_t bl_ofs, off_t bl_len) { /* garbage collection related handling */ utime_t start_time = ceph_clock_now(s->cct); if (start_time > gc_invalidate_time) { int r = store->defer_gc(s->obj_ctx, obj); if (r < 0) { dout(0) << "WARNING: could not defer gc entry for obj" << dendl; } gc_invalidate_time = start_time; gc_invalidate_time += (s->cct->_conf->rgw_gc_obj_min_wait / 2); } return send_response_data(bl, bl_ofs, bl_len); } void RGWGetObj::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWGetObj::execute() { void *handle = NULL; utime_t start_time = s->time; bufferlist bl; gc_invalidate_time = ceph_clock_now(s->cct); gc_invalidate_time += (s->cct->_conf->rgw_gc_obj_min_wait / 2); RGWGetObj_CB cb(this); map::iterator attr_iter; perfcounter->inc(l_rgw_get); off_t new_ofs, new_end; ret = get_params(); if (ret < 0) goto done_err; ret = init_common(); if (ret < 0) goto done_err; new_ofs = ofs; new_end = end; ret = store->prepare_get_obj(s->obj_ctx, obj, &new_ofs, &new_end, &attrs, mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &s->obj_size, NULL, &handle, &s->err); if (ret < 0) goto done_err; attr_iter = attrs.find(RGW_ATTR_USER_MANIFEST); if (attr_iter != attrs.end()) { ret = handle_user_manifest(attr_iter->second.c_str()); if (ret < 0) { ldout(s->cct, 0) << "ERROR: failed to handle user manifest ret=" << ret << dendl; } return; } ofs = new_ofs; end = new_end; start = ofs; if (!get_data || ofs > end) goto done_err; perfcounter->inc(l_rgw_get_b, end - ofs); ret = store->get_obj_iterate(s->obj_ctx, &handle, obj, ofs, end, &cb); perfcounter->tinc(l_rgw_get_lat, (ceph_clock_now(s->cct) - start_time)); if (ret < 0) { goto done_err; } store->finish_get_obj(&handle); done_err: send_response_data(bl, 0, 0); store->finish_get_obj(&handle); } int RGWGetObj::init_common() { if (range_str) { int r = parse_range(range_str, ofs, end, &partial_content); if (r < 0) return r; } if (if_mod) { if (parse_time(if_mod, &mod_time) < 0) return -EINVAL; mod_ptr = &mod_time; } if (if_unmod) { if (parse_time(if_unmod, &unmod_time) < 0) return -EINVAL; unmod_ptr = &unmod_time; } return 0; } int RGWListBuckets::verify_permission() { return 0; } void RGWListBuckets::execute() { bool done; bool started = false; uint64_t total_count = 0; uint64_t max_buckets = s->cct->_conf->rgw_list_buckets_max_chunk; ret = get_params(); if (ret < 0) goto send_end; do { RGWUserBuckets buckets; uint64_t read_count; if (limit > 0) read_count = min(limit - total_count, (uint64_t)max_buckets); else read_count = max_buckets; ret = rgw_read_user_buckets(store, s->user.user_id, buckets, marker, read_count, should_get_stats()); if (!started) { send_response_begin(buckets.count() > 0); started = true; } if (ret < 0) { /* hmm.. something wrong here.. the user was authenticated, so it should exist */ ldout(s->cct, 10) << "WARNING: failed on rgw_get_user_buckets uid=" << s->user.user_id << dendl; break; } map& m = buckets.get_buckets(); total_count += m.size(); done = (m.size() < read_count || (limit > 0 && total_count == limit)); if (!m.empty()) { send_response_data(buckets); map::reverse_iterator riter = m.rbegin(); marker = riter->first; } } while (!done); send_end: if (!started) { send_response_begin(false); } send_response_end(); } int RGWStatAccount::verify_permission() { return 0; } void RGWStatAccount::execute() { string marker; bool done; uint64_t max_buckets = s->cct->_conf->rgw_list_buckets_max_chunk; do { RGWUserBuckets buckets; ret = rgw_read_user_buckets(store, s->user.user_id, buckets, marker, max_buckets, true); if (ret < 0) { /* hmm.. something wrong here.. the user was authenticated, so it should exist */ ldout(s->cct, 10) << "WARNING: failed on rgw_get_user_buckets uid=" << s->user.user_id << dendl; break; } else { map& m = buckets.get_buckets(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt& bucket = iter->second; buckets_size += bucket.size; buckets_size_rounded += bucket.size_rounded; buckets_objcount += bucket.count; marker = iter->first; } buckets_count += m.size(); done = (m.size() < max_buckets); } } while (!done); } int RGWStatBucket::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_READ)) return -EACCES; return 0; } void RGWStatBucket::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWStatBucket::execute() { RGWUserBuckets buckets; bucket.bucket = s->bucket; buckets.add(bucket); map& m = buckets.get_buckets(); ret = store->update_containers_stats(m); if (!ret) ret = -EEXIST; if (ret > 0) { ret = 0; map::iterator iter = m.find(bucket.bucket.name); if (iter != m.end()) { bucket = iter->second; } else { ret = -EINVAL; } } } int RGWListBucket::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_READ)) return -EACCES; return 0; } int RGWListBucket::parse_max_keys() { if (!max_keys.empty()) { char *endptr; max = strtol(max_keys.c_str(), &endptr, 10); if (endptr) { while (*endptr && isspace(*endptr)) // ignore white space endptr++; if (*endptr) { return -EINVAL; } } } else { max = default_max; } return 0; } void RGWListBucket::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWListBucket::execute() { string no_ns; ret = get_params(); if (ret < 0) return; string *pnext_marker = (delimiter.empty() ? NULL : &next_marker); ret = store->list_objects(s->bucket, max, prefix, delimiter, marker, pnext_marker, objs, common_prefixes, !!(s->prot_flags & RGW_REST_SWIFT), no_ns, true, &is_truncated, NULL); } int RGWGetBucketLogging::verify_permission() { if (s->user.user_id.compare(s->bucket_owner.get_id()) != 0) return -EACCES; return 0; } int RGWCreateBucket::verify_permission() { if (!rgw_user_is_authenticated(s->user)) return -EACCES; if (s->user.max_buckets) { RGWUserBuckets buckets; string marker; int ret = rgw_read_user_buckets(store, s->user.user_id, buckets, marker, s->user.max_buckets, false); if (ret < 0) return ret; map& m = buckets.get_buckets(); if (m.size() >= s->user.max_buckets) { return -ERR_TOO_MANY_BUCKETS; } } return 0; } static int forward_request_to_master(struct req_state *s, obj_version *objv, RGWRados *store, bufferlist& in_data, JSONParser *jp) { if (!store->rest_master_conn) { ldout(s->cct, 0) << "rest connection is invalid" << dendl; return -EINVAL; } ldout(s->cct, 0) << "sending create_bucket request to master region" << dendl; bufferlist response; #define MAX_REST_RESPONSE (128 * 1024) // we expect a very small response int ret = store->rest_master_conn->forward(s->user.user_id, s->info, objv, MAX_REST_RESPONSE, &in_data, &response); if (ret < 0) return ret; ldout(s->cct, 20) << "response: " << response.c_str() << dendl; ret = jp->parse(response.c_str(), response.length()); if (ret < 0) { ldout(s->cct, 0) << "failed parsing response from master region" << dendl; return ret; } return 0; } void RGWCreateBucket::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWCreateBucket::execute() { RGWAccessControlPolicy old_policy(s->cct); map attrs; bufferlist aclbl; bufferlist corsbl; bool existed; int r; rgw_obj obj(store->zone.domain_root, s->bucket_name_str); obj_version objv, *pobjv = NULL; ret = get_params(); if (ret < 0) return; if (!store->region.is_master && store->region.api_name != location_constraint) { ldout(s->cct, 0) << "location constraint (" << location_constraint << ") doesn't match region" << " (" << store->region.api_name << ")" << dendl; ret = -EINVAL; return; } /* we need to make sure we read bucket info, it's not read before for this specific request */ ret = store->get_bucket_info(s->obj_ctx, s->bucket_name_str, s->bucket_info, NULL, &s->bucket_attrs); if (ret < 0 && ret != -ENOENT) return; s->bucket_exists = (ret != -ENOENT); s->bucket_owner.set_id(s->user.user_id); s->bucket_owner.set_name(s->user.display_name); if (s->bucket_exists) { r = get_policy_from_attr(s->cct, store, s->obj_ctx, s->bucket_info, s->bucket_attrs, &old_policy, obj); if (r >= 0) { if (old_policy.get_owner().get_id().compare(s->user.user_id) != 0) { ret = -EEXIST; return; } } } RGWBucketInfo master_info; rgw_bucket *pmaster_bucket; time_t creation_time; if (!store->region.is_master) { JSONParser jp; ret = forward_request_to_master(s, NULL, store, in_data, &jp); if (ret < 0) return; JSONDecoder::decode_json("entry_point_object_ver", ep_objv, &jp); JSONDecoder::decode_json("object_ver", objv, &jp); JSONDecoder::decode_json("bucket_info", master_info, &jp); ldout(s->cct, 20) << "parsed: objv.tag=" << objv.tag << " objv.ver=" << objv.ver << dendl; ldout(s->cct, 20) << "got creation time: << " << master_info.creation_time << dendl; pmaster_bucket= &master_info.bucket; creation_time = master_info.creation_time; pobjv = &objv; } else { pmaster_bucket = NULL; creation_time = 0; } string region_name; if (s->system_request) { region_name = s->info.args.get(RGW_SYS_PARAM_PREFIX "region"); if (region_name.empty()) { region_name = store->region.name; } } else { region_name = store->region.name; } policy.encode(aclbl); attrs[RGW_ATTR_ACL] = aclbl; if (has_cors) { cors_config.encode(corsbl); attrs[RGW_ATTR_CORS] = corsbl; } s->bucket.name = s->bucket_name_str; ret = store->create_bucket(s->user, s->bucket, region_name, placement_rule, attrs, info, pobjv, &ep_objv, creation_time, pmaster_bucket, true); /* continue if EEXIST and create_bucket will fail below. this way we can recover * from a partial create by retrying it. */ ldout(s->cct, 20) << "rgw_create_bucket returned ret=" << ret << " bucket=" << s->bucket << dendl; if (ret && ret != -EEXIST) return; existed = (ret == -EEXIST); if (existed) { /* bucket already existed, might have raced with another bucket creation, or * might be partial bucket creation that never completed. Read existing bucket * info, verify that the reported bucket owner is the current user. * If all is ok then update the user's list of buckets */ if (info.owner.compare(s->user.user_id) != 0) { ret = -ERR_BUCKET_EXISTS; return; } s->bucket = info.bucket; } ret = rgw_link_bucket(store, s->user.user_id, s->bucket, info.creation_time, false); if (ret && !existed && ret != -EEXIST) { /* if it exists (or previously existed), don't remove it! */ ret = rgw_unlink_bucket(store, s->user.user_id, s->bucket.name); if (ret < 0) { ldout(s->cct, 0) << "WARNING: failed to unlink bucket: ret=" << ret << dendl; } } if (ret == -EEXIST) ret = -ERR_BUCKET_EXISTS; } int RGWDeleteBucket::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } void RGWDeleteBucket::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWDeleteBucket::execute() { ret = -EINVAL; if (s->bucket_name_str.empty()) return; RGWObjVersionTracker ot; ot.read_version = s->bucket_info.ep_objv; if (s->system_request) { string tag = s->info.args.get(RGW_SYS_PARAM_PREFIX "tag"); string ver_str = s->info.args.get(RGW_SYS_PARAM_PREFIX "ver"); if (!tag.empty()) { ot.read_version.tag = tag; uint64_t ver; string err; ver = strict_strtol(ver_str.c_str(), 10, &err); if (!err.empty()) { ldout(s->cct, 0) << "failed to parse ver param" << dendl; ret = -EINVAL; return; } ot.read_version.ver = ver; } } ret = store->delete_bucket(s->bucket, ot); if (ret == 0) { ret = rgw_unlink_bucket(store, s->user.user_id, s->bucket.name, false); if (ret < 0) { ldout(s->cct, 0) << "WARNING: failed to unlink bucket: ret=" << ret << dendl; } } if (ret < 0) { return; } if (!store->region.is_master) { bufferlist in_data; JSONParser jp; ret = forward_request_to_master(s, &ot.read_version, store, in_data, &jp); if (ret < 0) { if (ret == -ENOENT) { /* adjust error, we want to return with NoSuchBucket and not NoSuchKey */ ret = -ERR_NO_SUCH_BUCKET; } return; } } } int RGWPutObj::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } class RGWPutObjProcessor_Multipart : public RGWPutObjProcessor_Atomic { string part_num; RGWMPObj mp; req_state *s; string upload_id; protected: int prepare(RGWRados *store, void *obj_ctx, string *oid_rand); int do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs); public: bool immutable_head() { return true; } RGWPutObjProcessor_Multipart(const string& bucket_owner, uint64_t _p, req_state *_s) : RGWPutObjProcessor_Atomic(bucket_owner, _s->bucket, _s->object_str, _p, _s->req_id), s(_s) {} }; int RGWPutObjProcessor_Multipart::prepare(RGWRados *store, void *obj_ctx, string *oid_rand) { int r = prepare_init(store, obj_ctx, NULL); if (r < 0) { return r; } string oid = obj_str; upload_id = s->info.args.get("uploadId"); if (!oid_rand) { mp.init(oid, upload_id); } else { mp.init(oid, upload_id, *oid_rand); } part_num = s->info.args.get("partNumber"); if (part_num.empty()) { ldout(s->cct, 10) << "part number is empty" << dendl; return -EINVAL; } string err; uint64_t num = (uint64_t)strict_strtol(part_num.c_str(), 10, &err); if (!err.empty()) { ldout(s->cct, 10) << "bad part number: " << part_num << ": " << err << dendl; return -EINVAL; } string upload_prefix = oid + "."; if (!oid_rand) { upload_prefix.append(upload_id); } else { upload_prefix.append(*oid_rand); } rgw_obj target_obj; target_obj.init(bucket, oid); manifest.set_prefix(upload_prefix); manifest.set_multipart_part_rule(store->ctx()->_conf->rgw_obj_stripe_size, num); r = manifest_gen.create_begin(store->ctx(), &manifest, bucket, target_obj); if (r < 0) { return r; } head_obj = manifest_gen.get_cur_obj(); cur_obj = head_obj; add_obj(cur_obj); return 0; } static bool is_v2_upload_id(const string& upload_id) { const char *uid = upload_id.c_str(); return (strncmp(uid, MULTIPART_UPLOAD_ID_PREFIX, sizeof(MULTIPART_UPLOAD_ID_PREFIX) - 1) == 0) || (strncmp(uid, MULTIPART_UPLOAD_ID_PREFIX_LEGACY, sizeof(MULTIPART_UPLOAD_ID_PREFIX_LEGACY) - 1) == 0); } int RGWPutObjProcessor_Multipart::do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) { complete_writing_data(); RGWRados::PutObjMetaExtraParams params; params.set_mtime = set_mtime; params.mtime = mtime; params.owner = s->owner.get_id(); int r = store->put_obj_meta(obj_ctx, head_obj, s->obj_size, attrs, RGW_OBJ_CATEGORY_MAIN, 0, params); if (r < 0) return r; bufferlist bl; RGWUploadPartInfo info; string p = "part."; bool sorted_omap = is_v2_upload_id(upload_id); if (sorted_omap) { string err; int part_num_int = strict_strtol(part_num.c_str(), 10, &err); if (!err.empty()) { dout(10) << "bad part number specified: " << part_num << dendl; return -EINVAL; } char buf[32]; snprintf(buf, sizeof(buf), "%08d", part_num_int); p.append(buf); } else { p.append(part_num); } info.num = atoi(part_num.c_str()); info.etag = etag; info.size = s->obj_size; info.modified = ceph_clock_now(store->ctx()); info.manifest = manifest; ::encode(info, bl); string multipart_meta_obj = mp.get_meta(); rgw_obj meta_obj; meta_obj.init_ns(bucket, multipart_meta_obj, mp_ns); meta_obj.set_in_extra_data(true); r = store->omap_set(meta_obj, p, bl); return r; } RGWPutObjProcessor *RGWPutObj::select_processor(bool *is_multipart) { RGWPutObjProcessor *processor; bool multipart = s->info.args.exists("uploadId"); uint64_t part_size = s->cct->_conf->rgw_obj_stripe_size; const string& bucket_owner = s->bucket_owner.get_id(); if (!multipart) { processor = new RGWPutObjProcessor_Atomic(bucket_owner, s->bucket, s->object_str, part_size, s->req_id); } else { processor = new RGWPutObjProcessor_Multipart(bucket_owner, part_size, s); } if (is_multipart) { *is_multipart = multipart; } return processor; } void RGWPutObj::dispose_processor(RGWPutObjProcessor *processor) { delete processor; } void RGWPutObj::pre_exec() { rgw_bucket_object_pre_exec(s); } static int put_data_and_throttle(RGWPutObjProcessor *processor, bufferlist& data, off_t ofs, MD5 *hash, bool need_to_wait) { bool again; do { void *handle; int ret = processor->handle_data(data, ofs, hash, &handle, &again); if (ret < 0) return ret; ret = processor->throttle_data(handle, need_to_wait); if (ret < 0) return ret; need_to_wait = false; /* the need to wait only applies to the first iteration */ } while (again); return 0; } void RGWPutObj::execute() { RGWPutObjProcessor *processor = NULL; char supplied_md5_bin[CEPH_CRYPTO_MD5_DIGESTSIZE + 1]; char supplied_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE]; MD5 hash; bufferlist bl, aclbl; map attrs; int len; map::iterator iter; bool multipart; bool need_calc_md5 = (obj_manifest == NULL); perfcounter->inc(l_rgw_put); ret = -EINVAL; if (!s->object) { goto done; } ret = get_params(); if (ret < 0) goto done; if (supplied_md5_b64) { need_calc_md5 = true; ldout(s->cct, 15) << "supplied_md5_b64=" << supplied_md5_b64 << dendl; ret = ceph_unarmor(supplied_md5_bin, &supplied_md5_bin[CEPH_CRYPTO_MD5_DIGESTSIZE + 1], supplied_md5_b64, supplied_md5_b64 + strlen(supplied_md5_b64)); ldout(s->cct, 15) << "ceph_armor ret=" << ret << dendl; if (ret != CEPH_CRYPTO_MD5_DIGESTSIZE) { ret = -ERR_INVALID_DIGEST; goto done; } buf_to_hex((const unsigned char *)supplied_md5_bin, CEPH_CRYPTO_MD5_DIGESTSIZE, supplied_md5); ldout(s->cct, 15) << "supplied_md5=" << supplied_md5 << dendl; } if (!chunked_upload) { /* with chunked upload we don't know how big is the upload. we also check sizes at the end anyway */ ret = store->check_quota(s->bucket_owner.get_id(), s->bucket, user_quota, bucket_quota, s->content_length); if (ret < 0) { goto done; } } if (supplied_etag) { strncpy(supplied_md5, supplied_etag, sizeof(supplied_md5) - 1); supplied_md5[sizeof(supplied_md5) - 1] = '\0'; } processor = select_processor(&multipart); ret = processor->prepare(store, s->obj_ctx, NULL); if (ret < 0) goto done; do { bufferlist data; len = get_data(data); if (len < 0) { ret = len; goto done; } if (!len) break; /* do we need this operation to be synchronous? if we're dealing with an object with immutable * head, e.g., multipart object we need to make sure we're the first one writing to this object */ bool need_to_wait = (ofs == 0) && multipart; bufferlist orig_data; if (need_to_wait) { orig_data = data; } ret = put_data_and_throttle(processor, data, ofs, (need_calc_md5 ? &hash : NULL), need_to_wait); if (ret < 0) { if (!need_to_wait || ret != -EEXIST) { ldout(s->cct, 20) << "processor->thottle_data() returned ret=" << ret << dendl; goto done; } ldout(s->cct, 5) << "NOTICE: processor->throttle_data() returned -EEXIST, need to restart write" << dendl; /* restore original data */ data.swap(orig_data); /* restart processing with different oid suffix */ dispose_processor(processor); processor = select_processor(&multipart); string oid_rand; char buf[33]; gen_rand_alphanumeric(store->ctx(), buf, sizeof(buf) - 1); oid_rand.append(buf); ret = processor->prepare(store, s->obj_ctx, &oid_rand); if (ret < 0) { ldout(s->cct, 0) << "ERROR: processor->prepare() returned " << ret << dendl; goto done; } ret = put_data_and_throttle(processor, data, ofs, NULL, false); if (ret < 0) { goto done; } } ofs += len; } while (len > 0); if (!chunked_upload && ofs != s->content_length) { ret = -ERR_REQUEST_TIMEOUT; goto done; } s->obj_size = ofs; perfcounter->inc(l_rgw_put_b, s->obj_size); ret = store->check_quota(s->bucket_owner.get_id(), s->bucket, user_quota, bucket_quota, s->obj_size); if (ret < 0) { goto done; } if (need_calc_md5) { processor->complete_hash(&hash); hash.Final(m); buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5); etag = calc_md5; if (supplied_md5_b64 && strcmp(calc_md5, supplied_md5)) { ret = -ERR_BAD_DIGEST; goto done; } } policy.encode(aclbl); attrs[RGW_ATTR_ACL] = aclbl; if (obj_manifest) { bufferlist manifest_bl; string manifest_obj_prefix; string manifest_bucket; char etag_buf[CEPH_CRYPTO_MD5_DIGESTSIZE]; char etag_buf_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16]; manifest_bl.append(obj_manifest, strlen(obj_manifest) + 1); attrs[RGW_ATTR_USER_MANIFEST] = manifest_bl; user_manifest_parts_hash = &hash; string prefix_str = obj_manifest; int pos = prefix_str.find('/'); if (pos < 0) { ldout(s->cct, 0) << "bad user manifest, missing slash separator: " << obj_manifest << dendl; goto done; } manifest_bucket = prefix_str.substr(0, pos); manifest_obj_prefix = prefix_str.substr(pos + 1); hash.Final((byte *)etag_buf); buf_to_hex((const unsigned char *)etag_buf, CEPH_CRYPTO_MD5_DIGESTSIZE, etag_buf_str); ldout(s->cct, 0) << __func__ << ": calculated md5 for user manifest: " << etag_buf_str << dendl; etag = etag_buf_str; } if (supplied_etag && etag.compare(supplied_etag) != 0) { ret = -ERR_UNPROCESSABLE_ENTITY; goto done; } bl.append(etag.c_str(), etag.size() + 1); attrs[RGW_ATTR_ETAG] = bl; for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end(); ++iter) { bufferlist& attrbl = attrs[iter->first]; const string& val = iter->second; attrbl.append(val.c_str(), val.size() + 1); } rgw_get_request_metadata(s->cct, s->info, attrs); ret = processor->complete(etag, &mtime, 0, attrs); done: dispose_processor(processor); perfcounter->tinc(l_rgw_put_lat, (ceph_clock_now(s->cct) - s->time)); } int RGWPostObj::verify_permission() { return 0; } RGWPutObjProcessor *RGWPostObj::select_processor() { RGWPutObjProcessor *processor; uint64_t part_size = s->cct->_conf->rgw_obj_stripe_size; processor = new RGWPutObjProcessor_Atomic(s->bucket_owner.get_id(), s->bucket, s->object_str, part_size, s->req_id); return processor; } void RGWPostObj::dispose_processor(RGWPutObjProcessor *processor) { delete processor; } void RGWPostObj::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWPostObj::execute() { RGWPutObjProcessor *processor = NULL; char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE]; MD5 hash; bufferlist bl, aclbl; int len = 0; // read in the data from the POST form ret = get_params(); if (ret < 0) goto done; ret = verify_params(); if (ret < 0) goto done; if (!verify_bucket_permission(s, RGW_PERM_WRITE)) { ret = -EACCES; goto done; } ret = store->check_quota(s->bucket_owner.get_id(), s->bucket, user_quota, bucket_quota, s->content_length); if (ret < 0) { goto done; } processor = select_processor(); ret = processor->prepare(store, s->obj_ctx, NULL); if (ret < 0) goto done; while (data_pending) { bufferlist data; len = get_data(data); if (len < 0) { ret = len; goto done; } if (!len) break; ret = put_data_and_throttle(processor, data, ofs, &hash, false); ofs += len; if (ofs > max_len) { ret = -ERR_TOO_LARGE; goto done; } } if (len < min_len) { ret = -ERR_TOO_SMALL; goto done; } s->obj_size = ofs; ret = store->check_quota(s->bucket_owner.get_id(), s->bucket, user_quota, bucket_quota, s->obj_size); if (ret < 0) { goto done; } hash.Final(m); buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5); policy.encode(aclbl); etag = calc_md5; bl.append(etag.c_str(), etag.size() + 1); attrs[RGW_ATTR_ETAG] = bl; attrs[RGW_ATTR_ACL] = aclbl; if (content_type.size()) { bufferlist ct_bl; ct_bl.append(content_type.c_str(), content_type.size() + 1); attrs[RGW_ATTR_CONTENT_TYPE] = ct_bl; } ret = processor->complete(etag, NULL, 0, attrs); done: dispose_processor(processor); } int RGWPutMetadata::verify_permission() { if (s->object) { if (!verify_object_permission(s, RGW_PERM_WRITE)) return -EACCES; } else { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; } return 0; } void RGWPutMetadata::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWPutMetadata::execute() { const char *meta_prefix = RGW_ATTR_META_PREFIX; int meta_prefix_len = sizeof(RGW_ATTR_META_PREFIX) - 1; map attrs, orig_attrs, rmattrs; map::iterator iter; bufferlist bl, cors_bl; rgw_obj obj(s->bucket, s->object_str); store->set_atomic(s->obj_ctx, obj); ret = get_params(); if (ret < 0) return; rgw_get_request_metadata(s->cct, s->info, attrs); /* no need to track object versioning, need it for bucket's data only */ RGWObjVersionTracker *ptracker = (s->object ? NULL : &s->bucket_info.objv_tracker); if (s->object) { /* check if obj exists, read orig attrs */ ret = get_obj_attrs(store, s, obj, orig_attrs, NULL, ptracker); if (ret < 0) return; } else { orig_attrs = s->bucket_attrs; } for (iter = orig_attrs.begin(); iter != orig_attrs.end(); ++iter) { const string& name = iter->first; /* check if the attr is user-defined metadata item */ if (name.compare(0, meta_prefix_len, meta_prefix) == 0) { if (!(s->object == NULL)) { /* for the objects all existing meta attrs have to be removed */ rmattrs[name] = iter->second; } else { /* for the buckets all existing meta attrs are preserved, except those that are listed in rmattr_names. */ if (rmattr_names.find(name) != rmattr_names.end()) { map::iterator aiter = attrs.find(name); if (aiter != attrs.end()) { attrs.erase(aiter); } rmattrs[name] = iter->second; } } } else if (attrs.find(name) == attrs.end()) { attrs[name] = iter->second; } } map::iterator giter; for (giter = s->generic_attrs.begin(); giter != s->generic_attrs.end(); ++giter) { bufferlist& attrbl = attrs[giter->first]; const string& val = giter->second; attrbl.append(val.c_str(), val.size() + 1); } if (has_policy) { policy.encode(bl); attrs[RGW_ATTR_ACL] = bl; } if (has_cors) { cors_config.encode(cors_bl); attrs[RGW_ATTR_CORS] = cors_bl; } if (s->object) { ret = store->set_attrs(s->obj_ctx, obj, attrs, &rmattrs, ptracker); } else { ret = rgw_bucket_set_attrs(store, s->bucket_info, attrs, &rmattrs, ptracker); } } int RGWSetTempUrl::verify_permission() { if (s->perm_mask != RGW_PERM_FULL_CONTROL) return -EACCES; return 0; } void RGWSetTempUrl::execute() { ret = get_params(); if (ret < 0) return; RGWUserAdminOpState user_op; user_op.set_user_id(s->user.user_id); map::iterator iter; for (iter = temp_url_keys.begin(); iter != temp_url_keys.end(); ++iter) { user_op.set_temp_url_key(iter->second, iter->first); } RGWUser user; ret = user.init(store, user_op); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: could not init user ret=" << ret << dendl; return; } string err_msg; ret = user.modify(user_op, &err_msg); if (ret < 0) { ldout(store->ctx(), 10) << "user.modify() returned " << ret << ": " << err_msg << dendl; return; } } int RGWDeleteObj::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } void RGWDeleteObj::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWDeleteObj::execute() { ret = -EINVAL; rgw_obj obj(s->bucket, s->object_str); if (s->object) { store->set_atomic(s->obj_ctx, obj); ret = store->delete_obj(s->obj_ctx, s->bucket_owner.get_id(), obj); } } bool RGWCopyObj::parse_copy_location(const char *src, string& bucket_name, string& object) { string url_src(src); string dec_src; url_decode(url_src, dec_src); src = dec_src.c_str(); if (*src == '/') ++src; string str(src); int pos = str.find("/"); if (pos <= 0) return false; bucket_name = str.substr(0, pos); object = str.substr(pos + 1); if (object.size() == 0) return false; return true; } int RGWCopyObj::verify_permission() { string empty_str; RGWAccessControlPolicy src_policy(s->cct); ret = get_params(); if (ret < 0) return ret; map src_attrs; ret = store->get_bucket_info(s->obj_ctx, src_bucket_name, src_bucket_info, NULL, &src_attrs); if (ret < 0) return ret; src_bucket = src_bucket_info.bucket; /* get buckets info (source and dest) */ if (s->local_source && source_zone.empty()) { rgw_obj src_obj(src_bucket, src_object); store->set_atomic(s->obj_ctx, src_obj); store->set_prefetch_data(s->obj_ctx, src_obj); /* check source object permissions */ ret = read_policy(store, s, src_bucket_info, src_attrs, &src_policy, src_bucket, src_object); if (ret < 0) return ret; if (!s->system_request && /* system request overrides permission checks */ !src_policy.verify_permission(s->user.user_id, s->perm_mask, RGW_PERM_READ)) return -EACCES; } RGWAccessControlPolicy dest_bucket_policy(s->cct); map dest_attrs; if (src_bucket_name.compare(dest_bucket_name) == 0) { /* will only happen if s->local_source */ dest_bucket_info = src_bucket_info; dest_attrs = src_attrs; } else { ret = store->get_bucket_info(s->obj_ctx, dest_bucket_name, dest_bucket_info, NULL, &dest_attrs); if (ret < 0) return ret; } dest_bucket = dest_bucket_info.bucket; rgw_obj dest_obj(dest_bucket, dest_object); store->set_atomic(s->obj_ctx, dest_obj); /* check dest bucket permissions */ ret = read_policy(store, s, dest_bucket_info, dest_attrs, &dest_bucket_policy, dest_bucket, empty_str); if (ret < 0) return ret; if (!s->system_request && /* system request overrides permission checks */ !dest_bucket_policy.verify_permission(s->user.user_id, s->perm_mask, RGW_PERM_WRITE)) return -EACCES; ret = init_dest_policy(); if (ret < 0) return ret; return 0; } int RGWCopyObj::init_common() { if (if_mod) { if (parse_time(if_mod, &mod_time) < 0) { ret = -EINVAL; return ret; } mod_ptr = &mod_time; } if (if_unmod) { if (parse_time(if_unmod, &unmod_time) < 0) { ret = -EINVAL; return ret; } unmod_ptr = &unmod_time; } bufferlist aclbl; dest_policy.encode(aclbl); attrs[RGW_ATTR_ACL] = aclbl; rgw_get_request_metadata(s->cct, s->info, attrs); map::iterator iter; for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end(); ++iter) { bufferlist& attrbl = attrs[iter->first]; const string& val = iter->second; attrbl.append(val.c_str(), val.size() + 1); } return 0; } static void copy_obj_progress_cb(off_t ofs, void *param) { RGWCopyObj *op = static_cast(param); op->progress_cb(ofs); } void RGWCopyObj::progress_cb(off_t ofs) { if (!s->cct->_conf->rgw_copy_obj_progress) return; if (ofs - last_ofs < s->cct->_conf->rgw_copy_obj_progress_every_bytes) return; send_partial_response(ofs); last_ofs = ofs; } void RGWCopyObj::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWCopyObj::execute() { rgw_obj src_obj, dst_obj; if (init_common() < 0) return; src_obj.init(src_bucket, src_object); dst_obj.init(dest_bucket, dest_object); store->set_atomic(s->obj_ctx, src_obj); store->set_atomic(s->obj_ctx, dst_obj); ret = store->copy_obj(s->obj_ctx, s->user.user_id, client_id, op_id, &s->info, source_zone, dst_obj, src_obj, dest_bucket_info, src_bucket_info, &mtime, mod_ptr, unmod_ptr, if_match, if_nomatch, replace_attrs, attrs, RGW_OBJ_CATEGORY_MAIN, &s->req_id, /* use req_id as tag */ &etag, &s->err, copy_obj_progress_cb, (void *)this ); } int RGWGetACLs::verify_permission() { bool perm; if (s->object) { perm = verify_object_permission(s, RGW_PERM_READ_ACP); } else { perm = verify_bucket_permission(s, RGW_PERM_READ_ACP); } if (!perm) return -EACCES; return 0; } void RGWGetACLs::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWGetACLs::execute() { stringstream ss; RGWAccessControlPolicy *acl = (s->object ? s->object_acl : s->bucket_acl); RGWAccessControlPolicy_S3 *s3policy = static_cast(acl); s3policy->to_xml(ss); acls = ss.str(); } int RGWPutACLs::verify_permission() { bool perm; if (s->object) { perm = verify_object_permission(s, RGW_PERM_WRITE_ACP); } else { perm = verify_bucket_permission(s, RGW_PERM_WRITE_ACP); } if (!perm) return -EACCES; return 0; } void RGWPutACLs::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWPutACLs::execute() { bufferlist bl; RGWAccessControlPolicy_S3 *policy = NULL; RGWACLXMLParser_S3 parser(s->cct); RGWAccessControlPolicy_S3 new_policy(s->cct); stringstream ss; char *new_data = NULL; rgw_obj obj; ret = 0; if (!parser.init()) { ret = -EINVAL; return; } RGWAccessControlPolicy *existing_policy = (s->object == NULL? s->bucket_acl : s->object_acl); owner = existing_policy->get_owner(); ret = get_params(); if (ret < 0) return; ldout(s->cct, 15) << "read len=" << len << " data=" << (data ? data : "") << dendl; if (!s->canned_acl.empty() && len) { ret = -EINVAL; return; } if (!s->canned_acl.empty() || s->has_acl_header) { ret = get_policy_from_state(store, s, ss); if (ret < 0) return; new_data = strdup(ss.str().c_str()); free(data); data = new_data; len = ss.str().size(); } if (!parser.parse(data, len, 1)) { ret = -EACCES; return; } policy = static_cast(parser.find_first("AccessControlPolicy")); if (!policy) { ret = -EINVAL; return; } if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) { ldout(s->cct, 15) << "Old AccessControlPolicy"; policy->to_xml(*_dout); *_dout << dendl; } ret = policy->rebuild(store, &owner, new_policy); if (ret < 0) return; if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) { ldout(s->cct, 15) << "New AccessControlPolicy:"; new_policy.to_xml(*_dout); *_dout << dendl; } RGWObjVersionTracker *ptracker = (s->object ? NULL : &s->bucket_info.objv_tracker); new_policy.encode(bl); obj.init(s->bucket, s->object_str); map attrs; attrs[RGW_ATTR_ACL] = bl; store->set_atomic(s->obj_ctx, obj); if (s->object) { ret = store->set_attrs(s->obj_ctx, obj, attrs, NULL, ptracker); } else { ret = rgw_bucket_set_attrs(store, s->bucket_info, attrs, NULL, ptracker); } } int RGWGetCORS::verify_permission() { if (s->user.user_id.compare(s->bucket_owner.get_id()) != 0) return -EACCES; return 0; } void RGWGetCORS::execute() { ret = read_bucket_cors(); if (ret < 0) return ; if (!cors_exist) { dout(2) << "No CORS configuration set yet for this bucket" << dendl; ret = -ENOENT; return; } } int RGWPutCORS::verify_permission() { if (s->user.user_id.compare(s->bucket_owner.get_id()) != 0) return -EACCES; return 0; } void RGWPutCORS::execute() { rgw_obj obj; ret = get_params(); if (ret < 0) return; RGWObjVersionTracker *ptracker = (s->object ? NULL : &s->bucket_info.objv_tracker); store->get_bucket_instance_obj(s->bucket, obj); store->set_atomic(s->obj_ctx, obj); ret = store->set_attr(s->obj_ctx, obj, RGW_ATTR_CORS, cors_bl, ptracker); } int RGWDeleteCORS::verify_permission() { if (s->user.user_id.compare(s->bucket_owner.get_id()) != 0) return -EACCES; return 0; } void RGWDeleteCORS::execute() { ret = read_bucket_cors(); if (ret < 0) return; bufferlist bl; rgw_obj obj; if (!cors_exist) { dout(2) << "No CORS configuration set yet for this bucket" << dendl; ret = -ENOENT; return; } store->get_bucket_instance_obj(s->bucket, obj); store->set_atomic(s->obj_ctx, obj); map orig_attrs, attrs, rmattrs; map::iterator iter; RGWObjVersionTracker *ptracker = (s->object ? NULL : &s->bucket_info.objv_tracker); /* check if obj exists, read orig attrs */ ret = get_obj_attrs(store, s, obj, orig_attrs, NULL, ptracker); if (ret < 0) return; /* only remove meta attrs */ for (iter = orig_attrs.begin(); iter != orig_attrs.end(); ++iter) { const string& name = iter->first; dout(10) << "DeleteCORS : attr: " << name << dendl; if (name.compare(0, (sizeof(RGW_ATTR_CORS) - 1), RGW_ATTR_CORS) == 0) { rmattrs[name] = iter->second; } else if (attrs.find(name) == attrs.end()) { attrs[name] = iter->second; } } ret = store->set_attrs(s->obj_ctx, obj, attrs, &rmattrs, ptracker); } void RGWOptionsCORS::get_response_params(string& hdrs, string& exp_hdrs, unsigned *max_age) { get_cors_response_headers(rule, req_hdrs, hdrs, exp_hdrs, max_age); } int RGWOptionsCORS::validate_cors_request(RGWCORSConfiguration *cc) { rule = cc->host_name_rule(origin); if (!rule) { dout(10) << "There is no cors rule present for " << origin << dendl; return -ENOENT; } if (!validate_cors_rule_method(rule, req_meth)) { return -ENOENT; } return 0; } void RGWOptionsCORS::execute() { ret = read_bucket_cors(); if (ret < 0) return; origin = s->info.env->get("HTTP_ORIGIN"); if (!origin) { dout(0) << "Preflight request without mandatory Origin header" << dendl; ret = -EINVAL; return; } req_meth = s->info.env->get("HTTP_ACCESS_CONTROL_REQUEST_METHOD"); if (!req_meth) { dout(0) << "Preflight request without mandatory Access-control-request-method header" << dendl; ret = -EINVAL; return; } if (!cors_exist) { dout(2) << "No CORS configuration set yet for this bucket" << dendl; ret = -ENOENT; return; } req_hdrs = s->info.env->get("HTTP_ACCESS_CONTROL_REQUEST_HEADERS"); ret = validate_cors_request(&bucket_cors); if (!rule) { origin = req_meth = NULL; return; } return; } int RGWInitMultipart::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } void RGWInitMultipart::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWInitMultipart::execute() { bufferlist aclbl; map attrs; rgw_obj obj; map::iterator iter; if (get_params() < 0) return; ret = -EINVAL; if (!s->object) return; policy.encode(aclbl); attrs[RGW_ATTR_ACL] = aclbl; for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end(); ++iter) { bufferlist& attrbl = attrs[iter->first]; const string& val = iter->second; attrbl.append(val.c_str(), val.size() + 1); } rgw_get_request_metadata(s->cct, s->info, attrs); do { char buf[33]; gen_rand_alphanumeric(s->cct, buf, sizeof(buf) - 1); upload_id = MULTIPART_UPLOAD_ID_PREFIX; /* v2 upload id */ upload_id.append(buf); string tmp_obj_name; RGWMPObj mp(s->object_str, upload_id); tmp_obj_name = mp.get_meta(); obj.init_ns(s->bucket, tmp_obj_name, mp_ns); // the meta object will be indexed with 0 size, we c obj.set_in_extra_data(true); ret = store->put_obj_meta(s->obj_ctx, obj, 0, NULL, attrs, RGW_OBJ_CATEGORY_MULTIMETA, PUT_OBJ_CREATE_EXCL, s->owner.get_id()); } while (ret == -EEXIST); } static int get_multipart_info(RGWRados *store, struct req_state *s, string& meta_oid, RGWAccessControlPolicy *policy, map& attrs) { map parts_map; map::iterator iter; bufferlist header; rgw_obj obj; obj.init_ns(s->bucket, meta_oid, mp_ns); obj.set_in_extra_data(true); int ret = get_obj_attrs(store, s, obj, attrs, NULL, NULL); if (ret < 0) return ret; if (policy) { for (iter = attrs.begin(); iter != attrs.end(); ++iter) { string name = iter->first; if (name.compare(RGW_ATTR_ACL) == 0) { bufferlist& bl = iter->second; bufferlist::iterator bli = bl.begin(); try { ::decode(*policy, bli); } catch (buffer::error& err) { ldout(s->cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl; return -EIO; } break; } } } return 0; } static int list_multipart_parts(RGWRados *store, struct req_state *s, const string& upload_id, string& meta_oid, int num_parts, int marker, map& parts, int *next_marker, bool *truncated, bool assume_unsorted = false) { map parts_map; map::iterator iter; bufferlist header; rgw_obj obj; obj.init_ns(s->bucket, meta_oid, mp_ns); obj.set_in_extra_data(true); bool sorted_omap = is_v2_upload_id(upload_id) && !assume_unsorted; int ret; parts.clear(); if (sorted_omap) { string p; p = "part."; char buf[32]; snprintf(buf, sizeof(buf), "%08d", marker); p.append(buf); ret = store->omap_get_vals(obj, header, p, num_parts + 1, parts_map); } else { ret = store->omap_get_all(obj, header, parts_map); } if (ret < 0) return ret; int i; int last_num = 0; uint32_t expected_next = marker + 1; for (i = 0, iter = parts_map.begin(); (i < num_parts || !sorted_omap) && iter != parts_map.end(); ++iter, ++i) { bufferlist& bl = iter->second; bufferlist::iterator bli = bl.begin(); RGWUploadPartInfo info; try { ::decode(info, bli); } catch (buffer::error& err) { ldout(s->cct, 0) << "ERROR: could not part info, caught buffer::error" << dendl; return -EIO; } if (sorted_omap) { if (info.num != expected_next) { /* ouch, we expected a specific part num here, but we got a different one. Either * a part is missing, or it could be a case of mixed rgw versions working on the same * upload, where one gateway doesn't support correctly sorted omap keys for multipart * upload just assume data is unsorted. */ return list_multipart_parts(store, s, upload_id, meta_oid, num_parts, marker, parts, next_marker, truncated, true); } expected_next++; } if (sorted_omap || (int)info.num > marker) { parts[info.num] = info; last_num = info.num; } } if (sorted_omap) { if (truncated) *truncated = (iter != parts_map.end()); } else { /* rebuild a map with only num_parts entries */ map new_parts; map::iterator piter; for (i = 0, piter = parts.begin(); i < num_parts && piter != parts.end(); ++i, ++piter) { new_parts[piter->first] = piter->second; last_num = piter->first; } if (truncated) *truncated = (piter != parts.end()); parts.swap(new_parts); } if (next_marker) { *next_marker = last_num; } return 0; } int RGWCompleteMultipart::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } void RGWCompleteMultipart::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWCompleteMultipart::execute() { RGWMultiCompleteUpload *parts; map::iterator iter; RGWMultiXMLParser parser; string meta_oid; map obj_parts; map::iterator obj_iter; map attrs; off_t ofs = 0; MD5 hash; char final_etag[CEPH_CRYPTO_MD5_DIGESTSIZE]; char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16]; bufferlist etag_bl; rgw_obj meta_obj; rgw_obj target_obj; RGWMPObj mp; RGWObjManifest manifest; ret = get_params(); if (ret < 0) return; if (!data) { ret = -EINVAL; return; } if (!parser.init()) { ret = -EINVAL; return; } if (!parser.parse(data, len, 1)) { ret = -EINVAL; return; } parts = static_cast(parser.find_first("CompleteMultipartUpload")); if (!parts) { ret = -EINVAL; return; } mp.init(s->object_str, upload_id); meta_oid = mp.get_meta(); int total_parts = 0; int handled_parts = 0; int max_parts = 1000; int marker = 0; bool truncated; uint64_t min_part_size = s->cct->_conf->rgw_multipart_min_part_size; list remove_objs; /* objects to be removed from index listing */ iter = parts->parts.begin(); meta_obj.init_ns(s->bucket, meta_oid, mp_ns); meta_obj.set_in_extra_data(true); ret = get_obj_attrs(store, s, meta_obj, attrs, NULL, NULL); if (ret < 0) { ldout(s->cct, 0) << "ERROR: failed to get obj attrs, obj=" << meta_obj << " ret=" << ret << dendl; return; } do { ret = list_multipart_parts(store, s, upload_id, meta_oid, max_parts, marker, obj_parts, &marker, &truncated); if (ret == -ENOENT) { ret = -ERR_NO_SUCH_UPLOAD; } if (ret < 0) return; total_parts += obj_parts.size(); if (!truncated && total_parts != (int)parts->parts.size()) { ret = -ERR_INVALID_PART; return; } for (obj_iter = obj_parts.begin(); iter != parts->parts.end() && obj_iter != obj_parts.end(); ++iter, ++obj_iter, ++handled_parts) { uint64_t part_size = obj_iter->second.size; if (handled_parts < (int)parts->parts.size() - 1 && part_size < min_part_size) { ret = -ERR_TOO_SMALL; return; } char petag[CEPH_CRYPTO_MD5_DIGESTSIZE]; if (iter->first != (int)obj_iter->first) { ldout(s->cct, 0) << "NOTICE: parts num mismatch: next requested: " << iter->first << " next uploaded: " << obj_iter->first << dendl; ret = -ERR_INVALID_PART; return; } string part_etag = rgw_string_unquote(iter->second); if (part_etag.compare(obj_iter->second.etag) != 0) { ldout(s->cct, 0) << "NOTICE: etag mismatch: part: " << iter->first << " etag: " << iter->second << dendl; ret = -ERR_INVALID_PART; return; } hex_to_buf(obj_iter->second.etag.c_str(), petag, CEPH_CRYPTO_MD5_DIGESTSIZE); hash.Update((const byte *)petag, sizeof(petag)); RGWUploadPartInfo& obj_part = obj_iter->second; /* update manifest for part */ string oid = mp.get_part(obj_iter->second.num); rgw_obj src_obj; src_obj.init_ns(s->bucket, oid, mp_ns); if (obj_part.manifest.empty()) { ldout(s->cct, 0) << "ERROR: empty manifest for object part: obj=" << src_obj << dendl; ret = -ERR_INVALID_PART; return; } else { manifest.append(obj_part.manifest); } remove_objs.push_back(src_obj.object); ofs += obj_part.size; } } while (truncated); hash.Final((byte *)final_etag); buf_to_hex((unsigned char *)final_etag, sizeof(final_etag), final_etag_str); snprintf(&final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2], sizeof(final_etag_str) - CEPH_CRYPTO_MD5_DIGESTSIZE * 2, "-%lld", (long long)parts->parts.size()); etag = final_etag_str; ldout(s->cct, 10) << "calculated etag: " << final_etag_str << dendl; etag_bl.append(final_etag_str, strlen(final_etag_str) + 1); attrs[RGW_ATTR_ETAG] = etag_bl; target_obj.init(s->bucket, s->object_str); store->set_atomic(s->obj_ctx, target_obj); RGWRados::PutObjMetaExtraParams extra_params; extra_params.manifest = &manifest; extra_params.remove_objs = &remove_objs; extra_params.ptag = &s->req_id; /* use req_id as operation tag */ extra_params.owner = s->owner.get_id(); ret = store->put_obj_meta(s->obj_ctx, target_obj, ofs, attrs, RGW_OBJ_CATEGORY_MAIN, PUT_OBJ_CREATE, extra_params); if (ret < 0) return; // remove the upload obj store->delete_obj(s->obj_ctx, s->bucket_owner.get_id(), meta_obj); } int RGWAbortMultipart::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } void RGWAbortMultipart::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWAbortMultipart::execute() { ret = -EINVAL; string upload_id; string meta_oid; upload_id = s->info.args.get("uploadId"); map obj_parts; map::iterator obj_iter; map attrs; rgw_obj meta_obj; RGWMPObj mp; const string& owner = s->bucket_owner.get_id(); if (upload_id.empty() || s->object_str.empty()) return; mp.init(s->object_str, upload_id); meta_oid = mp.get_meta(); ret = get_multipart_info(store, s, meta_oid, NULL, attrs); if (ret < 0) return; bool truncated; int marker = 0; int max_parts = 1000; do { ret = list_multipart_parts(store, s, upload_id, meta_oid, max_parts, marker, obj_parts, &marker, &truncated); if (ret < 0) return; for (obj_iter = obj_parts.begin(); obj_iter != obj_parts.end(); ++obj_iter) { RGWUploadPartInfo& obj_part = obj_iter->second; if (obj_part.manifest.empty()) { string oid = mp.get_part(obj_iter->second.num); rgw_obj obj; obj.init_ns(s->bucket, oid, mp_ns); ret = store->delete_obj(s->obj_ctx, owner, obj); if (ret < 0 && ret != -ENOENT) return; } else { RGWObjManifest& manifest = obj_part.manifest; RGWObjManifest::obj_iterator oiter; for (oiter = manifest.obj_begin(); oiter != manifest.obj_end(); ++oiter) { rgw_obj loc = oiter.get_location(); ret = store->delete_obj(s->obj_ctx, owner, loc); if (ret < 0 && ret != -ENOENT) return; } } } } while (truncated); // and also remove the metadata obj meta_obj.init_ns(s->bucket, meta_oid, mp_ns); meta_obj.set_in_extra_data(true); ret = store->delete_obj(s->obj_ctx, owner, meta_obj); if (ret == -ENOENT) { ret = -ERR_NO_SUCH_BUCKET; } } int RGWListMultipart::verify_permission() { if (!verify_object_permission(s, RGW_PERM_READ)) return -EACCES; return 0; } void RGWListMultipart::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWListMultipart::execute() { map xattrs; string meta_oid; RGWMPObj mp; ret = get_params(); if (ret < 0) return; mp.init(s->object_str, upload_id); meta_oid = mp.get_meta(); ret = get_multipart_info(store, s, meta_oid, &policy, xattrs); if (ret < 0) return; ret = list_multipart_parts(store, s, upload_id, meta_oid, max_parts, marker, parts, NULL, &truncated); } int RGWListBucketMultiparts::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_READ)) return -EACCES; return 0; } void RGWListBucketMultiparts::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWListBucketMultiparts::execute() { vector objs; string marker_meta; ret = get_params(); if (ret < 0) return; if (s->prot_flags & RGW_REST_SWIFT) { string path_args; path_args = s->info.args.get("path"); if (!path_args.empty()) { if (!delimiter.empty() || !prefix.empty()) { ret = -EINVAL; return; } prefix = path_args; delimiter="/"; } } marker_meta = marker.get_meta(); ret = store->list_objects(s->bucket, max_uploads, prefix, delimiter, marker_meta, NULL, objs, common_prefixes, !!(s->prot_flags & RGW_REST_SWIFT), mp_ns, true, &is_truncated, &mp_filter); if (!objs.empty()) { vector::iterator iter; RGWMultipartUploadEntry entry; for (iter = objs.begin(); iter != objs.end(); ++iter) { string name = iter->name; if (!entry.mp.from_meta(name)) continue; entry.obj = *iter; uploads.push_back(entry); } next_marker = entry; } } int RGWDeleteMultiObj::verify_permission() { if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; } void RGWDeleteMultiObj::pre_exec() { rgw_bucket_object_pre_exec(s); } void RGWDeleteMultiObj::execute() { RGWMultiDelDelete *multi_delete; vector::iterator iter; RGWMultiDelXMLParser parser; pair result; int num_processed = 0; ret = get_params(); if (ret < 0) { goto error; } if (!data) { ret = -EINVAL; goto error; } if (!parser.init()) { ret = -EINVAL; goto error; } if (!parser.parse(data, len, 1)) { ret = -EINVAL; goto error; } multi_delete = static_cast(parser.find_first("Delete")); if (!multi_delete) { ret = -EINVAL; goto error; } if (multi_delete->is_quiet()) quiet = true; begin_response(); if (multi_delete->objects.empty()) { goto done; } for (iter = multi_delete->objects.begin(); iter != multi_delete->objects.end() && num_processed < max_to_delete; ++iter, num_processed++) { rgw_obj obj(bucket,(*iter)); store->set_atomic(s->obj_ctx, obj); ret = store->delete_obj(s->obj_ctx, s->bucket_owner.get_id(), obj); if (ret == -ENOENT) { ret = 0; } result = make_pair(*iter, ret); send_partial_response(result); } /* set the return code to zero, errors at this point will be dumped to the response */ ret = 0; done: // will likely segfault if begin_response() has not been called end_response(); free(data); return; error: send_status(); free(data); return; } RGWHandler::~RGWHandler() { } int RGWHandler::init(RGWRados *_store, struct req_state *_s, RGWClientIO *cio) { store = _store; s = _s; return 0; } int RGWHandler::do_read_permissions(RGWOp *op, bool only_bucket) { int ret = rgw_build_policies(store, s, only_bucket, op->prefetch_data()); if (ret < 0) { ldout(s->cct, 10) << "read_permissions on " << s->bucket << ":" <object_str << " only_bucket=" << only_bucket << " ret=" << ret << dendl; if (ret == -ENODATA) ret = -EACCES; } return ret; } RGWOp *RGWHandler::get_op(RGWRados *store) { RGWOp *op; switch (s->op) { case OP_GET: op = op_get(); break; case OP_PUT: op = op_put(); break; case OP_DELETE: op = op_delete(); break; case OP_HEAD: op = op_head(); break; case OP_POST: op = op_post(); break; case OP_COPY: op = op_copy(); break; case OP_OPTIONS: op = op_options(); break; default: return NULL; } if (op) { op->init(store, s, this); } return op; } void RGWHandler::put_op(RGWOp *op) { delete op; } ceph-0.80.11/src/rgw/Makefile.am0000664000175100017510000000774112623076744020330 0ustar jenkins-buildjenkins-buildif WITH_RADOSGW librgw_la_SOURCES = \ rgw/librgw.cc \ rgw/rgw_acl.cc \ rgw/rgw_acl_s3.cc \ rgw/rgw_acl_swift.cc \ rgw/rgw_client_io.cc \ rgw/rgw_fcgi.cc \ rgw/rgw_xml.cc \ rgw/rgw_usage.cc \ rgw/rgw_json_enc.cc \ rgw/rgw_user.cc \ rgw/rgw_bucket.cc\ rgw/rgw_tools.cc \ rgw/rgw_rados.cc \ rgw/rgw_http_client.cc \ rgw/rgw_rest_client.cc \ rgw/rgw_rest_conn.cc \ rgw/rgw_op.cc \ rgw/rgw_common.cc \ rgw/rgw_cache.cc \ rgw/rgw_formats.cc \ rgw/rgw_log.cc \ rgw/rgw_multi.cc \ rgw/rgw_policy_s3.cc \ rgw/rgw_gc.cc \ rgw/rgw_multi_del.cc \ rgw/rgw_env.cc \ rgw/rgw_cors.cc \ rgw/rgw_cors_s3.cc \ rgw/rgw_auth_s3.cc \ rgw/rgw_metadata.cc \ rgw/rgw_replica_log.cc \ rgw/rgw_keystone.cc \ rgw/rgw_quota.cc \ rgw/rgw_dencoder.cc librgw_la_CXXFLAGS = -Woverloaded-virtual ${AM_CXXFLAGS} noinst_LTLIBRARIES += librgw.la LIBRGW_DEPS += \ $(LIBRADOS) \ libcls_rgw_client.la \ libcls_log_client.a \ libcls_statelog_client.a \ libcls_user_client.a \ libcls_replica_log_client.a \ libcls_lock_client.la \ libcls_refcount_client.la \ libcls_version_client.a \ -lcurl \ -lexpat \ -lm \ -lfcgi \ -ldl CIVETWEB_INCLUDE = --include civetweb/include/civetweb_conf.h libcivetweb_la_SOURCES = \ rgw/rgw_civetweb.cc \ rgw/rgw_civetweb_log.cc \ civetweb/src/civetweb.c libcivetweb_la_CXXFLAGS = ${CIVETWEB_INCLUDE} -Woverloaded-virtual ${AM_CXXFLAGS} libcivetweb_la_CFLAGS = -Icivetweb/include ${CIVETWEB_INCLUDE} noinst_LTLIBRARIES += libcivetweb.la radosgw_SOURCES = \ rgw/rgw_resolve.cc \ rgw/rgw_rest.cc \ rgw/rgw_rest_swift.cc \ rgw/rgw_rest_s3.cc \ rgw/rgw_rest_usage.cc \ rgw/rgw_rest_user.cc \ rgw/rgw_rest_bucket.cc \ rgw/rgw_rest_metadata.cc \ rgw/rgw_replica_log.cc \ rgw/rgw_rest_log.cc \ rgw/rgw_rest_opstate.cc \ rgw/rgw_rest_replica_log.cc \ rgw/rgw_rest_config.cc \ rgw/rgw_http_client.cc \ rgw/rgw_swift.cc \ rgw/rgw_swift_auth.cc \ rgw/rgw_loadgen.cc \ rgw/rgw_main.cc radosgw_CFLAGS = -I$(srcdir)/civetweb/include radosgw_LDADD = $(LIBRGW) $(LIBCIVETWEB) $(LIBRGW_DEPS) $(RESOLV_LIBS) $(CEPH_GLOBAL) bin_PROGRAMS += radosgw radosgw_admin_SOURCES = rgw/rgw_admin.cc radosgw_admin_LDADD = $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) bin_PROGRAMS += radosgw-admin ceph_rgw_multiparser_SOURCES = rgw/rgw_multiparser.cc ceph_rgw_multiparser_LDADD = $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_rgw_multiparser ceph_rgw_jsonparser_SOURCES = \ rgw/rgw_jsonparser.cc \ rgw/rgw_common.cc \ rgw/rgw_env.cc \ rgw/rgw_json_enc.cc ceph_rgw_jsonparser_LDADD = $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_rgw_jsonparser # inject rgw stuff in the decoder testcase DENCODER_SOURCES += \ rgw/rgw_dencoder.cc \ rgw/rgw_acl.cc \ rgw/rgw_common.cc \ rgw/rgw_env.cc \ rgw/rgw_json_enc.cc endif # WITH_RADOSGW noinst_HEADERS += \ rgw/logrotate.conf \ rgw/rgw_acl.h \ rgw/rgw_acl_s3.h \ rgw/rgw_acl_swift.h \ rgw/rgw_client_io.h \ rgw/rgw_fcgi.h \ rgw/rgw_xml.h \ rgw/rgw_cache.h \ rgw/rgw_common.h \ rgw/rgw_cors.h \ rgw/rgw_cors_s3.h \ rgw/rgw_cors_swift.h \ rgw/rgw_string.h \ rgw/rgw_formats.h \ rgw/rgw_http_errors.h \ rgw/rgw_log.h \ rgw/rgw_loadgen.h \ rgw/rgw_multi.h \ rgw/rgw_policy_s3.h \ rgw/rgw_gc.h \ rgw/rgw_metadata.h \ rgw/rgw_multi_del.h \ rgw/rgw_op.h \ rgw/rgw_http_client.h \ rgw/rgw_swift.h \ rgw/rgw_swift_auth.h \ rgw/rgw_quota.h \ rgw/rgw_rados.h \ rgw/rgw_replica_log.h \ rgw/rgw_resolve.h \ rgw/rgw_rest.h \ rgw/rgw_rest_swift.h \ rgw/rgw_rest_s3.h \ rgw/rgw_auth_s3.h \ rgw/rgw_rest_admin.h \ rgw/rgw_rest_usage.h \ rgw/rgw_rest_user.h \ rgw/rgw_rest_bucket.h \ rgw/rgw_rest_client.h \ rgw/rgw_rest_conn.h \ rgw/rgw_tools.h \ rgw/rgw_rest_metadata.h \ rgw/rgw_rest_log.h \ rgw/rgw_rest_opstate.h \ rgw/rgw_rest_replica_log.h \ rgw/rgw_rest_config.h \ rgw/rgw_usage.h \ rgw/rgw_user.h \ rgw/rgw_bucket.h \ rgw/rgw_keystone.h \ rgw/rgw_civetweb.h \ rgw/rgw_civetweb_log.h \ civetweb/civetweb.h \ civetweb/include/civetweb.h \ civetweb/include/civetweb_conf.h \ civetweb/src/md5.h ceph-0.80.11/src/rgw/rgw_op.h0000664000175100017510000005051012623076744017732 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /** * All operations via the rados gateway are carried out by * small classes known as RGWOps. This class contains a req_state * and each possible command is a subclass of this with a defined * execute() method that does whatever the subclass name implies. * These subclasses must be further subclassed (by interface type) * to provide additional virtual methods such as send_response or get_params. */ #ifndef CEPH_RGW_OP_H #define CEPH_RGW_OP_H #include #include #include #include #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_user.h" #include "rgw_bucket.h" #include "rgw_acl.h" #include "rgw_cors.h" #include "rgw_quota.h" using namespace std; struct req_state; class RGWHandler; /** * Provide the base class for all ops. */ class RGWOp { protected: struct req_state *s; RGWHandler *dialect_handler; RGWRados *store; RGWCORSConfiguration bucket_cors; bool cors_exist; RGWQuotaInfo bucket_quota; RGWQuotaInfo user_quota; virtual int init_quota(); public: RGWOp() : s(NULL), dialect_handler(NULL), store(NULL), cors_exist(false) {} virtual ~RGWOp() {} virtual int init_processing() { int ret = init_quota(); if (ret < 0) return ret; return 0; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *dialect_handler) { this->store = store; this->s = s; this->dialect_handler = dialect_handler; } int read_bucket_cors(); bool generate_cors_headers(string& origin, string& method, string& headers, string& exp_headers, unsigned *max_age); virtual int verify_params() { return 0; } virtual bool prefetch_data() { return false; } virtual int verify_permission() = 0; virtual int verify_op_mask(); virtual void pre_exec() {} virtual void execute() = 0; virtual void send_response() {} virtual void complete() { send_response(); } virtual const string name() = 0; virtual uint32_t op_mask() { return 0; } }; class RGWGetObj : public RGWOp { protected: const char *range_str; const char *if_mod; const char *if_unmod; const char *if_match; const char *if_nomatch; off_t ofs; uint64_t total_len; off_t start; off_t end; time_t mod_time; time_t lastmod; time_t unmod_time; time_t *mod_ptr; time_t *unmod_ptr; map attrs; int ret; bool get_data; bool partial_content; rgw_obj obj; utime_t gc_invalidate_time; int init_common(); public: RGWGetObj() { range_str = NULL; if_mod = NULL; if_unmod = NULL; if_match = NULL; if_nomatch = NULL; start = 0; ofs = 0; total_len = 0; end = -1; mod_time = 0; lastmod = 0; unmod_time = 0; mod_ptr = NULL; unmod_ptr = NULL; get_data = false; partial_content = false; ret = 0; } virtual bool prefetch_data() { return true; } void set_get_data(bool get_data) { this->get_data = get_data; } int verify_permission(); void pre_exec(); void execute(); int read_user_manifest_part(rgw_bucket& bucket, RGWObjEnt& ent, RGWAccessControlPolicy *bucket_policy, off_t start_ofs, off_t end_ofs); int handle_user_manifest(const char *prefix); int get_data_cb(bufferlist& bl, off_t ofs, off_t len); virtual int get_params() = 0; virtual int send_response_data(bufferlist& bl, off_t ofs, off_t len) = 0; virtual const string name() { return "get_obj"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; #define RGW_LIST_BUCKETS_LIMIT_MAX 10000 class RGWListBuckets : public RGWOp { protected: int ret; bool sent_data; string marker; uint64_t limit; uint64_t limit_max; public: RGWListBuckets() : ret(0), sent_data(false) { limit = limit_max = RGW_LIST_BUCKETS_LIMIT_MAX; } int verify_permission(); void execute(); virtual int get_params() = 0; virtual void send_response_begin(bool has_buckets) = 0; virtual void send_response_data(RGWUserBuckets& buckets) = 0; virtual void send_response_end() = 0; virtual void send_response() {} virtual bool should_get_stats() { return false; } virtual const string name() { return "list_buckets"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWStatAccount : public RGWOp { protected: int ret; uint32_t buckets_count; uint64_t buckets_objcount; uint64_t buckets_size; uint64_t buckets_size_rounded; public: RGWStatAccount() { ret = 0; buckets_count = 0; buckets_objcount = 0; buckets_size = 0; buckets_size_rounded = 0; } int verify_permission(); void execute(); virtual void send_response() = 0; virtual const string name() { return "stat_account"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWListBucket : public RGWOp { protected: string prefix; string marker; string next_marker; string max_keys; string delimiter; int max; int ret; vector objs; map common_prefixes; int default_max; bool is_truncated; int parse_max_keys(); public: RGWListBucket() { max = 0; ret = 0; default_max = 0; is_truncated = false; } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "list_bucket"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWGetBucketLogging : public RGWOp { public: RGWGetBucketLogging() {} int verify_permission(); void execute() {} virtual void send_response() = 0; virtual const string name() { return "get_bucket_logging"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWStatBucket : public RGWOp { protected: int ret; RGWBucketEnt bucket; public: RGWStatBucket() : ret(0) {} ~RGWStatBucket() {} int verify_permission(); void pre_exec(); void execute(); virtual void send_response() = 0; virtual const string name() { return "stat_bucket"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWCreateBucket : public RGWOp { protected: int ret; RGWAccessControlPolicy policy; string location_constraint; string placement_rule; RGWBucketInfo info; obj_version ep_objv; bool has_cors; RGWCORSConfiguration cors_config; bufferlist in_data; public: RGWCreateBucket() : ret(0), has_cors(false) {} int verify_permission(); void pre_exec(); void execute(); virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); policy.set_ctx(s->cct); } virtual int get_params() { return 0; } virtual void send_response() = 0; virtual const string name() { return "create_bucket"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWDeleteBucket : public RGWOp { protected: int ret; RGWObjVersionTracker objv_tracker; public: RGWDeleteBucket() : ret(0) {} int verify_permission(); void pre_exec(); void execute(); virtual void send_response() = 0; virtual const string name() { return "delete_bucket"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; } }; class RGWPutObj : public RGWOp { friend class RGWPutObjProcessor; protected: int ret; off_t ofs; const char *supplied_md5_b64; const char *supplied_etag; string etag; bool chunked_upload; RGWAccessControlPolicy policy; const char *obj_manifest; time_t mtime; MD5 *user_manifest_parts_hash; public: RGWPutObj() { ret = 0; ofs = 0; supplied_md5_b64 = NULL; supplied_etag = NULL; chunked_upload = false; obj_manifest = NULL; mtime = 0; user_manifest_parts_hash = NULL; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); policy.set_ctx(s->cct); } RGWPutObjProcessor *select_processor(bool *is_multipart); void dispose_processor(RGWPutObjProcessor *processor); int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual int get_data(bufferlist& bl) = 0; virtual void send_response() = 0; virtual const string name() { return "put_obj"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWPostObj : public RGWOp { friend class RGWPutObjProcessor; protected: off_t min_len; off_t max_len; int ret; int len; off_t ofs; const char *supplied_md5_b64; const char *supplied_etag; string etag; string boundary; bool data_pending; string content_type; RGWAccessControlPolicy policy; map attrs; public: RGWPostObj() : min_len(0), max_len(LLONG_MAX), ret(0), len(0), ofs(0), supplied_md5_b64(NULL), supplied_etag(NULL), data_pending(false) {} virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); policy.set_ctx(s->cct); } int verify_permission(); void pre_exec(); void execute(); RGWPutObjProcessor *select_processor(); void dispose_processor(RGWPutObjProcessor *processor); virtual int get_params() = 0; virtual int get_data(bufferlist& bl) = 0; virtual void send_response() = 0; virtual const string name() { return "post_obj"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWPutMetadata : public RGWOp { protected: int ret; set rmattr_names; bool has_policy, has_cors; RGWAccessControlPolicy policy; RGWCORSConfiguration cors_config; public: RGWPutMetadata() { has_cors = false; has_policy = false; ret = 0; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); policy.set_ctx(s->cct); } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "put_obj_metadata"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWSetTempUrl : public RGWOp { protected: int ret; map temp_url_keys; public: RGWSetTempUrl() : ret(0) {} int verify_permission(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "set_temp_url"; } }; class RGWDeleteObj : public RGWOp { protected: int ret; public: RGWDeleteObj() : ret(0) {} int verify_permission(); void pre_exec(); void execute(); virtual void send_response() = 0; virtual const string name() { return "delete_obj"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; } }; class RGWCopyObj : public RGWOp { protected: RGWAccessControlPolicy dest_policy; const char *if_mod; const char *if_unmod; const char *if_match; const char *if_nomatch; off_t ofs; off_t len; off_t end; time_t mod_time; time_t unmod_time; time_t *mod_ptr; time_t *unmod_ptr; int ret; map attrs; string src_bucket_name; rgw_bucket src_bucket; string src_object; string dest_bucket_name; rgw_bucket dest_bucket; string dest_object; time_t mtime; bool replace_attrs; RGWBucketInfo src_bucket_info; RGWBucketInfo dest_bucket_info; string source_zone; string client_id; string op_id; string etag; off_t last_ofs; int init_common(); public: RGWCopyObj() { if_mod = NULL; if_unmod = NULL; if_match = NULL; if_nomatch = NULL; ofs = 0; len = 0; end = -1; mod_time = 0; unmod_time = 0; mod_ptr = NULL; unmod_ptr = NULL; ret = 0; mtime = 0; replace_attrs = false; last_ofs = 0; } static bool parse_copy_location(const char *src, string& bucket_name, string& object); virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); dest_policy.set_ctx(s->cct); } int verify_permission(); void pre_exec(); void execute(); void progress_cb(off_t ofs); virtual int init_dest_policy() { return 0; } virtual int get_params() = 0; virtual void send_partial_response(off_t ofs) {} virtual void send_response() = 0; virtual const string name() { return "copy_obj"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWGetACLs : public RGWOp { protected: int ret; string acls; public: RGWGetACLs() : ret(0) {} int verify_permission(); void pre_exec(); void execute(); virtual void send_response() = 0; virtual const string name() { return "get_acls"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWPutACLs : public RGWOp { protected: int ret; size_t len; char *data; ACLOwner owner; public: RGWPutACLs() { ret = 0; len = 0; data = NULL; } virtual ~RGWPutACLs() { free(data); } int verify_permission(); void pre_exec(); void execute(); virtual int get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss) { return 0; } virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "put_acls"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWGetCORS : public RGWOp { protected: int ret; public: RGWGetCORS() : ret(0) {} int verify_permission(); void execute(); virtual void send_response() = 0; virtual const string name() { return "get_cors"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWPutCORS : public RGWOp { protected: int ret; bufferlist cors_bl; public: RGWPutCORS() { ret = 0; } virtual ~RGWPutCORS() { } int verify_permission(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "put_cors"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWDeleteCORS : public RGWOp { protected: int ret; public: RGWDeleteCORS() : ret(0) {} int verify_permission(); void execute(); virtual void send_response() = 0; virtual const string name() { return "delete_cors"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWOptionsCORS : public RGWOp { protected: int ret; RGWCORSRule *rule; const char *origin, *req_hdrs, *req_meth; public: RGWOptionsCORS() : ret(0), rule(NULL), origin(NULL), req_hdrs(NULL), req_meth(NULL) { } int verify_permission() {return 0;} int validate_cors_request(RGWCORSConfiguration *cc); void execute(); void get_response_params(string& allowed_hdrs, string& exp_hdrs, unsigned *max_age); virtual void send_response() = 0; virtual const string name() { return "options_cors"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWInitMultipart : public RGWOp { protected: int ret; string upload_id; RGWAccessControlPolicy policy; public: RGWInitMultipart() { ret = 0; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); policy.set_ctx(s->cct); } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "init_multipart"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWCompleteMultipart : public RGWOp { protected: int ret; string upload_id; string etag; char *data; int len; public: RGWCompleteMultipart() { ret = 0; data = NULL; len = 0; } virtual ~RGWCompleteMultipart() { free(data); } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "complete_multipart"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; } }; class RGWAbortMultipart : public RGWOp { protected: int ret; public: RGWAbortMultipart() : ret(0) {} int verify_permission(); void pre_exec(); void execute(); virtual void send_response() = 0; virtual const string name() { return "abort_multipart"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; } }; class RGWListMultipart : public RGWOp { protected: int ret; string upload_id; map parts; int max_parts; int marker; RGWAccessControlPolicy policy; bool truncated; public: RGWListMultipart() { ret = 0; max_parts = 1000; marker = 0; truncated = false; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); policy = RGWAccessControlPolicy(s->cct); } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "list_multipart"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; #define MP_META_SUFFIX ".meta" class RGWMPObj { string oid; string prefix; string meta; string upload_id; public: RGWMPObj() {} RGWMPObj(const string& _oid, const string& _upload_id) { init(_oid, _upload_id, _upload_id); } void init(const string& _oid, const string& _upload_id) { init(_oid, _upload_id, _upload_id); } void init(const string& _oid, const string& _upload_id, const string& part_unique_str) { if (_oid.empty()) { clear(); return; } oid = _oid; upload_id = _upload_id; prefix = oid + "."; meta = prefix + upload_id + MP_META_SUFFIX; prefix.append(part_unique_str); } string& get_meta() { return meta; } string get_part(int num) { char buf[16]; snprintf(buf, 16, ".%d", num); string s = prefix; s.append(buf); return s; } string get_part(string& part) { string s = prefix; s.append("."); s.append(part); return s; } string& get_upload_id() { return upload_id; } string& get_key() { return oid; } bool from_meta(string& meta) { int end_pos = meta.rfind('.'); // search for ".meta" if (end_pos < 0) return false; int mid_pos = meta.rfind('.', end_pos - 1); // . if (mid_pos < 0) return false; oid = meta.substr(0, mid_pos); upload_id = meta.substr(mid_pos + 1, end_pos - mid_pos - 1); init(oid, upload_id, upload_id); return true; } void clear() { oid = ""; prefix = ""; meta = ""; upload_id = ""; } }; struct RGWMultipartUploadEntry { RGWObjEnt obj; RGWMPObj mp; }; class RGWListBucketMultiparts : public RGWOp { protected: string prefix; RGWMPObj marker; RGWMultipartUploadEntry next_marker; int max_uploads; string delimiter; int ret; vector uploads; map common_prefixes; bool is_truncated; int default_max; public: RGWListBucketMultiparts() { max_uploads = 0; ret = 0; is_truncated = false; default_max = 0; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWOp::init(store, s, h); max_uploads = default_max; } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_response() = 0; virtual const string name() { return "list_bucket_multiparts"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; } }; class RGWDeleteMultiObj : public RGWOp { protected: int ret; int max_to_delete; size_t len; char *data; string bucket_name; rgw_bucket bucket; bool quiet; bool status_dumped; public: RGWDeleteMultiObj() { ret = 0; max_to_delete = 1000; len = 0; data = NULL; quiet = false; status_dumped = false; } int verify_permission(); void pre_exec(); void execute(); virtual int get_params() = 0; virtual void send_status() = 0; virtual void begin_response() = 0; virtual void send_partial_response(pair& result) = 0; virtual void end_response() = 0; virtual const string name() { return "multi_object_delete"; } virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; } }; class RGWHandler { protected: RGWRados *store; struct req_state *s; int do_read_permissions(RGWOp *op, bool only_bucket); virtual RGWOp *op_get() { return NULL; } virtual RGWOp *op_put() { return NULL; } virtual RGWOp *op_delete() { return NULL; } virtual RGWOp *op_head() { return NULL; } virtual RGWOp *op_post() { return NULL; } virtual RGWOp *op_copy() { return NULL; } virtual RGWOp *op_options() { return NULL; } public: RGWHandler() : store(NULL), s(NULL) {} virtual ~RGWHandler(); virtual int init(RGWRados *store, struct req_state *_s, RGWClientIO *cio); virtual RGWOp *get_op(RGWRados *store); virtual void put_op(RGWOp *op); virtual int read_permissions(RGWOp *op) = 0; virtual int authorize() = 0; }; #endif ceph-0.80.11/src/rgw/rgw_user.cc0000664000175100017510000016775312623076744020452 0ustar jenkins-buildjenkins-build#include #include #include #include "common/errno.h" #include "common/Formatter.h" #include "common/ceph_json.h" #include "rgw_rados.h" #include "rgw_acl.h" #include "include/types.h" #include "rgw_user.h" #include "rgw_string.h" // until everything is moved from rgw_common #include "rgw_common.h" #include "rgw_bucket.h" #define dout_subsys ceph_subsys_rgw using namespace std; static RGWMetadataHandler *user_meta_handler = NULL; /** * Get the anonymous (ie, unauthenticated) user info. */ void rgw_get_anon_user(RGWUserInfo& info) { info.user_id = RGW_USER_ANON_ID; info.display_name.clear(); info.access_keys.clear(); } bool rgw_user_is_authenticated(RGWUserInfo& info) { return (info.user_id != RGW_USER_ANON_ID); } int rgw_user_sync_all_stats(RGWRados *store, const string& user_id) { CephContext *cct = store->ctx(); size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk; bool done; string marker; int ret; do { RGWUserBuckets user_buckets; ret = rgw_read_user_buckets(store, user_id, user_buckets, marker, max_entries, false); if (ret < 0) { ldout(cct, 0) << "failed to read user buckets: ret=" << ret << dendl; return ret; } map& buckets = user_buckets.get_buckets(); for (map::iterator i = buckets.begin(); i != buckets.end(); ++i) { marker = i->first; RGWBucketEnt& bucket_ent = i->second; ret = rgw_bucket_sync_user_stats(store, user_id, bucket_ent.bucket); if (ret < 0) { ldout(cct, 0) << "ERROR: could not sync bucket stats: ret=" << ret << dendl; return ret; } } done = (buckets.size() < max_entries); } while (!done); ret = store->complete_sync_user_stats(user_id); if (ret < 0) { cerr << "ERROR: failed to complete syncing user stats: ret=" << ret << std::endl; return ret; } return 0; } /** * Save the given user information to storage. * Returns: 0 on success, -ERR# on failure. */ int rgw_store_user_info(RGWRados *store, RGWUserInfo& info, RGWUserInfo *old_info, RGWObjVersionTracker *objv_tracker, time_t mtime, bool exclusive) { bufferlist bl; info.encode(bl); int ret; RGWObjVersionTracker ot; if (objv_tracker) { ot = *objv_tracker; } if (ot.write_version.tag.empty()) { if (ot.read_version.tag.empty()) { ot.generate_new_write_ver(store->ctx()); } else { ot.write_version = ot.read_version; ot.write_version.ver++; } } map::iterator iter; for (iter = info.swift_keys.begin(); iter != info.swift_keys.end(); ++iter) { if (old_info && old_info->swift_keys.count(iter->first) != 0) continue; RGWAccessKey& k = iter->second; /* check if swift mapping exists */ RGWUserInfo inf; int r = rgw_get_user_info_by_swift(store, k.id, inf); if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { ldout(store->ctx(), 0) << "WARNING: can't store user info, swift id (" << k.id << ") already mapped to another user (" << info.user_id << ")" << dendl; return -EEXIST; } } if (!info.access_keys.empty()) { /* check if access keys already exist */ RGWUserInfo inf; map::iterator iter = info.access_keys.begin(); for (; iter != info.access_keys.end(); ++iter) { RGWAccessKey& k = iter->second; if (old_info && old_info->access_keys.count(iter->first) != 0) continue; int r = rgw_get_user_info_by_access_key(store, k.id, inf); if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { ldout(store->ctx(), 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl; return -EEXIST; } } } RGWUID ui; ui.user_id = info.user_id; bufferlist link_bl; ::encode(ui, link_bl); bufferlist data_bl; ::encode(ui, data_bl); ::encode(info, data_bl); ret = store->meta_mgr->put_entry(user_meta_handler, info.user_id, data_bl, exclusive, &ot, mtime); if (ret < 0) return ret; if (!info.user_email.empty()) { if (!old_info || old_info->user_email.compare(info.user_email) != 0) { /* only if new index changed */ ret = rgw_put_system_obj(store, store->zone.user_email_pool, info.user_email, link_bl.c_str(), link_bl.length(), exclusive, NULL, 0); if (ret < 0) return ret; } } if (!info.access_keys.empty()) { map::iterator iter = info.access_keys.begin(); for (; iter != info.access_keys.end(); ++iter) { RGWAccessKey& k = iter->second; if (old_info && old_info->access_keys.count(iter->first) != 0) continue; ret = rgw_put_system_obj(store, store->zone.user_keys_pool, k.id, link_bl.c_str(), link_bl.length(), exclusive, NULL, 0); if (ret < 0) return ret; } } map::iterator siter; for (siter = info.swift_keys.begin(); siter != info.swift_keys.end(); ++siter) { RGWAccessKey& k = siter->second; if (old_info && old_info->swift_keys.count(siter->first) != 0) continue; ret = rgw_put_system_obj(store, store->zone.user_swift_pool, k.id, link_bl.c_str(), link_bl.length(), exclusive, NULL, 0); if (ret < 0) return ret; } return ret; } int rgw_get_user_info_from_index(RGWRados *store, string& key, rgw_bucket& bucket, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker, time_t *pmtime) { bufferlist bl; RGWUID uid; int ret = rgw_get_system_obj(store, NULL, bucket, key, bl, NULL, pmtime); if (ret < 0) return ret; bufferlist::iterator iter = bl.begin(); try { ::decode(uid, iter); return rgw_get_user_info_by_uid(store, uid.user_id, info, objv_tracker); } catch (buffer::error& err) { ldout(store->ctx(), 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl; return -EIO; } return 0; } /** * Given a uid, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ int rgw_get_user_info_by_uid(RGWRados *store, string& uid, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker, time_t *pmtime) { bufferlist bl; RGWUID user_id; int ret = rgw_get_system_obj(store, NULL, store->zone.user_uid_pool, uid, bl, objv_tracker, pmtime); if (ret < 0) return ret; bufferlist::iterator iter = bl.begin(); try { ::decode(user_id, iter); if (user_id.user_id.compare(uid) != 0) { lderr(store->ctx()) << "ERROR: rgw_get_user_info_by_uid(): user id mismatch: " << user_id.user_id << " != " << uid << dendl; return -EIO; } if (!iter.end()) { ::decode(info, iter); } } catch (buffer::error& err) { ldout(store->ctx(), 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl; return -EIO; } return 0; } /** * Given an email, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ int rgw_get_user_info_by_email(RGWRados *store, string& email, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker, time_t *pmtime) { return rgw_get_user_info_from_index(store, email, store->zone.user_email_pool, info, objv_tracker, pmtime); } /** * Given an swift username, finds the user_info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ extern int rgw_get_user_info_by_swift(RGWRados *store, string& swift_name, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker, time_t *pmtime) { return rgw_get_user_info_from_index(store, swift_name, store->zone.user_swift_pool, info, objv_tracker, pmtime); } /** * Given an access key, finds the user info associated with it. * returns: 0 on success, -ERR# on failure (including nonexistence) */ extern int rgw_get_user_info_by_access_key(RGWRados *store, string& access_key, RGWUserInfo& info, RGWObjVersionTracker *objv_tracker, time_t *pmtime) { return rgw_get_user_info_from_index(store, access_key, store->zone.user_keys_pool, info, objv_tracker, pmtime); } int rgw_remove_key_index(RGWRados *store, RGWAccessKey& access_key) { rgw_obj obj(store->zone.user_keys_pool, access_key.id); int ret = store->delete_system_obj(NULL, obj); return ret; } int rgw_remove_uid_index(RGWRados *store, string& uid) { RGWObjVersionTracker objv_tracker; RGWUserInfo info; int ret = rgw_get_user_info_by_uid(store, uid, info, &objv_tracker, NULL); if (ret < 0) return ret; ret = store->meta_mgr->remove_entry(user_meta_handler, uid, &objv_tracker); if (ret < 0) return ret; return 0; } int rgw_remove_email_index(RGWRados *store, string& email) { rgw_obj obj(store->zone.user_email_pool, email); int ret = store->delete_system_obj(NULL, obj); return ret; } int rgw_remove_swift_name_index(RGWRados *store, string& swift_name) { rgw_obj obj(store->zone.user_swift_pool, swift_name); int ret = store->delete_system_obj(NULL, obj); return ret; } /** * delete a user's presence from the RGW system. * First remove their bucket ACLs, then delete them * from the user and user email pools. This leaves the pools * themselves alone, as well as any ACLs embedded in object xattrs. */ int rgw_delete_user(RGWRados *store, RGWUserInfo& info, RGWObjVersionTracker& objv_tracker) { string marker; vector buckets_vec; bool done; int ret; CephContext *cct = store->ctx(); size_t max_buckets = cct->_conf->rgw_list_buckets_max_chunk; do { RGWUserBuckets user_buckets; ret = rgw_read_user_buckets(store, info.user_id, user_buckets, marker, max_buckets, false); if (ret < 0) return ret; map& buckets = user_buckets.get_buckets(); for (map::iterator i = buckets.begin(); i != buckets.end(); ++i) { RGWBucketEnt& bucket = i->second; buckets_vec.push_back(bucket.bucket); marker = i->first; } done = (buckets.size() < max_buckets); } while (!done); map::iterator kiter = info.access_keys.begin(); for (; kiter != info.access_keys.end(); ++kiter) { ldout(store->ctx(), 10) << "removing key index: " << kiter->first << dendl; ret = rgw_remove_key_index(store, kiter->second); if (ret < 0 && ret != -ENOENT) { ldout(store->ctx(), 0) << "ERROR: could not remove " << kiter->first << " (access key object), should be fixed (err=" << ret << ")" << dendl; return ret; } } map::iterator siter = info.swift_keys.begin(); for (; siter != info.swift_keys.end(); ++siter) { RGWAccessKey& k = siter->second; ldout(store->ctx(), 10) << "removing swift subuser index: " << k.id << dendl; /* check if swift mapping exists */ ret = rgw_remove_swift_name_index(store, k.id); if (ret < 0 && ret != -ENOENT) { ldout(store->ctx(), 0) << "ERROR: could not remove " << k.id << " (swift name object), should be fixed (err=" << ret << ")" << dendl; return ret; } } rgw_obj email_obj(store->zone.user_email_pool, info.user_email); ldout(store->ctx(), 10) << "removing email index: " << info.user_email << dendl; ret = store->delete_system_obj(NULL, email_obj); if (ret < 0 && ret != -ENOENT) { ldout(store->ctx(), 0) << "ERROR: could not remove " << info.user_id << ":" << email_obj << ", should be fixed (err=" << ret << ")" << dendl; return ret; } string buckets_obj_id; rgw_get_buckets_obj(info.user_id, buckets_obj_id); rgw_obj uid_bucks(store->zone.user_uid_pool, buckets_obj_id); ldout(store->ctx(), 10) << "removing user buckets index" << dendl; ret = store->delete_system_obj(NULL, uid_bucks); if (ret < 0 && ret != -ENOENT) { ldout(store->ctx(), 0) << "ERROR: could not remove " << info.user_id << ":" << uid_bucks << ", should be fixed (err=" << ret << ")" << dendl; return ret; } rgw_obj uid_obj(store->zone.user_uid_pool, info.user_id); ldout(store->ctx(), 10) << "removing user index: " << info.user_id << dendl; ret = store->meta_mgr->remove_entry(user_meta_handler, info.user_id, &objv_tracker); if (ret < 0 && ret != -ENOENT) { ldout(store->ctx(), 0) << "ERROR: could not remove " << info.user_id << ":" << uid_obj << ", should be fixed (err=" << ret << ")" << dendl; return ret; } return 0; } static bool char_is_unreserved_url(char c) { if (isalnum(c)) return true; switch (c) { case '-': case '.': case '_': case '~': return true; default: return false; } } struct rgw_flags_desc { uint32_t mask; const char *str; }; static struct rgw_flags_desc rgw_perms[] = { { RGW_PERM_FULL_CONTROL, "full-control" }, { RGW_PERM_READ | RGW_PERM_WRITE, "read-write" }, { RGW_PERM_READ, "read" }, { RGW_PERM_WRITE, "write" }, { RGW_PERM_READ_ACP, "read-acp" }, { RGW_PERM_WRITE_ACP, "read-acp" }, { 0, NULL } }; void rgw_perm_to_str(uint32_t mask, char *buf, int len) { const char *sep = ""; int pos = 0; if (!mask) { snprintf(buf, len, ""); return; } while (mask) { uint32_t orig_mask = mask; for (int i = 0; rgw_perms[i].mask; i++) { struct rgw_flags_desc *desc = &rgw_perms[i]; if ((mask & desc->mask) == desc->mask) { pos += snprintf(buf + pos, len - pos, "%s%s", sep, desc->str); if (pos == len) return; sep = ", "; mask &= ~desc->mask; if (!mask) return; } } if (mask == orig_mask) // no change break; } } uint32_t rgw_str_to_perm(const char *str) { if (strcasecmp(str, "read") == 0) return RGW_PERM_READ; else if (strcasecmp(str, "write") == 0) return RGW_PERM_WRITE; else if (strcasecmp(str, "readwrite") == 0) return RGW_PERM_READ | RGW_PERM_WRITE; else if (strcasecmp(str, "full") == 0) return RGW_PERM_FULL_CONTROL; return 0; // better to return no permission } static bool validate_access_key(string& key) { const char *p = key.c_str(); while (*p) { if (!char_is_unreserved_url(*p)) return false; p++; } return true; } static void set_err_msg(std::string *sink, std::string msg) { if (sink && !msg.empty()) *sink = msg; } static bool remove_old_indexes(RGWRados *store, RGWUserInfo& old_info, RGWUserInfo& new_info, std::string *err_msg) { int ret; bool success = true; if (!old_info.user_id.empty() && old_info.user_id.compare(new_info.user_id) != 0) { ret = rgw_remove_uid_index(store, old_info.user_id); if (ret < 0 && ret != -ENOENT) { set_err_msg(err_msg, "ERROR: could not remove index for uid " + old_info.user_id); success = false; } } if (!old_info.user_email.empty() && old_info.user_email.compare(new_info.user_email) != 0) { ret = rgw_remove_email_index(store, old_info.user_email); if (ret < 0 && ret != -ENOENT) { set_err_msg(err_msg, "ERROR: could not remove index for email " + old_info.user_email); success = false; } } map::iterator old_iter; for (old_iter = old_info.swift_keys.begin(); old_iter != old_info.swift_keys.end(); ++old_iter) { RGWAccessKey& swift_key = old_iter->second; map::iterator new_iter = new_info.swift_keys.find(swift_key.id); if (new_iter == new_info.swift_keys.end()) { ret = rgw_remove_swift_name_index(store, swift_key.id); if (ret < 0 && ret != -ENOENT) { set_err_msg(err_msg, "ERROR: could not remove index for swift_name " + swift_key.id); success = false; } } } return success; } /* * Dump either the full user info or a subset to a formatter. * * NOTE: It is the caller's respnsibility to ensure that the * formatter is flushed at the correct time. */ static void dump_subusers_info(Formatter *f, RGWUserInfo &info) { map::iterator uiter; f->open_array_section("subusers"); for (uiter = info.subusers.begin(); uiter != info.subusers.end(); ++uiter) { RGWSubUser& u = uiter->second; f->open_object_section("user"); f->dump_format("id", "%s:%s", info.user_id.c_str(), u.name.c_str()); char buf[256]; rgw_perm_to_str(u.perm_mask, buf, sizeof(buf)); f->dump_string("permissions", buf); f->close_section(); } f->close_section(); } static void dump_access_keys_info(Formatter *f, RGWUserInfo &info) { map::iterator kiter; f->open_array_section("keys"); for (kiter = info.access_keys.begin(); kiter != info.access_keys.end(); ++kiter) { RGWAccessKey& k = kiter->second; const char *sep = (k.subuser.empty() ? "" : ":"); const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str()); f->open_object_section("key"); f->dump_format("user", "%s%s%s", info.user_id.c_str(), sep, subuser); f->dump_string("access_key", k.id); f->dump_string("secret_key", k.key); f->close_section(); } f->close_section(); } static void dump_swift_keys_info(Formatter *f, RGWUserInfo &info) { map::iterator kiter; f->open_array_section("swift_keys"); for (kiter = info.swift_keys.begin(); kiter != info.swift_keys.end(); ++kiter) { RGWAccessKey& k = kiter->second; const char *sep = (k.subuser.empty() ? "" : ":"); const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str()); f->open_object_section("key"); f->dump_format("user", "%s%s%s", info.user_id.c_str(), sep, subuser); f->dump_string("secret_key", k.key); f->close_section(); } f->close_section(); } static void dump_user_info(Formatter *f, RGWUserInfo &info) { f->open_object_section("user_info"); f->dump_string("user_id", info.user_id); f->dump_string("display_name", info.display_name); f->dump_string("email", info.user_email); f->dump_int("suspended", (int)info.suspended); f->dump_int("max_buckets", (int)info.max_buckets); dump_subusers_info(f, info); dump_access_keys_info(f, info); dump_swift_keys_info(f, info); info.caps.dump(f); f->close_section(); } RGWAccessKeyPool::RGWAccessKeyPool(RGWUser* usr) { user = usr; swift_keys = NULL; access_keys = NULL; if (!user) { keys_allowed = false; store = NULL; return; } keys_allowed = true; store = user->get_store(); } RGWAccessKeyPool::~RGWAccessKeyPool() { } int RGWAccessKeyPool::init(RGWUserAdminOpState& op_state) { if (!op_state.is_initialized()) { keys_allowed = false; return -EINVAL; } std::string uid = op_state.get_user_id(); if (uid.compare(RGW_USER_ANON_ID) == 0) { keys_allowed = false; return -EACCES; } swift_keys = op_state.get_swift_keys(); access_keys = op_state.get_access_keys(); keys_allowed = true; return 0; } /* * Do a fairly exhaustive search for an existing key matching the parameters * given. Also handles the case where no key type was specified and updates * the operation state if needed. */ bool RGWAccessKeyPool::check_existing_key(RGWUserAdminOpState& op_state) { bool existing_key = false; int key_type = op_state.get_key_type(); std::string kid = op_state.get_access_key(); std::map::iterator kiter; std::string swift_kid = op_state.build_default_swift_kid(); RGWUserInfo dup_info; if (kid.empty() && swift_kid.empty()) return false; switch (key_type) { case KEY_TYPE_SWIFT: kiter = swift_keys->find(swift_kid); existing_key = (kiter != swift_keys->end()); if (existing_key) op_state.set_access_key(swift_kid); break; case KEY_TYPE_S3: kiter = access_keys->find(kid); existing_key = (kiter != access_keys->end()); break; default: kiter = access_keys->find(kid); existing_key = (kiter != access_keys->end()); if (existing_key) { op_state.set_key_type(KEY_TYPE_S3); break; } kiter = swift_keys->find(kid); existing_key = (kiter != swift_keys->end()); if (existing_key) { op_state.set_key_type(KEY_TYPE_SWIFT); break; } // handle the case where the access key was not provided in user:key format if (swift_kid.empty()) return false; kiter = swift_keys->find(swift_kid); existing_key = (kiter != swift_keys->end()); if (existing_key) { op_state.set_access_key(swift_kid); op_state.set_key_type(KEY_TYPE_SWIFT); } } op_state.set_existing_key(existing_key); return existing_key; } int RGWAccessKeyPool::check_op(RGWUserAdminOpState& op_state, std::string *err_msg) { RGWUserInfo dup_info; if (!op_state.is_populated()) { set_err_msg(err_msg, "user info was not populated"); return -EINVAL; } if (!keys_allowed) { set_err_msg(err_msg, "keys not allowed for this user"); return -EACCES; } std::string access_key = op_state.get_access_key(); std::string secret_key = op_state.get_secret_key(); int32_t key_type = op_state.get_key_type(); // if a key type wasn't specified set it to s3 if (key_type < 0) key_type = KEY_TYPE_S3; op_state.set_key_type(key_type); /* see if the access key or secret key was specified */ if (key_type == KEY_TYPE_S3 && !op_state.will_gen_access() && access_key.empty()) { set_err_msg(err_msg, "empty access key"); return -EINVAL; } // don't check for secret key because we may be doing a removal check_existing_key(op_state); return 0; } // Generate a new random key int RGWAccessKeyPool::generate_key(RGWUserAdminOpState& op_state, std::string *err_msg) { std::string id; std::string key; std::pair key_pair; RGWAccessKey new_key; RGWUserInfo duplicate_check; int ret = 0; int key_type = op_state.get_key_type(); bool gen_access = op_state.will_gen_access(); bool gen_secret = op_state.will_gen_secret(); std::string subuser = op_state.get_subuser(); if (!keys_allowed) { set_err_msg(err_msg, "access keys not allowed for this user"); return -EACCES; } if (op_state.has_existing_key()) { set_err_msg(err_msg, "cannot create existing key"); return -EEXIST; } if (!gen_access) { id = op_state.get_access_key(); } if (!id.empty()) { switch (key_type) { case KEY_TYPE_SWIFT: if (rgw_get_user_info_by_swift(store, id, duplicate_check) >= 0) { set_err_msg(err_msg, "existing swift key in RGW system:" + id); return -EEXIST; } break; case KEY_TYPE_S3: if (rgw_get_user_info_by_access_key(store, id, duplicate_check) >= 0) { set_err_msg(err_msg, "existing S3 key in RGW system:" + id); return -EEXIST; } } } if (op_state.has_subuser()) new_key.subuser = op_state.get_subuser(); if (!gen_secret) { key = op_state.get_secret_key(); } else if (gen_secret) { char secret_key_buf[SECRET_KEY_LEN + 1]; ret = gen_rand_base64(g_ceph_context, secret_key_buf, sizeof(secret_key_buf)); if (ret < 0) { set_err_msg(err_msg, "unable to generate secret key"); return ret; } key = secret_key_buf; } // Generate the access key if (key_type == KEY_TYPE_S3 && gen_access) { char public_id_buf[PUBLIC_ID_LEN + 1]; do { int id_buf_size = sizeof(public_id_buf); ret = gen_rand_alphanumeric_upper(g_ceph_context, public_id_buf, id_buf_size); if (ret < 0) { set_err_msg(err_msg, "unable to generate access key"); return ret; } id = public_id_buf; if (!validate_access_key(id)) continue; } while (!rgw_get_user_info_by_access_key(store, id, duplicate_check)); } if (key_type == KEY_TYPE_SWIFT) { id = op_state.build_default_swift_kid(); if (id.empty()) { set_err_msg(err_msg, "empty swift access key"); return -EINVAL; } // check that the access key doesn't exist if (rgw_get_user_info_by_swift(store, id, duplicate_check) >= 0) { set_err_msg(err_msg, "cannot create existing swift key"); return -EEXIST; } } // finally create the new key new_key.id = id; new_key.key = key; key_pair.first = id; key_pair.second = new_key; if (key_type == KEY_TYPE_S3) { access_keys->insert(key_pair); } else if (key_type == KEY_TYPE_SWIFT) { swift_keys->insert(key_pair); } return 0; } // modify an existing key int RGWAccessKeyPool::modify_key(RGWUserAdminOpState& op_state, std::string *err_msg) { std::string id; std::string key = op_state.get_secret_key(); int key_type = op_state.get_key_type(); RGWAccessKey modify_key; pair key_pair; map::iterator kiter; switch (key_type) { case KEY_TYPE_S3: id = op_state.get_access_key(); if (id.empty()) { set_err_msg(err_msg, "no access key specified"); return -EINVAL; } break; case KEY_TYPE_SWIFT: id = op_state.build_default_swift_kid(); if (id.empty()) { set_err_msg(err_msg, "no subuser specified"); return -EINVAL; } break; default: set_err_msg(err_msg, "invalid key type"); return -EINVAL; } if (!op_state.has_existing_key()) { set_err_msg(err_msg, "key does not exist"); return -EINVAL; } key_pair.first = id; if (key_type == KEY_TYPE_SWIFT) { modify_key.id = id; modify_key.subuser = op_state.get_subuser(); } else if (key_type == KEY_TYPE_S3) { kiter = access_keys->find(id); if (kiter != access_keys->end()) { modify_key = kiter->second; } } if (op_state.will_gen_secret()) { char secret_key_buf[SECRET_KEY_LEN + 1]; int ret; int key_buf_size = sizeof(secret_key_buf); ret = gen_rand_base64(g_ceph_context, secret_key_buf, key_buf_size); if (ret < 0) { set_err_msg(err_msg, "unable to generate secret key"); return ret; } key = secret_key_buf; } if (key.empty()) { set_err_msg(err_msg, "empty secret key"); return -EINVAL; } // update the access key with the new secret key modify_key.key = key; key_pair.second = modify_key; if (key_type == KEY_TYPE_S3) { (*access_keys)[id] = modify_key; } else if (key_type == KEY_TYPE_SWIFT) { (*swift_keys)[id] = modify_key; } return 0; } int RGWAccessKeyPool::execute_add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret = 0; std::string subprocess_msg; int key_op = GENERATE_KEY; // set the op if (op_state.has_existing_key()) key_op = MODIFY_KEY; switch (key_op) { case GENERATE_KEY: ret = generate_key(op_state, &subprocess_msg); break; case MODIFY_KEY: ret = modify_key(op_state, &subprocess_msg); break; } if (ret < 0) { set_err_msg(err_msg, subprocess_msg); return ret; } // store the updated info if (!defer_user_update) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWAccessKeyPool::add(RGWUserAdminOpState& op_state, std::string *err_msg) { return add(op_state, err_msg, false); } int RGWAccessKeyPool::add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret; std::string subprocess_msg; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse request, " + subprocess_msg); return ret; } ret = execute_add(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to add access key, " + subprocess_msg); return ret; } return 0; } int RGWAccessKeyPool::execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret = 0; int key_type = op_state.get_key_type(); std::string id = op_state.get_access_key(); map::iterator kiter; map *keys_map; if (!op_state.has_existing_key()) { set_err_msg(err_msg, "unable to find access key"); return -EINVAL; } if (key_type == KEY_TYPE_S3) { keys_map = access_keys; } else if (key_type == KEY_TYPE_SWIFT) { keys_map = swift_keys; } else { keys_map = NULL; set_err_msg(err_msg, "invalid access key"); return -EINVAL; } kiter = keys_map->find(id); if (kiter == keys_map->end()) { set_err_msg(err_msg, "key not found"); return -EINVAL; } rgw_remove_key_index(store, kiter->second); keys_map->erase(kiter); if (!defer_user_update) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWAccessKeyPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg) { return remove(op_state, err_msg, false); } int RGWAccessKeyPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret; std::string subprocess_msg; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse request, " + subprocess_msg); return ret; } ret = execute_remove(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to remove access key, " + subprocess_msg); return ret; } return 0; } RGWSubUserPool::RGWSubUserPool(RGWUser *usr) { subusers_allowed = (usr != NULL); if (usr) store = usr->get_store(); else store = NULL; user = usr; subuser_map = NULL; } RGWSubUserPool::~RGWSubUserPool() { } int RGWSubUserPool::init(RGWUserAdminOpState& op_state) { if (!op_state.is_initialized()) { subusers_allowed = false; return -EINVAL; } std::string uid = op_state.get_user_id(); if (uid.compare(RGW_USER_ANON_ID) == 0) { subusers_allowed = false; return -EACCES; } subuser_map = op_state.get_subusers(); if (subuser_map == NULL) { subusers_allowed = false; return -EINVAL; } subusers_allowed = true; return 0; } bool RGWSubUserPool::exists(std::string subuser) { if (subuser.empty()) return false; if (!subuser_map) return false; if (subuser_map->count(subuser)) return true; return false; } int RGWSubUserPool::check_op(RGWUserAdminOpState& op_state, std::string *err_msg) { bool existing = false; std::string subuser = op_state.get_subuser(); if (!op_state.is_populated()) { set_err_msg(err_msg, "user info was not populated"); return -EINVAL; } if (!subusers_allowed) { set_err_msg(err_msg, "subusers not allowed for this user"); return -EACCES; } if (subuser.empty() && !op_state.will_gen_subuser()) { set_err_msg(err_msg, "empty subuser name"); return -EINVAL; } // check if the subuser exists if (!subuser.empty()) existing = exists(subuser); op_state.set_existing_subuser(existing); return 0; } int RGWSubUserPool::execute_add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret = 0; std::string subprocess_msg; RGWSubUser subuser; std::pair subuser_pair; std::string subuser_str = op_state.get_subuser(); subuser_pair.first = subuser_str; // assumes key should be created if (op_state.has_key_op()) { ret = user->keys.add(op_state, &subprocess_msg, true); if (ret < 0) { set_err_msg(err_msg, "unable to create subuser key, " + subprocess_msg); return ret; } } // create the subuser subuser.name = subuser_str; if (op_state.has_subuser_perm()) subuser.perm_mask = op_state.get_subuser_perm(); // insert the subuser into user info subuser_pair.second = subuser; subuser_map->insert(subuser_pair); // attempt to save the subuser if (!defer_user_update) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWSubUserPool::add(RGWUserAdminOpState& op_state, std::string *err_msg) { return add(op_state, err_msg, false); } int RGWSubUserPool::add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { std::string subprocess_msg; int ret; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse request, " + subprocess_msg); return ret; } if (op_state.get_secret_key().empty()) { op_state.set_gen_access(); } ret = execute_add(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to create subuser, " + subprocess_msg); return ret; } return 0; } int RGWSubUserPool::execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret = 0; std::string subprocess_msg; std::string subuser_str = op_state.get_subuser(); map::iterator siter; siter = subuser_map->find(subuser_str); if (!op_state.has_existing_subuser()) { set_err_msg(err_msg, "subuser not found: " + subuser_str); return -EINVAL; } if (op_state.will_purge_keys()) { // error would be non-existance so don't check user->keys.remove(op_state, &subprocess_msg, true); } //remove the subuser from the user info subuser_map->erase(siter); // attempt to save the subuser if (!defer_user_update) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWSubUserPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg) { return remove(op_state, err_msg, false); } int RGWSubUserPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { std::string subprocess_msg; int ret; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse request, " + subprocess_msg); return ret; } ret = execute_remove(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to remove subuser, " + subprocess_msg); return ret; } return 0; } int RGWSubUserPool::execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { int ret = 0; std::string subprocess_msg; std::map::iterator siter; std::pair subuser_pair; std::string subuser_str = op_state.get_subuser(); RGWSubUser subuser; if (!op_state.has_existing_subuser()) { set_err_msg(err_msg, "subuser does not exist"); return -EINVAL; } subuser_pair.first = subuser_str; siter = subuser_map->find(subuser_str); subuser = siter->second; if (op_state.has_key_op()) { ret = user->keys.add(op_state, &subprocess_msg, true); if (ret < 0) { set_err_msg(err_msg, "unable to create subuser keys, " + subprocess_msg); return ret; } } if (op_state.has_subuser_perm()) subuser.perm_mask = op_state.get_subuser_perm(); subuser_pair.second = subuser; subuser_map->erase(siter); subuser_map->insert(subuser_pair); // attempt to save the subuser if (!defer_user_update) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWSubUserPool::modify(RGWUserAdminOpState& op_state, std::string *err_msg) { return RGWSubUserPool::modify(op_state, err_msg, false); } int RGWSubUserPool::modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update) { std::string subprocess_msg; int ret; RGWSubUser subuser; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse request, " + subprocess_msg); return ret; } ret = execute_modify(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to modify subuser, " + subprocess_msg); return ret; } return 0; } RGWUserCapPool::RGWUserCapPool(RGWUser *usr) { user = usr; caps = NULL; caps_allowed = (user != NULL); } RGWUserCapPool::~RGWUserCapPool() { } int RGWUserCapPool::init(RGWUserAdminOpState& op_state) { if (!op_state.is_initialized()) { caps_allowed = false; return -EINVAL; } std::string uid = op_state.get_user_id(); if (uid == RGW_USER_ANON_ID) { caps_allowed = false; return -EACCES; } caps = op_state.get_caps_obj(); if (!caps) { caps_allowed = false; return -EINVAL; } caps_allowed = true; return 0; } int RGWUserCapPool::add(RGWUserAdminOpState& op_state, std::string *err_msg) { return add(op_state, err_msg, false); } int RGWUserCapPool::add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save) { int ret = 0; std::string caps_str = op_state.get_caps(); if (!op_state.is_populated()) { set_err_msg(err_msg, "user info was not populated"); return -EINVAL; } if (!caps_allowed) { set_err_msg(err_msg, "caps not allowed for this user"); return -EACCES; } if (caps_str.empty()) { set_err_msg(err_msg, "empty user caps"); return -EINVAL; } int r = caps->add_from_string(caps_str); if (r < 0) { set_err_msg(err_msg, "unable to add caps: " + caps_str); return r; } if (!defer_save) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWUserCapPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg) { return remove(op_state, err_msg, false); } int RGWUserCapPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save) { int ret = 0; std::string caps_str = op_state.get_caps(); if (!op_state.is_populated()) { set_err_msg(err_msg, "user info was not populated"); return -EINVAL; } if (!caps_allowed) { set_err_msg(err_msg, "caps not allowed for this user"); return -EACCES; } if (caps_str.empty()) { set_err_msg(err_msg, "empty user caps"); return -EINVAL; } int r = caps->remove_from_string(caps_str); if (r < 0) { set_err_msg(err_msg, "unable to remove caps: " + caps_str); return r; } if (!defer_save) ret = user->update(op_state, err_msg); if (ret < 0) return ret; return 0; } RGWUser::RGWUser() : store(NULL), info_stored(false), caps(this), keys(this), subusers(this) { init_default(); } int RGWUser::init(RGWRados *storage, RGWUserAdminOpState& op_state) { init_default(); int ret = init_storage(storage); if (ret < 0) return ret; ret = init(op_state); if (ret < 0) return ret; return 0; } RGWUser::~RGWUser() { } void RGWUser::init_default() { // use anonymous user info as a placeholder rgw_get_anon_user(old_info); user_id = RGW_USER_ANON_ID; clear_populated(); } int RGWUser::init_storage(RGWRados *storage) { if (!storage) { return -EINVAL; } store = storage; clear_populated(); /* API wrappers */ keys = RGWAccessKeyPool(this); caps = RGWUserCapPool(this); subusers = RGWSubUserPool(this); return 0; } int RGWUser::init(RGWUserAdminOpState& op_state) { bool found = false; std::string swift_user; std::string uid = op_state.get_user_id(); std::string user_email = op_state.get_user_email(); std::string access_key = op_state.get_access_key(); std::string subuser = op_state.get_subuser(); int key_type = op_state.get_key_type(); if (key_type == KEY_TYPE_SWIFT) { swift_user = op_state.get_access_key(); access_key.clear(); } RGWUserInfo user_info; clear_populated(); if (uid.empty() && !subuser.empty()) { size_t pos = subuser.find(':'); if (pos != string::npos) { uid = subuser.substr(0, pos); op_state.set_user_id(uid); } } if (!uid.empty() && (uid.compare(RGW_USER_ANON_ID) != 0)) found = (rgw_get_user_info_by_uid(store, uid, user_info, &op_state.objv) >= 0); if (!user_email.empty() && !found) found = (rgw_get_user_info_by_email(store, user_email, user_info, &op_state.objv) >= 0); if (!swift_user.empty() && !found) found = (rgw_get_user_info_by_swift(store, swift_user, user_info, &op_state.objv) >= 0); if (!access_key.empty() && !found) found = (rgw_get_user_info_by_access_key(store, access_key, user_info, &op_state.objv) >= 0); op_state.set_existing_user(found); if (found) { op_state.set_user_info(user_info); op_state.set_populated(); old_info = user_info; set_populated(); } user_id = user_info.user_id; op_state.set_initialized(); // this may have been called by a helper object int ret = init_members(op_state); if (ret < 0) return ret; return 0; } int RGWUser::init_members(RGWUserAdminOpState& op_state) { int ret = 0; ret = keys.init(op_state); if (ret < 0) return ret; ret = subusers.init(op_state); if (ret < 0) return ret; ret = caps.init(op_state); if (ret < 0) return ret; return 0; } int RGWUser::update(RGWUserAdminOpState& op_state, std::string *err_msg) { int ret; std::string subprocess_msg; RGWUserInfo user_info = op_state.get_user_info(); if (!store) { set_err_msg(err_msg, "couldn't initialize storage"); return -EINVAL; } if (is_populated()) { ret = rgw_store_user_info(store, user_info, &old_info, &op_state.objv, 0, false); if (ret < 0) { set_err_msg(err_msg, "unable to store user info"); return ret; } ret = remove_old_indexes(store, old_info, user_info, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to remove old user info, " + subprocess_msg); return ret; } } else { ret = rgw_store_user_info(store, user_info, NULL, &op_state.objv, 0, false); if (ret < 0) { set_err_msg(err_msg, "unable to store user info"); return ret; } } old_info = user_info; set_populated(); return 0; } int RGWUser::check_op(RGWUserAdminOpState& op_state, std::string *err_msg) { bool same_id; bool populated; //bool existing_email = false; // this check causes a fault std::string op_id = op_state.get_user_id(); std::string op_email = op_state.get_user_email(); RGWUserInfo user_info; same_id = (user_id.compare(op_id) == 0); populated = is_populated(); if (op_id.compare(RGW_USER_ANON_ID) == 0) { set_err_msg(err_msg, "unable to perform operations on the anonymous user"); return -EINVAL; } if (populated && !same_id) { set_err_msg(err_msg, "user id mismatch, operation id: " + op_id\ + " does not match: " + user_id); return -EINVAL; } return 0; } int RGWUser::execute_add(RGWUserAdminOpState& op_state, std::string *err_msg) { std::string subprocess_msg; int ret = 0; bool defer_user_update = true; RGWUserInfo user_info; std::string uid = op_state.get_user_id(); std::string user_email = op_state.get_user_email(); std::string display_name = op_state.get_display_name(); // fail if the user exists already if (op_state.has_existing_user()) { if ((user_email.empty() || old_info.user_email == user_email) && old_info.display_name == display_name) { return execute_modify(op_state, err_msg); } set_err_msg(err_msg, "user: " + op_state.user_id + " exists"); return -EEXIST; } // fail if the user_info has already been populated if (op_state.is_populated()) { set_err_msg(err_msg, "cannot overwrite already populated user"); return -EEXIST; } // fail if the display name was not included if (display_name.empty()) { set_err_msg(err_msg, "no display name specified"); return -EINVAL; } // fail if the user email is a duplicate if (op_state.has_existing_email()) { set_err_msg(err_msg, "duplicate email provided"); return -EEXIST; } // set the user info user_id = uid; user_info.user_id = user_id; user_info.display_name = display_name; if (!user_email.empty()) user_info.user_email = user_email; user_info.max_buckets = op_state.get_max_buckets(); user_info.suspended = op_state.get_suspension_status(); user_info.system = op_state.system; if (op_state.op_mask_specified) user_info.op_mask = op_state.get_op_mask(); if (op_state.has_bucket_quota()) user_info.bucket_quota = op_state.get_bucket_quota(); if (op_state.temp_url_key_specified) { map::iterator iter; for (iter = op_state.temp_url_keys.begin(); iter != op_state.temp_url_keys.end(); ++iter) { user_info.temp_url_keys[iter->first] = iter->second; } } if (op_state.has_user_quota()) user_info.user_quota = op_state.get_user_quota(); // update the request op_state.set_user_info(user_info); op_state.set_populated(); // update the helper objects ret = init_members(op_state); if (ret < 0) { set_err_msg(err_msg, "unable to initialize user"); return ret; } // see if we need to add an access key if (op_state.has_key_op()) { ret = keys.add(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to create access key, " + subprocess_msg); return ret; } } // see if we need to add some caps if (op_state.has_caps_op()) { ret = caps.add(op_state, &subprocess_msg, defer_user_update); if (ret < 0) { set_err_msg(err_msg, "unable to add user capabilities, " + subprocess_msg); return ret; } } ret = update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWUser::add(RGWUserAdminOpState& op_state, std::string *err_msg) { std::string subprocess_msg; int ret; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg); return ret; } ret = execute_add(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to create user, " + subprocess_msg); return ret; } return 0; } int RGWUser::execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg) { int ret; bool purge_data = op_state.will_purge_data(); std::string uid = op_state.get_user_id(); RGWUserInfo user_info = op_state.get_user_info(); if (!op_state.has_existing_user()) { set_err_msg(err_msg, "user does not exist"); return -EINVAL; } bool done; string marker; CephContext *cct = store->ctx(); size_t max_buckets = cct->_conf->rgw_list_buckets_max_chunk; do { RGWUserBuckets buckets; ret = rgw_read_user_buckets(store, uid, buckets, marker, max_buckets, false); if (ret < 0) { set_err_msg(err_msg, "unable to read user bucket info"); return ret; } map& m = buckets.get_buckets(); if (!m.empty() && !purge_data) { set_err_msg(err_msg, "must specify purge data to remove user with buckets"); return -EEXIST; // change to code that maps to 409: conflict } std::map::iterator it; for (it = m.begin(); it != m.end(); ++it) { ret = rgw_remove_bucket(store, uid, ((*it).second).bucket, true); if (ret < 0) { set_err_msg(err_msg, "unable to delete user data"); return ret; } marker = it->first; } done = (m.size() < max_buckets); } while (!done); ret = rgw_delete_user(store, user_info, op_state.objv); if (ret < 0) { set_err_msg(err_msg, "unable to remove user from RADOS"); return ret; } op_state.clear_populated(); clear_populated(); return 0; } int RGWUser::remove(RGWUserAdminOpState& op_state, std::string *err_msg) { std::string subprocess_msg; int ret; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg); return ret; } ret = execute_remove(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to remove user, " + subprocess_msg); return ret; } return 0; } int RGWUser::execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg) { bool populated = op_state.is_populated(); int ret = 0; std::string subprocess_msg; std::string op_email = op_state.get_user_email(); std::string display_name = op_state.get_display_name(); RGWUserInfo user_info; RGWUserInfo duplicate_check; // ensure that the user info has been populated or is populate-able if (!op_state.has_existing_user() && !populated) { set_err_msg(err_msg, "user not found"); return -ENOENT; } // if the user hasn't already been populated...attempt to if (!populated) { ret = init(op_state); if (ret < 0) { set_err_msg(err_msg, "unable to retrieve user info"); return ret; } } // ensure that we can modify the user's attributes if (user_id == RGW_USER_ANON_ID) { set_err_msg(err_msg, "unable to modify anonymous user's info"); return -EACCES; } user_info = old_info; std::string old_email = old_info.user_email; if (!op_email.empty()) { bool same_email = false; same_email = (old_email.compare(op_email) == 0); // make sure we are not adding a duplicate email if (!same_email) { ret = rgw_get_user_info_by_email(store, op_email, duplicate_check); if (ret >= 0 && duplicate_check.user_id != user_id) { set_err_msg(err_msg, "cannot add duplicate email"); return -EEXIST; } } user_info.user_email = op_email; } // update the remaining user info if (!display_name.empty()) user_info.display_name = display_name; // will be set to RGW_DEFAULT_MAX_BUCKETS by default uint32_t max_buckets = op_state.get_max_buckets(); ldout(store->ctx(), 0) << "max_buckets=" << max_buckets << " specified=" << op_state.max_buckets_specified << dendl; if (op_state.max_buckets_specified) user_info.max_buckets = max_buckets; if (op_state.system_specified) user_info.system = op_state.system; if (op_state.temp_url_key_specified) { map::iterator iter; for (iter = op_state.temp_url_keys.begin(); iter != op_state.temp_url_keys.end(); ++iter) { user_info.temp_url_keys[iter->first] = iter->second; } } if (op_state.op_mask_specified) user_info.op_mask = op_state.get_op_mask(); if (op_state.has_bucket_quota()) user_info.bucket_quota = op_state.get_bucket_quota(); if (op_state.has_user_quota()) user_info.user_quota = op_state.get_user_quota(); if (op_state.has_suspension_op()) { __u8 suspended = op_state.get_suspension_status(); user_info.suspended = suspended; RGWUserBuckets buckets; if (user_id.empty()) { set_err_msg(err_msg, "empty user id passed...aborting"); return -EINVAL; } bool done; string marker; CephContext *cct = store->ctx(); size_t max_buckets = cct->_conf->rgw_list_buckets_max_chunk; do { ret = rgw_read_user_buckets(store, user_id, buckets, marker, max_buckets, false); if (ret < 0) { set_err_msg(err_msg, "could not get buckets for uid: " + user_id); return ret; } map& m = buckets.get_buckets(); map::iterator iter; vector bucket_names; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt obj = iter->second; bucket_names.push_back(obj.bucket); marker = iter->first; } ret = store->set_buckets_enabled(bucket_names, !suspended); if (ret < 0) { set_err_msg(err_msg, "failed to modify bucket"); return ret; } done = (m.size() < max_buckets); } while (!done); } op_state.set_user_info(user_info); // if we're supposed to modify keys, do so if (op_state.has_key_op()) { ret = keys.add(op_state, &subprocess_msg, true); if (ret < 0) { set_err_msg(err_msg, "unable to create or modify keys, " + subprocess_msg); return ret; } } ret = update(op_state, err_msg); if (ret < 0) return ret; return 0; } int RGWUser::modify(RGWUserAdminOpState& op_state, std::string *err_msg) { std::string subprocess_msg; int ret; ret = check_op(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg); return ret; } ret = execute_modify(op_state, &subprocess_msg); if (ret < 0) { set_err_msg(err_msg, "unable to modify user, " + subprocess_msg); return ret; } return 0; } int RGWUser::info(RGWUserAdminOpState& op_state, RGWUserInfo& fetched_info, std::string *err_msg) { int ret = init(op_state); if (ret < 0) { set_err_msg(err_msg, "unable to fetch user info"); return ret; } fetched_info = op_state.get_user_info(); return 0; } int RGWUser::info(RGWUserInfo& fetched_info, std::string *err_msg) { if (!is_populated()) { set_err_msg(err_msg, "no user info saved"); return -EINVAL; } fetched_info = old_info; return 0; } int RGWUserAdminOp_User::info(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; if (!op_state.has_existing_user()) return -ENOENT; Formatter *formatter = flusher.get_formatter(); ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); dump_user_info(formatter, info); flusher.flush(); return 0; } int RGWUserAdminOp_User::create(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.add(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); dump_user_info(formatter, info); flusher.flush(); return 0; } int RGWUserAdminOp_User::modify(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.modify(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); dump_user_info(formatter, info); flusher.flush(); return 0; } int RGWUserAdminOp_User::remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; ret = user.remove(op_state, NULL); return ret; } int RGWUserAdminOp_Subuser::create(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.subusers.add(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); dump_subusers_info(formatter, info); flusher.flush(); return 0; } int RGWUserAdminOp_Subuser::modify(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.subusers.modify(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); dump_subusers_info(formatter, info); flusher.flush(); return 0; } int RGWUserAdminOp_Subuser::remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; ret = user.subusers.remove(op_state, NULL); if (ret < 0) return ret; return 0; } int RGWUserAdminOp_Key::create(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.keys.add(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); int key_type = op_state.get_key_type(); if (key_type == KEY_TYPE_SWIFT) dump_swift_keys_info(formatter, info); else if (key_type == KEY_TYPE_S3) dump_access_keys_info(formatter, info); flusher.flush(); return 0; } int RGWUserAdminOp_Key::remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; ret = user.keys.remove(op_state, NULL); if (ret < 0) return ret; return 0; } int RGWUserAdminOp_Caps::add(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.caps.add(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); info.caps.dump(formatter); flusher.flush(); return 0; } int RGWUserAdminOp_Caps::remove(RGWRados *store, RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWUserInfo info; RGWUser user; int ret = user.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); ret = user.caps.remove(op_state, NULL); if (ret < 0) return ret; ret = user.info(info, NULL); if (ret < 0) return ret; flusher.start(0); info.caps.dump(formatter); flusher.flush(); return 0; } class RGWUserMetadataObject : public RGWMetadataObject { RGWUserInfo info; public: RGWUserMetadataObject(RGWUserInfo& i, obj_version& v, time_t m) : info(i) { objv = v; mtime = m; } void dump(Formatter *f) const { info.dump(f); } }; class RGWUserMetadataHandler : public RGWMetadataHandler { public: string get_type() { return "user"; } int get(RGWRados *store, string& entry, RGWMetadataObject **obj) { RGWUserInfo info; RGWObjVersionTracker objv_tracker; time_t mtime; int ret = rgw_get_user_info_by_uid(store, entry, info, &objv_tracker, &mtime); if (ret < 0) return ret; RGWUserMetadataObject *mdo = new RGWUserMetadataObject(info, objv_tracker.read_version, mtime); *obj = mdo; return 0; } int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj, sync_type_t sync_mode) { RGWUserInfo info; decode_json_obj(info, obj); RGWUserInfo old_info; time_t orig_mtime; int ret = rgw_get_user_info_by_uid(store, entry, old_info, &objv_tracker, &orig_mtime); if (ret < 0 && ret != -ENOENT) return ret; // are we actually going to perform this put, or is it too old? if (ret != -ENOENT && !check_versions(objv_tracker.read_version, orig_mtime, objv_tracker.write_version, mtime, sync_mode)) { return STATUS_NO_APPLY; } ret = rgw_store_user_info(store, info, &old_info, &objv_tracker, mtime, false); if (ret < 0) return ret; return STATUS_APPLIED; } struct list_keys_info { RGWRados *store; RGWListRawObjsCtx ctx; }; int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) { RGWUserInfo info; int ret = rgw_get_user_info_by_uid(store, entry, info, &objv_tracker); if (ret < 0) return ret; return rgw_delete_user(store, info, objv_tracker); } void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) { oid = key; bucket = store->zone.user_uid_pool; } int list_keys_init(RGWRados *store, void **phandle) { list_keys_info *info = new list_keys_info; info->store = store; *phandle = (void *)info; return 0; } int list_keys_next(void *handle, int max, list& keys, bool *truncated) { list_keys_info *info = static_cast(handle); string no_filter; keys.clear(); RGWRados *store = info->store; list unfiltered_keys; int ret = store->list_raw_objects(store->zone.user_uid_pool, no_filter, max, info->ctx, unfiltered_keys, truncated); if (ret < 0) return ret; // now filter out the buckets entries list::iterator iter; for (iter = unfiltered_keys.begin(); iter != unfiltered_keys.end(); ++iter) { string& k = *iter; if (k.find(".buckets") == string::npos) { keys.push_back(k); } } return 0; } void list_keys_complete(void *handle) { list_keys_info *info = static_cast(handle); delete info; } }; void rgw_user_init(RGWMetadataManager *mm) { user_meta_handler = new RGWUserMetadataHandler; mm->register_handler(user_meta_handler); } ceph-0.80.11/src/rgw/rgw_civetweb.h0000664000175100017510000000134512623076744021126 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_MONGOOSE_H #define CEPH_RGW_MONGOOSE_H #define TIME_BUF_SIZE 128 #include "rgw_client_io.h" struct mg_connection; class RGWMongoose : public RGWClientIO { mg_connection *conn; bufferlist header_data; bufferlist data; int port; bool header_done; bool sent_header; bool has_content_length; bool explicit_keepalive; public: void init_env(CephContext *cct); int write_data(const char *buf, int len); int read_data(char *buf, int len); int send_status(const char *status, const char *status_name); int send_100_continue(); int complete_header(); int complete_request(); int send_content_length(uint64_t len); RGWMongoose(mg_connection *_conn, int _port); void flush(); }; #endif ceph-0.80.11/src/rgw/rgw_swift.cc0000664000175100017510000004611312623076744020612 0ustar jenkins-buildjenkins-build#include #include #include #include "common/ceph_json.h" #include "rgw_common.h" #include "rgw_swift.h" #include "rgw_swift_auth.h" #include "rgw_user.h" #include "rgw_http_client.h" #include "rgw_keystone.h" #include "include/str_list.h" #include "common/ceph_crypto_cms.h" #include "common/armor.h" #define dout_subsys ceph_subsys_rgw static list roles_list; class RGWValidateSwiftToken : public RGWHTTPClient { struct rgw_swift_auth_info *info; protected: RGWValidateSwiftToken() : RGWHTTPClient(NULL), info(NULL) {} public: RGWValidateSwiftToken(CephContext *_cct, struct rgw_swift_auth_info *_info) : RGWHTTPClient(_cct), info(_info) {} int receive_header(void *ptr, size_t len); int receive_data(void *ptr, size_t len) { return 0; } int send_data(void *ptr, size_t len) { return 0; } friend class RGWKeystoneTokenCache; }; int RGWValidateSwiftToken::receive_header(void *ptr, size_t len) { char line[len + 1]; char *s = (char *)ptr, *end = (char *)ptr + len; char *p = line; ldout(cct, 10) << "read_http_header" << dendl; while (s != end) { if (*s == '\r') { s++; continue; } if (*s == '\n') { *p = '\0'; ldout(cct, 10) << "os_auth:" << line << dendl; // TODO: fill whatever data required here char *l = line; char *tok = strsep(&l, " \t:"); if (tok) { while (l && *l == ' ') l++; if (strcmp(tok, "HTTP") == 0) { info->status = atoi(l); } else if (strcasecmp(tok, "X-Auth-Groups") == 0) { info->auth_groups = l; char *s = strchr(l, ','); if (s) { *s = '\0'; info->user = l; } } else if (strcasecmp(tok, "X-Auth-Ttl") == 0) { info->ttl = atoll(l); } } } if (s != end) *p++ = *s++; } return 0; } int RGWSwift::validate_token(const char *token, struct rgw_swift_auth_info *info) { if (g_conf->rgw_swift_auth_url.empty()) return -EINVAL; string auth_url = g_conf->rgw_swift_auth_url; if (auth_url[auth_url.size() - 1] != '/') auth_url.append("/"); auth_url.append("token"); char url_buf[auth_url.size() + 1 + strlen(token) + 1]; sprintf(url_buf, "%s/%s", auth_url.c_str(), token); RGWValidateSwiftToken validate(cct, info); ldout(cct, 10) << "rgw_swift_validate_token url=" << url_buf << dendl; int ret = validate.process(url_buf); if (ret < 0) return ret; return 0; } class RGWPostHTTPData : public RGWHTTPClient { bufferlist *bl; std::string post_data; size_t post_data_index; public: RGWPostHTTPData(CephContext *_cct, bufferlist *_bl) : RGWHTTPClient(_cct), bl(_bl), post_data_index(0) {} void set_post_data(const std::string& _post_data) { this->post_data = _post_data; } int send_data(void* ptr, size_t len) { int length_to_copy = 0; if (post_data_index < post_data.length()) { length_to_copy = min(post_data.length() - post_data_index, len); memcpy(ptr, post_data.data() + post_data_index, length_to_copy); post_data_index += length_to_copy; } return length_to_copy; } int receive_data(void *ptr, size_t len) { bl->append((char *)ptr, len); return 0; } int receive_header(void *ptr, size_t len) { return 0; } }; typedef RGWPostHTTPData RGWGetKeystoneAdminToken; typedef RGWPostHTTPData RGWGetRevokedTokens; class RGWValidateKeystoneToken : public RGWHTTPClient { bufferlist *bl; public: RGWValidateKeystoneToken(CephContext *_cct, bufferlist *_bl) : RGWHTTPClient(_cct), bl(_bl) {} int receive_data(void *ptr, size_t len) { bl->append((char *)ptr, len); return 0; } int receive_header(void *ptr, size_t len) { return 0; } int send_data(void *ptr, size_t len) { return 0; } }; static RGWKeystoneTokenCache *keystone_token_cache = NULL; static int open_cms_envelope(CephContext *cct, string& src, string& dst) { #define BEGIN_CMS "-----BEGIN CMS-----" #define END_CMS "-----END CMS-----" int start = src.find(BEGIN_CMS); if (start < 0) { ldout(cct, 0) << "failed to find " << BEGIN_CMS << " in response" << dendl; return -EINVAL; } start += sizeof(BEGIN_CMS) - 1; int end = src.find(END_CMS); if (end < 0) { ldout(cct, 0) << "failed to find " << END_CMS << " in response" << dendl; return -EINVAL; } string s = src.substr(start, end - start); int pos = 0; do { int next = s.find('\n', pos); if (next < 0) { dst.append(s.substr(pos)); break; } else { dst.append(s.substr(pos, next - pos)); } pos = next + 1; } while (pos < (int)s.size()); return 0; } static int decode_b64_cms(CephContext *cct, const string& signed_b64, bufferlist& bl) { bufferptr signed_ber(signed_b64.size() * 2); char *dest = signed_ber.c_str(); const char *src = signed_b64.c_str(); size_t len = signed_b64.size(); char buf[len + 1]; buf[len] = '\0'; for (size_t i = 0; i < len; i++, src++) { if (*src != '-') buf[i] = *src; else buf[i] = '/'; } int ret = ceph_unarmor(dest, dest + signed_ber.length(), buf, buf + signed_b64.size()); if (ret < 0) { ldout(cct, 0) << "ceph_unarmor() failed, ret=" << ret << dendl; return ret; } bufferlist signed_ber_bl; signed_ber_bl.append(signed_ber); ret = ceph_decode_cms(cct, signed_ber_bl, bl); if (ret < 0) { ldout(cct, 0) << "ceph_decode_cms returned " << ret << dendl; return ret; } return 0; } int RGWSwift::get_keystone_url(std::string& url) { bufferlist bl; RGWGetRevokedTokens req(cct, &bl); url = cct->_conf->rgw_keystone_url; if (url.empty()) { ldout(cct, 0) << "ERROR: keystone url is not configured" << dendl; return -EINVAL; } if (url[url.size() - 1] != '/') url.append("/"); return 0; } int RGWSwift::get_keystone_admin_token(std::string& token) { std::string token_url; if (get_keystone_url(token_url) < 0) return -EINVAL; if (cct->_conf->rgw_keystone_admin_token.empty()) { token_url.append("v2.0/tokens"); KeystoneToken t; bufferlist token_bl; RGWGetKeystoneAdminToken token_req(cct, &token_bl); token_req.append_header("Content-Type", "application/json"); JSONFormatter jf; jf.open_object_section("token_request"); jf.open_object_section("auth"); jf.open_object_section("passwordCredentials"); encode_json("username", cct->_conf->rgw_keystone_admin_user, &jf); encode_json("password", cct->_conf->rgw_keystone_admin_password, &jf); jf.close_section(); encode_json("tenantName", cct->_conf->rgw_keystone_admin_tenant, &jf); jf.close_section(); jf.close_section(); std::stringstream ss; jf.flush(ss); token_req.set_post_data(ss.str()); int ret = token_req.process("POST", token_url.c_str()); if (ret < 0) return ret; if (t.parse(cct, token_bl) != 0) return -EINVAL; token = t.token.id; } else { token = cct->_conf->rgw_keystone_admin_token; } return 0; } int RGWSwift::check_revoked() { string url; string token; bufferlist bl; RGWGetRevokedTokens req(cct, &bl); if (get_keystone_admin_token(token) < 0) return -EINVAL; if (get_keystone_url(url) < 0) return -EINVAL; url.append("v2.0/tokens/revoked"); req.append_header("X-Auth-Token", token); int ret = req.process(url.c_str()); if (ret < 0) return ret; bl.append((char)0); // NULL terminate for debug output ldout(cct, 10) << "request returned " << bl.c_str() << dendl; JSONParser parser; if (!parser.parse(bl.c_str(), bl.length())) { ldout(cct, 0) << "malformed json" << dendl; return -EINVAL; } JSONObjIter iter = parser.find_first("signed"); if (iter.end()) { ldout(cct, 0) << "revoked tokens response is missing signed section" << dendl; return -EINVAL; } JSONObj *signed_obj = *iter; string signed_str = signed_obj->get_data(); ldout(cct, 10) << "signed=" << signed_str << dendl; string signed_b64; ret = open_cms_envelope(cct, signed_str, signed_b64); if (ret < 0) return ret; ldout(cct, 10) << "content=" << signed_b64 << dendl; bufferlist json; ret = decode_b64_cms(cct, signed_b64, json); if (ret < 0) { return ret; } ldout(cct, 10) << "ceph_decode_cms: decoded: " << json.c_str() << dendl; JSONParser list_parser; if (!list_parser.parse(json.c_str(), json.length())) { ldout(cct, 0) << "malformed json" << dendl; return -EINVAL; } JSONObjIter revoked_iter = list_parser.find_first("revoked"); if (revoked_iter.end()) { ldout(cct, 0) << "no revoked section in json" << dendl; return -EINVAL; } JSONObj *revoked_obj = *revoked_iter; JSONObjIter tokens_iter = revoked_obj->find_first(); for (; !tokens_iter.end(); ++tokens_iter) { JSONObj *o = *tokens_iter; JSONObj *token = o->find_obj("id"); if (!token) { ldout(cct, 0) << "bad token in array, missing id" << dendl; continue; } string token_id = token->get_data(); keystone_token_cache->invalidate(token_id); } return 0; } static void rgw_set_keystone_token_auth_info(KeystoneToken& token, struct rgw_swift_auth_info *info) { info->user = token.token.tenant.id; info->display_name = token.token.tenant.name; info->status = 200; } int RGWSwift::parse_keystone_token_response(const string& token, bufferlist& bl, struct rgw_swift_auth_info *info, KeystoneToken& t) { int ret = t.parse(cct, bl); if (ret < 0) return ret; bool found = false; list::iterator iter; for (iter = roles_list.begin(); iter != roles_list.end(); ++iter) { const string& role = *iter; if ((found=t.user.has_role(role))==true) break; } if (!found) { ldout(cct, 0) << "user does not hold a matching role; required roles: " << g_conf->rgw_keystone_accepted_roles << dendl; return -EPERM; } ldout(cct, 0) << "validated token: " << t.token.tenant.name << ":" << t.user.name << " expires: " << t.token.expires << dendl; rgw_set_keystone_token_auth_info(t, info); return 0; } int RGWSwift::update_user_info(RGWRados *store, struct rgw_swift_auth_info *info, RGWUserInfo& user_info) { if (rgw_get_user_info_by_uid(store, info->user, user_info) < 0) { ldout(cct, 0) << "NOTICE: couldn't map swift user" << dendl; user_info.user_id = info->user; user_info.display_name = info->display_name; int ret = rgw_store_user_info(store, user_info, NULL, NULL, 0, true); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to store new user's info: ret=" << ret << dendl; return ret; } } return 0; } #define PKI_ANS1_PREFIX "MII" static bool is_pki_token(const string& token) { return token.compare(0, sizeof(PKI_ANS1_PREFIX) - 1, PKI_ANS1_PREFIX) == 0; } static void get_token_id(const string& token, string& token_id) { if (!is_pki_token(token)) { token_id = token; return; } unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE]; MD5 hash; hash.Update((const byte *)token.c_str(), token.size()); hash.Final(m); char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5); token_id = calc_md5; } static bool decode_pki_token(CephContext *cct, const string& token, bufferlist& bl) { if (!is_pki_token(token)) return false; int ret = decode_b64_cms(cct, token, bl); if (ret < 0) return false; ldout(cct, 20) << "successfully decoded pki token" << dendl; return true; } int RGWSwift::validate_keystone_token(RGWRados *store, const string& token, struct rgw_swift_auth_info *info, RGWUserInfo& rgw_user) { KeystoneToken t; string token_id; get_token_id(token, token_id); ldout(cct, 20) << "token_id=" << token_id << dendl; /* check cache first */ if (keystone_token_cache->find(token_id, t)) { rgw_set_keystone_token_auth_info(t, info); ldout(cct, 20) << "cached token.tenant.id=" << t.token.tenant.id << dendl; int ret = update_user_info(store, info, rgw_user); if (ret < 0) return ret; return 0; } bufferlist bl; /* check if that's a self signed token that we can decode */ if (!decode_pki_token(cct, token, bl)) { /* can't decode, just go to the keystone server for validation */ RGWValidateKeystoneToken validate(cct, &bl); string url = g_conf->rgw_keystone_url; if (url.empty()) { ldout(cct, 0) << "ERROR: keystone url is not configured" << dendl; return -EINVAL; } if (url[url.size() - 1] != '/') url.append("/"); std::string admin_token; if (get_keystone_admin_token(admin_token) < 0) return -EINVAL; if (get_keystone_url(url) < 0) return -EINVAL; url.append("v2.0/tokens/"); url.append(token); validate.append_header("X-Auth-Token", admin_token); validate.set_send_length(0); int ret = validate.process(url.c_str()); if (ret < 0) return ret; } bl.append((char)0); // NULL terminate for debug output ldout(cct, 20) << "received response: " << bl.c_str() << dendl; int ret = parse_keystone_token_response(token, bl, info, t); if (ret < 0) return ret; if (t.expired()) { ldout(cct, 0) << "got expired token: " << t.token.tenant.name << ":" << t.user.name << " expired: " << t.token.expires << dendl; return -EPERM; } keystone_token_cache->add(token_id, t); ret = update_user_info(store, info, rgw_user); if (ret < 0) return ret; return 0; } int authenticate_temp_url(RGWRados *store, req_state *s) { /* temp url requires bucket and object specified in the requets */ if (s->bucket_name_str.empty()) return -EPERM; if (s->object_str.empty()) return -EPERM; string temp_url_sig = s->info.args.get("temp_url_sig"); if (temp_url_sig.empty()) return -EPERM; string temp_url_expires = s->info.args.get("temp_url_expires"); if (temp_url_expires.empty()) return -EPERM; /* need to get user info of bucket owner */ RGWBucketInfo bucket_info; int ret = store->get_bucket_info(NULL, s->bucket_name_str, bucket_info, NULL); if (ret < 0) return -EPERM; dout(20) << "temp url user (bucket owner): " << bucket_info.owner << dendl; if (rgw_get_user_info_by_uid(store, bucket_info.owner, s->user) < 0) { return -EPERM; } if (s->user.temp_url_keys.empty()) { dout(5) << "user does not have temp url key set, aborting" << dendl; return -EPERM; } if (!s->info.method) return -EPERM; utime_t now = ceph_clock_now(g_ceph_context); string err; uint64_t expiration = (uint64_t)strict_strtoll(temp_url_expires.c_str(), 10, &err); if (!err.empty()) { dout(5) << "failed to parse temp_url_expires: " << err << dendl; return -EPERM; } if (expiration <= (uint64_t)now.sec()) { dout(5) << "temp url expired: " << expiration << " <= " << now.sec() << dendl; return -EPERM; } /* strip the swift prefix from the uri */ int pos = g_conf->rgw_swift_url_prefix.find_last_not_of('/') + 1; string object_path = s->info.request_uri.substr(pos + 1); string str = string(s->info.method) + "\n" + temp_url_expires + "\n" + object_path; dout(20) << "temp url signature (plain text): " << str << dendl; map::iterator iter; for (iter = s->user.temp_url_keys.begin(); iter != s->user.temp_url_keys.end(); ++iter) { string& temp_url_key = iter->second; if (temp_url_key.empty()) continue; char dest[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; calc_hmac_sha1(temp_url_key.c_str(), temp_url_key.size(), str.c_str(), str.size(), dest); char dest_str[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE * 2 + 1]; buf_to_hex((const unsigned char *)dest, sizeof(dest), dest_str); dout(20) << "temp url signature [" << iter->first << "] (calculated): " << dest_str << dendl; if (dest_str != temp_url_sig) { dout(5) << "temp url signature mismatch: " << dest_str << " != " << temp_url_sig << dendl; } else { return 0; } } return -EPERM; } bool RGWSwift::verify_swift_token(RGWRados *store, req_state *s) { if (!do_verify_swift_token(store, s)) { return false; } if (!s->swift_user.empty()) { string subuser; ssize_t pos = s->swift_user.find(':'); if (pos < 0) { subuser = s->swift_user; } else { subuser = s->swift_user.substr(pos + 1); } s->perm_mask = 0; map::iterator iter = s->user.subusers.find(subuser); if (iter != s->user.subusers.end()) { RGWSubUser& subuser = iter->second; s->perm_mask = subuser.perm_mask; } } else { s->perm_mask = RGW_PERM_FULL_CONTROL; } return true; } bool RGWSwift::do_verify_swift_token(RGWRados *store, req_state *s) { if (!s->os_auth_token) { int ret = authenticate_temp_url(store, s); return (ret >= 0); } if (strncmp(s->os_auth_token, "AUTH_rgwtk", 10) == 0) { int ret = rgw_swift_verify_signed_token(s->cct, store, s->os_auth_token, s->user, &s->swift_user); if (ret < 0) return false; return true; } struct rgw_swift_auth_info info; info.status = 401; // start with access denied, validate_token might change that int ret; if (supports_keystone()) { ret = validate_keystone_token(store, s->os_auth_token, &info, s->user); return (ret >= 0); } ret = validate_token(s->os_auth_token, &info); if (ret < 0) return false; if (info.user.empty()) { ldout(cct, 5) << "swift auth didn't authorize a user" << dendl; return false; } s->swift_user = info.user; s->swift_groups = info.auth_groups; string swift_user = s->swift_user; ldout(cct, 10) << "swift user=" << s->swift_user << dendl; if (rgw_get_user_info_by_swift(store, swift_user, s->user) < 0) { ldout(cct, 0) << "NOTICE: couldn't map swift user" << dendl; return false; } ldout(cct, 10) << "user_id=" << s->user.user_id << dendl; return true; } void RGWSwift::init() { get_str_list(cct->_conf->rgw_keystone_accepted_roles, roles_list); if (supports_keystone()) init_keystone(); } void RGWSwift::init_keystone() { keystone_token_cache = new RGWKeystoneTokenCache(cct, cct->_conf->rgw_keystone_token_cache_size); keystone_revoke_thread = new KeystoneRevokeThread(cct, this); keystone_revoke_thread->create(); } void RGWSwift::finalize() { if (supports_keystone()) finalize_keystone(); } void RGWSwift::finalize_keystone() { delete keystone_token_cache; keystone_token_cache = NULL; down_flag.set(1); if (keystone_revoke_thread) { keystone_revoke_thread->stop(); keystone_revoke_thread->join(); } delete keystone_revoke_thread; keystone_revoke_thread = NULL; } RGWSwift *rgw_swift = NULL; void swift_init(CephContext *cct) { rgw_swift = new RGWSwift(cct); } void swift_finalize() { delete rgw_swift; } bool RGWSwift::going_down() { return (down_flag.read() != 0); } void *RGWSwift::KeystoneRevokeThread::entry() { do { dout(2) << "keystone revoke thread: start" << dendl; int r = swift->check_revoked(); if (r < 0) { dout(0) << "ERROR: keystone revocation processing returned error r=" << r << dendl; } if (swift->going_down()) break; lock.Lock(); cond.WaitInterval(cct, lock, utime_t(cct->_conf->rgw_keystone_revocation_interval, 0)); lock.Unlock(); } while (!swift->going_down()); return NULL; } void RGWSwift::KeystoneRevokeThread::stop() { Mutex::Locker l(lock); cond.Signal(); } ceph-0.80.11/src/rgw/rgw_usage.h0000664000175100017510000000103312623076744020414 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_USAGE_H #define CEPH_RGW_USAGE_H #include #include #include "common/Formatter.h" #include "rgw_formats.h" class RGWRados; class RGWUsage { public: static int show(RGWRados *store, std::string& uid, uint64_t start_epoch, uint64_t end_epoch, bool show_log_entries, bool show_log_sum, std::map *categories, RGWFormatterFlusher& flusher); static int trim(RGWRados *store, std::string& uid, uint64_t start_epoch, uint64_t end_epoch); }; #endif ceph-0.80.11/src/rgw/rgw_keystone.h0000664000175100017510000000374412623076744021164 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_KEYSTONE_H #define CEPH_RGW_KEYSTONE_H #include "rgw_common.h" class KeystoneToken { public: class Metadata { public: Metadata() : is_admin(false) { }; bool is_admin; void decode_json(JSONObj *obj); }; class Service { public: class Endpoint { public: string id; string admin_url; string public_url; string internal_url; string region; void decode_json(JSONObj *obj); }; string type; string name; list endpoints; void decode_json(JSONObj *obj); }; class Token { public: Token() : expires(0) { }; class Tenant { public: Tenant() : enabled(false) { }; string id; string name; string description; bool enabled; void decode_json(JSONObj *obj); }; string id; time_t expires; Tenant tenant; void decode_json(JSONObj *obj); }; class User { public: class Role { public: string id; string name; void decode_json(JSONObj *obj); }; string id; string name; string user_name; list roles; void decode_json(JSONObj *obj); bool has_role(const string& r); }; Metadata metadata; list service_catalog; Token token; User user; public: int parse(CephContext *cct, bufferlist& bl); bool expired() { uint64_t now = ceph_clock_now(NULL).sec(); return (now >= (uint64_t)token.expires); } void decode_json(JSONObj *access_obj); }; struct token_entry { KeystoneToken token; list::iterator lru_iter; }; class RGWKeystoneTokenCache { CephContext *cct; map tokens; list tokens_lru; Mutex lock; size_t max; public: RGWKeystoneTokenCache(CephContext *_cct, int _max) : cct(_cct), lock("RGWKeystoneTokenCache"), max(_max) {} bool find(const string& token_id, KeystoneToken& token); void add(const string& token_id, KeystoneToken& token); void invalidate(const string& token_id); }; #endif ceph-0.80.11/src/rgw/rgw_resolve.h0000664000175100017510000000061112623076744020770 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_RESOLVE_H #define CEPH_RGW_RESOLVE_H #include "rgw_common.h" class RGWDNSResolver; class RGWResolver { RGWDNSResolver *resolver; public: ~RGWResolver(); RGWResolver(); int resolve_cname(const string& hostname, string& cname, bool *found); }; extern void rgw_init_resolver(void); extern void rgw_shutdown_resolver(void); extern RGWResolver *rgw_resolver; #endif ceph-0.80.11/src/rgw/rgw_bucket.h0000664000175100017510000002663412623076744020603 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_BUCKET_H #define CEPH_RGW_BUCKET_H #include #include #include "include/types.h" #include "rgw_common.h" #include "rgw_tools.h" #include "rgw_rados.h" #include "rgw_string.h" #include "common/Formatter.h" #include "common/lru_map.h" #include "rgw_formats.h" using namespace std; // define as static when RGWBucket implementation compete extern void rgw_get_buckets_obj(const string& user_id, string& buckets_obj_id); extern int rgw_bucket_store_info(RGWRados *store, const string& bucket_name, bufferlist& bl, bool exclusive, map *pattrs, RGWObjVersionTracker *objv_tracker, time_t mtime); extern int rgw_bucket_instance_store_info(RGWRados *store, string& oid, bufferlist& bl, bool exclusive, map *pattrs, RGWObjVersionTracker *objv_tracker, time_t mtime); extern int rgw_bucket_instance_remove_entry(RGWRados *store, string& entry, RGWObjVersionTracker *objv_tracker); extern int rgw_bucket_delete_bucket_obj(RGWRados *store, string& bucket_name, RGWObjVersionTracker& objv_tracker); extern int rgw_bucket_sync_user_stats(RGWRados *store, const string& user_id, rgw_bucket& bucket); extern int rgw_bucket_sync_user_stats(RGWRados *store, const string& bucket_name); /** * Store a list of the user's buckets, with associated functinos. */ class RGWUserBuckets { map buckets; public: RGWUserBuckets() {} void encode(bufferlist& bl) const { ::encode(buckets, bl); } void decode(bufferlist::iterator& bl) { ::decode(buckets, bl); } /** * Check if the user owns a bucket by the given name. */ bool owns(string& name) { map::iterator iter; iter = buckets.find(name); return (iter != buckets.end()); } /** * Add a (created) bucket to the user's bucket list. */ void add(RGWBucketEnt& bucket) { buckets[bucket.bucket.name] = bucket; } /** * Remove a bucket from the user's list by name. */ void remove(string& name) { map::iterator iter; iter = buckets.find(name); if (iter != buckets.end()) { buckets.erase(iter); } } /** * Get the user's buckets as a map. */ map& get_buckets() { return buckets; } /** * Cleanup data structure */ void clear() { buckets.clear(); } size_t count() { return buckets.size(); } }; WRITE_CLASS_ENCODER(RGWUserBuckets) class RGWMetadataManager; extern void rgw_bucket_init(RGWMetadataManager *mm); /** * Get all the buckets owned by a user and fill up an RGWUserBuckets with them. * Returns: 0 on success, -ERR# on failure. */ extern int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, const string& marker, uint64_t max, bool need_stats); extern int rgw_link_bucket(RGWRados *store, string user_id, rgw_bucket& bucket, time_t creation_time, bool update_entrypoint = true); extern int rgw_unlink_bucket(RGWRados *store, string user_id, const string& bucket_name, bool update_entrypoint = true); extern int rgw_remove_object(RGWRados *store, const string& bucket_owner, rgw_bucket& bucket, std::string& object); extern int rgw_remove_bucket(RGWRados *store, const string& bucket_owner, rgw_bucket& bucket, bool delete_children); extern int rgw_bucket_set_attrs(RGWRados *store, RGWBucketInfo& bucket_info, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker); extern void check_bad_user_bucket_mapping(RGWRados *store, const string& user_id, bool fix); struct RGWBucketAdminOpState { std::string uid; std::string display_name; std::string bucket_name; std::string bucket_id; std::string object_name; bool list_buckets; bool stat_buckets; bool check_objects; bool fix_index; bool delete_child_objects; bool bucket_stored; rgw_bucket bucket; void set_fetch_stats(bool value) { stat_buckets = value; } void set_check_objects(bool value) { check_objects = value; } void set_fix_index(bool value) { fix_index = value; } void set_delete_children(bool value) { delete_child_objects = value; } void set_user_id(std::string& user_id) { if (!user_id.empty()) uid = user_id; } void set_bucket_name(std::string& bucket_str) { bucket_name = bucket_str; } void set_object(std::string& object_str) { object_name = object_str; } std::string& get_user_id() { return uid; }; std::string& get_user_display_name() { return display_name; }; std::string& get_bucket_name() { return bucket_name; }; std::string& get_object_name() { return object_name; }; rgw_bucket& get_bucket() { return bucket; }; void set_bucket(rgw_bucket& _bucket) { bucket = _bucket; bucket_stored = true; } bool will_fetch_stats() { return stat_buckets; }; bool will_fix_index() { return fix_index; }; bool will_delete_children() { return delete_child_objects; }; bool will_check_objects() { return check_objects; }; bool is_user_op() { return !uid.empty(); }; bool is_system_op() { return uid.empty(); }; bool has_bucket_stored() { return bucket_stored; }; RGWBucketAdminOpState() : list_buckets(false), stat_buckets(false), check_objects(false), fix_index(false), delete_child_objects(false), bucket_stored(false) {} }; /* * A simple wrapper class for administrative bucket operations */ class RGWBucket { RGWUserBuckets buckets; RGWRados *store; RGWAccessHandle handle; RGWUserInfo user_info; std::string bucket_name; bool failure; RGWBucketInfo bucket_info; private: public: RGWBucket() : store(NULL), handle(NULL), failure(false) {} int init(RGWRados *storage, RGWBucketAdminOpState& op_state); int check_bad_index_multipart(RGWBucketAdminOpState& op_state, list& objs_to_unlink, std::string *err_msg = NULL); int check_object_index(RGWBucketAdminOpState& op_state, map result, std::string *err_msg = NULL); int check_index(RGWBucketAdminOpState& op_state, map& existing_stats, map& calculated_stats, std::string *err_msg = NULL); int remove(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL); int link(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL); int unlink(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL); int remove_object(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL); int policy_bl_to_stream(bufferlist& bl, ostream& o); int get_policy(RGWBucketAdminOpState& op_state, ostream& o); void clear_failure() { failure = false; }; }; class RGWBucketAdminOp { public: static int get_policy(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher); static int get_policy(RGWRados *store, RGWBucketAdminOpState& op_state, ostream& os); static int unlink(RGWRados *store, RGWBucketAdminOpState& op_state); static int link(RGWRados *store, RGWBucketAdminOpState& op_state); static int check_index(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher); static int remove_bucket(RGWRados *store, RGWBucketAdminOpState& op_state); static int remove_object(RGWRados *store, RGWBucketAdminOpState& op_state); static int info(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher); }; enum DataLogEntityType { ENTITY_TYPE_BUCKET = 1, }; struct rgw_data_change { DataLogEntityType entity_type; string key; utime_t timestamp; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); uint8_t t = (uint8_t)entity_type; ::encode(t, bl); ::encode(key, bl); ::encode(timestamp, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); uint8_t t; ::decode(t, bl); entity_type = (DataLogEntityType)t; ::decode(key, bl); ::decode(timestamp, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; }; WRITE_CLASS_ENCODER(rgw_data_change) struct RGWDataChangesLogInfo { string marker; utime_t last_update; void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; class RGWDataChangesLog { CephContext *cct; RGWRados *store; int num_shards; string *oids; Mutex lock; atomic_t down_flag; struct ChangeStatus { utime_t cur_expiration; utime_t cur_sent; bool pending; RefCountedCond *cond; Mutex *lock; ChangeStatus() : pending(false), cond(NULL) { lock = new Mutex("RGWDataChangesLog::ChangeStatus"); } ~ChangeStatus() { delete lock; } }; typedef ceph::shared_ptr ChangeStatusPtr; lru_map changes; map cur_cycle; void _get_change(string& bucket_name, ChangeStatusPtr& status); void register_renew(rgw_bucket& bucket); void update_renewed(string& bucket_name, utime_t& expiration); class ChangesRenewThread : public Thread { CephContext *cct; RGWDataChangesLog *log; Mutex lock; Cond cond; public: ChangesRenewThread(CephContext *_cct, RGWDataChangesLog *_log) : cct(_cct), log(_log), lock("ChangesRenewThread") {} void *entry(); void stop(); }; ChangesRenewThread *renew_thread; public: RGWDataChangesLog(CephContext *_cct, RGWRados *_store) : cct(_cct), store(_store), lock("RGWDataChangesLog"), changes(cct->_conf->rgw_data_log_changes_size) { num_shards = cct->_conf->rgw_data_log_num_shards; oids = new string[num_shards]; string prefix = cct->_conf->rgw_data_log_obj_prefix; if (prefix.empty()) { prefix = "data_log"; } for (int i = 0; i < num_shards; i++) { char buf[16]; snprintf(buf, sizeof(buf), "%s.%d", prefix.c_str(), i); oids[i] = buf; } renew_thread = new ChangesRenewThread(cct, this); renew_thread->create(); } ~RGWDataChangesLog(); int choose_oid(rgw_bucket& bucket); int add_entry(rgw_bucket& bucket); int renew_entries(); int list_entries(int shard, utime_t& start_time, utime_t& end_time, int max_entries, list& entries, const string& marker, string *out_marker, bool *truncated); int trim_entries(int shard_id, const utime_t& start_time, const utime_t& end_time, const string& start_marker, const string& end_marker); int trim_entries(const utime_t& start_time, const utime_t& end_time, const string& start_marker, const string& end_marker); int get_info(int shard_id, RGWDataChangesLogInfo *info); int lock_exclusive(int shard_id, utime_t& duration, string& zone_id, string& owner_id) { return store->lock_exclusive(store->zone.log_pool, oids[shard_id], duration, zone_id, owner_id); } int unlock(int shard_id, string& zone_id, string& owner_id) { return store->unlock(store->zone.log_pool, oids[shard_id], zone_id, owner_id); } struct LogMarker { int shard; string marker; LogMarker() : shard(0) {} }; int list_entries(utime_t& start_time, utime_t& end_time, int max_entries, list& entries, LogMarker& marker, bool *ptruncated); bool going_down(); }; #endif ceph-0.80.11/src/rgw/rgw_rest_swift.h0000664000175100017510000001227712623076744021515 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_SWIFT_H #define CEPH_RGW_REST_SWIFT_H #define TIME_BUF_SIZE 128 #include "rgw_op.h" #include "rgw_rest.h" class RGWGetObj_ObjStore_SWIFT : public RGWGetObj_ObjStore { public: RGWGetObj_ObjStore_SWIFT() {} ~RGWGetObj_ObjStore_SWIFT() {} int send_response_data(bufferlist& bl, off_t ofs, off_t len); }; class RGWListBuckets_ObjStore_SWIFT : public RGWListBuckets_ObjStore { bool need_stats; public: RGWListBuckets_ObjStore_SWIFT() : need_stats(true) {} ~RGWListBuckets_ObjStore_SWIFT() {} int get_params(); void send_response_begin(bool has_buckets); void send_response_data(RGWUserBuckets& buckets); void send_response_end(); bool should_get_stats() { return need_stats; } }; class RGWListBucket_ObjStore_SWIFT : public RGWListBucket_ObjStore { string path; public: RGWListBucket_ObjStore_SWIFT() { default_max = 10000; } ~RGWListBucket_ObjStore_SWIFT() {} int get_params(); void send_response(); }; class RGWStatAccount_ObjStore_SWIFT : public RGWStatAccount_ObjStore { public: RGWStatAccount_ObjStore_SWIFT() { } ~RGWStatAccount_ObjStore_SWIFT() {} void send_response(); }; class RGWStatBucket_ObjStore_SWIFT : public RGWStatBucket_ObjStore { public: RGWStatBucket_ObjStore_SWIFT() {} ~RGWStatBucket_ObjStore_SWIFT() {} void send_response(); }; class RGWCreateBucket_ObjStore_SWIFT : public RGWCreateBucket_ObjStore { public: RGWCreateBucket_ObjStore_SWIFT() {} ~RGWCreateBucket_ObjStore_SWIFT() {} int get_params(); void send_response(); }; class RGWDeleteBucket_ObjStore_SWIFT : public RGWDeleteBucket_ObjStore { public: RGWDeleteBucket_ObjStore_SWIFT() {} ~RGWDeleteBucket_ObjStore_SWIFT() {} void send_response(); }; class RGWPutObj_ObjStore_SWIFT : public RGWPutObj_ObjStore { public: RGWPutObj_ObjStore_SWIFT() {} ~RGWPutObj_ObjStore_SWIFT() {} int get_params(); void send_response(); }; class RGWPutMetadata_ObjStore_SWIFT : public RGWPutMetadata_ObjStore { public: RGWPutMetadata_ObjStore_SWIFT() {} ~RGWPutMetadata_ObjStore_SWIFT() {} int get_params(); void send_response(); }; class RGWSetTempUrl_ObjStore_SWIFT : public RGWSetTempUrl_ObjStore { public: RGWSetTempUrl_ObjStore_SWIFT() {} ~RGWSetTempUrl_ObjStore_SWIFT() {} int get_params(); void send_response(); }; class RGWDeleteObj_ObjStore_SWIFT : public RGWDeleteObj_ObjStore { public: RGWDeleteObj_ObjStore_SWIFT() {} ~RGWDeleteObj_ObjStore_SWIFT() {} void send_response(); }; class RGWCopyObj_ObjStore_SWIFT : public RGWCopyObj_ObjStore { bool sent_header; public: RGWCopyObj_ObjStore_SWIFT() : sent_header(false) {} ~RGWCopyObj_ObjStore_SWIFT() {} int init_dest_policy(); int get_params(); void send_response(); void send_partial_response(off_t ofs); }; class RGWGetACLs_ObjStore_SWIFT : public RGWGetACLs_ObjStore { public: RGWGetACLs_ObjStore_SWIFT() {} ~RGWGetACLs_ObjStore_SWIFT() {} void send_response() {} }; class RGWPutACLs_ObjStore_SWIFT : public RGWPutACLs_ObjStore { public: RGWPutACLs_ObjStore_SWIFT() : RGWPutACLs_ObjStore() {} virtual ~RGWPutACLs_ObjStore_SWIFT() {} void send_response() {} }; class RGWOptionsCORS_ObjStore_SWIFT : public RGWOptionsCORS_ObjStore { public: RGWOptionsCORS_ObjStore_SWIFT() {} ~RGWOptionsCORS_ObjStore_SWIFT() {} void send_response(); }; class RGWHandler_ObjStore_SWIFT : public RGWHandler_ObjStore { friend class RGWRESTMgr_SWIFT; protected: virtual bool is_acl_op() { return false; } static int init_from_header(struct req_state *s); public: RGWHandler_ObjStore_SWIFT() {} virtual ~RGWHandler_ObjStore_SWIFT() {} int validate_bucket_name(const string& bucket); int init(RGWRados *store, struct req_state *state, RGWClientIO *cio); int authorize(); RGWAccessControlPolicy *alloc_policy() { return NULL; /* return new RGWAccessControlPolicy_SWIFT; */ } void free_policy(RGWAccessControlPolicy *policy) { delete policy; } }; class RGWHandler_ObjStore_Service_SWIFT : public RGWHandler_ObjStore_SWIFT { protected: RGWOp *op_get(); RGWOp *op_head(); RGWOp *op_post(); public: RGWHandler_ObjStore_Service_SWIFT() {} virtual ~RGWHandler_ObjStore_Service_SWIFT() {} }; class RGWHandler_ObjStore_Bucket_SWIFT : public RGWHandler_ObjStore_SWIFT { protected: bool is_obj_update_op() { return s->op == OP_POST; } RGWOp *get_obj_op(bool get_data); RGWOp *op_get(); RGWOp *op_head(); RGWOp *op_put(); RGWOp *op_delete(); RGWOp *op_post(); RGWOp *op_options(); public: RGWHandler_ObjStore_Bucket_SWIFT() {} virtual ~RGWHandler_ObjStore_Bucket_SWIFT() {} }; class RGWHandler_ObjStore_Obj_SWIFT : public RGWHandler_ObjStore_SWIFT { protected: bool is_obj_update_op() { return s->op == OP_POST; } RGWOp *get_obj_op(bool get_data); RGWOp *op_get(); RGWOp *op_head(); RGWOp *op_put(); RGWOp *op_delete(); RGWOp *op_post(); RGWOp *op_copy(); RGWOp *op_options(); public: RGWHandler_ObjStore_Obj_SWIFT() {} virtual ~RGWHandler_ObjStore_Obj_SWIFT() {} }; class RGWRESTMgr_SWIFT : public RGWRESTMgr { public: RGWRESTMgr_SWIFT() {} virtual ~RGWRESTMgr_SWIFT() {} virtual RGWRESTMgr *get_resource_mgr(struct req_state *s, const string& uri) { return this; } virtual RGWHandler *get_handler(struct req_state *s); }; #endif ceph-0.80.11/src/rgw/rgw_rest.cc0000664000175100017510000007425212623076744020440 0ustar jenkins-buildjenkins-build#include #include #include "common/Formatter.h" #include "common/utf8.h" #include "include/str_list.h" #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_formats.h" #include "rgw_op.h" #include "rgw_rest.h" #include "rgw_rest_swift.h" #include "rgw_rest_s3.h" #include "rgw_swift_auth.h" #include "rgw_cors_s3.h" #include "rgw_http_errors.h" #include "rgw_client_io.h" #include "rgw_resolve.h" #define dout_subsys ceph_subsys_rgw struct rgw_http_attr { const char *rgw_attr; const char *http_attr; }; /* * mapping between rgw object attrs and output http fields */ static struct rgw_http_attr rgw_to_http_attr_list[] = { { RGW_ATTR_CONTENT_TYPE, "Content-Type"}, { RGW_ATTR_CONTENT_LANG, "Content-Language"}, { RGW_ATTR_EXPIRES, "Expires"}, { RGW_ATTR_CACHE_CONTROL, "Cache-Control"}, { RGW_ATTR_CONTENT_DISP, "Content-Disposition"}, { RGW_ATTR_CONTENT_ENC, "Content-Encoding"}, { RGW_ATTR_USER_MANIFEST, "X-Object-Manifest"}, { NULL, NULL}, }; struct generic_attr { const char *http_header; const char *rgw_attr; }; /* * mapping between http env fields and rgw object attrs */ struct generic_attr generic_attrs[] = { { "CONTENT_TYPE", RGW_ATTR_CONTENT_TYPE }, { "HTTP_CONTENT_LANGUAGE", RGW_ATTR_CONTENT_LANG }, { "HTTP_EXPIRES", RGW_ATTR_EXPIRES }, { "HTTP_CACHE_CONTROL", RGW_ATTR_CACHE_CONTROL }, { "HTTP_CONTENT_DISPOSITION", RGW_ATTR_CONTENT_DISP }, { "HTTP_CONTENT_ENCODING", RGW_ATTR_CONTENT_ENC }, { NULL, NULL }, }; map rgw_to_http_attrs; static map generic_attrs_map; map http_status_names; /* * make attrs look_like_this * converts dashes to underscores */ string lowercase_underscore_http_attr(const string& orig) { const char *s = orig.c_str(); char buf[orig.size() + 1]; buf[orig.size()] = '\0'; for (size_t i = 0; i < orig.size(); ++i, ++s) { switch (*s) { case '-': buf[i] = '_'; break; default: buf[i] = tolower(*s); } } return string(buf); } /* * make attrs LOOK_LIKE_THIS * converts dashes to underscores */ string uppercase_underscore_http_attr(const string& orig) { const char *s = orig.c_str(); char buf[orig.size() + 1]; buf[orig.size()] = '\0'; for (size_t i = 0; i < orig.size(); ++i, ++s) { switch (*s) { case '-': buf[i] = '_'; break; default: buf[i] = toupper(*s); } } return string(buf); } /* * make attrs look-like-this * converts underscores to dashes */ string lowercase_dash_http_attr(const string& orig) { const char *s = orig.c_str(); char buf[orig.size() + 1]; buf[orig.size()] = '\0'; for (size_t i = 0; i < orig.size(); ++i, ++s) { switch (*s) { case '_': buf[i] = '-'; break; default: buf[i] = tolower(*s); } } return string(buf); } /* * make attrs Look-Like-This * converts underscores to dashes */ string camelcase_dash_http_attr(const string& orig) { const char *s = orig.c_str(); char buf[orig.size() + 1]; buf[orig.size()] = '\0'; bool last_sep = true; for (size_t i = 0; i < orig.size(); ++i, ++s) { switch (*s) { case '_': buf[i] = '-'; last_sep = true; break; default: if (last_sep) buf[i] = toupper(*s); else buf[i] = tolower(*s); last_sep = false; } } return string(buf); } void rgw_rest_init(CephContext *cct) { for (struct rgw_http_attr *attr = rgw_to_http_attr_list; attr->rgw_attr; attr++) { rgw_to_http_attrs[attr->rgw_attr] = attr->http_attr; } for (struct generic_attr *gen_attr = generic_attrs; gen_attr->http_header; gen_attr++) { generic_attrs_map[gen_attr->http_header] = gen_attr->rgw_attr; } list extended_http_attrs; get_str_list(cct->_conf->rgw_extended_http_attrs, extended_http_attrs); list::iterator iter; for (iter = extended_http_attrs.begin(); iter != extended_http_attrs.end(); ++iter) { string rgw_attr = RGW_ATTR_PREFIX; rgw_attr.append(lowercase_underscore_http_attr(*iter)); rgw_to_http_attrs[rgw_attr] = camelcase_dash_http_attr(*iter); string http_header = "HTTP_"; http_header.append(uppercase_underscore_http_attr(*iter)); generic_attrs_map[http_header] = rgw_attr; } for (const struct rgw_http_status_code *h = http_codes; h->code; h++) { http_status_names[h->code] = h->name; } } static void dump_status(struct req_state *s, const char *status, const char *status_name) { int r = s->cio->send_status(status, status_name); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->send_status() returned err=" << r << dendl; } } void rgw_flush_formatter_and_reset(struct req_state *s, Formatter *formatter) { std::ostringstream oss; formatter->flush(oss); std::string outs(oss.str()); if (!outs.empty() && s->op != OP_HEAD) { s->cio->write(outs.c_str(), outs.size()); } s->formatter->reset(); } void rgw_flush_formatter(struct req_state *s, Formatter *formatter) { std::ostringstream oss; formatter->flush(oss); std::string outs(oss.str()); if (!outs.empty() && s->op != OP_HEAD) { s->cio->write(outs.c_str(), outs.size()); } } void set_req_state_err(struct req_state *s, int err_no) { const struct rgw_http_errors *r; if (err_no < 0) err_no = -err_no; s->err.ret = -err_no; if (s->prot_flags & RGW_REST_SWIFT) { r = search_err(err_no, RGW_HTTP_SWIFT_ERRORS, ARRAY_LEN(RGW_HTTP_SWIFT_ERRORS)); if (r) { s->err.http_ret = r->http_ret; s->err.s3_code = r->s3_code; return; } } r = search_err(err_no, RGW_HTTP_ERRORS, ARRAY_LEN(RGW_HTTP_ERRORS)); if (r) { s->err.http_ret = r->http_ret; s->err.s3_code = r->s3_code; return; } dout(0) << "WARNING: set_req_state_err err_no=" << err_no << " resorting to 500" << dendl; s->err.http_ret = 500; s->err.s3_code = "UnknownError"; } void dump_errno(struct req_state *s) { char buf[32]; snprintf(buf, sizeof(buf), "%d", s->err.http_ret); dump_status(s, buf, http_status_names[s->err.http_ret]); } void dump_errno(struct req_state *s, int err) { char buf[32]; snprintf(buf, sizeof(buf), "%d", err); dump_status(s, buf, http_status_names[s->err.http_ret]); } void dump_content_length(struct req_state *s, uint64_t len) { int r = s->cio->send_content_length(len); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } r = s->cio->print("Accept-Ranges: %s\r\n", "bytes"); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } } void dump_etag(struct req_state *s, const char *etag) { int r; if (s->prot_flags & RGW_REST_SWIFT) r = s->cio->print("etag: %s\r\n", etag); else r = s->cio->print("ETag: \"%s\"\r\n", etag); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } } void dump_pair(struct req_state *s, const char *key, const char *value) { if ( (strlen(key) > 0) && (strlen(value) > 0)) s->cio->print("%s: %s\r\n", key, value); } void dump_bucket_from_state(struct req_state *s) { int expose_bucket = g_conf->rgw_expose_bucket; if (expose_bucket) { if (!s->bucket_name_str.empty()) { string b; url_encode(s->bucket_name_str, b); s->cio->print("Bucket: %s\r\n", b.c_str()); } } } void dump_uri_from_state(struct req_state *s) { if (strcmp(s->info.request_uri.c_str(), "/") == 0) { string location = "http://"; string server = s->info.env->get("SERVER_NAME", ""); location.append(server); location += "/"; if (!s->bucket_name_str.empty()) { location += s->bucket_name_str; location += "/"; if (!s->object_str.empty()) { location += s->object_str; s->cio->print("Location: %s\r\n", location.c_str()); } } } else { s->cio->print("Location: \"%s\"\r\n", s->info.request_uri.c_str()); } } void dump_redirect(struct req_state *s, const string& redirect) { if (redirect.empty()) return; s->cio->print("Location: %s\r\n", redirect.c_str()); } static void dump_time_header(struct req_state *s, const char *name, time_t t) { char timestr[TIME_BUF_SIZE]; struct tm result; struct tm *tmp = gmtime_r(&t, &result); if (tmp == NULL) return; if (strftime(timestr, sizeof(timestr), "%a, %d %b %Y %H:%M:%S %Z", tmp) == 0) return; int r = s->cio->print("%s: %s\r\n", name, timestr); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } } void dump_last_modified(struct req_state *s, time_t t) { dump_time_header(s, "Last-Modified", t); } void dump_epoch_header(struct req_state *s, const char *name, time_t t) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", (long long)t); int r = s->cio->print("%s: %s\r\n", name, buf); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } } void dump_time(struct req_state *s, const char *name, time_t *t) { char buf[TIME_BUF_SIZE]; struct tm result; struct tm *tmp = gmtime_r(t, &result); if (tmp == NULL) return; if (strftime(buf, sizeof(buf), "%Y-%m-%dT%T.000Z", tmp) == 0) return; s->formatter->dump_string(name, buf); } void dump_owner(struct req_state *s, string& id, string& name, const char *section) { if (!section) section = "Owner"; s->formatter->open_object_section(section); s->formatter->dump_string("ID", id); s->formatter->dump_string("DisplayName", name); s->formatter->close_section(); } void dump_access_control(struct req_state *s, const char *origin, const char *meth, const char *hdr, const char *exp_hdr, uint32_t max_age) { if (origin && (origin[0] != '\0')) { s->cio->print("Access-Control-Allow-Origin: %s\r\n", origin); if (meth && (meth[0] != '\0')) s->cio->print("Access-Control-Allow-Methods: %s\r\n", meth); if (hdr && (hdr[0] != '\0')) s->cio->print("Access-Control-Allow-Headers: %s\r\n", hdr); if (exp_hdr && (exp_hdr[0] != '\0')) { s->cio->print("Access-Control-Expose-Headers: %s\r\n", exp_hdr); } if (max_age != CORS_MAX_AGE_INVALID) { s->cio->print("Access-Control-Max-Age: %d\r\n", max_age); } } } void dump_access_control(req_state *s, RGWOp *op) { string origin; string method; string header; string exp_header; unsigned max_age = CORS_MAX_AGE_INVALID; if (!op->generate_cors_headers(origin, method, header, exp_header, &max_age)) return; dump_access_control(s, origin.c_str(), method.c_str(), header.c_str(), exp_header.c_str(), max_age); } void dump_start(struct req_state *s) { if (!s->content_started) { if (s->format == RGW_FORMAT_XML) s->formatter->write_raw_data(XMLFormatter::XML_1_DTD); s->content_started = true; } } void end_header(struct req_state *s, RGWOp *op, const char *content_type, const int64_t proposed_content_length, bool force_content_type) { string ctype; if (op) { dump_access_control(s, op); } if (s->prot_flags & RGW_REST_SWIFT && !content_type) { force_content_type = true; } /* do not send content type if content length is zero and the content type was not set by the user */ if (force_content_type || (!content_type && s->formatter->get_len() != 0) || s->err.is_err()){ switch (s->format) { case RGW_FORMAT_XML: ctype = "application/xml"; break; case RGW_FORMAT_JSON: ctype = "application/json"; break; default: ctype = "text/plain"; break; } if (s->prot_flags & RGW_REST_SWIFT) ctype.append("; charset=utf-8"); content_type = ctype.c_str(); } if (s->err.is_err()) { dump_start(s); s->formatter->open_object_section("Error"); if (!s->err.s3_code.empty()) s->formatter->dump_string("Code", s->err.s3_code); if (!s->err.message.empty()) s->formatter->dump_string("Message", s->err.message); s->formatter->close_section(); dump_content_length(s, s->formatter->get_len()); } else { if (proposed_content_length != NO_CONTENT_LENGTH) { dump_content_length(s, proposed_content_length); } } int r; if (content_type) { r = s->cio->print("Content-Type: %s\r\n", content_type); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } } r = s->cio->complete_header(); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->complete_header() returned err=" << r << dendl; } s->cio->set_account(true); rgw_flush_formatter_and_reset(s, s->formatter); } void abort_early(struct req_state *s, RGWOp *op, int err_no) { if (!s->formatter) { s->formatter = new JSONFormatter; s->format = RGW_FORMAT_JSON; } set_req_state_err(s, err_no); dump_errno(s); dump_bucket_from_state(s); end_header(s, op); rgw_flush_formatter_and_reset(s, s->formatter); perfcounter->inc(l_rgw_failed_req); } void dump_continue(struct req_state *s) { s->cio->send_100_continue(); } void dump_range(struct req_state *s, uint64_t ofs, uint64_t end, uint64_t total) { char range_buf[128]; /* dumping range into temp buffer first, as libfcgi will fail to digest %lld */ snprintf(range_buf, sizeof(range_buf), "%lld-%lld/%lld", (long long)ofs, (long long)end, (long long)total); int r = s->cio->print("Content-Range: bytes %s\r\n", range_buf); if (r < 0) { ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl; } } int RGWGetObj_ObjStore::get_params() { range_str = s->info.env->get("HTTP_RANGE"); if_mod = s->info.env->get("HTTP_IF_MODIFIED_SINCE"); if_unmod = s->info.env->get("HTTP_IF_UNMODIFIED_SINCE"); if_match = s->info.env->get("HTTP_IF_MATCH"); if_nomatch = s->info.env->get("HTTP_IF_NONE_MATCH"); return 0; } int RESTArgs::get_string(struct req_state *s, const string& name, const string& def_val, string *val, bool *existed) { bool exists; *val = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } return 0; } int RESTArgs::get_uint64(struct req_state *s, const string& name, uint64_t def_val, uint64_t *val, bool *existed) { bool exists; string sval = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } int r = stringtoull(sval, val); if (r < 0) return r; return 0; } int RESTArgs::get_int64(struct req_state *s, const string& name, int64_t def_val, int64_t *val, bool *existed) { bool exists; string sval = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } int r = stringtoll(sval, val); if (r < 0) return r; return 0; } int RESTArgs::get_uint32(struct req_state *s, const string& name, uint32_t def_val, uint32_t *val, bool *existed) { bool exists; string sval = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } int r = stringtoul(sval, val); if (r < 0) return r; return 0; } int RESTArgs::get_int32(struct req_state *s, const string& name, int32_t def_val, int32_t *val, bool *existed) { bool exists; string sval = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } int r = stringtol(sval, val); if (r < 0) return r; return 0; } int RESTArgs::get_time(struct req_state *s, const string& name, const utime_t& def_val, utime_t *val, bool *existed) { bool exists; string sval = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } uint64_t epoch, nsec; int r = utime_t::parse_date(sval, &epoch, &nsec); if (r < 0) return r; *val = utime_t(epoch, nsec); return 0; } int RESTArgs::get_epoch(struct req_state *s, const string& name, uint64_t def_val, uint64_t *epoch, bool *existed) { bool exists; string date = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *epoch = def_val; return 0; } int r = utime_t::parse_date(date, epoch, NULL); if (r < 0) return r; return 0; } int RESTArgs::get_bool(struct req_state *s, const string& name, bool def_val, bool *val, bool *existed) { bool exists; string sval = s->info.args.get(name, &exists); if (existed) *existed = exists; if (!exists) { *val = def_val; return 0; } const char *str = sval.c_str(); if (sval.empty() || strcasecmp(str, "true") == 0 || sval.compare("1") == 0) { *val = true; return 0; } if (strcasecmp(str, "false") != 0 && sval.compare("0") != 0) { *val = def_val; return -EINVAL; } *val = false; return 0; } void RGWRESTFlusher::do_start(int ret) { set_req_state_err(s, ret); /* no going back from here */ dump_errno(s); dump_start(s); end_header(s, op); rgw_flush_formatter_and_reset(s, s->formatter); } void RGWRESTFlusher::do_flush() { rgw_flush_formatter(s, s->formatter); } int RGWPutObj_ObjStore::verify_params() { if (s->length) { off_t len = atoll(s->length); if (len > (off_t)RGW_MAX_PUT_SIZE) { return -ERR_TOO_LARGE; } } return 0; } int RGWPutObj_ObjStore::get_params() { supplied_md5_b64 = s->info.env->get("HTTP_CONTENT_MD5"); return 0; } int RGWPutObj_ObjStore::get_data(bufferlist& bl) { size_t cl; uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size; if (s->length) { cl = atoll(s->length) - ofs; if (cl > chunk_size) cl = chunk_size; } else { cl = chunk_size; } int len = 0; if (cl) { bufferptr bp(cl); int read_len; /* cio->read() expects int * */ int r = s->cio->read(bp.c_str(), cl, &read_len); len = read_len; if (r < 0) return r; bl.append(bp, 0, len); } if ((uint64_t)ofs + len > RGW_MAX_PUT_SIZE) { return -ERR_TOO_LARGE; } if (!ofs) supplied_md5_b64 = s->info.env->get("HTTP_CONTENT_MD5"); return len; } int RGWPostObj_ObjStore::verify_params() { /* check that we have enough memory to store the object note that this test isn't exact and may fail unintentionally for large requests is */ if (!s->length) { return -ERR_LENGTH_REQUIRED; } off_t len = atoll(s->length); if (len > (off_t)RGW_MAX_PUT_SIZE) { return -ERR_TOO_LARGE; } return 0; } int RGWPutACLs_ObjStore::get_params() { size_t cl = 0; if (s->length) cl = atoll(s->length); if (cl) { data = (char *)malloc(cl + 1); if (!data) { ret = -ENOMEM; return ret; } int read_len; int r = s->cio->read(data, cl, &read_len); len = read_len; if (r < 0) return r; data[len] = '\0'; } else { len = 0; } return ret; } static int read_all_chunked_input(req_state *s, char **pdata, int *plen, int max_read) { #define READ_CHUNK 4096 #define MAX_READ_CHUNK (128 * 1024) int need_to_read = READ_CHUNK; int total = need_to_read; char *data = (char *)malloc(total + 1); if (!data) return -ENOMEM; int read_len = 0, len = 0; do { int r = s->cio->read(data + len, need_to_read, &read_len); if (r < 0) { free(data); return r; } len += read_len; if (read_len == need_to_read) { if (need_to_read < MAX_READ_CHUNK) need_to_read *= 2; if (total > max_read) { free(data); return -ERANGE; } total += need_to_read; void *p = realloc(data, total + 1); if (!p) { free(data); return -ENOMEM; } data = (char *)p; } else { break; } } while (true); data[len] = '\0'; *pdata = data; *plen = len; return 0; } int rgw_rest_read_all_input(struct req_state *s, char **pdata, int *plen, int max_len) { size_t cl = 0; int len = 0; char *data = NULL; if (s->length) cl = atoll(s->length); if (cl) { if (cl > (size_t)max_len) { return -ERANGE; } data = (char *)malloc(cl + 1); if (!data) { return -ENOMEM; } int ret = s->cio->read(data, cl, &len); if (ret < 0) { free(data); return ret; } data[len] = '\0'; } else if (!s->length) { const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING"); if (!encoding || strcmp(encoding, "chunked") != 0) return -ERR_LENGTH_REQUIRED; int ret = read_all_chunked_input(s, &data, &len, max_len); if (ret < 0) return ret; } *plen = len; *pdata = data; return 0; } int RGWCompleteMultipart_ObjStore::get_params() { upload_id = s->info.args.get("uploadId"); if (upload_id.empty()) { ret = -ENOTSUP; return ret; } #define COMPLETE_MULTIPART_MAX_LEN (1024 * 1024) /* api defines max 10,000 parts, this should be enough */ ret = rgw_rest_read_all_input(s, &data, &len, COMPLETE_MULTIPART_MAX_LEN); if (ret < 0) return ret; return 0; } int RGWListMultipart_ObjStore::get_params() { upload_id = s->info.args.get("uploadId"); if (upload_id.empty()) { ret = -ENOTSUP; } string marker_str = s->info.args.get("part-number-marker"); if (!marker_str.empty()) { string err; marker = strict_strtol(marker_str.c_str(), 10, &err); if (!err.empty()) { ldout(s->cct, 20) << "bad marker: " << marker << dendl; ret = -EINVAL; return ret; } } string str = s->info.args.get("max-parts"); if (!str.empty()) max_parts = atoi(str.c_str()); return ret; } int RGWListBucketMultiparts_ObjStore::get_params() { delimiter = s->info.args.get("delimiter"); prefix = s->info.args.get("prefix"); string str = s->info.args.get("max-parts"); if (!str.empty()) max_uploads = atoi(str.c_str()); else max_uploads = default_max; string key_marker = s->info.args.get("key-marker"); string upload_id_marker = s->info.args.get("upload-id-marker"); if (!key_marker.empty()) marker.init(key_marker, upload_id_marker); return 0; } int RGWDeleteMultiObj_ObjStore::get_params() { bucket_name = s->bucket_name_str; if (bucket_name.empty()) { ret = -EINVAL; return ret; } // everything is probably fine, set the bucket bucket = s->bucket; size_t cl = 0; if (s->length) cl = atoll(s->length); if (cl) { data = (char *)malloc(cl + 1); if (!data) { ret = -ENOMEM; return ret; } int read_len; ret = s->cio->read(data, cl, &read_len); len = read_len; if (ret < 0) return ret; data[len] = '\0'; } else { return -EINVAL; } return ret; } void RGWRESTOp::send_response() { if (!flusher.did_start()) { set_req_state_err(s, http_ret); dump_errno(s); end_header(s, this); } flusher.flush(); } int RGWRESTOp::verify_permission() { return check_caps(s->user.caps); } int RGWHandler_ObjStore::allocate_formatter(struct req_state *s, int default_type, bool configurable) { s->format = default_type; if (configurable) { string format_str = s->info.args.get("format"); if (format_str.compare("xml") == 0) { s->format = RGW_FORMAT_XML; } else if (format_str.compare("json") == 0) { s->format = RGW_FORMAT_JSON; } } switch (s->format) { case RGW_FORMAT_PLAIN: s->formatter = new RGWFormatter_Plain; break; case RGW_FORMAT_XML: s->formatter = new XMLFormatter(false); break; case RGW_FORMAT_JSON: s->formatter = new JSONFormatter(false); break; default: return -EINVAL; }; s->formatter->reset(); return 0; } // This function enforces Amazon's spec for bucket names. // (The requirements, not the recommendations.) int RGWHandler_ObjStore::validate_bucket_name(const string& bucket) { int len = bucket.size(); if (len < 3) { if (len == 0) { // This request doesn't specify a bucket at all return 0; } // Name too short return -ERR_INVALID_BUCKET_NAME; } else if (len > 255) { // Name too long return -ERR_INVALID_BUCKET_NAME; } return 0; } // "The name for a key is a sequence of Unicode characters whose UTF-8 encoding // is at most 1024 bytes long." // However, we can still have control characters and other nasties in there. // Just as long as they're utf-8 nasties. int RGWHandler_ObjStore::validate_object_name(const string& object) { int len = object.size(); if (len > 1024) { // Name too long return -ERR_INVALID_OBJECT_NAME; } if (check_utf8(object.c_str(), len)) { // Object names must be valid UTF-8. return -ERR_INVALID_OBJECT_NAME; } return 0; } static http_op op_from_method(const char *method) { if (!method) return OP_UNKNOWN; if (strcmp(method, "GET") == 0) return OP_GET; if (strcmp(method, "PUT") == 0) return OP_PUT; if (strcmp(method, "DELETE") == 0) return OP_DELETE; if (strcmp(method, "HEAD") == 0) return OP_HEAD; if (strcmp(method, "POST") == 0) return OP_POST; if (strcmp(method, "COPY") == 0) return OP_COPY; if (strcmp(method, "OPTIONS") == 0) return OP_OPTIONS; return OP_UNKNOWN; } int RGWHandler_ObjStore::read_permissions(RGWOp *op_obj) { bool only_bucket; switch (s->op) { case OP_HEAD: case OP_GET: only_bucket = false; break; case OP_PUT: case OP_POST: case OP_COPY: /* is it a 'multi-object delete' request? */ if (s->info.request_params == "delete") { only_bucket = true; break; } if (is_obj_update_op()) { only_bucket = false; break; } /* is it a 'create bucket' request? */ if ((s->op == OP_PUT) && s->object_str.size() == 0) return 0; only_bucket = true; break; case OP_DELETE: only_bucket = true; break; case OP_OPTIONS: only_bucket = true; break; default: return -EINVAL; } return do_read_permissions(op_obj, only_bucket); } void RGWRESTMgr::register_resource(string resource, RGWRESTMgr *mgr) { string r = "/"; r.append(resource); /* do we have a resource manager registered for this entry point? */ map::iterator iter = resource_mgrs.find(r); if (iter != resource_mgrs.end()) { delete iter->second; } resource_mgrs[r] = mgr; resources_by_size.insert(pair(r.size(), r)); /* now build default resource managers for the path (instead of nested entry points) * e.g., if the entry point is /auth/v1.0/ then we'd want to create a default * manager for /auth/ */ size_t pos = r.find('/', 1); while (pos != r.size() - 1 && pos != string::npos) { string s = r.substr(0, pos); iter = resource_mgrs.find(s); if (iter == resource_mgrs.end()) { /* only register it if one does not exist */ resource_mgrs[s] = new RGWRESTMgr; /* a default do-nothing manager */ resources_by_size.insert(pair(s.size(), s)); } pos = r.find('/', pos + 1); } } void RGWRESTMgr::register_default_mgr(RGWRESTMgr *mgr) { delete default_mgr; default_mgr = mgr; } RGWRESTMgr *RGWRESTMgr::get_resource_mgr(struct req_state *s, const string& uri, string *out_uri) { *out_uri = uri; if (resources_by_size.empty()) return this; multimap::reverse_iterator iter; for (iter = resources_by_size.rbegin(); iter != resources_by_size.rend(); ++iter) { string& resource = iter->second; if (uri.compare(0, iter->first, resource) == 0 && (uri.size() == iter->first || uri[iter->first] == '/')) { string suffix = uri.substr(iter->first); return resource_mgrs[resource]->get_resource_mgr(s, suffix, out_uri); } } if (default_mgr) return default_mgr; return this; } RGWRESTMgr::~RGWRESTMgr() { map::iterator iter; for (iter = resource_mgrs.begin(); iter != resource_mgrs.end(); ++iter) { delete iter->second; } delete default_mgr; } int RGWREST::preprocess(struct req_state *s, RGWClientIO *cio) { req_info& info = s->info; s->cio = cio; if (g_conf->rgw_dns_name.length() && info.host) { string h(s->info.host); ldout(s->cct, 10) << "host=" << s->info.host << " rgw_dns_name=" << g_conf->rgw_dns_name << dendl; int pos = h.find(g_conf->rgw_dns_name); if (g_conf->rgw_resolve_cname && pos < 0) { string cname; bool found; int r = rgw_resolver->resolve_cname(h, cname, &found); if (r < 0) { dout(0) << "WARNING: rgw_resolver->resolve_cname() returned r=" << r << dendl; } if (found) { dout(0) << "resolved host cname " << h << " -> " << cname << dendl; h = cname; pos = h.find(g_conf->rgw_dns_name); } } if (pos > 0 && h[pos - 1] == '.') { string encoded_bucket = "/"; encoded_bucket.append(h.substr(0, pos-1)); if (s->info.request_uri[0] != '/') encoded_bucket.append("/'"); encoded_bucket.append(s->info.request_uri); s->info.request_uri = encoded_bucket; } } url_decode(s->info.request_uri, s->decoded_uri); s->length = info.env->get("CONTENT_LENGTH"); if (s->length) { if (*s->length == '\0') { s->content_length = 0; } else { string err; s->content_length = strict_strtoll(s->length, 10, &err); if (!err.empty()) { ldout(s->cct, 10) << "bad content length, aborting" << dendl; return -EINVAL; } } } if (s->content_length < 0) { ldout(s->cct, 10) << "negative content length, aborting" << dendl; return -EINVAL; } map::iterator giter; for (giter = generic_attrs_map.begin(); giter != generic_attrs_map.end(); ++giter) { const char *env = info.env->get(giter->first.c_str()); if (env) { s->generic_attrs[giter->second] = env; } } s->http_auth = info.env->get("HTTP_AUTHORIZATION"); if (g_conf->rgw_print_continue) { const char *expect = info.env->get("HTTP_EXPECT"); s->expect_cont = (expect && !strcasecmp(expect, "100-continue")); } s->op = op_from_method(info.method); info.init_meta_info(&s->has_bad_meta); return 0; } RGWHandler *RGWREST::get_handler(RGWRados *store, struct req_state *s, RGWClientIO *cio, RGWRESTMgr **pmgr, int *init_error) { RGWHandler *handler; *init_error = preprocess(s, cio); if (*init_error < 0) return NULL; RGWRESTMgr *m = mgr.get_resource_mgr(s, s->decoded_uri, &s->relative_uri); if (!m) { *init_error = -ERR_METHOD_NOT_ALLOWED; return NULL; } if (pmgr) *pmgr = m; handler = m->get_handler(s); if (!handler) { *init_error = -ERR_METHOD_NOT_ALLOWED; return NULL; } *init_error = handler->init(store, s, cio); if (*init_error < 0) { m->put_handler(handler); return NULL; } return handler; } ceph-0.80.11/src/rgw/rgw_cors.cc0000664000175100017510000001215712623076744020425 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "include/types.h" #include "common/debug.h" #include "include/str_list.h" #include "common/Formatter.h" #include "rgw_cors.h" #define dout_subsys ceph_subsys_rgw using namespace std; void RGWCORSRule::dump_origins() { unsigned num_origins = allowed_origins.size(); dout(10) << "Allowed origins : " << num_origins << dendl; for(set::iterator it = allowed_origins.begin(); it != allowed_origins.end(); ++it) { dout(10) << *it << "," << dendl; } } void RGWCORSRule::erase_origin_if_present(string& origin, bool *rule_empty) { set::iterator it = allowed_origins.find(origin); if (!rule_empty) return; *rule_empty = false; if (it != allowed_origins.end()) { dout(10) << "Found origin " << origin << ", set size:" << allowed_origins.size() << dendl; allowed_origins.erase(it); *rule_empty = (allowed_origins.empty()); } } /* * make attrs look-like-this * does not convert underscores or dashes * * Per CORS specification, section 3: * === * "Converting a string to ASCII lowercase" means replacing all characters in the * range U+0041 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z with * the corresponding characters in the range U+0061 LATIN SMALL LETTER A to * U+007A LATIN SMALL LETTER Z). * === * * @todo When UTF-8 is allowed in HTTP headers, this function will need to change */ string lowercase_http_attr(const string& orig) { const char *s = orig.c_str(); char buf[orig.size() + 1]; buf[orig.size()] = '\0'; for (size_t i = 0; i < orig.size(); ++i, ++s) { buf[i] = tolower(*s); } return string(buf); } static bool is_string_in_set(set& s, string h) { if ((s.find("*") != s.end()) || (s.find(h) != s.end())) { return true; } /* The header can be Content-*-type, or Content-* */ for(set::iterator it = s.begin(); it != s.end(); ++it) { size_t off; if ((off = (*it).find("*"))!=string::npos) { list ssplit; unsigned flen = 0; get_str_list((*it), "* \t", ssplit); if (off != 0) { string sl = ssplit.front(); flen = sl.length(); dout(10) << "Finding " << sl << ", in " << h << ", at offset 0" << dendl; if (!boost::algorithm::starts_with(h,sl)) continue; ssplit.pop_front(); } if (off != ((*it).length() - 1)) { string sl = ssplit.front(); dout(10) << "Finding " << sl << ", in " << h << ", at offset not less than " << flen << dendl; if (h.compare((h.size() - sl.size()), sl.size(), sl) != 0) continue; ssplit.pop_front(); } if (!ssplit.empty()) continue; return true; } } return false; } bool RGWCORSRule::is_origin_present(const char *o) { string origin = o; return is_string_in_set(allowed_origins, origin); } bool RGWCORSRule::is_header_allowed(const char *h, size_t len) { string hdr(h, len); if(lowercase_allowed_hdrs.empty()) { set::iterator iter; for (iter = allowed_hdrs.begin(); iter != allowed_hdrs.end(); ++iter) { lowercase_allowed_hdrs.insert(lowercase_http_attr(*iter)); } } return is_string_in_set(lowercase_allowed_hdrs, lowercase_http_attr(hdr)); } void RGWCORSRule::format_exp_headers(string& s) { s = ""; for(list::iterator it = exposable_hdrs.begin(); it != exposable_hdrs.end(); ++it) { if (s.length() > 0) s.append(","); s.append((*it)); } } RGWCORSRule * RGWCORSConfiguration::host_name_rule(const char *origin) { for(list::iterator it_r = rules.begin(); it_r != rules.end(); ++it_r) { RGWCORSRule& r = (*it_r); if (r.is_origin_present(origin)) return &r; } return NULL; } void RGWCORSConfiguration::erase_host_name_rule(string& origin) { bool rule_empty; unsigned loop = 0; /*Erase the host name from that rule*/ dout(10) << "Num of rules : " << rules.size() << dendl; for(list::iterator it_r = rules.begin(); it_r != rules.end(); ++it_r, loop++) { RGWCORSRule& r = (*it_r); r.erase_origin_if_present(origin, &rule_empty); dout(10) << "Origin:" << origin << ", rule num:" << loop << ", emptying now:" << rule_empty << dendl; if (rule_empty) { rules.erase(it_r); break; } } } void RGWCORSConfiguration::dump() { unsigned loop = 1; unsigned num_rules = rules.size(); dout(10) << "Number of rules: " << num_rules << dendl; for(list::iterator it = rules.begin(); it!= rules.end(); ++it, loop++) { dout(10) << " <<<<<<< Rule " << loop << " >>>>>>> " << dendl; (*it).dump_origins(); } } ceph-0.80.11/src/rgw/rgw_acl_swift.h0000664000175100017510000000115612623076744021271 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_ACL_SWIFT_H #define CEPH_RGW_ACL_SWIFT3_H #include #include #include #include #include #include "rgw_acl.h" using namespace std; class RGWAccessControlPolicy_SWIFT : public RGWAccessControlPolicy { public: RGWAccessControlPolicy_SWIFT(CephContext *_cct) : RGWAccessControlPolicy(_cct) {} ~RGWAccessControlPolicy_SWIFT() {} void add_grants(RGWRados *store, vector& uids, int perm); bool create(RGWRados *store, string& id, string& name, string& read_list, string& write_list); void to_str(string& read, string& write); }; #endif ceph-0.80.11/src/rgw/rgw_civetweb_log.h0000664000175100017510000000023312623076744021762 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_CIVETWEB_LOG_H #define CEPH_RGW_CIVETWEB_LOG_H int rgw_civetweb_log_callback(const struct mg_connection *conn, const char *buf); #endif ceph-0.80.11/src/rgw/rgw_cache.h0000664000175100017510000003764612623076744020376 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGWCACHE_H #define CEPH_RGWCACHE_H #include "rgw_rados.h" #include #include #include "include/types.h" #include "include/utime.h" #include "include/assert.h" #include "common/RWLock.h" enum { UPDATE_OBJ, REMOVE_OBJ, }; #define CACHE_FLAG_DATA 0x01 #define CACHE_FLAG_XATTRS 0x02 #define CACHE_FLAG_META 0x04 #define CACHE_FLAG_MODIFY_XATTRS 0x08 #define CACHE_FLAG_OBJV 0x10 #define mydout(v) lsubdout(T::cct, rgw, v) struct ObjectMetaInfo { uint64_t size; time_t mtime; ObjectMetaInfo() : size(0), mtime(0) {} void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(size, bl); utime_t t(mtime, 0); ::encode(t, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(size, bl); utime_t t; ::decode(t, bl); mtime = t.sec(); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ObjectMetaInfo) struct ObjectCacheInfo { int status; uint32_t flags; uint64_t epoch; bufferlist data; map xattrs; map rm_xattrs; ObjectMetaInfo meta; obj_version version; ObjectCacheInfo() : status(0), flags(0), epoch(0), version() {} void encode(bufferlist& bl) const { ENCODE_START(5, 3, bl); ::encode(status, bl); ::encode(flags, bl); ::encode(data, bl); ::encode(xattrs, bl); ::encode(meta, bl); ::encode(rm_xattrs, bl); ::encode(epoch, bl); ::encode(version, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl); ::decode(status, bl); ::decode(flags, bl); ::decode(data, bl); ::decode(xattrs, bl); ::decode(meta, bl); if (struct_v >= 2) ::decode(rm_xattrs, bl); if (struct_v >= 4) ::decode(epoch, bl); if (struct_v >= 5) ::decode(version, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ObjectCacheInfo) struct RGWCacheNotifyInfo { uint32_t op; rgw_obj obj; ObjectCacheInfo obj_info; off_t ofs; string ns; RGWCacheNotifyInfo() : op(0), ofs(0) {} void encode(bufferlist& obl) const { ENCODE_START(2, 2, obl); ::encode(op, obl); ::encode(obj, obl); ::encode(obj_info, obl); ::encode(ofs, obl); ::encode(ns, obl); ENCODE_FINISH(obl); } void decode(bufferlist::iterator& ibl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, ibl); ::decode(op, ibl); ::decode(obj, ibl); ::decode(obj_info, ibl); ::decode(ofs, ibl); ::decode(ns, ibl); DECODE_FINISH(ibl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(RGWCacheNotifyInfo) struct ObjectCacheEntry { ObjectCacheInfo info; std::list::iterator lru_iter; uint64_t lru_promotion_ts; ObjectCacheEntry() : lru_promotion_ts(0) {} }; class ObjectCache { std::map cache_map; std::list lru; unsigned long lru_size; unsigned long lru_counter; unsigned long lru_window; RWLock lock; CephContext *cct; void touch_lru(string& name, ObjectCacheEntry& entry, std::list::iterator& lru_iter); void remove_lru(string& name, std::list::iterator& lru_iter); public: ObjectCache() : lru_size(0), lru_counter(0), lru_window(0), lock("ObjectCache"), cct(NULL) { } int get(std::string& name, ObjectCacheInfo& bl, uint32_t mask); void put(std::string& name, ObjectCacheInfo& bl); void remove(std::string& name); void set_ctx(CephContext *_cct) { cct = _cct; lru_window = cct->_conf->rgw_cache_lru_size / 2; } }; template class RGWCache : public T { ObjectCache cache; int list_objects_raw_init(rgw_bucket& bucket, RGWAccessHandle *handle) { return T::list_objects_raw_init(bucket, handle); } int list_objects_raw_next(RGWObjEnt& obj, RGWAccessHandle *handle) { return T::list_objects_raw_next(obj, handle); } string normal_name(rgw_bucket& bucket, std::string& oid) { string& bucket_name = bucket.name; char buf[bucket_name.size() + 1 + oid.size() + 1]; const char *bucket_str = bucket_name.c_str(); const char *oid_str = oid.c_str(); sprintf(buf, "%s+%s", bucket_str, oid_str); return string(buf); } void normalize_bucket_and_obj(rgw_bucket& src_bucket, string& src_obj, rgw_bucket& dst_bucket, string& dst_obj); string normal_name(rgw_obj& obj) { return normal_name(obj.bucket, obj.object); } int init_rados() { int ret; cache.set_ctx(T::cct); ret = T::init_rados(); if (ret < 0) return ret; return 0; } bool need_watch_notify() { return true; } int distribute_cache(const string& normal_name, rgw_obj& obj, ObjectCacheInfo& obj_info, int op); int watch_cb(int opcode, uint64_t ver, bufferlist& bl); public: RGWCache() {} int set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl, RGWObjVersionTracker *objv_tracker); int set_attrs(void *ctx, rgw_obj& obj, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker); int put_obj_meta_impl(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, int flags, map* rmattrs, const bufferlist *data, RGWObjManifest *manifest, const string *ptag, list *remove_objs, bool modify_version, RGWObjVersionTracker *objv_tracker, time_t set_mtime, const string& owner); int put_obj_data(void *ctx, rgw_obj& obj, const char *data, off_t ofs, size_t len, bool exclusive); int get_obj(void *ctx, RGWObjVersionTracker *objv_tracker, void **handle, rgw_obj& obj, bufferlist& bl, off_t ofs, off_t end); int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, uint64_t *epoch, map *attrs, bufferlist *first_chunk, RGWObjVersionTracker *objv_tracker); int delete_obj_impl(void *ctx, const string& bucket_owner, rgw_obj& obj, RGWObjVersionTracker *objv_tracker); }; template void RGWCache::normalize_bucket_and_obj(rgw_bucket& src_bucket, string& src_obj, rgw_bucket& dst_bucket, string& dst_obj) { if (src_obj.size()) { dst_bucket = src_bucket; dst_obj = src_obj; } else { dst_bucket = T::zone.domain_root; dst_obj = src_bucket.name; } } template int RGWCache::delete_obj_impl(void *ctx, const string& bucket_owner, rgw_obj& obj, RGWObjVersionTracker *objv_tracker) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); if (bucket.name[0] != '.') return T::delete_obj_impl(ctx, bucket_owner, obj, objv_tracker); string name = normal_name(obj); cache.remove(name); ObjectCacheInfo info; distribute_cache(name, obj, info, REMOVE_OBJ); return T::delete_obj_impl(ctx, bucket_owner, obj, objv_tracker); } template int RGWCache::get_obj(void *ctx, RGWObjVersionTracker *objv_tracker, void **handle, rgw_obj& obj, bufferlist& obl, off_t ofs, off_t end) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); if (bucket.name[0] != '.' || ofs != 0) return T::get_obj(ctx, objv_tracker, handle, obj, obl, ofs, end); string name = normal_name(obj.bucket, oid); ObjectCacheInfo info; uint32_t flags = CACHE_FLAG_DATA; if (objv_tracker) flags |= CACHE_FLAG_OBJV; if (cache.get(name, info, flags) == 0) { if (info.status < 0) return info.status; bufferlist& bl = info.data; bufferlist::iterator i = bl.begin(); obl.clear(); i.copy_all(obl); if (objv_tracker) objv_tracker->read_version = info.version; return bl.length(); } int r = T::get_obj(ctx, objv_tracker, handle, obj, obl, ofs, end); if (r < 0) { if (r == -ENOENT) { // only update ENOENT, we'd rather retry other errors info.status = r; cache.put(name, info); } return r; } if (obl.length() == end + 1) { /* in this case, most likely object contains more data, we can't cache it */ return r; } bufferptr p(r); bufferlist& bl = info.data; bl.clear(); bufferlist::iterator o = obl.begin(); o.copy_all(bl); info.status = 0; info.flags = flags; if (objv_tracker) { info.version = objv_tracker->read_version; } cache.put(name, info); return r; } template int RGWCache::set_attr(void *ctx, rgw_obj& obj, const char *attr_name, bufferlist& bl, RGWObjVersionTracker *objv_tracker) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); ObjectCacheInfo info; bool cacheable = false; if (bucket.name[0] == '.') { cacheable = true; info.xattrs[attr_name] = bl; info.status = 0; info.flags = CACHE_FLAG_MODIFY_XATTRS; if (objv_tracker) { info.version = objv_tracker->write_version; info.flags |= CACHE_FLAG_OBJV; } } int ret = T::set_attr(ctx, obj, attr_name, bl, objv_tracker); if (cacheable) { string name = normal_name(bucket, oid); if (ret >= 0) { cache.put(name, info); int r = distribute_cache(name, obj, info, UPDATE_OBJ); if (r < 0) mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl; } else { cache.remove(name); } } return ret; } template int RGWCache::set_attrs(void *ctx, rgw_obj& obj, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); ObjectCacheInfo info; bool cacheable = false; if (bucket.name[0] == '.') { cacheable = true; info.xattrs = attrs; if (rmattrs) info.rm_xattrs = *rmattrs; info.status = 0; info.flags = CACHE_FLAG_MODIFY_XATTRS; if (objv_tracker) { info.version = objv_tracker->write_version; info.flags |= CACHE_FLAG_OBJV; } } int ret = T::set_attrs(ctx, obj, attrs, rmattrs, objv_tracker); if (cacheable) { string name = normal_name(bucket, oid); if (ret >= 0) { cache.put(name, info); int r = distribute_cache(name, obj, info, UPDATE_OBJ); if (r < 0) mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl; } else { cache.remove(name); } } return ret; } template int RGWCache::put_obj_meta_impl(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, int flags, map* rmattrs, const bufferlist *data, RGWObjManifest *manifest, const string *ptag, list *remove_objs, bool modify_version, RGWObjVersionTracker *objv_tracker, time_t set_mtime, const string& owner) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); ObjectCacheInfo info; bool cacheable = false; if (bucket.name[0] == '.') { cacheable = true; info.xattrs = attrs; info.status = 0; info.flags = CACHE_FLAG_XATTRS; if (data) { info.data = *data; info.flags |= CACHE_FLAG_DATA; } if (objv_tracker) { info.version = objv_tracker->write_version; info.flags |= CACHE_FLAG_OBJV; } } int ret = T::put_obj_meta_impl(ctx, obj, size, mtime, attrs, category, flags, rmattrs, data, manifest, ptag, remove_objs, modify_version, objv_tracker, set_mtime, owner); if (cacheable) { string name = normal_name(bucket, oid); if (ret >= 0) { cache.put(name, info); int r = distribute_cache(name, obj, info, UPDATE_OBJ); if (r < 0) mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl; } else { cache.remove(name); } } return ret; } template int RGWCache::put_obj_data(void *ctx, rgw_obj& obj, const char *data, off_t ofs, size_t len, bool exclusive) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); ObjectCacheInfo info; bool cacheable = false; if ((bucket.name[0] == '.') && ((ofs == 0) || (ofs == -1))) { cacheable = true; bufferptr p(len); memcpy(p.c_str(), data, len); bufferlist& bl = info.data; bl.append(p); info.meta.size = bl.length(); info.status = 0; info.flags = CACHE_FLAG_DATA; } int ret = T::put_obj_data(ctx, obj, data, ofs, len, exclusive); if (cacheable) { string name = normal_name(bucket, oid); if (ret >= 0) { cache.put(name, info); int r = distribute_cache(name, obj, info, UPDATE_OBJ); if (r < 0) mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl; } else { cache.remove(name); } } return ret; } template int RGWCache::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, uint64_t *pepoch, map *attrs, bufferlist *first_chunk, RGWObjVersionTracker *objv_tracker) { rgw_bucket bucket; string oid; normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); if (bucket.name[0] != '.') return T::obj_stat(ctx, obj, psize, pmtime, pepoch, attrs, first_chunk, objv_tracker); string name = normal_name(bucket, oid); uint64_t size; time_t mtime; uint64_t epoch; ObjectCacheInfo info; uint32_t flags = CACHE_FLAG_META | CACHE_FLAG_XATTRS; if (objv_tracker) flags |= CACHE_FLAG_OBJV; int r = cache.get(name, info, flags); if (r == 0) { if (info.status < 0) return info.status; size = info.meta.size; mtime = info.meta.mtime; epoch = info.epoch; if (objv_tracker) objv_tracker->read_version = info.version; goto done; } r = T::obj_stat(ctx, obj, &size, &mtime, &epoch, &info.xattrs, first_chunk, objv_tracker); if (r < 0) { if (r == -ENOENT) { info.status = r; cache.put(name, info); } return r; } info.status = 0; info.epoch = epoch; info.meta.mtime = mtime; info.meta.size = size; info.flags = CACHE_FLAG_META | CACHE_FLAG_XATTRS; if (objv_tracker) { info.flags |= CACHE_FLAG_OBJV; info.version = objv_tracker->read_version; } cache.put(name, info); done: if (psize) *psize = size; if (pmtime) *pmtime = mtime; if (pepoch) *pepoch = epoch; if (attrs) *attrs = info.xattrs; return 0; } template int RGWCache::distribute_cache(const string& normal_name, rgw_obj& obj, ObjectCacheInfo& obj_info, int op) { RGWCacheNotifyInfo info; info.op = op; info.obj_info = obj_info; info.obj = obj; bufferlist bl; ::encode(info, bl); int ret = T::distribute(normal_name, bl); return ret; } template int RGWCache::watch_cb(int opcode, uint64_t ver, bufferlist& bl) { RGWCacheNotifyInfo info; try { bufferlist::iterator iter = bl.begin(); ::decode(info, iter); } catch (buffer::end_of_buffer& err) { mydout(0) << "ERROR: got bad notification" << dendl; return -EIO; } catch (buffer::error& err) { mydout(0) << "ERROR: buffer::error" << dendl; return -EIO; } rgw_bucket bucket; string oid; normalize_bucket_and_obj(info.obj.bucket, info.obj.object, bucket, oid); string name = normal_name(bucket, oid); switch (info.op) { case UPDATE_OBJ: cache.put(name, info.obj_info); break; case REMOVE_OBJ: cache.remove(name); break; default: mydout(0) << "WARNING: got unknown notification op: " << info.op << dendl; return -EINVAL; } return 0; } #endif ceph-0.80.11/src/rgw/rgw_rados.h0000664000175100017510000017535112623076744020437 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGWRADOS_H #define CEPH_RGWRADOS_H #include "include/rados/librados.hpp" #include "include/Context.h" #include "common/RefCountedObj.h" #include "rgw_common.h" #include "cls/rgw/cls_rgw_types.h" #include "cls/version/cls_version_types.h" #include "cls/log/cls_log_types.h" #include "cls/statelog/cls_statelog_types.h" #include "rgw_log.h" #include "rgw_metadata.h" #include "rgw_rest_conn.h" class RGWWatcher; class SafeTimer; class ACLOwner; class RGWGC; /* flags for put_obj_meta() */ #define PUT_OBJ_CREATE 0x01 #define PUT_OBJ_EXCL 0x02 #define PUT_OBJ_CREATE_EXCL (PUT_OBJ_CREATE | PUT_OBJ_EXCL) #define RGW_OBJ_NS_MULTIPART "multipart" #define RGW_OBJ_NS_SHADOW "shadow" #define RGW_BUCKET_INSTANCE_MD_PREFIX ".bucket.meta." static inline void prepend_bucket_marker(rgw_bucket& bucket, const string& orig_oid, string& oid) { if (bucket.marker.empty() || orig_oid.empty()) { oid = orig_oid; } else { oid = bucket.marker; oid.append("_"); oid.append(orig_oid); } } static inline void get_obj_bucket_and_oid_key(const rgw_obj& obj, rgw_bucket& bucket, string& oid, string& key) { bucket = obj.bucket; prepend_bucket_marker(bucket, obj.object, oid); prepend_bucket_marker(bucket, obj.key, key); } int rgw_policy_from_attrset(CephContext *cct, map& attrset, RGWAccessControlPolicy *policy); struct RGWUsageBatch { map m; void insert(utime_t& t, rgw_usage_log_entry& entry, bool *account) { bool exists = m.find(t) != m.end(); *account = !exists; m[t].aggregate(entry); } }; struct RGWUsageIter { string read_iter; uint32_t index; RGWUsageIter() : index(0) {} }; class RGWGetDataCB { protected: uint64_t extra_data_len; public: virtual int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) = 0; RGWGetDataCB() : extra_data_len(0) {} virtual ~RGWGetDataCB() {} virtual void set_extra_data_len(uint64_t len) { extra_data_len = len; } }; class RGWAccessListFilter { public: virtual ~RGWAccessListFilter() {} virtual bool filter(string& name, string& key) = 0; }; struct RGWCloneRangeInfo { rgw_obj src; off_t src_ofs; off_t dst_ofs; uint64_t len; }; struct RGWObjManifestPart { rgw_obj loc; /* the object where the data is located */ uint64_t loc_ofs; /* the offset at that object where the data is located */ uint64_t size; /* the part size */ RGWObjManifestPart() : loc_ofs(0), size(0) {} void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(loc, bl); ::encode(loc_ofs, bl); ::encode(size, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN_32(2, 2, 2, bl); ::decode(loc, bl); ::decode(loc_ofs, bl); ::decode(size, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(RGWObjManifestPart); /* The manifest defines a set of rules for structuring the object parts. There are a few terms to note: - head: the head part of the object, which is the part that contains the first chunk of data. An object might not have a head (as in the case of multipart-part objects). - stripe: data portion of a single rgw object that resides on a single rados object. - part: a collection of stripes that make a contiguous part of an object. A regular object will only have one part (although might have many stripes), a multipart object might have many parts. Each part has a fixed stripe size, although the last stripe of a part might be smaller than that. Consecutive parts may be merged if their stripe value is the same. */ struct RGWObjManifestRule { uint32_t start_part_num; uint64_t start_ofs; uint64_t part_size; /* each part size, 0 if there's no part size, meaning it's unlimited */ uint64_t stripe_max_size; /* underlying obj max size */ string override_prefix; RGWObjManifestRule() : start_part_num(0), start_ofs(0), part_size(0), stripe_max_size(0) {} RGWObjManifestRule(uint32_t _start_part_num, uint64_t _start_ofs, uint64_t _part_size, uint64_t _stripe_max_size) : start_part_num(_start_part_num), start_ofs(_start_ofs), part_size(_part_size), stripe_max_size(_stripe_max_size) {} void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(start_part_num, bl); ::encode(start_ofs, bl); ::encode(part_size, bl); ::encode(stripe_max_size, bl); ::encode(override_prefix, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(start_part_num, bl); ::decode(start_ofs, bl); ::decode(part_size, bl); ::decode(stripe_max_size, bl); if (struct_v >= 2) ::decode(override_prefix, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; }; WRITE_CLASS_ENCODER(RGWObjManifestRule); class RGWObjManifest { protected: bool explicit_objs; /* old manifest? */ map objs; uint64_t obj_size; rgw_obj head_obj; uint64_t head_size; uint64_t max_head_size; string prefix; rgw_bucket tail_bucket; /* might be different than the original bucket, as object might have been copied across buckets */ map rules; void convert_to_explicit(); int append_explicit(RGWObjManifest& m); void append_rules(RGWObjManifest& m, map::iterator& iter, string *override_prefix); void update_iterators() { begin_iter.seek(0); end_iter.seek(obj_size); } public: RGWObjManifest() : explicit_objs(false), obj_size(0), head_size(0), max_head_size(0), begin_iter(this), end_iter(this) {} RGWObjManifest(const RGWObjManifest& rhs) { *this = rhs; } RGWObjManifest& operator=(const RGWObjManifest& rhs) { explicit_objs = rhs.explicit_objs; objs = rhs.objs; obj_size = rhs.obj_size; head_obj = rhs.head_obj; head_size = rhs.head_size; max_head_size = rhs.max_head_size; prefix = rhs.prefix; tail_bucket = rhs.tail_bucket; rules = rhs.rules; begin_iter.set_manifest(this); end_iter.set_manifest(this); begin_iter.seek(rhs.begin_iter.get_ofs()); end_iter.seek(rhs.end_iter.get_ofs()); return *this; } void set_explicit(uint64_t _size, map& _objs) { explicit_objs = true; obj_size = _size; objs.swap(_objs); } void get_implicit_location(uint64_t cur_part_id, uint64_t cur_stripe, uint64_t ofs, string *override_prefix, rgw_obj *location); void set_trivial_rule(uint64_t tail_ofs, uint64_t stripe_max_size) { RGWObjManifestRule rule(0, tail_ofs, 0, stripe_max_size); rules[0] = rule; max_head_size = tail_ofs; } void set_multipart_part_rule(uint64_t stripe_max_size, uint64_t part_num) { RGWObjManifestRule rule(0, 0, 0, stripe_max_size); rule.start_part_num = part_num; rules[0] = rule; max_head_size = 0; } void encode(bufferlist& bl) const { ENCODE_START(4, 3, bl); ::encode(obj_size, bl); ::encode(objs, bl); ::encode(explicit_objs, bl); ::encode(head_obj, bl); ::encode(head_size, bl); ::encode(max_head_size, bl); ::encode(prefix, bl); ::encode(rules, bl); ::encode(tail_bucket, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN_32(4, 2, 2, bl); ::decode(obj_size, bl); ::decode(objs, bl); if (struct_v >= 3) { ::decode(explicit_objs, bl); ::decode(head_obj, bl); ::decode(head_size, bl); ::decode(max_head_size, bl); ::decode(prefix, bl); ::decode(rules, bl); } else { explicit_objs = true; if (!objs.empty()) { map::iterator iter = objs.begin(); head_obj = iter->second.loc; head_size = iter->second.size; max_head_size = head_size; } } if (struct_v >= 4) { ::decode(tail_bucket, bl); } update_iterators(); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); int append(RGWObjManifest& m); bool get_rule(uint64_t ofs, RGWObjManifestRule *rule); bool empty() { if (explicit_objs) return objs.empty(); return rules.empty(); } bool has_explicit_objs() { return explicit_objs; } bool has_tail() { if (explicit_objs) { if (objs.size() == 1) { map::iterator iter = objs.begin(); rgw_obj& obj = iter->second.loc; return head_obj.object != obj.object; } return (objs.size() >= 2); } return (obj_size > head_size); } void set_head(const rgw_obj& _o) { head_obj = _o; } const rgw_obj& get_head() { return head_obj; } void set_tail_bucket(const rgw_bucket& _b) { tail_bucket = _b; } rgw_bucket& get_tail_bucket() { return tail_bucket; } void set_prefix(const string& _p) { prefix = _p; } const string& get_prefix() { return prefix; } void set_head_size(uint64_t _s) { head_size = _s; } void set_obj_size(uint64_t s) { obj_size = s; update_iterators(); } uint64_t get_obj_size() { return obj_size; } uint64_t get_head_size() { return head_size; } void set_max_head_size(uint64_t s) { max_head_size = s; } uint64_t get_max_head_size() { return max_head_size; } class obj_iterator { RGWObjManifest *manifest; uint64_t part_ofs; /* where current part starts */ uint64_t stripe_ofs; /* where current stripe starts */ uint64_t ofs; /* current position within the object */ uint64_t stripe_size; /* current part size */ int cur_part_id; int cur_stripe; string cur_override_prefix; rgw_obj location; map::iterator rule_iter; map::iterator next_rule_iter; map::iterator explicit_iter; void init() { part_ofs = 0; stripe_ofs = 0; ofs = 0; stripe_size = 0; cur_part_id = 0; cur_stripe = 0; } void update_explicit_pos(); protected: void set_manifest(RGWObjManifest *m) { manifest = m; } public: obj_iterator() : manifest(NULL) { init(); } obj_iterator(RGWObjManifest *_m) : manifest(_m) { init(); seek(0); } obj_iterator(RGWObjManifest *_m, uint64_t _ofs) : manifest(_m) { init(); seek(_ofs); } void seek(uint64_t ofs); void operator++(); bool operator==(const obj_iterator& rhs) { return (ofs == rhs.ofs); } bool operator!=(const obj_iterator& rhs) { return (ofs != rhs.ofs); } const rgw_obj& get_location() { return location; } /* start of current stripe */ uint64_t get_stripe_ofs() { if (manifest->explicit_objs) { return explicit_iter->first; } return stripe_ofs; } /* current ofs relative to start of rgw object */ uint64_t get_ofs() const { return ofs; } /* current stripe size */ uint64_t get_stripe_size() { if (manifest->explicit_objs) { return explicit_iter->second.size; } return stripe_size; } /* offset where data starts within current stripe */ uint64_t location_ofs() { if (manifest->explicit_objs) { return explicit_iter->second.loc_ofs; } return 0; /* all stripes start at zero offset */ } void update_location(); friend class RGWObjManifest; }; const obj_iterator& obj_begin(); const obj_iterator& obj_end(); obj_iterator obj_find(uint64_t ofs); obj_iterator begin_iter; obj_iterator end_iter; /* * simple object generator. Using a simple single rule manifest. */ class generator { RGWObjManifest *manifest; uint64_t last_ofs; uint64_t cur_part_ofs; int cur_part_id; int cur_stripe; uint64_t cur_stripe_size; string cur_oid; string oid_prefix; rgw_obj cur_obj; rgw_bucket bucket; RGWObjManifestRule rule; public: generator() : manifest(NULL), last_ofs(0), cur_part_ofs(0), cur_part_id(0), cur_stripe(0), cur_stripe_size(0) {} int create_begin(CephContext *cct, RGWObjManifest *manifest, rgw_bucket& bucket, rgw_obj& head); int create_next(uint64_t ofs); const rgw_obj& get_cur_obj() { return cur_obj; } /* total max size of current stripe (including head obj) */ uint64_t cur_stripe_max_size() { return cur_stripe_size; } }; }; WRITE_CLASS_ENCODER(RGWObjManifest); struct RGWUploadPartInfo { uint32_t num; uint64_t size; string etag; utime_t modified; RGWObjManifest manifest; RGWUploadPartInfo() : num(0), size(0) {} void encode(bufferlist& bl) const { ENCODE_START(3, 2, bl); ::encode(num, bl); ::encode(size, bl); ::encode(etag, bl); ::encode(modified, bl); ::encode(manifest, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl); ::decode(num, bl); ::decode(size, bl); ::decode(etag, bl); ::decode(modified, bl); if (struct_v >= 3) ::decode(manifest, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(RGWUploadPartInfo) class RGWPutObjProcessor { protected: RGWRados *store; void *obj_ctx; bool is_complete; string bucket_owner; virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) = 0; list objs; void add_obj(const rgw_obj& obj) { objs.push_back(obj); } public: RGWPutObjProcessor(const string& _bo) : store(NULL), obj_ctx(NULL), is_complete(false), bucket_owner(_bo) {} virtual ~RGWPutObjProcessor(); virtual int prepare(RGWRados *_store, void *_o, string *oid_rand) { store = _store; obj_ctx = _o; return 0; }; virtual int handle_data(bufferlist& bl, off_t ofs, MD5 *hash, void **phandle, bool *again) = 0; virtual int throttle_data(void *handle, bool need_to_wait) = 0; virtual void complete_hash(MD5 *hash) { assert(0); } virtual int complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs); CephContext *ctx(); }; class RGWPutObjProcessor_Plain : public RGWPutObjProcessor { rgw_bucket bucket; string obj_str; bufferlist data; rgw_obj obj; off_t ofs; protected: int prepare(RGWRados *store, void *obj_ctx, string *oid_rand); int handle_data(bufferlist& bl, off_t ofs, MD5 *hash /* NULL expected */, void **phandle, bool *again); int do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs); public: int throttle_data(void *handle, bool need_to_wait) { return 0; } RGWPutObjProcessor_Plain(const string& bucket_owner, rgw_bucket& b, const string& o) : RGWPutObjProcessor(bucket_owner), bucket(b), obj_str(o), ofs(0) {} }; struct put_obj_aio_info { void *handle; }; class RGWPutObjProcessor_Aio : public RGWPutObjProcessor { list pending; size_t max_chunks; struct put_obj_aio_info pop_pending(); int wait_pending_front(); bool pending_has_completed(); protected: uint64_t obj_len; int drain_pending(); int handle_obj_data(rgw_obj& obj, bufferlist& bl, off_t ofs, off_t abs_ofs, void **phandle, bool exclusive); public: int throttle_data(void *handle, bool need_to_wait); RGWPutObjProcessor_Aio(const string& bucket_owner) : RGWPutObjProcessor(bucket_owner), max_chunks(RGW_MAX_PENDING_CHUNKS), obj_len(0) {} virtual ~RGWPutObjProcessor_Aio() { drain_pending(); } }; class RGWPutObjProcessor_Atomic : public RGWPutObjProcessor_Aio { bufferlist first_chunk; uint64_t part_size; off_t cur_part_ofs; off_t next_part_ofs; int cur_part_id; off_t data_ofs; uint64_t extra_data_len; bufferlist extra_data_bl; bufferlist pending_data_bl; uint64_t max_chunk_size; protected: rgw_bucket bucket; string obj_str; string unique_tag; rgw_obj head_obj; rgw_obj cur_obj; RGWObjManifest manifest; RGWObjManifest::generator manifest_gen; int write_data(bufferlist& bl, off_t ofs, void **phandle, bool exclusive); virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs); int prepare_next_part(off_t ofs); int complete_parts(); int complete_writing_data(); int prepare_init(RGWRados *store, void *obj_ctx, string *oid_rand); public: ~RGWPutObjProcessor_Atomic() {} RGWPutObjProcessor_Atomic(const string& bucket_owner, rgw_bucket& _b, const string& _o, uint64_t _p, const string& _t) : RGWPutObjProcessor_Aio(bucket_owner), part_size(_p), cur_part_ofs(0), next_part_ofs(_p), cur_part_id(0), data_ofs(0), extra_data_len(0), max_chunk_size(0), bucket(_b), obj_str(_o), unique_tag(_t) {} int prepare(RGWRados *store, void *obj_ctx, string *oid_rand); virtual bool immutable_head() { return false; } void set_extra_data_len(uint64_t len) { extra_data_len = len; } virtual int handle_data(bufferlist& bl, off_t ofs, MD5 *hash, void **phandle, bool *again); virtual void complete_hash(MD5 *hash); bufferlist& get_extra_data() { return extra_data_bl; } }; struct RGWObjState { bool is_atomic; bool has_attrs; bool exists; uint64_t size; time_t mtime; uint64_t epoch; bufferlist obj_tag; string write_tag; bool fake_tag; RGWObjManifest manifest; bool has_manifest; string shadow_obj; bool has_data; bufferlist data; bool prefetch_data; bool keep_tail; RGWObjVersionTracker objv_tracker; map attrset; RGWObjState() : is_atomic(false), has_attrs(0), exists(false), size(0), mtime(0), epoch(0), fake_tag(false), has_manifest(false), has_data(false), prefetch_data(false), keep_tail(false) {} bool get_attr(string name, bufferlist& dest) { map::iterator iter = attrset.find(name); if (iter != attrset.end()) { dest = iter->second; return true; } return false; } void clear() { has_attrs = false; exists = false; fake_tag = false; epoch = 0; size = 0; mtime = 0; obj_tag.clear(); shadow_obj.clear(); attrset.clear(); data.clear(); } }; struct RGWRadosCtx { RGWRados *store; map objs_state; int (*intent_cb)(RGWRados *store, void *user_ctx, rgw_obj& obj, RGWIntentEvent intent); void *user_ctx; RGWRadosCtx(RGWRados *_store) : store(_store), intent_cb(NULL), user_ctx(NULL) { } RGWRadosCtx(RGWRados *_store, void *_user_ctx) : store(_store), intent_cb(NULL), user_ctx(_user_ctx) { } RGWObjState *get_state(rgw_obj& obj); void set_atomic(rgw_obj& obj); void set_prefetch_data(rgw_obj& obj); void set_intent_cb(int (*cb)(RGWRados *store, void *user_ctx, rgw_obj& obj, RGWIntentEvent intent)) { intent_cb = cb; } int notify_intent(RGWRados *store, rgw_obj& obj, RGWIntentEvent intent) { if (intent_cb) { return intent_cb(store, user_ctx, obj, intent); } return 0; } }; struct RGWPoolIterCtx { librados::IoCtx io_ctx; librados::ObjectIterator iter; }; struct RGWListRawObjsCtx { bool initialized; RGWPoolIterCtx iter_ctx; RGWListRawObjsCtx() : initialized(false) {} }; struct RGWRegion; struct RGWZonePlacementInfo { string index_pool; string data_pool; string data_extra_pool; /* if not set we should use data_pool */ void encode(bufferlist& bl) const { ENCODE_START(4, 1, bl); ::encode(index_pool, bl); ::encode(data_pool, bl); ::encode(data_extra_pool, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(4, bl); ::decode(index_pool, bl); ::decode(data_pool, bl); if (struct_v >= 4) { ::decode(data_extra_pool, bl); } DECODE_FINISH(bl); } const string& get_data_extra_pool() { if (data_extra_pool.empty()) { return data_pool; } return data_extra_pool; } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWZonePlacementInfo); struct RGWZoneParams { rgw_bucket domain_root; rgw_bucket control_pool; rgw_bucket gc_pool; rgw_bucket log_pool; rgw_bucket intent_log_pool; rgw_bucket usage_log_pool; rgw_bucket user_keys_pool; rgw_bucket user_email_pool; rgw_bucket user_swift_pool; rgw_bucket user_uid_pool; string name; bool is_master; RGWAccessKey system_key; map placement_pools; RGWZoneParams() : is_master(false) {} static int get_pool_name(CephContext *cct, string *pool_name); void init_name(CephContext *cct, RGWRegion& region); int init(CephContext *cct, RGWRados *store, RGWRegion& region); void init_default(RGWRados *store); int store_info(CephContext *cct, RGWRados *store, RGWRegion& region); void encode(bufferlist& bl) const { ENCODE_START(4, 1, bl); ::encode(domain_root, bl); ::encode(control_pool, bl); ::encode(gc_pool, bl); ::encode(log_pool, bl); ::encode(intent_log_pool, bl); ::encode(usage_log_pool, bl); ::encode(user_keys_pool, bl); ::encode(user_email_pool, bl); ::encode(user_swift_pool, bl); ::encode(user_uid_pool, bl); ::encode(name, bl); ::encode(system_key, bl); ::encode(placement_pools, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(4, bl); ::decode(domain_root, bl); ::decode(control_pool, bl); ::decode(gc_pool, bl); ::decode(log_pool, bl); ::decode(intent_log_pool, bl); ::decode(usage_log_pool, bl); ::decode(user_keys_pool, bl); ::decode(user_email_pool, bl); ::decode(user_swift_pool, bl); ::decode(user_uid_pool, bl); if (struct_v >= 2) ::decode(name, bl); if (struct_v >= 3) ::decode(system_key, bl); if (struct_v >= 4) ::decode(placement_pools, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWZoneParams); struct RGWZone { string name; list endpoints; bool log_meta; bool log_data; RGWZone() : log_meta(false), log_data(false) {} void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(name, bl); ::encode(endpoints, bl); ::encode(log_meta, bl); ::encode(log_data, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(name, bl); ::decode(endpoints, bl); if (struct_v >= 2) { ::decode(log_meta, bl); ::decode(log_data, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWZone); struct RGWDefaultRegionInfo { string default_region; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(default_region, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(default_region, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWDefaultRegionInfo); struct RGWRegionPlacementTarget { string name; list tags; bool user_permitted(list& user_tags) { if (tags.empty()) { return true; } for (list::iterator uiter = user_tags.begin(); uiter != user_tags.end(); ++uiter) { /* we don't expect many of either, so we can handle this kind of lookup */ string& rule = *uiter; for (list::iterator iter = tags.begin(); iter != tags.end(); ++iter) { if (rule == *iter) { return true; } } } return false; } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(name, bl); ::encode(tags, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(name, bl); ::decode(tags, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWRegionPlacementTarget); struct RGWRegion { string name; string api_name; list endpoints; bool is_master; string master_zone; map zones; map placement_targets; string default_placement; CephContext *cct; RGWRados *store; RGWRegion() : is_master(false), cct(NULL), store(NULL) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(name, bl); ::encode(api_name, bl); ::encode(is_master, bl); ::encode(endpoints, bl); ::encode(master_zone, bl); ::encode(zones, bl); ::encode(placement_targets, bl); ::encode(default_placement, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(name, bl); ::decode(api_name, bl); ::decode(is_master, bl); ::decode(endpoints, bl); ::decode(master_zone, bl); ::decode(zones, bl); ::decode(placement_targets, bl); ::decode(default_placement, bl); DECODE_FINISH(bl); } int init(CephContext *_cct, RGWRados *_store, bool setup_region = true); int create_default(); int store_info(bool exclusive); int read_info(const string& region_name); int read_default(RGWDefaultRegionInfo& default_region); int set_as_default(); int equals(const string& other_region); static int get_pool_name(CephContext *cct, string *pool_name); void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWRegion); struct RGWRegionMap { Mutex lock; map regions; map regions_by_api; string master_region; RGWQuotaInfo bucket_quota; RGWQuotaInfo user_quota; RGWRegionMap() : lock("RGWRegionMap") {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void get_params(CephContext *cct, string& pool_name, string& oid); int read(CephContext *cct, RGWRados *store); int store(CephContext *cct, RGWRados *store); int update(RGWRegion& region); void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(RGWRegionMap); class RGWDataChangesLog; class RGWReplicaLogger; class RGWStateLog { RGWRados *store; int num_shards; string module_name; void oid_str(int shard, string& oid); int get_shard_num(const string& object); string get_oid(const string& object); int open_ioctx(librados::IoCtx& ioctx); struct list_state { int cur_shard; int max_shard; string marker; string client_id; string op_id; string object; list_state() : cur_shard(0), max_shard(0) {} }; protected: virtual bool dump_entry_internal(const cls_statelog_entry& entry, Formatter *f) { return false; } public: RGWStateLog(RGWRados *_store, int _num_shards, const string& _module_name) : store(_store), num_shards(_num_shards), module_name(_module_name) {} virtual ~RGWStateLog() {} int store_entry(const string& client_id, const string& op_id, const string& object, uint32_t state, bufferlist *bl, uint32_t *check_state); int remove_entry(const string& client_id, const string& op_id, const string& object); void init_list_entries(const string& client_id, const string& op_id, const string& object, void **handle); int list_entries(void *handle, int max_entries, list& entries, bool *done); void finish_list_entries(void *handle); virtual void dump_entry(const cls_statelog_entry& entry, Formatter *f); }; /* * state transitions: * * unknown -> in-progress -> complete * -> error * * user can try setting the 'abort' state, and it can only succeed if state is * in-progress. * * state renewal cannot switch state (stays in the same state) * * rgw can switch from in-progress to complete * rgw can switch from in-progress to error * * rgw can switch from abort to cancelled * */ class RGWOpState : public RGWStateLog { protected: bool dump_entry_internal(const cls_statelog_entry& entry, Formatter *f); public: enum OpState { OPSTATE_UNKNOWN = 0, OPSTATE_IN_PROGRESS = 1, OPSTATE_COMPLETE = 2, OPSTATE_ERROR = 3, OPSTATE_ABORT = 4, OPSTATE_CANCELLED = 5, }; RGWOpState(RGWRados *_store); int state_from_str(const string& s, OpState *state); int set_state(const string& client_id, const string& op_id, const string& object, OpState state); int renew_state(const string& client_id, const string& op_id, const string& object, OpState state); }; class RGWOpStateSingleOp { RGWOpState os; string client_id; string op_id; string object; CephContext *cct; RGWOpState::OpState cur_state; utime_t last_update; public: RGWOpStateSingleOp(RGWRados *store, const string& cid, const string& oid, const string& obj); int set_state(RGWOpState::OpState state); int renew_state(); }; class RGWGetBucketStats_CB : public RefCountedObject { protected: rgw_bucket bucket; uint64_t bucket_ver; uint64_t master_ver; map *stats; string max_marker; public: RGWGetBucketStats_CB(rgw_bucket& _bucket) : bucket(_bucket), stats(NULL) {} virtual ~RGWGetBucketStats_CB() {} virtual void handle_response(int r) = 0; virtual void set_response(uint64_t _bucket_ver, uint64_t _master_ver, map *_stats, const string &_max_marker) { bucket_ver = _bucket_ver; master_ver = _master_ver; stats = _stats; max_marker = _max_marker; } }; class RGWGetUserStats_CB : public RefCountedObject { protected: string user; RGWStorageStats stats; public: RGWGetUserStats_CB(const string& _user) : user(_user) {} virtual ~RGWGetUserStats_CB() {} virtual void handle_response(int r) = 0; virtual void set_response(RGWStorageStats& _stats) { stats = _stats; } }; class RGWGetDirHeader_CB; class RGWGetUserHeader_CB; struct rgw_rados_ref { string oid; string key; librados::IoCtx ioctx; }; class RGWRados { friend class RGWGC; friend class RGWStateLog; friend class RGWReplicaLogger; /** Open the pool used as root for this gateway */ int open_root_pool_ctx(); int open_gc_pool_ctx(); int open_bucket_pool_ctx(const string& bucket_name, const string& pool, librados::IoCtx& io_ctx); int open_bucket_index_ctx(rgw_bucket& bucket, librados::IoCtx& index_ctx); int open_bucket_data_ctx(rgw_bucket& bucket, librados::IoCtx& io_ctx); int open_bucket_data_extra_ctx(rgw_bucket& bucket, librados::IoCtx& io_ctx); int open_bucket_index(rgw_bucket& bucket, librados::IoCtx& index_ctx, string& bucket_oid); struct GetObjState { librados::IoCtx io_ctx; bool sent_data; GetObjState() : sent_data(false) {} }; atomic64_t max_req_id; Mutex lock; SafeTimer *timer; class C_Tick : public Context { RGWRados *rados; public: C_Tick(RGWRados *_r) : rados(_r) {} void finish(int r) { rados->tick(); } }; RGWGC *gc; bool use_gc_thread; bool quota_threads; int num_watchers; RGWWatcher **watchers; uint64_t *watch_handles; librados::IoCtx root_pool_ctx; // .rgw librados::IoCtx control_pool_ctx; // .rgw.control bool watch_initialized; Mutex bucket_id_lock; int get_obj_ioctx(const rgw_obj& obj, librados::IoCtx *ioctx); int get_obj_ref(const rgw_obj& obj, rgw_rados_ref *ref, rgw_bucket *bucket, bool ref_system_obj = false); uint64_t max_bucket_id; int get_obj_state(RGWRadosCtx *rctx, rgw_obj& obj, RGWObjState **state, RGWObjVersionTracker *objv_tracker); int append_atomic_test(RGWRadosCtx *rctx, rgw_obj& obj, librados::ObjectOperation& op, RGWObjState **state); int prepare_atomic_for_write_impl(RGWRadosCtx *rctx, rgw_obj& obj, librados::ObjectWriteOperation& op, RGWObjState **pstate, bool reset_obj, const string *ptag); int prepare_atomic_for_write(RGWRadosCtx *rctx, rgw_obj& obj, librados::ObjectWriteOperation& op, RGWObjState **pstate, bool reset_obj, const string *ptag); void atomic_write_finish(RGWObjState *state, int r) { if (state && r == -ECANCELED) { state->clear(); } } int clone_objs_impl(void *ctx, rgw_obj& dst_obj, vector& ranges, map attrs, RGWObjCategory category, time_t *pmtime, bool truncate_dest, bool exclusive, pair *cmp_xattr); virtual int clone_obj(void *ctx, rgw_obj& dst_obj, off_t dst_ofs, rgw_obj& src_obj, off_t src_ofs, uint64_t size, time_t *pmtime, map attrs, RGWObjCategory category) { RGWCloneRangeInfo info; vector v; info.src = src_obj; info.src_ofs = src_ofs; info.dst_ofs = dst_ofs; info.len = size; v.push_back(info); return clone_objs(ctx, dst_obj, v, attrs, category, pmtime, true, false); } int complete_atomic_overwrite(RGWRadosCtx *rctx, RGWObjState *state, rgw_obj& obj); int update_placement_map(); int store_bucket_info(RGWBucketInfo& info, map *pattrs, RGWObjVersionTracker *objv_tracker, bool exclusive); protected: virtual int delete_obj_impl(void *ctx, const string& bucket_owner, rgw_obj& src_obj, RGWObjVersionTracker *objv_tracker); CephContext *cct; librados::Rados *rados; librados::IoCtx gc_pool_ctx; // .rgw.gc bool pools_initialized; string region_name; string zone_name; RGWQuotaHandler *quota_handler; public: RGWRados() : max_req_id(0), lock("rados_timer_lock"), timer(NULL), gc(NULL), use_gc_thread(false), quota_threads(false), num_watchers(0), watchers(NULL), watch_handles(NULL), watch_initialized(false), bucket_id_lock("rados_bucket_id"), max_bucket_id(0), cct(NULL), rados(NULL), pools_initialized(false), quota_handler(NULL), rest_master_conn(NULL), meta_mgr(NULL), data_log(NULL) {} uint64_t get_new_req_id() { return max_req_id.inc(); } void set_context(CephContext *_cct) { cct = _cct; } void set_region(const string& name) { region_name = name; } void set_zone(const string& name) { zone_name = name; } RGWRegion region; RGWZoneParams zone; /* internal zone params, e.g., rados pools */ RGWZone zone_public_config; /* external zone params, e.g., entrypoints, log flags, etc. */ RGWRegionMap region_map; RGWRESTConn *rest_master_conn; map zone_conn_map; map region_conn_map; RGWMetadataManager *meta_mgr; RGWDataChangesLog *data_log; virtual ~RGWRados() { if (rados) { rados->shutdown(); delete rados; } } int get_required_alignment(rgw_bucket& bucket, uint64_t *alignment); int get_max_chunk_size(rgw_bucket& bucket, uint64_t *max_chunk_size); int list_raw_objects(rgw_bucket& pool, const string& prefix_filter, int max, RGWListRawObjsCtx& ctx, list& oids, bool *is_truncated); int list_raw_prefixed_objs(string pool_name, const string& prefix, list& result); int list_regions(list& regions); int list_zones(list& zones); void tick(); CephContext *ctx() { return cct; } /** do all necessary setup of the storage device */ int initialize(CephContext *_cct, bool _use_gc_thread, bool _quota_threads) { set_context(_cct); use_gc_thread = _use_gc_thread; quota_threads = _quota_threads; return initialize(); } /** Initialize the RADOS instance and prepare to do other ops */ virtual int init_rados(); int init_complete(); virtual int initialize(); virtual void finalize(); /** set up a bucket listing. handle is filled in. */ virtual int list_buckets_init(RGWAccessHandle *handle); /** * get the next bucket in the listing. obj is filled in, * handle is updated. */ virtual int list_buckets_next(RGWObjEnt& obj, RGWAccessHandle *handle); /// list logs int log_list_init(const string& prefix, RGWAccessHandle *handle); int log_list_next(RGWAccessHandle handle, string *name); /// remove log int log_remove(const string& name); /// show log int log_show_init(const string& name, RGWAccessHandle *handle); int log_show_next(RGWAccessHandle handle, rgw_log_entry *entry); // log bandwidth info int log_usage(map& usage_info); int read_usage(string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, bool *is_truncated, RGWUsageIter& read_iter, map& usage); int trim_usage(string& user, uint64_t start_epoch, uint64_t end_epoch); /** * get listing of the objects in a bucket. * bucket: bucket to list contents of * max: maximum number of results to return * prefix: only return results that match this prefix * delim: do not include results that match this string. * Any skipped results will have the matching portion of their name * inserted in common_prefixes with a "true" mark. * marker: if filled in, begin the listing with this object. * result: the objects are put in here. * common_prefixes: if delim is filled in, any matching prefixes are placed * here. */ virtual int list_objects(rgw_bucket& bucket, int max, std::string& prefix, std::string& delim, std::string& marker, std::string *next_marker, std::vector& result, map& common_prefixes, bool get_content_type, string& ns, bool enforce_ns, bool *is_truncated, RGWAccessListFilter *filter); virtual int create_pool(rgw_bucket& bucket); /** * create a bucket with name bucket and the given list of attrs * returns 0 on success, -ERR# otherwise. */ virtual int init_bucket_index(rgw_bucket& bucket); int select_bucket_placement(RGWUserInfo& user_info, const string& region_name, const std::string& rule, const std::string& bucket_name, rgw_bucket& bucket, string *pselected_rule); int select_legacy_bucket_placement(const string& bucket_name, rgw_bucket& bucket); int select_new_bucket_location(RGWUserInfo& user_info, const string& region_name, const string& rule, const std::string& bucket_name, rgw_bucket& bucket, string *pselected_rule); int set_bucket_location_by_rule(const string& location_rule, const std::string& bucket_name, rgw_bucket& bucket); virtual int create_bucket(RGWUserInfo& owner, rgw_bucket& bucket, const string& region_name, const string& placement_rule, map& attrs, RGWBucketInfo& bucket_info, obj_version *pobjv, obj_version *pep_objv, time_t creation_time, rgw_bucket *master_bucket, bool exclusive = true); virtual int add_bucket_placement(std::string& new_pool); virtual int remove_bucket_placement(std::string& new_pool); virtual int list_placement_set(set& names); virtual int create_pools(vector& names, vector& retcodes); struct PutObjMetaExtraParams { time_t *mtime; map* rmattrs; const bufferlist *data; RGWObjManifest *manifest; const string *ptag; list *remove_objs; bool modify_version; RGWObjVersionTracker *objv_tracker; time_t set_mtime; string owner; PutObjMetaExtraParams() : mtime(NULL), rmattrs(NULL), data(NULL), manifest(NULL), ptag(NULL), remove_objs(NULL), modify_version(false), objv_tracker(NULL), set_mtime(0) {} }; /** Write/overwrite an object to the bucket storage. */ virtual int put_obj_meta_impl(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, int flags, map* rmattrs, const bufferlist *data, RGWObjManifest *manifest, const string *ptag, list *remove_objs, bool modify_version, RGWObjVersionTracker *objv_tracker, time_t set_mtime /* 0 for don't set */, const string& owner); virtual int put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, int flags, const string& owner, const bufferlist *data = NULL) { return put_obj_meta_impl(ctx, obj, size, mtime, attrs, category, flags, NULL, data, NULL, NULL, NULL, false, NULL, 0, owner); } virtual int put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, map& attrs, RGWObjCategory category, int flags, PutObjMetaExtraParams& params) { return put_obj_meta_impl(ctx, obj, size, params.mtime, attrs, category, flags, params.rmattrs, params.data, params.manifest, params.ptag, params.remove_objs, params.modify_version, params.objv_tracker, params.set_mtime, params.owner); } virtual int put_obj_data(void *ctx, rgw_obj& obj, const char *data, off_t ofs, size_t len, bool exclusive); virtual int aio_put_obj_data(void *ctx, rgw_obj& obj, bufferlist& bl, off_t ofs, bool exclusive, void **handle); /* note that put_obj doesn't set category on an object, only use it for none user objects */ int put_system_obj(void *ctx, rgw_obj& obj, const char *data, size_t len, bool exclusive, time_t *mtime, map& attrs, RGWObjVersionTracker *objv_tracker, time_t set_mtime) { bufferlist bl; bl.append(data, len); int flags = PUT_OBJ_CREATE; if (exclusive) flags |= PUT_OBJ_EXCL; PutObjMetaExtraParams ep; ep.mtime = mtime; ep.data = &bl; ep.modify_version = true; ep.objv_tracker = objv_tracker; ep.set_mtime = set_mtime; int ret = put_obj_meta(ctx, obj, len, attrs, RGW_OBJ_CATEGORY_NONE, flags, ep); return ret; } virtual int aio_wait(void *handle); virtual bool aio_completed(void *handle); virtual int clone_objs(void *ctx, rgw_obj& dst_obj, vector& ranges, map attrs, RGWObjCategory category, time_t *pmtime, bool truncate_dest, bool exclusive) { return clone_objs(ctx, dst_obj, ranges, attrs, category, pmtime, truncate_dest, exclusive, NULL); } int clone_objs(void *ctx, rgw_obj& dst_obj, vector& ranges, map attrs, RGWObjCategory category, time_t *pmtime, bool truncate_dest, bool exclusive, pair *cmp_xattr); int clone_obj_cond(void *ctx, rgw_obj& dst_obj, off_t dst_ofs, rgw_obj& src_obj, off_t src_ofs, uint64_t size, map attrs, RGWObjCategory category, time_t *pmtime, bool truncate_dest, bool exclusive, pair *xattr_cond) { RGWCloneRangeInfo info; vector v; info.src = src_obj; info.src_ofs = src_ofs; info.dst_ofs = dst_ofs; info.len = size; v.push_back(info); return clone_objs(ctx, dst_obj, v, attrs, category, pmtime, truncate_dest, exclusive, xattr_cond); } /** * Copy an object. * dest_obj: the object to copy into * src_obj: the object to copy from * attrs: if replace_attrs is set then these are placed on the new object * err: stores any errors resulting from the get of the original object * Returns: 0 on success, -ERR# otherwise. */ virtual int copy_obj(void *ctx, const string& user_id, const string& client_id, const string& op_id, req_info *info, const string& source_zone, rgw_obj& dest_obj, rgw_obj& src_obj, RGWBucketInfo& dest_bucket_info, RGWBucketInfo& src_bucket_info, time_t *mtime, const time_t *mod_ptr, const time_t *unmod_ptr, const char *if_match, const char *if_nomatch, bool replace_attrs, map& attrs, RGWObjCategory category, string *ptag, string *petag, struct rgw_err *err, void (*progress_cb)(off_t, void *), void *progress_data); int copy_obj_data(void *ctx, const string& owner, void **handle, off_t end, rgw_obj& dest_obj, rgw_obj& src_obj, uint64_t max_chunk_size, time_t *mtime, map& attrs, RGWObjCategory category, string *ptag, string *petag, struct rgw_err *err); /** * Delete a bucket. * bucket: the name of the bucket to delete * Returns 0 on success, -ERR# otherwise. */ virtual int delete_bucket(rgw_bucket& bucket, RGWObjVersionTracker& objv_tracker); /** * Check to see if the bucket metadata is synced */ bool is_syncing_bucket_meta(rgw_bucket& bucket); int set_bucket_owner(rgw_bucket& bucket, ACLOwner& owner); int set_buckets_enabled(std::vector& buckets, bool enabled); int bucket_suspended(rgw_bucket& bucket, bool *suspended); /** Delete an object.*/ virtual int delete_obj(void *ctx, const string& bucket_owner, rgw_obj& src_obj, RGWObjVersionTracker *objv_tracker = NULL); virtual int delete_system_obj(void *ctx, rgw_obj& src_obj, RGWObjVersionTracker *objv_tracker = NULL); /** Remove an object from the bucket index */ int delete_obj_index(rgw_obj& obj); /** * Get the attributes for an object. * bucket: name of the bucket holding the object. * obj: name of the object * name: name of the attr to retrieve * dest: bufferlist to store the result in * Returns: 0 on success, -ERR# otherwise. */ virtual int get_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& dest); /** * Set an attr on an object. * bucket: name of the bucket holding the object * obj: name of the object to set the attr on * name: the attr to set * bl: the contents of the attr * Returns: 0 on success, -ERR# otherwise. */ virtual int set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl, RGWObjVersionTracker *objv_tracker); virtual int set_attrs(void *ctx, rgw_obj& obj, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker); /** * Get data about an object out of RADOS and into memory. * bucket: name of the bucket the object is in. * obj: name/key of the object to read * data: if get_data==true, this pointer will be set * to an address containing the object's data/value * ofs: the offset of the object to read from * end: the point in the object to stop reading * attrs: if non-NULL, the pointed-to map will contain * all the attrs of the object when this function returns * mod_ptr: if non-NULL, compares the object's mtime to *mod_ptr, * and if mtime is smaller it fails. * unmod_ptr: if non-NULL, compares the object's mtime to *unmod_ptr, * and if mtime is >= it fails. * if_match/nomatch: if non-NULL, compares the object's etag attr * to the string and, if it doesn't/does match, fails out. * err: Many errors will result in this structure being filled * with extra informatin on the error. * Returns: -ERR# on failure, otherwise * (if get_data==true) length of read data, * (if get_data==false) length of the object */ virtual int prepare_get_obj(void *ctx, rgw_obj& obj, off_t *ofs, off_t *end, map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, time_t *lastmod, const char *if_match, const char *if_nomatch, uint64_t *total_size, uint64_t *obj_size, RGWObjVersionTracker *objv_tracker, void **handle, struct rgw_err *err); virtual int get_obj(void *ctx, RGWObjVersionTracker *objv_tracker, void **handle, rgw_obj& obj, bufferlist& bl, off_t ofs, off_t end); virtual void finish_get_obj(void **handle); int iterate_obj(void *ctx, rgw_obj& obj, off_t ofs, off_t end, uint64_t max_chunk_size, int (*iterate_obj_cb)(rgw_obj&, off_t, off_t, off_t, bool, RGWObjState *, void *), void *arg); int get_obj_iterate(void *ctx, void **handle, rgw_obj& obj, off_t ofs, off_t end, RGWGetDataCB *cb); int flush_read_list(struct get_obj_data *d); int get_obj_iterate_cb(void *ctx, RGWObjState *astate, rgw_obj& obj, off_t obj_ofs, off_t read_ofs, off_t len, bool is_head_obj, void *arg); void get_obj_aio_completion_cb(librados::completion_t cb, void *arg); /** * a simple object read without keeping state */ virtual int read(void *ctx, rgw_obj& obj, off_t ofs, size_t size, bufferlist& bl); virtual int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, uint64_t *epoch, map *attrs, bufferlist *first_chunk, RGWObjVersionTracker *objv_tracker); virtual bool supports_omap() { return true; } int omap_get_vals(rgw_obj& obj, bufferlist& header, const std::string& marker, uint64_t count, std::map& m); virtual int omap_get_all(rgw_obj& obj, bufferlist& header, std::map& m); virtual int omap_set(rgw_obj& obj, std::string& key, bufferlist& bl); virtual int omap_set(rgw_obj& obj, map& m); virtual int omap_del(rgw_obj& obj, const std::string& key); virtual int update_containers_stats(map& m); virtual int append_async(rgw_obj& obj, size_t size, bufferlist& bl); virtual bool need_watch_notify() { return false; } virtual int init_watch(); virtual void finalize_watch(); virtual int distribute(const string& key, bufferlist& bl); virtual int watch_cb(int opcode, uint64_t ver, bufferlist& bl) { return 0; } void pick_control_oid(const string& key, string& notify_oid); void *create_context(void *user_ctx) { RGWRadosCtx *rctx = new RGWRadosCtx(this); rctx->user_ctx = user_ctx; return rctx; } void destroy_context(void *ctx) { delete static_cast(ctx); } void set_atomic(void *ctx, rgw_obj& obj) { RGWRadosCtx *rctx = static_cast(ctx); rctx->set_atomic(obj); } void set_prefetch_data(void *ctx, rgw_obj& obj) { RGWRadosCtx *rctx = static_cast(ctx); rctx->set_prefetch_data(obj); } // to notify upper layer that we need to do some operation on an object, and it's up to // the upper layer to schedule this operation.. e.g., log intent in intent log void set_intent_cb(void *ctx, int (*cb)(RGWRados *store, void *user_ctx, rgw_obj& obj, RGWIntentEvent intent)) { RGWRadosCtx *rctx = static_cast(ctx); rctx->set_intent_cb(cb); } int decode_policy(bufferlist& bl, ACLOwner *owner); int get_bucket_stats(rgw_bucket& bucket, uint64_t *bucket_ver, uint64_t *master_ver, map& stats, string *max_marker); int get_bucket_stats_async(rgw_bucket& bucket, RGWGetBucketStats_CB *cb); int get_user_stats(const string& user, RGWStorageStats& stats); int get_user_stats_async(const string& user, RGWGetUserStats_CB *cb); void get_bucket_instance_obj(rgw_bucket& bucket, rgw_obj& obj); void get_bucket_instance_entry(rgw_bucket& bucket, string& entry); void get_bucket_meta_oid(rgw_bucket& bucket, string& oid); int put_bucket_entrypoint_info(const string& bucket_name, RGWBucketEntryPoint& entry_point, bool exclusive, RGWObjVersionTracker& objv_tracker, time_t mtime, map *pattrs); int put_bucket_instance_info(RGWBucketInfo& info, bool exclusive, time_t mtime, map *pattrs); int get_bucket_entrypoint_info(void *ctx, const string& bucket_name, RGWBucketEntryPoint& entry_point, RGWObjVersionTracker *objv_tracker, time_t *pmtime, map *pattrs); int get_bucket_instance_info(void *ctx, const string& meta_key, RGWBucketInfo& info, time_t *pmtime, map *pattrs); int get_bucket_instance_info(void *ctx, rgw_bucket& bucket, RGWBucketInfo& info, time_t *pmtime, map *pattrs); int get_bucket_instance_from_oid(void *ctx, string& oid, RGWBucketInfo& info, time_t *pmtime, map *pattrs); int convert_old_bucket_info(void *ctx, string& bucket_name); virtual int get_bucket_info(void *ctx, const string& bucket_name, RGWBucketInfo& info, time_t *pmtime, map *pattrs = NULL); virtual int put_linked_bucket_info(RGWBucketInfo& info, bool exclusive, time_t mtime, obj_version *pep_objv, map *pattrs, bool create_entry_point); int cls_rgw_init_index(librados::IoCtx& io_ctx, librados::ObjectWriteOperation& op, string& oid); int cls_obj_prepare_op(rgw_bucket& bucket, RGWModifyOp op, string& tag, string& name, string& locator); int cls_obj_complete_op(rgw_bucket& bucket, RGWModifyOp op, string& tag, int64_t pool, uint64_t epoch, RGWObjEnt& ent, RGWObjCategory category, list *remove_objs); int cls_obj_complete_add(rgw_bucket& bucket, string& tag, int64_t pool, uint64_t epoch, RGWObjEnt& ent, RGWObjCategory category, list *remove_objs); int cls_obj_complete_del(rgw_bucket& bucket, string& tag, int64_t pool, uint64_t epoch, string& name); int cls_obj_complete_cancel(rgw_bucket& bucket, string& tag, string& name); int cls_obj_set_bucket_tag_timeout(rgw_bucket& bucket, uint64_t timeout); int cls_bucket_list(rgw_bucket& bucket, string start, string prefix, uint32_t num, map& m, bool *is_truncated, string *last_entry, bool (*force_check_filter)(const string& name) = NULL); int cls_bucket_head(rgw_bucket& bucket, struct rgw_bucket_dir_header& header); int cls_bucket_head_async(rgw_bucket& bucket, RGWGetDirHeader_CB *ctx); int prepare_update_index(RGWObjState *state, rgw_bucket& bucket, RGWModifyOp op, rgw_obj& oid, string& tag); int complete_update_index(rgw_bucket& bucket, string& oid, string& tag, int64_t poolid, uint64_t epoch, uint64_t size, utime_t& ut, string& etag, string& content_type, bufferlist *acl_bl, RGWObjCategory category, list *remove_objs); int complete_update_index_del(rgw_bucket& bucket, string& oid, string& tag, int64_t pool, uint64_t epoch) { if (bucket_is_system(bucket)) return 0; return cls_obj_complete_del(bucket, tag, pool, epoch, oid); } int complete_update_index_cancel(rgw_bucket& bucket, string& oid, string& tag) { if (bucket_is_system(bucket)) return 0; return cls_obj_complete_cancel(bucket, tag, oid); } int list_bi_log_entries(rgw_bucket& bucket, string& marker, uint32_t max, std::list& result, bool *truncated); int trim_bi_log_entries(rgw_bucket& bucket, string& marker, string& end_marker); int cls_obj_usage_log_add(const string& oid, rgw_usage_log_info& info); int cls_obj_usage_log_read(string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, string& read_iter, map& usage, bool *is_truncated); int cls_obj_usage_log_trim(string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch); void shard_name(const string& prefix, unsigned max_shards, const string& key, string& name); void shard_name(const string& prefix, unsigned max_shards, const string& section, const string& key, string& name); void time_log_prepare_entry(cls_log_entry& entry, const utime_t& ut, string& section, string& key, bufferlist& bl); int time_log_add(const string& oid, list& entries); int time_log_add(const string& oid, const utime_t& ut, const string& section, const string& key, bufferlist& bl); int time_log_list(const string& oid, utime_t& start_time, utime_t& end_time, int max_entries, list& entries, const string& marker, string *out_marker, bool *truncated); int time_log_info(const string& oid, cls_log_header *header); int time_log_trim(const string& oid, const utime_t& start_time, const utime_t& end_time, const string& from_marker, const string& to_marker); int lock_exclusive(rgw_bucket& pool, const string& oid, utime_t& duration, string& zone_id, string& owner_id); int unlock(rgw_bucket& pool, const string& oid, string& zone_id, string& owner_id); /// clean up/process any temporary objects older than given date[/time] int remove_temp_objects(string date, string time); int gc_operate(string& oid, librados::ObjectWriteOperation *op); int gc_aio_operate(string& oid, librados::ObjectWriteOperation *op); int gc_operate(string& oid, librados::ObjectReadOperation *op, bufferlist *pbl); int list_gc_objs(int *index, string& marker, uint32_t max, bool expired_only, std::list& result, bool *truncated); int process_gc(); int defer_gc(void *ctx, rgw_obj& obj); int bucket_check_index(rgw_bucket& bucket, map *existing_stats, map *calculated_stats); int bucket_rebuild_index(rgw_bucket& bucket); int remove_objs_from_index(rgw_bucket& bucket, list& oid_list); int cls_user_get_header(const string& user_id, cls_user_header *header); int cls_user_get_header_async(const string& user_id, RGWGetUserHeader_CB *ctx); int cls_user_sync_bucket_stats(rgw_obj& user_obj, rgw_bucket& bucket); int update_user_bucket_stats(const string& user_id, rgw_bucket& bucket, RGWStorageStats& stats); int cls_user_list_buckets(rgw_obj& obj, const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated); int cls_user_add_bucket(rgw_obj& obj, const cls_user_bucket_entry& entry); int cls_user_update_buckets(rgw_obj& obj, list& entries, bool add); int cls_user_complete_stats_sync(rgw_obj& obj); int complete_sync_user_stats(const string& user_id); int cls_user_add_bucket(rgw_obj& obj, list& entries); int cls_user_remove_bucket(rgw_obj& obj, const cls_user_bucket& bucket); int check_quota(const string& bucket_owner, rgw_bucket& bucket, RGWQuotaInfo& user_quota, RGWQuotaInfo& bucket_quota, uint64_t obj_size); string unique_id(uint64_t unique_num) { char buf[32]; snprintf(buf, sizeof(buf), ".%llu.%llu", (unsigned long long)instance_id(), (unsigned long long)unique_num); string s = zone.name + buf; return s; } void get_log_pool_name(string& name) { name = zone.log_pool.name; } bool need_to_log_data() { return zone_public_config.log_data; } bool need_to_log_metadata() { return zone_public_config.log_meta; } private: int process_intent_log(rgw_bucket& bucket, string& oid, time_t epoch, int flags, bool purge); /** * Check the actual on-disk state of the object specified * by list_state, and fill in the time and size of object. * Then append any changes to suggested_updates for * the rgw class' dir_suggest_changes function. * * Note that this can maul list_state; don't use it afterwards. Also * it expects object to already be filled in from list_state; it only * sets the size and mtime. * * Returns 0 on success, -ENOENT if the object doesn't exist on disk, * and -errno on other failures. (-ENOENT is not a failure, and it * will encode that info as a suggested update.) */ int check_disk_state(librados::IoCtx io_ctx, rgw_bucket& bucket, rgw_bucket_dir_entry& list_state, RGWObjEnt& object, bufferlist& suggested_updates); bool bucket_is_system(rgw_bucket& bucket) { return (bucket.name[0] == '.'); } /** * Init pool iteration * bucket: pool name in a bucket object * ctx: context object to use for the iteration * Returns: 0 on success, -ERR# otherwise. */ int pool_iterate_begin(rgw_bucket& bucket, RGWPoolIterCtx& ctx); /** * Iterate over pool return object names, use optional filter * ctx: iteration context, initialized with pool_iterate_begin() * num: max number of objects to return * objs: a vector that the results will append into * is_truncated: if not NULL, will hold true iff iteration is complete * filter: if not NULL, will be used to filter returned objects * Returns: 0 on success, -ERR# otherwise. */ int pool_iterate(RGWPoolIterCtx& ctx, uint32_t num, vector& objs, bool *is_truncated, RGWAccessListFilter *filter); uint64_t instance_id(); uint64_t next_bucket_id(); }; class RGWStoreManager { public: RGWStoreManager() {} static RGWRados *get_storage(CephContext *cct, bool use_gc_thread, bool quota_threads) { RGWRados *store = init_storage_provider(cct, use_gc_thread, quota_threads); return store; } static RGWRados *get_raw_storage(CephContext *cct) { RGWRados *store = init_raw_storage_provider(cct); return store; } static RGWRados *init_storage_provider(CephContext *cct, bool use_gc_thread, bool quota_threads); static RGWRados *init_raw_storage_provider(CephContext *cct); static void close_storage(RGWRados *store); }; #endif ceph-0.80.11/src/rgw/rgw_swift_auth.cc0000664000175100017510000001413012623076744021625 0ustar jenkins-buildjenkins-build#include "rgw_swift_auth.h" #include "rgw_rest.h" #include "common/ceph_crypto.h" #include "common/Clock.h" #include "auth/Crypto.h" #include "rgw_client_io.h" #define dout_subsys ceph_subsys_rgw #define DEFAULT_SWIFT_PREFIX "swift" using namespace ceph::crypto; static int build_token(string& swift_user, string& key, uint64_t nonce, utime_t& expiration, bufferlist& bl) { ::encode(swift_user, bl); ::encode(nonce, bl); ::encode(expiration, bl); bufferptr p(CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); char buf[bl.length() * 2 + 1]; buf_to_hex((const unsigned char *)bl.c_str(), bl.length(), buf); dout(20) << "build_token token=" << buf << dendl; char k[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; memset(k, 0, sizeof(k)); const char *s = key.c_str(); for (int i = 0; i < (int)key.length(); i++, s++) { k[i % CEPH_CRYPTO_HMACSHA1_DIGESTSIZE] |= *s; } calc_hmac_sha1(k, sizeof(k), bl.c_str(), bl.length(), p.c_str()); bl.append(p); return 0; } static int encode_token(CephContext *cct, string& swift_user, string& key, bufferlist& bl) { uint64_t nonce; int ret = get_random_bytes((char *)&nonce, sizeof(nonce)); if (ret < 0) return ret; utime_t expiration = ceph_clock_now(cct); expiration += cct->_conf->rgw_swift_token_expiration; ret = build_token(swift_user, key, nonce, expiration, bl); return ret; } int rgw_swift_verify_signed_token(CephContext *cct, RGWRados *store, const char *token, RGWUserInfo& info, string *pswift_user) { if (strncmp(token, "AUTH_rgwtk", 10) != 0) return -EINVAL; token += 10; int len = strlen(token); if (len & 1) { dout(0) << "NOTICE: failed to verify token: invalid token length len=" << len << dendl; return -EINVAL; } bufferptr p(len/2); int ret = hex_to_buf(token, p.c_str(), len); if (ret < 0) return ret; bufferlist bl; bl.append(p); bufferlist::iterator iter = bl.begin(); uint64_t nonce; utime_t expiration; string swift_user; try { ::decode(swift_user, iter); ::decode(nonce, iter); ::decode(expiration, iter); } catch (buffer::error& err) { dout(0) << "NOTICE: failed to decode token: caught exception" << dendl; return -EINVAL; } utime_t now = ceph_clock_now(cct); if (expiration < now) { dout(0) << "NOTICE: old timed out token was used now=" << now << " token.expiration=" << expiration << dendl; return -EPERM; } if ((ret = rgw_get_user_info_by_swift(store, swift_user, info)) < 0) return ret; dout(10) << "swift_user=" << swift_user << dendl; map::iterator siter = info.swift_keys.find(swift_user); if (siter == info.swift_keys.end()) return -EPERM; RGWAccessKey& swift_key = siter->second; bufferlist tok; ret = build_token(swift_user, swift_key.key, nonce, expiration, tok); if (ret < 0) return ret; if (tok.length() != bl.length()) { dout(0) << "NOTICE: tokens length mismatch: bl.length()=" << bl.length() << " tok.length()=" << tok.length() << dendl; return -EPERM; } if (memcmp(tok.c_str(), bl.c_str(), tok.length()) != 0) { char buf[tok.length() * 2 + 1]; buf_to_hex((const unsigned char *)tok.c_str(), tok.length(), buf); dout(0) << "NOTICE: tokens mismatch tok=" << buf << dendl; return -EPERM; } *pswift_user = swift_user; return 0; } void RGW_SWIFT_Auth_Get::execute() { int ret = -EPERM; const char *key = s->info.env->get("HTTP_X_AUTH_KEY"); const char *user = s->info.env->get("HTTP_X_AUTH_USER"); string user_str; RGWUserInfo info; bufferlist bl; RGWAccessKey *swift_key; map::iterator siter; string swift_url = g_conf->rgw_swift_url; string swift_prefix = g_conf->rgw_swift_url_prefix; string tenant_path; if (swift_prefix.size() == 0) { swift_prefix = DEFAULT_SWIFT_PREFIX; } if (swift_url.size() == 0) { bool add_port = false; const char *server_port = s->info.env->get("SERVER_PORT_SECURE"); const char *protocol; if (server_port) { add_port = (strcmp(server_port, "443") != 0); protocol = "https"; } else { server_port = s->info.env->get("SERVER_PORT"); add_port = (strcmp(server_port, "80") != 0); protocol = "http"; } const char *host = s->info.env->get("HTTP_HOST"); if (!host) { dout(0) << "NOTICE: server is misconfigured, missing rgw_swift_url_prefix or rgw_swift_url, HTTP_HOST is not set" << dendl; ret = -EINVAL; goto done; } swift_url = protocol; swift_url.append("://"); swift_url.append(host); if (add_port && !strchr(host, ':')) { swift_url.append(":"); swift_url.append(server_port); } } if (!key || !user) goto done; user_str = user; if ((ret = rgw_get_user_info_by_swift(store, user_str, info)) < 0) { ret = -EACCES; goto done; } siter = info.swift_keys.find(user_str); if (siter == info.swift_keys.end()) { ret = -EPERM; goto done; } swift_key = &siter->second; if (swift_key->key.compare(key) != 0) { dout(0) << "NOTICE: RGW_SWIFT_Auth_Get::execute(): bad swift key" << dendl; ret = -EPERM; goto done; } if (!g_conf->rgw_swift_tenant_name.empty()) { tenant_path = "/AUTH_"; tenant_path.append(g_conf->rgw_swift_tenant_name); } s->cio->print("X-Storage-Url: %s/%s/v1%s\r\n", swift_url.c_str(), swift_prefix.c_str(), tenant_path.c_str()); if ((ret = encode_token(s->cct, swift_key->id, swift_key->key, bl)) < 0) goto done; { char buf[bl.length() * 2 + 1]; buf_to_hex((const unsigned char *)bl.c_str(), bl.length(), buf); s->cio->print("X-Storage-Token: AUTH_rgwtk%s\r\n", buf); s->cio->print("X-Auth-Token: AUTH_rgwtk%s\r\n", buf); } ret = STATUS_NO_CONTENT; done: set_req_state_err(s, ret); dump_errno(s); end_header(s); } int RGWHandler_SWIFT_Auth::init(RGWRados *store, struct req_state *state, RGWClientIO *cio) { state->dialect = "swift-auth"; state->formatter = new JSONFormatter; state->format = RGW_FORMAT_JSON; return RGWHandler::init(store, state, cio); } int RGWHandler_SWIFT_Auth::authorize() { return 0; } RGWOp *RGWHandler_SWIFT_Auth::op_get() { return new RGW_SWIFT_Auth_Get; } ceph-0.80.11/src/rgw/rgw_rest_config.cc0000664000175100017510000000221512623076744021753 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_json.h" #include "common/strtol.h" #include "rgw_rest.h" #include "rgw_op.h" #include "rgw_rados.h" #include "rgw_rest_s3.h" #include "rgw_rest_config.h" #include "rgw_client_io.h" #include "common/errno.h" #define dout_subsys ceph_subsys_rgw void RGWOp_RegionMap_Get::execute() { http_ret = regionmap.read(g_ceph_context, store); if (http_ret < 0) { dout(5) << "failed to read region map" << dendl; } } void RGWOp_RegionMap_Get::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); if (http_ret < 0) return; encode_json("region-map", regionmap, s->formatter); flusher.flush(); } RGWOp* RGWHandler_Config::op_get() { return new RGWOp_RegionMap_Get; } ceph-0.80.11/src/rgw/rgw_string.h0000664000175100017510000000314212623076744020621 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_STRING_H #define CEPH_RGW_STRING_H #include #include struct ltstr_nocase { bool operator()(const string& s1, const string& s2) const { return strcasecmp(s1.c_str(), s2.c_str()) < 0; } }; static inline int stringcasecmp(const string& s1, const string& s2) { return strcasecmp(s1.c_str(), s2.c_str()); } static inline int stringcasecmp(const string& s1, const char *s2) { return strcasecmp(s1.c_str(), s2); } static inline int stringcasecmp(const string& s1, int ofs, int size, const string& s2) { return strncasecmp(s1.c_str() + ofs, s2.c_str(), size); } static inline int stringtoll(const string& s, int64_t *val) { char *end; long long result = strtoll(s.c_str(), &end, 10); if (result == LLONG_MAX) return -EINVAL; if (*end) return -EINVAL; *val = (int64_t)result; return 0; } static inline int stringtoull(const string& s, uint64_t *val) { char *end; unsigned long long result = strtoull(s.c_str(), &end, 10); if (result == ULLONG_MAX) return -EINVAL; if (*end) return -EINVAL; *val = (uint64_t)result; return 0; } static inline int stringtol(const string& s, int32_t *val) { char *end; long result = strtol(s.c_str(), &end, 10); if (result == LONG_MAX) return -EINVAL; if (*end) return -EINVAL; *val = (int32_t)result; return 0; } static inline int stringtoul(const string& s, uint32_t *val) { char *end; unsigned long result = strtoul(s.c_str(), &end, 10); if (result == ULONG_MAX) return -EINVAL; if (*end) return -EINVAL; *val = (uint32_t)result; return 0; } #endif ceph-0.80.11/src/rgw/rgw_http_client.h0000664000175100017510000000206712623076744021635 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_HTTP_CLIENT_H #define CEPH_RGW_HTTP_CLIENT_H #include "rgw_common.h" class RGWHTTPClient { bufferlist send_bl; bufferlist::iterator send_iter; size_t send_len; bool has_send_len; protected: CephContext *cct; list > headers; public: virtual ~RGWHTTPClient() {} RGWHTTPClient(CephContext *_cct): send_len (0), has_send_len(false), cct(_cct) {} void append_header(const string& name, const string& val) { headers.push_back(pair(name, val)); } virtual int receive_header(void *ptr, size_t len) = 0; virtual int receive_data(void *ptr, size_t len) = 0; virtual int send_data(void *ptr, size_t len) = 0; void set_send_length(size_t len) { send_len = len; has_send_len = true; } int process(const char *method, const char *url); int process(const char *url) { return process("GET", url); } int init_async(const char *method, const char *url, void **handle); int process_request(void *handle, bool wait_for_data, bool *done); int complete_request(void *handle); }; #endif ceph-0.80.11/src/rgw/rgw_loadgen.h0000664000175100017510000000163712623076744020733 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_LOADGEN_H #define CEPH_RGW_LOADGEN_H #include "rgw_client_io.h" struct RGWLoadGenRequestEnv { int port; uint64_t content_length; string content_type; string request_method; string uri; string query_string; string date_str; map headers; RGWLoadGenRequestEnv() : port(0), content_length(0) {} void set_date(utime_t& tm); int sign(RGWAccessKey& access_key); }; class RGWLoadGenIO : public RGWClientIO { uint64_t left_to_read; RGWLoadGenRequestEnv *req; public: void init_env(CephContext *cct); int write_data(const char *buf, int len); int read_data(char *buf, int len); int send_status(const char *status, const char *status_name); int send_100_continue(); int complete_header(); int complete_request(); int send_content_length(uint64_t len); RGWLoadGenIO(RGWLoadGenRequestEnv *_re) : left_to_read(0), req(_re) {} void flush(); }; #endif ceph-0.80.11/src/rgw/rgw_rados.cc0000664000175100017510000055166612623076744020604 0ustar jenkins-buildjenkins-build#include #include #include #include "common/ceph_json.h" #include "common/utf8.h" #include "common/errno.h" #include "common/Formatter.h" #include "common/Throttle.h" #include "rgw_rados.h" #include "rgw_cache.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" /* for dumping s3policy in debug log */ #include "rgw_metadata.h" #include "rgw_bucket.h" #include "cls/rgw/cls_rgw_types.h" #include "cls/rgw/cls_rgw_client.h" #include "cls/refcount/cls_refcount_client.h" #include "cls/version/cls_version_client.h" #include "cls/log/cls_log_client.h" #include "cls/statelog/cls_statelog_client.h" #include "cls/lock/cls_lock_client.h" #include "cls/user/cls_user_client.h" #include "rgw_tools.h" #include "common/Clock.h" #include "include/rados/librados.hpp" using namespace librados; #include #include #include #include #include #include "auth/Crypto.h" // get_random_bytes() #include "rgw_log.h" #include "rgw_gc.h" #define dout_subsys ceph_subsys_rgw using namespace std; static RGWCache cached_rados_provider; static RGWRados rados_provider; static string notify_oid_prefix = "notify"; static string *notify_oids = NULL; static string shadow_ns = "shadow"; static string dir_oid_prefix = ".dir."; static string default_storage_pool = ".rgw.buckets"; static string default_storage_extra_pool = ".rgw.buckets.extra"; static string avail_pools = ".pools.avail"; static string zone_info_oid_prefix = "zone_info."; static string region_info_oid_prefix = "region_info."; static string default_region_info_oid = "default.region"; static string region_map_oid = "region_map"; static string log_lock_name = "rgw_log_lock"; static RGWObjCategory main_category = RGW_OBJ_CATEGORY_MAIN; #define RGW_USAGE_OBJ_PREFIX "usage." #define RGW_DEFAULT_ZONE_ROOT_POOL ".rgw.root" #define RGW_DEFAULT_REGION_ROOT_POOL ".rgw.root" #define RGW_STATELOG_OBJ_PREFIX "statelog." #define dout_subsys ceph_subsys_rgw void RGWDefaultRegionInfo::dump(Formatter *f) const { encode_json("default_region", default_region, f); } void RGWDefaultRegionInfo::decode_json(JSONObj *obj) { JSONDecoder::decode_json("default_region", default_region, obj); } int RGWRegion::get_pool_name(CephContext *cct, string *pool_name) { *pool_name = cct->_conf->rgw_region_root_pool; if (pool_name->empty()) { *pool_name = RGW_DEFAULT_REGION_ROOT_POOL; } else if ((*pool_name)[0] != '.') { derr << "ERROR: region root pool name must start with a period" << dendl; return -EINVAL; } return 0; } int RGWRegion::read_default(RGWDefaultRegionInfo& default_info) { string pool_name; int ret = get_pool_name(cct, &pool_name); if (ret < 0) { return ret; } string oid = cct->_conf->rgw_default_region_info_oid; if (oid.empty()) { oid = default_region_info_oid; } rgw_bucket pool(pool_name.c_str()); bufferlist bl; ret = rgw_get_system_obj(store, NULL, pool, oid, bl, NULL, NULL); if (ret < 0) return ret; try { bufferlist::iterator iter = bl.begin(); ::decode(default_info, iter); } catch (buffer::error& err) { derr << "error decoding data from " << pool << ":" << oid << dendl; return -EIO; } name = default_info.default_region; return 0; } int RGWRegion::set_as_default() { string pool_name; int ret = get_pool_name(cct, &pool_name); if (ret < 0) return ret; string oid = cct->_conf->rgw_default_region_info_oid; if (oid.empty()) { oid = default_region_info_oid; } rgw_bucket pool(pool_name.c_str()); bufferlist bl; RGWDefaultRegionInfo default_info; default_info.default_region = name; ::encode(default_info, bl); ret = rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(), false, NULL, 0, NULL); if (ret < 0) return ret; return 0; } int RGWRegion::init(CephContext *_cct, RGWRados *_store, bool setup_region) { cct = _cct; store = _store; if (!setup_region) return 0; string region_name = cct->_conf->rgw_region; if (region_name.empty()) { RGWDefaultRegionInfo default_info; int r = read_default(default_info); if (r == -ENOENT) { r = create_default(); if (r == -EEXIST) { /* we may have raced with another region creation, make sure we can read the region info and continue as usual to make sure region creation is complete */ ldout(cct, 0) << "create_default() returned -EEXIST, we raced with another region creation" << dendl; r = read_info(name); } if (r < 0) return r; r = set_as_default(); /* set this as default even if we weren't the creators */ if (r < 0) return r; /*Re attempt to read region info from newly created default region */ r = read_default(default_info); if (r < 0) return r; } else if (r < 0) { lderr(cct) << "failed reading default region info: " << cpp_strerror(-r) << dendl; return r; } region_name = default_info.default_region; } return read_info(region_name); } int RGWRegion::read_info(const string& region_name) { string pool_name; int ret = get_pool_name(cct, &pool_name); if (ret < 0) return ret; rgw_bucket pool(pool_name.c_str()); bufferlist bl; name = region_name; string oid = region_info_oid_prefix + name; ret = rgw_get_system_obj(store, NULL, pool, oid, bl, NULL, NULL); if (ret < 0) { lderr(cct) << "failed reading region info from " << pool << ":" << oid << ": " << cpp_strerror(-ret) << dendl; return ret; } try { bufferlist::iterator iter = bl.begin(); ::decode(*this, iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: failed to decode region from " << pool << ":" << oid << dendl; return -EIO; } return 0; } int RGWRegion::create_default() { name = "default"; string zone_name = "default"; is_master = true; RGWRegionPlacementTarget placement_target; placement_target.name = "default-placement"; placement_targets[placement_target.name] = placement_target; default_placement = "default-placement"; RGWZone& default_zone = zones[zone_name]; default_zone.name = zone_name; RGWZoneParams zone_params; zone_params.name = zone_name; zone_params.init_default(store); int r = zone_params.store_info(cct, store, *this); if (r < 0) { derr << "error storing zone params: " << cpp_strerror(-r) << dendl; return r; } r = store_info(true); if (r < 0) { derr << "error storing region info: " << cpp_strerror(-r) << dendl; return r; } return 0; } int RGWRegion::store_info(bool exclusive) { string pool_name; int ret = get_pool_name(cct, &pool_name); if (ret < 0) return ret; rgw_bucket pool(pool_name.c_str()); string oid = region_info_oid_prefix + name; bufferlist bl; ::encode(*this, bl); ret = rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(), exclusive, NULL, 0, NULL); return ret; } int RGWRegion::equals(const string& other_region) { if (is_master && other_region.empty()) return true; return (name == other_region); } void RGWZoneParams::init_default(RGWRados *store) { domain_root = ".rgw"; control_pool = ".rgw.control"; gc_pool = ".rgw.gc"; log_pool = ".log"; intent_log_pool = ".intent-log"; usage_log_pool = ".usage"; user_keys_pool = ".users"; user_email_pool = ".users.email"; user_swift_pool = ".users.swift"; user_uid_pool = ".users.uid"; /* check for old pools config */ rgw_obj obj(domain_root, avail_pools); int r = store->obj_stat(NULL, obj, NULL, NULL, NULL, NULL, NULL, NULL); if (r < 0) { ldout(store->ctx(), 0) << "couldn't find old data placement pools config, setting up new ones for the zone" << dendl; /* a new system, let's set new placement info */ RGWZonePlacementInfo default_placement; default_placement.index_pool = ".rgw.buckets.index"; default_placement.data_pool = ".rgw.buckets"; default_placement.data_extra_pool = ".rgw.buckets.extra"; placement_pools["default-placement"] = default_placement; } } int RGWZoneParams::get_pool_name(CephContext *cct, string *pool_name) { *pool_name = cct->_conf->rgw_zone_root_pool; if (pool_name->empty()) { *pool_name = RGW_DEFAULT_ZONE_ROOT_POOL; } else if ((*pool_name)[0] != '.') { derr << "ERROR: zone root pool name must start with a period" << dendl; return -EINVAL; } return 0; } void RGWZoneParams::init_name(CephContext *cct, RGWRegion& region) { name = cct->_conf->rgw_zone; if (name.empty()) { name = region.master_zone; if (name.empty()) { name = "default"; } } } int RGWZoneParams::init(CephContext *cct, RGWRados *store, RGWRegion& region) { init_name(cct, region); string pool_name; int ret = get_pool_name(cct, &pool_name); if (ret < 0) return ret; rgw_bucket pool(pool_name.c_str()); bufferlist bl; string oid = zone_info_oid_prefix + name; ret = rgw_get_system_obj(store, NULL, pool, oid, bl, NULL, NULL); if (ret < 0) return ret; try { bufferlist::iterator iter = bl.begin(); ::decode(*this, iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: failed to decode zone info from " << pool << ":" << oid << dendl; return -EIO; } is_master = (name == region.master_zone) || (region.master_zone.empty() && name == "default"); ldout(cct, 2) << "zone " << name << " is " << (is_master ? "" : "NOT ") << "master" << dendl; return 0; } int RGWZoneParams::store_info(CephContext *cct, RGWRados *store, RGWRegion& region) { init_name(cct, region); string pool_name; int ret = get_pool_name(cct, &pool_name); if (ret < 0) return ret; rgw_bucket pool(pool_name.c_str()); string oid = zone_info_oid_prefix + name; bufferlist bl; ::encode(*this, bl); ret = rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(), false, NULL, 0, NULL); return ret; } void RGWRegionMap::encode(bufferlist& bl) const { ENCODE_START(3, 1, bl); ::encode(regions, bl); ::encode(master_region, bl); ::encode(bucket_quota, bl); ::encode(user_quota, bl); ENCODE_FINISH(bl); } void RGWRegionMap::decode(bufferlist::iterator& bl) { DECODE_START(3, bl); ::decode(regions, bl); ::decode(master_region, bl); if (struct_v >= 2) ::decode(bucket_quota, bl); if (struct_v >= 3) ::decode(user_quota, bl); DECODE_FINISH(bl); regions_by_api.clear(); for (map::iterator iter = regions.begin(); iter != regions.end(); ++iter) { RGWRegion& region = iter->second; regions_by_api[region.api_name] = region; if (region.is_master) { master_region = region.name; } } } void RGWRegionMap::get_params(CephContext *cct, string& pool_name, string& oid) { pool_name = cct->_conf->rgw_zone_root_pool; if (pool_name.empty()) { pool_name = RGW_DEFAULT_ZONE_ROOT_POOL; } oid = region_map_oid; } int RGWRegionMap::read(CephContext *cct, RGWRados *store) { string pool_name, oid; get_params(cct, pool_name, oid); rgw_bucket pool(pool_name.c_str()); bufferlist bl; int ret = rgw_get_system_obj(store, NULL, pool, oid, bl, NULL, NULL); if (ret < 0) return ret; Mutex::Locker l(lock); try { bufferlist::iterator iter = bl.begin(); ::decode(*this, iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: failed to decode region map info from " << pool << ":" << oid << dendl; return -EIO; } return 0; } int RGWRegionMap::store(CephContext *cct, RGWRados *store) { string pool_name, oid; get_params(cct, pool_name, oid); rgw_bucket pool(pool_name.c_str()); Mutex::Locker l(lock); bufferlist bl; ::encode(*this, bl); int ret = rgw_put_system_obj(store, pool, oid, bl.c_str(), bl.length(), false, NULL, 0, NULL); return ret; } int RGWRegionMap::update(RGWRegion& region) { Mutex::Locker l(lock); if (region.is_master && !region.equals(master_region)) { derr << "cannot update region map, master_region conflict" << dendl; return -EINVAL; } map::iterator iter = regions.find(region.name); if (iter != regions.end()) { RGWRegion& old_region = iter->second; if (!old_region.api_name.empty()) { regions_by_api.erase(old_region.api_name); } } regions[region.name] = region; if (!region.api_name.empty()) { regions_by_api[region.api_name] = region; } if (region.is_master) { master_region = region.name; } return 0; } void RGWObjVersionTracker::prepare_op_for_read(ObjectReadOperation *op) { obj_version *check_objv = version_for_check(); if (check_objv) { cls_version_check(*op, *check_objv, VER_COND_EQ); } cls_version_read(*op, &read_version); } void RGWObjVersionTracker::prepare_op_for_write(ObjectWriteOperation *op) { obj_version *check_objv = version_for_check(); obj_version *modify_version = version_for_write(); if (check_objv) { cls_version_check(*op, *check_objv, VER_COND_EQ); } if (modify_version) { cls_version_set(*op, *modify_version); } else { cls_version_inc(*op); } } void RGWObjManifest::obj_iterator::operator++() { if (manifest->explicit_objs) { ++explicit_iter; if (explicit_iter == manifest->objs.end()) { ofs = manifest->obj_size; return; } update_explicit_pos(); update_location(); return; } uint64_t obj_size = manifest->get_obj_size(); uint64_t head_size = manifest->get_head_size(); if (ofs == obj_size) { return; } if (manifest->rules.empty()) { return; } /* are we still pointing at the head? */ if (ofs < head_size) { rule_iter = manifest->rules.begin(); RGWObjManifestRule *rule = &rule_iter->second; ofs = MIN(head_size, obj_size); stripe_ofs = ofs; cur_stripe = 1; stripe_size = MIN(obj_size - ofs, rule->stripe_max_size); if (rule->part_size > 0) { stripe_size = MIN(stripe_size, rule->part_size); } update_location(); return; } RGWObjManifestRule *rule = &rule_iter->second; stripe_ofs += rule->stripe_max_size; cur_stripe++; dout(20) << "RGWObjManifest::operator++(): rule->part_size=" << rule->part_size << " rules.size()=" << manifest->rules.size() << dendl; if (rule->part_size > 0) { /* multi part, multi stripes object */ dout(20) << "RGWObjManifest::operator++(): stripe_ofs=" << stripe_ofs << " part_ofs=" << part_ofs << " rule->part_size=" << rule->part_size << dendl; if (stripe_ofs >= part_ofs + rule->part_size) { /* moved to the next part */ cur_stripe = 0; part_ofs += rule->part_size; stripe_ofs = part_ofs; bool last_rule = (next_rule_iter == manifest->rules.end()); /* move to the next rule? */ if (!last_rule && stripe_ofs >= next_rule_iter->second.start_ofs) { rule_iter = next_rule_iter; last_rule = (next_rule_iter == manifest->rules.end()); if (!last_rule) { ++next_rule_iter; } cur_part_id = rule_iter->second.start_part_num; } else { cur_part_id++; } rule = &rule_iter->second; } stripe_size = MIN(rule->part_size - (stripe_ofs - part_ofs), rule->stripe_max_size); } cur_override_prefix = rule->override_prefix; ofs = stripe_ofs; if (ofs > obj_size) { ofs = obj_size; stripe_ofs = ofs; stripe_size = 0; } dout(0) << "RGWObjManifest::operator++(): result: ofs=" << ofs << " stripe_ofs=" << stripe_ofs << " part_ofs=" << part_ofs << " rule->part_size=" << rule->part_size << dendl; update_location(); } int RGWObjManifest::generator::create_begin(CephContext *cct, RGWObjManifest *_m, rgw_bucket& _b, rgw_obj& _h) { manifest = _m; bucket = _b; manifest->set_tail_bucket(_b); manifest->set_head(_h); last_ofs = 0; if (manifest->get_prefix().empty()) { char buf[33]; gen_rand_alphanumeric(cct, buf, sizeof(buf) - 1); string oid_prefix = "."; oid_prefix.append(buf); oid_prefix.append("_"); manifest->set_prefix(oid_prefix); } bool found = manifest->get_rule(0, &rule); if (!found) { derr << "ERROR: manifest->get_rule() could not find rule" << dendl; return -EIO; } uint64_t head_size = manifest->get_head_size(); if (head_size > 0) { cur_stripe_size = head_size; } else { cur_stripe_size = rule.stripe_max_size; } cur_part_id = rule.start_part_num; manifest->get_implicit_location(cur_part_id, cur_stripe, 0, NULL, &cur_obj); manifest->update_iterators(); return 0; } int RGWObjManifest::generator::create_next(uint64_t ofs) { if (ofs < last_ofs) /* only going forward */ return -EINVAL; string obj_name = manifest->prefix; uint64_t max_head_size = manifest->get_max_head_size(); if (ofs <= max_head_size) { manifest->set_head_size(ofs); } if (ofs >= max_head_size) { manifest->set_head_size(max_head_size); cur_stripe = (ofs - max_head_size) / rule.stripe_max_size; cur_stripe_size = rule.stripe_max_size; if (cur_part_id == 0 && max_head_size > 0) { cur_stripe++; } } last_ofs = ofs; manifest->set_obj_size(ofs); manifest->get_implicit_location(cur_part_id, cur_stripe, ofs, NULL, &cur_obj); manifest->update_iterators(); return 0; } const RGWObjManifest::obj_iterator& RGWObjManifest::obj_begin() { return begin_iter; } const RGWObjManifest::obj_iterator& RGWObjManifest::obj_end() { return end_iter; } RGWObjManifest::obj_iterator RGWObjManifest::obj_find(uint64_t ofs) { if (ofs > obj_size) { ofs = obj_size; } RGWObjManifest::obj_iterator iter(this); iter.seek(ofs); return iter; } int RGWObjManifest::append(RGWObjManifest& m) { if (explicit_objs || m.explicit_objs) { return append_explicit(m); } if (rules.empty()) { *this = m; return 0; } string override_prefix; if (prefix.empty()) { prefix = m.prefix; } if (prefix != m.prefix) { override_prefix = m.prefix; } map::iterator miter = m.rules.begin(); if (miter == m.rules.end()) { return append_explicit(m); } for (; miter != m.rules.end(); ++miter) { map::reverse_iterator last_rule = rules.rbegin(); RGWObjManifestRule& rule = last_rule->second; if (rule.part_size == 0) { rule.part_size = obj_size - rule.start_ofs; } RGWObjManifestRule& next_rule = miter->second; if (!next_rule.part_size) { next_rule.part_size = m.obj_size - next_rule.start_ofs; } string rule_prefix = prefix; if (!rule.override_prefix.empty()) { rule_prefix = rule.override_prefix; } string next_rule_prefix = m.prefix; if (!next_rule.override_prefix.empty()) { next_rule_prefix = next_rule.override_prefix; } if (rule.part_size != next_rule.part_size || rule.stripe_max_size != next_rule.stripe_max_size || rule_prefix != next_rule_prefix) { if (next_rule_prefix != prefix) { append_rules(m, miter, &next_rule_prefix); } else { append_rules(m, miter, NULL); } break; } uint64_t expected_part_num = rule.start_part_num + 1; if (rule.part_size > 0) { expected_part_num = rule.start_part_num + (obj_size + next_rule.start_ofs - rule.start_ofs) / rule.part_size; } if (expected_part_num != next_rule.start_part_num) { append_rules(m, miter, NULL); break; } } set_obj_size(obj_size + m.obj_size); return 0; } void RGWObjManifest::append_rules(RGWObjManifest& m, map::iterator& miter, string *override_prefix) { for (; miter != m.rules.end(); ++miter) { RGWObjManifestRule rule = miter->second; rule.start_ofs += obj_size; if (override_prefix) rule.override_prefix = *override_prefix; rules[rule.start_ofs] = rule; } } void RGWObjManifest::convert_to_explicit() { if (explicit_objs) { return; } obj_iterator iter = obj_begin(); while (iter != obj_end()) { RGWObjManifestPart& part = objs[iter.get_stripe_ofs()]; part.loc = iter.get_location(); part.loc_ofs = 0; uint64_t ofs = iter.get_stripe_ofs(); ++iter; uint64_t next_ofs = iter.get_stripe_ofs(); part.size = next_ofs - ofs; } explicit_objs = true; rules.clear(); prefix.clear(); } int RGWObjManifest::append_explicit(RGWObjManifest& m) { if (!explicit_objs) { convert_to_explicit(); } if (!m.explicit_objs) { m.convert_to_explicit(); } map::iterator iter; uint64_t base = obj_size; for (iter = m.objs.begin(); iter != m.objs.end(); ++iter) { RGWObjManifestPart& part = iter->second; objs[base + iter->first] = part; } obj_size += m.obj_size; return 0; } bool RGWObjManifest::get_rule(uint64_t ofs, RGWObjManifestRule *rule) { if (rules.empty()) { return false; } map::iterator iter = rules.upper_bound(ofs); if (iter != rules.begin()) { --iter; } *rule = iter->second; return true; } void RGWObjVersionTracker::generate_new_write_ver(CephContext *cct) { write_version.ver = 1; #define TAG_LEN 24 write_version.tag.clear(); append_rand_alpha(cct, write_version.tag, write_version.tag, TAG_LEN); } int RGWPutObjProcessor::complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) { int r = do_complete(etag, mtime, set_mtime, attrs); if (r < 0) return r; is_complete = true; return 0; } CephContext *RGWPutObjProcessor::ctx() { return store->ctx(); } RGWPutObjProcessor::~RGWPutObjProcessor() { if (is_complete) return; list::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { rgw_obj& obj = *iter; int r = store->delete_obj(obj_ctx, bucket_owner, obj); if (r < 0 && r != -ENOENT) { ldout(store->ctx(), 0) << "WARNING: failed to remove obj (" << obj << "), leaked" << dendl; } } } int RGWPutObjProcessor_Plain::prepare(RGWRados *store, void *obj_ctx, string *oid_rand) { RGWPutObjProcessor::prepare(store, obj_ctx, oid_rand); obj.init(bucket, obj_str); return 0; }; int RGWPutObjProcessor_Plain::handle_data(bufferlist& bl, off_t _ofs, MD5 *hash, void **phandle, bool *again) { assert(!hash); *again = false; if (ofs != _ofs) return -EINVAL; data.append(bl); ofs += bl.length(); return 0; } int RGWPutObjProcessor_Plain::do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) { RGWRados::PutObjMetaExtraParams params; params.set_mtime = set_mtime; params.mtime = mtime; params.data = &data; params.owner = bucket_owner; int r = store->put_obj_meta(obj_ctx, obj, data.length(), attrs, RGW_OBJ_CATEGORY_MAIN, PUT_OBJ_CREATE, params); return r; } int RGWPutObjProcessor_Aio::handle_obj_data(rgw_obj& obj, bufferlist& bl, off_t ofs, off_t abs_ofs, void **phandle, bool exclusive) { if ((uint64_t)abs_ofs + bl.length() > obj_len) obj_len = abs_ofs + bl.length(); // For the first call pass -1 as the offset to // do a write_full. int r = store->aio_put_obj_data(NULL, obj, bl, ((ofs != 0) ? ofs : -1), exclusive, phandle); return r; } struct put_obj_aio_info RGWPutObjProcessor_Aio::pop_pending() { struct put_obj_aio_info info; info = pending.front(); pending.pop_front(); return info; } int RGWPutObjProcessor_Aio::wait_pending_front() { if (pending.empty()) { return 0; } struct put_obj_aio_info info = pop_pending(); int ret = store->aio_wait(info.handle); return ret; } bool RGWPutObjProcessor_Aio::pending_has_completed() { if (pending.empty()) return false; struct put_obj_aio_info& info = pending.front(); return store->aio_completed(info.handle); } int RGWPutObjProcessor_Aio::drain_pending() { int ret = 0; while (!pending.empty()) { int r = wait_pending_front(); if (r < 0) ret = r; } return ret; } int RGWPutObjProcessor_Aio::throttle_data(void *handle, bool need_to_wait) { if (handle) { struct put_obj_aio_info info; info.handle = handle; pending.push_back(info); } size_t orig_size = pending.size(); /* first drain complete IOs */ while (pending_has_completed()) { int r = wait_pending_front(); if (r < 0) return r; need_to_wait = false; } /* resize window in case messages are draining too fast */ if (orig_size - pending.size() >= max_chunks) { max_chunks++; } /* now throttle. Note that need_to_wait should only affect the first IO operation */ if (pending.size() > max_chunks || need_to_wait) { int r = wait_pending_front(); if (r < 0) return r; need_to_wait = false; } return 0; } int RGWPutObjProcessor_Atomic::write_data(bufferlist& bl, off_t ofs, void **phandle, bool exclusive) { if (ofs >= next_part_ofs) { int r = prepare_next_part(ofs); if (r < 0) { return r; } } return RGWPutObjProcessor_Aio::handle_obj_data(cur_obj, bl, ofs - cur_part_ofs, ofs, phandle, exclusive); } int RGWPutObjProcessor_Atomic::handle_data(bufferlist& bl, off_t ofs, MD5 *hash, void **phandle, bool *again) { *again = false; *phandle = NULL; if (extra_data_len) { size_t extra_len = bl.length(); if (extra_len > extra_data_len) extra_len = extra_data_len; bufferlist extra; bl.splice(0, extra_len, &extra); extra_data_bl.append(extra); extra_data_len -= extra_len; if (bl.length() == 0) { return 0; } } uint64_t max_write_size = MIN(max_chunk_size, (uint64_t)next_part_ofs - data_ofs); pending_data_bl.claim_append(bl); if (pending_data_bl.length() < max_write_size) return 0; pending_data_bl.splice(0, max_write_size, &bl); /* do we have enough data pending accumulated that needs to be written? */ *again = (pending_data_bl.length() >= max_chunk_size); if (!data_ofs && !immutable_head()) { first_chunk.claim(bl); obj_len = (uint64_t)first_chunk.length(); if (hash) { hash->Update((const byte *)first_chunk.c_str(), obj_len); } int r = prepare_next_part(obj_len); if (r < 0) { return r; } data_ofs = obj_len; return 0; } off_t write_ofs = data_ofs; data_ofs = write_ofs + bl.length(); bool exclusive = (!write_ofs && immutable_head()); /* immutable head object, need to verify nothing exists there we could be racing with another upload, to the same object and cleanup can be messy */ int ret = write_data(bl, write_ofs, phandle, exclusive); if (ret >= 0) { /* we might return, need to clear bl as it was already sent */ if (hash) { hash->Update((const byte *)bl.c_str(), bl.length()); } bl.clear(); } return ret; } void RGWPutObjProcessor_Atomic::complete_hash(MD5 *hash) { hash->Update((const byte *)pending_data_bl.c_str(), pending_data_bl.length()); } int RGWPutObjProcessor_Atomic::prepare_init(RGWRados *store, void *obj_ctx, string *oid_rand) { RGWPutObjProcessor::prepare(store, obj_ctx, oid_rand); int r = store->get_max_chunk_size(bucket, &max_chunk_size); if (r < 0) { return r; } return 0; } int RGWPutObjProcessor_Atomic::prepare(RGWRados *store, void *obj_ctx, string *oid_rand) { int r = prepare_init(store, obj_ctx, oid_rand); if (r < 0) { return r; } head_obj.init(bucket, obj_str); manifest.set_trivial_rule(max_chunk_size, store->ctx()->_conf->rgw_obj_stripe_size); r = manifest_gen.create_begin(store->ctx(), &manifest, bucket, head_obj); if (r < 0) { return r; } return 0; } int RGWPutObjProcessor_Atomic::prepare_next_part(off_t ofs) { int ret = manifest_gen.create_next(ofs); if (ret < 0) { lderr(store->ctx()) << "ERROR: manifest_gen.create_next() returned ret=" << ret << dendl; return ret; } cur_part_ofs = ofs; next_part_ofs = ofs + manifest_gen.cur_stripe_max_size(); cur_obj = manifest_gen.get_cur_obj(); add_obj(cur_obj); return 0; }; int RGWPutObjProcessor_Atomic::complete_parts() { if (obj_len > (uint64_t)cur_part_ofs) { return prepare_next_part(obj_len); } return 0; } int RGWPutObjProcessor_Atomic::complete_writing_data() { if (!data_ofs && !immutable_head()) { first_chunk.claim(pending_data_bl); obj_len = (uint64_t)first_chunk.length(); } if (pending_data_bl.length()) { void *handle; int r = write_data(pending_data_bl, data_ofs, &handle, false); if (r < 0) { ldout(store->ctx(), 0) << "ERROR: write_data() returned " << r << dendl; return r; } r = throttle_data(handle, false); if (r < 0) { ldout(store->ctx(), 0) << "ERROR: throttle_data() returned " << r << dendl; return r; } } int r = complete_parts(); if (r < 0) { return r; } r = drain_pending(); if (r < 0) return r; return 0; } int RGWPutObjProcessor_Atomic::do_complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) { int r = complete_writing_data(); if (r < 0) return r; store->set_atomic(obj_ctx, head_obj); RGWRados::PutObjMetaExtraParams extra_params; extra_params.data = &first_chunk; extra_params.manifest = &manifest; extra_params.ptag = &unique_tag; /* use req_id as operation tag */ extra_params.mtime = mtime; extra_params.set_mtime = set_mtime; extra_params.owner = bucket_owner; r = store->put_obj_meta(obj_ctx, head_obj, obj_len, attrs, RGW_OBJ_CATEGORY_MAIN, PUT_OBJ_CREATE, extra_params); return r; } class RGWWatcher : public librados::WatchCtx { RGWRados *rados; public: RGWWatcher(RGWRados *r) : rados(r) {} void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { ldout(rados->ctx(), 10) << "RGWWatcher::notify() opcode=" << (int)opcode << " ver=" << ver << " bl.length()=" << bl.length() << dendl; rados->watch_cb(opcode, ver, bl); } }; RGWObjState *RGWRadosCtx::get_state(rgw_obj& obj) { if (obj.object.size()) { return &objs_state[obj]; } else { rgw_obj new_obj(store->zone.domain_root, obj.bucket.name); return &objs_state[new_obj]; } } void RGWRadosCtx::set_atomic(rgw_obj& obj) { if (obj.object.size()) { objs_state[obj].is_atomic = true; } else { rgw_obj new_obj(store->zone.domain_root, obj.bucket.name); objs_state[new_obj].is_atomic = true; } } void RGWRadosCtx::set_prefetch_data(rgw_obj& obj) { if (obj.object.size()) { objs_state[obj].prefetch_data = true; } else { rgw_obj new_obj(store->zone.domain_root, obj.bucket.name); objs_state[new_obj].prefetch_data = true; } } int RGWRados::get_required_alignment(rgw_bucket& bucket, uint64_t *alignment) { IoCtx ioctx; int r = open_bucket_data_ctx(bucket, ioctx); if (r < 0) { ldout(cct, 0) << "ERROR: open_bucket_data_ctx() returned " << r << dendl; return r; } *alignment = ioctx.pool_required_alignment(); return 0; } int RGWRados::get_max_chunk_size(rgw_bucket& bucket, uint64_t *max_chunk_size) { uint64_t alignment; int r = get_required_alignment(bucket, &alignment); if (r < 0) { return r; } uint64_t config_chunk_size = cct->_conf->rgw_max_chunk_size; if (alignment == 0) { *max_chunk_size = config_chunk_size; return 0; } if (config_chunk_size <= alignment) { *max_chunk_size = alignment; return 0; } *max_chunk_size = config_chunk_size - (config_chunk_size % alignment); return 0; } void RGWRados::finalize() { if (need_watch_notify()) { finalize_watch(); } delete meta_mgr; delete data_log; if (use_gc_thread) { gc->stop_processor(); delete gc; gc = NULL; } delete rest_master_conn; map::iterator iter; for (iter = zone_conn_map.begin(); iter != zone_conn_map.end(); ++iter) { RGWRESTConn *conn = iter->second; delete conn; } for (iter = region_conn_map.begin(); iter != region_conn_map.end(); ++iter) { RGWRESTConn *conn = iter->second; delete conn; } RGWQuotaHandler::free_handler(quota_handler); } /** * Initialize the RADOS instance and prepare to do other ops * Returns 0 on success, -ERR# on failure. */ int RGWRados::init_rados() { int ret; rados = new Rados(); if (!rados) return -ENOMEM; ret = rados->init_with_context(cct); if (ret < 0) return ret; ret = rados->connect(); if (ret < 0) return ret; meta_mgr = new RGWMetadataManager(cct, this); data_log = new RGWDataChangesLog(cct, this); return ret; } /** * Initialize the RADOS instance and prepare to do other ops * Returns 0 on success, -ERR# on failure. */ int RGWRados::init_complete() { int ret; ret = region.init(cct, this); if (ret < 0) return ret; ret = zone.init(cct, this, region); if (ret < 0) return ret; ret = region_map.read(cct, this); if (ret < 0) { if (ret != -ENOENT) { ldout(cct, 0) << "WARNING: cannot read region map" << dendl; } ret = region_map.update(region); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to update regionmap with local region info" << dendl; return -EIO; } } else { string master_region = region_map.master_region; if (master_region.empty()) { lderr(cct) << "ERROR: region map does not specify master region" << dendl; return -EINVAL; } map::iterator iter = region_map.regions.find(master_region); if (iter == region_map.regions.end()) { lderr(cct) << "ERROR: bad region map: inconsistent master region" << dendl; return -EINVAL; } RGWRegion& region = iter->second; rest_master_conn = new RGWRESTConn(cct, this, region.endpoints); for (iter = region_map.regions.begin(); iter != region_map.regions.end(); ++iter) { RGWRegion& region = iter->second; region_conn_map[region.name] = new RGWRESTConn(cct, this, region.endpoints); } } if (need_watch_notify()) { ret = init_watch(); if (ret < 0) { lderr(cct) << "ERROR: failed to initialize watch" << dendl; return ret; } } map::iterator ziter; for (ziter = region.zones.begin(); ziter != region.zones.end(); ++ziter) { const string& name = ziter->first; RGWZone& z = ziter->second; if (name != zone.name) { ldout(cct, 20) << "generating connection object for zone " << name << dendl; zone_conn_map[name] = new RGWRESTConn(cct, this, z.endpoints); } else { zone_public_config = z; } } ret = open_root_pool_ctx(); if (ret < 0) return ret; ret = open_gc_pool_ctx(); if (ret < 0) return ret; pools_initialized = true; gc = new RGWGC(); gc->initialize(cct, this); if (use_gc_thread) gc->start_processor(); quota_handler = RGWQuotaHandler::generate_handler(this, quota_threads); return ret; } /** * Initialize the RADOS instance and prepare to do other ops * Returns 0 on success, -ERR# on failure. */ int RGWRados::initialize() { int ret; ret = init_rados(); if (ret < 0) return ret; ret = init_complete(); return ret; } void RGWRados::finalize_watch() { for (int i = 0; i < num_watchers; i++) { string& notify_oid = notify_oids[i]; if (notify_oid.empty()) continue; uint64_t watch_handle = watch_handles[i]; control_pool_ctx.unwatch(notify_oid, watch_handle); RGWWatcher *watcher = watchers[i]; delete watcher; } delete[] notify_oids; delete[] watch_handles; delete[] watchers; } int RGWRados::list_raw_prefixed_objs(string pool_name, const string& prefix, list& result) { rgw_bucket pool(pool_name.c_str()); bool is_truncated; RGWListRawObjsCtx ctx; do { list oids; int r = list_raw_objects(pool, prefix, 1000, ctx, oids, &is_truncated); if (r < 0) { return r; } list::iterator iter; for (iter = oids.begin(); iter != oids.end(); ++iter) { string& val = *iter; if (val.size() > prefix.size()) result.push_back(val.substr(prefix.size())); } } while (is_truncated); return 0; } int RGWRados::list_regions(list& regions) { string pool_name; int ret = RGWRegion::get_pool_name(cct, &pool_name); if (ret < 0) return ret; return list_raw_prefixed_objs(pool_name, region_info_oid_prefix, regions); } int RGWRados::list_zones(list& zones) { string pool_name; int ret = RGWZoneParams::get_pool_name(cct, &pool_name); if (ret < 0) return ret; return list_raw_prefixed_objs(pool_name, zone_info_oid_prefix, zones); } /** * Open the pool used as root for this gateway * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::open_root_pool_ctx() { const string& pool = zone.domain_root.name; const char *pool_str = pool.c_str(); int r = rados->ioctx_create(pool_str, root_pool_ctx); if (r == -ENOENT) { r = rados->pool_create(pool_str); if (r == -EEXIST) r = 0; if (r < 0) return r; r = rados->ioctx_create(pool_str, root_pool_ctx); } return r; } int RGWRados::open_gc_pool_ctx() { const char *gc_pool = zone.gc_pool.name.c_str(); int r = rados->ioctx_create(gc_pool, gc_pool_ctx); if (r == -ENOENT) { r = rados->pool_create(gc_pool); if (r == -EEXIST) r = 0; if (r < 0) return r; r = rados->ioctx_create(gc_pool, gc_pool_ctx); } return r; } int RGWRados::init_watch() { const char *control_pool = zone.control_pool.name.c_str(); int r = rados->ioctx_create(control_pool, control_pool_ctx); if (r == -ENOENT) { r = rados->pool_create(control_pool); if (r == -EEXIST) r = 0; if (r < 0) return r; r = rados->ioctx_create(control_pool, control_pool_ctx); if (r < 0) return r; } num_watchers = cct->_conf->rgw_num_control_oids; bool compat_oid = (num_watchers == 0); if (num_watchers <= 0) num_watchers = 1; notify_oids = new string[num_watchers]; watchers = new RGWWatcher *[num_watchers]; watch_handles = new uint64_t[num_watchers]; for (int i=0; i < num_watchers; i++) { string& notify_oid = notify_oids[i]; notify_oid = notify_oid_prefix; if (!compat_oid) { char buf[16]; snprintf(buf, sizeof(buf), ".%d", i); notify_oid.append(buf); } r = control_pool_ctx.create(notify_oid, false); if (r < 0 && r != -EEXIST) return r; RGWWatcher *watcher = new RGWWatcher(this); watchers[i] = watcher; r = control_pool_ctx.watch(notify_oid, 0, &watch_handles[i], watcher); if (r < 0) return r; } watch_initialized = true; return 0; } void RGWRados::pick_control_oid(const string& key, string& notify_oid) { uint32_t r = ceph_str_hash_linux(key.c_str(), key.size()); int i = r % num_watchers; char buf[16]; snprintf(buf, sizeof(buf), ".%d", i); notify_oid = notify_oid_prefix; notify_oid.append(buf); } int RGWRados::open_bucket_pool_ctx(const string& bucket_name, const string& pool, librados::IoCtx& io_ctx) { int r = rados->ioctx_create(pool.c_str(), io_ctx); if (r != -ENOENT) return r; if (!pools_initialized) return r; r = rados->pool_create(pool.c_str()); if (r < 0 && r != -EEXIST) return r; r = rados->ioctx_create(pool.c_str(), io_ctx); return r; } int RGWRados::open_bucket_data_ctx(rgw_bucket& bucket, librados::IoCtx& data_ctx) { int r = open_bucket_pool_ctx(bucket.name, bucket.data_pool, data_ctx); if (r < 0) return r; return 0; } int RGWRados::open_bucket_data_extra_ctx(rgw_bucket& bucket, librados::IoCtx& data_ctx) { string& pool = (!bucket.data_extra_pool.empty() ? bucket.data_extra_pool : bucket.data_pool); int r = open_bucket_pool_ctx(bucket.name, pool, data_ctx); if (r < 0) return r; return 0; } int RGWRados::open_bucket_index_ctx(rgw_bucket& bucket, librados::IoCtx& index_ctx) { int r = open_bucket_pool_ctx(bucket.name, bucket.index_pool, index_ctx); if (r < 0) return r; return 0; } /** * set up a bucket listing. * handle is filled in. * Returns 0 on success, -ERR# otherwise. */ int RGWRados::list_buckets_init(RGWAccessHandle *handle) { librados::ObjectIterator *state = new librados::ObjectIterator(root_pool_ctx.objects_begin()); *handle = (RGWAccessHandle)state; return 0; } /** * get the next bucket in the listing. * obj is filled in, * handle is updated. * returns 0 on success, -ERR# otherwise. */ int RGWRados::list_buckets_next(RGWObjEnt& obj, RGWAccessHandle *handle) { librados::ObjectIterator *state = (librados::ObjectIterator *)*handle; do { if (*state == root_pool_ctx.objects_end()) { delete state; return -ENOENT; } obj.name = (*state)->first; (*state)++; } while (obj.name[0] == '.'); /* skip all entries starting with '.' */ return 0; } /**** logs ****/ struct log_list_state { string prefix; librados::IoCtx io_ctx; librados::ObjectIterator obit; }; int RGWRados::log_list_init(const string& prefix, RGWAccessHandle *handle) { log_list_state *state = new log_list_state; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, state->io_ctx); if (r < 0) { delete state; return r; } state->prefix = prefix; state->obit = state->io_ctx.objects_begin(); *handle = (RGWAccessHandle)state; return 0; } int RGWRados::log_list_next(RGWAccessHandle handle, string *name) { log_list_state *state = static_cast(handle); while (true) { if (state->obit == state->io_ctx.objects_end()) { delete state; return -ENOENT; } if (state->prefix.length() && state->obit->first.find(state->prefix) != 0) { state->obit++; continue; } *name = state->obit->first; state->obit++; break; } return 0; } int RGWRados::log_remove(const string& name) { librados::IoCtx io_ctx; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, io_ctx); if (r < 0) return r; return io_ctx.remove(name); } struct log_show_state { librados::IoCtx io_ctx; bufferlist bl; bufferlist::iterator p; string name; uint64_t pos; bool eof; log_show_state() : pos(0), eof(false) {} }; int RGWRados::log_show_init(const string& name, RGWAccessHandle *handle) { log_show_state *state = new log_show_state; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, state->io_ctx); if (r < 0) { delete state; return r; } state->name = name; *handle = (RGWAccessHandle)state; return 0; } int RGWRados::log_show_next(RGWAccessHandle handle, rgw_log_entry *entry) { log_show_state *state = static_cast(handle); off_t off = state->p.get_off(); ldout(cct, 10) << "log_show_next pos " << state->pos << " bl " << state->bl.length() << " off " << off << " eof " << (int)state->eof << dendl; // read some? unsigned chunk = 1024*1024; if ((state->bl.length() - off) < chunk/2 && !state->eof) { bufferlist more; int r = state->io_ctx.read(state->name, more, chunk, state->pos); if (r < 0) return r; state->pos += r; bufferlist old; try { old.substr_of(state->bl, off, state->bl.length() - off); } catch (buffer::error& err) { return -EINVAL; } state->bl.clear(); state->bl.claim(old); state->bl.claim_append(more); state->p = state->bl.begin(); if ((unsigned)r < chunk) state->eof = true; ldout(cct, 10) << " read " << r << dendl; } if (state->p.end()) return 0; // end of file try { ::decode(*entry, state->p); } catch (const buffer::error &e) { return -EINVAL; } return 1; } /** * usage_log_hash: get usage log key hash, based on name and index * * Get the usage object name. Since a user may have more than 1 * object holding that info (multiple shards), we use index to * specify that shard number. Once index exceeds max shards it * wraps. * If name is not being set, results for all users will be returned * and index will wrap only after total shards number. * * @param cct [in] ceph context * @param name [in] user name * @param hash [out] hash value * @param index [in] shard index number */ static void usage_log_hash(CephContext *cct, const string& name, string& hash, uint32_t index) { uint32_t val = index; if (!name.empty()) { int max_user_shards = max(cct->_conf->rgw_usage_max_user_shards, 1); val %= max_user_shards; val += ceph_str_hash_linux(name.c_str(), name.size()); } char buf[16]; int max_shards = max(cct->_conf->rgw_usage_max_shards, 1); snprintf(buf, sizeof(buf), RGW_USAGE_OBJ_PREFIX "%u", (unsigned)(val % max_shards)); hash = buf; } int RGWRados::log_usage(map& usage_info) { uint32_t index = 0; map log_objs; string hash; string last_user; /* restructure usage map, zone by object hash */ map::iterator iter; for (iter = usage_info.begin(); iter != usage_info.end(); ++iter) { const rgw_user_bucket& ub = iter->first; RGWUsageBatch& info = iter->second; if (ub.user.empty()) { ldout(cct, 0) << "WARNING: RGWRados::log_usage(): user name empty (bucket=" << ub.bucket << "), skipping" << dendl; continue; } if (ub.user != last_user) { /* index *should* be random, but why waste extra cycles in most cases max user shards is not going to exceed 1, so just incrementing it */ usage_log_hash(cct, ub.user, hash, index++); } last_user = ub.user; vector& v = log_objs[hash].entries; map::iterator miter; for (miter = info.m.begin(); miter != info.m.end(); ++miter) { v.push_back(miter->second); } } map::iterator liter; for (liter = log_objs.begin(); liter != log_objs.end(); ++liter) { int r = cls_obj_usage_log_add(liter->first, liter->second); if (r < 0) return r; } return 0; } int RGWRados::read_usage(string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, bool *is_truncated, RGWUsageIter& usage_iter, map& usage) { uint32_t num = max_entries; string hash, first_hash; usage_log_hash(cct, user, first_hash, 0); if (usage_iter.index) { usage_log_hash(cct, user, hash, usage_iter.index); } else { hash = first_hash; } usage.clear(); do { map ret_usage; map::iterator iter; int ret = cls_obj_usage_log_read(hash, user, start_epoch, end_epoch, num, usage_iter.read_iter, ret_usage, is_truncated); if (ret == -ENOENT) goto next; if (ret < 0) return ret; num -= ret_usage.size(); for (iter = ret_usage.begin(); iter != ret_usage.end(); ++iter) { usage[iter->first].aggregate(iter->second); } next: if (!*is_truncated) { usage_iter.read_iter.clear(); usage_log_hash(cct, user, hash, ++usage_iter.index); } } while (num && !*is_truncated && hash != first_hash); return 0; } int RGWRados::trim_usage(string& user, uint64_t start_epoch, uint64_t end_epoch) { uint32_t index = 0; string hash, first_hash; usage_log_hash(cct, user, first_hash, index); hash = first_hash; do { int ret = cls_obj_usage_log_trim(hash, user, start_epoch, end_epoch); if (ret == -ENOENT) goto next; if (ret < 0) return ret; next: usage_log_hash(cct, user, hash, ++index); } while (hash != first_hash); return 0; } void RGWRados::shard_name(const string& prefix, unsigned max_shards, const string& key, string& name) { uint32_t val = ceph_str_hash_linux(key.c_str(), key.size()); char buf[16]; snprintf(buf, sizeof(buf), "%u", (unsigned)(val % max_shards)); name = prefix + buf; } void RGWRados::shard_name(const string& prefix, unsigned max_shards, const string& section, const string& key, string& name) { uint32_t val = ceph_str_hash_linux(key.c_str(), key.size()); val ^= ceph_str_hash_linux(section.c_str(), section.size()); char buf[16]; snprintf(buf, sizeof(buf), "%u", (unsigned)(val % max_shards)); name = prefix + buf; } void RGWRados::time_log_prepare_entry(cls_log_entry& entry, const utime_t& ut, string& section, string& key, bufferlist& bl) { cls_log_add_prepare_entry(entry, ut, section, key, bl); } int RGWRados::time_log_add(const string& oid, const utime_t& ut, const string& section, const string& key, bufferlist& bl) { librados::IoCtx io_ctx; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, io_ctx); if (r == -ENOENT) { rgw_bucket pool(log_pool); r = create_pool(pool); if (r < 0) return r; // retry r = rados->ioctx_create(log_pool, io_ctx); } if (r < 0) return r; ObjectWriteOperation op; cls_log_add(op, ut, section, key, bl); r = io_ctx.operate(oid, &op); return r; } int RGWRados::time_log_add(const string& oid, list& entries) { librados::IoCtx io_ctx; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, io_ctx); if (r == -ENOENT) { rgw_bucket pool(log_pool); r = create_pool(pool); if (r < 0) return r; // retry r = rados->ioctx_create(log_pool, io_ctx); } if (r < 0) return r; ObjectWriteOperation op; cls_log_add(op, entries); r = io_ctx.operate(oid, &op); return r; } int RGWRados::time_log_list(const string& oid, utime_t& start_time, utime_t& end_time, int max_entries, list& entries, const string& marker, string *out_marker, bool *truncated) { librados::IoCtx io_ctx; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, io_ctx); if (r < 0) return r; librados::ObjectReadOperation op; cls_log_list(op, start_time, end_time, marker, max_entries, entries, out_marker, truncated); bufferlist obl; int ret = io_ctx.operate(oid, &op, &obl); if (ret < 0) return ret; return 0; } int RGWRados::time_log_info(const string& oid, cls_log_header *header) { librados::IoCtx io_ctx; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, io_ctx); if (r < 0) return r; librados::ObjectReadOperation op; cls_log_info(op, header); bufferlist obl; int ret = io_ctx.operate(oid, &op, &obl); if (ret < 0) return ret; return 0; } int RGWRados::time_log_trim(const string& oid, const utime_t& start_time, const utime_t& end_time, const string& from_marker, const string& to_marker) { librados::IoCtx io_ctx; const char *log_pool = zone.log_pool.name.c_str(); int r = rados->ioctx_create(log_pool, io_ctx); if (r < 0) return r; return cls_log_trim(io_ctx, oid, start_time, end_time, from_marker, to_marker); } int RGWRados::lock_exclusive(rgw_bucket& pool, const string& oid, utime_t& duration, string& zone_id, string& owner_id) { librados::IoCtx io_ctx; const char *pool_name = pool.name.c_str(); int r = rados->ioctx_create(pool_name, io_ctx); if (r < 0) return r; rados::cls::lock::Lock l(log_lock_name); l.set_duration(duration); l.set_cookie(owner_id); l.set_tag(zone_id); l.set_renew(true); return l.lock_exclusive(&io_ctx, oid); } int RGWRados::unlock(rgw_bucket& pool, const string& oid, string& zone_id, string& owner_id) { librados::IoCtx io_ctx; const char *pool_name = pool.name.c_str(); int r = rados->ioctx_create(pool_name, io_ctx); if (r < 0) return r; rados::cls::lock::Lock l(log_lock_name); l.set_tag(zone_id); l.set_cookie(owner_id); return l.unlock(&io_ctx, oid); } int RGWRados::decode_policy(bufferlist& bl, ACLOwner *owner) { bufferlist::iterator i = bl.begin(); RGWAccessControlPolicy policy(cct); try { policy.decode_owner(i); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl; return -EIO; } *owner = policy.get_owner(); return 0; } int rgw_policy_from_attrset(CephContext *cct, map& attrset, RGWAccessControlPolicy *policy) { map::iterator aiter = attrset.find(RGW_ATTR_ACL); if (aiter == attrset.end()) return -EIO; bufferlist& bl = aiter->second; bufferlist::iterator iter = bl.begin(); try { policy->decode(iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl; return -EIO; } if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) { RGWAccessControlPolicy_S3 *s3policy = static_cast(policy); ldout(cct, 15) << "Read AccessControlPolicy"; s3policy->to_xml(*_dout); *_dout << dendl; } return 0; } /** * get listing of the objects in a bucket. * bucket: bucket to list contents of * max: maximum number of results to return * prefix: only return results that match this prefix * delim: do not include results that match this string. * Any skipped results will have the matching portion of their name * inserted in common_prefixes with a "true" mark. * marker: if filled in, begin the listing with this object. * result: the objects are put in here. * common_prefixes: if delim is filled in, any matching prefixes are placed * here. */ int RGWRados::list_objects(rgw_bucket& bucket, int max, string& prefix, string& delim, string& marker, string *next_marker, vector& result, map& common_prefixes, bool get_content_type, string& ns, bool enforce_ns, bool *is_truncated, RGWAccessListFilter *filter) { int count = 0; bool truncated = true; if (bucket_is_system(bucket)) { return -EINVAL; } result.clear(); rgw_obj marker_obj, prefix_obj; marker_obj.set_ns(ns); marker_obj.set_obj(marker); string cur_marker = marker_obj.object; prefix_obj.set_ns(ns); prefix_obj.set_obj(prefix); string cur_prefix = prefix_obj.object; string bigger_than_delim; if (!delim.empty()) { unsigned long val = decode_utf8((unsigned char *)delim.c_str(), delim.size()); char buf[delim.size() + 16]; int r = encode_utf8(val + 1, (unsigned char *)buf); if (r < 0) { ldout(cct,0) << "ERROR: encode_utf8() failed" << dendl; return -EINVAL; } buf[r] = '\0'; bigger_than_delim = buf; } string skip_after_delim; /* if marker points at a common prefix, fast forward it into its upperbound string */ if (!delim.empty()) { int delim_pos = cur_marker.find(delim, prefix.size()); if (delim_pos >= 0) { cur_marker = cur_marker.substr(0, delim_pos); cur_marker.append(bigger_than_delim); } } while (truncated && count <= max) { if (skip_after_delim > cur_marker) { cur_marker = skip_after_delim; ldout(cct, 20) << "setting cur_marker=" << cur_marker << dendl; } std::map ent_map; int r = cls_bucket_list(bucket, cur_marker, cur_prefix, max + 1 - count, ent_map, &truncated, &cur_marker); if (r < 0) return r; std::map::iterator eiter; for (eiter = ent_map.begin(); eiter != ent_map.end(); ++eiter) { string obj = eiter->first; string key = obj; bool check_ns = rgw_obj::translate_raw_obj_to_obj_in_ns(obj, ns); if (enforce_ns && !check_ns) { if (!ns.empty()) { /* we've iterated past the namespace we're searching -- done now */ truncated = false; goto done; } /* we're not looking at the namespace this object is in, next! */ continue; } if (next_marker && count < max) { *next_marker = obj; } if (filter && !filter->filter(obj, key)) continue; if (prefix.size() && ((obj).compare(0, prefix.size(), prefix) != 0)) continue; if (!delim.empty()) { int delim_pos = obj.find(delim, prefix.size()); if (delim_pos >= 0) { string prefix_key = obj.substr(0, delim_pos + 1); if (common_prefixes.find(prefix_key) == common_prefixes.end()) { if (count >= max) { truncated = true; goto done; } if (next_marker) { *next_marker = prefix_key; } common_prefixes[prefix_key] = true; skip_after_delim = obj.substr(0, delim_pos); skip_after_delim.append(bigger_than_delim); ldout(cct, 20) << "skip_after_delim=" << skip_after_delim << dendl; count++; } continue; } } if (count >= max) { truncated = true; goto done; } RGWObjEnt ent = eiter->second; ent.name = obj; ent.ns = ns; result.push_back(ent); count++; } } done: if (is_truncated) *is_truncated = truncated; return 0; } /** * create a rados pool, associated meta info * returns 0 on success, -ERR# otherwise. */ int RGWRados::create_pool(rgw_bucket& bucket) { int ret = 0; string pool = bucket.index_pool; ret = rados->pool_create(pool.c_str(), 0); if (ret == -EEXIST) ret = 0; if (ret < 0) return ret; if (bucket.data_pool != pool) { ret = rados->pool_create(bucket.data_pool.c_str(), 0); if (ret == -EEXIST) ret = 0; if (ret < 0) return ret; } return 0; } int RGWRados::init_bucket_index(rgw_bucket& bucket) { librados::IoCtx index_ctx; // context for new bucket int r = open_bucket_index_ctx(bucket, index_ctx); if (r < 0) return r; string dir_oid = dir_oid_prefix; dir_oid.append(bucket.marker); librados::ObjectWriteOperation op; op.create(true); r = cls_rgw_init_index(index_ctx, op, dir_oid); if (r < 0 && r != -EEXIST) return r; return 0; } /** * create a bucket with name bucket and the given list of attrs * returns 0 on success, -ERR# otherwise. */ int RGWRados::create_bucket(RGWUserInfo& owner, rgw_bucket& bucket, const string& region_name, const string& placement_rule, map& attrs, RGWBucketInfo& info, obj_version *pobjv, obj_version *pep_objv, time_t creation_time, rgw_bucket *pmaster_bucket, bool exclusive) { #define MAX_CREATE_RETRIES 20 /* need to bound retries */ string selected_placement_rule; for (int i = 0; i < MAX_CREATE_RETRIES; i++) { int ret = 0; ret = select_bucket_placement(owner, region_name, placement_rule, bucket.name, bucket, &selected_placement_rule); if (ret < 0) return ret; bufferlist bl; uint32_t nop = 0; ::encode(nop, bl); const string& pool = zone.domain_root.name; const char *pool_str = pool.c_str(); librados::IoCtx id_io_ctx; int r = rados->ioctx_create(pool_str, id_io_ctx); if (r < 0) return r; if (!pmaster_bucket) { uint64_t iid = instance_id(); uint64_t bid = next_bucket_id(); char buf[zone.name.size() + 48]; snprintf(buf, sizeof(buf), "%s.%llu.%llu", zone.name.c_str(), (long long)iid, (long long)bid); bucket.marker = buf; bucket.bucket_id = bucket.marker; } else { bucket.marker = pmaster_bucket->marker; bucket.bucket_id = pmaster_bucket->bucket_id; } string dir_oid = dir_oid_prefix; dir_oid.append(bucket.marker); r = init_bucket_index(bucket); if (r < 0) return r; RGWObjVersionTracker& objv_tracker = info.objv_tracker; if (pobjv) { objv_tracker.write_version = *pobjv; } else { objv_tracker.generate_new_write_ver(cct); } info.bucket = bucket; info.owner = owner.user_id; info.region = region_name; info.placement_rule = selected_placement_rule; if (!creation_time) time(&info.creation_time); else info.creation_time = creation_time; ret = put_linked_bucket_info(info, exclusive, 0, pep_objv, &attrs, true); if (ret == -EEXIST) { /* we need to reread the info and return it, caller will have a use for it */ RGWObjVersionTracker instance_ver = info.objv_tracker; info.objv_tracker.clear(); r = get_bucket_info(NULL, bucket.name, info, NULL, NULL); if (r < 0) { if (r == -ENOENT) { continue; } ldout(cct, 0) << "get_bucket_info returned " << r << dendl; return r; } /* only remove it if it's a different bucket instance */ if (info.bucket.bucket_id != bucket.bucket_id) { /* remove bucket meta instance */ string entry; get_bucket_instance_entry(bucket, entry); r = rgw_bucket_instance_remove_entry(this, entry, &instance_ver); if (r < 0) return r; /* remove bucket index */ librados::IoCtx index_ctx; // context for new bucket int r = open_bucket_index_ctx(bucket, index_ctx); if (r < 0) return r; index_ctx.remove(dir_oid); } /* ret == -ENOENT here */ } return ret; } /* this is highly unlikely */ ldout(cct, 0) << "ERROR: could not create bucket, continuously raced with bucket creation and removal" << dendl; return -ENOENT; } int RGWRados::select_new_bucket_location(RGWUserInfo& user_info, const string& region_name, const string& request_rule, const string& bucket_name, rgw_bucket& bucket, string *pselected_rule) { /* first check that rule exists within the specific region */ map::iterator riter = region_map.regions.find(region_name); if (riter == region_map.regions.end()) { ldout(cct, 0) << "could not find region " << region_name << " in region map" << dendl; return -EINVAL; } /* now check that tag exists within region */ RGWRegion& region = riter->second; /* find placement rule. Hierarchy: request rule > user default rule > region default rule */ string rule = request_rule; if (rule.empty()) { rule = user_info.default_placement; if (rule.empty()) rule = region.default_placement; } if (rule.empty()) { ldout(cct, 0) << "misconfiguration, should not have an empty placement rule name" << dendl; return -EIO; } if (!rule.empty()) { map::iterator titer = region.placement_targets.find(rule); if (titer == region.placement_targets.end()) { ldout(cct, 0) << "could not find placement rule " << rule << " within region " << dendl; return -EINVAL; } /* now check tag for the rule, whether user is permitted to use rule */ RGWRegionPlacementTarget& target_rule = titer->second; if (!target_rule.user_permitted(user_info.placement_tags)) { ldout(cct, 0) << "user not permitted to use placement rule" << dendl; return -EPERM; } } if (pselected_rule) *pselected_rule = rule; return set_bucket_location_by_rule(rule, bucket_name, bucket); } int RGWRados::set_bucket_location_by_rule(const string& location_rule, const std::string& bucket_name, rgw_bucket& bucket) { bucket.name = bucket_name; if (location_rule.empty()) { /* we can only reach here if we're trying to set a bucket location from a bucket * created on a different zone, using a legacy / default pool configuration */ return select_legacy_bucket_placement(bucket_name, bucket); } /* * make sure that zone has this rule configured. We're * checking it for the local zone, because that's where this bucket object is going to * reside. */ map::iterator piter = zone.placement_pools.find(location_rule); if (piter == zone.placement_pools.end()) { /* couldn't find, means we cannot really place data for this bucket in this zone */ if (region.equals(region_name)) { /* that's a configuration error, zone should have that rule, as we're within the requested * region */ return -EINVAL; } else { /* oh, well, data is not going to be placed here, bucket object is just a placeholder */ return 0; } } RGWZonePlacementInfo& placement_info = piter->second; bucket.data_pool = placement_info.data_pool; bucket.data_extra_pool = placement_info.data_extra_pool; bucket.index_pool = placement_info.index_pool; return 0; } int RGWRados::select_bucket_placement(RGWUserInfo& user_info, const string& region_name, const string& placement_rule, const string& bucket_name, rgw_bucket& bucket, string *pselected_rule) { if (!zone.placement_pools.empty()) { return select_new_bucket_location(user_info, region_name, placement_rule, bucket_name, bucket, pselected_rule); } if (pselected_rule) pselected_rule->clear(); return select_legacy_bucket_placement(bucket_name, bucket); } int RGWRados::select_legacy_bucket_placement(const string& bucket_name, rgw_bucket& bucket) { bufferlist map_bl; map m; string pool_name; bool write_map = false; rgw_obj obj(zone.domain_root, avail_pools); int ret = rgw_get_system_obj(this, NULL, zone.domain_root, avail_pools, map_bl, NULL, NULL); if (ret < 0) { goto read_omap; } try { bufferlist::iterator iter = map_bl.begin(); ::decode(m, iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: couldn't decode avail_pools" << dendl; } read_omap: if (m.empty()) { bufferlist header; ret = omap_get_all(obj, header, m); write_map = true; } if (ret < 0 || m.empty()) { vector names; names.push_back(default_storage_pool); vector retcodes; bufferlist bl; ret = create_pools(names, retcodes); if (ret < 0) return ret; ret = omap_set(obj, default_storage_pool, bl); if (ret < 0) return ret; m[default_storage_pool] = bl; } if (write_map) { bufferlist new_bl; ::encode(m, new_bl); ret = put_obj_data(NULL, obj, new_bl.c_str(), -1, new_bl.length(), false); if (ret < 0) { ldout(cct, 0) << "WARNING: could not save avail pools map info ret=" << ret << dendl; } } map::iterator miter; if (m.size() > 1) { vector v; for (miter = m.begin(); miter != m.end(); ++miter) { v.push_back(miter->first); } uint32_t r; ret = get_random_bytes((char *)&r, sizeof(r)); if (ret < 0) return ret; int i = r % v.size(); pool_name = v[i]; } else { miter = m.begin(); pool_name = miter->first; } bucket.data_pool = pool_name; bucket.index_pool = pool_name; bucket.name = bucket_name; return 0; } int RGWRados::update_placement_map() { bufferlist header; map m; rgw_obj obj(zone.domain_root, avail_pools); int ret = omap_get_all(obj, header, m); if (ret < 0) return ret; bufferlist new_bl; ::encode(m, new_bl); ret = put_obj_data(NULL, obj, new_bl.c_str(), -1, new_bl.length(), false); if (ret < 0) { ldout(cct, 0) << "WARNING: could not save avail pools map info ret=" << ret << dendl; } return ret; } int RGWRados::add_bucket_placement(std::string& new_pool) { int ret = rados->pool_lookup(new_pool.c_str()); if (ret < 0) // DNE, or something return ret; rgw_obj obj(zone.domain_root, avail_pools); bufferlist empty_bl; ret = omap_set(obj, new_pool, empty_bl); // don't care about return value update_placement_map(); return ret; } int RGWRados::remove_bucket_placement(std::string& old_pool) { rgw_obj obj(zone.domain_root, avail_pools); int ret = omap_del(obj, old_pool); // don't care about return value update_placement_map(); return ret; } int RGWRados::list_placement_set(set& names) { bufferlist header; map m; rgw_obj obj(zone.domain_root, avail_pools); int ret = omap_get_all(obj, header, m); if (ret < 0) return ret; names.clear(); map::iterator miter; for (miter = m.begin(); miter != m.end(); ++miter) { names.insert(miter->first); } return names.size(); } int RGWRados::create_pools(vector& names, vector& retcodes) { vector::iterator iter; vector completions; vector rets; for (iter = names.begin(); iter != names.end(); ++iter) { librados::PoolAsyncCompletion *c = librados::Rados::pool_async_create_completion(); completions.push_back(c); string& name = *iter; int ret = rados->pool_create_async(name.c_str(), c); rets.push_back(ret); } vector::iterator riter; vector::iterator citer; assert(rets.size() == completions.size()); for (riter = rets.begin(), citer = completions.begin(); riter != rets.end(); ++riter, ++citer) { int r = *riter; PoolAsyncCompletion *c = *citer; if (r == 0) { c->wait(); r = c->get_return_value(); if (r < 0) { ldout(cct, 0) << "WARNING: async pool_create returned " << r << dendl; } } c->release(); retcodes.push_back(r); } return 0; } int RGWRados::get_obj_ioctx(const rgw_obj& obj, librados::IoCtx *ioctx) { rgw_bucket bucket; string oid, key; get_obj_bucket_and_oid_key(obj, bucket, oid, key); int r; if (!obj.is_in_extra_data()) { r = open_bucket_data_ctx(bucket, *ioctx); } else { r = open_bucket_data_extra_ctx(bucket, *ioctx); } if (r < 0) return r; ioctx->locator_set_key(key); return 0; } int RGWRados::get_obj_ref(const rgw_obj& obj, rgw_rados_ref *ref, rgw_bucket *bucket, bool ref_system_obj) { get_obj_bucket_and_oid_key(obj, *bucket, ref->oid, ref->key); int r; if (ref_system_obj && ref->oid.empty()) { ref->oid = bucket->name; *bucket = zone.domain_root; r = open_bucket_data_ctx(*bucket, ref->ioctx); } else if (!obj.is_in_extra_data()) { r = open_bucket_data_ctx(*bucket, ref->ioctx); } else { r = open_bucket_data_extra_ctx(*bucket, ref->ioctx); } if (r < 0) return r; ref->ioctx.locator_set_key(ref->key); return 0; } /** * Write/overwrite an object to the bucket storage. * bucket: the bucket to store the object in * obj: the object name/key * data: the object contents/value * size: the amount of data to write (data must be this long) * mtime: if non-NULL, writes the given mtime to the bucket storage * attrs: all the given attrs are written to bucket storage for the given object * exclusive: create object exclusively * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::put_obj_meta_impl(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, int flags, map* rmattrs, const bufferlist *data, RGWObjManifest *manifest, const string *ptag, list *remove_objs, bool modify_version, RGWObjVersionTracker *objv_tracker, time_t set_mtime, const string& bucket_owner) { rgw_bucket bucket; rgw_rados_ref ref; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) return r; RGWRadosCtx *rctx = static_cast(ctx); ObjectWriteOperation op; RGWObjState *state = NULL; if (flags & PUT_OBJ_EXCL) { if (!(flags & PUT_OBJ_CREATE)) return -EINVAL; op.create(true); // exclusive create } else { bool reset_obj = (flags & PUT_OBJ_CREATE) != 0; r = prepare_atomic_for_write(rctx, obj, op, &state, reset_obj, ptag); if (r < 0) return r; } if (objv_tracker) { objv_tracker->prepare_op_for_write(&op); } utime_t ut; if (set_mtime) { ut = utime_t(set_mtime, 0); } else { ut = ceph_clock_now(0); set_mtime = ut.sec(); } op.mtime(&set_mtime); if (data) { /* if we want to overwrite the data, we also want to overwrite the xattrs, so just remove the object */ op.write_full(*data); } string etag; string content_type; bufferlist acl_bl; map::iterator iter; if (rmattrs) { for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) { const string& name = iter->first; op.rmxattr(name.c_str()); } } if (manifest) { /* remove existing manifest attr */ iter = attrs.find(RGW_ATTR_MANIFEST); if (iter != attrs.end()) attrs.erase(iter); bufferlist bl; ::encode(*manifest, bl); op.setxattr(RGW_ATTR_MANIFEST, bl); } for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const string& name = iter->first; bufferlist& bl = iter->second; if (!bl.length()) continue; op.setxattr(name.c_str(), bl); if (name.compare(RGW_ATTR_ETAG) == 0) { etag = bl.c_str(); } else if (name.compare(RGW_ATTR_CONTENT_TYPE) == 0) { content_type = bl.c_str(); } else if (name.compare(RGW_ATTR_ACL) == 0) { acl_bl = bl; } } if (!op.size()) return 0; string index_tag; uint64_t epoch; int64_t poolid; if (state) { index_tag = state->write_tag; } r = prepare_update_index(NULL, bucket, CLS_RGW_OP_ADD, obj, index_tag); if (r < 0) return r; r = ref.ioctx.operate(ref.oid, &op); if (r < 0) /* we can expect to get -ECANCELED if object was replaced under, or -ENOENT if was removed, or -EEXIST if it did not exist before and now it does */ goto done_cancel; if (objv_tracker) { objv_tracker->apply_write(); } epoch = ref.ioctx.get_last_version(); poolid = ref.ioctx.get_id(); r = complete_atomic_overwrite(rctx, state, obj); if (r < 0) { ldout(cct, 0) << "ERROR: complete_atomic_overwrite returned r=" << r << dendl; } r = complete_update_index(bucket, obj.object, index_tag, poolid, epoch, size, ut, etag, content_type, &acl_bl, category, remove_objs); if (r < 0) goto done_cancel; if (mtime) { *mtime = set_mtime; } if (state) { /* update quota cache */ quota_handler->update_stats(bucket_owner, bucket, (state->exists ? 0 : 1), size, state->size); } return 0; done_cancel: int ret = complete_update_index_cancel(bucket, obj.object, index_tag); if (ret < 0) { ldout(cct, 0) << "ERROR: complete_update_index_cancel() returned ret=" << ret << dendl; } /* we lost in a race. There are a few options: * - existing object was rewritten (ECANCELED) * - non existing object was created (EEXIST) * - object was removed (ENOENT) * should treat it as a success */ if ((r == -ECANCELED || r == -ENOENT) || (!(flags & PUT_OBJ_EXCL) && r == -EEXIST)) { r = 0; } return r; } /** * Write/overwrite an object to the bucket storage. * bucket: the bucket to store the object in * obj: the object name/key * data: the object contents/value * offset: the offet to write to in the object * If this is -1, we will overwrite the whole object. * size: the amount of data to write (data must be this long) * attrs: all the given attrs are written to bucket storage for the given object * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::put_obj_data(void *ctx, rgw_obj& obj, const char *data, off_t ofs, size_t len, bool exclusive) { void *handle; bufferlist bl; bl.append(data, len); int r = aio_put_obj_data(ctx, obj, bl, ofs, exclusive, &handle); if (r < 0) return r; return aio_wait(handle); } int RGWRados::aio_put_obj_data(void *ctx, rgw_obj& obj, bufferlist& bl, off_t ofs, bool exclusive, void **handle) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); *handle = c; ObjectWriteOperation op; if (exclusive) op.create(true); if (ofs == -1) { op.write_full(bl); } else { op.write(ofs, bl); } r = ref.ioctx.aio_operate(ref.oid, c, &op); if (r < 0) return r; return 0; } int RGWRados::aio_wait(void *handle) { AioCompletion *c = (AioCompletion *)handle; c->wait_for_complete(); int ret = c->get_return_value(); c->release(); return ret; } bool RGWRados::aio_completed(void *handle) { AioCompletion *c = (AioCompletion *)handle; return c->is_complete(); } class RGWRadosPutObj : public RGWGetDataCB { rgw_obj obj; RGWPutObjProcessor_Atomic *processor; RGWOpStateSingleOp *opstate; void (*progress_cb)(off_t, void *); void *progress_data; public: RGWRadosPutObj(RGWPutObjProcessor_Atomic *p, RGWOpStateSingleOp *_ops, void (*_progress_cb)(off_t, void *), void *_progress_data) : processor(p), opstate(_ops), progress_cb(_progress_cb), progress_data(_progress_data) {} int handle_data(bufferlist& bl, off_t ofs, off_t len) { progress_cb(ofs, progress_data); bool again; bool need_opstate = true; do { void *handle; int ret = processor->handle_data(bl, ofs, NULL, &handle, &again); if (ret < 0) return ret; if (need_opstate && opstate) { /* need to update opstate repository with new state. This is ratelimited, so we're not * really doing it every time */ ret = opstate->renew_state(); if (ret < 0) { ldout(processor->ctx(), 0) << "ERROR: RGWRadosPutObj::handle_data(): failed to renew op state ret=" << ret << dendl; int r = processor->throttle_data(handle, false); if (r < 0) { ldout(processor->ctx(), 0) << "ERROR: RGWRadosPutObj::handle_data(): processor->throttle_data() returned " << r << dendl; } /* could not renew state! might have been marked as cancelled */ return ret; } need_opstate = false; } ret = processor->throttle_data(handle, false); if (ret < 0) return ret; } while (again); return 0; } void set_extra_data_len(uint64_t len) { RGWGetDataCB::set_extra_data_len(len); processor->set_extra_data_len(len); } int complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) { return processor->complete(etag, mtime, set_mtime, attrs); } }; /* * prepare attrset, either replace it with new attrs, or keep it (other than acls). */ static void set_copy_attrs(map& src_attrs, map& attrs, bool replace_attrs, bool intra_region) { if (replace_attrs) { if (!attrs[RGW_ATTR_ETAG].length()) attrs[RGW_ATTR_ETAG] = src_attrs[RGW_ATTR_ETAG]; src_attrs = attrs; } else { /* copying attrs from source, however acls should only be copied if it's intra-region operation */ if (!intra_region) src_attrs[RGW_ATTR_ACL] = attrs[RGW_ATTR_ACL]; } } class GetObjHandleDestructor { RGWRados *store; void **handle; public: GetObjHandleDestructor(RGWRados *_store) : store(_store), handle(NULL) {} ~GetObjHandleDestructor() { if (handle) { store->finish_get_obj(handle); } } void set_handle(void **_h) { handle = _h; } }; /** * Copy an object. * dest_obj: the object to copy into * src_obj: the object to copy from * attrs: if replace_attrs is set then these are placed on the new object * err: stores any errors resulting from the get of the original object * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::copy_obj(void *ctx, const string& user_id, const string& client_id, const string& op_id, req_info *info, const string& source_zone, rgw_obj& dest_obj, rgw_obj& src_obj, RGWBucketInfo& dest_bucket_info, RGWBucketInfo& src_bucket_info, time_t *mtime, const time_t *mod_ptr, const time_t *unmod_ptr, const char *if_match, const char *if_nomatch, bool replace_attrs, map& attrs, RGWObjCategory category, string *ptag, string *petag, struct rgw_err *err, void (*progress_cb)(off_t, void *), void *progress_data) { int ret; uint64_t total_len, obj_size; time_t lastmod; rgw_obj shadow_obj = dest_obj; string shadow_oid; bool remote_src; bool remote_dest; append_rand_alpha(cct, dest_obj.object, shadow_oid, 32); shadow_obj.init_ns(dest_obj.bucket, shadow_oid, shadow_ns); remote_dest = !region.equals(dest_bucket_info.region); remote_src = !region.equals(src_bucket_info.region); if (remote_src && remote_dest) { ldout(cct, 0) << "ERROR: can't copy object when both src and dest buckets are remote" << dendl; return -EINVAL; } ldout(cct, 5) << "Copy object " << src_obj.bucket << ":" << src_obj.object << " => " << dest_obj.bucket << ":" << dest_obj.object << dendl; void *handle = NULL; GetObjHandleDestructor handle_destructor(this); map src_attrs; off_t ofs = 0; off_t end = -1; if (!remote_src && source_zone.empty()) { ret = prepare_get_obj(ctx, src_obj, &ofs, &end, &src_attrs, mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &obj_size, NULL, &handle, err); if (ret < 0) return ret; handle_destructor.set_handle(&handle); } else { /* source is in a different region, copy it there */ RGWRESTStreamReadRequest *in_stream_req; string tag; append_rand_alpha(cct, tag, tag, 32); RGWPutObjProcessor_Atomic processor(dest_bucket_info.owner, dest_obj.bucket, dest_obj.object, cct->_conf->rgw_obj_stripe_size, tag); ret = processor.prepare(this, ctx, NULL); if (ret < 0) return ret; RGWRESTConn *conn; if (source_zone.empty()) { if (dest_bucket_info.region.empty()) { /* source is in the master region */ conn = rest_master_conn; } else { map::iterator iter = region_conn_map.find(src_bucket_info.region); if (iter == region_conn_map.end()) { ldout(cct, 0) << "could not find region connection to region: " << source_zone << dendl; return -ENOENT; } conn = iter->second; } } else { map::iterator iter = zone_conn_map.find(source_zone); if (iter == zone_conn_map.end()) { ldout(cct, 0) << "could not find zone connection to zone: " << source_zone << dendl; return -ENOENT; } conn = iter->second; } string obj_name = dest_obj.bucket.name + "/" + dest_obj.object; RGWOpStateSingleOp opstate(this, client_id, op_id, obj_name); int ret = opstate.set_state(RGWOpState::OPSTATE_IN_PROGRESS); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl; return ret; } RGWRadosPutObj cb(&processor, &opstate, progress_cb, progress_data); string etag; map req_headers; time_t set_mtime; ret = conn->get_obj(user_id, info, src_obj, true, &cb, &in_stream_req); if (ret < 0) goto set_err_state; ret = conn->complete_request(in_stream_req, etag, &set_mtime, req_headers); if (ret < 0) goto set_err_state; if (petag) { *petag = etag; } { /* opening scope so that we can do goto, sorry */ bufferlist& extra_data_bl = processor.get_extra_data(); if (extra_data_bl.length()) { JSONParser jp; if (!jp.parse(extra_data_bl.c_str(), extra_data_bl.length())) { ldout(cct, 0) << "failed to parse response extra data. len=" << extra_data_bl.length() << " data=" << extra_data_bl.c_str() << dendl; goto set_err_state; } JSONDecoder::decode_json("attrs", src_attrs, &jp); src_attrs.erase(RGW_ATTR_MANIFEST); // not interested in original object layout } } set_copy_attrs(src_attrs, attrs, replace_attrs, !source_zone.empty()); ret = cb.complete(etag, mtime, set_mtime, src_attrs); if (ret < 0) goto set_err_state; ret = opstate.set_state(RGWOpState::OPSTATE_COMPLETE); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl; } return 0; set_err_state: int r = opstate.set_state(RGWOpState::OPSTATE_ERROR); if (r < 0) { ldout(cct, 0) << "ERROR: failed to set opstate r=" << ret << dendl; } return ret; } set_copy_attrs(src_attrs, attrs, replace_attrs, false); src_attrs.erase(RGW_ATTR_ID_TAG); RGWObjManifest manifest; RGWObjState *astate = NULL; RGWRadosCtx *rctx = static_cast(ctx); ret = get_obj_state(rctx, src_obj, &astate, NULL); if (ret < 0) return ret; vector ref_objs; if (remote_dest) { /* dest is in a different region, copy it there */ string etag; RGWRESTStreamWriteRequest *out_stream_req; int ret = rest_master_conn->put_obj_init(user_id, dest_obj, astate->size, src_attrs, &out_stream_req); if (ret < 0) return ret; ret = get_obj_iterate(ctx, &handle, src_obj, 0, astate->size - 1, out_stream_req->get_out_cb()); if (ret < 0) return ret; ret = rest_master_conn->complete_request(out_stream_req, etag, mtime); if (ret < 0) return ret; if (petag) { *petag = etag; } return 0; } uint64_t max_chunk_size; ret = get_max_chunk_size(dest_obj.bucket, &max_chunk_size); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to get max_chunk_size() for bucket " << dest_obj.bucket << dendl; return ret; } bool copy_data = !astate->has_manifest || (src_obj.bucket.data_pool != dest_obj.bucket.data_pool); bool copy_first = false; if (astate->has_manifest) { if (!astate->manifest.has_tail()) { copy_data = true; } else { uint64_t head_size = astate->manifest.get_head_size(); if (head_size > 0) { if (head_size > max_chunk_size) copy_data = true; else copy_first = true; } } } if (copy_data) { /* refcounting tail wouldn't work here, just copy the data */ return copy_obj_data(ctx, dest_bucket_info.owner, &handle, end, dest_obj, src_obj, max_chunk_size, mtime, src_attrs, category, ptag, petag, err); } RGWObjManifest::obj_iterator miter = astate->manifest.obj_begin(); if (copy_first) // we need to copy first chunk, not increase refcount ++miter; rgw_rados_ref ref; rgw_bucket bucket; ret = get_obj_ref(miter.get_location(), &ref, &bucket); if (ret < 0) { return ret; } PutObjMetaExtraParams ep; bufferlist first_chunk; bool copy_itself = (dest_obj == src_obj); RGWObjManifest *pmanifest; ldout(cct, 0) << "dest_obj=" << dest_obj << " src_obj=" << src_obj << " copy_itself=" << (int)copy_itself << dendl; string tag; if (ptag) tag = *ptag; if (tag.empty()) { append_rand_alpha(cct, tag, tag, 32); } if (!copy_itself) { manifest = astate->manifest; rgw_bucket& tail_bucket = manifest.get_tail_bucket(); if (tail_bucket.name.empty()) { manifest.set_tail_bucket(src_obj.bucket); } string oid, key; for (; miter != astate->manifest.obj_end(); ++miter) { ObjectWriteOperation op; cls_refcount_get(op, tag, true); const rgw_obj& loc = miter.get_location(); get_obj_bucket_and_oid_key(loc, bucket, oid, key); ref.ioctx.locator_set_key(key); ret = ref.ioctx.operate(oid, &op); if (ret < 0) goto done_ret; ref_objs.push_back(loc); } pmanifest = &manifest; } else { pmanifest = &astate->manifest; /* don't send the object's tail for garbage collection */ astate->keep_tail = true; } if (copy_first) { ret = get_obj(ctx, NULL, &handle, src_obj, first_chunk, 0, max_chunk_size); if (ret < 0) goto done_ret; pmanifest->set_head(dest_obj); pmanifest->set_head_size(first_chunk.length()); } ep.data = &first_chunk; ep.manifest = pmanifest; ep.ptag = &tag; ep.owner = dest_bucket_info.owner; ret = put_obj_meta(ctx, dest_obj, end + 1, src_attrs, category, PUT_OBJ_CREATE, ep); if (mtime) obj_stat(ctx, dest_obj, NULL, mtime, NULL, NULL, NULL, NULL); if (petag) { map::iterator iter = src_attrs.find(RGW_ATTR_ETAG); if (iter != src_attrs.end()) { bufferlist& etagbl = iter->second; *petag = string(etagbl.c_str(), etagbl.length()); } } return 0; done_ret: if (!copy_itself) { vector::iterator riter; string oid, key; /* rollback reference */ for (riter = ref_objs.begin(); riter != ref_objs.end(); ++riter) { ObjectWriteOperation op; cls_refcount_put(op, tag, true); get_obj_bucket_and_oid_key(*riter, bucket, oid, key); ref.ioctx.locator_set_key(key); int r = ref.ioctx.operate(oid, &op); if (r < 0) { ldout(cct, 0) << "ERROR: cleanup after error failed to drop reference on obj=" << *riter << dendl; } } } return ret; } int RGWRados::copy_obj_data(void *ctx, const string& owner, void **handle, off_t end, rgw_obj& dest_obj, rgw_obj& src_obj, uint64_t max_chunk_size, time_t *mtime, map& attrs, RGWObjCategory category, string *ptag, string *petag, struct rgw_err *err) { bufferlist first_chunk; RGWObjManifest manifest; map objs; string tag; append_rand_alpha(cct, tag, tag, 32); RGWPutObjProcessor_Atomic processor(owner, dest_obj.bucket, dest_obj.object, cct->_conf->rgw_obj_stripe_size, tag); int ret = processor.prepare(this, ctx, NULL); if (ret < 0) return ret; off_t ofs = 0; do { bufferlist bl; ret = get_obj(ctx, NULL, handle, src_obj, bl, ofs, end); if (ret < 0) return ret; uint64_t read_len = ret; bool again; do { void *handle; ret = processor.handle_data(bl, ofs, NULL, &handle, &again); if (ret < 0) { return ret; } ret = processor.throttle_data(handle, false); if (ret < 0) return ret; } while (again); ofs += read_len; } while (ofs <= end); string etag; map::iterator iter = attrs.find(RGW_ATTR_ETAG); if (iter != attrs.end()) { bufferlist& bl = iter->second; etag = string(bl.c_str(), bl.length()); if (petag) { *petag = etag; } } ret = processor.complete(etag, NULL, 0, attrs); if (mtime) obj_stat(ctx, dest_obj, NULL, mtime, NULL, NULL, NULL, NULL); return ret; } /** * Check to see if the bucket metadata could be synced * bucket: the bucket to check * Returns false is the bucket is not synced */ bool RGWRados::is_syncing_bucket_meta(rgw_bucket& bucket) { /* region is not master region */ if (!region.is_master) { return false; } /* single region and a single zone */ if (region_map.regions.size() == 1 && region.zones.size() == 1) { return false; } /* zone is not master */ if (region.master_zone.compare(zone_name) != 0) { return false; } return true; } /** * Delete a bucket. * bucket: the name of the bucket to delete * Returns 0 on success, -ERR# otherwise. */ int RGWRados::delete_bucket(rgw_bucket& bucket, RGWObjVersionTracker& objv_tracker) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; std::map ent_map; string marker, prefix; bool is_truncated; do { #define NUM_ENTRIES 1000 r = cls_bucket_list(bucket, marker, prefix, NUM_ENTRIES, ent_map, &is_truncated, &marker); if (r < 0) return r; string ns; std::map::iterator eiter; string obj; for (eiter = ent_map.begin(); eiter != ent_map.end(); ++eiter) { obj = eiter->first; if (rgw_obj::translate_raw_obj_to_obj_in_ns(obj, ns)) return -ENOTEMPTY; } } while (is_truncated); r = rgw_bucket_delete_bucket_obj(this, bucket.name, objv_tracker); if (r < 0) return r; /* if the bucked is not synced we can remove the meta file */ if (!is_syncing_bucket_meta(bucket)) { RGWObjVersionTracker objv_tracker; string entry; get_bucket_instance_entry(bucket, entry); r= rgw_bucket_instance_remove_entry(this, entry, &objv_tracker); if (r < 0) { return r; } } return 0; } int RGWRados::set_bucket_owner(rgw_bucket& bucket, ACLOwner& owner) { RGWBucketInfo info; map attrs; int r = get_bucket_info(NULL, bucket.name, info, NULL, &attrs); if (r < 0) { ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl; return r; } info.owner = owner.get_id(); r = put_bucket_instance_info(info, false, 0, &attrs); if (r < 0) { ldout(cct, 0) << "NOTICE: put_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl; return r; } return 0; } int RGWRados::set_buckets_enabled(vector& buckets, bool enabled) { int ret = 0; vector::iterator iter; for (iter = buckets.begin(); iter != buckets.end(); ++iter) { rgw_bucket& bucket = *iter; if (enabled) ldout(cct, 20) << "enabling bucket name=" << bucket.name << dendl; else ldout(cct, 20) << "disabling bucket name=" << bucket.name << dendl; RGWBucketInfo info; map attrs; int r = get_bucket_info(NULL, bucket.name, info, NULL, &attrs); if (r < 0) { ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << ", skipping bucket" << dendl; ret = r; continue; } if (enabled) { info.flags &= ~BUCKET_SUSPENDED; } else { info.flags |= BUCKET_SUSPENDED; } r = put_bucket_instance_info(info, false, 0, &attrs); if (r < 0) { ldout(cct, 0) << "NOTICE: put_bucket_info on bucket=" << bucket.name << " returned err=" << r << ", skipping bucket" << dendl; ret = r; continue; } } return ret; } int RGWRados::bucket_suspended(rgw_bucket& bucket, bool *suspended) { RGWBucketInfo bucket_info; int ret = get_bucket_info(NULL, bucket.name, bucket_info, NULL); if (ret < 0) { return ret; } *suspended = ((bucket_info.flags & BUCKET_SUSPENDED) != 0); return 0; } int RGWRados::complete_atomic_overwrite(RGWRadosCtx *rctx, RGWObjState *state, rgw_obj& obj) { if (!state || !state->has_manifest || state->keep_tail) return 0; cls_rgw_obj_chain chain; RGWObjManifest::obj_iterator iter; for (iter = state->manifest.obj_begin(); iter != state->manifest.obj_end(); ++iter) { const rgw_obj& mobj = iter.get_location(); if (mobj == obj) continue; string oid, key; rgw_bucket bucket; get_obj_bucket_and_oid_key(mobj, bucket, oid, key); chain.push_obj(bucket.data_pool, oid, key); } string tag = state->obj_tag.c_str(); int ret = gc->send_chain(chain, tag, false); // do it async return ret; } int RGWRados::open_bucket_index(rgw_bucket& bucket, librados::IoCtx& index_ctx, string& bucket_oid) { if (bucket_is_system(bucket)) return -EINVAL; int r = open_bucket_index_ctx(bucket, index_ctx); if (r < 0) return r; if (bucket.marker.empty()) { ldout(cct, 0) << "ERROR: empty marker for bucket operation" << dendl; return -EIO; } bucket_oid = dir_oid_prefix; bucket_oid.append(bucket.marker); return 0; } static void translate_raw_stats(rgw_bucket_dir_header& header, map& stats) { map::iterator iter = header.stats.begin(); for (; iter != header.stats.end(); ++iter) { RGWObjCategory category = (RGWObjCategory)iter->first; RGWStorageStats& s = stats[category]; struct rgw_bucket_category_stats& header_stats = iter->second; s.category = (RGWObjCategory)iter->first; s.num_kb = ((header_stats.total_size + 1023) / 1024); s.num_kb_rounded = ((header_stats.total_size_rounded + 1023) / 1024); s.num_objects = header_stats.num_entries; } } int RGWRados::bucket_check_index(rgw_bucket& bucket, map *existing_stats, map *calculated_stats) { librados::IoCtx index_ctx; string oid; int ret = open_bucket_index(bucket, index_ctx, oid); if (ret < 0) return ret; rgw_bucket_dir_header existing_header; rgw_bucket_dir_header calculated_header; ret = cls_rgw_bucket_check_index_op(index_ctx, oid, &existing_header, &calculated_header); if (ret < 0) return ret; translate_raw_stats(existing_header, *existing_stats); translate_raw_stats(calculated_header, *calculated_stats); return 0; } int RGWRados::bucket_rebuild_index(rgw_bucket& bucket) { librados::IoCtx index_ctx; string oid; int ret = open_bucket_index(bucket, index_ctx, oid); if (ret < 0) return ret; return cls_rgw_bucket_rebuild_index_op(index_ctx, oid); } int RGWRados::defer_gc(void *ctx, rgw_obj& obj) { RGWRadosCtx *rctx = static_cast(ctx); rgw_bucket bucket; std::string oid, key; get_obj_bucket_and_oid_key(obj, bucket, oid, key); if (!rctx) return 0; RGWObjState *state = NULL; int r = get_obj_state(rctx, obj, &state, NULL); if (r < 0) return r; if (!state->is_atomic) { ldout(cct, 20) << "state for obj=" << obj << " is not atomic, not deferring gc operation" << dendl; return -EINVAL; } if (state->obj_tag.length() == 0) {// check for backward compatibility ldout(cct, 20) << "state->obj_tag is empty, not deferring gc operation" << dendl; return -EINVAL; } string tag = state->obj_tag.c_str(); ldout(cct, 0) << "defer chain tag=" << tag << dendl; return gc->defer_chain(tag, false); } /** * Delete an object. * bucket: name of the bucket storing the object * obj: name of the object to delete * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::delete_obj_impl(void *ctx, const string& bucket_owner, rgw_obj& obj, RGWObjVersionTracker *objv_tracker) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } RGWRadosCtx *rctx = static_cast(ctx); ObjectWriteOperation op; RGWObjState *state; r = prepare_atomic_for_write(rctx, obj, op, &state, false, NULL); if (r < 0) return r; bool ret_not_existed = (state && !state->exists); string tag; r = prepare_update_index(state, bucket, CLS_RGW_OP_DEL, obj, tag); if (r < 0) return r; if (objv_tracker) { objv_tracker->prepare_op_for_write(&op); } cls_refcount_put(op, tag, true); r = ref.ioctx.operate(ref.oid, &op); bool removed = (r >= 0); int64_t poolid = ref.ioctx.get_id(); if (r >= 0 || r == -ENOENT) { uint64_t epoch = ref.ioctx.get_last_version(); r = complete_update_index_del(bucket, obj.object, tag, poolid, epoch); } else { int ret = complete_update_index_cancel(bucket, obj.object, tag); if (ret < 0) { ldout(cct, 0) << "ERROR: complete_update_index_cancel returned ret=" << ret << dendl; } } if (removed) { int ret = complete_atomic_overwrite(rctx, state, obj); if (ret < 0) { ldout(cct, 0) << "ERROR: complete_atomic_removal returned ret=" << ret << dendl; } /* other than that, no need to propagate error */ } atomic_write_finish(state, r); if (r < 0) return r; if (ret_not_existed) return -ENOENT; if (state) { /* update quota cache */ quota_handler->update_stats(bucket_owner, bucket, -1, 0, state->size); } return 0; } int RGWRados::delete_obj(void *ctx, const string& bucket_owner, rgw_obj& obj, RGWObjVersionTracker *objv_tracker) { int r; r = delete_obj_impl(ctx, bucket_owner, obj, objv_tracker); if (r == -ECANCELED) r = 0; return r; } int RGWRados::delete_system_obj(void *ctx, rgw_obj& obj, RGWObjVersionTracker *objv_tracker) { int r; string no_owner; r = delete_obj_impl(ctx, no_owner, obj, objv_tracker); if (r == -ECANCELED) r = 0; return r; } int RGWRados::delete_obj_index(rgw_obj& obj) { rgw_bucket bucket; std::string oid, key; get_obj_bucket_and_oid_key(obj, bucket, oid, key); string tag; int r = complete_update_index_del(bucket, obj.object, tag, -1 /* pool */, 0); return r; } static void generate_fake_tag(CephContext *cct, map& attrset, RGWObjManifest& manifest, bufferlist& manifest_bl, bufferlist& tag_bl) { string tag; RGWObjManifest::obj_iterator mi = manifest.obj_begin(); if (mi != manifest.obj_end()) { if (manifest.has_tail()) // first object usually points at the head, let's skip to a more unique part ++mi; tag = mi.get_location().object; tag.append("_"); } unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE]; char md5_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; MD5 hash; hash.Update((const byte *)manifest_bl.c_str(), manifest_bl.length()); map::iterator iter = attrset.find(RGW_ATTR_ETAG); if (iter != attrset.end()) { bufferlist& bl = iter->second; hash.Update((const byte *)bl.c_str(), bl.length()); } hash.Final(md5); buf_to_hex(md5, CEPH_CRYPTO_MD5_DIGESTSIZE, md5_str); tag.append(md5_str); ldout(cct, 10) << "generate_fake_tag new tag=" << tag << dendl; tag_bl.append(tag.c_str(), tag.size() + 1); } int RGWRados::get_obj_state(RGWRadosCtx *rctx, rgw_obj& obj, RGWObjState **state, RGWObjVersionTracker *objv_tracker) { RGWObjState *s = rctx->get_state(obj); ldout(cct, 20) << "get_obj_state: rctx=" << (void *)rctx << " obj=" << obj << " state=" << (void *)s << " s->prefetch_data=" << s->prefetch_data << dendl; *state = s; if (s->has_attrs) return 0; int r = obj_stat(rctx, obj, &s->size, &s->mtime, &s->epoch, &s->attrset, (s->prefetch_data ? &s->data : NULL), objv_tracker); if (r == -ENOENT) { s->exists = false; s->has_attrs = true; s->mtime = 0; return 0; } if (r < 0) return r; s->exists = true; s->has_attrs = true; map::iterator iter = s->attrset.find(RGW_ATTR_SHADOW_OBJ); if (iter != s->attrset.end()) { bufferlist bl = iter->second; bufferlist::iterator it = bl.begin(); it.copy(bl.length(), s->shadow_obj); s->shadow_obj[bl.length()] = '\0'; } s->obj_tag = s->attrset[RGW_ATTR_ID_TAG]; bufferlist manifest_bl = s->attrset[RGW_ATTR_MANIFEST]; if (manifest_bl.length()) { bufferlist::iterator miter = manifest_bl.begin(); try { ::decode(s->manifest, miter); s->has_manifest = true; s->size = s->manifest.get_obj_size(); } catch (buffer::error& err) { ldout(cct, 20) << "ERROR: couldn't decode manifest" << dendl; return -EIO; } ldout(cct, 10) << "manifest: total_size = " << s->manifest.get_obj_size() << dendl; if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20) && s->manifest.has_explicit_objs()) { RGWObjManifest::obj_iterator mi; for (mi = s->manifest.obj_begin(); mi != s->manifest.obj_end(); ++mi) { ldout(cct, 20) << "manifest: ofs=" << mi.get_ofs() << " loc=" << mi.get_location() << dendl; } } if (!s->obj_tag.length()) { /* * Uh oh, something's wrong, object with manifest should have tag. Let's * create one out of the manifest, would be unique */ generate_fake_tag(cct, s->attrset, s->manifest, manifest_bl, s->obj_tag); s->fake_tag = true; } } if (s->obj_tag.length()) ldout(cct, 20) << "get_obj_state: setting s->obj_tag to " << s->obj_tag.c_str() << dendl; else ldout(cct, 20) << "get_obj_state: s->obj_tag was set empty" << dendl; return 0; } /** * Get the attributes for an object. * bucket: name of the bucket holding the object. * obj: name of the object * name: name of the attr to retrieve * dest: bufferlist to store the result in * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::get_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& dest) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket, true); if (r < 0) { return r; } RGWRadosCtx *rctx = static_cast(ctx); if (rctx) { RGWObjState *state; r = get_obj_state(rctx, obj, &state, NULL); if (r < 0) return r; if (!state->exists) return -ENOENT; if (state->get_attr(name, dest)) return 0; return -ENODATA; } ObjectReadOperation op; int rval; op.getxattr(name, &dest, &rval); r = ref.ioctx.operate(ref.oid, &op, NULL); if (r < 0) return r; return 0; } int RGWRados::append_atomic_test(RGWRadosCtx *rctx, rgw_obj& obj, ObjectOperation& op, RGWObjState **pstate) { if (!rctx) return 0; int r = get_obj_state(rctx, obj, pstate, NULL); if (r < 0) return r; RGWObjState *state = *pstate; if (!state->is_atomic) { ldout(cct, 20) << "state for obj=" << obj << " is not atomic, not appending atomic test" << dendl; return 0; } if (state->obj_tag.length() > 0 && !state->fake_tag) {// check for backward compatibility op.cmpxattr(RGW_ATTR_ID_TAG, LIBRADOS_CMPXATTR_OP_EQ, state->obj_tag); } else { ldout(cct, 20) << "state->obj_tag is empty, not appending atomic test" << dendl; } return 0; } int RGWRados::prepare_atomic_for_write_impl(RGWRadosCtx *rctx, rgw_obj& obj, ObjectWriteOperation& op, RGWObjState **pstate, bool reset_obj, const string *ptag) { int r = get_obj_state(rctx, obj, pstate, NULL); if (r < 0) return r; RGWObjState *state = *pstate; bool need_guard = (state->has_manifest || (state->obj_tag.length() != 0)) && (!state->fake_tag); if (!state->is_atomic) { ldout(cct, 20) << "prepare_atomic_for_write_impl: state is not atomic. state=" << (void *)state << dendl; if (reset_obj) { op.create(false); op.remove(); // we're not dropping reference here, actually removing object } return 0; } if (need_guard) { /* first verify that the object wasn't replaced under */ op.cmpxattr(RGW_ATTR_ID_TAG, LIBRADOS_CMPXATTR_OP_EQ, state->obj_tag); // FIXME: need to add FAIL_NOTEXIST_OK for racing deletion } if (reset_obj) { if (state->exists) { op.create(false); op.remove(); } else { op.create(true); } } if (ptag) { state->write_tag = *ptag; } else { append_rand_alpha(cct, state->write_tag, state->write_tag, 32); } bufferlist bl; bl.append(state->write_tag.c_str(), state->write_tag.size() + 1); ldout(cct, 10) << "setting object write_tag=" << state->write_tag << dendl; op.setxattr(RGW_ATTR_ID_TAG, bl); return 0; } int RGWRados::prepare_atomic_for_write(RGWRadosCtx *rctx, rgw_obj& obj, ObjectWriteOperation& op, RGWObjState **pstate, bool reset_obj, const string *ptag) { if (!rctx) { *pstate = NULL; return 0; } int r; r = prepare_atomic_for_write_impl(rctx, obj, op, pstate, reset_obj, ptag); return r; } /** * Set an attr on an object. * bucket: name of the bucket holding the object * obj: name of the object to set the attr on * name: the attr to set * bl: the contents of the attr * Returns: 0 on success, -ERR# otherwise. */ int RGWRados::set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl, RGWObjVersionTracker *objv_tracker) { map attrs; attrs[name] = bl; return set_attrs(ctx, obj, attrs, NULL, objv_tracker); } int RGWRados::set_attrs(void *ctx, rgw_obj& obj, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket, true); if (r < 0) { return r; } RGWRadosCtx *rctx = static_cast(ctx); ObjectWriteOperation op; RGWObjState *state = NULL; r = append_atomic_test(rctx, obj, op, &state); if (r < 0) return r; if (objv_tracker) { objv_tracker->prepare_op_for_write(&op); } map::iterator iter; if (rmattrs) { for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) { const string& name = iter->first; op.rmxattr(name.c_str()); } } for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const string& name = iter->first; bufferlist& bl = iter->second; if (!bl.length()) continue; op.setxattr(name.c_str(), bl); } if (!op.size()) return 0; string tag; bufferlist bl; if (state) { /* we don't pass state here, because we need to generate a new tag, not reuse the * same tag, otherwise we might race and clobber another operation on the same object */ r = prepare_update_index(NULL, bucket, CLS_RGW_OP_ADD, obj, tag); if (r < 0) return r; bl.append(tag.c_str(), tag.size() + 1); op.setxattr(RGW_ATTR_ID_TAG, bl); } r = ref.ioctx.operate(ref.oid, &op); if (state) { if (r >= 0) { bufferlist acl_bl = attrs[RGW_ATTR_ACL]; bufferlist etag_bl = attrs[RGW_ATTR_ETAG]; bufferlist content_type_bl = attrs[RGW_ATTR_CONTENT_TYPE]; string etag(etag_bl.c_str(), etag_bl.length()); string content_type(content_type_bl.c_str(), content_type_bl.length()); uint64_t epoch = ref.ioctx.get_last_version(); int64_t poolid = ref.ioctx.get_id(); utime_t mtime = ceph_clock_now(cct); r = complete_update_index(bucket, obj.object, tag, poolid, epoch, state->size, mtime, etag, content_type, &acl_bl, RGW_OBJ_CATEGORY_MAIN, NULL); } else { int ret = complete_update_index_cancel(bucket, obj.object, tag); if (ret < 0) { ldout(cct, 0) << "ERROR: comlete_update_index_cancel() returned r=" << r << dendl; } } } if (r < 0) return r; if (state) { state->obj_tag.swap(bl); if (rmattrs) { for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) { state->attrset.erase(iter->first); } } for (iter = attrs.begin(); iter != attrs.end(); ++iter) { state->attrset[iter->first] = iter->second; } } return 0; } /** * Get data about an object out of RADOS and into memory. * bucket: name of the bucket the object is in. * obj: name/key of the object to read * data: if get_data==true, this pointer will be set * to an address containing the object's data/value * ofs: the offset of the object to read from * end: the point in the object to stop reading * attrs: if non-NULL, the pointed-to map will contain * all the attrs of the object when this function returns * mod_ptr: if non-NULL, compares the object's mtime to *mod_ptr, * and if mtime is smaller it fails. * unmod_ptr: if non-NULL, compares the object's mtime to *unmod_ptr, * and if mtime is >= it fails. * if_match/nomatch: if non-NULL, compares the object's etag attr * to the string and, if it doesn't/does match, fails out. * get_data: if true, the object's data/value will be read out, otherwise not * err: Many errors will result in this structure being filled * with extra informatin on the error. * Returns: -ERR# on failure, otherwise * (if get_data==true) length of read data, * (if get_data==false) length of the object */ int RGWRados::prepare_get_obj(void *ctx, rgw_obj& obj, off_t *pofs, off_t *pend, map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, time_t *lastmod, const char *if_match, const char *if_nomatch, uint64_t *total_size, uint64_t *obj_size, RGWObjVersionTracker *objv_tracker, void **handle, struct rgw_err *err) { bufferlist etag; time_t ctime; RGWRadosCtx *rctx = static_cast(ctx); RGWRadosCtx *new_ctx = NULL; RGWObjState *astate = NULL; off_t ofs = 0; off_t end = -1; map::iterator iter; *handle = NULL; GetObjState *state = new GetObjState; if (!state) return -ENOMEM; *handle = state; int r = get_obj_ioctx(obj, &state->io_ctx); if (r < 0) { delete state; return r; } if (!rctx) { new_ctx = new RGWRadosCtx(this); rctx = new_ctx; } r = get_obj_state(rctx, obj, &astate, objv_tracker); if (r < 0) goto done_err; if (!astate->exists) { r = -ENOENT; goto done_err; } if (attrs) { *attrs = astate->attrset; if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) { for (iter = attrs->begin(); iter != attrs->end(); ++iter) { ldout(cct, 20) << "Read xattr: " << iter->first << dendl; } } if (r < 0) goto done_err; } /* Convert all times go GMT to make them compatible */ if (mod_ptr || unmod_ptr) { ctime = astate->mtime; if (mod_ptr) { ldout(cct, 10) << "If-Modified-Since: " << *mod_ptr << " Last-Modified: " << ctime << dendl; if (ctime < *mod_ptr) { r = -ERR_NOT_MODIFIED; goto done_err; } } if (unmod_ptr) { ldout(cct, 10) << "If-UnModified-Since: " << *unmod_ptr << " Last-Modified: " << ctime << dendl; if (ctime > *unmod_ptr) { r = -ERR_PRECONDITION_FAILED; goto done_err; } } } if (if_match || if_nomatch) { r = get_attr(rctx, obj, RGW_ATTR_ETAG, etag); if (r < 0) goto done_err; if (if_match) { string if_match_str = rgw_string_unquote(if_match); ldout(cct, 10) << "ETag: " << etag.c_str() << " " << " If-Match: " << if_match_str << dendl; if (if_match_str.compare(etag.c_str()) != 0) { r = -ERR_PRECONDITION_FAILED; goto done_err; } } if (if_nomatch) { string if_nomatch_str = rgw_string_unquote(if_nomatch); ldout(cct, 10) << "ETag: " << etag.c_str() << " " << " If-NoMatch: " << if_nomatch_str << dendl; if (if_nomatch_str.compare(etag.c_str()) == 0) { r = -ERR_NOT_MODIFIED; goto done_err; } } } if (pofs) ofs = *pofs; if (pend) end = *pend; if (ofs < 0) { ofs += astate->size; if (ofs < 0) ofs = 0; end = astate->size - 1; } else if (end < 0) { end = astate->size - 1; } if (astate->size > 0) { if (ofs >= (off_t)astate->size) { r = -ERANGE; goto done_err; } if (end >= (off_t)astate->size) { end = astate->size - 1; } } if (pofs) *pofs = ofs; if (pend) *pend = end; if (total_size) *total_size = (ofs <= end ? end + 1 - ofs : 0); if (obj_size) *obj_size = astate->size; if (lastmod) *lastmod = astate->mtime; delete new_ctx; return 0; done_err: delete new_ctx; finish_get_obj(handle); return r; } int RGWRados::prepare_update_index(RGWObjState *state, rgw_bucket& bucket, RGWModifyOp op, rgw_obj& obj, string& tag) { if (bucket_is_system(bucket)) return 0; int ret = data_log->add_entry(obj.bucket); if (ret < 0) { lderr(cct) << "ERROR: failed writing data log" << dendl; return ret; } if (state && state->obj_tag.length()) { int len = state->obj_tag.length(); char buf[len + 1]; memcpy(buf, state->obj_tag.c_str(), len); buf[len] = '\0'; tag = buf; } else { if (tag.empty()) { append_rand_alpha(cct, tag, tag, 32); } } ret = cls_obj_prepare_op(bucket, op, tag, obj.object, obj.key); return ret; } int RGWRados::complete_update_index(rgw_bucket& bucket, string& oid, string& tag, int64_t poolid, uint64_t epoch, uint64_t size, utime_t& ut, string& etag, string& content_type, bufferlist *acl_bl, RGWObjCategory category, list *remove_objs) { if (bucket_is_system(bucket)) return 0; RGWObjEnt ent; ent.name = oid; ent.size = size; ent.mtime = ut; ent.etag = etag; ACLOwner owner; if (acl_bl && acl_bl->length()) { int ret = decode_policy(*acl_bl, &owner); if (ret < 0) { ldout(cct, 0) << "WARNING: could not decode policy ret=" << ret << dendl; } } ent.owner = owner.get_id(); ent.owner_display_name = owner.get_display_name(); ent.content_type = content_type; int ret = cls_obj_complete_add(bucket, tag, poolid, epoch, ent, category, remove_objs); return ret; } int RGWRados::clone_objs_impl(void *ctx, rgw_obj& dst_obj, vector& ranges, map attrs, RGWObjCategory category, time_t *pmtime, bool truncate_dest, bool exclusive, pair *xattr_cond) { rgw_bucket bucket; std::string dst_oid, dst_key; get_obj_bucket_and_oid_key(dst_obj, bucket, dst_oid, dst_key); librados::IoCtx io_ctx; RGWRadosCtx *rctx = static_cast(ctx); uint64_t size = 0; string etag; string content_type; bufferlist acl_bl; bool update_index = (category == RGW_OBJ_CATEGORY_MAIN || category == RGW_OBJ_CATEGORY_MULTIMETA); int r = open_bucket_data_ctx(bucket, io_ctx); if (r < 0) return r; io_ctx.locator_set_key(dst_key); ObjectWriteOperation op; if (truncate_dest) { op.remove(); op.set_op_flags(OP_FAILOK); // don't fail if object didn't exist } op.create(exclusive); map::iterator iter; for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const string& name = iter->first; bufferlist& bl = iter->second; op.setxattr(name.c_str(), bl); if (name.compare(RGW_ATTR_ETAG) == 0) { etag = bl.c_str(); } else if (name.compare(RGW_ATTR_CONTENT_TYPE) == 0) { content_type = bl.c_str(); } else if (name.compare(RGW_ATTR_ACL) == 0) { acl_bl = bl; } } RGWObjState *state; r = prepare_atomic_for_write(rctx, dst_obj, op, &state, true, NULL); if (r < 0) return r; vector::iterator range_iter; for (range_iter = ranges.begin(); range_iter != ranges.end(); ++range_iter) { RGWCloneRangeInfo range = *range_iter; vector::iterator next_iter = range_iter; // merge ranges while (++next_iter != ranges.end()) { RGWCloneRangeInfo& next = *next_iter; if (range.src_ofs + (int64_t)range.len != next.src_ofs || range.dst_ofs + (int64_t)range.len != next.dst_ofs) break; range_iter = next_iter; range.len += next.len; } if (range.len) { ldout(cct, 20) << "calling op.clone_range(dst_ofs=" << range.dst_ofs << ", src.object=" << range.src.object << " range.src_ofs=" << range.src_ofs << " range.len=" << range.len << dendl; if (xattr_cond) { string src_cmp_obj, src_cmp_key; get_obj_bucket_and_oid_key(range.src, bucket, src_cmp_obj, src_cmp_key); op.src_cmpxattr(src_cmp_obj, xattr_cond->first.c_str(), LIBRADOS_CMPXATTR_OP_EQ, xattr_cond->second); } string src_oid, src_key; get_obj_bucket_and_oid_key(range.src, bucket, src_oid, src_key); if (range.dst_ofs + range.len > size) size = range.dst_ofs + range.len; op.clone_range(range.dst_ofs, src_oid, range.src_ofs, range.len); } } time_t mt; utime_t ut; if (pmtime) { op.mtime(pmtime); ut = utime_t(*pmtime, 0); } else { ut = ceph_clock_now(cct); mt = ut.sec(); op.mtime(&mt); } string tag; uint64_t epoch = 0; int64_t poolid = io_ctx.get_id(); int ret; if (update_index) { ret = prepare_update_index(state, bucket, CLS_RGW_OP_ADD, dst_obj, tag); if (ret < 0) goto done; } ret = io_ctx.operate(dst_oid, &op); epoch = io_ctx.get_last_version(); done: atomic_write_finish(state, ret); if (update_index) { if (ret >= 0) { ret = complete_update_index(bucket, dst_obj.object, tag, poolid, epoch, size, ut, etag, content_type, &acl_bl, category, NULL); } else { int r = complete_update_index_cancel(bucket, dst_obj.object, tag); if (r < 0) { ldout(cct, 0) << "ERROR: comlete_update_index_cancel() returned r=" << r << dendl; } } } return ret; } int RGWRados::clone_objs(void *ctx, rgw_obj& dst_obj, vector& ranges, map attrs, RGWObjCategory category, time_t *pmtime, bool truncate_dest, bool exclusive, pair *xattr_cond) { int r; r = clone_objs_impl(ctx, dst_obj, ranges, attrs, category, pmtime, truncate_dest, exclusive, xattr_cond); if (r == -ECANCELED) r = 0; return r; } int RGWRados::get_obj(void *ctx, RGWObjVersionTracker *objv_tracker, void **handle, rgw_obj& obj, bufferlist& bl, off_t ofs, off_t end) { rgw_bucket bucket; std::string oid, key; rgw_obj read_obj = obj; uint64_t read_ofs = ofs; uint64_t len, read_len; RGWRadosCtx *rctx = static_cast(ctx); RGWRadosCtx *new_ctx = NULL; bool reading_from_head = true; ObjectReadOperation op; GetObjState *state = *(GetObjState **)handle; RGWObjState *astate = NULL; bool merge_bl = false; bufferlist *pbl = &bl; bufferlist read_bl; uint64_t max_chunk_size; get_obj_bucket_and_oid_key(obj, bucket, oid, key); if (!rctx) { new_ctx = new RGWRadosCtx(this); rctx = new_ctx; } int r = get_obj_state(rctx, obj, &astate, NULL); if (r < 0) goto done_ret; if (end < 0) len = 0; else len = end - ofs + 1; if (astate->has_manifest && astate->manifest.has_tail()) { /* now get the relevant object part */ RGWObjManifest::obj_iterator iter = astate->manifest.obj_find(ofs); uint64_t stripe_ofs = iter.get_stripe_ofs(); read_obj = iter.get_location(); len = min(len, iter.get_stripe_size() - (ofs - stripe_ofs)); read_ofs = iter.location_ofs() + (ofs - stripe_ofs); reading_from_head = (read_obj == obj); if (!reading_from_head) { get_obj_bucket_and_oid_key(read_obj, bucket, oid, key); } } r = get_max_chunk_size(bucket, &max_chunk_size); if (r < 0) { ldout(cct, 0) << "ERROR: failed to get max_chunk_size() for bucket " << bucket << dendl; goto done_ret; } if (len > max_chunk_size) len = max_chunk_size; state->io_ctx.locator_set_key(key); read_len = len; if (reading_from_head) { /* only when reading from the head object do we need to do the atomic test */ r = append_atomic_test(rctx, read_obj, op, &astate); if (r < 0) goto done_ret; if (astate && astate->prefetch_data) { if (!ofs && astate->data.length() >= len) { bl = astate->data; goto done; } if (ofs < astate->data.length()) { unsigned copy_len = min((uint64_t)astate->data.length() - ofs, len); astate->data.copy(ofs, copy_len, bl); read_len -= copy_len; read_ofs += copy_len; if (!read_len) goto done; merge_bl = true; pbl = &read_bl; } } } if (objv_tracker) { objv_tracker->prepare_op_for_read(&op); } ldout(cct, 20) << "rados->read obj-ofs=" << ofs << " read_ofs=" << read_ofs << " read_len=" << read_len << dendl; op.read(read_ofs, read_len, pbl, NULL); r = state->io_ctx.operate(oid, &op, NULL); ldout(cct, 20) << "rados->read r=" << r << " bl.length=" << bl.length() << dendl; if (merge_bl) bl.append(read_bl); done: if (r >= 0) { r = bl.length(); } if (r < 0 || !len || ((off_t)(ofs + len - 1) == end)) { finish_get_obj(handle); } done_ret: delete new_ctx; return r; } struct get_obj_data; struct get_obj_aio_data { struct get_obj_data *op_data; off_t ofs; off_t len; }; struct get_obj_io { off_t len; bufferlist bl; }; static void _get_obj_aio_completion_cb(completion_t cb, void *arg); struct get_obj_data : public RefCountedObject { CephContext *cct; RGWRados *rados; void *ctx; IoCtx io_ctx; map io_map; map completion_map; uint64_t total_read; Mutex lock; Mutex data_lock; list aio_data; RGWGetDataCB *client_cb; atomic_t cancelled; atomic_t err_code; Throttle throttle; list read_list; get_obj_data(CephContext *_cct) : cct(_cct), rados(NULL), ctx(NULL), total_read(0), lock("get_obj_data"), data_lock("get_obj_data::data_lock"), client_cb(NULL), throttle(cct, "get_obj_data", cct->_conf->rgw_get_obj_window_size, false) {} virtual ~get_obj_data() { } void set_cancelled(int r) { cancelled.set(1); err_code.set(r); } bool is_cancelled() { return cancelled.read() == 1; } int get_err_code() { return err_code.read(); } int wait_next_io(bool *done) { lock.Lock(); map::iterator iter = completion_map.begin(); if (iter == completion_map.end()) { *done = true; lock.Unlock(); return 0; } off_t cur_ofs = iter->first; librados::AioCompletion *c = iter->second; lock.Unlock(); c->wait_for_complete_and_cb(); int r = c->get_return_value(); lock.Lock(); completion_map.erase(cur_ofs); if (completion_map.empty()) { *done = true; } lock.Unlock(); c->release(); return r; } void add_io(off_t ofs, off_t len, bufferlist **pbl, AioCompletion **pc) { Mutex::Locker l(lock); get_obj_io& io = io_map[ofs]; *pbl = &io.bl; struct get_obj_aio_data aio; aio.ofs = ofs; aio.len = len; aio.op_data = this; aio_data.push_back(aio); struct get_obj_aio_data *paio_data = &aio_data.back(); /* last element */ librados::AioCompletion *c = librados::Rados::aio_create_completion((void *)paio_data, _get_obj_aio_completion_cb, NULL); completion_map[ofs] = c; *pc = c; /* we have a reference per IO, plus one reference for the calling function. * reference is dropped for each callback, plus when we're done iterating * over the parts */ get(); } void cancel_io(off_t ofs) { ldout(cct, 20) << "get_obj_data::cancel_io() ofs=" << ofs << dendl; lock.Lock(); map::iterator iter = completion_map.find(ofs); if (iter != completion_map.end()) { AioCompletion *c = iter->second; c->release(); completion_map.erase(ofs); io_map.erase(ofs); } lock.Unlock(); /* we don't drop a reference here -- e.g., not calling d->put(), because we still * need IoCtx to live, as io callback may still be called */ } void cancel_all_io() { ldout(cct, 20) << "get_obj_data::cancel_all_io()" << dendl; Mutex::Locker l(lock); for (map::iterator iter = completion_map.begin(); iter != completion_map.end(); ++iter) { librados::AioCompletion *c = iter->second; c->release(); } } int get_complete_ios(off_t ofs, list& bl_list) { Mutex::Locker l(lock); map::iterator liter = io_map.begin(); if (liter == io_map.end() || liter->first != ofs) { return 0; } map::iterator aiter; aiter = completion_map.find(ofs); if (aiter == completion_map.end()) { /* completion map does not hold this io, it was cancelled */ return 0; } AioCompletion *completion = aiter->second; int r = completion->get_return_value(); if (r < 0) return r; for (; aiter != completion_map.end(); ++aiter) { completion = aiter->second; if (!completion->is_complete()) { /* reached a request that is not yet complete, stop */ break; } r = completion->get_return_value(); if (r < 0) { set_cancelled(r); /* mark it as cancelled, so that we don't continue processing next operations */ return r; } total_read += r; map::iterator old_liter = liter++; bl_list.push_back(old_liter->second.bl); io_map.erase(old_liter); } return 0; } }; static int _get_obj_iterate_cb(rgw_obj& obj, off_t obj_ofs, off_t read_ofs, off_t len, bool is_head_obj, RGWObjState *astate, void *arg) { struct get_obj_data *d = (struct get_obj_data *)arg; return d->rados->get_obj_iterate_cb(d->ctx, astate, obj, obj_ofs, read_ofs, len, is_head_obj, arg); } static void _get_obj_aio_completion_cb(completion_t cb, void *arg) { struct get_obj_aio_data *aio_data = (struct get_obj_aio_data *)arg; struct get_obj_data *d = aio_data->op_data; d->rados->get_obj_aio_completion_cb(cb, arg); } void RGWRados::get_obj_aio_completion_cb(completion_t c, void *arg) { struct get_obj_aio_data *aio_data = (struct get_obj_aio_data *)arg; struct get_obj_data *d = aio_data->op_data; off_t ofs = aio_data->ofs; off_t len = aio_data->len; list bl_list; list::iterator iter; int r; ldout(cct, 20) << "get_obj_aio_completion_cb: io completion ofs=" << ofs << " len=" << len << dendl; d->throttle.put(len); r = rados_aio_get_return_value(c); if (r < 0) { ldout(cct, 0) << "ERROR: got unexpected error when trying to read object: " << r << dendl; d->set_cancelled(r); goto done; } if (d->is_cancelled()) { goto done; } d->data_lock.Lock(); r = d->get_complete_ios(ofs, bl_list); if (r < 0) { goto done_unlock; } d->read_list.splice(d->read_list.end(), bl_list); done_unlock: d->data_lock.Unlock(); done: d->put(); return; } int RGWRados::flush_read_list(struct get_obj_data *d) { d->data_lock.Lock(); list l; l.swap(d->read_list); d->get(); d->read_list.clear(); d->data_lock.Unlock(); int r = 0; list::iterator iter; for (iter = l.begin(); iter != l.end(); ++iter) { bufferlist& bl = *iter; r = d->client_cb->handle_data(bl, 0, bl.length()); if (r < 0) { dout(0) << "ERROR: flush_read_list(): d->client_c->handle_data() returned " << r << dendl; break; } } d->data_lock.Lock(); d->put(); if (r < 0) { d->set_cancelled(r); } d->data_lock.Unlock(); return r; } int RGWRados::get_obj_iterate_cb(void *ctx, RGWObjState *astate, rgw_obj& obj, off_t obj_ofs, off_t read_ofs, off_t len, bool is_head_obj, void *arg) { RGWRadosCtx *rctx = static_cast(ctx); ObjectReadOperation op; struct get_obj_data *d = (struct get_obj_data *)arg; string oid, key; rgw_bucket bucket; bufferlist *pbl; AioCompletion *c; int r; if (is_head_obj) { /* only when reading from the head object do we need to do the atomic test */ r = append_atomic_test(rctx, obj, op, &astate); if (r < 0) return r; if (astate && obj_ofs < astate->data.length()) { unsigned chunk_len = min((uint64_t)astate->data.length() - obj_ofs, (uint64_t)len); d->data_lock.Lock(); r = d->client_cb->handle_data(astate->data, obj_ofs, chunk_len); d->data_lock.Unlock(); if (r < 0) return r; d->lock.Lock(); d->total_read += chunk_len; d->lock.Unlock(); len -= chunk_len; read_ofs += chunk_len; obj_ofs += chunk_len; if (!len) return 0; } } r = flush_read_list(d); if (r < 0) return r; get_obj_bucket_and_oid_key(obj, bucket, oid, key); d->throttle.get(len); if (d->is_cancelled()) { return d->get_err_code(); } /* add io after we check that we're not cancelled, otherwise we're going to have trouble * cleaning up */ d->add_io(obj_ofs, len, &pbl, &c); ldout(cct, 20) << "rados->get_obj_iterate_cb oid=" << oid << " obj-ofs=" << obj_ofs << " read_ofs=" << read_ofs << " len=" << len << dendl; op.read(read_ofs, len, pbl, NULL); librados::IoCtx io_ctx(d->io_ctx); io_ctx.locator_set_key(key); r = io_ctx.aio_operate(oid, c, &op, NULL); ldout(cct, 20) << "rados->aio_operate r=" << r << " bl.length=" << pbl->length() << dendl; if (r < 0) goto done_err; return 0; done_err: ldout(cct, 20) << "cancelling io r=" << r << " obj_ofs=" << obj_ofs << dendl; d->set_cancelled(r); d->cancel_io(obj_ofs); return r; } int RGWRados::get_obj_iterate(void *ctx, void **handle, rgw_obj& obj, off_t ofs, off_t end, RGWGetDataCB *cb) { struct get_obj_data *data = new get_obj_data(cct); bool done = false; GetObjState *state = *(GetObjState **)handle; data->rados = this; data->ctx = ctx; data->io_ctx.dup(state->io_ctx); data->client_cb = cb; int r = iterate_obj(ctx, obj, ofs, end, cct->_conf->rgw_get_obj_max_req_size, _get_obj_iterate_cb, (void *)data); if (r < 0) { data->cancel_all_io(); goto done; } while (!done) { r = data->wait_next_io(&done); if (r < 0) { dout(10) << "get_obj_iterate() r=" << r << ", canceling all io" << dendl; data->cancel_all_io(); break; } r = flush_read_list(data); if (r < 0) { dout(10) << "get_obj_iterate() r=" << r << ", canceling all io" << dendl; data->cancel_all_io(); break; } } done: data->put(); return r; } void RGWRados::finish_get_obj(void **handle) { if (*handle) { GetObjState *state = *(GetObjState **)handle; delete state; *handle = NULL; } } int RGWRados::iterate_obj(void *ctx, rgw_obj& obj, off_t ofs, off_t end, uint64_t max_chunk_size, int (*iterate_obj_cb)(rgw_obj&, off_t, off_t, off_t, bool, RGWObjState *, void *), void *arg) { rgw_bucket bucket; rgw_obj read_obj = obj; uint64_t read_ofs = ofs; uint64_t len; RGWRadosCtx *rctx = static_cast(ctx); RGWRadosCtx *new_ctx = NULL; bool reading_from_head = true; RGWObjState *astate = NULL; if (!rctx) { new_ctx = new RGWRadosCtx(this); rctx = new_ctx; } int r = get_obj_state(rctx, obj, &astate, NULL); if (r < 0) goto done_err; if (end < 0) len = 0; else len = end - ofs + 1; if (astate->has_manifest) { /* now get the relevant object stripe */ RGWObjManifest::obj_iterator iter = astate->manifest.obj_find(ofs); RGWObjManifest::obj_iterator obj_end = astate->manifest.obj_end(); for (; iter != obj_end && ofs <= end; ++iter) { off_t stripe_ofs = iter.get_stripe_ofs(); off_t next_stripe_ofs = stripe_ofs + iter.get_stripe_size(); while (ofs < next_stripe_ofs && ofs <= end) { read_obj = iter.get_location(); uint64_t read_len = min(len, iter.get_stripe_size() - (ofs - stripe_ofs)); read_ofs = iter.location_ofs() + (ofs - stripe_ofs); if (read_len > max_chunk_size) { read_len = max_chunk_size; } reading_from_head = (read_obj == obj); r = iterate_obj_cb(read_obj, ofs, read_ofs, read_len, reading_from_head, astate, arg); if (r < 0) goto done_err; len -= read_len; ofs += read_len; } } } else { while (ofs <= end) { uint64_t read_len = min(len, max_chunk_size); r = iterate_obj_cb(obj, ofs, ofs, read_len, reading_from_head, astate, arg); if (r < 0) goto done_err; len -= read_len; ofs += read_len; } } return 0; done_err: delete new_ctx; return r; } /* a simple object read */ int RGWRados::read(void *ctx, rgw_obj& obj, off_t ofs, size_t size, bufferlist& bl) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } RGWRadosCtx *rctx = static_cast(ctx); RGWObjState *astate = NULL; ObjectReadOperation op; r = append_atomic_test(rctx, obj, op, &astate); if (r < 0) return r; op.read(ofs, size, &bl, NULL); return ref.ioctx.operate(ref.oid, &op, NULL); } int RGWRados::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, uint64_t *epoch, map *attrs, bufferlist *first_chunk, RGWObjVersionTracker *objv_tracker) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } map unfiltered_attrset; uint64_t size = 0; time_t mtime = 0; ObjectReadOperation op; if (objv_tracker) { objv_tracker->prepare_op_for_read(&op); } op.getxattrs(&unfiltered_attrset, NULL); op.stat(&size, &mtime, NULL); if (first_chunk) { op.read(0, cct->_conf->rgw_max_chunk_size, first_chunk, NULL); } bufferlist outbl; r = ref.ioctx.operate(ref.oid, &op, &outbl); if (epoch) *epoch = ref.ioctx.get_last_version(); if (r < 0) return r; map attrset; map::iterator iter; string check_prefix = RGW_ATTR_PREFIX; for (iter = unfiltered_attrset.lower_bound(check_prefix); iter != unfiltered_attrset.end(); ++iter) { if (!str_startswith(iter->first, check_prefix)) break; attrset[iter->first] = iter->second; } if (psize) *psize = size; if (pmtime) *pmtime = mtime; if (attrs) *attrs = attrset; return 0; } int RGWRados::get_bucket_stats(rgw_bucket& bucket, uint64_t *bucket_ver, uint64_t *master_ver, map& stats, string *max_marker) { rgw_bucket_dir_header header; int r = cls_bucket_head(bucket, header); if (r < 0) return r; stats.clear(); translate_raw_stats(header, stats); *bucket_ver = header.ver; *master_ver = header.master_ver; if (max_marker) *max_marker = header.max_marker; return 0; } class RGWGetBucketStatsContext : public RGWGetDirHeader_CB { RGWGetBucketStats_CB *cb; public: RGWGetBucketStatsContext(RGWGetBucketStats_CB *_cb) : cb(_cb) {} void handle_response(int r, rgw_bucket_dir_header& header) { map stats; if (r >= 0) { translate_raw_stats(header, stats); cb->set_response(header.ver, header.master_ver, &stats, header.max_marker); } cb->handle_response(r); cb->put(); } }; int RGWRados::get_bucket_stats_async(rgw_bucket& bucket, RGWGetBucketStats_CB *ctx) { RGWGetBucketStatsContext *get_ctx = new RGWGetBucketStatsContext(ctx); int r = cls_bucket_head_async(bucket, get_ctx); if (r < 0) { ctx->put(); delete get_ctx; return r; } return 0; } class RGWGetUserStatsContext : public RGWGetUserHeader_CB { RGWGetUserStats_CB *cb; public: RGWGetUserStatsContext(RGWGetUserStats_CB *_cb) : cb(_cb) {} void handle_response(int r, cls_user_header& header) { cls_user_stats& hs = header.stats; if (r >= 0) { RGWStorageStats stats; stats.num_kb = (hs.total_bytes + 1023) / 1024; stats.num_kb_rounded = (hs.total_bytes_rounded + 1023) / 1024; stats.num_objects = hs.total_entries; cb->set_response(stats); } cb->handle_response(r); cb->put(); } }; int RGWRados::get_user_stats(const string& user, RGWStorageStats& stats) { cls_user_header header; int r = cls_user_get_header(user, &header); if (r < 0) return r; cls_user_stats& hs = header.stats; stats.num_kb = (hs.total_bytes + 1023) / 1024; stats.num_kb_rounded = (hs.total_bytes_rounded + 1023) / 1024; stats.num_objects = hs.total_entries; return 0; } int RGWRados::get_user_stats_async(const string& user, RGWGetUserStats_CB *ctx) { RGWGetUserStatsContext *get_ctx = new RGWGetUserStatsContext(ctx); int r = cls_user_get_header_async(user, get_ctx); if (r < 0) { ctx->put(); delete get_ctx; return r; } return 0; } void RGWRados::get_bucket_instance_entry(rgw_bucket& bucket, string& entry) { entry = bucket.name + ":" + bucket.bucket_id; } void RGWRados::get_bucket_meta_oid(rgw_bucket& bucket, string& oid) { string entry; get_bucket_instance_entry(bucket, entry); oid = RGW_BUCKET_INSTANCE_MD_PREFIX + entry; } void RGWRados::get_bucket_instance_obj(rgw_bucket& bucket, rgw_obj& obj) { if (!bucket.oid.empty()) { obj.init(zone.domain_root, bucket.oid); } else { string oid; get_bucket_meta_oid(bucket, oid); obj.init(zone.domain_root, oid); } } int RGWRados::get_bucket_instance_info(void *ctx, const string& meta_key, RGWBucketInfo& info, time_t *pmtime, map *pattrs) { int pos = meta_key.find(':'); if (pos < 0) { return -EINVAL; } string oid = RGW_BUCKET_INSTANCE_MD_PREFIX + meta_key; return get_bucket_instance_from_oid(ctx, oid, info, pmtime, pattrs); } int RGWRados::get_bucket_instance_info(void *ctx, rgw_bucket& bucket, RGWBucketInfo& info, time_t *pmtime, map *pattrs) { string oid; if (!bucket.oid.empty()) { get_bucket_meta_oid(bucket, oid); } else { oid = bucket.oid; } return get_bucket_instance_from_oid(ctx, oid, info, pmtime, pattrs); } int RGWRados::get_bucket_instance_from_oid(void *ctx, string& oid, RGWBucketInfo& info, time_t *pmtime, map *pattrs) { ldout(cct, 20) << "reading from " << zone.domain_root << ":" << oid << dendl; bufferlist epbl; int ret = rgw_get_system_obj(this, ctx, zone.domain_root, oid, epbl, &info.objv_tracker, pmtime, pattrs); if (ret < 0) { return ret; } bufferlist::iterator iter = epbl.begin(); try { ::decode(info, iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: could not decode buffer info, caught buffer::error" << dendl; return -EIO; } info.bucket.oid = oid; return 0; } int RGWRados::get_bucket_entrypoint_info(void *ctx, const string& bucket_name, RGWBucketEntryPoint& entry_point, RGWObjVersionTracker *objv_tracker, time_t *pmtime, map *pattrs) { bufferlist bl; int ret = rgw_get_system_obj(this, ctx, zone.domain_root, bucket_name, bl, objv_tracker, pmtime, pattrs); if (ret < 0) { return ret; } bufferlist::iterator iter = bl.begin(); try { ::decode(entry_point, iter); } catch (buffer::error& err) { ldout(cct, 0) << "ERROR: could not decode buffer info, caught buffer::error" << dendl; return -EIO; } return 0; } int RGWRados::convert_old_bucket_info(void *ctx, string& bucket_name) { RGWBucketEntryPoint entry_point; time_t ep_mtime; RGWObjVersionTracker ot; map attrs; RGWBucketInfo info; ldout(cct, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket_name << dendl; int ret = get_bucket_entrypoint_info(ctx, bucket_name, entry_point, &ot, &ep_mtime, &attrs); if (ret < 0) { ldout(cct, 0) << "ERROR: get_bucket_entrypont_info() returned " << ret << " bucket=" << bucket_name << dendl; return ret; } if (!entry_point.has_bucket_info) { /* already converted! */ return 0; } info = entry_point.old_bucket_info; info.bucket.oid = bucket_name; info.ep_objv = ot.read_version; ot.generate_new_write_ver(cct); ret = put_linked_bucket_info(info, false, ep_mtime, &ot.write_version, &attrs, true); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to put_linked_bucket_info(): " << ret << dendl; } return 0; } int RGWRados::get_bucket_info(void *ctx, const string& bucket_name, RGWBucketInfo& info, time_t *pmtime, map *pattrs) { bufferlist bl; RGWBucketEntryPoint entry_point; time_t ep_mtime; RGWObjVersionTracker ot; int ret = get_bucket_entrypoint_info(ctx, bucket_name, entry_point, &ot, &ep_mtime, pattrs); if (ret < 0) { info.bucket.name = bucket_name; /* only init this field */ return ret; } if (entry_point.has_bucket_info) { info = entry_point.old_bucket_info; info.bucket.oid = bucket_name; info.ep_objv = ot.read_version; ldout(cct, 20) << "rgw_get_bucket_info: old bucket info, bucket=" << info.bucket << " owner " << info.owner << dendl; return 0; } /* data is in the bucket instance object, we need to get attributes from there, clear everything * that we got */ if (pattrs) { pattrs->clear(); } ldout(cct, 20) << "rgw_get_bucket_info: bucket instance: " << entry_point.bucket << dendl; if (pattrs) pattrs->clear(); /* read bucket instance info */ string oid; get_bucket_meta_oid(entry_point.bucket, oid); ret = get_bucket_instance_from_oid(ctx, oid, info, pmtime, pattrs); info.ep_objv = ot.read_version; if (ret < 0) { info.bucket.name = bucket_name; return ret; } return 0; } int RGWRados::put_bucket_entrypoint_info(const string& bucket_name, RGWBucketEntryPoint& entry_point, bool exclusive, RGWObjVersionTracker& objv_tracker, time_t mtime, map *pattrs) { bufferlist epbl; ::encode(entry_point, epbl); return rgw_bucket_store_info(this, bucket_name, epbl, exclusive, pattrs, &objv_tracker, mtime); } int RGWRados::put_bucket_instance_info(RGWBucketInfo& info, bool exclusive, time_t mtime, map *pattrs) { info.has_instance_obj = true; bufferlist bl; ::encode(info, bl); string key; get_bucket_instance_entry(info.bucket, key); /* when we go through meta api, we don't use oid directly */ return rgw_bucket_instance_store_info(this, key, bl, exclusive, pattrs, &info.objv_tracker, mtime); } int RGWRados::put_linked_bucket_info(RGWBucketInfo& info, bool exclusive, time_t mtime, obj_version *pep_objv, map *pattrs, bool create_entry_point) { bufferlist bl; bool create_head = !info.has_instance_obj || create_entry_point; int ret = put_bucket_instance_info(info, exclusive, mtime, pattrs); if (ret < 0) { return ret; } if (!create_head) return 0; /* done! */ RGWBucketEntryPoint entry_point; entry_point.bucket = info.bucket; entry_point.owner = info.owner; entry_point.creation_time = info.creation_time; entry_point.linked = true; RGWObjVersionTracker ot; if (pep_objv && !pep_objv->tag.empty()) { ot.write_version = *pep_objv; } else { ot.generate_new_write_ver(cct); if (pep_objv) { *pep_objv = ot.write_version; } } ret = put_bucket_entrypoint_info(info.bucket.name, entry_point, exclusive, ot, mtime, NULL); if (ret < 0) return ret; return 0; } int RGWRados::omap_get_vals(rgw_obj& obj, bufferlist& header, const string& marker, uint64_t count, std::map& m) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } r = ref.ioctx.omap_get_vals(ref.oid, marker, count, &m); if (r < 0) return r; return 0; } int RGWRados::omap_get_all(rgw_obj& obj, bufferlist& header, std::map& m) { string start_after; return omap_get_vals(obj, header, start_after, (uint64_t)-1, m); } int RGWRados::omap_set(rgw_obj& obj, std::string& key, bufferlist& bl) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } ldout(cct, 15) << "omap_set bucket=" << bucket << " oid=" << ref.oid << " key=" << key << dendl; map m; m[key] = bl; r = ref.ioctx.omap_set(ref.oid, m); return r; } int RGWRados::omap_set(rgw_obj& obj, std::map& m) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } r = ref.ioctx.omap_set(ref.oid, m); return r; } int RGWRados::omap_del(rgw_obj& obj, const std::string& key) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } set k; k.insert(key); r = ref.ioctx.omap_rm_keys(ref.oid, k); return r; } int RGWRados::update_containers_stats(map& m) { map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt& ent = iter->second; rgw_bucket& bucket = ent.bucket; rgw_bucket_dir_header header; int r = cls_bucket_head(bucket, header); if (r < 0) return r; ent.count = 0; ent.size = 0; RGWObjCategory category = main_category; map::iterator iter = header.stats.find((uint8_t)category); if (iter != header.stats.end()) { struct rgw_bucket_category_stats& stats = iter->second; ent.count = stats.num_entries; ent.size = stats.total_size; ent.size_rounded = stats.total_size_rounded; } } return m.size(); } int RGWRados::append_async(rgw_obj& obj, size_t size, bufferlist& bl) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } librados::AioCompletion *completion = rados->aio_create_completion(NULL, NULL, NULL); r = ref.ioctx.aio_append(ref.oid, completion, bl, size); completion->release(); return r; } int RGWRados::distribute(const string& key, bufferlist& bl) { /* * we were called before watch was initialized. This can only happen if we're updating some system * config object (e.g., zone info) during init. Don't try to distribute the cache info for these * objects, they're currently only read on startup anyway. */ if (!watch_initialized) return 0; string notify_oid; pick_control_oid(key, notify_oid); ldout(cct, 10) << "distributing notification oid=" << notify_oid << " bl.length()=" << bl.length() << dendl; int r = control_pool_ctx.notify(notify_oid, 0, bl); return r; } int RGWRados::pool_iterate_begin(rgw_bucket& bucket, RGWPoolIterCtx& ctx) { librados::IoCtx& io_ctx = ctx.io_ctx; librados::ObjectIterator& iter = ctx.iter; int r = open_bucket_data_ctx(bucket, io_ctx); if (r < 0) return r; iter = io_ctx.objects_begin(); return 0; } int RGWRados::pool_iterate(RGWPoolIterCtx& ctx, uint32_t num, vector& objs, bool *is_truncated, RGWAccessListFilter *filter) { librados::IoCtx& io_ctx = ctx.io_ctx; librados::ObjectIterator& iter = ctx.iter; if (iter == io_ctx.objects_end()) return -ENOENT; uint32_t i; for (i = 0; i < num && iter != io_ctx.objects_end(); ++i, ++iter) { RGWObjEnt e; string oid = iter->first; ldout(cct, 20) << "RGWRados::pool_iterate: got " << oid << dendl; // fill it in with initial values; we may correct later if (filter && !filter->filter(oid, oid)) continue; e.name = oid; objs.push_back(e); } if (is_truncated) *is_truncated = (iter != io_ctx.objects_end()); return objs.size(); } struct RGWAccessListFilterPrefix : public RGWAccessListFilter { string prefix; RGWAccessListFilterPrefix(const string& _prefix) : prefix(_prefix) {} virtual bool filter(string& name, string& key) { return (prefix.compare(key.substr(0, prefix.size())) == 0); } }; int RGWRados::list_raw_objects(rgw_bucket& pool, const string& prefix_filter, int max, RGWListRawObjsCtx& ctx, list& oids, bool *is_truncated) { RGWAccessListFilterPrefix filter(prefix_filter); if (!ctx.initialized) { int r = pool_iterate_begin(pool, ctx.iter_ctx); if (r < 0) { lderr(cct) << "failed to list objects pool_iterate_begin() returned r=" << r << dendl; return r; } ctx.initialized = true; } vector objs; int r = pool_iterate(ctx.iter_ctx, max, objs, is_truncated, &filter); if (r < 0) { lderr(cct) << "failed to list objects pool_iterate returned r=" << r << dendl; return r; } vector::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { oids.push_back(iter->name); } return oids.size(); } int RGWRados::list_bi_log_entries(rgw_bucket& bucket, string& marker, uint32_t max, std::list& result, bool *truncated) { result.clear(); librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; std::list entries; int ret = cls_rgw_bi_log_list(index_ctx, oid, marker, max - result.size(), entries, truncated); if (ret < 0) return ret; std::list::iterator iter; for (iter = entries.begin(); iter != entries.end(); ++iter) { result.push_back(*iter); } return 0; } int RGWRados::trim_bi_log_entries(rgw_bucket& bucket, string& start_marker, string& end_marker) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; int ret = cls_rgw_bi_log_trim(index_ctx, oid, start_marker, end_marker); if (ret < 0) return ret; return 0; } int RGWRados::gc_operate(string& oid, librados::ObjectWriteOperation *op) { return gc_pool_ctx.operate(oid, op); } int RGWRados::gc_aio_operate(string& oid, librados::ObjectWriteOperation *op) { AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); int r = gc_pool_ctx.aio_operate(oid, c, op); c->release(); return r; } int RGWRados::gc_operate(string& oid, librados::ObjectReadOperation *op, bufferlist *pbl) { return gc_pool_ctx.operate(oid, op, pbl); } int RGWRados::list_gc_objs(int *index, string& marker, uint32_t max, bool expired_only, std::list& result, bool *truncated) { return gc->list(index, marker, max, expired_only, result, truncated); } int RGWRados::process_gc() { return gc->process(); } int RGWRados::cls_rgw_init_index(librados::IoCtx& index_ctx, librados::ObjectWriteOperation& op, string& oid) { bufferlist in; cls_rgw_bucket_init(op); int r = index_ctx.operate(oid, &op); return r; } int RGWRados::cls_obj_prepare_op(rgw_bucket& bucket, RGWModifyOp op, string& tag, string& name, string& locator) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; ObjectWriteOperation o; cls_rgw_bucket_prepare_op(o, op, tag, name, locator, zone_public_config.log_data); r = index_ctx.operate(oid, &o); return r; } int RGWRados::cls_obj_complete_op(rgw_bucket& bucket, RGWModifyOp op, string& tag, int64_t pool, uint64_t epoch, RGWObjEnt& ent, RGWObjCategory category, list *remove_objs) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; ObjectWriteOperation o; rgw_bucket_dir_entry_meta dir_meta; dir_meta.size = ent.size; dir_meta.mtime = utime_t(ent.mtime, 0); dir_meta.etag = ent.etag; dir_meta.owner = ent.owner; dir_meta.owner_display_name = ent.owner_display_name; dir_meta.content_type = ent.content_type; dir_meta.category = category; rgw_bucket_entry_ver ver; ver.pool = pool; ver.epoch = epoch; cls_rgw_bucket_complete_op(o, op, tag, ver, ent.name, dir_meta, remove_objs, zone_public_config.log_data); AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); r = index_ctx.aio_operate(oid, c, &o); c->release(); return r; } int RGWRados::cls_obj_complete_add(rgw_bucket& bucket, string& tag, int64_t pool, uint64_t epoch, RGWObjEnt& ent, RGWObjCategory category, list *remove_objs) { return cls_obj_complete_op(bucket, CLS_RGW_OP_ADD, tag, pool, epoch, ent, category, remove_objs); } int RGWRados::cls_obj_complete_del(rgw_bucket& bucket, string& tag, int64_t pool, uint64_t epoch, string& name) { RGWObjEnt ent; ent.name = name; return cls_obj_complete_op(bucket, CLS_RGW_OP_DEL, tag, pool, epoch, ent, RGW_OBJ_CATEGORY_NONE, NULL); } int RGWRados::cls_obj_complete_cancel(rgw_bucket& bucket, string& tag, string& name) { RGWObjEnt ent; ent.name = name; return cls_obj_complete_op(bucket, CLS_RGW_OP_CANCEL, tag, -1 /* pool id */, 0, ent, RGW_OBJ_CATEGORY_NONE, NULL); } int RGWRados::cls_obj_set_bucket_tag_timeout(rgw_bucket& bucket, uint64_t timeout) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; ObjectWriteOperation o; cls_rgw_bucket_set_tag_timeout(o, timeout); r = index_ctx.operate(oid, &o); return r; } int RGWRados::cls_bucket_list(rgw_bucket& bucket, string start, string prefix, uint32_t num, map& m, bool *is_truncated, string *last_entry, bool (*force_check_filter)(const string& name)) { ldout(cct, 10) << "cls_bucket_list " << bucket << " start " << start << " num " << num << dendl; librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; struct rgw_bucket_dir dir; r = cls_rgw_list_op(index_ctx, oid, start, prefix, num, &dir, is_truncated); if (r < 0) return r; map::iterator miter; bufferlist updates; for (miter = dir.m.begin(); miter != dir.m.end(); ++miter) { RGWObjEnt e; rgw_bucket_dir_entry& dirent = miter->second; // fill it in with initial values; we may correct later e.name = dirent.name; e.size = dirent.meta.size; e.mtime = dirent.meta.mtime; e.etag = dirent.meta.etag; e.owner = dirent.meta.owner; e.owner_display_name = dirent.meta.owner_display_name; e.content_type = dirent.meta.content_type; e.tag = dirent.tag; /* oh, that shouldn't happen! */ if (e.name.empty()) { ldout(cct, 0) << "WARNING: got empty dirent name, skipping" << dendl; continue; } bool force_check = force_check_filter && force_check_filter(dirent.name); if (!dirent.exists || !dirent.pending_map.empty() || force_check) { /* there are uncommitted ops. We need to check the current state, * and if the tags are old we need to do cleanup as well. */ librados::IoCtx sub_ctx; sub_ctx.dup(index_ctx); r = check_disk_state(sub_ctx, bucket, dirent, e, updates); if (r < 0) { if (r == -ENOENT) continue; else return r; } } m[e.name] = e; ldout(cct, 10) << "RGWRados::cls_bucket_list: got " << e.name << dendl; } if (dir.m.size()) { *last_entry = dir.m.rbegin()->first; } if (updates.length()) { ObjectWriteOperation o; cls_rgw_suggest_changes(o, updates); // we don't care if we lose suggested updates, send them off blindly AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); r = index_ctx.aio_operate(oid, c, &o); c->release(); } return m.size(); } int RGWRados::cls_obj_usage_log_add(const string& oid, rgw_usage_log_info& info) { librados::IoCtx io_ctx; const char *usage_log_pool = zone.usage_log_pool.name.c_str(); int r = rados->ioctx_create(usage_log_pool, io_ctx); if (r == -ENOENT) { rgw_bucket pool(usage_log_pool); r = create_pool(pool); if (r < 0) return r; // retry r = rados->ioctx_create(usage_log_pool, io_ctx); } if (r < 0) return r; ObjectWriteOperation op; cls_rgw_usage_log_add(op, info); r = io_ctx.operate(oid, &op); return r; } int RGWRados::cls_obj_usage_log_read(string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, string& read_iter, map& usage, bool *is_truncated) { librados::IoCtx io_ctx; *is_truncated = false; const char *usage_log_pool = zone.usage_log_pool.name.c_str(); int r = rados->ioctx_create(usage_log_pool, io_ctx); if (r < 0) return r; r = cls_rgw_usage_log_read(io_ctx, oid, user, start_epoch, end_epoch, max_entries, read_iter, usage, is_truncated); return r; } int RGWRados::cls_obj_usage_log_trim(string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch) { librados::IoCtx io_ctx; const char *usage_log_pool = zone.usage_log_pool.name.c_str(); int r = rados->ioctx_create(usage_log_pool, io_ctx); if (r < 0) return r; ObjectWriteOperation op; cls_rgw_usage_log_trim(op, user, start_epoch, end_epoch); r = io_ctx.operate(oid, &op); return r; } int RGWRados::remove_objs_from_index(rgw_bucket& bucket, list& oid_list) { librados::IoCtx index_ctx; string dir_oid; int r = open_bucket_index(bucket, index_ctx, dir_oid); if (r < 0) return r; bufferlist updates; list::iterator iter; for (iter = oid_list.begin(); iter != oid_list.end(); ++iter) { string& oid = *iter; dout(2) << "RGWRados::remove_objs_from_index bucket=" << bucket << " oid=" << oid << dendl; rgw_bucket_dir_entry entry; entry.ver.epoch = (uint64_t)-1; // ULLONG_MAX, needed to that objclass doesn't skip out request entry.name = oid; updates.append(CEPH_RGW_REMOVE); ::encode(entry, updates); } bufferlist out; r = index_ctx.exec(dir_oid, "rgw", "dir_suggest_changes", updates, out); return r; } int RGWRados::check_disk_state(librados::IoCtx io_ctx, rgw_bucket& bucket, rgw_bucket_dir_entry& list_state, RGWObjEnt& object, bufferlist& suggested_updates) { rgw_obj obj; std::string oid, key, ns; oid = list_state.name; if (!rgw_obj::strip_namespace_from_object(oid, ns)) { // well crap assert(0 == "got bad object name off disk"); } obj.init(bucket, oid, list_state.locator, ns); get_obj_bucket_and_oid_key(obj, bucket, oid, key); io_ctx.locator_set_key(key); RGWObjState *astate = NULL; RGWRadosCtx rctx(this); int r = get_obj_state(&rctx, obj, &astate, NULL); if (r < 0) return r; list_state.pending_map.clear(); // we don't need this and it inflates size if (!astate->exists) { /* object doesn't exist right now -- hopefully because it's * marked as !exists and got deleted */ if (list_state.exists) { /* FIXME: what should happen now? Work out if there are any * non-bad ways this could happen (there probably are, but annoying * to handle!) */ } // encode a suggested removal of that key list_state.ver.epoch = io_ctx.get_last_version(); list_state.ver.pool = io_ctx.get_id(); cls_rgw_encode_suggestion(CEPH_RGW_REMOVE, list_state, suggested_updates); return -ENOENT; } string etag; string content_type; ACLOwner owner; object.size = astate->size; object.mtime = utime_t(astate->mtime, 0); map::iterator iter = astate->attrset.find(RGW_ATTR_ETAG); if (iter != astate->attrset.end()) { etag = iter->second.c_str(); } iter = astate->attrset.find(RGW_ATTR_CONTENT_TYPE); if (iter != astate->attrset.end()) { content_type = iter->second.c_str(); } iter = astate->attrset.find(RGW_ATTR_ACL); if (iter != astate->attrset.end()) { r = decode_policy(iter->second, &owner); if (r < 0) { dout(0) << "WARNING: could not decode policy for object: " << obj << dendl; } } if (astate->has_manifest) { RGWObjManifest::obj_iterator miter; RGWObjManifest& manifest = astate->manifest; for (miter = manifest.obj_begin(); miter != manifest.obj_end(); ++miter) { rgw_obj loc = miter.get_location(); if (loc.ns == RGW_OBJ_NS_MULTIPART) { dout(10) << "check_disk_state(): removing manifest part from index: " << loc << dendl; r = delete_obj_index(loc); if (r < 0) { dout(0) << "WARNING: delete_obj_index() returned r=" << r << dendl; } } } } object.etag = etag; object.content_type = content_type; object.owner = owner.get_id(); object.owner_display_name = owner.get_display_name(); // encode suggested updates list_state.ver.pool = io_ctx.get_id(); list_state.ver.epoch = astate->epoch; list_state.meta.size = object.size; list_state.meta.mtime.set_from_double(double(object.mtime)); list_state.meta.category = main_category; list_state.meta.etag = etag; list_state.meta.content_type = content_type; if (astate->obj_tag.length() > 0) list_state.tag = astate->obj_tag.c_str(); list_state.meta.owner = owner.get_id(); list_state.meta.owner_display_name = owner.get_display_name(); list_state.exists = true; cls_rgw_encode_suggestion(CEPH_RGW_UPDATE, list_state, suggested_updates); return 0; } int RGWRados::cls_bucket_head(rgw_bucket& bucket, struct rgw_bucket_dir_header& header) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; r = cls_rgw_get_dir_header(index_ctx, oid, &header); if (r < 0) return r; return 0; } int RGWRados::cls_bucket_head_async(rgw_bucket& bucket, RGWGetDirHeader_CB *ctx) { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(bucket, index_ctx, oid); if (r < 0) return r; r = cls_rgw_get_dir_header_async(index_ctx, oid, ctx); if (r < 0) return r; return 0; } int RGWRados::cls_user_get_header(const string& user_id, cls_user_header *header) { string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); rgw_obj obj(zone.user_uid_pool, buckets_obj_id); rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } librados::ObjectReadOperation op; int rc; ::cls_user_get_header(op, header, &rc); bufferlist ibl; r = ref.ioctx.operate(ref.oid, &op, &ibl); if (r < 0) return r; if (rc < 0) return rc; return 0; } int RGWRados::cls_user_get_header_async(const string& user_id, RGWGetUserHeader_CB *ctx) { string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); rgw_obj obj(zone.user_uid_pool, buckets_obj_id); rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } r = ::cls_user_get_header_async(ref.ioctx, ref.oid, ctx); if (r < 0) return r; return 0; } int RGWRados::cls_user_sync_bucket_stats(rgw_obj& user_obj, rgw_bucket& bucket) { rgw_bucket_dir_header header; int r = cls_bucket_head(bucket, header); if (r < 0) { ldout(cct, 20) << "cls_bucket_header() returned " << r << dendl; return r; } cls_user_bucket_entry entry; bucket.convert(&entry.bucket); map::iterator iter = header.stats.begin(); for (; iter != header.stats.end(); ++iter) { struct rgw_bucket_category_stats& header_stats = iter->second; entry.size += header_stats.total_size; entry.size_rounded += header_stats.total_size_rounded; entry.count += header_stats.num_entries; } list entries; entries.push_back(entry); r = cls_user_update_buckets(user_obj, entries, false); if (r < 0) { ldout(cct, 20) << "cls_user_update_buckets() returned " << r << dendl; return r; } return 0; } int RGWRados::update_user_bucket_stats(const string& user_id, rgw_bucket& bucket, RGWStorageStats& stats) { cls_user_bucket_entry entry; entry.size = stats.num_kb * 1024; entry.size_rounded = stats.num_kb_rounded * 1024; entry.count += stats.num_objects; list entries; entries.push_back(entry); string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); rgw_obj obj(zone.user_uid_pool, buckets_obj_id); int r = cls_user_update_buckets(obj, entries, false); if (r < 0) { ldout(cct, 20) << "cls_user_update_buckets() returned " << r << dendl; return r; } return 0; } int RGWRados::cls_user_list_buckets(rgw_obj& obj, const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } librados::ObjectReadOperation op; int rc; cls_user_bucket_list(op, in_marker, max_entries, entries, out_marker, truncated, &rc); bufferlist ibl; r = ref.ioctx.operate(ref.oid, &op, &ibl); if (r < 0) return r; if (rc < 0) return rc; return 0; } int RGWRados::cls_user_update_buckets(rgw_obj& obj, list& entries, bool add) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } librados::ObjectWriteOperation op; cls_user_set_buckets(op, entries, add); r = ref.ioctx.operate(ref.oid, &op); if (r < 0) return r; return 0; } int RGWRados::complete_sync_user_stats(const string& user_id) { string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); rgw_obj obj(zone.user_uid_pool, buckets_obj_id); return cls_user_complete_stats_sync(obj); } int RGWRados::cls_user_complete_stats_sync(rgw_obj& obj) { rgw_rados_ref ref; rgw_bucket bucket; int r = get_obj_ref(obj, &ref, &bucket); if (r < 0) { return r; } librados::ObjectWriteOperation op; ::cls_user_complete_stats_sync(op); r = ref.ioctx.operate(ref.oid, &op); if (r < 0) return r; return 0; } int RGWRados::cls_user_add_bucket(rgw_obj& obj, const cls_user_bucket_entry& entry) { list l; l.push_back(entry); return cls_user_update_buckets(obj, l, true); } int RGWRados::cls_user_remove_bucket(rgw_obj& obj, const cls_user_bucket& bucket) { rgw_bucket b; rgw_rados_ref ref; int r = get_obj_ref(obj, &ref, &b); if (r < 0) { return r; } librados::ObjectWriteOperation op; ::cls_user_remove_bucket(op, bucket); r = ref.ioctx.operate(ref.oid, &op); if (r < 0) return r; return 0; } int RGWRados::check_quota(const string& bucket_owner, rgw_bucket& bucket, RGWQuotaInfo& user_quota, RGWQuotaInfo& bucket_quota, uint64_t obj_size) { return quota_handler->check_quota(bucket_owner, bucket, user_quota, bucket_quota, 1, obj_size); } class IntentLogNameFilter : public RGWAccessListFilter { string prefix; bool filter_exact_date; public: IntentLogNameFilter(const char *date, struct tm *tm) : prefix(date) { filter_exact_date = !(tm->tm_hour || tm->tm_min || tm->tm_sec); /* if time was specified and is not 00:00:00 we should look at objects from that date */ } bool filter(string& name, string& key) { if (filter_exact_date) return name.compare(prefix) < 0; else return name.compare(0, prefix.size(), prefix) <= 0; } }; enum IntentFlags { // bitmask I_DEL_OBJ = 1, I_DEL_DIR = 2, }; int RGWRados::remove_temp_objects(string date, string time) { struct tm tm; string format = "%Y-%m-%d"; string datetime = date; if (datetime.size() != 10) { cerr << "bad date format" << std::endl; return -EINVAL; } if (!time.empty()) { if (time.size() != 5 && time.size() != 8) { cerr << "bad time format" << std::endl; return -EINVAL; } format.append(" %H:%M:%S"); datetime.append(time.c_str()); } memset(&tm, 0, sizeof(tm)); const char *s = strptime(datetime.c_str(), format.c_str(), &tm); if (s && *s) { cerr << "failed to parse date/time" << std::endl; return -EINVAL; } time_t epoch = mktime(&tm); vector objs; int max = 1000; bool is_truncated; IntentLogNameFilter filter(date.c_str(), &tm); RGWPoolIterCtx iter_ctx; int r = pool_iterate_begin(zone.intent_log_pool, iter_ctx); if (r < 0) { cerr << "failed to list objects" << std::endl; return r; } do { objs.clear(); r = pool_iterate(iter_ctx, max, objs, &is_truncated, &filter); if (r == -ENOENT) break; if (r < 0) { cerr << "failed to list objects" << std::endl; } vector::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { process_intent_log(zone.intent_log_pool, (*iter).name, epoch, I_DEL_OBJ | I_DEL_DIR, true); } } while (is_truncated); return 0; } int RGWRados::process_intent_log(rgw_bucket& bucket, string& oid, time_t epoch, int flags, bool purge) { cout << "processing intent log " << oid << std::endl; rgw_obj obj(bucket, oid); unsigned chunk = 1024 * 1024; off_t pos = 0; bool eof = false; bool complete = true; int ret = 0; int r; bufferlist bl; bufferlist::iterator iter; off_t off; string no_owner; while (!eof || !iter.end()) { off = iter.get_off(); if (!eof && (bl.length() - off) < chunk / 2) { bufferlist more; r = read(NULL, obj, pos, chunk, more); if (r < 0) { cerr << "error while reading from " << bucket << ":" << oid << " " << cpp_strerror(-r) << std::endl; return -r; } eof = (more.length() < (off_t)chunk); pos += more.length(); bufferlist old; old.substr_of(bl, off, bl.length() - off); bl.clear(); bl.claim(old); bl.claim_append(more); iter = bl.begin(); } struct rgw_intent_log_entry entry; try { ::decode(entry, iter); } catch (buffer::error& err) { cerr << "failed to decode intent log entry in " << bucket << ":" << oid << std::endl; cerr << "skipping log" << std::endl; // no use to continue ret = -EIO; complete = false; break; } if (entry.op_time.sec() > epoch) { cerr << "skipping entry for obj=" << obj << " entry.op_time=" << entry.op_time.sec() << " requested epoch=" << epoch << std::endl; cerr << "skipping log" << std::endl; // no use to continue complete = false; break; } switch (entry.intent) { case DEL_OBJ: if (!(flags & I_DEL_OBJ)) { complete = false; break; } r = delete_obj(NULL, no_owner, entry.obj); if (r < 0 && r != -ENOENT) { cerr << "failed to remove obj: " << entry.obj << std::endl; complete = false; } break; case DEL_DIR: if (!(flags & I_DEL_DIR)) { complete = false; break; } else { librados::IoCtx index_ctx; string oid; int r = open_bucket_index(entry.obj.bucket, index_ctx, oid); if (r < 0) return r; ObjectWriteOperation op; op.remove(); oid.append(entry.obj.bucket.marker); librados::AioCompletion *completion = rados->aio_create_completion(NULL, NULL, NULL); r = index_ctx.aio_operate(oid, completion, &op); completion->release(); if (r < 0 && r != -ENOENT) { cerr << "failed to remove bucket: " << entry.obj.bucket << std::endl; complete = false; } } break; default: complete = false; } } if (complete) { rgw_obj obj(bucket, oid); cout << "completed intent log: " << obj << (purge ? ", purging it" : "") << std::endl; if (purge) { r = delete_system_obj(NULL, obj); if (r < 0) cerr << "failed to remove obj: " << obj << std::endl; } } return ret; } void RGWStateLog::oid_str(int shard, string& oid) { oid = RGW_STATELOG_OBJ_PREFIX + module_name + "."; char buf[16]; snprintf(buf, sizeof(buf), "%d", shard); oid += buf; } int RGWStateLog::get_shard_num(const string& object) { uint32_t val = ceph_str_hash_linux(object.c_str(), object.length()); return val % num_shards; } string RGWStateLog::get_oid(const string& object) { int shard = get_shard_num(object); string oid; oid_str(shard, oid); return oid; } int RGWStateLog::open_ioctx(librados::IoCtx& ioctx) { string pool_name; store->get_log_pool_name(pool_name); int r = store->rados->ioctx_create(pool_name.c_str(), ioctx); if (r < 0) { lderr(store->ctx()) << "ERROR: could not open rados pool" << dendl; return r; } return 0; } int RGWStateLog::store_entry(const string& client_id, const string& op_id, const string& object, uint32_t state, bufferlist *bl, uint32_t *check_state) { if (client_id.empty() || op_id.empty() || object.empty()) { ldout(store->ctx(), 0) << "client_id / op_id / object is empty" << dendl; } librados::IoCtx ioctx; int r = open_ioctx(ioctx); if (r < 0) return r; string oid = get_oid(object); librados::ObjectWriteOperation op; if (check_state) { cls_statelog_check_state(op, client_id, op_id, object, *check_state); } utime_t ts = ceph_clock_now(store->ctx()); bufferlist nobl; cls_statelog_add(op, client_id, op_id, object, ts, state, (bl ? *bl : nobl)); r = ioctx.operate(oid, &op); if (r < 0) { return r; } return 0; } int RGWStateLog::remove_entry(const string& client_id, const string& op_id, const string& object) { if (client_id.empty() || op_id.empty() || object.empty()) { ldout(store->ctx(), 0) << "client_id / op_id / object is empty" << dendl; } librados::IoCtx ioctx; int r = open_ioctx(ioctx); if (r < 0) return r; string oid = get_oid(object); librados::ObjectWriteOperation op; cls_statelog_remove_by_object(op, object, op_id); r = ioctx.operate(oid, &op); if (r < 0) { return r; } return 0; } void RGWStateLog::init_list_entries(const string& client_id, const string& op_id, const string& object, void **handle) { list_state *state = new list_state; state->client_id = client_id; state->op_id = op_id; state->object = object; if (object.empty()) { state->cur_shard = 0; state->max_shard = num_shards - 1; } else { state->cur_shard = state->max_shard = get_shard_num(object); } *handle = (void *)state; } int RGWStateLog::list_entries(void *handle, int max_entries, list& entries, bool *done) { list_state *state = static_cast(handle); librados::IoCtx ioctx; int r = open_ioctx(ioctx); if (r < 0) return r; entries.clear(); for (; state->cur_shard <= state->max_shard && max_entries > 0; ++state->cur_shard) { string oid; oid_str(state->cur_shard, oid); librados::ObjectReadOperation op; list ents; bool truncated; cls_statelog_list(op, state->client_id, state->op_id, state->object, state->marker, max_entries, ents, &state->marker, &truncated); bufferlist ibl; r = ioctx.operate(oid, &op, &ibl); if (r == -ENOENT) { truncated = false; r = 0; } if (r < 0) { ldout(store->ctx(), 0) << "cls_statelog_list returned " << r << dendl; return r; } if (!truncated) { state->marker.clear(); } max_entries -= ents.size(); entries.splice(entries.end(), ents); if (truncated) break; } *done = (state->cur_shard > state->max_shard); return 0; } void RGWStateLog::finish_list_entries(void *handle) { list_state *state = static_cast(handle); delete state; } void RGWStateLog::dump_entry(const cls_statelog_entry& entry, Formatter *f) { f->open_object_section("statelog_entry"); f->dump_string("client_id", entry.client_id); f->dump_string("op_id", entry.op_id); f->dump_string("object", entry.object); entry.timestamp.gmtime(f->dump_stream("timestamp")); if (!dump_entry_internal(entry, f)) { f->dump_int("state", entry.state); } f->close_section(); } RGWOpState::RGWOpState(RGWRados *_store) : RGWStateLog(_store, _store->ctx()->_conf->rgw_num_zone_opstate_shards, string("obj_opstate")) { } bool RGWOpState::dump_entry_internal(const cls_statelog_entry& entry, Formatter *f) { string s; switch ((OpState)entry.state) { case OPSTATE_UNKNOWN: s = "unknown"; break; case OPSTATE_IN_PROGRESS: s = "in-progress"; break; case OPSTATE_COMPLETE: s = "complete"; break; case OPSTATE_ERROR: s = "error"; break; case OPSTATE_ABORT: s = "abort"; break; case OPSTATE_CANCELLED: s = "cancelled"; break; default: s = "invalid"; } f->dump_string("state", s); return true; } int RGWOpState::state_from_str(const string& s, OpState *state) { if (s == "unknown") { *state = OPSTATE_UNKNOWN; } else if (s == "in-progress") { *state = OPSTATE_IN_PROGRESS; } else if (s == "complete") { *state = OPSTATE_COMPLETE; } else if (s == "error") { *state = OPSTATE_ERROR; } else if (s == "abort") { *state = OPSTATE_ABORT; } else if (s == "cancelled") { *state = OPSTATE_CANCELLED; } else { return -EINVAL; } return 0; } int RGWOpState::set_state(const string& client_id, const string& op_id, const string& object, OpState state) { uint32_t s = (uint32_t)state; return store_entry(client_id, op_id, object, s, NULL, NULL); } int RGWOpState::renew_state(const string& client_id, const string& op_id, const string& object, OpState state) { uint32_t s = (uint32_t)state; return store_entry(client_id, op_id, object, s, NULL, &s); } RGWOpStateSingleOp::RGWOpStateSingleOp(RGWRados *store, const string& cid, const string& oid, const string& obj) : os(store), client_id(cid), op_id(oid), object(obj) { cct = store->ctx(); cur_state = RGWOpState::OPSTATE_UNKNOWN; } int RGWOpStateSingleOp::set_state(RGWOpState::OpState state) { last_update = ceph_clock_now(cct); cur_state = state; return os.set_state(client_id, op_id, object, state); } int RGWOpStateSingleOp::renew_state() { utime_t now = ceph_clock_now(cct); int rate_limit_sec = cct->_conf->rgw_opstate_ratelimit_sec; if (rate_limit_sec && now - last_update < rate_limit_sec) { return 0; } last_update = now; return os.renew_state(client_id, op_id, object, cur_state); } uint64_t RGWRados::instance_id() { return rados->get_instance_id(); } uint64_t RGWRados::next_bucket_id() { Mutex::Locker l(bucket_id_lock); return ++max_bucket_id; } RGWRados *RGWStoreManager::init_storage_provider(CephContext *cct, bool use_gc_thread, bool quota_threads) { int use_cache = cct->_conf->rgw_cache_enabled; RGWRados *store = NULL; if (!use_cache) { store = new RGWRados; } else { store = new RGWCache; } if (store->initialize(cct, use_gc_thread, quota_threads) < 0) { delete store; return NULL; } return store; } RGWRados *RGWStoreManager::init_raw_storage_provider(CephContext *cct) { RGWRados *store = NULL; store = new RGWRados; store->set_context(cct); if (store->init_rados() < 0) { delete store; return NULL; } return store; } void RGWStoreManager::close_storage(RGWRados *store) { if (!store) return; store->finalize(); delete store; } ceph-0.80.11/src/rgw/rgw_rest_replica_log.cc0000664000175100017510000001704012623076744022770 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_json.h" #include "common/strtol.h" #include "rgw_rest.h" #include "rgw_op.h" #include "rgw_rest_s3.h" #include "rgw_replica_log.h" #include "rgw_metadata.h" #include "rgw_bucket.h" #include "rgw_rest_replica_log.h" #include "rgw_client_io.h" #include "common/errno.h" #define dout_subsys ceph_subsys_rgw #define REPLICA_INPUT_MAX_LEN (512*1024) static int parse_to_utime(string& in, utime_t& out) { uint64_t sec = 0; uint64_t nsec = 0; int ret = utime_t::parse_date(in.c_str(), &sec, &nsec); if (ret < 0) return ret; out = utime_t(sec, nsec); return 0; } void RGWOp_OBJLog_SetBounds::execute() { string id_str = s->info.args.get("id"), marker = s->info.args.get("marker"), time = s->info.args.get("time"), daemon_id = s->info.args.get("daemon_id"); if (id_str.empty() || marker.empty() || time.empty() || daemon_id.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } int shard; string err; utime_t ut; shard = (int)strict_strtol(id_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing id parameter - " << id_str << ", err " << err << dendl; http_ret = -EINVAL; return; } if (parse_to_utime(time, ut) < 0) { http_ret = -EINVAL; return; } string pool; RGWReplicaObjectLogger rl(store, pool, prefix); bufferlist bl; list markers; if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, markers, REPLICA_INPUT_MAX_LEN, NULL)) < 0) { dout(5) << "Error - retrieving input data - " << http_ret << dendl; return; } http_ret = rl.update_bound(shard, daemon_id, marker, ut, &markers); } void RGWOp_OBJLog_GetBounds::execute() { string id = s->info.args.get("id"); if (id.empty()) { dout(5) << " Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } int shard; string err; shard = (int)strict_strtol(id.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing id parameter - " << id << ", err " << err << dendl; http_ret = -EINVAL; return; } string pool; RGWReplicaObjectLogger rl(store, pool, prefix); http_ret = rl.get_bounds(shard, bounds); } void RGWOp_OBJLog_GetBounds::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); if (http_ret < 0) return; encode_json("bounds", bounds, s->formatter); flusher.flush(); } void RGWOp_OBJLog_DeleteBounds::execute() { string id = s->info.args.get("id"), daemon_id = s->info.args.get("daemon_id"); if (id.empty() || daemon_id.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } int shard; string err; shard = (int)strict_strtol(id.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing id parameter - " << id << ", err " << err << dendl; http_ret = -EINVAL; } string pool; RGWReplicaObjectLogger rl(store, pool, prefix); http_ret = rl.delete_bound(shard, daemon_id); } static int bucket_instance_to_bucket(RGWRados *store, string& bucket_instance, rgw_bucket& bucket) { RGWBucketInfo bucket_info; time_t mtime; int r = store->get_bucket_instance_info(NULL, bucket_instance, bucket_info, &mtime, NULL); if (r < 0) { dout(5) << "could not get bucket instance info for bucket=" << bucket_instance << ": " << cpp_strerror(r) << dendl; if (r == -ENOENT) return r; return -EINVAL; } bucket = bucket_info.bucket; return 0; } void RGWOp_BILog_SetBounds::execute() { string bucket_instance = s->info.args.get("bucket-instance"), marker = s->info.args.get("marker"), time = s->info.args.get("time"), daemon_id = s->info.args.get("daemon_id"); if (bucket_instance.empty() || marker.empty() || time.empty() || daemon_id.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } utime_t ut; if (parse_to_utime(time, ut) < 0) { http_ret = -EINVAL; return; } rgw_bucket bucket; if ((http_ret = bucket_instance_to_bucket(store, bucket_instance, bucket)) < 0) return; RGWReplicaBucketLogger rl(store); bufferlist bl; list markers; if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, markers, REPLICA_INPUT_MAX_LEN, NULL)) < 0) { dout(5) << "Error - retrieving input data - " << http_ret << dendl; return; } http_ret = rl.update_bound(bucket, daemon_id, marker, ut, &markers); } void RGWOp_BILog_GetBounds::execute() { string bucket_instance = s->info.args.get("bucket-instance"); if (bucket_instance.empty()) { dout(5) << " Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } rgw_bucket bucket; if ((http_ret = bucket_instance_to_bucket(store, bucket_instance, bucket)) < 0) return; RGWReplicaBucketLogger rl(store); http_ret = rl.get_bounds(bucket, bounds); } void RGWOp_BILog_GetBounds::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); if (http_ret < 0) return; encode_json("bounds", bounds, s->formatter); flusher.flush(); } void RGWOp_BILog_DeleteBounds::execute() { string bucket_instance = s->info.args.get("bucket-instance"), daemon_id = s->info.args.get("daemon_id"); if (bucket_instance.empty() || daemon_id.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } rgw_bucket bucket; if ((http_ret = bucket_instance_to_bucket(store, bucket_instance, bucket)) < 0) return; RGWReplicaBucketLogger rl(store); http_ret = rl.delete_bound(bucket, daemon_id); } RGWOp *RGWHandler_ReplicaLog::op_get() { bool exists; string type = s->info.args.get("type", &exists); if (!exists) { return NULL; } if (type.compare("metadata") == 0) { return new RGWOp_OBJLog_GetBounds(META_REPLICA_LOG_OBJ_PREFIX, "mdlog"); } else if (type.compare("bucket-index") == 0) { return new RGWOp_BILog_GetBounds; } else if (type.compare("data") == 0) { return new RGWOp_OBJLog_GetBounds(DATA_REPLICA_LOG_OBJ_PREFIX, "datalog"); } return NULL; } RGWOp *RGWHandler_ReplicaLog::op_delete() { bool exists; string type = s->info.args.get("type", &exists); if (!exists) { return NULL; } if (type.compare("metadata") == 0) return new RGWOp_OBJLog_DeleteBounds(META_REPLICA_LOG_OBJ_PREFIX, "mdlog"); else if (type.compare("bucket-index") == 0) return new RGWOp_BILog_DeleteBounds; else if (type.compare("data") == 0) return new RGWOp_OBJLog_DeleteBounds(DATA_REPLICA_LOG_OBJ_PREFIX, "datalog"); return NULL; } RGWOp *RGWHandler_ReplicaLog::op_post() { bool exists; string type = s->info.args.get("type", &exists); if (!exists) { return NULL; } if (type.compare("metadata") == 0) { return new RGWOp_OBJLog_SetBounds(META_REPLICA_LOG_OBJ_PREFIX, "mdlog"); } else if (type.compare("bucket-index") == 0) { return new RGWOp_BILog_SetBounds; } else if (type.compare("data") == 0) { return new RGWOp_OBJLog_SetBounds(DATA_REPLICA_LOG_OBJ_PREFIX, "datalog"); } return NULL; } ceph-0.80.11/src/rgw/rgw_cors.h0000664000175100017510000000736512623076744020274 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_CORS_H #define CEPH_RGW_CORS_H #include #include #include #include #define RGW_CORS_GET 0x1 #define RGW_CORS_PUT 0x2 #define RGW_CORS_HEAD 0x4 #define RGW_CORS_POST 0x8 #define RGW_CORS_DELETE 0x10 #define RGW_CORS_COPY 0x20 #define RGW_CORS_ALL (RGW_CORS_GET | \ RGW_CORS_PUT | \ RGW_CORS_HEAD | \ RGW_CORS_POST | \ RGW_CORS_DELETE | \ RGW_CORS_COPY) #define CORS_MAX_AGE_INVALID ((uint32_t)-1) class RGWCORSRule { protected: uint32_t max_age; uint8_t allowed_methods; std::string id; std::set allowed_hdrs; /* If you change this, you need to discard lowercase_allowed_hdrs */ std::set lowercase_allowed_hdrs; /* Not built until needed in RGWCORSRule::is_header_allowed */ std::set allowed_origins; std::list exposable_hdrs; public: RGWCORSRule() : max_age(CORS_MAX_AGE_INVALID),allowed_methods(0) {} RGWCORSRule(std::set& o, std::set& h, std::list& e, uint8_t f, uint32_t a) :max_age(a), allowed_methods(f), allowed_hdrs(h), allowed_origins(o), exposable_hdrs(e) {} virtual ~RGWCORSRule() {} std::string& get_id() { return id; } uint32_t get_max_age() { return max_age; } uint8_t get_allowed_methods() { return allowed_methods; } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(max_age, bl); ::encode(allowed_methods, bl); ::encode(id, bl); ::encode(allowed_hdrs, bl); ::encode(allowed_origins, bl); ::encode(exposable_hdrs, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(max_age, bl); ::decode(allowed_methods, bl); ::decode(id, bl); ::decode(allowed_hdrs, bl); ::decode(allowed_origins, bl); ::decode(exposable_hdrs, bl); DECODE_FINISH(bl); } bool is_origin_present(const char *o); void format_exp_headers(std::string& s); void erase_origin_if_present(std::string& origin, bool *rule_empty); void dump_origins(); void dump(Formatter *f) const; bool is_header_allowed(const char *hdr, size_t len); }; WRITE_CLASS_ENCODER(RGWCORSRule) class RGWCORSConfiguration { protected: std::list rules; public: RGWCORSConfiguration() {} ~RGWCORSConfiguration() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(rules, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(rules, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; std::list& get_rules() { return rules; } bool is_empty() { return rules.empty(); } void get_origins_list(const char *origin, std::list& origins); RGWCORSRule * host_name_rule(const char *origin); void erase_host_name_rule(std::string& origin); void dump(); void stack_rule(RGWCORSRule& r) { rules.push_front(r); } }; WRITE_CLASS_ENCODER(RGWCORSConfiguration) static inline int validate_name_string(string& o) { if (o.length() == 0) return -1; if (o.find_first_of("*") != o.find_last_of("*")) return -1; return 0; } #endif /*CEPH_RGW_CORS_H*/ ceph-0.80.11/src/rgw/rgw_acl_swift.cc0000664000175100017510000000611212623076744021424 0ustar jenkins-buildjenkins-build #include #include #include "rgw_common.h" #include "rgw_user.h" #include "rgw_acl_swift.h" #define dout_subsys ceph_subsys_rgw using namespace std; #define SWIFT_PERM_READ RGW_PERM_READ_OBJS #define SWIFT_PERM_WRITE RGW_PERM_WRITE_OBJS #define SWIFT_GROUP_ALL_USERS ".r:*" static int parse_list(string& uid_list, vector& uids) { char *s = strdup(uid_list.c_str()); if (!s) return -ENOMEM; const char *p = strtok(s, " ,"); while (p) { if (*p) { string acl = p; uids.push_back(acl); } p = strtok(NULL, " ,"); } free(s); return 0; } static bool uid_is_public(string& uid) { if (uid[0] != '.' || uid[1] != 'r') return false; int pos = uid.find(':'); if (pos < 0 || pos == (int)uid.size()) return false; string sub = uid.substr(0, pos); string after = uid.substr(pos + 1); if (after.compare("*") != 0) return false; return sub.compare(".r") == 0 || sub.compare(".referer") == 0 || sub.compare(".referrer") == 0; } void RGWAccessControlPolicy_SWIFT::add_grants(RGWRados *store, vector& uids, int perm) { vector::iterator iter; for (iter = uids.begin(); iter != uids.end(); ++iter ) { ACLGrant grant; RGWUserInfo grant_user; string& uid = *iter; if (uid_is_public(uid)) { grant.set_group(ACL_GROUP_ALL_USERS, perm); acl.add_grant(&grant); } else if (rgw_get_user_info_by_uid(store, uid, grant_user) < 0) { ldout(cct, 10) << "grant user does not exist:" << uid << dendl; /* skipping silently */ } else { grant.set_canon(uid, grant_user.display_name, perm); acl.add_grant(&grant); } } } bool RGWAccessControlPolicy_SWIFT::create(RGWRados *store, string& id, string& name, string& read_list, string& write_list) { acl.create_default(id, name); owner.set_id(id); owner.set_name(name); if (read_list.size()) { vector uids; int r = parse_list(read_list, uids); if (r < 0) { ldout(cct, 0) << "ERROR: parse_list returned r=" << r << dendl; return false; } add_grants(store, uids, SWIFT_PERM_READ); } if (write_list.size()) { vector uids; int r = parse_list(write_list, uids); if (r < 0) { ldout(cct, 0) << "ERROR: parse_list returned r=" << r << dendl; return false; } add_grants(store, uids, SWIFT_PERM_WRITE); } return true; } void RGWAccessControlPolicy_SWIFT::to_str(string& read, string& write) { multimap& m = acl.get_grant_map(); multimap::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { ACLGrant& grant = iter->second; int perm = grant.get_permission().get_permissions(); string id; if (!grant.get_id(id)) { if (grant.get_group() != ACL_GROUP_ALL_USERS) continue; id = SWIFT_GROUP_ALL_USERS; } if (perm & SWIFT_PERM_READ) { if (!read.empty()) read.append(", "); read.append(id); } else if (perm & SWIFT_PERM_WRITE) { if (!write.empty()) write.append(", "); write.append(id); } } } ceph-0.80.11/src/rgw/rgw_bucket.cc0000664000175100017510000013551412623076744020737 0ustar jenkins-buildjenkins-build#include #include #include #include "common/errno.h" #include "common/ceph_json.h" #include "rgw_rados.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" #include "include/types.h" #include "rgw_bucket.h" #include "rgw_user.h" #include "rgw_string.h" // until everything is moved from rgw_common #include "rgw_common.h" #include "cls/user/cls_user_types.h" #define dout_subsys ceph_subsys_rgw #define BUCKET_TAG_TIMEOUT 30 using namespace std; static RGWMetadataHandler *bucket_meta_handler = NULL; static RGWMetadataHandler *bucket_instance_meta_handler = NULL; // define as static when RGWBucket implementation compete void rgw_get_buckets_obj(const string& user_id, string& buckets_obj_id) { buckets_obj_id = user_id; buckets_obj_id += RGW_BUCKETS_OBJ_SUFFIX; } /** * Get all the buckets owned by a user and fill up an RGWUserBuckets with them. * Returns: 0 on success, -ERR# on failure. */ int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, const string& marker, uint64_t max, bool need_stats) { int ret; buckets.clear(); string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); bufferlist bl; rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id); bufferlist header; list entries; bool truncated = false; string m = marker; uint64_t total = 0; do { ret = store->cls_user_list_buckets(obj, m, max - total, entries, &m, &truncated); if (ret == -ENOENT) ret = 0; if (ret < 0) return ret; for (list::iterator q = entries.begin(); q != entries.end(); ++q) { RGWBucketEnt e(*q); buckets.add(e); total++; } } while (truncated && total < max); if (need_stats) { map& m = buckets.get_buckets(); int r = store->update_containers_stats(m); if (r < 0) { ldout(store->ctx(), 0) << "ERROR: could not get stats for buckets" << dendl; } } return 0; } int rgw_bucket_sync_user_stats(RGWRados *store, const string& user_id, rgw_bucket& bucket) { string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id); return store->cls_user_sync_bucket_stats(obj, bucket); } int rgw_bucket_sync_user_stats(RGWRados *store, const string& bucket_name) { RGWBucketInfo bucket_info; int ret = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: could not fetch bucket info: ret=" << ret << dendl; return ret; } ret = rgw_bucket_sync_user_stats(store, bucket_info.owner, bucket_info.bucket); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: could not sync user stats for bucket " << bucket_name << ": ret=" << ret << dendl; return ret; } return 0; } int rgw_link_bucket(RGWRados *store, string user_id, rgw_bucket& bucket, time_t creation_time, bool update_entrypoint) { int ret; string& bucket_name = bucket.name; cls_user_bucket_entry new_bucket; RGWBucketEntryPoint ep; RGWObjVersionTracker ot; bucket.convert(&new_bucket.bucket); new_bucket.size = 0; if (!creation_time) time(&new_bucket.creation_time); else new_bucket.creation_time = creation_time; map attrs; if (update_entrypoint) { ret = store->get_bucket_entrypoint_info(NULL, bucket_name, ep, &ot, NULL, &attrs); if (ret < 0 && ret != -ENOENT) { ldout(store->ctx(), 0) << "ERROR: store->get_bucket_entrypoint_info() returned " << ret << dendl; } else if (ret >= 0 && ep.linked && ep.owner != user_id) { ldout(store->ctx(), 0) << "can't link bucket, already linked to a different user: " << ep.owner << dendl; return -EINVAL; } } string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id); ret = store->cls_user_add_bucket(obj, new_bucket); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: error adding bucket to directory: " << cpp_strerror(-ret)<< dendl; goto done_err; } if (!update_entrypoint) return 0; ep.linked = true; ep.owner = user_id; ret = store->put_bucket_entrypoint_info(bucket_name, ep, false, ot, 0, &attrs); if (ret < 0) goto done_err; return 0; done_err: int r = rgw_unlink_bucket(store, user_id, bucket.name); if (r < 0) { ldout(store->ctx(), 0) << "ERROR: failed unlinking bucket on error cleanup: " << cpp_strerror(-r) << dendl; } return ret; } int rgw_unlink_bucket(RGWRados *store, string user_id, const string& bucket_name, bool update_entrypoint) { int ret; bufferlist bl; string buckets_obj_id; rgw_get_buckets_obj(user_id, buckets_obj_id); cls_user_bucket bucket; bucket.name = bucket_name; rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id); ret = store->cls_user_remove_bucket(obj, bucket); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: error removing bucket from directory: " << cpp_strerror(-ret)<< dendl; } if (!update_entrypoint) return 0; RGWBucketEntryPoint ep; RGWObjVersionTracker ot; map attrs; ret = store->get_bucket_entrypoint_info(NULL, bucket_name, ep, &ot, NULL, &attrs); if (ret == -ENOENT) return 0; if (ret < 0) return ret; if (!ep.linked) return 0; if (ep.owner != user_id) { ldout(store->ctx(), 0) << "bucket entry point user mismatch, can't unlink bucket: " << ep.owner << " != " << user_id << dendl; return -EINVAL; } ep.linked = false; ret = store->put_bucket_entrypoint_info(bucket_name, ep, false, ot, 0, &attrs); if (ret < 0) return ret; return ret; } int rgw_bucket_store_info(RGWRados *store, const string& bucket_name, bufferlist& bl, bool exclusive, map *pattrs, RGWObjVersionTracker *objv_tracker, time_t mtime) { return store->meta_mgr->put_entry(bucket_meta_handler, bucket_name, bl, exclusive, objv_tracker, mtime, pattrs); } int rgw_bucket_instance_store_info(RGWRados *store, string& entry, bufferlist& bl, bool exclusive, map *pattrs, RGWObjVersionTracker *objv_tracker, time_t mtime) { return store->meta_mgr->put_entry(bucket_instance_meta_handler, entry, bl, exclusive, objv_tracker, mtime, pattrs); } int rgw_bucket_instance_remove_entry(RGWRados *store, string& entry, RGWObjVersionTracker *objv_tracker) { return store->meta_mgr->remove_entry(bucket_instance_meta_handler, entry, objv_tracker); } int rgw_bucket_set_attrs(RGWRados *store, RGWBucketInfo& bucket_info, map& attrs, map* rmattrs, RGWObjVersionTracker *objv_tracker) { rgw_bucket& bucket = bucket_info.bucket; if (!bucket_info.has_instance_obj) { /* an old bucket object, need to convert it */ int ret = store->convert_old_bucket_info(NULL, bucket.name); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: failed converting old bucket info: " << ret << dendl; return ret; } } string oid; store->get_bucket_meta_oid(bucket, oid); rgw_obj obj(store->zone.domain_root, oid); string key; store->get_bucket_instance_entry(bucket, key); /* we want the bucket instance name without the oid prefix cruft */ return store->meta_mgr->set_attrs(bucket_instance_meta_handler, key, obj, attrs, rmattrs, objv_tracker); } static void dump_mulipart_index_results(list& objs_to_unlink, Formatter *f) { // make sure that an appropiately titled header has been opened previously list::iterator oiter = objs_to_unlink.begin(); f->open_array_section("invalid_multipart_entries"); for ( ; oiter != objs_to_unlink.end(); ++oiter) { f->dump_string("object", *oiter); } f->close_section(); } void check_bad_user_bucket_mapping(RGWRados *store, const string& user_id, bool fix) { RGWUserBuckets user_buckets; bool done; string marker; CephContext *cct = store->ctx(); size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk; do { int ret = rgw_read_user_buckets(store, user_id, user_buckets, marker, max_entries, false); if (ret < 0) { ldout(store->ctx(), 0) << "failed to read user buckets: " << cpp_strerror(-ret) << dendl; return; } map& buckets = user_buckets.get_buckets(); for (map::iterator i = buckets.begin(); i != buckets.end(); ++i) { marker = i->first; RGWBucketEnt& bucket_ent = i->second; rgw_bucket& bucket = bucket_ent.bucket; RGWBucketInfo bucket_info; time_t mtime; int r = store->get_bucket_info(NULL, bucket.name, bucket_info, &mtime); if (r < 0) { ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket << dendl; continue; } rgw_bucket& actual_bucket = bucket_info.bucket; if (actual_bucket.name.compare(bucket.name) != 0 || actual_bucket.data_pool.compare(bucket.data_pool) != 0 || actual_bucket.index_pool.compare(bucket.index_pool) != 0 || actual_bucket.marker.compare(bucket.marker) != 0 || actual_bucket.bucket_id.compare(bucket.bucket_id) != 0) { cout << "bucket info mismatch: expected " << actual_bucket << " got " << bucket << std::endl; if (fix) { cout << "fixing" << std::endl; r = rgw_link_bucket(store, user_id, actual_bucket, bucket_info.creation_time); if (r < 0) { cerr << "failed to fix bucket: " << cpp_strerror(-r) << std::endl; } } } } done = (buckets.size() < max_entries); } while (!done); } static bool bucket_object_check_filter(const string& name) { string ns; string obj = name; return rgw_obj::translate_raw_obj_to_obj_in_ns(obj, ns); } int rgw_remove_object(RGWRados *store, const string& bucket_owner, rgw_bucket& bucket, std::string& object) { RGWRadosCtx rctx(store); rgw_obj obj(bucket, object); int ret = store->delete_obj((void *)&rctx, bucket_owner, obj); return ret; } int rgw_remove_bucket(RGWRados *store, const string& bucket_owner, rgw_bucket& bucket, bool delete_children) { int ret; map stats; std::vector objs; std::string prefix, delim, marker, ns; map common_prefixes; rgw_obj obj; RGWBucketInfo info; bufferlist bl; uint64_t bucket_ver, master_ver; ret = store->get_bucket_stats(bucket, &bucket_ver, &master_ver, stats, NULL); if (ret < 0) return ret; obj.bucket = bucket; ret = store->get_bucket_info(NULL, bucket.name, info, NULL); if (ret < 0) return ret; if (delete_children) { int max = 1000; ret = store->list_objects(bucket, max, prefix, delim, marker, NULL, objs, common_prefixes, false, ns, true, NULL, NULL); if (ret < 0) return ret; while (!objs.empty()) { std::vector::iterator it = objs.begin(); for (it = objs.begin(); it != objs.end(); ++it) { ret = rgw_remove_object(store, bucket_owner, bucket, (*it).name); if (ret < 0) return ret; } objs.clear(); ret = store->list_objects(bucket, max, prefix, delim, marker, NULL, objs, common_prefixes, false, ns, true, NULL, NULL); if (ret < 0) return ret; } } RGWObjVersionTracker objv_tracker; ret = store->delete_bucket(bucket, objv_tracker); if (ret < 0) { lderr(store->ctx()) << "ERROR: could not remove bucket " << bucket.name << dendl; return ret; } ret = rgw_unlink_bucket(store, info.owner, bucket.name); if (ret < 0) { lderr(store->ctx()) << "ERROR: unable to remove user bucket information" << dendl; } return ret; } int rgw_bucket_delete_bucket_obj(RGWRados *store, string& bucket_name, RGWObjVersionTracker& objv_tracker) { return store->meta_mgr->remove_entry(bucket_meta_handler, bucket_name, &objv_tracker); } static void set_err_msg(std::string *sink, std::string msg) { if (sink && !msg.empty()) *sink = msg; } int RGWBucket::init(RGWRados *storage, RGWBucketAdminOpState& op_state) { if (!storage) return -EINVAL; store = storage; string user_id = op_state.get_user_id(); bucket_name = op_state.get_bucket_name(); RGWUserBuckets user_buckets; if (bucket_name.empty() && user_id.empty()) return -EINVAL; if (!bucket_name.empty()) { int r = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL); if (r < 0) { ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket_name << dendl; return r; } op_state.set_bucket(bucket_info.bucket); } if (!user_id.empty()) { int r = rgw_get_user_info_by_uid(store, user_id, user_info); if (r < 0) return r; op_state.display_name = user_info.display_name; } clear_failure(); return 0; } int RGWBucket::link(RGWBucketAdminOpState& op_state, std::string *err_msg) { if (!op_state.is_user_op()) { set_err_msg(err_msg, "empty user id"); return -EINVAL; } std::string no_oid; std::string display_name = op_state.get_user_display_name(); rgw_bucket bucket = op_state.get_bucket(); rgw_obj obj(bucket, no_oid); RGWObjVersionTracker objv_tracker; map attrs; RGWBucketInfo bucket_info; int r = store->get_bucket_info(NULL, bucket.name, bucket_info, NULL, &attrs); if (r < 0) { return r; } map::iterator aiter = attrs.find(RGW_ATTR_ACL); if (aiter != attrs.end()) { bufferlist aclbl = aiter->second; RGWAccessControlPolicy policy; ACLOwner owner; try { bufferlist::iterator iter = aclbl.begin(); ::decode(policy, iter); owner = policy.get_owner(); } catch (buffer::error& err) { set_err_msg(err_msg, "couldn't decode policy"); return -EIO; } r = rgw_unlink_bucket(store, owner.get_id(), bucket.name); if (r < 0) { set_err_msg(err_msg, "could not unlink policy from user " + owner.get_id()); return r; } // now update the user for the bucket... if (display_name.empty()) { ldout(store->ctx(), 0) << "WARNING: user " << user_info.user_id << " has no display name set" << dendl; } policy.create_default(user_info.user_id, display_name); owner = policy.get_owner(); r = store->set_bucket_owner(bucket, owner); if (r < 0) { set_err_msg(err_msg, "failed to set bucket owner: " + cpp_strerror(-r)); return r; } // ...and encode the acl aclbl.clear(); policy.encode(aclbl); r = store->set_attr(NULL, obj, RGW_ATTR_ACL, aclbl, &objv_tracker); if (r < 0) return r; r = rgw_link_bucket(store, user_info.user_id, bucket, 0); if (r < 0) return r; } return 0; } int RGWBucket::unlink(RGWBucketAdminOpState& op_state, std::string *err_msg) { rgw_bucket bucket = op_state.get_bucket(); if (!op_state.is_user_op()) { set_err_msg(err_msg, "could not fetch user or user bucket info"); return -EINVAL; } int r = rgw_unlink_bucket(store, user_info.user_id, bucket.name); if (r < 0) { set_err_msg(err_msg, "error unlinking bucket" + cpp_strerror(-r)); } return r; } int RGWBucket::remove(RGWBucketAdminOpState& op_state, std::string *err_msg) { bool delete_children = op_state.will_delete_children(); rgw_bucket bucket = op_state.get_bucket(); int ret = rgw_remove_bucket(store, bucket_info.owner, bucket, delete_children); if (ret < 0) { set_err_msg(err_msg, "unable to remove bucket" + cpp_strerror(-ret)); return ret; } return 0; } int RGWBucket::remove_object(RGWBucketAdminOpState& op_state, std::string *err_msg) { rgw_bucket bucket = op_state.get_bucket(); std::string object_name = op_state.get_object_name(); int ret = rgw_remove_object(store, bucket_info.owner, bucket, object_name); if (ret < 0) { set_err_msg(err_msg, "unable to remove object" + cpp_strerror(-ret)); return ret; } return 0; } static void dump_bucket_index(map result, Formatter *f) { map::iterator iter; for (iter = result.begin(); iter != result.end(); ++iter) { f->dump_string("object", iter->first); } } static void dump_bucket_usage(map& stats, Formatter *formatter) { map::iterator iter; formatter->open_object_section("usage"); for (iter = stats.begin(); iter != stats.end(); ++iter) { RGWStorageStats& s = iter->second; const char *cat_name = rgw_obj_category_name(iter->first); formatter->open_object_section(cat_name); formatter->dump_int("size_kb", s.num_kb); formatter->dump_int("size_kb_actual", s.num_kb_rounded); formatter->dump_int("num_objects", s.num_objects); formatter->close_section(); } formatter->close_section(); } static void dump_index_check(map existing_stats, map calculated_stats, Formatter *formatter) { formatter->open_object_section("check_result"); formatter->open_object_section("existing_header"); dump_bucket_usage(existing_stats, formatter); formatter->close_section(); formatter->open_object_section("calculated_header"); dump_bucket_usage(calculated_stats, formatter); formatter->close_section(); formatter->close_section(); } int RGWBucket::check_bad_index_multipart(RGWBucketAdminOpState& op_state, list& objs_to_unlink, std::string *err_msg) { bool fix_index = op_state.will_fix_index(); rgw_bucket bucket = op_state.get_bucket(); int max = 1000; string prefix; string marker; string delim; map common_prefixes; string ns = "multipart"; bool is_truncated; map meta_objs; map all_objs; do { vector result; int r = store->list_objects(bucket, max, prefix, delim, marker, NULL, result, common_prefixes, false, ns, true, &is_truncated, NULL); if (r < 0) { set_err_msg(err_msg, "failed to list objects in bucket=" + bucket.name + " err=" + cpp_strerror(-r)); return r; } vector::iterator iter; for (iter = result.begin(); iter != result.end(); ++iter) { RGWObjEnt& ent = *iter; rgw_obj obj(bucket, ent.name); obj.set_ns(ns); string& oid = obj.object; marker = oid; int pos = oid.find_last_of('.'); if (pos < 0) continue; string name = oid.substr(0, pos); string suffix = oid.substr(pos + 1); if (suffix.compare("meta") == 0) { meta_objs[name] = true; } else { all_objs[oid] = name; } } } while (is_truncated); map::iterator aiter; for (aiter = all_objs.begin(); aiter != all_objs.end(); ++aiter) { string& name = aiter->second; if (meta_objs.find(name) == meta_objs.end()) { objs_to_unlink.push_back(aiter->first); } } if (objs_to_unlink.empty()) return 0; if (fix_index) { int r = store->remove_objs_from_index(bucket, objs_to_unlink); if (r < 0) { set_err_msg(err_msg, "ERROR: remove_obj_from_index() returned error: " + cpp_strerror(-r)); return r; } } return 0; } int RGWBucket::check_object_index(RGWBucketAdminOpState& op_state, map result, std::string *err_msg) { bool fix_index = op_state.will_fix_index(); rgw_bucket bucket = op_state.get_bucket(); if (!fix_index) { set_err_msg(err_msg, "check-objects flag requires fix index enabled"); return -EINVAL; } /* dout(0) << "Checking objects, decreasing bucket 2-phase commit timeout.\n"\ << "** Note that timeout will reset only when operation completes successfully **" << dendl; */ store->cls_obj_set_bucket_tag_timeout(bucket, BUCKET_TAG_TIMEOUT); string prefix; string marker; bool is_truncated = true; while (is_truncated) { map result; int r = store->cls_bucket_list(bucket, marker, prefix, 1000, result, &is_truncated, &marker, bucket_object_check_filter); if (r == -ENOENT) { break; } else if (r < 0 && r != -ENOENT) { set_err_msg(err_msg, "ERROR: failed operation r=" + cpp_strerror(-r)); } } store->cls_obj_set_bucket_tag_timeout(bucket, 0); return 0; } int RGWBucket::check_index(RGWBucketAdminOpState& op_state, map& existing_stats, map& calculated_stats, std::string *err_msg) { rgw_bucket bucket = op_state.get_bucket(); bool fix_index = op_state.will_fix_index(); int r = store->bucket_check_index(bucket, &existing_stats, &calculated_stats); if (r < 0) { set_err_msg(err_msg, "failed to check index error=" + cpp_strerror(-r)); return r; } if (fix_index) { r = store->bucket_rebuild_index(bucket); if (r < 0) { set_err_msg(err_msg, "failed to rebuild index err=" + cpp_strerror(-r)); return r; } } return 0; } int RGWBucket::policy_bl_to_stream(bufferlist& bl, ostream& o) { RGWAccessControlPolicy_S3 policy(g_ceph_context); bufferlist::iterator iter = bl.begin(); try { policy.decode(iter); } catch (buffer::error& err) { dout(0) << "ERROR: caught buffer::error, could not decode policy" << dendl; return -EIO; } policy.to_xml(o); return 0; } int RGWBucket::get_policy(RGWBucketAdminOpState& op_state, ostream& o) { std::string object_name = op_state.get_object_name(); rgw_bucket bucket = op_state.get_bucket(); if (!object_name.empty()) { bufferlist bl; rgw_obj obj(bucket, object_name); int ret = store->get_attr(NULL, obj, RGW_ATTR_ACL, bl); if (ret < 0) return ret; return policy_bl_to_stream(bl, o); } RGWBucketInfo bucket_info; map attrs; int ret = store->get_bucket_info(NULL, bucket.name, bucket_info, NULL, &attrs); if (ret < 0) { return ret; } map::iterator aiter = attrs.find(RGW_ATTR_ACL); if (aiter == attrs.end()) { return -ENOENT; } return policy_bl_to_stream(aiter->second, o); } int RGWBucketAdminOp::get_policy(RGWRados *store, RGWBucketAdminOpState& op_state, ostream& os) { RGWBucket bucket; int ret = bucket.init(store, op_state); if (ret < 0) return ret; ret = bucket.get_policy(op_state, os); if (ret < 0) return ret; return 0; } /* Wrappers to facilitate RESTful interface */ int RGWBucketAdminOp::get_policy(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher) { std::ostringstream policy_stream; int ret = get_policy(store, op_state, policy_stream); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); flusher.start(0); formatter->dump_string("policy", policy_stream.str()); flusher.flush(); return 0; } int RGWBucketAdminOp::unlink(RGWRados *store, RGWBucketAdminOpState& op_state) { RGWBucket bucket; int ret = bucket.init(store, op_state); if (ret < 0) return ret; return bucket.unlink(op_state); } int RGWBucketAdminOp::link(RGWRados *store, RGWBucketAdminOpState& op_state) { RGWBucket bucket; int ret = bucket.init(store, op_state); if (ret < 0) return ret; return bucket.link(op_state); } int RGWBucketAdminOp::check_index(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher) { int ret; map result; map existing_stats; map calculated_stats; list objs_to_unlink; RGWBucket bucket; ret = bucket.init(store, op_state); if (ret < 0) return ret; Formatter *formatter = flusher.get_formatter(); flusher.start(0); ret = bucket.check_bad_index_multipart(op_state, objs_to_unlink); if (ret < 0) return ret; dump_mulipart_index_results(objs_to_unlink, formatter); flusher.flush(); ret = bucket.check_object_index(op_state, result); if (ret < 0) return ret; dump_bucket_index(result, formatter); flusher.flush(); ret = bucket.check_index(op_state, existing_stats, calculated_stats); if (ret < 0) return ret; dump_index_check(existing_stats, calculated_stats, formatter); flusher.flush(); return 0; } int RGWBucketAdminOp::remove_bucket(RGWRados *store, RGWBucketAdminOpState& op_state) { RGWBucket bucket; int ret = bucket.init(store, op_state); if (ret < 0) return ret; return bucket.remove(op_state); } int RGWBucketAdminOp::remove_object(RGWRados *store, RGWBucketAdminOpState& op_state) { RGWBucket bucket; int ret = bucket.init(store, op_state); if (ret < 0) return ret; return bucket.remove_object(op_state); } static int bucket_stats(RGWRados *store, std::string& bucket_name, Formatter *formatter) { RGWBucketInfo bucket_info; rgw_bucket bucket; map stats; time_t mtime; int r = store->get_bucket_info(NULL, bucket_name, bucket_info, &mtime); if (r < 0) return r; bucket = bucket_info.bucket; uint64_t bucket_ver, master_ver; string max_marker; int ret = store->get_bucket_stats(bucket, &bucket_ver, &master_ver, stats, &max_marker); if (ret < 0) { cerr << "error getting bucket stats ret=" << ret << std::endl; return ret; } formatter->open_object_section("stats"); formatter->dump_string("bucket", bucket.name); formatter->dump_string("pool", bucket.data_pool); formatter->dump_string("index_pool", bucket.index_pool); formatter->dump_string("id", bucket.bucket_id); formatter->dump_string("marker", bucket.marker); formatter->dump_string("owner", bucket_info.owner); formatter->dump_int("ver", bucket_ver); formatter->dump_int("master_ver", master_ver); formatter->dump_int("mtime", mtime); formatter->dump_string("max_marker", max_marker); dump_bucket_usage(stats, formatter); encode_json("bucket_quota", bucket_info.quota, formatter); formatter->close_section(); return 0; } int RGWBucketAdminOp::info(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher) { RGWBucket bucket; int ret; string bucket_name = op_state.get_bucket_name(); if (!bucket_name.empty()) { ret = bucket.init(store, op_state); if (ret < 0) return ret; } Formatter *formatter = flusher.get_formatter(); flusher.start(0); CephContext *cct = store->ctx(); size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk; bool show_stats = op_state.will_fetch_stats(); if (op_state.is_user_op()) { formatter->open_array_section("buckets"); RGWUserBuckets buckets; string marker; bool done; do { ret = rgw_read_user_buckets(store, op_state.get_user_id(), buckets, marker, max_entries, false); if (ret < 0) return ret; map& m = buckets.get_buckets(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { std::string obj_name = iter->first; if (show_stats) bucket_stats(store, obj_name, formatter); else formatter->dump_string("bucket", obj_name); marker = obj_name; } flusher.flush(); done = (m.size() < max_entries); } while (!done); formatter->close_section(); } else if (!bucket_name.empty()) { bucket_stats(store, bucket_name, formatter); } else { RGWAccessHandle handle; formatter->open_array_section("buckets"); if (store->list_buckets_init(&handle) >= 0) { RGWObjEnt obj; while (store->list_buckets_next(obj, &handle) >= 0) { formatter->dump_string("bucket", obj.name); if (show_stats) bucket_stats(store, obj.name, formatter); } } formatter->close_section(); } flusher.flush(); return 0; } void rgw_data_change::dump(Formatter *f) const { string type; switch (entity_type) { case ENTITY_TYPE_BUCKET: type = "bucket"; break; default: type = "unknown"; } encode_json("entity_type", type, f); encode_json("key", key, f); encode_json("timestamp", timestamp, f); } int RGWDataChangesLog::choose_oid(rgw_bucket& bucket) { string& name = bucket.name; uint32_t r = ceph_str_hash_linux(name.c_str(), name.size()) % num_shards; return (int)r; } int RGWDataChangesLog::renew_entries() { if (!store->need_to_log_data()) return 0; /* we can't keep the bucket name as part of the cls_log_entry, and we need * it later, so we keep two lists under the map */ map, list > > m; lock.Lock(); map entries; entries.swap(cur_cycle); lock.Unlock(); map::iterator iter; string section; utime_t ut = ceph_clock_now(cct); for (iter = entries.begin(); iter != entries.end(); ++iter) { rgw_bucket& bucket = iter->second; int index = choose_oid(bucket); cls_log_entry entry; rgw_data_change change; bufferlist bl; change.entity_type = ENTITY_TYPE_BUCKET; change.key = bucket.name + ":" + bucket.bucket_id; change.timestamp = ut; ::encode(change, bl); store->time_log_prepare_entry(entry, ut, section, bucket.name, bl); m[index].first.push_back(bucket.name); m[index].second.push_back(entry); } map, list > >::iterator miter; for (miter = m.begin(); miter != m.end(); ++miter) { list& entries = miter->second.second; utime_t now = ceph_clock_now(cct); int ret = store->time_log_add(oids[miter->first], entries); if (ret < 0) { /* we don't really need to have a special handling for failed cases here, * as this is just an optimization. */ lderr(cct) << "ERROR: store->time_log_add() returned " << ret << dendl; return ret; } utime_t expiration = now; expiration += utime_t(cct->_conf->rgw_data_log_window, 0); list& buckets = miter->second.first; list::iterator liter; for (liter = buckets.begin(); liter != buckets.end(); ++liter) { update_renewed(*liter, expiration); } } return 0; } void RGWDataChangesLog::_get_change(string& bucket_name, ChangeStatusPtr& status) { assert(lock.is_locked()); if (!changes.find(bucket_name, status)) { status = ChangeStatusPtr(new ChangeStatus); changes.add(bucket_name, status); } } void RGWDataChangesLog::register_renew(rgw_bucket& bucket) { Mutex::Locker l(lock); cur_cycle[bucket.name] = bucket; } void RGWDataChangesLog::update_renewed(string& bucket_name, utime_t& expiration) { Mutex::Locker l(lock); ChangeStatusPtr status; _get_change(bucket_name, status); ldout(cct, 20) << "RGWDataChangesLog::update_renewd() bucket_name=" << bucket_name << " expiration=" << expiration << dendl; status->cur_expiration = expiration; } int RGWDataChangesLog::add_entry(rgw_bucket& bucket) { if (!store->need_to_log_data()) return 0; lock.Lock(); ChangeStatusPtr status; _get_change(bucket.name, status); lock.Unlock(); utime_t now = ceph_clock_now(cct); status->lock->Lock(); ldout(cct, 20) << "RGWDataChangesLog::add_entry() bucket.name=" << bucket.name << " now=" << now << " cur_expiration=" << status->cur_expiration << dendl; if (now < status->cur_expiration) { /* no need to send, recently completed */ status->lock->Unlock(); register_renew(bucket); return 0; } RefCountedCond *cond; if (status->pending) { cond = status->cond; assert(cond); status->cond->get(); status->lock->Unlock(); int ret = cond->wait(); cond->put(); if (!ret) { register_renew(bucket); } return ret; } status->cond = new RefCountedCond; status->pending = true; string& oid = oids[choose_oid(bucket)]; utime_t expiration; int ret; do { status->cur_sent = now; expiration = now; expiration += utime_t(cct->_conf->rgw_data_log_window, 0); status->lock->Unlock(); bufferlist bl; rgw_data_change change; change.entity_type = ENTITY_TYPE_BUCKET; change.key = bucket.name + ":" + bucket.bucket_id; change.timestamp = now; ::encode(change, bl); string section; ldout(cct, 20) << "RGWDataChangesLog::add_entry() sending update with now=" << now << " cur_expiration=" << expiration << dendl; ret = store->time_log_add(oid, now, section, change.key, bl); now = ceph_clock_now(cct); status->lock->Lock(); } while (!ret && ceph_clock_now(cct) > expiration); cond = status->cond; status->pending = false; status->cur_expiration = status->cur_sent; /* time of when operation started, not completed */ status->cur_expiration += utime_t(cct->_conf->rgw_data_log_window, 0); status->cond = NULL; status->lock->Unlock(); cond->done(ret); cond->put(); return ret; } int RGWDataChangesLog::list_entries(int shard, utime_t& start_time, utime_t& end_time, int max_entries, list& entries, const string& marker, string *out_marker, bool *truncated) { list log_entries; int ret = store->time_log_list(oids[shard], start_time, end_time, max_entries, log_entries, marker, out_marker, truncated); if (ret < 0) return ret; list::iterator iter; for (iter = log_entries.begin(); iter != log_entries.end(); ++iter) { rgw_data_change entry; bufferlist::iterator liter = iter->data.begin(); try { ::decode(entry, liter); } catch (buffer::error& err) { lderr(cct) << "ERROR: failed to decode data changes log entry" << dendl; return -EIO; } entries.push_back(entry); } return 0; } int RGWDataChangesLog::list_entries(utime_t& start_time, utime_t& end_time, int max_entries, list& entries, LogMarker& marker, bool *ptruncated) { bool truncated; entries.clear(); for (; marker.shard < num_shards && (int)entries.size() < max_entries; marker.shard++, marker.marker.clear()) { int ret = list_entries(marker.shard, start_time, end_time, max_entries - entries.size(), entries, marker.marker, NULL, &truncated); if (ret == -ENOENT) { continue; } if (ret < 0) { return ret; } if (truncated) { *ptruncated = true; return 0; } } *ptruncated = (marker.shard < num_shards); return 0; } int RGWDataChangesLog::get_info(int shard_id, RGWDataChangesLogInfo *info) { if (shard_id > num_shards) return -EINVAL; string oid = oids[shard_id]; cls_log_header header; int ret = store->time_log_info(oid, &header); if ((ret < 0) && (ret != -ENOENT)) return ret; info->marker = header.max_marker; info->last_update = header.max_time; return 0; } int RGWDataChangesLog::trim_entries(int shard_id, const utime_t& start_time, const utime_t& end_time, const string& start_marker, const string& end_marker) { int ret; if (shard_id > num_shards) return -EINVAL; ret = store->time_log_trim(oids[shard_id], start_time, end_time, start_marker, end_marker); if (ret == -ENOENT) ret = 0; return ret; } int RGWDataChangesLog::trim_entries(const utime_t& start_time, const utime_t& end_time, const string& start_marker, const string& end_marker) { for (int shard = 0; shard < num_shards; shard++) { int ret = store->time_log_trim(oids[shard], start_time, end_time, start_marker, end_marker); if (ret == -ENOENT) { continue; } if (ret < 0) return ret; } return 0; } bool RGWDataChangesLog::going_down() { return (down_flag.read() != 0); } RGWDataChangesLog::~RGWDataChangesLog() { down_flag.set(1); renew_thread->stop(); renew_thread->join(); delete renew_thread; delete[] oids; } void *RGWDataChangesLog::ChangesRenewThread::entry() { do { dout(2) << "RGWDataChangesLog::ChangesRenewThread: start" << dendl; int r = log->renew_entries(); if (r < 0) { dout(0) << "ERROR: RGWDataChangesLog::renew_entries returned error r=" << r << dendl; } if (log->going_down()) break; int interval = cct->_conf->rgw_data_log_window * 3 / 4; lock.Lock(); cond.WaitInterval(cct, lock, utime_t(interval, 0)); lock.Unlock(); } while (!log->going_down()); return NULL; } void RGWDataChangesLog::ChangesRenewThread::stop() { Mutex::Locker l(lock); cond.Signal(); } struct RGWBucketCompleteInfo { RGWBucketInfo info; map attrs; void dump(Formatter *f) const { encode_json("bucket_info", info, f); encode_json("attrs", attrs, f); } void decode_json(JSONObj *obj) { JSONDecoder::decode_json("bucket_info", info, obj); JSONDecoder::decode_json("attrs", attrs, obj); } }; class RGWBucketEntryMetadataObject : public RGWMetadataObject { RGWBucketEntryPoint ep; public: RGWBucketEntryMetadataObject(RGWBucketEntryPoint& _ep, obj_version& v, time_t m) : ep(_ep) { objv = v; mtime = m; } void dump(Formatter *f) const { ep.dump(f); } }; class RGWBucketInstanceMetadataObject : public RGWMetadataObject { RGWBucketCompleteInfo info; public: RGWBucketInstanceMetadataObject(RGWBucketCompleteInfo& i, obj_version& v, time_t m) : info(i) { objv = v; mtime = m; } void dump(Formatter *f) const { info.dump(f); } }; class RGWBucketMetadataHandler : public RGWMetadataHandler { int init_bucket(RGWRados *store, string& bucket_name, rgw_bucket& bucket, RGWObjVersionTracker *objv_tracker) { RGWBucketInfo bucket_info; int r = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL); if (r < 0) { cerr << "could not get bucket info for bucket=" << bucket_name << std::endl; return r; } bucket = bucket_info.bucket; return 0; } public: string get_type() { return "bucket"; } int get(RGWRados *store, string& entry, RGWMetadataObject **obj) { RGWObjVersionTracker ot; RGWBucketEntryPoint be; time_t mtime; map attrs; int ret = store->get_bucket_entrypoint_info(NULL, entry, be, &ot, &mtime, &attrs); if (ret < 0) return ret; RGWBucketEntryMetadataObject *mdo = new RGWBucketEntryMetadataObject(be, ot.read_version, mtime); *obj = mdo; return 0; } int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj, sync_type_t sync_type) { RGWBucketEntryPoint be, old_be; decode_json_obj(be, obj); time_t orig_mtime; map attrs; RGWObjVersionTracker old_ot; int ret = store->get_bucket_entrypoint_info(NULL, entry, old_be, &old_ot, &orig_mtime, &attrs); if (ret < 0 && ret != -ENOENT) return ret; // are we actually going to perform this put, or is it too old? if (ret != -ENOENT && !check_versions(old_ot.read_version, orig_mtime, objv_tracker.write_version, mtime, sync_type)) { return STATUS_NO_APPLY; } objv_tracker.read_version = old_ot.read_version; /* maintain the obj version we just read */ ret = store->put_bucket_entrypoint_info(entry, be, false, objv_tracker, mtime, &attrs); if (ret < 0) return ret; /* link bucket */ if (be.linked) { ret = rgw_link_bucket(store, be.owner, be.bucket, be.creation_time, false); } else { ret = rgw_unlink_bucket(store, be.owner, be.bucket.name, false); } return ret; } struct list_keys_info { RGWRados *store; RGWListRawObjsCtx ctx; }; int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) { RGWBucketEntryPoint be; int ret = store->get_bucket_entrypoint_info(NULL, entry, be, &objv_tracker, NULL, NULL); if (ret < 0) return ret; /* * We're unlinking the bucket but we don't want to update the entrypoint here — we're removing * it immediately and don't want to invalidate our cached objv_version or the bucket obj removal * will incorrectly fail. */ ret = rgw_unlink_bucket(store, be.owner, entry, false); if (ret < 0) { lderr(store->ctx()) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl; } ret = rgw_bucket_delete_bucket_obj(store, entry, objv_tracker); if (ret < 0) { lderr(store->ctx()) << "could not delete bucket=" << entry << dendl; } /* idempotent */ return 0; } void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) { oid = key; bucket = store->zone.domain_root; } int list_keys_init(RGWRados *store, void **phandle) { list_keys_info *info = new list_keys_info; info->store = store; *phandle = (void *)info; return 0; } int list_keys_next(void *handle, int max, list& keys, bool *truncated) { list_keys_info *info = static_cast(handle); string no_filter; keys.clear(); RGWRados *store = info->store; list unfiltered_keys; int ret = store->list_raw_objects(store->zone.domain_root, no_filter, max, info->ctx, unfiltered_keys, truncated); if (ret < 0 && ret != -ENOENT) return ret; if (ret == -ENOENT) { if (truncated) *truncated = false; return 0; } // now filter out the system entries list::iterator iter; for (iter = unfiltered_keys.begin(); iter != unfiltered_keys.end(); ++iter) { string& k = *iter; if (k[0] != '.') { keys.push_back(k); } } return 0; } void list_keys_complete(void *handle) { list_keys_info *info = static_cast(handle); delete info; } }; class RGWBucketInstanceMetadataHandler : public RGWMetadataHandler { int init_bucket(RGWRados *store, string& bucket_name, rgw_bucket& bucket, RGWObjVersionTracker *objv_tracker) { RGWBucketInfo bucket_info; int r = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL); if (r < 0) { cerr << "could not get bucket info for bucket=" << bucket_name << std::endl; return r; } bucket = bucket_info.bucket; return 0; } public: string get_type() { return "bucket.instance"; } int get(RGWRados *store, string& oid, RGWMetadataObject **obj) { RGWBucketCompleteInfo bci; time_t mtime; int ret = store->get_bucket_instance_info(NULL, oid, bci.info, &mtime, &bci.attrs); if (ret < 0) return ret; RGWBucketInstanceMetadataObject *mdo = new RGWBucketInstanceMetadataObject(bci, bci.info.objv_tracker.read_version, mtime); *obj = mdo; return 0; } int put(RGWRados *store, string& oid, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj, sync_type_t sync_type) { RGWBucketCompleteInfo bci, old_bci; decode_json_obj(bci, obj); time_t orig_mtime; int ret = store->get_bucket_instance_info(NULL, oid, old_bci.info, &orig_mtime, &old_bci.attrs); bool exists = (ret != -ENOENT); if (ret < 0 && exists) return ret; if (!exists || old_bci.info.bucket.bucket_id != bci.info.bucket.bucket_id) { /* a new bucket, we need to select a new bucket placement for it */ rgw_bucket bucket; ret = store->set_bucket_location_by_rule(bci.info.placement_rule, oid, bucket); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: select_bucket_placement() returned " << ret << dendl; return ret; } bci.info.bucket.data_pool = bucket.data_pool; bci.info.bucket.index_pool = bucket.index_pool; } else { /* existing bucket, keep its placement pools */ bci.info.bucket.data_pool = old_bci.info.bucket.data_pool; bci.info.bucket.index_pool = old_bci.info.bucket.index_pool; } // are we actually going to perform this put, or is it too old? if (exists && !check_versions(old_bci.info.objv_tracker.read_version, orig_mtime, objv_tracker.write_version, mtime, sync_type)) { objv_tracker.read_version = old_bci.info.objv_tracker.read_version; return STATUS_NO_APPLY; } /* record the read version (if any), store the new version */ bci.info.objv_tracker.read_version = old_bci.info.objv_tracker.read_version; bci.info.objv_tracker.write_version = objv_tracker.write_version; ret = store->put_bucket_instance_info(bci.info, false, mtime, &bci.attrs); if (ret < 0) return ret; objv_tracker = bci.info.objv_tracker; ret = store->init_bucket_index(bci.info.bucket); if (ret < 0) return ret; return STATUS_APPLIED; } struct list_keys_info { RGWRados *store; RGWListRawObjsCtx ctx; }; int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) { RGWBucketInfo info; int ret = store->get_bucket_instance_info(NULL, entry, info, NULL, NULL); if (ret < 0 && ret != -ENOENT) return ret; return rgw_bucket_instance_remove_entry(store, entry, &info.objv_tracker); } void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) { oid = RGW_BUCKET_INSTANCE_MD_PREFIX + key; bucket = store->zone.domain_root; } int list_keys_init(RGWRados *store, void **phandle) { list_keys_info *info = new list_keys_info; info->store = store; *phandle = (void *)info; return 0; } int list_keys_next(void *handle, int max, list& keys, bool *truncated) { list_keys_info *info = static_cast(handle); string no_filter; keys.clear(); RGWRados *store = info->store; list unfiltered_keys; int ret = store->list_raw_objects(store->zone.domain_root, no_filter, max, info->ctx, unfiltered_keys, truncated); if (ret < 0 && ret != -ENOENT) return ret; if (ret == -ENOENT) { if (truncated) *truncated = false; return 0; } int prefix_size = sizeof(RGW_BUCKET_INSTANCE_MD_PREFIX) - 1; // now filter in the relevant entries list::iterator iter; for (iter = unfiltered_keys.begin(); iter != unfiltered_keys.end(); ++iter) { string& k = *iter; if (k.compare(0, prefix_size, RGW_BUCKET_INSTANCE_MD_PREFIX) == 0) { keys.push_back(k.substr(prefix_size)); } } return 0; } void list_keys_complete(void *handle) { list_keys_info *info = static_cast(handle); delete info; } /* * hash entry for mdlog placement. Use the same hash key we'd have for the bucket entry * point, so that the log entries end up at the same log shard, so that we process them * in order */ virtual void get_hash_key(const string& section, const string& key, string& hash_key) { string k; int pos = key.find(':'); if (pos < 0) k = key; else k = key.substr(0, pos); hash_key = "bucket:" + k; } }; void rgw_bucket_init(RGWMetadataManager *mm) { bucket_meta_handler = new RGWBucketMetadataHandler; mm->register_handler(bucket_meta_handler); bucket_instance_meta_handler = new RGWBucketInstanceMetadataHandler; mm->register_handler(bucket_instance_meta_handler); } ceph-0.80.11/src/rgw/rgw_multi.cc0000664000175100017510000000260212623076744020603 0ustar jenkins-buildjenkins-build#include #include #include #include "include/types.h" #include "rgw_xml.h" #include "rgw_multi.h" #define dout_subsys ceph_subsys_rgw using namespace std; bool RGWMultiPart::xml_end(const char *el) { RGWMultiPartNumber *num_obj = static_cast(find_first("PartNumber")); RGWMultiETag *etag_obj = static_cast(find_first("ETag")); if (!num_obj || !etag_obj) return false; string s = num_obj->get_data(); if (s.empty()) return false; num = atoi(s.c_str()); s = etag_obj->get_data(); etag = s; return true; } bool RGWMultiCompleteUpload::xml_end(const char *el) { XMLObjIter iter = find("Part"); RGWMultiPart *part = static_cast(iter.get_next()); while (part) { int num = part->get_num(); string etag = part->get_etag(); parts[num] = etag; part = static_cast(iter.get_next()); } return true; } XMLObj *RGWMultiXMLParser::alloc_obj(const char *el) { XMLObj *obj = NULL; if (strcmp(el, "CompleteMultipartUpload") == 0 || strcmp(el, "MultipartUpload") == 0) { obj = new RGWMultiCompleteUpload(); } else if (strcmp(el, "Part") == 0) { obj = new RGWMultiPart(); } else if (strcmp(el, "PartNumber") == 0) { obj = new RGWMultiPartNumber(); } else if (strcmp(el, "ETag") == 0) { obj = new RGWMultiETag(); } return obj; } ceph-0.80.11/src/rgw/rgw_rest_user.h0000664000175100017510000000107612623076744021332 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_USER_H #define CEPH_RGW_REST_USER_H #include "rgw_rest.h" #include "rgw_rest_s3.h" class RGWHandler_User : public RGWHandler_Auth_S3 { protected: RGWOp *op_get(); RGWOp *op_put(); RGWOp *op_post(); RGWOp *op_delete(); public: RGWHandler_User() {} virtual ~RGWHandler_User() {} int read_permissions(RGWOp*) { return 0; } }; class RGWRESTMgr_User : public RGWRESTMgr { public: RGWRESTMgr_User() {} virtual ~RGWRESTMgr_User() {} RGWHandler *get_handler(struct req_state *s) { return new RGWHandler_User; } }; #endif ceph-0.80.11/src/rgw/rgw_rest_client.cc0000664000175100017510000004273012623076744021772 0ustar jenkins-buildjenkins-build#include "rgw_common.h" #include "rgw_rest_client.h" #include "rgw_auth_s3.h" #include "rgw_http_errors.h" #include "rgw_rados.h" #include "common/ceph_crypto_cms.h" #include "common/armor.h" #include "common/strtol.h" #define dout_subsys ceph_subsys_rgw int RGWRESTSimpleRequest::receive_header(void *ptr, size_t len) { char line[len + 1]; char *s = (char *)ptr, *end = (char *)ptr + len; char *p = line; ldout(cct, 10) << "receive_http_header" << dendl; while (s != end) { if (*s == '\r') { s++; continue; } if (*s == '\n') { *p = '\0'; ldout(cct, 10) << "received header:" << line << dendl; // TODO: fill whatever data required here char *l = line; char *tok = strsep(&l, " \t:"); if (tok && l) { while (*l == ' ') l++; if (strcmp(tok, "HTTP") == 0 || strncmp(tok, "HTTP/", 5) == 0) { http_status = atoi(l); if (http_status == 100) /* 100-continue response */ continue; status = rgw_http_error_to_errno(http_status); } else { /* convert header field name to upper case */ char *src = tok; char buf[len + 1]; size_t i; for (i = 0; i < len && *src; ++i, ++src) { switch (*src) { case '-': buf[i] = '_'; break; default: buf[i] = toupper(*src); } } buf[i] = '\0'; out_headers[buf] = l; int r = handle_header(buf, l); if (r < 0) return r; } } } if (s != end) *p++ = *s++; } return 0; } static void get_new_date_str(CephContext *cct, string& date_str) { utime_t tm = ceph_clock_now(cct); stringstream s; tm.asctime(s); date_str = s.str(); } int RGWRESTSimpleRequest::execute(RGWAccessKey& key, const char *method, const char *resource) { string new_url = url; string new_resource = resource; if (new_url[new_url.size() - 1] == '/' && resource[0] == '/') { new_url = new_url.substr(0, new_url.size() - 1); } else if (resource[0] != '/') { new_resource = "/"; new_resource.append(resource); } new_url.append(new_resource); string date_str; get_new_date_str(cct, date_str); headers.push_back(make_pair("HTTP_DATE", date_str)); string canonical_header; map meta_map; map sub_resources; rgw_create_s3_canonical_header(method, NULL, NULL, date_str.c_str(), meta_map, new_url.c_str(), sub_resources, canonical_header); string digest; int ret = rgw_get_s3_header_digest(canonical_header, key.key, digest); if (ret < 0) { return ret; } string auth_hdr = "AWS " + key.id + ":" + digest; ldout(cct, 15) << "generated auth header: " << auth_hdr << dendl; headers.push_back(make_pair("AUTHORIZATION", auth_hdr)); int r = process(method, new_url.c_str()); if (r < 0) return r; return status; } int RGWRESTSimpleRequest::send_data(void *ptr, size_t len) { if (!send_iter) return 0; if (len > send_iter->get_remaining()) len = send_iter->get_remaining(); send_iter->copy(len, (char *)ptr); return len; } int RGWRESTSimpleRequest::receive_data(void *ptr, size_t len) { if (response.length() > max_response) return 0; /* don't read extra data */ bufferptr p((char *)ptr, len); response.append(p); return 0; } void RGWRESTSimpleRequest::append_param(string& dest, const string& name, const string& val) { if (dest.empty()) { dest.append("?"); } else { dest.append("&"); } dest.append(name); if (!val.empty()) { dest.append("="); dest.append(val); } } void RGWRESTSimpleRequest::get_params_str(map& extra_args, string& dest) { map::iterator miter; for (miter = extra_args.begin(); miter != extra_args.end(); ++miter) { append_param(dest, miter->first, miter->second); } list >::iterator iter; for (iter = params.begin(); iter != params.end(); ++iter) { append_param(dest, iter->first, iter->second); } } int RGWRESTSimpleRequest::sign_request(RGWAccessKey& key, RGWEnv& env, req_info& info) { map& m = env.get_map(); map::iterator i; for (i = m.begin(); i != m.end(); ++i) { ldout(cct, 0) << "> " << i->first << " -> " << i->second << dendl; } string canonical_header; if (!rgw_create_s3_canonical_header(info, NULL, canonical_header, false)) { ldout(cct, 0) << "failed to create canonical s3 header" << dendl; return -EINVAL; } ldout(cct, 10) << "generated canonical header: " << canonical_header << dendl; string digest; int ret = rgw_get_s3_header_digest(canonical_header, key.key, digest); if (ret < 0) { return ret; } string auth_hdr = "AWS " + key.id + ":" + digest; ldout(cct, 15) << "generated auth header: " << auth_hdr << dendl; m["AUTHORIZATION"] = auth_hdr; return 0; } int RGWRESTSimpleRequest::forward_request(RGWAccessKey& key, req_info& info, size_t max_response, bufferlist *inbl, bufferlist *outbl) { string date_str; get_new_date_str(cct, date_str); RGWEnv new_env; req_info new_info(cct, &new_env); new_info.rebuild_from(info); new_env.set("HTTP_DATE", date_str.c_str()); int ret = sign_request(key, new_env, new_info); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to sign request" << dendl; return ret; } map& m = new_env.get_map(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { headers.push_back(make_pair(iter->first, iter->second)); } map& meta_map = new_info.x_meta_map; for (iter = meta_map.begin(); iter != meta_map.end(); ++iter) { headers.push_back(make_pair(iter->first, iter->second)); } string params_str; map& args = new_info.args.get_params(); get_params_str(args, params_str); string new_url = url; string& resource = new_info.request_uri; string new_resource = resource; if (new_url[new_url.size() - 1] == '/' && resource[0] == '/') { new_url = new_url.substr(0, new_url.size() - 1); } else if (resource[0] != '/') { new_resource = "/"; new_resource.append(resource); } new_url.append(new_resource + params_str); bufferlist::iterator bliter; if (inbl) { bliter = inbl->begin(); send_iter = &bliter; set_send_length(inbl->length()); } int r = process(new_info.method, new_url.c_str()); if (r < 0) return r; response.append((char)0); /* NULL terminate response */ if (outbl) { outbl->claim(response); } return status; } class RGWRESTStreamOutCB : public RGWGetDataCB { RGWRESTStreamWriteRequest *req; public: RGWRESTStreamOutCB(RGWRESTStreamWriteRequest *_req) : req(_req) {} int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len); /* callback for object iteration when sending data */ }; int RGWRESTStreamOutCB::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) { dout(20) << "RGWRESTStreamOutCB::handle_data bl.length()=" << bl.length() << " bl_ofs=" << bl_ofs << " bl_len=" << bl_len << dendl; if (!bl_ofs && bl_len == bl.length()) { return req->add_output_data(bl); } bufferptr bp(bl.c_str() + bl_ofs, bl_len); bufferlist new_bl; new_bl.push_back(bp); return req->add_output_data(new_bl); } RGWRESTStreamWriteRequest::~RGWRESTStreamWriteRequest() { delete cb; } int RGWRESTStreamWriteRequest::add_output_data(bufferlist& bl) { lock.Lock(); if (status < 0) { int ret = status; lock.Unlock(); return ret; } pending_send.push_back(bl); lock.Unlock(); bool done; return process_request(handle, false, &done); } static void grants_by_type_add_one_grant(map& grants_by_type, int perm, ACLGrant& grant) { string& s = grants_by_type[perm]; if (!s.empty()) s.append(", "); string id_type_str; ACLGranteeType& type = grant.get_type(); switch (type.get_type()) { case ACL_TYPE_GROUP: id_type_str = "uri"; break; case ACL_TYPE_EMAIL_USER: id_type_str = "emailAddress"; break; default: id_type_str = "id"; } string id; grant.get_id(id); s.append(id_type_str + "=\"" + id + "\""); } struct grant_type_to_header { int type; const char *header; }; struct grant_type_to_header grants_headers_def[] = { { RGW_PERM_FULL_CONTROL, "x-amz-grant-full-control"}, { RGW_PERM_READ, "x-amz-grant-read"}, { RGW_PERM_WRITE, "x-amz-grant-write"}, { RGW_PERM_READ_ACP, "x-amz-grant-read-acp"}, { RGW_PERM_WRITE_ACP, "x-amz-grant-write-acp"}, { 0, NULL} }; static bool grants_by_type_check_perm(map& grants_by_type, int perm, ACLGrant& grant, int check_perm) { if ((perm & check_perm) == perm) { grants_by_type_add_one_grant(grants_by_type, check_perm, grant); return true; } return false; } static void grants_by_type_add_perm(map& grants_by_type, int perm, ACLGrant& grant) { struct grant_type_to_header *t; for (t = grants_headers_def; t->header; t++) { if (grants_by_type_check_perm(grants_by_type, perm, grant, t->type)) return; } } static void add_grants_headers(map& grants, map& attrs, map& meta_map) { struct grant_type_to_header *t; for (t = grants_headers_def; t->header; t++) { map::iterator iter = grants.find(t->type); if (iter != grants.end()) { attrs[t->header] = iter->second; meta_map[t->header] = iter->second; } } } int RGWRESTStreamWriteRequest::put_obj_init(RGWAccessKey& key, rgw_obj& obj, uint64_t obj_size, map& attrs) { string resource = obj.bucket.name + "/" + obj.object; string new_url = url; if (new_url[new_url.size() - 1] != '/') new_url.append("/"); string date_str; get_new_date_str(cct, date_str); RGWEnv new_env; req_info new_info(cct, &new_env); string params_str; map& args = new_info.args.get_params(); get_params_str(args, params_str); new_url.append(resource + params_str); new_env.set("HTTP_DATE", date_str.c_str()); new_info.method = "PUT"; new_info.script_uri = "/"; new_info.script_uri.append(resource); new_info.request_uri = new_info.script_uri; new_info.effective_uri = new_info.effective_uri; map& m = new_env.get_map(); map::iterator bliter; /* merge send headers */ for (bliter = attrs.begin(); bliter != attrs.end(); ++bliter) { bufferlist& bl = bliter->second; const string& name = bliter->first; string val = bl.c_str(); if (name.compare(0, sizeof(RGW_ATTR_META_PREFIX) - 1, RGW_ATTR_META_PREFIX) == 0) { string header_name = RGW_AMZ_META_PREFIX; header_name.append(name.substr(sizeof(RGW_ATTR_META_PREFIX) - 1)); m[header_name] = val; new_info.x_meta_map[header_name] = val; } } RGWAccessControlPolicy policy; int ret = rgw_policy_from_attrset(cct, attrs, &policy); if (ret < 0) { ldout(cct, 0) << "ERROR: couldn't get policy ret=" << ret << dendl; return ret; } /* update acl headers */ RGWAccessControlList& acl = policy.get_acl(); multimap& grant_map = acl.get_grant_map(); multimap::iterator giter; map grants_by_type; for (giter = grant_map.begin(); giter != grant_map.end(); ++giter) { ACLGrant& grant = giter->second; ACLPermission& perm = grant.get_permission(); grants_by_type_add_perm(grants_by_type, perm.get_permissions(), grant); } add_grants_headers(grants_by_type, m, new_info.x_meta_map); ret = sign_request(key, new_env, new_info); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to sign request" << dendl; return ret; } map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { headers.push_back(make_pair(iter->first, iter->second)); } cb = new RGWRESTStreamOutCB(this); set_send_length(obj_size); int r = init_async(new_info.method, new_url.c_str(), &handle); if (r < 0) return r; return 0; } int RGWRESTStreamWriteRequest::send_data(void *ptr, size_t len) { uint64_t sent = 0; dout(20) << "RGWRESTStreamWriteRequest::send_data()" << dendl; lock.Lock(); if (pending_send.empty() || status < 0) { lock.Unlock(); return status; } list::iterator iter = pending_send.begin(); while (iter != pending_send.end() && len > 0) { bufferlist& bl = *iter; list::iterator next_iter = iter; ++next_iter; lock.Unlock(); uint64_t send_len = min(len, (size_t)bl.length()); memcpy(ptr, bl.c_str(), send_len); ptr = (char *)ptr + send_len; len -= send_len; sent += send_len; lock.Lock(); bufferlist new_bl; if (bl.length() > send_len) { bufferptr bp(bl.c_str() + send_len, bl.length() - send_len); new_bl.append(bp); } pending_send.pop_front(); /* need to do this after we copy data from bl */ if (new_bl.length()) { pending_send.push_front(new_bl); } iter = next_iter; } lock.Unlock(); return sent; } void set_str_from_headers(map& out_headers, const string& header_name, string& str) { map::iterator iter = out_headers.find(header_name); if (iter != out_headers.end()) { str = iter->second; } else { str.clear(); } } int RGWRESTStreamWriteRequest::complete(string& etag, time_t *mtime) { int ret = complete_request(handle); if (ret < 0) return ret; set_str_from_headers(out_headers, "ETAG", etag); if (mtime) { string mtime_str; set_str_from_headers(out_headers, "RGWX_MTIME", mtime_str); string err; long t = strict_strtol(mtime_str.c_str(), 10, &err); if (!err.empty()) { ldout(cct, 0) << "ERROR: failed converting mtime (" << mtime_str << ") to int " << dendl; return -EINVAL; } *mtime = (time_t)t; } return status; } int RGWRESTStreamReadRequest::get_obj(RGWAccessKey& key, map& extra_headers, rgw_obj& obj) { string urlsafe_bucket, urlsafe_object; url_encode(obj.bucket.name, urlsafe_bucket); url_encode(obj.object, urlsafe_object); string resource = urlsafe_bucket + "/" + urlsafe_object; string new_url = url; if (new_url[new_url.size() - 1] != '/') new_url.append("/"); string date_str; get_new_date_str(cct, date_str); RGWEnv new_env; req_info new_info(cct, &new_env); string params_str; map& args = new_info.args.get_params(); get_params_str(args, params_str); new_url.append(resource + params_str); new_env.set("HTTP_DATE", date_str.c_str()); for (map::iterator iter = extra_headers.begin(); iter != extra_headers.end(); ++iter) { new_env.set(iter->first.c_str(), iter->second.c_str()); } new_info.method = "GET"; new_info.script_uri = "/"; new_info.script_uri.append(resource); new_info.request_uri = new_info.script_uri; new_info.effective_uri = new_info.effective_uri; new_info.init_meta_info(NULL); int ret = sign_request(key, new_env, new_info); if (ret < 0) { ldout(cct, 0) << "ERROR: failed to sign request" << dendl; return ret; } map& m = new_env.get_map(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { headers.push_back(make_pair(iter->first, iter->second)); } int r = process(new_info.method, new_url.c_str()); if (r < 0) return r; return 0; } int RGWRESTStreamReadRequest::complete(string& etag, time_t *mtime, map& attrs) { set_str_from_headers(out_headers, "ETAG", etag); if (mtime) { string mtime_str; set_str_from_headers(out_headers, "RGWX_MTIME", mtime_str); if (!mtime_str.empty()) { string err; long t = strict_strtol(mtime_str.c_str(), 10, &err); if (!err.empty()) { ldout(cct, 0) << "ERROR: failed converting mtime (" << mtime_str << ") to int " << dendl; return -EINVAL; } *mtime = (time_t)t; } } map::iterator iter; for (iter = out_headers.begin(); iter != out_headers.end(); ++iter) { const string& attr_name = iter->first; if (attr_name.compare(0, sizeof(RGW_HTTP_RGWX_ATTR_PREFIX) - 1, RGW_HTTP_RGWX_ATTR_PREFIX) == 0) { string name = attr_name.substr(sizeof(RGW_HTTP_RGWX_ATTR_PREFIX) - 1); const char *src = name.c_str(); char buf[name.size() + 1]; char *dest = buf; for (; *src; ++src, ++dest) { switch(*src) { case '_': *dest = '-'; break; default: *dest = tolower(*src); } } *dest = '\0'; attrs[buf] = iter->second; } } return status; } int RGWRESTStreamReadRequest::handle_header(const string& name, const string& val) { if (name == "RGWX_EMBEDDED_METADATA_LEN") { string err; long len = strict_strtol(val.c_str(), 10, &err); if (!err.empty()) { ldout(cct, 0) << "ERROR: failed converting embedded metadata len (" << val << ") to int " << dendl; return -EINVAL; } cb->set_extra_data_len(len); } return 0; } int RGWRESTStreamReadRequest::receive_data(void *ptr, size_t len) { bufferptr bp((const char *)ptr, len); bufferlist bl; bl.append(bp); int ret = cb->handle_data(bl, ofs, len); if (ret < 0) return ret; ofs += len; return len; } int RGWRESTStreamReadRequest::send_data(void *ptr, size_t len) { /* not sending any data */ return 0; } ceph-0.80.11/src/rgw/rgw_client_io.cc0000664000175100017510000000257312623076744021425 0ustar jenkins-buildjenkins-build #include #include #include #include "rgw_client_io.h" #define dout_subsys ceph_subsys_rgw void RGWClientIO::init(CephContext *cct) { init_env(cct); if (cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) { std::map& env_map = env.get_map(); std::map::iterator iter = env_map.begin(); for (iter = env_map.begin(); iter != env_map.end(); ++iter) { ldout(cct, 20) << iter->first << "=" << iter->second << dendl; } } } int RGWClientIO::print(const char *format, ...) { #define LARGE_ENOUGH 128 int size = LARGE_ENOUGH; va_list ap; while(1) { char buf[size]; va_start(ap, format); int ret = vsnprintf(buf, size, format, ap); va_end(ap); if (ret >= 0 && ret < size) { return write(buf, ret); } if (ret >= 0) size = ret + 1; else size *= 2; } /* not reachable */ } int RGWClientIO::write(const char *buf, int len) { int ret = write_data(buf, len); if (ret < 0) return ret; if (account) bytes_sent += ret; if (ret < len) { /* sent less than tried to send, error out */ return -EIO; } return 0; } int RGWClientIO::read(char *buf, int max, int *actual) { int ret = read_data(buf, max); if (ret < 0) return ret; *actual = ret; bytes_received += *actual; return 0; } ceph-0.80.11/src/rgw/rgw_quota.cc0000664000175100017510000005552212623076744020613 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/utime.h" #include "common/lru_map.h" #include "common/RefCountedObj.h" #include "common/Thread.h" #include "common/Mutex.h" #include "common/RWLock.h" #include "rgw_common.h" #include "rgw_rados.h" #include "rgw_quota.h" #include "rgw_bucket.h" #include "rgw_user.h" #define dout_subsys ceph_subsys_rgw struct RGWQuotaCacheStats { RGWStorageStats stats; utime_t expiration; utime_t async_refresh_time; }; template class RGWQuotaCache { protected: RGWRados *store; lru_map stats_map; RefCountedWaitObject *async_refcount; class StatsAsyncTestSet : public lru_map::UpdateContext { int objs_delta; uint64_t added_bytes; uint64_t removed_bytes; public: StatsAsyncTestSet() {} bool update(RGWQuotaCacheStats *entry) { if (entry->async_refresh_time.sec() == 0) return false; entry->async_refresh_time = utime_t(0, 0); return true; } }; virtual int fetch_stats_from_storage(const string& user, rgw_bucket& bucket, RGWStorageStats& stats) = 0; virtual bool map_find(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) = 0; virtual bool map_find_and_update(const string& user, rgw_bucket& bucket, typename lru_map::UpdateContext *ctx) = 0; virtual void map_add(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) = 0; virtual void data_modified(const string& user, rgw_bucket& bucket) {} public: RGWQuotaCache(RGWRados *_store, int size) : store(_store), stats_map(size) { async_refcount = new RefCountedWaitObject; } virtual ~RGWQuotaCache() { async_refcount->put_wait(); /* wait for all pending async requests to complete */ } int get_stats(const string& user, rgw_bucket& bucket, RGWStorageStats& stats, RGWQuotaInfo& quota); void adjust_stats(const string& user, rgw_bucket& bucket, int objs_delta, uint64_t added_bytes, uint64_t removed_bytes); virtual bool can_use_cached_stats(RGWQuotaInfo& quota, RGWStorageStats& stats); void set_stats(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs, RGWStorageStats& stats); int async_refresh(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs); void async_refresh_response(const string& user, rgw_bucket& bucket, RGWStorageStats& stats); class AsyncRefreshHandler { protected: RGWRados *store; RGWQuotaCache *cache; public: AsyncRefreshHandler(RGWRados *_store, RGWQuotaCache *_cache) : store(_store), cache(_cache) {} virtual ~AsyncRefreshHandler() {} virtual int init_fetch() = 0; virtual void drop_reference() = 0; }; virtual AsyncRefreshHandler *allocate_refresh_handler(const string& user, rgw_bucket& bucket) = 0; }; template bool RGWQuotaCache::can_use_cached_stats(RGWQuotaInfo& quota, RGWStorageStats& cached_stats) { if (quota.max_size_kb >= 0) { if (quota.max_size_soft_threshold < 0) { quota.max_size_soft_threshold = quota.max_size_kb * store->ctx()->_conf->rgw_bucket_quota_soft_threshold; } if (cached_stats.num_kb_rounded >= (uint64_t)quota.max_size_soft_threshold) { ldout(store->ctx(), 20) << "quota: can't use cached stats, exceeded soft threshold (size): " << cached_stats.num_kb_rounded << " >= " << quota.max_size_soft_threshold << dendl; return false; } } if (quota.max_objects >= 0) { if (quota.max_objs_soft_threshold < 0) { quota.max_objs_soft_threshold = quota.max_objects * store->ctx()->_conf->rgw_bucket_quota_soft_threshold; } if (cached_stats.num_objects >= (uint64_t)quota.max_objs_soft_threshold) { ldout(store->ctx(), 20) << "quota: can't use cached stats, exceeded soft threshold (num objs): " << cached_stats.num_objects << " >= " << quota.max_objs_soft_threshold << dendl; return false; } } return true; } template int RGWQuotaCache::async_refresh(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) { /* protect against multiple updates */ StatsAsyncTestSet test_update; if (!map_find_and_update(user, bucket, &test_update)) { /* most likely we just raced with another update */ return 0; } async_refcount->get(); AsyncRefreshHandler *handler = allocate_refresh_handler(user, bucket); int ret = handler->init_fetch(); if (ret < 0) { async_refcount->put(); handler->drop_reference(); return ret; } return 0; } template void RGWQuotaCache::async_refresh_response(const string& user, rgw_bucket& bucket, RGWStorageStats& stats) { ldout(store->ctx(), 20) << "async stats refresh response for bucket=" << bucket << dendl; RGWQuotaCacheStats qs; map_find(user, bucket, qs); set_stats(user, bucket, qs, stats); async_refcount->put(); } template void RGWQuotaCache::set_stats(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs, RGWStorageStats& stats) { qs.stats = stats; qs.expiration = ceph_clock_now(store->ctx()); qs.async_refresh_time = qs.expiration; qs.expiration += store->ctx()->_conf->rgw_bucket_quota_ttl; qs.async_refresh_time += store->ctx()->_conf->rgw_bucket_quota_ttl / 2; map_add(user, bucket, qs); } template int RGWQuotaCache::get_stats(const string& user, rgw_bucket& bucket, RGWStorageStats& stats, RGWQuotaInfo& quota) { RGWQuotaCacheStats qs; utime_t now = ceph_clock_now(store->ctx()); if (map_find(user, bucket, qs)) { if (qs.async_refresh_time.sec() > 0 && now >= qs.async_refresh_time) { int r = async_refresh(user, bucket, qs); if (r < 0) { ldout(store->ctx(), 0) << "ERROR: quota async refresh returned ret=" << r << dendl; /* continue processing, might be a transient error, async refresh is just optimization */ } } if (can_use_cached_stats(quota, qs.stats) && qs.expiration > ceph_clock_now(store->ctx())) { stats = qs.stats; return 0; } } int ret = fetch_stats_from_storage(user, bucket, stats); if (ret < 0 && ret != -ENOENT) return ret; set_stats(user, bucket, qs, stats); return 0; } template class RGWQuotaStatsUpdate : public lru_map::UpdateContext { int objs_delta; uint64_t added_bytes; uint64_t removed_bytes; public: RGWQuotaStatsUpdate(int _objs_delta, uint64_t _added_bytes, uint64_t _removed_bytes) : objs_delta(_objs_delta), added_bytes(_added_bytes), removed_bytes(_removed_bytes) {} bool update(RGWQuotaCacheStats *entry) { uint64_t rounded_kb_added = rgw_rounded_objsize_kb(added_bytes); uint64_t rounded_kb_removed = rgw_rounded_objsize_kb(removed_bytes); entry->stats.num_kb_rounded += (rounded_kb_added - rounded_kb_removed); entry->stats.num_kb += (added_bytes - removed_bytes) / 1024; entry->stats.num_objects += objs_delta; return true; } }; template void RGWQuotaCache::adjust_stats(const string& user, rgw_bucket& bucket, int objs_delta, uint64_t added_bytes, uint64_t removed_bytes) { RGWQuotaStatsUpdate update(objs_delta, added_bytes, removed_bytes); map_find_and_update(user, bucket, &update); data_modified(user, bucket); } class BucketAsyncRefreshHandler : public RGWQuotaCache::AsyncRefreshHandler, public RGWGetBucketStats_CB { string user; public: BucketAsyncRefreshHandler(RGWRados *_store, RGWQuotaCache *_cache, const string& _user, rgw_bucket& _bucket) : RGWQuotaCache::AsyncRefreshHandler(_store, _cache), RGWGetBucketStats_CB(_bucket), user(_user) {} void drop_reference() { put(); } void handle_response(int r); int init_fetch(); }; int BucketAsyncRefreshHandler::init_fetch() { ldout(store->ctx(), 20) << "initiating async quota refresh for bucket=" << bucket << dendl; int r = store->get_bucket_stats_async(bucket, this); if (r < 0) { ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket.name << dendl; /* get_bucket_stats_async() dropped our reference already */ return r; } return 0; } void BucketAsyncRefreshHandler::handle_response(int r) { if (r < 0) { ldout(store->ctx(), 20) << "AsyncRefreshHandler::handle_response() r=" << r << dendl; return; /* nothing to do here */ } RGWStorageStats bs; map::iterator iter; for (iter = stats->begin(); iter != stats->end(); ++iter) { RGWStorageStats& s = iter->second; bs.num_kb += s.num_kb; bs.num_kb_rounded += s.num_kb_rounded; bs.num_objects += s.num_objects; } cache->async_refresh_response(user, bucket, bs); } class RGWBucketStatsCache : public RGWQuotaCache { protected: bool map_find(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) { return stats_map.find(bucket, qs); } bool map_find_and_update(const string& user, rgw_bucket& bucket, lru_map::UpdateContext *ctx) { return stats_map.find_and_update(bucket, NULL, ctx); } void map_add(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) { stats_map.add(bucket, qs); } int fetch_stats_from_storage(const string& user, rgw_bucket& bucket, RGWStorageStats& stats); public: RGWBucketStatsCache(RGWRados *_store) : RGWQuotaCache(_store, _store->ctx()->_conf->rgw_bucket_quota_cache_size) { } AsyncRefreshHandler *allocate_refresh_handler(const string& user, rgw_bucket& bucket) { return new BucketAsyncRefreshHandler(store, this, user, bucket); } }; int RGWBucketStatsCache::fetch_stats_from_storage(const string& user, rgw_bucket& bucket, RGWStorageStats& stats) { RGWBucketInfo bucket_info; uint64_t bucket_ver; uint64_t master_ver; map bucket_stats; int r = store->get_bucket_stats(bucket, &bucket_ver, &master_ver, bucket_stats, NULL); if (r < 0) { ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket.name << dendl; return r; } stats = RGWStorageStats(); map::iterator iter; for (iter = bucket_stats.begin(); iter != bucket_stats.end(); ++iter) { RGWStorageStats& s = iter->second; stats.num_kb += s.num_kb; stats.num_kb_rounded += s.num_kb_rounded; stats.num_objects += s.num_objects; } return 0; } class UserAsyncRefreshHandler : public RGWQuotaCache::AsyncRefreshHandler, public RGWGetUserStats_CB { rgw_bucket bucket; public: UserAsyncRefreshHandler(RGWRados *_store, RGWQuotaCache *_cache, const string& _user, rgw_bucket& _bucket) : RGWQuotaCache::AsyncRefreshHandler(_store, _cache), RGWGetUserStats_CB(_user), bucket(_bucket) {} void drop_reference() { put(); } int init_fetch(); void handle_response(int r); }; int UserAsyncRefreshHandler::init_fetch() { ldout(store->ctx(), 20) << "initiating async quota refresh for user=" << user << dendl; int r = store->get_user_stats_async(user, this); if (r < 0) { ldout(store->ctx(), 0) << "could not get bucket info for user=" << user << dendl; /* get_bucket_stats_async() dropped our reference already */ return r; } return 0; } void UserAsyncRefreshHandler::handle_response(int r) { if (r < 0) { ldout(store->ctx(), 20) << "AsyncRefreshHandler::handle_response() r=" << r << dendl; return; /* nothing to do here */ } cache->async_refresh_response(user, bucket, stats); } class RGWUserStatsCache : public RGWQuotaCache { atomic_t down_flag; RWLock rwlock; map modified_buckets; /* thread, sync recent modified buckets info */ class BucketsSyncThread : public Thread { CephContext *cct; RGWUserStatsCache *stats; Mutex lock; Cond cond; public: BucketsSyncThread(CephContext *_cct, RGWUserStatsCache *_s) : cct(_cct), stats(_s), lock("RGWUserStatsCache::BucketsSyncThread") {} void *entry() { ldout(cct, 20) << "BucketsSyncThread: start" << dendl; do { map buckets; stats->swap_modified_buckets(buckets); for (map::iterator iter = buckets.begin(); iter != buckets.end(); ++iter) { rgw_bucket bucket = iter->first; string& user = iter->second; ldout(cct, 20) << "BucketsSyncThread: sync user=" << user << " bucket=" << bucket << dendl; int r = stats->sync_bucket(user, bucket); if (r < 0) { ldout(cct, 0) << "WARNING: sync_bucket() returned r=" << r << dendl; } } if (stats->going_down()) break; lock.Lock(); cond.WaitInterval(cct, lock, utime_t(cct->_conf->rgw_user_quota_bucket_sync_interval, 0)); lock.Unlock(); } while (!stats->going_down()); ldout(cct, 20) << "BucketsSyncThread: done" << dendl; return NULL; } void stop() { Mutex::Locker l(lock); cond.Signal(); } }; /* * thread, full sync all users stats periodically * * only sync non idle users or ones that never got synced before, this is needed so that * users that didn't have quota turned on before (or existed before the user objclass * tracked stats) need to get their backend stats up to date. */ class UserSyncThread : public Thread { CephContext *cct; RGWUserStatsCache *stats; Mutex lock; Cond cond; public: UserSyncThread(CephContext *_cct, RGWUserStatsCache *_s) : cct(_cct), stats(_s), lock("RGWUserStatsCache::UserSyncThread") {} void *entry() { ldout(cct, 20) << "UserSyncThread: start" << dendl; do { string key = "user"; int ret = stats->sync_all_users(); if (ret < 0) { ldout(cct, 0) << "ERROR: sync_all_users() returned ret=" << ret << dendl; } lock.Lock(); cond.WaitInterval(cct, lock, utime_t(cct->_conf->rgw_user_quota_sync_interval, 0)); lock.Unlock(); } while (!stats->going_down()); ldout(cct, 20) << "UserSyncThread: done" << dendl; return NULL; } void stop() { Mutex::Locker l(lock); cond.Signal(); } }; BucketsSyncThread *buckets_sync_thread; UserSyncThread *user_sync_thread; protected: bool map_find(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) { return stats_map.find(user, qs); } bool map_find_and_update(const string& user, rgw_bucket& bucket, lru_map::UpdateContext *ctx) { return stats_map.find_and_update(user, NULL, ctx); } void map_add(const string& user, rgw_bucket& bucket, RGWQuotaCacheStats& qs) { stats_map.add(user, qs); } int fetch_stats_from_storage(const string& user, rgw_bucket& bucket, RGWStorageStats& stats); int sync_bucket(const string& user, rgw_bucket& bucket); int sync_user(const string& user); int sync_all_users(); void data_modified(const string& user, rgw_bucket& bucket); void swap_modified_buckets(map& out) { rwlock.get_write(); modified_buckets.swap(out); rwlock.unlock(); } template /* easier doing it as a template, Thread doesn't have ->stop() */ void stop_thread(T **pthr) { T *thread = *pthr; if (!thread) return; thread->stop(); thread->join(); delete thread; *pthr = NULL; } public: RGWUserStatsCache(RGWRados *_store, bool quota_threads) : RGWQuotaCache(_store, _store->ctx()->_conf->rgw_bucket_quota_cache_size), rwlock("RGWUserStatsCache::rwlock") { if (quota_threads) { buckets_sync_thread = new BucketsSyncThread(store->ctx(), this); buckets_sync_thread->create(); user_sync_thread = new UserSyncThread(store->ctx(), this); user_sync_thread->create(); } else { buckets_sync_thread = NULL; user_sync_thread = NULL; } } ~RGWUserStatsCache() { stop(); } AsyncRefreshHandler *allocate_refresh_handler(const string& user, rgw_bucket& bucket) { return new UserAsyncRefreshHandler(store, this, user, bucket); } bool can_use_cached_stats(RGWQuotaInfo& quota, RGWStorageStats& stats) { /* in the user case, the cached stats may contain a better estimation of the totals, as * the backend is only periodically getting updated. */ return true; } bool going_down() { return (down_flag.read() != 0); } void stop() { down_flag.set(1); rwlock.get_write(); stop_thread(&buckets_sync_thread); rwlock.unlock(); stop_thread(&user_sync_thread); } }; int RGWUserStatsCache::fetch_stats_from_storage(const string& user, rgw_bucket& bucket, RGWStorageStats& stats) { int r = store->get_user_stats(user, stats); if (r < 0) { ldout(store->ctx(), 0) << "could not get user stats for user=" << user << dendl; return r; } return 0; } int RGWUserStatsCache::sync_bucket(const string& user, rgw_bucket& bucket) { int r = rgw_bucket_sync_user_stats(store, user, bucket); if (r < 0) { ldout(store->ctx(), 0) << "ERROR: rgw_bucket_sync_user_stats() for user=" << user << ", bucket=" << bucket << " returned " << r << dendl; return r; } return 0; } int RGWUserStatsCache::sync_user(const string& user) { cls_user_header header; int ret = store->cls_user_get_header(user, &header); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: can't read user header: ret=" << ret << dendl; return ret; } if (!store->ctx()->_conf->rgw_user_quota_sync_idle_users && header.last_stats_update < header.last_stats_sync) { ldout(store->ctx(), 20) << "user is idle, not doing a full sync (user=" << user << ")" << dendl; return 0; } utime_t when_need_full_sync = header.last_stats_sync; when_need_full_sync += store->ctx()->_conf->rgw_user_quota_sync_wait_time; // check if enough time passed since last full sync ret = rgw_user_sync_all_stats(store, user); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: failed user stats sync, ret=" << ret << dendl; return ret; } return 0; } int RGWUserStatsCache::sync_all_users() { string key = "user"; void *handle; int ret = store->meta_mgr->list_keys_init(key, &handle); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: can't get key: ret=" << ret << dendl; return ret; } bool truncated; int max = 1000; do { list keys; ret = store->meta_mgr->list_keys_next(handle, max, keys, &truncated); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: lists_keys_next(): ret=" << ret << dendl; goto done; } for (list::iterator iter = keys.begin(); iter != keys.end() && !going_down(); ++iter) { string& user = *iter; ldout(store->ctx(), 20) << "RGWUserStatsCache: sync user=" << user << dendl; int ret = sync_user(user); if (ret < 0) { ldout(store->ctx(), 0) << "ERROR: sync_user() failed, user=" << user << " ret=" << ret << dendl; /* continuing to next user */ continue; } } } while (truncated); ret = 0; done: store->meta_mgr->list_keys_complete(handle); return ret; } void RGWUserStatsCache::data_modified(const string& user, rgw_bucket& bucket) { /* racy, but it's ok */ rwlock.get_read(); bool need_update = modified_buckets.find(bucket) == modified_buckets.end(); rwlock.unlock(); if (need_update) { rwlock.get_write(); modified_buckets[bucket] = user; rwlock.unlock(); } } class RGWQuotaHandlerImpl : public RGWQuotaHandler { RGWRados *store; RGWBucketStatsCache bucket_stats_cache; RGWUserStatsCache user_stats_cache; int check_quota(const char *entity, RGWQuotaInfo& quota, RGWStorageStats& stats, uint64_t num_objs, uint64_t size_kb) { ldout(store->ctx(), 20) << entity << " quota: max_objects=" << quota.max_objects << " max_size_kb=" << quota.max_size_kb << dendl; if (quota.max_objects >= 0 && stats.num_objects + num_objs > (uint64_t)quota.max_objects) { ldout(store->ctx(), 10) << "quota exceeded: stats.num_objects=" << stats.num_objects << " " << entity << "_quota.max_objects=" << quota.max_objects << dendl; return -ERR_QUOTA_EXCEEDED; } if (quota.max_size_kb >= 0 && stats.num_kb_rounded + size_kb > (uint64_t)quota.max_size_kb) { ldout(store->ctx(), 10) << "quota exceeded: stats.num_kb_rounded=" << stats.num_kb_rounded << " size_kb=" << size_kb << " " << entity << "_quota.max_size_kb=" << quota.max_size_kb << dendl; return -ERR_QUOTA_EXCEEDED; } return 0; } public: RGWQuotaHandlerImpl(RGWRados *_store, bool quota_threads) : store(_store), bucket_stats_cache(_store), user_stats_cache(_store, quota_threads) {} virtual int check_quota(const string& user, rgw_bucket& bucket, RGWQuotaInfo& user_quota, RGWQuotaInfo& bucket_quota, uint64_t num_objs, uint64_t size) { if (!bucket_quota.enabled && !user_quota.enabled) return 0; uint64_t size_kb = rgw_rounded_objsize_kb(size); RGWStorageStats bucket_stats; /* * we need to fetch bucket stats if the user quota is enabled, because the whole system relies * on us periodically updating the user's bucket stats in the user's header, this happens in * get_stats() if we actually fetch that info and not rely on cached data */ int ret = bucket_stats_cache.get_stats(user, bucket, bucket_stats, bucket_quota); if (ret < 0) return ret; if (bucket_quota.enabled) { ret = check_quota("bucket", bucket_quota, bucket_stats, num_objs, size_kb); if (ret < 0) return ret; } if (user_quota.enabled) { RGWStorageStats user_stats; ret = user_stats_cache.get_stats(user, bucket, user_stats, user_quota); if (ret < 0) return ret; ret = check_quota("user", user_quota, user_stats, num_objs, size_kb); if (ret < 0) return ret; } return 0; } virtual void update_stats(const string& user, rgw_bucket& bucket, int obj_delta, uint64_t added_bytes, uint64_t removed_bytes) { bucket_stats_cache.adjust_stats(user, bucket, obj_delta, added_bytes, removed_bytes); user_stats_cache.adjust_stats(user, bucket, obj_delta, added_bytes, removed_bytes); }; }; RGWQuotaHandler *RGWQuotaHandler::generate_handler(RGWRados *store, bool quota_threads) { return new RGWQuotaHandlerImpl(store, quota_threads); }; void RGWQuotaHandler::free_handler(RGWQuotaHandler *handler) { delete handler; } ceph-0.80.11/src/rgw/rgw_rest_opstate.cc0000664000175100017510000001125512623076744022171 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_json.h" #include "common/strtol.h" #include "rgw_rest.h" #include "rgw_op.h" #include "rgw_rest_s3.h" #include "rgw_rest_opstate.h" #include "rgw_client_io.h" #include "common/errno.h" #define OPSTATE_LIST_MAX_ENTRIES 1000 #define dout_subsys ceph_subsys_rgw void RGWOp_Opstate_List::execute() { string client_id = s->info.args.get("client-id"), op_id = s->info.args.get("op-id"), object = s->info.args.get("object"), max_entries_str = s->info.args.get("max-entries"); unsigned max_entries = OPSTATE_LIST_MAX_ENTRIES; if (!max_entries_str.empty()) { string err; max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing max-entries " << max_entries_str << dendl; http_ret = -EINVAL; return; } } RGWOpState oc = RGWOpState(store); void *handle; bool done; list entries; oc.init_list_entries(client_id, op_id, object, &handle); http_ret = 0; send_response(); do { int ret = oc.list_entries(handle, max_entries, entries, &done); if (ret < 0) { dout(5) << "oc.list_entries failed with error " << ret << dendl; http_ret = ret; oc.finish_list_entries(handle); return; } if (!max_entries_str.empty()) max_entries -= entries.size(); send_response(entries); } while (!done && max_entries > 0); oc.finish_list_entries(handle); send_response_end(); } void RGWOp_Opstate_List::send_response() { if (sent_header) return; set_req_state_err(s, http_ret); dump_errno(s); end_header(s); sent_header = true; if (http_ret < 0) return; s->formatter->open_array_section("entries"); } void RGWOp_Opstate_List::send_response(list entries) { RGWOpState oc(store); for (list::iterator it = entries.begin(); it != entries.end(); ++it) { oc.dump_entry(*it, s->formatter); flusher.flush(); } } void RGWOp_Opstate_List::send_response_end() { s->formatter->close_section(); flusher.flush(); } void RGWOp_Opstate_Set::execute() { string client_id = s->info.args.get("client-id"), op_id = s->info.args.get("op-id"), object = s->info.args.get("object"), state_str = s->info.args.get("state"); if (client_id.empty() || op_id.empty() || object.empty() || state_str.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } RGWOpState oc(store); RGWOpState::OpState state; http_ret = oc.state_from_str(state_str, &state); if (http_ret < 0) { dout(5) << "Error - invalid state" << dendl; return; } http_ret = oc.set_state(client_id, op_id, object, state); if (http_ret < 0) { dout(5) << "Error - Unable to set state" << dendl; return; } } void RGWOp_Opstate_Renew::execute() { string client_id = s->info.args.get("client-id"), op_id = s->info.args.get("op-id"), object = s->info.args.get("object"), state_str = s->info.args.get("state"); if (client_id.empty() || op_id.empty() || object.empty() || state_str.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } RGWOpState oc(store); RGWOpState::OpState state; http_ret = oc.state_from_str(state_str, &state); if (http_ret < 0) { dout(5) << "Error - invalid state" << dendl; return; } http_ret = oc.renew_state(client_id, op_id, object, state); if (http_ret < 0) { dout(5) << "Error - Unable to renew state" << dendl; return; } } void RGWOp_Opstate_Delete::execute() { string client_id = s->info.args.get("client-id"), op_id = s->info.args.get("op-id"), object = s->info.args.get("object"); if (client_id.empty() || op_id.empty() || object.empty()) { dout(5) << "Error - invalid parameter list" << dendl; http_ret = -EINVAL; return; } RGWOpState oc(store); http_ret = oc.remove_entry(client_id, op_id, object); if (http_ret < 0) { dout(5) << "Error - Unable to remove entry" << dendl; } } RGWOp *RGWHandler_Opstate::op_post() { if (s->info.args.exists("renew")) { return new RGWOp_Opstate_Renew; } return new RGWOp_Opstate_Set; } ceph-0.80.11/src/rgw/rgw_auth_s3.cc0000664000175100017510000001206012623076744021016 0ustar jenkins-buildjenkins-build #include "common/armor.h" #include "rgw_common.h" #define dout_subsys ceph_subsys_rgw static const char *signed_subresources[] = { "acl", "cors", "delete", "lifecycle", "location", "logging", "notification", "partNumber", "policy", "requestPayment", "response-cache-control", "response-content-disposition", "response-content-encoding", "response-content-language", "response-content-type", "response-expires", "torrent", "uploadId", "uploads", "versionId", "versioning", "versions", "website", NULL }; /* * ?get the canonical amazon-style header for something? */ static void get_canon_amz_hdr(map& meta_map, string& dest) { dest = ""; map::iterator iter; for (iter = meta_map.begin(); iter != meta_map.end(); ++iter) { dest.append(iter->first); dest.append(":"); dest.append(iter->second); dest.append("\n"); } } /* * ?get the canonical representation of the object's location */ static void get_canon_resource(const char *request_uri, map& sub_resources, string& dest) { string s; if (request_uri) s.append(request_uri); string append_str; const char **p = signed_subresources; for (; *p; ++p) { map::iterator iter = sub_resources.find(*p); if (iter == sub_resources.end()) continue; if (append_str.empty()) append_str.append("?"); else append_str.append("&"); append_str.append(iter->first); if (!iter->second.empty()) { append_str.append("="); append_str.append(iter->second); } } if (!append_str.empty()) { s.append(append_str); } dest = s; dout(10) << "get_canon_resource(): dest=" << dest << dendl; } /* * get the header authentication information required to * compute a request's signature */ void rgw_create_s3_canonical_header(const char *method, const char *content_md5, const char *content_type, const char *date, map& meta_map, const char *request_uri, map& sub_resources, string& dest_str) { string dest; if (method) dest = method; dest.append("\n"); if (content_md5) { dest.append(content_md5); } dest.append("\n"); if (content_type) dest.append(content_type); dest.append("\n"); if (date) dest.append(date); dest.append("\n"); string canon_amz_hdr; get_canon_amz_hdr(meta_map, canon_amz_hdr); dest.append(canon_amz_hdr); string canon_resource; get_canon_resource(request_uri, sub_resources, canon_resource); dest.append(canon_resource); dest_str = dest; } int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& dest) { char hmac_sha1[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; calc_hmac_sha1(key.c_str(), key.size(), auth_hdr.c_str(), auth_hdr.size(), hmac_sha1); char b64[64]; /* 64 is really enough */ int ret = ceph_armor(b64, b64 + 64, hmac_sha1, hmac_sha1 + CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); if (ret < 0) { dout(10) << "ceph_armor failed" << dendl; return ret; } b64[ret] = '\0'; dest = b64; return 0; } static inline bool is_base64_for_content_md5(unsigned char c) { return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '=')); } /* * get the header authentication information required to * compute a request's signature */ bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time, string& dest, bool qsr) { const char *content_md5 = info.env->get("HTTP_CONTENT_MD5"); if (content_md5) { for (const char *p = content_md5; *p; p++) { if (!is_base64_for_content_md5(*p)) { dout(0) << "NOTICE: bad content-md5 provided (not base64), aborting request p=" << *p << " " << (int)*p << dendl; return false; } } } const char *content_type = info.env->get("CONTENT_TYPE"); string date; if (qsr) { date = info.args.get("Expires"); } else { const char *str = info.env->get("HTTP_DATE"); const char *req_date = str; if (str) { date = str; } else { req_date = info.env->get("HTTP_X_AMZ_DATE"); if (!req_date) { dout(0) << "NOTICE: missing date for auth header" << dendl; return false; } } if (header_time) { struct tm t; if (!parse_rfc2616(req_date, &t)) { dout(0) << "NOTICE: failed to parse date for auth header" << dendl; return false; } if (t.tm_year < 70) { dout(0) << "NOTICE: bad date (predates epoch): " << req_date << dendl; return false; } *header_time = utime_t(timegm(&t), 0); } } map& meta_map = info.x_meta_map; map& sub_resources = info.args.get_sub_resources(); string request_uri; if (info.effective_uri.empty()) request_uri = info.request_uri; else request_uri = info.effective_uri; rgw_create_s3_canonical_header(info.method, content_md5, content_type, date.c_str(), meta_map, request_uri.c_str(), sub_resources, dest); return true; } ceph-0.80.11/src/rgw/rgw_multi_del.h0000664000175100017510000000160512623076744021273 0ustar jenkins-buildjenkins-build#ifndef RGW_MULTI_DELETE_H_ #define RGW_MULTI_DELETE_H_ #include #include "rgw_xml.h" class RGWMultiDelDelete : public XMLObj { public: RGWMultiDelDelete() :quiet(false) {} ~RGWMultiDelDelete() {} bool xml_end(const char *el); std::vector objects; bool quiet; bool is_quiet() { return quiet; }; }; class RGWMultiDelQuiet : public XMLObj { public: RGWMultiDelQuiet() {} ~RGWMultiDelQuiet() {} }; class RGWMultiDelObject : public XMLObj { string key; string versionID; public: RGWMultiDelObject() {} ~RGWMultiDelObject() {} bool xml_end(const char *el); string get_key() { return key; } }; class RGWMultiDelKey : public XMLObj { public: RGWMultiDelKey() {} ~RGWMultiDelKey() {} }; class RGWMultiDelXMLParser : public RGWXMLParser { XMLObj *alloc_obj(const char *el); public: RGWMultiDelXMLParser() {} ~RGWMultiDelXMLParser() {} }; #endif ceph-0.80.11/src/rgw/rgw_rest.h0000664000175100017510000002511012623076744020267 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_H #define CEPH_RGW_REST_H #define TIME_BUF_SIZE 128 #include "common/ceph_json.h" #include "include/assert.h" /* needed because of common/ceph_json.h */ #include "rgw_op.h" #include "rgw_formats.h" extern std::map rgw_to_http_attrs; extern void rgw_rest_init(CephContext *cct); extern string lowercase_dash_http_attr(const string& orig); extern void rgw_flush_formatter_and_reset(struct req_state *s, ceph::Formatter *formatter); extern void rgw_flush_formatter(struct req_state *s, ceph::Formatter *formatter); extern int rgw_rest_read_all_input(struct req_state *s, char **data, int *plen, int max_len); template int rgw_rest_get_json_input(CephContext *cct, req_state *s, T& out, int max_len, bool *empty) { int rv, data_len; char *data; if (empty) *empty = false; if ((rv = rgw_rest_read_all_input(s, &data, &data_len, max_len)) < 0) { return rv; } if (!data_len) { if (empty) { *empty = true; } return -EINVAL; } JSONParser parser; if (!parser.parse(data, data_len)) { free(data); return -EINVAL; } decode_json_obj(out, &parser); free(data); return 0; } class RESTArgs { public: static int get_string(struct req_state *s, const string& name, const string& def_val, string *val, bool *existed = NULL); static int get_uint64(struct req_state *s, const string& name, uint64_t def_val, uint64_t *val, bool *existed = NULL); static int get_int64(struct req_state *s, const string& name, int64_t def_val, int64_t *val, bool *existed = NULL); static int get_uint32(struct req_state *s, const string& name, uint32_t def_val, uint32_t *val, bool *existed = NULL); static int get_int32(struct req_state *s, const string& name, int32_t def_val, int32_t *val, bool *existed = NULL); static int get_time(struct req_state *s, const string& name, const utime_t& def_val, utime_t *val, bool *existed = NULL); static int get_epoch(struct req_state *s, const string& name, uint64_t def_val, uint64_t *epoch, bool *existed = NULL); static int get_bool(struct req_state *s, const string& name, bool def_val, bool *val, bool *existed = NULL); }; class RGWRESTFlusher : public RGWFormatterFlusher { struct req_state *s; RGWOp *op; protected: virtual void do_flush(); virtual void do_start(int ret); public: RGWRESTFlusher(struct req_state *_s, RGWOp *_op) : RGWFormatterFlusher(_s->formatter), s(_s), op(_op) {} RGWRESTFlusher() : RGWFormatterFlusher(NULL), s(NULL), op(NULL) {} void init(struct req_state *_s, RGWOp *_op) { s = _s; op = _op; set_formatter(s->formatter); } }; class RGWClientIO; class RGWGetObj_ObjStore : public RGWGetObj { protected: bool sent_header; public: RGWGetObj_ObjStore() : sent_header(false) {} virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { RGWGetObj::init(store, s, h); sent_header = false; } int get_params(); }; class RGWListBuckets_ObjStore : public RGWListBuckets { public: RGWListBuckets_ObjStore() {} ~RGWListBuckets_ObjStore() {} }; class RGWListBucket_ObjStore : public RGWListBucket { public: RGWListBucket_ObjStore() {} ~RGWListBucket_ObjStore() {} }; class RGWStatAccount_ObjStore : public RGWStatAccount { public: RGWStatAccount_ObjStore() {} ~RGWStatAccount_ObjStore() {} }; class RGWStatBucket_ObjStore : public RGWStatBucket { public: RGWStatBucket_ObjStore() {} ~RGWStatBucket_ObjStore() {} }; class RGWCreateBucket_ObjStore : public RGWCreateBucket { public: RGWCreateBucket_ObjStore() {} ~RGWCreateBucket_ObjStore() {} }; class RGWDeleteBucket_ObjStore : public RGWDeleteBucket { public: RGWDeleteBucket_ObjStore() {} ~RGWDeleteBucket_ObjStore() {} }; class RGWPutObj_ObjStore : public RGWPutObj { public: RGWPutObj_ObjStore() {} ~RGWPutObj_ObjStore() {} virtual int verify_params(); virtual int get_params(); int get_data(bufferlist& bl); }; class RGWPostObj_ObjStore : public RGWPostObj { public: RGWPostObj_ObjStore() {} ~RGWPostObj_ObjStore() {} virtual int verify_params(); }; class RGWPutMetadata_ObjStore : public RGWPutMetadata { public: RGWPutMetadata_ObjStore() {} ~RGWPutMetadata_ObjStore() {} }; class RGWSetTempUrl_ObjStore : public RGWSetTempUrl { public: RGWSetTempUrl_ObjStore() {} ~RGWSetTempUrl_ObjStore() {} }; class RGWDeleteObj_ObjStore : public RGWDeleteObj { public: RGWDeleteObj_ObjStore() {} ~RGWDeleteObj_ObjStore() {} }; class RGWCopyObj_ObjStore : public RGWCopyObj { public: RGWCopyObj_ObjStore() {} ~RGWCopyObj_ObjStore() {} }; class RGWGetACLs_ObjStore : public RGWGetACLs { public: RGWGetACLs_ObjStore() {} ~RGWGetACLs_ObjStore() {} }; class RGWPutACLs_ObjStore : public RGWPutACLs { public: RGWPutACLs_ObjStore() {} ~RGWPutACLs_ObjStore() {} int get_params(); }; class RGWGetCORS_ObjStore : public RGWGetCORS { public: RGWGetCORS_ObjStore() {} ~RGWGetCORS_ObjStore() {} }; class RGWPutCORS_ObjStore : public RGWPutCORS { public: RGWPutCORS_ObjStore() {} ~RGWPutCORS_ObjStore() {} }; class RGWDeleteCORS_ObjStore : public RGWDeleteCORS { public: RGWDeleteCORS_ObjStore() {} ~RGWDeleteCORS_ObjStore() {} }; class RGWOptionsCORS_ObjStore : public RGWOptionsCORS { public: RGWOptionsCORS_ObjStore() {} ~RGWOptionsCORS_ObjStore() {} }; class RGWInitMultipart_ObjStore : public RGWInitMultipart { public: RGWInitMultipart_ObjStore() {} ~RGWInitMultipart_ObjStore() {} }; class RGWCompleteMultipart_ObjStore : public RGWCompleteMultipart { public: RGWCompleteMultipart_ObjStore() {} ~RGWCompleteMultipart_ObjStore() {} int get_params(); }; class RGWAbortMultipart_ObjStore : public RGWAbortMultipart { public: RGWAbortMultipart_ObjStore() {} ~RGWAbortMultipart_ObjStore() {} }; class RGWListMultipart_ObjStore : public RGWListMultipart { public: RGWListMultipart_ObjStore() {} ~RGWListMultipart_ObjStore() {} int get_params(); }; class RGWListBucketMultiparts_ObjStore : public RGWListBucketMultiparts { public: RGWListBucketMultiparts_ObjStore() {} ~RGWListBucketMultiparts_ObjStore() {} int get_params(); }; class RGWDeleteMultiObj_ObjStore : public RGWDeleteMultiObj { public: RGWDeleteMultiObj_ObjStore() {} ~RGWDeleteMultiObj_ObjStore() {} int get_params(); }; class RGWRESTOp : public RGWOp { protected: int http_ret; RGWRESTFlusher flusher; public: RGWRESTOp() : http_ret(0) {} virtual void init(RGWRados *store, struct req_state *s, RGWHandler *dialect_handler) { RGWOp::init(store, s, dialect_handler); flusher.init(s, this); } virtual void send_response(); virtual int check_caps(RGWUserCaps& caps) { return -EPERM; } /* should to be implemented! */ virtual int verify_permission(); }; class RGWHandler_ObjStore : public RGWHandler { protected: virtual bool is_obj_update_op() { return false; } virtual RGWOp *op_get() { return NULL; } virtual RGWOp *op_put() { return NULL; } virtual RGWOp *op_delete() { return NULL; } virtual RGWOp *op_head() { return NULL; } virtual RGWOp *op_post() { return NULL; } virtual RGWOp *op_copy() { return NULL; } virtual RGWOp *op_options() { return NULL; } virtual int validate_bucket_name(const string& bucket); virtual int validate_object_name(const string& object); static int allocate_formatter(struct req_state *s, int default_formatter, bool configurable); public: RGWHandler_ObjStore() {} virtual ~RGWHandler_ObjStore() {} int read_permissions(RGWOp *op); virtual int authorize() = 0; }; class RGWHandler_ObjStore_SWIFT; class RGWHandler_SWIFT_Auth; class RGWHandler_ObjStore_S3; class RGWRESTMgr { bool should_log; protected: map resource_mgrs; multimap resources_by_size; RGWRESTMgr *default_mgr; public: RGWRESTMgr() : should_log(false), default_mgr(NULL) {} virtual ~RGWRESTMgr(); void register_resource(string resource, RGWRESTMgr *mgr); void register_default_mgr(RGWRESTMgr *mgr); virtual RGWRESTMgr *get_resource_mgr(struct req_state *s, const string& uri, string *out_uri); virtual RGWHandler *get_handler(struct req_state *s) { return NULL; } virtual void put_handler(RGWHandler *handler) { delete handler; } void set_logging(bool _should_log) { should_log = _should_log; } bool get_logging() { return should_log; } }; class RGWREST { RGWRESTMgr mgr; static int preprocess(struct req_state *s, RGWClientIO *cio); public: RGWREST() {} RGWHandler *get_handler(RGWRados *store, struct req_state *s, RGWClientIO *cio, RGWRESTMgr **pmgr, int *init_error); void put_handler(RGWHandler *handler) { mgr.put_handler(handler); } void register_resource(string resource, RGWRESTMgr *m, bool register_empty = false) { if (!register_empty && resource.empty()) return; mgr.register_resource(resource, m); } void register_default_mgr(RGWRESTMgr *m) { mgr.register_default_mgr(m); } }; static const int64_t NO_CONTENT_LENGTH = -1; extern void set_req_state_err(struct req_state *s, int err_no); extern void dump_errno(struct req_state *s); extern void dump_errno(struct req_state *s, int ret); extern void end_header(struct req_state *s, RGWOp *op = NULL, const char *content_type = NULL, const int64_t proposed_content_length = NO_CONTENT_LENGTH, bool force_content_type = false); extern void dump_start(struct req_state *s); extern void list_all_buckets_start(struct req_state *s); extern void dump_owner(struct req_state *s, string& id, string& name, const char *section = NULL); extern void dump_content_length(struct req_state *s, uint64_t len); extern void dump_etag(struct req_state *s, const char *etag); extern void dump_epoch_header(struct req_state *s, const char *name, time_t t); extern void dump_last_modified(struct req_state *s, time_t t); extern void abort_early(struct req_state *s, RGWOp *op, int err); extern void dump_range(struct req_state *s, uint64_t ofs, uint64_t end, uint64_t total_size); extern void dump_continue(struct req_state *s); extern void list_all_buckets_end(struct req_state *s); extern void dump_time(struct req_state *s, const char *name, time_t *t); extern void dump_bucket_from_state(struct req_state *s); extern void dump_uri_from_state(struct req_state *s); extern void dump_redirect(struct req_state *s, const string& redirect); extern void dump_pair(struct req_state *s, const char *key, const char *value); extern bool is_valid_url(const char *url); extern void dump_access_control(struct req_state *s, const char *origin, const char *meth, const char *hdr, const char *exp_hdr, uint32_t max_age); extern void dump_access_control(req_state *s, RGWOp *op); #endif ceph-0.80.11/src/rgw/rgw_usage.cc0000664000175100017510000001054312623076744020560 0ustar jenkins-buildjenkins-build #include #include #include "rgw_rados.h" #include "rgw_usage.h" #include "rgw_formats.h" using namespace std; static void dump_usage_categories_info(Formatter *formatter, const rgw_usage_log_entry& entry, map *categories) { formatter->open_array_section("categories"); map::const_iterator uiter; for (uiter = entry.usage_map.begin(); uiter != entry.usage_map.end(); ++uiter) { if (categories && !categories->empty() && !categories->count(uiter->first)) continue; const rgw_usage_data& usage = uiter->second; formatter->open_object_section("entry"); formatter->dump_string("category", uiter->first); formatter->dump_int("bytes_sent", usage.bytes_sent); formatter->dump_int("bytes_received", usage.bytes_received); formatter->dump_int("ops", usage.ops); formatter->dump_int("successful_ops", usage.successful_ops); formatter->close_section(); // entry } formatter->close_section(); // categories } int RGWUsage::show(RGWRados *store, string& uid, uint64_t start_epoch, uint64_t end_epoch, bool show_log_entries, bool show_log_sum, map *categories, RGWFormatterFlusher& flusher) { uint32_t max_entries = 1000; bool is_truncated = true; RGWUsageIter usage_iter; Formatter *formatter = flusher.get_formatter(); map usage; flusher.start(0); formatter->open_object_section("usage"); if (show_log_entries) { formatter->open_array_section("entries"); } string last_owner; bool user_section_open = false; map summary_map; while (is_truncated) { int ret = store->read_usage(uid, start_epoch, end_epoch, max_entries, &is_truncated, usage_iter, usage); if (ret == -ENOENT) { ret = 0; is_truncated = false; } if (ret < 0) { return ret; } map::iterator iter; for (iter = usage.begin(); iter != usage.end(); ++iter) { const rgw_user_bucket& ub = iter->first; const rgw_usage_log_entry& entry = iter->second; if (show_log_entries) { if (ub.user.compare(last_owner) != 0) { if (user_section_open) { formatter->close_section(); formatter->close_section(); } formatter->open_object_section("user"); formatter->dump_string("owner", ub.user); formatter->open_array_section("buckets"); user_section_open = true; last_owner = ub.user; } formatter->open_object_section("bucket"); formatter->dump_string("bucket", ub.bucket); utime_t ut(entry.epoch, 0); ut.gmtime(formatter->dump_stream("time")); formatter->dump_int("epoch", entry.epoch); dump_usage_categories_info(formatter, entry, categories); formatter->close_section(); // bucket flusher.flush(); } summary_map[ub.user].aggregate(entry, categories); } } if (show_log_entries) { if (user_section_open) { formatter->close_section(); // buckets formatter->close_section(); //user } formatter->close_section(); // entries } if (show_log_sum) { formatter->open_array_section("summary"); map::iterator siter; for (siter = summary_map.begin(); siter != summary_map.end(); ++siter) { const rgw_usage_log_entry& entry = siter->second; formatter->open_object_section("user"); formatter->dump_string("user", siter->first); dump_usage_categories_info(formatter, entry, categories); rgw_usage_data total_usage; entry.sum(total_usage, *categories); formatter->open_object_section("total"); formatter->dump_int("bytes_sent", total_usage.bytes_sent); formatter->dump_int("bytes_received", total_usage.bytes_received); formatter->dump_int("ops", total_usage.ops); formatter->dump_int("successful_ops", total_usage.successful_ops); formatter->close_section(); // total formatter->close_section(); // user flusher.flush(); } formatter->close_section(); // summary } formatter->close_section(); // usage flusher.flush(); return 0; } int RGWUsage::trim(RGWRados *store, string& uid, uint64_t start_epoch, uint64_t end_epoch) { return store->trim_usage(uid, start_epoch, end_epoch); } ceph-0.80.11/src/rgw/rgw_rest_swift.cc0000664000175100017510000006430312623076744021650 0ustar jenkins-buildjenkins-build #include "common/Formatter.h" #include "common/utf8.h" #include "rgw_swift.h" #include "rgw_rest_swift.h" #include "rgw_acl_swift.h" #include "rgw_cors_swift.h" #include "rgw_formats.h" #include "rgw_client_io.h" #include #define dout_subsys ceph_subsys_rgw int RGWListBuckets_ObjStore_SWIFT::get_params() { marker = s->info.args.get("marker"); string limit_str; limit_str = s->info.args.get("limit"); long l = strtol(limit_str.c_str(), NULL, 10); if (l > (long)limit_max || l < 0) return -ERR_PRECONDITION_FAILED; limit = (uint64_t)l; if (limit == 0) limit = limit_max; need_stats = (s->format != RGW_FORMAT_PLAIN); if (need_stats) { bool stats, exists; int r = s->info.args.get_bool("stats", &stats, &exists); if (r < 0) return r; if (exists) { need_stats = stats; } } return 0; } void RGWListBuckets_ObjStore_SWIFT::send_response_begin(bool has_buckets) { if (ret) { set_req_state_err(s, ret); } else if (!has_buckets && s->format == RGW_FORMAT_PLAIN) { ret = STATUS_NO_CONTENT; set_req_state_err(s, ret); } if (!g_conf->rgw_swift_enforce_content_length) { dump_errno(s); end_header(s, NULL, NULL, NO_CONTENT_LENGTH, true); } if (!ret) { dump_start(s); s->formatter->open_array_section("account"); sent_data = true; } } void RGWListBuckets_ObjStore_SWIFT::send_response_data(RGWUserBuckets& buckets) { map& m = buckets.get_buckets(); map::iterator iter; if (!sent_data) return; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt obj = iter->second; s->formatter->open_object_section("container"); s->formatter->dump_string("name", obj.bucket.name); if (need_stats) { s->formatter->dump_int("count", obj.count); s->formatter->dump_int("bytes", obj.size); } s->formatter->close_section(); if (!g_conf->rgw_swift_enforce_content_length) { rgw_flush_formatter(s, s->formatter); } } } void RGWListBuckets_ObjStore_SWIFT::send_response_end() { if (sent_data) { s->formatter->close_section(); } if (g_conf->rgw_swift_enforce_content_length) { dump_errno(s); end_header(s, NULL, NULL, s->formatter->get_len(), true); } if (sent_data || g_conf->rgw_swift_enforce_content_length) { rgw_flush_formatter_and_reset(s, s->formatter); } } int RGWListBucket_ObjStore_SWIFT::get_params() { prefix = s->info.args.get("prefix"); marker = s->info.args.get("marker"); max_keys = s->info.args.get("limit"); ret = parse_max_keys(); if (ret < 0) { return ret; } if (max > default_max) return -ERR_PRECONDITION_FAILED; delimiter = s->info.args.get("delimiter"); string path_args; if (s->info.args.exists("path")) { // should handle empty path path_args = s->info.args.get("path"); if (!delimiter.empty() || !prefix.empty()) { return -EINVAL; } prefix = path_args; delimiter="/"; path = prefix; if (path.size() && path[path.size() - 1] != '/') path.append("/"); } int len = prefix.size(); int delim_size = delimiter.size(); if (len >= delim_size) { if (prefix.substr(len - delim_size).compare(delimiter) != 0) prefix.append(delimiter); } return 0; } void RGWListBucket_ObjStore_SWIFT::send_response() { vector::iterator iter = objs.begin(); map::iterator pref_iter = common_prefixes.begin(); dump_start(s); s->formatter->open_array_section_with_attrs("container", FormatterAttrs("name", s->bucket.name.c_str(), NULL)); while (iter != objs.end() || pref_iter != common_prefixes.end()) { bool do_pref = false; bool do_objs = false; if (pref_iter == common_prefixes.end()) do_objs = true; else if (iter == objs.end()) do_pref = true; else if (iter->name.compare(pref_iter->first) == 0) { do_objs = true; ++pref_iter; } else if (iter->name.compare(pref_iter->first) <= 0) do_objs = true; else do_pref = true; if (do_objs && (marker.empty() || iter->name.compare(marker) > 0)) { if (iter->name.compare(path) == 0) goto next; s->formatter->open_object_section("object"); s->formatter->dump_string("name", iter->name); s->formatter->dump_string("hash", iter->etag); s->formatter->dump_int("bytes", iter->size); string single_content_type = iter->content_type; if (iter->content_type.size()) { // content type might hold multiple values, just dump the last one ssize_t pos = iter->content_type.rfind(','); if (pos > 0) { ++pos; while (single_content_type[pos] == ' ') ++pos; single_content_type = single_content_type.substr(pos); } s->formatter->dump_string("content_type", single_content_type); } time_t mtime = iter->mtime.sec(); dump_time(s, "last_modified", &mtime); s->formatter->close_section(); } if (do_pref && (marker.empty() || pref_iter->first.compare(marker) > 0)) { const string& name = pref_iter->first; if (name.compare(delimiter) == 0) goto next; s->formatter->open_object_section_with_attrs("subdir", FormatterAttrs("name", name.c_str(), NULL)); /* swift is a bit inconsistent here */ switch (s->format) { case RGW_FORMAT_XML: s->formatter->dump_string("name", name); break; default: s->formatter->dump_string("subdir", name); } s->formatter->close_section(); } next: if (do_objs) ++iter; else ++pref_iter; } s->formatter->close_section(); int64_t content_len = 0; if (!ret) { content_len = s->formatter->get_len(); if (content_len == 0) { ret = STATUS_NO_CONTENT; } } else if (ret > 0) { ret = 0; } set_req_state_err(s, ret); dump_errno(s); end_header(s, this, NULL, content_len); if (ret < 0) { return; } rgw_flush_formatter_and_reset(s, s->formatter); } static void dump_container_metadata(struct req_state *s, RGWBucketEnt& bucket) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", (long long)bucket.count); s->cio->print("X-Container-Object-Count: %s\r\n", buf); snprintf(buf, sizeof(buf), "%lld", (long long)bucket.size); s->cio->print("X-Container-Bytes-Used: %s\r\n", buf); snprintf(buf, sizeof(buf), "%lld", (long long)bucket.size_rounded); s->cio->print("X-Container-Bytes-Used-Actual: %s\r\n", buf); if (!s->object) { RGWAccessControlPolicy_SWIFT *swift_policy = static_cast(s->bucket_acl); string read_acl, write_acl; swift_policy->to_str(read_acl, write_acl); if (read_acl.size()) { s->cio->print("X-Container-Read: %s\r\n", read_acl.c_str()); } if (write_acl.size()) { s->cio->print("X-Container-Write: %s\r\n", write_acl.c_str()); } // Dump user-defined metadata items const size_t PREFIX_LEN = sizeof(RGW_ATTR_META_PREFIX) - 1; map::iterator iter; for (iter = s->bucket_attrs.lower_bound(RGW_ATTR_META_PREFIX); iter != s->bucket_attrs.end(); ++iter) { const char *name = iter->first.c_str(); if (strncmp(name, RGW_ATTR_META_PREFIX, PREFIX_LEN) == 0) { s->cio->print("X-Container-Meta-%s: %s\r\n", name + PREFIX_LEN, iter->second.c_str()); } else { break; } } } } static void dump_account_metadata(struct req_state *s, uint32_t buckets_count, uint64_t buckets_object_count, uint64_t buckets_size, uint64_t buckets_size_rounded) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", (long long)buckets_count); s->cio->print("X-Account-Container-Count: %s\r\n", buf); snprintf(buf, sizeof(buf), "%lld", (long long)buckets_object_count); s->cio->print("X-Account-Object-Count: %s\r\n", buf); snprintf(buf, sizeof(buf), "%lld", (long long)buckets_size); s->cio->print("X-Account-Bytes-Used: %s\r\n", buf); snprintf(buf, sizeof(buf), "%lld", (long long)buckets_size_rounded); s->cio->print("X-Account-Bytes-Used-Actual: %s\r\n", buf); } void RGWStatAccount_ObjStore_SWIFT::send_response() { if (ret >= 0) { ret = STATUS_NO_CONTENT; dump_account_metadata(s, buckets_count, buckets_objcount, buckets_size, buckets_size_rounded); } set_req_state_err(s, ret); dump_errno(s); end_header(s, NULL, NULL, 0, true); dump_start(s); } void RGWStatBucket_ObjStore_SWIFT::send_response() { if (ret >= 0) { ret = STATUS_NO_CONTENT; dump_container_metadata(s, bucket); } set_req_state_err(s, ret); dump_errno(s); end_header(s, this,NULL,0, true); dump_start(s); } static int get_swift_container_settings(req_state *s, RGWRados *store, RGWAccessControlPolicy *policy, bool *has_policy, RGWCORSConfiguration *cors_config, bool *has_cors) { string read_list, write_list; const char *read_attr = s->info.env->get("HTTP_X_CONTAINER_READ"); if (read_attr) { read_list = read_attr; } const char *write_attr = s->info.env->get("HTTP_X_CONTAINER_WRITE"); if (write_attr) { write_list = write_attr; } *has_policy = false; if (read_attr || write_attr) { RGWAccessControlPolicy_SWIFT swift_policy(s->cct); int r = swift_policy.create(store, s->user.user_id, s->user.display_name, read_list, write_list); if (r < 0) return r; *policy = swift_policy; *has_policy = true; } *has_cors = false; /*Check and update CORS configuration*/ const char *allow_origins = s->info.env->get("HTTP_X_CONTAINER_META_ACCESS_CONTROL_ALLOW_ORIGIN"); const char *allow_headers = s->info.env->get("HTTP_X_CONTAINER_META_ACCESS_CONTROL_ALLOW_HEADERS"); const char *expose_headers = s->info.env->get("HTTP_X_CONTAINER_META_ACCESS_CONTROL_EXPOSE_HEADERS"); const char *max_age = s->info.env->get("HTTP_X_CONTAINER_META_ACCESS_CONTROL_MAX_AGE"); if (allow_origins) { RGWCORSConfiguration_SWIFT *swift_cors = new RGWCORSConfiguration_SWIFT; int r = swift_cors->create_update(allow_origins, allow_headers, expose_headers, max_age); if (r < 0) { dout(0) << "Error creating/updating the cors configuration" << dendl; delete swift_cors; return r; } *has_cors = true; *cors_config = *swift_cors; cors_config->dump(); delete swift_cors; } return 0; } int RGWCreateBucket_ObjStore_SWIFT::get_params() { bool has_policy; int r = get_swift_container_settings(s, store, &policy, &has_policy, &cors_config, &has_cors); if (r < 0) { return r; } if (!has_policy) { policy.create_default(s->user.user_id, s->user.display_name); } location_constraint = store->region.api_name; return 0; } void RGWCreateBucket_ObjStore_SWIFT::send_response() { if (!ret) ret = STATUS_CREATED; else if (ret == -ERR_BUCKET_EXISTS) ret = STATUS_ACCEPTED; set_req_state_err(s, ret); dump_errno(s); /* Propose ending HTTP header with 0 Content-Length header. */ end_header(s, NULL, NULL, 0); rgw_flush_formatter_and_reset(s, s->formatter); } void RGWDeleteBucket_ObjStore_SWIFT::send_response() { int r = ret; if (!r) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, this, NULL, 0); rgw_flush_formatter_and_reset(s, s->formatter); } int RGWPutObj_ObjStore_SWIFT::get_params() { if (s->has_bad_meta) return -EINVAL; if (!s->length) { const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING"); if (!encoding || strcmp(encoding, "chunked") != 0) return -ERR_LENGTH_REQUIRED; chunked_upload = true; } supplied_etag = s->info.env->get("HTTP_ETAG"); if (!s->generic_attrs.count(RGW_ATTR_CONTENT_TYPE)) { dout(5) << "content type wasn't provided, trying to guess" << dendl; const char *suffix = strrchr(s->object, '.'); if (suffix) { suffix++; if (*suffix) { string suffix_str(suffix); const char *mime = rgw_find_mime_by_ext(suffix_str); if (mime) { s->generic_attrs[RGW_ATTR_CONTENT_TYPE] = mime; } } } } policy.create_default(s->user.user_id, s->user.display_name); obj_manifest = s->info.env->get("HTTP_X_OBJECT_MANIFEST"); return RGWPutObj_ObjStore::get_params(); } void RGWPutObj_ObjStore_SWIFT::send_response() { if (!ret) ret = STATUS_CREATED; dump_etag(s, etag.c_str()); set_req_state_err(s, ret); dump_errno(s); end_header(s, this); rgw_flush_formatter_and_reset(s, s->formatter); } #define REMOVE_ATTR_PREFIX "HTTP_X_REMOVE_CONTAINER_META_" #define PUT_ATTR_PREFIX "HTTP_X_CONTAINER_META_" #define REMOVE_ATTR_PREFIX_LEN sizeof(REMOVE_ATTR_PREFIX) - 1 #define PUT_ATTR_PREFIX_LEN sizeof(PUT_ATTR_PREFIX) - 1 int RGWPutMetadata_ObjStore_SWIFT::get_params() { if (s->has_bad_meta) return -EINVAL; if (!s->object) { int r = get_swift_container_settings(s, store, &policy, &has_policy, &cors_config, &has_cors); if (r < 0) { return r; } map& m = s->info.env->get_map(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { size_t prefix_len = 0; const char *p = iter->first.c_str(); if (strncasecmp(p, REMOVE_ATTR_PREFIX, REMOVE_ATTR_PREFIX_LEN) == 0) { // Explicitly requested removal prefix_len = REMOVE_ATTR_PREFIX_LEN; } else if ((strncasecmp(p, PUT_ATTR_PREFIX, PUT_ATTR_PREFIX_LEN) == 0) && iter->second.empty()) { // Removal requested by putting an empty value prefix_len = PUT_ATTR_PREFIX_LEN; } if (prefix_len > 0) { string name(RGW_ATTR_META_PREFIX); name.append(lowercase_dash_http_attr(p + prefix_len)); rmattr_names.insert(name); } } } return 0; } void RGWPutMetadata_ObjStore_SWIFT::send_response() { if (!ret) ret = STATUS_ACCEPTED; set_req_state_err(s, ret); dump_errno(s); end_header(s, this); rgw_flush_formatter_and_reset(s, s->formatter); } int RGWSetTempUrl_ObjStore_SWIFT::get_params() { const char *temp_url = s->info.env->get("HTTP_X_ACCOUNT_META_TEMP_URL_KEY"); if (temp_url) { temp_url_keys[0] = temp_url; } temp_url = s->info.env->get("HTTP_X_ACCOUNT_META_TEMP_URL_KEY_2"); if (temp_url) { temp_url_keys[1] = temp_url; } if (temp_url_keys.size() == 0) return -EINVAL; return 0; } void RGWSetTempUrl_ObjStore_SWIFT::send_response() { int r = ret; if (!r) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, this); rgw_flush_formatter_and_reset(s, s->formatter); } void RGWDeleteObj_ObjStore_SWIFT::send_response() { int r = ret; if (!r) r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); end_header(s, this); rgw_flush_formatter_and_reset(s, s->formatter); } int RGWCopyObj_ObjStore_SWIFT::init_dest_policy() { dest_policy.create_default(s->user.user_id, s->user.display_name); return 0; } int RGWCopyObj_ObjStore_SWIFT::get_params() { if_mod = s->info.env->get("HTTP_IF_MODIFIED_SINCE"); if_unmod = s->info.env->get("HTTP_IF_UNMODIFIED_SINCE"); if_match = s->info.env->get("HTTP_COPY_IF_MATCH"); if_nomatch = s->info.env->get("HTTP_COPY_IF_NONE_MATCH"); src_bucket_name = s->src_bucket_name; src_object = s->src_object; dest_bucket_name = s->bucket_name_str; dest_object = s->object_str; return 0; } void RGWCopyObj_ObjStore_SWIFT::send_partial_response(off_t ofs) { if (!sent_header) { if (!ret) ret = STATUS_CREATED; set_req_state_err(s, ret); dump_errno(s); end_header(s, this); /* Send progress information. Note that this diverge from the original swift * spec. We do this in order to keep connection alive. */ if (ret == 0) { s->formatter->open_array_section("progress"); } sent_header = true; } else { s->formatter->dump_int("ofs", (uint64_t)ofs); } rgw_flush_formatter(s, s->formatter); } void RGWCopyObj_ObjStore_SWIFT::send_response() { if (!sent_header) { if (!ret) ret = STATUS_CREATED; set_req_state_err(s, ret); dump_errno(s); end_header(s, this); } else { s->formatter->close_section(); rgw_flush_formatter(s, s->formatter); } } int RGWGetObj_ObjStore_SWIFT::send_response_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) { const char *content_type = NULL; map response_attrs; map::iterator riter; if (sent_header) goto send_data; if (range_str) dump_range(s, ofs, end, s->obj_size); dump_content_length(s, total_len); dump_last_modified(s, lastmod); s->cio->print("X-Timestamp: %lld\r\n", (long long)lastmod); if (!ret) { map::iterator iter = attrs.find(RGW_ATTR_ETAG); if (iter != attrs.end()) { bufferlist& bl = iter->second; if (bl.length()) { char *etag = bl.c_str(); dump_etag(s, etag); } } for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const char *name = iter->first.c_str(); map::iterator aiter = rgw_to_http_attrs.find(name); if (aiter != rgw_to_http_attrs.end()) { if (aiter->first.compare(RGW_ATTR_CONTENT_TYPE) == 0) { // special handling for content_type content_type = iter->second.c_str(); continue; } response_attrs[aiter->second] = iter->second.c_str(); } else { if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) { name += sizeof(RGW_ATTR_META_PREFIX) - 1; s->cio->print("X-Object-Meta-%s: %s\r\n", name, iter->second.c_str()); } } } } set_req_state_err(s, (partial_content && !ret) ? STATUS_PARTIAL_CONTENT : ret); dump_errno(s); for (riter = response_attrs.begin(); riter != response_attrs.end(); ++riter) { s->cio->print("%s: %s\r\n", riter->first.c_str(), riter->second.c_str()); } if (!content_type) content_type = "binary/octet-stream"; end_header(s, this, content_type); sent_header = true; send_data: if (get_data && !ret) { int r = s->cio->write(bl.c_str() + bl_ofs, bl_len); if (r < 0) return r; } rgw_flush_formatter_and_reset(s, s->formatter); return 0; } void RGWOptionsCORS_ObjStore_SWIFT::send_response() { string hdrs, exp_hdrs; uint32_t max_age = CORS_MAX_AGE_INVALID; /*EACCES means, there is no CORS registered yet for the bucket *ENOENT means, there is no match of the Origin in the list of CORSRule */ if (ret == -ENOENT) ret = -EACCES; if (ret < 0) { set_req_state_err(s, ret); dump_errno(s); end_header(s, NULL); return; } get_response_params(hdrs, exp_hdrs, &max_age); dump_errno(s); dump_access_control(s, origin, req_meth, hdrs.c_str(), exp_hdrs.c_str(), max_age); end_header(s, NULL); } RGWOp *RGWHandler_ObjStore_Service_SWIFT::op_get() { return new RGWListBuckets_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Service_SWIFT::op_head() { return new RGWStatAccount_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Service_SWIFT::op_post() { const char *temp_url = s->info.env->get("HTTP_X_ACCOUNT_META_TEMP_URL_KEY"); if (temp_url) { return new RGWSetTempUrl_ObjStore_SWIFT; } temp_url = s->info.env->get("HTTP_X_ACCOUNT_META_TEMP_URL_KEY_2"); if (temp_url) { return new RGWSetTempUrl_ObjStore_SWIFT; } return NULL; } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::get_obj_op(bool get_data) { if (is_acl_op()) { return new RGWGetACLs_ObjStore_SWIFT; } if (get_data) return new RGWListBucket_ObjStore_SWIFT; else return new RGWStatBucket_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::op_get() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_SWIFT; } return get_obj_op(true); } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::op_head() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_SWIFT; } return get_obj_op(false); } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::op_put() { if (is_acl_op()) { return new RGWPutACLs_ObjStore_SWIFT; } return new RGWCreateBucket_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::op_delete() { return new RGWDeleteBucket_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::op_post() { return new RGWPutMetadata_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Bucket_SWIFT::op_options() { return new RGWOptionsCORS_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::get_obj_op(bool get_data) { if (is_acl_op()) { return new RGWGetACLs_ObjStore_SWIFT; } RGWGetObj_ObjStore_SWIFT *get_obj_op = new RGWGetObj_ObjStore_SWIFT; get_obj_op->set_get_data(get_data); return get_obj_op; } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_get() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_SWIFT; } return get_obj_op(true); } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_head() { if (is_acl_op()) { return new RGWGetACLs_ObjStore_SWIFT; } return get_obj_op(false); } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_put() { if (is_acl_op()) { return new RGWPutACLs_ObjStore_SWIFT; } if (s->src_bucket_name.empty()) return new RGWPutObj_ObjStore_SWIFT; else return new RGWCopyObj_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_delete() { return new RGWDeleteObj_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_post() { return new RGWPutMetadata_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_copy() { return new RGWCopyObj_ObjStore_SWIFT; } RGWOp *RGWHandler_ObjStore_Obj_SWIFT::op_options() { return new RGWOptionsCORS_ObjStore_SWIFT; } int RGWHandler_ObjStore_SWIFT::authorize() { if ((!s->os_auth_token && s->info.args.get("temp_url_sig").empty()) || (s->op == OP_OPTIONS)) { /* anonymous access */ rgw_get_anon_user(s->user); s->perm_mask = RGW_PERM_FULL_CONTROL; return 0; } bool authorized = rgw_swift->verify_swift_token(store, s); if (!authorized) return -EPERM; return 0; } int RGWHandler_ObjStore_SWIFT::validate_bucket_name(const string& bucket) { int ret = RGWHandler_ObjStore::validate_bucket_name(bucket); if (ret < 0) return ret; int len = bucket.size(); if (len == 0) return 0; if (bucket[0] == '.') return -ERR_INVALID_BUCKET_NAME; if (check_utf8(bucket.c_str(), len)) return -ERR_INVALID_UTF8; const char *s = bucket.c_str(); for (int i = 0; i < len; ++i, ++s) { if (*(unsigned char *)s == 0xff) return -ERR_INVALID_BUCKET_NAME; } return 0; } static void next_tok(string& str, string& tok, char delim) { if (str.size() == 0) { tok = ""; return; } tok = str; int pos = str.find(delim); if (pos > 0) { tok = str.substr(0, pos); str = str.substr(pos + 1); } else { str = ""; } } int RGWHandler_ObjStore_SWIFT::init_from_header(struct req_state *s) { string req; string first; s->prot_flags |= RGW_REST_SWIFT; const char *req_name = s->decoded_uri.c_str(); const char *p; if (*req_name == '?') { p = req_name; } else { p = s->info.request_params.c_str(); } s->info.args.set(p); s->info.args.parse(); if (*req_name != '/') return 0; req_name++; if (!*req_name) return 0; req = req_name; int pos = req.find('/'); if (pos >= 0) { bool cut_url = g_conf->rgw_swift_url_prefix.length(); first = req.substr(0, pos); if (first.compare(g_conf->rgw_swift_url_prefix) == 0) { if (cut_url) { next_tok(req, first, '/'); } } } else { if (req.compare(g_conf->rgw_swift_url_prefix) == 0) { s->formatter = new RGWFormatter_Plain; return -ERR_BAD_URL; } first = req; } string tenant_path; if (!g_conf->rgw_swift_tenant_name.empty()) { tenant_path = "/AUTH_"; tenant_path.append(g_conf->rgw_swift_tenant_name); } /* verify that the request_uri conforms with what's expected */ char buf[g_conf->rgw_swift_url_prefix.length() + 16 + tenant_path.length()]; int blen = sprintf(buf, "/%s/v1%s", g_conf->rgw_swift_url_prefix.c_str(), tenant_path.c_str()); if (s->decoded_uri[0] != '/' || s->decoded_uri.compare(0, blen, buf) != 0) { return -ENOENT; } int ret = allocate_formatter(s, RGW_FORMAT_PLAIN, true); if (ret < 0) return ret; string ver; next_tok(req, ver, '/'); string tenant; if (!tenant_path.empty()) { next_tok(req, tenant, '/'); } s->os_auth_token = s->info.env->get("HTTP_X_AUTH_TOKEN"); next_tok(req, first, '/'); dout(10) << "ver=" << ver << " first=" << first << " req=" << req << dendl; if (first.size() == 0) return 0; s->bucket_name_str = first; s->info.effective_uri = "/" + s->bucket_name_str; if (req.size()) { s->object_str = req; s->object = strdup(s->object_str.c_str()); s->info.effective_uri.append("/" + s->object_str); } return 0; } int RGWHandler_ObjStore_SWIFT::init(RGWRados *store, struct req_state *s, RGWClientIO *cio) { dout(10) << "s->object=" << (s->object ? s->object : "") << " s->bucket=" << (!s->bucket_name_str.empty() ? s->bucket_name_str : "") << dendl; int ret = validate_bucket_name(s->bucket_name_str.c_str()); if (ret) return ret; ret = validate_object_name(s->object_str); if (ret) return ret; s->copy_source = s->info.env->get("HTTP_X_COPY_FROM"); if (s->copy_source) { bool result = RGWCopyObj::parse_copy_location(s->copy_source, s->src_bucket_name, s->src_object); if (!result) return -ERR_BAD_URL; } s->dialect = "swift"; if (s->op == OP_COPY) { const char *req_dest = s->info.env->get("HTTP_DESTINATION"); if (!req_dest) return -ERR_BAD_URL; string dest_bucket_name; string dest_object; bool result = RGWCopyObj::parse_copy_location(req_dest, dest_bucket_name, dest_object); if (!result) return -ERR_BAD_URL; if (dest_bucket_name != s->bucket_name_str) { ret = validate_bucket_name(dest_bucket_name.c_str()); if (ret < 0) return ret; } /* convert COPY operation into PUT */ s->src_bucket_name = s->bucket_name_str; s->src_object = s->object_str; s->bucket_name_str = dest_bucket_name; s->object_str = dest_object; s->op = OP_PUT; } return RGWHandler_ObjStore::init(store, s, cio); } RGWHandler *RGWRESTMgr_SWIFT::get_handler(struct req_state *s) { int ret = RGWHandler_ObjStore_SWIFT::init_from_header(s); if (ret < 0) return NULL; if (s->bucket_name_str.empty()) return new RGWHandler_ObjStore_Service_SWIFT; if (!s->object) return new RGWHandler_ObjStore_Bucket_SWIFT; return new RGWHandler_ObjStore_Obj_SWIFT; } ceph-0.80.11/src/rgw/rgw_rest_client.h0000664000175100017510000000623412623076744021633 0ustar jenkins-buildjenkins-build#ifndef CEPH_RGW_REST_CLIENT_H #define CEPH_RGW_REST_CLIENT_H #include #include "rgw_http_client.h" class RGWGetDataCB; class RGWRESTSimpleRequest : public RGWHTTPClient { protected: int http_status; int status; string url; map out_headers; list > params; bufferlist::iterator *send_iter; size_t max_response; /* we need this as we don't stream out response */ bufferlist response; virtual int handle_header(const string& name, const string& val) { return 0; } void append_param(string& dest, const string& name, const string& val); void get_params_str(map& extra_args, string& dest); int sign_request(RGWAccessKey& key, RGWEnv& env, req_info& info); public: RGWRESTSimpleRequest(CephContext *_cct, string& _url, list > *_headers, list > *_params) : RGWHTTPClient(_cct), http_status(0), status(0), url(_url), send_iter(NULL), max_response(0) { if (_headers) headers = *_headers; if (_params) params = *_params; } int receive_header(void *ptr, size_t len); virtual int receive_data(void *ptr, size_t len); virtual int send_data(void *ptr, size_t len); bufferlist& get_response() { return response; } int execute(RGWAccessKey& key, const char *method, const char *resource); int forward_request(RGWAccessKey& key, req_info& info, size_t max_response, bufferlist *inbl, bufferlist *outbl); map& get_out_headers() { return out_headers; } }; class RGWRESTStreamWriteRequest : public RGWRESTSimpleRequest { Mutex lock; list pending_send; void *handle; RGWGetDataCB *cb; public: int add_output_data(bufferlist& bl); int send_data(void *ptr, size_t len); RGWRESTStreamWriteRequest(CephContext *_cct, string& _url, list > *_headers, list > *_params) : RGWRESTSimpleRequest(_cct, _url, _headers, _params), lock("RGWRESTStreamWriteRequest"), handle(NULL), cb(NULL) {} ~RGWRESTStreamWriteRequest(); int put_obj_init(RGWAccessKey& key, rgw_obj& obj, uint64_t obj_size, map& attrs); int complete(string& etag, time_t *mtime); RGWGetDataCB *get_out_cb() { return cb; } }; class RGWRESTStreamReadRequest : public RGWRESTSimpleRequest { Mutex lock; RGWGetDataCB *cb; bufferlist in_data; size_t chunk_ofs; size_t ofs; protected: int handle_header(const string& name, const string& val); public: int send_data(void *ptr, size_t len); int receive_data(void *ptr, size_t len); RGWRESTStreamReadRequest(CephContext *_cct, string& _url, RGWGetDataCB *_cb, list > *_headers, list > *_params) : RGWRESTSimpleRequest(_cct, _url, _headers, _params), lock("RGWRESTStreamReadRequest"), cb(_cb), chunk_ofs(0), ofs(0) {} ~RGWRESTStreamReadRequest() {} int get_obj(RGWAccessKey& key, map& extra_headers, rgw_obj& obj); int complete(string& etag, time_t *mtime, map& attrs); void set_in_cb(RGWGetDataCB *_cb) { cb = _cb; } }; #endif ceph-0.80.11/src/rgw/rgw_rest_log.cc0000664000175100017510000004656312623076744021305 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_json.h" #include "common/strtol.h" #include "rgw_rest.h" #include "rgw_op.h" #include "rgw_rest_s3.h" #include "rgw_rest_log.h" #include "rgw_client_io.h" #include "common/errno.h" #define LOG_CLASS_LIST_MAX_ENTRIES (1000) #define dout_subsys ceph_subsys_rgw static int parse_date_str(string& in, utime_t& out) { uint64_t epoch = 0; uint64_t nsec = 0; if (!in.empty()) { if (utime_t::parse_date(in, &epoch, &nsec) < 0) { dout(5) << "Error parsing date " << in << dendl; return -EINVAL; } } out = utime_t(epoch, nsec); return 0; } void RGWOp_MDLog_List::execute() { string shard = s->info.args.get("id"); string max_entries_str = s->info.args.get("max-entries"); string st = s->info.args.get("start-time"), et = s->info.args.get("end-time"), marker = s->info.args.get("marker"), err; utime_t ut_st, ut_et; void *handle; unsigned shard_id, max_entries = LOG_CLASS_LIST_MAX_ENTRIES; shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id " << shard << dendl; http_ret = -EINVAL; return; } if (parse_date_str(st, ut_st) < 0) { http_ret = -EINVAL; return; } if (parse_date_str(et, ut_et) < 0) { http_ret = -EINVAL; return; } if (!max_entries_str.empty()) { max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing max-entries " << max_entries_str << dendl; http_ret = -EINVAL; return; } } RGWMetadataLog *meta_log = store->meta_mgr->get_log(); meta_log->init_list_entries(shard_id, ut_st, ut_et, marker, &handle); do { http_ret = meta_log->list_entries(handle, max_entries, entries, &last_marker, &truncated); if (http_ret < 0) break; if (!max_entries_str.empty()) max_entries -= entries.size(); } while (truncated && (max_entries > 0)); meta_log->complete_list_entries(handle); } void RGWOp_MDLog_List::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); if (http_ret < 0) return; s->formatter->open_object_section("log_entries"); s->formatter->dump_string("marker", last_marker); s->formatter->dump_bool("truncated", truncated); { s->formatter->open_array_section("entries"); for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { cls_log_entry& entry = *iter; store->meta_mgr->dump_log_entry(entry, s->formatter); flusher.flush(); } s->formatter->close_section(); } s->formatter->close_section(); flusher.flush(); } void RGWOp_MDLog_Info::execute() { num_objects = s->cct->_conf->rgw_md_log_max_shards; http_ret = 0; } void RGWOp_MDLog_Info::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); s->formatter->open_object_section("num_objects"); s->formatter->dump_unsigned("num_objects", num_objects); s->formatter->close_section(); flusher.flush(); } void RGWOp_MDLog_ShardInfo::execute() { string shard = s->info.args.get("id"); string err; unsigned shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id " << shard << dendl; http_ret = -EINVAL; return; } RGWMetadataLog *meta_log = store->meta_mgr->get_log(); http_ret = meta_log->get_info(shard_id, &info); } void RGWOp_MDLog_ShardInfo::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); encode_json("info", info, s->formatter); flusher.flush(); } void RGWOp_MDLog_Delete::execute() { string st = s->info.args.get("start-time"), et = s->info.args.get("end-time"), start_marker = s->info.args.get("start-marker"), end_marker = s->info.args.get("end-marker"), shard = s->info.args.get("id"), err; utime_t ut_st, ut_et; unsigned shard_id; http_ret = 0; shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id " << shard << dendl; http_ret = -EINVAL; return; } if (et.empty() && end_marker.empty()) { /* bounding end */ http_ret = -EINVAL; return; } if (parse_date_str(st, ut_st) < 0) { http_ret = -EINVAL; return; } if (parse_date_str(et, ut_et) < 0) { http_ret = -EINVAL; return; } RGWMetadataLog *meta_log = store->meta_mgr->get_log(); http_ret = meta_log->trim(shard_id, ut_st, ut_et, start_marker, end_marker); } void RGWOp_MDLog_Lock::execute() { string shard_id_str, duration_str, locker_id, zone_id; unsigned shard_id; http_ret = 0; shard_id_str = s->info.args.get("id"); duration_str = s->info.args.get("length"); locker_id = s->info.args.get("locker-id"); zone_id = s->info.args.get("zone-id"); if (shard_id_str.empty() || (duration_str.empty()) || locker_id.empty() || zone_id.empty()) { dout(5) << "Error invalid parameter list" << dendl; http_ret = -EINVAL; return; } string err; shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id param " << shard_id_str << dendl; http_ret = -EINVAL; return; } RGWMetadataLog *meta_log = store->meta_mgr->get_log(); unsigned dur; dur = (unsigned)strict_strtol(duration_str.c_str(), 10, &err); if (!err.empty() || dur <= 0) { dout(5) << "invalid length param " << duration_str << dendl; http_ret = -EINVAL; return; } utime_t time(dur, 0); http_ret = meta_log->lock_exclusive(shard_id, time, zone_id, locker_id); if (http_ret == -EBUSY) http_ret = -ERR_LOCKED; } void RGWOp_MDLog_Unlock::execute() { string shard_id_str, locker_id, zone_id; unsigned shard_id; http_ret = 0; shard_id_str = s->info.args.get("id"); locker_id = s->info.args.get("locker-id"); zone_id = s->info.args.get("zone-id"); if (shard_id_str.empty() || locker_id.empty() || zone_id.empty()) { dout(5) << "Error invalid parameter list" << dendl; http_ret = -EINVAL; return; } string err; shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id param " << shard_id_str << dendl; http_ret = -EINVAL; return; } RGWMetadataLog *meta_log = store->meta_mgr->get_log(); http_ret = meta_log->unlock(shard_id, zone_id, locker_id); } void RGWOp_BILog_List::execute() { string bucket_name = s->info.args.get("bucket"), marker = s->info.args.get("marker"), max_entries_str = s->info.args.get("max-entries"), bucket_instance = s->info.args.get("bucket-instance"); RGWBucketInfo bucket_info; unsigned max_entries; if (bucket_name.empty() && bucket_instance.empty()) { dout(5) << "ERROR: neither bucket nor bucket instance specified" << dendl; http_ret = -EINVAL; return; } if (!bucket_instance.empty()) { http_ret = store->get_bucket_instance_info(NULL, bucket_instance, bucket_info, NULL, NULL); if (http_ret < 0) { dout(5) << "could not get bucket instance info for bucket instance id=" << bucket_instance << dendl; return; } } else { /* !bucket_name.empty() */ http_ret = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL, NULL); if (http_ret < 0) { dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl; return; } } bool truncated; unsigned count = 0; string err; max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err); if (!err.empty()) max_entries = LOG_CLASS_LIST_MAX_ENTRIES; send_response(); do { list entries; int ret = store->list_bi_log_entries(bucket_info.bucket, marker, max_entries - count, entries, &truncated); if (ret < 0) { dout(5) << "ERROR: list_bi_log_entries()" << dendl; return; } count += entries.size(); send_response(entries, marker); } while (truncated && count < max_entries); send_response_end(); } void RGWOp_BILog_List::send_response() { if (sent_header) return; set_req_state_err(s, http_ret); dump_errno(s); end_header(s); sent_header = true; if (http_ret < 0) return; s->formatter->open_array_section("entries"); } void RGWOp_BILog_List::send_response(list& entries, string& marker) { for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { rgw_bi_log_entry& entry = *iter; encode_json("entry", entry, s->formatter); marker = entry.id; flusher.flush(); } } void RGWOp_BILog_List::send_response_end() { s->formatter->close_section(); flusher.flush(); } void RGWOp_BILog_Info::execute() { string bucket_name = s->info.args.get("bucket"), bucket_instance = s->info.args.get("bucket-instance"); RGWBucketInfo bucket_info; if (bucket_name.empty() && bucket_instance.empty()) { dout(5) << "ERROR: neither bucket nor bucket instance specified" << dendl; http_ret = -EINVAL; return; } if (!bucket_instance.empty()) { http_ret = store->get_bucket_instance_info(NULL, bucket_instance, bucket_info, NULL, NULL); if (http_ret < 0) { dout(5) << "could not get bucket instance info for bucket instance id=" << bucket_instance << dendl; return; } } else { /* !bucket_name.empty() */ http_ret = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL, NULL); if (http_ret < 0) { dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl; return; } } map stats; int ret = store->get_bucket_stats(bucket_info.bucket, &bucket_ver, &master_ver, stats, &max_marker); if (ret < 0 && ret != -ENOENT) { http_ret = ret; return; } } void RGWOp_BILog_Info::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); if (http_ret < 0) return; s->formatter->open_object_section("info"); encode_json("bucket_ver", bucket_ver, s->formatter); encode_json("master_ver", master_ver, s->formatter); encode_json("max_marker", max_marker, s->formatter); s->formatter->close_section(); flusher.flush(); } void RGWOp_BILog_Delete::execute() { string bucket_name = s->info.args.get("bucket"), start_marker = s->info.args.get("start-marker"), end_marker = s->info.args.get("end-marker"), bucket_instance = s->info.args.get("bucket-instance"); RGWBucketInfo bucket_info; http_ret = 0; if ((bucket_name.empty() && bucket_instance.empty()) || end_marker.empty()) { dout(5) << "ERROR: one of bucket and bucket instance, and also end-marker is mandatory" << dendl; http_ret = -EINVAL; return; } if (!bucket_instance.empty()) { http_ret = store->get_bucket_instance_info(NULL, bucket_instance, bucket_info, NULL, NULL); if (http_ret < 0) { dout(5) << "could not get bucket instance info for bucket instance id=" << bucket_instance << dendl; return; } } else { /* !bucket_name.empty() */ http_ret = store->get_bucket_info(NULL, bucket_name, bucket_info, NULL, NULL); if (http_ret < 0) { dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl; return; } } http_ret = store->trim_bi_log_entries(bucket_info.bucket, start_marker, end_marker); if (http_ret < 0) { dout(5) << "ERROR: trim_bi_log_entries() " << dendl; } return; } void RGWOp_DATALog_List::execute() { string shard = s->info.args.get("id"); string st = s->info.args.get("start-time"), et = s->info.args.get("end-time"), max_entries_str = s->info.args.get("max-entries"), marker = s->info.args.get("marker"), err; utime_t ut_st, ut_et; unsigned shard_id, max_entries = LOG_CLASS_LIST_MAX_ENTRIES; shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id " << shard << dendl; http_ret = -EINVAL; return; } if (parse_date_str(st, ut_st) < 0) { http_ret = -EINVAL; return; } if (parse_date_str(et, ut_et) < 0) { http_ret = -EINVAL; return; } if (!max_entries_str.empty()) { max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing max-entries " << max_entries_str << dendl; http_ret = -EINVAL; return; } } do { // Note that last_marker is updated to be the marker of the last // entry listed http_ret = store->data_log->list_entries(shard_id, ut_st, ut_et, max_entries, entries, marker, &last_marker, &truncated); if (http_ret < 0) break; if (!max_entries_str.empty()) max_entries -= entries.size(); } while (truncated && (max_entries > 0)); } void RGWOp_DATALog_List::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); if (http_ret < 0) return; s->formatter->open_object_section("log_entries"); s->formatter->dump_string("marker", last_marker); s->formatter->dump_bool("truncated", truncated); { s->formatter->open_array_section("entries"); for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { rgw_data_change& entry = *iter; encode_json("entry", entry, s->formatter); flusher.flush(); } s->formatter->close_section(); } s->formatter->close_section(); flusher.flush(); } void RGWOp_DATALog_Info::execute() { num_objects = s->cct->_conf->rgw_data_log_num_shards; http_ret = 0; } void RGWOp_DATALog_Info::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); s->formatter->open_object_section("num_objects"); s->formatter->dump_unsigned("num_objects", num_objects); s->formatter->close_section(); flusher.flush(); } void RGWOp_DATALog_ShardInfo::execute() { string shard = s->info.args.get("id"); string err; unsigned shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id " << shard << dendl; http_ret = -EINVAL; return; } http_ret = store->data_log->get_info(shard_id, &info); } void RGWOp_DATALog_ShardInfo::send_response() { set_req_state_err(s, http_ret); dump_errno(s); end_header(s); encode_json("info", info, s->formatter); flusher.flush(); } void RGWOp_DATALog_Lock::execute() { string shard_id_str, duration_str, locker_id, zone_id; unsigned shard_id; http_ret = 0; shard_id_str = s->info.args.get("id"); duration_str = s->info.args.get("length"); locker_id = s->info.args.get("locker-id"); zone_id = s->info.args.get("zone-id"); if (shard_id_str.empty() || (duration_str.empty()) || locker_id.empty() || zone_id.empty()) { dout(5) << "Error invalid parameter list" << dendl; http_ret = -EINVAL; return; } string err; shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id param " << shard_id_str << dendl; http_ret = -EINVAL; return; } unsigned dur; dur = (unsigned)strict_strtol(duration_str.c_str(), 10, &err); if (!err.empty() || dur <= 0) { dout(5) << "invalid length param " << duration_str << dendl; http_ret = -EINVAL; return; } utime_t time(dur, 0); http_ret = store->data_log->lock_exclusive(shard_id, time, zone_id, locker_id); if (http_ret == -EBUSY) http_ret = -ERR_LOCKED; } void RGWOp_DATALog_Unlock::execute() { string shard_id_str, locker_id, zone_id; unsigned shard_id; http_ret = 0; shard_id_str = s->info.args.get("id"); locker_id = s->info.args.get("locker-id"); zone_id = s->info.args.get("zone-id"); if (shard_id_str.empty() || locker_id.empty() || zone_id.empty()) { dout(5) << "Error invalid parameter list" << dendl; http_ret = -EINVAL; return; } string err; shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id param " << shard_id_str << dendl; http_ret = -EINVAL; return; } http_ret = store->data_log->unlock(shard_id, zone_id, locker_id); } void RGWOp_DATALog_Delete::execute() { string st = s->info.args.get("start-time"), et = s->info.args.get("end-time"), start_marker = s->info.args.get("start-marker"), end_marker = s->info.args.get("end-marker"), shard = s->info.args.get("id"), err; utime_t ut_st, ut_et; unsigned shard_id; http_ret = 0; shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err); if (!err.empty()) { dout(5) << "Error parsing shard_id " << shard << dendl; http_ret = -EINVAL; return; } if (et.empty() && end_marker.empty()) { /* bounding end */ http_ret = -EINVAL; return; } if (parse_date_str(st, ut_st) < 0) { http_ret = -EINVAL; return; } if (parse_date_str(et, ut_et) < 0) { http_ret = -EINVAL; return; } http_ret = store->data_log->trim_entries(shard_id, ut_st, ut_et, start_marker, end_marker); } RGWOp *RGWHandler_Log::op_get() { bool exists; string type = s->info.args.get("type", &exists); if (!exists) { return NULL; } if (type.compare("metadata") == 0) { if (s->info.args.exists("id")) { if (s->info.args.exists("info")) { return new RGWOp_MDLog_ShardInfo; } else { return new RGWOp_MDLog_List; } } else { return new RGWOp_MDLog_Info; } } else if (type.compare("bucket-index") == 0) { if (s->info.args.exists("info")) { return new RGWOp_BILog_Info; } else { return new RGWOp_BILog_List; } } else if (type.compare("data") == 0) { if (s->info.args.exists("id")) { if (s->info.args.exists("info")) { return new RGWOp_DATALog_ShardInfo; } else { return new RGWOp_DATALog_List; } } else { return new RGWOp_DATALog_Info; } } return NULL; } RGWOp *RGWHandler_Log::op_delete() { bool exists; string type = s->info.args.get("type", &exists); if (!exists) { return NULL; } if (type.compare("metadata") == 0) return new RGWOp_MDLog_Delete; else if (type.compare("bucket-index") == 0) return new RGWOp_BILog_Delete; else if (type.compare("data") == 0) return new RGWOp_DATALog_Delete; return NULL; } RGWOp *RGWHandler_Log::op_post() { bool exists; string type = s->info.args.get("type", &exists); if (!exists) { return NULL; } if (type.compare("metadata") == 0) { if (s->info.args.exists("lock")) return new RGWOp_MDLog_Lock; else if (s->info.args.exists("unlock")) return new RGWOp_MDLog_Unlock; } else if (type.compare("data") == 0) { if (s->info.args.exists("lock")) return new RGWOp_DATALog_Lock; else if (s->info.args.exists("unlock")) return new RGWOp_DATALog_Unlock; } return NULL; } ceph-0.80.11/src/rgw/rgw_acl.cc0000664000175100017510000000701312623076744020211 0ustar jenkins-buildjenkins-build#include #include #include #include "include/types.h" #include "common/Formatter.h" #include "rgw_acl.h" #include "rgw_user.h" #include "rgw_acl_s3.h" // required for backward compatibility #define dout_subsys ceph_subsys_rgw using namespace std; void RGWAccessControlList::_add_grant(ACLGrant *grant) { ACLPermission& perm = grant->get_permission(); ACLGranteeType& type = grant->get_type(); switch (type.get_type()) { case ACL_TYPE_GROUP: acl_group_map[grant->get_group()] |= perm.get_permissions(); break; default: { string id; if (!grant->get_id(id)) { ldout(cct, 0) << "ERROR: grant->get_id() failed" << dendl; } acl_user_map[id] |= perm.get_permissions(); } } } void RGWAccessControlList::add_grant(ACLGrant *grant) { string id; grant->get_id(id); // not that this will return false for groups, but that's ok, we won't search groups grant_map.insert(pair(id, *grant)); _add_grant(grant); } int RGWAccessControlList::get_perm(string& id, int perm_mask) { ldout(cct, 5) << "Searching permissions for uid=" << id << " mask=" << perm_mask << dendl; map::iterator iter = acl_user_map.find(id); if (iter != acl_user_map.end()) { ldout(cct, 5) << "Found permission: " << iter->second << dendl; return iter->second & perm_mask; } ldout(cct, 5) << "Permissions for user not found" << dendl; return 0; } int RGWAccessControlList::get_group_perm(ACLGroupTypeEnum group, int perm_mask) { ldout(cct, 5) << "Searching permissions for group=" << (int)group << " mask=" << perm_mask << dendl; map::iterator iter = acl_group_map.find((uint32_t)group); if (iter != acl_group_map.end()) { ldout(cct, 5) << "Found permission: " << iter->second << dendl; return iter->second & perm_mask; } ldout(cct, 5) << "Permissions for group not found" << dendl; return 0; } int RGWAccessControlPolicy::get_perm(string& id, int perm_mask) { int perm = acl.get_perm(id, perm_mask); if (id.compare(owner.get_id()) == 0) { perm |= perm_mask & (RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP); } if (perm == perm_mask) return perm; /* should we continue looking up? */ if ((perm & perm_mask) != perm_mask) { perm |= acl.get_group_perm(ACL_GROUP_ALL_USERS, perm_mask); if (!compare_group_name(id, ACL_GROUP_ALL_USERS)) { /* this is not the anonymous user */ perm |= acl.get_group_perm(ACL_GROUP_AUTHENTICATED_USERS, perm_mask); } } ldout(cct, 5) << "Getting permissions id=" << id << " owner=" << owner.get_id() << " perm=" << perm << dendl; return perm; } bool RGWAccessControlPolicy::verify_permission(string& uid, int user_perm_mask, int perm) { int test_perm = perm | RGW_PERM_READ_OBJS | RGW_PERM_WRITE_OBJS; int policy_perm = get_perm(uid, test_perm); /* the swift WRITE_OBJS perm is equivalent to the WRITE obj, just convert those bits. Note that these bits will only be set on buckets, so the swift READ permission on bucket will allow listing the bucket content */ if (policy_perm & RGW_PERM_WRITE_OBJS) { policy_perm |= (RGW_PERM_WRITE | RGW_PERM_WRITE_ACP); } if (policy_perm & RGW_PERM_READ_OBJS) { policy_perm |= (RGW_PERM_READ | RGW_PERM_READ_ACP); } int acl_perm = policy_perm & perm & user_perm_mask; ldout(cct, 10) << " uid=" << uid << " requested perm (type)=" << perm << ", policy perm=" << policy_perm << ", user_perm_mask=" << user_perm_mask << ", acl perm=" << acl_perm << dendl; return (perm == acl_perm); } ceph-0.80.11/src/ceph_mon.cc0000664000175100017510000005363212623076744017574 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include using namespace std; #include "common/config.h" #include "include/ceph_features.h" #include "mon/MonMap.h" #include "mon/Monitor.h" #include "mon/MonitorDBStore.h" #include "mon/MonClient.h" #include "msg/Messenger.h" #include "include/CompatSet.h" #include "common/ceph_argparse.h" #include "common/pick_address.h" #include "common/Timer.h" #include "common/errno.h" #include "common/Preforker.h" #include "global/global_init.h" #include "global/signal_handler.h" #include "include/assert.h" #include "erasure-code/ErasureCodePlugin.h" #define dout_subsys ceph_subsys_mon Monitor *mon = NULL; void handle_mon_signal(int signum) { if (mon) mon->handle_signal(signum); } int obtain_monmap(MonitorDBStore &store, bufferlist &bl) { dout(10) << __func__ << dendl; /* * the monmap may be in one of three places: * 'monmap:' - the monmap we'd really like to have * 'mon_sync:latest_monmap' - last monmap backed up for the last sync * 'mkfs:monmap' - a monmap resulting from mkfs */ if (store.exists("monmap", "last_committed")) { version_t latest_ver = store.get("monmap", "last_committed"); if (store.exists("monmap", latest_ver)) { int err = store.get("monmap", latest_ver, bl); assert(err == 0); assert(bl.length() > 0); dout(10) << __func__ << " read last committed monmap ver " << latest_ver << dendl; return 0; } } if (store.exists("mon_sync", "in_sync") || store.exists("mon_sync", "force_sync")) { dout(10) << __func__ << " detected aborted sync" << dendl; if (store.exists("mon_sync", "latest_monmap")) { int err = store.get("mon_sync", "latest_monmap", bl); assert(err == 0); assert(bl.length() > 0); dout(10) << __func__ << " read backup monmap" << dendl; return 0; } } if (store.exists("mkfs", "monmap")) { dout(10) << __func__ << " found mkfs monmap" << dendl; int err = store.get("mkfs", "monmap", bl); assert(err == 0); assert(bl.length() > 0); return 0; } derr << __func__ << " unable to find a monmap" << dendl; return -ENOENT; } int mon_data_exists(bool *r) { string mon_data = g_conf->mon_data; struct stat buf; if (::stat(mon_data.c_str(), &buf)) { if (errno == ENOENT) { *r = false; } else { cerr << "stat(" << mon_data << ") " << cpp_strerror(errno) << std::endl; return -errno; } } else { *r = true; } return 0; } int mon_data_empty(bool *r) { string mon_data = g_conf->mon_data; DIR *dir = ::opendir(mon_data.c_str()); if (!dir) { cerr << "opendir(" << mon_data << ") " << cpp_strerror(errno) << std::endl; return -errno; } char buf[offsetof(struct dirent, d_name) + PATH_MAX + 1]; *r = false; int code = 0; struct dirent *de; errno = 0; while (!::readdir_r(dir, reinterpret_cast(buf), &de)) { if (!de) { if (errno) { cerr << "readdir(" << mon_data << ") " << cpp_strerror(errno) << std::endl; code = -errno; } break; } if (string(".") != de->d_name && string("..") != de->d_name) { *r = true; break; } } ::closedir(dir); return code; } int mon_exists(bool *r) { int code = mon_data_exists(r); if (code || *r == false) return code; return mon_data_empty(r); } void usage() { cerr << "usage: ceph-mon -i monid [flags]" << std::endl; cerr << " --debug_mon n\n"; cerr << " debug monitor level (e.g. 10)\n"; cerr << " --mkfs\n"; cerr << " build fresh monitor fs\n"; cerr << " --force-sync\n"; cerr << " force a sync from another mon by wiping local data (BE CAREFUL)\n"; cerr << " --yes-i-really-mean-it\n"; cerr << " mandatory safeguard for --force-sync\n"; cerr << " --compact\n"; cerr << " compact the monitor store\n"; cerr << " --osdmap \n"; cerr << " only used when --mkfs is provided: load the osdmap from \n"; cerr << " --inject-monmap \n"; cerr << " write the monmap to the local monitor store and exit\n"; cerr << " --extract-monmap \n"; cerr << " extract the monmap from the local monitor store and exit\n"; cerr << " --mon-data \n"; cerr << " where the mon store and keyring are located\n"; generic_server_usage(); } int preload_erasure_code() { string directory = g_conf->osd_pool_default_erasure_code_directory; string plugins = g_conf->osd_erasure_code_plugins; stringstream ss; int r = ErasureCodePluginRegistry::instance().preload(plugins, directory, ss); if (r) derr << ss.str() << dendl; else dout(10) << ss.str() << dendl; return r; } int main(int argc, const char **argv) { int err; bool mkfs = false; bool compact = false; bool force_sync = false; bool yes_really = false; std::string osdmapfn, inject_monmap, extract_monmap; vector args; argv_to_vec(argc, argv, args); env_to_vec(args); int flags = 0; { vector args_copy = args; std::string val; for (std::vector::iterator i = args_copy.begin(); i != args_copy.end(); ) { if (ceph_argparse_double_dash(args_copy, i)) { break; } else if (ceph_argparse_flag(args_copy, i, "--mkfs", (char*)NULL)) { flags |= CINIT_FLAG_NO_DAEMON_ACTIONS; } else if (ceph_argparse_witharg(args_copy, i, &val, "--inject_monmap", (char*)NULL)) { flags |= CINIT_FLAG_NO_DAEMON_ACTIONS; } else if (ceph_argparse_witharg(args_copy, i, &val, "--extract-monmap", (char*)NULL)) { flags |= CINIT_FLAG_NO_DAEMON_ACTIONS; } else { ++i; } } } global_init(NULL, args, CEPH_ENTITY_TYPE_MON, CODE_ENVIRONMENT_DAEMON, flags); uuid_d fsid; std::string val; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); exit(0); } else if (ceph_argparse_flag(args, i, "--mkfs", (char*)NULL)) { mkfs = true; } else if (ceph_argparse_flag(args, i, "--compact", (char*)NULL)) { compact = true; } else if (ceph_argparse_flag(args, i, "--force-sync", (char*)NULL)) { force_sync = true; } else if (ceph_argparse_flag(args, i, "--yes-i-really-mean-it", (char*)NULL)) { yes_really = true; } else if (ceph_argparse_witharg(args, i, &val, "--osdmap", (char*)NULL)) { osdmapfn = val; } else if (ceph_argparse_witharg(args, i, &val, "--inject_monmap", (char*)NULL)) { inject_monmap = val; } else if (ceph_argparse_witharg(args, i, &val, "--extract-monmap", (char*)NULL)) { extract_monmap = val; } else { ++i; } } if (!args.empty()) { cerr << "too many arguments: " << args << std::endl; usage(); } if (force_sync && !yes_really) { cerr << "are you SURE you want to force a sync? this will erase local data and may\n" << "break your mon cluster. pass --yes-i-really-mean-it if you do." << std::endl; exit(1); } if (g_conf->mon_data.empty()) { cerr << "must specify '--mon-data=foo' data path" << std::endl; usage(); } if (g_conf->name.get_id().empty()) { cerr << "must specify id (--id or --name mon.)" << std::endl; usage(); } bool exists; if (mon_exists(&exists)) exit(1); if (mkfs && exists) { cerr << g_conf->mon_data << " already exists" << std::endl; exit(0); } // -- mkfs -- if (mkfs) { if (mon_data_exists(&exists)) exit(1); if (!exists) { if (::mkdir(g_conf->mon_data.c_str(), 0755)) { cerr << "mkdir(" << g_conf->mon_data << ") : " << cpp_strerror(errno) << std::endl; exit(1); } } // resolve public_network -> public_addr pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC); common_init_finish(g_ceph_context, flags); bufferlist monmapbl, osdmapbl; std::string error; MonMap monmap; // load or generate monmap if (g_conf->monmap.length()) { int err = monmapbl.read_file(g_conf->monmap.c_str(), &error); if (err < 0) { cerr << argv[0] << ": error reading " << g_conf->monmap << ": " << error << std::endl; exit(1); } try { monmap.decode(monmapbl); // always mark seed/mkfs monmap as epoch 0 monmap.set_epoch(0); } catch (const buffer::error& e) { cerr << argv[0] << ": error decoding monmap " << g_conf->monmap << ": " << e.what() << std::endl; exit(1); } } else { int err = monmap.build_initial(g_ceph_context, cerr); if (err < 0) { cerr << argv[0] << ": warning: no initial monitors; must use admin socket to feed hints" << std::endl; } // am i part of the initial quorum? if (monmap.contains(g_conf->name.get_id())) { // hmm, make sure the ip listed exists on the current host? // maybe later. } else if (!g_conf->public_addr.is_blank_ip()) { entity_addr_t a = g_conf->public_addr; if (a.get_port() == 0) a.set_port(CEPH_MON_PORT); if (monmap.contains(a)) { string name; monmap.get_addr_name(a, name); monmap.rename(name, g_conf->name.get_id()); cout << argv[0] << ": renaming mon." << name << " " << a << " to mon." << g_conf->name.get_id() << std::endl; } } else { // is a local address listed without a name? if so, name myself. list ls; monmap.list_addrs(ls); entity_addr_t local; if (have_local_addr(g_ceph_context, ls, &local)) { string name; monmap.get_addr_name(local, name); if (name.find("noname-") == 0) { cout << argv[0] << ": mon." << name << " " << local << " is local, renaming to mon." << g_conf->name.get_id() << std::endl; monmap.rename(name, g_conf->name.get_id()); } else { cout << argv[0] << ": mon." << name << " " << local << " is local, but not 'noname-' + something; not assuming it's me" << std::endl; } } } } if (!g_conf->fsid.is_zero()) { monmap.fsid = g_conf->fsid; cout << argv[0] << ": set fsid to " << g_conf->fsid << std::endl; } if (monmap.fsid.is_zero()) { cerr << argv[0] << ": generated monmap has no fsid; use '--fsid '" << std::endl; exit(10); } //monmap.print(cout); // osdmap if (osdmapfn.length()) { err = osdmapbl.read_file(osdmapfn.c_str(), &error); if (err < 0) { cerr << argv[0] << ": error reading " << osdmapfn << ": " << error << std::endl; exit(1); } } // go MonitorDBStore store(g_conf->mon_data); int r = store.create_and_open(cerr); if (r < 0) { cerr << argv[0] << ": error opening mon data directory at '" << g_conf->mon_data << "': " << cpp_strerror(r) << std::endl; exit(1); } assert(r == 0); Monitor mon(g_ceph_context, g_conf->name.get_id(), &store, 0, &monmap); r = mon.mkfs(osdmapbl); if (r < 0) { cerr << argv[0] << ": error creating monfs: " << cpp_strerror(r) << std::endl; exit(1); } cout << argv[0] << ": created monfs at " << g_conf->mon_data << " for " << g_conf->name << std::endl; return 0; } { // check fs stats. don't start if it's critically close to full. ceph_data_stats_t stats; int err = get_fs_stats(stats, g_conf->mon_data.c_str()); if (err < 0) { cerr << "error checking monitor data's fs stats: " << cpp_strerror(err) << std::endl; exit(-err); } if (stats.avail_percent <= g_conf->mon_data_avail_crit) { cerr << "error: monitor data filesystem reached concerning levels of" << " available storage space (available: " << stats.avail_percent << "% " << prettybyte_t(stats.byte_avail) << ")\nyou may adjust 'mon data avail crit' to a lower value" << " to make this go away (default: " << g_conf->mon_data_avail_crit << "%)\n" << std::endl; exit(ENOSPC); } } // we fork early to prevent leveldb's environment static state from // screwing us over Preforker prefork; if (!(flags & CINIT_FLAG_NO_DAEMON_ACTIONS)) { if (global_init_prefork(g_ceph_context, 0) >= 0) { prefork.prefork(); if (prefork.is_parent()) { return prefork.parent_wait(); } global_init_postfork_start(g_ceph_context); } common_init_finish(g_ceph_context); global_init_chdir(g_ceph_context); if (preload_erasure_code() < -1) prefork.exit(1); } MonitorDBStore *store = new MonitorDBStore(g_conf->mon_data); Monitor::StoreConverter converter(g_conf->mon_data, store); if (store->open(std::cerr) < 0) { int ret = store->create_and_open(std::cerr); if (ret < 0) { derr << "failed to create new leveldb store" << dendl; prefork.exit(1); } ret = converter.needs_conversion(); if (ret < 0) { derr << "found errors while validating legacy unconverted monitor store: " << cpp_strerror(ret) << dendl; prefork.exit(1); } if (ret > 0) { dout(0) << "converting monitor store, please do not interrupt..." << dendl; int r = converter.convert(); if (r) { derr << "failed to convert monitor store: " << cpp_strerror(r) << dendl; prefork.exit(1); } } } else if (converter.is_converting()) { derr << "there is an on-going (maybe aborted?) conversion." << dendl; derr << "you should check what happened" << dendl; derr << "remove store.db to restart conversion" << dendl; prefork.exit(1); } bufferlist magicbl; err = store->get(Monitor::MONITOR_NAME, "magic", magicbl); if (!magicbl.length()) { derr << "unable to read magic from mon data.. did you run mkcephfs?" << dendl; prefork.exit(1); } string magic(magicbl.c_str(), magicbl.length()-1); // ignore trailing \n if (strcmp(magic.c_str(), CEPH_MON_ONDISK_MAGIC)) { derr << "mon fs magic '" << magic << "' != current '" << CEPH_MON_ONDISK_MAGIC << "'" << dendl; prefork.exit(1); } err = Monitor::check_features(store); if (err < 0) { derr << "error checking features: " << cpp_strerror(err) << dendl; prefork.exit(1); } // inject new monmap? if (!inject_monmap.empty()) { bufferlist bl; std::string error; int r = bl.read_file(inject_monmap.c_str(), &error); if (r) { derr << "unable to read monmap from " << inject_monmap << ": " << error << dendl; prefork.exit(1); } // get next version version_t v = store->get("monmap", "last_committed"); dout(0) << "last committed monmap epoch is " << v << ", injected map will be " << (v+1) << dendl; v++; // set the version MonMap tmp; tmp.decode(bl); if (tmp.get_epoch() != v) { dout(0) << "changing monmap epoch from " << tmp.get_epoch() << " to " << v << dendl; tmp.set_epoch(v); } bufferlist mapbl; tmp.encode(mapbl, CEPH_FEATURES_ALL); bufferlist final; ::encode(v, final); ::encode(mapbl, final); MonitorDBStore::Transaction t; // save it t.put("monmap", v, mapbl); t.put("monmap", "latest", final); t.put("monmap", "last_committed", v); store->apply_transaction(t); dout(0) << "done." << dendl; prefork.exit(0); } // monmap? MonMap monmap; { // note that even if we don't find a viable monmap, we should go ahead // and try to build it up in the next if-else block. bufferlist mapbl; int err = obtain_monmap(*store, mapbl); if (err >= 0) { try { monmap.decode(mapbl); } catch (const buffer::error& e) { cerr << "can't decode monmap: " << e.what() << std::endl; } } else { derr << "unable to obtain a monmap: " << cpp_strerror(err) << dendl; } if (!extract_monmap.empty()) { int r = mapbl.write_file(extract_monmap.c_str()); if (r < 0) { r = -errno; derr << "error writing monmap to " << extract_monmap << ": " << cpp_strerror(r) << dendl; prefork.exit(1); } derr << "wrote monmap to " << extract_monmap << dendl; prefork.exit(0); } } // this is what i will bind to entity_addr_t ipaddr; if (monmap.contains(g_conf->name.get_id())) { ipaddr = monmap.get_addr(g_conf->name.get_id()); // print helpful warning if the conf file doesn't match entity_addr_t conf_addr; std::vector my_sections; g_conf->get_my_sections(my_sections); std::string mon_addr_str; if (g_conf->get_val_from_conf_file(my_sections, "mon addr", mon_addr_str, true) == 0) { if (conf_addr.parse(mon_addr_str.c_str()) && (ipaddr != conf_addr)) { derr << "WARNING: 'mon addr' config option " << conf_addr << " does not match monmap file" << std::endl << " continuing with monmap configuration" << dendl; } } } else { dout(0) << g_conf->name << " does not exist in monmap, will attempt to join an existing cluster" << dendl; pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC); if (!g_conf->public_addr.is_blank_ip()) { ipaddr = g_conf->public_addr; if (ipaddr.get_port() == 0) ipaddr.set_port(CEPH_MON_PORT); dout(0) << "using public_addr " << g_conf->public_addr << " -> " << ipaddr << dendl; } else { MonMap tmpmap; int err = tmpmap.build_initial(g_ceph_context, cerr); if (err < 0) { derr << argv[0] << ": error generating initial monmap: " << cpp_strerror(err) << dendl; usage(); prefork.exit(1); } if (tmpmap.contains(g_conf->name.get_id())) { ipaddr = tmpmap.get_addr(g_conf->name.get_id()); } else { derr << "no public_addr or public_network specified, and " << g_conf->name << " not present in monmap or ceph.conf" << dendl; prefork.exit(1); } } } // bind int rank = monmap.get_rank(g_conf->name.get_id()); Messenger *messenger = Messenger::create(g_ceph_context, entity_name_t::MON(rank), "mon", 0); messenger->set_cluster_protocol(CEPH_MON_PROTOCOL); messenger->set_default_send_priority(CEPH_MSG_PRIO_HIGH); uint64_t supported = CEPH_FEATURE_UID | CEPH_FEATURE_NOSRCADDR | CEPH_FEATURE_MONCLOCKCHECK | CEPH_FEATURE_PGID64 | CEPH_FEATURE_MSG_AUTH; messenger->set_default_policy(Messenger::Policy::stateless_server(supported, 0)); messenger->set_policy(entity_name_t::TYPE_MON, Messenger::Policy::lossless_peer_reuse(supported, CEPH_FEATURE_UID | CEPH_FEATURE_PGID64 | CEPH_FEATURE_MON_SINGLE_PAXOS)); messenger->set_policy(entity_name_t::TYPE_OSD, Messenger::Policy::stateless_server(supported, CEPH_FEATURE_PGID64 | CEPH_FEATURE_OSDENC)); messenger->set_policy(entity_name_t::TYPE_CLIENT, Messenger::Policy::stateless_server(supported, 0)); messenger->set_policy(entity_name_t::TYPE_MDS, Messenger::Policy::stateless_server(supported, 0)); // throttle client traffic Throttle *client_throttler = new Throttle(g_ceph_context, "mon_client_bytes", g_conf->mon_client_bytes); messenger->set_policy_throttlers(entity_name_t::TYPE_CLIENT, client_throttler, NULL); // throttle daemon traffic // NOTE: actual usage on the leader may multiply by the number of // monitors if they forward large update messages from daemons. Throttle *daemon_throttler = new Throttle(g_ceph_context, "mon_daemon_bytes", g_conf->mon_daemon_bytes); messenger->set_policy_throttlers(entity_name_t::TYPE_OSD, daemon_throttler, NULL); messenger->set_policy_throttlers(entity_name_t::TYPE_MDS, daemon_throttler, NULL); dout(0) << "starting " << g_conf->name << " rank " << rank << " at " << ipaddr << " mon_data " << g_conf->mon_data << " fsid " << monmap.get_fsid() << dendl; err = messenger->bind(ipaddr); if (err < 0) { derr << "unable to bind monitor to " << ipaddr << dendl; prefork.exit(1); } // start monitor mon = new Monitor(g_ceph_context, g_conf->name.get_id(), store, messenger, &monmap); if (force_sync) { derr << "flagging a forced sync ..." << dendl; mon->sync_force(NULL, cerr); } err = mon->preinit(); if (err < 0) { derr << "failed to initialize" << dendl; prefork.exit(1); } if (compact || g_conf->mon_compact_on_start) { derr << "compacting monitor store ..." << dendl; mon->store->compact(); derr << "done compacting" << dendl; } if (g_conf->daemonize) { global_init_postfork_finish(g_ceph_context, 0); prefork.daemonize(); } messenger->start(); mon->init(); // set up signal handlers, now that we've daemonized/forked. init_async_signal_handler(); register_async_signal_handler(SIGHUP, sighup_handler); register_async_signal_handler_oneshot(SIGINT, handle_mon_signal); register_async_signal_handler_oneshot(SIGTERM, handle_mon_signal); if (g_conf->inject_early_sigterm) kill(getpid(), SIGTERM); messenger->wait(); unregister_async_signal_handler(SIGHUP, sighup_handler); unregister_async_signal_handler(SIGINT, handle_mon_signal); unregister_async_signal_handler(SIGTERM, handle_mon_signal); shutdown_async_signal_handler(); delete mon; delete store; delete messenger; delete client_throttler; delete daemon_throttler; g_ceph_context->put(); // cd on exit, so that gmon.out (if any) goes into a separate directory for each node. char s[20]; snprintf(s, sizeof(s), "gmon/%d", getpid()); if ((mkdir(s, 0755) == 0) && (chdir(s) == 0)) { dout(0) << "ceph-mon: gmon.out should be in " << s << dendl; } prefork.signal_exit(0); return 0; } ceph-0.80.11/src/ceph.in0000775000175100017510000007161412623076744016747 0ustar jenkins-buildjenkins-build# -*- mode:python -*- # vim: ts=4 sw=4 smarttab expandtab # # Processed in Makefile to add python #! line and version variable # # """ ceph.in becomes ceph, the command-line management tool for Ceph clusters. This is a replacement for tools/ceph.cc and tools/common.cc. Copyright (C) 2013 Inktank Storage, Inc. This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2, as published by the Free Software Foundation. See file COPYING. """ import os import sys # Make life easier on developers: # If in src/, and .libs and pybind exist here, assume we're running # from a Ceph source dir and tweak PYTHONPATH and LD_LIBRARY_PATH # to use local files MYPATH = os.path.abspath(__file__) MYDIR = os.path.dirname(MYPATH) DEVMODEMSG = '*** DEVELOPER MODE: setting PATH, PYTHONPATH and LD_LIBRARY_PATH ***' if MYDIR.endswith('src') and \ os.path.exists(os.path.join(MYDIR, '.libs')) and \ os.path.exists(os.path.join(MYDIR, 'pybind')): MYLIBPATH = os.path.join(MYDIR, '.libs') if 'LD_LIBRARY_PATH' in os.environ: if MYLIBPATH not in os.environ['LD_LIBRARY_PATH']: os.environ['LD_LIBRARY_PATH'] += ':' + MYLIBPATH print >> sys.stderr, DEVMODEMSG os.execvp('python', ['python'] + sys.argv) else: os.environ['LD_LIBRARY_PATH'] = MYLIBPATH print >> sys.stderr, DEVMODEMSG os.execvp('python', ['python'] + sys.argv) sys.path.insert(0, os.path.join(MYDIR, 'pybind')) if os.environ.has_key('PATH') and MYDIR not in os.environ['PATH']: os.environ['PATH'] += ':' + MYDIR import argparse import errno import json import rados import signal import socket import string import struct import subprocess from ceph_argparse import \ concise_sig, descsort, parse_json_funcsigs, \ matchnum, validate_command, find_cmd_target, \ send_command, json_command # just a couple of globals verbose = False cluster_handle = None ############################################################################ def osdids(): ret, outbuf, outs = json_command(cluster_handle, prefix='osd ls') if ret == -errno.EINVAL: # try old mon ret, outbuf, outs = send_command(cluster_handle, cmd=['osd', 'ls']) if ret: raise RuntimeError('Can\'t contact mon for osd list') return [i for i in outbuf.split('\n') if i != ''] def monids(): ret, outbuf, outs = json_command(cluster_handle, prefix='mon dump', argdict={'format':'json'}) if ret == -errno.EINVAL: # try old mon ret, outbuf, outs = send_command(cluster_handle, cmd=['mon', 'dump', '--format=json']) if ret: raise RuntimeError('Can\'t contact mon for mon list') d = json.loads(outbuf) return [m['name'] for m in d['mons']] def mdsids(): ret, outbuf, outs = json_command(cluster_handle, prefix='mds dump', argdict={'format':'json'}) if ret == -errno.EINVAL: # try old mon ret, outbuf, outs = send_command(cluster_handle, cmd=['mds', 'dump', '--format=json']) if ret: raise RuntimeError('Can\'t contact mon for mds list') d = json.loads(outbuf) l = [] infodict = d['info'] for mdsdict in infodict.values(): l.append(mdsdict['name']) return l # these args must be passed to all child programs GLOBAL_ARGS = { 'client_id': '--id', 'client_name': '--name', 'cluster': '--cluster', 'cephconf': '--conf', } def parse_cmdargs(args=None, target=''): # alias: let the line-wrapping be sane AP = argparse.ArgumentParser # format our own help parser = AP(description='Ceph administration tool', add_help=False) parser.add_argument('--completion', action='store_true', help=argparse.SUPPRESS) parser.add_argument('-h', '--help', help='request mon help', action='store_true') parser.add_argument('-c', '--conf', dest='cephconf', help='ceph configuration file') parser.add_argument('-i', '--in-file', dest='input_file', help='input file') parser.add_argument('-o', '--out-file', dest='output_file', help='output file') parser.add_argument('--id', '--user', dest='client_id', help='client id for authentication') parser.add_argument('--name', '-n', dest='client_name', help='client name for authentication') parser.add_argument('--cluster', help='cluster name') parser.add_argument('--admin-daemon', dest='admin_socket', help='submit admin-socket commands (\"help\" for help') parser.add_argument('--admin-socket', dest='admin_socket_nope', help='you probably mean --admin-daemon') parser.add_argument('-s', '--status', action='store_true', help='show cluster status') parser.add_argument('-w', '--watch', action='store_true', help='watch live cluster changes') parser.add_argument('--watch-debug', action='store_true', help='watch debug events') parser.add_argument('--watch-info', action='store_true', help='watch info events') parser.add_argument('--watch-sec', action='store_true', help='watch security events') parser.add_argument('--watch-warn', action='store_true', help='watch warn events') parser.add_argument('--watch-error', action='store_true', help='watch error events') parser.add_argument('--version', '-v', action="store_true", help="display version") parser.add_argument('--verbose', action="store_true", help="make verbose") parser.add_argument('--concise', dest='verbose', action="store_false", help="make less verbose") parser.add_argument('-f', '--format', choices=['json', 'json-pretty', 'xml', 'xml-pretty', 'plain'], dest='output_format') parser.add_argument('--connect-timeout', dest='cluster_timeout', type=int, help='set a timeout for connecting to the cluster') # returns a Namespace with the parsed args, and a list of all extras parsed_args, extras = parser.parse_known_args(args) return parser, parsed_args, extras def hdr(s): print '\n', s, '\n', '=' * len(s) def do_basic_help(parser, args): """ Print basic parser help If the cluster is available, get and print monitor help """ hdr('General usage:') parser.print_help() def do_extended_help(parser, args): def help_for_sigs(sigs, partial=None): sys.stdout.write(format_help(parse_json_funcsigs(sigs, 'cli'), partial=partial)) def help_for_target(target, partial=None): ret, outbuf, outs = json_command(cluster_handle, target=target, prefix='get_command_descriptions', timeout=10) if ret: print >> sys.stderr, \ "couldn't get command descriptions for {0}: {1}".\ format(target, outs) else: help_for_sigs(outbuf, partial) partial = ' '.join(args) if (cluster_handle.state == "connected"): help_for_target(target=('mon', ''), partial=partial) return 0 DONTSPLIT = string.letters + '{[<>]}' def wrap(s, width, indent): """ generator to transform s into a sequence of strings width or shorter, for wrapping text to a specific column width. Attempt to break on anything but DONTSPLIT characters. indent is amount to indent 2nd-through-nth lines. so "long string long string long string" width=11 indent=1 becomes 'long string', ' long string', ' long string' so that it can be printed as long string long string long string Consumes s. """ result = '' leader = '' while len(s): if (len(s) <= width): # no splitting; just possibly indent result = leader + s s = '' yield result else: splitpos = width while (splitpos > 0) and (s[splitpos-1] in DONTSPLIT): splitpos -= 1 if splitpos == 0: splitpos = width if result: # prior result means we're mid-iteration, indent result = leader else: # first time, set leader and width for next leader = ' ' * indent width -= 1 # for subsequent space additions # remove any leading spaces in this chunk of s result += s[:splitpos].lstrip() s = s[splitpos:] yield result raise StopIteration def format_help(cmddict, partial=None): """ Formats all the cmdsigs and helptexts from cmddict into a sorted-by- cmdsig 2-column display, with each column wrapped and indented to fit into 40 characters. """ fullusage = '' for cmd in sorted(cmddict.itervalues(), cmp=descsort): if not cmd['help']: continue concise = concise_sig(cmd['sig']) if partial and not concise.startswith(partial): continue siglines = [l for l in wrap(concise, 40, 1)] helplines = [l for l in wrap(cmd['help'], 39, 1)] # make lists the same length maxlen = max(len(siglines), len(helplines)) siglines.extend([''] * (maxlen - len(siglines))) helplines.extend([''] * (maxlen - len(helplines))) # so we can zip them for output for (s, h) in zip(siglines, helplines): fullusage += '{0:40s} {1}\n'.format(s, h) return fullusage def admin_socket(asok_path, cmd, format=''): """ Send a daemon (--admin-daemon) command 'cmd'. asok_path is the path to the admin socket; cmd is a list of strings; format may be set to one of the formatted forms to get output in that form (daemon commands don't support 'plain' output). """ def do_sockio(path, cmd): """ helper: do all the actual low-level stream I/O """ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(path) try: sock.sendall(cmd + '\0') len_str = sock.recv(4) if len(len_str) < 4: raise RuntimeError("no data returned from admin socket") l, = struct.unpack(">I", len_str) ret = '' got = 0 while got < l: bit = sock.recv(l - got) ret += bit got += len(bit) except Exception as e: raise RuntimeError('exception: ' + str(e)) return ret try: cmd_json = do_sockio(asok_path, json.dumps({"prefix":"get_command_descriptions"})) except Exception as e: raise RuntimeError('exception getting command descriptions: ' + str(e)) if cmd == 'get_command_descriptions': return cmd_json sigdict = parse_json_funcsigs(cmd_json, 'cli') valid_dict = validate_command(sigdict, cmd) if not valid_dict: raise RuntimeError('invalid command') if format: valid_dict['format'] = format try: ret = do_sockio(asok_path, json.dumps(valid_dict)) except Exception as e: raise RuntimeError('exception: ' + str(e)) return ret def ceph_conf(parsed_args, field, name): args=['ceph-conf'] if name: args.extend(['--name', name]) # add any args in GLOBAL_ARGS for key, val in GLOBAL_ARGS.iteritems(): # ignore name in favor of argument name, if any if name and key == 'client_name': continue if getattr(parsed_args, key): args.extend([val, getattr(parsed_args, key)]) args.extend(['--show-config-value', field]) p = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) outdata, errdata = p.communicate() if (len(errdata)): raise RuntimeError('unable to get conf option %s for %s: %s' % (field, name, errdata)) return outdata.rstrip() def new_style_command(parsed_args, cmdargs, target, sigdict, inbuf, verbose): """ Do new-style command dance. target: daemon to receive command: mon (any) or osd.N sigdict - the parsed output from the new monitor describing commands inbuf - any -i input file data verbose - bool """ if verbose: for cmdtag in sorted(sigdict.keys()): cmd = sigdict[cmdtag] sig = cmd['sig'] print '{0}: {1}'.format(cmdtag, concise_sig(sig)) got_command = False if not got_command: if cmdargs: # Validate input args against list of sigs valid_dict = validate_command(sigdict, cmdargs, verbose) if valid_dict: got_command = True if parsed_args.output_format: valid_dict['format'] = parsed_args.output_format else: return -errno.EINVAL, '', 'invalid command' else: # do the command-interpreter looping # for raw_input to do readline cmd editing import readline while True: interactive_input = raw_input('ceph> ') if interactive_input in ['q', 'quit', 'Q']: return 0, '', '' cmdargs = parse_cmdargs(interactive_input.split())[2] target = find_cmd_target(cmdargs) valid_dict = validate_command(sigdict, cmdargs, verbose) if valid_dict: if parsed_args.output_format: valid_dict['format'] = parsed_args.output_format if verbose: print >> sys.stderr, "Submitting command ", valid_dict ret, outbuf, outs = json_command(cluster_handle, target=target, argdict=valid_dict) if ret: ret = abs(ret) print >> sys.stderr, \ 'Error: {0} {1}'.format(ret, errno.errorcode[ret]) if outbuf: print outbuf if outs: print >> sys.stderr, 'Status:\n', outs else: print >> sys.stderr, "Invalid command" if verbose: print >> sys.stderr, "Submitting command ", valid_dict return json_command(cluster_handle, target=target, argdict=valid_dict, inbuf=inbuf) def complete(sigdict, args, target): """ Command completion. Match as much of [args] as possible, and print every possible match separated by newlines. Return exitcode. """ # XXX this looks a lot like the front of validate_command(). Refactor? complete_verbose = 'COMPVERBOSE' in os.environ # Repulsive hack to handle tell: lop off 'tell' and target # and validate the rest of the command. 'target' is already # determined in our callers, so it's ok to remove it here. if len(args) and args[0] == 'tell': args = args[2:] # look for best match, accumulate possibles in bestcmds # (so we can maybe give a more-useful error message) best_match_cnt = 0 bestcmds = [] for cmdtag, cmd in sigdict.iteritems(): sig = cmd['sig'] matched = matchnum(args, sig, partial=True) if (matched > best_match_cnt): if complete_verbose: print >> sys.stderr, \ "better match: {0} > {1}: {2}:{3} ".format(matched, best_match_cnt, cmdtag, concise_sig(sig)) best_match_cnt = matched bestcmds = [{cmdtag:cmd}] elif matched == best_match_cnt: if complete_verbose: print >> sys.stderr, \ "equal match: {0} > {1}: {2}:{3} ".format(matched, best_match_cnt, cmdtag, concise_sig(sig)) bestcmds.append({cmdtag:cmd}) # look through all matching sigs comps = [] for cmddict in bestcmds: for cmd in cmddict.itervalues(): sig = cmd['sig'] # either: # we match everything fully, so we want the next desc, or # we match more partially, so we want the partial match fullindex = matchnum(args, sig, partial=False) - 1 partindex = matchnum(args, sig, partial=True) - 1 if complete_verbose: print >> sys.stderr, '{}: f {} p {} len {}'.format(sig, fullindex, partindex, len(sig)) if fullindex == partindex and fullindex + 1 < len(sig): d = sig[fullindex + 1] else: d = sig[partindex] comps.append(str(d)) if complete_verbose: print >> sys.stderr, '\n'.join(comps) print '\n'.join(comps) return 0 ### # ping a monitor ### def ping_monitor(cluster_handle, name): if 'mon.' not in name: print >> sys.stderr, '"ping" expects a monitor to ping; try "ping mon."' return 1 mon_id = name[len('mon.'):] s = cluster_handle.ping_monitor(mon_id) print s return 0 ### # main ### def main(): ceph_args = os.environ.get('CEPH_ARGS') if ceph_args: sys.argv.extend(ceph_args.split()) parser, parsed_args, childargs = parse_cmdargs() if parsed_args.version: print 'ceph version {0} ({1})'.format(CEPH_GIT_NICE_VER, CEPH_GIT_VER) return 0 global verbose verbose = parsed_args.verbose if parsed_args.admin_socket_nope: print >> sys.stderr, '--admin-socket is used by daemons; '\ 'you probably mean --admin-daemon/daemon' return 1 # pass on --id, --name, --conf name = 'client.admin' if parsed_args.client_id: name = 'client.' + parsed_args.client_id if parsed_args.client_name: name = parsed_args.client_name # default '' means default conf search conffile = '' if parsed_args.cephconf: conffile = parsed_args.cephconf # For now, --admin-daemon is handled as usual. Try it # first in case we can't connect() to the cluster format = parsed_args.output_format sockpath = None if parsed_args.admin_socket: sockpath = parsed_args.admin_socket elif len(childargs) > 0 and childargs[0] == "daemon": # Treat "daemon " or "daemon " like --admin_daemon if len(childargs) > 2: if childargs[1].find('/') >= 0: sockpath = childargs[1] else: # try resolve daemon name try: sockpath = ceph_conf(parsed_args, 'admin_socket', childargs[1]) except Exception as e: print >> sys.stderr, \ 'Can\'t get admin socket path: ' + str(e) return errno.EINVAL # for both: childargs = childargs[2:] else: print >> sys.stderr, 'daemon requires at least 3 arguments' return errno.EINVAL if sockpath: try: print admin_socket(sockpath, childargs, format) except Exception as e: print >> sys.stderr, 'admin_socket: {0}'.format(e) return errno.EINVAL return 0 timeout = None if parsed_args.cluster_timeout: timeout = parsed_args.cluster_timeout # basic help if parsed_args.help: do_basic_help(parser, childargs) # handle any 'generic' ceph arguments that we didn't parse here global cluster_handle # rados.Rados() will call rados_create2, and then read the conf file, # and then set the keys from the dict. So we must do these # "pre-file defaults" first (see common_preinit in librados) conf_defaults = { 'log_to_stderr':'true', 'err_to_stderr':'true', 'log_flush_on_exit':'true', } clustername = 'ceph' if parsed_args.cluster: clustername = parsed_args.cluster try: cluster_handle = rados.Rados(name=name, clustername=clustername, conf_defaults=conf_defaults, conffile=conffile) retargs = cluster_handle.conf_parse_argv(childargs) except rados.Error as e: print >> sys.stderr, 'Error initializing cluster client: {0}'.\ format(e.__class__.__name__) return 1 #tmp = childargs childargs = retargs if not childargs: childargs = [] # -- means "stop parsing args", but we don't want to see it either if '--' in childargs: childargs.remove('--') # special deprecation warning for 'ceph tell' # someday 'mds' will be here too if len(childargs) >= 2 and \ childargs[0] in ['mon', 'osd'] and \ childargs[1] == 'tell': print >> sys.stderr, '"{0} tell" is deprecated; try "tell {0}." instead (id can be "*") '.format(childargs[0]) return 1 if parsed_args.help: # short default timeout for -h if not timeout: timeout = 5 hdr('Monitor commands:') print '[Contacting monitor, timeout after %d seconds]' % timeout if childargs and childargs[0] == 'ping': if len(childargs) < 2: print >> sys.stderr, '"ping" requires a monitor name as argument: "ping mon."' return 1 try: if childargs and childargs[0] == 'ping': return ping_monitor(cluster_handle, childargs[1]) cluster_handle.connect(timeout=timeout) except KeyboardInterrupt: print >> sys.stderr, 'Cluster connection aborted' return 1 except Exception as e: print >> sys.stderr, 'Error connecting to cluster: {0}'.\ format(e.__class__.__name__) return 1 if parsed_args.help: return do_extended_help(parser, childargs) # implement -w/--watch_* # This is ugly, but Namespace() isn't quite rich enough. level = '' for k, v in parsed_args._get_kwargs(): if k.startswith('watch') and v: if k == 'watch': level = 'info' else: level = k.replace('watch_', '') if level: # an awfully simple callback def watch_cb(arg, line, who, stamp_sec, stamp_nsec, seq, level, msg): print line sys.stdout.flush() # first do a ceph status ret, outbuf, outs = json_command(cluster_handle, prefix='status') if ret == -errno.EINVAL: # try old mon ret, outbuf, outs = send_command(cluster_handle, cmd=['status']) # old mon returns status to outs...ick if ret == 0: outbuf += outs if ret: print >> sys.stderr, "status query failed: ", outs return ret print outbuf # this instance keeps the watch connection alive, but is # otherwise unused logwatch = rados.MonitorLog(cluster_handle, level, watch_cb, 0) # loop forever letting watch_cb print lines try: signal.pause() except KeyboardInterrupt: # or until ^C, at least return 0 # read input file, if any inbuf = '' if parsed_args.input_file: try: with open(parsed_args.input_file, 'r') as f: inbuf = f.read() except Exception as e: print >> sys.stderr, 'Can\'t open input file {0}: {1}'.format(parsed_args.input_file, e) return 1 # prepare output file, if any if parsed_args.output_file: try: outf = open(parsed_args.output_file, 'w') except Exception as e: print >> sys.stderr, \ 'Can\'t open output file {0}: {1}'.\ format(parsed_args.output_file, e) return 1 # -s behaves like a command (ceph status). if parsed_args.status: childargs.insert(0, 'status') target = find_cmd_target(childargs) # Repulsive hack to handle tell: lop off 'tell' and target # and validate the rest of the command. 'target' is already # determined in our callers, so it's ok to remove it here. is_tell = False if len(childargs) and childargs[0] == 'tell': childargs = childargs[2:] is_tell = True if is_tell and not len(childargs): print >> sys.stderr, \ 'Cannot use \'tell\' with interactive mode' return errno.EINVAL # fetch JSON sigs from command # each line contains one command signature (a placeholder name # of the form 'cmdNNN' followed by an array of argument descriptors) # as part of the validated argument JSON object targets = [target] if target[1] == '*': if target[0] == 'osd': targets = [(target[0], o) for o in osdids()] elif target[0] == 'mon': targets = [(target[0], m) for m in monids()] final_ret = 0 for target in targets: # prettify? prefix output with target, if there was a wildcard used prefix = '' suffix = '' if not parsed_args.output_file and len(targets) > 1: prefix = '{0}.{1}: '.format(*target) suffix = '\n' ret, outbuf, outs = json_command(cluster_handle, target=target, prefix='get_command_descriptions') compat = False if ret == -errno.EINVAL: # send command to old monitor or OSD if verbose: print prefix + '{0} to old {1}'.format(' '.join(childargs), target[0]) compat = True if parsed_args.output_format: childargs.extend(['--format', parsed_args.output_format]) ret, outbuf, outs = send_command(cluster_handle, target, childargs, inbuf) if ret == -errno.EINVAL: # did we race with a mon upgrade? try again! ret, outbuf, outs = json_command(cluster_handle, target=target, prefix='get_command_descriptions') if ret == 0: compat = False # yep, carry on if not compat: if ret: if ret < 0: outs = 'problem getting command descriptions from {0}.{1}'.format(*target) else: sigdict = parse_json_funcsigs(outbuf, 'cli') if parsed_args.completion: return complete(sigdict, childargs, target) ret, outbuf, outs = new_style_command(parsed_args, childargs, target, sigdict, inbuf, verbose) # debug tool: send any successful command *again* to # verify that it is idempotent. if not ret and 'CEPH_CLI_TEST_DUP_COMMAND' in os.environ: ret, outbuf, outs = new_style_command(parsed_args, childargs, target, sigdict, inbuf, verbose) if ret < 0: ret = -ret print >> sys.stderr, prefix + 'Second attempt of previously successful command failed with {0}: {1}'.format(errno.errorcode[ret], outs) if ret < 0: ret = -ret print >> sys.stderr, prefix + 'Error {0}: {1}'.format(errno.errorcode[ret], outs) if len(targets) > 1: final_ret = ret else: return ret # this assumes outs never has useful command output, only status if compat: if ret == 0: # old cli/mon would send status string to stdout on non-error print outs else: if outs: print >> sys.stderr, prefix + outs if (parsed_args.output_file): outf.write(outbuf) else: # hack: old code printed status line before many json outputs # (osd dump, etc.) that consumers know to ignore. Add blank line # to satisfy consumers that skip the first line, but not annoy # consumers that don't. if parsed_args.output_format and \ parsed_args.output_format.startswith('json') and \ not compat: sys.stdout.write('\n') # if we are prettifying things, normalize newlines. sigh. if suffix != '': outbuf = outbuf.rstrip() if outbuf != '': sys.stdout.write(prefix + outbuf + suffix) sys.stdout.flush() if (parsed_args.output_file): outf.close() if final_ret: return final_ret return 0 if __name__ == '__main__': retval = main() # shutdown explicitly; Rados() does not if cluster_handle: cluster_handle.shutdown() sys.exit(retval) ceph-0.80.11/src/.git_version0000664000175100017510000000006212623077033020003 0ustar jenkins-buildjenkins-build8424145d49264624a3b0a204aedb127835161070 v0.80.11 ceph-0.80.11/src/erasure-code/0000775000175100017510000000000012623077035020034 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/ErasureCodeInterface.h0000664000175100017510000003477512623076744024255 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #ifndef CEPH_ERASURE_CODE_INTERFACE_H #define CEPH_ERASURE_CODE_INTERFACE_H /*! @file ErasureCodeInterface.h @brief Interface provided by erasure code plugins The erasure coded pools rely on plugins implementing **ErasureCodeInterface** to encode and decode content. All codes are systematic (i.e. the data is not mangled and can be reconstructed by concatenating chunks ). Methods returning an **int** return **0** on success and a negative value on error. If the value returned on error is not explained in **ErasureCodeInterface**, the sources or the documentation of the interface implementer (i.e. the plugin ) must be read to figure out what it means. It is recommended that each error code matches an *errno* value that relates to the cause of the error. If an object is small enough, the caller can process it with one call to the **encode** or **decode** method. +---------------- coded object O -------------------------+ |+----------------+ +----------------+ +----------------+ | || chunk 0 | | chunk 1 | | chunk 2 | | || [0,N) | | [N,2N) | | [2N,3N) | | |+----------------+ +----------------+ +----------------+ | +------^--------------------------------------------------+ | chunk B / C | offset B % C ( where C is the chunk size ) | +-----^---- raw object O ----+------+ | B [0,X) | pad | +----------------------------+------+ The object size is paded so that each chunks are of the same size. In the example above, if the actual object size was X, then it will be padded to 2N >= X assuming there are two data chunks (0 and 1) and one coding chunk (2). For chunks of size C, byte B of the object is found in chunk number B / C at offset B % C. If an object is too large to be encoded in memory, the caller should divide it in smaller units named **stripes**. +---------------------- object O -------------------------+ |+----------------+ +----------------+ +----------------+ | stripe || chunk 0 | | chunk 1 | | chunk 2 | | 0 || [0,N) | | [N,2N) | | [2N,3N) | | |+----------------+ +----------------+ +----------------+ | |+----------------+ +----------------+ +----------------+ | stripe || chunk 0 | | chunk 1 | | chunk 2 | | 1 || [X,M) | | [X+M,X+2M) | | [X+2M,X+3M) | | || | | | | | | |+----------------+ +----------------+ +----------------+ | | ... | +---------------------------------------------------------+ The interface does not concern itself with stripes nor does it impose constraints on the size of each stripe. Variable names in the interface always use **object** and never use **stripe**. Assuming the interface implementer provides three data chunks ( K = 3 ) and two coding chunks ( M = 2 ), a buffer could be encoded as follows: ~~~~~~~~~~~~~~~~{.c} set want_to_encode(0, 1, 2, // data chunks 3, 4 // coding chunks ); bufferlist in = "ABCDEF"; map encoded encode(want_to_encode, in, &encoded); encoded[0] == "AB" // data chunk 0 encoded[1] == "CD" // data chunk 1 encoded[2] == "EF" // data chunk 2 encoded[3] // coding chunk 0 encoded[4] // coding chunk 1 ~~~~~~~~~~~~~~~~ The **minimum_to_decode_with_cost** method can be used to minimize the cost of fetching the chunks necessary to retrieve a given content. For instance, if encoded[2] (contained **EF**) is missing and accessing encoded[3] (the first coding chunk) is more expensive than accessing encoded[4] (the second coding chunk), **minimum_to_decode_with_cost** is expected to chose the first coding chunk. ~~~~~~~~~~~~~~~~{.c} set want_to_read(2); // want the chunk containing "EF" map available( 0 => 1, // data chunk 0 : available and costs 1 1 => 1, // data chunk 1 : available and costs 1 // data chunk 2 : missing 3 => 9, // coding chunk 1 : available and costs 9 4 => 1, // coding chunk 2 : available and costs 1 ); set minimum; minimum_to_decode_with_cost(want_to_read, available, &minimum); minimum == set(0, 1, 4); // NOT set(0, 1, 3); ~~~~~~~~~~~~~~~~ It sets **minimum** with three chunks to reconstruct the desired data chunk and will pick the second coding chunk ( 4 ) because it is less expensive ( 1 < 9 ) to retrieve than the first coding chunk ( 3 ). The caller is responsible for retrieving the chunks and call **decode** to reconstruct the second data chunk. ~~~~~~~~~~~~~~~~{.c} map chunks; for i in minimum.keys(): chunks[i] = fetch_chunk(i); // get chunk from storage map decoded; decode(want_to_read, chunks, &decoded); decoded[2] == "EF" ~~~~~~~~~~~~~~~~ The semantic of the cost value is defined by the caller and must be known to the implementer. For instance, it may be more expensive to retrieve two chunks with cost 1 + 9 = 10 than two chunks with cost 6 + 6 = 12. */ #include #include #include "include/memory.h" #include "include/buffer.h" class CrushWrapper; using namespace std; namespace ceph { class ErasureCodeInterface { public: virtual ~ErasureCodeInterface() {} /** * Create a new ruleset in **crush** under the name **name**, * unless it already exists. * * Return the ruleset number that was created on success. If a * ruleset **name** already exists, return -EEXISTS, otherwise * return a negative value indicating an error with a semantic * defined by the implementation. * * @param [in] name of the ruleset to create * @param [in] crush crushmap in which the ruleset is created * @param [out] ss contains informative messages when an error occurs * @return a ruleset on success or a negative errno on error. */ virtual int create_ruleset(const string &name, CrushWrapper &crush, ostream *ss) const = 0; /** * Return the number of chunks created by a call to the **encode** * method. * * In the simplest case it can be K + M, i.e. the number * of data chunks (K) plus the number of parity chunks * (M). However, if the implementation provides local parity there * could be an additional overhead. * * @return the number of chunks created by encode() */ virtual unsigned int get_chunk_count() const = 0; /** * Return the number of data chunks created by a call to the * **encode** method. The data chunks contain the buffer provided * to **encode**, verbatim, with padding at the end of the last * chunk. * * @return the number of data chunks created by encode() */ virtual unsigned int get_data_chunk_count() const = 0; /** * Return the size (in bytes) of a single chunk created by a call * to the **decode** method. The returned size multiplied by * **get_chunk_count()** is greater or equal to **object_size**. * * If the object size is properly aligned, the chunk size is * **object_size / get_chunk_count()**. However, if * **object_size** is not a multiple of **get_chunk_count** or if * the implementation imposes additional alignment constraints, * the chunk size may be larger. * * The byte found at offset **B** of the original object is mapped * to chunk **B / get_chunk_size()** at offset **B % get_chunk_size()**. * * @param [in] object_size the number of bytes of the object to **encode()** * @return the size (in bytes) of a single chunk created by **encode()** */ virtual unsigned int get_chunk_size(unsigned int object_size) const = 0; /** * Compute the smallest subset of **available** chunks that needs * to be retrieved in order to successfully decode * **want_to_read** chunks. * * It is strictly equivalent to calling * **minimum_to_decode_with_cost** where each **available** chunk * has the same cost. * * @see minimum_to_decode_with_cost * * @param [in] want_to_read chunk indexes to be decoded * @param [in] available chunk indexes containing valid data * @param [out] minimum chunk indexes to retrieve * @return **0** on success or a negative errno on error. */ virtual int minimum_to_decode(const set &want_to_read, const set &available, set *minimum) = 0; /** * Compute the smallest subset of **available** chunks that needs * to be retrieved in order to successfully decode * **want_to_read** chunks. If there are more than one possible * subset, select the subset that minimizes the overall retrieval * cost. * * The **available** parameter maps chunk indexes to their * retrieval cost. The higher the cost value, the more costly it * is to retrieve the chunk content. * * Returns -EIO if there are not enough chunk indexes in * **available** to decode **want_to_read**. * * Returns 0 on success. * * The **minimum** argument must be a pointer to an empty set. * * @param [in] want_to_read chunk indexes to be decoded * @param [in] available map chunk indexes containing valid data * to their retrieval cost * @param [out] minimum chunk indexes to retrieve * @return **0** on success or a negative errno on error. */ virtual int minimum_to_decode_with_cost(const set &want_to_read, const map &available, set *minimum) = 0; /** * Encode the content of **in** and store the result in * **encoded**. All buffers pointed to by **encoded** have the * same size. The **encoded** map contains at least all chunk * indexes found in the **want_to_encode** set. * * The **encoded** map is expected to be a pointer to an empty * map. * * Assuming the **in** parameter is **length** bytes long, * the concatenation of the first **length** bytes of the * **encoded** buffers is equal to the content of the **in** * parameter. * * The **encoded** map may contain more chunks than required by * **want_to_encode** and the caller is expected to permanently * store all of them, not just the chunks listed in * **want_to_encode**. * * The **encoded** map may contain pointers to data stored in * the **in** parameter. If the caller modifies the content of * **in** after calling the encode method, it may have a side * effect on the content of **encoded**. * * The **encoded** map may contain pointers to buffers allocated * by the encode method. They will be freed when **encoded** is * freed. The allocation method is not specified. * * Returns 0 on success. * * @param [in] want_to_encode chunk indexes to be encoded * @param [in] in data to be encoded * @param [out] encoded map chunk indexes to chunk data * @return **0** on success or a negative errno on error. */ virtual int encode(const set &want_to_encode, const bufferlist &in, map *encoded) = 0; /** * Decode the **chunks** and store at least **want_to_read** * chunks in **decoded**. * * The **decoded** map must be a pointer to an empty map. * * There must be enough **chunks** ( as returned by * **minimum_to_decode** or **minimum_to_decode_with_cost** ) to * perform a successful decoding of all chunks listed in * **want_to_read**. * * All buffers pointed by **in** must have the same size. * * On success, the **decoded** map may contain more chunks than * required by **want_to_read** and they can safely be used by the * caller. * * If a chunk is listed in **want_to_read** and there is a * corresponding **bufferlist** in **chunks**, it will be * referenced in **decoded**. If not it will be reconstructed from * the existing chunks. * * Because **decoded** may contain pointers to data found in * **chunks**, modifying the content of **chunks** after calling * decode may have a side effect on the content of **decoded**. * * Returns 0 on success. * * @param [in] want_to_read chunk indexes to be decoded * @param [in] chunks map chunk indexes to chunk data * @param [out] decoded map chunk indexes to chunk data * @return **0** on success or a negative errno on error. */ virtual int decode(const set &want_to_read, const map &chunks, map *decoded) = 0; /** * Decode the first **get_data_chunk_count()** **chunks** and * concatenate them them into **decoded**. * * Returns 0 on success. * * @param [in] chunks map chunk indexes to chunk data * @param [out] decoded concatenante of the data chunks * @return **0** on success or a negative errno on error. */ int decode_concat(const map &chunks, bufferlist *decoded) { set want_to_read; for (unsigned int i = 0; i < get_data_chunk_count(); i++) want_to_read.insert(i); map decoded_map; int r = decode(want_to_read, chunks, &decoded_map); if (r == 0) for (unsigned int i = 0; i < get_data_chunk_count(); i++) decoded->claim_append(decoded_map[i]); return r; } }; typedef ceph::shared_ptr ErasureCodeInterfaceRef; } #endif ceph-0.80.11/src/erasure-code/jerasure/0000775000175100017510000000000012623077035021654 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/ErasureCodeJerasure.cc0000664000175100017510000003475512623076744026111 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include #include #include "common/debug.h" #include "ErasureCodeJerasure.h" #include "crush/CrushWrapper.h" #include "osd/osd_types.h" extern "C" { #include "jerasure.h" #include "reed_sol.h" #include "galois.h" #include "cauchy.h" #include "liberation.h" } // FIXME(loic) this may be too conservative, check back with feedback from Andreas #define LARGEST_VECTOR_WORDSIZE 16 #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout) static ostream& _prefix(std::ostream* _dout) { return *_dout << "ErasureCodeJerasure: "; } int ErasureCodeJerasure::create_ruleset(const string &name, CrushWrapper &crush, ostream *ss) const { int ruleid = crush.add_simple_ruleset(name, ruleset_root, ruleset_failure_domain, "indep", pg_pool_t::TYPE_ERASURE, ss); if (ruleid < 0) return ruleid; else return crush.get_rule_mask_ruleset(ruleid); } void ErasureCodeJerasure::init(const map ¶meters) { dout(10) << "technique=" << technique << dendl; map::const_iterator parameter; parameter = parameters.find("ruleset-root"); if (parameter != parameters.end()) ruleset_root = parameter->second; parameter = parameters.find("ruleset-failure-domain"); if (parameter != parameters.end()) ruleset_failure_domain = parameter->second; parse(parameters); prepare(); } unsigned int ErasureCodeJerasure::get_chunk_size(unsigned int object_size) const { unsigned alignment = get_alignment(); unsigned tail = object_size % alignment; unsigned padded_length = object_size + ( tail ? ( alignment - tail ) : 0 ); assert(padded_length % k == 0); return padded_length / k; } int ErasureCodeJerasure::minimum_to_decode(const set &want_to_read, const set &available_chunks, set *minimum) { if (includes(available_chunks.begin(), available_chunks.end(), want_to_read.begin(), want_to_read.end())) { *minimum = want_to_read; } else { if (available_chunks.size() < (unsigned)k) return -EIO; set::iterator i; unsigned j; for (i = available_chunks.begin(), j = 0; j < (unsigned)k; ++i, j++) minimum->insert(*i); } return 0; } int ErasureCodeJerasure::minimum_to_decode_with_cost(const set &want_to_read, const map &available, set *minimum) { set available_chunks; for (map::const_iterator i = available.begin(); i != available.end(); ++i) available_chunks.insert(i->first); return minimum_to_decode(want_to_read, available_chunks, minimum); } int ErasureCodeJerasure::encode(const set &want_to_encode, const bufferlist &in, map *encoded) { unsigned blocksize = get_chunk_size(in.length()); unsigned padded_length = blocksize * k; dout(10) << "encode adjusted buffer length from " << in.length() << " to " << padded_length << dendl; assert(padded_length % k == 0); bufferlist out(in); if (padded_length - in.length() > 0) { bufferptr pad(padded_length - in.length()); pad.zero(); out.push_back(pad); } unsigned coding_length = blocksize * m; bufferptr coding(buffer::create_page_aligned(coding_length)); out.push_back(coding); out.rebuild_page_aligned(); char *chunks[k + m]; for (int i = 0; i < k + m; i++) { bufferlist &chunk = (*encoded)[i]; chunk.substr_of(out, i * blocksize, blocksize); chunks[i] = chunk.c_str(); } jerasure_encode(&chunks[0], &chunks[k], blocksize); for (int i = 0; i < k + m; i++) { if (want_to_encode.count(i) == 0) encoded->erase(i); } return 0; } int ErasureCodeJerasure::decode(const set &want_to_read, const map &chunks, map *decoded) { vector have; have.reserve(chunks.size()); for (map::const_iterator i = chunks.begin(); i != chunks.end(); ++i) { have.push_back(i->first); } if (includes( have.begin(), have.end(), want_to_read.begin(), want_to_read.end())) { for (set::iterator i = want_to_read.begin(); i != want_to_read.end(); ++i) { (*decoded)[*i] = chunks.find(*i)->second; } return 0; } unsigned blocksize = (*chunks.begin()).second.length(); int erasures[k + m + 1]; int erasures_count = 0; char *data[k]; char *coding[m]; for (int i = 0; i < k + m; i++) { if (chunks.find(i) == chunks.end()) { erasures[erasures_count] = i; erasures_count++; bufferptr ptr(buffer::create_page_aligned(blocksize)); (*decoded)[i].push_front(ptr); } else { (*decoded)[i] = chunks.find(i)->second; (*decoded)[i].rebuild_page_aligned(); } if (i < k) data[i] = (*decoded)[i].c_str(); else coding[i - k] = (*decoded)[i].c_str(); } erasures[erasures_count] = -1; if (erasures_count > 0) return jerasure_decode(erasures, data, coding, blocksize); else return 0; } int ErasureCodeJerasure::to_int(const std::string &name, const map ¶meters, int default_value) { if (parameters.find(name) == parameters.end() || parameters.find(name)->second.size() == 0) { dout(10) << name << " defaults to " << default_value << dendl; return default_value; } const std::string value = parameters.find(name)->second; std::string p = value; std::string err; int r = strict_strtol(p.c_str(), 10, &err); if (!err.empty()) { derr << "could not convert " << name << "=" << value << " to int because " << err << ", set to default " << default_value << dendl; return default_value; } dout(10) << name << " set to " << r << dendl; return r; } bool ErasureCodeJerasure::is_prime(int value) { int prime55[] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71, 73,79,83,89,97,101,103,107,109,113,127,131,137,139,149, 151,157,163,167,173,179, 181,191,193,197,199,211,223,227,229,233,239,241,251,257 }; int i; for (i = 0; i < 55; i++) if (value == prime55[i]) return true; return false; } // // ErasureCodeJerasureReedSolomonVandermonde // void ErasureCodeJerasureReedSolomonVandermonde::jerasure_encode(char **data, char **coding, int blocksize) { jerasure_matrix_encode(k, m, w, matrix, data, coding, blocksize); } int ErasureCodeJerasureReedSolomonVandermonde::jerasure_decode(int *erasures, char **data, char **coding, int blocksize) { return jerasure_matrix_decode(k, m, w, matrix, 1, erasures, data, coding, blocksize); } unsigned ErasureCodeJerasureReedSolomonVandermonde::get_alignment() const { unsigned alignment = k*w*sizeof(int); if ( ((w*sizeof(int))%LARGEST_VECTOR_WORDSIZE) ) alignment = k*w*LARGEST_VECTOR_WORDSIZE; return alignment; } void ErasureCodeJerasureReedSolomonVandermonde::parse(const map ¶meters) { k = to_int("k", parameters, DEFAULT_K); m = to_int("m", parameters, DEFAULT_M); w = to_int("w", parameters, DEFAULT_W); if (w != 8 && w != 16 && w != 32) { derr << "ReedSolomonVandermonde: w=" << w << " must be one of {8, 16, 32} : revert to 8 " << dendl; w = 8; } } void ErasureCodeJerasureReedSolomonVandermonde::prepare() { matrix = reed_sol_vandermonde_coding_matrix(k, m, w); } // // ErasureCodeJerasureReedSolomonRAID6 // void ErasureCodeJerasureReedSolomonRAID6::jerasure_encode(char **data, char **coding, int blocksize) { reed_sol_r6_encode(k, w, data, coding, blocksize); } int ErasureCodeJerasureReedSolomonRAID6::jerasure_decode(int *erasures, char **data, char **coding, int blocksize) { return jerasure_matrix_decode(k, m, w, matrix, 1, erasures, data, coding, blocksize); } unsigned ErasureCodeJerasureReedSolomonRAID6::get_alignment() const { unsigned alignment = k*w*sizeof(int); if ( ((w*sizeof(int))%LARGEST_VECTOR_WORDSIZE) ) alignment = k*w*LARGEST_VECTOR_WORDSIZE; return alignment; } void ErasureCodeJerasureReedSolomonRAID6::parse(const map ¶meters) { k = to_int("k", parameters, DEFAULT_K); m = 2; w = to_int("w", parameters, DEFAULT_W); if (w != 8 && w != 16 && w != 32) { derr << "ReedSolomonRAID6: w=" << w << " must be one of {8, 16, 32} : revert to 8 " << dendl; w = 8; } } void ErasureCodeJerasureReedSolomonRAID6::prepare() { matrix = reed_sol_r6_coding_matrix(k, w); } // // ErasureCodeJerasureCauchy // void ErasureCodeJerasureCauchy::jerasure_encode(char **data, char **coding, int blocksize) { jerasure_schedule_encode(k, m, w, schedule, data, coding, blocksize, packetsize); } int ErasureCodeJerasureCauchy::jerasure_decode(int *erasures, char **data, char **coding, int blocksize) { return jerasure_schedule_decode_lazy(k, m, w, bitmatrix, erasures, data, coding, blocksize, packetsize, 1); } unsigned ErasureCodeJerasureCauchy::get_alignment() const { unsigned alignment = k*w*packetsize*sizeof(int); if ( ((w*packetsize*sizeof(int))%LARGEST_VECTOR_WORDSIZE) ) alignment = k*w*packetsize*LARGEST_VECTOR_WORDSIZE; return alignment; } void ErasureCodeJerasureCauchy::parse(const map ¶meters) { k = to_int("k", parameters, DEFAULT_K); m = to_int("m", parameters, DEFAULT_M); w = to_int("w", parameters, DEFAULT_W); packetsize = to_int("packetsize", parameters, DEFAULT_PACKETSIZE); } void ErasureCodeJerasureCauchy::prepare_schedule(int *matrix) { bitmatrix = jerasure_matrix_to_bitmatrix(k, m, w, matrix); schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix); } // // ErasureCodeJerasureCauchyOrig // void ErasureCodeJerasureCauchyOrig::prepare() { int *matrix = cauchy_original_coding_matrix(k, m, w); prepare_schedule(matrix); free(matrix); } // // ErasureCodeJerasureCauchyGood // void ErasureCodeJerasureCauchyGood::prepare() { int *matrix = cauchy_good_general_coding_matrix(k, m, w); prepare_schedule(matrix); free(matrix); } // // ErasureCodeJerasureLiberation // ErasureCodeJerasureLiberation::~ErasureCodeJerasureLiberation() { if (bitmatrix) free(bitmatrix); if (schedule) jerasure_free_schedule(schedule); } void ErasureCodeJerasureLiberation::jerasure_encode(char **data, char **coding, int blocksize) { jerasure_schedule_encode(k, m, w, schedule, data, coding, blocksize, packetsize); } int ErasureCodeJerasureLiberation::jerasure_decode(int *erasures, char **data, char **coding, int blocksize) { return jerasure_schedule_decode_lazy(k, m, w, bitmatrix, erasures, data, coding, blocksize, packetsize, 1); } unsigned ErasureCodeJerasureLiberation::get_alignment() const { unsigned alignment = k*w*packetsize*sizeof(int); if ( ((w*packetsize*sizeof(int))%LARGEST_VECTOR_WORDSIZE) ) alignment = k*w*packetsize*LARGEST_VECTOR_WORDSIZE; return alignment; } void ErasureCodeJerasureLiberation::parse(const map ¶meters) { k = to_int("k", parameters, DEFAULT_K); m = to_int("m", parameters, DEFAULT_M); w = to_int("w", parameters, DEFAULT_W); packetsize = to_int("packetsize", parameters, DEFAULT_PACKETSIZE); bool error = false; if (k > w) { derr << "k=" << k << " must be less than or equal to w=" << w << dendl; error = true; } if (w <= 2 || !is_prime(w)) { derr << "w=" << w << " must be greater than two and be prime" << dendl; error = true; } if (packetsize == 0) { derr << "packetsize=" << packetsize << " must be set" << dendl; error = true; } if ((packetsize%(sizeof(int))) != 0) { derr << "packetsize=" << packetsize << " must be a multiple of sizeof(int) = " << sizeof(int) << dendl; error = true; } if (error) { derr << "reverting to k=" << DEFAULT_K << ", w=" << DEFAULT_W << ", packetsize=" << DEFAULT_PACKETSIZE << dendl; k = DEFAULT_K; w = DEFAULT_W; packetsize = DEFAULT_PACKETSIZE; } } void ErasureCodeJerasureLiberation::prepare() { bitmatrix = liberation_coding_bitmatrix(k, w); schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix); } // // ErasureCodeJerasureBlaumRoth // void ErasureCodeJerasureBlaumRoth::prepare() { bitmatrix = blaum_roth_coding_bitmatrix(k, w); schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix); } // // ErasureCodeJerasureLiber8tion // void ErasureCodeJerasureLiber8tion::parse(const map ¶meters) { k = to_int("k", parameters, DEFAULT_K); m = DEFAULT_M; w = DEFAULT_W; packetsize = to_int("packetsize", parameters, DEFAULT_PACKETSIZE); bool error = false; if (k > w) { derr << "k=" << k << " must be less than or equal to w=" << w << dendl; error = true; } if (packetsize == 0) { derr << "packetsize=" << packetsize << " must be set" << dendl; error = true; } if (error) { derr << "reverting to k=" << DEFAULT_K << ", packetsize=" << DEFAULT_PACKETSIZE << dendl; k = DEFAULT_K; packetsize = DEFAULT_PACKETSIZE; } } void ErasureCodeJerasureLiber8tion::prepare() { bitmatrix = liber8tion_coding_bitmatrix(k); schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix); } ceph-0.80.11/src/erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc0000664000175100017510000000426312623076744030417 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include "common/debug.h" #include "arch/probe.h" #include "arch/intel.h" #include "erasure-code/ErasureCodePlugin.h" #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout) static ostream& _prefix(std::ostream* _dout) { return *_dout << "ErasureCodePluginSelectJerasure: "; } class ErasureCodePluginSelectJerasure : public ErasureCodePlugin { public: virtual int factory(const map ¶meters, ErasureCodeInterfaceRef *erasure_code) { ErasureCodePluginRegistry &instance = ErasureCodePluginRegistry::instance(); stringstream ss; int ret; ceph_arch_probe(); string name = "jerasure"; if (parameters.count("jerasure-name")) name = parameters.find("jerasure-name")->second; if (ceph_arch_intel_pclmul && ceph_arch_intel_sse42 && ceph_arch_intel_sse41 && ceph_arch_intel_ssse3 && ceph_arch_intel_sse3 && ceph_arch_intel_sse2) { dout(10) << "SSE4 plugin" << dendl; ret = instance.factory(name + "_sse4", parameters, erasure_code, ss); } else if (ceph_arch_intel_ssse3 && ceph_arch_intel_sse3 && ceph_arch_intel_sse2) { dout(10) << "SSE3 plugin" << dendl; ret = instance.factory(name + "_sse3", parameters, erasure_code, ss); } else { dout(10) << "generic plugin" << dendl; ret = instance.factory(name + "_generic", parameters, erasure_code, ss); } if (ret) derr << ss.str() << dendl; return ret; } }; int __erasure_code_init(char *plugin_name) { ErasureCodePluginRegistry &instance = ErasureCodePluginRegistry::instance(); return instance.add(plugin_name, new ErasureCodePluginSelectJerasure()); } ceph-0.80.11/src/erasure-code/jerasure/jerasure/0000775000175100017510000000000012623077033023472 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/jerasure/include/0000775000175100017510000000000012623077034025116 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/jerasure/include/galois.h0000664000175100017510000001110112623076752026545 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2013, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ #ifndef _GALOIS_H #define _GALOIS_H #include #include #include extern void galois_change_technique(gf_t *gf, int w); extern int galois_single_multiply(int a, int b, int w); extern int galois_single_divide(int a, int b, int w); extern int galois_inverse(int x, int w); void galois_region_xor( char *src, /* Source Region */ char *dest, /* Dest Region (holds result) */ int nbytes); /* Number of bytes in region */ /* These multiply regions in w=8, w=16 and w=32. They are much faster than calling galois_single_multiply. The regions must be long word aligned. */ void galois_w08_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here. Otherwise region is overwritten */ int add); /* If (r2 != NULL && add) the produce is XOR'd with r2 */ void galois_w16_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here. Otherwise region is overwritten */ int add); /* If (r2 != NULL && add) the produce is XOR'd with r2 */ void galois_w32_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here. Otherwise region is overwritten */ int add); /* If (r2 != NULL && add) the produce is XOR'd with r2 */ gf_t* galois_init_field(int w, int mult_type, int region_type, int divide_type, uint64_t prim_poly, int arg1, int arg2); gf_t* galois_init_composite_field(int w, int region_type, int divide_type, int degree, gf_t* base_gf); gf_t * galois_get_field_ptr(int w); #endif ceph-0.80.11/src/erasure-code/jerasure/jerasure/include/jerasure.h0000664000175100017510000003045312623076752027122 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2013, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ #ifndef _JERASURE_H #define _JERASURE_H /* This uses procedures from the Galois Field arithmetic library */ #include "galois.h" /* ------------------------------------------------------------ */ /* In all of the routines below: k = Number of data devices m = Number of coding devices w = Word size data_ptrs = An array of k pointers to data which is size bytes. Size must be a multiple of sizeof(long). Pointers must also be longword aligned. coding_ptrs = An array of m pointers to coding data which is size bytes. packetsize = The size of a coding block with bitmatrix coding. When you code with a bitmatrix, you will use w packets of size packetsize. matrix = an array of k*m integers. It represents an m by k matrix. Element i,j is in matrix[i*k+j]; bitmatrix = an array of k*m*w*w integers. It represents an mw by kw matrix. Element i,j is in matrix[i*k*w+j]; erasures = an array of id's of erased devices. Id's are integers between 0 and k+m-1. Id's 0 to k-1 are id's of data devices. Id's k to k+m-1 are id's of coding devices: Coding device id = id-k. If there are e erasures, erasures[e] = -1. schedule = an array of schedule operations. If there are m operations, then schedule[m][0] = -1. operation = an array of 5 integers: 0 = operation: 0 for copy, 1 for xor (-1 for end) 1 = source device (0 - k+m-1) 2 = source packet (0 - w-1) 3 = destination device (0 - k+m-1) 4 = destination packet (0 - w-1) */ /* --------------------------------------------------------------- */ /* Bitmatrices / schedules ---------------------------------------- */ /* - jerasure_matrix_to_bitmatrix turns a m X k matrix in GF(2^w) into a wm X wk bitmatrix (in GF(2)). This is explained in the Cauchy Reed-Solomon coding paper. - jerasure_dumb_bitmatrix_to_schedule turns a bitmatrix into a schedule using the straightforward algorithm -- just schedule the dot products defined by each row of the matrix. - jerasure_smart_bitmatrix_to_schedule turns a bitmatrix into a schedule, but tries to use previous dot products to calculate new ones. This is the optimization explained in the original Liberation code paper. - jerasure_generate_schedule_cache precalcalculate all the schedule for the given distribution bitmatrix. M must equal 2. - jerasure_free_schedule frees a schedule that was allocated with jerasure_XXX_bitmatrix_to_schedule. - jerasure_free_schedule_cache frees a schedule cache that was created with jerasure_generate_schedule_cache. */ int *jerasure_matrix_to_bitmatrix(int k, int m, int w, int *matrix); int **jerasure_dumb_bitmatrix_to_schedule(int k, int m, int w, int *bitmatrix); int **jerasure_smart_bitmatrix_to_schedule(int k, int m, int w, int *bitmatrix); int ***jerasure_generate_schedule_cache(int k, int m, int w, int *bitmatrix, int smart); void jerasure_free_schedule(int **schedule); void jerasure_free_schedule_cache(int k, int m, int ***cache); /* ------------------------------------------------------------ */ /* Encoding - these are all straightforward. jerasure_matrix_encode only works with w = 8|16|32. */ void jerasure_do_parity(int k, char **data_ptrs, char *parity_ptr, int size); void jerasure_matrix_encode(int k, int m, int w, int *matrix, char **data_ptrs, char **coding_ptrs, int size); void jerasure_bitmatrix_encode(int k, int m, int w, int *bitmatrix, char **data_ptrs, char **coding_ptrs, int size, int packetsize); void jerasure_schedule_encode(int k, int m, int w, int **schedule, char **data_ptrs, char **coding_ptrs, int size, int packetsize); /* ------------------------------------------------------------ */ /* Decoding. -------------------------------------------------- */ /* These return integers, because the matrix may not be invertible. The parameter row_k_ones should be set to 1 if row k of the matrix (or rows kw to (k+1)w+1) of th distribution matrix are all ones (or all identity matrices). Then you can improve the performance of decoding when there is more than one failure, and the parity device didn't fail. You do it by decoding all but one of the data devices, and then decoding the last data device from the data devices and the parity device. jerasure_schedule_decode_lazy generates the schedule on the fly. jerasure_matrix_decode only works when w = 8|16|32. jerasure_make_decoding_matrix/bitmatrix make the k*k decoding matrix (or wk*wk bitmatrix) by taking the rows corresponding to k non-erased devices of the distribution matrix, and then inverting that matrix. You should already have allocated the decoding matrix and dm_ids, which is a vector of k integers. These will be filled in appropriately. dm_ids[i] is the id of element i of the survivors vector. I.e. row i of the decoding matrix times dm_ids equals data drive i. Both of these routines take "erased" instead of "erasures". Erased is a vector with k+m elements, which has 0 or 1 for each device's id, according to whether the device is erased. jerasure_erasures_to_erased allocates and returns erased from erasures. */ int jerasure_matrix_decode(int k, int m, int w, int *matrix, int row_k_ones, int *erasures, char **data_ptrs, char **coding_ptrs, int size); int jerasure_bitmatrix_decode(int k, int m, int w, int *bitmatrix, int row_k_ones, int *erasures, char **data_ptrs, char **coding_ptrs, int size, int packetsize); int jerasure_schedule_decode_lazy(int k, int m, int w, int *bitmatrix, int *erasures, char **data_ptrs, char **coding_ptrs, int size, int packetsize, int smart); int jerasure_schedule_decode_cache(int k, int m, int w, int ***scache, int *erasures, char **data_ptrs, char **coding_ptrs, int size, int packetsize); int jerasure_make_decoding_matrix(int k, int m, int w, int *matrix, int *erased, int *decoding_matrix, int *dm_ids); int jerasure_make_decoding_bitmatrix(int k, int m, int w, int *matrix, int *erased, int *decoding_matrix, int *dm_ids); int *jerasure_erasures_to_erased(int k, int m, int *erasures); /* ------------------------------------------------------------ */ /* These perform dot products and schedules. -------------------*/ /* src_ids is a matrix of k id's (0 - k-1 for data devices, k - k+m-1 for coding devices) that identify the source devices. Dest_id is the id of the destination device. jerasure_matrix_dotprod only works when w = 8|16|32. jerasure_do_scheduled_operations executes the schedule on w*packetsize worth of bytes from each device. ptrs is an array of pointers which should have as many elements as the highest referenced device in the schedule. */ void jerasure_matrix_dotprod(int k, int w, int *matrix_row, int *src_ids, int dest_id, char **data_ptrs, char **coding_ptrs, int size); void jerasure_bitmatrix_dotprod(int k, int w, int *bitmatrix_row, int *src_ids, int dest_id, char **data_ptrs, char **coding_ptrs, int size, int packetsize); void jerasure_do_scheduled_operations(char **ptrs, int **schedule, int packetsize); /* ------------------------------------------------------------ */ /* Matrix Inversion ------------------------------------------- */ /* The two matrix inversion functions work on rows*rows matrices of ints. If a bitmatrix, then each int will just be zero or one. Otherwise, they will be elements of gf(2^w). Obviously, you can do bit matrices with crs_invert_matrix() and set w = 1, but crs_invert_bitmatrix will be more efficient. The two invertible functions return whether a matrix is invertible. They are more efficient than the inverstion functions. Mat will be destroyed when the matrix inversion or invertible testing is done. Sorry. Inv must be allocated by the caller. The two invert_matrix functions return 0 on success, and -1 if the matrix is uninvertible. The two invertible function simply return whether the matrix is invertible. (0 or 1). Mat will be destroyed. */ int jerasure_invert_matrix(int *mat, int *inv, int rows, int w); int jerasure_invert_bitmatrix(int *mat, int *inv, int rows); int jerasure_invertible_matrix(int *mat, int rows, int w); int jerasure_invertible_bitmatrix(int *mat, int rows); /* ------------------------------------------------------------ */ /* Basic matrix operations -------------------------------------*/ /* Each of the print_matrix routines require a w. In jerasure_print_matrix, this is to calculate the field width. In jerasure_print_bitmatrix, it is to put spaces between the bits. jerasure_matrix_multiply is a simple matrix multiplier in GF(2^w). It returns a r1*c2 matrix, which is the product of the two input matrices. It allocates the product. Obviously, c1 should equal r2. However, this is not validated by the procedure. */ void jerasure_print_matrix(int *matrix, int rows, int cols, int w); void jerasure_print_bitmatrix(int *matrix, int rows, int cols, int w); int *jerasure_matrix_multiply(int *m1, int *m2, int r1, int c1, int r2, int c2, int w); /* ------------------------------------------------------------ */ /* Stats ------------------------------------------------------ */ /* jerasure_get_stats fills in a vector of three doubles: fill_in[0] is the number of bytes that have been XOR'd fill_in[1] is the number of bytes that have been copied fill_in[2] is the number of bytes that have been multiplied by a constant in GF(2^w) When jerasure_get_stats() is called, it resets its values. */ void jerasure_get_stats(double *fill_in); int jerasure_autoconf_test(); #endif ceph-0.80.11/src/erasure-code/jerasure/jerasure/include/liberation.h0000664000175100017510000000367712623076752027442 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2013, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ #ifndef _LIBERATION extern int *liberation_coding_bitmatrix(int k, int w); extern int *liber8tion_coding_bitmatrix(int k); extern int *blaum_roth_coding_bitmatrix(int k, int w); #endif ceph-0.80.11/src/erasure-code/jerasure/jerasure/include/reed_sol.h0000664000175100017510000000454012623076752027074 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2013, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ extern int *reed_sol_vandermonde_coding_matrix(int k, int m, int w); extern int *reed_sol_extended_vandermonde_matrix(int rows, int cols, int w); extern int *reed_sol_big_vandermonde_distribution_matrix(int rows, int cols, int w); extern int reed_sol_r6_encode(int k, int w, char **data_ptrs, char **coding_ptrs, int size); extern int *reed_sol_r6_coding_matrix(int k, int w); extern void reed_sol_galois_w08_region_multby_2(char *region, int nbytes); extern void reed_sol_galois_w16_region_multby_2(char *region, int nbytes); extern void reed_sol_galois_w32_region_multby_2(char *region, int nbytes); ceph-0.80.11/src/erasure-code/jerasure/jerasure/include/cauchy.h0000664000175100017510000000410612623076752026552 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2013, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ extern int *cauchy_original_coding_matrix(int k, int m, int w); extern int *cauchy_xy_coding_matrix(int k, int m, int w, int *x, int *y); extern void cauchy_improve_coding_matrix(int k, int m, int w, int *matrix); extern int *cauchy_good_general_coding_matrix(int k, int m, int w); extern int cauchy_n_ones(int n, int w); ceph-0.80.11/src/erasure-code/jerasure/jerasure/src/0000775000175100017510000000000012623077035024263 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/jerasure/src/reed_sol.c0000664000175100017510000002120312623076752026226 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2014, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ /* Jerasure's authors: Revision 2.x - 2014: James S. Plank and Kevin M. Greenan Revision 1.2 - 2008: James S. Plank, Scott Simmerman and Catherine D. Schuman. Revision 1.0 - 2007: James S. Plank */ #include #include #include #include #include "galois.h" #include "jerasure.h" #include "reed_sol.h" #define talloc(type, num) (type *) malloc(sizeof(type)*(num)) int *reed_sol_r6_coding_matrix(int k, int w) { int *matrix; int i, tmp; if (w != 8 && w != 16 && w != 32) return NULL; matrix = talloc(int, 2*k); if (matrix == NULL) return NULL; for (i = 0; i < k; i++) matrix[i] = 1; matrix[k] = 1; tmp = 1; for (i = 1; i < k; i++) { tmp = galois_single_multiply(tmp, 2, w); matrix[k+i] = tmp; } return matrix; } int *reed_sol_vandermonde_coding_matrix(int k, int m, int w) { int i, j; int *vdm, *dist; vdm = reed_sol_big_vandermonde_distribution_matrix(k+m, k, w); if (vdm == NULL) return NULL; dist = talloc(int, m*k); if (dist == NULL) { free(vdm); return NULL; } i = k*k; for (j = 0; j < m*k; j++) { dist[j] = vdm[i]; i++; } free(vdm); return dist; } static int prim08 = -1; static gf_t GF08; void reed_sol_galois_w08_region_multby_2(char *region, int nbytes) { if (prim08 == -1) { prim08 = galois_single_multiply((1 << 7), 2, 8); if (!gf_init_hard(&GF08, 8, GF_MULT_BYTWO_b, GF_REGION_DEFAULT, GF_DIVIDE_DEFAULT, prim08, 0, 0, NULL, NULL)) { fprintf(stderr, "Error: Can't initialize the GF for reed_sol_galois_w08_region_multby_2\n"); exit(1); } } GF08.multiply_region.w32(&GF08, region, region, 2, nbytes, 0); } static int prim16 = -1; static gf_t GF16; void reed_sol_galois_w16_region_multby_2(char *region, int nbytes) { if (prim16 == -1) { prim16 = galois_single_multiply((1 << 15), 2, 16); if (!gf_init_hard(&GF16, 16, GF_MULT_BYTWO_b, GF_REGION_DEFAULT, GF_DIVIDE_DEFAULT, prim16, 0, 0, NULL, NULL)) { fprintf(stderr, "Error: Can't initialize the GF for reed_sol_galois_w16_region_multby_2\n"); exit(1); } } GF16.multiply_region.w32(&GF16, region, region, 2, nbytes, 0); } static int prim32 = -1; static gf_t GF32; void reed_sol_galois_w32_region_multby_2(char *region, int nbytes) { if (prim32 == -1) { prim32 = galois_single_multiply((1 << 31), 2, 32); if (!gf_init_hard(&GF32, 32, GF_MULT_BYTWO_b, GF_REGION_DEFAULT, GF_DIVIDE_DEFAULT, prim32, 0, 0, NULL, NULL)) { fprintf(stderr, "Error: Can't initialize the GF for reed_sol_galois_w32_region_multby_2\n"); exit(1); } } GF32.multiply_region.w32(&GF32, region, region, 2, nbytes, 0); } int reed_sol_r6_encode(int k, int w, char **data_ptrs, char **coding_ptrs, int size) { int i; /* First, put the XOR into coding region 0 */ memcpy(coding_ptrs[0], data_ptrs[0], size); for (i = 1; i < k; i++) galois_region_xor(data_ptrs[i], coding_ptrs[0], size); /* Next, put the sum of (2^j)*Dj into coding region 1 */ memcpy(coding_ptrs[1], data_ptrs[k-1], size); for (i = k-2; i >= 0; i--) { switch (w) { case 8: reed_sol_galois_w08_region_multby_2(coding_ptrs[1], size); break; case 16: reed_sol_galois_w16_region_multby_2(coding_ptrs[1], size); break; case 32: reed_sol_galois_w32_region_multby_2(coding_ptrs[1], size); break; default: return 0; } galois_region_xor(data_ptrs[i], coding_ptrs[1], size); } return 1; } int *reed_sol_extended_vandermonde_matrix(int rows, int cols, int w) { int *vdm; int i, j, k; if (w < 30 && (1 << w) < rows) return NULL; if (w < 30 && (1 << w) < cols) return NULL; vdm = talloc(int, rows*cols); if (vdm == NULL) { return NULL; } vdm[0] = 1; for (j = 1; j < cols; j++) vdm[j] = 0; if (rows == 1) return vdm; i=(rows-1)*cols; for (j = 0; j < cols-1; j++) vdm[i+j] = 0; vdm[i+j] = 1; if (rows == 2) return vdm; for (i = 1; i < rows-1; i++) { k = 1; for (j = 0; j < cols; j++) { vdm[i*cols+j] = k; k = galois_single_multiply(k, i, w); } } return vdm; } int *reed_sol_big_vandermonde_distribution_matrix(int rows, int cols, int w) { int *dist; int i, j, k; int sindex, srindex, siindex, tmp; if (cols >= rows) return NULL; dist = reed_sol_extended_vandermonde_matrix(rows, cols, w); if (dist == NULL) return NULL; sindex = 0; for (i = 1; i < cols; i++) { sindex += cols; /* Find an appropriate row -- where i,i != 0 */ srindex = sindex+i; for (j = i; j < rows && dist[srindex] == 0; j++) srindex += cols; if (j >= rows) { /* This should never happen if rows/w are correct */ fprintf(stderr, "reed_sol_big_vandermonde_distribution_matrix(%d,%d,%d) - couldn't make matrix\n", rows, cols, w); exit(1); } /* If necessary, swap rows */ if (j != i) { srindex -= i; for (k = 0; k < cols; k++) { tmp = dist[srindex+k]; dist[srindex+k] = dist[sindex+k]; dist[sindex+k] = tmp; } } /* If Element i,i is not equal to 1, multiply the column by 1/i */ if (dist[sindex+i] != 1) { tmp = galois_single_divide(1, dist[sindex+i], w); srindex = i; for (j = 0; j < rows; j++) { dist[srindex] = galois_single_multiply(tmp, dist[srindex], w); srindex += cols; } } /* Now, for each element in row i that is not in column 1, you need to make it zero. Suppose that this is column j, and the element at i,j = e. Then you want to replace all of column j with (col-j + col-i*e). Note, that in row i, col-i = 1 and col-j = e. So (e + 1e) = 0, which is indeed what we want. */ for (j = 0; j < cols; j++) { tmp = dist[sindex+j]; if (j != i && tmp != 0) { srindex = j; siindex = i; for (k = 0; k < rows; k++) { dist[srindex] = dist[srindex] ^ galois_single_multiply(tmp, dist[siindex], w); srindex += cols; siindex += cols; } } } } /* We desire to have row k be all ones. To do that, multiply the entire column j by 1/dist[k,j]. Then row j by 1/dist[j,j]. */ sindex = cols*cols; for (j = 0; j < cols; j++) { tmp = dist[sindex]; if (tmp != 1) { tmp = galois_single_divide(1, tmp, w); srindex = sindex; for (i = cols; i < rows; i++) { dist[srindex] = galois_single_multiply(tmp, dist[srindex], w); srindex += cols; } } sindex++; } /* Finally, we'd like the first column of each row to be all ones. To do that, we multiply the row by the inverse of the first element. */ sindex = cols*(cols+1); for (i = cols+1; i < rows; i++) { tmp = dist[sindex]; if (tmp != 1) { tmp = galois_single_divide(1, tmp, w); for (j = 0; j < cols; j++) dist[sindex+j] = galois_single_multiply(dist[sindex+j], tmp, w); } sindex += cols; } return dist; } ceph-0.80.11/src/erasure-code/jerasure/jerasure/src/galois.c0000664000175100017510000002316712623076752025723 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2014, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ /* Jerasure's authors: Revision 2.x - 2014: James S. Plank and Kevin M. Greenan Revision 1.2 - 2008: James S. Plank, Scott Simmerman and Catherine D. Schuman. Revision 1.0 - 2007: James S. Plank */ #include #include #include #include "galois.h" #define MAX_GF_INSTANCES 64 gf_t *gfp_array[MAX_GF_INSTANCES] = { 0 }; int gfp_is_composite[MAX_GF_INSTANCES] = { 0 }; gf_t *galois_get_field_ptr(int w) { if (gfp_array[w] != NULL) { return gfp_array[w]; } return NULL; } gf_t* galois_init_field(int w, int mult_type, int region_type, int divide_type, uint64_t prim_poly, int arg1, int arg2) { int scratch_size; void *scratch_memory; gf_t *gfp; if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); exit(1); } gfp = (gf_t *) malloc(sizeof(gf_t)); if (!gfp) { fprintf(stderr, "ERROR -- cannot allocate memory for Galois field w=%d\n", w); exit(1); } scratch_size = gf_scratch_size(w, mult_type, region_type, divide_type, arg1, arg2); if (!scratch_size) { fprintf(stderr, "ERROR -- cannot get scratch size for base field w=%d\n", w); exit(1); } scratch_memory = malloc(scratch_size); if (!scratch_memory) { fprintf(stderr, "ERROR -- cannot get scratch memory for base field w=%d\n", w); exit(1); } if(!gf_init_hard(gfp, w, mult_type, region_type, divide_type, prim_poly, arg1, arg2, NULL, scratch_memory)) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); exit(1); } gfp_is_composite[w] = 0; return gfp; } gf_t* galois_init_composite_field(int w, int region_type, int divide_type, int degree, gf_t* base_gf) { int scratch_size; void *scratch_memory; gf_t *gfp; if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot init composite field for w=%d\n", w); exit(1); } gfp = (gf_t *) malloc(sizeof(gf_t)); if (!gfp) { fprintf(stderr, "ERROR -- cannot allocate memory for Galois field w=%d\n", w); exit(1); } scratch_size = gf_scratch_size(w, GF_MULT_COMPOSITE, region_type, divide_type, degree, 0); if (!scratch_size) { fprintf(stderr, "ERROR -- cannot get scratch size for composite field w=%d\n", w); exit(1); } scratch_memory = malloc(scratch_size); if (!scratch_memory) { fprintf(stderr, "ERROR -- cannot get scratch memory for composite field w=%d\n", w); exit(1); } if(!gf_init_hard(gfp, w, GF_MULT_COMPOSITE, region_type, divide_type, 0, degree, 0, base_gf, scratch_memory)) { fprintf(stderr, "ERROR -- cannot init default composite field for w=%d\n", w); exit(1); } gfp_is_composite[w] = 1; return gfp; } static void galois_init_default_field(int w) { if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); exit(1); } if (gfp_array[w] == NULL) { gfp_array[w] = (gf_t*)malloc(sizeof(gf_t)); if (gfp_array[w] == NULL) { fprintf(stderr, "ERROR -- cannot allocate memory for Galois field w=%d\n", w); exit(1); } } if (!gf_init_easy(gfp_array[w], w)) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); exit(1); } } static int is_valid_gf(gf_t *gf, int w) { // TODO: I assume we may eventually // want to do w=64 and 128, so w // will be needed to perform this check (void)w; if (gf == NULL) { return 0; } if (gf->multiply.w32 == NULL) { return 0; } if (gf->multiply_region.w32 == NULL) { return 0; } if (gf->divide.w32 == NULL) { return 0; } if (gf->inverse.w32 == NULL) { return 0; } if (gf->extract_word.w32 == NULL) { return 0; } return 1; } void galois_change_technique(gf_t *gf, int w) { if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot support Galois field for w=%d\n", w); exit(1); } if (!is_valid_gf(gf, w)) { fprintf(stderr, "ERROR -- overriding with invalid Galois field for w=%d\n", w); exit(1); } if (gfp_array[w] != NULL) { gf_free(gfp_array[w], gfp_is_composite[w]); } gfp_array[w] = gf; } int galois_single_multiply(int x, int y, int w) { if (x == 0 || y == 0) return 0; if (gfp_array[w] == NULL) { galois_init_default_field(w); } if (w <= 32) { return gfp_array[w]->multiply.w32(gfp_array[w], x, y); } else { fprintf(stderr, "ERROR -- Galois field not implemented for w=%d\n", w); return 0; } } int galois_single_divide(int x, int y, int w) { if (x == 0) return 0; if (y == 0) return -1; if (gfp_array[w] == NULL) { galois_init_default_field(w); } if (w <= 32) { return gfp_array[w]->divide.w32(gfp_array[w], x, y); } else { fprintf(stderr, "ERROR -- Galois field not implemented for w=%d\n", w); return 0; } } void galois_w08_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here */ int add) { if (gfp_array[8] == NULL) { galois_init_default_field(8); } gfp_array[8]->multiply_region.w32(gfp_array[8], region, r2, multby, nbytes, add); } void galois_w16_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here */ int add) { if (gfp_array[16] == NULL) { galois_init_default_field(16); } gfp_array[16]->multiply_region.w32(gfp_array[16], region, r2, multby, nbytes, add); } void galois_w32_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here */ int add) { if (gfp_array[32] == NULL) { galois_init_default_field(32); } gfp_array[32]->multiply_region.w32(gfp_array[32], region, r2, multby, nbytes, add); } void galois_w8_region_xor(void *src, void *dest, int nbytes) { if (gfp_array[8] == NULL) { galois_init_default_field(8); } gfp_array[8]->multiply_region.w32(gfp_array[32], src, dest, 1, nbytes, 1); } void galois_w16_region_xor(void *src, void *dest, int nbytes) { if (gfp_array[16] == NULL) { galois_init_default_field(16); } gfp_array[16]->multiply_region.w32(gfp_array[16], src, dest, 1, nbytes, 1); } void galois_w32_region_xor(void *src, void *dest, int nbytes) { if (gfp_array[32] == NULL) { galois_init_default_field(32); } gfp_array[32]->multiply_region.w32(gfp_array[32], src, dest, 1, nbytes, 1); } void galois_region_xor(char *src, char *dest, int nbytes) { if (nbytes >= 16) { galois_w32_region_xor(src, dest, nbytes); } else { int i = 0; for (i = 0; i < nbytes; i++) { *dest ^= *src; dest++; src++; } } } int galois_inverse(int y, int w) { if (y == 0) return -1; return galois_single_divide(1, y, w); } ceph-0.80.11/src/erasure-code/jerasure/jerasure/src/cauchy.c0000664000175100017510000005530712623076752025722 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2014, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ /* Jerasure's authors: Revision 2.x - 2014: James S. Plank and Kevin M. Greenan Revision 1.2 - 2008: James S. Plank, Scott Simmerman and Catherine D. Schuman. Revision 1.0 - 2007: James S. Plank */ #include #include #include #include "galois.h" #include "jerasure.h" #include "cauchy.h" static int PPs[33] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static int NOs[33]; static int ONEs[33][33]; static int *cbest_0; static int *cbest_1; static int cbest_2[3]; static int cbest_3[7]; static int cbest_4[15]; static int cbest_5[31]; static int cbest_6[63]; static int cbest_7[127]; static int cbest_8[255]; static int cbest_9[511]; static int cbest_10[1023]; static int cbest_11[1023]; static int *cbest_12, *cbest_13, *cbest_14, *cbest_15, *cbest_16, *cbest_17, *cbest_18, *cbest_19, *cbest_20, *cbest_21, *cbest_22, *cbest_23, *cbest_24, *cbest_25, *cbest_26, *cbest_27, *cbest_28, *cbest_29, *cbest_30, *cbest_31, *cbest_32; static int cbest_max_k[33] = { -1, -1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 1023, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static int cbest_init = 0; static int *cbest_all[33]; #define talloc(type, num) (type *) malloc(sizeof(type)*(num)) int cauchy_n_ones(int n, int w) { int no; int cno; int nones; int i, j; int highbit; highbit = (1 << (w-1)); if (PPs[w] == -1) { nones = 0; PPs[w] = galois_single_multiply(highbit, 2, w); for (i = 0; i < w; i++) { if (PPs[w] & (1 << i)) { ONEs[w][nones] = (1 << i); nones++; } } NOs[w] = nones; } no = 0; for (i = 0; i < w; i++) if (n & (1 << i)) no++; cno = no; for (i = 1; i < w; i++) { if (n & highbit) { n ^= highbit; n <<= 1; n ^= PPs[w]; cno--; for (j = 0; j < NOs[w]; j++) { cno += (n & ONEs[w][j]) ? 1 : -1; } } else { n <<= 1; } no += cno; } return no; } int *cauchy_original_coding_matrix(int k, int m, int w) { int *matrix; int i, j, index; if (w < 31 && (k+m) > (1 << w)) return NULL; matrix = talloc(int, k*m); if (matrix == NULL) return NULL; index = 0; for (i = 0; i < m; i++) { for (j = 0; j < k; j++) { matrix[index] = galois_single_divide(1, (i ^ (m+j)), w); index++; } } return matrix; } int *cauchy_xy_coding_matrix(int k, int m, int w, int *X, int *Y) { int index, i, j; int *matrix; matrix = talloc(int, k*m); if (matrix == NULL) { return NULL; } index = 0; for (i = 0; i < m; i++) { for (j = 0; j < k; j++) { matrix[index] = galois_single_divide(1, (X[i] ^ Y[j]), w); index++; } } return matrix; } void cauchy_improve_coding_matrix(int k, int m, int w, int *matrix) { int index, i, j, x; int tmp; int bno, tno, bno_index; for (j = 0; j < k; j++) { if (matrix[j] != 1) { tmp = galois_single_divide(1, matrix[j], w); index = j; for (i = 0; i < m; i++) { matrix[index] = galois_single_multiply(matrix[index], tmp, w); index += k; } } } for (i = 1; i < m; i++) { bno = 0; index = i*k; for (j = 0; j < k; j++) bno += cauchy_n_ones(matrix[index+j], w); bno_index = -1; for (j = 0; j < k; j++) { if (matrix[index+j] != 1) { tmp = galois_single_divide(1, matrix[index+j], w); tno = 0; for (x = 0; x < k; x++) { tno += cauchy_n_ones(galois_single_multiply(matrix[index+x], tmp, w), w); } if (tno < bno) { bno = tno; bno_index = j; } } } if (bno_index != -1) { tmp = galois_single_divide(1, matrix[index+bno_index], w); for (j = 0; j < k; j++) { matrix[index+j] = galois_single_multiply(matrix[index+j], tmp, w); } } } } int *cauchy_good_general_coding_matrix(int k, int m, int w) { int *matrix, i; if (m == 2 && k <= cbest_max_k[w]) { matrix = talloc(int, k*m); if (matrix == NULL) return NULL; if (!cbest_init) { cbest_init = 1; cbest_all[0] = cbest_0; cbest_all[1] = cbest_1; cbest_all[2] = cbest_2; cbest_all[3] = cbest_3; cbest_all[4] = cbest_4; cbest_all[5] = cbest_5; cbest_all[6] = cbest_6; cbest_all[7] = cbest_7; cbest_all[8] = cbest_8; cbest_all[9] = cbest_9; cbest_all[10] = cbest_10; cbest_all[11] = cbest_11; cbest_all[12] = cbest_12; cbest_all[13] = cbest_13; cbest_all[14] = cbest_14; cbest_all[15] = cbest_15; cbest_all[16] = cbest_16; cbest_all[17] = cbest_17; cbest_all[18] = cbest_18; cbest_all[19] = cbest_19; cbest_all[20] = cbest_20; cbest_all[21] = cbest_21; cbest_all[22] = cbest_22; cbest_all[23] = cbest_23; cbest_all[24] = cbest_24; cbest_all[25] = cbest_25; cbest_all[26] = cbest_26; cbest_all[27] = cbest_27; cbest_all[28] = cbest_28; cbest_all[29] = cbest_29; cbest_all[30] = cbest_30; cbest_all[31] = cbest_31; cbest_all[32] = (int *) cbest_32; } for (i = 0; i < k; i++) { matrix[i] = 1; matrix[i+k] = cbest_all[w][i]; } return matrix; } else { matrix = cauchy_original_coding_matrix(k, m, w); if (matrix == NULL) return NULL; cauchy_improve_coding_matrix(k, m, w, matrix); return matrix; } } static int cbest_2[3] = { 1, 2, 3 }; static int cbest_3[7] = { 1, 2, 5, 4, 7, 3, 6 }; static int cbest_4[15] = { 1, 2, 9, 4, 8, 13, 3, 6, 12, 5, 11, 15, 10, 14, 7 }; static int cbest_5[31] = { 1, 2, 18, 4, 9, 8, 22, 16, 3, 11, 19, 5, 10, 6, 20, 27, 13, 23, 26, 12, 17, 25, 24, 31, 30, 7, 15, 21, 29, 14, 28 }; static int cbest_6[63] = { 1, 2, 33, 4, 8, 49, 16, 32, 57, 3, 6, 12, 24, 48, 5, 35, 9, 37, 10, 17, 41, 51, 56, 61, 18, 28, 53, 14, 20, 34, 7, 13, 25, 36, 59, 26, 39, 40, 45, 50, 60, 52, 63, 11, 30, 55, 19, 22, 29, 43, 58, 15, 21, 38, 44, 47, 62, 27, 54, 42, 31, 23, 46 }; static int cbest_7[127] = { 1, 2, 68, 4, 34, 8, 17, 16, 76, 32, 38, 3, 64, 69, 5, 19, 35, 70, 6, 9, 18, 102, 10, 36, 85, 12, 21, 42, 51, 72, 77, 84, 20, 25, 33, 50, 78, 98, 24, 39, 49, 100, 110 , 48, 65, 93, 40, 66, 71, 92, 7, 46, 55, 87, 96, 103, 106, 11, 23, 37, 54, 81, 86, 108, 13, 22, 27, 43, 53, 73, 80, 14, 26, 52, 74, 79, 99, 119, 44, 95, 101, 104, 111, 118, 29, 59, 89, 94, 117, 28, 41, 58, 67, 88, 115, 116, 47, 57, 83, 97, 107, 114, 127, 56, 82, 109, 113, 126, 112, 125, 15, 63, 75, 123, 124, 31, 45, 62, 91, 105, 122, 30, 61, 90, 121, 60, 120 }; static int cbest_8[255] = { 1, 2, 142, 4, 71, 8, 70, 173, 3, 35, 143, 16, 17, 67, 134, 140, 172, 6, 34 , 69, 201, 216, 5, 33, 86, 12, 65, 138, 158, 159, 175, 10, 32, 43, 66, 108, 130, 193, 234, 9, 24, 25, 50, 68, 79, 100, 132, 174, 200, 217, 20, 21, 42, 48, 87, 169, 41, 54, 64, 84, 96, 117 , 154, 155, 165, 226, 77, 82, 135, 136, 141, 168, 192, 218, 238, 7, 18, 19, 39, 40, 78, 113, 116, 128, 164, 180, 195, 205, 220, 232, 14, 26, 27, 58, 109, 156, 157, 203, 235, 13, 28, 29, 38 , 51, 56, 75, 85, 90, 101, 110, 112, 139, 171, 11, 37, 49, 52, 76, 83, 102, 119, 131, 150, 151 , 167, 182, 184, 188, 197, 219, 224, 45, 55, 80, 94, 97, 133, 170, 194, 204, 221, 227, 236, 36, 47, 73, 92, 98, 104, 118, 152, 153, 166, 202, 207, 239, 251, 22, 23, 44, 74, 91, 148, 149, 161 , 181, 190, 233, 46, 59, 88, 137, 146, 147, 163, 196, 208, 212, 222, 250, 57, 81, 95, 106, 111, 129, 160, 176, 199, 243, 249, 15, 53, 72, 93, 103, 115, 125, 162, 183, 185, 189, 206, 225, 255, 186, 210, 230, 237, 242, 248, 30, 31, 62, 89, 99, 105, 114, 121, 124, 178, 209, 213, 223, 228, 241, 254, 60, 191, 198, 247, 120, 240, 107, 127, 144, 145, 177, 211, 214, 246, 245, 123, 126, 187, 231, 253, 63, 179, 229, 244, 61, 122, 215, 252 }; static int cbest_9[511] = { 1, 2, 264, 4, 132, 8, 66, 16, 33, 32, 280, 64, 140, 128, 3, 70, 265, 5, 133, 256, 266, 6, 9, 35, 67, 134, 268, 396, 10, 17, 34, 330, 12, 18, 68, 198, 297, 20, 37, 74 , 136, 148, 165, 281, 296, 24, 36, 41, 65, 82, 99, 164, 272, 282, 388, 40, 49, 98, 141, 194, 284, 328, 412, 48, 97, 129, 142, 196, 346, 71, 72, 96, 130, 313, 392, 80, 206, 257, 267, 312, 334, 7, 135, 156, 173, 192, 258, 269, 397, 404, 11, 78, 144, 161, 172, 260, 270, 299, 331, 344, 398, 13, 19, 39, 69, 86, 103, 160, 167, 199, 202, 298, 322, 384, 14, 21, 38, 43, 75, 102, 137, 149, 166, 204, 289, 332, 408, 462, 22, 25, 42, 51, 83, 101, 138, 150, 273, 283, 288, 301, 350, 389, 429, 26, 50, 76, 100, 195, 274, 285, 300, 329, 363, 390, 413, 428, 28, 45, 84, 143, 197, 200, 214, 231, 276, 286, 315, 320, 347, 362, 414, 458, 44, 53, 73, 90, 107, 131, 152, 169, 181, 230, 314, 338, 361, 393, 400, 454, 460, 52, 57, 81, 106, 115, 168, 175, 180, 207, 229, 305, 335 , 348, 360, 394, 421, 478, 56, 105, 114, 157, 163, 174, 193, 210, 227, 228, 259, 304, 317, 326, 405, 420, 445, 79, 104, 113, 145, 158, 162, 212, 226, 261, 271, 316, 345, 379, 399, 406, 444, 450, 456, 87, 88, 112, 146, 203, 225, 262, 291, 323, 336, 378, 385, 425, 452, 474, 15, 205, 222 , 224, 239, 290, 303, 333, 367, 377, 386, 409, 424, 431, 463, 470, 476, 23, 139, 151, 189, 208, 238, 302, 324, 351, 366, 376, 410, 430, 437, 27, 47, 77, 94, 111, 177, 188, 237, 275, 293, 342, 365, 391, 436, 448, 29, 46, 55, 85, 110, 119, 171, 176, 183, 201, 215, 218, 235, 236, 277, 287, 292, 321, 355, 364, 415, 417, 459, 466, 472, 30, 54, 59, 91, 109, 118, 153, 170, 182, 220, 234, 278, 307, 339, 354, 401, 416, 423, 441, 455, 461, 468, 495, 58, 108, 117, 154, 233, 306, 319, 349, 353, 383, 395, 402, 422, 440, 447, 479, 494, 92, 116, 211, 232, 318, 327, 340, 352, 382, 446, 493, 61, 159, 213, 216, 247, 309, 381, 407, 427, 451, 457, 464, 491, 492, 60, 89, 123, 147 , 185, 246, 263, 308, 337, 371, 380, 426, 433, 453, 475, 487, 490, 122, 184, 191, 223, 245, 370, 387, 432, 439, 471, 477, 486, 489, 511, 121, 179, 190, 209, 243, 244, 295, 325, 359, 369, 411, 438, 485, 488, 510, 95, 120, 178, 242, 294, 343, 358, 368, 419, 449, 483, 484, 509, 219, 241, 357, 418, 443, 467, 473, 482, 507, 508, 31, 221, 240, 255, 279, 356, 442, 469, 481, 503, 506, 155, 254, 403, 480, 502, 505, 63, 93, 127, 253, 311, 341, 375, 501, 504, 62, 126, 187, 217, 251 , 252, 310, 374, 435, 465, 499, 500, 125, 186, 250, 373, 434, 498, 124, 249, 372, 497, 248, 496 }; static int cbest_10[1023] = { 1, 2, 516, 4, 258, 8, 129, 16, 32, 580, 64, 128, 290, 145, 256, 3, 512, 517, 5, 259, 518, 588, 6, 9, 18, 36, 72, 144, 774, 10, 17, 131, 262, 288, 524, 645, 12, 33, 133, 266, 294, 387, 532, 576, 581, 20, 34, 65, 137, 274, 548, 582, 24, 66, 291, 838, 40, 68, 130, 147, 161, 322, 644, 709, 806, 48, 132, 193, 257, 386, 596, 80, 136, 298, 419, 612, 661, 772 , 96, 149, 260, 272, 306, 403, 513, 146, 153, 160, 264, 292, 385, 514, 519, 544, 584, 589, 708, 870, 7, 19, 37, 73, 192, 354, 590, 770, 775, 11, 38, 74, 177, 263, 289, 418, 520, 525, 534, 641 , 660, 725, 802, 836, 846, 13, 22, 76, 148, 209, 267, 295, 320, 330, 402, 526, 528, 533, 577, 647, 717, 804, 14, 21, 26, 35, 44, 135, 152, 165, 201, 275, 304, 384, 401, 435, 549, 578, 583, 604, 608, 782, 903, 25, 52, 67, 88, 139, 270, 296, 391, 417, 550, 620, 653, 790, 834, 839, 41, 50, 69, 104, 141, 176, 278, 302, 323, 395, 423, 540, 598, 640, 705, 724, 807, 866, 28, 42, 49, 70, 82, 100, 163, 208, 282, 310, 556, 592, 597, 646, 663, 677, 711, 716, 868, 878, 81, 134, 151 , 164, 195, 200, 299, 326, 352, 362, 400, 434, 564, 613, 657, 768, 773, 902, 967, 97, 138, 155, 169, 197, 261, 273, 307, 358, 390, 416, 433, 451, 614, 652, 733, 800, 814, 844, 854, 935, 56, 84 , 98, 140, 181, 217, 265, 293, 328, 338, 394, 422, 515, 545, 585, 704, 788, 822, 871, 919, 162, 179, 276, 355, 407, 427, 546, 586, 591, 616, 662, 669, 676, 710, 727, 741, 771, 780, 901, 39, 75 , 150, 157, 194, 211, 225, 268, 280, 308, 314, 389, 411, 439, 521, 530, 535, 628, 656, 721, 803, 832, 837, 842, 847, 966, 23, 77, 112, 154, 168, 196, 300, 321, 331, 393, 421, 432, 450, 522, 527 , 529, 552, 606, 643, 673, 693, 713, 732, 805, 864, 874, 934, 999, 15, 27, 45, 54, 78, 90, 108, 180, 216, 305, 483, 560, 579, 600, 605, 609, 719, 778, 783, 852, 876, 886, 899, 918, 983, 46, 53 , 89, 167, 178, 185, 203, 213, 271, 297, 324, 334, 336, 360, 370, 406, 426, 467, 542, 551, 610, 621, 649, 668, 726, 740, 786, 791, 810, 820, 835, 900, 917, 931, 951, 965, 975, 30, 51, 105, 156 , 205, 210, 224, 279, 303, 356, 366, 388, 405, 410, 438, 449, 459, 536, 541, 594, 599, 622, 655, 720, 812, 818, 862, 867, 933, 29, 43, 71, 83, 92, 101, 106, 143, 173, 283, 311, 312, 346, 392, 409, 420, 437, 443, 557, 566, 593, 642, 659, 672, 692, 707, 712, 737, 757, 869, 879, 911, 998, 60, 102, 241, 327, 353, 363, 399, 425, 482, 558, 565, 624, 679, 718, 735, 749, 769, 798, 898, 963, 982, 58, 86, 166, 183, 184, 202, 212, 219, 233, 286, 359, 431, 466, 615, 636, 648, 689, 729 , 801, 815, 840, 845, 850, 855, 884, 916, 930, 950, 964, 974, 981, 995, 1015, 57, 85, 99, 120, 171, 199, 204, 229, 318, 329, 339, 368, 404, 448, 458, 465, 499, 654, 671, 685, 784, 789, 823, 872, 882, 915, 932, 949, 997, 1007, 116, 142, 159, 172, 277, 408, 436, 442, 455, 481, 491, 547, 572, 587, 617, 630, 658, 665, 706, 723, 736, 756, 776, 781, 816, 860, 894, 897, 910, 947, 991, 114, 221, 240, 269, 281, 309, 315, 332, 342, 344, 378, 398, 424, 441, 475, 487, 531, 618, 629, 678, 695, 734, 743, 748, 808, 833, 843, 929, 943, 962, 973, 113, 182, 189, 218, 227, 232, 301, 364, 374, 430, 457, 523, 553, 562, 602, 607, 688, 728, 753, 796, 830, 865, 875, 927, 980, 994, 1014, 55, 79, 91, 109, 170, 187, 198, 215, 228, 284, 415, 464, 498, 554, 561, 601, 670, 675, 684 , 715, 745, 765, 779, 848, 853, 877, 887, 909, 914, 948, 979, 996, 1006, 1013, 47, 110, 158, 249 , 316, 325, 335, 337, 361, 371, 397, 447, 454, 480, 490, 497, 538, 543, 611, 632, 664, 722, 787, 811, 821, 880, 896, 913, 946, 961, 971, 990, 1011, 31, 94, 220, 245, 357, 367, 429, 440, 474, 486, 537, 595, 623, 651, 681, 694, 701, 742, 759, 813, 819, 858, 863, 892, 928, 942, 945, 972, 989, 993, 1003, 1023, 62, 93, 107, 188, 207, 226, 237, 243, 313, 340, 347, 376, 456, 471, 473, 507, 567, 568, 626, 752, 890, 907, 926, 1005, 61, 103, 124, 175, 186, 214, 372, 414, 453, 463, 489, 503, 559, 625, 638, 674, 691, 714, 731, 739, 744, 764, 794, 799, 828, 908, 925, 939, 959, 978, 1012, 59, 87, 122, 248, 287, 350, 396, 413, 446, 485, 495, 496, 637, 751, 826, 841, 851, 885, 912, 941, 960, 970, 977, 1010, 118, 121, 235, 244, 319, 369, 382, 428, 445, 574, 650, 667, 680, 700, 758, 761, 785, 873, 883, 944, 988, 992, 1002, 1009, 1022, 117, 206, 223, 231, 236, 242 , 470, 472, 506, 573, 631, 687, 777, 817, 856, 861, 895, 906, 987, 1004, 1021, 115, 174, 191, 333 , 343, 345, 379, 452, 462, 469, 488, 502, 505, 619, 690, 697, 730, 738, 755, 809, 888, 924, 938, 958, 969, 1019, 253, 365, 375, 412, 484, 494, 501, 563, 603, 750, 767, 792, 797, 831, 923, 940, 957, 976, 1001, 234, 251, 285, 348, 444, 479, 555, 634, 666, 760, 824, 849, 905, 955, 1008, 111, 222, 230, 247, 317, 380, 461, 511, 539, 633, 686, 703, 747, 881, 937, 986, 1020, 95, 190, 468, 493, 504, 570, 696, 754, 859, 893, 968, 985, 1018, 63, 126, 252, 341, 377, 500, 569, 627, 683, 766, 891, 922, 956, 1000, 1017, 125, 239, 250, 373, 478, 639, 795, 829, 904, 921, 954, 123, 246, 351, 460, 477, 510, 702, 746, 763, 827, 936, 953, 119, 383, 492, 509, 575, 984, 682, 699, 857, 1016, 238, 255, 889, 920, 476, 762, 793, 952, 349, 508, 635, 825, 381, 698, 254, 571, 127 }; static int cbest_11[1023] = { 1, 2, 1026, 4, 513, 8, 16, 1282, 32, 64, 641, 128, 256, 512, 1346, 1024, 3, 673, 1027, 5, 10, 20, 40, 80, 160, 320, 640, 6, 9, 515, 1030, 1280, 1539, 17, 517, 1034, 1283, 12, 18, 33, 521, 1042, 1362, 34, 65, 529, 1058, 1286, 1795, 24, 36, 66, 129, 545, 643, 1090, 1290, 1667, 68, 130, 257, 577, 645, 672, 1154, 1298, 1344, 48, 72, 132, 258, 336, 649, 681, 1314, 1347, 136, 168, 260, 514, 657, 769, 1538, 1923, 84, 96, 144, 264, 516, 1025, 1350, 1410, 1859, 42, 272, 520, 705, 1032, 1354, 11, 21, 41, 81, 161, 192, 288, 321, 528, 675, 1028, 1537, 1699, 1794, 7, 22, 82, 162, 322, 544, 642, 677, 897, 1031, 1046, 1066, 1106, 1186, 1281, 1366, 1378, 1666, 14, 44, 164, 324, 384, 523, 533, 553, 576, 593, 644, 833, 1035, 1040, 1288, 1360, 1987, 13, 19, 28, 88, 328, 519, 648, 680, 689, 1043, 1056, 1284, 1363, 1474, 1543, 1793, 1955, 26, 35, 56, 176, 656, 768, 1038, 1059, 1088, 1287, 1302, 1322, 1442, 1547, 1665, 1922, 25, 37, 52, 67, 112, 340, 352, 525, 531, 737, 1091, 1152, 1291, 1296, 1555, 1858, 1875, 38, 69, 74, 104, 131, 224, 547, 651, 661, 683, 704, 721, 961, 1050, 1062, 1155, 1299, 1312, 1345, 1370, 1571, 1799, 49, 70, 73, 133, 138, 148, 170, 208, 259, 337, 448, 537, 549, 579, 647, 674, 929, 1094, 1294, 1315, 1352, 1536, 1603, 1671, 1698, 1803, 1921, 50, 134, 137, 169, 261, 266, 276, 296, 338, 416, 581, 676, 896, 1074, 1098, 1158, 1348, 1394, 1408, 1675, 1707, 1811, 1857, 2019, 76, 85, 97, 145, 262, 265, 522, 532, 552, 561, 585, 592, 653, 659, 685, 771, 832, 849, 1064, 1162, 1194, 1306, 1318, 1351, 1386, 1411, 1506, 1683, 1827, 1986, 2003, 43, 86, 98, 140, 146, 172, 273, 344, 518, 688, 773, 1033, 1110, 1122, 1170, 1355, 1490, 1542, 1697, 1792, 1927, 1954, 100, 193, 268, 274, 289, 597, 609, 665, 697, 707, 777, 1029, 1044, 1104, 1184, 1330, 1364, 1376, 1414, 1546, 1664, 1731, 1863, 1931, 1963, 23, 46, 83, 92, 152, 163, 184, 194, 290, 323, 368, 524, 530, 555, 693, 709, 736, 753, 785, 993, 1036, 1047, 1067, 1107, 1187, 1218, 1320, 1358, 1367, 1379, 1418, 1450, 1545, 1554, 1867, 1874, 1939, 1985, 15, 30, 45, 60, 90, 120, 165, 180, 196, 240, 280, 292, 325, 330, 360, 385, 480, 546, 650, 660, 679, 682, 713, 720, 745, 801, 899, 960, 977, 1041, 1289, 1361, 1426, 1472, 1541, 1570, 1703, 1798, 1953, 29, 58, 89, 116, 166, 200, 232, 326, 329, 386, 464, 535, 536, 548, 578, 595, 646, 835, 901, 928, 1048, 1057, 1070, 1190, 1285, 1300, 1368, 1382, 1440, 1475, 1559, 1579, 1602, 1619, 1670, 1802, 1879, 1891, 1920, 27, 57, 177, 304, 388, 527, 557, 580, 691, 725, 837, 905, 937, 1039, 1054, 1089, 1114, 1292, 1303, 1323, 1374, 1443, 1553, 1674, 1706, 1715, 1801, 1810, 1856, 1873, 1991, 2018, 2035, 53, 106, 113, 178, 212, 332, 341, 353, 392, 424, 541, 560, 584, 601, 652, 658, 684, 770, 841, 848, 913, 1060, 1082, 1096, 1153, 1202, 1297, 1402, 1478, 1522, 1569, 1673, 1682, 1705, 1797, 1826, 1959, 1995, 2002, 2027, 39, 54, 75, 105, 114, 225, 342, 354, 400, 539, 569, 739, 772, 1051, 1063, 1078, 1092, 1138, 1160, 1192, 1304, 1313, 1326, 1371, 1384, 1398, 1446, 1482, 1514, 1551, 1601, 1669, 1696, 1763, 1815, 1835, 1926, 71, 139, 149, 171, 209, 226, 298, 356, 449, 565, 596, 608, 625, 663, 664, 696, 706, 723, 741, 776, 853, 865, 963, 1072, 1095, 1130, 1156, 1250, 1295, 1310, 1353, 1392, 1687, 1730, 1747, 1809, 1862, 1930, 1962, 1971, 2007, 2017, 51, 78, 108, 135, 150, 210, 228, 267, 277, 297, 339, 348, 417, 450, 551, 554, 587, 617, 655, 687, 692, 708, 752, 784, 931, 965, 992, 1009, 1075, 1099, 1159, 1174, 1234, 1316, 1338, 1349, 1395, 1409, 1458, 1494, 1504, 1544, 1563, 1575, 1681, 1825, 1866, 1883, 1929, 1938, 1961, 1984, 2001, 77, 142, 174, 263, 278, 346, 376, 418, 452, 496, 583, 669, 678, 701, 712, 729, 744, 761, 800, 898, 933, 969, 976, 1001, 1065, 1108, 1120, 1163, 1168, 1195, 1307, 1319, 1334, 1356, 1387, 1416, 1448, 1488, 1507, 1540, 1607, 1702, 1807, 1865, 1925, 1952, 87, 99, 141, 147, 156, 173, 188, 216, 248, 270, 300, 345, 372, 420, 456, 488, 534, 563, 594, 667, 699, 757, 779, 789, 809, 834, 851, 900, 1102, 1111, 1123, 1171, 1328, 1412, 1491, 1558, 1578, 1587, 1611, 1618, 1679, 1711, 1729, 1861, 1878, 1890, 1907, 1943, 2023, 94, 101, 124, 154, 186, 244, 269, 275, 284, 526, 556, 589, 690, 724, 775, 836, 904, 936, 945, 981, 1045, 1068, 1105, 1166, 1185, 1198, 1216, 1331, 1365, 1377, 1390, 1415, 1430, 1510, 1552, 1577, 1714, 1800, 1819, 1831, 1872, 1899, 1937, 1990, 2034, 47, 62, 93, 102, 122, 153, 185, 195, 282, 291, 312, 362, 369, 432, 468, 540, 599, 600, 611, 715, 747, 840, 857, 912, 1037, 1052, 1112, 1126, 1219, 1321, 1359, 1372, 1419, 1424, 1451, 1568, 1623, 1635, 1672, 1691, 1701, 1704, 1723, 1796, 1958, 1994, 2011, 2026, 2043, 31, 61, 91, 121, 181, 197, 202, 234, 241, 281, 293, 308, 331, 361, 370, 481, 538, 568, 613, 695, 711, 738, 755, 781, 787, 995, 1080, 1118, 1178, 1188, 1210, 1380, 1400, 1427, 1473, 1498, 1530, 1550, 1557, 1600, 1617, 1668, 1719, 1735, 1762, 1779, 1814, 1834, 1843, 1877, 1889, 1935, 1967, 1993, 2025, 2039, 59, 117, 167, 182, 198, 201, 233, 242, 294, 327, 387, 465, 482, 559, 564, 605, 624, 662, 722, 740, 803, 852, 864, 881, 907, 917, 939, 962, 979, 997, 1049, 1071, 1086, 1146, 1191, 1206, 1222, 1266, 1301, 1324, 1369, 1383, 1406, 1422, 1441, 1454, 1480, 1512, 1526, 1549, 1686, 1713, 1739, 1746, 1771, 1808, 1833, 1871, 1970, 1989, 2006, 2016, 2033, 118, 305, 334, 364, 389, 394, 404, 426, 466, 484, 543, 550, 573, 586, 603, 616, 633, 654, 686, 717, 749, 793, 805, 843, 873, 903, 930, 964, 1008, 1055, 1115, 1128, 1142, 1200, 1226, 1258, 1293, 1308, 1375, 1476, 1520, 1562, 1574, 1680, 1824 }; ceph-0.80.11/src/erasure-code/jerasure/jerasure/src/jerasure.c0000664000175100017510000010671412623076752026265 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2014, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ /* Jerasure's authors: Revision 2.x - 2014: James S. Plank and Kevin M. Greenan Revision 1.2 - 2008: James S. Plank, Scott Simmerman and Catherine D. Schuman. Revision 1.0 - 2007: James S. Plank */ #include #include #include #include "galois.h" #include "jerasure.h" #define talloc(type, num) (type *) malloc(sizeof(type)*(num)) static double jerasure_total_xor_bytes = 0; static double jerasure_total_gf_bytes = 0; static double jerasure_total_memcpy_bytes = 0; void jerasure_print_matrix(int *m, int rows, int cols, int w) { int i, j; int fw; char s[30]; unsigned int w2; if (w == 32) { fw = 10; } else { w2 = (1 << w); sprintf(s, "%u", w2-1); fw = strlen(s); } for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { if (j != 0) printf(" "); printf("%*u", fw, m[i*cols+j]); } printf("\n"); } } void jerasure_print_bitmatrix(int *m, int rows, int cols, int w) { int i, j; for (i = 0; i < rows; i++) { if (i != 0 && i%w == 0) printf("\n"); for (j = 0; j < cols; j++) { if (j != 0 && j%w == 0) printf(" "); printf("%d", m[i*cols+j]); } printf("\n"); } } int jerasure_make_decoding_matrix(int k, int m, int w, int *matrix, int *erased, int *decoding_matrix, int *dm_ids) { int i, j, *tmpmat; j = 0; for (i = 0; j < k; i++) { if (erased[i] == 0) { dm_ids[j] = i; j++; } } tmpmat = talloc(int, k*k); if (tmpmat == NULL) { return -1; } for (i = 0; i < k; i++) { if (dm_ids[i] < k) { for (j = 0; j < k; j++) tmpmat[i*k+j] = 0; tmpmat[i*k+dm_ids[i]] = 1; } else { for (j = 0; j < k; j++) { tmpmat[i*k+j] = matrix[(dm_ids[i]-k)*k+j]; } } } i = jerasure_invert_matrix(tmpmat, decoding_matrix, k, w); free(tmpmat); return i; } /* Internal Routine */ int jerasure_make_decoding_bitmatrix(int k, int m, int w, int *matrix, int *erased, int *decoding_matrix, int *dm_ids) { int i, j, *tmpmat; int index, mindex; j = 0; for (i = 0; j < k; i++) { if (erased[i] == 0) { dm_ids[j] = i; j++; } } tmpmat = talloc(int, k*k*w*w); if (tmpmat == NULL) { return -1; } for (i = 0; i < k; i++) { if (dm_ids[i] < k) { index = i*k*w*w; for (j = 0; j < k*w*w; j++) tmpmat[index+j] = 0; index = i*k*w*w+dm_ids[i]*w; for (j = 0; j < w; j++) { tmpmat[index] = 1; index += (k*w+1); } } else { index = i*k*w*w; mindex = (dm_ids[i]-k)*k*w*w; for (j = 0; j < k*w*w; j++) { tmpmat[index+j] = matrix[mindex+j]; } } } i = jerasure_invert_bitmatrix(tmpmat, decoding_matrix, k*w); free(tmpmat); return i; } int jerasure_matrix_decode(int k, int m, int w, int *matrix, int row_k_ones, int *erasures, char **data_ptrs, char **coding_ptrs, int size) { int i, edd, lastdrive; int *tmpids; int *erased, *decoding_matrix, *dm_ids; if (w != 8 && w != 16 && w != 32) return -1; erased = jerasure_erasures_to_erased(k, m, erasures); if (erased == NULL) return -1; /* Find the number of data drives failed */ lastdrive = k; edd = 0; for (i = 0; i < k; i++) { if (erased[i]) { edd++; lastdrive = i; } } /* You only need to create the decoding matrix in the following cases: 1. edd > 0 and row_k_ones is false. 2. edd > 0 and row_k_ones is true and coding device 0 has been erased. 3. edd > 1 We're going to use lastdrive to denote when to stop decoding data. At this point in the code, it is equal to the last erased data device. However, if we can't use the parity row to decode it (i.e. row_k_ones=0 or erased[k] = 1, we're going to set it to k so that the decoding pass will decode all data. */ if (!row_k_ones || erased[k]) lastdrive = k; dm_ids = NULL; decoding_matrix = NULL; if (edd > 1 || (edd > 0 && (!row_k_ones || erased[k]))) { dm_ids = talloc(int, k); if (dm_ids == NULL) { free(erased); return -1; } decoding_matrix = talloc(int, k*k); if (decoding_matrix == NULL) { free(erased); free(dm_ids); return -1; } if (jerasure_make_decoding_matrix(k, m, w, matrix, erased, decoding_matrix, dm_ids) < 0) { free(erased); free(dm_ids); free(decoding_matrix); return -1; } } /* Decode the data drives. If row_k_ones is true and coding device 0 is intact, then only decode edd-1 drives. This is done by stopping at lastdrive. We test whether edd > 0 so that we can exit the loop early if we're done. */ for (i = 0; edd > 0 && i < lastdrive; i++) { if (erased[i]) { jerasure_matrix_dotprod(k, w, decoding_matrix+(i*k), dm_ids, i, data_ptrs, coding_ptrs, size); edd--; } } /* Then if necessary, decode drive lastdrive */ if (edd > 0) { tmpids = talloc(int, k); for (i = 0; i < k; i++) { tmpids[i] = (i < lastdrive) ? i : i+1; } jerasure_matrix_dotprod(k, w, matrix, tmpids, lastdrive, data_ptrs, coding_ptrs, size); free(tmpids); } /* Finally, re-encode any erased coding devices */ for (i = 0; i < m; i++) { if (erased[k+i]) { jerasure_matrix_dotprod(k, w, matrix+(i*k), NULL, i+k, data_ptrs, coding_ptrs, size); } } free(erased); if (dm_ids != NULL) free(dm_ids); if (decoding_matrix != NULL) free(decoding_matrix); return 0; } int *jerasure_matrix_to_bitmatrix(int k, int m, int w, int *matrix) { int *bitmatrix; int rowelts, rowindex, colindex, elt, i, j, l, x; bitmatrix = talloc(int, k*m*w*w); if (matrix == NULL) { return NULL; } rowelts = k * w; rowindex = 0; for (i = 0; i < m; i++) { colindex = rowindex; for (j = 0; j < k; j++) { elt = matrix[i*k+j]; for (x = 0; x < w; x++) { for (l = 0; l < w; l++) { bitmatrix[colindex+x+l*rowelts] = ((elt & (1 << l)) ? 1 : 0); } elt = galois_single_multiply(elt, 2, w); } colindex += w; } rowindex += rowelts * w; } return bitmatrix; } void jerasure_matrix_encode(int k, int m, int w, int *matrix, char **data_ptrs, char **coding_ptrs, int size) { int i; if (w != 8 && w != 16 && w != 32) { fprintf(stderr, "ERROR: jerasure_matrix_encode() and w is not 8, 16 or 32\n"); exit(1); } for (i = 0; i < m; i++) { jerasure_matrix_dotprod(k, w, matrix+(i*k), NULL, k+i, data_ptrs, coding_ptrs, size); } } void jerasure_bitmatrix_dotprod(int k, int w, int *bitmatrix_row, int *src_ids, int dest_id, char **data_ptrs, char **coding_ptrs, int size, int packetsize) { int j, sindex, pstarted, index, x, y; char *dptr, *pptr, *bdptr, *bpptr; if (size%(w*packetsize) != 0) { fprintf(stderr, "jerasure_bitmatrix_dotprod - size%c(w*packetsize)) must = 0\n", '%'); exit(1); } bpptr = (dest_id < k) ? data_ptrs[dest_id] : coding_ptrs[dest_id-k]; for (sindex = 0; sindex < size; sindex += (packetsize*w)) { index = 0; for (j = 0; j < w; j++) { pstarted = 0; pptr = bpptr + sindex + j*packetsize; for (x = 0; x < k; x++) { if (src_ids == NULL) { bdptr = data_ptrs[x]; } else if (src_ids[x] < k) { bdptr = data_ptrs[src_ids[x]]; } else { bdptr = coding_ptrs[src_ids[x]-k]; } for (y = 0; y < w; y++) { if (bitmatrix_row[index]) { dptr = bdptr + sindex + y*packetsize; if (!pstarted) { memcpy(pptr, dptr, packetsize); jerasure_total_memcpy_bytes += packetsize; pstarted = 1; } else { galois_region_xor(dptr, pptr, packetsize); jerasure_total_xor_bytes += packetsize; } } index++; } } } } } void jerasure_do_parity(int k, char **data_ptrs, char *parity_ptr, int size) { int i; memcpy(parity_ptr, data_ptrs[0], size); jerasure_total_memcpy_bytes += size; for (i = 1; i < k; i++) { galois_region_xor(data_ptrs[i], parity_ptr, size); jerasure_total_xor_bytes += size; } } int jerasure_invert_matrix(int *mat, int *inv, int rows, int w) { int cols, i, j, k, x, rs2; int row_start, tmp, inverse; cols = rows; k = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { inv[k] = (i == j) ? 1 : 0; k++; } } /* First -- convert into upper triangular */ for (i = 0; i < cols; i++) { row_start = cols*i; /* Swap rows if we ave a zero i,i element. If we can't swap, then the matrix was not invertible */ if (mat[row_start+i] == 0) { for (j = i+1; j < rows && mat[cols*j+i] == 0; j++) ; if (j == rows) return -1; rs2 = j*cols; for (k = 0; k < cols; k++) { tmp = mat[row_start+k]; mat[row_start+k] = mat[rs2+k]; mat[rs2+k] = tmp; tmp = inv[row_start+k]; inv[row_start+k] = inv[rs2+k]; inv[rs2+k] = tmp; } } /* Multiply the row by 1/element i,i */ tmp = mat[row_start+i]; if (tmp != 1) { inverse = galois_single_divide(1, tmp, w); for (j = 0; j < cols; j++) { mat[row_start+j] = galois_single_multiply(mat[row_start+j], inverse, w); inv[row_start+j] = galois_single_multiply(inv[row_start+j], inverse, w); } } /* Now for each j>i, add A_ji*Ai to Aj */ k = row_start+i; for (j = i+1; j != cols; j++) { k += cols; if (mat[k] != 0) { if (mat[k] == 1) { rs2 = cols*j; for (x = 0; x < cols; x++) { mat[rs2+x] ^= mat[row_start+x]; inv[rs2+x] ^= inv[row_start+x]; } } else { tmp = mat[k]; rs2 = cols*j; for (x = 0; x < cols; x++) { mat[rs2+x] ^= galois_single_multiply(tmp, mat[row_start+x], w); inv[rs2+x] ^= galois_single_multiply(tmp, inv[row_start+x], w); } } } } } /* Now the matrix is upper triangular. Start at the top and multiply down */ for (i = rows-1; i >= 0; i--) { row_start = i*cols; for (j = 0; j < i; j++) { rs2 = j*cols; if (mat[rs2+i] != 0) { tmp = mat[rs2+i]; mat[rs2+i] = 0; for (k = 0; k < cols; k++) { inv[rs2+k] ^= galois_single_multiply(tmp, inv[row_start+k], w); } } } } return 0; } int jerasure_invertible_matrix(int *mat, int rows, int w) { int cols, i, j, k, x, rs2; int row_start, tmp, inverse; cols = rows; /* First -- convert into upper triangular */ for (i = 0; i < cols; i++) { row_start = cols*i; /* Swap rows if we ave a zero i,i element. If we can't swap, then the matrix was not invertible */ if (mat[row_start+i] == 0) { for (j = i+1; j < rows && mat[cols*j+i] == 0; j++) ; if (j == rows) return 0; rs2 = j*cols; for (k = 0; k < cols; k++) { tmp = mat[row_start+k]; mat[row_start+k] = mat[rs2+k]; mat[rs2+k] = tmp; } } /* Multiply the row by 1/element i,i */ tmp = mat[row_start+i]; if (tmp != 1) { inverse = galois_single_divide(1, tmp, w); for (j = 0; j < cols; j++) { mat[row_start+j] = galois_single_multiply(mat[row_start+j], inverse, w); } } /* Now for each j>i, add A_ji*Ai to Aj */ k = row_start+i; for (j = i+1; j != cols; j++) { k += cols; if (mat[k] != 0) { if (mat[k] == 1) { rs2 = cols*j; for (x = 0; x < cols; x++) { mat[rs2+x] ^= mat[row_start+x]; } } else { tmp = mat[k]; rs2 = cols*j; for (x = 0; x < cols; x++) { mat[rs2+x] ^= galois_single_multiply(tmp, mat[row_start+x], w); } } } } } return 1; } /* Converts a list-style version of the erasures into an array of k+m elements where the element = 1 if the index has been erased, and zero otherwise */ int *jerasure_erasures_to_erased(int k, int m, int *erasures) { int td; int t_non_erased; int *erased; int i; td = k+m; erased = talloc(int, td); if (erased == NULL) return NULL; t_non_erased = td; for (i = 0; i < td; i++) erased[i] = 0; for (i = 0; erasures[i] != -1; i++) { if (erased[erasures[i]] == 0) { erased[erasures[i]] = 1; t_non_erased--; if (t_non_erased < k) { free(erased); return NULL; } } } return erased; } void jerasure_free_schedule(int **schedule) { int i; for (i = 0; schedule[i][0] >= 0; i++) free(schedule[i]); free(schedule[i]); free(schedule); } void jerasure_free_schedule_cache(int k, int m, int ***cache) { int e1, e2; if (m != 2) { fprintf(stderr, "jerasure_free_schedule_cache(): m must equal 2\n"); exit(1); } for (e1 = 0; e1 < k+m; e1++) { for (e2 = 0; e2 < e1; e2++) { jerasure_free_schedule(cache[e1*(k+m)+e2]); } jerasure_free_schedule(cache[e1*(k+m)+e1]); } free(cache); } void jerasure_matrix_dotprod(int k, int w, int *matrix_row, int *src_ids, int dest_id, char **data_ptrs, char **coding_ptrs, int size) { int init; char *dptr, *sptr; int i; if (w != 1 && w != 8 && w != 16 && w != 32) { fprintf(stderr, "ERROR: jerasure_matrix_dotprod() called and w is not 1, 8, 16 or 32\n"); exit(1); } init = 0; dptr = (dest_id < k) ? data_ptrs[dest_id] : coding_ptrs[dest_id-k]; /* First copy or xor any data that does not need to be multiplied by a factor */ for (i = 0; i < k; i++) { if (matrix_row[i] == 1) { if (src_ids == NULL) { sptr = data_ptrs[i]; } else if (src_ids[i] < k) { sptr = data_ptrs[src_ids[i]]; } else { sptr = coding_ptrs[src_ids[i]-k]; } if (init == 0) { memcpy(dptr, sptr, size); jerasure_total_memcpy_bytes += size; init = 1; } else { galois_region_xor(sptr, dptr, size); jerasure_total_xor_bytes += size; } } } /* Now do the data that needs to be multiplied by a factor */ for (i = 0; i < k; i++) { if (matrix_row[i] != 0 && matrix_row[i] != 1) { if (src_ids == NULL) { sptr = data_ptrs[i]; } else if (src_ids[i] < k) { sptr = data_ptrs[src_ids[i]]; } else { sptr = coding_ptrs[src_ids[i]-k]; } switch (w) { case 8: galois_w08_region_multiply(sptr, matrix_row[i], size, dptr, init); break; case 16: galois_w16_region_multiply(sptr, matrix_row[i], size, dptr, init); break; case 32: galois_w32_region_multiply(sptr, matrix_row[i], size, dptr, init); break; } jerasure_total_gf_bytes += size; init = 1; } } } int jerasure_bitmatrix_decode(int k, int m, int w, int *bitmatrix, int row_k_ones, int *erasures, char **data_ptrs, char **coding_ptrs, int size, int packetsize) { int i; int *erased; int *decoding_matrix; int *dm_ids; int edd, *tmpids, lastdrive; erased = jerasure_erasures_to_erased(k, m, erasures); if (erased == NULL) return -1; /* See jerasure_matrix_decode for the logic of this routine. This one works just like it, but calls the bitmatrix ops instead */ lastdrive = k; edd = 0; for (i = 0; i < k; i++) { if (erased[i]) { edd++; lastdrive = i; } } if (row_k_ones != 1 || erased[k]) lastdrive = k; dm_ids = NULL; decoding_matrix = NULL; if (edd > 1 || (edd > 0 && (row_k_ones != 1 || erased[k]))) { dm_ids = talloc(int, k); if (dm_ids == NULL) { free(erased); return -1; } decoding_matrix = talloc(int, k*k*w*w); if (decoding_matrix == NULL) { free(erased); free(dm_ids); return -1; } if (jerasure_make_decoding_bitmatrix(k, m, w, bitmatrix, erased, decoding_matrix, dm_ids) < 0) { free(erased); free(dm_ids); free(decoding_matrix); return -1; } } for (i = 0; edd > 0 && i < lastdrive; i++) { if (erased[i]) { jerasure_bitmatrix_dotprod(k, w, decoding_matrix+i*k*w*w, dm_ids, i, data_ptrs, coding_ptrs, size, packetsize); edd--; } } if (edd > 0) { tmpids = talloc(int, k); for (i = 0; i < k; i++) { tmpids[i] = (i < lastdrive) ? i : i+1; } jerasure_bitmatrix_dotprod(k, w, bitmatrix, tmpids, lastdrive, data_ptrs, coding_ptrs, size, packetsize); free(tmpids); } for (i = 0; i < m; i++) { if (erased[k+i]) { jerasure_bitmatrix_dotprod(k, w, bitmatrix+i*k*w*w, NULL, k+i, data_ptrs, coding_ptrs, size, packetsize); } } free(erased); if (dm_ids != NULL) free(dm_ids); if (decoding_matrix != NULL) free(decoding_matrix); return 0; } static char **set_up_ptrs_for_scheduled_decoding(int k, int m, int *erasures, char **data_ptrs, char **coding_ptrs) { int ddf, cdf; int *erased; char **ptrs; int i, j, x; ddf = 0; cdf = 0; for (i = 0; erasures[i] != -1; i++) { if (erasures[i] < k) ddf++; else cdf++; } erased = jerasure_erasures_to_erased(k, m, erasures); if (erased == NULL) return NULL; /* Set up ptrs. It will be as follows: - If data drive i has not failed, then ptrs[i] = data_ptrs[i]. - If data drive i has failed, then ptrs[i] = coding_ptrs[j], where j is the lowest unused non-failed coding drive. - Elements k to k+ddf-1 are data_ptrs[] of the failed data drives. - Elements k+ddf to k+ddf+cdf-1 are coding_ptrs[] of the failed data drives. The array row_ids contains the ids of ptrs. The array ind_to_row_ids contains the row_id of drive i. However, we're going to set row_ids and ind_to_row in a different procedure. */ ptrs = talloc(char *, k+m); j = k; x = k; for (i = 0; i < k; i++) { if (erased[i] == 0) { ptrs[i] = data_ptrs[i]; } else { while (erased[j]) j++; ptrs[i] = coding_ptrs[j-k]; j++; ptrs[x] = data_ptrs[i]; x++; } } for (i = k; i < k+m; i++) { if (erased[i]) { ptrs[x] = coding_ptrs[i-k]; x++; } } free(erased); return ptrs; } static int set_up_ids_for_scheduled_decoding(int k, int m, int *erasures, int *row_ids, int *ind_to_row) { int ddf, cdf; int *erased; int i, j, x; ddf = 0; cdf = 0; for (i = 0; erasures[i] != -1; i++) { if (erasures[i] < k) ddf++; else cdf++; } erased = jerasure_erasures_to_erased(k, m, erasures); if (erased == NULL) return -1; /* See set_up_ptrs_for_scheduled_decoding for how these are set */ j = k; x = k; for (i = 0; i < k; i++) { if (erased[i] == 0) { row_ids[i] = i; ind_to_row[i] = i; } else { while (erased[j]) j++; row_ids[i] = j; ind_to_row[j] = i; j++; row_ids[x] = i; ind_to_row[i] = x; x++; } } for (i = k; i < k+m; i++) { if (erased[i]) { row_ids[x] = i; ind_to_row[i] = x; x++; } } free(erased); return 0; } static int **jerasure_generate_decoding_schedule(int k, int m, int w, int *bitmatrix, int *erasures, int smart) { int i, j, x, drive, y, index, z; int *decoding_matrix, *inverse, *real_decoding_matrix; int *ptr; int *row_ids; int *ind_to_row; int ddf, cdf; int **schedule; int *b1, *b2; /* First, figure out the number of data drives that have failed, and the number of coding drives that have failed: ddf and cdf */ ddf = 0; cdf = 0; for (i = 0; erasures[i] != -1; i++) { if (erasures[i] < k) ddf++; else cdf++; } row_ids = talloc(int, k+m); ind_to_row = talloc(int, k+m); if (set_up_ids_for_scheduled_decoding(k, m, erasures, row_ids, ind_to_row) < 0) return NULL; /* Now, we're going to create one decoding matrix which is going to decode everything with one call. The hope is that the scheduler will do a good job. This matrix has w*e rows, where e is the number of erasures (ddf+cdf) */ real_decoding_matrix = talloc(int, k*w*(cdf+ddf)*w); /* First, if any data drives have failed, then initialize the first ddf*w rows of the decoding matrix from the standard decoding matrix inversion */ if (ddf > 0) { decoding_matrix = talloc(int, k*k*w*w); ptr = decoding_matrix; for (i = 0; i < k; i++) { if (row_ids[i] == i) { bzero(ptr, k*w*w*sizeof(int)); for (x = 0; x < w; x++) { ptr[x+i*w+x*k*w] = 1; } } else { memcpy(ptr, bitmatrix+k*w*w*(row_ids[i]-k), k*w*w*sizeof(int)); } ptr += (k*w*w); } inverse = talloc(int, k*k*w*w); jerasure_invert_bitmatrix(decoding_matrix, inverse, k*w); /* printf("\nMatrix to invert\n"); jerasure_print_bitmatrix(decoding_matrix, k*w, k*w, w); printf("\n"); printf("\nInverse\n"); jerasure_print_bitmatrix(inverse, k*w, k*w, w); printf("\n"); */ free(decoding_matrix); ptr = real_decoding_matrix; for (i = 0; i < ddf; i++) { memcpy(ptr, inverse+k*w*w*row_ids[k+i], sizeof(int)*k*w*w); ptr += (k*w*w); } free(inverse); } /* Next, here comes the hard part. For each coding node that needs to be decoded, you start by putting its rows of the distribution matrix into the decoding matrix. If there were no failed data nodes, then you're done. However, if there have been failed data nodes, then you need to modify the columns that correspond to the data nodes. You do that by first zeroing them. Then whereever there is a one in the distribution matrix, you XOR in the corresponding row from the failed data node's entry in the decoding matrix. The whole process kind of makes my head spin, but it works. */ for (x = 0; x < cdf; x++) { drive = row_ids[x+ddf+k]-k; ptr = real_decoding_matrix + k*w*w*(ddf+x); memcpy(ptr, bitmatrix+drive*k*w*w, sizeof(int)*k*w*w); for (i = 0; i < k; i++) { if (row_ids[i] != i) { for (j = 0; j < w; j++) { bzero(ptr+j*k*w+i*w, sizeof(int)*w); } } } /* There's the yucky part */ index = drive*k*w*w; for (i = 0; i < k; i++) { if (row_ids[i] != i) { b1 = real_decoding_matrix+(ind_to_row[i]-k)*k*w*w; for (j = 0; j < w; j++) { b2 = ptr + j*k*w; for (y = 0; y < w; y++) { if (bitmatrix[index+j*k*w+i*w+y]) { for (z = 0; z < k*w; z++) { b2[z] = b2[z] ^ b1[z+y*k*w]; } } } } } } } /* printf("\n\nReal Decoding Matrix\n\n"); jerasure_print_bitmatrix(real_decoding_matrix, (ddf+cdf)*w, k*w, w); printf("\n"); */ if (smart) { schedule = jerasure_smart_bitmatrix_to_schedule(k, ddf+cdf, w, real_decoding_matrix); } else { schedule = jerasure_dumb_bitmatrix_to_schedule(k, ddf+cdf, w, real_decoding_matrix); } free(row_ids); free(ind_to_row); free(real_decoding_matrix); return schedule; } int jerasure_schedule_decode_lazy(int k, int m, int w, int *bitmatrix, int *erasures, char **data_ptrs, char **coding_ptrs, int size, int packetsize, int smart) { int i, tdone; char **ptrs; int **schedule; ptrs = set_up_ptrs_for_scheduled_decoding(k, m, erasures, data_ptrs, coding_ptrs); if (ptrs == NULL) return -1; schedule = jerasure_generate_decoding_schedule(k, m, w, bitmatrix, erasures, smart); if (schedule == NULL) { free(ptrs); return -1; } for (tdone = 0; tdone < size; tdone += packetsize*w) { jerasure_do_scheduled_operations(ptrs, schedule, packetsize); for (i = 0; i < k+m; i++) ptrs[i] += (packetsize*w); } jerasure_free_schedule(schedule); free(ptrs); return 0; } int jerasure_schedule_decode_cache(int k, int m, int w, int ***scache, int *erasures, char **data_ptrs, char **coding_ptrs, int size, int packetsize) { int i, tdone; char **ptrs; int **schedule; int index; if (erasures[1] == -1) { index = erasures[0]*(k+m) + erasures[0]; } else if (erasures[2] == -1) { index = erasures[0]*(k+m) + erasures[1]; } else { return -1; } schedule = scache[index]; ptrs = set_up_ptrs_for_scheduled_decoding(k, m, erasures, data_ptrs, coding_ptrs); if (ptrs == NULL) return -1; for (tdone = 0; tdone < size; tdone += packetsize*w) { jerasure_do_scheduled_operations(ptrs, schedule, packetsize); for (i = 0; i < k+m; i++) ptrs[i] += (packetsize*w); } free(ptrs); return 0; } /* This only works when m = 2 */ int ***jerasure_generate_schedule_cache(int k, int m, int w, int *bitmatrix, int smart) { int ***scache; int erasures[3]; int e1, e2; /* Ok -- this is yucky, but it's how I'm doing it. You will make an index out of erasures, which will be e1*(k+m)+(e2). If there is no e2, then e2 = e1. Isn't that clever and confusing. Sorry. We're not going to worry about ordering -- in other words, the schedule for e1,e2 will be the same as e2,e1. They will have the same pointer -- the schedule will not be duplicated. */ if (m != 2) return NULL; scache = talloc(int **, (k+m)*(k+m+1)); if (scache == NULL) return NULL; for (e1 = 0; e1 < k+m; e1++) { erasures[0] = e1; for (e2 = 0; e2 < e1; e2++) { erasures[1] = e2; erasures[2] = -1; scache[e1*(k+m)+e2] = jerasure_generate_decoding_schedule(k, m, w, bitmatrix, erasures, smart); scache[e2*(k+m)+e1] = scache[e1*(k+m)+e2]; } erasures[1] = -1; scache[e1*(k+m)+e1] = jerasure_generate_decoding_schedule(k, m, w, bitmatrix, erasures, smart); } return scache; } int jerasure_invert_bitmatrix(int *mat, int *inv, int rows) { int cols, i, j, k; int tmp; cols = rows; k = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { inv[k] = (i == j) ? 1 : 0; k++; } } /* First -- convert into upper triangular */ for (i = 0; i < cols; i++) { /* Swap rows if we have a zero i,i element. If we can't swap, then the matrix was not invertible */ if ((mat[i*cols+i]) == 0) { for (j = i+1; j < rows && (mat[j*cols+i]) == 0; j++) ; if (j == rows) return -1; for (k = 0; k < cols; k++) { tmp = mat[i*cols+k]; mat[i*cols+k] = mat[j*cols+k]; mat[j*cols+k] = tmp; tmp = inv[i*cols+k]; inv[i*cols+k] = inv[j*cols+k]; inv[j*cols+k] = tmp; } } /* Now for each j>i, add A_ji*Ai to Aj */ for (j = i+1; j != rows; j++) { if (mat[j*cols+i] != 0) { for (k = 0; k < cols; k++) { mat[j*cols+k] ^= mat[i*cols+k]; inv[j*cols+k] ^= inv[i*cols+k]; } } } } /* Now the matrix is upper triangular. Start at the top and multiply down */ for (i = rows-1; i >= 0; i--) { for (j = 0; j < i; j++) { if (mat[j*cols+i]) { for (k = 0; k < cols; k++) { mat[j*cols+k] ^= mat[i*cols+k]; inv[j*cols+k] ^= inv[i*cols+k]; } } } } return 0; } int jerasure_invertible_bitmatrix(int *mat, int rows) { int cols, i, j, k; int tmp; cols = rows; /* First -- convert into upper triangular */ for (i = 0; i < cols; i++) { /* Swap rows if we have a zero i,i element. If we can't swap, then the matrix was not invertible */ if ((mat[i*cols+i]) == 0) { for (j = i+1; j < rows && (mat[j*cols+i]) == 0; j++) ; if (j == rows) return 0; for (k = 0; k < cols; k++) { tmp = mat[i*cols+k]; mat[i*cols+k] = mat[j*cols+k]; mat[j*cols+k] = tmp; } } /* Now for each j>i, add A_ji*Ai to Aj */ for (j = i+1; j != rows; j++) { if (mat[j*cols+i] != 0) { for (k = 0; k < cols; k++) { mat[j*cols+k] ^= mat[i*cols+k]; } } } } return 1; } int *jerasure_matrix_multiply(int *m1, int *m2, int r1, int c1, int r2, int c2, int w) { int *product, i, j, k; product = (int *) malloc(sizeof(int)*r1*c2); for (i = 0; i < r1*c2; i++) product[i] = 0; for (i = 0; i < r1; i++) { for (j = 0; j < c2; j++) { for (k = 0; k < r2; k++) { product[i*c2+j] ^= galois_single_multiply(m1[i*c1+k], m2[k*c2+j], w); } } } return product; } void jerasure_get_stats(double *fill_in) { fill_in[0] = jerasure_total_xor_bytes; fill_in[1] = jerasure_total_gf_bytes; fill_in[2] = jerasure_total_memcpy_bytes; jerasure_total_xor_bytes = 0; jerasure_total_gf_bytes = 0; jerasure_total_memcpy_bytes = 0; } void jerasure_do_scheduled_operations(char **ptrs, int **operations, int packetsize) { char *sptr; char *dptr; int op; for (op = 0; operations[op][0] >= 0; op++) { sptr = ptrs[operations[op][0]] + operations[op][1]*packetsize; dptr = ptrs[operations[op][2]] + operations[op][3]*packetsize; if (operations[op][4]) { /* printf("%d,%d %d,%d\n", operations[op][0], operations[op][1], operations[op][2], operations[op][3]); printf("xor(0x%x, 0x%x -> 0x%x, %d)\n", sptr, dptr, dptr, packetsize); */ galois_region_xor(sptr, dptr, packetsize); jerasure_total_xor_bytes += packetsize; } else { /* printf("memcpy(0x%x <- 0x%x)\n", dptr, sptr); */ memcpy(dptr, sptr, packetsize); jerasure_total_memcpy_bytes += packetsize; } } } void jerasure_schedule_encode(int k, int m, int w, int **schedule, char **data_ptrs, char **coding_ptrs, int size, int packetsize) { char **ptr_copy; int i, tdone; ptr_copy = talloc(char *, (k+m)); for (i = 0; i < k; i++) ptr_copy[i] = data_ptrs[i]; for (i = 0; i < m; i++) ptr_copy[i+k] = coding_ptrs[i]; for (tdone = 0; tdone < size; tdone += packetsize*w) { jerasure_do_scheduled_operations(ptr_copy, schedule, packetsize); for (i = 0; i < k+m; i++) ptr_copy[i] += (packetsize*w); } free(ptr_copy); } int **jerasure_dumb_bitmatrix_to_schedule(int k, int m, int w, int *bitmatrix) { int **operations; int op; int index, optodo, i, j; operations = talloc(int *, k*m*w*w+1); op = 0; index = 0; for (i = 0; i < m*w; i++) { optodo = 0; for (j = 0; j < k*w; j++) { if (bitmatrix[index]) { operations[op] = talloc(int, 5); operations[op][4] = optodo; operations[op][0] = j/w; operations[op][1] = j%w; operations[op][2] = k+i/w; operations[op][3] = i%w; optodo = 1; op++; } index++; } } operations[op] = talloc(int, 5); operations[op][0] = -1; return operations; } int **jerasure_smart_bitmatrix_to_schedule(int k, int m, int w, int *bitmatrix) { int **operations; int op; int i, j; int *diff, *from, *b1, *flink, *blink; int *ptr, no, row; int optodo; int bestrow = 0, bestdiff, top; /* printf("Scheduling:\n\n"); jerasure_print_bitmatrix(bitmatrix, m*w, k*w, w); */ operations = talloc(int *, k*m*w*w+1); op = 0; diff = talloc(int, m*w); from = talloc(int, m*w); flink = talloc(int, m*w); blink = talloc(int, m*w); ptr = bitmatrix; bestdiff = k*w+1; top = 0; for (i = 0; i < m*w; i++) { no = 0; for (j = 0; j < k*w; j++) { no += *ptr; ptr++; } diff[i] = no; from[i] = -1; flink[i] = i+1; blink[i] = i-1; if (no < bestdiff) { bestdiff = no; bestrow = i; } } flink[m*w-1] = -1; while (top != -1) { row = bestrow; /* printf("Doing row %d - %d from %d\n", row, diff[row], from[row]); */ if (blink[row] == -1) { top = flink[row]; if (top != -1) blink[top] = -1; } else { flink[blink[row]] = flink[row]; if (flink[row] != -1) { blink[flink[row]] = blink[row]; } } ptr = bitmatrix + row*k*w; if (from[row] == -1) { optodo = 0; for (j = 0; j < k*w; j++) { if (ptr[j]) { operations[op] = talloc(int, 5); operations[op][4] = optodo; operations[op][0] = j/w; operations[op][1] = j%w; operations[op][2] = k+row/w; operations[op][3] = row%w; optodo = 1; op++; } } } else { operations[op] = talloc(int, 5); operations[op][4] = 0; operations[op][0] = k+from[row]/w; operations[op][1] = from[row]%w; operations[op][2] = k+row/w; operations[op][3] = row%w; op++; b1 = bitmatrix + from[row]*k*w; for (j = 0; j < k*w; j++) { if (ptr[j] ^ b1[j]) { operations[op] = talloc(int, 5); operations[op][4] = 1; operations[op][0] = j/w; operations[op][1] = j%w; operations[op][2] = k+row/w; operations[op][3] = row%w; optodo = 1; op++; } } } bestdiff = k*w+1; for (i = top; i != -1; i = flink[i]) { no = 1; b1 = bitmatrix + i*k*w; for (j = 0; j < k*w; j++) no += (ptr[j] ^ b1[j]); if (no < diff[i]) { from[i] = row; diff[i] = no; } if (diff[i] < bestdiff) { bestdiff = diff[i]; bestrow = i; } } } operations[op] = talloc(int, 5); operations[op][0] = -1; free(from); free(diff); free(blink); free(flink); return operations; } void jerasure_bitmatrix_encode(int k, int m, int w, int *bitmatrix, char **data_ptrs, char **coding_ptrs, int size, int packetsize) { int i; if (packetsize%sizeof(long) != 0) { fprintf(stderr, "jerasure_bitmatrix_encode - packetsize(%d) %c sizeof(long) != 0\n", packetsize, '%'); exit(1); } if (size%(packetsize*w) != 0) { fprintf(stderr, "jerasure_bitmatrix_encode - size(%d) %c (packetsize(%d)*w(%d))) != 0\n", size, '%', packetsize, w); exit(1); } for (i = 0; i < m; i++) { jerasure_bitmatrix_dotprod(k, w, bitmatrix+i*k*w*w, NULL, k+i, data_ptrs, coding_ptrs, size, packetsize); } } /* * Exported function for use by autoconf to perform quick * spot-check. */ int jerasure_autoconf_test() { int x = galois_single_multiply(1, 2, 8); if (x != 2) { return -1; } return 0; } ceph-0.80.11/src/erasure-code/jerasure/jerasure/src/liberation.c0000664000175100017510000001552412623076752026573 0ustar jenkins-buildjenkins-build/* * * Copyright (c) 2014, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * 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 the University of Tennessee 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 * HOLDER 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. */ /* Jerasure's authors: Revision 2.x - 2014: James S. Plank and Kevin M. Greenan Revision 1.2 - 2008: James S. Plank, Scott Simmerman and Catherine D. Schuman. Revision 1.0 - 2007: James S. Plank */ #include #include #include #include "galois.h" #include "jerasure.h" #include "liberation.h" #define talloc(type, num) (type *) malloc(sizeof(type)*(num)) int *liberation_coding_bitmatrix(int k, int w) { int *matrix, i, j, index; if (k > w) return NULL; matrix = talloc(int, 2*k*w*w); if (matrix == NULL) return NULL; bzero(matrix, sizeof(int)*2*k*w*w); /* Set up identity matrices */ for(i = 0; i < w; i++) { index = i*k*w+i; for (j = 0; j < k; j++) { matrix[index] = 1; index += w; } } /* Set up liberation matrices */ for (j = 0; j < k; j++) { index = k*w*w+j*w; for (i = 0; i < w; i++) { matrix[index+(j+i)%w] = 1; index += (k*w); } if (j > 0) { i = (j*((w-1)/2))%w; matrix[k*w*w+j*w+i*k*w+(i+j-1)%w] = 1; } } return matrix; } int *liber8tion_coding_bitmatrix(int k) { int *matrix, i, j, index; int w; w = 8; if (k > w) return NULL; matrix = talloc(int, 2*k*w*w); if (matrix == NULL) return NULL; bzero(matrix, sizeof(int)*2*k*w*w); /* Set up identity matrices */ for(i = 0; i < w; i++) { index = i*k*w+i; for (j = 0; j < k; j++) { matrix[index] = 1; index += w; } } /* Set up liber8tion matrices */ index = k*w*w; if (k == 0) return matrix; matrix[index+0*k*w+0*w+0] = 1; matrix[index+1*k*w+0*w+1] = 1; matrix[index+2*k*w+0*w+2] = 1; matrix[index+3*k*w+0*w+3] = 1; matrix[index+4*k*w+0*w+4] = 1; matrix[index+5*k*w+0*w+5] = 1; matrix[index+6*k*w+0*w+6] = 1; matrix[index+7*k*w+0*w+7] = 1; if (k == 1) return matrix; matrix[index+0*k*w+1*w+7] = 1; matrix[index+1*k*w+1*w+3] = 1; matrix[index+2*k*w+1*w+0] = 1; matrix[index+3*k*w+1*w+2] = 1; matrix[index+4*k*w+1*w+6] = 1; matrix[index+5*k*w+1*w+1] = 1; matrix[index+6*k*w+1*w+5] = 1; matrix[index+7*k*w+1*w+4] = 1; matrix[index+4*k*w+1*w+7] = 1; if (k == 2) return matrix; matrix[index+0*k*w+2*w+6] = 1; matrix[index+1*k*w+2*w+2] = 1; matrix[index+2*k*w+2*w+4] = 1; matrix[index+3*k*w+2*w+0] = 1; matrix[index+4*k*w+2*w+7] = 1; matrix[index+5*k*w+2*w+3] = 1; matrix[index+6*k*w+2*w+1] = 1; matrix[index+7*k*w+2*w+5] = 1; matrix[index+1*k*w+2*w+3] = 1; if (k == 3) return matrix; matrix[index+0*k*w+3*w+2] = 1; matrix[index+1*k*w+3*w+5] = 1; matrix[index+2*k*w+3*w+7] = 1; matrix[index+3*k*w+3*w+6] = 1; matrix[index+4*k*w+3*w+0] = 1; matrix[index+5*k*w+3*w+3] = 1; matrix[index+6*k*w+3*w+4] = 1; matrix[index+7*k*w+3*w+1] = 1; matrix[index+5*k*w+3*w+4] = 1; if (k == 4) return matrix; matrix[index+0*k*w+4*w+5] = 1; matrix[index+1*k*w+4*w+6] = 1; matrix[index+2*k*w+4*w+1] = 1; matrix[index+3*k*w+4*w+7] = 1; matrix[index+4*k*w+4*w+2] = 1; matrix[index+5*k*w+4*w+4] = 1; matrix[index+6*k*w+4*w+3] = 1; matrix[index+7*k*w+4*w+0] = 1; matrix[index+2*k*w+4*w+0] = 1; if (k == 5) return matrix; matrix[index+0*k*w+5*w+1] = 1; matrix[index+1*k*w+5*w+2] = 1; matrix[index+2*k*w+5*w+3] = 1; matrix[index+3*k*w+5*w+4] = 1; matrix[index+4*k*w+5*w+5] = 1; matrix[index+5*k*w+5*w+6] = 1; matrix[index+6*k*w+5*w+7] = 1; matrix[index+7*k*w+5*w+0] = 1; matrix[index+7*k*w+5*w+2] = 1; if (k == 6) return matrix; matrix[index+0*k*w+6*w+3] = 1; matrix[index+1*k*w+6*w+0] = 1; matrix[index+2*k*w+6*w+6] = 1; matrix[index+3*k*w+6*w+5] = 1; matrix[index+4*k*w+6*w+1] = 1; matrix[index+5*k*w+6*w+7] = 1; matrix[index+6*k*w+6*w+4] = 1; matrix[index+7*k*w+6*w+2] = 1; matrix[index+6*k*w+6*w+5] = 1; if (k == 7) return matrix; matrix[index+0*k*w+7*w+4] = 1; matrix[index+1*k*w+7*w+7] = 1; matrix[index+2*k*w+7*w+1] = 1; matrix[index+3*k*w+7*w+5] = 1; matrix[index+4*k*w+7*w+3] = 1; matrix[index+5*k*w+7*w+2] = 1; matrix[index+6*k*w+7*w+0] = 1; matrix[index+7*k*w+7*w+6] = 1; matrix[index+3*k*w+7*w+1] = 1; return matrix; } int *blaum_roth_coding_bitmatrix(int k, int w) { int *matrix, i, j, index, l, m, p; if (k > w) return NULL ; matrix = talloc(int, 2*k*w*w); if (matrix == NULL) return NULL; bzero(matrix, sizeof(int)*2*k*w*w); /* Set up identity matrices */ for(i = 0; i < w; i++) { index = i*k*w+i; for (j = 0; j < k; j++) { matrix[index] = 1; index += w; } } /* Set up blaum_roth matrices -- Ignore identity */ p = w+1; for (j = 0; j < k; j++) { index = k*w*w+j*w; if (j == 0) { for (l = 0; l < w; l++) { matrix[index+l] = 1; index += k*w; } } else { i = j; for (l = 1; l <= w; l++) { if (l != p-i) { m = l+i; if (m >= p) m -= p; m--; matrix[index+m] = 1; } else { matrix[index+i-1] = 1; if (i%2 == 0) { m = i/2; } else { m = (p/2) + 1 + (i/2); } m--; matrix[index+m] = 1; } index += k*w; } } } return matrix; } ceph-0.80.11/src/erasure-code/jerasure/ErasureCodeJerasure.h0000664000175100017510000001633512623076744025745 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #ifndef CEPH_ERASURE_CODE_JERASURE_H #define CEPH_ERASURE_CODE_JERASURE_H #include "erasure-code/ErasureCodeInterface.h" class ErasureCodeJerasure : public ErasureCodeInterface { public: int k; int m; int w; const char *technique; string ruleset_root; string ruleset_failure_domain; ErasureCodeJerasure(const char *_technique) : technique(_technique), ruleset_root("default"), ruleset_failure_domain("host") {} virtual ~ErasureCodeJerasure() {} virtual int create_ruleset(const string &name, CrushWrapper &crush, ostream *ss) const; virtual unsigned int get_chunk_count() const { return k + m; } virtual unsigned int get_data_chunk_count() const { return k; } virtual unsigned int get_chunk_size(unsigned int object_size) const; virtual int minimum_to_decode(const set &want_to_read, const set &available_chunks, set *minimum); virtual int minimum_to_decode_with_cost(const set &want_to_read, const map &available, set *minimum); virtual int encode(const set &want_to_encode, const bufferlist &in, map *encoded); virtual int decode(const set &want_to_read, const map &chunks, map *decoded); void init(const map ¶meters); virtual void jerasure_encode(char **data, char **coding, int blocksize) = 0; virtual int jerasure_decode(int *erasures, char **data, char **coding, int blocksize) = 0; virtual unsigned get_alignment() const = 0; virtual void parse(const map ¶meters) = 0; virtual void prepare() = 0; static int to_int(const std::string &name, const map ¶meters, int default_value); static bool is_prime(int value); }; class ErasureCodeJerasureReedSolomonVandermonde : public ErasureCodeJerasure { public: static const int DEFAULT_K = 7; static const int DEFAULT_M = 3; static const int DEFAULT_W = 8; int *matrix; ErasureCodeJerasureReedSolomonVandermonde() : ErasureCodeJerasure("reed_sol_van"), matrix(0) { } virtual ~ErasureCodeJerasureReedSolomonVandermonde() { if (matrix) free(matrix); } virtual void jerasure_encode(char **data, char **coding, int blocksize); virtual int jerasure_decode(int *erasures, char **data, char **coding, int blocksize); virtual unsigned get_alignment() const; virtual void parse(const map ¶meters); virtual void prepare(); }; class ErasureCodeJerasureReedSolomonRAID6 : public ErasureCodeJerasure { public: static const int DEFAULT_K = 7; static const int DEFAULT_W = 8; int *matrix; ErasureCodeJerasureReedSolomonRAID6() : ErasureCodeJerasure("reed_sol_r6_op"), matrix(0) { } virtual ~ErasureCodeJerasureReedSolomonRAID6() { if (matrix) free(matrix); } virtual void jerasure_encode(char **data, char **coding, int blocksize); virtual int jerasure_decode(int *erasures, char **data, char **coding, int blocksize); virtual unsigned get_alignment() const; virtual void parse(const map ¶meters); virtual void prepare(); }; class ErasureCodeJerasureCauchy : public ErasureCodeJerasure { public: static const int DEFAULT_K = 7; static const int DEFAULT_M = 3; static const int DEFAULT_W = 8; static const int DEFAULT_PACKETSIZE = 2048; int *bitmatrix; int **schedule; int packetsize; ErasureCodeJerasureCauchy(const char *technique) : ErasureCodeJerasure(technique), bitmatrix(0), schedule(0) { } virtual ~ErasureCodeJerasureCauchy() { if (bitmatrix) free(bitmatrix); if (schedule) free(schedule); } virtual void jerasure_encode(char **data, char **coding, int blocksize); virtual int jerasure_decode(int *erasures, char **data, char **coding, int blocksize); virtual unsigned get_alignment() const; virtual void parse(const map ¶meters); void prepare_schedule(int *matrix); }; class ErasureCodeJerasureCauchyOrig : public ErasureCodeJerasureCauchy { public: ErasureCodeJerasureCauchyOrig() : ErasureCodeJerasureCauchy("cauchy_orig") {} virtual void prepare(); }; class ErasureCodeJerasureCauchyGood : public ErasureCodeJerasureCauchy { public: ErasureCodeJerasureCauchyGood() : ErasureCodeJerasureCauchy("cauchy_good") {} virtual void prepare(); }; class ErasureCodeJerasureLiberation : public ErasureCodeJerasure { public: static const int DEFAULT_K = 2; static const int DEFAULT_M = 2; static const int DEFAULT_W = 7; static const int DEFAULT_PACKETSIZE = 2048; int *bitmatrix; int **schedule; int packetsize; ErasureCodeJerasureLiberation(const char *technique = "liberation") : ErasureCodeJerasure(technique), bitmatrix(0), schedule(0) { } virtual ~ErasureCodeJerasureLiberation(); virtual void jerasure_encode(char **data, char **coding, int blocksize); virtual int jerasure_decode(int *erasures, char **data, char **coding, int blocksize); virtual unsigned get_alignment() const; virtual void parse(const map ¶meters); virtual void prepare(); }; class ErasureCodeJerasureBlaumRoth : public ErasureCodeJerasureLiberation { public: ErasureCodeJerasureBlaumRoth() : ErasureCodeJerasureLiberation("blaum_roth") {} virtual void prepare(); }; class ErasureCodeJerasureLiber8tion : public ErasureCodeJerasureLiberation { public: static const int DEFAULT_K = 2; static const int DEFAULT_M = 2; static const int DEFAULT_W = 8; ErasureCodeJerasureLiber8tion() : ErasureCodeJerasureLiberation("liber8tion") {} virtual void parse(const map ¶meters); virtual void prepare(); }; #endif ceph-0.80.11/src/erasure-code/jerasure/Makefile.am0000664000175100017510000001041112623076744023713 0ustar jenkins-buildjenkins-build# jerasure plugin noinst_HEADERS += \ erasure-code/jerasure/jerasure/include/cauchy.h \ erasure-code/jerasure/jerasure/include/galois.h \ erasure-code/jerasure/jerasure/include/jerasure.h \ erasure-code/jerasure/jerasure/include/liberation.h \ erasure-code/jerasure/jerasure/include/reed_sol.h \ erasure-code/jerasure/gf-complete/include/gf_int.h \ erasure-code/jerasure/gf-complete/include/gf_complete.h \ erasure-code/jerasure/gf-complete/include/gf_rand.h \ erasure-code/jerasure/gf-complete/include/gf_method.h \ erasure-code/jerasure/gf-complete/include/gf_general.h \ erasure-code/jerasure/ErasureCodeJerasure.h jerasure_sources = \ erasure-code/jerasure/jerasure/src/cauchy.c \ erasure-code/jerasure/jerasure/src/galois.c \ erasure-code/jerasure/jerasure/src/jerasure.c \ erasure-code/jerasure/jerasure/src/liberation.c \ erasure-code/jerasure/jerasure/src/reed_sol.c \ erasure-code/jerasure/gf-complete/src/gf_wgen.c \ erasure-code/jerasure/gf-complete/src/gf_method.c \ erasure-code/jerasure/gf-complete/src/gf_w16.c \ erasure-code/jerasure/gf-complete/src/gf.c \ erasure-code/jerasure/gf-complete/src/gf_w32.c \ erasure-code/jerasure/gf-complete/src/gf_w64.c \ erasure-code/jerasure/gf-complete/src/gf_w128.c \ erasure-code/jerasure/gf-complete/src/gf_general.c \ erasure-code/jerasure/gf-complete/src/gf_w4.c \ erasure-code/jerasure/gf-complete/src/gf_rand.c \ erasure-code/jerasure/gf-complete/src/gf_w8.c \ erasure-code/jerasure/ErasureCodePluginJerasure.cc \ erasure-code/jerasure/ErasureCodeJerasure.cc libec_jerasure_generic_la_SOURCES = ${jerasure_sources} libec_jerasure_generic_la_CFLAGS = ${AM_CFLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_generic_la_CXXFLAGS= ${AM_CXXFLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_generic_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_generic_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 if LINUX libec_jerasure_generic_la_LDFLAGS += -export-symbols-regex '.*__erasure_code_.*' endif erasure_codelib_LTLIBRARIES += libec_jerasure_generic.la libec_jerasure_sse3_la_SOURCES = ${jerasure_sources} libec_jerasure_sse3_la_CFLAGS = ${AM_CFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse3_la_CXXFLAGS= ${AM_CXXFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse3_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_sse3_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 if LINUX libec_jerasure_sse3_la_LDFLAGS += -export-symbols-regex '.*__erasure_code_.*' endif erasure_codelib_LTLIBRARIES += libec_jerasure_sse3.la libec_jerasure_sse4_la_SOURCES = ${jerasure_sources} libec_jerasure_sse4_la_CFLAGS = ${AM_CFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ ${INTEL_SSE4_1_FLAGS} \ ${INTEL_SSE4_2_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse4_la_CXXFLAGS= ${AM_CXXFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ ${INTEL_SSE4_1_FLAGS} \ ${INTEL_SSE4_2_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse4_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_sse4_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 if LINUX libec_jerasure_sse4_la_LDFLAGS += -export-symbols-regex '.*__erasure_code_.*' endif erasure_codelib_LTLIBRARIES += libec_jerasure_sse4.la libec_jerasure_la_SOURCES = \ erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc libec_jerasure_la_CFLAGS = ${AM_CFLAGS} libec_jerasure_la_CXXFLAGS= ${AM_CXXFLAGS} libec_jerasure_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 if LINUX libec_jerasure_la_LDFLAGS += -export-symbols-regex '.*__erasure_code_.*' endif erasure_codelib_LTLIBRARIES += libec_jerasure.la ceph-0.80.11/src/erasure-code/jerasure/gf-complete/0000775000175100017510000000000012623077033024054 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/gf-complete/include/0000775000175100017510000000000012623077034025500 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/gf-complete/include/gf_method.h0000664000175100017510000000110112623076752027604 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_method.h * * Parses argv to figure out the flags and arguments. Creates the gf. */ #pragma once #include "gf_complete.h" /* Parses argv starting at "starting". Returns 0 on failure. On success, it returns one past the last argument it read in argv. */ extern int create_gf_from_argv(gf_t *gf, int w, int argc, char **argv, int starting); ceph-0.80.11/src/erasure-code/jerasure/gf-complete/include/gf_int.h0000664000175100017510000002304312623076752027127 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_int.h * * Internal code for Galois field routines. This is not meant for * users to include, but for the internal GF files to use. */ #pragma once #include "gf_complete.h" #include extern void timer_start (double *t); extern double timer_split (const double *t); extern void galois_fill_random (void *buf, int len, unsigned int seed); typedef struct { int mult_type; int region_type; int divide_type; int w; uint64_t prim_poly; int free_me; int arg1; int arg2; gf_t *base_gf; void *private; } gf_internal_t; extern int gf_w4_init (gf_t *gf); extern int gf_w4_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2); extern int gf_w8_init (gf_t *gf); extern int gf_w8_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2); extern int gf_w16_init (gf_t *gf); extern int gf_w16_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2); extern int gf_w32_init (gf_t *gf); extern int gf_w32_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2); extern int gf_w64_init (gf_t *gf); extern int gf_w64_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2); extern int gf_w128_init (gf_t *gf); extern int gf_w128_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2); extern int gf_wgen_init (gf_t *gf); extern int gf_wgen_scratch_size(int w, int mult_type, int region_type, int divide_type, int arg1, int arg2); void gf_wgen_cauchy_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor); gf_val_32_t gf_wgen_extract_word(gf_t *gf, void *start, int bytes, int index); extern void gf_alignment_error(char *s, int a); extern uint32_t gf_bitmatrix_inverse(uint32_t y, int w, uint32_t pp); /* This returns the correct default for prim_poly when base is used as the base field for COMPOSITE. It returns 0 if we don't have a default prim_poly. */ extern uint64_t gf_composite_get_default_poly(gf_t *base); /* This structure lets you define a region multiply. It helps because you can handle unaligned portions of the data with the procedures below, which really cleans up the code. */ typedef struct { gf_t *gf; void *src; void *dest; int bytes; uint64_t val; int xor; int align; /* The number of bytes to which to align. */ void *s_start; /* The start and the top of the aligned region. */ void *d_start; void *s_top; void *d_top; } gf_region_data; /* This lets you set up one of these in one call. It also sets the start/top pointers. */ void gf_set_region_data(gf_region_data *rd, gf_t *gf, void *src, void *dest, int bytes, uint64_t val, int xor, int align); /* This performs gf->multiply.32() on all of the unaligned bytes in the beginning of the region */ extern void gf_do_initial_region_alignment(gf_region_data *rd); /* This performs gf->multiply.32() on all of the unaligned bytes in the end of the region */ extern void gf_do_final_region_alignment(gf_region_data *rd); extern void gf_two_byte_region_table_multiply(gf_region_data *rd, uint16_t *base); extern void gf_multby_zero(void *dest, int bytes, int xor); extern void gf_multby_one(void *src, void *dest, int bytes, int xor); typedef enum {GF_E_MDEFDIV, /* Dev != Default && Mult == Default */ GF_E_MDEFREG, /* Reg != Default && Mult == Default */ GF_E_MDEFARG, /* Args != Default && Mult == Default */ GF_E_DIVCOMP, /* Mult == Composite && Div != Default */ GF_E_CAUCOMP, /* Mult == Composite && Reg == CAUCHY */ GF_E_DOUQUAD, /* Reg == DOUBLE && Reg == QUAD */ GF_E_SSE__NO, /* Reg == SSE && Reg == NOSSE */ GF_E_CAUCHYB, /* Reg == CAUCHY && Other Reg */ GF_E_CAUGT32, /* Reg == CAUCHY && w > 32*/ GF_E_ARG1SET, /* Arg1 != 0 && Mult \notin COMPOSITE/SPLIT/GROUP */ GF_E_ARG2SET, /* Arg2 != 0 && Mult \notin SPLIT/GROUP */ GF_E_MATRIXW, /* Div == MATRIX && w > 32 */ GF_E_BAD___W, /* Illegal w */ GF_E_DOUBLET, /* Reg == DOUBLE && Mult != TABLE */ GF_E_DOUBLEW, /* Reg == DOUBLE && w \notin {4,8} */ GF_E_DOUBLEJ, /* Reg == DOUBLE && other Reg */ GF_E_DOUBLEL, /* Reg == DOUBLE & LAZY but w = 4 */ GF_E_QUAD__T, /* Reg == QUAD && Mult != TABLE */ GF_E_QUAD__W, /* Reg == QUAD && w != 4 */ GF_E_QUAD__J, /* Reg == QUAD && other Reg */ GF_E_LAZY__X, /* Reg == LAZY && not DOUBLE or QUAD*/ GF_E_ALTSHIF, /* Mult == Shift && Reg == ALTMAP */ GF_E_SSESHIF, /* Mult == Shift && Reg == SSE|NOSSE */ GF_E_ALT_CFM, /* Mult == CARRY_FREE && Reg == ALTMAP */ GF_E_SSE_CFM, /* Mult == CARRY_FREE && Reg == SSE|NOSSE */ GF_E_PCLMULX, /* Mult == Carry_Free && No PCLMUL */ GF_E_ALT_BY2, /* Mult == Bytwo_x && Reg == ALTMAP */ GF_E_BY2_SSE, /* Mult == Bytwo_x && Reg == SSE && No SSE2 */ GF_E_LOGBADW, /* Mult == LOGx, w too big*/ GF_E_LOG___J, /* Mult == LOGx, && Reg == SSE|ALTMAP|NOSSE */ GF_E_ZERBADW, /* Mult == LOG_ZERO, w \notin {8,16} */ GF_E_ZEXBADW, /* Mult == LOG_ZERO_EXT, w != 8 */ GF_E_LOGPOLY, /* Mult == LOG & poly not primitive */ GF_E_GR_ARGX, /* Mult == GROUP, Bad arg1/2 */ GF_E_GR_W_48, /* Mult == GROUP, w \in { 4, 8 } */ GF_E_GR_W_16, /* Mult == GROUP, w == 16, arg1 != 4 || arg2 != 4 */ GF_E_GR_128A, /* Mult == GROUP, w == 128, bad args */ GF_E_GR_A_27, /* Mult == GROUP, either arg > 27 */ GF_E_GR_AR_W, /* Mult == GROUP, either arg > w */ GF_E_GR____J, /* Mult == GROUP, Reg == SSE|ALTMAP|NOSSE */ GF_E_TABLE_W, /* Mult == TABLE, w too big */ GF_E_TAB_SSE, /* Mult == TABLE, SSE|NOSSE only apply to w == 4 */ GF_E_TABSSE3, /* Mult == TABLE, Need SSSE3 for SSE */ GF_E_TAB_ALT, /* Mult == TABLE, Reg == ALTMAP */ GF_E_SP128AR, /* Mult == SPLIT, w=128, Bad arg1/arg2 */ GF_E_SP128AL, /* Mult == SPLIT, w=128, SSE requires ALTMAP */ GF_E_SP128AS, /* Mult == SPLIT, w=128, ALTMAP requires SSE */ GF_E_SP128_A, /* Mult == SPLIT, w=128, SSE only with 4/128 */ GF_E_SP128_S, /* Mult == SPLIT, w=128, ALTMAP only with 4/128 */ GF_E_SPLIT_W, /* Mult == SPLIT, Bad w (8, 16, 32, 64, 128) */ GF_E_SP_16AR, /* Mult == SPLIT, w=16, Bad arg1/arg2 */ GF_E_SP_16_A, /* Mult == SPLIT, w=16, ALTMAP only with 4/16 */ GF_E_SP_16_S, /* Mult == SPLIT, w=16, SSE only with 4/16 */ GF_E_SP_32AR, /* Mult == SPLIT, w=32, Bad arg1/arg2 */ GF_E_SP_32AS, /* Mult == SPLIT, w=32, ALTMAP requires SSE */ GF_E_SP_32_A, /* Mult == SPLIT, w=32, ALTMAP only with 4/32 */ GF_E_SP_32_S, /* Mult == SPLIT, w=32, SSE only with 4/32 */ GF_E_SP_64AR, /* Mult == SPLIT, w=64, Bad arg1/arg2 */ GF_E_SP_64AS, /* Mult == SPLIT, w=64, ALTMAP requires SSE */ GF_E_SP_64_A, /* Mult == SPLIT, w=64, ALTMAP only with 4/64 */ GF_E_SP_64_S, /* Mult == SPLIT, w=64, SSE only with 4/64 */ GF_E_SP_8_AR, /* Mult == SPLIT, w=8, Bad arg1/arg2 */ GF_E_SP_8__A, /* Mult == SPLIT, w=8, no ALTMAP */ GF_E_SP_SSE3, /* Mult == SPLIT, Need SSSE3 for SSE */ GF_E_COMP_A2, /* Mult == COMP, arg1 must be = 2 */ GF_E_COMP_SS, /* Mult == COMP, SSE|NOSSE */ GF_E_COMP__W, /* Mult == COMP, Bad w. */ GF_E_UNKFLAG, /* Unknown flag in create_from.... */ GF_E_UNKNOWN, /* Unknown mult_type. */ GF_E_UNK_REG, /* Unknown region_type. */ GF_E_UNK_DIV, /* Unknown divide_type. */ GF_E_CFM___W, /* Mult == CFM, Bad w. */ GF_E_CFM4POL, /* Mult == CFM & Prim Poly has high bits set. */ GF_E_CFM8POL, /* Mult == CFM & Prim Poly has high bits set. */ GF_E_CF16POL, /* Mult == CFM & Prim Poly has high bits set. */ GF_E_CF32POL, /* Mult == CFM & Prim Poly has high bits set. */ GF_E_CF64POL, /* Mult == CFM & Prim Poly has high bits set. */ GF_E_FEWARGS, /* Too few args in argc/argv. */ GF_E_BADPOLY, /* Bad primitive polynomial -- too many bits set. */ GF_E_COMP_PP, /* Bad primitive polynomial -- bigger than sub-field. */ GF_E_COMPXPP, /* Can't derive a default pp for composite field. */ GF_E_BASE__W, /* Composite -- Base field is the wrong size. */ GF_E_TWOMULT, /* In create_from... two -m's. */ GF_E_TWO_DIV, /* In create_from... two -d's. */ GF_E_POLYSPC, /* Bad numbera after -p. */ GF_E_SPLITAR, /* Ran out of arguments in SPLIT */ GF_E_SPLITNU, /* Arguments not integers in SPLIT. */ GF_E_GROUPAR, /* Ran out of arguments in GROUP */ GF_E_GROUPNU, /* Arguments not integers in GROUP. */ GF_E_DEFAULT } gf_error_type_t; ceph-0.80.11/src/erasure-code/jerasure/gf-complete/include/gf_complete.h0000664000175100017510000001446712623076752030157 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_complete.h * * The main include file for gf_complete. */ #ifndef _GF_COMPLETE_H_ #define _GF_COMPLETE_H_ #include #ifdef INTEL_SSE4 #include #endif #ifdef INTEL_SSSE3 #include #endif #ifdef INTEL_SSE2 #include #endif #ifdef INTEL_SSE4_PCLMUL #include #endif /* These are the different ways to perform multiplication. Not all are implemented for all values of w. See the paper for an explanation of how they work. */ typedef enum {GF_MULT_DEFAULT, GF_MULT_SHIFT, GF_MULT_CARRY_FREE, GF_MULT_GROUP, GF_MULT_BYTWO_p, GF_MULT_BYTWO_b, GF_MULT_TABLE, GF_MULT_LOG_TABLE, GF_MULT_LOG_ZERO, GF_MULT_LOG_ZERO_EXT, GF_MULT_SPLIT_TABLE, GF_MULT_COMPOSITE } gf_mult_type_t; /* These are the different ways to optimize region operations. They are bits because you can compose them. Certain optimizations only apply to certain gf_mult_type_t's. Again, please see documentation for how to use these */ #define GF_REGION_DEFAULT (0x0) #define GF_REGION_DOUBLE_TABLE (0x1) #define GF_REGION_QUAD_TABLE (0x2) #define GF_REGION_LAZY (0x4) #define GF_REGION_SSE (0x8) #define GF_REGION_NOSSE (0x10) #define GF_REGION_ALTMAP (0x20) #define GF_REGION_CAUCHY (0x40) typedef uint32_t gf_region_type_t; /* These are different ways to implement division. Once again, it's best to use "DEFAULT". However, there are times when you may want to experiment with the others. */ typedef enum { GF_DIVIDE_DEFAULT, GF_DIVIDE_MATRIX, GF_DIVIDE_EUCLID } gf_division_type_t; /* We support w=4,8,16,32,64 and 128 with their own data types and operations for multiplication, division, etc. We also support a "gen" type so that you can do general gf arithmetic for any value of w from 1 to 32. You can perform a "region" operation on these if you use "CAUCHY" as the mapping. */ typedef uint32_t gf_val_32_t; typedef uint64_t gf_val_64_t; typedef uint64_t *gf_val_128_t; extern int _gf_errno; extern void gf_error(); typedef struct gf *GFP; typedef union gf_func_a_b { gf_val_32_t (*w32) (GFP gf, gf_val_32_t a, gf_val_32_t b); gf_val_64_t (*w64) (GFP gf, gf_val_64_t a, gf_val_64_t b); void (*w128)(GFP gf, gf_val_128_t a, gf_val_128_t b, gf_val_128_t c); } gf_func_a_b; typedef union { gf_val_32_t (*w32) (GFP gf, gf_val_32_t a); gf_val_64_t (*w64) (GFP gf, gf_val_64_t a); void (*w128)(GFP gf, gf_val_128_t a, gf_val_128_t b); } gf_func_a; typedef union { void (*w32) (GFP gf, void *src, void *dest, gf_val_32_t val, int bytes, int add); void (*w64) (GFP gf, void *src, void *dest, gf_val_64_t val, int bytes, int add); void (*w128)(GFP gf, void *src, void *dest, gf_val_128_t val, int bytes, int add); } gf_region; typedef union { gf_val_32_t (*w32) (GFP gf, void *start, int bytes, int index); gf_val_64_t (*w64) (GFP gf, void *start, int bytes, int index); void (*w128)(GFP gf, void *start, int bytes, int index, gf_val_128_t rv); } gf_extract; typedef struct gf { gf_func_a_b multiply; gf_func_a_b divide; gf_func_a inverse; gf_region multiply_region; gf_extract extract_word; void *scratch; } gf_t; /* Initializes the GF to defaults. Pass it a pointer to a gf_t. Returns 0 on failure, 1 on success. */ extern int gf_init_easy(GFP gf, int w); /* Initializes the GF changing the defaults. Returns 0 on failure, 1 on success. Pass it a pointer to a gf_t. For mult_type and divide_type, use one of gf_mult_type_t gf_divide_type_t . For region_type, OR together the GF_REGION_xxx's defined above. Use 0 as prim_poly for defaults. Otherwise, the leading 1 is optional. Use NULL for scratch_memory to have init_hard allocate memory. Otherwise, use gf_scratch_size() to determine how big scratch_memory has to be. */ extern int gf_init_hard(GFP gf, int w, int mult_type, int region_type, int divide_type, uint64_t prim_poly, int arg1, int arg2, GFP base_gf, void *scratch_memory); /* Determines the size for scratch_memory. Returns 0 on failure and non-zero on success. */ extern int gf_scratch_size(int w, int mult_type, int region_type, int divide_type, int arg1, int arg2); /* This reports the gf_scratch_size of a gf_t that has already been created */ extern int gf_size(GFP gf); /* Frees scratch memory if gf_init_easy/gf_init_hard called malloc. If recursive = 1, then it calls itself recursively on base_gf. */ extern int gf_free(GFP gf, int recursive); /* This is support for inline single multiplications and divisions. I know it's yucky, but if you've got to be fast, you've got to be fast. We support inlining for w=4, w=8 and w=16. To use inline multiplication and division with w=4 or 8, you should use the default gf_t, or one with a single table. Otherwise, gf_w4/8_get_mult_table() will return NULL. Similarly, with w=16, the gf_t must be LOG */ uint8_t *gf_w4_get_mult_table(GFP gf); uint8_t *gf_w4_get_div_table(GFP gf); #define GF_W4_INLINE_MULTDIV(table, a, b) (table[((a)<<4)|(b)]) uint8_t *gf_w8_get_mult_table(GFP gf); uint8_t *gf_w8_get_div_table(GFP gf); #define GF_W8_INLINE_MULTDIV(table, a, b) (table[(((uint32_t) (a))<<8)|(b)]) uint16_t *gf_w16_get_log_table(GFP gf); uint16_t *gf_w16_get_mult_alog_table(GFP gf); uint16_t *gf_w16_get_div_alog_table(GFP gf); #define GF_W16_INLINE_MULT(log, alog, a, b) ((a) == 0 || (b) == 0) ? 0 : (alog[(uint32_t)log[a]+(uint32_t)log[b]]) #define GF_W16_INLINE_DIV(log, alog, a, b) ((a) == 0 || (b) == 0) ? 0 : (alog[(int)log[a]-(int)log[b]]) #endif ceph-0.80.11/src/erasure-code/jerasure/gf-complete/include/gf_general.h0000664000175100017510000000425012623076752027751 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_general.h * * This file has helper routines for doing basic GF operations with any * legal value of w. The problem is that w <= 32, w=64 and w=128 all have * different data types, which is a pain. The procedures in this file try * to alleviate that pain. They are used in gf_unit and gf_time. */ #pragma once #include #include #include #include #include #include #include "gf_complete.h" typedef union { uint32_t w32; uint64_t w64; uint64_t w128[2]; } gf_general_t; void gf_general_set_zero(gf_general_t *v, int w); void gf_general_set_one(gf_general_t *v, int w); void gf_general_set_two(gf_general_t *v, int w); int gf_general_is_zero(gf_general_t *v, int w); int gf_general_is_one(gf_general_t *v, int w); int gf_general_are_equal(gf_general_t *v1, gf_general_t *v2, int w); void gf_general_val_to_s(gf_general_t *v, int w, char *s, int hex); int gf_general_s_to_val(gf_general_t *v, int w, char *s, int hex); void gf_general_set_random(gf_general_t *v, int w, int zero_ok); void gf_general_add(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c); void gf_general_multiply(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c); void gf_general_divide(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c); void gf_general_inverse(gf_t *gf, gf_general_t *a, gf_general_t *b); void gf_general_do_region_multiply(gf_t *gf, gf_general_t *a, void *ra, void *rb, int bytes, int xor); void gf_general_do_region_check(gf_t *gf, gf_general_t *a, void *orig_a, void *orig_target, void *final_target, int bytes, int xor); /* Which is M, D or I for multiply, divide or inverse. */ void gf_general_set_up_single_timing_test(int w, void *ra, void *rb, int size); int gf_general_do_single_timing_test(gf_t *gf, void *ra, void *rb, int size, char which); ceph-0.80.11/src/erasure-code/jerasure/gf-complete/include/gf_rand.h0000664000175100017510000000140612623076752027260 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_rand.h * * Random number generation, using the "Mother of All" random number generator. */ #pragma once #include #include #include /* These are all pretty self-explanatory */ uint32_t MOA_Random_32(); uint64_t MOA_Random_64(); void MOA_Random_128(uint64_t *x); uint32_t MOA_Random_W(int w, int zero_ok); void MOA_Fill_Random_Region (void *reg, int size); /* reg should be aligned to 4 bytes, but size can be anything. */ void MOA_Seed(uint32_t seed); ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/0000775000175100017510000000000012623077035024645 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_w64.c0000664000175100017510000016560612623076752026130 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_w64.c * * Routines for 64-bit Galois fields */ #include "gf_int.h" #include #include #define GF_FIELD_WIDTH (64) #define GF_FIRST_BIT (1ULL << 63) #define GF_BASE_FIELD_WIDTH (32) #define GF_BASE_FIELD_SIZE (1ULL << GF_BASE_FIELD_WIDTH) #define GF_BASE_FIELD_GROUP_SIZE GF_BASE_FIELD_SIZE-1 struct gf_w64_group_data { uint64_t *reduce; uint64_t *shift; uint64_t *memory; }; struct gf_split_4_64_lazy_data { uint64_t tables[16][16]; uint64_t last_value; }; struct gf_split_8_64_lazy_data { uint64_t tables[8][(1<<8)]; uint64_t last_value; }; struct gf_split_16_64_lazy_data { uint64_t tables[4][(1<<16)]; uint64_t last_value; }; struct gf_split_8_8_data { uint64_t tables[15][256][256]; }; static inline gf_val_64_t gf_w64_inverse_from_divide (gf_t *gf, gf_val_64_t a) { return gf->divide.w64(gf, 1, a); } #define MM_PRINT8(s, r) { uint8_t blah[16], ii; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (ii = 0; ii < 16; ii += 1) printf("%s%02x", (ii%4==0) ? " " : " ", blah[15-ii]); printf("\n"); } static inline gf_val_64_t gf_w64_divide_from_inverse (gf_t *gf, gf_val_64_t a, gf_val_64_t b) { b = gf->inverse.w64(gf, b); return gf->multiply.w64(gf, a, b); } static void gf_w64_multiply_region_from_single(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { int i; gf_val_64_t *s64; gf_val_64_t *d64; s64 = (gf_val_64_t *) src; d64 = (gf_val_64_t *) dest; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } if (xor) { for (i = 0; i < bytes/sizeof(gf_val_64_t); i++) { d64[i] ^= gf->multiply.w64(gf, val, s64[i]); } } else { for (i = 0; i < bytes/sizeof(gf_val_64_t); i++) { d64[i] = gf->multiply.w64(gf, val, s64[i]); } } } #if defined(INTEL_SSE4_PCLMUL) static void gf_w64_clm_multiply_region_from_single_2(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { gf_val_64_t *s64, *d64, *top; gf_region_data rd; __m128i a, b; __m128i result, r1; __m128i prim_poly; __m128i w; __m128i m1, m2, m3, m4; gf_internal_t * h = gf->scratch; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0xffffffffULL)); b = _mm_insert_epi64 (_mm_setzero_si128(), val, 0); m1 = _mm_set_epi32(0, 0, 0, (uint32_t)0xffffffff); m2 = _mm_slli_si128(m1, 4); m2 = _mm_or_si128(m1, m2); m3 = _mm_slli_si128(m1, 8); m4 = _mm_slli_si128(m3, 4); s64 = (gf_val_64_t *) rd.s_start; d64 = (gf_val_64_t *) rd.d_start; top = (gf_val_64_t *) rd.d_top; if (xor) { while (d64 != top) { a = _mm_load_si128((__m128i *) s64); result = _mm_clmulepi64_si128 (a, b, 1); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); r1 = _mm_xor_si128 (result, w); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); result = _mm_xor_si128 (result, w); result = _mm_unpacklo_epi64(result, r1); r1 = _mm_load_si128((__m128i *) d64); result = _mm_xor_si128(r1, result); _mm_store_si128((__m128i *) d64, result); d64 += 2; s64 += 2; } } else { while (d64 != top) { a = _mm_load_si128((__m128i *) s64); result = _mm_clmulepi64_si128 (a, b, 1); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); r1 = _mm_xor_si128 (result, w); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); result = _mm_xor_si128 (result, w); result = _mm_unpacklo_epi64(result, r1); _mm_store_si128((__m128i *) d64, result); d64 += 2; s64 += 2; } } gf_do_final_region_alignment(&rd); } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w64_clm_multiply_region_from_single_4(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { gf_val_64_t *s64, *d64, *top; gf_region_data rd; __m128i a, b; __m128i result, r1; __m128i prim_poly; __m128i w; __m128i m1, m3, m4; gf_internal_t * h = gf->scratch; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0xffffffffULL)); b = _mm_insert_epi64 (_mm_setzero_si128(), val, 0); m1 = _mm_set_epi32(0, 0, 0, (uint32_t)0xffffffff); m3 = _mm_slli_si128(m1, 8); m4 = _mm_slli_si128(m3, 4); s64 = (gf_val_64_t *) rd.s_start; d64 = (gf_val_64_t *) rd.d_start; top = (gf_val_64_t *) rd.d_top; if (xor) { while (d64 != top) { a = _mm_load_si128((__m128i *) s64); result = _mm_clmulepi64_si128 (a, b, 1); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); r1 = _mm_xor_si128 (result, w); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); result = _mm_xor_si128 (result, w); result = _mm_unpacklo_epi64(result, r1); r1 = _mm_load_si128((__m128i *) d64); result = _mm_xor_si128(r1, result); _mm_store_si128((__m128i *) d64, result); d64 += 2; s64 += 2; } } else { while (d64 != top) { a = _mm_load_si128((__m128i *) s64); result = _mm_clmulepi64_si128 (a, b, 1); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); r1 = _mm_xor_si128 (result, w); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m4), prim_poly, 1); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (_mm_and_si128(result, m3), prim_poly, 1); result = _mm_xor_si128 (result, w); result = _mm_unpacklo_epi64(result, r1); _mm_store_si128((__m128i *) d64, result); d64 += 2; s64 += 2; } } gf_do_final_region_alignment(&rd); } #endif static inline gf_val_64_t gf_w64_euclid (gf_t *gf, gf_val_64_t b) { gf_val_64_t e_i, e_im1, e_ip1; gf_val_64_t d_i, d_im1, d_ip1; gf_val_64_t y_i, y_im1, y_ip1; gf_val_64_t c_i; gf_val_64_t one = 1; if (b == 0) return -1; e_im1 = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i = b; d_im1 = 64; for (d_i = d_im1-1; ((one << d_i) & e_i) == 0; d_i--) ; y_i = 1; y_im1 = 0; while (e_i != 1) { e_ip1 = e_im1; d_ip1 = d_im1; c_i = 0; while (d_ip1 >= d_i) { c_i ^= (one << (d_ip1 - d_i)); e_ip1 ^= (e_i << (d_ip1 - d_i)); d_ip1--; if (e_ip1 == 0) return 0; while ((e_ip1 & (one << d_ip1)) == 0) d_ip1--; } y_ip1 = y_im1 ^ gf->multiply.w64(gf, c_i, y_i); y_im1 = y_i; y_i = y_ip1; e_im1 = e_i; d_im1 = d_i; e_i = e_ip1; d_i = d_ip1; } return y_i; } /* JSP: GF_MULT_SHIFT: The world's dumbest multiplication algorithm. I only include it for completeness. It does have the feature that it requires no extra memory. */ static inline gf_val_64_t gf_w64_shift_multiply (gf_t *gf, gf_val_64_t a64, gf_val_64_t b64) { uint64_t pl, pr, ppl, ppr, i, a, bl, br, one, lbit; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; ppr = h->prim_poly; /* Allen: set leading one of primitive polynomial */ ppl = 1; a = a64; bl = 0; br = b64; one = 1; lbit = (one << 63); pl = 0; /* Allen: left side of product */ pr = 0; /* Allen: right side of product */ /* Allen: unlike the corresponding functions for smaller word sizes, * this loop carries out the initial carryless multiply by * shifting b itself rather than simply looking at successively * higher shifts of b */ for (i = 0; i < GF_FIELD_WIDTH; i++) { if (a & (one << i)) { pl ^= bl; pr ^= br; } bl <<= 1; if (br & lbit) bl ^= 1; br <<= 1; } /* Allen: the name of the variable "one" is no longer descriptive at this point */ one = lbit >> 1; ppl = (h->prim_poly >> 2) | one; ppr = (h->prim_poly << (GF_FIELD_WIDTH-2)); while (one != 0) { if (pl & one) { pl ^= ppl; pr ^= ppr; } one >>= 1; ppr >>= 1; if (ppl & 1) ppr ^= lbit; ppl >>= 1; } return pr; } /* * ELM: Use the Intel carryless multiply instruction to do very fast 64x64 multiply. */ static inline gf_val_64_t gf_w64_clm_multiply_2 (gf_t *gf, gf_val_64_t a64, gf_val_64_t b64) { gf_val_64_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i v, w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi64 (_mm_setzero_si128(), a64, 0); b = _mm_insert_epi64 (a, b64, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0xffffffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); /* Mask off the high order 32 bits using subtraction of the polynomial. * NOTE: this part requires that the polynomial have at least 32 leading 0 bits. */ /* Adam: We cant include the leading one in the 64 bit pclmul, so we need to split up the high 8 bytes of the result into two parts before we multiply them with the prim_poly.*/ v = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, v, 0); result = _mm_xor_si128 (result, w); v = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, v, 0); result = _mm_xor_si128 (result, w); rv = ((gf_val_64_t)_mm_extract_epi64(result, 0)); #endif return rv; } static inline gf_val_64_t gf_w64_clm_multiply_4 (gf_t *gf, gf_val_64_t a64, gf_val_64_t b64) { gf_val_64_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i v, w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi64 (_mm_setzero_si128(), a64, 0); b = _mm_insert_epi64 (a, b64, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0xffffffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); v = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, v, 0); result = _mm_xor_si128 (result, w); v = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, v, 0); result = _mm_xor_si128 (result, w); v = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, v, 0); result = _mm_xor_si128 (result, w); v = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, v, 0); result = _mm_xor_si128 (result, w); rv = ((gf_val_64_t)_mm_extract_epi64(result, 0)); #endif return rv; } void gf_w64_clm_multiply_region(gf_t *gf, void *src, void *dest, uint64_t val, int bytes, int xor) { #if defined(INTEL_SSE4_PCLMUL) gf_internal_t *h; uint8_t *s8, *d8, *dtop; gf_region_data rd; __m128i v, b, m, prim_poly, c, fr, w, result; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; dtop = (uint8_t *) rd.d_top; v = _mm_insert_epi64(_mm_setzero_si128(), val, 0); m = _mm_set_epi32(0, 0, 0xffffffff, 0xffffffff); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0xffffffffULL)); if (xor) { while (d8 != dtop) { b = _mm_load_si128((__m128i *) s8); result = _mm_clmulepi64_si128 (b, v, 0); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, c, 0); result = _mm_xor_si128 (result, w); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, c, 0); fr = _mm_xor_si128 (result, w); fr = _mm_and_si128 (fr, m); result = _mm_clmulepi64_si128 (b, v, 1); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, c, 0); result = _mm_xor_si128 (result, w); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, c, 0); result = _mm_xor_si128 (result, w); result = _mm_slli_si128 (result, 8); fr = _mm_xor_si128 (result, fr); result = _mm_load_si128((__m128i *) d8); fr = _mm_xor_si128 (result, fr); _mm_store_si128((__m128i *) d8, fr); d8 += 16; s8 += 16; } } else { while (d8 < dtop) { b = _mm_load_si128((__m128i *) s8); result = _mm_clmulepi64_si128 (b, v, 0); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, c, 0); result = _mm_xor_si128 (result, w); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, c, 0); fr = _mm_xor_si128 (result, w); fr = _mm_and_si128 (fr, m); result = _mm_clmulepi64_si128 (b, v, 1); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 0); w = _mm_clmulepi64_si128 (prim_poly, c, 0); result = _mm_xor_si128 (result, w); c = _mm_insert_epi32 (_mm_srli_si128 (result, 8), 0, 1); w = _mm_clmulepi64_si128 (prim_poly, c, 0); result = _mm_xor_si128 (result, w); result = _mm_slli_si128 (result, 8); fr = _mm_xor_si128 (result, fr); _mm_store_si128((__m128i *) d8, fr); d8 += 16; s8 += 16; } } gf_do_final_region_alignment(&rd); #endif } void gf_w64_split_4_64_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint64_t val, int bytes, int xor) { gf_internal_t *h; struct gf_split_4_64_lazy_data *ld; int i, j, k; uint64_t pp, v, s, *s64, *d64, *top; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; ld = (struct gf_split_4_64_lazy_data *) h->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); if (ld->last_value != val) { v = val; for (i = 0; i < 16; i++) { ld->tables[i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } } } ld->last_value = val; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; while (d64 != top) { v = (xor) ? *d64 : 0; s = *s64; i = 0; while (s != 0) { v ^= ld->tables[i][s&0xf]; s >>= 4; i++; } *d64 = v; d64++; s64++; } gf_do_final_region_alignment(&rd); } static inline uint64_t gf_w64_split_8_8_multiply (gf_t *gf, uint64_t a64, uint64_t b64) { uint64_t product, i, j, mask, tb; gf_internal_t *h; struct gf_split_8_8_data *d8; h = (gf_internal_t *) gf->scratch; d8 = (struct gf_split_8_8_data *) h->private; product = 0; mask = 0xff; for (i = 0; a64 != 0; i++) { tb = b64; for (j = 0; tb != 0; j++) { product ^= d8->tables[i+j][a64&mask][tb&mask]; tb >>= 8; } a64 >>= 8; } return product; } void gf_w64_split_8_64_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint64_t val, int bytes, int xor) { gf_internal_t *h; struct gf_split_8_64_lazy_data *ld; int i, j, k; uint64_t pp, v, s, *s64, *d64, *top; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; ld = (struct gf_split_8_64_lazy_data *) h->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); if (ld->last_value != val) { v = val; for (i = 0; i < 8; i++) { ld->tables[i][0] = 0; for (j = 1; j < 256; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } } } ld->last_value = val; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; while (d64 != top) { v = (xor) ? *d64 : 0; s = *s64; i = 0; while (s != 0) { v ^= ld->tables[i][s&0xff]; s >>= 8; i++; } *d64 = v; d64++; s64++; } gf_do_final_region_alignment(&rd); } void gf_w64_split_16_64_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint64_t val, int bytes, int xor) { gf_internal_t *h; struct gf_split_16_64_lazy_data *ld; int i, j, k; uint64_t pp, v, s, *s64, *d64, *top; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; ld = (struct gf_split_16_64_lazy_data *) h->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); if (ld->last_value != val) { v = val; for (i = 0; i < 4; i++) { ld->tables[i][0] = 0; for (j = 1; j < (1<<16); j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } } } ld->last_value = val; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; while (d64 != top) { v = (xor) ? *d64 : 0; s = *s64; i = 0; while (s != 0) { v ^= ld->tables[i][s&0xffff]; s >>= 16; i++; } *d64 = v; d64++; s64++; } gf_do_final_region_alignment(&rd); } static int gf_w64_shift_init(gf_t *gf) { gf->multiply.w64 = gf_w64_shift_multiply; gf->inverse.w64 = gf_w64_euclid; gf->multiply_region.w64 = gf_w64_multiply_region_from_single; return 1; } static int gf_w64_cfm_init(gf_t *gf) { gf->inverse.w64 = gf_w64_euclid; gf->multiply_region.w64 = gf_w64_multiply_region_from_single; #if defined(INTEL_SSE4_PCLMUL) gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if ((0xfffffffe00000000ULL & h->prim_poly) == 0){ gf->multiply.w64 = gf_w64_clm_multiply_2; gf->multiply_region.w64 = gf_w64_clm_multiply_region_from_single_2; }else if((0xfffe000000000000ULL & h->prim_poly) == 0){ gf->multiply.w64 = gf_w64_clm_multiply_4; gf->multiply_region.w64 = gf_w64_clm_multiply_region_from_single_4; } else { return 0; } return 1; #endif return 0; } static void gf_w64_group_set_shift_tables(uint64_t *shift, uint64_t val, gf_internal_t *h) { int i; uint64_t j; uint64_t one = 1; int g_s; g_s = h->arg1; shift[0] = 0; for (i = 1; i < (1 << g_s); i <<= 1) { for (j = 0; j < i; j++) shift[i|j] = shift[j]^val; if (val & (one << 63)) { val <<= 1; val ^= h->prim_poly; } else { val <<= 1; } } } static inline gf_val_64_t gf_w64_group_multiply(gf_t *gf, gf_val_64_t a, gf_val_64_t b) { uint64_t top, bot, mask, tp; int g_s, g_r, lshift, rshift; struct gf_w64_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; g_s = h->arg1; g_r = h->arg2; gd = (struct gf_w64_group_data *) h->private; gf_w64_group_set_shift_tables(gd->shift, b, h); mask = ((1 << g_s) - 1); top = 0; bot = gd->shift[a&mask]; a >>= g_s; if (a == 0) return bot; lshift = 0; rshift = 64; do { /* Shifting out is straightfoward */ lshift += g_s; rshift -= g_s; tp = gd->shift[a&mask]; top ^= (tp >> rshift); bot ^= (tp << lshift); a >>= g_s; } while (a != 0); /* Reducing is a bit gross, because I don't zero out the index bits of top. The reason is that we throw top away. Even better, that last (tp >> rshift) is going to be ignored, so it doesn't matter how (tp >> 64) is implemented. */ lshift = ((lshift-1) / g_r) * g_r; rshift = 64 - lshift; mask = (1 << g_r) - 1; while (lshift >= 0) { tp = gd->reduce[(top >> lshift) & mask]; top ^= (tp >> rshift); bot ^= (tp << lshift); lshift -= g_r; rshift += g_r; } return bot; } static void gf_w64_group_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { int i, fzb; uint64_t a64, smask, rmask, top, bot, tp; int lshift, rshift, g_s, g_r; gf_region_data rd; uint64_t *s64, *d64, *dtop; struct gf_w64_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gd = (struct gf_w64_group_data *) h->private; g_s = h->arg1; g_r = h->arg2; gf_w64_group_set_shift_tables(gd->shift, val, h); for (i = 63; !(val & (1ULL << i)); i--) ; i += g_s; /* i is the bit position of the first zero bit in any element of gd->shift[] */ if (i > 64) i = 64; fzb = i; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; dtop = (uint64_t *) rd.d_top; smask = (1 << g_s) - 1; rmask = (1 << g_r) - 1; while (d64 < dtop) { a64 = *s64; top = 0; bot = gd->shift[a64&smask]; a64 >>= g_s; i = fzb; if (a64 != 0) { lshift = 0; rshift = 64; do { lshift += g_s; rshift -= g_s; tp = gd->shift[a64&smask]; top ^= (tp >> rshift); bot ^= (tp << lshift); a64 >>= g_s; } while (a64 != 0); i += lshift; lshift = ((i-64-1) / g_r) * g_r; rshift = 64 - lshift; while (lshift >= 0) { tp = gd->reduce[(top >> lshift) & rmask]; top ^= (tp >> rshift); bot ^= (tp << lshift); lshift -= g_r; rshift += g_r; } } if (xor) bot ^= *d64; *d64 = bot; d64++; s64++; } gf_do_final_region_alignment(&rd); } static inline gf_val_64_t gf_w64_group_s_equals_r_multiply(gf_t *gf, gf_val_64_t a, gf_val_64_t b) { int leftover, rs; uint64_t p, l, ind, a64; int bits_left; int g_s; struct gf_w64_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; g_s = h->arg1; gd = (struct gf_w64_group_data *) h->private; gf_w64_group_set_shift_tables(gd->shift, b, h); leftover = 64 % g_s; if (leftover == 0) leftover = g_s; rs = 64 - leftover; a64 = a; ind = a64 >> rs; a64 <<= leftover; p = gd->shift[ind]; bits_left = rs; rs = 64 - g_s; while (bits_left > 0) { bits_left -= g_s; ind = a64 >> rs; a64 <<= g_s; l = p >> rs; p = (gd->shift[ind] ^ gd->reduce[l] ^ (p << g_s)); } return p; } static void gf_w64_group_s_equals_r_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { int leftover, rs; uint64_t p, l, ind, a64; int bits_left; int g_s; gf_region_data rd; uint64_t *s64, *d64, *top; struct gf_w64_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gd = (struct gf_w64_group_data *) h->private; g_s = h->arg1; gf_w64_group_set_shift_tables(gd->shift, val, h); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; leftover = 64 % g_s; if (leftover == 0) leftover = g_s; while (d64 < top) { rs = 64 - leftover; a64 = *s64; ind = a64 >> rs; a64 <<= leftover; p = gd->shift[ind]; bits_left = rs; rs = 64 - g_s; while (bits_left > 0) { bits_left -= g_s; ind = a64 >> rs; a64 <<= g_s; l = p >> rs; p = (gd->shift[ind] ^ gd->reduce[l] ^ (p << g_s)); } if (xor) p ^= *d64; *d64 = p; d64++; s64++; } gf_do_final_region_alignment(&rd); } static int gf_w64_group_init(gf_t *gf) { uint64_t i, j, p, index; struct gf_w64_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; int g_r, g_s; g_s = h->arg1; g_r = h->arg2; gd = (struct gf_w64_group_data *) h->private; gd->shift = (uint64_t *) (&(gd->memory)); gd->reduce = gd->shift + (1 << g_s); gd->reduce[0] = 0; for (i = 0; i < (1 << g_r); i++) { p = 0; index = 0; for (j = 0; j < g_r; j++) { if (i & (1 << j)) { p ^= (h->prim_poly << j); index ^= (1 << j); if (j > 0) index ^= (h->prim_poly >> (64-j)); } } gd->reduce[index] = p; } if (g_s == g_r) { gf->multiply.w64 = gf_w64_group_s_equals_r_multiply; gf->multiply_region.w64 = gf_w64_group_s_equals_r_multiply_region; } else { gf->multiply.w64 = gf_w64_group_multiply; gf->multiply_region.w64 = gf_w64_group_multiply_region; } gf->divide.w64 = NULL; gf->inverse.w64 = gf_w64_euclid; return 1; } static gf_val_64_t gf_w64_extract_word(gf_t *gf, void *start, int bytes, int index) { uint64_t *r64, rv; r64 = (uint64_t *) start; rv = r64[index]; return rv; } static gf_val_64_t gf_w64_composite_extract_word(gf_t *gf, void *start, int bytes, int index) { int sub_size; gf_internal_t *h; uint8_t *r8, *top; uint64_t a, b, *r64; gf_region_data rd; h = (gf_internal_t *) gf->scratch; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 32); r64 = (uint64_t *) start; if (r64 + index < (uint64_t *) rd.d_start) return r64[index]; if (r64 + index >= (uint64_t *) rd.d_top) return r64[index]; index -= (((uint64_t *) rd.d_start) - r64); r8 = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_size = (top-r8)/2; a = h->base_gf->extract_word.w32(h->base_gf, r8, sub_size, index); b = h->base_gf->extract_word.w32(h->base_gf, r8+sub_size, sub_size, index); return (a | ((uint64_t)b << 32)); } static gf_val_64_t gf_w64_split_extract_word(gf_t *gf, void *start, int bytes, int index) { int i; uint64_t *r64, rv; uint8_t *r8; gf_region_data rd; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 128); r64 = (uint64_t *) start; if (r64 + index < (uint64_t *) rd.d_start) return r64[index]; if (r64 + index >= (uint64_t *) rd.d_top) return r64[index]; index -= (((uint64_t *) rd.d_start) - r64); r8 = (uint8_t *) rd.d_start; r8 += ((index & 0xfffffff0)*8); r8 += (index & 0xf); r8 += 112; rv =0; for (i = 0; i < 8; i++) { rv <<= 8; rv |= *r8; r8 -= 16; } return rv; } static inline gf_val_64_t gf_w64_bytwo_b_multiply (gf_t *gf, gf_val_64_t a, gf_val_64_t b) { uint64_t prod, pp, bmask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; bmask = 0x8000000000000000ULL; while (1) { if (a & 1) prod ^= b; a >>= 1; if (a == 0) return prod; if (b & bmask) { b = ((b << 1) ^ pp); } else { b <<= 1; } } } static inline gf_val_64_t gf_w64_bytwo_p_multiply (gf_t *gf, gf_val_64_t a, gf_val_64_t b) { uint64_t prod, pp, pmask, amask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; /* changed from declare then shift to just declare.*/ pmask = 0x8000000000000000ULL; amask = 0x8000000000000000ULL; while (amask != 0) { if (prod & pmask) { prod = ((prod << 1) ^ pp); } else { prod <<= 1; } if (a & amask) prod ^= b; amask >>= 1; } return prod; } static void gf_w64_bytwo_p_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { uint64_t *s64, *d64, ta, prod, amask, pmask, pp; gf_region_data rd; gf_internal_t *h; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; pmask = 0x80000000; pmask <<= 32; pp = h->prim_poly; if (xor) { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = pmask; ta = *s64; while (amask != 0) { prod = (prod & pmask) ? ((prod << 1) ^ pp) : (prod << 1); if (val & amask) prod ^= ta; amask >>= 1; } *d64 ^= prod; d64++; s64++; } } else { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = pmask; ta = *s64; while (amask != 0) { prod = (prod & pmask) ? ((prod << 1) ^ pp) : (prod << 1); if (val & amask) prod ^= ta; amask >>= 1; } *d64 = prod; d64++; s64++; } } gf_do_final_region_alignment(&rd); } static void gf_w64_bytwo_b_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { uint64_t *s64, *d64, ta, tb, prod, bmask, pp; gf_region_data rd; gf_internal_t *h; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; bmask = 0x80000000; bmask <<= 32; pp = h->prim_poly; if (xor) { while (s64 < (uint64_t *) rd.s_top) { prod = 0; tb = val; ta = *s64; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; ta = (ta & bmask) ? ((ta << 1) ^ pp) : (ta << 1); } *d64 ^= prod; d64++; s64++; } } else { while (s64 < (uint64_t *) rd.s_top) { prod = 0; tb = val; ta = *s64; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; ta = (ta & bmask) ? ((ta << 1) ^ pp) : (ta << 1); } *d64 = prod; d64++; s64++; } } gf_do_final_region_alignment(&rd); } #define SSE_AB2(pp, m1 ,m2, va, t1, t2) {\ t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); \ t2 = _mm_and_si128(va, m2); \ t2 = _mm_sub_epi64 (_mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); \ va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } #define BYTWO_P_ONESTEP {\ SSE_AB2(pp, m1 ,m2, prod, t1, t2); \ t1 = _mm_and_si128(v, one); \ t1 = _mm_sub_epi64(t1, one); \ t1 = _mm_and_si128(t1, ta); \ prod = _mm_xor_si128(prod, t1); \ v = _mm_srli_epi64(v, 1); } void gf_w64_bytwo_p_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { #ifdef INTEL_SSE2 int i; uint8_t *s8, *d8; uint64_t vrev, one64; uint64_t amask; __m128i pp, m1, m2, ta, prod, t1, t2, tp, one, v; gf_region_data rd; gf_internal_t *h; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; one64 = 1; vrev = 0; for (i = 0; i < 64; i++) { vrev <<= 1; if (!(val & (one64 << i))) vrev |= 1; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; amask = -1; amask ^= 1; pp = _mm_set1_epi64x(h->prim_poly); m1 = _mm_set1_epi64x(amask); m2 = _mm_set1_epi64x(one64 << 63); one = _mm_set1_epi64x(1); while (d8 < (uint8_t *) rd.d_top) { prod = _mm_setzero_si128(); v = _mm_set1_epi64x(vrev); ta = _mm_load_si128((__m128i *) s8); tp = (!xor) ? _mm_setzero_si128() : _mm_load_si128((__m128i *) d8); BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; _mm_store_si128((__m128i *) d8, _mm_xor_si128(prod, tp)); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); #endif } #ifdef INTEL_SSE2 static void gf_w64_bytwo_b_sse_region_2_xor(gf_region_data *rd) { uint64_t one64, amask; uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; gf_internal_t *h; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; h = (gf_internal_t *) rd->gf->scratch; one64 = 1; amask = -1; amask ^= 1; pp = _mm_set1_epi64x(h->prim_poly); m1 = _mm_set1_epi64x(amask); m2 = _mm_set1_epi64x(one64 << 63); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); vb = _mm_load_si128 ((__m128i *)(d8)); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w64_bytwo_b_sse_region_2_noxor(gf_region_data *rd) { uint64_t one64, amask; uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va; gf_internal_t *h; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; h = (gf_internal_t *) rd->gf->scratch; one64 = 1; amask = -1; amask ^= 1; pp = _mm_set1_epi64x(h->prim_poly); m1 = _mm_set1_epi64x(amask); m2 = _mm_set1_epi64x(one64 << 63); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w64_bytwo_b_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { uint64_t itb, amask, one64; uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; gf_region_data rd; gf_internal_t *h; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); if (val == 2) { if (xor) { gf_w64_bytwo_b_sse_region_2_xor(&rd); } else { gf_w64_bytwo_b_sse_region_2_noxor(&rd); } gf_do_final_region_alignment(&rd); return; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; h = (gf_internal_t *) gf->scratch; one64 = 1; amask = -1; amask ^= 1; pp = _mm_set1_epi64x(h->prim_poly); m1 = _mm_set1_epi64x(amask); m2 = _mm_set1_epi64x(one64 << 63); while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = (!xor) ? _mm_setzero_si128() : _mm_load_si128 ((__m128i *)(d8)); itb = val; while (1) { if (itb & 1) vb = _mm_xor_si128(vb, va); itb >>= 1; if (itb == 0) break; SSE_AB2(pp, m1, m2, va, t1, t2); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif static int gf_w64_bytwo_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (h->mult_type == GF_MULT_BYTWO_p) { gf->multiply.w64 = gf_w64_bytwo_p_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w64 = gf_w64_bytwo_p_nosse_multiply_region; else gf->multiply_region.w64 = gf_w64_bytwo_p_sse_multiply_region; #else gf->multiply_region.w64 = gf_w64_bytwo_p_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } else { gf->multiply.w64 = gf_w64_bytwo_b_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w64 = gf_w64_bytwo_b_nosse_multiply_region; else gf->multiply_region.w64 = gf_w64_bytwo_b_sse_multiply_region; #else gf->multiply_region.w64 = gf_w64_bytwo_b_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } gf->inverse.w64 = gf_w64_euclid; return 1; } static gf_val_64_t gf_w64_composite_multiply(gf_t *gf, gf_val_64_t a, gf_val_64_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint32_t b0 = b & 0x00000000ffffffff; uint32_t b1 = (b & 0xffffffff00000000) >> 32; uint32_t a0 = a & 0x00000000ffffffff; uint32_t a1 = (a & 0xffffffff00000000) >> 32; uint32_t a1b1; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); return ((uint64_t)(base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((uint64_t)(base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 32)); } /* * Composite field division trick (explained in 2007 tech report) * * Compute a / b = a*b^-1, where p(x) = x^2 + sx + 1 * * let c = b^-1 * * c*b = (s*b1c1+b1c0+b0c1)x+(b1c1+b0c0) * * want (s*b1c1+b1c0+b0c1) = 0 and (b1c1+b0c0) = 1 * * let d = b1c1 and d+1 = b0c0 * * solve s*b1c1+b1c0+b0c1 = 0 * * solution: d = (b1b0^-1)(b1b0^-1+b0b1^-1+s)^-1 * * c0 = (d+1)b0^-1 * c1 = d*b1^-1 * * a / b = a * c */ static gf_val_64_t gf_w64_composite_inverse(gf_t *gf, gf_val_64_t a) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint32_t a0 = a & 0x00000000ffffffff; uint32_t a1 = (a & 0xffffffff00000000) >> 32; uint32_t c0, c1, d, tmp; uint64_t c; uint32_t a0inv, a1inv; if (a0 == 0) { a1inv = base_gf->inverse.w32(base_gf, a1); c0 = base_gf->multiply.w32(base_gf, a1inv, h->prim_poly); c1 = a1inv; } else if (a1 == 0) { c0 = base_gf->inverse.w32(base_gf, a0); c1 = 0; } else { a1inv = base_gf->inverse.w32(base_gf, a1); a0inv = base_gf->inverse.w32(base_gf, a0); d = base_gf->multiply.w32(base_gf, a1, a0inv); tmp = (base_gf->multiply.w32(base_gf, a1, a0inv) ^ base_gf->multiply.w32(base_gf, a0, a1inv) ^ h->prim_poly); tmp = base_gf->inverse.w32(base_gf, tmp); d = base_gf->multiply.w32(base_gf, d, tmp); c0 = base_gf->multiply.w32(base_gf, (d^1), a0inv); c1 = base_gf->multiply.w32(base_gf, d, a1inv); } c = c0 | ((uint64_t)c1 << 32); return c; } static void gf_w64_composite_multiply_region(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint32_t b0 = val & 0x00000000ffffffff; uint32_t b1 = (val & 0xffffffff00000000) >> 32; uint64_t *s64, *d64; uint64_t *top; uint64_t a0, a1, a1b1; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); s64 = rd.s_start; d64 = rd.d_start; top = rd.d_top; if (xor) { while (d64 < top) { a0 = *s64 & 0x00000000ffffffff; a1 = (*s64 & 0xffffffff00000000) >> 32; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); *d64 ^= ((uint64_t)(base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((uint64_t)(base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 32)); s64++; d64++; } } else { while (d64 < top) { a0 = *s64 & 0x00000000ffffffff; a1 = (*s64 & 0xffffffff00000000) >> 32; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); *d64 = ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((uint64_t)(base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 32)); s64++; d64++; } } } static void gf_w64_composite_multiply_region_alt(gf_t *gf, void *src, void *dest, gf_val_64_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; gf_val_32_t val0 = val & 0x00000000ffffffff; gf_val_32_t val1 = (val & 0xffffffff00000000) >> 32; uint8_t *slow, *shigh; uint8_t *dlow, *dhigh, *top; int sub_reg_size; gf_region_data rd; if (!xor) { memset(dest, 0, bytes); } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); slow = (uint8_t *) rd.s_start; dlow = (uint8_t *) rd.d_start; top = (uint8_t*) rd.d_top; sub_reg_size = (top - dlow)/2; shigh = slow + sub_reg_size; dhigh = dlow + sub_reg_size; base_gf->multiply_region.w32(base_gf, slow, dlow, val0, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, shigh, dlow, val1, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, slow, dhigh, val1, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, shigh, dhigh, val0, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, shigh, dhigh, base_gf->multiply.w32(base_gf, h->prim_poly, val1), sub_reg_size, 1); gf_do_final_region_alignment(&rd); } static int gf_w64_composite_init(gf_t *gf) { gf_internal_t *h = (gf_internal_t *) gf->scratch; if (h->region_type & GF_REGION_ALTMAP) { gf->multiply_region.w64 = gf_w64_composite_multiply_region_alt; } else { gf->multiply_region.w64 = gf_w64_composite_multiply_region; } gf->multiply.w64 = gf_w64_composite_multiply; gf->divide.w64 = NULL; gf->inverse.w64 = gf_w64_composite_inverse; return 1; } #ifdef INTEL_SSSE3 static void gf_w64_split_4_64_lazy_sse_altmap_multiply_region(gf_t *gf, void *src, void *dest, uint64_t val, int bytes, int xor) { gf_internal_t *h; int i, j, k; uint64_t pp, v, *s64, *d64, *top; __m128i si, tables[16][8], p[8], v0, mask1; struct gf_split_4_64_lazy_data *ld; uint8_t btable[16]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 128); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; ld = (struct gf_split_4_64_lazy_data *) h->private; v = val; for (i = 0; i < 16; i++) { ld->tables[i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } for (j = 0; j < 8; j++) { for (k = 0; k < 16; k++) { btable[k] = (uint8_t) ld->tables[i][k]; ld->tables[i][k] >>= 8; } tables[i][j] = _mm_loadu_si128((__m128i *) btable); } } mask1 = _mm_set1_epi8(0xf); while (d64 != top) { if (xor) { for (i = 0; i < 8; i++) p[i] = _mm_load_si128 ((__m128i *) (d64+i*2)); } else { for (i = 0; i < 8; i++) p[i] = _mm_setzero_si128(); } i = 0; for (k = 0; k < 8; k++) { v0 = _mm_load_si128((__m128i *) s64); /* MM_PRINT8("v", v0); */ s64 += 2; si = _mm_and_si128(v0, mask1); for (j = 0; j < 8; j++) { p[j] = _mm_xor_si128(p[j], _mm_shuffle_epi8(tables[i][j], si)); } i++; v0 = _mm_srli_epi32(v0, 4); si = _mm_and_si128(v0, mask1); for (j = 0; j < 8; j++) { p[j] = _mm_xor_si128(p[j], _mm_shuffle_epi8(tables[i][j], si)); } i++; } for (i = 0; i < 8; i++) { /* MM_PRINT8("v", p[i]); */ _mm_store_si128((__m128i *) d64, p[i]); d64 += 2; } } gf_do_final_region_alignment(&rd); } #endif #ifdef INTEL_SSE4 static void gf_w64_split_4_64_lazy_sse_multiply_region(gf_t *gf, void *src, void *dest, uint64_t val, int bytes, int xor) { gf_internal_t *h; int i, j, k; uint64_t pp, v, *s64, *d64, *top; __m128i si, tables[16][8], p[8], st[8], mask1, mask8, mask16, t1; struct gf_split_4_64_lazy_data *ld; uint8_t btable[16]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 128); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; ld = (struct gf_split_4_64_lazy_data *) h->private; v = val; for (i = 0; i < 16; i++) { ld->tables[i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } for (j = 0; j < 8; j++) { for (k = 0; k < 16; k++) { btable[k] = (uint8_t) ld->tables[i][k]; ld->tables[i][k] >>= 8; } tables[i][j] = _mm_loadu_si128((__m128i *) btable); } } mask1 = _mm_set1_epi8(0xf); mask8 = _mm_set1_epi16(0xff); mask16 = _mm_set1_epi32(0xffff); while (d64 != top) { for (i = 0; i < 8; i++) p[i] = _mm_setzero_si128(); for (k = 0; k < 8; k++) { st[k] = _mm_load_si128((__m128i *) s64); s64 += 2; } for (k = 0; k < 4; k ++) { st[k] = _mm_shuffle_epi32(st[k], _MM_SHUFFLE(3,1,2,0)); st[k+4] = _mm_shuffle_epi32(st[k+4], _MM_SHUFFLE(2,0,3,1)); t1 = _mm_blend_epi16(st[k], st[k+4], 0xf0); st[k] = _mm_srli_si128(st[k], 8); st[k+4] = _mm_slli_si128(st[k+4], 8); st[k+4] = _mm_blend_epi16(st[k], st[k+4], 0xf0); st[k] = t1; } /* printf("After pack pass 1\n"); for (k = 0; k < 8; k++) { MM_PRINT8("v", st[k]); } printf("\n"); */ t1 = _mm_packus_epi32(_mm_and_si128(st[0], mask16), _mm_and_si128(st[2], mask16)); st[2] = _mm_packus_epi32(_mm_srli_epi32(st[0], 16), _mm_srli_epi32(st[2], 16)); st[0] = t1; t1 = _mm_packus_epi32(_mm_and_si128(st[1], mask16), _mm_and_si128(st[3], mask16)); st[3] = _mm_packus_epi32(_mm_srli_epi32(st[1], 16), _mm_srli_epi32(st[3], 16)); st[1] = t1; t1 = _mm_packus_epi32(_mm_and_si128(st[4], mask16), _mm_and_si128(st[6], mask16)); st[6] = _mm_packus_epi32(_mm_srli_epi32(st[4], 16), _mm_srli_epi32(st[6], 16)); st[4] = t1; t1 = _mm_packus_epi32(_mm_and_si128(st[5], mask16), _mm_and_si128(st[7], mask16)); st[7] = _mm_packus_epi32(_mm_srli_epi32(st[5], 16), _mm_srli_epi32(st[7], 16)); st[5] = t1; /* printf("After pack pass 2\n"); for (k = 0; k < 8; k++) { MM_PRINT8("v", st[k]); } printf("\n"); */ t1 = _mm_packus_epi16(_mm_and_si128(st[0], mask8), _mm_and_si128(st[1], mask8)); st[1] = _mm_packus_epi16(_mm_srli_epi16(st[0], 8), _mm_srli_epi16(st[1], 8)); st[0] = t1; t1 = _mm_packus_epi16(_mm_and_si128(st[2], mask8), _mm_and_si128(st[3], mask8)); st[3] = _mm_packus_epi16(_mm_srli_epi16(st[2], 8), _mm_srli_epi16(st[3], 8)); st[2] = t1; t1 = _mm_packus_epi16(_mm_and_si128(st[4], mask8), _mm_and_si128(st[5], mask8)); st[5] = _mm_packus_epi16(_mm_srli_epi16(st[4], 8), _mm_srli_epi16(st[5], 8)); st[4] = t1; t1 = _mm_packus_epi16(_mm_and_si128(st[6], mask8), _mm_and_si128(st[7], mask8)); st[7] = _mm_packus_epi16(_mm_srli_epi16(st[6], 8), _mm_srli_epi16(st[7], 8)); st[6] = t1; /* printf("After final pack pass 2\n"); for (k = 0; k < 8; k++) { MM_PRINT8("v", st[k]); } */ i = 0; for (k = 0; k < 8; k++) { si = _mm_and_si128(st[k], mask1); for (j = 0; j < 8; j++) { p[j] = _mm_xor_si128(p[j], _mm_shuffle_epi8(tables[i][j], si)); } i++; st[k] = _mm_srli_epi32(st[k], 4); si = _mm_and_si128(st[k], mask1); for (j = 0; j < 8; j++) { p[j] = _mm_xor_si128(p[j], _mm_shuffle_epi8(tables[i][j], si)); } i++; } t1 = _mm_unpacklo_epi8(p[0], p[1]); p[1] = _mm_unpackhi_epi8(p[0], p[1]); p[0] = t1; t1 = _mm_unpacklo_epi8(p[2], p[3]); p[3] = _mm_unpackhi_epi8(p[2], p[3]); p[2] = t1; t1 = _mm_unpacklo_epi8(p[4], p[5]); p[5] = _mm_unpackhi_epi8(p[4], p[5]); p[4] = t1; t1 = _mm_unpacklo_epi8(p[6], p[7]); p[7] = _mm_unpackhi_epi8(p[6], p[7]); p[6] = t1; /* printf("After unpack pass 1:\n"); for (i = 0; i < 8; i++) { MM_PRINT8("v", p[i]); } */ t1 = _mm_unpacklo_epi16(p[0], p[2]); p[2] = _mm_unpackhi_epi16(p[0], p[2]); p[0] = t1; t1 = _mm_unpacklo_epi16(p[1], p[3]); p[3] = _mm_unpackhi_epi16(p[1], p[3]); p[1] = t1; t1 = _mm_unpacklo_epi16(p[4], p[6]); p[6] = _mm_unpackhi_epi16(p[4], p[6]); p[4] = t1; t1 = _mm_unpacklo_epi16(p[5], p[7]); p[7] = _mm_unpackhi_epi16(p[5], p[7]); p[5] = t1; /* printf("After unpack pass 2:\n"); for (i = 0; i < 8; i++) { MM_PRINT8("v", p[i]); } */ t1 = _mm_unpacklo_epi32(p[0], p[4]); p[4] = _mm_unpackhi_epi32(p[0], p[4]); p[0] = t1; t1 = _mm_unpacklo_epi32(p[1], p[5]); p[5] = _mm_unpackhi_epi32(p[1], p[5]); p[1] = t1; t1 = _mm_unpacklo_epi32(p[2], p[6]); p[6] = _mm_unpackhi_epi32(p[2], p[6]); p[2] = t1; t1 = _mm_unpacklo_epi32(p[3], p[7]); p[7] = _mm_unpackhi_epi32(p[3], p[7]); p[3] = t1; if (xor) { for (i = 0; i < 8; i++) { t1 = _mm_load_si128((__m128i *) d64); _mm_store_si128((__m128i *) d64, _mm_xor_si128(p[i], t1)); d64 += 2; } } else { for (i = 0; i < 8; i++) { _mm_store_si128((__m128i *) d64, p[i]); d64 += 2; } } } gf_do_final_region_alignment(&rd); } #endif #define GF_MULTBY_TWO(p) (((p) & GF_FIRST_BIT) ? (((p) << 1) ^ h->prim_poly) : (p) << 1); static int gf_w64_split_init(gf_t *gf) { gf_internal_t *h; struct gf_split_4_64_lazy_data *d4; struct gf_split_8_64_lazy_data *d8; struct gf_split_8_8_data *d88; struct gf_split_16_64_lazy_data *d16; uint64_t p, basep; int exp, i, j; h = (gf_internal_t *) gf->scratch; /* Defaults */ gf->multiply_region.w64 = gf_w64_multiply_region_from_single; gf->multiply.w64 = gf_w64_bytwo_p_multiply; #if defined(INTEL_SSE4_PCLMUL) if ((!(h->region_type & GF_REGION_NOSSE) && (h->arg1 == 64 || h->arg2 == 64)) || h->mult_type == GF_MULT_DEFAULT){ if ((0xfffffffe00000000ULL & h->prim_poly) == 0){ gf->multiply.w64 = gf_w64_clm_multiply_2; gf->multiply_region.w64 = gf_w64_clm_multiply_region_from_single_2; }else if((0xfffe000000000000ULL & h->prim_poly) == 0){ gf->multiply.w64 = gf_w64_clm_multiply_4; gf->multiply_region.w64 = gf_w64_clm_multiply_region_from_single_4; }else{ return 0; } } #endif gf->inverse.w64 = gf_w64_euclid; /* Allen: set region pointers for default mult type. Single pointers are * taken care of above (explicitly for sse, implicitly for no sse). */ #ifdef INTEL_SSE4 if (h->mult_type == GF_MULT_DEFAULT) { d4 = (struct gf_split_4_64_lazy_data *) h->private; d4->last_value = 0; gf->multiply_region.w64 = gf_w64_split_4_64_lazy_sse_multiply_region; } #else if (h->mult_type == GF_MULT_DEFAULT) { d8 = (struct gf_split_8_64_lazy_data *) h->private; d8->last_value = 0; gf->multiply_region.w64 = gf_w64_split_8_64_lazy_multiply_region; } #endif if ((h->arg1 == 4 && h->arg2 == 64) || (h->arg1 == 64 && h->arg2 == 4)) { d4 = (struct gf_split_4_64_lazy_data *) h->private; d4->last_value = 0; if((h->region_type & GF_REGION_ALTMAP) && (h->region_type & GF_REGION_NOSSE)) return 0; if(h->region_type & GF_REGION_ALTMAP) { #ifdef INTEL_SSSE3 gf->multiply_region.w64 = gf_w64_split_4_64_lazy_sse_altmap_multiply_region; #else return 0; #endif } else //no altmap { #ifdef INTEL_SSE4 if(h->region_type & GF_REGION_NOSSE) gf->multiply_region.w64 = gf_w64_split_4_64_lazy_multiply_region; else gf->multiply_region.w64 = gf_w64_split_4_64_lazy_sse_multiply_region; #else gf->multiply_region.w64 = gf_w64_split_4_64_lazy_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } } if ((h->arg1 == 8 && h->arg2 == 64) || (h->arg1 == 64 && h->arg2 == 8)) { d8 = (struct gf_split_8_64_lazy_data *) h->private; d8->last_value = 0; gf->multiply_region.w64 = gf_w64_split_8_64_lazy_multiply_region; } if ((h->arg1 == 16 && h->arg2 == 64) || (h->arg1 == 64 && h->arg2 == 16)) { d16 = (struct gf_split_16_64_lazy_data *) h->private; d16->last_value = 0; gf->multiply_region.w64 = gf_w64_split_16_64_lazy_multiply_region; } if ((h->arg1 == 8 && h->arg2 == 8)) { d88 = (struct gf_split_8_8_data *) h->private; gf->multiply.w64 = gf_w64_split_8_8_multiply; /* The performance of this guy sucks, so don't bother with a region op */ basep = 1; for (exp = 0; exp < 15; exp++) { for (j = 0; j < 256; j++) d88->tables[exp][0][j] = 0; for (i = 0; i < 256; i++) d88->tables[exp][i][0] = 0; d88->tables[exp][1][1] = basep; for (i = 2; i < 256; i++) { if (i&1) { p = d88->tables[exp][i^1][1]; d88->tables[exp][i][1] = p ^ basep; } else { p = d88->tables[exp][i>>1][1]; d88->tables[exp][i][1] = GF_MULTBY_TWO(p); } } for (i = 1; i < 256; i++) { p = d88->tables[exp][i][1]; for (j = 1; j < 256; j++) { if (j&1) { d88->tables[exp][i][j] = d88->tables[exp][i][j^1] ^ p; } else { d88->tables[exp][i][j] = GF_MULTBY_TWO(d88->tables[exp][i][j>>1]); } } } for (i = 0; i < 8; i++) basep = GF_MULTBY_TWO(basep); } } return 1; } int gf_w64_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2) { switch(mult_type) { case GF_MULT_SHIFT: return sizeof(gf_internal_t); break; case GF_MULT_CARRY_FREE: return sizeof(gf_internal_t); break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: return sizeof(gf_internal_t); break; case GF_MULT_DEFAULT: /* Allen: set the *local* arg1 and arg2, just for scratch size purposes, * then fall through to split table scratch size code. */ #ifdef INTEL_SSE4 arg1 = 64; arg2 = 4; #else arg1 = 64; arg2 = 8; #endif case GF_MULT_SPLIT_TABLE: if (arg1 == 8 && arg2 == 8) { return sizeof(gf_internal_t) + sizeof(struct gf_split_8_8_data) + 64; } if ((arg1 == 16 && arg2 == 64) || (arg2 == 16 && arg1 == 64)) { return sizeof(gf_internal_t) + sizeof(struct gf_split_16_64_lazy_data) + 64; } if ((arg1 == 8 && arg2 == 64) || (arg2 == 8 && arg1 == 64)) { return sizeof(gf_internal_t) + sizeof(struct gf_split_8_64_lazy_data) + 64; } if ((arg1 == 64 && arg2 == 4) || (arg1 == 4 && arg2 == 64)) { return sizeof(gf_internal_t) + sizeof(struct gf_split_4_64_lazy_data) + 64; } return 0; case GF_MULT_GROUP: return sizeof(gf_internal_t) + sizeof(struct gf_w64_group_data) + sizeof(uint64_t) * (1 << arg1) + sizeof(uint64_t) * (1 << arg2) + 64; break; case GF_MULT_COMPOSITE: if (arg1 == 2) return sizeof(gf_internal_t) + 64; return 0; break; default: return 0; } } int gf_w64_init(gf_t *gf) { gf_internal_t *h; int no_default_flag = 0; h = (gf_internal_t *) gf->scratch; /* Allen: set default primitive polynomial / irreducible polynomial if needed */ /* Omitting the leftmost 1 as in w=32 */ if (h->prim_poly == 0) { if (h->mult_type == GF_MULT_COMPOSITE) { h->prim_poly = gf_composite_get_default_poly(h->base_gf); if (h->prim_poly == 0) return 0; /* This shouldn't happen */ } else { h->prim_poly = 0x1b; } if (no_default_flag == 1) { fprintf(stderr,"Code contains no default irreducible polynomial for given base field\n"); return 0; } } gf->multiply.w64 = NULL; gf->divide.w64 = NULL; gf->inverse.w64 = NULL; gf->multiply_region.w64 = NULL; switch(h->mult_type) { case GF_MULT_CARRY_FREE: if (gf_w64_cfm_init(gf) == 0) return 0; break; case GF_MULT_SHIFT: if (gf_w64_shift_init(gf) == 0) return 0; break; case GF_MULT_COMPOSITE: if (gf_w64_composite_init(gf) == 0) return 0; break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if (gf_w64_split_init(gf) == 0) return 0; break; case GF_MULT_GROUP: if (gf_w64_group_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: if (gf_w64_bytwo_init(gf) == 0) return 0; break; default: return 0; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w64 = gf_w64_divide_from_inverse; gf->inverse.w64 = gf_w64_euclid; } if (gf->inverse.w64 != NULL && gf->divide.w64 == NULL) { gf->divide.w64 = gf_w64_divide_from_inverse; } if (gf->inverse.w64 == NULL && gf->divide.w64 != NULL) { gf->inverse.w64 = gf_w64_inverse_from_divide; } if (h->region_type == GF_REGION_CAUCHY) return 0; if (h->region_type & GF_REGION_ALTMAP) { if (h->mult_type == GF_MULT_COMPOSITE) { gf->extract_word.w64 = gf_w64_composite_extract_word; } else if (h->mult_type == GF_MULT_SPLIT_TABLE) { gf->extract_word.w64 = gf_w64_split_extract_word; } } else { gf->extract_word.w64 = gf_w64_extract_word; } return 1; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_rand.c0000664000175100017510000000331612623076752026421 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_rand.c -- Random number generator. */ #include #include #include #include "gf_rand.h" /* Lifted the "Mother of All" random number generator from http://www.agner.org/random/ */ static uint32_t MOA_X[5]; uint32_t MOA_Random_32() { uint64_t sum; sum = (uint64_t)2111111111UL * (uint64_t)MOA_X[3] + (uint64_t)1492 * (uint64_t)(MOA_X[2]) + (uint64_t)1776 * (uint64_t)(MOA_X[1]) + (uint64_t)5115 * (uint64_t)(MOA_X[0]) + (uint64_t)MOA_X[4]; MOA_X[3] = MOA_X[2]; MOA_X[2] = MOA_X[1]; MOA_X[1] = MOA_X[0]; MOA_X[4] = (uint32_t)(sum >> 32); MOA_X[0] = (uint32_t)sum; return MOA_X[0]; } uint64_t MOA_Random_64() { uint64_t sum; sum = MOA_Random_32(); sum <<= 32; sum |= MOA_Random_32(); return sum; } void MOA_Random_128(uint64_t *x) { x[0] = MOA_Random_64(); x[1] = MOA_Random_64(); return; } uint32_t MOA_Random_W(int w, int zero_ok) { uint32_t b; do { b = MOA_Random_32(); if (w == 31) b &= 0x7fffffff; if (w < 31) b %= (1 << w); } while (!zero_ok && b == 0); return b; } void MOA_Seed(uint32_t seed) { int i; uint32_t s = seed; for (i = 0; i < 5; i++) { s = s * 29943829 - 1; MOA_X[i] = s; } for (i=0; i<19; i++) MOA_Random_32(); } void MOA_Fill_Random_Region (void *reg, int size) { uint32_t *r32; uint8_t *r8; int i; r32 = (uint32_t *) reg; r8 = (uint8_t *) reg; for (i = 0; i < size/4; i++) r32[i] = MOA_Random_32(); for (i *= 4; i < size; i++) r8[i] = MOA_Random_W(8, 1); } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_w32.c0000664000175100017510000023014312623076752026110 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_w32.c * * Routines for 32-bit Galois fields */ #include "gf_int.h" #include #include #define GF_FIELD_WIDTH (32) #define GF_FIRST_BIT (1 << 31) #define GF_BASE_FIELD_WIDTH (16) #define GF_BASE_FIELD_SIZE (1 << GF_BASE_FIELD_WIDTH) #define GF_BASE_FIELD_GROUP_SIZE GF_BASE_FIELD_SIZE-1 #define GF_MULTBY_TWO(p) (((p) & GF_FIRST_BIT) ? (((p) << 1) ^ h->prim_poly) : (p) << 1) struct gf_split_2_32_lazy_data { uint32_t tables[16][4]; uint32_t last_value; }; struct gf_w32_split_8_8_data { uint32_t tables[7][256][256]; uint32_t region_tables[4][256]; uint32_t last_value; }; struct gf_w32_group_data { uint32_t *reduce; uint32_t *shift; int tshift; uint64_t rmask; uint32_t *memory; }; struct gf_split_16_32_lazy_data { uint32_t tables[2][(1<<16)]; uint32_t last_value; }; struct gf_split_8_32_lazy_data { uint32_t tables[4][256]; uint32_t last_value; }; struct gf_split_4_32_lazy_data { uint32_t tables[8][16]; uint32_t last_value; }; struct gf_w32_bytwo_data { uint64_t prim_poly; uint64_t mask1; uint64_t mask2; }; struct gf_w32_composite_data { uint16_t *log; uint16_t *alog; }; #define MM_PRINT32(s, r) { uint8_t blah[16], ii; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (ii = 0; ii < 16; ii += 4) printf(" %02x%02x%02x%02x", blah[15-ii], blah[14-ii], blah[13-ii], blah[12-ii]); printf("\n"); } #define MM_PRINT8(s, r) { uint8_t blah[16], ii; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (ii = 0; ii < 16; ii += 1) printf("%s%02x", (ii%4==0) ? " " : " ", blah[15-ii]); printf("\n"); } #define AB2(ip, am1 ,am2, b, t1, t2) {\ t1 = (b << 1) & am1;\ t2 = b & am2; \ t2 = ((t2 << 1) - (t2 >> (GF_FIELD_WIDTH-1))); \ b = (t1 ^ (t2 & ip));} #define SSE_AB2(pp, m1 ,m2, va, t1, t2) {\ t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); \ t2 = _mm_and_si128(va, m2); \ t2 = _mm_sub_epi64 (_mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); \ va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } static inline uint32_t gf_w32_inverse_from_divide (gf_t *gf, uint32_t a) { return gf->divide.w32(gf, 1, a); } static inline uint32_t gf_w32_divide_from_inverse (gf_t *gf, uint32_t a, uint32_t b) { b = gf->inverse.w32(gf, b); return gf->multiply.w32(gf, a, b); } static void gf_w32_multiply_region_from_single(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { int i; uint32_t *s32; uint32_t *d32; s32 = (uint32_t *) src; d32 = (uint32_t *) dest; if (xor) { for (i = 0; i < bytes/sizeof(uint32_t); i++) { d32[i] ^= gf->multiply.w32(gf, val, s32[i]); } } else { for (i = 0; i < bytes/sizeof(uint32_t); i++) { d32[i] = gf->multiply.w32(gf, val, s32[i]); } } } #if defined(INTEL_SSE4_PCLMUL) static void gf_w32_clm_multiply_region_from_single_2(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { int i; uint32_t *s32; uint32_t *d32; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 1, (uint32_t)(h->prim_poly & 0xffffffffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); s32 = (uint32_t *) src; d32 = (uint32_t *) dest; if (xor) { for (i = 0; i < bytes/sizeof(uint32_t); i++) { b = _mm_insert_epi32 (a, s32[i], 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); d32[i] ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); } } else { for (i = 0; i < bytes/sizeof(uint32_t); i++) { b = _mm_insert_epi32 (a, s32[i], 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); d32[i] = ((gf_val_32_t)_mm_extract_epi32(result, 0)); } } } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w32_clm_multiply_region_from_single_3(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { int i; uint32_t *s32; uint32_t *d32; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 1, (uint32_t)(h->prim_poly & 0xffffffffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); s32 = (uint32_t *) src; d32 = (uint32_t *) dest; if (xor) { for (i = 0; i < bytes/sizeof(uint32_t); i++) { b = _mm_insert_epi32 (a, s32[i], 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); d32[i] ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); } } else { for (i = 0; i < bytes/sizeof(uint32_t); i++) { b = _mm_insert_epi32 (a, s32[i], 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); d32[i] = ((gf_val_32_t)_mm_extract_epi32(result, 0)); } } } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w32_clm_multiply_region_from_single_4(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { int i; uint32_t *s32; uint32_t *d32; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 1, (uint32_t)(h->prim_poly & 0xffffffffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); s32 = (uint32_t *) src; d32 = (uint32_t *) dest; if (xor) { for (i = 0; i < bytes/sizeof(uint32_t); i++) { b = _mm_insert_epi32 (a, s32[i], 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); d32[i] ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); } } else { for (i = 0; i < bytes/sizeof(uint32_t); i++) { b = _mm_insert_epi32 (a, s32[i], 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); d32[i] = ((gf_val_32_t)_mm_extract_epi32(result, 0)); } } } #endif static inline uint32_t gf_w32_euclid (gf_t *gf, uint32_t b) { uint32_t e_i, e_im1, e_ip1; uint32_t d_i, d_im1, d_ip1; uint32_t y_i, y_im1, y_ip1; uint32_t c_i; if (b == 0) return -1; e_im1 = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i = b; d_im1 = 32; for (d_i = d_im1-1; ((1 << d_i) & e_i) == 0; d_i--) ; y_i = 1; y_im1 = 0; while (e_i != 1) { e_ip1 = e_im1; d_ip1 = d_im1; c_i = 0; while (d_ip1 >= d_i) { c_i ^= (1 << (d_ip1 - d_i)); e_ip1 ^= (e_i << (d_ip1 - d_i)); d_ip1--; if (e_ip1 == 0) return 0; while ((e_ip1 & (1 << d_ip1)) == 0) d_ip1--; } y_ip1 = y_im1 ^ gf->multiply.w32(gf, c_i, y_i); y_im1 = y_i; y_i = y_ip1; e_im1 = e_i; d_im1 = d_i; e_i = e_ip1; d_i = d_ip1; } return y_i; } static gf_val_32_t gf_w32_extract_word(gf_t *gf, void *start, int bytes, int index) { uint32_t *r32, rv; r32 = (uint32_t *) start; rv = r32[index]; return rv; } static gf_val_32_t gf_w32_composite_extract_word(gf_t *gf, void *start, int bytes, int index) { int sub_size; gf_internal_t *h; uint8_t *r8, *top; uint32_t a, b, *r32; gf_region_data rd; h = (gf_internal_t *) gf->scratch; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 32); r32 = (uint32_t *) start; if (r32 + index < (uint32_t *) rd.d_start) return r32[index]; if (r32 + index >= (uint32_t *) rd.d_top) return r32[index]; index -= (((uint32_t *) rd.d_start) - r32); r8 = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_size = (top-r8)/2; a = h->base_gf->extract_word.w32(h->base_gf, r8, sub_size, index); b = h->base_gf->extract_word.w32(h->base_gf, r8+sub_size, sub_size, index); return (a | (b << 16)); } static gf_val_32_t gf_w32_split_extract_word(gf_t *gf, void *start, int bytes, int index) { int i; uint32_t *r32, rv; uint8_t *r8; gf_region_data rd; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 64); r32 = (uint32_t *) start; if (r32 + index < (uint32_t *) rd.d_start) return r32[index]; if (r32 + index >= (uint32_t *) rd.d_top) return r32[index]; index -= (((uint32_t *) rd.d_start) - r32); r8 = (uint8_t *) rd.d_start; r8 += ((index & 0xfffffff0)*4); r8 += (index & 0xf); r8 += 48; rv =0; for (i = 0; i < 4; i++) { rv <<= 8; rv |= *r8; r8 -= 16; } return rv; } static inline uint32_t gf_w32_matrix (gf_t *gf, uint32_t b) { return gf_bitmatrix_inverse(b, 32, ((gf_internal_t *) (gf->scratch))->prim_poly); } /* JSP: GF_MULT_SHIFT: The world's dumbest multiplication algorithm. I only include it for completeness. It does have the feature that it requires no extra memory. */ static inline gf_val_32_t gf_w32_clm_multiply_2 (gf_t *gf, gf_val_32_t a32, gf_val_32_t b32) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a32, 0); b = _mm_insert_epi32 (a, b32, 0); prim_poly = _mm_set_epi32(0, 0, 1, (uint32_t)(h->prim_poly & 0xffffffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); /* Ben: Do prim_poly reduction twice. We are guaranteed that we will only have to do the reduction at most twice, because (w-2)/z == 2. Where z is equal to the number of zeros after the leading 1 _mm_clmulepi64_si128 is the carryless multiply operation. Here _mm_srli_si128 shifts the result to the right by 4 bytes. This allows us to multiply the prim_poly by the leading bits of the result. We then xor the result of that operation back with the result.*/ w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w32_clm_multiply_3 (gf_t *gf, gf_val_32_t a32, gf_val_32_t b32) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a32, 0); b = _mm_insert_epi32 (a, b32, 0); prim_poly = _mm_set_epi32(0, 0, 1, (uint32_t)(h->prim_poly & 0xffffffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w32_clm_multiply_4 (gf_t *gf, gf_val_32_t a32, gf_val_32_t b32) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a32, 0); b = _mm_insert_epi32 (a, b32, 0); prim_poly = _mm_set_epi32(0, 0, 1, (uint32_t)(h->prim_poly & 0xffffffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 4), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline uint32_t gf_w32_shift_multiply (gf_t *gf, uint32_t a32, uint32_t b32) { uint64_t product, i, pp, a, b, one; gf_internal_t *h; a = a32; b = b32; h = (gf_internal_t *) gf->scratch; one = 1; pp = h->prim_poly | (one << 32); product = 0; for (i = 0; i < GF_FIELD_WIDTH; i++) { if (a & (one << i)) product ^= (b << i); } for (i = (GF_FIELD_WIDTH*2-2); i >= GF_FIELD_WIDTH; i--) { if (product & (one << i)) product ^= (pp << (i-GF_FIELD_WIDTH)); } return product; } static int gf_w32_cfm_init(gf_t *gf) { gf->inverse.w32 = gf_w32_euclid; gf->multiply_region.w32 = gf_w32_multiply_region_from_single; /*Ben: We also check to see if the prim poly will work for pclmul */ /*Ben: Check to see how many reduction steps it will take*/ #if defined(INTEL_SSE4_PCLMUL) gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if ((0xfffe0000 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w32_clm_multiply_2; gf->multiply_region.w32 = gf_w32_clm_multiply_region_from_single_2; }else if ((0xffc00000 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w32_clm_multiply_3; gf->multiply_region.w32 = gf_w32_clm_multiply_region_from_single_3; }else if ((0xfe000000 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w32_clm_multiply_4; gf->multiply_region.w32 = gf_w32_clm_multiply_region_from_single_4; } else { return 0; } return 1; #endif return 0; } static int gf_w32_shift_init(gf_t *gf) { gf->inverse.w32 = gf_w32_euclid; gf->multiply_region.w32 = gf_w32_multiply_region_from_single; gf->multiply.w32 = gf_w32_shift_multiply; return 1; } static void gf_w32_group_set_shift_tables(uint32_t *shift, uint32_t val, gf_internal_t *h) { int i; uint32_t j; shift[0] = 0; for (i = 1; i < (1 << h->arg1); i <<= 1) { for (j = 0; j < i; j++) shift[i|j] = shift[j]^val; if (val & GF_FIRST_BIT) { val <<= 1; val ^= h->prim_poly; } else { val <<= 1; } } } static void gf_w32_group_s_equals_r_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int leftover, rs; uint32_t p, l, ind, a32; int bits_left; int g_s; gf_region_data rd; uint32_t *s32, *d32, *top; struct gf_w32_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gd = (struct gf_w32_group_data *) h->private; g_s = h->arg1; gf_w32_group_set_shift_tables(gd->shift, val, h); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; leftover = 32 % g_s; if (leftover == 0) leftover = g_s; while (d32 < top) { rs = 32 - leftover; a32 = *s32; ind = a32 >> rs; a32 <<= leftover; p = gd->shift[ind]; bits_left = rs; rs = 32 - g_s; while (bits_left > 0) { bits_left -= g_s; ind = a32 >> rs; a32 <<= g_s; l = p >> rs; p = (gd->shift[ind] ^ gd->reduce[l] ^ (p << g_s)); } if (xor) p ^= *d32; *d32 = p; d32++; s32++; } gf_do_final_region_alignment(&rd); } static void gf_w32_group_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint32_t *s32, *d32, *top; int i; int leftover; uint64_t p, l, r; uint32_t a32, ind; int g_s, g_r; struct gf_w32_group_data *gd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_internal_t *h = (gf_internal_t *) gf->scratch; g_s = h->arg1; g_r = h->arg2; gd = (struct gf_w32_group_data *) h->private; gf_w32_group_set_shift_tables(gd->shift, val, h); leftover = GF_FIELD_WIDTH % g_s; if (leftover == 0) leftover = g_s; gd = (struct gf_w32_group_data *) h->private; gf_w32_group_set_shift_tables(gd->shift, val, h); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; while (d32 < top) { a32 = *s32; ind = a32 >> (GF_FIELD_WIDTH - leftover); p = gd->shift[ind]; p <<= g_s; a32 <<= leftover; i = (GF_FIELD_WIDTH - leftover); while (i > g_s) { ind = a32 >> (GF_FIELD_WIDTH-g_s); p ^= gd->shift[ind]; a32 <<= g_s; p <<= g_s; i -= g_s; } ind = a32 >> (GF_FIELD_WIDTH-g_s); p ^= gd->shift[ind]; for (i = gd->tshift ; i >= 0; i -= g_r) { l = p & (gd->rmask << i); r = gd->reduce[l >> (i+32)]; r <<= (i); p ^= r; } if (xor) p ^= *d32; *d32 = p; d32++; s32++; } gf_do_final_region_alignment(&rd); } static inline gf_val_32_t gf_w32_group_s_equals_r_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int leftover, rs; uint32_t p, l, ind, a32; int bits_left; int g_s; struct gf_w32_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; g_s = h->arg1; gd = (struct gf_w32_group_data *) h->private; gf_w32_group_set_shift_tables(gd->shift, b, h); leftover = 32 % g_s; if (leftover == 0) leftover = g_s; rs = 32 - leftover; a32 = a; ind = a32 >> rs; a32 <<= leftover; p = gd->shift[ind]; bits_left = rs; rs = 32 - g_s; while (bits_left > 0) { bits_left -= g_s; ind = a32 >> rs; a32 <<= g_s; l = p >> rs; p = (gd->shift[ind] ^ gd->reduce[l] ^ (p << g_s)); } return p; } static inline gf_val_32_t gf_w32_group_4_4_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t p, l, ind, a32; struct gf_w32_group_data *d44; gf_internal_t *h = (gf_internal_t *) gf->scratch; d44 = (struct gf_w32_group_data *) h->private; gf_w32_group_set_shift_tables(d44->shift, b, h); p = 0; a32 = a; ind = a32 >> 28; a32 <<= 4; p = d44->shift[ind]; ind = a32 >> 28; a32 <<= 4; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); ind = a32 >> 28; a32 <<= 4; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); ind = a32 >> 28; a32 <<= 4; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); ind = a32 >> 28; a32 <<= 4; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); ind = a32 >> 28; a32 <<= 4; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); ind = a32 >> 28; a32 <<= 4; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); ind = a32 >> 28; l = p >> 28; p = (d44->shift[ind] ^ d44->reduce[l] ^ (p << 4)); return p; } static inline gf_val_32_t gf_w32_group_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int i; int leftover; uint64_t p, l, r; uint32_t a32, ind; int g_s, g_r; struct gf_w32_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; g_s = h->arg1; g_r = h->arg2; gd = (struct gf_w32_group_data *) h->private; gf_w32_group_set_shift_tables(gd->shift, b, h); leftover = GF_FIELD_WIDTH % g_s; if (leftover == 0) leftover = g_s; a32 = a; ind = a32 >> (GF_FIELD_WIDTH - leftover); p = gd->shift[ind]; p <<= g_s; a32 <<= leftover; i = (GF_FIELD_WIDTH - leftover); while (i > g_s) { ind = a32 >> (GF_FIELD_WIDTH-g_s); p ^= gd->shift[ind]; a32 <<= g_s; p <<= g_s; i -= g_s; } ind = a32 >> (GF_FIELD_WIDTH-g_s); p ^= gd->shift[ind]; for (i = gd->tshift ; i >= 0; i -= g_r) { l = p & (gd->rmask << i); r = gd->reduce[l >> (i+32)]; r <<= (i); p ^= r; } return p; } static inline gf_val_32_t gf_w32_bytwo_b_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, bmask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; bmask = 0x80000000; while (1) { if (a & 1) prod ^= b; a >>= 1; if (a == 0) return prod; if (b & bmask) { b = ((b << 1) ^ pp); } else { b <<= 1; } } } static inline gf_val_32_t gf_w32_bytwo_p_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, pmask, amask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; pmask = 0x80000000; amask = 0x80000000; while (amask != 0) { if (prod & pmask) { prod = ((prod << 1) ^ pp); } else { prod <<= 1; } if (a & amask) prod ^= b; amask >>= 1; } return prod; } static void gf_w32_bytwo_p_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, prod, amask; gf_region_data rd; struct gf_w32_bytwo_data *btd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_w32_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; if (xor) { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x80000000; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 ^= prod; d64++; s64++; } } else { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x80000000; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 = prod; d64++; s64++; } } gf_do_final_region_alignment(&rd); } #define BYTWO_P_ONESTEP {\ SSE_AB2(pp, m1 ,m2, prod, t1, t2); \ t1 = _mm_and_si128(v, one); \ t1 = _mm_sub_epi32(t1, one); \ t1 = _mm_and_si128(t1, ta); \ prod = _mm_xor_si128(prod, t1); \ v = _mm_srli_epi64(v, 1); } #ifdef INTEL_SSE2 static void gf_w32_bytwo_p_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8; uint32_t vrev; __m128i pp, m1, m2, ta, prod, t1, t2, tp, one, v; struct gf_w32_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_w32_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); vrev = 0; for (i = 0; i < 32; i++) { vrev <<= 1; if (!(val & (1 << i))) vrev |= 1; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi32(btd->prim_poly&0xffffffff); m1 = _mm_set1_epi32((btd->mask1)&0xffffffff); m2 = _mm_set1_epi32((btd->mask2)&0xffffffff); one = _mm_set1_epi32(1); while (d8 < (uint8_t *) rd.d_top) { prod = _mm_setzero_si128(); v = _mm_set1_epi32(vrev); ta = _mm_load_si128((__m128i *) s8); tp = (!xor) ? _mm_setzero_si128() : _mm_load_si128((__m128i *) d8); BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; _mm_store_si128((__m128i *) d8, _mm_xor_si128(prod, tp)); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif static void gf_w32_bytwo_b_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, tb, prod; struct gf_w32_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); btd = (struct gf_w32_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; switch (val) { case 2: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 3: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } case 4: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 5: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } default: if (xor) { while (d64 < (uint64_t *) rd.d_top) { prod = *d64 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { prod = 0 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } break; } gf_do_final_region_alignment(&rd); } #ifdef INTEL_SSE2 static void gf_w32_bytwo_b_sse_region_2_noxor(gf_region_data *rd, struct gf_w32_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi32(btd->prim_poly&0xffffffff); m1 = _mm_set1_epi32((btd->mask1)&0xffffffff); m2 = _mm_set1_epi32((btd->mask2)&0xffffffff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w32_bytwo_b_sse_region_2_xor(gf_region_data *rd, struct gf_w32_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi32(btd->prim_poly&0xffffffff); m1 = _mm_set1_epi32((btd->mask1)&0xffffffff); m2 = _mm_set1_epi32((btd->mask2)&0xffffffff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); vb = _mm_load_si128 ((__m128i *)(d8)); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w32_bytwo_b_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint32_t itb; uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; struct gf_w32_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); btd = (struct gf_w32_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; if (val == 2) { if (xor) { gf_w32_bytwo_b_sse_region_2_xor(&rd, btd); } else { gf_w32_bytwo_b_sse_region_2_noxor(&rd, btd); } gf_do_final_region_alignment(&rd); return; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi32(btd->prim_poly&0xffffffff); m1 = _mm_set1_epi32((btd->mask1)&0xffffffff); m2 = _mm_set1_epi32((btd->mask2)&0xffffffff); while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = (!xor) ? _mm_setzero_si128() : _mm_load_si128 ((__m128i *)(d8)); itb = val; while (1) { if (itb & 1) vb = _mm_xor_si128(vb, va); itb >>= 1; if (itb == 0) break; SSE_AB2(pp, m1, m2, va, t1, t2); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif static int gf_w32_bytwo_init(gf_t *gf) { gf_internal_t *h; uint64_t ip, m1, m2; struct gf_w32_bytwo_data *btd; h = (gf_internal_t *) gf->scratch; btd = (struct gf_w32_bytwo_data *) (h->private); ip = h->prim_poly & 0xffffffff; m1 = 0xfffffffe; m2 = 0x80000000; btd->prim_poly = 0; btd->mask1 = 0; btd->mask2 = 0; while (ip != 0) { btd->prim_poly |= ip; btd->mask1 |= m1; btd->mask2 |= m2; ip <<= GF_FIELD_WIDTH; m1 <<= GF_FIELD_WIDTH; m2 <<= GF_FIELD_WIDTH; } if (h->mult_type == GF_MULT_BYTWO_p) { gf->multiply.w32 = gf_w32_bytwo_p_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w32_bytwo_p_nosse_multiply_region; else gf->multiply_region.w32 = gf_w32_bytwo_p_sse_multiply_region; #else gf->multiply_region.w32 = gf_w32_bytwo_p_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } else { gf->multiply.w32 = gf_w32_bytwo_b_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w32_bytwo_b_nosse_multiply_region; else gf->multiply_region.w32 = gf_w32_bytwo_b_sse_multiply_region; #else gf->multiply_region.w32 = gf_w32_bytwo_b_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } gf->inverse.w32 = gf_w32_euclid; return 1; } static inline uint32_t gf_w32_split_8_8_multiply (gf_t *gf, uint32_t a32, uint32_t b32) { uint32_t product, i, j, mask, tb; gf_internal_t *h; struct gf_w32_split_8_8_data *d8; h = (gf_internal_t *) gf->scratch; d8 = (struct gf_w32_split_8_8_data *) h->private; product = 0; mask = 0xff; for (i = 0; i < 4; i++) { tb = b32; for (j = 0; j < 4; j++) { product ^= d8->tables[i+j][a32&mask][tb&mask]; tb >>= 8; } a32 >>= 8; } return product; } static inline void gf_w32_split_8_32_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h; uint32_t *s32, *d32, *top, p, a, v; struct gf_split_8_32_lazy_data *d8; struct gf_w32_split_8_8_data *d88; uint32_t *t[4]; int i, j, k, change; uint32_t pp; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; if (h->arg1 == 32 || h->arg2 == 32 || h->mult_type == GF_MULT_DEFAULT) { d8 = (struct gf_split_8_32_lazy_data *) h->private; for (i = 0; i < 4; i++) t[i] = d8->tables[i]; change = (val != d8->last_value); if (change) d8->last_value = val; } else { d88 = (struct gf_w32_split_8_8_data *) h->private; for (i = 0; i < 4; i++) t[i] = d88->region_tables[i]; change = (val != d88->last_value); if (change) d88->last_value = val; } pp = h->prim_poly; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; if (change) { v = val; for (i = 0; i < 4; i++) { t[i][0] = 0; for (j = 1; j < 256; j <<= 1) { for (k = 0; k < j; k++) { t[i][k^j] = (v ^ t[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } } } while (d32 < top) { p = (xor) ? *d32 : 0; a = *s32; i = 0; while (a != 0) { v = (a & 0xff); p ^= t[i][v]; a >>= 8; i++; } *d32 = p; d32++; s32++; } gf_do_final_region_alignment(&rd); } static inline void gf_w32_split_16_32_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h; uint32_t *s32, *d32, *top, p, a, v; struct gf_split_16_32_lazy_data *d16; uint32_t *t[2]; int i, j, k, change; uint32_t pp; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; d16 = (struct gf_split_16_32_lazy_data *) h->private; for (i = 0; i < 2; i++) t[i] = d16->tables[i]; change = (val != d16->last_value); if (change) d16->last_value = val; pp = h->prim_poly; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; if (change) { v = val; for (i = 0; i < 2; i++) { t[i][0] = 0; for (j = 1; j < (1 << 16); j <<= 1) { for (k = 0; k < j; k++) { t[i][k^j] = (v ^ t[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } } } while (d32 < top) { p = (xor) ? *d32 : 0; a = *s32; i = 0; while (a != 0) { v = (a & 0xffff); p ^= t[i][v]; a >>= 16; i++; } *d32 = p; d32++; s32++; } gf_do_final_region_alignment(&rd); } static void gf_w32_split_2_32_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h; struct gf_split_2_32_lazy_data *ld; int i; uint32_t pp, v, v2, s, *s32, *d32, *top; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; ld = (struct gf_split_2_32_lazy_data *) h->private; if (ld->last_value != val) { v = val; for (i = 0; i < 16; i++) { v2 = (v << 1); if (v & GF_FIRST_BIT) v2 ^= pp; ld->tables[i][0] = 0; ld->tables[i][1] = v; ld->tables[i][2] = v2; ld->tables[i][3] = (v2 ^ v); v = (v2 << 1); if (v2 & GF_FIRST_BIT) v ^= pp; } } ld->last_value = val; s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; while (d32 != top) { v = (xor) ? *d32 : 0; s = *s32; i = 0; while (s != 0) { v ^= ld->tables[i][s&3]; s >>= 2; i++; } *d32 = v; d32++; s32++; } gf_do_final_region_alignment(&rd); } #ifdef INTEL_SSSE3 static void gf_w32_split_2_32_lazy_sse_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h; int i, tindex; uint32_t pp, v, v2, *s32, *d32, *top; __m128i vi, si, pi, shuffler, tables[16], adder, xi, mask1, mask2; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; v = val; for (i = 0; i < 16; i++) { v2 = (v << 1); if (v & GF_FIRST_BIT) v2 ^= pp; tables[i] = _mm_set_epi32(v2 ^ v, v2, v, 0); v = (v2 << 1); if (v2 & GF_FIRST_BIT) v ^= pp; } shuffler = _mm_set_epi8(0xc, 0xc, 0xc, 0xc, 8, 8, 8, 8, 4, 4, 4, 4, 0, 0, 0, 0); adder = _mm_set_epi8(3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0); mask1 = _mm_set1_epi8(0x3); mask2 = _mm_set1_epi8(0xc); while (d32 != top) { pi = (xor) ? _mm_load_si128 ((__m128i *) d32) : _mm_setzero_si128(); vi = _mm_load_si128((__m128i *) s32); tindex = 0; for (i = 0; i < 4; i++) { si = _mm_shuffle_epi8(vi, shuffler); xi = _mm_and_si128(si, mask1); xi = _mm_slli_epi16(xi, 2); xi = _mm_xor_si128(xi, adder); pi = _mm_xor_si128(pi, _mm_shuffle_epi8(tables[tindex], xi)); tindex++; xi = _mm_and_si128(si, mask2); xi = _mm_xor_si128(xi, adder); pi = _mm_xor_si128(pi, _mm_shuffle_epi8(tables[tindex], xi)); si = _mm_srli_epi16(si, 2); tindex++; xi = _mm_and_si128(si, mask2); xi = _mm_xor_si128(xi, adder); pi = _mm_xor_si128(pi, _mm_shuffle_epi8(tables[tindex], xi)); si = _mm_srli_epi16(si, 2); tindex++; xi = _mm_and_si128(si, mask2); xi = _mm_xor_si128(xi, adder); pi = _mm_xor_si128(pi, _mm_shuffle_epi8(tables[tindex], xi)); si = _mm_srli_epi16(si, 2); tindex++; vi = _mm_srli_epi32(vi, 8); } _mm_store_si128((__m128i *) d32, pi); d32 += 4; s32 += 4; } gf_do_final_region_alignment(&rd); } #endif static void gf_w32_split_4_32_lazy_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h; struct gf_split_4_32_lazy_data *ld; int i, j, k; uint32_t pp, v, s, *s32, *d32, *top; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; ld = (struct gf_split_4_32_lazy_data *) h->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); gf_do_initial_region_alignment(&rd); if (ld->last_value != val) { v = val; for (i = 0; i < 8; i++) { ld->tables[i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } } } ld->last_value = val; s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; while (d32 != top) { v = (xor) ? *d32 : 0; s = *s32; i = 0; while (s != 0) { v ^= ld->tables[i][s&0xf]; s >>= 4; i++; } *d32 = v; d32++; s32++; } gf_do_final_region_alignment(&rd); } static void gf_w32_split_4_32_lazy_sse_altmap_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { #ifdef INTEL_SSSE3 gf_internal_t *h; int i, j, k; uint32_t pp, v, *s32, *d32, *top; __m128i si, tables[8][4], p0, p1, p2, p3, mask1, v0, v1, v2, v3; struct gf_split_4_32_lazy_data *ld; uint8_t btable[16]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 64); gf_do_initial_region_alignment(&rd); s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; ld = (struct gf_split_4_32_lazy_data *) h->private; v = val; for (i = 0; i < 8; i++) { ld->tables[i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[i][k^j] = (v ^ ld->tables[i][k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } for (j = 0; j < 4; j++) { for (k = 0; k < 16; k++) { btable[k] = (uint8_t) ld->tables[i][k]; ld->tables[i][k] >>= 8; } tables[i][j] = _mm_loadu_si128((__m128i *) btable); } } mask1 = _mm_set1_epi8(0xf); if (xor) { while (d32 != top) { p0 = _mm_load_si128 ((__m128i *) d32); p1 = _mm_load_si128 ((__m128i *) (d32+4)); p2 = _mm_load_si128 ((__m128i *) (d32+8)); p3 = _mm_load_si128 ((__m128i *) (d32+12)); v0 = _mm_load_si128((__m128i *) s32); s32 += 4; v1 = _mm_load_si128((__m128i *) s32); s32 += 4; v2 = _mm_load_si128((__m128i *) s32); s32 += 4; v3 = _mm_load_si128((__m128i *) s32); s32 += 4; si = _mm_and_si128(v0, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[0][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[0][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[0][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[0][3], si)); v0 = _mm_srli_epi32(v0, 4); si = _mm_and_si128(v0, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[1][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[1][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[1][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[1][3], si)); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[2][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[2][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[2][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[2][3], si)); v1 = _mm_srli_epi32(v1, 4); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[3][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[3][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[3][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[3][3], si)); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[4][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[4][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[4][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[4][3], si)); v2 = _mm_srli_epi32(v2, 4); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[5][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[5][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[5][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[5][3], si)); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[6][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[6][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[6][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[6][3], si)); v3 = _mm_srli_epi32(v3, 4); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[7][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[7][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[7][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[7][3], si)); _mm_store_si128((__m128i *) d32, p0); _mm_store_si128((__m128i *) (d32+4), p1); _mm_store_si128((__m128i *) (d32+8), p2); _mm_store_si128((__m128i *) (d32+12), p3); d32 += 16; } } else { while (d32 != top) { v0 = _mm_load_si128((__m128i *) s32); s32 += 4; v1 = _mm_load_si128((__m128i *) s32); s32 += 4; v2 = _mm_load_si128((__m128i *) s32); s32 += 4; v3 = _mm_load_si128((__m128i *) s32); s32 += 4; si = _mm_and_si128(v0, mask1); p0 = _mm_shuffle_epi8(tables[0][0], si); p1 = _mm_shuffle_epi8(tables[0][1], si); p2 = _mm_shuffle_epi8(tables[0][2], si); p3 = _mm_shuffle_epi8(tables[0][3], si); v0 = _mm_srli_epi32(v0, 4); si = _mm_and_si128(v0, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[1][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[1][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[1][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[1][3], si)); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[2][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[2][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[2][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[2][3], si)); v1 = _mm_srli_epi32(v1, 4); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[3][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[3][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[3][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[3][3], si)); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[4][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[4][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[4][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[4][3], si)); v2 = _mm_srli_epi32(v2, 4); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[5][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[5][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[5][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[5][3], si)); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[6][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[6][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[6][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[6][3], si)); v3 = _mm_srli_epi32(v3, 4); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[7][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[7][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[7][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[7][3], si)); _mm_store_si128((__m128i *) d32, p0); _mm_store_si128((__m128i *) (d32+4), p1); _mm_store_si128((__m128i *) (d32+8), p2); _mm_store_si128((__m128i *) (d32+12), p3); d32 += 16; } } gf_do_final_region_alignment(&rd); #endif } static void gf_w32_split_4_32_lazy_sse_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { #ifdef INTEL_SSSE3 gf_internal_t *h; int i, j, k; uint32_t pp, v, *s32, *d32, *top, tmp_table[16]; __m128i si, tables[8][4], p0, p1, p2, p3, mask1, v0, v1, v2, v3, mask8; __m128i tv1, tv2, tv3, tv0; uint8_t btable[16]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 64); gf_do_initial_region_alignment(&rd); s32 = (uint32_t *) rd.s_start; d32 = (uint32_t *) rd.d_start; top = (uint32_t *) rd.d_top; v = val; for (i = 0; i < 8; i++) { tmp_table[0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { tmp_table[k^j] = (v ^ tmp_table[k]); } v = (v & GF_FIRST_BIT) ? ((v << 1) ^ pp) : (v << 1); } for (j = 0; j < 4; j++) { for (k = 0; k < 16; k++) { btable[k] = (uint8_t) tmp_table[k]; tmp_table[k] >>= 8; } tables[i][j] = _mm_loadu_si128((__m128i *) btable); } } mask1 = _mm_set1_epi8(0xf); mask8 = _mm_set1_epi16(0xff); if (xor) { while (d32 != top) { v0 = _mm_load_si128((__m128i *) s32); s32 += 4; v1 = _mm_load_si128((__m128i *) s32); s32 += 4; v2 = _mm_load_si128((__m128i *) s32); s32 += 4; v3 = _mm_load_si128((__m128i *) s32); s32 += 4; p0 = _mm_srli_epi16(v0, 8); p1 = _mm_srli_epi16(v1, 8); p2 = _mm_srli_epi16(v2, 8); p3 = _mm_srli_epi16(v3, 8); tv0 = _mm_and_si128(v0, mask8); tv1 = _mm_and_si128(v1, mask8); tv2 = _mm_and_si128(v2, mask8); tv3 = _mm_and_si128(v3, mask8); v0 = _mm_packus_epi16(p1, p0); v1 = _mm_packus_epi16(tv1, tv0); v2 = _mm_packus_epi16(p3, p2); v3 = _mm_packus_epi16(tv3, tv2); p0 = _mm_srli_epi16(v0, 8); p1 = _mm_srli_epi16(v1, 8); p2 = _mm_srli_epi16(v2, 8); p3 = _mm_srli_epi16(v3, 8); tv0 = _mm_and_si128(v0, mask8); tv1 = _mm_and_si128(v1, mask8); tv2 = _mm_and_si128(v2, mask8); tv3 = _mm_and_si128(v3, mask8); v0 = _mm_packus_epi16(p2, p0); v1 = _mm_packus_epi16(p3, p1); v2 = _mm_packus_epi16(tv2, tv0); v3 = _mm_packus_epi16(tv3, tv1); si = _mm_and_si128(v0, mask1); p0 = _mm_shuffle_epi8(tables[6][0], si); p1 = _mm_shuffle_epi8(tables[6][1], si); p2 = _mm_shuffle_epi8(tables[6][2], si); p3 = _mm_shuffle_epi8(tables[6][3], si); v0 = _mm_srli_epi32(v0, 4); si = _mm_and_si128(v0, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[7][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[7][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[7][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[7][3], si)); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[4][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[4][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[4][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[4][3], si)); v1 = _mm_srli_epi32(v1, 4); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[5][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[5][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[5][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[5][3], si)); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[2][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[2][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[2][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[2][3], si)); v2 = _mm_srli_epi32(v2, 4); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[3][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[3][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[3][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[3][3], si)); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[0][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[0][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[0][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[0][3], si)); v3 = _mm_srli_epi32(v3, 4); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[1][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[1][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[1][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[1][3], si)); tv0 = _mm_unpackhi_epi8(p1, p3); tv1 = _mm_unpackhi_epi8(p0, p2); tv2 = _mm_unpacklo_epi8(p1, p3); tv3 = _mm_unpacklo_epi8(p0, p2); p0 = _mm_unpackhi_epi8(tv1, tv0); p1 = _mm_unpacklo_epi8(tv1, tv0); p2 = _mm_unpackhi_epi8(tv3, tv2); p3 = _mm_unpacklo_epi8(tv3, tv2); v0 = _mm_load_si128 ((__m128i *) d32); v1 = _mm_load_si128 ((__m128i *) (d32+4)); v2 = _mm_load_si128 ((__m128i *) (d32+8)); v3 = _mm_load_si128 ((__m128i *) (d32+12)); p0 = _mm_xor_si128(p0, v0); p1 = _mm_xor_si128(p1, v1); p2 = _mm_xor_si128(p2, v2); p3 = _mm_xor_si128(p3, v3); _mm_store_si128((__m128i *) d32, p0); _mm_store_si128((__m128i *) (d32+4), p1); _mm_store_si128((__m128i *) (d32+8), p2); _mm_store_si128((__m128i *) (d32+12), p3); d32 += 16; } } else { while (d32 != top) { v0 = _mm_load_si128((__m128i *) s32); s32 += 4; v1 = _mm_load_si128((__m128i *) s32); s32 += 4; v2 = _mm_load_si128((__m128i *) s32); s32 += 4; v3 = _mm_load_si128((__m128i *) s32); s32 += 4; p0 = _mm_srli_epi16(v0, 8); p1 = _mm_srli_epi16(v1, 8); p2 = _mm_srli_epi16(v2, 8); p3 = _mm_srli_epi16(v3, 8); tv0 = _mm_and_si128(v0, mask8); tv1 = _mm_and_si128(v1, mask8); tv2 = _mm_and_si128(v2, mask8); tv3 = _mm_and_si128(v3, mask8); v0 = _mm_packus_epi16(p1, p0); v1 = _mm_packus_epi16(tv1, tv0); v2 = _mm_packus_epi16(p3, p2); v3 = _mm_packus_epi16(tv3, tv2); p0 = _mm_srli_epi16(v0, 8); p1 = _mm_srli_epi16(v1, 8); p2 = _mm_srli_epi16(v2, 8); p3 = _mm_srli_epi16(v3, 8); tv0 = _mm_and_si128(v0, mask8); tv1 = _mm_and_si128(v1, mask8); tv2 = _mm_and_si128(v2, mask8); tv3 = _mm_and_si128(v3, mask8); v0 = _mm_packus_epi16(p2, p0); v1 = _mm_packus_epi16(p3, p1); v2 = _mm_packus_epi16(tv2, tv0); v3 = _mm_packus_epi16(tv3, tv1); p0 = v0; p1 = v1; p2 = v2; p3 = v3; si = _mm_and_si128(v0, mask1); p0 = _mm_shuffle_epi8(tables[6][0], si); p1 = _mm_shuffle_epi8(tables[6][1], si); p2 = _mm_shuffle_epi8(tables[6][2], si); p3 = _mm_shuffle_epi8(tables[6][3], si); v0 = _mm_srli_epi32(v0, 4); si = _mm_and_si128(v0, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[7][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[7][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[7][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[7][3], si)); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[4][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[4][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[4][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[4][3], si)); v1 = _mm_srli_epi32(v1, 4); si = _mm_and_si128(v1, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[5][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[5][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[5][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[5][3], si)); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[2][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[2][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[2][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[2][3], si)); v2 = _mm_srli_epi32(v2, 4); si = _mm_and_si128(v2, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[3][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[3][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[3][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[3][3], si)); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[0][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[0][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[0][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[0][3], si)); v3 = _mm_srli_epi32(v3, 4); si = _mm_and_si128(v3, mask1); p0 = _mm_xor_si128(p0, _mm_shuffle_epi8(tables[1][0], si)); p1 = _mm_xor_si128(p1, _mm_shuffle_epi8(tables[1][1], si)); p2 = _mm_xor_si128(p2, _mm_shuffle_epi8(tables[1][2], si)); p3 = _mm_xor_si128(p3, _mm_shuffle_epi8(tables[1][3], si)); tv0 = _mm_unpackhi_epi8(p1, p3); tv1 = _mm_unpackhi_epi8(p0, p2); tv2 = _mm_unpacklo_epi8(p1, p3); tv3 = _mm_unpacklo_epi8(p0, p2); p0 = _mm_unpackhi_epi8(tv1, tv0); p1 = _mm_unpacklo_epi8(tv1, tv0); p2 = _mm_unpackhi_epi8(tv3, tv2); p3 = _mm_unpacklo_epi8(tv3, tv2); _mm_store_si128((__m128i *) d32, p0); _mm_store_si128((__m128i *) (d32+4), p1); _mm_store_si128((__m128i *) (d32+8), p2); _mm_store_si128((__m128i *) (d32+12), p3); d32 += 16; } } gf_do_final_region_alignment(&rd); #endif } static int gf_w32_split_init(gf_t *gf) { gf_internal_t *h; struct gf_split_2_32_lazy_data *ld2; struct gf_split_4_32_lazy_data *ld4; struct gf_w32_split_8_8_data *d8; struct gf_split_8_32_lazy_data *d32; struct gf_split_16_32_lazy_data *d16; uint32_t p, basep; int i, j, exp, ispclmul, issse3; ispclmul = 0; #if defined(INTEL_SSE4_PCLMUL) ispclmul = 1; #endif issse3 = 0; #ifdef INTEL_SSSE3 issse3 = 1; #endif h = (gf_internal_t *) gf->scratch; /* Defaults */ gf->inverse.w32 = gf_w32_euclid; /* JSP: First handle single multiplication: If args == 8, then we're doing split 8 8. Otherwise, if PCLMUL, we use that. Otherwise, we use bytwo_p. */ if (h->arg1 == 8 && h->arg2 == 8) { gf->multiply.w32 = gf_w32_split_8_8_multiply; } else if (ispclmul) { if ((0xfffe0000 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w32_clm_multiply_2; } else if ((0xffc00000 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w32_clm_multiply_3; } else if ((0xfe000000 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w32_clm_multiply_4; } } else { gf->multiply.w32 = gf_w32_bytwo_p_multiply; } /* Easy cases: 16/32 and 2/32 */ if ((h->arg1 == 16 && h->arg2 == 32) || (h->arg1 == 32 && h->arg2 == 16)) { d16 = (struct gf_split_16_32_lazy_data *) h->private; d16->last_value = 0; gf->multiply_region.w32 = gf_w32_split_16_32_lazy_multiply_region; return 1; } if ((h->arg1 == 2 && h->arg2 == 32) || (h->arg1 == 32 && h->arg2 == 2)) { ld2 = (struct gf_split_2_32_lazy_data *) h->private; ld2->last_value = 0; #ifdef INTEL_SSSE3 if (!(h->region_type & GF_REGION_NOSSE)) gf->multiply_region.w32 = gf_w32_split_2_32_lazy_sse_multiply_region; else gf->multiply_region.w32 = gf_w32_split_2_32_lazy_multiply_region; #else gf->multiply_region.w32 = gf_w32_split_2_32_lazy_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif return 1; } /* 4/32 or Default + SSE - There is no ALTMAP/NOSSE. */ if ((h->arg1 == 4 && h->arg2 == 32) || (h->arg1 == 32 && h->arg2 == 4) || (issse3 && h->mult_type == GF_REGION_DEFAULT)) { ld4 = (struct gf_split_4_32_lazy_data *) h->private; ld4->last_value = 0; if ((h->region_type & GF_REGION_NOSSE) || !issse3) { gf->multiply_region.w32 = gf_w32_split_4_32_lazy_multiply_region; } else if (h->region_type & GF_REGION_ALTMAP) { gf->multiply_region.w32 = gf_w32_split_4_32_lazy_sse_altmap_multiply_region; } else { gf->multiply_region.w32 = gf_w32_split_4_32_lazy_sse_multiply_region; } return 1; } /* 8/32 or Default + no SSE */ if ((h->arg1 == 8 && h->arg2 == 32) || (h->arg1 == 32 && h->arg2 == 8) || h->mult_type == GF_MULT_DEFAULT) { d32 = (struct gf_split_8_32_lazy_data *) h->private; d32->last_value = 0; gf->multiply_region.w32 = gf_w32_split_8_32_lazy_multiply_region; return 1; } /* Finally, if args == 8, then we have to set up the tables here. */ if (h->arg1 == 8 && h->arg2 == 8) { d8 = (struct gf_w32_split_8_8_data *) h->private; d8->last_value = 0; gf->multiply.w32 = gf_w32_split_8_8_multiply; gf->multiply_region.w32 = gf_w32_split_8_32_lazy_multiply_region; basep = 1; for (exp = 0; exp < 7; exp++) { for (j = 0; j < 256; j++) d8->tables[exp][0][j] = 0; for (i = 0; i < 256; i++) d8->tables[exp][i][0] = 0; d8->tables[exp][1][1] = basep; for (i = 2; i < 256; i++) { if (i&1) { p = d8->tables[exp][i^1][1]; d8->tables[exp][i][1] = p ^ basep; } else { p = d8->tables[exp][i>>1][1]; d8->tables[exp][i][1] = GF_MULTBY_TWO(p); } } for (i = 1; i < 256; i++) { p = d8->tables[exp][i][1]; for (j = 1; j < 256; j++) { if (j&1) { d8->tables[exp][i][j] = d8->tables[exp][i][j^1] ^ p; } else { d8->tables[exp][i][j] = GF_MULTBY_TWO(d8->tables[exp][i][j>>1]); } } } for (i = 0; i < 8; i++) basep = GF_MULTBY_TWO(basep); } return 1; } /* If we get here, then the arguments were bad. */ return 0; } static int gf_w32_group_init(gf_t *gf) { uint32_t i, j, p, index; struct gf_w32_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; int g_r, g_s; g_s = h->arg1; g_r = h->arg2; gd = (struct gf_w32_group_data *) h->private; gd->shift = (uint32_t *) (&(gd->memory)); gd->reduce = gd->shift + (1 << g_s); gd->rmask = (1 << g_r) - 1; gd->rmask <<= 32; gd->tshift = 32 % g_s; if (gd->tshift == 0) gd->tshift = g_s; gd->tshift = (32 - gd->tshift); gd->tshift = ((gd->tshift-1)/g_r) * g_r; gd->reduce[0] = 0; for (i = 0; i < (1 << g_r); i++) { p = 0; index = 0; for (j = 0; j < g_r; j++) { if (i & (1 << j)) { p ^= (h->prim_poly << j); index ^= (1 << j); index ^= (h->prim_poly >> (32-j)); } } gd->reduce[index] = p; } if (g_s == g_r) { gf->multiply.w32 = gf_w32_group_s_equals_r_multiply; gf->multiply_region.w32 = gf_w32_group_s_equals_r_multiply_region; } else { gf->multiply.w32 = gf_w32_group_multiply; gf->multiply_region.w32 = gf_w32_group_multiply_region; } gf->divide.w32 = NULL; gf->inverse.w32 = gf_w32_euclid; return 1; } static uint32_t gf_w32_composite_multiply_recursive(gf_t *gf, uint32_t a, uint32_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint32_t b0 = b & 0x0000ffff; uint32_t b1 = (b & 0xffff0000) >> 16; uint32_t a0 = a & 0x0000ffff; uint32_t a1 = (a & 0xffff0000) >> 16; uint32_t a1b1; uint32_t rv; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); rv = ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 16) | (base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1); return rv; } /* JSP: This could be made faster. Someday, when I'm bored. */ static uint32_t gf_w32_composite_multiply_inline(gf_t *gf, uint32_t a, uint32_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; uint32_t b0 = b & 0x0000ffff; uint32_t b1 = b >> 16; uint32_t a0 = a & 0x0000ffff; uint32_t a1 = a >> 16; uint32_t a1b1, prod; uint16_t *log, *alog; struct gf_w32_composite_data *cd; cd = (struct gf_w32_composite_data *) h->private; log = cd->log; alog = cd->alog; a1b1 = GF_W16_INLINE_MULT(log, alog, a1, b1); prod = GF_W16_INLINE_MULT(log, alog, a1, b0); prod ^= GF_W16_INLINE_MULT(log, alog, a0, b1); prod ^= GF_W16_INLINE_MULT(log, alog, a1b1, h->prim_poly); prod <<= 16; prod ^= GF_W16_INLINE_MULT(log, alog, a0, b0); prod ^= a1b1; return prod; } /* * Composite field division trick (explained in 2007 tech report) * * Compute a / b = a*b^-1, where p(x) = x^2 + sx + 1 * * let c = b^-1 * * c*b = (s*b1c1+b1c0+b0c1)x+(b1c1+b0c0) * * want (s*b1c1+b1c0+b0c1) = 0 and (b1c1+b0c0) = 1 * * let d = b1c1 and d+1 = b0c0 * * solve s*b1c1+b1c0+b0c1 = 0 * * solution: d = (b1b0^-1)(b1b0^-1+b0b1^-1+s)^-1 * * c0 = (d+1)b0^-1 * c1 = d*b1^-1 * * a / b = a * c */ static uint32_t gf_w32_composite_inverse(gf_t *gf, uint32_t a) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint16_t a0 = a & 0x0000ffff; uint16_t a1 = (a & 0xffff0000) >> 16; uint16_t c0, c1, d, tmp; uint32_t c; uint16_t a0inv, a1inv; if (a0 == 0) { a1inv = base_gf->inverse.w32(base_gf, a1); c0 = base_gf->multiply.w32(base_gf, a1inv, h->prim_poly); c1 = a1inv; } else if (a1 == 0) { c0 = base_gf->inverse.w32(base_gf, a0); c1 = 0; } else { a1inv = base_gf->inverse.w32(base_gf, a1); a0inv = base_gf->inverse.w32(base_gf, a0); d = base_gf->multiply.w32(base_gf, a1, a0inv); tmp = (base_gf->multiply.w32(base_gf, a1, a0inv) ^ base_gf->multiply.w32(base_gf, a0, a1inv) ^ h->prim_poly); tmp = base_gf->inverse.w32(base_gf, tmp); d = base_gf->multiply.w32(base_gf, d, tmp); c0 = base_gf->multiply.w32(base_gf, (d^1), a0inv); c1 = base_gf->multiply.w32(base_gf, d, a1inv); } c = c0 | (c1 << 16); return c; } static void gf_w32_composite_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint32_t b0 = val & 0x0000ffff; uint32_t b1 = (val & 0xffff0000) >> 16; uint32_t *s32, *d32, *top; uint16_t a0, a1, a1b1, *log, *alog; uint32_t prod; gf_region_data rd; struct gf_w32_composite_data *cd; cd = (struct gf_w32_composite_data *) h->private; log = cd->log; alog = cd->alog; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 4); s32 = rd.s_start; d32 = rd.d_start; top = rd.d_top; if (log == NULL) { if (xor) { while (d32 < top) { a0 = *s32 & 0x0000ffff; a1 = (*s32 & 0xffff0000) >> 16; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); *d32 ^= ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 16)); s32++; d32++; } } else { while (d32 < top) { a0 = *s32 & 0x0000ffff; a1 = (*s32 & 0xffff0000) >> 16; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); *d32 = ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 16)); s32++; d32++; } } } else { if (xor) { while (d32 < top) { a0 = *s32 & 0x0000ffff; a1 = (*s32 & 0xffff0000) >> 16; a1b1 = GF_W16_INLINE_MULT(log, alog, a1, b1); prod = GF_W16_INLINE_MULT(log, alog, a1, b0); prod ^= GF_W16_INLINE_MULT(log, alog, a0, b1); prod ^= GF_W16_INLINE_MULT(log, alog, a1b1, h->prim_poly); prod <<= 16; prod ^= GF_W16_INLINE_MULT(log, alog, a0, b0); prod ^= a1b1; *d32 ^= prod; s32++; d32++; } } else { while (d32 < top) { a0 = *s32 & 0x0000ffff; a1 = (*s32 & 0xffff0000) >> 16; a1b1 = GF_W16_INLINE_MULT(log, alog, a1, b1); prod = GF_W16_INLINE_MULT(log, alog, a1, b0); prod ^= GF_W16_INLINE_MULT(log, alog, a0, b1); prod ^= GF_W16_INLINE_MULT(log, alog, a1b1, h->prim_poly); prod <<= 16; prod ^= GF_W16_INLINE_MULT(log, alog, a0, b0); prod ^= a1b1; *d32 = prod; s32++; d32++; } } } } static void gf_w32_composite_multiply_region_alt(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint16_t val0 = val & 0x0000ffff; uint16_t val1 = (val & 0xffff0000) >> 16; gf_region_data rd; int sub_reg_size; uint8_t *slow, *shigh; uint8_t *dlow, *dhigh, *top; /* JSP: I want the two pointers aligned wrt each other on 16 byte boundaries. So I'm going to make sure that the area on which the two operate is a multiple of 32. Of course, that junks up the mapping, but so be it -- that's why we have extract_word.... */ gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); slow = (uint8_t *) rd.s_start; dlow = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_reg_size = (top - dlow)/2; shigh = slow + sub_reg_size; dhigh = dlow + sub_reg_size; base_gf->multiply_region.w32(base_gf, slow, dlow, val0, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, shigh, dlow, val1, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, slow, dhigh, val1, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, shigh, dhigh, val0, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, shigh, dhigh, base_gf->multiply.w32(base_gf, h->prim_poly, val1), sub_reg_size, 1); gf_do_final_region_alignment(&rd); } static int gf_w32_composite_init(gf_t *gf) { gf_internal_t *h = (gf_internal_t *) gf->scratch; struct gf_w32_composite_data *cd; if (h->base_gf == NULL) return 0; cd = (struct gf_w32_composite_data *) h->private; cd->log = gf_w16_get_log_table(h->base_gf); cd->alog = gf_w16_get_mult_alog_table(h->base_gf); if (h->region_type & GF_REGION_ALTMAP) { gf->multiply_region.w32 = gf_w32_composite_multiply_region_alt; } else { gf->multiply_region.w32 = gf_w32_composite_multiply_region; } if (cd->log == NULL) { gf->multiply.w32 = gf_w32_composite_multiply_recursive; } else { gf->multiply.w32 = gf_w32_composite_multiply_inline; } gf->divide.w32 = NULL; gf->inverse.w32 = gf_w32_composite_inverse; return 1; } int gf_w32_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2) { int issse3 = 0; #ifdef INTEL_SSSE3 issse3 = 1; #endif switch(mult_type) { case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: return sizeof(gf_internal_t) + sizeof(struct gf_w32_bytwo_data) + 64; break; case GF_MULT_GROUP: return sizeof(gf_internal_t) + sizeof(struct gf_w32_group_data) + sizeof(uint32_t) * (1 << arg1) + sizeof(uint32_t) * (1 << arg2) + 64; break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if (arg1 == 8 && arg2 == 8){ return sizeof(gf_internal_t) + sizeof(struct gf_w32_split_8_8_data) + 64; } if ((arg1 == 16 && arg2 == 32) || (arg2 == 16 && arg1 == 32)) { return sizeof(gf_internal_t) + sizeof(struct gf_split_16_32_lazy_data) + 64; } if ((arg1 == 2 && arg2 == 32) || (arg2 == 2 && arg1 == 32)) { return sizeof(gf_internal_t) + sizeof(struct gf_split_2_32_lazy_data) + 64; } if ((arg1 == 8 && arg2 == 32) || (arg2 == 8 && arg1 == 32) || (mult_type == GF_MULT_DEFAULT && !issse3)) { return sizeof(gf_internal_t) + sizeof(struct gf_split_8_32_lazy_data) + 64; } if ((arg1 == 4 && arg2 == 32) || (arg2 == 4 && arg1 == 32) || mult_type == GF_MULT_DEFAULT) { return sizeof(gf_internal_t) + sizeof(struct gf_split_4_32_lazy_data) + 64; } return 0; case GF_MULT_CARRY_FREE: return sizeof(gf_internal_t); break; case GF_MULT_SHIFT: return sizeof(gf_internal_t); break; case GF_MULT_COMPOSITE: return sizeof(gf_internal_t) + sizeof(struct gf_w32_composite_data) + 64; break; default: return 0; } return 0; } int gf_w32_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; /* Allen: set default primitive polynomial / irreducible polynomial if needed */ if (h->prim_poly == 0) { if (h->mult_type == GF_MULT_COMPOSITE) { h->prim_poly = gf_composite_get_default_poly(h->base_gf); if (h->prim_poly == 0) return 0; /* This shouldn't happen */ } else { /* Allen: use the following primitive polynomial to make carryless multiply work more efficiently for GF(2^32).*/ /* h->prim_poly = 0xc5; */ /* Allen: The following is the traditional primitive polynomial for GF(2^32) */ h->prim_poly = 0x400007; } } /* No leading one */ if(h->mult_type != GF_MULT_COMPOSITE) h->prim_poly &= 0xffffffff; gf->multiply.w32 = NULL; gf->divide.w32 = NULL; gf->inverse.w32 = NULL; gf->multiply_region.w32 = NULL; switch(h->mult_type) { case GF_MULT_CARRY_FREE: if (gf_w32_cfm_init(gf) == 0) return 0; break; case GF_MULT_SHIFT: if (gf_w32_shift_init(gf) == 0) return 0; break; case GF_MULT_COMPOSITE: if (gf_w32_composite_init(gf) == 0) return 0; break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if (gf_w32_split_init(gf) == 0) return 0; break; case GF_MULT_GROUP: if (gf_w32_group_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: if (gf_w32_bytwo_init(gf) == 0) return 0; break; default: return 0; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w32 = gf_w32_divide_from_inverse; gf->inverse.w32 = gf_w32_euclid; } else if (h->divide_type == GF_DIVIDE_MATRIX) { gf->divide.w32 = gf_w32_divide_from_inverse; gf->inverse.w32 = gf_w32_matrix; } if (gf->inverse.w32 != NULL && gf->divide.w32 == NULL) { gf->divide.w32 = gf_w32_divide_from_inverse; } if (gf->inverse.w32 == NULL && gf->divide.w32 != NULL) { gf->inverse.w32 = gf_w32_inverse_from_divide; } if (h->region_type == GF_REGION_CAUCHY) { gf->extract_word.w32 = gf_wgen_extract_word; gf->multiply_region.w32 = gf_wgen_cauchy_region; } else if (h->region_type & GF_REGION_ALTMAP) { if (h->mult_type == GF_MULT_COMPOSITE) { gf->extract_word.w32 = gf_w32_composite_extract_word; } else { gf->extract_word.w32 = gf_w32_split_extract_word; } } else { gf->extract_word.w32 = gf_w32_extract_word; } return 1; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf.c0000664000175100017510000011171512623076752025420 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf.c * * Generic routines for Galois fields */ #include "gf_int.h" #include #include int _gf_errno = GF_E_DEFAULT; void gf_error() { char *s; switch(_gf_errno) { case GF_E_DEFAULT: s = "No Error."; break; case GF_E_TWOMULT: s = "Cannot specify two -m's."; break; case GF_E_TWO_DIV: s = "Cannot specify two -d's."; break; case GF_E_POLYSPC: s = "-p needs to be followed by a number in hex (0x optional)."; break; case GF_E_GROUPAR: s = "Ran out of arguments in -m GROUP."; break; case GF_E_GROUPNU: s = "In -m GROUP g_s g_r -- g_s and g_r need to be numbers."; break; case GF_E_SPLITAR: s = "Ran out of arguments in -m SPLIT."; break; case GF_E_SPLITNU: s = "In -m SPLIT w_a w_b -- w_a and w_b need to be numbers."; break; case GF_E_FEWARGS: s = "Not enough arguments (Perhaps end with '-'?)"; break; case GF_E_CFM___W: s = "-m CARRY_FREE, w must be 4, 8, 16, 32, 64 or 128."; break; case GF_E_COMPXPP: s = "-m COMPOSITE, No poly specified, and we don't have a default for the given sub-field."; break; case GF_E_BASE__W: s = "-m COMPOSITE and the base field is not for w/2."; break; case GF_E_CFM4POL: s = "-m CARRY_FREE, w=4. (Prim-poly & 0xc) must equal 0."; break; case GF_E_CFM8POL: s = "-m CARRY_FREE, w=8. (Prim-poly & 0x80) must equal 0."; break; case GF_E_CF16POL: s = "-m CARRY_FREE, w=16. (Prim-poly & 0xe000) must equal 0."; break; case GF_E_CF32POL: s = "-m CARRY_FREE, w=32. (Prim-poly & 0xfe000000) must equal 0."; break; case GF_E_CF64POL: s = "-m CARRY_FREE, w=64. (Prim-poly & 0xfffe000000000000ULL) must equal 0."; break; case GF_E_MDEFDIV: s = "If multiplication method == default, can't change division."; break; case GF_E_MDEFREG: s = "If multiplication method == default, can't change region."; break; case GF_E_MDEFARG: s = "If multiplication method == default, can't use arg1/arg2."; break; case GF_E_DIVCOMP: s = "Cannot change the division technique with -m COMPOSITE."; break; case GF_E_DOUQUAD: s = "Cannot specify -r DOUBLE and -r QUAD."; break; case GF_E_SSE__NO: s = "Cannot specify -r SSE and -r NOSSE."; break; case GF_E_CAUCHYB: s = "Cannot specify -r CAUCHY and any other -r."; break; case GF_E_CAUCOMP: s = "Cannot specify -m COMPOSITE and -r CAUCHY."; break; case GF_E_CAUGT32: s = "Cannot specify -r CAUCHY with w > 32."; break; case GF_E_ARG1SET: s = "Only use arg1 with SPLIT, GROUP or COMPOSITE."; break; case GF_E_ARG2SET: s = "Only use arg2 with SPLIT or GROUP."; break; case GF_E_MATRIXW: s = "Cannot specify -d MATRIX with w > 32."; break; case GF_E_BAD___W: s = "W must be 1-32, 64 or 128."; break; case GF_E_DOUBLET: s = "Can only specify -r DOUBLE with -m TABLE."; break; case GF_E_DOUBLEW: s = "Can only specify -r DOUBLE w = 4 or w = 8."; break; case GF_E_DOUBLEJ: s = "Cannot specify -r DOUBLE with -r ALTMAP|SSE|NOSSE."; break; case GF_E_DOUBLEL: s = "Can only specify -r DOUBLE -r LAZY with w = 8"; break; case GF_E_QUAD__T: s = "Can only specify -r QUAD with -m TABLE."; break; case GF_E_QUAD__W: s = "Can only specify -r QUAD w = 4."; break; case GF_E_QUAD__J: s = "Cannot specify -r QUAD with -r ALTMAP|SSE|NOSSE."; break; case GF_E_BADPOLY: s = "Bad primitive polynomial (high bits set)."; break; case GF_E_COMP_PP: s = "Bad primitive polynomial -- bigger than sub-field."; break; case GF_E_LAZY__X: s = "If -r LAZY, then -r must be DOUBLE or QUAD."; break; case GF_E_ALTSHIF: s = "Cannot specify -m SHIFT and -r ALTMAP."; break; case GF_E_SSESHIF: s = "Cannot specify -m SHIFT and -r SSE|NOSSE."; break; case GF_E_ALT_CFM: s = "Cannot specify -m CARRY_FREE and -r ALTMAP."; break; case GF_E_SSE_CFM: s = "Cannot specify -m CARRY_FREE and -r SSE|NOSSE."; break; case GF_E_PCLMULX: s = "Specified -m CARRY_FREE, but PCLMUL is not supported."; break; case GF_E_ALT_BY2: s = "Cannot specify -m BYTWO_x and -r ALTMAP."; break; case GF_E_BY2_SSE: s = "Specified -m BYTWO_x -r SSE, but SSE2 is not supported."; break; case GF_E_LOGBADW: s = "With Log Tables, w must be <= 27."; break; case GF_E_LOG___J: s = "Cannot use Log tables with -r ALTMAP|SSE|NOSSE."; break; case GF_E_LOGPOLY: s = "Cannot use Log tables because the polynomial is not primitive."; break; case GF_E_ZERBADW: s = "With -m LOG_ZERO, w must be 8 or 16."; break; case GF_E_ZEXBADW: s = "With -m LOG_ZERO_EXT, w must be 8."; break; case GF_E_GR_ARGX: s = "With -m GROUP, arg1 and arg2 must be >= 0."; break; case GF_E_GR_W_48: s = "With -m GROUP, w cannot be 4 or 8."; break; case GF_E_GR_W_16: s = "With -m GROUP, w == 16, arg1 and arg2 must be 4."; break; case GF_E_GR_128A: s = "With -m GROUP, w == 128, arg1 must be 4, and arg2 in { 4,8,16 }."; break; case GF_E_GR_A_27: s = "With -m GROUP, arg1 and arg2 must be <= 27."; break; case GF_E_GR_AR_W: s = "With -m GROUP, arg1 and arg2 must be <= w."; break; case GF_E_GR____J: s = "Cannot use GROUP with -r ALTMAP|SSE|NOSSE."; break; case GF_E_TABLE_W: s = "With -m TABLE, w must be < 15, or == 16."; break; case GF_E_TAB_SSE: s = "With -m TABLE, SSE|NOSSE only applies to w=4."; break; case GF_E_TABSSE3: s = "With -m TABLE, -r SSE, you need SSSE3 supported."; break; case GF_E_TAB_ALT: s = "With -m TABLE, you cannot use ALTMAP."; break; case GF_E_SP128AR: s = "With -m SPLIT, w=128, bad arg1/arg2."; break; case GF_E_SP128AL: s = "With -m SPLIT, w=128, -r SSE requires -r ALTMAP."; break; case GF_E_SP128AS: s = "With -m SPLIT, w=128, ALTMAP needs SSSE3 supported."; break; case GF_E_SP128_A: s = "With -m SPLIT, w=128, -r SSE|NOSSE only with arg1/arg2 = 4/128."; break; case GF_E_SP128_S: s = "With -m SPLIT, w=128, -r ALTMAP only with arg1/arg2 = 4/128."; break; case GF_E_SPLIT_W: s = "With -m SPLIT, w must be in {8, 16, 32, 64, 128}."; break; case GF_E_SP_16AR: s = "With -m SPLIT, w=16, Bad arg1/arg2."; break; case GF_E_SP_16_A: s = "With -m SPLIT, w=16, -r ALTMAP only with arg1/arg2 = 4/16."; break; case GF_E_SP_16_S: s = "With -m SPLIT, w=16, -r SSE|NOSSE only with arg1/arg2 = 4/16."; break; case GF_E_SP_32AR: s = "With -m SPLIT, w=32, Bad arg1/arg2."; break; case GF_E_SP_32AS: s = "With -m SPLIT, w=32, -r ALTMAP needs SSSE3 supported."; break; case GF_E_SP_32_A: s = "With -m SPLIT, w=32, -r ALTMAP only with arg1/arg2 = 4/32."; break; case GF_E_SP_32_S: s = "With -m SPLIT, w=32, -r SSE|NOSSE only with arg1/arg2 = 4/32."; break; case GF_E_SP_64AR: s = "With -m SPLIT, w=64, Bad arg1/arg2."; break; case GF_E_SP_64AS: s = "With -m SPLIT, w=64, -r ALTMAP needs SSSE3 supported."; break; case GF_E_SP_64_A: s = "With -m SPLIT, w=64, -r ALTMAP only with arg1/arg2 = 4/64."; break; case GF_E_SP_64_S: s = "With -m SPLIT, w=64, -r SSE|NOSSE only with arg1/arg2 = 4/64."; break; case GF_E_SP_8_AR: s = "With -m SPLIT, w=8, Bad arg1/arg2."; break; case GF_E_SP_8__A: s = "With -m SPLIT, w=8, Can't have -r ALTMAP."; break; case GF_E_SP_SSE3: s = "With -m SPLIT, Need SSSE3 support for SSE."; break; case GF_E_COMP_A2: s = "With -m COMPOSITE, arg1 must equal 2."; break; case GF_E_COMP_SS: s = "With -m COMPOSITE, -r SSE and -r NOSSE do not apply."; break; case GF_E_COMP__W: s = "With -m COMPOSITE, w must be 8, 16, 32, 64 or 128."; break; case GF_E_UNKFLAG: s = "Unknown method flag - should be -m, -d, -r or -p."; break; case GF_E_UNKNOWN: s = "Unknown multiplication type."; break; case GF_E_UNK_REG: s = "Unknown region type."; break; case GF_E_UNK_DIV: s = "Unknown division type."; break; default: s = "Undefined error."; } fprintf(stderr, "%s\n", s); } uint64_t gf_composite_get_default_poly(gf_t *base) { gf_internal_t *h; int rv; h = (gf_internal_t *) base->scratch; if (h->w == 4) { if (h->mult_type == GF_MULT_COMPOSITE) return 0; if (h->prim_poly == 0x13) return 2; return 0; } if (h->w == 8) { if (h->mult_type == GF_MULT_COMPOSITE) return 0; if (h->prim_poly == 0x11d) return 3; return 0; } if (h->w == 16) { if (h->mult_type == GF_MULT_COMPOSITE) { rv = gf_composite_get_default_poly(h->base_gf); if (rv != h->prim_poly) return 0; if (rv == 3) return 0x105; return 0; } else { if (h->prim_poly == 0x1100b) return 2; if (h->prim_poly == 0x1002d) return 7; return 0; } } if (h->w == 32) { if (h->mult_type == GF_MULT_COMPOSITE) { rv = gf_composite_get_default_poly(h->base_gf); if (rv != h->prim_poly) return 0; if (rv == 2) return 0x10005; if (rv == 7) return 0x10008; if (rv == 0x105) return 0x10002; return 0; } else { if (h->prim_poly == 0x400007) return 2; if (h->prim_poly == 0xc5) return 3; return 0; } } if (h->w == 64) { if (h->mult_type == GF_MULT_COMPOSITE) { rv = gf_composite_get_default_poly(h->base_gf); if (rv != h->prim_poly) return 0; if (rv == 3) return 0x100000009ULL; if (rv == 2) return 0x100000004ULL; if (rv == 0x10005) return 0x100000003ULL; if (rv == 0x10002) return 0x100000005ULL; if (rv == 0x10008) return 0x100000006ULL; /* JSP: (0x0x100000003 works too, but I want to differentiate cases). */ return 0; } else { if (h->prim_poly == 0x1bULL) return 2; return 0; } } return 0; } int gf_error_check(int w, int mult_type, int region_type, int divide_type, int arg1, int arg2, uint64_t poly, gf_t *base) { int sse3 = 0; int sse2 = 0; int pclmul = 0; int rdouble, rquad, rlazy, rsse, rnosse, raltmap, rcauchy, tmp; gf_internal_t *sub; rdouble = (region_type & GF_REGION_DOUBLE_TABLE); rquad = (region_type & GF_REGION_QUAD_TABLE); rlazy = (region_type & GF_REGION_LAZY); rsse = (region_type & GF_REGION_SSE); rnosse = (region_type & GF_REGION_NOSSE); raltmap = (region_type & GF_REGION_ALTMAP); rcauchy = (region_type & GF_REGION_CAUCHY); if (divide_type != GF_DIVIDE_DEFAULT && divide_type != GF_DIVIDE_MATRIX && divide_type != GF_DIVIDE_EUCLID) { _gf_errno = GF_E_UNK_DIV; return 0; } tmp = ( GF_REGION_DOUBLE_TABLE | GF_REGION_QUAD_TABLE | GF_REGION_LAZY | GF_REGION_SSE | GF_REGION_NOSSE | GF_REGION_ALTMAP | GF_REGION_CAUCHY ); if (region_type & (~tmp)) { _gf_errno = GF_E_UNK_REG; return 0; } #ifdef INTEL_SSE2 sse2 = 1; #endif #ifdef INTEL_SSSE3 sse3 = 1; #endif #ifdef INTEL_SSE4_PCLMUL pclmul = 1; #endif if (w < 1 || (w > 32 && w != 64 && w != 128)) { _gf_errno = GF_E_BAD___W; return 0; } if (mult_type != GF_MULT_COMPOSITE && w < 64) { if ((poly >> (w+1)) != 0) { _gf_errno = GF_E_BADPOLY; return 0; } } if (mult_type == GF_MULT_DEFAULT) { if (divide_type != GF_DIVIDE_DEFAULT) { _gf_errno = GF_E_MDEFDIV; return 0; } if (region_type != GF_REGION_DEFAULT) { _gf_errno = GF_E_MDEFREG; return 0; } if (arg1 != 0 || arg2 != 0) { _gf_errno = GF_E_MDEFARG; return 0; } return 1; } if (rsse && rnosse) { _gf_errno = GF_E_SSE__NO; return 0; } if (rcauchy && w > 32) { _gf_errno = GF_E_CAUGT32; return 0; } if (rcauchy && region_type != GF_REGION_CAUCHY) { _gf_errno = GF_E_CAUCHYB; return 0; } if (rcauchy && mult_type == GF_MULT_COMPOSITE) { _gf_errno = GF_E_CAUCOMP; return 0; } if (arg1 != 0 && mult_type != GF_MULT_COMPOSITE && mult_type != GF_MULT_SPLIT_TABLE && mult_type != GF_MULT_GROUP) { _gf_errno = GF_E_ARG1SET; return 0; } if (arg2 != 0 && mult_type != GF_MULT_SPLIT_TABLE && mult_type != GF_MULT_GROUP) { _gf_errno = GF_E_ARG2SET; return 0; } if (divide_type == GF_DIVIDE_MATRIX && w > 32) { _gf_errno = GF_E_MATRIXW; return 0; } if (rdouble) { if (rquad) { _gf_errno = GF_E_DOUQUAD; return 0; } if (mult_type != GF_MULT_TABLE) { _gf_errno = GF_E_DOUBLET; return 0; } if (w != 4 && w != 8) { _gf_errno = GF_E_DOUBLEW; return 0; } if (rsse || rnosse || raltmap) { _gf_errno = GF_E_DOUBLEJ; return 0; } if (rlazy && w == 4) { _gf_errno = GF_E_DOUBLEL; return 0; } return 1; } if (rquad) { if (mult_type != GF_MULT_TABLE) { _gf_errno = GF_E_QUAD__T; return 0; } if (w != 4) { _gf_errno = GF_E_QUAD__W; return 0; } if (rsse || rnosse || raltmap) { _gf_errno = GF_E_QUAD__J; return 0; } return 1; } if (rlazy) { _gf_errno = GF_E_LAZY__X; return 0; } if (mult_type == GF_MULT_SHIFT) { if (raltmap) { _gf_errno = GF_E_ALTSHIF; return 0; } if (rsse || rnosse) { _gf_errno = GF_E_SSESHIF; return 0; } return 1; } if (mult_type == GF_MULT_CARRY_FREE) { if (w != 4 && w != 8 && w != 16 && w != 32 && w != 64 && w != 128) { _gf_errno = GF_E_CFM___W; return 0; } if (w == 4 && (poly & 0xc)) { _gf_errno = GF_E_CFM4POL; return 0; } if (w == 8 && (poly & 0x80)) { _gf_errno = GF_E_CFM8POL; return 0; } if (w == 16 && (poly & 0xe000)) { _gf_errno = GF_E_CF16POL; return 0; } if (w == 32 && (poly & 0xfe000000)) { _gf_errno = GF_E_CF32POL; return 0; } if (w == 64 && (poly & 0xfffe000000000000ULL)) { _gf_errno = GF_E_CF64POL; return 0; } if (raltmap) { _gf_errno = GF_E_ALT_CFM; return 0; } if (rsse || rnosse) { _gf_errno = GF_E_SSE_CFM; return 0; } if (!pclmul) { _gf_errno = GF_E_PCLMULX; return 0; } return 1; } if (mult_type == GF_MULT_BYTWO_p || mult_type == GF_MULT_BYTWO_b) { if (raltmap) { _gf_errno = GF_E_ALT_BY2; return 0; } if (rsse && !sse2) { _gf_errno = GF_E_BY2_SSE; return 0; } return 1; } if (mult_type == GF_MULT_LOG_TABLE || mult_type == GF_MULT_LOG_ZERO || mult_type == GF_MULT_LOG_ZERO_EXT ) { if (w > 27) { _gf_errno = GF_E_LOGBADW; return 0; } if (raltmap || rsse || rnosse) { _gf_errno = GF_E_LOG___J; return 0; } if (mult_type == GF_MULT_LOG_TABLE) return 1; if (w != 8 && w != 16) { _gf_errno = GF_E_ZERBADW; return 0; } if (mult_type == GF_MULT_LOG_ZERO) return 1; if (w != 8) { _gf_errno = GF_E_ZEXBADW; return 0; } return 1; } if (mult_type == GF_MULT_GROUP) { if (arg1 <= 0 || arg2 <= 0) { _gf_errno = GF_E_GR_ARGX; return 0; } if (w == 4 || w == 8) { _gf_errno = GF_E_GR_W_48; return 0; } if (w == 16 && (arg1 != 4 || arg2 != 4)) { _gf_errno = GF_E_GR_W_16; return 0; } if (w == 128 && (arg1 != 4 || (arg2 != 4 && arg2 != 8 && arg2 != 16))) { _gf_errno = GF_E_GR_128A; return 0; } if (arg1 > 27 || arg2 > 27) { _gf_errno = GF_E_GR_A_27; return 0; } if (arg1 > w || arg2 > w) { _gf_errno = GF_E_GR_AR_W; return 0; } if (raltmap || rsse || rnosse) { _gf_errno = GF_E_GR____J; return 0; } return 1; } if (mult_type == GF_MULT_TABLE) { if (w != 16 && w >= 15) { _gf_errno = GF_E_TABLE_W; return 0; } if (w != 4 && (rsse || rnosse)) { _gf_errno = GF_E_TAB_SSE; return 0; } if (rsse && !sse3) { _gf_errno = GF_E_TABSSE3; return 0; } if (raltmap) { _gf_errno = GF_E_TAB_ALT; return 0; } return 1; } if (mult_type == GF_MULT_SPLIT_TABLE) { if (arg1 > arg2) { tmp = arg1; arg1 = arg2; arg2 = tmp; } if (w == 8) { if (arg1 != 4 || arg2 != 8) { _gf_errno = GF_E_SP_8_AR; return 0; } if (rsse && !sse3) { _gf_errno = GF_E_SP_SSE3; return 0; } if (raltmap) { _gf_errno = GF_E_SP_8__A; return 0; } } else if (w == 16) { if (arg1 == 4 && arg2 == 16) { if (rsse && !sse3) { _gf_errno = GF_E_SP_SSE3; return 0; } } else if (arg1 == 8 && (arg2 == 16 || arg2 == 8)) { if (rsse || rnosse) { _gf_errno = GF_E_SP_16_S; return 0; } if (raltmap) { _gf_errno = GF_E_SP_16_A; return 0; } } else { _gf_errno = GF_E_SP_16AR; return 0; } } else if (w == 32) { if ((arg1 == 8 && arg2 == 8) || (arg1 == 8 && arg2 == 32) || (arg1 == 16 && arg2 == 32)) { if (rsse || rnosse) { _gf_errno = GF_E_SP_32_S; return 0; } if (raltmap) { _gf_errno = GF_E_SP_32_A; return 0; } } else if ((arg1 == 4 && arg2 == 32) || (arg1 == 4 && arg2 == 32)) { if (rsse && !sse3) { _gf_errno = GF_E_SP_SSE3; return 0; } if (raltmap && arg1 != 4) { _gf_errno = GF_E_SP_32_A; return 0; } if (raltmap && !sse3) { _gf_errno = GF_E_SP_32AS; return 0; } if (raltmap && rnosse) { _gf_errno = GF_E_SP_32AS; return 0; } } else { _gf_errno = GF_E_SP_32AR; return 0; } } else if (w == 64) { if ((arg1 == 8 && arg2 == 8) || (arg1 == 8 && arg2 == 64) || (arg1 == 16 && arg2 == 64)) { if (rsse || rnosse) { _gf_errno = GF_E_SP_64_S; return 0; } if (raltmap) { _gf_errno = GF_E_SP_64_A; return 0; } } else if (arg1 == 4 && arg2 == 64) { if (rsse && !sse3) { _gf_errno = GF_E_SP_SSE3; return 0; } if (raltmap && !sse3) { _gf_errno = GF_E_SP_64AS; return 0; } if (raltmap && rnosse) { _gf_errno = GF_E_SP_64AS; return 0; } } else { _gf_errno = GF_E_SP_64AR; return 0; } } else if (w == 128) { if (arg1 == 8 && arg2 == 128) { if (rsse || rnosse) { _gf_errno = GF_E_SP128_S; return 0; } if (raltmap) { _gf_errno = GF_E_SP128_A; return 0; } } else if (arg1 == 4 && arg2 == 128) { if (rsse && !sse3) { _gf_errno = GF_E_SP_SSE3; return 0; } if (raltmap && !sse3) { _gf_errno = GF_E_SP128AS; return 0; } if (raltmap && rnosse) { _gf_errno = GF_E_SP128AS; return 0; } } else { _gf_errno = GF_E_SP128AR; return 0; } } else { _gf_errno = GF_E_SPLIT_W; return 0; } return 1; } if (mult_type == GF_MULT_COMPOSITE) { if (w != 8 && w != 16 && w != 32 && w != 64 && w != 128) { _gf_errno = GF_E_COMP__W; return 0; } if ((poly >> (w/2)) != 0) { _gf_errno = GF_E_COMP_PP; return 0; } if (divide_type != GF_DIVIDE_DEFAULT) { _gf_errno = GF_E_DIVCOMP; return 0; } if (arg1 != 2) { _gf_errno = GF_E_COMP_A2; return 0; } if (rsse || rnosse) { _gf_errno = GF_E_COMP_SS; return 0; } if (base != NULL) { sub = (gf_internal_t *) base->scratch; if (sub->w != w/2) { _gf_errno = GF_E_BASE__W; return 0; } if (poly == 0) { if (gf_composite_get_default_poly(base) == 0) { _gf_errno = GF_E_COMPXPP; return 0; } } } return 1; } _gf_errno = GF_E_UNKNOWN; return 0; } int gf_scratch_size(int w, int mult_type, int region_type, int divide_type, int arg1, int arg2) { if (gf_error_check(w, mult_type, region_type, divide_type, arg1, arg2, 0, NULL) == 0) return 0; switch(w) { case 4: return gf_w4_scratch_size(mult_type, region_type, divide_type, arg1, arg2); case 8: return gf_w8_scratch_size(mult_type, region_type, divide_type, arg1, arg2); case 16: return gf_w16_scratch_size(mult_type, region_type, divide_type, arg1, arg2); case 32: return gf_w32_scratch_size(mult_type, region_type, divide_type, arg1, arg2); case 64: return gf_w64_scratch_size(mult_type, region_type, divide_type, arg1, arg2); case 128: return gf_w128_scratch_size(mult_type, region_type, divide_type, arg1, arg2); default: return gf_wgen_scratch_size(w, mult_type, region_type, divide_type, arg1, arg2); } } extern int gf_size(gf_t *gf) { gf_internal_t *h; int s; s = sizeof(gf_t); h = (gf_internal_t *) gf->scratch; s += gf_scratch_size(h->w, h->mult_type, h->region_type, h->divide_type, h->arg1, h->arg2); if (h->mult_type == GF_MULT_COMPOSITE) s += gf_size(h->base_gf); return s; } int gf_init_easy(gf_t *gf, int w) { return gf_init_hard(gf, w, GF_MULT_DEFAULT, GF_REGION_DEFAULT, GF_DIVIDE_DEFAULT, 0, 0, 0, NULL, NULL); } /* Allen: What's going on here is this function is putting info into the scratch mem of gf, and then calling the relevant REAL init func for the word size. Probably done this way to consolidate those aspects of initialization that don't rely on word size, and then take care of word-size-specific stuff. */ int gf_init_hard(gf_t *gf, int w, int mult_type, int region_type, int divide_type, uint64_t prim_poly, int arg1, int arg2, gf_t *base_gf, void *scratch_memory) { int sz; gf_internal_t *h; if (gf_error_check(w, mult_type, region_type, divide_type, arg1, arg2, prim_poly, base_gf) == 0) return 0; sz = gf_scratch_size(w, mult_type, region_type, divide_type, arg1, arg2); if (sz <= 0) return 0; /* This shouldn't happen, as all errors should get caught in gf_error_check() */ if (scratch_memory == NULL) { h = (gf_internal_t *) malloc(sz); h->free_me = 1; } else { h = scratch_memory; h->free_me = 0; } gf->scratch = (void *) h; h->mult_type = mult_type; h->region_type = region_type; h->divide_type = divide_type; h->w = w; h->prim_poly = prim_poly; h->arg1 = arg1; h->arg2 = arg2; h->base_gf = base_gf; h->private = (void *) gf->scratch; h->private = (char*)h->private + (sizeof(gf_internal_t)); gf->extract_word.w32 = NULL; switch(w) { case 4: return gf_w4_init(gf); case 8: return gf_w8_init(gf); case 16: return gf_w16_init(gf); case 32: return gf_w32_init(gf); case 64: return gf_w64_init(gf); case 128: return gf_w128_init(gf); default: return gf_wgen_init(gf); } } int gf_free(gf_t *gf, int recursive) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (recursive && h->base_gf != NULL) { gf_free(h->base_gf, 1); free(h->base_gf); } if (h->free_me) free(h); return 0; /* Making compiler happy */ } void gf_alignment_error(char *s, int a) { fprintf(stderr, "Alignment error in %s:\n", s); fprintf(stderr, " The source and destination buffers must be aligned to each other,\n"); fprintf(stderr, " and they must be aligned to a %d-byte address.\n", a); exit(1); } static void gf_invert_binary_matrix(uint32_t *mat, uint32_t *inv, int rows) { int cols, i, j; uint32_t tmp; cols = rows; for (i = 0; i < rows; i++) inv[i] = (1 << i); /* First -- convert into upper triangular */ for (i = 0; i < cols; i++) { /* Swap rows if we ave a zero i,i element. If we can't swap, then the matrix was not invertible */ if ((mat[i] & (1 << i)) == 0) { for (j = i+1; j < rows && (mat[j] & (1 << i)) == 0; j++) ; if (j == rows) { fprintf(stderr, "galois_invert_matrix: Matrix not invertible!!\n"); exit(1); } tmp = mat[i]; mat[i] = mat[j]; mat[j] = tmp; tmp = inv[i]; inv[i] = inv[j]; inv[j] = tmp; } /* Now for each j>i, add A_ji*Ai to Aj */ for (j = i+1; j != rows; j++) { if ((mat[j] & (1 << i)) != 0) { mat[j] ^= mat[i]; inv[j] ^= inv[i]; } } } /* Now the matrix is upper triangular. Start at the top and multiply down */ for (i = rows-1; i >= 0; i--) { for (j = 0; j < i; j++) { if (mat[j] & (1 << i)) { /* mat[j] ^= mat[i]; */ inv[j] ^= inv[i]; } } } } uint32_t gf_bitmatrix_inverse(uint32_t y, int w, uint32_t pp) { uint32_t mat[32], inv[32], mask; int i; mask = (w == 32) ? 0xffffffff : (1 << w) - 1; for (i = 0; i < w; i++) { mat[i] = y; if (y & (1 << (w-1))) { y = y << 1; y = ((y ^ pp) & mask); } else { y = y << 1; } } gf_invert_binary_matrix(mat, inv, w); return inv[0]; } void gf_two_byte_region_table_multiply(gf_region_data *rd, uint16_t *base) { uint64_t a, prod; int xor; uint64_t *s64, *d64, *top; s64 = rd->s_start; d64 = rd->d_start; top = rd->d_top; xor = rd->xor; if (xor) { while (d64 != top) { a = *s64; prod = base[a >> 48]; a <<= 16; prod <<= 16; prod ^= base[a >> 48]; a <<= 16; prod <<= 16; prod ^= base[a >> 48]; a <<= 16; prod <<= 16; prod ^= base[a >> 48]; prod ^= *d64; *d64 = prod; s64++; d64++; } } else { while (d64 != top) { a = *s64; prod = base[a >> 48]; a <<= 16; prod <<= 16; prod ^= base[a >> 48]; a <<= 16; prod <<= 16; prod ^= base[a >> 48]; a <<= 16; prod <<= 16; prod ^= base[a >> 48]; *d64 = prod; s64++; d64++; } } } static void gf_slow_multiply_region(gf_region_data *rd, void *src, void *dest, void *s_top) { uint8_t *s8, *d8; uint16_t *s16, *d16; uint32_t *s32, *d32; uint64_t *s64, *d64; gf_internal_t *h; int wb; uint32_t p, a; h = rd->gf->scratch; wb = (h->w)/8; if (wb == 0) wb = 1; while (src < s_top) { switch (h->w) { case 8: s8 = (uint8_t *) src; d8 = (uint8_t *) dest; *d8 = (rd->xor) ? (*d8 ^ rd->gf->multiply.w32(rd->gf, rd->val, *s8)) : rd->gf->multiply.w32(rd->gf, rd->val, *s8); break; case 4: s8 = (uint8_t *) src; d8 = (uint8_t *) dest; a = *s8; p = rd->gf->multiply.w32(rd->gf, rd->val, a&0xf); p |= (rd->gf->multiply.w32(rd->gf, rd->val, a >> 4) << 4); if (rd->xor) p ^= *d8; *d8 = p; break; case 16: s16 = (uint16_t *) src; d16 = (uint16_t *) dest; *d16 = (rd->xor) ? (*d16 ^ rd->gf->multiply.w32(rd->gf, rd->val, *s16)) : rd->gf->multiply.w32(rd->gf, rd->val, *s16); break; case 32: s32 = (uint32_t *) src; d32 = (uint32_t *) dest; *d32 = (rd->xor) ? (*d32 ^ rd->gf->multiply.w32(rd->gf, rd->val, *s32)) : rd->gf->multiply.w32(rd->gf, rd->val, *s32); break; case 64: s64 = (uint64_t *) src; d64 = (uint64_t *) dest; *d64 = (rd->xor) ? (*d64 ^ rd->gf->multiply.w64(rd->gf, rd->val, *s64)) : rd->gf->multiply.w64(rd->gf, rd->val, *s64); break; default: fprintf(stderr, "Error: gf_slow_multiply_region: w=%d not implemented.\n", h->w); exit(1); } src = (char*)src + wb; dest = (char*)dest + wb; } } /* JSP - The purpose of this procedure is to error check alignment, and to set up the region operation so that it can best leverage large words. It stores its information in rd. Assuming you're not doing Cauchy coding, (see below for that), then w will be 4, 8, 16, 32 or 64. It can't be 128 (probably should change that). src and dest must then be aligned on ceil(w/8)-byte boundaries. Moreover, bytes must be a multiple of ceil(w/8). If the variable align is equal to ceil(w/8), then we will set s_start = src, d_start = dest, s_top to (src+bytes) and d_top to (dest+bytes). And we return -- the implementation will go ahead and do the multiplication on individual words (e.g. using discrete logs). If align is greater than ceil(w/8), then the implementation needs to work on groups of "align" bytes. For example, suppose you are implementing BYTWO, without SSE. Then you will be doing the region multiplication in units of 8 bytes, so align = 8. Or, suppose you are doing a Quad table in GF(2^4). You will be doing the region multiplication in units of 2 bytes, so align = 2. Or, suppose you are doing split multiplication with SSE operations in GF(2^8). Then align = 16. Worse yet, suppose you are doing split multiplication with SSE operations in GF(2^16), with or without ALTMAP. Then, you will be doing the multiplication on 256 bits at a time. So align = 32. When align does not equal ceil(w/8), we split the region multiplication into three parts. We are going to make s_start be the first address greater than or equal to src that is a multiple of align. s_top is going to be the largest address >= src+bytes such that (s_top - s_start) is a multiple of align. We do the same with d_start and d_top. When we say that "src and dest must be aligned with respect to each other, we mean that s_start-src must equal d_start-dest. Now, the region multiplication is done in three parts -- the part between src and s_start must be done using single words. Similarly, the part between s_top and src+bytes must also be done using single words. The part between s_start and s_top will be done in chunks of "align" bytes. One final thing -- if align > 16, then s_start and d_start will be aligned on a 16 byte boundary. Perhaps we should have two variables: align and chunksize. Then we'd have s_start & d_start aligned to "align", and have s_top-s_start be a multiple of chunksize. That may be less confusing, but it would be a big change. Finally, if align = -1, then we are doing Cauchy multiplication, using only XOR's. In this case, we're not going to care about alignment because we are just doing XOR's. Instead, the only thing we care about is that bytes must be a multiple of w. This is not to say that alignment doesn't matter in performance with XOR's. See that discussion in gf_multby_one(). After you call gf_set_region_data(), the procedure gf_do_initial_region_alignment() calls gf->multiply.w32() on everything between src and s_start. The procedure gf_do_final_region_alignment() calls gf->multiply.w32() on everything between s_top and src+bytes. */ void gf_set_region_data(gf_region_data *rd, gf_t *gf, void *src, void *dest, int bytes, uint64_t val, int xor, int align) { gf_internal_t *h = NULL; int wb; uint32_t a; unsigned long uls, uld; if (gf == NULL) { /* JSP - Can be NULL if you're just doing XOR's */ wb = 1; } else { h = gf->scratch; wb = (h->w)/8; if (wb == 0) wb = 1; } rd->gf = gf; rd->src = src; rd->dest = dest; rd->bytes = bytes; rd->val = val; rd->xor = xor; rd->align = align; uls = (unsigned long) src; uld = (unsigned long) dest; a = (align <= 16) ? align : 16; if (align == -1) { /* JSP: This is cauchy. Error check bytes, then set up the pointers so that there are no alignment regions. */ if (h != NULL && bytes % h->w != 0) { fprintf(stderr, "Error in region multiply operation.\n"); fprintf(stderr, "The size must be a multiple of %d bytes.\n", h->w); exit(1); } rd->s_start = src; rd->d_start = dest; rd->s_top = (char*)src + bytes; rd->d_top = (char*)src + bytes; return; } if (uls % a != uld % a) { fprintf(stderr, "Error in region multiply operation.\n"); fprintf(stderr, "The source & destination pointers must be aligned with respect\n"); fprintf(stderr, "to each other along a %d byte boundary.\n", a); fprintf(stderr, "Src = 0x%lx. Dest = 0x%lx\n", (unsigned long) src, (unsigned long) dest); exit(1); } if (uls % wb != 0) { fprintf(stderr, "Error in region multiply operation.\n"); fprintf(stderr, "The pointers must be aligned along a %d byte boundary.\n", wb); fprintf(stderr, "Src = 0x%lx. Dest = 0x%lx\n", (unsigned long) src, (unsigned long) dest); exit(1); } if (bytes % wb != 0) { fprintf(stderr, "Error in region multiply operation.\n"); fprintf(stderr, "The size must be a multiple of %d bytes.\n", wb); exit(1); } uls %= a; if (uls != 0) uls = (a-uls); rd->s_start = (char*)rd->src + uls; rd->d_start = (char*)rd->dest + uls; bytes -= uls; bytes -= (bytes % align); rd->s_top = (char*)rd->s_start + bytes; rd->d_top = (char*)rd->d_start + bytes; } void gf_do_initial_region_alignment(gf_region_data *rd) { gf_slow_multiply_region(rd, rd->src, rd->dest, rd->s_start); } void gf_do_final_region_alignment(gf_region_data *rd) { gf_slow_multiply_region(rd, rd->s_top, rd->d_top, (char*)rd->src+rd->bytes); } void gf_multby_zero(void *dest, int bytes, int xor) { if (xor) return; bzero(dest, bytes); return; } /* JSP - gf_multby_one tries to do this in the most efficient way possible. If xor = 0, then simply call memcpy() since that should be optimized by the system. Otherwise, try to do the xor in the following order: If src and dest are aligned with respect to each other on 16-byte boundaries and you have SSE instructions, then use aligned SSE instructions. If they aren't but you still have SSE instructions, use unaligned SSE instructions. If there are no SSE instructions, but they are aligned with respect to each other on 8-byte boundaries, then do them with uint64_t's. Otherwise, call gf_unaligned_xor(), which does the following: align a destination pointer along an 8-byte boundary, and then memcpy 32 bytes at a time from the src pointer to an array of doubles. I'm not sure if that's the best -- probably needs testing, but this seems like it could be a black hole. */ static void gf_unaligned_xor(void *src, void *dest, int bytes); void gf_multby_one(void *src, void *dest, int bytes, int xor) { #ifdef INTEL_SSE2 __m128i ms, md; #endif unsigned long uls, uld; uint8_t *s8, *d8; uint64_t *s64, *d64, *dtop64; gf_region_data rd; if (!xor) { memcpy(dest, src, bytes); return; } uls = (unsigned long) src; uld = (unsigned long) dest; #ifdef INTEL_SSE2 int abytes; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; if (uls % 16 == uld % 16) { gf_set_region_data(&rd, NULL, src, dest, bytes, 1, xor, 16); while (s8 != rd.s_start) { *d8 ^= *s8; d8++; s8++; } while (s8 < (uint8_t *) rd.s_top) { ms = _mm_load_si128 ((__m128i *)(s8)); md = _mm_load_si128 ((__m128i *)(d8)); md = _mm_xor_si128(md, ms); _mm_store_si128((__m128i *)(d8), md); s8 += 16; d8 += 16; } while (s8 != (uint8_t *) src + bytes) { *d8 ^= *s8; d8++; s8++; } return; } abytes = (bytes & 0xfffffff0); while (d8 < (uint8_t *) dest + abytes) { ms = _mm_loadu_si128 ((__m128i *)(s8)); md = _mm_loadu_si128 ((__m128i *)(d8)); md = _mm_xor_si128(md, ms); _mm_storeu_si128((__m128i *)(d8), md); s8 += 16; d8 += 16; } while (d8 != (uint8_t *) dest+bytes) { *d8 ^= *s8; d8++; s8++; } return; #endif if (uls % 8 != uld % 8) { gf_unaligned_xor(src, dest, bytes); return; } gf_set_region_data(&rd, NULL, src, dest, bytes, 1, xor, 8); s8 = (uint8_t *) src; d8 = (uint8_t *) dest; while (d8 != rd.d_start) { *d8 ^= *s8; d8++; s8++; } dtop64 = (uint64_t *) rd.d_top; d64 = (uint64_t *) rd.d_start; s64 = (uint64_t *) rd.s_start; while (d64 < dtop64) { *d64 ^= *s64; d64++; s64++; } s8 = (uint8_t *) rd.s_top; d8 = (uint8_t *) rd.d_top; while (d8 != (uint8_t *) dest+bytes) { *d8 ^= *s8; d8++; s8++; } return; } #define UNALIGNED_BUFSIZE (8) static void gf_unaligned_xor(void *src, void *dest, int bytes) { uint64_t scopy[UNALIGNED_BUFSIZE], *d64; int i; gf_region_data rd; uint8_t *s8, *d8; /* JSP - call gf_set_region_data(), but use dest in both places. This is because I only want to set up dest. If I used src, gf_set_region_data() would fail because src and dest are not aligned to each other wrt 8-byte pointers. I know this will actually align d_start to 16 bytes. If I change gf_set_region_data() to split alignment & chunksize, then I could do this correctly. */ gf_set_region_data(&rd, NULL, dest, dest, bytes, 1, 1, 8*UNALIGNED_BUFSIZE); s8 = (uint8_t *) src; d8 = (uint8_t *) dest; while (d8 < (uint8_t *) rd.d_start) { *d8 ^= *s8; d8++; s8++; } d64 = (uint64_t *) d8; while (d64 < (uint64_t *) rd.d_top) { memcpy(scopy, s8, 8*UNALIGNED_BUFSIZE); s8 += 8*UNALIGNED_BUFSIZE; for (i = 0; i < UNALIGNED_BUFSIZE; i++) { *d64 ^= scopy[i]; d64++; } } d8 = (uint8_t *) d64; while (d8 < (uint8_t *) ((char*)dest+bytes)) { *d8 ^= *s8; d8++; s8++; } } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_wgen.c0000664000175100017510000005401012623076752026432 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_wgen.c * * Routines for Galois fields for general w < 32. For specific w, like 4, 8, 16, 32, 64 and 128, see the other files. */ #include "gf_int.h" #include #include struct gf_wgen_table_w8_data { uint8_t *mult; uint8_t *div; uint8_t base; }; struct gf_wgen_table_w16_data { uint16_t *mult; uint16_t *div; uint16_t base; }; struct gf_wgen_log_w8_data { uint8_t *log; uint8_t *anti; uint8_t *danti; uint8_t base; }; struct gf_wgen_log_w16_data { uint16_t *log; uint16_t *anti; uint16_t *danti; uint16_t base; }; struct gf_wgen_log_w32_data { uint32_t *log; uint32_t *anti; uint32_t *danti; uint32_t base; }; struct gf_wgen_group_data { uint32_t *reduce; uint32_t *shift; uint32_t mask; uint64_t rmask; int tshift; uint32_t memory; }; static inline gf_val_32_t gf_wgen_inverse_from_divide (gf_t *gf, gf_val_32_t a) { return gf->divide.w32(gf, 1, a); } static inline gf_val_32_t gf_wgen_divide_from_inverse (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { b = gf->inverse.w32(gf, b); return gf->multiply.w32(gf, a, b); } static inline gf_val_32_t gf_wgen_euclid (gf_t *gf, gf_val_32_t b) { gf_val_32_t e_i, e_im1, e_ip1; gf_val_32_t d_i, d_im1, d_ip1; gf_val_32_t y_i, y_im1, y_ip1; gf_val_32_t c_i; if (b == 0) return -1; e_im1 = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i = b; d_im1 = ((gf_internal_t *) (gf->scratch))->w; for (d_i = d_im1; ((1 << d_i) & e_i) == 0; d_i--) ; y_i = 1; y_im1 = 0; while (e_i != 1) { e_ip1 = e_im1; d_ip1 = d_im1; c_i = 0; while (d_ip1 >= d_i) { c_i ^= (1 << (d_ip1 - d_i)); e_ip1 ^= (e_i << (d_ip1 - d_i)); if (e_ip1 == 0) return 0; while ((e_ip1 & (1 << d_ip1)) == 0) d_ip1--; } y_ip1 = y_im1 ^ gf->multiply.w32(gf, c_i, y_i); y_im1 = y_i; y_i = y_ip1; e_im1 = e_i; d_im1 = d_i; e_i = e_ip1; d_i = d_ip1; } return y_i; } gf_val_32_t gf_wgen_extract_word(gf_t *gf, void *start, int bytes, int index) { uint8_t *ptr; uint32_t rv; int rs; int byte, bit, i; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; rs = bytes / h->w; byte = index/8; bit = index%8; ptr = (uint8_t *) start; ptr += bytes; ptr -= rs; ptr += byte; rv = 0; for (i = 0; i < h->w; i++) { rv <<= 1; if ((*ptr) & (1 << bit)) rv |= 1; ptr -= rs; } return rv; } static inline gf_val_32_t gf_wgen_matrix (gf_t *gf, gf_val_32_t b) { return gf_bitmatrix_inverse(b, ((gf_internal_t *) (gf->scratch))->w, ((gf_internal_t *) (gf->scratch))->prim_poly); } static inline uint32_t gf_wgen_shift_multiply (gf_t *gf, uint32_t a32, uint32_t b32) { uint64_t product, i, pp, a, b, one; gf_internal_t *h; a = a32; b = b32; h = (gf_internal_t *) gf->scratch; one = 1; pp = h->prim_poly | (one << h->w); product = 0; for (i = 0; i < h->w; i++) { if (a & (one << i)) product ^= (b << i); } for (i = h->w*2-1; i >= h->w; i--) { if (product & (one << i)) product ^= (pp << (i-h->w)); } return product; } static int gf_wgen_shift_init(gf_t *gf) { gf->multiply.w32 = gf_wgen_shift_multiply; gf->inverse.w32 = gf_wgen_euclid; return 1; } static gf_val_32_t gf_wgen_bytwo_b_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, bmask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; bmask = (1 << (h->w-1)); while (1) { if (a & 1) prod ^= b; a >>= 1; if (a == 0) return prod; if (b & bmask) { b = ((b << 1) ^ pp); } else { b <<= 1; } } } static int gf_wgen_bytwo_b_init(gf_t *gf) { gf->multiply.w32 = gf_wgen_bytwo_b_multiply; gf->inverse.w32 = gf_wgen_euclid; return 1; } static inline gf_val_32_t gf_wgen_bytwo_p_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, pmask, amask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; pmask = (1 << ((h->w)-1)); /*Ben: Had an operator precedence warning here*/ amask = pmask; while (amask != 0) { if (prod & pmask) { prod = ((prod << 1) ^ pp); } else { prod <<= 1; } if (a & amask) prod ^= b; amask >>= 1; } return prod; } static int gf_wgen_bytwo_p_init(gf_t *gf) { gf->multiply.w32 = gf_wgen_bytwo_p_multiply; gf->inverse.w32 = gf_wgen_euclid; return 1; } static void gf_wgen_group_set_shift_tables(uint32_t *shift, uint32_t val, gf_internal_t *h) { int i; uint32_t j; int g_s; if (h->mult_type == GF_MULT_DEFAULT) { g_s = 2; } else { g_s = h->arg1; } shift[0] = 0; for (i = 1; i < (1 << g_s); i <<= 1) { for (j = 0; j < i; j++) shift[i|j] = shift[j]^val; if (val & (1 << (h->w-1))) { val <<= 1; val ^= h->prim_poly; } else { val <<= 1; } } } static inline gf_val_32_t gf_wgen_group_s_equals_r_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int leftover, rs; uint32_t p, l, ind, a32; int bits_left; int g_s; int w; struct gf_wgen_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; g_s = h->arg1; w = h->w; gd = (struct gf_wgen_group_data *) h->private; gf_wgen_group_set_shift_tables(gd->shift, b, h); leftover = w % g_s; if (leftover == 0) leftover = g_s; rs = w - leftover; a32 = a; ind = a32 >> rs; a32 <<= leftover; a32 &= gd->mask; p = gd->shift[ind]; bits_left = rs; rs = w - g_s; while (bits_left > 0) { bits_left -= g_s; ind = a32 >> rs; a32 <<= g_s; a32 &= gd->mask; l = p >> rs; p = (gd->shift[ind] ^ gd->reduce[l] ^ (p << g_s)) & gd->mask; } return p; } char *bits(uint32_t v) { char *rv; int i, j; rv = malloc(30); j = 0; for (i = 27; i >= 0; i--) { rv[j] = '0' + ((v & (1 << i)) ? 1 : 0); j++; } rv[j] = '\0'; return rv; } char *bits_56(uint64_t v) { char *rv; int i, j; uint64_t one; one = 1; rv = malloc(60); j = 0; for (i = 55; i >= 0; i--) { rv[j] = '0' + ((v & (one << i)) ? 1 : 0); j++; } rv[j] = '\0'; return rv; } static inline gf_val_32_t gf_wgen_group_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int i; int leftover; uint64_t p, l, r; uint32_t a32, ind; int g_s, g_r; struct gf_wgen_group_data *gd; int w; gf_internal_t *h = (gf_internal_t *) gf->scratch; if (h->mult_type == GF_MULT_DEFAULT) { g_s = 2; g_r = 8; } else { g_s = h->arg1; g_r = h->arg2; } w = h->w; gd = (struct gf_wgen_group_data *) h->private; gf_wgen_group_set_shift_tables(gd->shift, b, h); leftover = w % g_s; if (leftover == 0) leftover = g_s; a32 = a; ind = a32 >> (w - leftover); p = gd->shift[ind]; p <<= g_s; a32 <<= leftover; a32 &= gd->mask; i = (w - leftover); while (i > g_s) { ind = a32 >> (w-g_s); p ^= gd->shift[ind]; a32 <<= g_s; a32 &= gd->mask; p <<= g_s; i -= g_s; } ind = a32 >> (h->w-g_s); p ^= gd->shift[ind]; for (i = gd->tshift ; i >= 0; i -= g_r) { l = p & (gd->rmask << i); r = gd->reduce[l >> (i+w)]; r <<= (i); p ^= r; } return p & gd->mask; } static int gf_wgen_group_init(gf_t *gf) { uint32_t i, j, p, index; struct gf_wgen_group_data *gd; gf_internal_t *h = (gf_internal_t *) gf->scratch; int g_s, g_r; if (h->mult_type == GF_MULT_DEFAULT) { g_s = 2; g_r = 8; } else { g_s = h->arg1; g_r = h->arg2; } gd = (struct gf_wgen_group_data *) h->private; gd->shift = &(gd->memory); gd->reduce = gd->shift + (1 << g_s); gd->mask = (h->w != 31) ? ((1 << h->w)-1) : 0x7fffffff; gd->rmask = (1 << g_r) - 1; gd->rmask <<= h->w; gd->tshift = h->w % g_s; if (gd->tshift == 0) gd->tshift = g_s; gd->tshift = (h->w - gd->tshift); gd->tshift = ((gd->tshift-1)/g_r) * g_r; gd->reduce[0] = 0; for (i = 0; i < (1 << g_r); i++) { p = 0; index = 0; for (j = 0; j < g_r; j++) { if (i & (1 << j)) { p ^= (h->prim_poly << j); index ^= (h->prim_poly >> (h->w-j)); } } gd->reduce[index] = (p & gd->mask); } if (g_s == g_r) { gf->multiply.w32 = gf_wgen_group_s_equals_r_multiply; } else { gf->multiply.w32 = gf_wgen_group_multiply; } gf->divide.w32 = NULL; gf->divide.w32 = NULL; return 1; } static gf_val_32_t gf_wgen_table_8_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_table_w8_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_table_w8_data *) h->private; return (std->mult[(a<w)+b]); } static gf_val_32_t gf_wgen_table_8_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_table_w8_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_table_w8_data *) h->private; return (std->div[(a<w)+b]); } static int gf_wgen_table_8_init(gf_t *gf) { gf_internal_t *h; int w; struct gf_wgen_table_w8_data *std; uint32_t a, b, p; h = (gf_internal_t *) gf->scratch; w = h->w; std = (struct gf_wgen_table_w8_data *) h->private; std->mult = &(std->base); std->div = std->mult + ((1<w)*(1<w)); for (a = 0; a < (1 << w); a++) { std->mult[a] = 0; std->mult[a<div[a] = 0; std->div[a<mult[(a<div[(p<multiply.w32 = gf_wgen_table_8_multiply; gf->divide.w32 = gf_wgen_table_8_divide; return 1; } static gf_val_32_t gf_wgen_table_16_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_table_w16_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_table_w16_data *) h->private; return (std->mult[(a<w)+b]); } static gf_val_32_t gf_wgen_table_16_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_table_w16_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_table_w16_data *) h->private; return (std->div[(a<w)+b]); } static int gf_wgen_table_16_init(gf_t *gf) { gf_internal_t *h; int w; struct gf_wgen_table_w16_data *std; uint32_t a, b, p; h = (gf_internal_t *) gf->scratch; w = h->w; std = (struct gf_wgen_table_w16_data *) h->private; std->mult = &(std->base); std->div = std->mult + ((1<w)*(1<w)); for (a = 0; a < (1 << w); a++) { std->mult[a] = 0; std->mult[a<div[a] = 0; std->div[a<mult[(a<div[(p<multiply.w32 = gf_wgen_table_16_multiply; gf->divide.w32 = gf_wgen_table_16_divide; return 1; } static int gf_wgen_table_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (h->w <= 8) return gf_wgen_table_8_init(gf); if (h->w <= 14) return gf_wgen_table_16_init(gf); /* Returning zero to make the compiler happy, but this won't get executed, because it is tested in _scratch_space. */ return 0; } static gf_val_32_t gf_wgen_log_8_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_log_w8_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_log_w8_data *) h->private; if (a == 0 || b == 0) return 0; return (std->anti[std->log[a]+std->log[b]]); } static gf_val_32_t gf_wgen_log_8_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_log_w8_data *std; int index; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_log_w8_data *) h->private; if (a == 0 || b == 0) return 0; index = std->log[a]; index -= std->log[b]; return (std->danti[index]); } static int gf_wgen_log_8_init(gf_t *gf) { gf_internal_t *h; struct gf_wgen_log_w8_data *std; int w; uint32_t a, i; int check = 0; h = (gf_internal_t *) gf->scratch; w = h->w; std = (struct gf_wgen_log_w8_data *) h->private; std->log = &(std->base); std->anti = std->log + (1<w); std->danti = std->anti + (1<w)-1; for (i = 0; i < (1 << w); i++) std->log[i] = 0; a = 1; for(i=0; i < (1<log[a] != 0) check = 1; std->log[a] = i; std->anti[i] = a; std->danti[i] = a; a <<= 1; if(a & (1<prim_poly; //a &= ((1 << w)-1); } if (check != 0) { _gf_errno = GF_E_LOGPOLY; return 0; } gf->multiply.w32 = gf_wgen_log_8_multiply; gf->divide.w32 = gf_wgen_log_8_divide; return 1; } static gf_val_32_t gf_wgen_log_16_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_log_w16_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_log_w16_data *) h->private; if (a == 0 || b == 0) return 0; return (std->anti[std->log[a]+std->log[b]]); } static gf_val_32_t gf_wgen_log_16_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_log_w16_data *std; int index; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_log_w16_data *) h->private; if (a == 0 || b == 0) return 0; index = std->log[a]; index -= std->log[b]; return (std->danti[index]); } static int gf_wgen_log_16_init(gf_t *gf) { gf_internal_t *h; struct gf_wgen_log_w16_data *std; int w; uint32_t a, i; int check = 0; h = (gf_internal_t *) gf->scratch; w = h->w; std = (struct gf_wgen_log_w16_data *) h->private; std->log = &(std->base); std->anti = std->log + (1<w); std->danti = std->anti + (1<w)-1; for (i = 0; i < (1 << w); i++) std->log[i] = 0; a = 1; for(i=0; i < (1<log[a] != 0) check = 1; std->log[a] = i; std->anti[i] = a; std->danti[i] = a; a <<= 1; if(a & (1<prim_poly; //a &= ((1 << w)-1); } if (check) { if (h->mult_type != GF_MULT_LOG_TABLE) return gf_wgen_shift_init(gf); _gf_errno = GF_E_LOGPOLY; return 0; } gf->multiply.w32 = gf_wgen_log_16_multiply; gf->divide.w32 = gf_wgen_log_16_divide; return 1; } static gf_val_32_t gf_wgen_log_32_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_log_w32_data *std; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_log_w32_data *) h->private; if (a == 0 || b == 0) return 0; return (std->anti[std->log[a]+std->log[b]]); } static gf_val_32_t gf_wgen_log_32_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h; struct gf_wgen_log_w32_data *std; int index; h = (gf_internal_t *) gf->scratch; std = (struct gf_wgen_log_w32_data *) h->private; if (a == 0 || b == 0) return 0; index = std->log[a]; index -= std->log[b]; return (std->danti[index]); } static int gf_wgen_log_32_init(gf_t *gf) { gf_internal_t *h; struct gf_wgen_log_w32_data *std; int w; uint32_t a, i; int check = 0; h = (gf_internal_t *) gf->scratch; w = h->w; std = (struct gf_wgen_log_w32_data *) h->private; std->log = &(std->base); std->anti = std->log + (1<w); std->danti = std->anti + (1<w)-1; for (i = 0; i < (1 << w); i++) std->log[i] = 0; a = 1; for(i=0; i < (1<log[a] != 0) check = 1; std->log[a] = i; std->anti[i] = a; std->danti[i] = a; a <<= 1; if(a & (1<prim_poly; //a &= ((1 << w)-1); } if (check != 0) { _gf_errno = GF_E_LOGPOLY; return 0; } gf->multiply.w32 = gf_wgen_log_32_multiply; gf->divide.w32 = gf_wgen_log_32_divide; return 1; } static int gf_wgen_log_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (h->w <= 8) return gf_wgen_log_8_init(gf); if (h->w <= 16) return gf_wgen_log_16_init(gf); if (h->w <= 32) return gf_wgen_log_32_init(gf); /* Returning zero to make the compiler happy, but this won't get executed, because it is tested in _scratch_space. */ return 0; } int gf_wgen_scratch_size(int w, int mult_type, int region_type, int divide_type, int arg1, int arg2) { switch(mult_type) { case GF_MULT_DEFAULT: if (w <= 8) { return sizeof(gf_internal_t) + sizeof(struct gf_wgen_table_w8_data) + sizeof(uint8_t)*(1 << w)*(1<scratch; rs = bytes / (h->w); written = (xor) ? 0xffffffff : 0; for (i = 0; i < h->w; i++) { for (j = 0; j < h->w; j++) { if (val & (1 << j)) { gf_multby_one(src, ((char*)dest) + j*rs, rs, (written & (1 << j))); written |= (1 << j); } } src = (char*)src + rs; val = gf->multiply.w32(gf, val, 2); } } int gf_wgen_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (h->prim_poly == 0) { switch (h->w) { case 1: h->prim_poly = 1; break; case 2: h->prim_poly = 7; break; case 3: h->prim_poly = 013; break; case 4: h->prim_poly = 023; break; case 5: h->prim_poly = 045; break; case 6: h->prim_poly = 0103; break; case 7: h->prim_poly = 0211; break; case 8: h->prim_poly = 0435; break; case 9: h->prim_poly = 01021; break; case 10: h->prim_poly = 02011; break; case 11: h->prim_poly = 04005; break; case 12: h->prim_poly = 010123; break; case 13: h->prim_poly = 020033; break; case 14: h->prim_poly = 042103; break; case 15: h->prim_poly = 0100003; break; case 16: h->prim_poly = 0210013; break; case 17: h->prim_poly = 0400011; break; case 18: h->prim_poly = 01000201; break; case 19: h->prim_poly = 02000047; break; case 20: h->prim_poly = 04000011; break; case 21: h->prim_poly = 010000005; break; case 22: h->prim_poly = 020000003; break; case 23: h->prim_poly = 040000041; break; case 24: h->prim_poly = 0100000207; break; case 25: h->prim_poly = 0200000011; break; case 26: h->prim_poly = 0400000107; break; case 27: h->prim_poly = 01000000047; break; case 28: h->prim_poly = 02000000011; break; case 29: h->prim_poly = 04000000005; break; case 30: h->prim_poly = 010040000007; break; case 31: h->prim_poly = 020000000011; break; case 32: h->prim_poly = 00020000007; break; default: fprintf(stderr, "gf_wgen_init: w not defined yet\n"); exit(1); } } else { if (h->w == 32) { h->prim_poly &= 0xffffffff; } else { h->prim_poly |= (1 << h->w); if (h->prim_poly & ~((1ULL<<(h->w+1))-1)) return 0; } } gf->multiply.w32 = NULL; gf->divide.w32 = NULL; gf->inverse.w32 = NULL; gf->multiply_region.w32 = gf_wgen_cauchy_region; gf->extract_word.w32 = gf_wgen_extract_word; switch(h->mult_type) { case GF_MULT_DEFAULT: if (h->w <= 8) { if (gf_wgen_table_init(gf) == 0) return 0; } else if (h->w <= 16) { if (gf_wgen_log_init(gf) == 0) return 0; } else { if (gf_wgen_bytwo_p_init(gf) == 0) return 0; } break; case GF_MULT_SHIFT: if (gf_wgen_shift_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_b: if (gf_wgen_bytwo_b_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_p: if (gf_wgen_bytwo_p_init(gf) == 0) return 0; break; case GF_MULT_GROUP: if (gf_wgen_group_init(gf) == 0) return 0; break; case GF_MULT_TABLE: if (gf_wgen_table_init(gf) == 0) return 0; break; case GF_MULT_LOG_TABLE: if (gf_wgen_log_init(gf) == 0) return 0; break; default: return 0; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w32 = gf_wgen_divide_from_inverse; gf->inverse.w32 = gf_wgen_euclid; } else if (h->divide_type == GF_DIVIDE_MATRIX) { gf->divide.w32 = gf_wgen_divide_from_inverse; gf->inverse.w32 = gf_wgen_matrix; } if (gf->inverse.w32== NULL && gf->divide.w32 == NULL) gf->inverse.w32 = gf_wgen_euclid; if (gf->inverse.w32 != NULL && gf->divide.w32 == NULL) { gf->divide.w32 = gf_wgen_divide_from_inverse; } if (gf->inverse.w32 == NULL && gf->divide.w32 != NULL) { gf->inverse.w32 = gf_wgen_inverse_from_divide; } return 1; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_w4.c0000664000175100017510000014760412623076752026040 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_w4.c * * Routines for 4-bit Galois fields */ #include "gf_int.h" #include #include #define GF_FIELD_WIDTH 4 #define GF_DOUBLE_WIDTH (GF_FIELD_WIDTH*2) #define GF_FIELD_SIZE (1 << GF_FIELD_WIDTH) #define GF_MULT_GROUP_SIZE (GF_FIELD_SIZE-1) /* ------------------------------------------------------------ JSP: Each implementation has its own data, which is allocated at one time as part of the handle. For that reason, it shouldn't be hierarchical -- i.e. one should be able to allocate it with one call to malloc. */ struct gf_logtable_data { uint8_t log_tbl[GF_FIELD_SIZE]; uint8_t antilog_tbl[GF_FIELD_SIZE * 2]; uint8_t *antilog_tbl_div; }; struct gf_single_table_data { uint8_t mult[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint8_t div[GF_FIELD_SIZE][GF_FIELD_SIZE]; }; struct gf_double_table_data { uint8_t div[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint8_t mult[GF_FIELD_SIZE][GF_FIELD_SIZE*GF_FIELD_SIZE]; }; struct gf_quad_table_data { uint8_t div[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint16_t mult[GF_FIELD_SIZE][(1<<16)]; }; struct gf_quad_table_lazy_data { uint8_t div[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint8_t smult[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint16_t mult[(1 << 16)]; }; struct gf_bytwo_data { uint64_t prim_poly; uint64_t mask1; uint64_t mask2; }; #define AB2(ip, am1 ,am2, b, t1, t2) {\ t1 = (b << 1) & am1;\ t2 = b & am2; \ t2 = ((t2 << 1) - (t2 >> (GF_FIELD_WIDTH-1))); \ b = (t1 ^ (t2 & ip));} #define SSE_AB2(pp, m1, va, t1, t2) {\ t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); \ t2 = _mm_and_si128(va, _mm_set1_epi8(0x88)); \ t2 = _mm_sub_epi64 (_mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); \ va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } /* ------------------------------------------------------------ JSP: These are basic and work from multiple implementations. */ static inline gf_val_32_t gf_w4_inverse_from_divide (gf_t *gf, gf_val_32_t a) { return gf->divide.w32(gf, 1, a); } static inline gf_val_32_t gf_w4_divide_from_inverse (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { b = gf->inverse.w32(gf, b); return gf->multiply.w32(gf, a, b); } static inline gf_val_32_t gf_w4_euclid (gf_t *gf, gf_val_32_t b) { gf_val_32_t e_i, e_im1, e_ip1; gf_val_32_t d_i, d_im1, d_ip1; gf_val_32_t y_i, y_im1, y_ip1; gf_val_32_t c_i; if (b == 0) return -1; e_im1 = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i = b; d_im1 = 4; for (d_i = d_im1; ((1 << d_i) & e_i) == 0; d_i--) ; y_i = 1; y_im1 = 0; while (e_i != 1) { e_ip1 = e_im1; d_ip1 = d_im1; c_i = 0; while (d_ip1 >= d_i) { c_i ^= (1 << (d_ip1 - d_i)); e_ip1 ^= (e_i << (d_ip1 - d_i)); if (e_ip1 == 0) return 0; while ((e_ip1 & (1 << d_ip1)) == 0) d_ip1--; } y_ip1 = y_im1 ^ gf->multiply.w32(gf, c_i, y_i); y_im1 = y_i; y_i = y_ip1; e_im1 = e_i; d_im1 = d_i; e_i = e_ip1; d_i = d_ip1; } return y_i; } static gf_val_32_t gf_w4_extract_word(gf_t *gf, void *start, int bytes, int index) { uint8_t *r8, v; r8 = (uint8_t *) start; v = r8[index/2]; if (index%2) { return v >> 4; } else { return v&0xf; } } static inline gf_val_32_t gf_w4_matrix (gf_t *gf, gf_val_32_t b) { return gf_bitmatrix_inverse(b, 4, ((gf_internal_t *) (gf->scratch))->prim_poly); } static inline gf_val_32_t gf_w4_shift_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint8_t product, i, pp; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; product = 0; for (i = 0; i < GF_FIELD_WIDTH; i++) { if (a & (1 << i)) product ^= (b << i); } for (i = (GF_FIELD_WIDTH*2-2); i >= GF_FIELD_WIDTH; i--) { if (product & (1 << i)) product ^= (pp << (i-GF_FIELD_WIDTH)); } return product; } /* Ben: This function works, but it is 33% slower than the normal shift mult */ static inline gf_val_32_t gf_w4_clm_multiply (gf_t *gf, gf_val_32_t a4, gf_val_32_t b4) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a4, 0); b = _mm_insert_epi32 (a, b4, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1fULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); /* Ben/JSP: Do prim_poly reduction once. We are guaranteed that we will only have to do the reduction only once, because (w-2)/z == 1. Where z is equal to the number of zeros after the leading 1. _mm_clmulepi64_si128 is the carryless multiply operation. Here _mm_srli_epi64 shifts the result to the right by 4 bits. This allows us to multiply the prim_poly by the leading bits of the result. We then xor the result of that operation back with the result. */ w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_epi64 (result, 4), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static void gf_w4_multiply_region_from_single(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint8_t *s8; uint8_t *d8; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 1); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; if (xor) { while (d8 < ((uint8_t *) rd.d_top)) { *d8 ^= (gf->multiply.w32(gf, val, (*s8 & 0xf)) | ((gf->multiply.w32(gf, val, (*s8 >> 4))) << 4)); d8++; s8++; } } else { while (d8 < ((uint8_t *) rd.d_top)) { *d8 = (gf->multiply.w32(gf, val, (*s8 & 0xf)) | ((gf->multiply.w32(gf, val, (*s8 >> 4))) << 4)); d8++; s8++; } } gf_do_final_region_alignment(&rd); } /* ------------------------------------------------------------ IMPLEMENTATION: LOG_TABLE: JSP: This is a basic log-antilog implementation. I'm not going to spend any time optimizing it because the other techniques are faster for both single and region operations. */ static inline gf_val_32_t gf_w4_log_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_logtable_data *ltd; ltd = (struct gf_logtable_data *) ((gf_internal_t *) (gf->scratch))->private; return (a == 0 || b == 0) ? 0 : ltd->antilog_tbl[(unsigned)(ltd->log_tbl[a] + ltd->log_tbl[b])]; } static inline gf_val_32_t gf_w4_log_divide (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int log_sum = 0; struct gf_logtable_data *ltd; if (a == 0 || b == 0) return 0; ltd = (struct gf_logtable_data *) ((gf_internal_t *) (gf->scratch))->private; log_sum = ltd->log_tbl[a] - ltd->log_tbl[b]; return (ltd->antilog_tbl_div[log_sum]); } static void gf_w4_log_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t lv, b, c; uint8_t *s8, *d8; struct gf_logtable_data *ltd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } ltd = (struct gf_logtable_data *) ((gf_internal_t *) (gf->scratch))->private; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; lv = ltd->log_tbl[val]; for (i = 0; i < bytes; i++) { c = (xor) ? d8[i] : 0; b = (s8[i] >> GF_FIELD_WIDTH); c ^= (b == 0) ? 0 : (ltd->antilog_tbl[lv + ltd->log_tbl[b]] << GF_FIELD_WIDTH); b = (s8[i] & 0xf); c ^= (b == 0) ? 0 : ltd->antilog_tbl[lv + ltd->log_tbl[b]]; d8[i] = c; } } static int gf_w4_log_init(gf_t *gf) { gf_internal_t *h; struct gf_logtable_data *ltd; int i, b; h = (gf_internal_t *) gf->scratch; ltd = h->private; for (i = 0; i < GF_FIELD_SIZE; i++) ltd->log_tbl[i]=0; ltd->antilog_tbl_div = ltd->antilog_tbl + (GF_FIELD_SIZE-1); b = 1; i = 0; do { if (ltd->log_tbl[b] != 0 && i != 0) { fprintf(stderr, "Cannot construct log table: Polynomial is not primitive.\n\n"); return 0; } ltd->log_tbl[b] = i; ltd->antilog_tbl[i] = b; ltd->antilog_tbl[i+GF_FIELD_SIZE-1] = b; b <<= 1; i++; if (b & GF_FIELD_SIZE) b = b ^ h->prim_poly; } while (b != 1); if (i != GF_FIELD_SIZE - 1) { _gf_errno = GF_E_LOGPOLY; return 0; } gf->inverse.w32 = gf_w4_inverse_from_divide; gf->divide.w32 = gf_w4_log_divide; gf->multiply.w32 = gf_w4_log_multiply; gf->multiply_region.w32 = gf_w4_log_multiply_region; return 1; } /* ------------------------------------------------------------ IMPLEMENTATION: SINGLE TABLE: JSP. */ static inline gf_val_32_t gf_w4_single_table_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_single_table_data *std; std = (struct gf_single_table_data *) ((gf_internal_t *) (gf->scratch))->private; return std->mult[a][b]; } static inline gf_val_32_t gf_w4_single_table_divide (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_single_table_data *std; std = (struct gf_single_table_data *) ((gf_internal_t *) (gf->scratch))->private; return std->div[a][b]; } static void gf_w4_single_table_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t b, c; uint8_t *s8, *d8; struct gf_single_table_data *std; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } std = (struct gf_single_table_data *) ((gf_internal_t *) (gf->scratch))->private; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; for (i = 0; i < bytes; i++) { c = (xor) ? d8[i] : 0; b = (s8[i] >> GF_FIELD_WIDTH); c ^= (std->mult[val][b] << GF_FIELD_WIDTH); b = (s8[i] & 0xf); c ^= (std->mult[val][b]); d8[i] = c; } } #define MM_PRINT(s, r) { uint8_t blah[16]; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (i = 0; i < 16; i++) printf(" %02x", blah[i]); printf("\n"); } #ifdef INTEL_SSSE3 static void gf_w4_single_table_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint8_t *base, *sptr, *dptr, *top; __m128i tl, loset, r, va, th; struct gf_single_table_data *std; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); std = (struct gf_single_table_data *) ((gf_internal_t *) (gf->scratch))->private; base = (uint8_t *) std->mult; base += (val << GF_FIELD_WIDTH); gf_do_initial_region_alignment(&rd); tl = _mm_loadu_si128((__m128i *)base); th = _mm_slli_epi64(tl, 4); loset = _mm_set1_epi8 (0x0f); sptr = rd.s_start; dptr = rd.d_start; top = rd.s_top; while (sptr < (uint8_t *) top) { va = _mm_load_si128 ((__m128i *)(sptr)); r = _mm_and_si128 (loset, va); r = _mm_shuffle_epi8 (tl, r); va = _mm_srli_epi64 (va, 4); va = _mm_and_si128 (loset, va); va = _mm_shuffle_epi8 (th, va); r = _mm_xor_si128 (r, va); va = (xor) ? _mm_load_si128 ((__m128i *)(dptr)) : _mm_setzero_si128(); r = _mm_xor_si128 (r, va); _mm_store_si128 ((__m128i *)(dptr), r); dptr += 16; sptr += 16; } gf_do_final_region_alignment(&rd); } #endif static int gf_w4_single_table_init(gf_t *gf) { gf_internal_t *h; struct gf_single_table_data *std; int a, b, prod; h = (gf_internal_t *) gf->scratch; std = (struct gf_single_table_data *)h->private; bzero(std->mult, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(std->div, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); for (a = 1; a < GF_FIELD_SIZE; a++) { for (b = 1; b < GF_FIELD_SIZE; b++) { prod = gf_w4_shift_multiply(gf, a, b); std->mult[a][b] = prod; std->div[prod][b] = a; } } gf->inverse.w32 = NULL; gf->divide.w32 = gf_w4_single_table_divide; gf->multiply.w32 = gf_w4_single_table_multiply; #ifdef INTEL_SSSE3 if(h->region_type & (GF_REGION_NOSSE | GF_REGION_CAUCHY)) gf->multiply_region.w32 = gf_w4_single_table_multiply_region; else gf->multiply_region.w32 = gf_w4_single_table_sse_multiply_region; #else gf->multiply_region.w32 = gf_w4_single_table_multiply_region; if (h->region_type & GF_REGION_SSE) return 0; #endif return 1; } /* ------------------------------------------------------------ IMPLEMENTATION: DOUBLE TABLE: JSP. */ static inline gf_val_32_t gf_w4_double_table_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_double_table_data *std; std = (struct gf_double_table_data *) ((gf_internal_t *) (gf->scratch))->private; return std->mult[a][b]; } static inline gf_val_32_t gf_w4_double_table_divide (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_double_table_data *std; std = (struct gf_double_table_data *) ((gf_internal_t *) (gf->scratch))->private; return std->div[a][b]; } static void gf_w4_double_table_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8, *base; gf_region_data rd; struct gf_double_table_data *std; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); std = (struct gf_double_table_data *) ((gf_internal_t *) (gf->scratch))->private; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; base = (uint8_t *) std->mult; base += (val << GF_DOUBLE_WIDTH); if (xor) { for (i = 0; i < bytes; i++) d8[i] ^= base[s8[i]]; } else { for (i = 0; i < bytes; i++) d8[i] = base[s8[i]]; } } static int gf_w4_double_table_init(gf_t *gf) { gf_internal_t *h; struct gf_double_table_data *std; int a, b, c, prod, ab; uint8_t mult[GF_FIELD_SIZE][GF_FIELD_SIZE]; h = (gf_internal_t *) gf->scratch; std = (struct gf_double_table_data *)h->private; bzero(mult, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(std->div, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); for (a = 1; a < GF_FIELD_SIZE; a++) { for (b = 1; b < GF_FIELD_SIZE; b++) { prod = gf_w4_shift_multiply(gf, a, b); mult[a][b] = prod; std->div[prod][b] = a; } } bzero(std->mult, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE * GF_FIELD_SIZE); for (a = 0; a < GF_FIELD_SIZE; a++) { for (b = 0; b < GF_FIELD_SIZE; b++) { ab = mult[a][b]; for (c = 0; c < GF_FIELD_SIZE; c++) { std->mult[a][(b << 4) | c] = ((ab << 4) | mult[a][c]); } } } gf->inverse.w32 = NULL; gf->divide.w32 = gf_w4_double_table_divide; gf->multiply.w32 = gf_w4_double_table_multiply; gf->multiply_region.w32 = gf_w4_double_table_multiply_region; return 1; } static inline gf_val_32_t gf_w4_quad_table_lazy_divide (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_quad_table_lazy_data *std; std = (struct gf_quad_table_lazy_data *) ((gf_internal_t *) (gf->scratch))->private; return std->div[a][b]; } static inline gf_val_32_t gf_w4_quad_table_lazy_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_quad_table_lazy_data *std; std = (struct gf_quad_table_lazy_data *) ((gf_internal_t *) (gf->scratch))->private; return std->smult[a][b]; } static inline gf_val_32_t gf_w4_quad_table_divide (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_quad_table_data *std; std = (struct gf_quad_table_data *) ((gf_internal_t *) (gf->scratch))->private; return std->div[a][b]; } static inline gf_val_32_t gf_w4_quad_table_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_quad_table_data *std; uint16_t v; std = (struct gf_quad_table_data *) ((gf_internal_t *) (gf->scratch))->private; v = std->mult[a][b]; return v; } static void gf_w4_quad_table_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint16_t *base; gf_region_data rd; struct gf_quad_table_data *std; struct gf_quad_table_lazy_data *ltd; gf_internal_t *h; int a, b, c, d, va, vb, vc, vd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) (gf->scratch); if (h->region_type & GF_REGION_LAZY) { ltd = (struct gf_quad_table_lazy_data *) ((gf_internal_t *) (gf->scratch))->private; base = ltd->mult; for (a = 0; a < 16; a++) { va = (ltd->smult[val][a] << 12); for (b = 0; b < 16; b++) { vb = (ltd->smult[val][b] << 8); for (c = 0; c < 16; c++) { vc = (ltd->smult[val][c] << 4); for (d = 0; d < 16; d++) { vd = ltd->smult[val][d]; base[(a << 12) | (b << 8) | (c << 4) | d ] = (va | vb | vc | vd); } } } } } else { std = (struct gf_quad_table_data *) ((gf_internal_t *) (gf->scratch))->private; base = &(std->mult[val][0]); } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); gf_two_byte_region_table_multiply(&rd, base); gf_do_final_region_alignment(&rd); } static int gf_w4_quad_table_init(gf_t *gf) { gf_internal_t *h; struct gf_quad_table_data *std; int prod, val, a, b, c, d, va, vb, vc, vd; uint8_t mult[GF_FIELD_SIZE][GF_FIELD_SIZE]; h = (gf_internal_t *) gf->scratch; std = (struct gf_quad_table_data *)h->private; bzero(mult, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(std->div, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); for (a = 1; a < GF_FIELD_SIZE; a++) { for (b = 1; b < GF_FIELD_SIZE; b++) { prod = gf_w4_shift_multiply(gf, a, b); mult[a][b] = prod; std->div[prod][b] = a; } } for (val = 0; val < 16; val++) { for (a = 0; a < 16; a++) { va = (mult[val][a] << 12); for (b = 0; b < 16; b++) { vb = (mult[val][b] << 8); for (c = 0; c < 16; c++) { vc = (mult[val][c] << 4); for (d = 0; d < 16; d++) { vd = mult[val][d]; std->mult[val][(a << 12) | (b << 8) | (c << 4) | d ] = (va | vb | vc | vd); } } } } } gf->inverse.w32 = NULL; gf->divide.w32 = gf_w4_quad_table_divide; gf->multiply.w32 = gf_w4_quad_table_multiply; gf->multiply_region.w32 = gf_w4_quad_table_multiply_region; return 1; } static int gf_w4_quad_table_lazy_init(gf_t *gf) { gf_internal_t *h; struct gf_quad_table_lazy_data *std; int a, b, prod, loga, logb; uint8_t log_tbl[GF_FIELD_SIZE]; uint8_t antilog_tbl[GF_FIELD_SIZE*2]; h = (gf_internal_t *) gf->scratch; std = (struct gf_quad_table_lazy_data *)h->private; b = 1; for (a = 0; a < GF_MULT_GROUP_SIZE; a++) { log_tbl[b] = a; antilog_tbl[a] = b; antilog_tbl[a+GF_MULT_GROUP_SIZE] = b; b <<= 1; if (b & GF_FIELD_SIZE) { b = b ^ h->prim_poly; } } bzero(std->smult, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(std->div, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); for (a = 1; a < GF_FIELD_SIZE; a++) { loga = log_tbl[a]; for (b = 1; b < GF_FIELD_SIZE; b++) { logb = log_tbl[b]; prod = antilog_tbl[loga+logb]; std->smult[a][b] = prod; std->div[prod][b] = a; } } gf->inverse.w32 = NULL; gf->divide.w32 = gf_w4_quad_table_lazy_divide; gf->multiply.w32 = gf_w4_quad_table_lazy_multiply; gf->multiply_region.w32 = gf_w4_quad_table_multiply_region; return 1; } static int gf_w4_table_init(gf_t *gf) { int rt; gf_internal_t *h; int issse3 = 0; #ifdef INTEL_SSSE3 issse3 = 1; #endif h = (gf_internal_t *) gf->scratch; rt = (h->region_type); if (h->mult_type == GF_MULT_DEFAULT && !issse3) rt |= GF_REGION_DOUBLE_TABLE; if (rt & GF_REGION_DOUBLE_TABLE) { return gf_w4_double_table_init(gf); } else if (rt & GF_REGION_QUAD_TABLE) { if (rt & GF_REGION_LAZY) { return gf_w4_quad_table_lazy_init(gf); } else { return gf_w4_quad_table_init(gf); } return gf_w4_double_table_init(gf); } else { return gf_w4_single_table_init(gf); } return 0; } /* ------------------------------------------------------------ JSP: GF_MULT_BYTWO_p and _b: See the paper. */ static inline gf_val_32_t gf_w4_bytwo_p_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, pmask, amask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; pmask = 0x8; amask = 0x8; while (amask != 0) { if (prod & pmask) { prod = ((prod << 1) ^ pp); } else { prod <<= 1; } if (a & amask) prod ^= b; amask >>= 1; } return prod; } static inline gf_val_32_t gf_w4_bytwo_b_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, bmask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; bmask = 0x8; while (1) { if (a & 1) prod ^= b; a >>= 1; if (a == 0) return prod; if (b & bmask) { b = ((b << 1) ^ pp); } else { b <<= 1; } } } static void gf_w4_bytwo_p_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, prod, amask; gf_region_data rd; struct gf_bytwo_data *btd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; if (xor) { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x8; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 ^= prod; d64++; s64++; } } else { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x8; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 = prod; d64++; s64++; } } gf_do_final_region_alignment(&rd); } #define BYTWO_P_ONESTEP {\ SSE_AB2(pp, m1, prod, t1, t2); \ t1 = _mm_and_si128(v, one); \ t1 = _mm_sub_epi8(t1, one); \ t1 = _mm_and_si128(t1, ta); \ prod = _mm_xor_si128(prod, t1); \ v = _mm_srli_epi64(v, 1); } #ifdef INTEL_SSE2 static void gf_w4_bytwo_p_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8; uint8_t vrev; __m128i pp, m1, ta, prod, t1, t2, tp, one, v; struct gf_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); vrev = 0; for (i = 0; i < 4; i++) { vrev <<= 1; if (!(val & (1 << i))) vrev |= 1; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); one = _mm_set1_epi8(1); while (d8 < (uint8_t *) rd.d_top) { prod = _mm_setzero_si128(); v = _mm_set1_epi8(vrev); ta = _mm_load_si128((__m128i *) s8); tp = (!xor) ? _mm_setzero_si128() : _mm_load_si128((__m128i *) d8); BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; _mm_store_si128((__m128i *) d8, _mm_xor_si128(prod, tp)); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif /* static void gf_w4_bytwo_b_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { #ifdef INTEL_SSE2 uint8_t *d8, *s8, tb; __m128i pp, m1, m2, t1, t2, va, vb; struct gf_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; btd = (struct gf_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); m2 = _mm_set1_epi8((btd->mask2)&0xff); if (xor) { while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_load_si128 ((__m128i *)(d8)); tb = val; while (1) { if (tb & 1) vb = _mm_xor_si128(vb, va); tb >>= 1; if (tb == 0) break; SSE_AB2(pp, m1, m2, va, t1, t2); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } else { while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_setzero_si128 (); tb = val; while (1) { if (tb & 1) vb = _mm_xor_si128(vb, va); tb >>= 1; if (tb == 0) break; t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); t2 = _mm_and_si128(va, m2); t2 = _mm_sub_epi64 ( _mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } gf_do_final_region_alignment(&rd); #endif } */ #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_2_noxor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, va, t1, t2); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_2_xor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_load_si128 ((__m128i *)(d8)); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_4_noxor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, va, t1, t2); SSE_AB2(pp, m1, va, t1, t2); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_4_xor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, va, t1, t2); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_load_si128 ((__m128i *)(d8)); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_3_noxor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = va; SSE_AB2(pp, m1, va, t1, t2); va = _mm_xor_si128(va, vb); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_3_xor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_xor_si128(_mm_load_si128 ((__m128i *)(d8)), va); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_5_noxor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = va; SSE_AB2(pp, m1, va, t1, t2); SSE_AB2(pp, m1, va, t1, t2); va = _mm_xor_si128(va, vb); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_5_xor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_xor_si128(_mm_load_si128 ((__m128i *)(d8)), va); SSE_AB2(pp, m1, va, t1, t2); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_7_noxor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = va; SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(va, vb); SSE_AB2(pp, m1, va, t1, t2); va = _mm_xor_si128(va, vb); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_7_xor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_xor_si128(_mm_load_si128 ((__m128i *)(d8)), va); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(vb, va); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_6_noxor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, va, t1, t2); vb = va; SSE_AB2(pp, m1, va, t1, t2); va = _mm_xor_si128(va, vb); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_region_6_xor(gf_region_data *rd, struct gf_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(_mm_load_si128 ((__m128i *)(d8)), va); SSE_AB2(pp, m1, va, t1, t2); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w4_bytwo_b_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint8_t *d8, *s8, tb; __m128i pp, m1, m2, t1, t2, va, vb; struct gf_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; btd = (struct gf_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; switch (val) { case 2: if (!xor) { gf_w4_bytwo_b_sse_region_2_noxor(&rd, btd); } else { gf_w4_bytwo_b_sse_region_2_xor(&rd, btd); } gf_do_final_region_alignment(&rd); return; case 3: if (!xor) { gf_w4_bytwo_b_sse_region_3_noxor(&rd, btd); } else { gf_w4_bytwo_b_sse_region_3_xor(&rd, btd); } gf_do_final_region_alignment(&rd); return; case 4: if (!xor) { gf_w4_bytwo_b_sse_region_4_noxor(&rd, btd); } else { gf_w4_bytwo_b_sse_region_4_xor(&rd, btd); } gf_do_final_region_alignment(&rd); return; case 5: if (!xor) { gf_w4_bytwo_b_sse_region_5_noxor(&rd, btd); } else { gf_w4_bytwo_b_sse_region_5_xor(&rd, btd); } gf_do_final_region_alignment(&rd); return; case 6: if (!xor) { gf_w4_bytwo_b_sse_region_6_noxor(&rd, btd); } else { gf_w4_bytwo_b_sse_region_6_xor(&rd, btd); } gf_do_final_region_alignment(&rd); return; case 7: if (!xor) { gf_w4_bytwo_b_sse_region_7_noxor(&rd, btd); } else { gf_w4_bytwo_b_sse_region_7_xor(&rd, btd); } gf_do_final_region_alignment(&rd); return; } pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); m2 = _mm_set1_epi8((btd->mask2)&0xff); if (xor) { while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_load_si128 ((__m128i *)(d8)); tb = val; while (1) { if (tb & 1) vb = _mm_xor_si128(vb, va); tb >>= 1; if (tb == 0) break; SSE_AB2(pp, m1, va, t1, t2); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } else { while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = _mm_setzero_si128 (); tb = val; while (1) { if (tb & 1) vb = _mm_xor_si128(vb, va); tb >>= 1; if (tb == 0) break; t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); t2 = _mm_and_si128(va, m2); t2 = _mm_sub_epi64 ( _mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } gf_do_final_region_alignment(&rd); } #endif static void gf_w4_bytwo_b_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, tb, prod; struct gf_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); btd = (struct gf_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; switch (val) { case 1: if (xor) { while (d64 < (uint64_t *) rd.d_top) { *d64 ^= *s64; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { *d64 = *s64; d64++; s64++; } } break; case 2: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 3: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 4: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 5: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } case 6: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } case 7: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } break; case 8: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 9: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 10: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 11: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 12: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 13: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 14: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 15: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; default: if (xor) { while (d64 < (uint64_t *) rd.d_top) { prod = *d64 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { prod = 0 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } break; } gf_do_final_region_alignment(&rd); } static int gf_w4_bytwo_init(gf_t *gf) { gf_internal_t *h; uint64_t ip, m1, m2; struct gf_bytwo_data *btd; h = (gf_internal_t *) gf->scratch; btd = (struct gf_bytwo_data *) (h->private); ip = h->prim_poly & 0xf; m1 = 0xe; m2 = 0x8; btd->prim_poly = 0; btd->mask1 = 0; btd->mask2 = 0; while (ip != 0) { btd->prim_poly |= ip; btd->mask1 |= m1; btd->mask2 |= m2; ip <<= GF_FIELD_WIDTH; m1 <<= GF_FIELD_WIDTH; m2 <<= GF_FIELD_WIDTH; } if (h->mult_type == GF_MULT_BYTWO_p) { gf->multiply.w32 = gf_w4_bytwo_p_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w4_bytwo_p_nosse_multiply_region; else gf->multiply_region.w32 = gf_w4_bytwo_p_sse_multiply_region; #else gf->multiply_region.w32 = gf_w4_bytwo_p_nosse_multiply_region; if (h->region_type & GF_REGION_SSE) return 0; #endif } else { gf->multiply.w32 = gf_w4_bytwo_b_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w4_bytwo_b_nosse_multiply_region; else gf->multiply_region.w32 = gf_w4_bytwo_b_sse_multiply_region; #else gf->multiply_region.w32 = gf_w4_bytwo_b_nosse_multiply_region; if (h->region_type & GF_REGION_SSE) return 0; #endif } return 1; } static int gf_w4_cfm_init(gf_t *gf) { #if defined(INTEL_SSE4_PCLMUL) gf->multiply.w32 = gf_w4_clm_multiply; return 1; #endif return 0; } static int gf_w4_shift_init(gf_t *gf) { gf->multiply.w32 = gf_w4_shift_multiply; return 1; } /* JSP: I'm putting all error-checking into gf_error_check(), so you don't have to do error checking in scratch_size or in init */ int gf_w4_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2) { int issse3 = 0; #ifdef INTEL_SSSE3 issse3 = 1; #endif switch(mult_type) { case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: return sizeof(gf_internal_t) + sizeof(struct gf_bytwo_data); break; case GF_MULT_DEFAULT: case GF_MULT_TABLE: if (region_type == GF_REGION_CAUCHY) { return sizeof(gf_internal_t) + sizeof(struct gf_single_table_data) + 64; } if (mult_type == GF_MULT_DEFAULT && !issse3) region_type = GF_REGION_DOUBLE_TABLE; if (region_type & GF_REGION_DOUBLE_TABLE) { return sizeof(gf_internal_t) + sizeof(struct gf_double_table_data) + 64; } else if (region_type & GF_REGION_QUAD_TABLE) { if ((region_type & GF_REGION_LAZY) == 0) { return sizeof(gf_internal_t) + sizeof(struct gf_quad_table_data) + 64; } else { return sizeof(gf_internal_t) + sizeof(struct gf_quad_table_lazy_data) + 64; } } else { return sizeof(gf_internal_t) + sizeof(struct gf_single_table_data) + 64; } break; case GF_MULT_LOG_TABLE: return sizeof(gf_internal_t) + sizeof(struct gf_logtable_data) + 64; break; case GF_MULT_CARRY_FREE: return sizeof(gf_internal_t); break; case GF_MULT_SHIFT: return sizeof(gf_internal_t); break; default: return 0; } return 0; } int gf_w4_init (gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (h->prim_poly == 0) h->prim_poly = 0x13; h->prim_poly |= 0x10; gf->multiply.w32 = NULL; gf->divide.w32 = NULL; gf->inverse.w32 = NULL; gf->multiply_region.w32 = NULL; gf->extract_word.w32 = gf_w4_extract_word; switch(h->mult_type) { case GF_MULT_CARRY_FREE: if (gf_w4_cfm_init(gf) == 0) return 0; break; case GF_MULT_SHIFT: if (gf_w4_shift_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: if (gf_w4_bytwo_init(gf) == 0) return 0; break; case GF_MULT_LOG_TABLE: if (gf_w4_log_init(gf) == 0) return 0; break; case GF_MULT_DEFAULT: case GF_MULT_TABLE: if (gf_w4_table_init(gf) == 0) return 0; break; default: return 0; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w32 = gf_w4_divide_from_inverse; gf->inverse.w32 = gf_w4_euclid; } else if (h->divide_type == GF_DIVIDE_MATRIX) { gf->divide.w32 = gf_w4_divide_from_inverse; gf->inverse.w32 = gf_w4_matrix; } if (gf->divide.w32 == NULL) { gf->divide.w32 = gf_w4_divide_from_inverse; if (gf->inverse.w32 == NULL) gf->inverse.w32 = gf_w4_euclid; } if (gf->inverse.w32 == NULL) gf->inverse.w32 = gf_w4_inverse_from_divide; if (h->region_type == GF_REGION_CAUCHY) { gf->multiply_region.w32 = gf_wgen_cauchy_region; gf->extract_word.w32 = gf_wgen_extract_word; } if (gf->multiply_region.w32 == NULL) { gf->multiply_region.w32 = gf_w4_multiply_region_from_single; } return 1; } /* Inline setup functions */ uint8_t *gf_w4_get_mult_table(gf_t *gf) { gf_internal_t *h; struct gf_single_table_data *std; h = (gf_internal_t *) gf->scratch; if (gf->multiply.w32 == gf_w4_single_table_multiply) { std = (struct gf_single_table_data *) h->private; return (uint8_t *) std->mult; } return NULL; } uint8_t *gf_w4_get_div_table(gf_t *gf) { gf_internal_t *h; struct gf_single_table_data *std; h = (gf_internal_t *) gf->scratch; if (gf->multiply.w32 == gf_w4_single_table_multiply) { std = (struct gf_single_table_data *) h->private; return (uint8_t *) std->div; } return NULL; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_general.c0000664000175100017510000003246112623076752027115 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_general.c * * This file has helper routines for doing basic GF operations with any * legal value of w. The problem is that w <= 32, w=64 and w=128 all have * different data types, which is a pain. The procedures in this file try * to alleviate that pain. They are used in gf_unit and gf_time. */ #include #include #include #include #include #include #include "gf_complete.h" #include "gf_int.h" #include "gf_method.h" #include "gf_rand.h" #include "gf_general.h" void gf_general_set_zero(gf_general_t *v, int w) { if (w <= 32) { v->w32 = 0; } else if (w <= 64) { v->w64 = 0; } else { v->w128[0] = 0; v->w128[1] = 0; } } void gf_general_set_one(gf_general_t *v, int w) { if (w <= 32) { v->w32 = 1; } else if (w <= 64) { v->w64 = 1; } else { v->w128[0] = 0; v->w128[1] = 1; } } void gf_general_set_two(gf_general_t *v, int w) { if (w <= 32) { v->w32 = 2; } else if (w <= 64) { v->w64 = 2; } else { v->w128[0] = 0; v->w128[1] = 2; } } int gf_general_is_zero(gf_general_t *v, int w) { if (w <= 32) { return (v->w32 == 0); } else if (w <= 64) { return (v->w64 == 0); } else { return (v->w128[0] == 0 && v->w128[1] == 0); } } int gf_general_is_one(gf_general_t *v, int w) { if (w <= 32) { return (v->w32 == 1); } else if (w <= 64) { return (v->w64 == 1); } else { return (v->w128[0] == 0 && v->w128[1] == 1); } } void gf_general_set_random(gf_general_t *v, int w, int zero_ok) { if (w <= 32) { v->w32 = MOA_Random_W(w, zero_ok); } else if (w <= 64) { while (1) { v->w64 = MOA_Random_64(); if (v->w64 != 0 || zero_ok) return; } } else { while (1) { MOA_Random_128(v->w128); if (v->w128[0] != 0 || v->w128[1] != 0 || zero_ok) return; } } } void gf_general_val_to_s(gf_general_t *v, int w, char *s, int hex) { if (w <= 32) { if (hex) { sprintf(s, "%x", v->w32); } else { sprintf(s, "%u", v->w32); } } else if (w <= 64) { if (hex) { sprintf(s, "%llx", (long long unsigned int) v->w64); } else { sprintf(s, "%lld", (long long unsigned int) v->w64); } } else { if (v->w128[0] == 0) { sprintf(s, "%llx", (long long unsigned int) v->w128[1]); } else { sprintf(s, "%llx%016llx", (long long unsigned int) v->w128[0], (long long unsigned int) v->w128[1]); } } } int gf_general_s_to_val(gf_general_t *v, int w, char *s, int hex) { int l; int save; if (w <= 32) { if (hex) { if (sscanf(s, "%x", &(v->w32)) == 0) return 0; } else { if (sscanf(s, "%u", &(v->w32)) == 0) return 0; } if (w == 32) return 1; if (w == 31) { if (v->w32 & (1 << 31)) return 0; return 1; } if (v->w32 & ~((1 << w)-1)) return 0; return 1; } else if (w <= 64) { if (hex) return (sscanf(s, "%llx", (long long unsigned int *) (&(v->w64))) == 1); return (sscanf(s, "%lld", (long long int *) (&(v->w64))) == 1); } else { if (!hex) return 0; l = strlen(s); if (l <= 16) { v->w128[0] = 0; return (sscanf(s, "%llx", (long long unsigned int *) (&(v->w128[1]))) == 1); } else { if (l > 32) return 0; save = s[l-16]; s[l-16] = '\0'; if (sscanf(s, "%llx", (long long unsigned int *) (&(v->w128[0]))) == 0) { s[l-16] = save; return 0; } return (sscanf(s+(l-16), "%llx", (long long unsigned int *) (&(v->w128[1]))) == 1); } } } void gf_general_add(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c) { gf_internal_t *h; int w; h = (gf_internal_t *) gf->scratch; w = h->w; if (w <= 32) { c->w32 = a->w32 ^ b->w32; } else if (w <= 64) { c->w64 = a->w64 ^ b->w64; } else { c->w128[0] = a->w128[0] ^ b->w128[0]; c->w128[1] = a->w128[1] ^ b->w128[1]; } } void gf_general_multiply(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c) { gf_internal_t *h; int w; h = (gf_internal_t *) gf->scratch; w = h->w; if (w <= 32) { c->w32 = gf->multiply.w32(gf, a->w32, b->w32); } else if (w <= 64) { c->w64 = gf->multiply.w64(gf, a->w64, b->w64); } else { gf->multiply.w128(gf, a->w128, b->w128, c->w128); } } void gf_general_divide(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c) { gf_internal_t *h; int w; h = (gf_internal_t *) gf->scratch; w = h->w; if (w <= 32) { c->w32 = gf->divide.w32(gf, a->w32, b->w32); } else if (w <= 64) { c->w64 = gf->divide.w64(gf, a->w64, b->w64); } else { gf->divide.w128(gf, a->w128, b->w128, c->w128); } } void gf_general_inverse(gf_t *gf, gf_general_t *a, gf_general_t *b) { gf_internal_t *h; int w; h = (gf_internal_t *) gf->scratch; w = h->w; if (w <= 32) { b->w32 = gf->inverse.w32(gf, a->w32); } else if (w <= 64) { b->w64 = gf->inverse.w64(gf, a->w64); } else { gf->inverse.w128(gf, a->w128, b->w128); } } int gf_general_are_equal(gf_general_t *v1, gf_general_t *v2, int w) { if (w <= 32) { return (v1->w32 == v2->w32); } else if (w <= 64) { return (v1->w64 == v2->w64); } else { return (v1->w128[0] == v2->w128[0] && v1->w128[0] == v2->w128[0]); } } void gf_general_do_region_multiply(gf_t *gf, gf_general_t *a, void *ra, void *rb, int bytes, int xor) { gf_internal_t *h; int w; h = (gf_internal_t *) gf->scratch; w = h->w; if (w <= 32) { gf->multiply_region.w32(gf, ra, rb, a->w32, bytes, xor); } else if (w <= 64) { gf->multiply_region.w64(gf, ra, rb, a->w64, bytes, xor); } else { gf->multiply_region.w128(gf, ra, rb, a->w128, bytes, xor); } } void gf_general_do_region_check(gf_t *gf, gf_general_t *a, void *orig_a, void *orig_target, void *final_target, int bytes, int xor) { gf_internal_t *h; int w, words, i; gf_general_t oa, ot, ft, sb; char sa[50], soa[50], sot[50], sft[50], ssb[50]; h = (gf_internal_t *) gf->scratch; w = h->w; words = (bytes * 8) / w; for (i = 0; i < words; i++) { if (w <= 32) { oa.w32 = gf->extract_word.w32(gf, orig_a, bytes, i); ot.w32 = gf->extract_word.w32(gf, orig_target, bytes, i); ft.w32 = gf->extract_word.w32(gf, final_target, bytes, i); sb.w32 = gf->multiply.w32(gf, a->w32, oa.w32); if (xor) sb.w32 ^= ot.w32; } else if (w <= 64) { oa.w64 = gf->extract_word.w64(gf, orig_a, bytes, i); ot.w64 = gf->extract_word.w64(gf, orig_target, bytes, i); ft.w64 = gf->extract_word.w64(gf, final_target, bytes, i); sb.w64 = gf->multiply.w64(gf, a->w64, oa.w64); if (xor) sb.w64 ^= ot.w64; } else { gf->extract_word.w128(gf, orig_a, bytes, i, oa.w128); gf->extract_word.w128(gf, orig_target, bytes, i, ot.w128); gf->extract_word.w128(gf, final_target, bytes, i, ft.w128); gf->multiply.w128(gf, a->w128, oa.w128, sb.w128); if (xor) { sb.w128[0] ^= ot.w128[0]; sb.w128[1] ^= ot.w128[1]; } } if (!gf_general_are_equal(&ft, &sb, w)) { fprintf(stderr,"Problem with region multiply (all values in hex):\n"); fprintf(stderr," Target address base: 0x%lx. Word 0x%x of 0x%x. Xor: %d\n", (unsigned long) final_target, i, words, xor); gf_general_val_to_s(a, w, sa, 1); gf_general_val_to_s(&oa, w, soa, 1); gf_general_val_to_s(&ot, w, sot, 1); gf_general_val_to_s(&ft, w, sft, 1); gf_general_val_to_s(&sb, w, ssb, 1); fprintf(stderr," Value: %s\n", sa); fprintf(stderr," Original source word: %s\n", soa); if (xor) fprintf(stderr," XOR with target word: %s\n", sot); fprintf(stderr," Product word: %s\n", sft); fprintf(stderr," It should be: %s\n", ssb); exit(0); } } } void gf_general_set_up_single_timing_test(int w, void *ra, void *rb, int size) { void *top; gf_general_t g; uint8_t *r8, *r8a; uint16_t *r16; uint32_t *r32; uint64_t *r64; int i; top = (char*)rb+size; /* If w is 8, 16, 32, 64 or 128, fill the regions with random bytes. However, don't allow for zeros in rb, because that will screw up division. When w is 4, you fill the regions with random 4-bit words in each byte. Otherwise, treat every four bytes as an uint32_t and fill it with a random value mod (1 << w). */ if (w == 8 || w == 16 || w == 32 || w == 64 || w == 128) { MOA_Fill_Random_Region (ra, size); while (rb < top) { gf_general_set_random(&g, w, 0); switch (w) { case 8: r8 = (uint8_t *) rb; *r8 = g.w32; break; case 16: r16 = (uint16_t *) rb; *r16 = g.w32; break; case 32: r32 = (uint32_t *) rb; *r32 = g.w32; break; case 64: r64 = (uint64_t *) rb; *r64 = g.w64; break; case 128: r64 = (uint64_t *) rb; r64[0] = g.w128[0]; r64[1] = g.w128[1]; break; } rb = (char*)rb + (w/8); } } else if (w == 4) { r8a = (uint8_t *) ra; r8 = (uint8_t *) rb; while (r8 < (uint8_t *) top) { gf_general_set_random(&g, w, 1); *r8a = g.w32; gf_general_set_random(&g, w, 0); *r8 = g.w32; r8a++; r8++; } } else { r32 = (uint32_t *) ra; for (i = 0; i < size/4; i++) r32[i] = MOA_Random_W(w, 1); r32 = (uint32_t *) rb; for (i = 0; i < size/4; i++) r32[i] = MOA_Random_W(w, 0); } } /* This sucks, but in order to time, you really need to avoid putting ifs in the inner loops. So, I'm doing a separate timing test for each w: (4 & 8), 16, 32, 64, 128 and everything else. Fortunately, the "everything else" tests can be equivalent to w=32. I'm also putting the results back into ra, because otherwise, the optimizer might figure out that we're not really doing anything in the inner loops and it will chuck that. */ int gf_general_do_single_timing_test(gf_t *gf, void *ra, void *rb, int size, char test) { gf_internal_t *h; void *top; uint8_t *r8a, *r8b, *top8; uint16_t *r16a, *r16b, *top16; uint32_t *r32a, *r32b, *top32; uint64_t *r64a, *r64b, *top64, *r64c; int w, rv; h = (gf_internal_t *) gf->scratch; w = h->w; top = (char*)ra + size; if (w == 8 || w == 4) { r8a = (uint8_t *) ra; r8b = (uint8_t *) rb; top8 = (uint8_t *) top; if (test == 'M') { while (r8a < top8) { *r8a = gf->multiply.w32(gf, *r8a, *r8b); r8a++; r8b++; } } else if (test == 'D') { while (r8a < top8) { *r8a = gf->divide.w32(gf, *r8a, *r8b); r8a++; r8b++; } } else if (test == 'I') { while (r8a < top8) { *r8a = gf->inverse.w32(gf, *r8a); r8a++; } } return (top8 - (uint8_t *) ra); } if (w == 16) { r16a = (uint16_t *) ra; r16b = (uint16_t *) rb; top16 = (uint16_t *) top; if (test == 'M') { while (r16a < top16) { *r16a = gf->multiply.w32(gf, *r16a, *r16b); r16a++; r16b++; } } else if (test == 'D') { while (r16a < top16) { *r16a = gf->divide.w32(gf, *r16a, *r16b); r16a++; r16b++; } } else if (test == 'I') { while (r16a < top16) { *r16a = gf->inverse.w32(gf, *r16a); r16a++; } } return (top16 - (uint16_t *) ra); } if (w <= 32) { r32a = (uint32_t *) ra; r32b = (uint32_t *) rb; top32 = (uint32_t *) ra + (size/4); /* This is for the "everything elses" */ if (test == 'M') { while (r32a < top32) { *r32a = gf->multiply.w32(gf, *r32a, *r32b); r32a++; r32b++; } } else if (test == 'D') { while (r32a < top32) { *r32a = gf->divide.w32(gf, *r32a, *r32b); r32a++; r32b++; } } else if (test == 'I') { while (r32a < top32) { *r32a = gf->inverse.w32(gf, *r32a); r32a++; } } return (top32 - (uint32_t *) ra); } if (w == 64) { r64a = (uint64_t *) ra; r64b = (uint64_t *) rb; top64 = (uint64_t *) top; if (test == 'M') { while (r64a < top64) { *r64a = gf->multiply.w64(gf, *r64a, *r64b); r64a++; r64b++; } } else if (test == 'D') { while (r64a < top64) { *r64a = gf->divide.w64(gf, *r64a, *r64b); r64a++; r64b++; } } else if (test == 'I') { while (r64a < top64) { *r64a = gf->inverse.w64(gf, *r64a); r64a++; } } return (top64 - (uint64_t *) ra); } if (w == 128) { r64a = (uint64_t *) ra; r64c = r64a; r64a += 2; r64b = (uint64_t *) rb; top64 = (uint64_t *) top; rv = (top64 - r64a)/2; if (test == 'M') { while (r64a < top64) { gf->multiply.w128(gf, r64a, r64b, r64c); r64a += 2; r64b += 2; } } else if (test == 'D') { while (r64a < top64) { gf->divide.w128(gf, r64a, r64b, r64c); r64a += 2; r64b += 2; } } else if (test == 'I') { while (r64a < top64) { gf->inverse.w128(gf, r64a, r64c); r64a += 2; } } return rv; } return 0; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_w128.c0000664000175100017510000013647512623076752026213 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_w128.c * * Routines for 128-bit Galois fields */ #include "gf_int.h" #include #include #define GF_FIELD_WIDTH (128) #define two_x(a) {\ a[0] <<= 1; \ if (a[1] & 1ULL << 63) a[0] ^= 1; \ a[1] <<= 1; } #define a_get_b(a, i, b, j) {\ a[i] = b[j]; \ a[i + 1] = b[j + 1];} #define set_zero(a, i) {\ a[i] = 0; \ a[i + 1] = 0;} struct gf_w128_split_4_128_data { uint64_t last_value[2]; uint64_t tables[2][32][16]; }; struct gf_w128_split_8_128_data { uint64_t last_value[2]; uint64_t tables[2][16][256]; }; typedef struct gf_group_tables_s { gf_val_128_t m_table; gf_val_128_t r_table; } gf_group_tables_t; #define MM_PRINT8(s, r) { uint8_t blah[16], ii; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (ii = 0; ii < 16; ii += 1) printf("%s%02x", (ii%4==0) ? " " : " ", blah[15-ii]); printf("\n"); } static void gf_w128_multiply_region_from_single(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { int i; gf_val_128_t s128; gf_val_128_t d128; uint64_t c128[2]; gf_region_data rd; /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } set_zero(c128, 0); s128 = (gf_val_128_t) src; d128 = (gf_val_128_t) dest; if (xor) { for (i = 0; i < bytes/sizeof(gf_val_64_t); i += 2) { gf->multiply.w128(gf, &s128[i], val, c128); d128[i] ^= c128[0]; d128[i+1] ^= c128[1]; } } else { for (i = 0; i < bytes/sizeof(gf_val_64_t); i += 2) { gf->multiply.w128(gf, &s128[i], val, &d128[i]); } } } #if defined(INTEL_SSE4_PCLMUL) static void gf_w128_clm_multiply_region_from_single(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { int i; gf_val_128_t s128; gf_val_128_t d128; gf_region_data rd; __m128i a,b; __m128i result0,result1; __m128i prim_poly; __m128i c,d,e,f; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)h->prim_poly); /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } s128 = (gf_val_128_t) src; d128 = (gf_val_128_t) dest; if (xor) { for (i = 0; i < bytes/sizeof(gf_val_64_t); i += 2) { a = _mm_insert_epi64 (_mm_setzero_si128(), s128[i+1], 0); b = _mm_insert_epi64 (a, val[1], 0); a = _mm_insert_epi64 (a, s128[i], 1); b = _mm_insert_epi64 (b, val[0], 1); c = _mm_clmulepi64_si128 (a, b, 0x00); /*low-low*/ f = _mm_clmulepi64_si128 (a, b, 0x01); /*high-low*/ e = _mm_clmulepi64_si128 (a, b, 0x10); /*low-high*/ d = _mm_clmulepi64_si128 (a, b, 0x11); /*high-high*/ /* now reusing a and b as temporary variables*/ result0 = _mm_setzero_si128(); result1 = result0; result0 = _mm_xor_si128 (result0, _mm_insert_epi64 (d, 0, 0)); a = _mm_xor_si128 (_mm_srli_si128 (e, 8), _mm_insert_epi64 (d, 0, 1)); result0 = _mm_xor_si128 (result0, _mm_xor_si128 (_mm_srli_si128 (f, 8), a)); a = _mm_xor_si128 (_mm_slli_si128 (e, 8), _mm_insert_epi64 (c, 0, 0)); result1 = _mm_xor_si128 (result1, _mm_xor_si128 (_mm_slli_si128 (f, 8), a)); result1 = _mm_xor_si128 (result1, _mm_insert_epi64 (c, 0, 1)); /* now we have constructed our 'result' with result0 being the carry bits, and we have to reduce. */ a = _mm_srli_si128 (result0, 8); b = _mm_clmulepi64_si128 (a, prim_poly, 0x00); result0 = _mm_xor_si128 (result0, _mm_srli_si128 (b, 8)); result1 = _mm_xor_si128 (result1, _mm_slli_si128 (b, 8)); a = _mm_insert_epi64 (result0, 0, 1); b = _mm_clmulepi64_si128 (a, prim_poly, 0x00); result1 = _mm_xor_si128 (result1, b); d128[i] ^= (uint64_t)_mm_extract_epi64(result1,1); d128[i+1] ^= (uint64_t)_mm_extract_epi64(result1,0); } } else { for (i = 0; i < bytes/sizeof(gf_val_64_t); i += 2) { a = _mm_insert_epi64 (_mm_setzero_si128(), s128[i+1], 0); b = _mm_insert_epi64 (a, val[1], 0); a = _mm_insert_epi64 (a, s128[i], 1); b = _mm_insert_epi64 (b, val[0], 1); c = _mm_clmulepi64_si128 (a, b, 0x00); /*low-low*/ f = _mm_clmulepi64_si128 (a, b, 0x01); /*high-low*/ e = _mm_clmulepi64_si128 (a, b, 0x10); /*low-high*/ d = _mm_clmulepi64_si128 (a, b, 0x11); /*high-high*/ /* now reusing a and b as temporary variables*/ result0 = _mm_setzero_si128(); result1 = result0; result0 = _mm_xor_si128 (result0, _mm_insert_epi64 (d, 0, 0)); a = _mm_xor_si128 (_mm_srli_si128 (e, 8), _mm_insert_epi64 (d, 0, 1)); result0 = _mm_xor_si128 (result0, _mm_xor_si128 (_mm_srli_si128 (f, 8), a)); a = _mm_xor_si128 (_mm_slli_si128 (e, 8), _mm_insert_epi64 (c, 0, 0)); result1 = _mm_xor_si128 (result1, _mm_xor_si128 (_mm_slli_si128 (f, 8), a)); result1 = _mm_xor_si128 (result1, _mm_insert_epi64 (c, 0, 1)); /* now we have constructed our 'result' with result0 being the carry bits, and we have to reduce.*/ a = _mm_srli_si128 (result0, 8); b = _mm_clmulepi64_si128 (a, prim_poly, 0x00); result0 = _mm_xor_si128 (result0, _mm_srli_si128 (b, 8)); result1 = _mm_xor_si128 (result1, _mm_slli_si128 (b, 8)); a = _mm_insert_epi64 (result0, 0, 1); b = _mm_clmulepi64_si128 (a, prim_poly, 0x00); result1 = _mm_xor_si128 (result1, b); d128[i] = (uint64_t)_mm_extract_epi64(result1,1); d128[i+1] = (uint64_t)_mm_extract_epi64(result1,0); } } } #endif /* * Some w128 notes: * --Big Endian * --return values allocated beforehand */ #define GF_W128_IS_ZERO(val) (val[0] == 0 && val[1] == 0) void gf_w128_shift_multiply(gf_t *gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { /* ordered highest bit to lowest l[0] l[1] r[0] r[1] */ uint64_t pl[2], pr[2], ppl[2], ppr[2], i, a[2], bl[2], br[2], one, lbit; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (GF_W128_IS_ZERO(a128) || GF_W128_IS_ZERO(b128)) { set_zero(c128, 0); return; } a_get_b(a, 0, a128, 0); a_get_b(br, 0, b128, 0); set_zero(bl, 0); one = 1; lbit = (one << 63); set_zero(pl, 0); set_zero(pr, 0); /* Allen: a*b for right half of a */ for (i = 0; i < GF_FIELD_WIDTH/2; i++) { if (a[1] & (one << i)) { pl[1] ^= bl[1]; pr[0] ^= br[0]; pr[1] ^= br[1]; } bl[1] <<= 1; if (br[0] & lbit) bl[1] ^= 1; br[0] <<= 1; if (br[1] & lbit) br[0] ^= 1; br[1] <<= 1; } /* Allen: a*b for left half of a */ for (i = 0; i < GF_FIELD_WIDTH/2; i++) { if (a[0] & (one << i)) { pl[0] ^= bl[0]; pl[1] ^= bl[1]; pr[0] ^= br[0]; } bl[0] <<= 1; if (bl[1] & lbit) bl[0] ^= 1; bl[1] <<= 1; if (br[0] & lbit) bl[1] ^= 1; br[0] <<= 1; } /* Allen: do first half of reduction (based on left quarter of initial product) */ one = lbit >> 1; ppl[0] = one; /* Allen: introduce leading one of primitive polynomial */ ppl[1] = h->prim_poly >> 2; ppr[0] = h->prim_poly << (GF_FIELD_WIDTH/2-2); ppr[1] = 0; while (one != 0) { if (pl[0] & one) { pl[0] ^= ppl[0]; pl[1] ^= ppl[1]; pr[0] ^= ppr[0]; pr[1] ^= ppr[1]; } one >>= 1; ppr[1] >>= 1; if (ppr[0] & 1) ppr[1] ^= lbit; ppr[0] >>= 1; if (ppl[1] & 1) ppr[0] ^= lbit; ppl[1] >>= 1; if (ppl[0] & 1) ppl[1] ^= lbit; ppl[0] >>= 1; } /* Allen: final half of reduction */ one = lbit; while (one != 0) { if (pl[1] & one) { pl[1] ^= ppl[1]; pr[0] ^= ppr[0]; pr[1] ^= ppr[1]; } one >>= 1; ppr[1] >>= 1; if (ppr[0] & 1) ppr[1] ^= lbit; ppr[0] >>= 1; if (ppl[1] & 1) ppr[0] ^= lbit; ppl[1] >>= 1; } /* Allen: if we really want to optimize this we can just be using c128 instead of pr all along */ c128[0] = pr[0]; c128[1] = pr[1]; return; } void gf_w128_clm_multiply(gf_t *gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { #if defined(INTEL_SSE4_PCLMUL) __m128i a,b; __m128i result0,result1; __m128i prim_poly; __m128i c,d,e,f; gf_internal_t * h = gf->scratch; a = _mm_insert_epi64 (_mm_setzero_si128(), a128[1], 0); b = _mm_insert_epi64 (a, b128[1], 0); a = _mm_insert_epi64 (a, a128[0], 1); b = _mm_insert_epi64 (b, b128[0], 1); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)h->prim_poly); /* we need to test algorithm 2 later*/ c = _mm_clmulepi64_si128 (a, b, 0x00); /*low-low*/ f = _mm_clmulepi64_si128 (a, b, 0x01); /*high-low*/ e = _mm_clmulepi64_si128 (a, b, 0x10); /*low-high*/ d = _mm_clmulepi64_si128 (a, b, 0x11); /*high-high*/ /* now reusing a and b as temporary variables*/ result0 = _mm_setzero_si128(); result1 = result0; result0 = _mm_xor_si128 (result0, _mm_insert_epi64 (d, 0, 0)); a = _mm_xor_si128 (_mm_srli_si128 (e, 8), _mm_insert_epi64 (d, 0, 1)); result0 = _mm_xor_si128 (result0, _mm_xor_si128 (_mm_srli_si128 (f, 8), a)); a = _mm_xor_si128 (_mm_slli_si128 (e, 8), _mm_insert_epi64 (c, 0, 0)); result1 = _mm_xor_si128 (result1, _mm_xor_si128 (_mm_slli_si128 (f, 8), a)); result1 = _mm_xor_si128 (result1, _mm_insert_epi64 (c, 0, 1)); /* now we have constructed our 'result' with result0 being the carry bits, and we have to reduce.*/ a = _mm_srli_si128 (result0, 8); b = _mm_clmulepi64_si128 (a, prim_poly, 0x00); result0 = _mm_xor_si128 (result0, _mm_srli_si128 (b, 8)); result1 = _mm_xor_si128 (result1, _mm_slli_si128 (b, 8)); a = _mm_insert_epi64 (result0, 0, 1); b = _mm_clmulepi64_si128 (a, prim_poly, 0x00); result1 = _mm_xor_si128 (result1, b); c128[0] = (uint64_t)_mm_extract_epi64(result1,1); c128[1] = (uint64_t)_mm_extract_epi64(result1,0); #endif return; } void gf_w128_bytwo_p_multiply(gf_t *gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { uint64_t amask[2], pmask, pp, prod[2]; /*John: pmask is always the highest bit set, and the rest zeros. amask changes, it's a countdown.*/ uint64_t topbit; /* this is used as a boolean value */ gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod[0] = 0; prod[1] = 0; pmask = 0x8000000000000000ULL; amask[0] = 0x8000000000000000ULL; amask[1] = 0; while (amask[1] != 0 || amask[0] != 0) { topbit = (prod[0] & pmask); prod[0] <<= 1; if (prod[1] & pmask) prod[0] ^= 1; prod[1] <<= 1; if (topbit) prod[1] ^= pp; if ((a128[0] & amask[0]) || (a128[1] & amask[1])) { prod[0] ^= b128[0]; prod[1] ^= b128[1]; } amask[1] >>= 1; if (amask[0] & 1) amask[1] ^= pmask; amask[0] >>= 1; } c128[0] = prod [0]; c128[1] = prod [1]; return; } void gf_w128_sse_bytwo_p_multiply(gf_t *gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { #if defined(INTEL_SSE4) int i; __m128i a, b, pp, prod, amask, u_middle_one; /*John: pmask is always the highest bit set, and the rest zeros. amask changes, it's a countdown.*/ uint32_t topbit, middlebit, pmask; /* this is used as a boolean value */ gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = _mm_set_epi32(0, 0, 0, (uint32_t)h->prim_poly); prod = _mm_setzero_si128(); a = _mm_insert_epi64(prod, a128[1], 0x0); a = _mm_insert_epi64(a, a128[0], 0x1); b = _mm_insert_epi64(prod, b128[1], 0x0); b = _mm_insert_epi64(b, b128[0], 0x1); pmask = 0x80000000; amask = _mm_insert_epi32(prod, 0x80000000, 0x3); u_middle_one = _mm_insert_epi32(prod, 1, 0x2); for (i = 0; i < 64; i++) { topbit = (_mm_extract_epi32(prod, 0x3) & pmask); middlebit = (_mm_extract_epi32(prod, 0x1) & pmask); prod = _mm_slli_epi64(prod, 1); /* this instruction loses the middle bit */ if (middlebit) { prod = _mm_xor_si128(prod, u_middle_one); } if (topbit) { prod = _mm_xor_si128(prod, pp); } if (((uint64_t)_mm_extract_epi64(_mm_and_si128(a, amask), 1))) { prod = _mm_xor_si128(prod, b); } amask = _mm_srli_epi64(amask, 1); /*so does this one, but we can just replace after loop*/ } amask = _mm_insert_epi32(amask, 1 << 31, 0x1); for (i = 64; i < 128; i++) { topbit = (_mm_extract_epi32(prod, 0x3) & pmask); middlebit = (_mm_extract_epi32(prod, 0x1) & pmask); prod = _mm_slli_epi64(prod, 1); if (middlebit) prod = _mm_xor_si128(prod, u_middle_one); if (topbit) prod = _mm_xor_si128(prod, pp); if (((uint64_t)_mm_extract_epi64(_mm_and_si128(a, amask), 0))) { prod = _mm_xor_si128(prod, b); } amask = _mm_srli_epi64(amask, 1); } c128[0] = (uint64_t)_mm_extract_epi64(prod, 1); c128[1] = (uint64_t)_mm_extract_epi64(prod, 0); #endif return; } /* Ben: This slow function implements sse instrutions for bytwo_b because why not */ void gf_w128_sse_bytwo_b_multiply(gf_t *gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { #if defined(INTEL_SSE4) __m128i a, b, lmask, hmask, pp, c, middle_one; gf_internal_t *h; uint64_t topbit, middlebit; h = (gf_internal_t *) gf->scratch; c = _mm_setzero_si128(); lmask = _mm_insert_epi64(c, 1ULL << 63, 0); hmask = _mm_insert_epi64(c, 1ULL << 63, 1); b = _mm_insert_epi64(c, a128[0], 1); b = _mm_insert_epi64(b, a128[1], 0); a = _mm_insert_epi64(c, b128[0], 1); a = _mm_insert_epi64(a, b128[1], 0); pp = _mm_insert_epi64(c, h->prim_poly, 0); middle_one = _mm_insert_epi64(c, 1, 0x1); while (1) { if (_mm_extract_epi32(a, 0x0) & 1) { c = _mm_xor_si128(c, b); } middlebit = (_mm_extract_epi32(a, 0x2) & 1); a = _mm_srli_epi64(a, 1); if (middlebit) a = _mm_xor_si128(a, lmask); if ((_mm_extract_epi64(a, 0x1) == 0ULL) && (_mm_extract_epi64(a, 0x0) == 0ULL)){ c128[0] = _mm_extract_epi64(c, 0x1); c128[1] = _mm_extract_epi64(c, 0x0); return; } topbit = (_mm_extract_epi64(_mm_and_si128(b, hmask), 1)); middlebit = (_mm_extract_epi64(_mm_and_si128(b, lmask), 0)); b = _mm_slli_epi64(b, 1); if (middlebit) b = _mm_xor_si128(b, middle_one); if (topbit) b = _mm_xor_si128(b, pp); } #endif } void gf_w128_bytwo_b_multiply(gf_t *gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { uint64_t bmask, pp; gf_internal_t *h; uint64_t a[2], b[2], c[2]; h = (gf_internal_t *) gf->scratch; bmask = (1ULL << 63); set_zero(c, 0); b[0] = a128[0]; b[1] = a128[1]; a[0] = b128[0]; a[1] = b128[1]; while (1) { if (a[1] & 1) { c[0] ^= b[0]; c[1] ^= b[1]; } a[1] >>= 1; if (a[0] & 1) a[1] ^= bmask; a[0] >>= 1; if (a[1] == 0 && a[0] == 0) { c128[0] = c[0]; c128[1] = c[1]; return; } pp = (b[0] & bmask); b[0] <<= 1; if (b[1] & bmask) b[0] ^= 1; b[1] <<= 1; if (pp) b[1] ^= h->prim_poly; } } static void gf_w128_split_4_128_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { int i, j, k; uint64_t pp; gf_internal_t *h; uint64_t *s64, *d64, *top; gf_region_data rd; uint64_t v[2], s; struct gf_w128_split_4_128_data *ld; /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } h = (gf_internal_t *) gf->scratch; ld = (struct gf_w128_split_4_128_data *) h->private; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; if (val[0] != ld->last_value[0] || val[1] != ld->last_value[1]) { v[0] = val[0]; v[1] = val[1]; for (i = 0; i < 32; i++) { ld->tables[0][i][0] = 0; ld->tables[1][i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[0][i][k^j] = (v[0] ^ ld->tables[0][i][k]); ld->tables[1][i][k^j] = (v[1] ^ ld->tables[1][i][k]); } pp = (v[0] & (1ULL << 63)); v[0] <<= 1; if (v[1] & (1ULL << 63)) v[0] ^= 1; v[1] <<= 1; if (pp) v[1] ^= h->prim_poly; } } } ld->last_value[0] = val[0]; ld->last_value[1] = val[1]; /* for (i = 0; i < 32; i++) { for (j = 0; j < 16; j++) { printf("%2d %2d %016llx %016llx\n", i, j, ld->tables[0][i][j], ld->tables[1][i][j]); } printf("\n"); } */ i = 0; while (d64 < top) { v[0] = (xor) ? d64[0] : 0; v[1] = (xor) ? d64[1] : 0; s = s64[1]; i = 0; while (s != 0) { v[0] ^= ld->tables[0][i][s&0xf]; v[1] ^= ld->tables[1][i][s&0xf]; s >>= 4; i++; } s = s64[0]; i = 16; while (s != 0) { v[0] ^= ld->tables[0][i][s&0xf]; v[1] ^= ld->tables[1][i][s&0xf]; s >>= 4; i++; } d64[0] = v[0]; d64[1] = v[1]; s64 += 2; d64 += 2; } } #if defined(INTEL_SSSE3) && defined(INTEL_SSE4) static void gf_w128_split_4_128_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { gf_internal_t *h; int i, j, k; uint64_t pp, v[2], s, *s64, *d64, *top; __m128i p, tables[32][16]; struct gf_w128_split_4_128_data *ld; gf_region_data rd; if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 16); /* Doing this instead of gf_do_initial_region_alignment() because that doesn't hold 128-bit vals */ gf_w128_multiply_region_from_single(gf, src, dest, val, ((char*)rd.s_start-(char*)src), xor); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; ld = (struct gf_w128_split_4_128_data *) h->private; if (val[0] != ld->last_value[0] || val[1] != ld->last_value[1]) { v[0] = val[0]; v[1] = val[1]; for (i = 0; i < 32; i++) { ld->tables[0][i][0] = 0; ld->tables[1][i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[0][i][k^j] = (v[0] ^ ld->tables[0][i][k]); ld->tables[1][i][k^j] = (v[1] ^ ld->tables[1][i][k]); } pp = (v[0] & (1ULL << 63)); v[0] <<= 1; if (v[1] & (1ULL << 63)) v[0] ^= 1; v[1] <<= 1; if (pp) v[1] ^= h->prim_poly; } } } ld->last_value[0] = val[0]; ld->last_value[1] = val[1]; for (i = 0; i < 32; i++) { for (j = 0; j < 16; j++) { v[0] = ld->tables[0][i][j]; v[1] = ld->tables[1][i][j]; tables[i][j] = _mm_loadu_si128((__m128i *) v); /* printf("%2d %2d: ", i, j); MM_PRINT8("", tables[i][j]); */ } } while (d64 != top) { if (xor) { p = _mm_load_si128 ((__m128i *) d64); } else { p = _mm_setzero_si128(); } s = *s64; s64++; for (i = 0; i < 16; i++) { j = (s&0xf); s >>= 4; p = _mm_xor_si128(p, tables[16+i][j]); } s = *s64; s64++; for (i = 0; i < 16; i++) { j = (s&0xf); s >>= 4; p = _mm_xor_si128(p, tables[i][j]); } _mm_store_si128((__m128i *) d64, p); d64 += 2; } /* Doing this instead of gf_do_final_region_alignment() because that doesn't hold 128-bit vals */ gf_w128_multiply_region_from_single(gf, rd.s_top, rd.d_top, val, ((char*)src+bytes)-(char*)rd.s_top, xor); } #endif #if defined(INTEL_SSSE3) && defined(INTEL_SSE4) static void gf_w128_split_4_128_sse_altmap_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { gf_internal_t *h; int i, j, k; uint64_t pp, v[2], *s64, *d64, *top; __m128i si, tables[32][16], p[16], v0, mask1; struct gf_w128_split_4_128_data *ld; uint8_t btable[16]; gf_region_data rd; if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 256); /* Doing this instead of gf_do_initial_region_alignment() because that doesn't hold 128-bit vals */ gf_w128_multiply_region_from_single(gf, src, dest, val, ((char*)rd.s_start-(char*)src), xor); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; ld = (struct gf_w128_split_4_128_data *) h->private; if (val[0] != ld->last_value[0] || val[1] != ld->last_value[1]) { v[0] = val[0]; v[1] = val[1]; for (i = 0; i < 32; i++) { ld->tables[0][i][0] = 0; ld->tables[1][i][0] = 0; for (j = 1; j < 16; j <<= 1) { for (k = 0; k < j; k++) { ld->tables[0][i][k^j] = (v[0] ^ ld->tables[0][i][k]); ld->tables[1][i][k^j] = (v[1] ^ ld->tables[1][i][k]); } pp = (v[0] & (1ULL << 63)); v[0] <<= 1; if (v[1] & (1ULL << 63)) v[0] ^= 1; v[1] <<= 1; if (pp) v[1] ^= h->prim_poly; } } } ld->last_value[0] = val[0]; ld->last_value[1] = val[1]; for (i = 0; i < 32; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < 16; k++) { btable[k] = (uint8_t) ld->tables[1-(j/8)][i][k]; ld->tables[1-(j/8)][i][k] >>= 8; } tables[i][j] = _mm_loadu_si128((__m128i *) btable); /* printf("%2d %2d: ", i, j); MM_PRINT8("", tables[i][j]); */ } } mask1 = _mm_set1_epi8(0xf); while (d64 != top) { if (xor) { for (i = 0; i < 16; i++) p[i] = _mm_load_si128 ((__m128i *) (d64+i*2)); } else { for (i = 0; i < 16; i++) p[i] = _mm_setzero_si128(); } i = 0; for (k = 0; k < 16; k++) { v0 = _mm_load_si128((__m128i *) s64); s64 += 2; si = _mm_and_si128(v0, mask1); for (j = 0; j < 16; j++) { p[j] = _mm_xor_si128(p[j], _mm_shuffle_epi8(tables[i][j], si)); } i++; v0 = _mm_srli_epi32(v0, 4); si = _mm_and_si128(v0, mask1); for (j = 0; j < 16; j++) { p[j] = _mm_xor_si128(p[j], _mm_shuffle_epi8(tables[i][j], si)); } i++; } for (i = 0; i < 16; i++) { _mm_store_si128((__m128i *) d64, p[i]); d64 += 2; } } /* Doing this instead of gf_do_final_region_alignment() because that doesn't hold 128-bit vals */ gf_w128_multiply_region_from_single(gf, rd.s_top, rd.d_top, val, ((char*)src+bytes)-(char*)rd.s_top, xor); } #endif static void gf_w128_split_8_128_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { int i, j, k; uint64_t pp; gf_internal_t *h; uint64_t *s64, *d64, *top; gf_region_data rd; uint64_t v[2], s; struct gf_w128_split_8_128_data *ld; /* Check on alignment. Ignore it otherwise. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } h = (gf_internal_t *) gf->scratch; ld = (struct gf_w128_split_8_128_data *) h->private; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; if (val[0] != ld->last_value[0] || val[1] != ld->last_value[1]) { v[0] = val[0]; v[1] = val[1]; for (i = 0; i < 16; i++) { ld->tables[0][i][0] = 0; ld->tables[1][i][0] = 0; for (j = 1; j < (1 << 8); j <<= 1) { for (k = 0; k < j; k++) { ld->tables[0][i][k^j] = (v[0] ^ ld->tables[0][i][k]); ld->tables[1][i][k^j] = (v[1] ^ ld->tables[1][i][k]); } pp = (v[0] & (1ULL << 63)); v[0] <<= 1; if (v[1] & (1ULL << 63)) v[0] ^= 1; v[1] <<= 1; if (pp) v[1] ^= h->prim_poly; } } } ld->last_value[0] = val[0]; ld->last_value[1] = val[1]; while (d64 < top) { v[0] = (xor) ? d64[0] : 0; v[1] = (xor) ? d64[1] : 0; s = s64[1]; i = 0; while (s != 0) { v[0] ^= ld->tables[0][i][s&0xff]; v[1] ^= ld->tables[1][i][s&0xff]; s >>= 8; i++; } s = s64[0]; i = 8; while (s != 0) { v[0] ^= ld->tables[0][i][s&0xff]; v[1] ^= ld->tables[1][i][s&0xff]; s >>= 8; i++; } d64[0] = v[0]; d64[1] = v[1]; s64 += 2; d64 += 2; } } void gf_w128_bytwo_b_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { uint64_t bmask, pp; gf_internal_t *h; uint64_t a[2], c[2], b[2], *s64, *d64, *top; gf_region_data rd; /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } h = (gf_internal_t *) gf->scratch; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top = (uint64_t *) rd.d_top; bmask = (1ULL << 63); while (d64 < top) { set_zero(c, 0); b[0] = s64[0]; b[1] = s64[1]; a[0] = val[0]; a[1] = val[1]; while (a[0] != 0) { if (a[1] & 1) { c[0] ^= b[0]; c[1] ^= b[1]; } a[1] >>= 1; if (a[0] & 1) a[1] ^= bmask; a[0] >>= 1; pp = (b[0] & bmask); b[0] <<= 1; if (b[1] & bmask) b[0] ^= 1; b[1] <<= 1; if (pp) b[1] ^= h->prim_poly; } while (1) { if (a[1] & 1) { c[0] ^= b[0]; c[1] ^= b[1]; } a[1] >>= 1; if (a[1] == 0) break; pp = (b[0] & bmask); b[0] <<= 1; if (b[1] & bmask) b[0] ^= 1; b[1] <<= 1; if (pp) b[1] ^= h->prim_poly; } if (xor) { d64[0] ^= c[0]; d64[1] ^= c[1]; } else { d64[0] = c[0]; d64[1] = c[1]; } s64 += 2; d64 += 2; } } static void gf_w128_group_m_init(gf_t *gf, gf_val_128_t b128) { int i, j; int g_m; uint64_t prim_poly, lbit; gf_internal_t *scratch; gf_group_tables_t *gt; uint64_t a128[2]; scratch = (gf_internal_t *) gf->scratch; gt = scratch->private; g_m = scratch->arg1; prim_poly = scratch->prim_poly; set_zero(gt->m_table, 0); a_get_b(gt->m_table, 2, b128, 0); lbit = 1; lbit <<= 63; for (i = 2; i < (1 << g_m); i <<= 1) { a_get_b(a128, 0, gt->m_table, 2 * (i >> 1)); two_x(a128); a_get_b(gt->m_table, 2 * i, a128, 0); if (gt->m_table[2 * (i >> 1)] & lbit) gt->m_table[(2 * i) + 1] ^= prim_poly; for (j = 0; j < i; j++) { gt->m_table[(2 * i) + (2 * j)] = gt->m_table[(2 * i)] ^ gt->m_table[(2 * j)]; gt->m_table[(2 * i) + (2 * j) + 1] = gt->m_table[(2 * i) + 1] ^ gt->m_table[(2 * j) + 1]; } } return; } void gf_w128_group_multiply(GFP gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { int i; /* index_r, index_m, total_m (if g_r > g_m) */ int i_r, i_m, t_m; int mask_m, mask_r; int g_m, g_r; uint64_t p_i[2], a[2]; gf_internal_t *scratch; gf_group_tables_t *gt; scratch = (gf_internal_t *) gf->scratch; gt = scratch->private; g_m = scratch->arg1; g_r = scratch->arg2; mask_m = (1 << g_m) - 1; mask_r = (1 << g_r) - 1; if (b128[0] != gt->m_table[2] || b128[1] != gt->m_table[3]) { gf_w128_group_m_init(gf, b128); } p_i[0] = 0; p_i[1] = 0; a[0] = a128[0]; a[1] = a128[1]; t_m = 0; i_r = 0; /* Top 64 bits */ for (i = ((GF_FIELD_WIDTH / 2) / g_m) - 1; i >= 0; i--) { i_m = (a[0] >> (i * g_m)) & mask_m; i_r ^= (p_i[0] >> (64 - g_m)) & mask_r; p_i[0] <<= g_m; p_i[0] ^= (p_i[1] >> (64-g_m)); p_i[1] <<= g_m; p_i[0] ^= gt->m_table[2 * i_m]; p_i[1] ^= gt->m_table[(2 * i_m) + 1]; t_m += g_m; if (t_m == g_r) { p_i[1] ^= gt->r_table[i_r]; t_m = 0; i_r = 0; } else { i_r <<= g_m; } } for (i = ((GF_FIELD_WIDTH / 2) / g_m) - 1; i >= 0; i--) { i_m = (a[1] >> (i * g_m)) & mask_m; i_r ^= (p_i[0] >> (64 - g_m)) & mask_r; p_i[0] <<= g_m; p_i[0] ^= (p_i[1] >> (64-g_m)); p_i[1] <<= g_m; p_i[0] ^= gt->m_table[2 * i_m]; p_i[1] ^= gt->m_table[(2 * i_m) + 1]; t_m += g_m; if (t_m == g_r) { p_i[1] ^= gt->r_table[i_r]; t_m = 0; i_r = 0; } else { i_r <<= g_m; } } c128[0] = p_i[0]; c128[1] = p_i[1]; } static void gf_w128_group_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { int i; int i_r, i_m, t_m; int mask_m, mask_r; int g_m, g_r; uint64_t p_i[2], a[2]; gf_internal_t *scratch; gf_group_tables_t *gt; gf_region_data rd; uint64_t *a128, *c128, *top; /* We only do this to check on alignment. */ gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); if (val[0] == 0) { if (val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val[1] == 1) { gf_multby_one(src, dest, bytes, xor); return; } } scratch = (gf_internal_t *) gf->scratch; gt = scratch->private; g_m = scratch->arg1; g_r = scratch->arg2; mask_m = (1 << g_m) - 1; mask_r = (1 << g_r) - 1; if (val[0] != gt->m_table[2] || val[1] != gt->m_table[3]) { gf_w128_group_m_init(gf, val); } a128 = (uint64_t *) src; c128 = (uint64_t *) dest; top = (uint64_t *) rd.d_top; while (c128 < top) { p_i[0] = 0; p_i[1] = 0; a[0] = a128[0]; a[1] = a128[1]; t_m = 0; i_r = 0; /* Top 64 bits */ for (i = ((GF_FIELD_WIDTH / 2) / g_m) - 1; i >= 0; i--) { i_m = (a[0] >> (i * g_m)) & mask_m; i_r ^= (p_i[0] >> (64 - g_m)) & mask_r; p_i[0] <<= g_m; p_i[0] ^= (p_i[1] >> (64-g_m)); p_i[1] <<= g_m; p_i[0] ^= gt->m_table[2 * i_m]; p_i[1] ^= gt->m_table[(2 * i_m) + 1]; t_m += g_m; if (t_m == g_r) { p_i[1] ^= gt->r_table[i_r]; t_m = 0; i_r = 0; } else { i_r <<= g_m; } } for (i = ((GF_FIELD_WIDTH / 2) / g_m) - 1; i >= 0; i--) { i_m = (a[1] >> (i * g_m)) & mask_m; i_r ^= (p_i[0] >> (64 - g_m)) & mask_r; p_i[0] <<= g_m; p_i[0] ^= (p_i[1] >> (64-g_m)); p_i[1] <<= g_m; p_i[0] ^= gt->m_table[2 * i_m]; p_i[1] ^= gt->m_table[(2 * i_m) + 1]; t_m += g_m; if (t_m == g_r) { p_i[1] ^= gt->r_table[i_r]; t_m = 0; i_r = 0; } else { i_r <<= g_m; } } if (xor) { c128[0] ^= p_i[0]; c128[1] ^= p_i[1]; } else { c128[0] = p_i[0]; c128[1] = p_i[1]; } a128 += 2; c128 += 2; } } /* a^-1 -> b */ void gf_w128_euclid(GFP gf, gf_val_128_t a128, gf_val_128_t b128) { uint64_t e_i[2], e_im1[2], e_ip1[2]; uint64_t d_i, d_im1, d_ip1; uint64_t y_i[2], y_im1[2], y_ip1[2]; uint64_t c_i[2]; uint64_t *b; uint64_t one = 1; /* This needs to return some sort of error (in b128?) */ if (a128[0] == 0 && a128[1] == 0) return; b = (uint64_t *) b128; e_im1[0] = 0; e_im1[1] = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i[0] = a128[0]; e_i[1] = a128[1]; d_im1 = 128; //Allen: I think d_i starts at 63 here, and checks each bit of a, starting at MSB, looking for the first nonzero bit //so d_i should be 0 if this half of a is all 0s, otherwise it should be the position from right of the first-from-left zero bit of this half of a. //BUT if d_i is 0 at end we won't know yet if the rightmost bit of this half is 1 or not for (d_i = (d_im1-1) % 64; ((one << d_i) & e_i[0]) == 0 && d_i > 0; d_i--) ; //Allen: this is testing just the first half of the stop condition above, so if it holds we know we did not find a nonzero bit yet if (!((one << d_i) & e_i[0])) { //Allen: this is doing the same thing on the other half of a. In other words, we're still searching for a nonzero bit of a. // but not bothering to test if d_i hits zero, which is fine because we've already tested for a=0. for (d_i = (d_im1-1) % 64; ((one << d_i) & e_i[1]) == 0; d_i--) ; } else { //Allen: if a 1 was found in more-significant half of a, make d_i the ACTUAL index of the first nonzero bit in the entire a. d_i += 64; } y_i[0] = 0; y_i[1] = 1; y_im1[0] = 0; y_im1[1] = 0; while (!(e_i[0] == 0 && e_i[1] == 1)) { e_ip1[0] = e_im1[0]; e_ip1[1] = e_im1[1]; d_ip1 = d_im1; c_i[0] = 0; c_i[1] = 0; while (d_ip1 >= d_i) { if ((d_ip1 - d_i) >= 64) { c_i[0] ^= (one << ((d_ip1 - d_i) - 64)); e_ip1[0] ^= (e_i[1] << ((d_ip1 - d_i) - 64)); } else { c_i[1] ^= (one << (d_ip1 - d_i)); e_ip1[0] ^= (e_i[0] << (d_ip1 - d_i)); if (d_ip1 - d_i > 0) e_ip1[0] ^= (e_i[1] >> (64 - (d_ip1 - d_i))); e_ip1[1] ^= (e_i[1] << (d_ip1 - d_i)); } d_ip1--; if (e_ip1[0] == 0 && e_ip1[1] == 0) { b[0] = 0; b[1] = 0; return; } while (d_ip1 >= 64 && (e_ip1[0] & (one << (d_ip1 - 64))) == 0) d_ip1--; while (d_ip1 < 64 && (e_ip1[1] & (one << d_ip1)) == 0) d_ip1--; } gf->multiply.w128(gf, c_i, y_i, y_ip1); y_ip1[0] ^= y_im1[0]; y_ip1[1] ^= y_im1[1]; y_im1[0] = y_i[0]; y_im1[1] = y_i[1]; y_i[0] = y_ip1[0]; y_i[1] = y_ip1[1]; e_im1[0] = e_i[0]; e_im1[1] = e_i[1]; d_im1 = d_i; e_i[0] = e_ip1[0]; e_i[1] = e_ip1[1]; d_i = d_ip1; } b[0] = y_i[0]; b[1] = y_i[1]; return; } void gf_w128_divide_from_inverse(GFP gf, gf_val_128_t a128, gf_val_128_t b128, gf_val_128_t c128) { uint64_t d[2]; gf->inverse.w128(gf, b128, d); gf->multiply.w128(gf, a128, d, c128); return; } void gf_w128_inverse_from_divide(GFP gf, gf_val_128_t a128, gf_val_128_t b128) { uint64_t one128[2]; one128[0] = 0; one128[1] = 1; gf->divide.w128(gf, one128, a128, b128); return; } static void gf_w128_composite_inverse(gf_t *gf, gf_val_128_t a, gf_val_128_t inv) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint64_t a0 = a[1]; uint64_t a1 = a[0]; uint64_t c0, c1, d, tmp; uint64_t a0inv, a1inv; if (a0 == 0) { a1inv = base_gf->inverse.w64(base_gf, a1); c0 = base_gf->multiply.w64(base_gf, a1inv, h->prim_poly); c1 = a1inv; } else if (a1 == 0) { c0 = base_gf->inverse.w64(base_gf, a0); c1 = 0; } else { a1inv = base_gf->inverse.w64(base_gf, a1); a0inv = base_gf->inverse.w64(base_gf, a0); d = base_gf->multiply.w64(base_gf, a1, a0inv); tmp = (base_gf->multiply.w64(base_gf, a1, a0inv) ^ base_gf->multiply.w64(base_gf, a0, a1inv) ^ h->prim_poly); tmp = base_gf->inverse.w64(base_gf, tmp); d = base_gf->multiply.w64(base_gf, d, tmp); c0 = base_gf->multiply.w64(base_gf, (d^1), a0inv); c1 = base_gf->multiply.w64(base_gf, d, a1inv); } inv[0] = c1; inv[1] = c0; } static void gf_w128_composite_multiply(gf_t *gf, gf_val_128_t a, gf_val_128_t b, gf_val_128_t rv) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint64_t b0 = b[1]; uint64_t b1 = b[0]; uint64_t a0 = a[1]; uint64_t a1 = a[0]; uint64_t a1b1; a1b1 = base_gf->multiply.w64(base_gf, a1, b1); rv[1] = (base_gf->multiply.w64(base_gf, a0, b0) ^ a1b1); rv[0] = base_gf->multiply.w64(base_gf, a1, b0) ^ base_gf->multiply.w64(base_gf, a0, b1) ^ base_gf->multiply.w64(base_gf, a1b1, h->prim_poly); } static void gf_w128_composite_multiply_region(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint64_t b0 = val[1]; uint64_t b1 = val[0]; uint64_t *s64, *d64; uint64_t *top; uint64_t a0, a1, a1b1; gf_region_data rd; if (val[0] == 0 && val[1] == 0) { gf_multby_zero(dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 8); s64 = rd.s_start; d64 = rd.d_start; top = rd.d_top; if (xor) { while (d64 < top) { a1 = s64[0]; a0 = s64[1]; a1b1 = base_gf->multiply.w64(base_gf, a1, b1); d64[1] ^= (base_gf->multiply.w64(base_gf, a0, b0) ^ a1b1); d64[0] ^= (base_gf->multiply.w64(base_gf, a1, b0) ^ base_gf->multiply.w64(base_gf, a0, b1) ^ base_gf->multiply.w64(base_gf, a1b1, h->prim_poly)); s64 += 2; d64 += 2; } } else { while (d64 < top) { a1 = s64[0]; a0 = s64[1]; a1b1 = base_gf->multiply.w64(base_gf, a1, b1); d64[1] = (base_gf->multiply.w64(base_gf, a0, b0) ^ a1b1); d64[0] = (base_gf->multiply.w64(base_gf, a1, b0) ^ base_gf->multiply.w64(base_gf, a0, b1) ^ base_gf->multiply.w64(base_gf, a1b1, h->prim_poly)); s64 += 2; d64 += 2; } } } static void gf_w128_composite_multiply_region_alt(gf_t *gf, void *src, void *dest, gf_val_128_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; gf_val_64_t val0 = val[1]; gf_val_64_t val1 = val[0]; uint8_t *slow, *shigh; uint8_t *dlow, *dhigh, *top; int sub_reg_size; gf_region_data rd; gf_set_region_data(&rd, gf, src, dest, bytes, 0, xor, 64); gf_w128_multiply_region_from_single(gf, src, dest, val, ((char*)rd.s_start-(char*)src), xor); slow = (uint8_t *) rd.s_start; dlow = (uint8_t *) rd.d_start; top = (uint8_t*) rd.d_top; sub_reg_size = (top - dlow)/2; shigh = slow + sub_reg_size; dhigh = dlow + sub_reg_size; base_gf->multiply_region.w64(base_gf, slow, dlow, val0, sub_reg_size, xor); base_gf->multiply_region.w64(base_gf, shigh, dlow, val1, sub_reg_size, 1); base_gf->multiply_region.w64(base_gf, slow, dhigh, val1, sub_reg_size, xor); base_gf->multiply_region.w64(base_gf, shigh, dhigh, val0, sub_reg_size, 1); base_gf->multiply_region.w64(base_gf, shigh, dhigh, base_gf->multiply.w64(base_gf, h->prim_poly, val1 ), sub_reg_size, 1); gf_w128_multiply_region_from_single(gf, rd.s_top, rd.d_top, val, ((char*)src+bytes)-(char*)rd.s_top, xor); } static int gf_w128_composite_init(gf_t *gf) { gf_internal_t *h = (gf_internal_t *) gf->scratch; if (h->region_type & GF_REGION_ALTMAP) { gf->multiply_region.w128 = gf_w128_composite_multiply_region_alt; } else { gf->multiply_region.w128 = gf_w128_composite_multiply_region; } gf->multiply.w128 = gf_w128_composite_multiply; gf->divide.w128 = gf_w128_divide_from_inverse; gf->inverse.w128 = gf_w128_composite_inverse; return 1; } static int gf_w128_cfm_init(gf_t *gf) { #if defined(INTEL_SSE4_PCLMUL) gf->inverse.w128 = gf_w128_euclid; gf->multiply.w128 = gf_w128_clm_multiply; gf->multiply_region.w128 = gf_w128_clm_multiply_region_from_single; return 1; #endif return 0; } static int gf_w128_shift_init(gf_t *gf) { gf->multiply.w128 = gf_w128_shift_multiply; gf->inverse.w128 = gf_w128_euclid; gf->multiply_region.w128 = gf_w128_multiply_region_from_single; return 1; } static int gf_w128_bytwo_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if (h->mult_type == GF_MULT_BYTWO_p) { gf->multiply.w128 = gf_w128_bytwo_p_multiply; /*gf->multiply.w128 = gf_w128_sse_bytwo_p_multiply;*/ /* John: the sse function is slower.*/ } else { gf->multiply.w128 = gf_w128_bytwo_b_multiply; /*gf->multiply.w128 = gf_w128_sse_bytwo_b_multiply; Ben: This sse function is also slower. */ } gf->inverse.w128 = gf_w128_euclid; gf->multiply_region.w128 = gf_w128_bytwo_b_multiply_region; return 1; } /* * Because the prim poly is only 8 bits and we are limiting g_r to 16, I do not need the high 64 * bits in all of these numbers. */ static void gf_w128_group_r_init(gf_t *gf) { int i, j; int g_r; uint64_t pp; gf_internal_t *scratch; gf_group_tables_t *gt; scratch = (gf_internal_t *) gf->scratch; gt = scratch->private; g_r = scratch->arg2; pp = scratch->prim_poly; gt->r_table[0] = 0; for (i = 1; i < (1 << g_r); i++) { gt->r_table[i] = 0; for (j = 0; j < g_r; j++) { if (i & (1 << j)) { gt->r_table[i] ^= (pp << j); } } } return; } static int gf_w128_split_init(gf_t *gf) { struct gf_w128_split_4_128_data *sd4; struct gf_w128_split_8_128_data *sd8; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; gf->multiply.w128 = gf_w128_bytwo_p_multiply; #if defined(INTEL_SSE4_PCLMUL) if (!(h->region_type & GF_REGION_NOSSE)){ gf->multiply.w128 = gf_w128_clm_multiply; } #endif gf->inverse.w128 = gf_w128_euclid; if ((h->arg1 != 4 && h->arg2 != 4) || h->mult_type == GF_MULT_DEFAULT) { sd8 = (struct gf_w128_split_8_128_data *) h->private; sd8->last_value[0] = 0; sd8->last_value[1] = 0; gf->multiply_region.w128 = gf_w128_split_8_128_multiply_region; } else { sd4 = (struct gf_w128_split_4_128_data *) h->private; sd4->last_value[0] = 0; sd4->last_value[1] = 0; if((h->region_type & GF_REGION_ALTMAP)) { #ifdef INTEL_SSE4 if(!(h->region_type & GF_REGION_NOSSE)) gf->multiply_region.w128 = gf_w128_split_4_128_sse_altmap_multiply_region; else return 0; #else return 0; #endif } else { #ifdef INTEL_SSE4 if(!(h->region_type & GF_REGION_NOSSE)) gf->multiply_region.w128 = gf_w128_split_4_128_sse_multiply_region; else gf->multiply_region.w128 = gf_w128_split_4_128_multiply_region; #else gf->multiply_region.w128 = gf_w128_split_4_128_multiply_region; #endif } } return 1; } static int gf_w128_group_init(gf_t *gf) { gf_internal_t *scratch; gf_group_tables_t *gt; int g_r, size_r; scratch = (gf_internal_t *) gf->scratch; gt = scratch->private; g_r = scratch->arg2; size_r = (1 << g_r); gt->r_table = (gf_val_128_t)((char*)scratch->private + (2 * sizeof(uint64_t *))); gt->m_table = gt->r_table + size_r; gt->m_table[2] = 0; gt->m_table[3] = 0; gf->multiply.w128 = gf_w128_group_multiply; gf->inverse.w128 = gf_w128_euclid; gf->multiply_region.w128 = gf_w128_group_multiply_region; gf_w128_group_r_init(gf); return 1; } void gf_w128_extract_word(gf_t *gf, void *start, int bytes, int index, gf_val_128_t rv) { gf_val_128_t s; s = (gf_val_128_t) start; s += (index * 2); memcpy(rv, s, 16); } static void gf_w128_split_extract_word(gf_t *gf, void *start, int bytes, int index, gf_val_128_t rv) { int i, blocks; uint64_t *r64, tmp; uint8_t *r8; gf_region_data rd; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 256); r64 = (uint64_t *) start; if ((r64 + index*2 < (uint64_t *) rd.d_start) || (r64 + index*2 >= (uint64_t *) rd.d_top)) { memcpy(rv, r64+(index*2), 16); return; } index -= (((uint64_t *) rd.d_start) - r64)/2; r64 = (uint64_t *) rd.d_start; blocks = index/16; r64 += (blocks*32); index %= 16; r8 = (uint8_t *) r64; r8 += index; rv[0] = 0; rv[1] = 0; for (i = 0; i < 8; i++) { tmp = *r8; rv[1] |= (tmp << (i*8)); r8 += 16; } for (i = 0; i < 8; i++) { tmp = *r8; rv[0] |= (tmp << (i*8)); r8 += 16; } return; } static void gf_w128_composite_extract_word(gf_t *gf, void *start, int bytes, int index, gf_val_128_t rv) { int sub_size; gf_internal_t *h; uint8_t *r8, *top; uint64_t *r64; gf_region_data rd; h = (gf_internal_t *) gf->scratch; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 64); r64 = (uint64_t *) start; if ((r64 + index*2 < (uint64_t *) rd.d_start) || (r64 + index*2 >= (uint64_t *) rd.d_top)) { memcpy(rv, r64+(index*2), 16); return; } index -= (((uint64_t *) rd.d_start) - r64)/2; r8 = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_size = (top-r8)/2; rv[1] = h->base_gf->extract_word.w64(h->base_gf, r8, sub_size, index); rv[0] = h->base_gf->extract_word.w64(h->base_gf, r8+sub_size, sub_size, index); return; } int gf_w128_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2) { int size_m, size_r; if (divide_type==GF_DIVIDE_MATRIX) return 0; switch(mult_type) { case GF_MULT_CARRY_FREE: return sizeof(gf_internal_t); break; case GF_MULT_SHIFT: return sizeof(gf_internal_t); break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: return sizeof(gf_internal_t); break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if ((arg1 == 4 && arg2 == 128) || (arg1 == 128 && arg2 == 4)) { return sizeof(gf_internal_t) + sizeof(struct gf_w128_split_4_128_data) + 64; } else if ((arg1 == 8 && arg2 == 128) || (arg1 == 128 && arg2 == 8) || mult_type == GF_MULT_DEFAULT) { return sizeof(gf_internal_t) + sizeof(struct gf_w128_split_8_128_data) + 64; } return 0; break; case GF_MULT_GROUP: /* JSP We've already error checked the arguments. */ size_m = (1 << arg1) * 2 * sizeof(uint64_t); size_r = (1 << arg2) * 2 * sizeof(uint64_t); /* * two pointers prepend the table data for structure * because the tables are of dynamic size */ return sizeof(gf_internal_t) + size_m + size_r + 4 * sizeof(uint64_t *); break; case GF_MULT_COMPOSITE: if (arg1 == 2) { return sizeof(gf_internal_t) + 4; } else { return 0; } break; default: return 0; } } int gf_w128_init(gf_t *gf) { gf_internal_t *h; int no_default_flag = 0; h = (gf_internal_t *) gf->scratch; /* Allen: set default primitive polynomial / irreducible polynomial if needed */ if (h->prim_poly == 0) { if (h->mult_type == GF_MULT_COMPOSITE) { h->prim_poly = gf_composite_get_default_poly(h->base_gf); if (h->prim_poly == 0) return 0; /* This shouldn't happen */ } else { h->prim_poly = 0x87; /* Omitting the leftmost 1 as in w=32 */ } if (no_default_flag == 1) { fprintf(stderr,"Code contains no default irreducible polynomial for given base field\n"); return 0; } } gf->multiply.w128 = NULL; gf->divide.w128 = NULL; gf->inverse.w128 = NULL; gf->multiply_region.w128 = NULL; switch(h->mult_type) { case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: if (gf_w128_bytwo_init(gf) == 0) return 0; break; case GF_MULT_CARRY_FREE: if (gf_w128_cfm_init(gf) == 0) return 0; break; case GF_MULT_SHIFT: if (gf_w128_shift_init(gf) == 0) return 0; break; case GF_MULT_GROUP: if (gf_w128_group_init(gf) == 0) return 0; break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if (gf_w128_split_init(gf) == 0) return 0; break; case GF_MULT_COMPOSITE: if (gf_w128_composite_init(gf) == 0) return 0; break; default: return 0; } /* Ben: Used to be h->region_type == GF_REGION_ALTMAP, but failed since there are multiple flags in h->region_type */ if (h->mult_type == GF_MULT_SPLIT_TABLE && (h->region_type & GF_REGION_ALTMAP)) { gf->extract_word.w128 = gf_w128_split_extract_word; } else if (h->mult_type == GF_MULT_COMPOSITE && h->region_type == GF_REGION_ALTMAP) { gf->extract_word.w128 = gf_w128_composite_extract_word; } else { gf->extract_word.w128 = gf_w128_extract_word; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w128 = gf_w128_divide_from_inverse; } if (gf->inverse.w128 != NULL && gf->divide.w128 == NULL) { gf->divide.w128 = gf_w128_divide_from_inverse; } if (gf->inverse.w128 == NULL && gf->divide.w128 != NULL) { gf->inverse.w128 = gf_w128_inverse_from_divide; } return 1; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_w8.c0000664000175100017510000020352112623076752026033 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_w8.c * * Routines for 8-bit Galois fields */ #include "gf_int.h" #include #include #define GF_FIELD_WIDTH (8) #define GF_FIELD_SIZE (1 << GF_FIELD_WIDTH) #define GF_HALF_SIZE (1 << (GF_FIELD_WIDTH/2)) #define GF_MULT_GROUP_SIZE GF_FIELD_SIZE-1 #define GF_BASE_FIELD_WIDTH (4) #define GF_BASE_FIELD_SIZE (1 << GF_BASE_FIELD_WIDTH) struct gf_w8_logtable_data { uint8_t log_tbl[GF_FIELD_SIZE]; uint8_t antilog_tbl[GF_FIELD_SIZE * 2]; uint8_t inv_tbl[GF_FIELD_SIZE]; }; struct gf_w8_logzero_table_data { short log_tbl[GF_FIELD_SIZE]; /* Make this signed, so that we can divide easily */ uint8_t antilog_tbl[512+512+1]; uint8_t *div_tbl; uint8_t *inv_tbl; }; struct gf_w8_logzero_small_table_data { short log_tbl[GF_FIELD_SIZE]; /* Make this signed, so that we can divide easily */ uint8_t antilog_tbl[255*3]; uint8_t inv_tbl[GF_FIELD_SIZE]; uint8_t *div_tbl; }; struct gf_w8_composite_data { uint8_t *mult_table; }; /* Don't change the order of these relative to gf_w8_half_table_data */ struct gf_w8_default_data { uint8_t high[GF_FIELD_SIZE][GF_HALF_SIZE]; uint8_t low[GF_FIELD_SIZE][GF_HALF_SIZE]; uint8_t divtable[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint8_t multtable[GF_FIELD_SIZE][GF_FIELD_SIZE]; }; struct gf_w8_half_table_data { uint8_t high[GF_FIELD_SIZE][GF_HALF_SIZE]; uint8_t low[GF_FIELD_SIZE][GF_HALF_SIZE]; }; struct gf_w8_single_table_data { uint8_t divtable[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint8_t multtable[GF_FIELD_SIZE][GF_FIELD_SIZE]; }; struct gf_w8_double_table_data { uint8_t div[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint16_t mult[GF_FIELD_SIZE][GF_FIELD_SIZE*GF_FIELD_SIZE]; }; struct gf_w8_double_table_lazy_data { uint8_t div[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint8_t smult[GF_FIELD_SIZE][GF_FIELD_SIZE]; uint16_t mult[GF_FIELD_SIZE*GF_FIELD_SIZE]; }; struct gf_w4_logtable_data { uint8_t log_tbl[GF_BASE_FIELD_SIZE]; uint8_t antilog_tbl[GF_BASE_FIELD_SIZE * 2]; uint8_t *antilog_tbl_div; }; struct gf_w4_single_table_data { uint8_t div[GF_BASE_FIELD_SIZE][GF_BASE_FIELD_SIZE]; uint8_t mult[GF_BASE_FIELD_SIZE][GF_BASE_FIELD_SIZE]; }; struct gf_w8_bytwo_data { uint64_t prim_poly; uint64_t mask1; uint64_t mask2; }; #define AB2(ip, am1 ,am2, b, t1, t2) {\ t1 = (b << 1) & am1;\ t2 = b & am2; \ t2 = ((t2 << 1) - (t2 >> (GF_FIELD_WIDTH-1))); \ b = (t1 ^ (t2 & ip));} #define SSE_AB2(pp, m1 ,m2, va, t1, t2) {\ t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); \ t2 = _mm_and_si128(va, m2); \ t2 = _mm_sub_epi64 (_mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); \ va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } #define MM_PRINT(s, r) { uint8_t blah[16], ii; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (ii = 0; ii < 16; ii += 2) printf(" %02x %02x", blah[15-ii], blah[14-ii]); printf("\n"); } static inline uint32_t gf_w8_inverse_from_divide (gf_t *gf, uint32_t a) { return gf->divide.w32(gf, 1, a); } static inline uint32_t gf_w8_divide_from_inverse (gf_t *gf, uint32_t a, uint32_t b) { b = gf->inverse.w32(gf, b); return gf->multiply.w32(gf, a, b); } static inline uint32_t gf_w8_euclid (gf_t *gf, uint32_t b) { uint32_t e_i, e_im1, e_ip1; uint32_t d_i, d_im1, d_ip1; uint32_t y_i, y_im1, y_ip1; uint32_t c_i; if (b == 0) return -1; e_im1 = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i = b; d_im1 = 8; for (d_i = d_im1; ((1 << d_i) & e_i) == 0; d_i--) ; y_i = 1; y_im1 = 0; while (e_i != 1) { e_ip1 = e_im1; d_ip1 = d_im1; c_i = 0; while (d_ip1 >= d_i) { c_i ^= (1 << (d_ip1 - d_i)); e_ip1 ^= (e_i << (d_ip1 - d_i)); if (e_ip1 == 0) return 0; while ((e_ip1 & (1 << d_ip1)) == 0) d_ip1--; } y_ip1 = y_im1 ^ gf->multiply.w32(gf, c_i, y_i); y_im1 = y_i; y_i = y_ip1; e_im1 = e_i; d_im1 = d_i; e_i = e_ip1; d_i = d_ip1; } return y_i; } static gf_val_32_t gf_w8_extract_word(gf_t *gf, void *start, int bytes, int index) { uint8_t *r8; r8 = (uint8_t *) start; return r8[index]; } static gf_val_32_t gf_w8_composite_extract_word(gf_t *gf, void *start, int bytes, int index) { int sub_size; gf_internal_t *h; uint8_t *r8, *top; uint8_t a, b; gf_region_data rd; h = (gf_internal_t *) gf->scratch; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 32); r8 = (uint8_t *) start; if (r8 + index < (uint8_t *) rd.d_start) return r8[index]; if (r8 + index >= (uint8_t *) rd.d_top) return r8[index]; index -= (((uint8_t *) rd.d_start) - r8); r8 = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_size = (top-r8)/2; a = h->base_gf->extract_word.w32(h->base_gf, r8, sub_size, index); b = h->base_gf->extract_word.w32(h->base_gf, r8+sub_size, sub_size, index); return (a | (b << 4)); } static inline uint32_t gf_w8_matrix (gf_t *gf, uint32_t b) { return gf_bitmatrix_inverse(b, 8, ((gf_internal_t *) (gf->scratch))->prim_poly); } static inline gf_val_32_t gf_w8_clm_multiply_2 (gf_t *gf, gf_val_32_t a8, gf_val_32_t b8) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a8, 0); b = _mm_insert_epi32 (a, b8, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); /* Ben: Do prim_poly reduction twice. We are guaranteed that we will only have to do the reduction at most twice, because (w-2)/z == 2. Where z is equal to the number of zeros after the leading 1 _mm_clmulepi64_si128 is the carryless multiply operation. Here _mm_srli_si128 shifts the result to the right by 1 byte. This allows us to multiply the prim_poly by the leading bits of the result. We then xor the result of that operation back with the result.*/ w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w8_clm_multiply_3 (gf_t *gf, gf_val_32_t a8, gf_val_32_t b8) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a8, 0); b = _mm_insert_epi32 (a, b8, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w8_clm_multiply_4 (gf_t *gf, gf_val_32_t a8, gf_val_32_t b8) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a8, 0); b = _mm_insert_epi32 (a, b8, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static void gf_w8_multiply_region_from_single(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint8_t *s8; uint8_t *d8; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 1); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; if (xor) { while (d8 < ((uint8_t *) rd.d_top)) { *d8 ^= gf->multiply.w32(gf, val, *s8); d8++; s8++; } } else { while (d8 < ((uint8_t *) rd.d_top)) { *d8 = gf->multiply.w32(gf, val, *s8); d8++; s8++; } } gf_do_final_region_alignment(&rd); } #if defined(INTEL_SSE4_PCLMUL) static void gf_w8_clm_multiply_region_from_single_2(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint8_t *s8; uint8_t *d8; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 1); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; if (xor) { while (d8 < ((uint8_t *) rd.d_top)) { b = _mm_insert_epi32 (a, (gf_val_32_t)(*s8), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); *d8 ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); d8++; s8++; } } else { while (d8 < ((uint8_t *) rd.d_top)) { b = _mm_insert_epi32 (a, (gf_val_32_t)(*s8), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); *d8 = ((gf_val_32_t)_mm_extract_epi32(result, 0)); d8++; s8++; } } gf_do_final_region_alignment(&rd); } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w8_clm_multiply_region_from_single_3(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint8_t *s8; uint8_t *d8; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 1); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; if (xor) { while (d8 < ((uint8_t *) rd.d_top)) { b = _mm_insert_epi32 (a, (gf_val_32_t)(*s8), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); *d8 ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); d8++; s8++; } } else { while (d8 < ((uint8_t *) rd.d_top)) { b = _mm_insert_epi32 (a, (gf_val_32_t)(*s8), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); *d8 = ((gf_val_32_t)_mm_extract_epi32(result, 0)); d8++; s8++; } } gf_do_final_region_alignment(&rd); } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w8_clm_multiply_region_from_single_4(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint8_t *s8; uint8_t *d8; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 1); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; if (xor) { while (d8 < ((uint8_t *) rd.d_top)) { b = _mm_insert_epi32 (a, (gf_val_32_t)(*s8), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); *d8 ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); d8++; s8++; } } else { while (d8 < ((uint8_t *) rd.d_top)) { b = _mm_insert_epi32 (a, (gf_val_32_t)(*s8), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 1), 0); result = _mm_xor_si128 (result, w); *d8 = ((gf_val_32_t)_mm_extract_epi32(result, 0)); d8++; s8++; } } gf_do_final_region_alignment(&rd); } #endif /* ------------------------------------------------------------ IMPLEMENTATION: SHIFT: JSP: The world's dumbest multiplication algorithm. I only include it for completeness. It does have the feature that it requires no extra memory. */ static inline uint32_t gf_w8_shift_multiply (gf_t *gf, uint32_t a8, uint32_t b8) { uint16_t product, i, pp, a, b; gf_internal_t *h; a = a8; b = b8; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; product = 0; for (i = 0; i < GF_FIELD_WIDTH; i++) { if (a & (1 << i)) product ^= (b << i); } for (i = (GF_FIELD_WIDTH*2-2); i >= GF_FIELD_WIDTH; i--) { if (product & (1 << i)) product ^= (pp << (i-GF_FIELD_WIDTH)); } return product; } static int gf_w8_cfm_init(gf_t *gf) { #if defined(INTEL_SSE4_PCLMUL) gf_internal_t *h; h = (gf_internal_t *) gf->scratch; if ((0xe0 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w8_clm_multiply_2; gf->multiply_region.w32 = gf_w8_clm_multiply_region_from_single_2; }else if ((0xc0 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w8_clm_multiply_3; gf->multiply_region.w32 = gf_w8_clm_multiply_region_from_single_3; }else if ((0x80 & h->prim_poly) == 0){ gf->multiply.w32 = gf_w8_clm_multiply_4; gf->multiply_region.w32 = gf_w8_clm_multiply_region_from_single_4; }else{ return 0; } return 1; #endif return 0; } static int gf_w8_shift_init(gf_t *gf) { gf->multiply.w32 = gf_w8_shift_multiply; /* The others will be set automatically */ return 1; } /* ------------------------------------------------------------ IMPLEMENTATION: LOG_TABLE: JSP: Kevin wrote this, and I'm converting it to my structure. */ static inline uint32_t gf_w8_logzero_multiply (gf_t *gf, uint32_t a, uint32_t b) { struct gf_w8_logzero_table_data *ltd; ltd = (struct gf_w8_logzero_table_data *) ((gf_internal_t *) gf->scratch)->private; return ltd->antilog_tbl[ltd->log_tbl[a] + ltd->log_tbl[b]]; } static inline uint32_t gf_w8_logzero_divide (gf_t *gf, uint32_t a, uint32_t b) { struct gf_w8_logzero_table_data *ltd; ltd = (struct gf_w8_logzero_table_data *) ((gf_internal_t *) gf->scratch)->private; return ltd->div_tbl[ltd->log_tbl[a] - ltd->log_tbl[b]]; } static inline uint32_t gf_w8_logzero_small_multiply (gf_t *gf, uint32_t a, uint32_t b) { struct gf_w8_logzero_small_table_data *std; std = (struct gf_w8_logzero_small_table_data *) ((gf_internal_t *) gf->scratch)->private; if (b == 0) return 0; return std->antilog_tbl[std->log_tbl[a] + std->log_tbl[b]]; } static inline uint32_t gf_w8_logzero_small_divide (gf_t *gf, uint32_t a, uint32_t b) { struct gf_w8_logzero_small_table_data *std; std = (struct gf_w8_logzero_small_table_data *) ((gf_internal_t *) gf->scratch)->private; return std->div_tbl[std->log_tbl[a] - std->log_tbl[b]]; } static inline uint32_t gf_w8_log_multiply (gf_t *gf, uint32_t a, uint32_t b) { struct gf_w8_logtable_data *ltd; ltd = (struct gf_w8_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return (a == 0 || b == 0) ? 0 : ltd->antilog_tbl[(unsigned)(ltd->log_tbl[a] + ltd->log_tbl[b])]; } static inline uint32_t gf_w8_log_divide (gf_t *gf, uint32_t a, uint32_t b) { int log_sum = 0; struct gf_w8_logtable_data *ltd; if (a == 0 || b == 0) return 0; ltd = (struct gf_w8_logtable_data *) ((gf_internal_t *) gf->scratch)->private; log_sum = ltd->log_tbl[a] - ltd->log_tbl[b] + (GF_MULT_GROUP_SIZE); return (ltd->antilog_tbl[log_sum]); } static uint32_t gf_w8_log_inverse (gf_t *gf, uint32_t a) { struct gf_w8_logtable_data *ltd; ltd = (struct gf_w8_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return (ltd->inv_tbl[a]); } static uint32_t gf_w8_logzero_inverse (gf_t *gf, uint32_t a) { struct gf_w8_logzero_table_data *ltd; ltd = (struct gf_w8_logzero_table_data *) ((gf_internal_t *) gf->scratch)->private; return (ltd->inv_tbl[a]); } static uint32_t gf_w8_logzero_small_inverse (gf_t *gf, uint32_t a) { struct gf_w8_logzero_small_table_data *std; std = (struct gf_w8_logzero_small_table_data *) ((gf_internal_t *) gf->scratch)->private; return (std->inv_tbl[a]); } static void gf_w8_log_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { int i; uint8_t lv; uint8_t *s8, *d8; struct gf_w8_logtable_data *ltd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } ltd = (struct gf_w8_logtable_data *) ((gf_internal_t *) gf->scratch)->private; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; lv = ltd->log_tbl[val]; if (xor) { for (i = 0; i < bytes; i++) { d8[i] ^= (s8[i] == 0 ? 0 : ltd->antilog_tbl[lv + ltd->log_tbl[s8[i]]]); } } else { for (i = 0; i < bytes; i++) { d8[i] = (s8[i] == 0 ? 0 : ltd->antilog_tbl[lv + ltd->log_tbl[s8[i]]]); } } } static void gf_w8_logzero_multiply_region(gf_t *gf, void *src, void *dest, uint32_t val, int bytes, int xor) { int i; uint8_t lv; uint8_t *s8, *d8; struct gf_w8_logzero_table_data *ltd; struct gf_w8_logzero_small_table_data *std; short *log; uint8_t *alt; gf_internal_t *h; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) gf->scratch; if (h->arg1 == 1) { std = (struct gf_w8_logzero_small_table_data *) h->private; log = std->log_tbl; alt = std->antilog_tbl; } else { ltd = (struct gf_w8_logzero_table_data *) h->private; log = ltd->log_tbl; alt = ltd->antilog_tbl; } s8 = (uint8_t *) src; d8 = (uint8_t *) dest; lv = log[val]; if (xor) { for (i = 0; i < bytes; i++) { d8[i] ^= (alt[lv + log[s8[i]]]); } } else { for (i = 0; i < bytes; i++) { d8[i] = (alt[lv + log[s8[i]]]); } } } static int gf_w8_log_init(gf_t *gf) { gf_internal_t *h; struct gf_w8_logtable_data *ltd = NULL; struct gf_w8_logzero_table_data *ztd = NULL; struct gf_w8_logzero_small_table_data *std = NULL; uint8_t *alt; uint8_t *inv; int i, b; int check = 0; h = (gf_internal_t *) gf->scratch; if (h->mult_type == GF_MULT_LOG_TABLE) { ltd = h->private; alt = ltd->antilog_tbl; inv = ltd->inv_tbl; } else if (h->mult_type == GF_MULT_LOG_ZERO) { std = h->private; alt = std->antilog_tbl; std->div_tbl = (alt + 255); inv = std->inv_tbl; } else { ztd = h->private; alt = ztd->antilog_tbl; ztd->inv_tbl = (alt + 512 + 256); ztd->div_tbl = (alt + 255); inv = ztd->inv_tbl; } for (i = 0; i < GF_MULT_GROUP_SIZE+1; i++) { if (h->mult_type == GF_MULT_LOG_TABLE) ltd->log_tbl[i] = 0; else if (h->mult_type == GF_MULT_LOG_ZERO) std->log_tbl[i] = 0; else ztd->log_tbl[i] = 0; } if (h->mult_type == GF_MULT_LOG_TABLE) { ltd->log_tbl[0] = 0; } else if (h->mult_type == GF_MULT_LOG_ZERO) { std->log_tbl[0] = 510; } else { ztd->log_tbl[0] = 512; } b = 1; for (i = 0; i < GF_MULT_GROUP_SIZE; i++) { if (h->mult_type == GF_MULT_LOG_TABLE) { if (ltd->log_tbl[b] != 0) check = 1; ltd->log_tbl[b] = i; } else if (h->mult_type == GF_MULT_LOG_ZERO) { if (std->log_tbl[b] != 0) check = 1; std->log_tbl[b] = i; } else { if (ztd->log_tbl[b] != 0) check = 1; ztd->log_tbl[b] = i; } alt[i] = b; alt[i+GF_MULT_GROUP_SIZE] = b; b <<= 1; if (b & GF_FIELD_SIZE) { b = b ^ h->prim_poly; } } if (check) { _gf_errno = GF_E_LOGPOLY; return 0; } if (h->mult_type == GF_MULT_LOG_ZERO) bzero(alt+510, 255); if (h->mult_type == GF_MULT_LOG_ZERO_EXT) { bzero(alt+512, 255); alt[512+512] = 0; } inv[0] = 0; /* Not really, but we need to fill it with something */ i = 1; b = GF_MULT_GROUP_SIZE; do { inv[i] = alt[b]; i <<= 1; if (i & (1 << 8)) i ^= h->prim_poly; b--; } while (i != 1); if (h->mult_type == GF_MULT_LOG_TABLE) { gf->inverse.w32 = gf_w8_log_inverse; gf->divide.w32 = gf_w8_log_divide; gf->multiply.w32 = gf_w8_log_multiply; gf->multiply_region.w32 = gf_w8_log_multiply_region; } else if (h->mult_type == GF_MULT_LOG_ZERO) { gf->inverse.w32 = gf_w8_logzero_small_inverse; gf->divide.w32 = gf_w8_logzero_small_divide; gf->multiply.w32 = gf_w8_logzero_small_multiply; gf->multiply_region.w32 = gf_w8_logzero_multiply_region; } else { gf->inverse.w32 = gf_w8_logzero_inverse; gf->divide.w32 = gf_w8_logzero_divide; gf->multiply.w32 = gf_w8_logzero_multiply; gf->multiply_region.w32 = gf_w8_logzero_multiply_region; } return 1; } /* ------------------------------------------------------------ IMPLEMENTATION: FULL_TABLE: JSP: Kevin wrote this, and I'm converting it to my structure. */ static gf_val_32_t gf_w8_table_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_single_table_data *ftd; ftd = (struct gf_w8_single_table_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->multtable[a][b]); } static gf_val_32_t gf_w8_table_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_single_table_data *ftd; ftd = (struct gf_w8_single_table_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->divtable[a][b]); } static gf_val_32_t gf_w8_default_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_default_data *ftd; ftd = (struct gf_w8_default_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->multtable[a][b]); } #ifdef INTEL_SSSE3 static gf_val_32_t gf_w8_default_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_default_data *ftd; ftd = (struct gf_w8_default_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->divtable[a][b]); } #endif static gf_val_32_t gf_w8_double_table_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_double_table_data *ftd; ftd = (struct gf_w8_double_table_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->mult[a][b]); } static gf_val_32_t gf_w8_double_table_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_double_table_data *ftd; ftd = (struct gf_w8_double_table_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->div[a][b]); } static void gf_w8_double_table_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint16_t *base; uint32_t b, c, vc, vb; gf_internal_t *h; struct gf_w8_double_table_data *dtd; struct gf_w8_double_table_lazy_data *ltd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } h = (gf_internal_t *) (gf->scratch); if (h->region_type & GF_REGION_LAZY) { ltd = (struct gf_w8_double_table_lazy_data *) h->private; base = ltd->mult; for (b = 0; b < GF_FIELD_SIZE; b++) { vb = (ltd->smult[val][b] << 8); for (c = 0; c < GF_FIELD_SIZE; c++) { vc = ltd->smult[val][c]; base[(b << 8)| c] = (vb | vc); } } } else { dtd = (struct gf_w8_double_table_data *) h->private; base = &(dtd->mult[val][0]); } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); gf_two_byte_region_table_multiply(&rd, base); gf_do_final_region_alignment(&rd); } static gf_val_32_t gf_w8_double_table_lazy_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_double_table_lazy_data *ftd; ftd = (struct gf_w8_double_table_lazy_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->smult[a][b]); } static gf_val_32_t gf_w8_double_table_lazy_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_double_table_lazy_data *ftd; ftd = (struct gf_w8_double_table_lazy_data *) ((gf_internal_t *) gf->scratch)->private; return (ftd->div[a][b]); } static void gf_w8_table_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8; struct gf_w8_single_table_data *ftd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } ftd = (struct gf_w8_single_table_data *) ((gf_internal_t *) gf->scratch)->private; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; if (xor) { for (i = 0; i < bytes; i++) { d8[i] ^= ftd->multtable[s8[i]][val]; } } else { for (i = 0; i < bytes; i++) { d8[i] = ftd->multtable[s8[i]][val]; } } } #ifdef INTEL_SSSE3 static void gf_w8_split_multiply_region_sse(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint8_t *bh, *bl, *sptr, *dptr; __m128i loset, t1, r, va, mth, mtl; struct gf_w8_half_table_data *htd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } htd = (struct gf_w8_half_table_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); bh = (uint8_t *) htd->high; bh += (val << 4); bl = (uint8_t *) htd->low; bl += (val << 4); sptr = rd.s_start; dptr = rd.d_start; mth = _mm_loadu_si128 ((__m128i *)(bh)); mtl = _mm_loadu_si128 ((__m128i *)(bl)); loset = _mm_set1_epi8 (0x0f); if (xor) { while (sptr < (uint8_t *) rd.s_top) { va = _mm_load_si128 ((__m128i *)(sptr)); t1 = _mm_and_si128 (loset, va); r = _mm_shuffle_epi8 (mtl, t1); va = _mm_srli_epi64 (va, 4); t1 = _mm_and_si128 (loset, va); r = _mm_xor_si128 (r, _mm_shuffle_epi8 (mth, t1)); va = _mm_load_si128 ((__m128i *)(dptr)); r = _mm_xor_si128 (r, va); _mm_store_si128 ((__m128i *)(dptr), r); dptr += 16; sptr += 16; } } else { while (sptr < (uint8_t *) rd.s_top) { va = _mm_load_si128 ((__m128i *)(sptr)); t1 = _mm_and_si128 (loset, va); r = _mm_shuffle_epi8 (mtl, t1); va = _mm_srli_epi64 (va, 4); t1 = _mm_and_si128 (loset, va); r = _mm_xor_si128 (r, _mm_shuffle_epi8 (mth, t1)); _mm_store_si128 ((__m128i *)(dptr), r); dptr += 16; sptr += 16; } } gf_do_final_region_alignment(&rd); } #endif /* ------------------------------------------------------------ IMPLEMENTATION: FULL_TABLE: */ static gf_val_32_t gf_w8_split_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w8_half_table_data *htd; htd = (struct gf_w8_half_table_data *) ((gf_internal_t *) gf->scratch)->private; return htd->high[b][a>>4] ^ htd->low[b][a&0xf]; } static void gf_w8_split_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8; struct gf_w8_half_table_data *htd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } htd = (struct gf_w8_half_table_data *) ((gf_internal_t *) gf->scratch)->private; s8 = (uint8_t *) src; d8 = (uint8_t *) dest; if (xor) { for (i = 0; i < bytes; i++) { d8[i] ^= (htd->high[val][s8[i]>>4] ^ htd->low[val][s8[i]&0xf]); } } else { for (i = 0; i < bytes; i++) { d8[i] = (htd->high[val][s8[i]>>4] ^ htd->low[val][s8[i]&0xf]); } } } static int gf_w8_split_init(gf_t *gf) { gf_internal_t *h; struct gf_w8_half_table_data *htd; int a, b; h = (gf_internal_t *) gf->scratch; htd = (struct gf_w8_half_table_data *)h->private; bzero(htd->high, sizeof(uint8_t)*GF_FIELD_SIZE*GF_HALF_SIZE); bzero(htd->low, sizeof(uint8_t)*GF_FIELD_SIZE*GF_HALF_SIZE); for (a = 1; a < GF_FIELD_SIZE; a++) { for (b = 1; b < GF_HALF_SIZE; b++) { htd->low[a][b] = gf_w8_shift_multiply(gf,a,b); htd->high[a][b] = gf_w8_shift_multiply(gf,a,b<<4); } } gf->multiply.w32 = gf_w8_split_multiply; #ifdef INTEL_SSSE3 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w8_split_multiply_region; else gf->multiply_region.w32 = gf_w8_split_multiply_region_sse; #else gf->multiply_region.w32 = gf_w8_split_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif return 1; } /* JSP: This is disgusting, but it is what it is. If there is no SSE, then the default is equivalent to single table. If there is SSE, then we use the "gf_w8_default_data" which is a hybrid of SPLIT & TABLE. */ static int gf_w8_table_init(gf_t *gf) { gf_internal_t *h; struct gf_w8_single_table_data *ftd = NULL; struct gf_w8_double_table_data *dtd = NULL; struct gf_w8_double_table_lazy_data *ltd = NULL; struct gf_w8_default_data *dd = NULL; int a, b, c, prod, scase, issse; h = (gf_internal_t *) gf->scratch; issse = 0; #ifdef INTEL_SSSE3 issse = 1; #endif if (h->mult_type == GF_MULT_DEFAULT && issse) { dd = (struct gf_w8_default_data *)h->private; scase = 3; bzero(dd->high, sizeof(uint8_t) * GF_FIELD_SIZE * GF_HALF_SIZE); bzero(dd->low, sizeof(uint8_t) * GF_FIELD_SIZE * GF_HALF_SIZE); bzero(dd->divtable, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(dd->multtable, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); } else if (h->mult_type == GF_MULT_DEFAULT || h->region_type == 0 || (h->region_type & GF_REGION_CAUCHY)) { ftd = (struct gf_w8_single_table_data *)h->private; bzero(ftd->divtable, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(ftd->multtable, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); scase = 0; } else if (h->region_type == GF_REGION_DOUBLE_TABLE) { dtd = (struct gf_w8_double_table_data *)h->private; bzero(dtd->div, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(dtd->mult, sizeof(uint16_t) * GF_FIELD_SIZE * GF_FIELD_SIZE * GF_FIELD_SIZE); scase = 1; } else if (h->region_type == (GF_REGION_DOUBLE_TABLE | GF_REGION_LAZY)) { ltd = (struct gf_w8_double_table_lazy_data *)h->private; bzero(ltd->div, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); bzero(ltd->smult, sizeof(uint8_t) * GF_FIELD_SIZE * GF_FIELD_SIZE); scase = 2; } else { fprintf(stderr, "Internal error in gf_w8_table_init\n"); exit(0); } for (a = 1; a < GF_FIELD_SIZE; a++) { for (b = 1; b < GF_FIELD_SIZE; b++) { prod = gf_w8_shift_multiply(gf,a,b); switch (scase) { case 0: ftd->multtable[a][b] = prod; ftd->divtable[prod][b] = a; break; case 1: dtd->div[prod][b] = a; for (c = 0; c < GF_FIELD_SIZE; c++) { dtd->mult[a][(c<<8)|b] |= prod; dtd->mult[a][(b<<8)|c] |= (prod<<8); } break; case 2: ltd->div[prod][b] = a; ltd->smult[a][b] = prod; break; case 3: dd->multtable[a][b] = prod; dd->divtable[prod][b] = a; if ((b & 0xf) == b) { dd->low[a][b] = prod; } if ((b & 0xf0) == b) { dd->high[a][b>>4] = prod; } break; } } } gf->inverse.w32 = NULL; /* Will set from divide */ switch (scase) { case 0: gf->divide.w32 = gf_w8_table_divide; gf->multiply.w32 = gf_w8_table_multiply; gf->multiply_region.w32 = gf_w8_table_multiply_region; break; case 1: gf->divide.w32 = gf_w8_double_table_divide; gf->multiply.w32 = gf_w8_double_table_multiply; gf->multiply_region.w32 = gf_w8_double_table_multiply_region; break; case 2: gf->divide.w32 = gf_w8_double_table_lazy_divide; gf->multiply.w32 = gf_w8_double_table_lazy_multiply; gf->multiply_region.w32 = gf_w8_double_table_multiply_region; break; case 3: #ifdef INTEL_SSSE3 gf->divide.w32 = gf_w8_default_divide; gf->multiply.w32 = gf_w8_default_multiply; gf->multiply_region.w32 = gf_w8_split_multiply_region_sse; #endif break; } return 1; } static void gf_w8_composite_multiply_region_alt(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t val0 = val & 0x0f; uint8_t val1 = (val & 0xf0) >> 4; gf_region_data rd; int sub_reg_size; if (val == 0) { if (xor) return; bzero(dest, bytes); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); sub_reg_size = ((char*)rd.d_top - (char*)rd.d_start) / 2; base_gf->multiply_region.w32(base_gf, rd.s_start, rd.d_start, val0, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, (char*)rd.s_start+sub_reg_size, rd.d_start, val1, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, rd.s_start, (char*)rd.d_start+sub_reg_size, val1, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, (char*)rd.s_start+sub_reg_size, (char*)rd.d_start+sub_reg_size, val0, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, (char*)rd.s_start+sub_reg_size, (char*)rd.d_start+sub_reg_size, base_gf->multiply.w32(base_gf, h->prim_poly, val1), sub_reg_size, 1); gf_do_final_region_alignment(&rd); } static gf_val_32_t gf_w8_composite_multiply_recursive(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t b0 = b & 0x0f; uint8_t b1 = (b & 0xf0) >> 4; uint8_t a0 = a & 0x0f; uint8_t a1 = (a & 0xf0) >> 4; uint8_t a1b1; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); return ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 4)); } static gf_val_32_t gf_w8_composite_multiply_inline(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; uint8_t b0 = b & 0x0f; uint8_t b1 = (b & 0xf0) >> 4; uint8_t a0 = a & 0x0f; uint8_t a1 = (a & 0xf0) >> 4; uint8_t a1b1, *mt; struct gf_w8_composite_data *cd; cd = (struct gf_w8_composite_data *) h->private; mt = cd->mult_table; a1b1 = GF_W4_INLINE_MULTDIV(mt, a1, b1); return ((GF_W4_INLINE_MULTDIV(mt, a0, b0) ^ a1b1) | ((GF_W4_INLINE_MULTDIV(mt, a1, b0) ^ GF_W4_INLINE_MULTDIV(mt, a0, b1) ^ GF_W4_INLINE_MULTDIV(mt, a1b1, h->prim_poly)) << 4)); } /* * Composite field division trick (explained in 2007 tech report) * * Compute a / b = a*b^-1, where p(x) = x^2 + sx + 1 * * let c = b^-1 * * c*b = (s*b1c1+b1c0+b0c1)x+(b1c1+b0c0) * * want (s*b1c1+b1c0+b0c1) = 0 and (b1c1+b0c0) = 1 * * let d = b1c1 and d+1 = b0c0 * * solve s*b1c1+b1c0+b0c1 = 0 * * solution: d = (b1b0^-1)(b1b0^-1+b0b1^-1+s)^-1 * * c0 = (d+1)b0^-1 * c1 = d*b1^-1 * * a / b = a * c */ static gf_val_32_t gf_w8_composite_inverse(gf_t *gf, gf_val_32_t a) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t a0 = a & 0x0f; uint8_t a1 = (a & 0xf0) >> 4; uint8_t c0, c1, c, d, tmp; uint8_t a0inv, a1inv; if (a0 == 0) { a1inv = base_gf->inverse.w32(base_gf, a1) & 0xf; c0 = base_gf->multiply.w32(base_gf, a1inv, h->prim_poly); c1 = a1inv; } else if (a1 == 0) { c0 = base_gf->inverse.w32(base_gf, a0); c1 = 0; } else { a1inv = base_gf->inverse.w32(base_gf, a1) & 0xf; a0inv = base_gf->inverse.w32(base_gf, a0) & 0xf; d = base_gf->multiply.w32(base_gf, a1, a0inv) & 0xf; tmp = (base_gf->multiply.w32(base_gf, a1, a0inv) ^ base_gf->multiply.w32(base_gf, a0, a1inv) ^ h->prim_poly) & 0xf; tmp = base_gf->inverse.w32(base_gf, tmp) & 0xf; d = base_gf->multiply.w32(base_gf, d, tmp) & 0xf; c0 = base_gf->multiply.w32(base_gf, (d^1), a0inv) & 0xf; c1 = base_gf->multiply.w32(base_gf, d, a1inv) & 0xf; } c = c0 | (c1 << 4); return c; } static void gf_w8_composite_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t b0 = val & 0x0f; uint8_t b1 = (val & 0xf0) >> 4; uint8_t *s8; uint8_t *d8; uint8_t *mt; uint8_t a0, a1, a1b1; struct gf_w8_composite_data *cd; cd = (struct gf_w8_composite_data *) h->private; if (val == 0) { if (xor) return; bzero(dest, bytes); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 1); gf_do_initial_region_alignment(&rd); s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; mt = cd->mult_table; if (mt == NULL) { if (xor) { while (d8 < (uint8_t *) rd.d_top) { a0 = *s8 & 0x0f; a1 = (*s8 & 0xf0) >> 4; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); *d8 ^= ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 4)); s8++; d8++; } } else { while (d8 < (uint8_t *) rd.d_top) { a0 = *s8 & 0x0f; a1 = (*s8 & 0xf0) >> 4; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); *d8 = ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 4)); s8++; d8++; } } } else { if (xor) { while (d8 < (uint8_t *) rd.d_top) { a0 = *s8 & 0x0f; a1 = (*s8 & 0xf0) >> 4; a1b1 = GF_W4_INLINE_MULTDIV(mt, a1, b1); *d8 ^= ((GF_W4_INLINE_MULTDIV(mt, a0, b0) ^ a1b1) | ((GF_W4_INLINE_MULTDIV(mt, a1, b0) ^ GF_W4_INLINE_MULTDIV(mt, a0, b1) ^ GF_W4_INLINE_MULTDIV(mt, a1b1, h->prim_poly)) << 4)); s8++; d8++; } } else { while (d8 < (uint8_t *) rd.d_top) { a0 = *s8 & 0x0f; a1 = (*s8 & 0xf0) >> 4; a1b1 = GF_W4_INLINE_MULTDIV(mt, a1, b1); *d8 = ((GF_W4_INLINE_MULTDIV(mt, a0, b0) ^ a1b1) | ((GF_W4_INLINE_MULTDIV(mt, a1, b0) ^ GF_W4_INLINE_MULTDIV(mt, a0, b1) ^ GF_W4_INLINE_MULTDIV(mt, a1b1, h->prim_poly)) << 4)); s8++; d8++; } } } gf_do_final_region_alignment(&rd); return; } static int gf_w8_composite_init(gf_t *gf) { gf_internal_t *h = (gf_internal_t *) gf->scratch; struct gf_w8_composite_data *cd; if (h->base_gf == NULL) return 0; cd = (struct gf_w8_composite_data *) h->private; cd->mult_table = gf_w4_get_mult_table(h->base_gf); if (h->region_type & GF_REGION_ALTMAP) { gf->multiply_region.w32 = gf_w8_composite_multiply_region_alt; } else { gf->multiply_region.w32 = gf_w8_composite_multiply_region; } if (cd->mult_table == NULL) { gf->multiply.w32 = gf_w8_composite_multiply_recursive; } else { gf->multiply.w32 = gf_w8_composite_multiply_inline; } gf->divide.w32 = NULL; gf->inverse.w32 = gf_w8_composite_inverse; return 1; } static inline gf_val_32_t gf_w8_bytwo_p_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, pmask, amask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; pmask = 0x80; amask = 0x80; while (amask != 0) { if (prod & pmask) { prod = ((prod << 1) ^ pp); } else { prod <<= 1; } if (a & amask) prod ^= b; amask >>= 1; } return prod; } static inline gf_val_32_t gf_w8_bytwo_b_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, bmask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; bmask = 0x80; while (1) { if (a & 1) prod ^= b; a >>= 1; if (a == 0) return prod; if (b & bmask) { b = ((b << 1) ^ pp); } else { b <<= 1; } } } static void gf_w8_bytwo_p_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, prod, amask; gf_region_data rd; struct gf_w8_bytwo_data *btd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_w8_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; if (xor) { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x80; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 ^= prod; d64++; s64++; } } else { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x80; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 = prod; d64++; s64++; } } gf_do_final_region_alignment(&rd); } #define BYTWO_P_ONESTEP {\ SSE_AB2(pp, m1 ,m2, prod, t1, t2); \ t1 = _mm_and_si128(v, one); \ t1 = _mm_sub_epi8(t1, one); \ t1 = _mm_and_si128(t1, ta); \ prod = _mm_xor_si128(prod, t1); \ v = _mm_srli_epi64(v, 1); } #ifdef INTEL_SSE2 static void gf_w8_bytwo_p_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8; uint8_t vrev; __m128i pp, m1, m2, ta, prod, t1, t2, tp, one, v; struct gf_w8_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_w8_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); vrev = 0; for (i = 0; i < 8; i++) { vrev <<= 1; if (!(val & (1 << i))) vrev |= 1; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); m2 = _mm_set1_epi8((btd->mask2)&0xff); one = _mm_set1_epi8(1); while (d8 < (uint8_t *) rd.d_top) { prod = _mm_setzero_si128(); v = _mm_set1_epi8(vrev); ta = _mm_load_si128((__m128i *) s8); tp = (!xor) ? _mm_setzero_si128() : _mm_load_si128((__m128i *) d8); BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; _mm_store_si128((__m128i *) d8, _mm_xor_si128(prod, tp)); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif #ifdef INTEL_SSE2 static void gf_w8_bytwo_b_sse_region_2_noxor(gf_region_data *rd, struct gf_w8_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); m2 = _mm_set1_epi8((btd->mask2)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w8_bytwo_b_sse_region_2_xor(gf_region_data *rd, struct gf_w8_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); m2 = _mm_set1_epi8((btd->mask2)&0xff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); vb = _mm_load_si128 ((__m128i *)(d8)); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w8_bytwo_b_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int itb; uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; struct gf_w8_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); btd = (struct gf_w8_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; if (val == 2) { if (xor) { gf_w8_bytwo_b_sse_region_2_xor(&rd, btd); } else { gf_w8_bytwo_b_sse_region_2_noxor(&rd, btd); } gf_do_final_region_alignment(&rd); return; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi8(btd->prim_poly&0xff); m1 = _mm_set1_epi8((btd->mask1)&0xff); m2 = _mm_set1_epi8((btd->mask2)&0xff); while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = (!xor) ? _mm_setzero_si128() : _mm_load_si128 ((__m128i *)(d8)); itb = val; while (1) { if (itb & 1) vb = _mm_xor_si128(vb, va); itb >>= 1; if (itb == 0) break; SSE_AB2(pp, m1, m2, va, t1, t2); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif static void gf_w8_bytwo_b_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, tb, prod; struct gf_w8_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); btd = (struct gf_w8_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; switch (val) { case 2: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 3: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 4: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 5: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } case 6: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } /* case 7: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } break; */ case 8: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; /* case 9: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 10: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 11: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 12: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 13: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 14: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 15: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); prod ^= ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; */ default: if (xor) { while (d64 < (uint64_t *) rd.d_top) { prod = *d64 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { prod = 0 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } break; } gf_do_final_region_alignment(&rd); } static int gf_w8_bytwo_init(gf_t *gf) { gf_internal_t *h; uint64_t ip, m1, m2; struct gf_w8_bytwo_data *btd; h = (gf_internal_t *) gf->scratch; btd = (struct gf_w8_bytwo_data *) (h->private); ip = h->prim_poly & 0xff; m1 = 0xfe; m2 = 0x80; btd->prim_poly = 0; btd->mask1 = 0; btd->mask2 = 0; while (ip != 0) { btd->prim_poly |= ip; btd->mask1 |= m1; btd->mask2 |= m2; ip <<= GF_FIELD_WIDTH; m1 <<= GF_FIELD_WIDTH; m2 <<= GF_FIELD_WIDTH; } if (h->mult_type == GF_MULT_BYTWO_p) { gf->multiply.w32 = gf_w8_bytwo_p_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w8_bytwo_p_nosse_multiply_region; else gf->multiply_region.w32 = gf_w8_bytwo_p_sse_multiply_region; #else gf->multiply_region.w32 = gf_w8_bytwo_p_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } else { gf->multiply.w32 = gf_w8_bytwo_b_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w8_bytwo_b_nosse_multiply_region; else gf->multiply_region.w32 = gf_w8_bytwo_b_sse_multiply_region; #else gf->multiply_region.w32 = gf_w8_bytwo_b_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } return 1; } /* ------------------------------------------------------------ General procedures. You don't need to error check here on in init, because it's done for you in gf_error_check(). */ int gf_w8_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2) { switch(mult_type) { case GF_MULT_DEFAULT: #ifdef INTEL_SSSE3 return sizeof(gf_internal_t) + sizeof(struct gf_w8_default_data) + 64; #endif return sizeof(gf_internal_t) + sizeof(struct gf_w8_single_table_data) + 64; case GF_MULT_TABLE: if (region_type == GF_REGION_CAUCHY) { return sizeof(gf_internal_t) + sizeof(struct gf_w8_single_table_data) + 64; } if (region_type == GF_REGION_DEFAULT) { return sizeof(gf_internal_t) + sizeof(struct gf_w8_single_table_data) + 64; } if (region_type & GF_REGION_DOUBLE_TABLE) { if (region_type == GF_REGION_DOUBLE_TABLE) { return sizeof(gf_internal_t) + sizeof(struct gf_w8_double_table_data) + 64; } else if (region_type == (GF_REGION_DOUBLE_TABLE | GF_REGION_LAZY)) { return sizeof(gf_internal_t) + sizeof(struct gf_w8_double_table_lazy_data) + 64; } else { return 0; } } return 0; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: return sizeof(gf_internal_t) + sizeof(struct gf_w8_bytwo_data); break; case GF_MULT_SPLIT_TABLE: if ((arg1 == 4 && arg2 == 8) || (arg1 == 8 && arg2 == 4)) { return sizeof(gf_internal_t) + sizeof(struct gf_w8_half_table_data) + 64; } break; case GF_MULT_LOG_TABLE: return sizeof(gf_internal_t) + sizeof(struct gf_w8_logtable_data) + 64; break; case GF_MULT_LOG_ZERO: return sizeof(gf_internal_t) + sizeof(struct gf_w8_logzero_small_table_data) + 64; break; case GF_MULT_LOG_ZERO_EXT: return sizeof(gf_internal_t) + sizeof(struct gf_w8_logzero_table_data) + 64; break; case GF_MULT_CARRY_FREE: return sizeof(gf_internal_t); break; case GF_MULT_SHIFT: return sizeof(gf_internal_t); break; case GF_MULT_COMPOSITE: return sizeof(gf_internal_t) + sizeof(struct gf_w8_composite_data) + 64; default: return 0; } return 0; } int gf_w8_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; /* Allen: set default primitive polynomial / irreducible polynomial if needed */ if (h->prim_poly == 0) { if (h->mult_type == GF_MULT_COMPOSITE) { h->prim_poly = gf_composite_get_default_poly(h->base_gf); if (h->prim_poly == 0) return 0; /* JSP: This shouldn't happen, but just in case. */ } else { h->prim_poly = 0x11d; } } if (h->mult_type != GF_MULT_COMPOSITE) { h->prim_poly |= 0x100; } gf->multiply.w32 = NULL; gf->divide.w32 = NULL; gf->inverse.w32 = NULL; gf->multiply_region.w32 = NULL; gf->extract_word.w32 = gf_w8_extract_word; switch(h->mult_type) { case GF_MULT_DEFAULT: case GF_MULT_TABLE: if (gf_w8_table_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: if (gf_w8_bytwo_init(gf) == 0) return 0; break; case GF_MULT_LOG_ZERO: case GF_MULT_LOG_ZERO_EXT: case GF_MULT_LOG_TABLE: if (gf_w8_log_init(gf) == 0) return 0; break; case GF_MULT_CARRY_FREE: if (gf_w8_cfm_init(gf) == 0) return 0; break; case GF_MULT_SHIFT: if (gf_w8_shift_init(gf) == 0) return 0; break; case GF_MULT_SPLIT_TABLE: if (gf_w8_split_init(gf) == 0) return 0; break; case GF_MULT_COMPOSITE: if (gf_w8_composite_init(gf) == 0) return 0; break; default: return 0; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w32 = gf_w8_divide_from_inverse; gf->inverse.w32 = gf_w8_euclid; } else if (h->divide_type == GF_DIVIDE_MATRIX) { gf->divide.w32 = gf_w8_divide_from_inverse; gf->inverse.w32 = gf_w8_matrix; } if (gf->divide.w32 == NULL) { gf->divide.w32 = gf_w8_divide_from_inverse; if (gf->inverse.w32 == NULL) gf->inverse.w32 = gf_w8_euclid; } if (gf->inverse.w32 == NULL) gf->inverse.w32 = gf_w8_inverse_from_divide; if (h->mult_type == GF_MULT_COMPOSITE && (h->region_type & GF_REGION_ALTMAP)) { gf->extract_word.w32 = gf_w8_composite_extract_word; } if (h->region_type == GF_REGION_CAUCHY) { gf->multiply_region.w32 = gf_wgen_cauchy_region; gf->extract_word.w32 = gf_wgen_extract_word; } if (gf->multiply_region.w32 == NULL) { gf->multiply_region.w32 = gf_w8_multiply_region_from_single; } return 1; } /* Inline setup functions */ uint8_t *gf_w8_get_mult_table(gf_t *gf) { gf_internal_t *h; struct gf_w8_default_data *ftd; struct gf_w8_single_table_data *std; h = (gf_internal_t *) gf->scratch; if (gf->multiply.w32 == gf_w8_default_multiply) { ftd = (struct gf_w8_default_data *) h->private; return (uint8_t *) ftd->multtable; } else if (gf->multiply.w32 == gf_w8_table_multiply) { std = (struct gf_w8_single_table_data *) h->private; return (uint8_t *) std->multtable; } return NULL; } uint8_t *gf_w8_get_div_table(gf_t *gf) { struct gf_w8_default_data *ftd; struct gf_w8_single_table_data *std; if (gf->multiply.w32 == gf_w8_default_multiply) { ftd = (struct gf_w8_default_data *) ((gf_internal_t *) gf->scratch)->private; return (uint8_t *) ftd->divtable; } else if (gf->multiply.w32 == gf_w8_table_multiply) { std = (struct gf_w8_single_table_data *) ((gf_internal_t *) gf->scratch)->private; return (uint8_t *) std->divtable; } return NULL; } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_method.c0000664000175100017510000001410312623076752026751 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_method.c * * Parses argv to figure out the mult_type and arguments. Returns the gf. */ #include #include #include #include #include #include "gf_complete.h" #include "gf_int.h" #include "gf_method.h" int create_gf_from_argv(gf_t *gf, int w, int argc, char **argv, int starting) { int mult_type, divide_type, region_type; int arg1, arg2; uint64_t prim_poly; gf_t *base; mult_type = GF_MULT_DEFAULT; region_type = GF_REGION_DEFAULT; divide_type = GF_DIVIDE_DEFAULT; prim_poly = 0; base = NULL; arg1 = 0; arg2 = 0; while (1) { if (argc > starting) { if (strcmp(argv[starting], "-m") == 0) { starting++; if (mult_type != GF_MULT_DEFAULT) { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_TWOMULT; return 0; } if (strcmp(argv[starting], "SHIFT") == 0) { mult_type = GF_MULT_SHIFT; starting++; } else if (strcmp(argv[starting], "CARRY_FREE") == 0) { mult_type = GF_MULT_CARRY_FREE; starting++; } else if (strcmp(argv[starting], "GROUP") == 0) { mult_type = GF_MULT_GROUP; if (argc < starting + 3) { _gf_errno = GF_E_GROUPAR; return 0; } if (sscanf(argv[starting+1], "%d", &arg1) == 0 || sscanf(argv[starting+2], "%d", &arg2) == 0) { _gf_errno = GF_E_GROUPNU; return 0; } starting += 3; } else if (strcmp(argv[starting], "BYTWO_p") == 0) { mult_type = GF_MULT_BYTWO_p; starting++; } else if (strcmp(argv[starting], "BYTWO_b") == 0) { mult_type = GF_MULT_BYTWO_b; starting++; } else if (strcmp(argv[starting], "TABLE") == 0) { mult_type = GF_MULT_TABLE; starting++; } else if (strcmp(argv[starting], "LOG") == 0) { mult_type = GF_MULT_LOG_TABLE; starting++; } else if (strcmp(argv[starting], "LOG_ZERO") == 0) { mult_type = GF_MULT_LOG_ZERO; starting++; } else if (strcmp(argv[starting], "LOG_ZERO_EXT") == 0) { mult_type = GF_MULT_LOG_ZERO_EXT; starting++; } else if (strcmp(argv[starting], "SPLIT") == 0) { mult_type = GF_MULT_SPLIT_TABLE; if (argc < starting + 3) { _gf_errno = GF_E_SPLITAR; return 0; } if (sscanf(argv[starting+1], "%d", &arg1) == 0 || sscanf(argv[starting+2], "%d", &arg2) == 0) { _gf_errno = GF_E_SPLITNU; return 0; } starting += 3; } else if (strcmp(argv[starting], "COMPOSITE") == 0) { mult_type = GF_MULT_COMPOSITE; if (argc < starting + 2) { _gf_errno = GF_E_FEWARGS; return 0; } if (sscanf(argv[starting+1], "%d", &arg1) == 0) { _gf_errno = GF_E_COMP_A2; return 0; } starting += 2; base = (gf_t *) malloc(sizeof(gf_t)); starting = create_gf_from_argv(base, w/arg1, argc, argv, starting); if (starting == 0) { free(base); return 0; } } else { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_UNKNOWN; return 0; } } else if (strcmp(argv[starting], "-r") == 0) { starting++; if (strcmp(argv[starting], "DOUBLE") == 0) { region_type |= GF_REGION_DOUBLE_TABLE; starting++; } else if (strcmp(argv[starting], "QUAD") == 0) { region_type |= GF_REGION_QUAD_TABLE; starting++; } else if (strcmp(argv[starting], "LAZY") == 0) { region_type |= GF_REGION_LAZY; starting++; } else if (strcmp(argv[starting], "SSE") == 0) { region_type |= GF_REGION_SSE; starting++; } else if (strcmp(argv[starting], "NOSSE") == 0) { region_type |= GF_REGION_NOSSE; starting++; } else if (strcmp(argv[starting], "CAUCHY") == 0) { region_type |= GF_REGION_CAUCHY; starting++; } else if (strcmp(argv[starting], "ALTMAP") == 0) { region_type |= GF_REGION_ALTMAP; starting++; } else { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_UNK_REG; return 0; } } else if (strcmp(argv[starting], "-p") == 0) { starting++; if (sscanf(argv[starting], "%llx", (long long unsigned int *)(&prim_poly)) == 0) { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_POLYSPC; return 0; } starting++; } else if (strcmp(argv[starting], "-d") == 0) { starting++; if (divide_type != GF_DIVIDE_DEFAULT) { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_TWO_DIV; return 0; } else if (strcmp(argv[starting], "EUCLID") == 0) { divide_type = GF_DIVIDE_EUCLID; starting++; } else if (strcmp(argv[starting], "MATRIX") == 0) { divide_type = GF_DIVIDE_MATRIX; starting++; } else { _gf_errno = GF_E_UNK_DIV; return 0; } } else if (strcmp(argv[starting], "-") == 0) { /* printf("Scratch size: %d\n", gf_scratch_size(w, mult_type, region_type, divide_type, arg1, arg2)); */ if (gf_init_hard(gf, w, mult_type, region_type, divide_type, prim_poly, arg1, arg2, base, NULL) == 0) { if (base != NULL) gf_free(base, 1); return 0; } else return starting + 1; } else { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_UNKFLAG; return 0; } } else { if (base != NULL) gf_free(base, 1); _gf_errno = GF_E_FEWARGS; return 0; } } } ceph-0.80.11/src/erasure-code/jerasure/gf-complete/src/gf_w16.c0000664000175100017510000020243012623076752026110 0ustar jenkins-buildjenkins-build/* * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic * James S. Plank, Ethan L. Miller, Kevin M. Greenan, * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride. * * gf_w16.c * * Routines for 16-bit Galois fields */ #include "gf_int.h" #include #include #define GF_FIELD_WIDTH (16) #define GF_FIELD_SIZE (1 << GF_FIELD_WIDTH) #define GF_MULT_GROUP_SIZE GF_FIELD_SIZE-1 #define GF_BASE_FIELD_WIDTH (8) #define GF_BASE_FIELD_SIZE (1 << GF_BASE_FIELD_WIDTH) struct gf_w16_logtable_data { uint16_t log_tbl[GF_FIELD_SIZE]; uint16_t antilog_tbl[GF_FIELD_SIZE * 2]; uint16_t inv_tbl[GF_FIELD_SIZE]; uint16_t *d_antilog; }; struct gf_w16_zero_logtable_data { int log_tbl[GF_FIELD_SIZE]; uint16_t _antilog_tbl[GF_FIELD_SIZE * 4]; uint16_t *antilog_tbl; uint16_t inv_tbl[GF_FIELD_SIZE]; }; struct gf_w16_lazytable_data { uint16_t log_tbl[GF_FIELD_SIZE]; uint16_t antilog_tbl[GF_FIELD_SIZE * 2]; uint16_t inv_tbl[GF_FIELD_SIZE]; uint16_t *d_antilog; uint16_t lazytable[GF_FIELD_SIZE]; }; struct gf_w16_bytwo_data { uint64_t prim_poly; uint64_t mask1; uint64_t mask2; }; struct gf_w16_split_8_8_data { uint16_t tables[3][256][256]; }; struct gf_w16_group_4_4_data { uint16_t reduce[16]; uint16_t shift[16]; }; struct gf_w16_composite_data { uint8_t *mult_table; }; #define AB2(ip, am1 ,am2, b, t1, t2) {\ t1 = (b << 1) & am1;\ t2 = b & am2; \ t2 = ((t2 << 1) - (t2 >> (GF_FIELD_WIDTH-1))); \ b = (t1 ^ (t2 & ip));} #define SSE_AB2(pp, m1 ,m2, va, t1, t2) {\ t1 = _mm_and_si128(_mm_slli_epi64(va, 1), m1); \ t2 = _mm_and_si128(va, m2); \ t2 = _mm_sub_epi64 (_mm_slli_epi64(t2, 1), _mm_srli_epi64(t2, (GF_FIELD_WIDTH-1))); \ va = _mm_xor_si128(t1, _mm_and_si128(t2, pp)); } #define MM_PRINT(s, r) { uint8_t blah[16], ii; printf("%-12s", s); _mm_storeu_si128((__m128i *)blah, r); for (ii = 0; ii < 16; ii += 2) printf(" %02x %02x", blah[15-ii], blah[14-ii]); printf("\n"); } #define GF_FIRST_BIT (1 << 15) #define GF_MULTBY_TWO(p) (((p) & GF_FIRST_BIT) ? (((p) << 1) ^ h->prim_poly) : (p) << 1) static inline gf_val_32_t gf_w16_inverse_from_divide (gf_t *gf, gf_val_32_t a) { return gf->divide.w32(gf, 1, a); } static inline gf_val_32_t gf_w16_divide_from_inverse (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { b = gf->inverse.w32(gf, b); return gf->multiply.w32(gf, a, b); } static void gf_w16_multiply_region_from_single(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint16_t *s16; uint16_t *d16; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; if (xor) { while (d16 < ((uint16_t *) rd.d_top)) { *d16 ^= gf->multiply.w32(gf, val, *s16); d16++; s16++; } } else { while (d16 < ((uint16_t *) rd.d_top)) { *d16 = gf->multiply.w32(gf, val, *s16); d16++; s16++; } } gf_do_final_region_alignment(&rd); } #if defined(INTEL_SSE4_PCLMUL) static void gf_w16_clm_multiply_region_from_single_2(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint16_t *s16; uint16_t *d16; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; if (xor) { while (d16 < ((uint16_t *) rd.d_top)) { /* see gf_w16_clm_multiply() to see explanation of method */ b = _mm_insert_epi32 (a, (gf_val_32_t)(*s16), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); *d16 ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); d16++; s16++; } } else { while (d16 < ((uint16_t *) rd.d_top)) { /* see gf_w16_clm_multiply() to see explanation of method */ b = _mm_insert_epi32 (a, (gf_val_32_t)(*s16), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); *d16 = ((gf_val_32_t)_mm_extract_epi32(result, 0)); d16++; s16++; } } gf_do_final_region_alignment(&rd); } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w16_clm_multiply_region_from_single_3(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint16_t *s16; uint16_t *d16; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; if (xor) { while (d16 < ((uint16_t *) rd.d_top)) { /* see gf_w16_clm_multiply() to see explanation of method */ b = _mm_insert_epi32 (a, (gf_val_32_t)(*s16), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); *d16 ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); d16++; s16++; } } else { while (d16 < ((uint16_t *) rd.d_top)) { /* see gf_w16_clm_multiply() to see explanation of method */ b = _mm_insert_epi32 (a, (gf_val_32_t)(*s16), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); *d16 = ((gf_val_32_t)_mm_extract_epi32(result, 0)); d16++; s16++; } } gf_do_final_region_alignment(&rd); } #endif #if defined(INTEL_SSE4_PCLMUL) static void gf_w16_clm_multiply_region_from_single_4(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_region_data rd; uint16_t *s16; uint16_t *d16; __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffffULL)); if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); a = _mm_insert_epi32 (_mm_setzero_si128(), val, 0); s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; if (xor) { while (d16 < ((uint16_t *) rd.d_top)) { /* see gf_w16_clm_multiply() to see explanation of method */ b = _mm_insert_epi32 (a, (gf_val_32_t)(*s16), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); *d16 ^= ((gf_val_32_t)_mm_extract_epi32(result, 0)); d16++; s16++; } } else { while (d16 < ((uint16_t *) rd.d_top)) { /* see gf_w16_clm_multiply() to see explanation of method */ b = _mm_insert_epi32 (a, (gf_val_32_t)(*s16), 0); result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); *d16 = ((gf_val_32_t)_mm_extract_epi32(result, 0)); d16++; s16++; } } gf_do_final_region_alignment(&rd); } #endif static inline gf_val_32_t gf_w16_euclid (gf_t *gf, gf_val_32_t b) { gf_val_32_t e_i, e_im1, e_ip1; gf_val_32_t d_i, d_im1, d_ip1; gf_val_32_t y_i, y_im1, y_ip1; gf_val_32_t c_i; if (b == 0) return -1; e_im1 = ((gf_internal_t *) (gf->scratch))->prim_poly; e_i = b; d_im1 = 16; for (d_i = d_im1; ((1 << d_i) & e_i) == 0; d_i--) ; y_i = 1; y_im1 = 0; while (e_i != 1) { e_ip1 = e_im1; d_ip1 = d_im1; c_i = 0; while (d_ip1 >= d_i) { c_i ^= (1 << (d_ip1 - d_i)); e_ip1 ^= (e_i << (d_ip1 - d_i)); if (e_ip1 == 0) return 0; while ((e_ip1 & (1 << d_ip1)) == 0) d_ip1--; } y_ip1 = y_im1 ^ gf->multiply.w32(gf, c_i, y_i); y_im1 = y_i; y_i = y_ip1; e_im1 = e_i; d_im1 = d_i; e_i = e_ip1; d_i = d_ip1; } return y_i; } static gf_val_32_t gf_w16_extract_word(gf_t *gf, void *start, int bytes, int index) { uint16_t *r16, rv; r16 = (uint16_t *) start; rv = r16[index]; return rv; } static gf_val_32_t gf_w16_composite_extract_word(gf_t *gf, void *start, int bytes, int index) { int sub_size; gf_internal_t *h; uint8_t *r8, *top; uint16_t a, b, *r16; gf_region_data rd; h = (gf_internal_t *) gf->scratch; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 32); r16 = (uint16_t *) start; if (r16 + index < (uint16_t *) rd.d_start) return r16[index]; if (r16 + index >= (uint16_t *) rd.d_top) return r16[index]; index -= (((uint16_t *) rd.d_start) - r16); r8 = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_size = (top-r8)/2; a = h->base_gf->extract_word.w32(h->base_gf, r8, sub_size, index); b = h->base_gf->extract_word.w32(h->base_gf, r8+sub_size, sub_size, index); return (a | (b << 8)); } static gf_val_32_t gf_w16_split_extract_word(gf_t *gf, void *start, int bytes, int index) { uint16_t *r16, rv; uint8_t *r8; gf_region_data rd; gf_set_region_data(&rd, gf, start, start, bytes, 0, 0, 32); r16 = (uint16_t *) start; if (r16 + index < (uint16_t *) rd.d_start) return r16[index]; if (r16 + index >= (uint16_t *) rd.d_top) return r16[index]; index -= (((uint16_t *) rd.d_start) - r16); r8 = (uint8_t *) rd.d_start; r8 += ((index & 0xfffffff0)*2); r8 += (index & 0xf); rv = (*r8 << 8); r8 += 16; rv |= *r8; return rv; } static inline gf_val_32_t gf_w16_matrix (gf_t *gf, gf_val_32_t b) { return gf_bitmatrix_inverse(b, 16, ((gf_internal_t *) (gf->scratch))->prim_poly); } /* JSP: GF_MULT_SHIFT: The world's dumbest multiplication algorithm. I only include it for completeness. It does have the feature that it requires no extra memory. */ static inline gf_val_32_t gf_w16_clm_multiply_2 (gf_t *gf, gf_val_32_t a16, gf_val_32_t b16) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a16, 0); b = _mm_insert_epi32 (a, b16, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); /* Ben: Do prim_poly reduction twice. We are guaranteed that we will only have to do the reduction at most twice, because (w-2)/z == 2. Where z is equal to the number of zeros after the leading 1 _mm_clmulepi64_si128 is the carryless multiply operation. Here _mm_srli_si128 shifts the result to the right by 2 bytes. This allows us to multiply the prim_poly by the leading bits of the result. We then xor the result of that operation back with the result.*/ w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w16_clm_multiply_3 (gf_t *gf, gf_val_32_t a16, gf_val_32_t b16) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a16, 0); b = _mm_insert_epi32 (a, b16, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w16_clm_multiply_4 (gf_t *gf, gf_val_32_t a16, gf_val_32_t b16) { gf_val_32_t rv = 0; #if defined(INTEL_SSE4_PCLMUL) __m128i a, b; __m128i result; __m128i prim_poly; __m128i w; gf_internal_t * h = gf->scratch; a = _mm_insert_epi32 (_mm_setzero_si128(), a16, 0); b = _mm_insert_epi32 (a, b16, 0); prim_poly = _mm_set_epi32(0, 0, 0, (uint32_t)(h->prim_poly & 0x1ffffULL)); /* Do the initial multiply */ result = _mm_clmulepi64_si128 (a, b, 0); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); w = _mm_clmulepi64_si128 (prim_poly, _mm_srli_si128 (result, 2), 0); result = _mm_xor_si128 (result, w); /* Extracts 32 bit value from result. */ rv = ((gf_val_32_t)_mm_extract_epi32(result, 0)); #endif return rv; } static inline gf_val_32_t gf_w16_shift_multiply (gf_t *gf, gf_val_32_t a16, gf_val_32_t b16) { gf_val_32_t product, i, pp, a, b; gf_internal_t *h; a = a16; b = b16; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; product = 0; for (i = 0; i < GF_FIELD_WIDTH; i++) { if (a & (1 << i)) product ^= (b << i); } for (i = (GF_FIELD_WIDTH*2-2); i >= GF_FIELD_WIDTH; i--) { if (product & (1 << i)) product ^= (pp << (i-GF_FIELD_WIDTH)); } return product; } static int gf_w16_shift_init(gf_t *gf) { gf->multiply.w32 = gf_w16_shift_multiply; return 1; } static int gf_w16_cfm_init(gf_t *gf) { #if defined(INTEL_SSE4_PCLMUL) gf_internal_t *h; h = (gf_internal_t *) gf->scratch; /*Ben: Determining how many reductions to do */ if ((0xfe00 & h->prim_poly) == 0) { gf->multiply.w32 = gf_w16_clm_multiply_2; gf->multiply_region.w32 = gf_w16_clm_multiply_region_from_single_2; } else if((0xf000 & h->prim_poly) == 0) { gf->multiply.w32 = gf_w16_clm_multiply_3; gf->multiply_region.w32 = gf_w16_clm_multiply_region_from_single_3; } else if ((0xe000 & h->prim_poly) == 0) { gf->multiply.w32 = gf_w16_clm_multiply_4; gf->multiply_region.w32 = gf_w16_clm_multiply_region_from_single_4; } else { return 0; } return 1; #endif return 0; } /* KMG: GF_MULT_LOGTABLE: */ static void gf_w16_log_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint16_t *s16, *d16; int lv; struct gf_w16_logtable_data *ltd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); ltd = (struct gf_w16_logtable_data *) ((gf_internal_t *) gf->scratch)->private; s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; lv = ltd->log_tbl[val]; if (xor) { while (d16 < (uint16_t *) rd.d_top) { *d16 ^= (*s16 == 0 ? 0 : ltd->antilog_tbl[lv + ltd->log_tbl[*s16]]); d16++; s16++; } } else { while (d16 < (uint16_t *) rd.d_top) { *d16 = (*s16 == 0 ? 0 : ltd->antilog_tbl[lv + ltd->log_tbl[*s16]]); d16++; s16++; } } gf_do_final_region_alignment(&rd); } static inline gf_val_32_t gf_w16_log_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w16_logtable_data *ltd; ltd = (struct gf_w16_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return (a == 0 || b == 0) ? 0 : ltd->antilog_tbl[(int) ltd->log_tbl[a] + (int) ltd->log_tbl[b]]; } static inline gf_val_32_t gf_w16_log_divide(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int log_sum = 0; struct gf_w16_logtable_data *ltd; if (a == 0 || b == 0) return 0; ltd = (struct gf_w16_logtable_data *) ((gf_internal_t *) gf->scratch)->private; log_sum = (int) ltd->log_tbl[a] - (int) ltd->log_tbl[b]; return (ltd->d_antilog[log_sum]); } static gf_val_32_t gf_w16_log_inverse(gf_t *gf, gf_val_32_t a) { struct gf_w16_logtable_data *ltd; ltd = (struct gf_w16_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return (ltd->inv_tbl[a]); } static int gf_w16_log_init(gf_t *gf) { gf_internal_t *h; struct gf_w16_logtable_data *ltd; int i, b; int check = 0; h = (gf_internal_t *) gf->scratch; ltd = h->private; for (i = 0; i < GF_MULT_GROUP_SIZE+1; i++) ltd->log_tbl[i] = 0; ltd->d_antilog = ltd->antilog_tbl + GF_MULT_GROUP_SIZE; b = 1; for (i = 0; i < GF_MULT_GROUP_SIZE; i++) { if (ltd->log_tbl[b] != 0) check = 1; ltd->log_tbl[b] = i; ltd->antilog_tbl[i] = b; ltd->antilog_tbl[i+GF_MULT_GROUP_SIZE] = b; b <<= 1; if (b & GF_FIELD_SIZE) { b = b ^ h->prim_poly; } } /* If you can't construct the log table, there's a problem. This code is used for some other implementations (e.g. in SPLIT), so if the log table doesn't work in that instance, use CARRY_FREE / SHIFT instead. */ if (check) { if (h->mult_type != GF_MULT_LOG_TABLE) { #if defined(INTEL_SSE4_PCLMUL) return gf_w16_cfm_init(gf); #endif return gf_w16_shift_init(gf); } else { _gf_errno = GF_E_LOGPOLY; return 0; } } ltd->inv_tbl[0] = 0; /* Not really, but we need to fill it with something */ ltd->inv_tbl[1] = 1; for (i = 2; i < GF_FIELD_SIZE; i++) { ltd->inv_tbl[i] = ltd->antilog_tbl[GF_MULT_GROUP_SIZE-ltd->log_tbl[i]]; } gf->inverse.w32 = gf_w16_log_inverse; gf->divide.w32 = gf_w16_log_divide; gf->multiply.w32 = gf_w16_log_multiply; gf->multiply_region.w32 = gf_w16_log_multiply_region; return 1; } /* JSP: GF_MULT_SPLIT_TABLE: Using 8 multiplication tables to leverage SSE instructions. */ /* Ben: Does alternate mapping multiplication using a split table in the lazy method without sse instructions*/ static void gf_w16_split_4_16_lazy_nosse_altmap_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t i, j, c, prod; uint8_t *s8, *d8, *top; uint16_t table[4][16]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); /*Ben: Constructs lazy multiplication table*/ for (j = 0; j < 16; j++) { for (i = 0; i < 4; i++) { c = (j << (i*4)); table[i][j] = gf->multiply.w32(gf, c, val); } } /*Ben: s8 is the start of source, d8 is the start of dest, top is end of dest region. */ s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; while (d8 < top) { /*Ben: Multiplies across 16 two byte quantities using alternate mapping high bits are on the left, low bits are on the right. */ for (j=0;j<16;j++) { /*Ben: If the xor flag is set, the product should include what is in dest */ prod = (xor) ? ((uint16_t)(*d8)<<8) ^ *(d8+16) : 0; /*Ben: xors all 4 table lookups into the product variable*/ prod ^= ((table[0][*(s8+16)&0xf]) ^ (table[1][(*(s8+16)&0xf0)>>4]) ^ (table[2][*(s8)&0xf]) ^ (table[3][(*(s8)&0xf0)>>4])); /*Ben: Stores product in the destination and moves on*/ *d8 = (uint8_t)(prod >> 8); *(d8+16) = (uint8_t)(prod & 0x00ff); s8++; d8++; } s8+=16; d8+=16; } gf_do_final_region_alignment(&rd); } static void gf_w16_split_4_16_lazy_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t i, j, a, c, prod; uint16_t *s16, *d16, *top; uint16_t table[4][16]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); for (j = 0; j < 16; j++) { for (i = 0; i < 4; i++) { c = (j << (i*4)); table[i][j] = gf->multiply.w32(gf, c, val); } } s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; top = (uint16_t *) rd.d_top; while (d16 < top) { a = *s16; prod = (xor) ? *d16 : 0; for (i = 0; i < 4; i++) { prod ^= table[i][a&0xf]; a >>= 4; } *d16 = prod; s16++; d16++; } } static void gf_w16_split_8_16_lazy_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t j, k, v, a, prod, *s64, *d64, *top64; gf_internal_t *h; uint64_t htable[256], ltable[256]; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; v = val; ltable[0] = 0; for (j = 1; j < 256; j <<= 1) { for (k = 0; k < j; k++) ltable[k^j] = (v ^ ltable[k]); v = GF_MULTBY_TWO(v); } htable[0] = 0; for (j = 1; j < 256; j <<= 1) { for (k = 0; k < j; k++) htable[k^j] = (v ^ htable[k]); v = GF_MULTBY_TWO(v); } s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top64 = (uint64_t *) rd.d_top; /* Does Unrolling Matter? -- Doesn't seem to. while (d64 != top64) { a = *s64; prod = htable[a >> 56]; a <<= 8; prod ^= ltable[a >> 56]; a <<= 8; prod <<= 16; prod ^= htable[a >> 56]; a <<= 8; prod ^= ltable[a >> 56]; a <<= 8; prod <<= 16; prod ^= htable[a >> 56]; a <<= 8; prod ^= ltable[a >> 56]; a <<= 8; prod <<= 16; prod ^= htable[a >> 56]; a <<= 8; prod ^= ltable[a >> 56]; prod ^= ((xor) ? *d64 : 0); *d64 = prod; s64++; d64++; } */ while (d64 != top64) { a = *s64; prod = 0; for (j = 0; j < 4; j++) { prod <<= 16; prod ^= htable[a >> 56]; a <<= 8; prod ^= ltable[a >> 56]; a <<= 8; } //JSP: We can move the conditional outside the while loop, but we need to fully test it to understand which is better. prod ^= ((xor) ? *d64 : 0); *d64 = prod; s64++; d64++; } gf_do_final_region_alignment(&rd); } static void gf_w16_table_lazy_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t c; gf_internal_t *h; struct gf_w16_lazytable_data *ltd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); h = (gf_internal_t *) gf->scratch; ltd = (struct gf_w16_lazytable_data *) h->private; ltd->lazytable[0] = 0; /* a = val; c = 1; pp = h->prim_poly; do { ltd->lazytable[c] = a; c <<= 1; if (c & (1 << GF_FIELD_WIDTH)) c ^= pp; a <<= 1; if (a & (1 << GF_FIELD_WIDTH)) a ^= pp; } while (c != 1); */ for (c = 1; c < GF_FIELD_SIZE; c++) { ltd->lazytable[c] = gf_w16_shift_multiply(gf, c, val); } gf_two_byte_region_table_multiply(&rd, ltd->lazytable); gf_do_final_region_alignment(&rd); } static void gf_w16_split_4_16_lazy_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { #ifdef INTEL_SSSE3 uint64_t i, j, *s64, *d64, *top64;; uint64_t c, prod; uint8_t low[4][16]; uint8_t high[4][16]; gf_region_data rd; __m128i mask, ta, tb, ti, tpl, tph, tlow[4], thigh[4], tta, ttb, lmask; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); for (j = 0; j < 16; j++) { for (i = 0; i < 4; i++) { c = (j << (i*4)); prod = gf->multiply.w32(gf, c, val); low[i][j] = (prod & 0xff); high[i][j] = (prod >> 8); } } for (i = 0; i < 4; i++) { tlow[i] = _mm_loadu_si128((__m128i *)low[i]); thigh[i] = _mm_loadu_si128((__m128i *)high[i]); } s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top64 = (uint64_t *) rd.d_top; mask = _mm_set1_epi8 (0x0f); lmask = _mm_set1_epi16 (0xff); if (xor) { while (d64 != top64) { ta = _mm_load_si128((__m128i *) s64); tb = _mm_load_si128((__m128i *) (s64+2)); tta = _mm_srli_epi16(ta, 8); ttb = _mm_srli_epi16(tb, 8); tpl = _mm_and_si128(tb, lmask); tph = _mm_and_si128(ta, lmask); tb = _mm_packus_epi16(tpl, tph); ta = _mm_packus_epi16(ttb, tta); ti = _mm_and_si128 (mask, tb); tph = _mm_shuffle_epi8 (thigh[0], ti); tpl = _mm_shuffle_epi8 (tlow[0], ti); tb = _mm_srli_epi16(tb, 4); ti = _mm_and_si128 (mask, tb); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[1], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[1], ti), tph); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[2], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[2], ti), tph); ta = _mm_srli_epi16(ta, 4); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[3], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[3], ti), tph); ta = _mm_unpackhi_epi8(tpl, tph); tb = _mm_unpacklo_epi8(tpl, tph); tta = _mm_load_si128((__m128i *) d64); ta = _mm_xor_si128(ta, tta); ttb = _mm_load_si128((__m128i *) (d64+2)); tb = _mm_xor_si128(tb, ttb); _mm_store_si128 ((__m128i *)d64, ta); _mm_store_si128 ((__m128i *)(d64+2), tb); d64 += 4; s64 += 4; } } else { while (d64 != top64) { ta = _mm_load_si128((__m128i *) s64); tb = _mm_load_si128((__m128i *) (s64+2)); tta = _mm_srli_epi16(ta, 8); ttb = _mm_srli_epi16(tb, 8); tpl = _mm_and_si128(tb, lmask); tph = _mm_and_si128(ta, lmask); tb = _mm_packus_epi16(tpl, tph); ta = _mm_packus_epi16(ttb, tta); ti = _mm_and_si128 (mask, tb); tph = _mm_shuffle_epi8 (thigh[0], ti); tpl = _mm_shuffle_epi8 (tlow[0], ti); tb = _mm_srli_epi16(tb, 4); ti = _mm_and_si128 (mask, tb); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[1], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[1], ti), tph); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[2], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[2], ti), tph); ta = _mm_srli_epi16(ta, 4); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[3], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[3], ti), tph); ta = _mm_unpackhi_epi8(tpl, tph); tb = _mm_unpacklo_epi8(tpl, tph); _mm_store_si128 ((__m128i *)d64, ta); _mm_store_si128 ((__m128i *)(d64+2), tb); d64 += 4; s64 += 4; } } gf_do_final_region_alignment(&rd); #endif } static void gf_w16_split_4_16_lazy_sse_altmap_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { #ifdef INTEL_SSSE3 uint64_t i, j, *s64, *d64, *top64;; uint64_t c, prod; uint8_t low[4][16]; uint8_t high[4][16]; gf_region_data rd; __m128i mask, ta, tb, ti, tpl, tph, tlow[4], thigh[4]; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); for (j = 0; j < 16; j++) { for (i = 0; i < 4; i++) { c = (j << (i*4)); prod = gf->multiply.w32(gf, c, val); low[i][j] = (prod & 0xff); high[i][j] = (prod >> 8); } } for (i = 0; i < 4; i++) { tlow[i] = _mm_loadu_si128((__m128i *)low[i]); thigh[i] = _mm_loadu_si128((__m128i *)high[i]); } s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; top64 = (uint64_t *) rd.d_top; mask = _mm_set1_epi8 (0x0f); if (xor) { while (d64 != top64) { ta = _mm_load_si128((__m128i *) s64); tb = _mm_load_si128((__m128i *) (s64+2)); ti = _mm_and_si128 (mask, tb); tph = _mm_shuffle_epi8 (thigh[0], ti); tpl = _mm_shuffle_epi8 (tlow[0], ti); tb = _mm_srli_epi16(tb, 4); ti = _mm_and_si128 (mask, tb); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[1], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[1], ti), tph); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[2], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[2], ti), tph); ta = _mm_srli_epi16(ta, 4); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[3], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[3], ti), tph); ta = _mm_load_si128((__m128i *) d64); tph = _mm_xor_si128(tph, ta); _mm_store_si128 ((__m128i *)d64, tph); tb = _mm_load_si128((__m128i *) (d64+2)); tpl = _mm_xor_si128(tpl, tb); _mm_store_si128 ((__m128i *)(d64+2), tpl); d64 += 4; s64 += 4; } } else { while (d64 != top64) { ta = _mm_load_si128((__m128i *) s64); tb = _mm_load_si128((__m128i *) (s64+2)); ti = _mm_and_si128 (mask, tb); tph = _mm_shuffle_epi8 (thigh[0], ti); tpl = _mm_shuffle_epi8 (tlow[0], ti); tb = _mm_srli_epi16(tb, 4); ti = _mm_and_si128 (mask, tb); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[1], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[1], ti), tph); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[2], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[2], ti), tph); ta = _mm_srli_epi16(ta, 4); ti = _mm_and_si128 (mask, ta); tpl = _mm_xor_si128(_mm_shuffle_epi8 (tlow[3], ti), tpl); tph = _mm_xor_si128(_mm_shuffle_epi8 (thigh[3], ti), tph); _mm_store_si128 ((__m128i *)d64, tph); _mm_store_si128 ((__m128i *)(d64+2), tpl); d64 += 4; s64 += 4; } } gf_do_final_region_alignment(&rd); #endif } uint32_t gf_w16_split_8_8_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t alow, blow; struct gf_w16_split_8_8_data *d8; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; d8 = (struct gf_w16_split_8_8_data *) h->private; alow = a & 0xff; blow = b & 0xff; a >>= 8; b >>= 8; return d8->tables[0][alow][blow] ^ d8->tables[1][alow][b] ^ d8->tables[1][a][blow] ^ d8->tables[2][a][b]; } static int gf_w16_split_init(gf_t *gf) { gf_internal_t *h; struct gf_w16_split_8_8_data *d8; int i, j, exp, issse3; uint32_t p, basep; h = (gf_internal_t *) gf->scratch; issse3 = 0; #ifdef INTEL_SSSE3 issse3 = 1; #endif if (h->arg1 == 8 && h->arg2 == 8) { d8 = (struct gf_w16_split_8_8_data *) h->private; basep = 1; for (exp = 0; exp < 3; exp++) { for (j = 0; j < 256; j++) d8->tables[exp][0][j] = 0; for (i = 0; i < 256; i++) d8->tables[exp][i][0] = 0; d8->tables[exp][1][1] = basep; for (i = 2; i < 256; i++) { if (i&1) { p = d8->tables[exp][i^1][1]; d8->tables[exp][i][1] = p ^ basep; } else { p = d8->tables[exp][i>>1][1]; d8->tables[exp][i][1] = GF_MULTBY_TWO(p); } } for (i = 1; i < 256; i++) { p = d8->tables[exp][i][1]; for (j = 1; j < 256; j++) { if (j&1) { d8->tables[exp][i][j] = d8->tables[exp][i][j^1] ^ p; } else { d8->tables[exp][i][j] = GF_MULTBY_TWO(d8->tables[exp][i][j>>1]); } } } for (i = 0; i < 8; i++) basep = GF_MULTBY_TWO(basep); } gf->multiply.w32 = gf_w16_split_8_8_multiply; gf->multiply_region.w32 = gf_w16_split_8_16_lazy_multiply_region; return 1; } /* We'll be using LOG for multiplication, unless the pp isn't primitive. In that case, we'll be using SHIFT. */ gf_w16_log_init(gf); /* Defaults */ if (issse3) { gf->multiply_region.w32 = gf_w16_split_4_16_lazy_sse_multiply_region; } else { gf->multiply_region.w32 = gf_w16_split_8_16_lazy_multiply_region; } if ((h->arg1 == 8 && h->arg2 == 16) || (h->arg2 == 8 && h->arg1 == 16)) { gf->multiply_region.w32 = gf_w16_split_8_16_lazy_multiply_region; } else if ((h->arg1 == 4 && h->arg2 == 16) || (h->arg2 == 4 && h->arg1 == 16)) { if (issse3) { if(h->region_type & GF_REGION_ALTMAP && h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w16_split_4_16_lazy_nosse_altmap_multiply_region; else if(h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w16_split_4_16_lazy_multiply_region; else if(h->region_type & GF_REGION_ALTMAP) gf->multiply_region.w32 = gf_w16_split_4_16_lazy_sse_altmap_multiply_region; } else { if(h->region_type & GF_REGION_SSE) return 0; else if(h->region_type & GF_REGION_ALTMAP) gf->multiply_region.w32 = gf_w16_split_4_16_lazy_nosse_altmap_multiply_region; else gf->multiply_region.w32 = gf_w16_split_4_16_lazy_multiply_region; } } return 1; } static int gf_w16_table_init(gf_t *gf) { gf_w16_log_init(gf); gf->multiply_region.w32 = gf_w16_table_lazy_multiply_region; return 1; } static void gf_w16_log_zero_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint16_t lv; int i; uint16_t *s16, *d16, *top16; struct gf_w16_zero_logtable_data *ltd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); ltd = (struct gf_w16_zero_logtable_data*) ((gf_internal_t *) gf->scratch)->private; s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; top16 = (uint16_t *) rd.d_top; bytes = top16 - d16; lv = ltd->log_tbl[val]; if (xor) { for (i = 0; i < bytes; i++) { d16[i] ^= (ltd->antilog_tbl[lv + ltd->log_tbl[s16[i]]]); } } else { for (i = 0; i < bytes; i++) { d16[i] = (ltd->antilog_tbl[lv + ltd->log_tbl[s16[i]]]); } } /* This isn't necessary. */ gf_do_final_region_alignment(&rd); } /* Here -- double-check Kevin */ static inline gf_val_32_t gf_w16_log_zero_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { struct gf_w16_zero_logtable_data *ltd; ltd = (struct gf_w16_zero_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return ltd->antilog_tbl[ltd->log_tbl[a] + ltd->log_tbl[b]]; } static inline gf_val_32_t gf_w16_log_zero_divide (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { int log_sum = 0; struct gf_w16_zero_logtable_data *ltd; if (a == 0 || b == 0) return 0; ltd = (struct gf_w16_zero_logtable_data *) ((gf_internal_t *) gf->scratch)->private; log_sum = ltd->log_tbl[a] - ltd->log_tbl[b] + (GF_MULT_GROUP_SIZE); return (ltd->antilog_tbl[log_sum]); } static gf_val_32_t gf_w16_log_zero_inverse (gf_t *gf, gf_val_32_t a) { struct gf_w16_zero_logtable_data *ltd; ltd = (struct gf_w16_zero_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return (ltd->inv_tbl[a]); } static inline gf_val_32_t gf_w16_bytwo_p_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, pmask, amask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; pmask = 0x8000; amask = 0x8000; while (amask != 0) { if (prod & pmask) { prod = ((prod << 1) ^ pp); } else { prod <<= 1; } if (a & amask) prod ^= b; amask >>= 1; } return prod; } static inline gf_val_32_t gf_w16_bytwo_b_multiply (gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint32_t prod, pp, bmask; gf_internal_t *h; h = (gf_internal_t *) gf->scratch; pp = h->prim_poly; prod = 0; bmask = 0x8000; while (1) { if (a & 1) prod ^= b; a >>= 1; if (a == 0) return prod; if (b & bmask) { b = ((b << 1) ^ pp); } else { b <<= 1; } } } static void gf_w16_bytwo_p_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, prod, amask; gf_region_data rd; struct gf_w16_bytwo_data *btd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_w16_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 8); gf_do_initial_region_alignment(&rd); s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; if (xor) { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x8000; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 ^= prod; d64++; s64++; } } else { while (s64 < (uint64_t *) rd.s_top) { prod = 0; amask = 0x8000; ta = *s64; while (amask != 0) { AB2(btd->prim_poly, btd->mask1, btd->mask2, prod, t1, t2); if (val & amask) prod ^= ta; amask >>= 1; } *d64 = prod; d64++; s64++; } } gf_do_final_region_alignment(&rd); } #define BYTWO_P_ONESTEP {\ SSE_AB2(pp, m1 ,m2, prod, t1, t2); \ t1 = _mm_and_si128(v, one); \ t1 = _mm_sub_epi16(t1, one); \ t1 = _mm_and_si128(t1, ta); \ prod = _mm_xor_si128(prod, t1); \ v = _mm_srli_epi64(v, 1); } #ifdef INTEL_SSE2 static void gf_w16_bytwo_p_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int i; uint8_t *s8, *d8; uint32_t vrev; __m128i pp, m1, m2, ta, prod, t1, t2, tp, one, v; struct gf_w16_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } btd = (struct gf_w16_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); vrev = 0; for (i = 0; i < 16; i++) { vrev <<= 1; if (!(val & (1 << i))) vrev |= 1; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi16(btd->prim_poly&0xffff); m1 = _mm_set1_epi16((btd->mask1)&0xffff); m2 = _mm_set1_epi16((btd->mask2)&0xffff); one = _mm_set1_epi16(1); while (d8 < (uint8_t *) rd.d_top) { prod = _mm_setzero_si128(); v = _mm_set1_epi16(vrev); ta = _mm_load_si128((__m128i *) s8); tp = (!xor) ? _mm_setzero_si128() : _mm_load_si128((__m128i *) d8); BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; BYTWO_P_ONESTEP; _mm_store_si128((__m128i *) d8, _mm_xor_si128(prod, tp)); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif #ifdef INTEL_SSE2 static void gf_w16_bytwo_b_sse_region_2_noxor(gf_region_data *rd, struct gf_w16_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi16(btd->prim_poly&0xffff); m1 = _mm_set1_epi16((btd->mask1)&0xffff); m2 = _mm_set1_epi16((btd->mask2)&0xffff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); _mm_store_si128((__m128i *)d8, va); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w16_bytwo_b_sse_region_2_xor(gf_region_data *rd, struct gf_w16_bytwo_data *btd) { uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; s8 = (uint8_t *) rd->s_start; d8 = (uint8_t *) rd->d_start; pp = _mm_set1_epi16(btd->prim_poly&0xffff); m1 = _mm_set1_epi16((btd->mask1)&0xffff); m2 = _mm_set1_epi16((btd->mask2)&0xffff); while (d8 < (uint8_t *) rd->d_top) { va = _mm_load_si128 ((__m128i *)(s8)); SSE_AB2(pp, m1, m2, va, t1, t2); vb = _mm_load_si128 ((__m128i *)(d8)); vb = _mm_xor_si128(vb, va); _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } } #endif #ifdef INTEL_SSE2 static void gf_w16_bytwo_b_sse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { int itb; uint8_t *d8, *s8; __m128i pp, m1, m2, t1, t2, va, vb; struct gf_w16_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); btd = (struct gf_w16_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; if (val == 2) { if (xor) { gf_w16_bytwo_b_sse_region_2_xor(&rd, btd); } else { gf_w16_bytwo_b_sse_region_2_noxor(&rd, btd); } gf_do_final_region_alignment(&rd); return; } s8 = (uint8_t *) rd.s_start; d8 = (uint8_t *) rd.d_start; pp = _mm_set1_epi16(btd->prim_poly&0xffff); m1 = _mm_set1_epi16((btd->mask1)&0xffff); m2 = _mm_set1_epi16((btd->mask2)&0xffff); while (d8 < (uint8_t *) rd.d_top) { va = _mm_load_si128 ((__m128i *)(s8)); vb = (!xor) ? _mm_setzero_si128() : _mm_load_si128 ((__m128i *)(d8)); itb = val; while (1) { if (itb & 1) vb = _mm_xor_si128(vb, va); itb >>= 1; if (itb == 0) break; SSE_AB2(pp, m1, m2, va, t1, t2); } _mm_store_si128((__m128i *)d8, vb); d8 += 16; s8 += 16; } gf_do_final_region_alignment(&rd); } #endif static void gf_w16_bytwo_b_nosse_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint64_t *s64, *d64, t1, t2, ta, tb, prod; struct gf_w16_bytwo_data *btd; gf_region_data rd; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 16); gf_do_initial_region_alignment(&rd); btd = (struct gf_w16_bytwo_data *) ((gf_internal_t *) (gf->scratch))->private; s64 = (uint64_t *) rd.s_start; d64 = (uint64_t *) rd.d_start; switch (val) { case 2: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 3: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = (ta ^ prod); d64++; s64++; } } break; case 4: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= ta; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta; d64++; s64++; } } break; case 5: if (xor) { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 ^= (ta ^ prod); d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { ta = *s64; prod = ta; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); *d64 = ta ^ prod; d64++; s64++; } } default: if (xor) { while (d64 < (uint64_t *) rd.d_top) { prod = *d64 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } else { while (d64 < (uint64_t *) rd.d_top) { prod = 0 ; ta = *s64; tb = val; while (1) { if (tb & 1) prod ^= ta; tb >>= 1; if (tb == 0) break; AB2(btd->prim_poly, btd->mask1, btd->mask2, ta, t1, t2); } *d64 = prod; d64++; s64++; } } break; } gf_do_final_region_alignment(&rd); } static int gf_w16_bytwo_init(gf_t *gf) { gf_internal_t *h; uint64_t ip, m1, m2; struct gf_w16_bytwo_data *btd; h = (gf_internal_t *) gf->scratch; btd = (struct gf_w16_bytwo_data *) (h->private); ip = h->prim_poly & 0xffff; m1 = 0xfffe; m2 = 0x8000; btd->prim_poly = 0; btd->mask1 = 0; btd->mask2 = 0; while (ip != 0) { btd->prim_poly |= ip; btd->mask1 |= m1; btd->mask2 |= m2; ip <<= GF_FIELD_WIDTH; m1 <<= GF_FIELD_WIDTH; m2 <<= GF_FIELD_WIDTH; } if (h->mult_type == GF_MULT_BYTWO_p) { gf->multiply.w32 = gf_w16_bytwo_p_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w16_bytwo_p_nosse_multiply_region; else gf->multiply_region.w32 = gf_w16_bytwo_p_sse_multiply_region; #else gf->multiply_region.w32 = gf_w16_bytwo_p_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } else { gf->multiply.w32 = gf_w16_bytwo_b_multiply; #ifdef INTEL_SSE2 if (h->region_type & GF_REGION_NOSSE) gf->multiply_region.w32 = gf_w16_bytwo_b_nosse_multiply_region; else gf->multiply_region.w32 = gf_w16_bytwo_b_sse_multiply_region; #else gf->multiply_region.w32 = gf_w16_bytwo_b_nosse_multiply_region; if(h->region_type & GF_REGION_SSE) return 0; #endif } return 1; } static int gf_w16_log_zero_init(gf_t *gf) { gf_internal_t *h; struct gf_w16_zero_logtable_data *ltd; int i, b; h = (gf_internal_t *) gf->scratch; ltd = h->private; ltd->log_tbl[0] = (-GF_MULT_GROUP_SIZE) + 1; bzero(&(ltd->_antilog_tbl[0]), sizeof(ltd->_antilog_tbl)); ltd->antilog_tbl = &(ltd->_antilog_tbl[GF_FIELD_SIZE * 2]); b = 1; for (i = 0; i < GF_MULT_GROUP_SIZE; i++) { ltd->log_tbl[b] = (uint16_t)i; ltd->antilog_tbl[i] = (uint16_t)b; ltd->antilog_tbl[i+GF_MULT_GROUP_SIZE] = (uint16_t)b; b <<= 1; if (b & GF_FIELD_SIZE) { b = b ^ h->prim_poly; } } ltd->inv_tbl[0] = 0; /* Not really, but we need to fill it with something */ ltd->inv_tbl[1] = 1; for (i = 2; i < GF_FIELD_SIZE; i++) { ltd->inv_tbl[i] = ltd->antilog_tbl[GF_MULT_GROUP_SIZE-ltd->log_tbl[i]]; } gf->inverse.w32 = gf_w16_log_zero_inverse; gf->divide.w32 = gf_w16_log_zero_divide; gf->multiply.w32 = gf_w16_log_zero_multiply; gf->multiply_region.w32 = gf_w16_log_zero_multiply_region; return 1; } static gf_val_32_t gf_w16_composite_multiply_recursive(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t b0 = b & 0x00ff; uint8_t b1 = (b & 0xff00) >> 8; uint8_t a0 = a & 0x00ff; uint8_t a1 = (a & 0xff00) >> 8; uint8_t a1b1; uint16_t rv; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); rv = ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 8)); return rv; } static gf_val_32_t gf_w16_composite_multiply_inline(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { gf_internal_t *h = (gf_internal_t *) gf->scratch; uint8_t b0 = b & 0x00ff; uint8_t b1 = (b & 0xff00) >> 8; uint8_t a0 = a & 0x00ff; uint8_t a1 = (a & 0xff00) >> 8; uint8_t a1b1, *mt; uint16_t rv; struct gf_w16_composite_data *cd; cd = (struct gf_w16_composite_data *) h->private; mt = cd->mult_table; a1b1 = GF_W8_INLINE_MULTDIV(mt, a1, b1); rv = ((GF_W8_INLINE_MULTDIV(mt, a0, b0) ^ a1b1) | ((GF_W8_INLINE_MULTDIV(mt, a1, b0) ^ GF_W8_INLINE_MULTDIV(mt, a0, b1) ^ GF_W8_INLINE_MULTDIV(mt, a1b1, h->prim_poly)) << 8)); return rv; } /* * Composite field division trick (explained in 2007 tech report) * * Compute a / b = a*b^-1, where p(x) = x^2 + sx + 1 * * let c = b^-1 * * c*b = (s*b1c1+b1c0+b0c1)x+(b1c1+b0c0) * * want (s*b1c1+b1c0+b0c1) = 0 and (b1c1+b0c0) = 1 * * let d = b1c1 and d+1 = b0c0 * * solve s*b1c1+b1c0+b0c1 = 0 * * solution: d = (b1b0^-1)(b1b0^-1+b0b1^-1+s)^-1 * * c0 = (d+1)b0^-1 * c1 = d*b1^-1 * * a / b = a * c */ static gf_val_32_t gf_w16_composite_inverse(gf_t *gf, gf_val_32_t a) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t a0 = a & 0x00ff; uint8_t a1 = (a & 0xff00) >> 8; uint8_t c0, c1, d, tmp; uint16_t c; uint8_t a0inv, a1inv; if (a0 == 0) { a1inv = base_gf->inverse.w32(base_gf, a1); c0 = base_gf->multiply.w32(base_gf, a1inv, h->prim_poly); c1 = a1inv; } else if (a1 == 0) { c0 = base_gf->inverse.w32(base_gf, a0); c1 = 0; } else { a1inv = base_gf->inverse.w32(base_gf, a1); a0inv = base_gf->inverse.w32(base_gf, a0); d = base_gf->multiply.w32(base_gf, a1, a0inv); tmp = (base_gf->multiply.w32(base_gf, a1, a0inv) ^ base_gf->multiply.w32(base_gf, a0, a1inv) ^ h->prim_poly); tmp = base_gf->inverse.w32(base_gf, tmp); d = base_gf->multiply.w32(base_gf, d, tmp); c0 = base_gf->multiply.w32(base_gf, (d^1), a0inv); c1 = base_gf->multiply.w32(base_gf, d, a1inv); } c = c0 | (c1 << 8); return c; } static void gf_w16_composite_multiply_region(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t b0 = val & 0x00ff; uint8_t b1 = (val & 0xff00) >> 8; uint16_t *s16, *d16, *top; uint8_t a0, a1, a1b1, *mt; gf_region_data rd; struct gf_w16_composite_data *cd; cd = (struct gf_w16_composite_data *) h->private; mt = cd->mult_table; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); s16 = rd.s_start; d16 = rd.d_start; top = rd.d_top; if (mt == NULL) { if (xor) { while (d16 < top) { a0 = (*s16) & 0x00ff; a1 = ((*s16) & 0xff00) >> 8; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); (*d16) ^= ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 8)); s16++; d16++; } } else { while (d16 < top) { a0 = (*s16) & 0x00ff; a1 = ((*s16) & 0xff00) >> 8; a1b1 = base_gf->multiply.w32(base_gf, a1, b1); (*d16) = ((base_gf->multiply.w32(base_gf, a0, b0) ^ a1b1) | ((base_gf->multiply.w32(base_gf, a1, b0) ^ base_gf->multiply.w32(base_gf, a0, b1) ^ base_gf->multiply.w32(base_gf, a1b1, h->prim_poly)) << 8)); s16++; d16++; } } } else { if (xor) { while (d16 < top) { a0 = (*s16) & 0x00ff; a1 = ((*s16) & 0xff00) >> 8; a1b1 = GF_W8_INLINE_MULTDIV(mt, a1, b1); (*d16) ^= ((GF_W8_INLINE_MULTDIV(mt, a0, b0) ^ a1b1) | ((GF_W8_INLINE_MULTDIV(mt, a1, b0) ^ GF_W8_INLINE_MULTDIV(mt, a0, b1) ^ GF_W8_INLINE_MULTDIV(mt, a1b1, h->prim_poly)) << 8)); s16++; d16++; } } else { while (d16 < top) { a0 = (*s16) & 0x00ff; a1 = ((*s16) & 0xff00) >> 8; a1b1 = GF_W8_INLINE_MULTDIV(mt, a1, b1); (*d16) = ((GF_W8_INLINE_MULTDIV(mt, a0, b0) ^ a1b1) | ((GF_W8_INLINE_MULTDIV(mt, a1, b0) ^ GF_W8_INLINE_MULTDIV(mt, a0, b1) ^ GF_W8_INLINE_MULTDIV(mt, a1b1, h->prim_poly)) << 8)); s16++; d16++; } } } } static void gf_w16_composite_multiply_region_alt(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { gf_internal_t *h = (gf_internal_t *) gf->scratch; gf_t *base_gf = h->base_gf; uint8_t val0 = val & 0x00ff; uint8_t val1 = (val & 0xff00) >> 8; gf_region_data rd; int sub_reg_size; uint8_t *slow, *shigh; uint8_t *dlow, *dhigh, *top;; /* JSP: I want the two pointers aligned wrt each other on 16 byte boundaries. So I'm going to make sure that the area on which the two operate is a multiple of 32. Of course, that junks up the mapping, but so be it -- that's why we have extract_word.... */ gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 32); gf_do_initial_region_alignment(&rd); slow = (uint8_t *) rd.s_start; dlow = (uint8_t *) rd.d_start; top = (uint8_t *) rd.d_top; sub_reg_size = (top - dlow)/2; shigh = slow + sub_reg_size; dhigh = dlow + sub_reg_size; base_gf->multiply_region.w32(base_gf, slow, dlow, val0, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, shigh, dlow, val1, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, slow, dhigh, val1, sub_reg_size, xor); base_gf->multiply_region.w32(base_gf, shigh, dhigh, val0, sub_reg_size, 1); base_gf->multiply_region.w32(base_gf, shigh, dhigh, base_gf->multiply.w32(base_gf, h->prim_poly, val1), sub_reg_size, 1); gf_do_final_region_alignment(&rd); } static int gf_w16_composite_init(gf_t *gf) { gf_internal_t *h = (gf_internal_t *) gf->scratch; struct gf_w16_composite_data *cd; if (h->base_gf == NULL) return 0; cd = (struct gf_w16_composite_data *) h->private; cd->mult_table = gf_w8_get_mult_table(h->base_gf); if (h->region_type & GF_REGION_ALTMAP) { gf->multiply_region.w32 = gf_w16_composite_multiply_region_alt; } else { gf->multiply_region.w32 = gf_w16_composite_multiply_region; } if (cd->mult_table == NULL) { gf->multiply.w32 = gf_w16_composite_multiply_recursive; } else { gf->multiply.w32 = gf_w16_composite_multiply_inline; } gf->divide.w32 = NULL; gf->inverse.w32 = gf_w16_composite_inverse; return 1; } static void gf_w16_group_4_set_shift_tables(uint16_t *shift, uint16_t val, gf_internal_t *h) { int i, j; shift[0] = 0; for (i = 0; i < 16; i += 2) { j = (shift[i>>1] << 1); if (j & (1 << 16)) j ^= h->prim_poly; shift[i] = j; shift[i^1] = j^val; } } static inline gf_val_32_t gf_w16_group_4_4_multiply(gf_t *gf, gf_val_32_t a, gf_val_32_t b) { uint16_t p, l, ind, r, a16; struct gf_w16_group_4_4_data *d44; gf_internal_t *h = (gf_internal_t *) gf->scratch; d44 = (struct gf_w16_group_4_4_data *) h->private; gf_w16_group_4_set_shift_tables(d44->shift, b, h); a16 = a; ind = a16 >> 12; a16 <<= 4; p = d44->shift[ind]; r = p & 0xfff; l = p >> 12; ind = a16 >> 12; a16 <<= 4; p = (d44->shift[ind] ^ d44->reduce[l] ^ (r << 4)); r = p & 0xfff; l = p >> 12; ind = a16 >> 12; a16 <<= 4; p = (d44->shift[ind] ^ d44->reduce[l] ^ (r << 4)); r = p & 0xfff; l = p >> 12; ind = a16 >> 12; p = (d44->shift[ind] ^ d44->reduce[l] ^ (r << 4)); return p; } static void gf_w16_group_4_4_region_multiply(gf_t *gf, void *src, void *dest, gf_val_32_t val, int bytes, int xor) { uint16_t p, l, ind, r, a16, p16; struct gf_w16_group_4_4_data *d44; gf_region_data rd; uint16_t *s16, *d16, *top; if (val == 0) { gf_multby_zero(dest, bytes, xor); return; } if (val == 1) { gf_multby_one(src, dest, bytes, xor); return; } gf_internal_t *h = (gf_internal_t *) gf->scratch; d44 = (struct gf_w16_group_4_4_data *) h->private; gf_w16_group_4_set_shift_tables(d44->shift, val, h); gf_set_region_data(&rd, gf, src, dest, bytes, val, xor, 2); gf_do_initial_region_alignment(&rd); s16 = (uint16_t *) rd.s_start; d16 = (uint16_t *) rd.d_start; top = (uint16_t *) rd.d_top; while (d16 < top) { p = 0; a16 = *s16; p16 = (xor) ? *d16 : 0; ind = a16 >> 12; a16 <<= 4; p = d44->shift[ind]; r = p & 0xfff; l = p >> 12; ind = a16 >> 12; a16 <<= 4; p = (d44->shift[ind] ^ d44->reduce[l] ^ (r << 4)); r = p & 0xfff; l = p >> 12; ind = a16 >> 12; a16 <<= 4; p = (d44->shift[ind] ^ d44->reduce[l] ^ (r << 4)); r = p & 0xfff; l = p >> 12; ind = a16 >> 12; p = (d44->shift[ind] ^ d44->reduce[l] ^ (r << 4)); p ^= p16; *d16 = p; d16++; s16++; } gf_do_final_region_alignment(&rd); } static int gf_w16_group_init(gf_t *gf) { int i, j, p; struct gf_w16_group_4_4_data *d44; gf_internal_t *h = (gf_internal_t *) gf->scratch; d44 = (struct gf_w16_group_4_4_data *) h->private; d44->reduce[0] = 0; for (i = 0; i < 16; i++) { p = 0; for (j = 0; j < 4; j++) { if (i & (1 << j)) p ^= (h->prim_poly << j); } d44->reduce[p>>16] = (p&0xffff); } gf->multiply.w32 = gf_w16_group_4_4_multiply; gf->divide.w32 = NULL; gf->inverse.w32 = NULL; gf->multiply_region.w32 = gf_w16_group_4_4_region_multiply; return 1; } int gf_w16_scratch_size(int mult_type, int region_type, int divide_type, int arg1, int arg2) { switch(mult_type) { case GF_MULT_TABLE: return sizeof(gf_internal_t) + sizeof(struct gf_w16_lazytable_data) + 64; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: return sizeof(gf_internal_t) + sizeof(struct gf_w16_bytwo_data); break; case GF_MULT_LOG_ZERO: return sizeof(gf_internal_t) + sizeof(struct gf_w16_zero_logtable_data) + 64; break; case GF_MULT_LOG_TABLE: return sizeof(gf_internal_t) + sizeof(struct gf_w16_logtable_data) + 64; break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if (arg1 == 8 && arg2 == 8) { return sizeof(gf_internal_t) + sizeof(struct gf_w16_split_8_8_data) + 64; } else if ((arg1 == 8 && arg2 == 16) || (arg2 == 8 && arg1 == 16)) { return sizeof(gf_internal_t) + sizeof(struct gf_w16_logtable_data) + 64; } else if (mult_type == GF_MULT_DEFAULT || (arg1 == 4 && arg2 == 16) || (arg2 == 4 && arg1 == 16)) { return sizeof(gf_internal_t) + sizeof(struct gf_w16_logtable_data) + 64; } return 0; break; case GF_MULT_GROUP: return sizeof(gf_internal_t) + sizeof(struct gf_w16_group_4_4_data) + 64; break; case GF_MULT_CARRY_FREE: return sizeof(gf_internal_t); break; case GF_MULT_SHIFT: return sizeof(gf_internal_t); break; case GF_MULT_COMPOSITE: return sizeof(gf_internal_t) + sizeof(struct gf_w16_composite_data) + 64; break; default: return 0; } return 0; } int gf_w16_init(gf_t *gf) { gf_internal_t *h; h = (gf_internal_t *) gf->scratch; /* Allen: set default primitive polynomial / irreducible polynomial if needed */ if (h->prim_poly == 0) { if (h->mult_type == GF_MULT_COMPOSITE) { h->prim_poly = gf_composite_get_default_poly(h->base_gf); if (h->prim_poly == 0) return 0; } else { /* Allen: use the following primitive polynomial to make carryless multiply work more efficiently for GF(2^16). h->prim_poly = 0x1002d; The following is the traditional primitive polynomial for GF(2^16) */ h->prim_poly = 0x1100b; } } if (h->mult_type != GF_MULT_COMPOSITE) h->prim_poly |= (1 << 16); gf->multiply.w32 = NULL; gf->divide.w32 = NULL; gf->inverse.w32 = NULL; gf->multiply_region.w32 = NULL; switch(h->mult_type) { case GF_MULT_LOG_ZERO: if (gf_w16_log_zero_init(gf) == 0) return 0; break; case GF_MULT_LOG_TABLE: if (gf_w16_log_init(gf) == 0) return 0; break; case GF_MULT_DEFAULT: case GF_MULT_SPLIT_TABLE: if (gf_w16_split_init(gf) == 0) return 0; break; case GF_MULT_TABLE: if (gf_w16_table_init(gf) == 0) return 0; break; case GF_MULT_CARRY_FREE: if (gf_w16_cfm_init(gf) == 0) return 0; break; case GF_MULT_SHIFT: if (gf_w16_shift_init(gf) == 0) return 0; break; case GF_MULT_COMPOSITE: if (gf_w16_composite_init(gf) == 0) return 0; break; case GF_MULT_BYTWO_p: case GF_MULT_BYTWO_b: if (gf_w16_bytwo_init(gf) == 0) return 0; break; case GF_MULT_GROUP: if (gf_w16_group_init(gf) == 0) return 0; break; default: return 0; } if (h->divide_type == GF_DIVIDE_EUCLID) { gf->divide.w32 = gf_w16_divide_from_inverse; gf->inverse.w32 = gf_w16_euclid; } else if (h->divide_type == GF_DIVIDE_MATRIX) { gf->divide.w32 = gf_w16_divide_from_inverse; gf->inverse.w32 = gf_w16_matrix; } if (gf->divide.w32 == NULL) { gf->divide.w32 = gf_w16_divide_from_inverse; if (gf->inverse.w32 == NULL) gf->inverse.w32 = gf_w16_euclid; } if (gf->inverse.w32 == NULL) gf->inverse.w32 = gf_w16_inverse_from_divide; if (h->region_type & GF_REGION_ALTMAP) { if (h->mult_type == GF_MULT_COMPOSITE) { gf->extract_word.w32 = gf_w16_composite_extract_word; } else { gf->extract_word.w32 = gf_w16_split_extract_word; } } else if (h->region_type == GF_REGION_CAUCHY) { gf->multiply_region.w32 = gf_wgen_cauchy_region; gf->extract_word.w32 = gf_wgen_extract_word; } else { gf->extract_word.w32 = gf_w16_extract_word; } if (gf->multiply_region.w32 == NULL) { gf->multiply_region.w32 = gf_w16_multiply_region_from_single; } return 1; } /* Inline setup functions */ uint16_t *gf_w16_get_log_table(gf_t *gf) { struct gf_w16_logtable_data *ltd; if (gf->multiply.w32 == gf_w16_log_multiply) { ltd = (struct gf_w16_logtable_data *) ((gf_internal_t *) gf->scratch)->private; return (uint16_t *) ltd->log_tbl; } return NULL; } uint16_t *gf_w16_get_mult_alog_table(gf_t *gf) { gf_internal_t *h; struct gf_w16_logtable_data *ltd; h = (gf_internal_t *) gf->scratch; if (gf->multiply.w32 == gf_w16_log_multiply) { ltd = (struct gf_w16_logtable_data *) h->private; return (uint16_t *) ltd->antilog_tbl; } return NULL; } uint16_t *gf_w16_get_div_alog_table(gf_t *gf) { gf_internal_t *h; struct gf_w16_logtable_data *ltd; h = (gf_internal_t *) gf->scratch; if (gf->multiply.w32 == gf_w16_log_multiply) { ltd = (struct gf_w16_logtable_data *) h->private; return (uint16_t *) ltd->d_antilog; } return NULL; } ceph-0.80.11/src/erasure-code/jerasure/ErasureCodePluginJerasure.cc0000664000175100017510000000547412623076744027264 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include "common/debug.h" #include "erasure-code/ErasureCodePlugin.h" #include "ErasureCodeJerasure.h" #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout) static ostream& _prefix(std::ostream* _dout) { return *_dout << "ErasureCodePluginJerasure: "; } class ErasureCodePluginJerasure : public ErasureCodePlugin { public: virtual int factory(const map ¶meters, ErasureCodeInterfaceRef *erasure_code) { ErasureCodeJerasure *interface; std::string t; if (parameters.find("technique") != parameters.end()) t = parameters.find("technique")->second; if (t == "reed_sol_van") { interface = new ErasureCodeJerasureReedSolomonVandermonde(); } else if (t == "reed_sol_r6_op") { interface = new ErasureCodeJerasureReedSolomonRAID6(); } else if (t == "cauchy_orig") { interface = new ErasureCodeJerasureCauchyOrig(); } else if (t == "cauchy_good") { interface = new ErasureCodeJerasureCauchyGood(); } else if (t == "liberation") { interface = new ErasureCodeJerasureLiberation(); } else if (t == "blaum_roth") { interface = new ErasureCodeJerasureBlaumRoth(); } else if (t == "liber8tion") { interface = new ErasureCodeJerasureLiber8tion(); } else { derr << "technique=" << t << " is not a valid coding technique. " << " Choose one of the following: " << "reed_sol_van, reed_sol_r6_op, cauchy_orig, " << "cauchy_good, liberation, blaum_roth, liber8tion" << dendl; return -ENOENT; } interface->init(parameters); *erasure_code = ErasureCodeInterfaceRef(interface); return 0; } }; extern "C" { #include "galois.h" extern gf_t *gfp_array[]; extern int gfp_is_composite[]; } int __erasure_code_init(char *plugin_name) { ErasureCodePluginRegistry &instance = ErasureCodePluginRegistry::instance(); int w[] = { 4, 8, 16, 32 }; for(int i = 0; i < 4; i++) { if (gfp_array[w[i]] == NULL) { gfp_array[w[i]] = (gf_t*)malloc(sizeof(gf_t)); assert(gfp_array[w[i]]); gfp_is_composite[w[i]] = 0; if (!gf_init_easy(gfp_array[w[i]], w[i])) { derr << "failed to gf_init_easy(" << w[i] << ")" << dendl; return -EINVAL; } } } return instance.add(plugin_name, new ErasureCodePluginJerasure()); } ceph-0.80.11/src/erasure-code/ErasureCodePlugin.cc0000664000175100017510000001020712623076744023731 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Cloudwatt * Copyright (C) 2014 Red Hat * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include #include #include "ErasureCodePlugin.h" #include "common/errno.h" #include "include/str_list.h" #define PLUGIN_PREFIX "libec_" #define PLUGIN_SUFFIX ".so" #define PLUGIN_INIT_FUNCTION "__erasure_code_init" ErasureCodePluginRegistry ErasureCodePluginRegistry::singleton; ErasureCodePluginRegistry::ErasureCodePluginRegistry() : lock("ErasureCodePluginRegistry::lock"), loading(false), disable_dlclose(false) { } ErasureCodePluginRegistry::~ErasureCodePluginRegistry() { if (disable_dlclose) return; for (std::map::iterator i = plugins.begin(); i != plugins.end(); ++i) { void *library = i->second->library; delete i->second; dlclose(library); } } int ErasureCodePluginRegistry::add(const std::string &name, ErasureCodePlugin* plugin) { if (plugins.find(name) != plugins.end()) return -EEXIST; plugins[name] = plugin; return 0; } ErasureCodePlugin *ErasureCodePluginRegistry::get(const std::string &name) { if (plugins.find(name) != plugins.end()) return plugins[name]; else return 0; } int ErasureCodePluginRegistry::factory(const std::string &plugin_name, const map ¶meters, ErasureCodeInterfaceRef *erasure_code, ostream &ss) { ErasureCodePlugin *plugin; { Mutex::Locker l(lock); int r = 0; plugin = get(plugin_name); if (plugin == 0) { loading = true; r = load(plugin_name, parameters, &plugin, ss); loading = false; if (r != 0) return r; } } return plugin->factory(parameters, erasure_code); } int ErasureCodePluginRegistry::load(const std::string &plugin_name, const map ¶meters, ErasureCodePlugin **plugin, ostream &ss) { assert(parameters.count("directory") != 0); std::string fname = parameters.find("directory")->second + "/" PLUGIN_PREFIX + plugin_name + PLUGIN_SUFFIX; void *library = dlopen(fname.c_str(), RTLD_NOW); if (!library) { ss << "load dlopen(" << fname << "): " << dlerror(); return -EIO; } int (*erasure_code_init)(const char *) = (int (*)(const char *))dlsym(library, PLUGIN_INIT_FUNCTION); if (erasure_code_init) { std::string name = plugin_name; int r = erasure_code_init(name.c_str()); if (r != 0) { ss << "erasure_code_init(" << plugin_name << "): " << cpp_strerror(r); dlclose(library); return r; } } else { ss << "load dlsym(" << fname << ", " << PLUGIN_INIT_FUNCTION << "): " << dlerror(); dlclose(library); return -ENOENT; } *plugin = get(plugin_name); if (*plugin == 0) { ss << "load " << PLUGIN_INIT_FUNCTION << "()" << "did not register " << plugin_name; dlclose(library); return -EBADF; } (*plugin)->library = library; ss << __func__ << ": " << plugin_name << " "; return 0; } int ErasureCodePluginRegistry::preload(const std::string &plugins, const std::string &directory, ostream &ss) { map profile; profile["directory"] = directory; list plugins_list; get_str_list(plugins, plugins_list); for (list::iterator i = plugins_list.begin(); i != plugins_list.end(); i++) { ErasureCodePlugin *plugin; int r = load(*i, profile, &plugin, ss); if (r) return r; ErasureCodeInterfaceRef erasure_code; profile["technique"] = "reed_sol_van"; r = plugin->factory(profile, &erasure_code); if (r) return r; } return 0; } ceph-0.80.11/src/erasure-code/Makefile.am0000664000175100017510000000062412623076744022100 0ustar jenkins-buildjenkins-build## erasure code plugins erasure_codelibdir = $(pkglibdir)/erasure-code erasure_codelib_LTLIBRARIES = include erasure-code/jerasure/Makefile.am liberasure_code_la_SOURCES = \ erasure-code/ErasureCodePlugin.cc if LINUX liberasure_code_la_LIBADD = -ldl endif # LINUX noinst_LTLIBRARIES += liberasure_code.la noinst_HEADERS += \ erasure-code/ErasureCodeInterface.h \ erasure-code/ErasureCodePlugin.h ceph-0.80.11/src/erasure-code/ErasureCodePlugin.h0000664000175100017510000000361212623076744023575 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #ifndef CEPH_ERASURE_CODE_PLUGIN_H #define CEPH_ERASURE_CODE_PLUGIN_H #include "common/Mutex.h" #include "ErasureCodeInterface.h" extern "C" { int __erasure_code_init(char *plugin_name); } namespace ceph { class ErasureCodePlugin { public: void *library; ErasureCodePlugin() : library(0) {} virtual ~ErasureCodePlugin() {} virtual int factory(const map ¶meters, ErasureCodeInterfaceRef *erasure_code) = 0; }; class ErasureCodePluginRegistry { public: Mutex lock; bool loading; bool disable_dlclose; std::map plugins; static ErasureCodePluginRegistry singleton; ErasureCodePluginRegistry(); ~ErasureCodePluginRegistry(); static ErasureCodePluginRegistry &instance() { return singleton; } int factory(const std::string &plugin, const map ¶meters, ErasureCodeInterfaceRef *erasure_code, ostream &ss); int add(const std::string &name, ErasureCodePlugin *plugin); ErasureCodePlugin *get(const std::string &name); int load(const std::string &plugin_name, const map ¶meters, ErasureCodePlugin **plugin, ostream &ss); int preload(const std::string &plugins, const std::string &directory, ostream &ss); }; } #endif ceph-0.80.11/src/ceph-rbdnamer0000775000175100017510000000042512623076744020122 0ustar jenkins-buildjenkins-build#!/bin/sh DEV=$1 NUM=`echo $DEV | sed 's#p.*##g' | tr -d 'a-z'` POOL=`cat /sys/devices/rbd/$NUM/pool` IMAGE=`cat /sys/devices/rbd/$NUM/name` SNAP=`cat /sys/devices/rbd/$NUM/current_snap` if [ "$SNAP" = "-" ]; then echo -n "$POOL $IMAGE" else echo -n "$POOL $IMAGE@$SNAP" fi ceph-0.80.11/src/ceph-run0000775000175100017510000000045012623076744017132 0ustar jenkins-buildjenkins-build#!/bin/sh sleep=5 while [ true ]; do "$@" exit_code=$? if [ $exit_code -gt 128 ]; then case $(($exit_code-128)) in 3 | 4 | 5 | 6 | 8 | 11) ;; *) exit; esac echo ceph-run: $1 dumped core, restarting in $sleep seconds... sleep $sleep else exit fi done ceph-0.80.11/src/crush/0000775000175100017510000000000012623077035016602 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/crush/CrushTester.h0000664000175100017510000002343012623076744021236 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CRUSH_TESTER_H #define CEPH_CRUSH_TESTER_H #include "crush/CrushWrapper.h" #include #include class CrushTester { CrushWrapper& crush; ostream& err; map device_weight; int min_rule, max_rule; int min_x, max_x; int min_rep, max_rep; int num_batches; bool use_crush; float mark_down_device_ratio; float mark_down_bucket_ratio; bool output_utilization; bool output_utilization_all; bool output_statistics; bool output_mappings; bool output_bad_mappings; bool output_choose_tries; bool output_data_file; bool output_csv; string output_data_file_name; /* * mark a ratio of devices down, can be used to simulate placement distributions * under degrated cluster conditions */ void adjust_weights(vector<__u32>& weight); /* * Get the maximum number of devices that could be selected to satisfy ruleno. */ int get_maximum_affected_by_rule(int ruleno); /* * for maps where in devices have non-sequential id numbers, return a mapping of device id * to a sequential id number. For example, if we have devices with id's 0 1 4 5 6 return a map * where: * 0 = 0 * 1 = 1 * 4 = 2 * 5 = 3 * 6 = 4 * * which can help make post-processing easier */ map get_collapsed_mapping(); /* * Essentially a re-implementation of CRUSH. Given a vector of devices * check that the vector represents a valid placement for a given ruleno. */ bool check_valid_placement(int ruleno, vector in, const vector<__u32>& weight); /* * Generate a random selection of devices which satisfies ruleno. Essentially a * monte-carlo simulator for CRUSH placements which can be used to compare the * statistical distribution of the CRUSH algorithm to a random number generator */ int random_placement(int ruleno, vector& out, int maxout, vector<__u32>& weight); // scaffolding to store data for off-line processing struct tester_data_set { vector device_utilization; vector device_utilization_all; vector placement_information; vector batch_device_utilization_all; vector batch_device_expected_utilization_all; map proportional_weights; map proportional_weights_all; map absolute_weights; } ; void write_to_csv(ofstream& csv_file, vector& payload) { if (csv_file.good()) for (vector::iterator it = payload.begin(); it != payload.end(); ++it) csv_file << (*it); } void write_to_csv(ofstream& csv_file, map& payload) { if (csv_file.good()) for (map::iterator it = payload.begin(); it != payload.end(); ++it) csv_file << (*it).first << ',' << (*it).second << std::endl; } void write_data_set_to_csv(string user_tag, tester_data_set& tester_data) { ofstream device_utilization_file ((user_tag + (string)"-device_utilization.csv").c_str()); ofstream device_utilization_all_file ((user_tag + (string)"-device_utilization_all.csv").c_str()); ofstream placement_information_file ((user_tag + (string)"-placement_information.csv").c_str()); ofstream proportional_weights_file ((user_tag + (string)"-proportional_weights.csv").c_str()); ofstream proportional_weights_all_file ((user_tag + (string)"-proportional_weights_all.csv").c_str()); ofstream absolute_weights_file ((user_tag + (string)"-absolute_weights.csv").c_str()); // write the headers device_utilization_file << "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl; device_utilization_all_file << "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl; proportional_weights_file << "Device ID, Proportional Weight" << std::endl; proportional_weights_all_file << "Device ID, Proportional Weight" << std::endl; absolute_weights_file << "Device ID, Absolute Weight" << std::endl; placement_information_file << "Input"; for (int i = 0; i < max_rep; i++) { placement_information_file << ", OSD" << i; } placement_information_file << std::endl; write_to_csv(device_utilization_file, tester_data.device_utilization); write_to_csv(device_utilization_all_file, tester_data.device_utilization_all); write_to_csv(placement_information_file, tester_data.placement_information); write_to_csv(proportional_weights_file, tester_data.proportional_weights); write_to_csv(proportional_weights_all_file, tester_data.proportional_weights_all); write_to_csv(absolute_weights_file, tester_data.absolute_weights); device_utilization_file.close(); device_utilization_all_file.close(); placement_information_file.close(); proportional_weights_file.close(); absolute_weights_file.close(); if (num_batches > 1) { ofstream batch_device_utilization_all_file ((user_tag + (string)"-batch_device_utilization_all.csv").c_str()); ofstream batch_device_expected_utilization_all_file ((user_tag + (string)"-batch_device_expected_utilization_all.csv").c_str()); batch_device_utilization_all_file << "Batch Round"; for (unsigned i = 0; i < tester_data.device_utilization.size(); i++) { batch_device_utilization_all_file << ", Objects Stored on OSD" << i; } batch_device_utilization_all_file << std::endl; batch_device_expected_utilization_all_file << "Batch Round"; for (unsigned i = 0; i < tester_data.device_utilization.size(); i++) { batch_device_expected_utilization_all_file << ", Objects Expected on OSD" << i; } batch_device_expected_utilization_all_file << std::endl; write_to_csv(batch_device_utilization_all_file, tester_data.batch_device_utilization_all); write_to_csv(batch_device_expected_utilization_all_file, tester_data.batch_device_expected_utilization_all); batch_device_expected_utilization_all_file.close(); batch_device_utilization_all_file.close(); } } void write_integer_indexed_vector_data_string(vector &dst, int index, vector vector_data); void write_integer_indexed_vector_data_string(vector &dst, int index, vector vector_data); void write_integer_indexed_scalar_data_string(vector &dst, int index, int scalar_data); void write_integer_indexed_scalar_data_string(vector &dst, int index, float scalar_data); public: CrushTester(CrushWrapper& c, ostream& eo) : crush(c), err(eo), min_rule(-1), max_rule(-1), min_x(-1), max_x(-1), min_rep(-1), max_rep(-1), num_batches(1), use_crush(true), mark_down_device_ratio(0.0), mark_down_bucket_ratio(1.0), output_utilization(false), output_utilization_all(false), output_statistics(false), output_mappings(false), output_bad_mappings(false), output_choose_tries(false), output_data_file(false), output_csv(false), output_data_file_name("") { } void set_output_data_file_name(string name) { output_data_file_name = name; } string get_output_data_file_name() const { return output_data_file_name; } void set_output_data_file(bool b) { output_data_file = b; } bool get_output_data_file() const { return output_data_file; } void set_output_csv(bool b) { output_csv = b; } bool get_output_csv() const { return output_csv; } void set_output_utilization(bool b) { output_utilization = b; } bool get_output_utilization() const { return output_utilization; } void set_output_utilization_all(bool b) { output_utilization_all = b; } bool get_output_utilization_all() const { return output_utilization_all; } void set_output_statistics(bool b) { output_statistics = b; } bool get_output_statistics() const { return output_statistics; } void set_output_mappings(bool b) { output_mappings = b; } bool get_output_mappings() const { return output_mappings; } void set_output_bad_mappings(bool b) { output_bad_mappings = b; } bool get_output_bad_mappings() const { return output_bad_mappings; } void set_output_choose_tries(bool b) { output_choose_tries = b; } bool get_output_choose_tries() const { return output_choose_tries; } void set_batches(int b) { num_batches = b; } int get_batches() const { return num_batches; } void set_random_placement() { use_crush = false; } bool get_random_placement() const { return use_crush == false; } void set_bucket_down_ratio(float bucket_ratio) { mark_down_bucket_ratio = bucket_ratio; } float get_bucket_down_ratio() const { return mark_down_bucket_ratio; } void set_device_down_ratio(float device_ratio) { mark_down_device_ratio = device_ratio; } float set_device_down_ratio() const { return mark_down_device_ratio; } void set_device_weight(int dev, float f); void set_min_rep(int r) { min_rep = r; } int get_min_rep() const { return min_rep; } void set_max_rep(int r) { max_rep = r; } int get_max_rep() const { return max_rep; } void set_num_rep(int r) { min_rep = max_rep = r; } void set_min_x(int x) { min_x = x; } int get_min_x() const { return min_x; } void set_max_x(int x) { max_x = x; } int get_max_x() const { return max_x; } void set_x(int x) { min_x = max_x = x; } void set_min_rule(int rule) { min_rule = rule; } int get_min_rule() const { return min_rule; } void set_max_rule(int rule) { max_rule = rule; } int get_max_rule() const { return max_rule; } void set_rule(int rule) { min_rule = max_rule = rule; } int test(); }; #endif ceph-0.80.11/src/crush/CrushWrapper.h0000664000175100017510000007221412623076744021414 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CRUSH_WRAPPER_H #define CEPH_CRUSH_WRAPPER_H #include #include #include #include #include //for testing, remove #include "include/types.h" extern "C" { #include "crush.h" #include "hash.h" #include "mapper.h" #include "builder.h" } #include "include/err.h" #include "include/encoding.h" #include "common/Mutex.h" #include "include/assert.h" #define BUG_ON(x) assert(!(x)) namespace ceph { class Formatter; } WRITE_RAW_ENCODER(crush_rule_mask) // it's all u8's inline static void encode(const crush_rule_step &s, bufferlist &bl) { ::encode(s.op, bl); ::encode(s.arg1, bl); ::encode(s.arg2, bl); } inline static void decode(crush_rule_step &s, bufferlist::iterator &p) { ::decode(s.op, p); ::decode(s.arg1, p); ::decode(s.arg2, p); } using namespace std; class CrushWrapper { mutable Mutex mapper_lock; public: std::map type_map; /* bucket/device type names */ std::map name_map; /* bucket/device names */ std::map rule_name_map; private: struct crush_map *crush; /* reverse maps */ mutable bool have_rmaps; mutable std::map type_rmap, name_rmap, rule_name_rmap; void build_rmaps() const { if (have_rmaps) return; build_rmap(type_map, type_rmap); build_rmap(name_map, name_rmap); build_rmap(rule_name_map, rule_name_rmap); have_rmaps = true; } void build_rmap(const map &f, std::map &r) const { r.clear(); for (std::map::const_iterator p = f.begin(); p != f.end(); ++p) r[p->second] = p->first; } public: CrushWrapper(const CrushWrapper& other); const CrushWrapper& operator=(const CrushWrapper& other); CrushWrapper() : mapper_lock("CrushWrapper::mapper_lock"), crush(0), have_rmaps(false) { create(); } ~CrushWrapper() { if (crush) crush_destroy(crush); } crush_map *get_crush_map() { return crush; } /* building */ void create() { if (crush) crush_destroy(crush); crush = crush_create(); assert(crush); have_rmaps = false; set_tunables_default(); } // tunables void set_tunables_argonaut() { crush->choose_local_tries = 2; crush->choose_local_fallback_tries = 5; crush->choose_total_tries = 19; crush->chooseleaf_descend_once = 0; crush->chooseleaf_vary_r = 0; } void set_tunables_bobtail() { crush->choose_local_tries = 0; crush->choose_local_fallback_tries = 0; crush->choose_total_tries = 50; crush->chooseleaf_descend_once = 1; crush->chooseleaf_vary_r = 0; } void set_tunables_firefly() { crush->choose_local_tries = 0; crush->choose_local_fallback_tries = 0; crush->choose_total_tries = 50; crush->chooseleaf_descend_once = 1; crush->chooseleaf_vary_r = 1; } void set_tunables_legacy() { set_tunables_argonaut(); crush->straw_calc_version = 0; } void set_tunables_optimal() { set_tunables_firefly(); crush->straw_calc_version = 1; } void set_tunables_default() { set_tunables_bobtail(); crush->straw_calc_version = 1; } int get_choose_local_tries() const { return crush->choose_local_tries; } void set_choose_local_tries(int n) { crush->choose_local_tries = n; } int get_choose_local_fallback_tries() const { return crush->choose_local_fallback_tries; } void set_choose_local_fallback_tries(int n) { crush->choose_local_fallback_tries = n; } int get_choose_total_tries() const { return crush->choose_total_tries; } void set_choose_total_tries(int n) { crush->choose_total_tries = n; } int get_chooseleaf_descend_once() const { return crush->chooseleaf_descend_once; } void set_chooseleaf_descend_once(int n) { crush->chooseleaf_descend_once = !!n; } int get_chooseleaf_vary_r() const { return crush->chooseleaf_vary_r; } void set_chooseleaf_vary_r(int n) { crush->chooseleaf_vary_r = n; } int get_straw_calc_version() const { return crush->straw_calc_version; } void set_straw_calc_version(int n) { crush->straw_calc_version = n; } bool has_argonaut_tunables() const { return crush->choose_local_tries == 2 && crush->choose_local_fallback_tries == 5 && crush->choose_total_tries == 19 && crush->chooseleaf_descend_once == 0 && crush->chooseleaf_vary_r == 0 && crush->straw_calc_version == 0; } bool has_bobtail_tunables() const { return crush->choose_local_tries == 0 && crush->choose_local_fallback_tries == 0 && crush->choose_total_tries == 50 && crush->chooseleaf_descend_once == 1 && crush->chooseleaf_vary_r == 0 && crush->straw_calc_version == 0; } bool has_firefly_tunables() const { return crush->choose_local_tries == 0 && crush->choose_local_fallback_tries == 0 && crush->choose_total_tries == 50 && crush->chooseleaf_descend_once == 1 && crush->chooseleaf_vary_r == 1 && crush->straw_calc_version == 0; } bool has_optimal_tunables() const { return has_firefly_tunables(); } bool has_legacy_tunables() const { return has_argonaut_tunables(); } bool has_nondefault_tunables() const { return (crush->choose_local_tries != 2 || crush->choose_local_fallback_tries != 5 || crush->choose_total_tries != 19); } bool has_nondefault_tunables2() const { return crush->chooseleaf_descend_once != 0; } bool has_nondefault_tunables3() const { return crush->chooseleaf_vary_r != 0; } bool has_v2_rules() const; bool has_v3_rules() const; bool is_v2_rule(unsigned ruleid) const; bool is_v3_rule(unsigned ruleid) const; // bucket types int get_num_type_names() const { return type_map.size(); } int get_type_id(const string& name) const { build_rmaps(); if (type_rmap.count(name)) return type_rmap[name]; return -1; } const char *get_type_name(int t) const { std::map::const_iterator p = type_map.find(t); if (p != type_map.end()) return p->second.c_str(); return 0; } void set_type_name(int i, const string& name) { type_map[i] = name; if (have_rmaps) type_rmap[name] = i; } // item/bucket names bool name_exists(const string& name) const { build_rmaps(); return name_rmap.count(name); } bool item_exists(int i) { return name_map.count(i); } int get_item_id(const string& name) const { build_rmaps(); if (name_rmap.count(name)) return name_rmap[name]; return 0; /* hrm */ } const char *get_item_name(int t) const { std::map::const_iterator p = name_map.find(t); if (p != name_map.end()) return p->second.c_str(); return 0; } int set_item_name(int i, const string& name) { if (!is_valid_crush_name(name)) return -EINVAL; name_map[i] = name; if (have_rmaps) name_rmap[name] = i; return 0; } // rule names bool rule_exists(string name) const { build_rmaps(); return rule_name_rmap.count(name); } int get_rule_id(string name) const { build_rmaps(); if (rule_name_rmap.count(name)) return rule_name_rmap[name]; return -ENOENT; } const char *get_rule_name(int t) const { std::map::const_iterator p = rule_name_map.find(t); if (p != rule_name_map.end()) return p->second.c_str(); return 0; } void set_rule_name(int i, const string& name) { rule_name_map[i] = name; if (have_rmaps) rule_name_rmap[name] = i; } /** * find tree nodes referenced by rules by a 'take' command * * Note that these may not be parentless roots. */ void find_takes(set& roots) const; /** * find tree roots * * These are parentless nodes in the map. */ void find_roots(set& roots) const; /** * see if an item is contained within a subtree * * @param root haystack * @param item needle * @return true if the item is located beneath the given node */ bool subtree_contains(int root, int item) const; private: /** * search for an item in any bucket * * @param i item * @return true if present */ bool _search_item_exists(int i) const; public: /** * see if item is located where we think it is * * This verifies that the given item is located at a particular * location in the hierarchy. However, that check is imprecise; we * are actually verifying that the most specific location key/value * is correct. For example, if loc specifies that rack=foo and * host=bar, it will verify that host=bar is correct; any placement * above that level in the hierarchy is ignored. This matches the * semantics for insert_item(). * * @param cct cct * @param item item id * @param loc location to check (map of type to bucket names) * @param weight optional pointer to weight of item at that location * @return true if item is at specified location */ bool check_item_loc(CephContext *cct, int item, const map& loc, int *iweight); bool check_item_loc(CephContext *cct, int item, const map& loc, float *weight) { int iweight; bool ret = check_item_loc(cct, item, loc, &iweight); if (weight) *weight = (float)iweight / (float)0x10000; return ret; } /** * returns the (type, name) of the parent bucket of id * * FIXME: ambiguous for items that occur multiple times in the map */ pair get_immediate_parent(int id, int *ret = NULL); int get_immediate_parent_id(int id, int *parent); /** * get the fully qualified location of a device by successively finding * parents beginning at ID and ending at highest type number specified in * the CRUSH map which assumes that if device foo is under device bar, the * type_id of foo < bar where type_id is the integer specified in the CRUSH map * * returns the location in the form of (type=foo) where type is a type of bucket * specified in the CRUSH map and foo is a name specified in the CRUSH map */ map get_full_location(int id); /* * identical to get_full_location(int id) although it returns the type/name * pairs in the order they occur in the hierarchy. * * returns -ENOENT if id is not found. */ int get_full_location_ordered(int id, vector >& path); /** * returns (type_id, type) of all parent buckets between id and * default, can be used to check for anomolous CRUSH maps */ map get_parent_hierarchy(int id); /** * enumerate immediate children of given node * * @param id parent bucket or device id * @return number of items, or error */ int get_children(int id, list *children); /** * insert an item into the map at a specific position * * Add an item as a specific location of the hierarchy. * Specifically, we look for the most specific location constraint * for which a bucket already exists, and then create intervening * buckets beneath that in order to place the item. * * Note that any location specifiers *above* the most specific match * are ignored. For example, if we specify that osd.12 goes in * host=foo, rack=bar, and row=baz, and rack=bar is the most * specific match, we will create host=foo beneath that point and * put osd.12 inside it. However, we will not verify that rack=bar * is beneath row=baz or move it. * * In short, we will build out a hierarchy, and move leaves around, * but not adjust the hierarchy's internal structure. Yet. * * If the item is already present in the map, we will return EEXIST. * If the location key/value pairs are nonsensical * (rack=nameofdevice), or location specifies that do not attach us * to any existing part of the hierarchy, we will return EINVAL. * * @param cct cct * @param id item id * @param weight item weight * @param name item name * @param loc location (map of type to bucket names) * @return 0 for success, negative on error */ int insert_item(CephContext *cct, int id, float weight, string name, const map& loc); /** * move a bucket in the hierarchy to the given location * * This has the same location and ancestor creation behavior as * insert_item(), but will relocate the specified existing bucket. * * @param cct cct * @param id bucket id * @param loc location (map of type to bucket names) * @return 0 for success, negative on error */ int move_bucket(CephContext *cct, int id, const map& loc); /** * add a link to an existing bucket in the hierarchy to the new location * * This has the same location and ancestor creation behavior as * insert_item(), but will add a new link to the specified existing * bucket. * * @param cct cct * @param id bucket id * @param loc location (map of type to bucket names) * @return 0 for success, negative on error */ int link_bucket(CephContext *cct, int id, const map& loc); /** * add or update an item's position in the map * * This is analogous to insert_item, except we will move an item if * it is already present. * * @param cct cct * @param id item id * @param weight item weight * @param name item name * @param loc location (map of type to bucket names) * @return 0 for no change, 1 for successful change, negative on error */ int update_item(CephContext *cct, int id, float weight, string name, const map& loc); /** * create or move an item, but do not adjust its weight if it already exists * * @param cct cct * @param item item id * @param weight initial item weight (if we need to create it) * @param name item name * @param loc location (map of type to bucket names) * @return 0 for no change, 1 for successful change, negative on error */ int create_or_move_item(CephContext *cct, int item, float weight, string name, const map& loc); /** * remove all instances of an item from the map * * @param cct cct * @param id item id to remove * @param unlink_only unlink but do not remove bucket (useful if multiple links or not empty) * @return 0 on success, negative on error */ int remove_item(CephContext *cct, int id, bool unlink_only); /** * remove all instances of an item nested beneath a certain point from the map * * @param cct cct * @param id item id to remove * @param ancestor ancestor item id under which to search for id * @param unlink_only unlink but do not remove bucket (useful if bucket has multiple links or is not empty) * @return 0 on success, negative on error */ private: bool _maybe_remove_last_instance(CephContext *cct, int id, bool unlink_only); int _remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only); bool _bucket_is_in_use(CephContext *cct, int id); public: int remove_item_under(CephContext *cct, int id, int ancestor, bool unlink_only); /** * calculate the locality/distance from a given id to a crush location map * * Specifically, we look for the lowest-valued type for which the * location of id matches that described in loc. * * @param cct cct * @param id the existing id in the map * @param loc a set of key=value pairs describing a location in the hierarchy */ int get_common_ancestor_distance(CephContext *cct, int id, const std::multimap& loc); /** * parse a set of key/value pairs out of a string vector * * These are used to describe a location in the CRUSH hierarchy. * * @param args list of strings (each key= or key=value) * @param ploc pointer to a resulting location map or multimap */ static int parse_loc_map(const std::vector& args, std::map *ploc); static int parse_loc_multimap(const std::vector& args, std::multimap *ploc); /** * get an item's weight * * Will return the weight for the first instance it finds. * * @param cct cct * @param id item id to check * @return weight of item */ int get_item_weight(int id) const; float get_item_weightf(int id) const { return (float)get_item_weight(id) / (float)0x10000; } int get_item_weight_in_loc(int id, const map &loc); float get_item_weightf_in_loc(int id, const map &loc) { return (float)get_item_weight_in_loc(id, loc) / (float)0x10000; } int adjust_item_weight(CephContext *cct, int id, int weight); int adjust_item_weightf(CephContext *cct, int id, float weight) { return adjust_item_weight(cct, id, (int)(weight * (float)0x10000)); } int adjust_item_weight_in_loc(CephContext *cct, int id, int weight, const map& loc); int adjust_item_weightf_in_loc(CephContext *cct, int id, float weight, const map& loc) { return adjust_item_weight_in_loc(cct, id, (int)(weight * (float)0x10000), loc); } void reweight(CephContext *cct); /// check if item id is present in the map hierarchy bool check_item_present(int id) const; /*** devices ***/ int get_max_devices() const { if (!crush) return 0; return crush->max_devices; } /*** rules ***/ private: crush_rule *get_rule(unsigned ruleno) const { if (!crush) return (crush_rule *)(-ENOENT); if (ruleno >= crush->max_rules) return 0; return crush->rules[ruleno]; } crush_rule_step *get_rule_step(unsigned ruleno, unsigned step) const { crush_rule *n = get_rule(ruleno); if (!n) return (crush_rule_step *)(-EINVAL); if (step >= n->len) return (crush_rule_step *)(-EINVAL); return &n->steps[step]; } public: /* accessors */ int get_max_rules() const { if (!crush) return 0; return crush->max_rules; } bool rule_exists(unsigned ruleno) const { if (!crush) return false; if (ruleno < crush->max_rules && crush->rules[ruleno] != NULL) return true; return false; } int get_rule_len(unsigned ruleno) const { crush_rule *r = get_rule(ruleno); if (IS_ERR(r)) return PTR_ERR(r); return r->len; } int get_rule_mask_ruleset(unsigned ruleno) const { crush_rule *r = get_rule(ruleno); if (IS_ERR(r)) return -1; return r->mask.ruleset; } int get_rule_mask_type(unsigned ruleno) const { crush_rule *r = get_rule(ruleno); if (IS_ERR(r)) return -1; return r->mask.type; } int get_rule_mask_min_size(unsigned ruleno) const { crush_rule *r = get_rule(ruleno); if (IS_ERR(r)) return -1; return r->mask.min_size; } int get_rule_mask_max_size(unsigned ruleno) const { crush_rule *r = get_rule(ruleno); if (IS_ERR(r)) return -1; return r->mask.max_size; } int get_rule_op(unsigned ruleno, unsigned step) const { crush_rule_step *s = get_rule_step(ruleno, step); if (IS_ERR(s)) return PTR_ERR(s); return s->op; } int get_rule_arg1(unsigned ruleno, unsigned step) const { crush_rule_step *s = get_rule_step(ruleno, step); if (IS_ERR(s)) return PTR_ERR(s); return s->arg1; } int get_rule_arg2(unsigned ruleno, unsigned step) const { crush_rule_step *s = get_rule_step(ruleno, step); if (IS_ERR(s)) return PTR_ERR(s); return s->arg2; } /** * calculate a map of osds to weights for a given rule * * Generate a map of which OSDs get how much relative weight for a * given rule. * * @param ruleno [in] rule id * @param pmap [out] map of osd to weight * @return 0 for success, or negative error code */ int get_rule_weight_osd_map(unsigned ruleno, map *pmap); /* modifiers */ int add_rule(int len, int ruleset, int type, int minsize, int maxsize, int ruleno) { if (!crush) return -ENOENT; crush_rule *n = crush_make_rule(len, ruleset, type, minsize, maxsize); assert(n); ruleno = crush_add_rule(crush, n, ruleno); return ruleno; } int set_rule_step(unsigned ruleno, unsigned step, int op, int arg1, int arg2) { if (!crush) return -ENOENT; crush_rule *n = get_rule(ruleno); if (!n) return -1; crush_rule_set_step(n, step, op, arg1, arg2); return 0; } int set_rule_step_take(unsigned ruleno, unsigned step, int val) { return set_rule_step(ruleno, step, CRUSH_RULE_TAKE, val, 0); } int set_rule_step_set_choose_tries(unsigned ruleno, unsigned step, int val) { return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSE_TRIES, val, 0); } int set_rule_step_set_choose_local_tries(unsigned ruleno, unsigned step, int val) { return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES, val, 0); } int set_rule_step_set_choose_local_fallback_tries(unsigned ruleno, unsigned step, int val) { return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES, val, 0); } int set_rule_step_set_chooseleaf_tries(unsigned ruleno, unsigned step, int val) { return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSELEAF_TRIES, val, 0); } int set_rule_step_set_chooseleaf_vary_r(unsigned ruleno, unsigned step, int val) { return set_rule_step(ruleno, step, CRUSH_RULE_SET_CHOOSELEAF_VARY_R, val, 0); } int set_rule_step_choose_firstn(unsigned ruleno, unsigned step, int val, int type) { return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSE_FIRSTN, val, type); } int set_rule_step_choose_indep(unsigned ruleno, unsigned step, int val, int type) { return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSE_INDEP, val, type); } int set_rule_step_choose_leaf_firstn(unsigned ruleno, unsigned step, int val, int type) { return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSELEAF_FIRSTN, val, type); } int set_rule_step_choose_leaf_indep(unsigned ruleno, unsigned step, int val, int type) { return set_rule_step(ruleno, step, CRUSH_RULE_CHOOSELEAF_INDEP, val, type); } int set_rule_step_emit(unsigned ruleno, unsigned step) { return set_rule_step(ruleno, step, CRUSH_RULE_EMIT, 0, 0); } int add_simple_ruleset(string name, string root_name, string failure_domain_type, string mode, int rule_type, ostream *err = 0); int remove_rule(int ruleno); /** buckets **/ private: const crush_bucket *get_bucket(int id) const { if (!crush) return (crush_bucket *)(-EINVAL); unsigned int pos = (unsigned int)(-1 - id); unsigned int max_buckets = crush->max_buckets; if (pos >= max_buckets) return (crush_bucket *)(-ENOENT); crush_bucket *ret = crush->buckets[pos]; if (ret == NULL) return (crush_bucket *)(-ENOENT); return ret; } crush_bucket *get_bucket(int id) { if (!crush) return (crush_bucket *)(-EINVAL); unsigned int pos = (unsigned int)(-1 - id); unsigned int max_buckets = crush->max_buckets; if (pos >= max_buckets) return (crush_bucket *)(-ENOENT); crush_bucket *ret = crush->buckets[pos]; if (ret == NULL) return (crush_bucket *)(-ENOENT); return ret; } /** * detach a bucket from its parent and adjust the parent weight * * returns the weight of the detached bucket **/ int detach_bucket(CephContext *cct, int item){ if (!crush) return (-EINVAL); if (item >= 0) return (-EINVAL); // check that the bucket that we want to detach exists assert( get_bucket(item) ); // get the bucket's weight crush_bucket *b = get_bucket(item); unsigned bucket_weight = b->weight; // get where the bucket is located pair bucket_location = get_immediate_parent(item); // get the id of the parent bucket int parent_id = get_item_id(bucket_location.second); // get the parent bucket crush_bucket *parent_bucket = get_bucket(parent_id); if (!IS_ERR(parent_bucket)) { // zero out the bucket weight crush_bucket_adjust_item_weight(crush, parent_bucket, item, 0); adjust_item_weight(cct, parent_bucket->id, parent_bucket->weight); // remove the bucket from the parent crush_bucket_remove_item(crush, parent_bucket, item); } else if (PTR_ERR(parent_bucket) != -ENOENT) { return PTR_ERR(parent_bucket); } // check that we're happy int test_weight = 0; map test_location; test_location[ bucket_location.first ] = (bucket_location.second); bool successful_detach = !(check_item_loc(cct, item, test_location, &test_weight)); assert(successful_detach); assert(test_weight == 0); return bucket_weight; } public: int get_max_buckets() const { if (!crush) return -EINVAL; return crush->max_buckets; } int get_next_bucket_id() const { if (!crush) return -EINVAL; return crush_get_next_bucket_id(crush); } bool bucket_exists(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return false; return true; } int get_bucket_weight(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); return b->weight; } float get_bucket_weightf(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return 0; return b->weight / (float)0x10000; } int get_bucket_type(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); return b->type; } int get_bucket_alg(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); return b->alg; } int get_bucket_hash(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); return b->hash; } int get_bucket_size(int id) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); return b->size; } int get_bucket_item(int id, int pos) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); if ((__u32)pos >= b->size) return PTR_ERR(b); return b->items[pos]; } int get_bucket_item_weight(int id, int pos) const { const crush_bucket *b = get_bucket(id); if (IS_ERR(b)) return PTR_ERR(b); return crush_get_bucket_item_weight(b, pos); } /* modifiers */ int add_bucket(int bucketno, int alg, int hash, int type, int size, int *items, int *weights, int *idout) { if (type == 0) return -EINVAL; crush_bucket *b = crush_make_bucket(crush, alg, hash, type, size, items, weights); assert(b); return crush_add_bucket(crush, bucketno, b, idout); } void finalize() { assert(crush); crush_finalize(crush); } void start_choose_profile() { free(crush->choose_tries); crush->choose_tries = (__u32 *)malloc(sizeof(*crush->choose_tries) * crush->choose_total_tries); memset(crush->choose_tries, 0, sizeof(*crush->choose_tries) * crush->choose_total_tries); } void stop_choose_profile() { free(crush->choose_tries); crush->choose_tries = 0; } int get_choose_profile(__u32 **vec) { if (crush->choose_tries) { *vec = crush->choose_tries; return crush->choose_total_tries; } return 0; } void set_max_devices(int m) { crush->max_devices = m; } int find_rule(int ruleset, int type, int size) const { if (!crush) return -1; return crush_find_rule(crush, ruleset, type, size); } bool ruleset_exists(int ruleset) const { for (size_t i = 0; i < crush->max_rules; ++i) { if (rule_exists(i) && crush->rules[i]->mask.ruleset == ruleset) { return true; } } return false; } /** * Return the lowest numbered ruleset of type `type` * * @returns a ruleset ID, or -1 if no matching rulesets found. */ int find_first_ruleset(int type) const { int result = -1; for (size_t i = 0; i < crush->max_rules; ++i) { if (crush->rules[i] && crush->rules[i]->mask.type == type && (crush->rules[i]->mask.ruleset < result || result == -1)) { result = crush->rules[i]->mask.ruleset; } } return result; } void do_rule(int rule, int x, vector& out, int maxout, const vector<__u32>& weight) const { Mutex::Locker l(mapper_lock); int rawout[maxout]; int scratch[maxout * 3]; int numrep = crush_do_rule(crush, rule, x, rawout, maxout, &weight[0], weight.size(), scratch); if (numrep < 0) numrep = 0; out.resize(numrep); for (int i=0; i& w, ostream *out, Formatter *f) const; static void generate_test_instances(list& o); int get_osd_pool_default_crush_replicated_ruleset(CephContext *cct); static bool is_valid_crush_name(const string& s); static bool is_valid_crush_loc(CephContext *cct, const map& loc); }; WRITE_CLASS_ENCODER(CrushWrapper) #endif ceph-0.80.11/src/crush/CrushCompiler.cc0000664000175100017510000005763312623076744021714 0ustar jenkins-buildjenkins-build #include "CrushCompiler.h" #ifndef EBADE #define EBADE EFTYPE #endif #include #include #include #include #include #include #include #include #include "common/errno.h" // ------------- static void print_type_name(ostream& out, int t, CrushWrapper &crush) { const char *name = crush.get_type_name(t); if (name) out << name; else if (t == 0) out << "device"; else out << "type" << t; } static void print_item_name(ostream& out, int t, CrushWrapper &crush) { const char *name = crush.get_item_name(t); if (name) out << name; else if (t >= 0) out << "device" << t; else out << "bucket" << (-1-t); } static void print_rule_name(ostream& out, int t, CrushWrapper &crush) { const char *name = crush.get_rule_name(t); if (name) out << name; else out << "rule" << t; } static void print_fixedpoint(ostream& out, int i) { char s[20]; snprintf(s, sizeof(s), "%.3f", (float)i / (float)0x10000); out << s; } int CrushCompiler::decompile_bucket_impl(int i, ostream &out) { int type = crush.get_bucket_type(i); print_type_name(out, type, crush); out << " "; print_item_name(out, i, crush); out << " {\n"; out << "\tid " << i << "\t\t# do not change unnecessarily\n"; out << "\t# weight "; print_fixedpoint(out, crush.get_bucket_weight(i)); out << "\n"; int n = crush.get_bucket_size(i); int alg = crush.get_bucket_alg(i); out << "\talg " << crush_bucket_alg_name(alg); // notate based on alg type bool dopos = false; switch (alg) { case CRUSH_BUCKET_UNIFORM: out << "\t# do not change bucket size (" << n << ") unnecessarily"; dopos = true; break; case CRUSH_BUCKET_LIST: out << "\t# add new items at the end; do not change order unnecessarily"; break; case CRUSH_BUCKET_TREE: out << "\t# do not change pos for existing items unnecessarily"; dopos = true; break; } out << "\n"; int hash = crush.get_bucket_hash(i); out << "\thash " << hash << "\t# " << crush_hash_name(hash) << "\n"; for (int j=0; j& dcb_states, ostream &out) { if ((cur == 0) || (!crush.bucket_exists(cur))) return 0; std::map::iterator c = dcb_states.find(cur); if (c == dcb_states.end()) { // Mark this bucket as "in progress." std::map::value_type val(cur, DCB_STATE_IN_PROGRESS); std::pair ::iterator, bool> rval (dcb_states.insert(val)); assert(rval.second); c = rval.first; } else if (c->second == DCB_STATE_DONE) { // We already did this bucket. return 0; } else if (c->second == DCB_STATE_IN_PROGRESS) { err << "decompile_crush_bucket: logic error: tried to decompile " "a bucket that is already being decompiled" << std::endl; return -EBADE; } else { err << "decompile_crush_bucket: logic error: illegal bucket state! " << c->second << std::endl; return -EBADE; } int bsize = crush.get_bucket_size(cur); for (int i = 0; i < bsize; ++i) { int item = crush.get_bucket_item(cur, i); std::map::iterator d = dcb_states.find(item); if (d == dcb_states.end()) { int ret = decompile_bucket(item, dcb_states, out); if (ret) return ret; } else if (d->second == DCB_STATE_IN_PROGRESS) { err << "decompile_crush_bucket: error: while trying to output bucket " << cur << ", we found out that it contains one of the buckets that " << "contain it. This is not allowed. The buckets must form a " << "directed acyclic graph." << std::endl; return -EINVAL; } else if (d->second != DCB_STATE_DONE) { err << "decompile_crush_bucket: logic error: illegal bucket state " << d->second << std::endl; return -EBADE; } } decompile_bucket_impl(cur, out); c->second = DCB_STATE_DONE; return 0; } int CrushCompiler::decompile(ostream &out) { out << "# begin crush map\n"; // only dump tunables if they differ from the defaults if (crush.get_choose_local_tries() != 2) out << "tunable choose_local_tries " << crush.get_choose_local_tries() << "\n"; if (crush.get_choose_local_fallback_tries() != 5) out << "tunable choose_local_fallback_tries " << crush.get_choose_local_fallback_tries() << "\n"; if (crush.get_choose_total_tries() != 19) out << "tunable choose_total_tries " << crush.get_choose_total_tries() << "\n"; if (crush.get_chooseleaf_descend_once() != 0) out << "tunable chooseleaf_descend_once " << crush.get_chooseleaf_descend_once() << "\n"; if (crush.get_chooseleaf_vary_r() != 0) out << "tunable chooseleaf_vary_r " << crush.get_chooseleaf_vary_r() << "\n"; if (crush.get_straw_calc_version() != 0) out << "tunable straw_calc_version " << crush.get_straw_calc_version() << "\n"; out << "\n# devices\n"; for (int i=0; i dcb_states; for (int bucket = -1; bucket > -1-crush.get_max_buckets(); --bucket) { int ret = decompile_bucket(bucket, dcb_states, out); if (ret) return ret; } out << "\n# rules\n"; for (int i=0; i 0 && s[0] == ' ') s = string(s.begin() + 1, s.end()); return s; } int CrushCompiler::int_node(node_t &node) { string str = string_node(node); return strtol(str.c_str(), 0, 10); } float CrushCompiler::float_node(node_t &node) { string s = string_node(node); return strtof(s.c_str(), 0); } int CrushCompiler::parse_device(iter_t const& i) { int id = int_node(i->children[1]); string name = string_node(i->children[2]); crush.set_item_name(id, name.c_str()); if (item_id.count(name)) { err << "item " << name << " defined twice" << std::endl; return -1; } item_id[name] = id; id_item[id] = name; if (verbose) err << "device " << id << " '" << name << "'" << std::endl; return 0; } int CrushCompiler::parse_tunable(iter_t const& i) { string name = string_node(i->children[1]); int val = int_node(i->children[2]); if (name == "choose_local_tries") crush.set_choose_local_tries(val); else if (name == "choose_local_fallback_tries") crush.set_choose_local_fallback_tries(val); else if (name == "choose_total_tries") crush.set_choose_total_tries(val); else if (name == "chooseleaf_descend_once") crush.set_chooseleaf_descend_once(val); else if (name == "chooseleaf_vary_r") crush.set_chooseleaf_vary_r(val); else if (name == "straw_calc_version") crush.set_straw_calc_version(val); else { err << "tunable " << name << " not recognized" << std::endl; return -1; } /* current crop of tunables are all now "safe". re-enable this when we add new ones that are ... new. if (!unsafe_tunables) { err << "tunables are NOT FULLY IMPLEMENTED; enable with --enable-unsafe-tunables to enable this feature" << std::endl; return -1; } */ if (verbose) err << "tunable " << name << " " << val << std::endl; return 0; } int CrushCompiler::parse_bucket_type(iter_t const& i) { int id = int_node(i->children[1]); string name = string_node(i->children[2]); if (verbose) err << "type " << id << " '" << name << "'" << std::endl; type_id[name] = id; crush.set_type_name(id, name.c_str()); return 0; } int CrushCompiler::parse_bucket(iter_t const& i) { string tname = string_node(i->children[0]); if (!type_id.count(tname)) { err << "bucket type '" << tname << "' is not defined" << std::endl; return -1; } int type = type_id[tname]; string name = string_node(i->children[1]); if (item_id.count(name)) { err << "bucket or device '" << name << "' is already defined" << std::endl; return -1; } int id = 0; // none, yet! int alg = -1; int hash = 0; set used_items; int size = 0; for (unsigned p=3; pchildren.size()-1; p++) { iter_t sub = i->children.begin() + p; string tag = string_node(sub->children[0]); //err << "tag " << tag << std::endl; if (tag == "id") id = int_node(sub->children[1]); else if (tag == "alg") { string a = string_node(sub->children[1]); if (a == "uniform") alg = CRUSH_BUCKET_UNIFORM; else if (a == "list") alg = CRUSH_BUCKET_LIST; else if (a == "tree") alg = CRUSH_BUCKET_TREE; else if (a == "straw") alg = CRUSH_BUCKET_STRAW; else { err << "unknown bucket alg '" << a << "'" << std::endl << std::endl; return -EINVAL; } } else if (tag == "hash") { string a = string_node(sub->children[1]); if (a == "rjenkins1") hash = CRUSH_HASH_RJENKINS1; else hash = atoi(a.c_str()); } else if (tag == "item") { // first, just determine which item pos's are already used size++; for (unsigned q = 2; q < sub->children.size(); q++) { string tag = string_node(sub->children[q++]); if (tag == "pos") { int pos = int_node(sub->children[q]); if (used_items.count(pos)) { err << "item '" << string_node(sub->children[1]) << "' in bucket '" << name << "' has explicit pos " << pos << ", which is occupied" << std::endl; return -1; } used_items.insert(pos); } } } else assert(0); } // now do the items. if (!used_items.empty()) size = MAX(size, *used_items.rbegin()); vector items(size); vector weights(size); int curpos = 0; unsigned bucketweight = 0; bool have_uniform_weight = false; unsigned uniform_weight = 0; for (unsigned p=3; pchildren.size()-1; p++) { iter_t sub = i->children.begin() + p; string tag = string_node(sub->children[0]); if (tag == "item") { string iname = string_node(sub->children[1]); if (!item_id.count(iname)) { err << "item '" << iname << "' in bucket '" << name << "' is not defined" << std::endl; return -1; } int itemid = item_id[iname]; unsigned weight = 0x10000; if (item_weight.count(itemid)) weight = item_weight[itemid]; int pos = -1; for (unsigned q = 2; q < sub->children.size(); q++) { string tag = string_node(sub->children[q++]); if (tag == "weight") { weight = float_node(sub->children[q]) * (float)0x10000; if (weight > CRUSH_MAX_DEVICE_WEIGHT && itemid >= 0) { err << "device weight limited to " << CRUSH_MAX_DEVICE_WEIGHT / 0x10000 << std::endl; return -ERANGE; } else if (weight > CRUSH_MAX_BUCKET_WEIGHT && itemid < 0) { err << "bucket weight limited to " << CRUSH_MAX_BUCKET_WEIGHT / 0x10000 << " to prevent overflow" << std::endl; return -ERANGE; } } else if (tag == "pos") pos = int_node(sub->children[q]); else assert(0); } if (alg == CRUSH_BUCKET_UNIFORM) { if (!have_uniform_weight) { have_uniform_weight = true; uniform_weight = weight; } else { if (uniform_weight != weight) { err << "item '" << iname << "' in uniform bucket '" << name << "' has weight " << weight << " but previous item(s) have weight " << (float)uniform_weight/(float)0x10000 << "; uniform bucket items must all have identical weights." << std::endl; return -1; } } } if (pos >= size) { err << "item '" << iname << "' in bucket '" << name << "' has pos " << pos << " >= size " << size << std::endl; return -1; } if (pos < 0) { while (used_items.count(curpos)) curpos++; pos = curpos++; } //err << " item " << iname << " (" << itemid << ") pos " << pos << " weight " << weight << std::endl; items[pos] = itemid; weights[pos] = weight; if (crush_addition_is_unsafe(bucketweight, weight)) { err << "oh no! our bucket weights are overflowing all over the place, better lower the item weights" << std::endl; return -ERANGE; } bucketweight += weight; } } if (id == 0) { for (id=-1; id_item.count(id); id--) ; //err << "assigned id " << id << std::endl; } if (verbose) err << "bucket " << name << " (" << id << ") " << size << " items and weight " << (float)bucketweight / (float)0x10000 << std::endl; id_item[id] = name; item_id[name] = id; item_weight[id] = bucketweight; assert(id != 0); int r = crush.add_bucket(id, alg, hash, type, size, &items[0], &weights[0], NULL); if (r < 0) { if (r == -EEXIST) err << "Duplicate bucket id " << id << std::endl; else err << "add_bucket failed " << cpp_strerror(r) << std::endl; return r; } r = crush.set_item_name(id, name.c_str()); return r; } int CrushCompiler::parse_rule(iter_t const& i) { int start; // rule name is optional! string rname = string_node(i->children[1]); if (rname != "{") { if (rule_id.count(rname)) { err << "rule name '" << rname << "' already defined\n" << std::endl; return -1; } start = 4; } else { rname = string(); start = 3; } int ruleset = int_node(i->children[start]); string tname = string_node(i->children[start+2]); int type; if (tname == "replicated") type = CEPH_PG_TYPE_REPLICATED; else if (tname == "erasure") type = CEPH_PG_TYPE_ERASURE; else assert(0); int minsize = int_node(i->children[start+4]); int maxsize = int_node(i->children[start+6]); int steps = i->children.size() - start - 8; //err << "num steps " << steps << std::endl; int ruleno = crush.add_rule(steps, ruleset, type, minsize, maxsize, -1); if (rname.length()) { crush.set_rule_name(ruleno, rname.c_str()); rule_id[rname] = ruleno; } int step = 0; for (iter_t p = i->children.begin() + start + 7; step < steps; p++) { iter_t s = p->children.begin() + 1; int stepid = s->value.id().to_long(); switch (stepid) { case crush_grammar::_step_take: { string item = string_node(s->children[1]); if (!item_id.count(item)) { err << "in rule '" << rname << "' item '" << item << "' not defined" << std::endl; return -1; } crush.set_rule_step_take(ruleno, step++, item_id[item]); } break; case crush_grammar::_step_set_choose_tries: { int val = int_node(s->children[1]); crush.set_rule_step_set_choose_tries(ruleno, step++, val); } break; case crush_grammar::_step_set_choose_local_tries: { int val = int_node(s->children[1]); crush.set_rule_step_set_choose_local_tries(ruleno, step++, val); } break; case crush_grammar::_step_set_choose_local_fallback_tries: { int val = int_node(s->children[1]); crush.set_rule_step_set_choose_local_fallback_tries(ruleno, step++, val); } break; case crush_grammar::_step_set_chooseleaf_tries: { int val = int_node(s->children[1]); crush.set_rule_step_set_chooseleaf_tries(ruleno, step++, val); } break; case crush_grammar::_step_set_chooseleaf_vary_r: { int val = int_node(s->children[1]); crush.set_rule_step_set_chooseleaf_vary_r(ruleno, step++, val); } break; case crush_grammar::_step_choose: case crush_grammar::_step_chooseleaf: { string type = string_node(s->children[4]); if (!type_id.count(type)) { err << "in rule '" << rname << "' type '" << type << "' not defined" << std::endl; return -1; } string choose = string_node(s->children[0]); string mode = string_node(s->children[1]); if (choose == "choose") { if (mode == "firstn") crush.set_rule_step_choose_firstn(ruleno, step++, int_node(s->children[2]), type_id[type]); else if (mode == "indep") crush.set_rule_step_choose_indep(ruleno, step++, int_node(s->children[2]), type_id[type]); else assert(0); } else if (choose == "chooseleaf") { if (mode == "firstn") crush.set_rule_step_choose_leaf_firstn(ruleno, step++, int_node(s->children[2]), type_id[type]); else if (mode == "indep") crush.set_rule_step_choose_leaf_indep(ruleno, step++, int_node(s->children[2]), type_id[type]); else assert(0); } else assert(0); } break; case crush_grammar::_step_emit: crush.set_rule_step_emit(ruleno, step++); break; default: err << "bad crush step " << stepid << std::endl; return -1; } } assert(step == steps); return 0; } void CrushCompiler::find_used_bucket_ids(iter_t const& i) { for (iter_t p = i->children.begin(); p != i->children.end(); p++) { if ((int)p->value.id().to_long() == crush_grammar::_bucket) { iter_t firstline = p->children.begin() + 3; string tag = string_node(firstline->children[0]); if (tag == "id") { int id = int_node(firstline->children[1]); //err << "saw bucket id " << id << std::endl; id_item[id] = string(); } } } } int CrushCompiler::parse_crush(iter_t const& i) { find_used_bucket_ids(i); int r = 0; for (iter_t p = i->children.begin(); p != i->children.end(); p++) { switch (p->value.id().to_long()) { case crush_grammar::_tunable: r = parse_tunable(p); break; case crush_grammar::_device: r = parse_device(p); break; case crush_grammar::_bucket_type: r = parse_bucket_type(p); break; case crush_grammar::_bucket: r = parse_bucket(p); break; case crush_grammar::_crushrule: r = parse_rule(p); break; default: assert(0); } } if (r < 0) return r; //err << "max_devices " << crush.get_max_devices() << std::endl; crush.finalize(); return 0; } // squash runs of whitespace to one space, excepting newlines string CrushCompiler::consolidate_whitespace(string in) { string out; bool white = false; for (unsigned p=0; p 3) err << " \"" << in << "\" -> \"" << out << "\"" << std::endl; return out; } void CrushCompiler::dump(iter_t const& i, int ind) { err << "dump"; for (int j=0; jvalue.id().to_long(); err << id << "\t"; err << "'" << string(i->value.begin(), i->value.end()) << "' " << i->children.size() << " children" << std::endl; for (unsigned int j = 0; j < i->children.size(); j++) dump(i->children.begin() + j, ind+1); } int CrushCompiler::compile(istream& in, const char *infn) { if (!infn) infn = ""; // always start with legacy tunables, so that the compiled result of // a given crush file is fixed for all time. crush.set_tunables_legacy(); string big; string str; int line = 1; map line_pos; // pos -> line map line_val; while (getline(in, str)) { // remove newline int l = str.length(); if (l && str[l] == '\n') str.erase(l-1, 1); line_val[line] = str; // strip comment int n = str.find("#"); if (n >= 0) str.erase(n, str.length()-n); if (verbose>1) err << line << ": " << str << std::endl; // work around spirit crankiness by removing extraneous // whitespace. there is probably a more elegant solution, but // this only broke with the latest spirit (with the switchover to // "classic"), i don't want to spend too much time figuring it // out. string stripped = consolidate_whitespace(str); if (stripped.length() && big.length() && big[big.length()-1] != ' ') big += " "; line_pos[big.length()] = line; line++; big += stripped; } if (verbose > 2) err << "whole file is: \"" << big << "\"" << std::endl; crush_grammar crushg; const char *start = big.c_str(); //tree_parse_info info = ast_parse(start, crushg, space_p); tree_parse_info<> info = ast_parse(start, crushg, space_p); // parse error? if (!info.full) { int cpos = info.stop - start; //out << "cpos " << cpos << std::endl; //out << " linemap " << line_pos << std::endl; assert(!line_pos.empty()); map::iterator p = line_pos.upper_bound(cpos); if (p != line_pos.begin()) --p; int line = p->second; int pos = cpos - p->first; err << infn << ":" << line //<< ":" << (pos+1) << " error: parse error at '" << line_val[line].substr(pos) << "'" << std::endl; return -1; } //out << "parsing succeeded\n"; //dump(info.trees.begin()); return parse_crush(info.trees.begin()); } ceph-0.80.11/src/crush/mapper.h0000664000175100017510000000067712623076744020257 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRUSH_MAPPER_H #define CEPH_CRUSH_MAPPER_H /* * CRUSH functions for find rules and then mapping an input to an * output set. * * LGPL2 */ #include "crush.h" extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, int size); extern int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, const __u32 *weights, int weight_max, int *scratch); #endif ceph-0.80.11/src/crush/builder.c0000664000175100017510000007533512623076744020417 0ustar jenkins-buildjenkins-build#include #include #include #include #include #include #include #include "include/int_types.h" #include "builder.h" #include "hash.h" #define dprintk(args...) /* printf(args) */ #define BUG_ON(x) assert(!(x)) struct crush_map *crush_create() { struct crush_map *m; m = malloc(sizeof(*m)); if (!m) return NULL; memset(m, 0, sizeof(*m)); /* initialize legacy tunable values */ m->choose_local_tries = 2; m->choose_local_fallback_tries = 5; m->choose_total_tries = 19; m->chooseleaf_descend_once = 0; m->chooseleaf_vary_r = 0; m->straw_calc_version = 0; return m; } /* * finalize should be called _after_ all buckets are added to the map. */ void crush_finalize(struct crush_map *map) { int b; __u32 i; /* calc max_devices */ map->max_devices = 0; for (b=0; bmax_buckets; b++) { if (map->buckets[b] == 0) continue; for (i=0; ibuckets[b]->size; i++) if (map->buckets[b]->items[i] >= map->max_devices) map->max_devices = map->buckets[b]->items[i] + 1; } } /** rules **/ int crush_add_rule(struct crush_map *map, struct crush_rule *rule, int ruleno) { __u32 r; if (ruleno < 0) { for (r=0; r < map->max_rules; r++) if (map->rules[r] == 0) break; assert(r < CRUSH_MAX_RULES); } else r = ruleno; if (r >= map->max_rules) { /* expand array */ int oldsize; void *_realloc = NULL; if (map->max_rules +1 > CRUSH_MAX_RULES) return -ENOSPC; oldsize = map->max_rules; map->max_rules = r+1; if ((_realloc = realloc(map->rules, map->max_rules * sizeof(map->rules[0]))) == NULL) { return -ENOMEM; } else { map->rules = _realloc; } memset(map->rules + oldsize, 0, (map->max_rules-oldsize) * sizeof(map->rules[0])); } /* add it */ map->rules[r] = rule; return r; } struct crush_rule *crush_make_rule(int len, int ruleset, int type, int minsize, int maxsize) { struct crush_rule *rule; rule = malloc(crush_rule_size(len)); if (!rule) return NULL; rule->len = len; rule->mask.ruleset = ruleset; rule->mask.type = type; rule->mask.min_size = minsize; rule->mask.max_size = maxsize; return rule; } /* * be careful; this doesn't verify that the buffer you allocated is big enough! */ void crush_rule_set_step(struct crush_rule *rule, int n, int op, int arg1, int arg2) { assert((__u32)n < rule->len); rule->steps[n].op = op; rule->steps[n].arg1 = arg1; rule->steps[n].arg2 = arg2; } /** buckets **/ int crush_get_next_bucket_id(struct crush_map *map) { int pos; for (pos=0; pos < map->max_buckets; pos++) if (map->buckets[pos] == 0) break; return -1 - pos; } int crush_add_bucket(struct crush_map *map, int id, struct crush_bucket *bucket, int *idout) { int pos; /* find a bucket id */ if (id == 0) id = crush_get_next_bucket_id(map); pos = -1 - id; while (pos >= map->max_buckets) { /* expand array */ int oldsize = map->max_buckets; if (map->max_buckets) map->max_buckets *= 2; else map->max_buckets = 8; void *_realloc = NULL; if ((_realloc = realloc(map->buckets, map->max_buckets * sizeof(map->buckets[0]))) == NULL) { return -ENOMEM; } else { map->buckets = _realloc; } memset(map->buckets + oldsize, 0, (map->max_buckets-oldsize) * sizeof(map->buckets[0])); } if (map->buckets[pos] != 0) { return -EEXIST; } /* add it */ bucket->id = id; map->buckets[pos] = bucket; if (idout) *idout = id; return 0; } int crush_remove_bucket(struct crush_map *map, struct crush_bucket *bucket) { int pos = -1 - bucket->id; map->buckets[pos] = NULL; crush_destroy_bucket(bucket); return 0; } /* uniform bucket */ struct crush_bucket_uniform * crush_make_uniform_bucket(int hash, int type, int size, int *items, int item_weight) { int i; struct crush_bucket_uniform *bucket; bucket = malloc(sizeof(*bucket)); if (!bucket) return NULL; memset(bucket, 0, sizeof(*bucket)); bucket->h.alg = CRUSH_BUCKET_UNIFORM; bucket->h.hash = hash; bucket->h.type = type; bucket->h.size = size; if (crush_multiplication_is_unsafe(size, item_weight)) goto err; bucket->h.weight = size * item_weight; bucket->item_weight = item_weight; bucket->h.items = malloc(sizeof(__s32)*size); if (!bucket->h.items) goto err; bucket->h.perm = malloc(sizeof(__u32)*size); if (!bucket->h.perm) goto err; for (i=0; ih.items[i] = items[i]; return bucket; err: free(bucket->h.perm); free(bucket->h.items); free(bucket); return NULL; } /* list bucket */ struct crush_bucket_list* crush_make_list_bucket(int hash, int type, int size, int *items, int *weights) { int i; int w; struct crush_bucket_list *bucket; bucket = malloc(sizeof(*bucket)); if (!bucket) return NULL; memset(bucket, 0, sizeof(*bucket)); bucket->h.alg = CRUSH_BUCKET_LIST; bucket->h.hash = hash; bucket->h.type = type; bucket->h.size = size; bucket->h.items = malloc(sizeof(__s32)*size); if (!bucket->h.items) goto err; bucket->h.perm = malloc(sizeof(__u32)*size); if (!bucket->h.perm) goto err; bucket->item_weights = malloc(sizeof(__u32)*size); if (!bucket->item_weights) goto err; bucket->sum_weights = malloc(sizeof(__u32)*size); if (!bucket->sum_weights) goto err; w = 0; for (i=0; ih.items[i] = items[i]; bucket->item_weights[i] = weights[i]; if (crush_addition_is_unsafe(w, weights[i])) goto err; w += weights[i]; bucket->sum_weights[i] = w; /*dprintk("pos %d item %d weight %d sum %d\n", i, items[i], weights[i], bucket->sum_weights[i]);*/ } bucket->h.weight = w; return bucket; err: free(bucket->sum_weights); free(bucket->item_weights); free(bucket->h.perm); free(bucket->h.items); free(bucket); return NULL; } /* tree bucket */ static int height(int n) { int h = 0; while ((n & 1) == 0) { h++; n = n >> 1; } return h; } static int on_right(int n, int h) { return n & (1 << (h+1)); } static int parent(int n) { int h = height(n); if (on_right(n, h)) return n - (1<> 1; depth++; } return depth; } struct crush_bucket_tree* crush_make_tree_bucket(int hash, int type, int size, int *items, /* in leaf order */ int *weights) { struct crush_bucket_tree *bucket; int depth; int node; int i, j; bucket = malloc(sizeof(*bucket)); if (!bucket) return NULL; memset(bucket, 0, sizeof(*bucket)); bucket->h.alg = CRUSH_BUCKET_TREE; bucket->h.hash = hash; bucket->h.type = type; bucket->h.size = size; if (size == 0) { bucket->h.items = NULL; bucket->h.perm = NULL; bucket->h.weight = 0; bucket->node_weights = NULL; bucket->num_nodes = 0; /* printf("size 0 depth 0 nodes 0\n"); */ return bucket; } bucket->h.items = malloc(sizeof(__s32)*size); if (!bucket->h.items) goto err; bucket->h.perm = malloc(sizeof(__u32)*size); if (!bucket->h.perm) goto err; /* calc tree depth */ depth = calc_depth(size); bucket->num_nodes = 1 << depth; dprintk("size %d depth %d nodes %d\n", size, depth, bucket->num_nodes); bucket->node_weights = malloc(sizeof(__u32)*bucket->num_nodes); if (!bucket->node_weights) goto err; memset(bucket->h.items, 0, sizeof(__s32)*bucket->h.size); memset(bucket->node_weights, 0, sizeof(__u32)*bucket->num_nodes); for (i=0; ih.items[i] = items[i]; node = crush_calc_tree_node(i); dprintk("item %d node %d weight %d\n", i, node, weights[i]); bucket->node_weights[node] = weights[i]; if (crush_addition_is_unsafe(bucket->h.weight, weights[i])) goto err; bucket->h.weight += weights[i]; for (j=1; jnode_weights[node], weights[i])) goto err; bucket->node_weights[node] += weights[i]; dprintk(" node %d weight %d\n", node, bucket->node_weights[node]); } } BUG_ON(bucket->node_weights[bucket->num_nodes/2] != bucket->h.weight); return bucket; err: free(bucket->node_weights); free(bucket->h.perm); free(bucket->h.items); free(bucket); return NULL; } /* straw bucket */ /* * this code was written 8 years ago. i have a vague recollection of * drawing boxes underneath bars of different lengths, where the bar * length represented the probability/weight, and that there was some * trial and error involved in arriving at this implementation. * however, reading the code now after all this time, the intuition * that motivated is lost on me. lame. my only excuse is that I now * know that the approach is fundamentally flawed and am not * particularly motivated to reconstruct the flawed reasoning. * * as best as i can remember, the idea is: sort the weights, and start * with the smallest. arbitrarily scale it at 1.0 (16-bit fixed * point). look at the next larger weight, and calculate the scaling * factor for that straw based on the relative difference in weight so * far. what's not clear to me now is why we are looking at wnext * (the delta to the next bigger weight) for all remaining weights, * and slicing things horizontally instead of considering just the * next item or set of items. or why pow() is used the way it is. * * note that the original version 1 of this function made special * accomodation for the case where straw lengths were identical. this * is also flawed in a non-obvious way; version 2 drops the special * handling and appears to work just as well. * * moral of the story: if you do something clever, write down why it * works. */ int crush_calc_straw(struct crush_map *map, struct crush_bucket_straw *bucket) { int *reverse; int i, j, k; double straw, wbelow, lastw, wnext, pbelow; int numleft; int size = bucket->h.size; __u32 *weights = bucket->item_weights; /* reverse sort by weight (simple insertion sort) */ reverse = malloc(sizeof(int) * size); if (!reverse) return -ENOMEM; if (size) reverse[0] = 0; for (i=1; ij; k--) reverse[k] = reverse[k-1]; reverse[j] = i; break; } } if (j == i) reverse[i] = i; } numleft = size; straw = 1.0; wbelow = 0; lastw = 0; i=0; while (i < size) { if (map->straw_calc_version == 0) { /* zero weight items get 0 length straws! */ if (weights[reverse[i]] == 0) { bucket->straws[reverse[i]] = 0; i++; continue; } /* set this item's straw */ bucket->straws[reverse[i]] = straw * 0x10000; dprintk("item %d at %d weight %d straw %d (%lf)\n", bucket->h.items[reverse[i]], reverse[i], weights[reverse[i]], bucket->straws[reverse[i]], straw); i++; if (i == size) break; /* same weight as previous? */ if (weights[reverse[i]] == weights[reverse[i-1]]) { dprintk("same as previous\n"); continue; } /* adjust straw for next guy */ wbelow += ((double)weights[reverse[i-1]] - lastw) * numleft; for (j=i; jstraw_calc_version >= 1) { /* zero weight items get 0 length straws! */ if (weights[reverse[i]] == 0) { bucket->straws[reverse[i]] = 0; i++; numleft--; continue; } /* set this item's straw */ bucket->straws[reverse[i]] = straw * 0x10000; dprintk("item %d at %d weight %d straw %d (%lf)\n", bucket->h.items[reverse[i]], reverse[i], weights[reverse[i]], bucket->straws[reverse[i]], straw); i++; if (i == size) break; /* adjust straw for next guy */ wbelow += ((double)weights[reverse[i-1]] - lastw) * numleft; numleft--; wnext = numleft * (weights[reverse[i]] - weights[reverse[i-1]]); pbelow = wbelow / (wbelow + wnext); dprintk("wbelow %lf wnext %lf pbelow %lf numleft %d\n", wbelow, wnext, pbelow, numleft); straw *= pow((double)1.0 / pbelow, (double)1.0 / (double)numleft); lastw = weights[reverse[i-1]]; } } free(reverse); return 0; } struct crush_bucket_straw * crush_make_straw_bucket(struct crush_map *map, int hash, int type, int size, int *items, int *weights) { struct crush_bucket_straw *bucket; int i; bucket = malloc(sizeof(*bucket)); if (!bucket) return NULL; memset(bucket, 0, sizeof(*bucket)); bucket->h.alg = CRUSH_BUCKET_STRAW; bucket->h.hash = hash; bucket->h.type = type; bucket->h.size = size; bucket->h.items = malloc(sizeof(__s32)*size); if (!bucket->h.items) goto err; bucket->h.perm = malloc(sizeof(__u32)*size); if (!bucket->h.perm) goto err; bucket->item_weights = malloc(sizeof(__u32)*size); if (!bucket->item_weights) goto err; bucket->straws = malloc(sizeof(__u32)*size); if (!bucket->straws) goto err; bucket->h.weight = 0; for (i=0; ih.items[i] = items[i]; bucket->h.weight += weights[i]; bucket->item_weights[i] = weights[i]; } if (crush_calc_straw(map, bucket) < 0) goto err; return bucket; err: free(bucket->straws); free(bucket->item_weights); free(bucket->h.perm); free(bucket->h.items); free(bucket); return NULL; } struct crush_bucket* crush_make_bucket(struct crush_map *map, int alg, int hash, int type, int size, int *items, int *weights) { int item_weight; switch (alg) { case CRUSH_BUCKET_UNIFORM: if (size && weights) item_weight = weights[0]; else item_weight = 0; return (struct crush_bucket *)crush_make_uniform_bucket(hash, type, size, items, item_weight); case CRUSH_BUCKET_LIST: return (struct crush_bucket *)crush_make_list_bucket(hash, type, size, items, weights); case CRUSH_BUCKET_TREE: return (struct crush_bucket *)crush_make_tree_bucket(hash, type, size, items, weights); case CRUSH_BUCKET_STRAW: return (struct crush_bucket *)crush_make_straw_bucket(map, hash, type, size, items, weights); } return 0; } /************************************************/ int crush_add_uniform_bucket_item(struct crush_bucket_uniform *bucket, int item, int weight) { int newsize = bucket->h.size + 1; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } bucket->h.items[newsize-1] = item; if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.weight += weight; bucket->h.size++; return 0; } int crush_add_list_bucket_item(struct crush_bucket_list *bucket, int item, int weight) { int newsize = bucket->h.size + 1; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } if ((_realloc = realloc(bucket->item_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->item_weights = _realloc; } if ((_realloc = realloc(bucket->sum_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->sum_weights = _realloc; } bucket->h.items[newsize-1] = item; bucket->item_weights[newsize-1] = weight; if (newsize > 1) { if (crush_addition_is_unsafe(bucket->sum_weights[newsize-2], weight)) return -ERANGE; bucket->sum_weights[newsize-1] = bucket->sum_weights[newsize-2] + weight; } else { bucket->sum_weights[newsize-1] = weight; } bucket->h.weight += weight; bucket->h.size++; return 0; } int crush_add_tree_bucket_item(struct crush_bucket_tree *bucket, int item, int weight) { int newsize = bucket->h.size + 1; int depth = calc_depth(newsize);; int node; int j; void *_realloc = NULL; bucket->num_nodes = 1 << depth; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } if ((_realloc = realloc(bucket->node_weights, sizeof(__u32)*bucket->num_nodes)) == NULL) { return -ENOMEM; } else { bucket->node_weights = _realloc; } node = crush_calc_tree_node(newsize-1); bucket->node_weights[node] = weight; /* if the depth increase, we need to initialize the new root node's weight before add bucket item */ int root = bucket->num_nodes/2; if (depth >= 2 && (node - 1) == root) { /* if the new item is the first node in right sub tree, so * the root node initial weight is left sub tree's weight */ bucket->node_weights[root] = bucket->node_weights[root/2]; } for (j=1; jnode_weights[node], weight)) return -ERANGE; bucket->node_weights[node] += weight; dprintk(" node %d weight %d\n", node, bucket->node_weights[node]); } if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.items[newsize-1] = item; bucket->h.weight += weight; bucket->h.size++; return 0; } int crush_add_straw_bucket_item(struct crush_map *map, struct crush_bucket_straw *bucket, int item, int weight) { int newsize = bucket->h.size + 1; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } if ((_realloc = realloc(bucket->item_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->item_weights = _realloc; } if ((_realloc = realloc(bucket->straws, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->straws = _realloc; } bucket->h.items[newsize-1] = item; bucket->item_weights[newsize-1] = weight; if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.weight += weight; bucket->h.size++; return crush_calc_straw(map, bucket); } int crush_bucket_add_item(struct crush_map *map, struct crush_bucket *b, int item, int weight) { /* invalidate perm cache */ b->perm_n = 0; switch (b->alg) { case CRUSH_BUCKET_UNIFORM: return crush_add_uniform_bucket_item((struct crush_bucket_uniform *)b, item, weight); case CRUSH_BUCKET_LIST: return crush_add_list_bucket_item((struct crush_bucket_list *)b, item, weight); case CRUSH_BUCKET_TREE: return crush_add_tree_bucket_item((struct crush_bucket_tree *)b, item, weight); case CRUSH_BUCKET_STRAW: return crush_add_straw_bucket_item(map, (struct crush_bucket_straw *)b, item, weight); default: return -1; } return 0; } /************************************************/ int crush_remove_uniform_bucket_item(struct crush_bucket_uniform *bucket, int item) { unsigned i, j; int newsize; void *_realloc = NULL; for (i = 0; i < bucket->h.size; i++) if (bucket->h.items[i] == item) break; if (i == bucket->h.size) return -ENOENT; for (j = i; j < bucket->h.size; j++) bucket->h.items[j] = bucket->h.items[j+1]; newsize = --bucket->h.size; if (bucket->item_weight < bucket->h.weight) bucket->h.weight -= bucket->item_weight; else bucket->h.weight = 0; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } return 0; } int crush_remove_list_bucket_item(struct crush_bucket_list *bucket, int item) { unsigned i, j; int newsize; unsigned weight; for (i = 0; i < bucket->h.size; i++) if (bucket->h.items[i] == item) break; if (i == bucket->h.size) return -ENOENT; weight = bucket->item_weights[i]; for (j = i; j < bucket->h.size; j++) { bucket->h.items[j] = bucket->h.items[j+1]; bucket->item_weights[j] = bucket->item_weights[j+1]; bucket->sum_weights[j] = bucket->sum_weights[j+1] - weight; } if (weight < bucket->h.weight) bucket->h.weight -= weight; else bucket->h.weight = 0; newsize = --bucket->h.size; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } if ((_realloc = realloc(bucket->item_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->item_weights = _realloc; } if ((_realloc = realloc(bucket->sum_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->sum_weights = _realloc; } return 0; } int crush_remove_tree_bucket_item(struct crush_bucket_tree *bucket, int item) { unsigned i; unsigned newsize; for (i = 0; i < bucket->h.size; i++) { int node; unsigned weight; int j; int depth = calc_depth(bucket->h.size); if (bucket->h.items[i] != item) continue; node = crush_calc_tree_node(i); weight = bucket->node_weights[node]; bucket->node_weights[node] = 0; for (j = 1; j < depth; j++) { node = parent(node); bucket->node_weights[node] -= weight; dprintk(" node %d weight %d\n", node, bucket->node_weights[node]); } if (weight < bucket->h.weight) bucket->h.weight -= weight; else bucket->h.weight = 0; break; } if (i == bucket->h.size) return -ENOENT; newsize = bucket->h.size; while (newsize > 0) { int node = crush_calc_tree_node(newsize - 1); if (bucket->node_weights[node]) break; --newsize; } if (newsize != bucket->h.size) { int olddepth, newdepth; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } olddepth = calc_depth(bucket->h.size); newdepth = calc_depth(newsize); if (olddepth != newdepth) { bucket->num_nodes = 1 << newdepth; if ((_realloc = realloc(bucket->node_weights, sizeof(__u32)*bucket->num_nodes)) == NULL) { return -ENOMEM; } else { bucket->node_weights = _realloc; } } bucket->h.size = newsize; } return 0; } int crush_remove_straw_bucket_item(struct crush_map *map, struct crush_bucket_straw *bucket, int item) { int newsize = bucket->h.size - 1; unsigned i, j; for (i = 0; i < bucket->h.size; i++) { if (bucket->h.items[i] == item) { bucket->h.size--; if (bucket->item_weights[i] < bucket->h.weight) bucket->h.weight -= bucket->item_weights[i]; else bucket->h.weight = 0; for (j = i; j < bucket->h.size; j++) { bucket->h.items[j] = bucket->h.items[j+1]; bucket->item_weights[j] = bucket->item_weights[j+1]; } break; } } if (i == bucket->h.size) return -ENOENT; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } if ((_realloc = realloc(bucket->item_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->item_weights = _realloc; } if ((_realloc = realloc(bucket->straws, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->straws = _realloc; } return crush_calc_straw(map, bucket); } int crush_bucket_remove_item(struct crush_map *map, struct crush_bucket *b, int item) { /* invalidate perm cache */ b->perm_n = 0; switch (b->alg) { case CRUSH_BUCKET_UNIFORM: return crush_remove_uniform_bucket_item((struct crush_bucket_uniform *)b, item); case CRUSH_BUCKET_LIST: return crush_remove_list_bucket_item((struct crush_bucket_list *)b, item); case CRUSH_BUCKET_TREE: return crush_remove_tree_bucket_item((struct crush_bucket_tree *)b, item); case CRUSH_BUCKET_STRAW: return crush_remove_straw_bucket_item(map, (struct crush_bucket_straw *)b, item); default: return -1; } return 0; } /************************************************/ int crush_adjust_uniform_bucket_item_weight(struct crush_bucket_uniform *bucket, int item, int weight) { int diff = (weight - bucket->item_weight) * bucket->h.size; bucket->item_weight = weight; bucket->h.weight = bucket->item_weight * bucket->h.size; return diff; } int crush_adjust_list_bucket_item_weight(struct crush_bucket_list *bucket, int item, int weight) { int diff; unsigned i, j; for (i = 0; i < bucket->h.size; i++) { if (bucket->h.items[i] == item) break; } if (i == bucket->h.size) return 0; diff = weight - bucket->item_weights[i]; bucket->item_weights[i] = weight; bucket->h.weight += diff; for (j = i; j < bucket->h.size; j++) bucket->sum_weights[j] += diff; return diff; } int crush_adjust_tree_bucket_item_weight(struct crush_bucket_tree *bucket, int item, int weight) { int diff; int node; unsigned i, j; unsigned depth = calc_depth(bucket->h.size); for (i = 0; i < bucket->h.size; i++) { if (bucket->h.items[i] == item) break; } if (i == bucket->h.size) return 0; node = crush_calc_tree_node(i); diff = weight - bucket->node_weights[node]; bucket->node_weights[node] = weight; bucket->h.weight += diff; for (j=1; jnode_weights[node] += diff; } return diff; } int crush_adjust_straw_bucket_item_weight(struct crush_map *map, struct crush_bucket_straw *bucket, int item, int weight) { unsigned idx; int diff; int r; for (idx = 0; idx < bucket->h.size; idx++) if (bucket->h.items[idx] == item) break; if (idx == bucket->h.size) return 0; diff = weight - bucket->item_weights[idx]; bucket->item_weights[idx] = weight; bucket->h.weight += diff; r = crush_calc_straw(map, bucket); if (r < 0) return r; return diff; } int crush_bucket_adjust_item_weight(struct crush_map *map, struct crush_bucket *b, int item, int weight) { switch (b->alg) { case CRUSH_BUCKET_UNIFORM: return crush_adjust_uniform_bucket_item_weight((struct crush_bucket_uniform *)b, item, weight); case CRUSH_BUCKET_LIST: return crush_adjust_list_bucket_item_weight((struct crush_bucket_list *)b, item, weight); case CRUSH_BUCKET_TREE: return crush_adjust_tree_bucket_item_weight((struct crush_bucket_tree *)b, item, weight); case CRUSH_BUCKET_STRAW: return crush_adjust_straw_bucket_item_weight(map, (struct crush_bucket_straw *)b, item, weight); default: return -1; } return 0; } /************************************************/ static int crush_reweight_uniform_bucket(struct crush_map *crush, struct crush_bucket_uniform *bucket) { unsigned i; unsigned sum = 0, n = 0, leaves = 0; for (i = 0; i < bucket->h.size; i++) { int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); if (crush_addition_is_unsafe(sum, c->weight)) return -ERANGE; sum += c->weight; n++; } else { leaves++; } } if (n > leaves) bucket->item_weight = sum / n; // more bucket children than leaves, average! bucket->h.weight = bucket->item_weight * bucket->h.size; return 0; } static int crush_reweight_list_bucket(struct crush_map *crush, struct crush_bucket_list *bucket) { unsigned i; bucket->h.weight = 0; for (i = 0; i < bucket->h.size; i++) { int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); bucket->item_weights[i] = c->weight; } if (crush_addition_is_unsafe(bucket->h.weight, bucket->item_weights[i])) return -ERANGE; bucket->h.weight += bucket->item_weights[i]; } return 0; } static int crush_reweight_tree_bucket(struct crush_map *crush, struct crush_bucket_tree *bucket) { unsigned i; bucket->h.weight = 0; for (i = 0; i < bucket->h.size; i++) { int node = crush_calc_tree_node(i); int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); bucket->node_weights[node] = c->weight; } if (crush_addition_is_unsafe(bucket->h.weight, bucket->node_weights[node])) return -ERANGE; bucket->h.weight += bucket->node_weights[node]; } return 0; } static int crush_reweight_straw_bucket(struct crush_map *crush, struct crush_bucket_straw *bucket) { unsigned i; bucket->h.weight = 0; for (i = 0; i < bucket->h.size; i++) { int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); bucket->item_weights[i] = c->weight; } if (crush_addition_is_unsafe(bucket->h.weight, bucket->item_weights[i])) return -ERANGE; bucket->h.weight += bucket->item_weights[i]; } crush_calc_straw(crush, bucket); return 0; } int crush_reweight_bucket(struct crush_map *crush, struct crush_bucket *b) { switch (b->alg) { case CRUSH_BUCKET_UNIFORM: return crush_reweight_uniform_bucket(crush, (struct crush_bucket_uniform *)b); case CRUSH_BUCKET_LIST: return crush_reweight_list_bucket(crush, (struct crush_bucket_list *)b); case CRUSH_BUCKET_TREE: return crush_reweight_tree_bucket(crush, (struct crush_bucket_tree *)b); case CRUSH_BUCKET_STRAW: return crush_reweight_straw_bucket(crush, (struct crush_bucket_straw *)b); default: return -1; } return 0; } /***************************/ ceph-0.80.11/src/crush/Makefile.am0000664000175100017510000000115212623076744020643 0ustar jenkins-buildjenkins-buildlibcrush_la_SOURCES = \ crush/builder.c \ crush/mapper.c \ crush/crush.c \ crush/hash.c \ crush/CrushWrapper.cc \ crush/CrushCompiler.cc \ crush/CrushTester.cc noinst_LTLIBRARIES += libcrush.la noinst_HEADERS += \ crush/CrushCompiler.h \ crush/CrushTester.h \ crush/CrushWrapper.h \ crush/CrushWrapper.i \ crush/builder.h \ crush/crush.h \ crush/grammar.h \ crush/hash.h \ crush/mapper.h \ crush/sample.txt \ crush/types.h #crush_includedir = $(includedir)/crush #crush_include_DATA = \ # $(srcdir)/crush/hash.h \ # $(srcdir)/crush/crush.h \ # $(srcdir)/crush/mapper.h \ # $(srcdir)/crush/types.h ceph-0.80.11/src/crush/CrushTester.cc0000664000175100017510000004652412623076744021405 0ustar jenkins-buildjenkins-build #include "CrushTester.h" #include #include void CrushTester::set_device_weight(int dev, float f) { int w = (int)(f * 0x10000); if (w < 0) w = 0; if (w > 0x10000) w = 0x10000; device_weight[dev] = w; } int CrushTester::get_maximum_affected_by_rule(int ruleno) { // get the number of steps in RULENO int rule_size = crush.get_rule_len(ruleno); vector affected_types; map replications_by_type; for (int i = 0; i < rule_size; i++){ // get what operation is done by the current step int rule_operation = crush.get_rule_op(ruleno, i); // if the operation specifies choosing a device type, store it if (rule_operation >= 2 && rule_operation != 4){ int desired_replication = crush.get_rule_arg1(ruleno,i); int affected_type = crush.get_rule_arg2(ruleno,i); affected_types.push_back(affected_type); replications_by_type[affected_type] = desired_replication; } } /* * now for each of the affected bucket types, see what is the * maximum we are (a) requesting or (b) have */ map max_devices_of_type; // loop through the vector of affected types for (vector::iterator it = affected_types.begin(); it != affected_types.end(); ++it){ // loop through the number of buckets looking for affected types for (map::iterator p = crush.name_map.begin(); p != crush.name_map.end(); ++p){ int bucket_type = crush.get_bucket_type(p->first); if ( bucket_type == *it) max_devices_of_type[*it]++; } } for(std::vector::iterator it = affected_types.begin(); it != affected_types.end(); ++it){ if ( replications_by_type[*it] > 0 && replications_by_type[*it] < max_devices_of_type[*it] ) max_devices_of_type[*it] = replications_by_type[*it]; } /* * get the smallest number of buckets available of any type as this is our upper bound on * the number of replicas we can place */ int max_affected = max( crush.get_max_buckets(), crush.get_max_devices() ); for(std::vector::iterator it = affected_types.begin(); it != affected_types.end(); ++it){ if (max_devices_of_type[*it] > 0 && max_devices_of_type[*it] < max_affected ) max_affected = max_devices_of_type[*it]; } return max_affected; } map CrushTester::get_collapsed_mapping() { int num_to_check = crush.get_max_devices(); int next_id = 0; map collapse_mask; for (int i = 0; i < num_to_check; i++){ if (crush.check_item_present(i)){ collapse_mask[i] = next_id; next_id++; } } return collapse_mask; } void CrushTester::adjust_weights(vector<__u32>& weight) { if (mark_down_device_ratio > 0) { // active buckets vector bucket_ids; for (int i = 0; i < crush.get_max_buckets(); i++) { int id = -1 - i; if (crush.get_bucket_weight(id) > 0) { bucket_ids.push_back(id); } } // get buckets that are one level above a device vector buckets_above_devices; for (unsigned i = 0; i < bucket_ids.size(); i++) { // grab the first child object of a bucket and check if it's ID is less than 0 int id = bucket_ids[i]; if (crush.get_bucket_size(id) == 0) continue; int first_child = crush.get_bucket_item(id, 0); // returns the ID of the bucket or device if (first_child >= 0) { buckets_above_devices.push_back(id); } } // permute bucket list for (unsigned i = 0; i < buckets_above_devices.size(); i++) { unsigned j = lrand48() % (buckets_above_devices.size() - 1); std::swap(buckets_above_devices[i], buckets_above_devices[j]); } // calculate how many buckets and devices we need to reap... int num_buckets_to_visit = (int) (mark_down_bucket_ratio * buckets_above_devices.size()); for (int i = 0; i < num_buckets_to_visit; i++) { int id = buckets_above_devices[i]; int size = crush.get_bucket_size(id); vector items; for (int o = 0; o < size; o++) items.push_back(crush.get_bucket_item(id, o)); // permute items for (int o = 0; o < size; o++) { int j = lrand48() % (crush.get_bucket_size(id) - 1); std::swap(items[o], items[j]); } int local_devices_to_visit = (int) (mark_down_device_ratio*size); for (int o = 0; o < local_devices_to_visit; o++){ int item = crush.get_bucket_item(id, o); weight[item] = 0; } } } } bool CrushTester::check_valid_placement(int ruleno, vector in, const vector<__u32>& weight) { bool valid_placement = true; vector included_devices; map seen_devices; // first do the easy check that all devices are "up" for (vector::iterator it = in.begin(); it != in.end(); ++it) { if (weight[(*it)] == 0) { valid_placement = false; break; } else if (weight[(*it)] > 0) { included_devices.push_back( (*it) ); } } /* * now do the harder test of checking that the CRUSH rule r is not violated * we could test that none of the devices mentioned in out are unique, * but this is a special case of this test */ // get the number of steps in RULENO int rule_size = crush.get_rule_len(ruleno); vector affected_types; // get the smallest type id, and name int min_map_type = crush.get_num_type_names(); for (map::iterator it = crush.type_map.begin(); it != crush.type_map.end(); ++it ) { if ( (*it).first < min_map_type ) { min_map_type = (*it).first; } } string min_map_type_name = crush.type_map[min_map_type]; // get the types of devices affected by RULENO for (int i = 0; i < rule_size; i++) { // get what operation is done by the current step int rule_operation = crush.get_rule_op(ruleno, i); // if the operation specifies choosing a device type, store it if (rule_operation >= 2 && rule_operation != 4) { int affected_type = crush.get_rule_arg2(ruleno,i); affected_types.push_back( crush.get_type_name(affected_type)); } } // find in if we are only dealing with osd's bool only_osd_affected = false; if (affected_types.size() == 1) { if ((affected_types.back() == min_map_type_name) && (min_map_type_name == "osd")) { only_osd_affected = true; } } // check that we don't have any duplicate id's for (vector::iterator it = included_devices.begin(); it != included_devices.end(); ++it) { int num_copies = std::count(included_devices.begin(), included_devices.end(), (*it) ); if (num_copies > 1) { valid_placement = false; } } // if we have more than just osd's affected we need to do a lot more work if (!only_osd_affected) { // loop through the devices that are "in/up" for (vector::iterator it = included_devices.begin(); it != included_devices.end(); ++it) { if (valid_placement == false) break; // create a temporary map of the form (device type, device name in map) map device_location_hierarchy = crush.get_full_location(*it); // loop over the types affected by RULENO looking for duplicate bucket assignments for (vector::iterator t = affected_types.begin(); t != affected_types.end(); ++t) { if (seen_devices.count( device_location_hierarchy[*t])) { valid_placement = false; break; } else { // store the devices we have seen in the form of (device name, device type) seen_devices[ device_location_hierarchy[*t] ] = *t; } } } } return valid_placement; } int CrushTester::random_placement(int ruleno, vector& out, int maxout, vector<__u32>& weight) { // get the total weight of the system int total_weight = 0; for (unsigned i = 0; i < weight.size(); i++) total_weight += weight[i]; if (total_weight == 0 || crush.get_max_devices() == 0) return -EINVAL; // compute each device's proportional weight vector proportional_weights( weight.size() ); for (unsigned i = 0; i < weight.size(); i++) { proportional_weights[i] = (float) weight[i] / (float) total_weight; } // determine the real maximum number of devices to return int devices_requested = min(maxout, get_maximum_affected_by_rule(ruleno)); bool accept_placement = false; vector trial_placement(devices_requested); int attempted_tries = 0; int max_tries = 100; do { // create a vector to hold our trial mappings int temp_array[devices_requested]; for (int i = 0; i < devices_requested; i++){ temp_array[i] = lrand48() % (crush.get_max_devices()); } trial_placement.assign(temp_array, temp_array + devices_requested); accept_placement = check_valid_placement(ruleno, trial_placement, weight); attempted_tries++; } while (accept_placement == false && attempted_tries < max_tries); // save our random placement to the out vector if (accept_placement) out.assign(trial_placement.begin(), trial_placement.end()); // or don't.... else if (attempted_tries == max_tries) return -EINVAL; return 0; } void CrushTester::write_integer_indexed_vector_data_string(vector &dst, int index, vector vector_data) { stringstream data_buffer (stringstream::in | stringstream::out); unsigned input_size = vector_data.size(); // pass the indexing variable to the data buffer data_buffer << index; // pass the rest of the input data to the buffer for (unsigned i = 0; i < input_size; i++) { data_buffer << ',' << vector_data[i]; } data_buffer << std::endl; // write the data buffer to the destination dst.push_back( data_buffer.str() ); } void CrushTester::write_integer_indexed_vector_data_string(vector &dst, int index, vector vector_data) { stringstream data_buffer (stringstream::in | stringstream::out); unsigned input_size = vector_data.size(); // pass the indexing variable to the data buffer data_buffer << index; // pass the rest of the input data to the buffer for (unsigned i = 0; i < input_size; i++) { data_buffer << ',' << vector_data[i]; } data_buffer << std::endl; // write the data buffer to the destination dst.push_back( data_buffer.str() ); } void CrushTester::write_integer_indexed_scalar_data_string(vector &dst, int index, int scalar_data) { stringstream data_buffer (stringstream::in | stringstream::out); // pass the indexing variable to the data buffer data_buffer << index; // pass the input data to the buffer data_buffer << ',' << scalar_data; data_buffer << std::endl; // write the data buffer to the destination dst.push_back( data_buffer.str() ); } void CrushTester::write_integer_indexed_scalar_data_string(vector &dst, int index, float scalar_data) { stringstream data_buffer (stringstream::in | stringstream::out); // pass the indexing variable to the data buffer data_buffer << index; // pass the input data to the buffer data_buffer << ',' << scalar_data; data_buffer << std::endl; // write the data buffer to the destination dst.push_back( data_buffer.str() ); } int CrushTester::test() { if (min_rule < 0 || max_rule < 0) { min_rule = 0; max_rule = crush.get_max_rules() - 1; } if (min_x < 0 || max_x < 0) { min_x = 0; max_x = 1023; } // initial osd weights vector<__u32> weight; /* * note device weight is set by crushtool * (likely due to a given a command line option) */ for (int o = 0; o < crush.get_max_devices(); o++) { if (device_weight.count(o)) { weight.push_back(device_weight[o]); } else if (crush.check_item_present(o)) { weight.push_back(0x10000); } else { weight.push_back(0); } } if (output_utilization_all) err << "devices weights (hex): " << hex << weight << dec << std::endl; // make adjustments adjust_weights(weight); int num_devices_active = 0; for (vector<__u32>::iterator p = weight.begin(); p != weight.end(); ++p) if (*p > 0) num_devices_active++; if (output_choose_tries) crush.start_choose_profile(); for (int r = min_rule; r < crush.get_max_rules() && r <= max_rule; r++) { if (!crush.rule_exists(r)) { if (output_statistics) err << "rule " << r << " dne" << std::endl; continue; } int minr = min_rep, maxr = max_rep; if (min_rep < 0 || max_rep < 0) { minr = crush.get_rule_mask_min_size(r); maxr = crush.get_rule_mask_max_size(r); } if (output_statistics) err << "rule " << r << " (" << crush.get_rule_name(r) << "), x = " << min_x << ".." << max_x << ", numrep = " << minr << ".." << maxr << std::endl; for (int nr = minr; nr <= maxr; nr++) { vector per(crush.get_max_devices()); map sizes; int num_objects = ((max_x - min_x) + 1); float num_devices = (float) per.size(); // get the total number of devices, better to cast as a float here // create a structure to hold data for post-processing tester_data_set tester_data; vector vector_data_buffer; vector vector_data_buffer_f; // create a map to hold batch-level placement information map > batch_per; int objects_per_batch = num_objects / num_batches; int batch_min = min_x; int batch_max = min_x + objects_per_batch - 1; // get the total weight of the system int total_weight = 0; for (unsigned i = 0; i < per.size(); i++) total_weight += weight[i]; if (total_weight == 0) continue; // compute the expected number of objects stored per device in the absence of weighting float expected_objects = min(nr, get_maximum_affected_by_rule(r)) * num_objects; // compute each device's proportional weight vector proportional_weights( per.size() ); for (unsigned i = 0; i < per.size(); i++) proportional_weights[i] = (float) weight[i] / (float) total_weight; if (output_data_file) { // stage the absolute weight information for post-processing for (unsigned i = 0; i < per.size(); i++) { tester_data.absolute_weights[i] = (float) weight[i] / (float)0x10000; } // stage the proportional weight information for post-processing for (unsigned i = 0; i < per.size(); i++) { if (proportional_weights[i] > 0 ) tester_data.proportional_weights[i] = proportional_weights[i]; tester_data.proportional_weights_all[i] = proportional_weights[i]; } } // compute the expected number of objects stored per device when a device's weight is considered vector num_objects_expected(num_devices); for (unsigned i = 0; i < num_devices; i++) num_objects_expected[i] = (proportional_weights[i]*expected_objects); for (int current_batch = 0; current_batch < num_batches; current_batch++) { if (current_batch == (num_batches - 1)) { batch_max = max_x; objects_per_batch = (batch_max - batch_min + 1); } float batch_expected_objects = min(nr, get_maximum_affected_by_rule(r)) * objects_per_batch; vector batch_num_objects_expected( per.size() ); for (unsigned i = 0; i < per.size() ; i++) batch_num_objects_expected[i] = (proportional_weights[i]*batch_expected_objects); // create a vector to hold placement results temporarily vector temporary_per ( per.size() ); for (int x = batch_min; x <= batch_max; x++) { // create a vector to hold the results of a CRUSH placement or RNG simulation vector out; if (use_crush) { if (output_mappings) err << "CRUSH"; // prepend CRUSH to placement output crush.do_rule(r, x, out, nr, weight); } else { if (output_mappings) err << "RNG"; // prepend RNG to placement output to denote simulation // test our new monte carlo placement generator random_placement(r, out, nr, weight); } if (output_mappings) err << " rule " << r << " x " << x << " " << out << std::endl; if (output_data_file) write_integer_indexed_vector_data_string(tester_data.placement_information, x, out); bool has_item_none = false; for (unsigned i = 0; i < out.size(); i++) { if (out[i] != CRUSH_ITEM_NONE) { per[out[i]]++; temporary_per[out[i]]++; } else { has_item_none = true; } } batch_per[current_batch] = temporary_per; sizes[out.size()]++; if (output_bad_mappings && (out.size() != (unsigned)nr || has_item_none)) { err << "bad mapping rule " << r << " x " << x << " num_rep " << nr << " result " << out << std::endl; } } batch_min = batch_max + 1; batch_max = batch_min + objects_per_batch - 1; } for (unsigned i = 0; i < per.size(); i++) if (output_utilization && !output_statistics) err << " device " << i << ":\t" << per[i] << std::endl; for (map::iterator p = sizes.begin(); p != sizes.end(); ++p) if (output_statistics) err << "rule " << r << " (" << crush.get_rule_name(r) << ") num_rep " << nr << " result size == " << p->first << ":\t" << p->second << "/" << (max_x-min_x+1) << std::endl; if (output_statistics) for (unsigned i = 0; i < per.size(); i++) { if (output_utilization) { if (num_objects_expected[i] > 0 && per[i] > 0) { err << " device " << i << ":\t" << "\t" << " stored " << ": " << per[i] << "\t" << " expected " << ": " << num_objects_expected[i] << std::endl; } } else if (output_utilization_all) { err << " device " << i << ":\t" << "\t" << " stored " << ": " << per[i] << "\t" << " expected " << ": " << num_objects_expected[i] << std::endl; } } if (output_data_file) for (unsigned i = 0; i < per.size(); i++) { vector_data_buffer_f.clear(); vector_data_buffer_f.push_back( (float) per[i]); vector_data_buffer_f.push_back( (float) num_objects_expected[i]); write_integer_indexed_vector_data_string(tester_data.device_utilization_all, i, vector_data_buffer_f); if (num_objects_expected[i] > 0 && per[i] > 0) write_integer_indexed_vector_data_string(tester_data.device_utilization, i, vector_data_buffer_f); } if (output_data_file && num_batches > 1) { // stage batch utilization information for post-processing for (int i = 0; i < num_batches; i++) { write_integer_indexed_vector_data_string(tester_data.batch_device_utilization_all, i, batch_per[i]); write_integer_indexed_vector_data_string(tester_data.batch_device_expected_utilization_all, i, batch_per[i]); } } string rule_tag = crush.get_rule_name(r); if (output_csv) write_data_set_to_csv(output_data_file_name+rule_tag,tester_data); } } if (output_choose_tries) { __u32 *v = 0; int n = crush.get_choose_profile(&v); for (int i=0; i normal, 1.0 -> failed device 5 osd005 offload 0.1 device 6 osd006 offload 0.1 # hierarchy type 0 osd # 'device' is actually the default for 0 type 2 cab type 3 row type 10 pool cab root { id -1 # optional alg tree # required item osd001 item osd002 weight 600 pos 1 item osd003 weight 600 pos 0 item osd004 weight 600 pos 3 item osd005 weight 600 pos 4 } # rules rule normal { # these are required. pool 0 type replicated min_size 1 max_size 4 # need 1 or more of these. step take root step choose firstn 0 type osd step emit } rule { pool 1 type erasure min_size 3 max_size 6 step take root step choose indep 0 type osd step emit } ceph-0.80.11/src/crush/crush.c0000664000175100017510000000577012623076744020111 0ustar jenkins-buildjenkins-build #ifdef __KERNEL__ # include #else # include # include # define kfree(x) do { if (x) free(x); } while (0) # define BUG_ON(x) assert(!(x)) # include "include/int_types.h" #endif #include "crush.h" const char *crush_bucket_alg_name(int alg) { switch (alg) { case CRUSH_BUCKET_UNIFORM: return "uniform"; case CRUSH_BUCKET_LIST: return "list"; case CRUSH_BUCKET_TREE: return "tree"; case CRUSH_BUCKET_STRAW: return "straw"; default: return "unknown"; } } /** * crush_get_bucket_item_weight - Get weight of an item in given bucket * @b: bucket pointer * @p: item index in bucket */ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p) { if ((__u32)p >= b->size) return 0; switch (b->alg) { case CRUSH_BUCKET_UNIFORM: return ((struct crush_bucket_uniform *)b)->item_weight; case CRUSH_BUCKET_LIST: return ((struct crush_bucket_list *)b)->item_weights[p]; case CRUSH_BUCKET_TREE: return ((struct crush_bucket_tree *)b)->node_weights[crush_calc_tree_node(p)]; case CRUSH_BUCKET_STRAW: return ((struct crush_bucket_straw *)b)->item_weights[p]; } return 0; } void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b) { kfree(b->h.perm); kfree(b->h.items); kfree(b); } void crush_destroy_bucket_list(struct crush_bucket_list *b) { kfree(b->item_weights); kfree(b->sum_weights); kfree(b->h.perm); kfree(b->h.items); kfree(b); } void crush_destroy_bucket_tree(struct crush_bucket_tree *b) { kfree(b->h.perm); kfree(b->h.items); kfree(b->node_weights); kfree(b); } void crush_destroy_bucket_straw(struct crush_bucket_straw *b) { kfree(b->straws); kfree(b->item_weights); kfree(b->h.perm); kfree(b->h.items); kfree(b); } void crush_destroy_bucket(struct crush_bucket *b) { switch (b->alg) { case CRUSH_BUCKET_UNIFORM: crush_destroy_bucket_uniform((struct crush_bucket_uniform *)b); break; case CRUSH_BUCKET_LIST: crush_destroy_bucket_list((struct crush_bucket_list *)b); break; case CRUSH_BUCKET_TREE: crush_destroy_bucket_tree((struct crush_bucket_tree *)b); break; case CRUSH_BUCKET_STRAW: crush_destroy_bucket_straw((struct crush_bucket_straw *)b); break; } } /** * crush_destroy - Destroy a crush_map * @map: crush_map pointer */ void crush_destroy(struct crush_map *map) { /* buckets */ if (map->buckets) { __s32 b; for (b = 0; b < map->max_buckets; b++) { if (map->buckets[b] == NULL) continue; crush_destroy_bucket(map->buckets[b]); } kfree(map->buckets); } /* rules */ if (map->rules) { __u32 b; for (b = 0; b < map->max_rules; b++) crush_destroy_rule(map->rules[b]); kfree(map->rules); } kfree(map->choose_tries); kfree(map); } void crush_destroy_rule(struct crush_rule *rule) { kfree(rule); } // methods to check for safe arithmetic operations int crush_addition_is_unsafe(__u32 a, __u32 b) { if ((((__u32)(-1)) - b) < a) return 1; else return 0; } int crush_multiplication_is_unsafe(__u32 a, __u32 b) { if ((((__u32)(-1)) / b) < a) return 1; else return 0; } ceph-0.80.11/src/crush/CrushWrapper.i0000664000175100017510000000166712623076744021421 0ustar jenkins-buildjenkins-build/* File : CrushWrapper.i */ %module CrushWrapper %{ #include "CrushWrapper.h" %} %include typemaps.i // This tells SWIG to treat 'int *data' as a special case %typemap(in) int *items { AV *tempav; I32 len; int i; SV **tv; // int view; //printf("typemap\n"); if (!SvROK($input)) croak("$input is not a reference."); if (SvTYPE(SvRV($input)) != SVt_PVAV) croak("$input is not an array."); tempav = (AV*)SvRV($input); len = av_len(tempav); //printf("typemap len: %i\n",len); $1 = (int *) malloc((len+1)*sizeof(int)); for (i = 0; i <= len; i++) { tv = av_fetch(tempav, i, 0); $1[i] = (int) SvIV(*tv); /* view = SvIV(*tv); printf("view: %d",view); printf("\n"); */ } } %apply int *items { int *weights }; %apply double *OUTPUT { double *min, double *max, double *avg }; /* Let's just grab the original header file here */ %include "CrushWrapper.h" %clear double *min, double *max, double *avg; ceph-0.80.11/src/crush/mapper.c0000664000175100017510000004731512623076744020252 0ustar jenkins-buildjenkins-build #ifdef __KERNEL__ # include # include # include # include # ifndef dprintk # define dprintk(args...) # endif #else # include # include # include # include # define BUG_ON(x) assert(!(x)) # define dprintk(args...) /* printf(args) */ # define kmalloc(x, f) malloc(x) # define kfree(x) free(x) /*# define DEBUG_INDEP*/ # include "include/int_types.h" #endif #include "crush.h" #include "hash.h" /* * Implement the core CRUSH mapping algorithm. */ /** * crush_find_rule - find a crush_rule id for a given ruleset, type, and size. * @map: the crush_map * @ruleset: the storage ruleset id (user defined) * @type: storage ruleset type (user defined) * @size: output set size */ int crush_find_rule(const struct crush_map *map, int ruleset, int type, int size) { __u32 i; for (i = 0; i < map->max_rules; i++) { if (map->rules[i] && map->rules[i]->mask.ruleset == ruleset && map->rules[i]->mask.type == type && map->rules[i]->mask.min_size <= size && map->rules[i]->mask.max_size >= size) return i; } return -1; } /* * bucket choose methods * * For each bucket algorithm, we have a "choose" method that, given a * crush input @x and replica position (usually, position in output set) @r, * will produce an item in the bucket. */ /* * Choose based on a random permutation of the bucket. * * We used to use some prime number arithmetic to do this, but it * wasn't very random, and had some other bad behaviors. Instead, we * calculate an actual random permutation of the bucket members. * Since this is expensive, we optimize for the r=0 case, which * captures the vast majority of calls. */ static int bucket_perm_choose(struct crush_bucket *bucket, int x, int r) { unsigned int pr = r % bucket->size; unsigned int i, s; /* start a new permutation if @x has changed */ if (bucket->perm_x != (__u32)x || bucket->perm_n == 0) { dprintk("bucket %d new x=%d\n", bucket->id, x); bucket->perm_x = x; /* optimize common r=0 case */ if (pr == 0) { s = crush_hash32_3(bucket->hash, x, bucket->id, 0) % bucket->size; bucket->perm[0] = s; bucket->perm_n = 0xffff; /* magic value, see below */ goto out; } for (i = 0; i < bucket->size; i++) bucket->perm[i] = i; bucket->perm_n = 0; } else if (bucket->perm_n == 0xffff) { /* clean up after the r=0 case above */ for (i = 1; i < bucket->size; i++) bucket->perm[i] = i; bucket->perm[bucket->perm[0]] = 0; bucket->perm_n = 1; } /* calculate permutation up to pr */ for (i = 0; i < bucket->perm_n; i++) dprintk(" perm_choose have %d: %d\n", i, bucket->perm[i]); while (bucket->perm_n <= pr) { unsigned int p = bucket->perm_n; /* no point in swapping the final entry */ if (p < bucket->size - 1) { i = crush_hash32_3(bucket->hash, x, bucket->id, p) % (bucket->size - p); if (i) { unsigned int t = bucket->perm[p + i]; bucket->perm[p + i] = bucket->perm[p]; bucket->perm[p] = t; } dprintk(" perm_choose swap %d with %d\n", p, p+i); } bucket->perm_n++; } for (i = 0; i < bucket->size; i++) dprintk(" perm_choose %d: %d\n", i, bucket->perm[i]); s = bucket->perm[pr]; out: dprintk(" perm_choose %d sz=%d x=%d r=%d (%d) s=%d\n", bucket->id, bucket->size, x, r, pr, s); return bucket->items[s]; } /* uniform */ static int bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r) { return bucket_perm_choose(&bucket->h, x, r); } /* list */ static int bucket_list_choose(struct crush_bucket_list *bucket, int x, int r) { int i; for (i = bucket->h.size-1; i >= 0; i--) { __u64 w = crush_hash32_4(bucket->h.hash,x, bucket->h.items[i], r, bucket->h.id); w &= 0xffff; dprintk("list_choose i=%d x=%d r=%d item %d weight %x " "sw %x rand %llx", i, x, r, bucket->h.items[i], bucket->item_weights[i], bucket->sum_weights[i], w); w *= bucket->sum_weights[i]; w = w >> 16; /*dprintk(" scaled %llx\n", w);*/ if (w < bucket->item_weights[i]) return bucket->h.items[i]; } dprintk("bad list sums for bucket %d\n", bucket->h.id); return bucket->h.items[0]; } /* (binary) tree */ static int height(int n) { int h = 0; while ((n & 1) == 0) { h++; n = n >> 1; } return h; } static int left(int x) { int h = height(x); return x - (1 << (h-1)); } static int right(int x) { int h = height(x); return x + (1 << (h-1)); } static int terminal(int x) { return x & 1; } static int bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r) { int n; __u32 w; __u64 t; /* start at root */ n = bucket->num_nodes >> 1; while (!terminal(n)) { int l; /* pick point in [0, w) */ w = bucket->node_weights[n]; t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r, bucket->h.id) * (__u64)w; t = t >> 32; /* descend to the left or right? */ l = left(n); if (t < bucket->node_weights[l]) n = l; else n = right(n); } return bucket->h.items[n >> 1]; } /* straw */ static int bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r) { __u32 i; int high = 0; __u64 high_draw = 0; __u64 draw; for (i = 0; i < bucket->h.size; i++) { draw = crush_hash32_3(bucket->h.hash, x, bucket->h.items[i], r); draw &= 0xffff; draw *= bucket->straws[i]; if (i == 0 || draw > high_draw) { high = i; high_draw = draw; } } return bucket->h.items[high]; } static int crush_bucket_choose(struct crush_bucket *in, int x, int r) { dprintk(" crush_bucket_choose %d x=%d r=%d\n", in->id, x, r); BUG_ON(in->size == 0); switch (in->alg) { case CRUSH_BUCKET_UNIFORM: return bucket_uniform_choose((struct crush_bucket_uniform *)in, x, r); case CRUSH_BUCKET_LIST: return bucket_list_choose((struct crush_bucket_list *)in, x, r); case CRUSH_BUCKET_TREE: return bucket_tree_choose((struct crush_bucket_tree *)in, x, r); case CRUSH_BUCKET_STRAW: return bucket_straw_choose((struct crush_bucket_straw *)in, x, r); default: dprintk("unknown bucket %d alg %d\n", in->id, in->alg); return in->items[0]; } } /* * true if device is marked "out" (failed, fully offloaded) * of the cluster */ static int is_out(const struct crush_map *map, const __u32 *weight, int weight_max, int item, int x) { if (item >= weight_max) return 1; if (weight[item] >= 0x10000) return 0; if (weight[item] == 0) return 1; if ((crush_hash32_2(CRUSH_HASH_RJENKINS1, x, item) & 0xffff) < weight[item]) return 0; return 1; } /** * crush_choose_firstn - choose numrep distinct items of given type * @map: the crush_map * @bucket: the bucket we are choose an item from * @x: crush input value * @numrep: the number of items to choose * @type: the type of item to choose * @out: pointer to output vector * @outpos: our position in that vector * @out_size: size of the out vector * @tries: number of attempts to make * @recurse_tries: number of attempts to have recursive chooseleaf make * @local_retries: localized retries * @local_fallback_retries: localized fallback retries * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose) * @vary_r: pass r to recursive calls * @out2: second output vector for leaf items (if @recurse_to_leaf) * @parent_r: r value passed from the parent */ static int crush_choose_firstn(const struct crush_map *map, struct crush_bucket *bucket, const __u32 *weight, int weight_max, int x, int numrep, int type, int *out, int outpos, int out_size, unsigned int tries, unsigned int recurse_tries, unsigned int local_retries, unsigned int local_fallback_retries, int recurse_to_leaf, unsigned int vary_r, int *out2, int parent_r) { int rep; unsigned int ftotal, flocal; int retry_descent, retry_bucket, skip_rep; struct crush_bucket *in = bucket; int r; int i; int item = 0; int itemtype; int collide, reject; int count = out_size; dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d tries %d recurse_tries %d local_retries %d local_fallback_retries %d parent_r %d\n", recurse_to_leaf ? "_LEAF" : "", bucket->id, x, outpos, numrep, tries, recurse_tries, local_retries, local_fallback_retries, parent_r); for (rep = outpos; rep < numrep && count > 0 ; rep++) { /* keep trying until we get a non-out, non-colliding item */ ftotal = 0; skip_rep = 0; do { retry_descent = 0; in = bucket; /* initial bucket */ /* choose through intervening buckets */ flocal = 0; do { collide = 0; retry_bucket = 0; r = rep + parent_r; /* r' = r + f_total */ r += ftotal; /* bucket choose */ if (in->size == 0) { reject = 1; goto reject; } if (local_fallback_retries > 0 && flocal >= (in->size>>1) && flocal > local_fallback_retries) item = bucket_perm_choose(in, x, r); else item = crush_bucket_choose(in, x, r); if (item >= map->max_devices) { dprintk(" bad item %d\n", item); skip_rep = 1; break; } /* desired type? */ if (item < 0) itemtype = map->buckets[-1-item]->type; else itemtype = 0; dprintk(" item %d type %d\n", item, itemtype); /* keep going? */ if (itemtype != type) { if (item >= 0 || (-1-item) >= map->max_buckets) { dprintk(" bad item type %d\n", type); skip_rep = 1; break; } in = map->buckets[-1-item]; retry_bucket = 1; continue; } /* collision? */ for (i = 0; i < outpos; i++) { if (out[i] == item) { collide = 1; break; } } reject = 0; if (!collide && recurse_to_leaf) { if (item < 0) { int sub_r; if (vary_r) sub_r = r >> (vary_r-1); else sub_r = 0; if (crush_choose_firstn(map, map->buckets[-1-item], weight, weight_max, x, outpos+1, 0, out2, outpos, count, recurse_tries, 0, local_retries, local_fallback_retries, 0, vary_r, NULL, sub_r) <= outpos) /* didn't get leaf */ reject = 1; } else { /* we already have a leaf! */ out2[outpos] = item; } } if (!reject) { /* out? */ if (itemtype == 0) reject = is_out(map, weight, weight_max, item, x); else reject = 0; } reject: if (reject || collide) { ftotal++; flocal++; if (collide && flocal <= local_retries) /* retry locally a few times */ retry_bucket = 1; else if (local_fallback_retries > 0 && flocal <= in->size + local_fallback_retries) /* exhaustive bucket search */ retry_bucket = 1; else if (ftotal < tries) /* then retry descent */ retry_descent = 1; else /* else give up */ skip_rep = 1; dprintk(" reject %d collide %d " "ftotal %u flocal %u\n", reject, collide, ftotal, flocal); } } while (retry_bucket); } while (retry_descent); if (skip_rep) { dprintk("skip rep\n"); continue; } dprintk("CHOOSE got %d\n", item); out[outpos] = item; outpos++; count--; if (map->choose_tries && ftotal <= map->choose_total_tries) map->choose_tries[ftotal]++; } dprintk("CHOOSE returns %d\n", outpos); return outpos; } /** * crush_choose_indep: alternative breadth-first positionally stable mapping * */ static void crush_choose_indep(const struct crush_map *map, struct crush_bucket *bucket, const __u32 *weight, int weight_max, int x, int left, int numrep, int type, int *out, int outpos, unsigned int tries, unsigned int recurse_tries, int recurse_to_leaf, int *out2, int parent_r) { struct crush_bucket *in = bucket; int endpos = outpos + left; int rep; unsigned int ftotal; int r; int i; int item = 0; int itemtype; int collide; dprintk("CHOOSE%s INDEP bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "", bucket->id, x, outpos, numrep); /* initially my result is undefined */ for (rep = outpos; rep < endpos; rep++) { out[rep] = CRUSH_ITEM_UNDEF; if (out2) out2[rep] = CRUSH_ITEM_UNDEF; } for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) { #ifdef DEBUG_INDEP if (out2 && ftotal) { printf("%d %d a: ", ftotal, left); for (rep = outpos; rep < endpos; rep++) { printf(" %d", out[rep]); } printf("\n"); printf("%d %d b: ", ftotal, left); for (rep = outpos; rep < endpos; rep++) { printf(" %d", out2[rep]); } printf("\n"); } #endif for (rep = outpos; rep < endpos; rep++) { if (out[rep] != CRUSH_ITEM_UNDEF) continue; in = bucket; /* initial bucket */ /* choose through intervening buckets */ for (;;) { /* note: we base the choice on the position * even in the nested call. that means that * if the first layer chooses the same bucket * in a different position, we will tend to * choose a different item in that bucket. * this will involve more devices in data * movement and tend to distribute the load. */ r = rep + parent_r; /* be careful */ if (in->alg == CRUSH_BUCKET_UNIFORM && in->size % numrep == 0) /* r'=r+(n+1)*f_total */ r += (numrep+1) * ftotal; else /* r' = r + n*f_total */ r += numrep * ftotal; /* bucket choose */ if (in->size == 0) { dprintk(" empty bucket\n"); break; } item = crush_bucket_choose(in, x, r); if (item >= map->max_devices) { dprintk(" bad item %d\n", item); out[rep] = CRUSH_ITEM_NONE; if (out2) out2[rep] = CRUSH_ITEM_NONE; left--; break; } /* desired type? */ if (item < 0) itemtype = map->buckets[-1-item]->type; else itemtype = 0; dprintk(" item %d type %d\n", item, itemtype); /* keep going? */ if (itemtype != type) { if (item >= 0 || (-1-item) >= map->max_buckets) { dprintk(" bad item type %d\n", type); out[rep] = CRUSH_ITEM_NONE; if (out2) out2[rep] = CRUSH_ITEM_NONE; left--; break; } in = map->buckets[-1-item]; continue; } /* collision? */ collide = 0; for (i = outpos; i < endpos; i++) { if (out[i] == item) { collide = 1; break; } } if (collide) break; if (recurse_to_leaf) { if (item < 0) { crush_choose_indep(map, map->buckets[-1-item], weight, weight_max, x, 1, numrep, 0, out2, rep, recurse_tries, 0, 0, NULL, r); if (out2[rep] == CRUSH_ITEM_NONE) { /* placed nothing; no leaf */ break; } } else { /* we already have a leaf! */ out2[rep] = item; } } /* out? */ if (itemtype == 0 && is_out(map, weight, weight_max, item, x)) break; /* yay! */ out[rep] = item; left--; break; } } } for (rep = outpos; rep < endpos; rep++) { if (out[rep] == CRUSH_ITEM_UNDEF) { out[rep] = CRUSH_ITEM_NONE; } if (out2 && out2[rep] == CRUSH_ITEM_UNDEF) { out2[rep] = CRUSH_ITEM_NONE; } } #ifdef DEBUG_INDEP if (out2) { printf("%d %d a: ", ftotal, left); for (rep = outpos; rep < endpos; rep++) { printf(" %d", out[rep]); } printf("\n"); printf("%d %d b: ", ftotal, left); for (rep = outpos; rep < endpos; rep++) { printf(" %d", out2[rep]); } printf("\n"); } #endif } /** * crush_do_rule - calculate a mapping with the given input and rule * @map: the crush_map * @ruleno: the rule id * @x: hash input * @result: pointer to result vector * @result_max: maximum result size * @weight: weight vector (for map leaves) * @weight_max: size of weight vector * @scratch: scratch vector for private use; must be >= 3 * result_max */ int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, const __u32 *weight, int weight_max, int *scratch) { int result_len; int *a = scratch; int *b = scratch + result_max; int *c = scratch + result_max*2; int recurse_to_leaf; int *w; int wsize = 0; int *o; int osize; int *tmp; struct crush_rule *rule; __u32 step; int i, j; int numrep; int out_size; /* * the original choose_total_tries value was off by one (it * counted "retries" and not "tries"). add one. */ int choose_tries = map->choose_total_tries + 1; int choose_leaf_tries = 0; /* * the local tries values were counted as "retries", though, * and need no adjustment */ int choose_local_retries = map->choose_local_tries; int choose_local_fallback_retries = map->choose_local_fallback_tries; int vary_r = map->chooseleaf_vary_r; if ((__u32)ruleno >= map->max_rules) { dprintk(" bad ruleno %d\n", ruleno); return 0; } rule = map->rules[ruleno]; result_len = 0; w = a; o = b; for (step = 0; step < rule->len; step++) { int firstn = 0; struct crush_rule_step *curstep = &rule->steps[step]; switch (curstep->op) { case CRUSH_RULE_TAKE: w[0] = curstep->arg1; wsize = 1; break; case CRUSH_RULE_SET_CHOOSE_TRIES: if (curstep->arg1 > 0) choose_tries = curstep->arg1; break; case CRUSH_RULE_SET_CHOOSELEAF_TRIES: if (curstep->arg1 > 0) choose_leaf_tries = curstep->arg1; break; case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES: if (curstep->arg1 >= 0) choose_local_retries = curstep->arg1; break; case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES: if (curstep->arg1 >= 0) choose_local_fallback_retries = curstep->arg1; break; case CRUSH_RULE_SET_CHOOSELEAF_VARY_R: if (curstep->arg1 >= 0) vary_r = curstep->arg1; break; case CRUSH_RULE_CHOOSELEAF_FIRSTN: case CRUSH_RULE_CHOOSE_FIRSTN: firstn = 1; /* fall through */ case CRUSH_RULE_CHOOSELEAF_INDEP: case CRUSH_RULE_CHOOSE_INDEP: if (wsize == 0) break; recurse_to_leaf = curstep->op == CRUSH_RULE_CHOOSELEAF_FIRSTN || curstep->op == CRUSH_RULE_CHOOSELEAF_INDEP; /* reset output */ osize = 0; for (i = 0; i < wsize; i++) { /* * see CRUSH_N, CRUSH_N_MINUS macros. * basically, numrep <= 0 means relative to * the provided result_max */ numrep = curstep->arg1; if (numrep <= 0) { numrep += result_max; if (numrep <= 0) continue; } j = 0; if (firstn) { int recurse_tries; if (choose_leaf_tries) recurse_tries = choose_leaf_tries; else if (map->chooseleaf_descend_once) recurse_tries = 1; else recurse_tries = choose_tries; osize += crush_choose_firstn( map, map->buckets[-1-w[i]], weight, weight_max, x, numrep, curstep->arg2, o+osize, j, result_max-osize, choose_tries, recurse_tries, choose_local_retries, choose_local_fallback_retries, recurse_to_leaf, vary_r, c+osize, 0); } else { out_size = ((numrep < (result_max-osize)) ? numrep : (result_max-osize)); crush_choose_indep( map, map->buckets[-1-w[i]], weight, weight_max, x, out_size, numrep, curstep->arg2, o+osize, j, choose_tries, choose_leaf_tries ? choose_leaf_tries : 1, recurse_to_leaf, c+osize, 0); osize += out_size; } } if (recurse_to_leaf) /* copy final _leaf_ values to output set */ memcpy(o, c, osize*sizeof(*o)); /* swap o and w arrays */ tmp = o; o = w; w = tmp; wsize = osize; break; case CRUSH_RULE_EMIT: for (i = 0; i < wsize && result_len < result_max; i++) { result[result_len] = w[i]; result_len++; } wsize = 0; break; default: dprintk(" unknown op %d at step %d\n", curstep->op, step); break; } } return result_len; } ceph-0.80.11/src/crush/crush.h0000664000175100017510000001463112623076744020112 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRUSH_CRUSH_H #define CEPH_CRUSH_CRUSH_H #include "include/int_types.h" #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif /* * CRUSH is a pseudo-random data distribution algorithm that * efficiently distributes input values (typically, data objects) * across a heterogeneous, structured storage cluster. * * The algorithm was originally described in detail in this paper * (although the algorithm has evolved somewhat since then): * * http://www.ssrc.ucsc.edu/Papers/weil-sc06.pdf * * LGPL2 */ #define CRUSH_MAGIC 0x00010000ul /* for detecting algorithm revisions */ #define CRUSH_MAX_DEPTH 10 /* max crush hierarchy depth */ #define CRUSH_MAX_RULESET (1<<8) /*max crush ruleset number*/ #define CRUSH_MAX_RULES CRUSH_MAX_RULESET /*max crush rules, shold be the same as max rulesets*/ #define CRUSH_MAX_DEVICE_WEIGHT (100u * 0x10000u) #define CRUSH_MAX_BUCKET_WEIGHT (65535u * 0x10000u) #define CRUSH_ITEM_UNDEF 0x7ffffffe /* undefined result (internal use only) */ #define CRUSH_ITEM_NONE 0x7fffffff /* no result */ /* * CRUSH uses user-defined "rules" to describe how inputs should be * mapped to devices. A rule consists of sequence of steps to perform * to generate the set of output devices. */ struct crush_rule_step { __u32 op; __s32 arg1; __s32 arg2; }; /* step op codes */ enum { CRUSH_RULE_NOOP = 0, CRUSH_RULE_TAKE = 1, /* arg1 = value to start with */ CRUSH_RULE_CHOOSE_FIRSTN = 2, /* arg1 = num items to pick */ /* arg2 = type */ CRUSH_RULE_CHOOSE_INDEP = 3, /* same */ CRUSH_RULE_EMIT = 4, /* no args */ CRUSH_RULE_CHOOSELEAF_FIRSTN = 6, CRUSH_RULE_CHOOSELEAF_INDEP = 7, CRUSH_RULE_SET_CHOOSE_TRIES = 8, /* override choose_total_tries */ CRUSH_RULE_SET_CHOOSELEAF_TRIES = 9, /* override chooseleaf_descend_once */ CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES = 10, CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES = 11, CRUSH_RULE_SET_CHOOSELEAF_VARY_R = 12 }; /* * for specifying choose num (arg1) relative to the max parameter * passed to do_rule */ #define CRUSH_CHOOSE_N 0 #define CRUSH_CHOOSE_N_MINUS(x) (-(x)) /* * The rule mask is used to describe what the rule is intended for. * Given a ruleset and size of output set, we search through the * rule list for a matching rule_mask. */ struct crush_rule_mask { __u8 ruleset; __u8 type; __u8 min_size; __u8 max_size; }; struct crush_rule { __u32 len; struct crush_rule_mask mask; struct crush_rule_step steps[0]; }; #define crush_rule_size(len) (sizeof(struct crush_rule) + \ (len)*sizeof(struct crush_rule_step)) /* * A bucket is a named container of other items (either devices or * other buckets). Items within a bucket are chosen using one of a * few different algorithms. The table summarizes how the speed of * each option measures up against mapping stability when items are * added or removed. * * Bucket Alg Speed Additions Removals * ------------------------------------------------ * uniform O(1) poor poor * list O(n) optimal poor * tree O(log n) good good * straw O(n) optimal optimal */ enum { CRUSH_BUCKET_UNIFORM = 1, CRUSH_BUCKET_LIST = 2, CRUSH_BUCKET_TREE = 3, CRUSH_BUCKET_STRAW = 4 }; extern const char *crush_bucket_alg_name(int alg); struct crush_bucket { __s32 id; /* this'll be negative */ __u16 type; /* non-zero; type=0 is reserved for devices */ __u8 alg; /* one of CRUSH_BUCKET_* */ __u8 hash; /* which hash function to use, CRUSH_HASH_* */ __u32 weight; /* 16-bit fixed point */ __u32 size; /* num items */ __s32 *items; /* * cached random permutation: used for uniform bucket and for * the linear search fallback for the other bucket types. */ __u32 perm_x; /* @x for which *perm is defined */ __u32 perm_n; /* num elements of *perm that are permuted/defined */ __u32 *perm; }; struct crush_bucket_uniform { struct crush_bucket h; __u32 item_weight; /* 16-bit fixed point; all items equally weighted */ }; struct crush_bucket_list { struct crush_bucket h; __u32 *item_weights; /* 16-bit fixed point */ __u32 *sum_weights; /* 16-bit fixed point. element i is sum of weights 0..i, inclusive */ }; struct crush_bucket_tree { struct crush_bucket h; /* note: h.size is _tree_ size, not number of actual items */ __u8 num_nodes; __u32 *node_weights; }; struct crush_bucket_straw { struct crush_bucket h; __u32 *item_weights; /* 16-bit fixed point */ __u32 *straws; /* 16-bit fixed point */ }; /* * CRUSH map includes all buckets, rules, etc. */ struct crush_map { struct crush_bucket **buckets; struct crush_rule **rules; __s32 max_buckets; __u32 max_rules; __s32 max_devices; /* choose local retries before re-descent */ __u32 choose_local_tries; /* choose local attempts using a fallback permutation before * re-descent */ __u32 choose_local_fallback_tries; /* choose attempts before giving up */ __u32 choose_total_tries; /* attempt chooseleaf inner descent once for firstn mode; on * reject retry outer descent. Note that this does *not* * apply to a collision: in that case we will retry as we used * to. */ __u32 chooseleaf_descend_once; /* if non-zero, feed r into chooseleaf, bit-shifted right by (r-1) * bits. a value of 1 is best for new clusters. for legacy clusters * that want to limit reshuffling, a value of 3 or 4 will make the * mappings line up a bit better with previous mappings. */ __u8 chooseleaf_vary_r; /* * version 0 (original) of straw_calc has various flaws. version 1 * fixes a few of them. */ __u8 straw_calc_version; __u32 *choose_tries; }; /* crush.c */ extern int crush_get_bucket_item_weight(const struct crush_bucket *b, int pos); extern int crush_addition_is_unsafe(__u32 a, __u32 b); extern int crush_multiplication_is_unsafe(__u32 a, __u32 b); extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b); extern void crush_destroy_bucket_list(struct crush_bucket_list *b); extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b); extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b); extern void crush_destroy_bucket(struct crush_bucket *b); extern void crush_destroy_rule(struct crush_rule *r); extern void crush_destroy(struct crush_map *map); static inline int crush_calc_tree_node(int i) { return ((i+1) << 1)-1; } #endif ceph-0.80.11/src/crush/types.h0000664000175100017510000000036512623076744020131 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRUSH_TYPES_H #define CEPH_CRUSH_TYPES_H #ifdef KERNEL # define free(x) kfree(x) #else # include #endif #include /* just for int types */ #ifndef BUG_ON # define BUG_ON(x) assert(!(x)) #endif #endif ceph-0.80.11/src/crush/builder.h0000664000175100017510000000345312623076744020414 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRUSH_BUILDER_H #define CEPH_CRUSH_BUILDER_H #include "crush.h" extern struct crush_map *crush_create(); extern void crush_finalize(struct crush_map *map); /* rules */ extern struct crush_rule *crush_make_rule(int len, int ruleset, int type, int minsize, int maxsize); extern void crush_rule_set_step(struct crush_rule *rule, int pos, int op, int arg1, int arg2); extern int crush_add_rule(struct crush_map *map, struct crush_rule *rule, int ruleno); /* buckets */ extern int crush_get_next_bucket_id(struct crush_map *map); extern int crush_add_bucket(struct crush_map *map, int bucketno, struct crush_bucket *bucket, int *idout); struct crush_bucket *crush_make_bucket(struct crush_map *map, int alg, int hash, int type, int size, int *items, int *weights); extern int crush_bucket_add_item(struct crush_map *map, struct crush_bucket *bucket, int item, int weight); extern int crush_bucket_adjust_item_weight(struct crush_map *map, struct crush_bucket *bucket, int item, int weight); extern int crush_reweight_bucket(struct crush_map *crush, struct crush_bucket *bucket); extern int crush_remove_bucket(struct crush_map *map, struct crush_bucket *bucket); extern int crush_bucket_remove_item(struct crush_map *map, struct crush_bucket *bucket, int item); struct crush_bucket_uniform * crush_make_uniform_bucket(int hash, int type, int size, int *items, int item_weight); struct crush_bucket_list* crush_make_list_bucket(int hash, int type, int size, int *items, int *weights); struct crush_bucket_tree* crush_make_tree_bucket(int hash, int type, int size, int *items, /* in leaf order */ int *weights); struct crush_bucket_straw * crush_make_straw_bucket(struct crush_map *map, int hash, int type, int size, int *items, int *weights); #endif ceph-0.80.11/src/crush/hash.h0000664000175100017510000000101612623076744017702 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRUSH_HASH_H #define CEPH_CRUSH_HASH_H #define CRUSH_HASH_RJENKINS1 0 #define CRUSH_HASH_DEFAULT CRUSH_HASH_RJENKINS1 extern const char *crush_hash_name(int type); extern __u32 crush_hash32(int type, __u32 a); extern __u32 crush_hash32_2(int type, __u32 a, __u32 b); extern __u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c); extern __u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d); extern __u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d, __u32 e); #endif ceph-0.80.11/src/crush/CrushCompiler.h0000664000175100017510000000335112623076744021542 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CRUSH_COMPILER_H #define CEPH_CRUSH_COMPILER_H #include "crush/CrushWrapper.h" #include "crush/grammar.h" #include #include #include class CrushCompiler { CrushWrapper& crush; ostream& err; int verbose; bool unsafe_tunables; // decompile enum dcb_state_t { DCB_STATE_IN_PROGRESS = 0, DCB_STATE_DONE }; int decompile_bucket_impl(int i, ostream &out); int decompile_bucket(int cur, std::map& dcb_states, ostream &out); // compile typedef char const* iterator_t; typedef tree_match parse_tree_match_t; typedef parse_tree_match_t::tree_iterator iter_t; typedef parse_tree_match_t::node_t node_t; map item_id; map id_item; map item_weight; map type_id; map rule_id; string string_node(node_t &node); int int_node(node_t &node); float float_node(node_t &node); int parse_tunable(iter_t const& i); int parse_device(iter_t const& i); int parse_bucket_type(iter_t const& i); int parse_bucket(iter_t const& i); int parse_rule(iter_t const& i); void find_used_bucket_ids(iter_t const& i); int parse_crush(iter_t const& i); void dump(iter_t const& i, int ind=1); string consolidate_whitespace(string in); public: CrushCompiler(CrushWrapper& c, ostream& eo, int verbosity=0) : crush(c), err(eo), verbose(verbosity), unsafe_tunables(false) {} ~CrushCompiler() {} void enable_unsafe_tunables() { unsafe_tunables = true; } int decompile(ostream& out); int compile(istream& in, const char *infn=0); }; #endif ceph-0.80.11/src/crush/CrushWrapper.cc0000664000175100017510000012574712623076744021564 0ustar jenkins-buildjenkins-build #include "osd/osd_types.h" #include "common/debug.h" #include "common/Formatter.h" #include "common/errno.h" #include "CrushWrapper.h" #define dout_subsys ceph_subsys_crush bool CrushWrapper::has_v2_rules() const { for (unsigned i=0; imax_rules; i++) { if (is_v2_rule(i)) { return true; } } return false; } bool CrushWrapper::is_v2_rule(unsigned ruleid) const { // check rule for use of indep or new SET_* rule steps if (ruleid >= crush->max_rules) return false; crush_rule *r = crush->rules[ruleid]; if (!r) return false; for (unsigned j=0; jlen; j++) { if (r->steps[j].op == CRUSH_RULE_CHOOSE_INDEP || r->steps[j].op == CRUSH_RULE_CHOOSELEAF_INDEP || r->steps[j].op == CRUSH_RULE_SET_CHOOSE_TRIES || r->steps[j].op == CRUSH_RULE_SET_CHOOSELEAF_TRIES) { return true; } } return false; } bool CrushWrapper::has_v3_rules() const { for (unsigned i=0; imax_rules; i++) { if (is_v3_rule(i)) { return true; } } return false; } bool CrushWrapper::is_v3_rule(unsigned ruleid) const { // check rule for use of SET_CHOOSELEAF_VARY_R step if (ruleid >= crush->max_rules) return false; crush_rule *r = crush->rules[ruleid]; if (!r) return false; for (unsigned j=0; jlen; j++) { if (r->steps[j].op == CRUSH_RULE_SET_CHOOSELEAF_VARY_R) { return true; } } return false; } void CrushWrapper::find_takes(set& roots) const { for (unsigned i=0; imax_rules; i++) { crush_rule *r = crush->rules[i]; if (!r) continue; for (unsigned j=0; jlen; j++) { if (r->steps[j].op == CRUSH_RULE_TAKE) roots.insert(r->steps[j].arg1); } } } void CrushWrapper::find_roots(set& roots) const { for (int i = 0; i < crush->max_buckets; i++) { if (!crush->buckets[i]) continue; crush_bucket *b = crush->buckets[i]; if (!_search_item_exists(b->id)) roots.insert(b->id); } } bool CrushWrapper::subtree_contains(int root, int item) const { if (root == item) return true; if (root >= 0) return false; // root is a leaf const crush_bucket *b = get_bucket(root); if (!b) return false; for (unsigned j=0; jsize; j++) { if (subtree_contains(b->items[j], item)) return true; } return false; } bool CrushWrapper::_maybe_remove_last_instance(CephContext *cct, int item, bool unlink_only) { // last instance? if (_search_item_exists(item)) { return false; } if (item < 0 && _bucket_is_in_use(cct, item)) { return false; } if (item < 0 && !unlink_only) { crush_bucket *t = get_bucket(item); ldout(cct, 5) << "_maybe_remove_last_instance removing bucket " << item << dendl; crush_remove_bucket(crush, t); } if ((item >= 0 || !unlink_only) && name_map.count(item)) { ldout(cct, 5) << "_maybe_remove_last_instance removing name for item " << item << dendl; name_map.erase(item); have_rmaps = false; } return true; } int CrushWrapper::remove_item(CephContext *cct, int item, bool unlink_only) { ldout(cct, 5) << "remove_item " << item << (unlink_only ? " unlink_only":"") << dendl; int ret = -ENOENT; if (item < 0 && !unlink_only) { crush_bucket *t = get_bucket(item); if (t && t->size) { ldout(cct, 1) << "remove_item bucket " << item << " has " << t->size << " items, not empty" << dendl; return -ENOTEMPTY; } if (_bucket_is_in_use(cct, item)) { return -EBUSY; } } for (int i = 0; i < crush->max_buckets; i++) { if (!crush->buckets[i]) continue; crush_bucket *b = crush->buckets[i]; for (unsigned i=0; isize; ++i) { int id = b->items[i]; if (id == item) { ldout(cct, 5) << "remove_item removing item " << item << " from bucket " << b->id << dendl; crush_bucket_remove_item(crush, b, item); adjust_item_weight(cct, b->id, b->weight); ret = 0; } } } if (_maybe_remove_last_instance(cct, item, unlink_only)) ret = 0; return ret; } bool CrushWrapper::_search_item_exists(int item) const { for (int i = 0; i < crush->max_buckets; i++) { if (!crush->buckets[i]) continue; crush_bucket *b = crush->buckets[i]; for (unsigned j=0; jsize; ++j) { if (b->items[j] == item) return true; } } return false; } bool CrushWrapper::_bucket_is_in_use(CephContext *cct, int item) { for (unsigned i = 0; i < crush->max_rules; ++i) { crush_rule *r = crush->rules[i]; if (!r) continue; for (unsigned j = 0; j < r->len; ++j) { if (r->steps[j].op == CRUSH_RULE_TAKE && r->steps[j].arg1 == item) { return true; } } } return false; } int CrushWrapper::_remove_item_under(CephContext *cct, int item, int ancestor, bool unlink_only) { ldout(cct, 5) << "_remove_item_under " << item << " under " << ancestor << (unlink_only ? " unlink_only":"") << dendl; if (ancestor >= 0) { return -EINVAL; } if (!bucket_exists(ancestor)) return -EINVAL; int ret = -ENOENT; crush_bucket *b = get_bucket(ancestor); for (unsigned i=0; isize; ++i) { int id = b->items[i]; if (id == item) { ldout(cct, 5) << "_remove_item_under removing item " << item << " from bucket " << b->id << dendl; crush_bucket_remove_item(crush, b, item); adjust_item_weight(cct, b->id, b->weight); ret = 0; } else if (id < 0) { int r = remove_item_under(cct, item, id, unlink_only); if (r == 0) ret = 0; } } return ret; } int CrushWrapper::remove_item_under(CephContext *cct, int item, int ancestor, bool unlink_only) { ldout(cct, 5) << "remove_item_under " << item << " under " << ancestor << (unlink_only ? " unlink_only":"") << dendl; if (!unlink_only && _bucket_is_in_use(cct, item)) { return -EBUSY; } int ret = _remove_item_under(cct, item, ancestor, unlink_only); if (ret < 0) return ret; if (item < 0 && !unlink_only) { crush_bucket *t = get_bucket(item); if (t && t->size) { ldout(cct, 1) << "remove_item_undef bucket " << item << " has " << t->size << " items, not empty" << dendl; return -ENOTEMPTY; } } if (_maybe_remove_last_instance(cct, item, unlink_only)) ret = 0; return ret; } int CrushWrapper::get_common_ancestor_distance(CephContext *cct, int id, const std::multimap& loc) { ldout(cct, 5) << __func__ << " " << id << " " << loc << dendl; if (!item_exists(id)) return -ENOENT; map id_loc = get_full_location(id); ldout(cct, 20) << " id is at " << id_loc << dendl; for (map::const_iterator p = type_map.begin(); p != type_map.end(); ++p) { map::iterator ip = id_loc.find(p->second); if (ip == id_loc.end()) continue; for (std::multimap::const_iterator q = loc.find(p->second); q != loc.end(); ++q) { if (q->first != p->second) break; if (q->second == ip->second) return p->first; } } return -ERANGE; } int CrushWrapper::parse_loc_map(const std::vector& args, std::map *ploc) { ploc->clear(); for (unsigned i = 0; i < args.size(); ++i) { const char *s = args[i].c_str(); const char *pos = strchr(s, '='); if (!pos) return -EINVAL; string key(s, 0, pos-s); string value(pos+1); if (value.length()) (*ploc)[key] = value; else return -EINVAL; } return 0; } int CrushWrapper::parse_loc_multimap(const std::vector& args, std::multimap *ploc) { ploc->clear(); for (unsigned i = 0; i < args.size(); ++i) { const char *s = args[i].c_str(); const char *pos = strchr(s, '='); if (!pos) return -EINVAL; string key(s, 0, pos-s); string value(pos+1); if (value.length()) ploc->insert(make_pair(key, value)); else return -EINVAL; } return 0; } bool CrushWrapper::check_item_loc(CephContext *cct, int item, const map& loc, int *weight) { ldout(cct, 5) << "check_item_loc item " << item << " loc " << loc << dendl; for (map::const_iterator p = type_map.begin(); p != type_map.end(); ++p) { // ignore device if (p->first == 0) continue; // ignore types that aren't specified in loc map::const_iterator q = loc.find(p->second); if (q == loc.end()) { ldout(cct, 2) << "warning: did not specify location for '" << p->second << "' level (levels are " << type_map << ")" << dendl; continue; } if (!name_exists(q->second)) { ldout(cct, 5) << "check_item_loc bucket " << q->second << " dne" << dendl; return false; } int id = get_item_id(q->second); if (id >= 0) { ldout(cct, 5) << "check_item_loc requested " << q->second << " for type " << p->second << " is a device, not bucket" << dendl; return false; } crush_bucket *b = get_bucket(id); assert(b); // see if item exists in this bucket for (unsigned j=0; jsize; j++) { if (b->items[j] == item) { ldout(cct, 2) << "check_item_loc " << item << " exists in bucket " << b->id << dendl; if (weight) *weight = crush_get_bucket_item_weight(b, j); return true; } } return false; } ldout(cct, 1) << "check_item_loc item " << item << " loc " << loc << dendl; return false; } map CrushWrapper::get_full_location(int id) { vector > full_location_ordered; map full_location; get_full_location_ordered(id, full_location_ordered); std::copy(full_location_ordered.begin(), full_location_ordered.end(), std::inserter(full_location, full_location.begin())); return full_location; } int CrushWrapper::get_full_location_ordered(int id, vector >& path) { if (!item_exists(id)) return -ENOENT; int cur = id; int ret; while (true) { pair parent_coord = get_immediate_parent(cur, &ret); if (ret != 0) break; path.push_back(parent_coord); cur = get_item_id(parent_coord.second); } return 0; } map CrushWrapper::get_parent_hierarchy(int id) { map parent_hierarchy; pair parent_coord = get_immediate_parent(id); int parent_id; // get the integer type for id and create a counter from there int type_counter = get_bucket_type(id); // if we get a negative type then we can assume that we have an OSD // change behavior in get_item_type FIXME if (type_counter < 0) type_counter = 0; // read the type map and get the name of the type with the largest ID int high_type = 0; for (map::iterator it = type_map.begin(); it != type_map.end(); ++it){ if ( (*it).first > high_type ) high_type = (*it).first; } parent_id = get_item_id(parent_coord.second); while (type_counter < high_type) { type_counter++; parent_hierarchy[ type_counter ] = parent_coord.first; if (type_counter < high_type){ // get the coordinate information for the next parent parent_coord = get_immediate_parent(parent_id); parent_id = get_item_id(parent_coord.second); } } return parent_hierarchy; } int CrushWrapper::get_children(int id, list *children) { // leaf? if (id >= 0) { return 0; } crush_bucket *b = get_bucket(id); if (!b) { return -ENOENT; } for (unsigned n=0; nsize; n++) { children->push_back(b->items[n]); } return b->size; } int CrushWrapper::insert_item(CephContext *cct, int item, float weight, string name, const map& loc) // typename -> bucketname { ldout(cct, 5) << "insert_item item " << item << " weight " << weight << " name " << name << " loc " << loc << dendl; if (!is_valid_crush_name(name)) return -EINVAL; if (!is_valid_crush_loc(cct, loc)) return -EINVAL; if (name_exists(name)) { if (get_item_id(name) != item) { ldout(cct, 10) << "device name '" << name << "' already exists as id " << get_item_id(name) << dendl; return -EEXIST; } } else { set_item_name(item, name); } int cur = item; // create locations if locations don't exist and add child in location with 0 weight // the more detail in the insert_item method declaration in CrushWrapper.h for (map::iterator p = type_map.begin(); p != type_map.end(); ++p) { // ignore device type if (p->first == 0) continue; // skip types that are unspecified map::const_iterator q = loc.find(p->second); if (q == loc.end()) { ldout(cct, 2) << "warning: did not specify location for '" << p->second << "' level (levels are " << type_map << ")" << dendl; continue; } if (!name_exists(q->second)) { ldout(cct, 5) << "insert_item creating bucket " << q->second << dendl; int empty = 0, newid; int r = add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_DEFAULT, p->first, 1, &cur, &empty, &newid); if (r < 0) { ldout(cct, 1) << "add_bucket failure error: " << cpp_strerror(r) << dendl; return r; } set_item_name(newid, q->second); cur = newid; continue; } // add to an existing bucket int id = get_item_id(q->second); if (!bucket_exists(id)) { ldout(cct, 1) << "insert_item doesn't have bucket " << id << dendl; return -EINVAL; } // check that we aren't creating a cycle. if (subtree_contains(id, cur)) { ldout(cct, 1) << "insert_item item " << cur << " already exists beneath " << id << dendl; return -EINVAL; } crush_bucket *b = get_bucket(id); assert(b); if (p->first != b->type) { ldout(cct, 1) << "insert_item existing bucket has type " << "'" << type_map[b->type] << "' != " << "'" << type_map[p->first] << "'" << dendl; return -EINVAL; } // are we forming a loop? if (subtree_contains(cur, b->id)) { ldout(cct, 1) << "insert_item " << cur << " already contains " << b->id << "; cannot form loop" << dendl; return -ELOOP; } ldout(cct, 5) << "insert_item adding " << cur << " weight " << weight << " to bucket " << id << dendl; int r = crush_bucket_add_item(crush, b, cur, 0); assert (!r); break; } // adjust the item's weight in location if(adjust_item_weightf_in_loc(cct, item, weight, loc) > 0) { if (item >= crush->max_devices) { crush->max_devices = item + 1; ldout(cct, 5) << "insert_item max_devices now " << crush->max_devices << dendl; } return 0; } ldout(cct, 1) << "error: didn't find anywhere to add item " << item << " in " << loc << dendl; return -EINVAL; } int CrushWrapper::move_bucket(CephContext *cct, int id, const map& loc) { // sorry this only works for buckets if (id >= 0) return -EINVAL; if (!item_exists(id)) return -ENOENT; // get the name of the bucket we are trying to move for later string id_name = get_item_name(id); // detach the bucket int bucket_weight = detach_bucket(cct, id); // insert the bucket back into the hierarchy return insert_item(cct, id, bucket_weight / (float)0x10000, id_name, loc); } int CrushWrapper::link_bucket(CephContext *cct, int id, const map& loc) { // sorry this only works for buckets if (id >= 0) return -EINVAL; if (!item_exists(id)) return -ENOENT; // get the name of the bucket we are trying to move for later string id_name = get_item_name(id); crush_bucket *b = get_bucket(id); unsigned bucket_weight = b->weight; return insert_item(cct, id, bucket_weight / (float)0x10000, id_name, loc); } int CrushWrapper::create_or_move_item(CephContext *cct, int item, float weight, string name, const map& loc) // typename -> bucketname { int ret = 0; int old_iweight; if (!is_valid_crush_name(name)) return -EINVAL; if (check_item_loc(cct, item, loc, &old_iweight)) { ldout(cct, 5) << "create_or_move_item " << item << " already at " << loc << dendl; } else { if (_search_item_exists(item)) { weight = get_item_weightf(item); ldout(cct, 10) << "create_or_move_item " << item << " exists with weight " << weight << dendl; remove_item(cct, item, true); } ldout(cct, 5) << "create_or_move_item adding " << item << " weight " << weight << " at " << loc << dendl; ret = insert_item(cct, item, weight, name, loc); if (ret == 0) ret = 1; // changed } return ret; } int CrushWrapper::update_item(CephContext *cct, int item, float weight, string name, const map& loc) // typename -> bucketname { ldout(cct, 5) << "update_item item " << item << " weight " << weight << " name " << name << " loc " << loc << dendl; int ret = 0; if (!is_valid_crush_name(name)) return -EINVAL; if (!is_valid_crush_loc(cct, loc)) return -EINVAL; // compare quantized (fixed-point integer) weights! int iweight = (int)(weight * (float)0x10000); int old_iweight; if (check_item_loc(cct, item, loc, &old_iweight)) { ldout(cct, 5) << "update_item " << item << " already at " << loc << dendl; if (old_iweight != iweight) { ldout(cct, 5) << "update_item " << item << " adjusting weight " << ((float)old_iweight/(float)0x10000) << " -> " << weight << dendl; adjust_item_weight_in_loc(cct, item, iweight, loc); ret = 1; } if (get_item_name(item) != name) { ldout(cct, 5) << "update_item setting " << item << " name to " << name << dendl; set_item_name(item, name); ret = 1; } } else { if (item_exists(item)) { remove_item(cct, item, true); } ldout(cct, 5) << "update_item adding " << item << " weight " << weight << " at " << loc << dendl; ret = insert_item(cct, item, weight, name, loc); if (ret == 0) ret = 1; // changed } return ret; } int CrushWrapper::get_item_weight(int id) const { for (int bidx = 0; bidx < crush->max_buckets; bidx++) { crush_bucket *b = crush->buckets[bidx]; if (b == NULL) continue; for (unsigned i = 0; i < b->size; i++) if (b->items[i] == id) return crush_get_bucket_item_weight(b, i); } return -ENOENT; } int CrushWrapper::get_item_weight_in_loc(int id, const map &loc) { for (map::const_iterator l = loc.begin(); l != loc.end(); l++) { int bid = get_item_id(l->second); if (!bucket_exists(bid)) continue; crush_bucket *b = get_bucket(bid); if ( b == NULL) continue; for (unsigned int i = 0; i < b->size; i++) { if (b->items[i] == id) { return crush_get_bucket_item_weight(b, i); } } } return -ENOENT; } int CrushWrapper::adjust_item_weight(CephContext *cct, int id, int weight) { ldout(cct, 5) << "adjust_item_weight " << id << " weight " << weight << dendl; int changed = 0; for (int bidx = 0; bidx < crush->max_buckets; bidx++) { crush_bucket *b = crush->buckets[bidx]; if (b == 0) continue; for (unsigned i = 0; i < b->size; i++) { if (b->items[i] == id) { int diff = crush_bucket_adjust_item_weight(crush, b, id, weight); ldout(cct, 5) << "adjust_item_weight " << id << " diff " << diff << " in bucket " << bidx << dendl; adjust_item_weight(cct, -1 - bidx, b->weight); changed++; } } } if (!changed) return -ENOENT; return changed; } int CrushWrapper::adjust_item_weight_in_loc(CephContext *cct, int id, int weight, const map& loc) { ldout(cct, 5) << "adjust_item_weight_in_loc " << id << " weight " << weight << " in " << loc << dendl; int changed = 0; for (map::const_iterator l = loc.begin(); l != loc.end(); l++) { int bid = get_item_id(l->second); if (!bucket_exists(bid)) continue; crush_bucket *b = get_bucket(bid); if ( b == NULL) continue; for (unsigned int i = 0; i < b->size; i++) { if (b->items[i] == id) { int diff = crush_bucket_adjust_item_weight(crush, b, id, weight); ldout(cct, 5) << "adjust_item_weight_in_loc " << id << " diff " << diff << " in bucket " << bid << dendl; adjust_item_weight(cct, bid, b->weight); changed++; } } } if (!changed) return -ENOENT; return changed; } bool CrushWrapper::check_item_present(int id) const { bool found = false; for (int bidx = 0; bidx < crush->max_buckets; bidx++) { crush_bucket *b = crush->buckets[bidx]; if (b == 0) continue; for (unsigned i = 0; i < b->size; i++) if (b->items[i] == id) found = true; } return found; } pair CrushWrapper::get_immediate_parent(int id, int *_ret) { pair loc; int ret = -ENOENT; for (int bidx = 0; bidx < crush->max_buckets; bidx++) { crush_bucket *b = crush->buckets[bidx]; if (b == 0) continue; for (unsigned i = 0; i < b->size; i++) if (b->items[i] == id) { string parent_id = name_map[b->id]; string parent_bucket_type = type_map[b->type]; loc = make_pair(parent_bucket_type, parent_id); ret = 0; } } if (_ret) *_ret = ret; return loc; } int CrushWrapper::get_immediate_parent_id(int id, int *parent) { for (int bidx = 0; bidx < crush->max_buckets; bidx++) { crush_bucket *b = crush->buckets[bidx]; if (b == 0) continue; for (unsigned i = 0; i < b->size; i++) { if (b->items[i] == id) { *parent = b->id; return 0; } } } return -ENOENT; } void CrushWrapper::reweight(CephContext *cct) { set roots; find_roots(roots); for (set::iterator p = roots.begin(); p != roots.end(); ++p) { if (*p >= 0) continue; crush_bucket *b = get_bucket(*p); ldout(cct, 5) << "reweight bucket " << *p << dendl; int r = crush_reweight_bucket(crush, b); assert(r == 0); } } int CrushWrapper::add_simple_ruleset(string name, string root_name, string failure_domain_name, string mode, int rule_type, ostream *err) { if (rule_exists(name)) { if (err) *err << "rule " << name << " exists"; return -EEXIST; } if (!name_exists(root_name)) { if (err) *err << "root item " << root_name << " does not exist"; return -ENOENT; } int root = get_item_id(root_name); int type = 0; if (failure_domain_name.length()) { type = get_type_id(failure_domain_name); if (type < 0) { if (err) *err << "unknown type " << failure_domain_name; return -EINVAL; } } if (mode != "firstn" && mode != "indep") { if (err) *err << "unknown mode " << mode; return -EINVAL; } int rno = -1; for (rno = 0; rno < get_max_rules(); rno++) { if (!rule_exists(rno) && !ruleset_exists(rno)) break; } int steps = 3; if (mode == "indep") steps = 5; int min_rep = mode == "firstn" ? 1 : 3; int max_rep = mode == "firstn" ? 10 : 20; //set the ruleset the same as rule_id(rno) crush_rule *rule = crush_make_rule(steps, rno, rule_type, min_rep, max_rep); assert(rule); int step = 0; if (mode == "indep") { crush_rule_set_step(rule, step++, CRUSH_RULE_SET_CHOOSELEAF_TRIES, 5, 0); crush_rule_set_step(rule, step++, CRUSH_RULE_SET_CHOOSE_TRIES, 100, 0); } crush_rule_set_step(rule, step++, CRUSH_RULE_TAKE, root, 0); if (type) crush_rule_set_step(rule, step++, mode == "firstn" ? CRUSH_RULE_CHOOSELEAF_FIRSTN : CRUSH_RULE_CHOOSELEAF_INDEP, CRUSH_CHOOSE_N, type); else crush_rule_set_step(rule, step++, mode == "firstn" ? CRUSH_RULE_CHOOSE_FIRSTN : CRUSH_RULE_CHOOSE_INDEP, CRUSH_CHOOSE_N, 0); crush_rule_set_step(rule, step++, CRUSH_RULE_EMIT, 0, 0); int ret = crush_add_rule(crush, rule, rno); if(ret < 0) { *err << "failed to add rule " << rno << " because " << cpp_strerror(ret); return ret; } set_rule_name(rno, name); have_rmaps = false; return rno; } int CrushWrapper::get_rule_weight_osd_map(unsigned ruleno, map *pmap) { if (ruleno >= crush->max_rules) return -ENOENT; if (crush->rules[ruleno] == NULL) return -ENOENT; crush_rule *rule = crush->rules[ruleno]; // build a weight map for each TAKE in the rule, and then merge them for (unsigned i=0; ilen; ++i) { map m; float sum = 0; if (rule->steps[i].op == CRUSH_RULE_TAKE) { int n = rule->steps[i].arg1; if (n >= 0) { m[n] = 1.0; sum = 1.0; } else { list q; q.push_back(n); //breadth first iterate the OSD tree while (!q.empty()) { int bno = q.front(); q.pop_front(); crush_bucket *b = crush->buckets[-1-bno]; assert(b); for (unsigned j=0; jsize; ++j) { int item_id = b->items[j]; if (item_id >= 0) //it's an OSD { float w = crush_get_bucket_item_weight(b, j); m[item_id] = w; sum += w; } else //not an OSD, expand the child later q.push_back(item_id); } } } } for (map::iterator p = m.begin(); p != m.end(); ++p) { map::iterator q = pmap->find(p->first); if (q == pmap->end()) { (*pmap)[p->first] = p->second / sum; } else { q->second += p->second / sum; } } } return 0; } int CrushWrapper::remove_rule(int ruleno) { if (ruleno >= (int)crush->max_rules) return -ENOENT; if (crush->rules[ruleno] == NULL) return -ENOENT; crush_destroy_rule(crush->rules[ruleno]); crush->rules[ruleno] = NULL; rule_name_map.erase(ruleno); have_rmaps = false; return 0; } void CrushWrapper::encode(bufferlist& bl, bool lean) const { assert(crush); __u32 magic = CRUSH_MAGIC; ::encode(magic, bl); ::encode(crush->max_buckets, bl); ::encode(crush->max_rules, bl); ::encode(crush->max_devices, bl); // buckets for (int i=0; imax_buckets; i++) { __u32 alg = 0; if (crush->buckets[i]) alg = crush->buckets[i]->alg; ::encode(alg, bl); if (!alg) continue; ::encode(crush->buckets[i]->id, bl); ::encode(crush->buckets[i]->type, bl); ::encode(crush->buckets[i]->alg, bl); ::encode(crush->buckets[i]->hash, bl); ::encode(crush->buckets[i]->weight, bl); ::encode(crush->buckets[i]->size, bl); for (unsigned j=0; jbuckets[i]->size; j++) ::encode(crush->buckets[i]->items[j], bl); switch (crush->buckets[i]->alg) { case CRUSH_BUCKET_UNIFORM: ::encode(((crush_bucket_uniform*)crush->buckets[i])->item_weight, bl); break; case CRUSH_BUCKET_LIST: for (unsigned j=0; jbuckets[i]->size; j++) { ::encode(((crush_bucket_list*)crush->buckets[i])->item_weights[j], bl); ::encode(((crush_bucket_list*)crush->buckets[i])->sum_weights[j], bl); } break; case CRUSH_BUCKET_TREE: ::encode(((crush_bucket_tree*)crush->buckets[i])->num_nodes, bl); for (unsigned j=0; j<((crush_bucket_tree*)crush->buckets[i])->num_nodes; j++) ::encode(((crush_bucket_tree*)crush->buckets[i])->node_weights[j], bl); break; case CRUSH_BUCKET_STRAW: for (unsigned j=0; jbuckets[i]->size; j++) { ::encode(((crush_bucket_straw*)crush->buckets[i])->item_weights[j], bl); ::encode(((crush_bucket_straw*)crush->buckets[i])->straws[j], bl); } break; default: assert(0); break; } } // rules for (unsigned i=0; imax_rules; i++) { __u32 yes = crush->rules[i] ? 1:0; ::encode(yes, bl); if (!yes) continue; ::encode(crush->rules[i]->len, bl); ::encode(crush->rules[i]->mask, bl); for (unsigned j=0; jrules[i]->len; j++) ::encode(crush->rules[i]->steps[j], bl); } // name info ::encode(type_map, bl); ::encode(name_map, bl); ::encode(rule_name_map, bl); // tunables ::encode(crush->choose_local_tries, bl); ::encode(crush->choose_local_fallback_tries, bl); ::encode(crush->choose_total_tries, bl); ::encode(crush->chooseleaf_descend_once, bl); ::encode(crush->chooseleaf_vary_r, bl); ::encode(crush->straw_calc_version, bl); } static void decode_32_or_64_string_map(map& m, bufferlist::iterator& blp) { m.clear(); __u32 n; ::decode(n, blp); while (n--) { __s32 key; ::decode(key, blp); __u32 strlen; ::decode(strlen, blp); if (strlen == 0) { // der, key was actually 64-bits! ::decode(strlen, blp); } ::decode_nohead(strlen, m[key], blp); } } void CrushWrapper::decode(bufferlist::iterator& blp) { create(); __u32 magic; ::decode(magic, blp); if (magic != CRUSH_MAGIC) throw buffer::malformed_input("bad magic number"); ::decode(crush->max_buckets, blp); ::decode(crush->max_rules, blp); ::decode(crush->max_devices, blp); // legacy tunables, unless we decode something newer set_tunables_legacy(); try { // buckets crush->buckets = (crush_bucket**)calloc(1, crush->max_buckets * sizeof(crush_bucket*)); for (int i=0; imax_buckets; i++) { decode_crush_bucket(&crush->buckets[i], blp); } // rules crush->rules = (crush_rule**)calloc(1, crush->max_rules * sizeof(crush_rule*)); for (unsigned i = 0; i < crush->max_rules; ++i) { __u32 yes; ::decode(yes, blp); if (!yes) { crush->rules[i] = NULL; continue; } __u32 len; ::decode(len, blp); crush->rules[i] = (crush_rule*)calloc(1, crush_rule_size(len)); crush->rules[i]->len = len; ::decode(crush->rules[i]->mask, blp); for (unsigned j=0; jrules[i]->len; j++) ::decode(crush->rules[i]->steps[j], blp); } // name info // NOTE: we had a bug where we were incoding int instead of int32, which means the // 'key' field for these maps may be either 32 or 64 bits, depending. tolerate // both by assuming the string is always non-empty. decode_32_or_64_string_map(type_map, blp); decode_32_or_64_string_map(name_map, blp); decode_32_or_64_string_map(rule_name_map, blp); // tunables if (!blp.end()) { ::decode(crush->choose_local_tries, blp); ::decode(crush->choose_local_fallback_tries, blp); ::decode(crush->choose_total_tries, blp); } if (!blp.end()) { ::decode(crush->chooseleaf_descend_once, blp); } if (!blp.end()) { ::decode(crush->chooseleaf_vary_r, blp); } if (!blp.end()) { ::decode(crush->straw_calc_version, blp); } finalize(); } catch (...) { crush_destroy(crush); throw; } } void CrushWrapper::decode_crush_bucket(crush_bucket** bptr, bufferlist::iterator &blp) { __u32 alg; ::decode(alg, blp); if (!alg) { *bptr = NULL; return; } int size = 0; switch (alg) { case CRUSH_BUCKET_UNIFORM: size = sizeof(crush_bucket_uniform); break; case CRUSH_BUCKET_LIST: size = sizeof(crush_bucket_list); break; case CRUSH_BUCKET_TREE: size = sizeof(crush_bucket_tree); break; case CRUSH_BUCKET_STRAW: size = sizeof(crush_bucket_straw); break; default: { char str[128]; snprintf(str, sizeof(str), "unsupported bucket algorithm: %d", alg); throw buffer::malformed_input(str); } } crush_bucket *bucket = (crush_bucket*)calloc(1, size); *bptr = bucket; ::decode(bucket->id, blp); ::decode(bucket->type, blp); ::decode(bucket->alg, blp); ::decode(bucket->hash, blp); ::decode(bucket->weight, blp); ::decode(bucket->size, blp); bucket->items = (__s32*)calloc(1, bucket->size * sizeof(__s32)); for (unsigned j = 0; j < bucket->size; ++j) { ::decode(bucket->items[j], blp); } bucket->perm = (__u32*)calloc(1, bucket->size * sizeof(__s32)); bucket->perm_n = 0; switch (bucket->alg) { case CRUSH_BUCKET_UNIFORM: ::decode(((crush_bucket_uniform*)bucket)->item_weight, blp); break; case CRUSH_BUCKET_LIST: { crush_bucket_list* cbl = (crush_bucket_list*)bucket; cbl->item_weights = (__u32*)calloc(1, bucket->size * sizeof(__u32)); cbl->sum_weights = (__u32*)calloc(1, bucket->size * sizeof(__u32)); for (unsigned j = 0; j < bucket->size; ++j) { ::decode(cbl->item_weights[j], blp); ::decode(cbl->sum_weights[j], blp); } break; } case CRUSH_BUCKET_TREE: { crush_bucket_tree* cbt = (crush_bucket_tree*)bucket; ::decode(cbt->num_nodes, blp); cbt->node_weights = (__u32*)calloc(1, cbt->num_nodes * sizeof(__u32)); for (unsigned j=0; jnum_nodes; j++) { ::decode(cbt->node_weights[j], blp); } break; } case CRUSH_BUCKET_STRAW: { crush_bucket_straw* cbs = (crush_bucket_straw*)bucket; cbs->straws = (__u32*)calloc(1, bucket->size * sizeof(__u32)); cbs->item_weights = (__u32*)calloc(1, bucket->size * sizeof(__u32)); for (unsigned j = 0; j < bucket->size; ++j) { ::decode(cbs->item_weights[j], blp); ::decode(cbs->straws[j], blp); } break; } default: // We should have handled this case in the first switch statement assert(0); break; } } void CrushWrapper::dump(Formatter *f) const { f->open_array_section("devices"); for (int i=0; iopen_object_section("device"); f->dump_int("id", i); const char *n = get_item_name(i); if (n) { f->dump_string("name", n); } else { char name[20]; sprintf(name, "device%d", i); f->dump_string("name", name); } f->close_section(); } f->close_section(); f->open_array_section("types"); int n = get_num_type_names(); for (int i=0; n; i++) { const char *name = get_type_name(i); if (!name) { if (i == 0) { f->open_object_section("type"); f->dump_int("type_id", 0); f->dump_string("name", "device"); f->close_section(); } continue; } n--; f->open_object_section("type"); f->dump_int("type_id", i); f->dump_string("name", name); f->close_section(); } f->close_section(); f->open_array_section("buckets"); for (int bucket = -1; bucket > -1-get_max_buckets(); --bucket) { if (!bucket_exists(bucket)) continue; f->open_object_section("bucket"); f->dump_int("id", bucket); if (get_item_name(bucket)) f->dump_string("name", get_item_name(bucket)); f->dump_int("type_id", get_bucket_type(bucket)); if (get_type_name(get_bucket_type(bucket))) f->dump_string("type_name", get_type_name(get_bucket_type(bucket))); f->dump_int("weight", get_bucket_weight(bucket)); f->dump_string("alg", crush_bucket_alg_name(get_bucket_alg(bucket))); f->dump_string("hash", crush_hash_name(get_bucket_hash(bucket))); f->open_array_section("items"); for (int j=0; jopen_object_section("item"); f->dump_int("id", get_bucket_item(bucket, j)); f->dump_int("weight", get_bucket_item_weight(bucket, j)); f->dump_int("pos", j); f->close_section(); } f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("rules"); dump_rules(f); f->close_section(); f->open_object_section("tunables"); dump_tunables(f); f->close_section(); } void CrushWrapper::dump_tunables(Formatter *f) const { f->dump_int("choose_local_tries", get_choose_local_tries()); f->dump_int("choose_local_fallback_tries", get_choose_local_fallback_tries()); f->dump_int("choose_total_tries", get_choose_total_tries()); f->dump_int("chooseleaf_descend_once", get_chooseleaf_descend_once()); f->dump_int("chooseleaf_vary_r", get_chooseleaf_vary_r()); f->dump_int("straw_calc_version", get_straw_calc_version()); // be helpful about it if (has_firefly_tunables()) f->dump_string("profile", "firefly"); else if (has_bobtail_tunables()) f->dump_string("profile", "bobtail"); else if (has_argonaut_tunables()) f->dump_string("profile", "argonaut"); else f->dump_string("profile", "unknown"); f->dump_int("optimal_tunables", (int)has_optimal_tunables()); f->dump_int("legacy_tunables", (int)has_legacy_tunables()); f->dump_int("require_feature_tunables", (int)has_nondefault_tunables()); f->dump_int("require_feature_tunables2", (int)has_nondefault_tunables2()); f->dump_int("require_feature_tunables3", (int)has_nondefault_tunables3()); f->dump_int("has_v2_rules", (int)has_v2_rules()); f->dump_int("has_v3_rules", (int)has_v3_rules()); } void CrushWrapper::dump_rules(Formatter *f) const { for (int i=0; iopen_object_section("rule"); f->dump_int("rule_id", ruleset); if (get_rule_name(ruleset)) f->dump_string("rule_name", get_rule_name(ruleset)); f->dump_int("ruleset", get_rule_mask_ruleset(ruleset)); f->dump_int("type", get_rule_mask_type(ruleset)); f->dump_int("min_size", get_rule_mask_min_size(ruleset)); f->dump_int("max_size", get_rule_mask_max_size(ruleset)); f->open_array_section("steps"); for (int j=0; jopen_object_section("step"); switch (get_rule_op(ruleset, j)) { case CRUSH_RULE_NOOP: f->dump_string("op", "noop"); break; case CRUSH_RULE_TAKE: f->dump_string("op", "take"); { int item = get_rule_arg1(ruleset, j); f->dump_int("item", item); const char *name = get_item_name(item); f->dump_string("item_name", name ? name : ""); } break; case CRUSH_RULE_EMIT: f->dump_string("op", "emit"); break; case CRUSH_RULE_CHOOSE_FIRSTN: f->dump_string("op", "choose_firstn"); f->dump_int("num", get_rule_arg1(ruleset, j)); f->dump_string("type", get_type_name(get_rule_arg2(ruleset, j))); break; case CRUSH_RULE_CHOOSE_INDEP: f->dump_string("op", "choose_indep"); f->dump_int("num", get_rule_arg1(ruleset, j)); f->dump_string("type", get_type_name(get_rule_arg2(ruleset, j))); break; case CRUSH_RULE_CHOOSELEAF_FIRSTN: f->dump_string("op", "chooseleaf_firstn"); f->dump_int("num", get_rule_arg1(ruleset, j)); f->dump_string("type", get_type_name(get_rule_arg2(ruleset, j))); break; case CRUSH_RULE_CHOOSELEAF_INDEP: f->dump_string("op", "chooseleaf_indep"); f->dump_int("num", get_rule_arg1(ruleset, j)); f->dump_string("type", get_type_name(get_rule_arg2(ruleset, j))); break; case CRUSH_RULE_SET_CHOOSE_TRIES: f->dump_string("op", "set_choose_tries"); f->dump_int("num", get_rule_arg1(ruleset, j)); break; case CRUSH_RULE_SET_CHOOSELEAF_TRIES: f->dump_string("op", "set_chooseleaf_tries"); f->dump_int("num", get_rule_arg1(ruleset, j)); break; default: f->dump_int("opcode", get_rule_op(ruleset, j)); f->dump_int("arg1", get_rule_arg1(ruleset, j)); f->dump_int("arg2", get_rule_arg2(ruleset, j)); } f->close_section(); } f->close_section(); f->close_section(); } void CrushWrapper::list_rules(Formatter *f) const { for (int rule = 0; rule < get_max_rules(); rule++) { if (!rule_exists(rule)) continue; f->dump_string("name", get_rule_name(rule)); } } struct qi { int item; int depth; float weight; qi() : item(0), depth(0), weight(0) {} qi(int i, int d, float w) : item(i), depth(d), weight(w) {} }; void CrushWrapper::dump_tree(const vector<__u32>& w, ostream *out, Formatter *f) const { if (out) *out << "# id\tweight\ttype name\treweight\n"; if (f) f->open_array_section("nodes"); set touched; set roots; find_roots(roots); for (set::iterator p = roots.begin(); p != roots.end(); ++p) { list q; q.push_back(qi(*p, 0, get_bucket_weight(*p) / (float)0x10000)); while (!q.empty()) { int cur = q.front().item; int depth = q.front().depth; float weight = q.front().weight; q.pop_front(); if (out) { *out << cur << "\t"; int oldprecision = out->precision(); *out << std::setprecision(4) << weight << std::setprecision(oldprecision) << "\t"; for (int k=0; kopen_object_section("item"); } if (cur >= 0) { if (f) { f->dump_unsigned("id", cur); f->dump_stream("name") << "osd." << cur; f->dump_string("type", get_type_name(0)); f->dump_int("type_id", 0); } if (out) *out << "osd." << cur << "\t"; double wf = (double)w[cur] / (double)0x10000; if (out) { std::streamsize p = out->precision(); *out << std::setprecision(4) << wf << std::setprecision(p) << "\t"; } if (f) { f->dump_float("reweight", wf); } if (out) *out << "\n"; if (f) { f->dump_float("crush_weight", weight); f->dump_unsigned("depth", depth); f->close_section(); } touched.insert(cur); } if (cur >= 0) { continue; } // queue bucket contents... int type = get_bucket_type(cur); int s = get_bucket_size(cur); if (f) { f->dump_int("id", cur); f->dump_string("name", get_item_name(cur)); f->dump_string("type", get_type_name(type)); f->dump_int("type_id", type); f->open_array_section("children"); } for (int k=s-1; k>=0; k--) { int item = get_bucket_item(cur, k); q.push_front(qi(item, depth+1, (float)get_bucket_item_weight(cur, k) / (float)0x10000)); if (f) f->dump_int("child", item); } if (f) f->close_section(); if (out) *out << get_type_name(type) << " " << get_item_name(cur) << "\n"; if (f) { f->close_section(); } } } if (f) { f->close_section(); f->open_array_section("stray"); } if (f) f->close_section(); } void CrushWrapper::generate_test_instances(list& o) { o.push_back(new CrushWrapper); // fixme } /** * Determine the default CRUSH ruleset ID to be used with * newly created replicated pools. * * @returns a ruleset ID (>=0) or an error (<0) */ int CrushWrapper::get_osd_pool_default_crush_replicated_ruleset(CephContext *cct) { int crush_ruleset = cct->_conf->osd_pool_default_crush_replicated_ruleset; if (cct->_conf->osd_pool_default_crush_rule != -1) { ldout(cct, 0) << "osd_pool_default_crush_rule is deprecated " << "use osd_pool_default_crush_replicated_ruleset instead" << dendl; ldout(cct, 0) << "osd_pool_default_crush_rule = " << cct->_conf-> osd_pool_default_crush_rule << " overrides " << "osd_pool_default_crush_replicated_ruleset = " << cct->_conf->osd_pool_default_crush_replicated_ruleset << dendl; crush_ruleset = cct->_conf->osd_pool_default_crush_rule; } if (crush_ruleset == CEPH_DEFAULT_CRUSH_REPLICATED_RULESET) { crush_ruleset = find_first_ruleset(pg_pool_t::TYPE_REPLICATED); } return crush_ruleset; } bool CrushWrapper::is_valid_crush_name(const string& s) { if (s.empty()) return false; for (string::const_iterator p = s.begin(); p != s.end(); ++p) { if (!(*p == '-') && !(*p == '_') && !(*p == '.') && !(*p >= '0' && *p <= '9') && !(*p >= 'A' && *p <= 'Z') && !(*p >= 'a' && *p <= 'z')) return false; } return true; } bool CrushWrapper::is_valid_crush_loc(CephContext *cct, const map& loc) { for (map::const_iterator l = loc.begin(); l != loc.end(); ++l) { if (!is_valid_crush_name(l->first) || !is_valid_crush_name(l->second)) { ldout(cct, 1) << "loc[" << l->first << "] = '" << l->second << "' not a valid crush name ([A-Za-z0-9_-.]+)" << dendl; return false; } } return true; } ceph-0.80.11/src/crush/hash.c0000664000175100017510000000632112623076744017701 0ustar jenkins-buildjenkins-build#include "include/int_types.h" #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif #include "hash.h" /* * Robert Jenkins' function for mixing 32-bit values * http://burtleburtle.net/bob/hash/evahash.html * a, b = random bits, c = input and output */ #define crush_hashmix(a, b, c) do { \ a = a-b; a = a-c; a = a^(c>>13); \ b = b-c; b = b-a; b = b^(a<<8); \ c = c-a; c = c-b; c = c^(b>>13); \ a = a-b; a = a-c; a = a^(c>>12); \ b = b-c; b = b-a; b = b^(a<<16); \ c = c-a; c = c-b; c = c^(b>>5); \ a = a-b; a = a-c; a = a^(c>>3); \ b = b-c; b = b-a; b = b^(a<<10); \ c = c-a; c = c-b; c = c^(b>>15); \ } while (0) #define crush_hash_seed 1315423911 static __u32 crush_hash32_rjenkins1(__u32 a) { __u32 hash = crush_hash_seed ^ a; __u32 b = a; __u32 x = 231232; __u32 y = 1232; crush_hashmix(b, x, hash); crush_hashmix(y, a, hash); return hash; } static __u32 crush_hash32_rjenkins1_2(__u32 a, __u32 b) { __u32 hash = crush_hash_seed ^ a ^ b; __u32 x = 231232; __u32 y = 1232; crush_hashmix(a, b, hash); crush_hashmix(x, a, hash); crush_hashmix(b, y, hash); return hash; } static __u32 crush_hash32_rjenkins1_3(__u32 a, __u32 b, __u32 c) { __u32 hash = crush_hash_seed ^ a ^ b ^ c; __u32 x = 231232; __u32 y = 1232; crush_hashmix(a, b, hash); crush_hashmix(c, x, hash); crush_hashmix(y, a, hash); crush_hashmix(b, x, hash); crush_hashmix(y, c, hash); return hash; } static __u32 crush_hash32_rjenkins1_4(__u32 a, __u32 b, __u32 c, __u32 d) { __u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d; __u32 x = 231232; __u32 y = 1232; crush_hashmix(a, b, hash); crush_hashmix(c, d, hash); crush_hashmix(a, x, hash); crush_hashmix(y, b, hash); crush_hashmix(c, x, hash); crush_hashmix(y, d, hash); return hash; } static __u32 crush_hash32_rjenkins1_5(__u32 a, __u32 b, __u32 c, __u32 d, __u32 e) { __u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e; __u32 x = 231232; __u32 y = 1232; crush_hashmix(a, b, hash); crush_hashmix(c, d, hash); crush_hashmix(e, x, hash); crush_hashmix(y, a, hash); crush_hashmix(b, x, hash); crush_hashmix(y, c, hash); crush_hashmix(d, x, hash); crush_hashmix(y, e, hash); return hash; } __u32 crush_hash32(int type, __u32 a) { switch (type) { case CRUSH_HASH_RJENKINS1: return crush_hash32_rjenkins1(a); default: return 0; } } __u32 crush_hash32_2(int type, __u32 a, __u32 b) { switch (type) { case CRUSH_HASH_RJENKINS1: return crush_hash32_rjenkins1_2(a, b); default: return 0; } } __u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c) { switch (type) { case CRUSH_HASH_RJENKINS1: return crush_hash32_rjenkins1_3(a, b, c); default: return 0; } } __u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d) { switch (type) { case CRUSH_HASH_RJENKINS1: return crush_hash32_rjenkins1_4(a, b, c, d); default: return 0; } } __u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d, __u32 e) { switch (type) { case CRUSH_HASH_RJENKINS1: return crush_hash32_rjenkins1_5(a, b, c, d, e); default: return 0; } } const char *crush_hash_name(int type) { switch (type) { case CRUSH_HASH_RJENKINS1: return "rjenkins1"; default: return "unknown"; } } ceph-0.80.11/src/crush/grammar.h0000664000175100017510000001370512623076744020415 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2008 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CRUSH_GRAMMAR_H #define CEPH_CRUSH_GRAMMAR_H //#define BOOST_SPIRIT_DEBUG #ifdef USE_BOOST_SPIRIT_OLD_HDR #include #include #include #else #define BOOST_SPIRIT_USE_OLD_NAMESPACE #include #include #include #endif using namespace boost::spirit; struct crush_grammar : public grammar { enum { _int = 1, _posint, _negint, _name, _device, _bucket_type, _bucket_id, _bucket_alg, _bucket_hash, _bucket_item, _bucket, _step_take, _step_set_chooseleaf_tries, _step_set_chooseleaf_vary_r, _step_set_choose_tries, _step_set_choose_local_tries, _step_set_choose_local_fallback_tries, _step_choose, _step_chooseleaf, _step_emit, _step, _crushrule, _crushmap, _tunable, }; template struct definition { rule, parser_tag<_int> > integer; rule, parser_tag<_posint> > posint; rule, parser_tag<_negint> > negint; rule, parser_tag<_name> > name; rule, parser_tag<_tunable> > tunable; rule, parser_tag<_device> > device; rule, parser_tag<_bucket_type> > bucket_type; rule, parser_tag<_bucket_id> > bucket_id; rule, parser_tag<_bucket_alg> > bucket_alg; rule, parser_tag<_bucket_hash> > bucket_hash; rule, parser_tag<_bucket_item> > bucket_item; rule, parser_tag<_bucket> > bucket; rule, parser_tag<_step_take> > step_take; rule, parser_tag<_step_set_choose_tries> > step_set_choose_tries; rule, parser_tag<_step_set_choose_local_tries> > step_set_choose_local_tries; rule, parser_tag<_step_set_choose_local_fallback_tries> > step_set_choose_local_fallback_tries; rule, parser_tag<_step_set_chooseleaf_tries> > step_set_chooseleaf_tries; rule, parser_tag<_step_set_chooseleaf_vary_r> > step_set_chooseleaf_vary_r; rule, parser_tag<_step_choose> > step_choose; rule, parser_tag<_step_chooseleaf> > step_chooseleaf; rule, parser_tag<_step_emit> > step_emit; rule, parser_tag<_step> > step; rule, parser_tag<_crushrule> > crushrule; rule, parser_tag<_crushmap> > crushmap; definition(crush_grammar const& /*self*/) { // base types integer = leaf_node_d[ lexeme_d[ (!ch_p('-') >> +digit_p) ] ]; posint = leaf_node_d[ lexeme_d[ +digit_p ] ]; negint = leaf_node_d[ lexeme_d[ ch_p('-') >> +digit_p ] ]; name = leaf_node_d[ lexeme_d[ +( alnum_p || ch_p('-') || ch_p('_') || ch_p('.')) ] ]; // tunables tunable = str_p("tunable") >> name >> posint; // devices device = str_p("device") >> posint >> name; // bucket types bucket_type = str_p("type") >> posint >> name; // buckets bucket_id = str_p("id") >> negint; bucket_alg = str_p("alg") >> ( str_p("uniform") | str_p("list") | str_p("tree") | str_p("straw") ); bucket_hash = str_p("hash") >> ( integer | str_p("rjenkins1") ); bucket_item = str_p("item") >> name >> !( str_p("weight") >> real_p ) >> !( str_p("pos") >> posint ); bucket = name >> name >> '{' >> !bucket_id >> bucket_alg >> *bucket_hash >> *bucket_item >> '}'; // rules step_take = str_p("take") >> name; step_set_choose_tries = str_p("set_choose_tries") >> posint; step_set_choose_local_tries = str_p("set_choose_local_tries") >> posint; step_set_choose_local_fallback_tries = str_p("set_choose_local_fallback_tries") >> posint; step_set_chooseleaf_tries = str_p("set_chooseleaf_tries") >> posint; step_set_chooseleaf_vary_r = str_p("set_chooseleaf_vary_r") >> posint; step_choose = str_p("choose") >> ( str_p("indep") | str_p("firstn") ) >> integer >> str_p("type") >> name; step_chooseleaf = str_p("chooseleaf") >> ( str_p("indep") | str_p("firstn") ) >> integer >> str_p("type") >> name; step_emit = str_p("emit"); step = str_p("step") >> ( step_take | step_set_choose_tries | step_set_choose_local_tries | step_set_choose_local_fallback_tries | step_set_chooseleaf_tries | step_set_chooseleaf_vary_r | step_choose | step_chooseleaf | step_emit ); crushrule = str_p("rule") >> !name >> '{' >> str_p("ruleset") >> posint >> str_p("type") >> ( str_p("replicated") | str_p("erasure") ) >> str_p("min_size") >> posint >> str_p("max_size") >> posint >> +step >> '}'; // the whole crush map crushmap = *(tunable | device | bucket_type) >> *(bucket | crushrule); } rule, parser_tag<_crushmap> > const& start() const { return crushmap; } }; }; #endif ceph-0.80.11/src/mount.fuse.ceph0000775000175100017510000000203112623076744020427 0ustar jenkins-buildjenkins-build#!/bin/sh # # Helper to mount ceph-fuse from /etc/fstab. To use, add an entry # like: # # # DEVICE PATH TYPE OPTIONS # id=admin /mnt/ceph fuse.ceph defaults 0 0 # id=myuser,conf=/etc/ceph/foo.conf /mnt/ceph2 fuse.ceph defaults 0 0 # # where the device field is a comma-separated list of options to pass on # the command line. The examples above, for example, specify that # ceph-fuse will authenticated as client.admin and client.myuser # (respectively), and the second example also sets the 'conf' option to # '/etc/ceph/foo.conf' via the ceph-fuse command line. Any valid # ceph-fuse can be passed in this way. set -e # convert device string to options cephargs='--'`echo $1 | sed 's/,/ --/g'` # strip out 'noauto' option; libfuse doesn't like it opts=`echo $4 | sed 's/,noauto//' | sed 's/noauto,//'` # strip out '_netdev' option; libfuse doesn't like it opts=`echo $opts | sed 's/,_netdev//' | sed 's/_netdev,//'` # go exec ceph-fuse $cephargs $2 $3 $opts ceph-0.80.11/src/init-radosgw.sysv0000664000175100017510000000654612623076744021034 0ustar jenkins-buildjenkins-build#! /bin/bash ### BEGIN INIT INFO # Provides: radosgw # Required-Start: $remote_fs $named $network $time # Required-Stop: $remote_fs $named $network $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: radosgw RESTful rados gateway ### END INIT INFO PATH=/sbin:/bin:/usr/bin #. /lib/lsb/init-functions . /etc/rc.d/init.d/functions daemon_is_running() { daemon=$1 sleep 1 if pidof $daemon >/dev/null; then echo "$daemon is running." exit 0 else echo "$daemon is not running." exit 1 fi } VERBOSE=0 for opt in $*; do if [ "$opt" = "-v" ] || [ "$opt" = "--verbose" ]; then VERBOSE=1 fi done # prefix for radosgw instances in ceph.conf PREFIX='client.radosgw.' # user to run radosgw as (it not specified in ceph.conf) #DEFAULT_USER='www-data' DEFAULT_USER='root' RADOSGW=`which radosgw` if [ ! -x "$RADOSGW" ]; then [ $VERBOSE -eq 1 ] && echo "$RADOSGW could not start, it is not executable." exit 1 fi # detect systemd SYSTEMD=0 grep -qs systemd /proc/1/comm && SYSTEMD=1 case "$1" in start) echo "Starting radosgw instance(s)..." for name in `ceph-conf --list-sections $PREFIX`; do auto_start=`ceph-conf -n $name 'auto start'` if [ "$auto_start" = "no" ] || [ "$auto_start" = "false" ] || [ "$auto_start" = "0" ]; then continue fi # mapped to this host? host=`ceph-conf -n $name host` hostname=`hostname -s` if [ "$host" != "$hostname" ]; then [ $VERBOSE -eq 1 ] && echo "hostname $hostname could not be found in ceph.conf:[$name], not starting." continue fi user=`ceph-conf -n $name user` if [ -z "$user" ]; then user="$DEFAULT_USER" fi log_file=`$RADOSGW -n $name --show-config-value log_file` if [ -n "$log_file" ]; then if [ ! -e "$log_file" ]; then touch "$log_file" fi chown $user $log_file fi if [ $SYSTEMD -eq 1 ]; then systemd-run -r sudo -u "$user" bash -c "ulimit -n 32768; $RADOSGW -n $name" else ulimit -n 32768 daemon --user="$user" "$RADOSGW -n $name" fi echo "Starting $name..." done daemon_is_running $RADOSGW ;; reload) #start-stop-daemon --signal HUP -x $RADOSGW --oknodo killproc $RADOSGW -SIGHUP echo "Reloading radosgw instance(s)..." ;; restart|force-reload) $0 stop $0 start ;; stop) #start-stop-daemon --stop -x $RADOSGW --oknodo timeout=0 for name in `ceph-conf --list-sections $PREFIX`; do t=`$RADOSGW -n $name --show-config-value rgw_exit_timeout_secs` if [ $t -gt $timeout ]; then timeout=$t; fi done killproc $RADOSGW echo "Stopping radosgw instance(s)..." while pidof $RADOSGW >/dev/null && [ $timeout -gt 0 ] ; do sleep 1 timeout=$(($timeout - 1)) done ;; status) daemon_is_running $RADOSGW ;; *) echo "Usage: $0 {start|stop|restart|force-reload|reload|status} [-v|--verbose]" >&2 exit 3 ;; esac ceph-0.80.11/src/java/0000775000175100017510000000000012623077037016401 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/native/0000775000175100017510000000000012623077035017665 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/native/JniConstants.cpp0000664000175100017510000000272312623076744023020 0ustar jenkins-buildjenkins-build/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "JniConstants.h" #include "ScopedLocalRef.h" #include jclass JniConstants::inet6AddressClass; jclass JniConstants::inetAddressClass; jclass JniConstants::inetSocketAddressClass; jclass JniConstants::stringClass; static jclass findClass(JNIEnv* env, const char* name) { ScopedLocalRef localClass(env, env->FindClass(name)); jclass result = reinterpret_cast(env->NewGlobalRef(localClass.get())); if (result == NULL) { fprintf(stderr, "failed to find class '%s'", name); abort(); } return result; } void JniConstants::init(JNIEnv* env) { inet6AddressClass = findClass(env, "java/net/Inet6Address"); inetAddressClass = findClass(env, "java/net/InetAddress"); inetSocketAddressClass = findClass(env, "java/net/InetSocketAddress"); stringClass = findClass(env, "java/lang/String"); } ceph-0.80.11/src/java/native/ScopedLocalRef.h0000664000175100017510000000312112623076744022666 0ustar jenkins-buildjenkins-build/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SCOPED_LOCAL_REF_H_included #define SCOPED_LOCAL_REF_H_included #include "jni.h" #include // A smart pointer that deletes a JNI local reference when it goes out of scope. template class ScopedLocalRef { public: ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) { } ~ScopedLocalRef() { reset(); } void reset(T ptr = NULL) { if (ptr != mLocalRef) { if (mLocalRef != NULL) { mEnv->DeleteLocalRef(mLocalRef); } mLocalRef = ptr; } } T release() __attribute__((warn_unused_result)) { T localRef = mLocalRef; mLocalRef = NULL; return localRef; } T get() const { return mLocalRef; } private: JNIEnv* mEnv; T mLocalRef; // Disallow copy and assignment. ScopedLocalRef(const ScopedLocalRef&); void operator=(const ScopedLocalRef&); }; #endif // SCOPED_LOCAL_REF_H_included ceph-0.80.11/src/java/native/JniConstants.h0000664000175100017510000000422312623076744022462 0ustar jenkins-buildjenkins-build/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef JNI_CONSTANTS_H_included #define JNI_CONSTANTS_H_included #include /** * A cache to avoid calling FindClass at runtime. * * Class lookup is relatively expensive (2.5us on passion-eng at the time of writing), so we do * all such lookups eagerly at VM startup. This means that code that never uses, say, * java.util.zip.Deflater still has to pay for the lookup, but it means that on a device the cost * is definitely paid during boot and amortized. A central cache also removes the temptation to * dynamically call FindClass rather than add a small cache to each file that needs one. Another * cost is that each class cached here requires a global reference, though in practice we save * enough by not having a global reference for each file that uses a class such as java.lang.String * which is used in several files. * * FindClass is still called in a couple of situations: when throwing exceptions, and in some of * the serialization code. The former is clearly not a performance case, and we're currently * assuming that neither is the latter. * * TODO: similar arguments hold for field and method IDs; we should cache them centrally too. */ struct JniConstants { static void init(JNIEnv* env); static jclass inet6AddressClass; static jclass inetAddressClass; static jclass inetSocketAddressClass; static jclass stringClass; }; #define NATIVE_METHOD(className, functionName, signature) \ { #functionName, signature, reinterpret_cast(className ## _ ## functionName) } #endif // JNI_CONSTANTS_H_included ceph-0.80.11/src/java/native/libcephfs_jni.cc0000664000175100017510000022712612623076744023013 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "ScopedLocalRef.h" #include "JniConstants.h" #include "include/cephfs/libcephfs.h" #include "common/dout.h" #define dout_subsys ceph_subsys_javaclient #include "com_ceph_fs_CephMount.h" #define CEPH_STAT_CP "com/ceph/fs/CephStat" #define CEPH_STAT_VFS_CP "com/ceph/fs/CephStatVFS" #define CEPH_FILE_EXTENT_CP "com/ceph/fs/CephFileExtent" #define CEPH_MOUNT_CP "com/ceph/fs/CephMount" #define CEPH_NOTMOUNTED_CP "com/ceph/fs/CephNotMountedException" #define CEPH_FILEEXISTS_CP "com/ceph/fs/CephFileAlreadyExistsException" #define CEPH_ALREADYMOUNTED_CP "com/ceph/fs/CephAlreadyMountedException" #define CEPH_NOTDIR_CP "com/ceph/fs/CephNotDirectoryException" /* * Flags to open(). must be synchronized with CephMount.java * * There are two versions of flags: the version in Java and the version in the * target library (e.g. libc or libcephfs). We control the Java values and map * to the target value with fixup_* functions below. This is much faster than * keeping the values in Java and making a cross-JNI up-call to retrieve them, * and makes it easy to keep any platform specific value changes in this file. */ #define JAVA_O_RDONLY 1 #define JAVA_O_RDWR 2 #define JAVA_O_APPEND 4 #define JAVA_O_CREAT 8 #define JAVA_O_TRUNC 16 #define JAVA_O_EXCL 32 #define JAVA_O_WRONLY 64 /* * Whence flags for seek(). sync with CephMount.java if changed. * * Mapping of SEEK_* done in seek function. */ #define JAVA_SEEK_SET 1 #define JAVA_SEEK_CUR 2 #define JAVA_SEEK_END 3 /* * File attribute flags. sync with CephMount.java if changed. */ #define JAVA_SETATTR_MODE 1 #define JAVA_SETATTR_UID 2 #define JAVA_SETATTR_GID 4 #define JAVA_SETATTR_MTIME 8 #define JAVA_SETATTR_ATIME 16 /* * Setxattr flags. sync with CephMount.java if changed. */ #define JAVA_XATTR_CREATE 1 #define JAVA_XATTR_REPLACE 2 #define JAVA_XATTR_NONE 3 /* Map JAVA_O_* open flags to values in libc */ static inline int fixup_open_flags(jint jflags) { int ret = 0; #define FIXUP_OPEN_FLAG(name) \ if (jflags & JAVA_##name) \ ret |= name; FIXUP_OPEN_FLAG(O_RDONLY) FIXUP_OPEN_FLAG(O_RDWR) FIXUP_OPEN_FLAG(O_APPEND) FIXUP_OPEN_FLAG(O_CREAT) FIXUP_OPEN_FLAG(O_TRUNC) FIXUP_OPEN_FLAG(O_EXCL) FIXUP_OPEN_FLAG(O_WRONLY) #undef FIXUP_OPEN_FLAG return ret; } /* Map JAVA_SETATTR_* to values in ceph lib */ static inline int fixup_attr_mask(jint jmask) { int mask = 0; #define FIXUP_ATTR_MASK(name) \ if (jmask & JAVA_##name) \ mask |= CEPH_##name; FIXUP_ATTR_MASK(SETATTR_MODE) FIXUP_ATTR_MASK(SETATTR_UID) FIXUP_ATTR_MASK(SETATTR_GID) FIXUP_ATTR_MASK(SETATTR_MTIME) FIXUP_ATTR_MASK(SETATTR_ATIME) #undef FIXUP_ATTR_MASK return mask; } /* Cached field IDs for com.ceph.fs.CephStat */ static jfieldID cephstat_mode_fid; static jfieldID cephstat_uid_fid; static jfieldID cephstat_gid_fid; static jfieldID cephstat_size_fid; static jfieldID cephstat_blksize_fid; static jfieldID cephstat_blocks_fid; static jfieldID cephstat_a_time_fid; static jfieldID cephstat_m_time_fid; static jfieldID cephstat_is_file_fid; static jfieldID cephstat_is_directory_fid; static jfieldID cephstat_is_symlink_fid; /* Cached field IDs for com.ceph.fs.CephStatVFS */ static jfieldID cephstatvfs_bsize_fid; static jfieldID cephstatvfs_frsize_fid; static jfieldID cephstatvfs_blocks_fid; static jfieldID cephstatvfs_bavail_fid; static jfieldID cephstatvfs_files_fid; static jfieldID cephstatvfs_fsid_fid; static jfieldID cephstatvfs_namemax_fid; /* Cached field IDs for com.ceph.fs.CephMount */ static jfieldID cephmount_instance_ptr_fid; /* Cached field IDs for com.ceph.fs.CephFileExtent */ static jclass cephfileextent_cls; static jmethodID cephfileextent_ctor_fid; /* * Exception throwing helper. Adapted from Apache Hadoop header * org_apache_hadoop.h by adding the do {} while (0) construct. */ #define THROW(env, exception_name, message) \ do { \ jclass ecls = env->FindClass(exception_name); \ if (ecls) { \ int ret = env->ThrowNew(ecls, message); \ if (ret < 0) { \ printf("(CephFS) Fatal Error\n"); \ } \ env->DeleteLocalRef(ecls); \ } \ } while (0) static void cephThrowNullArg(JNIEnv *env, const char *msg) { THROW(env, "java/lang/NullPointerException", msg); } static void cephThrowOutOfMemory(JNIEnv *env, const char *msg) { THROW(env, "java/lang/OutOfMemoryError", msg); } static void cephThrowInternal(JNIEnv *env, const char *msg) { THROW(env, "java/lang/InternalError", msg); } static void cephThrowIndexBounds(JNIEnv *env, const char *msg) { THROW(env, "java/lang/IndexOutOfBoundsException", msg); } static void cephThrowIllegalArg(JNIEnv *env, const char *msg) { THROW(env, "java/lang/IllegalArgumentException", msg); } static void cephThrowFNF(JNIEnv *env, const char *msg) { THROW(env, "java/io/FileNotFoundException", msg); } static void cephThrowFileExists(JNIEnv *env, const char *msg) { THROW(env, CEPH_FILEEXISTS_CP, msg); } static void cephThrowNotDir(JNIEnv *env, const char *msg) { THROW(env, CEPH_NOTDIR_CP, msg); } static void handle_error(JNIEnv *env, int rc) { switch (rc) { case -ENOENT: cephThrowFNF(env, ""); return; case -EEXIST: cephThrowFileExists(env, ""); return; case -ENOTDIR: cephThrowNotDir(env, ""); return; default: break; } THROW(env, "java/io/IOException", strerror(-rc)); } #define CHECK_ARG_NULL(v, m, r) do { \ if (!(v)) { \ cephThrowNullArg(env, (m)); \ return (r); \ } } while (0) #define CHECK_ARG_BOUNDS(c, m, r) do { \ if ((c)) { \ cephThrowIndexBounds(env, (m)); \ return (r); \ } } while (0) #define CHECK_MOUNTED(_c, _r) do { \ if (!ceph_is_mounted((_c))) { \ THROW(env, CEPH_NOTMOUNTED_CP, "not mounted"); \ return (_r); \ } } while (0) /* * Cast a jlong to ceph_mount_info. Each JNI function is expected to pass in * the class instance variable instance_ptr. Passing a parameter is faster * than reaching back into Java via an upcall to retreive this pointer. */ static inline struct ceph_mount_info *get_ceph_mount(jlong j_mntp) { return (struct ceph_mount_info *)j_mntp; } /* * Setup cached field IDs */ static void setup_field_ids(JNIEnv *env, jclass clz) { jclass cephstat_cls; jclass cephstatvfs_cls; jclass tmp_cephfileextent_cls; /* * Get a fieldID from a class with a specific type * * clz: jclass * field: field in clz * type: integer, long, etc.. * * This macro assumes some naming convention that is used * only in this file: * * GETFID(cephstat, mode, I) gets translated into * cephstat_mode_fid = env->GetFieldID(cephstat_cls, "mode", "I"); */ #define GETFID(clz, field, type) do { \ clz ## _ ## field ## _fid = env->GetFieldID(clz ## _cls, #field, #type); \ if ( ! clz ## _ ## field ## _fid ) \ return; \ } while (0) /* Cache CephStat fields */ cephstat_cls = env->FindClass(CEPH_STAT_CP); if (!cephstat_cls) return; GETFID(cephstat, mode, I); GETFID(cephstat, uid, I); GETFID(cephstat, gid, I); GETFID(cephstat, size, J); GETFID(cephstat, blksize, J); GETFID(cephstat, blocks, J); GETFID(cephstat, a_time, J); GETFID(cephstat, m_time, J); GETFID(cephstat, is_file, Z); GETFID(cephstat, is_directory, Z); GETFID(cephstat, is_symlink, Z); /* Cache CephStatVFS fields */ cephstatvfs_cls = env->FindClass(CEPH_STAT_VFS_CP); if (!cephstatvfs_cls) return; GETFID(cephstatvfs, bsize, J); GETFID(cephstatvfs, frsize, J); GETFID(cephstatvfs, blocks, J); GETFID(cephstatvfs, bavail, J); GETFID(cephstatvfs, files, J); GETFID(cephstatvfs, fsid, J); GETFID(cephstatvfs, namemax, J); /* Cache CephFileExtent fields */ tmp_cephfileextent_cls = env->FindClass(CEPH_FILE_EXTENT_CP); if (!tmp_cephfileextent_cls) return; cephfileextent_cls = (jclass)env->NewGlobalRef(tmp_cephfileextent_cls); env->DeleteLocalRef(tmp_cephfileextent_cls); cephfileextent_ctor_fid = env->GetMethodID(cephfileextent_cls, "", "(JJ[I)V"); if (!cephfileextent_ctor_fid) return; JniConstants::init(env); #undef GETFID cephmount_instance_ptr_fid = env->GetFieldID(clz, "instance_ptr", "J"); } /* * Class: com_ceph_fs_CephMount * Method: native_initialize * Signature: ()V */ JNIEXPORT void JNICALL Java_com_ceph_fs_CephMount_native_1initialize (JNIEnv *env, jclass clz) { setup_field_ids(env, clz); } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_create * Signature: (Lcom/ceph/fs/CephMount;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1create (JNIEnv *env, jclass clz, jobject j_cephmount, jstring j_id) { struct ceph_mount_info *cmount; const char *c_id = NULL; int ret; CHECK_ARG_NULL(j_cephmount, "@mount is null", -1); if (j_id) { c_id = env->GetStringUTFChars(j_id, NULL); if (!c_id) { cephThrowInternal(env, "Failed to pin memory"); return -1; } } ret = ceph_create(&cmount, c_id); if (c_id) env->ReleaseStringUTFChars(j_id, c_id); if (ret) { THROW(env, "java/lang/RuntimeException", "failed to create Ceph mount object"); return ret; } env->SetLongField(j_cephmount, cephmount_instance_ptr_fid, (long)cmount); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_mount * Signature: (JLjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mount (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_root) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_root = NULL; int ret; /* * Toss a message up if we are already mounted. */ if (ceph_is_mounted(cmount)) { THROW(env, CEPH_ALREADYMOUNTED_CP, ""); return -1; } if (j_root) { c_root = env->GetStringUTFChars(j_root, NULL); if (!c_root) { cephThrowInternal(env, "Failed to pin memory"); return -1; } } ldout(cct, 10) << "jni: ceph_mount: " << (c_root ? c_root : "") << dendl; ret = ceph_mount(cmount, c_root); ldout(cct, 10) << "jni: ceph_mount: exit ret " << ret << dendl; if (c_root) env->ReleaseStringUTFChars(j_root, c_root); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_unmount * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1unmount (JNIEnv *env, jclass clz, jlong j_mntp) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; ldout(cct, 10) << "jni: ceph_unmount enter" << dendl; CHECK_MOUNTED(cmount, -1); ret = ceph_unmount(cmount); ldout(cct, 10) << "jni: ceph_unmount exit ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_release * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1release (JNIEnv *env, jclass clz, jlong j_mntp) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; ldout(cct, 10) << "jni: ceph_release called" << dendl; ret = ceph_release(cmount); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_conf_set * Signature: (JLjava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1set (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_opt, jstring j_val) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_opt, *c_val; int ret; CHECK_ARG_NULL(j_opt, "@option is null", -1); CHECK_ARG_NULL(j_val, "@value is null", -1); c_opt = env->GetStringUTFChars(j_opt, NULL); if (!c_opt) { cephThrowInternal(env, "failed to pin memory"); return -1; } c_val = env->GetStringUTFChars(j_val, NULL); if (!c_val) { env->ReleaseStringUTFChars(j_opt, c_opt); cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: conf_set: opt " << c_opt << " val " << c_val << dendl; ret = ceph_conf_set(cmount, c_opt, c_val); ldout(cct, 10) << "jni: conf_set: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_opt, c_opt); env->ReleaseStringUTFChars(j_val, c_val); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_conf_get * Signature: (JLjava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1get (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_opt) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_opt; jstring value = NULL; int ret, buflen; char *buf; CHECK_ARG_NULL(j_opt, "@option is null", NULL); c_opt = env->GetStringUTFChars(j_opt, NULL); if (!c_opt) { cephThrowInternal(env, "failed to pin memory"); return NULL; } buflen = 128; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "head allocation failed"); goto out; } while (1) { memset(buf, 0, sizeof(char)*buflen); ldout(cct, 10) << "jni: conf_get: opt " << c_opt << " len " << buflen << dendl; ret = ceph_conf_get(cmount, c_opt, buf, buflen); if (ret == -ENAMETOOLONG) { buflen *= 2; delete [] buf; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "head allocation failed"); goto out; } } else break; } ldout(cct, 10) << "jni: conf_get: ret " << ret << dendl; if (ret == 0) value = env->NewStringUTF(buf); else if (ret != -ENOENT) handle_error(env, ret); delete [] buf; out: env->ReleaseStringUTFChars(j_opt, c_opt); return value; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_conf_read_file * Signature: (JLjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1read_1file (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: conf_read_file: path " << c_path << dendl; ret = ceph_conf_read_file(cmount, c_path); ldout(cct, 10) << "jni: conf_read_file: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_statfs * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStatVFS;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1statfs (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstatvfs) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; struct statvfs st; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_cephstatvfs, "@stat is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: statfs: path " << c_path << dendl; ret = ceph_statfs(cmount, c_path, &st); ldout(cct, 10) << "jni: statfs: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) { handle_error(env, ret); return ret; } env->SetLongField(j_cephstatvfs, cephstatvfs_bsize_fid, st.f_bsize); env->SetLongField(j_cephstatvfs, cephstatvfs_frsize_fid, st.f_frsize); env->SetLongField(j_cephstatvfs, cephstatvfs_blocks_fid, st.f_blocks); env->SetLongField(j_cephstatvfs, cephstatvfs_bavail_fid, st.f_bavail); env->SetLongField(j_cephstatvfs, cephstatvfs_files_fid, st.f_files); env->SetLongField(j_cephstatvfs, cephstatvfs_fsid_fid, st.f_fsid); env->SetLongField(j_cephstatvfs, cephstatvfs_namemax_fid, st.f_namemax); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_getcwd * Signature: (J)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1getcwd (JNIEnv *env, jclass clz, jlong j_mntp) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_cwd; CHECK_MOUNTED(cmount, NULL); ldout(cct, 10) << "jni: getcwd: enter" << dendl; c_cwd = ceph_getcwd(cmount); if (!c_cwd) { cephThrowOutOfMemory(env, "ceph_getcwd"); return NULL; } ldout(cct, 10) << "jni: getcwd: exit ret " << c_cwd << dendl; return env->NewStringUTF(c_cwd); } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_chdir * Signature: (JLjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1chdir (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: chdir: path " << c_path << dendl; ret = ceph_chdir(cmount, c_path); ldout(cct, 10) << "jni: chdir: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_listdir * Signature: (JLjava/lang/String;)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1listdir (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); struct ceph_dir_result *dirp; list::iterator it; list contents; const char *c_path; jobjectArray dirlist; string *ent; int ret, buflen, bufpos, i; jstring name; char *buf; CHECK_ARG_NULL(j_path, "@path is null", NULL); CHECK_MOUNTED(cmount, NULL); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return NULL; } ldout(cct, 10) << "jni: listdir: opendir: path " << c_path << dendl; /* ret < 0 also includes -ENOTDIR which should return NULL */ ret = ceph_opendir(cmount, c_path, &dirp); if (ret) { env->ReleaseStringUTFChars(j_path, c_path); handle_error(env, ret); return NULL; } ldout(cct, 10) << "jni: listdir: opendir: exit ret " << ret << dendl; /* buffer for ceph_getdnames() results */ buflen = 256; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } while (1) { ldout(cct, 10) << "jni: listdir: getdnames: enter" << dendl; ret = ceph_getdnames(cmount, dirp, buf, buflen); if (ret == -ERANGE) { delete [] buf; buflen *= 2; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } continue; } ldout(cct, 10) << "jni: listdir: getdnames: exit ret " << ret << dendl; if (ret <= 0) break; /* got at least one name */ bufpos = 0; while (bufpos < ret) { ent = new (std::nothrow) string(buf + bufpos); if (!ent) { delete [] buf; cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } /* filter out dot files: xref: java.io.File::list() */ if (ent->compare(".") && ent->compare("..")) { contents.push_back(*ent); ldout(cct, 20) << "jni: listdir: take path " << *ent << dendl; } bufpos += ent->size() + 1; delete ent; } } delete [] buf; if (ret < 0) { handle_error(env, ret); goto out; } /* directory list */ dirlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL); if (!dirlist) goto out; /* * Fill directory listing array. * * FIXME: how should a partially filled array be cleaned-up properly? */ for (i = 0, it = contents.begin(); it != contents.end(); ++it) { name = env->NewStringUTF(it->c_str()); if (!name) goto out; env->SetObjectArrayElement(dirlist, i++, name); if (env->ExceptionOccurred()) goto out; env->DeleteLocalRef(name); } env->ReleaseStringUTFChars(j_path, c_path); ceph_closedir(cmount, dirp); return dirlist; out: env->ReleaseStringUTFChars(j_path, c_path); ceph_closedir(cmount, dirp); return NULL; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_link * Signature: (JLjava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1link (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_oldpath, jstring j_newpath) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_oldpath, *c_newpath; int ret; CHECK_ARG_NULL(j_oldpath, "@oldpath is null", -1); CHECK_ARG_NULL(j_newpath, "@newpath is null", -1); CHECK_MOUNTED(cmount, -1); c_oldpath = env->GetStringUTFChars(j_oldpath, NULL); if (!c_oldpath) { cephThrowInternal(env, "failed to pin memory"); return -1; } c_newpath = env->GetStringUTFChars(j_newpath, NULL); if (!c_newpath) { env->ReleaseStringUTFChars(j_oldpath, c_oldpath); cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: link: oldpath " << c_oldpath << " newpath " << c_newpath << dendl; ret = ceph_link(cmount, c_oldpath, c_newpath); ldout(cct, 10) << "jni: link: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_oldpath, c_oldpath); env->ReleaseStringUTFChars(j_newpath, c_newpath); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_unlink * Signature: (JLjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1unlink (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: unlink: path " << c_path << dendl; ret = ceph_unlink(cmount, c_path); ldout(cct, 10) << "jni: unlink: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_rename * Signature: (JLjava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1rename (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_from, jstring j_to) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_from, *c_to; int ret; CHECK_ARG_NULL(j_from, "@from is null", -1); CHECK_ARG_NULL(j_to, "@to is null", -1); CHECK_MOUNTED(cmount, -1); c_from = env->GetStringUTFChars(j_from, NULL); if (!c_from) { cephThrowInternal(env, "Failed to pin memory!"); return -1; } c_to = env->GetStringUTFChars(j_to, NULL); if (!c_to) { env->ReleaseStringUTFChars(j_from, c_from); cephThrowInternal(env, "Failed to pin memory."); return -1; } ldout(cct, 10) << "jni: rename: from " << c_from << " to " << c_to << dendl; ret = ceph_rename(cmount, c_from, c_to); ldout(cct, 10) << "jni: rename: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_from, c_from); env->ReleaseStringUTFChars(j_to, c_to); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_mkdir * Signature: (JLjava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mkdir (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: mkdir: path " << c_path << " mode " << (int)j_mode << dendl; ret = ceph_mkdir(cmount, c_path, (int)j_mode); ldout(cct, 10) << "jni: mkdir: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_mkdirs * Signature: (JLjava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mkdirs (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: mkdirs: path " << c_path << " mode " << (int)j_mode << dendl; ret = ceph_mkdirs(cmount, c_path, (int)j_mode); ldout(cct, 10) << "jni: mkdirs: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_rmdir * Signature: (JLjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1rmdir (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: rmdir: path " << c_path << dendl; ret = ceph_rmdir(cmount, c_path); ldout(cct, 10) << "jni: rmdir: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_readlink * Signature: (JLjava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1readlink (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; char *linkname; struct stat st; jstring j_linkname; CHECK_ARG_NULL(j_path, "@path is null", NULL); CHECK_MOUNTED(cmount, NULL); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "failed to pin memory"); return NULL; } for (;;) { ldout(cct, 10) << "jni: readlink: lstatx " << c_path << dendl; int ret = ceph_lstat(cmount, c_path, &st); ldout(cct, 10) << "jni: readlink: lstat exit ret " << ret << dendl; if (ret) { env->ReleaseStringUTFChars(j_path, c_path); handle_error(env, ret); return NULL; } linkname = new (std::nothrow) char[st.st_size + 1]; if (!linkname) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowOutOfMemory(env, "head allocation failed"); return NULL; } ldout(cct, 10) << "jni: readlink: size " << st.st_size << " path " << c_path << dendl; ret = ceph_readlink(cmount, c_path, linkname, st.st_size + 1); ldout(cct, 10) << "jni: readlink: exit ret " << ret << dendl; if (ret < 0) { delete [] linkname; env->ReleaseStringUTFChars(j_path, c_path); handle_error(env, ret); return NULL; } /* re-stat and try again */ if (ret > st.st_size) { delete [] linkname; continue; } linkname[ret] = '\0'; break; } env->ReleaseStringUTFChars(j_path, c_path); j_linkname = env->NewStringUTF(linkname); delete [] linkname; return j_linkname; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_symlink * Signature: (JLjava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1symlink (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_oldpath, jstring j_newpath) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_oldpath, *c_newpath; int ret; CHECK_ARG_NULL(j_oldpath, "@oldpath is null", -1); CHECK_ARG_NULL(j_newpath, "@newpath is null", -1); CHECK_MOUNTED(cmount, -1); c_oldpath = env->GetStringUTFChars(j_oldpath, NULL); if (!c_oldpath) { cephThrowInternal(env, "failed to pin memory"); return -1; } c_newpath = env->GetStringUTFChars(j_newpath, NULL); if (!c_newpath) { env->ReleaseStringUTFChars(j_oldpath, c_oldpath); cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: symlink: oldpath " << c_oldpath << " newpath " << c_newpath << dendl; ret = ceph_symlink(cmount, c_oldpath, c_newpath); ldout(cct, 10) << "jni: symlink: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_oldpath, c_oldpath); env->ReleaseStringUTFChars(j_newpath, c_newpath); if (ret) handle_error(env, ret); return ret; } static void fill_cephstat(JNIEnv *env, jobject j_cephstat, struct stat *st) { env->SetIntField(j_cephstat, cephstat_mode_fid, st->st_mode); env->SetIntField(j_cephstat, cephstat_uid_fid, st->st_uid); env->SetIntField(j_cephstat, cephstat_gid_fid, st->st_gid); env->SetLongField(j_cephstat, cephstat_size_fid, st->st_size); env->SetLongField(j_cephstat, cephstat_blksize_fid, st->st_blksize); env->SetLongField(j_cephstat, cephstat_blocks_fid, st->st_blocks); long long time = st->st_mtim.tv_sec; time *= 1000; time += st->st_mtim.tv_nsec / 1000000; env->SetLongField(j_cephstat, cephstat_m_time_fid, time); time = st->st_atim.tv_sec; time *= 1000; time += st->st_atim.tv_nsec / 1000000; env->SetLongField(j_cephstat, cephstat_a_time_fid, time); env->SetBooleanField(j_cephstat, cephstat_is_file_fid, S_ISREG(st->st_mode) ? JNI_TRUE : JNI_FALSE); env->SetBooleanField(j_cephstat, cephstat_is_directory_fid, S_ISDIR(st->st_mode) ? JNI_TRUE : JNI_FALSE); env->SetBooleanField(j_cephstat, cephstat_is_symlink_fid, S_ISLNK(st->st_mode) ? JNI_TRUE : JNI_FALSE); } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_lstat * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lstat (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; struct stat st; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_cephstat, "@stat is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: lstat: path " << c_path << dendl; ret = ceph_lstat(cmount, c_path, &st); ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) { handle_error(env, ret); return ret; } fill_cephstat(env, j_cephstat, &st); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_stat * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1stat (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; struct stat st; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_cephstat, "@stat is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: lstat: path " << c_path << dendl; ret = ceph_stat(cmount, c_path, &st); ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) { handle_error(env, ret); return ret; } fill_cephstat(env, j_cephstat, &st); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_setattr * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;I)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1setattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat, jint j_mask) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; struct stat st; int ret, mask = fixup_attr_mask(j_mask); CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_cephstat, "@stat is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } memset(&st, 0, sizeof(st)); st.st_mode = env->GetIntField(j_cephstat, cephstat_mode_fid); st.st_uid = env->GetIntField(j_cephstat, cephstat_uid_fid); st.st_gid = env->GetIntField(j_cephstat, cephstat_gid_fid); st.st_mtime = env->GetLongField(j_cephstat, cephstat_m_time_fid); st.st_atime = env->GetLongField(j_cephstat, cephstat_a_time_fid); ldout(cct, 10) << "jni: setattr: path " << c_path << " mask " << mask << dendl; ret = ceph_setattr(cmount, c_path, &st, mask); ldout(cct, 10) << "jni: setattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_chmod * Signature: (JLjava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1chmod (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: chmod: path " << c_path << " mode " << (int)j_mode << dendl; ret = ceph_chmod(cmount, c_path, (int)j_mode); ldout(cct, 10) << "jni: chmod: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_fchmod * Signature: (JII)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fchmod (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jint j_mode) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: fchmod: fd " << (int)j_fd << " mode " << (int)j_mode << dendl; ret = ceph_fchmod(cmount, (int)j_fd, (int)j_mode); ldout(cct, 10) << "jni: fchmod: exit ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_truncate * Signature: (JLjava/lang/String;J)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1truncate (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jlong j_size) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: truncate: path " << c_path << " size " << (loff_t)j_size << dendl; ret = ceph_truncate(cmount, c_path, (loff_t)j_size); ldout(cct, 10) << "jni: truncate: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_open * Signature: (JLjava/lang/String;II)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1open (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_flags, jint j_mode) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; int ret, flags = fixup_open_flags(j_flags); CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: open: path " << c_path << " flags " << flags << " mode " << (int)j_mode << dendl; ret = ceph_open(cmount, c_path, flags, (int)j_mode); ldout(cct, 10) << "jni: open: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (ret < 0) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_open_layout * Signature: (JLjava/lang/String;IIIIILjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1open_1layout (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_flags, jint j_mode, jint stripe_unit, jint stripe_count, jint object_size, jstring j_data_pool) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path, *c_data_pool = NULL; int ret, flags = fixup_open_flags(j_flags); CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } if (j_data_pool) { c_data_pool = env->GetStringUTFChars(j_data_pool, NULL); if (!c_data_pool) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } } ldout(cct, 10) << "jni: open_layout: path " << c_path << " flags " << flags << " mode " << (int)j_mode << " stripe_unit " << stripe_unit << " stripe_count " << stripe_count << " object_size " << object_size << " data_pool " << (c_data_pool ? c_data_pool : "") << dendl; ret = ceph_open_layout(cmount, c_path, flags, (int)j_mode, (int)stripe_unit, (int)stripe_count, (int)object_size, c_data_pool); ldout(cct, 10) << "jni: open_layout: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); if (j_data_pool) env->ReleaseStringUTFChars(j_data_pool, c_data_pool); if (ret < 0) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_close * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1close (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: close: fd " << (int)j_fd << dendl; ret = ceph_close(cmount, (int)j_fd); ldout(cct, 10) << "jni: close: ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_lseek * Signature: (JIJI)J */ JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lseek (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jlong j_offset, jint j_whence) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int whence; jlong ret; CHECK_MOUNTED(cmount, -1); switch (j_whence) { case JAVA_SEEK_SET: whence = SEEK_SET; break; case JAVA_SEEK_CUR: whence = SEEK_CUR; break; case JAVA_SEEK_END: whence = SEEK_END; break; default: cephThrowIllegalArg(env, "Unknown whence value"); return -1; } ldout(cct, 10) << "jni: lseek: fd " << (int)j_fd << " offset " << (long)j_offset << " whence " << whence << dendl; ret = ceph_lseek(cmount, (int)j_fd, (long)j_offset, whence); ldout(cct, 10) << "jni: lseek: exit ret " << ret << dendl; if (ret < 0) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_read * Signature: (JI[BJJ)J */ JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1read (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jbyteArray j_buf, jlong j_size, jlong j_offset) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); jsize buf_size; jbyte *c_buf; long ret; CHECK_ARG_NULL(j_buf, "@buf is null", -1); CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1); CHECK_MOUNTED(cmount, -1); buf_size = env->GetArrayLength(j_buf); CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1); c_buf = env->GetByteArrayElements(j_buf, NULL); if (!c_buf) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: read: fd " << (int)j_fd << " len " << (int)j_size << " offset " << (int)j_offset << dendl; ret = ceph_read(cmount, (int)j_fd, (char*)c_buf, (int)j_size, (int)j_offset); ldout(cct, 10) << "jni: read: exit ret " << ret << dendl; if (ret < 0) handle_error(env, (int)ret); else env->ReleaseByteArrayElements(j_buf, c_buf, 0); return (jlong)ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_write * Signature: (JI[BJJ)J */ JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1write (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jbyteArray j_buf, jlong j_size, jlong j_offset) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); jsize buf_size; jbyte *c_buf; long ret; CHECK_ARG_NULL(j_buf, "@buf is null", -1); CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1); CHECK_MOUNTED(cmount, -1); buf_size = env->GetArrayLength(j_buf); CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1); c_buf = env->GetByteArrayElements(j_buf, NULL); if (!c_buf) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: write: fd " << (int)j_fd << " len " << (int)j_size << " offset " << (int)j_offset << dendl; ret = ceph_write(cmount, (int)j_fd, (char*)c_buf, (int)j_size, (int)j_offset); ldout(cct, 10) << "jni: write: exit ret " << ret << dendl; if (ret < 0) handle_error(env, (int)ret); else env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_ftruncate * Signature: (JIJ)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1ftruncate (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jlong j_size) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: ftruncate: fd " << (int)j_fd << " size " << (loff_t)j_size << dendl; ret = ceph_ftruncate(cmount, (int)j_fd, (loff_t)j_size); ldout(cct, 10) << "jni: ftruncate: exit ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_fsync * Signature: (JIZ)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fsync (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jboolean j_dataonly) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; ldout(cct, 10) << "jni: fsync: fd " << (int)j_fd << " dataonly " << (j_dataonly ? 1 : 0) << dendl; ret = ceph_fsync(cmount, (int)j_fd, j_dataonly ? 1 : 0); ldout(cct, 10) << "jni: fsync: exit ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_fstat * Signature: (JILcom/ceph/fs/CephStat;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fstat (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jobject j_cephstat) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); long long time; struct stat st; int ret; CHECK_ARG_NULL(j_cephstat, "@stat is null", -1); CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: fstat: fd " << (int)j_fd << dendl; ret = ceph_fstat(cmount, (int)j_fd, &st); ldout(cct, 10) << "jni: fstat exit ret " << ret << dendl; if (ret) { handle_error(env, ret); return ret; } env->SetIntField(j_cephstat, cephstat_mode_fid, st.st_mode); env->SetIntField(j_cephstat, cephstat_uid_fid, st.st_uid); env->SetIntField(j_cephstat, cephstat_gid_fid, st.st_gid); env->SetLongField(j_cephstat, cephstat_size_fid, st.st_size); env->SetLongField(j_cephstat, cephstat_blksize_fid, st.st_blksize); env->SetLongField(j_cephstat, cephstat_blocks_fid, st.st_blocks); time = st.st_mtim.tv_sec; time *= 1000; time += st.st_mtim.tv_nsec / 1000; env->SetLongField(j_cephstat, cephstat_m_time_fid, time); time = st.st_atim.tv_sec; time *= 1000; time += st.st_atim.tv_nsec / 1000; env->SetLongField(j_cephstat, cephstat_a_time_fid, time); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_sync_fs * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1sync_1fs (JNIEnv *env, jclass clz, jlong j_mntp) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; ldout(cct, 10) << "jni: sync_fs: enter" << dendl; ret = ceph_sync_fs(cmount); ldout(cct, 10) << "jni: sync_fs: exit ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_getxattr * Signature: (JLjava/lang/String;Ljava/lang/String;[B)J */ JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1getxattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; const char *c_name; jsize buf_size; jbyte *c_buf = NULL; /* please gcc with goto */ long ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_name, "@name is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } c_name = env->GetStringUTFChars(j_name, NULL); if (!c_name) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } /* just lookup the size if buf is null */ if (!j_buf) { buf_size = 0; goto do_getxattr; } c_buf = env->GetByteArrayElements(j_buf, NULL); if (!c_buf) { env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); cephThrowInternal(env, "failed to pin memory"); return -1; } buf_size = env->GetArrayLength(j_buf); do_getxattr: ldout(cct, 10) << "jni: getxattr: path " << c_path << " name " << c_name << " len " << buf_size << dendl; ret = ceph_getxattr(cmount, c_path, c_name, c_buf, buf_size); if (ret == -ERANGE) ret = ceph_getxattr(cmount, c_path, c_name, c_buf, 0); ldout(cct, 10) << "jni: getxattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); if (j_buf) env->ReleaseByteArrayElements(j_buf, c_buf, 0); if (ret < 0) handle_error(env, (int)ret); return (jlong)ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_lgetxattr * Signature: (JLjava/lang/String;Ljava/lang/String;[B)I */ JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lgetxattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; const char *c_name; jsize buf_size; jbyte *c_buf = NULL; /* please gcc with goto */ long ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_name, "@name is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } c_name = env->GetStringUTFChars(j_name, NULL); if (!c_name) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } /* just lookup the size if buf is null */ if (!j_buf) { buf_size = 0; goto do_lgetxattr; } c_buf = env->GetByteArrayElements(j_buf, NULL); if (!c_buf) { env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); cephThrowInternal(env, "failed to pin memory"); return -1; } buf_size = env->GetArrayLength(j_buf); do_lgetxattr: ldout(cct, 10) << "jni: lgetxattr: path " << c_path << " name " << c_name << " len " << buf_size << dendl; ret = ceph_lgetxattr(cmount, c_path, c_name, c_buf, buf_size); if (ret == -ERANGE) ret = ceph_lgetxattr(cmount, c_path, c_name, c_buf, 0); ldout(cct, 10) << "jni: lgetxattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); if (j_buf) env->ReleaseByteArrayElements(j_buf, c_buf, 0); if (ret < 0) handle_error(env, (int)ret); return (jlong)ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_listxattr * Signature: (JLjava/lang/String;)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1listxattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); jobjectArray xattrlist; const char *c_path; string *ent; jstring name; list::iterator it; list contents; int ret, buflen, bufpos, i; char *buf; CHECK_ARG_NULL(j_path, "@path is null", NULL); CHECK_MOUNTED(cmount, NULL); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return NULL; } buflen = 1024; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "head allocation failed"); goto out; } while (1) { ldout(cct, 10) << "jni: listxattr: path " << c_path << " len " << buflen << dendl; ret = ceph_listxattr(cmount, c_path, buf, buflen); if (ret == -ERANGE) { delete [] buf; buflen *= 2; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } continue; } break; } ldout(cct, 10) << "jni: listxattr: ret " << ret << dendl; if (ret < 0) { delete [] buf; handle_error(env, ret); goto out; } bufpos = 0; while (bufpos < ret) { ent = new (std::nothrow) string(buf + bufpos); if (!ent) { delete [] buf; cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } contents.push_back(*ent); bufpos += ent->size() + 1; delete ent; } delete [] buf; xattrlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL); if (!xattrlist) goto out; for (i = 0, it = contents.begin(); it != contents.end(); ++it) { name = env->NewStringUTF(it->c_str()); if (!name) goto out; env->SetObjectArrayElement(xattrlist, i++, name); if (env->ExceptionOccurred()) goto out; env->DeleteLocalRef(name); } env->ReleaseStringUTFChars(j_path, c_path); return xattrlist; out: env->ReleaseStringUTFChars(j_path, c_path); return NULL; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_llistxattr * Signature: (JLjava/lang/String;)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1llistxattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); jobjectArray xattrlist; const char *c_path; string *ent; jstring name; list::iterator it; list contents; int ret, buflen, bufpos, i; char *buf; CHECK_ARG_NULL(j_path, "@path is null", NULL); CHECK_MOUNTED(cmount, NULL); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return NULL; } buflen = 1024; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "head allocation failed"); goto out; } while (1) { ldout(cct, 10) << "jni: llistxattr: path " << c_path << " len " << buflen << dendl; ret = ceph_llistxattr(cmount, c_path, buf, buflen); if (ret == -ERANGE) { delete [] buf; buflen *= 2; buf = new (std::nothrow) char[buflen]; if (!buf) { cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } continue; } break; } ldout(cct, 10) << "jni: llistxattr: ret " << ret << dendl; if (ret < 0) { delete [] buf; handle_error(env, ret); goto out; } bufpos = 0; while (bufpos < ret) { ent = new (std::nothrow) string(buf + bufpos); if (!ent) { delete [] buf; cephThrowOutOfMemory(env, "heap allocation failed"); goto out; } contents.push_back(*ent); bufpos += ent->size() + 1; delete ent; } delete [] buf; xattrlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL); if (!xattrlist) goto out; for (i = 0, it = contents.begin(); it != contents.end(); ++it) { name = env->NewStringUTF(it->c_str()); if (!name) goto out; env->SetObjectArrayElement(xattrlist, i++, name); if (env->ExceptionOccurred()) goto out; env->DeleteLocalRef(name); } env->ReleaseStringUTFChars(j_path, c_path); return xattrlist; out: env->ReleaseStringUTFChars(j_path, c_path); return NULL; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_removexattr * Signature: (JLjava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1removexattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; const char *c_name; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_name, "@name is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } c_name = env->GetStringUTFChars(j_name, NULL); if (!c_name) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: removexattr: path " << c_path << " name " << c_name << dendl; ret = ceph_removexattr(cmount, c_path, c_name); ldout(cct, 10) << "jni: removexattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_lremovexattr * Signature: (JLjava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lremovexattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; const char *c_name; int ret; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_name, "@name is null", -1); CHECK_MOUNTED(cmount, -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } c_name = env->GetStringUTFChars(j_name, NULL); if (!c_name) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } ldout(cct, 10) << "jni: lremovexattr: path " << c_path << " name " << c_name << dendl; ret = ceph_lremovexattr(cmount, c_path, c_name); ldout(cct, 10) << "jni: lremovexattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_setxattr * Signature: (JLjava/lang/String;Ljava/lang/String;[BJI)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1setxattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf, jlong j_size, jint j_flags) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; const char *c_name; jsize buf_size; jbyte *c_buf; int ret, flags; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_name, "@name is null", -1); CHECK_ARG_NULL(j_buf, "@buf is null", -1); CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1); CHECK_MOUNTED(cmount, -1); buf_size = env->GetArrayLength(j_buf); CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } c_name = env->GetStringUTFChars(j_name, NULL); if (!c_name) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } c_buf = env->GetByteArrayElements(j_buf, NULL); if (!c_buf) { env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); cephThrowInternal(env, "failed to pin memory"); return -1; } switch (j_flags) { case JAVA_XATTR_CREATE: flags = CEPH_XATTR_CREATE; break; case JAVA_XATTR_REPLACE: flags = CEPH_XATTR_REPLACE; break; case JAVA_XATTR_NONE: flags = 0; break; default: env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT); cephThrowIllegalArg(env, "setxattr flag"); return -1; } ldout(cct, 10) << "jni: setxattr: path " << c_path << " name " << c_name << " len " << j_size << " flags " << flags << dendl; ret = ceph_setxattr(cmount, c_path, c_name, c_buf, j_size, flags); ldout(cct, 10) << "jni: setxattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_lsetxattr * Signature: (JLjava/lang/String;Ljava/lang/String;[BJI)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lsetxattr (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf, jlong j_size, jint j_flags) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; const char *c_name; jsize buf_size; jbyte *c_buf; int ret, flags; CHECK_ARG_NULL(j_path, "@path is null", -1); CHECK_ARG_NULL(j_name, "@name is null", -1); CHECK_ARG_NULL(j_buf, "@buf is null", -1); CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1); CHECK_MOUNTED(cmount, -1); buf_size = env->GetArrayLength(j_buf); CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1); c_path = env->GetStringUTFChars(j_path, NULL); if (!c_path) { cephThrowInternal(env, "Failed to pin memory"); return -1; } c_name = env->GetStringUTFChars(j_name, NULL); if (!c_name) { env->ReleaseStringUTFChars(j_path, c_path); cephThrowInternal(env, "Failed to pin memory"); return -1; } c_buf = env->GetByteArrayElements(j_buf, NULL); if (!c_buf) { env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); cephThrowInternal(env, "failed to pin memory"); return -1; } switch (j_flags) { case JAVA_XATTR_CREATE: flags = CEPH_XATTR_CREATE; break; case JAVA_XATTR_REPLACE: flags = CEPH_XATTR_REPLACE; break; case JAVA_XATTR_NONE: flags = 0; break; default: env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT); cephThrowIllegalArg(env, "lsetxattr flag"); return -1; } ldout(cct, 10) << "jni: lsetxattr: path " << c_path << " name " << c_name << " len " << j_size << " flags " << flags << dendl; ret = ceph_lsetxattr(cmount, c_path, c_name, c_buf, j_size, flags); ldout(cct, 10) << "jni: lsetxattr: exit ret " << ret << dendl; env->ReleaseStringUTFChars(j_path, c_path); env->ReleaseStringUTFChars(j_name, c_name); env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT); if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_file_stripe_unit * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1stripe_1unit (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: get_file_stripe_unit: fd " << (int)j_fd << dendl; ret = ceph_get_file_stripe_unit(cmount, (int)j_fd); ldout(cct, 10) << "jni: get_file_stripe_unit: exit ret " << ret << dendl; if (ret < 0) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_file_replication * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1replication (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: get_file_replication: fd " << (int)j_fd << dendl; ret = ceph_get_file_replication(cmount, (int)j_fd); ldout(cct, 10) << "jni: get_file_replication: exit ret " << ret << dendl; if (ret < 0) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_file_pool_name * Signature: (JI)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1pool_1name (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); jstring pool = NULL; int ret, buflen = 0; char *buf = NULL; CHECK_MOUNTED(cmount, NULL); ldout(cct, 10) << "jni: get_file_pool_name: fd " << (int)j_fd << dendl; for (;;) { /* get pool name length (len==0) */ ret = ceph_get_file_pool_name(cmount, (int)j_fd, NULL, 0); if (ret < 0) break; /* allocate buffer */ if (buf) delete [] buf; buflen = ret; buf = new (std::nothrow) char[buflen+1]; /* +1 for '\0' */ if (!buf) { cephThrowOutOfMemory(env, "head allocation failed"); goto out; } memset(buf, 0, (buflen+1)*sizeof(*buf)); /* handle zero-length pool name!? */ if (buflen == 0) break; /* fill buffer */ ret = ceph_get_file_pool_name(cmount, (int)j_fd, buf, buflen); if (ret == -ERANGE) /* size changed! */ continue; else break; } ldout(cct, 10) << "jni: get_file_pool_name: ret " << ret << dendl; if (ret < 0) handle_error(env, ret); else pool = env->NewStringUTF(buf); out: if (buf) delete [] buf; return pool; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_localize_reads * Signature: (JZ)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1localize_1reads (JNIEnv *env, jclass clz, jlong j_mntp, jboolean j_on) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret, val = j_on ? 1 : 0; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: localize_reads: val " << val << dendl; ret = ceph_localize_reads(cmount, val); ldout(cct, 10) << "jni: localize_reads: exit ret " << ret << dendl; if (ret) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_stripe_unit_granularity * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1stripe_1unit_1granularity (JNIEnv *env, jclass clz, jlong j_mntp) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: get_stripe_unit_granularity" << dendl; ret = ceph_get_stripe_unit_granularity(cmount); ldout(cct, 10) << "jni: get_stripe_unit_granularity: exit ret " << ret << dendl; if (ret < 0) handle_error(env, ret); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_pool_id * Signature: (JLjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1pool_1id (JNIEnv *env, jclass clz, jlong j_mntp, jstring jname) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_name; int ret; CHECK_MOUNTED(cmount, -1); CHECK_ARG_NULL(jname, "@name is null", -1); c_name = env->GetStringUTFChars(jname, NULL); if (!c_name) { cephThrowInternal(env, "failed to pin memory"); return -1; } ldout(cct, 10) << "jni: get_pool_id: name " << c_name << dendl; ret = ceph_get_pool_id(cmount, c_name); if (ret < 0) handle_error(env, ret); ldout(cct, 10) << "jni: get_pool_id: ret " << ret << dendl; env->ReleaseStringUTFChars(jname, c_name); return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_pool_replication * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1pool_1replication (JNIEnv *env, jclass clz, jlong j_mntp, jint jpoolid) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); int ret; CHECK_MOUNTED(cmount, -1); ldout(cct, 10) << "jni: get_pool_replication: poolid " << jpoolid << dendl; ret = ceph_get_pool_replication(cmount, jpoolid); if (ret < 0) handle_error(env, ret); ldout(cct, 10) << "jni: get_pool_replication: ret " << ret << dendl; return ret; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_file_extent_osds * Signature: (JIJ)Lcom/ceph/fs/CephFileExtent; */ JNIEXPORT jobject JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1extent_1osds (JNIEnv *env, jclass clz, jlong mntp, jint fd, jlong off) { struct ceph_mount_info *cmount = get_ceph_mount(mntp); CephContext *cct = ceph_get_mount_context(cmount); jobject extent = NULL; int ret, nosds, *osds = NULL; jintArray osd_array; loff_t len; CHECK_MOUNTED(cmount, NULL); ldout(cct, 10) << "jni: get_file_extent_osds: fd " << fd << " off " << off << dendl; for (;;) { /* get pg size */ ret = ceph_get_file_extent_osds(cmount, fd, off, NULL, NULL, 0); if (ret < 0) break; /* alloc osd id array */ if (osds) delete [] osds; nosds = ret; osds = new int[nosds]; /* get osd ids */ ret = ceph_get_file_extent_osds(cmount, fd, off, &len, osds, nosds); if (ret == -ERANGE) continue; else break; } ldout(cct, 10) << "jni: get_file_extent_osds: ret " << ret << dendl; if (ret < 0) { handle_error(env, ret); goto out; } nosds = ret; osd_array = env->NewIntArray(nosds); if (!osd_array) goto out; env->SetIntArrayRegion(osd_array, 0, nosds, osds); if (env->ExceptionOccurred()) goto out; extent = env->NewObject(cephfileextent_cls, cephfileextent_ctor_fid, off, len, osd_array); if (!extent) goto out; out: if (osds) delete [] osds; return extent; } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_osd_crush_location * Signature: (JI)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1osd_1crush_1location (JNIEnv *env, jclass clz, jlong j_mntp, jint osdid) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); jobjectArray path = NULL; vector str_path; int ret, bufpos, buflen = 0; char *buf = NULL; CHECK_MOUNTED(cmount, NULL); ldout(cct, 10) << "jni: osd loc: osd " << osdid << dendl; for (;;) { /* get length of the location path */ ret = ceph_get_osd_crush_location(cmount, osdid, NULL, 0); if (ret < 0) break; /* alloc path buffer */ if (buf) delete [] buf; buflen = ret; buf = new char[buflen+1]; memset(buf, 0, buflen*sizeof(*buf)); /* empty path */ if (buflen == 0) break; /* get the path */ ret = ceph_get_osd_crush_location(cmount, osdid, buf, buflen); if (ret == -ERANGE) continue; else break; } ldout(cct, 10) << "jni: osd loc: osd " << osdid << " ret " << ret << dendl; if (ret < 0) { handle_error(env, ret); goto out; } bufpos = 0; while (bufpos < ret) { string type(buf + bufpos); bufpos += type.size() + 1; string name(buf + bufpos); bufpos += name.size() + 1; str_path.push_back(type); str_path.push_back(name); } path = env->NewObjectArray(str_path.size(), env->FindClass("java/lang/String"), NULL); if (!path) goto out; for (unsigned i = 0; i < str_path.size(); i++) { jstring ent = env->NewStringUTF(str_path[i].c_str()); if (!ent) goto out; env->SetObjectArrayElement(path, i, ent); if (env->ExceptionOccurred()) goto out; env->DeleteLocalRef(ent); } out: if (buf) delete [] buf; return path; } /* * sockaddrToInetAddress uses with the following license, and is adapted for * use in this project by using Ceph JNI exception utilities. * * ---- * * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ jobject sockaddrToInetAddress(JNIEnv* env, const sockaddr_storage& ss, jint* port) { // Convert IPv4-mapped IPv6 addresses to IPv4 addresses. // The RI states "Java will never return an IPv4-mapped address". const sockaddr_in6& sin6 = reinterpret_cast(ss); if (ss.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { // Copy the IPv6 address into the temporary sockaddr_storage. sockaddr_storage tmp; memset(&tmp, 0, sizeof(tmp)); memcpy(&tmp, &ss, sizeof(sockaddr_in6)); // Unmap it into an IPv4 address. sockaddr_in& sin = reinterpret_cast(tmp); sin.sin_family = AF_INET; sin.sin_port = sin6.sin6_port; memcpy(&sin.sin_addr.s_addr, &sin6.sin6_addr.s6_addr[12], 4); // Do the regular conversion using the unmapped address. return sockaddrToInetAddress(env, tmp, port); } const void* rawAddress; size_t addressLength; int sin_port = 0; int scope_id = 0; if (ss.ss_family == AF_INET) { const sockaddr_in& sin = reinterpret_cast(ss); rawAddress = &sin.sin_addr.s_addr; addressLength = 4; sin_port = ntohs(sin.sin_port); } else if (ss.ss_family == AF_INET6) { const sockaddr_in6& sin6 = reinterpret_cast(ss); rawAddress = &sin6.sin6_addr.s6_addr; addressLength = 16; sin_port = ntohs(sin6.sin6_port); scope_id = sin6.sin6_scope_id; } else if (ss.ss_family == AF_UNIX) { const sockaddr_un& sun = reinterpret_cast(ss); rawAddress = &sun.sun_path; addressLength = strlen(sun.sun_path); } else { // We can't throw SocketException. We aren't meant to see bad addresses, so seeing one // really does imply an internal error. //jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", // "sockaddrToInetAddress unsupported ss_family: %i", ss.ss_family); cephThrowIllegalArg(env, "sockaddrToInetAddress unsupposed ss_family"); return NULL; } if (port != NULL) { *port = sin_port; } ScopedLocalRef byteArray(env, env->NewByteArray(addressLength)); if (byteArray.get() == NULL) { return NULL; } env->SetByteArrayRegion(byteArray.get(), 0, addressLength, reinterpret_cast(const_cast(rawAddress))); if (ss.ss_family == AF_UNIX) { // Note that we get here for AF_UNIX sockets on accept(2). The unix(7) man page claims // that the peer's sun_path will contain the path, but in practice it doesn't, and the // peer length is returned as 2 (meaning only the sun_family field was set). // // Ceph Note: this isn't supported. inetUnixAddress appears to just be // something in Dalvik/Android stuff. cephThrowInternal(env, "OSD address should never be a UNIX socket"); return NULL; //static jmethodID ctor = env->GetMethodID(JniConstants::inetUnixAddressClass, "", "([B)V"); //return env->NewObject(JniConstants::inetUnixAddressClass, ctor, byteArray.get()); } if (addressLength == 4) { static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inetAddressClass, "getByAddress", "(Ljava/lang/String;[B)Ljava/net/InetAddress;"); if (getByAddressMethod == NULL) { return NULL; } return env->CallStaticObjectMethod(JniConstants::inetAddressClass, getByAddressMethod, NULL, byteArray.get()); } else if (addressLength == 16) { static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inet6AddressClass, "getByAddress", "(Ljava/lang/String;[BI)Ljava/net/Inet6Address;"); if (getByAddressMethod == NULL) { return NULL; } return env->CallStaticObjectMethod(JniConstants::inet6AddressClass, getByAddressMethod, NULL, byteArray.get(), scope_id); } else { abort(); return NULL; } } /* * Class: com_ceph_fs_CephMount * Method: native_ceph_get_osd_addr * Signature: (JI)Ljava/net/InetAddress; */ JNIEXPORT jobject JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1osd_1addr (JNIEnv *env, jclass clz, jlong j_mntp, jint osd) { struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); struct sockaddr_storage addr; int ret; CHECK_MOUNTED(cmount, NULL); ldout(cct, 10) << "jni: get_osd_addr: osd " << osd << dendl; ret = ceph_get_osd_addr(cmount, osd, &addr); ldout(cct, 10) << "jni: get_osd_addr: ret " << ret << dendl; if (ret < 0) { handle_error(env, ret); return NULL; } return sockaddrToInetAddress(env, addr, NULL); } ceph-0.80.11/src/java/java/0000775000175100017510000000000012623077037017322 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/java/com/0000775000175100017510000000000012623077037020100 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/java/com/ceph/0000775000175100017510000000000012623077037021017 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/java/com/ceph/crush/0000775000175100017510000000000012623077037022143 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/java/com/ceph/crush/Bucket.java0000664000175100017510000000265112623076744024233 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.crush; public class Bucket { private String type; private String name; public Bucket(String type, String name) { this.type = type; this.name = name; } public String getType() { return type; } public String getName() { return name; } public String toString() { return "bucket[" + type + "," + name + "]"; } } ceph-0.80.11/src/java/java/com/ceph/fs/0000775000175100017510000000000012623077037021427 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/java/com/ceph/fs/CephAlreadyMountedException.java0000664000175100017510000000277712623076744027707 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.IOException; /** * Ceph is already mounted. */ public class CephAlreadyMountedException extends IOException { private static final long serialVersionUID = 1L; /** * Construct CephAlreadyMountedException. */ public CephAlreadyMountedException() { super(); } /** * Construct CephAlreadyMountedException with message. */ public CephAlreadyMountedException(String s) { super(s); } } ceph-0.80.11/src/java/java/com/ceph/fs/CephPoolException.java0000664000175100017510000000272412623076744025673 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.IOException; /** * Exception related to Ceph pool. */ public class CephPoolException extends IOException { private static final long serialVersionUID = 1L; /** * Construct CephPoolException. */ public CephPoolException() { super(); } /** * Construct CephPoolException with message. */ public CephPoolException(String s) { super(s); } } ceph-0.80.11/src/java/java/com/ceph/fs/CephNotDirectoryException.java0000664000175100017510000000300212623076744027375 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.IOException; /** * Component of path is not a directory. */ public class CephNotDirectoryException extends IOException { private static final long serialVersionUID = 1L; /** * Construct CephNotDirectoryException. */ public CephNotDirectoryException() { super(); } /** * Construct CephNotDirectoryException with message. */ public CephNotDirectoryException(String s) { super(s); } } ceph-0.80.11/src/java/java/com/ceph/fs/CephStatVFS.java0000664000175100017510000000245112623076744024372 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; /** * Holds struct statvfs fields. */ public class CephStatVFS { public long bsize; public long frsize; public long blocks; public long bavail; public long files; public long fsid; public long namemax; } ceph-0.80.11/src/java/java/com/ceph/fs/CephNativeLoader.java0000664000175100017510000000251612623076744025457 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; class CephNativeLoader { private static boolean loaded = false; static { if (!loaded) { System.loadLibrary("cephfs_jni"); CephMount.native_initialize(); loaded = true; } } static void checkLoaded() { assert(loaded); } } ceph-0.80.11/src/java/java/com/ceph/fs/CephFileAlreadyExistsException.java0000664000175100017510000000303112623076744030333 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.IOException; /** * Ceph file/directory already exists. */ public class CephFileAlreadyExistsException extends IOException { private static final long serialVersionUID = 1L; /** * Construct CephFileAlreadyExistsException. */ public CephFileAlreadyExistsException() { super(); } /** * Construct CephFileAlreadyExistsException with message. */ public CephFileAlreadyExistsException(String s) { super(s); } } ceph-0.80.11/src/java/java/com/ceph/fs/CephMount.java0000664000175100017510000006645612623076744024221 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.IOException; import java.io.FileNotFoundException; import java.net.InetAddress; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.lang.String; import com.ceph.crush.Bucket; public class CephMount { /* * Set via JNI callback in native_ceph_create * * Do not touch! */ private long instance_ptr; /* * Flags for open(). * * Must be synchronized with JNI if changed. */ public static final int O_RDONLY = 1; public static final int O_RDWR = 2; public static final int O_APPEND = 4; public static final int O_CREAT = 8; public static final int O_TRUNC = 16; public static final int O_EXCL = 32; public static final int O_WRONLY = 64; /* * Whence flags for seek(). * * Must be synchronized with JNI if changed. */ public static final int SEEK_SET = 1; public static final int SEEK_CUR = 2; public static final int SEEK_END = 3; /* * Attribute flags for setattr(). * * Must be synchronized with JNI if changed. */ public static final int SETATTR_MODE = 1; public static final int SETATTR_UID = 2; public static final int SETATTR_GID = 4; public static final int SETATTR_MTIME = 8; public static final int SETATTR_ATIME = 16; /* * Flags for setxattr(); * * Must be synchronized with JNI if changed. */ public static final int XATTR_CREATE = 1; public static final int XATTR_REPLACE = 2; public static final int XATTR_NONE = 3; /* * This is run by the class loader and will report early any problems * finding or linking in the shared JNI library. */ static { CephNativeLoader.checkLoaded(); } /* * Package-private: called from CephNativeLoader */ static native void native_initialize(); /* * RW lock used for fine grained synchronization to native */ private final ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock(); private final Lock rlock = rwlock.readLock(); private final Lock wlock = rwlock.writeLock(); /* * Controls clean-up synchronization between the constructor and finalize(). * If native_ceph_create fails, then we want a call to finalize() to not * attempt to clean-up native context, because there is none. */ private boolean initialized = false; /* * Try to clean-up. First, unmount() will catch users who forget to do the * unmount manually. Second, release() will destroy the entire context. It * is safe to call release after a failure in unmount. */ protected void finalize() throws Throwable { if (initialized) { try { unmount(); } catch (Exception e) {} try { native_ceph_release(instance_ptr); } catch (Exception e) {} } super.finalize(); } /** * Create a new CephMount with specific client id. * * @param id client id. */ public CephMount(String id) { native_ceph_create(this, id); initialized = true; } private static native int native_ceph_create(CephMount mount, String id); /** * Create a new CephMount with default client id. */ public CephMount() { this(null); } /** * Activate the mount with a given root path. * * @param root The path to use as the root (pass null for "/"). */ public void mount(String root) { wlock.lock(); try { native_ceph_mount(instance_ptr, root); } finally { wlock.unlock(); } } private static native int native_ceph_mount(long mountp, String root); /** * Deactivate the mount. * * The mount can be reactivated using mount(). Configuration parameters * previously set are not reset. */ public void unmount() { wlock.lock(); try { native_ceph_unmount(instance_ptr); } finally { wlock.unlock(); } } private static native int native_ceph_unmount(long mountp); /* * Private access to low-level ceph_release. */ private static native int native_ceph_release(long mountp); /** * Load configuration from a file. * * @param path The path to the configuration file. */ public void conf_read_file(String path) throws FileNotFoundException { rlock.lock(); try { native_ceph_conf_read_file(instance_ptr, path); } finally { rlock.unlock(); } } private static native int native_ceph_conf_read_file(long mountp, String path); /** * Set the value of a configuration option. * * @param option The configuration option to modify. * @param value The new value of the option. */ public void conf_set(String option, String value) { rlock.lock(); try { native_ceph_conf_set(instance_ptr, option, value); } finally { rlock.unlock(); } } private static native int native_ceph_conf_set(long mountp, String option, String value); /** * Get the value of a configuration option. * * @param option The name of the configuration option. * @return The value of the option or null if option not found */ public String conf_get(String option) { rlock.lock(); try { return native_ceph_conf_get(instance_ptr, option); } finally { rlock.unlock(); } } private static native String native_ceph_conf_get(long mountp, String option); /** * Get file system status. * * @param path Path to file in file system. * @param statvfs CephStatVFS structure to hold status. */ public void statfs(String path, CephStatVFS statvfs) throws FileNotFoundException { rlock.lock(); try { native_ceph_statfs(instance_ptr, path, statvfs); } finally { rlock.unlock(); } } private static native int native_ceph_statfs(long mountp, String path, CephStatVFS statvfs); /** * Get the current working directory. * * @return The current working directory in Ceph. */ public String getcwd() { rlock.lock(); try { return native_ceph_getcwd(instance_ptr); } finally { rlock.unlock(); } } private static native String native_ceph_getcwd(long mountp); /** * Set the current working directory. * * @param path The directory set as the cwd. */ public void chdir(String path) throws FileNotFoundException { rlock.lock(); try { native_ceph_chdir(instance_ptr, path); } finally { rlock.unlock(); } } private static native int native_ceph_chdir(long mountp, String cwd); /** * List the contents of a directory. * * @param dir The directory. * @return List of files and directories excluding "." and "..". */ public String[] listdir(String dir) throws FileNotFoundException { rlock.lock(); try { return native_ceph_listdir(instance_ptr, dir); } finally { rlock.unlock(); } } private static native String[] native_ceph_listdir(long mountp, String path); /** * Create a hard link to an existing file. * * @param oldpath The target path of the link. * @param newpath The name of the link. */ public void link(String oldpath, String newpath) throws FileNotFoundException { rlock.lock(); try { native_ceph_link(instance_ptr, oldpath, newpath); } finally { rlock.unlock(); } } private static native int native_ceph_link(long mountp, String existing, String newname); /** * Unlink/delete a name from the file system. * * @param path The name to unlink/delete. */ public void unlink(String path) throws FileNotFoundException { rlock.lock(); try { native_ceph_unlink(instance_ptr, path); } finally { rlock.unlock(); } } private static native int native_ceph_unlink(long mountp, String path); /** * Rename a file or directory. * * @param from The current path. * @param to The new path. */ public void rename(String from, String to) throws FileNotFoundException { rlock.lock(); try { native_ceph_rename(instance_ptr, from, to); } finally { rlock.unlock(); } } private static native int native_ceph_rename(long mountp, String from, String to); /** * Create a directory. * * @param path The directory to create. * @param mode The mode of the new directory. */ public void mkdir(String path, int mode) { rlock.lock(); try { native_ceph_mkdir(instance_ptr, path, mode); } finally { rlock.unlock(); } } private static native int native_ceph_mkdir(long mountp, String path, int mode); /** * Create a directory and all parents. * * @param path The directory to create. * @param mode The mode of the new directory. */ public void mkdirs(String path, int mode) throws IOException { rlock.lock(); try { native_ceph_mkdirs(instance_ptr, path, mode); } finally { rlock.unlock(); } } private static native int native_ceph_mkdirs(long mountp, String path, int mode); /** * Delete a directory. * * @param path The directory to delete. */ public void rmdir(String path) throws FileNotFoundException { rlock.lock(); try { native_ceph_rmdir(instance_ptr, path); } finally { rlock.unlock(); } } private static native int native_ceph_rmdir(long mountp, String path); /** * Read the value of a symbolic link. */ public String readlink(String path) throws FileNotFoundException { rlock.lock(); try { return native_ceph_readlink(instance_ptr, path); } finally { rlock.unlock(); } } private static native String native_ceph_readlink(long mountp, String path); /** * Create a symbolic link. * * @param oldpath Target of the symbolic link. * @param newpath Name of the link. */ public void symlink(String oldpath, String newpath) { rlock.lock(); try { native_ceph_symlink(instance_ptr, oldpath, newpath); } finally { rlock.unlock(); } } private static native int native_ceph_symlink(long mountp, String existing, String newname); /** * Get file status. * * @param path Path of file to stat. * @param stat CephStat structure to hold file status. */ public void stat(String path, CephStat stat) throws FileNotFoundException, CephNotDirectoryException { rlock.lock(); try { native_ceph_stat(instance_ptr, path, stat); } finally { rlock.unlock(); } } private static native int native_ceph_stat(long mountp, String path, CephStat stat); /** * Get file status, without following symlinks. * * @param path Path of file to stat. * @param stat CephStat structure to hold file status. */ public void lstat(String path, CephStat stat) throws FileNotFoundException, CephNotDirectoryException { rlock.lock(); try { native_ceph_lstat(instance_ptr, path, stat); } finally { rlock.unlock(); } } private static native int native_ceph_lstat(long mountp, String path, CephStat stat); /** * Set file attributes. * * @param path Path to file. * @param stat CephStat structure holding attributes. * @param mask Mask specifying which attributes to set. */ public void setattr(String path, CephStat stat, int mask) throws FileNotFoundException { rlock.lock(); try { native_ceph_setattr(instance_ptr, path, stat, mask); } finally { rlock.unlock(); } } private static native int native_ceph_setattr(long mountp, String relpath, CephStat stat, int mask); /** * Change file mode. * * @param path Path to file. * @param mode New mode bits. */ public void chmod(String path, int mode) throws FileNotFoundException { rlock.lock(); try { native_ceph_chmod(instance_ptr, path, mode); } finally { rlock.unlock(); } } private static native int native_ceph_chmod(long mountp, String path, int mode); /** * Change file mode of an open file. * * @param fd The open file descriptor to change the mode bits on. * @param mode New mode bits. */ public void fchmod(int fd, int mode) { rlock.lock(); try { native_ceph_fchmod(instance_ptr, fd, mode); } finally { rlock.unlock(); } } private static native int native_ceph_fchmod(long mountp, int fd, int mode); /** * Truncate a file to a specified length. * * @param path Path of the file. * @param size New file length. */ public void truncate(String path, long size) throws FileNotFoundException { rlock.lock(); try { native_ceph_truncate(instance_ptr, path, size); } finally { rlock.unlock(); } } private static native int native_ceph_truncate(long mountp, String path, long size); /** * Open a file. * * @param path Path of file to open or create. * @param flags Open flags. * @param mode Permission mode. * @return File descriptor. */ public int open(String path, int flags, int mode) throws FileNotFoundException { rlock.lock(); try { return native_ceph_open(instance_ptr, path, flags, mode); } finally { rlock.unlock(); } } private static native int native_ceph_open(long mountp, String path, int flags, int mode); /** * Open a file with a specific file layout. * * @param path Path of file to open or create. * @param flags Open flags. * @param mode Permission mode. * @param stripe_unit File layout stripe unit size. * @param stripe_count File layout stripe count. * @param object_size Size of each object. * @param data_pool The target data pool. * @return File descriptor. */ public int open(String path, int flags, int mode, int stripe_unit, int stripe_count, int object_size, String data_pool) throws FileNotFoundException { rlock.lock(); try { return native_ceph_open_layout(instance_ptr, path, flags, mode, stripe_unit, stripe_count, object_size, data_pool); } finally { rlock.unlock(); } } private static native int native_ceph_open_layout(long mountp, String path, int flags, int mode, int stripe_unit, int stripe_count, int object_size, String data_pool); /** * Close an open file. * * @param fd The file descriptor. */ public void close(int fd) { rlock.lock(); try { native_ceph_close(instance_ptr, fd); } finally { rlock.unlock(); } } private static native int native_ceph_close(long mountp, int fd); /** * Seek to a position in a file. * * @param fd File descriptor. * @param offset New offset. * @param whence Whence value. * @return The new offset. */ public long lseek(int fd, long offset, int whence) { rlock.lock(); try { return native_ceph_lseek(instance_ptr, fd, offset, whence); } finally { rlock.unlock(); } } private static native long native_ceph_lseek(long mountp, int fd, long offset, int whence); /** * Read from a file. * * @param fd The file descriptor. * @param buf Buffer to for data read. * @param size Amount of data to read into the buffer. * @param offset Offset to read from (-1 for current position). * @return The number of bytes read. */ public long read(int fd, byte[] buf, long size, long offset) { rlock.lock(); try { return native_ceph_read(instance_ptr, fd, buf, size, offset); } finally { rlock.unlock(); } } private static native long native_ceph_read(long mountp, int fd, byte[] buf, long size, long offset); /** * Write to a file at a specific offset. * * @param fd The file descriptor. * @param buf Buffer to write. * @param size Amount of data to write. * @param offset Offset to write from (-1 for current position). * @return The number of bytes written. */ public long write(int fd, byte[] buf, long size, long offset) { rlock.lock(); try { return native_ceph_write(instance_ptr, fd, buf, size, offset); } finally { rlock.unlock(); } } private static native long native_ceph_write(long mountp, int fd, byte[] buf, long size, long offset); /** * Truncate a file. * * @param fd File descriptor of the file to truncate. * @param size New file size. */ public void ftruncate(int fd, long size) { rlock.lock(); try { native_ceph_ftruncate(instance_ptr, fd, size); } finally { rlock.unlock(); } } private static native int native_ceph_ftruncate(long mountp, int fd, long size); /** * Synchronize a file with the file system. * * @param fd File descriptor to synchronize. * @param dataonly Synchronize only data. */ public void fsync(int fd, boolean dataonly) { rlock.lock(); try { native_ceph_fsync(instance_ptr, fd, dataonly); } finally { rlock.unlock(); } } private static native int native_ceph_fsync(long mountp, int fd, boolean dataonly); /** * Get file status. * * @param fd The file descriptor. * @param stat The object in which to store the status. */ public void fstat(int fd, CephStat stat) { rlock.lock(); try { native_ceph_fstat(instance_ptr, fd, stat); } finally { rlock.unlock(); } } private static native int native_ceph_fstat(long mountp, int fd, CephStat stat); /** * Synchronize the client with the file system. */ public void sync_fs() { rlock.lock(); try { native_ceph_sync_fs(instance_ptr); } finally { rlock.unlock(); } } private static native int native_ceph_sync_fs(long mountp); /** * Get an extended attribute value. * * If the buffer is large enough to hold the entire attribute value, or * buf is null, the size of the value is returned. * * @param path File path. * @param name Name of the attribute. * @param buf Buffer to store attribute value. * @return The length of the attribute value. See description for more * details. */ public long getxattr(String path, String name, byte[] buf) throws FileNotFoundException { rlock.lock(); try { return native_ceph_getxattr(instance_ptr, path, name, buf); } finally { rlock.unlock(); } } private static native long native_ceph_getxattr(long mountp, String path, String name, byte[] buf); /** * Get an extended attribute value of a symbolic link. * * If the buffer is large enough to hold the entire attribute value, or * buf is null, the size of the value is returned. * * @param path File path. * @param name Name of attribute. * @param buf Buffer to store attribute value. * @return The length of the attribute value. See description for more * details. */ public long lgetxattr(String path, String name, byte[] buf) throws FileNotFoundException { rlock.lock(); try { return native_ceph_lgetxattr(instance_ptr, path, name, buf); } finally { rlock.unlock(); } } private static native long native_ceph_lgetxattr(long mountp, String path, String name, byte[] buf); /** * List extended attributes. * * @param path File path. * @return List of attribute names. */ public String[] listxattr(String path) throws FileNotFoundException { rlock.lock(); try { return native_ceph_listxattr(instance_ptr, path); } finally { rlock.unlock(); } } private static native String[] native_ceph_listxattr(long mountp, String path); /** * List extended attributes of a symbolic link. * * @param path File path. * @return List of attribute names. */ public String[] llistxattr(String path) throws FileNotFoundException { rlock.lock(); try { return native_ceph_llistxattr(instance_ptr, path); } finally { rlock.unlock(); } } private static native String[] native_ceph_llistxattr(long mountp, String path); /** * Remove an extended attribute. * * @param path File path. * @param name Name of attribute. */ public void removexattr(String path, String name) throws FileNotFoundException { rlock.lock(); try { native_ceph_removexattr(instance_ptr, path, name); } finally { rlock.unlock(); } } private static native int native_ceph_removexattr(long mountp, String path, String name); /** * Remove an extended attribute from a symbolic link. * * @param path File path. * @param name Name of attribute. */ public void lremovexattr(String path, String name) throws FileNotFoundException { rlock.lock(); try { native_ceph_lremovexattr(instance_ptr, path, name); } finally { rlock.unlock(); } } private static native int native_ceph_lremovexattr(long mountp, String path, String name); /** * Set the value of an extended attribute. * * @param path The file path. * @param name The attribute name. * @param buf The attribute value. * @param size The size of the attribute value. * @param flags Flag controlling behavior (XATTR_CREATE/REPLACE/NONE). */ public void setxattr(String path, String name, byte[] buf, long size, int flags) throws FileNotFoundException { rlock.lock(); try { native_ceph_setxattr(instance_ptr, path, name, buf, size, flags); } finally { rlock.unlock(); } } private static native int native_ceph_setxattr(long mountp, String path, String name, byte[] buf, long size, int flags); /** * Set the value of an extended attribute on a symbolic link. * * @param path The file path. * @param name The attribute name. * @param buf The attribute value. * @param size The size of the attribute value. * @param flags Flag controlling behavior (XATTR_CREATE/REPLACE/NONE). */ public void lsetxattr(String path, String name, byte[] buf, long size, int flags) throws FileNotFoundException { rlock.lock(); try { native_ceph_lsetxattr(instance_ptr, path, name, buf, size, flags); } finally { rlock.unlock(); } } private static native int native_ceph_lsetxattr(long mountp, String path, String name, byte[] buf, long size, int flags); /** * Get the stripe unit of a file. * * @param fd The file descriptor. * @return The stripe unit. */ public int get_file_stripe_unit(int fd) { rlock.lock(); try { return native_ceph_get_file_stripe_unit(instance_ptr, fd); } finally { rlock.unlock(); } } private static native int native_ceph_get_file_stripe_unit(long mountp, int fd); /** * Get the name of the pool a file is stored in. * * @param fd An open file descriptor. * @return The pool name. */ public String get_file_pool_name(int fd) { rlock.lock(); try { return native_ceph_get_file_pool_name(instance_ptr, fd); } finally { rlock.unlock(); } } private static native String native_ceph_get_file_pool_name(long mountp, int fd); /** * Get the replication of a file. * * @param fd The file descriptor. * @return The file replication. */ public int get_file_replication(int fd) { rlock.lock(); try { return native_ceph_get_file_replication(instance_ptr, fd); } finally { rlock.unlock(); } } private static native int native_ceph_get_file_replication(long mountp, int fd); /** * Favor reading from local replicas when possible. * * @param state Enable or disable localized reads. */ public void localize_reads(boolean state) { rlock.lock(); try { native_ceph_localize_reads(instance_ptr, state); } finally { rlock.unlock(); } } private static native int native_ceph_localize_reads(long mountp, boolean on); /** * Get file layout stripe unit granularity. * * @return Stripe unit granularity. */ public int get_stripe_unit_granularity() { rlock.lock(); try { return native_ceph_get_stripe_unit_granularity(instance_ptr); } finally { rlock.unlock(); } } private static native int native_ceph_get_stripe_unit_granularity(long mountp); /** * Get the pool id for the named pool. * * @param name The pool name. * @return The pool id. */ public int get_pool_id(String name) throws CephPoolException { rlock.lock(); try { return native_ceph_get_pool_id(instance_ptr, name); } catch (FileNotFoundException e) { throw new CephPoolException("pool name " + name + " not found"); } finally { rlock.unlock(); } } private static native int native_ceph_get_pool_id(long mountp, String name) throws FileNotFoundException; /** * Get the pool replication factor. * * @param pool_id The pool id. * @return Number of replicas stored in the pool. */ public int get_pool_replication(int pool_id) throws CephPoolException { rlock.lock(); try { return native_ceph_get_pool_replication(instance_ptr, pool_id); } catch (FileNotFoundException e) { throw new CephPoolException("pool id " + pool_id + " not found"); } finally { rlock.unlock(); } } private static native int native_ceph_get_pool_replication(long mountp, int pool_id) throws FileNotFoundException; /** * Get file extent containing a given offset. * * @param fd The file descriptor. * @param offset Offset in file. * @return A CephFileExtent object. */ public CephFileExtent get_file_extent(int fd, long offset) { rlock.lock(); try { return native_ceph_get_file_extent_osds(instance_ptr, fd, offset); } finally { rlock.unlock(); } } private static native CephFileExtent native_ceph_get_file_extent_osds(long mountp, int fd, long offset); /** * Get the fully qualified CRUSH location of an OSD. * * Returns (type, name) string pairs for each device in the CRUSH bucket * hierarchy starting from the given OSD to the root. * * @param osd The OSD device id. * @return List of pairs. */ public Bucket[] get_osd_crush_location(int osd) { rlock.lock(); try { String[] parts = native_ceph_get_osd_crush_location(instance_ptr, osd); Bucket[] path = new Bucket[parts.length / 2]; for (int i = 0; i < path.length; i++) path[i] = new Bucket(parts[i*2], parts[i*2+1]); return path; } finally { rlock.unlock(); } } private static native String[] native_ceph_get_osd_crush_location(long mountp, int osd); /** * Get the network address of an OSD. * * @param osd The OSD device id. * @return The network address. */ public InetAddress get_osd_address(int osd) { rlock.lock(); try { return native_ceph_get_osd_addr(instance_ptr, osd); } finally { rlock.unlock(); } } private static native InetAddress native_ceph_get_osd_addr(long mountp, int osd); } ceph-0.80.11/src/java/java/com/ceph/fs/CephNotMountedException.java0000664000175100017510000000274712623076744027063 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.IOException; /** * Ceph is not mounted. */ public class CephNotMountedException extends IOException { private static final long serialVersionUID = 1L; /** * Construct CephNotMountedException. */ public CephNotMountedException() { super(); } /** * Construct CephNotMountedException with message. */ public CephNotMountedException(String s) { super(s); } } ceph-0.80.11/src/java/java/com/ceph/fs/CephFileExtent.java0000664000175100017510000000351412623076744025150 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.util.Arrays; /** * Holds information about a file extent in CephFS. */ public class CephFileExtent { private long offset; private long length; private int[] osds; CephFileExtent(long offset, long length, int[] osds) { this.offset = offset; this.length = length; this.osds = osds; } /** * Get starting offset of extent. */ public long getOffset() { return offset; } /** * Get length of extent. */ public long getLength() { return length; } /** * Get list of OSDs with this extent. */ public int[] getOSDs() { return osds; } /** * Pretty print. */ public String toString() { return "extent[" + offset + "," + length + "," + Arrays.toString(osds) + "]"; } } ceph-0.80.11/src/java/java/com/ceph/fs/CephStat.java0000664000175100017510000000320112623076744024005 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; /** * Holds struct stat fields. */ public class CephStat { /* Set from native */ private boolean is_file; /* S_ISREG */ private boolean is_directory; /* S_ISDIR */ private boolean is_symlink; /* S_ISLNK */ public int mode; public int uid; public int gid; public long size; public long blksize; public long blocks; public long a_time; public long m_time; public boolean isFile() { return is_file; } public boolean isDir() { return is_directory; } public boolean isSymlink() { return is_symlink; } } ceph-0.80.11/src/java/Makefile.am0000664000175100017510000000474712623076744020455 0ustar jenkins-buildjenkins-build# automake technique adapted from OpenMPI Java JAVA_SRC = \ java/com/ceph/fs/CephMount.java \ java/com/ceph/fs/CephStat.java \ java/com/ceph/fs/CephStatVFS.java \ java/com/ceph/fs/CephNativeLoader.java \ java/com/ceph/fs/CephNotMountedException.java \ java/com/ceph/fs/CephFileAlreadyExistsException.java \ java/com/ceph/fs/CephAlreadyMountedException.java \ java/com/ceph/fs/CephNotDirectoryException.java \ java/com/ceph/fs/CephPoolException.java \ java/com/ceph/fs/CephFileExtent.java \ java/com/ceph/crush/Bucket.java JAVA_TEST_SRC = \ test/com/ceph/fs/CephDoubleMountTest.java \ test/com/ceph/fs/CephMountCreateTest.java \ test/com/ceph/fs/CephMountTest.java \ test/com/ceph/fs/CephUnmountedTest.java \ test/com/ceph/fs/CephAllTests.java EXTRA_DIST = $(JAVA_SRC) $(JAVA_TEST_SRC) if ENABLE_CEPHFS_JAVA JAVA_CLASSES = $(JAVA_SRC:java/%.java=%.class) # This is dumb -- It might be better to split some work # between Make and Ant or Maven #ESCAPED_JAVA_CLASSES = \ # com/ceph/fs/CephMount\$$State.class JAVA_H = native/com_ceph_fs_CephMount.h # target to make automake happy CEPH_PROXY=java/com/ceph/fs/CephMount.class # note: for the -source 1.5 builds, we add # -Xlint:-options # to get rid of the warning # warning: [options] bootstrap class path not set in conjunction with -source 1.5 # as per # https://blogs.oracle.com/darcy/entry/bootclasspath_older_source $(CEPH_PROXY): $(JAVA_SRC) export CLASSPATH=java/ ; \ $(JAVAC) -classpath java -source 1.5 -target 1.5 -Xlint:-options java/com/ceph/fs/*.java $(JAVA_H): $(CEPH_PROXY) export CLASSPATH=java/ ; \ $(JAVAH) -classpath java -jni -o $@ com.ceph.fs.CephMount libcephfs.jar: $(CEPH_PROXY) $(JAR) cf $@ $(JAVA_CLASSES:%=-C java %) javadir = $(datadir)/java java_DATA = libcephfs.jar CLEANFILES = -rf java/com/ceph/fs/*.class $(JAVA_H) libcephfs.jar BUILT_SOURCES = $(JAVA_H) # build the tests if *both* --enable-cephfs-java and --with-debug were specifed if HAVE_JUNIT4 JAVA_TEST_CLASSES = $(JAVA_TEST_SRC:test/%.java=%.class) CEPH_TEST_PROXY=test/com/ceph/fs/CephMountTest.class $(CEPH_TEST_PROXY): $(JAVA_TEST_SRC) $(CEPH_PROXY) export CLASSPATH=$(CLASSPATH):$(EXTRA_CLASSPATH_JAR):java/:test/ ; \ $(JAVAC) -source 1.5 -target 1.5 -Xlint:-options test/com/ceph/fs/*.java libcephfs-test.jar: $(CEPH_TEST_PROXY) $(JAR) cf $@ $(JAVA_TEST_CLASSES:%=-C test %) java_DATA += libcephfs-test.jar CLEANFILES += test/com/ceph/fs/*.class libcephfs-test.jar endif # HAVE_JUNIT4 (includes WITH_DEBUG) endif #ENABLE_CEPHFS_JAVA ceph-0.80.11/src/java/test/0000775000175100017510000000000012623077037017360 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/test/com/0000775000175100017510000000000012623077037020136 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/test/com/ceph/0000775000175100017510000000000012623077037021055 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/test/com/ceph/fs/0000775000175100017510000000000012623077037021465 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/java/test/com/ceph/fs/CephDoubleMountTest.java0000664000175100017510000000320612623076744026232 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.FileNotFoundException; import java.io.IOException; import java.util.UUID; import org.junit.*; import static org.junit.Assert.*; public class CephDoubleMountTest { @Test(expected=CephAlreadyMountedException.class) public void test_double_mount() throws Exception { CephMount mount = new CephMount("admin"); String conf_file = System.getProperty("CEPH_CONF_FILE"); if (conf_file != null) mount.conf_read_file(conf_file); mount.mount(null); try { mount.mount(null); } finally { mount.unmount(); } } } ceph-0.80.11/src/java/test/com/ceph/fs/CephAllTests.java0000664000175100017510000000310112623076744024662 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.FileNotFoundException; import java.io.IOException; import java.util.UUID; import org.junit.*; import org.junit.runners.Suite; import org.junit.runner.RunWith; import static org.junit.Assert.*; @RunWith( Suite.class ) @Suite.SuiteClasses( { CephDoubleMountTest.class, CephMountCreateTest.class, CephMountTest.class, CephUnmountedTest.class, }) /** * Every Java test class must be added to this list in order to be executed with 'ant test' */ public class CephAllTests{ } ceph-0.80.11/src/java/test/com/ceph/fs/CephUnmountedTest.java0000664000175100017510000001140512623076744025753 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import org.junit.*; import static org.junit.Assert.*; public class CephUnmountedTest { private CephMount mount; @Before public void setup() throws Exception { mount = new CephMount("admin"); } @Test(expected=CephNotMountedException.class) public void test_unmount() throws Exception { mount.unmount(); } @Test(expected=CephNotMountedException.class) public void test_statfs() throws Exception { CephStatVFS stat = new CephStatVFS(); mount.statfs("/a/path", stat); } @Test(expected=CephNotMountedException.class) public void test_getcwd() throws Exception { mount.getcwd(); } @Test(expected=CephNotMountedException.class) public void test_chdir() throws Exception { mount.chdir("/a/path"); } @Test(expected=CephNotMountedException.class) public void test_listdir() throws Exception { mount.listdir("/a/path"); } @Test(expected=CephNotMountedException.class) public void test_unlink() throws Exception { mount.unlink("/a/path"); } @Test(expected=CephNotMountedException.class) public void test_rename() throws Exception { mount.rename("/a/path", "/another/path"); } @Test(expected=CephNotMountedException.class) public void test_mkdirs() throws Exception { mount.mkdirs("/a/path", 0); } @Test(expected=CephNotMountedException.class) public void test_rmdir() throws Exception { mount.rmdir("/a/path"); } @Test(expected=CephNotMountedException.class) public void test_stat() throws Exception { CephStat stat = new CephStat(); mount.stat("/a/path", stat); } @Test(expected=CephNotMountedException.class) public void test_lstat() throws Exception { CephStat stat = new CephStat(); mount.lstat("/a/path", stat); } @Test(expected=CephNotMountedException.class) public void test_setattr() throws Exception { CephStat stat = new CephStat(); mount.setattr("/a/path", stat, 0); } @Test(expected=CephNotMountedException.class) public void test_open() throws Exception { mount.open("/a/path", 0, 0); } @Test(expected=CephNotMountedException.class) public void test_open_layout() throws Exception { mount.open("/a/path", 0, 0, 0, 0, 0, null); } @Test(expected=CephNotMountedException.class) public void test_close() throws Exception { mount.close(0); } @Test(expected=CephNotMountedException.class) public void test_lseek() throws Exception { mount.lseek(0, 0, CephMount.SEEK_CUR); } @Test(expected=CephNotMountedException.class) public void test_read() throws Exception { byte[] buf = new byte[1]; mount.read(0, buf, 1, 0); } @Test(expected=CephNotMountedException.class) public void test_write() throws Exception { byte[] buf = new byte[1]; mount.write(0, buf, 1, 0); } @Test(expected=CephNotMountedException.class) public void test_get_stripe_unit() throws Exception { mount.get_file_stripe_unit(0); } @Test(expected=CephNotMountedException.class) public void test_get_repl() throws Exception { mount.get_file_replication(0); } @Test(expected=CephNotMountedException.class) public void test_get_stripe_unit_gran() throws Exception { mount.get_stripe_unit_granularity(); } @Test(expected=CephNotMountedException.class) public void test_get_pool_id() throws Exception { mount.get_pool_id("data"); } @Test(expected=CephNotMountedException.class) public void test_get_pool_replication() throws Exception { mount.get_pool_replication(1); } @Test(expected=CephNotMountedException.class) public void test_fchmod() throws Exception { mount.fchmod(1, 0); } @Test(expected=CephNotMountedException.class) public void test_chmod() throws Exception { mount.chmod("/foo", 0); } } ceph-0.80.11/src/java/test/com/ceph/fs/CephMountCreateTest.java0000664000175100017510000000544112623076744026226 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.FileNotFoundException; import org.junit.*; import java.util.UUID; import static org.junit.Assert.*; /* * This tests the mount root dir functionality. It creates an empty * directory in the real root, then it re-mounts the file system * with the empty directory specified as the root. Assertions are * that the "/" in the normal mount is non-empty, and that "/" is * empty in the mount with the empty directory as the root. */ public class CephMountCreateTest { private static String conf_file; @BeforeClass public static void class_setup() throws Exception { conf_file = System.getProperty("CEPH_CONF_FILE"); } private CephMount setupMount(String root) throws Exception { CephMount mount = new CephMount("admin"); if (conf_file != null) mount.conf_read_file(conf_file); mount.mount(root); return mount; } @Test public void test_CephMountCreate() throws Exception { CephMount mount; boolean found; String dir = "libcephfs_junit_" + UUID.randomUUID(); /* root dir has more than one dir */ mount = setupMount("/"); try { mount.rmdir("/" + dir); } catch (FileNotFoundException e) {} mount.mkdirs("/" + dir, 777); String[] subdirs = mount.listdir("/"); found = false; for (String d : subdirs) { if (d.compareTo(dir) == 0) found = true; } assertTrue(found); mount.unmount(); /* changing root to empty dir */ mount = setupMount("/" + dir); subdirs = mount.listdir("/"); found = false; for (String d : subdirs) { found = true; } assertFalse(found); mount.unmount(); /* cleanup */ mount = setupMount("/"); mount.rmdir("/" + dir); mount.unmount(); } } ceph-0.80.11/src/java/test/com/ceph/fs/CephMountTest.java0000664000175100017510000006044112623076744025103 0ustar jenkins-buildjenkins-build/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.ceph.fs; import java.io.FileNotFoundException; import java.io.IOException; import java.net.InetAddress; import java.util.UUID; import org.junit.*; import static org.junit.Assert.*; import com.ceph.crush.Bucket; /* * Coverage * - Everything is covered in at least success cases. * - l[set,get,remove]xattr are not working */ public class CephMountTest { private static CephMount mount; private static String basedir = null; @BeforeClass public static void setup() throws Exception { mount = new CephMount("admin"); String conf_file = System.getProperty("CEPH_CONF_FILE"); if (conf_file != null) mount.conf_read_file(conf_file); mount.mount(null); basedir = "/libcephfs_junit_" + UUID.randomUUID(); mount.mkdir(basedir, 0777); } @AfterClass public static void destroy() throws Exception { String[] list = mount.listdir(basedir); for (String l : list) System.out.println(l); mount.rmdir(basedir); mount.unmount(); } /* * Helper function to construct a unique path. */ public String makePath() { String path = basedir + "/" + UUID.randomUUID(); return path; } /* * Helper function to create a file with the given path and size. The file * is filled with size bytes and the file descriptor is returned. */ public int createFile(String path, int size) throws Exception { int fd = mount.open(path, CephMount.O_RDWR|CephMount.O_CREAT, 0600); byte[] buf = new byte[4096]; int left = size; while (left > 0) { size = Math.min(buf.length, left); long ret = mount.write(fd, buf, size, -1); left -= ret; } return fd; } /* * Helper function to create a unique file and fill it with size bytes. The * file descriptor is returned. */ public int createFile(int size) throws Exception { return createFile(makePath(), size); } @Test(expected=FileNotFoundException.class) public void test_mount_dne() throws Exception { CephMount mount2 = new CephMount("admin"); String conf_file = System.getProperty("CEPH_CONF_FILE"); if (conf_file != null) mount2.conf_read_file(conf_file); mount2.mount("/wlfkjwlekfjwlejfwe"); mount2.unmount(); } /* * Test loading of conf file that doesn't exist. * * FIXME: * Ceph returns -ENOSYS rather than -ENOENT. Correct? */ //@Test(expected=FileNotFoundException.class) @Test public void test_conf_read_file_dne() throws Exception { //mount.conf_read_file("/this_file_does_not_exist"); } /* * Test loading of conf file that isn't valid * * FIXME: implement */ @Test public void test_conf_read_file_invalid() throws Exception { } @Test(expected=NullPointerException.class) public void test_conf_read_file_null() throws Exception { mount.conf_read_file(null); } /* * conf_set/conf_get */ @Test(expected=NullPointerException.class) public void test_conf_set_null_opt() throws Exception { mount.conf_set(null, "value"); } @Test(expected=NullPointerException.class) public void test_conf_set_null_val() throws Exception { mount.conf_set("option", null); } @Test(expected=NullPointerException.class) public void test_conf_get_null_opt() throws Exception { mount.conf_get(null); } @Test public void test_conf() throws Exception { String opt = "log to stderr"; String val1, val2, val3; /* get the current value */ val1 = mount.conf_get(opt); /* * flip the value. this may make some debug information be dumped to the * console when the value becomes true. TODO: find a better config option * to toggle. */ if (val1.compareTo("true") == 0) val2 = "false"; else val2 = "true"; mount.conf_set(opt, val2); /* verify the change */ val3 = mount.conf_get(opt); assertTrue(val3.compareTo(val2) == 0); /* reset to original value */ mount.conf_set(opt, val1); val3 = mount.conf_get(opt); assertTrue(val3.compareTo(val1) == 0); } /* * statfs */ @Test public void test_statfs() throws Exception { CephStatVFS st1 = new CephStatVFS(); mount.statfs("/", st1); /* * FIXME: a better test here is to see if changes to the file system are * reflected through statfs (e.g. increasing number of files). However, it * appears that the updates aren't immediately visible. */ assertTrue(st1.bsize > 0); assertTrue(st1.frsize > 0); assertTrue(st1.blocks > 0); assertTrue(st1.bavail > 0); assertTrue(st1.namemax > 0); } /* * getcwd/chdir */ @Test public void test_getcwd() throws Exception { mount.chdir(basedir); String cwd = mount.getcwd(); assertTrue(cwd.compareTo(basedir) == 0); /* Make sure to reset cwd to root */ mount.chdir("/"); cwd = mount.getcwd(); assertTrue(cwd.compareTo("/") == 0); } @Test(expected=NullPointerException.class) public void test_chdir_null() throws Exception { mount.chdir(null); } @Test(expected=FileNotFoundException.class) public void test_chdir_dne() throws Exception { mount.chdir("/this/path/does/not/exist/"); } /* * FIXME: this test should throw an error (but does not)? */ //@Test(expected=IOException.class) @Test public void test_chdir_not_dir() throws Exception { String path = makePath(); int fd = createFile(path, 1); mount.close(fd); //mount.chdir(path); shouldn't be able to do this? mount.unlink(path); /* * Switch back. Other tests seem to be sensitive to the current directory * being something other than "/". This shouldn't happen once this tests * passes and the call to chdir fails anyway. */ mount.chdir("/"); } /* * listdir */ @Test(expected=NullPointerException.class) public void test_listdir_null() throws Exception { mount.listdir(null); } @Test(expected=FileNotFoundException.class) public void test_listdir_dne() throws Exception { mount.listdir("/this/path/does/not/exist/"); } @Test(expected=IOException.class) public void test_listdir_not_dir() throws Exception { String path = makePath(); int fd = createFile(path, 1); mount.close(fd); try { mount.listdir(path); } finally { mount.unlink(path); } } @Test public void test_listdir() throws Exception { String dir = makePath(); mount.mkdir(dir, 0777); /* test that new directory is empty */ String[] list = mount.listdir(dir); assertTrue(list.length == 0); /* test that new directories are seen */ for (int i = 0; i < 3; i++) mount.mkdir(dir + "/" + i, 777); list = mount.listdir(dir); assertTrue(list.length == 3); /* test that more new directories are seen */ for (int i = 0; i < 30; i++) mount.mkdir(dir + "/x" + i, 777); list = mount.listdir(dir); assertTrue(list.length == 33); /* remove */ for (int i = 0; i < 30; i++) mount.rmdir(dir + "/x" + i); for (int i = 0; i < 3; i++) mount.rmdir(dir + "/" + i); mount.rmdir(dir); } /* * Missing * * ceph_link * ceph_unlink */ /* * rename */ @Test(expected=NullPointerException.class) public void test_rename_null_from() throws Exception { mount.rename(null, "to"); } @Test(expected=NullPointerException.class) public void test_rename_null_to() throws Exception { mount.rename("from", null); } @Test(expected=FileNotFoundException.class) public void test_rename_dne() throws Exception { mount.rename("/this/doesnt/exist", "/this/neither"); } @Test public void test_rename() throws Exception { /* create a file */ String path = makePath(); int fd = createFile(path, 1); mount.close(fd); /* move it to a new name */ String newpath = makePath(); mount.rename(path, newpath); /* verfiy the sizes are the same */ CephStat st = new CephStat(); mount.lstat(newpath, st); assertTrue(st.size == 1); /* remove the file */ mount.unlink(newpath); } /* * mkdir/mkdirs/rmdir */ @Test(expected=IOException.class) public void test_mkdir_exists() throws Exception { String path = makePath(); mount.mkdir(path, 0777); try { mount.mkdir(path, 0777); } finally { mount.rmdir(path); } } @Test(expected=IOException.class) public void test_mkdirs_exists() throws Exception { String path = makePath(); mount.mkdirs(path, 0777); try { mount.mkdirs(path, 0777); } finally { mount.rmdir(path); } } @Test public void test_mkdir() throws Exception { String path = makePath(); mount.mkdir(path, 0777); CephStat st = new CephStat(); mount.lstat(path, st); assertTrue(st.isDir()); mount.rmdir(path); } @Test public void test_mkdirs() throws Exception { String path = makePath(); mount.mkdirs(path + "/x/y", 0777); CephStat st = new CephStat(); mount.lstat(path, st); assertTrue(st.isDir()); mount.lstat(path + "/x", st); assertTrue(st.isDir()); mount.lstat(path + "/x/y", st); assertTrue(st.isDir()); mount.rmdir(path + "/x/y"); mount.rmdir(path + "/x"); mount.rmdir(path); } @Test(expected=FileNotFoundException.class) public void test_rmdir() throws Exception { /* make a new directory */ String path = makePath(); mount.mkdir(path, 0777); CephStat st = new CephStat(); mount.lstat(path, st); assertTrue(st.isDir()); /* remove it */ mount.rmdir(path); /* should not exist now */ mount.lstat(path, st); } /* * readlink * symlink */ @Test public void test_symlink() throws Exception { String oldpath = makePath(); String newpath = makePath(); mount.symlink(oldpath, newpath); CephStat stat = new CephStat(); mount.lstat(newpath, stat); assertTrue(stat.isSymlink()); String symlink = mount.readlink(newpath); assertTrue(symlink.compareTo(oldpath) == 0); mount.unlink(newpath); } /* * lstat */ @Test(expected=NullPointerException.class) public void test_lstat_null_path() throws Exception { mount.lstat(null, new CephStat()); } @Test(expected=NullPointerException.class) public void test_lstat_null_stat() throws Exception { mount.lstat("/path", null); } @Test(expected=FileNotFoundException.class) public void test_lstat_null_dne() throws Exception { mount.lstat("/path/does/not/exist", new CephStat()); } /* * test_stat covers lstat and fstat and stat. * * TODO: create test that for lstat vs stat with symlink follow/nofollow. */ @Test public void test_stat() throws Exception { /* create a new file */ String path = makePath(); int size = 12345; int fd = createFile(path, size); mount.close(fd); /* test some basic info about the new file */ CephStat orig_st = new CephStat(); mount.lstat(path, orig_st); assertTrue(orig_st.size == size); assertTrue(orig_st.blksize > 0); assertTrue(orig_st.blocks > 0); /* now try stat */ CephStat stat_st = new CephStat(); mount.stat(path, stat_st); /* now try fstat */ CephStat other_st = new CephStat(); fd = mount.open(path, CephMount.O_RDWR, 0); mount.fstat(fd, other_st); mount.close(fd); mount.unlink(path); /* compare to fstat results */ assertTrue(orig_st.mode == other_st.mode); assertTrue(orig_st.uid == other_st.uid); assertTrue(orig_st.gid == other_st.gid); assertTrue(orig_st.size == other_st.size); assertTrue(orig_st.blksize == other_st.blksize); assertTrue(orig_st.blocks == other_st.blocks); /* compare to stat results */ assertTrue(orig_st.mode == stat_st.mode); assertTrue(orig_st.uid == stat_st.uid); assertTrue(orig_st.gid == stat_st.gid); assertTrue(orig_st.size == stat_st.size); assertTrue(orig_st.blksize == stat_st.blksize); assertTrue(orig_st.blocks == stat_st.blocks); } /* * stat */ @Test(expected=NullPointerException.class) public void test_stat_null_path() throws Exception { mount.stat(null, new CephStat()); } @Test(expected=NullPointerException.class) public void test_stat_null_stat() throws Exception { mount.stat("/path", null); } @Test(expected=FileNotFoundException.class) public void test_stat_null_dne() throws Exception { mount.stat("/path/does/not/exist", new CephStat()); } @Test(expected=CephNotDirectoryException.class) public void test_enotdir() throws Exception { String path = makePath(); int fd = createFile(path, 1); mount.close(fd); try { CephStat stat = new CephStat(); mount.lstat(path + "/blah", stat); } finally { mount.unlink(path); } } /* * setattr */ @Test(expected=NullPointerException.class) public void test_setattr_null_path() throws Exception { mount.setattr(null, new CephStat(), 0); } @Test(expected=NullPointerException.class) public void test_setattr_null_stat() throws Exception { mount.setattr("/path", null, 0); } @Test(expected=FileNotFoundException.class) public void test_setattr_dne() throws Exception { mount.setattr("/path/does/not/exist", new CephStat(), 0); } @Test public void test_setattr() throws Exception { /* create a file */ String path = makePath(); int fd = createFile(path, 1); mount.close(fd); CephStat st1 = new CephStat(); mount.lstat(path, st1); st1.uid += 1; st1.gid += 1; mount.setattr(path, st1, mount.SETATTR_UID|mount.SETATTR_GID); CephStat st2 = new CephStat(); mount.lstat(path, st2); assertTrue(st2.uid == st1.uid); assertTrue(st2.gid == st1.gid); /* remove the file */ mount.unlink(path); } /* * chmod */ @Test(expected=NullPointerException.class) public void test_chmod_null_path() throws Exception { mount.chmod(null, 0); } @Test(expected=FileNotFoundException.class) public void test_chmod_dne() throws Exception { mount.chmod("/path/does/not/exist", 0); } @Test public void test_chmod() throws Exception { /* create a file */ String path = makePath(); int fd = createFile(path, 1); mount.close(fd); CephStat st = new CephStat(); mount.lstat(path, st); /* flip a bit */ int mode = st.mode; if ((mode & 1) != 0) mode -= 1; else mode += 1; mount.chmod(path, mode); CephStat st2 = new CephStat(); mount.lstat(path, st2); assertTrue(st2.mode == mode); mount.unlink(path); } /* * fchmod */ @Test public void test_fchmod() throws Exception { /* create a file */ String path = makePath(); int fd = createFile(path, 1); CephStat st = new CephStat(); mount.lstat(path, st); /* flip a bit */ int mode = st.mode; if ((mode & 1) != 0) mode -= 1; else mode += 1; mount.fchmod(fd, mode); mount.close(fd); CephStat st2 = new CephStat(); mount.lstat(path, st2); assertTrue(st2.mode == mode); mount.unlink(path); } /* * truncate */ @Test(expected=FileNotFoundException.class) public void test_truncate_dne() throws Exception { mount.truncate("/path/does/not/exist", 0); } @Test(expected=NullPointerException.class) public void test_truncate_null_path() throws Exception { mount.truncate(null, 0); } @Test public void test_truncate() throws Exception { // make file String path = makePath(); int orig_size = 1398331; int fd = createFile(path, orig_size); mount.close(fd); // check file size CephStat st = new CephStat(); mount.lstat(path, st); assertTrue(st.size == orig_size); // truncate and check int crop_size = 333333; mount.truncate(path, crop_size); mount.lstat(path, st); assertTrue(st.size == crop_size); // check after re-open fd = mount.open(path, CephMount.O_RDWR, 0); mount.fstat(fd, st); assertTrue(st.size == crop_size); mount.close(fd); mount.unlink(path); } @Test public void test_open_layout() throws Exception { String path = makePath(); int fd = mount.open(path, CephMount.O_WRONLY|CephMount.O_CREAT, 0, (1<<20), 1, (1<<20), null); mount.close(fd); mount.unlink(path); } /* * open/close */ @Test(expected=FileNotFoundException.class) public void test_open_dne() throws Exception { mount.open("/path/doesnt/exist", 0, 0); } /* * lseek */ @Test public void test_lseek() throws Exception { /* create a new file */ String path = makePath(); int size = 12345; int fd = createFile(path, size); mount.close(fd); /* open and check size */ fd = mount.open(path, CephMount.O_RDWR, 0); long end = mount.lseek(fd, 0, CephMount.SEEK_END); mount.close(fd); mount.unlink(path); assertTrue(size == (int)end); } /* * read/write */ @Test public void test_read() throws Exception { String path = makePath(); int fd = createFile(path, 1500); byte[] buf = new byte[1500]; long ret = mount.read(fd, buf, 1500, 0); assertTrue(ret == 1500); mount.unlink(path); } /* * ftruncate */ @Test public void test_ftruncate() throws Exception { // make file String path = makePath(); int orig_size = 1398331; int fd = createFile(path, orig_size); // check file size CephStat st = new CephStat(); mount.fstat(fd, st); assertTrue(st.size == orig_size); // truncate and check int crop_size = 333333; mount.ftruncate(fd, crop_size); mount.fstat(fd, st); assertTrue(st.size == crop_size); mount.close(fd); // check after re-open fd = mount.open(path, CephMount.O_RDWR, 0); mount.fstat(fd, st); assertTrue(st.size == crop_size); mount.close(fd); mount.unlink(path); } /* * fsync */ @Test public void test_fsync() throws Exception { String path = makePath(); int fd = createFile(path, 123); mount.fsync(fd, false); mount.fsync(fd, true); mount.close(fd); mount.unlink(path); } /* * fstat * * success case is handled in test_stat along with lstat. */ /* * sync_fs */ @Test public void test_sync_fs() throws Exception { mount.sync_fs(); } /* * get/set/list/remove xattr */ @Test public void test_xattr() throws Exception { /* make file */ String path = makePath(); int fd = createFile(path, 123); mount.close(fd); /* make xattrs */ String val1 = "This is a new xattr"; String val2 = "This is a different xattr"; byte[] buf1 = val1.getBytes(); byte[] buf2 = val2.getBytes(); mount.setxattr(path, "user.attr1", buf1, buf1.length, mount.XATTR_CREATE); mount.setxattr(path, "user.attr2", buf2, buf2.length, mount.XATTR_CREATE); /* list xattrs */ String[] xattrs = mount.listxattr(path); assertTrue(xattrs.length == 2); int found = 0; for (String xattr : xattrs) { if (xattr.compareTo("user.attr1") == 0) { found++; continue; } if (xattr.compareTo("user.attr2") == 0) { found++; continue; } System.out.println("found unwanted xattr: " + xattr); } assertTrue(found == 2); /* get first xattr by looking up length */ long attr1_len = mount.getxattr(path, "user.attr1", null); byte[] out = new byte[(int)attr1_len]; mount.getxattr(path, "user.attr1", out); String outStr = new String(out); assertTrue(outStr.compareTo(val1) == 0); /* get second xattr assuming original length */ out = new byte[buf2.length]; mount.getxattr(path, "user.attr2", out); outStr = new String(out); assertTrue(outStr.compareTo(val2) == 0); /* remove the attributes */ /* FIXME: the MDS returns ENODATA for removexattr */ /* mount.removexattr(path, "attr1"); xattrs = mount.listxattr(path); assertTrue(xattrs.length == 1); mount.removexattr(path, "attr2"); xattrs = mount.listxattr(path); assertTrue(xattrs.length == 0); */ mount.unlink(path); } /* * get/set/list/remove symlink xattr * * Currently not working. Code is the same as for regular xattrs, so there * might be a deeper issue. */ @Test public void test_get_stripe_unit() throws Exception { String path = makePath(); int fd = createFile(path, 1); assertTrue(mount.get_file_stripe_unit(fd) > 0); mount.close(fd); mount.unlink(path); } @Test public void test_get_repl() throws Exception { String path = makePath(); int fd = createFile(path, 1); assertTrue(mount.get_file_replication(fd) > 0); mount.close(fd); mount.unlink(path); } /* * stripe unit granularity */ @Test public void test_get_stripe_unit_gran() throws Exception { assertTrue(mount.get_stripe_unit_granularity() > 0); } /* * pool info. below we use "data" and "metadata" pool names which we assume * to exist (they are the default pools created for file data / metadata in * CephFS). */ @Test public void test_get_pool_id() throws Exception { /* returns valid pool ids */ assertTrue(mount.get_pool_id("data") >= 0); assertTrue(mount.get_pool_id("metadata") >= 0); /* test non-existent pool name */ try { mount.get_pool_id("asdlfkjlsejflkjef"); assertTrue(false); } catch (CephPoolException e) {} } @Test public void test_get_pool_replication() throws Exception { /* test invalid pool id */ try { mount.get_pool_replication(-1); assertTrue(false); } catch (CephPoolException e) {} /* test valid pool id */ int poolid = mount.get_pool_id("data"); assertTrue(poolid >= 0); assertTrue(mount.get_pool_replication(poolid) > 0); } @Test public void test_get_file_pool_name() throws Exception { String path = makePath(); int fd = createFile(path, 1); String pool = mount.get_file_pool_name(fd); mount.close(fd); assertTrue(pool != null); /* assumes using default data pool "data" */ assertTrue(pool.compareTo("data") == 0); mount.unlink(path); } @Test(expected=IOException.class) public void test_get_file_pool_name_ebadf() throws Exception { String pool = mount.get_file_pool_name(-40); } @Test public void test_get_file_extent() throws Exception { int stripe_unit = 1<<18; String path = makePath(); int fd = mount.open(path, CephMount.O_WRONLY|CephMount.O_CREAT, 0, stripe_unit, 2, stripe_unit*2, null); CephFileExtent e = mount.get_file_extent(fd, 0); assertTrue(e.getOSDs().length > 0); assertTrue(e.getOffset() == 0); assertTrue(e.getLength() == stripe_unit); e = mount.get_file_extent(fd, stripe_unit/2); assertTrue(e.getOffset() == stripe_unit/2); assertTrue(e.getLength() == stripe_unit/2); e = mount.get_file_extent(fd, 3*stripe_unit/2-1); assertTrue(e.getOffset() == 3*stripe_unit/2-1); assertTrue(e.getLength() == stripe_unit/2+1); e = mount.get_file_extent(fd, 3*stripe_unit/2+1); assertTrue(e.getLength() == stripe_unit/2-1); mount.close(fd); mount.unlink(path); } @Test public void test_get_osd_crush_location() throws Exception { Bucket[] path = mount.get_osd_crush_location(0); assertTrue(path.length > 0); for (Bucket b : path) { assertTrue(b.getType().length() > 0); assertTrue(b.getName().length() > 0); } } @Test public void test_get_osd_address() throws Exception { InetAddress addr = mount.get_osd_address(0); assertTrue(addr.getHostAddress().length() > 0); } } ceph-0.80.11/src/java/Makefile.in0000664000175100017510000004643412623076765020470 0ustar jenkins-buildjenkins-build# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. @SET_MAKE@ # automake technique adapted from OpenMPI Java VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@am__append_1 = libcephfs-test.jar @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@am__append_2 = test/com/ceph/fs/*.class libcephfs-test.jar subdir = src/java DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_check_classpath.m4 \ $(top_srcdir)/m4/ac_prog_jar.m4 \ $(top_srcdir)/m4/ac_prog_javac.m4 \ $(top_srcdir)/m4/ac_prog_javac_works.m4 \ $(top_srcdir)/m4/ac_prog_javah.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/ax_c_pretty_func.m4 \ $(top_srcdir)/m4/ax_c_var_func.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_cxx_static_cast.m4 \ $(top_srcdir)/m4/ax_intel.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/acconfig.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(javadir)" DATA = $(java_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CXXFLAGS = @AM_CXXFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@ CC = @CC@ CCAS = @CCAS@ CCASDEPMODE = @CCASDEPMODE@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOPP_CFLAGS = @CRYPTOPP_CFLAGS@ CRYPTOPP_LIBS = @CRYPTOPP_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CLASSPATH_JAR = @EXTRA_CLASSPATH_JAR@ FGREP = @FGREP@ GCOV_PREFIX_STRIP = @GCOV_PREFIX_STRIP@ GIT_CHECK = @GIT_CHECK@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTEL_FLAGS = @INTEL_FLAGS@ INTEL_PCLMUL_FLAGS = @INTEL_PCLMUL_FLAGS@ INTEL_SSE2_FLAGS = @INTEL_SSE2_FLAGS@ INTEL_SSE3_FLAGS = @INTEL_SSE3_FLAGS@ INTEL_SSE4_1_FLAGS = @INTEL_SSE4_1_FLAGS@ INTEL_SSE4_2_FLAGS = @INTEL_SSE4_2_FLAGS@ INTEL_SSE_FLAGS = @INTEL_SSE_FLAGS@ INTEL_SSSE3_FLAGS = @INTEL_SSSE3_FLAGS@ JAR = @JAR@ JAVAC = @JAVAC@ JAVAH = @JAVAH@ JDK_CPPFLAGS = @JDK_CPPFLAGS@ KEYUTILS_LIB = @KEYUTILS_LIB@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEDIT_CFLAGS = @LIBEDIT_CFLAGS@ LIBEDIT_LIBS = @LIBEDIT_LIBS@ LIBFUSE = @LIBFUSE@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTCMALLOC = @LIBTCMALLOC@ LIBTOOL = @LIBTOOL@ LIBZFS_CFLAGS = @LIBZFS_CFLAGS@ LIBZFS_LIBS = @LIBZFS_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NSS_CFLAGS = @NSS_CFLAGS@ NSS_LIBS = @NSS_LIBS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RESOLV_LIBS = @RESOLV_LIBS@ RPM_RELEASE = @RPM_RELEASE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WARN_IGNORED_QUALIFIERS = @WARN_IGNORED_QUALIFIERS@ WARN_TYPE_LIMITS = @WARN_TYPE_LIMITS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ JAVA_SRC = \ java/com/ceph/fs/CephMount.java \ java/com/ceph/fs/CephStat.java \ java/com/ceph/fs/CephStatVFS.java \ java/com/ceph/fs/CephNativeLoader.java \ java/com/ceph/fs/CephNotMountedException.java \ java/com/ceph/fs/CephFileAlreadyExistsException.java \ java/com/ceph/fs/CephAlreadyMountedException.java \ java/com/ceph/fs/CephNotDirectoryException.java \ java/com/ceph/fs/CephPoolException.java \ java/com/ceph/fs/CephFileExtent.java \ java/com/ceph/crush/Bucket.java JAVA_TEST_SRC = \ test/com/ceph/fs/CephDoubleMountTest.java \ test/com/ceph/fs/CephMountCreateTest.java \ test/com/ceph/fs/CephMountTest.java \ test/com/ceph/fs/CephUnmountedTest.java \ test/com/ceph/fs/CephAllTests.java EXTRA_DIST = $(JAVA_SRC) $(JAVA_TEST_SRC) @ENABLE_CEPHFS_JAVA_TRUE@JAVA_CLASSES = $(JAVA_SRC:java/%.java=%.class) # This is dumb -- It might be better to split some work # between Make and Ant or Maven #ESCAPED_JAVA_CLASSES = \ # com/ceph/fs/CephMount\$$State.class @ENABLE_CEPHFS_JAVA_TRUE@JAVA_H = native/com_ceph_fs_CephMount.h # target to make automake happy @ENABLE_CEPHFS_JAVA_TRUE@CEPH_PROXY = java/com/ceph/fs/CephMount.class @ENABLE_CEPHFS_JAVA_TRUE@javadir = $(datadir)/java @ENABLE_CEPHFS_JAVA_TRUE@java_DATA = libcephfs.jar $(am__append_1) @ENABLE_CEPHFS_JAVA_TRUE@CLEANFILES = -rf java/com/ceph/fs/*.class \ @ENABLE_CEPHFS_JAVA_TRUE@ $(JAVA_H) libcephfs.jar \ @ENABLE_CEPHFS_JAVA_TRUE@ $(am__append_2) @ENABLE_CEPHFS_JAVA_TRUE@BUILT_SOURCES = $(JAVA_H) # build the tests if *both* --enable-cephfs-java and --with-debug were specifed @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@JAVA_TEST_CLASSES = $(JAVA_TEST_SRC:test/%.java=%.class) @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@CEPH_TEST_PROXY = test/com/ceph/fs/CephMountTest.class all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/java/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/java/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-javaDATA: $(java_DATA) @$(NORMAL_INSTALL) @list='$(java_DATA)'; test -n "$(javadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(javadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(javadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(javadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(javadir)" || exit $$?; \ done uninstall-javaDATA: @$(NORMAL_UNINSTALL) @list='$(java_DATA)'; test -n "$(javadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(javadir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(javadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-javaDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-javaDATA .MAKE: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-javaDATA \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-javaDATA # note: for the -source 1.5 builds, we add # -Xlint:-options # to get rid of the warning # warning: [options] bootstrap class path not set in conjunction with -source 1.5 # as per # https://blogs.oracle.com/darcy/entry/bootclasspath_older_source @ENABLE_CEPHFS_JAVA_TRUE@$(CEPH_PROXY): $(JAVA_SRC) @ENABLE_CEPHFS_JAVA_TRUE@ export CLASSPATH=java/ ; \ @ENABLE_CEPHFS_JAVA_TRUE@ $(JAVAC) -classpath java -source 1.5 -target 1.5 -Xlint:-options java/com/ceph/fs/*.java @ENABLE_CEPHFS_JAVA_TRUE@$(JAVA_H): $(CEPH_PROXY) @ENABLE_CEPHFS_JAVA_TRUE@ export CLASSPATH=java/ ; \ @ENABLE_CEPHFS_JAVA_TRUE@ $(JAVAH) -classpath java -jni -o $@ com.ceph.fs.CephMount @ENABLE_CEPHFS_JAVA_TRUE@libcephfs.jar: $(CEPH_PROXY) @ENABLE_CEPHFS_JAVA_TRUE@ $(JAR) cf $@ $(JAVA_CLASSES:%=-C java %) @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@$(CEPH_TEST_PROXY): $(JAVA_TEST_SRC) $(CEPH_PROXY) @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@ export CLASSPATH=$(CLASSPATH):$(EXTRA_CLASSPATH_JAR):java/:test/ ; \ @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@ $(JAVAC) -source 1.5 -target 1.5 -Xlint:-options test/com/ceph/fs/*.java @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@libcephfs-test.jar: $(CEPH_TEST_PROXY) @ENABLE_CEPHFS_JAVA_TRUE@@HAVE_JUNIT4_TRUE@ $(JAR) cf $@ $(JAVA_TEST_CLASSES:%=-C test %) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ceph-0.80.11/src/java/README0000664000175100017510000000303012623076744017261 0ustar jenkins-buildjenkins-buildlibcephfs Java wrappers ======================= - native/: C++ - java/: Java - test/: JUnit tests - lib/: JUnit library - build.xml: Test runner Building -------- Autotools handles the build using the configure flag --enable-cephfs-java Testing ------- These tests assume a live cluster, and depend on JUnit4 and Ant. To run the tests make sure that the JUnit4 JAR is installed. Install it via a package manager or like this: $ mkdir lib $ cd lib $ wget https://github.com/downloads/KentBeck/junit/junit-4.8.2.jar And then add the jar to the CLASSPATH. *NOTE* for now, configure is only looking for this jar in the /usr/share/java directory as junit4.jar. So create a softlink to that location from wherever the junit jar is installed. Ant is used to run the unit test (apt-get install ant). For example: $ cd src/ $ ./vstart -d -n --localhost $ cd java $ CEPHFS_CONF=../ceph.conf CLASSPATH=/usr/share/java/junit4.jar ant test 1. The tests depend on the compiled wrappers. If the wrappers are installed as part of a package (e.g. Debian package) then this should 'just work'. Ant will also look in the current directory for 'libcephfs.jar' and 'libcephfs-test.jar'; and in ../.libs for the JNI library. If all else fails, set the environment variables CEPHFS_JAR, and CEPHFS_JNI_LIB accordingly. 2. Set CEPHFS_CONF environment variable to point to a ceph.conf. This can be omitted if the desired configuration file can be found in a default location. Documentation ------------- Ant is used to build the Javadocs: $ ant docs ceph-0.80.11/src/log/0000775000175100017510000000000012623077036016240 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/log/test.cc0000664000175100017510000001027012623076744017533 0ustar jenkins-buildjenkins-build#include #include "log/Log.h" #include "common/Clock.h" #include "common/PrebufferedStreambuf.h" using namespace ceph::log; TEST(Log, Simple) { SubsystemMap subs; subs.add(0, "none", 10, 10); subs.add(1, "foosys", 20, 1); subs.add(2, "bar", 20, 2); subs.add(3, "baz", 10, 3); Log log(&subs); log.start(); log.set_log_file("/tmp/foo"); log.reopen_log_file(); log.set_stderr_level(5, -1); for (int i=0; i<100; i++) { int sys = i % 4; int l = 5 + (i%4); if (subs.should_gather(sys, l)) { Entry *e = new Entry(ceph_clock_now(NULL), pthread_self(), l, sys, "hello world"); log.submit_entry(e); } } log.flush(); log.dump_recent(); log.stop(); } int many = 10000; TEST(Log, ManyNoGather) { SubsystemMap subs; subs.add(1, "foo", 1, 1); Log log(&subs); log.start(); log.set_log_file("/tmp/big"); log.reopen_log_file(); for (int i=0; iset_str(oss.str()); log.submit_entry(e); } } log.flush(); log.stop(); } TEST(Log, ManyGatherLogStringAssignWithReserve) { SubsystemMap subs; subs.add(1, "foo", 20, 10); Log log(&subs); log.start(); log.set_log_file("/tmp/big"); log.reopen_log_file(); for (int i=0; iset_str(oss.str()); log.submit_entry(e); } } log.flush(); log.stop(); } TEST(Log, ManyGatherLogPrebuf) { SubsystemMap subs; subs.add(1, "foo", 20, 10); Log log(&subs); log.start(); log.set_log_file("/tmp/big"); log.reopen_log_file(); for (int i=0; im_static_buf, sizeof(e->m_static_buf)); ostream oss(&psb); oss << "this i a long stream asdf asdf asdf asdf asdf asdf asdf asdf asdf as fd"; //e->m_str = oss.str(); log.submit_entry(e); } } log.flush(); log.stop(); } TEST(Log, ManyGatherLogPrebufOverflow) { SubsystemMap subs; subs.add(1, "foo", 20, 10); Log log(&subs); log.start(); log.set_log_file("/tmp/big"); log.reopen_log_file(); for (int i=0; im_static_buf, 20); ostream oss(&psb); oss << "this i a long stream asdf asdf asdf asdf asdf asdf asdf asdf asdf as fd"; //e->m_str = oss.str(); log.submit_entry(e); } } log.flush(); log.stop(); } TEST(Log, ManyGather) { SubsystemMap subs; subs.add(1, "foo", 20, 1); Log log(&subs); log.start(); log.set_log_file("/tmp/big"); log.reopen_log_file(); for (int i=0; i #include "Entry.h" #include "EntryQueue.h" #include "SubsystemMap.h" namespace ceph { namespace log { class Log : private Thread { Log **m_indirect_this; SubsystemMap *m_subs; pthread_mutex_t m_queue_mutex; pthread_mutex_t m_flush_mutex; pthread_cond_t m_cond_loggers; pthread_cond_t m_cond_flusher; EntryQueue m_new; ///< new entries EntryQueue m_recent; ///< recent (less new) entries we've already written at low detail std::string m_log_file; int m_fd; int m_syslog_log, m_syslog_crash; int m_stderr_log, m_stderr_crash; bool m_stop; int m_max_new, m_max_recent; void *entry(); void _flush(EntryQueue *q, EntryQueue *requeue, bool crash); void _log_message(const char *s, bool crash); public: Log(SubsystemMap *s); virtual ~Log(); void set_flush_on_exit(); void set_max_new(int n); void set_max_recent(int n); void set_log_file(std::string fn); void reopen_log_file(); void flush(); void dump_recent(); void set_syslog_level(int log, int crash); void set_stderr_level(int log, int crash); Entry *create_entry(int level, int subsys); void submit_entry(Entry *e); void start(); void stop(); }; } } #endif ceph-0.80.11/src/log/SubsystemMap.cc0000664000175100017510000000125412623076744021212 0ustar jenkins-buildjenkins-build #include "SubsystemMap.h" namespace ceph { namespace log { void SubsystemMap::add(unsigned subsys, std::string name, int log, int gather) { if (subsys >= m_subsys.size()) m_subsys.resize(subsys + 1); m_subsys[subsys].name = name; m_subsys[subsys].log_level = log; m_subsys[subsys].gather_level = gather; if (name.length() > m_max_name_len) m_max_name_len = name.length(); } void SubsystemMap::set_log_level(unsigned subsys, int log) { assert(subsys < m_subsys.size()); m_subsys[subsys].log_level = log; } void SubsystemMap::set_gather_level(unsigned subsys, int gather) { assert(subsys < m_subsys.size()); m_subsys[subsys].gather_level = gather; } } } ceph-0.80.11/src/log/Entry.h0000664000175100017510000000212512623076744017517 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef __CEPH_LOG_ENTRY_H #define __CEPH_LOG_ENTRY_H #include "include/utime.h" #include "common/PrebufferedStreambuf.h" #include #include #define CEPH_LOG_ENTRY_PREALLOC 80 namespace ceph { namespace log { struct Entry { utime_t m_stamp; pthread_t m_thread; short m_prio, m_subsys; Entry *m_next; char m_static_buf[CEPH_LOG_ENTRY_PREALLOC]; PrebufferedStreambuf m_streambuf; Entry() : m_thread(0), m_prio(0), m_subsys(0), m_next(NULL), m_streambuf(m_static_buf, sizeof(m_static_buf)) {} Entry(utime_t s, pthread_t t, short pr, short sub, const char *msg = NULL) : m_stamp(s), m_thread(t), m_prio(pr), m_subsys(sub), m_next(NULL), m_streambuf(m_static_buf, sizeof(m_static_buf)) { if (msg) { ostream os(&m_streambuf); os << msg; } } void set_str(const std::string &s) { ostream os(&m_streambuf); os << s; } std::string get_str() const { return m_streambuf.get_str(); } }; } } #endif ceph-0.80.11/src/log/Log.cc0000664000175100017510000001664212623076744017306 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "Log.h" #include #include #include #include #include "common/errno.h" #include "common/safe_io.h" #include "common/Clock.h" #include "include/assert.h" #include "include/compat.h" #include "include/on_exit.h" #define DEFAULT_MAX_NEW 100 #define DEFAULT_MAX_RECENT 10000 #define PREALLOC 1000000 namespace ceph { namespace log { static OnExitManager exit_callbacks; static void log_on_exit(void *p) { Log *l = *(Log **)p; if (l) l->flush(); } Log::Log(SubsystemMap *s) : m_indirect_this(NULL), m_subs(s), m_new(), m_recent(), m_fd(-1), m_syslog_log(-2), m_syslog_crash(-2), m_stderr_log(1), m_stderr_crash(-1), m_stop(false), m_max_new(DEFAULT_MAX_NEW), m_max_recent(DEFAULT_MAX_RECENT) { int ret; ret = pthread_mutex_init(&m_flush_mutex, NULL); assert(ret == 0); ret = pthread_mutex_init(&m_queue_mutex, NULL); assert(ret == 0); ret = pthread_cond_init(&m_cond_loggers, NULL); assert(ret == 0); ret = pthread_cond_init(&m_cond_flusher, NULL); assert(ret == 0); // kludge for prealloc testing if (false) for (int i=0; i < PREALLOC; i++) m_recent.enqueue(new Entry); } Log::~Log() { if (m_indirect_this) { *m_indirect_this = NULL; } assert(!is_started()); if (m_fd >= 0) VOID_TEMP_FAILURE_RETRY(::close(m_fd)); pthread_mutex_destroy(&m_queue_mutex); pthread_mutex_destroy(&m_flush_mutex); pthread_cond_destroy(&m_cond_loggers); pthread_cond_destroy(&m_cond_flusher); } /// void Log::set_flush_on_exit() { // Make sure we flush on shutdown. We do this by deliberately // leaking an indirect pointer to ourselves (on_exit() can't // unregister a callback). This is not racy only becuase we // assume that exit() won't race with ~Log(). if (m_indirect_this == NULL) { m_indirect_this = new (Log*)(this); exit_callbacks.add_callback(log_on_exit, m_indirect_this); } } void Log::set_max_new(int n) { m_max_new = n; } void Log::set_max_recent(int n) { m_max_recent = n; } void Log::set_log_file(string fn) { m_log_file = fn; } void Log::reopen_log_file() { pthread_mutex_lock(&m_flush_mutex); if (m_fd >= 0) VOID_TEMP_FAILURE_RETRY(::close(m_fd)); if (m_log_file.length()) { m_fd = ::open(m_log_file.c_str(), O_CREAT|O_WRONLY|O_APPEND, 0644); } else { m_fd = -1; } pthread_mutex_unlock(&m_flush_mutex); } void Log::set_syslog_level(int log, int crash) { pthread_mutex_lock(&m_flush_mutex); m_syslog_log = log; m_syslog_crash = crash; pthread_mutex_unlock(&m_flush_mutex); } void Log::set_stderr_level(int log, int crash) { pthread_mutex_lock(&m_flush_mutex); m_stderr_log = log; m_stderr_crash = crash; pthread_mutex_unlock(&m_flush_mutex); } void Log::submit_entry(Entry *e) { pthread_mutex_lock(&m_queue_mutex); // wait for flush to catch up while (m_new.m_len > m_max_new) pthread_cond_wait(&m_cond_loggers, &m_queue_mutex); m_new.enqueue(e); pthread_cond_signal(&m_cond_flusher); pthread_mutex_unlock(&m_queue_mutex); } Entry *Log::create_entry(int level, int subsys) { if (true) { return new Entry(ceph_clock_now(NULL), pthread_self(), level, subsys); } else { // kludge for perf testing Entry *e = m_recent.dequeue(); e->m_stamp = ceph_clock_now(NULL); e->m_thread = pthread_self(); e->m_prio = level; e->m_subsys = subsys; return e; } } void Log::flush() { pthread_mutex_lock(&m_flush_mutex); pthread_mutex_lock(&m_queue_mutex); EntryQueue t; t.swap(m_new); pthread_cond_broadcast(&m_cond_loggers); pthread_mutex_unlock(&m_queue_mutex); _flush(&t, &m_recent, false); // trim while (m_recent.m_len > m_max_recent) { delete m_recent.dequeue(); } pthread_mutex_unlock(&m_flush_mutex); } void Log::_flush(EntryQueue *t, EntryQueue *requeue, bool crash) { Entry *e; char buf[80]; while ((e = t->dequeue()) != NULL) { unsigned sub = e->m_subsys; bool should_log = crash || m_subs->get_log_level(sub) >= e->m_prio; bool do_fd = m_fd >= 0 && should_log; bool do_syslog = m_syslog_crash >= e->m_prio && should_log; bool do_stderr = m_stderr_crash >= e->m_prio && should_log; if (do_fd || do_syslog || do_stderr) { int buflen = 0; if (crash) buflen += snprintf(buf, sizeof(buf), "%6d> ", -t->m_len); buflen += e->m_stamp.sprintf(buf + buflen, sizeof(buf)-buflen); buflen += snprintf(buf + buflen, sizeof(buf)-buflen, " %lx %2d ", (unsigned long)e->m_thread, e->m_prio); // FIXME: this is slow string s = e->get_str(); if (do_fd) { int r = safe_write(m_fd, buf, buflen); if (r >= 0) r = safe_write(m_fd, s.data(), s.size()); if (r >= 0) r = write(m_fd, "\n", 1); if (r < 0) cerr << "problem writing to " << m_log_file << ": " << cpp_strerror(r) << std::endl; } if (do_syslog) { syslog(LOG_USER, "%s%s", buf, s.c_str()); } if (do_stderr) { cerr << buf << s << std::endl; } } requeue->enqueue(e); } } void Log::_log_message(const char *s, bool crash) { if (m_fd >= 0) { int r = safe_write(m_fd, s, strlen(s)); if (r >= 0) r = safe_write(m_fd, "\n", 1); if (r < 0) cerr << "problem writing to " << m_log_file << ": " << cpp_strerror(r) << std::endl; } if ((crash ? m_syslog_crash : m_syslog_log) >= 0) { syslog(LOG_USER, "%s", s); } if ((crash ? m_stderr_crash : m_stderr_log) >= 0) { cerr << s << std::endl; } } void Log::dump_recent() { pthread_mutex_lock(&m_flush_mutex); pthread_mutex_lock(&m_queue_mutex); EntryQueue t; t.swap(m_new); pthread_mutex_unlock(&m_queue_mutex); _flush(&t, &m_recent, false); EntryQueue old; _log_message("--- begin dump of recent events ---", true); _flush(&m_recent, &old, true); char buf[4096]; _log_message("--- logging levels ---", true); for (vector::iterator p = m_subs->m_subsys.begin(); p != m_subs->m_subsys.end(); ++p) { snprintf(buf, sizeof(buf), " %2d/%2d %s", p->log_level, p->gather_level, p->name.c_str()); _log_message(buf, true); } sprintf(buf, " %2d/%2d (syslog threshold)", m_syslog_log, m_syslog_crash); _log_message(buf, true); sprintf(buf, " %2d/%2d (stderr threshold)", m_stderr_log, m_stderr_crash); _log_message(buf, true); sprintf(buf, " max_recent %9d", m_max_recent); _log_message(buf, true); sprintf(buf, " max_new %9d", m_max_new); _log_message(buf, true); sprintf(buf, " log_file %s", m_log_file.c_str()); _log_message(buf, true); _log_message("--- end dump of recent events ---", true); pthread_mutex_unlock(&m_flush_mutex); } void Log::start() { assert(!is_started()); pthread_mutex_lock(&m_queue_mutex); m_stop = false; pthread_mutex_unlock(&m_queue_mutex); create(); } void Log::stop() { assert(is_started()); pthread_mutex_lock(&m_queue_mutex); m_stop = true; pthread_cond_signal(&m_cond_flusher); pthread_cond_broadcast(&m_cond_loggers); pthread_mutex_unlock(&m_queue_mutex); join(); } void *Log::entry() { pthread_mutex_lock(&m_queue_mutex); while (!m_stop) { if (!m_new.empty()) { pthread_mutex_unlock(&m_queue_mutex); flush(); pthread_mutex_lock(&m_queue_mutex); continue; } pthread_cond_wait(&m_cond_flusher, &m_queue_mutex); } pthread_mutex_unlock(&m_queue_mutex); flush(); return NULL; } } // ceph::log:: } // ceph:: ceph-0.80.11/src/log/SubsystemMap.h0000664000175100017510000000267412623076744021063 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LOG_SUBSYSTEMS #define CEPH_LOG_SUBSYSTEMS #include #include #include "include/assert.h" namespace ceph { namespace log { struct Subsystem { int log_level, gather_level; std::string name; Subsystem() : log_level(0), gather_level(0) {} }; class SubsystemMap { std::vector m_subsys; unsigned m_max_name_len; friend class Log; public: SubsystemMap() : m_max_name_len(0) {} int get_num() const { return m_subsys.size(); } int get_max_subsys_len() const { return m_max_name_len; } void add(unsigned subsys, std::string name, int log, int gather); void set_log_level(unsigned subsys, int log); void set_gather_level(unsigned subsys, int gather); int get_log_level(unsigned subsys) const { if (subsys >= m_subsys.size()) subsys = 0; return m_subsys[subsys].log_level; } int get_gather_level(unsigned subsys) const { if (subsys >= m_subsys.size()) subsys = 0; return m_subsys[subsys].gather_level; } const std::string& get_name(unsigned subsys) const { if (subsys >= m_subsys.size()) subsys = 0; return m_subsys[subsys].name; } bool should_gather(unsigned sub, int level) { assert(sub < m_subsys.size()); return level <= m_subsys[sub].gather_level || level <= m_subsys[sub].log_level; } }; } } #endif ceph-0.80.11/src/log/Makefile.am0000664000175100017510000000026312623076744020302 0ustar jenkins-buildjenkins-buildliblog_la_SOURCES = \ log/Log.cc \ log/SubsystemMap.cc noinst_LTLIBRARIES += liblog.la noinst_HEADERS += \ log/Entry.h \ log/EntryQueue.h \ log/Log.h \ log/SubsystemMap.h ceph-0.80.11/src/log/EntryQueue.h0000664000175100017510000000221312623076744020522 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef __CEPH_LOG_ENTRYQUEUE_H #define __CEPH_LOG_ENTRYQUEUE_H #include "Entry.h" namespace ceph { namespace log { struct EntryQueue { int m_len; struct Entry *m_head, *m_tail; bool empty() const { return m_len == 0; } void swap(EntryQueue& other) { int len = m_len; struct Entry *h = m_head, *t = m_tail; m_len = other.m_len; m_head = other.m_head; m_tail = other.m_tail; other.m_len = len; other.m_head = h; other.m_tail = t; } void enqueue(Entry *e) { if (m_tail) { m_tail->m_next = e; m_tail = e; } else { m_head = m_tail = e; } m_len++; } Entry *dequeue() { if (!m_head) return NULL; Entry *e = m_head; m_head = m_head->m_next; if (!m_head) m_tail = NULL; m_len--; e->m_next = NULL; return e; } EntryQueue() : m_len(0), m_head(NULL), m_tail(NULL) {} ~EntryQueue() { Entry *t; while (m_head) { t = m_head->m_next; delete m_head; m_head = t; } } }; } } #endif ceph-0.80.11/src/librbd/0000775000175100017510000000000012623077035016714 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/librbd/LibrbdWriteback.cc0000664000175100017510000001414312623076744022266 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "common/ceph_context.h" #include "common/dout.h" #include "common/Mutex.h" #include "include/Context.h" #include "include/rados/librados.hpp" #include "include/rbd/librbd.hpp" #include "librbd/AioRequest.h" #include "librbd/ImageCtx.h" #include "librbd/internal.h" #include "librbd/LibrbdWriteback.h" #include "include/assert.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbdwriteback: " namespace librbd { /** * callback to finish a rados completion as a Context * * @param c completion * @param arg Context* recast as void* */ void context_cb(rados_completion_t c, void *arg) { Context *con = reinterpret_cast(arg); con->complete(rados_aio_get_return_value(c)); } /** * context to wrap another context in a Mutex * * @param cct cct * @param c context to finish * @param l mutex to lock */ class C_Request : public Context { public: C_Request(CephContext *cct, Context *c, Mutex *l) : m_cct(cct), m_ctx(c), m_lock(l) {} virtual ~C_Request() {} virtual void finish(int r) { ldout(m_cct, 20) << "aio_cb completing " << dendl; { Mutex::Locker l(*m_lock); m_ctx->complete(r); } ldout(m_cct, 20) << "aio_cb finished" << dendl; } private: CephContext *m_cct; Context *m_ctx; Mutex *m_lock; }; class C_OrderedWrite : public Context { public: C_OrderedWrite(CephContext *cct, LibrbdWriteback::write_result_d *result, LibrbdWriteback *wb) : m_cct(cct), m_result(result), m_wb_handler(wb) {} virtual ~C_OrderedWrite() {} virtual void finish(int r) { ldout(m_cct, 20) << "C_OrderedWrite completing " << m_result << dendl; { Mutex::Locker l(m_wb_handler->m_lock); assert(!m_result->done); m_result->done = true; m_result->ret = r; m_wb_handler->complete_writes(m_result->oid); } ldout(m_cct, 20) << "C_OrderedWrite finished " << m_result << dendl; } private: CephContext *m_cct; LibrbdWriteback::write_result_d *m_result; LibrbdWriteback *m_wb_handler; }; LibrbdWriteback::LibrbdWriteback(ImageCtx *ictx, Mutex& lock) : m_tid(0), m_lock(lock), m_ictx(ictx) { } void LibrbdWriteback::read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snapid, bufferlist *pbl, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) { // on completion, take the mutex and then call onfinish. Context *req = new C_Request(m_ictx->cct, onfinish, &m_lock); librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(req, context_cb, NULL); librados::ObjectReadOperation op; op.read(off, len, pbl, NULL); int flags = m_ictx->get_read_flags(snapid); int r = m_ictx->data_ctx.aio_operate(oid.name, rados_completion, &op, flags, NULL); rados_completion->release(); assert(r >= 0); } bool LibrbdWriteback::may_copy_on_write(const object_t& oid, uint64_t read_off, uint64_t read_len, snapid_t snapid) { m_ictx->snap_lock.get_read(); librados::snap_t snap_id = m_ictx->snap_id; m_ictx->parent_lock.get_read(); uint64_t overlap = 0; m_ictx->get_parent_overlap(snap_id, &overlap); m_ictx->parent_lock.put_read(); m_ictx->snap_lock.put_read(); uint64_t object_no = oid_to_object_no(oid.name, m_ictx->object_prefix); // reverse map this object extent onto the parent vector > objectx; Striper::extent_to_file(m_ictx->cct, &m_ictx->layout, object_no, 0, m_ictx->layout.fl_object_size, objectx); uint64_t object_overlap = m_ictx->prune_parent_extents(objectx, overlap); bool may = object_overlap > 0; ldout(m_ictx->cct, 10) << "may_copy_on_write " << oid << " " << read_off << "~" << read_len << " = " << may << dendl; return may; } ceph_tid_t LibrbdWriteback::write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, uint64_t trunc_size, __u32 trunc_seq, Context *oncommit) { m_ictx->snap_lock.get_read(); librados::snap_t snap_id = m_ictx->snap_id; m_ictx->parent_lock.get_read(); uint64_t overlap = 0; m_ictx->get_parent_overlap(snap_id, &overlap); m_ictx->parent_lock.put_read(); m_ictx->snap_lock.put_read(); uint64_t object_no = oid_to_object_no(oid.name, m_ictx->object_prefix); // reverse map this object extent onto the parent vector > objectx; Striper::extent_to_file(m_ictx->cct, &m_ictx->layout, object_no, 0, m_ictx->layout.fl_object_size, objectx); uint64_t object_overlap = m_ictx->prune_parent_extents(objectx, overlap); write_result_d *result = new write_result_d(oid.name, oncommit); m_writes[oid.name].push(result); ldout(m_ictx->cct, 20) << "write will wait for result " << result << dendl; C_OrderedWrite *req_comp = new C_OrderedWrite(m_ictx->cct, result, this); AioWrite *req = new AioWrite(m_ictx, oid.name, object_no, off, objectx, object_overlap, bl, snapc, snap_id, req_comp); req->send(); return ++m_tid; } void LibrbdWriteback::complete_writes(const std::string& oid) { assert(m_lock.is_locked()); std::queue& results = m_writes[oid]; ldout(m_ictx->cct, 20) << "complete_writes() oid " << oid << dendl; std::list finished; while (!results.empty()) { write_result_d *result = results.front(); if (!result->done) break; finished.push_back(result); results.pop(); } if (results.empty()) m_writes.erase(oid); for (std::list::iterator it = finished.begin(); it != finished.end(); ++it) { write_result_d *result = *it; ldout(m_ictx->cct, 20) << "complete_writes() completing " << result << dendl; result->oncommit->complete(result->ret); delete result; } } } ceph-0.80.11/src/librbd/LibrbdWriteback.h0000664000175100017510000000367412623076744022137 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_LIBRBDWRITEBACKHANDLER_H #define CEPH_LIBRBD_LIBRBDWRITEBACKHANDLER_H #include #include "include/Context.h" #include "include/types.h" #include "include/rados/librados.hpp" #include "osd/osd_types.h" #include "osdc/WritebackHandler.h" class Mutex; namespace librbd { struct ImageCtx; class LibrbdWriteback : public WritebackHandler { public: LibrbdWriteback(ImageCtx *ictx, Mutex& lock); virtual ~LibrbdWriteback() {} // Note that oloc, trunc_size, and trunc_seq are ignored virtual void read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snapid, bufferlist *pbl, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish); // Determine whether a read to this extent could be affected by a write-triggered copy-on-write virtual bool may_copy_on_write(const object_t& oid, uint64_t read_off, uint64_t read_len, snapid_t snapid); // Note that oloc, trunc_size, and trunc_seq are ignored virtual ceph_tid_t write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, uint64_t trunc_size, __u32 trunc_seq, Context *oncommit); struct write_result_d { bool done; int ret; std::string oid; Context *oncommit; write_result_d(const std::string& oid, Context *oncommit) : done(false), ret(0), oid(oid), oncommit(oncommit) {} private: write_result_d(const write_result_d& rhs); const write_result_d& operator=(const write_result_d& rhs); }; private: void complete_writes(const std::string& oid); ceph_tid_t m_tid; Mutex& m_lock; librbd::ImageCtx *m_ictx; ceph::unordered_map > m_writes; friend class C_OrderedWrite; }; } #endif ceph-0.80.11/src/librbd/AioCompletion.cc0000664000175100017510000001061312623076744021774 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "common/ceph_context.h" #include "common/dout.h" #include "common/errno.h" #include "librbd/AioRequest.h" #include "librbd/internal.h" #include "librbd/AioCompletion.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::AioCompletion: " namespace librbd { void AioCompletion::finish_adding_requests(CephContext *cct) { ldout(cct, 20) << "AioCompletion::finish_adding_requests " << (void*)this << " pending " << pending_count << dendl; lock.Lock(); assert(building); building = false; if (!pending_count) { finalize(cct, rval); complete(cct); } lock.Unlock(); } void AioCompletion::finalize(CephContext *cct, ssize_t rval) { ldout(cct, 20) << "AioCompletion::finalize() " << (void*)this << " rval " << rval << " read_buf " << (void*)read_buf << " read_bl " << (void*)read_bl << dendl; if (rval >= 0 && aio_type == AIO_TYPE_READ) { // FIXME: make the destriper write directly into a buffer so // that we avoid shuffling pointers and copying zeros around. bufferlist bl; destriper.assemble_result(cct, bl, true); if (read_buf) { assert(bl.length() == read_buf_len); bl.copy(0, read_buf_len, read_buf); ldout(cct, 20) << "AioCompletion::finalize() copied resulting " << bl.length() << " bytes to " << (void*)read_buf << dendl; } if (read_bl) { ldout(cct, 20) << "AioCompletion::finalize() moving resulting " << bl.length() << " bytes to bl " << (void*)read_bl << dendl; read_bl->claim(bl); } } } void AioCompletion::complete(CephContext *cct) { utime_t elapsed; assert(lock.is_locked()); elapsed = ceph_clock_now(cct) - start_time; switch (aio_type) { case AIO_TYPE_READ: ictx->perfcounter->tinc(l_librbd_aio_rd_latency, elapsed); break; case AIO_TYPE_WRITE: ictx->perfcounter->tinc(l_librbd_aio_wr_latency, elapsed); break; case AIO_TYPE_DISCARD: ictx->perfcounter->tinc(l_librbd_aio_discard_latency, elapsed); break; case AIO_TYPE_FLUSH: ictx->perfcounter->tinc(l_librbd_aio_flush_latency, elapsed); break; default: lderr(cct) << "completed invalid aio_type: " << aio_type << dendl; break; } if (ictx != NULL) { Mutex::Locker l(ictx->aio_lock); assert(ictx->pending_aio != 0); --ictx->pending_aio; ictx->pending_aio_cond.Signal(); } if (complete_cb) { complete_cb(rbd_comp, complete_arg); } done = true; cond.Signal(); } void AioCompletion::fail(CephContext *cct, int r) { lderr(cct) << "AioCompletion::fail() " << this << ": " << cpp_strerror(r) << dendl; lock.Lock(); assert(pending_count == 0); rval = r; complete(cct); put_unlock(); } void AioCompletion::complete_request(CephContext *cct, ssize_t r) { ldout(cct, 20) << "AioCompletion::complete_request() " << (void *)this << " complete_cb=" << (void *)complete_cb << " pending " << pending_count << dendl; lock.Lock(); if (rval >= 0) { if (r < 0 && r != -EEXIST) rval = r; else if (r > 0) rval += r; } assert(pending_count); int count = --pending_count; if (!count && !building) { finalize(cct, rval); complete(cct); } put_unlock(); } void C_AioRead::finish(int r) { ldout(m_cct, 10) << "C_AioRead::finish() " << this << " r = " << r << dendl; if (r >= 0 || r == -ENOENT) { // this was a sparse_read operation ldout(m_cct, 10) << " got " << m_req->m_ext_map << " for " << m_req->m_buffer_extents << " bl " << m_req->data().length() << dendl; // reads from the parent don't populate the m_ext_map and the overlap // may not be the full buffer. compensate here by filling in m_ext_map // with the read extent when it is empty. if (m_req->m_ext_map.empty()) m_req->m_ext_map[m_req->m_object_off] = m_req->data().length(); m_completion->lock.Lock(); m_completion->destriper.add_partial_sparse_result( m_cct, m_req->data(), m_req->m_ext_map, m_req->m_object_off, m_req->m_buffer_extents); m_completion->lock.Unlock(); r = m_req->m_object_len; } m_completion->complete_request(m_cct, r); } void C_CacheRead::finish(int r) { m_req->complete(r); } } ceph-0.80.11/src/librbd/librbd.cc0000664000175100017510000010503312623076744020471 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include #include "common/Cond.h" #include "common/dout.h" #include "common/errno.h" #include "common/snap_types.h" #include "common/perf_counters.h" #include "common/WorkQueue.h" #include "include/Context.h" #include "include/rbd/librbd.hpp" #include "osdc/ObjectCacher.h" #include "librbd/AioCompletion.h" #include "cls/rbd/cls_rbd_client.h" #include "librbd/ImageCtx.h" #include "librbd/internal.h" #include "librbd/LibrbdWriteback.h" #include #include #include #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd: " using std::string; using std::vector; using ceph::bufferlist; using librados::snap_t; using librados::IoCtx; namespace { class C_AioReadWQ : public Context { public: C_AioReadWQ(librbd::ImageCtx *ictx, uint64_t off, size_t len, char *buf, bufferlist *pbl, librbd::AioCompletion *c) : m_ictx(ictx), m_off(off), m_len(len), m_buf(buf), m_pbl(pbl), m_comp(c) { } protected: virtual void finish(int r) { librbd::aio_read(m_ictx, m_off, m_len, m_buf, m_pbl, m_comp); } private: librbd::ImageCtx *m_ictx; uint64_t m_off; uint64_t m_len; char *m_buf; bufferlist *m_pbl; librbd::AioCompletion *m_comp; }; class C_AioWriteWQ : public Context { public: C_AioWriteWQ(librbd::ImageCtx *ictx, uint64_t off, size_t len, const char *buf, librbd::AioCompletion *c) : m_ictx(ictx), m_off(off), m_len(len), m_buf(buf), m_comp(c) { } protected: virtual void finish(int r) { librbd::aio_write(m_ictx, m_off, m_len, m_buf, m_comp); } private: librbd::ImageCtx *m_ictx; uint64_t m_off; uint64_t m_len; const char *m_buf; librbd::AioCompletion *m_comp; }; class C_AioDiscardWQ : public Context { public: C_AioDiscardWQ(librbd::ImageCtx *ictx, uint64_t off, uint64_t len, librbd::AioCompletion *c) : m_ictx(ictx), m_off(off), m_len(len), m_comp(c) { } protected: virtual void finish(int r) { librbd::aio_discard(m_ictx, m_off, m_len, m_comp); } private: librbd::ImageCtx *m_ictx; uint64_t m_off; uint64_t m_len; librbd::AioCompletion *m_comp; }; class C_AioFlushWQ : public Context { public: C_AioFlushWQ(librbd::ImageCtx *ictx, librbd::AioCompletion *c) : m_ictx(ictx), m_comp(c) { } protected: virtual void finish(int r) { librbd::aio_flush(m_ictx, m_comp); } private: librbd::ImageCtx *m_ictx; librbd::AioCompletion *m_comp; }; void submit_aio_read(librbd::ImageCtx *ictx, uint64_t off, size_t len, char *buf, bufferlist *pbl, librbd::AioCompletion *c) { if (ictx->cct->_conf->rbd_non_blocking_aio) { ictx->aio_work_queue->queue(new C_AioReadWQ(ictx, off, len, buf, pbl, c)); } else { librbd::aio_read(ictx, off, len, buf, pbl, c); } } void submit_aio_write(librbd::ImageCtx *ictx, uint64_t off, size_t len, const char *buf, librbd::AioCompletion *c) { if (ictx->cct->_conf->rbd_non_blocking_aio) { ictx->aio_work_queue->queue(new C_AioWriteWQ(ictx, off, len, buf, c)); } else { librbd::aio_write(ictx, off, len, buf, c); } } void submit_aio_discard(librbd::ImageCtx *ictx, uint64_t off, uint64_t len, librbd::AioCompletion *c) { if (ictx->cct->_conf->rbd_non_blocking_aio) { ictx->aio_work_queue->queue(new C_AioDiscardWQ(ictx, off, len, c)); } else { librbd::aio_discard(ictx, off, len, c); } } void submit_aio_flush(librbd::ImageCtx *ictx, librbd::AioCompletion *c) { if (ictx->cct->_conf->rbd_non_blocking_aio) { ictx->aio_work_queue->queue(new C_AioFlushWQ(ictx, c)); } else { librbd::aio_flush(ictx, c); } } librbd::AioCompletion* get_aio_completion(librbd::RBD::AioCompletion *comp) { return reinterpret_cast(comp->pc); } } // anonymous namespace namespace librbd { ProgressContext::~ProgressContext() { } class CProgressContext : public ProgressContext { public: CProgressContext(librbd_progress_fn_t fn, void *data) : m_fn(fn), m_data(data) { } int update_progress(uint64_t offset, uint64_t src_size) { return m_fn(offset, src_size, m_data); } private: librbd_progress_fn_t m_fn; void *m_data; }; /* RBD */ RBD::RBD() { } RBD::~RBD() { } void RBD::version(int *major, int *minor, int *extra) { rbd_version(major, minor, extra); } int RBD::open(IoCtx& io_ctx, Image& image, const char *name) { return open(io_ctx, image, name, NULL); } int RBD::open(IoCtx& io_ctx, Image& image, const char *name, const char *snap_name) { ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, false); int r = librbd::open_image(ictx); if (r < 0) return r; image.ctx = (image_ctx_t) ictx; return 0; } int RBD::open_read_only(IoCtx& io_ctx, Image& image, const char *name, const char *snap_name) { ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, true); int r = librbd::open_image(ictx); if (r < 0) return r; image.ctx = (image_ctx_t) ictx; return 0; } int RBD::create(IoCtx& io_ctx, const char *name, uint64_t size, int *order) { return librbd::create(io_ctx, name, size, order); } int RBD::create2(IoCtx& io_ctx, const char *name, uint64_t size, uint64_t features, int *order) { return librbd::create(io_ctx, name, size, false, features, order, 0, 0); } int RBD::create3(IoCtx& io_ctx, const char *name, uint64_t size, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count) { return librbd::create(io_ctx, name, size, false, features, order, stripe_unit, stripe_count); } int RBD::clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name, IoCtx& c_ioctx, const char *c_name, uint64_t features, int *c_order) { return librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name, features, c_order, 0, 0); } int RBD::clone2(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name, IoCtx& c_ioctx, const char *c_name, uint64_t features, int *c_order, uint64_t stripe_unit, int stripe_count) { return librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name, features, c_order, stripe_unit, stripe_count); } int RBD::remove(IoCtx& io_ctx, const char *name) { librbd::NoOpProgressContext prog_ctx; int r = librbd::remove(io_ctx, name, prog_ctx); return r; } int RBD::remove_with_progress(IoCtx& io_ctx, const char *name, ProgressContext& pctx) { int r = librbd::remove(io_ctx, name, pctx); return r; } int RBD::list(IoCtx& io_ctx, vector& names) { int r = librbd::list(io_ctx, names); return r; } int RBD::rename(IoCtx& src_io_ctx, const char *srcname, const char *destname) { int r = librbd::rename(src_io_ctx, srcname, destname); return r; } RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb) { librbd::AioCompletion *c = librbd::aio_create_completion(cb_arg, complete_cb); pc = (void *)c; c->rbd_comp = this; } bool RBD::AioCompletion::is_complete() { librbd::AioCompletion *c = (librbd::AioCompletion *)pc; return c->is_complete(); } int RBD::AioCompletion::wait_for_complete() { librbd::AioCompletion *c = (librbd::AioCompletion *)pc; return c->wait_for_complete(); } ssize_t RBD::AioCompletion::get_return_value() { librbd::AioCompletion *c = (librbd::AioCompletion *)pc; return c->get_return_value(); } void RBD::AioCompletion::release() { librbd::AioCompletion *c = (librbd::AioCompletion *)pc; c->release(); delete this; } /* Image */ Image::Image() : ctx(NULL) { } Image::~Image() { if (ctx) { ImageCtx *ictx = (ImageCtx *)ctx; close_image(ictx); } } int Image::resize(uint64_t size) { ImageCtx *ictx = (ImageCtx *)ctx; librbd::NoOpProgressContext prog_ctx; return librbd::resize(ictx, size, prog_ctx); } int Image::resize_with_progress(uint64_t size, librbd::ProgressContext& pctx) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::resize(ictx, size, pctx); } int Image::stat(image_info_t& info, size_t infosize) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::info(ictx, info, infosize); } int Image::old_format(uint8_t *old) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::get_old_format(ictx, old); } int Image::size(uint64_t *size) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::get_size(ictx, size); } int Image::features(uint64_t *features) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::get_features(ictx, features); } uint64_t Image::get_stripe_unit() const { ImageCtx *ictx = (ImageCtx *)ctx; return ictx->get_stripe_unit(); } uint64_t Image::get_stripe_count() const { ImageCtx *ictx = (ImageCtx *)ctx; return ictx->get_stripe_count(); } int Image::overlap(uint64_t *overlap) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::get_overlap(ictx, overlap); } int Image::parent_info(string *parent_pool_name, string *parent_name, string *parent_snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::get_parent_info(ictx, parent_pool_name, parent_name, parent_snap_name); } int Image::copy(IoCtx& dest_io_ctx, const char *destname) { ImageCtx *ictx = (ImageCtx *)ctx; librbd::NoOpProgressContext prog_ctx; return librbd::copy(ictx, dest_io_ctx, destname, prog_ctx); } int Image::copy2(Image& dest) { ImageCtx *srcctx = (ImageCtx *)ctx; ImageCtx *destctx = (ImageCtx *)dest.ctx; librbd::NoOpProgressContext prog_ctx; return librbd::copy(srcctx, destctx, prog_ctx); } int Image::copy_with_progress(IoCtx& dest_io_ctx, const char *destname, librbd::ProgressContext &pctx) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::copy(ictx, dest_io_ctx, destname, pctx); } int Image::copy_with_progress2(Image& dest, librbd::ProgressContext &pctx) { ImageCtx *srcctx = (ImageCtx *)ctx; ImageCtx *destctx = (ImageCtx *)dest.ctx; return librbd::copy(srcctx, destctx, pctx); } int Image::flatten() { ImageCtx *ictx = (ImageCtx *)ctx; librbd::NoOpProgressContext prog_ctx; return librbd::flatten(ictx, prog_ctx); } int Image::flatten_with_progress(librbd::ProgressContext& prog_ctx) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::flatten(ictx, prog_ctx); } int Image::list_children(set > *children) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::list_children(ictx, *children); } int Image::list_lockers(std::list *lockers, bool *exclusive, string *tag) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::list_lockers(ictx, lockers, exclusive, tag); } int Image::lock_exclusive(const string& cookie) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::lock(ictx, true, cookie, ""); } int Image::lock_shared(const string& cookie, const std::string& tag) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::lock(ictx, false, cookie, tag); } int Image::unlock(const string& cookie) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::unlock(ictx, cookie); } int Image::break_lock(const string& client, const string& cookie) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::break_lock(ictx, client, cookie); } int Image::snap_create(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_create(ictx, snap_name); } int Image::snap_remove(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_remove(ictx, snap_name); } int Image::snap_rollback(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; librbd::NoOpProgressContext prog_ctx; return librbd::snap_rollback(ictx, snap_name, prog_ctx); } int Image::snap_rollback_with_progress(const char *snap_name, ProgressContext& prog_ctx) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_rollback(ictx, snap_name, prog_ctx); } int Image::snap_protect(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_protect(ictx, snap_name); } int Image::snap_unprotect(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_unprotect(ictx, snap_name); } int Image::snap_is_protected(const char *snap_name, bool *is_protected) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_is_protected(ictx, snap_name, is_protected); } int Image::snap_list(vector& snaps) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_list(ictx, snaps); } bool Image::snap_exists(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_exists(ictx, snap_name); } int Image::snap_set(const char *snap_name) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::snap_set(ictx, snap_name); } ssize_t Image::read(uint64_t ofs, size_t len, bufferlist& bl) { ImageCtx *ictx = (ImageCtx *)ctx; bufferptr ptr(len); bl.push_back(ptr); return librbd::read(ictx, ofs, len, bl.c_str()); } int64_t Image::read_iterate(uint64_t ofs, size_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::read_iterate(ictx, ofs, len, cb, arg); } int Image::read_iterate2(uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg) { ImageCtx *ictx = (ImageCtx *)ctx; int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg); if (r > 0) r = 0; return (int)r; } int Image::diff_iterate(const char *fromsnapname, uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, int, void *), void *arg) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::diff_iterate(ictx, fromsnapname, ofs, len, cb, arg); } ssize_t Image::write(uint64_t ofs, size_t len, bufferlist& bl) { ImageCtx *ictx = (ImageCtx *)ctx; if (bl.length() < len) return -EINVAL; return librbd::write(ictx, ofs, len, bl.c_str()); } int Image::discard(uint64_t ofs, uint64_t len) { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::discard(ictx, ofs, len); } int Image::aio_write(uint64_t off, size_t len, bufferlist& bl, RBD::AioCompletion *c) { ImageCtx *ictx = (ImageCtx *)ctx; if (bl.length() < len) return -EINVAL; submit_aio_write(ictx, off, len, bl.c_str(), get_aio_completion(c)); return 0; } int Image::aio_discard(uint64_t off, uint64_t len, RBD::AioCompletion *c) { ImageCtx *ictx = (ImageCtx *)ctx; submit_aio_discard(ictx, off, len, get_aio_completion(c)); return 0; } int Image::aio_read(uint64_t off, size_t len, bufferlist& bl, RBD::AioCompletion *c) { ImageCtx *ictx = (ImageCtx *)ctx; ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~" << (void *)(bl.c_str() + len - 1) << dendl; submit_aio_read(ictx, off, len, NULL, &bl, get_aio_completion(c)); return 0; } int Image::flush() { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::flush(ictx); } int Image::aio_flush(RBD::AioCompletion *c) { ImageCtx *ictx = (ImageCtx *)ctx; submit_aio_flush(ictx, get_aio_completion(c)); return 0; } int Image::invalidate_cache() { ImageCtx *ictx = (ImageCtx *)ctx; return librbd::invalidate_cache(ictx); } } // namespace librbd extern "C" void rbd_version(int *major, int *minor, int *extra) { if (major) *major = LIBRBD_VER_MAJOR; if (minor) *minor = LIBRBD_VER_MINOR; if (extra) *extra = LIBRBD_VER_EXTRA; } /* images */ extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); vector cpp_names; int r = librbd::list(io_ctx, cpp_names); if (r == -ENOENT) return 0; if (r < 0) return r; size_t expected_size = 0; for (size_t i = 0; i < cpp_names.size(); i++) { expected_size += cpp_names[i].size() + 1; } if (*size < expected_size) { *size = expected_size; return -ERANGE; } for (int i = 0; i < (int)cpp_names.size(); i++) { strcpy(names, cpp_names[i].c_str()); names += strlen(names) + 1; } return (int)expected_size; } extern "C" int rbd_create(rados_ioctx_t p, const char *name, uint64_t size, int *order) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); return librbd::create(io_ctx, name, size, order); } extern "C" int rbd_create2(rados_ioctx_t p, const char *name, uint64_t size, uint64_t features, int *order) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); return librbd::create(io_ctx, name, size, false, features, order, 0, 0); } extern "C" int rbd_create3(rados_ioctx_t p, const char *name, uint64_t size, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); return librbd::create(io_ctx, name, size, false, features, order, stripe_unit, stripe_count); } extern "C" int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name, const char *p_snap_name, rados_ioctx_t c_ioctx, const char *c_name, uint64_t features, int *c_order) { librados::IoCtx p_ioc, c_ioc; librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc); librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc); return librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name, features, c_order, 0, 0); } extern "C" int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name, const char *p_snap_name, rados_ioctx_t c_ioctx, const char *c_name, uint64_t features, int *c_order, uint64_t stripe_unit, int stripe_count) { librados::IoCtx p_ioc, c_ioc; librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc); librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc); return librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name, features, c_order, stripe_unit, stripe_count); } extern "C" int rbd_remove(rados_ioctx_t p, const char *name) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); librbd::NoOpProgressContext prog_ctx; return librbd::remove(io_ctx, name, prog_ctx); } extern "C" int rbd_remove_with_progress(rados_ioctx_t p, const char *name, librbd_progress_fn_t cb, void *cbdata) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); librbd::CProgressContext prog_ctx(cb, cbdata); return librbd::remove(io_ctx, name, prog_ctx); } extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p, const char *destname) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librados::IoCtx dest_io_ctx; librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx); librbd::NoOpProgressContext prog_ctx; return librbd::copy(ictx, dest_io_ctx, destname, prog_ctx); } extern "C" int rbd_copy2(rbd_image_t srcp, rbd_image_t destp) { librbd::ImageCtx *src = (librbd::ImageCtx *)srcp; librbd::ImageCtx *dest = (librbd::ImageCtx *)destp; librbd::NoOpProgressContext prog_ctx; return librbd::copy(src, dest, prog_ctx); } extern "C" int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p, const char *destname, librbd_progress_fn_t fn, void *data) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librados::IoCtx dest_io_ctx; librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx); librbd::CProgressContext prog_ctx(fn, data); int ret = librbd::copy(ictx, dest_io_ctx, destname, prog_ctx); return ret; } extern "C" int rbd_copy_with_progress2(rbd_image_t srcp, rbd_image_t destp, librbd_progress_fn_t fn, void *data) { librbd::ImageCtx *src = (librbd::ImageCtx *)srcp; librbd::ImageCtx *dest = (librbd::ImageCtx *)destp; librbd::CProgressContext prog_ctx(fn, data); int ret = librbd::copy(src, dest, prog_ctx); return ret; } extern "C" int rbd_flatten(rbd_image_t image) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::NoOpProgressContext prog_ctx; return librbd::flatten(ictx, prog_ctx); } extern "C" int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb, void *cbdata) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::CProgressContext prog_ctx(cb, cbdata); return librbd::flatten(ictx, prog_ctx); } extern "C" int rbd_rename(rados_ioctx_t src_p, const char *srcname, const char *destname) { librados::IoCtx src_io_ctx; librados::IoCtx::from_rados_ioctx_t(src_p, src_io_ctx); return librbd::rename(src_io_ctx, srcname, destname); } extern "C" int rbd_open(rados_ioctx_t p, const char *name, rbd_image_t *image, const char *snap_name) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx, false); int r = librbd::open_image(ictx); if (r >= 0) *image = (rbd_image_t)ictx; return r; } extern "C" int rbd_open_read_only(rados_ioctx_t p, const char *name, rbd_image_t *image, const char *snap_name) { librados::IoCtx io_ctx; librados::IoCtx::from_rados_ioctx_t(p, io_ctx); librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx, true); int r = librbd::open_image(ictx); if (r >= 0) *image = (rbd_image_t)ictx; return r; } extern "C" int rbd_close(rbd_image_t image) { librbd::ImageCtx *ctx = (librbd::ImageCtx *)image; librbd::close_image(ctx); return 0; } extern "C" int rbd_resize(rbd_image_t image, uint64_t size) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::NoOpProgressContext prog_ctx; return librbd::resize(ictx, size, prog_ctx); } extern "C" int rbd_resize_with_progress(rbd_image_t image, uint64_t size, librbd_progress_fn_t cb, void *cbdata) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::CProgressContext prog_ctx(cb, cbdata); return librbd::resize(ictx, size, prog_ctx); } extern "C" int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::info(ictx, *info, infosize); } extern "C" int rbd_get_old_format(rbd_image_t image, uint8_t *old) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::get_old_format(ictx, old); } extern "C" int rbd_get_size(rbd_image_t image, uint64_t *size) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::get_size(ictx, size); } extern "C" int rbd_get_features(rbd_image_t image, uint64_t *features) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::get_features(ictx, features); } extern "C" int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; *stripe_unit = ictx->get_stripe_unit(); return 0; } extern "C" int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; *stripe_count = ictx->get_stripe_count(); return 0; } extern "C" int rbd_get_overlap(rbd_image_t image, uint64_t *overlap) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::get_overlap(ictx, overlap); } extern "C" int rbd_get_parent_info(rbd_image_t image, char *parent_pool_name, size_t ppool_namelen, char *parent_name, size_t pnamelen, char *parent_snap_name, size_t psnap_namelen) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; string p_pool_name, p_name, p_snap_name; int r = librbd::get_parent_info(ictx, &p_pool_name, &p_name, &p_snap_name); if (r < 0) return r; // compare against input bufferlen, leaving room for \0 if (p_pool_name.length() + 1 > ppool_namelen || p_name.length() + 1 > pnamelen || p_snap_name.length() + 1 > psnap_namelen) { return -ERANGE; } strcpy(parent_pool_name, p_pool_name.c_str()); strcpy(parent_name, p_name.c_str()); strcpy(parent_snap_name, p_snap_name.c_str()); return 0; } /* snapshots */ extern "C" int rbd_snap_create(rbd_image_t image, const char *snap_name) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::snap_create(ictx, snap_name); } extern "C" int rbd_snap_remove(rbd_image_t image, const char *snap_name) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::snap_remove(ictx, snap_name); } extern "C" int rbd_snap_rollback(rbd_image_t image, const char *snap_name) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::NoOpProgressContext prog_ctx; return librbd::snap_rollback(ictx, snap_name, prog_ctx); } extern "C" int rbd_snap_rollback_with_progress(rbd_image_t image, const char *snap_name, librbd_progress_fn_t cb, void *cbdata) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::CProgressContext prog_ctx(cb, cbdata); return librbd::snap_rollback(ictx, snap_name, prog_ctx); } extern "C" int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps, int *max_snaps) { vector cpp_snaps; librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; int r = librbd::snap_list(ictx, cpp_snaps); if (r == -ENOENT) return 0; if (r < 0) return r; if (!max_snaps) return -EINVAL; if (*max_snaps < (int)cpp_snaps.size() + 1) { *max_snaps = (int)cpp_snaps.size() + 1; return -ERANGE; } int i; for (i = 0; i < (int)cpp_snaps.size(); i++) { snaps[i].id = cpp_snaps[i].id; snaps[i].size = cpp_snaps[i].size; snaps[i].name = strdup(cpp_snaps[i].name.c_str()); if (!snaps[i].name) { for (int j = 0; j < i; j++) free((void *)snaps[j].name); return -ENOMEM; } } snaps[i].id = 0; snaps[i].size = 0; snaps[i].name = NULL; return (int)cpp_snaps.size(); } extern "C" void rbd_snap_list_end(rbd_snap_info_t *snaps) { while (snaps->name) { free((void *)snaps->name); snaps++; } } extern "C" int rbd_snap_protect(rbd_image_t image, const char *snap_name) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::snap_protect(ictx, snap_name); } extern "C" int rbd_snap_unprotect(rbd_image_t image, const char *snap_name) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::snap_unprotect(ictx, snap_name); } extern "C" int rbd_snap_is_protected(rbd_image_t image, const char *snap_name, int *is_protected) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; bool protected_snap; int r = librbd::snap_is_protected(ictx, snap_name, &protected_snap); if (r < 0) return r; *is_protected = protected_snap ? 1 : 0; return 0; } extern "C" int rbd_snap_set(rbd_image_t image, const char *snap_name) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::snap_set(ictx, snap_name); } extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools, size_t *pools_len, char *images, size_t *images_len) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; set > image_set; int r = librbd::list_children(ictx, image_set); if (r < 0) return r; size_t pools_total = 0; size_t images_total = 0; for (set >::const_iterator it = image_set.begin(); it != image_set.end(); ++it) { pools_total += it->first.length() + 1; images_total += it->second.length() + 1; } bool too_short = false; if (pools_total > *pools_len) too_short = true; if (images_total > *images_len) too_short = true; *pools_len = pools_total; *images_len = images_total; if (too_short) return -ERANGE; char *pools_p = pools; char *images_p = images; for (set >::const_iterator it = image_set.begin(); it != image_set.end(); ++it) { strcpy(pools_p, it->first.c_str()); pools_p += it->first.length() + 1; strcpy(images_p, it->second.c_str()); images_p += it->second.length() + 1; } return image_set.size(); } extern "C" ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive, char *tag, size_t *tag_len, char *clients, size_t *clients_len, char *cookies, size_t *cookies_len, char *addrs, size_t *addrs_len) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; std::list lockers; bool exclusive_bool; string tag_str; int r = list_lockers(ictx, &lockers, &exclusive_bool, &tag_str); if (r < 0) return r; ldout(ictx->cct, 20) << "list_lockers r = " << r << " lockers.size() = " << lockers.size() << dendl; *exclusive = (int)exclusive_bool; size_t clients_total = 0; size_t cookies_total = 0; size_t addrs_total = 0; for (list::const_iterator it = lockers.begin(); it != lockers.end(); ++it) { clients_total += it->client.length() + 1; cookies_total += it->cookie.length() + 1; addrs_total += it->address.length() + 1; } bool too_short = ((clients_total > *clients_len) || (cookies_total > *cookies_len) || (addrs_total > *addrs_len) || (tag_str.length() + 1 > *tag_len)); *clients_len = clients_total; *cookies_len = cookies_total; *addrs_len = addrs_total; *tag_len = tag_str.length() + 1; if (too_short) return -ERANGE; strcpy(tag, tag_str.c_str()); char *clients_p = clients; char *cookies_p = cookies; char *addrs_p = addrs; for (list::const_iterator it = lockers.begin(); it != lockers.end(); ++it) { strcpy(clients_p, it->client.c_str()); clients_p += it->client.length() + 1; strcpy(cookies_p, it->cookie.c_str()); cookies_p += it->cookie.length() + 1; strcpy(addrs_p, it->address.c_str()); addrs_p += it->address.length() + 1; } return lockers.size(); } extern "C" int rbd_lock_exclusive(rbd_image_t image, const char *cookie) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::lock(ictx, true, cookie ? cookie : "", ""); } extern "C" int rbd_lock_shared(rbd_image_t image, const char *cookie, const char *tag) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::lock(ictx, false, cookie ? cookie : "", tag ? tag : ""); } extern "C" int rbd_unlock(rbd_image_t image, const char *cookie) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::unlock(ictx, cookie ? cookie : ""); } extern "C" int rbd_break_lock(rbd_image_t image, const char *client, const char *cookie) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::break_lock(ictx, client, cookie ? cookie : ""); } /* I/O */ extern "C" ssize_t rbd_read(rbd_image_t image, uint64_t ofs, size_t len, char *buf) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::read(ictx, ofs, len, buf); } extern "C" int64_t rbd_read_iterate(rbd_image_t image, uint64_t ofs, size_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::read_iterate(ictx, ofs, len, cb, arg); } extern "C" int rbd_read_iterate2(rbd_image_t image, uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg); if (r > 0) r = 0; return (int)r; } extern "C" int rbd_diff_iterate(rbd_image_t image, const char *fromsnapname, uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, int, void *), void *arg) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::diff_iterate(ictx, fromsnapname, ofs, len, cb, arg); } extern "C" ssize_t rbd_write(rbd_image_t image, uint64_t ofs, size_t len, const char *buf) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::write(ictx, ofs, len, buf); } extern "C" int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::discard(ictx, ofs, len); } extern "C" int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb, rbd_completion_t *c) { librbd::RBD::AioCompletion *rbd_comp = new librbd::RBD::AioCompletion(cb_arg, complete_cb); *c = (rbd_completion_t) rbd_comp; return 0; } extern "C" int rbd_aio_write(rbd_image_t image, uint64_t off, size_t len, const char *buf, rbd_completion_t c) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; submit_aio_write(ictx, off, len, buf, get_aio_completion(comp)); return 0; } extern "C" int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len, rbd_completion_t c) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; submit_aio_discard(ictx, off, len, get_aio_completion(comp)); return 0; } extern "C" int rbd_aio_read(rbd_image_t image, uint64_t off, size_t len, char *buf, rbd_completion_t c) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; submit_aio_read(ictx, off, len, buf, NULL, get_aio_completion(comp)); return 0; } extern "C" int rbd_flush(rbd_image_t image) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::flush(ictx); } extern "C" int rbd_aio_flush(rbd_image_t image, rbd_completion_t c) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; submit_aio_flush(ictx, get_aio_completion(comp)); return 0; } extern "C" int rbd_invalidate_cache(rbd_image_t image) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; return librbd::invalidate_cache(ictx); } extern "C" int rbd_aio_is_complete(rbd_completion_t c) { librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; return comp->is_complete(); } extern "C" int rbd_aio_wait_for_complete(rbd_completion_t c) { librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; return comp->wait_for_complete(); } extern "C" ssize_t rbd_aio_get_return_value(rbd_completion_t c) { librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; return comp->get_return_value(); } extern "C" void rbd_aio_release(rbd_completion_t c) { librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c; comp->release(); } ceph-0.80.11/src/librbd/SnapInfo.h0000664000175100017510000000132012623076744020604 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_SNAPINFO_H #define CEPH_LIBRBD_SNAPINFO_H #include "include/int_types.h" #include "include/rados/librados.hpp" #include "cls/rbd/cls_rbd_client.h" #include "librbd/parent_types.h" namespace librbd { struct SnapInfo { librados::snap_t id; uint64_t size; uint64_t features; parent_info parent; uint8_t protection_status; SnapInfo(librados::snap_t _id, uint64_t _size, uint64_t _features, parent_info _parent, uint8_t _protection_status) : id(_id), size(_size), features(_features), parent(_parent), protection_status(_protection_status) {} }; } #endif ceph-0.80.11/src/librbd/internal.h0000664000175100017510000001776612623076744020730 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_INTERNAL_H #define CEPH_LIBRBD_INTERNAL_H #include "include/int_types.h" #include #include #include #include #include "include/buffer.h" #include "include/rbd/librbd.hpp" #include "include/rbd_types.h" enum { l_librbd_first = 26000, l_librbd_rd, // read ops l_librbd_rd_bytes, // bytes read l_librbd_rd_latency, // average latency l_librbd_wr, l_librbd_wr_bytes, l_librbd_wr_latency, l_librbd_discard, l_librbd_discard_bytes, l_librbd_discard_latency, l_librbd_flush, l_librbd_aio_rd, // read ops l_librbd_aio_rd_bytes, // bytes read l_librbd_aio_rd_latency, l_librbd_aio_wr, l_librbd_aio_wr_bytes, l_librbd_aio_wr_latency, l_librbd_aio_discard, l_librbd_aio_discard_bytes, l_librbd_aio_discard_latency, l_librbd_aio_flush, l_librbd_aio_flush_latency, l_librbd_snap_create, l_librbd_snap_remove, l_librbd_snap_rollback, l_librbd_notify, l_librbd_resize, l_librbd_last, }; namespace librbd { struct AioCompletion; struct ImageCtx; class NoOpProgressContext : public ProgressContext { public: NoOpProgressContext() { } int update_progress(uint64_t offset, uint64_t src_size) { return 0; } }; const std::string id_obj_name(const std::string &name); const std::string header_name(const std::string &image_id); const std::string old_header_name(const std::string &image_name); int detect_format(librados::IoCtx &io_ctx, const std::string &name, bool *old_format, uint64_t *size); bool has_parent(int64_t parent_pool_id, uint64_t off, uint64_t overlap); int snap_set(ImageCtx *ictx, const char *snap_name); int list(librados::IoCtx& io_ctx, std::vector& names); int list_children(ImageCtx *ictx, std::set > & names); int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, int *order); int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, bool old_format, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count); int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name, IoCtx& c_ioctx, const char *c_name, uint64_t features, int *c_order, uint64_t stripe_unit, int stripe_count); int rename(librados::IoCtx& io_ctx, const char *srcname, const char *dstname); int info(ImageCtx *ictx, image_info_t& info, size_t image_size); int get_old_format(ImageCtx *ictx, uint8_t *old); int get_size(ImageCtx *ictx, uint64_t *size); int get_features(ImageCtx *ictx, uint64_t *features); int get_overlap(ImageCtx *ictx, uint64_t *overlap); int get_parent_info(ImageCtx *ictx, string *parent_pool_name, string *parent_name, string *parent_snap_name); int remove(librados::IoCtx& io_ctx, const char *imgname, ProgressContext& prog_ctx); int resize(ImageCtx *ictx, uint64_t size, ProgressContext& prog_ctx); int resize_helper(ImageCtx *ictx, uint64_t size, ProgressContext& prog_ctx); int snap_create(ImageCtx *ictx, const char *snap_name); int snap_list(ImageCtx *ictx, std::vector& snaps); bool snap_exists(ImageCtx *ictx, const char *snap_name); int snap_rollback(ImageCtx *ictx, const char *snap_name, ProgressContext& prog_ctx); int snap_remove(ImageCtx *ictx, const char *snap_name); int snap_protect(ImageCtx *ictx, const char *snap_name); int snap_unprotect(ImageCtx *ictx, const char *snap_name); int snap_is_protected(ImageCtx *ictx, const char *snap_name, bool *is_protected); int add_snap(ImageCtx *ictx, const char *snap_name); int rm_snap(ImageCtx *ictx, const char *snap_name); int refresh_parent(ImageCtx *ictx); int ictx_check(ImageCtx *ictx); int ictx_refresh(ImageCtx *ictx); int copy(ImageCtx *ictx, IoCtx& dest_md_ctx, const char *destname, ProgressContext &prog_ctx); int copy(ImageCtx *src, ImageCtx *dest, ProgressContext &prog_ctx); int open_parent(ImageCtx *ictx); int open_image(ImageCtx *ictx); void close_image(ImageCtx *ictx); int copyup_block(ImageCtx *ictx, uint64_t offset, size_t len, const char *buf); int flatten(ImageCtx *ictx, ProgressContext &prog_ctx); /* cooperative locking */ int list_lockers(ImageCtx *ictx, std::list *locks, bool *exclusive, std::string *tag); int lock(ImageCtx *ictx, bool exclusive, const std::string& cookie, const std::string& tag); int lock_shared(ImageCtx *ictx, const std::string& cookie, const std::string& tag); int unlock(ImageCtx *ictx, const std::string& cookie); int break_lock(ImageCtx *ictx, const std::string& client, const std::string& cookie); void trim_image(ImageCtx *ictx, uint64_t newsize, ProgressContext& prog_ctx); int read_rbd_info(librados::IoCtx& io_ctx, const std::string& info_oid, struct rbd_info *info); int read_header_bl(librados::IoCtx& io_ctx, const std::string& md_oid, ceph::bufferlist& header, uint64_t *ver); int notify_change(librados::IoCtx& io_ctx, const std::string& oid, uint64_t *pver, ImageCtx *ictx); int read_header(librados::IoCtx& io_ctx, const std::string& md_oid, struct rbd_obj_header_ondisk *header, uint64_t *ver); int write_header(librados::IoCtx& io_ctx, const std::string& md_oid, ceph::bufferlist& header); int tmap_set(librados::IoCtx& io_ctx, const std::string& imgname); int tmap_rm(librados::IoCtx& io_ctx, const std::string& imgname); int rollback_image(ImageCtx *ictx, uint64_t snap_id, ProgressContext& prog_ctx); void image_info(const ImageCtx *ictx, image_info_t& info, size_t info_size); std::string get_block_oid(const std::string &object_prefix, uint64_t num, bool old_format); uint64_t oid_to_object_no(const string& oid, const string& object_prefix); int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len); int init_rbd_info(struct rbd_info *info); void init_rbd_header(struct rbd_obj_header_ondisk& ondisk, uint64_t size, int order, uint64_t bid); int64_t read_iterate(ImageCtx *ictx, uint64_t off, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg); int diff_iterate(ImageCtx *ictx, const char *fromsnapname, uint64_t off, uint64_t len, int (*cb)(uint64_t, size_t, int, void *), void *arg); ssize_t read(ImageCtx *ictx, uint64_t off, size_t len, char *buf); ssize_t read(ImageCtx *ictx, const vector >& image_extents, char *buf, bufferlist *pbl); ssize_t write(ImageCtx *ictx, uint64_t off, size_t len, const char *buf); int discard(ImageCtx *ictx, uint64_t off, uint64_t len); void aio_write(ImageCtx *ictx, uint64_t off, size_t len, const char *buf, AioCompletion *c); void aio_discard(ImageCtx *ictx, uint64_t off, uint64_t len, AioCompletion *c); void aio_read(ImageCtx *ictx, uint64_t off, size_t len, char *buf, bufferlist *pbl, AioCompletion *c); void aio_read(ImageCtx *ictx, const vector >& image_extents, char *buf, bufferlist *pbl, AioCompletion *c); void aio_flush(ImageCtx *ictx, AioCompletion *c); int flush(ImageCtx *ictx); int _flush(ImageCtx *ictx); int invalidate_cache(ImageCtx *ictx); ssize_t handle_sparse_read(CephContext *cct, ceph::bufferlist data_bl, uint64_t block_ofs, const std::map &data_map, uint64_t buf_ofs, size_t buf_len, char *dest_buf); AioCompletion *aio_create_completion(); AioCompletion *aio_create_completion(void *cb_arg, callback_t cb_complete); AioCompletion *aio_create_completion_internal(void *cb_arg, callback_t cb_complete); // raw callbacks int simple_read_cb(uint64_t ofs, size_t len, const char *buf, void *arg); void rados_req_cb(rados_completion_t cb, void *arg); void rados_ctx_cb(rados_completion_t cb, void *arg); void rbd_req_cb(completion_t cb, void *arg); void rbd_ctx_cb(completion_t cb, void *arg); } #endif ceph-0.80.11/src/librbd/AioRequest.cc0000664000175100017510000001771612623076744021326 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/ceph_context.h" #include "common/dout.h" #include "common/Mutex.h" #include "common/RWLock.h" #include "librbd/AioCompletion.h" #include "librbd/ImageCtx.h" #include "librbd/internal.h" #include "librbd/AioRequest.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::AioRequest: " namespace librbd { AioRequest::AioRequest() : m_ictx(NULL), m_ioctx(NULL), m_object_no(0), m_object_off(0), m_object_len(0), m_snap_id(CEPH_NOSNAP), m_completion(NULL), m_parent_completion(NULL), m_hide_enoent(false) {} AioRequest::AioRequest(ImageCtx *ictx, const std::string &oid, uint64_t objectno, uint64_t off, uint64_t len, librados::snap_t snap_id, Context *completion, bool hide_enoent) : m_ictx(ictx), m_ioctx(&ictx->data_ctx), m_oid(oid), m_object_no(objectno), m_object_off(off), m_object_len(len), m_snap_id(snap_id), m_completion(completion), m_parent_completion(NULL), m_hide_enoent(hide_enoent) {} AioRequest::~AioRequest() { if (m_parent_completion) { m_parent_completion->release(); m_parent_completion = NULL; } } void AioRequest::read_from_parent(vector >& image_extents) { assert(!m_parent_completion); m_parent_completion = aio_create_completion_internal(this, rbd_req_cb); ldout(m_ictx->cct, 20) << "read_from_parent this = " << this << " parent completion " << m_parent_completion << " extents " << image_extents << dendl; aio_read(m_ictx->parent, image_extents, NULL, &m_read_data, m_parent_completion); } /** read **/ bool AioRead::should_complete(int r) { ldout(m_ictx->cct, 20) << "should_complete " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len << " r = " << r << dendl; if (!m_tried_parent && r == -ENOENT) { RWLock::RLocker l(m_ictx->snap_lock); RWLock::RLocker l2(m_ictx->parent_lock); // calculate reverse mapping onto the image vector > image_extents; Striper::extent_to_file(m_ictx->cct, &m_ictx->layout, m_object_no, m_object_off, m_object_len, image_extents); uint64_t image_overlap = 0; r = m_ictx->get_parent_overlap(m_snap_id, &image_overlap); if (r < 0) { assert(0 == "FIXME"); } uint64_t object_overlap = m_ictx->prune_parent_extents(image_extents, image_overlap); if (object_overlap) { m_tried_parent = true; read_from_parent(image_extents); return false; } } return true; } void AioRead::send() { ldout(m_ictx->cct, 20) << "send " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len << dendl; librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(this, rados_req_cb, NULL); int r; librados::ObjectReadOperation op; int flags = m_ictx->get_read_flags(m_snap_id); if (m_sparse) { op.sparse_read(m_object_off, m_object_len, &m_ext_map, &m_read_data, NULL); } else { op.read(m_object_off, m_object_len, &m_read_data, NULL); } r = m_ioctx->aio_operate(m_oid, rados_completion, &op, flags, NULL); assert(r == 0); rados_completion->release(); } /** write **/ AbstractWrite::AbstractWrite() : m_state(LIBRBD_AIO_WRITE_FLAT), m_parent_overlap(0), m_snap_seq(0) {} AbstractWrite::AbstractWrite(ImageCtx *ictx, const std::string &oid, uint64_t object_no, uint64_t object_off, uint64_t len, vector >& objectx, uint64_t object_overlap, const ::SnapContext &snapc, librados::snap_t snap_id, Context *completion, bool hide_enoent) : AioRequest(ictx, oid, object_no, object_off, len, snap_id, completion, hide_enoent), m_state(LIBRBD_AIO_WRITE_FLAT), m_snap_seq(snapc.seq.val) { m_object_image_extents = objectx; m_parent_overlap = object_overlap; // TODO: find a way to make this less stupid for (std::vector::const_iterator it = snapc.snaps.begin(); it != snapc.snaps.end(); ++it) { m_snaps.push_back(it->val); } } void AbstractWrite::guard_write() { if (has_parent()) { m_state = LIBRBD_AIO_WRITE_GUARD; m_write.assert_exists(); ldout(m_ictx->cct, 20) << __func__ << " guarding write" << dendl; } } bool AbstractWrite::should_complete(int r) { ldout(m_ictx->cct, 20) << "write " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len << " should_complete: r = " << r << dendl; bool finished = true; switch (m_state) { case LIBRBD_AIO_WRITE_GUARD: ldout(m_ictx->cct, 20) << "WRITE_CHECK_GUARD" << dendl; if (r == -ENOENT) { RWLock::RLocker l(m_ictx->snap_lock); RWLock::RLocker l2(m_ictx->parent_lock); /* * Parent may have disappeared; if so, recover by using * send_copyup() to send the original write req (the copyup * operation itself will be a no-op, since someone must have * populated the child object while we weren't looking). * Move to WRITE_FLAT state as we'll be done with the * operation once the null copyup completes. */ if (m_ictx->parent == NULL) { ldout(m_ictx->cct, 20) << "parent is gone; do null copyup " << dendl; m_state = LIBRBD_AIO_WRITE_FLAT; send_copyup(); finished = false; break; } // If parent still exists, overlap might also have changed. uint64_t newlen = m_ictx->prune_parent_extents( m_object_image_extents, m_ictx->parent_md.overlap); // copyup the entire object up to the overlap point, if any if (newlen != 0) { ldout(m_ictx->cct, 20) << "should_complete(" << this << ") overlap " << m_ictx->parent_md.overlap << " newlen " << newlen << " image_extents" << m_object_image_extents << dendl; m_state = LIBRBD_AIO_WRITE_COPYUP; read_from_parent(m_object_image_extents); } else { ldout(m_ictx->cct, 20) << "should_complete(" << this << "): parent overlap now 0" << dendl; m_object_image_extents.clear(); m_state = LIBRBD_AIO_WRITE_FLAT; send_copyup(); } finished = false; break; } if (r < 0) { ldout(m_ictx->cct, 20) << "error checking for object existence" << dendl; break; } break; case LIBRBD_AIO_WRITE_COPYUP: ldout(m_ictx->cct, 20) << "WRITE_COPYUP" << dendl; m_state = LIBRBD_AIO_WRITE_GUARD; if (r < 0) return should_complete(r); send_copyup(); finished = false; break; case LIBRBD_AIO_WRITE_FLAT: ldout(m_ictx->cct, 20) << "WRITE_FLAT" << dendl; // nothing to do break; default: lderr(m_ictx->cct) << "invalid request state: " << m_state << dendl; assert(0); } return finished; } void AbstractWrite::send() { ldout(m_ictx->cct, 20) << "send " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len << dendl; librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(this, NULL, rados_req_cb); int r; assert(m_write.size()); r = m_ioctx->aio_operate(m_oid, rados_completion, &m_write, m_snap_seq, m_snaps); assert(r == 0); rados_completion->release(); } void AbstractWrite::send_copyup() { ldout(m_ictx->cct, 20) << "send_copyup " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len << dendl; if (!m_read_data.is_zero()) m_copyup.exec("rbd", "copyup", m_read_data); add_copyup_ops(); librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(this, NULL, rados_req_cb); m_ictx->md_ctx.aio_operate(m_oid, rados_completion, &m_copyup, m_snap_seq, m_snaps); rados_completion->release(); } void AioWrite::add_write_ops(librados::ObjectWriteOperation &wr) { wr.set_alloc_hint(m_ictx->get_object_size(), m_ictx->get_object_size()); wr.write(m_object_off, m_write_data); } } ceph-0.80.11/src/librbd/WatchCtx.h0000664000175100017510000000131312623076744020616 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_WATCHCTX_H #define CEPH_LIBRBD_WATCHCTX_H #include "include/int_types.h" #include "common/Mutex.h" #include "include/buffer.h" #include "include/rados/librados.hpp" class ImageCtx; namespace librbd { class WatchCtx : public librados::WatchCtx { ImageCtx *ictx; bool valid; Mutex lock; public: uint64_t cookie; WatchCtx(ImageCtx *ctx) : ictx(ctx), valid(true), lock("librbd::WatchCtx"), cookie(0) {} virtual ~WatchCtx() {} void invalidate(); virtual void notify(uint8_t opcode, uint64_t ver, ceph::bufferlist& bl); }; } #endif ceph-0.80.11/src/librbd/ImageCtx.h0000664000175100017510000001247312623076744020603 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_IMAGECTX_H #define CEPH_LIBRBD_IMAGECTX_H #include "include/int_types.h" #include #include #include #include #include "common/Cond.h" #include "common/Mutex.h" #include "common/RWLock.h" #include "common/snap_types.h" #include "include/buffer.h" #include "include/rbd/librbd.hpp" #include "include/rbd_types.h" #include "include/types.h" #include "osdc/ObjectCacher.h" #include "cls/rbd/cls_rbd_client.h" #include "librbd/LibrbdWriteback.h" #include "librbd/SnapInfo.h" #include "librbd/parent_types.h" class CephContext; class ContextWQ; class PerfCounters; namespace librbd { class WatchCtx; struct ImageCtx { CephContext *cct; PerfCounters *perfcounter; struct rbd_obj_header_ondisk header; ::SnapContext snapc; std::vector snaps; // this mirrors snapc.snaps, but is in // a format librados can understand std::map snaps_by_name; uint64_t snap_id; bool snap_exists; // false if our snap_id was deleted // whether the image was opened read-only. cannot be changed after opening bool read_only; bool flush_encountered; std::map lockers; bool exclusive_locked; std::string lock_tag; std::string name; std::string snap_name; IoCtx data_ctx, md_ctx; WatchCtx *wctx; int refresh_seq; ///< sequence for refresh requests int last_refresh; ///< last completed refresh /** * Lock ordering: * md_lock, cache_lock, snap_lock, parent_lock, refresh_lock, * aio_lock */ RWLock md_lock; // protects access to the mutable image metadata that // isn't guarded by other locks below // (size, features, image locks, etc) Mutex cache_lock; // used as client_lock for the ObjectCacher RWLock snap_lock; // protects snapshot-related member variables: RWLock parent_lock; // protects parent_md and parent Mutex refresh_lock; // protects refresh_seq and last_refresh Mutex aio_lock; // protects pending_aio and pending_aio_cond unsigned extra_read_flags; bool old_format; uint8_t order; uint64_t size; uint64_t features; std::string object_prefix; char *format_string; std::string header_oid; std::string id; // only used for new-format images parent_info parent_md; ImageCtx *parent; uint64_t stripe_unit, stripe_count; ceph_file_layout layout; ObjectCacher *object_cacher; LibrbdWriteback *writeback_handler; ObjectCacher::ObjectSet *object_set; Cond pending_aio_cond; uint64_t pending_aio; ContextWQ *aio_work_queue; /** * Either image_name or image_id must be set. * If id is not known, pass the empty std::string, * and init() will look it up. */ ImageCtx(const std::string &image_name, const std::string &image_id, const char *snap, IoCtx& p, bool read_only); ~ImageCtx(); int init(); void init_layout(); void perf_start(std::string name); void perf_stop(); void set_read_flag(unsigned flag); int get_read_flags(librados::snap_t snap_id); int snap_set(std::string in_snap_name); void snap_unset(); librados::snap_t get_snap_id(std::string in_snap_name) const; int get_snap_name(snapid_t snap_id, std::string *out_snap_name) const; int get_parent_spec(snapid_t snap_id, parent_spec *pspec); int is_snap_protected(string in_snap_name, bool *is_protected) const; int is_snap_unprotected(string in_snap_name, bool *is_unprotected) const; uint64_t get_current_size() const; uint64_t get_object_size() const; string get_object_name(uint64_t num) const; uint64_t get_num_objects() const; uint64_t get_stripe_unit() const; uint64_t get_stripe_count() const; uint64_t get_stripe_period() const; void add_snap(std::string in_snap_name, librados::snap_t id, uint64_t in_size, uint64_t features, parent_info parent, uint8_t protection_status); uint64_t get_image_size(librados::snap_t in_snap_id) const; int get_features(librados::snap_t in_snap_id, uint64_t *out_features) const; int64_t get_parent_pool_id(librados::snap_t in_snap_id) const; std::string get_parent_image_id(librados::snap_t in_snap_id) const; uint64_t get_parent_snap_id(librados::snap_t in_snap_id) const; int get_parent_overlap(librados::snap_t in_snap_id, uint64_t *overlap) const; void aio_read_from_cache(object_t o, bufferlist *bl, size_t len, uint64_t off, Context *onfinish); void write_to_cache(object_t o, bufferlist& bl, size_t len, uint64_t off, Context *onfinish); int read_from_cache(object_t o, bufferlist *bl, size_t len, uint64_t off); void user_flushed(); void flush_cache_aio(Context *onfinish); int flush_cache(); void shutdown_cache(); int invalidate_cache(); void clear_nonexistence_cache(); int register_watch(); void unregister_watch(); size_t parent_io_len(uint64_t offset, size_t length, librados::snap_t in_snap_id); uint64_t prune_parent_extents(vector >& objectx, uint64_t overlap); void wait_for_pending_aio(); }; } #endif ceph-0.80.11/src/librbd/WatchCtx.cc0000664000175100017510000000154612623076744020764 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/ceph_context.h" #include "common/dout.h" #include "common/perf_counters.h" #include "librbd/ImageCtx.h" #include "librbd/internal.h" #include "librbd/WatchCtx.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::WatchCtx: " namespace librbd { void WatchCtx::invalidate() { Mutex::Locker l(lock); valid = false; } void WatchCtx::notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { Mutex::Locker l(lock); ldout(ictx->cct, 1) << " got notification opcode=" << (int)opcode << " ver=" << ver << " cookie=" << cookie << dendl; if (valid) { Mutex::Locker lictx(ictx->refresh_lock); ++ictx->refresh_seq; ictx->perfcounter->inc(l_librbd_notify); } } } ceph-0.80.11/src/librbd/Makefile.am0000664000175100017510000000123112623076744020753 0ustar jenkins-buildjenkins-buildlibrbd_la_SOURCES = \ librbd/librbd.cc \ librbd/AioCompletion.cc \ librbd/AioRequest.cc \ librbd/ImageCtx.cc \ librbd/internal.cc \ librbd/LibrbdWriteback.cc \ librbd/WatchCtx.cc librbd_la_LIBADD = \ $(LIBRADOS) $(LIBOSDC) \ libcls_rbd_client.la libcls_lock_client.la \ $(PTHREAD_LIBS) $(EXTRALIBS) librbd_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 if LINUX librbd_la_LDFLAGS += -export-symbols-regex '^rbd_.*' endif lib_LTLIBRARIES += librbd.la noinst_HEADERS += \ librbd/AioCompletion.h \ librbd/AioRequest.h \ librbd/ImageCtx.h \ librbd/internal.h \ librbd/LibrbdWriteback.h \ librbd/parent_types.h \ librbd/SnapInfo.h \ librbd/WatchCtx.h ceph-0.80.11/src/librbd/ImageCtx.cc0000664000175100017510000004771612623076744020751 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "common/ceph_context.h" #include "common/dout.h" #include "common/errno.h" #include "common/perf_counters.h" #include "common/WorkQueue.h" #include "librbd/internal.h" #include "librbd/WatchCtx.h" #include "librbd/ImageCtx.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::ImageCtx: " using std::map; using std::pair; using std::set; using std::string; using std::vector; using ceph::bufferlist; using librados::snap_t; using librados::IoCtx; namespace librbd { namespace { class ThreadPoolSingleton : public ThreadPool { public: ThreadPoolSingleton(CephContext *cct) : ThreadPool(cct, "librbd::thread_pool", cct->_conf->rbd_op_threads, "rbd_op_threads") { start(); } virtual ~ThreadPoolSingleton() { stop(); } }; } // anonymous namespace ImageCtx::ImageCtx(const string &image_name, const string &image_id, const char *snap, IoCtx& p, bool ro) : cct((CephContext*)p.cct()), perfcounter(NULL), snap_id(CEPH_NOSNAP), snap_exists(true), read_only(ro), flush_encountered(false), exclusive_locked(false), name(image_name), wctx(NULL), refresh_seq(0), last_refresh(0), md_lock("librbd::ImageCtx::md_lock"), cache_lock("librbd::ImageCtx::cache_lock"), snap_lock("librbd::ImageCtx::snap_lock"), parent_lock("librbd::ImageCtx::parent_lock"), refresh_lock("librbd::ImageCtx::refresh_lock"), aio_lock("librbd::ImageCtx::aio_lock"), extra_read_flags(0), old_format(true), order(0), size(0), features(0), format_string(NULL), id(image_id), parent(NULL), stripe_unit(0), stripe_count(0), object_cacher(NULL), writeback_handler(NULL), object_set(NULL), pending_aio(0), aio_work_queue(NULL) { md_ctx.dup(p); data_ctx.dup(p); memset(&header, 0, sizeof(header)); memset(&layout, 0, sizeof(layout)); string pname = string("librbd-") + id + string("-") + data_ctx.get_pool_name() + string("/") + name; if (snap) { snap_name = snap; pname += "@"; pname += snap_name; } perf_start(pname); if (cct->_conf->rbd_cache) { Mutex::Locker l(cache_lock); ldout(cct, 20) << "enabling caching..." << dendl; writeback_handler = new LibrbdWriteback(this, cache_lock); uint64_t init_max_dirty = cct->_conf->rbd_cache_max_dirty; if (cct->_conf->rbd_cache_writethrough_until_flush) init_max_dirty = 0; ldout(cct, 20) << "Initial cache settings:" << " size=" << cct->_conf->rbd_cache_size << " num_objects=" << 10 << " max_dirty=" << init_max_dirty << " target_dirty=" << cct->_conf->rbd_cache_target_dirty << " max_dirty_age=" << cct->_conf->rbd_cache_max_dirty_age << dendl; object_cacher = new ObjectCacher(cct, pname, *writeback_handler, cache_lock, NULL, NULL, cct->_conf->rbd_cache_size, 10, /* reset this in init */ init_max_dirty, cct->_conf->rbd_cache_target_dirty, cct->_conf->rbd_cache_max_dirty_age, cct->_conf->rbd_cache_block_writes_upfront); object_set = new ObjectCacher::ObjectSet(NULL, data_ctx.get_id(), 0); object_set->return_enoent = true; object_cacher->start(); } ThreadPoolSingleton *thread_pool_singleton; cct->lookup_or_create_singleton_object( thread_pool_singleton, "librbd::thread_pool"); aio_work_queue = new ContextWQ("librbd::aio_work_queue", cct->_conf->rbd_op_thread_timeout, thread_pool_singleton); } ImageCtx::~ImageCtx() { perf_stop(); if (object_cacher) { delete object_cacher; object_cacher = NULL; } if (writeback_handler) { delete writeback_handler; writeback_handler = NULL; } if (object_set) { delete object_set; object_set = NULL; } delete[] format_string; delete aio_work_queue; } int ImageCtx::init() { int r; if (id.length()) { old_format = false; } else { r = detect_format(md_ctx, name, &old_format, NULL); if (r < 0) { lderr(cct) << "error finding header: " << cpp_strerror(r) << dendl; return r; } } if (!old_format) { if (!id.length()) { r = cls_client::get_id(&md_ctx, id_obj_name(name), &id); if (r < 0) { lderr(cct) << "error reading image id: " << cpp_strerror(r) << dendl; return r; } } header_oid = header_name(id); r = cls_client::get_immutable_metadata(&md_ctx, header_oid, &object_prefix, &order); if (r < 0) { lderr(cct) << "error reading immutable metadata: " << cpp_strerror(r) << dendl; return r; } r = cls_client::get_stripe_unit_count(&md_ctx, header_oid, &stripe_unit, &stripe_count); if (r < 0 && r != -ENOEXEC && r != -EINVAL) { lderr(cct) << "error reading striping metadata: " << cpp_strerror(r) << dendl; return r; } init_layout(); } else { header_oid = old_header_name(name); } return 0; } void ImageCtx::init_layout() { if (stripe_unit == 0 || stripe_count == 0) { stripe_unit = 1ull << order; stripe_count = 1; } memset(&layout, 0, sizeof(layout)); layout.fl_stripe_unit = stripe_unit; layout.fl_stripe_count = stripe_count; layout.fl_object_size = 1ull << order; layout.fl_pg_pool = data_ctx.get_id(); // FIXME: pool id overflow? delete[] format_string; size_t len = object_prefix.length() + 16; format_string = new char[len]; if (old_format) { snprintf(format_string, len, "%s.%%012llx", object_prefix.c_str()); } else { snprintf(format_string, len, "%s.%%016llx", object_prefix.c_str()); } // size object cache appropriately if (object_cacher) { uint64_t obj = cct->_conf->rbd_cache_max_dirty_object; if (!obj) { obj = MIN(2000, MAX(10, cct->_conf->rbd_cache_size / 100 / sizeof(ObjectCacher::Object))); } ldout(cct, 10) << " cache bytes " << cct->_conf->rbd_cache_size << " -> about " << obj << " objects" << dendl; object_cacher->set_max_objects(obj); } ldout(cct, 10) << "init_layout stripe_unit " << stripe_unit << " stripe_count " << stripe_count << " object_size " << layout.fl_object_size << " prefix " << object_prefix << " format " << format_string << dendl; } void ImageCtx::perf_start(string name) { PerfCountersBuilder plb(cct, name, l_librbd_first, l_librbd_last); plb.add_u64_counter(l_librbd_rd, "rd"); plb.add_u64_counter(l_librbd_rd_bytes, "rd_bytes"); plb.add_time_avg(l_librbd_rd_latency, "rd_latency"); plb.add_u64_counter(l_librbd_wr, "wr"); plb.add_u64_counter(l_librbd_wr_bytes, "wr_bytes"); plb.add_time_avg(l_librbd_wr_latency, "wr_latency"); plb.add_u64_counter(l_librbd_discard, "discard"); plb.add_u64_counter(l_librbd_discard_bytes, "discard_bytes"); plb.add_time_avg(l_librbd_discard_latency, "discard_latency"); plb.add_u64_counter(l_librbd_flush, "flush"); plb.add_u64_counter(l_librbd_aio_rd, "aio_rd"); plb.add_u64_counter(l_librbd_aio_rd_bytes, "aio_rd_bytes"); plb.add_time_avg(l_librbd_aio_rd_latency, "aio_rd_latency"); plb.add_u64_counter(l_librbd_aio_wr, "aio_wr"); plb.add_u64_counter(l_librbd_aio_wr_bytes, "aio_wr_bytes"); plb.add_time_avg(l_librbd_aio_wr_latency, "aio_wr_latency"); plb.add_u64_counter(l_librbd_aio_discard, "aio_discard"); plb.add_u64_counter(l_librbd_aio_discard_bytes, "aio_discard_bytes"); plb.add_time_avg(l_librbd_aio_discard_latency, "aio_discard_latency"); plb.add_u64_counter(l_librbd_aio_flush, "aio_flush"); plb.add_time_avg(l_librbd_aio_flush_latency, "aio_flush_latency"); plb.add_u64_counter(l_librbd_snap_create, "snap_create"); plb.add_u64_counter(l_librbd_snap_remove, "snap_remove"); plb.add_u64_counter(l_librbd_snap_rollback, "snap_rollback"); plb.add_u64_counter(l_librbd_notify, "notify"); plb.add_u64_counter(l_librbd_resize, "resize"); perfcounter = plb.create_perf_counters(); cct->get_perfcounters_collection()->add(perfcounter); } void ImageCtx::perf_stop() { assert(perfcounter); cct->get_perfcounters_collection()->remove(perfcounter); delete perfcounter; } void ImageCtx::set_read_flag(unsigned flag) { extra_read_flags |= flag; } int ImageCtx::get_read_flags(snap_t snap_id) { int flags = librados::OPERATION_NOFLAG | extra_read_flags; if (snap_id == LIBRADOS_SNAP_HEAD) return flags; if (cct->_conf->rbd_balance_snap_reads) flags |= librados::OPERATION_BALANCE_READS; else if (cct->_conf->rbd_localize_snap_reads) flags |= librados::OPERATION_LOCALIZE_READS; return flags; } int ImageCtx::snap_set(string in_snap_name) { map::iterator it = snaps_by_name.find(in_snap_name); if (it != snaps_by_name.end()) { snap_name = in_snap_name; snap_id = it->second.id; snap_exists = true; data_ctx.snap_set_read(snap_id); return 0; } return -ENOENT; } void ImageCtx::snap_unset() { snap_id = CEPH_NOSNAP; snap_name = ""; snap_exists = true; data_ctx.snap_set_read(snap_id); } snap_t ImageCtx::get_snap_id(string in_snap_name) const { map::const_iterator it = snaps_by_name.find(in_snap_name); if (it != snaps_by_name.end()) return it->second.id; return CEPH_NOSNAP; } int ImageCtx::get_snap_name(snapid_t in_snap_id, string *out_snap_name) const { map::const_iterator it; for (it = snaps_by_name.begin(); it != snaps_by_name.end(); ++it) { if (it->second.id == in_snap_id) { *out_snap_name = it->first; return 0; } } return -ENOENT; } int ImageCtx::get_parent_spec(snapid_t in_snap_id, parent_spec *out_pspec) { map::iterator it; for (it = snaps_by_name.begin(); it != snaps_by_name.end(); ++it) { if (it->second.id == in_snap_id) { *out_pspec = it->second.parent.spec; return 0; } } return -ENOENT; } uint64_t ImageCtx::get_current_size() const { return size; } uint64_t ImageCtx::get_object_size() const { return 1ull << order; } string ImageCtx::get_object_name(uint64_t num) const { char buf[object_prefix.length() + 32]; snprintf(buf, sizeof(buf), format_string, num); return string(buf); } uint64_t ImageCtx::get_stripe_unit() const { return stripe_unit; } uint64_t ImageCtx::get_stripe_count() const { return stripe_count; } uint64_t ImageCtx::get_stripe_period() const { return stripe_count * (1ull << order); } uint64_t ImageCtx::get_num_objects() const { uint64_t period = get_stripe_period(); uint64_t num_periods = (size + period - 1) / period; return num_periods * stripe_count; } int ImageCtx::is_snap_protected(string in_snap_name, bool *is_protected) const { map::const_iterator it = snaps_by_name.find(in_snap_name); if (it != snaps_by_name.end()) { *is_protected = (it->second.protection_status == RBD_PROTECTION_STATUS_PROTECTED); return 0; } return -ENOENT; } int ImageCtx::is_snap_unprotected(string in_snap_name, bool *is_unprotected) const { map::const_iterator it = snaps_by_name.find(in_snap_name); if (it != snaps_by_name.end()) { *is_unprotected = (it->second.protection_status == RBD_PROTECTION_STATUS_UNPROTECTED); return 0; } return -ENOENT; } void ImageCtx::add_snap(string in_snap_name, snap_t id, uint64_t in_size, uint64_t features, parent_info parent, uint8_t protection_status) { snaps.push_back(id); SnapInfo info(id, in_size, features, parent, protection_status); snaps_by_name.insert(pair(in_snap_name, info)); } uint64_t ImageCtx::get_image_size(snap_t in_snap_id) const { if (in_snap_id == CEPH_NOSNAP) { return size; } string in_snap_name; int r = get_snap_name(in_snap_id, &in_snap_name); if (r < 0) return 0; map::const_iterator p = snaps_by_name.find(in_snap_name); if (p == snaps_by_name.end()) return 0; return p->second.size; } int ImageCtx::get_features(snap_t in_snap_id, uint64_t *out_features) const { if (in_snap_id == CEPH_NOSNAP) { *out_features = features; return 0; } string in_snap_name; int r = get_snap_name(in_snap_id, &in_snap_name); if (r < 0) return r; map::const_iterator p = snaps_by_name.find(in_snap_name); if (p == snaps_by_name.end()) return -ENOENT; *out_features = p->second.features; return 0; } int64_t ImageCtx::get_parent_pool_id(snap_t in_snap_id) const { if (in_snap_id == CEPH_NOSNAP) { return parent_md.spec.pool_id; } string in_snap_name; int r = get_snap_name(in_snap_id, &in_snap_name); if (r < 0) return -1; map::const_iterator p = snaps_by_name.find(in_snap_name); if (p == snaps_by_name.end()) return -1; return p->second.parent.spec.pool_id; } string ImageCtx::get_parent_image_id(snap_t in_snap_id) const { if (in_snap_id == CEPH_NOSNAP) { return parent_md.spec.image_id; } string in_snap_name; int r = get_snap_name(in_snap_id, &in_snap_name); if (r < 0) return ""; map::const_iterator p = snaps_by_name.find(in_snap_name); if (p == snaps_by_name.end()) return ""; return p->second.parent.spec.image_id; } uint64_t ImageCtx::get_parent_snap_id(snap_t in_snap_id) const { if (in_snap_id == CEPH_NOSNAP) { return parent_md.spec.snap_id; } string in_snap_name; int r = get_snap_name(in_snap_id, &in_snap_name); if (r < 0) return CEPH_NOSNAP; map::const_iterator p = snaps_by_name.find(in_snap_name); if (p == snaps_by_name.end()) return CEPH_NOSNAP; return p->second.parent.spec.snap_id; } int ImageCtx::get_parent_overlap(snap_t in_snap_id, uint64_t *overlap) const { if (in_snap_id == CEPH_NOSNAP) { *overlap = parent_md.overlap; return 0; } string in_snap_name; int r = get_snap_name(in_snap_id, &in_snap_name); if (r < 0) return r; map::const_iterator p = snaps_by_name.find(in_snap_name); if (p == snaps_by_name.end()) return -ENOENT; *overlap = p->second.parent.overlap; return 0; } void ImageCtx::aio_read_from_cache(object_t o, bufferlist *bl, size_t len, uint64_t off, Context *onfinish) { snap_lock.get_read(); ObjectCacher::OSDRead *rd = object_cacher->prepare_read(snap_id, bl, 0); snap_lock.put_read(); ObjectExtent extent(o, 0 /* a lie */, off, len, 0); extent.oloc.pool = data_ctx.get_id(); extent.buffer_extents.push_back(make_pair(0, len)); rd->extents.push_back(extent); cache_lock.Lock(); int r = object_cacher->readx(rd, object_set, onfinish); cache_lock.Unlock(); if (r != 0) onfinish->complete(r); } void ImageCtx::write_to_cache(object_t o, bufferlist& bl, size_t len, uint64_t off, Context *onfinish) { snap_lock.get_read(); ObjectCacher::OSDWrite *wr = object_cacher->prepare_write(snapc, bl, utime_t(), 0); snap_lock.put_read(); ObjectExtent extent(o, 0, off, len, 0); extent.oloc.pool = data_ctx.get_id(); // XXX: nspace is always default, io_ctx_impl field private //extent.oloc.nspace = data_ctx.io_ctx_impl->oloc.nspace; extent.buffer_extents.push_back(make_pair(0, len)); wr->extents.push_back(extent); { Mutex::Locker l(cache_lock); object_cacher->writex(wr, object_set, cache_lock, onfinish); } } int ImageCtx::read_from_cache(object_t o, bufferlist *bl, size_t len, uint64_t off) { int r; Mutex mylock("librbd::ImageCtx::read_from_cache"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &r); aio_read_from_cache(o, bl, len, off, onfinish); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return r; } void ImageCtx::user_flushed() { if (object_cacher && cct->_conf->rbd_cache_writethrough_until_flush) { md_lock.get_read(); bool flushed_before = flush_encountered; md_lock.put_read(); uint64_t max_dirty = cct->_conf->rbd_cache_max_dirty; if (!flushed_before && max_dirty > 0) { md_lock.get_write(); flush_encountered = true; md_lock.put_write(); ldout(cct, 10) << "saw first user flush, enabling writeback" << dendl; Mutex::Locker l(cache_lock); object_cacher->set_max_dirty(max_dirty); } } } void ImageCtx::flush_cache_aio(Context *onfinish) { cache_lock.Lock(); object_cacher->flush_set(object_set, onfinish); cache_lock.Unlock(); } int ImageCtx::flush_cache() { int r = 0; Mutex mylock("librbd::ImageCtx::flush_cache"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &r); flush_cache_aio(onfinish); mylock.Lock(); while (!done) { ldout(cct, 20) << "waiting for cache to be flushed" << dendl; cond.Wait(mylock); } mylock.Unlock(); ldout(cct, 20) << "finished flushing cache" << dendl; return r; } void ImageCtx::shutdown_cache() { md_lock.get_write(); invalidate_cache(); md_lock.put_write(); object_cacher->stop(); } int ImageCtx::invalidate_cache() { if (!object_cacher) return 0; cache_lock.Lock(); object_cacher->release_set(object_set); cache_lock.Unlock(); int r = flush_cache(); if (r) lderr(cct) << "flush_cache returned " << r << dendl; wait_for_pending_aio(); cache_lock.Lock(); bool unclean = object_cacher->release_set(object_set); cache_lock.Unlock(); if (unclean) { lderr(cct) << "could not release all objects from cache: " << unclean << " bytes remain" << dendl; return -EBUSY; } return r; } void ImageCtx::clear_nonexistence_cache() { if (!object_cacher) return; object_cacher->clear_nonexistence(object_set); } int ImageCtx::register_watch() { assert(!wctx); wctx = new WatchCtx(this); return md_ctx.watch(header_oid, 0, &(wctx->cookie), wctx); } void ImageCtx::unregister_watch() { assert(wctx); wctx->invalidate(); md_ctx.unwatch(header_oid, wctx->cookie); delete wctx; wctx = NULL; } size_t ImageCtx::parent_io_len(uint64_t offset, size_t length, snap_t in_snap_id) { uint64_t overlap = 0; get_parent_overlap(in_snap_id, &overlap); size_t parent_len = 0; if (get_parent_pool_id(in_snap_id) != -1 && offset <= overlap) parent_len = min(overlap, offset + length) - offset; ldout(cct, 20) << __func__ << " off = " << offset << " len = " << length << " overlap = " << overlap << " parent_io_len = " << parent_len << dendl; return parent_len; } uint64_t ImageCtx::prune_parent_extents(vector >& objectx, uint64_t overlap) { // drop extents completely beyond the overlap while (!objectx.empty() && objectx.back().first >= overlap) objectx.pop_back(); // trim final overlapping extent if (!objectx.empty() && objectx.back().first + objectx.back().second > overlap) objectx.back().second = overlap - objectx.back().first; uint64_t len = 0; for (vector >::iterator p = objectx.begin(); p != objectx.end(); ++p) len += p->second; ldout(cct, 10) << "prune_parent_extents image overlap " << overlap << ", object overlap " << len << " from image extents " << objectx << dendl; return len; } void ImageCtx::wait_for_pending_aio() { Mutex::Locker l(aio_lock); while (pending_aio > 0) { pending_aio_cond.Wait(aio_lock); } } } ceph-0.80.11/src/librbd/parent_types.h0000664000175100017510000000224012623076744021606 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_PARENT_TYPES_H #define CEPH_LIBRBD_PARENT_TYPES_H // parent_spec uniquely identifies a parent in the clone relationship // (clone(parent) creates child, then parent_spec <-> child_imageid) namespace librbd { struct parent_spec { int64_t pool_id; string image_id; snapid_t snap_id; parent_spec() : pool_id(-1), snap_id(CEPH_NOSNAP) {} parent_spec(uint64_t pool_id, string image_id, snapid_t snap_id) : pool_id(pool_id), image_id(image_id), snap_id(snap_id) {} bool operator==(const parent_spec &other) { return ((this->pool_id == other.pool_id) && (this->image_id == other.image_id) && (this->snap_id == other.snap_id)); } bool operator!=(const parent_spec &other) { return !(*this == other); } }; struct parent_info { parent_spec spec; uint64_t overlap; parent_info() : overlap(0) {} }; } enum { RBD_PROTECTION_STATUS_UNPROTECTED = 0, RBD_PROTECTION_STATUS_UNPROTECTING = 1, RBD_PROTECTION_STATUS_PROTECTED = 2, RBD_PROTECTION_STATUS_LAST = 3 }; #endif ceph-0.80.11/src/librbd/internal.cc0000664000175100017510000026165512623076744021064 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/int_types.h" #include #include #include "common/ceph_context.h" #include "common/dout.h" #include "common/errno.h" #include "common/Throttle.h" #include "common/WorkQueue.h" #include "cls/lock/cls_lock_client.h" #include "include/stringify.h" #include "cls/rbd/cls_rbd.h" #include "librbd/AioCompletion.h" #include "librbd/AioRequest.h" #include "librbd/ImageCtx.h" #include "librbd/internal.h" #include "librbd/parent_types.h" #include "include/util.h" #include "librados/snap_set_diff.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd: " #define rbd_howmany(x, y) (((x) + (y) - 1) / (y)) using std::map; using std::pair; using std::set; using std::string; using std::vector; // list binds to list() here, so std::list is explicitly used below using ceph::bufferlist; using librados::snap_t; using librados::IoCtx; using librados::Rados; namespace librbd { const string id_obj_name(const string &name) { return RBD_ID_PREFIX + name; } const string header_name(const string &image_id) { return RBD_HEADER_PREFIX + image_id; } const string old_header_name(const string &image_name) { return image_name + RBD_SUFFIX; } int detect_format(IoCtx &io_ctx, const string &name, bool *old_format, uint64_t *size) { CephContext *cct = (CephContext *)io_ctx.cct(); if (old_format) *old_format = true; int r = io_ctx.stat(old_header_name(name), size, NULL); if (r < 0) { if (old_format) *old_format = false; r = io_ctx.stat(id_obj_name(name), size, NULL); if (r < 0) return r; } ldout(cct, 20) << "detect format of " << name << " : " << (old_format ? (*old_format ? "old" : "new") : "don't care") << dendl; return 0; } bool has_parent(int64_t parent_pool_id, uint64_t off, uint64_t overlap) { return (parent_pool_id != -1 && off <= overlap); } void init_rbd_header(struct rbd_obj_header_ondisk& ondisk, uint64_t size, int order, uint64_t bid) { uint32_t hi = bid >> 32; uint32_t lo = bid & 0xFFFFFFFF; uint32_t extra = rand() % 0xFFFFFFFF; memset(&ondisk, 0, sizeof(ondisk)); memcpy(&ondisk.text, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT)); memcpy(&ondisk.signature, RBD_HEADER_SIGNATURE, sizeof(RBD_HEADER_SIGNATURE)); memcpy(&ondisk.version, RBD_HEADER_VERSION, sizeof(RBD_HEADER_VERSION)); snprintf(ondisk.block_name, sizeof(ondisk.block_name), "rb.%x.%x.%x", hi, lo, extra); ondisk.image_size = size; ondisk.options.order = order; ondisk.options.crypt_type = RBD_CRYPT_NONE; ondisk.options.comp_type = RBD_COMP_NONE; ondisk.snap_seq = 0; ondisk.snap_count = 0; ondisk.reserved = 0; ondisk.snap_names_len = 0; } void image_info(ImageCtx *ictx, image_info_t& info, size_t infosize) { int obj_order = ictx->order; ictx->md_lock.get_read(); ictx->snap_lock.get_read(); info.size = ictx->get_image_size(ictx->snap_id); ictx->snap_lock.put_read(); ictx->md_lock.put_read(); info.obj_size = 1ULL << obj_order; info.num_objs = rbd_howmany(info.size, ictx->get_object_size()); info.order = obj_order; memcpy(&info.block_name_prefix, ictx->object_prefix.c_str(), min((size_t)RBD_MAX_BLOCK_NAME_SIZE, ictx->object_prefix.length() + 1)); // clear deprecated fields info.parent_pool = -1L; info.parent_name[0] = '\0'; } uint64_t oid_to_object_no(const string& oid, const string& object_prefix) { istringstream iss(oid); // skip object prefix and separator iss.ignore(object_prefix.length() + 1); uint64_t num; iss >> std::hex >> num; return num; } int init_rbd_info(struct rbd_info *info) { memset(info, 0, sizeof(*info)); return 0; } void trim_image(ImageCtx *ictx, uint64_t newsize, ProgressContext& prog_ctx) { CephContext *cct = (CephContext *)ictx->data_ctx.cct(); uint64_t size = ictx->get_current_size(); uint64_t period = ictx->get_stripe_period(); uint64_t num_period = ((newsize + period - 1) / period); uint64_t delete_off = MIN(num_period * period, size); // first object we can delete free and clear uint64_t delete_start = num_period * ictx->get_stripe_count(); uint64_t num_objects = ictx->get_num_objects(); uint64_t object_size = ictx->get_object_size(); ldout(cct, 10) << "trim_image " << size << " -> " << newsize << " periods " << num_period << " discard to offset " << delete_off << " delete objects " << delete_start << " to " << (num_objects-1) << dendl; SimpleThrottle throttle(cct->_conf->rbd_concurrent_management_ops, true); if (delete_start < num_objects) { ldout(cct, 2) << "trim_image objects " << delete_start << " to " << (num_objects - 1) << dendl; for (uint64_t i = delete_start; i < num_objects; ++i) { string oid = ictx->get_object_name(i); Context *req_comp = new C_SimpleThrottle(&throttle); librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(req_comp, NULL, rados_ctx_cb); ictx->data_ctx.aio_remove(oid, rados_completion); rados_completion->release(); prog_ctx.update_progress((i - delete_start) * object_size, (num_objects - delete_start) * object_size); } } // discard the weird boundary, if any if (delete_off > newsize) { vector extents; Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, newsize, delete_off - newsize, 0, extents); for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { ldout(ictx->cct, 20) << " ex " << *p << dendl; Context *req_comp = new C_SimpleThrottle(&throttle); librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(req_comp, NULL, rados_ctx_cb); if (p->offset == 0) { ictx->data_ctx.aio_remove(p->oid.name, rados_completion); } else { librados::ObjectWriteOperation op; op.truncate(p->offset); ictx->data_ctx.aio_operate(p->oid.name, rados_completion, &op); } rados_completion->release(); } } int r = throttle.wait_for_ret(); if (r < 0) { lderr(cct) << "warning: failed to remove some object(s): " << cpp_strerror(r) << dendl; } } int read_rbd_info(IoCtx& io_ctx, const string& info_oid, struct rbd_info *info) { int r; bufferlist bl; r = io_ctx.read(info_oid, bl, sizeof(*info), 0); if (r < 0) return r; if (r == 0) { return init_rbd_info(info); } if (r < (int)sizeof(*info)) return -EIO; memcpy(info, bl.c_str(), r); return 0; } int read_header_bl(IoCtx& io_ctx, const string& header_oid, bufferlist& header, uint64_t *ver) { int r; uint64_t off = 0; #define READ_SIZE 4096 do { bufferlist bl; r = io_ctx.read(header_oid, bl, READ_SIZE, off); if (r < 0) return r; header.claim_append(bl); off += r; } while (r == READ_SIZE); if (memcmp(RBD_HEADER_TEXT, header.c_str(), sizeof(RBD_HEADER_TEXT))) { CephContext *cct = (CephContext *)io_ctx.cct(); lderr(cct) << "unrecognized header format" << dendl; return -ENXIO; } if (ver) *ver = io_ctx.get_last_version(); return 0; } int notify_change(IoCtx& io_ctx, const string& oid, uint64_t *pver, ImageCtx *ictx) { uint64_t ver; if (ictx) { ictx->refresh_lock.Lock(); ldout(ictx->cct, 20) << "notify_change refresh_seq = " << ictx->refresh_seq << " last_refresh = " << ictx->last_refresh << dendl; ++ictx->refresh_seq; ictx->refresh_lock.Unlock(); } if (pver) ver = *pver; else ver = io_ctx.get_last_version(); bufferlist bl; io_ctx.notify(oid, ver, bl); return 0; } int read_header(IoCtx& io_ctx, const string& header_oid, struct rbd_obj_header_ondisk *header, uint64_t *ver) { bufferlist header_bl; int r = read_header_bl(io_ctx, header_oid, header_bl, ver); if (r < 0) return r; if (header_bl.length() < (int)sizeof(*header)) return -EIO; memcpy(header, header_bl.c_str(), sizeof(*header)); return 0; } int write_header(IoCtx& io_ctx, const string& header_oid, bufferlist& header) { bufferlist bl; int r = io_ctx.write(header_oid, header, header.length(), 0); notify_change(io_ctx, header_oid, NULL, NULL); return r; } int tmap_set(IoCtx& io_ctx, const string& imgname) { bufferlist cmdbl, emptybl; __u8 c = CEPH_OSD_TMAP_SET; ::encode(c, cmdbl); ::encode(imgname, cmdbl); ::encode(emptybl, cmdbl); return io_ctx.tmap_update(RBD_DIRECTORY, cmdbl); } int tmap_rm(IoCtx& io_ctx, const string& imgname) { bufferlist cmdbl; __u8 c = CEPH_OSD_TMAP_RM; ::encode(c, cmdbl); ::encode(imgname, cmdbl); return io_ctx.tmap_update(RBD_DIRECTORY, cmdbl); } int rollback_image(ImageCtx *ictx, uint64_t snap_id, ProgressContext& prog_ctx) { uint64_t numseg = ictx->get_num_objects(); uint64_t bsize = ictx->get_object_size(); int r; CephContext *cct = ictx->cct; SimpleThrottle throttle(cct->_conf->rbd_concurrent_management_ops, true); for (uint64_t i = 0; i < numseg; i++) { string oid = ictx->get_object_name(i); Context *req_comp = new C_SimpleThrottle(&throttle); librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(req_comp, NULL, rados_ctx_cb); librados::ObjectWriteOperation op; op.selfmanaged_snap_rollback(snap_id); ictx->data_ctx.aio_operate(oid, rados_completion, &op); ldout(cct, 10) << "scheduling selfmanaged_snap_rollback on " << oid << " to " << snap_id << dendl; rados_completion->release(); prog_ctx.update_progress(i * bsize, numseg * bsize); } r = throttle.wait_for_ret(); if (r < 0) { ldout(cct, 10) << "failed to rollback at least one object: " << cpp_strerror(r) << dendl; return r; } return 0; } int list(IoCtx& io_ctx, vector& names) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 20) << "list " << &io_ctx << dendl; bufferlist bl; int r = io_ctx.read(RBD_DIRECTORY, bl, 0, 0); if (r < 0) return r; // old format images are in a tmap if (bl.length()) { bufferlist::iterator p = bl.begin(); bufferlist header; map m; ::decode(header, p); ::decode(m, p); for (map::iterator q = m.begin(); q != m.end(); ++q) { names.push_back(q->first); } } // new format images are accessed by class methods int max_read = 1024; string last_read = ""; do { map images; cls_client::dir_list(&io_ctx, RBD_DIRECTORY, last_read, max_read, &images); for (map::const_iterator it = images.begin(); it != images.end(); ++it) { names.push_back(it->first); } if (!images.empty()) { last_read = images.rbegin()->first; } r = images.size(); } while (r == max_read); return 0; } int list_children(ImageCtx *ictx, set >& names) { CephContext *cct = ictx->cct; ldout(cct, 20) << "children list " << ictx->name << dendl; int r = ictx_check(ictx); if (r < 0) return r; // no children for non-layered or old format image if ((ictx->features & RBD_FEATURE_LAYERING) == 0) return 0; parent_spec parent_spec(ictx->md_ctx.get_id(), ictx->id, ictx->snap_id); names.clear(); // search all pools for children depending on this snapshot Rados rados(ictx->md_ctx); std::list pools; rados.pool_list(pools); for (std::list::const_iterator it = pools.begin(); it != pools.end(); ++it) { IoCtx ioctx; r = rados.ioctx_create(it->c_str(), ioctx); if (r == -ENOENT) { ldout(cct, 1) << "pool " << *it << " no longer exists" << dendl; continue; } else if (r < 0) { lderr(cct) << "Error accessing child image pool " << *it << dendl; return r; } set image_ids; int r = cls_client::get_children(&ioctx, RBD_CHILDREN, parent_spec, image_ids); if (r < 0 && r != -ENOENT) { lderr(cct) << "Error reading list of children from pool " << *it << dendl; return r; } for (set::const_iterator id_it = image_ids.begin(); id_it != image_ids.end(); ++id_it) { string name; r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, *id_it, &name); if (r < 0) { lderr(cct) << "Error looking up name for image id " << *id_it << " in pool " << *it << dendl; return r; } names.insert(make_pair(*it, name)); } } return 0; } int snap_create(ImageCtx *ictx, const char *snap_name) { ldout(ictx->cct, 20) << "snap_create " << ictx << " " << snap_name << dendl; if (ictx->read_only) return -EROFS; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->md_lock); do { r = add_snap(ictx, snap_name); } while (r == -ESTALE); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); ictx->perfcounter->inc(l_librbd_snap_create); return 0; } static int scan_for_parents(ImageCtx *ictx, parent_spec &pspec, snapid_t oursnap_id) { if (pspec.pool_id != -1) { map::iterator it; for (it = ictx->snaps_by_name.begin(); it != ictx->snaps_by_name.end(); ++it) { // skip our snap id (if checking base image, CEPH_NOSNAP won't match) if (it->second.id == oursnap_id) continue; if (it->second.parent.spec == pspec) break; } if (it == ictx->snaps_by_name.end()) return -ENOENT; } return 0; } int snap_remove(ImageCtx *ictx, const char *snap_name) { ldout(ictx->cct, 20) << "snap_remove " << ictx << " " << snap_name << dendl; if (ictx->read_only) return -EROFS; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->md_lock); snap_t snap_id; { // block for purposes of auto-destruction of l2 on early return RWLock::RLocker l2(ictx->snap_lock); snap_id = ictx->get_snap_id(snap_name); if (snap_id == CEPH_NOSNAP) return -ENOENT; parent_spec our_pspec; RWLock::RLocker l3(ictx->parent_lock); r = ictx->get_parent_spec(snap_id, &our_pspec); if (r < 0) { lderr(ictx->cct) << "snap_remove: can't get parent spec" << dendl; return r; } if (ictx->parent_md.spec != our_pspec && (scan_for_parents(ictx, our_pspec, snap_id) == -ENOENT)) { r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN, our_pspec, ictx->id); if (r < 0 && r != -ENOENT) { lderr(ictx->cct) << "snap_remove: failed to deregister from parent " "image" << dendl; return r; } } } r = rm_snap(ictx, snap_name); if (r < 0) return r; r = ictx->data_ctx.selfmanaged_snap_remove(snap_id); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); ictx->perfcounter->inc(l_librbd_snap_remove); return 0; } int snap_protect(ImageCtx *ictx, const char *snap_name) { ldout(ictx->cct, 20) << "snap_protect " << ictx << " " << snap_name << dendl; if (ictx->read_only) return -EROFS; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->md_lock); RWLock::RLocker l2(ictx->snap_lock); uint64_t features; ictx->get_features(ictx->snap_id, &features); if ((features & RBD_FEATURE_LAYERING) == 0) { lderr(ictx->cct) << "snap_protect: image must support layering" << dendl; return -ENOSYS; } snap_t snap_id = ictx->get_snap_id(snap_name); if (snap_id == CEPH_NOSNAP) return -ENOENT; bool is_protected; r = ictx->is_snap_protected(snap_name, &is_protected); if (r < 0) return r; if (is_protected) return -EBUSY; r = cls_client::set_protection_status(&ictx->md_ctx, ictx->header_oid, snap_id, RBD_PROTECTION_STATUS_PROTECTED); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); return 0; } int snap_unprotect(ImageCtx *ictx, const char *snap_name) { ldout(ictx->cct, 20) << "snap_unprotect " << ictx << " " << snap_name << dendl; if (ictx->read_only) return -EROFS; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->md_lock); RWLock::RLocker l2(ictx->snap_lock); uint64_t features; ictx->get_features(ictx->snap_id, &features); if ((features & RBD_FEATURE_LAYERING) == 0) { lderr(ictx->cct) << "snap_unprotect: image must support layering" << dendl; return -ENOSYS; } snap_t snap_id = ictx->get_snap_id(snap_name); if (snap_id == CEPH_NOSNAP) return -ENOENT; bool is_unprotected; r = ictx->is_snap_unprotected(snap_name, &is_unprotected); if (r < 0) return r; if (is_unprotected) { lderr(ictx->cct) << "snap_unprotect: snapshot is already unprotected" << dendl; return -EINVAL; } r = cls_client::set_protection_status(&ictx->md_ctx, ictx->header_oid, snap_id, RBD_PROTECTION_STATUS_UNPROTECTING); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); parent_spec pspec(ictx->md_ctx.get_id(), ictx->id, snap_id); // search all pools for children depending on this snapshot Rados rados(ictx->md_ctx); // protect against pools being renamed/deleted bool retry_pool_check; do { retry_pool_check = false; std::list pools; rados.pool_list(pools); for (std::list::const_iterator it = pools.begin(); it != pools.end(); ++it) { IoCtx pool_ioctx; r = rados.ioctx_create(it->c_str(), pool_ioctx); if (r == -ENOENT) { ldout(ictx->cct, 1) << "pool " << *it << " no longer exists" << dendl; retry_pool_check = true; break; } else if (r < 0) { lderr(ictx->cct) << "snap_unprotect: can't create ioctx for pool " << *it << dendl; goto reprotect_and_return_err; } std::set children; r = cls_client::get_children(&pool_ioctx, RBD_CHILDREN, pspec, children); // key should not exist for this parent if there is no entry if (((r < 0) && (r != -ENOENT))) { lderr(ictx->cct) << "can't get children for pool " << *it << dendl; goto reprotect_and_return_err; } // if we found a child, can't unprotect if (r == 0) { lderr(ictx->cct) << "snap_unprotect: can't unprotect; at least " << children.size() << " child(ren) in pool " << it->c_str() << dendl; r = -EBUSY; goto reprotect_and_return_err; } pool_ioctx.close(); // last one out will self-destruct } } while(retry_pool_check); // didn't find any child in any pool, go ahead with unprotect r = cls_client::set_protection_status(&ictx->md_ctx, ictx->header_oid, snap_id, RBD_PROTECTION_STATUS_UNPROTECTED); notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); return 0; reprotect_and_return_err: int proterr = cls_client::set_protection_status(&ictx->md_ctx, ictx->header_oid, snap_id, RBD_PROTECTION_STATUS_PROTECTED); if (proterr < 0) { lderr(ictx->cct) << "snap_unprotect: can't reprotect image" << dendl; } notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); return r; } int snap_is_protected(ImageCtx *ictx, const char *snap_name, bool *is_protected) { ldout(ictx->cct, 20) << "snap_is_protected " << ictx << " " << snap_name << dendl; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->snap_lock); bool is_unprotected; r = ictx->is_snap_unprotected(snap_name, &is_unprotected); // consider both PROTECTED or UNPROTECTING to be 'protected', // since in either state they can't be deleted *is_protected = !is_unprotected; return r; } int create_v1(IoCtx& io_ctx, const char *imgname, uint64_t bid, uint64_t size, int order) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 2) << "adding rbd image to directory..." << dendl; int r = tmap_set(io_ctx, imgname); if (r < 0) { lderr(cct) << "error adding image to directory: " << cpp_strerror(r) << dendl; return r; } ldout(cct, 2) << "creating rbd image..." << dendl; struct rbd_obj_header_ondisk header; init_rbd_header(header, size, order, bid); bufferlist bl; bl.append((const char *)&header, sizeof(header)); string header_oid = old_header_name(imgname); r = io_ctx.write(header_oid, bl, bl.length(), 0); if (r < 0) { lderr(cct) << "Error writing image header: " << cpp_strerror(r) << dendl; int remove_r = tmap_rm(io_ctx, imgname); if (remove_r < 0) { lderr(cct) << "Could not remove image from directory after " << "header creation failed: " << cpp_strerror(r) << dendl; } return r; } ldout(cct, 2) << "done." << dendl; return 0; } int create_v2(IoCtx& io_ctx, const char *imgname, uint64_t bid, uint64_t size, int order, uint64_t features, uint64_t stripe_unit, uint64_t stripe_count) { ostringstream bid_ss; uint32_t extra; string id, id_obj, header_oid; int remove_r; ostringstream oss; CephContext *cct = (CephContext *)io_ctx.cct(); id_obj = id_obj_name(imgname); int r = io_ctx.create(id_obj, true); if (r < 0) { lderr(cct) << "error creating rbd id object: " << cpp_strerror(r) << dendl; return r; } extra = rand() % 0xFFFFFFFF; bid_ss << std::hex << bid << std::hex << extra; id = bid_ss.str(); r = cls_client::set_id(&io_ctx, id_obj, id); if (r < 0) { lderr(cct) << "error setting image id: " << cpp_strerror(r) << dendl; goto err_remove_id; } ldout(cct, 2) << "adding rbd image to directory..." << dendl; r = cls_client::dir_add_image(&io_ctx, RBD_DIRECTORY, imgname, id); if (r < 0) { lderr(cct) << "error adding image to directory: " << cpp_strerror(r) << dendl; goto err_remove_id; } oss << RBD_DATA_PREFIX << id; header_oid = header_name(id); r = cls_client::create_image(&io_ctx, header_oid, size, order, features, oss.str()); if (r < 0) { lderr(cct) << "error writing header: " << cpp_strerror(r) << dendl; goto err_remove_from_dir; } if ((stripe_unit || stripe_count) && (stripe_count != 1 || stripe_unit != (1ull << order))) { r = cls_client::set_stripe_unit_count(&io_ctx, header_oid, stripe_unit, stripe_count); if (r < 0) { lderr(cct) << "error setting striping parameters: " << cpp_strerror(r) << dendl; goto err_remove_header; } } ldout(cct, 2) << "done." << dendl; return 0; err_remove_header: remove_r = io_ctx.remove(header_oid); if (remove_r < 0) { lderr(cct) << "error cleaning up image header after creation failed: " << dendl; } err_remove_from_dir: remove_r = cls_client::dir_remove_image(&io_ctx, RBD_DIRECTORY, imgname, id); if (remove_r < 0) { lderr(cct) << "error cleaning up image from rbd_directory object " << "after creation failed: " << cpp_strerror(remove_r) << dendl; } err_remove_id: remove_r = io_ctx.remove(id_obj); if (remove_r < 0) { lderr(cct) << "error cleaning up id object after creation failed: " << cpp_strerror(remove_r) << dendl; } return r; } int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size, int *order) { CephContext *cct = (CephContext *)io_ctx.cct(); bool old_format = cct->_conf->rbd_default_format == 1; uint64_t features = old_format ? 0 : cct->_conf->rbd_default_features; return create(io_ctx, imgname, size, old_format, features, order, 0, 0); } int create(IoCtx& io_ctx, const char *imgname, uint64_t size, bool old_format, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count) { if (!order) return -EINVAL; CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 20) << "create " << &io_ctx << " name = " << imgname << " size = " << size << " old_format = " << old_format << " features = " << features << " order = " << *order << " stripe_unit = " << stripe_unit << " stripe_count = " << stripe_count << dendl; if (features & ~RBD_FEATURES_ALL) { lderr(cct) << "librbd does not support requested features." << dendl; return -ENOSYS; } // make sure it doesn't already exist, in either format int r = detect_format(io_ctx, imgname, NULL, NULL); if (r != -ENOENT) { if (r) { lderr(cct) << "Could not tell if " << imgname << " already exists" << dendl; return r; } lderr(cct) << "rbd image " << imgname << " already exists" << dendl; return -EEXIST; } if (!*order) *order = cct->_conf->rbd_default_order; if (!*order) *order = RBD_DEFAULT_OBJ_ORDER; if (*order && (*order > 64 || *order < 12)) { lderr(cct) << "order must be in the range [12, 64]" << dendl; return -EDOM; } Rados rados(io_ctx); uint64_t bid = rados.get_instance_id(); // if striping is enabled, use possibly custom defaults if (!old_format && (features & RBD_FEATURE_STRIPINGV2) && !stripe_unit && !stripe_count) { stripe_unit = cct->_conf->rbd_default_stripe_unit; stripe_count = cct->_conf->rbd_default_stripe_count; } // normalize for default striping if (stripe_unit == (1ull << *order) && stripe_count == 1) { stripe_unit = 0; stripe_count = 0; } if ((stripe_unit || stripe_count) && (features & RBD_FEATURE_STRIPINGV2) == 0) { lderr(cct) << "STRIPINGV2 and format 2 or later required for non-default striping" << dendl; return -EINVAL; } if ((stripe_unit && !stripe_count) || (!stripe_unit && stripe_count)) return -EINVAL; if (old_format) { if (stripe_unit && stripe_unit != (1ull << *order)) return -EINVAL; if (stripe_count && stripe_count != 1) return -EINVAL; return create_v1(io_ctx, imgname, bid, size, *order); } else { return create_v2(io_ctx, imgname, bid, size, *order, features, stripe_unit, stripe_count); } } /* * Parent may be in different pool, hence different IoCtx */ int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name, IoCtx& c_ioctx, const char *c_name, uint64_t features, int *c_order, uint64_t stripe_unit, int stripe_count) { CephContext *cct = (CephContext *)p_ioctx.cct(); ldout(cct, 20) << "clone " << &p_ioctx << " name " << p_name << " snap " << p_snap_name << "to child " << &c_ioctx << " name " << c_name << " features = " << features << " order = " << *c_order << " stripe_unit = " << stripe_unit << " stripe_count = " << stripe_count << dendl; if (features & ~RBD_FEATURES_ALL) { lderr(cct) << "librbd does not support requested features" << dendl; return -ENOSYS; } // make sure child doesn't already exist, in either format int r = detect_format(c_ioctx, c_name, NULL, NULL); if (r != -ENOENT) { lderr(cct) << "rbd image " << c_name << " already exists" << dendl; return -EEXIST; } if (p_snap_name == NULL) { lderr(cct) << "image to be cloned must be a snapshot" << dendl; return -EINVAL; } bool snap_protected; int order; uint64_t size; uint64_t p_features; int remove_r; librbd::NoOpProgressContext no_op; ImageCtx *c_imctx = NULL; // make sure parent snapshot exists ImageCtx *p_imctx = new ImageCtx(p_name, "", p_snap_name, p_ioctx, true); r = open_image(p_imctx); if (r < 0) { lderr(cct) << "error opening parent image: " << cpp_strerror(-r) << dendl; return r; } parent_spec pspec(p_ioctx.get_id(), p_imctx->id, p_imctx->snap_id); if (p_imctx->old_format) { lderr(cct) << "parent image must be in new format" << dendl; r = -EINVAL; goto err_close_parent; } p_imctx->md_lock.get_read(); p_imctx->snap_lock.get_read(); p_imctx->get_features(p_imctx->snap_id, &p_features); size = p_imctx->get_image_size(p_imctx->snap_id); p_imctx->is_snap_protected(p_imctx->snap_name, &snap_protected); p_imctx->snap_lock.put_read(); p_imctx->md_lock.put_read(); if ((p_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) { lderr(cct) << "parent image must support layering" << dendl; r = -ENOSYS; goto err_close_parent; } if (!snap_protected) { lderr(cct) << "parent snapshot must be protected" << dendl; r = -EINVAL; goto err_close_parent; } order = *c_order; if (!order) order = p_imctx->order; r = create(c_ioctx, c_name, size, false, features, &order, stripe_unit, stripe_count); if (r < 0) { lderr(cct) << "error creating child: " << cpp_strerror(r) << dendl; goto err_close_parent; } c_imctx = new ImageCtx(c_name, "", NULL, c_ioctx, false); r = open_image(c_imctx); if (r < 0) { lderr(cct) << "Error opening new image: " << cpp_strerror(r) << dendl; goto err_remove; } r = cls_client::set_parent(&c_ioctx, c_imctx->header_oid, pspec, size); if (r < 0) { lderr(cct) << "couldn't set parent: " << r << dendl; goto err_close_child; } r = cls_client::add_child(&c_ioctx, RBD_CHILDREN, pspec, c_imctx->id); if (r < 0) { lderr(cct) << "couldn't add child: " << r << dendl; goto err_close_child; } p_imctx->md_lock.get_write(); r = ictx_refresh(p_imctx); p_imctx->md_lock.put_write(); if (r == 0) { p_imctx->snap_lock.get_read(); r = p_imctx->is_snap_protected(p_imctx->snap_name, &snap_protected); p_imctx->snap_lock.put_read(); } if (r < 0 || !snap_protected) { // we lost the race with unprotect r = -EINVAL; goto err_remove_child; } ldout(cct, 2) << "done." << dendl; close_image(c_imctx); close_image(p_imctx); return 0; err_remove_child: remove_r = cls_client::remove_child(&c_ioctx, RBD_CHILDREN, pspec, c_imctx->id); if (remove_r < 0) { lderr(cct) << "Error removing failed clone from list of children: " << cpp_strerror(remove_r) << dendl; } err_close_child: close_image(c_imctx); err_remove: remove_r = remove(c_ioctx, c_name, no_op); if (remove_r < 0) { lderr(cct) << "Error removing failed clone: " << cpp_strerror(remove_r) << dendl; } err_close_parent: close_image(p_imctx); return r; } int rename(IoCtx& io_ctx, const char *srcname, const char *dstname) { CephContext *cct = (CephContext *)io_ctx.cct(); ldout(cct, 20) << "rename " << &io_ctx << " " << srcname << " -> " << dstname << dendl; bool old_format; uint64_t src_size; int r = detect_format(io_ctx, srcname, &old_format, &src_size); if (r < 0) { lderr(cct) << "error finding source object: " << cpp_strerror(r) << dendl; return r; } string src_oid = old_format ? old_header_name(srcname) : id_obj_name(srcname); string dst_oid = old_format ? old_header_name(dstname) : id_obj_name(dstname); string id; if (!old_format) { r = cls_client::get_id(&io_ctx, src_oid, &id); if (r < 0) { lderr(cct) << "error reading image id: " << cpp_strerror(r) << dendl; return r; } } bufferlist databl; map omap_values; r = io_ctx.read(src_oid, databl, src_size, 0); if (r < 0) { lderr(cct) << "error reading source object: " << src_oid << ": " << cpp_strerror(r) << dendl; return r; } int MAX_READ = 1024; string last_read = ""; do { map outbl; r = io_ctx.omap_get_vals(src_oid, last_read, MAX_READ, &outbl); if (r < 0) { lderr(cct) << "error reading source object omap values: " << cpp_strerror(r) << dendl; return r; } omap_values.insert(outbl.begin(), outbl.end()); if (!outbl.empty()) last_read = outbl.rbegin()->first; } while (r == MAX_READ); r = detect_format(io_ctx, dstname, NULL, NULL); if (r < 0 && r != -ENOENT) { lderr(cct) << "error checking for existing image called " << dstname << ":" << cpp_strerror(r) << dendl; return r; } if (r == 0) { lderr(cct) << "rbd image " << dstname << " already exists" << dendl; return -EEXIST; } librados::ObjectWriteOperation op; op.create(true); op.write_full(databl); if (!omap_values.empty()) op.omap_set(omap_values); r = io_ctx.operate(dst_oid, &op); if (r < 0) { lderr(cct) << "error writing destination object: " << dst_oid << ": " << cpp_strerror(r) << dendl; return r; } if (old_format) { r = tmap_set(io_ctx, dstname); if (r < 0) { io_ctx.remove(dst_oid); lderr(cct) << "couldn't add " << dstname << " to directory: " << cpp_strerror(r) << dendl; return r; } r = tmap_rm(io_ctx, srcname); if (r < 0) { lderr(cct) << "warning: couldn't remove old entry from directory (" << srcname << ")" << dendl; } } else { r = cls_client::dir_rename_image(&io_ctx, RBD_DIRECTORY, srcname, dstname, id); if (r < 0) { lderr(cct) << "error updating directory: " << cpp_strerror(r) << dendl; return r; } } r = io_ctx.remove(src_oid); if (r < 0 && r != -ENOENT) { lderr(cct) << "warning: couldn't remove old source object (" << src_oid << ")" << dendl; } if (old_format) { notify_change(io_ctx, old_header_name(srcname), NULL, NULL); } return 0; } int info(ImageCtx *ictx, image_info_t& info, size_t infosize) { ldout(ictx->cct, 20) << "info " << ictx << dendl; int r = ictx_check(ictx); if (r < 0) return r; image_info(ictx, info, infosize); return 0; } int get_old_format(ImageCtx *ictx, uint8_t *old) { int r = ictx_check(ictx); if (r < 0) return r; *old = ictx->old_format; return 0; } int get_size(ImageCtx *ictx, uint64_t *size) { int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->md_lock); RWLock::RLocker l2(ictx->snap_lock); *size = ictx->get_image_size(ictx->snap_id); return 0; } int get_features(ImageCtx *ictx, uint64_t *features) { int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->md_lock); RWLock::RLocker l2(ictx->snap_lock); return ictx->get_features(ictx->snap_id, features); } int get_overlap(ImageCtx *ictx, uint64_t *overlap) { int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->snap_lock); RWLock::RLocker l2(ictx->parent_lock); return ictx->get_parent_overlap(ictx->snap_id, overlap); } int open_parent(ImageCtx *ictx) { string pool_name; Rados rados(ictx->md_ctx); int64_t pool_id = ictx->get_parent_pool_id(ictx->snap_id); string parent_image_id = ictx->get_parent_image_id(ictx->snap_id); snap_t parent_snap_id = ictx->get_parent_snap_id(ictx->snap_id); assert(parent_snap_id != CEPH_NOSNAP); if (pool_id < 0) return -ENOENT; int r = rados.pool_reverse_lookup(pool_id, &pool_name); if (r < 0) { lderr(ictx->cct) << "error looking up name for pool id " << pool_id << ": " << cpp_strerror(r) << dendl; return r; } IoCtx p_ioctx; r = rados.ioctx_create(pool_name.c_str(), p_ioctx); if (r < 0) { lderr(ictx->cct) << "error opening pool " << pool_name << ": " << cpp_strerror(r) << dendl; return r; } // since we don't know the image and snapshot name, set their ids and // reset the snap_name and snap_exists fields after we read the header ictx->parent = new ImageCtx("", parent_image_id, NULL, p_ioctx, true); // set rados flags for reading the parent image if (ictx->cct->_conf->rbd_balance_parent_reads) ictx->parent->set_read_flag(librados::OPERATION_BALANCE_READS); else if (ictx->cct->_conf->rbd_localize_parent_reads) ictx->parent->set_read_flag(librados::OPERATION_LOCALIZE_READS); r = open_image(ictx->parent); if (r < 0) { lderr(ictx->cct) << "error opening parent image: " << cpp_strerror(r) << dendl; ictx->parent = NULL; return r; } ictx->parent->cache_lock.Lock(); ictx->parent->snap_lock.get_write(); r = ictx->parent->get_snap_name(parent_snap_id, &ictx->parent->snap_name); if (r < 0) { lderr(ictx->cct) << "parent snapshot does not exist" << dendl; ictx->parent->snap_lock.put_write(); ictx->parent->cache_lock.Unlock(); close_image(ictx->parent); ictx->parent = NULL; return r; } ictx->parent->snap_set(ictx->parent->snap_name); ictx->parent->parent_lock.get_write(); r = refresh_parent(ictx->parent); if (r < 0) { lderr(ictx->cct) << "error refreshing parent snapshot " << ictx->parent->id << " " << ictx->parent->snap_name << dendl; ictx->parent->parent_lock.put_write(); ictx->parent->snap_lock.put_write(); ictx->parent->cache_lock.Unlock(); close_image(ictx->parent); ictx->parent = NULL; return r; } ictx->parent->parent_lock.put_write(); ictx->parent->snap_lock.put_write(); ictx->parent->cache_lock.Unlock(); return 0; } int get_parent_info(ImageCtx *ictx, string *parent_pool_name, string *parent_name, string *parent_snap_name) { int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->snap_lock); RWLock::RLocker l2(ictx->parent_lock); if (ictx->parent == NULL) { return -ENOENT; } parent_spec parent_spec; if (ictx->snap_id == CEPH_NOSNAP) { if (!ictx->parent) return -ENOENT; parent_spec = ictx->parent_md.spec; } else { r = ictx->get_parent_spec(ictx->snap_id, &parent_spec); if (r < 0) { lderr(ictx->cct) << "Can't find snapshot id" << ictx->snap_id << dendl; return r; } if (parent_spec.pool_id == -1) return -ENOENT; } if (parent_pool_name) { Rados rados(ictx->md_ctx); r = rados.pool_reverse_lookup(parent_spec.pool_id, parent_pool_name); if (r < 0) { lderr(ictx->cct) << "error looking up pool name" << cpp_strerror(r) << dendl; return r; } } if (parent_snap_name) { RWLock::RLocker l(ictx->parent->snap_lock); r = ictx->parent->get_snap_name(parent_spec.snap_id, parent_snap_name); if (r < 0) { lderr(ictx->cct) << "error finding parent snap name: " << cpp_strerror(r) << dendl; return r; } } if (parent_name) { r = cls_client::dir_get_name(&ictx->parent->md_ctx, RBD_DIRECTORY, parent_spec.image_id, parent_name); if (r < 0) { lderr(ictx->cct) << "error getting parent image name: " << cpp_strerror(r) << dendl; return r; } } return 0; } int remove(IoCtx& io_ctx, const char *imgname, ProgressContext& prog_ctx) { CephContext *cct((CephContext *)io_ctx.cct()); ldout(cct, 20) << "remove " << &io_ctx << " " << imgname << dendl; string id; bool old_format = false; bool unknown_format = true; ImageCtx *ictx = new ImageCtx(imgname, "", NULL, io_ctx, false); int r = open_image(ictx); if (r < 0) { ldout(cct, 2) << "error opening image: " << cpp_strerror(-r) << dendl; } else { string header_oid = ictx->header_oid; old_format = ictx->old_format; unknown_format = false; id = ictx->id; if (ictx->snaps.size()) { lderr(cct) << "image has snapshots - not removing" << dendl; close_image(ictx); return -ENOTEMPTY; } std::list watchers; r = io_ctx.list_watchers(header_oid, &watchers); if (r < 0) { lderr(cct) << "error listing watchers" << dendl; close_image(ictx); return r; } if (watchers.size() > 1) { lderr(cct) << "image has watchers - not removing" << dendl; close_image(ictx); return -EBUSY; } ictx->md_lock.get_read(); trim_image(ictx, 0, prog_ctx); ictx->md_lock.put_read(); ictx->parent_lock.get_read(); // struct assignment parent_info parent_info = ictx->parent_md; ictx->parent_lock.put_read(); r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN, parent_info.spec, id); if (r < 0 && r != -ENOENT) { lderr(cct) << "error removing child from children list" << dendl; close_image(ictx); return r; } close_image(ictx); ldout(cct, 2) << "removing header..." << dendl; r = io_ctx.remove(header_oid); if (r < 0 && r != -ENOENT) { lderr(cct) << "error removing header: " << cpp_strerror(-r) << dendl; return r; } } if (old_format || unknown_format) { ldout(cct, 2) << "removing rbd image from directory..." << dendl; r = tmap_rm(io_ctx, imgname); old_format = (r == 0); if (r < 0 && !unknown_format) { lderr(cct) << "error removing img from old-style directory: " << cpp_strerror(-r) << dendl; return r; } } if (!old_format) { ldout(cct, 2) << "removing id object..." << dendl; r = io_ctx.remove(id_obj_name(imgname)); if (r < 0 && r != -ENOENT) { lderr(cct) << "error removing id object: " << cpp_strerror(r) << dendl; return r; } r = cls_client::dir_get_id(&io_ctx, RBD_DIRECTORY, imgname, &id); if (r < 0 && r != -ENOENT) { lderr(cct) << "error getting id of image" << dendl; return r; } ldout(cct, 2) << "removing rbd image from directory..." << dendl; r = cls_client::dir_remove_image(&io_ctx, RBD_DIRECTORY, imgname, id); if (r < 0) { lderr(cct) << "error removing img from new-style directory: " << cpp_strerror(-r) << dendl; return r; } } ldout(cct, 2) << "done." << dendl; return 0; } int resize_helper(ImageCtx *ictx, uint64_t size, ProgressContext& prog_ctx) { CephContext *cct = ictx->cct; if (size == ictx->size) { ldout(cct, 2) << "no change in size (" << ictx->size << " -> " << size << ")" << dendl; return 0; } if (size > ictx->size) { ldout(cct, 2) << "expanding image " << ictx->size << " -> " << size << dendl; // TODO: make ictx->set_size } else { ldout(cct, 2) << "shrinking image " << ictx->size << " -> " << size << dendl; trim_image(ictx, size, prog_ctx); } ictx->size = size; int r; if (ictx->old_format) { // rewrite header bufferlist bl; ictx->header.image_size = size; bl.append((const char *)&(ictx->header), sizeof(ictx->header)); r = ictx->md_ctx.write(ictx->header_oid, bl, bl.length(), 0); } else { r = cls_client::set_size(&(ictx->md_ctx), ictx->header_oid, size); } // TODO: remove this useless check if (r == -ERANGE) lderr(cct) << "operation might have conflicted with another client!" << dendl; if (r < 0) { lderr(cct) << "error writing header: " << cpp_strerror(-r) << dendl; return r; } else { notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); } return 0; } int resize(ImageCtx *ictx, uint64_t size, ProgressContext& prog_ctx) { CephContext *cct = ictx->cct; ldout(cct, 20) << "resize " << ictx << " " << ictx->size << " -> " << size << dendl; if (ictx->read_only) return -EROFS; int r = ictx_check(ictx); if (r < 0) return r; RWLock::WLocker l(ictx->md_lock); if (size < ictx->size && ictx->object_cacher) { // need to invalidate since we're deleting objects, and // ObjectCacher doesn't track non-existent objects r = ictx->invalidate_cache(); if (r < 0) return r; } resize_helper(ictx, size, prog_ctx); ldout(cct, 2) << "done." << dendl; ictx->perfcounter->inc(l_librbd_resize); return 0; } int snap_list(ImageCtx *ictx, vector& snaps) { ldout(ictx->cct, 20) << "snap_list " << ictx << dendl; int r = ictx_check(ictx); if (r < 0) return r; bufferlist bl, bl2; RWLock::RLocker l(ictx->snap_lock); for (map::iterator it = ictx->snaps_by_name.begin(); it != ictx->snaps_by_name.end(); ++it) { snap_info_t info; info.name = it->first; info.id = it->second.id; info.size = it->second.size; snaps.push_back(info); } return 0; } bool snap_exists(ImageCtx *ictx, const char *snap_name) { ldout(ictx->cct, 20) << "snap_exists " << ictx << " " << snap_name << dendl; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker l(ictx->snap_lock); return ictx->snaps_by_name.count(snap_name); } int add_snap(ImageCtx *ictx, const char *snap_name) { uint64_t snap_id; int r = ictx->md_ctx.selfmanaged_snap_create(&snap_id); if (r < 0) { lderr(ictx->cct) << "failed to create snap id: " << cpp_strerror(-r) << dendl; return r; } if (ictx->old_format) { r = cls_client::old_snapshot_add(&ictx->md_ctx, ictx->header_oid, snap_id, snap_name); } else { r = cls_client::snapshot_add(&ictx->md_ctx, ictx->header_oid, snap_id, snap_name); } if (r < 0) { lderr(ictx->cct) << "adding snapshot to header failed: " << cpp_strerror(r) << dendl; return r; } return 0; } int rm_snap(ImageCtx *ictx, const char *snap_name) { int r; if (ictx->old_format) { r = cls_client::old_snapshot_remove(&ictx->md_ctx, ictx->header_oid, snap_name); } else { RWLock::RLocker l(ictx->snap_lock); r = cls_client::snapshot_remove(&ictx->md_ctx, ictx->header_oid, ictx->get_snap_id(snap_name)); } if (r < 0) { lderr(ictx->cct) << "removing snapshot from header failed: " << cpp_strerror(r) << dendl; return r; } return 0; } int ictx_check(ImageCtx *ictx) { CephContext *cct = ictx->cct; ldout(cct, 20) << "ictx_check " << ictx << dendl; ictx->refresh_lock.Lock(); bool needs_refresh = ictx->last_refresh != ictx->refresh_seq; ictx->refresh_lock.Unlock(); if (needs_refresh) { RWLock::WLocker l(ictx->md_lock); int r = ictx_refresh(ictx); if (r < 0) { lderr(cct) << "Error re-reading rbd header: " << cpp_strerror(-r) << dendl; return r; } } return 0; } int refresh_parent(ImageCtx *ictx) { // close the parent if it changed or this image no longer needs // to read from it int r; if (ictx->parent) { uint64_t overlap; r = ictx->get_parent_overlap(ictx->snap_id, &overlap); if (r < 0) return r; if (!overlap || ictx->parent->md_ctx.get_id() != ictx->get_parent_pool_id(ictx->snap_id) || ictx->parent->id != ictx->get_parent_image_id(ictx->snap_id) || ictx->parent->snap_id != ictx->get_parent_snap_id(ictx->snap_id)) { ictx->clear_nonexistence_cache(); close_image(ictx->parent); ictx->parent = NULL; } } if (ictx->get_parent_pool_id(ictx->snap_id) > -1 && !ictx->parent) { r = open_parent(ictx); if (r < 0) { lderr(ictx->cct) << "error opening parent snapshot: " << cpp_strerror(r) << dendl; return r; } } return 0; } int ictx_refresh(ImageCtx *ictx) { CephContext *cct = ictx->cct; bufferlist bl, bl2; ldout(cct, 20) << "ictx_refresh " << ictx << dendl; ictx->refresh_lock.Lock(); int refresh_seq = ictx->refresh_seq; ictx->refresh_lock.Unlock(); ::SnapContext new_snapc; bool new_snap = false; vector snap_names; vector snap_sizes; vector snap_features; vector snap_parents; vector snap_protection; { Mutex::Locker cache_locker(ictx->cache_lock); RWLock::WLocker snap_locker(ictx->snap_lock); { int r; RWLock::WLocker parent_locker(ictx->parent_lock); ictx->lockers.clear(); if (ictx->old_format) { r = read_header(ictx->md_ctx, ictx->header_oid, &ictx->header, NULL); if (r < 0) { lderr(cct) << "Error reading header: " << cpp_strerror(r) << dendl; return r; } r = cls_client::old_snapshot_list(&ictx->md_ctx, ictx->header_oid, &snap_names, &snap_sizes, &new_snapc); if (r < 0) { lderr(cct) << "Error listing snapshots: " << cpp_strerror(r) << dendl; return r; } ClsLockType lock_type = LOCK_NONE; r = rados::cls::lock::get_lock_info(&ictx->md_ctx, ictx->header_oid, RBD_LOCK_NAME, &ictx->lockers, &lock_type, &ictx->lock_tag); // If EOPNOTSUPP, treat image as if there are no locks (we can't // query them). // Ugly: OSDs prior to eed28daaf8927339c2ecae1b1b06c1b63678ab03 // return EIO when the class isn't present; should be EOPNOTSUPP. // Treat EIO or EOPNOTSUPP the same for now, as LOCK_NONE. Blech. if (r < 0 && ((r != -EOPNOTSUPP) && (r != -EIO))) { lderr(cct) << "Error getting lock info: " << cpp_strerror(r) << dendl; return r; } ictx->exclusive_locked = (lock_type == LOCK_EXCLUSIVE); ictx->order = ictx->header.options.order; ictx->size = ictx->header.image_size; ictx->object_prefix = ictx->header.block_name; ictx->init_layout(); } else { do { uint64_t incompatible_features; r = cls_client::get_mutable_metadata(&ictx->md_ctx, ictx->header_oid, &ictx->size, &ictx->features, &incompatible_features, &ictx->lockers, &ictx->exclusive_locked, &ictx->lock_tag, &new_snapc, &ictx->parent_md); if (r < 0) { lderr(cct) << "Error reading mutable metadata: " << cpp_strerror(r) << dendl; return r; } uint64_t unsupported = incompatible_features & ~RBD_FEATURES_ALL; if (unsupported) { lderr(ictx->cct) << "Image uses unsupported features: " << unsupported << dendl; return -ENOSYS; } r = cls_client::snapshot_list(&(ictx->md_ctx), ictx->header_oid, new_snapc.snaps, &snap_names, &snap_sizes, &snap_features, &snap_parents, &snap_protection); // -ENOENT here means we raced with snapshot deletion if (r < 0 && r != -ENOENT) { lderr(ictx->cct) << "snapc = " << new_snapc << dendl; lderr(ictx->cct) << "Error listing snapshots: " << cpp_strerror(r) << dendl; return r; } } while (r == -ENOENT); } for (size_t i = 0; i < new_snapc.snaps.size(); ++i) { uint64_t features = ictx->old_format ? 0 : snap_features[i]; parent_info parent; if (!ictx->old_format) parent = snap_parents[i]; vector::const_iterator it = find(ictx->snaps.begin(), ictx->snaps.end(), new_snapc.snaps[i].val); if (it == ictx->snaps.end()) { new_snap = true; ldout(cct, 20) << "new snapshot id=" << new_snapc.snaps[i].val << " name=" << snap_names[i] << " size=" << snap_sizes[i] << " features=" << features << dendl; } } ictx->snaps.clear(); ictx->snaps_by_name.clear(); for (size_t i = 0; i < new_snapc.snaps.size(); ++i) { uint64_t features = ictx->old_format ? 0 : snap_features[i]; uint8_t protection_status = ictx->old_format ? (uint8_t)RBD_PROTECTION_STATUS_UNPROTECTED : snap_protection[i]; parent_info parent; if (!ictx->old_format) parent = snap_parents[i]; ictx->add_snap(snap_names[i], new_snapc.snaps[i].val, snap_sizes[i], features, parent, protection_status); } r = refresh_parent(ictx); if (r < 0) return r; } // release parent_lock if (!new_snapc.is_valid()) { lderr(cct) << "image snap context is invalid!" << dendl; return -EIO; } ictx->snapc = new_snapc; if (ictx->snap_id != CEPH_NOSNAP && ictx->get_snap_id(ictx->snap_name) != ictx->snap_id) { lderr(cct) << "tried to read from a snapshot that no longer exists: " << ictx->snap_name << dendl; ictx->snap_exists = false; } ictx->data_ctx.selfmanaged_snap_set_write_ctx(ictx->snapc.seq, ictx->snaps); } // release snap_lock and cache_lock if (new_snap) { _flush(ictx); } ictx->refresh_lock.Lock(); ictx->last_refresh = refresh_seq; ictx->refresh_lock.Unlock(); return 0; } int snap_rollback(ImageCtx *ictx, const char *snap_name, ProgressContext& prog_ctx) { CephContext *cct = ictx->cct; ldout(cct, 20) << "snap_rollback " << ictx << " snap = " << snap_name << dendl; int r = ictx_check(ictx); if (r < 0) return r; RWLock::WLocker l(ictx->md_lock); snap_t snap_id; uint64_t new_size; { // need to drop snap_lock before invalidating cache RWLock::RLocker l2(ictx->snap_lock); if (!ictx->snap_exists) return -ENOENT; if (ictx->snap_id != CEPH_NOSNAP || ictx->read_only) return -EROFS; snap_id = ictx->get_snap_id(snap_name); if (snap_id == CEPH_NOSNAP) { lderr(cct) << "No such snapshot found." << dendl; return -ENOENT; } new_size = ictx->get_image_size(snap_id); } // need to flush any pending writes before resizing and rolling back - // writes might create new snapshots. Rolling back will replace // the current version, so we have to invalidate that too. r = ictx->invalidate_cache(); if (r < 0) return r; ldout(cct, 2) << "resizing to snapshot size..." << dendl; NoOpProgressContext no_op; r = resize_helper(ictx, new_size, no_op); if (r < 0) { lderr(cct) << "Error resizing to snapshot size: " << cpp_strerror(-r) << dendl; return r; } r = rollback_image(ictx, snap_id, prog_ctx); if (r < 0) { lderr(cct) << "Error rolling back image: " << cpp_strerror(-r) << dendl; return r; } notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); ictx->perfcounter->inc(l_librbd_snap_rollback); return r; } struct CopyProgressCtx { CopyProgressCtx(ProgressContext &p) : destictx(NULL), src_size(0), prog_ctx(p) { } ImageCtx *destictx; uint64_t src_size; ProgressContext &prog_ctx; }; int do_copy_extent(uint64_t offset, size_t len, const char *buf, void *data) { CopyProgressCtx *cp = reinterpret_cast(data); cp->prog_ctx.update_progress(offset, cp->src_size); int ret = 0; if (buf) { ret = write(cp->destictx, offset, len, buf); } return ret; } int copy(ImageCtx *src, IoCtx& dest_md_ctx, const char *destname, ProgressContext &prog_ctx) { CephContext *cct = (CephContext *)dest_md_ctx.cct(); ldout(cct, 20) << "copy " << src->name << (src->snap_name.length() ? "@" + src->snap_name : "") << " -> " << destname << dendl; int order = src->order; src->md_lock.get_read(); src->snap_lock.get_read(); uint64_t src_size = src->get_image_size(src->snap_id); src->snap_lock.put_read(); src->md_lock.put_read(); int r = create(dest_md_ctx, destname, src_size, src->old_format, src->features, &order, src->stripe_unit, src->stripe_count); if (r < 0) { lderr(cct) << "header creation failed" << dendl; return r; } ImageCtx *dest = new librbd::ImageCtx(destname, "", NULL, dest_md_ctx, false); r = open_image(dest); if (r < 0) { lderr(cct) << "failed to read newly created header" << dendl; return r; } r = copy(src, dest, prog_ctx); close_image(dest); return r; } class C_CopyWrite : public Context { public: C_CopyWrite(SimpleThrottle *throttle, bufferlist *bl) : m_throttle(throttle), m_bl(bl) {} virtual void finish(int r) { delete m_bl; m_throttle->end_op(r); } private: SimpleThrottle *m_throttle; bufferlist *m_bl; }; class C_CopyRead : public Context { public: C_CopyRead(SimpleThrottle *throttle, ImageCtx *dest, uint64_t offset, bufferlist *bl) : m_throttle(throttle), m_dest(dest), m_offset(offset), m_bl(bl) { m_throttle->start_op(); } virtual void finish(int r) { if (r < 0) { lderr(m_dest->cct) << "error reading from source image at offset " << m_offset << ": " << cpp_strerror(r) << dendl; delete m_bl; m_throttle->end_op(r); return; } assert(m_bl->length() == (size_t)r); if (m_bl->is_zero()) { delete m_bl; m_throttle->end_op(r); return; } Context *ctx = new C_CopyWrite(m_throttle, m_bl); AioCompletion *comp = aio_create_completion_internal(ctx, rbd_ctx_cb); aio_write(m_dest, m_offset, m_bl->length(), m_bl->c_str(), comp); } private: SimpleThrottle *m_throttle; ImageCtx *m_dest; uint64_t m_offset; bufferlist *m_bl; }; int copy(ImageCtx *src, ImageCtx *dest, ProgressContext &prog_ctx) { src->md_lock.get_read(); src->snap_lock.get_read(); uint64_t src_size = src->get_image_size(src->snap_id); src->snap_lock.put_read(); src->md_lock.put_read(); dest->md_lock.get_read(); dest->snap_lock.get_read(); uint64_t dest_size = dest->get_image_size(dest->snap_id); dest->snap_lock.put_read(); dest->md_lock.put_read(); CephContext *cct = src->cct; if (dest_size < src_size) { lderr(cct) << " src size " << src_size << " >= dest size " << dest_size << dendl; return -EINVAL; } int r; SimpleThrottle throttle(cct->_conf->rbd_concurrent_management_ops, false); uint64_t period = src->get_stripe_period(); for (uint64_t offset = 0; offset < src_size; offset += period) { if (throttle.pending_error()) { return throttle.wait_for_ret(); } uint64_t len = min(period, src_size - offset); bufferlist *bl = new bufferlist(); Context *ctx = new C_CopyRead(&throttle, dest, offset, bl); AioCompletion *comp = aio_create_completion_internal(ctx, rbd_ctx_cb); aio_read(src, offset, len, NULL, bl, comp); prog_ctx.update_progress(offset, src_size); } r = throttle.wait_for_ret(); if (r >= 0) prog_ctx.update_progress(src_size, src_size); return r; } // common snap_set functionality for snap_set and open_image int _snap_set(ImageCtx *ictx, const char *snap_name) { Mutex::Locker cache_locker(ictx->cache_lock); RWLock::WLocker snap_locker(ictx->snap_lock); RWLock::WLocker parent_locker(ictx->parent_lock); int r; if ((snap_name != NULL) && (strlen(snap_name) != 0)) { r = ictx->snap_set(snap_name); } else { ictx->snap_unset(); r = 0; } if (r < 0) { return r; } refresh_parent(ictx); return 0; } int snap_set(ImageCtx *ictx, const char *snap_name) { ldout(ictx->cct, 20) << "snap_set " << ictx << " snap = " << (snap_name ? snap_name : "NULL") << dendl; // ignore return value, since we may be set to a non-existent // snapshot and the user is trying to fix that ictx_check(ictx); if (ictx->object_cacher) { // complete pending writes before we're set to a snapshot and // get -EROFS for writes RWLock::WLocker l(ictx->md_lock); ictx->flush_cache(); } return _snap_set(ictx, snap_name); } int open_image(ImageCtx *ictx) { ldout(ictx->cct, 20) << "open_image: ictx = " << ictx << " name = '" << ictx->name << "' id = '" << ictx->id << "' snap_name = '" << ictx->snap_name << "'" << dendl; int r = ictx->init(); if (r < 0) goto err_close; if (!ictx->read_only) { r = ictx->register_watch(); if (r < 0) { lderr(ictx->cct) << "error registering a watch: " << cpp_strerror(r) << dendl; goto err_close; } } ictx->md_lock.get_write(); r = ictx_refresh(ictx); ictx->md_lock.put_write(); if (r < 0) goto err_close; if ((r = _snap_set(ictx, ictx->snap_name.c_str())) < 0) goto err_close; return 0; err_close: close_image(ictx); return r; } void close_image(ImageCtx *ictx) { ldout(ictx->cct, 20) << "close_image " << ictx << dendl; ictx->aio_work_queue->drain(); if (ictx->object_cacher) { ictx->shutdown_cache(); // implicitly flushes } else { flush(ictx); ictx->wait_for_pending_aio(); } if (ictx->parent) { close_image(ictx->parent); ictx->parent = NULL; } if (ictx->wctx) ictx->unregister_watch(); delete ictx; } // 'flatten' child image by copying all parent's blocks int flatten(ImageCtx *ictx, ProgressContext &prog_ctx) { CephContext *cct = ictx->cct; ldout(cct, 20) << "flatten" << dendl; if (ictx->read_only) return -EROFS; int r; // ictx_check also updates parent data if ((r = ictx_check(ictx)) < 0) { lderr(cct) << "ictx_check failed" << dendl; return r; } uint64_t object_size; uint64_t period; uint64_t overlap; uint64_t overlap_periods; uint64_t overlap_objects; ::SnapContext snapc; { RWLock::RLocker l(ictx->md_lock); RWLock::RLocker l2(ictx->snap_lock); RWLock::RLocker l3(ictx->parent_lock); // can't flatten a non-clone if (ictx->parent_md.spec.pool_id == -1) { lderr(cct) << "image has no parent" << dendl; return -EINVAL; } if (ictx->snap_id != CEPH_NOSNAP || ictx->read_only) { lderr(cct) << "snapshots cannot be flattened" << dendl; return -EROFS; } snapc = ictx->snapc; assert(ictx->parent != NULL); assert(ictx->parent_md.overlap <= ictx->size); object_size = ictx->get_object_size(); period = ictx->get_stripe_period(); overlap = ictx->parent_md.overlap; overlap_periods = (overlap + period - 1) / period; overlap_objects = overlap_periods * ictx->get_stripe_count(); } SimpleThrottle throttle(cct->_conf->rbd_concurrent_management_ops, false); for (uint64_t ono = 0; ono < overlap_objects; ono++) { if (throttle.pending_error()) { return throttle.wait_for_ret(); } { RWLock::RLocker l(ictx->parent_lock); // stop early if the parent went away - it just means // another flatten finished first, so this one is useless. if (!ictx->parent) { r = 0; goto err; } } // map child object onto the parent vector > objectx; Striper::extent_to_file(cct, &ictx->layout, ono, 0, object_size, objectx); uint64_t object_overlap = ictx->prune_parent_extents(objectx, overlap); assert(object_overlap <= object_size); bufferlist bl; string oid = ictx->get_object_name(ono); Context *comp = new C_SimpleThrottle(&throttle); AioWrite *req = new AioWrite(ictx, oid, ono, 0, objectx, object_overlap, bl, snapc, CEPH_NOSNAP, comp); req->send(); prog_ctx.update_progress(ono, overlap_objects); } r = throttle.wait_for_ret(); if (r < 0) { lderr(cct) << "failed to flatten at least one object: " << cpp_strerror(r) << dendl; goto err; } // remove parent from this (base) image r = cls_client::remove_parent(&ictx->md_ctx, ictx->header_oid); if (r < 0) { lderr(cct) << "error removing parent" << dendl; return r; } // and if there are no snaps, remove from the children object as well // (if snapshots remain, they have their own parent info, and the child // will be removed when the last snap goes away) ictx->snap_lock.get_read(); if (ictx->snaps.empty()) { ldout(cct, 2) << "removing child from children list..." << dendl; int r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN, ictx->parent_md.spec, ictx->id); if (r < 0) { lderr(cct) << "error removing child from children list" << dendl; ictx->snap_lock.put_read(); return r; } } ictx->snap_lock.put_read(); notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); ldout(cct, 20) << "finished flattening" << dendl; return 0; err: throttle.wait_for_ret(); return r; } int list_lockers(ImageCtx *ictx, std::list *lockers, bool *exclusive, string *tag) { ldout(ictx->cct, 20) << "list_locks on image " << ictx << dendl; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker locker(ictx->md_lock); if (exclusive) *exclusive = ictx->exclusive_locked; if (tag) *tag = ictx->lock_tag; if (lockers) { lockers->clear(); map::const_iterator it; for (it = ictx->lockers.begin(); it != ictx->lockers.end(); ++it) { locker_t locker; locker.client = stringify(it->first.locker); locker.cookie = it->first.cookie; locker.address = stringify(it->second.addr); lockers->push_back(locker); } } return 0; } int lock(ImageCtx *ictx, bool exclusive, const string& cookie, const string& tag) { ldout(ictx->cct, 20) << "lock image " << ictx << " exclusive=" << exclusive << " cookie='" << cookie << "' tag='" << tag << "'" << dendl; int r = ictx_check(ictx); if (r < 0) return r; /** * If we wanted we could do something more intelligent, like local * checks that we think we will succeed. But for now, let's not * duplicate that code. */ RWLock::RLocker locker(ictx->md_lock); r = rados::cls::lock::lock(&ictx->md_ctx, ictx->header_oid, RBD_LOCK_NAME, exclusive ? LOCK_EXCLUSIVE : LOCK_SHARED, cookie, tag, "", utime_t(), 0); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); return 0; } int unlock(ImageCtx *ictx, const string& cookie) { ldout(ictx->cct, 20) << "unlock image " << ictx << " cookie='" << cookie << "'" << dendl; int r = ictx_check(ictx); if (r < 0) return r; RWLock::RLocker locker(ictx->md_lock); r = rados::cls::lock::unlock(&ictx->md_ctx, ictx->header_oid, RBD_LOCK_NAME, cookie); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); return 0; } int break_lock(ImageCtx *ictx, const string& client, const string& cookie) { ldout(ictx->cct, 20) << "break_lock image " << ictx << " client='" << client << "' cookie='" << cookie << "'" << dendl; int r = ictx_check(ictx); if (r < 0) return r; entity_name_t lock_client; if (!lock_client.parse(client)) { lderr(ictx->cct) << "Unable to parse client '" << client << "'" << dendl; return -EINVAL; } RWLock::RLocker locker(ictx->md_lock); r = rados::cls::lock::break_lock(&ictx->md_ctx, ictx->header_oid, RBD_LOCK_NAME, cookie, lock_client); if (r < 0) return r; notify_change(ictx->md_ctx, ictx->header_oid, NULL, ictx); return 0; } void rbd_ctx_cb(completion_t cb, void *arg) { Context *ctx = reinterpret_cast(arg); AioCompletion *comp = reinterpret_cast(cb); ctx->complete(comp->get_return_value()); comp->release(); } int64_t read_iterate(ImageCtx *ictx, uint64_t off, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg) { utime_t start_time, elapsed; ldout(ictx->cct, 20) << "read_iterate " << ictx << " off = " << off << " len = " << len << dendl; int r = ictx_check(ictx); if (r < 0) return r; uint64_t mylen = len; r = clip_io(ictx, off, &mylen); if (r < 0) return r; int64_t total_read = 0; uint64_t period = ictx->get_stripe_period(); uint64_t left = mylen; start_time = ceph_clock_now(ictx->cct); while (left > 0) { uint64_t period_off = off - (off % period); uint64_t read_len = min(period_off + period - off, left); bufferlist bl; Mutex mylock("IoCtxImpl::write::mylock"); Cond cond; bool done; int ret; Context *ctx = new C_SafeCond(&mylock, &cond, &done, &ret); AioCompletion *c = aio_create_completion_internal(ctx, rbd_ctx_cb); aio_read(ictx, off, read_len, NULL, &bl, c); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); if (ret < 0) return ret; r = cb(total_read, ret, bl.c_str(), arg); if (r < 0) return r; total_read += ret; left -= ret; off += ret; } elapsed = ceph_clock_now(ictx->cct) - start_time; ictx->perfcounter->tinc(l_librbd_rd_latency, elapsed); ictx->perfcounter->inc(l_librbd_rd); ictx->perfcounter->inc(l_librbd_rd_bytes, mylen); return total_read; } int simple_diff_cb(uint64_t off, size_t len, int exists, void *arg) { // This reads the existing extents in a parent from the beginning // of time. Since images are thin-provisioned, the extents will // always represent data, not holes. assert(exists); interval_set *diff = static_cast *>(arg); diff->insert(off, len); return 0; } int diff_iterate(ImageCtx *ictx, const char *fromsnapname, uint64_t off, uint64_t len, int (*cb)(uint64_t, size_t, int, void *), void *arg) { utime_t start_time, elapsed; ldout(ictx->cct, 20) << "diff_iterate " << ictx << " off = " << off << " len = " << len << dendl; // ensure previous writes are visible to listsnaps _flush(ictx); int r = ictx_check(ictx); if (r < 0) return r; r = clip_io(ictx, off, &len); if (r < 0) return r; librados::IoCtx head_ctx; ictx->md_lock.get_read(); ictx->snap_lock.get_read(); head_ctx.dup(ictx->data_ctx); snap_t from_snap_id = 0; uint64_t from_size = 0; if (fromsnapname) { from_snap_id = ictx->get_snap_id(fromsnapname); from_size = ictx->get_image_size(from_snap_id); } snap_t end_snap_id = ictx->snap_id; uint64_t end_size = ictx->get_image_size(end_snap_id); ictx->snap_lock.put_read(); ictx->md_lock.put_read(); if (from_snap_id == CEPH_NOSNAP) { return -ENOENT; } if (from_snap_id == end_snap_id) { // no diff. return 0; } if (from_snap_id >= end_snap_id) { return -EINVAL; } // we must list snaps via the head, not end snap head_ctx.snap_set_read(CEPH_SNAPDIR); ldout(ictx->cct, 20) << "diff_iterate from " << from_snap_id << " to " << end_snap_id << " size from " << from_size << " to " << end_size << dendl; // FIXME: if end_size > from_size, we could read_iterate for the // final part, and skip the listsnaps op. // check parent overlap only if we are comparing to the beginning of time interval_set parent_diff; if (from_snap_id == 0) { ictx->parent_lock.get_read(); uint64_t overlap = end_size; ictx->get_parent_overlap(from_snap_id, &overlap); r = 0; if (ictx->parent && overlap > 0) { ldout(ictx->cct, 10) << " first getting parent diff" << dendl; r = diff_iterate(ictx->parent, NULL, 0, overlap, simple_diff_cb, &parent_diff); } ictx->parent_lock.put_read(); if (r < 0) return r; } uint64_t period = ictx->get_stripe_period(); uint64_t left = len; while (left > 0) { uint64_t period_off = off - (off % period); uint64_t read_len = min(period_off + period - off, left); // map to extents map > object_extents; Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, read_len, 0, object_extents, 0); // get snap info for each object for (map >::iterator p = object_extents.begin(); p != object_extents.end(); ++p) { ldout(ictx->cct, 20) << "diff_iterate object " << p->first << dendl; librados::snap_set_t snap_set; int r = head_ctx.list_snaps(p->first.name, &snap_set); if (r == -ENOENT) { if (from_snap_id == 0 && !parent_diff.empty()) { // report parent diff instead for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { for (vector >::iterator r = q->buffer_extents.begin(); r != q->buffer_extents.end(); ++r) { interval_set o; o.insert(off + r->first, r->second); o.intersection_of(parent_diff); ldout(ictx->cct, 20) << " reporting parent overlap " << o << dendl; for (interval_set::iterator s = o.begin(); s != o.end(); ++s) { cb(s.get_start(), s.get_len(), true, arg); } } } } continue; } if (r < 0) return r; // calc diff from from_snap_id -> to_snap_id interval_set diff; bool end_exists; calc_snap_set_diff(ictx->cct, snap_set, from_snap_id, end_snap_id, &diff, &end_exists); ldout(ictx->cct, 20) << " diff " << diff << " end_exists=" << end_exists << dendl; if (diff.empty()) continue; for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { ldout(ictx->cct, 20) << "diff_iterate object " << p->first << " extent " << q->offset << "~" << q->length << " from " << q->buffer_extents << dendl; uint64_t opos = q->offset; for (vector >::iterator r = q->buffer_extents.begin(); r != q->buffer_extents.end(); ++r) { interval_set overlap; // object extents overlap.insert(opos, r->second); overlap.intersection_of(diff); ldout(ictx->cct, 20) << " opos " << opos << " buf " << r->first << "~" << r->second << " overlap " << overlap << dendl; for (interval_set::iterator s = overlap.begin(); s != overlap.end(); ++s) { uint64_t su_off = s.get_start() - opos; uint64_t logical_off = off + r->first + su_off; ldout(ictx->cct, 20) << " overlap extent " << s.get_start() << "~" << s.get_len() << " logical " << logical_off << "~" << s.get_len() << dendl; cb(logical_off, s.get_len(), end_exists, arg); } opos += r->second; } assert(opos == q->offset + q->length); } } left -= read_len; off += read_len; } return 0; } int simple_read_cb(uint64_t ofs, size_t len, const char *buf, void *arg) { char *dest_buf = (char *)arg; if (buf) memcpy(dest_buf + ofs, buf, len); else memset(dest_buf + ofs, 0, len); return 0; } ssize_t read(ImageCtx *ictx, uint64_t ofs, size_t len, char *buf) { vector > extents; extents.push_back(make_pair(ofs, len)); return read(ictx, extents, buf, NULL); } ssize_t read(ImageCtx *ictx, const vector >& image_extents, char *buf, bufferlist *pbl) { Mutex mylock("IoCtxImpl::write::mylock"); Cond cond; bool done; int ret; Context *ctx = new C_SafeCond(&mylock, &cond, &done, &ret); AioCompletion *c = aio_create_completion_internal(ctx, rbd_ctx_cb); aio_read(ictx, image_extents, buf, pbl, c); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return ret; } ssize_t write(ImageCtx *ictx, uint64_t off, size_t len, const char *buf) { utime_t start_time, elapsed; ldout(ictx->cct, 20) << "write " << ictx << " off = " << off << " len = " << len << dendl; start_time = ceph_clock_now(ictx->cct); Mutex mylock("librbd::write::mylock"); Cond cond; bool done; int ret; uint64_t mylen = len; int r = clip_io(ictx, off, &mylen); if (r < 0) return r; Context *ctx = new C_SafeCond(&mylock, &cond, &done, &ret); AioCompletion *c = aio_create_completion_internal(ctx, rbd_ctx_cb); aio_write(ictx, off, mylen, buf, c); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); if (ret < 0) return ret; elapsed = ceph_clock_now(ictx->cct) - start_time; ictx->perfcounter->tinc(l_librbd_wr_latency, elapsed); ictx->perfcounter->inc(l_librbd_wr); ictx->perfcounter->inc(l_librbd_wr_bytes, mylen); return mylen; } int discard(ImageCtx *ictx, uint64_t off, uint64_t len) { utime_t start_time, elapsed; ldout(ictx->cct, 20) << "discard " << ictx << " off = " << off << " len = " << len << dendl; start_time = ceph_clock_now(ictx->cct); Mutex mylock("librbd::discard::mylock"); Cond cond; bool done; int ret; Context *ctx = new C_SafeCond(&mylock, &cond, &done, &ret); AioCompletion *c = aio_create_completion_internal(ctx, rbd_ctx_cb); aio_discard(ictx, off, len, c); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); if (ret < 0) return ret; elapsed = ceph_clock_now(ictx->cct) - start_time; ictx->perfcounter->inc(l_librbd_discard_latency, elapsed); ictx->perfcounter->inc(l_librbd_discard); ictx->perfcounter->inc(l_librbd_discard_bytes, len); return len; } ssize_t handle_sparse_read(CephContext *cct, bufferlist data_bl, uint64_t block_ofs, const map &data_map, uint64_t buf_ofs, // offset into buffer size_t buf_len, // length in buffer (not size of buffer!) char *dest_buf) { uint64_t bl_ofs = 0; size_t buf_left = buf_len; for (map::const_iterator iter = data_map.begin(); iter != data_map.end(); ++iter) { uint64_t extent_ofs = iter->first; size_t extent_len = iter->second; ldout(cct, 10) << "extent_ofs=" << extent_ofs << " extent_len=" << extent_len << dendl; ldout(cct, 10) << "block_ofs=" << block_ofs << dendl; /* a hole? */ if (extent_ofs > block_ofs) { uint64_t gap = extent_ofs - block_ofs; ldout(cct, 10) << "<1>zeroing " << buf_ofs << "~" << gap << dendl; memset(dest_buf + buf_ofs, 0, gap); buf_ofs += gap; buf_left -= gap; block_ofs = extent_ofs; } else if (extent_ofs < block_ofs) { assert(0 == "osd returned data prior to what we asked for"); return -EIO; } if (bl_ofs + extent_len > (buf_ofs + buf_left)) { assert(0 == "osd returned more data than we asked for"); return -EIO; } /* data */ ldout(cct, 10) << "<2>copying " << buf_ofs << "~" << extent_len << " from ofs=" << bl_ofs << dendl; memcpy(dest_buf + buf_ofs, data_bl.c_str() + bl_ofs, extent_len); bl_ofs += extent_len; buf_ofs += extent_len; assert(buf_left >= extent_len); buf_left -= extent_len; block_ofs += extent_len; } /* last hole */ if (buf_left > 0) { ldout(cct, 10) << "<3>zeroing " << buf_ofs << "~" << buf_left << dendl; memset(dest_buf + buf_ofs, 0, buf_left); } return buf_len; } void rados_req_cb(rados_completion_t c, void *arg) { AioRequest *req = reinterpret_cast(arg); req->complete(rados_aio_get_return_value(c)); } void rados_ctx_cb(rados_completion_t c, void *arg) { Context *comp = reinterpret_cast(arg); comp->complete(rados_aio_get_return_value(c)); } // validate extent against image size; clip to image size if necessary int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len) { ictx->md_lock.get_read(); ictx->snap_lock.get_read(); uint64_t image_size = ictx->get_image_size(ictx->snap_id); bool snap_exists = ictx->snap_exists; ictx->snap_lock.put_read(); ictx->md_lock.put_read(); if (!snap_exists) return -ENOENT; // special-case "len == 0" requests: always valid if (*len == 0) return 0; // can't start past end if (off >= image_size) return -EINVAL; // clip requests that extend past end to just end if ((off + *len) > image_size) *len = (size_t)(image_size - off); return 0; } void aio_flush(ImageCtx *ictx, AioCompletion *c) { CephContext *cct = ictx->cct; ldout(cct, 20) << "aio_flush " << ictx << " completion " << c << dendl; c->get(); int r = ictx_check(ictx); if (r < 0) { c->fail(cct, r); return; } ictx->user_flushed(); c->add_request(); c->init_time(ictx, AIO_TYPE_FLUSH); C_AioWrite *req_comp = new C_AioWrite(cct, c); if (ictx->object_cacher) { ictx->flush_cache_aio(req_comp); } else { librados::AioCompletion *rados_completion = librados::Rados::aio_create_completion(req_comp, NULL, rados_ctx_cb); ictx->data_ctx.aio_flush_async(rados_completion); rados_completion->release(); } c->finish_adding_requests(cct); c->put(); ictx->perfcounter->inc(l_librbd_aio_flush); } int flush(ImageCtx *ictx) { CephContext *cct = ictx->cct; ldout(cct, 20) << "flush " << ictx << dendl; int r = ictx_check(ictx); if (r < 0) return r; ictx->user_flushed(); r = _flush(ictx); ictx->perfcounter->inc(l_librbd_flush); return r; } int _flush(ImageCtx *ictx) { CephContext *cct = ictx->cct; int r; // flush any outstanding writes if (ictx->object_cacher) { r = ictx->flush_cache(); } else { r = ictx->data_ctx.aio_flush(); } if (r) lderr(cct) << "_flush " << ictx << " r = " << r << dendl; return r; } int invalidate_cache(ImageCtx *ictx) { CephContext *cct = ictx->cct; ldout(cct, 20) << "invalidate_cache " << ictx << dendl; int r = ictx_check(ictx); if (r < 0) return r; RWLock::WLocker l(ictx->md_lock); return ictx->invalidate_cache(); } void aio_write(ImageCtx *ictx, uint64_t off, size_t len, const char *buf, AioCompletion *c) { CephContext *cct = ictx->cct; ldout(cct, 20) << "aio_write " << ictx << " off = " << off << " len = " << len << " buf = " << (void*)buf << dendl; c->get(); int r = ictx_check(ictx); if (r < 0) { c->fail(cct, r); return; } uint64_t mylen = len; r = clip_io(ictx, off, &mylen); if (r < 0) { c->fail(cct, r); return; } ictx->snap_lock.get_read(); snapid_t snap_id = ictx->snap_id; ::SnapContext snapc = ictx->snapc; ictx->parent_lock.get_read(); uint64_t overlap = 0; ictx->get_parent_overlap(ictx->snap_id, &overlap); ictx->parent_lock.put_read(); ictx->snap_lock.put_read(); if (snap_id != CEPH_NOSNAP || ictx->read_only) { c->fail(cct, -EROFS); return; } ldout(cct, 20) << " parent overlap " << overlap << dendl; // map vector extents; if (len > 0) { Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, mylen, 0, extents); } c->init_time(ictx, AIO_TYPE_WRITE); for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { ldout(cct, 20) << " oid " << p->oid << " " << p->offset << "~" << p->length << " from " << p->buffer_extents << dendl; // assemble extent bufferlist bl; for (vector >::iterator q = p->buffer_extents.begin(); q != p->buffer_extents.end(); ++q) { bl.append(buf + q->first, q->second); } C_AioWrite *req_comp = new C_AioWrite(cct, c); if (ictx->object_cacher) { c->add_request(); ictx->write_to_cache(p->oid, bl, p->length, p->offset, req_comp); } else { // reverse map this object extent onto the parent vector > objectx; Striper::extent_to_file(ictx->cct, &ictx->layout, p->objectno, 0, ictx->layout.fl_object_size, objectx); uint64_t object_overlap = ictx->prune_parent_extents(objectx, overlap); AioWrite *req = new AioWrite(ictx, p->oid.name, p->objectno, p->offset, objectx, object_overlap, bl, snapc, snap_id, req_comp); c->add_request(); req->send(); } } c->finish_adding_requests(ictx->cct); c->put(); ictx->perfcounter->inc(l_librbd_aio_wr); ictx->perfcounter->inc(l_librbd_aio_wr_bytes, mylen); } void aio_discard(ImageCtx *ictx, uint64_t off, uint64_t len, AioCompletion *c) { CephContext *cct = ictx->cct; ldout(cct, 20) << "aio_discard " << ictx << " off = " << off << " len = " << len << dendl; c->get(); int r = ictx_check(ictx); if (r < 0) { c->fail(cct, r); return; } r = clip_io(ictx, off, &len); if (r < 0) { c->fail(cct, r); return; } // TODO: check for snap ictx->snap_lock.get_read(); snapid_t snap_id = ictx->snap_id; ::SnapContext snapc = ictx->snapc; ictx->parent_lock.get_read(); uint64_t overlap = 0; ictx->get_parent_overlap(ictx->snap_id, &overlap); ictx->parent_lock.put_read(); ictx->snap_lock.put_read(); if (snap_id != CEPH_NOSNAP || ictx->read_only) { c->fail(cct, -EROFS); return; } // map vector extents; if (len > 0) { Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, len, 0, extents); } c->init_time(ictx, AIO_TYPE_DISCARD); for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { ldout(cct, 20) << " oid " << p->oid << " " << p->offset << "~" << p->length << " from " << p->buffer_extents << dendl; C_AioWrite *req_comp = new C_AioWrite(cct, c); AbstractWrite *req; c->add_request(); // reverse map this object extent onto the parent vector > objectx; uint64_t object_overlap = 0; if (off < overlap) { // we might overlap... Striper::extent_to_file(ictx->cct, &ictx->layout, p->objectno, 0, ictx->layout.fl_object_size, objectx); object_overlap = ictx->prune_parent_extents(objectx, overlap); } if (p->offset == 0 && p->length == ictx->layout.fl_object_size) { req = new AioRemove(ictx, p->oid.name, p->objectno, objectx, object_overlap, snapc, snap_id, req_comp); } else if (p->offset + p->length == ictx->layout.fl_object_size) { req = new AioTruncate(ictx, p->oid.name, p->objectno, p->offset, objectx, object_overlap, snapc, snap_id, req_comp); } else { req = new AioZero(ictx, p->oid.name, p->objectno, p->offset, p->length, objectx, object_overlap, snapc, snap_id, req_comp); } req->send(); } r = 0; if (ictx->object_cacher) { Mutex::Locker l(ictx->cache_lock); ictx->object_cacher->discard_set(ictx->object_set, extents); } c->finish_adding_requests(ictx->cct); c->put(); ictx->perfcounter->inc(l_librbd_aio_discard); ictx->perfcounter->inc(l_librbd_aio_discard_bytes, len); } void rbd_req_cb(completion_t cb, void *arg) { AioRequest *req = reinterpret_cast(arg); AioCompletion *comp = reinterpret_cast(cb); req->complete(comp->get_return_value()); } void aio_read(ImageCtx *ictx, uint64_t off, size_t len, char *buf, bufferlist *bl, AioCompletion *c) { vector > image_extents(1); image_extents[0] = make_pair(off, len); aio_read(ictx, image_extents, buf, bl, c); } void aio_read(ImageCtx *ictx, const vector >& image_extents, char *buf, bufferlist *pbl, AioCompletion *c) { CephContext *cct = ictx->cct; ldout(cct, 20) << "aio_read " << ictx << " completion " << c << " " << image_extents << dendl; c->get(); int r = ictx_check(ictx); if (r < 0) { c->fail(cct, r); return; } ictx->snap_lock.get_read(); snap_t snap_id = ictx->snap_id; ictx->snap_lock.put_read(); // map map > object_extents; uint64_t buffer_ofs = 0; for (vector >::const_iterator p = image_extents.begin(); p != image_extents.end(); ++p) { uint64_t len = p->second; r = clip_io(ictx, p->first, &len); if (r < 0) { c->fail(cct, r); return; } if (len == 0) continue; Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, p->first, len, 0, object_extents, buffer_ofs); buffer_ofs += len; } c->read_buf = buf; c->read_buf_len = buffer_ofs; c->read_bl = pbl; c->init_time(ictx, AIO_TYPE_READ); for (map >::iterator p = object_extents.begin(); p != object_extents.end(); ++p) { for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { ldout(ictx->cct, 20) << " oid " << q->oid << " " << q->offset << "~" << q->length << " from " << q->buffer_extents << dendl; C_AioRead *req_comp = new C_AioRead(ictx->cct, c); AioRead *req = new AioRead(ictx, q->oid.name, q->objectno, q->offset, q->length, q->buffer_extents, snap_id, true, req_comp); req_comp->set_req(req); c->add_request(); if (ictx->object_cacher) { C_CacheRead *cache_comp = new C_CacheRead(req); ictx->aio_read_from_cache(q->oid, &req->data(), q->length, q->offset, cache_comp); } else { req->send(); } } } c->finish_adding_requests(ictx->cct); c->put(); ictx->perfcounter->inc(l_librbd_aio_rd); ictx->perfcounter->inc(l_librbd_aio_rd_bytes, buffer_ofs); } AioCompletion *aio_create_completion() { AioCompletion *c = new AioCompletion(); return c; } AioCompletion *aio_create_completion(void *cb_arg, callback_t cb_complete) { AioCompletion *c = new AioCompletion(); c->set_complete_cb(cb_arg, cb_complete); return c; } AioCompletion *aio_create_completion_internal(void *cb_arg, callback_t cb_complete) { AioCompletion *c = aio_create_completion(cb_arg, cb_complete); c->rbd_comp = c; return c; } } ceph-0.80.11/src/librbd/AioRequest.h0000664000175100017510000001512212623076744021155 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_AIOREQUEST_H #define CEPH_LIBRBD_AIOREQUEST_H #include "include/int_types.h" #include #include "common/snap_types.h" #include "include/buffer.h" #include "include/Context.h" #include "include/rados/librados.hpp" namespace librbd { struct AioCompletion; struct ImageCtx; /** * This class represents an I/O operation to a single RBD data object. * Its subclasses encapsulate logic for dealing with special cases * for I/O due to layering. */ class AioRequest { public: AioRequest(); AioRequest(ImageCtx *ictx, const std::string &oid, uint64_t objectno, uint64_t off, uint64_t len, librados::snap_t snap_id, Context *completion, bool hide_enoent); virtual ~AioRequest(); void complete(int r) { if (should_complete(r)) { if (m_hide_enoent && r == -ENOENT) r = 0; m_completion->complete(r); delete this; } } virtual bool should_complete(int r) = 0; virtual void send() = 0; protected: void read_from_parent(vector >& image_extents); ImageCtx *m_ictx; librados::IoCtx *m_ioctx; std::string m_oid; uint64_t m_object_no, m_object_off, m_object_len; librados::snap_t m_snap_id; Context *m_completion; AioCompletion *m_parent_completion; ceph::bufferlist m_read_data; bool m_hide_enoent; }; class AioRead : public AioRequest { public: AioRead(ImageCtx *ictx, const std::string &oid, uint64_t objectno, uint64_t offset, uint64_t len, vector >& be, librados::snap_t snap_id, bool sparse, Context *completion) : AioRequest(ictx, oid, objectno, offset, len, snap_id, completion, false), m_buffer_extents(be), m_tried_parent(false), m_sparse(sparse) { } virtual ~AioRead() {} virtual bool should_complete(int r); virtual void send(); ceph::bufferlist &data() { return m_read_data; } std::map m_ext_map; friend class C_AioRead; private: vector > m_buffer_extents; bool m_tried_parent; bool m_sparse; }; class AbstractWrite : public AioRequest { public: AbstractWrite(); AbstractWrite(ImageCtx *ictx, const std::string &oid, uint64_t object_no, uint64_t object_off, uint64_t len, vector >& objectx, uint64_t object_overlap, const ::SnapContext &snapc, librados::snap_t snap_id, Context *completion, bool hide_enoent); virtual ~AbstractWrite() {} virtual bool should_complete(int r); virtual void send(); void guard_write(); bool has_parent() const { return !m_object_image_extents.empty(); } private: /** * Writes go through the following state machine to deal with * layering: * * need copyup * LIBRBD_AIO_WRITE_GUARD ---------------> LIBRBD_AIO_WRITE_COPYUP * | ^ | * v \------------------------------/ * done * ^ * | * LIBRBD_AIO_WRITE_FLAT * * Writes start in LIBRBD_AIO_WRITE_GUARD or _FLAT, depending on whether * there is a parent or not. */ enum write_state_d { LIBRBD_AIO_WRITE_GUARD, LIBRBD_AIO_WRITE_COPYUP, LIBRBD_AIO_WRITE_FLAT }; protected: virtual void add_copyup_ops() = 0; write_state_d m_state; vector > m_object_image_extents; uint64_t m_parent_overlap; librados::ObjectWriteOperation m_write; librados::ObjectWriteOperation m_copyup; uint64_t m_snap_seq; std::vector m_snaps; private: void send_copyup(); }; class AioWrite : public AbstractWrite { public: AioWrite(ImageCtx *ictx, const std::string &oid, uint64_t object_no, uint64_t object_off, vector >& objectx, uint64_t object_overlap, const ceph::bufferlist &data, const ::SnapContext &snapc, librados::snap_t snap_id, Context *completion) : AbstractWrite(ictx, oid, object_no, object_off, data.length(), objectx, object_overlap, snapc, snap_id, completion, false), m_write_data(data) { guard_write(); add_write_ops(m_write); } virtual ~AioWrite() {} protected: virtual void add_copyup_ops() { add_write_ops(m_copyup); } private: void add_write_ops(librados::ObjectWriteOperation &wr); ceph::bufferlist m_write_data; }; class AioRemove : public AbstractWrite { public: AioRemove(ImageCtx *ictx, const std::string &oid, uint64_t object_no, vector >& objectx, uint64_t object_overlap, const ::SnapContext &snapc, librados::snap_t snap_id, Context *completion) : AbstractWrite(ictx, oid, object_no, 0, 0, objectx, object_overlap, snapc, snap_id, completion, true) { if (has_parent()) m_write.truncate(0); else m_write.remove(); } virtual ~AioRemove() {} protected: virtual void add_copyup_ops() { // removing an object never needs to copyup assert(0); } }; class AioTruncate : public AbstractWrite { public: AioTruncate(ImageCtx *ictx, const std::string &oid, uint64_t object_no, uint64_t object_off, vector >& objectx, uint64_t object_overlap, const ::SnapContext &snapc, librados::snap_t snap_id, Context *completion) : AbstractWrite(ictx, oid, object_no, object_off, 0, objectx, object_overlap, snapc, snap_id, completion, true) { guard_write(); m_write.truncate(object_off); } virtual ~AioTruncate() {} protected: virtual void add_copyup_ops() { m_copyup.truncate(m_object_off); } }; class AioZero : public AbstractWrite { public: AioZero(ImageCtx *ictx, const std::string &oid, uint64_t object_no, uint64_t object_off, uint64_t object_len, vector >& objectx, uint64_t object_overlap, const ::SnapContext &snapc, librados::snap_t snap_id, Context *completion) : AbstractWrite(ictx, oid, object_no, object_off, object_len, objectx, object_overlap, snapc, snap_id, completion, true) { guard_write(); m_write.zero(object_off, object_len); } virtual ~AioZero() {} protected: virtual void add_copyup_ops() { m_copyup.zero(m_object_off, m_object_len); } }; } #endif ceph-0.80.11/src/librbd/AioCompletion.h0000664000175100017510000001051212623076744021634 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_AIOCOMPLETION_H #define CEPH_LIBRBD_AIOCOMPLETION_H #include "common/Cond.h" #include "common/Mutex.h" #include "common/ceph_context.h" #include "common/perf_counters.h" #include "include/Context.h" #include "include/utime.h" #include "include/rbd/librbd.hpp" #include "librbd/ImageCtx.h" #include "librbd/internal.h" #include "osdc/Striper.h" namespace librbd { class AioRead; typedef enum { AIO_TYPE_READ = 0, AIO_TYPE_WRITE, AIO_TYPE_DISCARD, AIO_TYPE_FLUSH, AIO_TYPE_NONE, } aio_type_t; /** * AioCompletion is the overall completion for a single * rbd I/O request. It may be composed of many AioRequests, * which each go to a single object. * * The retrying of individual requests is handled at a lower level, * so all AioCompletion cares about is the count of outstanding * requests. Note that this starts at 1 to prevent the reference * count from reaching 0 while more requests are being added. When * all requests have been added, finish_adding_requests() releases * this initial reference. */ struct AioCompletion { Mutex lock; Cond cond; bool done; ssize_t rval; callback_t complete_cb; void *complete_arg; rbd_completion_t rbd_comp; int pending_count; ///< number of requests bool building; ///< true if we are still building this completion int ref; bool released; ImageCtx *ictx; utime_t start_time; aio_type_t aio_type; Striper::StripedReadResult destriper; bufferlist *read_bl; char *read_buf; size_t read_buf_len; AioCompletion() : lock("AioCompletion::lock", true), done(false), rval(0), complete_cb(NULL), complete_arg(NULL), rbd_comp(NULL), pending_count(0), building(true), ref(1), released(false), ictx(NULL), aio_type(AIO_TYPE_NONE), read_bl(NULL), read_buf(NULL), read_buf_len(0) { } ~AioCompletion() { } int wait_for_complete() { lock.Lock(); while (!done) cond.Wait(lock); lock.Unlock(); return 0; } void add_request() { lock.Lock(); pending_count++; lock.Unlock(); get(); } void finalize(CephContext *cct, ssize_t rval); void finish_adding_requests(CephContext *cct); void init_time(ImageCtx *i, aio_type_t t) { ictx = i; { Mutex::Locker l(ictx->aio_lock); ++ictx->pending_aio; } aio_type = t; start_time = ceph_clock_now(ictx->cct); } void complete(CephContext *cct); void fail(CephContext *cct, int r); void set_complete_cb(void *cb_arg, callback_t cb) { complete_cb = cb; complete_arg = cb_arg; } void complete_request(CephContext *cct, ssize_t r); bool is_complete() { Mutex::Locker l(lock); return done; } ssize_t get_return_value() { lock.Lock(); ssize_t r = rval; lock.Unlock(); return r; } void get() { lock.Lock(); assert(ref > 0); ref++; lock.Unlock(); } void release() { lock.Lock(); assert(!released); released = true; put_unlock(); } void put() { lock.Lock(); put_unlock(); } void put_unlock() { assert(ref > 0); int n = --ref; lock.Unlock(); if (!n) delete this; } }; class C_AioRead : public Context { public: C_AioRead(CephContext *cct, AioCompletion *completion) : m_cct(cct), m_completion(completion), m_req(NULL) { } virtual ~C_AioRead() {} virtual void finish(int r); void set_req(AioRead *req) { m_req = req; } private: CephContext *m_cct; AioCompletion *m_completion; AioRead *m_req; }; class C_AioWrite : public Context { public: C_AioWrite(CephContext *cct, AioCompletion *completion) : m_cct(cct), m_completion(completion) {} virtual ~C_AioWrite() {} virtual void finish(int r) { m_completion->complete_request(m_cct, r); } private: CephContext *m_cct; AioCompletion *m_completion; }; class C_CacheRead : public Context { public: explicit C_CacheRead(AioRead *req) : m_req(req) {} virtual ~C_CacheRead() {} virtual void finish(int r); private: AioRead *m_req; }; } #endif ceph-0.80.11/src/ceph-crush-location0000555000175100017510000000345412623077033021253 0ustar jenkins-buildjenkins-build#!/bin/sh # # Generate a CRUSH location for the given entity # # The CRUSH location consists of a list of key=value pairs, separated # by spaces, all on a single line. This describes where in CRUSH # hierarhcy this entity should be placed. # # Arguments: # --cluster name of the cluster (see /etc/ceph/$cluster.conf) # --type daemon/entity type # --id id (osd number, mds name, client name) # # if we start up as ./ceph-crush-location, assume everything else is # in the current directory too. if [ `dirname $0` = "." ] && [ $PWD != "/usr/bin" ]; then BINDIR=. SBINDIR=. LIBDIR=. ETCDIR=. else BINDIR=/usr/bin SBINDIR=/usr/sbin LIBDIR=/usr/lib/ceph ETCDIR=/etc/ceph fi usage_exit() { echo "usage: $0 [--cluster ] --id --type " exit } cluster="ceph" type="" id="" while [ $# -ge 1 ]; do case $1 in --cluster | -C) shift cluster="$1" shift ;; --id | -i) shift id="$1" shift ;; --type | -t) shift type="$1" shift ;; *) echo "unrecognized option '$1'" usage_exit ;; esac done if [ -z "$type" ]; then echo "must specify entity type" usage_exit fi if [ -z "$id" ]; then echo "must specify id" usage_exit fi # try a type-specific config, e.g. 'osd crush location' location="$($BINDIR/ceph-conf --cluster=${cluster:-ceph} --name=$type.$id --lookup ${type}_crush_location || :)" if [ -n "$location" ]; then echo $location exit 0 fi # try a generic location location="$($BINDIR/ceph-conf --cluster=${cluster:-ceph} --name=$type.$id --lookup crush_location || :)" if [ -n "$location" ]; then echo $location exit 0 fi # spit out something generic echo "host=$(hostname -s) root=default" ceph-0.80.11/src/include/0000775000175100017510000000000012623077034017100 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/include/hash_namespace.h0000664000175100017510000000066112623076744022222 0ustar jenkins-buildjenkins-build#ifndef CEPH_HASH_NAMESPACE_H #define CEPH_HASH_NAMESPACE_H #include #ifdef _LIBCPP_VERSION #include #define CEPH_HASH_NAMESPACE_START namespace std { #define CEPH_HASH_NAMESPACE_END } #define CEPH_HASH_NAMESPACE std #else #include #define CEPH_HASH_NAMESPACE_START namespace std { namespace tr1 { #define CEPH_HASH_NAMESPACE_END }} #define CEPH_HASH_NAMESPACE std::tr1 #endif #endif ceph-0.80.11/src/include/assert.h0000664000175100017510000000721612623076744020567 0ustar jenkins-buildjenkins-build#ifndef CEPH_ASSERT_H #define CEPH_ASSERT_H #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #define __GNUC_PREREQ(minor, major) __GNUC_PREREQ__(minor, major) #endif #ifdef __CEPH__ # include "acconfig.h" #endif class CephContext; #ifdef __cplusplus namespace ceph { struct BackTrace; struct FailedAssertion { BackTrace *backtrace; FailedAssertion(BackTrace *bt) : backtrace(bt) {} }; #endif #ifdef HAVE_STATIC_CAST # define __CEPH_ASSERT_VOID_CAST static_cast #else # define __CEPH_ASSERT_VOID_CAST (void) #endif /* * For GNU, test specific version features. Otherwise (e.g. LLVM) we'll use * the defaults selected below. */ #ifdef __GNUC_PREREQ /* * Version 2.4 and later of GCC define a magical variable * `__PRETTY_FUNCTION__' which contains the name of the function currently * being defined. This is broken in G++ before version 2.6. C9x has a * similar variable called __func__, but prefer the GCC one since it demangles * C++ function names. We define __CEPH_NO_PRETTY_FUNC if we want to avoid * broken versions of G++. */ # if defined __cplusplus ? !__GNUC_PREREQ (2, 6) : !__GNUC_PREREQ (2, 4) # define __CEPH_NO_PRETTY_FUNC # endif #endif /* * Select a function-name variable based on compiler tests, and any compiler * specific overrides. */ #if defined(HAVE_PRETTY_FUNC) && !defined(__CEPH_NO_PRETTY_FUNC) # define __CEPH_ASSERT_FUNCTION __PRETTY_FUNCTION__ #elif defined(HAVE_FUNC) # define __CEPH_ASSERT_FUNCTION __func__ #else # define __CEPH_ASSERT_FUNCTION ((__const char *) 0) #endif extern void register_assert_context(CephContext *cct); extern void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *function) __attribute__ ((__noreturn__)); extern void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *function); #define ceph_assert(expr) \ ((expr) \ ? __CEPH_ASSERT_VOID_CAST (0) \ : __ceph_assert_fail (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION)) #define assert_warn(expr) \ ((expr) \ ? __CEPH_ASSERT_VOID_CAST (0) \ : __ceph_assert_warn (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION)) /* #define assert(expr) \ do { \ static int __assert_flag = 0; \ struct TlsData *tls = tls_get_val(); \ if (!__assert_flag && tls && tls->disable_assert) { \ __assert_flag = 1; \ __ceph_assert_warn(__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION); \ } \ ((expr) \ ? __CEPH_ASSERT_VOID_CAST (0) \ : __ceph_assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION)); \ } while (0) #endif */ /* #define assert_protocol(expr) assert(expr) #define assert_disk(expr) assert(expr) */ #ifdef __cplusplus } using namespace ceph; #endif /* * ceph_abort aborts the program with a nice backtrace. * * Currently, it's the same as assert(0), but we may one day make assert a * debug-only thing, like it is in many projects. */ #define ceph_abort() assert(0) #endif // wipe any prior assert definition #ifdef assert # undef assert #endif // make _ASSERT_H something that *must* have a value other than what // /usr/include/assert.h gives it (nothing!), so that we detect when // our assert is clobbered. #undef _ASSERT_H #define _ASSERT_H _dout_cct // make __ASSERT_FUNCTION empty (/usr/include/assert.h makes it a function) // and make our encoding macros break if it non-empty. #undef __ASSERT_FUNCTION #define __ASSERT_FUNCTION #define assert(expr) \ ((expr) \ ? __CEPH_ASSERT_VOID_CAST (0) \ : __ceph_assert_fail (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION)) ceph-0.80.11/src/include/on_exit.h0000664000175100017510000000200112623076744020716 0ustar jenkins-buildjenkins-build#ifndef CEPH_ON_EXIT_H #define CEPH_ON_EXIT_H #include #include #include /* * Create a static instance at the file level to get callbacks called when the * process exits via main() or exit(). */ class OnExitManager { public: typedef void (*callback_t)(void *arg); OnExitManager() { int ret = pthread_mutex_init(&lock_, NULL); assert(ret == 0); } ~OnExitManager() { pthread_mutex_lock(&lock_); std::vector::iterator it; for (it = funcs_.begin(); it != funcs_.end(); it++) { it->func(it->arg); } funcs_.clear(); pthread_mutex_unlock(&lock_); } void add_callback(callback_t func, void *arg) { pthread_mutex_lock(&lock_); struct cb callback = { func, arg }; funcs_.push_back(callback); pthread_mutex_unlock(&lock_); } private: struct cb { callback_t func; void *arg; }; std::vector funcs_; pthread_mutex_t lock_; }; #endif ceph-0.80.11/src/include/err.h0000664000175100017510000000077312623076744020057 0ustar jenkins-buildjenkins-build#ifndef CEPH_ERR_H #define CEPH_ERR_H /* * adapted from linux 2.6.24 include/linux/err.h */ #define MAX_ERRNO 4095 #define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) #include /* this generates a warning in c++; caller can do the cast manually static inline void *ERR_PTR(long error) { return (void *) error; } */ static inline long PTR_ERR(const void *ptr) { return (long) ptr; } static inline long IS_ERR(const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); } #endif ceph-0.80.11/src/include/object.h0000664000175100017510000001116112623076744020526 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OBJECT_H #define CEPH_OBJECT_H #include #include #include #include using namespace std; #include "include/unordered_map.h" #include "include/hash_namespace.h" #include "hash.h" #include "encoding.h" #include "ceph_hash.h" #include "cmp.h" /// Maximum supported object name length for Ceph, in bytes. #define MAX_CEPH_OBJECT_NAME_LEN 4096 struct object_t { string name; object_t() {} object_t(const char *s) : name(s) {} object_t(const string& s) : name(s) {} void swap(object_t& o) { name.swap(o.name); } void clear() { name.clear(); } void encode(bufferlist &bl) const { ::encode(name, bl); } void decode(bufferlist::iterator &bl) { ::decode(name, bl); } }; WRITE_CLASS_ENCODER(object_t) inline bool operator==(const object_t& l, const object_t& r) { return l.name == r.name; } inline bool operator!=(const object_t& l, const object_t& r) { return l.name != r.name; } inline bool operator>(const object_t& l, const object_t& r) { return l.name > r.name; } inline bool operator<(const object_t& l, const object_t& r) { return l.name < r.name; } inline bool operator>=(const object_t& l, const object_t& r) { return l.name >= r.name; } inline bool operator<=(const object_t& l, const object_t& r) { return l.name <= r.name; } inline ostream& operator<<(ostream& out, const object_t& o) { return out << o.name; } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const object_t& r) const { //static hash H; //return H(r.name); return ceph_str_hash_linux(r.name.c_str(), r.name.length()); } }; CEPH_HASH_NAMESPACE_END struct file_object_t { uint64_t ino, bno; mutable char buf[33]; file_object_t(uint64_t i=0, uint64_t b=0) : ino(i), bno(b) { buf[0] = 0; } const char *c_str() const { if (!buf[0]) sprintf(buf, "%llx.%08llx", (long long unsigned)ino, (long long unsigned)bno); return buf; } operator object_t() { return object_t(c_str()); } }; // --------------------------- // snaps struct snapid_t { uint64_t val; snapid_t(uint64_t v=0) : val(v) {} snapid_t operator+=(snapid_t o) { val += o.val; return *this; } snapid_t operator++() { ++val; return *this; } operator uint64_t() const { return val; } }; inline void encode(snapid_t i, bufferlist &bl) { encode(i.val, bl); } inline void decode(snapid_t &i, bufferlist::iterator &p) { decode(i.val, p); } inline ostream& operator<<(ostream& out, snapid_t s) { if (s == CEPH_NOSNAP) return out << "head"; else if (s == CEPH_SNAPDIR) return out << "snapdir"; else return out << hex << s.val << dec; } struct sobject_t { object_t oid; snapid_t snap; sobject_t() : snap(0) {} sobject_t(object_t o, snapid_t s) : oid(o), snap(s) {} void swap(sobject_t& o) { oid.swap(o.oid); snapid_t t = snap; snap = o.snap; o.snap = t; } void encode(bufferlist& bl) const { ::encode(oid, bl); ::encode(snap, bl); } void decode(bufferlist::iterator& bl) { ::decode(oid, bl); ::decode(snap, bl); } }; WRITE_CLASS_ENCODER(sobject_t) inline bool operator==(const sobject_t &l, const sobject_t &r) { return l.oid == r.oid && l.snap == r.snap; } inline bool operator!=(const sobject_t &l, const sobject_t &r) { return l.oid != r.oid || l.snap != r.snap; } inline bool operator>(const sobject_t &l, const sobject_t &r) { return l.oid > r.oid || (l.oid == r.oid && l.snap > r.snap); } inline bool operator<(const sobject_t &l, const sobject_t &r) { return l.oid < r.oid || (l.oid == r.oid && l.snap < r.snap); } inline bool operator>=(const sobject_t &l, const sobject_t &r) { return l.oid > r.oid || (l.oid == r.oid && l.snap >= r.snap); } inline bool operator<=(const sobject_t &l, const sobject_t &r) { return l.oid < r.oid || (l.oid == r.oid && l.snap <= r.snap); } inline ostream& operator<<(ostream& out, const sobject_t &o) { return out << o.oid << "/" << o.snap; } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const sobject_t &r) const { static hash H; static rjhash I; return H(r.oid) ^ I(r.snap); } }; CEPH_HASH_NAMESPACE_END #endif ceph-0.80.11/src/include/stringify.h0000664000175100017510000000033512623076744021277 0ustar jenkins-buildjenkins-build#ifndef __CEPH_STRINGIFY_H #define __CEPH_STRINGIFY_H #include #include template inline std::string stringify(const T& a) { std::stringstream ss; ss << a; return ss.str(); } #endif ceph-0.80.11/src/include/str_list.h0000664000175100017510000000207212623076744021124 0ustar jenkins-buildjenkins-build#ifndef CEPH_STRLIST_H #define CEPH_STRLIST_H #include #include #include #include #include extern void get_str_list(const std::string& str, std::list& str_list); extern void get_str_list(const std::string& str, const char *delims, std::list& str_list); extern void get_str_vec(const std::string& str, std::vector& str_vec); extern void get_str_vec(const std::string& str, const char *delims, std::vector& str_vec); extern void get_str_set(const std::string& str, std::set& str_list); extern void get_str_set(const std::string& str, const char *delims, std::set& str_list); inline std::string str_join(const std::vector& v, std::string sep) { if (v.empty()) return std::string(); std::vector::const_iterator i = v.begin(); std::string r = *i; for (++i; i != v.end(); ++i) { r += sep; r += *i; } return r; } #endif ceph-0.80.11/src/include/color.h0000664000175100017510000000046512623076744020403 0ustar jenkins-buildjenkins-build#ifndef CEPH_COLOR_H #define CEPH_COLOR_H #define TEXT_NORMAL "\033[0m" /*#define TEXT_HAZARD "\033[5;31m"*/ #define TEXT_RED "\033[0;31m" #define TEXT_GREEN "\033[0;32m" #define TEXT_YELLOW "\033[0;33m" #define TEXT_BLUE "\033[0;34m" #define TEXT_MAGENTA "\033[0;35m" #define TEXT_CYAN "\033[0;36m" #endif ceph-0.80.11/src/include/CompatSet.h0000664000175100017510000001611012623076744021156 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMPATSET_H #define CEPH_COMPATSET_H #include "include/buffer.h" #include #include "common/Formatter.h" struct CompatSet { struct Feature { uint64_t id; string name; Feature(uint64_t _id, const char *_name) : id(_id), name(_name) {} Feature(uint64_t _id, string& _name) : id(_id), name(_name) {} }; struct FeatureSet { uint64_t mask; map names; FeatureSet() : mask(1), names() {} void insert(Feature f) { assert(f.id > 0); assert(f.id < 64); mask |= ((uint64_t)1< temp_names; temp_names.swap(names); for (map::iterator i = temp_names.begin(); i != temp_names.end(); ++i) { insert(Feature(i->first, i->second)); } } else { mask |= 1; } } void dump(Formatter *f) const { for (map::const_iterator p = names.begin(); p != names.end(); ++p) { char s[10]; snprintf(s, sizeof(s), "feature_%lld", (unsigned long long)p->first); f->dump_string(s, p->second); } } }; FeatureSet compat, ro_compat, incompat; CompatSet(FeatureSet& _compat, FeatureSet& _ro_compat, FeatureSet& _incompat) : compat(_compat), ro_compat(_ro_compat), incompat(_incompat) {} CompatSet() : compat(), ro_compat(), incompat() { } /* does this filesystem implementation have the features required to read the other? */ bool readable(CompatSet& other) { return !((other.incompat.mask ^ incompat.mask) & other.incompat.mask); } /* does this filesystem implementation have the features required to write the other? */ bool writeable(CompatSet& other) { return readable(other) && !((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask); } /* Compare this CompatSet to another. * CAREFULLY NOTE: This operation is NOT commutative. * a > b DOES NOT imply that b < a. * If returns: * 0: The CompatSets have the same feature set. * 1: This CompatSet's features are a strict superset of the other's. * -1: This CompatSet is missing at least one feature * described in the other. It may still have more features, though. */ int compare(CompatSet& other) { if ((other.compat.mask == compat.mask) && (other.ro_compat.mask == ro_compat.mask) && (other.incompat.mask == incompat.mask)) return 0; //okay, they're not the same //if we're writeable we have a superset of theirs on incompat and ro_compat if (writeable(other) && !((other.compat.mask ^ compat.mask) & other.compat.mask)) return 1; //if we make it here, we weren't writeable or had a difference compat set return -1; } /* Get the features supported by other CompatSet but not this one, * as a CompatSet. */ CompatSet unsupported(CompatSet& other) { CompatSet diff; uint64_t other_compat = ((other.compat.mask ^ compat.mask) & other.compat.mask); uint64_t other_ro_compat = ((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask); uint64_t other_incompat = ((other.incompat.mask ^ incompat.mask) & other.incompat.mask); for (int id = 1; id < 64; ++id) { uint64_t mask = (uint64_t)1 << id; if (mask & other_compat) { diff.compat.insert( Feature(id, other.compat.names[id])); } if (mask & other_ro_compat) { diff.ro_compat.insert(Feature(id, other.ro_compat.names[id])); } if (mask & other_incompat) { diff.incompat.insert( Feature(id, other.incompat.names[id])); } } return diff; } /* Merge features supported by other CompatSet into this one. * Return: true if some features were merged */ bool merge(CompatSet& other) { uint64_t other_compat = ((other.compat.mask ^ compat.mask) & other.compat.mask); uint64_t other_ro_compat = ((other.ro_compat.mask ^ ro_compat.mask) & other.ro_compat.mask); uint64_t other_incompat = ((other.incompat.mask ^ incompat.mask) & other.incompat.mask); if (!other_compat && !other_ro_compat && !other_incompat) return false; for (int id = 1; id < 64; ++id) { uint64_t mask = (uint64_t)1 << id; if (mask & other_compat) { compat.insert( Feature(id, other.compat.names[id])); } if (mask & other_ro_compat) { ro_compat.insert(Feature(id, other.ro_compat.names[id])); } if (mask & other_incompat) { incompat.insert( Feature(id, other.incompat.names[id])); } } return true; } void encode(bufferlist& bl) const { compat.encode(bl); ro_compat.encode(bl); incompat.encode(bl); } void decode(bufferlist::iterator& bl) { compat.decode(bl); ro_compat.decode(bl); incompat.decode(bl); } void dump(Formatter *f) const { f->open_object_section("compat"); compat.dump(f); f->close_section(); f->open_object_section("ro_compat"); ro_compat.dump(f); f->close_section(); f->open_object_section("incompat"); incompat.dump(f); f->close_section(); } static void generate_test_instances(list& o) { o.push_back(new CompatSet); o.push_back(new CompatSet); o.back()->compat.insert(Feature(1, "one")); o.back()->compat.insert(Feature(2, "two")); o.back()->ro_compat.insert(Feature(4, "four")); o.back()->incompat.insert(Feature(3, "three")); } }; WRITE_CLASS_ENCODER(CompatSet) inline ostream& operator<<(ostream& out, const CompatSet::FeatureSet& fs) { return out << fs.names; } inline ostream& operator<<(ostream& out, const CompatSet& compat) { return out << "compat=" << compat.compat << ",rocompat=" << compat.ro_compat << ",incompat=" << compat.incompat; } #endif ceph-0.80.11/src/include/linux_fiemap.h0000664000175100017510000000533412623076744021745 0ustar jenkins-buildjenkins-build/* * FS_IOC_FIEMAP ioctl infrastructure. * * Some portions copyright (C) 2007 Cluster File Systems, Inc * * Authors: Mark Fasheh * Kalpak Shah * Andreas Dilger */ #ifndef _LINUX_FIEMAP_H #define _LINUX_FIEMAP_H #include "include/int_types.h" #if defined(__linux__) #include #elif defined(__FreeBSD_) #include #endif #include "include/int_types.h" struct fiemap_extent { __u64 fe_logical; /* logical offset in bytes for the start of * the extent from the beginning of the file */ __u64 fe_physical; /* physical offset in bytes for the start * of the extent from the beginning of the disk */ __u64 fe_length; /* length in bytes for this extent */ __u64 fe_reserved64[2]; __u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */ __u32 fe_reserved[3]; }; struct fiemap { __u64 fm_start; /* logical offset (inclusive) at * which to start mapping (in) */ __u64 fm_length; /* logical length of mapping which * userspace wants (in) */ __u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */ __u32 fm_mapped_extents;/* number of extents that were mapped (out) */ __u32 fm_extent_count; /* size of fm_extents array (in) */ __u32 fm_reserved; struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */ }; #define FIEMAP_MAX_OFFSET (~0ULL) #define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */ #define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */ #define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR) #define FIEMAP_EXTENT_LAST 0x00000001 /* Last extent in file. */ #define FIEMAP_EXTENT_UNKNOWN 0x00000002 /* Data location unknown. */ #define FIEMAP_EXTENT_DELALLOC 0x00000004 /* Location still pending. * Sets EXTENT_UNKNOWN. */ #define FIEMAP_EXTENT_ENCODED 0x00000008 /* Data can not be read * while fs is unmounted */ #define FIEMAP_EXTENT_DATA_ENCRYPTED 0x00000080 /* Data is encrypted by fs. * Sets EXTENT_NO_BYPASS. */ #define FIEMAP_EXTENT_NOT_ALIGNED 0x00000100 /* Extent offsets may not be * block aligned. */ #define FIEMAP_EXTENT_DATA_INLINE 0x00000200 /* Data mixed with metadata. * Sets EXTENT_NOT_ALIGNED.*/ #define FIEMAP_EXTENT_DATA_TAIL 0x00000400 /* Multiple files in block. * Sets EXTENT_NOT_ALIGNED.*/ #define FIEMAP_EXTENT_UNWRITTEN 0x00000800 /* Space allocated, but * no data (i.e. zero). */ #define FIEMAP_EXTENT_MERGED 0x00001000 /* File does not natively * support extents. Result * merged for efficiency. */ #define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other * files. */ #endif /* _LINUX_FIEMAP_H */ ceph-0.80.11/src/include/unordered_map.h0000664000175100017510000000043212623076744022103 0ustar jenkins-buildjenkins-build#ifndef CEPH_UNORDERED_MAP_H #define CEPH_UNORDERED_MAP_H #include #ifdef _LIBCPP_VERSION #include namespace ceph { using std::unordered_map; } #else #include namespace ceph { using std::tr1::unordered_map; } #endif #endif ceph-0.80.11/src/include/triple.h0000664000175100017510000000121512623076744020556 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_TRIPLE_H #define CEPH_TRIPLE_H template class triple { public: A first; B second; C third; triple() {} triple(A f, B s, C t) : first(f), second(s), third(t) {} }; #endif ceph-0.80.11/src/include/addr_parsing.h0000664000175100017510000000102612623076744021714 0ustar jenkins-buildjenkins-build/* * addr_parsing.h * * Created on: Sep 14, 2010 * Author: gregf * contains functions used by Ceph to convert named addresses * (eg ceph.newdream.net) into IP addresses (ie 127.0.0.1). */ #ifndef ADDR_PARSING_H_ #define ADDR_PARSING_H_ #ifdef __cplusplus extern "C" { #endif int safe_cat(char **pstr, int *plen, int pos, const char *str2); /* * returns a string allocated by malloc; caller must free */ char *resolve_addrs(const char *orig_str); #ifdef __cplusplus } #endif #endif /* ADDR_PARSING_H_ */ ceph-0.80.11/src/include/Spinlock.h0000664000175100017510000000416112623076744021044 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * @author Sage Weil */ #ifndef CEPH_SPINLOCK_H #define CEPH_SPINLOCK_H #include "acconfig.h" #include typedef struct { #ifdef HAVE_PTHREAD_SPINLOCK pthread_spinlock_t lock; #else pthread_mutex_t lock; #endif } ceph_spinlock_t; #ifdef HAVE_PTHREAD_SPINLOCK static inline int ceph_spin_init(ceph_spinlock_t *l) { return pthread_spin_init(&l->lock, PTHREAD_PROCESS_PRIVATE); } static inline int ceph_spin_destroy(ceph_spinlock_t *l) { return pthread_spin_destroy(&l->lock); } static inline int ceph_spin_lock(ceph_spinlock_t *l) { return pthread_spin_lock(&l->lock); } static inline int ceph_spin_unlock(ceph_spinlock_t *l) { return pthread_spin_unlock(&l->lock); } #else /* !HAVE_PTHREAD_SPINLOCK */ static inline int ceph_spin_init(ceph_spinlock_t *l) { return pthread_mutex_init(&l->lock, NULL); } static inline int ceph_spin_destroy(ceph_spinlock_t *l) { return pthread_mutex_destroy(&l->lock); } static inline int ceph_spin_lock(ceph_spinlock_t *l) { return pthread_mutex_lock(&l->lock); } static inline int ceph_spin_unlock(ceph_spinlock_t *l) { return pthread_mutex_unlock(&l->lock); } #endif class Spinlock { mutable ceph_spinlock_t _lock; public: Spinlock() { ceph_spin_init(&_lock); } ~Spinlock() { ceph_spin_destroy(&_lock); } // don't allow copying. void operator=(Spinlock& s); Spinlock(const Spinlock& s); /// acquire spinlock void lock() const { ceph_spin_lock(&_lock); } /// release spinlock void unlock() const { ceph_spin_unlock(&_lock); } class Locker { const Spinlock& spinlock; public: Locker(const Spinlock& s) : spinlock(s) { spinlock.lock(); } ~Locker() { spinlock.unlock(); } }; }; #endif ceph-0.80.11/src/include/uuid.h0000664000175100017510000000204612623076744020230 0ustar jenkins-buildjenkins-build#ifndef _CEPH_UUID_H #define _CEPH_UUID_H /* * Thin C++ wrapper around libuuid. */ #include "encoding.h" #include extern "C" { #include #include } struct uuid_d { uuid_t uuid; uuid_d() { memset(&uuid, 0, sizeof(uuid)); } bool is_zero() const { return uuid_is_null(uuid); } void generate_random() { uuid_generate(uuid); } bool parse(const char *s) { return uuid_parse(s, uuid) == 0; } void print(char *s) { return uuid_unparse(uuid, s); } void encode(bufferlist& bl) const { ::encode_raw(uuid, bl); } void decode(bufferlist::iterator& p) const { ::decode_raw(uuid, p); } }; WRITE_CLASS_ENCODER(uuid_d) inline std::ostream& operator<<(std::ostream& out, const uuid_d& u) { char b[37]; uuid_unparse(u.uuid, b); return out << b; } inline bool operator==(const uuid_d& l, const uuid_d& r) { return uuid_compare(l.uuid, r.uuid) == 0; } inline bool operator!=(const uuid_d& l, const uuid_d& r) { return uuid_compare(l.uuid, r.uuid) != 0; } #endif ceph-0.80.11/src/include/unordered_set.h0000664000175100017510000000043212623076744022121 0ustar jenkins-buildjenkins-build#ifndef CEPH_UNORDERED_SET_H #define CEPH_UNORDERED_SET_H #include #ifdef _LIBCPP_VERSION #include namespace ceph { using std::unordered_set; } #else #include namespace ceph { using std::tr1::unordered_set; } #endif #endif ceph-0.80.11/src/include/Context.h0000664000175100017510000002051512623076744020707 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CONTEXT_H #define CEPH_CONTEXT_H #include "common/dout.h" #include "include/assert.h" #include #include #include #include "include/memory.h" #define mydout(cct, v) lgeneric_subdout(cct, context, v) /* * GenContext - abstract callback class */ template class GenContext { GenContext(const GenContext& other); const GenContext& operator=(const GenContext& other); protected: virtual void finish(T t) = 0; public: GenContext() {} virtual ~GenContext() {} // we want a virtual destructor!!! virtual void complete(T t) { finish(t); delete this; } }; /* * Context - abstract callback class */ class Context { Context(const Context& other); const Context& operator=(const Context& other); protected: virtual void finish(int r) = 0; public: Context() {} virtual ~Context() {} // we want a virtual destructor!!! virtual void complete(int r) { finish(r); delete this; } }; /** * Simple context holding a single object */ template class ContainerContext : public Context { T obj; public: ContainerContext(T &obj) : obj(obj) {} void finish(int r) {} }; template struct Wrapper : public Context { Context *to_run; T val; Wrapper(Context *to_run, T val) : to_run(to_run), val(val) {} void finish(int r) { if (to_run) to_run->complete(r); } }; struct RunOnDelete { Context *to_run; RunOnDelete(Context *to_run) : to_run(to_run) {} ~RunOnDelete() { if (to_run) to_run->complete(0); } }; typedef ceph::shared_ptr RunOnDeleteRef; /* * finish and destroy a list of Contexts */ inline void finish_contexts(CephContext *cct, std::list& finished, int result = 0) { if (finished.empty()) return; list ls; ls.swap(finished); // swap out of place to avoid weird loops if (cct) mydout(cct, 10) << ls.size() << " contexts to finish with " << result << dendl; for (std::list::iterator it = ls.begin(); it != ls.end(); it++) { Context *c = *it; if (cct) mydout(cct,10) << "---- " << c << dendl; c->complete(result); } } inline void finish_contexts(CephContext *cct, std::vector& finished, int result = 0) { if (finished.empty()) return; vector ls; ls.swap(finished); // swap out of place to avoid weird loops if (cct) mydout(cct,10) << ls.size() << " contexts to finish with " << result << dendl; for (std::vector::iterator it = ls.begin(); it != ls.end(); it++) { Context *c = *it; if (cct) mydout(cct,10) << "---- " << c << dendl; c->complete(result); } } class C_NoopContext : public Context { public: void finish(int r) { } }; /* * C_Contexts - set of Contexts */ class C_Contexts : public Context { public: CephContext *cct; std::list contexts; C_Contexts(CephContext *cct_) : cct(cct_) { } void add(Context* c) { contexts.push_back(c); } void take(std::list& ls) { contexts.splice(contexts.end(), ls); } void finish(int r) { finish_contexts(cct, contexts, r); } bool empty() { return contexts.empty(); } static Context *list_to_context(list &cs) { if (cs.size() == 0) { return 0; } else if (cs.size() == 1) { Context *c = cs.front(); cs.clear(); return c; } else { C_Contexts *c(new C_Contexts(0)); c->take(cs); return c; } } }; /* * C_Gather * * BUG:? only reports error from last sub to have an error return */ class C_Gather : public Context { private: CephContext *cct; int result; Context *onfinish; #ifdef DEBUG_GATHER std::set waitfor; #endif int sub_created_count; int sub_existing_count; Mutex lock; bool activated; void sub_finish(Context* sub, int r) { lock.Lock(); #ifdef DEBUG_GATHER assert(waitfor.count(sub)); waitfor.erase(sub); #endif --sub_existing_count; mydout(cct,10) << "C_Gather " << this << ".sub_finish(r=" << r << ") " << sub #ifdef DEBUG_GATHER << " (remaining " << waitfor << ")" #endif << dendl; if (r < 0 && result == 0) result = r; if ((activated == false) || (sub_existing_count != 0)) { lock.Unlock(); return; } lock.Unlock(); delete_me(); } void delete_me() { if (onfinish) { onfinish->complete(result); onfinish = 0; } delete this; } class C_GatherSub : public Context { C_Gather *gather; public: C_GatherSub(C_Gather *g) : gather(g) {} void finish(int r) { gather->sub_finish(this, r); gather = 0; } ~C_GatherSub() { if (gather) gather->sub_finish(this, 0); } }; C_Gather(CephContext *cct_, Context *onfinish_) : cct(cct_), result(0), onfinish(onfinish_), sub_created_count(0), sub_existing_count(0), lock("C_Gather::lock", true, false), //disable lockdep activated(false) { mydout(cct,10) << "C_Gather " << this << ".new" << dendl; } public: ~C_Gather() { mydout(cct,10) << "C_Gather " << this << ".delete" << dendl; } void set_finisher(Context *onfinish_) { Mutex::Locker l(lock); assert(!onfinish); onfinish = onfinish_; } void activate() { lock.Lock(); assert(activated == false); activated = true; if (sub_existing_count != 0) { lock.Unlock(); return; } lock.Unlock(); delete_me(); } Context *new_sub() { Mutex::Locker l(lock); assert(activated == false); sub_created_count++; sub_existing_count++; Context *s = new C_GatherSub(this); #ifdef DEBUG_GATHER waitfor.insert(s); #endif mydout(cct,10) << "C_Gather " << this << ".new_sub is " << sub_created_count << " " << s << dendl; return s; } void finish(int r) { assert(0); // nobody should ever call me. } friend class C_GatherBuilder; }; /* * How to use C_GatherBuilder: * * 1. Create a C_GatherBuilder on the stack * 2. Call gather_bld.new_sub() as many times as you want to create new subs * It is safe to call this 0 times, or 100, or anything in between. * 3. If you didn't supply a finisher in the C_GatherBuilder constructor, * set one with gather_bld.set_finisher(my_finisher) * 4. Call gather_bld.activate() * * The finisher may be called at any point after step 4, including immediately * from the activate() function. * The finisher will never be called before activate(). * * Note: Currently, subs must be manually freed by the caller (for some reason.) */ class C_GatherBuilder { public: C_GatherBuilder(CephContext *cct_) : cct(cct_), c_gather(NULL), finisher(NULL), activated(false) { } C_GatherBuilder(CephContext *cct_, Context *finisher_) : cct(cct_), c_gather(NULL), finisher(finisher_), activated(false) { } ~C_GatherBuilder() { if (c_gather) { assert(activated); // Don't forget to activate your C_Gather! } else { delete finisher; } } Context *new_sub() { if (!c_gather) { c_gather = new C_Gather(cct, finisher); } return c_gather->new_sub(); } void activate() { if (!c_gather) return; assert(finisher != NULL); activated = true; c_gather->activate(); } void set_finisher(Context *finisher_) { finisher = finisher_; if (c_gather) c_gather->set_finisher(finisher); } C_Gather *get() const { return c_gather; } bool has_subs() const { return (c_gather != NULL); } int num_subs_created() { assert(!activated); if (c_gather == NULL) return 0; Mutex::Locker l(c_gather->lock); return c_gather->sub_created_count; } int num_subs_remaining() { assert(!activated); if (c_gather == NULL) return 0; Mutex::Locker l(c_gather->lock); return c_gather->sub_existing_count; } private: CephContext *cct; C_Gather *c_gather; Context *finisher; bool activated; }; #undef mydout #endif ceph-0.80.11/src/include/xlist.h0000664000175100017510000000633712623076744020434 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_XLIST_H #define CEPH_XLIST_H #include "include/assert.h" template class xlist { public: struct item { T _item; item *_prev, *_next; xlist *_list; item(T i) : _item(i), _prev(0), _next(0), _list(0) {} ~item() { assert(!is_on_list()); //remove_myself(); } // no copying! item(const item& other); const item& operator= (const item& right); xlist* get_list() { return _list; } bool is_on_list() const { return _list ? true:false; } bool remove_myself() { if (_list) { _list->remove(this); assert(_list == 0); return true; } else return false; } void move_to_front() { assert(_list); _list->push_front(this); } void move_to_back() { assert(_list); _list->push_back(this); } }; private: item *_front, *_back; int _size; public: xlist(const xlist& other); const xlist& operator=(const xlist& other); xlist() : _front(0), _back(0), _size(0) {} ~xlist() { assert(_size == 0); assert(_front == 0); assert(_back == 0); } int size() const { assert((bool)_front == (bool)_size); return _size; } bool empty() const { assert((bool)_front == (bool)_size); return _front == 0; } void clear() { while (_front) remove(_front); assert((bool)_front == (bool)_size); } void push_front(item *i) { if (i->_list) i->_list->remove(i); i->_list = this; i->_next = _front; i->_prev = 0; if (_front) _front->_prev = i; else _back = i; _front = i; _size++; } void push_back(item *i) { if (i->_list) i->_list->remove(i); i->_list = this; i->_next = 0; i->_prev = _back; if (_back) _back->_next = i; else _front = i; _back = i; _size++; } void remove(item *i) { assert(i->_list == this); if (i->_prev) i->_prev->_next = i->_next; else _front = i->_next; if (i->_next) i->_next->_prev = i->_prev; else _back = i->_prev; _size--; i->_list = 0; i->_next = i->_prev = 0; assert((bool)_front == (bool)_size); } T front() { return static_cast(_front->_item); } T back() { return static_cast(_back->_item); } void pop_front() { assert(!empty()); remove(_front); } void pop_back() { assert(!empty()); remove(_back); } class iterator { private: item *cur; public: iterator(item *i = 0) : cur(i) {} T operator*() { return static_cast(cur->_item); } iterator& operator++() { assert(cur); assert(cur->_list); cur = cur->_next; return *this; } bool end() const { return cur == 0; } }; iterator begin() { return iterator(_front); } iterator end() { return iterator(NULL); } }; #endif ceph-0.80.11/src/include/blobhash.h0000664000175100017510000000205512623076744021044 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_BLOBHASH_H #define CEPH_BLOBHASH_H #include "hash.h" /* - this is to make some of the STL types work with 64 bit values, string hash keys, etc. - added when i was using an old STL.. maybe try taking these out and see if things compile now? */ class blobhash { public: uint32_t operator()(const char *p, unsigned len) { static rjhash H; uint32_t acc = 0; while (len >= sizeof(acc)) { acc ^= *(uint32_t*)p; p += sizeof(uint32_t); len -= sizeof(uint32_t); } int sh = 0; while (len) { acc ^= (uint32_t)*p << sh; sh += 8; len--; p++; } return H(acc); } }; #endif ceph-0.80.11/src/include/buffer.h0000664000175100017510000003227612623076744020543 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_BUFFER_H #define CEPH_BUFFER_H #if defined(__linux__) #include #include #elif defined(__FreeBSD__) #include #include #endif #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 #endif #include #if defined(__linux__) // For malloc(2). #include #endif #include #include #include #ifndef __CYGWIN__ # include #endif #include #include #include #include #include #include #include "page.h" #include "crc32c.h" #ifdef __CEPH__ # include "include/assert.h" #else # include #endif namespace ceph { class buffer { /* * exceptions */ public: struct error : public std::exception{ const char *what() const throw () { return "buffer::exception"; } }; struct bad_alloc : public error { const char *what() const throw () { return "buffer::bad_alloc"; } }; struct end_of_buffer : public error { const char *what() const throw () { return "buffer::end_of_buffer"; } }; struct malformed_input : public error { explicit malformed_input(const char *w) { snprintf(buf, sizeof(buf), "buffer::malformed_input: %s", w); } const char *what() const throw () { return buf; } private: char buf[256]; }; struct error_code : public malformed_input { explicit error_code(int error); int code; }; /// total bytes allocated static int get_total_alloc(); /// enable/disable alloc tracking static void track_alloc(bool b); /// count of cached crc hits (matching input) static int get_cached_crc(); /// count of cached crc hits (mismatching input, required adjustment) static int get_cached_crc_adjusted(); /// enable/disable tracking of cached crcs static void track_cached_crc(bool b); /// count of calls to buffer::ptr::c_str() static int get_c_str_accesses(); /// enable/disable tracking of buffer::ptr::c_str() calls static void track_c_str(bool b); private: /* hack for memory utilization debugging. */ static void inc_total_alloc(unsigned len); static void dec_total_alloc(unsigned len); /* * an abstract raw buffer. with a reference count. */ class raw; class raw_malloc; class raw_static; class raw_mmap_pages; class raw_posix_aligned; class raw_hack_aligned; class raw_char; class raw_pipe; friend std::ostream& operator<<(std::ostream& out, const raw &r); public: /* * named constructors */ static raw* copy(const char *c, unsigned len); static raw* create(unsigned len); static raw* claim_char(unsigned len, char *buf); static raw* create_malloc(unsigned len); static raw* claim_malloc(unsigned len, char *buf); static raw* create_static(unsigned len, char *buf); static raw* create_page_aligned(unsigned len); static raw* create_zero_copy(unsigned len, int fd, int64_t *offset); /* * a buffer pointer. references (a subsequence of) a raw buffer. */ class ptr { raw *_raw; unsigned _off, _len; void release(); public: ptr() : _raw(0), _off(0), _len(0) {} ptr(raw *r); ptr(unsigned l); ptr(const char *d, unsigned l); ptr(const ptr& p); ptr(const ptr& p, unsigned o, unsigned l); ptr& operator= (const ptr& p); ~ptr() { release(); } bool have_raw() const { return _raw ? true:false; } raw *clone(); void swap(ptr& other); // misc bool at_buffer_head() const { return _off == 0; } bool at_buffer_tail() const; bool is_page_aligned() const { return ((long)c_str() & ~CEPH_PAGE_MASK) == 0; } bool is_n_page_sized() const { return (length() & ~CEPH_PAGE_MASK) == 0; } // accessors raw *get_raw() const { return _raw; } const char *c_str() const; char *c_str(); unsigned length() const { return _len; } unsigned offset() const { return _off; } unsigned start() const { return _off; } unsigned end() const { return _off + _len; } unsigned unused_tail_length() const; const char& operator[](unsigned n) const; char& operator[](unsigned n); const char *raw_c_str() const; unsigned raw_length() const; int raw_nref() const; void copy_out(unsigned o, unsigned l, char *dest) const { assert(_raw); if (!((o <= _len) && (o+l <= _len))) throw end_of_buffer(); memcpy(dest, c_str()+o, l); } bool can_zero_copy() const; int zero_copy_to_fd(int fd, int64_t *offset) const; unsigned wasted(); int cmp(const ptr& o) const; bool is_zero() const; // modifiers void set_offset(unsigned o) { _off = o; } void set_length(unsigned l) { _len = l; } void append(char c); void append(const char *p, unsigned l); void copy_in(unsigned o, unsigned l, const char *src); void zero(); void zero(unsigned o, unsigned l); }; friend std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp); /* * list - the useful bit! */ class list { // my private bits std::list _buffers; unsigned _len; ptr append_buffer; // where i put small appends. public: class iterator { list *bl; std::list *ls; // meh.. just here to avoid an extra pointer dereference.. unsigned off; // in bl std::list::iterator p; unsigned p_off; // in *p public: // constructor. position. iterator() : bl(0), ls(0), off(0), p_off(0) {} iterator(list *l, unsigned o=0) : bl(l), ls(&bl->_buffers), off(0), p(ls->begin()), p_off(0) { advance(o); } iterator(list *l, unsigned o, std::list::iterator ip, unsigned po) : bl(l), ls(&bl->_buffers), off(o), p(ip), p_off(po) { } iterator(const iterator& other) : bl(other.bl), ls(other.ls), off(other.off), p(other.p), p_off(other.p_off) {} iterator& operator=(const iterator& other) { if (this != &other) { bl = other.bl; ls = other.ls; off = other.off; p = other.p; p_off = other.p_off; } return *this; } /// get current iterator offset in buffer::list unsigned get_off() { return off; } /// get number of bytes remaining from iterator position to the end of the buffer::list unsigned get_remaining() { return bl->length() - off; } /// true if iterator is at the end of the buffer::list bool end() { return p == ls->end(); //return off == bl->length(); } void advance(int o); void seek(unsigned o); char operator*(); iterator& operator++(); ptr get_current_ptr(); // copy data out. // note that these all _append_ to dest! void copy(unsigned len, char *dest); void copy(unsigned len, ptr &dest); void copy(unsigned len, list &dest); void copy(unsigned len, std::string &dest); void copy_all(list &dest); // copy data in void copy_in(unsigned len, const char *src); void copy_in(unsigned len, const list& otherl); }; private: mutable iterator last_p; int zero_copy_to_fd(int fd) const; public: // cons/des list() : _len(0), last_p(this) {} list(unsigned prealloc) : _len(0), last_p(this) { append_buffer = buffer::create(prealloc); append_buffer.set_length(0); // unused, so far. } ~list() {} list(const list& other) : _buffers(other._buffers), _len(other._len), last_p(this) { } list& operator= (const list& other) { if (this != &other) { _buffers = other._buffers; _len = other._len; } return *this; } const std::list& buffers() const { return _buffers; } void swap(list& other); unsigned length() const { #if 0 // DEBUG: verify _len unsigned len = 0; for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); it++) { len += (*it).length(); } assert(len == _len); #endif return _len; } bool contents_equal(buffer::list& other); bool can_zero_copy() const; bool is_page_aligned() const; bool is_n_page_sized() const; bool is_zero() const; // modifiers void clear() { _buffers.clear(); _len = 0; last_p = begin(); } void push_front(ptr& bp) { if (bp.length() == 0) return; _buffers.push_front(bp); _len += bp.length(); } void push_front(raw *r) { ptr bp(r); push_front(bp); } void push_back(const ptr& bp) { if (bp.length() == 0) return; _buffers.push_back(bp); _len += bp.length(); } void push_back(raw *r) { ptr bp(r); push_back(bp); } void zero(); void zero(unsigned o, unsigned l); bool is_contiguous(); void rebuild(); void rebuild(ptr& nb); void rebuild_page_aligned(); // sort-of-like-assignment-op void claim(list& bl); void claim_append(list& bl); void claim_prepend(list& bl); iterator begin() { return iterator(this, 0); } iterator end() { return iterator(this, _len, _buffers.end(), 0); } // crope lookalikes. // **** WARNING: this are horribly inefficient for large bufferlists. **** void copy(unsigned off, unsigned len, char *dest) const; void copy(unsigned off, unsigned len, list &dest) const; void copy(unsigned off, unsigned len, std::string& dest) const; void copy_in(unsigned off, unsigned len, const char *src); void copy_in(unsigned off, unsigned len, const list& src); void append(char c); void append(const char *data, unsigned len); void append(const std::string& s) { append(s.data(), s.length()); } void append(const ptr& bp); void append(const ptr& bp, unsigned off, unsigned len); void append(const list& bl); void append(std::istream& in); void append_zero(unsigned len); /* * get a char */ const char& operator[](unsigned n) const; char *c_str(); void substr_of(const list& other, unsigned off, unsigned len); // funky modifer void splice(unsigned off, unsigned len, list *claim_by=0 /*, bufferlist& replace_with */); void write(int off, int len, std::ostream& out) const; void encode_base64(list& o); void decode_base64(list& o); void hexdump(std::ostream &out) const; int read_file(const char *fn, std::string *error); ssize_t read_fd(int fd, size_t len); int read_fd_zero_copy(int fd, size_t len); int write_file(const char *fn, int mode=0644); int write_fd(int fd) const; int write_fd_zero_copy(int fd) const; uint32_t crc32c(uint32_t crc) const; }; /* * efficient hash of one or more bufferlists */ class hash { uint32_t crc; public: hash() : crc(0) { } hash(uint32_t init) : crc(init) { } void update(buffer::list& bl) { crc = bl.crc32c(crc); } uint32_t digest() { return crc; } }; }; typedef buffer::ptr bufferptr; typedef buffer::list bufferlist; typedef buffer::hash bufferhash; inline bool operator>(bufferlist& l, bufferlist& r) { for (unsigned p = 0; ; p++) { if (l.length() > p && r.length() == p) return true; if (l.length() == p) return false; if (l[p] > r[p]) return true; if (l[p] < r[p]) return false; } } inline bool operator>=(bufferlist& l, bufferlist& r) { for (unsigned p = 0; ; p++) { if (l.length() > p && r.length() == p) return true; if (r.length() == p && l.length() == p) return true; if (l.length() == p && r.length() > p) return false; if (l[p] > r[p]) return true; if (l[p] < r[p]) return false; } } inline bool operator==(bufferlist &l, bufferlist &r) { if (l.length() != r.length()) return false; for (unsigned p = 0; p < l.length(); p++) { if (l[p] != r[p]) return false; } return true; } inline bool operator<(bufferlist& l, bufferlist& r) { return r > l; } inline bool operator<=(bufferlist& l, bufferlist& r) { return r >= l; } inline std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp) { if (bp.have_raw()) out << "buffer::ptr(" << bp.offset() << "~" << bp.length() << " " << (void*)bp.c_str() << " in raw " << (void*)bp.raw_c_str() << " len " << bp.raw_length() << " nref " << bp.raw_nref() << ")"; else out << "buffer:ptr(" << bp.offset() << "~" << bp.length() << " no raw)"; return out; } inline std::ostream& operator<<(std::ostream& out, const buffer::list& bl) { out << "buffer::list(len=" << bl.length() << "," << std::endl; std::list::const_iterator it = bl.buffers().begin(); while (it != bl.buffers().end()) { out << "\t" << *it; if (++it == bl.buffers().end()) break; out << "," << std::endl; } out << std::endl << ")"; return out; } inline std::ostream& operator<<(std::ostream& out, buffer::error& e) { return out << e.what(); } inline bufferhash& operator<<(bufferhash& l, bufferlist &r) { l.update(r); return l; } } #endif ceph-0.80.11/src/include/interval_set.h0000664000175100017510000003177612623076744021775 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_INTERVAL_SET_H #define CEPH_INTERVAL_SET_H #include #include #include using namespace std; #include "encoding.h" #ifndef MIN # define MIN(a,b) ((a)<=(b) ? (a):(b)) #endif #ifndef MAX # define MAX(a,b) ((a)>=(b) ? (a):(b)) #endif template class interval_set { public: class const_iterator; class iterator : public std::iterator { public: explicit iterator(typename std::map::iterator iter) : _iter(iter) { } // For the copy constructor and assignment operator, the compiler-generated functions, which // perform simple bitwise copying, should be fine. bool operator==(const iterator& rhs) const { return (_iter == rhs._iter); } bool operator!=(const iterator& rhs) const { return (_iter != rhs._iter); } // Dereference this iterator to get a pair. pair < T, T > &operator*() { return *_iter; } // Return the interval start. T get_start() const { return _iter->first; } // Return the interval length. T get_len() const { return _iter->second; } // Set the interval length. void set_len(T len) { _iter->second = len; } // Preincrement iterator &operator++() { ++_iter; return *this; } // Postincrement iterator operator++(int) { iterator prev(_iter); ++_iter; return prev; } friend class interval_set::const_iterator; protected: typename map::iterator _iter; friend class interval_set; }; class const_iterator : public std::iterator { public: explicit const_iterator(typename std::map::const_iterator iter) : _iter(iter) { } const_iterator(const iterator &i) : _iter(i._iter) { } // For the copy constructor and assignment operator, the compiler-generated functions, which // perform simple bitwise copying, should be fine. bool operator==(const const_iterator& rhs) const { return (_iter == rhs._iter); } bool operator!=(const const_iterator& rhs) const { return (_iter != rhs._iter); } // Dereference this iterator to get a pair. pair < T, T > operator*() const { return *_iter; } // Return the interval start. T get_start() const { return _iter->first; } // Return the interval length. T get_len() const { return _iter->second; } // Preincrement const_iterator &operator++() { ++_iter; return *this; } // Postincrement const_iterator operator++(int) { const_iterator prev(_iter); ++_iter; return prev; } protected: typename map::const_iterator _iter; }; interval_set() : _size(0) {} int num_intervals() const { return m.size(); } typename interval_set::iterator begin() { return typename interval_set::iterator(m.begin()); } typename interval_set::iterator end() { return typename interval_set::iterator(m.end()); } typename interval_set::const_iterator begin() const { return typename interval_set::const_iterator(m.begin()); } typename interval_set::const_iterator end() const { return typename interval_set::const_iterator(m.end()); } // helpers private: typename map::const_iterator find_inc(T start) const { typename map::const_iterator p = m.lower_bound(start); // p->first >= start if (p != m.begin() && (p == m.end() || p->first > start)) { p--; // might overlap? if (p->first + p->second <= start) p++; // it doesn't. } return p; } typename map::iterator find_inc_m(T start) { typename map::iterator p = m.lower_bound(start); if (p != m.begin() && (p == m.end() || p->first > start)) { p--; // might overlap? if (p->first + p->second <= start) p++; // it doesn't. } return p; } typename map::const_iterator find_adj(T start) const { typename map::const_iterator p = m.lower_bound(start); if (p != m.begin() && (p == m.end() || p->first > start)) { p--; // might touch? if (p->first + p->second < start) p++; // it doesn't. } return p; } typename map::iterator find_adj_m(T start) { typename map::iterator p = m.lower_bound(start); if (p != m.begin() && (p == m.end() || p->first > start)) { p--; // might touch? if (p->first + p->second < start) p++; // it doesn't. } return p; } public: bool operator==(const interval_set& other) const { return _size == other._size && m == other.m; } int size() const { return _size; } void encode(bufferlist& bl) const { ::encode(m, bl); } void encode_nohead(bufferlist& bl) const { ::encode_nohead(m, bl); } void decode(bufferlist::iterator& bl) { ::decode(m, bl); _size = 0; for (typename map::const_iterator p = m.begin(); p != m.end(); p++) _size += p->second; } void decode_nohead(int n, bufferlist::iterator& bl) { ::decode_nohead(n, m, bl); _size = 0; for (typename map::const_iterator p = m.begin(); p != m.end(); p++) _size += p->second; } void clear() { m.clear(); _size = 0; } bool contains(T i) const { typename map::const_iterator p = find_inc(i); if (p == m.end()) return false; if (p->first > i) return false; if (p->first+p->second <= i) return false; assert(p->first <= i && p->first+p->second > i); return true; } bool contains(T start, T len) const { typename map::const_iterator p = find_inc(start); if (p == m.end()) return false; if (p->first > start) return false; if (p->first+p->second <= start) return false; assert(p->first <= start && p->first+p->second > start); if (p->first+p->second < start+len) return false; return true; } bool intersects(T start, T len) const { interval_set a; a.insert(start, len); interval_set i; i.intersection_of( *this, a ); if (i.empty()) return false; return true; } // outer range of set bool empty() const { return m.empty(); } T range_start() const { assert(!empty()); typename map::const_iterator p = m.begin(); return p->first; } T range_end() const { assert(!empty()); typename map::const_iterator p = m.end(); p--; return p->first+p->second; } // interval start after p (where p not in set) bool starts_after(T i) const { assert(!contains(i)); typename map::const_iterator p = find_inc(i); if (p == m.end()) return false; return true; } T start_after(T i) const { assert(!contains(i)); typename map::const_iterator p = find_inc(i); return p->first; } // interval end that contains start T end_after(T start) const { assert(contains(start)); typename map::const_iterator p = find_inc(start); return p->first+p->second; } void insert(T val) { insert(val, 1); } void insert(T start, T len) { //cout << "insert " << start << "~" << len << endl; assert(len > 0); _size += len; typename map::iterator p = find_adj_m(start); if (p == m.end()) { m[start] = len; // new interval } else { if (p->first < start) { if (p->first + p->second != start) { //cout << "p is " << p->first << "~" << p->second << ", start is " << start << ", len is " << len << endl; assert(0); } assert(p->first + p->second == start); p->second += len; // append to end typename map::iterator n = p; n++; if (n != m.end() && start+len == n->first) { // combine with next, too! p->second += n->second; m.erase(n); } } else { if (start+len == p->first) { m[start] = len + p->second; // append to front m.erase(p); } else { assert(p->first > start+len); m[start] = len; // new interval } } } } void swap(interval_set& other) { m.swap(other.m); int64_t t = _size; _size = other._size; other._size = t; } void erase(iterator &i) { _size -= i.get_len(); assert(_size >= 0); m.erase(i._iter); } void erase(T val) { erase(val, 1); } void erase(T start, T len) { typename map::iterator p = find_inc_m(start); _size -= len; assert(_size >= 0); assert(p != m.end()); assert(p->first <= start); T before = start - p->first; assert(p->second >= before+len); T after = p->second - before - len; if (before) p->second = before; // shorten bit before else m.erase(p); if (after) m[start+len] = after; } void subtract(const interval_set &a) { for (typename map::const_iterator p = a.m.begin(); p != a.m.end(); p++) erase(p->first, p->second); } void insert(const interval_set &a) { for (typename map::const_iterator p = a.m.begin(); p != a.m.end(); p++) insert(p->first, p->second); } void intersection_of(const interval_set &a, const interval_set &b) { assert(&a != this); assert(&b != this); clear(); typename map::const_iterator pa = a.m.begin(); typename map::const_iterator pb = b.m.begin(); while (pa != a.m.end() && pb != b.m.end()) { // passing? if (pa->first + pa->second <= pb->first) { pa++; continue; } if (pb->first + pb->second <= pa->first) { pb++; continue; } T start = MAX(pa->first, pb->first); T en = MIN(pa->first+pa->second, pb->first+pb->second); assert(en > start); insert(start, en-start); if (pa->first+pa->second > pb->first+pb->second) pb++; else pa++; } } void intersection_of(const interval_set& b) { interval_set a; swap(a); intersection_of(a, b); } void union_of(const interval_set &a, const interval_set &b) { assert(&a != this); assert(&b != this); clear(); //cout << "union_of" << endl; // a m = a.m; _size = a._size; // - (a*b) interval_set ab; ab.intersection_of(a, b); subtract(ab); // + b insert(b); return; } void union_of(const interval_set &b) { interval_set a; swap(a); union_of(a, b); } bool subset_of(const interval_set &big) const { for (typename map::const_iterator i = m.begin(); i != m.end(); i++) if (!big.contains(i->first, i->second)) return false; return true; } /* * build a subset of @other, starting at or after @start, and including * @len worth of values, skipping holes. e.g., * span_of([5~10,20~5], 8, 5) -> [8~2,20~3] */ void span_of(const interval_set &other, T start, T len) { clear(); typename map::const_iterator p = other.find_inc(start); if (p == other.m.end()) return; if (p->first < start) { if (p->first + p->second < start) return; if (p->first + p->second < start + len) { T howmuch = p->second - (start - p->first); insert(start, howmuch); len -= howmuch; p++; } else { insert(start, len); return; } } while (p != other.m.end() && len > 0) { if (p->second < len) { insert(p->first, p->second); len -= p->second; p++; } else { insert(p->first, len); return; } } } private: // data int64_t _size; map m; // map start -> len }; template inline ostream& operator<<(ostream& out, const interval_set &s) { out << "["; const char *prequel = ""; for (typename interval_set::const_iterator i = s.begin(); i != s.end(); ++i) { out << prequel << i.get_start() << "~" << i.get_len(); prequel = ","; } out << "]"; return out; } template inline void encode(const interval_set& s, bufferlist& bl) { s.encode(bl); } template inline void decode(interval_set& s, bufferlist::iterator& p) { s.decode(p); } #endif ceph-0.80.11/src/include/elist.h0000664000175100017510000001014312623076744020377 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_ELIST_H #define CEPH_ELIST_H /* * elist: embedded list. * * requirements: * - elist::item be embedded in the parent class * - items are _always_ added to the list via the same elist::item at the same * fixed offset in the class. * - begin(), front(), back() methods take the member offset as an argument for traversal. * */ #define member_offset(cls, member) ((size_t)(&((cls*)1)->member) - 1) template class elist { public: struct item { item *_prev, *_next; item(T i=0) : _prev(this), _next(this) {} ~item() { assert(!is_on_list()); } // no copying! item(const item& other); const item& operator= (const item& right); bool empty() const { return _prev == this; } bool is_on_list() const { return !empty(); } bool remove_myself() { if (_next == this) { assert(_prev == this); return false; } _next->_prev = _prev; _prev->_next = _next; _prev = _next = this; return true; } void insert_after(item *other) { assert(other->empty()); other->_prev = this; other->_next = _next; _next->_prev = other; _next = other; } void insert_before(item *other) { assert(other->empty()); other->_next = this; other->_prev = _prev; _prev->_next = other; _prev = other; } T get_item(size_t offset) { assert(offset); return (T)(((char *)this) - offset); } }; private: item _head; size_t item_offset; public: elist(const elist& other); const elist& operator=(const elist& other); elist(size_t o) : _head(NULL), item_offset(o) {} ~elist() { assert(_head.empty()); } bool empty() const { return _head.empty(); } void clear() { while (!_head.empty()) pop_front(); } void push_front(item *i) { if (!i->empty()) i->remove_myself(); _head.insert_after(i); } void push_back(item *i) { if (!i->empty()) i->remove_myself(); _head.insert_before(i); } T front(size_t o=0) { assert(!_head.empty()); return _head._next->get_item(o ? o : item_offset); } T back(size_t o=0) { assert(!_head.empty()); return _head._prev->get_item(o ? o : item_offset); } void pop_front() { assert(!empty()); _head._next->remove_myself(); } void pop_back() { assert(!empty()); _head._prev->remove_myself(); } void clear_list() { while (!empty()) pop_front(); } enum mode_t { MAGIC, CURRENT, CACHE_NEXT }; class iterator { private: item *head; item *cur, *next; size_t item_offset; mode_t mode; public: iterator(item *h, size_t o, mode_t m) : head(h), cur(h->_next), next(cur->_next), item_offset(o), mode(m) { assert(item_offset > 0); } T operator*() { return cur->get_item(item_offset); } iterator& operator++() { assert(cur); assert(cur != head); if (mode == MAGIC) { // if 'cur' appears to be valid, use that. otherwise, // use cached 'next'. // this is a bit magic, and probably a bad idea... :/ if (cur->empty()) cur = next; else cur = cur->_next; } else if (mode == CURRENT) cur = cur->_next; else if (mode == CACHE_NEXT) cur = next; else assert(0); next = cur->_next; return *this; } bool end() const { return cur == head; } }; iterator begin(size_t o=0) { return iterator(&_head, o ? o : item_offset, MAGIC); } iterator begin_use_current(size_t o=0) { return iterator(&_head, o ? o : item_offset, CURRENT); } iterator begin_cache_next(size_t o=0) { return iterator(&_head, o ? o : item_offset, CACHE_NEXT); } }; #endif ceph-0.80.11/src/include/cmp.h0000664000175100017510000001275112623076744020045 0ustar jenkins-buildjenkins-build#ifndef __CEPH_CMP_H #define __CEPH_CMP_H /* * macros to define comparison operators for classes with small numbers of members. */ #define WRITE_EQ_OPERATORS_2(type, a, b) \ inline bool operator==(const type &l, const type &r) { \ return l.a == r.a && l.b == r.b; \ } \ inline bool operator!=(const type &l, const type &r) { \ return l.a != r.a || l.b != r.b; \ } #define WRITE_CMP_OPERATORS_2(type, a, b) \ inline bool operator>(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b)); \ } \ inline bool operator<(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b)); \ } \ inline bool operator>=(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b >= r.b)); \ } \ inline bool operator<=(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b <= r.b)); \ } #define WRITE_EQ_OPERATORS_3(type, a, b, c) \ inline bool operator==(const type &l, const type &r) { \ return l.a == r.a && l.b == r.b && l.c == r.c; \ } \ inline bool operator!=(const type &l, const type &r) { \ return l.a != r.a || l.b != r.b || l.c != r.c; \ } #define WRITE_CMP_OPERATORS_3(type, a, b, c) \ inline bool operator>(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b || \ (l.b == r.b && (l.c > r.c)))); \ } \ inline bool operator<(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b || \ (l.b == r.b && (l.c < r.c)))); \ } \ inline bool operator>=(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b || \ (l.b == r.b && (l.c >= r.c)))); \ } \ inline bool operator<=(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b || \ (l.b == r.b && (l.c <= r.c)))); \ } #define WRITE_EQ_OPERATORS_5(type, a, b, c, d, e) \ inline bool operator==(const type &l, const type &r) { \ return l.a == r.a && l.b == r.b && l.c == r.c && l.d == r.d && l.e == r.e; \ } \ inline bool operator!=(const type &l, const type &r) { \ return l.a != r.a || l.b != r.b || l.c != r.c || l.d != r.d || l.e != r.e; \ } #define WRITE_CMP_OPERATORS_5(type, a, b, c, d, e) \ inline bool operator>(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b || \ (l.b == r.b && (l.c > r.c || \ (l.c == r.c && (l.d > r.d || \ (l.d == r.d && l.e > r.e))))))); \ } \ inline bool operator<(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b || \ (l.b == r.b && (l.c < r.c || \ (l.c == r.c && (l.d < r.d || \ (l.d == r.d && (l.e < r.e)))))))); \ } \ inline bool operator>=(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b || \ (l.b == r.b && (l.c > r.c || \ (l.c == r.c && (l.d > r.d || \ (l.d == r.d && l.e >= r.e))))))); \ } \ inline bool operator<=(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b || \ (l.b == r.b && (l.c < r.c || \ (l.c == r.c && (l.d < r.d || \ (l.d == r.d && l.e <= r.e))))))); \ } #define WRITE_EQ_OPERATORS_7(type, a, b, c, d, e, f, g) \ inline bool operator==(const type &l, const type &r) { \ return l.a == r.a && l.b == r.b && l.c == r.c && l.d == r.d && l.e == r.e && l.f == r.f && l.g == r.g; \ } \ inline bool operator!=(const type &l, const type &r) { \ return l.a != r.a || l.b != r.b || l.c != r.c || l.d != r.d || l.e != r.e || l.f != r.f || l.g != r.g; \ } #define WRITE_CMP_OPERATORS_7(type, a, b, c, d, e, f, g) \ inline bool operator<=(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b || \ (l.b == r.b && (l.c < r.c || \ (l.c == r.c && (l.d < r.d || \ (l.d == r.d && (l.e < r.e || \ (l.e == r.e && (l.f < r.f || \ (l.f == r.f && l.g <= r.g))))))))))); \ } \ inline bool operator>=(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b || \ (l.b == r.b && (l.c > r.c || \ (l.c == r.c && (l.d > r.d || \ (l.d == r.d && (l.e > r.e || \ (l.e == r.e && (l.f > r.f || \ (l.f == r.f && l.g >= r.g))))))))))); \ } \ inline bool operator>(const type &l, const type &r) { \ return l.a > r.a || \ (l.a == r.a && (l.b > r.b || \ (l.b == r.b && (l.c > r.c || \ (l.c == r.c && (l.d > r.d || \ (l.d == r.d && (l.e > r.e || \ (l.e == r.e && (l.f > r.f || \ (l.f == r.f && l.g > r.g))))))))))); \ } \ inline bool operator<(const type &l, const type &r) { \ return l.a < r.a || \ (l.a == r.a && (l.b < r.b || \ (l.b == r.b && (l.c < r.c || \ (l.c == r.c && (l.d < r.d || \ (l.d == r.d && (l.e < r.e || \ (l.e == r.e && (l.f < r.f || \ (l.f == r.f && l.g < r.g))))))))))); \ } #endif ceph-0.80.11/src/include/int_types.h0000664000175100017510000000347512623076744021307 0ustar jenkins-buildjenkins-build#ifndef CEPH_INTTYPES_H #define CEPH_INTTYPES_H #include "acconfig.h" #ifdef HAVE_LINUX_TYPES_H #include #endif /* * Get 64b integers either from inttypes.h or glib.h */ #ifdef HAVE_INTTYPES_H # include //#else //# ifdef HAVE_GLIB //# include //# endif #endif /* * C99 says inttypes.h includes stdint.h, but that's not true on all * systems. If it's there, include it always - just in case. */ #ifdef HAVE_STDINT_H #include #endif /* * Emergency replacements for PRI*64 modifiers. Some systems have * an inttypes.h that doesn't define all the PRI[doxu]64 macros. */ #if !defined(PRIu64) # if defined(HAVE_INTTYPES_H) || defined(HAVE_GLIB) /* If we have inttypes or glib, assume we have 64-bit long long int */ # define PRIu64 "llu" # define PRIi64 "lli" # define PRIx64 "llx" # define PRIX64 "llX" # define PRIo64 "llo" # define PRId64 "lld" # else /* Assume that we don't have long long, so use long int modifiers */ # define PRIu64 "lu" # define PRIi64 "li" # define PRIx64 "lx" # define PRIX64 "lX" # define PRIo64 "lo" # define PRId64 "ld" # endif #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifndef HAVE___U8 typedef uint8_t __u8; #endif #ifndef HAVE___S8 typedef int8_t __s8; #endif #ifndef HAVE___U16 typedef uint16_t __u16; #endif #ifndef HAVE___S16 typedef int16_t __s16; #endif #ifndef HAVE___U32 typedef uint32_t __u32; #endif #ifndef HAVE___S32 typedef int32_t __s32; #endif #ifndef HAVE___U64 typedef uint64_t __u64; #endif #ifndef HAVE___S64 typedef int64_t __s64; #endif #define __bitwise__ typedef __u16 __bitwise__ __le16; typedef __u16 __bitwise__ __be16; typedef __u32 __bitwise__ __le32; typedef __u32 __bitwise__ __be32; typedef __u64 __bitwise__ __le64; typedef __u64 __bitwise__ __be64; #endif ceph-0.80.11/src/include/crc32c.h0000664000175100017510000000137412623076744020344 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRC32C_H #define CEPH_CRC32C_H #include #include typedef uint32_t (*ceph_crc32c_func_t)(uint32_t crc, unsigned char const *data, unsigned length); /* * this is a static global with the chosen crc32c implementation for * the given architecture. */ extern ceph_crc32c_func_t ceph_crc32c_func; extern ceph_crc32c_func_t ceph_choose_crc32(void); /** * calculate crc32c * * Note: if the data pointer is NULL, we calculate a crc value as if * it were zero-filled. * * @param crc initial value * @param data pointer to data buffer * @param length length of buffer */ static inline uint32_t ceph_crc32c(uint32_t crc, unsigned char const *data, unsigned length) { return ceph_crc32c_func(crc, data, length); } #endif ceph-0.80.11/src/include/ipaddr.h0000664000175100017510000000102012623076744020514 0ustar jenkins-buildjenkins-build#ifndef CEPH_IPADDR_H #define CEPH_IPADDR_H #include #include #include /* Find an IP address that is in the wanted subnet. If there are multiple matches, the first one is returned; this order is system-dependent and should not be relied on. */ const struct sockaddr *find_ip_in_subnet(const struct ifaddrs *addrs, const struct sockaddr *net, unsigned int prefix_len); bool parse_network(const char *s, struct sockaddr *network, unsigned int *prefix_len); #endif ceph-0.80.11/src/include/frag.h0000664000175100017510000003637312623076744020213 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_FRAG_H #define CEPH_FRAG_H #include #include #include #include #include #include "buffer.h" #include "ceph_frag.h" #include "include/assert.h" /* * * the goal here is to use a binary split strategy to partition a namespace. * frag_t represents a particular fragment. bits() tells you the size of the * fragment, and value() it's name. this is roughly analogous to an ip address * and netmask. * * fragtree_t represents an entire namespace and it's partition. it essentially * tells you where fragments are split into other fragments, and by how much * (i.e. by how many bits, resulting in a power of 2 number of child fragments). * * this vaguely resembles a btree, in that when a fragment becomes large or small * we can split or merge, except that there is no guarantee of being balanced. * * presumably we are partitioning the output of a (perhaps specialized) hash * function. */ /** * frag_t * * description of an individual fragment. that is, a particular piece * of the overall namespace. * * this is conceptually analogous to an ip address and netmask. * * a value v falls "within" fragment f iff (v & f.mask()) == f.value(). * * we write it as v/b, where v is a value and b is the number of bits. * 0/0 (bits==0) corresponds to the entire namespace. if we bisect that, * we get 0/1 and 1/1. quartering gives us 0/2, 1/2, 2/2, 3/2. and so on. * * this makes the right most bit of v the "most significant", which is the * opposite of what we usually see. */ /* * TODO: * - get_first_child(), next_sibling(int parent_bits) to make (possibly partial) * iteration efficient (see, e.g., try_assimilate_children() * - rework frag_t so that we mask the left-most (most significant) bits instead of * the right-most (least significant) bits. just because it's more intutive, and * matches the network/netmask concept. */ typedef uint32_t _frag_t; class frag_t { /* * encoding is dictated by frag_* functions in ceph_fs.h. use those * helpers _exclusively_. */ public: _frag_t _enc; frag_t() : _enc(0) { } frag_t(unsigned v, unsigned b) : _enc(ceph_frag_make(b, v)) { } frag_t(_frag_t e) : _enc(e) { } // constructors void from_unsigned(unsigned e) { _enc = e; } // accessors unsigned value() const { return ceph_frag_value(_enc); } unsigned bits() const { return ceph_frag_bits(_enc); } unsigned mask() const { return ceph_frag_mask(_enc); } unsigned mask_shift() const { return ceph_frag_mask_shift(_enc); } operator _frag_t() const { return _enc; } // tests bool contains(unsigned v) const { return ceph_frag_contains_value(_enc, v); } bool contains(frag_t sub) const { return ceph_frag_contains_frag(_enc, sub._enc); } bool is_root() const { return bits() == 0; } frag_t parent() const { assert(bits() > 0); return frag_t(ceph_frag_parent(_enc)); } // splitting frag_t make_child(int i, int nb) const { assert(i < (1<& fragments) const { assert(nb > 0); unsigned nway = 1 << nb; for (unsigned i=0; i: // frag_t f is split by b bits. // if child frag_t does not appear, it is not split. public: std::map _splits; public: // ------------- // basics void swap(fragtree_t& other) { _splits.swap(other._splits); } void clear() { _splits.clear(); } // ------------- // accessors bool empty() { return _splits.empty(); } int get_split(const frag_t hb) const { std::map::const_iterator p = _splits.find(hb); if (p == _splits.end()) return 0; else return p->second; } bool is_leaf(frag_t x) const { std::list ls; get_leaves_under(x, ls); //generic_dout(10) << "is_leaf(" << x << ") -> " << ls << dendl; if (!ls.empty() && ls.front() == x && ls.size() == 1) return true; return false; } /** * get_leaves -- list all leaves */ void get_leaves(std::list& ls) const { return get_leaves_under_split(frag_t(), ls); } /** * get_leaves_under_split -- list all leaves under a known split point (or root) */ void get_leaves_under_split(frag_t under, std::list& ls) const { std::list q; q.push_back(under); while (!q.empty()) { frag_t t = q.back(); q.pop_back(); int nb = get_split(t); if (nb) t.split(nb, q); // queue up children else ls.push_front(t); // not spit, it's a leaf. } } /** * get_branch -- get branch point at OR above frag @a x * - may be @a x itself, if @a x is a split * - may be root (frag_t()) */ frag_t get_branch(frag_t x) const { while (1) { if (x == frag_t()) return x; // root if (get_split(x)) return x; // found it! x = x.parent(); } } /** * get_branch_above -- get a branch point above frag @a x * - may be root (frag_t()) * - may NOT be @a x, even if @a x is a split. */ frag_t get_branch_above(frag_t x) const { while (1) { if (x == frag_t()) return x; // root x = x.parent(); if (get_split(x)) return x; // found it! } } /** * get_branch_or_leaf -- get branch or leaf point parent for frag @a x * - may be @a x itself, if @a x is a split or leaf * - may be root (frag_t()) */ frag_t get_branch_or_leaf(frag_t x) const { frag_t branch = get_branch(x); int nb = get_split(branch); if (nb > 0 && // if branch is a split, and branch.bits() + nb <= x.bits()) // one of the children is or contains x return frag_t(x.value(), branch.bits()+nb); // then return that child (it's a leaf) else return branch; } /** * get_leaves_under(x, ls) -- search for any leaves fully contained by x */ void get_leaves_under(frag_t x, std::list& ls) const { std::list q; q.push_back(get_branch_or_leaf(x)); while (!q.empty()) { frag_t t = q.front(); q.pop_front(); if (t.bits() >= x.bits() && // if t is more specific than x, and !x.contains(t)) // x does not contain t, continue; // then skip int nb = get_split(t); if (nb) t.split(nb, q); // queue up children else if (x.contains(t)) ls.push_back(t); // not spit, it's a leaf. } } /** * contains(fg) -- does fragtree contain the specific frag @a x */ bool contains(frag_t x) const { std::list q; q.push_back(get_branch(x)); while (!q.empty()) { frag_t t = q.front(); q.pop_front(); if (t.bits() >= x.bits() && // if t is more specific than x, and !x.contains(t)) // x does not contain t, continue; // then skip int nb = get_split(t); if (nb) { if (t == x) return false; // it's split. t.split(nb, q); // queue up children } else { if (t == x) return true; // it's there. } } return false; } /** * operator[] -- map a (hash?) value to a frag */ frag_t operator[](unsigned v) const { frag_t t; while (1) { assert(t.contains(v)); int nb = get_split(t); // is this a leaf? if (nb == 0) return t; // done. // pick appropriate child fragment. unsigned nway = 1 << nb; unsigned i; for (i=0; i children; x.split(nb, children); int childbits = 0; for (std::list::iterator p = children.begin(); p != children.end(); ++p) { int cb = get_split(*p); if (!cb) return; // nope. if (childbits && cb != childbits) return; // not the same childbits = cb; } // all children are split with childbits! for (std::list::iterator p = children.begin(); p != children.end(); ++p) _splits.erase(*p); _splits[x] += childbits; } bool force_to_leaf(CephContext *cct, frag_t x) { if (is_leaf(x)) return false; lgeneric_dout(cct, 10) << "force_to_leaf " << x << " on " << _splits << dendl; frag_t parent = get_branch_or_leaf(x); assert(parent.bits() <= x.bits()); lgeneric_dout(cct, 10) << "parent is " << parent << dendl; // do we need to split from parent to x? if (parent.bits() < x.bits()) { int spread = x.bits() - parent.bits(); int nb = get_split(parent); lgeneric_dout(cct, 10) << "spread " << spread << ", parent splits by " << nb << dendl; if (nb == 0) { // easy: split parent (a leaf) by the difference lgeneric_dout(cct, 10) << "splitting parent " << parent << " by spread " << spread << dendl; split(parent, spread); assert(is_leaf(x)); return true; } assert(nb > spread); // add an intermediary split merge(parent, nb, false); split(parent, spread, false); std::list subs; parent.split(spread, subs); for (std::list::iterator p = subs.begin(); p != subs.end(); ++p) { lgeneric_dout(cct, 10) << "splitting intermediate " << *p << " by " << (nb-spread) << dendl; split(*p, nb - spread, false); } } // x is now a leaf or split. // hoover up any children. std::list q; q.push_back(x); while (!q.empty()) { frag_t t = q.front(); q.pop_front(); int nb = get_split(t); if (nb) { lgeneric_dout(cct, 10) << "merging child " << t << " by " << nb << dendl; merge(t, nb, false); // merge this point, and t.split(nb, q); // queue up children } } lgeneric_dout(cct, 10) << "force_to_leaf done" << dendl; assert(is_leaf(x)); return true; } // verify that we describe a legal partition of the namespace. void verify() const { std::map copy; std::list q; q.push_back(frag_t()); while (1) { frag_t cur = q.front(); q.pop_front(); int b = get_split(cur); if (!b) continue; copy[cur] = b; cur.split(b, q); } assert(copy == _splits); } // encoding void encode(bufferlist& bl) const { ::encode(_splits, bl); } void decode(bufferlist::iterator& p) { ::decode(_splits, p); } void print(std::ostream& out) { out << "fragtree_t("; std::list q; q.push_back(frag_t()); while (!q.empty()) { frag_t t = q.front(); q.pop_front(); // newline + indent? if (t.bits()) { out << std::endl; for (unsigned i=0; i q; q.push_back(frag_t()); while (!q.empty()) { frag_t t = q.front(); q.pop_front(); int nb = ft.get_split(t); if (nb) { if (t.bits()) out << ' '; out << t << '%' << nb; t.split(nb, q); // queue up children } } } if (0) { std::list leaves; ft.get_leaves(leaves); out << leaves; } if (1) { for (std::map::const_iterator p = ft._splits.begin(); p != ft._splits.end(); p++) { if (p != ft._splits.begin()) out << " "; out << p->first << "^" << p->second; } } return out << ")"; } /** * fragset_t -- a set of fragments */ class fragset_t { std::set _set; public: const std::set &get() const { return _set; } std::set::iterator begin() { return _set.begin(); } std::set::iterator end() { return _set.end(); } bool empty() const { return _set.empty(); } bool contains(frag_t f) const { while (1) { if (_set.count(f)) return true; if (f.bits() == 0) return false; f = f.parent(); } } void insert(frag_t f) { _set.insert(f); simplify(); } void simplify() { while (1) { bool clean = true; std::set::iterator p = _set.begin(); while (p != _set.end()) { if (!p->is_root() && _set.count(p->get_sibling())) { _set.erase(p->get_sibling()); _set.insert(p->parent()); _set.erase(p++); clean = false; } else { p++; } } if (clean) break; } } }; inline std::ostream& operator<<(std::ostream& out, const fragset_t& fs) { return out << "fragset_t(" << fs.get() << ")"; } #endif ceph-0.80.11/src/include/Distribution.h0000664000175100017510000000262212623076744021741 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DISTRIBUTION_H #define CEPH_DISTRIBUTION_H #include using namespace std; class Distribution { vector p; vector v; public: //Distribution() { //} unsigned get_width() { return p.size(); } void clear() { p.clear(); v.clear(); } void add(int val, float pr) { p.push_back(pr); v.push_back(val); } void random() { float sum = 0.0; for (unsigned i=0; i * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRADOS_H #define CEPH_LIBRADOS_H #ifdef __cplusplus extern "C" { #endif #include #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif #include #include "rados_types.h" #include #ifndef CEPH_OSD_TMAP_SET /* These are also defined in rados.h and objclass.h. Keep them in sync! */ #define CEPH_OSD_TMAP_HDR 'h' #define CEPH_OSD_TMAP_SET 's' #define CEPH_OSD_TMAP_CREATE 'c' #define CEPH_OSD_TMAP_RM 'r' #endif #define LIBRADOS_VER_MAJOR 0 #define LIBRADOS_VER_MINOR 69 #define LIBRADOS_VER_EXTRA 0 #define LIBRADOS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra) #define LIBRADOS_VERSION_CODE LIBRADOS_VERSION(LIBRADOS_VER_MAJOR, LIBRADOS_VER_MINOR, LIBRADOS_VER_EXTRA) #define LIBRADOS_SUPPORTS_WATCH 1 /* RADOS lock flags * They are also defined in cls_lock_types.h. Keep them in sync! */ #define LIBRADOS_LOCK_FLAG_RENEW 0x1 /* * Constants for rados_write_op_create(). */ #define LIBRADOS_CREATE_EXCLUSIVE 1 #define LIBRADOS_CREATE_IDEMPOTENT 0 /* * Flags that can be set on a per-op basis via * rados_read_op_set_flags() and rados_write_op_set_flags(). */ // fail a create operation if the object already exists #define LIBRADOS_OP_FLAG_EXCL 1 // allow the transaction to succeed even if the flagged op fails #define LIBRADOS_OP_FLAG_FAILOK 2 /** * @defgroup librados_h_xattr_comp xattr comparison operations * Operators for comparing xattrs on objects, and aborting the * rados_read_op or rados_write_op transaction if the comparison * fails. * * @{ */ /** @cond TODO_enums_not_yet_in_asphyxiate */ enum { LIBRADOS_CMPXATTR_OP_EQ = 1, LIBRADOS_CMPXATTR_OP_NE = 2, LIBRADOS_CMPXATTR_OP_GT = 3, LIBRADOS_CMPXATTR_OP_GTE = 4, LIBRADOS_CMPXATTR_OP_LT = 5, LIBRADOS_CMPXATTR_OP_LTE = 6 }; /** @endcond */ /** @} */ /** * @defgroup librados_h_operation_flags * Flags for rados_read_op_opeprate(), rados_write_op_operate(), * rados_aio_read_op_operate(), and rados_aio_write_op_operate(). * See librados.hpp for details. * @{ */ /** @cond TODO_enums_not_yet_in_asphyxiate */ enum { LIBRADOS_OPERATION_NOFLAG = 0, LIBRADOS_OPERATION_BALANCE_READS = 1, LIBRADOS_OPERATION_LOCALIZE_READS = 2, LIBRADOS_OPERATION_ORDER_READS_WRITES = 4, LIBRADOS_OPERATION_IGNORE_CACHE = 8, LIBRADOS_OPERATION_SKIPRWLOCKS = 16, LIBRADOS_OPERATION_IGNORE_OVERLAY = 32, }; /** @endcond */ /** @} */ /* * snap id contants */ #define LIBRADOS_SNAP_HEAD ((uint64_t)(-2)) #define LIBRADOS_SNAP_DIR ((uint64_t)(-1)) /** * @typedef rados_t * * A handle for interacting with a RADOS cluster. It encapsulates all * RADOS client configuration, including username, key for * authentication, logging, and debugging. Talking different clusters * -- or to the same cluster with different users -- requires * different cluster handles. */ typedef void *rados_t; /** * @tyepdef rados_config_t * * A handle for the ceph configuration context for the rados_t cluster * instance. This can be used to share configuration context/state * (e.g., logging configuration) between librados instance. * * @warning The config context does not have independent reference * counting. As such, a rados_config_t handle retrieved from a given * rados_t is only valid as long as that rados_t. */ typedef void *rados_config_t; /** * @typedef rados_ioctx_t * * An io context encapsulates a few settings for all I/O operations * done on it: * - pool - set when the io context is created (see rados_ioctx_create()) * - snapshot context for writes (see * rados_ioctx_selfmanaged_snap_set_write_ctx()) * - snapshot id to read from (see rados_ioctx_snap_set_read()) * - object locator for all single-object operations (see * rados_ioctx_locator_set_key()) * * @warning changing any of these settings is not thread-safe - * librados users must synchronize any of these changes on their own, * or use separate io contexts for each thread */ typedef void *rados_ioctx_t; /** * @typedef rados_list_ctx_t * * An iterator for listing the objects in a pool. * Used with rados_objects_list_open(), * rados_objects_list_next(), and * rados_objects_list_close(). */ typedef void *rados_list_ctx_t; /** * @typedef rados_snap_t * The id of a snapshot. */ typedef uint64_t rados_snap_t; /** * @typedef rados_xattrs_iter_t * An iterator for listing extended attrbutes on an object. * Used with rados_getxattrs(), rados_getxattrs_next(), and * rados_getxattrs_end(). */ typedef void *rados_xattrs_iter_t; /** * @typedef rados_omap_iter_t * An iterator for listing omap key/value pairs on an object. * Used with rados_read_op_omap_get_keys(), rados_read_op_omap_get_vals(), * rados_read_op_omap_get_vals_by_keys(), rados_omap_get_next(), and * rados_omap_get_end(). */ typedef void *rados_omap_iter_t; /** * @struct rados_pool_stat_t * Usage information for a pool. */ struct rados_pool_stat_t { /// space used in bytes uint64_t num_bytes; /// space used in KB uint64_t num_kb; /// number of objects in the pool uint64_t num_objects; /// number of clones of objects uint64_t num_object_clones; /// num_objects * num_replicas uint64_t num_object_copies; uint64_t num_objects_missing_on_primary; /// number of objects found on no OSDs uint64_t num_objects_unfound; /// number of objects replicated fewer times than they should be /// (but found on at least one OSD) uint64_t num_objects_degraded; uint64_t num_rd; uint64_t num_rd_kb; uint64_t num_wr; uint64_t num_wr_kb; }; /** * @struct rados_cluster_stat_t * Cluster-wide usage information */ struct rados_cluster_stat_t { uint64_t kb, kb_used, kb_avail; uint64_t num_objects; }; /** * @typedef rados_write_op_t * * An object write operation stores a number of operations which can be * executed atomically. For usage, see: * - Creation and deletion: rados_create_write_op() rados_release_write_op() * - Extended attribute manipulation: rados_write_op_cmpxattr() * rados_write_op_cmpxattr(), rados_write_op_setxattr(), * rados_write_op_rmxattr() * - Object map key/value pairs: rados_write_op_omap_set(), * rados_write_op_omap_rm_keys(), rados_write_op_omap_clear(), * rados_write_op_omap_cmp() * - Creating objects: rados_write_op_create() * - IO on objects: rados_write_op_append(), rados_write_op_write(), rados_write_op_zero * rados_write_op_write_full(), rados_write_op_remove, rados_write_op_truncate(), * rados_write_op_zero() * - Hints: rados_write_op_set_alloc_hint() * - Performing the operation: rados_write_op_operate(), rados_aio_write_op_operate() */ typedef void *rados_write_op_t; /** * @typedef rados_read_op_t * * An object read operation stores a number of operations which can be * executed atomically. For usage, see: * - Creation and deletion: rados_create_read_op() rados_release_read_op() * - Extended attribute manipulation: rados_read_op_cmpxattr(), * rados_read_op_getxattr(), rados_read_op_getxattrs() * - Object map key/value pairs: rados_read_op_omap_get_vals(), * rados_read_op_omap_get_keys(), rados_read_op_omap_get_vals_by_keys(), * rados_read_op_omap_cmp() * - Object properties: rados_read_op_stat(), rados_read_op_assert_exists() * - IO on objects: rados_read_op_read() * - Custom operations: rados_read_op_exec(), rados_read_op_exec_user_buf() * - Request properties: rados_read_op_set_flags() * - Performing the operation: rados_read_op_operate(), * rados_aio_read_op_operate() */ typedef void *rados_read_op_t; /** * Get the version of librados. * * The version number is major.minor.extra. Note that this is * unrelated to the Ceph version number. * * TODO: define version semantics, i.e.: * - incrementing major is for backwards-incompatible changes * - incrementing minor is for backwards-compatible changes * - incrementing extra is for bug fixes * * @param major where to store the major version number * @param minor where to store the minor version number * @param extra where to store the extra version number */ void rados_version(int *major, int *minor, int *extra); /** * @defgroup librados_h_init Setup and Teardown * These are the first and last functions to that should be called * when using librados. * * @{ */ /** * Create a handle for communicating with a RADOS cluster. * * Ceph environment variables are read when this is called, so if * $CEPH_ARGS specifies everything you need to connect, no further * configuration is necessary. * * @param cluster where to store the handle * @param id the user to connect as (i.e. admin, not client.admin) * @returns 0 on success, negative error code on failure */ int rados_create(rados_t *cluster, const char * const id); /** * Extended version of rados_create. * * Like rados_create, but * 1) don't assume 'client\.'+id; allow full specification of name * 2) allow specification of cluster name * 3) flags for future expansion */ int rados_create2(rados_t *pcluster, const char *const clustername, const char * const name, uint64_t flags); /** * Initialize a cluster handle from an existing configuration. * * Share configuration state with another rados_t instance. * * @param cluster where to store the handle * @param cct_ the existing configuration to use * @returns 0 on success, negative error code on failure */ int rados_create_with_context(rados_t *cluster, rados_config_t cct); /** * Ping the monitor with ID @p mon_id, storing the resulting reply in * @p buf (if specified) with a maximum size of @p len. * * The result buffer is allocated on the heap; the caller is * expected to release that memory with rados_buffer_free(). The * buffer and length pointers can be NULL, in which case they are * not filled in. * * @param cluster cluster handle * @param[in] mon_id ID of the monitor to ping * @param[out] outstr double pointer with the resulting reply * @param[out] outstrlen pointer with the size of the reply in @p outstr */ int rados_ping_monitor(rados_t cluster, const char *mon_id, char **outstr, size_t *outstrlen); /** * Connect to the cluster. * * @note BUG: Before calling this, calling a function that communicates with the * cluster will crash. * * @pre The cluster handle is configured with at least a monitor * address. If cephx is enabled, a client name and secret must also be * set. * * @post If this succeeds, any function in librados may be used * * @param cluster The cluster to connect to. * @returns 0 on sucess, negative error code on failure */ int rados_connect(rados_t cluster); /** * Disconnects from the cluster. * * For clean up, this is only necessary after rados_connect() has * succeeded. * * @warning This does not guarantee any asynchronous writes have * completed. To do that, you must call rados_aio_flush() on all open * io contexts. * * @post the cluster handle cannot be used again * * @param cluster the cluster to shutdown */ void rados_shutdown(rados_t cluster); /** @} init */ /** * @defgroup librados_h_config Configuration * These functions read and update Ceph configuration for a cluster * handle. Any configuration changes must be done before connecting to * the cluster. * * Options that librados users might want to set include: * - mon_host * - auth_supported * - key, keyfile, or keyring when using cephx * - log_file, log_to_stderr, err_to_stderr, and log_to_syslog * - debug_rados, debug_objecter, debug_monc, debug_auth, or debug_ms * * All possible options can be found in src/common/config_opts.h in ceph.git * * @{ */ /** * Configure the cluster handle using a Ceph config file * * If path is NULL, the default locations are searched, and the first * found is used. The locations are: * - $CEPH_CONF (environment variable) * - /etc/ceph/ceph.conf * - ~/.ceph/config * - ceph.conf (in the current working directory) * * @pre rados_connect() has not been called on the cluster handle * * @param cluster cluster handle to configure * @param path path to a Ceph configuration file * @returns 0 on success, negative error code on failure */ int rados_conf_read_file(rados_t cluster, const char *path); /** * Configure the cluster handle with command line arguments * * argv can contain any common Ceph command line option, including any * configuration parameter prefixed by '--' and replacing spaces with * dashes or underscores. For example, the following options are equivalent: * - --mon-host 10.0.0.1:6789 * - --mon_host 10.0.0.1:6789 * - -m 10.0.0.1:6789 * * @pre rados_connect() has not been called on the cluster handle * * @param cluster cluster handle to configure * @param argc number of arguments in argv * @param argv arguments to parse * @returns 0 on success, negative error code on failure */ int rados_conf_parse_argv(rados_t cluster, int argc, const char **argv); /** * Configure the cluster handle with command line arguments, returning * any remainders. Same rados_conf_parse_argv, except for extra * remargv argument to hold returns unrecognized arguments. * * @pre rados_connect() has not been called on the cluster handle * * @param cluster cluster handle to configure * @param argc number of arguments in argv * @param argv arguments to parse * @param remargv char* array for returned unrecognized arguments * @returns 0 on success, negative error code on failure */ int rados_conf_parse_argv_remainder(rados_t cluster, int argc, const char **argv, const char **remargv); /** * Configure the cluster handle based on an environment variable * * The contents of the environment variable are parsed as if they were * Ceph command line options. If var is NULL, the CEPH_ARGS * environment variable is used. * * @pre rados_connect() has not been called on the cluster handle * * @note BUG: this is not threadsafe - it uses a static buffer * * @param cluster cluster handle to configure * @param var name of the environment variable to read * @returns 0 on success, negative error code on failure */ int rados_conf_parse_env(rados_t cluster, const char *var); /** * Set a configuration option * * @pre rados_connect() has not been called on the cluster handle * * @param cluster cluster handle to configure * @param option option to set * @param value value of the option * @returns 0 on success, negative error code on failure * @returns -ENOENT when the option is not a Ceph configuration option */ int rados_conf_set(rados_t cluster, const char *option, const char *value); /** * Get the value of a configuration option * * @param cluster configuration to read * @param option which option to read * @param buf where to write the configuration value * @param len the size of buf in bytes * @returns 0 on success, negative error code on failure * @returns -ENAMETOOLONG if the buffer is too short to contain the * requested value */ int rados_conf_get(rados_t cluster, const char *option, char *buf, size_t len); /** @} config */ /** * Read usage info about the cluster * * This tells you total space, space used, space available, and number * of objects. These are not updated immediately when data is written, * they are eventually consistent. * * @param cluster cluster to query * @param result where to store the results * @returns 0 on success, negative error code on failure */ int rados_cluster_stat(rados_t cluster, struct rados_cluster_stat_t *result); /** * Get the fsid of the cluster as a hexadecimal string. * * The fsid is a unique id of an entire Ceph cluster. * * @param cluster where to get the fsid * @param buf where to write the fsid * @param len the size of buf in bytes (should be 37) * @returns 0 on success, negative error code on failure * @returns -ERANGE if the buffer is too short to contain the * fsid */ int rados_cluster_fsid(rados_t cluster, char *buf, size_t len); /** * Get/wait for the most recent osdmap * * @param cluster the cluster to shutdown * @returns 0 on sucess, negative error code on failure */ int rados_wait_for_latest_osdmap(rados_t cluster); /** * @defgroup librados_h_pools Pools * * RADOS pools are separate namespaces for objects. Pools may have * different crush rules associated with them, so they could have * differing replication levels or placement strategies. RADOS * permissions are also tied to pools - users can have different read, * write, and execute permissions on a per-pool basis. * * @{ */ /** * List pools * * Gets a list of pool names as NULL-terminated strings. The pool * names will be placed in the supplied buffer one after another. * After the last pool name, there will be two 0 bytes in a row. * * If len is too short to fit all the pool name entries we need, we will fill * as much as we can. * * @param cluster cluster handle * @param buf output buffer * @param len output buffer length * @returns length of the buffer we would need to list all pools */ int rados_pool_list(rados_t cluster, char *buf, size_t len); /** * Get a configuration handle for a rados cluster handle * * This handle is valid only as long as the cluster handle is valid. * * @param cluster cluster handle * @returns config handle for this cluster */ rados_config_t rados_cct(rados_t cluster); /** * Get a global id for current instance * * This id is a unique representation of current connection to the cluster * * @param cluster cluster handle * @returns instance global id */ uint64_t rados_get_instance_id(rados_t cluster); /** * Create an io context * * The io context allows you to perform operations within a particular * pool. For more details see rados_ioctx_t. * * @param cluster which cluster the pool is in * @param pool_name name of the pool * @param ioctx where to store the io context * @returns 0 on success, negative error code on failure */ int rados_ioctx_create(rados_t cluster, const char *pool_name, rados_ioctx_t *ioctx); /** * The opposite of rados_ioctx_create * * This just tells librados that you no longer need to use the io context. * It may not be freed immediately if there are pending asynchronous * requests on it, but you should not use an io context again after * calling this function on it. * * @warning This does not guarantee any asynchronous * writes have completed. You must call rados_aio_flush() * on the io context before destroying it to do that. * * @param io the io context to dispose of */ void rados_ioctx_destroy(rados_ioctx_t io); /** * Get configuration hadnle for a pool handle * * @param io pool handle * @returns rados_config_t for this cluster */ rados_config_t rados_ioctx_cct(rados_ioctx_t io); /** * Get the cluster handle used by this rados_ioctx_t * Note that this is a weak reference, and should not * be destroyed via rados_destroy(). * * @param io the io context * @returns the cluster handle for this io context */ rados_t rados_ioctx_get_cluster(rados_ioctx_t io); /** * Get pool usage statistics * * Fills in a rados_pool_stat_t after querying the cluster. * * @param io determines which pool to query * @param stats where to store the results * @returns 0 on success, negative error code on failure */ int rados_ioctx_pool_stat(rados_ioctx_t io, struct rados_pool_stat_t *stats); /** * Get the id of a pool * * @param cluster which cluster the pool is in * @param pool_name which pool to look up * @returns id of the pool * @returns -ENOENT if the pool is not found */ int64_t rados_pool_lookup(rados_t cluster, const char *pool_name); /** * Get the name of a pool * * @param cluster which cluster the pool is in * @param id the id of the pool * @param buf where to store the pool name * @param maxlen size of buffer where name will be stored * @returns length of string stored, or -ERANGE if buffer too small */ int rados_pool_reverse_lookup(rados_t cluster, int64_t id, char *buf, size_t maxlen); /** * Create a pool with default settings * * The default owner is the admin user (auid 0). * The default crush rule is rule 0. * * @param cluster the cluster in which the pool will be created * @param pool_name the name of the new pool * @returns 0 on success, negative error code on failure */ int rados_pool_create(rados_t cluster, const char *pool_name); /** * Create a pool owned by a specific auid * * The auid is the authenticated user id to give ownership of the pool. * TODO: document auid and the rest of the auth system * * @param cluster the cluster in which the pool will be created * @param pool_name the name of the new pool * @param auid the id of the owner of the new pool * @returns 0 on success, negative error code on failure */ int rados_pool_create_with_auid(rados_t cluster, const char *pool_name, uint64_t auid); /** * Create a pool with a specific CRUSH rule * * @param cluster the cluster in which the pool will be created * @param pool_name the name of the new pool * @param crush_rule_num which rule to use for placement in the new pool1 * @returns 0 on success, negative error code on failure */ int rados_pool_create_with_crush_rule(rados_t cluster, const char *pool_name, uint8_t crush_rule_num); /** * Create a pool with a specific CRUSH rule and auid * * This is a combination of rados_pool_create_with_crush_rule() and * rados_pool_create_with_auid(). * * @param cluster the cluster in which the pool will be created * @param pool_name the name of the new pool * @param crush_rule_num which rule to use for placement in the new pool2 * @param auid the id of the owner of the new pool * @returns 0 on success, negative error code on failure */ int rados_pool_create_with_all(rados_t cluster, const char *pool_name, uint64_t auid, uint8_t crush_rule_num); /** * Delete a pool and all data inside it * * The pool is removed from the cluster immediately, * but the actual data is deleted in the background. * * @param cluster the cluster the pool is in * @param pool_name which pool to delete * @returns 0 on success, negative error code on failure */ int rados_pool_delete(rados_t cluster, const char *pool_name); /** * Attempt to change an io context's associated auid "owner." * * Requires that you have write permission on both the current and new * auid. * * @param io reference to the pool to change. * @param auid the auid you wish the io to have. * @returns 0 on success, negative error code on failure */ int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid); /** * Get the auid of a pool * * @param io pool to query * @param auid where to store the auid * @returns 0 on success, negative error code on failure */ int rados_ioctx_pool_get_auid(rados_ioctx_t io, uint64_t *auid); int rados_ioctx_pool_requires_alignment(rados_ioctx_t io); uint64_t rados_ioctx_pool_required_alignment(rados_ioctx_t io); /** * Get the pool id of the io context * * @param io the io context to query * @returns the id of the pool the io context uses */ int64_t rados_ioctx_get_id(rados_ioctx_t io); /** * Get the pool name of the io context * * @param io the io context to query * @param buf pointer to buffer where name will be stored * @param maxlen size of buffer where name will be stored * @returns length of string stored, or -ERANGE if buffer too small */ int rados_ioctx_get_pool_name(rados_ioctx_t io, char *buf, unsigned maxlen); /** @} pools */ /** * @defgroup librados_h_obj_loc Object Locators * * @{ */ /** * Set the key for mapping objects to pgs within an io context. * * The key is used instead of the object name to determine which * placement groups an object is put in. This affects all subsequent * operations of the io context - until a different locator key is * set, all objects in this io context will be placed in the same pg. * * This is useful if you need to do clone_range operations, which must * be done with the source and destination objects in the same pg. * * @param io the io context to change * @param key the key to use as the object locator, or NULL to discard * any previously set key */ void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key); /** * Set the namespace for objects within an io context * * The namespace specification further refines a pool into different * domains. The mapping of objects to pgs is also based on this * value. * * @param io the io context to change * @param nspace the name to use as the namespace, or NULL use the * default namespace */ void rados_ioctx_set_namespace(rados_ioctx_t io, const char *nspace); /** @} obj_loc */ /** * @defgroup librados_h_list_obj Listing Objects * @{ */ /** * Start listing objects in a pool * * @param io the pool to list from * @param ctx the handle to store list context in * @returns 0 on success, negative error code on failure */ int rados_objects_list_open(rados_ioctx_t io, rados_list_ctx_t *ctx); /** * Return hash position of iterator, rounded to the current PG * * @param ctx iterator marking where you are in the listing * @returns current hash position, rounded to the current pg */ uint32_t rados_objects_list_get_pg_hash_position(rados_list_ctx_t ctx); /** * Reposition object iterator to a different hash position * * @param ctx iterator marking where you are in the listing * @param pos hash position to move to * @returns actual (rounded) position we moved to */ uint32_t rados_objects_list_seek(rados_list_ctx_t ctx, uint32_t pos); /** * Get the next object name and locator in the pool * * *entry and *key are valid until next call to rados_objects_list_* * * @param ctx iterator marking where you are in the listing * @param entry where to store the name of the entry * @param key where to store the object locator (set to NULL to ignore) * @returns 0 on success, negative error code on failure * @returns -ENOENT when there are no more objects to list */ int rados_objects_list_next(rados_list_ctx_t ctx, const char **entry, const char **key); /** * Close the object listing handle. * * This should be called when the handle is no longer needed. * The handle should not be used after it has been closed. * * @param ctx the handle to close */ void rados_objects_list_close(rados_list_ctx_t ctx); /** @} Listing Objects */ /** * @defgroup librados_h_snaps Snapshots * * RADOS snapshots are based upon sequence numbers that form a * snapshot context. They are pool-specific. The snapshot context * consists of the current snapshot sequence number for a pool, and an * array of sequence numbers at which snapshots were taken, in * descending order. Whenever a snapshot is created or deleted, the * snapshot sequence number for the pool is increased. To add a new * snapshot, the new snapshot sequence number must be increased and * added to the snapshot context. * * There are two ways to manage these snapshot contexts: * -# within the RADOS cluster * These are called pool snapshots, and store the snapshot context * in the OSDMap. These represent a snapshot of all the objects in * a pool. * -# within the RADOS clients * These are called self-managed snapshots, and push the * responsibility for keeping track of the snapshot context to the * clients. For every write, the client must send the snapshot * context. In librados, this is accomplished with * rados_selfmanaged_snap_set_write_ctx(). These are more * difficult to manage, but are restricted to specific objects * instead of applying to an entire pool. * * @{ */ /** * Create a pool-wide snapshot * * @param io the pool to snapshot * @param snapname the name of the snapshot * @returns 0 on success, negative error code on failure */ int rados_ioctx_snap_create(rados_ioctx_t io, const char *snapname); /** * Delete a pool snapshot * * @param io the pool to delete the snapshot from * @param snapname which snapshot to delete * @returns 0 on success, negative error code on failure */ int rados_ioctx_snap_remove(rados_ioctx_t io, const char *snapname); /** * Rollback an object to a pool snapshot * * The contents of the object will be the same as * when the snapshot was taken. * * @param io the pool in which the object is stored * @param oid the name of the object to rollback * @param snapname which snapshot to rollback to * @returns 0 on success, negative error code on failure */ int rados_ioctx_snap_rollback(rados_ioctx_t io, const char *oid, const char *snapname); /** * Rollback an object to a pool snapshot *DEPRECATED* * * Deprecated interface which is not rados_ioctx_snap_rollback() * This function could go away in the future * * @param io the pool in which the object is stored * @param oid the name of the object to rollback * @param snapname which snapshot to rollback to * @returns 0 on success, negative error code on failure */ int rados_rollback(rados_ioctx_t io, const char *oid, const char *snapname); /** * Set the snapshot from which reads are performed. * * Subsequent reads will return data as it was at the time of that * snapshot. * * @param io the io context to change * @param snap the id of the snapshot to set, or LIBRADOS_SNAP_HEAD for no * snapshot (i.e. normal operation) */ void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t snap); /** * Allocate an ID for a self-managed snapshot * * Get a unique ID to put in the snaphot context to create a * snapshot. A clone of an object is not created until a write with * the new snapshot context is completed. * * @param io the pool in which the snapshot will exist * @param snapid where to store the newly allocated snapshot ID * @returns 0 on success, negative error code on failure */ int rados_ioctx_selfmanaged_snap_create(rados_ioctx_t io, rados_snap_t *snapid); /** * Remove a self-managed snapshot * * This increases the snapshot sequence number, which will cause * snapshots to be removed lazily. * * @param io the pool in which the snapshot will exist * @param snapid where to store the newly allocated snapshot ID * @returns 0 on success, negative error code on failure */ int rados_ioctx_selfmanaged_snap_remove(rados_ioctx_t io, rados_snap_t snapid); /** * Rollback an object to a self-managed snapshot * * The contents of the object will be the same as * when the snapshot was taken. * * @param io the pool in which the object is stored * @param oid the name of the object to rollback * @param snapid which snapshot to rollback to * @returns 0 on success, negative error code on failure */ int rados_ioctx_selfmanaged_snap_rollback(rados_ioctx_t io, const char *oid, rados_snap_t snapid); /** * Set the snapshot context for use when writing to objects * * This is stored in the io context, and applies to all future writes. * * @param io the io context to change * @param seq the newest snapshot sequence number for the pool * @param snaps array of snapshots in sorted by descending id * @param num_snaps how many snaphosts are in the snaps array * @returns 0 on success, negative error code on failure * @returns -EINVAL if snaps are not in descending order */ int rados_ioctx_selfmanaged_snap_set_write_ctx(rados_ioctx_t io, rados_snap_t seq, rados_snap_t *snaps, int num_snaps); /** * List all the ids of pool snapshots * * If the output array does not have enough space to fit all the * snapshots, -ERANGE is returned and the caller should retry with a * larger array. * * @param io the pool to read from * @param snaps where to store the results * @param maxlen the number of rados_snap_t that fit in the snaps array * @returns number of snapshots on success, negative error code on failure * @returns -ERANGE is returned if the snaps array is too short */ int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t *snaps, int maxlen); /** * Get the id of a pool snapshot * * @param io the pool to read from * @param name the snapshot to find * @param id where to store the result * @returns 0 on success, negative error code on failure */ int rados_ioctx_snap_lookup(rados_ioctx_t io, const char *name, rados_snap_t *id); /** * Get the name of a pool snapshot * * @param io the pool to read from * @param id the snapshot to find * @param name where to store the result * @param maxlen the size of the name array * @returns 0 on success, negative error code on failure * @returns -ERANGE if the name array is too small */ int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id, char *name, int maxlen); /** * Find when a pool snapshot occurred * * @param io the pool the snapshot was taken in * @param id the snapshot to lookup * @param t where to store the result * @returns 0 on success, negative error code on failure */ int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t *t); /** @} Snapshots */ /** * @defgroup librados_h_synch_io Synchronous I/O * Writes are replicated to a number of OSDs based on the * configuration of the pool they are in. These write functions block * until data is in memory on all replicas of the object they're * writing to - they are equivalent to doing the corresponding * asynchronous write, and the calling * rados_ioctx_wait_for_complete(). For greater data safety, use the * asynchronous functions and rados_aio_wait_for_safe(). * * @{ */ /** * Return the version of the last object read or written to. * * This exposes the internal version number of the last object read or * written via this io context * * @param io the io context to check * @returns last read or written object version */ uint64_t rados_get_last_version(rados_ioctx_t io); /** * Write data to an object * * @note This will never return a positive value not equal to len. * @param io the io context in which the write will occur * @param oid name of the object * @param buf data to write * @param len length of the data, in bytes * @param off byte offset in the object to begin writing at * @returns 0 on success, negative error code on failure */ int rados_write(rados_ioctx_t io, const char *oid, const char *buf, size_t len, uint64_t off); /** * Write an entire object * * The object is filled with the provided data. If the object exists, * it is atomically truncated and then written. * * @param io the io context in which the write will occur * @param oid name of the object * @param buf data to write * @param len length of the data, in bytes * @returns 0 on success, negative error code on failure */ int rados_write_full(rados_ioctx_t io, const char *oid, const char *buf, size_t len); /** * Efficiently copy a portion of one object to another * * If the underlying filesystem on the OSD supports it, this will be a * copy-on-write clone. * * The src and dest objects must be in the same pg. To ensure this, * the io context should have a locator key set (see * rados_ioctx_locator_set_key()). * * @param io the context in which the data is cloned * @param dst the name of the destination object * @param dst_off the offset within the destination object (in bytes) * @param src the name of the source object * @param src_off the offset within the source object (in bytes) * @param len how much data to copy * @returns 0 on success, negative error code on failure */ int rados_clone_range(rados_ioctx_t io, const char *dst, uint64_t dst_off, const char *src, uint64_t src_off, size_t len); /** * Append data to an object * * @param io the context to operate in * @param oid the name of the object * @param buf the data to append * @param len length of buf (in bytes) * @returns 0 on success, negative error code on failure */ int rados_append(rados_ioctx_t io, const char *oid, const char *buf, size_t len); /** * Read data from an object * * The io context determines the snapshot to read from, if any was set * by rados_ioctx_snap_set_read(). * * @param io the context in which to perform the read * @param oid the name of the object to read from * @param buf where to store the results * @param len the number of bytes to read * @param off the offset to start reading from in the object * @returns number of bytes read on success, negative error code on * failure */ int rados_read(rados_ioctx_t io, const char *oid, char *buf, size_t len, uint64_t off); /** * Delete an object * * @note This does not delete any snapshots of the object. * * @param io the pool to delete the object from * @param oid the name of the object to delete * @returns 0 on success, negative error code on failure */ int rados_remove(rados_ioctx_t io, const char *oid); /** * Resize an object * * If this enlarges the object, the new area is logically filled with * zeroes. If this shrinks the object, the excess data is removed. * * @param io the context in which to truncate * @param oid the name of the object * @param size the new size of the object in bytes * @returns 0 on success, negative error code on failure */ int rados_trunc(rados_ioctx_t io, const char *oid, uint64_t size); /** * @defgroup librados_h_xattrs Xattrs * Extended attributes are stored as extended attributes on the files * representing an object on the OSDs. Thus, they have the same * limitations as the underlying filesystem. On ext4, this means that * the total data stored in xattrs cannot exceed 4KB. * * @{ */ /** * Get the value of an extended attribute on an object. * * @param io the context in which the attribute is read * @param o name of the object * @param name which extended attribute to read * @param buf where to store the result * @param len size of buf in bytes * @returns length of xattr value on success, negative error code on failure */ int rados_getxattr(rados_ioctx_t io, const char *o, const char *name, char *buf, size_t len); /** * Set an extended attribute on an object. * * @param io the context in which xattr is set * @param o name of the object * @param name which extended attribute to set * @param buf what to store in the xattr * @param len the number of bytes in buf * @returns 0 on success, negative error code on failure */ int rados_setxattr(rados_ioctx_t io, const char *o, const char *name, const char *buf, size_t len); /** * Delete an extended attribute from an object. * * @param io the context in which to delete the xattr * @param o the name of the object * @param name which xattr to delete * @returns 0 on success, negative error code on failure */ int rados_rmxattr(rados_ioctx_t io, const char *o, const char *name); /** * Start iterating over xattrs on an object. * * @post iter is a valid iterator * * @param io the context in which to list xattrs * @param oid name of the object * @param iter where to store the iterator * @returns 0 on success, negative error code on failure */ int rados_getxattrs(rados_ioctx_t io, const char *oid, rados_xattrs_iter_t *iter); /** * Get the next xattr on the object * * @pre iter is a valid iterator * * @post name is the NULL-terminated name of the next xattr, and val * contains the value of the xattr, which is of length len. If the end * of the list has been reached, name and val are NULL, and len is 0. * * @param iter iterator to advance * @param name where to store the name of the next xattr * @param val where to store the value of the next xattr * @param len the number of bytes in val * @returns 0 on success, negative error code on failure */ int rados_getxattrs_next(rados_xattrs_iter_t iter, const char **name, const char **val, size_t *len); /** * Close the xattr iterator. * * iter should not be used after this is called. * * @param iter the iterator to close */ void rados_getxattrs_end(rados_xattrs_iter_t iter); /** @} Xattrs */ /** * Get the next omap key/value pair on the object * * @pre iter is a valid iterator * * @post key and val are the next key/value pair. key is * null-terminated, and val has length len. If the end of the list has * been reached, key and val are NULL, and len is 0. key and val will * not be accessible after rados_omap_get_end() is called on iter, so * if they are needed after that they should be copied. * * @param iter iterator to advance * @param key where to store the key of the next omap entry * @param val where to store the value of the next omap entry * @param len where to store the number of bytes in val * @returns 0 on success, negative error code on failure */ int rados_omap_get_next(rados_omap_iter_t iter, char **key, char **val, size_t *len); /** * Close the omap iterator. * * iter should not be used after this is called. * * @param iter the iterator to close */ void rados_omap_get_end(rados_omap_iter_t iter); /** * Get object stats (size/mtime) * * TODO: when are these set, and by whom? can they be out of date? * * @param io ioctx * @param o object name * @param psize where to store object size * @param pmtime where to store modification time * @returns 0 on success, negative error code on failure */ int rados_stat(rados_ioctx_t io, const char *o, uint64_t *psize, time_t *pmtime); /** * Update tmap (trivial map) * * Do compound update to a tmap object, inserting or deleting some * number of records. cmdbuf is a series of operation byte * codes, following by command payload. Each command is a single-byte * command code, whose value is one of CEPH_OSD_TMAP_*. * * - update tmap 'header' * - 1 byte = CEPH_OSD_TMAP_HDR * - 4 bytes = data length (little endian) * - N bytes = data * * - insert/update one key/value pair * - 1 byte = CEPH_OSD_TMAP_SET * - 4 bytes = key name length (little endian) * - N bytes = key name * - 4 bytes = data length (little endian) * - M bytes = data * * - insert one key/value pair; return -EEXIST if it already exists. * - 1 byte = CEPH_OSD_TMAP_CREATE * - 4 bytes = key name length (little endian) * - N bytes = key name * - 4 bytes = data length (little endian) * - M bytes = data * * - remove one key/value pair * - 1 byte = CEPH_OSD_TMAP_RM * - 4 bytes = key name length (little endian) * - N bytes = key name * * Restrictions: * - The HDR update must preceed any key/value updates. * - All key/value updates must be in lexicographically sorted order * in cmdbuf. * - You can read/write to a tmap object via the regular APIs, but * you should be careful not to corrupt it. Also be aware that the * object format may change without notice. * * @param io ioctx * @param o object name * @param cmdbuf command buffer * @param cmdbuflen command buffer length in bytes * @returns 0 on success, negative error code on failure */ int rados_tmap_update(rados_ioctx_t io, const char *o, const char *cmdbuf, size_t cmdbuflen); /** * Store complete tmap (trivial map) object * * Put a full tmap object into the store, replacing what was there. * * The format of buf is: * - 4 bytes - length of header (little endian) * - N bytes - header data * - 4 bytes - number of keys (little endian) * * and for each key, * - 4 bytes - key name length (little endian) * - N bytes - key name * - 4 bytes - value length (little endian) * - M bytes - value data * * @param io ioctx * @param o object name * @param buf buffer * @param buflen buffer length in bytes * @returns 0 on success, negative error code on failure */ int rados_tmap_put(rados_ioctx_t io, const char *o, const char *buf, size_t buflen); /** * Fetch complete tmap (trivial map) object * * Read a full tmap object. See rados_tmap_put() for the format the * data is returned in. * * @param io ioctx * @param o object name * @param buf buffer * @param buflen buffer length in bytes * @returns 0 on success, negative error code on failure * @returns -ERANGE if buf isn't big enough */ int rados_tmap_get(rados_ioctx_t io, const char *o, char *buf, size_t buflen); /** * Execute an OSD class method on an object * * The OSD has a plugin mechanism for performing complicated * operations on an object atomically. These plugins are called * classes. This function allows librados users to call the custom * methods. The input and output formats are defined by the class. * Classes in ceph.git can be found in src/cls subdirectories * * @param io the context in which to call the method * @param oid the object to call the method on * @param cls the name of the class * @param method the name of the method * @param in_buf where to find input * @param in_len length of in_buf in bytes * @param buf where to store output * @param out_len length of buf in bytes * @returns the length of the output, or * -ERANGE if out_buf does not have enough space to store it (For methods that return data). For * methods that don't return data, the return value is * method-specific. */ int rados_exec(rados_ioctx_t io, const char *oid, const char *cls, const char *method, const char *in_buf, size_t in_len, char *buf, size_t out_len); /** @} Synchronous I/O */ /** * @defgroup librados_h_asynch_io Asynchronous I/O * Read and write to objects without blocking. * * @{ */ /** * @typedef rados_completion_t * Represents the state of an asynchronous operation - it contains the * return value once the operation completes, and can be used to block * until the operation is complete or safe. */ typedef void *rados_completion_t; /** * @typedef rados_callback_t * Callbacks for asynchrous operations take two parameters: * - cb the completion that has finished * - arg application defined data made available to the callback function */ typedef void (*rados_callback_t)(rados_completion_t cb, void *arg); /** * Constructs a completion to use with asynchronous operations * * The complete and safe callbacks correspond to operations being * acked and committed, respectively. The callbacks are called in * order of receipt, so the safe callback may be triggered before the * complete callback, and vice versa. This is affected by journalling * on the OSDs. * * TODO: more complete documentation of this elsewhere (in the RADOS docs?) * * @note Read operations only get a complete callback. * @note BUG: this should check for ENOMEM instead of throwing an exception * * @param cb_arg application-defined data passed to the callback functions * @param cb_complete the function to be called when the operation is * in memory on all relpicas * @param cb_safe the function to be called when the operation is on * stable storage on all replicas * @param pc where to store the completion * @returns 0 */ int rados_aio_create_completion(void *cb_arg, rados_callback_t cb_complete, rados_callback_t cb_safe, rados_completion_t *pc); /** * Block until an operation completes * * This means it is in memory on all replicas. * * @note BUG: this should be void * * @param c operation to wait for * @returns 0 */ int rados_aio_wait_for_complete(rados_completion_t c); /** * Block until an operation is safe * * This means it is on stable storage on all replicas. * * @note BUG: this should be void * * @param c operation to wait for * @returns 0 */ int rados_aio_wait_for_safe(rados_completion_t c); /** * Has an asynchronous operation completed? * * @warning This does not imply that the complete callback has * finished * * @param c async operation to inspect * @returns whether c is complete */ int rados_aio_is_complete(rados_completion_t c); /** * Is an asynchronous operation safe? * * @warning This does not imply that the safe callback has * finished * * @param c async operation to inspect * @returns whether c is safe */ int rados_aio_is_safe(rados_completion_t c); /** * Block until an operation completes and callback completes * * This means it is in memory on all replicas and can be read. * * @note BUG: this should be void * * @param c operation to wait for * @returns 0 */ int rados_aio_wait_for_complete_and_cb(rados_completion_t c); /** * Block until an operation is safe and callback has completed * * This means it is on stable storage on all replicas. * * @note BUG: this should be void * * @param c operation to wait for * @returns 0 */ int rados_aio_wait_for_safe_and_cb(rados_completion_t c); /** * Has an asynchronous operation and callback completed * * @param c async operation to inspect * @returns whether c is complete */ int rados_aio_is_complete_and_cb(rados_completion_t c); /** * Is an asynchronous operation safe and has the callback completed * * @param c async operation to inspect * @returns whether c is safe */ int rados_aio_is_safe_and_cb(rados_completion_t c); /** * Get the return value of an asychronous operation * * The return value is set when the operation is complete or safe, * whichever comes first. * * @pre The operation is safe or complete * * @note BUG: complete callback may never be called when the safe * message is received before the complete message * * @param c async operation to inspect * @returns return value of the operation */ int rados_aio_get_return_value(rados_completion_t c); /** * Release a completion * * Call this when you no longer need the completion. It may not be * freed immediately if the operation is not acked and committed. * * @param c completion to release */ void rados_aio_release(rados_completion_t c); /** * Write data to an object asynchronously * * Queues the write and returns. The return value of the completion * will be 0 on success, negative error code on failure. * * @param io the context in which the write will occur * @param oid name of the object * @param completion what to do when the write is safe and complete * @param buf data to write * @param len length of the data, in bytes * @param off byte offset in the object to begin writing at * @returns 0 on success, -EROFS if the io context specifies a snap_seq * other than LIBRADOS_SNAP_HEAD */ int rados_aio_write(rados_ioctx_t io, const char *oid, rados_completion_t completion, const char *buf, size_t len, uint64_t off); /** * Asychronously append data to an object * * Queues the append and returns. * * The return value of the completion will be 0 on success, negative * error code on failure. * * @param io the context to operate in * @param oid the name of the object * @param completion what to do when the append is safe and complete * @param buf the data to append * @param len length of buf (in bytes) * @returns 0 on success, -EROFS if the io context specifies a snap_seq * other than LIBRADOS_SNAP_HEAD */ int rados_aio_append(rados_ioctx_t io, const char *oid, rados_completion_t completion, const char *buf, size_t len); /** * Asychronously write an entire object * * The object is filled with the provided data. If the object exists, * it is atomically truncated and then written. * Queues the write_full and returns. * * The return value of the completion will be 0 on success, negative * error code on failure. * * @param io the io context in which the write will occur * @param oid name of the object * @param completion what to do when the write_full is safe and complete * @param buf data to write * @param len length of the data, in bytes * @returns 0 on success, -EROFS if the io context specifies a snap_seq * other than LIBRADOS_SNAP_HEAD */ int rados_aio_write_full(rados_ioctx_t io, const char *oid, rados_completion_t completion, const char *buf, size_t len); /** * Asychronously remove an object * * Queues the remove and returns. * * The return value of the completion will be 0 on success, negative * error code on failure. * * @param io the context to operate in * @param oid the name of the object * @param completion what to do when the remove is safe and complete * @returns 0 on success, -EROFS if the io context specifies a snap_seq * other than LIBRADOS_SNAP_HEAD */ int rados_aio_remove(rados_ioctx_t io, const char *oid, rados_completion_t completion); /** * Asychronously read data from an object * * The io context determines the snapshot to read from, if any was set * by rados_ioctx_snap_set_read(). * * The return value of the completion will be number of bytes read on * success, negative error code on failure. * * @note only the 'complete' callback of the completion will be called. * * @param io the context in which to perform the read * @param oid the name of the object to read from * @param completion what to do when the read is complete * @param buf where to store the results * @param len the number of bytes to read * @param off the offset to start reading from in the object * @returns 0 on success, negative error code on failure */ int rados_aio_read(rados_ioctx_t io, const char *oid, rados_completion_t completion, char *buf, size_t len, uint64_t off); /** * Block until all pending writes in an io context are safe * * This is not equivalent to calling rados_aio_wait_for_safe() on all * write completions, since this waits for the associated callbacks to * complete as well. * * @note BUG: always returns 0, should be void or accept a timeout * * @param io the context to flush * @returns 0 on success, negative error code on failure */ int rados_aio_flush(rados_ioctx_t io); /** * Schedule a callback for when all currently pending * aio writes are safe. This is a non-blocking version of * rados_aio_flush(). * * @param io the context to flush * @param completion what to do when the writes are safe * @returns 0 on success, negative error code on failure */ int rados_aio_flush_async(rados_ioctx_t io, rados_completion_t completion); /** * Asynchronously get object stats (size/mtime) * * @param io ioctx * @param o object name * @param psize where to store object size * @param pmtime where to store modification time * @returns 0 on success, negative error code on failure */ int rados_aio_stat(rados_ioctx_t io, const char *o, rados_completion_t completion, uint64_t *psize, time_t *pmtime); /** @} Asynchronous I/O */ /** * @defgroup librados_h_watch_notify Watch/Notify * * Watch/notify is a protocol to help communicate among clients. It * can be used to sychronize client state. All that's needed is a * well-known object name (for example, rbd uses the header object of * an image). * * Watchers register an interest in an object, and receive all * notifies on that object. A notify attempts to communicate with all * clients watching an object, and blocks on the notifier until each * client responds or a timeout is reached. * * See rados_watch() and rados_notify() for more details. * * @{ */ /** * @typedef rados_watchcb_t * * Callback activated when a notify is received on a watched * object. Parameters are: * - opcode undefined * - ver version of the watched object * - arg application-specific data * * @note BUG: opcode is an internal detail that shouldn't be exposed */ typedef void (*rados_watchcb_t)(uint8_t opcode, uint64_t ver, void *arg); /** * Register an interest in an object * * A watch operation registers the client as being interested in * notifications on an object. OSDs keep track of watches on * persistent storage, so they are preserved across cluster changes by * the normal recovery process. If the client loses its connection to * the primary OSD for a watched object, the watch will be removed * after 30 seconds. Watches are automatically reestablished when a new * connection is made, or a placement group switches OSDs. * * @note BUG: watch timeout should be configurable * @note BUG: librados should provide a way for watchers to notice connection resets * @note BUG: the ver parameter does not work, and -ERANGE will never be returned * (http://www.tracker.newdream.net/issues/2592) * * @param io the pool the object is in * @param o the object to watch * @param ver expected version of the object * @param handle where to store the internal id assigned to this watch * @param watchcb what to do when a notify is received on this object * @param arg application defined data to pass when watchcb is called * @returns 0 on success, negative error code on failure * @returns -ERANGE if the version of the object is greater than ver */ int rados_watch(rados_ioctx_t io, const char *o, uint64_t ver, uint64_t *handle, rados_watchcb_t watchcb, void *arg); /** * Unregister an interest in an object * * Once this completes, no more notifies will be sent to us for this * watch. This should be called to clean up unneeded watchers. * * @param io the pool the object is in * @param o the name of the watched object * @param handle which watch to unregister * @returns 0 on success, negative error code on failure */ int rados_unwatch(rados_ioctx_t io, const char *o, uint64_t handle); /** * Sychronously notify watchers of an object * * This blocks until all watchers of the object have received and * reacted to the notify, or a timeout is reached. * * @note BUG: the timeout is not changeable via the C API * @note BUG: the bufferlist is inaccessible in a rados_watchcb_t * * @param io the pool the object is in * @param o the name of the object * @param ver obsolete - just pass zero * @param buf data to send to watchers * @param buf_len length of buf in bytes * @returns 0 on success, negative error code on failure */ int rados_notify(rados_ioctx_t io, const char *o, uint64_t ver, const char *buf, int buf_len); /** @} Watch/Notify */ /** * @defgroup librados_h_hints Hints * * @{ */ /** * Set allocation hint for an object * * This is an advisory operation, it will always succeed (as if it was * submitted with a LIBRADOS_OP_FLAG_FAILOK flag set) and is not * guaranteed to do anything on the backend. * * @param io the pool the object is in * @param o the name of the object * @param expected_object_size expected size of the object, in bytes * @param expected_write_size expected size of writes to the object, in bytes * @returns 0 on success, negative error code on failure */ int rados_set_alloc_hint(rados_ioctx_t io, const char *o, uint64_t expected_object_size, uint64_t expected_write_size); /** @} Hints */ /** * @defgroup librados_h_obj_op Object Operations * * A single rados operation can do multiple operations on one object * atomicly. The whole operation will suceed or fail, and no partial * results will be visible. * * Operations may be either reads, which can return data, or writes, * which cannot. The effects of writes are applied and visible all at * once, so an operation that sets an xattr and then checks its value * will not see the updated value. * * @{ */ /** * Create a new rados_write_op_t write operation. This will store all actions * to be performed atomically. You must call rados_release_write_op when you are * finished with it. * * @returns non-NULL on success, NULL on memory allocation error. */ rados_write_op_t rados_create_write_op(); /** * Free a rados_write_op_t, must be called when you're done with it. * @param write_op operation to deallocate, created with rados_create_write_op */ void rados_release_write_op(rados_write_op_t write_op); /** * Set flags for the last operation added to this write_op. * At least one op must have been added to the write_op. * @param flags see librados.h constants beginning with LIBRADOS_OP_FLAG */ void rados_write_op_set_flags(rados_write_op_t write_op, int flags); /** * Ensure that the object exists before writing * @param write_op operation to add this action to */ void rados_write_op_assert_exists(rados_write_op_t write_op); /** * Ensure that given xattr satisfies comparison * @param write_op operation to add this action to * @param name name of the xattr to look up * @param comparison_operator currently undocumented, look for * LIBRADOS_CMPXATTR_OP_EQ in librados.h * @param value buffer to compare actual xattr value to * @param value_len length of buffer to compare actual xattr value to */ void rados_write_op_cmpxattr(rados_write_op_t write_op, const char *name, uint8_t comparison_operator, const char *value, size_t value_len); /** * Ensure that the an omap value satisfies a comparison, * with the supplied value on the right hand side (i.e. * for OP_LT, the comparison is actual_value < value. * * @param write_op operation to add this action to * @param key which omap value to compare * @param comparison_operator one of LIBRADOS_CMPXATTR_OP_EQ, LIBRADOS_CMPXATTR_OP_LT, or LIBRADOS_CMPXATTR_OP_GT * @param val value to compare with * @param val_len length of value in bytes * @param prval where to store the return value from this action */ void rados_write_op_omap_cmp(rados_write_op_t write_op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval); /** * Set an xattr * @param write_op operation to add this action to * @param name name of the xattr * @param value buffer to set xattr to * @param value_len length of buffer to set xattr to */ void rados_write_op_setxattr(rados_write_op_t write_op, const char *name, const char *value, size_t value_len); /** * Remove an xattr * @param write_op operation to add this action to * @param name name of the xattr to remove */ void rados_write_op_rmxattr(rados_write_op_t write_op, const char *name); /** * Create the object * @param write_op operation to add this action to * @param exclusive set to either LIBRADOS_CREATE_EXCLUSIVE or LIBRADOS_CREATE_IDEMPOTENT * will error if the object already exists. */ void rados_write_op_create(rados_write_op_t write_op, int exclusive, const char* category); /** * Write to offset * @param write_op operation to add this action to * @param offset offset to write to * @param buffer bytes to write * @param len length of buffer */ void rados_write_op_write(rados_write_op_t write_op, const char *buffer, size_t len, uint64_t offset); /** * Write whole object, atomically replacing it. * @param write_op operation to add this action to * @param buffer bytes to write * @param len length of buffer */ void rados_write_op_write_full(rados_write_op_t write_op, const char *buffer, size_t len); /** * Append to end of object. * @param write_op operation to add this action to * @param buffer bytes to write * @param len length of buffer */ void rados_write_op_append(rados_write_op_t write_op, const char *buffer, size_t len); /** * Remove object * @param write_op operation to add this action to */ void rados_write_op_remove(rados_write_op_t write_op); /** * Truncate an object * @param write_op operation to add this action to * @offset Offset to truncate to */ void rados_write_op_truncate(rados_write_op_t write_op, uint64_t offset); /** * Zero part of an object * @param write_op operation to add this action to * @offset Offset to zero * @len length to zero */ void rados_write_op_zero(rados_write_op_t write_op, uint64_t offset, uint64_t len); /** * Execute an OSD class method on an object * See rados_exec() for general description. * * @param write_op operation to add this action to * @param cls the name of the class * @param method the name of the method * @param in_buf where to find input * @param in_len length of in_buf in bytes * @param prval where to store the return value from the method */ void rados_write_op_exec(rados_write_op_t write_op, const char *cls, const char *method, const char *in_buf, size_t in_len, int *prval); /** * Set key/value pairs on an object * * @param write_op operation to add this action to * @param keys array of null-terminated char arrays representing keys to set * @param vals array of pointers to values to set * @param lens array of lengths corresponding to each value * @param num number of key/value pairs to set */ void rados_write_op_omap_set(rados_write_op_t write_op, char const* const* keys, char const* const* vals, const size_t *lens, size_t num); /** * Remove key/value pairs from an object * * @param write_op operation to add this action to * @param keys array of null-terminated char arrays representing keys to remove * @param keys_len number of key/value pairs to remove */ void rados_write_op_omap_rm_keys(rados_write_op_t write_op, char const* const* keys, size_t keys_len); /** * Remove all key/value pairs from an object * * @param write_op operation to add this action to */ void rados_write_op_omap_clear(rados_write_op_t write_op); /** * Set allocation hint for an object * * @param write_op operation to add this action to * @param expected_object_size expected size of the object, in bytes * @param expected_write_size expected size of writes to the object, in bytes */ void rados_write_op_set_alloc_hint(rados_write_op_t write_op, uint64_t expected_object_size, uint64_t expected_write_size); /** * Perform a write operation synchronously * @param write_op operation to perform * @io the ioctx that the object is in * @oid the object id * @mtime the time to set the mtime to, NULL for the current time * @flags flags to apply to the entire operation (LIBRADOS_OPERATION_*) */ int rados_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, const char *oid, time_t *mtime, int flags); /** * Perform a write operation asynchronously * @param write_op operation to perform * @io the ioctx that the object is in * @param completion what to do when operation has been attempted * @oid the object id * @mtime the time to set the mtime to, NULL for the current time * @flags flags to apply to the entire operation (LIBRADOS_OPERATION_*) */ int rados_aio_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, time_t *mtime, int flags); /** * Create a new rados_read_op_t write operation. This will store all * actions to be performed atomically. You must call * rados_release_read_op when you are finished with it (after it * completes, or you decide not to send it in the first place). * * @returns non-NULL on success, NULL on memory allocation error. */ rados_read_op_t rados_create_read_op(); /** * Free a rados_read_op_t, must be called when you're done with it. * @param read_op operation to deallocate, created with rados_create_read_op */ void rados_release_read_op(rados_read_op_t read_op); /** * Set flags for the last operation added to this read_op. * At least one op must have been added to the read_op. * @param flags see librados.h constants beginning with LIBRADOS_OP_FLAG */ void rados_read_op_set_flags(rados_read_op_t read_op, int flags); /** * Ensure that the object exists before reading * @param read_op operation to add this action to */ void rados_read_op_assert_exists(rados_read_op_t read_op); /** * Ensure that the an xattr satisfies a comparison * @param read_op operation to add this action to * @param name name of the xattr to look up * @param comparison_operator currently undocumented, look for * LIBRADOS_CMPXATTR_OP_EQ in librados.h * @param value buffer to compare actual xattr value to * @param value_len length of buffer to compare actual xattr value to */ void rados_read_op_cmpxattr(rados_read_op_t read_op, const char *name, uint8_t comparison_operator, const char *value, size_t value_len); /** * Start iterating over xattrs on an object. * * @param read_op operation to add this action to * @param iter where to store the iterator * @param prval where to store the return value of this action */ void rados_read_op_getxattrs(rados_read_op_t read_op, rados_xattrs_iter_t *iter, int *prval); /** * Ensure that the an omap value satisfies a comparison, * with the supplied value on the right hand side (i.e. * for OP_LT, the comparison is actual_value < value. * * @param read_op operation to add this action to * @param key which omap value to compare * @param comparison_operator one of LIBRADOS_CMPXATTR_OP_EQ, LIBRADOS_CMPXATTR_OP_LT, or LIBRADOS_CMPXATTR_OP_GT * @param val value to compare with * @param val_len length of value in bytes * @param prval where to store the return value from this action */ void rados_read_op_omap_cmp(rados_read_op_t read_op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval); /** * Get object size and mtime * @param read_op operation to add this action to * @param psize where to store object size * @param pmtime where to store modification time * @param prval where to store the return value of this action */ void rados_read_op_stat(rados_read_op_t read_op, uint64_t *psize, time_t *pmtime, int *prval); /** * Read bytes from offset into buffer. * * prlen will be filled with the number of bytes read if successful. * A short read can only occur if the read reaches the end of the * object. * * @param read_op operation to add this action to * @param offset offset to read from * @param buffer where to put the data * @param len length of buffer * @param prval where to store the return value of this action * @param bytes_read where to store the number of bytes read by this action */ void rados_read_op_read(rados_read_op_t read_op, uint64_t offset, size_t len, char *buf, size_t *bytes_read, int *prval); /** * Execute an OSD class method on an object * See rados_exec() for general description. * * The output buffer is allocated on the heap; the caller is * expected to release that memory with rados_buffer_free(). The * buffer and length pointers can all be NULL, in which case they are * not filled in. * * @param read_op operation to add this action to * @param cls the name of the class * @param method the name of the method * @param in_buf where to find input * @param in_len length of in_buf in bytes * @param out_buf where to put librados-allocated output buffer * @param out_len length of out_buf in bytes * @param prval where to store the return value from the method */ void rados_read_op_exec(rados_read_op_t read_op, const char *cls, const char *method, const char *in_buf, size_t in_len, char **out_buf, size_t *out_len, int *prval); /** * Execute an OSD class method on an object * See rados_exec() for general description. * * If the output buffer is too small, prval will * be set to -ERANGE and used_len will be 0. * * @param read_op operation to add this action to * @param cls the name of the class * @param method the name of the method * @param in_buf where to find input * @param in_len length of in_buf in bytes * @param out_buf user-provided buffer to read into * @param out_len length of out_buf in bytes * @param used_len where to store the number of bytes read into out_buf * @param prval where to store the return value from the method */ void rados_read_op_exec_user_buf(rados_read_op_t read_op, const char *cls, const char *method, const char *in_buf, size_t in_len, char *out_buf, size_t out_len, size_t *used_len, int *prval); /** * Start iterating over key/value pairs on an object. * * They will be returned sorted by key. * * @param read_op operation to add this action to * @param start_after list keys starting after start_after * @param filter_prefix list only keys beginning with filter_prefix * @parem max_return list no more than max_return key/value pairs * @param iter where to store the iterator * @param prval where to store the return value from this action */ void rados_read_op_omap_get_vals(rados_read_op_t read_op, const char *start_after, const char *filter_prefix, uint64_t max_return, rados_omap_iter_t *iter, int *prval); /** * Start iterating over keys on an object. * * They will be returned sorted by key, and the iterator * will fill in NULL for all values if specified. * * @param read_op operation to add this action to * @param start_after list keys starting after start_after * @parem max_return list no more than max_return keys * @param iter where to store the iterator * @param prval where to store the return value from this action */ void rados_read_op_omap_get_keys(rados_read_op_t read_op, const char *start_after, uint64_t max_return, rados_omap_iter_t *iter, int *prval); /** * Start iterating over specific key/value pairs * * They will be returned sorted by key. * * @param read_op operation to add this action to * @param keys array of pointers to null-terminated keys to get * @param keys_len the number of strings in keys * @param iter where to store the iterator * @param prval where to store the return value from this action */ void rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op, char const* const* keys, size_t keys_len, rados_omap_iter_t *iter, int *prval); /** * Perform a read operation synchronously * @param read_op operation to perform * @io the ioctx that the object is in * @oid the object id * @flags flags to apply to the entire operation (LIBRADOS_OPERATION_*) */ int rados_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, const char *oid, int flags); /** * Perform a read operation asynchronously * @param read_op operation to perform * @io the ioctx that the object is in * @param completion what to do when operation has been attempted * @oid the object id * @flags flags to apply to the entire operation (LIBRADOS_OPERATION_*) */ int rados_aio_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, int flags); /** @} Object Operations */ /** * Take an exclusive lock on an object. * * @param io the context to operate in * @param oid the name of the object * @param name the name of the lock * @param cookie user-defined identifier for this instance of the lock * @param desc user-defined lock description * @param duration the duration of the lock. Set to NULL for infinite duration. * @param flags lock flags * @returns 0 on success, negative error code on failure * @returns -EBUSY if the lock is already held by another (client, cookie) pair * @returns -EEXIST if the lock is already held by the same (client, cookie) pair */ int rados_lock_exclusive(rados_ioctx_t io, const char * o, const char * name, const char * cookie, const char * desc, struct timeval * duration, uint8_t flags); /** * Take a shared lock on an object. * * @param io the context to operate in * @param o the name of the object * @param name the name of the lock * @param cookie user-defined identifier for this instance of the lock * @param tag The tag of the lock * @param desc user-defined lock description * @param duration the duration of the lock. Set to NULL for infinite duration. * @param flags lock flags * @returns 0 on success, negative error code on failure * @returns -EBUSY if the lock is already held by another (client, cookie) pair * @returns -EEXIST if the lock is already held by the same (client, cookie) pair */ int rados_lock_shared(rados_ioctx_t io, const char * o, const char * name, const char * cookie, const char * tag, const char * desc, struct timeval * duration, uint8_t flags); /** * Release a shared or exclusive lock on an object. * * @param io the context to operate in * @param o the name of the object * @param name the name of the lock * @param cookie user-defined identifier for the instance of the lock * @returns 0 on success, negative error code on failure * @returns -ENOENT if the lock is not held by the specified (client, cookie) pair */ int rados_unlock(rados_ioctx_t io, const char *o, const char *name, const char *cookie); /** * List clients that have locked the named object lock and information about * the lock. * * The number of bytes required in each buffer is put in the * corresponding size out parameter. If any of the provided buffers * are too short, -ERANGE is returned after these sizes are filled in. * * @param io the context to operate in * @param o the name of the object * @param name the name of the lock * @param exclusive where to store whether the lock is exclusive (1) or shared (0) * @param tag where to store the tag associated with the object lock * @param tag_len number of bytes in tag buffer * @param clients buffer in which locker clients are stored, separated by '\0' * @param clients_len number of bytes in the clients buffer * @param cookies buffer in which locker cookies are stored, separated by '\0' * @param cookies_len number of bytes in the cookies buffer * @param addrs buffer in which locker addresses are stored, separated by '\0' * @param addrs_len number of bytes in the clients buffer * @returns number of lockers on success, negative error code on failure * @returns -ERANGE if any of the buffers are too short */ ssize_t rados_list_lockers(rados_ioctx_t io, const char *o, const char *name, int *exclusive, char *tag, size_t *tag_len, char *clients, size_t *clients_len, char *cookies, size_t *cookies_len, char *addrs, size_t *addrs_len); /** * Releases a shared or exclusive lock on an object, which was taken by the * specified client. * * @param io the context to operate in * @param o the name of the object * @param name the name of the lock * @param client the client currently holding the lock * @param cookie user-defined identifier for the instance of the lock * @returns 0 on success, negative error code on failure * @returns -ENOENT if the lock is not held by the specified (client, cookie) pair * @returns -EINVAL if the client cannot be parsed */ int rados_break_lock(rados_ioctx_t io, const char *o, const char *name, const char *client, const char *cookie); /** * @defgroup librados_h_commands Mon/OSD/PG Commands * * These interfaces send commands relating to the monitor, OSD, or PGs. * * @{ */ /** * Send monitor command. * * @note Takes command string in carefully-formatted JSON; must match * defined commands, types, etc. * * The result buffers are allocated on the heap; the caller is * expected to release that memory with rados_buffer_free(). The * buffer and length pointers can all be NULL, in which case they are * not filled in. * * @param cluster cluster handle * @param cmd an array of char *'s representing the command * @param cmdlen count of valid entries in cmd * @param inbuf any bulk input data (crush map, etc.) * @param outbuf double pointer to output buffer * @param outbuflen pointer to output buffer length * @param outs double pointer to status string * @param outslen pointer to status string length * @returns 0 on success, negative error code on failure */ int rados_mon_command(rados_t cluster, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen); /** * Send monitor command to a specific monitor. * * @note Takes command string in carefully-formatted JSON; must match * defined commands, types, etc. * * The result buffers are allocated on the heap; the caller is * expected to release that memory with rados_buffer_free(). The * buffer and length pointers can all be NULL, in which case they are * not filled in. * * @param cluster cluster handle * @param name target monitor's name * @param cmd an array of char *'s representing the command * @param cmdlen count of valid entries in cmd * @param inbuf any bulk input data (crush map, etc.) * @param outbuf double pointer to output buffer * @param outbuflen pointer to output buffer length * @param outs double pointer to status string * @param outslen pointer to status string length * @returns 0 on success, negative error code on failure */ int rados_mon_command_target(rados_t cluster, const char *name, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen); /** * free a rados-allocated buffer * * Release memory allocated by librados calls like rados_mon_command(). * * @param buf buffer pointer */ void rados_buffer_free(char *buf); int rados_osd_command(rados_t cluster, int osdid, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen); int rados_pg_command(rados_t cluster, const char *pgstr, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen); /* * This is not a doxygen comment leadin, because doxygen breaks on * a typedef with function params and returns, and I can't figure out * how to fix it. * * Monitor cluster log * * Monitor events logged to the cluster log. The callback get each * log entry both as a single formatted line and with each field in a * separate arg. * * Calling with a cb argument of NULL will deregister any previously * registered callback. * * @param cluster cluster handle * @param level minimum log level (debug, info, warn|warning, err|error) * @param cb callback to run for each log message * @param arg void argument to pass to cb * * @returns 0 on success, negative code on error */ typedef void (*rados_log_callback_t)(void *arg, const char *line, const char *who, uint64_t sec, uint64_t nsec, uint64_t seq, const char *level, const char *msg); int rados_monitor_log(rados_t cluster, const char *level, rados_log_callback_t cb, void *arg); /** @} Mon/OSD/PG commands */ #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/include/rados/buffer.h0000664000175100017510000003227612623076744021653 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_BUFFER_H #define CEPH_BUFFER_H #if defined(__linux__) #include #include #elif defined(__FreeBSD__) #include #include #endif #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 #endif #include #if defined(__linux__) // For malloc(2). #include #endif #include #include #include #ifndef __CYGWIN__ # include #endif #include #include #include #include #include #include #include "page.h" #include "crc32c.h" #ifdef __CEPH__ # include "include/assert.h" #else # include #endif namespace ceph { class buffer { /* * exceptions */ public: struct error : public std::exception{ const char *what() const throw () { return "buffer::exception"; } }; struct bad_alloc : public error { const char *what() const throw () { return "buffer::bad_alloc"; } }; struct end_of_buffer : public error { const char *what() const throw () { return "buffer::end_of_buffer"; } }; struct malformed_input : public error { explicit malformed_input(const char *w) { snprintf(buf, sizeof(buf), "buffer::malformed_input: %s", w); } const char *what() const throw () { return buf; } private: char buf[256]; }; struct error_code : public malformed_input { explicit error_code(int error); int code; }; /// total bytes allocated static int get_total_alloc(); /// enable/disable alloc tracking static void track_alloc(bool b); /// count of cached crc hits (matching input) static int get_cached_crc(); /// count of cached crc hits (mismatching input, required adjustment) static int get_cached_crc_adjusted(); /// enable/disable tracking of cached crcs static void track_cached_crc(bool b); /// count of calls to buffer::ptr::c_str() static int get_c_str_accesses(); /// enable/disable tracking of buffer::ptr::c_str() calls static void track_c_str(bool b); private: /* hack for memory utilization debugging. */ static void inc_total_alloc(unsigned len); static void dec_total_alloc(unsigned len); /* * an abstract raw buffer. with a reference count. */ class raw; class raw_malloc; class raw_static; class raw_mmap_pages; class raw_posix_aligned; class raw_hack_aligned; class raw_char; class raw_pipe; friend std::ostream& operator<<(std::ostream& out, const raw &r); public: /* * named constructors */ static raw* copy(const char *c, unsigned len); static raw* create(unsigned len); static raw* claim_char(unsigned len, char *buf); static raw* create_malloc(unsigned len); static raw* claim_malloc(unsigned len, char *buf); static raw* create_static(unsigned len, char *buf); static raw* create_page_aligned(unsigned len); static raw* create_zero_copy(unsigned len, int fd, int64_t *offset); /* * a buffer pointer. references (a subsequence of) a raw buffer. */ class ptr { raw *_raw; unsigned _off, _len; void release(); public: ptr() : _raw(0), _off(0), _len(0) {} ptr(raw *r); ptr(unsigned l); ptr(const char *d, unsigned l); ptr(const ptr& p); ptr(const ptr& p, unsigned o, unsigned l); ptr& operator= (const ptr& p); ~ptr() { release(); } bool have_raw() const { return _raw ? true:false; } raw *clone(); void swap(ptr& other); // misc bool at_buffer_head() const { return _off == 0; } bool at_buffer_tail() const; bool is_page_aligned() const { return ((long)c_str() & ~CEPH_PAGE_MASK) == 0; } bool is_n_page_sized() const { return (length() & ~CEPH_PAGE_MASK) == 0; } // accessors raw *get_raw() const { return _raw; } const char *c_str() const; char *c_str(); unsigned length() const { return _len; } unsigned offset() const { return _off; } unsigned start() const { return _off; } unsigned end() const { return _off + _len; } unsigned unused_tail_length() const; const char& operator[](unsigned n) const; char& operator[](unsigned n); const char *raw_c_str() const; unsigned raw_length() const; int raw_nref() const; void copy_out(unsigned o, unsigned l, char *dest) const { assert(_raw); if (!((o <= _len) && (o+l <= _len))) throw end_of_buffer(); memcpy(dest, c_str()+o, l); } bool can_zero_copy() const; int zero_copy_to_fd(int fd, int64_t *offset) const; unsigned wasted(); int cmp(const ptr& o) const; bool is_zero() const; // modifiers void set_offset(unsigned o) { _off = o; } void set_length(unsigned l) { _len = l; } void append(char c); void append(const char *p, unsigned l); void copy_in(unsigned o, unsigned l, const char *src); void zero(); void zero(unsigned o, unsigned l); }; friend std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp); /* * list - the useful bit! */ class list { // my private bits std::list _buffers; unsigned _len; ptr append_buffer; // where i put small appends. public: class iterator { list *bl; std::list *ls; // meh.. just here to avoid an extra pointer dereference.. unsigned off; // in bl std::list::iterator p; unsigned p_off; // in *p public: // constructor. position. iterator() : bl(0), ls(0), off(0), p_off(0) {} iterator(list *l, unsigned o=0) : bl(l), ls(&bl->_buffers), off(0), p(ls->begin()), p_off(0) { advance(o); } iterator(list *l, unsigned o, std::list::iterator ip, unsigned po) : bl(l), ls(&bl->_buffers), off(o), p(ip), p_off(po) { } iterator(const iterator& other) : bl(other.bl), ls(other.ls), off(other.off), p(other.p), p_off(other.p_off) {} iterator& operator=(const iterator& other) { if (this != &other) { bl = other.bl; ls = other.ls; off = other.off; p = other.p; p_off = other.p_off; } return *this; } /// get current iterator offset in buffer::list unsigned get_off() { return off; } /// get number of bytes remaining from iterator position to the end of the buffer::list unsigned get_remaining() { return bl->length() - off; } /// true if iterator is at the end of the buffer::list bool end() { return p == ls->end(); //return off == bl->length(); } void advance(int o); void seek(unsigned o); char operator*(); iterator& operator++(); ptr get_current_ptr(); // copy data out. // note that these all _append_ to dest! void copy(unsigned len, char *dest); void copy(unsigned len, ptr &dest); void copy(unsigned len, list &dest); void copy(unsigned len, std::string &dest); void copy_all(list &dest); // copy data in void copy_in(unsigned len, const char *src); void copy_in(unsigned len, const list& otherl); }; private: mutable iterator last_p; int zero_copy_to_fd(int fd) const; public: // cons/des list() : _len(0), last_p(this) {} list(unsigned prealloc) : _len(0), last_p(this) { append_buffer = buffer::create(prealloc); append_buffer.set_length(0); // unused, so far. } ~list() {} list(const list& other) : _buffers(other._buffers), _len(other._len), last_p(this) { } list& operator= (const list& other) { if (this != &other) { _buffers = other._buffers; _len = other._len; } return *this; } const std::list& buffers() const { return _buffers; } void swap(list& other); unsigned length() const { #if 0 // DEBUG: verify _len unsigned len = 0; for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); it++) { len += (*it).length(); } assert(len == _len); #endif return _len; } bool contents_equal(buffer::list& other); bool can_zero_copy() const; bool is_page_aligned() const; bool is_n_page_sized() const; bool is_zero() const; // modifiers void clear() { _buffers.clear(); _len = 0; last_p = begin(); } void push_front(ptr& bp) { if (bp.length() == 0) return; _buffers.push_front(bp); _len += bp.length(); } void push_front(raw *r) { ptr bp(r); push_front(bp); } void push_back(const ptr& bp) { if (bp.length() == 0) return; _buffers.push_back(bp); _len += bp.length(); } void push_back(raw *r) { ptr bp(r); push_back(bp); } void zero(); void zero(unsigned o, unsigned l); bool is_contiguous(); void rebuild(); void rebuild(ptr& nb); void rebuild_page_aligned(); // sort-of-like-assignment-op void claim(list& bl); void claim_append(list& bl); void claim_prepend(list& bl); iterator begin() { return iterator(this, 0); } iterator end() { return iterator(this, _len, _buffers.end(), 0); } // crope lookalikes. // **** WARNING: this are horribly inefficient for large bufferlists. **** void copy(unsigned off, unsigned len, char *dest) const; void copy(unsigned off, unsigned len, list &dest) const; void copy(unsigned off, unsigned len, std::string& dest) const; void copy_in(unsigned off, unsigned len, const char *src); void copy_in(unsigned off, unsigned len, const list& src); void append(char c); void append(const char *data, unsigned len); void append(const std::string& s) { append(s.data(), s.length()); } void append(const ptr& bp); void append(const ptr& bp, unsigned off, unsigned len); void append(const list& bl); void append(std::istream& in); void append_zero(unsigned len); /* * get a char */ const char& operator[](unsigned n) const; char *c_str(); void substr_of(const list& other, unsigned off, unsigned len); // funky modifer void splice(unsigned off, unsigned len, list *claim_by=0 /*, bufferlist& replace_with */); void write(int off, int len, std::ostream& out) const; void encode_base64(list& o); void decode_base64(list& o); void hexdump(std::ostream &out) const; int read_file(const char *fn, std::string *error); ssize_t read_fd(int fd, size_t len); int read_fd_zero_copy(int fd, size_t len); int write_file(const char *fn, int mode=0644); int write_fd(int fd) const; int write_fd_zero_copy(int fd) const; uint32_t crc32c(uint32_t crc) const; }; /* * efficient hash of one or more bufferlists */ class hash { uint32_t crc; public: hash() : crc(0) { } hash(uint32_t init) : crc(init) { } void update(buffer::list& bl) { crc = bl.crc32c(crc); } uint32_t digest() { return crc; } }; }; typedef buffer::ptr bufferptr; typedef buffer::list bufferlist; typedef buffer::hash bufferhash; inline bool operator>(bufferlist& l, bufferlist& r) { for (unsigned p = 0; ; p++) { if (l.length() > p && r.length() == p) return true; if (l.length() == p) return false; if (l[p] > r[p]) return true; if (l[p] < r[p]) return false; } } inline bool operator>=(bufferlist& l, bufferlist& r) { for (unsigned p = 0; ; p++) { if (l.length() > p && r.length() == p) return true; if (r.length() == p && l.length() == p) return true; if (l.length() == p && r.length() > p) return false; if (l[p] > r[p]) return true; if (l[p] < r[p]) return false; } } inline bool operator==(bufferlist &l, bufferlist &r) { if (l.length() != r.length()) return false; for (unsigned p = 0; p < l.length(); p++) { if (l[p] != r[p]) return false; } return true; } inline bool operator<(bufferlist& l, bufferlist& r) { return r > l; } inline bool operator<=(bufferlist& l, bufferlist& r) { return r >= l; } inline std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp) { if (bp.have_raw()) out << "buffer::ptr(" << bp.offset() << "~" << bp.length() << " " << (void*)bp.c_str() << " in raw " << (void*)bp.raw_c_str() << " len " << bp.raw_length() << " nref " << bp.raw_nref() << ")"; else out << "buffer:ptr(" << bp.offset() << "~" << bp.length() << " no raw)"; return out; } inline std::ostream& operator<<(std::ostream& out, const buffer::list& bl) { out << "buffer::list(len=" << bl.length() << "," << std::endl; std::list::const_iterator it = bl.buffers().begin(); while (it != bl.buffers().end()) { out << "\t" << *it; if (++it == bl.buffers().end()) break; out << "," << std::endl; } out << std::endl << ")"; return out; } inline std::ostream& operator<<(std::ostream& out, buffer::error& e) { return out << e.what(); } inline bufferhash& operator<<(bufferhash& l, bufferlist &r) { l.update(r); return l; } } #endif ceph-0.80.11/src/include/rados/librados.hpp0000664000175100017510000010012612623076744022527 0ustar jenkins-buildjenkins-build#ifndef __LIBRADOS_HPP #define __LIBRADOS_HPP #include #include #include #include #include #include #include #include "memory.h" #include "buffer.h" #include "librados.h" #include "rados_types.hpp" namespace librados { using ceph::bufferlist; struct AioCompletionImpl; class IoCtx; struct IoCtxImpl; class ObjectOperationImpl; struct ObjListCtx; struct PoolAsyncCompletionImpl; class RadosClient; typedef void *list_ctx_t; typedef uint64_t auid_t; typedef void *config_t; struct cluster_stat_t { uint64_t kb, kb_used, kb_avail; uint64_t num_objects; }; struct pool_stat_t { uint64_t num_bytes; // in bytes uint64_t num_kb; // in KB uint64_t num_objects; uint64_t num_object_clones; uint64_t num_object_copies; // num_objects * num_replicas uint64_t num_objects_missing_on_primary; uint64_t num_objects_unfound; uint64_t num_objects_degraded; uint64_t num_rd, num_rd_kb, num_wr, num_wr_kb; }; typedef struct { std::string client; std::string cookie; std::string address; } locker_t; typedef std::map stats_map; typedef void *completion_t; typedef void (*callback_t)(completion_t cb, void *arg); class ObjectIterator : public std::iterator { public: static const ObjectIterator __EndObjectIterator; ObjectIterator() {} ObjectIterator(ObjListCtx *ctx_); ~ObjectIterator(); ObjectIterator(const ObjectIterator &rhs); ObjectIterator& operator=(const ObjectIterator& rhs); bool operator==(const ObjectIterator& rhs) const; bool operator!=(const ObjectIterator& rhs) const; const std::pair& operator*() const; const std::pair* operator->() const; ObjectIterator &operator++(); // Preincrement ObjectIterator operator++(int); // Postincrement friend class IoCtx; /// get current hash position of the iterator, rounded to the current pg uint32_t get_pg_hash_position() const; /// move the iterator to a given hash position. this may (will!) be rounded to the nearest pg. uint32_t seek(uint32_t pos); private: void get_next(); ceph::shared_ptr < ObjListCtx > ctx; std::pair cur_obj; }; class WatchCtx { public: virtual ~WatchCtx(); virtual void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) = 0; }; struct AioCompletion { AioCompletion(AioCompletionImpl *pc_) : pc(pc_) {} int set_complete_callback(void *cb_arg, callback_t cb); int set_safe_callback(void *cb_arg, callback_t cb); int wait_for_complete(); int wait_for_safe(); int wait_for_complete_and_cb(); int wait_for_safe_and_cb(); bool is_complete(); bool is_safe(); bool is_complete_and_cb(); bool is_safe_and_cb(); int get_return_value(); int get_version() __attribute__ ((deprecated)); uint64_t get_version64(); void release(); AioCompletionImpl *pc; }; struct PoolAsyncCompletion { PoolAsyncCompletion(PoolAsyncCompletionImpl *pc_) : pc(pc_) {} int set_callback(void *cb_arg, callback_t cb); int wait(); bool is_complete(); int get_return_value(); void release(); PoolAsyncCompletionImpl *pc; }; /** * These are per-op flags which may be different among * ops added to an ObjectOperation. */ enum ObjectOperationFlags { OP_EXCL = LIBRADOS_OP_FLAG_EXCL, OP_FAILOK = LIBRADOS_OP_FLAG_FAILOK, }; class ObjectOperationCompletion { public: virtual ~ObjectOperationCompletion() {} virtual void handle_completion(int r, bufferlist& outbl) = 0; }; /** * These flags apply to the ObjectOperation as a whole. * * BALANCE_READS and LOCALIZE_READS should only be used * when reading from data you're certain won't change, * like a snapshot, or where eventual consistency is ok. * * ORDER_READS_WRITES will order reads the same way writes are * ordered (e.g., waiting for degraded objects). In particular, it * will make a write followed by a read sequence be preserved. * * IGNORE_CACHE will skip the caching logic on the OSD that normally * handles promotion of objects between tiers. This allows an operation * to operate (or read) the cached (or uncached) object, even if it is * not coherent. * * IGNORE_OVERLAY will ignore the pool overlay tiering metadata and * process the op directly on the destination pool. This is useful * for CACHE_FLUSH and CACHE_EVICT operations. */ enum ObjectOperationGlobalFlags { OPERATION_NOFLAG = 0, OPERATION_BALANCE_READS = 1, OPERATION_LOCALIZE_READS = 2, OPERATION_ORDER_READS_WRITES = 4, OPERATION_IGNORE_CACHE = 8, OPERATION_SKIPRWLOCKS = 16, OPERATION_IGNORE_OVERLAY = 32, }; /* * ObjectOperation : compound object operation * Batch multiple object operations into a single request, to be applied * atomically. */ class ObjectOperation { public: ObjectOperation(); virtual ~ObjectOperation(); size_t size(); void set_op_flags(ObjectOperationFlags flags); void cmpxattr(const char *name, uint8_t op, const bufferlist& val); void cmpxattr(const char *name, uint8_t op, uint64_t v); void src_cmpxattr(const std::string& src_oid, const char *name, int op, const bufferlist& val); void src_cmpxattr(const std::string& src_oid, const char *name, int op, uint64_t v); void exec(const char *cls, const char *method, bufferlist& inbl); void exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *obl, int *prval); void exec(const char *cls, const char *method, bufferlist& inbl, ObjectOperationCompletion *completion); /** * Guard operation with a check that object version == ver * * @param ver [in] version to check */ void assert_version(uint64_t ver); /** * Guard operatation with a check that the object already exists */ void assert_exists(); /** * get key/value pairs for specified keys * * @param assertions [in] comparison assertions * @param prval [out] place error code in prval upon completion * * assertions has the form of mappings from keys to (comparison rval, assertion) * The assertion field may be CEPH_OSD_CMPXATTR_OP_[GT|LT|EQ]. * * That is, to assert that the value at key 'foo' is greater than 'bar': * * ObjectReadOperation op; * int r; * map > assertions; * bufferlist bar(string('bar')); * assertions['foo'] = make_pair(bar, CEPH_OSD_CMP_XATTR_OP_GT); * op.omap_cmp(assertions, &r); */ void omap_cmp( const std::map > &assertions, int *prval); protected: ObjectOperationImpl *impl; ObjectOperation(const ObjectOperation& rhs); ObjectOperation& operator=(const ObjectOperation& rhs); friend class IoCtx; friend class Rados; }; /* * ObjectWriteOperation : compound object write operation * Batch multiple object operations into a single request, to be applied * atomically. */ class ObjectWriteOperation : public ObjectOperation { protected: time_t *pmtime; public: ObjectWriteOperation() : pmtime(NULL) {} ~ObjectWriteOperation() {} void mtime(time_t *pt) { pmtime = pt; } void create(bool exclusive); void create(bool exclusive, const std::string& category); void write(uint64_t off, const bufferlist& bl); void write_full(const bufferlist& bl); void append(const bufferlist& bl); void remove(); void truncate(uint64_t off); void zero(uint64_t off, uint64_t len); void rmxattr(const char *name); void setxattr(const char *name, const bufferlist& bl); void tmap_update(const bufferlist& cmdbl); void tmap_put(const bufferlist& bl); void clone_range(uint64_t dst_off, const std::string& src_oid, uint64_t src_off, size_t len); void selfmanaged_snap_rollback(uint64_t snapid); /** * Rollback an object to the specified snapshot id * * Used with pool snapshots * * @param snapid [in] snopshot id specified */ void snap_rollback(uint64_t snapid); /** * set keys and values according to map * * @param map [in] keys and values to set */ void omap_set(const std::map &map); /** * set header * * @param bl [in] header to set */ void omap_set_header(const bufferlist &bl); /** * Clears omap contents */ void omap_clear(); /** * Clears keys in to_rm * * @param to_rm [in] keys to remove */ void omap_rm_keys(const std::set &to_rm); /** * Copy an object * * Copies an object from another location. The operation is atomic in that * the copy either succeeds in its entirety or fails (e.g., because the * source object was modified while the copy was in progress). * * @param src source object name * @param src_ioctx ioctx for the source object * @param version current version of the source object */ void copy_from(const std::string& src, const IoCtx& src_ioctx, uint64_t src_version); /** * undirty an object * * Clear an objects dirty flag */ void undirty(); /** * Set allocation hint for an object * * @param expected_object_size expected size of the object, in bytes * @param expected_write_size expected size of writes to the object, in bytes */ void set_alloc_hint(uint64_t expected_object_size, uint64_t expected_write_size); friend class IoCtx; }; /* * ObjectReadOperation : compound object operation that return value * Batch multiple object operations into a single request, to be applied * atomically. */ class ObjectReadOperation : public ObjectOperation { public: ObjectReadOperation() {} ~ObjectReadOperation() {} void stat(uint64_t *psize, time_t *pmtime, int *prval); void getxattr(const char *name, bufferlist *pbl, int *prval); void getxattrs(std::map *pattrs, int *prval); void read(size_t off, uint64_t len, bufferlist *pbl, int *prval); /** * see aio_sparse_read() */ void sparse_read(uint64_t off, uint64_t len, std::map *m, bufferlist *data_bl, int *prval); void tmap_get(bufferlist *pbl, int *prval); /** * omap_get_vals: keys and values from the object omap * * Get up to max_return keys and values beginning after start_after * * @param start_after [in] list no keys smaller than start_after * @parem max_return [in] list no more than max_return key/value pairs * @param out_vals [out] place returned values in out_vals on completion * @param prval [out] place error code in prval upon completion */ void omap_get_vals( const std::string &start_after, uint64_t max_return, std::map *out_vals, int *prval); /** * omap_get_vals: keys and values from the object omap * * Get up to max_return keys and values beginning after start_after * * @param start_after [in] list keys starting after start_after * @param filter_prefix [in] list only keys beginning with filter_prefix * @parem max_return [in] list no more than max_return key/value pairs * @param out_vals [out] place returned values in out_vals on completion * @param prval [out] place error code in prval upon completion */ void omap_get_vals( const std::string &start_after, const std::string &filter_prefix, uint64_t max_return, std::map *out_vals, int *prval); /** * omap_get_keys: keys from the object omap * * Get up to max_return keys beginning after start_after * * @param start_after [in] list keys starting after start_after * @parem max_return [in] list no more than max_return keys * @param out_keys [out] place returned values in out_keys on completion * @param prval [out] place error code in prval upon completion */ void omap_get_keys(const std::string &start_after, uint64_t max_return, std::set *out_keys, int *prval); /** * omap_get_header: get header from object omap * * @param header [out] place header here upon completion * @param prval [out] place error code in prval upon completion */ void omap_get_header(bufferlist *header, int *prval); /** * get key/value pairs for specified keys * * @param to_get [in] keys to get * @param out_vals [out] place key/value pairs found here on completion * @param prval [out] place error code in prval upon completion */ void omap_get_vals_by_keys(const std::set &keys, std::map *map, int *prval); /** * list_watchers: Get list watchers of object * * @param out_watchers [out] place returned values in out_watchers on completion * @param prval [out] place error code in prval upon completion */ void list_watchers(std::list *out_watchers, int *prval); /** * list snapshot clones associated with a logical object * * This will include a record for each version of the object, * include the "HEAD" (which will have a cloneid of SNAP_HEAD). * Each clone includes a vector of snap ids for which it is * defined to exist. * * NOTE: this operation must be submitted from an IoCtx with a * read snapid of SNAP_DIR for reliable results. * * @param out_snaps [out] pointer to resulting snap_set_t * @param prval [out] place error code in prval upon completion */ void list_snaps(snap_set_t *out_snaps, int *prval); /** * query dirty state of an object * * @param out_dirty [out] pointer to resulting bool * @param prval [out] place error code in prval upon completion */ void is_dirty(bool *isdirty, int *prval); /** * flush a cache tier object to backing tier; will block racing * updates. * * This should be used in concert with OPERATION_IGNORE_CACHE to avoid * triggering a promotion. */ void cache_flush(); /** * Flush a cache tier object to backing tier; will EAGAIN if we race * with an update. Must be used with the SKIPRWLOCKS flag. * * This should be used in concert with OPERATION_IGNORE_CACHE to avoid * triggering a promotion. */ void cache_try_flush(); /** * evict a clean cache tier object * * This should be used in concert with OPERATION_IGNORE_CACHE to avoid * triggering a promote on the OSD (that is then evicted). */ void cache_evict(); }; /* IoCtx : This is a context in which we can perform I/O. * It includes a Pool, * * Typical use (error checking omitted): * * IoCtx p; * rados.ioctx_create("my_pool", p); * p->stat(&stats); * ... etc ... */ class IoCtx { public: IoCtx(); static void from_rados_ioctx_t(rados_ioctx_t p, IoCtx &pool); IoCtx(const IoCtx& rhs); IoCtx& operator=(const IoCtx& rhs); ~IoCtx(); // Close our pool handle void close(); // deep copy void dup(const IoCtx& rhs); // set pool auid int set_auid(uint64_t auid_); // set pool auid int set_auid_async(uint64_t auid_, PoolAsyncCompletion *c); // get pool auid int get_auid(uint64_t *auid_); std::string get_pool_name(); bool pool_requires_alignment(); uint64_t pool_required_alignment(); // create an object int create(const std::string& oid, bool exclusive); int create(const std::string& oid, bool exclusive, const std::string& category); /** * write bytes to an object at a specified offset * * NOTE: this call steals the contents of @param bl. */ int write(const std::string& oid, bufferlist& bl, size_t len, uint64_t off); /** * append bytes to an object * * NOTE: this call steals the contents of @param bl. */ int append(const std::string& oid, bufferlist& bl, size_t len); /** * replace object contents with provided data * * NOTE: this call steals the contents of @param bl. */ int write_full(const std::string& oid, bufferlist& bl); int clone_range(const std::string& dst_oid, uint64_t dst_off, const std::string& src_oid, uint64_t src_off, size_t len); int read(const std::string& oid, bufferlist& bl, size_t len, uint64_t off); int remove(const std::string& oid); int trunc(const std::string& oid, uint64_t size); int mapext(const std::string& o, uint64_t off, size_t len, std::map& m); int sparse_read(const std::string& o, std::map& m, bufferlist& bl, size_t len, uint64_t off); int getxattr(const std::string& oid, const char *name, bufferlist& bl); int getxattrs(const std::string& oid, std::map& attrset); int setxattr(const std::string& oid, const char *name, bufferlist& bl); int rmxattr(const std::string& oid, const char *name); int stat(const std::string& oid, uint64_t *psize, time_t *pmtime); int exec(const std::string& oid, const char *cls, const char *method, bufferlist& inbl, bufferlist& outbl); /** * modify object tmap based on encoded update sequence * * NOTE: this call steals the contents of @param bl */ int tmap_update(const std::string& oid, bufferlist& cmdbl); /** * replace object contents with provided encoded tmap data * * NOTE: this call steals the contents of @param bl */ int tmap_put(const std::string& oid, bufferlist& bl); int tmap_get(const std::string& oid, bufferlist& bl); int tmap_to_omap(const std::string& oid, bool nullok=false); int omap_get_vals(const std::string& oid, const std::string& start_after, uint64_t max_return, std::map *out_vals); int omap_get_vals(const std::string& oid, const std::string& start_after, const std::string& filter_prefix, uint64_t max_return, std::map *out_vals); int omap_get_keys(const std::string& oid, const std::string& start_after, uint64_t max_return, std::set *out_keys); int omap_get_header(const std::string& oid, bufferlist *bl); int omap_get_vals_by_keys(const std::string& oid, const std::set& keys, std::map *vals); int omap_set(const std::string& oid, const std::map& map); int omap_set_header(const std::string& oid, const bufferlist& bl); int omap_clear(const std::string& oid); int omap_rm_keys(const std::string& oid, const std::set& keys); void snap_set_read(snap_t seq); int selfmanaged_snap_set_write_ctx(snap_t seq, std::vector& snaps); // Create a snapshot with a given name int snap_create(const char *snapname); // Look up a snapshot by name. // Returns 0 on success; error code otherwise int snap_lookup(const char *snapname, snap_t *snap); // Gets a timestamp for a snap int snap_get_stamp(snap_t snapid, time_t *t); // Gets the name of a snap int snap_get_name(snap_t snapid, std::string *s); // Remove a snapshot from this pool int snap_remove(const char *snapname); int snap_list(std::vector *snaps); int snap_rollback(const std::string& oid, const char *snapname); // Deprecated name kept for backward compatibility - same as snap_rollback() int rollback(const std::string& oid, const char *snapname); int selfmanaged_snap_create(uint64_t *snapid); int selfmanaged_snap_remove(uint64_t snapid); int selfmanaged_snap_rollback(const std::string& oid, uint64_t snapid); // Advisory locking on rados objects. int lock_exclusive(const std::string &oid, const std::string &name, const std::string &cookie, const std::string &description, struct timeval * duration, uint8_t flags); int lock_shared(const std::string &oid, const std::string &name, const std::string &cookie, const std::string &tag, const std::string &description, struct timeval * duration, uint8_t flags); int unlock(const std::string &oid, const std::string &name, const std::string &cookie); int break_lock(const std::string &oid, const std::string &name, const std::string &client, const std::string &cookie); int list_lockers(const std::string &oid, const std::string &name, int *exclusive, std::string *tag, std::list *lockers); /// Start enumerating objects for a pool ObjectIterator objects_begin(); /// Start enumerating objects for a pool starting from a hash position ObjectIterator objects_begin(uint32_t start_hash_position); /// Iterator indicating the end of a pool const ObjectIterator& objects_end() const; /** * List available hit set objects * * @param uint32_t [in] hash position to query * @param c [in] completion * @param pls [out] list of available intervals */ int hit_set_list(uint32_t hash, AioCompletion *c, std::list< std::pair > *pls); /** * Retrieve hit set for a given hash, and time * * @param uint32_t [in] hash position * @param c [in] completion * @param stamp [in] time interval that falls within the hit set's interval * @param pbl [out] buffer to store the result in */ int hit_set_get(uint32_t hash, AioCompletion *c, time_t stamp, bufferlist *pbl); uint64_t get_last_version(); int aio_read(const std::string& oid, AioCompletion *c, bufferlist *pbl, size_t len, uint64_t off); /** * Asynchronously read from an object at a particular snapshot * * This is the same as normal aio_read, except that it chooses * the snapshot to read from from its arguments instead of the * internal IoCtx state. * * The return value of the completion will be number of bytes read on * success, negative error code on failure. * * @param oid the name of the object to read from * @param c what to do when the read is complete * @param pbl where to store the results * @param len the number of bytes to read * @param off the offset to start reading from in the object * @param snapid the id of the snapshot to read from * @returns 0 on success, negative error code on failure */ int aio_read(const std::string& oid, AioCompletion *c, bufferlist *pbl, size_t len, uint64_t off, uint64_t snapid); int aio_sparse_read(const std::string& oid, AioCompletion *c, std::map *m, bufferlist *data_bl, size_t len, uint64_t off); /** * Asynchronously read existing extents from an object at a * particular snapshot * * This is the same as normal aio_sparse_read, except that it chooses * the snapshot to read from from its arguments instead of the * internal IoCtx state. * * m will be filled in with a map of extents in the object, * mapping offsets to lengths (in bytes) within the range * requested. The data for all of the extents are stored * back-to-back in offset order in data_bl. * * @param oid the name of the object to read from * @param c what to do when the read is complete * @param m where to store the map of extents * @param data_bl where to store the data * @param len the number of bytes to read * @param off the offset to start reading from in the object * @param snapid the id of the snapshot to read from * @returns 0 on success, negative error code on failure */ int aio_sparse_read(const std::string& oid, AioCompletion *c, std::map *m, bufferlist *data_bl, size_t len, uint64_t off, uint64_t snapid); int aio_write(const std::string& oid, AioCompletion *c, const bufferlist& bl, size_t len, uint64_t off); int aio_append(const std::string& oid, AioCompletion *c, const bufferlist& bl, size_t len); int aio_write_full(const std::string& oid, AioCompletion *c, const bufferlist& bl); /** * Asychronously remove an object * * Queues the remove and returns. * * The return value of the completion will be 0 on success, negative * error code on failure. * * @param io the context to operate in * @param oid the name of the object * @param completion what to do when the remove is safe and complete * @returns 0 on success, -EROFS if the io context specifies a snap_seq * other than SNAP_HEAD */ int aio_remove(const std::string& oid, AioCompletion *c); /** * Wait for all currently pending aio writes to be safe. * * @returns 0 on success, negative error code on failure */ int aio_flush(); /** * Schedule a callback for when all currently pending * aio writes are safe. This is a non-blocking version of * aio_flush(). * * @param c what to do when the writes are safe * @returns 0 on success, negative error code on failure */ int aio_flush_async(AioCompletion *c); int aio_stat(const std::string& oid, AioCompletion *c, uint64_t *psize, time_t *pmtime); int aio_exec(const std::string& oid, AioCompletion *c, const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl); // compound object operations int operate(const std::string& oid, ObjectWriteOperation *op); int operate(const std::string& oid, ObjectReadOperation *op, bufferlist *pbl); int aio_operate(const std::string& oid, AioCompletion *c, ObjectWriteOperation *op); int aio_operate(const std::string& oid, AioCompletion *c, ObjectWriteOperation *op, int flags); /** * Schedule an async write operation with explicit snapshot parameters * * This is the same as the first aio_operate(), except that it * gets the snapshot context from its arguments instead of the * IoCtx internal state. * * @param oid the object to operate on * @param c what to do when the operation is complete and safe * @param op which operations to perform * @param seq latest selfmanaged snapshot sequence number for this object * @param snaps currently existing selfmanaged snapshot ids for this object * @returns 0 on success, negative error code on failure */ int aio_operate(const std::string& oid, AioCompletion *c, ObjectWriteOperation *op, snap_t seq, std::vector& snaps); int aio_operate(const std::string& oid, AioCompletion *c, ObjectReadOperation *op, bufferlist *pbl); int aio_operate(const std::string& oid, AioCompletion *c, ObjectReadOperation *op, snap_t snapid, int flags, bufferlist *pbl) __attribute__ ((deprecated)); int aio_operate(const std::string& oid, AioCompletion *c, ObjectReadOperation *op, int flags, bufferlist *pbl); // watch/notify int watch(const std::string& o, uint64_t ver, uint64_t *handle, librados::WatchCtx *ctx); int unwatch(const std::string& o, uint64_t handle); int notify(const std::string& o, uint64_t ver, bufferlist& bl); int list_watchers(const std::string& o, std::list *out_watchers); int list_snaps(const std::string& o, snap_set_t *out_snaps); void set_notify_timeout(uint32_t timeout); /** * Set allocation hint for an object * * This is an advisory operation, it will always succeed (as if it * was submitted with a OP_FAILOK flag set) and is not guaranteed * to do anything on the backend. * * @param o the name of the object * @param expected_object_size expected size of the object, in bytes * @param expected_write_size expected size of writes to the object, in bytes * @returns 0 on success, negative error code on failure */ int set_alloc_hint(const std::string& o, uint64_t expected_object_size, uint64_t expected_write_size); // assert version for next sync operations void set_assert_version(uint64_t ver); void set_assert_src_version(const std::string& o, uint64_t ver); const std::string& get_pool_name() const; void locator_set_key(const std::string& key); void set_namespace(const std::string& nspace); int64_t get_id(); uint32_t get_object_hash_position(const std::string& oid); uint32_t get_object_pg_hash_position(const std::string& oid); config_t cct(); private: /* You can only get IoCtx instances from Rados */ IoCtx(IoCtxImpl *io_ctx_impl_); friend class Rados; // Only Rados can use our private constructor to create IoCtxes. friend class ObjectWriteOperation; // copy_from needs to see our IoCtxImpl IoCtxImpl *io_ctx_impl; }; class Rados { public: static void version(int *major, int *minor, int *extra); Rados(); explicit Rados(IoCtx& ioctx); ~Rados(); int init(const char * const id); int init2(const char * const name, const char * const clustername, uint64_t flags); int init_with_context(config_t cct_); config_t cct(); int connect(); void shutdown(); int conf_read_file(const char * const path) const; int conf_parse_argv(int argc, const char ** argv) const; int conf_parse_argv_remainder(int argc, const char ** argv, const char ** remargv) const; int conf_parse_env(const char *env) const; int conf_set(const char *option, const char *value); int conf_get(const char *option, std::string &val); int pool_create(const char *name); int pool_create(const char *name, uint64_t auid); int pool_create(const char *name, uint64_t auid, uint8_t crush_rule); int pool_create_async(const char *name, PoolAsyncCompletion *c); int pool_create_async(const char *name, uint64_t auid, PoolAsyncCompletion *c); int pool_create_async(const char *name, uint64_t auid, uint8_t crush_rule, PoolAsyncCompletion *c); int pool_delete(const char *name); int pool_delete_async(const char *name, PoolAsyncCompletion *c); int64_t pool_lookup(const char *name); int pool_reverse_lookup(int64_t id, std::string *name); uint64_t get_instance_id(); int mon_command(std::string cmd, const bufferlist& inbl, bufferlist *outbl, std::string *outs); int ioctx_create(const char *name, IoCtx &pioctx); // Features useful for test cases void test_blacklist_self(bool set); /* listing objects */ int pool_list(std::list& v); int get_pool_stats(std::list& v, std::map& stats); int get_pool_stats(std::list& v, std::string& category, std::map& stats); int cluster_stat(cluster_stat_t& result); int cluster_fsid(std::string *fsid); /// get/wait for the most recent osdmap int wait_for_latest_osdmap(); /* * pool aio * * It is up to the caller to release the completion handler, even if the pool_create_async() * and/or pool_delete_async() fails and does not send the async request */ static PoolAsyncCompletion *pool_async_create_completion(); // -- aio -- static AioCompletion *aio_create_completion(); static AioCompletion *aio_create_completion(void *cb_arg, callback_t cb_complete, callback_t cb_safe); friend std::ostream& operator<<(std::ostream &oss, const Rados& r); private: // We don't allow assignment or copying Rados(const Rados& rhs); const Rados& operator=(const Rados& rhs); RadosClient *client; }; } #endif ceph-0.80.11/src/include/rados/crc32c.h0000664000175100017510000000137412623076744021454 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRC32C_H #define CEPH_CRC32C_H #include #include typedef uint32_t (*ceph_crc32c_func_t)(uint32_t crc, unsigned char const *data, unsigned length); /* * this is a static global with the chosen crc32c implementation for * the given architecture. */ extern ceph_crc32c_func_t ceph_crc32c_func; extern ceph_crc32c_func_t ceph_choose_crc32(void); /** * calculate crc32c * * Note: if the data pointer is NULL, we calculate a crc value as if * it were zero-filled. * * @param crc initial value * @param data pointer to data buffer * @param length length of buffer */ static inline uint32_t ceph_crc32c(uint32_t crc, unsigned char const *data, unsigned length) { return ceph_crc32c_func(crc, data, length); } #endif ceph-0.80.11/src/include/rados/rados_types.hpp0000664000175100017510000000116312623076744023265 0ustar jenkins-buildjenkins-build#ifndef CEPH_RADOS_TYPES_HPP #define CEPH_RADOS_TYPES_HPP #include #include #include namespace librados { typedef uint64_t snap_t; enum { SNAP_HEAD = (uint64_t)(-2), SNAP_DIR = (uint64_t)(-1) }; struct clone_info_t { snap_t cloneid; std::vector snaps; // ascending std::vector< std::pair > overlap; // with next newest uint64_t size; clone_info_t() : cloneid(0), size(0) {} }; struct snap_set_t { std::vector clones; // ascending snap_t seq; // newest snapid seen by the object snap_set_t() : seq(0) {} }; } #endif ceph-0.80.11/src/include/rados/librgw.h0000664000175100017510000000164112623076744021660 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRGW_H #define CEPH_LIBRGW_H #ifdef __cplusplus extern "C" { #endif class CephContext; typedef CephContext* librgw_t; int librgw_create(librgw_t *rgw, const char * const id); int librgw_acl_bin2xml(librgw_t rgw, const char *bin, int bin_len, char **xml); void librgw_free_xml(librgw_t rgw, char *xml); int librgw_acl_xml2bin(librgw_t rgw, const char *xml, char **bin, int *bin_len); void librgw_free_bin(librgw_t rgw, char *bin); void librgw_shutdown(librgw_t rgw); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/include/rados/page.h0000664000175100017510000000050312623076744021302 0ustar jenkins-buildjenkins-build#ifndef CEPH_PAGE_H #define CEPH_PAGE_H namespace ceph { // these are in common/page.cc extern unsigned _page_size; extern unsigned long _page_mask; extern unsigned _page_shift; } #endif #define CEPH_PAGE_SIZE ceph::_page_size #define CEPH_PAGE_MASK ceph::_page_mask #define CEPH_PAGE_SHIFT ceph::_page_shift ceph-0.80.11/src/include/rados/rados_types.h0000664000175100017510000000040212623076744022720 0ustar jenkins-buildjenkins-build#ifndef CEPH_RADOS_TYPES_H #define CEPH_RADOS_TYPES_H #include /** * @struct obj_watch_t * One item from list_watchers */ struct obj_watch_t { char addr[256]; int64_t watcher_id; uint64_t cookie; uint32_t timeout_seconds; }; #endif ceph-0.80.11/src/include/rados/memory.h0000664000175100017510000000056412623076744021705 0ustar jenkins-buildjenkins-build#ifndef CEPH_MEMORY_H #define CEPH_MEMORY_H #include #ifdef _LIBCPP_VERSION #include namespace ceph { using std::shared_ptr; using std::weak_ptr; using std::static_pointer_cast; } #else #include namespace ceph { using std::tr1::shared_ptr; using std::tr1::weak_ptr; using std::tr1::static_pointer_cast; } #endif #endif ceph-0.80.11/src/include/bitmapper.h0000664000175100017510000000211312623076744021240 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_BITMAPPER_H #define CEPH_BITMAPPER_H class bitmapper { char *_data; int _len; public: bitmapper() : _data(0), _len(0) { } bitmapper(char *data, int len) : _data(data), _len(len) { } void set_data(char *data, int len) { _data = data; _len = len; } int bytes() const { return _len; } int bits() const { return _len * 8; } bool operator[](int b) const { return get(b); } bool get(int b) const { return _data[b >> 3] & (1 << (b&7)); } void set(int b) { _data[b >> 3] |= 1 << (b&7); } void clear(int b) { _data[b >> 3] &= ~(1 << (b&7)); } void toggle(int b) { _data[b >> 3] ^= 1 << (b&7); } }; #endif ceph-0.80.11/src/include/rangeset.h0000664000175100017510000001215012623076744021067 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RANGESET_H #define CEPH_RANGESET_H /* * * my first container with iterator! it's pretty ugly. * */ #include #include using namespace std; //typedef int T; template struct _rangeset_base { map ranges; // pair(first,last) (inclusive, e.g. [first,last]) typedef typename map::iterator mapit; // get iterator for range including val. or ranges.end(). mapit get_range_for(T val) { mapit it = ranges.lower_bound(val); if (it == ranges.end()) { // search backwards typename map::reverse_iterator it = ranges.rbegin(); if (it == ranges.rend()) return ranges.end(); if (it->first <= val && it->second >= val) return ranges.find(it->first); return ranges.end(); } else { if (it->first == val) return it--; if (it->first <= val && it->second >= val) return it; return ranges.end(); } } }; template class rangeset_iterator : public std::iterator { //typedef typename map::iterator mapit; map ranges; typename map::iterator it; T current; public: // cons rangeset_iterator() {} rangeset_iterator(typename map::iterator& it, map& ranges) { this->ranges = ranges; this->it = it; if (this->it != ranges.end()) current = it->first; } bool operator==(rangeset_iterator rit) { return (it == rit.it && rit.current == current); } bool operator!=(rangeset_iterator rit) { return (it != rit.it) || (rit.current != current); } T& operator*() { return current; } rangeset_iterator operator++(int) { if (current < it->second) current++; else { it++; if (it != ranges.end()) current = it->first; } return *this; } }; template class rangeset { typedef typename map::iterator map_iterator; _rangeset_base theset; inodeno_t _size; public: rangeset() { _size = 0; } typedef rangeset_iterator iterator; iterator begin() { map_iterator it = theset.ranges.begin(); return iterator(it, theset.ranges); } iterator end() { map_iterator it = theset.ranges.end(); return iterator(it, theset.ranges); } map_iterator map_begin() { return theset.ranges.begin(); } map_iterator map_end() { return theset.ranges.end(); } int map_size() { return theset.ranges.size(); } void map_insert(T v1, T v2) { theset.ranges.insert(pair(v1,v2)); _size += v2 - v1+1; } // ... bool contains(T val) { if (theset.get_range_for(val) == theset.ranges.end()) return false; assert(!empty()); return true; } void insert(T val) { assert(!contains(val)); map_iterator left = theset.get_range_for(val-1); map_iterator right = theset.get_range_for(val+1); if (left != theset.ranges.end() && right != theset.ranges.end()) { // join! left->second = right->second; theset.ranges.erase(right); _size++; return; } if (left != theset.ranges.end()) { // add to left range left->second = val; _size++; return; } if (right != theset.ranges.end()) { // add to right range theset.ranges.insert(pair(val, right->second)); theset.ranges.erase(val+1); _size++; return; } // new range theset.ranges.insert(pair(val,val)); _size++; return; } unsigned size() { return size(); } bool empty() { if (theset.ranges.empty()) { assert(_size == 0); return true; } assert(_size>0); return false; } T first() { assert(!empty()); map_iterator it = theset.ranges.begin(); return it->first; } void erase(T val) { assert(contains(val)); map_iterator it = theset.get_range_for(val); assert(it != theset.ranges.end()); // entire range if (val == it->first && val == it->second) { theset.ranges.erase(it); _size--; return; } // beginning if (val == it->first) { theset.ranges.insert(pair(val+1, it->second)); theset.ranges.erase(it); _size--; return; } // end if (val == it->second) { it->second = val-1; _size--; return; } // middle split theset.ranges.insert(pair(it->first, val-1)); theset.ranges.insert(pair(val+1, it->second)); theset.ranges.erase(it); _size--; return; } void dump() { for (typename map::iterator it = theset.ranges.begin(); it != theset.ranges.end(); it++) { cout << " " << it->first << "-" << it->second << endl; } } }; #endif ceph-0.80.11/src/include/error.h0000664000175100017510000000201212623076744020404 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #ifdef __cplusplus extern "C" { #endif #define SYSERROR() syserror("At %s:%d", __FILE__, __LINE__) #define ASSERT(c) \ ((c) || (exiterror("Assertion failed at %s:%d", __FILE__, __LINE__), 1)) /* print usage error message and exit */ extern void userror(const char *use, const char *fmt, ...); /* print system error message and exit */ extern void syserror(const char *fmt, ...); /* print error message and exit */ extern void exiterror(const char *fmt, ...); /* print error message */ extern void error(const char *fmt, ...); #ifdef __cplusplus } // extern "C" #endif ceph-0.80.11/src/include/intarith.h0000664000175100017510000000154012623076744021102 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_INTARITH_H #define CEPH_INTARITH_H #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a):(b)) #endif #ifndef MAX # define MAX(a,b) ((a) > (b) ? (a):(b)) #endif #ifndef DIV_ROUND_UP # define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #endif #ifndef ROUND_UP_TO # define ROUND_UP_TO(n, d) ((n)%(d) ? ((n)+(d)-(n)%(d)) : (n)) #endif #ifndef SHIFT_ROUND_UP # define SHIFT_ROUND_UP(x,y) (((x)+(1<<(y))-1) >> (y)) #endif #endif ceph-0.80.11/src/include/rados.h0000664000175100017510000004063612623076744020401 0ustar jenkins-buildjenkins-build#ifndef CEPH_RADOS_H #define CEPH_RADOS_H /* * Data types for the Ceph distributed object storage layer RADOS * (Reliable Autonomic Distributed Object Store). */ #include "msgr.h" /* * fs id */ struct ceph_fsid { unsigned char fsid[16]; }; static inline int ceph_fsid_compare(const struct ceph_fsid *a, const struct ceph_fsid *b) { return memcmp(a, b, sizeof(*a)); } /* * ino, object, etc. */ typedef __le64 ceph_snapid_t; #define CEPH_SNAPDIR ((__u64)(-1)) /* reserved for hidden .snap dir */ #define CEPH_NOSNAP ((__u64)(-2)) /* "head", "live" revision */ #define CEPH_MAXSNAP ((__u64)(-3)) /* largest valid snapid */ struct ceph_timespec { __le32 tv_sec; __le32 tv_nsec; } __attribute__ ((packed)); /* * object layout - how objects are mapped into PGs */ #define CEPH_OBJECT_LAYOUT_HASH 1 #define CEPH_OBJECT_LAYOUT_LINEAR 2 #define CEPH_OBJECT_LAYOUT_HASHINO 3 /* * pg layout -- how PGs are mapped onto (sets of) OSDs */ #define CEPH_PG_LAYOUT_CRUSH 0 #define CEPH_PG_LAYOUT_HASH 1 #define CEPH_PG_LAYOUT_LINEAR 2 #define CEPH_PG_LAYOUT_HYBRID 3 #define CEPH_PG_MAX_SIZE 16 /* max # osds in a single pg */ /* * placement group. * we encode this into one __le64. */ struct ceph_pg { __le16 preferred; /* preferred primary osd */ __le16 ps; /* placement seed */ __le32 pool; /* object pool */ } __attribute__ ((packed)); /* * pg pool types * * NOTE: These map 1:1 on to the pg_pool_t::TYPE_* values. They are * duplicated here only for CrushCompiler's benefit. */ #define CEPH_PG_TYPE_REPLICATED 1 /* #define CEPH_PG_TYPE_RAID4 2 never implemented */ #define CEPH_PG_TYPE_ERASURE 3 /* * stable_mod func is used to control number of placement groups. * similar to straight-up modulo, but produces a stable mapping as b * increases over time. b is the number of bins, and bmask is the * containing power of 2 minus 1. * * b <= bmask and bmask=(2**n)-1 * e.g., b=12 -> bmask=15, b=123 -> bmask=127 */ static inline int ceph_stable_mod(int x, int b, int bmask) { if ((x & bmask) < b) return x & bmask; else return x & (bmask >> 1); } /* * object layout - how a given object should be stored. */ struct ceph_object_layout { struct ceph_pg ol_pgid; /* raw pg, with _full_ ps precision. */ __le32 ol_stripe_unit; /* for per-object parity, if any */ } __attribute__ ((packed)); /* * compound epoch+version, used by storage layer to serialize mutations */ struct ceph_eversion { __le32 epoch; __le64 version; } __attribute__ ((packed)); /* * osd map bits */ /* status bits */ #define CEPH_OSD_EXISTS (1<<0) #define CEPH_OSD_UP (1<<1) #define CEPH_OSD_AUTOOUT (1<<2) /* osd was automatically marked out */ #define CEPH_OSD_NEW (1<<3) /* osd is new, never marked in */ extern const char *ceph_osd_state_name(int s); /* osd weights. fixed point value: 0x10000 == 1.0 ("in"), 0 == "out" */ #define CEPH_OSD_IN 0x10000 #define CEPH_OSD_OUT 0 #define CEPH_OSD_MAX_PRIMARY_AFFINITY 0x10000 #define CEPH_OSD_DEFAULT_PRIMARY_AFFINITY 0x10000 /* * osd map flag bits */ #define CEPH_OSDMAP_NEARFULL (1<<0) /* sync writes (near ENOSPC) */ #define CEPH_OSDMAP_FULL (1<<1) /* no data writes (ENOSPC) */ #define CEPH_OSDMAP_PAUSERD (1<<2) /* pause all reads */ #define CEPH_OSDMAP_PAUSEWR (1<<3) /* pause all writes */ #define CEPH_OSDMAP_PAUSEREC (1<<4) /* pause recovery */ #define CEPH_OSDMAP_NOUP (1<<5) /* block osd boot */ #define CEPH_OSDMAP_NODOWN (1<<6) /* block osd mark-down/failure */ #define CEPH_OSDMAP_NOOUT (1<<7) /* block osd auto mark-out */ #define CEPH_OSDMAP_NOIN (1<<8) /* block osd auto mark-in */ #define CEPH_OSDMAP_NOBACKFILL (1<<9) /* block osd backfill */ #define CEPH_OSDMAP_NORECOVER (1<<10) /* block osd recovery and backfill */ #define CEPH_OSDMAP_NOSCRUB (1<<11) /* block periodic scrub */ #define CEPH_OSDMAP_NODEEP_SCRUB (1<<12) /* block periodic deep-scrub */ #define CEPH_OSDMAP_NOTIERAGENT (1<<13) /* disable tiering agent */ /* * The error code to return when an OSD can't handle a write * because it is too large. */ #define OSD_WRITETOOBIG EMSGSIZE /* * osd ops * * WARNING: do not use these op codes directly. Use the helpers * defined below instead. In certain cases, op code behavior was * redefined, resulting in special-cases in the helpers. */ #define CEPH_OSD_OP_MODE 0xf000 #define CEPH_OSD_OP_MODE_RD 0x1000 #define CEPH_OSD_OP_MODE_WR 0x2000 #define CEPH_OSD_OP_MODE_RMW 0x3000 #define CEPH_OSD_OP_MODE_SUB 0x4000 #define CEPH_OSD_OP_MODE_CACHE 0x8000 #define CEPH_OSD_OP_TYPE 0x0f00 #define CEPH_OSD_OP_TYPE_LOCK 0x0100 #define CEPH_OSD_OP_TYPE_DATA 0x0200 #define CEPH_OSD_OP_TYPE_ATTR 0x0300 #define CEPH_OSD_OP_TYPE_EXEC 0x0400 #define CEPH_OSD_OP_TYPE_PG 0x0500 #define CEPH_OSD_OP_TYPE_MULTI 0x0600 /* multiobject */ enum { /** data **/ /* read */ CEPH_OSD_OP_READ = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 1, CEPH_OSD_OP_STAT = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 2, CEPH_OSD_OP_MAPEXT = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 3, /* fancy read */ CEPH_OSD_OP_MASKTRUNC = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 4, CEPH_OSD_OP_SPARSE_READ = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 5, CEPH_OSD_OP_NOTIFY = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 6, CEPH_OSD_OP_NOTIFY_ACK = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 7, /* versioning */ CEPH_OSD_OP_ASSERT_VER = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 8, CEPH_OSD_OP_LIST_WATCHERS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 9, CEPH_OSD_OP_LIST_SNAPS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 10, /* sync */ CEPH_OSD_OP_SYNC_READ = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 11, /* write */ CEPH_OSD_OP_WRITE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 1, CEPH_OSD_OP_WRITEFULL = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 2, CEPH_OSD_OP_TRUNCATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 3, CEPH_OSD_OP_ZERO = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 4, CEPH_OSD_OP_DELETE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 5, /* fancy write */ CEPH_OSD_OP_APPEND = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 6, CEPH_OSD_OP_STARTSYNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 7, CEPH_OSD_OP_SETTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 8, CEPH_OSD_OP_TRIMTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 9, CEPH_OSD_OP_TMAPUP = CEPH_OSD_OP_MODE_RMW | CEPH_OSD_OP_TYPE_DATA | 10, CEPH_OSD_OP_TMAPPUT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 11, CEPH_OSD_OP_TMAPGET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 12, CEPH_OSD_OP_CREATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13, CEPH_OSD_OP_ROLLBACK= CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 14, CEPH_OSD_OP_WATCH = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 15, /* omap */ CEPH_OSD_OP_OMAPGETKEYS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 17, CEPH_OSD_OP_OMAPGETVALS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 18, CEPH_OSD_OP_OMAPGETHEADER = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 19, CEPH_OSD_OP_OMAPGETVALSBYKEYS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 20, CEPH_OSD_OP_OMAPSETVALS = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 21, CEPH_OSD_OP_OMAPSETHEADER = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 22, CEPH_OSD_OP_OMAPCLEAR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 23, CEPH_OSD_OP_OMAPRMKEYS = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 24, CEPH_OSD_OP_OMAP_CMP = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 25, /* tiering */ CEPH_OSD_OP_COPY_FROM = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 26, CEPH_OSD_OP_COPY_GET_CLASSIC = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 27, CEPH_OSD_OP_UNDIRTY = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 28, CEPH_OSD_OP_ISDIRTY = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 29, CEPH_OSD_OP_COPY_GET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 30, CEPH_OSD_OP_CACHE_FLUSH = CEPH_OSD_OP_MODE_CACHE | CEPH_OSD_OP_TYPE_DATA | 31, CEPH_OSD_OP_CACHE_EVICT = CEPH_OSD_OP_MODE_CACHE | CEPH_OSD_OP_TYPE_DATA | 32, CEPH_OSD_OP_CACHE_TRY_FLUSH = CEPH_OSD_OP_MODE_CACHE | CEPH_OSD_OP_TYPE_DATA | 33, /* convert tmap to omap */ CEPH_OSD_OP_TMAP2OMAP = CEPH_OSD_OP_MODE_RMW | CEPH_OSD_OP_TYPE_DATA | 34, /* hints */ CEPH_OSD_OP_SETALLOCHINT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 35, /** multi **/ CEPH_OSD_OP_CLONERANGE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_MULTI | 1, CEPH_OSD_OP_ASSERT_SRC_VERSION = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_MULTI | 2, CEPH_OSD_OP_SRC_CMPXATTR = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_MULTI | 3, /** attrs **/ /* read */ CEPH_OSD_OP_GETXATTR = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 1, CEPH_OSD_OP_GETXATTRS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 2, CEPH_OSD_OP_CMPXATTR = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 3, /* write */ CEPH_OSD_OP_SETXATTR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 1, CEPH_OSD_OP_SETXATTRS = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 2, CEPH_OSD_OP_RESETXATTRS = CEPH_OSD_OP_MODE_WR|CEPH_OSD_OP_TYPE_ATTR | 3, CEPH_OSD_OP_RMXATTR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 4, /** subop **/ CEPH_OSD_OP_PULL = CEPH_OSD_OP_MODE_SUB | 1, CEPH_OSD_OP_PUSH = CEPH_OSD_OP_MODE_SUB | 2, CEPH_OSD_OP_BALANCEREADS = CEPH_OSD_OP_MODE_SUB | 3, CEPH_OSD_OP_UNBALANCEREADS = CEPH_OSD_OP_MODE_SUB | 4, CEPH_OSD_OP_SCRUB = CEPH_OSD_OP_MODE_SUB | 5, CEPH_OSD_OP_SCRUB_RESERVE = CEPH_OSD_OP_MODE_SUB | 6, CEPH_OSD_OP_SCRUB_UNRESERVE = CEPH_OSD_OP_MODE_SUB | 7, CEPH_OSD_OP_SCRUB_STOP = CEPH_OSD_OP_MODE_SUB | 8, CEPH_OSD_OP_SCRUB_MAP = CEPH_OSD_OP_MODE_SUB | 9, /** lock **/ CEPH_OSD_OP_WRLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 1, CEPH_OSD_OP_WRUNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 2, CEPH_OSD_OP_RDLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 3, CEPH_OSD_OP_RDUNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 4, CEPH_OSD_OP_UPLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 5, CEPH_OSD_OP_DNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 6, /** exec **/ /* note: the RD bit here is wrong; see special-case below in helper */ CEPH_OSD_OP_CALL = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_EXEC | 1, /** pg **/ CEPH_OSD_OP_PGLS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 1, CEPH_OSD_OP_PGLS_FILTER = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 2, CEPH_OSD_OP_PG_HITSET_LS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 3, CEPH_OSD_OP_PG_HITSET_GET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 4, }; static inline int ceph_osd_op_type_lock(int op) { return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_LOCK; } static inline int ceph_osd_op_type_data(int op) { return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_DATA; } static inline int ceph_osd_op_type_attr(int op) { return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_ATTR; } static inline int ceph_osd_op_type_exec(int op) { return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_EXEC; } static inline int ceph_osd_op_type_pg(int op) { return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_PG; } static inline int ceph_osd_op_type_multi(int op) { return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_MULTI; } static inline int ceph_osd_op_mode_subop(int op) { return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_SUB; } static inline int ceph_osd_op_mode_read(int op) { return (op & CEPH_OSD_OP_MODE_RD) && op != CEPH_OSD_OP_CALL; } static inline int ceph_osd_op_mode_modify(int op) { return op & CEPH_OSD_OP_MODE_WR; } static inline int ceph_osd_op_mode_cache(int op) { return op & CEPH_OSD_OP_MODE_CACHE; } /* * note that the following tmap stuff is also defined in the ceph librados.h * and objclass.h. Any modification here needs to be updated there */ #define CEPH_OSD_TMAP_HDR 'h' #define CEPH_OSD_TMAP_SET 's' #define CEPH_OSD_TMAP_CREATE 'c' /* create key */ #define CEPH_OSD_TMAP_RM 'r' #define CEPH_OSD_TMAP_RMSLOPPY 'R' extern const char *ceph_osd_op_name(int op); /* * osd op flags * * An op may be READ, WRITE, or READ|WRITE. */ enum { CEPH_OSD_FLAG_ACK = 0x0001, /* want (or is) "ack" ack */ CEPH_OSD_FLAG_ONNVRAM = 0x0002, /* want (or is) "onnvram" ack */ CEPH_OSD_FLAG_ONDISK = 0x0004, /* want (or is) "ondisk" ack */ CEPH_OSD_FLAG_RETRY = 0x0008, /* resend attempt */ CEPH_OSD_FLAG_READ = 0x0010, /* op may read */ CEPH_OSD_FLAG_WRITE = 0x0020, /* op may write */ CEPH_OSD_FLAG_ORDERSNAP = 0x0040, /* EOLDSNAP if snapc is out of order */ CEPH_OSD_FLAG_PEERSTAT_OLD = 0x0080, /* DEPRECATED msg includes osd_peer_stat */ CEPH_OSD_FLAG_BALANCE_READS = 0x0100, CEPH_OSD_FLAG_PARALLELEXEC = 0x0200, /* execute op in parallel */ CEPH_OSD_FLAG_PGOP = 0x0400, /* pg op, no object */ CEPH_OSD_FLAG_EXEC = 0x0800, /* op may exec */ CEPH_OSD_FLAG_EXEC_PUBLIC = 0x1000, /* DEPRECATED op may exec (public) */ CEPH_OSD_FLAG_LOCALIZE_READS = 0x2000, /* read from nearby replica, if any */ CEPH_OSD_FLAG_RWORDERED = 0x4000, /* order wrt concurrent reads */ CEPH_OSD_FLAG_IGNORE_CACHE = 0x8000, /* ignore cache logic */ CEPH_OSD_FLAG_SKIPRWLOCKS = 0x10000, /* skip rw locks */ CEPH_OSD_FLAG_IGNORE_OVERLAY =0x20000, /* ignore pool overlay */ CEPH_OSD_FLAG_FLUSH = 0x40000, /* this is part of flush */ CEPH_OSD_FLAG_MAP_SNAP_CLONE =0x80000, /* map snap direct to clone id */ CEPH_OSD_FLAG_ENFORCE_SNAPC =0x100000, /* use snapc provided even if pool uses pool snaps */ }; enum { CEPH_OSD_OP_FLAG_EXCL = 1, /* EXCL object create */ CEPH_OSD_OP_FLAG_FAILOK = 2, /* continue despite failure */ }; #define EOLDSNAPC 85 /* ORDERSNAP flag set; writer has old snapc*/ #define EBLACKLISTED 108 /* blacklisted */ /* xattr comparison */ enum { CEPH_OSD_CMPXATTR_OP_EQ = 1, CEPH_OSD_CMPXATTR_OP_NE = 2, CEPH_OSD_CMPXATTR_OP_GT = 3, CEPH_OSD_CMPXATTR_OP_GTE = 4, CEPH_OSD_CMPXATTR_OP_LT = 5, CEPH_OSD_CMPXATTR_OP_LTE = 6 }; enum { CEPH_OSD_CMPXATTR_MODE_STRING = 1, CEPH_OSD_CMPXATTR_MODE_U64 = 2 }; enum { CEPH_OSD_COPY_FROM_FLAG_FLUSH = 1, /* part of a flush operation */ CEPH_OSD_COPY_FROM_FLAG_IGNORE_OVERLAY = 2, /* ignore pool overlay */ CEPH_OSD_COPY_FROM_FLAG_IGNORE_CACHE = 4, /* ignore osd cache logic */ CEPH_OSD_COPY_FROM_FLAG_MAP_SNAP_CLONE = 8, /* map snap direct to * cloneid */ }; enum { CEPH_OSD_TMAP2OMAP_NULLOK = 1, }; /* * an individual object operation. each may be accompanied by some data * payload */ struct ceph_osd_op { __le16 op; /* CEPH_OSD_OP_* */ __le32 flags; /* CEPH_OSD_FLAG_* */ union { struct { __le64 offset, length; __le64 truncate_size; __le32 truncate_seq; } __attribute__ ((packed)) extent; struct { __le32 name_len; __le32 value_len; __u8 cmp_op; /* CEPH_OSD_CMPXATTR_OP_* */ __u8 cmp_mode; /* CEPH_OSD_CMPXATTR_MODE_* */ } __attribute__ ((packed)) xattr; struct { __u8 class_len; __u8 method_len; __u8 argc; __le32 indata_len; } __attribute__ ((packed)) cls; struct { __le64 count; __le32 start_epoch; /* for the pgls sequence */ } __attribute__ ((packed)) pgls; struct { __le64 snapid; } __attribute__ ((packed)) snap; struct { __le64 cookie; __le64 ver; __u8 flag; /* 0 = unwatch, 1 = watch */ } __attribute__ ((packed)) watch; struct { __le64 unused; __le64 ver; } __attribute__ ((packed)) assert_ver; struct { __le64 offset, length; __le64 src_offset; } __attribute__ ((packed)) clonerange; struct { __le64 max; /* max data in reply */ } __attribute__ ((packed)) copy_get; struct { __le64 snapid; __le64 src_version; __u8 flags; } __attribute__ ((packed)) copy_from; struct { struct ceph_timespec stamp; } __attribute__ ((packed)) hit_set_get; struct { __u8 flags; } __attribute__ ((packed)) tmap2omap; struct { __le64 expected_object_size; __le64 expected_write_size; } __attribute__ ((packed)) alloc_hint; }; __le32 payload_len; } __attribute__ ((packed)); struct ceph_osd_reply_head { __le32 client_inc; /* client incarnation */ __le32 flags; struct ceph_object_layout layout; __le32 osdmap_epoch; struct ceph_eversion reassert_version; /* for replaying uncommitted */ __le32 result; /* result code */ __le32 object_len; /* length of object name */ __le32 num_ops; struct ceph_osd_op ops[0]; /* ops[], object */ } __attribute__ ((packed)); #endif ceph-0.80.11/src/include/ceph_fs.h0000664000175100017510000006014212623076744020672 0ustar jenkins-buildjenkins-build/* * ceph_fs.h - Ceph constants and data types to share between kernel and * user space. * * Most types in this file are defined as little-endian, and are * primarily intended to describe data structures that pass over the * wire or that are stored on disk. * * LGPL2 */ #ifndef CEPH_FS_H #define CEPH_FS_H #include "msgr.h" #include "rados.h" /* * subprotocol versions. when specific messages types or high-level * protocols change, bump the affected components. we keep rev * internal cluster protocols separately from the public, * client-facing protocol. */ #define CEPH_OSDC_PROTOCOL 24 /* server/client */ #define CEPH_MDSC_PROTOCOL 32 /* server/client */ #define CEPH_MONC_PROTOCOL 15 /* server/client */ #define CEPH_INO_ROOT 1 #define CEPH_INO_CEPH 2 /* hidden .ceph dir */ #define CEPH_INO_DOTDOT 3 /* used by ceph fuse for parent (..) */ /* arbitrary limit on max # of monitors (cluster of 3 is typical) */ #define CEPH_MAX_MON 31 /* * ceph_file_layout - describe data layout for a file/inode */ struct ceph_file_layout { /* file -> object mapping */ __le32 fl_stripe_unit; /* stripe unit, in bytes. must be multiple of page size. */ __le32 fl_stripe_count; /* over this many objects */ __le32 fl_object_size; /* until objects are this big, then move to new objects */ __le32 fl_cas_hash; /* UNUSED. 0 = none; 1 = sha256 */ /* pg -> disk layout */ __le32 fl_object_stripe_unit; /* UNUSED. for per-object parity, if any */ /* object -> pg layout */ __le32 fl_unused; /* unused; used to be preferred primary for pg (-1 for none) */ __le32 fl_pg_pool; /* namespace, crush ruleset, rep level */ } __attribute__ ((packed)); #define CEPH_MIN_STRIPE_UNIT 65536 int ceph_file_layout_is_valid(const struct ceph_file_layout *layout); struct ceph_dir_layout { __u8 dl_dir_hash; /* see ceph_hash.h for ids */ __u8 dl_unused1; __u16 dl_unused2; __u32 dl_unused3; } __attribute__ ((packed)); /* crypto algorithms */ #define CEPH_CRYPTO_NONE 0x0 #define CEPH_CRYPTO_AES 0x1 #define CEPH_AES_IV "cephsageyudagreg" /* security/authentication protocols */ #define CEPH_AUTH_UNKNOWN 0x0 #define CEPH_AUTH_NONE 0x1 #define CEPH_AUTH_CEPHX 0x2 #define CEPH_AUTH_UID_DEFAULT ((__u64) -1) /********************************************* * message layer */ /* * message types */ /* misc */ #define CEPH_MSG_SHUTDOWN 1 #define CEPH_MSG_PING 2 /* client <-> monitor */ #define CEPH_MSG_MON_MAP 4 #define CEPH_MSG_MON_GET_MAP 5 #define CEPH_MSG_STATFS 13 #define CEPH_MSG_STATFS_REPLY 14 #define CEPH_MSG_MON_SUBSCRIBE 15 #define CEPH_MSG_MON_SUBSCRIBE_ACK 16 #define CEPH_MSG_AUTH 17 #define CEPH_MSG_AUTH_REPLY 18 #define CEPH_MSG_MON_GET_VERSION 19 #define CEPH_MSG_MON_GET_VERSION_REPLY 20 /* client <-> mds */ #define CEPH_MSG_MDS_MAP 21 #define CEPH_MSG_CLIENT_SESSION 22 #define CEPH_MSG_CLIENT_RECONNECT 23 #define CEPH_MSG_CLIENT_REQUEST 24 #define CEPH_MSG_CLIENT_REQUEST_FORWARD 25 #define CEPH_MSG_CLIENT_REPLY 26 #define CEPH_MSG_CLIENT_CAPS 0x310 #define CEPH_MSG_CLIENT_LEASE 0x311 #define CEPH_MSG_CLIENT_SNAP 0x312 #define CEPH_MSG_CLIENT_CAPRELEASE 0x313 /* pool ops */ #define CEPH_MSG_POOLOP_REPLY 48 #define CEPH_MSG_POOLOP 49 /* osd */ #define CEPH_MSG_OSD_MAP 41 #define CEPH_MSG_OSD_OP 42 #define CEPH_MSG_OSD_OPREPLY 43 #define CEPH_MSG_WATCH_NOTIFY 44 /* watch-notify operations */ enum { WATCH_NOTIFY = 1, /* notifying watcher */ WATCH_NOTIFY_COMPLETE = 2, /* notifier notified when done */ }; /* pool operations */ enum { POOL_OP_CREATE = 0x01, POOL_OP_DELETE = 0x02, POOL_OP_AUID_CHANGE = 0x03, POOL_OP_CREATE_SNAP = 0x11, POOL_OP_DELETE_SNAP = 0x12, POOL_OP_CREATE_UNMANAGED_SNAP = 0x21, POOL_OP_DELETE_UNMANAGED_SNAP = 0x22, }; struct ceph_mon_request_header { __le64 have_version; __le16 session_mon; __le64 session_mon_tid; } __attribute__ ((packed)); struct ceph_mon_statfs { struct ceph_mon_request_header monhdr; struct ceph_fsid fsid; } __attribute__ ((packed)); struct ceph_statfs { __le64 kb, kb_used, kb_avail; __le64 num_objects; } __attribute__ ((packed)); struct ceph_mon_statfs_reply { struct ceph_fsid fsid; __le64 version; struct ceph_statfs st; } __attribute__ ((packed)); const char *ceph_pool_op_name(int op); struct ceph_mon_poolop { struct ceph_mon_request_header monhdr; struct ceph_fsid fsid; __le32 pool; __le32 op; __le64 auid; __le64 snapid; __le32 name_len; } __attribute__ ((packed)); struct ceph_mon_poolop_reply { struct ceph_mon_request_header monhdr; struct ceph_fsid fsid; __le32 reply_code; __le32 epoch; char has_data; char data[0]; } __attribute__ ((packed)); struct ceph_mon_unmanaged_snap { __le64 snapid; } __attribute__ ((packed)); struct ceph_osd_getmap { struct ceph_mon_request_header monhdr; struct ceph_fsid fsid; __le32 start; } __attribute__ ((packed)); struct ceph_mds_getmap { struct ceph_mon_request_header monhdr; struct ceph_fsid fsid; } __attribute__ ((packed)); struct ceph_client_mount { struct ceph_mon_request_header monhdr; } __attribute__ ((packed)); #define CEPH_SUBSCRIBE_ONETIME 1 /* i want only 1 update after have */ struct ceph_mon_subscribe_item { __le64 start; __u8 flags; } __attribute__ ((packed)); struct ceph_mon_subscribe_ack { __le32 duration; /* seconds */ struct ceph_fsid fsid; } __attribute__ ((packed)); /* * mdsmap flags */ #define CEPH_MDSMAP_DOWN (1<<0) /* cluster deliberately down */ #define CEPH_MDSMAP_ALLOW_SNAPS (1<<1) /* cluster allowed to create snapshots */ /* * mds states * > 0 -> in * <= 0 -> out */ #define CEPH_MDS_STATE_DNE 0 /* down, does not exist. */ #define CEPH_MDS_STATE_STOPPED -1 /* down, once existed, but no subtrees. empty log. */ #define CEPH_MDS_STATE_BOOT -4 /* up, boot announcement. */ #define CEPH_MDS_STATE_STANDBY -5 /* up, idle. waiting for assignment. */ #define CEPH_MDS_STATE_CREATING -6 /* up, creating MDS instance. */ #define CEPH_MDS_STATE_STARTING -7 /* up, starting previously stopped mds */ #define CEPH_MDS_STATE_STANDBY_REPLAY -8 /* up, tailing active node's journal */ #define CEPH_MDS_STATE_REPLAYONCE -9 /* up, replaying an active node's journal */ #define CEPH_MDS_STATE_REPLAY 8 /* up, replaying journal. */ #define CEPH_MDS_STATE_RESOLVE 9 /* up, disambiguating distributed operations (import, rename, etc.) */ #define CEPH_MDS_STATE_RECONNECT 10 /* up, reconnect to clients */ #define CEPH_MDS_STATE_REJOIN 11 /* up, rejoining distributed cache */ #define CEPH_MDS_STATE_CLIENTREPLAY 12 /* up, replaying client operations */ #define CEPH_MDS_STATE_ACTIVE 13 /* up, active */ #define CEPH_MDS_STATE_STOPPING 14 /* up, but exporting metadata */ extern const char *ceph_mds_state_name(int s); /* * metadata lock types. * - these are bitmasks.. we can compose them * - they also define the lock ordering by the MDS * - a few of these are internal to the mds */ #define CEPH_LOCK_DVERSION 1 #define CEPH_LOCK_DN 2 #define CEPH_LOCK_ISNAP 16 #define CEPH_LOCK_IVERSION 32 /* mds internal */ #define CEPH_LOCK_IFILE 64 #define CEPH_LOCK_IAUTH 128 #define CEPH_LOCK_ILINK 256 #define CEPH_LOCK_IDFT 512 /* dir frag tree */ #define CEPH_LOCK_INEST 1024 /* mds internal */ #define CEPH_LOCK_IXATTR 2048 #define CEPH_LOCK_IFLOCK 4096 /* advisory file locks */ #define CEPH_LOCK_INO 8192 /* immutable inode bits; not a lock */ #define CEPH_LOCK_IPOLICY 16384 /* policy lock on dirs. MDS internal */ /* client_session ops */ enum { CEPH_SESSION_REQUEST_OPEN, CEPH_SESSION_OPEN, CEPH_SESSION_REQUEST_CLOSE, CEPH_SESSION_CLOSE, CEPH_SESSION_REQUEST_RENEWCAPS, CEPH_SESSION_RENEWCAPS, CEPH_SESSION_STALE, CEPH_SESSION_RECALL_STATE, CEPH_SESSION_FLUSHMSG, CEPH_SESSION_FLUSHMSG_ACK, }; extern const char *ceph_session_op_name(int op); struct ceph_mds_session_head { __le32 op; __le64 seq; struct ceph_timespec stamp; __le32 max_caps, max_leases; } __attribute__ ((packed)); /* client_request */ /* * metadata ops. * & 0x001000 -> write op * & 0x010000 -> follow symlink (e.g. stat(), not lstat()). & & 0x100000 -> use weird ino/path trace */ #define CEPH_MDS_OP_WRITE 0x001000 enum { CEPH_MDS_OP_LOOKUP = 0x00100, CEPH_MDS_OP_GETATTR = 0x00101, CEPH_MDS_OP_LOOKUPHASH = 0x00102, CEPH_MDS_OP_LOOKUPPARENT = 0x00103, CEPH_MDS_OP_LOOKUPINO = 0x00104, CEPH_MDS_OP_LOOKUPNAME = 0x00105, CEPH_MDS_OP_SETXATTR = 0x01105, CEPH_MDS_OP_RMXATTR = 0x01106, CEPH_MDS_OP_SETLAYOUT = 0x01107, CEPH_MDS_OP_SETATTR = 0x01108, CEPH_MDS_OP_SETFILELOCK= 0x01109, CEPH_MDS_OP_GETFILELOCK= 0x00110, CEPH_MDS_OP_SETDIRLAYOUT=0x0110a, CEPH_MDS_OP_MKNOD = 0x01201, CEPH_MDS_OP_LINK = 0x01202, CEPH_MDS_OP_UNLINK = 0x01203, CEPH_MDS_OP_RENAME = 0x01204, CEPH_MDS_OP_MKDIR = 0x01220, CEPH_MDS_OP_RMDIR = 0x01221, CEPH_MDS_OP_SYMLINK = 0x01222, CEPH_MDS_OP_CREATE = 0x01301, CEPH_MDS_OP_OPEN = 0x00302, CEPH_MDS_OP_READDIR = 0x00305, CEPH_MDS_OP_LOOKUPSNAP = 0x00400, CEPH_MDS_OP_MKSNAP = 0x01400, CEPH_MDS_OP_RMSNAP = 0x01401, CEPH_MDS_OP_LSSNAP = 0x00402, // internal op CEPH_MDS_OP_FRAGMENTDIR= 0x01500, CEPH_MDS_OP_EXPORTDIR = 0x01501, }; extern const char *ceph_mds_op_name(int op); #define CEPH_SETATTR_MODE 1 #define CEPH_SETATTR_UID 2 #define CEPH_SETATTR_GID 4 #define CEPH_SETATTR_MTIME 8 #define CEPH_SETATTR_ATIME 16 #define CEPH_SETATTR_SIZE 32 #define CEPH_SETATTR_CTIME 64 /* * Ceph setxattr request flags. */ #define CEPH_XATTR_CREATE (1 << 0) #define CEPH_XATTR_REPLACE (1 << 1) #define CEPH_XATTR_REMOVE (1 << 31) union ceph_mds_request_args { struct { __le32 mask; /* CEPH_CAP_* */ } __attribute__ ((packed)) getattr; struct { __le32 mode; __le32 uid; __le32 gid; struct ceph_timespec mtime; struct ceph_timespec atime; __le64 size, old_size; /* old_size needed by truncate */ __le32 mask; /* CEPH_SETATTR_* */ } __attribute__ ((packed)) setattr; struct { __le32 frag; /* which dir fragment */ __le32 max_entries; /* how many dentries to grab */ __le32 max_bytes; } __attribute__ ((packed)) readdir; struct { __le32 mode; __le32 rdev; } __attribute__ ((packed)) mknod; struct { __le32 mode; } __attribute__ ((packed)) mkdir; struct { __le32 flags; __le32 mode; __le32 stripe_unit; /* layout for newly created file */ __le32 stripe_count; /* ... */ __le32 object_size; __le32 pool; /* if >= 0 and CREATEPOOLID feature */ __le32 unused; /* used to be preferred */ __le64 old_size; /* if O_TRUNC */ } __attribute__ ((packed)) open; struct { __le32 flags; } __attribute__ ((packed)) setxattr; struct { struct ceph_file_layout layout; } __attribute__ ((packed)) setlayout; struct { __u8 rule; /* currently fcntl or flock */ __u8 type; /* shared, exclusive, remove*/ __le64 owner; /* who requests/holds the lock */ __le64 pid; /* process id requesting the lock */ __le64 start; /* initial location to lock */ __le64 length; /* num bytes to lock from start */ __u8 wait; /* will caller wait for lock to become available? */ } __attribute__ ((packed)) filelock_change; } __attribute__ ((packed)); #define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */ #define CEPH_MDS_FLAG_WANT_DENTRY 2 /* want dentry in reply */ struct ceph_mds_request_head { __le64 oldest_client_tid; __le32 mdsmap_epoch; /* on client */ __le32 flags; /* CEPH_MDS_FLAG_* */ __u8 num_retry, num_fwd; /* count retry, fwd attempts */ __le16 num_releases; /* # include cap/lease release records */ __le32 op; /* mds op code */ __le32 caller_uid, caller_gid; __le64 ino; /* use this ino for openc, mkdir, mknod, etc. (if replaying) */ union ceph_mds_request_args args; } __attribute__ ((packed)); /* cap/lease release record */ struct ceph_mds_request_release { __le64 ino, cap_id; /* ino and unique cap id */ __le32 caps, wanted; /* new issued, wanted */ __le32 seq, issue_seq, mseq; __le32 dname_seq; /* if releasing a dentry lease, a */ __le32 dname_len; /* string follows. */ } __attribute__ ((packed)); /* client reply */ struct ceph_mds_reply_head { __le32 op; __le32 result; __le32 mdsmap_epoch; __u8 safe; /* true if committed to disk */ __u8 is_dentry, is_target; /* true if dentry, target inode records are included with reply */ } __attribute__ ((packed)); /* one for each node split */ struct ceph_frag_tree_split { __le32 frag; /* this frag splits... */ __le32 by; /* ...by this many bits */ } __attribute__ ((packed)); struct ceph_frag_tree_head { __le32 nsplits; /* num ceph_frag_tree_split records */ struct ceph_frag_tree_split splits[]; } __attribute__ ((packed)); /* capability issue, for bundling with mds reply */ struct ceph_mds_reply_cap { __le32 caps, wanted; /* caps issued, wanted */ __le64 cap_id; __le32 seq, mseq; __le64 realm; /* snap realm */ __u8 flags; /* CEPH_CAP_FLAG_* */ } __attribute__ ((packed)); #define CEPH_CAP_FLAG_AUTH (1 << 0) /* cap is issued by auth mds */ #define CEPH_CAP_FLAG_RELEASE (1 << 1) /* ask client to release the cap */ /* inode record, for bundling with mds reply */ struct ceph_mds_reply_inode { __le64 ino; __le64 snapid; __le32 rdev; __le64 version; /* inode version */ __le64 xattr_version; /* version for xattr blob */ struct ceph_mds_reply_cap cap; /* caps issued for this inode */ struct ceph_file_layout layout; struct ceph_timespec ctime, mtime, atime; __le32 time_warp_seq; __le64 size, max_size, truncate_size; __le32 truncate_seq; __le32 mode, uid, gid; __le32 nlink; __le64 files, subdirs, rbytes, rfiles, rsubdirs; /* dir stats */ struct ceph_timespec rctime; struct ceph_frag_tree_head fragtree; /* (must be at end of struct) */ } __attribute__ ((packed)); /* followed by frag array, symlink string, dir layout, xattr blob */ /* reply_lease follows dname, and reply_inode */ struct ceph_mds_reply_lease { __le16 mask; /* lease type(s) */ __le32 duration_ms; /* lease duration */ __le32 seq; } __attribute__ ((packed)); struct ceph_mds_reply_dirfrag { __le32 frag; /* fragment */ __le32 auth; /* auth mds, if this is a delegation point */ __le32 ndist; /* number of mds' this is replicated on */ __le32 dist[]; } __attribute__ ((packed)); #define CEPH_LOCK_FCNTL 1 #define CEPH_LOCK_FLOCK 2 #define CEPH_LOCK_FCNTL_INTR 3 #define CEPH_LOCK_FLOCK_INTR 4 #define CEPH_LOCK_SHARED 1 #define CEPH_LOCK_EXCL 2 #define CEPH_LOCK_UNLOCK 4 struct ceph_filelock { __le64 start;/* file offset to start lock at */ __le64 length; /* num bytes to lock; 0 for all following start */ __le64 client; /* which client holds the lock */ __le64 owner; /* who requests/holds the lock */ __le64 pid; /* process id holding the lock on the client */ __u8 type; /* shared lock, exclusive lock, or unlock */ } __attribute__ ((packed)); /* file access modes */ #define CEPH_FILE_MODE_PIN 0 #define CEPH_FILE_MODE_RD 1 #define CEPH_FILE_MODE_WR 2 #define CEPH_FILE_MODE_RDWR 3 /* RD | WR */ #define CEPH_FILE_MODE_LAZY 4 /* lazy io */ #define CEPH_FILE_MODE_NUM 8 /* bc these are bit fields.. mostly */ int ceph_flags_to_mode(int flags); /* inline data state */ #define CEPH_INLINE_NONE ((__u64)-1) #define CEPH_INLINE_MAX_SIZE CEPH_MIN_STRIPE_UNIT /* capability bits */ #define CEPH_CAP_PIN 1 /* no specific capabilities beyond the pin */ /* generic cap bits */ #define CEPH_CAP_GSHARED 1 /* client can reads */ #define CEPH_CAP_GEXCL 2 /* client can read and update */ #define CEPH_CAP_GCACHE 4 /* (file) client can cache reads */ #define CEPH_CAP_GRD 8 /* (file) client can read */ #define CEPH_CAP_GWR 16 /* (file) client can write */ #define CEPH_CAP_GBUFFER 32 /* (file) client can buffer writes */ #define CEPH_CAP_GWREXTEND 64 /* (file) client can extend EOF */ #define CEPH_CAP_GLAZYIO 128 /* (file) client can perform lazy io */ #define CEPH_CAP_SIMPLE_BITS 2 #define CEPH_CAP_FILE_BITS 8 /* per-lock shift */ #define CEPH_CAP_SAUTH 2 #define CEPH_CAP_SLINK 4 #define CEPH_CAP_SXATTR 6 #define CEPH_CAP_SFILE 8 #define CEPH_CAP_SFLOCK 20 #define CEPH_CAP_BITS 22 /* composed values */ #define CEPH_CAP_AUTH_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SAUTH) #define CEPH_CAP_AUTH_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SAUTH) #define CEPH_CAP_LINK_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SLINK) #define CEPH_CAP_LINK_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SLINK) #define CEPH_CAP_XATTR_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SXATTR) #define CEPH_CAP_XATTR_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SXATTR) #define CEPH_CAP_FILE(x) (x << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_CACHE (CEPH_CAP_GCACHE << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_RD (CEPH_CAP_GRD << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_WR (CEPH_CAP_GWR << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_BUFFER (CEPH_CAP_GBUFFER << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE) #define CEPH_CAP_FILE_LAZYIO (CEPH_CAP_GLAZYIO << CEPH_CAP_SFILE) #define CEPH_CAP_FLOCK_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFLOCK) #define CEPH_CAP_FLOCK_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFLOCK) /* cap masks (for getattr) */ #define CEPH_STAT_CAP_INODE CEPH_CAP_PIN #define CEPH_STAT_CAP_TYPE CEPH_CAP_PIN /* mode >> 12 */ #define CEPH_STAT_CAP_SYMLINK CEPH_CAP_PIN #define CEPH_STAT_CAP_UID CEPH_CAP_AUTH_SHARED #define CEPH_STAT_CAP_GID CEPH_CAP_AUTH_SHARED #define CEPH_STAT_CAP_MODE CEPH_CAP_AUTH_SHARED #define CEPH_STAT_CAP_NLINK CEPH_CAP_LINK_SHARED #define CEPH_STAT_CAP_LAYOUT CEPH_CAP_FILE_SHARED #define CEPH_STAT_CAP_MTIME CEPH_CAP_FILE_SHARED #define CEPH_STAT_CAP_SIZE CEPH_CAP_FILE_SHARED #define CEPH_STAT_CAP_ATIME CEPH_CAP_FILE_SHARED /* fixme */ #define CEPH_STAT_CAP_XATTR CEPH_CAP_XATTR_SHARED #define CEPH_STAT_CAP_INODE_ALL (CEPH_CAP_PIN | \ CEPH_CAP_AUTH_SHARED | \ CEPH_CAP_LINK_SHARED | \ CEPH_CAP_FILE_SHARED | \ CEPH_CAP_XATTR_SHARED) #define CEPH_STAT_CAP_INLINE_DATA (CEPH_CAP_FILE_SHARED | \ CEPH_CAP_FILE_RD) #define CEPH_CAP_ANY_SHARED (CEPH_CAP_AUTH_SHARED | \ CEPH_CAP_LINK_SHARED | \ CEPH_CAP_XATTR_SHARED | \ CEPH_CAP_FILE_SHARED) #define CEPH_CAP_ANY_RD (CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_RD | \ CEPH_CAP_FILE_CACHE) #define CEPH_CAP_ANY_EXCL (CEPH_CAP_AUTH_EXCL | \ CEPH_CAP_LINK_EXCL | \ CEPH_CAP_XATTR_EXCL | \ CEPH_CAP_FILE_EXCL) #define CEPH_CAP_ANY_FILE_WR (CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | \ CEPH_CAP_FILE_EXCL) #define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR) #define CEPH_CAP_ANY (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \ CEPH_CAP_ANY_FILE_WR | CEPH_CAP_FILE_LAZYIO | \ CEPH_CAP_PIN) #define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \ CEPH_LOCK_IXATTR) int ceph_caps_for_mode(int mode); enum { CEPH_CAP_OP_GRANT, /* mds->client grant */ CEPH_CAP_OP_REVOKE, /* mds->client revoke */ CEPH_CAP_OP_TRUNC, /* mds->client trunc notify */ CEPH_CAP_OP_EXPORT, /* mds has exported the cap */ CEPH_CAP_OP_IMPORT, /* mds has imported the cap */ CEPH_CAP_OP_UPDATE, /* client->mds update */ CEPH_CAP_OP_DROP, /* client->mds drop cap bits */ CEPH_CAP_OP_FLUSH, /* client->mds cap writeback */ CEPH_CAP_OP_FLUSH_ACK, /* mds->client flushed */ CEPH_CAP_OP_FLUSHSNAP, /* client->mds flush snapped metadata */ CEPH_CAP_OP_FLUSHSNAP_ACK, /* mds->client flushed snapped metadata */ CEPH_CAP_OP_RELEASE, /* client->mds release (clean) cap */ CEPH_CAP_OP_RENEW, /* client->mds renewal request */ }; extern const char *ceph_cap_op_name(int op); /* extra info for cap import/export */ struct ceph_mds_cap_peer { __le64 cap_id; __le32 seq; __le32 mseq; __le32 mds; __u8 flags; } __attribute__ ((packed)); /* * caps message, used for capability callbacks, acks, requests, etc. */ struct ceph_mds_caps { __le32 op; /* CEPH_CAP_OP_* */ __le64 ino, realm; __le64 cap_id; __le32 seq, issue_seq; __le32 caps, wanted, dirty; /* latest issued/wanted/dirty */ __le32 migrate_seq; __le64 snap_follows; __le32 snap_trace_len; /* authlock */ __le32 uid, gid, mode; /* linklock */ __le32 nlink; /* xattrlock */ __le32 xattr_len; __le64 xattr_version; union { /* all except export */ struct { /* filelock */ __le64 size, max_size, truncate_size; __le32 truncate_seq; struct ceph_timespec mtime, atime, ctime; struct ceph_file_layout layout; __le32 time_warp_seq; }; /* export message */ struct ceph_mds_cap_peer peer; }; } __attribute__ ((packed)); /* cap release msg head */ struct ceph_mds_cap_release { __le32 num; /* number of cap_items that follow */ } __attribute__ ((packed)); struct ceph_mds_cap_item { __le64 ino; __le64 cap_id; __le32 migrate_seq, seq; } __attribute__ ((packed)); #define CEPH_MDS_LEASE_REVOKE 1 /* mds -> client */ #define CEPH_MDS_LEASE_RELEASE 2 /* client -> mds */ #define CEPH_MDS_LEASE_RENEW 3 /* client <-> mds */ #define CEPH_MDS_LEASE_REVOKE_ACK 4 /* client -> mds */ extern const char *ceph_lease_op_name(int o); /* lease msg header */ struct ceph_mds_lease { __u8 action; /* CEPH_MDS_LEASE_* */ __le16 mask; /* which lease */ __le64 ino; __le64 first, last; /* snap range */ __le32 seq; __le32 duration_ms; /* duration of renewal */ } __attribute__ ((packed)); /* followed by a __le32+string for dname */ /* client reconnect */ struct ceph_mds_cap_reconnect { __le64 cap_id; __le32 wanted; __le32 issued; __le64 snaprealm; __le64 pathbase; /* base ino for our path to this ino */ __le32 flock_len; /* size of flock state blob, if any */ } __attribute__ ((packed)); /* followed by flock blob */ struct ceph_mds_cap_reconnect_v1 { __le64 cap_id; __le32 wanted; __le32 issued; __le64 size; struct ceph_timespec mtime, atime; __le64 snaprealm; __le64 pathbase; /* base ino for our path to this ino */ } __attribute__ ((packed)); struct ceph_mds_snaprealm_reconnect { __le64 ino; /* snap realm base */ __le64 seq; /* snap seq for this snap realm */ __le64 parent; /* parent realm */ } __attribute__ ((packed)); /* * snaps */ enum { CEPH_SNAP_OP_UPDATE, /* CREATE or DESTROY */ CEPH_SNAP_OP_CREATE, CEPH_SNAP_OP_DESTROY, CEPH_SNAP_OP_SPLIT, }; extern const char *ceph_snap_op_name(int o); /* snap msg header */ struct ceph_mds_snap_head { __le32 op; /* CEPH_SNAP_OP_* */ __le64 split; /* ino to split off, if any */ __le32 num_split_inos; /* # inos belonging to new child realm */ __le32 num_split_realms; /* # child realms udner new child realm */ __le32 trace_len; /* size of snap trace blob */ } __attribute__ ((packed)); /* followed by split ino list, then split realms, then the trace blob */ /* * encode info about a snaprealm, as viewed by a client */ struct ceph_mds_snap_realm { __le64 ino; /* ino */ __le64 created; /* snap: when created */ __le64 parent; /* ino: parent realm */ __le64 parent_since; /* snap: same parent since */ __le64 seq; /* snap: version */ __le32 num_snaps; __le32 num_prior_parent_snaps; } __attribute__ ((packed)); /* followed by my snap list, then prior parent snap list */ #endif ceph-0.80.11/src/include/str_map.h0000664000175100017510000000354412623076744020733 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #ifndef CEPH_STRMAP_H #define CEPH_STRMAP_H #include #include #include /** * Parse **str** and set **str_map** with the key/value pairs read * from it. The format of **str** is either a well formed JSON object * or a custom key[=value] plain text format. * * JSON is tried first. If successfully parsed into a JSON object, it * is copied into **str_map** verbatim. If it is not a JSON object ( a * string, integer etc. ), -EINVAL is returned and **ss** is set to * a human readable error message. * * If **str** is no valid JSON, it is assumed to be a string * containing white space separated key=value pairs. A white space is * either space, tab or newline. The value is optional, in which case * it defaults to an empty string. For example: * * insert your own=political statement=here * * will be parsed into: * * { "insert": "", * "your": "", * "own": "policital", * "statement": "here" } * * Returns 0 on success. * * @param [in] str JSON or plain text key/value pairs * @param [out] ss human readable message on error * @param [out] str_map key/value pairs read from str * @return **0** on success or a -EINVAL on error. */ extern int get_str_map(const std::string &str, std::ostream &ss, std::map *str_map); #endif ceph-0.80.11/src/include/compat.h0000664000175100017510000000215512623076744020546 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * Copyright (C) 2011 Stanislav Sedov * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CEPH_COMPAT_H #define CEPH_COMPAT_H #if defined(__FreeBSD__) #define ENODATA 61 #define MSG_MORE 0 #endif /* !__FreeBSD__ */ #ifndef TEMP_FAILURE_RETRY #define TEMP_FAILURE_RETRY(expression) ({ \ typeof(expression) __result; \ do { \ __result = (expression); \ } while (__result == -1 && errno == EINTR); \ __result; }) #endif #ifdef __cplusplus # define VOID_TEMP_FAILURE_RETRY(expression) \ static_cast(TEMP_FAILURE_RETRY(expression)) #else # define VOID_TEMP_FAILURE_RETRY(expression) \ do { (void)TEMP_FAILURE_RETRY(expression); } while (0) #endif #if defined(__FreeBSD__) || defined(__APPLE__) #define lseek64(fd, offset, whence) lseek(fd, offset, whence) #endif #endif /* !CEPH_COMPAT_H */ ceph-0.80.11/src/include/ceph_features.h0000664000175100017510000001201312623076744022072 0ustar jenkins-buildjenkins-build#ifndef __CEPH_FEATURES #define __CEPH_FEATURES /* * feature bits */ #define CEPH_FEATURE_UID (1ULL<<0) #define CEPH_FEATURE_NOSRCADDR (1ULL<<1) #define CEPH_FEATURE_MONCLOCKCHECK (1ULL<<2) #define CEPH_FEATURE_FLOCK (1ULL<<3) #define CEPH_FEATURE_SUBSCRIBE2 (1ULL<<4) #define CEPH_FEATURE_MONNAMES (1ULL<<5) #define CEPH_FEATURE_RECONNECT_SEQ (1ULL<<6) #define CEPH_FEATURE_DIRLAYOUTHASH (1ULL<<7) #define CEPH_FEATURE_OBJECTLOCATOR (1ULL<<8) #define CEPH_FEATURE_PGID64 (1ULL<<9) #define CEPH_FEATURE_INCSUBOSDMAP (1ULL<<10) #define CEPH_FEATURE_PGPOOL3 (1ULL<<11) #define CEPH_FEATURE_OSDREPLYMUX (1ULL<<12) #define CEPH_FEATURE_OSDENC (1ULL<<13) #define CEPH_FEATURE_OMAP (1ULL<<14) #define CEPH_FEATURE_MONENC (1ULL<<15) #define CEPH_FEATURE_QUERY_T (1ULL<<16) #define CEPH_FEATURE_INDEP_PG_MAP (1ULL<<17) #define CEPH_FEATURE_CRUSH_TUNABLES (1ULL<<18) #define CEPH_FEATURE_CHUNKY_SCRUB (1ULL<<19) #define CEPH_FEATURE_MON_NULLROUTE (1ULL<<20) #define CEPH_FEATURE_MON_GV (1ULL<<21) #define CEPH_FEATURE_BACKFILL_RESERVATION (1ULL<<22) #define CEPH_FEATURE_MSG_AUTH (1ULL<<23) #define CEPH_FEATURE_RECOVERY_RESERVATION (1ULL<<24) #define CEPH_FEATURE_CRUSH_TUNABLES2 (1ULL<<25) #define CEPH_FEATURE_CREATEPOOLID (1ULL<<26) #define CEPH_FEATURE_REPLY_CREATE_INODE (1ULL<<27) #define CEPH_FEATURE_OSD_HBMSGS (1ULL<<28) #define CEPH_FEATURE_MDSENC (1ULL<<29) #define CEPH_FEATURE_OSDHASHPSPOOL (1ULL<<30) #define CEPH_FEATURE_MON_SINGLE_PAXOS (1ULL<<31) #define CEPH_FEATURE_OSD_SNAPMAPPER (1ULL<<32) #define CEPH_FEATURE_MON_SCRUB (1ULL<<33) #define CEPH_FEATURE_OSD_PACKED_RECOVERY (1ULL<<34) #define CEPH_FEATURE_OSD_CACHEPOOL (1ULL<<35) #define CEPH_FEATURE_CRUSH_V2 (1ULL<<36) /* new indep; SET_* steps */ #define CEPH_FEATURE_EXPORT_PEER (1ULL<<37) #define CEPH_FEATURE_OSD_ERASURE_CODES (1ULL<<38) #define CEPH_FEATURE_OSD_TMAP2OMAP (1ULL<<38) /* overlap with EC */ /* The process supports new-style OSDMap encoding. Monitors also use this bit to determine if peers support NAK messages. */ #define CEPH_FEATURE_OSDMAP_ENC (1ULL<<39) #define CEPH_FEATURE_MDS_INLINE_DATA (1ULL<<40) #define CEPH_FEATURE_CRUSH_TUNABLES3 (1ULL<<41) #define CEPH_FEATURE_OSD_PRIMARY_AFFINITY (1ULL<<41) /* overlap w/ tunables3 */ #define CEPH_FEATURE_MSGR_KEEPALIVE2 (1ULL<<42) #define CEPH_FEATURE_OSD_POOLRESEND (1ULL<<43) #define CEPH_FEATURE_OSD_SET_ALLOC_HINT (1ULL<<45) /* * The introduction of CEPH_FEATURE_OSD_SNAPMAPPER caused the feature * vector to evaluate to 64 bit ~0. To cope, we designate 1ULL << 63 * to mean 33 bit ~0, and introduce a helper below to do the * translation. * * This was introduced by commit * 9ea02b84104045c2ffd7e7f4e7af512953855ecd v0.58-657-g9ea02b8 * and fixed by commit * 4255b5c2fb54ae40c53284b3ab700fdfc7e61748 v0.65-263-g4255b5c */ #define CEPH_FEATURE_RESERVED (1ULL<<63) static inline unsigned long long ceph_sanitize_features(unsigned long long f) { if (f & CEPH_FEATURE_RESERVED) { /* everything through OSD_SNAPMAPPER */ return 0x1ffffffffull; } else { return f; } } /* * Features supported. Should be everything above. */ #define CEPH_FEATURES_ALL \ (CEPH_FEATURE_UID | \ CEPH_FEATURE_NOSRCADDR | \ CEPH_FEATURE_MONCLOCKCHECK | \ CEPH_FEATURE_FLOCK | \ CEPH_FEATURE_SUBSCRIBE2 | \ CEPH_FEATURE_MONNAMES | \ CEPH_FEATURE_RECONNECT_SEQ | \ CEPH_FEATURE_DIRLAYOUTHASH | \ CEPH_FEATURE_OBJECTLOCATOR | \ CEPH_FEATURE_PGID64 | \ CEPH_FEATURE_INCSUBOSDMAP | \ CEPH_FEATURE_PGPOOL3 | \ CEPH_FEATURE_OSDREPLYMUX | \ CEPH_FEATURE_OSDENC | \ CEPH_FEATURE_OMAP | \ CEPH_FEATURE_QUERY_T | \ CEPH_FEATURE_MONENC | \ CEPH_FEATURE_INDEP_PG_MAP | \ CEPH_FEATURE_CRUSH_TUNABLES | \ CEPH_FEATURE_CHUNKY_SCRUB | \ CEPH_FEATURE_MON_NULLROUTE | \ CEPH_FEATURE_MON_GV | \ CEPH_FEATURE_BACKFILL_RESERVATION | \ CEPH_FEATURE_MSG_AUTH | \ CEPH_FEATURE_RECOVERY_RESERVATION | \ CEPH_FEATURE_CRUSH_TUNABLES2 | \ CEPH_FEATURE_CREATEPOOLID | \ CEPH_FEATURE_REPLY_CREATE_INODE | \ CEPH_FEATURE_OSD_HBMSGS | \ CEPH_FEATURE_MDSENC | \ CEPH_FEATURE_OSDHASHPSPOOL | \ CEPH_FEATURE_MON_SINGLE_PAXOS | \ CEPH_FEATURE_OSD_SNAPMAPPER | \ CEPH_FEATURE_MON_SCRUB | \ CEPH_FEATURE_OSD_PACKED_RECOVERY | \ CEPH_FEATURE_OSD_CACHEPOOL | \ CEPH_FEATURE_CRUSH_V2 | \ CEPH_FEATURE_EXPORT_PEER | \ CEPH_FEATURE_OSD_ERASURE_CODES | \ CEPH_FEATURE_OSDMAP_ENC | \ CEPH_FEATURE_MDS_INLINE_DATA | \ CEPH_FEATURE_CRUSH_TUNABLES3 | \ CEPH_FEATURE_OSD_PRIMARY_AFFINITY | \ CEPH_FEATURE_MSGR_KEEPALIVE2 | \ CEPH_FEATURE_OSD_POOLRESEND | \ CEPH_FEATURE_OSD_SET_ALLOC_HINT | \ 0ULL) #define CEPH_FEATURES_SUPPORTED_DEFAULT CEPH_FEATURES_ALL /* * crush related features */ #define CEPH_FEATURES_CRUSH \ (CEPH_FEATURE_CRUSH_TUNABLES | \ CEPH_FEATURE_CRUSH_TUNABLES2 | \ CEPH_FEATURE_CRUSH_TUNABLES3 | \ CEPH_FEATURE_CRUSH_V2) #endif ceph-0.80.11/src/include/dlist.h0000664000175100017510000000501512623076744020400 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DLIST_H #define CEPH_DLIST_H template class dlist { public: struct item { T _item; item *_prev, *_next; item(T i) : _item(i), _prev(this), _next(this) {} ~item() { assert(!is_on_list()); } // no copying! item(const item& other); const item& operator= (const item& right); bool empty() const { return _prev == this; } bool is_on_list() const { return !empty(); } bool remove_myself() { if (_next == this) { assert(_prev == this); return false; } _next->_prev = _prev; _prev->_next = _next; _prev = _next = this; return true; } void insert_after(item *other) { assert(other->empty()); other->_prev = this; other->_next = _next; _next->_prev = other; _next = other; } void insert_before(item *other) { assert(other->empty()); other->_next = this; other->_prev = _prev; _prev->_next = other; _prev = other; } }; private: item _head; public: dlist(const dlist& other); const dlist& operator=(const dlist& other); dlist() : _head(NULL) {} ~dlist() { assert(_head.empty()); } bool empty() { return _head.empty(); } void clear() { while (!_head.empty()) remove(front()); } void push_front(item *i) { if (!i->empty()) i->remove_myself(); _head.insert_after(i); } void push_back(item *i) { if (!i->empty()) i->remove_myself(); _head.insert_before(i); } T front() { return (T)_head._next->_item; } T back() { return (T)_head._prev->_item; } void pop_front() { assert(!empty()); _head._next->remove_myself(); } void pop_back() { assert(!empty()); _head._prev->remove_myself(); } class iterator { private: item *cur; public: iterator(item *i = 0) : cur(i) {} T operator*() { return (T)cur->_item; } iterator& operator++() { assert(cur); cur = cur->_next; return *this; } bool end() { return cur->_item == 0; } }; iterator begin() { return iterator(_head._next); } }; #endif ceph-0.80.11/src/include/cephfs/0000775000175100017510000000000012623077034020350 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/include/cephfs/libcephfs.h0000664000175100017510000014607712623076744022506 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIB_H #define CEPH_LIB_H #include #include #include #include #include #include #include // FreeBSD compatibility #ifdef __FreeBSD__ typedef off_t loff_t; typedef off_t off64_t; #endif #ifdef __cplusplus extern "C" { #endif /* * On FreeBSD and Apple the offset is 64 bit, but libc doesn't announce it in * the way glibc does. */ #if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__USE_FILE_OFFSET64) # error libceph: must define __USE_FILE_OFFSET64 or readdir results will be corrupted #endif /* * XXXX redeclarations from ceph_fs.h, rados.h, etc. We need more of this * in the interface, but shouldn't be re-typing it (and using different * C data types). */ #ifndef __cplusplus #define CEPH_INO_ROOT 1 #define CEPH_NOSNAP ((uint64_t)(-2)) struct ceph_file_layout { /* file -> object mapping */ uint32_t fl_stripe_unit; /* stripe unit, in bytes. must be multiple of page size. */ uint32_t fl_stripe_count; /* over this many objects */ uint32_t fl_object_size; /* until objects are this big, then move to new objects */ uint32_t fl_cas_hash; /* 0 = none; 1 = sha256 */ /* pg -> disk layout */ uint32_t fl_object_stripe_unit; /* for per-object parity, if any */ /* object -> pg layout */ uint32_t fl_pg_preferred; /* preferred primary for pg (-1 for none) */ uint32_t fl_pg_pool; /* namespace, crush ruleset, rep level */ } __attribute__ ((packed)); typedef struct _inodeno_t { uint64_t val; } inodeno_t; typedef struct _snapid_t { uint64_t val; } snapid_t; typedef struct vinodeno_t { inodeno_t ino; snapid_t snapid; } vinodeno_t; typedef struct Fh Fh; #endif /* ! __cplusplus */ struct inodeno_t; struct Inode; typedef struct Inode Inode; struct vinodeno_t; typedef struct vinodeno_t vinodeno; struct ceph_mount_info; struct ceph_dir_result; struct CephContext; /* setattr mask bits */ #ifndef CEPH_SETATTR_MODE # define CEPH_SETATTR_MODE 1 # define CEPH_SETATTR_UID 2 # define CEPH_SETATTR_GID 4 # define CEPH_SETATTR_MTIME 8 # define CEPH_SETATTR_ATIME 16 # define CEPH_SETATTR_SIZE 32 # define CEPH_SETATTR_CTIME 64 #endif /** * @defgroup libcephfs_h_init Setup and Teardown * These are the first and last functions that should be called * when using libcephfs. * * @{ */ /** * Get the version of libcephfs. * * The version number is major.minor.patch. * * @param major where to store the major version number * @param minor where to store the minor version number * @param extra where to store the extra version number */ const char *ceph_version(int *major, int *minor, int *patch); /** * Create a mount handle for interacting with Ceph. All libcephfs * functions operate on a mount info handle. * * @param cmount the mount info handle to initialize * @param id the id of the client. This can be a unique id that identifies * this client, and will get appended onto "client.". Callers can * pass in NULL, and the id will be the process id of the client. * @returns 0 on success, negative error code on failure */ int ceph_create(struct ceph_mount_info **cmount, const char * const id); /** * Create a mount handle from a CephContext, which holds the configuration * for the ceph cluster. A CephContext can be acquired from an existing ceph_mount_info * handle, using the @ref ceph_get_mount_context call. Note that using the same CephContext * for two different mount handles results in the same client entity id being used. * * @param cmount the mount info handle to initialize * @param conf reuse this pre-existing CephContext config * @returns 0 on success, negative error code on failure */ int ceph_create_with_context(struct ceph_mount_info **cmount, struct CephContext *conf); /** * Perform a mount using the path for the root of the mount. * * @param cmount the mount info handle * @param root the path for the root of the mount. This can be an existing * directory within the ceph cluster, but most likely it will * be "/". Passing in NULL is equivalent to "/". * @returns 0 on success, negative error code on failure */ int ceph_mount(struct ceph_mount_info *cmount, const char *root); /** * Unmount a mount handle. * * @param cmount the mount handle * @return 0 on success, negative error code on failure */ int ceph_unmount(struct ceph_mount_info *cmount); /** * Destroy the mount handle. * * The handle should not be mounted. This should be called on completion of * all libcephfs functions. * * @param cmount the mount handle * @return 0 on success, negative error code on failure. */ int ceph_release(struct ceph_mount_info *cmount); /** * Deprecated. Unmount and destroy the ceph mount handle. This should be * called on completion of all libcephfs functions. * * Equivalent to ceph_unmount() + ceph_release() without error handling. * * @param cmount the mount handle to shutdown */ void ceph_shutdown(struct ceph_mount_info *cmount); /** * Extract the CephContext from the mount point handle. * * @param cmount the ceph mount handle to get the context from. * @returns the CephContext associated with the mount handle. */ struct CephContext *ceph_get_mount_context(struct ceph_mount_info *cmount); /* * Check mount status. * * Return non-zero value if mounted. Otherwise, zero. */ int ceph_is_mounted(struct ceph_mount_info *cmount); /** @} init */ /** * @defgroup libcephfs_h_config Config * Functions for manipulating the Ceph configuration at runtime. * * @{ */ /** * Load the ceph configuration from the specified config file. * * @param cmount the mount handle to load the configuration into. * @param path_list the configuration file path * @returns 0 on success, negative error code on failure */ int ceph_conf_read_file(struct ceph_mount_info *cmount, const char *path_list); /** * Parse the command line arguments and load the configuration parameters. * * @param cmount the mount handle to load the configuration parameters into. * @param argc count of the arguments in argv * @param argv the argument list * @returns 0 on success, negative error code on failure */ int ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc, const char **argv); /** * Configure the cluster handle based on an environment variable * * The contents of the environment variable are parsed as if they were * Ceph command line options. If var is NULL, the CEPH_ARGS * environment variable is used. * * @pre ceph_mount() has not been called on the handle * * @note BUG: this is not threadsafe - it uses a static buffer * * @param cmount handle to configure * @param var name of the environment variable to read * @returns 0 on success, negative error code on failure */ int ceph_conf_parse_env(struct ceph_mount_info *cmount, const char *var); /** Sets a configuration value from a string. * * @param cmount the mount handle to set the configuration value on * @param option the configuration option to set * @param value the value of the configuration option to set * * @returns 0 on success, negative error code otherwise. */ int ceph_conf_set(struct ceph_mount_info *cmount, const char *option, const char *value); /** * Gets the configuration value as a string. * * @param cmount the mount handle to set the configuration value on * @param option the config option to get * @param buf the buffer to fill with the value * @param len the length of the buffer. * @returns the size of the buffer filled in with the value, or negative error code on failure */ int ceph_conf_get(struct ceph_mount_info *cmount, const char *option, char *buf, size_t len); /** @} config */ /** * @defgroup libcephfs_h_fsops File System Operations. * Functions for getting/setting file system wide information specific to a particular * mount handle. * * @{ */ /** * Perform a statfs on the ceph file system. This call fills in file system wide statistics * into the passed in buffer. * * @param cmount the ceph mount handle to use for performing the statfs. * @param path can be any path within the mounted filesystem * @param stbuf the file system statistics filled in by this function. * @return 0 on success, negative error code otherwise. */ int ceph_statfs(struct ceph_mount_info *cmount, const char *path, struct statvfs *stbuf); /** * Synchronize all filesystem data to persistent media. * * @param cmount the ceph mount handle to use for performing the sync_fs. * @returns 0 on success or negative error code on failure. */ int ceph_sync_fs(struct ceph_mount_info *cmount); /** * Get the current working directory. * * @param cmount the ceph mount to get the current working directory for. * @returns the path to the current working directory */ const char* ceph_getcwd(struct ceph_mount_info *cmount); /** * Change the current working directory. * * @param cmount the ceph mount to change the current working directory for. * @param path the path to the working directory to change into. * @returns 0 on success, negative error code otherwise. */ int ceph_chdir(struct ceph_mount_info *cmount, const char *s); /** @} fsops */ /** * @defgroup libcephfs_h_dir Directory Operations. * Functions for manipulating and listing directories. * * @{ */ /** * Open the given directory. * * @param cmount the ceph mount handle to use to open the directory * @param name the path name of the directory to open. Must be either an absolute path * or a path relative to the current working directory. * @param dirpp the directory result pointer structure to fill in. * @returns 0 on success or negative error code otherwise. */ int ceph_opendir(struct ceph_mount_info *cmount, const char *name, struct ceph_dir_result **dirpp); /** * Close the open directory. * * @param cmount the ceph mount handle to use for closing the directory * @param dirp the directory result pointer (set by ceph_opendir) to close * @returns 0 on success or negative error code on failure. */ int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp); /** * Get the next entry in an open directory. * * @param cmount the ceph mount handle to use for performing the readdir. * @param dirp the directory stream pointer from an opendir holding the state of the * next entry to return. * @returns the next directory entry or NULL if at the end of the directory (or the directory * is empty. This pointer should not be freed by the caller, and is only safe to * access between return and the next call to ceph_readdir or ceph_closedir. */ struct dirent * ceph_readdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp); /** * A safe version of ceph_readdir, where the directory entry struct is allocated by the caller. * * @param cmount the ceph mount handle to use for performing the readdir. * @param dirp the directory stream pointer from an opendir holding the state of the * next entry to return. * @param de the directory entry pointer filled in with the next directory entry of the dirp state. * @returns 1 if the next entry was filled in, 0 if the end of the directory stream was reached, * and a negative error code on failure. */ int ceph_readdir_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de); /** * A safe version of ceph_readdir that also returns the file statistics (readdir+stat). * * @param cmount the ceph mount handle to use for performing the readdir_plus_r. * @param dirp the directory stream pointer from an opendir holding the state of the * next entry to return. * @param de the directory entry pointer filled in with the next directory entry of the dirp state. * @param st the stats of the file/directory of the entry returned * @param stmask a mask that gets filled in with the stats fields that are being set in the st parameter. * @returns 1 if the next entry was filled in, 0 if the end of the directory stream was reached, * and a negative error code on failure. */ int ceph_readdirplus_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de, struct stat *st, int *stmask); /** * Gets multiple directory entries. * * @param cmount the ceph mount handle to use for performing the getdents. * @param dirp the directory stream pointer from an opendir holding the state of the * next entry/entries to return. * @param name an array of struct dirent that gets filled in with the to fill returned directory entries into. * @param buflen the length of the buffer, which should be the number of dirent structs * sizeof(struct dirent). * @returns the length of the buffer that was filled in, will always be multiples of sizeof(struct dirent), or a * negative error code. If the buffer is not large enough for a single entry, -ERANGE is returned. */ int ceph_getdents(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, char *name, int buflen); /** * Gets multiple directory names. * * @param cmount the ceph mount handle to use for performing the getdents. * @param dirp the directory stream pointer from an opendir holding the state of the * next entry/entries to return. * @param name a buffer to fill in with directory entry names. * @param buflen the length of the buffer that can be filled in. * @returns the length of the buffer filled in with entry names, or a negative error code on failure. * If the buffer isn't large enough for a single entry, -ERANGE is returned. */ int ceph_getdnames(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, char *name, int buflen); /** * Rewind the directory stream to the beginning of the directory. * * @param cmount the ceph mount handle to use for performing the rewinddir. * @param dirp the directory stream pointer to rewind. */ void ceph_rewinddir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp); /** * Get the current position of a directory stream. * * @param cmount the ceph mount handle to use for performing the telldir. * @param dirp the directory stream pointer to get the current position of. * @returns the position of the directory stream. Note that the offsets returned * by ceph_telldir do not have a particular order (cannot be compared with * inequality). */ int64_t ceph_telldir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp); /** * Move the directory stream to a position specified by the given offset. * * @param cmount the ceph mount handle to use for performing the seekdir. * @param dirp the directory stream pointer to move. * @param offset the position to move the directory stream to. This offset should be * a value returned by seekdir. Note that this value does not refer to the nth * entry in a directory, and can not be manipulated with plus or minus. */ void ceph_seekdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, int64_t offset); /** * Create a directory. * * @param cmount the ceph mount handle to use for making the directory. * @param path the path of the directory to create. This must be either an * absolute path or a relative path off of the current working directory. * @param mode the permissions the directory should have once created. * @returns 0 on success or a negative return code on error. */ int ceph_mkdir(struct ceph_mount_info *cmount, const char *path, mode_t mode); /** * Create multiple directories at once. * * @param cmount the ceph mount handle to use for making the directories. * @param path the full path of directories and sub-directories that should * be created. * @param mode the permissions the directory should have once created. * @returns 0 on success or a negative return code on error. */ int ceph_mkdirs(struct ceph_mount_info *cmount, const char *path, mode_t mode); /** * Remove a directory. * * @param cmount the ceph mount handle to use for removing directories. * @param path the path of the directory to remove. * @returns 0 on success or a negative return code on error. */ int ceph_rmdir(struct ceph_mount_info *cmount, const char *path); /** @} dir */ /** * @defgroup libcephfs_h_links Links and Link Handling. * Functions for creating and manipulating hard links and symbolic inks. * * @{ */ /** * Create a link. * * @param cmount the ceph mount handle to use for creating the link. * @param existing the path to the existing file/directory to link to. * @param newname the path to the new file/directory to link from. * @returns 0 on success or a negative return code on error. */ int ceph_link(struct ceph_mount_info *cmount, const char *existing, const char *newname); /** * Read a symbolic link. * * @param cmount the ceph mount handle to use for creating the link. * @param path the path to the symlink to read * @param buf the buffer to hold the the path of the file that the symlink points to. * @param size the length of the buffer * @returns number of bytes copied on success or negative error code on failure */ int ceph_readlink(struct ceph_mount_info *cmount, const char *path, char *buf, int64_t size); /** * Creates a symbolic link. * * @param cmount the ceph mount handle to use for creating the symbolic link. * @param existing the path to the existing file/directory to link to. * @param newname the path to the new file/directory to link from. * @returns 0 on success or a negative return code on failure. */ int ceph_symlink(struct ceph_mount_info *cmount, const char *existing, const char *newname); /** @} links */ /** * @defgroup libcephfs_h_files File manipulation and handling. * Functions for creating and manipulating files. * * @{ */ /** * Removes a file, link, or symbolic link. If the file/link has multiple links to it, the * file will not disappear from the namespace until all references to it are removed. * * @param cmount the ceph mount handle to use for performing the unlink. * @param path the path of the file or link to unlink. * @returns 0 on success or negative error code on failure. */ int ceph_unlink(struct ceph_mount_info *cmount, const char *path); /** * Rename a file or directory. * * @param cmount the ceph mount handle to use for performing the rename. * @param from the path to the existing file or directory. * @param to the new name of the file or directory * @returns 0 on success or negative error code on failure. */ int ceph_rename(struct ceph_mount_info *cmount, const char *from, const char *to); /** * Get a file's statistics and attributes. * * @param cmount the ceph mount handle to use for performing the stat. * @param path the file or directory to get the statistics of. * @param stbuf the stat struct that will be filled in with the file's statistics. * @returns 0 on success or negative error code on failure. */ int ceph_stat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf); /** * Get a file's statistics and attributes, without following symlinks. * * @param cmount the ceph mount handle to use for performing the stat. * @param path the file or directory to get the statistics of. * @param stbuf the stat struct that will be filled in with the file's statistics. * @returns 0 on success or negative error code on failure. */ int ceph_lstat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf); /** * Set a file's attributes. * * @param cmount the ceph mount handle to use for performing the setattr. * @param relpath the path to the file/directory to set the attributes of. * @param attr the stat struct that must include attribute values to set on the file. * @param mask a mask of all the stat values that have been set on the stat struct. * @returns 0 on success or negative error code on failure. */ int ceph_setattr(struct ceph_mount_info *cmount, const char *relpath, struct stat *attr, int mask); /** * Change the mode bits (permissions) of a file/directory. * * @param cmount the ceph mount handle to use for performing the chmod. * @param path the path to the file/directory to change the mode bits on. * @param mode the new permissions to set. * @returns 0 on success or a negative error code on failure. */ int ceph_chmod(struct ceph_mount_info *cmount, const char *path, mode_t mode); /** * Change the mode bits (permissions) of an open file. * * @param cmount the ceph mount handle to use for performing the chmod. * @param fd the open file descriptor to change the mode bits on. * @param mode the new permissions to set. * @returns 0 on success or a negative error code on failure. */ int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode); /** * Change the ownership of a file/directory. * * @param cmount the ceph mount handle to use for performing the chown. * @param path the path of the file/directory to change the ownership of. * @param uid the user id to set on the file/directory. * @param gid the group id to set on the file/directory. * @returns 0 on success or negative error code on failure. */ int ceph_chown(struct ceph_mount_info *cmount, const char *path, int uid, int gid); /** * Change the ownership of a file from an open file descriptor. * * @param cmount the ceph mount handle to use for performing the chown. * @param path the path of the file/directory to change the ownership of. * @param uid the user id to set on the file/directory. * @param gid the group id to set on the file/directory. * @returns 0 on success or negative error code on failure. */ int ceph_fchown(struct ceph_mount_info *cmount, int fd, int uid, int gid); /** * Change the ownership of a file/directory, don't follow symlinks. * * @param cmount the ceph mount handle to use for performing the chown. * @param path the path of the file/directory to change the ownership of. * @param uid the user id to set on the file/directory. * @param gid the group id to set on the file/directory. * @returns 0 on success or negative error code on failure. */ int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int gid); /** * Change file/directory last access and modification times. * * @param cmount the ceph mount handle to use for performing the utime. * @param path the path to the file/directory to set the time values of. * @param buf holding the access and modification times to set on the file. * @returns 0 on success or negative error code on failure. */ int ceph_utime(struct ceph_mount_info *cmount, const char *path, struct utimbuf *buf); /** * Truncate the file to the given size. If this operation causes the * file to expand, the empty bytes will be filled in with zeros. * * @param cmount the ceph mount handle to use for performing the truncate. * @param path the path to the file to truncate. * @param size the new size of the file. * @returns 0 on success or a negative error code on failure. */ int ceph_truncate(struct ceph_mount_info *cmount, const char *path, int64_t size); /** * Make a block or character special file. * * @param cmount the ceph mount handle to use for performing the mknod. * @param path the path to the special file. * @param mode the permissions to use and the type of special file. The type can be * one of S_IFREG, S_IFCHR, S_IFBLK, S_IFIFO. * @param rdev If the file type is S_IFCHR or S_IFBLK then this parameter specifies the * major and minor numbers of the newly created device special file. Otherwise, * it is ignored. * @returns 0 on success or negative error code on failure. */ int ceph_mknod(struct ceph_mount_info *cmount, const char *path, mode_t mode, dev_t rdev); /** * Create and/or open a file. * * @param cmount the ceph mount handle to use for performing the open. * @param path the path of the file to open. If the flags parameter includes O_CREAT, * the file will first be created before opening. * @param flags a set of option masks that control how the file is created/opened. * @param mode the permissions to place on the file if the file does not exist and O_CREAT * is specified in the flags. * @returns a non-negative file descriptor number on success or a negative error code on failure. */ int ceph_open(struct ceph_mount_info *cmount, const char *path, int flags, mode_t mode); /** * Create and/or open a file with a specific file layout. * * @param cmount the ceph mount handle to use for performing the open. * @param path the path of the file to open. If the flags parameter includes O_CREAT, * the file will first be created before opening. * @param flags a set of option masks that control how the file is created/opened. * @param mode the permissions to place on the file if the file does not exist and O_CREAT * is specified in the flags. * @param stripe_unit the stripe unit size (option, 0 for default) * @param stripe_count the stripe count (optional, 0 for default) * @param object_size the object size (optional, 0 for default) * @param data_pool name of target data pool name (optional, NULL or empty string for default) * @returns a non-negative file descriptor number on success or a negative error code on failure. */ int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags, mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool); /** * Close the open file. * * @param cmount the ceph mount handle to use for performing the close. * @param fd the file descriptor referring to the open file. * @returns 0 on success or a negative error code on failure. */ int ceph_close(struct ceph_mount_info *cmount, int fd); /** * Reposition the open file stream based on the given offset. * * @param cmount the ceph mount handle to use for performing the lseek. * @param fd the open file descriptor referring to the open file and holding the * current position of the stream. * @param offset the offset to set the stream to * @param whence the flag to indicate what type of seeking to perform: * SEEK_SET: the offset is set to the given offset in the file. * SEEK_CUR: the offset is set to the current location plus @ref offset bytes. * SEEK_END: the offset is set to the end of the file plus @ref offset bytes. * @returns 0 on success or a negative error code on failure. */ int64_t ceph_lseek(struct ceph_mount_info *cmount, int fd, int64_t offset, int whence); /** * Read data from the file. * * @param cmount the ceph mount handle to use for performing the read. * @param fd the file descriptor of the open file to read from. * @param buf the buffer to read data into * @param the initial size of the buffer * @param offset the offset in the file to read from. If this value is negative, the * function reads from the current offset of the file descriptor. * @returns the number of bytes read into buf, or a negative error code on failure. */ int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf, int64_t size, int64_t offset); /** * Write data to a file. * * @param cmount the ceph mount handle to use for performing the write. * @param fd the file descriptor of the open file to write to * @param buf the bytes to write to the file * @param size the size of the buf array * @param offset the offset of the file write into. If this value is negative, the * function writes to the current offset of the file descriptor. * @returns the number of bytes written, or a negative error code */ int ceph_write(struct ceph_mount_info *cmount, int fd, const char *buf, int64_t size, int64_t offset); /** * Truncate a file to the given size. * * @param cmount the ceph mount handle to use for performing the ftruncate. * @param fd the file descriptor of the file to truncate * @param size the new size of the file * @returns 0 on success or a negative error code on failure. */ int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t size); /** * Synchronize an open file to persistent media. * * @param cmount the ceph mount handle to use for performing the fsync. * @param fd the file descriptor of the file to sync. * @param syncdataonly a boolean whether to synchronize metadata and data (0) * or just data (1). * @return 0 on success or a negative error code on failure. */ int ceph_fsync(struct ceph_mount_info *cmount, int fd, int syncdataonly); /** * Preallocate or release disk space for the file for the byte range. * * @param cmount the ceph mount handle to use for performing the fallocate. * @param fd the file descriptor of the file to fallocate. * @param mode the flags determines the operation to be performed on the given range. * default operation (0) allocate and initialize to zero the file in the byte range, * and the file size will be changed if offset + length is greater than * the file size. if the FALLOC_FL_KEEP_SIZE flag is specified in the mode, * the file size will not be changed. if the FALLOC_FL_PUNCH_HOLE flag is * specified in the mode, the operation is deallocate space and zero the byte range. * @param offset the byte range starting. * @param length the length of the range. * @return 0 on success or a negative error code on failure. */ int ceph_fallocate(struct ceph_mount_info *cmount, int fd, int mode, int64_t offset, int64_t length); /** * Get the open file's statistics. * * @param cmount the ceph mount handle to use for performing the fstat. * @param fd the file descriptor of the file to get statistics of. * @param stbuf the stat struct of the file's statistics, filled in by the * function. * @returns 0 on success or a negative error code on failure */ int ceph_fstat(struct ceph_mount_info *cmount, int fd, struct stat *stbuf); /** @} file */ /** * @defgroup libcephfs_h_xattr Extended Attribute manipulation and handling. * Functions for creating and manipulating extended attributes on files. * * @{ */ /** * Get an extended attribute. * * @param cmount the ceph mount handle to use for performing the getxattr. * @param path the path to the file * @param name the name of the extended attribute to get * @param value a pre-allocated buffer to hold the xattr's value * @param size the size of the pre-allocated buffer * @returns the size of the value or a negative error code on failure. */ int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size); /** * Get an extended attribute wihtout following symbolic links. This function is * identical to ceph_getxattr, but if the path refers to a symbolic link, * we get the extended attributes of the symlink rather than the attributes * of the link itself. * * @param cmount the ceph mount handle to use for performing the lgetxattr. * @param path the path to the file * @param name the name of the extended attribute to get * @param value a pre-allocated buffer to hold the xattr's value * @param size the size of the pre-allocated buffer * @returns the size of the value or a negative error code on failure. */ int ceph_lgetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size); /** * List the extended attribute keys on a file. * * @param cmount the ceph mount handle to use for performing the listxattr. * @param path the path to the file. * @param list a buffer to be filled in with the list of extended attributes keys. * @param size the size of the list buffer. * @returns the size of the resulting list filled in. */ int ceph_listxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size); /** * Get the list of extended attribute keys on a file, but do not follow symbolic links. * * @param cmount the ceph mount handle to use for performing the llistxattr. * @param path the path to the file. * @param list a buffer to be filled in with the list of extended attributes keys. * @param size the size of the list buffer. * @returns the size of the resulting list filled in. */ int ceph_llistxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size); /** * Remove an extended attribute from a file. * * @param cmount the ceph mount handle to use for performing the removexattr. * @param path the path to the file. * @param name the name of the extended attribute to remove. * @returns 0 on success or a negative error code on failure. */ int ceph_removexattr(struct ceph_mount_info *cmount, const char *path, const char *name); /** * Remove the extended attribute from a file, do not follow symbolic links. * * @param cmount the ceph mount handle to use for performing the lremovexattr. * @param path the path to the file. * @param name the name of the extended attribute to remove. * @returns 0 on success or a negative error code on failure. */ int ceph_lremovexattr(struct ceph_mount_info *cmount, const char *path, const char *name); /** * Set an extended attribute on a file. * * @param cmount the ceph mount handle to use for performing the setxattr. * @param path the path to the file. * @param name the name of the extended attribute to set. * @param value the bytes of the extended attribute value * @param size the size of the extended attribute value * @param flags the flags can be: * CEPH_XATTR_CREATE: create the extended attribute. Must not exist. * CEPH_XATTR_REPLACE: replace the extended attribute, Must already exist. * @returns 0 on success or a negative error code on failure. */ int ceph_setxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags); /** * Set an extended attribute on a file, do not follow symbolic links. * * @param cmount the ceph mount handle to use for performing the lsetxattr. * @param path the path to the file. * @param name the name of the extended attribute to set. * @param value the bytes of the extended attribute value * @param size the size of the extended attribute value * @param flags the flags can be: * CEPH_XATTR_CREATE: create the extended attribute. Must not exist. * CEPH_XATTR_REPLACE: replace the extended attribute, Must already exist. * @returns 0 on success or a negative error code on failure. */ int ceph_lsetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags); /** @} xattr */ /** * @defgroup libcephfs_h_filelayout Control File Layout. * Functions for setting and getting the file layout of existing files. * * @{ */ /** * Get the file striping unit from an open file descriptor. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file to get the striping unit of. * @returns the striping unit of the file or a negative error code on failure. */ int ceph_get_file_stripe_unit(struct ceph_mount_info *cmount, int fh); /** * Get the file striping unit. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory get the striping unit of. * @returns the striping unit of the file or a negative error code on failure. */ int ceph_get_path_stripe_unit(struct ceph_mount_info *cmount, const char *path); /** * Get the file striping count from an open file descriptor. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file to get the striping count of. * @returns the striping count of the file or a negative error code on failure. */ int ceph_get_file_stripe_count(struct ceph_mount_info *cmount, int fh); /** * Get the file striping count. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory get the striping count of. * @returns the striping count of the file or a negative error code on failure. */ int ceph_get_path_stripe_count(struct ceph_mount_info *cmount, const char *path); /** * Get the file object size from an open file descriptor. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file to get the object size of. * @returns the object size of the file or a negative error code on failure. */ int ceph_get_file_object_size(struct ceph_mount_info *cmount, int fh); /** * Get the file object size. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory get the object size of. * @returns the object size of the file or a negative error code on failure. */ int ceph_get_path_object_size(struct ceph_mount_info *cmount, const char *path); /** * Get the file pool information from an open file descriptor. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file to get the pool information of. * @returns the ceph pool id that the file is in */ int ceph_get_file_pool(struct ceph_mount_info *cmount, int fh); /** * Get the file pool information. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory get the pool information of. * @returns the ceph pool id that the file is in */ int ceph_get_path_pool(struct ceph_mount_info *cmount, const char *path); /** * Get the name of the pool a opened file is stored in, * * Write the name of the file's pool to the buffer. If buflen is 0, return * a suggested length for the buffer. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file * @param buf buffer to store the name in * @param buflen size of the buffer * @returns length in bytes of the pool name, or -ERANGE if the buffer is not large enough. */ int ceph_get_file_pool_name(struct ceph_mount_info *cmount, int fh, char *buf, size_t buflen); /** * get the name of a pool by id * * Given a pool's numeric identifier, get the pool's alphanumeric name. * * @param cmount the ceph mount handle to use * @param pool the numeric pool id * @param buf buffer to sore the name in * @param buflen size of the buffer * @returns length in bytes of the pool name, or -ERANGE if the buffer is not large enough */ int ceph_get_pool_name(struct ceph_mount_info *cmount, int pool, char *buf, size_t buflen); /** * Get the name of the pool a file is stored in * * Write the name of the file's pool to the buffer. If buflen is 0, return * a suggested length for the buffer. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory * @param buf buffer to store the name in * @param buflen size of the buffer * @returns length in bytes of the pool name, or -ERANGE if the buffer is not large enough. */ int ceph_get_path_pool_name(struct ceph_mount_info *cmount, const char *path, char *buf, size_t buflen); /** * Get the file layout from an open file descriptor. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file to get the layout of. * @param stripe_unit where to store the striping unit of the file * @param stripe_count where to store the striping count of the file * @param object_size where to store the object size of the file * @param pg_pool where to store the ceph pool id that the file is in * @returns 0 on success or a negative error code on failure. */ int ceph_get_file_layout(struct ceph_mount_info *cmount, int fh, int *stripe_unit, int *stripe_count, int *object_size, int *pg_pool); /** * Get the file layout. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory get the layout of. * @param stripe_unit where to store the striping unit of the file * @param stripe_count where to store the striping count of the file * @param object_size where to store the object size of the file * @param pg_pool where to store the ceph pool id that the file is in * @returns 0 on success or a negative error code on failure. */ int ceph_get_path_layout(struct ceph_mount_info *cmount, const char *path, int *stripe_unit, int *stripe_count, int *object_size, int *pg_pool); /** * Get the file replication information from an open file descriptor. * * @param cmount the ceph mount handle to use. * @param fh the open file descriptor referring to the file to get the replication information of. * @returns the replication factor of the file. */ int ceph_get_file_replication(struct ceph_mount_info *cmount, int fh); /** * Get the file replication information. * * @param cmount the ceph mount handle to use. * @param path the path of the file/directory get the replication information of. * @returns the replication factor of the file. */ int ceph_get_path_replication(struct ceph_mount_info *cmount, const char *path); /** * Get the id of the named pool. * * @param cmount the ceph mount handle to use. * @param pool_name the name of the pool. * @returns the pool id, or a negative error code on failure. */ int ceph_get_pool_id(struct ceph_mount_info *cmount, const char *pool_name); /** * Get the pool replication factor. * * @param cmount the ceph mount handle to use. * @param pool_id the pool id to look up * @returns the replication factor, or a negative error code on failure. */ int ceph_get_pool_replication(struct ceph_mount_info *cmount, int pool_id); /** * Get the OSD address where the primary copy of a file stripe is located. * * @param cmount the ceph mount handle to use. * @param fd the open file descriptor referring to the file to get the striping unit of. * @param offset the offset into the file to specify the stripe. The offset can be * anywhere within the stripe unit. * @param addr the address of the OSD holding that stripe * @param naddr the capacity of the address passed in. * @returns the size of the addressed filled into the @ref addr parameter, or a negative * error code on failure. */ int ceph_get_file_stripe_address(struct ceph_mount_info *cmount, int fd, int64_t offset, struct sockaddr_storage *addr, int naddr); /** * Get the list of OSDs where the objects containing a file offset are located. * * @param cmount the ceph mount handle to use. * @param fd the open file descriptor referring to the file. * @param offset the offset within the file. * @param length return the number of bytes between the offset and the end of * the stripe unit (optional). * @param osds an integer array to hold the OSD ids. * @param nosds the size of the integer array. * @returns the number of items stored in the output array, or -ERANGE if the * array is not large enough. */ int ceph_get_file_extent_osds(struct ceph_mount_info *cmount, int fh, int64_t offset, int64_t *length, int *osds, int nosds); /** * Get the fully qualified CRUSH location of an OSD. * * Returns (type, name) string pairs for each device in the CRUSH bucket * hierarchy starting from the given osd to the root. Each pair element is * separated by a NULL character. * * @param cmount the ceph mount handle to use. * @param osd the OSD id. * @param path buffer to store location. * @param len size of buffer. * @returns the amount of bytes written into the buffer, or -ERANGE if the * array is not large enough. */ int ceph_get_osd_crush_location(struct ceph_mount_info *cmount, int osd, char *path, size_t len); /** * Get the network address of an OSD. * * @param cmount the ceph mount handle. * @param osd the OSD id. * @param addr the OSD network address. * @returns zero on success, other returns a negative error code. */ int ceph_get_osd_addr(struct ceph_mount_info *cmount, int osd, struct sockaddr_storage *addr); /** * Get the file layout stripe unit granularity. * @param cmount the ceph mount handle. * @returns the stripe unit granularity or a negative error code on failure. */ int ceph_get_stripe_unit_granularity(struct ceph_mount_info *cmount); /** @} filelayout */ /** * No longer available. Do not use. * These functions will return -EOPNOTSUPP. */ int ceph_set_default_file_stripe_unit(struct ceph_mount_info *cmount, int stripe); int ceph_set_default_file_stripe_count(struct ceph_mount_info *cmount, int count); int ceph_set_default_object_size(struct ceph_mount_info *cmount, int size); int ceph_set_default_preferred_pg(struct ceph_mount_info *cmount, int osd); int ceph_set_default_file_replication(struct ceph_mount_info *cmount, int replication); /** * Read from local replicas when possible. * * @param cmount the ceph mount handle to use. * @param val a boolean to set (1) or clear (0) the option to favor local objects * for reads. * @returns 0 */ int ceph_localize_reads(struct ceph_mount_info *cmount, int val); /** * Get the osd id of the local osd (if any) * * @param cmount the ceph mount handle to use. * @returns the osd (if any) local to the node where this call is made, otherwise * -1 is returned. */ int ceph_get_local_osd(struct ceph_mount_info *cmount); /** @} default_filelayout */ /** * Get the capabilities currently issued to the client. * * @param cmount the ceph mount handle to use. * @param fd the file descriptor to get issued * @returns the current capabilities issued to this client * for the open file */ int ceph_debug_get_fd_caps(struct ceph_mount_info *cmount, int fd); /** * Get the capabilities currently issued to the client. * * @param cmount the ceph mount handle to use. * @param the path to the file * @returns the current capabilities issued to this client * for the file */ int ceph_debug_get_file_caps(struct ceph_mount_info *cmount, const char *path); /* Low Level */ struct Inode *ceph_ll_get_inode(struct ceph_mount_info *cmount, vinodeno_t vino); int ceph_ll_lookup_inode( struct ceph_mount_info *cmount, struct inodeno_t ino, Inode **inode); /** * Get the root inode of FS. Increase counter of references for root Inode. You must call ceph_ll_forget for it! * * @param cmount the ceph mount handle to use. * @param parent pointer to pointer to Inode struct. Pointer to root inode will be returned * @returns 0 if all good */ int ceph_ll_lookup_root(struct ceph_mount_info *cmount, Inode **parent); int ceph_ll_lookup(struct ceph_mount_info *cmount, struct Inode *parent, const char *name, struct stat *attr, Inode **out, int uid, int gid); int ceph_ll_put(struct ceph_mount_info *cmount, struct Inode *in); int ceph_ll_forget(struct ceph_mount_info *cmount, struct Inode *in, int count); int ceph_ll_walk(struct ceph_mount_info *cmount, const char *name, struct Inode **i, struct stat *attr); int ceph_ll_getattr(struct ceph_mount_info *cmount, struct Inode *in, struct stat *attr, int uid, int gid); int ceph_ll_setattr(struct ceph_mount_info *cmount, struct Inode *in, struct stat *st, int mask, int uid, int gid); int ceph_ll_open(struct ceph_mount_info *cmount, struct Inode *in, int flags, struct Fh **fh, int uid, int gid); loff_t ceph_ll_lseek(struct ceph_mount_info *cmount, struct Fh* filehandle, loff_t offset, int whence); int ceph_ll_read(struct ceph_mount_info *cmount, struct Fh* filehandle, int64_t off, uint64_t len, char* buf); int ceph_ll_fsync(struct ceph_mount_info *cmount, struct Fh *fh, int syncdataonly); int ceph_ll_write(struct ceph_mount_info *cmount, struct Fh* filehandle, int64_t off, uint64_t len, const char *data); int64_t ceph_ll_readv(struct ceph_mount_info *cmount, struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off); int64_t ceph_ll_writev(struct ceph_mount_info *cmount, struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off); int ceph_ll_close(struct ceph_mount_info *cmount, struct Fh* filehandle); int ceph_ll_iclose(struct ceph_mount_info *cmount, struct Inode *in, int mode); /** * Get xattr value by xattr name. * * @param cmount the ceph mount handle to use. * @param in file handle * @param name name of attribute * @param value pointer to begin buffer * @param size buffer size * @param uid user ID * @param gid group ID * @returns size of returned buffer. Negative number in error case */ int ceph_ll_getxattr(struct ceph_mount_info *cmount, struct Inode *in, const char *name, void *value, size_t size, int uid, int gid); int ceph_ll_setxattr(struct ceph_mount_info *cmount, struct Inode *in, const char *name, const void *value, size_t size, int flags, int uid, int gid); int ceph_ll_listxattr(struct ceph_mount_info *cmount, struct Inode *in, char *list, size_t buf_size, size_t *list_size, int uid, int gid); int ceph_ll_removexattr(struct ceph_mount_info *cmount, struct Inode *in, const char *name, int uid, int gid); int ceph_ll_create(struct ceph_mount_info *cmount, struct Inode *parent, const char *name, mode_t mode, int flags, struct stat *attr, struct Inode **out, Fh **fhp, int uid, int gid); int ceph_ll_mkdir(struct ceph_mount_info *cmount, struct Inode *parent, const char *name, mode_t mode, struct stat *attr, Inode **out, int uid, int gid); int ceph_ll_link(struct ceph_mount_info *cmount, struct Inode *in, struct Inode *newparrent, const char *name, struct stat *attr, int uid, int gid); int ceph_ll_truncate(struct ceph_mount_info *cmount, struct Inode *in, uint64_t length, int uid, int gid); int ceph_ll_opendir(struct ceph_mount_info *cmount, struct Inode *in, struct ceph_dir_result **dirpp, int uid, int gid); int ceph_ll_releasedir(struct ceph_mount_info *cmount, struct ceph_dir_result* dir); int ceph_ll_rename(struct ceph_mount_info *cmount, struct Inode *parent, const char *name, struct Inode *newparent, const char *newname, int uid, int gid); int ceph_ll_unlink(struct ceph_mount_info *cmount, struct Inode *in, const char *name, int uid, int gid); int ceph_ll_statfs(struct ceph_mount_info *cmount, struct Inode *in, struct statvfs *stbuf); int ceph_ll_readlink(struct ceph_mount_info *cmount, struct Inode *in, char *buf, size_t bufsize, int uid, int gid); int ceph_ll_symlink(struct ceph_mount_info *cmount, struct Inode *parent, const char *name, const char *value, struct stat *attr, struct Inode **in, int uid, int gid); int ceph_ll_rmdir(struct ceph_mount_info *cmount, struct Inode *in, const char *name, int uid, int gid); uint32_t ceph_ll_stripe_unit(struct ceph_mount_info *cmount, struct Inode *in); uint32_t ceph_ll_file_layout(struct ceph_mount_info *cmount, struct Inode *in, struct ceph_file_layout *layout); uint64_t ceph_ll_snap_seq(struct ceph_mount_info *cmount, struct Inode *in); int ceph_ll_get_stripe_osd(struct ceph_mount_info *cmount, struct Inode *in, uint64_t blockno, struct ceph_file_layout* layout); int ceph_ll_num_osds(struct ceph_mount_info *cmount); int ceph_ll_osdaddr(struct ceph_mount_info *cmount, int osd, uint32_t *addr); uint64_t ceph_ll_get_internal_offset(struct ceph_mount_info *cmount, struct Inode *in, uint64_t blockno); int ceph_ll_read_block(struct ceph_mount_info *cmount, struct Inode *in, uint64_t blockid, char* bl, uint64_t offset, uint64_t length, struct ceph_file_layout* layout); int ceph_ll_write_block(struct ceph_mount_info *cmount, struct Inode *in, uint64_t blockid, char* buf, uint64_t offset, uint64_t length, struct ceph_file_layout* layout, uint64_t snapseq, uint32_t sync); int ceph_ll_commit_blocks(struct ceph_mount_info *cmount, struct Inode *in, uint64_t offset, uint64_t range); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/include/stat.h0000664000175100017510000000523412623076744020237 0ustar jenkins-buildjenkins-build#ifndef CEPH_STAT_H #define CEPH_STAT_H #include #include /* * Access time-related `struct stat` members. * * Note that for each of the stat member get/set functions below, setting a * high-res value (stat_set_*_nsec) on a platform without high-res support is * a no-op. */ #ifdef HAVE_STAT_ST_MTIM_TV_NSEC static inline uint32_t stat_get_mtime_nsec(struct stat *st) { return st->st_mtim.tv_nsec; } static inline void stat_set_mtime_nsec(struct stat *st, uint32_t nsec) { st->st_mtim.tv_nsec = nsec; } static inline uint32_t stat_get_atime_nsec(struct stat *st) { return st->st_atim.tv_nsec; } static inline void stat_set_atime_nsec(struct stat *st, uint32_t nsec) { st->st_atim.tv_nsec = nsec; } static inline uint32_t stat_get_ctime_nsec(struct stat *st) { return st->st_ctim.tv_nsec; } static inline void stat_set_ctime_nsec(struct stat *st, uint32_t nsec) { st->st_ctim.tv_nsec = nsec; } #elif defined(HAVE_STAT_ST_MTIMESPEC_TV_NSEC) static inline uint32_t stat_get_mtime_nsec(struct stat *st) { return st->st_mtimespec.tv_nsec; } static inline void stat_set_mtime_nsec(struct stat *st, uint32_t nsec) { st->st_mtimespec.tv_nsec = nsec; } static inline uint32_t stat_get_atime_nsec(struct stat *st) { return st->st_atimespec.tv_nsec; } static inline void stat_set_atime_nsec(struct stat *st, uint32_t nsec) { st->st_atimespec.tv_nsec = nsec; } static inline uint32_t stat_get_ctime_nsec(struct stat *st) { return st->st_ctimespec.tv_nsec; } static inline void stat_set_ctime_nsec(struct stat *st, uint32_t nsec) { st->st_ctimespec.tv_nsec = nsec; } #else static inline uint32_t stat_get_mtime_nsec(struct stat *st) { return 0; } static inline void stat_set_mtime_nsec(struct stat *st, uint32_t nsec) { } static inline uint32_t stat_get_atime_nsec(struct stat *st) { return 0; } static inline void stat_set_atime_nsec(struct stat *st, uint32_t nsec) { } static inline uint32_t stat_get_ctime_nsec(struct stat *st) { return 0; } static inline void stat_set_ctime_nsec(struct stat *st, uint32_t nsec) { } #endif /* * Access second-resolution `struct stat` members. */ static inline uint32_t stat_get_mtime_sec(struct stat *st) { return st->st_mtime; } static inline void stat_set_mtime_sec(struct stat *st, uint32_t sec) { st->st_mtime = sec; } static inline uint32_t stat_get_atime_sec(struct stat *st) { return st->st_atime; } static inline void stat_set_atime_sec(struct stat *st, uint32_t sec) { st->st_atime = sec; } static inline uint32_t stat_get_ctime_sec(struct stat *st) { return st->st_ctime; } static inline void stat_set_ctime_sec(struct stat *st, uint32_t sec) { st->st_ctime = sec; } #endif ceph-0.80.11/src/include/Makefile.am0000664000175100017510000000415112623076744021144 0ustar jenkins-buildjenkins-buildlibcephfs_includedir = $(includedir)/cephfs libcephfs_include_DATA = $(srcdir)/include/cephfs/libcephfs.h librbd_includedir = $(includedir)/rbd librbd_include_DATA = \ $(srcdir)/include/rbd/features.h \ $(srcdir)/include/rbd/librbd.h \ $(srcdir)/include/rbd/librbd.hpp rados_includedir = $(includedir)/rados rados_include_DATA = \ $(srcdir)/include/rados/librados.h \ $(srcdir)/include/rados/rados_types.h \ $(srcdir)/include/rados/rados_types.hpp \ $(srcdir)/include/rados/librados.hpp \ $(srcdir)/include/buffer.h \ $(srcdir)/include/page.h \ $(srcdir)/include/crc32c.h \ $(srcdir)/include/memory.h noinst_HEADERS += \ include/Context.h \ include/CompatSet.h \ include/Distribution.h \ include/Spinlock.h \ include/addr_parsing.h \ include/assert.h \ include/atomic.h \ include/bitmapper.h \ include/blobhash.h \ include/buffer.h \ include/byteorder.h \ include/cephfs/libcephfs.h \ include/ceph_features.h \ include/ceph_frag.h \ include/ceph_fs.h \ include/ceph_hash.h \ include/cmp.h \ include/color.h \ include/compat.h \ include/crc32c.h \ include/encoding.h \ include/err.h \ include/error.h \ include/filepath.h \ include/frag.h \ include/hash.h \ include/intarith.h \ include/interval_set.h \ include/int_types.h \ include/ipaddr.h \ include/linux_fiemap.h \ include/lru.h \ include/msgr.h \ include/object.h \ include/page.h \ include/rangeset.h \ include/rados.h \ include/rbd_types.h \ include/statlite.h \ include/str_list.h \ include/str_map.h \ include/stringify.h \ include/triple.h \ include/types.h \ include/utime.h \ include/dlist.h \ include/elist.h \ include/uuid.h \ include/xlist.h \ include/rados/librados.h \ include/rados/rados_types.h \ include/rados/rados_types.hpp \ include/rados/librados.hpp \ include/rados/librgw.h \ include/rados/page.h \ include/rados/crc32c.h \ include/rados/buffer.h \ include/rbd/features.h \ include/rbd/librbd.h \ include/rbd/librbd.hpp\ include/util.h\ include/stat.h \ include/on_exit.h \ include/memory.h \ include/rados/memory.h \ include/hash_namespace.h \ include/unordered_set.h \ include/unordered_map.h ceph-0.80.11/src/include/msgr.h0000664000175100017510000001317112623076744020233 0ustar jenkins-buildjenkins-build#ifndef CEPH_MSGR_H #define CEPH_MSGR_H #ifdef __cplusplus #include // for struct sockaddr_storage #endif /* * Data types for message passing layer used by Ceph. */ #define CEPH_MON_PORT 6789 /* default monitor port */ /* * client-side processes will try to bind to ports in this * range, simply for the benefit of tools like nmap or wireshark * that would like to identify the protocol. */ #define CEPH_PORT_FIRST 6789 /* * tcp connection banner. include a protocol version. and adjust * whenever the wire protocol changes. try to keep this string length * constant. */ #define CEPH_BANNER "ceph v027" #define CEPH_BANNER_MAX_LEN 30 /* * Rollover-safe type and comparator for 32-bit sequence numbers. * Comparator returns -1, 0, or 1. */ typedef __u32 ceph_seq_t; static inline __s32 ceph_seq_cmp(__u32 a, __u32 b) { return (__s32)a - (__s32)b; } /* * entity_name -- logical name for a process participating in the * network, e.g. 'mds0' or 'osd3'. */ struct ceph_entity_name { __u8 type; /* CEPH_ENTITY_TYPE_* */ __le64 num; } __attribute__ ((packed)); #define CEPH_ENTITY_TYPE_MON 0x01 #define CEPH_ENTITY_TYPE_MDS 0x02 #define CEPH_ENTITY_TYPE_OSD 0x04 #define CEPH_ENTITY_TYPE_CLIENT 0x08 #define CEPH_ENTITY_TYPE_AUTH 0x20 #define CEPH_ENTITY_TYPE_ANY 0xFF extern const char *ceph_entity_type_name(int type); /* * entity_addr -- network address */ struct ceph_entity_addr { __le32 type; __le32 nonce; /* unique id for process (e.g. pid) */ struct sockaddr_storage in_addr; } __attribute__ ((packed)); struct ceph_entity_inst { struct ceph_entity_name name; struct ceph_entity_addr addr; } __attribute__ ((packed)); /* used by message exchange protocol */ #define CEPH_MSGR_TAG_READY 1 /* server->client: ready for messages */ #define CEPH_MSGR_TAG_RESETSESSION 2 /* server->client: reset, try again */ #define CEPH_MSGR_TAG_WAIT 3 /* server->client: wait for racing incoming connection */ #define CEPH_MSGR_TAG_RETRY_SESSION 4 /* server->client + cseq: try again with higher cseq */ #define CEPH_MSGR_TAG_RETRY_GLOBAL 5 /* server->client + gseq: try again with higher gseq */ #define CEPH_MSGR_TAG_CLOSE 6 /* closing pipe */ #define CEPH_MSGR_TAG_MSG 7 /* message */ #define CEPH_MSGR_TAG_ACK 8 /* message ack */ #define CEPH_MSGR_TAG_KEEPALIVE 9 /* just a keepalive byte! */ #define CEPH_MSGR_TAG_BADPROTOVER 10 /* bad protocol version */ #define CEPH_MSGR_TAG_BADAUTHORIZER 11 /* bad authorizer */ #define CEPH_MSGR_TAG_FEATURES 12 /* insufficient features */ #define CEPH_MSGR_TAG_SEQ 13 /* 64-bit int follows with seen seq number */ #define CEPH_MSGR_TAG_KEEPALIVE2 14 #define CEPH_MSGR_TAG_KEEPALIVE2_ACK 15 /* keepalive reply */ /* * connection negotiation */ struct ceph_msg_connect { __le64 features; /* supported feature bits */ __le32 host_type; /* CEPH_ENTITY_TYPE_* */ __le32 global_seq; /* count connections initiated by this host */ __le32 connect_seq; /* count connections initiated in this session */ __le32 protocol_version; __le32 authorizer_protocol; __le32 authorizer_len; __u8 flags; /* CEPH_MSG_CONNECT_* */ } __attribute__ ((packed)); struct ceph_msg_connect_reply { __u8 tag; __le64 features; /* feature bits for this session */ __le32 global_seq; __le32 connect_seq; __le32 protocol_version; __le32 authorizer_len; __u8 flags; } __attribute__ ((packed)); #define CEPH_MSG_CONNECT_LOSSY 1 /* messages i send may be safely dropped */ /* * message header */ struct ceph_msg_header_old { __le64 seq; /* message seq# for this session */ __le64 tid; /* transaction id */ __le16 type; /* message type */ __le16 priority; /* priority. higher value == higher priority */ __le16 version; /* version of message encoding */ __le32 front_len; /* bytes in main payload */ __le32 middle_len;/* bytes in middle payload */ __le32 data_len; /* bytes of data payload */ __le16 data_off; /* sender: include full offset; receiver: mask against ~PAGE_MASK */ struct ceph_entity_inst src, orig_src; __le32 reserved; __le32 crc; /* header crc32c */ } __attribute__ ((packed)); struct ceph_msg_header { __le64 seq; /* message seq# for this session */ __le64 tid; /* transaction id */ __le16 type; /* message type */ __le16 priority; /* priority. higher value == higher priority */ __le16 version; /* version of message encoding */ __le32 front_len; /* bytes in main payload */ __le32 middle_len;/* bytes in middle payload */ __le32 data_len; /* bytes of data payload */ __le16 data_off; /* sender: include full offset; receiver: mask against ~PAGE_MASK */ struct ceph_entity_name src; /* oldest code we think can decode this. unknown if zero. */ __le16 compat_version; __le16 reserved; __le32 crc; /* header crc32c */ } __attribute__ ((packed)); #define CEPH_MSG_PRIO_LOW 64 #define CEPH_MSG_PRIO_DEFAULT 127 #define CEPH_MSG_PRIO_HIGH 196 #define CEPH_MSG_PRIO_HIGHEST 255 /* * follows data payload * ceph_msg_footer_old does not support digital signatures on messages PLR */ struct ceph_msg_footer_old { __le32 front_crc, middle_crc, data_crc; __u8 flags; } __attribute__ ((packed)); struct ceph_msg_footer { __le32 front_crc, middle_crc, data_crc; // sig holds the 64 bits of the digital signature for the message PLR __le64 sig; __u8 flags; } __attribute__ ((packed)); #define CEPH_MSG_FOOTER_COMPLETE (1<<0) /* msg wasn't aborted */ #define CEPH_MSG_FOOTER_NOCRC (1<<1) /* no data crc */ #define CEPH_MSG_FOOTER_SIGNED (1<<2) /* msg was signed */ #endif ceph-0.80.11/src/include/page.h0000664000175100017510000000050312623076744020172 0ustar jenkins-buildjenkins-build#ifndef CEPH_PAGE_H #define CEPH_PAGE_H namespace ceph { // these are in common/page.cc extern unsigned _page_size; extern unsigned long _page_mask; extern unsigned _page_shift; } #endif #define CEPH_PAGE_SIZE ceph::_page_size #define CEPH_PAGE_MASK ceph::_page_mask #define CEPH_PAGE_SHIFT ceph::_page_shift ceph-0.80.11/src/include/ceph_frag.h0000664000175100017510000000605212623076744021201 0ustar jenkins-buildjenkins-build#ifndef FS_CEPH_FRAG_H #define FS_CEPH_FRAG_H /* * "Frags" are a way to describe a subset of a 32-bit number space, * using a mask and a value to match against that mask. Any given frag * (subset of the number space) can be partitioned into 2^n sub-frags. * * Frags are encoded into a 32-bit word: * 8 upper bits = "bits" * 24 lower bits = "value" * (We could go to 5+27 bits, but who cares.) * * We use the _most_ significant bits of the 24 bit value. This makes * values logically sort. * * Unfortunately, because the "bits" field is still in the high bits, we * can't sort encoded frags numerically. However, it does allow you * to feed encoded frags as values into frag_contains_value. */ static inline __u32 ceph_frag_make(__u32 b, __u32 v) { return (b << 24) | (v & (0xffffffu << (24-b)) & 0xffffffu); } static inline __u32 ceph_frag_bits(__u32 f) { return f >> 24; } static inline __u32 ceph_frag_value(__u32 f) { return f & 0xffffffu; } static inline __u32 ceph_frag_mask(__u32 f) { return (0xffffffu << (24-ceph_frag_bits(f))) & 0xffffffu; } static inline __u32 ceph_frag_mask_shift(__u32 f) { return 24 - ceph_frag_bits(f); } static inline int ceph_frag_contains_value(__u32 f, __u32 v) { return (v & ceph_frag_mask(f)) == ceph_frag_value(f); } static inline int ceph_frag_contains_frag(__u32 f, __u32 sub) { /* is sub as specific as us, and contained by us? */ return ceph_frag_bits(sub) >= ceph_frag_bits(f) && (ceph_frag_value(sub) & ceph_frag_mask(f)) == ceph_frag_value(f); } static inline __u32 ceph_frag_parent(__u32 f) { return ceph_frag_make(ceph_frag_bits(f) - 1, ceph_frag_value(f) & (ceph_frag_mask(f) << 1)); } static inline int ceph_frag_is_left_child(__u32 f) { return ceph_frag_bits(f) > 0 && (ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 0; } static inline int ceph_frag_is_right_child(__u32 f) { return ceph_frag_bits(f) > 0 && (ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 1; } static inline __u32 ceph_frag_sibling(__u32 f) { return ceph_frag_make(ceph_frag_bits(f), ceph_frag_value(f) ^ (0x1000000 >> ceph_frag_bits(f))); } static inline __u32 ceph_frag_left_child(__u32 f) { return ceph_frag_make(ceph_frag_bits(f)+1, ceph_frag_value(f)); } static inline __u32 ceph_frag_right_child(__u32 f) { return ceph_frag_make(ceph_frag_bits(f)+1, ceph_frag_value(f) | (0x1000000 >> (1+ceph_frag_bits(f)))); } static inline __u32 ceph_frag_make_child(__u32 f, int by, int i) { int newbits = ceph_frag_bits(f) + by; return ceph_frag_make(newbits, ceph_frag_value(f) | (i << (24 - newbits))); } static inline int ceph_frag_is_leftmost(__u32 f) { return ceph_frag_value(f) == 0; } static inline int ceph_frag_is_rightmost(__u32 f) { return ceph_frag_value(f) == ceph_frag_mask(f); } static inline __u32 ceph_frag_next(__u32 f) { return ceph_frag_make(ceph_frag_bits(f), ceph_frag_value(f) + (0x1000000 >> ceph_frag_bits(f))); } /* * comparator to sort frags logically, as when traversing the * number space in ascending order... */ int ceph_frag_compare(__u32 a, __u32 b); #endif ceph-0.80.11/src/include/rbd_types.h0000664000175100017510000000531412623076744021256 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * Copyright (C) 2004-2010 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RBD_TYPES_H #define CEPH_RBD_TYPES_H #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif #include "rbd/features.h" /* New-style rbd image 'foo' consists of objects * rbd_id.foo - id of image * rbd_header. - image metadata * rbd_data..00000000 * rbd_data..00000001 * ... - data */ #define RBD_HEADER_PREFIX "rbd_header." #define RBD_DATA_PREFIX "rbd_data." #define RBD_ID_PREFIX "rbd_id." /* * old-style rbd image 'foo' consists of objects * foo.rbd - image metadata * rb...00000000 * rb...00000001 * ... - data */ #define RBD_SUFFIX ".rbd" #define RBD_DIRECTORY "rbd_directory" #define RBD_INFO "rbd_info" /* * rbd_children object in each pool contains omap entries * that map parent (poolid, imageid, snapid) to a list of children * (imageids; snapids aren't required because we get all the snapshot * info from a read of the child's header object anyway). * * The clone operation writes a new item to this child list, and rm or * flatten removes an item, and may remove the whole entry if no children * exist after the rm/flatten. * * When attempting to remove a parent, all pools are searched for * rbd_children objects with entries referring to that parent; if any * exist (and those children exist), the parent removal is prevented. */ #define RBD_CHILDREN "rbd_children" #define RBD_LOCK_NAME "rbd_lock" #define RBD_DEFAULT_OBJ_ORDER 22 /* 4MB */ #define RBD_MAX_OBJ_NAME_SIZE 96 #define RBD_MAX_BLOCK_NAME_SIZE 24 #define RBD_COMP_NONE 0 #define RBD_CRYPT_NONE 0 #define RBD_HEADER_TEXT "<<< Rados Block Device Image >>>\n" #define RBD_HEADER_SIGNATURE "RBD" #define RBD_HEADER_VERSION "001.005" struct rbd_info { __le64 max_id; } __attribute__ ((packed)); struct rbd_obj_snap_ondisk { __le64 id; __le64 image_size; } __attribute__((packed)); struct rbd_obj_header_ondisk { char text[40]; char block_name[RBD_MAX_BLOCK_NAME_SIZE]; char signature[4]; char version[8]; struct { __u8 order; __u8 crypt_type; __u8 comp_type; __u8 unused; } __attribute__((packed)) options; __le64 image_size; __le64 snap_seq; __le32 snap_count; __le32 reserved; __le64 snap_names_len; struct rbd_obj_snap_ondisk snaps[0]; } __attribute__((packed)); #endif ceph-0.80.11/src/include/filepath.h0000664000175100017510000001261012623076744021054 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_FILEPATH_H #define CEPH_FILEPATH_H /* * BUG: /a/b/c is equivalent to a/b/c in dentry-breakdown, but not string. * -> should it be different? how? should this[0] be "", with depth 4? * */ #include #include #include using namespace std; #include "buffer.h" #include "encoding.h" #include "common/Formatter.h" class filepath { inodeno_t ino; // base inode. ino=0 implies pure relative path. string path; // relative path. /** bits - path segments * this is ['a', 'b', 'c'] for both the aboslute and relative case. * * NOTE: this value is LAZILY maintained... i.e. it's a cache */ mutable vector bits; bool encoded; void rebuild_path() { path.clear(); for (unsigned i=0; i 0) || encoded) { // skip empty components unless they were introduced deliberately // see commit message for more detail bits.push_back( path.substr(off,nextslash-off) ); } off = nextslash+1; } } public: filepath() : ino(0), encoded(false) { } filepath(const string& s, inodeno_t i) : ino(i), path(s), encoded(false) { } filepath(const char* s, inodeno_t i) : ino(i), path(s), encoded(false) { } filepath(const filepath& o) { ino = o.ino; path = o.path; bits = o.bits; encoded = o.encoded; } filepath(inodeno_t i) : ino(i), encoded(false) { } void set_path(const char *s, inodeno_t b) { path = s; ino = b; } /* * if we are fed a relative path as a string, either set ino=0 (strictly * relative) or 1 (absolute). throw out any leading '/'. */ filepath(const char *s) : encoded(false) { set_path(s); } void set_path(const char *s) { if (s[0] == '/') { path = s + 1; ino = 1; } else { ino = 0; path = s; } bits.clear(); } // accessors inodeno_t get_ino() const { return ino; } const string& get_path() const { return path; } const char *c_str() const { return path.c_str(); } int length() const { return path.length(); } unsigned depth() const { if (bits.empty() && path.length() > 0) parse_bits(); return bits.size(); } bool empty() const { return path.length() == 0 && ino == 0; } bool absolute() const { return ino == 1; } bool pure_relative() const { return ino == 0; } bool ino_relative() const { return ino > 0; } const string& operator[](int i) const { if (bits.empty() && path.length() > 0) parse_bits(); return bits[i]; } const string& last_dentry() const { if (bits.empty() && path.length() > 0) parse_bits(); return bits[ bits.size()-1 ]; } filepath prefixpath(int s) const { filepath t(ino); for (int i=0; i 0) parse_bits(); bits.pop_back(); rebuild_path(); } void push_dentry(const string& s) { if (bits.empty() && path.length() > 0) parse_bits(); if (!bits.empty()) path += "/"; path += s; bits.push_back(s); } void push_dentry(const char *cs) { string s = cs; push_dentry(s); } void push_front_dentry(const string& s) { bits.insert(bits.begin(), s); rebuild_path(); } void append(const filepath& a) { assert(a.pure_relative()); for (unsigned i=0; idump_unsigned("base_ino", ino); f->dump_string("relative_path", path); } static void generate_test_instances(list& o) { o.push_back(new filepath); o.push_back(new filepath("/usr/bin", 0)); o.push_back(new filepath("/usr/sbin", 1)); o.push_back(new filepath("var/log", 1)); o.push_back(new filepath("foo/bar", 101)); } }; WRITE_CLASS_ENCODER(filepath) inline ostream& operator<<(ostream& out, const filepath& path) { if (path.get_ino()) { out << '#' << path.get_ino(); if (path.depth()) out << '/'; } return out << path.get_path(); } #endif ceph-0.80.11/src/include/byteorder.h0000664000175100017510000000452612623076744021266 0ustar jenkins-buildjenkins-build/* * byteorder.h * * LGPL 2 */ #ifndef CEPH_BYTEORDER_H #define CEPH_BYTEORDER_H #include #include "int_types.h" #if defined(__APPLE__) # if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN # define CEPH_LITTLE_ENDIAN # elif __DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN # define CEPH_BIG_ENDIAN # endif #endif #if defined(__FreeBSD__) # if _BYTE_ORDER == _LITTLE_ENDIAN # define CEPH_LITTLE_ENDIAN # elif _BYTE_ORDER == _BIG_ENDIAN # define CEPH_BIG_ENDIAN # endif #endif #if defined(__linux__) # if BYTE_ORDER == LITTLE_ENDIAN # define CEPH_LITTLE_ENDIAN # elif BYTE_ORDER == BIG_ENDIAN # define CEPH_BIG_ENDIAN # endif #endif static __inline__ __u16 swab16(__u16 val) { return (val >> 8) | (val << 8); } static __inline__ __u32 swab32(__u32 val) { return (( val >> 24) | ((val >> 8) & 0xff00) | ((val << 8) & 0xff0000) | ((val << 24))); } static __inline__ uint64_t swab64(uint64_t val) { return (( val >> 56) | ((val >> 40) & 0xff00ull) | ((val >> 24) & 0xff0000ull) | ((val >> 8) & 0xff000000ull) | ((val << 8) & 0xff00000000ull) | ((val << 24) & 0xff0000000000ull) | ((val << 40) & 0xff000000000000ull) | ((val << 56))); } // mswab == maybe swab (if not LE) #ifdef CEPH_BIG_ENDIAN # define mswab64(a) swab64(a) # define mswab32(a) swab32(a) # define mswab16(a) swab16(a) #elif defined(CEPH_LITTLE_ENDIAN) # define mswab64(a) (a) # define mswab32(a) (a) # define mswab16(a) (a) #else # error "Could not determine endianess" #endif #ifdef __cplusplus #define MAKE_LE_CLASS(bits) \ struct ceph_le##bits { \ __u##bits v; \ ceph_le##bits &operator=(__u##bits nv) { \ v = mswab##bits(nv); \ return *this; \ } \ operator __u##bits() const { return mswab##bits(v); } \ } __attribute__ ((packed)); \ static inline bool operator==(ceph_le##bits a, ceph_le##bits b) { \ return a.v == b.v; \ } MAKE_LE_CLASS(64) MAKE_LE_CLASS(32) MAKE_LE_CLASS(16) #undef MAKE_LE_CLASS #endif /* __cplusplus */ #define init_le64(x) { (__u64)mswab64(x) } #define init_le32(x) { (__u32)mswab32(x) } #define init_le16(x) { (__u16)mswab16(x) } /* #define cpu_to_le64(x) (x) #define cpu_to_le32(x) (x) #define cpu_to_le16(x) (x) */ #define le64_to_cpu(x) ((uint64_t)x) #define le32_to_cpu(x) ((__u32)x) #define le16_to_cpu(x) ((__u16)x) #endif ceph-0.80.11/src/include/types.h0000664000175100017510000002470112623076744020430 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_TYPES_H #define CEPH_TYPES_H // this is needed for ceph_fs to compile in userland #include "int_types.h" #include "byteorder.h" #include "uuid.h" #include #include #include // // temporarily remap __le* to ceph_le* for benefit of shared kernel/userland headers #define __le16 ceph_le16 #define __le32 ceph_le32 #define __le64 ceph_le64 #include "ceph_fs.h" #include "ceph_frag.h" #include "rbd_types.h" #undef __le16 #undef __le32 #undef __le64 // #ifdef __cplusplus #ifndef _BACKWARD_BACKWARD_WARNING_H #define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_* #endif #endif extern "C" { #include #include #include #include "statlite.h" } #include #include #include #include #include #include #include using namespace std; #include "include/unordered_map.h" #include "include/hash_namespace.h" #include "object.h" #include "intarith.h" #include "acconfig.h" #include "assert.h" // DARWIN compatibility #ifdef DARWIN typedef long long loff_t; typedef long long off64_t; #define O_DIRECT 00040000 #endif // FreeBSD compatibility #ifdef __FreeBSD__ typedef off_t loff_t; typedef off_t off64_t; #endif // -- io helpers -- template inline ostream& operator<<(ostream& out, const pair& v) { return out << v.first << "," << v.second; } template inline ostream& operator<<(ostream& out, const vector& v) { out << "["; for (typename vector::const_iterator p = v.begin(); p != v.end(); ++p) { if (p != v.begin()) out << ","; out << *p; } out << "]"; return out; } template inline ostream& operator<<(ostream& out, const deque& v) { out << "<"; for (typename deque::const_iterator p = v.begin(); p != v.end(); ++p) { if (p != v.begin()) out << ","; out << *p; } out << ">"; return out; } template inline ostream& operator<<(ostream& out, const list& ilist) { for (typename list::const_iterator it = ilist.begin(); it != ilist.end(); ++it) { if (it != ilist.begin()) out << ","; out << *it; } return out; } template inline ostream& operator<<(ostream& out, const set& iset) { for (typename set::const_iterator it = iset.begin(); it != iset.end(); ++it) { if (it != iset.begin()) out << ","; out << *it; } return out; } template inline ostream& operator<<(ostream& out, const multiset& iset) { for (typename multiset::const_iterator it = iset.begin(); it != iset.end(); ++it) { if (it != iset.begin()) out << ","; out << *it; } return out; } template inline ostream& operator<<(ostream& out, const map& m) { out << "{"; for (typename map::const_iterator it = m.begin(); it != m.end(); ++it) { if (it != m.begin()) out << ","; out << it->first << "=" << it->second; } out << "}"; return out; } template inline ostream& operator<<(ostream& out, const multimap& m) { out << "{{"; for (typename multimap::const_iterator it = m.begin(); it != m.end(); ++it) { if (it != m.begin()) out << ","; out << it->first << "=" << it->second; } out << "}}"; return out; } /* * comparators for stl containers */ // for ceph::unordered_map: // ceph::unordered_map, eqstr> vals; struct eqstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } }; // for set, map struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; #include "encoding.h" WRITE_RAW_ENCODER(ceph_fsid) WRITE_RAW_ENCODER(ceph_file_layout) WRITE_RAW_ENCODER(ceph_dir_layout) WRITE_RAW_ENCODER(ceph_mds_session_head) WRITE_RAW_ENCODER(ceph_mds_request_head) WRITE_RAW_ENCODER(ceph_mds_request_release) WRITE_RAW_ENCODER(ceph_filelock) WRITE_RAW_ENCODER(ceph_mds_caps) WRITE_RAW_ENCODER(ceph_mds_cap_peer) WRITE_RAW_ENCODER(ceph_mds_cap_release) WRITE_RAW_ENCODER(ceph_mds_cap_item) WRITE_RAW_ENCODER(ceph_mds_lease) WRITE_RAW_ENCODER(ceph_mds_snap_head) WRITE_RAW_ENCODER(ceph_mds_snap_realm) WRITE_RAW_ENCODER(ceph_mds_reply_head) WRITE_RAW_ENCODER(ceph_mds_reply_inode) WRITE_RAW_ENCODER(ceph_mds_cap_reconnect) WRITE_RAW_ENCODER(ceph_mds_snaprealm_reconnect) WRITE_RAW_ENCODER(ceph_frag_tree_split) WRITE_RAW_ENCODER(ceph_osd_reply_head) WRITE_RAW_ENCODER(ceph_osd_op) WRITE_RAW_ENCODER(ceph_msg_header) WRITE_RAW_ENCODER(ceph_msg_footer) WRITE_RAW_ENCODER(ceph_msg_footer_old) WRITE_RAW_ENCODER(ceph_mon_subscribe_item) WRITE_RAW_ENCODER(ceph_mon_statfs) WRITE_RAW_ENCODER(ceph_mon_statfs_reply) // ---------------------- // some basic types // NOTE: these must match ceph_fs.h typedefs typedef uint64_t ceph_tid_t; // transaction id typedef uint64_t version_t; typedef __u32 epoch_t; // map epoch (32bits -> 13 epochs/second for 10 years) // -------------------------------------- // identify individual mount clients by 64bit value struct client_t { int64_t v; client_t(int64_t _v = -2) : v(_v) {} void encode(bufferlist& bl) const { ::encode(v, bl); } void decode(bufferlist::iterator& bl) { ::decode(v, bl); } }; WRITE_CLASS_ENCODER(client_t) static inline bool operator==(const client_t& l, const client_t& r) { return l.v == r.v; } static inline bool operator!=(const client_t& l, const client_t& r) { return l.v != r.v; } static inline bool operator<(const client_t& l, const client_t& r) { return l.v < r.v; } static inline bool operator<=(const client_t& l, const client_t& r) { return l.v <= r.v; } static inline bool operator>(const client_t& l, const client_t& r) { return l.v > r.v; } static inline bool operator>=(const client_t& l, const client_t& r) { return l.v >= r.v; } static inline bool operator>=(const client_t& l, int64_t o) { return l.v >= o; } static inline bool operator<(const client_t& l, int64_t o) { return l.v < o; } inline ostream& operator<<(ostream& out, const client_t& c) { return out << c.v; } // -------------------------------------- // ino typedef uint64_t _inodeno_t; struct inodeno_t { _inodeno_t val; inodeno_t() : val(0) {} inodeno_t(_inodeno_t v) : val(v) {} inodeno_t operator+=(inodeno_t o) { val += o.val; return *this; } operator _inodeno_t() const { return val; } void encode(bufferlist& bl) const { ::encode(val, bl); } void decode(bufferlist::iterator& p) { ::decode(val, p); } } __attribute__ ((__may_alias__)); WRITE_CLASS_ENCODER(inodeno_t) inline ostream& operator<<(ostream& out, inodeno_t ino) { return out << hex << ino.val << dec; } CEPH_HASH_NAMESPACE_START template<> struct hash< inodeno_t > { size_t operator()( const inodeno_t& x ) const { static rjhash H; return H(x.val); } }; CEPH_HASH_NAMESPACE_END // file modes static inline bool file_mode_is_readonly(int mode) { return (mode & CEPH_FILE_MODE_WR) == 0; } // dentries #define MAX_DENTRY_LEN 255 // -- namespace ceph { class Formatter; } void dump(const ceph_file_layout& l, ceph::Formatter *f); void dump(const ceph_dir_layout& l, ceph::Formatter *f); // -- struct prettybyte_t { uint64_t v; prettybyte_t(uint64_t _v) : v(_v) {} }; inline ostream& operator<<(ostream& out, const prettybyte_t& b) { uint64_t bump_after = 100; if (b.v > bump_after << 60) return out << (b.v >> 60) << " EB"; if (b.v > bump_after << 50) return out << (b.v >> 50) << " PB"; if (b.v > bump_after << 40) return out << (b.v >> 40) << " TB"; if (b.v > bump_after << 30) return out << (b.v >> 30) << " GB"; if (b.v > bump_after << 20) return out << (b.v >> 20) << " MB"; if (b.v > bump_after << 10) return out << (b.v >> 10) << " kB"; return out << b.v << " bytes"; } struct si_t { uint64_t v; si_t(uint64_t _v) : v(_v) {} }; inline ostream& operator<<(ostream& out, const si_t& b) { uint64_t bump_after = 100; if (b.v > bump_after << 60) return out << (b.v >> 60) << "E"; if (b.v > bump_after << 50) return out << (b.v >> 50) << "P"; if (b.v > bump_after << 40) return out << (b.v >> 40) << "T"; if (b.v > bump_after << 30) return out << (b.v >> 30) << "G"; if (b.v > bump_after << 20) return out << (b.v >> 20) << "M"; if (b.v > bump_after << 10) return out << (b.v >> 10) << "k"; return out << b.v; } struct pretty_si_t { uint64_t v; pretty_si_t(uint64_t _v) : v(_v) {} }; inline ostream& operator<<(ostream& out, const pretty_si_t& b) { uint64_t bump_after = 100; if (b.v > bump_after << 60) return out << (b.v >> 60) << " E"; if (b.v > bump_after << 50) return out << (b.v >> 50) << " P"; if (b.v > bump_after << 40) return out << (b.v >> 40) << " T"; if (b.v > bump_after << 30) return out << (b.v >> 30) << " G"; if (b.v > bump_after << 20) return out << (b.v >> 20) << " M"; if (b.v > bump_after << 10) return out << (b.v >> 10) << " k"; return out << b.v << " "; } struct kb_t { uint64_t v; kb_t(uint64_t _v) : v(_v) {} }; inline ostream& operator<<(ostream& out, const kb_t& kb) { uint64_t bump_after = 100; if (kb.v > bump_after << 40) return out << (kb.v >> 40) << " PB"; if (kb.v > bump_after << 30) return out << (kb.v >> 30) << " TB"; if (kb.v > bump_after << 20) return out << (kb.v >> 20) << " GB"; if (kb.v > bump_after << 10) return out << (kb.v >> 10) << " MB"; return out << kb.v << " kB"; } inline ostream& operator<<(ostream& out, const ceph_mon_subscribe_item& i) { return out << i.start << ((i.flags & CEPH_SUBSCRIBE_ONETIME) ? "" : "+"); } enum health_status_t { HEALTH_ERR = 0, HEALTH_WARN = 1, HEALTH_OK = 2, }; #ifdef __cplusplus inline ostream& operator<<(ostream &oss, health_status_t status) { switch (status) { case HEALTH_ERR: oss << "HEALTH_ERR"; break; case HEALTH_WARN: oss << "HEALTH_WARN"; break; case HEALTH_OK: oss << "HEALTH_OK"; break; } return oss; }; #endif #endif ceph-0.80.11/src/include/encoding.h0000664000175100017510000005420312623076744021052 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_ENCODING_H #define CEPH_ENCODING_H #include "include/int_types.h" #include "include/memory.h" #include "byteorder.h" #include "buffer.h" #include "assert.h" using namespace ceph; /* * Notes on feature encoding: * * - The default encode() methods have a features argument with a default parameter * (which goes to zero). * - Normal classes will use WRITE_CLASS_ENCODER, with that features=0 default. * - Classes that _require_ features will use WRITE_CLASS_ENCODER_FEATURES, which * does not define the default. Any caller must explicitly pass it in. * - STL container macros have two encode variants: one with a features arg, and one * without. * * The result: * - A feature encode() method will fail to compile if a value is not * passed in. * - The feature varianet of the STL templates will be used when the feature arg is * provided. It will be passed through to any template arg types, but it will be * ignored when not needed. */ // -------------------------------------- // base types template inline void encode_raw(const T& t, bufferlist& bl) { bl.append((char*)&t, sizeof(t)); } template inline void decode_raw(T& t, bufferlist::iterator &p) { p.copy(sizeof(t), (char*)&t); } #define WRITE_RAW_ENCODER(type) \ inline void encode(const type &v, bufferlist& bl, uint64_t features=0) { encode_raw(v, bl); } \ inline void decode(type &v, bufferlist::iterator& p) { __ASSERT_FUNCTION decode_raw(v, p); } WRITE_RAW_ENCODER(__u8) WRITE_RAW_ENCODER(__s8) WRITE_RAW_ENCODER(char) WRITE_RAW_ENCODER(ceph_le64) WRITE_RAW_ENCODER(ceph_le32) WRITE_RAW_ENCODER(ceph_le16) // FIXME: we need to choose some portable floating point encoding here WRITE_RAW_ENCODER(float) WRITE_RAW_ENCODER(double) inline void encode(const bool &v, bufferlist& bl) { __u8 vv = v; encode_raw(vv, bl); } inline void decode(bool &v, bufferlist::iterator& p) { __u8 vv; decode_raw(vv, p); v = vv; } // ----------------------------------- // int types #define WRITE_INTTYPE_ENCODER(type, etype) \ inline void encode(type v, bufferlist& bl, uint64_t features=0) { \ ceph_##etype e; \ e = v; \ encode_raw(e, bl); \ } \ inline void decode(type &v, bufferlist::iterator& p) { \ ceph_##etype e; \ decode_raw(e, p); \ v = e; \ } WRITE_INTTYPE_ENCODER(uint64_t, le64) WRITE_INTTYPE_ENCODER(int64_t, le64) WRITE_INTTYPE_ENCODER(uint32_t, le32) WRITE_INTTYPE_ENCODER(int32_t, le32) WRITE_INTTYPE_ENCODER(uint16_t, le16) WRITE_INTTYPE_ENCODER(int16_t, le16) #ifdef ENCODE_DUMP # include # include # include # include # define ENCODE_STR(x) #x # define ENCODE_STRINGIFY(x) ENCODE_STR(x) # define ENCODE_DUMP_PRE() \ unsigned pre_off = bl.length() // NOTE: This is almost an exponential backoff, but because we count // bits we get a better sample of things we encode later on. # define ENCODE_DUMP_POST(cl) \ do { \ static int i = 0; \ i++; \ int bits = 0; \ for (unsigned t = i; t; bits++) \ t &= t - 1; \ if (bits > 2) \ break; \ char fn[200]; \ snprintf(fn, sizeof(fn), ENCODE_STRINGIFY(ENCODE_DUMP) "/%s__%d.%x", #cl, getpid(), i++); \ int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); \ if (fd >= 0) { \ bufferlist sub; \ sub.substr_of(bl, pre_off, bl.length() - pre_off); \ sub.write_fd(fd); \ ::close(fd); \ } \ } while (0) #else # define ENCODE_DUMP_PRE() # define ENCODE_DUMP_POST(cl) #endif #define WRITE_CLASS_ENCODER(cl) \ inline void encode(const cl &c, bufferlist &bl, uint64_t features=0) { \ ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \ inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } #define WRITE_CLASS_MEMBER_ENCODER(cl) \ inline void encode(const cl &c, bufferlist &bl) const { \ ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \ inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } #define WRITE_CLASS_ENCODER_FEATURES(cl) \ inline void encode(const cl &c, bufferlist &bl, uint64_t features) { \ ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \ inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } // string inline void encode(const std::string& s, bufferlist& bl, uint64_t features=0) { __u32 len = s.length(); encode(len, bl); bl.append(s.data(), len); } inline void decode(std::string& s, bufferlist::iterator& p) { __u32 len; decode(len, p); s.clear(); p.copy(len, s); } inline void encode_nohead(const std::string& s, bufferlist& bl) { bl.append(s.data(), s.length()); } inline void decode_nohead(int len, std::string& s, bufferlist::iterator& p) { s.clear(); p.copy(len, s); } // const char* (encode only, string compatible) inline void encode(const char *s, bufferlist& bl) { __u32 len = strlen(s); encode(len, bl); bl.append(s, len); } // array template inline void encode_array_nohead(const A a[], int n, bufferlist &bl) { for (int i=0; i inline void decode_array_nohead(A a[], int n, bufferlist::iterator &p) { for (int i=0; i inline void decode(T &o, bufferlist& bl) { bufferlist::iterator p = bl.begin(); decode(o, p); assert(p.end()); } // ----------------------------- // STL container types #include #include #include #include #include #include #ifndef _BACKWARD_BACKWARD_WARNING_H #define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_* #endif #include "include/unordered_map.h" #include "include/unordered_set.h" #include "triple.h" // boost optional template inline void encode(const boost::optional &p, bufferlist &bl) { __u8 present = static_cast(p); ::encode(present, bl); if (p) encode(p.get(), bl); } template inline void decode(boost::optional &p, bufferlist::iterator &bp) { __u8 present; ::decode(present, bp); if (present) { T t; p = t; decode(p.get(), bp); } } // pair template inline void encode(const std::pair &p, bufferlist &bl, uint64_t features) { encode(p.first, bl, features); encode(p.second, bl, features); } template inline void encode(const std::pair &p, bufferlist &bl) { encode(p.first, bl); encode(p.second, bl); } template inline void decode(std::pair &pa, bufferlist::iterator &p) { decode(pa.first, p); decode(pa.second, p); } // triple template inline void encode(const triple &t, bufferlist &bl) { encode(t.first, bl); encode(t.second, bl); encode(t.third, bl); } template inline void decode(triple &t, bufferlist::iterator &p) { decode(t.first, p); decode(t.second, p); decode(t.third, p); } // list template inline void encode(const std::list& ls, bufferlist& bl) { // should i pre- or post- count? if (!ls.empty()) { unsigned pos = bl.length(); unsigned n = 0; encode(n, bl); for (typename std::list::const_iterator p = ls.begin(); p != ls.end(); ++p) { n++; encode(*p, bl); } ceph_le32 en; en = n; bl.copy_in(pos, sizeof(en), (char*)&en); } else { __u32 n = ls.size(); // FIXME: this is slow on a list. encode(n, bl); for (typename std::list::const_iterator p = ls.begin(); p != ls.end(); ++p) encode(*p, bl); } } template inline void decode(std::list& ls, bufferlist::iterator& p) { __u32 n; decode(n, p); ls.clear(); while (n--) { T v; decode(v, p); ls.push_back(v); } } template inline void encode(const std::list >& ls, bufferlist& bl) { // should i pre- or post- count? if (!ls.empty()) { unsigned pos = bl.length(); unsigned n = 0; encode(n, bl); for (typename std::list >::const_iterator p = ls.begin(); p != ls.end(); ++p) { n++; encode(**p, bl); } ceph_le32 en; en = n; bl.copy_in(pos, sizeof(en), (char*)&en); } else { __u32 n = ls.size(); // FIXME: this is slow on a list. encode(n, bl); for (typename std::list >::const_iterator p = ls.begin(); p != ls.end(); ++p) encode(**p, bl); } } template inline void decode(std::list >& ls, bufferlist::iterator& p) { __u32 n; decode(n, p); ls.clear(); while (n--) { ceph::shared_ptr v(new T); decode(*v, p); ls.push_back(v); } } // set template inline void encode(const std::set& s, bufferlist& bl) { __u32 n = s.size(); encode(n, bl); for (typename std::set::const_iterator p = s.begin(); p != s.end(); ++p) encode(*p, bl); } template inline void decode(std::set& s, bufferlist::iterator& p) { __u32 n; decode(n, p); s.clear(); while (n--) { T v; decode(v, p); s.insert(v); } } // vector (pointers) /*template inline void encode(const std::vector& v, bufferlist& bl) { __u32 n = v.size(); encode(n, bl); for (typename std::vector::const_iterator p = v.begin(); p != v.end(); ++p) encode(**p, bl); } template inline void decode(std::vector& v, bufferlist::iterator& p) { __u32 n; decode(n, p); v.resize(n); for (__u32 i=0; i inline void encode(const std::vector& v, bufferlist& bl, uint64_t features) { __u32 n = v.size(); encode(n, bl); for (typename std::vector::const_iterator p = v.begin(); p != v.end(); ++p) encode(*p, bl, features); } template inline void encode(const std::vector& v, bufferlist& bl) { __u32 n = v.size(); encode(n, bl); for (typename std::vector::const_iterator p = v.begin(); p != v.end(); ++p) encode(*p, bl); } template inline void decode(std::vector& v, bufferlist::iterator& p) { __u32 n; decode(n, p); v.resize(n); for (__u32 i=0; i inline void encode_nohead(const std::vector& v, bufferlist& bl) { for (typename std::vector::const_iterator p = v.begin(); p != v.end(); ++p) encode(*p, bl); } template inline void decode_nohead(int len, std::vector& v, bufferlist::iterator& p) { v.resize(len); for (__u32 i=0; i inline void encode(const std::vector >& v, bufferlist& bl) { __u32 n = v.size(); encode(n, bl); for (typename std::vector >::const_iterator p = v.begin(); p != v.end(); ++p) if (*p) encode(**p, bl); else encode(T(), bl); } template inline void decode(std::vector >& v, bufferlist::iterator& p) { __u32 n; decode(n, p); v.resize(n); for (__u32 i=0; i inline void encode(const std::map& m, bufferlist& bl) { __u32 n = m.size(); encode(n, bl); for (typename std::map::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl); encode(*p->second, bl); } } template inline void decode(std::map& m, bufferlist::iterator& p) { __u32 n; decode(n, p); m.clear(); while (n--) { T k; decode(k, p); m[k] = new U(p); } }*/ // map template inline void encode(const std::map& m, bufferlist& bl) { __u32 n = m.size(); encode(n, bl); for (typename std::map::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl); encode(p->second, bl); } } template inline void encode(const std::map& m, bufferlist& bl, uint64_t features) { __u32 n = m.size(); encode(n, bl); for (typename std::map::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl, features); encode(p->second, bl, features); } } template inline void decode(std::map& m, bufferlist::iterator& p) { __u32 n; decode(n, p); m.clear(); while (n--) { T k; decode(k, p); decode(m[k], p); } } template inline void decode_noclear(std::map& m, bufferlist::iterator& p) { __u32 n; decode(n, p); while (n--) { T k; decode(k, p); decode(m[k], p); } } template inline void encode_nohead(const std::map& m, bufferlist& bl) { for (typename std::map::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl); encode(p->second, bl); } } template inline void encode_nohead(const std::map& m, bufferlist& bl, uint64_t features) { for (typename std::map::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl, features); encode(p->second, bl, features); } } template inline void decode_nohead(int n, std::map& m, bufferlist::iterator& p) { m.clear(); while (n--) { T k; decode(k, p); decode(m[k], p); } } // multimap template inline void encode(const std::multimap& m, bufferlist& bl) { __u32 n = m.size(); encode(n, bl); for (typename std::multimap::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl); encode(p->second, bl); } } template inline void decode(std::multimap& m, bufferlist::iterator& p) { __u32 n; decode(n, p); m.clear(); while (n--) { typename std::pair tu = std::pair(); decode(tu.first, p); typename std::multimap::iterator it = m.insert(tu); decode(it->second, p); } } // ceph::unordered_map template inline void encode(const unordered_map& m, bufferlist& bl) { __u32 n = m.size(); encode(n, bl); for (typename unordered_map::const_iterator p = m.begin(); p != m.end(); ++p) { encode(p->first, bl); encode(p->second, bl); } } template inline void decode(unordered_map& m, bufferlist::iterator& p) { __u32 n; decode(n, p); m.clear(); while (n--) { T k; decode(k, p); decode(m[k], p); } } // ceph::unordered_set template inline void encode(const ceph::unordered_set& m, bufferlist& bl) { __u32 n = m.size(); encode(n, bl); for (typename ceph::unordered_set::const_iterator p = m.begin(); p != m.end(); ++p) encode(*p, bl); } template inline void decode(ceph::unordered_set& m, bufferlist::iterator& p) { __u32 n; decode(n, p); m.clear(); while (n--) { T k; decode(k, p); m.insert(k); } } // deque template inline void encode(const std::deque& ls, bufferlist& bl) { __u32 n = ls.size(); encode(n, bl); for (typename std::deque::const_iterator p = ls.begin(); p != ls.end(); ++p) encode(*p, bl); } template inline void decode(std::deque& ls, bufferlist::iterator& p) { __u32 n; decode(n, p); ls.clear(); while (n--) { T v; decode(v, p); ls.push_back(v); } } /* * guards */ /** * start encoding block * * @param v current (code) version of the encoding * @param compat oldest code version that can decode it * @param bl bufferlist to encode to */ #define ENCODE_START(v, compat, bl) \ __u8 struct_v = v, struct_compat = compat; \ ::encode(struct_v, bl); \ ::encode(struct_compat, bl); \ buffer::list::iterator struct_compat_it = bl.end(); \ struct_compat_it.advance(-1); \ ceph_le32 struct_len; \ struct_len = 0; \ ::encode(struct_len, bl); \ buffer::list::iterator struct_len_it = bl.end(); \ struct_len_it.advance(-4); \ do { /** * finish encoding block * * @param bl bufferlist we were encoding to * @param new_struct_compat struct-compat value to use */ #define ENCODE_FINISH_NEW_COMPAT(bl, new_struct_compat) \ } while (false); \ struct_len = bl.length() - struct_len_it.get_off() - sizeof(struct_len); \ struct_len_it.copy_in(4, (char *)&struct_len); \ if (new_struct_compat) { \ struct_compat = new_struct_compat; \ struct_compat_it.copy_in(1, (char *)&struct_compat); \ } #define ENCODE_FINISH(bl) ENCODE_FINISH_NEW_COMPAT(bl, 0) #define DECODE_ERR_VERSION(func, v) \ "" #func " unknown encoding version > " #v #define DECODE_ERR_OLDVERSION(func, v) \ "" #func " no longer understand old encoding version < " #v #define DECODE_ERR_PAST(func) \ "" #func " decode past end of struct encoding" /** * check for very old encoding * * If the encoded data is older than oldestv, raise an exception. * * @param oldestv oldest version of the code we can successfully decode. */ #define DECODE_OLDEST(oldestv) \ if (struct_v < oldestv) \ throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v)); /** * start a decoding block * * @param v current version of the encoding that the code supports/encodes * @param bl bufferlist::iterator for the encoded data */ #define DECODE_START(v, bl) \ __u8 struct_v, struct_compat; \ ::decode(struct_v, bl); \ ::decode(struct_compat, bl); \ if (v < struct_compat) \ throw buffer::malformed_input(DECODE_ERR_VERSION(__PRETTY_FUNCTION__, v)); \ __u32 struct_len; \ ::decode(struct_len, bl); \ if (struct_len > bl.get_remaining()) \ throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ unsigned struct_end = bl.get_off() + struct_len; \ do { #define __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, skip_v, bl) \ __u8 struct_v; \ ::decode(struct_v, bl); \ if (struct_v >= compatv) { \ __u8 struct_compat; \ ::decode(struct_compat, bl); \ if (v < struct_compat) \ throw buffer::malformed_input(DECODE_ERR_VERSION(__PRETTY_FUNCTION__, v)); \ } else if (skip_v) { \ if ((int)bl.get_remaining() < skip_v) \ throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ bl.advance(skip_v); \ } \ unsigned struct_end = 0; \ if (struct_v >= lenv) { \ __u32 struct_len; \ ::decode(struct_len, bl); \ if (struct_len > bl.get_remaining()) \ throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ struct_end = bl.get_off() + struct_len; \ } \ do { /** * start a decoding block with legacy support for older encoding schemes * * The old encoding schemes has a __u8 struct_v only, or lacked either * the compat version or length. Skip those fields conditionally. * * Most of the time, v, compatv, and lenv will all match the version * where the structure was switched over to the new macros. * * @param v current version of the encoding that the code supports/encodes * @param compatv oldest version that includes a __u8 compat version field * @param lenv oldest version that includes a __u32 length wrapper * @param bl bufferlist::iterator containing the encoded data */ #define DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, bl) \ __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 0, bl) /** * start a decoding block with legacy support for older encoding schemes * * This version of the macro assumes the legacy encoding had a 32 bit * version * * The old encoding schemes has a __u8 struct_v only, or lacked either * the compat version or length. Skip those fields conditionally. * * Most of the time, v, compatv, and lenv will all match the version * where the structure was switched over to the new macros. * * @param v current version of the encoding that the code supports/encodes * @param compatv oldest version that includes a __u8 compat version field * @param lenv oldest version that includes a __u32 length wrapper * @param bl bufferlist::iterator containing the encoded data */ #define DECODE_START_LEGACY_COMPAT_LEN_32(v, compatv, lenv, bl) \ __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3, bl) #define DECODE_START_LEGACY_COMPAT_LEN_16(v, compatv, lenv, bl) \ __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1, bl) /** * finish decode block * * @param bl bufferlist::iterator we were decoding from */ #define DECODE_FINISH(bl) \ } while (false); \ if (struct_end) { \ if (bl.get_off() > struct_end) \ throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ if (bl.get_off() < struct_end) \ bl.advance(struct_end - bl.get_off()); \ } #endif ceph-0.80.11/src/include/memory.h0000664000175100017510000000056412623076744020575 0ustar jenkins-buildjenkins-build#ifndef CEPH_MEMORY_H #define CEPH_MEMORY_H #include #ifdef _LIBCPP_VERSION #include namespace ceph { using std::shared_ptr; using std::weak_ptr; using std::static_pointer_cast; } #else #include namespace ceph { using std::tr1::shared_ptr; using std::tr1::weak_ptr; using std::tr1::static_pointer_cast; } #endif #endif ceph-0.80.11/src/include/hash.h0000664000175100017510000000261612623076744020210 0ustar jenkins-buildjenkins-build#ifndef CEPH_HASH_H #define CEPH_HASH_H #include "acconfig.h" // Robert Jenkins' function for mixing 32-bit values // http://burtleburtle.net/bob/hash/evahash.html // a, b = random bits, c = input and output #define hashmix(a,b,c) \ a=a-b; a=a-c; a=a^(c>>13); \ b=b-c; b=b-a; b=b^(a<<8); \ c=c-a; c=c-b; c=c^(b>>13); \ a=a-b; a=a-c; a=a^(c>>12); \ b=b-c; b=b-a; b=b^(a<<16); \ c=c-a; c=c-b; c=c^(b>>5); \ a=a-b; a=a-c; a=a^(c>>3); \ b=b-c; b=b-a; b=b^(a<<10); \ c=c-a; c=c-b; c=c^(b>>15); //namespace ceph { template struct rjhash { }; inline uint64_t rjhash64(uint64_t key) { key = (~key) + (key << 21); // key = (key << 21) - key - 1; key = key ^ (key >> 24); key = (key + (key << 3)) + (key << 8); // key * 265 key = key ^ (key >> 14); key = (key + (key << 2)) + (key << 4); // key * 21 key = key ^ (key >> 28); key = key + (key << 31); return key; } inline uint32_t rjhash32(uint32_t a) { a = (a+0x7ed55d16) + (a<<12); a = (a^0xc761c23c) ^ (a>>19); a = (a+0x165667b1) + (a<<5); a = (a+0xd3a2646c) ^ (a<<9); a = (a+0xfd7046c5) + (a<<3); a = (a^0xb55a4f09) ^ (a>>16); return a; } template<> struct rjhash { inline size_t operator()(const uint32_t x) const { return rjhash32(x); } }; template<> struct rjhash { inline size_t operator()(const uint64_t x) const { return rjhash64(x); } }; //} #endif ceph-0.80.11/src/include/lru.h0000664000175100017510000001542612623076744020072 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LRU_H #define CEPH_LRU_H #include #include "common/config.h" class LRUObject { private: LRUObject *lru_next, *lru_prev; bool lru_pinned; class LRU *lru; class LRUList *lru_list; public: LRUObject() { lru_next = lru_prev = NULL; lru_list = 0; lru_pinned = false; lru = 0; } // pin/unpin item in cache void lru_pin(); void lru_unpin(); bool lru_is_expireable() { return !lru_pinned; } friend class LRU; friend class LRUList; }; class LRUList { private: LRUObject *head, *tail; uint32_t len; public: LRUList() { head = tail = 0; len = 0; } uint32_t get_length() { return len; } LRUObject *get_head() { return head; } LRUObject *get_tail() { return tail; } void clear() { while (len > 0) { remove(get_head()); } } void insert_head(LRUObject *o) { o->lru_next = head; o->lru_prev = NULL; if (head) { head->lru_prev = o; } else { tail = o; } head = o; o->lru_list = this; len++; } void insert_tail(LRUObject *o) { o->lru_next = NULL; o->lru_prev = tail; if (tail) { tail->lru_next = o; } else { head = o; } tail = o; o->lru_list = this; len++; } void remove(LRUObject *o) { assert(o->lru_list == this); if (o->lru_next) o->lru_next->lru_prev = o->lru_prev; else tail = o->lru_prev; if (o->lru_prev) o->lru_prev->lru_next = o->lru_next; else head = o->lru_next; o->lru_next = o->lru_prev = NULL; o->lru_list = 0; assert(len>0); len--; } }; class LRU { protected: LRUList lru_top, lru_bot, lru_pintail; uint32_t lru_num, lru_num_pinned; uint32_t lru_max; // max items double lru_midpoint; friend class LRUObject; //friend class MDCache; // hack public: LRU(int max = 0) { lru_num = 0; lru_num_pinned = 0; lru_midpoint = .6; lru_max = max; } uint32_t lru_get_size() { return lru_num; } uint32_t lru_get_top() { return lru_top.get_length(); } uint32_t lru_get_bot() { return lru_bot.get_length(); } uint32_t lru_get_pintail() { return lru_pintail.get_length(); } uint32_t lru_get_max() { return lru_max; } uint32_t lru_get_num_pinned() { return lru_num_pinned; } void lru_set_max(uint32_t m) { lru_max = m; } void lru_set_midpoint(float f) { lru_midpoint = f; } void lru_clear() { lru_top.clear(); lru_bot.clear(); lru_pintail.clear(); } // insert at top of lru void lru_insert_top(LRUObject *o) { //assert(!o->lru_in_lru); //o->lru_in_lru = true; assert(!o->lru); o->lru = this; lru_top.insert_head( o ); lru_num++; if (o->lru_pinned) lru_num_pinned++; lru_adjust(); } // insert at mid point in lru void lru_insert_mid(LRUObject *o) { //assert(!o->lru_in_lru); //o->lru_in_lru = true; assert(!o->lru); o->lru = this; lru_bot.insert_head(o); lru_num++; if (o->lru_pinned) lru_num_pinned++; } // insert at bottom of lru void lru_insert_bot(LRUObject *o) { assert(!o->lru); o->lru = this; lru_bot.insert_tail(o); lru_num++; if (o->lru_pinned) lru_num_pinned++; } /* // insert at bottom of lru void lru_insert_pintail(LRUObject *o) { assert(!o->lru); o->lru = this; assert(o->lru_pinned); lru_pintail.insert_head(o); lru_num++; lru_num_pinned += o->lru_pinned; } */ // adjust top/bot balance, as necessary void lru_adjust() { if (!lru_max) return; unsigned toplen = lru_top.get_length(); unsigned topwant = (unsigned)(lru_midpoint * ((double)lru_max - lru_num_pinned)); while (toplen > 0 && toplen > topwant) { // remove from tail of top, stick at head of bot // FIXME: this could be way more efficient by moving a whole chain of items. LRUObject *o = lru_top.get_tail(); lru_top.remove(o); lru_bot.insert_head(o); toplen--; } } // remove an item LRUObject *lru_remove(LRUObject *o) { // not in list //assert(o->lru_in_lru); //if (!o->lru_in_lru) return o; // might have expired and been removed that way. if (!o->lru) return o; assert((o->lru_list == &lru_pintail) || (o->lru_list == &lru_top) || (o->lru_list == &lru_bot)); o->lru_list->remove(o); lru_num--; if (o->lru_pinned) lru_num_pinned--; o->lru = 0; return o; } // touch item -- move to head of lru bool lru_touch(LRUObject *o) { lru_remove(o); lru_insert_top(o); return true; } // touch item -- move to midpoint (unless already higher) bool lru_midtouch(LRUObject *o) { if (o->lru_list == &lru_top) return false; lru_remove(o); lru_insert_mid(o); return true; } // touch item -- move to bottom bool lru_bottouch(LRUObject *o) { lru_remove(o); lru_insert_bot(o); return true; } void lru_touch_entire_pintail() { // promote entire pintail to the top lru while (lru_pintail.get_length() > 0) { LRUObject *o = lru_pintail.get_head(); lru_pintail.remove(o); lru_top.insert_tail(o); } } // expire -- expire a single item LRUObject *lru_get_next_expire() { LRUObject *p; // look through tail of bot while (lru_bot.get_length()) { p = lru_bot.get_tail(); if (!p->lru_pinned) return p; // move to pintail lru_bot.remove(p); lru_pintail.insert_head(p); } // ok, try head then while (lru_top.get_length()) { p = lru_top.get_tail(); if (!p->lru_pinned) return p; // move to pintail lru_top.remove(p); lru_pintail.insert_head(p); } // no luck! return NULL; } LRUObject *lru_expire() { LRUObject *p = lru_get_next_expire(); if (p) return lru_remove(p); return NULL; } void lru_status() { //generic_dout(10) << "lru: " << lru_num << " items, " << lru_top.get_length() << " top, " << lru_bot.get_length() << " bot, " << lru_pintail.get_length() << " pintail" << dendl; } }; inline void LRUObject::lru_pin() { lru_pinned = true; if (lru) lru->lru_num_pinned++; } inline void LRUObject::lru_unpin() { lru_pinned = false; if (lru) { lru->lru_num_pinned--; // move from pintail -> bot if (lru_list == &lru->lru_pintail) { lru->lru_pintail.remove(this); lru->lru_bot.insert_tail(this); } } } #endif ceph-0.80.11/src/include/ceph_hash.h0000664000175100017510000000066112623076744021205 0ustar jenkins-buildjenkins-build#ifndef FS_CEPH_HASH_H #define FS_CEPH_HASH_H #define CEPH_STR_HASH_LINUX 0x1 /* linux dcache hash */ #define CEPH_STR_HASH_RJENKINS 0x2 /* robert jenkins' */ extern unsigned ceph_str_hash_linux(const char *s, unsigned len); extern unsigned ceph_str_hash_rjenkins(const char *s, unsigned len); extern unsigned ceph_str_hash(int type, const char *s, unsigned len); extern const char *ceph_str_hash_name(int type); #endif ceph-0.80.11/src/include/util.h0000664000175100017510000000224612623076744020241 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank Storage, Inc. * Copyright (C) 2014 Red Hat * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CEPH_UTIL_H #define CEPH_UTIL_H // is buf~len completely zero (in 8-byte chunks) #include "common/Formatter.h" #include "include/types.h" bool buf_is_zero(const char *buf, size_t len); int64_t unit_to_bytesize(string val, ostream *pss); struct ceph_data_stats { uint64_t byte_total; uint64_t byte_used; uint64_t byte_avail; int avail_percent; void dump(Formatter *f) const { assert(f != NULL); f->dump_int("total", byte_total); f->dump_int("used", byte_used); f->dump_int("avail", byte_avail); f->dump_int("avail_percent", avail_percent); } }; typedef struct ceph_data_stats ceph_data_stats_t; int get_fs_stats(ceph_data_stats_t &stats, const char *path); #endif /* CEPH_UTIL_H */ ceph-0.80.11/src/include/statlite.h0000664000175100017510000000524112623076744021113 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_STATLITE_H #define CEPH_STATLITE_H extern "C" { #include #include #include #include #include struct statlite { dev_t st_dev; /* device */ ino_t st_ino; /* inode */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device type (if inode device)*/ unsigned long st_litemask; /* bit mask for optional fields */ /***************************************************************/ /**** Remaining fields are optional according to st_litemask ***/ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of blocks allocated */ struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ //time_t st_atime; /* time of last access */ //time_t st_mtime; /* time of last modification */ //time_t st_ctime; /* time of last change */ }; #define S_STATLITE_SIZE 1 #define S_STATLITE_BLKSIZE 2 #define S_STATLITE_BLOCKS 4 #define S_STATLITE_ATIME 8 #define S_STATLITE_MTIME 16 #define S_STATLITE_CTIME 32 #define S_REQUIRESIZE(m) (m | S_STATLITE_SIZE) #define S_REQUIREBLKSIZE(m) (m | S_STATLITE_BLKSIZE) #define S_REQUIREBLOCKS(m) (m | S_STATLITE_BLOCKS) #define S_REQUIREATIME(m) (m | S_STATLITE_ATIME) #define S_REQUIREMTIME(m) (m | S_STATLITE_MTIME) #define S_REQUIRECTIME(m) (m | S_STATLITE_CTIME) #define S_ISVALIDSIZE(m) (m & S_STATLITE_SIZE) #define S_ISVALIDBLKSIZE(m) (m & S_STATLITE_BLKSIZE) #define S_ISVALIDBLOCKS(m) (m & S_STATLITE_BLOCKS) #define S_ISVALIDATIME(m) (m & S_STATLITE_ATIME) #define S_ISVALIDMTIME(m) (m & S_STATLITE_MTIME) #define S_ISVALIDCTIME(m) (m & S_STATLITE_CTIME) // readdirplus etc. struct dirent_plus { struct dirent d_dirent; /* dirent struct for this entry */ struct stat d_stat; /* attributes for this entry */ int d_stat_err;/* errno for d_stat, or 0 */ }; struct dirent_lite { struct dirent d_dirent; /* dirent struct for this entry */ struct statlite d_stat; /* attributes for this entry */ int d_stat_err;/* errno for d_stat, or 0 */ }; } #endif ceph-0.80.11/src/include/atomic.h0000664000175100017510000000606612623076744020544 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * @author Sage Weil */ #ifndef CEPH_ATOMIC_H #define CEPH_ATOMIC_H #ifdef __CEPH__ # include "acconfig.h" #endif #include #include "include/Spinlock.h" namespace ceph { template class atomic_spinlock_t { mutable ceph_spinlock_t lock; T val; public: atomic_spinlock_t(T i=0) : val(i) { ceph_spin_init(&lock); } ~atomic_spinlock_t() { ceph_spin_destroy(&lock); } void set(T v) { ceph_spin_lock(&lock); val = v; ceph_spin_unlock(&lock); } T inc() { ceph_spin_lock(&lock); T r = ++val; ceph_spin_unlock(&lock); return r; } T dec() { ceph_spin_lock(&lock); T r = --val; ceph_spin_unlock(&lock); return r; } void add(T d) { ceph_spin_lock(&lock); val += d; ceph_spin_unlock(&lock); } void sub(T d) { ceph_spin_lock(&lock); val -= d; ceph_spin_unlock(&lock); } T read() const { T ret; ceph_spin_lock(&lock); ret = val; ceph_spin_unlock(&lock); return ret; } private: // forbid copying atomic_spinlock_t(const atomic_spinlock_t &other); atomic_spinlock_t &operator=(const atomic_spinlock_t &rhs); }; } #ifndef NO_ATOMIC_OPS // libatomic_ops implementation #define AO_REQUIRE_CAS #include // reinclude our assert to clobber the system one #include "include/assert.h" namespace ceph { class atomic_t { AO_t val; public: atomic_t(AO_t i=0) : val(i) {} void set(AO_t v) { AO_store(&val, v); } AO_t inc() { return AO_fetch_and_add1(&val) + 1; } AO_t dec() { return AO_fetch_and_sub1_write(&val) - 1; } void add(AO_t add_me) { AO_fetch_and_add(&val, add_me); } void sub(AO_t sub_me) { AO_t negsub = 0 - sub_me; AO_fetch_and_add_write(&val, (AO_t)negsub); } AO_t read() const { // cast away const on the pointer. this is only needed to build // on lenny, but not newer debians, so the atomic_ops.h got fixed // at some point. this hack can go away someday... return AO_load_full((AO_t *)&val); } private: // forbid copying atomic_t(const atomic_t &other); atomic_t &operator=(const atomic_t &rhs); }; #if SIZEOF_AO_T == 8 typedef atomic_t atomic64_t; #else typedef atomic_spinlock_t atomic64_t; #endif } #else /* * crappy slow implementation that uses a pthreads spinlock. */ #include "include/Spinlock.h" namespace ceph { typedef atomic_spinlock_t atomic_t; typedef atomic_spinlock_t atomic64_t; } #endif #endif ceph-0.80.11/src/include/utime.h0000664000175100017510000002275712623076744020420 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_UTIME_H #define CEPH_UTIME_H #include #include #include #include #include "include/types.h" #include "common/strtol.h" // -------- // utime_t class utime_t { public: struct { __u32 tv_sec, tv_nsec; } tv; friend class Clock; public: bool is_zero() const { return (tv.tv_sec == 0) && (tv.tv_nsec == 0); } void normalize() { if (tv.tv_nsec > 1000000000ul) { tv.tv_sec += tv.tv_nsec / (1000000000ul); tv.tv_nsec %= 1000000000ul; } } // cons utime_t() { tv.tv_sec = 0; tv.tv_nsec = 0; } utime_t(time_t s, int n) { tv.tv_sec = s; tv.tv_nsec = n; normalize(); } utime_t(const struct ceph_timespec &v) { decode_timeval(&v); } utime_t(const struct timeval &v) { set_from_timeval(&v); } utime_t(const struct timeval *v) { set_from_timeval(v); } void to_timespec(struct timespec *ts) const { ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_nsec; } void set_from_double(double d) { tv.tv_sec = (__u32)trunc(d); tv.tv_nsec = (__u32)((d - (double)tv.tv_sec) * (double)1000000000.0); } // accessors time_t sec() const { return tv.tv_sec; } long usec() const { return tv.tv_nsec/1000; } int nsec() const { return tv.tv_nsec; } // ref accessors/modifiers __u32& sec_ref() { return tv.tv_sec; } __u32& nsec_ref() { return tv.tv_nsec; } uint64_t to_nsec() const { return (uint64_t)tv.tv_nsec + (uint64_t)tv.tv_sec * 1000000000ull; } void copy_to_timeval(struct timeval *v) const { v->tv_sec = tv.tv_sec; v->tv_usec = tv.tv_nsec/1000; } void set_from_timeval(const struct timeval *v) { tv.tv_sec = v->tv_sec; tv.tv_nsec = v->tv_usec*1000; } void encode(bufferlist &bl) const { ::encode(tv.tv_sec, bl); ::encode(tv.tv_nsec, bl); } void decode(bufferlist::iterator &p) { ::decode(tv.tv_sec, p); ::decode(tv.tv_nsec, p); } void encode_timeval(struct ceph_timespec *t) const { t->tv_sec = tv.tv_sec; t->tv_nsec = tv.tv_nsec; } void decode_timeval(const struct ceph_timespec *t) { tv.tv_sec = t->tv_sec; tv.tv_nsec = t->tv_nsec; } utime_t round_to_minute() { struct tm bdt; time_t tt = sec(); gmtime_r(&tt, &bdt); bdt.tm_sec = 0; tt = mktime(&bdt); return utime_t(tt, 0); } utime_t round_to_hour() { struct tm bdt; time_t tt = sec(); gmtime_r(&tt, &bdt); bdt.tm_sec = 0; bdt.tm_min = 0; tt = mktime(&bdt); return utime_t(tt, 0); } // cast to double operator double() const { return (double)sec() + ((double)nsec() / 1000000000.0L); } operator ceph_timespec() const { ceph_timespec ts; ts.tv_sec = sec(); ts.tv_nsec = nsec(); return ts; } void sleep() const { struct timespec ts; to_timespec(&ts); nanosleep(&ts, NULL); } // output ostream& gmtime(ostream& out) const { out.setf(std::ios::right); char oldfill = out.fill(); out.fill('0'); if (sec() < ((time_t)(60*60*24*365*10))) { // raw seconds. this looks like a relative time. out << (long)sec() << "." << std::setw(6) << usec(); } else { // localtime. this looks like an absolute time. // aim for http://en.wikipedia.org/wiki/ISO_8601 struct tm bdt; time_t tt = sec(); gmtime_r(&tt, &bdt); out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07' << '-' << std::setw(2) << (bdt.tm_mon+1) << '-' << std::setw(2) << bdt.tm_mday << ' ' << std::setw(2) << bdt.tm_hour << ':' << std::setw(2) << bdt.tm_min << ':' << std::setw(2) << bdt.tm_sec; out << "." << std::setw(6) << usec(); out << "Z"; } out.fill(oldfill); out.unsetf(std::ios::right); return out; } // output ostream& asctime(ostream& out) const { out.setf(std::ios::right); char oldfill = out.fill(); out.fill('0'); if (sec() < ((time_t)(60*60*24*365*10))) { // raw seconds. this looks like a relative time. out << (long)sec() << "." << std::setw(6) << usec(); } else { // localtime. this looks like an absolute time. // aim for http://en.wikipedia.org/wiki/ISO_8601 struct tm bdt; time_t tt = sec(); gmtime_r(&tt, &bdt); char buf[128]; asctime_r(&bdt, buf); int len = strlen(buf); if (buf[len - 1] == '\n') buf[len - 1] = '\0'; out << buf; } out.fill(oldfill); out.unsetf(std::ios::right); return out; } ostream& localtime(ostream& out) const { out.setf(std::ios::right); char oldfill = out.fill(); out.fill('0'); if (sec() < ((time_t)(60*60*24*365*10))) { // raw seconds. this looks like a relative time. out << (long)sec() << "." << std::setw(6) << usec(); } else { // localtime. this looks like an absolute time. // aim for http://en.wikipedia.org/wiki/ISO_8601 struct tm bdt; time_t tt = sec(); localtime_r(&tt, &bdt); out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07' << '-' << std::setw(2) << (bdt.tm_mon+1) << '-' << std::setw(2) << bdt.tm_mday << ' ' << std::setw(2) << bdt.tm_hour << ':' << std::setw(2) << bdt.tm_min << ':' << std::setw(2) << bdt.tm_sec; out << "." << std::setw(6) << usec(); //out << '_' << bdt.tm_zone; } out.fill(oldfill); out.unsetf(std::ios::right); return out; } int sprintf(char *out, int outlen) const { struct tm bdt; time_t tt = sec(); localtime_r(&tt, &bdt); return snprintf(out, outlen, "%04d-%02d-%02d %02d:%02d:%02d.%06ld", bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday, bdt.tm_hour, bdt.tm_min, bdt.tm_sec, usec()); } static int parse_date(const string& date, uint64_t *epoch, uint64_t *nsec, string *out_date=NULL, string *out_time=NULL) { struct tm tm; memset(&tm, 0, sizeof(tm)); if (nsec) *nsec = 0; const char *p = strptime(date.c_str(), "%Y-%m-%d", &tm); if (p) { if (*p == ' ') { p++; p = strptime(p, " %H:%M:%S", &tm); if (!p) return -EINVAL; if (nsec && *p == '.') { ++p; unsigned i; char buf[10]; /* 9 digit + null termination */ for (i = 0; (i < sizeof(buf) - 1) && isdigit(*p); ++i, ++p) { buf[i] = *p; } for (; i < sizeof(buf) - 1; ++i) { buf[i] = '0'; } buf[i] = '\0'; string err; *nsec = (uint64_t)strict_strtol(buf, 10, &err); if (!err.empty()) { return -EINVAL; } } } } else { return -EINVAL; } time_t t = timegm(&tm); if (epoch) *epoch = (uint64_t)t; if (out_date) { char buf[32]; strftime(buf, sizeof(buf), "%F", &tm); *out_date = buf; } if (out_time) { char buf[32]; strftime(buf, sizeof(buf), "%T", &tm); *out_time = buf; } return 0; } }; WRITE_CLASS_ENCODER(utime_t) // arithmetic operators inline utime_t operator+(const utime_t& l, const utime_t& r) { return utime_t( l.sec() + r.sec() + (l.nsec()+r.nsec())/1000000000L, (l.nsec()+r.nsec())%1000000000L ); } inline utime_t& operator+=(utime_t& l, const utime_t& r) { l.sec_ref() += r.sec() + (l.nsec()+r.nsec())/1000000000L; l.nsec_ref() += r.nsec(); l.nsec_ref() %= 1000000000L; return l; } inline utime_t& operator+=(utime_t& l, double f) { double fs = trunc(f); double ns = (f - fs) * (double)1000000000.0; l.sec_ref() += (long)fs; l.nsec_ref() += (long)ns; l.normalize(); return l; } inline utime_t operator-(const utime_t& l, const utime_t& r) { return utime_t( l.sec() - r.sec() - (l.nsec()= r.nsec()) l.nsec_ref() -= r.nsec(); else { l.nsec_ref() += 1000000000L - r.nsec(); l.sec_ref()--; } return l; } inline utime_t& operator-=(utime_t& l, double f) { double fs = trunc(f); double ns = (f - fs) * (double)1000000000.0; l.sec_ref() -= (long)fs; long nsl = (long)ns; if (nsl) { l.sec_ref()--; l.nsec_ref() = 1000000000L + l.nsec_ref() - nsl; } l.normalize(); return l; } // comparators inline bool operator>(const utime_t& a, const utime_t& b) { return (a.sec() > b.sec()) || (a.sec() == b.sec() && a.nsec() > b.nsec()); } inline bool operator<=(const utime_t& a, const utime_t& b) { return !(operator>(a, b)); } inline bool operator<(const utime_t& a, const utime_t& b) { return (a.sec() < b.sec()) || (a.sec() == b.sec() && a.nsec() < b.nsec()); } inline bool operator>=(const utime_t& a, const utime_t& b) { return !(operator<(a, b)); } inline bool operator==(const utime_t& a, const utime_t& b) { return a.sec() == b.sec() && a.nsec() == b.nsec(); } inline bool operator!=(const utime_t& a, const utime_t& b) { return a.sec() != b.sec() || a.nsec() != b.nsec(); } // output // ostream inline std::ostream& operator<<(std::ostream& out, const utime_t& t) { return t.localtime(out); } #endif ceph-0.80.11/src/include/rbd/0000775000175100017510000000000012623077034017647 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/include/rbd/features.h0000664000175100017510000000046412623076744021651 0ustar jenkins-buildjenkins-build#ifndef CEPH_RBD_FEATURES_H #define CEPH_RBD_FEATURES_H #define RBD_FEATURE_LAYERING (1<<0) #define RBD_FEATURE_STRIPINGV2 (1<<1) #define RBD_FEATURES_INCOMPATIBLE (RBD_FEATURE_LAYERING|RBD_FEATURE_STRIPINGV2) #define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING|RBD_FEATURE_STRIPINGV2) #endif ceph-0.80.11/src/include/rbd/librbd.h0000664000175100017510000003627512623076744021302 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRBD_H #define CEPH_LIBRBD_H #ifdef __cplusplus extern "C" { #endif #include #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif #include #include "../rados/librados.h" #include "features.h" #define LIBRBD_VER_MAJOR 0 #define LIBRBD_VER_MINOR 1 #define LIBRBD_VER_EXTRA 8 #define LIBRBD_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra) #define LIBRBD_VERSION_CODE LIBRBD_VERSION(LIBRBD_VER_MAJOR, LIBRBD_VER_MINOR, LIBRBD_VER_EXTRA) #define LIBRBD_SUPPORTS_WATCH 0 #define LIBRBD_SUPPORTS_AIO_FLUSH 1 #define LIBRBD_SUPPORTS_INVALIDATE 1 typedef void *rbd_snap_t; typedef void *rbd_image_t; typedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void *ptr); typedef struct { uint64_t id; uint64_t size; const char *name; } rbd_snap_info_t; #define RBD_MAX_IMAGE_NAME_SIZE 96 #define RBD_MAX_BLOCK_NAME_SIZE 24 typedef struct { uint64_t size; uint64_t obj_size; uint64_t num_objs; int order; char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]; int64_t parent_pool; /* deprecated */ char parent_name[RBD_MAX_IMAGE_NAME_SIZE]; /* deprecated */ } rbd_image_info_t; void rbd_version(int *major, int *minor, int *extra); /* images */ int rbd_list(rados_ioctx_t io, char *names, size_t *size); int rbd_create(rados_ioctx_t io, const char *name, uint64_t size, int *order); int rbd_create2(rados_ioctx_t io, const char *name, uint64_t size, uint64_t features, int *order); /** * create new rbd image * * The stripe_unit must be a factor of the object size (1 << order). * The stripe_count can be one (no intra-object striping) or greater * than one. The RBD_FEATURE_STRIPINGV2 must be specified if the * stripe_unit != the object size and the stripe_count is != 1. * * @param io ioctx * @param name image name * @param size image size in bytes * @param features initial feature bits * @param order object/block size, as a power of two (object size == 1 << order) * @param stripe_unit stripe unit size, in bytes. * @param stripe_count number of objects to stripe over before looping * @return 0 on success, or negative error code */ int rbd_create3(rados_ioctx_t io, const char *name, uint64_t size, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count); int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name, const char *p_snapname, rados_ioctx_t c_ioctx, const char *c_name, uint64_t features, int *c_order); int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name, const char *p_snapname, rados_ioctx_t c_ioctx, const char *c_name, uint64_t features, int *c_order, uint64_t stripe_unit, int stripe_count); int rbd_remove(rados_ioctx_t io, const char *name); int rbd_remove_with_progress(rados_ioctx_t io, const char *name, librbd_progress_fn_t cb, void *cbdata); int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname, const char *destname); int rbd_open(rados_ioctx_t io, const char *name, rbd_image_t *image, const char *snap_name); /** * Open an image in read-only mode. * * This is intended for use by clients that cannot write to a block * device due to cephx restrictions. There will be no watch * established on the header object, since a watch is a write. This * means the metadata reported about this image (parents, snapshots, * size, etc.) may become stale. This should not be used for * long-running operations, unless you can be sure that one of these * properties changing is safe. * * Attempting to write to a read-only image will return -EROFS. * * @param io ioctx to determine the pool the image is in * @param name image name * @param image where to store newly opened image handle * @param snap_name name of snapshot to open at, or NULL for no snapshot * @returns 0 on success, negative error code on failure */ int rbd_open_read_only(rados_ioctx_t io, const char *name, rbd_image_t *image, const char *snap_name); int rbd_close(rbd_image_t image); int rbd_resize(rbd_image_t image, uint64_t size); int rbd_resize_with_progress(rbd_image_t image, uint64_t size, librbd_progress_fn_t cb, void *cbdata); int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize); int rbd_get_old_format(rbd_image_t image, uint8_t *old); int rbd_get_size(rbd_image_t image, uint64_t *size); int rbd_get_features(rbd_image_t image, uint64_t *features); int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit); int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count); int rbd_get_overlap(rbd_image_t image, uint64_t *overlap); int rbd_get_parent_info(rbd_image_t image, char *parent_poolname, size_t ppoolnamelen, char *parent_name, size_t pnamelen, char *parent_snapname, size_t psnapnamelen); int rbd_copy(rbd_image_t image, rados_ioctx_t dest_io_ctx, const char *destname); int rbd_copy2(rbd_image_t src, rbd_image_t dest); int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p, const char *destname, librbd_progress_fn_t cb, void *cbdata); int rbd_copy_with_progress2(rbd_image_t src, rbd_image_t dest, librbd_progress_fn_t cb, void *cbdata); /* snapshots */ int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps, int *max_snaps); void rbd_snap_list_end(rbd_snap_info_t *snaps); int rbd_snap_create(rbd_image_t image, const char *snapname); int rbd_snap_remove(rbd_image_t image, const char *snapname); int rbd_snap_rollback(rbd_image_t image, const char *snapname); int rbd_snap_rollback_with_progress(rbd_image_t image, const char *snapname, librbd_progress_fn_t cb, void *cbdata); /** * Prevent a snapshot from being deleted until it is unprotected. * * @param snap_name which snapshot to protect * @returns 0 on success, negative error code on failure * @returns -EBUSY if snap is already protected */ int rbd_snap_protect(rbd_image_t image, const char *snap_name); /** * Allow a snaphshot to be deleted. * * @param snap_name which snapshot to unprotect * @returns 0 on success, negative error code on failure * @returns -EINVAL if snap is not protected */ int rbd_snap_unprotect(rbd_image_t image, const char *snap_name); /** * Determine whether a snapshot is protected. * * @param snap_name which snapshot query * @param is_protected where to store the result (0 or 1) * @returns 0 on success, negative error code on failure */ int rbd_snap_is_protected(rbd_image_t image, const char *snap_name, int *is_protected); int rbd_snap_set(rbd_image_t image, const char *snapname); int rbd_flatten(rbd_image_t image); /** * List all images that are cloned from the image at the * snapshot that is set via rbd_snap_set(). * * This iterates over all pools, so it should be run by a user with * read access to all of them. pools_len and images_len are filled in * with the number of bytes put into the pools and images buffers. * * If the provided buffers are too short, the required lengths are * still filled in, but the data is not and -ERANGE is returned. * Otherwise, the buffers are filled with the pool and image names * of the children, with a '\0' after each. * * @param image which image (and implicitly snapshot) to list clones of * @param pools buffer in which to store pool names * @param pools_len number of bytes in pools buffer * @param images buffer in which to store image names * @param images_len number of bytes in images buffer * @returns number of children on success, negative error code on failure * @returns -ERANGE if either buffer is too short */ ssize_t rbd_list_children(rbd_image_t image, char *pools, size_t *pools_len, char *images, size_t *images_len); /** * @defgroup librbd_h_locking Advisory Locking * * An rbd image may be locking exclusively, or shared, to facilitate * e.g. live migration where the image may be open in two places at once. * These locks are intended to guard against more than one client * writing to an image without coordination. They don't need to * be used for snapshots, since snapshots are read-only. * * Currently locks only guard against locks being acquired. * They do not prevent anything else. * * A locker is identified by the internal rados client id of the * holder and a user-defined cookie. This (client id, cookie) pair * must be unique for each locker. * * A shared lock also has a user-defined tag associated with it. Each * additional shared lock must specify the same tag or lock * acquisition will fail. This can be used by e.g. groups of hosts * using a clustered filesystem on top of an rbd image to make sure * they're accessing the correct image. * * @{ */ /** * List clients that have locked the image and information about the lock. * * The number of bytes required in each buffer is put in the * corresponding size out parameter. If any of the provided buffers * are too short, -ERANGE is returned after these sizes are filled in. * * @param exclusive where to store whether the lock is exclusive (1) or shared (0) * @param tag where to store the tag associated with the image * @param tag_len number of bytes in tag buffer * @param clients buffer in which locker clients are stored, separated by '\0' * @param clients_len number of bytes in the clients buffer * @param cookies buffer in which locker cookies are stored, separated by '\0' * @param cookies_len number of bytes in the cookies buffer * @param addrs buffer in which locker addresses are stored, separated by '\0' * @param addrs_len number of bytes in the clients buffer * @returns number of lockers on success, negative error code on failure * @returns -ERANGE if any of the buffers are too short */ ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive, char *tag, size_t *tag_len, char *clients, size_t *clients_len, char *cookies, size_t *cookies_len, char *addrs, size_t *addrs_len); /** * Take an exclusive lock on the image. * * @param image the image to lock * @param cookie user-defined identifier for this instance of the lock * @returns 0 on success, negative error code on failure * @returns -EBUSY if the lock is already held by another (client, cookie) pair * @returns -EEXIST if the lock is already held by the same (client, cookie) pair */ int rbd_lock_exclusive(rbd_image_t image, const char *cookie); /** * Take a shared lock on the image. * * Other clients may also take a shared lock, as lock as they use the * same tag. * * @param image the image to lock * @param cookie user-defined identifier for this instance of the lock * @param tag user-defined identifier for this shared use of the lock * @returns 0 on success, negative error code on failure * @returns -EBUSY if the lock is already held by another (client, cookie) pair * @returns -EEXIST if the lock is already held by the same (client, cookie) pair */ int rbd_lock_shared(rbd_image_t image, const char *cookie, const char *tag); /** * Release a shared or exclusive lock on the image. * * @param image the image to unlock * @param cookie user-defined identifier for the instance of the lock * @returns 0 on success, negative error code on failure * @returns -ENOENT if the lock is not held by the specified (client, cookie) pair */ int rbd_unlock(rbd_image_t image, const char *cookie); /** * Release a shared or exclusive lock that was taken by the specified client. * * @param image the image to unlock * @param client the entity holding the lock (as given by rbd_list_lockers()) * @param cookie user-defined identifier for the instance of the lock to break * @returns 0 on success, negative error code on failure * @returns -ENOENT if the lock is not held by the specified (client, cookie) pair */ int rbd_break_lock(rbd_image_t image, const char *client, const char *cookie); /** @} locking */ /* I/O */ typedef void *rbd_completion_t; typedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg); ssize_t rbd_read(rbd_image_t image, uint64_t ofs, size_t len, char *buf); /* DEPRECATED; use rbd_read_iterate2 */ int64_t rbd_read_iterate(rbd_image_t image, uint64_t ofs, size_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg); /** * iterate read over an image * * Reads each region of the image and calls the callback. If the * buffer pointer passed to the callback is NULL, the given extent is * defined to be zeros (a hole). Normally the granularity for the * callback is the image stripe size. * * @param image image to read * @param ofs offset to start from * @param len bytes of source image to cover * @param cb callback for each region * @returns 0 success, error otherwise */ int rbd_read_iterate2(rbd_image_t image, uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg); /** * get difference between two versions of an image * * This will return the differences between two versions of an image * via a callback, which gets the offset and length and a flag * indicating whether the extent exists (1), or is known/defined to * be zeros (a hole, 0). If the source snapshot name is NULL, we * interpret that as the beginning of time and return all allocated * regions of the image. The end version is whatever is currently * selected for the image handle (either a snapshot or the writeable * head). * * @param fromsnapname start snapshot name, or NULL * @param ofs start offset * @param len len in bytes of region to report on * @param cb callback to call for each allocated region * @param arg argument to pass to the callback * @returns 0 on success, or negative error code on error */ int rbd_diff_iterate(rbd_image_t image, const char *fromsnapname, uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, int, void *), void *arg); ssize_t rbd_write(rbd_image_t image, uint64_t ofs, size_t len, const char *buf); int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len); int rbd_aio_write(rbd_image_t image, uint64_t off, size_t len, const char *buf, rbd_completion_t c); int rbd_aio_read(rbd_image_t image, uint64_t off, size_t len, char *buf, rbd_completion_t c); int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len, rbd_completion_t c); int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb, rbd_completion_t *c); int rbd_aio_is_complete(rbd_completion_t c); int rbd_aio_wait_for_complete(rbd_completion_t c); ssize_t rbd_aio_get_return_value(rbd_completion_t c); void rbd_aio_release(rbd_completion_t c); int rbd_flush(rbd_image_t image); /** * Start a flush if caching is enabled. Get a callback when * the currently pending writes are on disk. * * @param image the image to flush writes to * @param c what to call when flushing is complete * @returns 0 on success, negative error code on failure */ int rbd_aio_flush(rbd_image_t image, rbd_completion_t c); /** * Drop any cached data for an image * * @param image the image to invalidate cached data for * @returns 0 on success, negative error code on failure */ int rbd_invalidate_cache(rbd_image_t image); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/include/rbd/librbd.hpp0000664000175100017510000001715212623076744021633 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef __LIBRBD_HPP #define __LIBRBD_HPP #include #include #include #include #include #include "../rados/buffer.h" #include "../rados/librados.hpp" #include "librbd.h" namespace librbd { using librados::IoCtx; class Image; typedef void *image_ctx_t; typedef void *completion_t; typedef void (*callback_t)(completion_t cb, void *arg); typedef struct { uint64_t id; uint64_t size; std::string name; } snap_info_t; typedef struct { std::string client; std::string cookie; std::string address; } locker_t; typedef rbd_image_info_t image_info_t; class ProgressContext { public: virtual ~ProgressContext(); virtual int update_progress(uint64_t offset, uint64_t total) = 0; }; class RBD { public: RBD(); ~RBD(); struct AioCompletion { void *pc; AioCompletion(void *cb_arg, callback_t complete_cb); bool is_complete(); int wait_for_complete(); ssize_t get_return_value(); void release(); }; void version(int *major, int *minor, int *extra); int open(IoCtx& io_ctx, Image& image, const char *name); int open(IoCtx& io_ctx, Image& image, const char *name, const char *snapname); // see librbd.h int open_read_only(IoCtx& io_ctx, Image& image, const char *name, const char *snapname); int list(IoCtx& io_ctx, std::vector& names); int create(IoCtx& io_ctx, const char *name, uint64_t size, int *order); int create2(IoCtx& io_ctx, const char *name, uint64_t size, uint64_t features, int *order); int create3(IoCtx& io_ctx, const char *name, uint64_t size, uint64_t features, int *order, uint64_t stripe_unit, uint64_t stripe_count); int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snapname, IoCtx& c_ioctx, const char *c_name, uint64_t features, int *c_order); int clone2(IoCtx& p_ioctx, const char *p_name, const char *p_snapname, IoCtx& c_ioctx, const char *c_name, uint64_t features, int *c_order, uint64_t stripe_unit, int stripe_count); int remove(IoCtx& io_ctx, const char *name); int remove_with_progress(IoCtx& io_ctx, const char *name, ProgressContext& pctx); int rename(IoCtx& src_io_ctx, const char *srcname, const char *destname); private: /* We don't allow assignment or copying */ RBD(const RBD& rhs); const RBD& operator=(const RBD& rhs); }; class Image { public: Image(); ~Image(); int resize(uint64_t size); int resize_with_progress(uint64_t size, ProgressContext& pctx); int stat(image_info_t &info, size_t infosize); int parent_info(std::string *parent_poolname, std::string *parent_name, std::string *parent_snapname); int old_format(uint8_t *old); int size(uint64_t *size); int features(uint64_t *features); int overlap(uint64_t *overlap); int copy(IoCtx& dest_io_ctx, const char *destname); int copy2(Image& dest); int copy_with_progress(IoCtx& dest_io_ctx, const char *destname, ProgressContext &prog_ctx); int copy_with_progress2(Image& dest, ProgressContext &prog_ctx); /* striping */ uint64_t get_stripe_unit() const; uint64_t get_stripe_count() const; int flatten(); int flatten_with_progress(ProgressContext &prog_ctx); /** * Returns a pair of poolname, imagename for each clone * of this image at the currently set snapshot. */ int list_children(std::set > *children); /* advisory locking (see librbd.h for details) */ int list_lockers(std::list *lockers, bool *exclusive, std::string *tag); int lock_exclusive(const std::string& cookie); int lock_shared(const std::string& cookie, const std::string& tag); int unlock(const std::string& cookie); int break_lock(const std::string& client, const std::string& cookie); /* snapshots */ int snap_list(std::vector& snaps); bool snap_exists(const char *snapname); int snap_create(const char *snapname); int snap_remove(const char *snapname); int snap_rollback(const char *snap_name); int snap_rollback_with_progress(const char *snap_name, ProgressContext& pctx); int snap_protect(const char *snap_name); int snap_unprotect(const char *snap_name); int snap_is_protected(const char *snap_name, bool *is_protected); int snap_set(const char *snap_name); /* I/O */ ssize_t read(uint64_t ofs, size_t len, ceph::bufferlist& bl); int64_t read_iterate(uint64_t ofs, size_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg); int read_iterate2(uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg); /** * get difference between two versions of an image * * This will return the differences between two versions of an image * via a callback, which gets the offset and length and a flag * indicating whether the extent exists (1), or is known/defined to * be zeros (a hole, 0). If the source snapshot name is NULL, we * interpret that as the beginning of time and return all allocated * regions of the image. The end version is whatever is currently * selected for the image handle (either a snapshot or the writeable * head). * * @param fromsnapname start snapshot name, or NULL * @param ofs start offset * @param len len in bytes of region to report on * @param cb callback to call for each allocated region * @param arg argument to pass to the callback * @returns 0 on success, or negative error code on error */ int diff_iterate(const char *fromsnapname, uint64_t ofs, uint64_t len, int (*cb)(uint64_t, size_t, int, void *), void *arg); ssize_t write(uint64_t ofs, size_t len, ceph::bufferlist& bl); int discard(uint64_t ofs, uint64_t len); int aio_write(uint64_t off, size_t len, ceph::bufferlist& bl, RBD::AioCompletion *c); /** * read async from image * * The target bufferlist is populated with references to buffers * that contain the data for the given extent of the image. * * NOTE: If caching is enabled, the bufferlist will directly * reference buffers in the cache to avoid an unnecessary data copy. * As a result, if the user intends to modify the buffer contents * directly, they should make a copy first (unconditionally, or when * the reference count on ther underlying buffer is more than 1). * * @param off offset in image * @param len length of read * @param bl bufferlist to read into * @param c aio completion to notify when read is complete */ int aio_read(uint64_t off, size_t len, ceph::bufferlist& bl, RBD::AioCompletion *c); int aio_discard(uint64_t off, uint64_t len, RBD::AioCompletion *c); int flush(); /** * Start a flush if caching is enabled. Get a callback when * the currently pending writes are on disk. * * @param image the image to flush writes to * @param c what to call when flushing is complete * @returns 0 on success, negative error code on failure */ int aio_flush(RBD::AioCompletion *c); /** * Drop any cached data for an image * * @param image the image to invalidate cached data for * @returns 0 on success, negative error code on failure */ int invalidate_cache(); private: friend class RBD; Image(const Image& rhs); const Image& operator=(const Image& rhs); image_ctx_t ctx; }; } #endif ceph-0.80.11/src/perfglue/0000775000175100017510000000000012623077035017267 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/perfglue/cpu_profiler.cc0000664000175100017510000000206112623076744022274 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/LogClient.h" #include "perfglue/cpu_profiler.h" #include void cpu_profiler_handle_command(const std::vector &cmd, ostream& out) { if (cmd[1] == "status") { ProfilerState st; ProfilerGetCurrentState(&st); out << "cpu_profiler " << (st.enabled ? "enabled":"not enabled") << " start_time " << st.start_time << " profile_name " << st.profile_name << " samples " << st.samples_gathered; } else if (cmd[1] == "flush") { ProfilerFlush(); out << "cpu_profiler: flushed"; } else { out << "cpu_profiler: unrecognized command " << cmd << "; expected one of status, flush."; } } ceph-0.80.11/src/perfglue/disabled_stubs.cc0000664000175100017510000000121412623076744022571 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/LogClient.h" #include "perfglue/cpu_profiler.h" #include #include void cpu_profiler_handle_command(const std::vector &cmd, ostream& out) { out << "cpu_profiler support not linked in"; } ceph-0.80.11/src/perfglue/heap_profiler.cc0000664000175100017510000000633612623076744022433 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network/Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include "heap_profiler.h" #include "common/environment.h" #include "common/LogClient.h" #include "global/global_context.h" #include "common/debug.h" bool ceph_using_tcmalloc() { return true; } void ceph_heap_profiler_init() { // Two other interesting environment variables to set are: // HEAP_PROFILE_ALLOCATION_INTERVAL, HEAP_PROFILE_INUSE_INTERVAL if (get_env_bool("CEPH_HEAP_PROFILER_INIT")) { ceph_heap_profiler_start(); } } void ceph_heap_profiler_stats(char *buf, int length) { MallocExtension::instance()->GetStats(buf, length); } void ceph_heap_release_free_memory() { MallocExtension::instance()->ReleaseFreeMemory(); } bool ceph_heap_profiler_running() { return IsHeapProfilerRunning(); } static void get_profile_name(char *profile_name, int profile_name_len) { char path[PATH_MAX]; snprintf(path, sizeof(path), "%s", g_conf->log_file.c_str()); char *last_slash = rindex(path, '/'); if (last_slash == NULL) { snprintf(profile_name, profile_name_len, "./%s.profile", g_conf->name.to_cstr()); } else { last_slash[1] = '\0'; snprintf(profile_name, profile_name_len, "%s/%s.profile", path, g_conf->name.to_cstr()); } } void ceph_heap_profiler_start() { char profile_name[PATH_MAX]; get_profile_name(profile_name, sizeof(profile_name)); generic_dout(0) << "turning on heap profiler with prefix " << profile_name << dendl; HeapProfilerStart(profile_name); } void ceph_heap_profiler_stop() { HeapProfilerStop(); } void ceph_heap_profiler_dump(const char *reason) { HeapProfilerDump(reason); } void ceph_heap_profiler_handle_command(const std::vector& cmd, ostream& out) { if (cmd.size() == 1 && cmd[0] == "dump") { if (!ceph_heap_profiler_running()) { out << "heap profiler not running; can't dump"; return; } char *heap_stats = new char[1024]; ceph_heap_profiler_stats(heap_stats, 1024); out << g_conf->name << "dumping heap profile now.\n" << heap_stats; ceph_heap_profiler_dump("admin request"); } else if (cmd.size() == 1 && cmd[0] == "start_profiler") { ceph_heap_profiler_start(); out << g_conf->name << " started profiler"; } else if (cmd.size() == 1 && cmd[0] == "stop_profiler") { ceph_heap_profiler_stop(); out << g_conf->name << " stopped profiler"; } else if (cmd.size() == 1 && cmd[0] == "release") { ceph_heap_release_free_memory(); out << g_conf->name << " releasing free RAM back to system."; } else if (cmd.size() == 1 && cmd[0] == "stats") { char *heap_stats = new char[1024]; ceph_heap_profiler_stats(heap_stats, 1024); out << g_conf->name << "tcmalloc heap stats:" << heap_stats; } else { out << "unknown command " << cmd; } } ceph-0.80.11/src/perfglue/cpu_profiler.h0000664000175100017510000000117512623076744022143 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_PERFGLUE_CPU_PROFILER /* * Ceph glue for the Google Perftools CPU profiler */ #include #include void cpu_profiler_handle_command(const std::vector &cmd, ostream& out); #endif ceph-0.80.11/src/perfglue/Makefile.am0000664000175100017510000000123212623076744021327 0ustar jenkins-buildjenkins-buildlibperfglue_la_SOURCES = if WITH_TCMALLOC libperfglue_la_SOURCES += perfglue/heap_profiler.cc libperfglue_la_LIBADD = -ltcmalloc AM_CFLAGS += -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free AM_CXXFLAGS += -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free else libperfglue_la_SOURCES += perfglue/disabled_heap_profiler.cc endif # WITH_TCMALLOC if WITH_PROFILER libperfglue_la_SOURCES += perfglue/cpu_profiler.cc else libperfglue_la_SOURCES += perfglue/disabled_stubs.cc endif # WITH_PROFILER noinst_LTLIBRARIES += libperfglue.la noinst_HEADERS += \ perfglue/cpu_profiler.h \ perfglue/heap_profiler.h ceph-0.80.11/src/perfglue/disabled_heap_profiler.cc0000664000175100017510000000177412623076744024263 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network/Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "heap_profiler.h" bool ceph_using_tcmalloc() { return false; } void ceph_heap_profiler_init() { return; } void ceph_heap_profiler_stats(char *buf, int length) { return; } void ceph_heap_release_free_memory() { return; } bool ceph_heap_profiler_running() { return false; } void ceph_heap_profiler_start() { return; } void ceph_heap_profiler_stop() { return; } void ceph_heap_profiler_dump(const char *reason) { return; } void ceph_heap_profiler_handle_command(const std::vector& cmd, ostream& out) { return; } ceph-0.80.11/src/perfglue/heap_profiler.h0000664000175100017510000000231412623076744022265 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network/Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef HEAP_PROFILER_H_ #define HEAP_PROFILER_H_ #include #include #include "common/config.h" class LogClient; /* * Ceph glue for the Google perftools heap profiler, included * as part of tcmalloc. This replaces ugly function pointers * and #ifdef hacks! */ bool ceph_using_tcmalloc(); /* * Configure the heap profiler */ void ceph_heap_profiler_init(); void ceph_heap_profiler_stats(char *buf, int length); void ceph_heap_release_free_memory(); bool ceph_heap_profiler_running(); void ceph_heap_profiler_start(); void ceph_heap_profiler_stop(); void ceph_heap_profiler_dump(const char *reason); void ceph_heap_profiler_handle_command(const std::vector &cmd, ostream& out); #endif /* HEAP_PROFILER_H_ */ ceph-0.80.11/src/osd/0000775000175100017510000000000012623077035016243 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/osd/ReplicatedBackend.h0000664000175100017510000002673712623076744021765 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef REPBACKEND_H #define REPBACKEND_H #include "OSD.h" #include "PGBackend.h" #include "osd_types.h" #include "../include/memory.h" struct C_ReplicatedBackend_OnPullComplete; class ReplicatedBackend : public PGBackend { struct RPGHandle : public PGBackend::RecoveryHandle { map > pushes; map > pulls; }; friend struct C_ReplicatedBackend_OnPullComplete; public: CephContext *cct; ReplicatedBackend( PGBackend::Listener *pg, coll_t coll, coll_t temp_coll, ObjectStore *store, CephContext *cct); /// @see PGBackend::open_recovery_op RPGHandle *_open_recovery_op() { return new RPGHandle(); } PGBackend::RecoveryHandle *open_recovery_op() { return _open_recovery_op(); } /// @see PGBackend::run_recovery_op void run_recovery_op( PGBackend::RecoveryHandle *h, int priority); /// @see PGBackend::recover_object void recover_object( const hobject_t &hoid, eversion_t v, ObjectContextRef head, ObjectContextRef obc, RecoveryHandle *h ); void check_recovery_sources(const OSDMapRef osdmap); /// @see PGBackend::delay_message_until_active bool can_handle_while_inactive(OpRequestRef op); /// @see PGBackend::handle_message bool handle_message( OpRequestRef op ); void on_change(); void clear_state(); void on_flushed(); class RPCRecPred : public IsRecoverablePredicate { public: bool operator()(const set &have) const { return !have.empty(); } }; IsRecoverablePredicate *get_is_recoverable_predicate() { return new RPCRecPred; } class RPCReadPred : public IsReadablePredicate { pg_shard_t whoami; public: RPCReadPred(pg_shard_t whoami) : whoami(whoami) {} bool operator()(const set &have) const { return have.count(whoami); } }; IsReadablePredicate *get_is_readable_predicate() { return new RPCReadPred(get_parent()->whoami_shard()); } virtual void dump_recovery_info(Formatter *f) const { { f->open_array_section("pull_from_peer"); for (map >::const_iterator i = pull_from_peer.begin(); i != pull_from_peer.end(); ++i) { f->open_object_section("pulling_from"); f->dump_stream("pull_from") << i->first; { f->open_array_section("pulls"); for (set::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { f->open_object_section("pull_info"); assert(pulling.count(*j)); pulling.find(*j)->second.dump(f); f->close_section(); } f->close_section(); } f->close_section(); } f->close_section(); } { f->open_array_section("pushing"); for (map >::const_iterator i = pushing.begin(); i != pushing.end(); ++i) { f->open_object_section("object"); f->dump_stream("pushing") << i->first; { f->open_array_section("pushing_to"); for (map::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { f->open_object_section("push_progress"); f->dump_stream("pushing_to") << j->first; { f->open_object_section("push_info"); j->second.dump(f); f->close_section(); } f->close_section(); } f->close_section(); } f->close_section(); } f->close_section(); } } int objects_read_sync( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist *bl); void objects_read_async( const hobject_t &hoid, const list, pair > > &to_read, Context *on_complete); private: // push struct PushInfo { ObjectRecoveryProgress recovery_progress; ObjectRecoveryInfo recovery_info; ObjectContextRef obc; object_stat_sum_t stat; void dump(Formatter *f) const { { f->open_object_section("recovery_progress"); recovery_progress.dump(f); f->close_section(); } { f->open_object_section("recovery_info"); recovery_info.dump(f); f->close_section(); } } }; map > pushing; // pull struct PullInfo { ObjectRecoveryProgress recovery_progress; ObjectRecoveryInfo recovery_info; ObjectContextRef head_ctx; ObjectContextRef obc; object_stat_sum_t stat; void dump(Formatter *f) const { { f->open_object_section("recovery_progress"); recovery_progress.dump(f); f->close_section(); } { f->open_object_section("recovery_info"); recovery_info.dump(f); f->close_section(); } } bool is_complete() const { return recovery_progress.is_complete(recovery_info); } }; map pulling; // Reverse mapping from osd peer to objects beging pulled from that peer map > pull_from_peer; void sub_op_push(OpRequestRef op); void sub_op_push_reply(OpRequestRef op); void sub_op_pull(OpRequestRef op); void _do_push(OpRequestRef op); void _do_pull_response(OpRequestRef op); void do_push(OpRequestRef op) { if (is_primary()) { _do_pull_response(op); } else { _do_push(op); } } void do_pull(OpRequestRef op); void do_push_reply(OpRequestRef op); bool handle_push_reply(pg_shard_t peer, PushReplyOp &op, PushOp *reply); void handle_pull(pg_shard_t peer, PullOp &op, PushOp *reply); bool handle_pull_response( pg_shard_t from, PushOp &op, PullOp *response, list *to_continue, ObjectStore::Transaction *t); void handle_push(pg_shard_t from, PushOp &op, PushReplyOp *response, ObjectStore::Transaction *t); static void trim_pushed_data(const interval_set ©_subset, const interval_set &intervals_received, bufferlist data_received, interval_set *intervals_usable, bufferlist *data_usable); void _failed_push(pg_shard_t from, const hobject_t &soid); void send_pushes(int prio, map > &pushes); void prep_push_op_blank(const hobject_t& soid, PushOp *op); int send_push_op_legacy(int priority, pg_shard_t peer, PushOp &pop); int send_pull_legacy(int priority, pg_shard_t peer, const ObjectRecoveryInfo& recovery_info, ObjectRecoveryProgress progress); void send_pulls( int priority, map > &pulls); int build_push_op(const ObjectRecoveryInfo &recovery_info, const ObjectRecoveryProgress &progress, ObjectRecoveryProgress *out_progress, PushOp *out_op, object_stat_sum_t *stat = 0); void submit_push_data(ObjectRecoveryInfo &recovery_info, bool first, bool complete, const interval_set &intervals_included, bufferlist data_included, bufferlist omap_header, map &attrs, map &omap_entries, ObjectStore::Transaction *t); void submit_push_complete(ObjectRecoveryInfo &recovery_info, ObjectStore::Transaction *t); void calc_clone_subsets( SnapSet& snapset, const hobject_t& poid, const pg_missing_t& missing, const hobject_t &last_backfill, interval_set& data_subset, map >& clone_subsets); void prepare_pull( eversion_t v, const hobject_t& soid, ObjectContextRef headctx, RPGHandle *h); int start_pushes( const hobject_t &soid, ObjectContextRef obj, RPGHandle *h); void prep_push_to_replica( ObjectContextRef obc, const hobject_t& soid, pg_shard_t peer, PushOp *pop); void prep_push(ObjectContextRef obc, const hobject_t& oid, pg_shard_t dest, PushOp *op); void prep_push(ObjectContextRef obc, const hobject_t& soid, pg_shard_t peer, eversion_t version, interval_set &data_subset, map >& clone_subsets, PushOp *op); void calc_head_subsets(ObjectContextRef obc, SnapSet& snapset, const hobject_t& head, const pg_missing_t& missing, const hobject_t &last_backfill, interval_set& data_subset, map >& clone_subsets); ObjectRecoveryInfo recalc_subsets( const ObjectRecoveryInfo& recovery_info, SnapSetContext *ssc ); /** * Client IO */ struct InProgressOp { ceph_tid_t tid; set waiting_for_commit; set waiting_for_applied; Context *on_commit; Context *on_applied; OpRequestRef op; eversion_t v; InProgressOp( ceph_tid_t tid, Context *on_commit, Context *on_applied, OpRequestRef op, eversion_t v) : tid(tid), on_commit(on_commit), on_applied(on_applied), op(op), v(v) {} bool done() const { return waiting_for_commit.empty() && waiting_for_applied.empty(); } }; map in_progress_ops; public: PGTransaction *get_transaction(); friend class C_OSD_OnOpCommit; friend class C_OSD_OnOpApplied; void submit_transaction( const hobject_t &hoid, const eversion_t &at_version, PGTransaction *t, const eversion_t &trim_to, const eversion_t &trim_rollback_to, vector &log_entries, boost::optional &hset_history, Context *on_local_applied_sync, Context *on_all_applied, Context *on_all_commit, ceph_tid_t tid, osd_reqid_t reqid, OpRequestRef op ); private: void issue_op( const hobject_t &soid, const eversion_t &at_version, ceph_tid_t tid, osd_reqid_t reqid, eversion_t pg_trim_to, eversion_t pg_trim_rollback_to, hobject_t new_temp_oid, hobject_t discard_temp_oid, vector &log_entries, boost::optional &hset_history, InProgressOp *op, ObjectStore::Transaction *op_t); void op_applied(InProgressOp *op); void op_commit(InProgressOp *op); void sub_op_modify_reply(OpRequestRef op); void sub_op_modify(OpRequestRef op); struct RepModify { OpRequestRef op; bool applied, committed; int ackerosd; eversion_t last_complete; epoch_t epoch_started; uint64_t bytes_written; ObjectStore::Transaction opt, localt; RepModify() : applied(false), committed(false), ackerosd(-1), epoch_started(0), bytes_written(0) {} }; typedef ceph::shared_ptr RepModifyRef; struct C_OSD_RepModifyApply : public Context { ReplicatedBackend *pg; RepModifyRef rm; C_OSD_RepModifyApply(ReplicatedBackend *pg, RepModifyRef r) : pg(pg), rm(r) {} void finish(int r) { pg->sub_op_modify_applied(rm); } }; struct C_OSD_RepModifyCommit : public Context { ReplicatedBackend *pg; RepModifyRef rm; C_OSD_RepModifyCommit(ReplicatedBackend *pg, RepModifyRef r) : pg(pg), rm(r) {} void finish(int r) { pg->sub_op_modify_commit(rm); } }; void sub_op_modify_applied(RepModifyRef rm); void sub_op_modify_commit(RepModifyRef rm); bool scrub_supported() { return true; } void be_deep_scrub( const hobject_t &obj, ScrubMap::object &o, ThreadPool::TPHandle &handle); uint64_t be_get_ondisk_size(uint64_t logical_size) { return logical_size; } }; #endif ceph-0.80.11/src/osd/ObjectVersioner.h0000664000175100017510000000162212623076744021526 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OSD_OBJECTVERSIONER_H #define CEPH_OSD_OBJECTVERSIONER_H class ObjectVersioner { public: pobject_t oid; void get_versions(list& ls); version_t head(); // newest version_t committed(); // last committed version_t tail(); // oldest /* * prepare a new version, starting wit "raw" transaction t. */ void prepare(ObjectStore::Transaction& t, version_t v); void rollback_to(version_t v); void commit_to(version_t v); }; #endif ceph-0.80.11/src/osd/PGBackend.h0000664000175100017510000004754112623076744020213 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Inktank Storage, Inc. * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef PGBACKEND_H #define PGBACKEND_H #include "OSDMap.h" #include "PGLog.h" #include "osd_types.h" #include "common/WorkQueue.h" #include "osd_types.h" #include "include/Context.h" #include "os/ObjectStore.h" #include "common/LogClient.h" #include /** * PGBackend * * PGBackend defines an interface for logic handling IO and * replication on RADOS objects. The PGBackend implementation * is responsible for: * * 1) Handling client operations * 2) Handling object recovery * 3) Handling object access * 4) Handling scrub, deep-scrub, repair */ class PGBackend { protected: ObjectStore *store; const coll_t coll; const coll_t temp_coll; public: /** * Provides interfaces for PGBackend callbacks * * The intention is that the parent calls into the PGBackend * implementation holding a lock and that the callbacks are * called under the same locks. */ class Listener { public: /// Recovery virtual void on_local_recover_start( const hobject_t &oid, ObjectStore::Transaction *t) = 0; /** * Called with the transaction recovering oid */ virtual void on_local_recover( const hobject_t &oid, const object_stat_sum_t &stat_diff, const ObjectRecoveryInfo &recovery_info, ObjectContextRef obc, ObjectStore::Transaction *t ) = 0; /** * Called when transaction recovering oid is durable and * applied on all replicas */ virtual void on_global_recover(const hobject_t &oid) = 0; /** * Called when peer is recovered */ virtual void on_peer_recover( pg_shard_t peer, const hobject_t &oid, const ObjectRecoveryInfo &recovery_info, const object_stat_sum_t &stat ) = 0; virtual void begin_peer_recover( pg_shard_t peer, const hobject_t oid) = 0; virtual void failed_push(pg_shard_t from, const hobject_t &soid) = 0; virtual void cancel_pull(const hobject_t &soid) = 0; /** * Bless a context * * Wraps a context in whatever outer layers the parent usually * uses to call into the PGBackend */ virtual Context *bless_context(Context *c) = 0; virtual GenContext *bless_gencontext( GenContext *c) = 0; virtual void send_message(int to_osd, Message *m) = 0; virtual void queue_transaction( ObjectStore::Transaction *t, OpRequestRef op = OpRequestRef() ) = 0; virtual epoch_t get_epoch() const = 0; virtual const set &get_actingbackfill_shards() const = 0; virtual const set &get_acting_shards() const = 0; virtual const set &get_backfill_shards() const = 0; virtual std::string gen_dbg_prefix() const = 0; virtual const map > &get_missing_loc_shards() const = 0; virtual const pg_missing_t &get_local_missing() const = 0; virtual const map &get_shard_missing() const = 0; virtual boost::optional maybe_get_shard_missing( pg_shard_t peer) const { if (peer == primary_shard()) { return get_local_missing(); } else { map::const_iterator i = get_shard_missing().find(peer); if (i == get_shard_missing().end()) { return boost::optional(); } else { return i->second; } } } virtual const pg_missing_t &get_shard_missing(pg_shard_t peer) const { boost::optional m = maybe_get_shard_missing(peer); assert(m); return *m; } virtual const map &get_shard_info() const = 0; virtual const pg_info_t &get_shard_info(pg_shard_t peer) const { if (peer == primary_shard()) { return get_info(); } else { map::const_iterator i = get_shard_info().find(peer); assert(i != get_shard_info().end()); return i->second; } } virtual const PGLog &get_log() const = 0; virtual bool pgb_is_primary() const = 0; virtual OSDMapRef pgb_get_osdmap() const = 0; virtual const pg_info_t &get_info() const = 0; virtual const pg_pool_t &get_pool() const = 0; virtual ObjectContextRef get_obc( const hobject_t &hoid, map &attrs) = 0; virtual void op_applied( const eversion_t &applied_version) = 0; virtual bool should_send_op( pg_shard_t peer, const hobject_t &hoid) = 0; virtual void log_operation( vector &logv, boost::optional &hset_history, const eversion_t &trim_to, const eversion_t &trim_rollback_to, bool transaction_applied, ObjectStore::Transaction *t) = 0; virtual void update_peer_last_complete_ondisk( pg_shard_t fromosd, eversion_t lcod) = 0; virtual void update_last_complete_ondisk( eversion_t lcod) = 0; virtual void update_stats( const pg_stat_t &stat) = 0; virtual void schedule_work( GenContext *c) = 0; virtual pg_shard_t whoami_shard() const = 0; int whoami() const { return whoami_shard().osd; } spg_t whoami_spg_t() const { return get_info().pgid; } virtual spg_t primary_spg_t() const = 0; virtual pg_shard_t primary_shard() const = 0; virtual void send_message_osd_cluster( int peer, Message *m, epoch_t from_epoch) = 0; virtual void send_message_osd_cluster( Message *m, Connection *con) = 0; virtual void send_message_osd_cluster( Message *m, const ConnectionRef& con) = 0; virtual ConnectionRef get_con_osd_cluster(int peer, epoch_t from_epoch) = 0; virtual entity_name_t get_cluster_msgr_name() = 0; virtual PerfCounters *get_logger() = 0; virtual ceph_tid_t get_tid() = 0; virtual LogClientTemp clog_error() = 0; virtual ~Listener() {} }; Listener *parent; Listener *get_parent() const { return parent; } PGBackend(Listener *l, ObjectStore *store, coll_t coll, coll_t temp_coll) : store(store), coll(coll), temp_coll(temp_coll), parent(l), temp_created(false) {} bool is_primary() const { return get_parent()->pgb_is_primary(); } OSDMapRef get_osdmap() const { return get_parent()->pgb_get_osdmap(); } const pg_info_t &get_info() { return get_parent()->get_info(); } std::string gen_prefix() const { return parent->gen_dbg_prefix(); } /** * RecoveryHandle * * We may want to recover multiple objects in the same set of * messages. RecoveryHandle is an interface for the opaque * object used by the implementation to store the details of * the pending recovery operations. */ struct RecoveryHandle { virtual ~RecoveryHandle() {} }; /// Get a fresh recovery operation virtual RecoveryHandle *open_recovery_op() = 0; /// run_recovery_op: finish the operation represented by h virtual void run_recovery_op( RecoveryHandle *h, ///< [in] op to finish int priority ///< [in] msg priority ) = 0; /** * recover_object * * Triggers a recovery operation on the specified hobject_t * onreadable must be called before onwriteable * * On each replica (primary included), get_parent()->on_not_missing() * must be called when the transaction finalizing the recovery * is queued. Similarly, get_parent()->on_readable() must be called * when the transaction is applied in the backing store. * * get_parent()->on_not_degraded() should be called on the primary * when writes can resume on the object. * * obc may be NULL if the primary lacks the object. * * head may be NULL only if the head/snapdir is missing * * @param missing [in] set of info, missing pairs for queried nodes * @param overlaps [in] mapping of object to file offset overlaps */ virtual void recover_object( const hobject_t &hoid, ///< [in] object to recover eversion_t v, ///< [in] version to recover ObjectContextRef head, ///< [in] context of the head/snapdir object ObjectContextRef obc, ///< [in] context of the object RecoveryHandle *h ///< [in,out] handle to attach recovery op to ) = 0; /** * true if PGBackend can handle this message while inactive * * If it returns true, handle_message *must* also return true */ virtual bool can_handle_while_inactive(OpRequestRef op) = 0; /// gives PGBackend a crack at an incoming message virtual bool handle_message( OpRequestRef op ///< [in] message received ) = 0; ///< @return true if the message was handled virtual void check_recovery_sources(const OSDMapRef osdmap) = 0; /** * clean up any temporary on-disk state due to a pg interval change */ void on_change_cleanup(ObjectStore::Transaction *t); /** * implementation should clear itself, contexts blessed prior to on_change * won't be called after on_change() */ virtual void on_change() = 0; virtual void clear_state() = 0; virtual void on_flushed() = 0; class IsRecoverablePredicate { public: /** * have encodes the shards available */ virtual bool operator()(const set &have) const = 0; virtual ~IsRecoverablePredicate() {} }; virtual IsRecoverablePredicate *get_is_recoverable_predicate() = 0; class IsReadablePredicate { public: /** * have encodes the shards available */ virtual bool operator()(const set &have) const = 0; virtual ~IsReadablePredicate() {} }; virtual IsReadablePredicate *get_is_readable_predicate() = 0; void temp_colls(list *out) { if (temp_created) out->push_back(temp_coll); } void split_colls( spg_t child, int split_bits, int seed, ObjectStore::Transaction *t) { coll_t target = coll_t::make_temp_coll(child); if (!temp_created) return; t->create_collection(target); t->split_collection( temp_coll, split_bits, seed, target); } virtual void dump_recovery_info(Formatter *f) const = 0; private: bool temp_created; set temp_contents; public: coll_t get_temp_coll(ObjectStore::Transaction *t); coll_t get_temp_coll() const { return temp_coll; } bool have_temp_coll() const { return temp_created; } // Track contents of temp collection, clear on reset void add_temp_obj(const hobject_t &oid) { temp_contents.insert(oid); } void add_temp_objs(const set &oids) { temp_contents.insert(oids.begin(), oids.end()); } void clear_temp_obj(const hobject_t &oid) { temp_contents.erase(oid); } void clear_temp_objs(const set &oids) { for (set::const_iterator i = oids.begin(); i != oids.end(); ++i) { temp_contents.erase(*i); } } virtual ~PGBackend() {} /** * Client IO Interface */ class PGTransaction { public: /// Write virtual void touch( const hobject_t &hoid ///< [in] obj to touch ) = 0; virtual void stash( const hobject_t &hoid, ///< [in] obj to remove version_t former_version ///< [in] former object version ) = 0; virtual void remove( const hobject_t &hoid ///< [in] obj to remove ) = 0; virtual void setattrs( const hobject_t &hoid, ///< [in] object to write map &attrs ///< [in] attrs, may be cleared ) = 0; virtual void setattr( const hobject_t &hoid, ///< [in] object to write const string &attrname, ///< [in] attr to write bufferlist &bl ///< [in] val to write, may be claimed ) = 0; virtual void rmattr( const hobject_t &hoid, ///< [in] object to write const string &attrname ///< [in] attr to remove ) = 0; virtual void clone( const hobject_t &from, const hobject_t &to ) = 0; virtual void rename( const hobject_t &from, const hobject_t &to ) = 0; virtual void set_alloc_hint( const hobject_t &hoid, uint64_t expected_object_size, uint64_t expected_write_size ) = 0; /// Optional, not supported on ec-pool virtual void write( const hobject_t &hoid, ///< [in] object to write uint64_t off, ///< [in] off at which to write uint64_t len, ///< [in] len to write from bl bufferlist &bl ///< [in] bl to write will be claimed to len ) { assert(0); } virtual void omap_setkeys( const hobject_t &hoid, ///< [in] object to write map &keys ///< [in] omap keys, may be cleared ) { assert(0); } virtual void omap_rmkeys( const hobject_t &hoid, ///< [in] object to write set &keys ///< [in] omap keys, may be cleared ) { assert(0); } virtual void omap_clear( const hobject_t &hoid ///< [in] object to clear omap ) { assert(0); } virtual void omap_setheader( const hobject_t &hoid, ///< [in] object to write bufferlist &header ///< [in] header ) { assert(0); } virtual void clone_range( const hobject_t &from, ///< [in] from const hobject_t &to, ///< [in] to uint64_t fromoff, ///< [in] offset uint64_t len, ///< [in] len uint64_t tooff ///< [in] offset ) { assert(0); } virtual void truncate( const hobject_t &hoid, uint64_t off ) { assert(0); } virtual void zero( const hobject_t &hoid, uint64_t off, uint64_t len ) { assert(0); } /// Supported on all backends /// off must be the current object size virtual void append( const hobject_t &hoid, ///< [in] object to write uint64_t off, ///< [in] off at which to write uint64_t len, ///< [in] len to write from bl bufferlist &bl ///< [in] bl to write will be claimed to len ) { write(hoid, off, len, bl); } /// to_append *must* have come from the same PGBackend (same concrete type) virtual void append( PGTransaction *to_append ///< [in] trans to append, to_append is cleared ) = 0; virtual void nop() = 0; virtual bool empty() const = 0; virtual uint64_t get_bytes_written() const = 0; virtual ~PGTransaction() {} }; /// Get implementation specific empty transaction virtual PGTransaction *get_transaction() = 0; /// execute implementation specific transaction virtual void submit_transaction( const hobject_t &hoid, ///< [in] object const eversion_t &at_version, ///< [in] version PGTransaction *t, ///< [in] trans to execute const eversion_t &trim_to, ///< [in] trim log to here const eversion_t &trim_rollback_to, ///< [in] trim rollback info to here vector &log_entries, ///< [in] log entries for t /// [in] hitset history (if updated with this transaction) boost::optional &hset_history, Context *on_local_applied_sync, ///< [in] called when applied locally Context *on_all_applied, ///< [in] called when all acked Context *on_all_commit, ///< [in] called when all commit ceph_tid_t tid, ///< [in] tid osd_reqid_t reqid, ///< [in] reqid OpRequestRef op ///< [in] op ) = 0; void rollback( const hobject_t &hoid, const ObjectModDesc &desc, ObjectStore::Transaction *t); /// Reapply old attributes void rollback_setattrs( const hobject_t &hoid, map > &old_attrs, ObjectStore::Transaction *t); /// Truncate object to rollback append virtual void rollback_append( const hobject_t &hoid, uint64_t old_size, ObjectStore::Transaction *t); /// Unstash object to rollback stash void rollback_stash( const hobject_t &hoid, version_t old_version, ObjectStore::Transaction *t); /// Delete object to rollback create void rollback_create( const hobject_t &hoid, ObjectStore::Transaction *t); /// Trim object stashed at stashed_version void trim_stashed_object( const hobject_t &hoid, version_t stashed_version, ObjectStore::Transaction *t); /// List objects in collection int objects_list_partial( const hobject_t &begin, int min, int max, snapid_t seq, vector *ls, hobject_t *next); int objects_list_range( const hobject_t &start, const hobject_t &end, snapid_t seq, vector *ls, vector *gen_obs=0); int objects_get_attr( const hobject_t &hoid, const string &attr, bufferlist *out); virtual int objects_get_attrs( const hobject_t &hoid, map *out); virtual int objects_read_sync( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist *bl) = 0; virtual void objects_read_async( const hobject_t &hoid, const list, pair > > &to_read, Context *on_complete) = 0; virtual bool scrub_supported() { return false; } void be_scan_list( ScrubMap &map, const vector &ls, bool deep, ThreadPool::TPHandle &handle); enum scrub_error_type be_compare_scrub_objects( const ScrubMap::object &auth, const ScrubMap::object &candidate, ostream &errorstream); map::const_iterator be_select_auth_object( const hobject_t &obj, const map &maps); void be_compare_scrubmaps( const map &maps, map > &missing, map > &inconsistent, map &authoritative, map > &invalid_snapcolls, int &shallow_errors, int &deep_errors, const spg_t pgid, const vector &acting, ostream &errorstream); virtual uint64_t be_get_ondisk_size( uint64_t logical_size) { assert(0); return 0; } virtual void be_deep_scrub( const hobject_t &poid, ScrubMap::object &o, ThreadPool::TPHandle &handle) { assert(0); } static PGBackend *build_pg_backend( const pg_pool_t &pool, const OSDMapRef curmap, Listener *l, coll_t coll, coll_t temp_coll, ObjectStore *store, CephContext *cct); }; struct PG_SendMessageOnConn: public Context { PGBackend::Listener *pg; Message *reply; ConnectionRef conn; PG_SendMessageOnConn( PGBackend::Listener *pg, Message *reply, ConnectionRef conn) : pg(pg), reply(reply), conn(conn) {} void finish(int) { pg->send_message_osd_cluster(reply, conn.get()); } }; struct PG_QueueAsync : public Context { PGBackend::Listener *pg; GenContext *c; PG_QueueAsync( PGBackend::Listener *pg, GenContext *c) : pg(pg), c(c) {} void finish(int) { pg->schedule_work(c); } }; #endif ceph-0.80.11/src/osd/OSDMap.cc0000664000175100017510000021647312623076744017660 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "OSDMap.h" #include "common/config.h" #include "common/Formatter.h" #include "include/ceph_features.h" #include "include/str_map.h" #include "common/code_environment.h" #define dout_subsys ceph_subsys_osd // ---------------------------------- // osd_info_t void osd_info_t::dump(Formatter *f) const { f->dump_int("last_clean_begin", last_clean_begin); f->dump_int("last_clean_end", last_clean_end); f->dump_int("up_from", up_from); f->dump_int("up_thru", up_thru); f->dump_int("down_at", down_at); f->dump_int("lost_at", lost_at); } void osd_info_t::encode(bufferlist& bl) const { __u8 struct_v = 1; ::encode(struct_v, bl); ::encode(last_clean_begin, bl); ::encode(last_clean_end, bl); ::encode(up_from, bl); ::encode(up_thru, bl); ::encode(down_at, bl); ::encode(lost_at, bl); } void osd_info_t::decode(bufferlist::iterator& bl) { __u8 struct_v; ::decode(struct_v, bl); ::decode(last_clean_begin, bl); ::decode(last_clean_end, bl); ::decode(up_from, bl); ::decode(up_thru, bl); ::decode(down_at, bl); ::decode(lost_at, bl); } void osd_info_t::generate_test_instances(list& o) { o.push_back(new osd_info_t); o.push_back(new osd_info_t); o.back()->last_clean_begin = 1; o.back()->last_clean_end = 2; o.back()->up_from = 30; o.back()->up_thru = 40; o.back()->down_at = 5; o.back()->lost_at = 6; } ostream& operator<<(ostream& out, const osd_info_t& info) { out << "up_from " << info.up_from << " up_thru " << info.up_thru << " down_at " << info.down_at << " last_clean_interval [" << info.last_clean_begin << "," << info.last_clean_end << ")"; if (info.lost_at) out << " lost_at " << info.lost_at; return out; } // ---------------------------------- // osd_xinfo_t void osd_xinfo_t::dump(Formatter *f) const { f->dump_stream("down_stamp") << down_stamp; f->dump_float("laggy_probability", laggy_probability); f->dump_int("laggy_interval", laggy_interval); f->dump_int("features", features); } void osd_xinfo_t::encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(down_stamp, bl); __u32 lp = laggy_probability * 0xfffffffful; ::encode(lp, bl); ::encode(laggy_interval, bl); ::encode(features, bl); ENCODE_FINISH(bl); } void osd_xinfo_t::decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(down_stamp, bl); __u32 lp; ::decode(lp, bl); laggy_probability = (float)lp / (float)0xffffffff; ::decode(laggy_interval, bl); if (struct_v >= 2) ::decode(features, bl); else features = 0; DECODE_FINISH(bl); } void osd_xinfo_t::generate_test_instances(list& o) { o.push_back(new osd_xinfo_t); o.push_back(new osd_xinfo_t); o.back()->down_stamp = utime_t(2, 3); o.back()->laggy_probability = .123; o.back()->laggy_interval = 123456; } ostream& operator<<(ostream& out, const osd_xinfo_t& xi) { return out << "down_stamp " << xi.down_stamp << " laggy_probability " << xi.laggy_probability << " laggy_interval " << xi.laggy_interval; } // ---------------------------------- // OSDMap::Incremental int OSDMap::Incremental::get_net_marked_out(const OSDMap *previous) const { int n = 0; for (map::const_iterator p = new_weight.begin(); p != new_weight.end(); ++p) { if (p->second == CEPH_OSD_OUT && !previous->is_out(p->first)) n++; // marked out if (p->second != CEPH_OSD_OUT && previous->is_out(p->first)) n--; // marked in } return n; } int OSDMap::Incremental::get_net_marked_down(const OSDMap *previous) const { int n = 0; for (map::const_iterator p = new_state.begin(); p != new_state.end(); ++p) { if (p->second & CEPH_OSD_UP) { if (previous->is_up(p->first)) n++; // marked down else n--; // marked up } } return n; } int OSDMap::Incremental::identify_osd(uuid_d u) const { for (map::const_iterator p = new_uuid.begin(); p != new_uuid.end(); ++p) if (p->second == u) return p->first; return -1; } int OSDMap::Incremental::propagate_snaps_to_tiers(CephContext *cct, const OSDMap& osdmap) { assert(epoch == osdmap.get_epoch() + 1); for (map::iterator p = new_pools.begin(); p != new_pools.end(); ++p) { if (!p->second.tiers.empty()) { pg_pool_t& base = p->second; for (set::const_iterator q = base.tiers.begin(); q != base.tiers.end(); ++q) { map::iterator r = new_pools.find(*q); pg_pool_t *tier = 0; if (r == new_pools.end()) { const pg_pool_t *orig = osdmap.get_pg_pool(*q); if (!orig) { lderr(cct) << __func__ << " no pool " << *q << dendl; return -EIO; } tier = get_new_pool(*q, orig); } else { tier = &r->second; } if (tier->tier_of != p->first) { lderr(cct) << __func__ << " " << r->first << " tier_of != " << p->first << dendl; return -EIO; } ldout(cct, 10) << __func__ << " from " << p->first << " to " << r->first << dendl; tier->snap_seq = base.snap_seq; tier->snap_epoch = base.snap_epoch; tier->snaps = base.snaps; tier->removed_snaps = base.removed_snaps; } } } return 0; } bool OSDMap::subtree_is_down(int id, set *down_cache) const { if (id >= 0) return is_down(id); if (down_cache && down_cache->count(id)) { return true; } list children; crush->get_children(id, &children); for (list::iterator p = children.begin(); p != children.end(); ++p) { if (!subtree_is_down(*p, down_cache)) { return false; } } if (down_cache) { down_cache->insert(id); } return true; } bool OSDMap::containing_subtree_is_down(CephContext *cct, int id, int subtree_type, set *down_cache) const { // use a stack-local down_cache if we didn't get one from the // caller. then at least this particular call will avoid duplicated // work. set local_down_cache; if (!down_cache) { down_cache = &local_down_cache; } int current = id; while (true) { int type; if (current >= 0) { type = 0; } else { type = crush->get_bucket_type(current); } assert(type >= 0); if (!subtree_is_down(current, down_cache)) { ldout(cct, 30) << "containing_subtree_is_down(" << id << ") = false" << dendl; return false; } // is this a big enough subtree to be done? if (type >= subtree_type) { ldout(cct, 30) << "containing_subtree_is_down(" << id << ") = true ... " << type << " >= " << subtree_type << dendl; return true; } int r = crush->get_immediate_parent_id(current, ¤t); if (r < 0) { return false; } } } void OSDMap::Incremental::encode_client_old(bufferlist& bl) const { __u16 v = 5; ::encode(v, bl); ::encode(fsid, bl); ::encode(epoch, bl); ::encode(modified, bl); int32_t new_t = new_pool_max; ::encode(new_t, bl); ::encode(new_flags, bl); ::encode(fullmap, bl); ::encode(crush, bl); ::encode(new_max_osd, bl); // for ::encode(new_pools, bl); __u32 n = new_pools.size(); ::encode(n, bl); for (map::const_iterator p = new_pools.begin(); p != new_pools.end(); ++p) { n = p->first; ::encode(n, bl); ::encode(p->second, bl, 0); } // for ::encode(new_pool_names, bl); n = new_pool_names.size(); ::encode(n, bl); for (map::const_iterator p = new_pool_names.begin(); p != new_pool_names.end(); ++p) { n = p->first; ::encode(n, bl); ::encode(p->second, bl); } // for ::encode(old_pools, bl); n = old_pools.size(); ::encode(n, bl); for (set::iterator p = old_pools.begin(); p != old_pools.end(); ++p) { n = *p; ::encode(n, bl); } ::encode(new_up_client, bl); ::encode(new_state, bl); ::encode(new_weight, bl); // for ::encode(new_pg_temp, bl); n = new_pg_temp.size(); ::encode(n, bl); for (map >::const_iterator p = new_pg_temp.begin(); p != new_pg_temp.end(); ++p) { old_pg_t opg = p->first.get_old_pg(); ::encode(opg, bl); ::encode(p->second, bl); } } void OSDMap::Incremental::encode_classic(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_PGID64) == 0) { encode_client_old(bl); return; } // base __u16 v = 6; ::encode(v, bl); ::encode(fsid, bl); ::encode(epoch, bl); ::encode(modified, bl); ::encode(new_pool_max, bl); ::encode(new_flags, bl); ::encode(fullmap, bl); ::encode(crush, bl); ::encode(new_max_osd, bl); ::encode(new_pools, bl, features); ::encode(new_pool_names, bl); ::encode(old_pools, bl); ::encode(new_up_client, bl); ::encode(new_state, bl); ::encode(new_weight, bl); ::encode(new_pg_temp, bl); // extended __u16 ev = 10; ::encode(ev, bl); ::encode(new_hb_back_up, bl); ::encode(new_up_thru, bl); ::encode(new_last_clean_interval, bl); ::encode(new_lost, bl); ::encode(new_blacklist, bl); ::encode(old_blacklist, bl); ::encode(new_up_cluster, bl); ::encode(cluster_snapshot, bl); ::encode(new_uuid, bl); ::encode(new_xinfo, bl); ::encode(new_hb_front_up, bl); } void OSDMap::Incremental::encode(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_OSDMAP_ENC) == 0) { encode_classic(bl, features); return; } // meta-encoding: how we include client-used and osd-specific data ENCODE_START(7, 7, bl); { ENCODE_START(3, 1, bl); // client-usable data ::encode(fsid, bl); ::encode(epoch, bl); ::encode(modified, bl); ::encode(new_pool_max, bl); ::encode(new_flags, bl); ::encode(fullmap, bl); ::encode(crush, bl); ::encode(new_max_osd, bl); ::encode(new_pools, bl, features); ::encode(new_pool_names, bl); ::encode(old_pools, bl); ::encode(new_up_client, bl); ::encode(new_state, bl); ::encode(new_weight, bl); ::encode(new_pg_temp, bl); ::encode(new_primary_temp, bl); ::encode(new_primary_affinity, bl); ::encode(new_erasure_code_profiles, bl); ::encode(old_erasure_code_profiles, bl); ENCODE_FINISH(bl); // client-usable data } { ENCODE_START(2, 1, bl); // extended, osd-only data ::encode(new_hb_back_up, bl); ::encode(new_up_thru, bl); ::encode(new_last_clean_interval, bl); ::encode(new_lost, bl); ::encode(new_blacklist, bl); ::encode(old_blacklist, bl); ::encode(new_up_cluster, bl); ::encode(cluster_snapshot, bl); ::encode(new_uuid, bl); ::encode(new_xinfo, bl); ::encode(new_hb_front_up, bl); ::encode(features, bl); // NOTE: features arg, not the member ENCODE_FINISH(bl); // osd-only data } ENCODE_FINISH(bl); // meta-encoding wrapper } void OSDMap::Incremental::decode_classic(bufferlist::iterator &p) { __u32 n, t; // base __u16 v; ::decode(v, p); ::decode(fsid, p); ::decode(epoch, p); ::decode(modified, p); if (v == 4 || v == 5) { ::decode(n, p); new_pool_max = n; } else if (v >= 6) ::decode(new_pool_max, p); ::decode(new_flags, p); ::decode(fullmap, p); ::decode(crush, p); ::decode(new_max_osd, p); if (v < 6) { new_pools.clear(); ::decode(n, p); while (n--) { ::decode(t, p); ::decode(new_pools[t], p); } } else { ::decode(new_pools, p); } if (v == 5) { new_pool_names.clear(); ::decode(n, p); while (n--) { ::decode(t, p); ::decode(new_pool_names[t], p); } } else if (v >= 6) { ::decode(new_pool_names, p); } if (v < 6) { old_pools.clear(); ::decode(n, p); while (n--) { ::decode(t, p); old_pools.insert(t); } } else { ::decode(old_pools, p); } ::decode(new_up_client, p); ::decode(new_state, p); ::decode(new_weight, p); if (v < 6) { new_pg_temp.clear(); ::decode(n, p); while (n--) { old_pg_t opg; ::decode_raw(opg, p); ::decode(new_pg_temp[pg_t(opg)], p); } } else { ::decode(new_pg_temp, p); } // decode short map, too. if (v == 5 && p.end()) return; // extended __u16 ev = 0; if (v >= 5) ::decode(ev, p); ::decode(new_hb_back_up, p); if (v < 5) ::decode(new_pool_names, p); ::decode(new_up_thru, p); ::decode(new_last_clean_interval, p); ::decode(new_lost, p); ::decode(new_blacklist, p); ::decode(old_blacklist, p); if (ev >= 6) ::decode(new_up_cluster, p); if (ev >= 7) ::decode(cluster_snapshot, p); if (ev >= 8) ::decode(new_uuid, p); if (ev >= 9) ::decode(new_xinfo, p); if (ev >= 10) ::decode(new_hb_front_up, p); } void OSDMap::Incremental::decode(bufferlist::iterator& bl) { /** * Older encodings of the Incremental had a single struct_v which * covered the whole encoding, and was prior to our modern * stuff which includes a compatv and a size. So if we see * a struct_v < 7, we must rewind to the beginning and use our * classic decoder. */ DECODE_START_LEGACY_COMPAT_LEN(7, 7, 7, bl); // wrapper if (struct_v < 7) { int struct_v_size = sizeof(struct_v); bl.advance(-struct_v_size); decode_classic(bl); encode_features = 0; return; } { DECODE_START(3, bl); // client-usable data ::decode(fsid, bl); ::decode(epoch, bl); ::decode(modified, bl); ::decode(new_pool_max, bl); ::decode(new_flags, bl); ::decode(fullmap, bl); ::decode(crush, bl); ::decode(new_max_osd, bl); ::decode(new_pools, bl); ::decode(new_pool_names, bl); ::decode(old_pools, bl); ::decode(new_up_client, bl); ::decode(new_state, bl); ::decode(new_weight, bl); ::decode(new_pg_temp, bl); ::decode(new_primary_temp, bl); if (struct_v >= 2) ::decode(new_primary_affinity, bl); else new_primary_affinity.clear(); if (struct_v >= 3) { ::decode(new_erasure_code_profiles, bl); ::decode(old_erasure_code_profiles, bl); } else { new_erasure_code_profiles.clear(); old_erasure_code_profiles.clear(); } DECODE_FINISH(bl); // client-usable data } { DECODE_START(2, bl); // extended, osd-only data ::decode(new_hb_back_up, bl); ::decode(new_up_thru, bl); ::decode(new_last_clean_interval, bl); ::decode(new_lost, bl); ::decode(new_blacklist, bl); ::decode(old_blacklist, bl); ::decode(new_up_cluster, bl); ::decode(cluster_snapshot, bl); ::decode(new_uuid, bl); ::decode(new_xinfo, bl); ::decode(new_hb_front_up, bl); if (struct_v >= 2) ::decode(encode_features, bl); else encode_features = 0; DECODE_FINISH(bl); // osd-only data } DECODE_FINISH(bl); // wrapper } void OSDMap::Incremental::dump(Formatter *f) const { f->dump_int("epoch", epoch); f->dump_stream("fsid") << fsid; f->dump_stream("modified") << modified; f->dump_int("new_pool_max", new_pool_max); f->dump_int("new_flags", new_flags); if (fullmap.length()) { f->open_object_section("full_map"); OSDMap full; bufferlist fbl = fullmap; // kludge around constness. bufferlist::iterator p = fbl.begin(); full.decode(p); full.dump(f); f->close_section(); } if (crush.length()) { f->open_object_section("crush"); CrushWrapper c; bufferlist tbl = crush; // kludge around constness. bufferlist::iterator p = tbl.begin(); c.decode(p); c.dump(f); f->close_section(); } f->dump_int("new_max_osd", new_max_osd); f->open_array_section("new_pools"); for (map::const_iterator p = new_pools.begin(); p != new_pools.end(); ++p) { f->open_object_section("pool"); f->dump_int("pool", p->first); p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("new_pool_names"); for (map::const_iterator p = new_pool_names.begin(); p != new_pool_names.end(); ++p) { f->open_object_section("pool_name"); f->dump_int("pool", p->first); f->dump_string("name", p->second); f->close_section(); } f->close_section(); f->open_array_section("old_pools"); for (set::const_iterator p = old_pools.begin(); p != old_pools.end(); ++p) f->dump_int("pool", *p); f->close_section(); f->open_array_section("new_up_osds"); for (map::const_iterator p = new_up_client.begin(); p != new_up_client.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); f->dump_stream("public_addr") << p->second; f->dump_stream("cluster_addr") << new_up_cluster.find(p->first)->second; f->dump_stream("heartbeat_back_addr") << new_hb_back_up.find(p->first)->second; map::const_iterator q; if ((q = new_hb_front_up.find(p->first)) != new_hb_front_up.end()) f->dump_stream("heartbeat_front_addr") << q->second; f->close_section(); } f->close_section(); f->open_array_section("new_weight"); for (map::const_iterator p = new_weight.begin(); p != new_weight.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); f->dump_int("weight", p->second); f->close_section(); } f->close_section(); f->open_array_section("osd_state_xor"); for (map::const_iterator p = new_state.begin(); p != new_state.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); set st; calc_state_set(new_state.find(p->first)->second, st); f->open_array_section("state_xor"); for (set::iterator p = st.begin(); p != st.end(); ++p) f->dump_string("state", *p); f->close_section(); } f->close_section(); f->open_array_section("new_pg_temp"); for (map >::const_iterator p = new_pg_temp.begin(); p != new_pg_temp.end(); ++p) { f->open_object_section("pg"); f->dump_stream("pgid") << p->first; f->open_array_section("osds"); for (vector::const_iterator q = p->second.begin(); q != p->second.end(); ++q) f->dump_int("osd", *q); f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("primary_temp"); for (map::const_iterator p = new_primary_temp.begin(); p != new_primary_temp.end(); ++p) { f->dump_stream("pgid") << p->first; f->dump_int("osd", p->second); } f->close_section(); // primary_temp f->open_array_section("new_up_thru"); for (map::const_iterator p = new_up_thru.begin(); p != new_up_thru.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); f->dump_int("up_thru", p->second); f->close_section(); } f->close_section(); f->open_array_section("new_lost"); for (map::const_iterator p = new_lost.begin(); p != new_lost.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); f->dump_int("epoch_lost", p->second); f->close_section(); } f->close_section(); f->open_array_section("new_last_clean_interval"); for (map >::const_iterator p = new_last_clean_interval.begin(); p != new_last_clean_interval.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); f->dump_int("first", p->second.first); f->dump_int("last", p->second.second); f->close_section(); } f->close_section(); f->open_array_section("new_blacklist"); for (map::const_iterator p = new_blacklist.begin(); p != new_blacklist.end(); ++p) { stringstream ss; ss << p->first; f->dump_stream(ss.str().c_str()) << p->second; } f->close_section(); f->open_array_section("old_blacklist"); for (vector::const_iterator p = old_blacklist.begin(); p != old_blacklist.end(); ++p) f->dump_stream("addr") << *p; f->close_section(); f->open_array_section("new_xinfo"); for (map::const_iterator p = new_xinfo.begin(); p != new_xinfo.end(); ++p) { f->open_object_section("xinfo"); f->dump_int("osd", p->first); p->second.dump(f); f->close_section(); } f->close_section(); if (cluster_snapshot.size()) f->dump_string("cluster_snapshot", cluster_snapshot); f->open_array_section("new_uuid"); for (map::const_iterator p = new_uuid.begin(); p != new_uuid.end(); ++p) { f->open_object_section("osd"); f->dump_int("osd", p->first); f->dump_stream("uuid") << p->second; f->close_section(); } f->close_section(); OSDMap::dump_erasure_code_profiles(new_erasure_code_profiles, f); f->open_array_section("old_erasure_code_profiles"); for (vector::const_iterator p = old_erasure_code_profiles.begin(); p != old_erasure_code_profiles.end(); p++) { f->dump_string("old", p->c_str()); } f->close_section(); } void OSDMap::Incremental::generate_test_instances(list& o) { o.push_back(new Incremental); } // ---------------------------------- // OSDMap void OSDMap::set_epoch(epoch_t e) { epoch = e; for (map::iterator p = pools.begin(); p != pools.end(); ++p) p->second.last_change = e; } bool OSDMap::is_blacklisted(const entity_addr_t& a) const { if (blacklist.empty()) return false; // this specific instance? if (blacklist.count(a)) return true; // is entire ip blacklisted? if (a.is_ip()) { entity_addr_t b = a; b.set_port(0); b.set_nonce(0); if (blacklist.count(b)) { return true; } } return false; } void OSDMap::get_blacklist(list > *bl) const { for (ceph::unordered_map::const_iterator it = blacklist.begin() ; it != blacklist.end(); ++it) { bl->push_back(*it); } } void OSDMap::set_max_osd(int m) { int o = max_osd; max_osd = m; osd_state.resize(m); osd_weight.resize(m); for (; oclient_addr.resize(m); osd_addrs->cluster_addr.resize(m); osd_addrs->hb_back_addr.resize(m); osd_addrs->hb_front_addr.resize(m); osd_uuid->resize(m); if (osd_primary_affinity) osd_primary_affinity->resize(m, CEPH_OSD_DEFAULT_PRIMARY_AFFINITY); calc_num_osds(); } int OSDMap::calc_num_osds() { num_osd = 0; for (int i=0; i& ls) const { for (int i=0; i& ls) const { for (int i = 0; i < max_osd; i++) { if (is_up(i)) ls.insert(i); } } unsigned OSDMap::get_num_up_osds() const { unsigned n = 0; for (int i=0; i& st) { unsigned t = state; for (unsigned s = 1; t; s <<= 1) { if (t & s) { t &= ~s; st.insert(ceph_osd_state_name(s)); } } } void OSDMap::adjust_osd_weights(const map& weights, Incremental& inc) const { float max = 0; for (map::const_iterator p = weights.begin(); p != weights.end(); ++p) { if (p->second > max) max = p->second; } for (map::const_iterator p = weights.begin(); p != weights.end(); ++p) { inc.new_weight[p->first] = (unsigned)((p->second / max) * CEPH_OSD_IN); } } int OSDMap::identify_osd(const entity_addr_t& addr) const { for (int i=0; ihas_nondefault_tunables()) features |= CEPH_FEATURE_CRUSH_TUNABLES; if (crush->has_nondefault_tunables2()) features |= CEPH_FEATURE_CRUSH_TUNABLES2; if (crush->has_nondefault_tunables3()) features |= CEPH_FEATURE_CRUSH_TUNABLES3; mask |= CEPH_FEATURES_CRUSH; for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { if (p->second.flags & pg_pool_t::FLAG_HASHPSPOOL) { features |= CEPH_FEATURE_OSDHASHPSPOOL; } if (p->second.is_erasure() && entity_type != CEPH_ENTITY_TYPE_CLIENT) { // not for clients features |= CEPH_FEATURE_OSD_ERASURE_CODES; } if (!p->second.tiers.empty() || p->second.is_tier()) { features |= CEPH_FEATURE_OSD_CACHEPOOL; } int ruleid = crush->find_rule(p->second.get_crush_ruleset(), p->second.get_type(), p->second.get_size()); if (ruleid >= 0) { if (crush->is_v2_rule(ruleid)) features |= CEPH_FEATURE_CRUSH_V2; if (crush->is_v3_rule(ruleid)) features |= CEPH_FEATURE_CRUSH_TUNABLES3; } } mask |= CEPH_FEATURE_OSDHASHPSPOOL | CEPH_FEATURE_OSD_CACHEPOOL; if (entity_type != CEPH_ENTITY_TYPE_CLIENT) mask |= CEPH_FEATURE_OSD_ERASURE_CODES; if (osd_primary_affinity) { for (int i = 0; i < max_osd; ++i) { if ((*osd_primary_affinity)[i] != CEPH_OSD_DEFAULT_PRIMARY_AFFINITY) { features |= CEPH_FEATURE_OSD_PRIMARY_AFFINITY; break; } } } mask |= CEPH_FEATURE_OSD_PRIMARY_AFFINITY; if (pmask) *pmask = mask; return features; } uint64_t OSDMap::get_up_osd_features() const { bool first = true; uint64_t features = 0; for (int osd = 0; osd < max_osd; ++osd) { if (!is_up(osd)) continue; const osd_xinfo_t &xi = get_xinfo(osd); if (first) { features = xi.features; first = false; } else { features &= xi.features; } } return features; } void OSDMap::dedup(const OSDMap *o, OSDMap *n) { if (o->epoch == n->epoch) return; int diff = 0; // do addrs match? if (o->max_osd != n->max_osd) diff++; for (int i = 0; i < o->max_osd && i < n->max_osd; i++) { if ( n->osd_addrs->client_addr[i] && o->osd_addrs->client_addr[i] && *n->osd_addrs->client_addr[i] == *o->osd_addrs->client_addr[i]) n->osd_addrs->client_addr[i] = o->osd_addrs->client_addr[i]; else diff++; if ( n->osd_addrs->cluster_addr[i] && o->osd_addrs->cluster_addr[i] && *n->osd_addrs->cluster_addr[i] == *o->osd_addrs->cluster_addr[i]) n->osd_addrs->cluster_addr[i] = o->osd_addrs->cluster_addr[i]; else diff++; if ( n->osd_addrs->hb_back_addr[i] && o->osd_addrs->hb_back_addr[i] && *n->osd_addrs->hb_back_addr[i] == *o->osd_addrs->hb_back_addr[i]) n->osd_addrs->hb_back_addr[i] = o->osd_addrs->hb_back_addr[i]; else diff++; if ( n->osd_addrs->hb_front_addr[i] && o->osd_addrs->hb_front_addr[i] && *n->osd_addrs->hb_front_addr[i] == *o->osd_addrs->hb_front_addr[i]) n->osd_addrs->hb_front_addr[i] = o->osd_addrs->hb_front_addr[i]; else diff++; } if (diff == 0) { // zoinks, no differences at all! n->osd_addrs = o->osd_addrs; } // does crush match? bufferlist oc, nc; ::encode(*o->crush, oc); ::encode(*n->crush, nc); if (oc.contents_equal(nc)) { n->crush = o->crush; } // does pg_temp match? if (o->pg_temp->size() == n->pg_temp->size()) { if (*o->pg_temp == *n->pg_temp) n->pg_temp = o->pg_temp; } // does primary_temp match? if (o->primary_temp->size() == n->primary_temp->size()) { if (*o->primary_temp == *n->primary_temp) n->primary_temp = o->primary_temp; } // do uuids match? if (o->osd_uuid->size() == n->osd_uuid->size() && *o->osd_uuid == *n->osd_uuid) n->osd_uuid = o->osd_uuid; } void OSDMap::remove_redundant_temporaries(CephContext *cct, const OSDMap& osdmap, OSDMap::Incremental *pending_inc) { ldout(cct, 10) << "remove_redundant_temporaries" << dendl; for (map >::iterator p = osdmap.pg_temp->begin(); p != osdmap.pg_temp->end(); ++p) { if (pending_inc->new_pg_temp.count(p->first) == 0) { vector raw_up; int primary; osdmap.pg_to_raw_up(p->first, &raw_up, &primary); if (raw_up == p->second) { ldout(cct, 10) << " removing unnecessary pg_temp " << p->first << " -> " << p->second << dendl; pending_inc->new_pg_temp[p->first].clear(); } } } if (!osdmap.primary_temp->empty()) { OSDMap templess; templess.deepish_copy_from(osdmap); templess.primary_temp->clear(); for (map::iterator p = osdmap.primary_temp->begin(); p != osdmap.primary_temp->end(); ++p) { if (pending_inc->new_primary_temp.count(p->first) == 0) { vector real_up, templess_up; int real_primary, templess_primary; osdmap.pg_to_acting_osds(p->first, &real_up, &real_primary); templess.pg_to_acting_osds(p->first, &templess_up, &templess_primary); if (real_primary == templess_primary){ ldout(cct, 10) << " removing unnecessary primary_temp " << p->first << " -> " << p->second << dendl; pending_inc->new_primary_temp[p->first] = -1; } } } } } void OSDMap::remove_down_temps(CephContext *cct, const OSDMap& osdmap, Incremental *pending_inc) { ldout(cct, 10) << "remove_down_pg_temp" << dendl; OSDMap tmpmap; tmpmap.deepish_copy_from(osdmap); tmpmap.apply_incremental(*pending_inc); for (map >::iterator p = tmpmap.pg_temp->begin(); p != tmpmap.pg_temp->end(); ++p) { unsigned num_up = 0; for (vector::iterator i = p->second.begin(); i != p->second.end(); ++i) { if (!tmpmap.is_down(*i)) ++num_up; } if (num_up == 0) pending_inc->new_pg_temp[p->first].clear(); } for (map::iterator p = tmpmap.primary_temp->begin(); p != tmpmap.primary_temp->end(); ++p) { if (tmpmap.is_down(p->second)) pending_inc->new_primary_temp[p->first] = -1; } } int OSDMap::apply_incremental(const Incremental &inc) { new_blacklist_entries = false; if (inc.epoch == 1) fsid = inc.fsid; else if (inc.fsid != fsid) return -EINVAL; assert(inc.epoch == epoch+1); epoch++; modified = inc.modified; // full map? if (inc.fullmap.length()) { bufferlist bl(inc.fullmap); decode(bl); return 0; } // nope, incremental. if (inc.new_flags >= 0) flags = inc.new_flags; if (inc.new_max_osd >= 0) set_max_osd(inc.new_max_osd); if (inc.new_pool_max != -1) pool_max = inc.new_pool_max; for (map::const_iterator p = inc.new_pools.begin(); p != inc.new_pools.end(); ++p) { pools[p->first] = p->second; pools[p->first].last_change = epoch; } for (map::const_iterator p = inc.new_pool_names.begin(); p != inc.new_pool_names.end(); ++p) { if (pool_name.count(p->first)) name_pool.erase(pool_name[p->first]); pool_name[p->first] = p->second; name_pool[p->second] = p->first; } for (set::const_iterator p = inc.old_pools.begin(); p != inc.old_pools.end(); ++p) { pools.erase(*p); name_pool.erase(pool_name[*p]); pool_name.erase(*p); } for (map::const_iterator i = inc.new_weight.begin(); i != inc.new_weight.end(); ++i) { set_weight(i->first, i->second); // if we are marking in, clear the AUTOOUT and NEW bits. if (i->second) osd_state[i->first] &= ~(CEPH_OSD_AUTOOUT | CEPH_OSD_NEW); } for (map::const_iterator i = inc.new_primary_affinity.begin(); i != inc.new_primary_affinity.end(); ++i) { set_primary_affinity(i->first, i->second); } // erasure_code_profiles for (vector::const_iterator i = inc.old_erasure_code_profiles.begin(); i != inc.old_erasure_code_profiles.end(); ++i) erasure_code_profiles.erase(*i); for (map >::const_iterator i = inc.new_erasure_code_profiles.begin(); i != inc.new_erasure_code_profiles.end(); i++) { set_erasure_code_profile(i->first, i->second); } // up/down for (map::const_iterator i = inc.new_state.begin(); i != inc.new_state.end(); ++i) { int s = i->second ? i->second : CEPH_OSD_UP; if ((osd_state[i->first] & CEPH_OSD_UP) && (s & CEPH_OSD_UP)) { osd_info[i->first].down_at = epoch; osd_xinfo[i->first].down_stamp = modified; } if ((osd_state[i->first] & CEPH_OSD_EXISTS) && (s & CEPH_OSD_EXISTS)) (*osd_uuid)[i->first] = uuid_d(); osd_state[i->first] ^= s; } for (map::const_iterator i = inc.new_up_client.begin(); i != inc.new_up_client.end(); ++i) { osd_state[i->first] |= CEPH_OSD_EXISTS | CEPH_OSD_UP; osd_addrs->client_addr[i->first].reset(new entity_addr_t(i->second)); if (inc.new_hb_back_up.empty()) osd_addrs->hb_back_addr[i->first].reset(new entity_addr_t(i->second)); //this is a backward-compatibility hack else osd_addrs->hb_back_addr[i->first].reset( new entity_addr_t(inc.new_hb_back_up.find(i->first)->second)); map::const_iterator j = inc.new_hb_front_up.find(i->first); if (j != inc.new_hb_front_up.end()) osd_addrs->hb_front_addr[i->first].reset(new entity_addr_t(j->second)); else osd_addrs->hb_front_addr[i->first].reset(); osd_info[i->first].up_from = epoch; } for (map::const_iterator i = inc.new_up_cluster.begin(); i != inc.new_up_cluster.end(); ++i) osd_addrs->cluster_addr[i->first].reset(new entity_addr_t(i->second)); // info for (map::const_iterator i = inc.new_up_thru.begin(); i != inc.new_up_thru.end(); ++i) osd_info[i->first].up_thru = i->second; for (map >::const_iterator i = inc.new_last_clean_interval.begin(); i != inc.new_last_clean_interval.end(); ++i) { osd_info[i->first].last_clean_begin = i->second.first; osd_info[i->first].last_clean_end = i->second.second; } for (map::const_iterator p = inc.new_lost.begin(); p != inc.new_lost.end(); ++p) osd_info[p->first].lost_at = p->second; // xinfo for (map::const_iterator p = inc.new_xinfo.begin(); p != inc.new_xinfo.end(); ++p) osd_xinfo[p->first] = p->second; // uuid for (map::const_iterator p = inc.new_uuid.begin(); p != inc.new_uuid.end(); ++p) (*osd_uuid)[p->first] = p->second; // pg rebuild for (map >::const_iterator p = inc.new_pg_temp.begin(); p != inc.new_pg_temp.end(); ++p) { if (p->second.empty()) pg_temp->erase(p->first); else (*pg_temp)[p->first] = p->second; } for (map::const_iterator p = inc.new_primary_temp.begin(); p != inc.new_primary_temp.end(); ++p) { if (p->second == -1) primary_temp->erase(p->first); else (*primary_temp)[p->first] = p->second; } // blacklist for (map::const_iterator p = inc.new_blacklist.begin(); p != inc.new_blacklist.end(); ++p) { blacklist[p->first] = p->second; new_blacklist_entries = true; } for (vector::const_iterator p = inc.old_blacklist.begin(); p != inc.old_blacklist.end(); ++p) blacklist.erase(*p); // cluster snapshot? if (inc.cluster_snapshot.length()) { cluster_snapshot = inc.cluster_snapshot; cluster_snapshot_epoch = inc.epoch; } else { cluster_snapshot.clear(); cluster_snapshot_epoch = 0; } // do new crush map last (after up/down stuff) if (inc.crush.length()) { bufferlist bl(inc.crush); bufferlist::iterator blp = bl.begin(); crush.reset(new CrushWrapper); crush->decode(blp); } calc_num_osds(); return 0; } // mapping int OSDMap::object_locator_to_pg( const object_t& oid, const object_locator_t& loc, pg_t &pg) const { // calculate ps (placement seed) const pg_pool_t *pool = get_pg_pool(loc.get_pool()); if (!pool) return -ENOENT; ps_t ps; if (loc.hash >= 0) { ps = loc.hash; } else { if (!loc.key.empty()) ps = pool->hash_key(loc.key, loc.nspace); else ps = pool->hash_key(oid.name, loc.nspace); } pg = pg_t(ps, loc.get_pool(), -1); return 0; } ceph_object_layout OSDMap::make_object_layout( object_t oid, int pg_pool, string nspace) const { object_locator_t loc(pg_pool, nspace); ceph_object_layout ol; pg_t pgid = object_locator_to_pg(oid, loc); ol.ol_pgid = pgid.get_old_pg().v; ol.ol_stripe_unit = 0; return ol; } void OSDMap::_remove_nonexistent_osds(const pg_pool_t& pool, vector& osds) const { if (pool.can_shift_osds()) { unsigned removed = 0; for (unsigned i = 0; i < osds.size(); i++) { if (!exists(osds[i])) { removed++; continue; } if (removed) { osds[i - removed] = osds[i]; } } if (removed) osds.resize(osds.size() - removed); } else { for (vector::iterator p = osds.begin(); p != osds.end(); ++p) { if (!exists(*p)) *p = CRUSH_ITEM_NONE; } } } int OSDMap::_pg_to_osds(const pg_pool_t& pool, pg_t pg, vector *osds, int *primary, ps_t *ppps) const { // map to osds[] ps_t pps = pool.raw_pg_to_pps(pg); // placement ps unsigned size = pool.get_size(); // what crush rule? int ruleno = crush->find_rule(pool.get_crush_ruleset(), pool.get_type(), size); if (ruleno >= 0) crush->do_rule(ruleno, pps, *osds, size, osd_weight); _remove_nonexistent_osds(pool, *osds); *primary = -1; for (unsigned i = 0; i < osds->size(); ++i) { if ((*osds)[i] != CRUSH_ITEM_NONE) { *primary = (*osds)[i]; break; } } if (ppps) *ppps = pps; return osds->size(); } // pg -> (up osd list) void OSDMap::_raw_to_up_osds(const pg_pool_t& pool, const vector& raw, vector *up, int *primary) const { if (pool.can_shift_osds()) { // shift left up->clear(); for (unsigned i=0; ipush_back(raw[i]); } *primary = (up->empty() ? -1 : up->front()); } else { // set down/dne devices to NONE *primary = -1; up->resize(raw.size()); for (int i = raw.size() - 1; i >= 0; --i) { if (!exists(raw[i]) || is_down(raw[i])) { (*up)[i] = CRUSH_ITEM_NONE; } else { *primary = (*up)[i] = raw[i]; } } } } void OSDMap::_apply_primary_affinity(ps_t seed, const pg_pool_t& pool, vector *osds, int *primary) const { // do we have any non-default primary_affinity values for these osds? if (!osd_primary_affinity) return; bool any = false; for (vector::const_iterator p = osds->begin(); p != osds->end(); ++p) { if (*p != CRUSH_ITEM_NONE && (*osd_primary_affinity)[*p] != CEPH_OSD_DEFAULT_PRIMARY_AFFINITY) { any = true; } } if (!any) return; // pick the primary. feed both the seed (for the pg) and the osd // into the hash/rng so that a proportional fraction of an osd's pgs // get rejected as primary. int pos = -1; for (unsigned i = 0; i < osds->size(); ++i) { int o = (*osds)[i]; if (o == CRUSH_ITEM_NONE) continue; unsigned a = (*osd_primary_affinity)[o]; if (a < CEPH_OSD_MAX_PRIMARY_AFFINITY && (crush_hash32_2(CRUSH_HASH_RJENKINS1, seed, o) >> 16) >= a) { // we chose not to use this primary. note it anyway as a // fallback in case we don't pick anyone else, but keep looking. if (pos < 0) pos = i; } else { pos = i; break; } } if (pos < 0) return; *primary = (*osds)[pos]; if (pool.can_shift_osds() && pos > 0) { // move the new primary to the front. for (int i = pos; i > 0; --i) { (*osds)[i] = (*osds)[i-1]; } (*osds)[0] = *primary; } } void OSDMap::_get_temp_osds(const pg_pool_t& pool, pg_t pg, vector *temp_pg, int *temp_primary) const { pg = pool.raw_pg_to_pg(pg); map >::const_iterator p = pg_temp->find(pg); temp_pg->clear(); if (p != pg_temp->end()) { for (unsigned i=0; isecond.size(); i++) { if (!exists(p->second[i]) || is_down(p->second[i])) { if (pool.can_shift_osds()) { continue; } else { temp_pg->push_back(CRUSH_ITEM_NONE); } } else { temp_pg->push_back(p->second[i]); } } } map::const_iterator pp = primary_temp->find(pg); *temp_primary = -1; if (pp != primary_temp->end()) { *temp_primary = pp->second; } else if (!temp_pg->empty()) { // apply pg_temp's primary for (unsigned i = 0; i < temp_pg->size(); ++i) { if ((*temp_pg)[i] != CRUSH_ITEM_NONE) { *temp_primary = (*temp_pg)[i]; break; } } } } int OSDMap::pg_to_osds(pg_t pg, vector *raw, int *primary) const { *primary = -1; raw->clear(); const pg_pool_t *pool = get_pg_pool(pg.pool()); if (!pool) return 0; int r = _pg_to_osds(*pool, pg, raw, primary, NULL); return r; } void OSDMap::pg_to_raw_up(pg_t pg, vector *up, int *primary) const { const pg_pool_t *pool = get_pg_pool(pg.pool()); if (!pool) { if (primary) *primary = -1; if (up) up->clear(); return; } vector raw; ps_t pps; _pg_to_osds(*pool, pg, &raw, primary, &pps); _raw_to_up_osds(*pool, raw, up, primary); _apply_primary_affinity(pps, *pool, up, primary); } void OSDMap::_pg_to_up_acting_osds(pg_t pg, vector *up, int *up_primary, vector *acting, int *acting_primary) const { const pg_pool_t *pool = get_pg_pool(pg.pool()); if (!pool) { if (up) up->clear(); if (up_primary) *up_primary = -1; if (acting) acting->clear(); if (acting_primary) *acting_primary = -1; return; } vector raw; vector _up; vector _acting; int _up_primary; int _acting_primary; ps_t pps; _pg_to_osds(*pool, pg, &raw, &_up_primary, &pps); _raw_to_up_osds(*pool, raw, &_up, &_up_primary); _apply_primary_affinity(pps, *pool, &_up, &_up_primary); _get_temp_osds(*pool, pg, &_acting, &_acting_primary); if (_acting.empty()) { _acting = _up; if (_acting_primary == -1) { _acting_primary = _up_primary; } } if (up) up->swap(_up); if (up_primary) *up_primary = _up_primary; if (acting) acting->swap(_acting); if (acting_primary) *acting_primary = _acting_primary; } int OSDMap::calc_pg_rank(int osd, const vector& acting, int nrep) { if (!nrep) nrep = acting.size(); for (int i=0; i& acting, int nrep) { if (!nrep) nrep = acting.size(); return calc_pg_rank(osd, acting, nrep); } bool OSDMap::primary_changed( int oldprimary, const vector &oldacting, int newprimary, const vector &newacting) { if (oldacting.empty() && newacting.empty()) return false; // both still empty if (oldacting.empty() ^ newacting.empty()) return true; // was empty, now not, or vice versa if (oldprimary != newprimary) return true; // primary changed if (calc_pg_rank(oldprimary, oldacting) != calc_pg_rank(newprimary, newacting)) return true; return false; // same primary (tho replicas may have changed) } // serialize, unserialize void OSDMap::encode_client_old(bufferlist& bl) const { __u16 v = 5; ::encode(v, bl); // base ::encode(fsid, bl); ::encode(epoch, bl); ::encode(created, bl); ::encode(modified, bl); // for ::encode(pools, bl); __u32 n = pools.size(); ::encode(n, bl); for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { n = p->first; ::encode(n, bl); ::encode(p->second, bl, 0); } // for ::encode(pool_name, bl); n = pool_name.size(); ::encode(n, bl); for (map::const_iterator p = pool_name.begin(); p != pool_name.end(); ++p) { n = p->first; ::encode(n, bl); ::encode(p->second, bl); } // for ::encode(pool_max, bl); n = pool_max; ::encode(n, bl); ::encode(flags, bl); ::encode(max_osd, bl); ::encode(osd_state, bl); ::encode(osd_weight, bl); ::encode(osd_addrs->client_addr, bl); // for ::encode(pg_temp, bl); n = pg_temp->size(); ::encode(n, bl); for (map >::const_iterator p = pg_temp->begin(); p != pg_temp->end(); ++p) { old_pg_t opg = p->first.get_old_pg(); ::encode(opg, bl); ::encode(p->second, bl); } // crush bufferlist cbl; crush->encode(cbl); ::encode(cbl, bl); } void OSDMap::encode_classic(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_PGID64) == 0) { encode_client_old(bl); return; } __u16 v = 6; ::encode(v, bl); // base ::encode(fsid, bl); ::encode(epoch, bl); ::encode(created, bl); ::encode(modified, bl); ::encode(pools, bl, features); ::encode(pool_name, bl); ::encode(pool_max, bl); ::encode(flags, bl); ::encode(max_osd, bl); ::encode(osd_state, bl); ::encode(osd_weight, bl); ::encode(osd_addrs->client_addr, bl); ::encode(*pg_temp, bl); // crush bufferlist cbl; crush->encode(cbl); ::encode(cbl, bl); // extended __u16 ev = 10; ::encode(ev, bl); ::encode(osd_addrs->hb_back_addr, bl); ::encode(osd_info, bl); ::encode(blacklist, bl); ::encode(osd_addrs->cluster_addr, bl); ::encode(cluster_snapshot_epoch, bl); ::encode(cluster_snapshot, bl); ::encode(*osd_uuid, bl); ::encode(osd_xinfo, bl); ::encode(osd_addrs->hb_front_addr, bl); } void OSDMap::encode(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_OSDMAP_ENC) == 0) { encode_classic(bl, features); return; } // meta-encoding: how we include client-used and osd-specific data ENCODE_START(7, 7, bl); { ENCODE_START(3, 1, bl); // client-usable data // base ::encode(fsid, bl); ::encode(epoch, bl); ::encode(created, bl); ::encode(modified, bl); ::encode(pools, bl, features); ::encode(pool_name, bl); ::encode(pool_max, bl); ::encode(flags, bl); ::encode(max_osd, bl); ::encode(osd_state, bl); ::encode(osd_weight, bl); ::encode(osd_addrs->client_addr, bl); ::encode(*pg_temp, bl); ::encode(*primary_temp, bl); if (osd_primary_affinity) { ::encode(*osd_primary_affinity, bl); } else { vector<__u32> v; ::encode(v, bl); } // crush bufferlist cbl; crush->encode(cbl); ::encode(cbl, bl); ::encode(erasure_code_profiles, bl); ENCODE_FINISH(bl); // client-usable data } { ENCODE_START(1, 1, bl); // extended, osd-only data ::encode(osd_addrs->hb_back_addr, bl); ::encode(osd_info, bl); { // put this in a sorted, ordered map<> so that we encode in a // deterministic order. map blacklist_map; for (ceph::unordered_map::const_iterator p = blacklist.begin(); p != blacklist.end(); ++p) blacklist_map.insert(make_pair(p->first, p->second)); ::encode(blacklist_map, bl); } ::encode(osd_addrs->cluster_addr, bl); ::encode(cluster_snapshot_epoch, bl); ::encode(cluster_snapshot, bl); ::encode(*osd_uuid, bl); ::encode(osd_xinfo, bl); ::encode(osd_addrs->hb_front_addr, bl); ENCODE_FINISH(bl); // osd-only data } ENCODE_FINISH(bl); // meta-encoding wrapper } void OSDMap::decode(bufferlist& bl) { bufferlist::iterator p = bl.begin(); decode(p); } void OSDMap::decode_classic(bufferlist::iterator& p) { __u32 n, t; __u16 v; ::decode(v, p); // base ::decode(fsid, p); ::decode(epoch, p); ::decode(created, p); ::decode(modified, p); if (v < 6) { if (v < 4) { int32_t max_pools = 0; ::decode(max_pools, p); pool_max = max_pools; } pools.clear(); ::decode(n, p); while (n--) { ::decode(t, p); ::decode(pools[t], p); } if (v == 4) { ::decode(n, p); pool_max = n; } else if (v == 5) { pool_name.clear(); ::decode(n, p); while (n--) { ::decode(t, p); ::decode(pool_name[t], p); } ::decode(n, p); pool_max = n; } } else { ::decode(pools, p); ::decode(pool_name, p); ::decode(pool_max, p); } // kludge around some old bug that zeroed out pool_max (#2307) if (pools.size() && pool_max < pools.rbegin()->first) { pool_max = pools.rbegin()->first; } ::decode(flags, p); ::decode(max_osd, p); ::decode(osd_state, p); ::decode(osd_weight, p); ::decode(osd_addrs->client_addr, p); if (v <= 5) { pg_temp->clear(); ::decode(n, p); while (n--) { old_pg_t opg; ::decode_raw(opg, p); ::decode((*pg_temp)[pg_t(opg)], p); } } else { ::decode(*pg_temp, p); } // crush bufferlist cbl; ::decode(cbl, p); bufferlist::iterator cblp = cbl.begin(); crush->decode(cblp); // extended __u16 ev = 0; if (v >= 5) ::decode(ev, p); ::decode(osd_addrs->hb_back_addr, p); ::decode(osd_info, p); if (v < 5) ::decode(pool_name, p); ::decode(blacklist, p); if (ev >= 6) ::decode(osd_addrs->cluster_addr, p); else osd_addrs->cluster_addr.resize(osd_addrs->client_addr.size()); if (ev >= 7) { ::decode(cluster_snapshot_epoch, p); ::decode(cluster_snapshot, p); } if (ev >= 8) { ::decode(*osd_uuid, p); } else { osd_uuid->resize(max_osd); } if (ev >= 9) ::decode(osd_xinfo, p); else osd_xinfo.resize(max_osd); if (ev >= 10) ::decode(osd_addrs->hb_front_addr, p); else osd_addrs->hb_front_addr.resize(osd_addrs->hb_back_addr.size()); osd_primary_affinity.reset(); post_decode(); } void OSDMap::decode(bufferlist::iterator& bl) { /** * Older encodings of the OSDMap had a single struct_v which * covered the whole encoding, and was prior to our modern * stuff which includes a compatv and a size. So if we see * a struct_v < 7, we must rewind to the beginning and use our * classic decoder. */ DECODE_START_LEGACY_COMPAT_LEN(7, 7, 7, bl); // wrapper if (struct_v < 7) { int struct_v_size = sizeof(struct_v); bl.advance(-struct_v_size); decode_classic(bl); return; } /** * Since we made it past that hurdle, we can use our normal paths. */ { DECODE_START(3, bl); // client-usable data // base ::decode(fsid, bl); ::decode(epoch, bl); ::decode(created, bl); ::decode(modified, bl); ::decode(pools, bl); ::decode(pool_name, bl); ::decode(pool_max, bl); ::decode(flags, bl); ::decode(max_osd, bl); ::decode(osd_state, bl); ::decode(osd_weight, bl); ::decode(osd_addrs->client_addr, bl); ::decode(*pg_temp, bl); ::decode(*primary_temp, bl); if (struct_v >= 2) { osd_primary_affinity.reset(new vector<__u32>); ::decode(*osd_primary_affinity, bl); if (osd_primary_affinity->empty()) osd_primary_affinity.reset(); } else { osd_primary_affinity.reset(); } // crush bufferlist cbl; ::decode(cbl, bl); bufferlist::iterator cblp = cbl.begin(); crush->decode(cblp); if (struct_v >= 3) { ::decode(erasure_code_profiles, bl); } else { erasure_code_profiles.clear(); } DECODE_FINISH(bl); // client-usable data } { DECODE_START(1, bl); // extended, osd-only data ::decode(osd_addrs->hb_back_addr, bl); ::decode(osd_info, bl); ::decode(blacklist, bl); ::decode(osd_addrs->cluster_addr, bl); ::decode(cluster_snapshot_epoch, bl); ::decode(cluster_snapshot, bl); ::decode(*osd_uuid, bl); ::decode(osd_xinfo, bl); ::decode(osd_addrs->hb_front_addr, bl); DECODE_FINISH(bl); // osd-only data } DECODE_FINISH(bl); // wrapper post_decode(); } void OSDMap::post_decode() { // index pool names name_pool.clear(); for (map::iterator i = pool_name.begin(); i != pool_name.end(); ++i) { name_pool[i->second] = i->first; } calc_num_osds(); } void OSDMap::dump_erasure_code_profiles(const map > &profiles, Formatter *f) { f->open_object_section("erasure_code_profiles"); for (map >::const_iterator i = profiles.begin(); i != profiles.end(); i++) { f->open_object_section(i->first.c_str()); for (map::const_iterator j = i->second.begin(); j != i->second.end(); j++) { f->dump_string(j->first.c_str(), j->second.c_str()); } f->close_section(); } f->close_section(); } void OSDMap::dump_json(ostream& out) const { JSONFormatter jsf(true); jsf.open_object_section("osdmap"); dump(&jsf); jsf.close_section(); jsf.flush(out); } void OSDMap::dump(Formatter *f) const { f->dump_int("epoch", get_epoch()); f->dump_stream("fsid") << get_fsid(); f->dump_stream("created") << get_created(); f->dump_stream("modified") << get_modified(); f->dump_string("flags", get_flag_string()); f->dump_string("cluster_snapshot", get_cluster_snapshot()); f->dump_int("pool_max", get_pool_max()); f->dump_int("max_osd", get_max_osd()); f->open_array_section("pools"); for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { std::string name(""); map::const_iterator pni = pool_name.find(p->first); if (pni != pool_name.end()) name = pni->second; f->open_object_section("pool"); f->dump_int("pool", p->first); f->dump_string("pool_name", name); p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("osds"); for (int i=0; iopen_object_section("osd_info"); f->dump_int("osd", i); f->dump_stream("uuid") << get_uuid(i); f->dump_int("up", is_up(i)); f->dump_int("in", is_in(i)); f->dump_float("weight", get_weightf(i)); f->dump_float("primary_affinity", get_primary_affinityf(i)); get_info(i).dump(f); f->dump_stream("public_addr") << get_addr(i); f->dump_stream("cluster_addr") << get_cluster_addr(i); f->dump_stream("heartbeat_back_addr") << get_hb_back_addr(i); f->dump_stream("heartbeat_front_addr") << get_hb_front_addr(i); set st; get_state(i, st); f->open_array_section("state"); for (set::iterator p = st.begin(); p != st.end(); ++p) f->dump_string("state", *p); f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("osd_xinfo"); for (int i=0; iopen_object_section("xinfo"); f->dump_int("osd", i); osd_xinfo[i].dump(f); f->close_section(); } } f->close_section(); f->open_array_section("pg_temp"); for (map >::const_iterator p = pg_temp->begin(); p != pg_temp->end(); ++p) { f->open_object_section("osds"); f->dump_stream("pgid") << p->first; f->open_array_section("osds"); for (vector::const_iterator q = p->second.begin(); q != p->second.end(); ++q) f->dump_int("osd", *q); f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("primary_temp"); for (map::const_iterator p = primary_temp->begin(); p != primary_temp->end(); ++p) { f->dump_stream("pgid") << p->first; f->dump_int("osd", p->second); } f->close_section(); // primary_temp f->open_array_section("blacklist"); for (ceph::unordered_map::const_iterator p = blacklist.begin(); p != blacklist.end(); ++p) { stringstream ss; ss << p->first; f->dump_stream(ss.str().c_str()) << p->second; } f->close_section(); dump_erasure_code_profiles(erasure_code_profiles, f); } void OSDMap::generate_test_instances(list& o) { o.push_back(new OSDMap); CephContext *cct = new CephContext(CODE_ENVIRONMENT_UTILITY); o.push_back(new OSDMap); uuid_d fsid; o.back()->build_simple(cct, 1, fsid, 16, 7, 8); o.back()->created = o.back()->modified = utime_t(1, 2); // fix timestamp o.back()->blacklist[entity_addr_t()] = utime_t(5, 6); cct->put(); } string OSDMap::get_flag_string(unsigned f) { string s; if ( f& CEPH_OSDMAP_NEARFULL) s += ",nearfull"; if (f & CEPH_OSDMAP_FULL) s += ",full"; if (f & CEPH_OSDMAP_PAUSERD) s += ",pauserd"; if (f & CEPH_OSDMAP_PAUSEWR) s += ",pausewr"; if (f & CEPH_OSDMAP_PAUSEREC) s += ",pauserec"; if (f & CEPH_OSDMAP_NOUP) s += ",noup"; if (f & CEPH_OSDMAP_NODOWN) s += ",nodown"; if (f & CEPH_OSDMAP_NOOUT) s += ",noout"; if (f & CEPH_OSDMAP_NOIN) s += ",noin"; if (f & CEPH_OSDMAP_NOBACKFILL) s += ",nobackfill"; if (f & CEPH_OSDMAP_NORECOVER) s += ",norecover"; if (f & CEPH_OSDMAP_NOSCRUB) s += ",noscrub"; if (f & CEPH_OSDMAP_NODEEP_SCRUB) s += ",nodeep-scrub"; if (f & CEPH_OSDMAP_NOTIERAGENT) s += ",notieragent"; if (s.length()) s = s.erase(0, 1); return s; } string OSDMap::get_flag_string() const { return get_flag_string(flags); } struct qi { int item; int depth; float weight; qi() : item(0), depth(0), weight(0) {} qi(int i, int d, float w) : item(i), depth(d), weight(w) {} }; void OSDMap::print(ostream& out) const { out << "epoch " << get_epoch() << "\n" << "fsid " << get_fsid() << "\n" << "created " << get_created() << "\n" << "modified " << get_modified() << "\n"; out << "flags " << get_flag_string() << "\n"; if (get_cluster_snapshot().length()) out << "cluster_snapshot " << get_cluster_snapshot() << "\n"; out << "\n"; for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { std::string name(""); map::const_iterator pni = pool_name.find(p->first); if (pni != pool_name.end()) name = pni->second; out << "pool " << p->first << " '" << name << "' " << p->second << "\n"; for (map::const_iterator q = p->second.snaps.begin(); q != p->second.snaps.end(); ++q) out << "\tsnap " << q->second.snapid << " '" << q->second.name << "' " << q->second.stamp << "\n"; if (!p->second.removed_snaps.empty()) out << "\tremoved_snaps " << p->second.removed_snaps << "\n"; } out << std::endl; out << "max_osd " << get_max_osd() << "\n"; for (int i=0; i st; get_state(i, st); out << " " << st; if (!get_uuid(i).is_zero()) out << " " << get_uuid(i); out << "\n"; } } out << std::endl; for (map >::const_iterator p = pg_temp->begin(); p != pg_temp->end(); ++p) out << "pg_temp " << p->first << " " << p->second << "\n"; for (map::const_iterator p = primary_temp->begin(); p != primary_temp->end(); ++p) out << "primary_temp " << p->first << " " << p->second << "\n"; for (ceph::unordered_map::const_iterator p = blacklist.begin(); p != blacklist.end(); ++p) out << "blacklist " << p->first << " expires " << p->second << "\n"; // ignore pg_swap_primary } void OSDMap::print_osd_line(int cur, ostream *out, Formatter *f) const { if (f) { f->dump_unsigned("id", cur); f->dump_stream("name") << "osd." << cur; f->dump_unsigned("exists", (int)exists(cur)); f->dump_string("type", crush->get_type_name(0)); f->dump_int("type_id", 0); } if (out) *out << "osd." << cur << "\t"; if (!exists(cur)) { if (out) *out << "DNE\t\t"; } else { if (is_up(cur)) { if (out) *out << "up\t"; if (f) f->dump_string("status", "up"); } else { if (out) *out << "down\t"; if (f) f->dump_string("status", "down"); } if (out) { std::streamsize p = out->precision(); *out << std::setprecision(4) << (exists(cur) ? get_weightf(cur) : 0) << std::setprecision(p) << "\t"; } if (f) { f->dump_float("reweight", get_weightf(cur)); } } } void OSDMap::print_tree(ostream *out, Formatter *f) const { if (out) *out << "# id\tweight\ttype name\tup/down\treweight\n"; if (f) f->open_array_section("nodes"); set touched; set roots; crush->find_roots(roots); for (set::iterator p = roots.begin(); p != roots.end(); ++p) { list q; q.push_back(qi(*p, 0, crush->get_bucket_weight(*p) / (float)0x10000)); while (!q.empty()) { int cur = q.front().item; int depth = q.front().depth; float weight = q.front().weight; q.pop_front(); if (out) { *out << cur << "\t"; int oldprecision = out->precision(); *out << std::setprecision(4) << weight << std::setprecision(oldprecision) << "\t"; for (int k=0; kopen_object_section("item"); } if (cur >= 0) { print_osd_line(cur, out, f); if (out) *out << "\n"; if (f) { f->dump_float("crush_weight", weight); f->dump_unsigned("depth", depth); f->close_section(); } touched.insert(cur); } if (cur >= 0) { continue; } // queue bucket contents... int type = crush->get_bucket_type(cur); int s = crush->get_bucket_size(cur); if (f) { f->dump_int("id", cur); f->dump_string("name", crush->get_item_name(cur)); f->dump_string("type", crush->get_type_name(type)); f->dump_int("type_id", type); f->open_array_section("children"); } for (int k=s-1; k>=0; k--) { int item = crush->get_bucket_item(cur, k); q.push_front(qi(item, depth+1, (float)crush->get_bucket_item_weight(cur, k) / (float)0x10000)); if (f) f->dump_int("child", item); } if (f) f->close_section(); if (out) *out << crush->get_type_name(type) << " " << crush->get_item_name(cur) << "\n"; if (f) { f->close_section(); } } } if (f) { f->close_section(); f->open_array_section("stray"); } set stray; for (int i=0; iopen_object_section("osd"); for (set::iterator p = stray.begin(); p != stray.end(); ++p) { if (out) *out << *p << "\t0\t"; print_osd_line(*p, out, f); if (out) *out << "\n"; } if (f) f->close_section(); } if (f) f->close_section(); } void OSDMap::print_summary(Formatter *f, ostream& out) const { if (f) { f->open_object_section("osdmap"); f->dump_int("epoch", get_epoch()); f->dump_int("num_osds", get_num_osds()); f->dump_int("num_up_osds", get_num_up_osds()); f->dump_int("num_in_osds", get_num_in_osds()); f->dump_bool("full", test_flag(CEPH_OSDMAP_FULL) ? true : false); f->dump_bool("nearfull", test_flag(CEPH_OSDMAP_NEARFULL) ? true : false); f->close_section(); } else { out << " osdmap e" << get_epoch() << ": " << get_num_osds() << " osds: " << get_num_up_osds() << " up, " << get_num_in_osds() << " in\n"; if (flags) out << " flags " << get_flag_string() << "\n"; } } void OSDMap::print_oneline_summary(ostream& out) const { out << "e" << get_epoch() << ": " << get_num_osds() << " osds: " << get_num_up_osds() << " up, " << get_num_in_osds() << " in"; if (test_flag(CEPH_OSDMAP_FULL)) out << " full"; else if (test_flag(CEPH_OSDMAP_NEARFULL)) out << " nearfull"; } bool OSDMap::crush_ruleset_in_use(int ruleset) const { for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { if (p->second.crush_ruleset == ruleset) return true; } return false; } int OSDMap::build_simple(CephContext *cct, epoch_t e, uuid_d &fsid, int nosd, int pg_bits, int pgp_bits) { ldout(cct, 10) << "build_simple on " << num_osd << " osds with " << pg_bits << " pg bits per osd, " << dendl; epoch = e; set_fsid(fsid); created = modified = ceph_clock_now(cct); if (nosd >= 0) { set_max_osd(nosd); } else { // count osds int maxosd = 0, numosd = 0; const md_config_t *conf = cct->_conf; vector sections; conf->get_all_sections(sections); for (vector::iterator i = sections.begin(); i != sections.end(); ++i) { if (i->find("osd.") != 0) continue; const char *begin = i->c_str() + 4; char *end = (char*)begin; int o = strtol(begin, &end, 10); if (*end != '\0') continue; if (o > cct->_conf->mon_max_osd) { lderr(cct) << "[osd." << o << "] in config has id > mon_max_osd " << cct->_conf->mon_max_osd << dendl; return -ERANGE; } numosd++; if (o > maxosd) maxosd = o; } set_max_osd(maxosd + 1); } // pgp_num <= pg_num if (pgp_bits > pg_bits) pgp_bits = pg_bits; vector pool_names; pool_names.push_back("data"); pool_names.push_back("metadata"); pool_names.push_back("rbd"); stringstream ss; int r; if (nosd >= 0) r = build_simple_crush_map(cct, *crush, nosd, &ss); else r = build_simple_crush_map_from_conf(cct, *crush, &ss); int poolbase = get_max_osd() ? get_max_osd() : 1; int const default_replicated_ruleset = crush->get_osd_pool_default_crush_replicated_ruleset(cct); assert(default_replicated_ruleset >= 0); for (vector::iterator p = pool_names.begin(); p != pool_names.end(); ++p) { int64_t pool = ++pool_max; pools[pool].type = pg_pool_t::TYPE_REPLICATED; pools[pool].flags = cct->_conf->osd_pool_default_flags; if (cct->_conf->osd_pool_default_flag_hashpspool) pools[pool].flags |= pg_pool_t::FLAG_HASHPSPOOL; pools[pool].size = cct->_conf->osd_pool_default_size; pools[pool].min_size = cct->_conf->get_osd_pool_default_min_size(); pools[pool].crush_ruleset = default_replicated_ruleset; pools[pool].object_hash = CEPH_STR_HASH_RJENKINS; pools[pool].set_pg_num(poolbase << pg_bits); pools[pool].set_pgp_num(poolbase << pgp_bits); pools[pool].last_change = epoch; if (*p == "data") pools[pool].crash_replay_interval = cct->_conf->osd_default_data_pool_replay_window; pool_name[pool] = *p; name_pool[*p] = pool; } if (r < 0) lderr(cct) << ss.str() << dendl; for (int i=0; i profile_map; r = get_erasure_code_profile_default(cct, profile_map, &ss); if (r < 0) { lderr(cct) << ss.str() << dendl; return r; } set_erasure_code_profile("default", profile_map); return 0; } int OSDMap::get_erasure_code_profile_default(CephContext *cct, map &profile_map, ostream *ss) { int r = get_str_map(cct->_conf->osd_pool_default_erasure_code_profile, *ss, &profile_map); profile_map["directory"] = cct->_conf->osd_pool_default_erasure_code_directory; return r; } int OSDMap::_build_crush_types(CrushWrapper& crush) { crush.set_type_name(0, "osd"); crush.set_type_name(1, "host"); crush.set_type_name(2, "chassis"); crush.set_type_name(3, "rack"); crush.set_type_name(4, "row"); crush.set_type_name(5, "pdu"); crush.set_type_name(6, "pod"); crush.set_type_name(7, "room"); crush.set_type_name(8, "datacenter"); crush.set_type_name(9, "region"); crush.set_type_name(10, "root"); return 10; } int OSDMap::build_simple_crush_map(CephContext *cct, CrushWrapper& crush, int nosd, ostream *ss) { crush.create(); // root int root_type = _build_crush_types(crush); int rootid; int r = crush.add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_DEFAULT, root_type, 0, NULL, NULL, &rootid); assert(r == 0); crush.set_item_name(rootid, "default"); for (int o=0; o loc; loc["host"] = "localhost"; loc["rack"] = "localrack"; loc["root"] = "default"; ldout(cct, 10) << " adding osd." << o << " at " << loc << dendl; char name[8]; sprintf(name, "osd.%d", o); crush.insert_item(cct, o, 1.0, name, loc); } build_simple_crush_rulesets(cct, crush, "default", ss); crush.finalize(); return 0; } int OSDMap::build_simple_crush_map_from_conf(CephContext *cct, CrushWrapper& crush, ostream *ss) { const md_config_t *conf = cct->_conf; crush.create(); set hosts, racks; // root int root_type = _build_crush_types(crush); int rootid; int r = crush.add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_DEFAULT, root_type, 0, NULL, NULL, &rootid); assert(r == 0); crush.set_item_name(rootid, "default"); // add osds vector sections; conf->get_all_sections(sections); for (vector::iterator i = sections.begin(); i != sections.end(); ++i) { if (i->find("osd.") != 0) continue; const char *begin = i->c_str() + 4; char *end = (char*)begin; int o = strtol(begin, &end, 10); if (*end != '\0') continue; string host, rack, row, room, dc, pool; vector sections; sections.push_back("osd"); sections.push_back(*i); conf->get_val_from_conf_file(sections, "host", host, false); conf->get_val_from_conf_file(sections, "rack", rack, false); conf->get_val_from_conf_file(sections, "row", row, false); conf->get_val_from_conf_file(sections, "room", room, false); conf->get_val_from_conf_file(sections, "datacenter", dc, false); conf->get_val_from_conf_file(sections, "root", pool, false); if (host.length() == 0) host = "unknownhost"; if (rack.length() == 0) rack = "unknownrack"; hosts.insert(host); racks.insert(rack); map loc; loc["host"] = host; loc["rack"] = rack; if (row.size()) loc["row"] = row; if (room.size()) loc["room"] = room; if (dc.size()) loc["datacenter"] = dc; loc["root"] = "default"; ldout(cct, 5) << " adding osd." << o << " at " << loc << dendl; crush.insert_item(cct, o, 1.0, *i, loc); } build_simple_crush_rulesets(cct, crush, "default", ss); crush.finalize(); return 0; } int OSDMap::build_simple_crush_rulesets(CephContext *cct, CrushWrapper& crush, const string& root, ostream *ss) { string failure_domain = crush.get_type_name(cct->_conf->osd_crush_chooseleaf_type); int r; r = crush.add_simple_ruleset("replicated_ruleset", root, failure_domain, "firstn", pg_pool_t::TYPE_REPLICATED, ss); if (r < 0) return r; // do not add an erasure rule by default or else we will implicitly // require the crush_v2 feature of clients return 0; } ceph-0.80.11/src/osd/Ager.h0000664000175100017510000000213712623076744017303 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_AGER_H #define CEPH_AGER_H #include "include/types.h" #include "include/Distribution.h" #include "os/ObjectStore.h" #include "common/Clock.h" #include "common/ceph_context.h" #include #include using namespace std; class Ager { CephContext *cct; ObjectStore *store; private: list age_free_oids; file_object_t age_cur_oid; vector< list > age_objects; Distribution file_size_distn; //kb bool did_distn; void age_empty(float pc); uint64_t age_fill(float pc, utime_t until); ssize_t age_pick_size(); file_object_t age_get_oid(); public: Ager(CephContext *cct_, ObjectStore *s) : cct(cct_), store(s), did_distn(false) {} void age(int time, float high_water, // fill to this % float low_water, // then empty to this % int count, // this many times float final_water, // and end here ( <= low_water) int fake_size_mb=0); }; #endif ceph-0.80.11/src/osd/ECUtil.h0000664000175100017510000001120612623076744017547 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef ECUTIL_H #define ECUTIL_H #include #include #include "include/memory.h" #include "erasure-code/ErasureCodeInterface.h" #include "include/buffer.h" #include "include/assert.h" #include "include/encoding.h" #include "common/Formatter.h" namespace ECUtil { const uint64_t CHUNK_ALIGNMENT = 64; const uint64_t CHUNK_INFO = 8; const uint64_t CHUNK_PADDING = 8; const uint64_t CHUNK_OVERHEAD = 16; // INFO + PADDING class stripe_info_t { const uint64_t stripe_size; const uint64_t stripe_width; const uint64_t chunk_size; public: stripe_info_t(uint64_t stripe_size, uint64_t stripe_width) : stripe_size(stripe_size), stripe_width(stripe_width), chunk_size(stripe_width / stripe_size) { assert(stripe_width % stripe_size == 0); } uint64_t get_stripe_width() const { return stripe_width; } uint64_t get_chunk_size() const { return chunk_size; } uint64_t logical_to_prev_chunk_offset(uint64_t offset) const { return (offset / stripe_width) * chunk_size; } uint64_t logical_to_next_chunk_offset(uint64_t offset) const { return ((offset + stripe_width - 1)/ stripe_width) * chunk_size; } uint64_t logical_to_prev_stripe_offset(uint64_t offset) const { return offset - (offset % stripe_width); } uint64_t logical_to_next_stripe_offset(uint64_t offset) const { return offset % stripe_width ? offset - (offset % stripe_width) + stripe_width : offset; } uint64_t aligned_logical_offset_to_chunk_offset(uint64_t offset) const { assert(offset % stripe_width == 0); return (offset / stripe_width) * chunk_size; } uint64_t aligned_chunk_offset_to_logical_offset(uint64_t offset) const { assert(offset % chunk_size == 0); return (offset / chunk_size) * stripe_width; } pair aligned_offset_len_to_chunk( pair in) const { return make_pair( aligned_logical_offset_to_chunk_offset(in.first), aligned_logical_offset_to_chunk_offset(in.second)); } pair offset_len_to_stripe_bounds( pair in) const { uint64_t off = logical_to_prev_stripe_offset(in.first); uint64_t len = logical_to_next_stripe_offset( (in.first - off) + in.second); return make_pair(off, len); } }; int decode( const stripe_info_t &sinfo, ErasureCodeInterfaceRef &ec_impl, map &to_decode, bufferlist *out); int decode( const stripe_info_t &sinfo, ErasureCodeInterfaceRef &ec_impl, map &to_decode, map &out); int encode( const stripe_info_t &sinfo, ErasureCodeInterfaceRef &ec_impl, bufferlist &in, const set &want, map *out); class HashInfo { uint64_t total_chunk_size; vector cumulative_shard_hashes; public: HashInfo() : total_chunk_size(0) {} HashInfo(unsigned num_chunks) : total_chunk_size(0), cumulative_shard_hashes(num_chunks, -1) {} void append(uint64_t old_size, map &to_append) { assert(to_append.size() == cumulative_shard_hashes.size()); assert(old_size == total_chunk_size); uint64_t size_to_append = to_append.begin()->second.length(); for (map::iterator i = to_append.begin(); i != to_append.end(); ++i) { assert(size_to_append == i->second.length()); assert((unsigned)i->first < cumulative_shard_hashes.size()); uint32_t new_hash = i->second.crc32c(cumulative_shard_hashes[i->first]); cumulative_shard_hashes[i->first] = new_hash; } total_chunk_size += size_to_append; } void clear() { total_chunk_size = 0; cumulative_shard_hashes = vector( cumulative_shard_hashes.size(), -1); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); uint32_t get_chunk_hash(int shard) const { assert((unsigned)shard < cumulative_shard_hashes.size()); return cumulative_shard_hashes[shard]; } uint64_t get_total_chunk_size() const { return total_chunk_size; } }; typedef ceph::shared_ptr HashInfoRef; bool is_hinfo_key_string(const string &key); const string &get_hinfo_key(); }; WRITE_CLASS_ENCODER(ECUtil::HashInfo) #endif ceph-0.80.11/src/osd/ECMsgTypes.cc0000664000175100017510000002315512623076744020551 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "ECMsgTypes.h" void ECSubWrite::encode(bufferlist &bl) const { ENCODE_START(3, 1, bl); ::encode(from, bl); ::encode(tid, bl); ::encode(reqid, bl); ::encode(soid, bl); ::encode(stats, bl); ::encode(t, bl); ::encode(at_version, bl); ::encode(trim_to, bl); ::encode(log_entries, bl); ::encode(temp_added, bl); ::encode(temp_removed, bl); ::encode(updated_hit_set_history, bl); ::encode(trim_rollback_to, bl); ENCODE_FINISH(bl); } void ECSubWrite::decode(bufferlist::iterator &bl) { DECODE_START(3, bl); ::decode(from, bl); ::decode(tid, bl); ::decode(reqid, bl); ::decode(soid, bl); ::decode(stats, bl); ::decode(t, bl); ::decode(at_version, bl); ::decode(trim_to, bl); ::decode(log_entries, bl); ::decode(temp_added, bl); ::decode(temp_removed, bl); if (struct_v >= 2) { ::decode(updated_hit_set_history, bl); } if (struct_v >= 3) { ::decode(trim_rollback_to, bl); } else { trim_rollback_to = trim_to; } DECODE_FINISH(bl); } std::ostream &operator<<( std::ostream &lhs, const ECSubWrite &rhs) { lhs << "ECSubWrite(tid=" << rhs.tid << ", reqid=" << rhs.reqid << ", at_version=" << rhs.at_version << ", trim_to=" << rhs.trim_to << ", trim_rollback_to=" << rhs.trim_rollback_to; if (rhs.updated_hit_set_history) lhs << ", has_updated_hit_set_history"; return lhs << ")"; } void ECSubWrite::dump(Formatter *f) const { f->dump_unsigned("tid", tid); f->dump_stream("reqid") << reqid; f->dump_stream("at_version") << at_version; f->dump_stream("trim_to") << trim_to; f->dump_stream("trim_rollback_to") << trim_rollback_to; f->dump_stream("has_updated_hit_set_history") << static_cast(updated_hit_set_history); } void ECSubWrite::generate_test_instances(list &o) { o.push_back(new ECSubWrite()); o.back()->tid = 1; o.back()->at_version = eversion_t(2, 100); o.back()->trim_to = eversion_t(1, 40); o.push_back(new ECSubWrite()); o.back()->tid = 4; o.back()->reqid = osd_reqid_t(entity_name_t::CLIENT(123), 1, 45678); o.back()->at_version = eversion_t(10, 300); o.back()->trim_to = eversion_t(5, 42); o.push_back(new ECSubWrite()); o.back()->tid = 9; o.back()->reqid = osd_reqid_t(entity_name_t::CLIENT(123), 1, 45678); o.back()->at_version = eversion_t(10, 300); o.back()->trim_to = eversion_t(5, 42); o.back()->trim_rollback_to = eversion_t(8, 250); } void ECSubWriteReply::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(from, bl); ::encode(tid, bl); ::encode(last_complete, bl); ::encode(committed, bl); ::encode(applied, bl); ENCODE_FINISH(bl); } void ECSubWriteReply::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(from, bl); ::decode(tid, bl); ::decode(last_complete, bl); ::decode(committed, bl); ::decode(applied, bl); DECODE_FINISH(bl); } std::ostream &operator<<( std::ostream &lhs, const ECSubWriteReply &rhs) { return lhs << "ECSubWriteReply(tid=" << rhs.tid << ", last_complete=" << rhs.last_complete << ", committed=" << rhs.committed << ", applied=" << rhs.applied << ")"; } void ECSubWriteReply::dump(Formatter *f) const { f->dump_unsigned("tid", tid); f->dump_stream("last_complete") << last_complete; f->dump_stream("committed") << committed; f->dump_stream("applied") << applied; } void ECSubWriteReply::generate_test_instances(list& o) { o.push_back(new ECSubWriteReply()); o.back()->tid = 20; o.back()->last_complete = eversion_t(100, 2000); o.back()->committed = true; o.push_back(new ECSubWriteReply()); o.back()->tid = 80; o.back()->last_complete = eversion_t(50, 200); o.back()->applied = true; } void ECSubRead::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(from, bl); ::encode(tid, bl); ::encode(to_read, bl); ::encode(attrs_to_read, bl); ENCODE_FINISH(bl); } void ECSubRead::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(from, bl); ::decode(tid, bl); ::decode(to_read, bl); ::decode(attrs_to_read, bl); DECODE_FINISH(bl); } std::ostream &operator<<( std::ostream &lhs, const ECSubRead &rhs) { return lhs << "ECSubRead(tid=" << rhs.tid << ", to_read=" << rhs.to_read << ", attrs_to_read=" << rhs.attrs_to_read << ")"; } void ECSubRead::dump(Formatter *f) const { f->dump_stream("from") << from; f->dump_unsigned("tid", tid); f->open_array_section("objects"); for (map > >::const_iterator i = to_read.begin(); i != to_read.end(); ++i) { f->open_object_section("object"); f->dump_stream("oid") << i->first; f->open_array_section("extents"); for (list >::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { f->open_object_section("extent"); f->dump_unsigned("off", j->first); f->dump_unsigned("len", j->second); f->close_section(); } f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("object_attrs_requested"); for (set::const_iterator i = attrs_to_read.begin(); i != attrs_to_read.end(); ++i) { f->open_object_section("object"); f->dump_stream("oid") << *i; f->close_section(); } f->close_section(); } void ECSubRead::generate_test_instances(list& o) { hobject_t hoid1(sobject_t("asdf", 1)); hobject_t hoid2(sobject_t("asdf2", CEPH_NOSNAP)); o.push_back(new ECSubRead()); o.back()->from = pg_shard_t(2, 255); o.back()->tid = 1; o.back()->to_read[hoid1].push_back(make_pair(100, 200)); o.back()->to_read[hoid1].push_back(make_pair(400, 600)); o.back()->to_read[hoid2].push_back(make_pair(400, 600)); o.back()->attrs_to_read.insert(hoid1); o.push_back(new ECSubRead()); o.back()->from = pg_shard_t(2, 255); o.back()->tid = 300; o.back()->to_read[hoid1].push_back(make_pair(300, 200)); o.back()->to_read[hoid2].push_back(make_pair(400, 600)); o.back()->to_read[hoid2].push_back(make_pair(2000, 600)); o.back()->attrs_to_read.insert(hoid2); } void ECSubReadReply::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(from, bl); ::encode(tid, bl); ::encode(buffers_read, bl); ::encode(attrs_read, bl); ::encode(errors, bl); ENCODE_FINISH(bl); } void ECSubReadReply::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(from, bl); ::decode(tid, bl); ::decode(buffers_read, bl); ::decode(attrs_read, bl); ::decode(errors, bl); DECODE_FINISH(bl); } std::ostream &operator<<( std::ostream &lhs, const ECSubReadReply &rhs) { return lhs << "ECSubReadReply(tid=" << rhs.tid << ", attrs_read=" << rhs.attrs_read.size() << ")"; } void ECSubReadReply::dump(Formatter *f) const { f->dump_stream("from") << from; f->dump_unsigned("tid", tid); f->open_array_section("buffers_read"); for (map > >::const_iterator i = buffers_read.begin(); i != buffers_read.end(); ++i) { f->open_object_section("object"); f->dump_stream("oid") << i->first; f->open_array_section("data"); for (list >::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { f->open_object_section("extent"); f->dump_unsigned("off", j->first); f->dump_unsigned("buf_len", j->second.length()); f->close_section(); } f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("attrs_returned"); for (map >::const_iterator i = attrs_read.begin(); i != attrs_read.end(); ++i) { f->open_object_section("object_attrs"); f->dump_stream("oid") << i->first; f->open_array_section("attrs"); for (map::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { f->open_object_section("attr"); f->dump_string("attr", j->first); f->dump_unsigned("val_len", j->second.length()); f->close_section(); } f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("errors"); for (map::const_iterator i = errors.begin(); i != errors.end(); ++i) { f->open_object_section("error_pair"); f->dump_stream("oid") << i->first; f->dump_int("error", i->second); f->close_section(); } f->close_section(); } void ECSubReadReply::generate_test_instances(list& o) { hobject_t hoid1(sobject_t("asdf", 1)); hobject_t hoid2(sobject_t("asdf2", CEPH_NOSNAP)); bufferlist bl; bl.append_zero(100); bufferlist bl2; bl2.append_zero(200); o.push_back(new ECSubReadReply()); o.back()->from = pg_shard_t(2, 255); o.back()->tid = 1; o.back()->buffers_read[hoid1].push_back(make_pair(20, bl)); o.back()->buffers_read[hoid1].push_back(make_pair(2000, bl2)); o.back()->buffers_read[hoid2].push_back(make_pair(0, bl)); o.back()->attrs_read[hoid1]["foo"] = bl; o.back()->attrs_read[hoid1]["_"] = bl2; o.push_back(new ECSubReadReply()); o.back()->from = pg_shard_t(2, 255); o.back()->tid = 300; o.back()->buffers_read[hoid2].push_back(make_pair(0, bl2)); o.back()->attrs_read[hoid2]["foo"] = bl; o.back()->attrs_read[hoid2]["_"] = bl2; o.back()->errors[hoid1] = -2; } ceph-0.80.11/src/osd/ReplicatedPG.cc0000664000175100017510000131402612623076744021072 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "boost/tuple/tuple.hpp" #include "PG.h" #include "ReplicatedPG.h" #include "OSD.h" #include "OpRequest.h" #include "common/errno.h" #include "common/perf_counters.h" #include "messages/MOSDOp.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDSubOp.h" #include "messages/MOSDSubOpReply.h" #include "messages/MOSDPGNotify.h" #include "messages/MOSDPGInfo.h" #include "messages/MOSDPGRemove.h" #include "messages/MOSDPGTrim.h" #include "messages/MOSDPGScan.h" #include "messages/MOSDPGBackfill.h" #include "messages/MOSDPing.h" #include "messages/MWatchNotify.h" #include "messages/MOSDPGPush.h" #include "messages/MOSDPGPull.h" #include "messages/MOSDPGPushReply.h" #include "Watch.h" #include "mds/inode_backtrace.h" // Ugh #include "common/config.h" #include "include/compat.h" #include "common/cmdparse.h" #include "mon/MonClient.h" #include "osdc/Objecter.h" #include "json_spirit/json_spirit_value.h" #include "json_spirit/json_spirit_reader.h" #include "include/assert.h" // json_spirit clobbers it #define dout_subsys ceph_subsys_osd #define DOUT_PREFIX_ARGS this, osd->whoami, get_osdmap() #undef dout_prefix #define dout_prefix _prefix(_dout, this) template static ostream& _prefix(std::ostream *_dout, T *pg) { return *_dout << pg->gen_prefix(); } #include #include #include PGLSFilter::PGLSFilter() { } PGLSFilter::~PGLSFilter() { } static void log_subop_stats( PerfCounters *logger, OpRequestRef op, int tag_inb, int tag_lat) { utime_t now = ceph_clock_now(g_ceph_context); utime_t latency = now; latency -= op->get_req()->get_recv_stamp(); uint64_t inb = op->get_req()->get_data().length(); logger->inc(l_osd_sop); logger->inc(l_osd_sop_inb, inb); logger->tinc(l_osd_sop_lat, latency); if (tag_inb) logger->inc(tag_inb, inb); logger->tinc(tag_lat, latency); } struct OnReadComplete : public Context { ReplicatedPG *pg; ReplicatedPG::OpContext *opcontext; OnReadComplete( ReplicatedPG *pg, ReplicatedPG::OpContext *ctx) : pg(pg), opcontext(ctx) {} void finish(int r) { if (r < 0) opcontext->async_read_result = r; opcontext->finish_read(pg); } ~OnReadComplete() {} }; // OpContext void ReplicatedPG::OpContext::start_async_reads(ReplicatedPG *pg) { inflightreads = 1; pg->pgbackend->objects_read_async( obc->obs.oi.soid, pending_async_reads, new OnReadComplete(pg, this)); pending_async_reads.clear(); } void ReplicatedPG::OpContext::finish_read(ReplicatedPG *pg) { assert(inflightreads > 0); --inflightreads; if (async_reads_complete()) { assert(pg->in_progress_async_reads.size()); assert(pg->in_progress_async_reads.front().second == this); pg->in_progress_async_reads.pop_front(); pg->complete_read_ctx(async_read_result, this); } } class CopyFromCallback: public ReplicatedPG::CopyCallback { public: ReplicatedPG::CopyResults *results; int retval; ReplicatedPG::OpContext *ctx; CopyFromCallback(ReplicatedPG::OpContext *ctx_) : results(NULL), retval(0), ctx(ctx_) {} ~CopyFromCallback() {} virtual void finish(ReplicatedPG::CopyCallbackResults results_) { results = results_.get<1>(); int r = results_.get<0>(); retval = r; // for finish_copyfrom ctx->user_at_version = results->user_version; if (r >= 0) { ctx->pg->execute_ctx(ctx); } ctx->copy_cb = NULL; if (r < 0) { if (r != -ECANCELED) { // on cancel just toss it out; client resends if (ctx->op) ctx->pg->osd->reply_op_error(ctx->op, r); } else if (results->should_requeue) { if (ctx->op) ctx->pg->requeue_op(ctx->op); } ctx->pg->close_op_ctx(ctx, r); } } bool is_temp_obj_used() { return results->started_temp_obj; } uint64_t get_data_size() { return results->object_size; } int get_result() { return retval; } }; // ====================== // PGBackend::Listener void ReplicatedPG::on_local_recover_start( const hobject_t &oid, ObjectStore::Transaction *t) { pg_log.revise_have(oid, eversion_t()); remove_snap_mapped_object(*t, oid); } void ReplicatedPG::on_local_recover( const hobject_t &hoid, const object_stat_sum_t &stat_diff, const ObjectRecoveryInfo &_recovery_info, ObjectContextRef obc, ObjectStore::Transaction *t ) { dout(10) << __func__ << ": " << hoid << dendl; ObjectRecoveryInfo recovery_info(_recovery_info); if (recovery_info.soid.snap < CEPH_NOSNAP) { assert(recovery_info.oi.snaps.size()); OSDriver::OSTransaction _t(osdriver.get_transaction(t)); set snaps( recovery_info.oi.snaps.begin(), recovery_info.oi.snaps.end()); snap_mapper.add_oid( recovery_info.soid, snaps, &_t); } if (pg_log.get_missing().is_missing(recovery_info.soid) && pg_log.get_missing().missing.find(recovery_info.soid)->second.need > recovery_info.version) { assert(is_primary()); const pg_log_entry_t *latest = pg_log.get_log().objects.find(recovery_info.soid)->second; if (latest->op == pg_log_entry_t::LOST_REVERT && latest->reverting_to == recovery_info.version) { dout(10) << " got old revert version " << recovery_info.version << " for " << *latest << dendl; recovery_info.version = latest->version; // update the attr to the revert event version recovery_info.oi.prior_version = recovery_info.oi.version; recovery_info.oi.version = latest->version; bufferlist bl; ::encode(recovery_info.oi, bl); t->setattr(coll, recovery_info.soid, OI_ATTR, bl); if (obc) obc->attr_cache[OI_ATTR] = bl; } } // keep track of active pushes for scrub ++active_pushes; recover_got(recovery_info.soid, recovery_info.version); if (is_primary()) { info.stats.stats.sum.add(stat_diff); assert(obc); obc->obs.exists = true; obc->ondisk_write_lock(); obc->obs.oi = recovery_info.oi; // may have been updated above t->register_on_applied(new C_OSD_AppliedRecoveredObject(this, obc)); t->register_on_applied_sync(new C_OSD_OndiskWriteUnlock(obc)); publish_stats_to_osd(); assert(missing_loc.needs_recovery(hoid)); missing_loc.add_location(hoid, pg_whoami); if (!is_unreadable_object(hoid) && waiting_for_unreadable_object.count(hoid)) { dout(20) << " kicking unreadable waiters on " << hoid << dendl; requeue_ops(waiting_for_unreadable_object[hoid]); waiting_for_unreadable_object.erase(hoid); } if (pg_log.get_missing().missing.size() == 0) { requeue_ops(waiting_for_all_missing); waiting_for_all_missing.clear(); } } else { t->register_on_applied( new C_OSD_AppliedRecoveredObjectReplica(this)); } t->register_on_commit( new C_OSD_CommittedPushedObject( this, get_osdmap()->get_epoch(), info.last_complete)); // update pg dirty_info = true; write_if_dirty(*t); } void ReplicatedPG::on_global_recover( const hobject_t &soid) { missing_loc.recovered(soid); publish_stats_to_osd(); dout(10) << "pushed " << soid << " to all replicas" << dendl; map::iterator i = recovering.find(soid); assert(i != recovering.end()); if (backfills_in_flight.count(soid)) { list requeue_list; i->second->drop_backfill_read(&requeue_list); requeue_ops(requeue_list); backfills_in_flight.erase(soid); } recovering.erase(i); finish_recovery_op(soid); if (waiting_for_degraded_object.count(soid)) { dout(20) << " kicking degraded waiters on " << soid << dendl; requeue_ops(waiting_for_degraded_object[soid]); waiting_for_degraded_object.erase(soid); } if (waiting_for_unreadable_object.count(soid)) { dout(20) << " kicking unreadable waiters on " << soid << dendl; requeue_ops(waiting_for_unreadable_object[soid]); waiting_for_unreadable_object.erase(soid); } finish_degraded_object(soid); } void ReplicatedPG::on_peer_recover( pg_shard_t peer, const hobject_t &soid, const ObjectRecoveryInfo &recovery_info, const object_stat_sum_t &stat) { info.stats.stats.sum.add(stat); publish_stats_to_osd(); // done! peer_missing[peer].got(soid, recovery_info.version); } void ReplicatedPG::begin_peer_recover( pg_shard_t peer, const hobject_t soid) { peer_missing[peer].revise_have(soid, eversion_t()); } void ReplicatedPG::schedule_work( GenContext *c) { osd->gen_wq.queue(c); } void ReplicatedPG::send_message_osd_cluster( int peer, Message *m, epoch_t from_epoch) { osd->send_message_osd_cluster(peer, m, from_epoch); } void ReplicatedPG::send_message_osd_cluster( Message *m, Connection *con) { osd->send_message_osd_cluster(m, con); } void ReplicatedPG::send_message_osd_cluster( Message *m, const ConnectionRef& con) { osd->send_message_osd_cluster(m, con); } ConnectionRef ReplicatedPG::get_con_osd_cluster( int peer, epoch_t from_epoch) { return osd->get_con_osd_cluster(peer, from_epoch); } PerfCounters *ReplicatedPG::get_logger() { return osd->logger; } // ==================== // missing objects bool ReplicatedPG::is_missing_object(const hobject_t& soid) const { return pg_log.get_missing().missing.count(soid); } void ReplicatedPG::wait_for_unreadable_object( const hobject_t& soid, OpRequestRef op) { assert(is_unreadable_object(soid)); eversion_t v; bool needs_recovery = missing_loc.needs_recovery(soid, &v); assert(needs_recovery); map::const_iterator p = recovering.find(soid); if (p != recovering.end()) { dout(7) << "missing " << soid << " v " << v << ", already recovering." << dendl; } else if (missing_loc.is_unfound(soid)) { dout(7) << "missing " << soid << " v " << v << ", is unfound." << dendl; } else { dout(7) << "missing " << soid << " v " << v << ", recovering." << dendl; PGBackend::RecoveryHandle *h = pgbackend->open_recovery_op(); recover_missing(soid, v, cct->_conf->osd_client_op_priority, h); pgbackend->run_recovery_op(h, cct->_conf->osd_client_op_priority); } waiting_for_unreadable_object[soid].push_back(op); op->mark_delayed("waiting for missing object"); } void ReplicatedPG::wait_for_all_missing(OpRequestRef op) { waiting_for_all_missing.push_back(op); } bool ReplicatedPG::is_degraded_object(const hobject_t& soid) { if (pg_log.get_missing().missing.count(soid)) return true; assert(actingbackfill.size() > 0); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_shard_t peer = *i; if (peer_missing.count(peer) && peer_missing[peer].missing.count(soid)) return true; // Object is degraded if after last_backfill AND // we are backfilling it if (is_backfill_targets(peer) && peer_info[peer].last_backfill <= soid && last_backfill_started >= soid && backfills_in_flight.count(soid)) return true; } return false; } void ReplicatedPG::wait_for_degraded_object(const hobject_t& soid, OpRequestRef op) { assert(is_degraded_object(soid)); // we don't have it (yet). if (recovering.count(soid)) { dout(7) << "degraded " << soid << ", already recovering" << dendl; } else if (missing_loc.is_unfound(soid)) { dout(7) << "degraded " << soid << ", still unfound, waiting" << dendl; } else { dout(7) << "degraded " << soid << ", recovering" << dendl; eversion_t v; assert(actingbackfill.size() > 0); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_shard_t peer = *i; if (peer_missing.count(peer) && peer_missing[peer].missing.count(soid)) { v = peer_missing[peer].missing[soid].need; break; } } PGBackend::RecoveryHandle *h = pgbackend->open_recovery_op(); prep_object_replica_pushes(soid, v, h); pgbackend->run_recovery_op(h, cct->_conf->osd_client_op_priority); } waiting_for_degraded_object[soid].push_back(op); op->mark_delayed("waiting for degraded object"); } bool ReplicatedPG::maybe_await_blocked_snapset( const hobject_t &hoid, OpRequestRef op) { ObjectContextRef obc; if (obc = object_contexts.lookup(hoid.get_head())) { if (obc->is_blocked()) { wait_for_blocked_object(obc->obs.oi.soid, op); return true; } else { return false; } } if (obc = object_contexts.lookup(hoid.get_snapdir())) { if (obc->is_blocked()) { wait_for_blocked_object(obc->obs.oi.soid, op); return true; } else { return false; } } return false; } void ReplicatedPG::wait_for_blocked_object(const hobject_t& soid, OpRequestRef op) { dout(10) << __func__ << " " << soid << " " << op << dendl; waiting_for_blocked_object[soid].push_back(op); op->mark_delayed("waiting for blocked object"); } bool PGLSParentFilter::filter(bufferlist& xattr_data, bufferlist& outdata) { bufferlist::iterator iter = xattr_data.begin(); inode_backtrace_t bt; generic_dout(0) << "PGLSParentFilter::filter" << dendl; ::decode(bt, iter); vector::iterator vi; for (vi = bt.ancestors.begin(); vi != bt.ancestors.end(); ++vi) { generic_dout(0) << "vi->dirino=" << vi->dirino << " parent_ino=" << parent_ino << dendl; if ( vi->dirino == parent_ino) { ::encode(*vi, outdata); return true; } } return false; } bool PGLSPlainFilter::filter(bufferlist& xattr_data, bufferlist& outdata) { if (val.size() != xattr_data.length()) return false; if (memcmp(val.c_str(), xattr_data.c_str(), val.size())) return false; return true; } bool ReplicatedPG::pgls_filter(PGLSFilter *filter, hobject_t& sobj, bufferlist& outdata) { bufferlist bl; int ret = pgbackend->objects_get_attr( sobj, filter->get_xattr(), &bl); dout(0) << "getattr (sobj=" << sobj << ", attr=" << filter->get_xattr() << ") returned " << ret << dendl; if (ret < 0) return false; return filter->filter(bl, outdata); } int ReplicatedPG::get_pgls_filter(bufferlist::iterator& iter, PGLSFilter **pfilter) { string type; PGLSFilter *filter; try { ::decode(type, iter); } catch (buffer::error& e) { return -EINVAL; } if (type.compare("parent") == 0) { filter = new PGLSParentFilter(iter); } else if (type.compare("plain") == 0) { filter = new PGLSPlainFilter(iter); } else { return -EINVAL; } *pfilter = filter; return 0; } // ========================================================== int ReplicatedPG::do_command(cmdmap_t cmdmap, ostream& ss, bufferlist& idata, bufferlist& odata) { const pg_missing_t &missing = pg_log.get_missing(); string prefix; string format; cmd_getval(cct, cmdmap, "format", format); boost::scoped_ptr f(new_formatter(format)); // demand that we have a formatter if (!f) f.reset(new_formatter("json")); string command; cmd_getval(cct, cmdmap, "cmd", command); if (command == "query") { f->open_object_section("pg"); f->dump_string("state", pg_state_string(get_state())); f->dump_stream("snap_trimq") << snap_trimq; f->dump_unsigned("epoch", get_osdmap()->get_epoch()); f->open_array_section("up"); for (vector::iterator p = up.begin(); p != up.end(); ++p) f->dump_unsigned("osd", *p); f->close_section(); f->open_array_section("acting"); for (vector::iterator p = acting.begin(); p != acting.end(); ++p) f->dump_unsigned("osd", *p); f->close_section(); if (backfill_targets.size() > 0) { f->open_array_section("backfill_targets"); for (set::iterator p = backfill_targets.begin(); p != backfill_targets.end(); ++p) f->dump_stream("shard") << *p; f->close_section(); } if (actingbackfill.size() > 0) { f->open_array_section("actingbackfill"); for (set::iterator p = actingbackfill.begin(); p != actingbackfill.end(); ++p) f->dump_stream("shard") << *p; f->close_section(); } f->open_object_section("info"); _update_calc_stats(); info.dump(f.get()); f->close_section(); f->open_array_section("peer_info"); for (map::iterator p = peer_info.begin(); p != peer_info.end(); ++p) { f->open_object_section("info"); f->dump_stream("peer") << p->first; p->second.dump(f.get()); f->close_section(); } f->close_section(); f->open_array_section("recovery_state"); handle_query_state(f.get()); f->close_section(); f->open_object_section("agent_state"); if (agent_state) agent_state->dump(f.get()); f->close_section(); f->close_section(); f->flush(odata); return 0; } else if (command == "mark_unfound_lost") { string mulcmd; cmd_getval(cct, cmdmap, "mulcmd", mulcmd); int mode = -1; if (mulcmd == "revert") { if (pool.info.ec_pool()) { ss << "mode must be 'delete' for ec pool"; return -EINVAL; } mode = pg_log_entry_t::LOST_REVERT; } else if (mulcmd == "delete") { mode = pg_log_entry_t::LOST_DELETE; } else { ss << "mode must be 'revert' or 'delete'; mark not yet implemented"; return -EINVAL; } assert(mode == pg_log_entry_t::LOST_REVERT || mode == pg_log_entry_t::LOST_DELETE); if (!is_primary()) { ss << "not primary"; return -EROFS; } int unfound = missing_loc.num_unfound(); if (!unfound) { ss << "pg has no unfound objects"; return 0; // make command idempotent } if (!all_unfound_are_queried_or_lost(get_osdmap())) { ss << "pg has " << unfound << " unfound objects but we haven't probed all sources, not marking lost"; return -EINVAL; } ss << "pg has " << unfound << " objects unfound and apparently lost, marking"; mark_all_unfound_lost(mode); return 0; } else if (command == "list_missing") { hobject_t offset; string offset_json; if (cmd_getval(cct, cmdmap, "offset", offset_json)) { json_spirit::Value v; try { if (!json_spirit::read(offset_json, v)) throw std::runtime_error("bad json"); offset.decode(v); } catch (std::runtime_error& e) { ss << "error parsing offset: " << e.what(); return -EINVAL; } } f->open_object_section("missing"); { f->open_object_section("offset"); offset.dump(f.get()); f->close_section(); } f->dump_int("num_missing", missing.num_missing()); f->dump_int("num_unfound", get_num_unfound()); map::const_iterator p = missing.missing.upper_bound(offset); { f->open_array_section("objects"); int32_t num = 0; bufferlist bl; while (p != missing.missing.end() && num < cct->_conf->osd_command_max_records) { f->open_object_section("object"); { f->open_object_section("oid"); p->first.dump(f.get()); f->close_section(); } p->second.dump(f.get()); // have, need keys { f->open_array_section("locations"); if (missing_loc.needs_recovery(p->first)) { for (set::iterator r = missing_loc.get_locations(p->first).begin(); r != missing_loc.get_locations(p->first).end(); ++r) f->dump_stream("shard") << *r; } f->close_section(); } f->close_section(); ++p; num++; } f->close_section(); } f->dump_int("more", p != missing.missing.end()); f->close_section(); f->flush(odata); return 0; }; ss << "unknown pg command " << prefix; return -EINVAL; } // ========================================================== bool ReplicatedPG::pg_op_must_wait(MOSDOp *op) { if (pg_log.get_missing().missing.empty()) return false; for (vector::iterator p = op->ops.begin(); p != op->ops.end(); ++p) { if (p->op.op == CEPH_OSD_OP_PGLS) { if (op->get_snapid() != CEPH_NOSNAP) { return true; } } } return false; } void ReplicatedPG::do_pg_op(OpRequestRef op) { MOSDOp *m = static_cast(op->get_req()); assert(m->get_header().type == CEPH_MSG_OSD_OP); dout(10) << "do_pg_op " << *m << dendl; op->mark_started(); int result = 0; string cname, mname; PGLSFilter *filter = NULL; bufferlist filter_out; snapid_t snapid = m->get_snapid(); vector ops = m->ops; for (vector::iterator p = ops.begin(); p != ops.end(); ++p) { OSDOp& osd_op = *p; bufferlist::iterator bp = p->indata.begin(); switch (p->op.op) { case CEPH_OSD_OP_PGLS_FILTER: try { ::decode(cname, bp); ::decode(mname, bp); } catch (const buffer::error& e) { dout(0) << "unable to decode PGLS_FILTER description in " << *m << dendl; result = -EINVAL; break; } result = get_pgls_filter(bp, &filter); if (result < 0) break; assert(filter); // fall through case CEPH_OSD_OP_PGLS: if (m->get_pg() != info.pgid.pgid) { dout(10) << " pgls pg=" << m->get_pg() << " != " << info.pgid << dendl; result = 0; // hmm? } else { unsigned list_size = MIN(cct->_conf->osd_max_pgls, p->op.pgls.count); dout(10) << " pgls pg=" << m->get_pg() << " count " << list_size << dendl; // read into a buffer vector sentries; pg_ls_response_t response; try { ::decode(response.handle, bp); } catch (const buffer::error& e) { dout(0) << "unable to decode PGLS handle in " << *m << dendl; result = -EINVAL; break; } hobject_t next; hobject_t current = response.handle; osr->flush(); int r = pgbackend->objects_list_partial( current, list_size, list_size, snapid, &sentries, &next); if (r != 0) { result = -EINVAL; break; } assert(snapid == CEPH_NOSNAP || pg_log.get_missing().missing.empty()); map::const_iterator missing_iter = pg_log.get_missing().missing.lower_bound(current); vector::iterator ls_iter = sentries.begin(); hobject_t _max = hobject_t::get_max(); while (1) { const hobject_t &mcand = missing_iter == pg_log.get_missing().missing.end() ? _max : missing_iter->first; const hobject_t &lcand = ls_iter == sentries.end() ? _max : *ls_iter; hobject_t candidate; if (mcand == lcand) { candidate = mcand; if (!mcand.is_max()) { ++ls_iter; ++missing_iter; } } else if (mcand < lcand) { candidate = mcand; assert(!mcand.is_max()); ++missing_iter; } else { candidate = lcand; assert(!lcand.is_max()); ++ls_iter; } if (candidate >= next) { break; } if (response.entries.size() == list_size) { next = candidate; break; } // skip snapdir objects if (candidate.snap == CEPH_SNAPDIR) continue; if (candidate.snap < snapid) continue; if (snapid != CEPH_NOSNAP) { bufferlist bl; if (candidate.snap == CEPH_NOSNAP) { pgbackend->objects_get_attr( candidate, SS_ATTR, &bl); SnapSet snapset(bl); if (snapid <= snapset.seq) continue; } else { bufferlist attr_bl; pgbackend->objects_get_attr( candidate, OI_ATTR, &attr_bl); object_info_t oi(attr_bl); vector::iterator i = find(oi.snaps.begin(), oi.snaps.end(), snapid); if (i == oi.snaps.end()) continue; } } // skip wrong namespace if (candidate.get_namespace() != m->get_object_locator().nspace) continue; if (filter && !pgls_filter(filter, candidate, filter_out)) continue; response.entries.push_back(make_pair(candidate.oid, candidate.get_key())); } if (next.is_max() && missing_iter == pg_log.get_missing().missing.end() && ls_iter == sentries.end()) { result = 1; } response.handle = next; ::encode(response, osd_op.outdata); if (filter) ::encode(filter_out, osd_op.outdata); dout(10) << " pgls result=" << result << " outdata.length()=" << osd_op.outdata.length() << dendl; } break; case CEPH_OSD_OP_PG_HITSET_LS: { list< pair > ls; for (list::const_iterator p = info.hit_set.history.begin(); p != info.hit_set.history.end(); ++p) ls.push_back(make_pair(p->begin, p->end)); if (info.hit_set.current_info.begin) ls.push_back(make_pair(info.hit_set.current_info.begin, utime_t())); else if (hit_set) ls.push_back(make_pair(hit_set_start_stamp, utime_t())); ::encode(ls, osd_op.outdata); } break; case CEPH_OSD_OP_PG_HITSET_GET: { utime_t stamp(osd_op.op.hit_set_get.stamp); if ((info.hit_set.current_info.begin && stamp >= info.hit_set.current_info.begin) || stamp >= hit_set_start_stamp) { // read the current in-memory HitSet, not the version we've // checkpointed. if (!hit_set) { result= -ENOENT; break; } ::encode(*hit_set, osd_op.outdata); result = osd_op.outdata.length(); } else { // read an archived HitSet. hobject_t oid; for (list::const_iterator p = info.hit_set.history.begin(); p != info.hit_set.history.end(); ++p) { if (stamp >= p->begin && stamp <= p->end) { oid = get_hit_set_archive_object(p->begin, p->end); break; } } if (oid == hobject_t()) { result = -ENOENT; break; } if (!pool.info.is_replicated()) { // FIXME: EC not supported yet result = -EOPNOTSUPP; break; } if (is_unreadable_object(oid)) { wait_for_unreadable_object(oid, op); return; } result = osd->store->read(coll, oid, 0, 0, osd_op.outdata); } } break; default: result = -EINVAL; break; } } // reply MOSDOpReply *reply = new MOSDOpReply(m, 0, get_osdmap()->get_epoch(), CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK, false); reply->claim_op_out_data(ops); reply->set_result(result); reply->set_reply_versions(info.last_update, info.last_user_version); osd->send_message_osd_client(reply, m->get_connection()); delete filter; } void ReplicatedPG::calc_trim_to() { if (is_scrubbing() && scrubber.classic) { dout(10) << "calc_trim_to no trim during classic scrub" << dendl; pg_trim_to = eversion_t(); return; } size_t target = cct->_conf->osd_min_pg_log_entries; if (is_degraded() || state_test(PG_STATE_RECOVERING | PG_STATE_RECOVERY_WAIT | PG_STATE_BACKFILL | PG_STATE_BACKFILL_WAIT | PG_STATE_BACKFILL_TOOFULL)) { target = cct->_conf->osd_max_pg_log_entries; } if (min_last_complete_ondisk != eversion_t() && min_last_complete_ondisk != pg_trim_to && pg_log.get_log().approx_size() > target) { size_t num_to_trim = pg_log.get_log().approx_size() - target; list::const_iterator it = pg_log.get_log().log.begin(); eversion_t new_trim_to; for (size_t i = 0; i < num_to_trim; ++i) { new_trim_to = it->version; ++it; if (new_trim_to > min_last_complete_ondisk) { new_trim_to = min_last_complete_ondisk; dout(10) << "calc_trim_to trimming to min_last_complete_ondisk" << dendl; break; } } dout(10) << "calc_trim_to " << pg_trim_to << " -> " << new_trim_to << dendl; pg_trim_to = new_trim_to; assert(pg_trim_to <= pg_log.get_head()); assert(pg_trim_to <= min_last_complete_ondisk); } } ReplicatedPG::ReplicatedPG(OSDService *o, OSDMapRef curmap, const PGPool &_pool, spg_t p, const hobject_t& oid, const hobject_t& ioid) : PG(o, curmap, _pool, p, oid, ioid), pgbackend( PGBackend::build_pg_backend( _pool.info, curmap, this, coll_t(p), coll_t::make_temp_coll(p), o->store, cct)), snapset_contexts_lock("ReplicatedPG::snapset_contexts"), temp_seq(0), snap_trimmer_machine(this) { missing_loc.set_backend_predicates( pgbackend->get_is_readable_predicate(), pgbackend->get_is_recoverable_predicate()); snap_trimmer_machine.initiate(); } void ReplicatedPG::get_src_oloc(const object_t& oid, const object_locator_t& oloc, object_locator_t& src_oloc) { src_oloc = oloc; if (oloc.key.empty()) src_oloc.key = oid.name; } void ReplicatedPG::do_request( OpRequestRef op, ThreadPool::TPHandle &handle) { if (!op_has_sufficient_caps(op)) { osd->reply_op_error(op, -EPERM); return; } assert(!op_must_wait_for_map(get_osdmap(), op)); if (can_discard_request(op)) { return; } if (flushes_in_progress > 0) { dout(20) << flushes_in_progress << " flushes_in_progress pending " << "waiting for active on " << op << dendl; waiting_for_active.push_back(op); return; } if (!is_active()) { // Delay unless PGBackend says it's ok if (pgbackend->can_handle_while_inactive(op)) { bool handled = pgbackend->handle_message(op); assert(handled); return; } else { waiting_for_active.push_back(op); return; } } assert(is_active() && flushes_in_progress == 0); if (pgbackend->handle_message(op)) return; switch (op->get_req()->get_type()) { case CEPH_MSG_OSD_OP: if (is_replay()) { dout(20) << " replay, waiting for active on " << op << dendl; waiting_for_active.push_back(op); return; } // verify client features if ((pool.info.has_tiers() || pool.info.is_tier()) && !op->has_feature(CEPH_FEATURE_OSD_CACHEPOOL)) { osd->reply_op_error(op, -EOPNOTSUPP); return; } do_op(op); // do it now break; case MSG_OSD_SUBOP: do_sub_op(op); break; case MSG_OSD_SUBOPREPLY: do_sub_op_reply(op); break; case MSG_OSD_PG_SCAN: do_scan(op, handle); break; case MSG_OSD_PG_BACKFILL: do_backfill(op); break; default: assert(0 == "bad message type in do_request"); } } hobject_t ReplicatedPG::earliest_backfill() const { hobject_t e = hobject_t::get_max(); for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; map::const_iterator iter = peer_info.find(bt); assert(iter != peer_info.end()); if (iter->second.last_backfill < e) e = iter->second.last_backfill; } return e; } // if we have src_oids, we need to be careful of the target being // before and a src being after the last_backfill line, or else the // operation won't apply properly on the backfill_target. (the // opposite is not a problem; if the target is after the line, we // don't apply on the backfill_target and it doesn't matter.) // With multi-backfill some backfill targets can be ahead of // last_backfill_started. We consider each replica individually and // take the larger of last_backfill_started and the replicas last_backfill. bool ReplicatedPG::check_src_targ(const hobject_t& soid, const hobject_t& toid) const { for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_shard_t bt = *i; map::const_iterator iter = peer_info.find(bt); assert(iter != peer_info.end()); if (toid <= MAX(last_backfill_started, iter->second.last_backfill) && soid > MAX(last_backfill_started, iter->second.last_backfill)) return true; } return false; } /** do_op - do an op * pg lock will be held (if multithreaded) * osd_lock NOT held. */ void ReplicatedPG::do_op(OpRequestRef op) { MOSDOp *m = static_cast(op->get_req()); assert(m->get_header().type == CEPH_MSG_OSD_OP); if (op->includes_pg_op()) { if (pg_op_must_wait(m)) { wait_for_all_missing(op); return; } return do_pg_op(op); } if (get_osdmap()->is_blacklisted(m->get_source_addr())) { dout(10) << "do_op " << m->get_source_addr() << " is blacklisted" << dendl; osd->reply_op_error(op, -EBLACKLISTED); return; } // order this op as a write? bool write_ordered = op->may_write() || op->may_cache() || (m->get_flags() & CEPH_OSD_FLAG_RWORDERED); dout(10) << "do_op " << *m << (op->may_write() ? " may_write" : "") << (op->may_read() ? " may_read" : "") << (op->may_cache() ? " may_cache" : "") << " -> " << (write_ordered ? "write-ordered" : "read-ordered") << " flags " << ceph_osd_flag_string(m->get_flags()) << dendl; hobject_t head(m->get_oid(), m->get_object_locator().key, CEPH_NOSNAP, m->get_pg().ps(), info.pgid.pool(), m->get_object_locator().nspace); if (write_ordered && scrubber.write_blocked_by_scrub(head)) { dout(20) << __func__ << ": waiting for scrub" << dendl; waiting_for_active.push_back(op); op->mark_delayed("waiting for scrub"); return; } // missing object? if (is_unreadable_object(head)) { wait_for_unreadable_object(head, op); return; } // degraded object? if (write_ordered && is_degraded_object(head)) { wait_for_degraded_object(head, op); return; } // missing snapdir? hobject_t snapdir(m->get_oid(), m->get_object_locator().key, CEPH_SNAPDIR, m->get_pg().ps(), info.pgid.pool(), m->get_object_locator().nspace); if (is_unreadable_object(snapdir)) { wait_for_unreadable_object(snapdir, op); return; } // degraded object? if (write_ordered && is_degraded_object(snapdir)) { wait_for_degraded_object(snapdir, op); return; } // asking for SNAPDIR is only ok for reads if (m->get_snapid() == CEPH_SNAPDIR && op->may_write()) { osd->reply_op_error(op, -EINVAL); return; } // dup/replay? if (op->may_write() || op->may_cache()) { const pg_log_entry_t *entry = pg_log.get_log().get_request(m->get_reqid()); if (entry) { const eversion_t& oldv = entry->version; dout(3) << __func__ << " dup " << m->get_reqid() << " was " << oldv << dendl; if (already_complete(oldv)) { osd->reply_op_error(op, 0, oldv, entry->user_version); } else { if (m->wants_ack()) { if (already_ack(oldv)) { MOSDOpReply *reply = new MOSDOpReply(m, 0, get_osdmap()->get_epoch(), 0, false); reply->add_flags(CEPH_OSD_FLAG_ACK); reply->set_reply_versions(oldv, entry->user_version); osd->send_message_osd_client(reply, m->get_connection()); } else { dout(10) << " waiting for " << oldv << " to ack" << dendl; waiting_for_ack[oldv].push_back(op); } } dout(10) << " waiting for " << oldv << " to commit" << dendl; waiting_for_ondisk[oldv].push_back(op); // always queue ondisk waiters, so that we can requeue if needed op->mark_delayed("waiting for ondisk"); } return; } } ObjectContextRef obc; bool can_create = op->may_write() || op->may_cache(); hobject_t missing_oid; hobject_t oid(m->get_oid(), m->get_object_locator().key, m->get_snapid(), m->get_pg().ps(), m->get_object_locator().get_pool(), m->get_object_locator().nspace); // io blocked on obc? if (((m->get_flags() & CEPH_OSD_FLAG_FLUSH) == 0) && maybe_await_blocked_snapset(oid, op)) { return; } int r = find_object_context( oid, &obc, can_create, m->get_flags() & CEPH_OSD_FLAG_MAP_SNAP_CLONE, &missing_oid); if (r == -EAGAIN) { // If we're not the primary of this OSD, and we have // CEPH_OSD_FLAG_LOCALIZE_READS set, we just return -EAGAIN. Otherwise, // we have to wait for the object. if (is_primary() || (!(m->get_flags() & CEPH_OSD_FLAG_BALANCE_READS) && !(m->get_flags() & CEPH_OSD_FLAG_LOCALIZE_READS))) { // missing the specific snap we need; requeue and wait. assert(!op->may_write()); // only happens on a read/cache wait_for_unreadable_object(missing_oid, op); return; } } else if (r == 0) { if (is_unreadable_object(obc->obs.oi.soid)) { dout(10) << __func__ << ": clone " << obc->obs.oi.soid << " is unreadable, waiting" << dendl; wait_for_unreadable_object(obc->obs.oi.soid, op); return; } // degraded object? (the check above was for head; this could be a clone) if (write_ordered && obc->obs.oi.soid.snap != CEPH_NOSNAP && is_degraded_object(obc->obs.oi.soid)) { dout(10) << __func__ << ": clone " << obc->obs.oi.soid << " is degraded, waiting" << dendl; wait_for_degraded_object(obc->obs.oi.soid, op); return; } } bool in_hit_set = false; if (hit_set) { if (missing_oid != hobject_t() && hit_set->contains(missing_oid)) in_hit_set = true; hit_set->insert(oid); if (hit_set->is_full() || hit_set_start_stamp + pool.info.hit_set_period <= m->get_recv_stamp()) { hit_set_persist(); } } if (agent_state) { agent_choose_mode(); } if ((m->get_flags() & CEPH_OSD_FLAG_IGNORE_CACHE) == 0 && maybe_handle_cache(op, write_ordered, obc, r, missing_oid, false, in_hit_set)) return; if (r) { osd->reply_op_error(op, r); return; } // make sure locator is consistent object_locator_t oloc(obc->obs.oi.soid); if (m->get_object_locator() != oloc) { dout(10) << " provided locator " << m->get_object_locator() << " != object's " << obc->obs.oi.soid << dendl; osd->clog.warn() << "bad locator " << m->get_object_locator() << " on object " << oloc << " op " << *m << "\n"; } // io blocked on obc? if (obc->is_blocked() && (m->get_flags() & CEPH_OSD_FLAG_FLUSH) == 0) { wait_for_blocked_object(obc->obs.oi.soid, op); return; } dout(25) << __func__ << " oi " << obc->obs.oi << dendl; // are writes blocked by another object? if (obc->blocked_by) { dout(10) << "do_op writes for " << obc->obs.oi.soid << " blocked by " << obc->blocked_by->obs.oi.soid << dendl; wait_for_degraded_object(obc->blocked_by->obs.oi.soid, op); return; } // src_oids map src_obc; for (vector::iterator p = m->ops.begin(); p != m->ops.end(); ++p) { OSDOp& osd_op = *p; // make sure LIST_SNAPS is on CEPH_SNAPDIR and nothing else if (osd_op.op.op == CEPH_OSD_OP_LIST_SNAPS && m->get_snapid() != CEPH_SNAPDIR) { dout(10) << "LIST_SNAPS with incorrect context" << dendl; osd->reply_op_error(op, -EINVAL); return; } if (!ceph_osd_op_type_multi(osd_op.op.op)) continue; if (osd_op.soid.oid.name.length()) { object_locator_t src_oloc; get_src_oloc(m->get_oid(), m->get_object_locator(), src_oloc); hobject_t src_oid(osd_op.soid, src_oloc.key, m->get_pg().ps(), info.pgid.pool(), m->get_object_locator().nspace); if (!src_obc.count(src_oid)) { ObjectContextRef sobc; hobject_t wait_oid; int r; if (src_oid.is_head() && is_missing_object(src_oid)) { wait_for_unreadable_object(src_oid, op); } else if ((r = find_object_context( src_oid, &sobc, false, false, &wait_oid)) == -EAGAIN) { // missing the specific snap we need; requeue and wait. wait_for_unreadable_object(wait_oid, op); } else if (r) { if (!maybe_handle_cache(op, write_ordered, sobc, r, wait_oid, true)) osd->reply_op_error(op, r); } else if (sobc->obs.oi.is_whiteout()) { osd->reply_op_error(op, -ENOENT); } else { if (sobc->obs.oi.soid.get_key() != obc->obs.oi.soid.get_key() && sobc->obs.oi.soid.get_key() != obc->obs.oi.soid.oid.name && sobc->obs.oi.soid.oid.name != obc->obs.oi.soid.get_key()) { dout(1) << " src_oid " << sobc->obs.oi.soid << " != " << obc->obs.oi.soid << dendl; osd->reply_op_error(op, -EINVAL); } else if (is_degraded_object(sobc->obs.oi.soid) || (check_src_targ(sobc->obs.oi.soid, obc->obs.oi.soid))) { if (is_degraded_object(sobc->obs.oi.soid)) { wait_for_degraded_object(sobc->obs.oi.soid, op); } else { waiting_for_degraded_object[sobc->obs.oi.soid].push_back(op); op->mark_delayed("waiting for degraded object"); } dout(10) << " writes for " << obc->obs.oi.soid << " now blocked by " << sobc->obs.oi.soid << dendl; obc->blocked_by = sobc; sobc->blocking.insert(obc); } else { dout(10) << " src_oid " << src_oid << " obc " << src_obc << dendl; src_obc[src_oid] = sobc; continue; } } // Error cleanup below } else { continue; } // Error cleanup below } else { dout(10) << "no src oid specified for multi op " << osd_op << dendl; osd->reply_op_error(op, -EINVAL); } return; } // any SNAPDIR op needs to have all clones present. treat them as // src_obc's so that we track references properly and clean up later. if (m->get_snapid() == CEPH_SNAPDIR) { for (vector::iterator p = obc->ssc->snapset.clones.begin(); p != obc->ssc->snapset.clones.end(); ++p) { hobject_t clone_oid = obc->obs.oi.soid; clone_oid.snap = *p; if (!src_obc.count(clone_oid)) { if (is_unreadable_object(clone_oid)) { wait_for_unreadable_object(clone_oid, op); return; } ObjectContextRef sobc = get_object_context(clone_oid, false); if (!sobc) { if (!maybe_handle_cache(op, write_ordered, sobc, -ENOENT, clone_oid, true)) osd->reply_op_error(op, -ENOENT); return; } else { dout(10) << " clone_oid " << clone_oid << " obc " << sobc << dendl; src_obc[clone_oid] = sobc; continue; } assert(0); // unreachable } else { continue; } } } OpContext *ctx = new OpContext(op, m->get_reqid(), m->ops, &obc->obs, obc->ssc, this); ctx->op_t = pgbackend->get_transaction(); ctx->obc = obc; if (!obc->obs.exists) ctx->snapset_obc = get_object_context(obc->obs.oi.soid.get_snapdir(), false); if (m->get_flags() & CEPH_OSD_FLAG_SKIPRWLOCKS) { dout(20) << __func__ << ": skipping rw locks" << dendl; } else if (m->get_flags() & CEPH_OSD_FLAG_FLUSH) { dout(20) << __func__ << ": part of flush, will ignore write lock" << dendl; // verify there is in fact a flush in progress // FIXME: we could make this a stronger test. map::iterator p = flush_ops.find(obc->obs.oi.soid); if (p == flush_ops.end()) { dout(10) << __func__ << " no flush in progress, aborting" << dendl; reply_ctx(ctx, -EINVAL); return; } } else if (!get_rw_locks(ctx)) { dout(20) << __func__ << " waiting for rw locks " << dendl; op->mark_delayed("waiting for rw locks"); close_op_ctx(ctx, -EBUSY); return; } if (m->get_flags() & CEPH_OSD_FLAG_IGNORE_CACHE) { ctx->ignore_cache = true; } if ((op->may_read()) && (obc->obs.oi.is_lost())) { // This object is lost. Reading from it returns an error. dout(20) << __func__ << ": object " << obc->obs.oi.soid << " is lost" << dendl; reply_ctx(ctx, -ENFILE); return; } if (!op->may_write() && !op->may_cache() && (!obc->obs.exists || ((m->get_snapid() != CEPH_SNAPDIR) && obc->obs.oi.is_whiteout()))) { reply_ctx(ctx, -ENOENT); return; } op->mark_started(); ctx->src_obc = src_obc; execute_ctx(ctx); } bool ReplicatedPG::maybe_handle_cache(OpRequestRef op, bool write_ordered, ObjectContextRef obc, int r, const hobject_t& missing_oid, bool must_promote, bool in_hit_set) { if (obc) dout(25) << __func__ << " " << obc->obs.oi << " " << (obc->obs.exists ? "exists" : "DNE") << " missing_oid " << missing_oid << dendl; else dout(25) << __func__ << " (no obc)" << " missing_oid " << missing_oid << dendl; if (obc.get() && obc->is_blocked()) { // we're already doing something with this object dout(20) << __func__ << " blocked on " << obc->obs.oi.soid << dendl; return false; } if (r == -ENOENT && missing_oid == hobject_t()) { // we know this object is logically absent (e.g., an undefined clone) return false; } switch (pool.info.cache_mode) { case pg_pool_t::CACHEMODE_NONE: return false; case pg_pool_t::CACHEMODE_WRITEBACK: if (obc.get() && obc->obs.exists) { return false; } if (agent_state && agent_state->evict_mode == TierAgentState::EVICT_MODE_FULL) { if (!op->may_write() && !op->may_cache() && !write_ordered) { dout(20) << __func__ << " cache pool full, redirecting read" << dendl; do_cache_redirect(op, obc); return true; } dout(20) << __func__ << " cache pool full, waiting" << dendl; waiting_for_cache_not_full.push_back(op); return true; } if (!must_promote && can_skip_promote(op, obc)) { return false; } if (op->may_write() || write_ordered || must_promote || !hit_set) { promote_object(op, obc, missing_oid); } else { switch (pool.info.min_read_recency_for_promote) { case 0: promote_object(op, obc, missing_oid); break; case 1: // Check if in the current hit set if (in_hit_set) { promote_object(op, obc, missing_oid); } else { do_cache_redirect(op, obc); } break; default: if (in_hit_set) { promote_object(op, obc, missing_oid); } else { // Check if in other hit sets map::iterator itor; bool in_other_hit_sets = false; for (itor = agent_state->hit_set_map.begin(); itor != agent_state->hit_set_map.end(); itor++) { if (itor->second->contains(missing_oid)) { in_other_hit_sets = true; break; } } if (in_other_hit_sets) { promote_object(op, obc, missing_oid); } else { do_cache_redirect(op, obc); } } break; } } return true; case pg_pool_t::CACHEMODE_FORWARD: if (obc.get() && obc->obs.exists) { return false; } if (must_promote) promote_object(op, obc, missing_oid); else do_cache_redirect(op, obc); return true; case pg_pool_t::CACHEMODE_READONLY: // TODO: clean this case up if (obc.get() && obc->obs.exists) { return false; } if (!obc.get() && r == -ENOENT) { // we don't have the object and op's a read promote_object(op, obc, missing_oid); return true; } if (!r) { // it must be a write do_cache_redirect(op, obc); return true; } // crap, there was a failure of some kind return false; default: assert(0 == "unrecognized cache_mode"); } return false; } bool ReplicatedPG::can_skip_promote(OpRequestRef op, ObjectContextRef obc) { MOSDOp *m = static_cast(op->get_req()); if (m->ops.empty()) return false; // if we get a delete with FAILOK we can skip promote. without // FAILOK we still need to promote (or do something smarter) to // determine whether to return ENOENT or 0. if (m->ops[0].op.op == CEPH_OSD_OP_DELETE && (m->ops[0].op.flags & CEPH_OSD_OP_FLAG_FAILOK)) return true; return false; } void ReplicatedPG::do_cache_redirect(OpRequestRef op, ObjectContextRef obc) { MOSDOp *m = static_cast(op->get_req()); int flags = m->get_flags() & (CEPH_OSD_FLAG_ACK|CEPH_OSD_FLAG_ONDISK); MOSDOpReply *reply = new MOSDOpReply(m, -ENOENT, get_osdmap()->get_epoch(), flags, false); request_redirect_t redir(m->get_object_locator(), pool.info.tier_of); reply->set_redirect(redir); dout(10) << "sending redirect to pool " << pool.info.tier_of << " for op " << op << dendl; m->get_connection()->get_messenger()->send_message(reply, m->get_connection()); return; } class PromoteCallback: public ReplicatedPG::CopyCallback { OpRequestRef op; ObjectContextRef obc; ReplicatedPG *pg; public: PromoteCallback(OpRequestRef op_, ObjectContextRef obc_, ReplicatedPG *pg_) : op(op_), obc(obc_), pg(pg_) {} virtual void finish(ReplicatedPG::CopyCallbackResults results) { ReplicatedPG::CopyResults *results_data = results.get<1>(); int r = results.get<0>(); pg->finish_promote(r, op, results_data, obc); } }; void ReplicatedPG::promote_object(OpRequestRef op, ObjectContextRef obc, const hobject_t& missing_oid) { MOSDOp *m = static_cast(op->get_req()); if (!obc) { // we need to create an ObjectContext assert(missing_oid != hobject_t()); obc = get_object_context(missing_oid, true); } dout(10) << __func__ << " " << obc->obs.oi.soid << dendl; if (scrubber.write_blocked_by_scrub(obc->obs.oi.soid)) { dout(10) << __func__ << " " << obc->obs.oi.soid << " blocked by scrub" << dendl; if (op) { waiting_for_active.push_back(op); dout(10) << __func__ << " " << obc->obs.oi.soid << " placing op in waiting_for_active" << dendl; } else { dout(10) << __func__ << " " << obc->obs.oi.soid << " no op, dropping on the floor" << dendl; } return; } PromoteCallback *cb = new PromoteCallback(op, obc, this); object_locator_t oloc(m->get_object_locator()); oloc.pool = pool.info.tier_of; start_copy(cb, obc, obc->obs.oi.soid, oloc, 0, CEPH_OSD_COPY_FROM_FLAG_IGNORE_OVERLAY | CEPH_OSD_COPY_FROM_FLAG_IGNORE_CACHE | CEPH_OSD_COPY_FROM_FLAG_MAP_SNAP_CLONE, obc->obs.oi.soid.snap == CEPH_NOSNAP); assert(obc->is_blocked()); wait_for_blocked_object(obc->obs.oi.soid, op); } void ReplicatedPG::execute_ctx(OpContext *ctx) { dout(10) << __func__ << " " << ctx << dendl; ctx->reset_obs(ctx->obc); OpRequestRef op = ctx->op; MOSDOp *m = static_cast(op->get_req()); ObjectContextRef obc = ctx->obc; const hobject_t& soid = obc->obs.oi.soid; map& src_obc = ctx->src_obc; // this method must be idempotent since we may call it several times // before we finally apply the resulting transaction. delete ctx->op_t; ctx->op_t = pgbackend->get_transaction(); if (op->may_write() || op->may_cache()) { op->mark_started(); // snap if (!(m->get_flags() & CEPH_OSD_FLAG_ENFORCE_SNAPC) && pool.info.is_pool_snaps_mode()) { // use pool's snapc ctx->snapc = pool.snapc; } else { // client specified snapc ctx->snapc.seq = m->get_snap_seq(); ctx->snapc.snaps = m->get_snaps(); } if ((m->get_flags() & CEPH_OSD_FLAG_ORDERSNAP) && ctx->snapc.seq < obc->ssc->snapset.seq) { dout(10) << " ORDERSNAP flag set and snapc seq " << ctx->snapc.seq << " < snapset seq " << obc->ssc->snapset.seq << " on " << obc->obs.oi.soid << dendl; reply_ctx(ctx, -EOLDSNAPC); return; } // version ctx->at_version = get_next_version(); ctx->mtime = m->get_mtime(); dout(10) << "do_op " << soid << " " << ctx->ops << " ov " << obc->obs.oi.version << " av " << ctx->at_version << " snapc " << ctx->snapc << " snapset " << obc->ssc->snapset << dendl; } else { dout(10) << "do_op " << soid << " " << ctx->ops << " ov " << obc->obs.oi.version << dendl; } if (!ctx->user_at_version) ctx->user_at_version = obc->obs.oi.user_version; dout(30) << __func__ << " user_at_version " << ctx->user_at_version << dendl; // note my stats utime_t now = ceph_clock_now(cct); if (op->may_read()) { dout(10) << " taking ondisk_read_lock" << dendl; obc->ondisk_read_lock(); } for (map::iterator p = src_obc.begin(); p != src_obc.end(); ++p) { dout(10) << " taking ondisk_read_lock for src " << p->first << dendl; p->second->ondisk_read_lock(); } int result = prepare_transaction(ctx); if (op->may_read()) { dout(10) << " dropping ondisk_read_lock" << dendl; obc->ondisk_read_unlock(); } for (map::iterator p = src_obc.begin(); p != src_obc.end(); ++p) { dout(10) << " dropping ondisk_read_lock for src " << p->first << dendl; p->second->ondisk_read_unlock(); } if (result == -EINPROGRESS) { // come back later. return; } if (result == -EAGAIN) { // clean up after the ctx close_op_ctx(ctx, result); return; } // check for full if (ctx->delta_stats.num_bytes > 0 && pool.info.get_flags() & pg_pool_t::FLAG_FULL) { reply_ctx(ctx, -ENOSPC); return; } bool successful_write = !ctx->op_t->empty() && op->may_write() && result >= 0; // prepare the reply ctx->reply = new MOSDOpReply(m, 0, get_osdmap()->get_epoch(), 0, successful_write); // Write operations aren't allowed to return a data payload because // we can't do so reliably. If the client has to resend the request // and it has already been applied, we will return 0 with no // payload. Non-deterministic behavior is no good. However, it is // possible to construct an operation that does a read, does a guard // check (e.g., CMPXATTR), and then a write. Then we either succeed // with the write, or return a CMPXATTR and the read value. if (successful_write) { // write. normalize the result code. dout(20) << " zeroing write result code " << result << dendl; result = 0; } ctx->reply->set_result(result); // read or error? if (ctx->op_t->empty() || result < 0) { if (ctx->pending_async_reads.empty()) { complete_read_ctx(result, ctx); } else { in_progress_async_reads.push_back(make_pair(op, ctx)); ctx->start_async_reads(this); } return; } ctx->reply->set_reply_versions(ctx->at_version, ctx->user_at_version); assert(op->may_write() || op->may_cache()); // trim log? calc_trim_to(); // verify that we are doing this in order? if (cct->_conf->osd_debug_op_order && m->get_source().is_client() && !pool.info.is_tier() && !pool.info.has_tiers()) { map& cm = debug_op_order[obc->obs.oi.soid]; ceph_tid_t t = m->get_tid(); client_t n = m->get_source().num(); map::iterator p = cm.find(n); if (p == cm.end()) { dout(20) << " op order client." << n << " tid " << t << " (first)" << dendl; cm[n] = t; } else { dout(20) << " op order client." << n << " tid " << t << " last was " << p->second << dendl; if (p->second > t) { derr << "bad op order, already applied " << p->second << " > this " << t << dendl;; assert(0 == "out of order op"); } p->second = t; } } // issue replica writes ceph_tid_t rep_tid = osd->get_tid(); RepGather *repop = new_repop(ctx, obc, rep_tid); // new repop claims our obc, src_obc refs // note: repop now owns ctx AND ctx->op repop->src_obc.swap(src_obc); // and src_obc. issue_repop(repop, now); eval_repop(repop); repop->put(); } void ReplicatedPG::reply_ctx(OpContext *ctx, int r) { if (ctx->op) osd->reply_op_error(ctx->op, r); close_op_ctx(ctx, r); } void ReplicatedPG::reply_ctx(OpContext *ctx, int r, eversion_t v, version_t uv) { if (ctx->op) osd->reply_op_error(ctx->op, r, v, uv); close_op_ctx(ctx, r); } void ReplicatedPG::log_op_stats(OpContext *ctx) { OpRequestRef op = ctx->op; MOSDOp *m = static_cast(op->get_req()); utime_t now = ceph_clock_now(cct); utime_t latency = now; latency -= ctx->op->get_req()->get_recv_stamp(); utime_t process_latency = now; process_latency -= ctx->op->get_dequeued_time(); utime_t rlatency; if (ctx->readable_stamp != utime_t()) { rlatency = ctx->readable_stamp; rlatency -= ctx->op->get_req()->get_recv_stamp(); } uint64_t inb = ctx->bytes_written; uint64_t outb = ctx->bytes_read; osd->logger->inc(l_osd_op); osd->logger->inc(l_osd_op_outb, outb); osd->logger->inc(l_osd_op_inb, inb); osd->logger->tinc(l_osd_op_lat, latency); osd->logger->tinc(l_osd_op_process_lat, process_latency); if (op->may_read() && op->may_write()) { osd->logger->inc(l_osd_op_rw); osd->logger->inc(l_osd_op_rw_inb, inb); osd->logger->inc(l_osd_op_rw_outb, outb); osd->logger->tinc(l_osd_op_rw_rlat, rlatency); osd->logger->tinc(l_osd_op_rw_lat, latency); osd->logger->tinc(l_osd_op_rw_process_lat, process_latency); } else if (op->may_read()) { osd->logger->inc(l_osd_op_r); osd->logger->inc(l_osd_op_r_outb, outb); osd->logger->tinc(l_osd_op_r_lat, latency); osd->logger->tinc(l_osd_op_r_process_lat, process_latency); } else if (op->may_write() || op->may_cache()) { osd->logger->inc(l_osd_op_w); osd->logger->inc(l_osd_op_w_inb, inb); osd->logger->tinc(l_osd_op_w_rlat, rlatency); osd->logger->tinc(l_osd_op_w_lat, latency); osd->logger->tinc(l_osd_op_w_process_lat, process_latency); } else assert(0); dout(15) << "log_op_stats " << *m << " inb " << inb << " outb " << outb << " rlat " << rlatency << " lat " << latency << dendl; } void ReplicatedPG::do_sub_op(OpRequestRef op) { MOSDSubOp *m = static_cast(op->get_req()); assert(have_same_or_newer_map(m->map_epoch)); assert(m->get_header().type == MSG_OSD_SUBOP); dout(15) << "do_sub_op " << *op->get_req() << dendl; OSDOp *first = NULL; if (m->ops.size() >= 1) { first = &m->ops[0]; } if (!is_active()) { waiting_for_active.push_back(op); op->mark_delayed("waiting for active"); return; } if (first) { switch (first->op.op) { case CEPH_OSD_OP_DELETE: sub_op_remove(op); return; case CEPH_OSD_OP_SCRUB_RESERVE: sub_op_scrub_reserve(op); return; case CEPH_OSD_OP_SCRUB_UNRESERVE: sub_op_scrub_unreserve(op); return; case CEPH_OSD_OP_SCRUB_STOP: sub_op_scrub_stop(op); return; case CEPH_OSD_OP_SCRUB_MAP: sub_op_scrub_map(op); return; } } } void ReplicatedPG::do_sub_op_reply(OpRequestRef op) { MOSDSubOpReply *r = static_cast(op->get_req()); assert(r->get_header().type == MSG_OSD_SUBOPREPLY); if (r->ops.size() >= 1) { OSDOp& first = r->ops[0]; switch (first.op.op) { case CEPH_OSD_OP_SCRUB_RESERVE: sub_op_scrub_reserve_reply(op); return; } } } void ReplicatedPG::do_scan( OpRequestRef op, ThreadPool::TPHandle &handle) { MOSDPGScan *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_SCAN); dout(10) << "do_scan " << *m << dendl; op->mark_started(); switch (m->op) { case MOSDPGScan::OP_SCAN_GET_DIGEST: { double ratio, full_ratio; if (osd->too_full_for_backfill(&ratio, &full_ratio)) { dout(1) << __func__ << ": Canceling backfill, current usage is " << ratio << ", which exceeds " << full_ratio << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), BackfillTooFull()))); return; } BackfillInterval bi; bi.begin = m->begin; // No need to flush, there won't be any in progress writes occuring // past m->begin scan_range( cct->_conf->osd_backfill_scan_min, cct->_conf->osd_backfill_scan_max, &bi, handle); MOSDPGScan *reply = new MOSDPGScan( MOSDPGScan::OP_SCAN_DIGEST, pg_whoami, get_osdmap()->get_epoch(), m->query_epoch, spg_t(info.pgid.pgid, get_primary().shard), bi.begin, bi.end); ::encode(bi.objects, reply->get_data()); osd->send_message_osd_cluster(reply, m->get_connection()); } break; case MOSDPGScan::OP_SCAN_DIGEST: { pg_shard_t from = m->from; // Check that from is in backfill_targets vector assert(is_backfill_targets(from)); BackfillInterval bi; bi.begin = m->begin; bi.end = m->end; bufferlist::iterator p = m->get_data().begin(); ::decode(bi.objects, p); // handle hobject_t encoding change if (bi.objects.size() && bi.objects.begin()->first.pool == -1) { map tmp; tmp.swap(bi.objects); for (map::iterator i = tmp.begin(); i != tmp.end(); ++i) { hobject_t first(i->first); if (!first.is_max() && first.pool == -1) first.pool = info.pgid.pool(); bi.objects[first] = i->second; } } peer_backfill_info[from] = bi; if (waiting_on_backfill.find(from) != waiting_on_backfill.end()) { waiting_on_backfill.erase(from); if (waiting_on_backfill.empty()) { assert(peer_backfill_info.size() == backfill_targets.size()); finish_recovery_op(hobject_t::get_max()); } } else { // we canceled backfill for a while due to a too full, and this // is an extra response from a non-too-full peer } } break; } } void ReplicatedBackend::_do_push(OpRequestRef op) { MOSDPGPush *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_PUSH); pg_shard_t from = m->from; vector replies; ObjectStore::Transaction *t = new ObjectStore::Transaction; for (vector::iterator i = m->pushes.begin(); i != m->pushes.end(); ++i) { replies.push_back(PushReplyOp()); handle_push(from, *i, &(replies.back()), t); } MOSDPGPushReply *reply = new MOSDPGPushReply; reply->from = get_parent()->whoami_shard(); reply->set_priority(m->get_priority()); reply->pgid = get_info().pgid; reply->map_epoch = m->map_epoch; reply->replies.swap(replies); reply->compute_cost(cct); t->register_on_complete( new PG_SendMessageOnConn( get_parent(), reply, m->get_connection())); t->register_on_applied( new ObjectStore::C_DeleteTransaction(t)); get_parent()->queue_transaction(t); } struct C_ReplicatedBackend_OnPullComplete : GenContext { ReplicatedBackend *bc; list to_continue; int priority; C_ReplicatedBackend_OnPullComplete(ReplicatedBackend *bc, int priority) : bc(bc), priority(priority) {} void finish(ThreadPool::TPHandle &handle) { ReplicatedBackend::RPGHandle *h = bc->_open_recovery_op(); for (list::iterator i = to_continue.begin(); i != to_continue.end(); ++i) { map::iterator j = bc->pulling.find(*i); assert(j != bc->pulling.end()); if (!bc->start_pushes(*i, j->second.obc, h)) { bc->get_parent()->on_global_recover( *i); } bc->pulling.erase(*i); handle.reset_tp_timeout(); } bc->run_recovery_op(h, priority); } }; void ReplicatedBackend::_do_pull_response(OpRequestRef op) { MOSDPGPush *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_PUSH); pg_shard_t from = m->from; vector replies(1); ObjectStore::Transaction *t = new ObjectStore::Transaction; list to_continue; for (vector::iterator i = m->pushes.begin(); i != m->pushes.end(); ++i) { bool more = handle_pull_response(from, *i, &(replies.back()), &to_continue, t); if (more) replies.push_back(PullOp()); } if (!to_continue.empty()) { C_ReplicatedBackend_OnPullComplete *c = new C_ReplicatedBackend_OnPullComplete( this, m->get_priority()); c->to_continue.swap(to_continue); t->register_on_complete( new PG_QueueAsync( get_parent(), get_parent()->bless_gencontext(c))); } replies.erase(replies.end() - 1); if (replies.size()) { MOSDPGPull *reply = new MOSDPGPull; reply->from = parent->whoami_shard(); reply->set_priority(m->get_priority()); reply->pgid = get_info().pgid; reply->map_epoch = m->map_epoch; reply->pulls.swap(replies); reply->compute_cost(cct); t->register_on_complete( new PG_SendMessageOnConn( get_parent(), reply, m->get_connection())); } t->register_on_applied( new ObjectStore::C_DeleteTransaction(t)); get_parent()->queue_transaction(t); } void ReplicatedBackend::do_pull(OpRequestRef op) { MOSDPGPull *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_PULL); pg_shard_t from = m->from; map > replies; for (vector::iterator i = m->pulls.begin(); i != m->pulls.end(); ++i) { replies[from].push_back(PushOp()); handle_pull(from, *i, &(replies[from].back())); } send_pushes(m->get_priority(), replies); } void ReplicatedBackend::do_push_reply(OpRequestRef op) { MOSDPGPushReply *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_PUSH_REPLY); pg_shard_t from = m->from; vector replies(1); for (vector::iterator i = m->replies.begin(); i != m->replies.end(); ++i) { bool more = handle_push_reply(from, *i, &(replies.back())); if (more) replies.push_back(PushOp()); } replies.erase(replies.end() - 1); map > _replies; _replies[from].swap(replies); send_pushes(m->get_priority(), _replies); } void ReplicatedPG::do_backfill(OpRequestRef op) { MOSDPGBackfill *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_BACKFILL); dout(10) << "do_backfill " << *m << dendl; op->mark_started(); switch (m->op) { case MOSDPGBackfill::OP_BACKFILL_FINISH: { assert(cct->_conf->osd_kill_backfill_at != 1); MOSDPGBackfill *reply = new MOSDPGBackfill( MOSDPGBackfill::OP_BACKFILL_FINISH_ACK, get_osdmap()->get_epoch(), m->query_epoch, spg_t(info.pgid.pgid, primary.shard)); reply->set_priority(cct->_conf->osd_recovery_op_priority); osd->send_message_osd_cluster(reply, m->get_connection()); queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), RecoveryDone()))); } // fall-thru case MOSDPGBackfill::OP_BACKFILL_PROGRESS: { assert(cct->_conf->osd_kill_backfill_at != 2); info.last_backfill = m->last_backfill; if (m->compat_stat_sum) { info.stats.stats = m->stats.stats; // Previously, we only sent sum } else { info.stats = m->stats; } ObjectStore::Transaction *t = new ObjectStore::Transaction; dirty_info = true; write_if_dirty(*t); int tr = osd->store->queue_transaction_and_cleanup(osr.get(), t); assert(tr == 0); } break; case MOSDPGBackfill::OP_BACKFILL_FINISH_ACK: { assert(is_primary()); assert(cct->_conf->osd_kill_backfill_at != 3); finish_recovery_op(hobject_t::get_max()); } break; } } ReplicatedPG::RepGather *ReplicatedPG::trim_object(const hobject_t &coid) { // load clone info bufferlist bl; ObjectContextRef obc = get_object_context(coid, false, NULL); if (!obc) { derr << __func__ << "could not find coid " << coid << dendl; assert(0); } assert(obc->ssc); if (!obc->get_snaptrimmer_write()) { dout(10) << __func__ << ": Unable to get a wlock on " << coid << dendl; return NULL; } hobject_t snapoid( coid.oid, coid.get_key(), obc->ssc->snapset.head_exists ? CEPH_NOSNAP:CEPH_SNAPDIR, coid.hash, info.pgid.pool(), coid.get_namespace()); ObjectContextRef snapset_obc = get_object_context(snapoid, false); if (!snapset_obc->get_snaptrimmer_write()) { dout(10) << __func__ << ": Unable to get a wlock on " << snapoid << dendl; list to_wake; bool requeue_recovery = false; bool requeue_snaptrimmer = false; obc->put_write(&to_wake, &requeue_recovery, &requeue_snaptrimmer); assert(to_wake.empty()); assert(!requeue_recovery); return NULL; } object_info_t &coi = obc->obs.oi; set old_snaps(coi.snaps.begin(), coi.snaps.end()); assert(old_snaps.size()); SnapSet& snapset = obc->ssc->snapset; dout(10) << coid << " old_snaps " << old_snaps << " old snapset " << snapset << dendl; assert(snapset.seq); RepGather *repop = simple_repop_create(obc); OpContext *ctx = repop->ctx; ctx->snapset_obc = snapset_obc; ctx->lock_to_release = OpContext::W_LOCK; ctx->release_snapset_obc = true; ctx->at_version = get_next_version(); PGBackend::PGTransaction *t = ctx->op_t; set new_snaps; for (set::iterator i = old_snaps.begin(); i != old_snaps.end(); ++i) { if (!pool.info.is_removed_snap(*i)) new_snaps.insert(*i); } if (new_snaps.empty()) { // remove clone dout(10) << coid << " snaps " << old_snaps << " -> " << new_snaps << " ... deleting" << dendl; // ...from snapset snapid_t last = coid.snap; vector::iterator p; for (p = snapset.clones.begin(); p != snapset.clones.end(); ++p) if (*p == last) break; assert(p != snapset.clones.end()); object_stat_sum_t delta; delta.num_bytes -= snapset.get_clone_bytes(last); if (p != snapset.clones.begin()) { // not the oldest... merge overlap into next older clone vector::iterator n = p - 1; hobject_t prev_coid = coid; prev_coid.snap = *n; bool adjust_prev_bytes = is_present_clone(prev_coid); if (adjust_prev_bytes) delta.num_bytes -= snapset.get_clone_bytes(*n); snapset.clone_overlap[*n].intersection_of( snapset.clone_overlap[*p]); if (adjust_prev_bytes) delta.num_bytes += snapset.get_clone_bytes(*n); } delta.num_objects--; if (coi.is_dirty()) delta.num_objects_dirty--; if (coi.is_omap()) delta.num_objects_omap--; if (coi.is_whiteout()) { dout(20) << __func__ << " trimming whiteout on " << coid << dendl; delta.num_whiteouts--; } delta.num_object_clones--; info.stats.stats.add(delta, obc->obs.oi.category); obc->obs.exists = false; snapset.clones.erase(p); snapset.clone_overlap.erase(last); snapset.clone_size.erase(last); ctx->log.push_back( pg_log_entry_t( pg_log_entry_t::DELETE, coid, ctx->at_version, ctx->obs->oi.version, 0, osd_reqid_t(), ctx->mtime) ); if (pool.info.require_rollback()) { set snaps( ctx->obc->obs.oi.snaps.begin(), ctx->obc->obs.oi.snaps.end()); ctx->log.back().mod_desc.update_snaps(snaps); if (ctx->log.back().mod_desc.rmobject(ctx->at_version.version)) { t->stash(coid, ctx->at_version.version); } else { t->remove(coid); } } else { t->remove(coid); ctx->log.back().mod_desc.mark_unrollbackable(); } ctx->at_version.version++; } else { // save adjusted snaps for this object dout(10) << coid << " snaps " << old_snaps << " -> " << new_snaps << dendl; coi.snaps = vector(new_snaps.rbegin(), new_snaps.rend()); coi.prior_version = coi.version; coi.version = ctx->at_version; bl.clear(); ::encode(coi, bl); setattr_maybe_cache(ctx->obc, ctx, t, OI_ATTR, bl); ctx->log.push_back( pg_log_entry_t( pg_log_entry_t::MODIFY, coid, coi.version, coi.prior_version, 0, osd_reqid_t(), ctx->mtime) ); if (pool.info.require_rollback()) { set changing; changing.insert(OI_ATTR); ctx->obc->fill_in_setattrs(changing, &(ctx->log.back().mod_desc)); set snaps( ctx->obc->obs.oi.snaps.begin(), ctx->obc->obs.oi.snaps.end()); ctx->log.back().mod_desc.update_snaps(old_snaps); } else { ctx->log.back().mod_desc.mark_unrollbackable(); } ::encode(coi.snaps, ctx->log.back().snaps); ctx->at_version.version++; } // save head snapset dout(10) << coid << " new snapset " << snapset << dendl; if (snapset.clones.empty() && !snapset.head_exists) { dout(10) << coid << " removing " << snapoid << dendl; ctx->log.push_back( pg_log_entry_t( pg_log_entry_t::DELETE, snapoid, ctx->at_version, ctx->snapset_obc->obs.oi.version, 0, osd_reqid_t(), ctx->mtime) ); ctx->snapset_obc->obs.exists = false; if (pool.info.require_rollback()) { if (ctx->log.back().mod_desc.rmobject(ctx->at_version.version)) { t->stash(snapoid, ctx->at_version.version); } else { t->remove(snapoid); } } else { t->remove(snapoid); ctx->log.back().mod_desc.mark_unrollbackable(); } } else { dout(10) << coid << " updating snapset on " << snapoid << dendl; ctx->log.push_back( pg_log_entry_t( pg_log_entry_t::MODIFY, snapoid, ctx->at_version, ctx->snapset_obc->obs.oi.version, 0, osd_reqid_t(), ctx->mtime) ); ctx->snapset_obc->obs.oi.prior_version = ctx->snapset_obc->obs.oi.version; ctx->snapset_obc->obs.oi.version = ctx->at_version; bl.clear(); ::encode(snapset, bl); setattr_maybe_cache(ctx->snapset_obc, ctx, t, SS_ATTR, bl); bl.clear(); ::encode(ctx->snapset_obc->obs.oi, bl); setattr_maybe_cache(ctx->snapset_obc, ctx, t, OI_ATTR, bl); if (pool.info.require_rollback()) { set changing; changing.insert(OI_ATTR); changing.insert(SS_ATTR); ctx->snapset_obc->fill_in_setattrs(changing, &(ctx->log.back().mod_desc)); } else { ctx->log.back().mod_desc.mark_unrollbackable(); } } return repop; } void ReplicatedPG::snap_trimmer() { if (g_conf->osd_snap_trim_sleep > 0) { utime_t t; t.set_from_double(g_conf->osd_snap_trim_sleep); t.sleep(); lock(); dout(20) << __func__ << " slept for " << t << dendl; } else { lock(); } if (deleting) { unlock(); return; } dout(10) << "snap_trimmer entry" << dendl; if (is_primary()) { entity_inst_t nobody; if (scrubber.active) { dout(10) << " scrubbing, will requeue snap_trimmer after" << dendl; scrubber.queue_snap_trim = true; unlock(); return; } dout(10) << "snap_trimmer posting" << dendl; snap_trimmer_machine.process_event(SnapTrim()); if (snap_trimmer_machine.need_share_pg_info) { dout(10) << "snap_trimmer share_pg_info" << dendl; snap_trimmer_machine.need_share_pg_info = false; share_pg_info(); } } else if (is_active() && last_complete_ondisk.epoch > info.history.last_epoch_started) { // replica collection trimming snap_trimmer_machine.process_event(SnapTrim()); } unlock(); return; } int ReplicatedPG::do_xattr_cmp_u64(int op, __u64 v1, bufferlist& xattr) { __u64 v2; if (xattr.length()) v2 = atoll(xattr.c_str()); else v2 = 0; dout(20) << "do_xattr_cmp_u64 '" << v1 << "' vs '" << v2 << "' op " << op << dendl; switch (op) { case CEPH_OSD_CMPXATTR_OP_EQ: return (v1 == v2); case CEPH_OSD_CMPXATTR_OP_NE: return (v1 != v2); case CEPH_OSD_CMPXATTR_OP_GT: return (v1 > v2); case CEPH_OSD_CMPXATTR_OP_GTE: return (v1 >= v2); case CEPH_OSD_CMPXATTR_OP_LT: return (v1 < v2); case CEPH_OSD_CMPXATTR_OP_LTE: return (v1 <= v2); default: return -EINVAL; } } int ReplicatedPG::do_xattr_cmp_str(int op, string& v1s, bufferlist& xattr) { string v2s(xattr.c_str(), xattr.length()); dout(20) << "do_xattr_cmp_str '" << v1s << "' vs '" << v2s << "' op " << op << dendl; switch (op) { case CEPH_OSD_CMPXATTR_OP_EQ: return (v1s.compare(v2s) == 0); case CEPH_OSD_CMPXATTR_OP_NE: return (v1s.compare(v2s) != 0); case CEPH_OSD_CMPXATTR_OP_GT: return (v1s.compare(v2s) > 0); case CEPH_OSD_CMPXATTR_OP_GTE: return (v1s.compare(v2s) >= 0); case CEPH_OSD_CMPXATTR_OP_LT: return (v1s.compare(v2s) < 0); case CEPH_OSD_CMPXATTR_OP_LTE: return (v1s.compare(v2s) <= 0); default: return -EINVAL; } } // ======================================================================== // low level osd ops int ReplicatedPG::do_tmap2omap(OpContext *ctx, unsigned flags) { dout(20) << " convert tmap to omap for " << ctx->new_obs.oi.soid << dendl; bufferlist header, vals; int r = _get_tmap(ctx, &header, &vals); if (r < 0) { if (r == -ENODATA && (flags & CEPH_OSD_TMAP2OMAP_NULLOK)) r = 0; return r; } vector ops(3); ops[0].op.op = CEPH_OSD_OP_TRUNCATE; ops[0].op.extent.offset = 0; ops[0].op.extent.length = 0; ops[1].op.op = CEPH_OSD_OP_OMAPSETHEADER; ops[1].indata.claim(header); ops[2].op.op = CEPH_OSD_OP_OMAPSETVALS; ops[2].indata.claim(vals); return do_osd_ops(ctx, ops); } int ReplicatedPG::do_tmapup_slow(OpContext *ctx, bufferlist::iterator& bp, OSDOp& osd_op, bufferlist& bl) { // decode bufferlist header; map m; if (bl.length()) { bufferlist::iterator p = bl.begin(); ::decode(header, p); ::decode(m, p); assert(p.end()); } // do the update(s) while (!bp.end()) { __u8 op; string key; ::decode(op, bp); switch (op) { case CEPH_OSD_TMAP_SET: // insert key { ::decode(key, bp); bufferlist data; ::decode(data, bp); m[key] = data; } break; case CEPH_OSD_TMAP_RM: // remove key ::decode(key, bp); if (!m.count(key)) { return -ENOENT; } m.erase(key); break; case CEPH_OSD_TMAP_RMSLOPPY: // remove key ::decode(key, bp); m.erase(key); break; case CEPH_OSD_TMAP_HDR: // update header { ::decode(header, bp); } break; default: return -EINVAL; } } // reencode bufferlist obl; ::encode(header, obl); ::encode(m, obl); // write it out vector nops(1); OSDOp& newop = nops[0]; newop.op.op = CEPH_OSD_OP_WRITEFULL; newop.op.extent.offset = 0; newop.op.extent.length = obl.length(); newop.indata = obl; do_osd_ops(ctx, nops); osd_op.outdata.claim(newop.outdata); return 0; } int ReplicatedPG::do_tmapup(OpContext *ctx, bufferlist::iterator& bp, OSDOp& osd_op) { bufferlist::iterator orig_bp = bp; int result = 0; if (bp.end()) { dout(10) << "tmapup is a no-op" << dendl; } else { // read the whole object vector nops(1); OSDOp& newop = nops[0]; newop.op.op = CEPH_OSD_OP_READ; newop.op.extent.offset = 0; newop.op.extent.length = 0; do_osd_ops(ctx, nops); dout(10) << "tmapup read " << newop.outdata.length() << dendl; dout(30) << " starting is \n"; newop.outdata.hexdump(*_dout); *_dout << dendl; bufferlist::iterator ip = newop.outdata.begin(); bufferlist obl; dout(30) << "the update command is: \n"; osd_op.indata.hexdump(*_dout); *_dout << dendl; // header bufferlist header; __u32 nkeys = 0; if (newop.outdata.length()) { ::decode(header, ip); ::decode(nkeys, ip); } dout(10) << "tmapup header " << header.length() << dendl; if (!bp.end() && *bp == CEPH_OSD_TMAP_HDR) { ++bp; ::decode(header, bp); dout(10) << "tmapup new header " << header.length() << dendl; } ::encode(header, obl); dout(20) << "tmapup initial nkeys " << nkeys << dendl; // update keys bufferlist newkeydata; string nextkey, last_in_key; bufferlist nextval; bool have_next = false; string last_disk_key; if (!ip.end()) { have_next = true; ::decode(nextkey, ip); ::decode(nextval, ip); if (nextkey < last_disk_key) { dout(5) << "tmapup warning: key '" << nextkey << "' < previous key '" << last_disk_key << "', falling back to an inefficient (unsorted) update" << dendl; bp = orig_bp; return do_tmapup_slow(ctx, bp, osd_op, newop.outdata); } last_disk_key = nextkey; } result = 0; while (!bp.end() && !result) { __u8 op; string key; try { ::decode(op, bp); ::decode(key, bp); } catch (buffer::error& e) { return -EINVAL; } if (key < last_in_key) { dout(5) << "tmapup warning: key '" << key << "' < previous key '" << last_in_key << "', falling back to an inefficient (unsorted) update" << dendl; bp = orig_bp; return do_tmapup_slow(ctx, bp, osd_op, newop.outdata); } last_in_key = key; dout(10) << "tmapup op " << (int)op << " key " << key << dendl; // skip existing intervening keys bool key_exists = false; while (have_next && !key_exists) { dout(20) << " (have_next=" << have_next << " nextkey=" << nextkey << ")" << dendl; if (nextkey > key) break; if (nextkey < key) { // copy untouched. ::encode(nextkey, newkeydata); ::encode(nextval, newkeydata); dout(20) << " keep " << nextkey << " " << nextval.length() << dendl; } else { // don't copy; discard old value. and stop. dout(20) << " drop " << nextkey << " " << nextval.length() << dendl; key_exists = true; nkeys--; } if (!ip.end()) { ::decode(nextkey, ip); ::decode(nextval, ip); } else { have_next = false; } } if (op == CEPH_OSD_TMAP_SET) { bufferlist val; try { ::decode(val, bp); } catch (buffer::error& e) { return -EINVAL; } ::encode(key, newkeydata); ::encode(val, newkeydata); dout(20) << " set " << key << " " << val.length() << dendl; nkeys++; } else if (op == CEPH_OSD_TMAP_CREATE) { if (key_exists) { return -EEXIST; } bufferlist val; try { ::decode(val, bp); } catch (buffer::error& e) { return -EINVAL; } ::encode(key, newkeydata); ::encode(val, newkeydata); dout(20) << " create " << key << " " << val.length() << dendl; nkeys++; } else if (op == CEPH_OSD_TMAP_RM) { // do nothing. if (!key_exists) { return -ENOENT; } } else if (op == CEPH_OSD_TMAP_RMSLOPPY) { // do nothing } else { dout(10) << " invalid tmap op " << (int)op << dendl; return -EINVAL; } } // copy remaining if (have_next) { ::encode(nextkey, newkeydata); ::encode(nextval, newkeydata); dout(20) << " keep " << nextkey << " " << nextval.length() << dendl; } if (!ip.end()) { bufferlist rest; rest.substr_of(newop.outdata, ip.get_off(), newop.outdata.length() - ip.get_off()); dout(20) << " keep trailing " << rest.length() << " at " << newkeydata.length() << dendl; newkeydata.claim_append(rest); } // encode final key count + key data dout(20) << "tmapup final nkeys " << nkeys << dendl; ::encode(nkeys, obl); obl.claim_append(newkeydata); if (0) { dout(30) << " final is \n"; obl.hexdump(*_dout); *_dout << dendl; // sanity check bufferlist::iterator tp = obl.begin(); bufferlist h; ::decode(h, tp); map d; ::decode(d, tp); assert(tp.end()); dout(0) << " **** debug sanity check, looks ok ****" << dendl; } // write it out if (!result) { dout(20) << "tmapput write " << obl.length() << dendl; newop.op.op = CEPH_OSD_OP_WRITEFULL; newop.op.extent.offset = 0; newop.op.extent.length = obl.length(); newop.indata = obl; do_osd_ops(ctx, nops); osd_op.outdata.claim(newop.outdata); } } return result; } static int check_offset_and_length(uint64_t offset, uint64_t length, uint64_t max) { if (offset >= max || length > max || offset + length > max) return -EFBIG; return 0; } struct FillInExtent : public Context { ceph_le64 *r; FillInExtent(ceph_le64 *r) : r(r) {} void finish(int _r) { if (_r >= 0) { *r = _r; } } }; int ReplicatedPG::do_osd_ops(OpContext *ctx, vector& ops) { int result = 0; SnapSetContext *ssc = ctx->obc->ssc; ObjectState& obs = ctx->new_obs; object_info_t& oi = obs.oi; const hobject_t& soid = oi.soid; bool first_read = true; PGBackend::PGTransaction* t = ctx->op_t; dout(10) << "do_osd_op " << soid << " " << ops << dendl; for (vector::iterator p = ops.begin(); p != ops.end(); ++p, ctx->current_osd_subop_num++) { OSDOp& osd_op = *p; ceph_osd_op& op = osd_op.op; dout(10) << "do_osd_op " << osd_op << dendl; bufferlist::iterator bp = osd_op.indata.begin(); // user-visible modifcation? switch (op.op) { // non user-visible modifications case CEPH_OSD_OP_WATCH: case CEPH_OSD_OP_CACHE_EVICT: case CEPH_OSD_OP_CACHE_FLUSH: case CEPH_OSD_OP_CACHE_TRY_FLUSH: case CEPH_OSD_OP_UNDIRTY: case CEPH_OSD_OP_COPY_FROM: // we handle user_version update explicitly break; default: if (op.op & CEPH_OSD_OP_MODE_WR) ctx->user_modify = true; } ObjectContextRef src_obc; if (ceph_osd_op_type_multi(op.op)) { MOSDOp *m = static_cast(ctx->op->get_req()); object_locator_t src_oloc; get_src_oloc(soid.oid, m->get_object_locator(), src_oloc); hobject_t src_oid(osd_op.soid, src_oloc.key, soid.hash, info.pgid.pool(), src_oloc.nspace); src_obc = ctx->src_obc[src_oid]; dout(10) << " src_oid " << src_oid << " obc " << src_obc << dendl; assert(src_obc); } // munge -1 truncate to 0 truncate if (op.extent.truncate_seq == 1 && op.extent.truncate_size == (-1ULL)) { op.extent.truncate_size = 0; op.extent.truncate_seq = 0; } // munge ZERO -> TRUNCATE? (don't munge to DELETE or we risk hosing attributes) if (op.op == CEPH_OSD_OP_ZERO && obs.exists && op.extent.offset < cct->_conf->osd_max_object_size && op.extent.length >= 1 && op.extent.length <= cct->_conf->osd_max_object_size && op.extent.offset + op.extent.length >= oi.size) { if (op.extent.offset >= oi.size) { // no-op goto fail; } dout(10) << " munging ZERO " << op.extent.offset << "~" << op.extent.length << " -> TRUNCATE " << op.extent.offset << " (old size is " << oi.size << ")" << dendl; op.op = CEPH_OSD_OP_TRUNCATE; } switch (op.op) { // --- READS --- case CEPH_OSD_OP_SYNC_READ: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } // fall through case CEPH_OSD_OP_READ: ++ctx->num_read; { __u32 seq = oi.truncate_seq; uint64_t size = oi.size; bool trimmed_read = false; // are we beyond truncate_size? if ( (seq < op.extent.truncate_seq) && (op.extent.offset + op.extent.length > op.extent.truncate_size) ) size = op.extent.truncate_size; if (op.extent.offset >= size) { op.extent.length = 0; trimmed_read = true; } else if (op.extent.offset + op.extent.length > size) { op.extent.length = size - op.extent.offset; trimmed_read = true; } // read into a buffer bufferlist bl; if (trimmed_read && op.extent.length == 0) { // read size was trimmed to zero and it is expected to do nothing // a read operation of 0 bytes does *not* do nothing, this is why // the trimmed_read boolean is needed } else if (pool.info.require_rollback()) { ctx->pending_async_reads.push_back( make_pair( make_pair(op.extent.offset, op.extent.length), make_pair(&osd_op.outdata, new FillInExtent(&op.extent.length)))); dout(10) << " async_read noted for " << soid << dendl; } else { int r = pgbackend->objects_read_sync( soid, op.extent.offset, op.extent.length, &osd_op.outdata); if (r >= 0) op.extent.length = r; else { result = r; op.extent.length = 0; } dout(10) << " read got " << r << " / " << op.extent.length << " bytes from obj " << soid << dendl; } if (first_read) { first_read = false; ctx->data_off = op.extent.offset; } ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(op.extent.length, 10); ctx->delta_stats.num_rd++; } break; /* map extents */ case CEPH_OSD_OP_MAPEXT: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_read; { // read into a buffer bufferlist bl; int r = osd->store->fiemap(coll, soid, op.extent.offset, op.extent.length, bl); osd_op.outdata.claim(bl); if (r < 0) result = r; ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(op.extent.length, 10); ctx->delta_stats.num_rd++; dout(10) << " map_extents done on object " << soid << dendl; } break; /* map extents */ case CEPH_OSD_OP_SPARSE_READ: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_read; { if (op.extent.truncate_seq) { dout(0) << "sparse_read does not support truncation sequence " << dendl; result = -EINVAL; break; } // read into a buffer bufferlist bl; int total_read = 0; int r = osd->store->fiemap(coll, soid, op.extent.offset, op.extent.length, bl); if (r < 0) { result = r; break; } map m; bufferlist::iterator iter = bl.begin(); ::decode(m, iter); map::iterator miter; bufferlist data_bl; uint64_t last = op.extent.offset; for (miter = m.begin(); miter != m.end(); ++miter) { // verify hole? if (cct->_conf->osd_verify_sparse_read_holes && last < miter->first) { bufferlist t; uint64_t len = miter->first - last; r = pgbackend->objects_read_sync( soid, last, len, &t); if (!t.is_zero()) { osd->clog.error() << coll << " " << soid << " sparse-read found data in hole " << last << "~" << len << "\n"; } } bufferlist tmpbl; r = pgbackend->objects_read_sync( soid, miter->first, miter->second, &tmpbl); if (r < 0) break; if (r < (int)miter->second) /* this is usually happen when we get extent that exceeds the actual file size */ miter->second = r; total_read += r; dout(10) << "sparse-read " << miter->first << "@" << miter->second << dendl; data_bl.claim_append(tmpbl); last = miter->first + r; } // verify trailing hole? if (cct->_conf->osd_verify_sparse_read_holes) { uint64_t end = MIN(op.extent.offset + op.extent.length, oi.size); if (last < end) { bufferlist t; uint64_t len = end - last; r = pgbackend->objects_read_sync( soid, last, len, &t); if (!t.is_zero()) { osd->clog.error() << coll << " " << soid << " sparse-read found data in hole " << last << "~" << len << "\n"; } } } if (r < 0) { result = r; break; } op.extent.length = total_read; ::encode(m, osd_op.outdata); ::encode(data_bl, osd_op.outdata); ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(op.extent.length, 10); ctx->delta_stats.num_rd++; dout(10) << " sparse_read got " << total_read << " bytes from object " << soid << dendl; } break; case CEPH_OSD_OP_CALL: { string cname, mname; bufferlist indata; try { bp.copy(op.cls.class_len, cname); bp.copy(op.cls.method_len, mname); bp.copy(op.cls.indata_len, indata); } catch (buffer::error& e) { dout(10) << "call unable to decode class + method + indata" << dendl; dout(30) << "in dump: "; osd_op.indata.hexdump(*_dout); *_dout << dendl; result = -EINVAL; break; } ClassHandler::ClassData *cls; result = osd->class_handler->open_class(cname, &cls); assert(result == 0); // init_op_flags() already verified this works. ClassHandler::ClassMethod *method = cls->get_method(mname.c_str()); if (!method) { dout(10) << "call method " << cname << "." << mname << " does not exist" << dendl; result = -EOPNOTSUPP; break; } int flags = method->get_flags(); if (flags & CLS_METHOD_WR) ctx->user_modify = true; bufferlist outdata; dout(10) << "call method " << cname << "." << mname << dendl; int prev_rd = ctx->num_read; int prev_wr = ctx->num_write; result = method->exec((cls_method_context_t)&ctx, indata, outdata); if (ctx->num_read > prev_rd && !(flags & CLS_METHOD_RD)) { derr << "method " << cname << "." << mname << " tried to read object but is not marked RD" << dendl; result = -EIO; break; } if (ctx->num_write > prev_wr && !(flags & CLS_METHOD_WR)) { derr << "method " << cname << "." << mname << " tried to update object but is not marked WR" << dendl; result = -EIO; break; } dout(10) << "method called response length=" << outdata.length() << dendl; op.extent.length = outdata.length(); osd_op.outdata.claim_append(outdata); dout(30) << "out dump: "; osd_op.outdata.hexdump(*_dout); *_dout << dendl; } break; case CEPH_OSD_OP_STAT: // note: stat does not require RD { if (obs.exists && !oi.is_whiteout()) { ::encode(oi.size, osd_op.outdata); ::encode(oi.mtime, osd_op.outdata); dout(10) << "stat oi has " << oi.size << " " << oi.mtime << dendl; } else { result = -ENOENT; dout(10) << "stat oi object does not exist" << dendl; } ctx->delta_stats.num_rd++; } break; case CEPH_OSD_OP_ISDIRTY: ++ctx->num_read; { bool is_dirty = obs.oi.is_dirty(); ::encode(is_dirty, osd_op.outdata); ctx->delta_stats.num_rd++; result = 0; } break; case CEPH_OSD_OP_UNDIRTY: ++ctx->num_write; { if (oi.is_dirty()) { ctx->undirty = true; // see make_writeable() ctx->modify = true; ctx->delta_stats.num_wr++; } result = 0; } break; case CEPH_OSD_OP_CACHE_TRY_FLUSH: ++ctx->num_write; { if (ctx->lock_to_release != OpContext::NONE) { dout(10) << "cache-try-flush without SKIPRWLOCKS flag set" << dendl; result = -EINVAL; break; } if (pool.info.cache_mode == pg_pool_t::CACHEMODE_NONE) { result = -EINVAL; break; } if (!obs.exists) { result = 0; break; } if (oi.is_dirty()) { result = start_flush(ctx->op, ctx->obc, false, NULL, NULL); if (result == -EINPROGRESS) result = -EAGAIN; } else { result = 0; } } break; case CEPH_OSD_OP_CACHE_FLUSH: ++ctx->num_write; { if (ctx->lock_to_release == OpContext::NONE) { dout(10) << "cache-flush with SKIPRWLOCKS flag set" << dendl; result = -EINVAL; break; } if (pool.info.cache_mode == pg_pool_t::CACHEMODE_NONE) { result = -EINVAL; break; } if (!obs.exists) { result = 0; break; } hobject_t missing; if (oi.is_dirty()) { result = start_flush(ctx->op, ctx->obc, true, &missing, NULL); if (result == -EINPROGRESS) result = -EAGAIN; } else { result = 0; } // Check special return value which has set missing_return if (result == -ENOENT) { dout(10) << __func__ << " CEPH_OSD_OP_CACHE_FLUSH got ENOENT" << dendl; assert(!missing.is_min()); wait_for_unreadable_object(missing, ctx->op); // Error code which is used elsewhere when wait_for_unreadable_object() is used result = -EAGAIN; } } break; case CEPH_OSD_OP_CACHE_EVICT: ++ctx->num_write; { if (pool.info.cache_mode == pg_pool_t::CACHEMODE_NONE) { result = -EINVAL; break; } if (oi.is_dirty()) { result = -EBUSY; break; } if (!oi.watchers.empty()) { result = -EBUSY; break; } if (soid.snap == CEPH_NOSNAP) { result = _verify_no_head_clones(soid, ssc->snapset); if (result < 0) break; } result = _delete_oid(ctx, true); if (result >= 0) { // mark that this is a cache eviction to avoid triggering normal // make_writeable() clone or snapdir object creation in finish_ctx() ctx->cache_evict = true; } osd->logger->inc(l_osd_tier_evict); } break; case CEPH_OSD_OP_GETXATTR: ++ctx->num_read; { string aname; bp.copy(op.xattr.name_len, aname); string name = "_" + aname; int r = getattr_maybe_cache( ctx->obc, name, &(osd_op.outdata)); if (r >= 0) { op.xattr.value_len = r; result = 0; ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(r, 10); ctx->delta_stats.num_rd++; } else result = r; } break; case CEPH_OSD_OP_GETXATTRS: ++ctx->num_read; { map out; result = getattrs_maybe_cache( ctx->obc, &out, true); bufferlist bl; ::encode(out, bl); ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(bl.length(), 10); ctx->delta_stats.num_rd++; osd_op.outdata.claim_append(bl); } break; case CEPH_OSD_OP_CMPXATTR: case CEPH_OSD_OP_SRC_CMPXATTR: ++ctx->num_read; { string aname; bp.copy(op.xattr.name_len, aname); string name = "_" + aname; name[op.xattr.name_len + 1] = 0; bufferlist xattr; if (op.op == CEPH_OSD_OP_CMPXATTR) result = getattr_maybe_cache( ctx->obc, name, &xattr); else result = getattr_maybe_cache( src_obc, name, &xattr); if (result < 0 && result != -EEXIST && result != -ENODATA) break; ctx->delta_stats.num_rd++; ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(xattr.length(), 10); switch (op.xattr.cmp_mode) { case CEPH_OSD_CMPXATTR_MODE_STRING: { string val; bp.copy(op.xattr.value_len, val); val[op.xattr.value_len] = 0; dout(10) << "CEPH_OSD_OP_CMPXATTR name=" << name << " val=" << val << " op=" << (int)op.xattr.cmp_op << " mode=" << (int)op.xattr.cmp_mode << dendl; result = do_xattr_cmp_str(op.xattr.cmp_op, val, xattr); } break; case CEPH_OSD_CMPXATTR_MODE_U64: { uint64_t u64val; try { ::decode(u64val, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } dout(10) << "CEPH_OSD_OP_CMPXATTR name=" << name << " val=" << u64val << " op=" << (int)op.xattr.cmp_op << " mode=" << (int)op.xattr.cmp_mode << dendl; result = do_xattr_cmp_u64(op.xattr.cmp_op, u64val, xattr); } break; default: dout(10) << "bad cmp mode " << (int)op.xattr.cmp_mode << dendl; result = -EINVAL; } if (!result) { dout(10) << "comparison returned false" << dendl; result = -ECANCELED; break; } if (result < 0) { dout(10) << "comparison returned " << result << " " << cpp_strerror(-result) << dendl; break; } dout(10) << "comparison returned true" << dendl; } break; case CEPH_OSD_OP_ASSERT_VER: ++ctx->num_read; { uint64_t ver = op.watch.ver; if (!ver) result = -EINVAL; else if (ver < oi.user_version) result = -ERANGE; else if (ver > oi.user_version) result = -EOVERFLOW; } break; case CEPH_OSD_OP_LIST_WATCHERS: ++ctx->num_read; { obj_list_watch_response_t resp; map, watch_info_t>::const_iterator oi_iter; for (oi_iter = oi.watchers.begin(); oi_iter != oi.watchers.end(); ++oi_iter) { dout(20) << "key cookie=" << oi_iter->first.first << " entity=" << oi_iter->first.second << " " << oi_iter->second << dendl; assert(oi_iter->first.first == oi_iter->second.cookie); assert(oi_iter->first.second.is_client()); watch_item_t wi(oi_iter->first.second, oi_iter->second.cookie, oi_iter->second.timeout_seconds, oi_iter->second.addr); resp.entries.push_back(wi); } resp.encode(osd_op.outdata); result = 0; ctx->delta_stats.num_rd++; break; } case CEPH_OSD_OP_LIST_SNAPS: ++ctx->num_read; { obj_list_snap_response_t resp; if (!ssc) { ssc = ctx->obc->ssc = get_snapset_context(soid, false); } assert(ssc); int clonecount = ssc->snapset.clones.size(); if (ssc->snapset.head_exists) clonecount++; resp.clones.reserve(clonecount); for (vector::const_iterator clone_iter = ssc->snapset.clones.begin(); clone_iter != ssc->snapset.clones.end(); ++clone_iter) { clone_info ci; ci.cloneid = *clone_iter; hobject_t clone_oid = soid; clone_oid.snap = *clone_iter; ObjectContextRef clone_obc = ctx->src_obc[clone_oid]; assert(clone_obc); for (vector::reverse_iterator p = clone_obc->obs.oi.snaps.rbegin(); p != clone_obc->obs.oi.snaps.rend(); ++p) { ci.snaps.push_back(*p); } dout(20) << " clone " << *clone_iter << " snaps " << ci.snaps << dendl; map >::const_iterator coi; coi = ssc->snapset.clone_overlap.find(ci.cloneid); if (coi == ssc->snapset.clone_overlap.end()) { osd->clog.error() << "osd." << osd->whoami << ": inconsistent clone_overlap found for oid " << soid << " clone " << *clone_iter; result = -EINVAL; break; } const interval_set &o = coi->second; ci.overlap.reserve(o.num_intervals()); for (interval_set::const_iterator r = o.begin(); r != o.end(); ++r) { ci.overlap.push_back(pair(r.get_start(), r.get_len())); } map::const_iterator si; si = ssc->snapset.clone_size.find(ci.cloneid); if (si == ssc->snapset.clone_size.end()) { osd->clog.error() << "osd." << osd->whoami << ": inconsistent clone_size found for oid " << soid << " clone " << *clone_iter; result = -EINVAL; break; } ci.size = si->second; resp.clones.push_back(ci); } if (ssc->snapset.head_exists && !ctx->obc->obs.oi.is_whiteout()) { assert(obs.exists); clone_info ci; ci.cloneid = CEPH_NOSNAP; //Size for HEAD is oi.size ci.size = oi.size; resp.clones.push_back(ci); } resp.seq = ssc->snapset.seq; resp.encode(osd_op.outdata); result = 0; ctx->delta_stats.num_rd++; break; } case CEPH_OSD_OP_ASSERT_SRC_VERSION: ++ctx->num_read; { uint64_t ver = op.assert_ver.ver; if (!ver) result = -EINVAL; else if (ver < src_obc->obs.oi.user_version) result = -ERANGE; else if (ver > src_obc->obs.oi.user_version) result = -EOVERFLOW; break; } case CEPH_OSD_OP_NOTIFY: ++ctx->num_read; { uint32_t ver; uint32_t timeout; bufferlist bl; try { ::decode(ver, bp); ::decode(timeout, bp); ::decode(bl, bp); } catch (const buffer::error &e) { timeout = 0; } if (!timeout) timeout = cct->_conf->osd_default_notify_timeout; notify_info_t n; n.timeout = timeout; n.cookie = op.watch.cookie; n.bl = bl; ctx->notifies.push_back(n); } break; case CEPH_OSD_OP_NOTIFY_ACK: ++ctx->num_read; { try { uint64_t notify_id = 0; uint64_t watch_cookie = 0; ::decode(notify_id, bp); ::decode(watch_cookie, bp); OpContext::NotifyAck ack(notify_id, watch_cookie); ctx->notify_acks.push_back(ack); } catch (const buffer::error &e) { OpContext::NotifyAck ack( // op.watch.cookie is actually the notify_id for historical reasons op.watch.cookie ); ctx->notify_acks.push_back(ack); } } break; case CEPH_OSD_OP_SETALLOCHINT: ++ctx->num_write; { if (!(get_min_peer_features() & CEPH_FEATURE_OSD_SET_ALLOC_HINT)) { result = -EOPNOTSUPP; break; } if (!obs.exists) { ctx->mod_desc.create(); t->touch(soid); ctx->delta_stats.num_objects++; obs.exists = true; } t->set_alloc_hint(soid, op.alloc_hint.expected_object_size, op.alloc_hint.expected_write_size); ctx->delta_stats.num_wr++; result = 0; } break; // --- WRITES --- // -- object data -- case CEPH_OSD_OP_WRITE: ++ctx->num_write; { // write if (op.extent.length != osd_op.indata.length()) { result = -EINVAL; break; } if (pool.info.requires_aligned_append() && (op.extent.offset % pool.info.required_alignment() != 0)) { result = -EOPNOTSUPP; break; } if (!obs.exists) { if (pool.info.require_rollback() && op.extent.offset) { result = -EOPNOTSUPP; break; } ctx->mod_desc.create(); } else if (op.extent.offset == oi.size) { ctx->mod_desc.append(oi.size); } else { ctx->mod_desc.mark_unrollbackable(); if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } } __u32 seq = oi.truncate_seq; if (seq && (seq > op.extent.truncate_seq) && (op.extent.offset + op.extent.length > oi.size)) { // old write, arrived after trimtrunc op.extent.length = (op.extent.offset > oi.size ? 0 : oi.size - op.extent.offset); dout(10) << " old truncate_seq " << op.extent.truncate_seq << " < current " << seq << ", adjusting write length to " << op.extent.length << dendl; bufferlist t; t.substr_of(osd_op.indata, 0, op.extent.length); osd_op.indata.swap(t); } if (op.extent.truncate_seq > seq) { // write arrives before trimtrunc if (obs.exists && !oi.is_whiteout()) { dout(10) << " truncate_seq " << op.extent.truncate_seq << " > current " << seq << ", truncating to " << op.extent.truncate_size << dendl; t->truncate(soid, op.extent.truncate_size); oi.truncate_seq = op.extent.truncate_seq; oi.truncate_size = op.extent.truncate_size; if (op.extent.truncate_size != oi.size) { ctx->delta_stats.num_bytes -= oi.size; ctx->delta_stats.num_bytes += op.extent.truncate_size; oi.size = op.extent.truncate_size; } } else { dout(10) << " truncate_seq " << op.extent.truncate_seq << " > current " << seq << ", but object is new" << dendl; oi.truncate_seq = op.extent.truncate_seq; oi.truncate_size = op.extent.truncate_size; } } result = check_offset_and_length(op.extent.offset, op.extent.length, cct->_conf->osd_max_object_size); if (result < 0) break; if (pool.info.require_rollback()) { t->append(soid, op.extent.offset, op.extent.length, osd_op.indata); } else { t->write(soid, op.extent.offset, op.extent.length, osd_op.indata); } write_update_size_and_usage(ctx->delta_stats, oi, ssc->snapset, ctx->modified_ranges, op.extent.offset, op.extent.length, true); if (!obs.exists) { ctx->delta_stats.num_objects++; obs.exists = true; } } break; case CEPH_OSD_OP_WRITEFULL: ++ctx->num_write; { // write full object if (op.extent.length != osd_op.indata.length()) { result = -EINVAL; break; } result = check_offset_and_length(op.extent.offset, op.extent.length, cct->_conf->osd_max_object_size); if (result < 0) break; if (pool.info.require_rollback()) { if (obs.exists) { if (ctx->mod_desc.rmobject(ctx->at_version.version)) { t->stash(soid, ctx->at_version.version); } else { t->remove(soid); } } ctx->mod_desc.create(); t->append(soid, op.extent.offset, op.extent.length, osd_op.indata); if (obs.exists) { map to_set = ctx->obc->attr_cache; map > &overlay = ctx->pending_attrs[ctx->obc]; for (map >::iterator i = overlay.begin(); i != overlay.end(); ++i) { if (i->second) { to_set[i->first] = *(i->second); } else { to_set.erase(i->first); } } t->setattrs(soid, to_set); } } else { ctx->mod_desc.mark_unrollbackable(); if (obs.exists) { t->truncate(soid, 0); } t->write(soid, op.extent.offset, op.extent.length, osd_op.indata); } if (!obs.exists) { ctx->delta_stats.num_objects++; obs.exists = true; } interval_set ch; if (oi.size > 0) ch.insert(0, oi.size); ctx->modified_ranges.union_of(ch); if (op.extent.length + op.extent.offset != oi.size) { ctx->delta_stats.num_bytes -= oi.size; oi.size = op.extent.length + op.extent.offset; ctx->delta_stats.num_bytes += oi.size; } ctx->delta_stats.num_wr++; ctx->delta_stats.num_wr_kb += SHIFT_ROUND_UP(op.extent.length, 10); } break; case CEPH_OSD_OP_ROLLBACK : ++ctx->num_write; result = _rollback_to(ctx, op); break; case CEPH_OSD_OP_ZERO: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_write; { // zero result = check_offset_and_length(op.extent.offset, op.extent.length, cct->_conf->osd_max_object_size); if (result < 0) break; assert(op.extent.length); if (obs.exists && !oi.is_whiteout()) { ctx->mod_desc.mark_unrollbackable(); t->zero(soid, op.extent.offset, op.extent.length); interval_set ch; ch.insert(op.extent.offset, op.extent.length); ctx->modified_ranges.union_of(ch); ctx->delta_stats.num_wr++; } else { // no-op } } break; case CEPH_OSD_OP_CREATE: ++ctx->num_write; { int flags = le32_to_cpu(op.flags); if (obs.exists && !oi.is_whiteout() && (flags & CEPH_OSD_OP_FLAG_EXCL)) { result = -EEXIST; /* this is an exclusive create */ } else { if (osd_op.indata.length()) { bufferlist::iterator p = osd_op.indata.begin(); string category; try { ::decode(category, p); } catch (buffer::error& e) { result = -EINVAL; goto fail; } if (category.size()) { if (obs.exists && !oi.is_whiteout()) { if (obs.oi.category != category) result = -EEXIST; // category cannot be reset } else { obs.oi.category = category; } } } if (result >= 0) { if (!obs.exists) ctx->mod_desc.create(); t->touch(soid); if (!obs.exists) { ctx->delta_stats.num_objects++; obs.exists = true; } } } } break; case CEPH_OSD_OP_TRIMTRUNC: op.extent.offset = op.extent.truncate_size; // falling through case CEPH_OSD_OP_TRUNCATE: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_write; ctx->mod_desc.mark_unrollbackable(); { // truncate if (!obs.exists || oi.is_whiteout()) { dout(10) << " object dne, truncate is a no-op" << dendl; break; } if (op.extent.offset > cct->_conf->osd_max_object_size) { result = -EFBIG; break; } if (op.extent.truncate_seq) { assert(op.extent.offset == op.extent.truncate_size); if (op.extent.truncate_seq <= oi.truncate_seq) { dout(10) << " truncate seq " << op.extent.truncate_seq << " <= current " << oi.truncate_seq << ", no-op" << dendl; break; // old } dout(10) << " truncate seq " << op.extent.truncate_seq << " > current " << oi.truncate_seq << ", truncating" << dendl; oi.truncate_seq = op.extent.truncate_seq; oi.truncate_size = op.extent.truncate_size; } t->truncate(soid, op.extent.offset); if (oi.size > op.extent.offset) { interval_set trim; trim.insert(op.extent.offset, oi.size-op.extent.offset); ctx->modified_ranges.union_of(trim); } if (op.extent.offset != oi.size) { ctx->delta_stats.num_bytes -= oi.size; ctx->delta_stats.num_bytes += op.extent.offset; oi.size = op.extent.offset; } ctx->delta_stats.num_wr++; // do no set exists, or we will break above DELETE -> TRUNCATE munging. } break; case CEPH_OSD_OP_DELETE: ++ctx->num_write; if (ctx->obc->obs.oi.watchers.size()) { // Cannot delete an object with watchers result = -EBUSY; } else { result = _delete_oid(ctx, ctx->ignore_cache); } break; case CEPH_OSD_OP_CLONERANGE: ctx->mod_desc.mark_unrollbackable(); if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_read; ++ctx->num_write; { if (!obs.exists) { t->touch(obs.oi.soid); ctx->delta_stats.num_objects++; obs.exists = true; } if (op.clonerange.src_offset + op.clonerange.length > src_obc->obs.oi.size) { dout(10) << " clonerange source " << osd_op.soid << " " << op.clonerange.src_offset << "~" << op.clonerange.length << " extends past size " << src_obc->obs.oi.size << dendl; result = -EINVAL; break; } t->clone_range(src_obc->obs.oi.soid, obs.oi.soid, op.clonerange.src_offset, op.clonerange.length, op.clonerange.offset); write_update_size_and_usage(ctx->delta_stats, oi, ssc->snapset, ctx->modified_ranges, op.clonerange.offset, op.clonerange.length, false); } break; case CEPH_OSD_OP_WATCH: ++ctx->num_write; { if (!obs.exists) { result = -ENOENT; break; } uint64_t cookie = op.watch.cookie; bool do_watch = op.watch.flag & 1; entity_name_t entity = ctx->reqid.name; ObjectContextRef obc = ctx->obc; dout(10) << "watch: ctx->obc=" << (void *)obc.get() << " cookie=" << cookie << " oi.version=" << oi.version.version << " ctx->at_version=" << ctx->at_version << dendl; dout(10) << "watch: oi.user_version=" << oi.user_version<< dendl; dout(10) << "watch: peer_addr=" << ctx->op->get_req()->get_connection()->get_peer_addr() << dendl; watch_info_t w(cookie, cct->_conf->osd_client_watch_timeout, ctx->op->get_req()->get_connection()->get_peer_addr()); if (do_watch) { if (oi.watchers.count(make_pair(cookie, entity))) { dout(10) << " found existing watch " << w << " by " << entity << dendl; } else { dout(10) << " registered new watch " << w << " by " << entity << dendl; oi.watchers[make_pair(cookie, entity)] = w; t->nop(); // make sure update the object_info on disk! } ctx->watch_connects.push_back(w); } else { map, watch_info_t>::iterator oi_iter = oi.watchers.find(make_pair(cookie, entity)); if (oi_iter != oi.watchers.end()) { dout(10) << " removed watch " << oi_iter->second << " by " << entity << dendl; oi.watchers.erase(oi_iter); t->nop(); // update oi on disk ctx->watch_disconnects.push_back(w); } else { dout(10) << " can't remove: no watch by " << entity << dendl; } } } break; // -- object attrs -- case CEPH_OSD_OP_SETXATTR: ++ctx->num_write; { if (cct->_conf->osd_max_attr_size > 0 && op.xattr.value_len > cct->_conf->osd_max_attr_size) { result = -EFBIG; break; } if (!obs.exists) { ctx->mod_desc.create(); t->touch(soid); ctx->delta_stats.num_objects++; obs.exists = true; } string aname; bp.copy(op.xattr.name_len, aname); string name = "_" + aname; if (pool.info.require_rollback()) { map > to_set; bufferlist old; int r = getattr_maybe_cache(ctx->obc, name, &old); if (r == 0) { to_set[name] = old; } else { to_set[name]; } ctx->mod_desc.setattrs(to_set); } else { ctx->mod_desc.mark_unrollbackable(); } bufferlist bl; bp.copy(op.xattr.value_len, bl); setattr_maybe_cache(ctx->obc, ctx, t, name, bl); ctx->delta_stats.num_wr++; } break; case CEPH_OSD_OP_RMXATTR: ++ctx->num_write; { string aname; bp.copy(op.xattr.name_len, aname); string name = "_" + aname; if (pool.info.require_rollback()) { map > to_set; bufferlist old; int r = getattr_maybe_cache(ctx->obc, name, &old); if (r == 0) { to_set[name] = old; } else { to_set[name]; } ctx->mod_desc.setattrs(to_set); } else { ctx->mod_desc.mark_unrollbackable(); } rmattr_maybe_cache(ctx->obc, ctx, t, name); ctx->delta_stats.num_wr++; } break; // -- fancy writers -- case CEPH_OSD_OP_APPEND: { // just do it inline; this works because we are happy to execute // fancy op on replicas as well. vector nops(1); OSDOp& newop = nops[0]; newop.op.op = CEPH_OSD_OP_WRITE; newop.op.extent.offset = oi.size; newop.op.extent.length = op.extent.length; newop.op.extent.truncate_seq = oi.truncate_seq; newop.indata = osd_op.indata; result = do_osd_ops(ctx, nops); osd_op.outdata.claim(newop.outdata); } break; case CEPH_OSD_OP_STARTSYNC: t->nop(); break; // -- trivial map -- case CEPH_OSD_OP_TMAPGET: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_read; { vector nops(1); OSDOp& newop = nops[0]; newop.op.op = CEPH_OSD_OP_SYNC_READ; newop.op.extent.offset = 0; newop.op.extent.length = 0; do_osd_ops(ctx, nops); osd_op.outdata.claim(newop.outdata); } break; case CEPH_OSD_OP_TMAPPUT: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_write; { //_dout_lock.Lock(); //osd_op.data.hexdump(*_dout); //_dout_lock.Unlock(); // verify sort order bool unsorted = false; if (true) { bufferlist header; ::decode(header, bp); uint32_t n; ::decode(n, bp); string last_key; while (n--) { string key; ::decode(key, bp); dout(10) << "tmapput key " << key << dendl; bufferlist val; ::decode(val, bp); if (key < last_key) { dout(10) << "TMAPPUT is unordered; resorting" << dendl; unsorted = true; break; } last_key = key; } } // write it vector nops(1); OSDOp& newop = nops[0]; newop.op.op = CEPH_OSD_OP_WRITEFULL; newop.op.extent.offset = 0; newop.op.extent.length = osd_op.indata.length(); newop.indata = osd_op.indata; if (unsorted) { bp = osd_op.indata.begin(); bufferlist header; map m; ::decode(header, bp); ::decode(m, bp); assert(bp.end()); bufferlist newbl; ::encode(header, newbl); ::encode(m, newbl); newop.indata = newbl; } do_osd_ops(ctx, nops); } break; case CEPH_OSD_OP_TMAPUP: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ++ctx->num_write; result = do_tmapup(ctx, bp, osd_op); break; case CEPH_OSD_OP_TMAP2OMAP: ++ctx->num_write; result = do_tmap2omap(ctx, op.tmap2omap.flags); break; // OMAP Read ops case CEPH_OSD_OP_OMAPGETKEYS: ++ctx->num_read; { string start_after; uint64_t max_return; try { ::decode(start_after, bp); ::decode(max_return, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } set out_set; if (!pool.info.require_rollback()) { ObjectMap::ObjectMapIterator iter = osd->store->get_omap_iterator( coll, soid ); assert(iter); iter->upper_bound(start_after); for (uint64_t i = 0; i < max_return && iter->valid(); ++i, iter->next()) { out_set.insert(iter->key()); } } // else return empty out_set ::encode(out_set, osd_op.outdata); ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(osd_op.outdata.length(), 10); ctx->delta_stats.num_rd++; } break; case CEPH_OSD_OP_OMAPGETVALS: ++ctx->num_read; { string start_after; uint64_t max_return; string filter_prefix; try { ::decode(start_after, bp); ::decode(max_return, bp); ::decode(filter_prefix, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } map out_set; if (!pool.info.require_rollback()) { ObjectMap::ObjectMapIterator iter = osd->store->get_omap_iterator( coll, soid ); if (!iter) { result = -ENOENT; goto fail; } iter->upper_bound(start_after); if (filter_prefix >= start_after) iter->lower_bound(filter_prefix); for (uint64_t i = 0; i < max_return && iter->valid() && iter->key().substr(0, filter_prefix.size()) == filter_prefix; ++i, iter->next()) { dout(20) << "Found key " << iter->key() << dendl; out_set.insert(make_pair(iter->key(), iter->value())); } } // else return empty out_set ::encode(out_set, osd_op.outdata); ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(osd_op.outdata.length(), 10); ctx->delta_stats.num_rd++; } break; case CEPH_OSD_OP_OMAPGETHEADER: if (pool.info.require_rollback()) { // return empty header break; } ++ctx->num_read; { osd->store->omap_get_header(coll, soid, &osd_op.outdata); ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(osd_op.outdata.length(), 10); ctx->delta_stats.num_rd++; } break; case CEPH_OSD_OP_OMAPGETVALSBYKEYS: ++ctx->num_read; { set keys_to_get; try { ::decode(keys_to_get, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } map out; if (!pool.info.require_rollback()) { osd->store->omap_get_values(coll, soid, keys_to_get, &out); } // else return empty omap entries ::encode(out, osd_op.outdata); ctx->delta_stats.num_rd_kb += SHIFT_ROUND_UP(osd_op.outdata.length(), 10); ctx->delta_stats.num_rd++; } break; case CEPH_OSD_OP_OMAP_CMP: ++ctx->num_read; { if (!obs.exists || oi.is_whiteout()) { result = -ENOENT; break; } map > assertions; try { ::decode(assertions, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } map out; if (!pool.info.require_rollback()) { set to_get; for (map >::iterator i = assertions.begin(); i != assertions.end(); ++i) to_get.insert(i->first); int r = osd->store->omap_get_values(coll, soid, to_get, &out); if (r < 0) { result = r; break; } } // else leave out empty //Should set num_rd_kb based on encode length of map ctx->delta_stats.num_rd++; int r = 0; bufferlist empty; for (map >::iterator i = assertions.begin(); i != assertions.end(); ++i) { bufferlist &bl = out.count(i->first) ? out[i->first] : empty; switch (i->second.second) { case CEPH_OSD_CMPXATTR_OP_EQ: if (!(bl == i->second.first)) { r = -ECANCELED; } break; case CEPH_OSD_CMPXATTR_OP_LT: if (!(bl < i->second.first)) { r = -ECANCELED; } break; case CEPH_OSD_CMPXATTR_OP_GT: if (!(bl > i->second.first)) { r = -ECANCELED; } break; default: r = -EINVAL; break; } if (r < 0) break; } if (r < 0) { result = r; } } break; // OMAP Write ops case CEPH_OSD_OP_OMAPSETVALS: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ctx->mod_desc.mark_unrollbackable(); ++ctx->num_write; { if (!obs.exists) { ctx->delta_stats.num_objects++; obs.exists = true; } t->touch(soid); map to_set; try { ::decode(to_set, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } dout(20) << "setting vals: " << dendl; for (map::iterator i = to_set.begin(); i != to_set.end(); ++i) { dout(20) << "\t" << i->first << dendl; } t->omap_setkeys(soid, to_set); ctx->delta_stats.num_wr++; } obs.oi.set_flag(object_info_t::FLAG_OMAP); break; case CEPH_OSD_OP_OMAPSETHEADER: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ctx->mod_desc.mark_unrollbackable(); ++ctx->num_write; { if (!obs.exists) { ctx->delta_stats.num_objects++; obs.exists = true; } t->touch(soid); t->omap_setheader(soid, osd_op.indata); ctx->delta_stats.num_wr++; } obs.oi.set_flag(object_info_t::FLAG_OMAP); break; case CEPH_OSD_OP_OMAPCLEAR: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ctx->mod_desc.mark_unrollbackable(); ++ctx->num_write; { if (!obs.exists || oi.is_whiteout()) { result = -ENOENT; break; } t->touch(soid); t->omap_clear(soid); ctx->delta_stats.num_wr++; } obs.oi.set_flag(object_info_t::FLAG_OMAP); break; case CEPH_OSD_OP_OMAPRMKEYS: if (pool.info.require_rollback()) { result = -EOPNOTSUPP; break; } ctx->mod_desc.mark_unrollbackable(); ++ctx->num_write; { if (!obs.exists || oi.is_whiteout()) { result = -ENOENT; break; } t->touch(soid); set to_rm; try { ::decode(to_rm, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } t->omap_rmkeys(soid, to_rm); ctx->delta_stats.num_wr++; } obs.oi.set_flag(object_info_t::FLAG_OMAP); break; case CEPH_OSD_OP_COPY_GET_CLASSIC: ++ctx->num_read; result = fill_in_copy_get(ctx, bp, osd_op, ctx->obc, true); if (result == -EINVAL) goto fail; break; case CEPH_OSD_OP_COPY_GET: ++ctx->num_read; result = fill_in_copy_get(ctx, bp, osd_op, ctx->obc, false); if (result == -EINVAL) goto fail; break; case CEPH_OSD_OP_COPY_FROM: ++ctx->num_write; { object_t src_name; object_locator_t src_oloc; snapid_t src_snapid = (uint64_t)op.copy_from.snapid; version_t src_version = op.copy_from.src_version; try { ::decode(src_name, bp); ::decode(src_oloc, bp); } catch (buffer::error& e) { result = -EINVAL; goto fail; } if (!ctx->copy_cb) { // start pg_t raw_pg; get_osdmap()->object_locator_to_pg(src_name, src_oloc, raw_pg); hobject_t src(src_name, src_oloc.key, src_snapid, raw_pg.ps(), raw_pg.pool(), src_oloc.nspace); if (src == soid) { dout(20) << " copy from self is invalid" << dendl; result = -EINVAL; break; } CopyFromCallback *cb = new CopyFromCallback(ctx); ctx->copy_cb = cb; start_copy(cb, ctx->obc, src, src_oloc, src_version, op.copy_from.flags, false); result = -EINPROGRESS; } else { // finish assert(ctx->copy_cb->get_result() >= 0); finish_copyfrom(ctx); result = 0; } } break; default: dout(1) << "unrecognized osd op " << op.op << " " << ceph_osd_op_name(op.op) << dendl; result = -EOPNOTSUPP; } ctx->bytes_read += osd_op.outdata.length(); fail: osd_op.rval = result; if (result < 0 && (op.flags & CEPH_OSD_OP_FLAG_FAILOK)) result = 0; if (result < 0) break; } return result; } int ReplicatedPG::_get_tmap(OpContext *ctx, bufferlist *header, bufferlist *vals) { if (ctx->new_obs.oi.size == 0) { dout(20) << "unable to get tmap for zero sized " << ctx->new_obs.oi.soid << dendl; return -ENODATA; } vector nops(1); OSDOp &newop = nops[0]; newop.op.op = CEPH_OSD_OP_TMAPGET; do_osd_ops(ctx, nops); try { bufferlist::iterator i = newop.outdata.begin(); ::decode(*header, i); (*vals).substr_of(newop.outdata, i.get_off(), i.get_remaining()); } catch (...) { dout(20) << "unsuccessful at decoding tmap for " << ctx->new_obs.oi.soid << dendl; return -EINVAL; } dout(20) << "successful at decoding tmap for " << ctx->new_obs.oi.soid << dendl; return 0; } int ReplicatedPG::_verify_no_head_clones(const hobject_t& soid, const SnapSet& ss) { // verify that all clones have been evicted dout(20) << __func__ << " verifying clones are absent " << ss << dendl; for (vector::const_iterator p = ss.clones.begin(); p != ss.clones.end(); ++p) { hobject_t clone_oid = soid; clone_oid.snap = *p; if (is_missing_object(clone_oid)) return -EBUSY; ObjectContextRef clone_obc = get_object_context(clone_oid, false); if (clone_obc && clone_obc->obs.exists) { dout(10) << __func__ << " cannot evict head before clone " << clone_oid << dendl; return -EBUSY; } if (copy_ops.count(clone_oid)) { dout(10) << __func__ << " cannot evict head, pending promote on clone " << clone_oid << dendl; return -EBUSY; } } return 0; } inline int ReplicatedPG::_delete_oid(OpContext *ctx, bool no_whiteout) { SnapSet& snapset = ctx->new_snapset; ObjectState& obs = ctx->new_obs; object_info_t& oi = obs.oi; const hobject_t& soid = oi.soid; PGBackend::PGTransaction* t = ctx->op_t; if (!obs.exists || (obs.oi.is_whiteout() && !no_whiteout)) return -ENOENT; if (pool.info.require_rollback()) { if (ctx->mod_desc.rmobject(ctx->at_version.version)) { t->stash(soid, ctx->at_version.version); } else { t->remove(soid); } map new_attrs; replace_cached_attrs(ctx, ctx->obc, new_attrs); } else { ctx->mod_desc.mark_unrollbackable(); t->remove(soid); } if (oi.size > 0) { interval_set ch; ch.insert(0, oi.size); ctx->modified_ranges.union_of(ch); } ctx->delta_stats.num_wr++; if (soid.is_snap()) { assert(ctx->obc->ssc->snapset.clone_overlap.count(soid.snap)); ctx->delta_stats.num_bytes -= ctx->obc->ssc->snapset.get_clone_bytes(soid.snap); } else { ctx->delta_stats.num_bytes -= oi.size; } oi.size = 0; // cache: cache: set whiteout on delete? if (pool.info.cache_mode != pg_pool_t::CACHEMODE_NONE && !no_whiteout) { dout(20) << __func__ << " setting whiteout on " << soid << dendl; oi.set_flag(object_info_t::FLAG_WHITEOUT); ctx->delta_stats.num_whiteouts++; t->touch(soid); osd->logger->inc(l_osd_tier_whiteout); return 0; } ctx->delta_stats.num_objects--; if (soid.is_snap()) ctx->delta_stats.num_object_clones--; if (oi.is_whiteout()) { dout(20) << __func__ << " deleting whiteout on " << soid << dendl; ctx->delta_stats.num_whiteouts--; } if (soid.is_head()) snapset.head_exists = false; obs.exists = false; return 0; } int ReplicatedPG::_rollback_to(OpContext *ctx, ceph_osd_op& op) { SnapSet& snapset = ctx->new_snapset; ObjectState& obs = ctx->new_obs; object_info_t& oi = obs.oi; const hobject_t& soid = oi.soid; PGBackend::PGTransaction* t = ctx->op_t; snapid_t snapid = (uint64_t)op.snap.snapid; hobject_t missing_oid; dout(10) << "_rollback_to " << soid << " snapid " << snapid << dendl; ObjectContextRef rollback_to; int ret = find_object_context( hobject_t(soid.oid, soid.get_key(), snapid, soid.hash, info.pgid.pool(), soid.get_namespace()), &rollback_to, false, false, &missing_oid); if (ret == -EAGAIN) { /* clone must be missing */ assert(is_missing_object(missing_oid)); dout(20) << "_rollback_to attempted to roll back to a missing object " << missing_oid << " (requested snapid: ) " << snapid << dendl; wait_for_unreadable_object(missing_oid, ctx->op); return ret; } if (maybe_handle_cache(ctx->op, true, rollback_to, ret, missing_oid, true)) { // promoting the rollback src, presumably return -EAGAIN; } if (ret == -ENOENT || (rollback_to && rollback_to->obs.oi.is_whiteout())) { // there's no snapshot here, or there's no object. // if there's no snapshot, we delete the object; otherwise, do nothing. dout(20) << "_rollback_to deleting head on " << soid.oid << " because got ENOENT|whiteout on find_object_context" << dendl; if (ctx->obc->obs.oi.watchers.size()) { // Cannot delete an object with watchers ret = -EBUSY; } else { _delete_oid(ctx, false); ret = 0; } } else if (ret) { // ummm....huh? It *can't* return anything else at time of writing. assert(0 == "unexpected error code in _rollback_to"); } else { //we got our context, let's use it to do the rollback! hobject_t& rollback_to_sobject = rollback_to->obs.oi.soid; if (is_degraded_object(rollback_to_sobject)) { dout(20) << "_rollback_to attempted to roll back to a degraded object " << rollback_to_sobject << " (requested snapid: ) " << snapid << dendl; wait_for_degraded_object(rollback_to_sobject, ctx->op); ret = -EAGAIN; } else if (rollback_to->obs.oi.soid.snap == CEPH_NOSNAP) { // rolling back to the head; we just need to clone it. ctx->modify = true; } else { /* 1) Delete current head * 2) Clone correct snapshot into head * 3) Calculate clone_overlaps by following overlaps * forward from rollback snapshot */ dout(10) << "_rollback_to deleting " << soid.oid << " and rolling back to old snap" << dendl; if (pool.info.require_rollback()) { if (obs.exists) { if (ctx->mod_desc.rmobject(ctx->at_version.version)) { t->stash(soid, ctx->at_version.version); } else { t->remove(soid); } } replace_cached_attrs(ctx, ctx->obc, rollback_to->attr_cache); } else { if (obs.exists) { ctx->mod_desc.mark_unrollbackable(); t->remove(soid); } } ctx->mod_desc.create(); t->clone(rollback_to_sobject, soid); snapset.head_exists = true; map >::iterator iter = snapset.clone_overlap.lower_bound(snapid); interval_set overlaps = iter->second; assert(iter != snapset.clone_overlap.end()); for ( ; iter != snapset.clone_overlap.end(); ++iter) overlaps.intersection_of(iter->second); if (obs.oi.size > 0) { interval_set modified; modified.insert(0, obs.oi.size); overlaps.intersection_of(modified); modified.subtract(overlaps); ctx->modified_ranges.union_of(modified); } // Adjust the cached objectcontext if (!obs.exists) { obs.exists = true; //we're about to recreate it ctx->delta_stats.num_objects++; } ctx->delta_stats.num_bytes -= obs.oi.size; ctx->delta_stats.num_bytes += rollback_to->obs.oi.size; obs.oi.size = rollback_to->obs.oi.size; snapset.head_exists = true; } } return ret; } void ReplicatedPG::_make_clone( OpContext *ctx, PGBackend::PGTransaction* t, ObjectContextRef obc, const hobject_t& head, const hobject_t& coid, object_info_t *poi) { bufferlist bv; ::encode(*poi, bv); t->clone(head, coid); setattr_maybe_cache(obc, ctx, t, OI_ATTR, bv); rmattr_maybe_cache(obc, ctx, t, SS_ATTR); } void ReplicatedPG::make_writeable(OpContext *ctx) { const hobject_t& soid = ctx->obs->oi.soid; SnapContext& snapc = ctx->snapc; PGBackend::PGTransaction *t = pgbackend->get_transaction(); // clone? assert(soid.snap == CEPH_NOSNAP); dout(20) << "make_writeable " << soid << " snapset=" << ctx->snapset << " snapc=" << snapc << dendl;; bool was_dirty = ctx->obc->obs.oi.is_dirty(); if (ctx->new_obs.exists) { // we will mark the object dirty if (ctx->undirty && was_dirty) { dout(20) << " clearing DIRTY flag" << dendl; assert(ctx->new_obs.oi.is_dirty()); ctx->new_obs.oi.clear_flag(object_info_t::FLAG_DIRTY); --ctx->delta_stats.num_objects_dirty; osd->logger->inc(l_osd_tier_clean); } else if (!was_dirty && !ctx->undirty) { dout(20) << " setting DIRTY flag" << dendl; ctx->new_obs.oi.set_flag(object_info_t::FLAG_DIRTY); ++ctx->delta_stats.num_objects_dirty; osd->logger->inc(l_osd_tier_dirty); } } else { if (was_dirty) { dout(20) << " deletion, decrementing num_dirty and clearing flag" << dendl; ctx->new_obs.oi.clear_flag(object_info_t::FLAG_DIRTY); --ctx->delta_stats.num_objects_dirty; } } if ((ctx->new_obs.exists && ctx->new_obs.oi.is_omap()) && (!ctx->obc->obs.exists || !ctx->obc->obs.oi.is_omap())) { ++ctx->delta_stats.num_objects_omap; } if ((!ctx->new_obs.exists || !ctx->new_obs.oi.is_omap()) && (ctx->obc->obs.exists && ctx->obc->obs.oi.is_omap())) { --ctx->delta_stats.num_objects_omap; } // use newer snapc? if (ctx->new_snapset.seq > snapc.seq) { snapc.seq = ctx->new_snapset.seq; snapc.snaps = ctx->new_snapset.snaps; dout(10) << " using newer snapc " << snapc << dendl; } if (ctx->obs->exists) filter_snapc(snapc.snaps); if ((ctx->obs->exists && !ctx->obs->oi.is_whiteout()) && // head exist(ed) snapc.snaps.size() && // there are snaps !ctx->cache_evict && snapc.snaps[0] > ctx->new_snapset.seq) { // existing object is old // clone hobject_t coid = soid; coid.snap = snapc.seq; unsigned l; for (l=1; l ctx->new_snapset.seq; l++) ; vector snaps(l); for (unsigned i=0; iclone_obc = object_contexts.lookup_or_create(static_snap_oi.soid); ctx->clone_obc->destructor_callback = new C_PG_ObjectContext(this, ctx->clone_obc.get()); ctx->clone_obc->obs.oi = static_snap_oi; ctx->clone_obc->obs.exists = true; ctx->clone_obc->ssc = ctx->obc->ssc; ctx->clone_obc->ssc->ref++; if (pool.info.require_rollback()) ctx->clone_obc->attr_cache = ctx->obc->attr_cache; snap_oi = &ctx->clone_obc->obs.oi; bool got = ctx->clone_obc->get_write_greedy(ctx->op); assert(got); dout(20) << " got greedy write on clone_obc " << *ctx->clone_obc << dendl; } else { snap_oi = &static_snap_oi; } snap_oi->version = ctx->at_version; snap_oi->prior_version = ctx->obs->oi.version; snap_oi->copy_user_bits(ctx->obs->oi); snap_oi->snaps = snaps; if (was_dirty) snap_oi->set_flag(object_info_t::FLAG_DIRTY); _make_clone(ctx, t, ctx->clone_obc, soid, coid, snap_oi); ctx->delta_stats.num_objects++; if (snap_oi->is_dirty()) ctx->delta_stats.num_objects_dirty++; if (snap_oi->is_whiteout()) { dout(20) << __func__ << " cloning whiteout on " << soid << " to " << coid << dendl; ctx->delta_stats.num_whiteouts++; } if (snap_oi->is_omap()) ctx->delta_stats.num_objects_omap++; ctx->delta_stats.num_object_clones++; ctx->new_snapset.clones.push_back(coid.snap); ctx->new_snapset.clone_size[coid.snap] = ctx->obs->oi.size; // clone_overlap should contain an entry for each clone // (an empty interval_set if there is no overlap) ctx->new_snapset.clone_overlap[coid.snap]; if (ctx->obs->oi.size) ctx->new_snapset.clone_overlap[coid.snap].insert(0, ctx->obs->oi.size); // log clone dout(10) << " cloning v " << ctx->obs->oi.version << " to " << coid << " v " << ctx->at_version << " snaps=" << snaps << dendl; ctx->log.push_back(pg_log_entry_t(pg_log_entry_t::CLONE, coid, ctx->at_version, ctx->obs->oi.version, ctx->obs->oi.user_version, osd_reqid_t(), ctx->new_obs.oi.mtime)); ::encode(snaps, ctx->log.back().snaps); ctx->log.back().mod_desc.create(); ctx->at_version.version++; } // update most recent clone_overlap and usage stats if (ctx->new_snapset.clones.size() > 0) { /* we need to check whether the most recent clone exists, if it's been evicted, * it's not included in the stats */ hobject_t last_clone_oid = soid; last_clone_oid.snap = ctx->new_snapset.clone_overlap.rbegin()->first; if (is_present_clone(last_clone_oid)) { interval_set &newest_overlap = ctx->new_snapset.clone_overlap.rbegin()->second; ctx->modified_ranges.intersection_of(newest_overlap); // modified_ranges is still in use by the clone add_interval_usage(ctx->modified_ranges, ctx->delta_stats); newest_overlap.subtract(ctx->modified_ranges); } } // prepend transaction to op_t t->append(ctx->op_t); delete ctx->op_t; ctx->op_t = t; // update snapset with latest snap context ctx->new_snapset.seq = snapc.seq; ctx->new_snapset.snaps = snapc.snaps; ctx->new_snapset.head_exists = ctx->new_obs.exists; dout(20) << "make_writeable " << soid << " done, snapset=" << ctx->new_snapset << dendl; } void ReplicatedPG::write_update_size_and_usage(object_stat_sum_t& delta_stats, object_info_t& oi, SnapSet& ss, interval_set& modified, uint64_t offset, uint64_t length, bool count_bytes) { interval_set ch; if (length) ch.insert(offset, length); modified.union_of(ch); if (length && (offset + length > oi.size)) { uint64_t new_size = offset + length; delta_stats.num_bytes += new_size - oi.size; oi.size = new_size; } delta_stats.num_wr++; if (count_bytes) delta_stats.num_wr_kb += SHIFT_ROUND_UP(length, 10); } void ReplicatedPG::add_interval_usage(interval_set& s, object_stat_sum_t& delta_stats) { for (interval_set::const_iterator p = s.begin(); p != s.end(); ++p) { delta_stats.num_bytes += p.get_len(); } } void ReplicatedPG::do_osd_op_effects(OpContext *ctx) { ConnectionRef conn(ctx->op->get_req()->get_connection()); boost::intrusive_ptr session( (OSD::Session *)conn->get_priv()); session->put(); // get_priv() takes a ref, and so does the intrusive_ptr entity_name_t entity = ctx->reqid.name; dout(15) << "do_osd_op_effects on session " << session.get() << dendl; for (list::iterator i = ctx->watch_connects.begin(); i != ctx->watch_connects.end(); ++i) { pair watcher(i->cookie, entity); dout(15) << "do_osd_op_effects applying watch connect on session " << session.get() << " watcher " << watcher << dendl; WatchRef watch; if (ctx->obc->watchers.count(watcher)) { dout(15) << "do_osd_op_effects found existing watch watcher " << watcher << dendl; watch = ctx->obc->watchers[watcher]; } else { dout(15) << "do_osd_op_effects new watcher " << watcher << dendl; watch = Watch::makeWatchRef( this, osd, ctx->obc, i->timeout_seconds, i->cookie, entity, conn->get_peer_addr()); ctx->obc->watchers.insert( make_pair( watcher, watch)); } watch->connect(conn); } for (list::iterator i = ctx->watch_disconnects.begin(); i != ctx->watch_disconnects.end(); ++i) { pair watcher(i->cookie, entity); dout(15) << "do_osd_op_effects applying watch disconnect on session " << session.get() << " and watcher " << watcher << dendl; if (ctx->obc->watchers.count(watcher)) { WatchRef watch = ctx->obc->watchers[watcher]; dout(10) << "do_osd_op_effects applying disconnect found watcher " << watcher << dendl; ctx->obc->watchers.erase(watcher); watch->remove(); } else { dout(10) << "do_osd_op_effects failed to find watcher " << watcher << dendl; } } for (list::iterator p = ctx->notifies.begin(); p != ctx->notifies.end(); ++p) { dout(10) << "do_osd_op_effects, notify " << *p << dendl; NotifyRef notif( Notify::makeNotifyRef( conn, ctx->obc->watchers.size(), p->bl, p->timeout, p->cookie, osd->get_next_id(get_osdmap()->get_epoch()), ctx->obc->obs.oi.user_version, osd)); for (map, WatchRef>::iterator i = ctx->obc->watchers.begin(); i != ctx->obc->watchers.end(); ++i) { dout(10) << "starting notify on watch " << i->first << dendl; i->second->start_notify(notif); } notif->init(); } for (list::iterator p = ctx->notify_acks.begin(); p != ctx->notify_acks.end(); ++p) { if (p->watch_cookie) dout(10) << "notify_ack " << make_pair(p->watch_cookie.get(), p->notify_id) << dendl; else dout(10) << "notify_ack " << make_pair("NULL", p->notify_id) << dendl; for (map, WatchRef>::iterator i = ctx->obc->watchers.begin(); i != ctx->obc->watchers.end(); ++i) { if (i->first.second != entity) continue; if (p->watch_cookie && p->watch_cookie.get() != i->first.first) continue; dout(10) << "acking notify on watch " << i->first << dendl; i->second->notify_ack(p->notify_id); } } } coll_t ReplicatedPG::get_temp_coll(ObjectStore::Transaction *t) { return pgbackend->get_temp_coll(t); } hobject_t ReplicatedPG::generate_temp_object() { ostringstream ss; ss << "temp_" << info.pgid << "_" << get_role() << "_" << osd->monc->get_global_id() << "_" << (++temp_seq); hobject_t hoid = hobject_t::make_temp(ss.str()); dout(20) << __func__ << " " << hoid << dendl; return hoid; } int ReplicatedPG::prepare_transaction(OpContext *ctx) { assert(!ctx->ops.empty()); const hobject_t& soid = ctx->obs->oi.soid; // valid snap context? if (!ctx->snapc.is_valid()) { dout(10) << " invalid snapc " << ctx->snapc << dendl; return -EINVAL; } // prepare the actual mutation int result = do_osd_ops(ctx, ctx->ops); if (result < 0) return result; // finish side-effects if (result == 0) do_osd_op_effects(ctx); // read-op? done? if (ctx->op_t->empty() && !ctx->modify) { unstable_stats.add(ctx->delta_stats, ctx->obc->obs.oi.category); return result; } // cache: clear whiteout? if (pool.info.cache_mode != pg_pool_t::CACHEMODE_NONE) { if (ctx->user_modify && ctx->obc->obs.oi.is_whiteout()) { dout(10) << __func__ << " clearing whiteout on " << soid << dendl; ctx->new_obs.oi.clear_flag(object_info_t::FLAG_WHITEOUT); --ctx->delta_stats.num_whiteouts; } } // clone, if necessary if (soid.snap == CEPH_NOSNAP) make_writeable(ctx); finish_ctx(ctx, ctx->new_obs.exists ? pg_log_entry_t::MODIFY : pg_log_entry_t::DELETE); return result; } void ReplicatedPG::finish_ctx(OpContext *ctx, int log_op_type, bool maintain_ssc) { const hobject_t& soid = ctx->obs->oi.soid; dout(20) << __func__ << " " << soid << " " << ctx << " op " << pg_log_entry_t::get_op_name(log_op_type) << dendl; utime_t now = ceph_clock_now(cct); // snapset bufferlist bss; if (soid.snap == CEPH_NOSNAP && maintain_ssc) { ::encode(ctx->new_snapset, bss); assert(ctx->new_obs.exists == ctx->new_snapset.head_exists); if (ctx->new_obs.exists) { if (!ctx->obs->exists) { if (ctx->snapset_obc && ctx->snapset_obc->obs.exists) { hobject_t snapoid = soid.get_snapdir(); ctx->log.push_back(pg_log_entry_t(pg_log_entry_t::DELETE, snapoid, ctx->at_version, ctx->snapset_obc->obs.oi.version, 0, osd_reqid_t(), ctx->mtime)); if (pool.info.require_rollback()) { if (ctx->log.back().mod_desc.rmobject(ctx->at_version.version)) { ctx->op_t->stash(snapoid, ctx->at_version.version); } else { ctx->op_t->remove(snapoid); } } else { ctx->op_t->remove(snapoid); ctx->log.back().mod_desc.mark_unrollbackable(); } dout(10) << " removing old " << snapoid << dendl; ctx->at_version.version++; ctx->snapset_obc->obs.exists = false; } } } else if (ctx->new_snapset.clones.size() && !ctx->cache_evict && (!ctx->snapset_obc || !ctx->snapset_obc->obs.exists)) { // save snapset on _snap hobject_t snapoid(soid.oid, soid.get_key(), CEPH_SNAPDIR, soid.hash, info.pgid.pool(), soid.get_namespace()); dout(10) << " final snapset " << ctx->new_snapset << " in " << snapoid << dendl; ctx->log.push_back(pg_log_entry_t(pg_log_entry_t::MODIFY, snapoid, ctx->at_version, eversion_t(), 0, osd_reqid_t(), ctx->mtime)); if (!ctx->snapset_obc) ctx->snapset_obc = get_object_context(snapoid, true); bool got = ctx->snapset_obc->get_write_greedy(ctx->op); assert(got); dout(20) << " got greedy write on snapset_obc " << *ctx->snapset_obc << dendl; ctx->release_snapset_obc = true; if (pool.info.require_rollback() && !ctx->snapset_obc->obs.exists) { ctx->log.back().mod_desc.create(); } else if (!pool.info.require_rollback()) { ctx->log.back().mod_desc.mark_unrollbackable(); } ctx->snapset_obc->obs.exists = true; ctx->snapset_obc->obs.oi.version = ctx->at_version; ctx->snapset_obc->obs.oi.last_reqid = ctx->reqid; ctx->snapset_obc->obs.oi.mtime = ctx->mtime; ctx->snapset_obc->obs.oi.local_mtime = now; bufferlist bv(sizeof(ctx->new_obs.oi)); ::encode(ctx->snapset_obc->obs.oi, bv); ctx->op_t->touch(snapoid); setattr_maybe_cache(ctx->snapset_obc, ctx, ctx->op_t, OI_ATTR, bv); setattr_maybe_cache(ctx->snapset_obc, ctx, ctx->op_t, SS_ATTR, bss); if (pool.info.require_rollback()) { map > to_set; to_set[SS_ATTR]; to_set[OI_ATTR]; ctx->log.back().mod_desc.setattrs(to_set); } else { ctx->log.back().mod_desc.mark_unrollbackable(); } ctx->at_version.version++; } } // finish and log the op. if (ctx->user_modify) { // update the user_version for any modify ops, except for the watch op ctx->user_at_version = MAX(info.last_user_version, ctx->new_obs.oi.user_version) + 1; /* In order for new clients and old clients to interoperate properly * when exchanging versions, we need to lower bound the user_version * (which our new clients pay proper attention to) * by the at_version (which is all the old clients can ever see). */ if (ctx->at_version.version > ctx->user_at_version) ctx->user_at_version = ctx->at_version.version; ctx->new_obs.oi.user_version = ctx->user_at_version; } ctx->bytes_written = ctx->op_t->get_bytes_written(); if (ctx->new_obs.exists) { // on the head object ctx->new_obs.oi.version = ctx->at_version; ctx->new_obs.oi.prior_version = ctx->obs->oi.version; ctx->new_obs.oi.last_reqid = ctx->reqid; if (ctx->mtime != utime_t()) { ctx->new_obs.oi.mtime = ctx->mtime; dout(10) << " set mtime to " << ctx->new_obs.oi.mtime << dendl; ctx->new_obs.oi.local_mtime = now; } else { dout(10) << " mtime unchanged at " << ctx->new_obs.oi.mtime << dendl; } bufferlist bv(sizeof(ctx->new_obs.oi)); ::encode(ctx->new_obs.oi, bv); setattr_maybe_cache(ctx->obc, ctx, ctx->op_t, OI_ATTR, bv); if (soid.snap == CEPH_NOSNAP) { dout(10) << " final snapset " << ctx->new_snapset << " in " << soid << dendl; setattr_maybe_cache(ctx->obc, ctx, ctx->op_t, SS_ATTR, bss); if (pool.info.require_rollback()) { set changing; changing.insert(OI_ATTR); changing.insert(SS_ATTR); ctx->obc->fill_in_setattrs(changing, &(ctx->mod_desc)); } else { // replicated pools are never rollbackable in this case ctx->mod_desc.mark_unrollbackable(); } } else { dout(10) << " no snapset (this is a clone)" << dendl; } } else { ctx->new_obs.oi = object_info_t(ctx->obc->obs.oi.soid); } // append to log ctx->log.push_back(pg_log_entry_t(log_op_type, soid, ctx->at_version, ctx->obs->oi.version, ctx->user_at_version, ctx->reqid, ctx->mtime)); if (soid.snap < CEPH_NOSNAP) { set _snaps(ctx->new_obs.oi.snaps.begin(), ctx->new_obs.oi.snaps.end()); switch (log_op_type) { case pg_log_entry_t::MODIFY: case pg_log_entry_t::PROMOTE: dout(20) << __func__ << " encoding snaps " << ctx->new_obs.oi.snaps << dendl; ::encode(ctx->new_obs.oi.snaps, ctx->log.back().snaps); break; case pg_log_entry_t::CLEAN: dout(20) << __func__ << " encoding snaps " << ctx->new_obs.oi.snaps << dendl; ::encode(ctx->new_obs.oi.snaps, ctx->log.back().snaps); break; default: break; } } ctx->log.back().mod_desc.claim(ctx->mod_desc); // apply new object state. ctx->obc->obs = ctx->new_obs; if (!maintain_ssc && soid.is_head()) { ctx->obc->ssc->exists = false; ctx->obc->ssc->snapset = SnapSet(); } else { ctx->obc->ssc->exists = true; ctx->obc->ssc->snapset = ctx->new_snapset; } info.stats.stats.add(ctx->delta_stats, ctx->obs->oi.category); for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; pg_info_t& pinfo = peer_info[bt]; if (soid <= pinfo.last_backfill) pinfo.stats.stats.add(ctx->delta_stats, ctx->obs->oi.category); else if (soid <= last_backfill_started) pending_backfill_updates[soid].stats.add(ctx->delta_stats, ctx->obs->oi.category); } if (scrubber.active && scrubber.is_chunky) { assert(soid < scrubber.start || soid >= scrubber.end); if (soid < scrubber.start) scrub_cstat.add(ctx->delta_stats, ctx->obs->oi.category); } } void ReplicatedPG::complete_read_ctx(int result, OpContext *ctx) { MOSDOp *m = static_cast(ctx->op->get_req()); assert(ctx->async_reads_complete()); ctx->reply->claim_op_out_data(ctx->ops); ctx->reply->get_header().data_off = ctx->data_off; MOSDOpReply *reply = ctx->reply; ctx->reply = NULL; if (result >= 0) { log_op_stats(ctx); publish_stats_to_osd(); // on read, return the current object version reply->set_reply_versions(eversion_t(), ctx->obs->oi.user_version); } else if (result == -ENOENT) { // on ENOENT, set a floor for what the next user version will be. reply->set_enoent_reply_versions(info.last_update, info.last_user_version); } reply->add_flags(CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK); osd->send_message_osd_client(reply, m->get_connection()); close_op_ctx(ctx, 0); } // ======================================================================== // copyfrom struct C_Copyfrom : public Context { ReplicatedPGRef pg; hobject_t oid; epoch_t last_peering_reset; ceph_tid_t tid; ReplicatedPG::CopyOpRef cop; C_Copyfrom(ReplicatedPG *p, hobject_t o, epoch_t lpr, const ReplicatedPG::CopyOpRef& c) : pg(p), oid(o), last_peering_reset(lpr), tid(0), cop(c) {} void finish(int r) { if (r == -ECANCELED) return; pg->lock(); if (last_peering_reset == pg->get_last_peering_reset()) { pg->process_copy_chunk(oid, tid, r); } pg->unlock(); } }; struct C_CopyFrom_AsyncReadCb : public Context { OSDOp *osd_op; object_copy_data_t reply_obj; bool classic; size_t len; C_CopyFrom_AsyncReadCb(OSDOp *osd_op, bool classic) : osd_op(osd_op), classic(classic), len(0) {} void finish(int r) { assert(len > 0); assert(len <= reply_obj.data.length()); bufferlist bl; bl.substr_of(reply_obj.data, 0, len); reply_obj.data.swap(bl); if (classic) { reply_obj.encode_classic(osd_op->outdata); } else { ::encode(reply_obj, osd_op->outdata); } } }; int ReplicatedPG::fill_in_copy_get( OpContext *ctx, bufferlist::iterator& bp, OSDOp& osd_op, ObjectContextRef &obc, bool classic) { object_info_t& oi = obc->obs.oi; hobject_t& soid = oi.soid; int result = 0; object_copy_cursor_t cursor; uint64_t out_max; try { ::decode(cursor, bp); ::decode(out_max, bp); } catch (buffer::error& e) { result = -EINVAL; return result; } bool async_read_started = false; object_copy_data_t _reply_obj; C_CopyFrom_AsyncReadCb *cb = NULL; if (pool.info.require_rollback()) { cb = new C_CopyFrom_AsyncReadCb(&osd_op, classic); } object_copy_data_t &reply_obj = cb ? cb->reply_obj : _reply_obj; // size, mtime reply_obj.size = oi.size; reply_obj.mtime = oi.mtime; reply_obj.category = oi.category; if (soid.snap < CEPH_NOSNAP) { reply_obj.snaps = oi.snaps; } else { assert(obc->ssc); reply_obj.snap_seq = obc->ssc->snapset.seq; } // attrs map& out_attrs = reply_obj.attrs; if (!cursor.attr_complete) { result = getattrs_maybe_cache( ctx->obc, &out_attrs, true); if (result < 0) { if (cb) { delete cb; } return result; } cursor.attr_complete = true; dout(20) << " got attrs" << dendl; } int64_t left = out_max - osd_op.outdata.length(); // data bufferlist& bl = reply_obj.data; if (left > 0 && !cursor.data_complete) { if (cursor.data_offset < oi.size) { if (cb) { async_read_started = true; ctx->pending_async_reads.push_back( make_pair( make_pair(cursor.data_offset, left), make_pair(&bl, cb))); result = MIN(oi.size - cursor.data_offset, (uint64_t)left); cb->len = result; } else { result = pgbackend->objects_read_sync( oi.soid, cursor.data_offset, left, &bl); if (result < 0) return result; } assert(result <= left); left -= result; cursor.data_offset += result; } if (cursor.data_offset == oi.size) { cursor.data_complete = true; dout(20) << " got data" << dendl; } assert(cursor.data_offset <= oi.size); } // omap std::map& out_omap = reply_obj.omap; if (pool.info.require_rollback()) { cursor.omap_complete = true; } else { if (left > 0 && !cursor.omap_complete) { assert(cursor.data_complete); if (cursor.omap_offset.empty()) { osd->store->omap_get_header(coll, oi.soid, &reply_obj.omap_header); } ObjectMap::ObjectMapIterator iter = osd->store->get_omap_iterator(coll, oi.soid); assert(iter); iter->upper_bound(cursor.omap_offset); for (; iter->valid(); iter->next()) { out_omap.insert(make_pair(iter->key(), iter->value())); left -= iter->key().length() + 4 + iter->value().length() + 4; if (left <= 0) break; } if (iter->valid()) { cursor.omap_offset = iter->key(); } else { cursor.omap_complete = true; dout(20) << " got omap" << dendl; } } } dout(20) << " cursor.is_complete=" << cursor.is_complete() << " " << out_attrs.size() << " attrs" << " " << bl.length() << " bytes" << " " << reply_obj.omap_header.length() << " omap header bytes" << " " << out_omap.size() << " keys" << dendl; reply_obj.cursor = cursor; if (!async_read_started) { if (classic) { reply_obj.encode_classic(osd_op.outdata); } else { ::encode(reply_obj, osd_op.outdata); } } if (cb && !async_read_started) { delete cb; } result = 0; return result; } void ReplicatedPG::start_copy(CopyCallback *cb, ObjectContextRef obc, hobject_t src, object_locator_t oloc, version_t version, unsigned flags, bool mirror_snapset) { const hobject_t& dest = obc->obs.oi.soid; dout(10) << __func__ << " " << dest << " from " << src << " " << oloc << " v" << version << " flags " << flags << (mirror_snapset ? " mirror_snapset" : "") << dendl; assert(!mirror_snapset || (src.snap == CEPH_NOSNAP || src.snap == CEPH_SNAPDIR)); // cancel a previous in-progress copy? if (copy_ops.count(dest)) { // FIXME: if the src etc match, we could avoid restarting from the // beginning. CopyOpRef cop = copy_ops[dest]; cancel_copy(cop, false); } CopyOpRef cop(new CopyOp(cb, obc, src, oloc, version, flags, mirror_snapset)); copy_ops[dest] = cop; obc->start_block(); _copy_some(obc, cop); } void ReplicatedPG::_copy_some(ObjectContextRef obc, CopyOpRef cop) { dout(10) << __func__ << " " << obc << " " << cop << dendl; unsigned flags = 0; if (cop->flags & CEPH_OSD_COPY_FROM_FLAG_FLUSH) flags |= CEPH_OSD_FLAG_FLUSH; if (cop->flags & CEPH_OSD_COPY_FROM_FLAG_IGNORE_CACHE) flags |= CEPH_OSD_FLAG_IGNORE_CACHE; if (cop->flags & CEPH_OSD_COPY_FROM_FLAG_IGNORE_OVERLAY) flags |= CEPH_OSD_FLAG_IGNORE_OVERLAY; if (cop->flags & CEPH_OSD_COPY_FROM_FLAG_MAP_SNAP_CLONE) flags |= CEPH_OSD_FLAG_MAP_SNAP_CLONE; C_GatherBuilder gather(g_ceph_context); if (cop->cursor.is_initial() && cop->mirror_snapset) { // list snaps too. assert(cop->src.snap == CEPH_NOSNAP); ObjectOperation op; op.list_snaps(&cop->results.snapset, NULL); osd->objecter_lock.Lock(); ceph_tid_t tid = osd->objecter->read(cop->src.oid, cop->oloc, op, CEPH_SNAPDIR, NULL, flags, gather.new_sub(), NULL); cop->objecter_tid2 = tid; osd->objecter_lock.Unlock(); } ObjectOperation op; if (cop->results.user_version) { op.assert_version(cop->results.user_version); } else { // we should learn the version after the first chunk, if we didn't know // it already! assert(cop->cursor.is_initial()); } op.copy_get(&cop->cursor, get_copy_chunk_size(), &cop->results.object_size, &cop->results.mtime, &cop->results.category, &cop->attrs, &cop->data, &cop->omap_header, &cop->omap, &cop->results.snaps, &cop->results.snap_seq, &cop->rval); C_Copyfrom *fin = new C_Copyfrom(this, obc->obs.oi.soid, get_last_peering_reset(), cop); gather.set_finisher(new C_OnFinisher(fin, &osd->objecter_finisher)); osd->objecter_lock.Lock(); ceph_tid_t tid = osd->objecter->read(cop->src.oid, cop->oloc, op, cop->src.snap, NULL, flags, gather.new_sub(), // discover the object version if we don't know it yet cop->results.user_version ? NULL : &cop->results.user_version); fin->tid = tid; cop->objecter_tid = tid; gather.activate(); osd->objecter_lock.Unlock(); } void ReplicatedPG::process_copy_chunk(hobject_t oid, ceph_tid_t tid, int r) { dout(10) << __func__ << " " << oid << " tid " << tid << " " << cpp_strerror(r) << dendl; map::iterator p = copy_ops.find(oid); if (p == copy_ops.end()) { dout(10) << __func__ << " no copy_op found" << dendl; return; } CopyOpRef cop = p->second; if (tid != cop->objecter_tid) { dout(10) << __func__ << " tid " << tid << " != cop " << cop << " tid " << cop->objecter_tid << dendl; return; } if (cop->omap.size()) cop->results.has_omap = true; if (r >= 0 && pool.info.require_rollback() && cop->omap.size()) { r = -EOPNOTSUPP; } cop->objecter_tid = 0; cop->objecter_tid2 = 0; // assume this ordered before us (if it happened) ObjectContextRef& cobc = cop->obc; if (r < 0) goto out; assert(cop->rval >= 0); if (oid.snap < CEPH_NOSNAP && !cop->results.snaps.empty()) { // verify snap hasn't been deleted vector::iterator p = cop->results.snaps.begin(); while (p != cop->results.snaps.end()) { if (pool.info.is_removed_snap(*p)) { dout(10) << __func__ << " clone snap " << *p << " has been deleted" << dendl; for (vector::iterator q = p + 1; q != cop->results.snaps.end(); ++q) *(q - 1) = *q; cop->results.snaps.resize(cop->results.snaps.size() - 1); } else { ++p; } } if (cop->results.snaps.empty()) { dout(10) << __func__ << " no more snaps for " << oid << dendl; r = -ENOENT; goto out; } } assert(cop->rval >= 0); if (!cop->cursor.is_complete()) { // write out what we have so far if (cop->temp_cursor.is_initial()) { assert(!cop->results.started_temp_obj); cop->results.started_temp_obj = true; cop->results.temp_oid = generate_temp_object(); dout(20) << __func__ << " using temp " << cop->results.temp_oid << dendl; } ObjectContextRef tempobc = get_object_context(cop->results.temp_oid, true); RepGather *repop = simple_repop_create(tempobc); if (cop->temp_cursor.is_initial()) { repop->ctx->new_temp_oid = cop->results.temp_oid; } _write_copy_chunk(cop, repop->ctx->op_t); simple_repop_submit(repop); dout(10) << __func__ << " fetching more" << dendl; _copy_some(cobc, cop); return; } dout(20) << __func__ << " success; committing" << dendl; cop->results.final_tx = pgbackend->get_transaction(); _build_finish_copy_transaction(cop, cop->results.final_tx); out: dout(20) << __func__ << " complete r = " << cpp_strerror(r) << dendl; CopyCallbackResults results(r, &cop->results); cop->cb->complete(results); copy_ops.erase(cobc->obs.oi.soid); cobc->stop_block(); kick_object_context_blocked(cobc); } void ReplicatedPG::_write_copy_chunk(CopyOpRef cop, PGBackend::PGTransaction *t) { dout(20) << __func__ << " " << cop << " " << cop->attrs.size() << " attrs" << " " << cop->data.length() << " bytes" << " " << cop->omap.size() << " keys" << dendl; if (!cop->temp_cursor.attr_complete) { t->touch(cop->results.temp_oid); for (map::iterator p = cop->attrs.begin(); p != cop->attrs.end(); ++p) { cop->results.attrs[string("_") + p->first] = p->second; t->setattr( cop->results.temp_oid, string("_") + p->first, p->second); } cop->attrs.clear(); } if (!cop->temp_cursor.data_complete) { assert(cop->data.length() + cop->temp_cursor.data_offset == cop->cursor.data_offset); if (pool.info.requires_aligned_append() && !cop->cursor.data_complete) { /** * Trim off the unaligned bit at the end, we'll adjust cursor.data_offset * to pick it up on the next pass. */ assert(cop->temp_cursor.data_offset % pool.info.required_alignment() == 0); if (cop->data.length() % pool.info.required_alignment() != 0) { uint64_t to_trim = cop->data.length() % pool.info.required_alignment(); bufferlist bl; bl.substr_of(cop->data, 0, cop->data.length() - to_trim); cop->data.swap(bl); cop->cursor.data_offset -= to_trim; assert(cop->data.length() + cop->temp_cursor.data_offset == cop->cursor.data_offset); } } t->append( cop->results.temp_oid, cop->temp_cursor.data_offset, cop->data.length(), cop->data); cop->data.clear(); } if (!pool.info.require_rollback()) { if (!cop->temp_cursor.omap_complete) { if (cop->omap_header.length()) { t->omap_setheader( cop->results.temp_oid, cop->omap_header); cop->omap_header.clear(); } t->omap_setkeys(cop->results.temp_oid, cop->omap); cop->omap.clear(); } } else { assert(cop->omap_header.length() == 0); assert(cop->omap.empty()); } cop->temp_cursor = cop->cursor; } void ReplicatedPG::_build_finish_copy_transaction(CopyOpRef cop, PGBackend::PGTransaction* t) { ObjectState& obs = cop->obc->obs; if (cop->temp_cursor.is_initial()) { // write directly to final object cop->results.temp_oid = obs.oi.soid; _write_copy_chunk(cop, t); } else { // finish writing to temp object, then move into place _write_copy_chunk(cop, t); t->rename(cop->results.temp_oid, obs.oi.soid); } } void ReplicatedPG::finish_copyfrom(OpContext *ctx) { dout(20) << "finish_copyfrom on " << ctx->obs->oi.soid << dendl; ObjectState& obs = ctx->new_obs; CopyFromCallback *cb = static_cast(ctx->copy_cb); if (pool.info.require_rollback()) { if (obs.exists) { if (ctx->mod_desc.rmobject(ctx->at_version.version)) { ctx->op_t->stash(obs.oi.soid, ctx->at_version.version); } else { ctx->op_t->remove(obs.oi.soid); } } ctx->mod_desc.create(); replace_cached_attrs(ctx, ctx->obc, cb->results->attrs); } else { if (obs.exists) { ctx->op_t->remove(obs.oi.soid); } ctx->mod_desc.mark_unrollbackable(); } if (!obs.exists) { ctx->delta_stats.num_objects++; obs.exists = true; } if (cb->is_temp_obj_used()) { ctx->discard_temp_oid = cb->results->temp_oid; } ctx->op_t->append(cb->results->final_tx); delete cb->results->final_tx; cb->results->final_tx = NULL; // CopyFromCallback fills this in for us obs.oi.user_version = ctx->user_at_version; // cache: clear whiteout? if (obs.oi.is_whiteout()) { dout(10) << __func__ << " clearing whiteout on " << obs.oi.soid << dendl; obs.oi.clear_flag(object_info_t::FLAG_WHITEOUT); --ctx->delta_stats.num_whiteouts; } if (cb->results->has_omap) { dout(10) << __func__ << " setting omap flag on " << obs.oi.soid << dendl; obs.oi.set_flag(object_info_t::FLAG_OMAP); } else { dout(10) << __func__ << " clearing omap flag on " << obs.oi.soid << dendl; obs.oi.clear_flag(object_info_t::FLAG_OMAP); } interval_set ch; if (obs.oi.size > 0) ch.insert(0, obs.oi.size); ctx->modified_ranges.union_of(ch); if (cb->get_data_size() != obs.oi.size) { ctx->delta_stats.num_bytes -= obs.oi.size; obs.oi.size = cb->get_data_size(); ctx->delta_stats.num_bytes += obs.oi.size; } ctx->delta_stats.num_wr++; ctx->delta_stats.num_wr_kb += SHIFT_ROUND_UP(obs.oi.size, 10); osd->logger->inc(l_osd_copyfrom); } void ReplicatedPG::finish_promote(int r, OpRequestRef op, CopyResults *results, ObjectContextRef obc) { const hobject_t& soid = obc->obs.oi.soid; dout(10) << __func__ << " " << soid << " r=" << r << " uv" << results->user_version << dendl; if (r == -ECANCELED) { return; } if (r == -ENOENT && results->started_temp_obj) { dout(10) << __func__ << " abort; will clean up partial work" << dendl; ObjectContextRef tempobc = get_object_context(results->temp_oid, true); RepGather *repop = simple_repop_create(tempobc); repop->ctx->op_t->remove(results->temp_oid); simple_repop_submit(repop); results->started_temp_obj = false; } if (r == -ENOENT && soid.is_snap()) { dout(10) << __func__ << ": enoent while trying to promote clone, " << soid << " must have been trimmed, removing from snapset" << dendl; hobject_t head(soid.get_head()); ObjectContextRef obc = get_object_context(head, false); assert(obc); RepGather *repop = simple_repop_create(obc); OpContext *tctx = repop->ctx; tctx->at_version = get_next_version(); filter_snapc(tctx->new_snapset.snaps); vector new_clones(tctx->new_snapset.clones.size()); for (vector::iterator i = tctx->new_snapset.clones.begin(); i != tctx->new_snapset.clones.end(); ++i) { if (*i != soid.snap) new_clones.push_back(*i); } tctx->new_snapset.clones.swap(new_clones); tctx->new_snapset.clone_overlap.erase(soid.snap); tctx->new_snapset.clone_size.erase(soid.snap); // take RWWRITE lock for duration of our local write. ignore starvation. if (!obc->rwstate.take_write_lock()) { assert(0 == "problem!"); } tctx->lock_to_release = OpContext::W_LOCK; dout(20) << __func__ << " took lock on obc, " << obc->rwstate << dendl; finish_ctx(tctx, pg_log_entry_t::PROMOTE); simple_repop_submit(repop); return; } bool whiteout = false; if (r == -ENOENT && soid.snap == CEPH_NOSNAP && (pool.info.cache_mode == pg_pool_t::CACHEMODE_WRITEBACK || pool.info.cache_mode == pg_pool_t::CACHEMODE_READONLY)) { dout(10) << __func__ << " whiteout " << soid << dendl; whiteout = true; } if (r < 0 && !whiteout) { // we need to get rid of the op in the blocked queue map >::iterator blocked_iter = waiting_for_blocked_object.find(soid); assert(blocked_iter != waiting_for_blocked_object.end()); assert(blocked_iter->second.begin()->get() == op.get()); blocked_iter->second.pop_front(); if (blocked_iter->second.empty()) { waiting_for_blocked_object.erase(blocked_iter); } osd->reply_op_error(op, r); return; } RepGather *repop = simple_repop_create(obc); OpContext *tctx = repop->ctx; tctx->at_version = get_next_version(); ++tctx->delta_stats.num_objects; if (soid.snap < CEPH_NOSNAP) ++tctx->delta_stats.num_object_clones; tctx->new_obs.exists = true; if (whiteout) { // create a whiteout tctx->op_t->touch(soid); tctx->new_obs.oi.set_flag(object_info_t::FLAG_WHITEOUT); ++tctx->delta_stats.num_whiteouts; dout(20) << __func__ << " creating whiteout on " << soid << dendl; osd->logger->inc(l_osd_tier_whiteout); } else { if (results->has_omap) { dout(10) << __func__ << " setting omap flag on " << soid << dendl; tctx->new_obs.oi.set_flag(object_info_t::FLAG_OMAP); ++tctx->delta_stats.num_objects_omap; } tctx->op_t->append(results->final_tx); delete results->final_tx; results->final_tx = NULL; if (results->started_temp_obj) { tctx->discard_temp_oid = results->temp_oid; } tctx->new_obs.oi.size = results->object_size; tctx->new_obs.oi.category = results->category; tctx->new_obs.oi.user_version = results->user_version; if (soid.snap != CEPH_NOSNAP) { if (!results->snaps.empty()) { tctx->new_obs.oi.snaps = results->snaps; } else { // we must have read "snap" content from the head object in // the base pool. use snap_seq to construct what snaps should // be for this clone (what is was before we evicted the clean // clone from this pool, and what it will be when we flush and // the clone eventually happens in the base pool). SnapSet& snapset = obc->ssc->snapset; vector::iterator p = snapset.snaps.begin(); while (p != snapset.snaps.end() && *p > soid.snap) ++p; assert(p != snapset.snaps.end()); do { tctx->new_obs.oi.snaps.push_back(*p); ++p; } while (p != snapset.snaps.end() && *p > results->snap_seq); } dout(20) << __func__ << " snaps " << tctx->new_obs.oi.snaps << dendl; assert(!tctx->new_obs.oi.snaps.empty()); assert(obc->ssc->snapset.clone_size.count(soid.snap)); assert(obc->ssc->snapset.clone_size[soid.snap] == results->object_size); assert(obc->ssc->snapset.clone_overlap.count(soid.snap)); tctx->delta_stats.num_bytes += obc->ssc->snapset.get_clone_bytes(soid.snap); } else { tctx->delta_stats.num_bytes += results->object_size; } } if (results->mirror_snapset) { assert(tctx->new_obs.oi.soid.snap == CEPH_NOSNAP); tctx->new_snapset.from_snap_set(results->snapset); } tctx->new_snapset.head_exists = true; dout(20) << __func__ << " new_snapset " << tctx->new_snapset << dendl; // take RWWRITE lock for duration of our local write. ignore starvation. if (!obc->rwstate.take_write_lock()) { assert(0 == "problem!"); } tctx->lock_to_release = OpContext::W_LOCK; dout(20) << __func__ << " took lock on obc, " << obc->rwstate << dendl; finish_ctx(tctx, pg_log_entry_t::PROMOTE); simple_repop_submit(repop); osd->logger->inc(l_osd_tier_promote); assert(agent_state); if (agent_state->is_idle()) agent_choose_mode(); } void ReplicatedPG::cancel_copy(CopyOpRef cop, bool requeue) { dout(10) << __func__ << " " << cop->obc->obs.oi.soid << " from " << cop->src << " " << cop->oloc << " v" << cop->results.user_version << dendl; // cancel objecter op, if we can if (cop->objecter_tid) { Mutex::Locker l(osd->objecter_lock); osd->objecter->op_cancel(cop->objecter_tid, -ECANCELED); cop->objecter_tid = 0; if (cop->objecter_tid2) { osd->objecter->op_cancel(cop->objecter_tid2, -ECANCELED); cop->objecter_tid2 = 0; } } copy_ops.erase(cop->obc->obs.oi.soid); cop->obc->stop_block(); kick_object_context_blocked(cop->obc); cop->results.should_requeue = requeue; CopyCallbackResults result(-ECANCELED, &cop->results); cop->cb->complete(result); // There may still be an objecter callback referencing this copy op. // That callback will not need the obc since it's been canceled, and // we need the obc reference to go away prior to flush. cop->obc = ObjectContextRef(); } void ReplicatedPG::cancel_copy_ops(bool requeue) { dout(10) << __func__ << dendl; map::iterator p = copy_ops.begin(); while (p != copy_ops.end()) { // requeue this op? can I queue up all of them? cancel_copy((p++)->second, requeue); } } // ======================================================================== // flush // // Flush a dirty object in the cache tier by writing it back to the // base tier. The sequence looks like: // // * send a copy-from operation to the base tier to copy the current // version of the object // * base tier will pull the object via (perhaps multiple) copy-get(s) // * on completion, we check if the object has been modified. if so, // just reply with -EAGAIN. // * try to take a write lock so we can clear the dirty flag. if this // fails, wait and retry // * start a repop that clears the bit. // // If we have to wait, we will retry by coming back through the // start_flush method. We check if a flush is already in progress // and, if so, try to finish it by rechecking the version and trying // to clear the dirty bit. // // In order for the cache-flush (a write op) to not block the copy-get // from reading the object, the client *must* set the SKIPRWLOCKS // flag. // // NOTE: normally writes are strictly ordered for the client, but // flushes are special in that they can be reordered with respect to // other writes. In particular, we can't have a flush request block // an update to the cache pool object! struct C_Flush : public Context { ReplicatedPGRef pg; hobject_t oid; epoch_t last_peering_reset; ceph_tid_t tid; C_Flush(ReplicatedPG *p, hobject_t o, epoch_t lpr) : pg(p), oid(o), last_peering_reset(lpr), tid(0) {} void finish(int r) { if (r == -ECANCELED) return; pg->lock(); if (last_peering_reset == pg->get_last_peering_reset()) { pg->finish_flush(oid, tid, r); } pg->unlock(); } }; int ReplicatedPG::start_flush( OpRequestRef op, ObjectContextRef obc, bool blocking, hobject_t *pmissing, Context *on_flush) { const object_info_t& oi = obc->obs.oi; const hobject_t& soid = oi.soid; dout(10) << __func__ << " " << soid << " v" << oi.version << " uv" << oi.user_version << " " << (blocking ? "blocking" : "non-blocking/best-effort") << dendl; // verify there are no (older) check for dirty clones SnapSet& snapset = obc->ssc->snapset; { dout(20) << " snapset " << snapset << dendl; vector::reverse_iterator p = snapset.clones.rbegin(); while (p != snapset.clones.rend() && *p >= soid.snap) ++p; if (p != snapset.clones.rend()) { hobject_t next = soid; next.snap = *p; assert(next.snap < soid.snap); if (pg_log.get_missing().is_missing(next)) { dout(10) << __func__ << " missing clone is " << next << dendl; if (pmissing) *pmissing = next; return -ENOENT; } ObjectContextRef older_obc = get_object_context(next, false); if (older_obc) { dout(20) << __func__ << " next oldest clone is " << older_obc->obs.oi << dendl; if (older_obc->obs.oi.is_dirty()) { dout(10) << __func__ << " next oldest clone is dirty: " << older_obc->obs.oi << dendl; return -EBUSY; } } else { dout(20) << __func__ << " next oldest clone " << next << " is not present; implicitly clean" << dendl; } } else { dout(20) << __func__ << " no older clones" << dendl; } } if (blocking) obc->start_block(); map::iterator p = flush_ops.find(soid); if (p != flush_ops.end()) { FlushOpRef fop = p->second; if (fop->op == op) { // we couldn't take the write lock on a cache-try-flush before; // now we are trying again for the lock. return try_flush_mark_clean(fop); } if (fop->flushed_version == obc->obs.oi.user_version && (fop->blocking || !blocking)) { // nonblocking can join anything // blocking can only join a blocking flush dout(20) << __func__ << " piggybacking on existing flush " << dendl; if (op) fop->dup_ops.push_back(op); return -EAGAIN; // clean up this ctx; op will retry later } // cancel current flush since it will fail anyway, or because we // are blocking and the existing flush is nonblocking. dout(20) << __func__ << " canceling previous flush; it will fail" << dendl; if (fop->op) osd->reply_op_error(fop->op, -EBUSY); while (!fop->dup_ops.empty()) { osd->reply_op_error(fop->dup_ops.front(), -EBUSY); fop->dup_ops.pop_front(); } cancel_flush(fop, false); } /** * In general, we need to send two deletes and a copyfrom. * Consider snapc 10:[10, 9, 8, 4, 3, 2]:[10(10, 9), 4(4,3,2)] * where 4 is marked as clean. To flush 10, we have to: * 1) delete 4:[4,3,2] -- ensure head is created at cloneid 4 * 2) delete (8-1):[4,3,2] -- ensure that the object does not exist at 8 * 3) copyfrom 8:[8,4,3,2] -- flush object excluding snap 8 * * The second delete is required in case at some point in the past * there had been a clone 7(7,6), which we had flushed. Without * the second delete, the object would appear in the base pool to * have existed. */ SnapContext snapc, dsnapc, dsnapc2; if (snapset.seq != 0) { if (soid.snap == CEPH_NOSNAP) { snapc.seq = snapset.seq; snapc.snaps = snapset.snaps; } else { snapid_t min_included_snap = oi.snaps.back(); snapc = snapset.get_ssc_as_of(min_included_snap - 1); } snapid_t prev_snapc = 0; for (vector::reverse_iterator citer = snapset.clones.rbegin(); citer != snapset.clones.rend(); ++citer) { if (*citer < soid.snap) { prev_snapc = *citer; break; } } if (prev_snapc != snapc.seq) { dsnapc = snapset.get_ssc_as_of(prev_snapc); snapid_t first_snap_after_prev_snapc = snapset.get_first_snap_after(prev_snapc, snapc.seq); dsnapc2 = snapset.get_ssc_as_of( first_snap_after_prev_snapc - 1); } } object_locator_t base_oloc(soid); base_oloc.pool = pool.info.tier_of; if (dsnapc.seq > 0 && dsnapc.seq < snapc.seq) { ObjectOperation o; o.remove(); osd->objecter_lock.Lock(); osd->objecter->mutate( soid.oid, base_oloc, o, dsnapc, oi.mtime, (CEPH_OSD_FLAG_IGNORE_OVERLAY | CEPH_OSD_FLAG_ORDERSNAP | CEPH_OSD_FLAG_ENFORCE_SNAPC), NULL, NULL /* no callback, we'll rely on the ordering w.r.t the next op */); osd->objecter_lock.Unlock(); } if (dsnapc2.seq > dsnapc.seq && dsnapc2.seq < snapc.seq) { ObjectOperation o; o.remove(); osd->objecter_lock.Lock(); osd->objecter->mutate( soid.oid, base_oloc, o, dsnapc2, oi.mtime, (CEPH_OSD_FLAG_IGNORE_OVERLAY | CEPH_OSD_FLAG_ORDERSNAP | CEPH_OSD_FLAG_ENFORCE_SNAPC), NULL, NULL /* no callback, we'll rely on the ordering w.r.t the next op */); osd->objecter_lock.Unlock(); } FlushOpRef fop(new FlushOp); fop->obc = obc; fop->flushed_version = oi.user_version; fop->blocking = blocking; fop->on_flush = on_flush; fop->op = op; ObjectOperation o; if (oi.is_whiteout()) { fop->removal = true; o.remove(); } else { object_locator_t oloc(soid); o.copy_from(soid.oid.name, soid.snap, oloc, oi.user_version, CEPH_OSD_COPY_FROM_FLAG_FLUSH | CEPH_OSD_COPY_FROM_FLAG_IGNORE_OVERLAY | CEPH_OSD_COPY_FROM_FLAG_IGNORE_CACHE | CEPH_OSD_COPY_FROM_FLAG_MAP_SNAP_CLONE); } C_Flush *fin = new C_Flush(this, soid, get_last_peering_reset()); osd->objecter_lock.Lock(); ceph_tid_t tid = osd->objecter->mutate( soid.oid, base_oloc, o, snapc, oi.mtime, CEPH_OSD_FLAG_IGNORE_OVERLAY | CEPH_OSD_FLAG_ENFORCE_SNAPC, NULL, new C_OnFinisher(fin, &osd->objecter_finisher)); fin->tid = tid; fop->objecter_tid = tid; osd->objecter_lock.Unlock(); flush_ops[soid] = fop; return -EINPROGRESS; } void ReplicatedPG::finish_flush(hobject_t oid, ceph_tid_t tid, int r) { dout(10) << __func__ << " " << oid << " tid " << tid << " " << cpp_strerror(r) << dendl; map::iterator p = flush_ops.find(oid); if (p == flush_ops.end()) { dout(10) << __func__ << " no flush_op found" << dendl; return; } FlushOpRef fop = p->second; if (tid != fop->objecter_tid) { dout(10) << __func__ << " tid " << tid << " != fop " << fop << " tid " << fop->objecter_tid << dendl; return; } ObjectContextRef obc = fop->obc; fop->objecter_tid = 0; if (r < 0 && !(r == -ENOENT && fop->removal)) { if (fop->op) osd->reply_op_error(fop->op, -EBUSY); if (!fop->dup_ops.empty()) { dout(20) << __func__ << " requeueing dups" << dendl; requeue_ops(fop->dup_ops); } if (fop->on_flush) { Context *on_flush = fop->on_flush; fop->on_flush = NULL; on_flush->complete(-EBUSY); } flush_ops.erase(oid); return; } r = try_flush_mark_clean(fop); if (r == -EBUSY && fop->op) { osd->reply_op_error(fop->op, r); } } int ReplicatedPG::try_flush_mark_clean(FlushOpRef fop) { ObjectContextRef obc = fop->obc; const hobject_t& oid = obc->obs.oi.soid; if (fop->blocking) { obc->stop_block(); kick_object_context_blocked(obc); } if (fop->flushed_version != obc->obs.oi.user_version || !obc->obs.exists) { if (obc->obs.exists) dout(10) << __func__ << " flushed_version " << fop->flushed_version << " != current " << obc->obs.oi.user_version << dendl; else dout(10) << __func__ << " object no longer exists" << dendl; if (!fop->dup_ops.empty()) { dout(20) << __func__ << " requeueing dups" << dendl; requeue_ops(fop->dup_ops); } if (fop->on_flush) { Context *on_flush = fop->on_flush; fop->on_flush = NULL; on_flush->complete(-EBUSY); } flush_ops.erase(oid); if (fop->blocking) osd->logger->inc(l_osd_tier_flush_fail); else osd->logger->inc(l_osd_tier_try_flush_fail); return -EBUSY; } if (!fop->blocking && scrubber.write_blocked_by_scrub(oid)) { if (fop->op) { dout(10) << __func__ << " blocked by scrub" << dendl; requeue_op(fop->op); requeue_ops(fop->dup_ops); return -EAGAIN; // will retry } else { osd->logger->inc(l_osd_tier_try_flush_fail); cancel_flush(fop, false); return -ECANCELED; } } // successfully flushed; can we clear the dirty bit? // try to take the lock manually, since we don't // have a ctx yet. if (obc->get_write(fop->op)) { dout(20) << __func__ << " took write lock" << dendl; } else if (fop->op) { dout(10) << __func__ << " waiting on write lock" << dendl; requeue_op(fop->op); requeue_ops(fop->dup_ops); return -EAGAIN; // will retry } else { dout(10) << __func__ << " failed write lock, no op; failing" << dendl; osd->logger->inc(l_osd_tier_try_flush_fail); cancel_flush(fop, false); return -ECANCELED; } dout(10) << __func__ << " clearing DIRTY flag for " << oid << dendl; RepGather *repop = simple_repop_create(fop->obc); OpContext *ctx = repop->ctx; ctx->on_finish = fop->on_flush; fop->on_flush = NULL; ctx->lock_to_release = OpContext::W_LOCK; // we took it above ctx->at_version = get_next_version(); ctx->new_obs = obc->obs; ctx->new_obs.oi.clear_flag(object_info_t::FLAG_DIRTY); --ctx->delta_stats.num_objects_dirty; finish_ctx(ctx, pg_log_entry_t::CLEAN); osd->logger->inc(l_osd_tier_clean); if (!fop->dup_ops.empty() || fop->op) { dout(20) << __func__ << " requeueing for " << ctx->at_version << dendl; list ls; if (fop->op) ls.push_back(fop->op); ls.splice(ls.end(), fop->dup_ops); requeue_ops(ls); } simple_repop_submit(repop); flush_ops.erase(oid); if (fop->blocking) osd->logger->inc(l_osd_tier_flush); else osd->logger->inc(l_osd_tier_try_flush); return -EINPROGRESS; } void ReplicatedPG::cancel_flush(FlushOpRef fop, bool requeue) { dout(10) << __func__ << " " << fop->obc->obs.oi.soid << " tid " << fop->objecter_tid << dendl; if (fop->objecter_tid) { Mutex::Locker l(osd->objecter_lock); osd->objecter->op_cancel(fop->objecter_tid, -ECANCELED); fop->objecter_tid = 0; } if (fop->blocking) { fop->obc->stop_block(); kick_object_context_blocked(fop->obc); } if (requeue) { if (fop->op) requeue_op(fop->op); requeue_ops(fop->dup_ops); } if (fop->on_flush) { Context *on_flush = fop->on_flush; fop->on_flush = NULL; on_flush->complete(-ECANCELED); } flush_ops.erase(fop->obc->obs.oi.soid); } void ReplicatedPG::cancel_flush_ops(bool requeue) { dout(10) << __func__ << dendl; map::iterator p = flush_ops.begin(); while (p != flush_ops.end()) { cancel_flush((p++)->second, requeue); } } bool ReplicatedPG::is_present_clone(hobject_t coid) { if (!pool.info.allow_incomplete_clones()) return true; if (is_missing_object(coid)) return true; ObjectContextRef obc = get_object_context(coid, false); return obc && obc->obs.exists; } // ======================================================================== // rep op gather class C_OSD_RepopApplied : public Context { ReplicatedPGRef pg; boost::intrusive_ptr repop; public: C_OSD_RepopApplied(ReplicatedPG *pg, ReplicatedPG::RepGather *repop) : pg(pg), repop(repop) {} void finish(int) { pg->repop_all_applied(repop.get()); } }; void ReplicatedPG::repop_all_applied(RepGather *repop) { dout(10) << __func__ << ": repop tid " << repop->rep_tid << " all applied " << dendl; repop->all_applied = true; if (!repop->rep_aborted) { eval_repop(repop); if (repop->on_applied) { repop->on_applied->complete(0); repop->on_applied = NULL; } } } class C_OSD_RepopCommit : public Context { ReplicatedPGRef pg; boost::intrusive_ptr repop; public: C_OSD_RepopCommit(ReplicatedPG *pg, ReplicatedPG::RepGather *repop) : pg(pg), repop(repop) {} void finish(int) { pg->repop_all_committed(repop.get()); } }; void ReplicatedPG::repop_all_committed(RepGather *repop) { dout(10) << __func__ << ": repop tid " << repop->rep_tid << " all committed " << dendl; repop->all_committed = true; if (!repop->rep_aborted) { if (repop->v != eversion_t()) { last_update_ondisk = repop->v; last_complete_ondisk = repop->pg_local_last_complete; } eval_repop(repop); } } void ReplicatedPG::op_applied(const eversion_t &applied_version) { dout(10) << "op_applied on primary on version " << applied_version << dendl; if (applied_version == eversion_t()) return; assert(applied_version > last_update_applied); assert(applied_version <= info.last_update); last_update_applied = applied_version; if (is_primary()) { if (scrubber.active && scrubber.is_chunky) { if (last_update_applied == scrubber.subset_last_update) { osd->scrub_wq.queue(this); } } else if (last_update_applied == info.last_update && scrubber.block_writes) { dout(10) << "requeueing scrub for cleanup" << dendl; scrubber.finalizing = true; scrub_gather_replica_maps(); ++scrubber.waiting_on; scrubber.waiting_on_whom.insert(pg_whoami); osd->scrub_wq.queue(this); } } else { dout(10) << "op_applied on replica on version " << applied_version << dendl; if (scrubber.active_rep_scrub) { if (last_update_applied == scrubber.active_rep_scrub->scrub_to) { osd->rep_scrub_wq.queue(scrubber.active_rep_scrub); scrubber.active_rep_scrub = 0; } } } } void ReplicatedPG::eval_repop(RepGather *repop) { MOSDOp *m = NULL; if (repop->ctx->op) m = static_cast(repop->ctx->op->get_req()); if (m) dout(10) << "eval_repop " << *repop << " wants=" << (m->wants_ack() ? "a":"") << (m->wants_ondisk() ? "d":"") << (repop->rep_done ? " DONE" : "") << dendl; else dout(10) << "eval_repop " << *repop << " (no op)" << (repop->rep_done ? " DONE" : "") << dendl; if (repop->rep_done) return; if (m) { // an 'ondisk' reply implies 'ack'. so, prefer to send just one // ondisk instead of ack followed by ondisk. // ondisk? if (repop->all_committed) { log_op_stats(repop->ctx); publish_stats_to_osd(); // send dup commits, in order if (waiting_for_ondisk.count(repop->v)) { assert(waiting_for_ondisk.begin()->first == repop->v); for (list::iterator i = waiting_for_ondisk[repop->v].begin(); i != waiting_for_ondisk[repop->v].end(); ++i) { osd->reply_op_error(*i, 0, repop->ctx->at_version, repop->ctx->user_at_version); } waiting_for_ondisk.erase(repop->v); } // clear out acks, we sent the commits above if (waiting_for_ack.count(repop->v)) { assert(waiting_for_ack.begin()->first == repop->v); waiting_for_ack.erase(repop->v); } if (m->wants_ondisk() && !repop->sent_disk) { // send commit. MOSDOpReply *reply = repop->ctx->reply; if (reply) repop->ctx->reply = NULL; else { reply = new MOSDOpReply(m, 0, get_osdmap()->get_epoch(), 0, true); reply->set_reply_versions(repop->ctx->at_version, repop->ctx->user_at_version); } reply->add_flags(CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK); dout(10) << " sending commit on " << *repop << " " << reply << dendl; osd->send_message_osd_client(reply, m->get_connection()); repop->sent_disk = true; repop->ctx->op->mark_commit_sent(); } } // applied? if (repop->all_applied) { // send dup acks, in order if (waiting_for_ack.count(repop->v)) { assert(waiting_for_ack.begin()->first == repop->v); for (list::iterator i = waiting_for_ack[repop->v].begin(); i != waiting_for_ack[repop->v].end(); ++i) { MOSDOp *m = (MOSDOp*)(*i)->get_req(); MOSDOpReply *reply = new MOSDOpReply(m, 0, get_osdmap()->get_epoch(), 0, true); reply->set_reply_versions(repop->ctx->at_version, repop->ctx->user_at_version); reply->add_flags(CEPH_OSD_FLAG_ACK); osd->send_message_osd_client(reply, m->get_connection()); } waiting_for_ack.erase(repop->v); } if (m->wants_ack() && !repop->sent_ack && !repop->sent_disk) { // send ack MOSDOpReply *reply = repop->ctx->reply; if (reply) repop->ctx->reply = NULL; else { reply = new MOSDOpReply(m, 0, get_osdmap()->get_epoch(), 0, true); reply->set_reply_versions(repop->ctx->at_version, repop->ctx->user_at_version); } reply->add_flags(CEPH_OSD_FLAG_ACK); dout(10) << " sending ack on " << *repop << " " << reply << dendl; assert(entity_name_t::TYPE_OSD != m->get_connection()->peer_type); osd->send_message_osd_client(reply, m->get_connection()); repop->sent_ack = true; } // note the write is now readable (for rlatency calc). note // that this will only be defined if the write is readable // _prior_ to being committed; it will not get set with // writeahead journaling, for instance. if (repop->ctx->readable_stamp == utime_t()) repop->ctx->readable_stamp = ceph_clock_now(cct); } } // done. if (repop->all_applied && repop->all_committed) { repop->rep_done = true; release_op_ctx_locks(repop->ctx); calc_min_last_complete_ondisk(); // kick snap_trimmer if necessary if (repop->queue_snap_trimmer) { queue_snap_trim(); } dout(10) << " removing " << *repop << dendl; assert(!repop_queue.empty()); dout(20) << " q front is " << *repop_queue.front() << dendl; if (repop_queue.front() != repop) { dout(0) << " removing " << *repop << dendl; dout(0) << " q front is " << *repop_queue.front() << dendl; assert(repop_queue.front() == repop); } repop_queue.pop_front(); remove_repop(repop); } } void ReplicatedPG::issue_repop(RepGather *repop, utime_t now) { OpContext *ctx = repop->ctx; const hobject_t& soid = ctx->obs->oi.soid; if (ctx->op && ((static_cast( ctx->op->get_req()))->get_flags() & CEPH_OSD_FLAG_PARALLELEXEC)) { // replicate original op for parallel execution on replica assert(0 == "broken implementation, do not use"); } dout(7) << "issue_repop rep_tid " << repop->rep_tid << " o " << soid << dendl; repop->v = ctx->at_version; if (ctx->at_version > eversion_t()) { for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_info_t &pinfo = peer_info[*i]; // keep peer_info up to date if (pinfo.last_complete == pinfo.last_update) pinfo.last_complete = ctx->at_version; pinfo.last_update = ctx->at_version; } } repop->obc->ondisk_write_lock(); if (repop->ctx->clone_obc) repop->ctx->clone_obc->ondisk_write_lock(); bool unlock_snapset_obc = false; if (repop->ctx->snapset_obc && repop->ctx->snapset_obc->obs.oi.soid != repop->obc->obs.oi.soid) { repop->ctx->snapset_obc->ondisk_write_lock(); unlock_snapset_obc = true; } repop->ctx->apply_pending_attrs(); if (pool.info.require_rollback()) { for (vector::iterator i = repop->ctx->log.begin(); i != repop->ctx->log.end(); ++i) { assert(i->mod_desc.can_rollback()); assert(!i->mod_desc.empty()); } } Context *on_all_commit = new C_OSD_RepopCommit(this, repop); Context *on_all_applied = new C_OSD_RepopApplied(this, repop); Context *onapplied_sync = new C_OSD_OndiskWriteUnlock( repop->obc, repop->ctx->clone_obc, unlock_snapset_obc ? repop->ctx->snapset_obc : ObjectContextRef()); pgbackend->submit_transaction( soid, repop->ctx->at_version, repop->ctx->op_t, pg_trim_to, min_last_complete_ondisk, repop->ctx->log, repop->ctx->updated_hset_history, onapplied_sync, on_all_applied, on_all_commit, repop->rep_tid, repop->ctx->reqid, repop->ctx->op); repop->ctx->op_t = NULL; } void ReplicatedBackend::issue_op( const hobject_t &soid, const eversion_t &at_version, ceph_tid_t tid, osd_reqid_t reqid, eversion_t pg_trim_to, eversion_t pg_trim_rollback_to, hobject_t new_temp_oid, hobject_t discard_temp_oid, vector &log_entries, boost::optional &hset_hist, InProgressOp *op, ObjectStore::Transaction *op_t) { int acks_wanted = CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK; if (parent->get_actingbackfill_shards().size() > 1) { ostringstream ss; set replicas = parent->get_actingbackfill_shards(); replicas.erase(parent->whoami_shard()); ss << "waiting for subops from " << replicas; if (op->op) op->op->mark_sub_op_sent(ss.str()); } for (set::const_iterator i = parent->get_actingbackfill_shards().begin(); i != parent->get_actingbackfill_shards().end(); ++i) { if (*i == parent->whoami_shard()) continue; pg_shard_t peer = *i; const pg_info_t &pinfo = parent->get_shard_info().find(peer)->second; // forward the write/update/whatever MOSDSubOp *wr = new MOSDSubOp( reqid, parent->whoami_shard(), spg_t(get_info().pgid.pgid, i->shard), soid, false, acks_wanted, get_osdmap()->get_epoch(), tid, at_version); // ship resulting transaction, log entries, and pg_stats if (!parent->should_send_op(peer, soid)) { dout(10) << "issue_repop shipping empty opt to osd." << peer <<", object " << soid << " beyond MAX(last_backfill_started " << ", pinfo.last_backfill " << pinfo.last_backfill << ")" << dendl; ObjectStore::Transaction t; ::encode(t, wr->get_data()); } else { ::encode(*op_t, wr->get_data()); } ::encode(log_entries, wr->logbl); if (pinfo.is_incomplete()) wr->pg_stats = pinfo.stats; // reflects backfill progress else wr->pg_stats = get_info().stats; wr->pg_trim_to = pg_trim_to; wr->pg_trim_rollback_to = pg_trim_rollback_to; wr->new_temp_oid = new_temp_oid; wr->discard_temp_oid = discard_temp_oid; wr->updated_hit_set_history = hset_hist; get_parent()->send_message_osd_cluster( peer.osd, wr, get_osdmap()->get_epoch()); } } ReplicatedPG::RepGather *ReplicatedPG::new_repop(OpContext *ctx, ObjectContextRef obc, ceph_tid_t rep_tid) { if (ctx->op) dout(10) << "new_repop rep_tid " << rep_tid << " on " << *ctx->op->get_req() << dendl; else dout(10) << "new_repop rep_tid " << rep_tid << " (no op)" << dendl; RepGather *repop = new RepGather(ctx, obc, rep_tid, info.last_complete); repop->start = ceph_clock_now(cct); repop_queue.push_back(&repop->queue_item); repop_map[repop->rep_tid] = repop; repop->get(); osd->logger->set(l_osd_op_wip, repop_map.size()); return repop; } void ReplicatedPG::remove_repop(RepGather *repop) { dout(20) << __func__ << " " << *repop << dendl; if (repop->ctx->obc) dout(20) << " obc " << *repop->ctx->obc << dendl; if (repop->ctx->clone_obc) dout(20) << " clone_obc " << *repop->ctx->clone_obc << dendl; if (repop->ctx->snapset_obc) dout(20) << " snapset_obc " << *repop->ctx->snapset_obc << dendl; release_op_ctx_locks(repop->ctx); repop->ctx->finish(0); // FIXME: return value here is sloppy repop_map.erase(repop->rep_tid); repop->put(); osd->logger->set(l_osd_op_wip, repop_map.size()); } ReplicatedPG::RepGather *ReplicatedPG::simple_repop_create(ObjectContextRef obc) { dout(20) << __func__ << " " << obc->obs.oi.soid << dendl; vector ops; ceph_tid_t rep_tid = osd->get_tid(); osd_reqid_t reqid(osd->get_cluster_msgr_name(), 0, rep_tid); OpContext *ctx = new OpContext(OpRequestRef(), reqid, ops, &obc->obs, obc->ssc, this); ctx->op_t = pgbackend->get_transaction(); ctx->mtime = ceph_clock_now(g_ceph_context); ctx->obc = obc; RepGather *repop = new_repop(ctx, obc, rep_tid); return repop; } void ReplicatedPG::simple_repop_submit(RepGather *repop) { dout(20) << __func__ << " " << repop << dendl; issue_repop(repop, repop->ctx->mtime); eval_repop(repop); repop->put(); } // ------------------------------------------------------- void ReplicatedPG::get_watchers(list &pg_watchers) { pair i; while (object_contexts.get_next(i.first, &i)) { ObjectContextRef obc(i.second); get_obc_watchers(obc, pg_watchers); } } void ReplicatedPG::get_obc_watchers(ObjectContextRef obc, list &pg_watchers) { for (map, WatchRef>::iterator j = obc->watchers.begin(); j != obc->watchers.end(); ++j) { obj_watch_item_t owi; owi.obj = obc->obs.oi.soid; owi.wi.addr = j->second->get_peer_addr(); owi.wi.name = j->second->get_entity(); owi.wi.cookie = j->second->get_cookie(); owi.wi.timeout_seconds = j->second->get_timeout(); dout(30) << "watch: Found oid=" << owi.obj << " addr=" << owi.wi.addr << " name=" << owi.wi.name << " cookie=" << owi.wi.cookie << dendl; pg_watchers.push_back(owi); } } void ReplicatedPG::check_blacklisted_watchers() { dout(20) << "ReplicatedPG::check_blacklisted_watchers for pg " << get_pgid() << dendl; pair i; while (object_contexts.get_next(i.first, &i)) check_blacklisted_obc_watchers(i.second); } void ReplicatedPG::check_blacklisted_obc_watchers(ObjectContextRef obc) { dout(20) << "ReplicatedPG::check_blacklisted_obc_watchers for obc " << obc->obs.oi.soid << dendl; for (map, WatchRef>::iterator k = obc->watchers.begin(); k != obc->watchers.end(); ) { //Advance iterator now so handle_watch_timeout() can erase element map, WatchRef>::iterator j = k++; dout(30) << "watch: Found " << j->second->get_entity() << " cookie " << j->second->get_cookie() << dendl; entity_addr_t ea = j->second->get_peer_addr(); dout(30) << "watch: Check entity_addr_t " << ea << dendl; if (get_osdmap()->is_blacklisted(ea)) { dout(10) << "watch: Found blacklisted watcher for " << ea << dendl; assert(j->second->get_pg() == this); j->second->unregister_cb(); handle_watch_timeout(j->second); } } } void ReplicatedPG::populate_obc_watchers(ObjectContextRef obc) { assert(is_active()); assert((recovering.count(obc->obs.oi.soid) || !is_missing_object(obc->obs.oi.soid)) || (pg_log.get_log().objects.count(obc->obs.oi.soid) && // or this is a revert... see recover_primary() pg_log.get_log().objects.find(obc->obs.oi.soid)->second->op == pg_log_entry_t::LOST_REVERT && pg_log.get_log().objects.find(obc->obs.oi.soid)->second->reverting_to == obc->obs.oi.version)); dout(10) << "populate_obc_watchers " << obc->obs.oi.soid << dendl; assert(obc->watchers.empty()); // populate unconnected_watchers for (map, watch_info_t>::iterator p = obc->obs.oi.watchers.begin(); p != obc->obs.oi.watchers.end(); ++p) { utime_t expire = info.stats.last_became_active; expire += p->second.timeout_seconds; dout(10) << " unconnected watcher " << p->first << " will expire " << expire << dendl; WatchRef watch( Watch::makeWatchRef( this, osd, obc, p->second.timeout_seconds, p->first.first, p->first.second, p->second.addr)); watch->disconnect(); obc->watchers.insert( make_pair( make_pair(p->first.first, p->first.second), watch)); } // Look for watchers from blacklisted clients and drop check_blacklisted_obc_watchers(obc); } void ReplicatedPG::handle_watch_timeout(WatchRef watch) { ObjectContextRef obc = watch->get_obc(); // handle_watch_timeout owns this ref dout(10) << "handle_watch_timeout obc " << obc << dendl; if (is_degraded_object(obc->obs.oi.soid)) { callbacks_for_degraded_object[obc->obs.oi.soid].push_back( watch->get_delayed_cb() ); dout(10) << "handle_watch_timeout waiting for degraded on obj " << obc->obs.oi.soid << dendl; return; } if (scrubber.write_blocked_by_scrub(obc->obs.oi.soid)) { dout(10) << "handle_watch_timeout waiting for scrub on obj " << obc->obs.oi.soid << dendl; scrubber.add_callback( watch->get_delayed_cb() // This callback! ); return; } obc->watchers.erase(make_pair(watch->get_cookie(), watch->get_entity())); obc->obs.oi.watchers.erase(make_pair(watch->get_cookie(), watch->get_entity())); watch->remove(); vector ops; ceph_tid_t rep_tid = osd->get_tid(); osd_reqid_t reqid(osd->get_cluster_msgr_name(), 0, rep_tid); OpContext *ctx = new OpContext(OpRequestRef(), reqid, ops, &obc->obs, obc->ssc, this); ctx->op_t = pgbackend->get_transaction(); ctx->mtime = ceph_clock_now(cct); ctx->at_version = get_next_version(); entity_inst_t nobody; RepGather *repop = new_repop(ctx, obc, rep_tid); PGBackend::PGTransaction *t = ctx->op_t; ctx->log.push_back(pg_log_entry_t(pg_log_entry_t::MODIFY, obc->obs.oi.soid, ctx->at_version, obc->obs.oi.version, 0, osd_reqid_t(), ctx->mtime)); obc->obs.oi.prior_version = repop->obc->obs.oi.version; obc->obs.oi.version = ctx->at_version; bufferlist bl; ::encode(obc->obs.oi, bl); setattr_maybe_cache(obc, repop->ctx, t, OI_ATTR, bl); if (pool.info.require_rollback()) { map > to_set; to_set[OI_ATTR] = bl; ctx->log.back().mod_desc.setattrs(to_set); } else { ctx->log.back().mod_desc.mark_unrollbackable(); } // obc ref swallowed by repop! issue_repop(repop, repop->ctx->mtime); eval_repop(repop); repop->put(); } ObjectContextRef ReplicatedPG::create_object_context(const object_info_t& oi, SnapSetContext *ssc) { ObjectContextRef obc(object_contexts.lookup_or_create(oi.soid)); assert(obc->destructor_callback == NULL); obc->destructor_callback = new C_PG_ObjectContext(this, obc.get()); obc->obs.oi = oi; obc->obs.exists = false; obc->ssc = ssc; if (ssc) register_snapset_context(ssc); dout(10) << "create_object_context " << (void*)obc.get() << " " << oi.soid << " " << dendl; populate_obc_watchers(obc); return obc; } ObjectContextRef ReplicatedPG::get_object_context(const hobject_t& soid, bool can_create, map *attrs) { assert( attrs || !pg_log.get_missing().is_missing(soid) || // or this is a revert... see recover_primary() (pg_log.get_log().objects.count(soid) && pg_log.get_log().objects.find(soid)->second->op == pg_log_entry_t::LOST_REVERT)); ObjectContextRef obc = object_contexts.lookup(soid); if (obc) { dout(10) << __func__ << ": found obc in cache: " << obc << dendl; } else { // check disk bufferlist bv; if (attrs) { assert(attrs->count(OI_ATTR)); bv = attrs->find(OI_ATTR)->second; } else { int r = pgbackend->objects_get_attr(soid, OI_ATTR, &bv); if (r < 0) { if (!can_create) { dout(10) << __func__ << ": no obc for soid " << soid << " and !can_create" << dendl; return ObjectContextRef(); // -ENOENT! } dout(10) << __func__ << ": no obc for soid " << soid << " but can_create" << dendl; // new object. object_info_t oi(soid); SnapSetContext *ssc = get_snapset_context( soid, true, soid.has_snapset() ? attrs : 0); obc = create_object_context(oi, ssc); dout(10) << __func__ << ": " << obc << " " << soid << " " << obc->rwstate << " oi: " << obc->obs.oi << " ssc: " << obc->ssc << " snapset: " << obc->ssc->snapset << dendl; return obc; } } object_info_t oi(bv); assert(oi.soid.pool == (int64_t)info.pgid.pool()); obc = object_contexts.lookup_or_create(oi.soid); obc->destructor_callback = new C_PG_ObjectContext(this, obc.get()); obc->obs.oi = oi; obc->obs.exists = true; obc->ssc = get_snapset_context( soid, true, soid.has_snapset() ? attrs : 0); register_snapset_context(obc->ssc); populate_obc_watchers(obc); if (pool.info.require_rollback()) { if (attrs) { obc->attr_cache = *attrs; } else { int r = pgbackend->objects_get_attrs( soid, &obc->attr_cache); assert(r == 0); } } dout(10) << __func__ << ": creating obc from disk: " << obc << dendl; } assert(obc->ssc); dout(10) << __func__ << ": " << obc << " " << soid << " " << obc->rwstate << " oi: " << obc->obs.oi << " ssc: " << obc->ssc << " snapset: " << obc->ssc->snapset << dendl; return obc; } void ReplicatedPG::context_registry_on_change() { pair i; while (object_contexts.get_next(i.first, &i)) { ObjectContextRef obc(i.second); if (obc) { for (map, WatchRef>::iterator j = obc->watchers.begin(); j != obc->watchers.end(); obc->watchers.erase(j++)) { j->second->discard(); } } } } /* * If we return an error, and set *pmissing, then promoting that * object may help. * * If we return -EAGAIN, we will always set *pmissing to the missing * object to wait for. * * If we return an error but do not set *pmissing, then we know the * object does not exist. */ int ReplicatedPG::find_object_context(const hobject_t& oid, ObjectContextRef *pobc, bool can_create, bool map_snapid_to_clone, hobject_t *pmissing) { hobject_t head(oid.oid, oid.get_key(), CEPH_NOSNAP, oid.hash, info.pgid.pool(), oid.get_namespace()); hobject_t snapdir(oid.oid, oid.get_key(), CEPH_SNAPDIR, oid.hash, info.pgid.pool(), oid.get_namespace()); // want the snapdir? if (oid.snap == CEPH_SNAPDIR) { // return head or snapdir, whichever exists. ObjectContextRef obc = get_object_context(head, can_create); if (!obc || !obc->obs.exists) obc = get_object_context(snapdir, can_create); if (!obc || !obc->obs.exists) { // if we have neither, we would want to promote the head. if (pmissing) *pmissing = head; return -ENOENT; } dout(10) << "find_object_context " << oid << " @" << oid.snap << " oi=" << obc->obs.oi << dendl; *pobc = obc; // always populate ssc for SNAPDIR... if (!obc->ssc) obc->ssc = get_snapset_context( oid, true); return 0; } // want the head? if (oid.snap == CEPH_NOSNAP) { ObjectContextRef obc = get_object_context(head, can_create); if (!obc) { if (pmissing) *pmissing = head; return -ENOENT; } dout(10) << "find_object_context " << oid << " @" << oid.snap << " oi=" << obc->obs.oi << dendl; *pobc = obc; if (can_create && !obc->ssc) obc->ssc = get_snapset_context(oid, true); return 0; } // we want a snap if (!map_snapid_to_clone && pool.info.is_removed_snap(oid.snap)) { dout(10) << __func__ << " snap " << oid.snap << " is removed" << dendl; return -ENOENT; } SnapSetContext *ssc = get_snapset_context(oid, can_create); if (!ssc || !(ssc->exists)) { dout(20) << __func__ << " " << oid << " no snapset" << dendl; if (pmissing) *pmissing = head; // start by getting the head if (ssc) put_snapset_context(ssc); return -ENOENT; } if (map_snapid_to_clone) { dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " map_snapid_to_clone=true" << dendl; if (oid.snap > ssc->snapset.seq) { // already must be readable ObjectContextRef obc = get_object_context(head, false); dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " maps to head" << dendl; *pobc = obc; put_snapset_context(ssc); return (obc && obc->obs.exists) ? 0 : -ENOENT; } else { vector::const_iterator citer = std::find( ssc->snapset.clones.begin(), ssc->snapset.clones.end(), oid.snap); if (citer == ssc->snapset.clones.end()) { dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " maps to nothing" << dendl; put_snapset_context(ssc); return -ENOENT; } dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " maps to " << oid << dendl; if (pg_log.get_missing().is_missing(oid)) { dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " " << oid << " is missing" << dendl; if (pmissing) *pmissing = oid; put_snapset_context(ssc); return -EAGAIN; } ObjectContextRef obc = get_object_context(oid, false); if (!obc || !obc->obs.exists) { dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " " << oid << " is not present" << dendl; if (pmissing) *pmissing = oid; put_snapset_context(ssc); return -ENOENT; } dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << " " << oid << " HIT" << dendl; *pobc = obc; put_snapset_context(ssc); return 0; } assert(0); //unreachable } dout(10) << "find_object_context " << oid << " @" << oid.snap << " snapset " << ssc->snapset << dendl; // head? if (oid.snap > ssc->snapset.seq) { if (ssc->snapset.head_exists) { ObjectContextRef obc = get_object_context(head, false); dout(10) << "find_object_context " << head << " want " << oid.snap << " > snapset seq " << ssc->snapset.seq << " -- HIT " << obc->obs << dendl; if (!obc->ssc) obc->ssc = ssc; else { assert(ssc == obc->ssc); put_snapset_context(ssc); } *pobc = obc; return 0; } dout(10) << "find_object_context " << head << " want " << oid.snap << " > snapset seq " << ssc->snapset.seq << " but head dne -- DNE" << dendl; put_snapset_context(ssc); return -ENOENT; } // which clone would it be? unsigned k = 0; while (k < ssc->snapset.clones.size() && ssc->snapset.clones[k] < oid.snap) k++; if (k == ssc->snapset.clones.size()) { dout(10) << "find_object_context no clones with last >= oid.snap " << oid.snap << " -- DNE" << dendl; put_snapset_context(ssc); return -ENOENT; } hobject_t soid(oid.oid, oid.get_key(), ssc->snapset.clones[k], oid.hash, info.pgid.pool(), oid.get_namespace()); if (pg_log.get_missing().is_missing(soid)) { dout(20) << "find_object_context " << soid << " missing, try again later" << dendl; if (pmissing) *pmissing = soid; put_snapset_context(ssc); return -EAGAIN; } ObjectContextRef obc = get_object_context(soid, false); if (!obc || !obc->obs.exists) { dout(20) << __func__ << " missing clone " << soid << dendl; if (pmissing) *pmissing = soid; put_snapset_context(ssc); return -ENOENT; } if (!obc->ssc) { obc->ssc = ssc; } else { assert(obc->ssc == ssc); put_snapset_context(ssc); } ssc = 0; // clone dout(20) << "find_object_context " << soid << " snaps " << obc->obs.oi.snaps << dendl; snapid_t first = obc->obs.oi.snaps[obc->obs.oi.snaps.size()-1]; snapid_t last = obc->obs.oi.snaps[0]; if (first <= oid.snap) { dout(20) << "find_object_context " << soid << " [" << first << "," << last << "] contains " << oid.snap << " -- HIT " << obc->obs << dendl; *pobc = obc; return 0; } else { dout(20) << "find_object_context " << soid << " [" << first << "," << last << "] does not contain " << oid.snap << " -- DNE" << dendl; return -ENOENT; } } void ReplicatedPG::object_context_destructor_callback(ObjectContext *obc) { if (obc->ssc) put_snapset_context(obc->ssc); } void ReplicatedPG::add_object_context_to_pg_stat(ObjectContextRef obc, pg_stat_t *pgstat) { object_info_t& oi = obc->obs.oi; dout(10) << "add_object_context_to_pg_stat " << oi.soid << dendl; object_stat_sum_t stat; stat.num_bytes += oi.size; if (oi.soid.snap != CEPH_SNAPDIR) stat.num_objects++; if (oi.is_dirty()) stat.num_objects_dirty++; if (oi.is_whiteout()) stat.num_whiteouts++; if (oi.is_omap()) stat.num_objects_omap++; if (oi.soid.snap && oi.soid.snap != CEPH_NOSNAP && oi.soid.snap != CEPH_SNAPDIR) { stat.num_object_clones++; if (!obc->ssc) obc->ssc = get_snapset_context(oi.soid, false); assert(obc->ssc); // subtract off clone overlap if (obc->ssc->snapset.clone_overlap.count(oi.soid.snap)) { interval_set& o = obc->ssc->snapset.clone_overlap[oi.soid.snap]; for (interval_set::const_iterator r = o.begin(); r != o.end(); ++r) { stat.num_bytes -= r.get_len(); } } } // add it in pgstat->stats.sum.add(stat); if (oi.category.length()) pgstat->stats.cat_sum[oi.category].add(stat); } void ReplicatedPG::kick_object_context_blocked(ObjectContextRef obc) { const hobject_t& soid = obc->obs.oi.soid; map >::iterator p = waiting_for_blocked_object.find(soid); if (p == waiting_for_blocked_object.end()) return; if (obc->is_blocked()) { dout(10) << __func__ << " " << soid << " still blocked" << dendl; return; } list& ls = p->second; dout(10) << __func__ << " " << soid << " requeuing " << ls.size() << " requests" << dendl; requeue_ops(ls); waiting_for_blocked_object.erase(p); if (obc->requeue_scrub_on_unblock) osd->queue_for_scrub(this); } SnapSetContext *ReplicatedPG::create_snapset_context(const hobject_t& oid) { Mutex::Locker l(snapset_contexts_lock); SnapSetContext *ssc = new SnapSetContext(oid.get_snapdir()); _register_snapset_context(ssc); ssc->ref++; return ssc; } SnapSetContext *ReplicatedPG::get_snapset_context( const hobject_t& oid, bool can_create, map *attrs) { Mutex::Locker l(snapset_contexts_lock); SnapSetContext *ssc; map::iterator p = snapset_contexts.find( oid.get_snapdir()); if (p != snapset_contexts.end()) { if (can_create || p->second->exists) { ssc = p->second; ssc->exists = true; } else { return NULL; } } else { bufferlist bv; if (!attrs) { int r = pgbackend->objects_get_attr(oid.get_head(), SS_ATTR, &bv); if (r < 0) { // try _snapset r = pgbackend->objects_get_attr(oid.get_snapdir(), SS_ATTR, &bv); if (r < 0 && !can_create) return NULL; } } else { assert(attrs->count(SS_ATTR)); bv = attrs->find(SS_ATTR)->second; } ssc = new SnapSetContext(oid.get_snapdir()); _register_snapset_context(ssc); if (bv.length()) { bufferlist::iterator bvp = bv.begin(); ssc->snapset.decode(bvp); } } assert(ssc); ssc->ref++; return ssc; } void ReplicatedPG::put_snapset_context(SnapSetContext *ssc) { Mutex::Locker l(snapset_contexts_lock); --ssc->ref; if (ssc->ref == 0) { if (ssc->registered) snapset_contexts.erase(ssc->oid); delete ssc; } } // sub op modify void ReplicatedBackend::sub_op_modify(OpRequestRef op) { MOSDSubOp *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); const hobject_t& soid = m->poid; const char *opname; if (m->noop) opname = "no-op"; else if (m->ops.size()) opname = ceph_osd_op_name(m->ops[0].op.op); else opname = "trans"; dout(10) << "sub_op_modify " << opname << " " << soid << " v " << m->version << (m->noop ? " NOOP" : "") << (m->logbl.length() ? " (transaction)" : " (parallel exec") << " " << m->logbl.length() << dendl; // sanity checks assert(m->map_epoch >= get_info().history.same_interval_since); // we better not be missing this. assert(!parent->get_log().get_missing().is_missing(soid)); int ackerosd = m->get_source().num(); op->mark_started(); RepModifyRef rm(new RepModify); rm->op = op; rm->ackerosd = ackerosd; rm->last_complete = get_info().last_complete; rm->epoch_started = get_osdmap()->get_epoch(); if (!m->noop) { assert(m->logbl.length()); // shipped transaction and log entries vector log; bufferlist::iterator p = m->get_data().begin(); ::decode(rm->opt, p); if (!(m->get_connection()->get_features() & CEPH_FEATURE_OSD_SNAPMAPPER)) rm->opt.set_tolerate_collection_add_enoent(); if (m->new_temp_oid != hobject_t()) { dout(20) << __func__ << " start tracking temp " << m->new_temp_oid << dendl; add_temp_obj(m->new_temp_oid); get_temp_coll(&rm->localt); } if (m->discard_temp_oid != hobject_t()) { dout(20) << __func__ << " stop tracking temp " << m->discard_temp_oid << dendl; if (rm->opt.empty()) { dout(10) << __func__ << ": removing object " << m->discard_temp_oid << " since we won't get the transaction" << dendl; rm->localt.remove(temp_coll, m->discard_temp_oid); } clear_temp_obj(m->discard_temp_oid); } p = m->logbl.begin(); ::decode(log, p); if (m->hobject_incorrect_pool) { for (vector::iterator i = log.begin(); i != log.end(); ++i) { if (!i->soid.is_max() && i->soid.pool == -1) i->soid.pool = get_info().pgid.pool(); } rm->opt.set_pool_override(get_info().pgid.pool()); } rm->opt.set_replica(); bool update_snaps = false; if (!rm->opt.empty()) { // If the opt is non-empty, we infer we are before // last_backfill (according to the primary, not our // not-quite-accurate value), and should update the // collections now. Otherwise, we do it later on push. update_snaps = true; } parent->update_stats(m->pg_stats); parent->log_operation( log, m->updated_hit_set_history, m->pg_trim_to, m->pg_trim_rollback_to, update_snaps, &(rm->localt)); rm->bytes_written = rm->opt.get_encoded_bytes(); } else { assert(0); #if 0 // just trim the log if (m->pg_trim_to != eversion_t()) { pg_log.trim(m->pg_trim_to, info); dirty_info = true; write_if_dirty(rm->localt); } #endif } op->mark_started(); rm->localt.append(rm->opt); rm->localt.register_on_commit( parent->bless_context( new C_OSD_RepModifyCommit(this, rm))); rm->localt.register_on_applied( parent->bless_context( new C_OSD_RepModifyApply(this, rm))); parent->queue_transaction(&(rm->localt), op); // op is cleaned up by oncommit/onapply when both are executed } void ReplicatedBackend::sub_op_modify_applied(RepModifyRef rm) { rm->op->mark_event("sub_op_applied"); rm->applied = true; dout(10) << "sub_op_modify_applied on " << rm << " op " << *rm->op->get_req() << dendl; MOSDSubOp *m = static_cast(rm->op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); if (!rm->committed) { // send ack to acker only if we haven't sent a commit already MOSDSubOpReply *ack = new MOSDSubOpReply( m, parent->whoami_shard(), 0, get_osdmap()->get_epoch(), CEPH_OSD_FLAG_ACK); ack->set_priority(CEPH_MSG_PRIO_HIGH); // this better match commit priority! get_parent()->send_message_osd_cluster( rm->ackerosd, ack, get_osdmap()->get_epoch()); } parent->op_applied(m->version); } void ReplicatedBackend::sub_op_modify_commit(RepModifyRef rm) { rm->op->mark_commit_sent(); rm->committed = true; // send commit. dout(10) << "sub_op_modify_commit on op " << *rm->op->get_req() << ", sending commit to osd." << rm->ackerosd << dendl; assert(get_osdmap()->is_up(rm->ackerosd)); get_parent()->update_last_complete_ondisk(rm->last_complete); MOSDSubOpReply *commit = new MOSDSubOpReply( static_cast(rm->op->get_req()), get_parent()->whoami_shard(), 0, get_osdmap()->get_epoch(), CEPH_OSD_FLAG_ONDISK); commit->set_last_complete_ondisk(rm->last_complete); commit->set_priority(CEPH_MSG_PRIO_HIGH); // this better match ack priority! get_parent()->send_message_osd_cluster( rm->ackerosd, commit, get_osdmap()->get_epoch()); log_subop_stats(get_parent()->get_logger(), rm->op, l_osd_sop_w_inb, l_osd_sop_w_lat); } // =========================================================== void ReplicatedBackend::calc_head_subsets( ObjectContextRef obc, SnapSet& snapset, const hobject_t& head, const pg_missing_t& missing, const hobject_t &last_backfill, interval_set& data_subset, map >& clone_subsets) { dout(10) << "calc_head_subsets " << head << " clone_overlap " << snapset.clone_overlap << dendl; uint64_t size = obc->obs.oi.size; if (size) data_subset.insert(0, size); if (get_parent()->get_pool().allow_incomplete_clones()) { dout(10) << __func__ << ": caching (was) enabled, skipping clone subsets" << dendl; return; } if (!cct->_conf->osd_recover_clone_overlap) { dout(10) << "calc_head_subsets " << head << " -- osd_recover_clone_overlap disabled" << dendl; return; } interval_set cloning; interval_set prev; if (size) prev.insert(0, size); for (int j=snapset.clones.size()-1; j>=0; j--) { hobject_t c = head; c.snap = snapset.clones[j]; prev.intersection_of(snapset.clone_overlap[snapset.clones[j]]); if (!missing.is_missing(c) && c < last_backfill) { dout(10) << "calc_head_subsets " << head << " has prev " << c << " overlap " << prev << dendl; clone_subsets[c] = prev; cloning.union_of(prev); break; } dout(10) << "calc_head_subsets " << head << " does not have prev " << c << " overlap " << prev << dendl; } if (cloning.num_intervals() > cct->_conf->osd_recover_clone_overlap_limit) { dout(10) << "skipping clone, too many holes" << dendl; clone_subsets.clear(); cloning.clear(); } // what's left for us to push? data_subset.subtract(cloning); dout(10) << "calc_head_subsets " << head << " data_subset " << data_subset << " clone_subsets " << clone_subsets << dendl; } void ReplicatedBackend::calc_clone_subsets( SnapSet& snapset, const hobject_t& soid, const pg_missing_t& missing, const hobject_t &last_backfill, interval_set& data_subset, map >& clone_subsets) { dout(10) << "calc_clone_subsets " << soid << " clone_overlap " << snapset.clone_overlap << dendl; uint64_t size = snapset.clone_size[soid.snap]; if (size) data_subset.insert(0, size); if (get_parent()->get_pool().allow_incomplete_clones()) { dout(10) << __func__ << ": caching (was) enabled, skipping clone subsets" << dendl; return; } if (!cct->_conf->osd_recover_clone_overlap) { dout(10) << "calc_clone_subsets " << soid << " -- osd_recover_clone_overlap disabled" << dendl; return; } unsigned i; for (i=0; i < snapset.clones.size(); i++) if (snapset.clones[i] == soid.snap) break; // any overlap with next older clone? interval_set cloning; interval_set prev; if (size) prev.insert(0, size); for (int j=i-1; j>=0; j--) { hobject_t c = soid; c.snap = snapset.clones[j]; prev.intersection_of(snapset.clone_overlap[snapset.clones[j]]); if (!missing.is_missing(c) && c < last_backfill) { dout(10) << "calc_clone_subsets " << soid << " has prev " << c << " overlap " << prev << dendl; clone_subsets[c] = prev; cloning.union_of(prev); break; } dout(10) << "calc_clone_subsets " << soid << " does not have prev " << c << " overlap " << prev << dendl; } // overlap with next newest? interval_set next; if (size) next.insert(0, size); for (unsigned j=i+1; j cct->_conf->osd_recover_clone_overlap_limit) { dout(10) << "skipping clone, too many holes" << dendl; clone_subsets.clear(); cloning.clear(); } // what's left for us to push? data_subset.subtract(cloning); dout(10) << "calc_clone_subsets " << soid << " data_subset " << data_subset << " clone_subsets " << clone_subsets << dendl; } /** pull - request object from a peer */ /* * Return values: * NONE - didn't pull anything * YES - pulled what the caller wanted * OTHER - needed to pull something else first (_head or _snapdir) */ enum { PULL_NONE, PULL_OTHER, PULL_YES }; void ReplicatedBackend::prepare_pull( eversion_t v, const hobject_t& soid, ObjectContextRef headctx, RPGHandle *h) { assert(get_parent()->get_local_missing().missing.count(soid)); eversion_t _v = get_parent()->get_local_missing().missing.find( soid)->second.need; assert(_v == v); const map > &missing_loc( get_parent()->get_missing_loc_shards()); const map &peer_missing( get_parent()->get_shard_missing()); map >::const_iterator q = missing_loc.find(soid); assert(q != missing_loc.end()); assert(!q->second.empty()); // pick a pullee vector shuffle(q->second.begin(), q->second.end()); random_shuffle(shuffle.begin(), shuffle.end()); vector::iterator p = shuffle.begin(); assert(get_osdmap()->is_up(p->osd)); pg_shard_t fromshard = *p; dout(7) << "pull " << soid << " v " << v << " on osds " << *p << " from osd." << fromshard << dendl; assert(peer_missing.count(fromshard)); const pg_missing_t &pmissing = peer_missing.find(fromshard)->second; if (pmissing.is_missing(soid, v)) { assert(pmissing.missing.find(soid)->second.have != v); dout(10) << "pulling soid " << soid << " from osd " << fromshard << " at version " << pmissing.missing.find(soid)->second.have << " rather than at version " << v << dendl; v = pmissing.missing.find(soid)->second.have; assert(get_parent()->get_log().get_log().objects.count(soid) && (get_parent()->get_log().get_log().objects.find(soid)->second->op == pg_log_entry_t::LOST_REVERT) && (get_parent()->get_log().get_log().objects.find( soid)->second->reverting_to == v)); } ObjectRecoveryInfo recovery_info; if (soid.is_snap()) { assert(!get_parent()->get_local_missing().is_missing( soid.get_head()) || !get_parent()->get_local_missing().is_missing( soid.get_snapdir())); assert(headctx); // check snapset SnapSetContext *ssc = headctx->ssc; assert(ssc); dout(10) << " snapset " << ssc->snapset << dendl; calc_clone_subsets(ssc->snapset, soid, get_parent()->get_local_missing(), get_info().last_backfill, recovery_info.copy_subset, recovery_info.clone_subset); // FIXME: this may overestimate if we are pulling multiple clones in parallel... dout(10) << " pulling " << recovery_info << dendl; } else { // pulling head or unversioned object. // always pull the whole thing. recovery_info.copy_subset.insert(0, (uint64_t)-1); recovery_info.size = ((uint64_t)-1); } h->pulls[fromshard].push_back(PullOp()); PullOp &op = h->pulls[fromshard].back(); op.soid = soid; op.recovery_info = recovery_info; op.recovery_info.soid = soid; op.recovery_info.version = v; op.recovery_progress.data_complete = false; op.recovery_progress.omap_complete = false; op.recovery_progress.data_recovered_to = 0; op.recovery_progress.first = true; assert(!pulling.count(soid)); pull_from_peer[fromshard].insert(soid); PullInfo &pi = pulling[soid]; pi.head_ctx = headctx; pi.recovery_info = op.recovery_info; pi.recovery_progress = op.recovery_progress; } int ReplicatedPG::recover_missing( const hobject_t &soid, eversion_t v, int priority, PGBackend::RecoveryHandle *h) { if (missing_loc.is_unfound(soid)) { dout(7) << "pull " << soid << " v " << v << " but it is unfound" << dendl; return PULL_NONE; } // is this a snapped object? if so, consult the snapset.. we may not need the entire object! ObjectContextRef obc; ObjectContextRef head_obc; if (soid.snap && soid.snap < CEPH_NOSNAP) { // do we have the head and/or snapdir? hobject_t head = soid.get_head(); if (pg_log.get_missing().is_missing(head)) { if (recovering.count(head)) { dout(10) << " missing but already recovering head " << head << dendl; return PULL_NONE; } else { int r = recover_missing( head, pg_log.get_missing().missing.find(head)->second.need, priority, h); if (r != PULL_NONE) return PULL_OTHER; return PULL_NONE; } } head = soid.get_snapdir(); if (pg_log.get_missing().is_missing(head)) { if (recovering.count(head)) { dout(10) << " missing but already recovering snapdir " << head << dendl; return PULL_NONE; } else { int r = recover_missing( head, pg_log.get_missing().missing.find(head)->second.need, priority, h); if (r != PULL_NONE) return PULL_OTHER; return PULL_NONE; } } // we must have one or the other head_obc = get_object_context( soid.get_head(), false, 0); if (!head_obc) head_obc = get_object_context( soid.get_snapdir(), false, 0); assert(head_obc); } start_recovery_op(soid); assert(!recovering.count(soid)); recovering.insert(make_pair(soid, obc)); pgbackend->recover_object( soid, v, head_obc, obc, h); return PULL_YES; } void ReplicatedPG::send_remove_op( const hobject_t& oid, eversion_t v, pg_shard_t peer) { ceph_tid_t tid = osd->get_tid(); osd_reqid_t rid(osd->get_cluster_msgr_name(), 0, tid); dout(10) << "send_remove_op " << oid << " from osd." << peer << " tid " << tid << dendl; MOSDSubOp *subop = new MOSDSubOp( rid, pg_whoami, spg_t(info.pgid.pgid, peer.shard), oid, false, CEPH_OSD_FLAG_ACK, get_osdmap()->get_epoch(), tid, v); subop->ops = vector(1); subop->ops[0].op.op = CEPH_OSD_OP_DELETE; osd->send_message_osd_cluster(peer.osd, subop, get_osdmap()->get_epoch()); } /* * intelligently push an object to a replica. make use of existing * clones/heads and dup data ranges where possible. */ void ReplicatedBackend::prep_push_to_replica( ObjectContextRef obc, const hobject_t& soid, pg_shard_t peer, PushOp *pop) { const object_info_t& oi = obc->obs.oi; uint64_t size = obc->obs.oi.size; dout(10) << __func__ << ": " << soid << " v" << oi.version << " size " << size << " to osd." << peer << dendl; map > clone_subsets; interval_set data_subset; // are we doing a clone on the replica? if (soid.snap && soid.snap < CEPH_NOSNAP) { hobject_t head = soid; head.snap = CEPH_NOSNAP; // try to base push off of clones that succeed/preceed poid // we need the head (and current SnapSet) locally to do that. if (get_parent()->get_local_missing().is_missing(head)) { dout(15) << "push_to_replica missing head " << head << ", pushing raw clone" << dendl; return prep_push(obc, soid, peer, pop); } hobject_t snapdir = head; snapdir.snap = CEPH_SNAPDIR; if (get_parent()->get_local_missing().is_missing(snapdir)) { dout(15) << "push_to_replica missing snapdir " << snapdir << ", pushing raw clone" << dendl; return prep_push(obc, soid, peer, pop); } SnapSetContext *ssc = obc->ssc; assert(ssc); dout(15) << "push_to_replica snapset is " << ssc->snapset << dendl; map::const_iterator pm = get_parent()->get_shard_missing().find(peer); assert(pm != get_parent()->get_shard_missing().end()); map::const_iterator pi = get_parent()->get_shard_info().find(peer); assert(pi != get_parent()->get_shard_info().end()); calc_clone_subsets(ssc->snapset, soid, pm->second, pi->second.last_backfill, data_subset, clone_subsets); } else if (soid.snap == CEPH_NOSNAP) { // pushing head or unversioned object. // base this on partially on replica's clones? SnapSetContext *ssc = obc->ssc; assert(ssc); dout(15) << "push_to_replica snapset is " << ssc->snapset << dendl; calc_head_subsets( obc, ssc->snapset, soid, get_parent()->get_shard_missing().find(peer)->second, get_parent()->get_shard_info().find(peer)->second.last_backfill, data_subset, clone_subsets); } prep_push(obc, soid, peer, oi.version, data_subset, clone_subsets, pop); } void ReplicatedBackend::prep_push(ObjectContextRef obc, const hobject_t& soid, pg_shard_t peer, PushOp *pop) { interval_set data_subset; if (obc->obs.oi.size) data_subset.insert(0, obc->obs.oi.size); map > clone_subsets; prep_push(obc, soid, peer, obc->obs.oi.version, data_subset, clone_subsets, pop); } void ReplicatedBackend::prep_push( ObjectContextRef obc, const hobject_t& soid, pg_shard_t peer, eversion_t version, interval_set &data_subset, map >& clone_subsets, PushOp *pop) { get_parent()->begin_peer_recover(peer, soid); // take note. PushInfo &pi = pushing[soid][peer]; pi.obc = obc; pi.recovery_info.size = obc->obs.oi.size; pi.recovery_info.copy_subset = data_subset; pi.recovery_info.clone_subset = clone_subsets; pi.recovery_info.soid = soid; pi.recovery_info.oi = obc->obs.oi; pi.recovery_info.version = version; pi.recovery_progress.first = true; pi.recovery_progress.data_recovered_to = 0; pi.recovery_progress.data_complete = 0; pi.recovery_progress.omap_complete = 0; ObjectRecoveryProgress new_progress; int r = build_push_op(pi.recovery_info, pi.recovery_progress, &new_progress, pop, &(pi.stat)); assert(r == 0); pi.recovery_progress = new_progress; } int ReplicatedBackend::send_pull_legacy(int prio, pg_shard_t peer, const ObjectRecoveryInfo &recovery_info, ObjectRecoveryProgress progress) { // send op ceph_tid_t tid = get_parent()->get_tid(); osd_reqid_t rid(get_parent()->get_cluster_msgr_name(), 0, tid); dout(10) << "send_pull_op " << recovery_info.soid << " " << recovery_info.version << " first=" << progress.first << " data " << recovery_info.copy_subset << " from osd." << peer << " tid " << tid << dendl; MOSDSubOp *subop = new MOSDSubOp( rid, parent->whoami_shard(), get_info().pgid, recovery_info.soid, false, CEPH_OSD_FLAG_ACK, get_osdmap()->get_epoch(), tid, recovery_info.version); subop->set_priority(prio); subop->ops = vector(1); subop->ops[0].op.op = CEPH_OSD_OP_PULL; subop->ops[0].op.extent.length = cct->_conf->osd_recovery_max_chunk; subop->recovery_info = recovery_info; subop->recovery_progress = progress; get_parent()->send_message_osd_cluster( peer.osd, subop, get_osdmap()->get_epoch()); get_parent()->get_logger()->inc(l_osd_pull); return 0; } void ReplicatedBackend::submit_push_data( ObjectRecoveryInfo &recovery_info, bool first, bool complete, const interval_set &intervals_included, bufferlist data_included, bufferlist omap_header, map &attrs, map &omap_entries, ObjectStore::Transaction *t) { coll_t target_coll; if (first && complete) { target_coll = coll; } else { dout(10) << __func__ << ": Creating oid " << recovery_info.soid << " in the temp collection" << dendl; add_temp_obj(recovery_info.soid); target_coll = get_temp_coll(t); } if (first) { get_parent()->on_local_recover_start(recovery_info.soid, t); t->remove(get_temp_coll(t), recovery_info.soid); t->touch(target_coll, recovery_info.soid); t->omap_setheader(target_coll, recovery_info.soid, omap_header); } uint64_t off = 0; for (interval_set::const_iterator p = intervals_included.begin(); p != intervals_included.end(); ++p) { bufferlist bit; bit.substr_of(data_included, off, p.get_len()); t->write(target_coll, recovery_info.soid, p.get_start(), p.get_len(), bit); off += p.get_len(); } t->omap_setkeys(target_coll, recovery_info.soid, omap_entries); t->setattrs(target_coll, recovery_info.soid, attrs); if (complete) { if (!first) { dout(10) << __func__ << ": Removing oid " << recovery_info.soid << " from the temp collection" << dendl; clear_temp_obj(recovery_info.soid); t->collection_move(coll, target_coll, recovery_info.soid); } submit_push_complete(recovery_info, t); } } void ReplicatedBackend::submit_push_complete(ObjectRecoveryInfo &recovery_info, ObjectStore::Transaction *t) { for (map >::const_iterator p = recovery_info.clone_subset.begin(); p != recovery_info.clone_subset.end(); ++p) { for (interval_set::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(15) << " clone_range " << p->first << " " << q.get_start() << "~" << q.get_len() << dendl; t->clone_range(coll, p->first, recovery_info.soid, q.get_start(), q.get_len(), q.get_start()); } } } ObjectRecoveryInfo ReplicatedBackend::recalc_subsets( const ObjectRecoveryInfo& recovery_info, SnapSetContext *ssc) { if (!recovery_info.soid.snap || recovery_info.soid.snap >= CEPH_NOSNAP) return recovery_info; ObjectRecoveryInfo new_info = recovery_info; new_info.copy_subset.clear(); new_info.clone_subset.clear(); assert(ssc); calc_clone_subsets(ssc->snapset, new_info.soid, get_parent()->get_local_missing(), get_info().last_backfill, new_info.copy_subset, new_info.clone_subset); return new_info; } bool ReplicatedBackend::handle_pull_response( pg_shard_t from, PushOp &pop, PullOp *response, list *to_continue, ObjectStore::Transaction *t ) { interval_set data_included = pop.data_included; bufferlist data; data.claim(pop.data); dout(10) << "handle_pull_response " << pop.recovery_info << pop.after_progress << " data.size() is " << data.length() << " data_included: " << data_included << dendl; if (pop.version == eversion_t()) { // replica doesn't have it! _failed_push(from, pop.soid); return false; } hobject_t &hoid = pop.soid; assert((data_included.empty() && data.length() == 0) || (!data_included.empty() && data.length() > 0)); if (!pulling.count(hoid)) { return false; } PullInfo &pi = pulling[hoid]; if (pi.recovery_info.size == (uint64_t(-1))) { pi.recovery_info.size = pop.recovery_info.size; pi.recovery_info.copy_subset.intersection_of( pop.recovery_info.copy_subset); } bool first = pi.recovery_progress.first; if (first) { pi.obc = get_parent()->get_obc(pi.recovery_info.soid, pop.attrset); pi.recovery_info.oi = pi.obc->obs.oi; pi.recovery_info = recalc_subsets(pi.recovery_info, pi.obc->ssc); } interval_set usable_intervals; bufferlist usable_data; trim_pushed_data(pi.recovery_info.copy_subset, data_included, data, &usable_intervals, &usable_data); data_included = usable_intervals; data.claim(usable_data); pi.recovery_progress = pop.after_progress; pi.stat.num_bytes_recovered += data.length(); dout(10) << "new recovery_info " << pi.recovery_info << ", new progress " << pi.recovery_progress << dendl; bool complete = pi.is_complete(); submit_push_data(pi.recovery_info, first, complete, data_included, data, pop.omap_header, pop.attrset, pop.omap_entries, t); pi.stat.num_keys_recovered += pop.omap_entries.size(); if (complete) { to_continue->push_back(hoid); pi.stat.num_objects_recovered++; get_parent()->on_local_recover( hoid, pi.stat, pi.recovery_info, pi.obc, t); pull_from_peer[from].erase(hoid); if (pull_from_peer[from].empty()) pull_from_peer.erase(from); return false; } else { response->soid = pop.soid; response->recovery_info = pi.recovery_info; response->recovery_progress = pi.recovery_progress; return true; } } struct C_OnPushCommit : public Context { ReplicatedPG *pg; OpRequestRef op; C_OnPushCommit(ReplicatedPG *pg, OpRequestRef op) : pg(pg), op(op) {} void finish(int) { op->mark_event("committed"); log_subop_stats(pg->osd->logger, op, l_osd_push_inb, l_osd_sop_push_lat); } }; void ReplicatedBackend::handle_push( pg_shard_t from, PushOp &pop, PushReplyOp *response, ObjectStore::Transaction *t) { dout(10) << "handle_push " << pop.recovery_info << pop.after_progress << dendl; bufferlist data; data.claim(pop.data); bool first = pop.before_progress.first; bool complete = pop.after_progress.data_complete && pop.after_progress.omap_complete; response->soid = pop.recovery_info.soid; submit_push_data(pop.recovery_info, first, complete, pop.data_included, data, pop.omap_header, pop.attrset, pop.omap_entries, t); if (complete) get_parent()->on_local_recover( pop.recovery_info.soid, object_stat_sum_t(), pop.recovery_info, ObjectContextRef(), // ok, is replica t); } void ReplicatedBackend::send_pushes(int prio, map > &pushes) { for (map >::iterator i = pushes.begin(); i != pushes.end(); ++i) { ConnectionRef con = get_parent()->get_con_osd_cluster( i->first.osd, get_osdmap()->get_epoch()); if (!con) continue; if (!(con->get_features() & CEPH_FEATURE_OSD_PACKED_RECOVERY)) { for (vector::iterator j = i->second.begin(); j != i->second.end(); ++j) { dout(20) << __func__ << ": sending push (legacy) " << *j << " to osd." << i->first << dendl; send_push_op_legacy(prio, i->first, *j); } } else { vector::iterator j = i->second.begin(); while (j != i->second.end()) { uint64_t cost = 0; uint64_t pushes = 0; MOSDPGPush *msg = new MOSDPGPush(); msg->from = get_parent()->whoami_shard(); msg->pgid = get_parent()->primary_spg_t(); msg->map_epoch = get_osdmap()->get_epoch(); msg->set_priority(prio); for (; (j != i->second.end() && cost < cct->_conf->osd_max_push_cost && pushes < cct->_conf->osd_max_push_objects) ; ++j) { dout(20) << __func__ << ": sending push " << *j << " to osd." << i->first << dendl; cost += j->cost(cct); pushes += 1; msg->pushes.push_back(*j); } msg->compute_cost(cct); get_parent()->send_message_osd_cluster(msg, con); } } } } void ReplicatedBackend::send_pulls(int prio, map > &pulls) { for (map >::iterator i = pulls.begin(); i != pulls.end(); ++i) { ConnectionRef con = get_parent()->get_con_osd_cluster( i->first.osd, get_osdmap()->get_epoch()); if (!con) continue; if (!(con->get_features() & CEPH_FEATURE_OSD_PACKED_RECOVERY)) { for (vector::iterator j = i->second.begin(); j != i->second.end(); ++j) { dout(20) << __func__ << ": sending pull (legacy) " << *j << " to osd." << i->first << dendl; send_pull_legacy( prio, i->first, j->recovery_info, j->recovery_progress); } } else { dout(20) << __func__ << ": sending pulls " << i->second << " to osd." << i->first << dendl; MOSDPGPull *msg = new MOSDPGPull(); msg->from = parent->whoami_shard(); msg->set_priority(prio); msg->pgid = get_parent()->primary_spg_t(); msg->map_epoch = get_osdmap()->get_epoch(); msg->pulls.swap(i->second); msg->compute_cost(cct); get_parent()->send_message_osd_cluster(msg, con); } } } int ReplicatedBackend::build_push_op(const ObjectRecoveryInfo &recovery_info, const ObjectRecoveryProgress &progress, ObjectRecoveryProgress *out_progress, PushOp *out_op, object_stat_sum_t *stat) { ObjectRecoveryProgress _new_progress; if (!out_progress) out_progress = &_new_progress; ObjectRecoveryProgress &new_progress = *out_progress; new_progress = progress; dout(7) << "send_push_op " << recovery_info.soid << " v " << recovery_info.version << " size " << recovery_info.size << " recovery_info: " << recovery_info << dendl; if (progress.first) { store->omap_get_header(coll, recovery_info.soid, &out_op->omap_header); store->getattrs(coll, recovery_info.soid, out_op->attrset); // Debug bufferlist bv = out_op->attrset[OI_ATTR]; object_info_t oi(bv); if (oi.version != recovery_info.version) { get_parent()->clog_error() << get_info().pgid << " push " << recovery_info.soid << " v " << recovery_info.version << " failed because local copy is " << oi.version << "\n"; return -EINVAL; } new_progress.first = false; } uint64_t available = cct->_conf->osd_recovery_max_chunk; if (!progress.omap_complete) { ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(coll, recovery_info.soid); for (iter->lower_bound(progress.omap_recovered_to); iter->valid(); iter->next()) { if (!out_op->omap_entries.empty() && available <= (iter->key().size() + iter->value().length())) break; out_op->omap_entries.insert(make_pair(iter->key(), iter->value())); if ((iter->key().size() + iter->value().length()) <= available) available -= (iter->key().size() + iter->value().length()); else available = 0; } if (!iter->valid()) new_progress.omap_complete = true; else new_progress.omap_recovered_to = iter->key(); } if (available > 0) { out_op->data_included.span_of(recovery_info.copy_subset, progress.data_recovered_to, available); } else { out_op->data_included.clear(); } for (interval_set::iterator p = out_op->data_included.begin(); p != out_op->data_included.end(); ++p) { bufferlist bit; store->read(coll, recovery_info.soid, p.get_start(), p.get_len(), bit); if (p.get_len() != bit.length()) { dout(10) << " extent " << p.get_start() << "~" << p.get_len() << " is actually " << p.get_start() << "~" << bit.length() << dendl; interval_set::iterator save = p++; if (bit.length() == 0) out_op->data_included.erase(save); //Remove this empty interval else save.set_len(bit.length()); // Remove any other intervals present while (p != out_op->data_included.end()) { interval_set::iterator save = p++; out_op->data_included.erase(save); } new_progress.data_complete = true; out_op->data.claim_append(bit); break; } out_op->data.claim_append(bit); } if (!out_op->data_included.empty()) new_progress.data_recovered_to = out_op->data_included.range_end(); if (new_progress.is_complete(recovery_info)) { new_progress.data_complete = true; if (stat) stat->num_objects_recovered++; } if (stat) { stat->num_keys_recovered += out_op->omap_entries.size(); stat->num_bytes_recovered += out_op->data.length(); } get_parent()->get_logger()->inc(l_osd_push); get_parent()->get_logger()->inc(l_osd_push_outb, out_op->data.length()); // send out_op->version = recovery_info.version; out_op->soid = recovery_info.soid; out_op->recovery_info = recovery_info; out_op->after_progress = new_progress; out_op->before_progress = progress; return 0; } int ReplicatedBackend::send_push_op_legacy(int prio, pg_shard_t peer, PushOp &pop) { ceph_tid_t tid = get_parent()->get_tid(); osd_reqid_t rid(get_parent()->get_cluster_msgr_name(), 0, tid); MOSDSubOp *subop = new MOSDSubOp( rid, parent->whoami_shard(), spg_t(get_info().pgid.pgid, peer.shard), pop.soid, false, 0, get_osdmap()->get_epoch(), tid, pop.recovery_info.version); subop->ops = vector(1); subop->ops[0].op.op = CEPH_OSD_OP_PUSH; subop->set_priority(prio); subop->version = pop.version; subop->ops[0].indata.claim(pop.data); subop->data_included.swap(pop.data_included); subop->omap_header.claim(pop.omap_header); subop->omap_entries.swap(pop.omap_entries); subop->attrset.swap(pop.attrset); subop->recovery_info = pop.recovery_info; subop->current_progress = pop.before_progress; subop->recovery_progress = pop.after_progress; get_parent()->send_message_osd_cluster(peer.osd, subop, get_osdmap()->get_epoch()); return 0; } void ReplicatedBackend::prep_push_op_blank(const hobject_t& soid, PushOp *op) { op->recovery_info.version = eversion_t(); op->version = eversion_t(); op->soid = soid; } void ReplicatedBackend::sub_op_push_reply(OpRequestRef op) { MOSDSubOpReply *reply = static_cast(op->get_req()); const hobject_t& soid = reply->get_poid(); assert(reply->get_header().type == MSG_OSD_SUBOPREPLY); dout(10) << "sub_op_push_reply from " << reply->get_source() << " " << *reply << dendl; pg_shard_t peer = reply->from; op->mark_started(); PushReplyOp rop; rop.soid = soid; PushOp pop; bool more = handle_push_reply(peer, rop, &pop); if (more) send_push_op_legacy(op->get_req()->get_priority(), peer, pop); } bool ReplicatedBackend::handle_push_reply(pg_shard_t peer, PushReplyOp &op, PushOp *reply) { const hobject_t &soid = op.soid; if (pushing.count(soid) == 0) { dout(10) << "huh, i wasn't pushing " << soid << " to osd." << peer << ", or anybody else" << dendl; return false; } else if (pushing[soid].count(peer) == 0) { dout(10) << "huh, i wasn't pushing " << soid << " to osd." << peer << dendl; return false; } else { PushInfo *pi = &pushing[soid][peer]; if (!pi->recovery_progress.data_complete) { dout(10) << " pushing more from, " << pi->recovery_progress.data_recovered_to << " of " << pi->recovery_info.copy_subset << dendl; ObjectRecoveryProgress new_progress; int r = build_push_op( pi->recovery_info, pi->recovery_progress, &new_progress, reply, &(pi->stat)); assert(r == 0); pi->recovery_progress = new_progress; return true; } else { // done! get_parent()->on_peer_recover( peer, soid, pi->recovery_info, pi->stat); pushing[soid].erase(peer); pi = NULL; if (pushing[soid].empty()) { get_parent()->on_global_recover(soid); pushing.erase(soid); } else { dout(10) << "pushed " << soid << ", still waiting for push ack from " << pushing[soid].size() << " others" << dendl; } return false; } } } void ReplicatedPG::finish_degraded_object(const hobject_t& oid) { dout(10) << "finish_degraded_object " << oid << dendl; ObjectContextRef obc(object_contexts.lookup(oid)); if (obc) { for (set::iterator j = obc->blocking.begin(); j != obc->blocking.end(); obc->blocking.erase(j++)) { dout(10) << " no longer blocking writes for " << (*j)->obs.oi.soid << dendl; (*j)->blocked_by = ObjectContextRef(); } } if (callbacks_for_degraded_object.count(oid)) { list contexts; contexts.swap(callbacks_for_degraded_object[oid]); callbacks_for_degraded_object.erase(oid); for (list::iterator i = contexts.begin(); i != contexts.end(); ++i) { (*i)->complete(0); } } } /** op_pull * process request to pull an entire object. * NOTE: called from opqueue. */ void ReplicatedBackend::sub_op_pull(OpRequestRef op) { MOSDSubOp *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); op->mark_started(); const hobject_t soid = m->poid; dout(7) << "pull" << soid << " v " << m->version << " from " << m->get_source() << dendl; assert(!is_primary()); // we should be a replica or stray. PullOp pop; pop.soid = soid; pop.recovery_info = m->recovery_info; pop.recovery_progress = m->recovery_progress; PushOp reply; handle_pull(m->from, pop, &reply); send_push_op_legacy( m->get_priority(), m->from, reply); log_subop_stats(get_parent()->get_logger(), op, 0, l_osd_sop_pull_lat); } void ReplicatedBackend::handle_pull(pg_shard_t peer, PullOp &op, PushOp *reply) { const hobject_t &soid = op.soid; struct stat st; int r = store->stat(coll, soid, &st); if (r != 0) { get_parent()->clog_error() << get_info().pgid << " " << peer << " tried to pull " << soid << " but got " << cpp_strerror(-r) << "\n"; prep_push_op_blank(soid, reply); } else { ObjectRecoveryInfo &recovery_info = op.recovery_info; ObjectRecoveryProgress &progress = op.recovery_progress; if (progress.first && recovery_info.size == ((uint64_t)-1)) { // Adjust size and copy_subset recovery_info.size = st.st_size; recovery_info.copy_subset.clear(); if (st.st_size) recovery_info.copy_subset.insert(0, st.st_size); assert(recovery_info.clone_subset.empty()); } r = build_push_op(recovery_info, progress, 0, reply); if (r < 0) prep_push_op_blank(soid, reply); } } void ReplicatedPG::_committed_pushed_object( epoch_t epoch, eversion_t last_complete) { lock(); if (!pg_has_reset_since(epoch)) { dout(10) << "_committed_pushed_object last_complete " << last_complete << " now ondisk" << dendl; last_complete_ondisk = last_complete; if (last_complete_ondisk == info.last_update) { if (!is_primary()) { // Either we are a replica or backfill target. // we are fully up to date. tell the primary! osd->send_message_osd_cluster( get_primary().osd, new MOSDPGTrim( get_osdmap()->get_epoch(), spg_t(info.pgid.pgid, primary.shard), last_complete_ondisk), get_osdmap()->get_epoch()); } else { // we are the primary. tell replicas to trim? if (calc_min_last_complete_ondisk()) trim_peers(); } } } else { dout(10) << "_committed_pushed_object pg has changed, not touching last_complete_ondisk" << dendl; } unlock(); } void ReplicatedPG::_applied_recovered_object(ObjectContextRef obc) { lock(); dout(10) << "_applied_recovered_object " << *obc << dendl; assert(active_pushes >= 1); --active_pushes; // requeue an active chunky scrub waiting on recovery ops if (!deleting && active_pushes == 0 && scrubber.is_chunky_scrub_active()) { osd->scrub_wq.queue(this); } unlock(); } void ReplicatedPG::_applied_recovered_object_replica() { lock(); dout(10) << "_applied_recovered_object_replica" << dendl; assert(active_pushes >= 1); --active_pushes; // requeue an active chunky scrub waiting on recovery ops if (!deleting && active_pushes == 0 && scrubber.active_rep_scrub && scrubber.active_rep_scrub->chunky) { osd->rep_scrub_wq.queue(scrubber.active_rep_scrub); scrubber.active_rep_scrub = 0; } unlock(); } void ReplicatedPG::recover_got(hobject_t oid, eversion_t v) { dout(10) << "got missing " << oid << " v " << v << dendl; pg_log.recover_got(oid, v, info); if (pg_log.get_log().complete_to != pg_log.get_log().log.end()) { dout(10) << "last_complete now " << info.last_complete << " log.complete_to " << pg_log.get_log().complete_to->version << dendl; } else { dout(10) << "last_complete now " << info.last_complete << " log.complete_to at end" << dendl; //below is not true in the repair case. //assert(missing.num_missing() == 0); // otherwise, complete_to was wrong. assert(info.last_complete == info.last_update); } } /** * trim received data to remove what we don't want * * @param copy_subset intervals we want * @param data_included intervals we got * @param data_recieved data we got * @param intervals_usable intervals we want to keep * @param data_usable matching data we want to keep */ void ReplicatedBackend::trim_pushed_data( const interval_set ©_subset, const interval_set &intervals_received, bufferlist data_received, interval_set *intervals_usable, bufferlist *data_usable) { if (intervals_received.subset_of(copy_subset)) { *intervals_usable = intervals_received; *data_usable = data_received; return; } intervals_usable->intersection_of(copy_subset, intervals_received); uint64_t off = 0; for (interval_set::const_iterator p = intervals_received.begin(); p != intervals_received.end(); ++p) { interval_set x; x.insert(p.get_start(), p.get_len()); x.intersection_of(copy_subset); for (interval_set::const_iterator q = x.begin(); q != x.end(); ++q) { bufferlist sub; uint64_t data_off = off + (q.get_start() - p.get_start()); sub.substr_of(data_received, data_off, q.get_len()); data_usable->claim_append(sub); } off += p.get_len(); } } /** op_push * NOTE: called from opqueue. */ void ReplicatedBackend::sub_op_push(OpRequestRef op) { op->mark_started(); MOSDSubOp *m = static_cast(op->get_req()); PushOp pop; pop.soid = m->recovery_info.soid; pop.version = m->version; m->claim_data(pop.data); pop.data_included.swap(m->data_included); pop.omap_header.swap(m->omap_header); pop.omap_entries.swap(m->omap_entries); pop.attrset.swap(m->attrset); pop.recovery_info = m->recovery_info; pop.before_progress = m->current_progress; pop.after_progress = m->recovery_progress; ObjectStore::Transaction *t = new ObjectStore::Transaction; if (is_primary()) { PullOp resp; RPGHandle *h = _open_recovery_op(); list to_continue; bool more = handle_pull_response( m->from, pop, &resp, &to_continue, t); if (more) { send_pull_legacy( m->get_priority(), m->from, resp.recovery_info, resp.recovery_progress); } else { C_ReplicatedBackend_OnPullComplete *c = new C_ReplicatedBackend_OnPullComplete( this, op->get_req()->get_priority()); c->to_continue.swap(to_continue); t->register_on_complete( new PG_QueueAsync( get_parent(), get_parent()->bless_gencontext(c))); } run_recovery_op(h, op->get_req()->get_priority()); } else { PushReplyOp resp; MOSDSubOpReply *reply = new MOSDSubOpReply( m, parent->whoami_shard(), 0, get_osdmap()->get_epoch(), CEPH_OSD_FLAG_ACK); reply->set_priority(m->get_priority()); assert(entity_name_t::TYPE_OSD == m->get_connection()->peer_type); handle_push(m->from, pop, &resp, t); t->register_on_complete(new PG_SendMessageOnConn( get_parent(), reply, m->get_connection())); } t->register_on_applied( new ObjectStore::C_DeleteTransaction(t)); get_parent()->queue_transaction(t); return; } void ReplicatedPG::failed_push(pg_shard_t from, const hobject_t &soid) { assert(recovering.count(soid)); recovering.erase(soid); missing_loc.remove_location(soid, from); dout(0) << "_failed_push " << soid << " from shard " << from << ", reps on " << missing_loc.get_locations(soid) << " unfound? " << missing_loc.is_unfound(soid) << dendl; finish_recovery_op(soid); // close out this attempt, } void ReplicatedBackend::_failed_push(pg_shard_t from, const hobject_t &soid) { get_parent()->failed_push(from, soid); pull_from_peer[from].erase(soid); if (pull_from_peer[from].empty()) pull_from_peer.erase(from); pulling.erase(soid); } void ReplicatedPG::sub_op_remove(OpRequestRef op) { MOSDSubOp *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); dout(7) << "sub_op_remove " << m->poid << dendl; op->mark_started(); ObjectStore::Transaction *t = new ObjectStore::Transaction; remove_snap_mapped_object(*t, m->poid); int r = osd->store->queue_transaction_and_cleanup(osr.get(), t); assert(r == 0); } eversion_t ReplicatedPG::pick_newest_available(const hobject_t& oid) { eversion_t v; assert(pg_log.get_missing().is_missing(oid)); v = pg_log.get_missing().missing.find(oid)->second.have; dout(10) << "pick_newest_available " << oid << " " << v << " on osd." << osd->whoami << " (local)" << dendl; assert(actingbackfill.size() > 0); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_shard_t peer = *i; if (!peer_missing[peer].is_missing(oid)) { assert(is_backfill_targets(peer)); continue; } eversion_t h = peer_missing[peer].missing[oid].have; dout(10) << "pick_newest_available " << oid << " " << h << " on osd." << peer << dendl; if (h > v) v = h; } dout(10) << "pick_newest_available " << oid << " " << v << " (newest)" << dendl; return v; } /* Mark an object as lost */ ObjectContextRef ReplicatedPG::mark_object_lost(ObjectStore::Transaction *t, const hobject_t &oid, eversion_t version, utime_t mtime, int what) { // Wake anyone waiting for this object. Now that it's been marked as lost, // we will just return an error code. map >::iterator wmo = waiting_for_unreadable_object.find(oid); if (wmo != waiting_for_unreadable_object.end()) { requeue_ops(wmo->second); } // Add log entry ++info.last_update.version; pg_log_entry_t e(what, oid, info.last_update, version, 0, osd_reqid_t(), mtime); pg_log.add(e); ObjectContextRef obc = get_object_context(oid, true); obc->ondisk_write_lock(); obc->obs.oi.set_flag(object_info_t::FLAG_LOST); obc->obs.oi.version = info.last_update; obc->obs.oi.prior_version = version; bufferlist b2; obc->obs.oi.encode(b2); t->setattr(coll, oid, OI_ATTR, b2); return obc; } struct C_PG_MarkUnfoundLost : public Context { ReplicatedPGRef pg; list obcs; C_PG_MarkUnfoundLost(ReplicatedPG *p) : pg(p) {} void finish(int r) { pg->_finish_mark_all_unfound_lost(obcs); } }; /* Mark all unfound objects as lost. */ void ReplicatedPG::mark_all_unfound_lost(int what) { dout(3) << __func__ << " " << pg_log_entry_t::get_op_name(what) << dendl; dout(30) << __func__ << ": log before:\n"; pg_log.get_log().print(*_dout); *_dout << dendl; ObjectStore::Transaction *t = new ObjectStore::Transaction; C_PG_MarkUnfoundLost *c = new C_PG_MarkUnfoundLost(this); utime_t mtime = ceph_clock_now(cct); info.last_update.epoch = get_osdmap()->get_epoch(); const pg_missing_t &missing = pg_log.get_missing(); map::const_iterator m = missing_loc.get_all_missing().begin(); map::const_iterator mend = missing_loc.get_all_missing().end(); while (m != mend) { const hobject_t &oid(m->first); if (!missing_loc.is_unfound(oid)) { // We only care about unfound objects ++m; continue; } ObjectContextRef obc; eversion_t prev; switch (what) { case pg_log_entry_t::LOST_MARK: obc = mark_object_lost(t, oid, m->second.need, mtime, pg_log_entry_t::LOST_MARK); pg_log.missing_got(m++); assert(0 == "actually, not implemented yet!"); // we need to be careful about how this is handled on the replica! break; case pg_log_entry_t::LOST_REVERT: prev = pick_newest_available(oid); if (prev > eversion_t()) { // log it ++info.last_update.version; pg_log_entry_t e( pg_log_entry_t::LOST_REVERT, oid, info.last_update, m->second.need, 0, osd_reqid_t(), mtime); e.reverting_to = prev; pg_log.add(e); dout(10) << e << dendl; // we are now missing the new version; recovery code will sort it out. ++m; pg_log.revise_need(oid, info.last_update); missing_loc.revise_need(oid, info.last_update); break; } /** fall-thru **/ case pg_log_entry_t::LOST_DELETE: { // log it ++info.last_update.version; pg_log_entry_t e(pg_log_entry_t::LOST_DELETE, oid, info.last_update, m->second.need, 0, osd_reqid_t(), mtime); pg_log.add(e); dout(10) << e << dendl; t->remove( coll, ghobject_t(oid, ghobject_t::NO_GEN, pg_whoami.shard)); pg_log.missing_add_event(e); ++m; missing_loc.recovered(oid); } break; default: assert(0); } if (obc) c->obcs.push_back(obc); } dout(30) << __func__ << ": log after:\n"; pg_log.get_log().print(*_dout); *_dout << dendl; info.stats.stats_invalid = true; if (missing.num_missing() == 0) { // advance last_complete since nothing else is missing! info.last_complete = info.last_update; } dirty_info = true; write_if_dirty(*t); t->register_on_complete(new ObjectStore::C_DeleteTransaction(t)); osd->store->queue_transaction(osr.get(), t, c, NULL, new C_OSD_OndiskWriteUnlockList(&c->obcs)); // Send out the PG log to all replicas // So that they know what is lost share_pg_log(); // queue ourselves so that we push the (now-lost) object_infos to replicas. osd->queue_for_recovery(this); } void ReplicatedPG::_finish_mark_all_unfound_lost(list& obcs) { lock(); dout(10) << "_finish_mark_all_unfound_lost " << dendl; if (!deleting) requeue_ops(waiting_for_all_missing); waiting_for_all_missing.clear(); obcs.clear(); unlock(); } void ReplicatedPG::_split_into(pg_t child_pgid, PG *child, unsigned split_bits) { assert(repop_queue.empty()); } /* * pg status change notification */ void ReplicatedPG::apply_and_flush_repops(bool requeue) { list rq; // apply all repops while (!repop_queue.empty()) { RepGather *repop = repop_queue.front(); repop_queue.pop_front(); dout(10) << " canceling repop tid " << repop->rep_tid << dendl; repop->rep_aborted = true; if (repop->on_applied) { delete repop->on_applied; repop->on_applied = NULL; } if (requeue) { if (repop->ctx->op) { dout(10) << " requeuing " << *repop->ctx->op->get_req() << dendl; rq.push_back(repop->ctx->op); repop->ctx->op = OpRequestRef(); } // also requeue any dups, interleaved into position map >::iterator p = waiting_for_ondisk.find(repop->v); if (p != waiting_for_ondisk.end()) { dout(10) << " also requeuing ondisk waiters " << p->second << dendl; rq.splice(rq.end(), p->second); waiting_for_ondisk.erase(p); } } remove_repop(repop); } if (requeue) { requeue_ops(rq); if (!waiting_for_ondisk.empty()) { for (map >::iterator i = waiting_for_ondisk.begin(); i != waiting_for_ondisk.end(); ++i) { for (list::iterator j = i->second.begin(); j != i->second.end(); ++j) { derr << __func__ << ": op " << *((*j)->get_req()) << " waiting on " << i->first << dendl; } } assert(waiting_for_ondisk.empty()); } } waiting_for_ondisk.clear(); waiting_for_ack.clear(); } void ReplicatedPG::on_flushed() { assert(flushes_in_progress > 0); flushes_in_progress--; if (flushes_in_progress == 0) { requeue_ops(waiting_for_active); } if (!is_active() || !is_primary()) { pair i; while (object_contexts.get_next(i.first, &i)) { derr << "on_flushed: object " << i.first << " obc still alive" << dendl; } assert(object_contexts.empty()); } pgbackend->on_flushed(); } void ReplicatedPG::on_removal(ObjectStore::Transaction *t) { dout(10) << "on_removal" << dendl; // adjust info to backfill info.last_backfill = hobject_t(); dirty_info = true; // clear log PGLogEntryHandler rollbacker; pg_log.clear_can_rollback_to(&rollbacker); rollbacker.apply(this, t); write_if_dirty(*t); on_shutdown(); } void ReplicatedPG::on_shutdown() { dout(10) << "on_shutdown" << dendl; // remove from queues osd->recovery_wq.dequeue(this); osd->scrub_wq.dequeue(this); osd->scrub_finalize_wq.dequeue(this); osd->snap_trim_wq.dequeue(this); osd->pg_stat_queue_dequeue(this); osd->dequeue_pg(this, 0); osd->peering_wq.dequeue(this); // handles queue races deleting = true; unreg_next_scrub(); cancel_copy_ops(false); cancel_flush_ops(false); apply_and_flush_repops(false); pgbackend->on_change(); context_registry_on_change(); osd->remote_reserver.cancel_reservation(info.pgid); osd->local_reserver.cancel_reservation(info.pgid); clear_primary_state(); cancel_recovery(); } void ReplicatedPG::on_activate() { // all clean? if (needs_recovery()) { dout(10) << "activate not all replicas are up-to-date, queueing recovery" << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), DoRecovery()))); } else if (needs_backfill()) { dout(10) << "activate queueing backfill" << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), RequestBackfill()))); } else { dout(10) << "activate all replicas clean, no recovery" << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), AllReplicasRecovered()))); } publish_stats_to_osd(); if (!backfill_targets.empty()) { last_backfill_started = earliest_backfill(); new_backfill = true; assert(!last_backfill_started.is_max()); dout(5) << "on activate: bft=" << backfill_targets << " from " << last_backfill_started << dendl; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { dout(5) << "target shard " << *i << " from " << peer_info[*i].last_backfill << dendl; } } hit_set_setup(); agent_setup(); } void ReplicatedPG::on_change(ObjectStore::Transaction *t) { dout(10) << "on_change" << dendl; if (hit_set && hit_set->insert_count() == 0) { dout(20) << " discarding empty hit_set" << dendl; hit_set_clear(); } // requeue everything in the reverse order they should be // reexamined. clear_scrub_reserved(); scrub_clear_state(); context_registry_on_change(); for (list >::iterator i = in_progress_async_reads.begin(); i != in_progress_async_reads.end(); in_progress_async_reads.erase(i++)) { close_op_ctx(i->second, -ECANCELED); requeue_op(i->first); } cancel_copy_ops(is_primary()); cancel_flush_ops(is_primary()); // requeue object waiters if (is_primary()) { requeue_object_waiters(waiting_for_unreadable_object); } else { waiting_for_unreadable_object.clear(); } for (map >::iterator p = waiting_for_degraded_object.begin(); p != waiting_for_degraded_object.end(); waiting_for_degraded_object.erase(p++)) { if (is_primary()) requeue_ops(p->second); else p->second.clear(); finish_degraded_object(p->first); } for (map >::iterator p = waiting_for_blocked_object.begin(); p != waiting_for_blocked_object.end(); waiting_for_blocked_object.erase(p++)) { if (is_primary()) requeue_ops(p->second); else p->second.clear(); } for (map >::iterator i = callbacks_for_degraded_object.begin(); i != callbacks_for_degraded_object.end(); ) { finish_degraded_object((i++)->first); } assert(callbacks_for_degraded_object.empty()); if (is_primary()) { requeue_ops(waiting_for_cache_not_full); requeue_ops(waiting_for_all_missing); } else { waiting_for_cache_not_full.clear(); waiting_for_all_missing.clear(); } // this will requeue ops we were working on but didn't finish, and // any dups apply_and_flush_repops(is_primary()); pgbackend->on_change_cleanup(t); pgbackend->on_change(); // clear snap_trimmer state snap_trimmer_machine.process_event(Reset()); debug_op_order.clear(); unstable_stats.clear(); } void ReplicatedPG::on_role_change() { dout(10) << "on_role_change" << dendl; if (get_role() != 0 && hit_set) { dout(10) << " clearing hit set" << dendl; hit_set_clear(); } } void ReplicatedPG::on_pool_change() { dout(10) << __func__ << dendl; // requeue cache full waiters just in case the cache_mode is // changing away from writeback mode. note that if we are not // active the normal requeuing machinery is sufficient (and properly // ordered). if (is_active() && pool.info.cache_mode != pg_pool_t::CACHEMODE_WRITEBACK && !waiting_for_cache_not_full.empty()) { dout(10) << __func__ << " requeuing full waiters (not in writeback) " << dendl; requeue_ops(waiting_for_cache_not_full); } hit_set_setup(); agent_setup(); } // clear state. called on recovery completion AND cancellation. void ReplicatedPG::_clear_recovery_state() { missing_loc.clear(); #ifdef DEBUG_RECOVERY_OIDS recovering_oids.clear(); #endif last_backfill_started = hobject_t(); list blocked_ops; set::iterator i = backfills_in_flight.begin(); while (i != backfills_in_flight.end()) { assert(recovering.count(*i)); recovering[*i]->drop_backfill_read(&blocked_ops); requeue_ops(blocked_ops); backfills_in_flight.erase(i++); } assert(backfills_in_flight.empty()); pending_backfill_updates.clear(); recovering.clear(); pgbackend->clear_state(); } void ReplicatedPG::cancel_pull(const hobject_t &soid) { dout(20) << __func__ << ": soid" << dendl; assert(recovering.count(soid)); recovering.erase(soid); finish_recovery_op(soid); if (waiting_for_degraded_object.count(soid)) { dout(20) << " kicking degraded waiters on " << soid << dendl; requeue_ops(waiting_for_degraded_object[soid]); waiting_for_degraded_object.erase(soid); } if (waiting_for_unreadable_object.count(soid)) { dout(20) << " kicking unreadable waiters on " << soid << dendl; requeue_ops(waiting_for_unreadable_object[soid]); waiting_for_unreadable_object.erase(soid); } if (is_missing_object(soid)) pg_log.set_last_requested(0); // get recover_primary to start over } void ReplicatedPG::check_recovery_sources(const OSDMapRef osdmap) { /* * check that any peers we are planning to (or currently) pulling * objects from are dealt with. */ missing_loc.check_recovery_sources(osdmap); pgbackend->check_recovery_sources(osdmap); for (set::iterator i = peer_log_requested.begin(); i != peer_log_requested.end(); ) { if (!osdmap->is_up(i->osd)) { dout(10) << "peer_log_requested removing " << *i << dendl; peer_log_requested.erase(i++); } else { ++i; } } for (set::iterator i = peer_missing_requested.begin(); i != peer_missing_requested.end(); ) { if (!osdmap->is_up(i->osd)) { dout(10) << "peer_missing_requested removing " << *i << dendl; peer_missing_requested.erase(i++); } else { ++i; } } } void PG::MissingLoc::check_recovery_sources(const OSDMapRef osdmap) { set now_down; for (set::iterator p = missing_loc_sources.begin(); p != missing_loc_sources.end(); ) { if (osdmap->is_up(p->osd)) { ++p; continue; } dout(10) << "check_recovery_sources source osd." << *p << " now down" << dendl; now_down.insert(*p); missing_loc_sources.erase(p++); } if (now_down.empty()) { dout(10) << "check_recovery_sources no source osds (" << missing_loc_sources << ") went down" << dendl; } else { dout(10) << "check_recovery_sources sources osds " << now_down << " now down, remaining sources are " << missing_loc_sources << dendl; // filter missing_loc map >::iterator p = missing_loc.begin(); while (p != missing_loc.end()) { set::iterator q = p->second.begin(); while (q != p->second.end()) if (now_down.count(*q)) { p->second.erase(q++); } else { ++q; } if (p->second.empty()) missing_loc.erase(p++); else ++p; } } } bool ReplicatedPG::start_recovery_ops( int max, RecoveryCtx *prctx, ThreadPool::TPHandle &handle, int *ops_started) { int& started = *ops_started; started = 0; bool work_in_progress = false; assert(is_primary()); if (!state_test(PG_STATE_RECOVERING) && !state_test(PG_STATE_BACKFILL)) { /* TODO: I think this case is broken and will make do_recovery() * unhappy since we're returning false */ dout(10) << "recovery raced and were queued twice, ignoring!" << dendl; return false; } const pg_missing_t &missing = pg_log.get_missing(); int num_missing = missing.num_missing(); int num_unfound = get_num_unfound(); if (num_missing == 0) { info.last_complete = info.last_update; } if (num_missing == num_unfound) { // All of the missing objects we have are unfound. // Recover the replicas. started = recover_replicas(max, handle); } if (!started) { // We still have missing objects that we should grab from replicas. started += recover_primary(max, handle); } if (!started && num_unfound != get_num_unfound()) { // second chance to recovery replicas started = recover_replicas(max, handle); } if (started) work_in_progress = true; bool deferred_backfill = false; if (recovering.empty() && state_test(PG_STATE_BACKFILL) && !backfill_targets.empty() && started < max && missing.num_missing() == 0 && waiting_on_backfill.empty()) { if (get_osdmap()->test_flag(CEPH_OSDMAP_NOBACKFILL)) { dout(10) << "deferring backfill due to NOBACKFILL" << dendl; deferred_backfill = true; } else if (!backfill_reserved) { dout(10) << "deferring backfill due to !backfill_reserved" << dendl; if (!backfill_reserving) { dout(10) << "queueing RequestBackfill" << dendl; backfill_reserving = true; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), RequestBackfill()))); } deferred_backfill = true; } else { started += recover_backfill(max - started, handle, &work_in_progress); } } dout(10) << " started " << started << dendl; osd->logger->inc(l_osd_rop, started); if (!recovering.empty() || work_in_progress || recovery_ops_active > 0 || deferred_backfill) return work_in_progress; assert(recovering.empty()); assert(recovery_ops_active == 0); dout(10) << __func__ << " needs_recovery: " << missing_loc.get_needs_recovery() << dendl; dout(10) << __func__ << " missing_loc: " << missing_loc.get_missing_locs() << dendl; int unfound = get_num_unfound(); if (unfound) { dout(10) << " still have " << unfound << " unfound" << dendl; return work_in_progress; } if (missing.num_missing() > 0) { // this shouldn't happen! osd->clog.error() << info.pgid << " recovery ending with " << missing.num_missing() << ": " << missing.missing << "\n"; return work_in_progress; } if (needs_recovery()) { // this shouldn't happen! // We already checked num_missing() so we must have missing replicas osd->clog.error() << info.pgid << " recovery ending with missing replicas\n"; return work_in_progress; } if (state_test(PG_STATE_RECOVERING)) { state_clear(PG_STATE_RECOVERING); if (needs_backfill()) { dout(10) << "recovery done, queuing backfill" << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), RequestBackfill()))); } else { dout(10) << "recovery done, no backfill" << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), AllReplicasRecovered()))); } } else { // backfilling state_clear(PG_STATE_BACKFILL); dout(10) << "recovery done, backfill done" << dendl; queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), Backfilled()))); } return false; } /** * do one recovery op. * return true if done, false if nothing left to do. */ int ReplicatedPG::recover_primary(int max, ThreadPool::TPHandle &handle) { assert(is_primary()); const pg_missing_t &missing = pg_log.get_missing(); dout(10) << "recover_primary recovering " << recovering.size() << " in pg" << dendl; dout(10) << "recover_primary " << missing << dendl; dout(25) << "recover_primary " << missing.missing << dendl; // look at log! pg_log_entry_t *latest = 0; int started = 0; int skipped = 0; PGBackend::RecoveryHandle *h = pgbackend->open_recovery_op(); map::const_iterator p = missing.rmissing.lower_bound(pg_log.get_log().last_requested); while (p != missing.rmissing.end()) { handle.reset_tp_timeout(); hobject_t soid; version_t v = p->first; if (pg_log.get_log().objects.count(p->second)) { latest = pg_log.get_log().objects.find(p->second)->second; assert(latest->is_update()); soid = latest->soid; } else { latest = 0; soid = p->second; } const pg_missing_t::item& item = missing.missing.find(p->second)->second; ++p; hobject_t head = soid; head.snap = CEPH_NOSNAP; eversion_t need = item.need; bool unfound = missing_loc.is_unfound(soid); dout(10) << "recover_primary " << soid << " " << item.need << (unfound ? " (unfound)":"") << (missing.is_missing(soid) ? " (missing)":"") << (missing.is_missing(head) ? " (missing head)":"") << (recovering.count(soid) ? " (recovering)":"") << (recovering.count(head) ? " (recovering head)":"") << dendl; if (latest) { switch (latest->op) { case pg_log_entry_t::CLONE: /* * Handling for this special case removed for now, until we * can correctly construct an accurate SnapSet from the old * one. */ break; case pg_log_entry_t::LOST_REVERT: { if (item.have == latest->reverting_to) { ObjectContextRef obc = get_object_context(soid, true); if (obc->obs.oi.version == latest->version) { // I'm already reverting dout(10) << " already reverting " << soid << dendl; } else { dout(10) << " reverting " << soid << " to " << latest->prior_version << dendl; obc->ondisk_write_lock(); obc->obs.oi.version = latest->version; ObjectStore::Transaction *t = new ObjectStore::Transaction; t->register_on_applied(new ObjectStore::C_DeleteTransaction(t)); bufferlist b2; obc->obs.oi.encode(b2); t->setattr(coll, soid, OI_ATTR, b2); recover_got(soid, latest->version); missing_loc.add_location(soid, pg_whoami); ++active_pushes; osd->store->queue_transaction(osr.get(), t, new C_OSD_AppliedRecoveredObject(this, obc), new C_OSD_CommittedPushedObject( this, get_osdmap()->get_epoch(), info.last_complete), new C_OSD_OndiskWriteUnlock(obc)); continue; } } else { /* * Pull the old version of the object. Update missing_loc here to have the location * of the version we want. * * This doesn't use the usual missing_loc paths, but that's okay: * - if we have it locally, we hit the case above, and go from there. * - if we don't, we always pass through this case during recovery and set up the location * properly. * - this way we don't need to mangle the missing code to be general about needing an old * version... */ eversion_t alternate_need = latest->reverting_to; dout(10) << " need to pull prior_version " << alternate_need << " for revert " << item << dendl; for (map::iterator p = peer_missing.begin(); p != peer_missing.end(); ++p) if (p->second.is_missing(soid, need) && p->second.missing[soid].have == alternate_need) { missing_loc.add_location(soid, p->first); } dout(10) << " will pull " << alternate_need << " or " << need << " from one of " << missing_loc.get_locations(soid) << dendl; unfound = false; } } break; } } if (!recovering.count(soid)) { if (recovering.count(head)) { ++skipped; } else if (unfound) { ++skipped; } else { int r = recover_missing( soid, need, cct->_conf->osd_recovery_op_priority, h); switch (r) { case PULL_YES: ++started; break; case PULL_OTHER: ++started; case PULL_NONE: ++skipped; break; default: assert(0); } if (started >= max) break; } } // only advance last_requested if we haven't skipped anything if (!skipped) pg_log.set_last_requested(v); } pgbackend->run_recovery_op(h, cct->_conf->osd_recovery_op_priority); return started; } int ReplicatedPG::prep_object_replica_pushes( const hobject_t& soid, eversion_t v, PGBackend::RecoveryHandle *h) { assert(is_primary()); dout(10) << __func__ << ": on " << soid << dendl; // NOTE: we know we will get a valid oloc off of disk here. ObjectContextRef obc = get_object_context(soid, false); if (!obc) { pg_log.missing_add(soid, v, eversion_t()); missing_loc.remove_location(soid, pg_whoami); bool uhoh = true; assert(actingbackfill.size() > 0); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_shard_t peer = *i; if (!peer_missing[peer].is_missing(soid, v)) { missing_loc.add_location(soid, peer); dout(10) << info.pgid << " unexpectedly missing " << soid << " v" << v << ", there should be a copy on shard " << peer << dendl; uhoh = false; } } if (uhoh) osd->clog.error() << info.pgid << " missing primary copy of " << soid << ", unfound\n"; else osd->clog.error() << info.pgid << " missing primary copy of " << soid << ", will try copies on " << missing_loc.get_locations(soid) << "\n"; return 0; } start_recovery_op(soid); assert(!recovering.count(soid)); recovering.insert(make_pair(soid, obc)); /* We need this in case there is an in progress write on the object. In fact, * the only possible write is an update to the xattr due to a lost_revert -- * a client write would be blocked since the object is degraded. * In almost all cases, therefore, this lock should be uncontended. */ obc->ondisk_read_lock(); pgbackend->recover_object( soid, v, ObjectContextRef(), obc, // has snapset context h); obc->ondisk_read_unlock(); return 1; } int ReplicatedBackend::start_pushes( const hobject_t &soid, ObjectContextRef obc, RPGHandle *h) { int pushes = 0; // who needs it? assert(get_parent()->get_actingbackfill_shards().size() > 0); for (set::iterator i = get_parent()->get_actingbackfill_shards().begin(); i != get_parent()->get_actingbackfill_shards().end(); ++i) { if (*i == get_parent()->whoami_shard()) continue; pg_shard_t peer = *i; map::const_iterator j = get_parent()->get_shard_missing().find(peer); assert(j != get_parent()->get_shard_missing().end()); if (j->second.is_missing(soid)) { ++pushes; h->pushes[peer].push_back(PushOp()); prep_push_to_replica(obc, soid, peer, &(h->pushes[peer].back()) ); } } return pushes; } int ReplicatedPG::recover_replicas(int max, ThreadPool::TPHandle &handle) { dout(10) << __func__ << "(" << max << ")" << dendl; int started = 0; PGBackend::RecoveryHandle *h = pgbackend->open_recovery_op(); // this is FAR from an optimal recovery order. pretty lame, really. assert(actingbackfill.size() > 0); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; pg_shard_t peer = *i; map::const_iterator pm = peer_missing.find(peer); assert(pm != peer_missing.end()); map::const_iterator pi = peer_info.find(peer); assert(pi != peer_info.end()); size_t m_sz = pm->second.num_missing(); dout(10) << " peer osd." << peer << " missing " << m_sz << " objects." << dendl; dout(20) << " peer osd." << peer << " missing " << pm->second.missing << dendl; // oldest first! const pg_missing_t &m(pm->second); for (map::const_iterator p = m.rmissing.begin(); p != m.rmissing.end() && started < max; ++p) { handle.reset_tp_timeout(); const hobject_t soid(p->second); if (soid > pi->second.last_backfill) { if (!recovering.count(soid)) { derr << __func__ << ": object added to missing set for backfill, but " << "is not in recovering, error!" << dendl; assert(0); } continue; } if (recovering.count(soid)) { dout(10) << __func__ << ": already recovering " << soid << dendl; continue; } if (missing_loc.is_unfound(soid)) { dout(10) << __func__ << ": " << soid << " still unfound" << dendl; continue; } if (soid.is_snap() && pg_log.get_missing().is_missing(soid.get_head())) { dout(10) << __func__ << ": " << soid.get_head() << " still missing on primary" << dendl; continue; } if (soid.is_snap() && pg_log.get_missing().is_missing(soid.get_snapdir())) { dout(10) << __func__ << ": " << soid.get_snapdir() << " still missing on primary" << dendl; continue; } if (pg_log.get_missing().is_missing(soid)) { dout(10) << __func__ << ": " << soid << " still missing on primary" << dendl; continue; } dout(10) << __func__ << ": recover_object_replicas(" << soid << ")" << dendl; map::const_iterator r = m.missing.find(soid); started += prep_object_replica_pushes(soid, r->second.need, h); } } pgbackend->run_recovery_op(h, cct->_conf->osd_recovery_op_priority); return started; } hobject_t ReplicatedPG::earliest_peer_backfill() const { hobject_t e = hobject_t::get_max(); for (set::const_iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t peer = *i; map::const_iterator iter = peer_backfill_info.find(peer); assert(iter != peer_backfill_info.end()); if (iter->second.begin < e) e = iter->second.begin; } return e; } bool ReplicatedPG::all_peer_done() const { // Primary hasn't got any more objects assert(backfill_info.empty()); for (set::const_iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; map::const_iterator piter = peer_backfill_info.find(bt); assert(piter != peer_backfill_info.end()); const BackfillInterval& pbi = piter->second; // See if peer has more to process if (!pbi.extends_to_end() || !pbi.empty()) return false; } return true; } /** * recover_backfill * * Invariants: * * backfilled: fully pushed to replica or present in replica's missing set (both * our copy and theirs). * * All objects on a backfill_target in * [MIN,peer_backfill_info[backfill_target].begin) are either * not present or backfilled (all removed objects have been removed). * There may be PG objects in this interval yet to be backfilled. * * All objects in PG in [MIN,backfill_info.begin) have been backfilled to all * backfill_targets. There may be objects on backfill_target(s) yet to be deleted. * * For a backfill target, all objects < MIN(peer_backfill_info[target].begin, * backfill_info.begin) in PG are backfilled. No deleted objects in this * interval remain on the backfill target. * * For a backfill target, all objects <= peer_info[target].last_backfill * have been backfilled to target * * There *MAY* be objects between last_backfill_started and * MIN(peer_backfill_info[*].begin, backfill_info.begin) in the event that client * io created objects since the last scan. For this reason, we call * update_range() again before continuing backfill. */ int ReplicatedPG::recover_backfill( int max, ThreadPool::TPHandle &handle, bool *work_started) { dout(10) << "recover_backfill (" << max << ")" << " bft=" << backfill_targets << " last_backfill_started " << last_backfill_started << dendl; assert(!backfill_targets.empty()); // Initialize from prior backfill state if (new_backfill) { // on_activate() was called prior to getting here assert(last_backfill_started == earliest_backfill()); new_backfill = false; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { peer_backfill_info[*i].reset(peer_info[*i].last_backfill); } backfill_info.reset(last_backfill_started); } for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { dout(10) << "peer osd." << *i << " info " << peer_info[*i] << " interval " << peer_backfill_info[*i].begin << "-" << peer_backfill_info[*i].end << " " << peer_backfill_info[*i].objects.size() << " objects" << dendl; } // update our local interval to cope with recent changes backfill_info.begin = last_backfill_started; update_range(&backfill_info, handle); int ops = 0; vector > > to_push; vector > to_remove; set add_to_stat; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { peer_backfill_info[*i].trim_to( MAX(peer_info[*i].last_backfill, last_backfill_started)); } backfill_info.trim_to(last_backfill_started); hobject_t backfill_pos = MIN(backfill_info.begin, earliest_peer_backfill()); while (ops < max) { if (backfill_info.begin <= earliest_peer_backfill() && !backfill_info.extends_to_end() && backfill_info.empty()) { hobject_t next = backfill_info.end; backfill_info.clear(); backfill_info.begin = next; backfill_info.end = hobject_t::get_max(); update_range(&backfill_info, handle); backfill_info.trim(); } backfill_pos = MIN(backfill_info.begin, earliest_peer_backfill()); dout(20) << " my backfill interval " << backfill_info.begin << "-" << backfill_info.end << " " << backfill_info.objects.size() << " objects" << " " << backfill_info.objects << dendl; bool sent_scan = false; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; BackfillInterval& pbi = peer_backfill_info[bt]; dout(20) << " peer shard " << bt << " backfill " << pbi.begin << "-" << pbi.end << " " << pbi.objects << dendl; if (pbi.begin <= backfill_info.begin && !pbi.extends_to_end() && pbi.empty()) { dout(10) << " scanning peer osd." << bt << " from " << pbi.end << dendl; epoch_t e = get_osdmap()->get_epoch(); MOSDPGScan *m = new MOSDPGScan( MOSDPGScan::OP_SCAN_GET_DIGEST, pg_whoami, e, e, spg_t(info.pgid.pgid, bt.shard), pbi.end, hobject_t()); osd->send_message_osd_cluster(bt.osd, m, get_osdmap()->get_epoch()); assert(waiting_on_backfill.find(bt) == waiting_on_backfill.end()); waiting_on_backfill.insert(bt); sent_scan = true; } } // Count simultaneous scans as a single op and let those complete if (sent_scan) { ops++; start_recovery_op(hobject_t::get_max()); // XXX: was pbi.end break; } if (backfill_info.empty() && all_peer_done()) { dout(10) << " reached end for both local and all peers" << dendl; break; } // Get object within set of peers to operate on and // the set of targets for which that object applies. hobject_t check = earliest_peer_backfill(); if (check < backfill_info.begin) { set check_targets; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; BackfillInterval& pbi = peer_backfill_info[bt]; if (pbi.begin == check) check_targets.insert(bt); } assert(!check_targets.empty()); dout(20) << " BACKFILL removing " << check << " from peers " << check_targets << dendl; for (set::iterator i = check_targets.begin(); i != check_targets.end(); ++i) { pg_shard_t bt = *i; BackfillInterval& pbi = peer_backfill_info[bt]; assert(pbi.begin == check); to_remove.push_back(boost::make_tuple(check, pbi.objects.begin()->second, bt)); pbi.pop_front(); } last_backfill_started = check; // Don't increment ops here because deletions // are cheap and not replied to unlike real recovery_ops, // and we can't increment ops without requeueing ourself // for recovery. } else { eversion_t& obj_v = backfill_info.objects.begin()->second; vector need_ver_targs, missing_targs, keep_ver_targs, skip_targs; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; BackfillInterval& pbi = peer_backfill_info[bt]; // Find all check peers that have the wrong version if (check == backfill_info.begin && check == pbi.begin) { if (pbi.objects.begin()->second != obj_v) { need_ver_targs.push_back(bt); } else { keep_ver_targs.push_back(bt); } } else { pg_info_t& pinfo = peer_info[bt]; // Only include peers that we've caught up to their backfill line // otherwise, they only appear to be missing this object // because their pbi.begin > backfill_info.begin. if (backfill_info.begin > pinfo.last_backfill) missing_targs.push_back(bt); else skip_targs.push_back(bt); } } if (!keep_ver_targs.empty()) { // These peers have version obj_v dout(20) << " BACKFILL keeping " << check << " with ver " << obj_v << " on peers " << keep_ver_targs << dendl; //assert(!waiting_for_degraded_object.count(check)); } if (!need_ver_targs.empty() || !missing_targs.empty()) { ObjectContextRef obc = get_object_context(backfill_info.begin, false); assert(obc); if (obc->get_backfill_read()) { if (!need_ver_targs.empty()) { dout(20) << " BACKFILL replacing " << check << " with ver " << obj_v << " to peers " << need_ver_targs << dendl; } if (!missing_targs.empty()) { dout(20) << " BACKFILL pushing " << backfill_info.begin << " with ver " << obj_v << " to peers " << missing_targs << dendl; } vector all_push = need_ver_targs; all_push.insert(all_push.end(), missing_targs.begin(), missing_targs.end()); to_push.push_back( boost::tuple > (backfill_info.begin, obj_v, obc, all_push)); // Count all simultaneous pushes of the same object as a single op ops++; } else { *work_started = true; dout(20) << "backfill blocking on " << backfill_info.begin << "; could not get rw_manager lock" << dendl; break; } } dout(20) << "need_ver_targs=" << need_ver_targs << " keep_ver_targs=" << keep_ver_targs << dendl; dout(20) << "backfill_targets=" << backfill_targets << " missing_targs=" << missing_targs << " skip_targs=" << skip_targs << dendl; last_backfill_started = backfill_info.begin; add_to_stat.insert(backfill_info.begin); // XXX: Only one for all pushes? backfill_info.pop_front(); vector check_targets = need_ver_targs; check_targets.insert(check_targets.end(), keep_ver_targs.begin(), keep_ver_targs.end()); for (vector::iterator i = check_targets.begin(); i != check_targets.end(); ++i) { pg_shard_t bt = *i; BackfillInterval& pbi = peer_backfill_info[bt]; pbi.pop_front(); } } } backfill_pos = MIN(backfill_info.begin, earliest_peer_backfill()); for (set::iterator i = add_to_stat.begin(); i != add_to_stat.end(); ++i) { ObjectContextRef obc = get_object_context(*i, false); pg_stat_t stat; add_object_context_to_pg_stat(obc, &stat); pending_backfill_updates[*i] = stat; } for (unsigned i = 0; i < to_remove.size(); ++i) { handle.reset_tp_timeout(); // ordered before any subsequent updates send_remove_op(to_remove[i].get<0>(), to_remove[i].get<1>(), to_remove[i].get<2>()); pending_backfill_updates[to_remove[i].get<0>()]; // add empty stat! } PGBackend::RecoveryHandle *h = pgbackend->open_recovery_op(); for (unsigned i = 0; i < to_push.size(); ++i) { handle.reset_tp_timeout(); prep_backfill_object_push(to_push[i].get<0>(), to_push[i].get<1>(), to_push[i].get<2>(), to_push[i].get<3>(), h); } pgbackend->run_recovery_op(h, cct->_conf->osd_recovery_op_priority); dout(5) << "backfill_pos is " << backfill_pos << dendl; for (set::iterator i = backfills_in_flight.begin(); i != backfills_in_flight.end(); ++i) { dout(20) << *i << " is still in flight" << dendl; } hobject_t next_backfill_to_complete = backfills_in_flight.size() ? *(backfills_in_flight.begin()) : backfill_pos; hobject_t new_last_backfill = earliest_backfill(); dout(10) << "starting new_last_backfill at " << new_last_backfill << dendl; for (map::iterator i = pending_backfill_updates.begin(); i != pending_backfill_updates.end() && i->first < next_backfill_to_complete; pending_backfill_updates.erase(i++)) { assert(i->first > new_last_backfill); for (set::iterator j = backfill_targets.begin(); j != backfill_targets.end(); ++j) { pg_shard_t bt = *j; pg_info_t& pinfo = peer_info[bt]; //Add stats to all peers that were missing object if (i->first > pinfo.last_backfill) pinfo.stats.add(i->second); } new_last_backfill = i->first; } dout(10) << "possible new_last_backfill at " << new_last_backfill << dendl; assert(!pending_backfill_updates.empty() || new_last_backfill == last_backfill_started); if (pending_backfill_updates.empty() && backfill_pos.is_max()) { assert(backfills_in_flight.empty()); new_last_backfill = backfill_pos; last_backfill_started = backfill_pos; } dout(10) << "final new_last_backfill at " << new_last_backfill << dendl; // If new_last_backfill == MAX, then we will send OP_BACKFILL_FINISH to // all the backfill targets. Otherwise, we will move last_backfill up on // those targets need it and send OP_BACKFILL_PROGRESS to them. for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { pg_shard_t bt = *i; pg_info_t& pinfo = peer_info[bt]; if (new_last_backfill > pinfo.last_backfill) { pinfo.last_backfill = new_last_backfill; epoch_t e = get_osdmap()->get_epoch(); MOSDPGBackfill *m = NULL; if (pinfo.last_backfill.is_max()) { m = new MOSDPGBackfill( MOSDPGBackfill::OP_BACKFILL_FINISH, e, e, spg_t(info.pgid.pgid, bt.shard)); // Use default priority here, must match sub_op priority /* pinfo.stats might be wrong if we did log-based recovery on the * backfilled portion in addition to continuing backfill. */ pinfo.stats = info.stats; start_recovery_op(hobject_t::get_max()); } else { m = new MOSDPGBackfill( MOSDPGBackfill::OP_BACKFILL_PROGRESS, e, e, spg_t(info.pgid.pgid, bt.shard)); // Use default priority here, must match sub_op priority } m->last_backfill = pinfo.last_backfill; m->stats = pinfo.stats; osd->send_message_osd_cluster(bt.osd, m, get_osdmap()->get_epoch()); dout(10) << " peer " << bt << " num_objects now " << pinfo.stats.stats.sum.num_objects << " / " << info.stats.stats.sum.num_objects << dendl; } } if (ops) *work_started = true; return ops; } void ReplicatedPG::prep_backfill_object_push( hobject_t oid, eversion_t v, ObjectContextRef obc, vector peers, PGBackend::RecoveryHandle *h) { dout(10) << "push_backfill_object " << oid << " v " << v << " to peers " << peers << dendl; assert(!peers.empty()); backfills_in_flight.insert(oid); for (unsigned int i = 0 ; i < peers.size(); ++i) { map::iterator bpm = peer_missing.find(peers[i]); assert(bpm != peer_missing.end()); bpm->second.add(oid, eversion_t(), eversion_t()); } assert(!recovering.count(oid)); start_recovery_op(oid); recovering.insert(make_pair(oid, obc)); // We need to take the read_lock here in order to flush in-progress writes obc->ondisk_read_lock(); pgbackend->recover_object( oid, v, ObjectContextRef(), obc, h); obc->ondisk_read_unlock(); } void ReplicatedPG::update_range( BackfillInterval *bi, ThreadPool::TPHandle &handle) { int local_min = cct->_conf->osd_backfill_scan_min; int local_max = cct->_conf->osd_backfill_scan_max; if (bi->version < info.log_tail) { dout(10) << __func__<< ": bi is old, rescanning local backfill_info" << dendl; if (last_update_applied >= info.log_tail) { bi->version = last_update_applied; } else { osr->flush(); bi->version = info.last_update; } scan_range(local_min, local_max, bi, handle); } if (bi->version >= info.last_update) { dout(10) << __func__<< ": bi is current " << dendl; assert(bi->version == info.last_update); } else if (bi->version >= info.log_tail) { if (pg_log.get_log().empty()) { /* Because we don't move log_tail on split, the log might be * empty even if log_tail != last_update. However, the only * way to get here with an empty log is if log_tail is actually * eversion_t(), because otherwise the entry which changed * last_update since the last scan would have to be present. */ assert(bi->version == eversion_t()); return; } assert(!pg_log.get_log().empty()); dout(10) << __func__<< ": bi is old, (" << bi->version << ") can be updated with log" << dendl; list::const_iterator i = pg_log.get_log().log.end(); --i; while (i != pg_log.get_log().log.begin() && i->version > bi->version) { --i; } if (i->version == bi->version) ++i; assert(i != pg_log.get_log().log.end()); dout(10) << __func__ << ": updating from version " << i->version << dendl; for (; i != pg_log.get_log().log.end(); ++i) { const hobject_t &soid = i->soid; if (soid >= bi->begin && soid < bi->end) { if (i->is_update()) { dout(10) << __func__ << ": " << i->soid << " updated to version " << i->version << dendl; bi->objects.erase(i->soid); bi->objects.insert( make_pair( i->soid, i->version)); } else if (i->is_delete()) { dout(10) << __func__ << ": " << i->soid << " removed" << dendl; bi->objects.erase(i->soid); } } } bi->version = info.last_update; } else { assert(0 == "scan_range should have raised bi->version past log_tail"); } } void ReplicatedPG::scan_range( int min, int max, BackfillInterval *bi, ThreadPool::TPHandle &handle) { assert(is_locked()); dout(10) << "scan_range from " << bi->begin << dendl; bi->objects.clear(); // for good measure vector ls; ls.reserve(max); int r = pgbackend->objects_list_partial(bi->begin, min, max, 0, &ls, &bi->end); assert(r >= 0); dout(10) << " got " << ls.size() << " items, next " << bi->end << dendl; dout(20) << ls << dendl; for (vector::iterator p = ls.begin(); p != ls.end(); ++p) { handle.reset_tp_timeout(); ObjectContextRef obc; if (is_primary()) obc = object_contexts.lookup(*p); if (obc) { bi->objects[*p] = obc->obs.oi.version; dout(20) << " " << *p << " " << obc->obs.oi.version << dendl; } else { bufferlist bl; int r = pgbackend->objects_get_attr(*p, OI_ATTR, &bl); /* If the object does not exist here, it must have been removed * between the collection_list_partial and here. This can happen * for the first item in the range, which is usually last_backfill. */ if (r == -ENOENT) continue; assert(r >= 0); object_info_t oi(bl); bi->objects[*p] = oi.version; dout(20) << " " << *p << " " << oi.version << dendl; } } } /** check_local * * verifies that stray objects have been deleted */ void ReplicatedPG::check_local() { dout(10) << __func__ << dendl; assert(info.last_update >= pg_log.get_tail()); // otherwise we need some help! if (!cct->_conf->osd_debug_verify_stray_on_activate) return; // just scan the log. set did; for (list::const_reverse_iterator p = pg_log.get_log().log.rbegin(); p != pg_log.get_log().log.rend(); ++p) { if (did.count(p->soid)) continue; did.insert(p->soid); if (p->is_delete()) { dout(10) << " checking " << p->soid << " at " << p->version << dendl; struct stat st; int r = osd->store->stat( coll, ghobject_t(p->soid, ghobject_t::NO_GEN, pg_whoami.shard), &st); if (r != -ENOENT) { derr << __func__ << " " << p->soid << " exists, but should have been " << "deleted" << dendl; assert(0 == "erroneously present object"); } } else { // ignore old(+missing) objects } } } // =========================== // hit sets hobject_t ReplicatedPG::get_hit_set_current_object(utime_t stamp) { ostringstream ss; ss << "hit_set_" << info.pgid.pgid << "_current_" << stamp; hobject_t hoid(sobject_t(ss.str(), CEPH_NOSNAP), "", info.pgid.ps(), info.pgid.pool(), cct->_conf->osd_hit_set_namespace); dout(20) << __func__ << " " << hoid << dendl; return hoid; } hobject_t ReplicatedPG::get_hit_set_archive_object(utime_t start, utime_t end) { ostringstream ss; ss << "hit_set_" << info.pgid.pgid << "_archive_" << start << "_" << end; hobject_t hoid(sobject_t(ss.str(), CEPH_NOSNAP), "", info.pgid.ps(), info.pgid.pool(), cct->_conf->osd_hit_set_namespace); dout(20) << __func__ << " " << hoid << dendl; return hoid; } void ReplicatedPG::hit_set_clear() { dout(20) << __func__ << dendl; hit_set.reset(); hit_set_start_stamp = utime_t(); hit_set_flushing.clear(); } void ReplicatedPG::hit_set_setup() { if (!is_active() || !is_primary() || !pool.info.hit_set_count || !pool.info.hit_set_period || pool.info.hit_set_params.get_type() == HitSet::TYPE_NONE) { hit_set_clear(); //hit_set_remove_all(); // FIXME: implement me soon return; } // FIXME: discard any previous data for now hit_set_create(); // include any writes we know about from the pg log. this doesn't // capture reads, but it is better than nothing! hit_set_apply_log(); } void ReplicatedPG::hit_set_create() { utime_t now = ceph_clock_now(NULL); // make a copy of the params to modify HitSet::Params params(pool.info.hit_set_params); dout(20) << __func__ << " " << params << dendl; if (pool.info.hit_set_params.get_type() == HitSet::TYPE_BLOOM) { BloomHitSet::Params *p = static_cast(params.impl.get()); // convert false positive rate so it holds up across the full period p->set_fpp(p->get_fpp() / pool.info.hit_set_count); if (p->get_fpp() <= 0.0) p->set_fpp(.01); // fpp cannot be zero! // if we don't have specified size, estimate target size based on the // previous bin! if (p->target_size == 0 && hit_set) { utime_t dur = now - hit_set_start_stamp; unsigned unique = hit_set->approx_unique_insert_count(); dout(20) << __func__ << " previous set had approx " << unique << " unique items over " << dur << " seconds" << dendl; p->target_size = (double)unique * (double)pool.info.hit_set_period / (double)dur; } if (p->target_size < static_cast(g_conf->osd_hit_set_min_size)) p->target_size = g_conf->osd_hit_set_min_size; if (p->target_size > static_cast(g_conf->osd_hit_set_max_size)) p->target_size = g_conf->osd_hit_set_max_size; p->seed = now.sec(); dout(10) << __func__ << " target_size " << p->target_size << " fpp " << p->get_fpp() << dendl; } hit_set.reset(new HitSet(params)); hit_set_start_stamp = now; } /** * apply log entries to set * * this would only happen after peering, to at least capture writes * during an interval that was potentially lost. */ bool ReplicatedPG::hit_set_apply_log() { if (!hit_set) return false; eversion_t to = info.last_update; eversion_t from = info.hit_set.current_last_update; if (to <= from) { dout(20) << __func__ << " no update" << dendl; return false; } dout(20) << __func__ << " " << to << " .. " << info.last_update << dendl; list::const_reverse_iterator p = pg_log.get_log().log.rbegin(); while (p != pg_log.get_log().log.rend() && p->version > to) ++p; while (p != pg_log.get_log().log.rend() && p->version > from) { hit_set->insert(p->soid); ++p; } return true; } struct C_HitSetFlushing : public Context { ReplicatedPGRef pg; time_t hit_set_name; C_HitSetFlushing(ReplicatedPG *p, time_t n) : pg(p), hit_set_name(n) { } void finish(int r) { pg->hit_set_flushing.erase(hit_set_name); } }; void ReplicatedPG::hit_set_persist() { dout(10) << __func__ << dendl; bufferlist bl; unsigned max = pool.info.hit_set_count; utime_t now = ceph_clock_now(cct); RepGather *repop; hobject_t oid; time_t flush_time = 0; // See what start is going to be used later utime_t start = info.hit_set.current_info.begin; if (!start) start = hit_set_start_stamp; // If any archives are degraded we skip this persist request // account for the additional entry being added below for (list::iterator p = info.hit_set.history.begin(); p != info.hit_set.history.end(); ++p) { hobject_t aoid = get_hit_set_archive_object(p->begin, p->end); // Once we hit a degraded object just skip further trim if (is_degraded_object(aoid)) return; } oid = get_hit_set_archive_object(start, now); // If the current object is degraded we skip this persist request if (is_degraded_object(oid)) return; // If backfill is in progress and we could possibly overlap with the // hit_set_* objects, back off. Since these all have // hobject_t::hash set to pgid.ps(), and those sort first, we can // look just at that. This is necessary because our transactions // may include a modify of the new hit_set *and* a delete of the // old one, and this may span the backfill boundary. for (set::iterator p = backfill_targets.begin(); p != backfill_targets.end(); ++p) { assert(peer_info.count(*p)); const pg_info_t& pi = peer_info[*p]; if (pi.last_backfill == hobject_t() || pi.last_backfill.hash == info.pgid.ps()) { dout(10) << __func__ << " backfill target osd." << *p << " last_backfill has not progressed past pgid ps" << dendl; return; } } if (!info.hit_set.current_info.begin) info.hit_set.current_info.begin = hit_set_start_stamp; hit_set->seal(); ::encode(*hit_set, bl); info.hit_set.current_info.end = now; dout(20) << __func__ << " archive " << oid << dendl; if (agent_state) { agent_state->add_hit_set(info.hit_set.current_info.begin, hit_set); hit_set_in_memory_trim(); } // hold a ref until it is flushed to disk hit_set_flushing[info.hit_set.current_info.begin] = hit_set; flush_time = info.hit_set.current_info.begin; ObjectContextRef obc = get_object_context(oid, true); repop = simple_repop_create(obc); if (flush_time != 0) repop->on_applied = new C_HitSetFlushing(this, flush_time); OpContext *ctx = repop->ctx; ctx->at_version = get_next_version(); ctx->updated_hset_history = info.hit_set; pg_hit_set_history_t &updated_hit_set_hist = *(ctx->updated_hset_history); if (updated_hit_set_hist.current_last_stamp != utime_t()) { // FIXME: we cheat slightly here by bundling in a remove on a object // other the RepGather object. we aren't carrying an ObjectContext for // the deleted object over this period. hobject_t old_obj = get_hit_set_current_object(updated_hit_set_hist.current_last_stamp); ctx->log.push_back( pg_log_entry_t(pg_log_entry_t::DELETE, old_obj, ctx->at_version, updated_hit_set_hist.current_last_update, 0, osd_reqid_t(), ctx->mtime)); if (pool.info.require_rollback()) { if (ctx->log.back().mod_desc.rmobject(ctx->at_version.version)) { ctx->op_t->stash(old_obj, ctx->at_version.version); } else { ctx->op_t->remove(old_obj); } } else { ctx->op_t->remove(old_obj); ctx->log.back().mod_desc.mark_unrollbackable(); } ++ctx->at_version.version; struct stat st; int r = osd->store->stat( coll, ghobject_t(old_obj, ghobject_t::NO_GEN, pg_whoami.shard), &st); assert(r == 0); --ctx->delta_stats.num_objects; ctx->delta_stats.num_bytes -= st.st_size; } updated_hit_set_hist.current_last_update = info.last_update; // *after* above remove! updated_hit_set_hist.current_info.version = ctx->at_version; updated_hit_set_hist.history.push_back(updated_hit_set_hist.current_info); hit_set_create(); updated_hit_set_hist.current_info = pg_hit_set_info_t(); updated_hit_set_hist.current_last_stamp = utime_t(); // fabricate an object_info_t and SnapSet obc->obs.oi.version = ctx->at_version; obc->obs.oi.mtime = now; obc->obs.oi.size = bl.length(); obc->obs.exists = true; ctx->new_obs = obc->obs; ctx->new_snapset.head_exists = true; ctx->delta_stats.num_objects++; ctx->delta_stats.num_objects_hit_set_archive++; ctx->delta_stats.num_bytes += bl.length(); bufferlist bss; ::encode(ctx->new_snapset, bss); bufferlist boi(sizeof(ctx->new_obs.oi)); ::encode(ctx->new_obs.oi, boi); ctx->op_t->append(oid, 0, bl.length(), bl); setattr_maybe_cache(ctx->obc, ctx, ctx->op_t, OI_ATTR, boi); setattr_maybe_cache(ctx->obc, ctx, ctx->op_t, SS_ATTR, bss); ctx->log.push_back( pg_log_entry_t( pg_log_entry_t::MODIFY, oid, ctx->at_version, eversion_t(), 0, osd_reqid_t(), ctx->mtime) ); if (pool.info.require_rollback()) { ctx->log.back().mod_desc.create(); } else { ctx->log.back().mod_desc.mark_unrollbackable(); } hit_set_trim(repop, max); info.stats.stats.add(ctx->delta_stats, string()); simple_repop_submit(repop); } void ReplicatedPG::hit_set_trim(RepGather *repop, unsigned max) { assert(repop->ctx->updated_hset_history); pg_hit_set_history_t &updated_hit_set_hist = *(repop->ctx->updated_hset_history); for (unsigned num = updated_hit_set_hist.history.size(); num > max; --num) { list::iterator p = updated_hit_set_hist.history.begin(); assert(p != updated_hit_set_hist.history.end()); hobject_t oid = get_hit_set_archive_object(p->begin, p->end); assert(!is_degraded_object(oid)); dout(20) << __func__ << " removing " << oid << dendl; ++repop->ctx->at_version.version; repop->ctx->log.push_back( pg_log_entry_t(pg_log_entry_t::DELETE, oid, repop->ctx->at_version, p->version, 0, osd_reqid_t(), repop->ctx->mtime)); if (pool.info.require_rollback()) { if (repop->ctx->log.back().mod_desc.rmobject( repop->ctx->at_version.version)) { repop->ctx->op_t->stash(oid, repop->ctx->at_version.version); } else { repop->ctx->op_t->remove(oid); } } else { repop->ctx->op_t->remove(oid); repop->ctx->log.back().mod_desc.mark_unrollbackable(); } updated_hit_set_hist.history.pop_front(); ObjectContextRef obc = get_object_context(oid, false); assert(obc); --repop->ctx->delta_stats.num_objects; --repop->ctx->delta_stats.num_objects_hit_set_archive; repop->ctx->delta_stats.num_bytes -= obc->obs.oi.size; } } void ReplicatedPG::hit_set_in_memory_trim() { unsigned max = pool.info.hit_set_count; unsigned max_in_memory = pool.info.min_read_recency_for_promote > 0 ? pool.info.min_read_recency_for_promote - 1 : 0; if (max_in_memory > max) { max_in_memory = max; } while (agent_state->hit_set_map.size() > max_in_memory) { agent_state->remove_oldest_hit_set(); } } // ======================================= // cache agent void ReplicatedPG::agent_setup() { assert(is_locked()); if (!is_active() || !is_primary() || pool.info.cache_mode == pg_pool_t::CACHEMODE_NONE || pool.info.tier_of < 0 || !get_osdmap()->have_pg_pool(pool.info.tier_of)) { agent_clear(); return; } if (!agent_state) { agent_state.reset(new TierAgentState); // choose random starting position agent_state->position = hobject_t(); agent_state->position.pool = info.pgid.pool(); agent_state->position.hash = pool.info.get_random_pg_position( info.pgid.pgid, rand()); agent_state->start = agent_state->position; dout(10) << __func__ << " allocated new state, position " << agent_state->position << dendl; } else { dout(10) << __func__ << " keeping existing state" << dendl; } if (info.stats.stats_invalid) { osd->clog.warn() << "pg " << info.pgid << " has invalid (post-split) stats; must scrub before tier agent can activate"; } agent_choose_mode(); } void ReplicatedPG::agent_clear() { agent_stop(); agent_state.reset(NULL); } // Return false if no objects operated on since start of object hash space bool ReplicatedPG::agent_work(int start_max) { lock(); if (!agent_state) { dout(10) << __func__ << " no agent state, stopping" << dendl; unlock(); return true; } assert(!deleting); if (agent_state->is_idle()) { dout(10) << __func__ << " idle, stopping" << dendl; unlock(); return true; } osd->logger->inc(l_osd_agent_wake); dout(10) << __func__ << " max " << start_max << ", flush " << agent_state->get_flush_mode_name() << ", evict " << agent_state->get_evict_mode_name() << ", pos " << agent_state->position << dendl; assert(is_primary()); assert(is_active()); agent_load_hit_sets(); const pg_pool_t *base_pool = get_osdmap()->get_pg_pool(pool.info.tier_of); assert(base_pool); int ls_min = 1; int ls_max = 10; // FIXME? // list some objects. this conveniently lists clones (oldest to // newest) before heads... the same order we want to flush in. // // NOTE: do not flush the Sequencer. we will assume that the // listing we get back is imprecise. vector ls; hobject_t next; int r = pgbackend->objects_list_partial(agent_state->position, ls_min, ls_max, 0 /* no filtering by snapid */, &ls, &next); assert(r >= 0); dout(20) << __func__ << " got " << ls.size() << " objects" << dendl; int started = 0; for (vector::iterator p = ls.begin(); p != ls.end(); ++p) { if (p->nspace == cct->_conf->osd_hit_set_namespace) { dout(20) << __func__ << " skip (hit set) " << *p << dendl; osd->logger->inc(l_osd_agent_skip); continue; } if (is_degraded_object(*p)) { dout(20) << __func__ << " skip (degraded) " << *p << dendl; osd->logger->inc(l_osd_agent_skip); continue; } if (is_missing_object(p->get_head())) { dout(20) << __func__ << " skip (missing head) " << *p << dendl; osd->logger->inc(l_osd_agent_skip); continue; } ObjectContextRef obc = get_object_context(*p, false, NULL); if (!obc) { // we didn't flush; we may miss something here. dout(20) << __func__ << " skip (no obc) " << *p << dendl; osd->logger->inc(l_osd_agent_skip); continue; } if (!obc->obs.exists) { dout(20) << __func__ << " skip (dne) " << obc->obs.oi.soid << dendl; osd->logger->inc(l_osd_agent_skip); continue; } if (scrubber.write_blocked_by_scrub(obc->obs.oi.soid)) { dout(20) << __func__ << " skip (scrubbing) " << obc->obs.oi << dendl; osd->logger->inc(l_osd_agent_skip); continue; } if (obc->is_blocked()) { dout(20) << __func__ << " skip (blocked) " << obc->obs.oi << dendl; osd->logger->inc(l_osd_agent_skip); continue; } // be careful flushing omap to an EC pool. if (base_pool->is_erasure() && obc->obs.oi.test_flag(object_info_t::FLAG_OMAP)) { dout(20) << __func__ << " skip (omap to EC) " << obc->obs.oi << dendl; osd->logger->inc(l_osd_agent_skip); continue; } if (agent_state->flush_mode != TierAgentState::FLUSH_MODE_IDLE && agent_maybe_flush(obc)) ++started; if (agent_state->evict_mode != TierAgentState::EVICT_MODE_IDLE && agent_maybe_evict(obc)) ++started; if (started >= start_max) { // If finishing early, set "next" to the next object if (++p != ls.end()) next = *p; break; } } if (++agent_state->hist_age > g_conf->osd_agent_hist_halflife) { dout(20) << __func__ << " resetting atime and temp histograms" << dendl; agent_state->hist_age = 0; agent_state->atime_hist.decay(); agent_state->temp_hist.decay(); } // Total objects operated on so far int total_started = agent_state->started + started; bool need_delay = false; dout(20) << __func__ << " start pos " << agent_state->position << " next start pos " << next << " started " << total_started << dendl; // See if we've made a full pass over the object hash space // This might check at most ls_max objects a second time to notice that // we've checked every objects at least once. if (agent_state->position < agent_state->start && next >= agent_state->start) { dout(20) << __func__ << " wrap around " << agent_state->start << dendl; if (total_started == 0) need_delay = true; else total_started = 0; agent_state->start = next; } agent_state->started = total_started; // See if we are starting from beginning if (next.is_max()) agent_state->position = hobject_t(); else agent_state->position = next; // Discard old in memory HitSets hit_set_in_memory_trim(); if (need_delay) { assert(agent_state->delaying == false); agent_delay(); unlock(); return false; } agent_choose_mode(); unlock(); return true; } void ReplicatedPG::agent_load_hit_sets() { if (agent_state->evict_mode == TierAgentState::EVICT_MODE_IDLE) { return; } if (agent_state->hit_set_map.size() < info.hit_set.history.size()) { dout(10) << __func__ << dendl; for (list::iterator p = info.hit_set.history.begin(); p != info.hit_set.history.end(); ++p) { if (agent_state->hit_set_map.count(p->begin.sec()) == 0) { dout(10) << __func__ << " loading " << p->begin << "-" << p->end << dendl; if (!pool.info.is_replicated()) { // FIXME: EC not supported here yet derr << __func__ << " on non-replicated pool" << dendl; break; } // check if it's still in flight if (hit_set_flushing.count(p->begin)) { agent_state->add_hit_set(p->begin.sec(), hit_set_flushing[p->begin]); continue; } hobject_t oid = get_hit_set_archive_object(p->begin, p->end); if (is_unreadable_object(oid)) { dout(10) << __func__ << " unreadable " << oid << ", waiting" << dendl; break; } ObjectContextRef obc = get_object_context(oid, false); if (!obc) { derr << __func__ << ": could not load hitset " << oid << dendl; break; } bufferlist bl; { obc->ondisk_read_lock(); int r = osd->store->read(coll, oid, 0, 0, bl); assert(r >= 0); obc->ondisk_read_unlock(); } HitSetRef hs(new HitSet); bufferlist::iterator pbl = bl.begin(); ::decode(*hs, pbl); agent_state->add_hit_set(p->begin.sec(), hs); } } } } struct C_AgentFlushStartStop : public Context { ReplicatedPGRef pg; hobject_t oid; C_AgentFlushStartStop(ReplicatedPG *p, hobject_t o) : pg(p), oid(o) { pg->osd->agent_start_op(oid); } void finish(int r) { pg->osd->agent_finish_op(oid); } }; bool ReplicatedPG::agent_maybe_flush(ObjectContextRef& obc) { if (!obc->obs.oi.is_dirty()) { dout(20) << __func__ << " skip (clean) " << obc->obs.oi << dendl; osd->logger->inc(l_osd_agent_skip); return false; } utime_t now = ceph_clock_now(NULL); utime_t ob_local_mtime; if (obc->obs.oi.local_mtime != utime_t()) { ob_local_mtime = obc->obs.oi.local_mtime; } else { ob_local_mtime = obc->obs.oi.mtime; } bool evict_mode_full = (agent_state->evict_mode == TierAgentState::EVICT_MODE_FULL); if (!evict_mode_full && (ob_local_mtime + utime_t(pool.info.cache_min_flush_age, 0) > now)) { dout(20) << __func__ << " skip (too young) " << obc->obs.oi << dendl; osd->logger->inc(l_osd_agent_skip); return false; } if (osd->agent_is_active_oid(obc->obs.oi.soid)) { dout(20) << __func__ << " skip (flushing) " << obc->obs.oi << dendl; osd->logger->inc(l_osd_agent_skip); return false; } dout(10) << __func__ << " flushing " << obc->obs.oi << dendl; // FIXME: flush anything dirty, regardless of what distribution of // ages we expect. Context *on_flush = new C_AgentFlushStartStop(this, obc->obs.oi.soid); int result = start_flush( OpRequestRef(), obc, false, NULL, on_flush); if (result != -EINPROGRESS) { on_flush->complete(result); dout(10) << __func__ << " start_flush() failed " << obc->obs.oi << " with " << result << dendl; osd->logger->inc(l_osd_agent_skip); return false; } osd->logger->inc(l_osd_agent_flush); return true; } bool ReplicatedPG::agent_maybe_evict(ObjectContextRef& obc) { const hobject_t& soid = obc->obs.oi.soid; if (obc->obs.oi.is_dirty()) { dout(20) << __func__ << " skip (dirty) " << obc->obs.oi << dendl; return false; } if (!obc->obs.oi.watchers.empty()) { dout(20) << __func__ << " skip (watchers) " << obc->obs.oi << dendl; return false; } if (soid.snap == CEPH_NOSNAP) { int result = _verify_no_head_clones(soid, obc->ssc->snapset); if (result < 0) { dout(20) << __func__ << " skip (clones) " << obc->obs.oi << dendl; return false; } } if (agent_state->evict_mode != TierAgentState::EVICT_MODE_FULL && hit_set) { // is this object old and/or cold enough? int atime = -1, temp = 0; agent_estimate_atime_temp(soid, &atime, NULL /*FIXME &temp*/); uint64_t atime_upper = 0, atime_lower = 0; if (atime < 0 && obc->obs.oi.mtime != utime_t()) atime = ceph_clock_now(NULL).sec() - obc->obs.oi.mtime; if (atime < 0) atime = pool.info.hit_set_period * pool.info.hit_set_count; // "infinite" if (atime >= 0) { agent_state->atime_hist.add(atime); agent_state->atime_hist.get_position_micro(atime, &atime_lower, &atime_upper); } unsigned temp_upper = 0, temp_lower = 0; /* // FIXME: bound atime based on creation time? agent_state->temp_hist.add(atime); agent_state->temp_hist.get_position_micro(temp, &temp_lower, &temp_upper); */ dout(20) << __func__ << " atime " << atime << " pos " << atime_lower << "-" << atime_upper << ", temp " << temp << " pos " << temp_lower << "-" << temp_upper << ", evict_effort " << agent_state->evict_effort << dendl; dout(30) << "agent_state:\n"; Formatter *f = new_formatter(""); f->open_object_section("agent_state"); agent_state->dump(f); f->close_section(); f->flush(*_dout); delete f; *_dout << dendl; // FIXME: ignore temperature for now. if (1000000 - atime_upper >= agent_state->evict_effort) return false; } dout(10) << __func__ << " evicting " << obc->obs.oi << dendl; RepGather *repop = simple_repop_create(obc); OpContext *ctx = repop->ctx; ctx->at_version = get_next_version(); assert(ctx->new_obs.exists); int r = _delete_oid(ctx, true); if (obc->obs.oi.is_omap()) ctx->delta_stats.num_objects_omap--; assert(r == 0); finish_ctx(ctx, pg_log_entry_t::DELETE, false); simple_repop_submit(repop); osd->logger->inc(l_osd_tier_evict); osd->logger->inc(l_osd_agent_evict); return true; } void ReplicatedPG::agent_stop() { dout(20) << __func__ << dendl; if (agent_state && !agent_state->is_idle()) { agent_state->evict_mode = TierAgentState::EVICT_MODE_IDLE; agent_state->flush_mode = TierAgentState::FLUSH_MODE_IDLE; osd->agent_disable_pg(this, agent_state->evict_effort); } } void ReplicatedPG::agent_delay() { dout(20) << __func__ << dendl; if (agent_state && !agent_state->is_idle()) { assert(agent_state->delaying == false); agent_state->delaying = true; osd->agent_disable_pg(this, agent_state->evict_effort); } } void ReplicatedPG::agent_choose_mode_restart() { dout(20) << __func__ << dendl; lock(); if (agent_state && agent_state->delaying) { agent_state->delaying = false; agent_choose_mode(true); } unlock(); } void ReplicatedPG::agent_choose_mode(bool restart) { // Let delay play out if (agent_state->delaying) { dout(20) << __func__ << this << " delaying, ignored" << dendl; return; } uint64_t divisor = pool.info.get_pg_num_divisor(info.pgid.pgid); assert(divisor > 0); uint64_t num_user_objects = info.stats.stats.sum.num_objects; // adjust (effective) user objects down based on the number // of HitSet objects, which should not count toward our total since // they cannot be flushed. uint64_t unflushable = info.stats.stats.sum.num_objects_hit_set_archive; // also exclude omap objects if ec backing pool const pg_pool_t *base_pool = get_osdmap()->get_pg_pool(pool.info.tier_of); assert(base_pool); if (base_pool->is_erasure()) unflushable += info.stats.stats.sum.num_objects_omap; if (num_user_objects > unflushable) num_user_objects -= unflushable; else num_user_objects = 0; // also reduce the num_dirty by num_objects_omap int64_t num_dirty = info.stats.stats.sum.num_objects_dirty; if (base_pool->is_erasure()) { if (num_dirty > info.stats.stats.sum.num_objects_omap) num_dirty -= info.stats.stats.sum.num_objects_omap; else num_dirty = 0; } dout(10) << __func__ << " flush_mode: " << TierAgentState::get_flush_mode_name(agent_state->flush_mode) << " evict_mode: " << TierAgentState::get_evict_mode_name(agent_state->evict_mode) << " num_objects: " << info.stats.stats.sum.num_objects << " num_bytes: " << info.stats.stats.sum.num_bytes << " num_objects_dirty: " << info.stats.stats.sum.num_objects_dirty << " num_objects_omap: " << info.stats.stats.sum.num_objects_omap << " num_dirty: " << num_dirty << " num_user_objects: " << num_user_objects << " pool.info.target_max_bytes: " << pool.info.target_max_bytes << " pool.info.target_max_objects: " << pool.info.target_max_objects << dendl; // get dirty, full ratios uint64_t dirty_micro = 0; uint64_t full_micro = 0; if (pool.info.target_max_bytes && info.stats.stats.sum.num_objects > 0) { uint64_t avg_size = info.stats.stats.sum.num_bytes / info.stats.stats.sum.num_objects; dirty_micro = num_dirty * avg_size * 1000000 / MAX(pool.info.target_max_bytes / divisor, 1); full_micro = num_user_objects * avg_size * 1000000 / MAX(pool.info.target_max_bytes / divisor, 1); } if (pool.info.target_max_objects > 0) { uint64_t dirty_objects_micro = num_dirty * 1000000 / MAX(pool.info.target_max_objects / divisor, 1); if (dirty_objects_micro > dirty_micro) dirty_micro = dirty_objects_micro; uint64_t full_objects_micro = num_user_objects * 1000000 / MAX(pool.info.target_max_objects / divisor, 1); if (full_objects_micro > full_micro) full_micro = full_objects_micro; } dout(20) << __func__ << " dirty " << ((float)dirty_micro / 1000000.0) << " full " << ((float)full_micro / 1000000.0) << dendl; // flush mode TierAgentState::flush_mode_t flush_mode = TierAgentState::FLUSH_MODE_IDLE; uint64_t flush_target = pool.info.cache_target_dirty_ratio_micro; uint64_t flush_slop = (float)flush_target * g_conf->osd_agent_slop; if (restart || agent_state->flush_mode == TierAgentState::FLUSH_MODE_IDLE) flush_target += flush_slop; else flush_target -= MIN(flush_target, flush_slop); if (info.stats.stats_invalid) { // idle; stats can't be trusted until we scrub. dout(20) << __func__ << " stats invalid (post-split), idle" << dendl; } else if (dirty_micro > flush_target) { flush_mode = TierAgentState::FLUSH_MODE_ACTIVE; } // evict mode TierAgentState::evict_mode_t evict_mode = TierAgentState::EVICT_MODE_IDLE; unsigned evict_effort = 0; uint64_t evict_target = pool.info.cache_target_full_ratio_micro; uint64_t evict_slop = (float)evict_target * g_conf->osd_agent_slop; if (restart || agent_state->evict_mode == TierAgentState::EVICT_MODE_IDLE) evict_target += evict_slop; else evict_target -= MIN(evict_target, evict_slop); if (info.stats.stats_invalid) { // idle; stats can't be trusted until we scrub. } else if (full_micro > 1000000) { // evict anything clean evict_mode = TierAgentState::EVICT_MODE_FULL; evict_effort = 1000000; } else if (full_micro > evict_target) { // set effort in [0..1] range based on where we are between evict_mode = TierAgentState::EVICT_MODE_SOME; uint64_t over = full_micro - evict_target; uint64_t span; if (evict_target >= 1000000) span = 1; else span = 1000000 - evict_target; evict_effort = MAX(over * 1000000 / span, (unsigned)(1000000.0 * g_conf->osd_agent_min_evict_effort)); // quantize effort to avoid too much reordering in the agent_queue. uint64_t inc = g_conf->osd_agent_quantize_effort * 1000000; assert(inc > 0); uint64_t was = evict_effort; evict_effort -= evict_effort % inc; if (evict_effort < inc) evict_effort = inc; assert(evict_effort >= inc && evict_effort <= 1000000); dout(30) << __func__ << " evict_effort " << was << " quantized by " << inc << " to " << evict_effort << dendl; } bool old_idle = agent_state->is_idle(); if (flush_mode != agent_state->flush_mode) { dout(5) << __func__ << " flush_mode " << TierAgentState::get_flush_mode_name(agent_state->flush_mode) << " -> " << TierAgentState::get_flush_mode_name(flush_mode) << dendl; agent_state->flush_mode = flush_mode; } if (evict_mode != agent_state->evict_mode) { dout(5) << __func__ << " evict_mode " << TierAgentState::get_evict_mode_name(agent_state->evict_mode) << " -> " << TierAgentState::get_evict_mode_name(evict_mode) << dendl; if (agent_state->evict_mode == TierAgentState::EVICT_MODE_FULL && is_active()) { requeue_ops(waiting_for_cache_not_full); requeue_ops(waiting_for_active); } agent_state->evict_mode = evict_mode; } uint64_t old_effort = agent_state->evict_effort; if (evict_effort != agent_state->evict_effort) { dout(5) << __func__ << " evict_effort " << ((float)agent_state->evict_effort / 1000000.0) << " -> " << ((float)evict_effort / 1000000.0) << dendl; agent_state->evict_effort = evict_effort; } // NOTE: we are using evict_effort as a proxy for *all* agent effort // (including flush). This is probably fine (they should be // correlated) but it is not precisely correct. if (agent_state->is_idle()) { if (!restart && !old_idle) { osd->agent_disable_pg(this, old_effort); } } else { if (restart || old_idle) { osd->agent_enable_pg(this, agent_state->evict_effort); } else if (old_effort != agent_state->evict_effort) { osd->agent_adjust_pg(this, old_effort, agent_state->evict_effort); } } } void ReplicatedPG::agent_estimate_atime_temp(const hobject_t& oid, int *atime, int *temp) { assert(hit_set); *atime = -1; if (temp) *temp = 0; if (hit_set->contains(oid)) { *atime = 0; if (temp) ++(*temp); else return; } time_t now = ceph_clock_now(NULL).sec(); for (map::reverse_iterator p = agent_state->hit_set_map.rbegin(); p != agent_state->hit_set_map.rend(); ++p) { if (p->second->contains(oid)) { if (*atime < 0) *atime = now - p->first; if (temp) ++(*temp); else return; } } } // ========================================================================================== // SCRUB bool ReplicatedPG::_range_available_for_scrub( const hobject_t &begin, const hobject_t &end) { pair next; next.second = object_contexts.lookup(begin); next.first = begin; bool more = true; while (more && next.first < end) { if (next.second && next.second->is_blocked()) { next.second->requeue_scrub_on_unblock = true; dout(10) << __func__ << ": scrub delayed, " << next.first << " is blocked" << dendl; return false; } more = object_contexts.get_next(next.first, &next); } return true; } void ReplicatedPG::_scrub(ScrubMap& scrubmap) { dout(10) << "_scrub" << dendl; coll_t c(info.pgid); bool repair = state_test(PG_STATE_REPAIR); bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); const char *mode = (repair ? "repair": (deep_scrub ? "deep-scrub" : "scrub")); // traverse in reverse order. hobject_t head; SnapSet snapset; vector::reverse_iterator curclone; hobject_t next_clone; bufferlist last_data; for (map::reverse_iterator p = scrubmap.objects.rbegin(); p != scrubmap.objects.rend(); ++p) { const hobject_t& soid = p->first; object_stat_sum_t stat; if (soid.snap != CEPH_SNAPDIR) stat.num_objects++; if (soid.nspace == cct->_conf->osd_hit_set_namespace) stat.num_objects_hit_set_archive++; // new snapset? if (soid.snap == CEPH_SNAPDIR || soid.snap == CEPH_NOSNAP) { if (p->second.attrs.count(SS_ATTR) == 0) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " no '" << SS_ATTR << "' attr"; ++scrubber.shallow_errors; continue; } bufferlist bl; bl.push_back(p->second.attrs[SS_ATTR]); bufferlist::iterator blp = bl.begin(); ::decode(snapset, blp); // did we finish the last oid? if (head != hobject_t() && !pool.info.allow_incomplete_clones()) { osd->clog.error() << mode << " " << info.pgid << " " << head << " missing clones"; ++scrubber.shallow_errors; } // what will be next? if (snapset.clones.empty()) head = hobject_t(); // no clones. else { curclone = snapset.clones.rbegin(); head = p->first; next_clone = hobject_t(); dout(20) << " snapset " << snapset << dendl; } } // basic checks. if (p->second.attrs.count(OI_ATTR) == 0) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " no '" << OI_ATTR << "' attr"; ++scrubber.shallow_errors; continue; } bufferlist bv; bv.push_back(p->second.attrs[OI_ATTR]); object_info_t oi(bv); if (pgbackend->be_get_ondisk_size(oi.size) != p->second.size) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " on disk size (" << p->second.size << ") does not match object info size (" << oi.size << ") ajusted for ondisk to (" << pgbackend->be_get_ondisk_size(oi.size) << ")"; ++scrubber.shallow_errors; } dout(20) << mode << " " << soid << " " << oi << dendl; if (soid.is_snap()) { stat.num_bytes += snapset.get_clone_bytes(soid.snap); } else { stat.num_bytes += oi.size; } if (!soid.is_snapdir()) { if (oi.is_dirty()) ++stat.num_objects_dirty; if (oi.is_whiteout()) ++stat.num_whiteouts; if (oi.is_omap()) ++stat.num_objects_omap; } //bufferlist data; //osd->store->read(c, poid, 0, 0, data); //assert(data.length() == p->size); // if (!next_clone.is_min() && next_clone != soid && pool.info.allow_incomplete_clones()) { // it is okay to be missing one or more clones in a cache tier. // skip higher-numbered clones in the list. while (curclone != snapset.clones.rend() && soid.snap < *curclone) ++curclone; if (curclone != snapset.clones.rend() && soid.snap == *curclone) { dout(20) << __func__ << " skipped some clones in cache tier" << dendl; next_clone.snap = *curclone; } if (curclone == snapset.clones.rend() || soid.snap == CEPH_NOSNAP) { dout(20) << __func__ << " skipped remaining clones in cache tier" << dendl; next_clone = hobject_t(); head = hobject_t(); } } if (!next_clone.is_min() && next_clone != soid) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " expected clone " << next_clone; ++scrubber.shallow_errors; } if (soid.snap == CEPH_NOSNAP || soid.snap == CEPH_SNAPDIR) { if (soid.snap == CEPH_NOSNAP && !snapset.head_exists) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " snapset.head_exists=false, but head exists"; ++scrubber.shallow_errors; } if (soid.snap == CEPH_SNAPDIR && snapset.head_exists) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " snapset.head_exists=true, but snapdir exists"; ++scrubber.shallow_errors; } if (curclone == snapset.clones.rend()) { next_clone = hobject_t(); } else { next_clone = soid; next_clone.snap = *curclone; } } else if (soid.snap) { // it's a clone stat.num_object_clones++; if (head == hobject_t()) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " found clone without head"; ++scrubber.shallow_errors; continue; } if (soid.snap != *curclone) { continue; // we warn above. we could do better here... } if (oi.size != snapset.clone_size[*curclone]) { osd->clog.error() << mode << " " << info.pgid << " " << soid << " size " << oi.size << " != clone_size " << snapset.clone_size[*curclone]; ++scrubber.shallow_errors; } // verify overlap? // ... // what's next? if (curclone != snapset.clones.rend()) { ++curclone; } if (curclone == snapset.clones.rend()) { head = hobject_t(); next_clone = hobject_t(); } else { next_clone.snap = *curclone; } } else { // it's unversioned. next_clone = hobject_t(); } string cat; // fixme scrub_cstat.add(stat, cat); } if (!next_clone.is_min() && !pool.info.allow_incomplete_clones()) { osd->clog.error() << mode << " " << info.pgid << " expected clone " << next_clone; ++scrubber.shallow_errors; } dout(10) << "_scrub (" << mode << ") finish" << dendl; } void ReplicatedPG::_scrub_clear_state() { scrub_cstat = object_stat_collection_t(); } void ReplicatedPG::_scrub_finish() { bool repair = state_test(PG_STATE_REPAIR); bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); const char *mode = (repair ? "repair": (deep_scrub ? "deep-scrub" : "scrub")); if (info.stats.stats_invalid) { info.stats.stats = scrub_cstat; info.stats.stats_invalid = false; if (agent_state) agent_choose_mode(); } dout(10) << mode << " got " << scrub_cstat.sum.num_objects << "/" << info.stats.stats.sum.num_objects << " objects, " << scrub_cstat.sum.num_object_clones << "/" << info.stats.stats.sum.num_object_clones << " clones, " << scrub_cstat.sum.num_objects_dirty << "/" << info.stats.stats.sum.num_objects_dirty << " dirty, " << scrub_cstat.sum.num_objects_omap << "/" << info.stats.stats.sum.num_objects_omap << " omap, " << scrub_cstat.sum.num_objects_hit_set_archive << "/" << info.stats.stats.sum.num_objects_hit_set_archive << " hit_set_archive, " << scrub_cstat.sum.num_bytes << "/" << info.stats.stats.sum.num_bytes << " bytes." << dendl; if (scrub_cstat.sum.num_objects != info.stats.stats.sum.num_objects || scrub_cstat.sum.num_object_clones != info.stats.stats.sum.num_object_clones || (scrub_cstat.sum.num_objects_dirty != info.stats.stats.sum.num_objects_dirty && !info.stats.dirty_stats_invalid) || (scrub_cstat.sum.num_objects_omap != info.stats.stats.sum.num_objects_omap && !info.stats.omap_stats_invalid) || (scrub_cstat.sum.num_objects_hit_set_archive != info.stats.stats.sum.num_objects_hit_set_archive && !info.stats.hitset_stats_invalid) || scrub_cstat.sum.num_whiteouts != info.stats.stats.sum.num_whiteouts || scrub_cstat.sum.num_bytes != info.stats.stats.sum.num_bytes) { osd->clog.error() << info.pgid << " " << mode << " stat mismatch, got " << scrub_cstat.sum.num_objects << "/" << info.stats.stats.sum.num_objects << " objects, " << scrub_cstat.sum.num_object_clones << "/" << info.stats.stats.sum.num_object_clones << " clones, " << scrub_cstat.sum.num_objects_dirty << "/" << info.stats.stats.sum.num_objects_dirty << " dirty, " << scrub_cstat.sum.num_objects_omap << "/" << info.stats.stats.sum.num_objects_omap << " omap, " << scrub_cstat.sum.num_objects_hit_set_archive << "/" << info.stats.stats.sum.num_objects_hit_set_archive << " hit_set_archive, " << scrub_cstat.sum.num_whiteouts << "/" << info.stats.stats.sum.num_whiteouts << " whiteouts, " << scrub_cstat.sum.num_bytes << "/" << info.stats.stats.sum.num_bytes << " bytes.\n"; ++scrubber.shallow_errors; if (repair) { ++scrubber.fixed; info.stats.stats = scrub_cstat; info.stats.dirty_stats_invalid = false; info.stats.omap_stats_invalid = false; info.stats.hitset_stats_invalid = false; publish_stats_to_osd(); share_pg_info(); } } } /*---SnapTrimmer Logging---*/ #undef dout_prefix #define dout_prefix *_dout << pg->gen_prefix() ReplicatedPG::SnapTrimmer::~SnapTrimmer() { while (!repops.empty()) { (*repops.begin())->put(); repops.erase(repops.begin()); } } void ReplicatedPG::SnapTrimmer::log_enter(const char *state_name) { dout(20) << "enter " << state_name << dendl; } void ReplicatedPG::SnapTrimmer::log_exit(const char *state_name, utime_t enter_time) { dout(20) << "exit " << state_name << dendl; } /*---SnapTrimmer states---*/ #undef dout_prefix #define dout_prefix (*_dout << context< SnapTrimmer >().pg->gen_prefix() \ << "SnapTrimmer state<" << get_state_name() << ">: ") /* NotTrimming */ ReplicatedPG::NotTrimming::NotTrimming(my_context ctx) : my_base(ctx), NamedState(context< SnapTrimmer >().pg->cct, "NotTrimming") { context< SnapTrimmer >().log_enter(state_name); } void ReplicatedPG::NotTrimming::exit() { context< SnapTrimmer >().log_exit(state_name, enter_time); } boost::statechart::result ReplicatedPG::NotTrimming::react(const SnapTrim&) { ReplicatedPG *pg = context< SnapTrimmer >().pg; dout(10) << "NotTrimming react" << dendl; if (!pg->is_primary() || !pg->is_active() || !pg->is_clean()) { dout(10) << "NotTrimming not primary, active, clean" << dendl; return discard_event(); } else if (pg->scrubber.active) { dout(10) << "NotTrimming finalizing scrub" << dendl; pg->queue_snap_trim(); return discard_event(); } // Primary trimming if (pg->snap_trimq.empty()) { return discard_event(); } else { context().snap_to_trim = pg->snap_trimq.range_start(); dout(10) << "NotTrimming: trimming " << pg->snap_trimq.range_start() << dendl; post_event(SnapTrim()); return transit(); } } /* TrimmingObjects */ ReplicatedPG::TrimmingObjects::TrimmingObjects(my_context ctx) : my_base(ctx), NamedState(context< SnapTrimmer >().pg->cct, "Trimming/TrimmingObjects") { context< SnapTrimmer >().log_enter(state_name); } void ReplicatedPG::TrimmingObjects::exit() { context< SnapTrimmer >().log_exit(state_name, enter_time); // Clean up repops in case of reset set &repops = context().repops; for (set::iterator i = repops.begin(); i != repops.end(); repops.erase(i++)) { (*i)->put(); } } boost::statechart::result ReplicatedPG::TrimmingObjects::react(const SnapTrim&) { dout(10) << "TrimmingObjects react" << dendl; ReplicatedPG *pg = context< SnapTrimmer >().pg; snapid_t snap_to_trim = context().snap_to_trim; set &repops = context().repops; dout(10) << "TrimmingObjects: trimming snap " << snap_to_trim << dendl; for (set::iterator i = repops.begin(); i != repops.end(); ) { if ((*i)->all_applied && (*i)->all_committed) { (*i)->put(); repops.erase(i++); } else { ++i; } } while (repops.size() < g_conf->osd_pg_max_concurrent_snap_trims) { // Get next hobject_t old_pos = pos; int r = pg->snap_mapper.get_next_object_to_trim(snap_to_trim, &pos); if (r != 0 && r != -ENOENT) { derr << __func__ << ": get_next returned " << cpp_strerror(r) << dendl; assert(0); } else if (r == -ENOENT) { // Done! dout(10) << "TrimmingObjects: got ENOENT" << dendl; post_event(SnapTrim()); return transit< WaitingOnReplicas >(); } dout(10) << "TrimmingObjects react trimming " << pos << dendl; RepGather *repop = pg->trim_object(pos); if (!repop) { dout(10) << __func__ << " could not get write lock on obj " << pos << dendl; pos = old_pos; return discard_event(); } assert(repop); repop->queue_snap_trimmer = true; repops.insert(repop->get()); pg->simple_repop_submit(repop); } return discard_event(); } /* WaitingOnReplicasObjects */ ReplicatedPG::WaitingOnReplicas::WaitingOnReplicas(my_context ctx) : my_base(ctx), NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitingOnReplicas") { context< SnapTrimmer >().log_enter(state_name); } void ReplicatedPG::WaitingOnReplicas::exit() { context< SnapTrimmer >().log_exit(state_name, enter_time); // Clean up repops in case of reset set &repops = context().repops; for (set::iterator i = repops.begin(); i != repops.end(); repops.erase(i++)) { (*i)->put(); } } boost::statechart::result ReplicatedPG::WaitingOnReplicas::react(const SnapTrim&) { // Have all the repops applied? dout(10) << "Waiting on Replicas react" << dendl; ReplicatedPG *pg = context< SnapTrimmer >().pg; set &repops = context().repops; for (set::iterator i = repops.begin(); i != repops.end(); repops.erase(i++)) { if (!(*i)->all_applied || !(*i)->all_committed) { return discard_event(); } else { (*i)->put(); } } snapid_t &sn = context().snap_to_trim; dout(10) << "WaitingOnReplicas: adding snap " << sn << " to purged_snaps" << dendl; pg->info.purged_snaps.insert(sn); pg->snap_trimq.erase(sn); dout(10) << "purged_snaps now " << pg->info.purged_snaps << ", snap_trimq now " << pg->snap_trimq << dendl; ObjectStore::Transaction *t = new ObjectStore::Transaction; pg->dirty_big_info = true; pg->write_if_dirty(*t); int tr = pg->osd->store->queue_transaction_and_cleanup(pg->osr.get(), t); assert(tr == 0); context().need_share_pg_info = true; // Back to the start pg->queue_snap_trim(); return transit< NotTrimming >(); } void ReplicatedPG::replace_cached_attrs( OpContext *ctx, ObjectContextRef obc, const map &new_attrs) { ctx->pending_attrs[obc].clear(); for (map::iterator i = obc->attr_cache.begin(); i != obc->attr_cache.end(); ++i) { ctx->pending_attrs[obc][i->first] = boost::optional(); } for (map::const_iterator i = new_attrs.begin(); i != new_attrs.end(); ++i) { ctx->pending_attrs[obc][i->first] = i->second; } } void ReplicatedPG::setattr_maybe_cache( ObjectContextRef obc, OpContext *op, PGBackend::PGTransaction *t, const string &key, bufferlist &val) { if (pool.info.require_rollback()) { op->pending_attrs[obc][key] = val; } t->setattr(obc->obs.oi.soid, key, val); } void ReplicatedPG::rmattr_maybe_cache( ObjectContextRef obc, OpContext *op, PGBackend::PGTransaction *t, const string &key) { if (pool.info.require_rollback()) { op->pending_attrs[obc][key] = boost::optional(); } t->rmattr(obc->obs.oi.soid, key); } int ReplicatedPG::getattr_maybe_cache( ObjectContextRef obc, const string &key, bufferlist *val) { if (pool.info.require_rollback()) { map::iterator i = obc->attr_cache.find(key); if (i != obc->attr_cache.end()) { if (val) *val = i->second; return 0; } else { return -ENODATA; } } return pgbackend->objects_get_attr(obc->obs.oi.soid, key, val); } int ReplicatedPG::getattrs_maybe_cache( ObjectContextRef obc, map *out, bool user_only) { int r = 0; if (pool.info.require_rollback()) { if (out) *out = obc->attr_cache; } else { r = pgbackend->objects_get_attrs(obc->obs.oi.soid, out); } if (out && user_only) { map tmp; for (map::iterator i = out->begin(); i != out->end(); ++i) { if (i->first.size() > 1 && i->first[0] == '_') tmp[i->first.substr(1, i->first.size())].claim(i->second); } tmp.swap(*out); } return r; } void intrusive_ptr_add_ref(ReplicatedPG *pg) { pg->get("intptr"); } void intrusive_ptr_release(ReplicatedPG *pg) { pg->put("intptr"); } #ifdef PG_DEBUG_REFS uint64_t get_with_id(ReplicatedPG *pg) { return pg->get_with_id(); } void put_with_id(ReplicatedPG *pg, uint64_t id) { return pg->put_with_id(id); } #endif void intrusive_ptr_add_ref(ReplicatedPG::RepGather *repop) { repop->get(); } void intrusive_ptr_release(ReplicatedPG::RepGather *repop) { repop->put(); } ceph-0.80.11/src/osd/TierAgentState.h0000664000175100017510000000634512623076744021315 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OSD_TIERAGENT_H #define CEPH_OSD_TIERAGENT_H struct TierAgentState { /// current position iterating across pool hobject_t position; /// Count of agent_work since "start" position of object hash space int started; hobject_t start; bool delaying; /// histogram of ages we've encountered pow2_hist_t atime_hist; pow2_hist_t temp_hist; int hist_age; /// past HitSet(s) (not current) map hit_set_map; /// a few recent things we've seen that are clean list recent_clean; enum flush_mode_t { FLUSH_MODE_IDLE, // nothing to flush FLUSH_MODE_ACTIVE, // flush what we can to bring down dirty count } flush_mode; ///< current flush behavior static const char *get_flush_mode_name(flush_mode_t m) { switch (m) { case FLUSH_MODE_IDLE: return "idle"; case FLUSH_MODE_ACTIVE: return "active"; default: assert(0 == "bad flush mode"); } } const char *get_flush_mode_name() const { return get_flush_mode_name(flush_mode); } enum evict_mode_t { EVICT_MODE_IDLE, // no need to evict anything EVICT_MODE_SOME, // evict some things as we are near the target EVICT_MODE_FULL, // evict anything } evict_mode; ///< current evict behavior static const char *get_evict_mode_name(evict_mode_t m) { switch (m) { case EVICT_MODE_IDLE: return "idle"; case EVICT_MODE_SOME: return "some"; case EVICT_MODE_FULL: return "full"; default: assert(0 == "bad evict mode"); } } const char *get_evict_mode_name() const { return get_evict_mode_name(evict_mode); } /// approximate ratio of objects (assuming they are uniformly /// distributed) that i should aim to evict. unsigned evict_effort; TierAgentState() : started(0), delaying(false), hist_age(0), flush_mode(FLUSH_MODE_IDLE), evict_mode(EVICT_MODE_IDLE), evict_effort(0) {} /// false if we have any work to do bool is_idle() const { return delaying || (flush_mode == FLUSH_MODE_IDLE && evict_mode == EVICT_MODE_IDLE); } /// add archived HitSet void add_hit_set(time_t start, HitSetRef hs) { hit_set_map.insert(make_pair(start, hs)); } /// remove old/trimmed HitSet void remove_oldest_hit_set() { if (!hit_set_map.empty()) hit_set_map.erase(hit_set_map.begin()); } /// discard all open hit sets void discard_hit_sets() { hit_set_map.clear(); } void dump(Formatter *f) const { f->dump_string("flush_mode", get_flush_mode_name()); f->dump_string("evict_mode", get_evict_mode_name()); f->dump_unsigned("evict_effort", evict_effort); f->dump_stream("position") << position; f->open_object_section("atime_hist"); atime_hist.dump(f); f->close_section(); f->open_object_section("temp_hist"); temp_hist.dump(f); f->close_section(); } }; #endif ceph-0.80.11/src/osd/OSD.cc0000664000175100017510000071755712623076744017233 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "acconfig.h" #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #include "osd/PG.h" #include "include/types.h" #include "include/compat.h" #include "OSD.h" #include "OSDMap.h" #include "Watch.h" #include "osdc/Objecter.h" #include "common/ceph_argparse.h" #include "common/version.h" #include "common/io_priority.h" #include "os/ObjectStore.h" #include "ReplicatedPG.h" #include "Ager.h" #include "msg/Messenger.h" #include "msg/Message.h" #include "mon/MonClient.h" #include "messages/MLog.h" #include "messages/MGenericMessage.h" #include "messages/MPing.h" #include "messages/MOSDPing.h" #include "messages/MOSDFailure.h" #include "messages/MOSDMarkMeDown.h" #include "messages/MOSDOp.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDSubOp.h" #include "messages/MOSDSubOpReply.h" #include "messages/MOSDBoot.h" #include "messages/MOSDPGTemp.h" #include "messages/MOSDMap.h" #include "messages/MOSDPGNotify.h" #include "messages/MOSDPGQuery.h" #include "messages/MOSDPGLog.h" #include "messages/MOSDPGRemove.h" #include "messages/MOSDPGInfo.h" #include "messages/MOSDPGCreate.h" #include "messages/MOSDPGTrim.h" #include "messages/MOSDPGScan.h" #include "messages/MOSDPGBackfill.h" #include "messages/MOSDPGMissing.h" #include "messages/MBackfillReserve.h" #include "messages/MRecoveryReserve.h" #include "messages/MOSDECSubOpWrite.h" #include "messages/MOSDECSubOpWriteReply.h" #include "messages/MOSDECSubOpRead.h" #include "messages/MOSDECSubOpReadReply.h" #include "messages/MOSDAlive.h" #include "messages/MOSDScrub.h" #include "messages/MOSDRepScrub.h" #include "messages/MMonCommand.h" #include "messages/MCommand.h" #include "messages/MCommandReply.h" #include "messages/MPGStats.h" #include "messages/MPGStatsAck.h" #include "messages/MWatchNotify.h" #include "messages/MOSDPGPush.h" #include "messages/MOSDPGPushReply.h" #include "messages/MOSDPGPull.h" #include "common/perf_counters.h" #include "common/Timer.h" #include "common/LogClient.h" #include "common/HeartbeatMap.h" #include "common/admin_socket.h" #include "global/signal_handler.h" #include "global/pidfile.h" #include "include/color.h" #include "perfglue/cpu_profiler.h" #include "perfglue/heap_profiler.h" #include "osd/ClassHandler.h" #include "osd/OpRequest.h" #include "auth/AuthAuthorizeHandler.h" #include "common/errno.h" #include "objclass/objclass.h" #include "common/cmdparse.h" #include "include/str_list.h" #include "include/assert.h" #include "common/config.h" #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout, whoami, get_osdmap()) static ostream& _prefix(std::ostream* _dout, int whoami, OSDMapRef osdmap) { return *_dout << "osd." << whoami << " " << (osdmap ? osdmap->get_epoch():0) << " "; } //Initial features in new superblock. //Features here are also automatically upgraded CompatSet OSD::get_osd_initial_compat_set() { CompatSet::FeatureSet ceph_osd_feature_compat; CompatSet::FeatureSet ceph_osd_feature_ro_compat; CompatSet::FeatureSet ceph_osd_feature_incompat; ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BASE); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_PGINFO); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_OLOC); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEC); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_CATEGORIES); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_HOBJECTPOOL); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BIGINFO); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEVELDBINFO); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEVELDBLOG); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SNAPMAPPER); return CompatSet(ceph_osd_feature_compat, ceph_osd_feature_ro_compat, ceph_osd_feature_incompat); } //Features are added here that this OSD supports. CompatSet OSD::get_osd_compat_set() { CompatSet compat = get_osd_initial_compat_set(); //Any features here can be set in code, but not in initial superblock compat.incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); return compat; } OSDService::OSDService(OSD *osd) : osd(osd), cct(osd->cct), whoami(osd->whoami), store(osd->store), clog(osd->clog), pg_recovery_stats(osd->pg_recovery_stats), infos_oid(OSD::make_infos_oid()), cluster_messenger(osd->cluster_messenger), client_messenger(osd->client_messenger), logger(osd->logger), recoverystate_perf(osd->recoverystate_perf), monc(osd->monc), op_wq(osd->op_wq), peering_wq(osd->peering_wq), recovery_wq(osd->recovery_wq), snap_trim_wq(osd->snap_trim_wq), scrub_wq(osd->scrub_wq), scrub_finalize_wq(osd->scrub_finalize_wq), rep_scrub_wq(osd->rep_scrub_wq), push_wq("push_wq", cct->_conf->osd_recovery_thread_timeout, &osd->recovery_tp), gen_wq("gen_wq", cct->_conf->osd_recovery_thread_timeout, &osd->recovery_tp), class_handler(osd->class_handler), pg_epoch_lock("OSDService::pg_epoch_lock"), publish_lock("OSDService::publish_lock"), pre_publish_lock("OSDService::pre_publish_lock"), sched_scrub_lock("OSDService::sched_scrub_lock"), scrubs_pending(0), scrubs_active(0), agent_lock("OSD::agent_lock"), agent_valid_iterator(false), agent_ops(0), agent_active(true), agent_thread(this), agent_stop_flag(false), agent_timer_lock("OSD::agent_timer_lock"), agent_timer(osd->client_messenger->cct, agent_timer_lock), objecter_lock("OSD::objecter_lock"), objecter_timer(osd->client_messenger->cct, objecter_lock), objecter(new Objecter(osd->client_messenger->cct, osd->objecter_messenger, osd->monc, &objecter_osdmap, objecter_lock, objecter_timer, 0, 0)), objecter_finisher(osd->client_messenger->cct), objecter_dispatcher(this), watch_lock("OSD::watch_lock"), watch_timer(osd->client_messenger->cct, watch_lock), next_notif_id(0), backfill_request_lock("OSD::backfill_request_lock"), backfill_request_timer(cct, backfill_request_lock, false), last_tid(0), tid_lock("OSDService::tid_lock"), reserver_finisher(cct), local_reserver(&reserver_finisher, cct->_conf->osd_max_backfills), remote_reserver(&reserver_finisher, cct->_conf->osd_max_backfills), pg_temp_lock("OSDService::pg_temp_lock"), map_cache_lock("OSDService::map_lock"), map_cache(cct->_conf->osd_map_cache_size), map_bl_cache(cct->_conf->osd_map_cache_size), map_bl_inc_cache(cct->_conf->osd_map_cache_size), in_progress_split_lock("OSDService::in_progress_split_lock"), full_status_lock("OSDService::full_status_lock"), cur_state(NONE), last_msg(0), cur_ratio(0), is_stopping_lock("OSDService::is_stopping_lock"), state(NOT_STOPPING) #ifdef PG_DEBUG_REFS , pgid_lock("OSDService::pgid_lock") #endif {} OSDService::~OSDService() { delete objecter; } void OSDService::_start_split(spg_t parent, const set &children) { for (set::const_iterator i = children.begin(); i != children.end(); ++i) { dout(10) << __func__ << ": Starting split on pg " << *i << ", parent=" << parent << dendl; assert(!pending_splits.count(*i)); assert(!in_progress_splits.count(*i)); pending_splits.insert(make_pair(*i, parent)); assert(!rev_pending_splits[parent].count(*i)); rev_pending_splits[parent].insert(*i); } } void OSDService::mark_split_in_progress(spg_t parent, const set &children) { Mutex::Locker l(in_progress_split_lock); map >::iterator piter = rev_pending_splits.find(parent); assert(piter != rev_pending_splits.end()); for (set::const_iterator i = children.begin(); i != children.end(); ++i) { assert(piter->second.count(*i)); assert(pending_splits.count(*i)); assert(!in_progress_splits.count(*i)); assert(pending_splits[*i] == parent); pending_splits.erase(*i); piter->second.erase(*i); in_progress_splits.insert(*i); } if (piter->second.empty()) rev_pending_splits.erase(piter); } void OSDService::cancel_pending_splits_for_parent(spg_t parent) { Mutex::Locker l(in_progress_split_lock); return _cancel_pending_splits_for_parent(parent); } void OSDService::_cancel_pending_splits_for_parent(spg_t parent) { map >::iterator piter = rev_pending_splits.find(parent); if (piter == rev_pending_splits.end()) return; for (set::iterator i = piter->second.begin(); i != piter->second.end(); ++i) { assert(pending_splits.count(*i)); assert(!in_progress_splits.count(*i)); pending_splits.erase(*i); dout(10) << __func__ << ": Completing split on pg " << *i << " for parent: " << parent << dendl; _cancel_pending_splits_for_parent(*i); } rev_pending_splits.erase(piter); } void OSDService::_maybe_split_pgid(OSDMapRef old_map, OSDMapRef new_map, spg_t pgid) { assert(old_map->have_pg_pool(pgid.pool())); if (pgid.ps() < static_cast(old_map->get_pg_num(pgid.pool()))) { set children; pgid.is_split(old_map->get_pg_num(pgid.pool()), new_map->get_pg_num(pgid.pool()), &children); _start_split(pgid, children); } else { assert(pgid.ps() < static_cast(new_map->get_pg_num(pgid.pool()))); } } void OSDService::init_splits_between(spg_t pgid, OSDMapRef frommap, OSDMapRef tomap) { // First, check whether we can avoid this potentially expensive check if (tomap->have_pg_pool(pgid.pool()) && pgid.is_split( frommap->get_pg_num(pgid.pool()), tomap->get_pg_num(pgid.pool()), NULL)) { // Ok, a split happened, so we need to walk the osdmaps set new_pgs; // pgs to scan on each map new_pgs.insert(pgid); OSDMapRef curmap(get_map(frommap->get_epoch())); for (epoch_t e = frommap->get_epoch() + 1; e <= tomap->get_epoch(); ++e) { OSDMapRef nextmap(try_get_map(e)); if (!nextmap) continue; set even_newer_pgs; // pgs added in this loop for (set::iterator i = new_pgs.begin(); i != new_pgs.end(); ++i) { set split_pgs; if (i->is_split(curmap->get_pg_num(i->pool()), nextmap->get_pg_num(i->pool()), &split_pgs)) { start_split(*i, split_pgs); even_newer_pgs.insert(split_pgs.begin(), split_pgs.end()); } } new_pgs.insert(even_newer_pgs.begin(), even_newer_pgs.end()); curmap = nextmap; } assert(curmap == tomap); // we must have had both frommap and tomap } } void OSDService::expand_pg_num(OSDMapRef old_map, OSDMapRef new_map) { Mutex::Locker l(in_progress_split_lock); for (set::iterator i = in_progress_splits.begin(); i != in_progress_splits.end(); ) { if (!new_map->have_pg_pool(i->pool())) { in_progress_splits.erase(i++); } else { _maybe_split_pgid(old_map, new_map, *i); ++i; } } for (map::iterator i = pending_splits.begin(); i != pending_splits.end(); ) { if (!new_map->have_pg_pool(i->first.pool())) { rev_pending_splits.erase(i->second); pending_splits.erase(i++); } else { _maybe_split_pgid(old_map, new_map, i->first); ++i; } } } bool OSDService::splitting(spg_t pgid) { Mutex::Locker l(in_progress_split_lock); return in_progress_splits.count(pgid) || pending_splits.count(pgid); } void OSDService::complete_split(const set &pgs) { Mutex::Locker l(in_progress_split_lock); for (set::const_iterator i = pgs.begin(); i != pgs.end(); ++i) { dout(10) << __func__ << ": Completing split on pg " << *i << dendl; assert(!pending_splits.count(*i)); assert(in_progress_splits.count(*i)); in_progress_splits.erase(*i); } } void OSDService::need_heartbeat_peer_update() { osd->need_heartbeat_peer_update(); } void OSDService::pg_stat_queue_enqueue(PG *pg) { osd->pg_stat_queue_enqueue(pg); } void OSDService::pg_stat_queue_dequeue(PG *pg) { osd->pg_stat_queue_dequeue(pg); } void OSDService::start_shutdown() { { Mutex::Locker l(agent_timer_lock); agent_timer.cancel_all_events(); agent_timer.shutdown(); } } void OSDService::shutdown() { reserver_finisher.stop(); { Mutex::Locker l(watch_lock); watch_timer.shutdown(); } { Mutex::Locker l(objecter_lock); objecter_timer.shutdown(); objecter->shutdown_locked(); } objecter->shutdown_unlocked(); objecter_finisher.stop(); { Mutex::Locker l(backfill_request_lock); backfill_request_timer.shutdown(); } osdmap = OSDMapRef(); next_osdmap = OSDMapRef(); } void OSDService::init() { reserver_finisher.start(); { objecter_finisher.start(); objecter->init_unlocked(); Mutex::Locker l(objecter_lock); objecter_timer.init(); objecter->set_client_incarnation(0); objecter->init_locked(); } watch_timer.init(); agent_timer.init(); agent_thread.create(); } void OSDService::activate_map() { // wake/unwake the tiering agent agent_lock.Lock(); agent_active = !osdmap->test_flag(CEPH_OSDMAP_NOTIERAGENT) && osd->is_active(); agent_cond.Signal(); agent_lock.Unlock(); } class AgentTimeoutCB : public Context { PGRef pg; public: AgentTimeoutCB(PGRef _pg) : pg(_pg) {} void finish(int) { pg->agent_choose_mode_restart(); } }; void OSDService::agent_entry() { dout(10) << __func__ << " start" << dendl; agent_lock.Lock(); while (!agent_stop_flag) { if (agent_queue.empty()) { dout(20) << __func__ << " empty queue" << dendl; agent_cond.Wait(agent_lock); continue; } uint64_t level = agent_queue.rbegin()->first; set& top = agent_queue.rbegin()->second; dout(10) << __func__ << " tiers " << agent_queue.size() << ", top is " << level << " with pgs " << top.size() << ", ops " << agent_ops << "/" << g_conf->osd_agent_max_ops << (agent_active ? " active" : " NOT ACTIVE") << dendl; dout(20) << __func__ << " oids " << agent_oids << dendl; if (agent_ops >= g_conf->osd_agent_max_ops || top.empty() || !agent_active) { agent_cond.Wait(agent_lock); continue; } if (!agent_valid_iterator || agent_queue_pos == top.end()) { agent_queue_pos = top.begin(); agent_valid_iterator = true; } PGRef pg = *agent_queue_pos; int max = g_conf->osd_agent_max_ops - agent_ops; agent_lock.Unlock(); if (!pg->agent_work(max)) { dout(10) << __func__ << " " << *pg << " no agent_work, delay for " << g_conf->osd_agent_delay_time << " seconds" << dendl; osd->logger->inc(l_osd_tier_delay); // Queue a timer to call agent_choose_mode for this pg in 5 seconds agent_timer_lock.Lock(); Context *cb = new AgentTimeoutCB(pg); agent_timer.add_event_after(g_conf->osd_agent_delay_time, cb); agent_timer_lock.Unlock(); } agent_lock.Lock(); } agent_lock.Unlock(); dout(10) << __func__ << " finish" << dendl; } void OSDService::agent_stop() { { Mutex::Locker l(agent_lock); // By this time all ops should be cancelled assert(agent_ops == 0); // By this time all PGs are shutdown and dequeued if (!agent_queue.empty()) { set& top = agent_queue.rbegin()->second; derr << "agent queue not empty, for example " << (*top.begin())->info.pgid << dendl; assert(0 == "agent queue not empty"); } agent_stop_flag = true; agent_cond.Signal(); } agent_thread.join(); } #undef dout_prefix #define dout_prefix *_dout int OSD::convert_collection(ObjectStore *store, coll_t cid) { coll_t tmp0("convertfs_temp"); coll_t tmp1("convertfs_temp1"); vector objects; map aset; int r = store->collection_getattrs(cid, aset); if (r < 0) return r; { ObjectStore::Transaction t; t.create_collection(tmp0); for (map::iterator i = aset.begin(); i != aset.end(); ++i) { bufferlist val; val.push_back(i->second); t.collection_setattr(tmp0, i->first, val); } store->apply_transaction(t); } ghobject_t next; while (!next.is_max()) { objects.clear(); ghobject_t start = next; r = store->collection_list_partial(cid, start, 200, 300, 0, &objects, &next); if (r < 0) return r; ObjectStore::Transaction t; for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { t.collection_add(tmp0, cid, *i); } store->apply_transaction(t); } { ObjectStore::Transaction t; t.collection_rename(cid, tmp1); t.collection_rename(tmp0, cid); store->apply_transaction(t); } recursive_remove_collection(store, tmp1); store->sync_and_flush(); store->sync(); return 0; } int OSD::do_convertfs(ObjectStore *store) { int r = store->mount(); if (r < 0) return r; uint32_t version; r = store->version_stamp_is_valid(&version); if (r < 0) return r; if (r == 1) return store->umount(); derr << "ObjectStore is old at version " << version << ". Updating..." << dendl; derr << "Removing tmp pgs" << dendl; vector collections; r = store->list_collections(collections); if (r < 0) return r; for (vector::iterator i = collections.begin(); i != collections.end(); ++i) { spg_t pgid; if (i->is_temp(pgid)) recursive_remove_collection(store, *i); else if (i->to_str() == "convertfs_temp" || i->to_str() == "convertfs_temp1") recursive_remove_collection(store, *i); } store->flush(); derr << "Getting collections" << dendl; derr << collections.size() << " to process." << dendl; collections.clear(); r = store->list_collections(collections); if (r < 0) return r; int processed = 0; for (vector::iterator i = collections.begin(); i != collections.end(); ++i, ++processed) { derr << processed << "/" << collections.size() << " processed" << dendl; uint32_t collection_version; r = store->collection_version_current(*i, &collection_version); if (r < 0) { return r; } else if (r == 1) { derr << "Collection " << *i << " is up to date" << dendl; } else { derr << "Updating collection " << *i << " current version is " << collection_version << dendl; r = convert_collection(store, *i); if (r < 0) return r; derr << "collection " << *i << " updated" << dendl; } } derr << "All collections up to date, updating version stamp..." << dendl; r = store->update_version_stamp(); if (r < 0) return r; store->sync_and_flush(); store->sync(); derr << "Version stamp updated, done with upgrade!" << dendl; return store->umount(); } int OSD::mkfs(CephContext *cct, ObjectStore *store, const string &dev, uuid_d fsid, int whoami) { int ret; try { // if we are fed a uuid for this osd, use it. store->set_fsid(cct->_conf->osd_uuid); ret = store->mkfs(); if (ret) { derr << "OSD::mkfs: ObjectStore::mkfs failed with error " << ret << dendl; goto free_store; } ret = store->mount(); if (ret) { derr << "OSD::mkfs: couldn't mount ObjectStore: error " << ret << dendl; goto free_store; } // age? if (cct->_conf->osd_age_time != 0) { if (cct->_conf->osd_age_time >= 0) { dout(0) << "aging..." << dendl; Ager ager(cct, store); ager.age(cct->_conf->osd_age_time, cct->_conf->osd_age, cct->_conf->osd_age - .05, 50000, cct->_conf->osd_age - .05); } } OSDSuperblock sb; bufferlist sbbl; ret = store->read(coll_t::META_COLL, OSD_SUPERBLOCK_POBJECT, 0, 0, sbbl); if (ret >= 0) { dout(0) << " have superblock" << dendl; if (whoami != sb.whoami) { derr << "provided osd id " << whoami << " != superblock's " << sb.whoami << dendl; ret = -EINVAL; goto umount_store; } if (fsid != sb.cluster_fsid) { derr << "provided cluster fsid " << fsid << " != superblock's " << sb.cluster_fsid << dendl; ret = -EINVAL; goto umount_store; } } else { // create superblock if (fsid.is_zero()) { derr << "must specify cluster fsid" << dendl; ret = -EINVAL; goto umount_store; } sb.cluster_fsid = fsid; sb.osd_fsid = store->get_fsid(); sb.whoami = whoami; sb.compat_features = get_osd_initial_compat_set(); // benchmark? if (cct->_conf->osd_auto_weight) { bufferlist bl; bufferptr bp(1048576); bp.zero(); bl.push_back(bp); dout(0) << "testing disk bandwidth..." << dendl; utime_t start = ceph_clock_now(cct); object_t oid("disk_bw_test"); for (int i=0; i<1000; i++) { ObjectStore::Transaction *t = new ObjectStore::Transaction; t->write(coll_t::META_COLL, hobject_t(sobject_t(oid, 0)), i*bl.length(), bl.length(), bl); store->queue_transaction_and_cleanup(NULL, t); } store->sync(); utime_t end = ceph_clock_now(cct); end -= start; dout(0) << "measured " << (1000.0 / (double)end) << " mb/sec" << dendl; ObjectStore::Transaction tr; tr.remove(coll_t::META_COLL, hobject_t(sobject_t(oid, 0))); ret = store->apply_transaction(tr); if (ret) { derr << "OSD::mkfs: error while benchmarking: apply_transaction returned " << ret << dendl; goto umount_store; } // set osd weight sb.weight = (1000.0 / (double)end); } bufferlist bl; ::encode(sb, bl); ObjectStore::Transaction t; t.create_collection(coll_t::META_COLL); t.write(coll_t::META_COLL, OSD_SUPERBLOCK_POBJECT, 0, bl.length(), bl); ret = store->apply_transaction(t); if (ret) { derr << "OSD::mkfs: error while writing OSD_SUPERBLOCK_POBJECT: " << "apply_transaction returned " << ret << dendl; goto umount_store; } } store->sync_and_flush(); ret = write_meta(store, sb.cluster_fsid, sb.osd_fsid, whoami); if (ret) { derr << "OSD::mkfs: failed to write fsid file: error " << ret << dendl; goto umount_store; } } catch (const std::exception &se) { derr << "OSD::mkfs: caught exception " << se.what() << dendl; ret = 1000; } catch (...) { derr << "OSD::mkfs: caught unknown exception." << dendl; ret = 1000; } umount_store: store->umount(); free_store: delete store; return ret; } int OSD::write_meta(ObjectStore *store, uuid_d& cluster_fsid, uuid_d& osd_fsid, int whoami) { char val[80]; int r; snprintf(val, sizeof(val), "%s", CEPH_OSD_ONDISK_MAGIC); r = store->write_meta("magic", val); if (r < 0) return r; snprintf(val, sizeof(val), "%d", whoami); r = store->write_meta("whoami", val); if (r < 0) return r; cluster_fsid.print(val); r = store->write_meta("ceph_fsid", val); if (r < 0) return r; r = store->write_meta("ready", "ready"); if (r < 0) return r; return 0; } int OSD::peek_meta(ObjectStore *store, std::string& magic, uuid_d& cluster_fsid, uuid_d& osd_fsid, int& whoami) { string val; int r = store->read_meta("magic", &val); if (r < 0) return r; magic = val; r = store->read_meta("whoami", &val); if (r < 0) return r; whoami = atoi(val.c_str()); r = store->read_meta("ceph_fsid", &val); if (r < 0) return r; r = cluster_fsid.parse(val.c_str()); if (r < 0) return r; r = store->read_meta("fsid", &val); if (r < 0) { osd_fsid = uuid_d(); } else { r = osd_fsid.parse(val.c_str()); if (r < 0) return r; } return 0; } #undef dout_prefix #define dout_prefix _prefix(_dout, whoami, osdmap) // cons/des OSD::OSD(CephContext *cct_, ObjectStore *store_, int id, Messenger *internal_messenger, Messenger *external_messenger, Messenger *hb_clientm, Messenger *hb_front_serverm, Messenger *hb_back_serverm, Messenger *osdc_messenger, MonClient *mc, const std::string &dev, const std::string &jdev) : Dispatcher(cct_), osd_lock("OSD::osd_lock"), tick_timer(cct, osd_lock), authorize_handler_cluster_registry(new AuthAuthorizeHandlerRegistry(cct, cct->_conf->auth_supported.length() ? cct->_conf->auth_supported : cct->_conf->auth_cluster_required)), authorize_handler_service_registry(new AuthAuthorizeHandlerRegistry(cct, cct->_conf->auth_supported.length() ? cct->_conf->auth_supported : cct->_conf->auth_service_required)), cluster_messenger(internal_messenger), client_messenger(external_messenger), objecter_messenger(osdc_messenger), monc(mc), logger(NULL), recoverystate_perf(NULL), store(store_), clog(cct, client_messenger, &mc->monmap, LogClient::NO_FLAGS), whoami(id), dev_path(dev), journal_path(jdev), dispatch_running(false), asok_hook(NULL), osd_compat(get_osd_compat_set()), state(STATE_INITIALIZING), boot_epoch(0), up_epoch(0), bind_epoch(0), op_tp(cct, "OSD::op_tp", cct->_conf->osd_op_threads, "osd_op_threads"), recovery_tp(cct, "OSD::recovery_tp", cct->_conf->osd_recovery_threads, "osd_recovery_threads"), disk_tp(cct, "OSD::disk_tp", cct->_conf->osd_disk_threads, "osd_disk_threads"), command_tp(cct, "OSD::command_tp", 1), paused_recovery(false), heartbeat_lock("OSD::heartbeat_lock"), heartbeat_stop(false), heartbeat_need_update(true), heartbeat_epoch(0), hbclient_messenger(hb_clientm), hb_front_server_messenger(hb_front_serverm), hb_back_server_messenger(hb_back_serverm), heartbeat_thread(this), heartbeat_dispatcher(this), stat_lock("OSD::stat_lock"), finished_lock("OSD::finished_lock"), op_tracker(cct, cct->_conf->osd_enable_op_tracker), test_ops_hook(NULL), op_wq( this, cct->_conf->osd_op_thread_timeout, cct->_conf->osd_op_thread_suicide_timeout, &op_tp), peering_wq( this, cct->_conf->osd_op_thread_timeout, cct->_conf->osd_op_thread_suicide_timeout, &op_tp), map_lock("OSD::map_lock"), peer_map_epoch_lock("OSD::peer_map_epoch_lock"), debug_drop_pg_create_probability(cct->_conf->osd_debug_drop_pg_create_probability), debug_drop_pg_create_duration(cct->_conf->osd_debug_drop_pg_create_duration), debug_drop_pg_create_left(-1), outstanding_pg_stats(false), timeout_mon_on_pg_stats(true), up_thru_wanted(0), up_thru_pending(0), pg_stat_queue_lock("OSD::pg_stat_queue_lock"), osd_stat_updated(false), pg_stat_tid(0), pg_stat_tid_flushed(0), command_wq( this, cct->_conf->osd_command_thread_timeout, cct->_conf->osd_command_thread_suicide_timeout, &command_tp), recovery_ops_active(0), recovery_wq( this, cct->_conf->osd_recovery_thread_timeout, cct->_conf->osd_recovery_thread_suicide_timeout, &recovery_tp), replay_queue_lock("OSD::replay_queue_lock"), snap_trim_wq( this, cct->_conf->osd_snap_trim_thread_timeout, cct->_conf->osd_snap_trim_thread_suicide_timeout, &disk_tp), scrub_wq( this, cct->_conf->osd_scrub_thread_timeout, cct->_conf->osd_scrub_thread_suicide_timeout, &disk_tp), scrub_finalize_wq( cct->_conf->osd_scrub_finalize_thread_timeout, cct->_conf->osd_scrub_finalize_thread_suicide_timeout, &op_tp), rep_scrub_wq( this, cct->_conf->osd_scrub_thread_timeout, cct->_conf->osd_scrub_thread_suicide_timeout, &disk_tp), remove_wq( store, cct->_conf->osd_remove_thread_timeout, cct->_conf->osd_remove_thread_suicide_timeout, &disk_tp), next_removal_seq(0), service(this) { monc->set_messenger(client_messenger); op_tracker.set_complaint_and_threshold(cct->_conf->osd_op_complaint_time, cct->_conf->osd_op_log_threshold); op_tracker.set_history_size_and_duration(cct->_conf->osd_op_history_size, cct->_conf->osd_op_history_duration); } OSD::~OSD() { delete authorize_handler_cluster_registry; delete authorize_handler_service_registry; delete class_handler; cct->get_perfcounters_collection()->remove(recoverystate_perf); cct->get_perfcounters_collection()->remove(logger); delete recoverystate_perf; delete logger; delete store; } void cls_initialize(ClassHandler *ch); void OSD::handle_signal(int signum) { assert(signum == SIGINT || signum == SIGTERM); derr << "*** Got signal " << sys_siglist[signum] << " ***" << dendl; //suicide(128 + signum); shutdown(); } int OSD::pre_init() { Mutex::Locker lock(osd_lock); if (is_stopping()) return 0; if (store->test_mount_in_use()) { derr << "OSD::pre_init: object store '" << dev_path << "' is " << "currently in use. (Is ceph-osd already running?)" << dendl; return -EBUSY; } cct->_conf->add_observer(this); return 0; } // asok class OSDSocketHook : public AdminSocketHook { OSD *osd; public: OSDSocketHook(OSD *o) : osd(o) {} bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out) { stringstream ss; bool r = osd->asok_command(command, cmdmap, format, ss); out.append(ss); return r; } }; bool OSD::asok_command(string command, cmdmap_t& cmdmap, string format, ostream& ss) { Formatter *f = new_formatter(format); if (!f) f = new_formatter("json-pretty"); if (command == "status") { f->open_object_section("status"); f->dump_stream("cluster_fsid") << superblock.cluster_fsid; f->dump_stream("osd_fsid") << superblock.osd_fsid; f->dump_unsigned("whoami", superblock.whoami); f->dump_string("state", get_state_name(state)); f->dump_unsigned("oldest_map", superblock.oldest_map); f->dump_unsigned("newest_map", superblock.newest_map); osd_lock.Lock(); f->dump_unsigned("num_pgs", pg_map.size()); osd_lock.Unlock(); f->close_section(); } else if (command == "flush_journal") { store->sync_and_flush(); } else if (command == "dump_ops_in_flight") { op_tracker.dump_ops_in_flight(f); } else if (command == "dump_historic_ops") { op_tracker.dump_historic_ops(f); } else if (command == "dump_op_pq_state") { f->open_object_section("pq"); op_wq.dump(f); f->close_section(); } else if (command == "dump_blacklist") { list > bl; OSDMapRef curmap = service.get_osdmap(); f->open_array_section("blacklist"); curmap->get_blacklist(&bl); for (list >::iterator it = bl.begin(); it != bl.end(); ++it) { f->open_array_section("entry"); f->open_object_section("entity_addr_t"); it->first.dump(f); f->close_section(); //entity_addr_t it->second.localtime(f->dump_stream("expire_time")); f->close_section(); //entry } f->close_section(); //blacklist } else if (command == "dump_watchers") { list watchers; osd_lock.Lock(); // scan pg's for (ceph::unordered_map::iterator it = pg_map.begin(); it != pg_map.end(); ++it) { list pg_watchers; PG *pg = it->second; pg->lock(); pg->get_watchers(pg_watchers); pg->unlock(); watchers.splice(watchers.end(), pg_watchers); } osd_lock.Unlock(); f->open_array_section("watchers"); for (list::iterator it = watchers.begin(); it != watchers.end(); ++it) { f->open_array_section("watch"); f->dump_string("namespace", it->obj.nspace); f->dump_string("object", it->obj.oid.name); f->open_object_section("entity_name"); it->wi.name.dump(f); f->close_section(); //entity_name_t f->dump_int("cookie", it->wi.cookie); f->dump_int("timeout", it->wi.timeout_seconds); f->open_object_section("entity_addr_t"); it->wi.addr.dump(f); f->close_section(); //entity_addr_t f->close_section(); //watch } f->close_section(); //watches } else { assert(0 == "broken asok registration"); } f->flush(ss); delete f; return true; } class TestOpsSocketHook : public AdminSocketHook { OSDService *service; ObjectStore *store; public: TestOpsSocketHook(OSDService *s, ObjectStore *st) : service(s), store(st) {} bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out) { stringstream ss; test_ops(service, store, command, cmdmap, ss); out.append(ss); return true; } void test_ops(OSDService *service, ObjectStore *store, std::string command, cmdmap_t& cmdmap, ostream &ss); }; int OSD::init() { CompatSet initial, diff; Mutex::Locker lock(osd_lock); if (is_stopping()) return 0; tick_timer.init(); service.backfill_request_timer.init(); // mount. dout(2) << "mounting " << dev_path << " " << (journal_path.empty() ? "(no journal)" : journal_path) << dendl; assert(store); // call pre_init() first! int r = store->mount(); if (r < 0) { derr << "OSD:init: unable to mount object store" << dendl; return r; } dout(2) << "boot" << dendl; // read superblock r = read_superblock(); if (r < 0) { derr << "OSD::init() : unable to read osd superblock" << dendl; r = -EINVAL; goto out; } if (osd_compat.compare(superblock.compat_features) < 0) { derr << "The disk uses features unsupported by the executable." << dendl; derr << " ondisk features " << superblock.compat_features << dendl; derr << " daemon features " << osd_compat << dendl; if (osd_compat.writeable(superblock.compat_features)) { CompatSet diff = osd_compat.unsupported(superblock.compat_features); derr << "it is still writeable, though. Missing features: " << diff << dendl; r = -EOPNOTSUPP; goto out; } else { CompatSet diff = osd_compat.unsupported(superblock.compat_features); derr << "Cannot write to disk! Missing features: " << diff << dendl; r = -EOPNOTSUPP; goto out; } } assert_warn(whoami == superblock.whoami); if (whoami != superblock.whoami) { derr << "OSD::init: superblock says osd" << superblock.whoami << " but i am osd." << whoami << dendl; r = -EINVAL; goto out; } initial = get_osd_initial_compat_set(); diff = superblock.compat_features.unsupported(initial); if (superblock.compat_features.merge(initial)) { // We need to persist the new compat_set before we // do anything else dout(5) << "Upgrading superblock adding: " << diff << dendl; ObjectStore::Transaction t; write_superblock(t); r = store->apply_transaction(t); if (r < 0) goto out; } // make sure info object exists if (!store->exists(coll_t::META_COLL, service.infos_oid)) { dout(10) << "init creating/touching snapmapper object" << dendl; ObjectStore::Transaction t; t.touch(coll_t::META_COLL, service.infos_oid); r = store->apply_transaction(t); if (r < 0) goto out; } // make sure snap mapper object exists if (!store->exists(coll_t::META_COLL, OSD::make_snapmapper_oid())) { dout(10) << "init creating/touching infos object" << dendl; ObjectStore::Transaction t; t.touch(coll_t::META_COLL, OSD::make_snapmapper_oid()); r = store->apply_transaction(t); if (r < 0) goto out; } class_handler = new ClassHandler(cct); cls_initialize(class_handler); if (cct->_conf->osd_open_classes_on_start) { int r = class_handler->open_all_classes(); if (r) dout(1) << "warning: got an error loading one or more classes: " << cpp_strerror(r) << dendl; } // load up "current" osdmap assert_warn(!osdmap); if (osdmap) { derr << "OSD::init: unable to read current osdmap" << dendl; r = -EINVAL; goto out; } osdmap = get_map(superblock.current_epoch); check_osdmap_features(store); create_recoverystate_perf(); bind_epoch = osdmap->get_epoch(); // load up pgs (as they previously existed) load_pgs(); dout(2) << "superblock: i am osd." << superblock.whoami << dendl; create_logger(); // i'm ready! client_messenger->add_dispatcher_head(this); cluster_messenger->add_dispatcher_head(this); hbclient_messenger->add_dispatcher_head(&heartbeat_dispatcher); hb_front_server_messenger->add_dispatcher_head(&heartbeat_dispatcher); hb_back_server_messenger->add_dispatcher_head(&heartbeat_dispatcher); objecter_messenger->add_dispatcher_head(&service.objecter_dispatcher); monc->set_want_keys(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD); r = monc->init(); if (r < 0) goto out; // tell monc about log_client so it will know about mon session resets monc->set_log_client(&clog); op_tp.start(); recovery_tp.start(); disk_tp.start(); command_tp.start(); set_disk_tp_priority(); // start the heartbeat heartbeat_thread.create(); // tick tick_timer.add_event_after(cct->_conf->osd_heartbeat_interval, new C_Tick(this)); service.init(); service.publish_map(osdmap); service.publish_superblock(superblock); osd_lock.Unlock(); r = monc->authenticate(); if (r < 0) { osd_lock.Lock(); // locker is going to unlock this on function exit if (is_stopping()) r = 0; goto monout; } while (monc->wait_auth_rotating(30.0) < 0) { derr << "unable to obtain rotating service keys; retrying" << dendl; } osd_lock.Lock(); if (is_stopping()) return 0; check_config(); dout(10) << "ensuring pgs have consumed prior maps" << dendl; consume_map(); peering_wq.drain(); dout(0) << "done with init, starting boot process" << dendl; state = STATE_BOOTING; start_boot(); return 0; monout: monc->shutdown(); out: store->umount(); delete store; return r; } void OSD::final_init() { int r; AdminSocket *admin_socket = cct->get_admin_socket(); asok_hook = new OSDSocketHook(this); r = admin_socket->register_command("status", "status", asok_hook, "high-level status of OSD"); assert(r == 0); r = admin_socket->register_command("flush_journal", "flush_journal", asok_hook, "flush the journal to permanent store"); assert(r == 0); r = admin_socket->register_command("dump_ops_in_flight", "dump_ops_in_flight", asok_hook, "show the ops currently in flight"); assert(r == 0); r = admin_socket->register_command("dump_historic_ops", "dump_historic_ops", asok_hook, "show slowest recent ops"); assert(r == 0); r = admin_socket->register_command("dump_op_pq_state", "dump_op_pq_state", asok_hook, "dump op priority queue state"); assert(r == 0); r = admin_socket->register_command("dump_blacklist", "dump_blacklist", asok_hook, "dump blacklisted clients and times"); assert(r == 0); r = admin_socket->register_command("dump_watchers", "dump_watchers", asok_hook, "show clients which have active watches," " and on which objects"); assert(r == 0); test_ops_hook = new TestOpsSocketHook(&(this->service), this->store); // Note: pools are CephString instead of CephPoolname because // these commands traditionally support both pool names and numbers r = admin_socket->register_command( "setomapval", "setomapval " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname " \ "name=key,type=CephString "\ "name=val,type=CephString", test_ops_hook, "set omap key"); assert(r == 0); r = admin_socket->register_command( "rmomapkey", "rmomapkey " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname " \ "name=key,type=CephString", test_ops_hook, "remove omap key"); assert(r == 0); r = admin_socket->register_command( "setomapheader", "setomapheader " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname " \ "name=header,type=CephString", test_ops_hook, "set omap header"); assert(r == 0); r = admin_socket->register_command( "getomap", "getomap " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname", test_ops_hook, "output entire object map"); assert(r == 0); r = admin_socket->register_command( "truncobj", "truncobj " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname " \ "name=len,type=CephInt", test_ops_hook, "truncate object to length"); assert(r == 0); r = admin_socket->register_command( "injectdataerr", "injectdataerr " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname", test_ops_hook, "inject data error into omap"); assert(r == 0); r = admin_socket->register_command( "injectmdataerr", "injectmdataerr " \ "name=pool,type=CephString " \ "name=objname,type=CephObjectname", test_ops_hook, "inject metadata error"); assert(r == 0); } void OSD::create_logger() { dout(10) << "create_logger" << dendl; PerfCountersBuilder osd_plb(cct, "osd", l_osd_first, l_osd_last); osd_plb.add_u64(l_osd_opq, "opq"); // op queue length (waiting to be processed yet) osd_plb.add_u64(l_osd_op_wip, "op_wip"); // rep ops currently being processed (primary) osd_plb.add_u64_counter(l_osd_op, "op"); // client ops osd_plb.add_u64_counter(l_osd_op_inb, "op_in_bytes"); // client op in bytes (writes) osd_plb.add_u64_counter(l_osd_op_outb, "op_out_bytes"); // client op out bytes (reads) osd_plb.add_time_avg(l_osd_op_lat, "op_latency"); // client op latency osd_plb.add_time_avg(l_osd_op_process_lat, "op_process_latency"); // client op process latency osd_plb.add_u64_counter(l_osd_op_r, "op_r"); // client reads osd_plb.add_u64_counter(l_osd_op_r_outb, "op_r_out_bytes"); // client read out bytes osd_plb.add_time_avg(l_osd_op_r_lat, "op_r_latency"); // client read latency osd_plb.add_time_avg(l_osd_op_r_process_lat, "op_r_process_latency"); // client read process latency osd_plb.add_u64_counter(l_osd_op_w, "op_w"); // client writes osd_plb.add_u64_counter(l_osd_op_w_inb, "op_w_in_bytes"); // client write in bytes osd_plb.add_time_avg(l_osd_op_w_rlat, "op_w_rlat"); // client write readable/applied latency osd_plb.add_time_avg(l_osd_op_w_lat, "op_w_latency"); // client write latency osd_plb.add_time_avg(l_osd_op_w_process_lat, "op_w_process_latency"); // client write process latency osd_plb.add_u64_counter(l_osd_op_rw, "op_rw"); // client rmw osd_plb.add_u64_counter(l_osd_op_rw_inb, "op_rw_in_bytes"); // client rmw in bytes osd_plb.add_u64_counter(l_osd_op_rw_outb,"op_rw_out_bytes"); // client rmw out bytes osd_plb.add_time_avg(l_osd_op_rw_rlat,"op_rw_rlat"); // client rmw readable/applied latency osd_plb.add_time_avg(l_osd_op_rw_lat, "op_rw_latency"); // client rmw latency osd_plb.add_time_avg(l_osd_op_rw_process_lat, "op_rw_process_latency"); // client rmw process latency osd_plb.add_u64_counter(l_osd_sop, "subop"); // subops osd_plb.add_u64_counter(l_osd_sop_inb, "subop_in_bytes"); // subop in bytes osd_plb.add_time_avg(l_osd_sop_lat, "subop_latency"); // subop latency osd_plb.add_u64_counter(l_osd_sop_w, "subop_w"); // replicated (client) writes osd_plb.add_u64_counter(l_osd_sop_w_inb, "subop_w_in_bytes"); // replicated write in bytes osd_plb.add_time_avg(l_osd_sop_w_lat, "subop_w_latency"); // replicated write latency osd_plb.add_u64_counter(l_osd_sop_pull, "subop_pull"); // pull request osd_plb.add_time_avg(l_osd_sop_pull_lat, "subop_pull_latency"); osd_plb.add_u64_counter(l_osd_sop_push, "subop_push"); // push (write) osd_plb.add_u64_counter(l_osd_sop_push_inb, "subop_push_in_bytes"); osd_plb.add_time_avg(l_osd_sop_push_lat, "subop_push_latency"); osd_plb.add_u64_counter(l_osd_pull, "pull"); // pull requests sent osd_plb.add_u64_counter(l_osd_push, "push"); // push messages osd_plb.add_u64_counter(l_osd_push_outb, "push_out_bytes"); // pushed bytes osd_plb.add_u64_counter(l_osd_push_in, "push_in"); // inbound push messages osd_plb.add_u64_counter(l_osd_push_inb, "push_in_bytes"); // inbound pushed bytes osd_plb.add_u64_counter(l_osd_rop, "recovery_ops"); // recovery ops (started) osd_plb.add_u64(l_osd_loadavg, "loadavg"); osd_plb.add_u64(l_osd_buf, "buffer_bytes"); // total ceph::buffer bytes osd_plb.add_u64(l_osd_pg, "numpg"); // num pgs osd_plb.add_u64(l_osd_pg_primary, "numpg_primary"); // num primary pgs osd_plb.add_u64(l_osd_pg_replica, "numpg_replica"); // num replica pgs osd_plb.add_u64(l_osd_pg_stray, "numpg_stray"); // num stray pgs osd_plb.add_u64(l_osd_hb_to, "heartbeat_to_peers"); // heartbeat peers we send to osd_plb.add_u64(l_osd_hb_from, "heartbeat_from_peers"); // heartbeat peers we recv from osd_plb.add_u64_counter(l_osd_map, "map_messages"); // osdmap messages osd_plb.add_u64_counter(l_osd_mape, "map_message_epochs"); // osdmap epochs osd_plb.add_u64_counter(l_osd_mape_dup, "map_message_epoch_dups"); // dup osdmap epochs osd_plb.add_u64_counter(l_osd_waiting_for_map, "messages_delayed_for_map"); // dup osdmap epochs osd_plb.add_u64(l_osd_stat_bytes, "stat_bytes"); osd_plb.add_u64(l_osd_stat_bytes_used, "stat_bytes_used"); osd_plb.add_u64(l_osd_stat_bytes_avail, "stat_bytes_avail"); osd_plb.add_u64_counter(l_osd_copyfrom, "copyfrom"); osd_plb.add_u64_counter(l_osd_tier_promote, "tier_promote"); osd_plb.add_u64_counter(l_osd_tier_flush, "tier_flush"); osd_plb.add_u64_counter(l_osd_tier_flush_fail, "tier_flush_fail"); osd_plb.add_u64_counter(l_osd_tier_try_flush, "tier_try_flush"); osd_plb.add_u64_counter(l_osd_tier_try_flush_fail, "tier_try_flush_fail"); osd_plb.add_u64_counter(l_osd_tier_evict, "tier_evict"); osd_plb.add_u64_counter(l_osd_tier_whiteout, "tier_whiteout"); osd_plb.add_u64_counter(l_osd_tier_dirty, "tier_dirty"); osd_plb.add_u64_counter(l_osd_tier_clean, "tier_clean"); osd_plb.add_u64_counter(l_osd_tier_delay, "tier_delay"); osd_plb.add_u64_counter(l_osd_agent_wake, "agent_wake"); osd_plb.add_u64_counter(l_osd_agent_skip, "agent_skip"); osd_plb.add_u64_counter(l_osd_agent_flush, "agent_flush"); osd_plb.add_u64_counter(l_osd_agent_evict, "agent_evict"); logger = osd_plb.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); } void OSD::create_recoverystate_perf() { dout(10) << "create_recoverystate_perf" << dendl; PerfCountersBuilder rs_perf(cct, "recoverystate_perf", rs_first, rs_last); rs_perf.add_time_avg(rs_initial_latency, "initial_latency"); rs_perf.add_time_avg(rs_started_latency, "started_latency"); rs_perf.add_time_avg(rs_reset_latency, "reset_latency"); rs_perf.add_time_avg(rs_start_latency, "start_latency"); rs_perf.add_time_avg(rs_primary_latency, "primary_latency"); rs_perf.add_time_avg(rs_peering_latency, "peering_latency"); rs_perf.add_time_avg(rs_backfilling_latency, "backfilling_latency"); rs_perf.add_time_avg(rs_waitremotebackfillreserved_latency, "waitremotebackfillreserved_latency"); rs_perf.add_time_avg(rs_waitlocalbackfillreserved_latency, "waitlocalbackfillreserved_latency"); rs_perf.add_time_avg(rs_notbackfilling_latency, "notbackfilling_latency"); rs_perf.add_time_avg(rs_repnotrecovering_latency, "repnotrecovering_latency"); rs_perf.add_time_avg(rs_repwaitrecoveryreserved_latency, "repwaitrecoveryreserved_latency"); rs_perf.add_time_avg(rs_repwaitbackfillreserved_latency, "repwaitbackfillreserved_latency"); rs_perf.add_time_avg(rs_RepRecovering_latency, "RepRecovering_latency"); rs_perf.add_time_avg(rs_activating_latency, "activating_latency"); rs_perf.add_time_avg(rs_waitlocalrecoveryreserved_latency, "waitlocalrecoveryreserved_latency"); rs_perf.add_time_avg(rs_waitremoterecoveryreserved_latency, "waitremoterecoveryreserved_latency"); rs_perf.add_time_avg(rs_recovering_latency, "recovering_latency"); rs_perf.add_time_avg(rs_recovered_latency, "recovered_latency"); rs_perf.add_time_avg(rs_clean_latency, "clean_latency"); rs_perf.add_time_avg(rs_active_latency, "active_latency"); rs_perf.add_time_avg(rs_replicaactive_latency, "replicaactive_latency"); rs_perf.add_time_avg(rs_stray_latency, "stray_latency"); rs_perf.add_time_avg(rs_getinfo_latency, "getinfo_latency"); rs_perf.add_time_avg(rs_getlog_latency, "getlog_latency"); rs_perf.add_time_avg(rs_waitactingchange_latency, "waitactingchange_latency"); rs_perf.add_time_avg(rs_incomplete_latency, "incomplete_latency"); rs_perf.add_time_avg(rs_getmissing_latency, "getmissing_latency"); rs_perf.add_time_avg(rs_waitupthru_latency, "waitupthru_latency"); recoverystate_perf = rs_perf.create_perf_counters(); cct->get_perfcounters_collection()->add(recoverystate_perf); } void OSD::suicide(int exitcode) { if (cct->_conf->filestore_blackhole) { derr << " filestore_blackhole=true, doing abbreviated shutdown" << dendl; _exit(exitcode); } // turn off lockdep; the surviving threads tend to fight with exit() below g_lockdep = 0; derr << " pausing thread pools" << dendl; op_tp.pause(); disk_tp.pause(); recovery_tp.pause(); command_tp.pause(); derr << " flushing io" << dendl; store->sync_and_flush(); derr << " removing pid file" << dendl; pidfile_remove(); derr << " exit" << dendl; exit(exitcode); } int OSD::shutdown() { if (!service.prepare_to_stop()) return 0; // already shutting down osd_lock.Lock(); if (is_stopping()) { osd_lock.Unlock(); return 0; } derr << "shutdown" << dendl; heartbeat_lock.Lock(); state = STATE_STOPPING; heartbeat_lock.Unlock(); // Debugging cct->_conf->set_val("debug_osd", "100"); cct->_conf->set_val("debug_journal", "100"); cct->_conf->set_val("debug_filestore", "100"); cct->_conf->set_val("debug_ms", "100"); cct->_conf->apply_changes(NULL); service.start_shutdown(); // Shutdown PGs for (ceph::unordered_map::iterator p = pg_map.begin(); p != pg_map.end(); ++p) { dout(20) << " kicking pg " << p->first << dendl; p->second->lock(); p->second->on_shutdown(); p->second->unlock(); p->second->osr->flush(); } // finish ops op_wq.drain(); // should already be empty except for lagard PGs { Mutex::Locker l(finished_lock); finished.clear(); // zap waiters (bleh, this is messy) } // unregister commands cct->get_admin_socket()->unregister_command("status"); cct->get_admin_socket()->unregister_command("flush_journal"); cct->get_admin_socket()->unregister_command("dump_ops_in_flight"); cct->get_admin_socket()->unregister_command("dump_historic_ops"); cct->get_admin_socket()->unregister_command("dump_op_pq_state"); cct->get_admin_socket()->unregister_command("dump_blacklist"); cct->get_admin_socket()->unregister_command("dump_watchers"); delete asok_hook; asok_hook = NULL; cct->get_admin_socket()->unregister_command("setomapval"); cct->get_admin_socket()->unregister_command("rmomapkey"); cct->get_admin_socket()->unregister_command("setomapheader"); cct->get_admin_socket()->unregister_command("getomap"); cct->get_admin_socket()->unregister_command("truncobj"); cct->get_admin_socket()->unregister_command("injectdataerr"); cct->get_admin_socket()->unregister_command("injectmdataerr"); delete test_ops_hook; test_ops_hook = NULL; osd_lock.Unlock(); heartbeat_lock.Lock(); heartbeat_stop = true; heartbeat_cond.Signal(); heartbeat_lock.Unlock(); heartbeat_thread.join(); recovery_tp.drain(); recovery_tp.stop(); dout(10) << "recovery tp stopped" << dendl; op_tp.drain(); peering_wq.clear(); scrub_finalize_wq.clear(); op_tp.stop(); dout(10) << "osd tp stopped" << dendl; command_tp.drain(); command_tp.stop(); dout(10) << "command tp stopped" << dendl; disk_tp.drain(); disk_tp.stop(); dout(10) << "disk tp paused (new)" << dendl; dout(10) << "stopping agent" << dendl; service.agent_stop(); osd_lock.Lock(); reset_heartbeat_peers(); tick_timer.shutdown(); // note unmount epoch dout(10) << "noting clean unmount in epoch " << osdmap->get_epoch() << dendl; superblock.mounted = boot_epoch; superblock.clean_thru = osdmap->get_epoch(); ObjectStore::Transaction t; write_superblock(t); int r = store->apply_transaction(t); if (r) { derr << "OSD::shutdown: error writing superblock: " << cpp_strerror(r) << dendl; } dout(10) << "syncing store" << dendl; store->flush(); store->sync(); store->umount(); delete store; store = 0; dout(10) << "Store synced" << dendl; { Mutex::Locker l(pg_stat_queue_lock); assert(pg_stat_queue.empty()); } // Remove PGs #ifdef PG_DEBUG_REFS service.dump_live_pgids(); #endif for (ceph::unordered_map::iterator p = pg_map.begin(); p != pg_map.end(); ++p) { dout(20) << " kicking pg " << p->first << dendl; p->second->lock(); if (p->second->ref.read() != 1) { derr << "pgid " << p->first << " has ref count of " << p->second->ref.read() << dendl; assert(0); } p->second->unlock(); p->second->put("PGMap"); } pg_map.clear(); #ifdef PG_DEBUG_REFS service.dump_live_pgids(); #endif cct->_conf->remove_observer(this); monc->shutdown(); osd_lock.Unlock(); osdmap = OSDMapRef(); service.shutdown(); op_tracker.on_shutdown(); class_handler->shutdown(); client_messenger->shutdown(); cluster_messenger->shutdown(); hbclient_messenger->shutdown(); objecter_messenger->shutdown(); hb_front_server_messenger->shutdown(); hb_back_server_messenger->shutdown(); peering_wq.clear(); return r; } void OSD::write_superblock(ObjectStore::Transaction& t) { dout(10) << "write_superblock " << superblock << dendl; //hack: at minimum it's using the baseline feature set if (!superblock.compat_features.incompat.mask | CEPH_OSD_FEATURE_INCOMPAT_BASE.id) superblock.compat_features.incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BASE); bufferlist bl; ::encode(superblock, bl); t.write(coll_t::META_COLL, OSD_SUPERBLOCK_POBJECT, 0, bl.length(), bl); } int OSD::read_superblock() { bufferlist bl; int r = store->read(coll_t::META_COLL, OSD_SUPERBLOCK_POBJECT, 0, 0, bl); if (r < 0) return r; bufferlist::iterator p = bl.begin(); ::decode(superblock, p); dout(10) << "read_superblock " << superblock << dendl; return 0; } void OSD::recursive_remove_collection(ObjectStore *store, coll_t tmp) { OSDriver driver( store, coll_t(), make_snapmapper_oid()); spg_t pg; tmp.is_pg_prefix(pg); ObjectStore::Transaction t; SnapMapper mapper(&driver, 0, 0, 0, pg.shard); vector objects; store->collection_list(tmp, objects); // delete them. unsigned removed = 0; for (vector::iterator p = objects.begin(); p != objects.end(); ++p, removed++) { OSDriver::OSTransaction _t(driver.get_transaction(&t)); int r = mapper.remove_oid(p->hobj, &_t); if (r != 0 && r != -ENOENT) assert(0); t.collection_remove(tmp, *p); if (removed > 300) { int r = store->apply_transaction(t); assert(r == 0); t = ObjectStore::Transaction(); removed = 0; } } t.remove_collection(tmp); int r = store->apply_transaction(t); assert(r == 0); store->sync_and_flush(); } // ====================================================== // PG's PGPool OSD::_get_pool(int id, OSDMapRef createmap) { if (!createmap->have_pg_pool(id)) { dout(5) << __func__ << ": the OSDmap does not contain a PG pool with id = " << id << dendl; assert(0); } PGPool p = PGPool(id, createmap->get_pool_name(id), createmap->get_pg_pool(id)->auid); const pg_pool_t *pi = createmap->get_pg_pool(id); p.info = *pi; p.snapc = pi->get_snap_context(); pi->build_removed_snaps(p.cached_removed_snaps); dout(10) << "_get_pool " << p.id << dendl; return p; } PG *OSD::_open_lock_pg( OSDMapRef createmap, spg_t pgid, bool no_lockdep_check, bool hold_map_lock) { assert(osd_lock.is_locked()); PG* pg = _make_pg(createmap, pgid); pg_map[pgid] = pg; service.pg_add_epoch(pg->info.pgid, createmap->get_epoch()); pg->lock(no_lockdep_check); pg->get("PGMap"); // because it's in pg_map return pg; } PG* OSD::_make_pg( OSDMapRef createmap, spg_t pgid) { dout(10) << "_open_lock_pg " << pgid << dendl; PGPool pool = _get_pool(pgid.pool(), createmap); // create PG *pg; hobject_t logoid = make_pg_log_oid(pgid); hobject_t infooid = make_pg_biginfo_oid(pgid); if (createmap->get_pg_type(pgid.pgid) == pg_pool_t::TYPE_REPLICATED || createmap->get_pg_type(pgid.pgid) == pg_pool_t::TYPE_ERASURE) pg = new ReplicatedPG(&service, createmap, pool, pgid, logoid, infooid); else assert(0); return pg; } void OSD::add_newly_split_pg(PG *pg, PG::RecoveryCtx *rctx) { epoch_t e(service.get_osdmap()->get_epoch()); pg->get("PGMap"); // For pg_map pg_map[pg->info.pgid] = pg; service.pg_add_epoch(pg->info.pgid, pg->get_osdmap()->get_epoch()); dout(10) << "Adding newly split pg " << *pg << dendl; vector up, acting; pg->get_osdmap()->pg_to_up_acting_osds(pg->info.pgid.pgid, up, acting); int role = OSDMap::calc_pg_role(service.whoami, acting); pg->set_role(role); pg->reg_next_scrub(); pg->handle_loaded(rctx); pg->write_if_dirty(*(rctx->transaction)); pg->queue_null(e, e); map >::iterator to_wake = peering_wait_for_split.find(pg->info.pgid); if (to_wake != peering_wait_for_split.end()) { for (list::iterator i = to_wake->second.begin(); i != to_wake->second.end(); ++i) { pg->queue_peering_event(*i); } peering_wait_for_split.erase(to_wake); } wake_pg_waiters(pg->info.pgid); if (!service.get_osdmap()->have_pg_pool(pg->info.pgid.pool())) _remove_pg(pg); } OSD::res_result OSD::_try_resurrect_pg( OSDMapRef curmap, spg_t pgid, spg_t *resurrected, PGRef *old_pg_state) { assert(resurrected); assert(old_pg_state); // find nearest ancestor DeletingStateRef df; spg_t cur(pgid); while (true) { df = service.deleting_pgs.lookup(cur); if (df) break; if (!cur.ps()) break; cur = cur.get_parent(); } if (!df) return RES_NONE; // good to go df->old_pg_state->lock(); OSDMapRef create_map = df->old_pg_state->get_osdmap(); df->old_pg_state->unlock(); set children; if (cur == pgid) { if (df->try_stop_deletion()) { dout(10) << __func__ << ": halted deletion on pg " << pgid << dendl; *resurrected = cur; *old_pg_state = df->old_pg_state; service.deleting_pgs.remove(pgid); // PG is no longer being removed! return RES_SELF; } else { // raced, ensure we don't see DeletingStateRef when we try to // delete this pg service.deleting_pgs.remove(pgid); return RES_NONE; } } else if (cur.is_split(create_map->get_pg_num(cur.pool()), curmap->get_pg_num(cur.pool()), &children) && children.count(pgid)) { if (df->try_stop_deletion()) { dout(10) << __func__ << ": halted deletion on ancestor pg " << pgid << dendl; *resurrected = cur; *old_pg_state = df->old_pg_state; service.deleting_pgs.remove(cur); // PG is no longer being removed! return RES_PARENT; } else { /* this is not a problem, failing to cancel proves that all objects * have been removed, so no hobject_t overlap is possible */ return RES_NONE; } } return RES_NONE; } PG *OSD::_create_lock_pg( OSDMapRef createmap, spg_t pgid, bool newly_created, bool hold_map_lock, bool backfill, int role, vector& up, int up_primary, vector& acting, int acting_primary, pg_history_t history, pg_interval_map_t& pi, ObjectStore::Transaction& t) { assert(osd_lock.is_locked()); dout(20) << "_create_lock_pg pgid " << pgid << dendl; PG *pg = _open_lock_pg(createmap, pgid, true, hold_map_lock); service.init_splits_between(pgid, pg->get_osdmap(), service.get_osdmap()); pg->init( role, up, up_primary, acting, acting_primary, history, pi, backfill, &t); dout(7) << "_create_lock_pg " << *pg << dendl; return pg; } bool OSD::_have_pg(spg_t pgid) { assert(osd_lock.is_locked()); return pg_map.count(pgid); } PG *OSD::_lookup_lock_pg(spg_t pgid) { assert(osd_lock.is_locked()); if (!pg_map.count(pgid)) return NULL; PG *pg = pg_map[pgid]; pg->lock(); return pg; } PG *OSD::_lookup_pg(spg_t pgid) { assert(osd_lock.is_locked()); if (!pg_map.count(pgid)) return NULL; PG *pg = pg_map[pgid]; return pg; } PG *OSD::_lookup_lock_pg_with_map_lock_held(spg_t pgid) { assert(osd_lock.is_locked()); assert(pg_map.count(pgid)); PG *pg = pg_map[pgid]; pg->lock(); return pg; } void OSD::load_pgs() { assert(osd_lock.is_locked()); dout(0) << "load_pgs" << dendl; assert(pg_map.empty()); vector ls; int r = store->list_collections(ls); if (r < 0) { derr << "failed to list pgs: " << cpp_strerror(-r) << dendl; } set head_pgs; map > pgs; for (vector::iterator it = ls.begin(); it != ls.end(); ++it) { spg_t pgid; snapid_t snap; uint64_t seq; if (it->is_temp(pgid) || it->is_removal(&seq, &pgid)) { dout(10) << "load_pgs " << *it << " clearing temp" << dendl; recursive_remove_collection(store, *it); continue; } if (it->is_pg(pgid, snap)) { if (snap != CEPH_NOSNAP) { dout(10) << "load_pgs skipping snapped dir " << *it << " (pg " << pgid << " snap " << snap << ")" << dendl; pgs[pgid].insert(snap); } else { pgs[pgid]; head_pgs.insert(pgid); } continue; } dout(10) << "load_pgs ignoring unrecognized " << *it << dendl; } bool has_upgraded = false; for (map >::iterator i = pgs.begin(); i != pgs.end(); ++i) { spg_t pgid(i->first); if (!head_pgs.count(pgid)) { dout(10) << __func__ << ": " << pgid << " has orphan snap collections " << i->second << " with no head" << dendl; continue; } if (pgid.preferred() >= 0) { dout(10) << __func__ << ": skipping localized PG " << pgid << dendl; // FIXME: delete it too, eventually continue; } dout(10) << "pgid " << pgid << " coll " << coll_t(pgid) << dendl; bufferlist bl; epoch_t map_epoch = PG::peek_map_epoch(store, coll_t(pgid), service.infos_oid, &bl); PG *pg = NULL; if (map_epoch > 0) { OSDMapRef pgosdmap = service.try_get_map(map_epoch); if (!pgosdmap) { if (!osdmap->have_pg_pool(pgid.pool())) { derr << __func__ << ": could not find map for epoch " << map_epoch << " on pg " << pgid << ", but the pool is not present in the " << "current map, so this is probably a result of bug 10617. " << "Skipping the pg for now, you can use ceph_objectstore_tool " << "to clean it up later." << dendl; continue; } else { derr << __func__ << ": have pgid " << pgid << " at epoch " << map_epoch << ", but missing map. Crashing." << dendl; assert(0 == "Missing map in load_pgs"); } } pg = _open_lock_pg(pgosdmap, pgid); } else { pg = _open_lock_pg(osdmap, pgid); } // there can be no waiters here, so we don't call wake_pg_waiters // read pg state, log pg->read_state(store, bl); if (pg->must_upgrade()) { if (!has_upgraded) { derr << "PGs are upgrading" << dendl; has_upgraded = true; } dout(10) << "PG " << pg->info.pgid << " must upgrade..." << dendl; pg->upgrade(store, i->second); } else if (!i->second.empty()) { // handle upgrade bug for (interval_set::iterator j = i->second.begin(); j != i->second.end(); ++j) { for (snapid_t k = j.get_start(); k != j.get_start() + j.get_len(); ++k) { assert(store->collection_empty(coll_t(pgid, k))); ObjectStore::Transaction t; t.remove_collection(coll_t(pgid, k)); store->apply_transaction(t); } } } if (!pg->snap_collections.empty()) { pg->snap_collections.clear(); pg->dirty_big_info = true; pg->dirty_info = true; ObjectStore::Transaction t; pg->write_if_dirty(t); store->apply_transaction(t); } service.init_splits_between(pg->info.pgid, pg->get_osdmap(), osdmap); // generate state for PG's current mapping int primary, up_primary; vector acting, up; pg->get_osdmap()->pg_to_up_acting_osds( pgid.pgid, &up, &up_primary, &acting, &primary); pg->init_primary_up_acting( up, acting, up_primary, primary); int role = OSDMap::calc_pg_role(whoami, pg->acting); pg->set_role(role); pg->reg_next_scrub(); PG::RecoveryCtx rctx(0, 0, 0, 0, 0, 0); pg->handle_loaded(&rctx); dout(10) << "load_pgs loaded " << *pg << " " << pg->pg_log.get_log() << dendl; pg->unlock(); } dout(0) << "load_pgs opened " << pg_map.size() << " pgs" << dendl; build_past_intervals_parallel(); } /* * build past_intervals efficiently on old, degraded, and buried * clusters. this is important for efficiently catching up osds that * are way behind on maps to the current cluster state. * * this is a parallel version of PG::generate_past_intervals(). * follow the same logic, but do all pgs at the same time so that we * can make a single pass across the osdmap history. */ struct pistate { epoch_t start, end; vector old_acting, old_up; epoch_t same_interval_since; int primary; int up_primary; }; void OSD::build_past_intervals_parallel() { map pis; // calculate junction of map range epoch_t end_epoch = superblock.oldest_map; epoch_t cur_epoch = superblock.newest_map; for (ceph::unordered_map::iterator i = pg_map.begin(); i != pg_map.end(); ++i) { PG *pg = i->second; epoch_t start, end; if (!pg->_calc_past_interval_range(&start, &end, superblock.oldest_map)) continue; dout(10) << pg->info.pgid << " needs " << start << "-" << end << dendl; pistate& p = pis[pg]; p.start = start; p.end = end; p.same_interval_since = 0; if (start < cur_epoch) cur_epoch = start; if (end > end_epoch) end_epoch = end; } if (pis.empty()) { dout(10) << __func__ << " nothing to build" << dendl; return; } dout(1) << __func__ << " over " << cur_epoch << "-" << end_epoch << dendl; assert(cur_epoch <= end_epoch); OSDMapRef cur_map, last_map; for ( ; cur_epoch <= end_epoch; cur_epoch++) { dout(10) << __func__ << " epoch " << cur_epoch << dendl; last_map = cur_map; cur_map = get_map(cur_epoch); for (map::iterator i = pis.begin(); i != pis.end(); ++i) { PG *pg = i->first; pistate& p = i->second; if (cur_epoch < p.start || cur_epoch > p.end) continue; vector acting, up; int up_primary; int primary; pg_t pgid = pg->info.pgid.pgid; if (p.same_interval_since && last_map->get_pools().count(pgid.pool())) pgid = pgid.get_ancestor(last_map->get_pg_num(pgid.pool())); cur_map->pg_to_up_acting_osds( pgid, &up, &up_primary, &acting, &primary); if (p.same_interval_since == 0) { dout(10) << __func__ << " epoch " << cur_epoch << " pg " << pg->info.pgid << " first map, acting " << acting << " up " << up << ", same_interval_since = " << cur_epoch << dendl; p.same_interval_since = cur_epoch; p.old_up = up; p.old_acting = acting; p.primary = primary; p.up_primary = up_primary; continue; } assert(last_map); std::stringstream debug; bool new_interval = pg_interval_t::check_new_interval( p.primary, primary, p.old_acting, acting, p.up_primary, up_primary, p.old_up, up, p.same_interval_since, pg->info.history.last_epoch_clean, cur_map, last_map, pg->info.pgid.pool(), pgid, &pg->past_intervals, &debug); if (new_interval) { dout(10) << __func__ << " epoch " << cur_epoch << " pg " << pg->info.pgid << " " << debug.str() << dendl; p.old_up = up; p.old_acting = acting; p.same_interval_since = cur_epoch; } } } // write info only at the end. this is necessary because we check // whether the past_intervals go far enough back or forward in time, // but we don't check for holes. we could avoid it by discarding // the previous past_intervals and rebuilding from scratch, or we // can just do this and commit all our work at the end. ObjectStore::Transaction t; int num = 0; for (map::iterator i = pis.begin(); i != pis.end(); ++i) { PG *pg = i->first; pg->lock(); pg->dirty_big_info = true; pg->dirty_info = true; pg->write_if_dirty(t); pg->unlock(); // don't let the transaction get too big if (++num >= cct->_conf->osd_target_transaction_size) { store->apply_transaction(t); t = ObjectStore::Transaction(); num = 0; } } if (!t.empty()) store->apply_transaction(t); } /* * look up a pg. if we have it, great. if not, consider creating it IF the pg mapping * hasn't changed since the given epoch and we are the primary. */ void OSD::handle_pg_peering_evt( spg_t pgid, const pg_info_t& info, pg_interval_map_t& pi, epoch_t epoch, pg_shard_t from, bool primary, PG::CephPeeringEvtRef evt) { if (service.splitting(pgid)) { peering_wait_for_split[pgid].push_back(evt); return; } if (!_have_pg(pgid)) { // same primary? if (!osdmap->have_pg_pool(pgid.pool())) return; int up_primary, acting_primary; vector up, acting; osdmap->pg_to_up_acting_osds( pgid.pgid, &up, &up_primary, &acting, &acting_primary); int role = osdmap->calc_pg_role(whoami, acting, acting.size()); pg_history_t history = info.history; bool valid_history = project_pg_history( pgid, history, epoch, up, up_primary, acting, acting_primary); if (!valid_history || epoch < history.same_interval_since) { dout(10) << "get_or_create_pg " << pgid << " acting changed in " << history.same_interval_since << " (msg from " << epoch << ")" << dendl; return; } if (service.splitting(pgid)) { assert(0); } bool create = false; if (primary) { // DNE on source? if (info.dne()) { // is there a creation pending on this pg? if (creating_pgs.count(pgid)) { creating_pgs[pgid].prior.erase(from); if (!can_create_pg(pgid)) return; history = creating_pgs[pgid].history; create = true; } else { dout(10) << "get_or_create_pg " << pgid << " DNE on source, but creation probe, ignoring" << dendl; return; } } creating_pgs.erase(pgid); } else { assert(!info.dne()); // pg exists if we are hearing about it } // do we need to resurrect a deleting pg? spg_t resurrected; PGRef old_pg_state; res_result result = _try_resurrect_pg( service.get_osdmap(), pgid, &resurrected, &old_pg_state); PG::RecoveryCtx rctx = create_context(); switch (result) { case RES_NONE: { // ok, create the pg locally using provided Info and History rctx.transaction->create_collection(coll_t(pgid)); PG *pg = _create_lock_pg( get_map(epoch), pgid, create, false, result == RES_SELF, role, up, up_primary, acting, acting_primary, history, pi, *rctx.transaction); pg->handle_create(&rctx); pg->write_if_dirty(*rctx.transaction); dispatch_context(rctx, pg, osdmap); dout(10) << *pg << " is new" << dendl; // kick any waiters wake_pg_waiters(pg->info.pgid); pg->queue_peering_event(evt); pg->unlock(); return; } case RES_SELF: { old_pg_state->lock(); PG *pg = _create_lock_pg( old_pg_state->get_osdmap(), resurrected, false, false, true, old_pg_state->role, old_pg_state->up, old_pg_state->up_primary.osd, old_pg_state->acting, old_pg_state->primary.osd, old_pg_state->info.history, old_pg_state->past_intervals, *rctx.transaction); old_pg_state->unlock(); pg->handle_create(&rctx); pg->write_if_dirty(*rctx.transaction); dispatch_context(rctx, pg, osdmap); dout(10) << *pg << " is new (resurrected)" << dendl; // kick any waiters wake_pg_waiters(pg->info.pgid); pg->queue_peering_event(evt); pg->unlock(); return; } case RES_PARENT: { assert(old_pg_state); old_pg_state->lock(); PG *parent = _create_lock_pg( old_pg_state->get_osdmap(), resurrected, false, false, true, old_pg_state->role, old_pg_state->up, old_pg_state->up_primary.osd, old_pg_state->acting, old_pg_state->primary.osd, old_pg_state->info.history, old_pg_state->past_intervals, *rctx.transaction ); old_pg_state->unlock(); parent->handle_create(&rctx); parent->write_if_dirty(*rctx.transaction); dispatch_context(rctx, parent, osdmap); dout(10) << *parent << " is new" << dendl; // kick any waiters wake_pg_waiters(parent->info.pgid); assert(service.splitting(pgid)); peering_wait_for_split[pgid].push_back(evt); //parent->queue_peering_event(evt); parent->queue_null(osdmap->get_epoch(), osdmap->get_epoch()); parent->unlock(); return; } } } else { // already had it. did the mapping change? PG *pg = _lookup_lock_pg(pgid); if (epoch < pg->info.history.same_interval_since) { dout(10) << *pg << " get_or_create_pg acting changed in " << pg->info.history.same_interval_since << " (msg from " << epoch << ")" << dendl; pg->unlock(); return; } pg->queue_peering_event(evt); pg->unlock(); return; } } /* * calculate prior pg members during an epoch interval [start,end) * - from each epoch, include all osds up then AND now * - if no osds from then are up now, include them all, even tho they're not reachable now */ void OSD::calc_priors_during( spg_t pgid, epoch_t start, epoch_t end, set& pset) { dout(15) << "calc_priors_during " << pgid << " [" << start << "," << end << ")" << dendl; for (epoch_t e = start; e < end; e++) { OSDMapRef oldmap = get_map(e); vector acting; oldmap->pg_to_acting_osds(pgid.pgid, acting); dout(20) << " " << pgid << " in epoch " << e << " was " << acting << dendl; int up = 0; int actual_osds = 0; for (unsigned i=0; iis_up(acting[i])) { if (acting[i] != whoami) { pset.insert( pg_shard_t( acting[i], osdmap->pg_is_ec(pgid.pgid) ? shard_id_t(i) : ghobject_t::NO_SHARD)); } up++; } actual_osds++; } } if (!up && actual_osds) { // sucky. add down osds, even tho we can't reach them right now. for (unsigned i=0; ipg_is_ec(pgid.pgid) ? i : ghobject_t::NO_SHARD)); } } } } dout(10) << "calc_priors_during " << pgid << " [" << start << "," << end << ") = " << pset << dendl; } /** * Fill in the passed history so you know same_interval_since, same_up_since, * and same_primary_since. */ bool OSD::project_pg_history(spg_t pgid, pg_history_t& h, epoch_t from, const vector& currentup, int currentupprimary, const vector& currentacting, int currentactingprimary) { dout(15) << "project_pg_history " << pgid << " from " << from << " to " << osdmap->get_epoch() << ", start " << h << dendl; epoch_t e; for (e = osdmap->get_epoch(); e > from; e--) { // verify during intermediate epoch (e-1) OSDMapRef oldmap = service.try_get_map(e-1); if (!oldmap) { dout(15) << __func__ << ": found map gap, returning false" << dendl; return false; } assert(oldmap->have_pg_pool(pgid.pool())); int upprimary, actingprimary; vector up, acting; oldmap->pg_to_up_acting_osds( pgid.pgid, &up, &upprimary, &acting, &actingprimary); // acting set change? if ((actingprimary != currentactingprimary || upprimary != currentupprimary || acting != currentacting || up != currentup) && e > h.same_interval_since) { dout(15) << "project_pg_history " << pgid << " acting|up changed in " << e << " from " << acting << "/" << up << " " << actingprimary << "/" << upprimary << " -> " << currentacting << "/" << currentup << " " << currentactingprimary << "/" << currentupprimary << dendl; h.same_interval_since = e; } // split? if (pgid.is_split(oldmap->get_pg_num(pgid.pool()), osdmap->get_pg_num(pgid.pool()), 0)) { h.same_interval_since = e; } // up set change? if ((up != currentup || upprimary != currentupprimary) && e > h.same_up_since) { dout(15) << "project_pg_history " << pgid << " up changed in " << e << " from " << up << " " << upprimary << " -> " << currentup << " " << currentupprimary << dendl; h.same_up_since = e; } // primary change? if (OSDMap::primary_changed( actingprimary, acting, currentactingprimary, currentacting) && e > h.same_primary_since) { dout(15) << "project_pg_history " << pgid << " primary changed in " << e << dendl; h.same_primary_since = e; } if (h.same_interval_since >= e && h.same_up_since >= e && h.same_primary_since >= e) break; } // base case: these floors should be the creation epoch if we didn't // find any changes. if (e == h.epoch_created) { if (!h.same_interval_since) h.same_interval_since = e; if (!h.same_up_since) h.same_up_since = e; if (!h.same_primary_since) h.same_primary_since = e; } dout(15) << "project_pg_history end " << h << dendl; return true; } // ------------------------------------- float OSDService::get_full_ratio() { float full_ratio = cct->_conf->osd_failsafe_full_ratio; if (full_ratio > 1.0) full_ratio /= 100.0; return full_ratio; } float OSDService::get_nearfull_ratio() { float nearfull_ratio = cct->_conf->osd_failsafe_nearfull_ratio; if (nearfull_ratio > 1.0) nearfull_ratio /= 100.0; return nearfull_ratio; } void OSDService::check_nearfull_warning(const osd_stat_t &osd_stat) { Mutex::Locker l(full_status_lock); enum s_names new_state; time_t now = ceph_clock_gettime(NULL); // We base ratio on kb_avail rather than kb_used because they can // differ significantly e.g. on btrfs volumes with a large number of // chunks reserved for metadata, and for our purposes (avoiding // completely filling the disk) it's far more important to know how // much space is available to use than how much we've already used. float ratio = ((float)(osd_stat.kb - osd_stat.kb_avail)) / ((float)osd_stat.kb); float nearfull_ratio = get_nearfull_ratio(); float full_ratio = get_full_ratio(); cur_ratio = ratio; if (full_ratio > 0 && ratio > full_ratio) { new_state = FULL; } else if (nearfull_ratio > 0 && ratio > nearfull_ratio) { new_state = NEAR; } else { cur_state = NONE; return; } if (cur_state != new_state) { cur_state = new_state; } else if (now - last_msg < cct->_conf->osd_op_complaint_time) { return; } last_msg = now; if (cur_state == FULL) clog.error() << "OSD full dropping all updates " << (int)(ratio * 100) << "% full"; else clog.warn() << "OSD near full (" << (int)(ratio * 100) << "%)"; } bool OSDService::check_failsafe_full() { Mutex::Locker l(full_status_lock); if (cur_state == FULL) return true; return false; } bool OSDService::too_full_for_backfill(double *_ratio, double *_max_ratio) { Mutex::Locker l(full_status_lock); double max_ratio; max_ratio = cct->_conf->osd_backfill_full_ratio; if (_ratio) *_ratio = cur_ratio; if (_max_ratio) *_max_ratio = max_ratio; return cur_ratio >= max_ratio; } void OSD::update_osd_stat() { // fill in osd stats too struct statfs stbuf; store->statfs(&stbuf); uint64_t bytes = stbuf.f_blocks * stbuf.f_bsize; uint64_t used = (stbuf.f_blocks - stbuf.f_bfree) * stbuf.f_bsize; uint64_t avail = stbuf.f_bavail * stbuf.f_bsize; osd_stat.kb = bytes >> 10; osd_stat.kb_used = used >> 10; osd_stat.kb_avail = avail >> 10; logger->set(l_osd_stat_bytes, bytes); logger->set(l_osd_stat_bytes_used, used); logger->set(l_osd_stat_bytes_avail, avail); osd_stat.hb_in.clear(); for (map::iterator p = heartbeat_peers.begin(); p != heartbeat_peers.end(); ++p) osd_stat.hb_in.push_back(p->first); osd_stat.hb_out.clear(); service.check_nearfull_warning(osd_stat); op_tracker.get_age_ms_histogram(&osd_stat.op_queue_age_hist); dout(20) << "update_osd_stat " << osd_stat << dendl; } void OSD::_add_heartbeat_peer(int p) { if (p == whoami) return; HeartbeatInfo *hi; map::iterator i = heartbeat_peers.find(p); if (i == heartbeat_peers.end()) { pair cons = service.get_con_osd_hb(p, osdmap->get_epoch()); if (!cons.first) return; hi = &heartbeat_peers[p]; hi->peer = p; HeartbeatSession *s = new HeartbeatSession(p); hi->con_back = cons.first.get(); hi->con_back->set_priv(s); if (cons.second) { hi->con_front = cons.second.get(); hi->con_front->set_priv(s->get()); dout(10) << "_add_heartbeat_peer: new peer osd." << p << " " << hi->con_back->get_peer_addr() << " " << hi->con_front->get_peer_addr() << dendl; } else { hi->con_front.reset(NULL); dout(10) << "_add_heartbeat_peer: new peer osd." << p << " " << hi->con_back->get_peer_addr() << dendl; } } else { hi = &i->second; } hi->epoch = osdmap->get_epoch(); } void OSD::_remove_heartbeat_peer(int n) { map::iterator q = heartbeat_peers.find(n); assert(q != heartbeat_peers.end()); dout(20) << " removing heartbeat peer osd." << n << " " << q->second.con_back->get_peer_addr() << " " << (q->second.con_front ? q->second.con_front->get_peer_addr() : entity_addr_t()) << dendl; hbclient_messenger->mark_down(q->second.con_back); if (q->second.con_front) { hbclient_messenger->mark_down(q->second.con_front); } heartbeat_peers.erase(q); } void OSD::need_heartbeat_peer_update() { Mutex::Locker l(heartbeat_lock); if (is_stopping()) return; dout(20) << "need_heartbeat_peer_update" << dendl; heartbeat_need_update = true; } void OSD::maybe_update_heartbeat_peers() { assert(osd_lock.is_locked()); if (is_waiting_for_healthy()) { utime_t now = ceph_clock_now(cct); if (last_heartbeat_resample == utime_t()) { last_heartbeat_resample = now; heartbeat_need_update = true; } else if (!heartbeat_need_update) { utime_t dur = now - last_heartbeat_resample; if (dur > cct->_conf->osd_heartbeat_grace) { dout(10) << "maybe_update_heartbeat_peers forcing update after " << dur << " seconds" << dendl; heartbeat_need_update = true; last_heartbeat_resample = now; reset_heartbeat_peers(); // we want *new* peers! } } } Mutex::Locker l(heartbeat_lock); if (!heartbeat_need_update) return; heartbeat_need_update = false; dout(10) << "maybe_update_heartbeat_peers updating" << dendl; heartbeat_epoch = osdmap->get_epoch(); // build heartbeat from set if (is_active()) { for (ceph::unordered_map::iterator i = pg_map.begin(); i != pg_map.end(); ++i) { PG *pg = i->second; pg->heartbeat_peer_lock.Lock(); dout(20) << i->first << " heartbeat_peers " << pg->heartbeat_peers << dendl; for (set::iterator p = pg->heartbeat_peers.begin(); p != pg->heartbeat_peers.end(); ++p) if (osdmap->is_up(*p)) _add_heartbeat_peer(*p); for (set::iterator p = pg->probe_targets.begin(); p != pg->probe_targets.end(); ++p) if (osdmap->is_up(*p)) _add_heartbeat_peer(*p); pg->heartbeat_peer_lock.Unlock(); } } // include next and previous up osds to ensure we have a fully-connected set set want, extras; int next = osdmap->get_next_up_osd_after(whoami); if (next >= 0) want.insert(next); int prev = osdmap->get_previous_up_osd_before(whoami); if (prev >= 0) want.insert(prev); for (set::iterator p = want.begin(); p != want.end(); ++p) { dout(10) << " adding neighbor peer osd." << *p << dendl; extras.insert(*p); _add_heartbeat_peer(*p); } // remove down peers; enumerate extras map::iterator p = heartbeat_peers.begin(); while (p != heartbeat_peers.end()) { if (!osdmap->is_up(p->first)) { int o = p->first; ++p; _remove_heartbeat_peer(o); continue; } if (p->second.epoch < osdmap->get_epoch()) { extras.insert(p->first); } ++p; } // too few? int start = osdmap->get_next_up_osd_after(whoami); for (int n = start; n >= 0; ) { if ((int)heartbeat_peers.size() >= cct->_conf->osd_heartbeat_min_peers) break; if (!extras.count(n) && !want.count(n) && n != whoami) { dout(10) << " adding random peer osd." << n << dendl; extras.insert(n); _add_heartbeat_peer(n); } n = osdmap->get_next_up_osd_after(n); if (n == start) break; // came full circle; stop } // too many? for (set::iterator p = extras.begin(); (int)heartbeat_peers.size() > cct->_conf->osd_heartbeat_min_peers && p != extras.end(); ++p) { if (want.count(*p)) continue; _remove_heartbeat_peer(*p); } dout(10) << "maybe_update_heartbeat_peers " << heartbeat_peers.size() << " peers, extras " << extras << dendl; } void OSD::reset_heartbeat_peers() { assert(osd_lock.is_locked()); dout(10) << "reset_heartbeat_peers" << dendl; Mutex::Locker l(heartbeat_lock); while (!heartbeat_peers.empty()) { HeartbeatInfo& hi = heartbeat_peers.begin()->second; hbclient_messenger->mark_down(hi.con_back); if (hi.con_front) { hbclient_messenger->mark_down(hi.con_front); } heartbeat_peers.erase(heartbeat_peers.begin()); } failure_queue.clear(); } void OSD::handle_osd_ping(MOSDPing *m) { if (superblock.cluster_fsid != m->fsid) { dout(20) << "handle_osd_ping from " << m->get_source_inst() << " bad fsid " << m->fsid << " != " << superblock.cluster_fsid << dendl; m->put(); return; } int from = m->get_source().num(); heartbeat_lock.Lock(); if (is_stopping()) { heartbeat_lock.Unlock(); m->put(); return; } OSDMapRef curmap = service.get_osdmap(); switch (m->op) { case MOSDPing::PING: { if (cct->_conf->osd_debug_drop_ping_probability > 0) { if (debug_heartbeat_drops_remaining.count(from)) { if (debug_heartbeat_drops_remaining[from] == 0) { debug_heartbeat_drops_remaining.erase(from); } else { debug_heartbeat_drops_remaining[from]--; dout(5) << "Dropping heartbeat from " << from << ", " << debug_heartbeat_drops_remaining[from] << " remaining to drop" << dendl; break; } } else if (cct->_conf->osd_debug_drop_ping_probability > ((((double)(rand()%100))/100.0))) { debug_heartbeat_drops_remaining[from] = cct->_conf->osd_debug_drop_ping_duration; dout(5) << "Dropping heartbeat from " << from << ", " << debug_heartbeat_drops_remaining[from] << " remaining to drop" << dendl; break; } } if (!cct->get_heartbeat_map()->is_healthy()) { dout(10) << "internal heartbeat not healthy, dropping ping request" << dendl; break; } Message *r = new MOSDPing(monc->get_fsid(), curmap->get_epoch(), MOSDPing::PING_REPLY, m->stamp); m->get_connection()->get_messenger()->send_message(r, m->get_connection()); if (curmap->is_up(from)) { note_peer_epoch(from, m->map_epoch); if (is_active()) { ConnectionRef con = service.get_con_osd_cluster(from, curmap->get_epoch()); if (con) { _share_map_outgoing(from, con.get()); } } } else if (!curmap->exists(from) || curmap->get_down_at(from) > m->map_epoch) { // tell them they have died Message *r = new MOSDPing(monc->get_fsid(), curmap->get_epoch(), MOSDPing::YOU_DIED, m->stamp); m->get_connection()->get_messenger()->send_message(r, m->get_connection()); } } break; case MOSDPing::PING_REPLY: { map::iterator i = heartbeat_peers.find(from); if (i != heartbeat_peers.end()) { if (m->get_connection() == i->second.con_back) { dout(25) << "handle_osd_ping got reply from osd." << from << " first_rx " << i->second.first_tx << " last_tx " << i->second.last_tx << " last_rx_back " << i->second.last_rx_back << " -> " << m->stamp << " last_rx_front " << i->second.last_rx_front << dendl; i->second.last_rx_back = m->stamp; // if there is no front con, set both stamps. if (i->second.con_front == NULL) i->second.last_rx_front = m->stamp; } else if (m->get_connection() == i->second.con_front) { dout(25) << "handle_osd_ping got reply from osd." << from << " first_rx " << i->second.first_tx << " last_tx " << i->second.last_tx << " last_rx_back " << i->second.last_rx_back << " last_rx_front " << i->second.last_rx_front << " -> " << m->stamp << dendl; i->second.last_rx_front = m->stamp; } } if (m->map_epoch && curmap->is_up(from)) { note_peer_epoch(from, m->map_epoch); if (is_active()) { ConnectionRef con = service.get_con_osd_cluster(from, curmap->get_epoch()); if (con) { _share_map_outgoing(from, con.get()); } } } utime_t cutoff = ceph_clock_now(cct); cutoff -= cct->_conf->osd_heartbeat_grace; if (i->second.is_healthy(cutoff)) { // Cancel false reports if (failure_queue.count(from)) { dout(10) << "handle_osd_ping canceling queued failure report for osd." << from<< dendl; failure_queue.erase(from); } if (failure_pending.count(from)) { dout(10) << "handle_osd_ping canceling in-flight failure report for osd." << from<< dendl; send_still_alive(curmap->get_epoch(), failure_pending[from]); failure_pending.erase(from); } } } break; case MOSDPing::YOU_DIED: dout(10) << "handle_osd_ping " << m->get_source_inst() << " says i am down in " << m->map_epoch << dendl; osdmap_subscribe(curmap->get_epoch()+1, false); break; } heartbeat_lock.Unlock(); m->put(); } void OSD::heartbeat_entry() { Mutex::Locker l(heartbeat_lock); if (is_stopping()) return; while (!heartbeat_stop) { heartbeat(); double wait = .5 + ((float)(rand() % 10)/10.0) * (float)cct->_conf->osd_heartbeat_interval; utime_t w; w.set_from_double(wait); dout(30) << "heartbeat_entry sleeping for " << wait << dendl; heartbeat_cond.WaitInterval(cct, heartbeat_lock, w); if (is_stopping()) return; dout(30) << "heartbeat_entry woke up" << dendl; } } void OSD::heartbeat_check() { assert(heartbeat_lock.is_locked()); utime_t now = ceph_clock_now(cct); double age = hbclient_messenger->get_dispatch_queue_max_age(now); if (age > (cct->_conf->osd_heartbeat_grace / 2)) { derr << "skipping heartbeat_check, hbqueue max age: " << age << dendl; return; // hb dispatch is too backed up for our hb status to be meaningful } // check for incoming heartbeats (move me elsewhere?) utime_t cutoff = now; cutoff -= cct->_conf->osd_heartbeat_grace; for (map::iterator p = heartbeat_peers.begin(); p != heartbeat_peers.end(); ++p) { dout(25) << "heartbeat_check osd." << p->first << " first_tx " << p->second.first_tx << " last_tx " << p->second.last_tx << " last_rx_back " << p->second.last_rx_back << " last_rx_front " << p->second.last_rx_front << dendl; if (p->second.is_unhealthy(cutoff)) { if (p->second.last_rx_back == utime_t() || p->second.last_rx_front == utime_t()) { derr << "heartbeat_check: no reply from osd." << p->first << " ever on either front or back, first ping sent " << p->second.first_tx << " (cutoff " << cutoff << ")" << dendl; // fail failure_queue[p->first] = p->second.last_tx; } else { derr << "heartbeat_check: no reply from osd." << p->first << " since back " << p->second.last_rx_back << " front " << p->second.last_rx_front << " (cutoff " << cutoff << ")" << dendl; // fail failure_queue[p->first] = MIN(p->second.last_rx_back, p->second.last_rx_front); } } } } void OSD::heartbeat() { dout(30) << "heartbeat" << dendl; // get CPU load avg double loadavgs[1]; if (getloadavg(loadavgs, 1) == 1) logger->set(l_osd_loadavg, 100 * loadavgs[0]); dout(30) << "heartbeat checking stats" << dendl; // refresh stats? { Mutex::Locker lock(stat_lock); update_osd_stat(); } dout(5) << "heartbeat: " << osd_stat << dendl; utime_t now = ceph_clock_now(cct); // send heartbeats for (map::iterator i = heartbeat_peers.begin(); i != heartbeat_peers.end(); ++i) { int peer = i->first; i->second.last_tx = now; if (i->second.first_tx == utime_t()) i->second.first_tx = now; dout(30) << "heartbeat sending ping to osd." << peer << dendl; hbclient_messenger->send_message(new MOSDPing(monc->get_fsid(), service.get_osdmap()->get_epoch(), MOSDPing::PING, now), i->second.con_back); if (i->second.con_front) hbclient_messenger->send_message(new MOSDPing(monc->get_fsid(), service.get_osdmap()->get_epoch(), MOSDPing::PING, now), i->second.con_front); } dout(30) << "heartbeat check" << dendl; heartbeat_check(); logger->set(l_osd_hb_to, heartbeat_peers.size()); logger->set(l_osd_hb_from, 0); // hmm.. am i all alone? dout(30) << "heartbeat lonely?" << dendl; if (heartbeat_peers.empty()) { if (now - last_mon_heartbeat > cct->_conf->osd_mon_heartbeat_interval && is_active()) { last_mon_heartbeat = now; dout(10) << "i have no heartbeat peers; checking mon for new map" << dendl; osdmap_subscribe(osdmap->get_epoch() + 1, true); } } dout(30) << "heartbeat done" << dendl; } bool OSD::heartbeat_reset(Connection *con) { HeartbeatSession *s = static_cast(con->get_priv()); if (s) { heartbeat_lock.Lock(); if (is_stopping()) { heartbeat_lock.Unlock(); s->put(); return true; } map::iterator p = heartbeat_peers.find(s->peer); if (p != heartbeat_peers.end() && (p->second.con_back == con || p->second.con_front == con)) { dout(10) << "heartbeat_reset failed hb con " << con << " for osd." << p->second.peer << ", reopening" << dendl; if (con != p->second.con_back) { hbclient_messenger->mark_down(p->second.con_back); } p->second.con_back.reset(NULL); if (p->second.con_front && con != p->second.con_front) { hbclient_messenger->mark_down(p->second.con_front); } p->second.con_front.reset(NULL); pair newcon = service.get_con_osd_hb(p->second.peer, p->second.epoch); if (newcon.first) { p->second.con_back = newcon.first.get(); p->second.con_back->set_priv(s->get()); if (newcon.second) { p->second.con_front = newcon.second.get(); p->second.con_front->set_priv(s->get()); } } else { dout(10) << "heartbeat_reset failed hb con " << con << " for osd." << p->second.peer << ", raced with osdmap update, closing out peer" << dendl; heartbeat_peers.erase(p); } } else { dout(10) << "heartbeat_reset closing (old) failed hb con " << con << dendl; } heartbeat_lock.Unlock(); s->put(); } return true; } // ========================================= void OSD::tick() { assert(osd_lock.is_locked()); dout(5) << "tick" << dendl; logger->set(l_osd_buf, buffer::get_total_alloc()); if (is_active() || is_waiting_for_healthy()) { map_lock.get_read(); maybe_update_heartbeat_peers(); heartbeat_lock.Lock(); heartbeat_check(); heartbeat_lock.Unlock(); // mon report? utime_t now = ceph_clock_now(cct); if (outstanding_pg_stats && timeout_mon_on_pg_stats && (now - cct->_conf->osd_mon_ack_timeout) > last_pg_stats_ack) { dout(1) << "mon hasn't acked PGStats in " << now - last_pg_stats_ack << " seconds, reconnecting elsewhere" << dendl; monc->reopen_session(new C_MonStatsAckTimer(this)); timeout_mon_on_pg_stats = false; last_pg_stats_ack = ceph_clock_now(cct); // reset clock last_pg_stats_sent = utime_t(); } if (now - last_pg_stats_sent > cct->_conf->osd_mon_report_interval_max) { osd_stat_updated = true; do_mon_report(); } else if (now - last_mon_report > cct->_conf->osd_mon_report_interval_min) { do_mon_report(); } map_lock.put_read(); } if (is_waiting_for_healthy()) { if (_is_healthy()) { dout(1) << "healthy again, booting" << dendl; state = STATE_BOOTING; start_boot(); } } if (is_active()) { // periodically kick recovery work queue recovery_tp.wake(); if (!scrub_random_backoff()) { sched_scrub(); } check_replay_queue(); } // only do waiters if dispatch() isn't currently running. (if it is, // it'll do the waiters, and doing them here may screw up ordering // of op_queue vs handle_osd_map.) if (!dispatch_running) { dispatch_running = true; do_waiters(); dispatch_running = false; dispatch_cond.Signal(); } check_ops_in_flight(); tick_timer.add_event_after(1.0, new C_Tick(this)); } void OSD::check_ops_in_flight() { vector warnings; if (op_tracker.check_ops_in_flight(warnings)) { for (vector::iterator i = warnings.begin(); i != warnings.end(); ++i) { clog.warn() << *i; } } return; } // Usage: // setomapval [namespace/] // rmomapkey [namespace/] // setomapheader [namespace/]
// getomap [namespace/] // truncobj [namespace/] // injectmdataerr [namespace/] // injectdataerr [namespace/] void TestOpsSocketHook::test_ops(OSDService *service, ObjectStore *store, std::string command, cmdmap_t& cmdmap, ostream &ss) { //Test support //Support changing the omap on a single osd by using the Admin Socket to //directly request the osd make a change. if (command == "setomapval" || command == "rmomapkey" || command == "setomapheader" || command == "getomap" || command == "truncobj" || command == "injectmdataerr" || command == "injectdataerr" ) { pg_t rawpg; int64_t pool; OSDMapRef curmap = service->get_osdmap(); int r; string poolstr; cmd_getval(service->cct, cmdmap, "pool", poolstr); pool = curmap->const_lookup_pg_pool_name(poolstr.c_str()); //If we can't find it by name then maybe id specified if (pool < 0 && isdigit(poolstr[0])) pool = atoll(poolstr.c_str()); if (pool < 0) { ss << "Invalid pool" << poolstr; return; } r = -1; string objname, nspace; cmd_getval(service->cct, cmdmap, "objname", objname); std::size_t found = objname.find_first_of('/'); if (found != string::npos) { nspace = objname.substr(0, found); objname = objname.substr(found+1); } object_locator_t oloc(pool, nspace); r = curmap->object_locator_to_pg(object_t(objname), oloc, rawpg); if (r < 0) { ss << "Invalid namespace/objname"; return; } if (curmap->pg_is_ec(rawpg)) { ss << "Must not call on ec pool"; return; } spg_t pgid = spg_t(curmap->raw_pg_to_pg(rawpg), ghobject_t::no_shard()); hobject_t obj(object_t(objname), string(""), CEPH_NOSNAP, rawpg.ps(), pool, nspace); ObjectStore::Transaction t; if (command == "setomapval") { map newattrs; bufferlist val; string key, valstr; cmd_getval(service->cct, cmdmap, "key", key); cmd_getval(service->cct, cmdmap, "val", valstr); val.append(valstr); newattrs[key] = val; t.omap_setkeys(coll_t(pgid), obj, newattrs); r = store->apply_transaction(t); if (r < 0) ss << "error=" << r; else ss << "ok"; } else if (command == "rmomapkey") { string key; set keys; cmd_getval(service->cct, cmdmap, "key", key); keys.insert(key); t.omap_rmkeys(coll_t(pgid), obj, keys); r = store->apply_transaction(t); if (r < 0) ss << "error=" << r; else ss << "ok"; } else if (command == "setomapheader") { bufferlist newheader; string headerstr; cmd_getval(service->cct, cmdmap, "header", headerstr); newheader.append(headerstr); t.omap_setheader(coll_t(pgid), obj, newheader); r = store->apply_transaction(t); if (r < 0) ss << "error=" << r; else ss << "ok"; } else if (command == "getomap") { //Debug: Output entire omap bufferlist hdrbl; map keyvals; r = store->omap_get(coll_t(pgid), obj, &hdrbl, &keyvals); if (r >= 0) { ss << "header=" << string(hdrbl.c_str(), hdrbl.length()); for (map::iterator it = keyvals.begin(); it != keyvals.end(); ++it) ss << " key=" << (*it).first << " val=" << string((*it).second.c_str(), (*it).second.length()); } else { ss << "error=" << r; } } else if (command == "truncobj") { int64_t trunclen; cmd_getval(service->cct, cmdmap, "len", trunclen); t.truncate(coll_t(pgid), obj, trunclen); r = store->apply_transaction(t); if (r < 0) ss << "error=" << r; else ss << "ok"; } else if (command == "injectdataerr") { store->inject_data_error(obj); ss << "ok"; } else if (command == "injectmdataerr") { store->inject_mdata_error(obj); ss << "ok"; } return; } ss << "Internal error - command=" << command; return; } // ========================================= bool remove_dir( CephContext *cct, ObjectStore *store, SnapMapper *mapper, OSDriver *osdriver, ObjectStore::Sequencer *osr, coll_t coll, DeletingStateRef dstate, ThreadPool::TPHandle &handle) { vector olist; int64_t num = 0; ObjectStore::Transaction *t = new ObjectStore::Transaction; ghobject_t next; while (!next.is_max()) { handle.reset_tp_timeout(); store->collection_list_partial( coll, next, store->get_ideal_list_min(), store->get_ideal_list_max(), 0, &olist, &next); for (vector::iterator i = olist.begin(); i != olist.end(); ++i, ++num) { OSDriver::OSTransaction _t(osdriver->get_transaction(t)); int r = mapper->remove_oid(i->hobj, &_t); if (r != 0 && r != -ENOENT) { assert(0); } t->remove(coll, *i); if (num >= cct->_conf->osd_target_transaction_size) { C_SaferCond waiter; store->queue_transaction(osr, t, &waiter); bool cont = dstate->pause_clearing(); handle.suspend_tp_timeout(); waiter.wait(); handle.reset_tp_timeout(); if (cont) cont = dstate->resume_clearing(); delete t; if (!cont) return false; t = new ObjectStore::Transaction; num = 0; } } olist.clear(); } C_SaferCond waiter; store->queue_transaction(osr, t, &waiter); bool cont = dstate->pause_clearing(); handle.suspend_tp_timeout(); waiter.wait(); handle.reset_tp_timeout(); if (cont) cont = dstate->resume_clearing(); delete t; return cont; } void OSD::RemoveWQ::_process( pair item, ThreadPool::TPHandle &handle) { PGRef pg(item.first); SnapMapper &mapper = pg->snap_mapper; OSDriver &driver = pg->osdriver; coll_t coll = coll_t(pg->info.pgid); pg->osr->flush(); if (!item.second->start_clearing()) return; list colls_to_remove; pg->get_colls(&colls_to_remove); for (list::iterator i = colls_to_remove.begin(); i != colls_to_remove.end(); ++i) { bool cont = remove_dir( pg->cct, store, &mapper, &driver, pg->osr.get(), *i, item.second, handle); if (!cont) return; } if (!item.second->start_deleting()) return; ObjectStore::Transaction *t = new ObjectStore::Transaction; PGLog::clear_info_log( pg->info.pgid, OSD::make_infos_oid(), pg->log_oid, t); for (list::iterator i = colls_to_remove.begin(); i != colls_to_remove.end(); ++i) { t->remove_collection(*i); } // We need the sequencer to stick around until the op is complete store->queue_transaction( pg->osr.get(), t, 0, // onapplied 0, // oncommit 0, // onreadable sync new ObjectStore::C_DeleteTransactionHolder( t, pg), // oncomplete TrackedOpRef()); item.second->finish_deleting(); } // ========================================= void OSD::do_mon_report() { dout(7) << "do_mon_report" << dendl; utime_t now(ceph_clock_now(cct)); last_mon_report = now; // do any pending reports send_alive(); service.send_pg_temp(); send_failures(); send_pg_stats(now); } void OSD::ms_handle_connect(Connection *con) { if (con->get_peer_type() == CEPH_ENTITY_TYPE_MON) { Mutex::Locker l(osd_lock); if (is_stopping()) return; dout(10) << "ms_handle_connect on mon" << dendl; if (is_booting()) { start_boot(); } else { send_alive(); service.send_pg_temp(); send_failures(); send_pg_stats(ceph_clock_now(cct)); monc->sub_want("osd_pg_creates", 0, CEPH_SUBSCRIBE_ONETIME); monc->renew_subs(); } } } bool OSD::ms_handle_reset(Connection *con) { OSD::Session *session = (OSD::Session *)con->get_priv(); dout(1) << "ms_handle_reset con " << con << " session " << session << dendl; if (!session) return false; session->wstate.reset(); session->con.reset(NULL); // break con <-> session ref cycle session->put(); return true; } struct C_OSD_GetVersion : public Context { OSD *osd; uint64_t oldest, newest; C_OSD_GetVersion(OSD *o) : osd(o), oldest(0), newest(0) {} void finish(int r) { if (r >= 0) osd->_maybe_boot(oldest, newest); } }; void OSD::start_boot() { dout(10) << "start_boot - have maps " << superblock.oldest_map << ".." << superblock.newest_map << dendl; C_OSD_GetVersion *c = new C_OSD_GetVersion(this); monc->get_version("osdmap", &c->newest, &c->oldest, c); } void OSD::_maybe_boot(epoch_t oldest, epoch_t newest) { Mutex::Locker l(osd_lock); if (is_stopping()) return; dout(10) << "_maybe_boot mon has osdmaps " << oldest << ".." << newest << dendl; if (is_initializing()) { dout(10) << "still initializing" << dendl; return; } // if our map within recent history, try to add ourselves to the osdmap. if (osdmap->test_flag(CEPH_OSDMAP_NOUP)) { dout(5) << "osdmap NOUP flag is set, waiting for it to clear" << dendl; } else if (is_waiting_for_healthy() || !_is_healthy()) { // if we are not healthy, do not mark ourselves up (yet) dout(1) << "not healthy; waiting to boot" << dendl; if (!is_waiting_for_healthy()) start_waiting_for_healthy(); // send pings sooner rather than later heartbeat_kick(); } else if (osdmap->get_epoch() >= oldest - 1 && osdmap->get_epoch() + cct->_conf->osd_map_message_max > newest) { _send_boot(); return; } // get all the latest maps if (osdmap->get_epoch() + 1 >= oldest) osdmap_subscribe(osdmap->get_epoch() + 1, true); else osdmap_subscribe(oldest - 1, true); } void OSD::start_waiting_for_healthy() { dout(1) << "start_waiting_for_healthy" << dendl; state = STATE_WAITING_FOR_HEALTHY; last_heartbeat_resample = utime_t(); } bool OSD::_is_healthy() { if (!cct->get_heartbeat_map()->is_healthy()) { dout(1) << "is_healthy false -- internal heartbeat failed" << dendl; return false; } if (is_waiting_for_healthy()) { Mutex::Locker l(heartbeat_lock); utime_t cutoff = ceph_clock_now(cct); cutoff -= cct->_conf->osd_heartbeat_grace; int num = 0, up = 0; for (map::iterator p = heartbeat_peers.begin(); p != heartbeat_peers.end(); ++p) { if (p->second.is_healthy(cutoff)) ++up; ++num; } if ((float)up < (float)num * cct->_conf->osd_heartbeat_min_healthy_ratio) { dout(1) << "is_healthy false -- only " << up << "/" << num << " up peers (less than 1/3)" << dendl; return false; } } return true; } void OSD::_send_boot() { dout(10) << "_send_boot" << dendl; entity_addr_t cluster_addr = cluster_messenger->get_myaddr(); if (cluster_addr.is_blank_ip()) { int port = cluster_addr.get_port(); cluster_addr = client_messenger->get_myaddr(); cluster_addr.set_port(port); cluster_messenger->set_addr_unknowns(cluster_addr); dout(10) << " assuming cluster_addr ip matches client_addr" << dendl; } entity_addr_t hb_back_addr = hb_back_server_messenger->get_myaddr(); if (hb_back_addr.is_blank_ip()) { int port = hb_back_addr.get_port(); hb_back_addr = cluster_addr; hb_back_addr.set_port(port); hb_back_server_messenger->set_addr_unknowns(hb_back_addr); dout(10) << " assuming hb_back_addr ip matches cluster_addr" << dendl; } entity_addr_t hb_front_addr = hb_front_server_messenger->get_myaddr(); if (hb_front_addr.is_blank_ip()) { int port = hb_front_addr.get_port(); hb_front_addr = client_messenger->get_myaddr(); hb_front_addr.set_port(port); hb_front_server_messenger->set_addr_unknowns(hb_front_addr); dout(10) << " assuming hb_front_addr ip matches client_addr" << dendl; } MOSDBoot *mboot = new MOSDBoot(superblock, boot_epoch, hb_back_addr, hb_front_addr, cluster_addr, CEPH_FEATURES_ALL); dout(10) << " client_addr " << client_messenger->get_myaddr() << ", cluster_addr " << cluster_addr << ", hb_back_addr " << hb_back_addr << ", hb_front_addr " << hb_front_addr << dendl; _collect_metadata(&mboot->metadata); monc->send_mon_message(mboot); } bool OSD::_lsb_release_set (char *buf, const char *str, map *pm, const char *key) { if (strncmp (buf, str, strlen (str)) == 0) { char *value; if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; value = buf + strlen (str) + 1; (*pm)[key] = value; return true; } return false; } void OSD::_lsb_release_parse (map *pm) { FILE *fp = NULL; char buf[512]; fp = popen("lsb_release -idrc", "r"); if (!fp) { int ret = -errno; derr << "lsb_release_parse - failed to call lsb_release binary with error: " << cpp_strerror(ret) << dendl; return; } while (fgets(buf, sizeof(buf) - 1, fp) != NULL) { if (_lsb_release_set(buf, "Distributor ID:", pm, "distro")) continue; if (_lsb_release_set(buf, "Description:", pm, "distro_description")) continue; if (_lsb_release_set(buf, "Release:", pm, "distro_version")) continue; if (_lsb_release_set(buf, "Codename:", pm, "distro_codename")) continue; derr << "unhandled output: " << buf << dendl; } if (pclose(fp)) { int ret = -errno; derr << "lsb_release_parse - pclose failed: " << cpp_strerror(ret) << dendl; } } void OSD::_collect_metadata(map *pm) { (*pm)["ceph_version"] = pretty_version_to_str(); // config info (*pm)["osd_data"] = dev_path; (*pm)["osd_journal"] = journal_path; (*pm)["front_addr"] = stringify(client_messenger->get_myaddr()); (*pm)["back_addr"] = stringify(cluster_messenger->get_myaddr()); (*pm)["hb_front_addr"] = stringify(hb_front_server_messenger->get_myaddr()); (*pm)["hb_back_addr"] = stringify(hb_back_server_messenger->get_myaddr()); // kernel info struct utsname u; int r = uname(&u); if (r >= 0) { (*pm)["os"] = u.sysname; (*pm)["kernel_version"] = u.release; (*pm)["kernel_description"] = u.version; (*pm)["hostname"] = u.nodename; (*pm)["arch"] = u.machine; } // memory FILE *f = fopen("/proc/meminfo", "r"); if (f) { char buf[100]; while (!feof(f)) { char *line = fgets(buf, sizeof(buf), f); if (!line) break; char key[40]; long long value; int r = sscanf(line, "%s %lld", key, &value); if (r == 2) { if (strcmp(key, "MemTotal:") == 0) (*pm)["mem_total_kb"] = stringify(value); else if (strcmp(key, "SwapTotal:") == 0) (*pm)["mem_swap_kb"] = stringify(value); } } fclose(f); } // processor f = fopen("/proc/cpuinfo", "r"); if (f) { char buf[100]; while (!feof(f)) { char *line = fgets(buf, sizeof(buf), f); if (!line) break; if (strncmp(line, "model name", 10) == 0) { char *c = strchr(buf, ':'); c++; while (*c == ' ') ++c; char *nl = c; while (*nl != '\n') ++nl; *nl = '\0'; (*pm)["cpu"] = c; break; } } fclose(f); } // distro info _lsb_release_parse(pm); dout(10) << __func__ << " " << *pm << dendl; } void OSD::queue_want_up_thru(epoch_t want) { map_lock.get_read(); epoch_t cur = osdmap->get_up_thru(whoami); if (want > up_thru_wanted) { dout(10) << "queue_want_up_thru now " << want << " (was " << up_thru_wanted << ")" << ", currently " << cur << dendl; up_thru_wanted = want; // expedite, a bit. WARNING this will somewhat delay other mon queries. last_mon_report = ceph_clock_now(cct); send_alive(); } else { dout(10) << "queue_want_up_thru want " << want << " <= queued " << up_thru_wanted << ", currently " << cur << dendl; } map_lock.put_read(); } void OSD::send_alive() { if (!osdmap->exists(whoami)) return; epoch_t up_thru = osdmap->get_up_thru(whoami); dout(10) << "send_alive up_thru currently " << up_thru << " want " << up_thru_wanted << dendl; if (up_thru_wanted > up_thru) { up_thru_pending = up_thru_wanted; dout(10) << "send_alive want " << up_thru_wanted << dendl; monc->send_mon_message(new MOSDAlive(osdmap->get_epoch(), up_thru_wanted)); } } void OSDService::send_message_osd_cluster(int peer, Message *m, epoch_t from_epoch) { Mutex::Locker l(pre_publish_lock); // service map is always newer/newest assert(from_epoch <= next_osdmap->get_epoch()); if (next_osdmap->is_down(peer) || next_osdmap->get_info(peer).up_from > from_epoch) { m->put(); return; } const entity_inst_t& peer_inst = next_osdmap->get_cluster_inst(peer); ConnectionRef peer_con = osd->cluster_messenger->get_connection(peer_inst); osd->_share_map_outgoing(peer, peer_con.get(), next_osdmap); osd->cluster_messenger->send_message(m, peer_inst); } ConnectionRef OSDService::get_con_osd_cluster(int peer, epoch_t from_epoch) { Mutex::Locker l(pre_publish_lock); // service map is always newer/newest assert(from_epoch <= next_osdmap->get_epoch()); if (next_osdmap->is_down(peer) || next_osdmap->get_info(peer).up_from > from_epoch) { return NULL; } return osd->cluster_messenger->get_connection(next_osdmap->get_cluster_inst(peer)); } pair OSDService::get_con_osd_hb(int peer, epoch_t from_epoch) { Mutex::Locker l(pre_publish_lock); // service map is always newer/newest assert(from_epoch <= next_osdmap->get_epoch()); pair ret; if (next_osdmap->is_down(peer) || next_osdmap->get_info(peer).up_from > from_epoch) { return ret; } ret.first = osd->hbclient_messenger->get_connection(next_osdmap->get_hb_back_inst(peer)); if (next_osdmap->get_hb_front_addr(peer) != entity_addr_t()) ret.second = osd->hbclient_messenger->get_connection(next_osdmap->get_hb_front_inst(peer)); return ret; } void OSDService::queue_want_pg_temp(pg_t pgid, vector& want) { Mutex::Locker l(pg_temp_lock); pg_temp_wanted[pgid] = want; } void OSDService::send_pg_temp() { Mutex::Locker l(pg_temp_lock); if (pg_temp_wanted.empty()) return; dout(10) << "send_pg_temp " << pg_temp_wanted << dendl; MOSDPGTemp *m = new MOSDPGTemp(osdmap->get_epoch()); m->pg_temp = pg_temp_wanted; monc->send_mon_message(m); } void OSD::send_failures() { assert(osd_lock.is_locked()); bool locked = false; if (!failure_queue.empty()) { heartbeat_lock.Lock(); locked = true; } utime_t now = ceph_clock_now(cct); while (!failure_queue.empty()) { int osd = failure_queue.begin()->first; int failed_for = (int)(double)(now - failure_queue.begin()->second); entity_inst_t i = osdmap->get_inst(osd); monc->send_mon_message(new MOSDFailure(monc->get_fsid(), i, failed_for, osdmap->get_epoch())); failure_pending[osd] = i; failure_queue.erase(osd); } if (locked) heartbeat_lock.Unlock(); } void OSD::send_still_alive(epoch_t epoch, const entity_inst_t &i) { MOSDFailure *m = new MOSDFailure(monc->get_fsid(), i, 0, epoch); m->is_failed = false; monc->send_mon_message(m); } void OSD::send_pg_stats(const utime_t &now) { assert(osd_lock.is_locked()); dout(20) << "send_pg_stats" << dendl; stat_lock.Lock(); osd_stat_t cur_stat = osd_stat; stat_lock.Unlock(); cur_stat.fs_perf_stat = store->get_cur_stats(); pg_stat_queue_lock.Lock(); if (osd_stat_updated || !pg_stat_queue.empty()) { last_pg_stats_sent = now; osd_stat_updated = false; dout(10) << "send_pg_stats - " << pg_stat_queue.size() << " pgs updated" << dendl; utime_t had_for(now); had_for -= had_map_since; MPGStats *m = new MPGStats(monc->get_fsid(), osdmap->get_epoch(), had_for); m->set_tid(++pg_stat_tid); m->osd_stat = cur_stat; xlist::iterator p = pg_stat_queue.begin(); while (!p.end()) { PG *pg = *p; ++p; if (!pg->is_primary()) { // we hold map_lock; role is stable. pg->stat_queue_item.remove_myself(); pg->put("pg_stat_queue"); continue; } pg->pg_stats_publish_lock.Lock(); if (pg->pg_stats_publish_valid) { m->pg_stat[pg->info.pgid.pgid] = pg->pg_stats_publish; dout(25) << " sending " << pg->info.pgid << " " << pg->pg_stats_publish.reported_epoch << ":" << pg->pg_stats_publish.reported_seq << dendl; } else { dout(25) << " NOT sending " << pg->info.pgid << " " << pg->pg_stats_publish.reported_epoch << ":" << pg->pg_stats_publish.reported_seq << ", not valid" << dendl; } pg->pg_stats_publish_lock.Unlock(); } if (!outstanding_pg_stats) { outstanding_pg_stats = true; last_pg_stats_ack = ceph_clock_now(cct); } monc->send_mon_message(m); } pg_stat_queue_lock.Unlock(); } void OSD::handle_pg_stats_ack(MPGStatsAck *ack) { dout(10) << "handle_pg_stats_ack " << dendl; if (!require_mon_peer(ack)) { ack->put(); return; } last_pg_stats_ack = ceph_clock_now(cct); pg_stat_queue_lock.Lock(); if (ack->get_tid() > pg_stat_tid_flushed) { pg_stat_tid_flushed = ack->get_tid(); pg_stat_queue_cond.Signal(); } xlist::iterator p = pg_stat_queue.begin(); while (!p.end()) { PG *pg = *p; PGRef _pg(pg); ++p; if (ack->pg_stat.count(pg->info.pgid.pgid)) { pair acked = ack->pg_stat[pg->info.pgid.pgid]; pg->pg_stats_publish_lock.Lock(); if (acked.first == pg->pg_stats_publish.reported_seq && acked.second == pg->pg_stats_publish.reported_epoch) { dout(25) << " ack on " << pg->info.pgid << " " << pg->pg_stats_publish.reported_epoch << ":" << pg->pg_stats_publish.reported_seq << dendl; pg->stat_queue_item.remove_myself(); pg->put("pg_stat_queue"); } else { dout(25) << " still pending " << pg->info.pgid << " " << pg->pg_stats_publish.reported_epoch << ":" << pg->pg_stats_publish.reported_seq << " > acked " << acked << dendl; } pg->pg_stats_publish_lock.Unlock(); } else { dout(30) << " still pending " << pg->info.pgid << " " << pg->pg_stats_publish.reported_epoch << ":" << pg->pg_stats_publish.reported_seq << dendl; } } if (!pg_stat_queue.size()) { outstanding_pg_stats = false; } pg_stat_queue_lock.Unlock(); ack->put(); } void OSD::flush_pg_stats() { dout(10) << "flush_pg_stats" << dendl; utime_t now = ceph_clock_now(cct); send_pg_stats(now); osd_lock.Unlock(); pg_stat_queue_lock.Lock(); uint64_t tid = pg_stat_tid; dout(10) << "flush_pg_stats waiting for stats tid " << tid << " to flush" << dendl; while (tid > pg_stat_tid_flushed) pg_stat_queue_cond.Wait(pg_stat_queue_lock); dout(10) << "flush_pg_stats finished waiting for stats tid " << tid << " to flush" << dendl; pg_stat_queue_lock.Unlock(); osd_lock.Lock(); } void OSD::handle_command(MMonCommand *m) { if (!require_mon_peer(m)) return; Command *c = new Command(m->cmd, m->get_tid(), m->get_data(), NULL); command_wq.queue(c); m->put(); } void OSD::handle_command(MCommand *m) { ConnectionRef con = m->get_connection(); Session *session = static_cast(con->get_priv()); if (!session) { client_messenger->send_message(new MCommandReply(m, -EPERM), con); m->put(); return; } OSDCap& caps = session->caps; session->put(); if (!caps.allow_all() || m->get_source().is_mon()) { client_messenger->send_message(new MCommandReply(m, -EPERM), con); m->put(); return; } Command *c = new Command(m->cmd, m->get_tid(), m->get_data(), con.get()); command_wq.queue(c); m->put(); } struct OSDCommand { string cmdstring; string helpstring; string module; string perm; string availability; } osd_commands[] = { #define COMMAND(parsesig, helptext, module, perm, availability) \ {parsesig, helptext, module, perm, availability}, // yes, these are really pg commands, but there's a limit to how // much work it's worth. The OSD returns all of them. Make this // form (pg ) valid only for the cli. // Rest uses "tell " COMMAND("pg " \ "name=pgid,type=CephPgid " \ "name=cmd,type=CephChoices,strings=query", \ "show details of a specific pg", "osd", "r", "cli") COMMAND("pg " \ "name=pgid,type=CephPgid " \ "name=cmd,type=CephChoices,strings=mark_unfound_lost " \ "name=mulcmd,type=CephChoices,strings=revert|delete", \ "mark all unfound objects in this pg as lost, either removing or reverting to a prior version if one is available", "osd", "rw", "cli") COMMAND("pg " \ "name=pgid,type=CephPgid " \ "name=cmd,type=CephChoices,strings=list_missing " \ "name=offset,type=CephString,req=false", "list missing objects on this pg, perhaps starting at an offset given in JSON", "osd", "r", "cli") // new form: tell for both cli and rest COMMAND("query", "show details of a specific pg", "osd", "r", "cli,rest") COMMAND("mark_unfound_lost " \ "name=mulcmd,type=CephChoices,strings=revert|delete", \ "mark all unfound objects in this pg as lost, either removing or reverting to a prior version if one is available", "osd", "rw", "cli,rest") COMMAND("list_missing " \ "name=offset,type=CephString,req=false", "list missing objects on this pg, perhaps starting at an offset given in JSON", "osd", "r", "cli,rest") // tell commands. Validation of osd.n must be special-cased in client COMMAND("version", "report version of OSD", "osd", "r", "cli,rest") COMMAND("injectargs " \ "name=injected_args,type=CephString,n=N", "inject configuration arguments into running OSD", "osd", "rw", "cli,rest") COMMAND("bench " \ "name=count,type=CephInt,req=false " \ "name=size,type=CephInt,req=false ", \ "OSD benchmark: write -byte objects, " \ "(default 1G size 4MB). Results in log.", "osd", "rw", "cli,rest") COMMAND("flush_pg_stats", "flush pg stats", "osd", "rw", "cli,rest") COMMAND("heap " \ "name=heapcmd,type=CephChoices,strings=dump|start_profiler|stop_profiler|release|stats", \ "show heap usage info (available only if compiled with tcmalloc)", \ "osd", "rw", "cli,rest") COMMAND("debug_dump_missing " \ "name=filename,type=CephFilepath", "dump missing objects to a named file", "osd", "r", "cli,rest") COMMAND("debug kick_recovery_wq " \ "name=delay,type=CephInt,range=0", "set osd_recovery_delay_start to ", "osd", "rw", "cli,rest") COMMAND("cpu_profiler " \ "name=arg,type=CephChoices,strings=status|flush", "run cpu profiling on daemon", "osd", "rw", "cli,rest") COMMAND("dump_pg_recovery_stats", "dump pg recovery statistics", "osd", "r", "cli,rest") COMMAND("reset_pg_recovery_stats", "reset pg recovery statistics", "osd", "rw", "cli,rest") }; void OSD::do_command(Connection *con, ceph_tid_t tid, vector& cmd, bufferlist& data) { int r = 0; stringstream ss, ds; string rs; bufferlist odata; dout(20) << "do_command tid " << tid << " " << cmd << dendl; map cmdmap; string prefix; string format; string pgidstr; boost::scoped_ptr f; if (cmd.empty()) { ss << "no command given"; goto out; } if (!cmdmap_from_json(cmd, &cmdmap, ss)) { r = -EINVAL; goto out; } cmd_getval(cct, cmdmap, "prefix", prefix); if (prefix == "get_command_descriptions") { int cmdnum = 0; JSONFormatter *f = new JSONFormatter(); f->open_object_section("command_descriptions"); for (OSDCommand *cp = osd_commands; cp < &osd_commands[ARRAY_SIZE(osd_commands)]; cp++) { ostringstream secname; secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; dump_cmddesc_to_json(f, secname.str(), cp->cmdstring, cp->helpstring, cp->module, cp->perm, cp->availability); cmdnum++; } f->close_section(); // command_descriptions f->flush(ds); delete f; goto out; } cmd_getval(cct, cmdmap, "format", format); f.reset(new_formatter(format)); if (prefix == "version") { if (f) { f->open_object_section("version"); f->dump_string("version", pretty_version_to_str()); f->close_section(); f->flush(ds); } else { ds << pretty_version_to_str(); } goto out; } else if (prefix == "injectargs") { vector argsvec; cmd_getval(cct, cmdmap, "injected_args", argsvec); if (argsvec.empty()) { r = -EINVAL; ss << "ignoring empty injectargs"; goto out; } string args = argsvec.front(); for (vector::iterator a = ++argsvec.begin(); a != argsvec.end(); ++a) args += " " + *a; osd_lock.Unlock(); cct->_conf->injectargs(args, &ss); osd_lock.Lock(); } // either 'pg ' or // 'tell ' (which comes in without any of that prefix)? else if (prefix == "pg" || (cmd_getval(cct, cmdmap, "pgid", pgidstr) && (prefix == "query" || prefix == "mark_unfound_lost" || prefix == "list_missing") )) { pg_t pgid; if (!cmd_getval(cct, cmdmap, "pgid", pgidstr)) { ss << "no pgid specified"; r = -EINVAL; } else if (!pgid.parse(pgidstr.c_str())) { ss << "couldn't parse pgid '" << pgidstr << "'"; r = -EINVAL; } else { spg_t pcand; if (osdmap->get_primary_shard(pgid, &pcand) && _have_pg(pcand)) { PG *pg = _lookup_lock_pg(pcand); assert(pg); if (pg->is_primary()) { // simulate pg cmd= for pg->do-command if (prefix != "pg") cmd_putval(cct, cmdmap, "cmd", prefix); r = pg->do_command(cmdmap, ss, data, odata); } else { ss << "not primary for pgid " << pgid; // send them the latest diff to ensure they realize the mapping // has changed. send_incremental_map(osdmap->get_epoch() - 1, con); // do not reply; they will get newer maps and realize they // need to resend. pg->unlock(); return; } pg->unlock(); } else { ss << "i don't have pgid " << pgid; r = -ENOENT; } } } else if (prefix == "bench") { int64_t count; int64_t bsize; // default count 1G, size 4MB cmd_getval(cct, cmdmap, "count", count, (int64_t)1 << 30); cmd_getval(cct, cmdmap, "size", bsize, (int64_t)4 << 20); uint32_t duration = g_conf->osd_bench_duration; if (bsize > (int64_t) g_conf->osd_bench_max_block_size) { // let us limit the block size because the next checks rely on it // having a sane value. If we allow any block size to be set things // can still go sideways. ss << "block 'size' values are capped at " << prettybyte_t(g_conf->osd_bench_max_block_size) << ". If you wish to use" << " a higher value, please adjust 'osd_bench_max_block_size'"; r = -EINVAL; goto out; } else if (bsize < (int64_t) (1 << 20)) { // entering the realm of small block sizes. // limit the count to a sane value, assuming a configurable amount of // IOPS and duration, so that the OSD doesn't get hung up on this, // preventing timeouts from going off int64_t max_count = bsize * duration * g_conf->osd_bench_small_size_max_iops; if (count > max_count) { ss << "'count' values greater than " << max_count << " for a block size of " << prettybyte_t(bsize) << ", assuming " << g_conf->osd_bench_small_size_max_iops << " IOPS," << " for " << duration << " seconds," << " can cause ill effects on osd. " << " Please adjust 'osd_bench_small_size_max_iops' with a higher" << " value if you wish to use a higher 'count'."; r = -EINVAL; goto out; } } else { // 1MB block sizes are big enough so that we get more stuff done. // However, to avoid the osd from getting hung on this and having // timers being triggered, we are going to limit the count assuming // a configurable throughput and duration. int64_t max_count = g_conf->osd_bench_large_size_max_throughput * duration; if (count > max_count) { ss << "'count' values greater than " << max_count << " for a block size of " << prettybyte_t(bsize) << ", assuming " << prettybyte_t(g_conf->osd_bench_large_size_max_throughput) << "/s," << " for " << duration << " seconds," << " can cause ill effects on osd. " << " Please adjust 'osd_bench_large_size_max_throughput'" << " with a higher value if you wish to use a higher 'count'."; r = -EINVAL; goto out; } } dout(1) << " bench count " << count << " bsize " << prettybyte_t(bsize) << dendl; bufferlist bl; bufferptr bp(bsize); bp.zero(); bl.push_back(bp); ObjectStore::Transaction *cleanupt = new ObjectStore::Transaction; store->sync_and_flush(); utime_t start = ceph_clock_now(cct); for (int64_t pos = 0; pos < count; pos += bsize) { char nm[30]; snprintf(nm, sizeof(nm), "disk_bw_test_%lld", (long long)pos); object_t oid(nm); hobject_t soid(sobject_t(oid, 0)); ObjectStore::Transaction *t = new ObjectStore::Transaction; t->write(coll_t::META_COLL, soid, 0, bsize, bl); store->queue_transaction_and_cleanup(NULL, t); cleanupt->remove(coll_t::META_COLL, soid); } store->sync_and_flush(); utime_t end = ceph_clock_now(cct); // clean up store->queue_transaction_and_cleanup(NULL, cleanupt); uint64_t rate = (double)count / (end - start); if (f) { f->open_object_section("osd_bench_results"); f->dump_int("bytes_written", count); f->dump_int("blocksize", bsize); f->dump_float("bytes_per_sec", rate); f->close_section(); f->flush(ss); } else { ss << "bench: wrote " << prettybyte_t(count) << " in blocks of " << prettybyte_t(bsize) << " in " << (end-start) << " sec at " << prettybyte_t(rate) << "/sec"; } } else if (prefix == "flush_pg_stats") { flush_pg_stats(); } else if (prefix == "heap") { if (!ceph_using_tcmalloc()) { r = -EOPNOTSUPP; ss << "could not issue heap profiler command -- not using tcmalloc!"; } else { string heapcmd; cmd_getval(cct, cmdmap, "heapcmd", heapcmd); // XXX 1-element vector, change at callee or make vector here? vector heapcmd_vec; get_str_vec(heapcmd, heapcmd_vec); ceph_heap_profiler_handle_command(heapcmd_vec, ds); } } else if (prefix == "debug dump_missing") { string file_name; cmd_getval(cct, cmdmap, "filename", file_name); std::ofstream fout(file_name.c_str()); if (!fout.is_open()) { ss << "failed to open file '" << file_name << "'"; r = -EINVAL; goto out; } std::set keys; for (ceph::unordered_map::const_iterator pg_map_e = pg_map.begin(); pg_map_e != pg_map.end(); ++pg_map_e) { keys.insert(pg_map_e->first); } fout << "*** osd " << whoami << ": dump_missing ***" << std::endl; for (std::set ::iterator p = keys.begin(); p != keys.end(); ++p) { ceph::unordered_map::iterator q = pg_map.find(*p); assert(q != pg_map.end()); PG *pg = q->second; pg->lock(); fout << *pg << std::endl; std::map::const_iterator mend = pg->pg_log.get_missing().missing.end(); std::map::const_iterator mi = pg->pg_log.get_missing().missing.begin(); for (; mi != mend; ++mi) { fout << mi->first << " -> " << mi->second << std::endl; if (!pg->missing_loc.needs_recovery(mi->first)) continue; if (pg->missing_loc.is_unfound(mi->first)) fout << " unfound "; const set &mls(pg->missing_loc.get_locations(mi->first)); if (mls.empty()) continue; fout << "missing_loc: " << mls << std::endl; } pg->unlock(); fout << std::endl; } fout.close(); } else if (prefix == "debug kick_recovery_wq") { int64_t delay; cmd_getval(cct, cmdmap, "delay", delay); ostringstream oss; oss << delay; r = cct->_conf->set_val("osd_recovery_delay_start", oss.str().c_str()); if (r != 0) { ss << "kick_recovery_wq: error setting " << "osd_recovery_delay_start to '" << delay << "': error " << r; goto out; } cct->_conf->apply_changes(NULL); ss << "kicking recovery queue. set osd_recovery_delay_start " << "to " << cct->_conf->osd_recovery_delay_start; defer_recovery_until = ceph_clock_now(cct); defer_recovery_until += cct->_conf->osd_recovery_delay_start; recovery_wq.wake(); } else if (prefix == "cpu_profiler") { string arg; cmd_getval(cct, cmdmap, "arg", arg); vector argvec; get_str_vec(arg, argvec); cpu_profiler_handle_command(argvec, ds); } else if (prefix == "dump_pg_recovery_stats") { stringstream s; if (f) { pg_recovery_stats.dump_formatted(f.get()); f->flush(ds); } else { pg_recovery_stats.dump(s); ds << "dump pg recovery stats: " << s.str(); } } else if (prefix == "reset_pg_recovery_stats") { ss << "reset pg recovery stats"; pg_recovery_stats.reset(); } else { ss << "unrecognized command! " << cmd; r = -EINVAL; } out: rs = ss.str(); odata.append(ds); dout(0) << "do_command r=" << r << " " << rs << dendl; clog.info() << rs << "\n"; if (con) { MCommandReply *reply = new MCommandReply(r, rs); reply->set_tid(tid); reply->set_data(odata); client_messenger->send_message(reply, con); } return; } // -------------------------------------- // dispatch epoch_t OSD::get_peer_epoch(int peer) { Mutex::Locker l(peer_map_epoch_lock); map::iterator p = peer_map_epoch.find(peer); if (p == peer_map_epoch.end()) return 0; return p->second; } epoch_t OSD::note_peer_epoch(int peer, epoch_t e) { Mutex::Locker l(peer_map_epoch_lock); map::iterator p = peer_map_epoch.find(peer); if (p != peer_map_epoch.end()) { if (p->second < e) { dout(10) << "note_peer_epoch osd." << peer << " has " << e << dendl; p->second = e; } else { dout(30) << "note_peer_epoch osd." << peer << " has " << p->second << " >= " << e << dendl; } return p->second; } else { dout(10) << "note_peer_epoch osd." << peer << " now has " << e << dendl; peer_map_epoch[peer] = e; return e; } } void OSD::forget_peer_epoch(int peer, epoch_t as_of) { Mutex::Locker l(peer_map_epoch_lock); map::iterator p = peer_map_epoch.find(peer); if (p != peer_map_epoch.end()) { if (p->second <= as_of) { dout(10) << "forget_peer_epoch osd." << peer << " as_of " << as_of << " had " << p->second << dendl; peer_map_epoch.erase(p); } else { dout(10) << "forget_peer_epoch osd." << peer << " as_of " << as_of << " has " << p->second << " - not forgetting" << dendl; } } } bool OSD::_share_map_incoming(entity_name_t name, Connection *con, epoch_t epoch, Session* session) { bool shared = false; dout(20) << "_share_map_incoming " << name << " " << con->get_peer_addr() << " " << epoch << dendl; //assert(osd_lock.is_locked()); assert(is_active()); // does client have old map? if (name.is_client()) { bool sendmap = epoch < osdmap->get_epoch(); if (sendmap && session) { if (session->last_sent_epoch < osdmap->get_epoch()) { session->last_sent_epoch = osdmap->get_epoch(); } else { sendmap = false; //we don't need to send it out again dout(15) << name << " already sent incremental to update from epoch "<< epoch << dendl; } } if (sendmap) { dout(10) << name << " has old map " << epoch << " < " << osdmap->get_epoch() << dendl; send_incremental_map(epoch, con); shared = true; } } // does peer have old map? if (con->get_messenger() == cluster_messenger && osdmap->is_up(name.num()) && (osdmap->get_cluster_addr(name.num()) == con->get_peer_addr() || osdmap->get_hb_back_addr(name.num()) == con->get_peer_addr())) { // remember epoch_t has = note_peer_epoch(name.num(), epoch); // share? if (has < osdmap->get_epoch()) { dout(10) << name << " " << con->get_peer_addr() << " has old map " << epoch << " < " << osdmap->get_epoch() << dendl; note_peer_epoch(name.num(), osdmap->get_epoch()); send_incremental_map(epoch, con); shared = true; } } if (session) session->put(); return shared; } void OSD::_share_map_outgoing(int peer, Connection *con, OSDMapRef map) { if (!map) map = service.get_osdmap(); // send map? epoch_t pe = get_peer_epoch(peer); if (pe) { if (pe < map->get_epoch()) { send_incremental_map(pe, con); note_peer_epoch(peer, map->get_epoch()); } else dout(20) << "_share_map_outgoing " << con << " already has epoch " << pe << dendl; } else { dout(20) << "_share_map_outgoing " << con << " don't know epoch, doing nothing" << dendl; // no idea about peer's epoch. // ??? send recent ??? // do nothing. } } bool OSD::heartbeat_dispatch(Message *m) { dout(30) << "heartbeat_dispatch " << m << dendl; switch (m->get_type()) { case CEPH_MSG_PING: dout(10) << "ping from " << m->get_source_inst() << dendl; m->put(); break; case MSG_OSD_PING: handle_osd_ping(static_cast(m)); break; case CEPH_MSG_OSD_MAP: { ConnectionRef self = cluster_messenger->get_loopback_connection(); cluster_messenger->send_message(m, self); } break; default: dout(0) << "dropping unexpected message " << *m << " from " << m->get_source_inst() << dendl; m->put(); } return true; } bool OSDService::ObjecterDispatcher::ms_dispatch(Message *m) { Mutex::Locker l(osd->objecter_lock); osd->objecter->dispatch(m); return true; } bool OSDService::ObjecterDispatcher::ms_handle_reset(Connection *con) { Mutex::Locker l(osd->objecter_lock); osd->objecter->ms_handle_reset(con); return true; } void OSDService::ObjecterDispatcher::ms_handle_connect(Connection *con) { Mutex::Locker l(osd->objecter_lock); return osd->objecter->ms_handle_connect(con); } bool OSDService::ObjecterDispatcher::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) { if (dest_type == CEPH_ENTITY_TYPE_MON) return true; *authorizer = osd->monc->auth->build_authorizer(dest_type); return *authorizer != NULL; } bool OSD::ms_dispatch(Message *m) { if (m->get_type() == MSG_OSD_MARK_ME_DOWN) { service.got_stop_ack(); m->put(); return true; } // lock! osd_lock.Lock(); if (is_stopping()) { osd_lock.Unlock(); m->put(); return true; } while (dispatch_running) { dout(10) << "ms_dispatch waiting for other dispatch thread to complete" << dendl; dispatch_cond.Wait(osd_lock); } dispatch_running = true; do_waiters(); _dispatch(m); do_waiters(); dispatch_running = false; dispatch_cond.Signal(); osd_lock.Unlock(); return true; } bool OSD::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) { dout(10) << "OSD::ms_get_authorizer type=" << ceph_entity_type_name(dest_type) << dendl; if (dest_type == CEPH_ENTITY_TYPE_MON) return true; if (force_new) { /* the MonClient checks keys every tick(), so we should just wait for that cycle to get through */ if (monc->wait_auth_rotating(10) < 0) return false; } *authorizer = monc->auth->build_authorizer(dest_type); return *authorizer != NULL; } bool OSD::ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key) { AuthAuthorizeHandler *authorize_handler = 0; switch (peer_type) { case CEPH_ENTITY_TYPE_MDS: /* * note: mds is technically a client from our perspective, but * this makes the 'cluster' consistent w/ monitor's usage. */ case CEPH_ENTITY_TYPE_OSD: authorize_handler = authorize_handler_cluster_registry->get_handler(protocol); break; default: authorize_handler = authorize_handler_service_registry->get_handler(protocol); } if (!authorize_handler) { dout(0) << "No AuthAuthorizeHandler found for protocol " << protocol << dendl; isvalid = false; return true; } AuthCapsInfo caps_info; EntityName name; uint64_t global_id; uint64_t auid = CEPH_AUTH_UID_DEFAULT; isvalid = authorize_handler->verify_authorizer(cct, monc->rotating_secrets, authorizer_data, authorizer_reply, name, global_id, caps_info, session_key, &auid); if (isvalid) { Session *s = static_cast(con->get_priv()); if (!s) { s = new Session; con->set_priv(s->get()); s->con = con; dout(10) << " new session " << s << " con=" << s->con << " addr=" << s->con->get_peer_addr() << dendl; } s->entity_name = name; if (caps_info.allow_all) s->caps.set_allow_all(); s->auid = auid; if (caps_info.caps.length() > 0) { bufferlist::iterator p = caps_info.caps.begin(); string str; try { ::decode(str, p); } catch (buffer::error& e) { } bool success = s->caps.parse(str); if (success) dout(10) << " session " << s << " " << s->entity_name << " has caps " << s->caps << " '" << str << "'" << dendl; else dout(10) << " session " << s << " " << s->entity_name << " failed to parse caps '" << str << "'" << dendl; } s->put(); } return true; }; void OSD::do_waiters() { assert(osd_lock.is_locked()); dout(10) << "do_waiters -- start" << dendl; finished_lock.Lock(); while (!finished.empty()) { OpRequestRef next = finished.front(); finished.pop_front(); finished_lock.Unlock(); dispatch_op(next); finished_lock.Lock(); } finished_lock.Unlock(); dout(10) << "do_waiters -- finish" << dendl; } void OSD::dispatch_op(OpRequestRef op) { switch (op->get_req()->get_type()) { case MSG_OSD_PG_CREATE: handle_pg_create(op); break; case MSG_OSD_PG_NOTIFY: handle_pg_notify(op); break; case MSG_OSD_PG_QUERY: handle_pg_query(op); break; case MSG_OSD_PG_LOG: handle_pg_log(op); break; case MSG_OSD_PG_REMOVE: handle_pg_remove(op); break; case MSG_OSD_PG_INFO: handle_pg_info(op); break; case MSG_OSD_PG_TRIM: handle_pg_trim(op); break; case MSG_OSD_PG_MISSING: assert(0 == "received MOSDPGMissing; this message is supposed to be unused!?!"); break; case MSG_OSD_PG_SCAN: handle_pg_scan(op); break; case MSG_OSD_PG_BACKFILL: handle_pg_backfill(op); break; case MSG_OSD_BACKFILL_RESERVE: handle_pg_backfill_reserve(op); break; case MSG_OSD_RECOVERY_RESERVE: handle_pg_recovery_reserve(op); break; // client ops case CEPH_MSG_OSD_OP: handle_op(op); break; // for replication etc. case MSG_OSD_SUBOP: handle_replica_op(op); break; case MSG_OSD_SUBOPREPLY: handle_replica_op(op); break; case MSG_OSD_PG_PUSH: handle_replica_op(op); break; case MSG_OSD_PG_PULL: handle_replica_op(op); break; case MSG_OSD_PG_PUSH_REPLY: handle_replica_op(op); break; case MSG_OSD_EC_WRITE: handle_replica_op(op); break; case MSG_OSD_EC_WRITE_REPLY: handle_replica_op(op); break; case MSG_OSD_EC_READ: handle_replica_op(op); break; case MSG_OSD_EC_READ_REPLY: handle_replica_op(op); break; } } void OSD::_dispatch(Message *m) { assert(osd_lock.is_locked()); dout(20) << "_dispatch " << m << " " << *m << dendl; Session *session = NULL; logger->set(l_osd_buf, buffer::get_total_alloc()); switch (m->get_type()) { // -- don't need lock -- case CEPH_MSG_PING: dout(10) << "ping from " << m->get_source() << dendl; m->put(); break; // -- don't need OSDMap -- // map and replication case CEPH_MSG_OSD_MAP: handle_osd_map(static_cast(m)); break; // osd case CEPH_MSG_SHUTDOWN: session = static_cast(m->get_connection()->get_priv()); if (!session || session->entity_name.is_mon() || session->entity_name.is_osd()) shutdown(); else dout(0) << "shutdown message from connection with insufficient privs!" << m->get_connection() << dendl; m->put(); if (session) session->put(); break; case MSG_PGSTATSACK: handle_pg_stats_ack(static_cast(m)); break; case MSG_MON_COMMAND: handle_command(static_cast(m)); break; case MSG_COMMAND: handle_command(static_cast(m)); break; case MSG_OSD_SCRUB: handle_scrub(static_cast(m)); break; case MSG_OSD_REP_SCRUB: handle_rep_scrub(static_cast(m)); break; // -- need OSDMap -- default: { OpRequestRef op = op_tracker.create_request(m); op->mark_event("waiting_for_osdmap"); // no map? starting up? if (!osdmap) { dout(7) << "no OSDMap, not booted" << dendl; waiting_for_osdmap.push_back(op); break; } // need OSDMap dispatch_op(op); } } logger->set(l_osd_buf, buffer::get_total_alloc()); } void OSD::handle_rep_scrub(MOSDRepScrub *m) { dout(10) << __func__ << " " << *m << dendl; if (!require_self_aliveness(m, m->map_epoch)) { m->put(); return; } if (!require_osd_peer(m)) { m->put(); return; } if (osdmap->get_epoch() >= m->map_epoch && !require_same_peer_instance(m, osdmap)) { m->put(); return; } rep_scrub_wq.queue(m); } void OSD::handle_scrub(MOSDScrub *m) { dout(10) << "handle_scrub " << *m << dendl; if (!require_mon_peer(m)) return; if (m->fsid != monc->get_fsid()) { dout(0) << "handle_scrub fsid " << m->fsid << " != " << monc->get_fsid() << dendl; m->put(); return; } if (m->scrub_pgs.empty()) { for (ceph::unordered_map::iterator p = pg_map.begin(); p != pg_map.end(); ++p) { PG *pg = p->second; pg->lock(); if (pg->is_primary()) { pg->unreg_next_scrub(); pg->scrubber.must_scrub = true; pg->scrubber.must_deep_scrub = m->deep || m->repair; pg->scrubber.must_repair = m->repair; pg->reg_next_scrub(); dout(10) << "marking " << *pg << " for scrub" << dendl; } pg->unlock(); } } else { for (vector::iterator p = m->scrub_pgs.begin(); p != m->scrub_pgs.end(); ++p) { spg_t pcand; if (osdmap->get_primary_shard(*p, &pcand) && pg_map.count(pcand)) { PG *pg = pg_map[pcand]; pg->lock(); if (pg->is_primary()) { pg->unreg_next_scrub(); pg->scrubber.must_scrub = true; pg->scrubber.must_deep_scrub = m->deep || m->repair; pg->scrubber.must_repair = m->repair; pg->reg_next_scrub(); dout(10) << "marking " << *pg << " for scrub" << dendl; } pg->unlock(); } } } m->put(); } bool OSD::scrub_random_backoff() { bool coin_flip = (rand() % 3) == whoami % 3; if (!coin_flip) { dout(20) << "scrub_random_backoff lost coin flip, randomly backing off" << dendl; return true; } return false; } bool OSD::scrub_should_schedule() { double loadavgs[1]; if (getloadavg(loadavgs, 1) != 1) { dout(10) << "scrub_should_schedule couldn't read loadavgs\n" << dendl; return false; } if (loadavgs[0] >= cct->_conf->osd_scrub_load_threshold) { dout(20) << "scrub_should_schedule loadavg " << loadavgs[0] << " >= max " << cct->_conf->osd_scrub_load_threshold << " = no, load too high" << dendl; return false; } dout(20) << "scrub_should_schedule loadavg " << loadavgs[0] << " < max " << cct->_conf->osd_scrub_load_threshold << " = yes" << dendl; return loadavgs[0] < cct->_conf->osd_scrub_load_threshold; } void OSD::sched_scrub() { assert(osd_lock.is_locked()); bool load_is_low = scrub_should_schedule(); dout(20) << "sched_scrub load_is_low=" << (int)load_is_low << dendl; utime_t now = ceph_clock_now(cct); //dout(20) << " " << last_scrub_pg << dendl; pair pos; if (service.first_scrub_stamp(&pos)) { do { utime_t t = pos.first; spg_t pgid = pos.second; dout(30) << "sched_scrub examine " << pgid << " at " << t << dendl; utime_t diff = now - t; if ((double)diff < cct->_conf->osd_scrub_min_interval) { dout(10) << "sched_scrub " << pgid << " at " << t << ": " << (double)diff << " < min (" << cct->_conf->osd_scrub_min_interval << " seconds)" << dendl; break; } if ((double)diff < cct->_conf->osd_scrub_max_interval && !load_is_low) { // save ourselves some effort dout(10) << "sched_scrub " << pgid << " high load at " << t << ": " << (double)diff << " < max (" << cct->_conf->osd_scrub_max_interval << " seconds)" << dendl; break; } PG *pg = _lookup_lock_pg(pgid); if (pg) { if (pg->get_pgbackend()->scrub_supported() && pg->is_active() && (load_is_low || (double)diff >= cct->_conf->osd_scrub_max_interval || pg->scrubber.must_scrub)) { dout(10) << "sched_scrub scrubbing " << pgid << " at " << t << (pg->scrubber.must_scrub ? ", explicitly requested" : ( (double)diff >= cct->_conf->osd_scrub_max_interval ? ", diff >= max" : "")) << dendl; if (pg->sched_scrub()) { pg->unlock(); break; } } pg->unlock(); } } while (service.next_scrub_stamp(pos, &pos)); } dout(20) << "sched_scrub done" << dendl; } bool OSDService::inc_scrubs_pending() { bool result = false; sched_scrub_lock.Lock(); if (scrubs_pending + scrubs_active < cct->_conf->osd_max_scrubs) { dout(20) << "inc_scrubs_pending " << scrubs_pending << " -> " << (scrubs_pending+1) << " (max " << cct->_conf->osd_max_scrubs << ", active " << scrubs_active << ")" << dendl; result = true; ++scrubs_pending; } else { dout(20) << "inc_scrubs_pending " << scrubs_pending << " + " << scrubs_active << " active >= max " << cct->_conf->osd_max_scrubs << dendl; } sched_scrub_lock.Unlock(); return result; } void OSDService::dec_scrubs_pending() { sched_scrub_lock.Lock(); dout(20) << "dec_scrubs_pending " << scrubs_pending << " -> " << (scrubs_pending-1) << " (max " << cct->_conf->osd_max_scrubs << ", active " << scrubs_active << ")" << dendl; --scrubs_pending; assert(scrubs_pending >= 0); sched_scrub_lock.Unlock(); } void OSDService::inc_scrubs_active(bool reserved) { sched_scrub_lock.Lock(); ++(scrubs_active); if (reserved) { --(scrubs_pending); dout(20) << "inc_scrubs_active " << (scrubs_active-1) << " -> " << scrubs_active << " (max " << cct->_conf->osd_max_scrubs << ", pending " << (scrubs_pending+1) << " -> " << scrubs_pending << ")" << dendl; assert(scrubs_pending >= 0); } else { dout(20) << "inc_scrubs_active " << (scrubs_active-1) << " -> " << scrubs_active << " (max " << cct->_conf->osd_max_scrubs << ", pending " << scrubs_pending << ")" << dendl; } sched_scrub_lock.Unlock(); } void OSDService::dec_scrubs_active() { sched_scrub_lock.Lock(); dout(20) << "dec_scrubs_active " << scrubs_active << " -> " << (scrubs_active-1) << " (max " << cct->_conf->osd_max_scrubs << ", pending " << scrubs_pending << ")" << dendl; --scrubs_active; sched_scrub_lock.Unlock(); } bool OSDService::prepare_to_stop() { Mutex::Locker l(is_stopping_lock); if (state != NOT_STOPPING) return false; OSDMapRef osdmap = get_osdmap(); if (osdmap && osdmap->is_up(whoami)) { dout(0) << __func__ << " telling mon we are shutting down" << dendl; state = PREPARING_TO_STOP; monc->send_mon_message(new MOSDMarkMeDown(monc->get_fsid(), osdmap->get_inst(whoami), osdmap->get_epoch(), false )); utime_t now = ceph_clock_now(cct); utime_t timeout; timeout.set_from_double(now + cct->_conf->osd_mon_shutdown_timeout); while ((ceph_clock_now(cct) < timeout) && (state != STOPPING)) { is_stopping_cond.WaitUntil(is_stopping_lock, timeout); } } dout(0) << __func__ << " starting shutdown" << dendl; state = STOPPING; return true; } void OSDService::got_stop_ack() { Mutex::Locker l(is_stopping_lock); dout(0) << __func__ << " starting shutdown" << dendl; state = STOPPING; is_stopping_cond.Signal(); } // ===================================================== // MAP void OSD::wait_for_new_map(OpRequestRef op) { // ask? if (waiting_for_osdmap.empty()) { osdmap_subscribe(osdmap->get_epoch() + 1, true); } logger->inc(l_osd_waiting_for_map); waiting_for_osdmap.push_back(op); op->mark_delayed("wait for new map"); } /** update_map * assimilate new OSDMap(s). scan pgs, etc. */ void OSD::note_down_osd(int peer) { assert(osd_lock.is_locked()); cluster_messenger->mark_down(osdmap->get_cluster_addr(peer)); heartbeat_lock.Lock(); failure_queue.erase(peer); failure_pending.erase(peer); map::iterator p = heartbeat_peers.find(peer); if (p != heartbeat_peers.end()) { hbclient_messenger->mark_down(p->second.con_back); if (p->second.con_front) { hbclient_messenger->mark_down(p->second.con_front); } heartbeat_peers.erase(p); } heartbeat_lock.Unlock(); } void OSD::note_up_osd(int peer) { forget_peer_epoch(peer, osdmap->get_epoch() - 1); } struct C_OnMapApply : public Context { OSDService *service; boost::scoped_ptr t; list pinned_maps; epoch_t e; C_OnMapApply(OSDService *service, ObjectStore::Transaction *t, const list &pinned_maps, epoch_t e) : service(service), t(t), pinned_maps(pinned_maps), e(e) {} void finish(int r) { service->clear_map_bl_cache_pins(e); } }; void OSD::osdmap_subscribe(version_t epoch, bool force_request) { OSDMapRef osdmap = service.get_osdmap(); if (osdmap->get_epoch() >= epoch) return; if (monc->sub_want_increment("osdmap", epoch, CEPH_SUBSCRIBE_ONETIME) || force_request) { monc->renew_subs(); } } void OSD::handle_osd_map(MOSDMap *m) { assert(osd_lock.is_locked()); list pinned_maps; if (m->fsid != monc->get_fsid()) { dout(0) << "handle_osd_map fsid " << m->fsid << " != " << monc->get_fsid() << dendl; m->put(); return; } if (is_initializing()) { dout(0) << "ignoring osdmap until we have initialized" << dendl; m->put(); return; } Session *session = static_cast(m->get_connection()->get_priv()); if (session && !(session->entity_name.is_mon() || session->entity_name.is_osd())) { //not enough perms! m->put(); session->put(); return; } if (session) session->put(); // share with the objecter { Mutex::Locker l(service.objecter_lock); m->get(); service.objecter->handle_osd_map(m); } epoch_t first = m->get_first(); epoch_t last = m->get_last(); dout(3) << "handle_osd_map epochs [" << first << "," << last << "], i have " << osdmap->get_epoch() << ", src has [" << m->oldest_map << "," << m->newest_map << "]" << dendl; logger->inc(l_osd_map); logger->inc(l_osd_mape, last - first + 1); if (first <= osdmap->get_epoch()) logger->inc(l_osd_mape_dup, osdmap->get_epoch() - first + 1); // make sure there is something new, here, before we bother flushing the queues and such if (last <= osdmap->get_epoch()) { dout(10) << " no new maps here, dropping" << dendl; m->put(); return; } // even if this map isn't from a mon, we may have satisfied our subscription monc->sub_got("osdmap", last); // missing some? bool skip_maps = false; if (first > osdmap->get_epoch() + 1) { dout(10) << "handle_osd_map message skips epochs " << osdmap->get_epoch() + 1 << ".." << (first-1) << dendl; if (m->oldest_map <= osdmap->get_epoch() + 1) { osdmap_subscribe(osdmap->get_epoch()+1, true); m->put(); return; } // always try to get the full range of maps--as many as we can. this // 1- is good to have // 2- is at present the only way to ensure that we get a *full* map as // the first map! if (m->oldest_map < first) { osdmap_subscribe(m->oldest_map - 1, true); m->put(); return; } skip_maps = true; } ObjectStore::Transaction *_t = new ObjectStore::Transaction; ObjectStore::Transaction &t = *_t; // store new maps: queue for disk and put in the osdmap cache epoch_t last_marked_full = 0; epoch_t start = MAX(osdmap->get_epoch() + 1, first); for (epoch_t e = start; e <= last; e++) { map::iterator p; p = m->maps.find(e); if (p != m->maps.end()) { dout(10) << "handle_osd_map got full map for epoch " << e << dendl; OSDMap *o = new OSDMap; bufferlist& bl = p->second; o->decode(bl); if (o->test_flag(CEPH_OSDMAP_FULL)) last_marked_full = e; pinned_maps.push_back(add_map(o)); hobject_t fulloid = get_osdmap_pobject_name(e); t.write(coll_t::META_COLL, fulloid, 0, bl.length(), bl); pin_map_bl(e, bl); continue; } p = m->incremental_maps.find(e); if (p != m->incremental_maps.end()) { dout(10) << "handle_osd_map got inc map for epoch " << e << dendl; bufferlist& bl = p->second; hobject_t oid = get_inc_osdmap_pobject_name(e); t.write(coll_t::META_COLL, oid, 0, bl.length(), bl); pin_map_inc_bl(e, bl); OSDMap *o = new OSDMap; if (e > 1) { bufferlist obl; OSDMapRef prev = get_map(e - 1); prev->encode(obl); o->decode(obl); } OSDMap::Incremental inc; bufferlist::iterator p = bl.begin(); inc.decode(p); if (o->apply_incremental(inc) < 0) { derr << "ERROR: bad fsid? i have " << osdmap->get_fsid() << " and inc has " << inc.fsid << dendl; assert(0 == "bad fsid"); } if (o->test_flag(CEPH_OSDMAP_FULL)) last_marked_full = e; pinned_maps.push_back(add_map(o)); bufferlist fbl; o->encode(fbl); hobject_t fulloid = get_osdmap_pobject_name(e); t.write(coll_t::META_COLL, fulloid, 0, fbl.length(), fbl); pin_map_bl(e, fbl); continue; } assert(0 == "MOSDMap lied about what maps it had?"); } if (superblock.oldest_map) { int num = 0; epoch_t min( MIN(m->oldest_map, service.map_cache.cached_key_lower_bound())); for (epoch_t e = superblock.oldest_map; e < min; ++e) { dout(20) << " removing old osdmap epoch " << e << dendl; t.remove(coll_t::META_COLL, get_osdmap_pobject_name(e)); t.remove(coll_t::META_COLL, get_inc_osdmap_pobject_name(e)); superblock.oldest_map = e+1; num++; if (num >= cct->_conf->osd_target_transaction_size && (uint64_t)num > (last - first)) // make sure we at least keep pace with incoming maps break; } } if (!superblock.oldest_map || skip_maps) superblock.oldest_map = first; superblock.newest_map = last; if (last_marked_full > superblock.last_map_marked_full) superblock.last_map_marked_full = last_marked_full; map_lock.get_write(); C_Contexts *fin = new C_Contexts(cct); // advance through the new maps for (epoch_t cur = start; cur <= superblock.newest_map; cur++) { dout(10) << " advance to epoch " << cur << " (<= newest " << superblock.newest_map << ")" << dendl; OSDMapRef newmap = get_map(cur); assert(newmap); // we just cached it above! // start blacklisting messages sent to peers that go down. service.pre_publish_map(newmap); // kill connections to newly down osds set old; osdmap->get_all_osds(old); for (set::iterator p = old.begin(); p != old.end(); ++p) { if (*p != whoami && osdmap->have_inst(*p) && // in old map (!newmap->exists(*p) || !newmap->is_up(*p))) { // but not the new one note_down_osd(*p); } } osdmap = newmap; superblock.current_epoch = cur; advance_map(t, fin); had_map_since = ceph_clock_now(cct); } if (osdmap->is_up(whoami) && osdmap->get_addr(whoami) == client_messenger->get_myaddr() && bind_epoch < osdmap->get_up_from(whoami)) { if (is_booting()) { dout(1) << "state: booting -> active" << dendl; state = STATE_ACTIVE; // set incarnation so that osd_reqid_t's we generate for our // objecter requests are unique across restarts. service.objecter->set_client_incarnation(osdmap->get_epoch()); } } bool do_shutdown = false; bool do_restart = false; if (osdmap->get_epoch() > 0 && state == STATE_ACTIVE) { if (!osdmap->exists(whoami)) { dout(0) << "map says i do not exist. shutting down." << dendl; do_shutdown = true; // don't call shutdown() while we have everything paused } else if (!osdmap->is_up(whoami) || !osdmap->get_addr(whoami).probably_equals(client_messenger->get_myaddr()) || !osdmap->get_cluster_addr(whoami).probably_equals(cluster_messenger->get_myaddr()) || !osdmap->get_hb_back_addr(whoami).probably_equals(hb_back_server_messenger->get_myaddr()) || (osdmap->get_hb_front_addr(whoami) != entity_addr_t() && !osdmap->get_hb_front_addr(whoami).probably_equals(hb_front_server_messenger->get_myaddr()))) { if (!osdmap->is_up(whoami)) { if (service.is_preparing_to_stop() || service.is_stopping()) { service.got_stop_ack(); } else { clog.warn() << "map e" << osdmap->get_epoch() << " wrongly marked me down"; } } else if (!osdmap->get_addr(whoami).probably_equals(client_messenger->get_myaddr())) clog.error() << "map e" << osdmap->get_epoch() << " had wrong client addr (" << osdmap->get_addr(whoami) << " != my " << client_messenger->get_myaddr() << ")"; else if (!osdmap->get_cluster_addr(whoami).probably_equals(cluster_messenger->get_myaddr())) clog.error() << "map e" << osdmap->get_epoch() << " had wrong cluster addr (" << osdmap->get_cluster_addr(whoami) << " != my " << cluster_messenger->get_myaddr() << ")"; else if (!osdmap->get_hb_back_addr(whoami).probably_equals(hb_back_server_messenger->get_myaddr())) clog.error() << "map e" << osdmap->get_epoch() << " had wrong hb back addr (" << osdmap->get_hb_back_addr(whoami) << " != my " << hb_back_server_messenger->get_myaddr() << ")"; else if (osdmap->get_hb_front_addr(whoami) != entity_addr_t() && !osdmap->get_hb_front_addr(whoami).probably_equals(hb_front_server_messenger->get_myaddr())) clog.error() << "map e" << osdmap->get_epoch() << " had wrong hb front addr (" << osdmap->get_hb_front_addr(whoami) << " != my " << hb_front_server_messenger->get_myaddr() << ")"; if (!service.is_stopping()) { up_epoch = 0; do_restart = true; bind_epoch = osdmap->get_epoch(); start_waiting_for_healthy(); set avoid_ports; avoid_ports.insert(cluster_messenger->get_myaddr().get_port()); avoid_ports.insert(hb_back_server_messenger->get_myaddr().get_port()); avoid_ports.insert(hb_front_server_messenger->get_myaddr().get_port()); int r = cluster_messenger->rebind(avoid_ports); if (r != 0) do_shutdown = true; // FIXME: do_restart? r = hb_back_server_messenger->rebind(avoid_ports); if (r != 0) do_shutdown = true; // FIXME: do_restart? r = hb_front_server_messenger->rebind(avoid_ports); if (r != 0) do_shutdown = true; // FIXME: do_restart? hbclient_messenger->mark_down_all(); reset_heartbeat_peers(); } } } // note in the superblock that we were clean thru the prior epoch if (boot_epoch && boot_epoch >= superblock.mounted) { superblock.mounted = boot_epoch; superblock.clean_thru = osdmap->get_epoch(); } // superblock and commit write_superblock(t); store->queue_transaction( 0, _t, new C_OnMapApply(&service, _t, pinned_maps, osdmap->get_epoch()), 0, fin); service.publish_superblock(superblock); map_lock.put_write(); check_osdmap_features(store); // yay! consume_map(); if (is_active() || is_waiting_for_healthy()) maybe_update_heartbeat_peers(); if (!is_active()) { dout(10) << " not yet active; waiting for peering wq to drain" << dendl; peering_wq.drain(); } else { activate_map(); } if (m->newest_map && m->newest_map > last) { dout(10) << " msg say newest map is " << m->newest_map << ", requesting more" << dendl; osdmap_subscribe(osdmap->get_epoch()+1, true); } else if (is_booting()) { start_boot(); // retry } else if (do_restart) start_boot(); if (do_shutdown) shutdown(); m->put(); } void OSD::check_osdmap_features(ObjectStore *fs) { // adjust required feature bits? // we have to be a bit careful here, because we are accessing the // Policy structures without taking any lock. in particular, only // modify integer values that can safely be read by a racing CPU. // since we are only accessing existing Policy structures a their // current memory location, and setting or clearing bits in integer // fields, and we are the only writer, this is not a problem. { Messenger::Policy p = client_messenger->get_default_policy(); uint64_t mask; uint64_t features = osdmap->get_features(entity_name_t::TYPE_CLIENT, &mask); if ((p.features_required & mask) != features) { dout(0) << "crush map has features " << features << ", adjusting msgr requires for clients" << dendl; p.features_required = (p.features_required & ~mask) | features; client_messenger->set_default_policy(p); } } { Messenger::Policy p = client_messenger->get_policy(entity_name_t::TYPE_MON); uint64_t mask; uint64_t features = osdmap->get_features(entity_name_t::TYPE_MON, &mask); if ((p.features_required & mask) != features) { dout(0) << "crush map has features " << features << " was " << p.features_required << ", adjusting msgr requires for mons" << dendl; p.features_required = (p.features_required & ~mask) | features; client_messenger->set_policy(entity_name_t::TYPE_MON, p); } } { Messenger::Policy p = cluster_messenger->get_policy(entity_name_t::TYPE_OSD); uint64_t mask; uint64_t features = osdmap->get_features(entity_name_t::TYPE_OSD, &mask); if ((p.features_required & mask) != features) { dout(0) << "crush map has features " << features << ", adjusting msgr requires for osds" << dendl; p.features_required = (p.features_required & ~mask) | features; cluster_messenger->set_policy(entity_name_t::TYPE_OSD, p); } if ((features & CEPH_FEATURE_OSD_ERASURE_CODES) && !fs->get_allow_sharded_objects()) { dout(0) << __func__ << " enabling on-disk ERASURE CODES compat feature" << dendl; superblock.compat_features.incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); ObjectStore::Transaction *t = new ObjectStore::Transaction; write_superblock(*t); int err = store->queue_transaction_and_cleanup(NULL, t); assert(err == 0); fs->set_allow_sharded_objects(); } } } bool OSD::advance_pg( epoch_t osd_epoch, PG *pg, ThreadPool::TPHandle &handle, PG::RecoveryCtx *rctx, set > *new_pgs) { assert(pg->is_locked()); epoch_t next_epoch = pg->get_osdmap()->get_epoch() + 1; OSDMapRef lastmap = pg->get_osdmap(); if (lastmap->get_epoch() == osd_epoch) return true; assert(lastmap->get_epoch() < osd_epoch); epoch_t min_epoch = service.get_min_pg_epoch(); epoch_t max; if (min_epoch) { max = min_epoch + g_conf->osd_map_max_advance; } else { max = next_epoch + g_conf->osd_map_max_advance; } for (; next_epoch <= osd_epoch && next_epoch <= max; ++next_epoch) { OSDMapRef nextmap = service.try_get_map(next_epoch); if (!nextmap) { dout(20) << __func__ << " missing map " << next_epoch << dendl; // make sure max is bumped up so that we can get past any // gap in maps max = MAX(max, next_epoch + g_conf->osd_map_max_advance); continue; } vector newup, newacting; int up_primary, acting_primary; nextmap->pg_to_up_acting_osds( pg->info.pgid.pgid, &newup, &up_primary, &newacting, &acting_primary); pg->handle_advance_map( nextmap, lastmap, newup, up_primary, newacting, acting_primary, rctx); // Check for split! set children; spg_t parent(pg->info.pgid); if (parent.is_split( lastmap->get_pg_num(pg->pool.id), nextmap->get_pg_num(pg->pool.id), &children)) { service.mark_split_in_progress(pg->info.pgid, children); split_pgs( pg, children, new_pgs, lastmap, nextmap, rctx); } lastmap = nextmap; handle.reset_tp_timeout(); } service.pg_update_epoch(pg->info.pgid, lastmap->get_epoch()); pg->handle_activate_map(rctx); if (next_epoch <= osd_epoch) { dout(10) << __func__ << " advanced to max " << max << " past min epoch " << min_epoch << " ... will requeue " << *pg << dendl; return false; } return true; } /** * scan placement groups, initiate any replication * activities. */ void OSD::advance_map(ObjectStore::Transaction& t, C_Contexts *tfin) { assert(osd_lock.is_locked()); dout(7) << "advance_map epoch " << osdmap->get_epoch() << " " << pg_map.size() << " pgs" << dendl; if (!up_epoch && osdmap->is_up(whoami) && osdmap->get_inst(whoami) == client_messenger->get_myinst()) { up_epoch = osdmap->get_epoch(); dout(10) << "up_epoch is " << up_epoch << dendl; if (!boot_epoch) { boot_epoch = osdmap->get_epoch(); dout(10) << "boot_epoch is " << boot_epoch << dendl; } } // scan pg creations ceph::unordered_map::iterator n = creating_pgs.begin(); while (n != creating_pgs.end()) { ceph::unordered_map::iterator p = n++; spg_t pgid = p->first; // am i still primary? vector acting; int primary; osdmap->pg_to_acting_osds(pgid.pgid, &acting, &primary); if (primary != whoami) { dout(10) << " no longer primary for " << pgid << ", stopping creation" << dendl; creating_pgs.erase(p); } else { /* * adding new ppl to our pg has no effect, since we're still primary, * and obviously haven't given the new nodes any data. */ p->second.acting.swap(acting); // keep the latest } } // scan pgs with waiters map >::iterator p = waiting_for_pg.begin(); while (p != waiting_for_pg.end()) { spg_t pgid = p->first; if (osdmap->osd_is_valid_op_target(pgid.pgid, whoami)) { ++p; // still me } else { dout(10) << " discarding waiting ops for " << pgid << dendl; while (!p->second.empty()) { p->second.pop_front(); } waiting_for_pg.erase(p++); } } } void OSD::consume_map() { assert(osd_lock.is_locked()); dout(7) << "consume_map version " << osdmap->get_epoch() << dendl; int num_pg_primary = 0, num_pg_replica = 0, num_pg_stray = 0; list to_remove; // scan pg's for (ceph::unordered_map::iterator it = pg_map.begin(); it != pg_map.end(); ++it) { PG *pg = it->second; pg->lock(); if (pg->is_primary()) num_pg_primary++; else if (pg->is_replica()) num_pg_replica++; else num_pg_stray++; if (!osdmap->have_pg_pool(pg->info.pgid.pool())) { //pool is deleted! to_remove.push_back(PGRef(pg)); } else { service.init_splits_between(it->first, service.get_osdmap(), osdmap); } pg->unlock(); } for (list::iterator i = to_remove.begin(); i != to_remove.end(); to_remove.erase(i++)) { (*i)->lock(); _remove_pg(&**i); (*i)->unlock(); } to_remove.clear(); service.expand_pg_num(service.get_osdmap(), osdmap); service.pre_publish_map(osdmap); service.publish_map(osdmap); // scan pg's for (ceph::unordered_map::iterator it = pg_map.begin(); it != pg_map.end(); ++it) { PG *pg = it->second; pg->lock(); pg->queue_null(osdmap->get_epoch(), osdmap->get_epoch()); pg->unlock(); } logger->set(l_osd_pg, pg_map.size()); logger->set(l_osd_pg_primary, num_pg_primary); logger->set(l_osd_pg_replica, num_pg_replica); logger->set(l_osd_pg_stray, num_pg_stray); } void OSD::activate_map() { assert(osd_lock.is_locked()); dout(7) << "activate_map version " << osdmap->get_epoch() << dendl; wake_all_pg_waiters(); // the pg mapping may have shifted if (osdmap->test_flag(CEPH_OSDMAP_FULL)) { dout(10) << " osdmap flagged full, doing onetime osdmap subscribe" << dendl; osdmap_subscribe(osdmap->get_epoch() + 1, true); } // norecover? if (osdmap->test_flag(CEPH_OSDMAP_NORECOVER)) { if (!paused_recovery) { dout(1) << "pausing recovery (NORECOVER flag set)" << dendl; paused_recovery = true; recovery_tp.pause_new(); } } else { if (paused_recovery) { dout(1) << "resuming recovery (NORECOVER flag cleared)" << dendl; paused_recovery = false; recovery_tp.unpause(); } } service.activate_map(); // process waiters take_waiters(waiting_for_osdmap); } MOSDMap *OSD::build_incremental_map_msg(epoch_t since, epoch_t to) { MOSDMap *m = new MOSDMap(monc->get_fsid()); m->oldest_map = superblock.oldest_map; m->newest_map = superblock.newest_map; for (epoch_t e = to; e > since; e--) { bufferlist bl; if (e > m->oldest_map && get_inc_map_bl(e, bl)) { m->incremental_maps[e].claim(bl); } else if (get_map_bl(e, bl)) { m->maps[e].claim(bl); break; } else { derr << "since " << since << " to " << to << " oldest " << m->oldest_map << " newest " << m->newest_map << dendl; assert(0 == "missing an osdmap on disk"); // we should have all maps. } } return m; } void OSD::send_map(MOSDMap *m, Connection *con) { Messenger *msgr = client_messenger; if (entity_name_t::TYPE_OSD == con->get_peer_type()) msgr = cluster_messenger; msgr->send_message(m, con); } void OSD::send_incremental_map(epoch_t since, Connection *con) { epoch_t to = osdmap->get_epoch(); dout(10) << "send_incremental_map " << since << " -> " << to << " to " << con << " " << con->get_peer_addr() << dendl; if (since < superblock.oldest_map) { // just send latest full map MOSDMap *m = new MOSDMap(monc->get_fsid()); m->oldest_map = superblock.oldest_map; m->newest_map = superblock.newest_map; get_map_bl(to, m->maps[to]); send_map(m, con); return; } if (to > since && (int64_t)(to - since) > cct->_conf->osd_map_share_max_epochs) { dout(10) << " " << (to - since) << " > max " << cct->_conf->osd_map_share_max_epochs << ", only sending most recent" << dendl; since = to - cct->_conf->osd_map_share_max_epochs; } while (since < to) { if (to - since > (epoch_t)cct->_conf->osd_map_message_max) to = since + cct->_conf->osd_map_message_max; MOSDMap *m = build_incremental_map_msg(since, to); send_map(m, con); since = to; } } bool OSDService::_get_map_bl(epoch_t e, bufferlist& bl) { bool found = map_bl_cache.lookup(e, &bl); if (found) return true; found = store->read( coll_t::META_COLL, OSD::get_osdmap_pobject_name(e), 0, 0, bl) >= 0; if (found) _add_map_bl(e, bl); return found; } bool OSDService::get_inc_map_bl(epoch_t e, bufferlist& bl) { Mutex::Locker l(map_cache_lock); bool found = map_bl_inc_cache.lookup(e, &bl); if (found) return true; found = store->read( coll_t::META_COLL, OSD::get_inc_osdmap_pobject_name(e), 0, 0, bl) >= 0; if (found) _add_map_inc_bl(e, bl); return found; } void OSDService::_add_map_bl(epoch_t e, bufferlist& bl) { dout(10) << "add_map_bl " << e << " " << bl.length() << " bytes" << dendl; map_bl_cache.add(e, bl); } void OSDService::_add_map_inc_bl(epoch_t e, bufferlist& bl) { dout(10) << "add_map_inc_bl " << e << " " << bl.length() << " bytes" << dendl; map_bl_inc_cache.add(e, bl); } void OSDService::pin_map_inc_bl(epoch_t e, bufferlist &bl) { Mutex::Locker l(map_cache_lock); map_bl_inc_cache.pin(e, bl); } void OSDService::pin_map_bl(epoch_t e, bufferlist &bl) { Mutex::Locker l(map_cache_lock); map_bl_cache.pin(e, bl); } void OSDService::clear_map_bl_cache_pins(epoch_t e) { Mutex::Locker l(map_cache_lock); map_bl_inc_cache.clear_pinned(e); map_bl_cache.clear_pinned(e); } OSDMapRef OSDService::_add_map(OSDMap *o) { epoch_t e = o->get_epoch(); if (cct->_conf->osd_map_dedup) { // Dedup against an existing map at a nearby epoch OSDMapRef for_dedup = map_cache.lower_bound(e); if (for_dedup) { OSDMap::dedup(for_dedup.get(), o); } } OSDMapRef l = map_cache.add(e, o); return l; } OSDMapRef OSDService::try_get_map(epoch_t epoch) { Mutex::Locker l(map_cache_lock); OSDMapRef retval = map_cache.lookup(epoch); if (retval) { dout(30) << "get_map " << epoch << " -cached" << dendl; return retval; } OSDMap *map = new OSDMap; if (epoch > 0) { dout(20) << "get_map " << epoch << " - loading and decoding " << map << dendl; bufferlist bl; if (!_get_map_bl(epoch, bl)) { delete map; return OSDMapRef(); } map->decode(bl); } else { dout(20) << "get_map " << epoch << " - return initial " << map << dendl; } return _add_map(map); } bool OSD::require_mon_peer(Message *m) { if (!m->get_connection()->peer_is_mon()) { dout(0) << "require_mon_peer received from non-mon " << m->get_connection()->get_peer_addr() << " " << *m << dendl; m->put(); return false; } return true; } bool OSD::require_osd_peer(Message *m) { if (!m->get_connection()->peer_is_osd()) { dout(0) << "require_osd_peer received from non-osd " << m->get_connection()->get_peer_addr() << " " << *m << dendl; return false; } return true; } bool OSD::require_self_aliveness(Message *m, epoch_t epoch) { if (epoch < up_epoch) { dout(7) << "from pre-up epoch " << epoch << " < " << up_epoch << dendl; return false; } if (!is_active()) { dout(7) << "still in boot state, dropping message " << *m << dendl; return false; } return true; } bool OSD::require_same_peer_instance(Message *m, OSDMapRef& map) { int from = m->get_source().num(); if (!map->have_inst(from) || (map->get_cluster_addr(from) != m->get_source_inst().addr)) { dout(5) << "from dead osd." << from << ", marking down, " << " msg was " << m->get_source_inst().addr << " expected " << (map->have_inst(from) ? map->get_cluster_addr(from) : entity_addr_t()) << dendl; ConnectionRef con = m->get_connection(); cluster_messenger->mark_down(con.get()); Session *s = static_cast(con->get_priv()); if (s) { con->set_priv(NULL); // break ref <-> session cycle, if any s->put(); } return false; } return true; } bool OSD::require_up_osd_peer(Message *m, OSDMapRef& map, epoch_t their_epoch) { if (!require_self_aliveness(m, their_epoch)) { return false; } else if (!require_osd_peer(m)) { return false; } else if (map->get_epoch() >= their_epoch && !require_same_peer_instance(m, map)) { return false; } return true; } /* * require that we have same (or newer) map, and that * the source is the pg primary. */ bool OSD::require_same_or_newer_map(OpRequestRef& op, epoch_t epoch) { Message *m = op->get_req(); dout(15) << "require_same_or_newer_map " << epoch << " (i am " << osdmap->get_epoch() << ") " << m << dendl; assert(osd_lock.is_locked()); // do they have a newer map? if (epoch > osdmap->get_epoch()) { dout(7) << "waiting for newer map epoch " << epoch << " > my " << osdmap->get_epoch() << " with " << m << dendl; wait_for_new_map(op); return false; } if (!require_self_aliveness(op->get_req(), epoch)) { return false; } // ok, our map is same or newer.. do they still exist? if (m->get_connection()->get_messenger() == cluster_messenger && !require_same_peer_instance(op->get_req(), osdmap)) { return false; } return true; } // ---------------------------------------- // pg creation bool OSD::can_create_pg(spg_t pgid) { assert(creating_pgs.count(pgid)); // priors empty? if (!creating_pgs[pgid].prior.empty()) { dout(10) << "can_create_pg " << pgid << " - waiting for priors " << creating_pgs[pgid].prior << dendl; return false; } dout(10) << "can_create_pg " << pgid << " - can create now" << dendl; return true; } void OSD::split_pgs( PG *parent, const set &childpgids, set > *out_pgs, OSDMapRef curmap, OSDMapRef nextmap, PG::RecoveryCtx *rctx) { unsigned pg_num = nextmap->get_pg_num( parent->pool.id); parent->update_snap_mapper_bits( parent->info.pgid.get_split_bits(pg_num) ); vector updated_stats(childpgids.size() + 1); parent->info.stats.stats.sum.split(updated_stats); vector::iterator stat_iter = updated_stats.begin(); for (set::const_iterator i = childpgids.begin(); i != childpgids.end(); ++i, ++stat_iter) { assert(stat_iter != updated_stats.end()); dout(10) << "Splitting " << *parent << " into " << *i << dendl; assert(service.splitting(*i)); PG* child = _make_pg(nextmap, *i); child->lock(true); out_pgs->insert(child); unsigned split_bits = i->get_split_bits(pg_num); dout(10) << "pg_num is " << pg_num << dendl; dout(10) << "m_seed " << i->ps() << dendl; dout(10) << "split_bits is " << split_bits << dendl; parent->split_colls( *i, split_bits, i->ps(), rctx->transaction); parent->split_into( i->pgid, child, split_bits); child->info.stats.stats.sum = *stat_iter; child->write_if_dirty(*(rctx->transaction)); child->unlock(); } assert(stat_iter != updated_stats.end()); parent->info.stats.stats.sum = *stat_iter; parent->write_if_dirty(*(rctx->transaction)); } /* * holding osd_lock */ void OSD::handle_pg_create(OpRequestRef op) { MOSDPGCreate *m = (MOSDPGCreate*)op->get_req(); assert(m->get_header().type == MSG_OSD_PG_CREATE); dout(10) << "handle_pg_create " << *m << dendl; // drop the next N pg_creates in a row? if (debug_drop_pg_create_left < 0 && cct->_conf->osd_debug_drop_pg_create_probability > ((((double)(rand()%100))/100.0))) { debug_drop_pg_create_left = debug_drop_pg_create_duration; } if (debug_drop_pg_create_left >= 0) { --debug_drop_pg_create_left; if (debug_drop_pg_create_left >= 0) { dout(0) << "DEBUG dropping/ignoring pg_create, will drop the next " << debug_drop_pg_create_left << " too" << dendl; return; } } /* we have to hack around require_mon_peer's interface limits, so * grab an extra reference before going in. If the peer isn't * a Monitor, the reference is put for us (and then cleared * up automatically by our OpTracker infrastructure). Otherwise, * we put the extra ref ourself. */ if (!require_mon_peer(op->get_req()->get())) { return; } op->get_req()->put(); if (!require_same_or_newer_map(op, m->epoch)) return; op->mark_started(); int num_created = 0; for (map::iterator p = m->mkpg.begin(); p != m->mkpg.end(); ++p) { epoch_t created = p->second.created; pg_t parent = p->second.parent; if (p->second.split_bits) // Skip split pgs continue; pg_t on = p->first; if (on.preferred() >= 0) { dout(20) << "ignoring localized pg " << on << dendl; continue; } if (!osdmap->have_pg_pool(on.pool())) { dout(20) << "ignoring pg on deleted pool " << on << dendl; continue; } dout(20) << "mkpg " << on << " e" << created << dendl; // is it still ours? vector up, acting; int up_primary = -1; int acting_primary = -1; osdmap->pg_to_up_acting_osds(on, &up, &up_primary, &acting, &acting_primary); int role = osdmap->calc_pg_role(whoami, acting, acting.size()); if (up_primary != whoami) { dout(10) << "mkpg " << on << " not primary (role=" << role << "), skipping" << dendl; continue; } if (up != acting) { dout(10) << "mkpg " << on << " up " << up << " != acting " << acting << ", ignoring" << dendl; // we'll get a query soon anyway, since we know the pg // must exist. we can ignore this. continue; } spg_t pgid; bool mapped = osdmap->get_primary_shard(on, &pgid); assert(mapped); // does it already exist? if (_have_pg(pgid)) { dout(10) << "mkpg " << pgid << " already exists, skipping" << dendl; continue; } // figure history pg_history_t history; history.epoch_created = created; history.last_epoch_clean = created; // Newly created PGs don't need to scrub immediately, so mark them // as scrubbed at creation time. utime_t now = ceph_clock_now(NULL); history.last_scrub_stamp = now; history.last_deep_scrub_stamp = now; bool valid_history = project_pg_history( pgid, history, created, up, up_primary, acting, acting_primary); /* the pg creation message must have come from a mon and therefore * cannot be on the other side of a map gap */ assert(valid_history); // register. creating_pgs[pgid].history = history; creating_pgs[pgid].parent = parent; creating_pgs[pgid].acting.swap(acting); calc_priors_during(pgid, created, history.same_interval_since, creating_pgs[pgid].prior); PG::RecoveryCtx rctx = create_context(); // poll priors set& pset = creating_pgs[pgid].prior; dout(10) << "mkpg " << pgid << " e" << created << " h " << history << " : querying priors " << pset << dendl; for (set::iterator p = pset.begin(); p != pset.end(); ++p) if (osdmap->is_up(p->osd)) (*rctx.query_map)[p->osd][spg_t(pgid.pgid, p->shard)] = pg_query_t( pg_query_t::INFO, p->shard, pgid.shard, history, osdmap->get_epoch()); PG *pg = NULL; if (can_create_pg(pgid)) { pg_interval_map_t pi; rctx.transaction->create_collection(coll_t(pgid)); pg = _create_lock_pg( osdmap, pgid, true, false, false, 0, creating_pgs[pgid].acting, whoami, creating_pgs[pgid].acting, whoami, history, pi, *rctx.transaction); pg->info.last_epoch_started = pg->info.history.last_epoch_started; creating_pgs.erase(pgid); wake_pg_waiters(pg->info.pgid); pg->handle_create(&rctx); pg->write_if_dirty(*rctx.transaction); pg->publish_stats_to_osd(); pg->unlock(); num_created++; } dispatch_context(rctx, pg, osdmap); } maybe_update_heartbeat_peers(); } // ---------------------------------------- // peering and recovery PG::RecoveryCtx OSD::create_context() { ObjectStore::Transaction *t = new ObjectStore::Transaction; C_Contexts *on_applied = new C_Contexts(cct); C_Contexts *on_safe = new C_Contexts(cct); map > *query_map = new map >; map > > *notify_list = new map > >; map > > *info_map = new map > >; PG::RecoveryCtx rctx(query_map, info_map, notify_list, on_applied, on_safe, t); return rctx; } void OSD::dispatch_context_transaction(PG::RecoveryCtx &ctx, PG *pg, ThreadPool::TPHandle *handle) { if (!ctx.transaction->empty()) { ctx.on_applied->add(new ObjectStore::C_DeleteTransaction(ctx.transaction)); int tr = store->queue_transaction( pg->osr.get(), ctx.transaction, ctx.on_applied, ctx.on_safe, NULL, TrackedOpRef(), handle); assert(tr == 0); ctx.transaction = new ObjectStore::Transaction; ctx.on_applied = new C_Contexts(cct); ctx.on_safe = new C_Contexts(cct); } } bool OSD::compat_must_dispatch_immediately(PG *pg) { assert(pg->is_locked()); set tmpacting; if (!pg->actingbackfill.empty()) { tmpacting = pg->actingbackfill; } else { for (unsigned i = 0; i < pg->acting.size(); ++i) { tmpacting.insert( pg_shard_t( pg->acting[i], pg->pool.info.ec_pool() ? i : ghobject_t::NO_SHARD)); } } for (set::iterator i = tmpacting.begin(); i != tmpacting.end(); ++i) { if (i->osd == whoami) continue; ConnectionRef conn = service.get_con_osd_cluster(i->osd, pg->get_osdmap()->get_epoch()); if (conn && !conn->has_feature(CEPH_FEATURE_INDEP_PG_MAP)) { return true; } } return false; } void OSD::dispatch_context(PG::RecoveryCtx &ctx, PG *pg, OSDMapRef curmap, ThreadPool::TPHandle *handle) { if (service.get_osdmap()->is_up(whoami) && is_active()) { do_notifies(*ctx.notify_list, curmap); do_queries(*ctx.query_map, curmap); do_infos(*ctx.info_map, curmap); } delete ctx.notify_list; delete ctx.query_map; delete ctx.info_map; if ((ctx.on_applied->empty() && ctx.on_safe->empty() && ctx.transaction->empty()) || !pg) { delete ctx.transaction; delete ctx.on_applied; delete ctx.on_safe; } else { ctx.on_applied->add(new ObjectStore::C_DeleteTransaction(ctx.transaction)); int tr = store->queue_transaction( pg->osr.get(), ctx.transaction, ctx.on_applied, ctx.on_safe, NULL, TrackedOpRef(), handle); assert(tr == 0); } } /** do_notifies * Send an MOSDPGNotify to a primary, with a list of PGs that I have * content for, and they are primary for. */ void OSD::do_notifies( map > >& notify_list, OSDMapRef curmap) { for (map > >::iterator it = notify_list.begin(); it != notify_list.end(); ++it) { if (!curmap->is_up(it->first)) continue; ConnectionRef con = service.get_con_osd_cluster( it->first, curmap->get_epoch()); if (!con) continue; _share_map_outgoing(it->first, con.get(), curmap); if (con->has_feature(CEPH_FEATURE_INDEP_PG_MAP)) { dout(7) << "do_notify osd " << it->first << " on " << it->second.size() << " PGs" << dendl; MOSDPGNotify *m = new MOSDPGNotify(curmap->get_epoch(), it->second); cluster_messenger->send_message(m, con.get()); } else { dout(7) << "do_notify osd " << it->first << " sending separate messages" << dendl; for (vector >::iterator i = it->second.begin(); i != it->second.end(); ++i) { vector > list(1); list[0] = *i; MOSDPGNotify *m = new MOSDPGNotify(i->first.epoch_sent, list); cluster_messenger->send_message(m, con.get()); } } } } /** do_queries * send out pending queries for info | summaries */ void OSD::do_queries(map >& query_map, OSDMapRef curmap) { for (map >::iterator pit = query_map.begin(); pit != query_map.end(); ++pit) { if (!curmap->is_up(pit->first)) continue; int who = pit->first; ConnectionRef con = service.get_con_osd_cluster(who, curmap->get_epoch()); if (!con) continue; _share_map_outgoing(who, con.get(), curmap); if (con->has_feature(CEPH_FEATURE_INDEP_PG_MAP)) { dout(7) << "do_queries querying osd." << who << " on " << pit->second.size() << " PGs" << dendl; MOSDPGQuery *m = new MOSDPGQuery(curmap->get_epoch(), pit->second); cluster_messenger->send_message(m, con.get()); } else { dout(7) << "do_queries querying osd." << who << " sending saperate messages " << " on " << pit->second.size() << " PGs" << dendl; for (map::iterator i = pit->second.begin(); i != pit->second.end(); ++i) { map to_send; to_send.insert(*i); MOSDPGQuery *m = new MOSDPGQuery(i->second.epoch_sent, to_send); cluster_messenger->send_message(m, con.get()); } } } } void OSD::do_infos(map > >& info_map, OSDMapRef curmap) { for (map > >::iterator p = info_map.begin(); p != info_map.end(); ++p) { if (!curmap->is_up(p->first)) continue; for (vector >::iterator i = p->second.begin(); i != p->second.end(); ++i) { dout(20) << "Sending info " << i->first.info << " to shard " << p->first << dendl; } ConnectionRef con = service.get_con_osd_cluster( p->first, curmap->get_epoch()); if (!con) continue; _share_map_outgoing(p->first, con.get(), curmap); if (con->has_feature(CEPH_FEATURE_INDEP_PG_MAP)) { MOSDPGInfo *m = new MOSDPGInfo(curmap->get_epoch()); m->pg_list = p->second; cluster_messenger->send_message(m, con.get()); } else { for (vector >::iterator i = p->second.begin(); i != p->second.end(); ++i) { vector > to_send(1); to_send[0] = *i; MOSDPGInfo *m = new MOSDPGInfo(i->first.epoch_sent); m->pg_list = to_send; cluster_messenger->send_message(m, con.get()); } } } info_map.clear(); } /** PGNotify * from non-primary to primary * includes pg_info_t. * NOTE: called with opqueue active. */ void OSD::handle_pg_notify(OpRequestRef op) { MOSDPGNotify *m = (MOSDPGNotify*)op->get_req(); assert(m->get_header().type == MSG_OSD_PG_NOTIFY); dout(7) << "handle_pg_notify from " << m->get_source() << dendl; int from = m->get_source().num(); if (!require_osd_peer(op->get_req())) return; if (!require_same_or_newer_map(op, m->get_epoch())) return; op->mark_started(); for (vector >::iterator it = m->get_pg_list().begin(); it != m->get_pg_list().end(); ++it) { if (it->first.info.pgid.preferred() >= 0) { dout(20) << "ignoring localized pg " << it->first.info.pgid << dendl; continue; } handle_pg_peering_evt( spg_t(it->first.info.pgid.pgid, it->first.to), it->first.info, it->second, it->first.query_epoch, pg_shard_t(from, it->first.from), true, PG::CephPeeringEvtRef( new PG::CephPeeringEvt( it->first.epoch_sent, it->first.query_epoch, PG::MNotifyRec(pg_shard_t(from, it->first.from), it->first, op->get_req()->get_connection()->get_features()))) ); } } void OSD::handle_pg_log(OpRequestRef op) { MOSDPGLog *m = (MOSDPGLog*) op->get_req(); assert(m->get_header().type == MSG_OSD_PG_LOG); dout(7) << "handle_pg_log " << *m << " from " << m->get_source() << dendl; if (!require_osd_peer(op->get_req())) return; int from = m->get_source().num(); if (!require_same_or_newer_map(op, m->get_epoch())) return; if (m->info.pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << m->info.pgid << dendl; return; } op->mark_started(); handle_pg_peering_evt( spg_t(m->info.pgid.pgid, m->to), m->info, m->past_intervals, m->get_epoch(), pg_shard_t(from, m->from), false, PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->get_epoch(), m->get_query_epoch(), PG::MLogRec(pg_shard_t(from, m->from), m))) ); } void OSD::handle_pg_info(OpRequestRef op) { MOSDPGInfo *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_INFO); dout(7) << "handle_pg_info " << *m << " from " << m->get_source() << dendl; if (!require_osd_peer(op->get_req())) return; int from = m->get_source().num(); if (!require_same_or_newer_map(op, m->get_epoch())) return; op->mark_started(); for (vector >::iterator p = m->pg_list.begin(); p != m->pg_list.end(); ++p) { if (p->first.info.pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << p->first.info.pgid << dendl; continue; } handle_pg_peering_evt( spg_t(p->first.info.pgid.pgid, p->first.to), p->first.info, p->second, p->first.epoch_sent, pg_shard_t(from, p->first.from), false, PG::CephPeeringEvtRef( new PG::CephPeeringEvt( p->first.epoch_sent, p->first.query_epoch, PG::MInfoRec( pg_shard_t( from, p->first.from), p->first.info, p->first.epoch_sent))) ); } } void OSD::handle_pg_trim(OpRequestRef op) { MOSDPGTrim *m = (MOSDPGTrim *)op->get_req(); assert(m->get_header().type == MSG_OSD_PG_TRIM); dout(7) << "handle_pg_trim " << *m << " from " << m->get_source() << dendl; if (!require_osd_peer(op->get_req())) return; int from = m->get_source().num(); if (!require_same_or_newer_map(op, m->epoch)) return; if (m->pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << m->pgid << dendl; return; } op->mark_started(); if (!_have_pg(m->pgid)) { dout(10) << " don't have pg " << m->pgid << dendl; } else { PG *pg = _lookup_lock_pg(m->pgid); if (m->epoch < pg->info.history.same_interval_since) { dout(10) << *pg << " got old trim to " << m->trim_to << ", ignoring" << dendl; pg->unlock(); return; } assert(pg); if (pg->is_primary()) { // peer is informing us of their last_complete_ondisk dout(10) << *pg << " replica osd." << from << " lcod " << m->trim_to << dendl; pg->peer_last_complete_ondisk[pg_shard_t(from, m->pgid.shard)] = m->trim_to; if (pg->calc_min_last_complete_ondisk()) { dout(10) << *pg << " min lcod now " << pg->min_last_complete_ondisk << dendl; pg->trim_peers(); } } else { // primary is instructing us to trim ObjectStore::Transaction *t = new ObjectStore::Transaction; PG::PGLogEntryHandler handler; pg->pg_log.trim(&handler, m->trim_to, pg->info); handler.apply(pg, t); pg->dirty_info = true; pg->write_if_dirty(*t); int tr = store->queue_transaction( pg->osr.get(), t, new ObjectStore::C_DeleteTransaction(t)); assert(tr == 0); } pg->unlock(); } } void OSD::handle_pg_scan(OpRequestRef op) { MOSDPGScan *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_SCAN); dout(10) << "handle_pg_scan " << *m << " from " << m->get_source() << dendl; if (!require_osd_peer(op->get_req())) return; if (!require_same_or_newer_map(op, m->query_epoch)) return; if (m->pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << m->pgid << dendl; return; } PG *pg; if (!_have_pg(m->pgid)) { return; } pg = _lookup_pg(m->pgid); assert(pg); enqueue_op(pg, op); } void OSD::handle_pg_backfill(OpRequestRef op) { MOSDPGBackfill *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_BACKFILL); dout(10) << "handle_pg_backfill " << *m << " from " << m->get_source() << dendl; if (!require_osd_peer(op->get_req())) return; if (!require_same_or_newer_map(op, m->query_epoch)) return; if (m->pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << m->pgid << dendl; return; } PG *pg; if (!_have_pg(m->pgid)) { return; } pg = _lookup_pg(m->pgid); assert(pg); enqueue_op(pg, op); } void OSD::handle_pg_backfill_reserve(OpRequestRef op) { MBackfillReserve *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_BACKFILL_RESERVE); if (!require_osd_peer(op->get_req())) return; if (!require_same_or_newer_map(op, m->query_epoch)) return; PG::CephPeeringEvtRef evt; if (m->type == MBackfillReserve::REQUEST) { evt = PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->query_epoch, m->query_epoch, PG::RequestBackfillPrio(m->priority))); } else if (m->type == MBackfillReserve::GRANT) { evt = PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->query_epoch, m->query_epoch, PG::RemoteBackfillReserved())); } else if (m->type == MBackfillReserve::REJECT) { evt = PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->query_epoch, m->query_epoch, PG::RemoteReservationRejected())); } else { assert(0); } if (service.splitting(m->pgid)) { peering_wait_for_split[m->pgid].push_back(evt); return; } PG *pg = 0; if (!_have_pg(m->pgid)) return; pg = _lookup_lock_pg(m->pgid); assert(pg); pg->queue_peering_event(evt); pg->unlock(); } void OSD::handle_pg_recovery_reserve(OpRequestRef op) { MRecoveryReserve *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_RECOVERY_RESERVE); if (!require_osd_peer(op->get_req())) return; if (!require_same_or_newer_map(op, m->query_epoch)) return; PG::CephPeeringEvtRef evt; if (m->type == MRecoveryReserve::REQUEST) { evt = PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->query_epoch, m->query_epoch, PG::RequestRecovery())); } else if (m->type == MRecoveryReserve::GRANT) { evt = PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->query_epoch, m->query_epoch, PG::RemoteRecoveryReserved())); } else if (m->type == MRecoveryReserve::RELEASE) { evt = PG::CephPeeringEvtRef( new PG::CephPeeringEvt( m->query_epoch, m->query_epoch, PG::RecoveryDone())); } else { assert(0); } if (service.splitting(m->pgid)) { peering_wait_for_split[m->pgid].push_back(evt); return; } PG *pg = 0; if (!_have_pg(m->pgid)) return; pg = _lookup_lock_pg(m->pgid); assert(pg); pg->queue_peering_event(evt); pg->unlock(); } /** PGQuery * from primary to replica | stray * NOTE: called with opqueue active. */ void OSD::handle_pg_query(OpRequestRef op) { assert(osd_lock.is_locked()); MOSDPGQuery *m = (MOSDPGQuery*)op->get_req(); assert(m->get_header().type == MSG_OSD_PG_QUERY); if (!require_osd_peer(op->get_req())) return; dout(7) << "handle_pg_query from " << m->get_source() << " epoch " << m->get_epoch() << dendl; int from = m->get_source().num(); if (!require_same_or_newer_map(op, m->get_epoch())) return; op->mark_started(); map< int, vector > > notify_list; for (map::iterator it = m->pg_list.begin(); it != m->pg_list.end(); ++it) { spg_t pgid = it->first; if (pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << pgid << dendl; continue; } if (service.splitting(pgid)) { peering_wait_for_split[pgid].push_back( PG::CephPeeringEvtRef( new PG::CephPeeringEvt( it->second.epoch_sent, it->second.epoch_sent, PG::MQuery(pg_shard_t(from, it->second.from), it->second, it->second.epoch_sent)))); continue; } if (pg_map.count(pgid)) { PG *pg = 0; pg = _lookup_lock_pg(pgid); pg->queue_query( it->second.epoch_sent, it->second.epoch_sent, pg_shard_t(from, it->second.from), it->second); pg->unlock(); continue; } if (!osdmap->have_pg_pool(pgid.pool())) continue; // get active crush mapping int up_primary, acting_primary; vector up, acting; osdmap->pg_to_up_acting_osds( pgid.pgid, &up, &up_primary, &acting, &acting_primary); // same primary? pg_history_t history = it->second.history; bool valid_history = project_pg_history( pgid, history, it->second.epoch_sent, up, up_primary, acting, acting_primary); if (!valid_history || it->second.epoch_sent < history.same_interval_since) { dout(10) << " pg " << pgid << " dne, and pg has changed in " << history.same_interval_since << " (msg from " << it->second.epoch_sent << ")" << dendl; continue; } dout(10) << " pg " << pgid << " dne" << dendl; pg_info_t empty(spg_t(pgid.pgid, it->second.to)); /* This is racy, but that should be ok: if we complete the deletion * before the pg is recreated, we'll just start it off backfilling * instead of just empty */ if (service.deleting_pgs.lookup(pgid)) empty.last_backfill = hobject_t(); if (it->second.type == pg_query_t::LOG || it->second.type == pg_query_t::FULLLOG) { ConnectionRef con = service.get_con_osd_cluster(from, osdmap->get_epoch()); if (con) { MOSDPGLog *mlog = new MOSDPGLog( it->second.from, it->second.to, osdmap->get_epoch(), empty, it->second.epoch_sent); _share_map_outgoing(from, con.get(), osdmap); cluster_messenger->send_message(mlog, con.get()); } } else { notify_list[from].push_back( make_pair( pg_notify_t( it->second.from, it->second.to, it->second.epoch_sent, osdmap->get_epoch(), empty), pg_interval_map_t())); } } do_notifies(notify_list, osdmap); } void OSD::handle_pg_remove(OpRequestRef op) { MOSDPGRemove *m = (MOSDPGRemove *)op->get_req(); assert(m->get_header().type == MSG_OSD_PG_REMOVE); assert(osd_lock.is_locked()); if (!require_osd_peer(op->get_req())) return; dout(7) << "handle_pg_remove from " << m->get_source() << " on " << m->pg_list.size() << " pgs" << dendl; if (!require_same_or_newer_map(op, m->get_epoch())) return; op->mark_started(); for (vector::iterator it = m->pg_list.begin(); it != m->pg_list.end(); ++it) { spg_t pgid = *it; if (pgid.preferred() >= 0) { dout(10) << "ignoring localized pg " << pgid << dendl; continue; } if (pg_map.count(pgid) == 0) { dout(10) << " don't have pg " << pgid << dendl; continue; } dout(5) << "queue_pg_for_deletion: " << pgid << dendl; PG *pg = _lookup_lock_pg(pgid); pg_history_t history = pg->info.history; int up_primary, acting_primary; vector up, acting; osdmap->pg_to_up_acting_osds( pgid.pgid, &up, &up_primary, &acting, &acting_primary); bool valid_history = project_pg_history( pg->info.pgid, history, pg->get_osdmap()->get_epoch(), up, up_primary, acting, acting_primary); if (valid_history && history.same_interval_since <= m->get_epoch()) { assert(pg->get_primary().osd == m->get_source().num()); PGRef _pg(pg); _remove_pg(pg); pg->unlock(); } else { dout(10) << *pg << " ignoring remove request, pg changed in epoch " << history.same_interval_since << " > " << m->get_epoch() << dendl; pg->unlock(); } } } void OSD::_remove_pg(PG *pg) { ObjectStore::Transaction *rmt = new ObjectStore::Transaction; // on_removal, which calls remove_watchers_and_notifies, and the erasure from // the pg_map must be done together without unlocking the pg lock, // to avoid racing with watcher cleanup in ms_handle_reset // and handle_notify_timeout pg->on_removal(rmt); service.cancel_pending_splits_for_parent(pg->info.pgid); store->queue_transaction( pg->osr.get(), rmt, new ObjectStore::C_DeleteTransactionHolder< SequencerRef>(rmt, pg->osr), new ContainerContext< SequencerRef>(pg->osr)); DeletingStateRef deleting = service.deleting_pgs.lookup_or_create( pg->info.pgid, make_pair( pg->info.pgid, PGRef(pg)) ); remove_wq.queue(make_pair(PGRef(pg), deleting)); service.pg_remove_epoch(pg->info.pgid); // remove from map pg_map.erase(pg->info.pgid); pg->put("PGMap"); // since we've taken it out of map } // ========================================================= // RECOVERY /* * caller holds osd_lock */ void OSD::check_replay_queue() { assert(osd_lock.is_locked()); utime_t now = ceph_clock_now(cct); list< pair > pgids; replay_queue_lock.Lock(); while (!replay_queue.empty() && replay_queue.front().second <= now) { pgids.push_back(replay_queue.front()); replay_queue.pop_front(); } replay_queue_lock.Unlock(); for (list< pair >::iterator p = pgids.begin(); p != pgids.end(); ++p) { spg_t pgid = p->first; if (pg_map.count(pgid)) { PG *pg = _lookup_lock_pg_with_map_lock_held(pgid); dout(10) << "check_replay_queue " << *pg << dendl; if (pg->is_active() && pg->is_replay() && pg->is_primary() && pg->replay_until == p->second) { pg->replay_queued_ops(); } pg->unlock(); } else { dout(10) << "check_replay_queue pgid " << pgid << " (not found)" << dendl; } } // wake up _all_ pg waiters; raw pg -> actual pg mapping may have shifted wake_all_pg_waiters(); } bool OSDService::queue_for_recovery(PG *pg) { bool b = recovery_wq.queue(pg); if (b) dout(10) << "queue_for_recovery queued " << *pg << dendl; else dout(10) << "queue_for_recovery already queued " << *pg << dendl; return b; } bool OSD::_recover_now() { if (recovery_ops_active >= cct->_conf->osd_recovery_max_active) { dout(15) << "_recover_now active " << recovery_ops_active << " >= max " << cct->_conf->osd_recovery_max_active << dendl; return false; } if (ceph_clock_now(cct) < defer_recovery_until) { dout(15) << "_recover_now defer until " << defer_recovery_until << dendl; return false; } return true; } void OSD::do_recovery(PG *pg, ThreadPool::TPHandle &handle) { // see how many we should try to start. note that this is a bit racy. recovery_wq.lock(); int max = MIN(cct->_conf->osd_recovery_max_active - recovery_ops_active, cct->_conf->osd_recovery_max_single_start); if (max > 0) { dout(10) << "do_recovery can start " << max << " (" << recovery_ops_active << "/" << cct->_conf->osd_recovery_max_active << " rops)" << dendl; recovery_ops_active += max; // take them now, return them if we don't use them. } else { dout(10) << "do_recovery can start 0 (" << recovery_ops_active << "/" << cct->_conf->osd_recovery_max_active << " rops)" << dendl; } recovery_wq.unlock(); if (max <= 0) { dout(10) << "do_recovery raced and failed to start anything; requeuing " << *pg << dendl; recovery_wq.queue(pg); return; } else { pg->lock_suspend_timeout(handle); if (pg->deleting || !(pg->is_active() && pg->is_primary())) { pg->unlock(); goto out; } dout(10) << "do_recovery starting " << max << " " << *pg << dendl; #ifdef DEBUG_RECOVERY_OIDS dout(20) << " active was " << recovery_oids[pg->info.pgid] << dendl; #endif PG::RecoveryCtx rctx = create_context(); int started; bool more = pg->start_recovery_ops(max, &rctx, handle, &started); dout(10) << "do_recovery started " << started << "/" << max << " on " << *pg << dendl; /* * if we couldn't start any recovery ops and things are still * unfound, see if we can discover more missing object locations. * It may be that our initial locations were bad and we errored * out while trying to pull. */ if (!more && pg->have_unfound()) { pg->discover_all_missing(*rctx.query_map); if (rctx.query_map->empty()) { dout(10) << "do_recovery no luck, giving up on this pg for now" << dendl; recovery_wq.lock(); recovery_wq._dequeue(pg); recovery_wq.unlock(); } } pg->write_if_dirty(*rctx.transaction); OSDMapRef curmap = pg->get_osdmap(); pg->unlock(); dispatch_context(rctx, pg, curmap); } out: recovery_wq.lock(); if (max > 0) { assert(recovery_ops_active >= max); recovery_ops_active -= max; } recovery_wq._wake(); recovery_wq.unlock(); } void OSD::start_recovery_op(PG *pg, const hobject_t& soid) { recovery_wq.lock(); dout(10) << "start_recovery_op " << *pg << " " << soid << " (" << recovery_ops_active << "/" << cct->_conf->osd_recovery_max_active << " rops)" << dendl; assert(recovery_ops_active >= 0); recovery_ops_active++; #ifdef DEBUG_RECOVERY_OIDS dout(20) << " active was " << recovery_oids[pg->info.pgid] << dendl; assert(recovery_oids[pg->info.pgid].count(soid) == 0); recovery_oids[pg->info.pgid].insert(soid); #endif recovery_wq.unlock(); } void OSD::finish_recovery_op(PG *pg, const hobject_t& soid, bool dequeue) { recovery_wq.lock(); dout(10) << "finish_recovery_op " << *pg << " " << soid << " dequeue=" << dequeue << " (" << recovery_ops_active << "/" << cct->_conf->osd_recovery_max_active << " rops)" << dendl; // adjust count recovery_ops_active--; assert(recovery_ops_active >= 0); #ifdef DEBUG_RECOVERY_OIDS dout(20) << " active oids was " << recovery_oids[pg->info.pgid] << dendl; assert(recovery_oids[pg->info.pgid].count(soid)); recovery_oids[pg->info.pgid].erase(soid); #endif if (dequeue) recovery_wq._dequeue(pg); else { recovery_wq._queue_front(pg); } recovery_wq._wake(); recovery_wq.unlock(); } // ========================================================= // OPS void OSDService::reply_op_error(OpRequestRef op, int err) { reply_op_error(op, err, eversion_t(), 0); } void OSDService::reply_op_error(OpRequestRef op, int err, eversion_t v, version_t uv) { MOSDOp *m = static_cast(op->get_req()); assert(m->get_header().type == CEPH_MSG_OSD_OP); int flags; flags = m->get_flags() & (CEPH_OSD_FLAG_ACK|CEPH_OSD_FLAG_ONDISK); MOSDOpReply *reply = new MOSDOpReply(m, err, osdmap->get_epoch(), flags, true); reply->set_reply_versions(v, uv); m->get_connection()->get_messenger()->send_message(reply, m->get_connection()); } void OSDService::handle_misdirected_op(PG *pg, OpRequestRef op) { MOSDOp *m = static_cast(op->get_req()); assert(m->get_header().type == CEPH_MSG_OSD_OP); assert(m->get_map_epoch() >= pg->info.history.same_primary_since); if (pg->is_ec_pg()) { /** * OSD recomputes op target based on current OSDMap. With an EC pg, we * can get this result: * 1) client at map 512 sends an op to osd 3, pg_t 3.9 based on mapping * [CRUSH_ITEM_NONE, 2, 3]/3 * 2) OSD 3 at map 513 remaps op to osd 3, spg_t 3.9s0 based on mapping * [3, 2, 3]/3 * 3) PG 3.9s0 dequeues the op at epoch 512 and notices that it isn't primary * -- misdirected op * 4) client resends and this time PG 3.9s0 having caught up to 513 gets * it and fulfils it * * We can't compute the op target based on the sending map epoch due to * splitting. The simplest thing is to detect such cases here and drop * them without an error (the client will resend anyway). */ OSDMapRef opmap = try_get_map(m->get_map_epoch()); if (!opmap) { dout(7) << __func__ << ": " << *pg << " no longer have map for " << m->get_map_epoch() << ", dropping" << dendl; return; } pg_t _pgid = m->get_pg(); spg_t pgid; if ((m->get_flags() & CEPH_OSD_FLAG_PGOP) == 0) _pgid = opmap->raw_pg_to_pg(_pgid); if (opmap->get_primary_shard(_pgid, &pgid) && pgid.shard != pg->info.pgid.shard) { dout(7) << __func__ << ": " << *pg << " primary changed since " << m->get_map_epoch() << ", dropping" << dendl; return; } } dout(7) << *pg << " misdirected op in " << m->get_map_epoch() << dendl; clog.warn() << m->get_source_inst() << " misdirected " << m->get_reqid() << " pg " << m->get_pg() << " to osd." << whoami << " not " << pg->acting << " in e" << m->get_map_epoch() << "/" << osdmap->get_epoch() << "\n"; reply_op_error(op, -ENXIO); } void OSD::handle_op(OpRequestRef op) { MOSDOp *m = static_cast(op->get_req()); assert(m->get_header().type == CEPH_MSG_OSD_OP); if (op_is_discardable(m)) { dout(10) << " discardable " << *m << dendl; return; } // we don't need encoded payload anymore m->clear_payload(); // require same or newer map if (!require_same_or_newer_map(op, m->get_map_epoch())) return; // object name too long? if (m->get_oid().name.size() > MAX_CEPH_OBJECT_NAME_LEN) { dout(4) << "handle_op '" << m->get_oid().name << "' is longer than " << MAX_CEPH_OBJECT_NAME_LEN << " bytes!" << dendl; service.reply_op_error(op, -ENAMETOOLONG); return; } // blacklisted? if (osdmap->is_blacklisted(m->get_source_addr())) { dout(4) << "handle_op " << m->get_source_addr() << " is blacklisted" << dendl; service.reply_op_error(op, -EBLACKLISTED); return; } // share our map with sender, if they're old _share_map_incoming(m->get_source(), m->get_connection().get(), m->get_map_epoch(), static_cast(m->get_connection()->get_priv())); if (op->rmw_flags == 0) { int r = init_op_flags(op); if (r) { service.reply_op_error(op, r); return; } } if (cct->_conf->osd_debug_drop_op_probability > 0 && !m->get_source().is_mds()) { if ((double)rand() / (double)RAND_MAX < cct->_conf->osd_debug_drop_op_probability) { dout(0) << "handle_op DEBUG artificially dropping op " << *m << dendl; return; } } if (op->may_write()) { // full? if ((service.check_failsafe_full() || osdmap->test_flag(CEPH_OSDMAP_FULL) || m->get_map_epoch() < superblock.last_map_marked_full) && !m->get_source().is_mds()) { // FIXME: we'll exclude mds writes for now. // Drop the request, since the client will retry when the full // flag is unset. return; } // invalid? if (m->get_snapid() != CEPH_NOSNAP) { service.reply_op_error(op, -EINVAL); return; } // too big? if (cct->_conf->osd_max_write_size && m->get_data_len() > cct->_conf->osd_max_write_size << 20) { // journal can't hold commit! derr << "handle_op msg data len " << m->get_data_len() << " > osd_max_write_size " << (cct->_conf->osd_max_write_size << 20) << " on " << *m << dendl; service.reply_op_error(op, -OSD_WRITETOOBIG); return; } } // calc actual pgid pg_t _pgid = m->get_pg(); int64_t pool = _pgid.pool(); if ((m->get_flags() & CEPH_OSD_FLAG_PGOP) == 0 && osdmap->have_pg_pool(pool)) _pgid = osdmap->raw_pg_to_pg(_pgid); spg_t pgid; if (!osdmap->get_primary_shard(_pgid, &pgid)) { // missing pool or acting set empty -- drop return; } // get and lock *pg. PG *pg = _have_pg(pgid) ? _lookup_pg(pgid) : NULL; if (!pg) { dout(7) << "hit non-existent pg " << pgid << dendl; if (osdmap->osd_is_valid_op_target(pgid.pgid, whoami)) { dout(7) << "we are valid target for op, waiting" << dendl; waiting_for_pg[pgid].push_back(op); op->mark_delayed("waiting for pg to exist locally"); return; } // okay, we aren't valid now; check send epoch if (m->get_map_epoch() < superblock.oldest_map) { dout(7) << "don't have sender's osdmap; assuming it was valid and that client will resend" << dendl; return; } OSDMapRef send_map = get_map(m->get_map_epoch()); if (send_map->osd_is_valid_op_target(pgid.pgid, whoami)) { dout(7) << "dropping request; client will resend when they get new map" << dendl; } else if (!send_map->have_pg_pool(pgid.pool())) { dout(7) << "dropping request; pool did not exist" << dendl; clog.warn() << m->get_source_inst() << " invalid " << m->get_reqid() << " pg " << m->get_pg() << " to osd." << whoami << " in e" << osdmap->get_epoch() << ", client e" << m->get_map_epoch() << " when pool " << m->get_pg().pool() << " did not exist" << "\n"; } else { dout(7) << "we are invalid target" << dendl; clog.warn() << m->get_source_inst() << " misdirected " << m->get_reqid() << " pg " << m->get_pg() << " to osd." << whoami << " in e" << osdmap->get_epoch() << ", client e" << m->get_map_epoch() << " pg " << pgid << " features " << m->get_connection()->get_features() << "\n"; service.reply_op_error(op, -ENXIO); } return; } enqueue_op(pg, op); } template void OSD::handle_replica_op(OpRequestRef op) { T *m = static_cast(op->get_req()); assert(m->get_header().type == MSGTYPE); dout(10) << __func__ << " " << *m << " epoch " << m->map_epoch << dendl; if (m->map_epoch < up_epoch) { dout(3) << "replica op from before up" << dendl; return; } if (!require_up_osd_peer(op->get_req(), osdmap, m->map_epoch)) return; // must be a rep op. assert(m->get_source().is_osd()); // require same or newer map if (!require_same_or_newer_map(op, m->map_epoch)) return; // share our map with sender, if they're old _share_map_incoming(m->get_source(), m->get_connection().get(), m->map_epoch, static_cast(m->get_connection()->get_priv())); // make sure we have the pg const spg_t pgid = m->pgid; if (service.splitting(pgid)) { waiting_for_pg[pgid].push_back(op); return; } PG *pg = _have_pg(pgid) ? _lookup_pg(pgid) : NULL; if (!pg) { return; } enqueue_op(pg, op); } bool OSD::op_is_discardable(MOSDOp *op) { // drop client request if they are not connected and can't get the // reply anyway. unless this is a replayed op, in which case we // want to do what we can to apply it. if (!op->get_connection()->is_connected() && op->get_version().version == 0) { return true; } return false; } /* * enqueue called with osd_lock held */ void OSD::enqueue_op(PG *pg, OpRequestRef op) { utime_t latency = ceph_clock_now(cct) - op->get_req()->get_recv_stamp(); dout(15) << "enqueue_op " << op << " prio " << op->get_req()->get_priority() << " cost " << op->get_req()->get_cost() << " latency " << latency << " " << *(op->get_req()) << dendl; pg->queue_op(op); } void OSD::OpWQ::_enqueue(pair item) { unsigned priority = item.second->get_req()->get_priority(); unsigned cost = item.second->get_req()->get_cost(); if (priority >= CEPH_MSG_PRIO_LOW) pqueue.enqueue_strict( item.second->get_req()->get_source_inst(), priority, item); else pqueue.enqueue(item.second->get_req()->get_source_inst(), priority, cost, item); osd->logger->set(l_osd_opq, pqueue.length()); } void OSD::OpWQ::_enqueue_front(pair item) { Mutex::Locker l(qlock); if (pg_for_processing.count(&*(item.first))) { pg_for_processing[&*(item.first)].push_front(item.second); item.second = pg_for_processing[&*(item.first)].back(); pg_for_processing[&*(item.first)].pop_back(); } unsigned priority = item.second->get_req()->get_priority(); unsigned cost = item.second->get_req()->get_cost(); if (priority >= CEPH_MSG_PRIO_LOW) pqueue.enqueue_strict_front( item.second->get_req()->get_source_inst(), priority, item); else pqueue.enqueue_front(item.second->get_req()->get_source_inst(), priority, cost, item); osd->logger->set(l_osd_opq, pqueue.length()); } PGRef OSD::OpWQ::_dequeue() { assert(!pqueue.empty()); PGRef pg; { Mutex::Locker l(qlock); pair ret = pqueue.dequeue(); pg = ret.first; pg_for_processing[&*pg].push_back(ret.second); } osd->logger->set(l_osd_opq, pqueue.length()); return pg; } void OSD::OpWQ::_process(PGRef pg, ThreadPool::TPHandle &handle) { pg->lock_suspend_timeout(handle); OpRequestRef op; { Mutex::Locker l(qlock); if (!pg_for_processing.count(&*pg)) { pg->unlock(); return; } assert(pg_for_processing[&*pg].size()); op = pg_for_processing[&*pg].front(); pg_for_processing[&*pg].pop_front(); if (!(pg_for_processing[&*pg].size())) pg_for_processing.erase(&*pg); } lgeneric_subdout(osd->cct, osd, 30) << "dequeue status: "; Formatter *f = new_formatter("json"); f->open_object_section("q"); dump(f); f->close_section(); f->flush(*_dout); delete f; *_dout << dendl; osd->dequeue_op(pg, op, handle); pg->unlock(); } void OSDService::dequeue_pg(PG *pg, list *dequeued) { osd->op_wq.dequeue(pg, dequeued); } /* * NOTE: dequeue called in worker thread, with pg lock */ void OSD::dequeue_op( PGRef pg, OpRequestRef op, ThreadPool::TPHandle &handle) { utime_t now = ceph_clock_now(cct); op->set_dequeued_time(now); utime_t latency = now - op->get_req()->get_recv_stamp(); dout(10) << "dequeue_op " << op << " prio " << op->get_req()->get_priority() << " cost " << op->get_req()->get_cost() << " latency " << latency << " " << *(op->get_req()) << " pg " << *pg << dendl; if (pg->deleting) return; op->mark_reached_pg(); pg->do_request(op, handle); // finish dout(10) << "dequeue_op " << op << " finish" << dendl; } void OSDService::queue_for_peering(PG *pg) { peering_wq.queue(pg); } struct C_CompleteSplits : public Context { OSD *osd; set > pgs; C_CompleteSplits(OSD *osd, const set > &in) : osd(osd), pgs(in) {} void finish(int r) { Mutex::Locker l(osd->osd_lock); if (osd->is_stopping()) return; PG::RecoveryCtx rctx = osd->create_context(); set to_complete; for (set >::iterator i = pgs.begin(); i != pgs.end(); ++i) { (*i)->lock(); osd->add_newly_split_pg(&**i, &rctx); osd->dispatch_context_transaction(rctx, &**i); if (!((*i)->deleting)) to_complete.insert((*i)->info.pgid); (*i)->unlock(); } osd->service.complete_split(to_complete); osd->dispatch_context(rctx, 0, osd->service.get_osdmap()); } }; void OSD::process_peering_events( const list &pgs, ThreadPool::TPHandle &handle ) { bool need_up_thru = false; epoch_t same_interval_since = 0; OSDMapRef curmap = service.get_osdmap(); PG::RecoveryCtx rctx = create_context(); for (list::const_iterator i = pgs.begin(); i != pgs.end(); ++i) { set > split_pgs; PG *pg = *i; pg->lock_suspend_timeout(handle); curmap = service.get_osdmap(); if (pg->deleting) { pg->unlock(); continue; } if (!advance_pg(curmap->get_epoch(), pg, handle, &rctx, &split_pgs)) { // we need to requeue the PG explicitly since we didn't actually // handle an event peering_wq.queue(pg); } else if (!pg->peering_queue.empty()) { PG::CephPeeringEvtRef evt = pg->peering_queue.front(); pg->peering_queue.pop_front(); pg->handle_peering_event(evt, &rctx); } need_up_thru = pg->need_up_thru || need_up_thru; same_interval_since = MAX(pg->info.history.same_interval_since, same_interval_since); pg->write_if_dirty(*rctx.transaction); if (!split_pgs.empty()) { rctx.on_applied->add(new C_CompleteSplits(this, split_pgs)); split_pgs.clear(); } if (compat_must_dispatch_immediately(pg)) { dispatch_context(rctx, pg, curmap, &handle); rctx = create_context(); } else { dispatch_context_transaction(rctx, pg, &handle); } pg->unlock(); handle.reset_tp_timeout(); } if (need_up_thru) queue_want_up_thru(same_interval_since); dispatch_context(rctx, 0, curmap, &handle); service.send_pg_temp(); } // -------------------------------- const char** OSD::get_tracked_conf_keys() const { static const char* KEYS[] = { "osd_max_backfills", "osd_op_complaint_time", "osd_op_log_threshold", "osd_op_history_size", "osd_op_history_duration", "osd_map_cache_size", "osd_map_max_advance", "osd_pg_epoch_persisted_max_stale", "osd_disk_thread_ioprio_class", "osd_disk_thread_ioprio_priority", NULL }; return KEYS; } void OSD::handle_conf_change(const struct md_config_t *conf, const std::set &changed) { if (changed.count("osd_max_backfills")) { service.local_reserver.set_max(cct->_conf->osd_max_backfills); service.remote_reserver.set_max(cct->_conf->osd_max_backfills); } if (changed.count("osd_op_complaint_time") || changed.count("osd_op_log_threshold")) { op_tracker.set_complaint_and_threshold(cct->_conf->osd_op_complaint_time, cct->_conf->osd_op_log_threshold); } if (changed.count("osd_op_history_size") || changed.count("osd_op_history_duration")) { op_tracker.set_history_size_and_duration(cct->_conf->osd_op_history_size, cct->_conf->osd_op_history_duration); } if (changed.count("osd_disk_thread_ioprio_class") || changed.count("osd_disk_thread_ioprio_priority")) { set_disk_tp_priority(); } check_config(); } void OSD::check_config() { // some sanity checks if (g_conf->osd_map_cache_size <= g_conf->osd_map_max_advance + 2) { clog.warn() << "osd_map_cache_size (" << g_conf->osd_map_cache_size << ")" << " is not > osd_map_max_advance (" << g_conf->osd_map_max_advance << ")"; } if (g_conf->osd_map_cache_size <= (int)g_conf->osd_pg_epoch_persisted_max_stale + 2) { clog.warn() << "osd_map_cache_size (" << g_conf->osd_map_cache_size << ")" << " is not > osd_pg_epoch_persisted_max_stale (" << g_conf->osd_pg_epoch_persisted_max_stale << ")"; } } void OSD::set_disk_tp_priority() { dout(10) << __func__ << " class " << cct->_conf->osd_disk_thread_ioprio_class << " priority " << cct->_conf->osd_disk_thread_ioprio_priority << dendl; int cls = ceph_ioprio_string_to_class(cct->_conf->osd_disk_thread_ioprio_class); if (cls < 0) derr << __func__ << cpp_strerror(cls) << ": " << "osd_disk_thread_ioprio_class is " << cct->_conf->osd_disk_thread_ioprio_class << " but only the following values are allowed: idle, be or rt" << dendl; else disk_tp.set_ioprio(cls, cct->_conf->osd_disk_thread_ioprio_priority); } // -------------------------------- int OSD::init_op_flags(OpRequestRef op) { MOSDOp *m = static_cast(op->get_req()); vector::iterator iter; // client flags have no bearing on whether an op is a read, write, etc. op->rmw_flags = 0; // set bits based on op codes, called methods. for (iter = m->ops.begin(); iter != m->ops.end(); ++iter) { if (ceph_osd_op_mode_modify(iter->op.op)) op->set_write(); if (ceph_osd_op_mode_read(iter->op.op)) op->set_read(); // set READ flag if there are src_oids if (iter->soid.oid.name.length()) op->set_read(); // set PGOP flag if there are PG ops if (ceph_osd_op_type_pg(iter->op.op)) op->set_pg_op(); if (ceph_osd_op_mode_cache(iter->op.op)) op->set_cache(); switch (iter->op.op) { case CEPH_OSD_OP_CALL: { bufferlist::iterator bp = iter->indata.begin(); int is_write, is_read; string cname, mname; bp.copy(iter->op.cls.class_len, cname); bp.copy(iter->op.cls.method_len, mname); ClassHandler::ClassData *cls; int r = class_handler->open_class(cname, &cls); if (r) { derr << "class " << cname << " open got " << cpp_strerror(r) << dendl; if (r == -ENOENT) r = -EOPNOTSUPP; else r = -EIO; return r; } int flags = cls->get_method_flags(mname.c_str()); if (flags < 0) { if (flags == -ENOENT) r = -EOPNOTSUPP; else r = flags; return r; } is_read = flags & CLS_METHOD_RD; is_write = flags & CLS_METHOD_WR; dout(10) << "class " << cname << " method " << mname << " flags=" << (is_read ? "r" : "") << (is_write ? "w" : "") << dendl; if (is_read) op->set_class_read(); if (is_write) op->set_class_write(); break; } default: break; } } if (op->rmw_flags == 0) return -EINVAL; return 0; } bool OSD::RecoveryWQ::_enqueue(PG *pg) { if (!pg->recovery_item.is_on_list()) { pg->get("RecoveryWQ"); osd->recovery_queue.push_back(&pg->recovery_item); if (osd->cct->_conf->osd_recovery_delay_start > 0) { osd->defer_recovery_until = ceph_clock_now(osd->cct); osd->defer_recovery_until += osd->cct->_conf->osd_recovery_delay_start; } return true; } return false; } void OSD::PeeringWQ::_dequeue(list *out) { set got; for (list::iterator i = peering_queue.begin(); i != peering_queue.end() && out->size() < osd->cct->_conf->osd_peering_wq_batch_size; ) { if (in_use.count(*i)) { ++i; } else { out->push_back(*i); got.insert(*i); peering_queue.erase(i++); } } in_use.insert(got.begin(), got.end()); } ceph-0.80.11/src/osd/osd_types.cc0000664000175100017510000036104612623076744020603 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "osd_types.h" #include "include/ceph_features.h" extern "C" { #include "crush/hash.h" } #include "PG.h" #include "OSDMap.h" #include "PGBackend.h" const char *ceph_osd_flag_name(unsigned flag) { switch (flag) { case CEPH_OSD_FLAG_ACK: return "ack"; case CEPH_OSD_FLAG_ONNVRAM: return "onnvram"; case CEPH_OSD_FLAG_ONDISK: return "ondisk"; case CEPH_OSD_FLAG_RETRY: return "retry"; case CEPH_OSD_FLAG_READ: return "read"; case CEPH_OSD_FLAG_WRITE: return "write"; case CEPH_OSD_FLAG_ORDERSNAP: return "ordersnap"; case CEPH_OSD_FLAG_PEERSTAT_OLD: return "peerstat_old"; case CEPH_OSD_FLAG_BALANCE_READS: return "balance_reads"; case CEPH_OSD_FLAG_PARALLELEXEC: return "parallelexec"; case CEPH_OSD_FLAG_PGOP: return "pgop"; case CEPH_OSD_FLAG_EXEC: return "exec"; case CEPH_OSD_FLAG_EXEC_PUBLIC: return "exec_public"; case CEPH_OSD_FLAG_LOCALIZE_READS: return "localize_reads"; case CEPH_OSD_FLAG_RWORDERED: return "rwordered"; case CEPH_OSD_FLAG_IGNORE_CACHE: return "ignore_cache"; case CEPH_OSD_FLAG_SKIPRWLOCKS: return "skiprwlocks"; case CEPH_OSD_FLAG_IGNORE_OVERLAY: return "ignore_overlay"; case CEPH_OSD_FLAG_FLUSH: return "flush"; case CEPH_OSD_FLAG_MAP_SNAP_CLONE: return "map_snap_clone"; case CEPH_OSD_FLAG_ENFORCE_SNAPC: return "enforce_snapc"; default: return "???"; } } string ceph_osd_flag_string(unsigned flags) { string s; for (unsigned i=0; i<32; ++i) { if (flags & (1u<dump_stream("name") << name; f->dump_int("inc", inc); f->dump_unsigned("tid", tid); } void osd_reqid_t::generate_test_instances(list& o) { o.push_back(new osd_reqid_t); o.push_back(new osd_reqid_t(entity_name_t::CLIENT(123), 1, 45678)); } // -- object_locator_t -- void object_locator_t::encode(bufferlist& bl) const { // verify that nobody's corrupted the locator assert(hash == -1 || key.empty()); __u8 encode_compat = 3; ENCODE_START(6, encode_compat, bl); ::encode(pool, bl); int32_t preferred = -1; // tell old code there is no preferred osd (-1). ::encode(preferred, bl); ::encode(key, bl); ::encode(nspace, bl); ::encode(hash, bl); if (hash != -1) encode_compat = MAX(encode_compat, 6); // need to interpret the hash ENCODE_FINISH_NEW_COMPAT(bl, encode_compat); } void object_locator_t::decode(bufferlist::iterator& p) { DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, p); if (struct_v < 2) { int32_t op; ::decode(op, p); pool = op; int16_t pref; ::decode(pref, p); } else { ::decode(pool, p); int32_t preferred; ::decode(preferred, p); } ::decode(key, p); if (struct_v >= 5) ::decode(nspace, p); if (struct_v >= 6) ::decode(hash, p); else hash = -1; DECODE_FINISH(p); // verify that nobody's corrupted the locator assert(hash == -1 || key.empty()); } void object_locator_t::dump(Formatter *f) const { f->dump_int("pool", pool); f->dump_string("key", key); f->dump_string("namespace", nspace); f->dump_int("hash", hash); } void object_locator_t::generate_test_instances(list& o) { o.push_back(new object_locator_t); o.push_back(new object_locator_t(123)); o.push_back(new object_locator_t(123, 876)); o.push_back(new object_locator_t(1, "n2")); o.push_back(new object_locator_t(1234, "", "key")); o.push_back(new object_locator_t(12, "n1", "key2")); } // -- request_redirect_t -- void request_redirect_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(redirect_locator, bl); ::encode(redirect_object, bl); ::encode(osd_instructions, bl); ENCODE_FINISH(bl); } void request_redirect_t::decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(redirect_locator, bl); ::decode(redirect_object, bl); ::decode(osd_instructions, bl); DECODE_FINISH(bl); } void request_redirect_t::dump(Formatter *f) const { f->dump_string("object", redirect_object); f->open_object_section("locator"); redirect_locator.dump(f); f->close_section(); // locator } void request_redirect_t::generate_test_instances(list& o) { object_locator_t loc(1, "redir_obj"); o.push_back(new request_redirect_t()); o.push_back(new request_redirect_t(loc, 0)); o.push_back(new request_redirect_t(loc, "redir_obj")); o.push_back(new request_redirect_t(loc)); } void objectstore_perf_stat_t::dump(Formatter *f) const { f->dump_unsigned("commit_latency_ms", filestore_commit_latency); f->dump_unsigned("apply_latency_ms", filestore_apply_latency); } void objectstore_perf_stat_t::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(filestore_commit_latency, bl); ::encode(filestore_apply_latency, bl); ENCODE_FINISH(bl); } void objectstore_perf_stat_t::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(filestore_commit_latency, bl); ::decode(filestore_apply_latency, bl); DECODE_FINISH(bl); } void objectstore_perf_stat_t::generate_test_instances(std::list& o) { o.push_back(new objectstore_perf_stat_t()); o.push_back(new objectstore_perf_stat_t()); o.back()->filestore_commit_latency = 20; o.back()->filestore_apply_latency = 30; } // -- osd_stat_t -- void osd_stat_t::dump(Formatter *f) const { f->dump_unsigned("kb", kb); f->dump_unsigned("kb_used", kb_used); f->dump_unsigned("kb_avail", kb_avail); f->open_array_section("hb_in"); for (vector::const_iterator p = hb_in.begin(); p != hb_in.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->open_array_section("hb_out"); for (vector::const_iterator p = hb_out.begin(); p != hb_out.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->dump_int("snap_trim_queue_len", snap_trim_queue_len); f->dump_int("num_snap_trimming", num_snap_trimming); f->open_object_section("op_queue_age_hist"); op_queue_age_hist.dump(f); f->close_section(); f->open_object_section("fs_perf_stat"); fs_perf_stat.dump(f); f->close_section(); } void osd_stat_t::encode(bufferlist &bl) const { ENCODE_START(4, 2, bl); ::encode(kb, bl); ::encode(kb_used, bl); ::encode(kb_avail, bl); ::encode(snap_trim_queue_len, bl); ::encode(num_snap_trimming, bl); ::encode(hb_in, bl); ::encode(hb_out, bl); ::encode(op_queue_age_hist, bl); ::encode(fs_perf_stat, bl); ENCODE_FINISH(bl); } void osd_stat_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 2, 2, bl); ::decode(kb, bl); ::decode(kb_used, bl); ::decode(kb_avail, bl); ::decode(snap_trim_queue_len, bl); ::decode(num_snap_trimming, bl); ::decode(hb_in, bl); ::decode(hb_out, bl); if (struct_v >= 3) ::decode(op_queue_age_hist, bl); if (struct_v >= 4) ::decode(fs_perf_stat, bl); DECODE_FINISH(bl); } void osd_stat_t::generate_test_instances(std::list& o) { o.push_back(new osd_stat_t); o.push_back(new osd_stat_t); o.back()->kb = 1; o.back()->kb_used = 2; o.back()->kb_avail = 3; o.back()->hb_in.push_back(5); o.back()->hb_in.push_back(6); o.back()->hb_out = o.back()->hb_in; o.back()->hb_out.push_back(7); o.back()->snap_trim_queue_len = 8; o.back()->num_snap_trimming = 99; } // -- pg_t -- int pg_t::print(char *o, int maxlen) const { if (preferred() >= 0) return snprintf(o, maxlen, "%llu.%xp%d", (unsigned long long)pool(), ps(), preferred()); else return snprintf(o, maxlen, "%llu.%x", (unsigned long long)pool(), ps()); } bool pg_t::parse(const char *s) { uint64_t ppool; uint32_t pseed; int32_t pref; int r = sscanf(s, "%llu.%xp%d", (long long unsigned *)&ppool, &pseed, &pref); if (r < 2) return false; m_pool = ppool; m_seed = pseed; if (r == 3) m_preferred = pref; else m_preferred = -1; return true; } bool spg_t::parse(const char *s) { pgid.set_preferred(-1); shard = ghobject_t::NO_SHARD; uint64_t ppool; uint32_t pseed; int32_t pref; uint32_t pshard; int r = sscanf(s, "%llu.%x", (long long unsigned *)&ppool, &pseed); if (r < 2) return false; pgid.set_pool(ppool); pgid.set_ps(pseed); const char *p = strchr(s, 'p'); if (p) { r = sscanf(p, "p%d", &pref); if (r == 1) { pgid.set_preferred(pref); } else { return false; } } p = strchr(s, 's'); if (p) { r = sscanf(p, "s%d", &pshard); if (r == 1) { shard = pshard; } else { return false; } } return true; } ostream& operator<<(ostream& out, const spg_t &pg) { out << pg.pgid; if (!pg.is_no_shard()) out << "s" << (unsigned)pg.shard; return out; } pg_t pg_t::get_ancestor(unsigned old_pg_num) const { int old_bits = pg_pool_t::calc_bits_of(old_pg_num); int old_mask = (1 << old_bits) - 1; pg_t ret = *this; ret.m_seed = ceph_stable_mod(m_seed, old_pg_num, old_mask); return ret; } bool pg_t::is_split(unsigned old_pg_num, unsigned new_pg_num, set *children) const { assert(m_seed < old_pg_num); if (new_pg_num <= old_pg_num) return false; bool split = false; if (true) { int old_bits = pg_pool_t::calc_bits_of(old_pg_num); int old_mask = (1 << old_bits) - 1; for (int n = 1; ; n++) { int next_bit = (n << (old_bits-1)); unsigned s = next_bit | m_seed; if (s < old_pg_num || s == m_seed) continue; if (s >= new_pg_num) break; if ((unsigned)ceph_stable_mod(s, old_pg_num, old_mask) == m_seed) { split = true; if (children) children->insert(pg_t(s, m_pool, m_preferred)); } } } if (false) { // brute force int old_bits = pg_pool_t::calc_bits_of(old_pg_num); int old_mask = (1 << old_bits) - 1; for (unsigned x = old_pg_num; x < new_pg_num; ++x) { unsigned o = ceph_stable_mod(x, old_pg_num, old_mask); if (o == m_seed) { split = true; children->insert(pg_t(x, m_pool, m_preferred)); } } } return split; } unsigned pg_t::get_split_bits(unsigned pg_num) const { if (pg_num == 1) return 0; assert(pg_num > 1); // Find unique p such that pg_num \in [2^(p-1), 2^p) unsigned p = pg_pool_t::calc_bits_of(pg_num); assert(p); // silence coverity #751330 if ((m_seed % (1<<(p-1))) < (pg_num % (1<<(p-1)))) return p; else return p - 1; } pg_t pg_t::get_parent() const { unsigned bits = pg_pool_t::calc_bits_of(m_seed); assert(bits); pg_t retval = *this; retval.m_seed &= ~((~0)<<(bits - 1)); return retval; } void pg_t::dump(Formatter *f) const { f->dump_unsigned("pool", m_pool); f->dump_unsigned("seed", m_seed); f->dump_int("preferred_osd", m_preferred); } void pg_t::generate_test_instances(list& o) { o.push_back(new pg_t); o.push_back(new pg_t(1, 2, -1)); o.push_back(new pg_t(13123, 3, -1)); o.push_back(new pg_t(131223, 4, 23)); } ostream& operator<<(ostream& out, const pg_t &pg) { out << pg.pool() << '.'; out << hex << pg.ps() << dec; if (pg.preferred() >= 0) out << 'p' << pg.preferred(); //out << "=" << hex << (__uint64_t)pg << dec; return out; } // -- coll_t -- const coll_t coll_t::META_COLL("meta"); bool coll_t::is_temp(spg_t& pgid) const { const char *cstr(str.c_str()); if (!pgid.parse(cstr)) return false; const char *tmp_start = strchr(cstr, '_'); if (!tmp_start) return false; if (strncmp(tmp_start, "_TEMP", 5) == 0) return true; return false; } bool coll_t::is_pg(spg_t& pgid, snapid_t& snap) const { const char *cstr(str.c_str()); if (!pgid.parse(cstr)) return false; const char *snap_start = strchr(cstr, '_'); if (!snap_start) return false; if (strncmp(snap_start, "_head", 5) == 0) { snap = CEPH_NOSNAP; } else { errno = 0; snap = strtoull(snap_start+1, 0, 16); if (errno) return false; } return true; } bool coll_t::is_pg_prefix(spg_t& pgid) const { const char *cstr(str.c_str()); if (!pgid.parse(cstr)) return false; const char *snap_start = strchr(cstr, '_'); if (!snap_start) return false; return true; } bool coll_t::is_removal(uint64_t *seq, spg_t *pgid) const { if (str.substr(0, 11) != string("FORREMOVAL_")) return false; stringstream ss(str.substr(11)); ss >> *seq; char sep; ss >> sep; assert(sep == '_'); string pgid_str; ss >> pgid_str; if (!pgid->parse(pgid_str.c_str())) { assert(0); return false; } return true; } void coll_t::encode(bufferlist& bl) const { __u8 struct_v = 3; ::encode(struct_v, bl); ::encode(str, bl); } void coll_t::decode(bufferlist::iterator& bl) { __u8 struct_v; ::decode(struct_v, bl); switch (struct_v) { case 1: { spg_t pgid; snapid_t snap; ::decode(pgid, bl); ::decode(snap, bl); // infer the type if (pgid == spg_t() && snap == 0) str = "meta"; else str = pg_and_snap_to_str(pgid, snap); break; } case 2: { __u8 type; spg_t pgid; snapid_t snap; ::decode(type, bl); ::decode(pgid, bl); ::decode(snap, bl); switch (type) { case 0: str = "meta"; break; case 1: str = "temp"; break; case 2: str = pg_and_snap_to_str(pgid, snap); break; default: { ostringstream oss; oss << "coll_t::decode(): can't understand type " << type; throw std::domain_error(oss.str()); } } break; } case 3: ::decode(str, bl); break; default: { ostringstream oss; oss << "coll_t::decode(): don't know how to decode version " << struct_v; throw std::domain_error(oss.str()); } } } void coll_t::dump(Formatter *f) const { f->dump_string("name", str); } void coll_t::generate_test_instances(list& o) { o.push_back(new coll_t); o.push_back(new coll_t("meta")); o.push_back(new coll_t("temp")); o.push_back(new coll_t("foo")); o.push_back(new coll_t("bar")); } // --- std::string pg_state_string(int state) { ostringstream oss; if (state & PG_STATE_STALE) oss << "stale+"; if (state & PG_STATE_CREATING) oss << "creating+"; if (state & PG_STATE_ACTIVE) oss << "active+"; if (state & PG_STATE_CLEAN) oss << "clean+"; if (state & PG_STATE_RECOVERY_WAIT) oss << "recovery_wait+"; if (state & PG_STATE_RECOVERING) oss << "recovering+"; if (state & PG_STATE_DOWN) oss << "down+"; if (state & PG_STATE_REPLAY) oss << "replay+"; if (state & PG_STATE_SPLITTING) oss << "splitting+"; if (state & PG_STATE_DEGRADED) oss << "degraded+"; if (state & PG_STATE_REMAPPED) oss << "remapped+"; if (state & PG_STATE_SCRUBBING) oss << "scrubbing+"; if (state & PG_STATE_DEEP_SCRUB) oss << "deep+"; if (state & PG_STATE_SCRUBQ) oss << "scrubq+"; if (state & PG_STATE_INCONSISTENT) oss << "inconsistent+"; if (state & PG_STATE_PEERING) oss << "peering+"; if (state & PG_STATE_REPAIR) oss << "repair+"; if ((state & PG_STATE_BACKFILL_WAIT) && !(state &PG_STATE_BACKFILL)) oss << "wait_backfill+"; if (state & PG_STATE_BACKFILL) oss << "backfilling+"; if (state & PG_STATE_BACKFILL_TOOFULL) oss << "backfill_toofull+"; if (state & PG_STATE_INCOMPLETE) oss << "incomplete+"; string ret(oss.str()); if (ret.length() > 0) ret.resize(ret.length() - 1); else ret = "inactive"; return ret; } // -- eversion_t -- string eversion_t::get_key_name() const { char key[40]; snprintf( key, sizeof(key), "%010u.%020llu", epoch, (long long unsigned)version); return string(key); } // -- pool_snap_info_t -- void pool_snap_info_t::dump(Formatter *f) const { f->dump_unsigned("snapid", snapid); f->dump_stream("stamp") << stamp; f->dump_string("name", name); } void pool_snap_info_t::encode(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_PGPOOL3) == 0) { __u8 struct_v = 1; ::encode(struct_v, bl); ::encode(snapid, bl); ::encode(stamp, bl); ::encode(name, bl); return; } ENCODE_START(2, 2, bl); ::encode(snapid, bl); ::encode(stamp, bl); ::encode(name, bl); ENCODE_FINISH(bl); } void pool_snap_info_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(snapid, bl); ::decode(stamp, bl); ::decode(name, bl); DECODE_FINISH(bl); } void pool_snap_info_t::generate_test_instances(list& o) { o.push_back(new pool_snap_info_t); o.push_back(new pool_snap_info_t); o.back()->snapid = 1; o.back()->stamp = utime_t(1, 2); o.back()->name = "foo"; } // -- pg_pool_t -- void pg_pool_t::dump(Formatter *f) const { f->dump_unsigned("flags", get_flags()); f->dump_string("flags_names", get_flags_string()); f->dump_int("type", get_type()); f->dump_int("size", get_size()); f->dump_int("min_size", get_min_size()); f->dump_int("crush_ruleset", get_crush_ruleset()); f->dump_int("object_hash", get_object_hash()); f->dump_int("pg_num", get_pg_num()); f->dump_int("pg_placement_num", get_pgp_num()); f->dump_unsigned("crash_replay_interval", get_crash_replay_interval()); f->dump_stream("last_change") << get_last_change(); f->dump_stream("last_force_op_resend") << get_last_force_op_resend(); f->dump_unsigned("auid", get_auid()); f->dump_string("snap_mode", is_pool_snaps_mode() ? "pool" : "selfmanaged"); f->dump_unsigned("snap_seq", get_snap_seq()); f->dump_unsigned("snap_epoch", get_snap_epoch()); f->open_array_section("pool_snaps"); for (map::const_iterator p = snaps.begin(); p != snaps.end(); ++p) { f->open_object_section("pool_snap_info"); p->second.dump(f); f->close_section(); } f->close_section(); f->dump_stream("removed_snaps") << removed_snaps; f->dump_int("quota_max_bytes", quota_max_bytes); f->dump_int("quota_max_objects", quota_max_objects); f->open_array_section("tiers"); for (set::const_iterator p = tiers.begin(); p != tiers.end(); ++p) f->dump_int("pool_id", *p); f->close_section(); f->dump_int("tier_of", tier_of); f->dump_int("read_tier", read_tier); f->dump_int("write_tier", write_tier); f->dump_string("cache_mode", get_cache_mode_name()); f->dump_unsigned("target_max_bytes", target_max_bytes); f->dump_unsigned("target_max_objects", target_max_objects); f->dump_unsigned("cache_target_dirty_ratio_micro", cache_target_dirty_ratio_micro); f->dump_unsigned("cache_target_full_ratio_micro", cache_target_full_ratio_micro); f->dump_unsigned("cache_min_flush_age", cache_min_flush_age); f->dump_unsigned("cache_min_evict_age", cache_min_evict_age); f->dump_string("erasure_code_profile", erasure_code_profile); f->open_object_section("hit_set_params"); hit_set_params.dump(f); f->close_section(); // hit_set_params f->dump_unsigned("hit_set_period", hit_set_period); f->dump_unsigned("hit_set_count", hit_set_count); f->dump_unsigned("min_read_recency_for_promote", min_read_recency_for_promote); f->dump_unsigned("stripe_width", get_stripe_width()); } int pg_pool_t::calc_bits_of(int t) { int b = 0; while (t > 0) { t = t >> 1; b++; } return b; } void pg_pool_t::calc_pg_masks() { pg_num_mask = (1 << calc_bits_of(pg_num-1)) - 1; pgp_num_mask = (1 << calc_bits_of(pgp_num-1)) - 1; } unsigned pg_pool_t::get_pg_num_divisor(pg_t pgid) const { if (pg_num == pg_num_mask + 1) return pg_num; // power-of-2 split unsigned mask = pg_num_mask >> 1; if ((pgid.ps() & mask) < (pg_num & mask)) return pg_num_mask + 1; // smaller bin size (already split) else return (pg_num_mask + 1) >> 1; // bigger bin (not yet split) } /* * we have two snap modes: * - pool global snaps * - snap existence/non-existence defined by snaps[] and snap_seq * - user managed snaps * - removal governed by removed_snaps * * we know which mode we're using based on whether removed_snaps is empty. */ bool pg_pool_t::is_pool_snaps_mode() const { return removed_snaps.empty() && get_snap_seq() > 0; } bool pg_pool_t::is_unmanaged_snaps_mode() const { return removed_snaps.size() && get_snap_seq() > 0; } bool pg_pool_t::is_removed_snap(snapid_t s) const { if (is_pool_snaps_mode()) return s <= get_snap_seq() && snaps.count(s) == 0; else return removed_snaps.contains(s); } /* * build set of known-removed sets from either pool snaps or * explicit removed_snaps set. */ void pg_pool_t::build_removed_snaps(interval_set& rs) const { if (is_pool_snaps_mode()) { rs.clear(); for (snapid_t s = 1; s <= get_snap_seq(); s = s + 1) if (snaps.count(s) == 0) rs.insert(s); } else { rs = removed_snaps; } } snapid_t pg_pool_t::snap_exists(const char *s) const { for (map::const_iterator p = snaps.begin(); p != snaps.end(); ++p) if (p->second.name == s) return p->second.snapid; return 0; } void pg_pool_t::add_snap(const char *n, utime_t stamp) { assert(!is_unmanaged_snaps_mode()); snapid_t s = get_snap_seq() + 1; snap_seq = s; snaps[s].snapid = s; snaps[s].name = n; snaps[s].stamp = stamp; } void pg_pool_t::add_unmanaged_snap(uint64_t& snapid) { if (removed_snaps.empty()) { assert(!is_pool_snaps_mode()); removed_snaps.insert(snapid_t(1)); snap_seq = 1; } snapid = snap_seq = snap_seq + 1; } void pg_pool_t::remove_snap(snapid_t s) { assert(snaps.count(s)); snaps.erase(s); snap_seq = snap_seq + 1; } void pg_pool_t::remove_unmanaged_snap(snapid_t s) { assert(is_unmanaged_snaps_mode()); removed_snaps.insert(s); snap_seq = snap_seq + 1; removed_snaps.insert(get_snap_seq()); } SnapContext pg_pool_t::get_snap_context() const { vector s(snaps.size()); unsigned i = 0; for (map::const_reverse_iterator p = snaps.rbegin(); p != snaps.rend(); ++p) s[i++] = p->first; return SnapContext(get_snap_seq(), s); } static string make_hash_str(const string &inkey, const string &nspace) { if (nspace.empty()) return inkey; return nspace + '\037' + inkey; } uint32_t pg_pool_t::hash_key(const string& key, const string& ns) const { string n = make_hash_str(key, ns); return ceph_str_hash(object_hash, n.c_str(), n.length()); } uint32_t pg_pool_t::raw_hash_to_pg(uint32_t v) const { return ceph_stable_mod(v, pg_num, pg_num_mask); } /* * map a raw pg (with full precision ps) into an actual pg, for storage */ pg_t pg_pool_t::raw_pg_to_pg(pg_t pg) const { pg.set_ps(ceph_stable_mod(pg.ps(), pg_num, pg_num_mask)); return pg; } /* * map raw pg (full precision ps) into a placement seed. include * pool id in that value so that different pools don't use the same * seeds. */ ps_t pg_pool_t::raw_pg_to_pps(pg_t pg) const { if (flags & FLAG_HASHPSPOOL) { // Hash the pool id so that pool PGs do not overlap. return crush_hash32_2(CRUSH_HASH_RJENKINS1, ceph_stable_mod(pg.ps(), pgp_num, pgp_num_mask), pg.pool()); } else { // Legacy behavior; add ps and pool together. This is not a great // idea because the PGs from each pool will essentially overlap on // top of each other: 0.5 == 1.4 == 2.3 == ... return ceph_stable_mod(pg.ps(), pgp_num, pgp_num_mask) + pg.pool(); } } uint32_t pg_pool_t::get_random_pg_position(pg_t pg, uint32_t seed) const { uint32_t r = crush_hash32_2(CRUSH_HASH_RJENKINS1, seed, 123); if (pg_num == pg_num_mask + 1) { r &= ~pg_num_mask; } else { unsigned smaller_mask = pg_num_mask >> 1; if ((pg.ps() & smaller_mask) < (pg_num & smaller_mask)) { r &= ~pg_num_mask; } else { r &= ~smaller_mask; } } r |= pg.ps(); return r; } void pg_pool_t::encode(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_PGPOOL3) == 0) { // this encoding matches the old struct ceph_pg_pool __u8 struct_v = 2; ::encode(struct_v, bl); ::encode(type, bl); ::encode(size, bl); ::encode(crush_ruleset, bl); ::encode(object_hash, bl); ::encode(pg_num, bl); ::encode(pgp_num, bl); __u32 lpg_num = 0, lpgp_num = 0; // tell old code that there are no localized pgs. ::encode(lpg_num, bl); ::encode(lpgp_num, bl); ::encode(last_change, bl); ::encode(snap_seq, bl); ::encode(snap_epoch, bl); __u32 n = snaps.size(); ::encode(n, bl); n = removed_snaps.num_intervals(); ::encode(n, bl); ::encode(auid, bl); ::encode_nohead(snaps, bl, features); removed_snaps.encode_nohead(bl); return; } if ((features & CEPH_FEATURE_OSDENC) == 0) { __u8 struct_v = 4; ::encode(struct_v, bl); ::encode(type, bl); ::encode(size, bl); ::encode(crush_ruleset, bl); ::encode(object_hash, bl); ::encode(pg_num, bl); ::encode(pgp_num, bl); __u32 lpg_num = 0, lpgp_num = 0; // tell old code that there are no localized pgs. ::encode(lpg_num, bl); ::encode(lpgp_num, bl); ::encode(last_change, bl); ::encode(snap_seq, bl); ::encode(snap_epoch, bl); ::encode(snaps, bl, features); ::encode(removed_snaps, bl); ::encode(auid, bl); ::encode(flags, bl); ::encode(crash_replay_interval, bl); return; } if ((features & CEPH_FEATURE_OSD_POOLRESEND) == 0) { // we simply added last_force_op_resend here, which is a fully // backward compatible change. however, encoding the same map // differently between monitors triggers scrub noise (even though // they are decodable without the feature), so let's be pendantic // about it. ENCODE_START(14, 5, bl); ::encode(type, bl); ::encode(size, bl); ::encode(crush_ruleset, bl); ::encode(object_hash, bl); ::encode(pg_num, bl); ::encode(pgp_num, bl); __u32 lpg_num = 0, lpgp_num = 0; // tell old code that there are no localized pgs. ::encode(lpg_num, bl); ::encode(lpgp_num, bl); ::encode(last_change, bl); ::encode(snap_seq, bl); ::encode(snap_epoch, bl); ::encode(snaps, bl, features); ::encode(removed_snaps, bl); ::encode(auid, bl); ::encode(flags, bl); ::encode(crash_replay_interval, bl); ::encode(min_size, bl); ::encode(quota_max_bytes, bl); ::encode(quota_max_objects, bl); ::encode(tiers, bl); ::encode(tier_of, bl); __u8 c = cache_mode; ::encode(c, bl); ::encode(read_tier, bl); ::encode(write_tier, bl); ::encode(properties, bl); ::encode(hit_set_params, bl); ::encode(hit_set_period, bl); ::encode(hit_set_count, bl); ::encode(stripe_width, bl); ::encode(target_max_bytes, bl); ::encode(target_max_objects, bl); ::encode(cache_target_dirty_ratio_micro, bl); ::encode(cache_target_full_ratio_micro, bl); ::encode(cache_min_flush_age, bl); ::encode(cache_min_evict_age, bl); ::encode(erasure_code_profile, bl); ENCODE_FINISH(bl); return; } ENCODE_START(16, 5, bl); ::encode(type, bl); ::encode(size, bl); ::encode(crush_ruleset, bl); ::encode(object_hash, bl); ::encode(pg_num, bl); ::encode(pgp_num, bl); __u32 lpg_num = 0, lpgp_num = 0; // tell old code that there are no localized pgs. ::encode(lpg_num, bl); ::encode(lpgp_num, bl); ::encode(last_change, bl); ::encode(snap_seq, bl); ::encode(snap_epoch, bl); ::encode(snaps, bl, features); ::encode(removed_snaps, bl); ::encode(auid, bl); ::encode(flags, bl); ::encode(crash_replay_interval, bl); ::encode(min_size, bl); ::encode(quota_max_bytes, bl); ::encode(quota_max_objects, bl); ::encode(tiers, bl); ::encode(tier_of, bl); __u8 c = cache_mode; ::encode(c, bl); ::encode(read_tier, bl); ::encode(write_tier, bl); ::encode(properties, bl); ::encode(hit_set_params, bl); ::encode(hit_set_period, bl); ::encode(hit_set_count, bl); ::encode(stripe_width, bl); ::encode(target_max_bytes, bl); ::encode(target_max_objects, bl); ::encode(cache_target_dirty_ratio_micro, bl); ::encode(cache_target_full_ratio_micro, bl); ::encode(cache_min_flush_age, bl); ::encode(cache_min_evict_age, bl); ::encode(erasure_code_profile, bl); ::encode(last_force_op_resend, bl); ::encode(min_read_recency_for_promote, bl); ENCODE_FINISH(bl); } void pg_pool_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(16, 5, 5, bl); ::decode(type, bl); ::decode(size, bl); ::decode(crush_ruleset, bl); ::decode(object_hash, bl); ::decode(pg_num, bl); ::decode(pgp_num, bl); { __u32 lpg_num, lpgp_num; ::decode(lpg_num, bl); ::decode(lpgp_num, bl); } ::decode(last_change, bl); ::decode(snap_seq, bl); ::decode(snap_epoch, bl); if (struct_v >= 3) { ::decode(snaps, bl); ::decode(removed_snaps, bl); ::decode(auid, bl); } else { __u32 n, m; ::decode(n, bl); ::decode(m, bl); ::decode(auid, bl); ::decode_nohead(n, snaps, bl); removed_snaps.decode_nohead(m, bl); } if (struct_v >= 4) { ::decode(flags, bl); ::decode(crash_replay_interval, bl); } else { flags = 0; // if this looks like the 'data' pool, set the // crash_replay_interval appropriately. unfortunately, we can't // be precise here. this should be good enough to preserve replay // on the data pool for the majority of cluster upgrades, though. if (crush_ruleset == 0 && auid == 0) crash_replay_interval = 60; else crash_replay_interval = 0; } if (struct_v >= 7) { ::decode(min_size, bl); } else { min_size = size - size/2; } if (struct_v >= 8) { ::decode(quota_max_bytes, bl); ::decode(quota_max_objects, bl); } if (struct_v >= 9) { ::decode(tiers, bl); ::decode(tier_of, bl); __u8 v; ::decode(v, bl); cache_mode = (cache_mode_t)v; ::decode(read_tier, bl); ::decode(write_tier, bl); } if (struct_v >= 10) { ::decode(properties, bl); } if (struct_v >= 11) { ::decode(hit_set_params, bl); ::decode(hit_set_period, bl); ::decode(hit_set_count, bl); } else { pg_pool_t def; hit_set_period = def.hit_set_period; hit_set_count = def.hit_set_count; } if (struct_v >= 12) { ::decode(stripe_width, bl); } else { set_stripe_width(0); } if (struct_v >= 13) { ::decode(target_max_bytes, bl); ::decode(target_max_objects, bl); ::decode(cache_target_dirty_ratio_micro, bl); ::decode(cache_target_full_ratio_micro, bl); ::decode(cache_min_flush_age, bl); ::decode(cache_min_evict_age, bl); } else { target_max_bytes = 0; target_max_objects = 0; cache_target_dirty_ratio_micro = 0; cache_target_full_ratio_micro = 0; cache_min_flush_age = 0; cache_min_evict_age = 0; } if (struct_v >= 14) { ::decode(erasure_code_profile, bl); } if (struct_v >= 15) { ::decode(last_force_op_resend, bl); } else { last_force_op_resend = 0; } if (struct_v >= 16) { ::decode(min_read_recency_for_promote, bl); } else { pg_pool_t def; min_read_recency_for_promote = def.min_read_recency_for_promote; } DECODE_FINISH(bl); calc_pg_masks(); } void pg_pool_t::generate_test_instances(list& o) { pg_pool_t a; o.push_back(new pg_pool_t(a)); a.type = TYPE_REPLICATED; a.size = 2; a.crush_ruleset = 3; a.object_hash = 4; a.pg_num = 6; a.pgp_num = 5; a.last_change = 9; a.last_force_op_resend = 123823; a.snap_seq = 10; a.snap_epoch = 11; a.auid = 12; a.crash_replay_interval = 13; a.quota_max_bytes = 473; a.quota_max_objects = 474; o.push_back(new pg_pool_t(a)); a.snaps[3].name = "asdf"; a.snaps[3].snapid = 3; a.snaps[3].stamp = utime_t(123, 4); a.snaps[6].name = "qwer"; a.snaps[6].snapid = 6; a.snaps[6].stamp = utime_t(23423, 4); o.push_back(new pg_pool_t(a)); a.removed_snaps.insert(2); // not quite valid to combine with snaps! a.quota_max_bytes = 2473; a.quota_max_objects = 4374; a.tiers.insert(0); a.tiers.insert(1); a.tier_of = 2; a.cache_mode = CACHEMODE_WRITEBACK; a.read_tier = 1; a.write_tier = 1; a.hit_set_params = HitSet::Params(new BloomHitSet::Params); a.hit_set_period = 3600; a.hit_set_count = 8; a.min_read_recency_for_promote = 1; a.set_stripe_width(12345); a.target_max_bytes = 1238132132; a.target_max_objects = 1232132; a.cache_target_dirty_ratio_micro = 187232; a.cache_target_full_ratio_micro = 987222; a.cache_min_flush_age = 231; a.cache_min_evict_age = 2321; a.erasure_code_profile = "profile in osdmap"; o.push_back(new pg_pool_t(a)); } ostream& operator<<(ostream& out, const pg_pool_t& p) { out << p.get_type_name() << " size " << p.get_size() << " min_size " << p.get_min_size() << " crush_ruleset " << p.get_crush_ruleset() << " object_hash " << p.get_object_hash_name() << " pg_num " << p.get_pg_num() << " pgp_num " << p.get_pgp_num() << " last_change " << p.get_last_change(); if (p.get_last_force_op_resend()) out << " lfor " << p.get_last_force_op_resend(); if (p.get_auid()) out << " owner " << p.get_auid(); if (p.flags) out << " flags " << p.get_flags_string(); if (p.crash_replay_interval) out << " crash_replay_interval " << p.crash_replay_interval; if (p.quota_max_bytes) out << " max_bytes " << p.quota_max_bytes; if (p.quota_max_objects) out << " max_objects " << p.quota_max_objects; if (!p.tiers.empty()) out << " tiers " << p.tiers; if (p.is_tier()) out << " tier_of " << p.tier_of; if (p.has_read_tier()) out << " read_tier " << p.read_tier; if (p.has_write_tier()) out << " write_tier " << p.write_tier; if (p.cache_mode) out << " cache_mode " << p.get_cache_mode_name(); if (p.target_max_bytes) out << " target_bytes " << p.target_max_bytes; if (p.target_max_objects) out << " target_objects " << p.target_max_objects; if (p.hit_set_params.get_type() != HitSet::TYPE_NONE) { out << " hit_set " << p.hit_set_params << " " << p.hit_set_period << "s" << " x" << p.hit_set_count; } if (p.min_read_recency_for_promote) out << " min_read_recency_for_promote " << p.min_read_recency_for_promote; out << " stripe_width " << p.get_stripe_width(); return out; } // -- object_stat_sum_t -- void object_stat_sum_t::dump(Formatter *f) const { f->dump_int("num_bytes", num_bytes); f->dump_int("num_objects", num_objects); f->dump_int("num_object_clones", num_object_clones); f->dump_int("num_object_copies", num_object_copies); f->dump_int("num_objects_missing_on_primary", num_objects_missing_on_primary); f->dump_int("num_objects_degraded", num_objects_degraded); f->dump_int("num_objects_unfound", num_objects_unfound); f->dump_int("num_objects_dirty", num_objects_dirty); f->dump_int("num_whiteouts", num_whiteouts); f->dump_int("num_read", num_rd); f->dump_int("num_read_kb", num_rd_kb); f->dump_int("num_write", num_wr); f->dump_int("num_write_kb", num_wr_kb); f->dump_int("num_scrub_errors", num_scrub_errors); f->dump_int("num_shallow_scrub_errors", num_shallow_scrub_errors); f->dump_int("num_deep_scrub_errors", num_deep_scrub_errors); f->dump_int("num_objects_recovered", num_objects_recovered); f->dump_int("num_bytes_recovered", num_bytes_recovered); f->dump_int("num_keys_recovered", num_keys_recovered); f->dump_int("num_objects_omap", num_objects_omap); f->dump_int("num_objects_hit_set_archive", num_objects_hit_set_archive); } void object_stat_sum_t::encode(bufferlist& bl) const { ENCODE_START(9, 3, bl); ::encode(num_bytes, bl); ::encode(num_objects, bl); ::encode(num_object_clones, bl); ::encode(num_object_copies, bl); ::encode(num_objects_missing_on_primary, bl); ::encode(num_objects_degraded, bl); ::encode(num_objects_unfound, bl); ::encode(num_rd, bl); ::encode(num_rd_kb, bl); ::encode(num_wr, bl); ::encode(num_wr_kb, bl); ::encode(num_scrub_errors, bl); ::encode(num_objects_recovered, bl); ::encode(num_bytes_recovered, bl); ::encode(num_keys_recovered, bl); ::encode(num_shallow_scrub_errors, bl); ::encode(num_deep_scrub_errors, bl); ::encode(num_objects_dirty, bl); ::encode(num_whiteouts, bl); ::encode(num_objects_omap, bl); ::encode(num_objects_hit_set_archive, bl); ENCODE_FINISH(bl); } void object_stat_sum_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(9, 3, 3, bl); ::decode(num_bytes, bl); if (struct_v < 3) { uint64_t num_kb; ::decode(num_kb, bl); } ::decode(num_objects, bl); ::decode(num_object_clones, bl); ::decode(num_object_copies, bl); ::decode(num_objects_missing_on_primary, bl); ::decode(num_objects_degraded, bl); if (struct_v >= 2) ::decode(num_objects_unfound, bl); ::decode(num_rd, bl); ::decode(num_rd_kb, bl); ::decode(num_wr, bl); ::decode(num_wr_kb, bl); if (struct_v >= 4) ::decode(num_scrub_errors, bl); else num_scrub_errors = 0; if (struct_v >= 5) { ::decode(num_objects_recovered, bl); ::decode(num_bytes_recovered, bl); ::decode(num_keys_recovered, bl); } else { num_objects_recovered = 0; num_bytes_recovered = 0; num_keys_recovered = 0; } if (struct_v >= 6) { ::decode(num_shallow_scrub_errors, bl); ::decode(num_deep_scrub_errors, bl); } else { num_shallow_scrub_errors = 0; num_deep_scrub_errors = 0; } if (struct_v >= 7) { ::decode(num_objects_dirty, bl); ::decode(num_whiteouts, bl); } else { num_objects_dirty = 0; num_whiteouts = 0; } if (struct_v >= 8) { ::decode(num_objects_omap, bl); } else { num_objects_omap = 0; } if (struct_v >= 9) { ::decode(num_objects_hit_set_archive, bl); } else { num_objects_hit_set_archive = 0; } DECODE_FINISH(bl); } void object_stat_sum_t::generate_test_instances(list& o) { object_stat_sum_t a; o.push_back(new object_stat_sum_t(a)); a.num_bytes = 1; a.num_objects = 3; a.num_object_clones = 4; a.num_object_copies = 5; a.num_objects_missing_on_primary = 6; a.num_objects_degraded = 7; a.num_objects_unfound = 8; a.num_rd = 9; a.num_rd_kb = 10; a.num_wr = 11; a.num_wr_kb = 12; a.num_objects_recovered = 14; a.num_bytes_recovered = 15; a.num_keys_recovered = 16; a.num_deep_scrub_errors = 17; a.num_shallow_scrub_errors = 18; a.num_scrub_errors = a.num_deep_scrub_errors + a.num_shallow_scrub_errors; a.num_objects_dirty = 21; a.num_whiteouts = 22; o.push_back(new object_stat_sum_t(a)); } void object_stat_sum_t::add(const object_stat_sum_t& o) { num_bytes += o.num_bytes; num_objects += o.num_objects; num_object_clones += o.num_object_clones; num_object_copies += o.num_object_copies; num_objects_missing_on_primary += o.num_objects_missing_on_primary; num_objects_degraded += o.num_objects_degraded; num_rd += o.num_rd; num_rd_kb += o.num_rd_kb; num_wr += o.num_wr; num_wr_kb += o.num_wr_kb; num_objects_unfound += o.num_objects_unfound; num_scrub_errors += o.num_scrub_errors; num_shallow_scrub_errors += o.num_shallow_scrub_errors; num_deep_scrub_errors += o.num_deep_scrub_errors; num_objects_recovered += o.num_objects_recovered; num_bytes_recovered += o.num_bytes_recovered; num_keys_recovered += o.num_keys_recovered; num_objects_dirty += o.num_objects_dirty; num_whiteouts += o.num_whiteouts; num_objects_omap += o.num_objects_omap; num_objects_hit_set_archive += o.num_objects_hit_set_archive; } void object_stat_sum_t::sub(const object_stat_sum_t& o) { num_bytes -= o.num_bytes; num_objects -= o.num_objects; num_object_clones -= o.num_object_clones; num_object_copies -= o.num_object_copies; num_objects_missing_on_primary -= o.num_objects_missing_on_primary; num_objects_degraded -= o.num_objects_degraded; num_rd -= o.num_rd; num_rd_kb -= o.num_rd_kb; num_wr -= o.num_wr; num_wr_kb -= o.num_wr_kb; num_objects_unfound -= o.num_objects_unfound; num_scrub_errors -= o.num_scrub_errors; num_shallow_scrub_errors -= o.num_shallow_scrub_errors; num_deep_scrub_errors -= o.num_deep_scrub_errors; num_objects_recovered -= o.num_objects_recovered; num_bytes_recovered -= o.num_bytes_recovered; num_keys_recovered -= o.num_keys_recovered; num_objects_dirty -= o.num_objects_dirty; num_whiteouts -= o.num_whiteouts; num_objects_omap -= o.num_objects_omap; num_objects_hit_set_archive -= o.num_objects_hit_set_archive; } // -- object_stat_collection_t -- void object_stat_collection_t::dump(Formatter *f) const { f->open_object_section("stat_sum"); sum.dump(f); f->close_section(); f->open_object_section("stat_cat_sum"); for (map::const_iterator p = cat_sum.begin(); p != cat_sum.end(); ++p) { f->open_object_section(p->first.c_str()); p->second.dump(f); f->close_section(); } f->close_section(); } void object_stat_collection_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(sum, bl); ::encode(cat_sum, bl); ENCODE_FINISH(bl); } void object_stat_collection_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(sum, bl); ::decode(cat_sum, bl); DECODE_FINISH(bl); } void object_stat_collection_t::generate_test_instances(list& o) { object_stat_collection_t a; o.push_back(new object_stat_collection_t(a)); list l; object_stat_sum_t::generate_test_instances(l); char n[2] = { 'a', 0 }; for (list::iterator p = l.begin(); p != l.end(); ++p) { a.add(**p, n); n[0]++; o.push_back(new object_stat_collection_t(a)); } } // -- pg_stat_t -- void pg_stat_t::dump(Formatter *f) const { f->dump_stream("version") << version; f->dump_stream("reported_seq") << reported_seq; f->dump_stream("reported_epoch") << reported_epoch; f->dump_string("state", pg_state_string(state)); f->dump_stream("last_fresh") << last_fresh; f->dump_stream("last_change") << last_change; f->dump_stream("last_active") << last_active; f->dump_stream("last_clean") << last_clean; f->dump_stream("last_became_active") << last_became_active; f->dump_stream("last_unstale") << last_unstale; f->dump_unsigned("mapping_epoch", mapping_epoch); f->dump_stream("log_start") << log_start; f->dump_stream("ondisk_log_start") << ondisk_log_start; f->dump_unsigned("created", created); f->dump_unsigned("last_epoch_clean", last_epoch_clean); f->dump_stream("parent") << parent; f->dump_unsigned("parent_split_bits", parent_split_bits); f->dump_stream("last_scrub") << last_scrub; f->dump_stream("last_scrub_stamp") << last_scrub_stamp; f->dump_stream("last_deep_scrub") << last_deep_scrub; f->dump_stream("last_deep_scrub_stamp") << last_deep_scrub_stamp; f->dump_stream("last_clean_scrub_stamp") << last_clean_scrub_stamp; f->dump_unsigned("log_size", log_size); f->dump_unsigned("ondisk_log_size", ondisk_log_size); f->dump_stream("stats_invalid") << stats_invalid; stats.dump(f); f->open_array_section("up"); for (vector::const_iterator p = up.begin(); p != up.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->open_array_section("acting"); for (vector::const_iterator p = acting.begin(); p != acting.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->dump_int("up_primary", up_primary); f->dump_int("acting_primary", acting_primary); } void pg_stat_t::dump_brief(Formatter *f) const { f->dump_string("state", pg_state_string(state)); f->open_array_section("up"); for (vector::const_iterator p = up.begin(); p != up.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->open_array_section("acting"); for (vector::const_iterator p = acting.begin(); p != acting.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->dump_int("up_primary", up_primary); f->dump_int("acting_primary", acting_primary); } void pg_stat_t::encode(bufferlist &bl) const { ENCODE_START(17, 8, bl); ::encode(version, bl); ::encode(reported_seq, bl); ::encode(reported_epoch, bl); ::encode(state, bl); ::encode(log_start, bl); ::encode(ondisk_log_start, bl); ::encode(created, bl); ::encode(last_epoch_clean, bl); ::encode(parent, bl); ::encode(parent_split_bits, bl); ::encode(last_scrub, bl); ::encode(last_scrub_stamp, bl); ::encode(stats, bl); ::encode(log_size, bl); ::encode(ondisk_log_size, bl); ::encode(up, bl); ::encode(acting, bl); ::encode(last_fresh, bl); ::encode(last_change, bl); ::encode(last_active, bl); ::encode(last_clean, bl); ::encode(last_unstale, bl); ::encode(mapping_epoch, bl); ::encode(last_deep_scrub, bl); ::encode(last_deep_scrub_stamp, bl); ::encode(stats_invalid, bl); ::encode(last_clean_scrub_stamp, bl); ::encode(last_became_active, bl); ::encode(dirty_stats_invalid, bl); ::encode(up_primary, bl); ::encode(acting_primary, bl); ::encode(omap_stats_invalid, bl); ::encode(hitset_stats_invalid, bl); ENCODE_FINISH(bl); } void pg_stat_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(17, 8, 8, bl); ::decode(version, bl); ::decode(reported_seq, bl); ::decode(reported_epoch, bl); ::decode(state, bl); ::decode(log_start, bl); ::decode(ondisk_log_start, bl); ::decode(created, bl); if (struct_v >= 7) ::decode(last_epoch_clean, bl); else last_epoch_clean = 0; if (struct_v < 6) { old_pg_t opgid; ::decode(opgid, bl); parent = opgid; } else { ::decode(parent, bl); } ::decode(parent_split_bits, bl); ::decode(last_scrub, bl); ::decode(last_scrub_stamp, bl); if (struct_v <= 4) { ::decode(stats.sum.num_bytes, bl); uint64_t num_kb; ::decode(num_kb, bl); ::decode(stats.sum.num_objects, bl); ::decode(stats.sum.num_object_clones, bl); ::decode(stats.sum.num_object_copies, bl); ::decode(stats.sum.num_objects_missing_on_primary, bl); ::decode(stats.sum.num_objects_degraded, bl); ::decode(log_size, bl); ::decode(ondisk_log_size, bl); if (struct_v >= 2) { ::decode(stats.sum.num_rd, bl); ::decode(stats.sum.num_rd_kb, bl); ::decode(stats.sum.num_wr, bl); ::decode(stats.sum.num_wr_kb, bl); } if (struct_v >= 3) { ::decode(up, bl); } if (struct_v == 4) { ::decode(stats.sum.num_objects_unfound, bl); // sigh. } ::decode(acting, bl); } else { ::decode(stats, bl); ::decode(log_size, bl); ::decode(ondisk_log_size, bl); ::decode(up, bl); ::decode(acting, bl); if (struct_v >= 9) { ::decode(last_fresh, bl); ::decode(last_change, bl); ::decode(last_active, bl); ::decode(last_clean, bl); ::decode(last_unstale, bl); ::decode(mapping_epoch, bl); if (struct_v >= 10) { ::decode(last_deep_scrub, bl); ::decode(last_deep_scrub_stamp, bl); } } } if (struct_v < 11) { stats_invalid = false; } else { ::decode(stats_invalid, bl); } if (struct_v >= 12) { ::decode(last_clean_scrub_stamp, bl); } else { last_clean_scrub_stamp = utime_t(); } if (struct_v >= 13) { ::decode(last_became_active, bl); } else { last_became_active = last_active; } if (struct_v >= 14) { ::decode(dirty_stats_invalid, bl); } else { // if we are decoding an old encoding of this object, then the // encoder may not have supported num_objects_dirty accounting. dirty_stats_invalid = true; } if (struct_v >= 15) { ::decode(up_primary, bl); ::decode(acting_primary, bl); } else { up_primary = up.size() ? up[0] : -1; acting_primary = acting.size() ? acting[0] : -1; } if (struct_v >= 16) { ::decode(omap_stats_invalid, bl); } else { // if we are decoding an old encoding of this object, then the // encoder may not have supported num_objects_omap accounting. omap_stats_invalid = true; } if (struct_v >= 17) { ::decode(hitset_stats_invalid, bl); } else { // if we are decoding an old encoding of this object, then the // encoder may not have supported num_objects_hit_set_archive accounting. hitset_stats_invalid = true; } DECODE_FINISH(bl); } void pg_stat_t::generate_test_instances(list& o) { pg_stat_t a; o.push_back(new pg_stat_t(a)); a.version = eversion_t(1, 3); a.reported_epoch = 1; a.reported_seq = 2; a.state = 123; a.mapping_epoch = 998; a.last_fresh = utime_t(1002, 1); a.last_change = utime_t(1002, 2); a.last_active = utime_t(1002, 3); a.last_clean = utime_t(1002, 4); a.last_unstale = utime_t(1002, 5); a.log_start = eversion_t(1, 4); a.ondisk_log_start = eversion_t(1, 5); a.created = 6; a.last_epoch_clean = 7; a.parent = pg_t(1, 2, 3); a.parent_split_bits = 12; a.last_scrub = eversion_t(9, 10); a.last_scrub_stamp = utime_t(11, 12); a.last_deep_scrub = eversion_t(13, 14); a.last_deep_scrub_stamp = utime_t(15, 16); a.last_clean_scrub_stamp = utime_t(17, 18); list l; object_stat_collection_t::generate_test_instances(l); a.stats = *l.back(); a.log_size = 99; a.ondisk_log_size = 88; a.up.push_back(123); a.up_primary = 123; a.acting.push_back(456); a.acting_primary = 456; o.push_back(new pg_stat_t(a)); a.up.push_back(124); a.up_primary = 124; a.acting.push_back(124); a.acting_primary = 124; o.push_back(new pg_stat_t(a)); } // -- pool_stat_t -- void pool_stat_t::dump(Formatter *f) const { stats.dump(f); f->dump_int("log_size", log_size); f->dump_int("ondisk_log_size", ondisk_log_size); } void pool_stat_t::encode(bufferlist &bl, uint64_t features) const { if ((features & CEPH_FEATURE_OSDENC) == 0) { __u8 v = 4; ::encode(v, bl); ::encode(stats, bl); ::encode(log_size, bl); ::encode(ondisk_log_size, bl); return; } ENCODE_START(5, 5, bl); ::encode(stats, bl); ::encode(log_size, bl); ::encode(ondisk_log_size, bl); ENCODE_FINISH(bl); } void pool_stat_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 5, 5, bl); if (struct_v >= 4) { ::decode(stats, bl); ::decode(log_size, bl); ::decode(ondisk_log_size, bl); } else { ::decode(stats.sum.num_bytes, bl); uint64_t num_kb; ::decode(num_kb, bl); ::decode(stats.sum.num_objects, bl); ::decode(stats.sum.num_object_clones, bl); ::decode(stats.sum.num_object_copies, bl); ::decode(stats.sum.num_objects_missing_on_primary, bl); ::decode(stats.sum.num_objects_degraded, bl); ::decode(log_size, bl); ::decode(ondisk_log_size, bl); if (struct_v >= 2) { ::decode(stats.sum.num_rd, bl); ::decode(stats.sum.num_rd_kb, bl); ::decode(stats.sum.num_wr, bl); ::decode(stats.sum.num_wr_kb, bl); } if (struct_v >= 3) { ::decode(stats.sum.num_objects_unfound, bl); } } DECODE_FINISH(bl); } void pool_stat_t::generate_test_instances(list& o) { pool_stat_t a; o.push_back(new pool_stat_t(a)); list l; object_stat_collection_t::generate_test_instances(l); a.stats = *l.back(); a.log_size = 123; a.ondisk_log_size = 456; o.push_back(new pool_stat_t(a)); } // -- pg_history_t -- void pg_history_t::encode(bufferlist &bl) const { ENCODE_START(6, 4, bl); ::encode(epoch_created, bl); ::encode(last_epoch_started, bl); ::encode(last_epoch_clean, bl); ::encode(last_epoch_split, bl); ::encode(same_interval_since, bl); ::encode(same_up_since, bl); ::encode(same_primary_since, bl); ::encode(last_scrub, bl); ::encode(last_scrub_stamp, bl); ::encode(last_deep_scrub, bl); ::encode(last_deep_scrub_stamp, bl); ::encode(last_clean_scrub_stamp, bl); ENCODE_FINISH(bl); } void pg_history_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 4, 4, bl); ::decode(epoch_created, bl); ::decode(last_epoch_started, bl); if (struct_v >= 3) ::decode(last_epoch_clean, bl); else last_epoch_clean = last_epoch_started; // careful, it's a lie! ::decode(last_epoch_split, bl); ::decode(same_interval_since, bl); ::decode(same_up_since, bl); ::decode(same_primary_since, bl); if (struct_v >= 2) { ::decode(last_scrub, bl); ::decode(last_scrub_stamp, bl); } if (struct_v >= 5) { ::decode(last_deep_scrub, bl); ::decode(last_deep_scrub_stamp, bl); } if (struct_v >= 6) { ::decode(last_clean_scrub_stamp, bl); } DECODE_FINISH(bl); } void pg_history_t::dump(Formatter *f) const { f->dump_int("epoch_created", epoch_created); f->dump_int("last_epoch_started", last_epoch_started); f->dump_int("last_epoch_clean", last_epoch_clean); f->dump_int("last_epoch_split", last_epoch_split); f->dump_int("same_up_since", same_up_since); f->dump_int("same_interval_since", same_interval_since); f->dump_int("same_primary_since", same_primary_since); f->dump_stream("last_scrub") << last_scrub; f->dump_stream("last_scrub_stamp") << last_scrub_stamp; f->dump_stream("last_deep_scrub") << last_deep_scrub; f->dump_stream("last_deep_scrub_stamp") << last_deep_scrub_stamp; f->dump_stream("last_clean_scrub_stamp") << last_clean_scrub_stamp; } void pg_history_t::generate_test_instances(list& o) { o.push_back(new pg_history_t); o.push_back(new pg_history_t); o.back()->epoch_created = 1; o.back()->last_epoch_started = 2; o.back()->last_epoch_clean = 3; o.back()->last_epoch_split = 4; o.back()->same_up_since = 5; o.back()->same_interval_since = 6; o.back()->same_primary_since = 7; o.back()->last_scrub = eversion_t(8, 9); o.back()->last_scrub_stamp = utime_t(10, 11); o.back()->last_deep_scrub = eversion_t(12, 13); o.back()->last_deep_scrub_stamp = utime_t(14, 15); o.back()->last_clean_scrub_stamp = utime_t(16, 17); } // -- pg_info_t -- void pg_info_t::encode(bufferlist &bl) const { ENCODE_START(30, 26, bl); ::encode(pgid.pgid, bl); ::encode(last_update, bl); ::encode(last_complete, bl); ::encode(log_tail, bl); ::encode(last_backfill, bl); ::encode(stats, bl); history.encode(bl); ::encode(purged_snaps, bl); ::encode(last_epoch_started, bl); ::encode(last_user_version, bl); ::encode(hit_set, bl); ::encode(pgid.shard, bl); ENCODE_FINISH(bl); } void pg_info_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(29, 26, 26, bl); if (struct_v < 23) { old_pg_t opgid; ::decode(opgid, bl); pgid.pgid = opgid; } else { ::decode(pgid.pgid, bl); } ::decode(last_update, bl); ::decode(last_complete, bl); ::decode(log_tail, bl); if (struct_v < 25) { bool log_backlog; ::decode(log_backlog, bl); } if (struct_v >= 24) ::decode(last_backfill, bl); ::decode(stats, bl); history.decode(bl); if (struct_v >= 22) ::decode(purged_snaps, bl); else { set snap_trimq; ::decode(snap_trimq, bl); } if (struct_v < 27) { last_epoch_started = history.last_epoch_started; } else { ::decode(last_epoch_started, bl); } if (struct_v >= 28) ::decode(last_user_version, bl); else last_user_version = last_update.version; if (struct_v >= 29) ::decode(hit_set, bl); if (struct_v >= 30) ::decode(pgid.shard, bl); else pgid.shard = ghobject_t::no_shard(); DECODE_FINISH(bl); } // -- pg_info_t -- void pg_info_t::dump(Formatter *f) const { f->dump_stream("pgid") << pgid; f->dump_stream("last_update") << last_update; f->dump_stream("last_complete") << last_complete; f->dump_stream("log_tail") << log_tail; f->dump_int("last_user_version", last_user_version); f->dump_stream("last_backfill") << last_backfill; f->dump_stream("purged_snaps") << purged_snaps; f->open_object_section("history"); history.dump(f); f->close_section(); f->open_object_section("stats"); stats.dump(f); f->close_section(); f->dump_int("empty", is_empty()); f->dump_int("dne", dne()); f->dump_int("incomplete", is_incomplete()); f->dump_int("last_epoch_started", last_epoch_started); f->open_object_section("hit_set_history"); hit_set.dump(f); f->close_section(); } void pg_info_t::generate_test_instances(list& o) { o.push_back(new pg_info_t); o.push_back(new pg_info_t); list h; pg_history_t::generate_test_instances(h); o.back()->history = *h.back(); o.back()->pgid = spg_t(pg_t(1, 2, -1), ghobject_t::no_shard()); o.back()->last_update = eversion_t(3, 4); o.back()->last_complete = eversion_t(5, 6); o.back()->last_user_version = 2; o.back()->log_tail = eversion_t(7, 8); o.back()->last_backfill = hobject_t(object_t("objname"), "key", 123, 456, -1, ""); { list s; pg_stat_t::generate_test_instances(s); o.back()->stats = *s.back(); } { list s; pg_hit_set_history_t::generate_test_instances(s); o.back()->hit_set = *s.back(); } } // -- pg_notify_t -- void pg_notify_t::encode(bufferlist &bl) const { ENCODE_START(2, 1, bl); ::encode(query_epoch, bl); ::encode(epoch_sent, bl); ::encode(info, bl); ::encode(to, bl); ::encode(from, bl); ENCODE_FINISH(bl); } void pg_notify_t::decode(bufferlist::iterator &bl) { DECODE_START(2, bl); ::decode(query_epoch, bl); ::decode(epoch_sent, bl); ::decode(info, bl); if (struct_v >= 2) { ::decode(to, bl); ::decode(from, bl); } else { to = ghobject_t::NO_SHARD; from = ghobject_t::NO_SHARD; } DECODE_FINISH(bl); } void pg_notify_t::dump(Formatter *f) const { f->dump_int("from", from); f->dump_int("to", to); f->dump_unsigned("query_epoch", query_epoch); f->dump_unsigned("epoch_sent", epoch_sent); { f->open_object_section("info"); info.dump(f); f->close_section(); } } void pg_notify_t::generate_test_instances(list& o) { o.push_back(new pg_notify_t(3, ghobject_t::NO_SHARD, 1 ,1 , pg_info_t())); o.push_back(new pg_notify_t(0, 0, 3, 10, pg_info_t())); } ostream &operator<<(ostream &lhs, const pg_notify_t ¬ify) { lhs << "(query_epoch:" << notify.query_epoch << ", epoch_sent:" << notify.epoch_sent << ", info:" << notify.info; if (notify.from != ghobject_t::NO_SHARD || notify.to != ghobject_t::NO_SHARD) lhs << " " << (unsigned)notify.from << "->" << (unsigned)notify.to; return lhs << ")"; } // -- pg_interval_t -- void pg_interval_t::encode(bufferlist& bl) const { ENCODE_START(4, 2, bl); ::encode(first, bl); ::encode(last, bl); ::encode(up, bl); ::encode(acting, bl); ::encode(maybe_went_rw, bl); ::encode(primary, bl); ::encode(up_primary, bl); ENCODE_FINISH(bl); } void pg_interval_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 2, 2, bl); ::decode(first, bl); ::decode(last, bl); ::decode(up, bl); ::decode(acting, bl); ::decode(maybe_went_rw, bl); if (struct_v >= 3) { ::decode(primary, bl); } else { if (acting.size()) primary = acting[0]; } if (struct_v >= 4) { ::decode(up_primary, bl); } else { if (up.size()) up_primary = up[0]; } DECODE_FINISH(bl); } void pg_interval_t::dump(Formatter *f) const { f->dump_unsigned("first", first); f->dump_unsigned("last", last); f->dump_int("maybe_went_rw", maybe_went_rw ? 1 : 0); f->open_array_section("up"); for (vector::const_iterator p = up.begin(); p != up.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->open_array_section("acting"); for (vector::const_iterator p = acting.begin(); p != acting.end(); ++p) f->dump_int("osd", *p); f->close_section(); f->dump_int("primary", primary); f->dump_int("up_primary", up_primary); } void pg_interval_t::generate_test_instances(list& o) { o.push_back(new pg_interval_t); o.push_back(new pg_interval_t); o.back()->up.push_back(1); o.back()->acting.push_back(2); o.back()->acting.push_back(3); o.back()->first = 4; o.back()->last = 5; o.back()->maybe_went_rw = true; } bool pg_interval_t::is_new_interval( int old_acting_primary, int new_acting_primary, const vector &old_acting, const vector &new_acting, int old_up_primary, int new_up_primary, const vector &old_up, const vector &new_up, int old_size, int new_size, int old_min_size, int new_min_size, unsigned old_pg_num, unsigned new_pg_num, pg_t pgid) { return old_acting_primary != new_acting_primary || new_acting != old_acting || old_up_primary != new_up_primary || new_up != old_up || old_min_size != new_min_size || old_size != new_size || pgid.is_split(old_pg_num, new_pg_num, 0); } bool pg_interval_t::is_new_interval( int old_acting_primary, int new_acting_primary, const vector &old_acting, const vector &new_acting, int old_up_primary, int new_up_primary, const vector &old_up, const vector &new_up, OSDMapRef osdmap, OSDMapRef lastmap, int64_t pool_id, pg_t pgid) { return !(lastmap->get_pools().count(pgid.pool())) || is_new_interval(old_acting_primary, new_acting_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, lastmap->get_pools().find(pgid.pool())->second.size, osdmap->get_pools().find(pgid.pool())->second.size, lastmap->get_pools().find(pgid.pool())->second.min_size, osdmap->get_pools().find(pgid.pool())->second.min_size, lastmap->get_pg_num(pgid.pool()), osdmap->get_pg_num(pgid.pool()), pgid); } bool pg_interval_t::check_new_interval( int old_acting_primary, int new_acting_primary, const vector &old_acting, const vector &new_acting, int old_up_primary, int new_up_primary, const vector &old_up, const vector &new_up, epoch_t same_interval_since, epoch_t last_epoch_clean, OSDMapRef osdmap, OSDMapRef lastmap, int64_t pool_id, pg_t pgid, map *past_intervals, std::ostream *out) { // remember past interval // NOTE: a change in the up set primary triggers an interval // change, even though the interval members in the pg_interval_t // do not change. if (is_new_interval( old_acting_primary, new_acting_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, osdmap, lastmap, pool_id, pgid)) { pg_interval_t& i = (*past_intervals)[same_interval_since]; i.first = same_interval_since; i.last = osdmap->get_epoch() - 1; i.acting = old_acting; i.up = old_up; i.primary = old_acting_primary; i.up_primary = old_up_primary; unsigned num_acting = 0; for (vector::const_iterator p = i.acting.begin(); p != i.acting.end(); ++p) if (*p != CRUSH_ITEM_NONE) ++num_acting; if (num_acting && i.primary != -1 && num_acting >= lastmap->get_pools().find(pgid.pool())->second.min_size) { if (out) *out << "generate_past_intervals " << i << ": not rw," << " up_thru " << lastmap->get_up_thru(i.primary) << " up_from " << lastmap->get_up_from(i.primary) << " last_epoch_clean " << last_epoch_clean << std::endl; if (lastmap->get_up_thru(i.primary) >= i.first && lastmap->get_up_from(i.primary) <= i.first) { i.maybe_went_rw = true; if (out) *out << "generate_past_intervals " << i << " : primary up " << lastmap->get_up_from(i.primary) << "-" << lastmap->get_up_thru(i.primary) << " includes interval" << std::endl; } else if (last_epoch_clean >= i.first && last_epoch_clean <= i.last) { // If the last_epoch_clean is included in this interval, then // the pg must have been rw (for recovery to have completed). // This is important because we won't know the _real_ // first_epoch because we stop at last_epoch_clean, and we // don't want the oldest interval to randomly have // maybe_went_rw false depending on the relative up_thru vs // last_epoch_clean timing. i.maybe_went_rw = true; if (out) *out << "generate_past_intervals " << i << " : includes last_epoch_clean " << last_epoch_clean << " and presumed to have been rw" << std::endl; } else { i.maybe_went_rw = false; if (out) *out << "generate_past_intervals " << i << " : primary up " << lastmap->get_up_from(i.primary) << "-" << lastmap->get_up_thru(i.primary) << " does not include interval" << std::endl; } } else { i.maybe_went_rw = false; if (out) *out << "generate_past_intervals " << i << " : acting set is too small" << std::endl; } return true; } else { return false; } } ostream& operator<<(ostream& out, const pg_interval_t& i) { out << "interval(" << i.first << "-" << i.last << " up " << i.up << "(" << i.up_primary << ")" << " acting " << i.acting << "(" << i.primary << ")"; if (i.maybe_went_rw) out << " maybe_went_rw"; out << ")"; return out; } // -- pg_query_t -- void pg_query_t::encode(bufferlist &bl, uint64_t features) const { if (features & CEPH_FEATURE_QUERY_T) { ENCODE_START(3, 2, bl); ::encode(type, bl); ::encode(since, bl); history.encode(bl); ::encode(epoch_sent, bl); ::encode(to, bl); ::encode(from, bl); ENCODE_FINISH(bl); } else { ::encode(type, bl); ::encode(since, bl); history.encode(bl); } } void pg_query_t::decode(bufferlist::iterator &bl) { bufferlist::iterator bl2 = bl; try { DECODE_START(3, bl); ::decode(type, bl); ::decode(since, bl); history.decode(bl); ::decode(epoch_sent, bl); if (struct_v >= 3) { ::decode(to, bl); ::decode(from, bl); } else { to = ghobject_t::NO_SHARD; from = ghobject_t::NO_SHARD; } DECODE_FINISH(bl); } catch (...) { bl = bl2; ::decode(type, bl); ::decode(since, bl); history.decode(bl); } } void pg_query_t::dump(Formatter *f) const { f->dump_int("from", from); f->dump_int("to", to); f->dump_string("type", get_type_name()); f->dump_stream("since") << since; f->dump_stream("epoch_sent") << epoch_sent; f->open_object_section("history"); history.dump(f); f->close_section(); } void pg_query_t::generate_test_instances(list& o) { o.push_back(new pg_query_t()); list h; pg_history_t::generate_test_instances(h); o.push_back(new pg_query_t(pg_query_t::INFO, 1, 2, *h.back(), 4)); o.push_back(new pg_query_t(pg_query_t::MISSING, 2, 3, *h.back(), 4)); o.push_back(new pg_query_t(pg_query_t::LOG, 0, 0, eversion_t(4, 5), *h.back(), 4)); o.push_back(new pg_query_t(pg_query_t::FULLLOG, ghobject_t::NO_SHARD, ghobject_t::NO_SHARD, *h.back(), 5)); } // -- ObjectModDesc -- void ObjectModDesc::visit(Visitor *visitor) const { bufferlist::iterator bp = bl.begin(); try { while (!bp.end()) { DECODE_START(1, bp); uint8_t code; ::decode(code, bp); switch (code) { case APPEND: { uint64_t size; ::decode(size, bp); visitor->append(size); break; } case SETATTRS: { map > attrs; ::decode(attrs, bp); visitor->setattrs(attrs); break; } case DELETE: { version_t old_version; ::decode(old_version, bp); visitor->rmobject(old_version); break; } case CREATE: { visitor->create(); break; } case UPDATE_SNAPS: { set snaps; ::decode(snaps, bp); visitor->update_snaps(snaps); break; } default: assert(0 == "Invalid rollback code"); } DECODE_FINISH(bp); } } catch (...) { assert(0 == "Invalid encoding"); } } struct DumpVisitor : public ObjectModDesc::Visitor { Formatter *f; DumpVisitor(Formatter *f) : f(f) {} void append(uint64_t old_size) { f->open_object_section("op"); f->dump_string("code", "APPEND"); f->dump_unsigned("old_size", old_size); f->close_section(); } void setattrs(map > &attrs) { f->open_object_section("op"); f->dump_string("code", "SETATTRS"); f->open_array_section("attrs"); for (map >::iterator i = attrs.begin(); i != attrs.end(); ++i) { f->dump_string("attr_name", i->first); } f->close_section(); f->close_section(); } void rmobject(version_t old_version) { f->open_object_section("op"); f->dump_string("code", "RMOBJECT"); f->dump_unsigned("old_version", old_version); f->close_section(); } void create() { f->open_object_section("op"); f->dump_string("code", "CREATE"); f->close_section(); } void update_snaps(set &snaps) { f->open_object_section("op"); f->dump_string("code", "UPDATE_SNAPS"); f->dump_stream("snaps") << snaps; f->close_section(); } }; void ObjectModDesc::dump(Formatter *f) const { f->open_object_section("object_mod_desc"); f->dump_bool("can_local_rollback", can_local_rollback); f->dump_bool("rollback_info_completed", rollback_info_completed); { f->open_array_section("ops"); DumpVisitor vis(f); visit(&vis); f->close_section(); } f->close_section(); } void ObjectModDesc::generate_test_instances(list& o) { map > attrs; attrs[OI_ATTR]; attrs[SS_ATTR]; attrs["asdf"]; o.push_back(new ObjectModDesc()); o.back()->append(100); o.back()->setattrs(attrs); o.push_back(new ObjectModDesc()); o.back()->rmobject(1001); o.push_back(new ObjectModDesc()); o.back()->create(); o.back()->setattrs(attrs); o.push_back(new ObjectModDesc()); o.back()->create(); o.back()->setattrs(attrs); o.back()->mark_unrollbackable(); o.back()->append(1000); } void ObjectModDesc::encode(bufferlist &_bl) const { ENCODE_START(1, 1, _bl); ::encode(can_local_rollback, _bl); ::encode(rollback_info_completed, _bl); ::encode(bl, _bl); ENCODE_FINISH(_bl); } void ObjectModDesc::decode(bufferlist::iterator &_bl) { DECODE_START(1, _bl); ::decode(can_local_rollback, _bl); ::decode(rollback_info_completed, _bl); ::decode(bl, _bl); DECODE_FINISH(_bl); } // -- pg_log_entry_t -- string pg_log_entry_t::get_key_name() const { return version.get_key_name(); } void pg_log_entry_t::encode_with_checksum(bufferlist& bl) const { bufferlist ebl(sizeof(*this)*2); encode(ebl); __u32 crc = ebl.crc32c(0); ::encode(ebl, bl); ::encode(crc, bl); } void pg_log_entry_t::decode_with_checksum(bufferlist::iterator& p) { bufferlist bl; ::decode(bl, p); __u32 crc; ::decode(crc, p); if (crc != bl.crc32c(0)) throw buffer::malformed_input("bad checksum on pg_log_entry_t"); bufferlist::iterator q = bl.begin(); decode(q); } void pg_log_entry_t::encode(bufferlist &bl) const { ENCODE_START(9, 4, bl); ::encode(op, bl); ::encode(soid, bl); ::encode(version, bl); /** * Added with reverting_to: * Previous code used prior_version to encode * what we now call reverting_to. This will * allow older code to decode reverting_to * into prior_version as expected. */ if (op == LOST_REVERT) ::encode(reverting_to, bl); else ::encode(prior_version, bl); ::encode(reqid, bl); ::encode(mtime, bl); if (op == LOST_REVERT) ::encode(prior_version, bl); ::encode(snaps, bl); ::encode(user_version, bl); ::encode(mod_desc, bl); ENCODE_FINISH(bl); } void pg_log_entry_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(8, 4, 4, bl); ::decode(op, bl); if (struct_v < 2) { sobject_t old_soid; ::decode(old_soid, bl); soid.oid = old_soid.oid; soid.snap = old_soid.snap; invalid_hash = true; } else { ::decode(soid, bl); } if (struct_v < 3) invalid_hash = true; ::decode(version, bl); if (struct_v >= 6 && op == LOST_REVERT) ::decode(reverting_to, bl); else ::decode(prior_version, bl); ::decode(reqid, bl); ::decode(mtime, bl); if (struct_v < 5) invalid_pool = true; if (op == LOST_REVERT) { if (struct_v >= 6) { ::decode(prior_version, bl); } else { reverting_to = prior_version; } } if (struct_v >= 7 || // for v >= 7, this is for all ops. op == CLONE) { // for v < 7, it's only present for CLONE. ::decode(snaps, bl); } if (struct_v >= 8) ::decode(user_version, bl); else user_version = version.version; if (struct_v >= 9) ::decode(mod_desc, bl); else mod_desc.mark_unrollbackable(); DECODE_FINISH(bl); } void pg_log_entry_t::dump(Formatter *f) const { f->dump_string("op", get_op_name()); f->dump_stream("object") << soid; f->dump_stream("version") << version; f->dump_stream("prior_version") << version; f->dump_stream("reqid") << reqid; f->dump_stream("mtime") << mtime; if (snaps.length() > 0) { vector v; bufferlist c = snaps; bufferlist::iterator p = c.begin(); try { ::decode(v, p); } catch (...) { v.clear(); } f->open_object_section("snaps"); for (vector::iterator p = v.begin(); p != v.end(); ++p) f->dump_unsigned("snap", *p); f->close_section(); } { f->open_object_section("mod_desc"); mod_desc.dump(f); f->close_section(); } } void pg_log_entry_t::generate_test_instances(list& o) { o.push_back(new pg_log_entry_t()); hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); o.push_back(new pg_log_entry_t(MODIFY, oid, eversion_t(1,2), eversion_t(3,4), 1, osd_reqid_t(entity_name_t::CLIENT(777), 8, 999), utime_t(8,9))); } ostream& operator<<(ostream& out, const pg_log_entry_t& e) { out << e.version << " (" << e.prior_version << ") " << e.get_op_name() << ' ' << e.soid << " by " << e.reqid << " " << e.mtime; if (e.snaps.length()) { vector snaps; bufferlist c = e.snaps; bufferlist::iterator p = c.begin(); try { ::decode(snaps, p); } catch (...) { snaps.clear(); } out << " snaps " << snaps; } return out; } // -- pg_log_t -- void pg_log_t::encode(bufferlist& bl) const { ENCODE_START(6, 3, bl); ::encode(head, bl); ::encode(tail, bl); ::encode(log, bl); ::encode(can_rollback_to, bl); ::encode(rollback_info_trimmed_to, bl); ENCODE_FINISH(bl); } void pg_log_t::decode(bufferlist::iterator &bl, int64_t pool) { DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl); ::decode(head, bl); ::decode(tail, bl); if (struct_v < 2) { bool backlog; ::decode(backlog, bl); } ::decode(log, bl); if (struct_v >= 5) ::decode(can_rollback_to, bl); if (struct_v >= 6) ::decode(rollback_info_trimmed_to, bl); else rollback_info_trimmed_to = tail; DECODE_FINISH(bl); // handle hobject_t format change if (struct_v < 4) { for (list::iterator i = log.begin(); i != log.end(); ++i) { if (!i->soid.is_max() && i->soid.pool == -1) i->soid.pool = pool; } } } void pg_log_t::dump(Formatter *f) const { f->dump_stream("head") << head; f->dump_stream("tail") << head; f->open_array_section("log"); for (list::const_iterator p = log.begin(); p != log.end(); ++p) { f->open_object_section("entry"); p->dump(f); f->close_section(); } f->close_section(); } void pg_log_t::generate_test_instances(list& o) { o.push_back(new pg_log_t); // this is nonsensical: o.push_back(new pg_log_t); o.back()->head = eversion_t(1,2); o.back()->tail = eversion_t(3,4); list e; pg_log_entry_t::generate_test_instances(e); for (list::iterator p = e.begin(); p != e.end(); ++p) o.back()->log.push_back(**p); } void pg_log_t::copy_after(const pg_log_t &other, eversion_t v) { can_rollback_to = other.can_rollback_to; head = other.head; tail = other.tail; for (list::const_reverse_iterator i = other.log.rbegin(); i != other.log.rend(); ++i) { assert(i->version > other.tail); if (i->version <= v) { // make tail accurate. tail = i->version; break; } log.push_front(*i); } } void pg_log_t::copy_range(const pg_log_t &other, eversion_t from, eversion_t to) { can_rollback_to = other.can_rollback_to; list::const_reverse_iterator i = other.log.rbegin(); assert(i != other.log.rend()); while (i->version > to) { ++i; assert(i != other.log.rend()); } assert(i->version == to); head = to; for ( ; i != other.log.rend(); ++i) { if (i->version <= from) { tail = i->version; break; } log.push_front(*i); } } void pg_log_t::copy_up_to(const pg_log_t &other, int max) { can_rollback_to = other.can_rollback_to; int n = 0; head = other.head; tail = other.tail; for (list::const_reverse_iterator i = other.log.rbegin(); i != other.log.rend(); ++i) { if (n++ >= max) { tail = i->version; break; } log.push_front(*i); } } ostream& pg_log_t::print(ostream& out) const { out << *this << std::endl; for (list::const_iterator p = log.begin(); p != log.end(); ++p) out << *p << std::endl; return out; } // -- pg_missing_t -- void pg_missing_t::encode(bufferlist &bl) const { ENCODE_START(3, 2, bl); ::encode(missing, bl); ENCODE_FINISH(bl); } void pg_missing_t::decode(bufferlist::iterator &bl, int64_t pool) { DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl); ::decode(missing, bl); DECODE_FINISH(bl); if (struct_v < 3) { // Handle hobject_t upgrade map tmp; for (map::iterator i = missing.begin(); i != missing.end(); ) { if (!i->first.is_max() && i->first.pool == -1) { hobject_t to_insert(i->first); to_insert.pool = pool; tmp[to_insert] = i->second; missing.erase(i++); } else { ++i; } } missing.insert(tmp.begin(), tmp.end()); } for (map::iterator it = missing.begin(); it != missing.end(); ++it) rmissing[it->second.need.version] = it->first; } void pg_missing_t::dump(Formatter *f) const { f->open_array_section("missing"); for (map::const_iterator p = missing.begin(); p != missing.end(); ++p) { f->open_object_section("item"); f->dump_stream("object") << p->first; p->second.dump(f); f->close_section(); } f->close_section(); } void pg_missing_t::generate_test_instances(list& o) { o.push_back(new pg_missing_t); o.push_back(new pg_missing_t); o.back()->add(hobject_t(object_t("foo"), "foo", 123, 456, 0, ""), eversion_t(5, 6), eversion_t(5, 1)); } ostream& operator<<(ostream& out, const pg_missing_t::item& i) { out << i.need; if (i.have != eversion_t()) out << "(" << i.have << ")"; return out; } ostream& operator<<(ostream& out, const pg_missing_t& missing) { out << "missing(" << missing.num_missing(); //if (missing.num_lost()) out << ", " << missing.num_lost() << " lost"; out << ")"; return out; } unsigned int pg_missing_t::num_missing() const { return missing.size(); } bool pg_missing_t::have_missing() const { return !missing.empty(); } void pg_missing_t::swap(pg_missing_t& o) { missing.swap(o.missing); rmissing.swap(o.rmissing); } bool pg_missing_t::is_missing(const hobject_t& oid) const { return (missing.find(oid) != missing.end()); } bool pg_missing_t::is_missing(const hobject_t& oid, eversion_t v) const { map::const_iterator m = missing.find(oid); if (m == missing.end()) return false; const pg_missing_t::item &item(m->second); if (item.need > v) return false; return true; } eversion_t pg_missing_t::have_old(const hobject_t& oid) const { map::const_iterator m = missing.find(oid); if (m == missing.end()) return eversion_t(); const pg_missing_t::item &item(m->second); return item.have; } /* * this needs to be called in log order as we extend the log. it * assumes missing is accurate up through the previous log entry. */ void pg_missing_t::add_next_event(const pg_log_entry_t& e) { if (e.is_update()) { if (e.prior_version == eversion_t() || e.is_clone()) { // new object. //assert(missing.count(e.soid) == 0); // might already be missing divergent item. if (missing.count(e.soid)) // already missing divergent item rmissing.erase(missing[e.soid].need.version); missing[e.soid] = item(e.version, eversion_t()); // .have = nil } else if (missing.count(e.soid)) { // already missing (prior). //assert(missing[e.soid].need == e.prior_version); rmissing.erase(missing[e.soid].need.version); missing[e.soid].need = e.version; // leave .have unchanged. } else if (e.is_backlog()) { // May not have prior version assert(0 == "these don't exist anymore"); } else { // not missing, we must have prior_version (if any) missing[e.soid] = item(e.version, e.prior_version); } rmissing[e.version.version] = e.soid; } else rm(e.soid, e.version); } void pg_missing_t::revise_need(hobject_t oid, eversion_t need) { if (missing.count(oid)) { rmissing.erase(missing[oid].need.version); missing[oid].need = need; // no not adjust .have } else { missing[oid] = item(need, eversion_t()); } rmissing[need.version] = oid; } void pg_missing_t::revise_have(hobject_t oid, eversion_t have) { if (missing.count(oid)) { missing[oid].have = have; } } void pg_missing_t::add(const hobject_t& oid, eversion_t need, eversion_t have) { missing[oid] = item(need, have); rmissing[need.version] = oid; } void pg_missing_t::rm(const hobject_t& oid, eversion_t v) { std::map::iterator p = missing.find(oid); if (p != missing.end() && p->second.need <= v) rm(p); } void pg_missing_t::rm(const std::map::iterator &m) { rmissing.erase(m->second.need.version); missing.erase(m); } void pg_missing_t::got(const hobject_t& oid, eversion_t v) { std::map::iterator p = missing.find(oid); assert(p != missing.end()); assert(p->second.need <= v); got(p); } void pg_missing_t::got(const std::map::iterator &m) { rmissing.erase(m->second.need.version); missing.erase(m); } void pg_missing_t::split_into( pg_t child_pgid, unsigned split_bits, pg_missing_t *omissing) { unsigned mask = ~((~0)<::iterator i = missing.begin(); i != missing.end(); ) { if ((i->first.hash & mask) == child_pgid.m_seed) { omissing->add(i->first, i->second.need, i->second.have); rm(i++); } else { ++i; } } } // -- object_copy_cursor_t -- void object_copy_cursor_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(attr_complete, bl); ::encode(data_offset, bl); ::encode(data_complete, bl); ::encode(omap_offset, bl); ::encode(omap_complete, bl); ENCODE_FINISH(bl); } void object_copy_cursor_t::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(attr_complete, bl); ::decode(data_offset, bl); ::decode(data_complete, bl); ::decode(omap_offset, bl); ::decode(omap_complete, bl); DECODE_FINISH(bl); } void object_copy_cursor_t::dump(Formatter *f) const { f->dump_unsigned("attr_complete", (int)attr_complete); f->dump_unsigned("data_offset", data_offset); f->dump_unsigned("data_complete", (int)data_complete); f->dump_string("omap_offset", omap_offset); f->dump_unsigned("omap_complete", (int)omap_complete); } void object_copy_cursor_t::generate_test_instances(list& o) { o.push_back(new object_copy_cursor_t); o.push_back(new object_copy_cursor_t); o.back()->attr_complete = true; o.back()->data_offset = 123; o.push_back(new object_copy_cursor_t); o.back()->attr_complete = true; o.back()->data_complete = true; o.back()->omap_offset = "foo"; o.push_back(new object_copy_cursor_t); o.back()->attr_complete = true; o.back()->data_complete = true; o.back()->omap_complete = true; } // -- object_copy_data_t -- void object_copy_data_t::encode_classic(bufferlist& bl) const { ::encode(size, bl); ::encode(mtime, bl); ::encode(attrs, bl); ::encode(data, bl); ::encode(omap, bl); ::encode(cursor, bl); } void object_copy_data_t::decode_classic(bufferlist::iterator& bl) { ::decode(size, bl); ::decode(mtime, bl); ::decode(attrs, bl); ::decode(data, bl); ::decode(omap, bl); ::decode(cursor, bl); } void object_copy_data_t::encode(bufferlist& bl) const { ENCODE_START(3, 1, bl); ::encode(size, bl); ::encode(mtime, bl); ::encode(category, bl); ::encode(attrs, bl); ::encode(data, bl); ::encode(omap, bl); ::encode(cursor, bl); ::encode(omap_header, bl); ::encode(snaps, bl); ::encode(snap_seq, bl); ENCODE_FINISH(bl); } void object_copy_data_t::decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(size, bl); ::decode(mtime, bl); ::decode(category, bl); ::decode(attrs, bl); ::decode(data, bl); ::decode(omap, bl); ::decode(cursor, bl); if (struct_v >= 2) ::decode(omap_header, bl); if (struct_v >= 3) { ::decode(snaps, bl); ::decode(snap_seq, bl); } else { snaps.clear(); snap_seq = 0; } DECODE_FINISH(bl); } void object_copy_data_t::generate_test_instances(list& o) { o.push_back(new object_copy_data_t()); list cursors; object_copy_cursor_t::generate_test_instances(cursors); list::iterator ci = cursors.begin(); o.back()->cursor = **(ci++); o.push_back(new object_copy_data_t()); o.back()->cursor = **(ci++); o.push_back(new object_copy_data_t()); o.back()->size = 1234; o.back()->mtime.set_from_double(1234); bufferptr bp("there", 5); bufferlist bl; bl.push_back(bp); o.back()->attrs["hello"] = bl; bufferptr bp2("not", 3); bufferlist bl2; bl2.push_back(bp2); o.back()->omap["why"] = bl2; bufferptr databp("iamsomedatatocontain", 20); o.back()->data.push_back(databp); o.back()->omap_header.append("this is an omap header"); o.back()->snaps.push_back(123); } void object_copy_data_t::dump(Formatter *f) const { f->open_object_section("cursor"); cursor.dump(f); f->close_section(); // cursor f->dump_int("size", size); f->dump_stream("mtime") << mtime; /* we should really print out the attrs here, but bufferlist const-correctness prents that */ f->dump_int("attrs_size", attrs.size()); f->dump_int("omap_size", omap.size()); f->dump_int("omap_header_length", omap_header.length()); f->dump_int("data_length", data.length()); f->open_array_section("snaps"); for (vector::const_iterator p = snaps.begin(); p != snaps.end(); ++p) f->dump_unsigned("snap", *p); f->close_section(); } // -- pg_create_t -- void pg_create_t::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(created, bl); ::encode(parent, bl); ::encode(split_bits, bl); ENCODE_FINISH(bl); } void pg_create_t::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(created, bl); ::decode(parent, bl); ::decode(split_bits, bl); DECODE_FINISH(bl); } void pg_create_t::dump(Formatter *f) const { f->dump_unsigned("created", created); f->dump_stream("parent") << parent; f->dump_int("split_bits", split_bits); } void pg_create_t::generate_test_instances(list& o) { o.push_back(new pg_create_t); o.push_back(new pg_create_t(1, pg_t(3, 4, -1), 2)); } // -- pg_hit_set_info_t -- void pg_hit_set_info_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(begin, bl); ::encode(end, bl); ::encode(version, bl); ENCODE_FINISH(bl); } void pg_hit_set_info_t::decode(bufferlist::iterator& p) { DECODE_START(1, p); ::decode(begin, p); ::decode(end, p); ::decode(version, p); DECODE_FINISH(p); } void pg_hit_set_info_t::dump(Formatter *f) const { f->dump_stream("begin") << begin; f->dump_stream("end") << end; f->dump_stream("version") << version; } void pg_hit_set_info_t::generate_test_instances(list& ls) { ls.push_back(new pg_hit_set_info_t); ls.push_back(new pg_hit_set_info_t); ls.back()->begin = utime_t(1, 2); ls.back()->end = utime_t(3, 4); } // -- pg_hit_set_history_t -- void pg_hit_set_history_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(current_last_update, bl); ::encode(current_last_stamp, bl); ::encode(current_info, bl); ::encode(history, bl); ENCODE_FINISH(bl); } void pg_hit_set_history_t::decode(bufferlist::iterator& p) { DECODE_START(1, p); ::decode(current_last_update, p); ::decode(current_last_stamp, p); ::decode(current_info, p); ::decode(history, p); DECODE_FINISH(p); } void pg_hit_set_history_t::dump(Formatter *f) const { f->dump_stream("current_last_update") << current_last_update; f->dump_stream("current_last_stamp") << current_last_stamp; f->open_object_section("current_info"); current_info.dump(f); f->close_section(); f->open_array_section("history"); for (list::const_iterator p = history.begin(); p != history.end(); ++p) { f->open_object_section("info"); p->dump(f); f->close_section(); } f->close_section(); } void pg_hit_set_history_t::generate_test_instances(list& ls) { ls.push_back(new pg_hit_set_history_t); ls.push_back(new pg_hit_set_history_t); ls.back()->current_last_update = eversion_t(1, 2); ls.back()->current_last_stamp = utime_t(100, 123); ls.back()->current_info.begin = utime_t(2, 4); ls.back()->current_info.end = utime_t(62, 24); ls.back()->history.push_back(ls.back()->current_info); ls.back()->history.push_back(pg_hit_set_info_t()); } // -- osd_peer_stat_t -- void osd_peer_stat_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(stamp, bl); ENCODE_FINISH(bl); } void osd_peer_stat_t::decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(stamp, bl); DECODE_FINISH(bl); } void osd_peer_stat_t::dump(Formatter *f) const { f->dump_stream("stamp") << stamp; } void osd_peer_stat_t::generate_test_instances(list& o) { o.push_back(new osd_peer_stat_t); o.push_back(new osd_peer_stat_t); o.back()->stamp = utime_t(1, 2); } ostream& operator<<(ostream& out, const osd_peer_stat_t &stat) { return out << "stat(" << stat.stamp << ")"; } // -- OSDSuperblock -- void OSDSuperblock::encode(bufferlist &bl) const { ENCODE_START(6, 5, bl); ::encode(cluster_fsid, bl); ::encode(whoami, bl); ::encode(current_epoch, bl); ::encode(oldest_map, bl); ::encode(newest_map, bl); ::encode(weight, bl); compat_features.encode(bl); ::encode(clean_thru, bl); ::encode(mounted, bl); ::encode(osd_fsid, bl); ::encode(last_map_marked_full, bl); ENCODE_FINISH(bl); } void OSDSuperblock::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 5, 5, bl); if (struct_v < 3) { string magic; ::decode(magic, bl); } ::decode(cluster_fsid, bl); ::decode(whoami, bl); ::decode(current_epoch, bl); ::decode(oldest_map, bl); ::decode(newest_map, bl); ::decode(weight, bl); if (struct_v >= 2) { compat_features.decode(bl); } else { //upgrade it! compat_features.incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BASE); } ::decode(clean_thru, bl); ::decode(mounted, bl); if (struct_v >= 4) ::decode(osd_fsid, bl); if (struct_v >= 6) ::decode(last_map_marked_full, bl); DECODE_FINISH(bl); } void OSDSuperblock::dump(Formatter *f) const { f->dump_stream("cluster_fsid") << cluster_fsid; f->dump_stream("osd_fsid") << osd_fsid; f->dump_int("whoami", whoami); f->dump_int("current_epoch", current_epoch); f->dump_int("oldest_map", oldest_map); f->dump_int("newest_map", newest_map); f->dump_float("weight", weight); f->open_object_section("compat"); compat_features.dump(f); f->close_section(); f->dump_int("clean_thru", clean_thru); f->dump_int("last_epoch_mounted", mounted); f->dump_int("last_map_marked_full", last_map_marked_full); } void OSDSuperblock::generate_test_instances(list& o) { OSDSuperblock z; o.push_back(new OSDSuperblock(z)); memset(&z.cluster_fsid, 1, sizeof(z.cluster_fsid)); memset(&z.osd_fsid, 2, sizeof(z.osd_fsid)); z.whoami = 3; z.current_epoch = 4; z.oldest_map = 5; z.newest_map = 9; z.mounted = 8; z.clean_thru = 7; o.push_back(new OSDSuperblock(z)); z.last_map_marked_full = 7; o.push_back(new OSDSuperblock(z)); } // -- SnapSet -- void SnapSet::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(seq, bl); ::encode(head_exists, bl); ::encode(snaps, bl); ::encode(clones, bl); ::encode(clone_overlap, bl); ::encode(clone_size, bl); ENCODE_FINISH(bl); } void SnapSet::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(seq, bl); ::decode(head_exists, bl); ::decode(snaps, bl); ::decode(clones, bl); ::decode(clone_overlap, bl); ::decode(clone_size, bl); DECODE_FINISH(bl); } void SnapSet::dump(Formatter *f) const { SnapContext sc(seq, snaps); f->open_object_section("snap_context"); sc.dump(f); f->close_section(); f->dump_int("head_exists", head_exists); f->open_array_section("clones"); for (vector::const_iterator p = clones.begin(); p != clones.end(); ++p) { f->open_object_section("clone"); f->dump_unsigned("snap", *p); f->dump_unsigned("size", clone_size.find(*p)->second); f->dump_stream("overlap") << clone_overlap.find(*p)->second; f->close_section(); } f->close_section(); } void SnapSet::generate_test_instances(list& o) { o.push_back(new SnapSet); o.push_back(new SnapSet); o.back()->head_exists = true; o.back()->seq = 123; o.back()->snaps.push_back(123); o.back()->snaps.push_back(12); o.push_back(new SnapSet); o.back()->head_exists = true; o.back()->seq = 123; o.back()->snaps.push_back(123); o.back()->snaps.push_back(12); o.back()->clones.push_back(12); o.back()->clone_size[12] = 12345; o.back()->clone_overlap[12]; } ostream& operator<<(ostream& out, const SnapSet& cs) { return out << cs.seq << "=" << cs.snaps << ":" << cs.clones << (cs.head_exists ? "+head":""); } void SnapSet::from_snap_set(const librados::snap_set_t& ss) { // NOTE: our reconstruction of snaps (and the snapc) is not strictly // correct: it will not include snaps that still logically exist // but for which there was no clone that is defined. For all // practical purposes this doesn't matter, since we only use that // information to clone on the OSD, and we have already moved // forward past that part of the object history. seq = ss.seq; set _snaps; set _clones; head_exists = false; for (vector::const_iterator p = ss.clones.begin(); p != ss.clones.end(); ++p) { if (p->cloneid == librados::SNAP_HEAD) { head_exists = true; } else { _clones.insert(p->cloneid); _snaps.insert(p->snaps.begin(), p->snaps.end()); clone_size[p->cloneid] = p->size; clone_overlap[p->cloneid]; // the entry must exist, even if it's empty. for (vector >::const_iterator q = p->overlap.begin(); q != p->overlap.end(); ++q) clone_overlap[p->cloneid].insert(q->first, q->second); } } // ascending clones.clear(); clones.reserve(_clones.size()); for (set::iterator p = _clones.begin(); p != _clones.end(); ++p) clones.push_back(*p); // descending snaps.clear(); snaps.reserve(_snaps.size()); for (set::reverse_iterator p = _snaps.rbegin(); p != _snaps.rend(); ++p) snaps.push_back(*p); } uint64_t SnapSet::get_clone_bytes(snapid_t clone) const { assert(clone_size.count(clone)); uint64_t size = clone_size.find(clone)->second; assert(clone_overlap.count(clone)); const interval_set &overlap = clone_overlap.find(clone)->second; for (interval_set::const_iterator i = overlap.begin(); i != overlap.end(); ++i) { assert(size >= i.get_len()); size -= i.get_len(); } return size; } // -- watch_info_t -- void watch_info_t::encode(bufferlist& bl) const { ENCODE_START(4, 3, bl); ::encode(cookie, bl); ::encode(timeout_seconds, bl); ::encode(addr, bl); ENCODE_FINISH(bl); } void watch_info_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl); ::decode(cookie, bl); if (struct_v < 2) { uint64_t ver; ::decode(ver, bl); } ::decode(timeout_seconds, bl); if (struct_v >= 4) { ::decode(addr, bl); } DECODE_FINISH(bl); } void watch_info_t::dump(Formatter *f) const { f->dump_unsigned("cookie", cookie); f->dump_unsigned("timeout_seconds", timeout_seconds); f->open_object_section("addr"); addr.dump(f); f->close_section(); } void watch_info_t::generate_test_instances(list& o) { o.push_back(new watch_info_t); o.push_back(new watch_info_t); o.back()->cookie = 123; o.back()->timeout_seconds = 99; entity_addr_t ea; ea.set_nonce(1); ea.set_family(AF_INET); ea.set_in4_quad(0, 127); ea.set_in4_quad(1, 0); ea.set_in4_quad(2, 1); ea.set_in4_quad(3, 2); ea.set_port(2); o.back()->addr = ea; } // -- object_info_t -- void object_info_t::copy_user_bits(const object_info_t& other) { // these bits are copied from head->clone. size = other.size; mtime = other.mtime; local_mtime = other.local_mtime; last_reqid = other.last_reqid; truncate_seq = other.truncate_seq; truncate_size = other.truncate_size; flags = other.flags; category = other.category; user_version = other.user_version; } ps_t object_info_t::legacy_object_locator_to_ps(const object_t &oid, const object_locator_t &loc) { ps_t ps; if (loc.key.length()) // Hack, we don't have the osd map, so we don't really know the hash... ps = ceph_str_hash(CEPH_STR_HASH_RJENKINS, loc.key.c_str(), loc.key.length()); else ps = ceph_str_hash(CEPH_STR_HASH_RJENKINS, oid.name.c_str(), oid.name.length()); return ps; } void object_info_t::encode(bufferlist& bl) const { object_locator_t myoloc(soid); map old_watchers; for (map, watch_info_t>::const_iterator i = watchers.begin(); i != watchers.end(); ++i) { old_watchers.insert(make_pair(i->first.second, i->second)); } ENCODE_START(14, 8, bl); ::encode(soid, bl); ::encode(myoloc, bl); //Retained for compatibility ::encode(category, bl); ::encode(version, bl); ::encode(prior_version, bl); ::encode(last_reqid, bl); ::encode(size, bl); ::encode(mtime, bl); if (soid.snap == CEPH_NOSNAP) ::encode(wrlock_by, bl); else ::encode(snaps, bl); ::encode(truncate_seq, bl); ::encode(truncate_size, bl); ::encode(is_lost(), bl); ::encode(old_watchers, bl); /* shenanigans to avoid breaking backwards compatibility in the disk format. * When we can, switch this out for simply putting the version_t on disk. */ eversion_t user_eversion(0, user_version); ::encode(user_eversion, bl); ::encode(test_flag(FLAG_USES_TMAP), bl); ::encode(watchers, bl); __u32 _flags = flags; ::encode(_flags, bl); ::encode(local_mtime, bl); ENCODE_FINISH(bl); } void object_info_t::decode(bufferlist::iterator& bl) { object_locator_t myoloc; DECODE_START_LEGACY_COMPAT_LEN(13, 8, 8, bl); map old_watchers; if (struct_v >= 2 && struct_v <= 5) { sobject_t obj; ::decode(obj, bl); ::decode(myoloc, bl); soid = hobject_t(obj.oid, myoloc.key, obj.snap, 0, 0 , ""); soid.hash = legacy_object_locator_to_ps(soid.oid, myoloc); } else if (struct_v >= 6) { ::decode(soid, bl); ::decode(myoloc, bl); if (struct_v == 6) { hobject_t hoid(soid.oid, myoloc.key, soid.snap, soid.hash, 0 , ""); soid = hoid; } } if (struct_v >= 5) ::decode(category, bl); ::decode(version, bl); ::decode(prior_version, bl); ::decode(last_reqid, bl); ::decode(size, bl); ::decode(mtime, bl); if (soid.snap == CEPH_NOSNAP) ::decode(wrlock_by, bl); else ::decode(snaps, bl); ::decode(truncate_seq, bl); ::decode(truncate_size, bl); if (struct_v >= 3) { // if this is struct_v >= 13, we will overwrite this // below since this field is just here for backwards // compatibility __u8 lo; ::decode(lo, bl); flags = (flag_t)lo; } else { flags = (flag_t)0; } if (struct_v >= 4) { ::decode(old_watchers, bl); eversion_t user_eversion; ::decode(user_eversion, bl); user_version = user_eversion.version; } if (struct_v >= 9) { bool uses_tmap = false; ::decode(uses_tmap, bl); if (uses_tmap) set_flag(FLAG_USES_TMAP); } else { set_flag(FLAG_USES_TMAP); } if (struct_v < 10) soid.pool = myoloc.pool; if (struct_v >= 11) { ::decode(watchers, bl); } else { for (map::iterator i = old_watchers.begin(); i != old_watchers.end(); ++i) { watchers.insert( make_pair( make_pair(i->second.cookie, i->first), i->second)); } } if (struct_v >= 13) { __u32 _flags; ::decode(_flags, bl); flags = (flag_t)_flags; } if (struct_v >= 14) { ::decode(local_mtime, bl); } else { local_mtime = utime_t(); } DECODE_FINISH(bl); } void object_info_t::dump(Formatter *f) const { f->open_object_section("oid"); soid.dump(f); f->close_section(); f->dump_string("category", category); f->dump_stream("version") << version; f->dump_stream("prior_version") << prior_version; f->dump_stream("last_reqid") << last_reqid; f->dump_unsigned("user_version", user_version); f->dump_unsigned("size", size); f->dump_stream("mtime") << mtime; f->dump_stream("local_mtime") << local_mtime; f->dump_unsigned("lost", (int)is_lost()); f->dump_unsigned("flags", (int)flags); f->dump_stream("wrlock_by") << wrlock_by; f->open_array_section("snaps"); for (vector::const_iterator p = snaps.begin(); p != snaps.end(); ++p) f->dump_unsigned("snap", *p); f->close_section(); f->dump_unsigned("truncate_seq", truncate_seq); f->dump_unsigned("truncate_size", truncate_size); f->open_object_section("watchers"); for (map,watch_info_t>::const_iterator p = watchers.begin(); p != watchers.end(); ++p) { stringstream ss; ss << p->first.second; f->open_object_section(ss.str().c_str()); p->second.dump(f); f->close_section(); } f->close_section(); } void object_info_t::generate_test_instances(list& o) { o.push_back(new object_info_t()); // fixme } ostream& operator<<(ostream& out, const object_info_t& oi) { out << oi.soid << "(" << oi.version << " " << oi.last_reqid; if (oi.soid.snap == CEPH_NOSNAP) out << " wrlock_by=" << oi.wrlock_by; else out << " " << oi.snaps; if (oi.flags) out << " " << oi.get_flag_string(); out << " s " << oi.size; out << " uv" << oi.user_version; out << ")"; return out; } // -- ObjectRecovery -- void ObjectRecoveryProgress::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(first, bl); ::encode(data_complete, bl); ::encode(data_recovered_to, bl); ::encode(omap_recovered_to, bl); ::encode(omap_complete, bl); ENCODE_FINISH(bl); } void ObjectRecoveryProgress::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(first, bl); ::decode(data_complete, bl); ::decode(data_recovered_to, bl); ::decode(omap_recovered_to, bl); ::decode(omap_complete, bl); DECODE_FINISH(bl); } ostream &operator<<(ostream &out, const ObjectRecoveryProgress &prog) { return prog.print(out); } void ObjectRecoveryProgress::generate_test_instances( list& o) { o.push_back(new ObjectRecoveryProgress); o.back()->first = false; o.back()->data_complete = true; o.back()->omap_complete = true; o.back()->data_recovered_to = 100; o.push_back(new ObjectRecoveryProgress); o.back()->first = true; o.back()->data_complete = false; o.back()->omap_complete = false; o.back()->data_recovered_to = 0; } ostream &ObjectRecoveryProgress::print(ostream &out) const { return out << "ObjectRecoveryProgress(" << ( first ? "" : "!" ) << "first, " << "data_recovered_to:" << data_recovered_to << ", data_complete:" << ( data_complete ? "true" : "false" ) << ", omap_recovered_to:" << omap_recovered_to << ", omap_complete:" << ( omap_complete ? "true" : "false" ) << ")"; } void ObjectRecoveryProgress::dump(Formatter *f) const { f->dump_int("first?", first); f->dump_int("data_complete?", data_complete); f->dump_unsigned("data_recovered_to", data_recovered_to); f->dump_int("omap_complete?", omap_complete); f->dump_string("omap_recovered_to", omap_recovered_to); } void ObjectRecoveryInfo::encode(bufferlist &bl) const { ENCODE_START(2, 1, bl); ::encode(soid, bl); ::encode(version, bl); ::encode(size, bl); ::encode(oi, bl); ::encode(ss, bl); ::encode(copy_subset, bl); ::encode(clone_subset, bl); ENCODE_FINISH(bl); } void ObjectRecoveryInfo::decode(bufferlist::iterator &bl, int64_t pool) { DECODE_START(2, bl); ::decode(soid, bl); ::decode(version, bl); ::decode(size, bl); ::decode(oi, bl); ::decode(ss, bl); ::decode(copy_subset, bl); ::decode(clone_subset, bl); DECODE_FINISH(bl); if (struct_v < 2) { if (!soid.is_max() && soid.pool == -1) soid.pool = pool; map > tmp; tmp.swap(clone_subset); for (map >::iterator i = tmp.begin(); i != tmp.end(); ++i) { hobject_t first(i->first); if (!first.is_max() && first.pool == -1) first.pool = pool; clone_subset[first].swap(i->second); } } } void ObjectRecoveryInfo::generate_test_instances( list& o) { o.push_back(new ObjectRecoveryInfo); o.back()->soid = hobject_t(sobject_t("key", CEPH_NOSNAP)); o.back()->version = eversion_t(0,0); o.back()->size = 100; } void ObjectRecoveryInfo::dump(Formatter *f) const { f->dump_stream("object") << soid; f->dump_stream("at_version") << version; f->dump_stream("size") << size; { f->open_object_section("object_info"); oi.dump(f); f->close_section(); } { f->open_object_section("snapset"); ss.dump(f); f->close_section(); } f->dump_stream("copy_subset") << copy_subset; f->dump_stream("clone_subset") << clone_subset; } ostream& operator<<(ostream& out, const ObjectRecoveryInfo &inf) { return inf.print(out); } ostream &ObjectRecoveryInfo::print(ostream &out) const { return out << "ObjectRecoveryInfo(" << soid << "@" << version << ", copy_subset: " << copy_subset << ", clone_subset: " << clone_subset << ")"; } // -- PushReplyOp -- void PushReplyOp::generate_test_instances(list &o) { o.push_back(new PushReplyOp); o.push_back(new PushReplyOp); o.back()->soid = hobject_t(sobject_t("asdf", 2)); o.push_back(new PushReplyOp); o.back()->soid = hobject_t(sobject_t("asdf", CEPH_NOSNAP)); } void PushReplyOp::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(soid, bl); ENCODE_FINISH(bl); } void PushReplyOp::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(soid, bl); DECODE_FINISH(bl); } void PushReplyOp::dump(Formatter *f) const { f->dump_stream("soid") << soid; } ostream &PushReplyOp::print(ostream &out) const { return out << "PushReplyOp(" << soid << ")"; } ostream& operator<<(ostream& out, const PushReplyOp &op) { return op.print(out); } uint64_t PushReplyOp::cost(CephContext *cct) const { return cct->_conf->osd_push_per_object_cost + cct->_conf->osd_recovery_max_chunk; } // -- PullOp -- void PullOp::generate_test_instances(list &o) { o.push_back(new PullOp); o.push_back(new PullOp); o.back()->soid = hobject_t(sobject_t("asdf", 2)); o.back()->recovery_info.version = eversion_t(3, 10); o.push_back(new PullOp); o.back()->soid = hobject_t(sobject_t("asdf", CEPH_NOSNAP)); o.back()->recovery_info.version = eversion_t(0, 0); } void PullOp::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(soid, bl); ::encode(recovery_info, bl); ::encode(recovery_progress, bl); ENCODE_FINISH(bl); } void PullOp::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(soid, bl); ::decode(recovery_info, bl); ::decode(recovery_progress, bl); DECODE_FINISH(bl); } void PullOp::dump(Formatter *f) const { f->dump_stream("soid") << soid; { f->open_object_section("recovery_info"); recovery_info.dump(f); f->close_section(); } { f->open_object_section("recovery_progress"); recovery_progress.dump(f); f->close_section(); } } ostream &PullOp::print(ostream &out) const { return out << "PullOp(" << soid << ", recovery_info: " << recovery_info << ", recovery_progress: " << recovery_progress << ")"; } ostream& operator<<(ostream& out, const PullOp &op) { return op.print(out); } uint64_t PullOp::cost(CephContext *cct) const { return cct->_conf->osd_push_per_object_cost + cct->_conf->osd_recovery_max_chunk; } // -- PushOp -- void PushOp::generate_test_instances(list &o) { o.push_back(new PushOp); o.push_back(new PushOp); o.back()->soid = hobject_t(sobject_t("asdf", 2)); o.back()->version = eversion_t(3, 10); o.push_back(new PushOp); o.back()->soid = hobject_t(sobject_t("asdf", CEPH_NOSNAP)); o.back()->version = eversion_t(0, 0); } void PushOp::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(soid, bl); ::encode(version, bl); ::encode(data, bl); ::encode(data_included, bl); ::encode(omap_header, bl); ::encode(omap_entries, bl); ::encode(attrset, bl); ::encode(recovery_info, bl); ::encode(after_progress, bl); ::encode(before_progress, bl); ENCODE_FINISH(bl); } void PushOp::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(soid, bl); ::decode(version, bl); ::decode(data, bl); ::decode(data_included, bl); ::decode(omap_header, bl); ::decode(omap_entries, bl); ::decode(attrset, bl); ::decode(recovery_info, bl); ::decode(after_progress, bl); ::decode(before_progress, bl); DECODE_FINISH(bl); } void PushOp::dump(Formatter *f) const { f->dump_stream("soid") << soid; f->dump_stream("version") << version; f->dump_int("data_len", data.length()); f->dump_stream("data_included") << data_included; f->dump_int("omap_header_len", omap_header.length()); f->dump_int("omap_entries_len", omap_entries.size()); f->dump_int("attrset_len", attrset.size()); { f->open_object_section("recovery_info"); recovery_info.dump(f); f->close_section(); } { f->open_object_section("after_progress"); after_progress.dump(f); f->close_section(); } { f->open_object_section("before_progress"); before_progress.dump(f); f->close_section(); } } ostream &PushOp::print(ostream &out) const { return out << "PushOp(" << soid << ", version: " << version << ", data_included: " << data_included << ", data_size: " << data.length() << ", omap_header_size: " << omap_header.length() << ", omap_entries_size: " << omap_entries.size() << ", attrset_size: " << attrset.size() << ", recovery_info: " << recovery_info << ", after_progress: " << after_progress << ", before_progress: " << before_progress << ")"; } ostream& operator<<(ostream& out, const PushOp &op) { return op.print(out); } uint64_t PushOp::cost(CephContext *cct) const { uint64_t cost = data_included.size(); for (map::const_iterator i = omap_entries.begin(); i != omap_entries.end(); ++i) { cost += i->second.length(); } cost += cct->_conf->osd_push_per_object_cost; return cost; } // -- ScrubMap -- void ScrubMap::merge_incr(const ScrubMap &l) { assert(valid_through == l.incr_since); attrs = l.attrs; valid_through = l.valid_through; for (map::const_iterator p = l.objects.begin(); p != l.objects.end(); ++p){ if (p->second.negative) { map::iterator q = objects.find(p->first); if (q != objects.end()) { objects.erase(q); } } else { objects[p->first] = p->second; } } } void ScrubMap::encode(bufferlist& bl) const { ENCODE_START(3, 2, bl); ::encode(objects, bl); ::encode(attrs, bl); bufferlist old_logbl; // not used ::encode(old_logbl, bl); ::encode(valid_through, bl); ::encode(incr_since, bl); ENCODE_FINISH(bl); } void ScrubMap::decode(bufferlist::iterator& bl, int64_t pool) { DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl); ::decode(objects, bl); ::decode(attrs, bl); bufferlist old_logbl; // not used ::decode(old_logbl, bl); ::decode(valid_through, bl); ::decode(incr_since, bl); DECODE_FINISH(bl); // handle hobject_t upgrade if (struct_v < 3) { map tmp; tmp.swap(objects); for (map::iterator i = tmp.begin(); i != tmp.end(); ++i) { hobject_t first(i->first); if (!first.is_max() && first.pool == -1) first.pool = pool; objects[first] = i->second; } } } void ScrubMap::dump(Formatter *f) const { f->dump_stream("valid_through") << valid_through; f->dump_stream("incremental_since") << incr_since; f->open_array_section("attrs"); for (map::const_iterator p = attrs.begin(); p != attrs.end(); ++p) { f->open_object_section("attr"); f->dump_string("name", p->first); f->dump_int("length", p->second.length()); f->close_section(); } f->close_section(); f->open_array_section("objects"); for (map::const_iterator p = objects.begin(); p != objects.end(); ++p) { f->open_object_section("object"); f->dump_string("name", p->first.oid.name); f->dump_unsigned("hash", p->first.hash); f->dump_string("key", p->first.get_key()); f->dump_int("snapid", p->first.snap); p->second.dump(f); f->close_section(); } f->close_section(); } void ScrubMap::generate_test_instances(list& o) { o.push_back(new ScrubMap); o.push_back(new ScrubMap); o.back()->valid_through = eversion_t(1, 2); o.back()->incr_since = eversion_t(3, 4); o.back()->attrs["foo"] = buffer::copy("foo", 3); o.back()->attrs["bar"] = buffer::copy("barval", 6); list obj; object::generate_test_instances(obj); o.back()->objects[hobject_t(object_t("foo"), "fookey", 123, 456, 0, "")] = *obj.back(); obj.pop_back(); o.back()->objects[hobject_t(object_t("bar"), string(), 123, 456, 0, "")] = *obj.back(); } // -- ScrubMap::object -- void ScrubMap::object::encode(bufferlist& bl) const { ENCODE_START(6, 2, bl); ::encode(size, bl); ::encode(negative, bl); ::encode(attrs, bl); ::encode(digest, bl); ::encode(digest_present, bl); ::encode(nlinks, bl); ::encode(snapcolls, bl); ::encode(omap_digest, bl); ::encode(omap_digest_present, bl); ::encode(read_error, bl); ENCODE_FINISH(bl); } void ScrubMap::object::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 2, 2, bl); ::decode(size, bl); ::decode(negative, bl); ::decode(attrs, bl); if (struct_v >= 3) { ::decode(digest, bl); ::decode(digest_present, bl); } if (struct_v >= 4) { ::decode(nlinks, bl); ::decode(snapcolls, bl); } else { /* Indicates that encoder was not aware of this field since stat must * return nlink >= 1 */ nlinks = 0; } if (struct_v >= 5) { ::decode(omap_digest, bl); ::decode(omap_digest_present, bl); } if (struct_v >= 6) { ::decode(read_error, bl); } DECODE_FINISH(bl); } void ScrubMap::object::dump(Formatter *f) const { f->dump_int("size", size); f->dump_int("negative", negative); f->open_array_section("attrs"); for (map::const_iterator p = attrs.begin(); p != attrs.end(); ++p) { f->open_object_section("attr"); f->dump_string("name", p->first); f->dump_int("length", p->second.length()); f->close_section(); } f->close_section(); } void ScrubMap::object::generate_test_instances(list& o) { o.push_back(new object); o.push_back(new object); o.back()->negative = true; o.push_back(new object); o.back()->size = 123; o.back()->attrs["foo"] = buffer::copy("foo", 3); o.back()->attrs["bar"] = buffer::copy("barval", 6); } // -- OSDOp -- ostream& operator<<(ostream& out, const OSDOp& op) { out << ceph_osd_op_name(op.op.op); if (ceph_osd_op_type_data(op.op.op)) { // data extent switch (op.op.op) { case CEPH_OSD_OP_STAT: case CEPH_OSD_OP_DELETE: case CEPH_OSD_OP_LIST_WATCHERS: case CEPH_OSD_OP_LIST_SNAPS: case CEPH_OSD_OP_UNDIRTY: case CEPH_OSD_OP_ISDIRTY: case CEPH_OSD_OP_CACHE_FLUSH: case CEPH_OSD_OP_CACHE_TRY_FLUSH: case CEPH_OSD_OP_CACHE_EVICT: break; case CEPH_OSD_OP_ASSERT_VER: out << " v" << op.op.assert_ver.ver; break; case CEPH_OSD_OP_TRUNCATE: out << " " << op.op.extent.offset; break; case CEPH_OSD_OP_MASKTRUNC: case CEPH_OSD_OP_TRIMTRUNC: out << " " << op.op.extent.truncate_seq << "@" << (int64_t)op.op.extent.truncate_size; break; case CEPH_OSD_OP_ROLLBACK: out << " " << snapid_t(op.op.snap.snapid); break; case CEPH_OSD_OP_WATCH: out << (op.op.watch.flag ? " add":" remove") << " cookie " << op.op.watch.cookie << " ver " << op.op.watch.ver; break; case CEPH_OSD_OP_COPY_GET: case CEPH_OSD_OP_COPY_GET_CLASSIC: out << " max " << op.op.copy_get.max; break; case CEPH_OSD_OP_COPY_FROM: out << " ver " << op.op.copy_from.src_version; break; case CEPH_OSD_OP_SETALLOCHINT: out << " object_size " << op.op.alloc_hint.expected_object_size << " write_size " << op.op.alloc_hint.expected_write_size; break; default: out << " " << op.op.extent.offset << "~" << op.op.extent.length; if (op.op.extent.truncate_seq) out << " [" << op.op.extent.truncate_seq << "@" << (int64_t)op.op.extent.truncate_size << "]"; } } else if (ceph_osd_op_type_attr(op.op.op)) { // xattr name if (op.op.xattr.name_len && op.indata.length()) { out << " "; op.indata.write(0, op.op.xattr.name_len, out); } if (op.op.xattr.value_len) out << " (" << op.op.xattr.value_len << ")"; if (op.op.op == CEPH_OSD_OP_CMPXATTR) out << " op " << (int)op.op.xattr.cmp_op << " mode " << (int)op.op.xattr.cmp_mode; } else if (ceph_osd_op_type_exec(op.op.op)) { // class.method if (op.op.cls.class_len && op.indata.length()) { out << " "; op.indata.write(0, op.op.cls.class_len, out); out << "."; op.indata.write(op.op.cls.class_len, op.op.cls.method_len, out); } } else if (ceph_osd_op_type_pg(op.op.op)) { switch (op.op.op) { case CEPH_OSD_OP_PGLS: case CEPH_OSD_OP_PGLS_FILTER: out << " start_epoch " << op.op.pgls.start_epoch; break; case CEPH_OSD_OP_PG_HITSET_LS: break; case CEPH_OSD_OP_PG_HITSET_GET: out << " " << utime_t(op.op.hit_set_get.stamp); break; } } else if (ceph_osd_op_type_multi(op.op.op)) { switch (op.op.op) { case CEPH_OSD_OP_CLONERANGE: out << " " << op.op.clonerange.offset << "~" << op.op.clonerange.length << " from " << op.soid << " offset " << op.op.clonerange.src_offset; break; case CEPH_OSD_OP_ASSERT_SRC_VERSION: out << " v" << op.op.watch.ver << " of " << op.soid; break; case CEPH_OSD_OP_SRC_CMPXATTR: out << " " << op.soid; if (op.op.xattr.name_len && op.indata.length()) { out << " "; op.indata.write(0, op.op.xattr.name_len, out); } if (op.op.xattr.value_len) out << " (" << op.op.xattr.value_len << ")"; if (op.op.op == CEPH_OSD_OP_CMPXATTR) out << " op " << (int)op.op.xattr.cmp_op << " mode " << (int)op.op.xattr.cmp_mode; break; } } return out; } void OSDOp::split_osd_op_vector_in_data(vector& ops, bufferlist& in) { bufferlist::iterator datap = in.begin(); for (unsigned i = 0; i < ops.size(); i++) { if (ceph_osd_op_type_multi(ops[i].op.op)) { ::decode(ops[i].soid, datap); } if (ops[i].op.payload_len) { datap.copy(ops[i].op.payload_len, ops[i].indata); } } } void OSDOp::merge_osd_op_vector_in_data(vector& ops, bufferlist& out) { for (unsigned i = 0; i < ops.size(); i++) { if (ceph_osd_op_type_multi(ops[i].op.op)) { ::encode(ops[i].soid, out); } if (ops[i].indata.length()) { ops[i].op.payload_len = ops[i].indata.length(); out.append(ops[i].indata); } } } void OSDOp::split_osd_op_vector_out_data(vector& ops, bufferlist& in) { bufferlist::iterator datap = in.begin(); for (unsigned i = 0; i < ops.size(); i++) { if (ops[i].op.payload_len) { datap.copy(ops[i].op.payload_len, ops[i].outdata); } } } void OSDOp::merge_osd_op_vector_out_data(vector& ops, bufferlist& out) { for (unsigned i = 0; i < ops.size(); i++) { if (ops[i].outdata.length()) { ops[i].op.payload_len = ops[i].outdata.length(); out.append(ops[i].outdata); } } } ceph-0.80.11/src/osd/ClassHandler.cc0000664000175100017510000001620312623076744021125 0ustar jenkins-buildjenkins-build #include "include/types.h" #include "msg/Message.h" #include "osd/OSD.h" #include "ClassHandler.h" #include #include #if defined(__FreeBSD__) #include #endif #include "common/config.h" #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix *_dout #define CLS_PREFIX "libcls_" #define CLS_SUFFIX ".so" int ClassHandler::open_class(const string& cname, ClassData **pcls) { Mutex::Locker lock(mutex); ClassData *cls = _get_class(cname); if (cls->status != ClassData::CLASS_OPEN) { int r = _load_class(cls); if (r) return r; } *pcls = cls; return 0; } int ClassHandler::open_all_classes() { dout(10) << __func__ << dendl; DIR *dir = ::opendir(cct->_conf->osd_class_dir.c_str()); if (!dir) return -errno; char buf[offsetof(struct dirent, d_name) + PATH_MAX + 1]; struct dirent *pde; int r = 0; while ((r = ::readdir_r(dir, (dirent *)&buf, &pde)) == 0 && pde) { if (pde->d_name[0] == '.') continue; if (strlen(pde->d_name) > sizeof(CLS_PREFIX) - 1 + sizeof(CLS_SUFFIX) - 1 && strncmp(pde->d_name, CLS_PREFIX, sizeof(CLS_PREFIX) - 1) == 0 && strcmp(pde->d_name + strlen(pde->d_name) - (sizeof(CLS_SUFFIX) - 1), CLS_SUFFIX) == 0) { char cname[PATH_MAX + 1]; strcpy(cname, pde->d_name + sizeof(CLS_PREFIX) - 1); cname[strlen(cname) - (sizeof(CLS_SUFFIX) - 1)] = '\0'; dout(10) << __func__ << " found " << cname << dendl; ClassData *cls; r = open_class(cname, &cls); if (r < 0) goto out; } } out: closedir(dir); return r; } void ClassHandler::shutdown() { for (map::iterator p = classes.begin(); p != classes.end(); ++p) { dlclose(p->second.handle); } classes.clear(); } ClassHandler::ClassData *ClassHandler::_get_class(const string& cname) { ClassData *cls; map::iterator iter = classes.find(cname); if (iter != classes.end()) { cls = &iter->second; } else { cls = &classes[cname]; dout(10) << "_get_class adding new class name " << cname << " " << cls << dendl; cls->name = cname; cls->handler = this; } return cls; } int ClassHandler::_load_class(ClassData *cls) { // already open if (cls->status == ClassData::CLASS_OPEN) return 0; if (cls->status == ClassData::CLASS_UNKNOWN || cls->status == ClassData::CLASS_MISSING) { char fname[PATH_MAX]; snprintf(fname, sizeof(fname), "%s/" CLS_PREFIX "%s" CLS_SUFFIX, cct->_conf->osd_class_dir.c_str(), cls->name.c_str()); dout(10) << "_load_class " << cls->name << " from " << fname << dendl; struct stat st; int r = ::stat(fname, &st); if (r < 0) return -errno; cls->handle = dlopen(fname, RTLD_NOW); if (!cls->handle) { dout(0) << "_load_class could not open class " << fname << " (dlopen failed): " << dlerror() << dendl; cls->status = ClassData::CLASS_MISSING; return -EIO; } cls_deps_t *(*cls_deps)(); cls_deps = (cls_deps_t *(*)())dlsym(cls->handle, "class_deps"); if (cls_deps) { cls_deps_t *deps = cls_deps(); while (deps) { if (!deps->name) break; ClassData *cls_dep = _get_class(deps->name); cls->dependencies.insert(cls_dep); if (cls_dep->status != ClassData::CLASS_OPEN) cls->missing_dependencies.insert(cls_dep); deps++; } } } // resolve dependencies set::iterator p = cls->missing_dependencies.begin(); while (p != cls->missing_dependencies.end()) { ClassData *dc = *p; int r = _load_class(dc); if (r < 0) { cls->status = ClassData::CLASS_MISSING_DEPS; return r; } dout(10) << "_load_class " << cls->name << " satisfied dependency " << dc->name << dendl; cls->missing_dependencies.erase(p++); } // initialize void (*cls_init)() = (void (*)())dlsym(cls->handle, "__cls_init"); if (cls_init) { cls->status = ClassData::CLASS_INITIALIZING; cls_init(); } dout(10) << "_load_class " << cls->name << " success" << dendl; cls->status = ClassData::CLASS_OPEN; return 0; } ClassHandler::ClassData *ClassHandler::register_class(const char *cname) { assert(mutex.is_locked()); ClassData *cls = _get_class(cname); dout(10) << "register_class " << cname << " status " << cls->status << dendl; if (cls->status != ClassData::CLASS_INITIALIZING) { dout(0) << "class " << cname << " isn't loaded; is the class registering under the wrong name?" << dendl; return NULL; } return cls; } void ClassHandler::unregister_class(ClassHandler::ClassData *cls) { /* FIXME: do we really need this one? */ } ClassHandler::ClassMethod *ClassHandler::ClassData::register_method(const char *mname, int flags, cls_method_call_t func) { /* no need for locking, called under the class_init mutex */ if (!flags) { derr << "register_method " << name << "." << mname << " flags " << flags << " " << (void*)func << " FAILED -- flags must be non-zero" << dendl; return NULL; } dout(10) << "register_method " << name << "." << mname << " flags " << flags << " " << (void*)func << dendl; ClassMethod& method = methods_map[mname]; method.func = func; method.name = mname; method.flags = flags; method.cls = this; return &method; } ClassHandler::ClassMethod *ClassHandler::ClassData::register_cxx_method(const char *mname, int flags, cls_method_cxx_call_t func) { /* no need for locking, called under the class_init mutex */ dout(10) << "register_cxx_method " << name << "." << mname << " flags " << flags << " " << (void*)func << dendl; ClassMethod& method = methods_map[mname]; method.cxx_func = func; method.name = mname; method.flags = flags; method.cls = this; return &method; } ClassHandler::ClassMethod *ClassHandler::ClassData::_get_method(const char *mname) { map::iterator iter = methods_map.find(mname); if (iter == methods_map.end()) return NULL; return &(iter->second); } int ClassHandler::ClassData::get_method_flags(const char *mname) { Mutex::Locker l(handler->mutex); ClassMethod *method = _get_method(mname); if (!method) return -ENOENT; return method->flags; } void ClassHandler::ClassData::unregister_method(ClassHandler::ClassMethod *method) { /* no need for locking, called under the class_init mutex */ map::iterator iter = methods_map.find(method->name); if (iter == methods_map.end()) return; methods_map.erase(iter); } void ClassHandler::ClassMethod::unregister() { cls->unregister_method(this); } int ClassHandler::ClassMethod::exec(cls_method_context_t ctx, bufferlist& indata, bufferlist& outdata) { int ret; if (cxx_func) { // C++ call version ret = cxx_func(ctx, &indata, &outdata); } else { // C version char *out = NULL; int olen = 0; ret = func(ctx, indata.c_str(), indata.length(), &out, &olen); if (out) { // assume *out was allocated via cls_alloc (which calls malloc!) buffer::ptr bp = buffer::claim_malloc(olen, out); outdata.push_back(bp); } } return ret; } ceph-0.80.11/src/osd/SnapMapper.cc0000664000175100017510000001514112623076744020630 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "SnapMapper.h" using std::string; const string SnapMapper::MAPPING_PREFIX = "MAP_"; const string SnapMapper::OBJECT_PREFIX = "OBJ_"; int OSDriver::get_keys( const std::set &keys, std::map *out) { return os->omap_get_values(cid, hoid, keys, out); } int OSDriver::get_next( const std::string &key, pair *next) { ObjectMap::ObjectMapIterator iter = os->get_omap_iterator(cid, hoid); if (!iter) { assert(0); return -EINVAL; } iter->upper_bound(key); if (iter->valid()) { if (next) *next = make_pair(iter->key(), iter->value()); return 0; } else { return -ENOENT; } } struct Mapping { snapid_t snap; hobject_t hoid; Mapping(const pair &in) : snap(in.first), hoid(in.second) {} Mapping() : snap(0) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(snap, bl); ::encode(hoid, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(snap, bl); ::decode(hoid, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(Mapping); string SnapMapper::get_prefix(snapid_t snap) { char buf[100]; int len = snprintf( buf, sizeof(buf), "%.*X_", (int)(sizeof(snap)*2), static_cast(snap)); return MAPPING_PREFIX + string(buf, len); } string SnapMapper::to_raw_key( const pair &in) { return get_prefix(in.first) + shard_prefix + in.second.to_str(); } pair SnapMapper::to_raw( const pair &in) { bufferlist bl; ::encode(Mapping(in), bl); return make_pair( to_raw_key(in), bl); } pair SnapMapper::from_raw( const pair &image) { Mapping map; bufferlist bl(image.second); bufferlist::iterator bp(bl.begin()); ::decode(map, bp); return make_pair(map.snap, map.hoid); } bool SnapMapper::is_mapping(const string &to_test) { return to_test.substr(0, MAPPING_PREFIX.size()) == MAPPING_PREFIX; } string SnapMapper::to_object_key(const hobject_t &hoid) { return OBJECT_PREFIX + shard_prefix + hoid.to_str(); } void SnapMapper::object_snaps::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(oid, bl); ::encode(snaps, bl); ENCODE_FINISH(bl); } void SnapMapper::object_snaps::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(oid, bl); ::decode(snaps, bl); DECODE_FINISH(bl); } int SnapMapper::get_snaps( const hobject_t &oid, object_snaps *out) { assert(check(oid)); set keys; map got; keys.insert(to_object_key(oid)); int r = backend.get_keys(keys, &got); if (r < 0) return r; if (got.empty()) return -ENOENT; if (out) { bufferlist::iterator bp = got.begin()->second.begin(); ::decode(*out, bp); assert(!out->snaps.empty()); } return 0; } void SnapMapper::clear_snaps( const hobject_t &oid, MapCacher::Transaction *t) { assert(check(oid)); set to_remove; to_remove.insert(to_object_key(oid)); backend.remove_keys(to_remove, t); } void SnapMapper::set_snaps( const hobject_t &oid, const object_snaps &in, MapCacher::Transaction *t) { assert(check(oid)); map to_set; bufferlist bl; ::encode(in, bl); to_set[to_object_key(oid)] = bl; backend.set_keys(to_set, t); } int SnapMapper::update_snaps( const hobject_t &oid, const set &new_snaps, const set *old_snaps_check, MapCacher::Transaction *t) { assert(check(oid)); if (new_snaps.empty()) return remove_oid(oid, t); object_snaps out; int r = get_snaps(oid, &out); if (r < 0) return r; if (old_snaps_check) assert(out.snaps == *old_snaps_check); object_snaps in(oid, new_snaps); set_snaps(oid, in, t); set to_remove; for (set::iterator i = out.snaps.begin(); i != out.snaps.end(); ++i) { if (!new_snaps.count(*i)) { to_remove.insert(to_raw_key(make_pair(*i, oid))); } } backend.remove_keys(to_remove, t); return 0; } void SnapMapper::add_oid( const hobject_t &oid, set snaps, MapCacher::Transaction *t) { assert(check(oid)); { object_snaps out; int r = get_snaps(oid, &out); assert(r == -ENOENT); } object_snaps _snaps(oid, snaps); set_snaps(oid, _snaps, t); map to_add; for (set::iterator i = snaps.begin(); i != snaps.end(); ++i) { to_add.insert(to_raw(make_pair(*i, oid))); } backend.set_keys(to_add, t); } int SnapMapper::get_next_object_to_trim( snapid_t snap, hobject_t *hoid) { for (set::iterator i = prefixes.begin(); i != prefixes.end(); ++i) { string list_after(get_prefix(snap) + *i); pair next; int r = backend.get_next(list_after, &next); if (r < 0) { break; // Done } if (next.first.substr(0, list_after.size()) != list_after) { continue; // Done with this prefix } assert(is_mapping(next.first)); pair next_decoded(from_raw(next)); assert(next_decoded.first == snap); assert(check(next_decoded.second)); if (hoid) *hoid = next_decoded.second; return 0; } return -ENOENT; } int SnapMapper::remove_oid( const hobject_t &oid, MapCacher::Transaction *t) { assert(check(oid)); return _remove_oid(oid, t); } int SnapMapper::_remove_oid( const hobject_t &oid, MapCacher::Transaction *t) { object_snaps out; int r = get_snaps(oid, &out); if (r < 0) return r; clear_snaps(oid, t); set to_remove; for (set::iterator i = out.snaps.begin(); i != out.snaps.end(); ++i) { to_remove.insert(to_raw_key(make_pair(*i, oid))); } backend.remove_keys(to_remove, t); return 0; } int SnapMapper::get_snaps( const hobject_t &oid, std::set *snaps) { assert(check(oid)); object_snaps out; int r = get_snaps(oid, &out); if (r < 0) return r; if (snaps) snaps->swap(out.snaps); return 0; } ceph-0.80.11/src/osd/osd_types.h0000664000175100017510000030421312623076744020436 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OSD_TYPES_H #define CEPH_OSD_TYPES_H #include #include #include #include #include #include "include/rados/rados_types.hpp" #include "msg/msg_types.h" #include "include/types.h" #include "include/utime.h" #include "include/CompatSet.h" #include "common/histogram.h" #include "include/interval_set.h" #include "common/Formatter.h" #include "common/bloom_filter.hpp" #include "common/hobject.h" #include "common/snap_types.h" #include "HitSet.h" #include "Watch.h" #include "OpRequest.h" #include "include/cmp.h" #define CEPH_OSD_ONDISK_MAGIC "ceph osd volume v026" #define CEPH_OSD_FEATURE_INCOMPAT_BASE CompatSet::Feature(1, "initial feature set(~v.18)") #define CEPH_OSD_FEATURE_INCOMPAT_PGINFO CompatSet::Feature(2, "pginfo object") #define CEPH_OSD_FEATURE_INCOMPAT_OLOC CompatSet::Feature(3, "object locator") #define CEPH_OSD_FEATURE_INCOMPAT_LEC CompatSet::Feature(4, "last_epoch_clean") #define CEPH_OSD_FEATURE_INCOMPAT_CATEGORIES CompatSet::Feature(5, "categories") #define CEPH_OSD_FEATURE_INCOMPAT_HOBJECTPOOL CompatSet::Feature(6, "hobjectpool") #define CEPH_OSD_FEATURE_INCOMPAT_BIGINFO CompatSet::Feature(7, "biginfo") #define CEPH_OSD_FEATURE_INCOMPAT_LEVELDBINFO CompatSet::Feature(8, "leveldbinfo") #define CEPH_OSD_FEATURE_INCOMPAT_LEVELDBLOG CompatSet::Feature(9, "leveldblog") #define CEPH_OSD_FEATURE_INCOMPAT_SNAPMAPPER CompatSet::Feature(10, "snapmapper") #define CEPH_OSD_FEATURE_INCOMPAT_SHARDS CompatSet::Feature(11, "sharded objects") typedef hobject_t collection_list_handle_t; typedef uint8_t shard_id_t; /// convert a single CPEH_OSD_FLAG_* to a string const char *ceph_osd_flag_name(unsigned flag); /// convert CEPH_OSD_FLAG_* op flags to a string string ceph_osd_flag_string(unsigned flags); struct pg_shard_t { int osd; shard_id_t shard; pg_shard_t() : osd(-1), shard(ghobject_t::NO_SHARD) {} explicit pg_shard_t(int osd) : osd(osd), shard(ghobject_t::NO_SHARD) {} pg_shard_t(int osd, shard_id_t shard) : osd(osd), shard(shard) {} static pg_shard_t undefined_shard() { return pg_shard_t(-1, ghobject_t::NO_SHARD); } bool is_undefined() const { return osd == -1; } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); }; WRITE_CLASS_ENCODER(pg_shard_t) WRITE_EQ_OPERATORS_2(pg_shard_t, osd, shard) WRITE_CMP_OPERATORS_2(pg_shard_t, osd, shard) ostream &operator<<(ostream &lhs, const pg_shard_t &rhs); inline ostream& operator<<(ostream& out, const osd_reqid_t& r) { return out << r.name << "." << r.inc << ":" << r.tid; } inline bool operator==(const osd_reqid_t& l, const osd_reqid_t& r) { return (l.name == r.name) && (l.inc == r.inc) && (l.tid == r.tid); } inline bool operator!=(const osd_reqid_t& l, const osd_reqid_t& r) { return (l.name != r.name) || (l.inc != r.inc) || (l.tid != r.tid); } inline bool operator<(const osd_reqid_t& l, const osd_reqid_t& r) { return (l.name < r.name) || (l.inc < r.inc) || (l.name == r.name && l.inc == r.inc && l.tid < r.tid); } inline bool operator<=(const osd_reqid_t& l, const osd_reqid_t& r) { return (l.name < r.name) || (l.inc < r.inc) || (l.name == r.name && l.inc == r.inc && l.tid <= r.tid); } inline bool operator>(const osd_reqid_t& l, const osd_reqid_t& r) { return !(l <= r); } inline bool operator>=(const osd_reqid_t& l, const osd_reqid_t& r) { return !(l < r); } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const osd_reqid_t &r) const { static hash H; return H(r.name.num() ^ r.tid ^ r.inc); } }; CEPH_HASH_NAMESPACE_END // ----- // a locator constrains the placement of an object. mainly, which pool // does it go in. struct object_locator_t { // You specify either the hash or the key -- not both int64_t pool; ///< pool id string key; ///< key string (if non-empty) string nspace; ///< namespace int64_t hash; ///< hash position (if >= 0) explicit object_locator_t() : pool(-1), hash(-1) {} explicit object_locator_t(int64_t po) : pool(po), hash(-1) {} explicit object_locator_t(int64_t po, int64_t ps) : pool(po), hash(ps) {} explicit object_locator_t(int64_t po, string ns) : pool(po), nspace(ns), hash(-1) {} explicit object_locator_t(int64_t po, string ns, int64_t ps) : pool(po), nspace(ns), hash(ps) {} explicit object_locator_t(int64_t po, string ns, string s) : pool(po), key(s), nspace(ns), hash(-1) {} explicit object_locator_t(const hobject_t& soid) : pool(soid.pool), key(soid.get_key()), nspace(soid.nspace), hash(-1) {} int64_t get_pool() const { return pool; } void clear() { pool = -1; key = ""; nspace = ""; hash = -1; } bool empty() const { return pool == -1; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(object_locator_t) inline bool operator==(const object_locator_t& l, const object_locator_t& r) { return l.pool == r.pool && l.key == r.key && l.nspace == r.nspace && l.hash == r.hash; } inline bool operator!=(const object_locator_t& l, const object_locator_t& r) { return !(l == r); } inline ostream& operator<<(ostream& out, const object_locator_t& loc) { out << "@" << loc.pool; if (loc.nspace.length()) out << ";" << loc.nspace; if (loc.key.length()) out << ":" << loc.key; return out; } struct request_redirect_t { private: object_locator_t redirect_locator; ///< this is authoritative string redirect_object; ///< If non-empty, the request goes to this object name bufferlist osd_instructions; ///< a bufferlist for the OSDs, passed but not interpreted by clients friend ostream& operator<<(ostream& out, const request_redirect_t& redir); public: request_redirect_t() {} explicit request_redirect_t(const object_locator_t& orig, int64_t rpool) : redirect_locator(orig) { redirect_locator.pool = rpool; } explicit request_redirect_t(const object_locator_t& rloc) : redirect_locator(rloc) {} explicit request_redirect_t(const object_locator_t& orig, const string& robj) : redirect_locator(orig), redirect_object(robj) {} void set_instructions(const bufferlist& bl) { osd_instructions = bl; } const bufferlist& get_instructions() { return osd_instructions; } bool empty() const { return redirect_locator.empty() && redirect_object.empty(); } void combine_with_locator(object_locator_t& orig, string& obj) const { orig = redirect_locator; if (!redirect_object.empty()) obj = redirect_object; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(request_redirect_t) inline ostream& operator<<(ostream& out, const request_redirect_t& redir) { out << "object " << redir.redirect_object << ", locator{" << redir.redirect_locator << "}"; return out; } // Internal OSD op flags - set by the OSD based on the op types enum { CEPH_OSD_RMW_FLAG_READ = (1 << 1), CEPH_OSD_RMW_FLAG_WRITE = (1 << 2), CEPH_OSD_RMW_FLAG_CLASS_READ = (1 << 3), CEPH_OSD_RMW_FLAG_CLASS_WRITE = (1 << 4), CEPH_OSD_RMW_FLAG_PGOP = (1 << 5), CEPH_OSD_RMW_FLAG_CACHE = (1 << 6), }; // pg stuff // object namespaces #define CEPH_METADATA_NS 1 #define CEPH_DATA_NS 2 #define CEPH_CAS_NS 3 #define CEPH_OSDMETADATA_NS 0xff #define OSD_SUPERBLOCK_POBJECT hobject_t(sobject_t(object_t("osd_superblock"), 0)) // placement seed (a hash value) typedef uint32_t ps_t; // old (v1) pg_t encoding (wrap old struct ceph_pg) struct old_pg_t { ceph_pg v; void encode(bufferlist& bl) const { ::encode_raw(v, bl); } void decode(bufferlist::iterator& bl) { ::decode_raw(v, bl); } }; WRITE_CLASS_ENCODER(old_pg_t) // placement group id struct pg_t { uint64_t m_pool; uint32_t m_seed; int32_t m_preferred; pg_t() : m_pool(0), m_seed(0), m_preferred(-1) {} pg_t(ps_t seed, uint64_t pool, int pref=-1) { m_seed = seed; m_pool = pool; m_preferred = pref; } pg_t(const ceph_pg& cpg) { m_pool = cpg.pool; m_seed = cpg.ps; m_preferred = (__s16)cpg.preferred; } old_pg_t get_old_pg() const { old_pg_t o; assert(m_pool < 0xffffffffull); o.v.pool = m_pool; o.v.ps = m_seed; o.v.preferred = (__s16)m_preferred; return o; } pg_t(const old_pg_t& opg) { *this = opg.v; } ps_t ps() const { return m_seed; } uint64_t pool() const { return m_pool; } int32_t preferred() const { return m_preferred; } void set_ps(ps_t p) { m_seed = p; } void set_pool(uint64_t p) { m_pool = p; } void set_preferred(int32_t osd) { m_preferred = osd; } pg_t get_parent() const; pg_t get_ancestor(unsigned old_pg_num) const; int print(char *o, int maxlen) const; bool parse(const char *s); bool is_split(unsigned old_pg_num, unsigned new_pg_num, set *pchildren) const; /** * Returns b such that for all object o: * ~((~0)<& o); }; WRITE_CLASS_ENCODER(pg_t) inline bool operator<(const pg_t& l, const pg_t& r) { return l.pool() < r.pool() || (l.pool() == r.pool() && (l.preferred() < r.preferred() || (l.preferred() == r.preferred() && (l.ps() < r.ps())))); } inline bool operator<=(const pg_t& l, const pg_t& r) { return l.pool() < r.pool() || (l.pool() == r.pool() && (l.preferred() < r.preferred() || (l.preferred() == r.preferred() && (l.ps() <= r.ps())))); } inline bool operator==(const pg_t& l, const pg_t& r) { return l.pool() == r.pool() && l.preferred() == r.preferred() && l.ps() == r.ps(); } inline bool operator!=(const pg_t& l, const pg_t& r) { return l.pool() != r.pool() || l.preferred() != r.preferred() || l.ps() != r.ps(); } inline bool operator>(const pg_t& l, const pg_t& r) { return l.pool() > r.pool() || (l.pool() == r.pool() && (l.preferred() > r.preferred() || (l.preferred() == r.preferred() && (l.ps() > r.ps())))); } inline bool operator>=(const pg_t& l, const pg_t& r) { return l.pool() > r.pool() || (l.pool() == r.pool() && (l.preferred() > r.preferred() || (l.preferred() == r.preferred() && (l.ps() >= r.ps())))); } ostream& operator<<(ostream& out, const pg_t &pg); CEPH_HASH_NAMESPACE_START template<> struct hash< pg_t > { size_t operator()( const pg_t& x ) const { static hash H; return H((x.pool() & 0xffffffff) ^ (x.pool() >> 32) ^ x.ps() ^ x.preferred()); } }; CEPH_HASH_NAMESPACE_END struct spg_t { pg_t pgid; shard_id_t shard; spg_t() : shard(ghobject_t::NO_SHARD) {} spg_t(pg_t pgid, shard_id_t shard) : pgid(pgid), shard(shard) {} explicit spg_t(pg_t pgid) : pgid(pgid), shard(ghobject_t::NO_SHARD) {} unsigned get_split_bits(unsigned pg_num) const { return pgid.get_split_bits(pg_num); } spg_t get_parent() const { return spg_t(pgid.get_parent(), shard); } ps_t ps() const { return pgid.ps(); } uint64_t pool() const { return pgid.pool(); } int32_t preferred() const { return pgid.preferred(); } bool parse(const char *s); bool is_split(unsigned old_pg_num, unsigned new_pg_num, set *pchildren) const { set _children; set *children = pchildren ? &_children : NULL; bool is_split = pgid.is_split(old_pg_num, new_pg_num, children); if (pchildren && is_split) { for (set::iterator i = _children.begin(); i != _children.end(); ++i) { pchildren->insert(spg_t(*i, shard)); } } return is_split; } bool is_no_shard() const { return shard == ghobject_t::NO_SHARD; } void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(pgid, bl); ::encode(shard, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(pgid, bl); ::decode(shard, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(spg_t) WRITE_EQ_OPERATORS_2(spg_t, pgid, shard) WRITE_CMP_OPERATORS_2(spg_t, pgid, shard) CEPH_HASH_NAMESPACE_START template<> struct hash< spg_t > { size_t operator()( const spg_t& x ) const { static hash H; return H(hash()(x.pgid) ^ x.shard); } }; CEPH_HASH_NAMESPACE_END ostream& operator<<(ostream& out, const spg_t &pg); // ---------------------- class coll_t { public: const static coll_t META_COLL; coll_t() : str("meta") { } explicit coll_t(const std::string &str_) : str(str_) { } explicit coll_t(spg_t pgid, snapid_t snap = CEPH_NOSNAP) : str(pg_and_snap_to_str(pgid, snap)) { } static coll_t make_temp_coll(spg_t pgid) { return coll_t(pg_to_tmp_str(pgid)); } static coll_t make_removal_coll(uint64_t seq, spg_t pgid) { return coll_t(seq_to_removal_str(seq, pgid)); } const std::string& to_str() const { return str; } const char* c_str() const { return str.c_str(); } int operator<(const coll_t &rhs) const { return str < rhs.str; } bool is_pg_prefix(spg_t& pgid) const; bool is_pg(spg_t& pgid, snapid_t& snap) const; bool is_temp(spg_t& pgid) const; bool is_removal(uint64_t *seq, spg_t *pgid) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); inline bool operator==(const coll_t& rhs) const { return str == rhs.str; } inline bool operator!=(const coll_t& rhs) const { return str != rhs.str; } void dump(Formatter *f) const; static void generate_test_instances(list& o); private: static std::string pg_and_snap_to_str(spg_t p, snapid_t s) { std::ostringstream oss; oss << p << "_" << s; return oss.str(); } static std::string pg_to_tmp_str(spg_t p) { std::ostringstream oss; oss << p << "_TEMP"; return oss.str(); } static std::string seq_to_removal_str(uint64_t seq, spg_t pgid) { std::ostringstream oss; oss << "FORREMOVAL_" << seq << "_" << pgid; return oss.str(); } std::string str; }; WRITE_CLASS_ENCODER(coll_t) inline ostream& operator<<(ostream& out, const coll_t& c) { out << c.to_str(); return out; } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const coll_t &c) const { size_t h = 0; string str(c.to_str()); std::string::const_iterator end(str.end()); for (std::string::const_iterator s = str.begin(); s != end; ++s) { h += *s; h += (h << 10); h ^= (h >> 6); } h += (h << 3); h ^= (h >> 11); h += (h << 15); return h; } }; CEPH_HASH_NAMESPACE_END inline ostream& operator<<(ostream& out, const ceph_object_layout &ol) { out << pg_t(ol.ol_pgid); int su = ol.ol_stripe_unit; if (su) out << ".su=" << su; return out; } // compound rados version type class eversion_t { public: version_t version; epoch_t epoch; __u32 __pad; eversion_t() : version(0), epoch(0), __pad(0) {} eversion_t(epoch_t e, version_t v) : version(v), epoch(e), __pad(0) {} eversion_t(const ceph_eversion& ce) : version(ce.version), epoch(ce.epoch), __pad(0) { } eversion_t(bufferlist& bl) : __pad(0) { decode(bl); } static eversion_t max() { eversion_t max; max.version -= 1; max.epoch -= 1; return max; } operator ceph_eversion() { ceph_eversion c; c.epoch = epoch; c.version = version; return c; } string get_key_name() const; void encode(bufferlist &bl) const { ::encode(version, bl); ::encode(epoch, bl); } void decode(bufferlist::iterator &bl) { ::decode(version, bl); ::decode(epoch, bl); } void decode(bufferlist& bl) { bufferlist::iterator p = bl.begin(); decode(p); } }; WRITE_CLASS_ENCODER(eversion_t) inline bool operator==(const eversion_t& l, const eversion_t& r) { return (l.epoch == r.epoch) && (l.version == r.version); } inline bool operator!=(const eversion_t& l, const eversion_t& r) { return (l.epoch != r.epoch) || (l.version != r.version); } inline bool operator<(const eversion_t& l, const eversion_t& r) { return (l.epoch == r.epoch) ? (l.version < r.version):(l.epoch < r.epoch); } inline bool operator<=(const eversion_t& l, const eversion_t& r) { return (l.epoch == r.epoch) ? (l.version <= r.version):(l.epoch <= r.epoch); } inline bool operator>(const eversion_t& l, const eversion_t& r) { return (l.epoch == r.epoch) ? (l.version > r.version):(l.epoch > r.epoch); } inline bool operator>=(const eversion_t& l, const eversion_t& r) { return (l.epoch == r.epoch) ? (l.version >= r.version):(l.epoch >= r.epoch); } inline ostream& operator<<(ostream& out, const eversion_t e) { return out << e.epoch << "'" << e.version; } /** * objectstore_perf_stat_t * * current perf information about the osd */ struct objectstore_perf_stat_t { // cur_op_latency is in ms since double add/sub are not associative uint32_t filestore_commit_latency; uint32_t filestore_apply_latency; objectstore_perf_stat_t() : filestore_commit_latency(0), filestore_apply_latency(0) {} bool operator==(const objectstore_perf_stat_t &r) const { return filestore_commit_latency == r.filestore_commit_latency && filestore_apply_latency == r.filestore_apply_latency; } void add(const objectstore_perf_stat_t &o) { filestore_commit_latency += o.filestore_commit_latency; filestore_apply_latency += o.filestore_apply_latency; } void sub(const objectstore_perf_stat_t &o) { filestore_commit_latency -= o.filestore_commit_latency; filestore_apply_latency -= o.filestore_apply_latency; } void dump(Formatter *f) const; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); static void generate_test_instances(std::list& o); }; WRITE_CLASS_ENCODER(objectstore_perf_stat_t) /** osd_stat * aggregate stats for an osd */ struct osd_stat_t { int64_t kb, kb_used, kb_avail; vector hb_in, hb_out; int32_t snap_trim_queue_len, num_snap_trimming; pow2_hist_t op_queue_age_hist; objectstore_perf_stat_t fs_perf_stat; osd_stat_t() : kb(0), kb_used(0), kb_avail(0), snap_trim_queue_len(0), num_snap_trimming(0) {} void add(const osd_stat_t& o) { kb += o.kb; kb_used += o.kb_used; kb_avail += o.kb_avail; snap_trim_queue_len += o.snap_trim_queue_len; num_snap_trimming += o.num_snap_trimming; op_queue_age_hist.add(o.op_queue_age_hist); fs_perf_stat.add(o.fs_perf_stat); } void sub(const osd_stat_t& o) { kb -= o.kb; kb_used -= o.kb_used; kb_avail -= o.kb_avail; snap_trim_queue_len -= o.snap_trim_queue_len; num_snap_trimming -= o.num_snap_trimming; op_queue_age_hist.sub(o.op_queue_age_hist); fs_perf_stat.sub(o.fs_perf_stat); } void dump(Formatter *f) const; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); static void generate_test_instances(std::list& o); }; WRITE_CLASS_ENCODER(osd_stat_t) inline bool operator==(const osd_stat_t& l, const osd_stat_t& r) { return l.kb == r.kb && l.kb_used == r.kb_used && l.kb_avail == r.kb_avail && l.snap_trim_queue_len == r.snap_trim_queue_len && l.num_snap_trimming == r.num_snap_trimming && l.hb_in == r.hb_in && l.hb_out == r.hb_out && l.op_queue_age_hist == r.op_queue_age_hist && l.fs_perf_stat == r.fs_perf_stat; } inline bool operator!=(const osd_stat_t& l, const osd_stat_t& r) { return !(l == r); } inline ostream& operator<<(ostream& out, const osd_stat_t& s) { return out << "osd_stat(" << kb_t(s.kb_used) << " used, " << kb_t(s.kb_avail) << " avail, " << kb_t(s.kb) << " total, " << "peers " << s.hb_in << "/" << s.hb_out << " op hist " << s.op_queue_age_hist.h << ")"; } /* * pg states */ #define PG_STATE_CREATING (1<<0) // creating #define PG_STATE_ACTIVE (1<<1) // i am active. (primary: replicas too) #define PG_STATE_CLEAN (1<<2) // peers are complete, clean of stray replicas. #define PG_STATE_DOWN (1<<4) // a needed replica is down, PG offline #define PG_STATE_REPLAY (1<<5) // crashed, waiting for replay //#define PG_STATE_STRAY (1<<6) // i must notify the primary i exist. #define PG_STATE_SPLITTING (1<<7) // i am splitting #define PG_STATE_SCRUBBING (1<<8) // scrubbing #define PG_STATE_SCRUBQ (1<<9) // queued for scrub #define PG_STATE_DEGRADED (1<<10) // pg membership not complete #define PG_STATE_INCONSISTENT (1<<11) // pg replicas are inconsistent (but shouldn't be) #define PG_STATE_PEERING (1<<12) // pg is (re)peering #define PG_STATE_REPAIR (1<<13) // pg should repair on next scrub #define PG_STATE_RECOVERING (1<<14) // pg is recovering/migrating objects #define PG_STATE_BACKFILL_WAIT (1<<15) // [active] reserving backfill #define PG_STATE_INCOMPLETE (1<<16) // incomplete content, peering failed. #define PG_STATE_STALE (1<<17) // our state for this pg is stale, unknown. #define PG_STATE_REMAPPED (1<<18) // pg is explicitly remapped to different OSDs than CRUSH #define PG_STATE_DEEP_SCRUB (1<<19) // deep scrub: check CRC32 on files #define PG_STATE_BACKFILL (1<<20) // [active] backfilling pg content #define PG_STATE_BACKFILL_TOOFULL (1<<21) // backfill can't proceed: too full #define PG_STATE_RECOVERY_WAIT (1<<22) // waiting for recovery reservations std::string pg_state_string(int state); /* * pool_snap_info_t * * attributes for a single pool snapshot. */ struct pool_snap_info_t { snapid_t snapid; utime_t stamp; string name; void dump(Formatter *f) const; void encode(bufferlist& bl, uint64_t features) const; void decode(bufferlist::iterator& bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER_FEATURES(pool_snap_info_t) inline ostream& operator<<(ostream& out, const pool_snap_info_t& si) { return out << si.snapid << '(' << si.name << ' ' << si.stamp << ')'; } /* * pg_pool */ struct pg_pool_t { enum { TYPE_REPLICATED = 1, // replication //TYPE_RAID4 = 2, // raid4 (never implemented) TYPE_ERASURE = 3, // erasure-coded }; static const char *get_type_name(int t) { switch (t) { case TYPE_REPLICATED: return "replicated"; //case TYPE_RAID4: return "raid4"; case TYPE_ERASURE: return "erasure"; default: return "???"; } } const char *get_type_name() const { return get_type_name(type); } static const char* get_default_type() { return "replicated"; } enum { FLAG_HASHPSPOOL = 1<<0, // hash pg seed and pool together (instead of adding) FLAG_FULL = 1<<1, // pool is full FLAG_DEBUG_FAKE_EC_POOL = 1<<2, // require ReplicatedPG to act like an EC pg FLAG_INCOMPLETE_CLONES = 1<<3, // may have incomplete clones (bc we are/were an overlay) }; static const char *get_flag_name(int f) { switch (f) { case FLAG_HASHPSPOOL: return "hashpspool"; case FLAG_FULL: return "full"; case FLAG_DEBUG_FAKE_EC_POOL: return "require_local_rollback"; case FLAG_INCOMPLETE_CLONES: return "incomplete_clones"; default: return "???"; } } static string get_flags_string(uint64_t f) { string s; for (unsigned n=0; f && n<64; ++n) { if (f & (1ull << n)) { if (s.length()) s += ","; s += get_flag_name(1ull << n); } } return s; } string get_flags_string() const { return get_flags_string(flags); } typedef enum { CACHEMODE_NONE = 0, ///< no caching CACHEMODE_WRITEBACK = 1, ///< write to cache, flush later CACHEMODE_FORWARD = 2, ///< forward if not in cache CACHEMODE_READONLY = 3, ///< handle reads, forward writes [not strongly consistent] } cache_mode_t; static const char *get_cache_mode_name(cache_mode_t m) { switch (m) { case CACHEMODE_NONE: return "none"; case CACHEMODE_WRITEBACK: return "writeback"; case CACHEMODE_FORWARD: return "forward"; case CACHEMODE_READONLY: return "readonly"; default: return "unknown"; } } static cache_mode_t get_cache_mode_from_str(const string& s) { if (s == "none") return CACHEMODE_NONE; if (s == "writeback") return CACHEMODE_WRITEBACK; if (s == "forward") return CACHEMODE_FORWARD; if (s == "readonly") return CACHEMODE_READONLY; return (cache_mode_t)-1; } const char *get_cache_mode_name() const { return get_cache_mode_name(cache_mode); } bool cache_mode_requires_hit_set() const { switch (cache_mode) { case CACHEMODE_NONE: case CACHEMODE_FORWARD: case CACHEMODE_READONLY: return false; case CACHEMODE_WRITEBACK: return true; default: assert(0 == "implement me"); } } uint64_t flags; ///< FLAG_* __u8 type; ///< TYPE_* __u8 size, min_size; ///< number of osds in each pg __u8 crush_ruleset; ///< crush placement rule set __u8 object_hash; ///< hash mapping object name to ps private: __u32 pg_num, pgp_num; ///< number of pgs public: map properties; ///< OBSOLETE string erasure_code_profile; ///< name of the erasure code profile in OSDMap epoch_t last_change; ///< most recent epoch changed, exclusing snapshot changes epoch_t last_force_op_resend; ///< last epoch that forced clients to resend snapid_t snap_seq; ///< seq for per-pool snapshot epoch_t snap_epoch; ///< osdmap epoch of last snap uint64_t auid; ///< who owns the pg __u32 crash_replay_interval; ///< seconds to allow clients to replay ACKed but unCOMMITted requests uint64_t quota_max_bytes; ///< maximum number of bytes for this pool uint64_t quota_max_objects; ///< maximum number of objects for this pool /* * Pool snaps (global to this pool). These define a SnapContext for * the pool, unless the client manually specifies an alternate * context. */ map snaps; /* * Alternatively, if we are definining non-pool snaps (e.g. via the * Ceph MDS), we must track @removed_snaps (since @snaps is not * used). Snaps and removed_snaps are to be used exclusive of each * other! */ interval_set removed_snaps; unsigned pg_num_mask, pgp_num_mask; set tiers; ///< pools that are tiers of us int64_t tier_of; ///< pool for which we are a tier // Note that write wins for read+write ops int64_t read_tier; ///< pool/tier for objecter to direct reads to int64_t write_tier; ///< pool/tier for objecter to direct writes to cache_mode_t cache_mode; ///< cache pool mode bool is_tier() const { return tier_of >= 0; } bool has_tiers() const { return !tiers.empty(); } void clear_tier() { tier_of = -1; clear_read_tier(); clear_write_tier(); clear_tier_tunables(); } bool has_read_tier() const { return read_tier >= 0; } void clear_read_tier() { read_tier = -1; } bool has_write_tier() const { return write_tier >= 0; } void clear_write_tier() { write_tier = -1; } void clear_tier_tunables() { if (cache_mode != CACHEMODE_NONE) flags |= FLAG_INCOMPLETE_CLONES; cache_mode = CACHEMODE_NONE; target_max_bytes = 0; target_max_objects = 0; cache_target_dirty_ratio_micro = 0; cache_target_full_ratio_micro = 0; hit_set_params = HitSet::Params(); hit_set_period = 0; hit_set_count = 0; } uint64_t target_max_bytes; ///< tiering: target max pool size uint64_t target_max_objects; ///< tiering: target max pool size uint32_t cache_target_dirty_ratio_micro; ///< cache: fraction of target to leave dirty uint32_t cache_target_full_ratio_micro; ///< cache: fraction of target to fill before we evict in earnest uint32_t cache_min_flush_age; ///< minimum age (seconds) before we can flush uint32_t cache_min_evict_age; ///< minimum age (seconds) before we can evict HitSet::Params hit_set_params; ///< The HitSet params to use on this pool uint32_t hit_set_period; ///< periodicity of HitSet segments (seconds) uint32_t hit_set_count; ///< number of periods to retain uint32_t min_read_recency_for_promote; ///< minimum number of HitSet to check before promote uint32_t stripe_width; ///< erasure coded stripe size in bytes pg_pool_t() : flags(0), type(0), size(0), min_size(0), crush_ruleset(0), object_hash(0), pg_num(0), pgp_num(0), last_change(0), last_force_op_resend(0), snap_seq(0), snap_epoch(0), auid(0), crash_replay_interval(0), quota_max_bytes(0), quota_max_objects(0), pg_num_mask(0), pgp_num_mask(0), tier_of(-1), read_tier(-1), write_tier(-1), cache_mode(CACHEMODE_NONE), target_max_bytes(0), target_max_objects(0), cache_target_dirty_ratio_micro(0), cache_target_full_ratio_micro(0), cache_min_flush_age(0), cache_min_evict_age(0), hit_set_params(), hit_set_period(0), hit_set_count(0), min_read_recency_for_promote(0), stripe_width(0) { } void dump(Formatter *f) const; uint64_t get_flags() const { return flags; } bool has_flag(uint64_t f) const { return flags & f; } /// This method will later return true for ec pools as well bool ec_pool() const { return type == TYPE_ERASURE; } bool require_rollback() const { return ec_pool() || flags & FLAG_DEBUG_FAKE_EC_POOL; } /// true if incomplete clones may be present bool allow_incomplete_clones() const { return cache_mode != CACHEMODE_NONE || has_flag(FLAG_INCOMPLETE_CLONES); } unsigned get_type() const { return type; } unsigned get_size() const { return size; } unsigned get_min_size() const { return min_size; } int get_crush_ruleset() const { return crush_ruleset; } int get_object_hash() const { return object_hash; } const char *get_object_hash_name() const { return ceph_str_hash_name(get_object_hash()); } epoch_t get_last_change() const { return last_change; } epoch_t get_last_force_op_resend() const { return last_force_op_resend; } epoch_t get_snap_epoch() const { return snap_epoch; } snapid_t get_snap_seq() const { return snap_seq; } uint64_t get_auid() const { return auid; } unsigned get_crash_replay_interval() const { return crash_replay_interval; } void set_snap_seq(snapid_t s) { snap_seq = s; } void set_snap_epoch(epoch_t e) { snap_epoch = e; } void set_stripe_width(uint32_t s) { stripe_width = s; } uint32_t get_stripe_width() const { return stripe_width; } bool is_replicated() const { return get_type() == TYPE_REPLICATED; } bool is_erasure() const { return get_type() == TYPE_ERASURE; } bool requires_aligned_append() const { return is_erasure(); } uint64_t required_alignment() const { return stripe_width; } bool can_shift_osds() const { switch (get_type()) { case TYPE_REPLICATED: return true; case TYPE_ERASURE: return false; default: assert(0 == "unhandled pool type"); } } unsigned get_pg_num() const { return pg_num; } unsigned get_pgp_num() const { return pgp_num; } unsigned get_pg_num_mask() const { return pg_num_mask; } unsigned get_pgp_num_mask() const { return pgp_num_mask; } // if pg_num is not a multiple of two, pgs are not equally sized. // return, for a given pg, the fraction (denominator) of the total // pool size that it represents. unsigned get_pg_num_divisor(pg_t pgid) const; void set_pg_num(int p) { pg_num = p; calc_pg_masks(); } void set_pgp_num(int p) { pgp_num = p; calc_pg_masks(); } void set_quota_max_bytes(uint64_t m) { quota_max_bytes = m; } uint64_t get_quota_max_bytes() { return quota_max_bytes; } void set_quota_max_objects(uint64_t m) { quota_max_objects = m; } uint64_t get_quota_max_objects() { return quota_max_objects; } static int calc_bits_of(int t); void calc_pg_masks(); /* * we have two snap modes: * - pool global snaps * - snap existence/non-existence defined by snaps[] and snap_seq * - user managed snaps * - removal governed by removed_snaps * * we know which mode we're using based on whether removed_snaps is empty. * If nothing has been created, both functions report false. */ bool is_pool_snaps_mode() const; bool is_unmanaged_snaps_mode() const; bool is_removed_snap(snapid_t s) const; /* * build set of known-removed sets from either pool snaps or * explicit removed_snaps set. */ void build_removed_snaps(interval_set& rs) const; snapid_t snap_exists(const char *s) const; void add_snap(const char *n, utime_t stamp); void add_unmanaged_snap(uint64_t& snapid); void remove_snap(snapid_t s); void remove_unmanaged_snap(snapid_t s); SnapContext get_snap_context() const; /// hash a object name+namespace key to a hash position uint32_t hash_key(const string& key, const string& ns) const; /// round a hash position down to a pg num uint32_t raw_hash_to_pg(uint32_t v) const; /* * map a raw pg (with full precision ps) into an actual pg, for storage */ pg_t raw_pg_to_pg(pg_t pg) const; /* * map raw pg (full precision ps) into a placement seed. include * pool id in that value so that different pools don't use the same * seeds. */ ps_t raw_pg_to_pps(pg_t pg) const; /// choose a random hash position within a pg uint32_t get_random_pg_position(pg_t pgid, uint32_t seed) const; void encode(bufferlist& bl, uint64_t features) const; void decode(bufferlist::iterator& bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER_FEATURES(pg_pool_t) ostream& operator<<(ostream& out, const pg_pool_t& p); /** * a summation of object stats * * This is just a container for object stats; we don't know what for. */ struct object_stat_sum_t { int64_t num_bytes; // in bytes int64_t num_objects; int64_t num_object_clones; int64_t num_object_copies; // num_objects * num_replicas int64_t num_objects_missing_on_primary; int64_t num_objects_degraded; int64_t num_objects_unfound; int64_t num_rd, num_rd_kb; int64_t num_wr, num_wr_kb; int64_t num_scrub_errors; // total deep and shallow scrub errors int64_t num_shallow_scrub_errors; int64_t num_deep_scrub_errors; int64_t num_objects_recovered; int64_t num_bytes_recovered; int64_t num_keys_recovered; int64_t num_objects_dirty; int64_t num_whiteouts; int64_t num_objects_omap; int64_t num_objects_hit_set_archive; object_stat_sum_t() : num_bytes(0), num_objects(0), num_object_clones(0), num_object_copies(0), num_objects_missing_on_primary(0), num_objects_degraded(0), num_objects_unfound(0), num_rd(0), num_rd_kb(0), num_wr(0), num_wr_kb(0), num_scrub_errors(0), num_shallow_scrub_errors(0), num_deep_scrub_errors(0), num_objects_recovered(0), num_bytes_recovered(0), num_keys_recovered(0), num_objects_dirty(0), num_whiteouts(0), num_objects_omap(0), num_objects_hit_set_archive(0) {} void floor(int64_t f) { #define FLOOR(x) if (x < f) x = f FLOOR(num_bytes); FLOOR(num_objects); FLOOR(num_object_clones); FLOOR(num_object_copies); FLOOR(num_objects_missing_on_primary); FLOOR(num_objects_degraded); FLOOR(num_objects_unfound); FLOOR(num_rd); FLOOR(num_rd_kb); FLOOR(num_wr); FLOOR(num_wr_kb); FLOOR(num_scrub_errors); FLOOR(num_shallow_scrub_errors); FLOOR(num_deep_scrub_errors); FLOOR(num_objects_recovered); FLOOR(num_bytes_recovered); FLOOR(num_keys_recovered); FLOOR(num_objects_dirty); FLOOR(num_whiteouts); FLOOR(num_objects_omap); FLOOR(num_objects_hit_set_archive); #undef FLOOR } void split(vector &out) const { #define SPLIT(PARAM) \ for (unsigned i = 0; i < out.size(); ++i) { \ out[i].PARAM = PARAM / out.size(); \ if (i < (PARAM % out.size())) { \ out[i].PARAM++; \ } \ } \ SPLIT(num_bytes); SPLIT(num_objects); SPLIT(num_object_clones); SPLIT(num_object_copies); SPLIT(num_objects_missing_on_primary); SPLIT(num_objects_degraded); SPLIT(num_objects_unfound); SPLIT(num_rd); SPLIT(num_rd_kb); SPLIT(num_wr); SPLIT(num_wr_kb); SPLIT(num_scrub_errors); SPLIT(num_shallow_scrub_errors); SPLIT(num_deep_scrub_errors); SPLIT(num_objects_recovered); SPLIT(num_bytes_recovered); SPLIT(num_keys_recovered); SPLIT(num_objects_dirty); SPLIT(num_whiteouts); SPLIT(num_objects_omap); SPLIT(num_objects_hit_set_archive); #undef SPLIT } void clear() { memset(this, 0, sizeof(*this)); } void calc_copies(int nrep) { num_object_copies = nrep * num_objects; } bool is_zero() const { object_stat_sum_t zero; return memcmp(this, &zero, sizeof(zero)) == 0; } void add(const object_stat_sum_t& o); void sub(const object_stat_sum_t& o); void dump(Formatter *f) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(object_stat_sum_t) /** * a collection of object stat sums * * This is a collection of stat sums over different categories. */ struct object_stat_collection_t { object_stat_sum_t sum; map cat_sum; void calc_copies(int nrep) { sum.calc_copies(nrep); for (map::iterator p = cat_sum.begin(); p != cat_sum.end(); ++p) p->second.calc_copies(nrep); } void dump(Formatter *f) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); static void generate_test_instances(list& o); bool is_zero() const { return (cat_sum.empty() && sum.is_zero()); } void clear() { sum.clear(); cat_sum.clear(); } void floor(int64_t f) { sum.floor(f); for (map::iterator p = cat_sum.begin(); p != cat_sum.end(); ++p) p->second.floor(f); } void add(const object_stat_sum_t& o, const string& cat) { sum.add(o); if (cat.length()) cat_sum[cat].add(o); } void add(const object_stat_collection_t& o) { sum.add(o.sum); for (map::const_iterator p = o.cat_sum.begin(); p != o.cat_sum.end(); ++p) cat_sum[p->first].add(p->second); } void sub(const object_stat_collection_t& o) { sum.sub(o.sum); for (map::const_iterator p = o.cat_sum.begin(); p != o.cat_sum.end(); ++p) { object_stat_sum_t& s = cat_sum[p->first]; s.sub(p->second); if (s.is_zero()) cat_sum.erase(p->first); } } }; WRITE_CLASS_ENCODER(object_stat_collection_t) /** pg_stat * aggregate stats for a single PG. */ struct pg_stat_t { eversion_t version; version_t reported_seq; // sequence number epoch_t reported_epoch; // epoch of this report __u32 state; utime_t last_fresh; // last reported utime_t last_change; // new state != previous state utime_t last_active; // state & PG_STATE_ACTIVE utime_t last_clean; // state & PG_STATE_CLEAN utime_t last_unstale; // (state & PG_STATE_STALE) == 0 eversion_t log_start; // (log_start,version] eversion_t ondisk_log_start; // there may be more on disk epoch_t created; epoch_t last_epoch_clean; pg_t parent; __u32 parent_split_bits; eversion_t last_scrub; eversion_t last_deep_scrub; utime_t last_scrub_stamp; utime_t last_deep_scrub_stamp; utime_t last_clean_scrub_stamp; object_stat_collection_t stats; bool stats_invalid; int64_t log_size; int64_t ondisk_log_size; // >= active_log_size vector up, acting; epoch_t mapping_epoch; utime_t last_became_active; /// true if num_objects_dirty is not accurate (because it was not /// maintained starting from pool creation) bool dirty_stats_invalid; bool omap_stats_invalid; bool hitset_stats_invalid; /// up, acting primaries int up_primary; int acting_primary; pg_stat_t() : reported_seq(0), reported_epoch(0), state(0), created(0), last_epoch_clean(0), parent_split_bits(0), stats_invalid(false), log_size(0), ondisk_log_size(0), mapping_epoch(0), dirty_stats_invalid(false), omap_stats_invalid(false), hitset_stats_invalid(false), up_primary(-1), acting_primary(-1) { } epoch_t get_effective_last_epoch_clean() const { if (state & PG_STATE_CLEAN) { // we are clean as of this report, and should thus take the // reported epoch return reported_epoch; } else { return last_epoch_clean; } } pair get_version_pair() const { return make_pair(reported_epoch, reported_seq); } void floor(int64_t f) { stats.floor(f); if (log_size < f) log_size = f; if (ondisk_log_size < f) ondisk_log_size = f; } void add(const pg_stat_t& o) { stats.add(o.stats); log_size += o.log_size; ondisk_log_size += o.ondisk_log_size; } void sub(const pg_stat_t& o) { stats.sub(o.stats); log_size -= o.log_size; ondisk_log_size -= o.ondisk_log_size; } void dump(Formatter *f) const; void dump_brief(Formatter *f) const; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_stat_t) /* * summation over an entire pool */ struct pool_stat_t { object_stat_collection_t stats; int64_t log_size; int64_t ondisk_log_size; // >= active_log_size pool_stat_t() : log_size(0), ondisk_log_size(0) { } void floor(int64_t f) { stats.floor(f); if (log_size < f) log_size = f; if (ondisk_log_size < f) ondisk_log_size = f; } void add(const pg_stat_t& o) { stats.add(o.stats); log_size += o.log_size; ondisk_log_size += o.ondisk_log_size; } void sub(const pg_stat_t& o) { stats.sub(o.stats); log_size -= o.log_size; ondisk_log_size -= o.ondisk_log_size; } bool is_zero() const { return (stats.is_zero() && log_size == 0 && ondisk_log_size == 0); } void dump(Formatter *f) const; void encode(bufferlist &bl, uint64_t features) const; void decode(bufferlist::iterator &bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER_FEATURES(pool_stat_t) // ----------------------------------------- /** * pg_hit_set_info_t - information about a single recorded HitSet * * Track basic metadata about a HitSet, like the nubmer of insertions * and the time range it covers. */ struct pg_hit_set_info_t { utime_t begin, end; ///< time interval eversion_t version; ///< version this HitSet object was written pg_hit_set_info_t() {} pg_hit_set_info_t(utime_t b) : begin(b) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_hit_set_info_t) /** * pg_hit_set_history_t - information about a history of hitsets * * Include information about the currently accumulating hit set as well * as archived/historical ones. */ struct pg_hit_set_history_t { eversion_t current_last_update; ///< last version inserted into current set utime_t current_last_stamp; ///< timestamp of last insert pg_hit_set_info_t current_info; ///< metadata about the current set list history; ///< archived sets, sorted oldest -> newest void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_hit_set_history_t) // ----------------------------------------- /** * pg_history_t - information about recent pg peering/mapping history * * This is aggressively shared between OSDs to bound the amount of past * history they need to worry about. */ struct pg_history_t { epoch_t epoch_created; // epoch in which PG was created epoch_t last_epoch_started; // lower bound on last epoch started (anywhere, not necessarily locally) epoch_t last_epoch_clean; // lower bound on last epoch the PG was completely clean. epoch_t last_epoch_split; // as parent /** * In the event of a map discontinuity, same_*_since may reflect the first * map the osd has seen in the new map sequence rather than the actual start * of the interval. This is ok since a discontinuity at epoch e means there * must have been a clean interval between e and now and that we cannot be * in the active set during the interval containing e. */ epoch_t same_up_since; // same acting set since epoch_t same_interval_since; // same acting AND up set since epoch_t same_primary_since; // same primary at least back through this epoch. eversion_t last_scrub; eversion_t last_deep_scrub; utime_t last_scrub_stamp; utime_t last_deep_scrub_stamp; utime_t last_clean_scrub_stamp; pg_history_t() : epoch_created(0), last_epoch_started(0), last_epoch_clean(0), last_epoch_split(0), same_up_since(0), same_interval_since(0), same_primary_since(0) {} bool merge(const pg_history_t &other) { // Here, we only update the fields which cannot be calculated from the OSDmap. bool modified = false; if (epoch_created < other.epoch_created) { epoch_created = other.epoch_created; modified = true; } if (last_epoch_started < other.last_epoch_started) { last_epoch_started = other.last_epoch_started; modified = true; } if (last_epoch_clean < other.last_epoch_clean) { last_epoch_clean = other.last_epoch_clean; modified = true; } if (last_epoch_split < other.last_epoch_split) { last_epoch_split = other.last_epoch_split; modified = true; } if (other.last_scrub > last_scrub) { last_scrub = other.last_scrub; modified = true; } if (other.last_scrub_stamp > last_scrub_stamp) { last_scrub_stamp = other.last_scrub_stamp; modified = true; } if (other.last_deep_scrub > last_deep_scrub) { last_deep_scrub = other.last_deep_scrub; modified = true; } if (other.last_deep_scrub_stamp > last_deep_scrub_stamp) { last_deep_scrub_stamp = other.last_deep_scrub_stamp; modified = true; } if (other.last_clean_scrub_stamp > last_clean_scrub_stamp) { last_clean_scrub_stamp = other.last_clean_scrub_stamp; modified = true; } return modified; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_history_t) inline ostream& operator<<(ostream& out, const pg_history_t& h) { return out << "ec=" << h.epoch_created << " les/c " << h.last_epoch_started << "/" << h.last_epoch_clean << " " << h.same_up_since << "/" << h.same_interval_since << "/" << h.same_primary_since; } /** * pg_info_t - summary of PG statistics. * * some notes: * - last_complete implies we have all objects that existed as of that * stamp, OR a newer object, OR have already applied a later delete. * - if last_complete >= log.bottom, then we know pg contents thru log.head. * otherwise, we have no idea what the pg is supposed to contain. */ struct pg_info_t { spg_t pgid; eversion_t last_update; // last object version applied to store. eversion_t last_complete; // last version pg was complete through. epoch_t last_epoch_started;// last epoch at which this pg started on this osd version_t last_user_version; // last user object version applied to store eversion_t log_tail; // oldest log entry. hobject_t last_backfill; // objects >= this and < last_complete may be missing interval_set purged_snaps; pg_stat_t stats; pg_history_t history; pg_hit_set_history_t hit_set; pg_info_t() : last_epoch_started(0), last_user_version(0), last_backfill(hobject_t::get_max()) { } pg_info_t(spg_t p) : pgid(p), last_epoch_started(0), last_user_version(0), last_backfill(hobject_t::get_max()) { } bool is_empty() const { return last_update.version == 0; } bool dne() const { return history.epoch_created == 0; } bool is_incomplete() const { return !last_backfill.is_max(); } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& p); void dump(Formatter *f) const; bool overlaps_with(const pg_info_t &oinfo) const { return last_update > oinfo.log_tail ? oinfo.last_update >= log_tail : last_update >= oinfo.log_tail; } static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_info_t) inline ostream& operator<<(ostream& out, const pg_info_t& pgi) { out << pgi.pgid << "("; if (pgi.dne()) out << " DNE"; if (pgi.is_empty()) out << " empty"; else { out << " v " << pgi.last_update; if (pgi.last_complete != pgi.last_update) out << " lc " << pgi.last_complete; out << " (" << pgi.log_tail << "," << pgi.last_update << "]"; } if (pgi.is_incomplete()) out << " lb " << pgi.last_backfill; //out << " c " << pgi.epoch_created; out << " local-les=" << pgi.last_epoch_started; out << " n=" << pgi.stats.stats.sum.num_objects; out << " " << pgi.history << ")"; return out; } struct pg_notify_t { epoch_t query_epoch; epoch_t epoch_sent; pg_info_t info; shard_id_t to; shard_id_t from; pg_notify_t() : query_epoch(0), epoch_sent(0), to(ghobject_t::no_shard()), from(ghobject_t::no_shard()) {} pg_notify_t( shard_id_t to, shard_id_t from, epoch_t query_epoch, epoch_t epoch_sent, const pg_info_t &info) : query_epoch(query_epoch), epoch_sent(epoch_sent), info(info), to(to), from(from) { assert(from == info.pgid.shard); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &p); void dump(Formatter *f) const; static void generate_test_instances(list &o); }; WRITE_CLASS_ENCODER(pg_notify_t) ostream &operator<<(ostream &lhs, const pg_notify_t ¬ify); /** * pg_interval_t - information about a past interval */ class OSDMap; struct pg_interval_t { vector up, acting; epoch_t first, last; bool maybe_went_rw; int primary; int up_primary; pg_interval_t() : first(0), last(0), maybe_went_rw(false), primary(-1), up_primary(-1) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); /** * Determines whether there is an interval change */ static bool is_new_interval( int old_acting_primary, int new_acting_primary, const vector &old_acting, const vector &new_acting, int old_up_primary, int new_up_primary, const vector &old_up, const vector &new_up, int old_size, int new_size, int old_min_size, int new_min_size, unsigned old_pg_num, unsigned new_pg_num, pg_t pgid ); /** * Determines whether there is an interval change */ static bool is_new_interval( int old_acting_primary, ///< [in] primary as of lastmap int new_acting_primary, ///< [in] primary as of lastmap const vector &old_acting, ///< [in] acting as of lastmap const vector &new_acting, ///< [in] acting as of osdmap int old_up_primary, ///< [in] up primary of lastmap int new_up_primary, ///< [in] up primary of osdmap const vector &old_up, ///< [in] up as of lastmap const vector &new_up, ///< [in] up as of osdmap ceph::shared_ptr osdmap, ///< [in] current map ceph::shared_ptr lastmap, ///< [in] last map int64_t poolid, ///< [in] pool for pg pg_t pgid ///< [in] pgid for pg ); /** * Integrates a new map into *past_intervals, returns true * if an interval was closed out. */ static bool check_new_interval( int old_acting_primary, ///< [in] primary as of lastmap int new_acting_primary, ///< [in] primary as of osdmap const vector &old_acting, ///< [in] acting as of lastmap const vector &new_acting, ///< [in] acting as of osdmap int old_up_primary, ///< [in] up primary of lastmap int new_up_primary, ///< [in] up primary of osdmap const vector &old_up, ///< [in] up as of lastmap const vector &new_up, ///< [in] up as of osdmap epoch_t same_interval_since, ///< [in] as of osdmap epoch_t last_epoch_clean, ///< [in] current ceph::shared_ptr osdmap, ///< [in] current map ceph::shared_ptr lastmap, ///< [in] last map int64_t poolid, ///< [in] pool for pg pg_t pgid, ///< [in] pgid for pg map *past_intervals,///< [out] intervals ostream *out = 0 ///< [out] debug ostream ); }; WRITE_CLASS_ENCODER(pg_interval_t) ostream& operator<<(ostream& out, const pg_interval_t& i); typedef map pg_interval_map_t; /** * pg_query_t - used to ask a peer for information about a pg. * * note: if version=0, type=LOG, then we just provide our full log. */ struct pg_query_t { enum { INFO = 0, LOG = 1, MISSING = 4, FULLLOG = 5, }; const char *get_type_name() const { switch (type) { case INFO: return "info"; case LOG: return "log"; case MISSING: return "missing"; case FULLLOG: return "fulllog"; default: return "???"; } } __s32 type; eversion_t since; pg_history_t history; epoch_t epoch_sent; shard_id_t to; shard_id_t from; pg_query_t() : type(-1), epoch_sent(0), to(ghobject_t::NO_SHARD), from(ghobject_t::NO_SHARD) {} pg_query_t( int t, shard_id_t to, shard_id_t from, const pg_history_t& h, epoch_t epoch_sent) : type(t), history(h), epoch_sent(epoch_sent), to(to), from(from) { assert(t != LOG); } pg_query_t( int t, shard_id_t to, shard_id_t from, eversion_t s, const pg_history_t& h, epoch_t epoch_sent) : type(t), since(s), history(h), epoch_sent(epoch_sent), to(to), from(from) { assert(t == LOG); } void encode(bufferlist &bl, uint64_t features) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER_FEATURES(pg_query_t) inline ostream& operator<<(ostream& out, const pg_query_t& q) { out << "query(" << q.get_type_name() << " " << q.since; if (q.type == pg_query_t::LOG) out << " " << q.history; out << ")"; return out; } class PGBackend; class ObjectModDesc { bool can_local_rollback; bool rollback_info_completed; public: class Visitor { public: virtual void append(uint64_t old_offset) {} virtual void setattrs(map > &attrs) {} virtual void rmobject(version_t old_version) {} virtual void create() {} virtual void update_snaps(set &old_snaps) {} virtual ~Visitor() {} }; void visit(Visitor *visitor) const; mutable bufferlist bl; enum ModID { APPEND = 1, SETATTRS = 2, DELETE = 3, CREATE = 4, UPDATE_SNAPS = 5 }; ObjectModDesc() : can_local_rollback(true), rollback_info_completed(false) {} void claim(ObjectModDesc &other) { bl.clear(); bl.claim(other.bl); can_local_rollback = other.can_local_rollback; rollback_info_completed = other.rollback_info_completed; } void claim_append(ObjectModDesc &other) { if (!can_local_rollback || rollback_info_completed) return; if (!other.can_local_rollback) { mark_unrollbackable(); return; } bl.claim_append(other.bl); rollback_info_completed = other.rollback_info_completed; } void swap(ObjectModDesc &other) { bl.swap(other.bl); bool temp = other.can_local_rollback; other.can_local_rollback = can_local_rollback; can_local_rollback = temp; temp = other.rollback_info_completed; other.rollback_info_completed = rollback_info_completed; rollback_info_completed = temp; } void append_id(ModID id) { uint8_t _id(id); ::encode(_id, bl); } void append(uint64_t old_size) { if (!can_local_rollback || rollback_info_completed) return; ENCODE_START(1, 1, bl); append_id(APPEND); ::encode(old_size, bl); ENCODE_FINISH(bl); } void setattrs(map > &old_attrs) { if (!can_local_rollback || rollback_info_completed) return; ENCODE_START(1, 1, bl); append_id(SETATTRS); ::encode(old_attrs, bl); ENCODE_FINISH(bl); } bool rmobject(version_t deletion_version) { if (!can_local_rollback || rollback_info_completed) return false; ENCODE_START(1, 1, bl); append_id(DELETE); ::encode(deletion_version, bl); ENCODE_FINISH(bl); rollback_info_completed = true; return true; } void create() { if (!can_local_rollback || rollback_info_completed) return; rollback_info_completed = true; ENCODE_START(1, 1, bl); append_id(CREATE); ENCODE_FINISH(bl); } void update_snaps(set &old_snaps) { if (!can_local_rollback || rollback_info_completed) return; ENCODE_START(1, 1, bl); append_id(UPDATE_SNAPS); ::encode(old_snaps, bl); ENCODE_FINISH(bl); } // cannot be rolled back void mark_unrollbackable() { can_local_rollback = false; bl.clear(); } bool can_rollback() const { return can_local_rollback; } bool empty() const { return can_local_rollback && (bl.length() == 0); } /** * Create fresh copy of bl bytes to avoid keeping large buffers around * in the case that bl contains ptrs which point into a much larger * message buffer */ void trim_bl() { if (bl.length() > 0) bl.rebuild(); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ObjectModDesc) /** * pg_log_entry_t - single entry/event in pg log * */ struct pg_log_entry_t { enum { MODIFY = 1, // some unspecified modification (but not *all* modifications) CLONE = 2, // cloned object from head DELETE = 3, // deleted object BACKLOG = 4, // event invented by generate_backlog [deprecated] LOST_REVERT = 5, // lost new version, revert to an older version. LOST_DELETE = 6, // lost new version, revert to no object (deleted). LOST_MARK = 7, // lost new version, now EIO PROMOTE = 8, // promoted object from another tier CLEAN = 9, // mark an object clean }; static const char *get_op_name(int op) { switch (op) { case MODIFY: return "modify "; case PROMOTE: return "promote "; case CLONE: return "clone "; case DELETE: return "delete "; case BACKLOG: return "backlog "; case LOST_REVERT: return "l_revert"; case LOST_DELETE: return "l_delete"; case LOST_MARK: return "l_mark "; case CLEAN: return "clean "; default: return "unknown "; } } const char *get_op_name() const { return get_op_name(op); } __s32 op; hobject_t soid; eversion_t version, prior_version, reverting_to; version_t user_version; // the user version for this entry osd_reqid_t reqid; // caller+tid to uniquely identify request utime_t mtime; // this is the _user_ mtime, mind you bufferlist snaps; // only for clone entries bool invalid_hash; // only when decoding sobject_t based entries bool invalid_pool; // only when decoding pool-less hobject based entries uint64_t offset; // [soft state] my offset on disk /// describes state for a locally-rollbackable entry ObjectModDesc mod_desc; pg_log_entry_t() : op(0), user_version(0), invalid_hash(false), invalid_pool(false), offset(0) {} pg_log_entry_t(int _op, const hobject_t& _soid, const eversion_t& v, const eversion_t& pv, version_t uv, const osd_reqid_t& rid, const utime_t& mt) : op(_op), soid(_soid), version(v), prior_version(pv), user_version(uv), reqid(rid), mtime(mt), invalid_hash(false), invalid_pool(false), offset(0) {} bool is_clone() const { return op == CLONE; } bool is_modify() const { return op == MODIFY; } bool is_promote() const { return op == PROMOTE; } bool is_clean() const { return op == CLEAN; } bool is_backlog() const { return op == BACKLOG; } bool is_lost_revert() const { return op == LOST_REVERT; } bool is_lost_delete() const { return op == LOST_DELETE; } bool is_lost_mark() const { return op == LOST_MARK; } bool is_update() const { return is_clone() || is_modify() || is_promote() || is_clean() || is_backlog() || is_lost_revert() || is_lost_mark(); } bool is_delete() const { return op == DELETE || op == LOST_DELETE; } bool reqid_is_indexed() const { return reqid != osd_reqid_t() && (op == MODIFY || op == DELETE); } string get_key_name() const; void encode_with_checksum(bufferlist& bl) const; void decode_with_checksum(bufferlist::iterator& p); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_log_entry_t) ostream& operator<<(ostream& out, const pg_log_entry_t& e); /** * pg_log_t - incremental log of recent pg changes. * * serves as a recovery queue for recent changes. */ struct pg_log_t { /* * head - newest entry (update|delete) * tail - entry previous to oldest (update|delete) for which we have * complete negative information. * i.e. we can infer pg contents for any store whose last_update >= tail. */ eversion_t head; // newest entry eversion_t tail; // version prior to oldest // We can rollback rollback-able entries > can_rollback_to eversion_t can_rollback_to; // always <= can_rollback_to, indicates how far stashed rollback // data can be found eversion_t rollback_info_trimmed_to; list log; // the actual log. pg_log_t() {} void clear() { eversion_t z; can_rollback_to = head = tail = z; log.clear(); } bool empty() const { return log.empty(); } bool null() const { return head.version == 0 && head.epoch == 0; } size_t approx_size() const { return head.version - tail.version; } list::const_iterator find_entry(eversion_t v) const { int fromhead = head.version - v.version; int fromtail = v.version - tail.version; list::const_iterator p; if (fromhead < fromtail) { p = log.end(); --p; while (p->version > v) --p; return p; } else { p = log.begin(); while (p->version < v) ++p; return p; } } list::iterator find_entry(eversion_t v) { int fromhead = head.version - v.version; int fromtail = v.version - tail.version; list::iterator p; if (fromhead < fromtail) { p = log.end(); --p; while (p->version > v) --p; return p; } else { p = log.begin(); while (p->version < v) ++p; return p; } } /** * copy entries from the tail of another pg_log_t * * @param other pg_log_t to copy from * @param from copy entries after this version */ void copy_after(const pg_log_t &other, eversion_t from); /** * copy a range of entries from another pg_log_t * * @param other pg_log_t to copy from * @param from copy entries after this version * @parem to up to and including this version */ void copy_range(const pg_log_t &other, eversion_t from, eversion_t to); /** * copy up to N entries * * @param o source log * @param max max number of entreis to copy */ void copy_up_to(const pg_log_t &other, int max); ostream& print(ostream& out) const; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl, int64_t pool = -1); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_log_t) inline ostream& operator<<(ostream& out, const pg_log_t& log) { out << "log((" << log.tail << "," << log.head << "], crt=" << log.can_rollback_to << ")"; return out; } /** * pg_missing_t - summary of missing objects. * * kept in memory, as a supplement to pg_log_t * also used to pass missing info in messages. */ struct pg_missing_t { struct item { eversion_t need, have; item() {} item(eversion_t n) : need(n) {} // have no old version item(eversion_t n, eversion_t h) : need(n), have(h) {} void encode(bufferlist& bl) const { ::encode(need, bl); ::encode(have, bl); } void decode(bufferlist::iterator& bl) { ::decode(need, bl); ::decode(have, bl); } void dump(Formatter *f) const { f->dump_stream("need") << need; f->dump_stream("have") << have; } static void generate_test_instances(list& o) { o.push_back(new item); o.push_back(new item); o.back()->need = eversion_t(1, 2); o.back()->have = eversion_t(1, 1); } }; WRITE_CLASS_ENCODER(item) map missing; // oid -> (need v, have v) map rmissing; // v -> oid unsigned int num_missing() const; bool have_missing() const; void swap(pg_missing_t& o); bool is_missing(const hobject_t& oid) const; bool is_missing(const hobject_t& oid, eversion_t v) const; eversion_t have_old(const hobject_t& oid) const; void add_next_event(const pg_log_entry_t& e); void revise_need(hobject_t oid, eversion_t need); void revise_have(hobject_t oid, eversion_t have); void add(const hobject_t& oid, eversion_t need, eversion_t have); void rm(const hobject_t& oid, eversion_t v); void rm(const std::map::iterator &m); void got(const hobject_t& oid, eversion_t v); void got(const std::map::iterator &m); void split_into(pg_t child_pgid, unsigned split_bits, pg_missing_t *omissing); void clear() { missing.clear(); rmissing.clear(); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl, int64_t pool = -1); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_missing_t::item) WRITE_CLASS_ENCODER(pg_missing_t) ostream& operator<<(ostream& out, const pg_missing_t::item& i); ostream& operator<<(ostream& out, const pg_missing_t& missing); /** * pg list objects response format * */ struct pg_ls_response_t { collection_list_handle_t handle; list > entries; void encode(bufferlist& bl) const { __u8 v = 1; ::encode(v, bl); ::encode(handle, bl); ::encode(entries, bl); } void decode(bufferlist::iterator& bl) { __u8 v; ::decode(v, bl); assert(v == 1); ::decode(handle, bl); ::decode(entries, bl); } void dump(Formatter *f) const { f->dump_stream("handle") << handle; f->open_array_section("entries"); for (list >::const_iterator p = entries.begin(); p != entries.end(); ++p) { f->open_object_section("object"); f->dump_stream("object") << p->first; f->dump_string("key", p->second); f->close_section(); } f->close_section(); } static void generate_test_instances(list& o) { o.push_back(new pg_ls_response_t); o.push_back(new pg_ls_response_t); o.back()->handle = hobject_t(object_t("hi"), "key", 1, 2, -1, ""); o.back()->entries.push_back(make_pair(object_t("one"), string())); o.back()->entries.push_back(make_pair(object_t("two"), string("twokey"))); } }; WRITE_CLASS_ENCODER(pg_ls_response_t) /** * object_copy_cursor_t */ struct object_copy_cursor_t { bool attr_complete; uint64_t data_offset; bool data_complete; string omap_offset; bool omap_complete; object_copy_cursor_t() : attr_complete(false), data_offset(0), data_complete(false), omap_complete(false) {} bool is_initial() const { return !attr_complete && data_offset == 0 && omap_offset.empty(); } bool is_complete() const { return attr_complete && data_complete && omap_complete; } static void generate_test_instances(list& o); void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; }; WRITE_CLASS_ENCODER(object_copy_cursor_t) /** * object_copy_data_t * * Return data from a copy request. The semantics are a little strange * as a result of the encoding's heritage. * * In particular, the sender unconditionally fills in the cursor (from what * it receives and sends), the size, and the mtime, but is responsible for * figuring out whether it should put any data in the attrs, data, or * omap members (corresponding to xattrs, object data, and the omap entries) * based on external data (the client includes a max amount to return with * the copy request). The client then looks into the attrs, data, and/or omap * based on the contents of the cursor. */ struct object_copy_data_t { object_copy_cursor_t cursor; uint64_t size; utime_t mtime; map attrs; bufferlist data; bufferlist omap_header; map omap; string category; /// which snaps we are defined for (if a snap and not the head) vector snaps; ///< latest snap seq for the object (if head) snapid_t snap_seq; public: object_copy_data_t() : size((uint64_t)-1) {} static void generate_test_instances(list& o); void encode_classic(bufferlist& bl) const; void decode_classic(bufferlist::iterator& bl); void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; }; WRITE_CLASS_ENCODER(object_copy_data_t) /** * pg creation info */ struct pg_create_t { epoch_t created; // epoch pg created pg_t parent; // split from parent (if != pg_t()) __s32 split_bits; pg_create_t() : created(0), split_bits(0) {} pg_create_t(unsigned c, pg_t p, int s) : created(c), parent(p), split_bits(s) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(pg_create_t) // ----------------------------------------- struct osd_peer_stat_t { utime_t stamp; osd_peer_stat_t() { } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(osd_peer_stat_t) ostream& operator<<(ostream& out, const osd_peer_stat_t &stat); // ----------------------------------------- class ObjectExtent { public: object_t oid; // object id uint64_t objectno; uint64_t offset; // in object uint64_t length; // in object uint64_t truncate_size; // in object object_locator_t oloc; // object locator (pool etc) vector > buffer_extents; // off -> len. extents in buffer being mapped (may be fragmented bc of striping!) ObjectExtent() : objectno(0), offset(0), length(0), truncate_size(0) {} ObjectExtent(object_t o, uint64_t ono, uint64_t off, uint64_t l, uint64_t ts) : oid(o), objectno(ono), offset(off), length(l), truncate_size(ts) { } }; inline ostream& operator<<(ostream& out, const ObjectExtent &ex) { return out << "extent(" << ex.oid << " (" << ex.objectno << ") in " << ex.oloc << " " << ex.offset << "~" << ex.length << " -> " << ex.buffer_extents << ")"; } // --------------------------------------- class OSDSuperblock { public: uuid_d cluster_fsid, osd_fsid; int32_t whoami; // my role in this fs. epoch_t current_epoch; // most recent epoch epoch_t oldest_map, newest_map; // oldest/newest maps we have. double weight; CompatSet compat_features; // last interval over which i mounted and was then active epoch_t mounted; // last epoch i mounted epoch_t clean_thru; // epoch i was active and clean thru epoch_t last_map_marked_full; // last epoch osdmap was marked full OSDSuperblock() : whoami(-1), current_epoch(0), oldest_map(0), newest_map(0), weight(0), mounted(0), clean_thru(0), last_map_marked_full(0) { } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(OSDSuperblock) inline ostream& operator<<(ostream& out, const OSDSuperblock& sb) { return out << "sb(" << sb.cluster_fsid << " osd." << sb.whoami << " " << sb.osd_fsid << " e" << sb.current_epoch << " [" << sb.oldest_map << "," << sb.newest_map << "]" << " lci=[" << sb.mounted << "," << sb.clean_thru << "]" << ")"; } // ------- WRITE_CLASS_ENCODER(interval_set) /* * attached to object head. describes most recent snap context, and * set of existing clones. */ struct SnapSet { snapid_t seq; bool head_exists; vector snaps; // descending vector clones; // ascending map > clone_overlap; // overlap w/ next newest map clone_size; SnapSet() : seq(0), head_exists(false) {} SnapSet(bufferlist& bl) { bufferlist::iterator p = bl.begin(); decode(p); } /// populate SnapSet from a librados::snap_set_t void from_snap_set(const librados::snap_set_t& ss); /// get space accounted to clone uint64_t get_clone_bytes(snapid_t clone) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); SnapContext get_ssc_as_of(snapid_t as_of) const { SnapContext out; out.seq = as_of; for (vector::const_iterator i = snaps.begin(); i != snaps.end(); ++i) { if (*i <= as_of) out.snaps.push_back(*i); } return out; } // return min element of snaps > after, return max if no such element snapid_t get_first_snap_after(snapid_t after, snapid_t max) const { for (vector::const_reverse_iterator i = snaps.rbegin(); i != snaps.rend(); ++i) { if (*i > after) return *i; } return max; } }; WRITE_CLASS_ENCODER(SnapSet) ostream& operator<<(ostream& out, const SnapSet& cs); #define OI_ATTR "_" #define SS_ATTR "snapset" struct watch_info_t { uint64_t cookie; uint32_t timeout_seconds; entity_addr_t addr; watch_info_t() : cookie(0), timeout_seconds(0) { } watch_info_t(uint64_t c, uint32_t t, const entity_addr_t& a) : cookie(c), timeout_seconds(t), addr(a) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(watch_info_t) static inline bool operator==(const watch_info_t& l, const watch_info_t& r) { return l.cookie == r.cookie && l.timeout_seconds == r.timeout_seconds && l.addr == r.addr; } static inline ostream& operator<<(ostream& out, const watch_info_t& w) { return out << "watch(cookie " << w.cookie << " " << w.timeout_seconds << "s" << " " << w.addr << ")"; } struct notify_info_t { uint64_t cookie; uint32_t timeout; bufferlist bl; }; static inline ostream& operator<<(ostream& out, const notify_info_t& n) { return out << "notify(cookie " << n.cookie << " " << n.timeout << "s)"; } struct object_info_t { hobject_t soid; string category; eversion_t version, prior_version; version_t user_version; osd_reqid_t last_reqid; uint64_t size; utime_t mtime; utime_t local_mtime; // local mtime // note: these are currently encoded into a total 16 bits; see // encode()/decode() for the weirdness. typedef enum { FLAG_LOST = 1<<0, FLAG_WHITEOUT = 1<<1, // object logically does not exist FLAG_DIRTY = 1<<2, // object has been modified since last flushed or undirtied FLAG_OMAP = 1 << 3, // has (or may have) some/any omap data // ... FLAG_USES_TMAP = 1<<8, // deprecated; no longer used. } flag_t; flag_t flags; static string get_flag_string(flag_t flags) { string s; if (flags & FLAG_LOST) s += "|lost"; if (flags & FLAG_WHITEOUT) s += "|whiteout"; if (flags & FLAG_DIRTY) s += "|dirty"; if (flags & FLAG_USES_TMAP) s += "|uses_tmap"; if (flags & FLAG_OMAP) s += "|omap"; if (s.length()) return s.substr(1); return s; } string get_flag_string() const { return get_flag_string(flags); } osd_reqid_t wrlock_by; // [head] vector snaps; // [clone] uint64_t truncate_seq, truncate_size; map, watch_info_t> watchers; void copy_user_bits(const object_info_t& other); static ps_t legacy_object_locator_to_ps(const object_t &oid, const object_locator_t &loc); bool test_flag(flag_t f) const { return (flags & f) == f; } void set_flag(flag_t f) { flags = (flag_t)(flags | f); } void clear_flag(flag_t f) { flags = (flag_t)(flags & ~f); } bool is_lost() const { return test_flag(FLAG_LOST); } bool is_whiteout() const { return test_flag(FLAG_WHITEOUT); } bool is_dirty() const { return test_flag(FLAG_DIRTY); } bool is_omap() const { return test_flag(FLAG_OMAP); } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void decode(bufferlist& bl) { bufferlist::iterator p = bl.begin(); decode(p); } void dump(Formatter *f) const; static void generate_test_instances(list& o); explicit object_info_t() : user_version(0), size(0), flags((flag_t)0), truncate_seq(0), truncate_size(0) {} object_info_t(const hobject_t& s) : soid(s), user_version(0), size(0), flags((flag_t)0), truncate_seq(0), truncate_size(0) {} object_info_t(bufferlist& bl) { decode(bl); } }; WRITE_CLASS_ENCODER(object_info_t) struct ObjectState { object_info_t oi; bool exists; ///< the stored object exists (i.e., we will remember the object_info_t) ObjectState() : exists(false) {} ObjectState(const object_info_t &oi_, bool exists_) : oi(oi_), exists(exists_) {} }; struct SnapSetContext { hobject_t oid; int ref; bool registered; SnapSet snapset; bool exists; SnapSetContext(const hobject_t& o) : oid(o), ref(0), registered(false), exists(true) { } }; /* * keep tabs on object modifications that are in flight. * we need to know the projected existence, size, snapset, * etc., because we don't send writes down to disk until after * replicas ack. */ struct ObjectContext; typedef ceph::shared_ptr ObjectContextRef; struct ObjectContext { ObjectState obs; SnapSetContext *ssc; // may be null Context *destructor_callback; private: Mutex lock; public: Cond cond; int unstable_writes, readers, writers_waiting, readers_waiting; /// in-progress copyfrom ops for this object bool blocked; // set if writes for this object are blocked on another objects recovery ObjectContextRef blocked_by; // object blocking our writes set blocking; // objects whose writes we block bool requeue_scrub_on_unblock; // true if we need to requeue scrub on unblock // any entity in obs.oi.watchers MUST be in either watchers or unconnected_watchers. map, WatchRef> watchers; struct RWState { enum State { RWNONE, RWREAD, RWWRITE }; static const char *get_state_name(State s) { switch (s) { case RWNONE: return "none"; case RWREAD: return "read"; case RWWRITE: return "write"; default: return "???"; } } const char *get_state_name() const { return get_state_name(state); } State state; ///< rw state uint64_t count; ///< number of readers or writers list waiters; ///< ops waiting on state change /// if set, restart backfill when we can get a read lock bool backfill_read_marker; /// if set, requeue snaptrim on lock release bool snaptrimmer_write_marker; RWState() : state(RWNONE), count(0), backfill_read_marker(false), snaptrimmer_write_marker(false) {} bool get_read(OpRequestRef op) { if (get_read_lock()) { return true; } // else waiters.push_back(op); return false; } /// this function adjusts the counts if necessary bool get_read_lock() { // don't starve anybody! if (!waiters.empty()) { return false; } switch (state) { case RWNONE: assert(count == 0); state = RWREAD; // fall through case RWREAD: count++; return true; case RWWRITE: return false; default: assert(0 == "unhandled case"); return false; } } bool get_write(OpRequestRef op, bool greedy=false) { if (get_write_lock(greedy)) { return true; } // else if (op) waiters.push_back(op); return false; } bool get_write_lock(bool greedy=false) { if (!greedy) { // don't starve anybody! if (!waiters.empty() || backfill_read_marker) { return false; } } switch (state) { case RWNONE: assert(count == 0); state = RWWRITE; // fall through case RWWRITE: count++; return true; case RWREAD: return false; default: assert(0 == "unhandled case"); return false; } } /// same as get_write_lock, but ignore starvation bool take_write_lock() { if (state == RWWRITE) { count++; return true; } return get_write_lock(); } void dec(list *requeue) { assert(count > 0); assert(requeue); count--; if (count == 0) { state = RWNONE; requeue->splice(requeue->end(), waiters); } } void put_read(list *requeue) { assert(state == RWREAD); dec(requeue); } void put_write(list *requeue) { assert(state == RWWRITE); dec(requeue); } bool empty() const { return state == RWNONE; } } rwstate; bool get_read(OpRequestRef op) { return rwstate.get_read(op); } bool get_write(OpRequestRef op) { return rwstate.get_write(op, false); } bool get_write_greedy(OpRequestRef op) { return rwstate.get_write(op, true); } bool get_snaptrimmer_write() { if (rwstate.get_write_lock()) { return true; } else { rwstate.snaptrimmer_write_marker = true; return false; } } bool get_backfill_read() { rwstate.backfill_read_marker = true; if (rwstate.get_read_lock()) { return true; } return false; } void drop_backfill_read(list *ls) { assert(rwstate.backfill_read_marker); rwstate.put_read(ls); rwstate.backfill_read_marker = false; } void put_read(list *to_wake) { rwstate.put_read(to_wake); } void put_write(list *to_wake, bool *requeue_recovery, bool *requeue_snaptrimmer) { rwstate.put_write(to_wake); if (rwstate.empty() && rwstate.backfill_read_marker) { rwstate.backfill_read_marker = false; *requeue_recovery = true; } if (rwstate.empty() && rwstate.snaptrimmer_write_marker) { rwstate.snaptrimmer_write_marker = false; *requeue_snaptrimmer = true; } } ObjectContext() : ssc(NULL), destructor_callback(0), lock("ReplicatedPG::ObjectContext::lock"), unstable_writes(0), readers(0), writers_waiting(0), readers_waiting(0), blocked(false), requeue_scrub_on_unblock(false) {} ~ObjectContext() { assert(rwstate.empty()); if (destructor_callback) destructor_callback->complete(0); } void start_block() { assert(!blocked); blocked = true; } void stop_block() { assert(blocked); blocked = false; } bool is_blocked() const { return blocked; } // do simple synchronous mutual exclusion, for now. now waitqueues or anything fancy. void ondisk_write_lock() { lock.Lock(); writers_waiting++; while (readers_waiting || readers) cond.Wait(lock); writers_waiting--; unstable_writes++; lock.Unlock(); } void ondisk_write_unlock() { lock.Lock(); assert(unstable_writes > 0); unstable_writes--; if (!unstable_writes && readers_waiting) cond.Signal(); lock.Unlock(); } void ondisk_read_lock() { lock.Lock(); readers_waiting++; while (unstable_writes) cond.Wait(lock); readers_waiting--; readers++; lock.Unlock(); } void ondisk_read_unlock() { lock.Lock(); assert(readers > 0); readers--; if (!readers && writers_waiting) cond.Signal(); lock.Unlock(); } // attr cache map attr_cache; void fill_in_setattrs(const set &changing, ObjectModDesc *mod) { map > to_set; for (set::const_iterator i = changing.begin(); i != changing.end(); ++i) { map::iterator iter = attr_cache.find(*i); if (iter != attr_cache.end()) { to_set[*i] = iter->second; } else { to_set[*i]; } } mod->setattrs(to_set); } }; inline ostream& operator<<(ostream& out, const ObjectState& obs) { out << obs.oi.soid; if (!obs.exists) out << "(dne)"; return out; } inline ostream& operator<<(ostream& out, const ObjectContext::RWState& rw) { return out << "rwstate(" << rw.get_state_name() << " n=" << rw.count << " w=" << rw.waiters.size() << ")"; } inline ostream& operator<<(ostream& out, const ObjectContext& obc) { return out << "obc(" << obc.obs << " " << obc.rwstate << ")"; } ostream& operator<<(ostream& out, const object_info_t& oi); // Object recovery struct ObjectRecoveryInfo { hobject_t soid; eversion_t version; uint64_t size; object_info_t oi; SnapSet ss; interval_set copy_subset; map > clone_subset; ObjectRecoveryInfo() : size(0) { } static void generate_test_instances(list& o); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl, int64_t pool = -1); ostream &print(ostream &out) const; void dump(Formatter *f) const; }; WRITE_CLASS_ENCODER(ObjectRecoveryInfo) ostream& operator<<(ostream& out, const ObjectRecoveryInfo &inf); struct ObjectRecoveryProgress { bool first; uint64_t data_recovered_to; bool data_complete; string omap_recovered_to; bool omap_complete; ObjectRecoveryProgress() : first(true), data_recovered_to(0), data_complete(false), omap_complete(false) { } bool is_complete(const ObjectRecoveryInfo& info) const { return (data_recovered_to >= ( info.copy_subset.empty() ? 0 : info.copy_subset.range_end())) && omap_complete; } static void generate_test_instances(list& o); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); ostream &print(ostream &out) const; void dump(Formatter *f) const; }; WRITE_CLASS_ENCODER(ObjectRecoveryProgress) ostream& operator<<(ostream& out, const ObjectRecoveryProgress &prog); struct PushReplyOp { hobject_t soid; static void generate_test_instances(list& o); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); ostream &print(ostream &out) const; void dump(Formatter *f) const; uint64_t cost(CephContext *cct) const; }; WRITE_CLASS_ENCODER(PushReplyOp) ostream& operator<<(ostream& out, const PushReplyOp &op); struct PullOp { hobject_t soid; ObjectRecoveryInfo recovery_info; ObjectRecoveryProgress recovery_progress; static void generate_test_instances(list& o); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); ostream &print(ostream &out) const; void dump(Formatter *f) const; uint64_t cost(CephContext *cct) const; }; WRITE_CLASS_ENCODER(PullOp) ostream& operator<<(ostream& out, const PullOp &op); struct PushOp { hobject_t soid; eversion_t version; bufferlist data; interval_set data_included; bufferlist omap_header; map omap_entries; map attrset; ObjectRecoveryInfo recovery_info; ObjectRecoveryProgress before_progress; ObjectRecoveryProgress after_progress; static void generate_test_instances(list& o); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); ostream &print(ostream &out) const; void dump(Formatter *f) const; uint64_t cost(CephContext *cct) const; }; WRITE_CLASS_ENCODER(PushOp) ostream& operator<<(ostream& out, const PushOp &op); /* * summarize pg contents for purposes of a scrub */ struct ScrubMap { struct object { uint64_t size; bool negative; map attrs; __u32 digest; bool digest_present; uint32_t nlinks; set snapcolls; __u32 omap_digest; bool omap_digest_present; bool read_error; object() : // Init invalid size so it won't match if we get a stat EIO error size(-1), negative(false), digest(0), digest_present(false), nlinks(0), omap_digest(0), omap_digest_present(false), read_error(false) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(object) map objects; map attrs; eversion_t valid_through; eversion_t incr_since; void merge_incr(const ScrubMap &l); void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl, int64_t pool=-1); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ScrubMap::object) WRITE_CLASS_ENCODER(ScrubMap) struct OSDOp { ceph_osd_op op; sobject_t soid; bufferlist indata, outdata; int32_t rval; OSDOp() : rval(0) { memset(&op, 0, sizeof(ceph_osd_op)); } /** * split a bufferlist into constituent indata nembers of a vector of OSDOps * * @param ops [out] vector of OSDOps * @param in [in] combined data buffer */ static void split_osd_op_vector_in_data(vector& ops, bufferlist& in); /** * merge indata nembers of a vector of OSDOp into a single bufferlist * * Notably this also encodes certain other OSDOp data into the data * buffer, including the sobject_t soid. * * @param ops [in] vector of OSDOps * @param in [out] combined data buffer */ static void merge_osd_op_vector_in_data(vector& ops, bufferlist& out); /** * split a bufferlist into constituent outdata members of a vector of OSDOps * * @param ops [out] vector of OSDOps * @param in [in] combined data buffer */ static void split_osd_op_vector_out_data(vector& ops, bufferlist& in); /** * merge outdata members of a vector of OSDOps into a single bufferlist * * @param ops [in] vector of OSDOps * @param in [out] combined data buffer */ static void merge_osd_op_vector_out_data(vector& ops, bufferlist& out); }; ostream& operator<<(ostream& out, const OSDOp& op); struct watch_item_t { entity_name_t name; uint64_t cookie; uint32_t timeout_seconds; entity_addr_t addr; watch_item_t() : cookie(0), timeout_seconds(0) { } watch_item_t(entity_name_t name, uint64_t cookie, uint32_t timeout, const entity_addr_t& addr) : name(name), cookie(cookie), timeout_seconds(timeout), addr(addr) { } void encode(bufferlist &bl) const { ENCODE_START(2, 1, bl); ::encode(name, bl); ::encode(cookie, bl); ::encode(timeout_seconds, bl); ::encode(addr, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(2, bl); ::decode(name, bl); ::decode(cookie, bl); ::decode(timeout_seconds, bl); if (struct_v >= 2) { ::decode(addr, bl); } DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(watch_item_t) struct obj_watch_item_t { hobject_t obj; watch_item_t wi; }; /** * obj list watch response format * */ struct obj_list_watch_response_t { list entries; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->open_array_section("entries"); for (list::const_iterator p = entries.begin(); p != entries.end(); ++p) { f->open_object_section("watch"); f->dump_stream("watcher") << p->name; f->dump_int("cookie", p->cookie); f->dump_int("timeout", p->timeout_seconds); f->open_object_section("addr"); p->addr.dump(f); f->close_section(); f->close_section(); } f->close_section(); } static void generate_test_instances(list& o) { entity_addr_t ea; o.push_back(new obj_list_watch_response_t); o.push_back(new obj_list_watch_response_t); ea.set_nonce(1000); ea.set_family(AF_INET); ea.set_in4_quad(0, 127); ea.set_in4_quad(1, 0); ea.set_in4_quad(2, 0); ea.set_in4_quad(3, 1); ea.set_port(1024); o.back()->entries.push_back(watch_item_t(entity_name_t(entity_name_t::TYPE_CLIENT, 1), 10, 30, ea)); ea.set_nonce(1001); ea.set_in4_quad(3, 2); ea.set_port(1025); o.back()->entries.push_back(watch_item_t(entity_name_t(entity_name_t::TYPE_CLIENT, 2), 20, 60, ea)); } }; WRITE_CLASS_ENCODER(obj_list_watch_response_t) struct clone_info { snapid_t cloneid; vector snaps; // ascending vector< pair > overlap; uint64_t size; clone_info() : cloneid(CEPH_NOSNAP), size(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(cloneid, bl); ::encode(snaps, bl); ::encode(overlap, bl); ::encode(size, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(cloneid, bl); ::decode(snaps, bl); ::decode(overlap, bl); ::decode(size, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { if (cloneid == CEPH_NOSNAP) f->dump_string("cloneid", "HEAD"); else f->dump_unsigned("cloneid", cloneid.val); f->open_array_section("snapshots"); for (vector::const_iterator p = snaps.begin(); p != snaps.end(); ++p) { f->open_object_section("snap"); f->dump_unsigned("id", p->val); f->close_section(); } f->close_section(); f->open_array_section("overlaps"); for (vector< pair >::const_iterator q = overlap.begin(); q != overlap.end(); ++q) { f->open_object_section("overlap"); f->dump_unsigned("offset", q->first); f->dump_unsigned("length", q->second); f->close_section(); } f->close_section(); f->dump_unsigned("size", size); } static void generate_test_instances(list& o) { o.push_back(new clone_info); o.push_back(new clone_info); o.back()->cloneid = 1; o.back()->snaps.push_back(1); o.back()->overlap.push_back(pair(0,4096)); o.back()->overlap.push_back(pair(8192,4096)); o.back()->size = 16384; o.push_back(new clone_info); o.back()->cloneid = CEPH_NOSNAP; o.back()->size = 32768; } }; WRITE_CLASS_ENCODER(clone_info) /** * obj list snaps response format * */ struct obj_list_snap_response_t { vector clones; // ascending snapid_t seq; void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(clones, bl); ::encode(seq, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(clones, bl); if (struct_v >= 2) ::decode(seq, bl); else seq = CEPH_NOSNAP; DECODE_FINISH(bl); } void dump(Formatter *f) const { f->open_array_section("clones"); for (vector::const_iterator p = clones.begin(); p != clones.end(); ++p) { f->open_object_section("clone"); p->dump(f); f->close_section(); } f->dump_unsigned("seq", seq); f->close_section(); } static void generate_test_instances(list& o) { o.push_back(new obj_list_snap_response_t); o.push_back(new obj_list_snap_response_t); clone_info cl; cl.cloneid = 1; cl.snaps.push_back(1); cl.overlap.push_back(pair(0,4096)); cl.overlap.push_back(pair(8192,4096)); cl.size = 16384; o.back()->clones.push_back(cl); cl.cloneid = CEPH_NOSNAP; cl.snaps.clear(); cl.overlap.clear(); cl.size = 32768; o.back()->clones.push_back(cl); o.back()->seq = 123; } }; WRITE_CLASS_ENCODER(obj_list_snap_response_t) enum scrub_error_type { CLEAN, DEEP_ERROR, SHALLOW_ERROR }; #endif ceph-0.80.11/src/osd/OSDCap.h0000664000175100017510000001200012623076744017464 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * OSDCaps: Hold the capabilities associated with a single authenticated * user key. These are specified by text strings of the form * "allow r" (which allows reading anything on the OSD) * "allow rwx auid foo" (which allows full access to listed auids) * "allow rwx pool foo" (which allows full access to listed pools) * "allow *" (which allows full access to EVERYTHING) * * The full grammar is documented in the parser in OSDCap.cc. * * The OSD assumes that anyone with * caps is an admin and has full * message permissions. This means that only the monitor and the OSDs * should get * */ #ifndef CEPH_OSDCAP_H #define CEPH_OSDCAP_H #include using std::ostream; #include "include/types.h" static const __u8 OSD_CAP_R = (1 << 1); // read static const __u8 OSD_CAP_W = (1 << 2); // write static const __u8 OSD_CAP_CLS_R = (1 << 3); // class read static const __u8 OSD_CAP_CLS_W = (1 << 4); // class write static const __u8 OSD_CAP_X = (OSD_CAP_CLS_R | OSD_CAP_CLS_W); // execute static const __u8 OSD_CAP_ANY = 0xff; // * struct osd_rwxa_t { __u8 val; osd_rwxa_t(__u8 v = 0) : val(v) {} osd_rwxa_t& operator=(__u8 v) { val = v; return *this; } operator __u8() const { return val; } }; ostream& operator<<(ostream& out, osd_rwxa_t p); struct OSDCapSpec { osd_rwxa_t allow; std::string class_name; std::string class_allow; OSDCapSpec() : allow(0) {} OSDCapSpec(osd_rwxa_t v) : allow(v) {} OSDCapSpec(std::string n) : allow(0), class_name(n) {} OSDCapSpec(std::string n, std::string a) : allow(0), class_name(n), class_allow(a) {} bool allow_all() const { return allow == OSD_CAP_ANY; } }; ostream& operator<<(ostream& out, const OSDCapSpec& s); struct OSDCapMatch { // auid and pool_name/nspace are mutually exclusive int64_t auid; std::string pool_name; bool is_nspace; // true if nspace is defined; false if not constrained. std::string nspace; std::string object_prefix; OSDCapMatch() : auid(CEPH_AUTH_UID_DEFAULT), is_nspace(false) {} OSDCapMatch(std::string pl, std::string pre) : auid(CEPH_AUTH_UID_DEFAULT), pool_name(pl), is_nspace(false), object_prefix(pre) {} OSDCapMatch(std::string pl, std::string ns, std::string pre) : auid(CEPH_AUTH_UID_DEFAULT), pool_name(pl), is_nspace(true), nspace(ns), object_prefix(pre) {} OSDCapMatch(uint64_t auid, std::string pre) : auid(auid), is_nspace(false), object_prefix(pre) {} /** * check if given request parameters match our constraints * * @param auid requesting user's auid * @param pool_name pool name * @param nspace_name namespace name * @param pool_auid pool's auid * @param object object name * @return true if we match, false otherwise */ bool is_match(const std::string& pool_name, const std::string& nspace_name, int64_t pool_auid, const std::string& object) const; bool is_match_all() const; }; ostream& operator<<(ostream& out, const OSDCapMatch& m); struct OSDCapGrant { OSDCapMatch match; OSDCapSpec spec; OSDCapGrant() {} OSDCapGrant(OSDCapMatch m, OSDCapSpec s) : match(m), spec(s) {} }; ostream& operator<<(ostream& out, const OSDCapGrant& g); struct OSDCap { std::vector grants; OSDCap() {} OSDCap(std::vector g) : grants(g) {} bool allow_all() const; void set_allow_all(); bool parse(const std::string& str, ostream *err=NULL); /** * check if we are capable of something * * This method actually checks a description of a particular operation against * what the capability has specified. Currently that is just rwx with matches * against pool, pool auid, and object name prefix. * * @param pool_name name of the pool we are accessing * @param ns name of the namespace we are accessing * @param pool_auid owner of the pool we are accessing * @param object name of the object we are accessing * @param op_may_read whether the operation may need to read * @param op_may_write whether the operation may need to write * @param op_may_class_read whether the operation needs to call a * read class method * @param op_may_class_write whether the operation needs to call a * write class method * @return true if the operation is allowed, false otherwise */ bool is_capable(const string& pool_name, const string& ns, int64_t pool_auid, const string& object, bool op_may_read, bool op_may_write, bool op_may_class_read, bool op_may_class_write) const; }; static inline ostream& operator<<(ostream& out, const OSDCap& cap) { return out << "osdcap" << cap.grants; } #endif ceph-0.80.11/src/osd/SnapMapper.h0000664000175100017510000001530612623076744020475 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef SNAPMAPPER_H #define SNAPMAPPER_H #include #include #include #include #include "common/map_cacher.hpp" #include "common/hobject.h" #include "include/buffer.h" #include "include/encoding.h" #include "include/object.h" #include "os/ObjectStore.h" class OSDriver : public MapCacher::StoreDriver { ObjectStore *os; coll_t cid; hobject_t hoid; public: class OSTransaction : public MapCacher::Transaction { friend class OSDriver; coll_t cid; hobject_t hoid; ObjectStore::Transaction *t; OSTransaction( coll_t cid, const hobject_t &hoid, ObjectStore::Transaction *t) : cid(cid), hoid(hoid), t(t) {} public: void set_keys( const std::map &to_set) { t->omap_setkeys(cid, hoid, to_set); } void remove_keys( const std::set &to_remove) { t->omap_rmkeys(cid, hoid, to_remove); } void add_callback( Context *c) { t->register_on_applied(c); } }; OSTransaction get_transaction( ObjectStore::Transaction *t) { return OSTransaction(cid, hoid, t); } OSDriver(ObjectStore *os, coll_t cid, const hobject_t &hoid) : os(os), cid(cid), hoid(hoid) {} int get_keys( const std::set &keys, std::map *out); int get_next( const std::string &key, pair *next); }; /** * SnapMapper * * Manages two mappings: * 1) hobject_t -> {snapid} * 2) snapid -> {hobject_t} * * We accomplish this using two sets of keys: * 1) OBJECT_PREFIX + obj.str() -> encoding of object_snaps * 2) MAPPING_PREFIX + snapid_t + obj.str() -> encoding of pair * * The on disk strings and encodings are implemented in to_raw, to_raw_key, * from_raw, to_object_key. * * The object -> {snapid} mapping is primarily included so that the * SnapMapper state can be verified against the external PG state during * scrub etc. * * The 2) mapping is arranged such that all objects in a particular * snap will sort together, and so that all objects in a pg for a * particular snap will group under up to 8 prefixes. */ class SnapMapper { public: struct object_snaps { hobject_t oid; std::set snaps; object_snaps(hobject_t oid, const std::set &snaps) : oid(oid), snaps(snaps) {} object_snaps() {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bp); }; private: MapCacher::MapCacher backend; static const std::string MAPPING_PREFIX; static const std::string OBJECT_PREFIX; static std::string get_prefix(snapid_t snap); std::string to_raw_key( const std::pair &to_map); std::pair to_raw( const std::pair &to_map); static bool is_mapping(const std::string &to_test); std::pair from_raw( const std::pair &image); std::string to_object_key(const hobject_t &hoid); int get_snaps(const hobject_t &oid, object_snaps *out); void set_snaps( const hobject_t &oid, const object_snaps &out, MapCacher::Transaction *t); void clear_snaps( const hobject_t &oid, MapCacher::Transaction *t); // True if hoid belongs in this mapping based on mask_bits and match bool check(const hobject_t &hoid) const { return hoid.match(mask_bits, match); } int _remove_oid( const hobject_t &oid, ///< [in] oid to remove MapCacher::Transaction *t ///< [out] transaction ); public: static string make_shard_prefix(shard_id_t shard) { if (shard == ghobject_t::NO_SHARD) return string(); char buf[20]; int r = snprintf(buf, sizeof(buf), ".%x", (int)shard); assert(r < (int)sizeof(buf)); return string(buf, r) + '_'; } uint32_t mask_bits; const uint32_t match; string last_key_checked; const int64_t pool; const shard_id_t shard; const string shard_prefix; SnapMapper( MapCacher::StoreDriver *driver, uint32_t match, ///< [in] pgid uint32_t bits, ///< [in] current split bits int64_t pool, ///< [in] pool shard_id_t shard ///< [in] shard ) : backend(driver), mask_bits(bits), match(match), pool(pool), shard(shard), shard_prefix(make_shard_prefix(shard)) { update_bits(mask_bits); } set prefixes; /// Update bits in case of pg split void update_bits( uint32_t new_bits ///< [in] new split bits ) { assert(new_bits >= mask_bits); mask_bits = new_bits; set _prefixes = hobject_t::get_prefixes( mask_bits, match, pool); prefixes.clear(); for (set::iterator i = _prefixes.begin(); i != _prefixes.end(); ++i) { prefixes.insert(shard_prefix + *i); } } /// Update snaps for oid, empty new_snaps removes the mapping int update_snaps( const hobject_t &oid, ///< [in] oid to update const std::set &new_snaps, ///< [in] new snap set const std::set *old_snaps, ///< [in] old snaps (for debugging) MapCacher::Transaction *t ///< [out] transaction ); ///@ return error, 0 on success /// Add mapping for oid, must not already be mapped void add_oid( const hobject_t &oid, ///< [in] oid to add std::set new_snaps, ///< [in] snaps MapCacher::Transaction *t ///< [out] transaction ); /// Returns first object with snap as a snap int get_next_object_to_trim( snapid_t snap, ///< [in] snap to check hobject_t *hoid ///< [out] next hoid to trim ); ///< @return error, -ENOENT if no more objects /// Remove mapping for oid int remove_oid( const hobject_t &oid, ///< [in] oid to remove MapCacher::Transaction *t ///< [out] transaction ); ///< @return error, -ENOENT if the object is not mapped /// Get snaps for oid int get_snaps( const hobject_t &oid, ///< [in] oid to get snaps for std::set *snaps ///< [out] snaps ); ///< @return error, -ENOENT if oid is not recorded }; WRITE_CLASS_ENCODER(SnapMapper::object_snaps) #endif ceph-0.80.11/src/osd/PGLog.cc0000664000175100017510000010032212623076744017526 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "PGLog.h" #include "PG.h" #include "SnapMapper.h" #include "../include/unordered_map.h" #define dout_subsys ceph_subsys_osd //////////////////// PGLog::IndexedLog //////////////////// void PGLog::IndexedLog::advance_rollback_info_trimmed_to( eversion_t to, LogEntryHandler *h) { assert(to <= can_rollback_to); if (to > rollback_info_trimmed_to) rollback_info_trimmed_to = to; while (rollback_info_trimmed_to_riter != log.rbegin()) { --rollback_info_trimmed_to_riter; if (rollback_info_trimmed_to_riter->version > rollback_info_trimmed_to) { ++rollback_info_trimmed_to_riter; break; } h->trim(*rollback_info_trimmed_to_riter); } } void PGLog::IndexedLog::split_into( pg_t child_pgid, unsigned split_bits, PGLog::IndexedLog *olog) { list oldlog; oldlog.swap(log); eversion_t old_tail; olog->head = head; olog->tail = tail; unsigned mask = ~((~0)<::iterator i = oldlog.begin(); i != oldlog.end(); ) { if ((i->soid.hash & mask) == child_pgid.m_seed) { olog->log.push_back(*i); } else { log.push_back(*i); } oldlog.erase(i++); } olog->can_rollback_to = can_rollback_to; olog->index(); index(); } void PGLog::IndexedLog::trim( LogEntryHandler *handler, eversion_t s, set *trimmed) { if (complete_to != log.end() && complete_to->version <= s) { generic_dout(0) << " bad trim to " << s << " when complete_to is " << complete_to->version << " on " << *this << dendl; } if (s > can_rollback_to) can_rollback_to = s; advance_rollback_info_trimmed_to(s, handler); while (!log.empty()) { pg_log_entry_t &e = *log.begin(); if (e.version > s) break; generic_dout(20) << "trim " << e << dendl; if (trimmed) trimmed->insert(e.version); unindex(e); // remove from index, if (rollback_info_trimmed_to_riter == log.rend() || e.version == rollback_info_trimmed_to_riter->version) { log.pop_front(); rollback_info_trimmed_to_riter = log.rend(); } else { log.pop_front(); } } // raise tail? if (tail < s) tail = s; } ostream& PGLog::IndexedLog::print(ostream& out) const { out << *this << std::endl; for (list::const_iterator p = log.begin(); p != log.end(); ++p) { out << *p << " " << (logged_object(p->soid) ? "indexed":"NOT INDEXED") << std::endl; assert(!p->reqid_is_indexed() || logged_req(p->reqid)); } return out; } //////////////////// PGLog //////////////////// void PGLog::reset_backfill() { missing.clear(); divergent_priors.clear(); dirty_divergent_priors = true; } void PGLog::clear() { divergent_priors.clear(); missing.clear(); log.clear(); log_keys_debug.clear(); undirty(); } void PGLog::clear_info_log( spg_t pgid, const hobject_t &infos_oid, const hobject_t &log_oid, ObjectStore::Transaction *t) { set keys_to_remove; keys_to_remove.insert(PG::get_epoch_key(pgid)); keys_to_remove.insert(PG::get_biginfo_key(pgid)); keys_to_remove.insert(PG::get_info_key(pgid)); t->remove(coll_t::META_COLL, log_oid); t->omap_rmkeys(coll_t::META_COLL, infos_oid, keys_to_remove); } void PGLog::trim( LogEntryHandler *handler, eversion_t trim_to, pg_info_t &info) { // trim? if (trim_to > log.tail) { /* If we are trimming, we must be complete up to trim_to, time * to throw out any divergent_priors */ divergent_priors.clear(); // We shouldn't be trimming the log past last_complete assert(trim_to <= info.last_complete); dout(10) << "trim " << log << " to " << trim_to << dendl; log.trim(handler, trim_to, &trimmed); info.log_tail = log.tail; } } void PGLog::proc_replica_log( ObjectStore::Transaction& t, pg_info_t &oinfo, const pg_log_t &olog, pg_missing_t& omissing, pg_shard_t from) const { dout(10) << "proc_replica_log for osd." << from << ": " << oinfo << " " << olog << " " << omissing << dendl; if (olog.head < log.tail) { dout(10) << __func__ << ": osd." << from << " does not overlap, not looking " << "for divergent objects" << dendl; return; } if (olog.head == log.head) { dout(10) << __func__ << ": osd." << from << " same log head, not looking " << "for divergent objects" << dendl; return; } assert(olog.head >= log.tail); /* basically what we're doing here is rewinding the remote log, dropping divergent entries, until we find something that matches our master log. we then reset last_update to reflect the new point up to which missing is accurate. later, in activate(), missing will get wound forward again and we will send the peer enough log to arrive at the same state. */ for (map::iterator i = omissing.missing.begin(); i != omissing.missing.end(); ++i) { dout(20) << " before missing " << i->first << " need " << i->second.need << " have " << i->second.have << dendl; } list::const_reverse_iterator first_non_divergent = log.log.rbegin(); while (1) { if (first_non_divergent == log.log.rend()) break; if (first_non_divergent->version <= olog.head) { dout(20) << "merge_log point (usually last shared) is " << *first_non_divergent << dendl; break; } ++first_non_divergent; } /* Because olog.head >= log.tail, we know that both pgs must at least have * the event represented by log.tail. Thus, lower_bound >= log.tail. It's * possible that olog/log contain no actual events between olog.head and * log.tail, however, since they might have been split out. Thus, if * we cannot find an event e such that log.tail <= e.version <= log.head, * the last_update must actually be log.tail. */ eversion_t lu = (first_non_divergent == log.log.rend() || first_non_divergent->version < log.tail) ? log.tail : first_non_divergent->version; list divergent; list::const_iterator pp = olog.log.end(); while (true) { if (pp == olog.log.begin()) break; --pp; const pg_log_entry_t& oe = *pp; // don't continue past the tail of our log. if (oe.version <= log.tail) { ++pp; break; } if (oe.version <= lu) { ++pp; break; } divergent.push_front(oe); } IndexedLog folog; folog.log.insert(folog.log.begin(), olog.log.begin(), pp); folog.index(); _merge_divergent_entries( folog, divergent, oinfo, olog.can_rollback_to, omissing, 0, 0); if (lu < oinfo.last_update) { dout(10) << " peer osd." << from << " last_update now " << lu << dendl; oinfo.last_update = lu; } if (omissing.have_missing()) { eversion_t first_missing = omissing.missing[omissing.rmissing.begin()->second].need; oinfo.last_complete = eversion_t(); list::const_iterator i = olog.log.begin(); for (; i != olog.log.end(); ++i) { if (i->version < first_missing) oinfo.last_complete = i->version; else break; } } else { oinfo.last_complete = oinfo.last_update; } } /** * _merge_object_divergent_entries * * There are 5 distinct cases: * 1) There is a more recent update: in this case we assume we adjusted the * store and missing during merge_log * 2) The first entry in the divergent sequence is a create. This might * either be because the object is a clone or because prior_version is * eversion_t(). In this case the object does not exist and we must * adjust missing and the store to match. * 3) We are currently missing the object. In this case, we adjust the * missing to our prior_version taking care to add a divergent_prior * if necessary * 4) We can rollback all of the entries. In this case, we do so using * the rollbacker and return -- the object does not go into missing. * 5) We cannot rollback at least 1 of the entries. In this case, we * clear the object out of the store and add a missing entry at * prior_version taking care to add a divergent_prior if * necessary. */ void PGLog::_merge_object_divergent_entries( const IndexedLog &log, const hobject_t &hoid, const list &entries, const pg_info_t &info, eversion_t olog_can_rollback_to, pg_missing_t &missing, boost::optional > *new_divergent_prior, LogEntryHandler *rollbacker ) { dout(10) << __func__ << ": merging hoid " << hoid << " entries: " << entries << dendl; if (hoid > info.last_backfill) { dout(10) << __func__ << ": hoid " << hoid << " after last_backfill" << dendl; return; } // entries is non-empty assert(!entries.empty()); eversion_t last; for (list::const_iterator i = entries.begin(); i != entries.end(); ++i) { // all entries are on hoid assert(i->soid == hoid); if (i != entries.begin() && i->prior_version != eversion_t()) { // in increasing order of version assert(i->version > last); // prior_version correct assert(i->prior_version == last); } last = i->version; if (rollbacker) rollbacker->trim(*i); } const eversion_t prior_version = entries.begin()->prior_version; const eversion_t first_divergent_update = entries.begin()->version; const eversion_t last_divergent_update = entries.rbegin()->version; const bool object_not_in_store = !missing.is_missing(hoid) && entries.rbegin()->is_delete(); dout(10) << __func__ << ": hoid " << hoid << " prior_version: " << prior_version << " first_divergent_update: " << first_divergent_update << " last_divergent_update: " << last_divergent_update << dendl; ceph::unordered_map::const_iterator objiter = log.objects.find(hoid); if (objiter != log.objects.end() && objiter->second->version >= first_divergent_update) { /// Case 1) assert(objiter->second->version > last_divergent_update); dout(10) << __func__ << ": more recent entry found: " << *objiter->second << ", already merged" << dendl; // ensure missing has been updated appropriately if (objiter->second->is_update()) { assert(missing.is_missing(hoid) && missing.missing[hoid].need == objiter->second->version); } else { assert(!missing.is_missing(hoid)); } missing.revise_have(hoid, eversion_t()); if (rollbacker && !object_not_in_store) rollbacker->remove(hoid); return; } dout(10) << __func__ << ": hoid " << hoid <<" has no more recent entries in log" << dendl; if (prior_version == eversion_t() || entries.front().is_clone()) { /// Case 2) dout(10) << __func__ << ": hoid " << hoid << " prior_version or op type indicates creation, deleting" << dendl; if (missing.is_missing(hoid)) missing.rm(missing.missing.find(hoid)); if (rollbacker && !object_not_in_store) rollbacker->remove(hoid); return; } if (missing.is_missing(hoid)) { /// Case 3) dout(10) << __func__ << ": hoid " << hoid << " missing, " << missing.missing[hoid] << " adjusting" << dendl; if (missing.missing[hoid].have == prior_version) { dout(10) << __func__ << ": hoid " << hoid << " missing.have is prior_version " << prior_version << " removing from missing" << dendl; missing.rm(missing.missing.find(hoid)); } else { dout(10) << __func__ << ": hoid " << hoid << " missing.have is " << missing.missing[hoid].have << ", adjusting" << dendl; missing.revise_need(hoid, prior_version); if (prior_version <= info.log_tail) { dout(10) << __func__ << ": hoid " << hoid << " prior_version " << prior_version << " <= info.log_tail " << info.log_tail << dendl; if (new_divergent_prior) *new_divergent_prior = make_pair(prior_version, hoid); } } return; } dout(10) << __func__ << ": hoid " << hoid << " must be rolled back or recovered, attempting to rollback" << dendl; bool can_rollback = true; /// Distinguish between 4) and 5) for (list::const_reverse_iterator i = entries.rbegin(); i != entries.rend(); ++i) { if (!i->mod_desc.can_rollback() || i->version <= olog_can_rollback_to) { dout(10) << __func__ << ": hoid " << hoid << " cannot rollback " << *i << dendl; can_rollback = false; break; } } if (can_rollback) { /// Case 4) for (list::const_reverse_iterator i = entries.rbegin(); i != entries.rend(); ++i) { assert(i->mod_desc.can_rollback() && i->version > olog_can_rollback_to); dout(10) << __func__ << ": hoid " << hoid << " rolling back " << *i << dendl; if (rollbacker) rollbacker->rollback(*i); } dout(10) << __func__ << ": hoid " << hoid << " rolled back" << dendl; return; } else { /// Case 5) dout(10) << __func__ << ": hoid " << hoid << " cannot roll back, " << "removing and adding to missing" << dendl; if (rollbacker && !object_not_in_store) rollbacker->remove(hoid); missing.add(hoid, prior_version, eversion_t()); if (prior_version <= info.log_tail) { dout(10) << __func__ << ": hoid " << hoid << " prior_version " << prior_version << " <= info.log_tail " << info.log_tail << dendl; if (new_divergent_prior) *new_divergent_prior = make_pair(prior_version, hoid); } } } /** * rewind divergent entries at the head of the log * * This rewinds entries off the head of our log that are divergent. * This is used by replicas during activation. * * @param t transaction * @param newhead new head to rewind to */ void PGLog::rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead, pg_info_t &info, LogEntryHandler *rollbacker, bool &dirty_info, bool &dirty_big_info) { dout(10) << "rewind_divergent_log truncate divergent future " << newhead << dendl; assert(newhead >= log.tail); list::iterator p = log.log.end(); list divergent; while (true) { if (p == log.log.begin()) { // yikes, the whole thing is divergent! divergent.swap(log.log); break; } --p; mark_dirty_from(p->version); if (p->version <= newhead) { ++p; divergent.splice(divergent.begin(), log.log, p, log.log.end()); break; } assert(p->version > newhead); dout(10) << "rewind_divergent_log future divergent " << *p << dendl; } log.head = newhead; info.last_update = newhead; if (info.last_complete > newhead) info.last_complete = newhead; log.index(); map new_priors; _merge_divergent_entries( log, divergent, info, log.can_rollback_to, missing, &new_priors, rollbacker); for (map::iterator i = new_priors.begin(); i != new_priors.end(); ++i) { add_divergent_prior( i->first, i->second); } if (info.last_update < log.can_rollback_to) log.can_rollback_to = info.last_update; dirty_info = true; dirty_big_info = true; } void PGLog::merge_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_shard_t fromosd, pg_info_t &info, LogEntryHandler *rollbacker, bool &dirty_info, bool &dirty_big_info) { dout(10) << "merge_log " << olog << " from osd." << fromosd << " into " << log << dendl; // Check preconditions // If our log is empty, the incoming log needs to have not been trimmed. assert(!log.null() || olog.tail == eversion_t()); // The logs must overlap. assert(log.head >= olog.tail && olog.head >= log.tail); for (map::iterator i = missing.missing.begin(); i != missing.missing.end(); ++i) { dout(20) << "pg_missing_t sobject: " << i->first << dendl; } bool changed = false; // extend on tail? // this is just filling in history. it does not affect our // missing set, as that should already be consistent with our // current log. if (olog.tail < log.tail) { dout(10) << "merge_log extending tail to " << olog.tail << dendl; list::iterator from = olog.log.begin(); list::iterator to; eversion_t last; for (to = from; to != olog.log.end(); ++to) { if (to->version > log.tail) break; log.index(*to); dout(15) << *to << dendl; last = to->version; } mark_dirty_to(last); // splice into our log. log.log.splice(log.log.begin(), olog.log, from, to); info.log_tail = log.tail = olog.tail; changed = true; } if (oinfo.stats.reported_seq < info.stats.reported_seq || // make sure reported always increases oinfo.stats.reported_epoch < info.stats.reported_epoch) { oinfo.stats.reported_seq = info.stats.reported_seq; oinfo.stats.reported_epoch = info.stats.reported_epoch; } if (info.last_backfill.is_max()) info.stats = oinfo.stats; info.hit_set = oinfo.hit_set; // do we have divergent entries to throw out? if (olog.head < log.head) { rewind_divergent_log(t, olog.head, info, rollbacker, dirty_info, dirty_big_info); changed = true; } // extend on head? if (olog.head > log.head) { dout(10) << "merge_log extending head to " << olog.head << dendl; // find start point in olog list::iterator to = olog.log.end(); list::iterator from = olog.log.end(); eversion_t lower_bound = olog.tail; while (1) { if (from == olog.log.begin()) break; --from; dout(20) << " ? " << *from << dendl; if (from->version <= log.head) { dout(20) << "merge_log cut point (usually last shared) is " << *from << dendl; lower_bound = from->version; ++from; break; } } mark_dirty_from(lower_bound); // index, update missing, delete deleted for (list::iterator p = from; p != to; ++p) { pg_log_entry_t &ne = *p; dout(20) << "merge_log " << ne << dendl; log.index(ne); if (ne.soid <= info.last_backfill) { missing.add_next_event(ne); if (ne.is_delete()) rollbacker->remove(ne.soid); } } // move aside divergent items list divergent; while (!log.empty()) { pg_log_entry_t &oe = *log.log.rbegin(); /* * look at eversion.version here. we want to avoid a situation like: * our log: 100'10 (0'0) m 10000004d3a.00000000/head by client4225.1:18529 * new log: 122'10 (0'0) m 10000004d3a.00000000/head by client4225.1:18529 * lower_bound = 100'9 * i.e, same request, different version. If the eversion.version is > the * lower_bound, we it is divergent. */ if (oe.version.version <= lower_bound.version) break; dout(10) << "merge_log divergent " << oe << dendl; divergent.push_front(oe); log.log.pop_back(); } // splice log.log.splice(log.log.end(), olog.log, from, to); log.index(); info.last_update = log.head = olog.head; info.last_user_version = oinfo.last_user_version; info.purged_snaps = oinfo.purged_snaps; map new_priors; _merge_divergent_entries( log, divergent, info, log.can_rollback_to, missing, &new_priors, rollbacker); for (map::iterator i = new_priors.begin(); i != new_priors.end(); ++i) { add_divergent_prior( i->first, i->second); } // We cannot rollback into the new log entries log.can_rollback_to = log.head; changed = true; } dout(10) << "merge_log result " << log << " " << missing << " changed=" << changed << dendl; if (changed) { dirty_info = true; dirty_big_info = true; } } void PGLog::check() { if (!pg_log_debug) return; if (log.log.size() != log_keys_debug.size()) { derr << "log.log.size() != log_keys_debug.size()" << dendl; derr << "actual log:" << dendl; for (list::iterator i = log.log.begin(); i != log.log.end(); ++i) { derr << " " << *i << dendl; } derr << "log_keys_debug:" << dendl; for (set::const_iterator i = log_keys_debug.begin(); i != log_keys_debug.end(); ++i) { derr << " " << *i << dendl; } } assert(log.log.size() == log_keys_debug.size()); for (list::iterator i = log.log.begin(); i != log.log.end(); ++i) { assert(log_keys_debug.count(i->get_key_name())); } } void PGLog::write_log( ObjectStore::Transaction& t, const hobject_t &log_oid) { if (is_dirty()) { dout(10) << "write_log with: " << "dirty_to: " << dirty_to << ", dirty_from: " << dirty_from << ", dirty_divergent_priors: " << dirty_divergent_priors << ", writeout_from: " << writeout_from << ", trimmed: " << trimmed << dendl; _write_log( t, log, log_oid, divergent_priors, dirty_to, dirty_from, writeout_from, trimmed, dirty_divergent_priors, !touched_log, (pg_log_debug ? &log_keys_debug : 0)); undirty(); } else { dout(10) << "log is not dirty" << dendl; } } void PGLog::write_log(ObjectStore::Transaction& t, pg_log_t &log, const hobject_t &log_oid, map &divergent_priors) { _write_log( t, log, log_oid, divergent_priors, eversion_t::max(), eversion_t(), eversion_t(), set(), true, true, 0); } void PGLog::_write_log( ObjectStore::Transaction& t, pg_log_t &log, const hobject_t &log_oid, map &divergent_priors, eversion_t dirty_to, eversion_t dirty_from, eversion_t writeout_from, const set &trimmed, bool dirty_divergent_priors, bool touch_log, set *log_keys_debug ) { set to_remove; for (set::const_iterator i = trimmed.begin(); i != trimmed.end(); ++i) { to_remove.insert(i->get_key_name()); if (log_keys_debug) { assert(log_keys_debug->count(i->get_key_name())); log_keys_debug->erase(i->get_key_name()); } } //dout(10) << "write_log, clearing up to " << dirty_to << dendl; if (touch_log) t.touch(coll_t(), log_oid); if (dirty_to != eversion_t()) { t.omap_rmkeyrange( coll_t(), log_oid, eversion_t().get_key_name(), dirty_to.get_key_name()); clear_up_to(log_keys_debug, dirty_to.get_key_name()); } if (dirty_to != eversion_t::max() && dirty_from != eversion_t::max()) { // dout(10) << "write_log, clearing from " << dirty_from << dendl; t.omap_rmkeyrange( coll_t(), log_oid, dirty_from.get_key_name(), eversion_t::max().get_key_name()); clear_after(log_keys_debug, dirty_from.get_key_name()); } map keys; for (list::iterator p = log.log.begin(); p != log.log.end() && p->version <= dirty_to; ++p) { bufferlist bl(sizeof(*p) * 2); p->encode_with_checksum(bl); keys[p->get_key_name()].claim(bl); } for (list::reverse_iterator p = log.log.rbegin(); p != log.log.rend() && (p->version >= dirty_from || p->version >= writeout_from) && p->version >= dirty_to; ++p) { bufferlist bl(sizeof(*p) * 2); p->encode_with_checksum(bl); keys[p->get_key_name()].claim(bl); } if (log_keys_debug) { for (map::iterator i = keys.begin(); i != keys.end(); ++i) { assert(!log_keys_debug->count(i->first)); log_keys_debug->insert(i->first); } } if (dirty_divergent_priors) { //dout(10) << "write_log: writing divergent_priors" << dendl; ::encode(divergent_priors, keys["divergent_priors"]); } ::encode(log.can_rollback_to, keys["can_rollback_to"]); ::encode(log.rollback_info_trimmed_to, keys["rollback_info_trimmed_to"]); t.omap_rmkeys(coll_t::META_COLL, log_oid, to_remove); t.omap_setkeys(coll_t::META_COLL, log_oid, keys); } bool PGLog::read_log(ObjectStore *store, coll_t coll, hobject_t log_oid, const pg_info_t &info, map &divergent_priors, IndexedLog &log, pg_missing_t &missing, ostringstream &oss, set *log_keys_debug) { dout(10) << "read_log" << dendl; bool rewrite_log = false; // legacy? struct stat st; int r = store->stat(coll_t::META_COLL, log_oid, &st); assert(r == 0); if (st.st_size > 0) { read_log_old(store, coll, log_oid, info, divergent_priors, log, missing, oss, log_keys_debug); rewrite_log = true; } else { log.tail = info.log_tail; // will get overridden below if it had been recorded log.can_rollback_to = info.last_update; log.rollback_info_trimmed_to = eversion_t(); ObjectMap::ObjectMapIterator p = store->get_omap_iterator(coll_t::META_COLL, log_oid); if (p) for (p->seek_to_first(); p->valid() ; p->next()) { bufferlist bl = p->value();//Copy bufferlist before creating iterator bufferlist::iterator bp = bl.begin(); if (p->key() == "divergent_priors") { ::decode(divergent_priors, bp); dout(20) << "read_log " << divergent_priors.size() << " divergent_priors" << dendl; } else if (p->key() == "can_rollback_to") { bufferlist bl = p->value(); bufferlist::iterator bp = bl.begin(); ::decode(log.can_rollback_to, bp); } else if (p->key() == "rollback_info_trimmed_to") { bufferlist bl = p->value(); bufferlist::iterator bp = bl.begin(); ::decode(log.rollback_info_trimmed_to, bp); } else { pg_log_entry_t e; e.decode_with_checksum(bp); dout(20) << "read_log " << e << dendl; if (!log.log.empty()) { pg_log_entry_t last_e(log.log.back()); assert(last_e.version.version < e.version.version); assert(last_e.version.epoch <= e.version.epoch); } log.log.push_back(e); log.head = e.version; if (log_keys_debug) log_keys_debug->insert(e.get_key_name()); } } } log.head = info.last_update; log.index(); // build missing if (info.last_complete < info.last_update) { dout(10) << "read_log checking for missing items over interval (" << info.last_complete << "," << info.last_update << "]" << dendl; set did; for (list::reverse_iterator i = log.log.rbegin(); i != log.log.rend(); ++i) { if (i->version <= info.last_complete) break; if (i->soid > info.last_backfill) continue; if (did.count(i->soid)) continue; did.insert(i->soid); if (i->is_delete()) continue; bufferlist bv; int r = store->getattr( coll, ghobject_t(i->soid, ghobject_t::NO_GEN, info.pgid.shard), OI_ATTR, bv); if (r >= 0) { object_info_t oi(bv); if (oi.version < i->version) { dout(15) << "read_log missing " << *i << " (have " << oi.version << ")" << dendl; missing.add(i->soid, i->version, oi.version); } } else { dout(15) << "read_log missing " << *i << dendl; missing.add(i->soid, i->version, eversion_t()); } } for (map::reverse_iterator i = divergent_priors.rbegin(); i != divergent_priors.rend(); ++i) { if (i->first <= info.last_complete) break; if (i->second > info.last_backfill) continue; if (did.count(i->second)) continue; did.insert(i->second); bufferlist bv; int r = store->getattr( coll, ghobject_t(i->second, ghobject_t::NO_GEN, info.pgid.shard), OI_ATTR, bv); if (r >= 0) { object_info_t oi(bv); /** * 1) we see this entry in the divergent priors mapping * 2) we didn't see an entry for this object in the log * * From 1 & 2 we know that either the object does not exist * or it is at the version specified in the divergent_priors * map since the object would have been deleted atomically * with the addition of the divergent_priors entry, an older * version would not have been recovered, and a newer version * would show up in the log above. */ assert(oi.version == i->first); } else { dout(15) << "read_log missing " << *i << dendl; missing.add(i->second, i->first, eversion_t()); } } } dout(10) << "read_log done" << dendl; return rewrite_log; } void PGLog::read_log_old(ObjectStore *store, coll_t coll, hobject_t log_oid, const pg_info_t &info, map &divergent_priors, IndexedLog &log, pg_missing_t &missing, ostringstream &oss, set *log_keys_debug) { // load bounds, based on old OndiskLog encoding. uint64_t ondisklog_tail = 0; uint64_t ondisklog_head = 0; uint64_t ondisklog_zero_to; bool ondisklog_has_checksums; bufferlist blb; store->collection_getattr(coll, "ondisklog", blb); { bufferlist::iterator bl = blb.begin(); DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); ondisklog_has_checksums = (struct_v >= 2); ::decode(ondisklog_tail, bl); ::decode(ondisklog_head, bl); if (struct_v >= 4) ::decode(ondisklog_zero_to, bl); else ondisklog_zero_to = 0; if (struct_v >= 5) ::decode(divergent_priors, bl); DECODE_FINISH(bl); } uint64_t ondisklog_length = ondisklog_head - ondisklog_tail; dout(10) << "read_log " << ondisklog_tail << "~" << ondisklog_length << dendl; log.tail = info.log_tail; if (ondisklog_head > 0) { // read bufferlist bl; store->read(coll_t::META_COLL, log_oid, ondisklog_tail, ondisklog_length, bl); if (bl.length() < ondisklog_length) { std::ostringstream oss; oss << "read_log got " << bl.length() << " bytes, expected " << ondisklog_head << "-" << ondisklog_tail << "=" << ondisklog_length; throw read_log_error(oss.str().c_str()); } pg_log_entry_t e; bufferlist::iterator p = bl.begin(); assert(log.empty()); eversion_t last; bool reorder = false; while (!p.end()) { uint64_t pos = ondisklog_tail + p.get_off(); if (ondisklog_has_checksums) { bufferlist ebl; ::decode(ebl, p); __u32 crc; ::decode(crc, p); __u32 got = ebl.crc32c(0); if (crc == got) { bufferlist::iterator q = ebl.begin(); ::decode(e, q); } else { std::ostringstream oss; oss << "read_log " << pos << " bad crc got " << got << " expected" << crc; throw read_log_error(oss.str().c_str()); } } else { ::decode(e, p); } dout(20) << "read_log " << pos << " " << e << dendl; // [repair] in order? if (e.version < last) { dout(0) << "read_log " << pos << " out of order entry " << e << " follows " << last << dendl; oss << info.pgid << " log has out of order entry " << e << " following " << last << "\n"; reorder = true; } if (e.version <= log.tail) { dout(20) << "read_log ignoring entry at " << pos << " below log.tail" << dendl; continue; } if (last.version == e.version.version) { dout(0) << "read_log got dup " << e.version << " (last was " << last << ", dropping that one)" << dendl; log.log.pop_back(); oss << info.pgid << " read_log got dup " << e.version << " after " << last << "\n"; } assert(!e.invalid_hash); if (e.invalid_pool) { e.soid.pool = info.pgid.pool(); } e.offset = pos; uint64_t endpos = ondisklog_tail + p.get_off(); log.log.push_back(e); if (log_keys_debug) log_keys_debug->insert(e.get_key_name()); last = e.version; // [repair] at end of log? if (!p.end() && e.version == info.last_update) { oss << info.pgid << " log has extra data at " << endpos << "~" << (ondisklog_head-endpos) << " after " << info.last_update << "\n"; dout(0) << "read_log " << endpos << " *** extra gunk at end of log, " << "adjusting ondisklog_head" << dendl; ondisklog_head = endpos; break; } } if (reorder) { dout(0) << "read_log reordering log" << dendl; map m; for (list::iterator p = log.log.begin(); p != log.log.end(); ++p) m[p->version] = *p; log.log.clear(); for (map::iterator p = m.begin(); p != m.end(); ++p) log.log.push_back(p->second); } } } ceph-0.80.11/src/osd/ReplicatedBackend.cc0000664000175100017510000004402012623076744022104 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/errno.h" #include "ReplicatedBackend.h" #include "messages/MOSDOp.h" #include "messages/MOSDSubOp.h" #include "messages/MOSDSubOpReply.h" #include "messages/MOSDPGPush.h" #include "messages/MOSDPGPull.h" #include "messages/MOSDPGPushReply.h" #define dout_subsys ceph_subsys_osd #define DOUT_PREFIX_ARGS this #undef dout_prefix #define dout_prefix _prefix(_dout, this) static ostream& _prefix(std::ostream *_dout, ReplicatedBackend *pgb) { return *_dout << pgb->get_parent()->gen_dbg_prefix(); } ReplicatedBackend::ReplicatedBackend( PGBackend::Listener *pg, coll_t coll, coll_t temp_coll, ObjectStore *store, CephContext *cct) : PGBackend(pg, store, coll, temp_coll), cct(cct) {} void ReplicatedBackend::run_recovery_op( PGBackend::RecoveryHandle *_h, int priority) { RPGHandle *h = static_cast(_h); send_pushes(priority, h->pushes); send_pulls(priority, h->pulls); delete h; } void ReplicatedBackend::recover_object( const hobject_t &hoid, eversion_t v, ObjectContextRef head, ObjectContextRef obc, RecoveryHandle *_h ) { dout(10) << __func__ << ": " << hoid << dendl; RPGHandle *h = static_cast(_h); if (get_parent()->get_local_missing().is_missing(hoid)) { assert(!obc); // pull prepare_pull( v, hoid, head, h); return; } else { assert(obc); int started = start_pushes( hoid, obc, h); assert(started > 0); } } void ReplicatedBackend::check_recovery_sources(const OSDMapRef osdmap) { for(map >::iterator i = pull_from_peer.begin(); i != pull_from_peer.end(); ) { if (osdmap->is_down(i->first.osd)) { dout(10) << "check_recovery_sources resetting pulls from osd." << i->first << ", osdmap has it marked down" << dendl; for (set::iterator j = i->second.begin(); j != i->second.end(); ++j) { assert(pulling.count(*j) == 1); get_parent()->cancel_pull(*j); pulling.erase(*j); } pull_from_peer.erase(i++); } else { ++i; } } } bool ReplicatedBackend::can_handle_while_inactive(OpRequestRef op) { dout(10) << __func__ << ": " << op << dendl; switch (op->get_req()->get_type()) { case MSG_OSD_PG_PULL: return true; case MSG_OSD_SUBOP: { MOSDSubOp *m = static_cast(op->get_req()); if (m->ops.size() >= 1) { OSDOp *first = &m->ops[0]; switch (first->op.op) { case CEPH_OSD_OP_PULL: return true; default: return false; } } else { return false; } } default: return false; } } bool ReplicatedBackend::handle_message( OpRequestRef op ) { dout(10) << __func__ << ": " << op << dendl; switch (op->get_req()->get_type()) { case MSG_OSD_PG_PUSH: do_push(op); return true; case MSG_OSD_PG_PULL: do_pull(op); return true; case MSG_OSD_PG_PUSH_REPLY: do_push_reply(op); return true; case MSG_OSD_SUBOP: { MOSDSubOp *m = static_cast(op->get_req()); if (m->ops.size() >= 1) { OSDOp *first = &m->ops[0]; switch (first->op.op) { case CEPH_OSD_OP_PULL: sub_op_pull(op); return true; case CEPH_OSD_OP_PUSH: sub_op_push(op); return true; default: break; } } else { sub_op_modify(op); } break; } case MSG_OSD_SUBOPREPLY: { MOSDSubOpReply *r = static_cast(op->get_req()); if (r->ops.size() >= 1) { OSDOp &first = r->ops[0]; switch (first.op.op) { case CEPH_OSD_OP_PUSH: // continue peer recovery sub_op_push_reply(op); return true; } } else { sub_op_modify_reply(op); } break; } default: break; } return false; } void ReplicatedBackend::clear_state() { // clear pushing/pulling maps pushing.clear(); pulling.clear(); pull_from_peer.clear(); } void ReplicatedBackend::on_change() { dout(10) << __func__ << dendl; for (map::iterator i = in_progress_ops.begin(); i != in_progress_ops.end(); in_progress_ops.erase(i++)) { if (i->second.on_commit) delete i->second.on_commit; if (i->second.on_applied) delete i->second.on_applied; } clear_state(); } void ReplicatedBackend::on_flushed() { if (have_temp_coll() && !store->collection_empty(get_temp_coll())) { vector objects; store->collection_list(get_temp_coll(), objects); derr << __func__ << ": found objects in the temp collection: " << objects << ", crashing now" << dendl; assert(0 == "found garbage in the temp collection"); } } int ReplicatedBackend::objects_read_sync( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist *bl) { return store->read(coll, hoid, off, len, *bl); } struct AsyncReadCallback : public GenContext { int r; Context *c; AsyncReadCallback(int r, Context *c) : r(r), c(c) {} void finish(ThreadPool::TPHandle&) { c->complete(r); c = NULL; } ~AsyncReadCallback() { delete c; } }; void ReplicatedBackend::objects_read_async( const hobject_t &hoid, const list, pair > > &to_read, Context *on_complete) { int r = 0; for (list, pair > >::const_iterator i = to_read.begin(); i != to_read.end() && r >= 0; ++i) { int _r = store->read(coll, hoid, i->first.first, i->first.second, *(i->second.first)); if (i->second.second) { get_parent()->schedule_work( get_parent()->bless_gencontext( new AsyncReadCallback(_r, i->second.second))); } if (_r < 0) r = _r; } get_parent()->schedule_work( get_parent()->bless_gencontext( new AsyncReadCallback(r, on_complete))); } class RPGTransaction : public PGBackend::PGTransaction { coll_t coll; coll_t temp_coll; set temp_added; set temp_cleared; ObjectStore::Transaction *t; const coll_t &get_coll_ct(const hobject_t &hoid) { if (hoid.is_temp()) { temp_cleared.erase(hoid); temp_added.insert(hoid); } return get_coll(hoid); } const coll_t &get_coll_rm(const hobject_t &hoid) { if (hoid.is_temp()) { temp_added.erase(hoid); temp_cleared.insert(hoid); } return get_coll(hoid); } const coll_t &get_coll(const hobject_t &hoid) { if (hoid.is_temp()) return temp_coll; else return coll; } public: RPGTransaction(coll_t coll, coll_t temp_coll) : coll(coll), temp_coll(temp_coll), t(new ObjectStore::Transaction) {} /// Yields ownership of contained transaction ObjectStore::Transaction *get_transaction() { ObjectStore::Transaction *_t = t; t = 0; return _t; } const set &get_temp_added() { return temp_added; } const set &get_temp_cleared() { return temp_cleared; } void write( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist &bl ) { t->write(get_coll_ct(hoid), hoid, off, len, bl); } void remove( const hobject_t &hoid ) { t->remove(get_coll_rm(hoid), hoid); } void stash( const hobject_t &hoid, version_t former_version) { t->collection_move_rename( coll, hoid, coll, ghobject_t(hoid, former_version, ghobject_t::NO_SHARD)); } void setattrs( const hobject_t &hoid, map &attrs ) { t->setattrs(get_coll(hoid), hoid, attrs); } void setattr( const hobject_t &hoid, const string &attrname, bufferlist &bl ) { t->setattr(get_coll(hoid), hoid, attrname, bl); } void rmattr( const hobject_t &hoid, const string &attrname ) { t->rmattr(get_coll(hoid), hoid, attrname); } void omap_setkeys( const hobject_t &hoid, map &keys ) { return t->omap_setkeys(get_coll(hoid), hoid, keys); } void omap_rmkeys( const hobject_t &hoid, set &keys ) { t->omap_rmkeys(get_coll(hoid), hoid, keys); } void omap_clear( const hobject_t &hoid ) { t->omap_clear(get_coll(hoid), hoid); } void omap_setheader( const hobject_t &hoid, bufferlist &header ) { t->omap_setheader(get_coll(hoid), hoid, header); } void clone_range( const hobject_t &from, const hobject_t &to, uint64_t fromoff, uint64_t len, uint64_t tooff ) { assert(get_coll(from) == get_coll_ct(to) && get_coll(from) == coll); t->clone_range(coll, from, to, fromoff, len, tooff); } void clone( const hobject_t &from, const hobject_t &to ) { assert(get_coll(from) == get_coll_ct(to) && get_coll(from) == coll); t->clone(coll, from, to); } void rename( const hobject_t &from, const hobject_t &to ) { t->collection_move_rename( get_coll_rm(from), from, get_coll_ct(to), to); } void touch( const hobject_t &hoid ) { t->touch(get_coll_ct(hoid), hoid); } void truncate( const hobject_t &hoid, uint64_t off ) { t->truncate(get_coll(hoid), hoid, off); } void zero( const hobject_t &hoid, uint64_t off, uint64_t len ) { t->zero(get_coll(hoid), hoid, off, len); } void set_alloc_hint( const hobject_t &hoid, uint64_t expected_object_size, uint64_t expected_write_size ) { t->set_alloc_hint(get_coll(hoid), hoid, expected_object_size, expected_write_size); } void append( PGTransaction *_to_append ) { RPGTransaction *to_append = dynamic_cast(_to_append); assert(to_append); t->append(*(to_append->t)); for (set::iterator i = to_append->temp_added.begin(); i != to_append->temp_added.end(); ++i) { temp_cleared.erase(*i); temp_added.insert(*i); } for (set::iterator i = to_append->temp_cleared.begin(); i != to_append->temp_cleared.end(); ++i) { temp_added.erase(*i); temp_cleared.insert(*i); } } void nop() { t->nop(); } bool empty() const { return t->empty(); } uint64_t get_bytes_written() const { return t->get_encoded_bytes(); } ~RPGTransaction() { delete t; } }; PGBackend::PGTransaction *ReplicatedBackend::get_transaction() { return new RPGTransaction(coll, get_temp_coll()); } class C_OSD_OnOpCommit : public Context { ReplicatedBackend *pg; ReplicatedBackend::InProgressOp *op; public: C_OSD_OnOpCommit(ReplicatedBackend *pg, ReplicatedBackend::InProgressOp *op) : pg(pg), op(op) {} void finish(int) { pg->op_commit(op); } }; class C_OSD_OnOpApplied : public Context { ReplicatedBackend *pg; ReplicatedBackend::InProgressOp *op; public: C_OSD_OnOpApplied(ReplicatedBackend *pg, ReplicatedBackend::InProgressOp *op) : pg(pg), op(op) {} void finish(int) { pg->op_applied(op); } }; void ReplicatedBackend::submit_transaction( const hobject_t &soid, const eversion_t &at_version, PGTransaction *_t, const eversion_t &trim_to, const eversion_t &trim_rollback_to, vector &log_entries, boost::optional &hset_history, Context *on_local_applied_sync, Context *on_all_acked, Context *on_all_commit, ceph_tid_t tid, osd_reqid_t reqid, OpRequestRef orig_op) { RPGTransaction *t = dynamic_cast(_t); assert(t); ObjectStore::Transaction *op_t = t->get_transaction(); assert(t->get_temp_added().size() <= 1); assert(t->get_temp_cleared().size() <= 1); assert(!in_progress_ops.count(tid)); InProgressOp &op = in_progress_ops.insert( make_pair( tid, InProgressOp( tid, on_all_commit, on_all_acked, orig_op, at_version) ) ).first->second; op.waiting_for_applied.insert( parent->get_actingbackfill_shards().begin(), parent->get_actingbackfill_shards().end()); op.waiting_for_commit.insert( parent->get_actingbackfill_shards().begin(), parent->get_actingbackfill_shards().end()); issue_op( soid, at_version, tid, reqid, trim_to, trim_rollback_to, t->get_temp_added().size() ? *(t->get_temp_added().begin()) : hobject_t(), t->get_temp_cleared().size() ? *(t->get_temp_cleared().begin()) :hobject_t(), log_entries, hset_history, &op, op_t); ObjectStore::Transaction local_t; if (t->get_temp_added().size()) { get_temp_coll(&local_t); add_temp_objs(t->get_temp_added()); } clear_temp_objs(t->get_temp_cleared()); parent->log_operation( log_entries, hset_history, trim_to, trim_rollback_to, true, &local_t); local_t.append(*op_t); local_t.swap(*op_t); op_t->register_on_applied_sync(on_local_applied_sync); op_t->register_on_applied( parent->bless_context( new C_OSD_OnOpApplied(this, &op))); op_t->register_on_applied( new ObjectStore::C_DeleteTransaction(op_t)); op_t->register_on_commit( parent->bless_context( new C_OSD_OnOpCommit(this, &op))); parent->queue_transaction(op_t, op.op); delete t; } void ReplicatedBackend::op_applied( InProgressOp *op) { dout(10) << __func__ << ": " << op->tid << dendl; if (op->op) op->op->mark_event("op_applied"); op->waiting_for_applied.erase(get_parent()->whoami_shard()); parent->op_applied(op->v); if (op->waiting_for_applied.empty()) { op->on_applied->complete(0); op->on_applied = 0; } if (op->done()) { assert(!op->on_commit && !op->on_applied); in_progress_ops.erase(op->tid); } } void ReplicatedBackend::op_commit( InProgressOp *op) { dout(10) << __func__ << ": " << op->tid << dendl; if (op->op) op->op->mark_event("op_commit"); op->waiting_for_commit.erase(get_parent()->whoami_shard()); if (op->waiting_for_commit.empty()) { op->on_commit->complete(0); op->on_commit = 0; } if (op->done()) { assert(!op->on_commit && !op->on_applied); in_progress_ops.erase(op->tid); } } void ReplicatedBackend::sub_op_modify_reply(OpRequestRef op) { MOSDSubOpReply *r = static_cast(op->get_req()); assert(r->get_header().type == MSG_OSD_SUBOPREPLY); op->mark_started(); // must be replication. ceph_tid_t rep_tid = r->get_tid(); pg_shard_t from = r->from; if (in_progress_ops.count(rep_tid)) { map::iterator iter = in_progress_ops.find(rep_tid); InProgressOp &ip_op = iter->second; MOSDOp *m = NULL; if (ip_op.op) m = static_cast(ip_op.op->get_req()); if (m) dout(7) << __func__ << ": tid " << ip_op.tid << " op " //<< *m << " ack_type " << (int)r->ack_type << " from " << from << dendl; else dout(7) << __func__ << ": tid " << ip_op.tid << " (no op) " << " ack_type " << (int)r->ack_type << " from " << from << dendl; // oh, good. if (r->ack_type & CEPH_OSD_FLAG_ONDISK) { assert(ip_op.waiting_for_commit.count(from)); ip_op.waiting_for_commit.erase(from); if (ip_op.op) ip_op.op->mark_event("sub_op_commit_rec"); } else { assert(ip_op.waiting_for_applied.count(from)); if (ip_op.op) ip_op.op->mark_event("sub_op_applied_rec"); } ip_op.waiting_for_applied.erase(from); parent->update_peer_last_complete_ondisk( from, r->get_last_complete_ondisk()); if (ip_op.waiting_for_applied.empty() && ip_op.on_applied) { ip_op.on_applied->complete(0); ip_op.on_applied = 0; } if (ip_op.waiting_for_commit.empty() && ip_op.on_commit) { ip_op.on_commit->complete(0); ip_op.on_commit= 0; } if (ip_op.done()) { assert(!ip_op.on_commit && !ip_op.on_applied); in_progress_ops.erase(iter); } } } void ReplicatedBackend::be_deep_scrub( const hobject_t &poid, ScrubMap::object &o, ThreadPool::TPHandle &handle) { bufferhash h, oh; bufferlist bl, hdrbl; int r; __u64 pos = 0; while ( (r = store->read( coll, ghobject_t( poid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), pos, cct->_conf->osd_deep_scrub_stride, bl, true)) > 0) { handle.reset_tp_timeout(); h << bl; pos += bl.length(); bl.clear(); } if (r == -EIO) { dout(25) << "_scan_list " << poid << " got " << r << " on read, read_error" << dendl; o.read_error = true; } o.digest = h.digest(); o.digest_present = true; bl.clear(); r = store->omap_get_header( coll, ghobject_t( poid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), &hdrbl, true); if (r == 0) { dout(25) << "CRC header " << string(hdrbl.c_str(), hdrbl.length()) << dendl; ::encode(hdrbl, bl); oh << bl; bl.clear(); } else if (r == -EIO) { dout(25) << "_scan_list " << poid << " got " << r << " on omap header read, read_error" << dendl; o.read_error = true; } ObjectMap::ObjectMapIterator iter = store->get_omap_iterator( coll, ghobject_t( poid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); assert(iter); uint64_t keys_scanned = 0; for (iter->seek_to_first(); iter->valid() ; iter->next()) { if (cct->_conf->osd_scan_list_ping_tp_interval && (keys_scanned % cct->_conf->osd_scan_list_ping_tp_interval == 0)) { handle.reset_tp_timeout(); } ++keys_scanned; dout(25) << "CRC key " << iter->key() << " value " << string(iter->value().c_str(), iter->value().length()) << dendl; ::encode(iter->key(), bl); ::encode(iter->value(), bl); oh << bl; bl.clear(); } if (iter->status() == -EIO) { dout(25) << "_scan_list " << poid << " got " << r << " on omap scan, read_error" << dendl; o.read_error = true; } //Store final calculated CRC32 of omap header & key/values o.omap_digest = oh.digest(); o.omap_digest_present = true; } ceph-0.80.11/src/osd/Makefile.am0000664000175100017510000000205612623076744020310 0ustar jenkins-buildjenkins-buildlibosd_types_la_SOURCES = \ osd/PGLog.cc \ osd/osd_types.cc \ osd/ECUtil.cc libosd_types_la_CXXFLAGS = ${AM_CXXFLAGS} noinst_LTLIBRARIES += libosd_types.la libosd_la_SOURCES = \ osd/PG.cc \ osd/ReplicatedPG.cc \ osd/ReplicatedBackend.cc \ osd/ECBackend.cc \ osd/ECMsgTypes.cc \ osd/ECTransaction.cc \ osd/PGBackend.cc \ osd/Ager.cc \ osd/HitSet.cc \ osd/OSD.cc \ osd/OSDCap.cc \ osd/Watch.cc \ osd/ClassHandler.cc \ osd/OpRequest.cc \ common/TrackedOp.cc \ osd/SnapMapper.cc \ objclass/class_api.cc libosd_la_CXXFLAGS = ${AM_CXXFLAGS} libosd_la_LIBADD = $(LIBOSDC) $(LIBOS) $(LIBOSD_TYPES) $(LIBOS_TYPES) noinst_LTLIBRARIES += libosd.la noinst_HEADERS += \ osd/Ager.h \ osd/ClassHandler.h \ osd/HitSet.h \ osd/OSD.h \ osd/OSDCap.h \ osd/OSDMap.h \ osd/ObjectVersioner.h \ osd/OpRequest.h \ osd/SnapMapper.h \ osd/PG.h \ osd/PGLog.h \ osd/ReplicatedPG.h \ osd/PGBackend.h \ osd/ReplicatedBackend.h \ osd/TierAgentState.h \ osd/ECBackend.h \ osd/ECUtil.h \ osd/ECMsgTypes.h \ osd/ECTransaction.h \ osd/Watch.h \ osd/osd_types.h ceph-0.80.11/src/osd/ECUtil.cc0000664000175100017510000001171312623076744017710 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include #include "include/encoding.h" #include "ECUtil.h" int ECUtil::decode( const stripe_info_t &sinfo, ErasureCodeInterfaceRef &ec_impl, map &to_decode, bufferlist *out) { uint64_t total_chunk_size = to_decode.begin()->second.length(); assert(to_decode.size()); assert(total_chunk_size % sinfo.get_chunk_size() == 0); assert(out); assert(out->length() == 0); for (map::iterator i = to_decode.begin(); i != to_decode.end(); ++i) { assert(i->second.length() == total_chunk_size); } if (total_chunk_size == 0) return 0; for (uint64_t i = 0; i < total_chunk_size; i += sinfo.get_chunk_size()) { map chunks; for (map::iterator j = to_decode.begin(); j != to_decode.end(); ++j) { chunks[j->first].substr_of(j->second, i, sinfo.get_chunk_size()); } bufferlist bl; int r = ec_impl->decode_concat(chunks, &bl); assert(bl.length() == sinfo.get_stripe_width()); assert(r == 0); out->claim_append(bl); } return 0; } int ECUtil::decode( const stripe_info_t &sinfo, ErasureCodeInterfaceRef &ec_impl, map &to_decode, map &out) { uint64_t total_chunk_size = to_decode.begin()->second.length(); assert(to_decode.size()); assert(total_chunk_size % sinfo.get_chunk_size() == 0); for (map::iterator i = to_decode.begin(); i != to_decode.end(); ++i) { assert(i->second.length() == total_chunk_size); } if (total_chunk_size == 0) return 0; set need; for (map::iterator i = out.begin(); i != out.end(); ++i) { assert(i->second); assert(i->second->length() == 0); need.insert(i->first); } for (uint64_t i = 0; i < total_chunk_size; i += sinfo.get_chunk_size()) { map chunks; for (map::iterator j = to_decode.begin(); j != to_decode.end(); ++j) { chunks[j->first].substr_of(j->second, i, sinfo.get_chunk_size()); } map out_bls; int r = ec_impl->decode(need, chunks, &out_bls); assert(r == 0); for (map::iterator j = out.begin(); j != out.end(); ++j) { assert(out_bls.count(j->first)); assert(out_bls[j->first].length() == sinfo.get_chunk_size()); j->second->claim_append(out_bls[j->first]); } } for (map::iterator i = out.begin(); i != out.end(); ++i) { assert(i->second->length() == total_chunk_size); } return 0; } int ECUtil::encode( const stripe_info_t &sinfo, ErasureCodeInterfaceRef &ec_impl, bufferlist &in, const set &want, map *out) { uint64_t logical_size = in.length(); assert(logical_size % sinfo.get_stripe_width() == 0); assert(out); assert(out->empty()); if (logical_size == 0) return 0; for (uint64_t i = 0; i < logical_size; i += sinfo.get_stripe_width()) { map encoded; bufferlist buf; buf.substr_of(in, i, sinfo.get_stripe_width()); int r = ec_impl->encode(want, buf, &encoded); assert(r == 0); for (map::iterator i = encoded.begin(); i != encoded.end(); ++i) { assert(i->second.length() == sinfo.get_chunk_size()); (*out)[i->first].claim_append(i->second); } } for (map::iterator i = out->begin(); i != out->end(); ++i) { assert(i->second.length() % sinfo.get_chunk_size() == 0); assert( sinfo.aligned_chunk_offset_to_logical_offset(i->second.length()) == logical_size); } return 0; } void ECUtil::HashInfo::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(total_chunk_size, bl); ::encode(cumulative_shard_hashes, bl); ENCODE_FINISH(bl); } void ECUtil::HashInfo::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(total_chunk_size, bl); ::decode(cumulative_shard_hashes, bl); DECODE_FINISH(bl); } void ECUtil::HashInfo::dump(Formatter *f) const { f->dump_unsigned("total_chunk_size", total_chunk_size); f->open_object_section("cumulative_shard_hashes"); for (unsigned i = 0; i != cumulative_shard_hashes.size(); ++i) { f->open_object_section("hash"); f->dump_unsigned("shard", i); f->dump_unsigned("hash", cumulative_shard_hashes[i]); f->close_section(); } f->close_section(); } void ECUtil::HashInfo::generate_test_instances(list& o) { o.push_back(new HashInfo(3)); { bufferlist bl; bl.append_zero(20); map buffers; buffers[0] = bl; buffers[1] = bl; buffers[2] = bl; o.back()->append(0, buffers); o.back()->append(20, buffers); } o.push_back(new HashInfo(4)); } const string HINFO_KEY = "hinfo_key"; bool ECUtil::is_hinfo_key_string(const string &key) { return key == HINFO_KEY; } const string &ECUtil::get_hinfo_key() { return HINFO_KEY; } ceph-0.80.11/src/osd/Ager.cc0000664000175100017510000001531712623076744017445 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "Ager.h" #include "os/ObjectStore.h" #include "common/Clock.h" #include "common/debug.h" // ick #include #include #include #if defined(DARWIN) || defined(__FreeBSD__) #include #include #endif // DARWIN || __FreeBSD__ int myrand() { if (0) return rand(); else { static int n = 0; srand(n++); return rand(); } } file_object_t Ager::age_get_oid() { if (!age_free_oids.empty()) { file_object_t o = age_free_oids.front(); age_free_oids.pop_front(); return o; } file_object_t last = age_cur_oid; ++age_cur_oid.bno; return last; } ssize_t Ager::age_pick_size() { ssize_t max = file_size_distn.sample() * 1024; return max/2 + (myrand() % 100) * max/200 + 1; } bool start_debug = false; uint64_t Ager::age_fill(float pc, utime_t until) { int max = 1024*1024; bufferptr bp(max); bp.zero(); bufferlist bl; bl.push_back(bp); uint64_t wrote = 0; while (1) { if (ceph_clock_now(cct) > until) break; struct statfs st; store->statfs(&st); float free = 1.0 - ((float)(st.f_bfree) / (float)st.f_blocks); float avail = 1.0 - ((float)(st.f_bavail) / (float)st.f_blocks); // to write to //float a = (float)(st.f_bfree) / (float)st.f_blocks; //dout(10) << "age_fill at " << a << " / " << pc << " .. " << st.f_blocks << " " << st.f_bavail << dendl; if (free >= pc) { generic_dout(2) << "age_fill at " << free << " / " << avail << " / " << " / " << pc << " stopping" << dendl; break; } // make sure we can write to it.. if (avail > .98 || avail - free > .02) store->sync(); file_object_t poid = age_get_oid(); int b = myrand() % 10; age_objects[b].push_back(poid); ssize_t s = age_pick_size(); wrote += (s + 4095) / 4096; generic_dout(2) << "age_fill at " << free << " / " << avail << " / " << pc << " creating " << hex << poid << dec << " sz " << s << dendl; if (false && start_debug && wrote > 1000000ULL) { /* 1005700 ? 1005000 1005700 1005710 1005725ULL 1005750ULL 1005800 1006000 // 99 1000500 ? 1000750 1006000 */ } off_t off = 0; while (s) { ssize_t t = MIN(s, max); bufferlist sbl; sbl.substr_of(bl, 0, t); ObjectStore::Transaction tr; hobject_t oid(sobject_t(poid, 0)); tr.write(coll_t(), oid, off, t, sbl); store->apply_transaction(tr); off += t; s -= t; } poid.bno++; } return wrote*4; // KB } void Ager::age_empty(float pc) { int nper = 20; int n = nper; while (1) { struct statfs st; store->statfs(&st); float free = 1.0 - ((float)(st.f_bfree) / (float)st.f_blocks); float avail = 1.0 - ((float)(st.f_bavail) / (float)st.f_blocks); // to write to generic_dout(2) << "age_empty at " << free << " / " << avail << " / " << pc << dendl;//" stopping" << dendl; if (free <= pc) { generic_dout(2) << "age_empty at " << free << " / " << avail << " / " << pc << " stopping" << dendl; break; } int b = myrand() % 10; n--; if (n == 0 || age_objects[b].empty()) { generic_dout(2) << "age_empty sync" << dendl; //sync(); //sync(); n = nper; continue; } file_object_t poid = age_objects[b].front(); age_objects[b].pop_front(); generic_dout(2) << "age_empty at " << free << " / " << avail << " / " << pc << " removing " << hex << poid << dec << dendl; ObjectStore::Transaction t; hobject_t oid(sobject_t(poid, 0)); t.remove(coll_t(), oid); store->apply_transaction(t); age_free_oids.push_back(poid); } } void Ager::age(int time, float high_water, // fill to this % float low_water, // then empty to this % int count, // this many times float final_water, // and end here ( <= low_water) int fake_size_mb) { srand(0); utime_t start = ceph_clock_now(cct); utime_t until = start; until.sec_ref() += time; //int elapsed = 0; int freelist_inc = 60; utime_t nextfl = start; nextfl.sec_ref() += freelist_inc; while (age_objects.size() < 10) age_objects.push_back( list() ); if (fake_size_mb) { int fake_bl = fake_size_mb * 256; struct statfs st; store->statfs(&st); float f = (float)fake_bl / (float)st.f_blocks; high_water = (float)high_water * f; low_water = (float)low_water * f; final_water = (float)final_water * f; generic_dout(2) << "fake " << fake_bl << " / " << st.f_blocks << " is " << f << ", high " << high_water << " low " << low_water << " final " << final_water << dendl; } // init size distn (once) if (!did_distn) { did_distn = true; age_cur_oid = file_object_t(888, 0); file_size_distn.add(1, 19.0758125+0.65434375); file_size_distn.add(512, 35.6566); file_size_distn.add(1024, 27.7271875); file_size_distn.add(2*1024, 16.63503125); //file_size_distn.add(4*1024, 106.82384375); //file_size_distn.add(8*1024, 81.493375); //file_size_distn.add(16*1024, 14.13553125); //file_size_distn.add(32*1024, 2.176); //file_size_distn.add(256*1024, 0.655938); //file_size_distn.add(512*1024, 0.1480625); //file_size_distn.add(1*1024*1024, 0.020125); // actually 2, but 32bit file_size_distn.normalize(); } // clear for (int i=0; i<10; i++) age_objects[i].clear(); uint64_t wrote = 0; for (int c=1; c<=count; c++) { if (ceph_clock_now(cct) > until) break; //if (c == 7) start_debug = true; generic_dout(1) << "#age " << c << "/" << count << " filling to " << high_water << dendl; uint64_t w = age_fill(high_water, until); //dout(1) << "age wrote " << w << dendl; wrote += w; //store->sync(); //store->_get_frag_stat(st); //pfrag(st); if (c == count) { generic_dout(1) << "#age final empty to " << final_water << dendl; age_empty(final_water); } else { generic_dout(1) << "#age " << c << "/" << count << " emptying to " << low_water << dendl; age_empty(low_water); } //store->sync(); //store->sync(); // show frag state /*store->_get_frag_stat(st); pfrag(wrote / (1024ULL*1024ULL) , // GB st);*/ // dump freelist? /* if (ceph_clock_now(cct) > nextfl) { elapsed += freelist_inc; save_freelist(elapsed); nextfl.sec_ref() += freelist_inc; } */ } // dump the freelist //save_freelist(0); exit(0); // hack // ok! store->sync(); store->sync(); generic_dout(1) << "age finished" << dendl; } ceph-0.80.11/src/osd/ECMsgTypes.h0000664000175100017510000000647712623076744020423 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef ECBMSGTYPES_H #define ECBMSGTYPES_H #include "osd_types.h" #include "include/buffer.h" #include "os/ObjectStore.h" struct ECSubWrite { pg_shard_t from; ceph_tid_t tid; osd_reqid_t reqid; hobject_t soid; pg_stat_t stats; ObjectStore::Transaction t; eversion_t at_version; eversion_t trim_to; eversion_t trim_rollback_to; vector log_entries; set temp_added; set temp_removed; boost::optional updated_hit_set_history; ECSubWrite() {} ECSubWrite( pg_shard_t from, ceph_tid_t tid, osd_reqid_t reqid, hobject_t soid, const pg_stat_t &stats, const ObjectStore::Transaction &t, eversion_t at_version, eversion_t trim_to, eversion_t trim_rollback_to, vector log_entries, boost::optional updated_hit_set_history, const set &temp_added, const set &temp_removed) : from(from), tid(tid), reqid(reqid), soid(soid), stats(stats), t(t), at_version(at_version), trim_to(trim_to), trim_rollback_to(trim_rollback_to), log_entries(log_entries), temp_added(temp_added), temp_removed(temp_removed), updated_hit_set_history(updated_hit_set_history) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ECSubWrite) struct ECSubWriteReply { pg_shard_t from; ceph_tid_t tid; eversion_t last_complete; bool committed; bool applied; ECSubWriteReply() : committed(false), applied(false) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ECSubWriteReply) struct ECSubRead { pg_shard_t from; ceph_tid_t tid; map > > to_read; set attrs_to_read; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ECSubRead) struct ECSubReadReply { pg_shard_t from; ceph_tid_t tid; map > > buffers_read; map > attrs_read; map errors; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(ECSubReadReply) std::ostream &operator<<( std::ostream &lhs, const ECSubWrite &rhs); std::ostream &operator<<( std::ostream &lhs, const ECSubWriteReply &rhs); std::ostream &operator<<( std::ostream &lhs, const ECSubRead &rhs); std::ostream &operator<<( std::ostream &lhs, const ECSubReadReply &rhs); #endif ceph-0.80.11/src/osd/ECBackend.h0000664000175100017510000003362612623076744020173 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef ECBACKEND_H #define ECBACKEND_H #include "OSD.h" #include "PGBackend.h" #include "osd_types.h" #include #include "erasure-code/ErasureCodeInterface.h" #include "ECTransaction.h" #include "ECMsgTypes.h" #include "ECUtil.h" #include "messages/MOSDECSubOpWrite.h" #include "messages/MOSDECSubOpWriteReply.h" #include "messages/MOSDECSubOpRead.h" #include "messages/MOSDECSubOpReadReply.h" struct RecoveryMessages; class ECBackend : public PGBackend { public: RecoveryHandle *open_recovery_op(); void run_recovery_op( RecoveryHandle *h, int priority ); void recover_object( const hobject_t &hoid, eversion_t v, ObjectContextRef head, ObjectContextRef obc, RecoveryHandle *h ); bool handle_message( OpRequestRef op ); bool can_handle_while_inactive( OpRequestRef op ); friend struct SubWriteApplied; friend struct SubWriteCommitted; void sub_write_applied( ceph_tid_t tid, eversion_t version); void sub_write_committed( ceph_tid_t tid, eversion_t version, eversion_t last_complete); void handle_sub_write( pg_shard_t from, OpRequestRef msg, ECSubWrite &op, Context *on_local_applied_sync = 0 ); void handle_sub_read( pg_shard_t from, ECSubRead &op, ECSubReadReply *reply ); void handle_sub_write_reply( pg_shard_t from, ECSubWriteReply &op ); void handle_sub_read_reply( pg_shard_t from, ECSubReadReply &op, RecoveryMessages *m ); /// @see ReadOp below void check_recovery_sources(const OSDMapRef osdmap); void on_change(); void clear_state(); void on_flushed(); void dump_recovery_info(Formatter *f) const; /// @see osd/ECTransaction.cc/h PGTransaction *get_transaction(); void submit_transaction( const hobject_t &hoid, const eversion_t &at_version, PGTransaction *t, const eversion_t &trim_to, const eversion_t &trim_rollback_to, vector &log_entries, boost::optional &hset_history, Context *on_local_applied_sync, Context *on_all_applied, Context *on_all_commit, ceph_tid_t tid, osd_reqid_t reqid, OpRequestRef op ); int objects_read_sync( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist *bl); /** * Async read mechanism * * Async reads use the same async read mechanism as does recovery. * CallClientContexts is responsible for reconstructing the response * buffer as well as for calling the callbacks. * * One tricky bit is that two reads may possibly not read from the same * set of replicas. This could result in two reads completing in the * wrong (from the interface user's point of view) order. Thus, we * maintain a queue of in progress reads (@see in_progress_client_reads) * to ensure that we always call the completion callback in order. * * Another subtely is that while we may read a degraded object, we will * still only perform a client read from shards in the acting set. This * ensures that we won't ever have to restart a client initiated read in * check_recovery_sources. */ friend struct CallClientContexts; struct ClientAsyncReadStatus { bool complete; Context *on_complete; ClientAsyncReadStatus(Context *on_complete) : complete(false), on_complete(on_complete) {} }; list in_progress_client_reads; void objects_read_async( const hobject_t &hoid, const list, pair > > &to_read, Context *on_complete); private: friend struct ECRecoveryHandle; uint64_t get_recovery_chunk_size() const { uint64_t max = cct->_conf->osd_recovery_max_chunk; max -= max % sinfo.get_stripe_width(); max += sinfo.get_stripe_width(); return max; } /** * Recovery * * Recovery uses the same underlying read mechanism as client reads * with the slight difference that recovery reads may come from non * acting shards. Thus, check_recovery_sources may wind up calling * cancel_pull for a read originating with RecoveryOp. * * The recovery process is expressed as a state machine: * - IDLE: Nothing is currently in progress, reads will be started and * we will transition to READING * - READING: We are awaiting a pending read op. Once complete, we will * decode the buffers and proceed to WRITING * - WRITING: We are awaiting a completed push. Once complete, we will * either transition to COMPLETE or to IDLE to continue. * - COMPLETE: complete * * We use the existing Push and PushReply messages and structures to * handle actually shuffling the data over to the replicas. recovery_info * and recovery_progress are expressed in terms of the logical offset * space except for data_included which is in terms of the chunked object * space (to match the passed buffer). * * xattrs are requested on the first read and used to initialize the * object_context if missing on completion of the first read. * * In order to batch up reads and writes, we batch Push, PushReply, * Transaction, and reads in a RecoveryMessages object which is passed * among the recovery methods. */ struct RecoveryOp { hobject_t hoid; eversion_t v; set missing_on; set missing_on_shards; ObjectRecoveryInfo recovery_info; ObjectRecoveryProgress recovery_progress; bool pending_read; enum state_t { IDLE, READING, WRITING, COMPLETE } state; static const char* tostr(state_t state) { switch (state) { case ECBackend::RecoveryOp::IDLE: return "IDLE"; break; case ECBackend::RecoveryOp::READING: return "READING"; break; case ECBackend::RecoveryOp::WRITING: return "WRITING"; break; case ECBackend::RecoveryOp::COMPLETE: return "COMPLETE"; break; default: assert(0); return ""; } } // must be filled if state == WRITING map returned_data; map xattrs; ECUtil::HashInfoRef hinfo; ObjectContextRef obc; set waiting_on_pushes; // valid in state READING pair extent_requested; void dump(Formatter *f) const; RecoveryOp() : pending_read(false), state(IDLE) {} }; friend ostream &operator<<(ostream &lhs, const RecoveryOp &rhs); map recovery_ops; public: /** * Low level async read mechanism * * To avoid duplicating the logic for requesting and waiting for * multiple object shards, there is a common async read mechanism * taking a map of hobject_t->read_request_t which defines callbacks * taking read_result_ts as arguments. * * tid_to_read_map gives open read ops. check_recovery_sources uses * shard_to_read_map and ReadOp::source_to_obj to restart reads * involving down osds. * * The user is responsible for specifying replicas on which to read * and for reassembling the buffer on the other side since client * reads require the original object buffer while recovery only needs * the missing pieces. * * Rather than handling reads on the primary directly, we simply send * ourselves a message. This avoids a dedicated primary path for that * part. */ struct read_result_t { int r; map errors; boost::optional > attrs; list< boost::tuple< uint64_t, uint64_t, map > > returned; read_result_t() : r(0) {} }; struct read_request_t { const list > to_read; const set need; const bool want_attrs; GenContext &> *cb; read_request_t( const hobject_t &hoid, const list > &to_read, const set &need, bool want_attrs, GenContext &> *cb) : to_read(to_read), need(need), want_attrs(want_attrs), cb(cb) {} }; friend ostream &operator<<(ostream &lhs, const read_request_t &rhs); struct ReadOp { int priority; ceph_tid_t tid; OpRequestRef op; // may be null if not on behalf of a client map to_read; map complete; map > obj_to_source; map > source_to_obj; void dump(Formatter *f) const; set in_progress; }; friend struct FinishReadOp; void filter_read_op( const OSDMapRef osdmap, ReadOp &op); void complete_read_op(ReadOp &rop, RecoveryMessages *m); friend ostream &operator<<(ostream &lhs, const ReadOp &rhs); map tid_to_read_map; map > shard_to_read_map; void start_read_op( int priority, map &to_read, OpRequestRef op); /** * Client writes * * ECTransaction is responsible for generating a transaction for * each shard to which we need to send the write. As required * by the PGBackend interface, the ECBackend write mechanism * passes trim information with the write and last_complete back * with the reply. * * As with client reads, there is a possibility of out-of-order * completions. Thus, callbacks and completion are called in order * on the writing list. */ struct Op { hobject_t hoid; eversion_t version; eversion_t trim_to; eversion_t trim_rollback_to; vector log_entries; boost::optional updated_hit_set_history; Context *on_local_applied_sync; Context *on_all_applied; Context *on_all_commit; ceph_tid_t tid; osd_reqid_t reqid; OpRequestRef client_op; ECTransaction *t; set temp_added; set temp_cleared; set pending_commit; set pending_apply; map unstable_hash_infos; ~Op() { delete t; delete on_local_applied_sync; delete on_all_applied; delete on_all_commit; } }; friend ostream &operator<<(ostream &lhs, const Op &rhs); void continue_recovery_op( RecoveryOp &op, RecoveryMessages *m); void dispatch_recovery_messages(RecoveryMessages &m, int priority); friend struct OnRecoveryReadComplete; void handle_recovery_read_complete( const hobject_t &hoid, boost::tuple > &to_read, boost::optional > attrs, RecoveryMessages *m); void handle_recovery_push( PushOp &op, RecoveryMessages *m); void handle_recovery_push_reply( PushReplyOp &op, pg_shard_t from, RecoveryMessages *m); map tid_to_op_map; /// lists below point into here list writing; CephContext *cct; ErasureCodeInterfaceRef ec_impl; /** * ECRecPred * * Determines the whether _have is suffient to recover an object */ class ECRecPred : public IsRecoverablePredicate { set want; ErasureCodeInterfaceRef ec_impl; public: ECRecPred(ErasureCodeInterfaceRef ec_impl) : ec_impl(ec_impl) { for (unsigned i = 0; i < ec_impl->get_data_chunk_count(); ++i) { want.insert(i); } } bool operator()(const set &_have) const { set have; for (set::const_iterator i = _have.begin(); i != _have.end(); ++i) { have.insert(i->shard); } set min; return ec_impl->minimum_to_decode(want, have, &min) == 0; } }; IsRecoverablePredicate *get_is_recoverable_predicate() { return new ECRecPred(ec_impl); } /** * ECReadPred * * Determines the whether _have is suffient to read an object */ class ECReadPred : public IsReadablePredicate { pg_shard_t whoami; ECRecPred rec_pred; public: ECReadPred( pg_shard_t whoami, ErasureCodeInterfaceRef ec_impl) : whoami(whoami), rec_pred(ec_impl) {} bool operator()(const set &_have) const { return _have.count(whoami) && rec_pred(_have); } }; IsReadablePredicate *get_is_readable_predicate() { return new ECReadPred(get_parent()->whoami_shard(), ec_impl); } const ECUtil::stripe_info_t sinfo; /// If modified, ensure that the ref is held until the update is applied SharedPtrRegistry unstable_hashinfo_registry; ECUtil::HashInfoRef get_hash_info(const hobject_t &hoid); friend struct ReadCB; void check_op(Op *op); void start_write(Op *op); public: ECBackend( PGBackend::Listener *pg, coll_t coll, coll_t temp_coll, ObjectStore *store, CephContext *cct, ErasureCodeInterfaceRef ec_impl, uint64_t stripe_width); /// Returns to_read replicas sufficient to reconstruct want int get_min_avail_to_read_shards( const hobject_t &hoid, ///< [in] object const set &want, ///< [in] desired shards bool for_recovery, ///< [in] true if we may use non-acting replicas set *to_read ///< [out] shards to read ); ///< @return error code, 0 on success int objects_get_attrs( const hobject_t &hoid, map *out); void rollback_append( const hobject_t &hoid, uint64_t old_size, ObjectStore::Transaction *t); bool scrub_supported() { return true; } void be_deep_scrub( const hobject_t &obj, ScrubMap::object &o, ThreadPool::TPHandle &handle); uint64_t be_get_ondisk_size(uint64_t logical_size) { return sinfo.logical_to_next_chunk_offset(logical_size); } }; #endif ceph-0.80.11/src/osd/Watch.h0000664000175100017510000001463212623076744017476 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_WATCH_H #define CEPH_WATCH_H #include #include "include/memory.h" #include #include "msg/Messenger.h" #include "include/Context.h" #include "common/Mutex.h" enum WatcherState { WATCHER_PENDING, WATCHER_NOTIFIED, }; class OSDService; class ReplicatedPG; void intrusive_ptr_add_ref(ReplicatedPG *pg); void intrusive_ptr_release(ReplicatedPG *pg); struct ObjectContext; class MWatchNotify; class Watch; typedef ceph::shared_ptr WatchRef; typedef ceph::weak_ptr WWatchRef; class Notify; typedef ceph::shared_ptr NotifyRef; typedef ceph::weak_ptr WNotifyRef; struct CancelableContext; /** * Notify tracks the progress of a particular notify * * References are held by Watch and the timeout callback. */ class NotifyTimeoutCB; class Notify { friend class NotifyTimeoutCB; friend class Watch; WNotifyRef self; ConnectionRef client; unsigned in_progress_watchers; bool complete; bool discarded; set watchers; bufferlist payload; uint32_t timeout; uint64_t cookie; uint64_t notify_id; uint64_t version; OSDService *osd; CancelableContext *cb; Mutex lock; /// true if this notify is being discarded bool is_discarded() { return discarded || complete; } /// Sends notify completion if in_progress_watchers == 0 void maybe_complete_notify(); /// Called on Notify timeout void do_timeout(); Notify( ConnectionRef client, unsigned num_watchers, bufferlist &payload, uint32_t timeout, uint64_t cookie, uint64_t notify_id, uint64_t version, OSDService *osd); /// registers a timeout callback with the watch_timer void register_cb(); /// removes the timeout callback, called on completion or cancellation void unregister_cb(); public: string gen_dbg_prefix() { stringstream ss; ss << "Notify(" << make_pair(cookie, notify_id) << " " << " in_progress_watchers=" << in_progress_watchers << ") "; return ss.str(); } void set_self(NotifyRef _self) { self = _self; } static NotifyRef makeNotifyRef( ConnectionRef client, unsigned num_watchers, bufferlist &payload, uint32_t timeout, uint64_t cookie, uint64_t notify_id, uint64_t version, OSDService *osd); /// Call after creation to initialize void init(); /// Called once per watcher prior to init() void start_watcher( WatchRef watcher ///< [in] watcher to complete ); /// Called once per NotifyAck void complete_watcher( WatchRef watcher ///< [in] watcher to complete ); /// Called when the notify is canceled due to a new peering interval void discard(); }; /** * Watch is a mapping between a Connection and an ObjectContext * * References are held by ObjectContext and the timeout callback */ class HandleWatchTimeout; class HandleDelayedWatchTimeout; class Watch { WWatchRef self; friend class HandleWatchTimeout; friend class HandleDelayedWatchTimeout; ConnectionRef conn; CancelableContext *cb; OSDService *osd; boost::intrusive_ptr pg; ceph::shared_ptr obc; std::map in_progress_notifies; // Could have watch_info_t here, but this file includes osd_types.h uint32_t timeout; uint64_t cookie; entity_addr_t addr; entity_name_t entity; bool discarded; Watch( ReplicatedPG *pg, OSDService *osd, ceph::shared_ptr obc, uint32_t timeout, uint64_t cookie, entity_name_t entity, const entity_addr_t& addr); /// Registers the timeout callback with watch_timer void register_cb(); /// send a Notify message when connected for notif void send_notify(NotifyRef notif); /// Cleans up state on discard or remove (including Connection state, obc) void discard_state(); public: /// Unregisters the timeout callback void unregister_cb(); /// NOTE: must be called with pg lock held ~Watch(); string gen_dbg_prefix(); static WatchRef makeWatchRef( ReplicatedPG *pg, OSDService *osd, ceph::shared_ptr obc, uint32_t timeout, uint64_t cookie, entity_name_t entity, const entity_addr_t &addr); void set_self(WatchRef _self) { self = _self; } /// Does not grant a ref count! boost::intrusive_ptr get_pg() { return pg; } ceph::shared_ptr get_obc() { return obc; } uint64_t get_cookie() const { return cookie; } entity_name_t get_entity() const { return entity; } entity_addr_t get_peer_addr() const { return addr; } uint32_t get_timeout() const { return timeout; } /// Generates context for use if watch timeout is delayed by scrub or recovery Context *get_delayed_cb(); /// True if currently connected bool connected(); /// Transitions Watch to connected, unregister_cb, resends pending Notifies void connect( ConnectionRef con ///< [in] Reference to new connection ); /// Transitions watch to disconnected, register_cb void disconnect(); /// Called if Watch state is discarded due to new peering interval void discard(); /// True if removed or discarded bool is_discarded(); /// Called on unwatch void remove(); /// Adds notif as in-progress notify void start_notify( NotifyRef notif ///< [in] Reference to new in-progress notify ); /// Removes timed out notify void cancel_notify( NotifyRef notif ///< [in] notify which timed out ); /// Call when notify_ack received on notify_id void notify_ack( uint64_t notify_id ///< [in] id of acked notify ); }; /** * Holds weak refs to Watch structures corresponding to a connection * Lives in the OSD::Session object of an OSD connection */ class WatchConState { Mutex lock; std::set watches; public: WatchConState() : lock("WatchConState") {} /// Add a watch void addWatch( WatchRef watch ///< [in] Ref to new watch object ); /// Remove a watch void removeWatch( WatchRef watch ///< [in] Ref to watch object to remove ); /// Called on session reset, disconnects watchers void reset(); }; #endif ceph-0.80.11/src/osd/PG.h0000664000175100017510000021260312623076744016734 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_PG_H #define CEPH_PG_H #include #include #include #include #include #include #include #include #include "include/memory.h" // re-include our assert to clobber boost's #include "include/assert.h" #include "include/types.h" #include "include/stringify.h" #include "osd_types.h" #include "include/buffer.h" #include "include/xlist.h" #include "include/atomic.h" #include "SnapMapper.h" #include "PGLog.h" #include "OpRequest.h" #include "OSDMap.h" #include "os/ObjectStore.h" #include "msg/Messenger.h" #include "messages/MOSDRepScrub.h" #include "messages/MOSDPGLog.h" #include "common/cmdparse.h" #include "common/tracked_int_ptr.hpp" #include "common/WorkQueue.h" #include "common/ceph_context.h" #include "include/str_list.h" #include "PGBackend.h" #include #include #include using namespace std; #include "include/unordered_map.h" #include "include/unordered_set.h" //#define DEBUG_RECOVERY_OIDS // track set of recovering oids explicitly, to find counting bugs class OSD; class OSDService; class MOSDOp; class MOSDSubOp; class MOSDSubOpReply; class MOSDPGScan; class MOSDPGBackfill; class MOSDPGInfo; class PG; void intrusive_ptr_add_ref(PG *pg); void intrusive_ptr_release(PG *pg); #ifdef PG_DEBUG_REFS uint64_t get_with_id(PG *pg); void put_with_id(PG *pg, uint64_t id); typedef TrackedIntPtr PGRef; #else typedef boost::intrusive_ptr PGRef; #endif struct PGRecoveryStats { struct per_state_info { uint64_t enter, exit; // enter/exit counts uint64_t events; utime_t event_time; // time spent processing events utime_t total_time; // total time in state utime_t min_time, max_time; per_state_info() : enter(0), exit(0), events(0) {} }; map info; Mutex lock; PGRecoveryStats() : lock("PGRecoverStats::lock") {} void reset() { Mutex::Locker l(lock); info.clear(); } void dump(ostream& out) { Mutex::Locker l(lock); for (map::iterator p = info.begin(); p != info.end(); ++p) { per_state_info& i = p->second; out << i.enter << "\t" << i.exit << "\t" << i.events << "\t" << i.event_time << "\t" << i.total_time << "\t" << i.min_time << "\t" << i.max_time << "\t" << p->first << "\n"; } } void dump_formatted(Formatter *f) { Mutex::Locker l(lock); f->open_array_section("pg_recovery_stats"); for (map::iterator p = info.begin(); p != info.end(); ++p) { per_state_info& i = p->second; f->open_object_section("recovery_state"); f->dump_int("enter", i.enter); f->dump_int("exit", i.exit); f->dump_int("events", i.events); f->dump_stream("event_time") << i.event_time; f->dump_stream("total_time") << i.total_time; f->dump_stream("min_time") << i.min_time; f->dump_stream("max_time") << i.max_time; vector states; get_str_vec(p->first, "/", states); f->open_array_section("nested_states"); for (vector::iterator st = states.begin(); st != states.end(); ++st) { f->dump_string("state", *st); } f->close_section(); f->close_section(); } f->close_section(); } void log_enter(const char *s) { Mutex::Locker l(lock); info[s].enter++; } void log_exit(const char *s, utime_t dur, uint64_t events, utime_t event_dur) { Mutex::Locker l(lock); per_state_info &i = info[s]; i.exit++; i.total_time += dur; if (dur > i.max_time) i.max_time = dur; if (dur < i.min_time || i.min_time == utime_t()) i.min_time = dur; i.events += events; i.event_time += event_dur; } }; struct PGPool { int64_t id; string name; uint64_t auid; pg_pool_t info; SnapContext snapc; // the default pool snapc, ready to go. interval_set cached_removed_snaps; // current removed_snaps set interval_set newly_removed_snaps; // newly removed in the last epoch PGPool(int64_t i, const char *_name, uint64_t au) : id(i), auid(au) { if (_name) name = _name; } void update(OSDMapRef map); }; /** PG - Replica Placement Group * */ class PG { public: std::string gen_prefix() const; /*** PG ****/ protected: OSDService *osd; CephContext *cct; OSDriver osdriver; SnapMapper snap_mapper; virtual PGBackend *get_pgbackend() = 0; public: void update_snap_mapper_bits(uint32_t bits) { snap_mapper.update_bits(bits); } protected: // Ops waiting for map, should be queued at back Mutex map_lock; list waiting_for_map; OSDMapRef osdmap_ref; OSDMapRef last_persisted_osdmap_ref; PGPool pool; void queue_op(OpRequestRef op); void take_op_map_waiters(); void update_osdmap_ref(OSDMapRef newmap) { assert(_lock.is_locked_by_me()); Mutex::Locker l(map_lock); osdmap_ref = newmap; } OSDMapRef get_osdmap_with_maplock() const { assert(map_lock.is_locked()); assert(osdmap_ref); return osdmap_ref; } OSDMapRef get_osdmap() const { assert(is_locked()); assert(osdmap_ref); return osdmap_ref; } /** locking and reference counting. * I destroy myself when the reference count hits zero. * lock() should be called before doing anything. * get() should be called on pointer copy (to another thread, etc.). * put() should be called on destruction of some previously copied pointer. * put_unlock() when done with the current pointer (_most common_). */ Mutex _lock; atomic_t ref; #ifdef PG_DEBUG_REFS Mutex _ref_id_lock; map _live_ids; map _tag_counts; uint64_t _ref_id; #endif public: bool deleting; // true while in removing or OSD is shutting down void lock_suspend_timeout(ThreadPool::TPHandle &handle); void lock(bool no_lockdep = false); void unlock() { //generic_dout(0) << this << " " << info.pgid << " unlock" << dendl; assert(!dirty_info); assert(!dirty_big_info); _lock.Unlock(); } void assert_locked() { assert(_lock.is_locked()); } bool is_locked() const { return _lock.is_locked(); } #ifdef PG_DEBUG_REFS uint64_t get_with_id(); void put_with_id(uint64_t); void dump_live_ids(); #endif void get(const string &tag); void put(const string &tag); bool dirty_info, dirty_big_info; public: bool is_ec_pg() const { return pool.info.ec_pool(); } // pg state pg_info_t info; __u8 info_struct_v; static const __u8 cur_struct_v = 7; bool must_upgrade() { return info_struct_v < 7; } void upgrade( ObjectStore *store, const interval_set &snapcolls); const coll_t coll; PGLog pg_log; static string get_info_key(spg_t pgid) { return stringify(pgid) + "_info"; } static string get_biginfo_key(spg_t pgid) { return stringify(pgid) + "_biginfo"; } static string get_epoch_key(spg_t pgid) { return stringify(pgid) + "_epoch"; } hobject_t log_oid; hobject_t biginfo_oid; class MissingLoc { map needs_recovery_map; map > missing_loc; set missing_loc_sources; PG *pg; set empty_set; public: boost::scoped_ptr is_readable; boost::scoped_ptr is_recoverable; MissingLoc(PG *pg) : pg(pg) {} void set_backend_predicates( PGBackend::IsReadablePredicate *_is_readable, PGBackend::IsRecoverablePredicate *_is_recoverable) { is_readable.reset(_is_readable); is_recoverable.reset(_is_recoverable); } string gen_prefix() const { return pg->gen_prefix(); } bool needs_recovery( const hobject_t &hoid, eversion_t *v = 0) const { map::const_iterator i = needs_recovery_map.find(hoid); if (i == needs_recovery_map.end()) return false; if (v) *v = i->second.need; return true; } bool is_unfound(const hobject_t &hoid) const { return needs_recovery(hoid) && ( !missing_loc.count(hoid) || !(*is_recoverable)(missing_loc.find(hoid)->second)); } bool readable_with_acting( const hobject_t &hoid, const set &acting) const; uint64_t num_unfound() const { uint64_t ret = 0; for (map::const_iterator i = needs_recovery_map.begin(); i != needs_recovery_map.end(); ++i) { if (is_unfound(i->first)) ++ret; } return ret; } const map &get_all_missing() { return needs_recovery_map; } void clear() { needs_recovery_map.clear(); missing_loc.clear(); missing_loc_sources.clear(); } void add_location(const hobject_t &hoid, pg_shard_t location) { missing_loc[hoid].insert(location); } void remove_location(const hobject_t &hoid, pg_shard_t location) { missing_loc[hoid].erase(location); } void add_active_missing(const pg_missing_t &missing) { for (map::const_iterator i = missing.missing.begin(); i != missing.missing.end(); ++i) { map::const_iterator j = needs_recovery_map.find(i->first); if (j == needs_recovery_map.end()) { needs_recovery_map.insert(*i); } else { assert(i->second.need == j->second.need); } } } void add_missing(const hobject_t &hoid, eversion_t need, eversion_t have) { needs_recovery_map[hoid] = pg_missing_t::item(need, have); } void revise_need(const hobject_t &hoid, eversion_t need) { assert(needs_recovery(hoid)); needs_recovery_map[hoid].need = need; } /// Adds info about a possible recovery source bool add_source_info( pg_shard_t source, ///< [in] source const pg_info_t &oinfo, ///< [in] info const pg_missing_t &omissing ///< [in] (optional) missing ); ///< @return whether a new object location was discovered /// Uses osdmap to update structures for now down sources void check_recovery_sources(const OSDMapRef osdmap); /// Call when hoid is no longer missing in acting set void recovered(const hobject_t &hoid) { needs_recovery_map.erase(hoid); missing_loc.erase(hoid); } const set &get_locations(const hobject_t &hoid) const { return missing_loc.count(hoid) ? missing_loc.find(hoid)->second : empty_set; } const map > &get_missing_locs() const { return missing_loc; } const map &get_needs_recovery() const { return needs_recovery_map; } } missing_loc; interval_set snap_collections; // obsolete map past_intervals; interval_set snap_trimq; /* You should not use these items without taking their respective queue locks * (if they have one) */ xlist::item recovery_item, scrub_item, scrub_finalize_item, snap_trim_item, stat_queue_item; int recovery_ops_active; set waiting_on_backfill; #ifdef DEBUG_RECOVERY_OIDS set recovering_oids; #endif utime_t replay_until; protected: int role; // 0 = primary, 1 = replica, -1=none. unsigned state; // PG_STATE_* bool send_notify; ///< true if we are non-primary and should notify the primary public: eversion_t last_update_ondisk; // last_update that has committed; ONLY DEFINED WHEN is_active() eversion_t last_complete_ondisk; // last_complete that has committed. eversion_t last_update_applied; struct C_UpdateLastRollbackInfoTrimmedToApplied : Context { PGRef pg; epoch_t e; eversion_t v; C_UpdateLastRollbackInfoTrimmedToApplied(PG *pg, epoch_t e, eversion_t v) : pg(pg), e(e), v(v) {} void finish(int) { pg->lock(); if (!pg->pg_has_reset_since(e)) { pg->last_rollback_info_trimmed_to_applied = v; } pg->unlock(); } }; // entries <= last_rollback_info_trimmed_to_applied have been trimmed, // and the transaction has applied eversion_t last_rollback_info_trimmed_to_applied; // primary state public: pg_shard_t primary; pg_shard_t pg_whoami; pg_shard_t up_primary; vector up, acting, want_acting; set actingbackfill, actingset; map peer_last_complete_ondisk; eversion_t min_last_complete_ondisk; // up: min over last_complete_ondisk, peer_last_complete_ondisk eversion_t pg_trim_to; // [primary only] content recovery state protected: struct PriorSet { const bool ec_pool; set probe; /// current+prior OSDs we need to probe. set down; /// down osds that would normally be in @a probe and might be interesting. map blocked_by; /// current lost_at values for any OSDs in cur set for which (re)marking them lost would affect cur set bool pg_down; /// some down osds are included in @a cur; the DOWN pg state bit should be set. boost::scoped_ptr pcontdec; PriorSet(bool ec_pool, PGBackend::IsRecoverablePredicate *c, const OSDMap &osdmap, const map &past_intervals, const vector &up, const vector &acting, const pg_info_t &info, const PG *debug_pg=NULL); bool affected_by_map(const OSDMapRef osdmap, const PG *debug_pg=0) const; }; friend std::ostream& operator<<(std::ostream& oss, const struct PriorSet &prior); bool may_need_replay(const OSDMapRef osdmap) const; public: struct BufferedRecoveryMessages { map > query_map; map > > info_map; map > > notify_list; }; struct RecoveryCtx { utime_t start_time; map > *query_map; map > > *info_map; map > > *notify_list; C_Contexts *on_applied; C_Contexts *on_safe; ObjectStore::Transaction *transaction; RecoveryCtx(map > *query_map, map > > *info_map, map > > *notify_list, C_Contexts *on_applied, C_Contexts *on_safe, ObjectStore::Transaction *transaction) : query_map(query_map), info_map(info_map), notify_list(notify_list), on_applied(on_applied), on_safe(on_safe), transaction(transaction) {} RecoveryCtx(BufferedRecoveryMessages &buf, RecoveryCtx &rctx) : query_map(&(buf.query_map)), info_map(&(buf.info_map)), notify_list(&(buf.notify_list)), on_applied(rctx.on_applied), on_safe(rctx.on_safe), transaction(rctx.transaction) {} void accept_buffered_messages(BufferedRecoveryMessages &m) { assert(query_map); assert(info_map); assert(notify_list); for (map >::iterator i = m.query_map.begin(); i != m.query_map.end(); ++i) { map &omap = (*query_map)[i->first]; for (map::iterator j = i->second.begin(); j != i->second.end(); ++j) { omap[j->first] = j->second; } } for (map > >::iterator i = m.info_map.begin(); i != m.info_map.end(); ++i) { vector > &ovec = (*info_map)[i->first]; ovec.reserve(ovec.size() + i->second.size()); ovec.insert(ovec.end(), i->second.begin(), i->second.end()); } for (map > >::iterator i = m.notify_list.begin(); i != m.notify_list.end(); ++i) { vector > &ovec = (*notify_list)[i->first]; ovec.reserve(ovec.size() + i->second.size()); ovec.insert(ovec.end(), i->second.begin(), i->second.end()); } } }; struct NamedState { const char *state_name; utime_t enter_time; const char *get_state_name() { return state_name; } NamedState(CephContext *cct_, const char *state_name_) : state_name(state_name_), enter_time(ceph_clock_now(cct_)) {}; virtual ~NamedState() {} }; protected: /* * peer_info -- projected (updates _before_ replicas ack) * peer_missing -- committed (updates _after_ replicas ack) */ bool need_up_thru; set stray_set; // non-acting osds that have PG data. eversion_t oldest_update; // acting: lowest (valid) last_update in active set map peer_info; // info from peers (stray or prior) set peer_purged; // peers purged map peer_missing; set peer_log_requested; // logs i've requested (and start stamps) set peer_missing_requested; // i deleted these strays; ignore racing PGInfo from them set stray_purged; set peer_activated; // primary-only, recovery-only state set might_have_unfound; // These osds might have objects on them // which are unfound on the primary epoch_t last_peering_reset; /* heartbeat peers */ void set_probe_targets(const set &probe_set); void clear_probe_targets(); public: Mutex heartbeat_peer_lock; set heartbeat_peers; set probe_targets; protected: /** * BackfillInterval * * Represents the objects in a range [begin, end) * * Possible states: * 1) begin == end == hobject_t() indicates the the interval is unpopulated * 2) Else, objects contains all objects in [begin, end) */ struct BackfillInterval { // info about a backfill interval on a peer eversion_t version; /// version at which the scan occurred map objects; hobject_t begin; hobject_t end; /// clear content void clear() { *this = BackfillInterval(); } void reset(hobject_t start) { clear(); begin = end = start; } /// true if there are no objects in this interval bool empty() const { return objects.empty(); } /// true if interval extends to the end of the range bool extends_to_end() const { return end.is_max(); } /// removes items <= soid and adjusts begin to the first object void trim_to(const hobject_t &soid) { trim(); while (!objects.empty() && objects.begin()->first <= soid) { pop_front(); } } /// Adjusts begin to the first object void trim() { if (!objects.empty()) begin = objects.begin()->first; else begin = end; } /// drop first entry, and adjust @begin accordingly void pop_front() { assert(!objects.empty()); objects.erase(objects.begin()); trim(); } /// dump void dump(Formatter *f) const { f->dump_stream("begin") << begin; f->dump_stream("end") << end; f->open_array_section("objects"); for (map::const_iterator i = objects.begin(); i != objects.end(); ++i) { f->open_object_section("object"); f->dump_stream("object") << i->first; f->dump_stream("version") << i->second; f->close_section(); } f->close_section(); } }; BackfillInterval backfill_info; map peer_backfill_info; bool backfill_reserved; bool backfill_reserving; friend class OSD; public: set backfill_targets; bool is_backfill_targets(pg_shard_t osd) { return backfill_targets.count(osd); } protected: // pg waiters unsigned flushes_in_progress; // Ops waiting on backfill_pos to change list waiting_for_active; list waiting_for_cache_not_full; list waiting_for_all_missing; map > waiting_for_unreadable_object, waiting_for_degraded_object, waiting_for_blocked_object; // Callbacks should assume pg (and nothing else) is locked map > callbacks_for_degraded_object; map > waiting_for_ack, waiting_for_ondisk; map replay_queue; void split_ops(PG *child, unsigned split_bits); void requeue_object_waiters(map >& m); void requeue_op(OpRequestRef op); void requeue_ops(list &l); // stats that persist lazily object_stat_collection_t unstable_stats; // publish stats Mutex pg_stats_publish_lock; bool pg_stats_publish_valid; pg_stat_t pg_stats_publish; // for ordering writes ceph::shared_ptr osr; void _update_calc_stats(); void publish_stats_to_osd(); void clear_publish_stats(); public: void clear_primary_state(); public: bool is_actingbackfill(pg_shard_t osd) const { return actingbackfill.count(osd); } bool is_acting(pg_shard_t osd) const { if (pool.info.ec_pool()) { return acting.size() > osd.shard && acting[osd.shard] == osd.osd; } else { return std::find(acting.begin(), acting.end(), osd.osd) != acting.end(); } } bool is_up(pg_shard_t osd) const { if (pool.info.ec_pool()) { return up.size() > osd.shard && up[osd.shard] == osd.osd; } else { return std::find(up.begin(), up.end(), osd.osd) != up.end(); } } bool needs_recovery() const; bool needs_backfill() const; void mark_clean(); ///< mark an active pg clean bool _calc_past_interval_range(epoch_t *start, epoch_t *end, epoch_t oldest_map); void generate_past_intervals(); void trim_past_intervals(); void build_prior(std::auto_ptr &prior_set); void remove_down_peer_info(const OSDMapRef osdmap); bool adjust_need_up_thru(const OSDMapRef osdmap); bool all_unfound_are_queried_or_lost(const OSDMapRef osdmap) const; virtual void mark_all_unfound_lost(int how) = 0; virtual void dump_recovery_info(Formatter *f) const = 0; bool calc_min_last_complete_ondisk() { eversion_t min = last_complete_ondisk; assert(!actingbackfill.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) continue; if (peer_last_complete_ondisk.count(*i) == 0) return false; // we don't have complete info eversion_t a = peer_last_complete_ondisk[*i]; if (a < min) min = a; } if (min == min_last_complete_ondisk) return false; min_last_complete_ondisk = min; return true; } virtual void calc_trim_to() = 0; void proc_replica_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_missing_t& omissing, pg_shard_t from); void proc_master_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_missing_t& omissing, pg_shard_t from); bool proc_replica_info(pg_shard_t from, const pg_info_t &info); struct LogEntryTrimmer : public ObjectModDesc::Visitor { const hobject_t &soid; PG *pg; ObjectStore::Transaction *t; LogEntryTrimmer(const hobject_t &soid, PG *pg, ObjectStore::Transaction *t) : soid(soid), pg(pg), t(t) {} void rmobject(version_t old_version) { pg->get_pgbackend()->trim_stashed_object( soid, old_version, t); } }; struct SnapRollBacker : public ObjectModDesc::Visitor { const hobject_t &soid; PG *pg; ObjectStore::Transaction *t; SnapRollBacker(const hobject_t &soid, PG *pg, ObjectStore::Transaction *t) : soid(soid), pg(pg), t(t) {} void update_snaps(set &snaps) { pg->update_object_snap_mapping(t, soid, snaps); } void create() { pg->clear_object_snap_mapping( t, soid); } }; struct PGLogEntryHandler : public PGLog::LogEntryHandler { list to_rollback; set to_remove; list to_trim; // LogEntryHandler void remove(const hobject_t &hoid) { to_remove.insert(hoid); } void rollback(const pg_log_entry_t &entry) { to_rollback.push_back(entry); } void trim(const pg_log_entry_t &entry) { to_trim.push_back(entry); } void apply(PG *pg, ObjectStore::Transaction *t) { for (list::iterator j = to_rollback.begin(); j != to_rollback.end(); ++j) { assert(j->mod_desc.can_rollback()); pg->get_pgbackend()->rollback(j->soid, j->mod_desc, t); SnapRollBacker rollbacker(j->soid, pg, t); j->mod_desc.visit(&rollbacker); } for (set::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { pg->get_pgbackend()->rollback_create(*i, t); pg->remove_snap_mapped_object(*t, *i); } for (list::reverse_iterator i = to_trim.rbegin(); i != to_trim.rend(); ++i) { LogEntryTrimmer trimmer(i->soid, pg, t); i->mod_desc.visit(&trimmer); } } }; friend struct SnapRollBacker; friend struct PGLogEntryHandler; friend struct LogEntryTrimmer; void update_object_snap_mapping( ObjectStore::Transaction *t, const hobject_t &soid, const set &snaps); void clear_object_snap_mapping( ObjectStore::Transaction *t, const hobject_t &soid); void remove_snap_mapped_object( ObjectStore::Transaction& t, const hobject_t& soid); void merge_log( ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_shard_t from); void rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead); bool search_for_missing( const pg_info_t &oinfo, const pg_missing_t &omissing, pg_shard_t fromosd, RecoveryCtx*); void check_for_lost_objects(); void forget_lost_objects(); void discover_all_missing(std::map > &query_map); void trim_write_ahead(); map::const_iterator find_best_info( const map &infos) const; static void calc_ec_acting( map::const_iterator auth_log_shard, unsigned size, const vector &acting, pg_shard_t acting_primary, const vector &up, pg_shard_t up_primary, const map &all_info, bool compat_mode, vector *want, set *backfill, set *acting_backfill, pg_shard_t *want_primary, ostream &ss); static void calc_replicated_acting( map::const_iterator auth_log_shard, unsigned size, const vector &acting, pg_shard_t acting_primary, const vector &up, pg_shard_t up_primary, const map &all_info, bool compat_mode, vector *want, set *backfill, set *acting_backfill, pg_shard_t *want_primary, ostream &ss); bool choose_acting(pg_shard_t &auth_log_shard); void build_might_have_unfound(); void replay_queued_ops(); void activate( ObjectStore::Transaction& t, epoch_t query_epoch, list& tfin, map >& query_map, map > > *activator_map, RecoveryCtx *ctx); void _activate_committed(epoch_t e); void all_activated_and_committed(); void proc_primary_info(ObjectStore::Transaction &t, const pg_info_t &info); bool have_unfound() const { return missing_loc.num_unfound(); } int get_num_unfound() const { return missing_loc.num_unfound(); } virtual void check_local() = 0; /** * @param ops_begun returns how many recovery ops the function started * @returns true if any useful work was accomplished; false otherwise */ virtual bool start_recovery_ops( int max, RecoveryCtx *prctx, ThreadPool::TPHandle &handle, int *ops_begun) = 0; void purge_strays(); void update_heartbeat_peers(); Context *finish_sync_event; void finish_recovery(list& tfin); void _finish_recovery(Context *c); void cancel_recovery(); void clear_recovery_state(); virtual void _clear_recovery_state() = 0; virtual void check_recovery_sources(const OSDMapRef newmap) = 0; void start_recovery_op(const hobject_t& soid); void finish_recovery_op(const hobject_t& soid, bool dequeue=false); void split_into(pg_t child_pgid, PG *child, unsigned split_bits); virtual void _split_into(pg_t child_pgid, PG *child, unsigned split_bits) = 0; loff_t get_log_write_pos() { return 0; } friend class C_OSD_RepModify_Commit; // -- scrub -- struct Scrubber { Scrubber() : reserved(false), reserve_failed(false), epoch_start(0), block_writes(false), active(false), queue_snap_trim(false), waiting_on(0), shallow_errors(0), deep_errors(0), fixed(0), active_rep_scrub(0), must_scrub(false), must_deep_scrub(false), must_repair(false), classic(false), finalizing(false), is_chunky(false), state(INACTIVE), deep(false) { } // metadata set reserved_peers; bool reserved, reserve_failed; epoch_t epoch_start; // common to both scrubs bool block_writes; bool active; bool queue_snap_trim; int waiting_on; set waiting_on_whom; int shallow_errors; int deep_errors; int fixed; ScrubMap primary_scrubmap; map received_maps; MOSDRepScrub *active_rep_scrub; utime_t scrub_reg_stamp; // stamp we registered for // flags to indicate explicitly requested scrubs (by admin) bool must_scrub, must_deep_scrub, must_repair; // Maps from objects with errors to missing/inconsistent peers map > missing; map > inconsistent; map > inconsistent_snapcolls; // Map from object with errors to good peer map > authoritative; // classic scrub bool classic; bool finalizing; // chunky scrub bool is_chunky; hobject_t start, end; eversion_t subset_last_update; // chunky scrub state enum State { INACTIVE, NEW_CHUNK, WAIT_PUSHES, WAIT_LAST_UPDATE, BUILD_MAP, WAIT_REPLICAS, COMPARE_MAPS, FINISH, } state; // deep scrub bool deep; list callbacks; void add_callback(Context *context) { callbacks.push_back(context); } void run_callbacks() { list to_run; to_run.swap(callbacks); for (list::iterator i = to_run.begin(); i != to_run.end(); ++i) { (*i)->complete(0); } } static const char *state_string(const PG::Scrubber::State& state) { const char *ret = NULL; switch( state ) { case INACTIVE: ret = "INACTIVE"; break; case NEW_CHUNK: ret = "NEW_CHUNK"; break; case WAIT_PUSHES: ret = "WAIT_PUSHES"; break; case WAIT_LAST_UPDATE: ret = "WAIT_LAST_UPDATE"; break; case BUILD_MAP: ret = "BUILD_MAP"; break; case WAIT_REPLICAS: ret = "WAIT_REPLICAS"; break; case COMPARE_MAPS: ret = "COMPARE_MAPS"; break; case FINISH: ret = "FINISH"; break; } return ret; } bool is_chunky_scrub_active() const { return state != INACTIVE; } // classic (non chunk) scrubs block all writes // chunky scrubs only block writes to a range bool write_blocked_by_scrub(const hobject_t &soid) { if (!block_writes) return false; if (!is_chunky) return true; if (soid >= start && soid < end) return true; return false; } // clear all state void reset() { classic = false; finalizing = false; block_writes = false; active = false; queue_snap_trim = false; waiting_on = 0; waiting_on_whom.clear(); if (active_rep_scrub) { active_rep_scrub->put(); active_rep_scrub = NULL; } received_maps.clear(); must_scrub = false; must_deep_scrub = false; must_repair = false; state = PG::Scrubber::INACTIVE; start = hobject_t(); end = hobject_t(); subset_last_update = eversion_t(); shallow_errors = 0; deep_errors = 0; fixed = 0; deep = false; run_callbacks(); inconsistent.clear(); missing.clear(); authoritative.clear(); } } scrubber; bool scrub_after_recovery; int active_pushes; void repair_object( const hobject_t& soid, ScrubMap::object *po, pg_shard_t bad_peer, pg_shard_t ok_peer); void scrub(ThreadPool::TPHandle &handle); void classic_scrub(ThreadPool::TPHandle &handle); void chunky_scrub(ThreadPool::TPHandle &handle); void scrub_compare_maps(); void scrub_process_inconsistent(); void scrub_finalize(); void scrub_finish(); void scrub_clear_state(); bool scrub_gather_replica_maps(); void _scan_snaps(ScrubMap &map); void _scan_rollback_obs( const vector &rollback_obs, ThreadPool::TPHandle &handle); void _request_scrub_map_classic(pg_shard_t replica, eversion_t version); void _request_scrub_map(pg_shard_t replica, eversion_t version, hobject_t start, hobject_t end, bool deep); int build_scrub_map_chunk( ScrubMap &map, hobject_t start, hobject_t end, bool deep, ThreadPool::TPHandle &handle); void build_scrub_map(ScrubMap &map, ThreadPool::TPHandle &handle); void build_inc_scrub_map( ScrubMap &map, eversion_t v, ThreadPool::TPHandle &handle); /** * returns true if [begin, end) is good to scrub at this time * a false return value obliges the implementer to requeue scrub when the * condition preventing scrub clears */ virtual bool _range_available_for_scrub( const hobject_t &begin, const hobject_t &end) = 0; virtual void _scrub(ScrubMap &map) { } virtual void _scrub_clear_state() { } virtual void _scrub_finish() { } virtual void get_colls(list *out) = 0; virtual void split_colls( spg_t child, int split_bits, int seed, ObjectStore::Transaction *t) = 0; virtual bool _report_snap_collection_errors( const hobject_t &hoid, const map &attrs, pg_shard_t osd, ostream &out) { return false; }; void clear_scrub_reserved(); void scrub_reserve_replicas(); void scrub_unreserve_replicas(); bool scrub_all_replicas_reserved() const; bool sched_scrub(); void reg_next_scrub(); void unreg_next_scrub(); void replica_scrub( struct MOSDRepScrub *op, ThreadPool::TPHandle &handle); void sub_op_scrub_map(OpRequestRef op); void sub_op_scrub_reserve(OpRequestRef op); void sub_op_scrub_reserve_reply(OpRequestRef op); void sub_op_scrub_unreserve(OpRequestRef op); void sub_op_scrub_stop(OpRequestRef op); void reject_reservation(); void schedule_backfill_full_retry(); // -- recovery state -- template struct QueuePeeringEvt : Context { PGRef pg; epoch_t epoch; EVT evt; QueuePeeringEvt(PG *pg, epoch_t epoch, EVT evt) : pg(pg), epoch(epoch), evt(evt) {} void finish(int r) { pg->lock(); pg->queue_peering_event(PG::CephPeeringEvtRef( new PG::CephPeeringEvt( epoch, epoch, evt))); pg->unlock(); } }; class CephPeeringEvt { epoch_t epoch_sent; epoch_t epoch_requested; boost::intrusive_ptr< const boost::statechart::event_base > evt; string desc; public: template CephPeeringEvt(epoch_t epoch_sent, epoch_t epoch_requested, const T &evt_) : epoch_sent(epoch_sent), epoch_requested(epoch_requested), evt(evt_.intrusive_from_this()) { stringstream out; out << "epoch_sent: " << epoch_sent << " epoch_requested: " << epoch_requested << " "; evt_.print(&out); desc = out.str(); } epoch_t get_epoch_sent() { return epoch_sent; } epoch_t get_epoch_requested() { return epoch_requested; } const boost::statechart::event_base &get_event() { return *evt; } string get_desc() { return desc; } }; typedef ceph::shared_ptr CephPeeringEvtRef; list peering_queue; // op queue list peering_waiters; struct QueryState : boost::statechart::event< QueryState > { Formatter *f; QueryState(Formatter *f) : f(f) {} void print(std::ostream *out) const { *out << "Query"; } }; struct MInfoRec : boost::statechart::event< MInfoRec > { pg_shard_t from; pg_info_t info; epoch_t msg_epoch; MInfoRec(pg_shard_t from, pg_info_t &info, epoch_t msg_epoch) : from(from), info(info), msg_epoch(msg_epoch) {} void print(std::ostream *out) const { *out << "MInfoRec from " << from << " info: " << info; } }; struct MLogRec : boost::statechart::event< MLogRec > { pg_shard_t from; boost::intrusive_ptr msg; MLogRec(pg_shard_t from, MOSDPGLog *msg) : from(from), msg(msg) {} void print(std::ostream *out) const { *out << "MLogRec from " << from; } }; struct MNotifyRec : boost::statechart::event< MNotifyRec > { pg_shard_t from; pg_notify_t notify; uint64_t features; MNotifyRec(pg_shard_t from, pg_notify_t ¬ify, uint64_t f) : from(from), notify(notify), features(f) {} void print(std::ostream *out) const { *out << "MNotifyRec from " << from << " notify: " << notify << " features: 0x" << hex << features << dec; } }; struct MQuery : boost::statechart::event< MQuery > { pg_shard_t from; pg_query_t query; epoch_t query_epoch; MQuery(pg_shard_t from, const pg_query_t &query, epoch_t query_epoch): from(from), query(query), query_epoch(query_epoch) {} void print(std::ostream *out) const { *out << "MQuery from " << from << " query_epoch " << query_epoch << " query: " << query; } }; struct AdvMap : boost::statechart::event< AdvMap > { OSDMapRef osdmap; OSDMapRef lastmap; vector newup, newacting; int up_primary, acting_primary; AdvMap( OSDMapRef osdmap, OSDMapRef lastmap, vector& newup, int up_primary, vector& newacting, int acting_primary): osdmap(osdmap), lastmap(lastmap), newup(newup), newacting(newacting), up_primary(up_primary), acting_primary(acting_primary) {} void print(std::ostream *out) const { *out << "AdvMap"; } }; struct ActMap : boost::statechart::event< ActMap > { ActMap() : boost::statechart::event< ActMap >() {} void print(std::ostream *out) const { *out << "ActMap"; } }; struct Activate : boost::statechart::event< Activate > { epoch_t query_epoch; Activate(epoch_t q) : boost::statechart::event< Activate >(), query_epoch(q) {} void print(std::ostream *out) const { *out << "Activate from " << query_epoch; } }; struct RequestBackfillPrio : boost::statechart::event< RequestBackfillPrio > { unsigned priority; RequestBackfillPrio(unsigned prio) : boost::statechart::event< RequestBackfillPrio >(), priority(prio) {} void print(std::ostream *out) const { *out << "RequestBackfillPrio: priority " << priority; } }; #define TrivialEvent(T) struct T : boost::statechart::event< T > { \ T() : boost::statechart::event< T >() {} \ void print(std::ostream *out) const { \ *out << #T; \ } \ }; TrivialEvent(Initialize) TrivialEvent(Load) TrivialEvent(GotInfo) TrivialEvent(NeedUpThru) TrivialEvent(CheckRepops) TrivialEvent(NullEvt) TrivialEvent(FlushedEvt) TrivialEvent(Backfilled) TrivialEvent(LocalBackfillReserved) TrivialEvent(RemoteBackfillReserved) TrivialEvent(RemoteReservationRejected) TrivialEvent(RequestBackfill) TrivialEvent(RequestRecovery) TrivialEvent(RecoveryDone) TrivialEvent(BackfillTooFull) TrivialEvent(AllReplicasRecovered) TrivialEvent(DoRecovery) TrivialEvent(LocalRecoveryReserved) TrivialEvent(RemoteRecoveryReserved) TrivialEvent(AllRemotesReserved) TrivialEvent(AllBackfillsReserved) TrivialEvent(Recovering) TrivialEvent(GoClean) TrivialEvent(AllReplicasActivated) TrivialEvent(IntervalFlush) /* Encapsulates PG recovery process */ class RecoveryState { void start_handle(RecoveryCtx *new_ctx); void end_handle(); public: void begin_block_outgoing(); void end_block_outgoing(); void clear_blocked_outgoing(); private: /* States */ struct Initial; class RecoveryMachine : public boost::statechart::state_machine< RecoveryMachine, Initial > { RecoveryState *state; public: PG *pg; utime_t event_time; uint64_t event_count; void clear_event_counters() { event_time = utime_t(); event_count = 0; } void log_enter(const char *state_name); void log_exit(const char *state_name, utime_t duration); RecoveryMachine(RecoveryState *state, PG *pg) : state(state), pg(pg), event_count(0) {} /* Accessor functions for state methods */ ObjectStore::Transaction* get_cur_transaction() { assert(state->rctx); assert(state->rctx->transaction); return state->rctx->transaction; } void send_query(pg_shard_t to, const pg_query_t &query) { assert(state->rctx); assert(state->rctx->query_map); (*state->rctx->query_map)[to.osd][spg_t(pg->info.pgid.pgid, to.shard)] = query; } map > *get_query_map() { assert(state->rctx); assert(state->rctx->query_map); return state->rctx->query_map; } map > > *get_info_map() { assert(state->rctx); assert(state->rctx->info_map); return state->rctx->info_map; } list< Context* > *get_on_safe_context_list() { assert(state->rctx); assert(state->rctx->on_safe); return &(state->rctx->on_safe->contexts); } list< Context * > *get_on_applied_context_list() { assert(state->rctx); assert(state->rctx->on_applied); return &(state->rctx->on_applied->contexts); } RecoveryCtx *get_recovery_ctx() { return &*(state->rctx); } void send_notify(pg_shard_t to, const pg_notify_t &info, const pg_interval_map_t &pi) { assert(state->rctx); assert(state->rctx->notify_list); (*state->rctx->notify_list)[to.osd].push_back(make_pair(info, pi)); } }; friend class RecoveryMachine; /* States */ struct Crashed : boost::statechart::state< Crashed, RecoveryMachine >, NamedState { Crashed(my_context ctx); }; struct Started; struct Reset; struct Initial : boost::statechart::state< Initial, RecoveryMachine >, NamedState { Initial(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::transition< Initialize, Reset >, boost::statechart::custom_reaction< Load >, boost::statechart::custom_reaction< NullEvt >, boost::statechart::transition< boost::statechart::event_base, Crashed > > reactions; boost::statechart::result react(const Load&); boost::statechart::result react(const MNotifyRec&); boost::statechart::result react(const MInfoRec&); boost::statechart::result react(const MLogRec&); boost::statechart::result react(const boost::statechart::event_base&) { return discard_event(); } }; struct Reset : boost::statechart::state< Reset, RecoveryMachine >, NamedState { Reset(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< AdvMap >, boost::statechart::custom_reaction< ActMap >, boost::statechart::custom_reaction< NullEvt >, boost::statechart::custom_reaction< FlushedEvt >, boost::statechart::custom_reaction< IntervalFlush >, boost::statechart::transition< boost::statechart::event_base, Crashed > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const AdvMap&); boost::statechart::result react(const ActMap&); boost::statechart::result react(const FlushedEvt&); boost::statechart::result react(const IntervalFlush&); boost::statechart::result react(const boost::statechart::event_base&) { return discard_event(); } }; struct Start; struct Started : boost::statechart::state< Started, RecoveryMachine, Start >, NamedState { Started(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< AdvMap >, boost::statechart::custom_reaction< NullEvt >, boost::statechart::custom_reaction< FlushedEvt >, boost::statechart::custom_reaction< IntervalFlush >, boost::statechart::transition< boost::statechart::event_base, Crashed > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const AdvMap&); boost::statechart::result react(const FlushedEvt&); boost::statechart::result react(const IntervalFlush&); boost::statechart::result react(const boost::statechart::event_base&) { return discard_event(); } }; struct MakePrimary : boost::statechart::event< MakePrimary > { MakePrimary() : boost::statechart::event< MakePrimary >() {} }; struct MakeStray : boost::statechart::event< MakeStray > { MakeStray() : boost::statechart::event< MakeStray >() {} }; struct Primary; struct Stray; struct Start : boost::statechart::state< Start, Started >, NamedState { Start(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::transition< MakePrimary, Primary >, boost::statechart::transition< MakeStray, Stray > > reactions; }; struct Peering; struct WaitActingChange; struct NeedActingChange : boost::statechart::event< NeedActingChange > { NeedActingChange() : boost::statechart::event< NeedActingChange >() {} }; struct Incomplete; struct IsIncomplete : boost::statechart::event< IsIncomplete > { IsIncomplete() : boost::statechart::event< IsIncomplete >() {} }; struct Primary : boost::statechart::state< Primary, Started, Peering >, NamedState { Primary(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< ActMap >, boost::statechart::custom_reaction< MNotifyRec >, boost::statechart::transition< NeedActingChange, WaitActingChange > > reactions; boost::statechart::result react(const ActMap&); boost::statechart::result react(const MNotifyRec&); }; struct WaitActingChange : boost::statechart::state< WaitActingChange, Primary>, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< AdvMap >, boost::statechart::custom_reaction< MLogRec >, boost::statechart::custom_reaction< MInfoRec >, boost::statechart::custom_reaction< MNotifyRec > > reactions; WaitActingChange(my_context ctx); boost::statechart::result react(const QueryState& q); boost::statechart::result react(const AdvMap&); boost::statechart::result react(const MLogRec&); boost::statechart::result react(const MInfoRec&); boost::statechart::result react(const MNotifyRec&); void exit(); }; struct GetInfo; struct Active; struct Peering : boost::statechart::state< Peering, Primary, GetInfo >, NamedState { std::auto_ptr< PriorSet > prior_set; Peering(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::transition< Activate, Active >, boost::statechart::custom_reaction< AdvMap > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const AdvMap &advmap); }; struct WaitLocalRecoveryReserved; struct Activating; struct Active : boost::statechart::state< Active, Primary, Activating >, NamedState { Active(my_context ctx); void exit(); const set remote_shards_to_reserve_recovery; const set remote_shards_to_reserve_backfill; bool all_replicas_activated; typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< ActMap >, boost::statechart::custom_reaction< AdvMap >, boost::statechart::custom_reaction< MInfoRec >, boost::statechart::custom_reaction< MNotifyRec >, boost::statechart::custom_reaction< MLogRec >, boost::statechart::custom_reaction< Backfilled >, boost::statechart::custom_reaction< AllReplicasActivated > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const ActMap&); boost::statechart::result react(const AdvMap&); boost::statechart::result react(const MInfoRec& infoevt); boost::statechart::result react(const MNotifyRec& notevt); boost::statechart::result react(const MLogRec& logevt); boost::statechart::result react(const Backfilled&) { return discard_event(); } boost::statechart::result react(const AllReplicasActivated&); }; struct Clean : boost::statechart::state< Clean, Active >, NamedState { typedef boost::mpl::list< boost::statechart::transition< DoRecovery, WaitLocalRecoveryReserved > > reactions; Clean(my_context ctx); void exit(); }; struct Recovered : boost::statechart::state< Recovered, Active >, NamedState { typedef boost::mpl::list< boost::statechart::transition< GoClean, Clean >, boost::statechart::custom_reaction< AllReplicasActivated > > reactions; Recovered(my_context ctx); void exit(); boost::statechart::result react(const AllReplicasActivated&) { post_event(GoClean()); return forward_event(); } }; struct Backfilling : boost::statechart::state< Backfilling, Active >, NamedState { typedef boost::mpl::list< boost::statechart::transition< Backfilled, Recovered >, boost::statechart::custom_reaction< RemoteReservationRejected > > reactions; Backfilling(my_context ctx); boost::statechart::result react(const RemoteReservationRejected& evt); void exit(); }; struct WaitRemoteBackfillReserved : boost::statechart::state< WaitRemoteBackfillReserved, Active >, NamedState { typedef boost::mpl::list< boost::statechart::custom_reaction< RemoteBackfillReserved >, boost::statechart::custom_reaction< RemoteReservationRejected >, boost::statechart::transition< AllBackfillsReserved, Backfilling > > reactions; set::const_iterator backfill_osd_it; WaitRemoteBackfillReserved(my_context ctx); void exit(); boost::statechart::result react(const RemoteBackfillReserved& evt); boost::statechart::result react(const RemoteReservationRejected& evt); }; struct WaitLocalBackfillReserved : boost::statechart::state< WaitLocalBackfillReserved, Active >, NamedState { typedef boost::mpl::list< boost::statechart::transition< LocalBackfillReserved, WaitRemoteBackfillReserved > > reactions; WaitLocalBackfillReserved(my_context ctx); void exit(); }; struct NotBackfilling : boost::statechart::state< NotBackfilling, Active>, NamedState { typedef boost::mpl::list< boost::statechart::transition< RequestBackfill, WaitLocalBackfillReserved>, boost::statechart::custom_reaction< RemoteBackfillReserved >, boost::statechart::custom_reaction< RemoteReservationRejected > > reactions; NotBackfilling(my_context ctx); void exit(); boost::statechart::result react(const RemoteBackfillReserved& evt); boost::statechart::result react(const RemoteReservationRejected& evt); }; struct RepNotRecovering; struct ReplicaActive : boost::statechart::state< ReplicaActive, Started, RepNotRecovering >, NamedState { ReplicaActive(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< ActMap >, boost::statechart::custom_reaction< MQuery >, boost::statechart::custom_reaction< MInfoRec >, boost::statechart::custom_reaction< MLogRec >, boost::statechart::custom_reaction< Activate > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const MInfoRec& infoevt); boost::statechart::result react(const MLogRec& logevt); boost::statechart::result react(const ActMap&); boost::statechart::result react(const MQuery&); boost::statechart::result react(const Activate&); }; struct RepRecovering : boost::statechart::state< RepRecovering, ReplicaActive >, NamedState { typedef boost::mpl::list< boost::statechart::transition< RecoveryDone, RepNotRecovering >, boost::statechart::transition< RemoteReservationRejected, RepNotRecovering >, boost::statechart::custom_reaction< BackfillTooFull > > reactions; RepRecovering(my_context ctx); boost::statechart::result react(const BackfillTooFull &evt); void exit(); }; struct RepWaitBackfillReserved : boost::statechart::state< RepWaitBackfillReserved, ReplicaActive >, NamedState { typedef boost::mpl::list< boost::statechart::custom_reaction< RemoteBackfillReserved >, boost::statechart::custom_reaction< RemoteReservationRejected > > reactions; RepWaitBackfillReserved(my_context ctx); void exit(); boost::statechart::result react(const RemoteBackfillReserved &evt); boost::statechart::result react(const RemoteReservationRejected &evt); }; struct RepWaitRecoveryReserved : boost::statechart::state< RepWaitRecoveryReserved, ReplicaActive >, NamedState { typedef boost::mpl::list< boost::statechart::custom_reaction< RemoteRecoveryReserved > > reactions; RepWaitRecoveryReserved(my_context ctx); void exit(); boost::statechart::result react(const RemoteRecoveryReserved &evt); }; struct RepNotRecovering : boost::statechart::state< RepNotRecovering, ReplicaActive>, NamedState { typedef boost::mpl::list< boost::statechart::custom_reaction< RequestBackfillPrio >, boost::statechart::transition< RequestRecovery, RepWaitRecoveryReserved >, boost::statechart::transition< RecoveryDone, RepNotRecovering > // for compat with pre-reservation peers > reactions; RepNotRecovering(my_context ctx); boost::statechart::result react(const RequestBackfillPrio &evt); void exit(); }; struct Recovering : boost::statechart::state< Recovering, Active >, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< AllReplicasRecovered >, boost::statechart::custom_reaction< RequestBackfill > > reactions; Recovering(my_context ctx); void exit(); void release_reservations(); boost::statechart::result react(const AllReplicasRecovered &evt); boost::statechart::result react(const RequestBackfill &evt); }; struct WaitRemoteRecoveryReserved : boost::statechart::state< WaitRemoteRecoveryReserved, Active >, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< RemoteRecoveryReserved >, boost::statechart::transition< AllRemotesReserved, Recovering > > reactions; set::const_iterator remote_recovery_reservation_it; WaitRemoteRecoveryReserved(my_context ctx); boost::statechart::result react(const RemoteRecoveryReserved &evt); void exit(); }; struct WaitLocalRecoveryReserved : boost::statechart::state< WaitLocalRecoveryReserved, Active >, NamedState { typedef boost::mpl::list < boost::statechart::transition< LocalRecoveryReserved, WaitRemoteRecoveryReserved > > reactions; WaitLocalRecoveryReserved(my_context ctx); void exit(); }; struct Activating : boost::statechart::state< Activating, Active >, NamedState { typedef boost::mpl::list < boost::statechart::transition< AllReplicasRecovered, Recovered >, boost::statechart::transition< DoRecovery, WaitLocalRecoveryReserved >, boost::statechart::transition< RequestBackfill, WaitLocalBackfillReserved > > reactions; Activating(my_context ctx); void exit(); }; struct Stray : boost::statechart::state< Stray, Started >, NamedState { map > pending_queries; Stray(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< MQuery >, boost::statechart::custom_reaction< MLogRec >, boost::statechart::custom_reaction< MInfoRec >, boost::statechart::custom_reaction< ActMap >, boost::statechart::custom_reaction< RecoveryDone > > reactions; boost::statechart::result react(const MQuery& query); boost::statechart::result react(const MLogRec& logevt); boost::statechart::result react(const MInfoRec& infoevt); boost::statechart::result react(const ActMap&); boost::statechart::result react(const RecoveryDone&) { return discard_event(); } }; struct GetLog; struct GetInfo : boost::statechart::state< GetInfo, Peering >, NamedState { set peer_info_requested; GetInfo(my_context ctx); void exit(); void get_infos(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::transition< GotInfo, GetLog >, boost::statechart::custom_reaction< MNotifyRec > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const MNotifyRec& infoevt); }; struct GetMissing; struct GotLog : boost::statechart::event< GotLog > { GotLog() : boost::statechart::event< GotLog >() {} }; struct GetLog : boost::statechart::state< GetLog, Peering >, NamedState { pg_shard_t auth_log_shard; boost::intrusive_ptr msg; GetLog(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< MLogRec >, boost::statechart::custom_reaction< GotLog >, boost::statechart::custom_reaction< AdvMap >, boost::statechart::transition< IsIncomplete, Incomplete > > reactions; boost::statechart::result react(const AdvMap&); boost::statechart::result react(const QueryState& q); boost::statechart::result react(const MLogRec& logevt); boost::statechart::result react(const GotLog&); }; struct WaitUpThru; struct GetMissing : boost::statechart::state< GetMissing, Peering >, NamedState { set peer_missing_requested; GetMissing(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< MLogRec >, boost::statechart::transition< NeedUpThru, WaitUpThru > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const MLogRec& logevt); }; struct WaitUpThru : boost::statechart::state< WaitUpThru, Peering >, NamedState { WaitUpThru(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::custom_reaction< QueryState >, boost::statechart::custom_reaction< ActMap >, boost::statechart::custom_reaction< MLogRec > > reactions; boost::statechart::result react(const QueryState& q); boost::statechart::result react(const ActMap& am); boost::statechart::result react(const MLogRec& logrec); }; struct Incomplete : boost::statechart::state< Incomplete, Peering>, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< AdvMap >, boost::statechart::custom_reaction< MNotifyRec > > reactions; Incomplete(my_context ctx); boost::statechart::result react(const AdvMap &advmap); boost::statechart::result react(const MNotifyRec& infoevt); void exit(); }; RecoveryMachine machine; PG *pg; /// context passed in by state machine caller RecoveryCtx *orig_ctx; /// populated if we are buffering messages pending a flush boost::optional messages_pending_flush; /** * populated between start_handle() and end_handle(), points into * the message lists for messages_pending_flush while blocking messages * or into orig_ctx otherwise */ boost::optional rctx; public: RecoveryState(PG *pg) : machine(this, pg), pg(pg), orig_ctx(0) { machine.initiate(); } void handle_event(const boost::statechart::event_base &evt, RecoveryCtx *rctx) { start_handle(rctx); machine.process_event(evt); end_handle(); } void handle_event(CephPeeringEvtRef evt, RecoveryCtx *rctx) { start_handle(rctx); machine.process_event(evt->get_event()); end_handle(); } } recovery_state; public: PG(OSDService *o, OSDMapRef curmap, const PGPool &pool, spg_t p, const hobject_t& loid, const hobject_t& ioid); virtual ~PG(); private: // Prevent copying PG(const PG& rhs); PG& operator=(const PG& rhs); uint64_t peer_features; public: spg_t get_pgid() const { return info.pgid; } int get_nrep() const { return acting.size(); } void reset_peer_features() { peer_features = (uint64_t)-1; } uint64_t get_min_peer_features() { return peer_features; } void apply_peer_features(uint64_t f) { peer_features &= f; } void init_primary_up_acting( const vector &newup, const vector &newacting, int new_up_primary, int new_acting_primary) { actingset.clear(); acting = newacting; for (shard_id_t i = 0; i < acting.size(); ++i) { if (acting[i] != CRUSH_ITEM_NONE) actingset.insert( pg_shard_t( acting[i], pool.info.ec_pool() ? i : ghobject_t::NO_SHARD)); } up = newup; if (!pool.info.ec_pool()) { up_primary = pg_shard_t(new_up_primary, ghobject_t::no_shard()); primary = pg_shard_t(new_acting_primary, ghobject_t::no_shard()); return; } up_primary = pg_shard_t(); primary = pg_shard_t(); for (shard_id_t i = 0; i < up.size(); ++i) { if (up[i] == new_up_primary) { up_primary = pg_shard_t(up[i], i); break; } } for (shard_id_t i = 0; i < acting.size(); ++i) { if (acting[i] == new_acting_primary) { primary = pg_shard_t(acting[i], i); break; } } assert(up_primary.osd == new_up_primary); assert(primary.osd == new_acting_primary); } pg_shard_t get_primary() const { return primary; } int get_role() const { return role; } void set_role(int r) { role = r; } bool is_primary() const { return pg_whoami == primary; } bool is_replica() const { return role > 0; } epoch_t get_last_peering_reset() const { return last_peering_reset; } //int get_state() const { return state; } bool state_test(int m) const { return (state & m) != 0; } void state_set(int m) { state |= m; } void state_clear(int m) { state &= ~m; } bool is_complete() const { return info.last_complete == info.last_update; } bool should_send_notify() const { return send_notify; } int get_state() const { return state; } bool is_active() const { return state_test(PG_STATE_ACTIVE); } bool is_peering() const { return state_test(PG_STATE_PEERING); } bool is_down() const { return state_test(PG_STATE_DOWN); } bool is_replay() const { return state_test(PG_STATE_REPLAY); } bool is_clean() const { return state_test(PG_STATE_CLEAN); } bool is_degraded() const { return state_test(PG_STATE_DEGRADED); } bool is_scrubbing() const { return state_test(PG_STATE_SCRUBBING); } bool is_empty() const { return info.last_update == eversion_t(0,0); } void init( int role, vector& up, int up_primary, vector& acting, int acting_primary, pg_history_t& history, pg_interval_map_t& pim, bool backfill, ObjectStore::Transaction *t); // pg on-disk state void do_pending_flush(); private: void write_info(ObjectStore::Transaction& t); public: static int _write_info(ObjectStore::Transaction& t, epoch_t epoch, pg_info_t &info, coll_t coll, map &past_intervals, interval_set &snap_collections, hobject_t &infos_oid, __u8 info_struct_v, bool dirty_big_info, bool force_ver = false); void write_if_dirty(ObjectStore::Transaction& t); eversion_t get_next_version() const { eversion_t at_version(get_osdmap()->get_epoch(), pg_log.get_head().version+1); assert(at_version > info.last_update); assert(at_version > pg_log.get_head()); return at_version; } void add_log_entry(pg_log_entry_t& e, bufferlist& log_bl); void append_log( vector& logv, eversion_t trim_to, eversion_t trim_rollback_to, ObjectStore::Transaction &t, bool transaction_applied = true); bool check_log_for_corruption(ObjectStore *store); void trim_peers(); std::string get_corrupt_pg_log_name() const; static int read_info( ObjectStore *store, const coll_t coll, bufferlist &bl, pg_info_t &info, map &past_intervals, hobject_t &biginfo_oid, hobject_t &infos_oid, interval_set &snap_collections, __u8 &); void read_state(ObjectStore *store, bufferlist &bl); static epoch_t peek_map_epoch(ObjectStore *store, coll_t coll, hobject_t &infos_oid, bufferlist *bl); void update_snap_map( vector &log_entries, ObjectStore::Transaction& t); void filter_snapc(vector &snaps); void log_weirdness(); void queue_snap_trim(); bool queue_scrub(); /// share pg info after a pg is active void share_pg_info(); /// share new pg log entries after a pg is active void share_pg_log(); void reset_interval_flush(); void start_peering_interval( const OSDMapRef lastmap, const vector& newup, int up_primary, const vector& newacting, int acting_primary, ObjectStore::Transaction *t); void start_flush(ObjectStore::Transaction *t, list *on_applied, list *on_safe); void set_last_peering_reset(); bool pg_has_reset_since(epoch_t e) { assert(is_locked()); return deleting || e < get_last_peering_reset(); } void update_history_from_master(pg_history_t new_history); void fulfill_info(pg_shard_t from, const pg_query_t &query, pair ¬ify_info); void fulfill_log(pg_shard_t from, const pg_query_t &query, epoch_t query_epoch); bool is_split(OSDMapRef lastmap, OSDMapRef nextmap); bool acting_up_affected( int newupprimary, int newactingprimary, const vector& newup, const vector& newacting); // OpRequest queueing bool can_discard_op(OpRequestRef op); bool can_discard_scan(OpRequestRef op); bool can_discard_backfill(OpRequestRef op); bool can_discard_request(OpRequestRef op); template bool can_discard_replica_op(OpRequestRef op); static bool op_must_wait_for_map(OSDMapRef curmap, OpRequestRef op); static bool split_request(OpRequestRef op, unsigned match, unsigned bits); bool old_peering_msg(epoch_t reply_epoch, epoch_t query_epoch); bool old_peering_evt(CephPeeringEvtRef evt) { return old_peering_msg(evt->get_epoch_sent(), evt->get_epoch_requested()); } static bool have_same_or_newer_map(OSDMapRef osdmap, epoch_t e) { return e <= osdmap->get_epoch(); } bool have_same_or_newer_map(epoch_t e) { return e <= get_osdmap()->get_epoch(); } bool op_has_sufficient_caps(OpRequestRef op); // recovery bits void take_waiters(); void queue_peering_event(CephPeeringEvtRef evt); void handle_peering_event(CephPeeringEvtRef evt, RecoveryCtx *rctx); void queue_query(epoch_t msg_epoch, epoch_t query_epoch, pg_shard_t from, const pg_query_t& q); void queue_null(epoch_t msg_epoch, epoch_t query_epoch); void queue_flushed(epoch_t started_at); void handle_advance_map( OSDMapRef osdmap, OSDMapRef lastmap, vector& newup, int up_primary, vector& newacting, int acting_primary, RecoveryCtx *rctx); void handle_activate_map(RecoveryCtx *rctx); void handle_create(RecoveryCtx *rctx); void handle_loaded(RecoveryCtx *rctx); void handle_query_state(Formatter *f); virtual void on_removal(ObjectStore::Transaction *t) = 0; // abstract bits virtual void do_request( OpRequestRef op, ThreadPool::TPHandle &handle ) = 0; virtual void do_op(OpRequestRef op) = 0; virtual void do_sub_op(OpRequestRef op) = 0; virtual void do_sub_op_reply(OpRequestRef op) = 0; virtual void do_scan( OpRequestRef op, ThreadPool::TPHandle &handle ) = 0; virtual void do_backfill(OpRequestRef op) = 0; virtual void snap_trimmer() = 0; virtual int do_command(cmdmap_t cmdmap, ostream& ss, bufferlist& idata, bufferlist& odata) = 0; virtual void on_role_change() = 0; virtual void on_pool_change() = 0; virtual void on_change(ObjectStore::Transaction *t) = 0; virtual void on_activate() = 0; virtual void on_flushed() = 0; virtual void on_shutdown() = 0; virtual void check_blacklisted_watchers() = 0; virtual void get_watchers(std::list&) = 0; virtual bool agent_work(int max) = 0; virtual void agent_stop() = 0; virtual void agent_delay() = 0; virtual void agent_clear() = 0; virtual void agent_choose_mode_restart() = 0; }; ostream& operator<<(ostream& out, const PG& pg); #endif ceph-0.80.11/src/osd/ECBackend.cc0000664000175100017510000014536512623076744020335 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "ECUtil.h" #include "ECBackend.h" #include "messages/MOSDPGPush.h" #include "messages/MOSDPGPushReply.h" #define dout_subsys ceph_subsys_osd #define DOUT_PREFIX_ARGS this #undef dout_prefix #define dout_prefix _prefix(_dout, this) static ostream& _prefix(std::ostream *_dout, ECBackend *pgb) { return *_dout << pgb->get_parent()->gen_dbg_prefix(); } struct ECRecoveryHandle : public PGBackend::RecoveryHandle { list ops; }; static ostream &operator<<(ostream &lhs, const map &rhs) { lhs << "["; for (map::const_iterator i = rhs.begin(); i != rhs.end(); ++i) { if (i != rhs.begin()) lhs << ", "; lhs << make_pair(i->first, i->second.length()); } return lhs << "]"; } static ostream &operator<<(ostream &lhs, const map &rhs) { lhs << "["; for (map::const_iterator i = rhs.begin(); i != rhs.end(); ++i) { if (i != rhs.begin()) lhs << ", "; lhs << make_pair(i->first, i->second.length()); } return lhs << "]"; } static ostream &operator<<( ostream &lhs, const boost::tuple > &rhs) { return lhs << "(" << rhs.get<0>() << ", " << rhs.get<1>() << ", " << rhs.get<2>() << ")"; } ostream &operator<<(ostream &lhs, const ECBackend::read_request_t &rhs) { return lhs << "read_request_t(to_read=[" << rhs.to_read << "]" << ", need=" << rhs.need << ", want_attrs=" << rhs.want_attrs << ")"; } ostream &operator<<(ostream &lhs, const ECBackend::read_result_t &rhs) { lhs << "read_result_t(r=" << rhs.r << ", errors=" << rhs.errors; if (rhs.attrs) { lhs << ", attrs=" << rhs.attrs.get(); } else { lhs << ", noattrs"; } return lhs << ", returned=" << rhs.returned; } ostream &operator<<(ostream &lhs, const ECBackend::ReadOp &rhs) { lhs << "ReadOp(tid=" << rhs.tid; if (rhs.op && rhs.op->get_req()) { lhs << ", op="; rhs.op->get_req()->print(lhs); } return lhs << ", to_read=" << rhs.to_read << ", complete=" << rhs.complete << ", priority=" << rhs.priority << ", obj_to_source=" << rhs.obj_to_source << ", source_to_obj=" << rhs.source_to_obj << ", in_progress=" << rhs.in_progress << ")"; } void ECBackend::ReadOp::dump(Formatter *f) const { f->dump_unsigned("tid", tid); if (op && op->get_req()) { f->dump_stream("op") << *(op->get_req()); } f->dump_stream("to_read") << to_read; f->dump_stream("complete") << complete; f->dump_int("priority", priority); f->dump_stream("obj_to_source") << obj_to_source; f->dump_stream("source_to_obj") << source_to_obj; f->dump_stream("in_progress") << in_progress; } ostream &operator<<(ostream &lhs, const ECBackend::Op &rhs) { lhs << "Op(" << rhs.hoid << " v=" << rhs.version << " tt=" << rhs.trim_to << " tid=" << rhs.tid << " reqid=" << rhs.reqid; if (rhs.client_op && rhs.client_op->get_req()) { lhs << " client_op="; rhs.client_op->get_req()->print(lhs); } lhs << " pending_commit=" << rhs.pending_commit << " pending_apply=" << rhs.pending_apply << ")"; return lhs; } ostream &operator<<(ostream &lhs, const ECBackend::RecoveryOp &rhs) { return lhs << "RecoveryOp(" << "hoid=" << rhs.hoid << " v=" << rhs.v << " missing_on=" << rhs.missing_on << " missing_on_shards=" << rhs.missing_on_shards << " recovery_info=" << rhs.recovery_info << " recovery_progress=" << rhs.recovery_progress << " pending_read=" << rhs.pending_read << " obc refcount=" << rhs.obc.use_count() << " state=" << ECBackend::RecoveryOp::tostr(rhs.state) << " waiting_on_pushes=" << rhs.waiting_on_pushes << " extent_requested=" << rhs.extent_requested; } void ECBackend::RecoveryOp::dump(Formatter *f) const { f->dump_stream("hoid") << hoid; f->dump_stream("v") << v; f->dump_stream("missing_on") << missing_on; f->dump_stream("missing_on_shards") << missing_on_shards; f->dump_stream("recovery_info") << recovery_info; f->dump_stream("recovery_progress") << recovery_progress; f->dump_bool("pending_read", pending_read); f->dump_stream("state") << tostr(state); f->dump_stream("waiting_on_pushes") << waiting_on_pushes; f->dump_stream("extent_requested") << extent_requested; } ECBackend::ECBackend( PGBackend::Listener *pg, coll_t coll, coll_t temp_coll, ObjectStore *store, CephContext *cct, ErasureCodeInterfaceRef ec_impl, uint64_t stripe_width) : PGBackend(pg, store, coll, temp_coll), cct(cct), ec_impl(ec_impl), sinfo(ec_impl->get_data_chunk_count(), stripe_width) { assert((ec_impl->get_data_chunk_count() * ec_impl->get_chunk_size(stripe_width)) == stripe_width); } PGBackend::RecoveryHandle *ECBackend::open_recovery_op() { return new ECRecoveryHandle; } struct OnRecoveryReadComplete : public GenContext &> { ECBackend *pg; hobject_t hoid; set want; OnRecoveryReadComplete(ECBackend *pg, const hobject_t &hoid) : pg(pg), hoid(hoid) {} void finish(pair &in) { ECBackend::read_result_t &res = in.second; assert(res.r == 0); assert(res.errors.empty()); assert(res.returned.size() == 1); pg->handle_recovery_read_complete( hoid, res.returned.back(), res.attrs, in.first); } }; struct RecoveryMessages { map reads; void read( ECBackend *ec, const hobject_t &hoid, uint64_t off, uint64_t len, const set &need, bool attrs) { list > to_read; to_read.push_back(make_pair(off, len)); assert(!reads.count(hoid)); reads.insert( make_pair( hoid, ECBackend::read_request_t( hoid, to_read, need, attrs, new OnRecoveryReadComplete( ec, hoid)))); } map > pushes; map > push_replies; ObjectStore::Transaction *t; RecoveryMessages() : t(new ObjectStore::Transaction) {} ~RecoveryMessages() { assert(!t); } }; void ECBackend::handle_recovery_push( PushOp &op, RecoveryMessages *m) { bool oneshot = op.before_progress.first && op.after_progress.data_complete; coll_t tcoll = oneshot ? coll : get_temp_coll(m->t); if (op.before_progress.first) { get_parent()->on_local_recover_start( op.soid, m->t); m->t->remove( get_temp_coll(m->t), ghobject_t( op.soid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); m->t->touch( tcoll, ghobject_t( op.soid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); } if (!op.data_included.empty()) { uint64_t start = op.data_included.range_start(); uint64_t end = op.data_included.range_end(); assert(op.data.length() == (end - start)); m->t->write( tcoll, ghobject_t( op.soid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), start, op.data.length(), op.data); } else { assert(op.data.length() == 0); } if (op.before_progress.first) { if (!oneshot) add_temp_obj(op.soid); assert(op.attrset.count(string("_"))); m->t->setattrs( tcoll, ghobject_t( op.soid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), op.attrset); } if (op.after_progress.data_complete && !oneshot) { clear_temp_obj(op.soid); m->t->collection_move( coll, tcoll, ghobject_t( op.soid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); } if (op.after_progress.data_complete) { if ((get_parent()->pgb_is_primary())) { assert(recovery_ops.count(op.soid)); assert(recovery_ops[op.soid].obc); object_stat_sum_t stats; stats.num_objects_recovered = 1; stats.num_bytes_recovered = recovery_ops[op.soid].obc->obs.oi.size; get_parent()->on_local_recover( op.soid, stats, op.recovery_info, recovery_ops[op.soid].obc, m->t); } else { get_parent()->on_local_recover( op.soid, object_stat_sum_t(), op.recovery_info, ObjectContextRef(), m->t); } } m->push_replies[get_parent()->primary_shard()].push_back(PushReplyOp()); m->push_replies[get_parent()->primary_shard()].back().soid = op.soid; } void ECBackend::handle_recovery_push_reply( PushReplyOp &op, pg_shard_t from, RecoveryMessages *m) { if (!recovery_ops.count(op.soid)) return; RecoveryOp &rop = recovery_ops[op.soid]; assert(rop.waiting_on_pushes.count(from)); rop.waiting_on_pushes.erase(from); continue_recovery_op(rop, m); } void ECBackend::handle_recovery_read_complete( const hobject_t &hoid, boost::tuple > &to_read, boost::optional > attrs, RecoveryMessages *m) { dout(10) << __func__ << ": returned " << hoid << " " << "(" << to_read.get<0>() << ", " << to_read.get<1>() << ", " << to_read.get<2>() << ")" << dendl; assert(recovery_ops.count(hoid)); RecoveryOp &op = recovery_ops[hoid]; assert(op.returned_data.empty()); map target; for (set::iterator i = op.missing_on_shards.begin(); i != op.missing_on_shards.end(); ++i) { target[*i] = &(op.returned_data[*i]); } map from; for(map::iterator i = to_read.get<2>().begin(); i != to_read.get<2>().end(); ++i) { from[i->first.shard].claim(i->second); } dout(10) << __func__ << ": " << from << dendl; ECUtil::decode(sinfo, ec_impl, from, target); if (attrs) { op.xattrs.swap(*attrs); if (!op.obc) { op.obc = get_parent()->get_obc(hoid, op.xattrs); op.recovery_info.size = op.obc->obs.oi.size; op.recovery_info.oi = op.obc->obs.oi; } ECUtil::HashInfo hinfo(ec_impl->get_chunk_count()); if (op.obc->obs.oi.size > 0) { assert(op.xattrs.count(ECUtil::get_hinfo_key())); bufferlist::iterator bp = op.xattrs[ECUtil::get_hinfo_key()].begin(); ::decode(hinfo, bp); } op.hinfo = unstable_hashinfo_registry.lookup_or_create(hoid, hinfo); } assert(op.xattrs.size()); assert(op.obc); continue_recovery_op(op, m); } struct SendPushReplies : public Context { PGBackend::Listener *l; epoch_t epoch; map replies; SendPushReplies( PGBackend::Listener *l, epoch_t epoch, map &in) : l(l), epoch(epoch) { replies.swap(in); } void finish(int) { for (map::iterator i = replies.begin(); i != replies.end(); ++i) { l->send_message_osd_cluster(i->first, i->second, epoch); } replies.clear(); } ~SendPushReplies() { for (map::iterator i = replies.begin(); i != replies.end(); ++i) { i->second->put(); } replies.clear(); } }; void ECBackend::dispatch_recovery_messages(RecoveryMessages &m, int priority) { for (map >::iterator i = m.pushes.begin(); i != m.pushes.end(); m.pushes.erase(i++)) { MOSDPGPush *msg = new MOSDPGPush(); msg->set_priority(priority); msg->map_epoch = get_parent()->get_epoch(); msg->from = get_parent()->whoami_shard(); msg->pgid = spg_t(get_parent()->get_info().pgid.pgid, i->first.shard); msg->pushes.swap(i->second); msg->compute_cost(cct); get_parent()->send_message( i->first.osd, msg); } map replies; for (map >::iterator i = m.push_replies.begin(); i != m.push_replies.end(); m.push_replies.erase(i++)) { MOSDPGPushReply *msg = new MOSDPGPushReply(); msg->set_priority(priority); msg->map_epoch = get_parent()->get_epoch(); msg->from = get_parent()->whoami_shard(); msg->pgid = spg_t(get_parent()->get_info().pgid.pgid, i->first.shard); msg->replies.swap(i->second); msg->compute_cost(cct); replies.insert(make_pair(i->first.osd, msg)); } m.t->register_on_complete( get_parent()->bless_context( new SendPushReplies( get_parent(), get_parent()->get_epoch(), replies))); m.t->register_on_applied( new ObjectStore::C_DeleteTransaction(m.t)); get_parent()->queue_transaction(m.t); m.t = NULL; if (m.reads.empty()) return; start_read_op( priority, m.reads, OpRequestRef()); } void ECBackend::continue_recovery_op( RecoveryOp &op, RecoveryMessages *m) { dout(10) << __func__ << ": continuing " << op << dendl; while (1) { switch (op.state) { case RecoveryOp::IDLE: { // start read op.state = RecoveryOp::READING; assert(!op.recovery_progress.data_complete); set want(op.missing_on_shards.begin(), op.missing_on_shards.end()); set to_read; int r = get_min_avail_to_read_shards( op.hoid, want, true, &to_read); if (r != 0) { // we must have lost a recovery source assert(!op.recovery_progress.first); dout(10) << __func__ << ": canceling recovery op for obj " << op.hoid << dendl; get_parent()->cancel_pull(op.hoid); recovery_ops.erase(op.hoid); return; } assert(r == 0); m->read( this, op.hoid, op.recovery_progress.data_recovered_to, get_recovery_chunk_size(), to_read, op.recovery_progress.first); op.extent_requested = make_pair(op.recovery_progress.data_recovered_to, get_recovery_chunk_size()); dout(10) << __func__ << ": IDLE return " << op << dendl; return; } case RecoveryOp::READING: { // read completed, start write assert(op.xattrs.size()); assert(op.returned_data.size()); op.state = RecoveryOp::WRITING; ObjectRecoveryProgress after_progress = op.recovery_progress; after_progress.data_recovered_to += get_recovery_chunk_size(); after_progress.first = false; if (after_progress.data_recovered_to >= op.obc->obs.oi.size) { after_progress.data_recovered_to = sinfo.logical_to_next_stripe_offset( op.obc->obs.oi.size); after_progress.data_complete = true; } for (set::iterator mi = op.missing_on.begin(); mi != op.missing_on.end(); ++mi) { assert(op.returned_data.count(mi->shard)); m->pushes[*mi].push_back(PushOp()); PushOp &pop = m->pushes[*mi].back(); pop.soid = op.hoid; pop.version = op.v; pop.data = op.returned_data[mi->shard]; dout(10) << __func__ << ": before_progress=" << op.recovery_progress << ", after_progress=" << after_progress << ", pop.data.length()=" << pop.data.length() << ", size=" << op.obc->obs.oi.size << dendl; assert( pop.data.length() == sinfo.aligned_logical_offset_to_chunk_offset( after_progress.data_recovered_to - op.recovery_progress.data_recovered_to) ); if (pop.data.length()) pop.data_included.insert( sinfo.aligned_logical_offset_to_chunk_offset( op.recovery_progress.data_recovered_to), pop.data.length() ); if (op.recovery_progress.first) { pop.attrset = op.xattrs; } pop.recovery_info = op.recovery_info; pop.before_progress = op.recovery_progress; pop.after_progress = after_progress; if (*mi != get_parent()->primary_shard()) get_parent()->begin_peer_recover( *mi, op.hoid); } op.returned_data.clear(); op.waiting_on_pushes = op.missing_on; op.recovery_progress = after_progress; dout(10) << __func__ << ": READING return " << op << dendl; return; } case RecoveryOp::WRITING: { if (op.waiting_on_pushes.empty()) { if (op.recovery_progress.data_complete) { op.state = RecoveryOp::COMPLETE; for (set::iterator i = op.missing_on.begin(); i != op.missing_on.end(); ++i) { if (*i != get_parent()->primary_shard()) { dout(10) << __func__ << ": on_peer_recover on " << *i << ", obj " << op.hoid << dendl; get_parent()->on_peer_recover( *i, op.hoid, op.recovery_info, object_stat_sum_t()); } } get_parent()->on_global_recover(op.hoid); dout(10) << __func__ << ": WRITING return " << op << dendl; recovery_ops.erase(op.hoid); return; } else { op.state = RecoveryOp::IDLE; dout(10) << __func__ << ": WRITING continue " << op << dendl; continue; } } return; } case RecoveryOp::COMPLETE: { assert(0); // should never be called once complete }; default: assert(0); } } } void ECBackend::run_recovery_op( RecoveryHandle *_h, int priority) { ECRecoveryHandle *h = static_cast(_h); RecoveryMessages m; for (list::iterator i = h->ops.begin(); i != h->ops.end(); ++i) { dout(10) << __func__ << ": starting " << *i << dendl; assert(!recovery_ops.count(i->hoid)); RecoveryOp &op = recovery_ops.insert(make_pair(i->hoid, *i)).first->second; continue_recovery_op(op, &m); } dispatch_recovery_messages(m, priority); delete _h; } void ECBackend::recover_object( const hobject_t &hoid, eversion_t v, ObjectContextRef head, ObjectContextRef obc, RecoveryHandle *_h) { ECRecoveryHandle *h = static_cast(_h); h->ops.push_back(RecoveryOp()); h->ops.back().v = v; h->ops.back().hoid = hoid; h->ops.back().obc = obc; h->ops.back().recovery_info.soid = hoid; h->ops.back().recovery_info.version = v; if (obc) { h->ops.back().recovery_info.size = obc->obs.oi.size; h->ops.back().recovery_info.oi = obc->obs.oi; } h->ops.back().recovery_progress.omap_complete = true; for (set::const_iterator i = get_parent()->get_actingbackfill_shards().begin(); i != get_parent()->get_actingbackfill_shards().end(); ++i) { dout(10) << "checking " << *i << dendl; if (get_parent()->get_shard_missing(*i).is_missing(hoid)) { h->ops.back().missing_on.insert(*i); h->ops.back().missing_on_shards.insert(i->shard); } } dout(10) << __func__ << ": built op " << h->ops.back() << dendl; } bool ECBackend::can_handle_while_inactive( OpRequestRef _op) { return false; } bool ECBackend::handle_message( OpRequestRef _op) { dout(10) << __func__ << ": " << *_op->get_req() << dendl; int priority = _op->get_req()->get_priority(); switch (_op->get_req()->get_type()) { case MSG_OSD_EC_WRITE: { MOSDECSubOpWrite *op = static_cast(_op->get_req()); handle_sub_write(op->op.from, _op, op->op); return true; } case MSG_OSD_EC_WRITE_REPLY: { MOSDECSubOpWriteReply *op = static_cast( _op->get_req()); op->set_priority(priority); handle_sub_write_reply(op->op.from, op->op); return true; } case MSG_OSD_EC_READ: { MOSDECSubOpRead *op = static_cast(_op->get_req()); MOSDECSubOpReadReply *reply = new MOSDECSubOpReadReply; reply->pgid = get_parent()->primary_spg_t(); reply->map_epoch = get_parent()->get_epoch(); handle_sub_read(op->op.from, op->op, &(reply->op)); op->set_priority(priority); get_parent()->send_message_osd_cluster( op->op.from.osd, reply, get_parent()->get_epoch()); return true; } case MSG_OSD_EC_READ_REPLY: { MOSDECSubOpReadReply *op = static_cast( _op->get_req()); RecoveryMessages rm; handle_sub_read_reply(op->op.from, op->op, &rm); dispatch_recovery_messages(rm, priority); return true; } case MSG_OSD_PG_PUSH: { MOSDPGPush *op = static_cast(_op->get_req()); RecoveryMessages rm; for (vector::iterator i = op->pushes.begin(); i != op->pushes.end(); ++i) { handle_recovery_push(*i, &rm); } dispatch_recovery_messages(rm, priority); return true; } case MSG_OSD_PG_PUSH_REPLY: { MOSDPGPushReply *op = static_cast(_op->get_req()); RecoveryMessages rm; for (vector::iterator i = op->replies.begin(); i != op->replies.end(); ++i) { handle_recovery_push_reply(*i, op->from, &rm); } dispatch_recovery_messages(rm, priority); return true; } default: return false; } return false; } struct SubWriteCommitted : public Context { ECBackend *pg; OpRequestRef msg; ceph_tid_t tid; eversion_t version; eversion_t last_complete; SubWriteCommitted( ECBackend *pg, OpRequestRef msg, ceph_tid_t tid, eversion_t version, eversion_t last_complete) : pg(pg), msg(msg), tid(tid), version(version), last_complete(last_complete) {} void finish(int) { if (msg) msg->mark_event("sub_op_committed"); pg->sub_write_committed(tid, version, last_complete); } }; void ECBackend::sub_write_committed( ceph_tid_t tid, eversion_t version, eversion_t last_complete) { if (get_parent()->pgb_is_primary()) { ECSubWriteReply reply; reply.tid = tid; reply.last_complete = last_complete; reply.committed = true; reply.from = get_parent()->whoami_shard(); handle_sub_write_reply( get_parent()->whoami_shard(), reply); } else { get_parent()->update_last_complete_ondisk(last_complete); MOSDECSubOpWriteReply *r = new MOSDECSubOpWriteReply; r->pgid = get_parent()->primary_spg_t(); r->map_epoch = get_parent()->get_epoch(); r->op.tid = tid; r->op.last_complete = last_complete; r->op.committed = true; r->op.from = get_parent()->whoami_shard(); get_parent()->send_message_osd_cluster( get_parent()->primary_shard().osd, r, get_parent()->get_epoch()); } } struct SubWriteApplied : public Context { ECBackend *pg; OpRequestRef msg; ceph_tid_t tid; eversion_t version; SubWriteApplied( ECBackend *pg, OpRequestRef msg, ceph_tid_t tid, eversion_t version) : pg(pg), msg(msg), tid(tid), version(version) {} void finish(int) { if (msg) msg->mark_event("sub_op_applied"); pg->sub_write_applied(tid, version); } }; void ECBackend::sub_write_applied( ceph_tid_t tid, eversion_t version) { parent->op_applied(version); if (get_parent()->pgb_is_primary()) { ECSubWriteReply reply; reply.from = get_parent()->whoami_shard(); reply.tid = tid; reply.applied = true; handle_sub_write_reply( get_parent()->whoami_shard(), reply); } else { MOSDECSubOpWriteReply *r = new MOSDECSubOpWriteReply; r->pgid = get_parent()->primary_spg_t(); r->map_epoch = get_parent()->get_epoch(); r->op.from = get_parent()->whoami_shard(); r->op.tid = tid; r->op.applied = true; get_parent()->send_message_osd_cluster( get_parent()->primary_shard().osd, r, get_parent()->get_epoch()); } } void ECBackend::handle_sub_write( pg_shard_t from, OpRequestRef msg, ECSubWrite &op, Context *on_local_applied_sync) { if (msg) msg->mark_started(); assert(!get_parent()->get_log().get_missing().is_missing(op.soid)); if (!get_parent()->pgb_is_primary()) get_parent()->update_stats(op.stats); ObjectStore::Transaction *localt = new ObjectStore::Transaction; if (!op.temp_added.empty()) { get_temp_coll(localt); add_temp_objs(op.temp_added); } if (op.t.empty()) { for (set::iterator i = op.temp_removed.begin(); i != op.temp_removed.end(); ++i) { dout(10) << __func__ << ": removing object " << *i << " since we won't get the transaction" << dendl; localt->remove( temp_coll, ghobject_t( *i, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); } } clear_temp_objs(op.temp_removed); get_parent()->log_operation( op.log_entries, op.updated_hit_set_history, op.trim_to, op.trim_rollback_to, !(op.t.empty()), localt); localt->append(op.t); if (on_local_applied_sync) { dout(10) << "Queueing onreadable_sync: " << on_local_applied_sync << dendl; localt->register_on_applied_sync(on_local_applied_sync); } localt->register_on_commit( get_parent()->bless_context( new SubWriteCommitted( this, msg, op.tid, op.at_version, get_parent()->get_info().last_complete))); localt->register_on_applied( get_parent()->bless_context( new SubWriteApplied(this, msg, op.tid, op.at_version))); localt->register_on_applied( new ObjectStore::C_DeleteTransaction(localt)); get_parent()->queue_transaction(localt, msg); } void ECBackend::handle_sub_read( pg_shard_t from, ECSubRead &op, ECSubReadReply *reply) { for(map > >::iterator i = op.to_read.begin(); i != op.to_read.end(); ++i) { for (list >::iterator j = i->second.begin(); j != i->second.end(); ++j) { bufferlist bl; int r = store->read( i->first.is_temp() ? temp_coll : coll, ghobject_t( i->first, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), j->first, j->second, bl, false); if (r < 0) { assert(0); reply->buffers_read.erase(i->first); reply->errors[i->first] = r; break; } else { reply->buffers_read[i->first].push_back( make_pair( j->first, bl) ); } } } for (set::iterator i = op.attrs_to_read.begin(); i != op.attrs_to_read.end(); ++i) { dout(10) << __func__ << ": fulfilling attr request on " << *i << dendl; if (reply->errors.count(*i)) continue; int r = store->getattrs( i->is_temp() ? temp_coll : coll, ghobject_t( *i, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), reply->attrs_read[*i]); if (r < 0) { assert(0); reply->buffers_read.erase(*i); reply->errors[*i] = r; } } reply->from = get_parent()->whoami_shard(); reply->tid = op.tid; } void ECBackend::handle_sub_write_reply( pg_shard_t from, ECSubWriteReply &op) { map::iterator i = tid_to_op_map.find(op.tid); assert(i != tid_to_op_map.end()); if (op.committed) { assert(i->second.pending_commit.count(from)); i->second.pending_commit.erase(from); if (from != get_parent()->whoami_shard()) { get_parent()->update_peer_last_complete_ondisk(from, op.last_complete); } } if (op.applied) { assert(i->second.pending_apply.count(from)); i->second.pending_apply.erase(from); } check_op(&(i->second)); } void ECBackend::handle_sub_read_reply( pg_shard_t from, ECSubReadReply &op, RecoveryMessages *m) { dout(10) << __func__ << ": reply " << op << dendl; map::iterator iter = tid_to_read_map.find(op.tid); if (iter == tid_to_read_map.end()) { //canceled return; } ReadOp &rop = iter->second; for (map > >::iterator i = op.buffers_read.begin(); i != op.buffers_read.end(); ++i) { assert(!op.errors.count(i->first)); if (!rop.to_read.count(i->first)) { // We canceled this read! @see filter_read_op continue; } list >::const_iterator req_iter = rop.to_read.find(i->first)->second.to_read.begin(); list< boost::tuple< uint64_t, uint64_t, map > >::iterator riter = rop.complete[i->first].returned.begin(); for (list >::iterator j = i->second.begin(); j != i->second.end(); ++j, ++req_iter, ++riter) { assert(req_iter != rop.to_read.find(i->first)->second.to_read.end()); assert(riter != rop.complete[i->first].returned.end()); pair adjusted = sinfo.aligned_offset_len_to_chunk( *req_iter); assert(adjusted.first == j->first); riter->get<2>()[from].claim(j->second); } } for (map >::iterator i = op.attrs_read.begin(); i != op.attrs_read.end(); ++i) { assert(!op.errors.count(i->first)); if (!rop.to_read.count(i->first)) { // We canceled this read! @see filter_read_op continue; } rop.complete[i->first].attrs = map(); (*(rop.complete[i->first].attrs)).swap(i->second); } for (map::iterator i = op.errors.begin(); i != op.errors.end(); ++i) { rop.complete[i->first].errors.insert( make_pair( from, i->second)); if (rop.complete[i->first].r == 0) rop.complete[i->first].r = i->second; } map >::iterator siter = shard_to_read_map.find(from); assert(siter != shard_to_read_map.end()); assert(siter->second.count(op.tid)); siter->second.erase(op.tid); assert(rop.in_progress.count(from)); rop.in_progress.erase(from); if (!rop.in_progress.empty()) { dout(10) << __func__ << " readop not complete: " << rop << dendl; } else { dout(10) << __func__ << " readop complete: " << rop << dendl; complete_read_op(rop, m); } } void ECBackend::complete_read_op(ReadOp &rop, RecoveryMessages *m) { map::iterator reqiter = rop.to_read.begin(); map::iterator resiter = rop.complete.begin(); assert(rop.to_read.size() == rop.complete.size()); for (; reqiter != rop.to_read.end(); ++reqiter, ++resiter) { if (reqiter->second.cb) { pair arg( m, resiter->second); reqiter->second.cb->complete(arg); reqiter->second.cb = NULL; } } tid_to_read_map.erase(rop.tid); } struct FinishReadOp : public GenContext { ECBackend *ec; ceph_tid_t tid; FinishReadOp(ECBackend *ec, ceph_tid_t tid) : ec(ec), tid(tid) {} void finish(ThreadPool::TPHandle &handle) { assert(ec->tid_to_read_map.count(tid)); int priority = ec->tid_to_read_map[tid].priority; RecoveryMessages rm; ec->complete_read_op(ec->tid_to_read_map[tid], &rm); ec->dispatch_recovery_messages(rm, priority); } }; void ECBackend::filter_read_op( const OSDMapRef osdmap, ReadOp &op) { set to_cancel; for (map >::iterator i = op.source_to_obj.begin(); i != op.source_to_obj.end(); ++i) { if (osdmap->is_down(i->first.osd)) { to_cancel.insert(i->second.begin(), i->second.end()); op.in_progress.erase(i->first); continue; } } if (to_cancel.empty()) return; for (map >::iterator i = op.source_to_obj.begin(); i != op.source_to_obj.end(); ) { for (set::iterator j = i->second.begin(); j != i->second.end(); ) { if (to_cancel.count(*j)) i->second.erase(j++); else ++j; } if (i->second.empty()) { op.source_to_obj.erase(i++); } else { assert(!osdmap->is_down(i->first.osd)); ++i; } } for (set::iterator i = to_cancel.begin(); i != to_cancel.end(); ++i) { get_parent()->cancel_pull(*i); assert(op.to_read.count(*i)); read_request_t &req = op.to_read.find(*i)->second; dout(10) << __func__ << ": canceling " << req << " for obj " << *i << dendl; assert(req.cb); delete req.cb; req.cb = NULL; op.to_read.erase(*i); op.complete.erase(*i); recovery_ops.erase(*i); } if (op.in_progress.empty()) { get_parent()->schedule_work( get_parent()->bless_gencontext( new FinishReadOp(this, op.tid))); } }; void ECBackend::check_recovery_sources(const OSDMapRef osdmap) { set tids_to_filter; for (map >::iterator i = shard_to_read_map.begin(); i != shard_to_read_map.end(); ) { if (osdmap->is_down(i->first.osd)) { tids_to_filter.insert(i->second.begin(), i->second.end()); shard_to_read_map.erase(i++); } else { ++i; } } for (set::iterator i = tids_to_filter.begin(); i != tids_to_filter.end(); ++i) { map::iterator j = tid_to_read_map.find(*i); assert(j != tid_to_read_map.end()); filter_read_op(osdmap, j->second); } } void ECBackend::on_change() { dout(10) << __func__ << dendl; writing.clear(); tid_to_op_map.clear(); for (map::iterator i = tid_to_read_map.begin(); i != tid_to_read_map.end(); ++i) { dout(10) << __func__ << ": cancelling " << i->second << dendl; for (map::iterator j = i->second.to_read.begin(); j != i->second.to_read.end(); ++j) { delete j->second.cb; j->second.cb = 0; } } tid_to_read_map.clear(); for (list::iterator i = in_progress_client_reads.begin(); i != in_progress_client_reads.end(); ++i) { delete i->on_complete; i->on_complete = NULL; } in_progress_client_reads.clear(); shard_to_read_map.clear(); clear_state(); } void ECBackend::clear_state() { recovery_ops.clear(); } void ECBackend::on_flushed() { } void ECBackend::dump_recovery_info(Formatter *f) const { f->open_array_section("recovery_ops"); for (map::const_iterator i = recovery_ops.begin(); i != recovery_ops.end(); ++i) { f->open_object_section("op"); i->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("read_ops"); for (map::const_iterator i = tid_to_read_map.begin(); i != tid_to_read_map.end(); ++i) { f->open_object_section("read_op"); i->second.dump(f); f->close_section(); } f->close_section(); } PGBackend::PGTransaction *ECBackend::get_transaction() { return new ECTransaction; } struct MustPrependHashInfo : public ObjectModDesc::Visitor { enum { EMPTY, FOUND_APPEND, FOUND_CREATE_STASH } state; MustPrependHashInfo() : state(EMPTY) {} void append(uint64_t) { if (state == EMPTY) { state = FOUND_APPEND; } } void rmobject(version_t) { if (state == EMPTY) { state = FOUND_CREATE_STASH; } } void create() { if (state == EMPTY) { state = FOUND_CREATE_STASH; } } bool must_prepend_hash_info() const { return state == FOUND_APPEND; } }; void ECBackend::submit_transaction( const hobject_t &hoid, const eversion_t &at_version, PGTransaction *_t, const eversion_t &trim_to, const eversion_t &trim_rollback_to, vector &log_entries, boost::optional &hset_history, Context *on_local_applied_sync, Context *on_all_applied, Context *on_all_commit, ceph_tid_t tid, osd_reqid_t reqid, OpRequestRef client_op ) { assert(!tid_to_op_map.count(tid)); Op *op = &(tid_to_op_map[tid]); op->hoid = hoid; op->version = at_version; op->trim_to = trim_to; op->trim_rollback_to = trim_rollback_to; op->log_entries.swap(log_entries); std::swap(op->updated_hit_set_history, hset_history); op->on_local_applied_sync = on_local_applied_sync; op->on_all_applied = on_all_applied; op->on_all_commit = on_all_commit; op->tid = tid; op->reqid = reqid; op->client_op = client_op; op->t = static_cast(_t); set need_hinfos; op->t->get_append_objects(&need_hinfos); for (set::iterator i = need_hinfos.begin(); i != need_hinfos.end(); ++i) { ECUtil::HashInfoRef ref = get_hash_info(*i); if (!ref) { derr << __func__ << ": get_hash_info(" << *i << ")" << " returned a null pointer and there is no " << " way to recover from such an error in this " << " context" << dendl; assert(0); } op->unstable_hash_infos.insert( make_pair( *i, ref)); } for (vector::iterator i = op->log_entries.begin(); i != op->log_entries.end(); ++i) { MustPrependHashInfo vis; i->mod_desc.visit(&vis); if (vis.must_prepend_hash_info()) { dout(10) << __func__ << ": stashing HashInfo for " << i->soid << " for entry " << *i << dendl; assert(op->unstable_hash_infos.count(i->soid)); ObjectModDesc desc; map > old_attrs; bufferlist old_hinfo; ::encode(*(op->unstable_hash_infos[i->soid]), old_hinfo); old_attrs[ECUtil::get_hinfo_key()] = old_hinfo; desc.setattrs(old_attrs); i->mod_desc.swap(desc); i->mod_desc.claim_append(desc); assert(i->mod_desc.can_rollback()); } } dout(10) << __func__ << ": op " << *op << " starting" << dendl; start_write(op); writing.push_back(op); dout(10) << "onreadable_sync: " << op->on_local_applied_sync << dendl; } int ECBackend::get_min_avail_to_read_shards( const hobject_t &hoid, const set &want, bool for_recovery, set *to_read) { map >::const_iterator miter = get_parent()->get_missing_loc_shards().find(hoid); set have; map shards; for (set::const_iterator i = get_parent()->get_acting_shards().begin(); i != get_parent()->get_acting_shards().end(); ++i) { dout(10) << __func__ << ": checking acting " << *i << dendl; const pg_missing_t &missing = get_parent()->get_shard_missing(*i); if (!missing.is_missing(hoid)) { assert(!have.count(i->shard)); have.insert(i->shard); assert(!shards.count(i->shard)); shards.insert(make_pair(i->shard, *i)); } } if (for_recovery) { for (set::const_iterator i = get_parent()->get_backfill_shards().begin(); i != get_parent()->get_backfill_shards().end(); ++i) { if (have.count(i->shard)) { assert(shards.count(i->shard)); continue; } dout(10) << __func__ << ": checking backfill " << *i << dendl; assert(!shards.count(i->shard)); const pg_info_t &info = get_parent()->get_shard_info(*i); const pg_missing_t &missing = get_parent()->get_shard_missing(*i); if (hoid < info.last_backfill && !missing.is_missing(hoid)) { have.insert(i->shard); shards.insert(make_pair(i->shard, *i)); } } if (miter != get_parent()->get_missing_loc_shards().end()) { for (set::iterator i = miter->second.begin(); i != miter->second.end(); ++i) { dout(10) << __func__ << ": checking missing_loc " << *i << dendl; boost::optional m = get_parent()->maybe_get_shard_missing(*i); if (m) { assert(!(*m).is_missing(hoid)); } have.insert(i->shard); shards.insert(make_pair(i->shard, *i)); } } } set need; int r = ec_impl->minimum_to_decode(want, have, &need); if (r < 0) return r; if (!to_read) return 0; for (set::iterator i = need.begin(); i != need.end(); ++i) { assert(shards.count(*i)); to_read->insert(shards[*i]); } return 0; } void ECBackend::start_read_op( int priority, map &to_read, OpRequestRef _op) { ceph_tid_t tid = get_parent()->get_tid(); assert(!tid_to_read_map.count(tid)); ReadOp &op(tid_to_read_map[tid]); op.priority = priority; op.tid = tid; op.to_read.swap(to_read); op.op = _op; dout(10) << __func__ << ": starting " << op << dendl; map messages; for (map::iterator i = op.to_read.begin(); i != op.to_read.end(); ++i) { list > > &reslist = op.complete[i->first].returned; bool need_attrs = i->second.want_attrs; for (set::const_iterator j = i->second.need.begin(); j != i->second.need.end(); ++j) { if (need_attrs) { messages[*j].attrs_to_read.insert(i->first); need_attrs = false; } op.obj_to_source[i->first].insert(*j); op.source_to_obj[*j].insert(i->first); } for (list >::const_iterator j = i->second.to_read.begin(); j != i->second.to_read.end(); ++j) { reslist.push_back( boost::make_tuple( j->first, j->second, map())); pair chunk_off_len = sinfo.aligned_offset_len_to_chunk( *j); for (set::const_iterator k = i->second.need.begin(); k != i->second.need.end(); ++k) { messages[*k].to_read[i->first].push_back(chunk_off_len); } assert(!need_attrs); } } for (map::iterator i = messages.begin(); i != messages.end(); ++i) { op.in_progress.insert(i->first); shard_to_read_map[i->first].insert(op.tid); i->second.tid = tid; MOSDECSubOpRead *msg = new MOSDECSubOpRead; msg->set_priority(priority); msg->pgid = spg_t( get_parent()->whoami_spg_t().pgid, i->first.shard); msg->map_epoch = get_parent()->get_epoch(); msg->op = i->second; msg->op.from = get_parent()->whoami_shard(); msg->op.tid = tid; get_parent()->send_message_osd_cluster( i->first.osd, msg, get_parent()->get_epoch()); } dout(10) << __func__ << ": started " << op << dendl; } ECUtil::HashInfoRef ECBackend::get_hash_info( const hobject_t &hoid) { dout(10) << __func__ << ": Getting attr on " << hoid << dendl; ECUtil::HashInfoRef ref = unstable_hashinfo_registry.lookup(hoid); if (!ref) { dout(10) << __func__ << ": not in cache " << hoid << dendl; struct stat st; int r = store->stat( hoid.is_temp() ? temp_coll : coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), &st); ECUtil::HashInfo hinfo(ec_impl->get_chunk_count()); if (r >= 0 && st.st_size > 0) { dout(10) << __func__ << ": found on disk, size " << st.st_size << dendl; bufferlist bl; r = store->getattr( hoid.is_temp() ? temp_coll : coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), ECUtil::get_hinfo_key(), bl); if (r >= 0) { bufferlist::iterator bp = bl.begin(); ::decode(hinfo, bp); assert(hinfo.get_total_chunk_size() == (unsigned)st.st_size); } else { return ECUtil::HashInfoRef(); } } ref = unstable_hashinfo_registry.lookup_or_create(hoid, hinfo); } return ref; } void ECBackend::check_op(Op *op) { if (op->pending_apply.empty() && op->on_all_applied) { dout(10) << __func__ << " Calling on_all_applied on " << *op << dendl; op->on_all_applied->complete(0); op->on_all_applied = 0; } if (op->pending_commit.empty() && op->on_all_commit) { dout(10) << __func__ << " Calling on_all_commit on " << *op << dendl; op->on_all_commit->complete(0); op->on_all_commit = 0; } if (op->pending_apply.empty() && op->pending_commit.empty()) { // done! assert(writing.front() == op); dout(10) << __func__ << " Completing " << *op << dendl; writing.pop_front(); tid_to_op_map.erase(op->tid); } for (map::iterator i = tid_to_op_map.begin(); i != tid_to_op_map.end(); ++i) { dout(20) << __func__ << " tid " << i->first <<": " << i->second << dendl; } } void ECBackend::start_write(Op *op) { map trans; for (set::const_iterator i = get_parent()->get_actingbackfill_shards().begin(); i != get_parent()->get_actingbackfill_shards().end(); ++i) { trans[i->shard]; } op->t->generate_transactions( op->unstable_hash_infos, ec_impl, get_parent()->get_info().pgid.pgid, sinfo, &trans, &(op->temp_added), &(op->temp_cleared)); dout(10) << "onreadable_sync: " << op->on_local_applied_sync << dendl; for (set::const_iterator i = get_parent()->get_actingbackfill_shards().begin(); i != get_parent()->get_actingbackfill_shards().end(); ++i) { op->pending_apply.insert(*i); op->pending_commit.insert(*i); map::iterator iter = trans.find(i->shard); assert(iter != trans.end()); bool should_send = get_parent()->should_send_op(*i, op->hoid); pg_stat_t stats = should_send ? get_info().stats : parent->get_shard_info().find(*i)->second.stats; ECSubWrite sop( get_parent()->whoami_shard(), op->tid, op->reqid, op->hoid, stats, should_send ? iter->second : ObjectStore::Transaction(), op->version, op->trim_to, op->trim_rollback_to, op->log_entries, op->updated_hit_set_history, op->temp_added, op->temp_cleared); if (*i == get_parent()->whoami_shard()) { handle_sub_write( get_parent()->whoami_shard(), op->client_op, sop, op->on_local_applied_sync); op->on_local_applied_sync = 0; } else { MOSDECSubOpWrite *r = new MOSDECSubOpWrite(sop); r->set_priority(cct->_conf->osd_client_op_priority); r->pgid = spg_t(get_parent()->primary_spg_t().pgid, i->shard); r->map_epoch = get_parent()->get_epoch(); get_parent()->send_message_osd_cluster( i->osd, r, get_parent()->get_epoch()); } } } int ECBackend::objects_read_sync( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist *bl) { return -EOPNOTSUPP; } struct CallClientContexts : public GenContext &> { ECBackend *ec; ECBackend::ClientAsyncReadStatus *status; list, pair > > to_read; CallClientContexts( ECBackend *ec, ECBackend::ClientAsyncReadStatus *status, const list, pair > > &to_read) : ec(ec), status(status), to_read(to_read) {} void finish(pair &in) { ECBackend::read_result_t &res = in.second; assert(res.returned.size() == to_read.size()); assert(res.r == 0); assert(res.errors.empty()); for (list, pair > >::iterator i = to_read.begin(); i != to_read.end(); to_read.erase(i++)) { pair adjusted = ec->sinfo.offset_len_to_stripe_bounds(i->first); assert(res.returned.front().get<0>() == adjusted.first && res.returned.front().get<1>() == adjusted.second); map to_decode; bufferlist bl; for (map::iterator j = res.returned.front().get<2>().begin(); j != res.returned.front().get<2>().end(); ++j) { to_decode[j->first.shard].claim(j->second); } ECUtil::decode( ec->sinfo, ec->ec_impl, to_decode, &bl); assert(i->second.second); assert(i->second.first); i->second.first->substr_of( bl, i->first.first - adjusted.first, MIN(i->first.second, bl.length() - (i->first.first - adjusted.first))); if (i->second.second) { i->second.second->complete(i->second.first->length()); } res.returned.pop_front(); } status->complete = true; list &ip = ec->in_progress_client_reads; while (ip.size() && ip.front().complete) { if (ip.front().on_complete) { ip.front().on_complete->complete(0); ip.front().on_complete = NULL; } ip.pop_front(); } } ~CallClientContexts() { for (list, pair > >::iterator i = to_read.begin(); i != to_read.end(); to_read.erase(i++)) { delete i->second.second; } } }; void ECBackend::objects_read_async( const hobject_t &hoid, const list, pair > > &to_read, Context *on_complete) { in_progress_client_reads.push_back(ClientAsyncReadStatus(on_complete)); CallClientContexts *c = new CallClientContexts( this, &(in_progress_client_reads.back()), to_read); list > offsets; for (list, pair > >::const_iterator i = to_read.begin(); i != to_read.end(); ++i) { offsets.push_back( sinfo.offset_len_to_stripe_bounds(i->first)); } set want_to_read; for (int i = 0; i < (int)ec_impl->get_data_chunk_count(); ++i) { want_to_read.insert(i); } set shards; int r = get_min_avail_to_read_shards( hoid, want_to_read, false, &shards); assert(r == 0); map for_read_op; for_read_op.insert( make_pair( hoid, read_request_t( hoid, offsets, shards, false, c))); start_read_op( cct->_conf->osd_client_op_priority, for_read_op, OpRequestRef()); return; } int ECBackend::objects_get_attrs( const hobject_t &hoid, map *out) { int r = store->getattrs( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), *out); if (r < 0) return r; for (map::iterator i = out->begin(); i != out->end(); ) { if (ECUtil::is_hinfo_key_string(i->first)) out->erase(i++); else ++i; } return r; } void ECBackend::rollback_append( const hobject_t &hoid, uint64_t old_size, ObjectStore::Transaction *t) { assert(old_size % sinfo.get_stripe_width() == 0); t->truncate( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), sinfo.aligned_logical_offset_to_chunk_offset( old_size)); } void ECBackend::be_deep_scrub( const hobject_t &poid, ScrubMap::object &o, ThreadPool::TPHandle &handle) { bufferhash h(-1); int r; uint64_t stride = cct->_conf->osd_deep_scrub_stride; if (stride % sinfo.get_chunk_size()) stride += sinfo.get_chunk_size() - (stride % sinfo.get_chunk_size()); uint64_t pos = 0; while (true) { bufferlist bl; handle.reset_tp_timeout(); r = store->read( coll, ghobject_t( poid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), pos, stride, bl, true); if (r < 0) break; if (bl.length() % sinfo.get_chunk_size()) { r = -EIO; break; } pos += r; h << bl; if ((unsigned)r < stride) break; } if (r == -EIO) { dout(0) << "_scan_list " << poid << " got " << r << " on read, read_error" << dendl; o.read_error = true; } ECUtil::HashInfoRef hinfo = get_hash_info(poid); if (!hinfo) { dout(0) << "_scan_list " << poid << " could not retrieve hash info" << dendl; o.read_error = true; o.digest_present = false; } else { if (hinfo->get_chunk_hash(get_parent()->whoami_shard().shard) != h.digest()) { dout(0) << "_scan_list " << poid << " got incorrect hash on read" << dendl; o.read_error = true; } if (hinfo->get_total_chunk_size() != pos) { dout(0) << "_scan_list " << poid << " got incorrect size on read" << dendl; o.read_error = true; } /* We checked above that we match our own stored hash. We cannot * send a hash of the actual object, so instead we simply send * our locally stored hash of shard 0 on the assumption that if * we match our chunk hash and our recollection of the hash for * chunk 0 matches that of our peers, there is likely no corruption. */ o.digest = hinfo->get_chunk_hash(0); o.digest_present = true; } o.omap_digest = 0; o.omap_digest_present = true; } ceph-0.80.11/src/osd/PGBackend.cc0000664000175100017510000003647412623076744020354 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Inktank Storage, Inc. * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/errno.h" #include "ReplicatedBackend.h" #include "ECBackend.h" #include "PGBackend.h" #include "OSD.h" #include "erasure-code/ErasureCodePlugin.h" #define dout_subsys ceph_subsys_osd #define DOUT_PREFIX_ARGS this #undef dout_prefix #define dout_prefix _prefix(_dout, this) static ostream& _prefix(std::ostream *_dout, PGBackend *pgb) { return *_dout << pgb->get_parent()->gen_dbg_prefix(); } // -- ObjectModDesc -- struct RollbackVisitor : public ObjectModDesc::Visitor { const hobject_t &hoid; PGBackend *pg; ObjectStore::Transaction t; RollbackVisitor( const hobject_t &hoid, PGBackend *pg) : hoid(hoid), pg(pg) {} void append(uint64_t old_size) { ObjectStore::Transaction temp; pg->rollback_append(hoid, old_size, &temp); temp.append(t); temp.swap(t); } void setattrs(map > &attrs) { ObjectStore::Transaction temp; pg->rollback_setattrs(hoid, attrs, &temp); temp.append(t); temp.swap(t); } void rmobject(version_t old_version) { ObjectStore::Transaction temp; pg->rollback_stash(hoid, old_version, &temp); temp.append(t); temp.swap(t); } void create() { ObjectStore::Transaction temp; pg->rollback_create(hoid, &temp); temp.append(t); temp.swap(t); } void update_snaps(set &snaps) { // pass } }; void PGBackend::rollback( const hobject_t &hoid, const ObjectModDesc &desc, ObjectStore::Transaction *t) { assert(desc.can_rollback()); RollbackVisitor vis(hoid, this); desc.visit(&vis); t->append(vis.t); } void PGBackend::on_change_cleanup(ObjectStore::Transaction *t) { dout(10) << __func__ << dendl; // clear temp for (set::iterator i = temp_contents.begin(); i != temp_contents.end(); ++i) { dout(10) << __func__ << ": Removing oid " << *i << " from the temp collection" << dendl; t->remove( get_temp_coll(t), ghobject_t(*i, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); } temp_contents.clear(); } coll_t PGBackend::get_temp_coll(ObjectStore::Transaction *t) { if (temp_created) return temp_coll; if (!store->collection_exists(temp_coll)) t->create_collection(temp_coll); temp_created = true; return temp_coll; } int PGBackend::objects_list_partial( const hobject_t &begin, int min, int max, snapid_t seq, vector *ls, hobject_t *next) { assert(ls); // Starts with the smallest shard id and generation to // make sure the result list has the marker object ( // it might have multiple generations though, which would // be filtered). ghobject_t _next(begin, 0, shard_id_t(0)); ls->reserve(max); int r = 0; while (!_next.is_max() && ls->size() < (unsigned)min) { vector objects; int r = store->collection_list_partial( coll, _next, min - ls->size(), max - ls->size(), seq, &objects, &_next); if (r != 0) break; for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { if (i->is_no_gen()) { ls->push_back(i->hobj); } } } if (r == 0) *next = _next.hobj; return r; } int PGBackend::objects_list_range( const hobject_t &start, const hobject_t &end, snapid_t seq, vector *ls, vector *gen_obs) { assert(ls); vector objects; int r = store->collection_list_range( coll, start, end, seq, &objects); ls->reserve(objects.size()); for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { if (i->is_no_gen()) { ls->push_back(i->hobj); } else if (gen_obs) { gen_obs->push_back(*i); } } return r; } int PGBackend::objects_get_attr( const hobject_t &hoid, const string &attr, bufferlist *out) { bufferptr bp; int r = store->getattr( hoid.is_temp() ? temp_coll : coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), attr.c_str(), bp); if (r >= 0 && out) { out->clear(); out->push_back(bp); } return r; } int PGBackend::objects_get_attrs( const hobject_t &hoid, map *out) { return store->getattrs( hoid.is_temp() ? temp_coll : coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), *out); } void PGBackend::rollback_setattrs( const hobject_t &hoid, map > &old_attrs, ObjectStore::Transaction *t) { map to_set; set to_remove; assert(!hoid.is_temp()); for (map >::iterator i = old_attrs.begin(); i != old_attrs.end(); ++i) { if (i->second) { to_set[i->first] = i->second.get(); } else { t->rmattr( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), i->first); } } t->setattrs( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), to_set); } void PGBackend::rollback_append( const hobject_t &hoid, uint64_t old_size, ObjectStore::Transaction *t) { assert(!hoid.is_temp()); t->truncate( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), old_size); } void PGBackend::rollback_stash( const hobject_t &hoid, version_t old_version, ObjectStore::Transaction *t) { assert(!hoid.is_temp()); t->remove( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); t->collection_move_rename( coll, ghobject_t(hoid, old_version, get_parent()->whoami_shard().shard), coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); } void PGBackend::rollback_create( const hobject_t &hoid, ObjectStore::Transaction *t) { assert(!hoid.is_temp()); t->remove( coll, ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard)); } void PGBackend::trim_stashed_object( const hobject_t &hoid, version_t old_version, ObjectStore::Transaction *t) { assert(!hoid.is_temp()); t->remove( coll, ghobject_t(hoid, old_version, get_parent()->whoami_shard().shard)); } PGBackend *PGBackend::build_pg_backend( const pg_pool_t &pool, const OSDMapRef curmap, Listener *l, coll_t coll, coll_t temp_coll, ObjectStore *store, CephContext *cct) { switch (pool.type) { case pg_pool_t::TYPE_REPLICATED: { return new ReplicatedBackend(l, coll, temp_coll, store, cct); } case pg_pool_t::TYPE_ERASURE: { ErasureCodeInterfaceRef ec_impl; const map &profile = curmap->get_erasure_code_profile(pool.erasure_code_profile); assert(profile.count("plugin")); stringstream ss; ceph::ErasureCodePluginRegistry::instance().factory( profile.find("plugin")->second, profile, &ec_impl, ss); assert(ec_impl); return new ECBackend( l, coll, temp_coll, store, cct, ec_impl, pool.stripe_width); } default: assert(0); return NULL; } } /* * pg lock may or may not be held */ void PGBackend::be_scan_list( ScrubMap &map, const vector &ls, bool deep, ThreadPool::TPHandle &handle) { dout(10) << "_scan_list scanning " << ls.size() << " objects" << (deep ? " deeply" : "") << dendl; int i = 0; for (vector::const_iterator p = ls.begin(); p != ls.end(); ++p, i++) { handle.reset_tp_timeout(); hobject_t poid = *p; struct stat st; int r = store->stat( coll, ghobject_t( poid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), &st, true); if (r == 0) { ScrubMap::object &o = map.objects[poid]; o.size = st.st_size; assert(!o.negative); store->getattrs( coll, ghobject_t( poid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard), o.attrs); // calculate the CRC32 on deep scrubs if (deep) { be_deep_scrub(*p, o, handle); } dout(25) << "_scan_list " << poid << dendl; } else if (r == -ENOENT) { dout(25) << "_scan_list " << poid << " got " << r << ", skipping" << dendl; } else if (r == -EIO) { dout(25) << "_scan_list " << poid << " got " << r << ", read_error" << dendl; ScrubMap::object &o = map.objects[poid]; o.read_error = true; } else { derr << "_scan_list got: " << cpp_strerror(r) << dendl; assert(0); } } } enum scrub_error_type PGBackend::be_compare_scrub_objects( const ScrubMap::object &auth, const ScrubMap::object &candidate, ostream &errorstream) { enum scrub_error_type error = CLEAN; if (candidate.read_error) { // This can occur on stat() of a shallow scrub, but in that case size will // be invalid, and this will be over-ridden below. error = DEEP_ERROR; errorstream << "candidate had a read error"; } if (auth.digest_present && candidate.digest_present) { if (auth.digest != candidate.digest) { if (error != CLEAN) errorstream << ", "; error = DEEP_ERROR; errorstream << "digest " << candidate.digest << " != known digest " << auth.digest; } } if (auth.omap_digest_present && candidate.omap_digest_present) { if (auth.omap_digest != candidate.omap_digest) { if (error != CLEAN) errorstream << ", "; error = DEEP_ERROR; errorstream << "omap_digest " << candidate.omap_digest << " != known omap_digest " << auth.omap_digest; } } // Shallow error takes precendence because this will be seen by // both types of scrubs. if (auth.size != candidate.size) { if (error != CLEAN) errorstream << ", "; error = SHALLOW_ERROR; errorstream << "size " << candidate.size << " != known size " << auth.size; } for (map::const_iterator i = auth.attrs.begin(); i != auth.attrs.end(); ++i) { if (!candidate.attrs.count(i->first)) { if (error != CLEAN) errorstream << ", "; error = SHALLOW_ERROR; errorstream << "missing attr " << i->first; } else if (candidate.attrs.find(i->first)->second.cmp(i->second)) { if (error != CLEAN) errorstream << ", "; error = SHALLOW_ERROR; errorstream << "attr value mismatch " << i->first; } } for (map::const_iterator i = candidate.attrs.begin(); i != candidate.attrs.end(); ++i) { if (!auth.attrs.count(i->first)) { if (error != CLEAN) errorstream << ", "; error = SHALLOW_ERROR; errorstream << "extra attr " << i->first; } } return error; } map::const_iterator PGBackend::be_select_auth_object( const hobject_t &obj, const map &maps) { map::const_iterator auth = maps.end(); for (map::const_iterator j = maps.begin(); j != maps.end(); ++j) { map::iterator i = j->second->objects.find(obj); if (i == j->second->objects.end()) { continue; } if (auth == maps.end()) { // Something is better than nothing // TODO: something is NOT better than nothing, do something like // unfound_lost if no valid copies can be found, or just mark unfound auth = j; dout(10) << __func__ << ": selecting osd " << j->first << " for obj " << obj << ", auth == maps.end()" << dendl; continue; } if (i->second.read_error) { // scrub encountered read error, probably corrupt dout(10) << __func__ << ": rejecting osd " << j->first << " for obj " << obj << ", read_error" << dendl; continue; } map::iterator k = i->second.attrs.find(OI_ATTR); if (k == i->second.attrs.end()) { // no object info on object, probably corrupt dout(10) << __func__ << ": rejecting osd " << j->first << " for obj " << obj << ", no oi attr" << dendl; continue; } bufferlist bl; bl.push_back(k->second); object_info_t oi; try { bufferlist::iterator bliter = bl.begin(); ::decode(oi, bliter); } catch (...) { dout(10) << __func__ << ": rejecting osd " << j->first << " for obj " << obj << ", corrupt oi attr" << dendl; // invalid object info, probably corrupt continue; } uint64_t correct_size = be_get_ondisk_size(oi.size); if (correct_size != i->second.size) { // invalid size, probably corrupt dout(10) << __func__ << ": rejecting osd " << j->first << " for obj " << obj << ", size mismatch" << dendl; // invalid object info, probably corrupt continue; } dout(10) << __func__ << ": selecting osd " << j->first << " for obj " << obj << dendl; auth = j; } return auth; } void PGBackend::be_compare_scrubmaps( const map &maps, map > &missing, map > &inconsistent, map &authoritative, map > &invalid_snapcolls, int &shallow_errors, int &deep_errors, const spg_t pgid, const vector &acting, ostream &errorstream) { map::const_iterator i; map::const_iterator j; set master_set; // Construct master set for (j = maps.begin(); j != maps.end(); ++j) { for (i = j->second->objects.begin(); i != j->second->objects.end(); ++i) { master_set.insert(i->first); } } // Check maps against master set and each other for (set::const_iterator k = master_set.begin(); k != master_set.end(); ++k) { map::const_iterator auth = be_select_auth_object(*k, maps); assert(auth != maps.end()); set cur_missing; set cur_inconsistent; for (j = maps.begin(); j != maps.end(); ++j) { if (j == auth) continue; if (j->second->objects.count(*k)) { // Compare stringstream ss; enum scrub_error_type error = be_compare_scrub_objects(auth->second->objects[*k], j->second->objects[*k], ss); if (error != CLEAN) { cur_inconsistent.insert(j->first); if (error == SHALLOW_ERROR) ++shallow_errors; else ++deep_errors; errorstream << pgid << " shard " << j->first << ": soid " << *k << " " << ss.str() << std::endl; } } else { cur_missing.insert(j->first); ++shallow_errors; errorstream << pgid << " shard " << j->first << " missing " << *k << std::endl; } } assert(auth != maps.end()); if (!cur_missing.empty()) { missing[*k] = cur_missing; } if (!cur_inconsistent.empty()) { inconsistent[*k] = cur_inconsistent; } if (!cur_inconsistent.empty() || !cur_missing.empty()) { authoritative[*k] = auth->first; } } } ceph-0.80.11/src/osd/ClassHandler.h0000664000175100017510000000426012623076744020767 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLASSHANDLER_H #define CEPH_CLASSHANDLER_H #include "include/types.h" #include "objclass/objclass.h" #include "common/Cond.h" #include "common/Mutex.h" #include "common/ceph_context.h" class ClassHandler { public: CephContext *cct; struct ClassData; struct ClassMethod { struct ClassHandler::ClassData *cls; string name; int flags; cls_method_call_t func; cls_method_cxx_call_t cxx_func; int exec(cls_method_context_t ctx, bufferlist& indata, bufferlist& outdata); void unregister(); int get_flags() { Mutex::Locker l(cls->handler->mutex); return flags; } ClassMethod() : cls(0), flags(0), func(0), cxx_func(0) {} }; struct ClassData { enum Status { CLASS_UNKNOWN, CLASS_MISSING, // missing CLASS_MISSING_DEPS, // missing dependencies CLASS_INITIALIZING, // calling init() right now CLASS_OPEN, // initialized, usable } status; string name; ClassHandler *handler; void *handle; map methods_map; set dependencies; /* our dependencies */ set missing_dependencies; /* only missing dependencies */ ClassMethod *_get_method(const char *mname); ClassData() : status(CLASS_UNKNOWN), handler(NULL), handle(NULL) {} ~ClassData() { } ClassMethod *register_method(const char *mname, int flags, cls_method_call_t func); ClassMethod *register_cxx_method(const char *mname, int flags, cls_method_cxx_call_t func); void unregister_method(ClassMethod *method); ClassMethod *get_method(const char *mname) { Mutex::Locker l(handler->mutex); return _get_method(mname); } int get_method_flags(const char *mname); }; private: Mutex mutex; map classes; ClassData *_get_class(const string& cname); int _load_class(ClassData *cls); public: ClassHandler(CephContext *cct_) : cct(cct_), mutex("ClassHandler") {} int open_all_classes(); int open_class(const string& cname, ClassData **pcls); ClassData *register_class(const char *cname); void unregister_class(ClassData *cls); void shutdown(); }; #endif ceph-0.80.11/src/osd/OSDCap.cc0000664000175100017510000001643612623076744017643 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "OSDCap.h" #include "common/config.h" #include "common/debug.h" using std::ostream; using std::vector; ostream& operator<<(ostream& out, osd_rwxa_t p) { if (p == OSD_CAP_ANY) return out << "*"; if (p & OSD_CAP_R) out << "r"; if (p & OSD_CAP_W) out << "w"; if ((p & OSD_CAP_X) == OSD_CAP_X) { out << "x"; } else { if (p & OSD_CAP_CLS_R) out << " class-read"; if (p & OSD_CAP_CLS_W) out << " class-write"; } return out; } ostream& operator<<(ostream& out, const OSDCapSpec& s) { if (s.allow) return out << s.allow; if (s.class_name.length()) return out << "class '" << s.class_name << "' '" << s.class_allow << "'"; return out; } ostream& operator<<(ostream& out, const OSDCapMatch& m) { if (m.auid != -1LL) { out << "auid " << m.auid << " "; } if (m.object_prefix.length()) { out << "object_prefix " << m.object_prefix << " "; } if (m.pool_name.length()) { out << "pool " << m.pool_name << " "; } if (m.is_nspace) { out << "namespace "; if (m.nspace.length() == 0) out << "\"\""; else out << m.nspace; out << " "; } return out; } bool OSDCapMatch::is_match(const string& pn, const string& ns, int64_t pool_auid, const string& object) const { if (auid >= 0) { if (auid != pool_auid) return false; } if (pool_name.length()) { if (pool_name != pn) return false; } if (is_nspace) { if (nspace != ns) return false; } if (object_prefix.length()) { if (object.find(object_prefix) != 0) return false; } return true; } bool OSDCapMatch::is_match_all() const { if (auid >= 0) return false; if (pool_name.length()) return false; if (is_nspace) return false; if (object_prefix.length()) return false; return true; } ostream& operator<<(ostream& out, const OSDCapGrant& g) { return out << "grant(" << g.match << g.spec << ")"; } bool OSDCap::allow_all() const { for (vector::const_iterator p = grants.begin(); p != grants.end(); ++p) if (p->match.is_match_all() && p->spec.allow_all()) return true; return false; } void OSDCap::set_allow_all() { grants.clear(); grants.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY))); } bool OSDCap::is_capable(const string& pool_name, const string& ns, int64_t pool_auid, const string& object, bool op_may_read, bool op_may_write, bool op_may_class_read, bool op_may_class_write) const { osd_rwxa_t allow = 0; for (vector::const_iterator p = grants.begin(); p != grants.end(); ++p) { if (p->match.is_match(pool_name, ns, pool_auid, object)) { allow = allow | p->spec.allow; if ((op_may_read && !(allow & OSD_CAP_R)) || (op_may_write && !(allow & OSD_CAP_W)) || (op_may_class_read && !(allow & OSD_CAP_CLS_R)) || (op_may_class_write && !(allow & OSD_CAP_CLS_W))) continue; return true; } } return false; } // grammar namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace phoenix = boost::phoenix; template struct OSDCapParser : qi::grammar { OSDCapParser() : OSDCapParser::base_type(osdcap) { using qi::char_; using qi::int_; using qi::lexeme; using qi::alnum; using qi::_val; using qi::_1; using qi::_2; using qi::_3; using qi::eps; using qi::lit; quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['\'' >> +(char_ - '\'') >> '\'']; equoted_string %= lexeme['"' >> *(char_ - '"') >> '"'] | lexeme['\'' >> *(char_ - '\'') >> '\'']; unquoted_word %= +char_("a-zA-Z0-9_.-"); str %= quoted_string | unquoted_word; estr %= equoted_string | unquoted_word; spaces = +(lit(' ') | lit('\n') | lit('\t')); // match := [pool[=] [namespace[=]] | auid <123>] [object_prefix ] pool_name %= -(spaces >> lit("pool") >> (lit('=') | spaces) >> str); nspace %= (spaces >> lit("namespace") >> (lit('=') | spaces) >> estr); auid %= (spaces >> lit("auid") >> spaces >> int_); object_prefix %= -(spaces >> lit("object_prefix") >> spaces >> str); match = ( (auid >> object_prefix) [_val = phoenix::construct(_1, _2)] | (pool_name >> nspace >> object_prefix) [_val = phoenix::construct(_1, _2, _3)] | (pool_name >> object_prefix) [_val = phoenix::construct(_1, _2)]); // rwxa := * | [r][w][x] [class-read] [class-write] rwxa = (spaces >> lit("*")[_val = OSD_CAP_ANY]) | ( eps[_val = 0] >> ( spaces >> ( lit('r')[_val |= OSD_CAP_R] || lit('w')[_val |= OSD_CAP_W] || lit('x')[_val |= OSD_CAP_X] )) || ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) || (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) )); // capspec := * | rwx | class [classcap] capspec = rwxa [_val = phoenix::construct(_1)] | ( spaces >> lit("class") >> spaces >> ((str >> spaces >> str) [_val = phoenix::construct(_1, _2)] | str [_val = phoenix::construct(_1, string())] )); // grant := allow match capspec grant = (*lit(' ') >> lit("allow") >> ((capspec >> match) [_val = phoenix::construct(_2, _1)] | (match >> capspec) [_val = phoenix::construct(_1, _2)]) >> *lit(' ')); // osdcap := grant [grant ...] grants %= (grant % (*lit(' ') >> (lit(';') | lit(',')) >> *lit(' '))); osdcap = grants [_val = phoenix::construct(_1)]; } qi::rule spaces; qi::rule rwxa; qi::rule quoted_string, equoted_string; qi::rule unquoted_word; qi::rule str, estr; qi::rule auid; qi::rule capspec; qi::rule pool_name; qi::rule nspace; qi::rule object_prefix; qi::rule match; qi::rule grant; qi::rule()> grants; qi::rule osdcap; }; bool OSDCap::parse(const string& str, ostream *err) { OSDCapParser g; string::const_iterator iter = str.begin(); string::const_iterator end = str.end(); bool r = qi::phrase_parse(iter, end, g, ascii::space, *this); if (r && iter == end) return true; // Make sure no grants are kept after parsing failed! grants.clear(); if (err) *err << "osdcap parse failed, stopped at '" << std::string(iter, end) << "' of '" << str << "'\n"; return false; } ceph-0.80.11/src/osd/ECTransaction.h0000664000175100017510000001226312623076744021123 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef ECTRANSACTION_H #define ECTRANSACTION_H #include "OSD.h" #include "PGBackend.h" #include "osd_types.h" #include "ECUtil.h" #include #include "erasure-code/ErasureCodeInterface.h" class ECTransaction : public PGBackend::PGTransaction { public: struct AppendOp { hobject_t oid; uint64_t off; bufferlist bl; AppendOp(const hobject_t &oid, uint64_t off, bufferlist &bl) : oid(oid), off(off), bl(bl) {} }; struct CloneOp { hobject_t source; hobject_t target; CloneOp(const hobject_t &source, const hobject_t &target) : source(source), target(target) {} }; struct RenameOp { hobject_t source; hobject_t destination; RenameOp(const hobject_t &source, const hobject_t &destination) : source(source), destination(destination) {} }; struct StashOp { hobject_t oid; version_t version; StashOp(const hobject_t &oid, version_t version) : oid(oid), version(version) {} }; struct TouchOp { hobject_t oid; TouchOp(const hobject_t &oid) : oid(oid) {} }; struct RemoveOp { hobject_t oid; RemoveOp(const hobject_t &oid) : oid(oid) {} }; struct SetAttrsOp { hobject_t oid; map attrs; SetAttrsOp(const hobject_t &oid, map &_attrs) : oid(oid) { attrs.swap(_attrs); } SetAttrsOp(const hobject_t &oid, const string &key, bufferlist &val) : oid(oid) { attrs.insert(make_pair(key, val)); } }; struct RmAttrOp { hobject_t oid; string key; RmAttrOp(const hobject_t &oid, const string &key) : oid(oid), key(key) {} }; struct AllocHintOp { hobject_t oid; uint64_t expected_object_size; uint64_t expected_write_size; AllocHintOp(const hobject_t &oid, uint64_t expected_object_size, uint64_t expected_write_size) : oid(oid), expected_object_size(expected_object_size), expected_write_size(expected_write_size) {} }; struct NoOp {}; typedef boost::variant< AppendOp, CloneOp, RenameOp, StashOp, TouchOp, RemoveOp, SetAttrsOp, RmAttrOp, AllocHintOp, NoOp> Op; list ops; uint64_t written; ECTransaction() : written(0) {} /// Write void touch( const hobject_t &hoid) { bufferlist bl; ops.push_back(TouchOp(hoid)); } void append( const hobject_t &hoid, uint64_t off, uint64_t len, bufferlist &bl) { if (len == 0) { touch(hoid); return; } written += len; assert(len == bl.length()); ops.push_back(AppendOp(hoid, off, bl)); } void stash( const hobject_t &hoid, version_t former_version) { ops.push_back(StashOp(hoid, former_version)); } void remove( const hobject_t &hoid) { ops.push_back(RemoveOp(hoid)); } void setattrs( const hobject_t &hoid, map &attrs) { ops.push_back(SetAttrsOp(hoid, attrs)); } void setattr( const hobject_t &hoid, const string &attrname, bufferlist &bl) { ops.push_back(SetAttrsOp(hoid, attrname, bl)); } void rmattr( const hobject_t &hoid, const string &attrname) { ops.push_back(RmAttrOp(hoid, attrname)); } void clone( const hobject_t &from, const hobject_t &to) { ops.push_back(CloneOp(from, to)); } void rename( const hobject_t &from, const hobject_t &to) { ops.push_back(RenameOp(from, to)); } void set_alloc_hint( const hobject_t &hoid, uint64_t expected_object_size, uint64_t expected_write_size) { ops.push_back(AllocHintOp(hoid, expected_object_size, expected_write_size)); } void append(PGTransaction *_to_append) { ECTransaction *to_append = static_cast(_to_append); written += to_append->written; to_append->written = 0; ops.splice(ops.end(), to_append->ops, to_append->ops.begin(), to_append->ops.end()); } void nop() { ops.push_back(NoOp()); } bool empty() const { return ops.empty(); } uint64_t get_bytes_written() const { return written; } template void visit(T &vis) const { for (list::const_iterator i = ops.begin(); i != ops.end(); ++i) { boost::apply_visitor(vis, *i); } } template void reverse_visit(T &vis) const { for (list::const_reverse_iterator i = ops.rbegin(); i != ops.rend(); ++i) { boost::apply_visitor(vis, *i); } } void get_append_objects( set *out) const; void generate_transactions( map &hash_infos, ErasureCodeInterfaceRef &ecimpl, pg_t pgid, const ECUtil::stripe_info_t &sinfo, map *transactions, set *temp_added, set *temp_removed, stringstream *out = 0) const; }; #endif ceph-0.80.11/src/osd/OpRequest.cc0000664000175100017510000000552212623076744020513 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "OpRequest.h" #include "common/Formatter.h" #include #include #include "common/debug.h" #include "common/config.h" #include "msg/Message.h" #include "messages/MOSDOp.h" #include "messages/MOSDSubOp.h" #include "include/assert.h" #include "osd/osd_types.h" OpRequest::OpRequest(Message *req, OpTracker *tracker) : TrackedOp(req, tracker), rmw_flags(0), hit_flag_points(0), latest_flag_point(0) { if (req->get_priority() < tracker->cct->_conf->osd_client_op_priority) { // don't warn as quickly for low priority ops warn_interval_multiplier = tracker->cct->_conf->osd_recovery_op_warn_multiple; } } void OpRequest::_dump(utime_t now, Formatter *f) const { Message *m = request; f->dump_string("flag_point", state_string()); if (m->get_orig_source().is_client()) { f->open_object_section("client_info"); stringstream client_name; client_name << m->get_orig_source(); f->dump_string("client", client_name.str()); f->dump_unsigned("tid", m->get_tid()); f->close_section(); // client_info } { f->open_array_section("events"); for (list >::const_iterator i = events.begin(); i != events.end(); ++i) { f->open_object_section("event"); f->dump_stream("time") << i->first; f->dump_string("event", i->second); f->close_section(); } f->close_section(); } } void OpRequest::init_from_message() { if (request->get_type() == CEPH_MSG_OSD_OP) { reqid = static_cast(request)->get_reqid(); } else if (request->get_type() == MSG_OSD_SUBOP) { reqid = static_cast(request)->reqid; } } bool OpRequest::check_rmw(int flag) { return rmw_flags & flag; } bool OpRequest::may_read() { return need_read_cap() || need_class_read_cap(); } bool OpRequest::may_write() { return need_write_cap() || need_class_write_cap(); } bool OpRequest::may_cache() { return check_rmw(CEPH_OSD_RMW_FLAG_CACHE); } bool OpRequest::includes_pg_op() { return check_rmw(CEPH_OSD_RMW_FLAG_PGOP); } bool OpRequest::need_read_cap() { return check_rmw(CEPH_OSD_RMW_FLAG_READ); } bool OpRequest::need_write_cap() { return check_rmw(CEPH_OSD_RMW_FLAG_WRITE); } bool OpRequest::need_class_read_cap() { return check_rmw(CEPH_OSD_RMW_FLAG_CLASS_READ); } bool OpRequest::need_class_write_cap() { return check_rmw(CEPH_OSD_RMW_FLAG_CLASS_WRITE); } void OpRequest::set_read() { rmw_flags |= CEPH_OSD_RMW_FLAG_READ; } void OpRequest::set_write() { rmw_flags |= CEPH_OSD_RMW_FLAG_WRITE; } void OpRequest::set_class_read() { rmw_flags |= CEPH_OSD_RMW_FLAG_CLASS_READ; } void OpRequest::set_class_write() { rmw_flags |= CEPH_OSD_RMW_FLAG_CLASS_WRITE; } void OpRequest::set_pg_op() { rmw_flags |= CEPH_OSD_RMW_FLAG_PGOP; } void OpRequest::set_cache() { rmw_flags |= CEPH_OSD_RMW_FLAG_CACHE; } ceph-0.80.11/src/osd/OSD.h0000664000175100017510000015315612623076744017062 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OSD_H #define CEPH_OSD_H #include "boost/tuple/tuple.hpp" #include "PG.h" #include "msg/Dispatcher.h" #include "common/Mutex.h" #include "common/RWLock.h" #include "common/Timer.h" #include "common/WorkQueue.h" #include "common/LogClient.h" #include "common/AsyncReserver.h" #include "common/ceph_context.h" #include "os/ObjectStore.h" #include "OSDCap.h" #include "osd/ClassHandler.h" #include "include/CompatSet.h" #include "auth/KeyRing.h" #include "messages/MOSDRepScrub.h" #include "OpRequest.h" #include #include #include "include/memory.h" using namespace std; #include "include/unordered_map.h" #include "include/unordered_set.h" #include "Watch.h" #include "common/shared_cache.hpp" #include "common/simple_cache.hpp" #include "common/sharedptr_registry.hpp" #include "common/PrioritizedQueue.h" #define CEPH_OSD_PROTOCOL 10 /* cluster internal */ enum { l_osd_first = 10000, l_osd_opq, l_osd_op_wip, l_osd_op, l_osd_op_inb, l_osd_op_outb, l_osd_op_lat, l_osd_op_process_lat, l_osd_op_r, l_osd_op_r_outb, l_osd_op_r_lat, l_osd_op_r_process_lat, l_osd_op_w, l_osd_op_w_inb, l_osd_op_w_rlat, l_osd_op_w_lat, l_osd_op_w_process_lat, l_osd_op_rw, l_osd_op_rw_inb, l_osd_op_rw_outb, l_osd_op_rw_rlat, l_osd_op_rw_lat, l_osd_op_rw_process_lat, l_osd_sop, l_osd_sop_inb, l_osd_sop_lat, l_osd_sop_w, l_osd_sop_w_inb, l_osd_sop_w_lat, l_osd_sop_pull, l_osd_sop_pull_lat, l_osd_sop_push, l_osd_sop_push_inb, l_osd_sop_push_lat, l_osd_pull, l_osd_push, l_osd_push_outb, l_osd_push_in, l_osd_push_inb, l_osd_rop, l_osd_loadavg, l_osd_buf, l_osd_pg, l_osd_pg_primary, l_osd_pg_replica, l_osd_pg_stray, l_osd_hb_to, l_osd_hb_from, l_osd_map, l_osd_mape, l_osd_mape_dup, l_osd_waiting_for_map, l_osd_stat_bytes, l_osd_stat_bytes_used, l_osd_stat_bytes_avail, l_osd_copyfrom, l_osd_tier_promote, l_osd_tier_flush, l_osd_tier_flush_fail, l_osd_tier_try_flush, l_osd_tier_try_flush_fail, l_osd_tier_evict, l_osd_tier_whiteout, l_osd_tier_dirty, l_osd_tier_clean, l_osd_tier_delay, l_osd_agent_wake, l_osd_agent_skip, l_osd_agent_flush, l_osd_agent_evict, l_osd_last, }; // RecoveryState perf counters enum { rs_first = 20000, rs_initial_latency, rs_started_latency, rs_reset_latency, rs_start_latency, rs_primary_latency, rs_peering_latency, rs_backfilling_latency, rs_waitremotebackfillreserved_latency, rs_waitlocalbackfillreserved_latency, rs_notbackfilling_latency, rs_repnotrecovering_latency, rs_repwaitrecoveryreserved_latency, rs_repwaitbackfillreserved_latency, rs_RepRecovering_latency, rs_activating_latency, rs_waitlocalrecoveryreserved_latency, rs_waitremoterecoveryreserved_latency, rs_recovering_latency, rs_recovered_latency, rs_clean_latency, rs_active_latency, rs_replicaactive_latency, rs_stray_latency, rs_getinfo_latency, rs_getlog_latency, rs_waitactingchange_latency, rs_incomplete_latency, rs_getmissing_latency, rs_waitupthru_latency, rs_last, }; class Messenger; class Message; class MonClient; class PerfCounters; class ObjectStore; class OSDMap; class MLog; class MClass; class MOSDPGMissing; class Objecter; class Watch; class Notification; class ReplicatedPG; class AuthAuthorizeHandlerRegistry; class OpsFlightSocketHook; class HistoricOpsSocketHook; class TestOpsSocketHook; struct C_CompleteSplits; typedef ceph::shared_ptr SequencerRef; class DeletingState { Mutex lock; Cond cond; enum { QUEUED, CLEARING_DIR, CLEARING_WAITING, DELETING_DIR, DELETED_DIR, CANCELED, } status; bool stop_deleting; public: const spg_t pgid; const PGRef old_pg_state; DeletingState(const pair &in) : lock("DeletingState::lock"), status(QUEUED), stop_deleting(false), pgid(in.first), old_pg_state(in.second) {} /// transition status to clearing bool start_clearing() { Mutex::Locker l(lock); assert( status == QUEUED || status == DELETED_DIR); if (stop_deleting) { status = CANCELED; cond.Signal(); return false; } status = CLEARING_DIR; return true; } ///< @return false if we should cancel deletion /// transition status to CLEARING_WAITING bool pause_clearing() { Mutex::Locker l(lock); assert(status == CLEARING_DIR); if (stop_deleting) { status = CANCELED; cond.Signal(); return false; } status = CLEARING_WAITING; return true; } ///< @return false if we should cancel deletion /// transition status to CLEARING_DIR bool resume_clearing() { Mutex::Locker l(lock); assert(status == CLEARING_WAITING); if (stop_deleting) { status = CANCELED; cond.Signal(); return false; } status = CLEARING_DIR; return true; } ///< @return false if we should cancel deletion /// transition status to deleting bool start_deleting() { Mutex::Locker l(lock); assert(status == CLEARING_DIR); if (stop_deleting) { status = CANCELED; cond.Signal(); return false; } status = DELETING_DIR; return true; } ///< @return false if we should cancel deletion /// signal collection removal queued void finish_deleting() { Mutex::Locker l(lock); assert(status == DELETING_DIR); status = DELETED_DIR; cond.Signal(); } /// try to halt the deletion bool try_stop_deletion() { Mutex::Locker l(lock); stop_deleting = true; /** * If we are in DELETING_DIR or CLEARING_DIR, there are in progress * operations we have to wait for before continuing on. States * CLEARING_WAITING and QUEUED indicate that the remover will check * stop_deleting before queueing any further operations. CANCELED * indicates that the remover has already halted. DELETED_DIR * indicates that the deletion has been fully queueud. */ while (status == DELETING_DIR || status == CLEARING_DIR) cond.Wait(lock); return status != DELETED_DIR; } ///< @return true if we don't need to recreate the collection }; typedef ceph::shared_ptr DeletingStateRef; class OSD; class OSDService { public: OSD *osd; CephContext *cct; SharedPtrRegistry osr_registry; SharedPtrRegistry deleting_pgs; const int whoami; ObjectStore *&store; LogClient &clog; PGRecoveryStats &pg_recovery_stats; hobject_t infos_oid; private: Messenger *&cluster_messenger; Messenger *&client_messenger; public: PerfCounters *&logger; PerfCounters *&recoverystate_perf; MonClient *&monc; ThreadPool::WorkQueueVal, PGRef> &op_wq; ThreadPool::BatchWorkQueue &peering_wq; ThreadPool::WorkQueue &recovery_wq; ThreadPool::WorkQueue &snap_trim_wq; ThreadPool::WorkQueue &scrub_wq; ThreadPool::WorkQueue &scrub_finalize_wq; ThreadPool::WorkQueue &rep_scrub_wq; GenContextWQ push_wq; GenContextWQ gen_wq; ClassHandler *&class_handler; void dequeue_pg(PG *pg, list *dequeued); // -- map epoch lower bound -- Mutex pg_epoch_lock; multiset pg_epochs; map pg_epoch; void pg_add_epoch(spg_t pgid, epoch_t epoch) { Mutex::Locker l(pg_epoch_lock); map::iterator t = pg_epoch.find(pgid); assert(t == pg_epoch.end()); pg_epoch[pgid] = epoch; pg_epochs.insert(epoch); } void pg_update_epoch(spg_t pgid, epoch_t epoch) { Mutex::Locker l(pg_epoch_lock); map::iterator t = pg_epoch.find(pgid); assert(t != pg_epoch.end()); pg_epochs.erase(pg_epochs.find(t->second)); t->second = epoch; pg_epochs.insert(epoch); } void pg_remove_epoch(spg_t pgid) { Mutex::Locker l(pg_epoch_lock); map::iterator t = pg_epoch.find(pgid); if (t != pg_epoch.end()) { pg_epochs.erase(pg_epochs.find(t->second)); pg_epoch.erase(t); } } epoch_t get_min_pg_epoch() { Mutex::Locker l(pg_epoch_lock); if (pg_epochs.empty()) return 0; else return *pg_epochs.begin(); } // -- superblock -- Mutex publish_lock, pre_publish_lock; // pre-publish orders before publish OSDSuperblock superblock; OSDSuperblock get_superblock() { Mutex::Locker l(publish_lock); return superblock; } void publish_superblock(const OSDSuperblock &block) { Mutex::Locker l(publish_lock); superblock = block; } int get_nodeid() const { return whoami; } OSDMapRef osdmap; OSDMapRef get_osdmap() { Mutex::Locker l(publish_lock); return osdmap; } void publish_map(OSDMapRef map) { Mutex::Locker l(publish_lock); osdmap = map; } /* * osdmap - current published amp * next_osdmap - pre_published map that is about to be published. * * We use the next_osdmap to send messages and initiate connections, * but only if the target is the same instance as the one in the map * epoch the current user is working from (i.e., the result is * equivalent to what is in next_osdmap). * * This allows the helpers to start ignoring osds that are about to * go down, and let OSD::handle_osd_map()/note_down_osd() mark them * down, without worrying about reopening connections from threads * working from old maps. */ OSDMapRef next_osdmap; void pre_publish_map(OSDMapRef map) { Mutex::Locker l(pre_publish_lock); next_osdmap = map; } void activate_map(); ConnectionRef get_con_osd_cluster(int peer, epoch_t from_epoch); pair get_con_osd_hb(int peer, epoch_t from_epoch); // (back, front) void send_message_osd_cluster(int peer, Message *m, epoch_t from_epoch); void send_message_osd_cluster(Message *m, Connection *con) { cluster_messenger->send_message(m, con); } void send_message_osd_cluster(Message *m, const ConnectionRef& con) { cluster_messenger->send_message(m, con.get()); } void send_message_osd_client(Message *m, Connection *con) { client_messenger->send_message(m, con); } void send_message_osd_client(Message *m, const ConnectionRef& con) { client_messenger->send_message(m, con.get()); } entity_name_t get_cluster_msgr_name() { return cluster_messenger->get_myname(); } // -- scrub scheduling -- Mutex sched_scrub_lock; int scrubs_pending; int scrubs_active; set< pair > last_scrub_pg; void reg_last_pg_scrub(spg_t pgid, utime_t t) { Mutex::Locker l(sched_scrub_lock); last_scrub_pg.insert(pair(t, pgid)); } void unreg_last_pg_scrub(spg_t pgid, utime_t t) { Mutex::Locker l(sched_scrub_lock); pair p(t, pgid); set >::iterator it = last_scrub_pg.find(p); assert(it != last_scrub_pg.end()); last_scrub_pg.erase(it); } bool first_scrub_stamp(pair *out) { Mutex::Locker l(sched_scrub_lock); if (last_scrub_pg.empty()) return false; set< pair >::iterator iter = last_scrub_pg.begin(); *out = *iter; return true; } bool next_scrub_stamp(pair next, pair *out) { Mutex::Locker l(sched_scrub_lock); if (last_scrub_pg.empty()) return false; set< pair >::iterator iter = last_scrub_pg.lower_bound(next); if (iter == last_scrub_pg.end()) return false; ++iter; if (iter == last_scrub_pg.end()) return false; *out = *iter; return true; } bool inc_scrubs_pending(); void inc_scrubs_active(bool reserved); void dec_scrubs_pending(); void dec_scrubs_active(); void reply_op_error(OpRequestRef op, int err); void reply_op_error(OpRequestRef op, int err, eversion_t v, version_t uv); void handle_misdirected_op(PG *pg, OpRequestRef op); // -- agent shared state -- Mutex agent_lock; Cond agent_cond; map > agent_queue; set::iterator agent_queue_pos; bool agent_valid_iterator; int agent_ops; set agent_oids; bool agent_active; struct AgentThread : public Thread { OSDService *osd; AgentThread(OSDService *o) : osd(o) {} void *entry() { osd->agent_entry(); return NULL; } } agent_thread; bool agent_stop_flag; Mutex agent_timer_lock; SafeTimer agent_timer; void agent_entry(); void agent_stop(); void _enqueue(PG *pg, uint64_t priority) { if (!agent_queue.empty() && agent_queue.rbegin()->first < priority) agent_valid_iterator = false; // inserting higher-priority queue set& nq = agent_queue[priority]; if (nq.empty()) agent_cond.Signal(); nq.insert(pg); } void _dequeue(PG *pg, uint64_t old_priority) { set& oq = agent_queue[old_priority]; set::iterator p = oq.find(pg); assert(p != oq.end()); if (p == agent_queue_pos) ++agent_queue_pos; oq.erase(p); if (oq.empty()) { if (agent_queue.rbegin()->first == old_priority) agent_valid_iterator = false; agent_queue.erase(old_priority); } } /// enable agent for a pg void agent_enable_pg(PG *pg, uint64_t priority) { Mutex::Locker l(agent_lock); _enqueue(pg, priority); } /// adjust priority for an enagled pg void agent_adjust_pg(PG *pg, uint64_t old_priority, uint64_t new_priority) { Mutex::Locker l(agent_lock); assert(new_priority != old_priority); _enqueue(pg, new_priority); _dequeue(pg, old_priority); } /// disable agent for a pg void agent_disable_pg(PG *pg, uint64_t old_priority) { Mutex::Locker l(agent_lock); _dequeue(pg, old_priority); } /// note start of an async (flush) op void agent_start_op(const hobject_t& oid) { Mutex::Locker l(agent_lock); ++agent_ops; assert(agent_oids.count(oid) == 0); agent_oids.insert(oid); } /// note finish or cancellation of an async (flush) op void agent_finish_op(const hobject_t& oid) { Mutex::Locker l(agent_lock); assert(agent_ops > 0); --agent_ops; assert(agent_oids.count(oid) == 1); agent_oids.erase(oid); agent_cond.Signal(); } /// check if we are operating on an object bool agent_is_active_oid(const hobject_t& oid) { Mutex::Locker l(agent_lock); return agent_oids.count(oid); } /// get count of active agent ops int agent_get_num_ops() { Mutex::Locker l(agent_lock); return agent_ops; } // -- Objecter, for teiring reads/writes from/to other OSDs -- Mutex objecter_lock; SafeTimer objecter_timer; OSDMap objecter_osdmap; Objecter *objecter; Finisher objecter_finisher; struct ObjecterDispatcher : public Dispatcher { OSDService *osd; bool ms_dispatch(Message *m); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con) {} void ms_handle_connect(Connection *con); bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); ObjecterDispatcher(OSDService *o) : Dispatcher(cct), osd(o) {} } objecter_dispatcher; friend struct ObjecterDispatcher; // -- Watch -- Mutex watch_lock; SafeTimer watch_timer; uint64_t next_notif_id; uint64_t get_next_id(epoch_t cur_epoch) { Mutex::Locker l(watch_lock); return (((uint64_t)cur_epoch) << 32) | ((uint64_t)(next_notif_id++)); } // -- Backfill Request Scheduling -- Mutex backfill_request_lock; SafeTimer backfill_request_timer; // -- tids -- // for ops i issue ceph_tid_t last_tid; Mutex tid_lock; ceph_tid_t get_tid() { ceph_tid_t t; tid_lock.Lock(); t = ++last_tid; tid_lock.Unlock(); return t; } // -- backfill_reservation -- enum { BACKFILL_LOW = 0, // backfill non-degraded PGs BACKFILL_HIGH = 1, // backfill degraded PGs RECOVERY = AsyncReserver::MAX_PRIORITY // log based recovery }; Finisher reserver_finisher; AsyncReserver local_reserver; AsyncReserver remote_reserver; // -- pg_temp -- Mutex pg_temp_lock; map > pg_temp_wanted; void queue_want_pg_temp(pg_t pgid, vector& want); void remove_want_pg_temp(pg_t pgid) { Mutex::Locker l(pg_temp_lock); pg_temp_wanted.erase(pgid); } void send_pg_temp(); void queue_for_peering(PG *pg); bool queue_for_recovery(PG *pg); bool queue_for_snap_trim(PG *pg) { return snap_trim_wq.queue(pg); } bool queue_for_scrub(PG *pg) { return scrub_wq.queue(pg); } // osd map cache (past osd maps) Mutex map_cache_lock; SharedLRU map_cache; SimpleLRU map_bl_cache; SimpleLRU map_bl_inc_cache; OSDMapRef try_get_map(epoch_t e); OSDMapRef get_map(epoch_t e) { OSDMapRef ret(try_get_map(e)); assert(ret); return ret; } OSDMapRef add_map(OSDMap *o) { Mutex::Locker l(map_cache_lock); return _add_map(o); } OSDMapRef _add_map(OSDMap *o); void add_map_bl(epoch_t e, bufferlist& bl) { Mutex::Locker l(map_cache_lock); return _add_map_bl(e, bl); } void pin_map_bl(epoch_t e, bufferlist &bl); void _add_map_bl(epoch_t e, bufferlist& bl); bool get_map_bl(epoch_t e, bufferlist& bl) { Mutex::Locker l(map_cache_lock); return _get_map_bl(e, bl); } bool _get_map_bl(epoch_t e, bufferlist& bl); void add_map_inc_bl(epoch_t e, bufferlist& bl) { Mutex::Locker l(map_cache_lock); return _add_map_inc_bl(e, bl); } void pin_map_inc_bl(epoch_t e, bufferlist &bl); void _add_map_inc_bl(epoch_t e, bufferlist& bl); bool get_inc_map_bl(epoch_t e, bufferlist& bl); void clear_map_bl_cache_pins(epoch_t e); void need_heartbeat_peer_update(); void pg_stat_queue_enqueue(PG *pg); void pg_stat_queue_dequeue(PG *pg); void init(); void start_shutdown(); void shutdown(); // split Mutex in_progress_split_lock; map pending_splits; // child -> parent map > rev_pending_splits; // parent -> [children] set in_progress_splits; // child void _start_split(spg_t parent, const set &children); void start_split(spg_t parent, const set &children) { Mutex::Locker l(in_progress_split_lock); return _start_split(parent, children); } void mark_split_in_progress(spg_t parent, const set &pgs); void complete_split(const set &pgs); void cancel_pending_splits_for_parent(spg_t parent); void _cancel_pending_splits_for_parent(spg_t parent); bool splitting(spg_t pgid); void expand_pg_num(OSDMapRef old_map, OSDMapRef new_map); void _maybe_split_pgid(OSDMapRef old_map, OSDMapRef new_map, spg_t pgid); void init_splits_between(spg_t pgid, OSDMapRef frommap, OSDMapRef tomap); // -- OSD Full Status -- Mutex full_status_lock; enum s_names { NONE, NEAR, FULL } cur_state; time_t last_msg; double cur_ratio; float get_full_ratio(); float get_nearfull_ratio(); void check_nearfull_warning(const osd_stat_t &stat); bool check_failsafe_full(); bool too_full_for_backfill(double *ratio, double *max_ratio); // -- stopping -- Mutex is_stopping_lock; Cond is_stopping_cond; enum { NOT_STOPPING, PREPARING_TO_STOP, STOPPING } state; bool is_stopping() { Mutex::Locker l(is_stopping_lock); return state == STOPPING; } bool is_preparing_to_stop() { Mutex::Locker l(is_stopping_lock); return state == PREPARING_TO_STOP; } bool prepare_to_stop(); void got_stop_ack(); #ifdef PG_DEBUG_REFS Mutex pgid_lock; map pgid_tracker; map live_pgs; void add_pgid(spg_t pgid, PG *pg) { Mutex::Locker l(pgid_lock); if (!pgid_tracker.count(pgid)) { pgid_tracker[pgid] = 0; live_pgs[pgid] = pg; } pgid_tracker[pgid]++; } void remove_pgid(spg_t pgid, PG *pg) { Mutex::Locker l(pgid_lock); assert(pgid_tracker.count(pgid)); assert(pgid_tracker[pgid] > 0); pgid_tracker[pgid]--; if (pgid_tracker[pgid] == 0) { pgid_tracker.erase(pgid); live_pgs.erase(pgid); } } void dump_live_pgids() { Mutex::Locker l(pgid_lock); derr << "live pgids:" << dendl; for (map::iterator i = pgid_tracker.begin(); i != pgid_tracker.end(); ++i) { derr << "\t" << *i << dendl; live_pgs[i->first]->dump_live_ids(); } } #endif OSDService(OSD *osd); ~OSDService(); }; struct C_OSD_SendMessageOnConn: public Context { OSDService *osd; Message *reply; ConnectionRef conn; C_OSD_SendMessageOnConn( OSDService *osd, Message *reply, ConnectionRef conn) : osd(osd), reply(reply), conn(conn) {} void finish(int) { osd->send_message_osd_cluster(reply, conn.get()); } }; class OSD : public Dispatcher, public md_config_obs_t { /** OSD **/ public: // config observer bits virtual const char** get_tracked_conf_keys() const; virtual void handle_conf_change(const struct md_config_t *conf, const std::set &changed); void check_config(); protected: Mutex osd_lock; // global lock SafeTimer tick_timer; // safe timer (osd_lock) AuthAuthorizeHandlerRegistry *authorize_handler_cluster_registry; AuthAuthorizeHandlerRegistry *authorize_handler_service_registry; Messenger *cluster_messenger; Messenger *client_messenger; Messenger *objecter_messenger; MonClient *monc; // check the "monc helpers" list before accessing directly PerfCounters *logger; PerfCounters *recoverystate_perf; ObjectStore *store; LogClient clog; int whoami; std::string dev_path, journal_path; class C_Tick : public Context { OSD *osd; public: C_Tick(OSD *o) : osd(o) {} void finish(int r) { osd->tick(); } }; Cond dispatch_cond; int dispatch_running; void create_logger(); void create_recoverystate_perf(); void tick(); void _dispatch(Message *m); void dispatch_op(OpRequestRef op); void check_osdmap_features(ObjectStore *store); // asok friend class OSDSocketHook; class OSDSocketHook *asok_hook; bool asok_command(string command, cmdmap_t& cmdmap, string format, ostream& ss); public: ClassHandler *class_handler; int get_nodeid() { return whoami; } static hobject_t get_osdmap_pobject_name(epoch_t epoch) { char foo[20]; snprintf(foo, sizeof(foo), "osdmap.%d", epoch); return hobject_t(sobject_t(object_t(foo), 0)); } static hobject_t get_inc_osdmap_pobject_name(epoch_t epoch) { char foo[20]; snprintf(foo, sizeof(foo), "inc_osdmap.%d", epoch); return hobject_t(sobject_t(object_t(foo), 0)); } static hobject_t make_snapmapper_oid() { return hobject_t( sobject_t( object_t("snapmapper"), 0)); } static hobject_t make_pg_log_oid(spg_t pg) { stringstream ss; ss << "pglog_" << pg; string s; getline(ss, s); return hobject_t(sobject_t(object_t(s.c_str()), 0)); } static hobject_t make_pg_biginfo_oid(spg_t pg) { stringstream ss; ss << "pginfo_" << pg; string s; getline(ss, s); return hobject_t(sobject_t(object_t(s.c_str()), 0)); } static hobject_t make_infos_oid() { hobject_t oid(sobject_t("infos", CEPH_NOSNAP)); return oid; } static void recursive_remove_collection(ObjectStore *store, coll_t tmp); /** * get_osd_initial_compat_set() * * Get the initial feature set for this OSD. Features * here are automatically upgraded. * * Return value: Initial osd CompatSet */ static CompatSet get_osd_initial_compat_set(); /** * get_osd_compat_set() * * Get all features supported by this OSD * * Return value: CompatSet of all supported features */ static CompatSet get_osd_compat_set(); private: // -- superblock -- OSDSuperblock superblock; void write_superblock(); void write_superblock(ObjectStore::Transaction& t); int read_superblock(); CompatSet osd_compat; // -- state -- public: static const int STATE_INITIALIZING = 1; static const int STATE_BOOTING = 2; static const int STATE_ACTIVE = 3; static const int STATE_STOPPING = 4; static const int STATE_WAITING_FOR_HEALTHY = 5; static const char *get_state_name(int s) { switch (s) { case STATE_INITIALIZING: return "initializing"; case STATE_BOOTING: return "booting"; case STATE_ACTIVE: return "active"; case STATE_STOPPING: return "stopping"; case STATE_WAITING_FOR_HEALTHY: return "waiting_for_healthy"; default: return "???"; } } private: int state; epoch_t boot_epoch; // _first_ epoch we were marked up (after this process started) epoch_t up_epoch; // _most_recent_ epoch we were marked up epoch_t bind_epoch; // epoch we last did a bind to new ip:ports public: bool is_initializing() { return state == STATE_INITIALIZING; } bool is_booting() { return state == STATE_BOOTING; } bool is_active() { return state == STATE_ACTIVE; } bool is_stopping() { return state == STATE_STOPPING; } bool is_waiting_for_healthy() { return state == STATE_WAITING_FOR_HEALTHY; } private: ThreadPool op_tp; ThreadPool recovery_tp; ThreadPool disk_tp; ThreadPool command_tp; bool paused_recovery; void set_disk_tp_priority(); // -- sessions -- public: struct Session : public RefCountedObject { EntityName entity_name; OSDCap caps; int64_t auid; epoch_t last_sent_epoch; ConnectionRef con; WatchConState wstate; Session() : auid(-1), last_sent_epoch(0), con(0) {} }; private: /** * @defgroup monc helpers * * Right now we only have the one */ /** * Ask the Monitors for a sequence of OSDMaps. * * @param epoch The epoch to start with when replying * @param force_request True if this request forces a new subscription to * the monitors; false if an outstanding request that encompasses it is * sufficient. */ void osdmap_subscribe(version_t epoch, bool force_request); /** @} monc helpers */ // -- heartbeat -- /// information about a heartbeat peer struct HeartbeatInfo { int peer; ///< peer ConnectionRef con_front; ///< peer connection (front) ConnectionRef con_back; ///< peer connection (back) utime_t first_tx; ///< time we sent our first ping request utime_t last_tx; ///< last time we sent a ping request utime_t last_rx_front; ///< last time we got a ping reply on the front side utime_t last_rx_back; ///< last time we got a ping reply on the back side epoch_t epoch; ///< most recent epoch we wanted this peer bool is_unhealthy(utime_t cutoff) { return ! ((last_rx_front > cutoff || (last_rx_front == utime_t() && (last_tx == utime_t() || first_tx > cutoff))) && (last_rx_back > cutoff || (last_rx_back == utime_t() && (last_tx == utime_t() || first_tx > cutoff)))); } bool is_healthy(utime_t cutoff) { return last_rx_front > cutoff && last_rx_back > cutoff; } }; /// state attached to outgoing heartbeat connections struct HeartbeatSession : public RefCountedObject { int peer; HeartbeatSession(int p) : peer(p) {} }; Mutex heartbeat_lock; map debug_heartbeat_drops_remaining; Cond heartbeat_cond; bool heartbeat_stop; bool heartbeat_need_update; ///< true if we need to refresh our heartbeat peers epoch_t heartbeat_epoch; ///< last epoch we updated our heartbeat peers map heartbeat_peers; ///< map of osd id to HeartbeatInfo utime_t last_mon_heartbeat; Messenger *hbclient_messenger; Messenger *hb_front_server_messenger; Messenger *hb_back_server_messenger; utime_t last_heartbeat_resample; ///< last time we chose random peers in waiting-for-healthy state void _add_heartbeat_peer(int p); void _remove_heartbeat_peer(int p); bool heartbeat_reset(Connection *con); void maybe_update_heartbeat_peers(); void reset_heartbeat_peers(); void heartbeat(); void heartbeat_check(); void heartbeat_entry(); void need_heartbeat_peer_update(); void heartbeat_kick() { Mutex::Locker l(heartbeat_lock); heartbeat_cond.Signal(); } struct T_Heartbeat : public Thread { OSD *osd; T_Heartbeat(OSD *o) : osd(o) {} void *entry() { osd->heartbeat_entry(); return 0; } } heartbeat_thread; public: bool heartbeat_dispatch(Message *m); struct HeartbeatDispatcher : public Dispatcher { OSD *osd; HeartbeatDispatcher(OSD *o) : Dispatcher(cct), osd(o) {} bool ms_dispatch(Message *m) { return osd->heartbeat_dispatch(m); }; bool ms_handle_reset(Connection *con) { return osd->heartbeat_reset(con); } void ms_handle_remote_reset(Connection *con) {} bool ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key) { isvalid = true; return true; } } heartbeat_dispatcher; private: // -- stats -- Mutex stat_lock; osd_stat_t osd_stat; void update_osd_stat(); // -- waiters -- list finished; Mutex finished_lock; void take_waiters(list& ls) { finished_lock.Lock(); finished.splice(finished.end(), ls); finished_lock.Unlock(); } void take_waiters_front(list& ls) { finished_lock.Lock(); finished.splice(finished.begin(), ls); finished_lock.Unlock(); } void take_waiter(OpRequestRef op) { finished_lock.Lock(); finished.push_back(op); finished_lock.Unlock(); } void do_waiters(); // -- op tracking -- OpTracker op_tracker; void check_ops_in_flight(); void test_ops(std::string command, std::string args, ostream& ss); friend class TestOpsSocketHook; TestOpsSocketHook *test_ops_hook; friend struct C_CompleteSplits; // -- op queue -- struct OpWQ: public ThreadPool::WorkQueueVal, PGRef > { Mutex qlock; map > pg_for_processing; OSD *osd; PrioritizedQueue, entity_inst_t > pqueue; OpWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueueVal, PGRef >( "OSD::OpWQ", ti, si, tp), qlock("OpWQ::qlock"), osd(o), pqueue(o->cct->_conf->osd_op_pq_max_tokens_per_priority, o->cct->_conf->osd_op_pq_min_cost) {} void dump(Formatter *f) { lock(); pqueue.dump(f); unlock(); } void _enqueue_front(pair item); void _enqueue(pair item); PGRef _dequeue(); struct Pred { PG *pg; Pred(PG *pg) : pg(pg) {} bool operator()(const pair &op) { return op.first == pg; } }; void dequeue(PG *pg, list *dequeued = 0) { lock(); if (!dequeued) { pqueue.remove_by_filter(Pred(pg)); pg_for_processing.erase(pg); } else { list > _dequeued; pqueue.remove_by_filter(Pred(pg), &_dequeued); for (list >::iterator i = _dequeued.begin(); i != _dequeued.end(); ++i) { dequeued->push_back(i->second); } if (pg_for_processing.count(pg)) { dequeued->splice( dequeued->begin(), pg_for_processing[pg]); pg_for_processing.erase(pg); } } unlock(); } bool _empty() { return pqueue.empty(); } void _process(PGRef pg, ThreadPool::TPHandle &handle); } op_wq; void enqueue_op(PG *pg, OpRequestRef op); void dequeue_op( PGRef pg, OpRequestRef op, ThreadPool::TPHandle &handle); // -- peering queue -- struct PeeringWQ : public ThreadPool::BatchWorkQueue { list peering_queue; OSD *osd; set in_use; PeeringWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::BatchWorkQueue( "OSD::PeeringWQ", ti, si, tp), osd(o) {} void _dequeue(PG *pg) { for (list::iterator i = peering_queue.begin(); i != peering_queue.end(); ) { if (*i == pg) { peering_queue.erase(i++); pg->put("PeeringWQ"); } else { ++i; } } } bool _enqueue(PG *pg) { pg->get("PeeringWQ"); peering_queue.push_back(pg); return true; } bool _empty() { return peering_queue.empty(); } void _dequeue(list *out); void _process( const list &pgs, ThreadPool::TPHandle &handle) { osd->process_peering_events(pgs, handle); for (list::const_iterator i = pgs.begin(); i != pgs.end(); ++i) { (*i)->put("PeeringWQ"); } } void _process_finish(const list &pgs) { for (list::const_iterator i = pgs.begin(); i != pgs.end(); ++i) { in_use.erase(*i); } } void _clear() { assert(peering_queue.empty()); } } peering_wq; void process_peering_events( const list &pg, ThreadPool::TPHandle &handle); friend class PG; friend class ReplicatedPG; protected: // -- osd map -- OSDMapRef osdmap; OSDMapRef get_osdmap() { return osdmap; } utime_t had_map_since; RWLock map_lock; list waiting_for_osdmap; Mutex peer_map_epoch_lock; map peer_map_epoch; epoch_t get_peer_epoch(int p); epoch_t note_peer_epoch(int p, epoch_t e); void forget_peer_epoch(int p, epoch_t e); bool _share_map_incoming(entity_name_t name, Connection *con, epoch_t epoch, Session *session = 0); void _share_map_outgoing(int peer, Connection *con, OSDMapRef map = OSDMapRef()); void wait_for_new_map(OpRequestRef op); void handle_osd_map(class MOSDMap *m); void note_down_osd(int osd); void note_up_osd(int osd); bool advance_pg( epoch_t advance_to, PG *pg, ThreadPool::TPHandle &handle, PG::RecoveryCtx *rctx, set > *split_pgs ); void advance_map(ObjectStore::Transaction& t, C_Contexts *tfin); void consume_map(); void activate_map(); // osd map cache (past osd maps) OSDMapRef get_map(epoch_t e) { return service.get_map(e); } OSDMapRef add_map(OSDMap *o) { return service.add_map(o); } void add_map_bl(epoch_t e, bufferlist& bl) { return service.add_map_bl(e, bl); } void pin_map_bl(epoch_t e, bufferlist &bl) { return service.pin_map_bl(e, bl); } bool get_map_bl(epoch_t e, bufferlist& bl) { return service.get_map_bl(e, bl); } void add_map_inc_bl(epoch_t e, bufferlist& bl) { return service.add_map_inc_bl(e, bl); } void pin_map_inc_bl(epoch_t e, bufferlist &bl) { return service.pin_map_inc_bl(e, bl); } bool get_inc_map_bl(epoch_t e, bufferlist& bl) { return service.get_inc_map_bl(e, bl); } MOSDMap *build_incremental_map_msg(epoch_t from, epoch_t to); void send_incremental_map(epoch_t since, Connection *con); void send_map(MOSDMap *m, Connection *con); protected: // -- placement groups -- ceph::unordered_map pg_map; map > waiting_for_pg; map > peering_wait_for_split; PGRecoveryStats pg_recovery_stats; PGPool _get_pool(int id, OSDMapRef createmap); bool _have_pg(spg_t pgid); PG *_lookup_lock_pg_with_map_lock_held(spg_t pgid); PG *_lookup_lock_pg(spg_t pgid); PG *_lookup_pg(spg_t pgid); PG *_open_lock_pg(OSDMapRef createmap, spg_t pg, bool no_lockdep_check=false, bool hold_map_lock=false); enum res_result { RES_PARENT, // resurrected a parent RES_SELF, // resurrected self RES_NONE // nothing relevant deleting }; res_result _try_resurrect_pg( OSDMapRef curmap, spg_t pgid, spg_t *resurrected, PGRef *old_pg_state); PG *_create_lock_pg( OSDMapRef createmap, spg_t pgid, bool newly_created, bool hold_map_lock, bool backfill, int role, vector& up, int up_primary, vector& acting, int acting_primary, pg_history_t history, pg_interval_map_t& pi, ObjectStore::Transaction& t); PG *_lookup_qlock_pg(spg_t pgid); PG* _make_pg(OSDMapRef createmap, spg_t pgid); void add_newly_split_pg(PG *pg, PG::RecoveryCtx *rctx); void handle_pg_peering_evt( spg_t pgid, const pg_info_t& info, pg_interval_map_t& pi, epoch_t epoch, pg_shard_t from, bool primary, PG::CephPeeringEvtRef evt); void load_pgs(); void build_past_intervals_parallel(); void calc_priors_during( spg_t pgid, epoch_t start, epoch_t end, set& pset); /// project pg history from from to now bool project_pg_history( spg_t pgid, pg_history_t& h, epoch_t from, const vector& lastup, int lastupprimary, const vector& lastacting, int lastactingprimary ); ///< @return false if there was a map gap between from and now void wake_pg_waiters(spg_t pgid) { if (waiting_for_pg.count(pgid)) { take_waiters_front(waiting_for_pg[pgid]); waiting_for_pg.erase(pgid); } } void wake_all_pg_waiters() { for (map >::iterator p = waiting_for_pg.begin(); p != waiting_for_pg.end(); ++p) take_waiters_front(p->second); waiting_for_pg.clear(); } // -- pg creation -- struct create_pg_info { pg_history_t history; vector acting; set prior; pg_t parent; }; ceph::unordered_map creating_pgs; double debug_drop_pg_create_probability; int debug_drop_pg_create_duration; int debug_drop_pg_create_left; // 0 if we just dropped the last one, -1 if we can drop more bool can_create_pg(spg_t pgid); void handle_pg_create(OpRequestRef op); void split_pgs( PG *parent, const set &childpgids, set > *out_pgs, OSDMapRef curmap, OSDMapRef nextmap, PG::RecoveryCtx *rctx); // == monitor interaction == utime_t last_mon_report; utime_t last_pg_stats_sent; /* if our monitor dies, we want to notice it and reconnect. * So we keep track of when it last acked our stat updates, * and if too much time passes (and we've been sending * more updates) then we can call it dead and reconnect * elsewhere. */ utime_t last_pg_stats_ack; bool outstanding_pg_stats; // some stat updates haven't been acked yet bool timeout_mon_on_pg_stats; void restart_stats_timer() { Mutex::Locker l(osd_lock); last_pg_stats_ack = ceph_clock_now(cct); timeout_mon_on_pg_stats = true; } class C_MonStatsAckTimer : public Context { OSD *osd; public: C_MonStatsAckTimer(OSD *o) : osd(o) {} void finish(int r) { osd->restart_stats_timer(); } }; friend class C_MonStatsAckTimer; void do_mon_report(); // -- boot -- void start_boot(); void _maybe_boot(epoch_t oldest, epoch_t newest); void _send_boot(); void _collect_metadata(map *pmeta); bool _lsb_release_set(char *buf, const char *str, map *pm, const char *key); void _lsb_release_parse (map *pm); void start_waiting_for_healthy(); bool _is_healthy(); friend struct C_OSD_GetVersion; // -- alive -- epoch_t up_thru_wanted; epoch_t up_thru_pending; void queue_want_up_thru(epoch_t want); void send_alive(); // -- failures -- map failure_queue; map failure_pending; void send_failures(); void send_still_alive(epoch_t epoch, const entity_inst_t &i); // -- pg stats -- Mutex pg_stat_queue_lock; Cond pg_stat_queue_cond; xlist pg_stat_queue; bool osd_stat_updated; uint64_t pg_stat_tid, pg_stat_tid_flushed; void send_pg_stats(const utime_t &now); void handle_pg_stats_ack(class MPGStatsAck *ack); void flush_pg_stats(); void pg_stat_queue_enqueue(PG *pg) { pg_stat_queue_lock.Lock(); if (pg->is_primary() && !pg->stat_queue_item.is_on_list()) { pg->get("pg_stat_queue"); pg_stat_queue.push_back(&pg->stat_queue_item); } osd_stat_updated = true; pg_stat_queue_lock.Unlock(); } void pg_stat_queue_dequeue(PG *pg) { pg_stat_queue_lock.Lock(); if (pg->stat_queue_item.remove_myself()) pg->put("pg_stat_queue"); pg_stat_queue_lock.Unlock(); } void clear_pg_stat_queue() { pg_stat_queue_lock.Lock(); while (!pg_stat_queue.empty()) { PG *pg = pg_stat_queue.front(); pg_stat_queue.pop_front(); pg->put("pg_stat_queue"); } pg_stat_queue_lock.Unlock(); } ceph_tid_t get_tid() { return service.get_tid(); } // -- generic pg peering -- PG::RecoveryCtx create_context(); bool compat_must_dispatch_immediately(PG *pg); void dispatch_context(PG::RecoveryCtx &ctx, PG *pg, OSDMapRef curmap, ThreadPool::TPHandle *handle = NULL); void dispatch_context_transaction(PG::RecoveryCtx &ctx, PG *pg, ThreadPool::TPHandle *handle = NULL); void do_notifies(map > >& notify_list, OSDMapRef map); void do_queries(map >& query_map, OSDMapRef map); void do_infos(map > >& info_map, OSDMapRef map); void repeer(PG *pg, map< int, map >& query_map); bool require_mon_peer(Message *m); bool require_osd_peer(Message *m); /*** * Verifies that we were alive in the given epoch, and that * still are. */ bool require_self_aliveness(Message *m, epoch_t alive_since); /** * Verifies that the OSD who sent the given op has the same * address as in the given map. * @pre op was sent by an OSD using the cluster messenger */ bool require_same_peer_instance(Message *m, OSDMapRef& map); bool require_up_osd_peer(Message *m, OSDMapRef& map, epoch_t their_epoch); bool require_same_or_newer_map(OpRequestRef& op, epoch_t e); void handle_pg_query(OpRequestRef op); void handle_pg_notify(OpRequestRef op); void handle_pg_log(OpRequestRef op); void handle_pg_info(OpRequestRef op); void handle_pg_trim(OpRequestRef op); void handle_pg_scan(OpRequestRef op); void handle_pg_backfill(OpRequestRef op); void handle_pg_backfill_reserve(OpRequestRef op); void handle_pg_recovery_reserve(OpRequestRef op); void handle_pg_remove(OpRequestRef op); void _remove_pg(PG *pg); // -- commands -- struct Command { vector cmd; ceph_tid_t tid; bufferlist indata; ConnectionRef con; Command(vector& c, ceph_tid_t t, bufferlist& bl, Connection *co) : cmd(c), tid(t), indata(bl), con(co) {} }; list command_queue; struct CommandWQ : public ThreadPool::WorkQueue { OSD *osd; CommandWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueue("OSD::CommandWQ", ti, si, tp), osd(o) {} bool _empty() { return osd->command_queue.empty(); } bool _enqueue(Command *c) { osd->command_queue.push_back(c); return true; } void _dequeue(Command *pg) { assert(0); } Command *_dequeue() { if (osd->command_queue.empty()) return NULL; Command *c = osd->command_queue.front(); osd->command_queue.pop_front(); return c; } void _process(Command *c) { osd->osd_lock.Lock(); if (osd->is_stopping()) { osd->osd_lock.Unlock(); delete c; return; } osd->do_command(c->con.get(), c->tid, c->cmd, c->indata); osd->osd_lock.Unlock(); delete c; } void _clear() { while (!osd->command_queue.empty()) { Command *c = osd->command_queue.front(); osd->command_queue.pop_front(); delete c; } } } command_wq; void handle_command(class MMonCommand *m); void handle_command(class MCommand *m); void do_command(Connection *con, ceph_tid_t tid, vector& cmd, bufferlist& data); // -- pg recovery -- xlist recovery_queue; utime_t defer_recovery_until; int recovery_ops_active; #ifdef DEBUG_RECOVERY_OIDS map > recovery_oids; #endif struct RecoveryWQ : public ThreadPool::WorkQueue { OSD *osd; RecoveryWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueue("OSD::RecoveryWQ", ti, si, tp), osd(o) {} bool _empty() { return osd->recovery_queue.empty(); } bool _enqueue(PG *pg); void _dequeue(PG *pg) { if (pg->recovery_item.remove_myself()) pg->put("RecoveryWQ"); } PG *_dequeue() { if (osd->recovery_queue.empty()) return NULL; if (!osd->_recover_now()) return NULL; PG *pg = osd->recovery_queue.front(); osd->recovery_queue.pop_front(); return pg; } void _queue_front(PG *pg) { if (!pg->recovery_item.is_on_list()) { pg->get("RecoveryWQ"); osd->recovery_queue.push_front(&pg->recovery_item); } } void _process(PG *pg, ThreadPool::TPHandle &handle) { osd->do_recovery(pg, handle); pg->put("RecoveryWQ"); } void _clear() { while (!osd->recovery_queue.empty()) { PG *pg = osd->recovery_queue.front(); osd->recovery_queue.pop_front(); pg->put("RecoveryWQ"); } } } recovery_wq; void start_recovery_op(PG *pg, const hobject_t& soid); void finish_recovery_op(PG *pg, const hobject_t& soid, bool dequeue); void do_recovery(PG *pg, ThreadPool::TPHandle &handle); bool _recover_now(); // replay / delayed pg activation Mutex replay_queue_lock; list< pair > replay_queue; void check_replay_queue(); // -- snap trimming -- xlist snap_trim_queue; struct SnapTrimWQ : public ThreadPool::WorkQueue { OSD *osd; SnapTrimWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueue("OSD::SnapTrimWQ", ti, si, tp), osd(o) {} bool _empty() { return osd->snap_trim_queue.empty(); } bool _enqueue(PG *pg) { if (pg->snap_trim_item.is_on_list()) return false; pg->get("SnapTrimWQ"); osd->snap_trim_queue.push_back(&pg->snap_trim_item); return true; } void _dequeue(PG *pg) { if (pg->snap_trim_item.remove_myself()) pg->put("SnapTrimWQ"); } PG *_dequeue() { if (osd->snap_trim_queue.empty()) return NULL; PG *pg = osd->snap_trim_queue.front(); osd->snap_trim_queue.pop_front(); return pg; } void _process(PG *pg) { pg->snap_trimmer(); pg->put("SnapTrimWQ"); } void _clear() { while (PG *pg = _dequeue()) { pg->put("SnapTrimWQ"); } } } snap_trim_wq; // -- scrubbing -- void sched_scrub(); bool scrub_random_backoff(); bool scrub_should_schedule(); xlist scrub_queue; struct ScrubWQ : public ThreadPool::WorkQueue { OSD *osd; ScrubWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueue("OSD::ScrubWQ", ti, si, tp), osd(o) {} bool _empty() { return osd->scrub_queue.empty(); } bool _enqueue(PG *pg) { if (pg->scrub_item.is_on_list()) { return false; } pg->get("ScrubWQ"); osd->scrub_queue.push_back(&pg->scrub_item); return true; } void _dequeue(PG *pg) { if (pg->scrub_item.remove_myself()) { pg->put("ScrubWQ"); } } PG *_dequeue() { if (osd->scrub_queue.empty()) return NULL; PG *pg = osd->scrub_queue.front(); osd->scrub_queue.pop_front(); return pg; } void _process( PG *pg, ThreadPool::TPHandle &handle) { pg->scrub(handle); pg->put("ScrubWQ"); } void _clear() { while (!osd->scrub_queue.empty()) { PG *pg = osd->scrub_queue.front(); osd->scrub_queue.pop_front(); pg->put("ScrubWQ"); } } } scrub_wq; struct ScrubFinalizeWQ : public ThreadPool::WorkQueue { private: xlist scrub_finalize_queue; public: ScrubFinalizeWQ(time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueue("OSD::ScrubFinalizeWQ", ti, si, tp) {} bool _empty() { return scrub_finalize_queue.empty(); } bool _enqueue(PG *pg) { if (pg->scrub_finalize_item.is_on_list()) { return false; } pg->get("ScrubFinalizeWQ"); scrub_finalize_queue.push_back(&pg->scrub_finalize_item); return true; } void _dequeue(PG *pg) { if (pg->scrub_finalize_item.remove_myself()) { pg->put("ScrubFinalizeWQ"); } } PG *_dequeue() { if (scrub_finalize_queue.empty()) return NULL; PG *pg = scrub_finalize_queue.front(); scrub_finalize_queue.pop_front(); return pg; } void _process(PG *pg) { pg->scrub_finalize(); pg->put("ScrubFinalizeWQ"); } void _clear() { while (!scrub_finalize_queue.empty()) { PG *pg = scrub_finalize_queue.front(); scrub_finalize_queue.pop_front(); pg->put("ScrubFinalizeWQ"); } } } scrub_finalize_wq; struct RepScrubWQ : public ThreadPool::WorkQueue { private: OSD *osd; list rep_scrub_queue; public: RepScrubWQ(OSD *o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueue("OSD::RepScrubWQ", ti, si, tp), osd(o) {} bool _empty() { return rep_scrub_queue.empty(); } bool _enqueue(MOSDRepScrub *msg) { rep_scrub_queue.push_back(msg); return true; } void _dequeue(MOSDRepScrub *msg) { assert(0); // Not applicable for this wq return; } MOSDRepScrub *_dequeue() { if (rep_scrub_queue.empty()) return NULL; MOSDRepScrub *msg = rep_scrub_queue.front(); rep_scrub_queue.pop_front(); return msg; } void _process( MOSDRepScrub *msg, ThreadPool::TPHandle &handle) { osd->osd_lock.Lock(); if (osd->is_stopping()) { osd->osd_lock.Unlock(); return; } if (osd->_have_pg(msg->pgid)) { PG *pg = osd->_lookup_lock_pg(msg->pgid); osd->osd_lock.Unlock(); pg->replica_scrub(msg, handle); msg->put(); pg->unlock(); } else { msg->put(); osd->osd_lock.Unlock(); } } void _clear() { while (!rep_scrub_queue.empty()) { MOSDRepScrub *msg = rep_scrub_queue.front(); rep_scrub_queue.pop_front(); msg->put(); } } } rep_scrub_wq; // -- removing -- struct RemoveWQ : public ThreadPool::WorkQueueVal > { ObjectStore *&store; list > remove_queue; RemoveWQ(ObjectStore *&o, time_t ti, time_t si, ThreadPool *tp) : ThreadPool::WorkQueueVal >( "OSD::RemoveWQ", ti, si, tp), store(o) {} bool _empty() { return remove_queue.empty(); } void _enqueue(pair item) { remove_queue.push_back(item); } void _enqueue_front(pair item) { remove_queue.push_front(item); } bool _dequeue(pair item) { assert(0); } pair _dequeue() { assert(!remove_queue.empty()); pair item = remove_queue.front(); remove_queue.pop_front(); return item; } void _process(pair, ThreadPool::TPHandle &); void _clear() { remove_queue.clear(); } } remove_wq; uint64_t next_removal_seq; coll_t get_next_removal_coll(spg_t pgid) { return coll_t::make_removal_coll(next_removal_seq++, pgid); } private: bool ms_dispatch(Message *m); bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); bool ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key); void ms_handle_connect(Connection *con); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con) {} public: /* internal and external can point to the same messenger, they will still * be cleaned up properly*/ OSD(CephContext *cct_, ObjectStore *store_, int id, Messenger *internal, Messenger *external, Messenger *hb_client, Messenger *hb_front_server, Messenger *hb_back_server, Messenger *osdc_messenger, MonClient *mc, const std::string &dev, const std::string &jdev); ~OSD(); // static bits static int find_osd_dev(char *result, int whoami); static int do_convertfs(ObjectStore *store); static int convert_collection(ObjectStore *store, coll_t cid); static int mkfs(CephContext *cct, ObjectStore *store, const string& dev, uuid_d fsid, int whoami); /* remove any non-user xattrs from a map of them */ void filter_xattrs(map& attrs) { for (map::iterator iter = attrs.begin(); iter != attrs.end(); ) { if (('_' != iter->first.at(0)) || (iter->first.size() == 1)) attrs.erase(iter++); else ++iter; } } private: static int write_meta(ObjectStore *store, uuid_d& cluster_fsid, uuid_d& osd_fsid, int whoami); public: static int peek_meta(ObjectStore *store, string& magic, uuid_d& cluster_fsid, uuid_d& osd_fsid, int& whoami); // startup/shutdown int pre_init(); int init(); void final_init(); void suicide(int exitcode); int shutdown(); void handle_signal(int signum); void handle_rep_scrub(MOSDRepScrub *m); void handle_scrub(struct MOSDScrub *m); void handle_osd_ping(class MOSDPing *m); void handle_op(OpRequestRef op); template void handle_replica_op(OpRequestRef op); /// check if we can throw out op from a disconnected client static bool op_is_discardable(class MOSDOp *m); /// check if op should be (re)queued for processing public: void force_remount(); int init_op_flags(OpRequestRef op); OSDService service; friend class OSDService; }; //compatibility of the executable extern const CompatSet::Feature ceph_osd_feature_compat[]; extern const CompatSet::Feature ceph_osd_feature_ro_compat[]; extern const CompatSet::Feature ceph_osd_feature_incompat[]; #endif ceph-0.80.11/src/osd/HitSet.cc0000664000175100017510000001247412623076744017770 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "HitSet.h" // -- HitSet -- HitSet::HitSet(const HitSet::Params& params) : sealed(false) { switch (params.get_type()) { case TYPE_BLOOM: { BloomHitSet::Params *p = static_cast(params.impl.get()); impl.reset(new BloomHitSet(p)); } break; case TYPE_EXPLICIT_HASH: impl.reset(new ExplicitHashHitSet(static_cast(params.impl.get()))); break; case TYPE_EXPLICIT_OBJECT: impl.reset(new ExplicitObjectHitSet(static_cast(params.impl.get()))); break; case TYPE_NONE: break; default: assert (0 == "unknown HitSet type"); } } void HitSet::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(sealed, bl); if (impl) { ::encode((__u8)impl->get_type(), bl); impl->encode(bl); } else { ::encode((__u8)TYPE_NONE, bl); } ENCODE_FINISH(bl); } void HitSet::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(sealed, bl); __u8 type; ::decode(type, bl); switch ((impl_type_t)type) { case TYPE_EXPLICIT_HASH: impl.reset(new ExplicitHashHitSet); break; case TYPE_EXPLICIT_OBJECT: impl.reset(new ExplicitObjectHitSet); break; case TYPE_BLOOM: impl.reset(new BloomHitSet); break; case TYPE_NONE: impl.reset(NULL); break; default: throw buffer::malformed_input("unrecognized HitMap type"); } if (impl) impl->decode(bl); DECODE_FINISH(bl); } void HitSet::dump(Formatter *f) const { f->dump_string("type", get_type_name()); f->dump_string("sealed", sealed ? "yes" : "no"); if (impl) impl->dump(f); } void HitSet::generate_test_instances(list& o) { o.push_back(new HitSet); o.push_back(new HitSet(new BloomHitSet(10, .1, 1))); o.back()->insert(hobject_t()); o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, "")); o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, "")); o.push_back(new HitSet(new ExplicitHashHitSet)); o.back()->insert(hobject_t()); o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, "")); o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, "")); o.push_back(new HitSet(new ExplicitObjectHitSet)); o.back()->insert(hobject_t()); o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, "")); o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, "")); } HitSet::Params::Params(const Params& o) { if (o.get_type() != TYPE_NONE) { create_impl(o.get_type()); // it's annoying to write virtual operator= methods; use encode/decode // instead. bufferlist bl; o.impl->encode(bl); bufferlist::iterator p = bl.begin(); impl->decode(p); } // else we don't need to do anything } const HitSet::Params& HitSet::Params::operator=(const Params& o) { create_impl(o.get_type()); if (o.impl) { // it's annoying to write virtual operator= methods; use encode/decode // instead. bufferlist bl; o.impl->encode(bl); bufferlist::iterator p = bl.begin(); impl->decode(p); } return *this; } void HitSet::Params::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); if (impl) { ::encode((__u8)impl->get_type(), bl); impl->encode(bl); } else { ::encode((__u8)TYPE_NONE, bl); } ENCODE_FINISH(bl); } bool HitSet::Params::create_impl(impl_type_t type) { switch ((impl_type_t)type) { case TYPE_EXPLICIT_HASH: impl.reset(new ExplicitHashHitSet::Params); break; case TYPE_EXPLICIT_OBJECT: impl.reset(new ExplicitObjectHitSet::Params); break; case TYPE_BLOOM: impl.reset(new BloomHitSet::Params); break; case TYPE_NONE: impl.reset(NULL); break; default: return false; } return true; } void HitSet::Params::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); __u8 type; ::decode(type, bl); if (!create_impl((impl_type_t)type)) throw buffer::malformed_input("unrecognized HitMap type"); if (impl) impl->decode(bl); DECODE_FINISH(bl); } void HitSet::Params::dump(Formatter *f) const { f->dump_string("type", HitSet::get_type_name(get_type())); if (impl) impl->dump(f); } void HitSet::Params::generate_test_instances(list& o) { #define loop_hitset_params(kind) \ { \ list params; \ kind::Params::generate_test_instances(params); \ for (list::iterator i = params.begin(); \ i != params.end(); ++i) \ o.push_back(new Params(*i)); \ } o.push_back(new Params); o.push_back(new Params(new BloomHitSet::Params)); loop_hitset_params(BloomHitSet); o.push_back(new Params(new ExplicitHashHitSet::Params)); loop_hitset_params(ExplicitHashHitSet); o.push_back(new Params(new ExplicitObjectHitSet::Params)); loop_hitset_params(ExplicitObjectHitSet); } ostream& operator<<(ostream& out, const HitSet::Params& p) { out << HitSet::get_type_name(p.get_type()); if (p.impl) { out << "{"; p.impl->dump_stream(out); } out << "}"; return out; } ceph-0.80.11/src/osd/PG.cc0000664000175100017510000070403412623076744017076 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "PG.h" #include "common/errno.h" #include "common/config.h" #include "OSD.h" #include "OpRequest.h" #include "common/Timer.h" #include "messages/MOSDOp.h" #include "messages/MOSDPGNotify.h" #include "messages/MOSDPGLog.h" #include "messages/MOSDPGRemove.h" #include "messages/MOSDPGInfo.h" #include "messages/MOSDPGTrim.h" #include "messages/MOSDPGScan.h" #include "messages/MOSDPGBackfill.h" #include "messages/MBackfillReserve.h" #include "messages/MRecoveryReserve.h" #include "messages/MOSDPGPush.h" #include "messages/MOSDPGPushReply.h" #include "messages/MOSDPGPull.h" #include "messages/MOSDECSubOpWrite.h" #include "messages/MOSDECSubOpWriteReply.h" #include "messages/MOSDECSubOpRead.h" #include "messages/MOSDECSubOpReadReply.h" #include "messages/MOSDSubOp.h" #include "messages/MOSDSubOpReply.h" #include "common/BackTrace.h" #include #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout, this) template static ostream& _prefix(std::ostream *_dout, T *t) { return *_dout << t->gen_prefix(); } void PG::get(const string &tag) { ref.inc(); #ifdef PG_DEBUG_REFS Mutex::Locker l(_ref_id_lock); if (!_tag_counts.count(tag)) { _tag_counts[tag] = 0; } _tag_counts[tag]++; #endif } void PG::put(const string &tag) { #ifdef PG_DEBUG_REFS { Mutex::Locker l(_ref_id_lock); assert(_tag_counts.count(tag)); _tag_counts[tag]--; if (_tag_counts[tag] == 0) { _tag_counts.erase(tag); } } #endif if (ref.dec() == 0) delete this; } #ifdef PG_DEBUG_REFS uint64_t PG::get_with_id() { ref.inc(); Mutex::Locker l(_ref_id_lock); uint64_t id = ++_ref_id; BackTrace bt(0); stringstream ss; bt.print(ss); dout(20) << __func__ << ": " << info.pgid << " got id " << id << dendl; assert(!_live_ids.count(id)); _live_ids.insert(make_pair(id, ss.str())); return id; } void PG::put_with_id(uint64_t id) { dout(20) << __func__ << ": " << info.pgid << " put id " << id << dendl; { Mutex::Locker l(_ref_id_lock); assert(_live_ids.count(id)); _live_ids.erase(id); } if (ref.dec() == 0) delete this; } void PG::dump_live_ids() { Mutex::Locker l(_ref_id_lock); dout(0) << "\t" << __func__ << ": " << info.pgid << " live ids:" << dendl; for (map::iterator i = _live_ids.begin(); i != _live_ids.end(); ++i) { dout(0) << "\t\tid: " << *i << dendl; } dout(0) << "\t" << __func__ << ": " << info.pgid << " live tags:" << dendl; for (map::iterator i = _tag_counts.begin(); i != _tag_counts.end(); ++i) { dout(0) << "\t\tid: " << *i << dendl; } } #endif void PGPool::update(OSDMapRef map) { const pg_pool_t *pi = map->get_pg_pool(id); assert(pi); info = *pi; auid = pi->auid; name = map->get_pool_name(id); if (pi->get_snap_epoch() == map->get_epoch()) { pi->build_removed_snaps(newly_removed_snaps); newly_removed_snaps.subtract(cached_removed_snaps); cached_removed_snaps.union_of(newly_removed_snaps); snapc = pi->get_snap_context(); } else { newly_removed_snaps.clear(); } lgeneric_subdout(g_ceph_context, osd, 20) << "PGPool::update cached_removed_snaps " << cached_removed_snaps << " newly_removed_snaps " << newly_removed_snaps << " snapc " << snapc << (pi->get_snap_epoch() == map->get_epoch() ? " (updated)":" (no change)") << dendl; } PG::PG(OSDService *o, OSDMapRef curmap, const PGPool &_pool, spg_t p, const hobject_t& loid, const hobject_t& ioid) : osd(o), cct(o->cct), osdriver(osd->store, coll_t(), OSD::make_snapmapper_oid()), snap_mapper( &osdriver, p.ps(), p.get_split_bits(curmap->get_pg_num(_pool.id)), _pool.id, p.shard), map_lock("PG::map_lock"), osdmap_ref(curmap), last_persisted_osdmap_ref(curmap), pool(_pool), _lock("PG::_lock"), ref(0), #ifdef PG_DEBUG_REFS _ref_id_lock("PG::_ref_id_lock"), _ref_id(0), #endif deleting(false), dirty_info(false), dirty_big_info(false), info(p), info_struct_v(0), coll(p), pg_log(cct), log_oid(loid), biginfo_oid(ioid), missing_loc(this), recovery_item(this), scrub_item(this), scrub_finalize_item(this), snap_trim_item(this), stat_queue_item(this), recovery_ops_active(0), role(0), state(0), send_notify(false), pg_whoami(osd->whoami, p.shard), need_up_thru(false), last_peering_reset(0), heartbeat_peer_lock("PG::heartbeat_peer_lock"), backfill_reserved(0), backfill_reserving(0), flushes_in_progress(0), pg_stats_publish_lock("PG::pg_stats_publish_lock"), pg_stats_publish_valid(false), osr(osd->osr_registry.lookup_or_create(p, (stringify(p)))), finish_sync_event(NULL), scrub_after_recovery(false), active_pushes(0), recovery_state(this), peer_features((uint64_t)-1) { #ifdef PG_DEBUG_REFS osd->add_pgid(p, this); #endif } PG::~PG() { #ifdef PG_DEBUG_REFS osd->remove_pgid(info.pgid, this); #endif } void PG::lock_suspend_timeout(ThreadPool::TPHandle &handle) { handle.suspend_tp_timeout(); lock(); handle.reset_tp_timeout(); } void PG::lock(bool no_lockdep) { _lock.Lock(no_lockdep); // if we have unrecorded dirty state with the lock dropped, there is a bug assert(!dirty_info); assert(!dirty_big_info); dout(30) << "lock" << dendl; } std::string PG::gen_prefix() const { stringstream out; OSDMapRef mapref = osdmap_ref; if (_lock.is_locked_by_me()) { out << "osd." << osd->whoami << " pg_epoch: " << (mapref ? mapref->get_epoch():0) << " " << *this << " "; } else { out << "osd." << osd->whoami << " pg_epoch: " << (mapref ? mapref->get_epoch():0) << " pg[" << info.pgid << "(unlocked)] "; } return out.str(); } /********* PG **********/ void PG::proc_master_log( ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_missing_t& omissing, pg_shard_t from) { dout(10) << "proc_master_log for osd." << from << ": " << olog << " " << omissing << dendl; assert(!is_active() && is_primary()); // merge log into our own log to build master log. no need to // make any adjustments to their missing map; we are taking their // log to be authoritative (i.e., their entries are by definitely // non-divergent). merge_log(t, oinfo, olog, from); peer_info[from] = oinfo; dout(10) << " peer osd." << from << " now " << oinfo << " " << omissing << dendl; might_have_unfound.insert(from); peer_missing[from].swap(omissing); } void PG::proc_replica_log( ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_missing_t& omissing, pg_shard_t from) { dout(10) << "proc_replica_log for osd." << from << ": " << oinfo << " " << olog << " " << omissing << dendl; pg_log.proc_replica_log(t, oinfo, olog, omissing, from); peer_info[from] = oinfo; dout(10) << " peer osd." << from << " now " << oinfo << " " << omissing << dendl; might_have_unfound.insert(from); for (map::iterator i = omissing.missing.begin(); i != omissing.missing.end(); ++i) { dout(20) << " after missing " << i->first << " need " << i->second.need << " have " << i->second.have << dendl; } peer_missing[from].swap(omissing); } bool PG::proc_replica_info(pg_shard_t from, const pg_info_t &oinfo) { map::iterator p = peer_info.find(from); if (p != peer_info.end() && p->second.last_update == oinfo.last_update) { dout(10) << " got dup osd." << from << " info " << oinfo << ", identical to ours" << dendl; return false; } dout(10) << " got osd." << from << " " << oinfo << dendl; assert(is_primary()); peer_info[from] = oinfo; might_have_unfound.insert(from); unreg_next_scrub(); if (info.history.merge(oinfo.history)) dirty_info = true; reg_next_scrub(); // stray? if (!is_up(from) && !is_acting(from)) { dout(10) << " osd." << from << " has stray content: " << oinfo << dendl; stray_set.insert(from); if (is_clean()) { purge_strays(); } } // was this a new info? if so, update peers! if (p == peer_info.end()) update_heartbeat_peers(); return true; } void PG::remove_snap_mapped_object( ObjectStore::Transaction &t, const hobject_t &soid) { t.remove( coll, ghobject_t(soid, ghobject_t::NO_GEN, pg_whoami.shard)); clear_object_snap_mapping(&t, soid); } void PG::clear_object_snap_mapping( ObjectStore::Transaction *t, const hobject_t &soid) { OSDriver::OSTransaction _t(osdriver.get_transaction(t)); if (soid.snap < CEPH_MAXSNAP) { int r = snap_mapper.remove_oid( soid, &_t); if (!(r == 0 || r == -ENOENT)) { derr << __func__ << ": remove_oid returned " << cpp_strerror(r) << dendl; assert(0); } } } void PG::update_object_snap_mapping( ObjectStore::Transaction *t, const hobject_t &soid, const set &snaps) { OSDriver::OSTransaction _t(osdriver.get_transaction(t)); assert(soid.snap < CEPH_MAXSNAP); int r = snap_mapper.remove_oid( soid, &_t); if (!(r == 0 || r == -ENOENT)) { derr << __func__ << ": remove_oid returned " << cpp_strerror(r) << dendl; assert(0); } snap_mapper.add_oid( soid, snaps, &_t); } void PG::merge_log( ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_shard_t from) { PGLogEntryHandler rollbacker; pg_log.merge_log( t, oinfo, olog, from, info, &rollbacker, dirty_info, dirty_big_info); rollbacker.apply(this, &t); } void PG::rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead) { PGLogEntryHandler rollbacker; pg_log.rewind_divergent_log( t, newhead, info, &rollbacker, dirty_info, dirty_big_info); rollbacker.apply(this, &t); } /* * Process information from a replica to determine if it could have any * objects that i need. * * TODO: if the missing set becomes very large, this could get expensive. * Instead, we probably want to just iterate over our unfound set. */ bool PG::search_for_missing( const pg_info_t &oinfo, const pg_missing_t &omissing, pg_shard_t from, RecoveryCtx *ctx) { unsigned num_unfound_before = missing_loc.num_unfound(); bool found_missing = missing_loc.add_source_info( from, oinfo, omissing); if (found_missing && num_unfound_before != missing_loc.num_unfound()) publish_stats_to_osd(); if (found_missing && (get_osdmap()->get_features(CEPH_ENTITY_TYPE_OSD, NULL) & CEPH_FEATURE_OSD_ERASURE_CODES)) { pg_info_t tinfo(oinfo); tinfo.pgid.shard = pg_whoami.shard; (*(ctx->info_map))[from.osd].push_back( make_pair( pg_notify_t( from.shard, pg_whoami.shard, get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), tinfo), past_intervals)); } return found_missing; } bool PG::MissingLoc::readable_with_acting( const hobject_t &hoid, const set &acting) const { if (!needs_recovery(hoid)) return true; if (!missing_loc.count(hoid)) return false; const set &locs = missing_loc.find(hoid)->second; dout(10) << __func__ << ": locs:" << locs << dendl; set have_acting; for (set::const_iterator i = locs.begin(); i != locs.end(); ++i) { if (acting.count(*i)) have_acting.insert(*i); } return (*is_readable)(have_acting); } bool PG::MissingLoc::add_source_info( pg_shard_t fromosd, const pg_info_t &oinfo, const pg_missing_t &omissing) { bool found_missing = false;; // found items? for (map::const_iterator p = needs_recovery_map.begin(); p != needs_recovery_map.end(); ++p) { const hobject_t &soid(p->first); eversion_t need = p->second.need; if (oinfo.last_update < need) { dout(10) << "search_for_missing " << soid << " " << need << " also missing on osd." << fromosd << " (last_update " << oinfo.last_update << " < needed " << need << ")" << dendl; continue; } if (p->first >= oinfo.last_backfill) { // FIXME: this is _probably_ true, although it could conceivably // be in the undefined region! Hmm! dout(10) << "search_for_missing " << soid << " " << need << " also missing on osd." << fromosd << " (past last_backfill " << oinfo.last_backfill << ")" << dendl; continue; } if (oinfo.last_complete < need) { if (omissing.is_missing(soid)) { dout(10) << "search_for_missing " << soid << " " << need << " also missing on osd." << fromosd << dendl; continue; } } dout(10) << "search_for_missing " << soid << " " << need << " is on osd." << fromosd << dendl; missing_loc[soid].insert(fromosd); missing_loc_sources.insert(fromosd); found_missing = true; } dout(20) << "needs_recovery_map missing " << needs_recovery_map << dendl; return found_missing; } void PG::discover_all_missing(map > &query_map) { const pg_missing_t &missing = pg_log.get_missing(); assert(have_unfound()); dout(10) << __func__ << " " << missing.num_missing() << " missing, " << get_num_unfound() << " unfound" << dendl; std::set::const_iterator m = might_have_unfound.begin(); std::set::const_iterator mend = might_have_unfound.end(); for (; m != mend; ++m) { pg_shard_t peer(*m); if (!get_osdmap()->is_up(peer.osd)) { dout(20) << __func__ << " skipping down osd." << peer << dendl; continue; } map::const_iterator iter = peer_info.find(peer); if (iter != peer_info.end() && (iter->second.is_empty() || iter->second.dne())) { // ignore empty peers continue; } // If we've requested any of this stuff, the pg_missing_t information // should be on its way. // TODO: coalsce requested_* into a single data structure if (peer_missing.find(peer) != peer_missing.end()) { dout(20) << __func__ << ": osd." << peer << ": we already have pg_missing_t" << dendl; continue; } if (peer_log_requested.find(peer) != peer_log_requested.end()) { dout(20) << __func__ << ": osd." << peer << ": in peer_log_requested" << dendl; continue; } if (peer_missing_requested.find(peer) != peer_missing_requested.end()) { dout(20) << __func__ << ": osd." << peer << ": in peer_missing_requested" << dendl; continue; } // Request missing dout(10) << __func__ << ": osd." << peer << ": requesting pg_missing_t" << dendl; peer_missing_requested.insert(peer); query_map[peer.osd][spg_t(info.pgid.pgid, peer.shard)] = pg_query_t( pg_query_t::FULLLOG, peer.shard, pg_whoami.shard, info.history, get_osdmap()->get_epoch()); } } /******* PG ***********/ bool PG::needs_recovery() const { assert(is_primary()); bool ret = false; const pg_missing_t &missing = pg_log.get_missing(); if (missing.num_missing()) { dout(10) << __func__ << " primary has " << missing.num_missing() << " missing" << dendl; ret = true; } assert(!actingbackfill.empty()); set::const_iterator end = actingbackfill.end(); set::const_iterator a = actingbackfill.begin(); assert(a != end); for (; a != end; ++a) { if (*a == get_primary()) continue; pg_shard_t peer = *a; map::const_iterator pm = peer_missing.find(peer); if (pm == peer_missing.end()) { dout(10) << __func__ << " osd." << peer << " doesn't have missing set" << dendl; ret = true; continue; } if (pm->second.num_missing()) { dout(10) << __func__ << " osd." << peer << " has " << pm->second.num_missing() << " missing" << dendl; ret = true; } } if (!ret) dout(10) << __func__ << " is recovered" << dendl; return ret; } bool PG::needs_backfill() const { assert(is_primary()); bool ret = false; // We can assume that only possible osds that need backfill // are on the backfill_targets vector nodes. set::const_iterator end = backfill_targets.end(); set::const_iterator a = backfill_targets.begin(); for (; a != end; ++a) { pg_shard_t peer = *a; map::const_iterator pi = peer_info.find(peer); if (!pi->second.last_backfill.is_max()) { dout(10) << __func__ << " osd." << peer << " has last_backfill " << pi->second.last_backfill << dendl; ret = true; } } if (!ret) dout(10) << __func__ << " does not need backfill" << dendl; return ret; } bool PG::_calc_past_interval_range(epoch_t *start, epoch_t *end, epoch_t oldest_map) { *end = info.history.same_interval_since; // Do we already have the intervals we want? map::const_iterator pif = past_intervals.begin(); if (pif != past_intervals.end()) { if (pif->first <= info.history.last_epoch_clean) { dout(10) << __func__ << ": already have past intervals back to " << info.history.last_epoch_clean << dendl; return false; } *end = past_intervals.begin()->first; } *start = MAX(MAX(info.history.epoch_created, info.history.last_epoch_clean), oldest_map); if (*start >= *end) { dout(10) << __func__ << " start epoch " << *start << " >= end epoch " << *end << ", nothing to do" << dendl; return false; } return true; } void PG::generate_past_intervals() { epoch_t cur_epoch, end_epoch; if (!_calc_past_interval_range(&cur_epoch, &end_epoch, osd->get_superblock().oldest_map)) { return; } OSDMapRef last_map, cur_map; int primary = -1; int up_primary = -1; vector acting, up, old_acting, old_up; cur_map = osd->get_map(cur_epoch); cur_map->pg_to_up_acting_osds( get_pgid().pgid, &up, &up_primary, &acting, &primary); epoch_t same_interval_since = cur_epoch; dout(10) << __func__ << " over epochs " << cur_epoch << "-" << end_epoch << dendl; ++cur_epoch; for (; cur_epoch <= end_epoch; ++cur_epoch) { int old_primary = primary; int old_up_primary = up_primary; last_map.swap(cur_map); old_up.swap(up); old_acting.swap(acting); cur_map = osd->get_map(cur_epoch); pg_t pgid = get_pgid().pgid; if (last_map->get_pools().count(pgid.pool())) pgid = pgid.get_ancestor(last_map->get_pg_num(pgid.pool())); cur_map->pg_to_up_acting_osds(pgid, &up, &up_primary, &acting, &primary); std::stringstream debug; bool new_interval = pg_interval_t::check_new_interval( old_primary, primary, old_acting, acting, old_up_primary, up_primary, old_up, up, same_interval_since, info.history.last_epoch_clean, cur_map, last_map, pgid.pool(), pgid, &past_intervals, &debug); if (new_interval) { dout(10) << debug.str() << dendl; same_interval_since = cur_epoch; } } // record our work. dirty_info = true; dirty_big_info = true; } /* * Trim past_intervals. * * This gets rid of all the past_intervals that happened before last_epoch_clean. */ void PG::trim_past_intervals() { std::map::iterator pif = past_intervals.begin(); std::map::iterator end = past_intervals.end(); while (pif != end) { if (pif->second.last >= info.history.last_epoch_clean) return; dout(10) << __func__ << ": trimming " << pif->second << dendl; past_intervals.erase(pif++); dirty_big_info = true; } } bool PG::adjust_need_up_thru(const OSDMapRef osdmap) { epoch_t up_thru = get_osdmap()->get_up_thru(osd->whoami); if (need_up_thru && up_thru >= info.history.same_interval_since) { dout(10) << "adjust_need_up_thru now " << up_thru << ", need_up_thru now false" << dendl; need_up_thru = false; return true; } return false; } void PG::remove_down_peer_info(const OSDMapRef osdmap) { // Remove any downed osds from peer_info bool removed = false; map::iterator p = peer_info.begin(); while (p != peer_info.end()) { if (!osdmap->is_up(p->first.osd)) { dout(10) << " dropping down osd." << p->first << " info " << p->second << dendl; peer_missing.erase(p->first); peer_log_requested.erase(p->first); peer_missing_requested.erase(p->first); peer_info.erase(p++); removed = true; } else ++p; } // if we removed anyone, update peers (which include peer_info) if (removed) update_heartbeat_peers(); check_recovery_sources(osdmap); } /* * Returns true unless there is a non-lost OSD in might_have_unfound. */ bool PG::all_unfound_are_queried_or_lost(const OSDMapRef osdmap) const { assert(is_primary()); set::const_iterator peer = might_have_unfound.begin(); set::const_iterator mend = might_have_unfound.end(); for (; peer != mend; ++peer) { if (peer_missing.count(*peer)) continue; map::const_iterator iter = peer_info.find(*peer); if (iter != peer_info.end() && (iter->second.is_empty() || iter->second.dne())) continue; if (!osdmap->exists(peer->osd)) continue; const osd_info_t &osd_info(osdmap->get_info(peer->osd)); if (osd_info.lost_at <= osd_info.up_from) { // If there is even one OSD in might_have_unfound that isn't lost, we // still might retrieve our unfound. return false; } } dout(10) << "all_unfound_are_queried_or_lost all of might_have_unfound " << might_have_unfound << " have been queried or are marked lost" << dendl; return true; } void PG::build_prior(std::auto_ptr &prior_set) { if (1) { // sanity check for (map::iterator it = peer_info.begin(); it != peer_info.end(); ++it) { assert(info.history.last_epoch_started >= it->second.history.last_epoch_started); } } prior_set.reset( new PriorSet( pool.info.ec_pool(), get_pgbackend()->get_is_recoverable_predicate(), *get_osdmap(), past_intervals, up, acting, info, this)); PriorSet &prior(*prior_set.get()); if (prior.pg_down) { state_set(PG_STATE_DOWN); } if (get_osdmap()->get_up_thru(osd->whoami) < info.history.same_interval_since) { dout(10) << "up_thru " << get_osdmap()->get_up_thru(osd->whoami) << " < same_since " << info.history.same_interval_since << ", must notify monitor" << dendl; need_up_thru = true; } else { dout(10) << "up_thru " << get_osdmap()->get_up_thru(osd->whoami) << " >= same_since " << info.history.same_interval_since << ", all is well" << dendl; need_up_thru = false; } set_probe_targets(prior_set->probe); } void PG::clear_primary_state() { dout(10) << "clear_primary_state" << dendl; // clear peering state stray_set.clear(); peer_log_requested.clear(); peer_missing_requested.clear(); peer_info.clear(); peer_missing.clear(); need_up_thru = false; peer_last_complete_ondisk.clear(); peer_activated.clear(); min_last_complete_ondisk = eversion_t(); pg_trim_to = eversion_t(); stray_purged.clear(); might_have_unfound.clear(); last_update_ondisk = eversion_t(); snap_trimq.clear(); finish_sync_event = 0; // so that _finish_recvoery doesn't go off in another thread missing_loc.clear(); pg_log.reset_recovery_pointers(); scrubber.reserved_peers.clear(); scrub_after_recovery = false; osd->recovery_wq.dequeue(this); osd->snap_trim_wq.dequeue(this); agent_clear(); } /** * find_best_info * * Returns an iterator to the best info in infos sorted by: * 1) Prefer newer last_update * 2) Prefer longer tail if it brings another info into contiguity * 3) Prefer current primary */ map::const_iterator PG::find_best_info( const map &infos) const { eversion_t min_last_update_acceptable = eversion_t::max(); epoch_t max_last_epoch_started_found = 0; for (map::const_iterator i = infos.begin(); i != infos.end(); ++i) { if (max_last_epoch_started_found < i->second.history.last_epoch_started) { min_last_update_acceptable = eversion_t::max(); max_last_epoch_started_found = i->second.history.last_epoch_started; } if (max_last_epoch_started_found < i->second.last_epoch_started) { min_last_update_acceptable = eversion_t::max(); max_last_epoch_started_found = i->second.last_epoch_started; } if (max_last_epoch_started_found == i->second.last_epoch_started) { if (min_last_update_acceptable > i->second.last_update) min_last_update_acceptable = i->second.last_update; } } if (min_last_update_acceptable == eversion_t::max()) return infos.end(); map::const_iterator best = infos.end(); // find osd with newest last_update (oldest for ec_pool). // if there are multiples, prefer // - a longer tail, if it brings another peer into log contiguity // - the current primary for (map::const_iterator p = infos.begin(); p != infos.end(); ++p) { // Only consider peers with last_update >= min_last_update_acceptable if (p->second.last_update < min_last_update_acceptable) continue; // Disquality anyone who is incomplete (not fully backfilled) if (p->second.is_incomplete()) continue; if (best == infos.end()) { best = p; continue; } // Prefer newer last_update if (pool.info.require_rollback()) { if (p->second.last_update > best->second.last_update) continue; if (p->second.last_update < best->second.last_update) { best = p; continue; } } else { if (p->second.last_update < best->second.last_update) continue; if (p->second.last_update > best->second.last_update) { best = p; continue; } } // Prefer longer tail if (p->second.log_tail > best->second.log_tail) { continue; } else if (p->second.log_tail < best->second.log_tail) { best = p; continue; } // prefer current primary (usually the caller), all things being equal if (p->first == pg_whoami) { dout(10) << "calc_acting prefer osd." << p->first << " because it is current primary" << dendl; best = p; continue; } } return best; } void PG::calc_ec_acting( map::const_iterator auth_log_shard, unsigned size, const vector &acting, pg_shard_t acting_primary, const vector &up, pg_shard_t up_primary, const map &all_info, bool compat_mode, vector *_want, set *backfill, set *acting_backfill, pg_shard_t *want_primary, ostream &ss) { vector want(size, CRUSH_ITEM_NONE); map > all_info_by_shard; unsigned usable = 0; for(map::const_iterator i = all_info.begin(); i != all_info.end(); ++i) { all_info_by_shard[i->first.shard].insert(i->first); } for (shard_id_t i = 0; i < want.size(); ++i) { ss << "For position " << (unsigned)i << ": "; if (up.size() > (unsigned)i && up[i] != CRUSH_ITEM_NONE && !all_info.find(pg_shard_t(up[i], i))->second.is_incomplete() && all_info.find(pg_shard_t(up[i], i))->second.last_update >= auth_log_shard->second.log_tail) { ss << " selecting up[i]: " << pg_shard_t(up[i], i) << std::endl; want[i] = up[i]; ++usable; continue; } if (up.size() > (unsigned)i && up[i] != CRUSH_ITEM_NONE) { ss << " backfilling up[i]: " << pg_shard_t(up[i], i) << " and "; backfill->insert(pg_shard_t(up[i], i)); } if (acting.size() > (unsigned)i && acting[i] != CRUSH_ITEM_NONE && !all_info.find(pg_shard_t(acting[i], i))->second.is_incomplete() && all_info.find(pg_shard_t(acting[i], i))->second.last_update >= auth_log_shard->second.log_tail) { ss << " selecting acting[i]: " << pg_shard_t(acting[i], i) << std::endl; want[i] = acting[i]; ++usable; } else { for (set::iterator j = all_info_by_shard[i].begin(); j != all_info_by_shard[i].end(); ++j) { assert(j->shard == i); if (!all_info.find(*j)->second.is_incomplete() && all_info.find(*j)->second.last_update >= auth_log_shard->second.log_tail) { ss << " selecting stray: " << *j << std::endl; want[i] = j->osd; ++usable; break; } } if (want[i] == CRUSH_ITEM_NONE) ss << " failed to fill position " << i << std::endl; } } bool found_primary = false; for (shard_id_t i = 0; i < want.size(); ++i) { if (want[i] != CRUSH_ITEM_NONE) { acting_backfill->insert(pg_shard_t(want[i], i)); if (!found_primary) { *want_primary = pg_shard_t(want[i], i); found_primary = true; } } } acting_backfill->insert(backfill->begin(), backfill->end()); _want->swap(want); } /** * calculate the desired acting set. * * Choose an appropriate acting set. Prefer up[0], unless it is * incomplete, or another osd has a longer tail that allows us to * bring other up nodes up to date. */ void PG::calc_replicated_acting( map::const_iterator auth_log_shard, unsigned size, const vector &acting, pg_shard_t acting_primary, const vector &up, pg_shard_t up_primary, const map &all_info, bool compat_mode, vector *want, set *backfill, set *acting_backfill, pg_shard_t *want_primary, ostream &ss) { ss << "calc_acting newest update on osd." << auth_log_shard->first << " with " << auth_log_shard->second << std::endl; pg_shard_t auth_log_shard_id = auth_log_shard->first; // select primary map::const_iterator primary; if (up.size() && !all_info.find(up_primary)->second.is_incomplete() && all_info.find(up_primary)->second.last_update >= auth_log_shard->second.log_tail) { ss << "up_primary: " << up_primary << ") selected as primary" << std::endl; primary = all_info.find(up_primary); // prefer up[0], all thing being equal } else { assert(!auth_log_shard->second.is_incomplete()); ss << "up[0] needs backfill, osd." << auth_log_shard_id << " selected as primary instead" << std::endl; primary = auth_log_shard; } ss << "calc_acting primary is osd." << primary->first << " with " << primary->second << std::endl; *want_primary = primary->first; want->push_back(primary->first.osd); acting_backfill->insert(primary->first); unsigned usable = 1; // select replicas that have log contiguity with primary. // prefer up, then acting, then any peer_info osds for (vector::const_iterator i = up.begin(); i != up.end(); ++i) { pg_shard_t up_cand = pg_shard_t(*i, ghobject_t::no_shard()); if (up_cand == primary->first) continue; const pg_info_t &cur_info = all_info.find(up_cand)->second; if (cur_info.is_incomplete() || cur_info.last_update < MIN( primary->second.log_tail, auth_log_shard->second.log_tail)) { /* We include auth_log_shard->second.log_tail because in GetLog, * we will request logs back to the min last_update over our * acting_backfill set, which will result in our log being extended * as far backwards as necessary to pick up any peers which can * be log recovered by auth_log_shard's log */ ss << " shard " << up_cand << " (up) backfill " << cur_info << std::endl; if (compat_mode) { if (backfill->empty()) { backfill->insert(up_cand); want->push_back(*i); acting_backfill->insert(up_cand); } } else { backfill->insert(up_cand); acting_backfill->insert(up_cand); } } else { want->push_back(*i); acting_backfill->insert(up_cand); usable++; ss << " osd." << *i << " (up) accepted " << cur_info << std::endl; } } // This no longer has backfill OSDs, but they are covered above. for (vector::const_iterator i = acting.begin(); i != acting.end(); ++i) { pg_shard_t acting_cand(*i, ghobject_t::no_shard()); if (usable >= size) break; // skip up osds we already considered above if (acting_cand == primary->first) continue; vector::const_iterator up_it = find(up.begin(), up.end(), acting_cand.osd); if (up_it != up.end()) continue; const pg_info_t &cur_info = all_info.find(acting_cand)->second; if (cur_info.is_incomplete() || cur_info.last_update < primary->second.log_tail) { ss << " shard " << acting_cand << " (stray) REJECTED " << cur_info << std::endl; } else { want->push_back(*i); acting_backfill->insert(acting_cand); ss << " shard " << acting_cand << " (stray) accepted " << cur_info << std::endl; usable++; } } for (map::const_iterator i = all_info.begin(); i != all_info.end(); ++i) { if (usable >= size) break; // skip up osds we already considered above if (i->first == primary->first) continue; vector::const_iterator up_it = find(up.begin(), up.end(), i->first.osd); if (up_it != up.end()) continue; vector::const_iterator acting_it = find( acting.begin(), acting.end(), i->first.osd); if (acting_it != acting.end()) continue; if (i->second.is_incomplete() || i->second.last_update < primary->second.log_tail) { ss << " shard " << i->first << " (stray) REJECTED " << i->second << std::endl; } else { want->push_back(i->first.osd); acting_backfill->insert(i->first); ss << " shard " << i->first << " (stray) accepted " << i->second << std::endl; usable++; } } } /** * choose acting * * calculate the desired acting, and request a change with the monitor * if it differs from the current acting. */ bool PG::choose_acting(pg_shard_t &auth_log_shard_id) { map all_info(peer_info.begin(), peer_info.end()); all_info[pg_whoami] = info; for (map::iterator p = all_info.begin(); p != all_info.end(); ++p) { dout(10) << "calc_acting osd." << p->first << " " << p->second << dendl; } map::const_iterator auth_log_shard = find_best_info(all_info); if (auth_log_shard == all_info.end()) { if (up != acting) { dout(10) << "choose_acting no suitable info found (incomplete backfills?)," << " reverting to up" << dendl; want_acting = up; vector empty; osd->queue_want_pg_temp(info.pgid.pgid, empty); } else { dout(10) << "choose_acting failed" << dendl; assert(want_acting.empty()); } return false; } if ((up.size() && !all_info.find(up_primary)->second.is_incomplete() && all_info.find(up_primary)->second.last_update >= auth_log_shard->second.log_tail) && auth_log_shard->second.is_incomplete()) { map complete_infos; for (map::const_iterator i = all_info.begin(); i != all_info.end(); ++i) { if (!i->second.is_incomplete()) complete_infos.insert(*i); } map::const_iterator i = find_best_info( complete_infos); if (i != complete_infos.end()) { auth_log_shard = all_info.find(i->first); } } auth_log_shard_id = auth_log_shard->first; // Determine if compatibility needed bool compat_mode = !cct->_conf->osd_debug_override_acting_compat; if (compat_mode) { bool all_support = true; OSDMapRef osdmap = get_osdmap(); for (map::iterator it = all_info.begin(); it != all_info.end(); ++it) { pg_shard_t peer = it->first; const osd_xinfo_t& xi = osdmap->get_xinfo(peer.osd); if (!(xi.features & CEPH_FEATURE_OSD_ERASURE_CODES)) { all_support = false; break; } } if (all_support) compat_mode = false; } set want_backfill, want_acting_backfill; vector want; pg_shard_t want_primary; stringstream ss; if (!pool.info.ec_pool()) calc_replicated_acting( auth_log_shard, get_osdmap()->get_pg_size(info.pgid.pgid), acting, primary, up, up_primary, all_info, compat_mode, &want, &want_backfill, &want_acting_backfill, &want_primary, ss); else calc_ec_acting( auth_log_shard, get_osdmap()->get_pg_size(info.pgid.pgid), acting, primary, up, up_primary, all_info, compat_mode, &want, &want_backfill, &want_acting_backfill, &want_primary, ss); dout(10) << ss.str() << dendl; unsigned num_want_acting = 0; for (vector::iterator i = want.begin(); i != want.end(); ++i) { if (*i != CRUSH_ITEM_NONE) ++num_want_acting; } // This is a bit of a problem, if we allow the pg to go active with // want.size() < min_size, we won't consider the pg to have been // maybe_went_rw in build_prior. if (num_want_acting < pool.info.min_size) { want_acting.clear(); return false; } /* Check whether we have enough acting shards to later perform recovery */ boost::scoped_ptr recoverable_predicate( get_pgbackend()->get_is_recoverable_predicate()); set have; for (int i = 0; i < (int)want.size(); ++i) { if (want[i] != CRUSH_ITEM_NONE) have.insert( pg_shard_t( want[i], pool.info.ec_pool() ? i : ghobject_t::NO_SHARD)); } if (!(*recoverable_predicate)(have)) { want_acting.clear(); return false; } if (want != acting) { dout(10) << "choose_acting want " << want << " != acting " << acting << ", requesting pg_temp change" << dendl; want_acting = want; if (want_acting == up) { // There can't be any pending backfill if // want is the same as crush map up OSDs. assert(compat_mode || want_backfill.empty()); vector empty; osd->queue_want_pg_temp(info.pgid.pgid, empty); } else osd->queue_want_pg_temp(info.pgid.pgid, want); return false; } want_acting.clear(); actingbackfill = want_acting_backfill; dout(10) << "actingbackfill is " << actingbackfill << dendl; assert(backfill_targets.empty() || backfill_targets == want_backfill); if (backfill_targets.empty()) { // Caller is GetInfo backfill_targets = want_backfill; for (set::iterator i = backfill_targets.begin(); i != backfill_targets.end(); ++i) { assert(!stray_set.count(*i)); } } else { // Will not change if already set because up would have had to change assert(backfill_targets == want_backfill); // Verify that nothing in backfill is in stray_set for (set::iterator i = want_backfill.begin(); i != want_backfill.end(); ++i) { assert(stray_set.find(*i) == stray_set.end()); } } dout(10) << "choose_acting want " << want << " (== acting) backfill_targets " << want_backfill << dendl; return true; } /* Build the might_have_unfound set. * * This is used by the primary OSD during recovery. * * This set tracks the OSDs which might have unfound objects that the primary * OSD needs. As we receive pg_missing_t from each OSD in might_have_unfound, we * will remove the OSD from the set. */ void PG::build_might_have_unfound() { assert(might_have_unfound.empty()); assert(is_primary()); dout(10) << __func__ << dendl; // Make sure that we have past intervals. generate_past_intervals(); // We need to decide who might have unfound objects that we need std::map::const_reverse_iterator p = past_intervals.rbegin(); std::map::const_reverse_iterator end = past_intervals.rend(); for (; p != end; ++p) { const pg_interval_t &interval(p->second); // We already have all the objects that exist at last_epoch_clean, // so there's no need to look at earlier intervals. if (interval.last < info.history.last_epoch_clean) break; // If nothing changed, we don't care about this interval. if (!interval.maybe_went_rw) continue; int i = 0; std::vector::const_iterator a = interval.acting.begin(); std::vector::const_iterator a_end = interval.acting.end(); for (; a != a_end; ++a, ++i) { pg_shard_t shard(*a, pool.info.ec_pool() ? i : ghobject_t::NO_SHARD); if (*a != CRUSH_ITEM_NONE && shard != pg_whoami) might_have_unfound.insert(shard); } } // include any (stray) peers for (map::iterator p = peer_info.begin(); p != peer_info.end(); ++p) might_have_unfound.insert(p->first); dout(15) << __func__ << ": built " << might_have_unfound << dendl; } struct C_PG_ActivateCommitted : public Context { PGRef pg; epoch_t epoch; C_PG_ActivateCommitted(PG *p, epoch_t e) : pg(p), epoch(e) {} void finish(int r) { pg->_activate_committed(epoch); } }; void PG::activate(ObjectStore::Transaction& t, epoch_t query_epoch, list& tfin, map >& query_map, map > > *activator_map, RecoveryCtx *ctx) { assert(!is_active()); assert(scrubber.callbacks.empty()); assert(callbacks_for_degraded_object.empty()); // -- crash recovery? if (is_primary() && pool.info.crash_replay_interval > 0 && may_need_replay(get_osdmap())) { replay_until = ceph_clock_now(cct); replay_until += pool.info.crash_replay_interval; dout(10) << "activate starting replay interval for " << pool.info.crash_replay_interval << " until " << replay_until << dendl; state_set(PG_STATE_REPLAY); // TODOSAM: osd->osd-> is no good osd->osd->replay_queue_lock.Lock(); osd->osd->replay_queue.push_back(pair( info.pgid, replay_until)); osd->osd->replay_queue_lock.Unlock(); } // twiddle pg state state_clear(PG_STATE_DOWN); send_notify = false; if (is_acting(pg_whoami)) info.last_epoch_started = query_epoch; const pg_missing_t &missing = pg_log.get_missing(); if (is_primary()) { last_update_ondisk = info.last_update; min_last_complete_ondisk = eversion_t(0,0); // we don't know (yet)! } last_update_applied = info.last_update; last_rollback_info_trimmed_to_applied = pg_log.get_rollback_trimmed_to(); need_up_thru = false; // write pg info, log dirty_info = true; dirty_big_info = true; // maybe // find out when we commit t.register_on_complete(new C_PG_ActivateCommitted(this, query_epoch)); // initialize snap_trimq if (is_primary()) { dout(20) << "activate - purged_snaps " << info.purged_snaps << " cached_removed_snaps " << pool.cached_removed_snaps << dendl; snap_trimq = pool.cached_removed_snaps; snap_trimq.subtract(info.purged_snaps); dout(10) << "activate - snap_trimq " << snap_trimq << dendl; if (!snap_trimq.empty() && is_clean()) queue_snap_trim(); } // init complete pointer if (missing.num_missing() == 0) { dout(10) << "activate - no missing, moving last_complete " << info.last_complete << " -> " << info.last_update << dendl; info.last_complete = info.last_update; pg_log.reset_recovery_pointers(); } else { dout(10) << "activate - not complete, " << missing << dendl; pg_log.activate_not_complete(info); } log_weirdness(); // if primary.. if (is_primary()) { assert(ctx); // start up replicas assert(!actingbackfill.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; pg_shard_t peer = *i; assert(peer_info.count(peer)); pg_info_t& pi = peer_info[peer]; dout(10) << "activate peer osd." << peer << " " << pi << dendl; MOSDPGLog *m = 0; pg_missing_t& pm = peer_missing[peer]; bool needs_past_intervals = pi.dne(); if (pi.last_update == info.last_update) { // empty log if (!pi.is_empty() && activator_map) { dout(10) << "activate peer osd." << peer << " is up to date, queueing in pending_activators" << dendl; (*activator_map)[peer.osd].push_back( make_pair( pg_notify_t( peer.shard, pg_whoami.shard, get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), info), past_intervals)); } else { dout(10) << "activate peer osd." << peer << " is up to date, but sending pg_log anyway" << dendl; m = new MOSDPGLog( i->shard, pg_whoami.shard, get_osdmap()->get_epoch(), info); } } else if ( pg_log.get_tail() > pi.last_update || pi.last_backfill == hobject_t() || (backfill_targets.count(*i) && pi.last_backfill.is_max())) { /* This last case covers a situation where a replica is not contiguous * with the auth_log, but is contiguous with this replica. Reshuffling * the active set to handle this would be tricky, so instead we just go * ahead and backfill it anyway. This is probably preferrable in any * case since the replica in question would have to be significantly * behind. */ // backfill osd->clog.info() << info.pgid << " restarting backfill on osd." << peer << " from (" << pi.log_tail << "," << pi.last_update << "] " << pi.last_backfill << " to " << info.last_update; pi.last_update = info.last_update; pi.last_complete = info.last_update; pi.last_backfill = hobject_t(); pi.history = info.history; pi.hit_set = info.hit_set; pi.stats.stats.clear(); // initialize peer with our purged_snaps. pi.purged_snaps = info.purged_snaps; m = new MOSDPGLog( i->shard, pg_whoami.shard, get_osdmap()->get_epoch(), pi); // send some recent log, so that op dup detection works well. m->log.copy_up_to(pg_log.get_log(), cct->_conf->osd_min_pg_log_entries); m->info.log_tail = m->log.tail; pi.log_tail = m->log.tail; // sigh... pm.clear(); } else { // catch up assert(pg_log.get_tail() <= pi.last_update); m = new MOSDPGLog( i->shard, pg_whoami.shard, get_osdmap()->get_epoch(), info); // send new stuff to append to replicas log m->log.copy_after(pg_log.get_log(), pi.last_update); } // share past_intervals if we are creating the pg on the replica // based on whether our info for that peer was dne() *before* // updating pi.history in the backfill block above. if (needs_past_intervals) m->past_intervals = past_intervals; // update local version of peer's missing list! if (m && pi.last_backfill != hobject_t()) { for (list::iterator p = m->log.log.begin(); p != m->log.log.end(); ++p) if (p->soid <= pi.last_backfill) pm.add_next_event(*p); } if (m) { dout(10) << "activate peer osd." << peer << " sending " << m->log << dendl; //m->log.print(cout); osd->send_message_osd_cluster(peer.osd, m, get_osdmap()->get_epoch()); } // peer now has pi.last_update = info.last_update; // update our missing if (pm.num_missing() == 0) { pi.last_complete = pi.last_update; dout(10) << "activate peer osd." << peer << " " << pi << " uptodate" << dendl; } else { dout(10) << "activate peer osd." << peer << " " << pi << " missing " << pm << dendl; } } // Set up missing_loc for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == get_primary()) { missing_loc.add_active_missing(pg_log.get_missing()); } else { assert(peer_missing.count(*i)); missing_loc.add_active_missing(peer_missing[*i]); } } // If necessary, create might_have_unfound to help us find our unfound objects. // NOTE: It's important that we build might_have_unfound before trimming the // past intervals. might_have_unfound.clear(); if (needs_recovery()) { missing_loc.add_source_info(pg_whoami, info, pg_log.get_missing()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; dout(10) << __func__ << ": adding " << *i << " as a source" << dendl; assert(peer_missing.count(*i)); assert(peer_info.count(*i)); missing_loc.add_source_info( *i, peer_info[*i], peer_missing[*i]); } for (map::iterator i = peer_missing.begin(); i != peer_missing.end(); ++i) { if (is_actingbackfill(i->first)) continue; assert(peer_info.count(i->first)); search_for_missing( peer_info[i->first], i->second, i->first, ctx); } build_might_have_unfound(); dout(10) << "activate - starting recovery" << dendl; osd->queue_for_recovery(this); if (have_unfound()) discover_all_missing(query_map); } // degraded? if (get_osdmap()->get_pg_size(info.pgid.pgid) > actingset.size()) state_set(PG_STATE_DEGRADED); } } bool PG::op_has_sufficient_caps(OpRequestRef op) { // only check MOSDOp if (op->get_req()->get_type() != CEPH_MSG_OSD_OP) return true; MOSDOp *req = static_cast(op->get_req()); OSD::Session *session = (OSD::Session *)req->get_connection()->get_priv(); if (!session) { dout(0) << "op_has_sufficient_caps: no session for op " << *req << dendl; return false; } OSDCap& caps = session->caps; session->put(); string key = req->get_object_locator().key; if (key.length() == 0) key = req->get_oid().name; bool cap = caps.is_capable(pool.name, req->get_object_locator().nspace, pool.auid, key, op->need_read_cap(), op->need_write_cap(), op->need_class_read_cap(), op->need_class_write_cap()); dout(20) << "op_has_sufficient_caps pool=" << pool.id << " (" << pool.name << " " << req->get_object_locator().nspace << ") owner=" << pool.auid << " need_read_cap=" << op->need_read_cap() << " need_write_cap=" << op->need_write_cap() << " need_class_read_cap=" << op->need_class_read_cap() << " need_class_write_cap=" << op->need_class_write_cap() << " -> " << (cap ? "yes" : "NO") << dendl; return cap; } void PG::take_op_map_waiters() { Mutex::Locker l(map_lock); for (list::iterator i = waiting_for_map.begin(); i != waiting_for_map.end(); ) { if (op_must_wait_for_map(get_osdmap_with_maplock(), *i)) { break; } else { osd->op_wq.queue(make_pair(PGRef(this), *i)); waiting_for_map.erase(i++); } } } void PG::queue_op(OpRequestRef op) { Mutex::Locker l(map_lock); if (!waiting_for_map.empty()) { // preserve ordering waiting_for_map.push_back(op); return; } if (op_must_wait_for_map(get_osdmap_with_maplock(), op)) { waiting_for_map.push_back(op); return; } osd->op_wq.queue(make_pair(PGRef(this), op)); } void PG::replay_queued_ops() { assert(is_replay()); eversion_t c = info.last_update; list replay; dout(10) << "replay_queued_ops" << dendl; state_clear(PG_STATE_REPLAY); for (map::iterator p = replay_queue.begin(); p != replay_queue.end(); ++p) { if (p->first.version != c.version+1) { dout(10) << "activate replay " << p->first << " skipping " << c.version+1 - p->first.version << " ops" << dendl; c = p->first; } dout(10) << "activate replay " << p->first << " " << *p->second->get_req() << dendl; replay.push_back(p->second); } replay_queue.clear(); requeue_ops(replay); requeue_ops(waiting_for_active); publish_stats_to_osd(); } void PG::_activate_committed(epoch_t e) { lock(); if (pg_has_reset_since(e)) { dout(10) << "_activate_committed " << e << ", that was an old interval" << dendl; } else if (is_primary()) { peer_activated.insert(pg_whoami); dout(10) << "_activate_committed " << e << " peer_activated now " << peer_activated << " last_epoch_started " << info.history.last_epoch_started << " same_interval_since " << info.history.same_interval_since << dendl; assert(!actingbackfill.empty()); if (peer_activated.size() == actingbackfill.size()) all_activated_and_committed(); } else { dout(10) << "_activate_committed " << e << " telling primary" << dendl; MOSDPGInfo *m = new MOSDPGInfo(e); pg_notify_t i = pg_notify_t( get_primary().shard, pg_whoami.shard, get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), info); i.info.history.last_epoch_started = e; m->pg_list.push_back(make_pair(i, pg_interval_map_t())); osd->send_message_osd_cluster(get_primary().osd, m, get_osdmap()->get_epoch()); state_set(PG_STATE_ACTIVE); // waiters if (flushes_in_progress == 0) { requeue_ops(waiting_for_active); } } if (dirty_info) { ObjectStore::Transaction *t = new ObjectStore::Transaction; write_if_dirty(*t); int tr = osd->store->queue_transaction_and_cleanup(osr.get(), t); assert(tr == 0); } unlock(); } /* * update info.history.last_epoch_started ONLY after we and all * replicas have activated AND committed the activate transaction * (i.e. the peering results are stable on disk). */ void PG::all_activated_and_committed() { dout(10) << "all_activated_and_committed" << dendl; assert(is_primary()); assert(peer_activated.size() == actingbackfill.size()); assert(!actingbackfill.empty()); // info.last_epoch_started is set during activate() info.history.last_epoch_started = info.last_epoch_started; state_clear(PG_STATE_CREATING); share_pg_info(); publish_stats_to_osd(); queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), AllReplicasActivated()))); } void PG::queue_snap_trim() { if (osd->queue_for_snap_trim(this)) dout(10) << "queue_snap_trim -- queuing" << dendl; else dout(10) << "queue_snap_trim -- already trimming" << dendl; } bool PG::queue_scrub() { assert(_lock.is_locked()); if (is_scrubbing()) { return false; } scrubber.must_scrub = false; state_set(PG_STATE_SCRUBBING); if (scrubber.must_deep_scrub) { state_set(PG_STATE_DEEP_SCRUB); scrubber.must_deep_scrub = false; } if (scrubber.must_repair) { state_set(PG_STATE_REPAIR); scrubber.must_repair = false; } osd->queue_for_scrub(this); return true; } struct C_PG_FinishRecovery : public Context { PGRef pg; C_PG_FinishRecovery(PG *p) : pg(p) {} void finish(int r) { pg->_finish_recovery(this); } }; void PG::mark_clean() { // only mark CLEAN if we have the desired number of replicas AND we // are not remapped. if (actingset.size() == get_osdmap()->get_pg_size(info.pgid.pgid) && up == acting) state_set(PG_STATE_CLEAN); // NOTE: this is actually a bit premature: we haven't purged the // strays yet. info.history.last_epoch_clean = get_osdmap()->get_epoch(); trim_past_intervals(); if (is_clean() && !snap_trimq.empty()) queue_snap_trim(); dirty_info = true; } void PG::finish_recovery(list& tfin) { dout(10) << "finish_recovery" << dendl; assert(info.last_complete == info.last_update); clear_recovery_state(); /* * sync all this before purging strays. but don't block! */ finish_sync_event = new C_PG_FinishRecovery(this); tfin.push_back(finish_sync_event); } void PG::_finish_recovery(Context *c) { lock(); if (deleting) { unlock(); return; } if (c == finish_sync_event) { dout(10) << "_finish_recovery" << dendl; finish_sync_event = 0; purge_strays(); publish_stats_to_osd(); if (scrub_after_recovery) { dout(10) << "_finish_recovery requeueing for scrub" << dendl; scrub_after_recovery = false; scrubber.must_deep_scrub = true; queue_scrub(); } } else { dout(10) << "_finish_recovery -- stale" << dendl; } unlock(); } void PG::start_recovery_op(const hobject_t& soid) { dout(10) << "start_recovery_op " << soid #ifdef DEBUG_RECOVERY_OIDS << " (" << recovering_oids << ")" #endif << dendl; assert(recovery_ops_active >= 0); recovery_ops_active++; #ifdef DEBUG_RECOVERY_OIDS assert(recovering_oids.count(soid) == 0); recovering_oids.insert(soid); #endif // TODOSAM: osd->osd-> not good osd->osd->start_recovery_op(this, soid); } void PG::finish_recovery_op(const hobject_t& soid, bool dequeue) { dout(10) << "finish_recovery_op " << soid #ifdef DEBUG_RECOVERY_OIDS << " (" << recovering_oids << ")" #endif << dendl; assert(recovery_ops_active > 0); recovery_ops_active--; #ifdef DEBUG_RECOVERY_OIDS assert(recovering_oids.count(soid)); recovering_oids.erase(soid); #endif // TODOSAM: osd->osd-> not good osd->osd->finish_recovery_op(this, soid, dequeue); } static void split_list( list *from, list *to, unsigned match, unsigned bits) { for (list::iterator i = from->begin(); i != from->end(); ) { if (PG::split_request(*i, match, bits)) { to->push_back(*i); from->erase(i++); } else { ++i; } } } static void split_replay_queue( map *from, map *to, unsigned match, unsigned bits) { for (map::iterator i = from->begin(); i != from->end(); ) { if (PG::split_request(i->second, match, bits)) { to->insert(*i); from->erase(i++); } else { ++i; } } } void PG::split_ops(PG *child, unsigned split_bits) { unsigned match = child->info.pgid.ps(); assert(waiting_for_all_missing.empty()); assert(waiting_for_cache_not_full.empty()); assert(waiting_for_unreadable_object.empty()); assert(waiting_for_degraded_object.empty()); assert(waiting_for_ack.empty()); assert(waiting_for_ondisk.empty()); split_replay_queue(&replay_queue, &(child->replay_queue), match, split_bits); osd->dequeue_pg(this, &waiting_for_active); split_list(&waiting_for_active, &(child->waiting_for_active), match, split_bits); { Mutex::Locker l(map_lock); // to avoid a race with the osd dispatch split_list(&waiting_for_map, &(child->waiting_for_map), match, split_bits); } } void PG::split_into(pg_t child_pgid, PG *child, unsigned split_bits) { child->update_snap_mapper_bits(split_bits); child->update_osdmap_ref(get_osdmap()); child->pool = pool; // Log pg_log.split_into(child_pgid, split_bits, &(child->pg_log)); child->info.last_complete = info.last_complete; info.last_update = pg_log.get_head(); child->info.last_update = child->pg_log.get_head(); child->info.last_user_version = info.last_user_version; info.log_tail = pg_log.get_tail(); child->info.log_tail = child->pg_log.get_tail(); if (info.last_complete < pg_log.get_tail()) info.last_complete = pg_log.get_tail(); if (child->info.last_complete < child->pg_log.get_tail()) child->info.last_complete = child->pg_log.get_tail(); // Info child->info.history = info.history; child->info.purged_snaps = info.purged_snaps; child->info.last_backfill = info.last_backfill; child->info.stats = info.stats; info.stats.stats_invalid = true; child->info.stats.stats_invalid = true; child->info.last_epoch_started = info.last_epoch_started; child->snap_trimq = snap_trimq; // There can't be recovery/backfill going on now int primary, up_primary; vector newup, newacting; get_osdmap()->pg_to_up_acting_osds( child->info.pgid.pgid, &newup, &up_primary, &newacting, &primary); child->init_primary_up_acting( newup, newacting, up_primary, primary); child->role = OSDMap::calc_pg_role(osd->whoami, child->acting); // this comparison includes primary rank via pg_shard_t if (get_primary() != child->get_primary()) child->info.history.same_primary_since = get_osdmap()->get_epoch(); // History child->past_intervals = past_intervals; split_ops(child, split_bits); _split_into(child_pgid, child, split_bits); child->dirty_info = true; child->dirty_big_info = true; dirty_info = true; dirty_big_info = true; } void PG::clear_recovery_state() { dout(10) << "clear_recovery_state" << dendl; pg_log.reset_recovery_pointers(); finish_sync_event = 0; hobject_t soid; while (recovery_ops_active > 0) { #ifdef DEBUG_RECOVERY_OIDS soid = *recovering_oids.begin(); #endif finish_recovery_op(soid, true); } backfill_targets.clear(); backfill_info.clear(); peer_backfill_info.clear(); waiting_on_backfill.clear(); _clear_recovery_state(); // pg impl specific hook } void PG::cancel_recovery() { dout(10) << "cancel_recovery" << dendl; clear_recovery_state(); } void PG::purge_strays() { dout(10) << "purge_strays " << stray_set << dendl; bool removed = false; for (set::iterator p = stray_set.begin(); p != stray_set.end(); ++p) { assert(!is_actingbackfill(*p)); if (get_osdmap()->is_up(p->osd)) { dout(10) << "sending PGRemove to osd." << *p << dendl; vector to_remove; to_remove.push_back(spg_t(info.pgid.pgid, p->shard)); MOSDPGRemove *m = new MOSDPGRemove( get_osdmap()->get_epoch(), to_remove); osd->send_message_osd_cluster(p->osd, m, get_osdmap()->get_epoch()); stray_purged.insert(*p); } else { dout(10) << "not sending PGRemove to down osd." << *p << dendl; } peer_info.erase(*p); peer_purged.insert(*p); removed = true; } // if we removed anyone, update peers (which include peer_info) if (removed) update_heartbeat_peers(); stray_set.clear(); // clear _requested maps; we may have to peer() again if we discover // (more) stray content peer_log_requested.clear(); peer_missing_requested.clear(); } void PG::set_probe_targets(const set &probe_set) { Mutex::Locker l(heartbeat_peer_lock); probe_targets.clear(); for (set::iterator i = probe_set.begin(); i != probe_set.end(); ++i) { probe_targets.insert(i->osd); } } void PG::clear_probe_targets() { Mutex::Locker l(heartbeat_peer_lock); probe_targets.clear(); } void PG::update_heartbeat_peers() { assert(is_locked()); set new_peers; if (is_primary()) { for (unsigned i=0; i::iterator p = peer_info.begin(); p != peer_info.end(); ++p) new_peers.insert(p->first.osd); } bool need_update = false; heartbeat_peer_lock.Lock(); if (new_peers == heartbeat_peers) { dout(10) << "update_heartbeat_peers " << heartbeat_peers << " unchanged" << dendl; } else { dout(10) << "update_heartbeat_peers " << heartbeat_peers << " -> " << new_peers << dendl; heartbeat_peers.swap(new_peers); need_update = true; } heartbeat_peer_lock.Unlock(); if (need_update) osd->need_heartbeat_peer_update(); } void PG::_update_calc_stats() { info.stats.version = info.last_update; info.stats.created = info.history.epoch_created; info.stats.last_scrub = info.history.last_scrub; info.stats.last_scrub_stamp = info.history.last_scrub_stamp; info.stats.last_deep_scrub = info.history.last_deep_scrub; info.stats.last_deep_scrub_stamp = info.history.last_deep_scrub_stamp; info.stats.last_clean_scrub_stamp = info.history.last_clean_scrub_stamp; info.stats.last_epoch_clean = info.history.last_epoch_clean; info.stats.log_size = pg_log.get_head().version - pg_log.get_tail().version; info.stats.ondisk_log_size = pg_log.get_head().version - pg_log.get_tail().version; info.stats.log_start = pg_log.get_tail(); info.stats.ondisk_log_start = pg_log.get_tail(); // calc copies, degraded unsigned target = MAX( get_osdmap()->get_pg_size(info.pgid.pgid), actingbackfill.size()); info.stats.stats.calc_copies(target); info.stats.stats.sum.num_objects_degraded = 0; if ((is_degraded() || !is_clean()) && is_active()) { // NOTE: we only generate copies, degraded, unfound values for // the summation, not individual stat categories. uint64_t num_objects = info.stats.stats.sum.num_objects; int64_t degraded = 0; // if the actingbackfill set is smaller than we want, add in those missing replicas if (actingbackfill.size() < target) degraded += (target - actingbackfill.size()) * num_objects; // missing on primary info.stats.stats.sum.num_objects_missing_on_primary = pg_log.get_missing().num_missing(); degraded += pg_log.get_missing().num_missing(); assert(!actingbackfill.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; assert(peer_missing.count(*i)); // in missing set degraded += peer_missing[*i].num_missing(); // not yet backfilled int64_t diff = num_objects - peer_info[*i].stats.stats.sum.num_objects; if (diff > 0) degraded += diff; } info.stats.stats.sum.num_objects_degraded = degraded; info.stats.stats.sum.num_objects_unfound = get_num_unfound(); } } void PG::publish_stats_to_osd() { pg_stats_publish_lock.Lock(); if (is_primary()) { // update our stat summary info.stats.reported_epoch = get_osdmap()->get_epoch(); ++info.stats.reported_seq; if (info.stats.stats.sum.num_scrub_errors) state_set(PG_STATE_INCONSISTENT); else state_clear(PG_STATE_INCONSISTENT); utime_t now = ceph_clock_now(cct); info.stats.last_fresh = now; if (info.stats.state != state) { info.stats.state = state; info.stats.last_change = now; if ((state & PG_STATE_ACTIVE) && !(info.stats.state & PG_STATE_ACTIVE)) info.stats.last_became_active = now; } if (info.stats.state & PG_STATE_CLEAN) info.stats.last_clean = now; if (info.stats.state & PG_STATE_ACTIVE) info.stats.last_active = now; info.stats.last_unstale = now; _update_calc_stats(); pg_stats_publish_valid = true; pg_stats_publish = info.stats; pg_stats_publish.stats.add(unstable_stats); dout(15) << "publish_stats_to_osd " << pg_stats_publish.reported_epoch << ":" << pg_stats_publish.reported_seq << dendl; } else { pg_stats_publish_valid = false; dout(15) << "publish_stats_to_osd -- not primary" << dendl; } pg_stats_publish_lock.Unlock(); if (is_primary()) osd->pg_stat_queue_enqueue(this); } void PG::clear_publish_stats() { dout(15) << "clear_stats" << dendl; pg_stats_publish_lock.Lock(); pg_stats_publish_valid = false; pg_stats_publish_lock.Unlock(); osd->pg_stat_queue_dequeue(this); } /** * initialize a newly instantiated pg * * Initialize PG state, as when a PG is initially created, or when it * is first instantiated on the current node. * * @param role our role/rank * @param newup up set * @param newacting acting set * @param history pg history * @param pi past_intervals * @param backfill true if info should be marked as backfill * @param t transaction to write out our new state in */ void PG::init( int role, vector& newup, int new_up_primary, vector& newacting, int new_acting_primary, pg_history_t& history, pg_interval_map_t& pi, bool backfill, ObjectStore::Transaction *t) { dout(10) << "init role " << role << " up " << newup << " acting " << newacting << " history " << history << " " << pi.size() << " past_intervals" << dendl; set_role(role); acting = newacting; up = newup; init_primary_up_acting( newup, newacting, new_up_primary, new_acting_primary); info.history = history; past_intervals.swap(pi); info.stats.up = up; info.stats.up_primary = new_up_primary; info.stats.acting = acting; info.stats.acting_primary = new_acting_primary; info.stats.mapping_epoch = info.history.same_interval_since; if (backfill) { dout(10) << __func__ << ": Setting backfill" << dendl; info.last_backfill = hobject_t(); info.last_complete = info.last_update; pg_log.mark_log_for_rewrite(); } reg_next_scrub(); dirty_info = true; dirty_big_info = true; write_if_dirty(*t); } void PG::upgrade(ObjectStore *store, const interval_set &snapcolls) { unsigned removed = 0; for (interval_set::const_iterator i = snapcolls.begin(); i != snapcolls.end(); ++i) { for (snapid_t next_dir = i.get_start(); next_dir != i.get_start() + i.get_len(); ++next_dir) { ++removed; coll_t cid(info.pgid, next_dir); dout(1) << "Removing collection " << cid << " (" << removed << "/" << snapcolls.size() << ")" << dendl; hobject_t cur; vector objects; while (1) { int r = get_pgbackend()->objects_list_partial( cur, store->get_ideal_list_min(), store->get_ideal_list_max(), 0, &objects, &cur); if (r != 0) { derr << __func__ << ": collection_list_partial returned " << cpp_strerror(r) << dendl; assert(0); } if (objects.empty()) { assert(cur.is_max()); break; } ObjectStore::Transaction t; for (vector::iterator j = objects.begin(); j != objects.end(); ++j) { t.remove(cid, *j); } r = store->apply_transaction(t); if (r != 0) { derr << __func__ << ": apply_transaction returned " << cpp_strerror(r) << dendl; assert(0); } objects.clear(); } ObjectStore::Transaction t; t.remove_collection(cid); int r = store->apply_transaction(t); if (r != 0) { derr << __func__ << ": apply_transaction returned " << cpp_strerror(r) << dendl; assert(0); } } } hobject_t cur; coll_t cid(info.pgid); unsigned done = 0; vector objects; while (1) { dout(1) << "Updating snap_mapper from main collection, " << done << " objects done" << dendl; int r = get_pgbackend()->objects_list_partial( cur, store->get_ideal_list_min(), store->get_ideal_list_max(), 0, &objects, &cur); if (r != 0) { derr << __func__ << ": collection_list_partial returned " << cpp_strerror(r) << dendl; assert(0); } if (objects.empty()) { assert(cur.is_max()); break; } done += objects.size(); ObjectStore::Transaction t; for (vector::iterator j = objects.begin(); j != objects.end(); ++j) { if (j->snap < CEPH_MAXSNAP) { OSDriver::OSTransaction _t(osdriver.get_transaction(&t)); bufferlist bl; r = get_pgbackend()->objects_get_attr( *j, OI_ATTR, &bl); if (r < 0) { derr << __func__ << ": getattr returned " << cpp_strerror(r) << dendl; assert(0); } object_info_t oi(bl); set oi_snaps(oi.snaps.begin(), oi.snaps.end()); set cur_snaps; r = snap_mapper.get_snaps(*j, &cur_snaps); if (r == 0) { assert(cur_snaps == oi_snaps); } else if (r == -ENOENT) { snap_mapper.add_oid(*j, oi_snaps, &_t); } else { derr << __func__ << ": get_snaps returned " << cpp_strerror(r) << dendl; assert(0); } } } r = store->apply_transaction(t); if (r != 0) { derr << __func__ << ": apply_transaction returned " << cpp_strerror(r) << dendl; assert(0); } objects.clear(); } ObjectStore::Transaction t; snap_collections.clear(); dirty_info = true; write_if_dirty(t); int r = store->apply_transaction(t); if (r != 0) { derr << __func__ << ": apply_transaction returned " << cpp_strerror(r) << dendl; assert(0); } assert(r == 0); } int PG::_write_info(ObjectStore::Transaction& t, epoch_t epoch, pg_info_t &info, coll_t coll, map &past_intervals, interval_set &snap_collections, hobject_t &infos_oid, __u8 info_struct_v, bool dirty_big_info, bool force_ver) { // pg state if (info_struct_v > cur_struct_v) return -EINVAL; // Only need to write struct_v to attr when upgrading if (force_ver || info_struct_v < cur_struct_v) { bufferlist attrbl; info_struct_v = cur_struct_v; ::encode(info_struct_v, attrbl); t.collection_setattr(coll, "info", attrbl); dirty_big_info = true; } // info. store purged_snaps separately. interval_set purged_snaps; map v; ::encode(epoch, v[get_epoch_key(info.pgid)]); purged_snaps.swap(info.purged_snaps); ::encode(info, v[get_info_key(info.pgid)]); purged_snaps.swap(info.purged_snaps); if (dirty_big_info) { // potentially big stuff bufferlist& bigbl = v[get_biginfo_key(info.pgid)]; ::encode(past_intervals, bigbl); ::encode(snap_collections, bigbl); ::encode(info.purged_snaps, bigbl); //dout(20) << "write_info bigbl " << bigbl.length() << dendl; } t.omap_setkeys(coll_t::META_COLL, infos_oid, v); return 0; } void PG::write_info(ObjectStore::Transaction& t) { info.stats.stats.add(unstable_stats); unstable_stats.clear(); int ret = _write_info(t, get_osdmap()->get_epoch(), info, coll, past_intervals, snap_collections, osd->infos_oid, info_struct_v, dirty_big_info); assert(ret == 0); last_persisted_osdmap_ref = osdmap_ref; dirty_info = false; dirty_big_info = false; } epoch_t PG::peek_map_epoch(ObjectStore *store, coll_t coll, hobject_t &infos_oid, bufferlist *bl) { assert(bl); spg_t pgid; snapid_t snap; bool ok = coll.is_pg(pgid, snap); assert(ok); int r = store->collection_getattr(coll, "info", *bl); assert(r > 0); bufferlist::iterator bp = bl->begin(); __u8 struct_v = 0; ::decode(struct_v, bp); if (struct_v < 5) return 0; epoch_t cur_epoch = 0; if (struct_v < 6) { ::decode(cur_epoch, bp); } else { // get epoch out of leveldb bufferlist tmpbl; string ek = get_epoch_key(pgid); set keys; keys.insert(get_epoch_key(pgid)); map values; store->omap_get_values(coll_t::META_COLL, infos_oid, keys, &values); assert(values.size() == 1); tmpbl = values[ek]; bufferlist::iterator p = tmpbl.begin(); ::decode(cur_epoch, p); } return cur_epoch; } void PG::write_if_dirty(ObjectStore::Transaction& t) { if (dirty_big_info || dirty_info) write_info(t); pg_log.write_log(t, log_oid); } void PG::trim_peers() { assert(is_primary()); calc_trim_to(); dout(10) << "trim_peers " << pg_trim_to << dendl; if (pg_trim_to != eversion_t()) { assert(!actingbackfill.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; osd->send_message_osd_cluster( i->osd, new MOSDPGTrim( get_osdmap()->get_epoch(), spg_t(info.pgid.pgid, i->shard), pg_trim_to), get_osdmap()->get_epoch()); } } } void PG::add_log_entry(pg_log_entry_t& e, bufferlist& log_bl) { // raise last_complete only if we were previously up to date if (info.last_complete == info.last_update) info.last_complete = e.version; // raise last_update. assert(e.version > info.last_update); info.last_update = e.version; // raise user_version, if it increased (it may have not get bumped // by all logged updates) if (e.user_version > info.last_user_version) info.last_user_version = e.user_version; /** * Make sure we don't keep around more than we need to in the * in-memory log */ e.mod_desc.trim_bl(); // log mutation pg_log.add(e); dout(10) << "add_log_entry " << e << dendl; e.encode_with_checksum(log_bl); } void PG::append_log( vector& logv, eversion_t trim_to, eversion_t trim_rollback_to, ObjectStore::Transaction &t, bool transaction_applied) { if (transaction_applied) update_snap_map(logv, t); dout(10) << "append_log " << pg_log.get_log() << " " << logv << dendl; map keys; for (vector::iterator p = logv.begin(); p != logv.end(); ++p) { p->offset = 0; add_log_entry(*p, keys[p->get_key_name()]); } PGLogEntryHandler handler; if (!transaction_applied) { pg_log.clear_can_rollback_to(&handler); t.register_on_applied( new C_UpdateLastRollbackInfoTrimmedToApplied( this, get_osdmap()->get_epoch(), info.last_update)); } else if (trim_rollback_to > pg_log.get_rollback_trimmed_to()) { pg_log.trim_rollback_info( trim_rollback_to, &handler); t.register_on_applied( new C_UpdateLastRollbackInfoTrimmedToApplied( this, get_osdmap()->get_epoch(), trim_rollback_to)); } dout(10) << "append_log adding " << keys.size() << " keys" << dendl; t.omap_setkeys(coll_t::META_COLL, log_oid, keys); pg_log.trim(&handler, trim_to, info); dout(10) << __func__ << ": trimming to " << trim_rollback_to << " entries " << handler.to_trim << dendl; handler.apply(this, &t); // update the local pg, pg log dirty_info = true; write_if_dirty(t); } bool PG::check_log_for_corruption(ObjectStore *store) { /// TODO: this method needs to work with the omap log return true; } //! Get the name we're going to save our corrupt page log as std::string PG::get_corrupt_pg_log_name() const { const int MAX_BUF = 512; char buf[MAX_BUF]; struct tm tm_buf; time_t my_time(time(NULL)); const struct tm *t = localtime_r(&my_time, &tm_buf); int ret = strftime(buf, sizeof(buf), "corrupt_log_%Y-%m-%d_%k:%M_", t); if (ret == 0) { dout(0) << "strftime failed" << dendl; return "corrupt_log_unknown_time"; } string out(buf); out += stringify(info.pgid); return out; } int PG::read_info( ObjectStore *store, const coll_t coll, bufferlist &bl, pg_info_t &info, map &past_intervals, hobject_t &biginfo_oid, hobject_t &infos_oid, interval_set &snap_collections, __u8 &struct_v) { bufferlist::iterator p = bl.begin(); bufferlist lbl; // info ::decode(struct_v, p); if (struct_v < 4) ::decode(info, p); if (struct_v < 2) { ::decode(past_intervals, p); // snap_collections store->collection_getattr(coll, "snap_collections", lbl); p = lbl.begin(); ::decode(struct_v, p); } else { if (struct_v < 6) { int r = store->read(coll_t::META_COLL, biginfo_oid, 0, 0, lbl); if (r < 0) return r; p = lbl.begin(); ::decode(past_intervals, p); } else { // get info out of leveldb string k = get_info_key(info.pgid); string bk = get_biginfo_key(info.pgid); set keys; keys.insert(k); keys.insert(bk); map values; store->omap_get_values(coll_t::META_COLL, infos_oid, keys, &values); assert(values.size() == 2); lbl = values[k]; p = lbl.begin(); ::decode(info, p); lbl = values[bk]; p = lbl.begin(); ::decode(past_intervals, p); } } if (struct_v < 3) { set snap_collections_temp; ::decode(snap_collections_temp, p); snap_collections.clear(); for (set::iterator i = snap_collections_temp.begin(); i != snap_collections_temp.end(); ++i) { snap_collections.insert(*i); } } else { ::decode(snap_collections, p); if (struct_v >= 4 && struct_v < 6) ::decode(info, p); else if (struct_v >= 6) ::decode(info.purged_snaps, p); } return 0; } void PG::read_state(ObjectStore *store, bufferlist &bl) { int r = read_info(store, coll, bl, info, past_intervals, biginfo_oid, osd->infos_oid, snap_collections, info_struct_v); assert(r >= 0); ostringstream oss; if (pg_log.read_log( store, coll, log_oid, info, oss)) { /* We don't want to leave the old format around in case the next log * write happens to be an append_log() */ pg_log.mark_log_for_rewrite(); ObjectStore::Transaction t; t.remove(coll_t(), log_oid); // remove old version pg_log.write_log(t, log_oid); int r = osd->store->apply_transaction(t); assert(!r); } if (oss.str().length()) osd->clog.error() << oss; // log any weirdness log_weirdness(); } void PG::log_weirdness() { if (pg_log.get_tail() != info.log_tail) osd->clog.error() << info.pgid << " info mismatch, log.tail " << pg_log.get_tail() << " != info.log_tail " << info.log_tail << "\n"; if (pg_log.get_head() != info.last_update) osd->clog.error() << info.pgid << " info mismatch, log.head " << pg_log.get_head() << " != info.last_update " << info.last_update << "\n"; if (!pg_log.get_log().empty()) { // sloppy check if ((pg_log.get_log().log.begin()->version <= pg_log.get_tail())) osd->clog.error() << info.pgid << " log bound mismatch, info (" << pg_log.get_tail() << "," << pg_log.get_head() << "]" << " actual [" << pg_log.get_log().log.begin()->version << "," << pg_log.get_log().log.rbegin()->version << "]" << "\n"; } if (pg_log.get_log().caller_ops.size() > pg_log.get_log().log.size()) { osd->clog.error() << info.pgid << " caller_ops.size " << pg_log.get_log().caller_ops.size() << " > log size " << pg_log.get_log().log.size() << "\n"; } } void PG::update_snap_map( vector &log_entries, ObjectStore::Transaction &t) { for (vector::iterator i = log_entries.begin(); i != log_entries.end(); ++i) { OSDriver::OSTransaction _t(osdriver.get_transaction(&t)); if (i->soid.snap < CEPH_MAXSNAP) { if (i->is_delete()) { int r = snap_mapper.remove_oid( i->soid, &_t); assert(r == 0); } else { assert(i->snaps.length() > 0); vector snaps; bufferlist::iterator p = i->snaps.begin(); try { ::decode(snaps, p); } catch (...) { snaps.clear(); } set _snaps(snaps.begin(), snaps.end()); if (i->is_clone() || i->is_promote()) { snap_mapper.add_oid( i->soid, _snaps, &_t); } else if (i->is_modify()) { assert(i->is_modify()); int r = snap_mapper.update_snaps( i->soid, _snaps, 0, &_t); assert(r == 0); } else { assert(i->is_clean()); } } } } } /** * filter trimming|trimmed snaps out of snapcontext */ void PG::filter_snapc(vector &snaps) { bool filtering = false; vector newsnaps; for (vector::iterator p = snaps.begin(); p != snaps.end(); ++p) { if (snap_trimq.contains(*p) || info.purged_snaps.contains(*p)) { if (!filtering) { // start building a new vector with what we've seen so far dout(10) << "filter_snapc filtering " << snaps << dendl; newsnaps.insert(newsnaps.begin(), snaps.begin(), p); filtering = true; } dout(20) << "filter_snapc removing trimq|purged snap " << *p << dendl; } else { if (filtering) newsnaps.push_back(*p); // continue building new vector } } if (filtering) { snaps.swap(newsnaps); dout(10) << "filter_snapc result " << snaps << dendl; } } void PG::requeue_object_waiters(map >& m) { for (map >::iterator it = m.begin(); it != m.end(); ++it) requeue_ops(it->second); m.clear(); } void PG::requeue_op(OpRequestRef op) { osd->op_wq.queue_front(make_pair(PGRef(this), op)); } void PG::requeue_ops(list &ls) { dout(15) << " requeue_ops " << ls << dendl; for (list::reverse_iterator i = ls.rbegin(); i != ls.rend(); ++i) { osd->op_wq.queue_front(make_pair(PGRef(this), *i)); } ls.clear(); } // ========================================================================================== // SCRUB /* * when holding pg and sched_scrub_lock, then the states are: * scheduling: * scrubber.reserved = true * scrub_rserved_peers includes whoami * osd->scrub_pending++ * scheduling, replica declined: * scrubber.reserved = true * scrubber.reserved_peers includes -1 * osd->scrub_pending++ * pending: * scrubber.reserved = true * scrubber.reserved_peers.size() == acting.size(); * pg on scrub_wq * osd->scrub_pending++ * scrubbing: * scrubber.reserved = false; * scrubber.reserved_peers empty * osd->scrubber.active++ */ // returns true if a scrub has been newly kicked off bool PG::sched_scrub() { assert(_lock.is_locked()); if (!(is_primary() && is_active() && is_clean() && !is_scrubbing())) { return false; } bool time_for_deep = (ceph_clock_now(cct) > info.history.last_deep_scrub_stamp + cct->_conf->osd_deep_scrub_interval); //NODEEP_SCRUB so ignore time initiated deep-scrub if (osd->osd->get_osdmap()->test_flag(CEPH_OSDMAP_NODEEP_SCRUB)) time_for_deep = false; if (!scrubber.must_scrub) { assert(!scrubber.must_deep_scrub); //NOSCRUB so skip regular scrubs if (osd->osd->get_osdmap()->test_flag(CEPH_OSDMAP_NOSCRUB) && !time_for_deep) return false; } bool ret = true; if (!scrubber.reserved) { assert(scrubber.reserved_peers.empty()); if (osd->inc_scrubs_pending()) { dout(20) << "sched_scrub: reserved locally, reserving replicas" << dendl; scrubber.reserved = true; scrubber.reserved_peers.insert(pg_whoami); scrub_reserve_replicas(); } else { dout(20) << "sched_scrub: failed to reserve locally" << dendl; ret = false; } } if (scrubber.reserved) { if (scrubber.reserve_failed) { dout(20) << "sched_scrub: failed, a peer declined" << dendl; clear_scrub_reserved(); scrub_unreserve_replicas(); ret = false; } else if (scrubber.reserved_peers.size() == acting.size()) { dout(20) << "sched_scrub: success, reserved self and replicas" << dendl; if (time_for_deep) { dout(10) << "sched_scrub: scrub will be deep" << dendl; state_set(PG_STATE_DEEP_SCRUB); } queue_scrub(); } else { // none declined, since scrubber.reserved is set dout(20) << "sched_scrub: reserved " << scrubber.reserved_peers << ", waiting for replicas" << dendl; } } return ret; } void PG::reg_next_scrub() { if (scrubber.must_scrub || (info.stats.stats_invalid && g_conf->osd_scrub_invalid_stats)) { scrubber.scrub_reg_stamp = utime_t(); } else { scrubber.scrub_reg_stamp = info.history.last_scrub_stamp; } if (is_primary()) osd->reg_last_pg_scrub(info.pgid, scrubber.scrub_reg_stamp); } void PG::unreg_next_scrub() { if (is_primary()) osd->unreg_last_pg_scrub(info.pgid, scrubber.scrub_reg_stamp); } void PG::sub_op_scrub_map(OpRequestRef op) { MOSDSubOp *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); dout(7) << "sub_op_scrub_map" << dendl; if (m->map_epoch < info.history.same_interval_since) { dout(10) << "sub_op_scrub discarding old sub_op from " << m->map_epoch << " < " << info.history.same_interval_since << dendl; return; } op->mark_started(); dout(10) << " got " << m->from << " scrub map" << dendl; bufferlist::iterator p = m->get_data().begin(); if (scrubber.is_chunky) { // chunky scrub scrubber.received_maps[m->from].decode(p, info.pgid.pool()); dout(10) << "map version is " << scrubber.received_maps[m->from].valid_through << dendl; } else { // classic scrub if (scrubber.received_maps.count(m->from)) { ScrubMap incoming; incoming.decode(p, info.pgid.pool()); dout(10) << "from replica " << m->from << dendl; dout(10) << "map version is " << incoming.valid_through << dendl; scrubber.received_maps[m->from].merge_incr(incoming); } else { scrubber.received_maps[m->from].decode(p, info.pgid.pool()); } } --scrubber.waiting_on; scrubber.waiting_on_whom.erase(m->from); if (scrubber.waiting_on == 0) { if (scrubber.is_chunky) { // chunky scrub osd->scrub_wq.queue(this); } else { // classic scrub if (scrubber.finalizing) { // incremental lists received osd->scrub_finalize_wq.queue(this); } else { // initial lists received scrubber.block_writes = true; if (last_update_applied == info.last_update) { scrubber.finalizing = true; scrub_gather_replica_maps(); ++scrubber.waiting_on; scrubber.waiting_on_whom.insert(pg_whoami); osd->scrub_wq.queue(this); } } } } } // send scrub v2-compatible messages (classic scrub) void PG::_request_scrub_map_classic(pg_shard_t replica, eversion_t version) { assert(replica != pg_whoami); dout(10) << "scrub requesting scrubmap from osd." << replica << dendl; MOSDRepScrub *repscrubop = new MOSDRepScrub( spg_t(info.pgid.pgid, replica.shard), version, last_update_applied, get_osdmap()->get_epoch()); osd->send_message_osd_cluster( replica.osd, repscrubop, get_osdmap()->get_epoch()); } // send scrub v3 messages (chunky scrub) void PG::_request_scrub_map( pg_shard_t replica, eversion_t version, hobject_t start, hobject_t end, bool deep) { assert(replica != pg_whoami); dout(10) << "scrub requesting scrubmap from osd." << replica << dendl; MOSDRepScrub *repscrubop = new MOSDRepScrub( spg_t(info.pgid.pgid, replica.shard), version, get_osdmap()->get_epoch(), start, end, deep); osd->send_message_osd_cluster( replica.osd, repscrubop, get_osdmap()->get_epoch()); } void PG::sub_op_scrub_reserve(OpRequestRef op) { MOSDSubOp *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); dout(7) << "sub_op_scrub_reserve" << dendl; if (scrubber.reserved) { dout(10) << "Ignoring reserve request: Already reserved" << dendl; return; } op->mark_started(); scrubber.reserved = osd->inc_scrubs_pending(); MOSDSubOpReply *reply = new MOSDSubOpReply( m, pg_whoami, 0, get_osdmap()->get_epoch(), CEPH_OSD_FLAG_ACK); ::encode(scrubber.reserved, reply->get_data()); osd->send_message_osd_cluster(reply, m->get_connection()); } void PG::sub_op_scrub_reserve_reply(OpRequestRef op) { MOSDSubOpReply *reply = static_cast(op->get_req()); assert(reply->get_header().type == MSG_OSD_SUBOPREPLY); dout(7) << "sub_op_scrub_reserve_reply" << dendl; if (!scrubber.reserved) { dout(10) << "ignoring obsolete scrub reserve reply" << dendl; return; } op->mark_started(); pg_shard_t from = reply->from; bufferlist::iterator p = reply->get_data().begin(); bool reserved; ::decode(reserved, p); if (scrubber.reserved_peers.find(from) != scrubber.reserved_peers.end()) { dout(10) << " already had osd." << from << " reserved" << dendl; } else { if (reserved) { dout(10) << " osd." << from << " scrub reserve = success" << dendl; scrubber.reserved_peers.insert(from); } else { /* One decline stops this pg from being scheduled for scrubbing. */ dout(10) << " osd." << from << " scrub reserve = fail" << dendl; scrubber.reserve_failed = true; } sched_scrub(); } } void PG::sub_op_scrub_unreserve(OpRequestRef op) { assert(op->get_req()->get_header().type == MSG_OSD_SUBOP); dout(7) << "sub_op_scrub_unreserve" << dendl; op->mark_started(); clear_scrub_reserved(); } void PG::sub_op_scrub_stop(OpRequestRef op) { op->mark_started(); MOSDSubOp *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_SUBOP); dout(7) << "sub_op_scrub_stop" << dendl; // see comment in sub_op_scrub_reserve scrubber.reserved = false; MOSDSubOpReply *reply = new MOSDSubOpReply( m, pg_whoami, 0, get_osdmap()->get_epoch(), CEPH_OSD_FLAG_ACK); osd->send_message_osd_cluster(reply, m->get_connection()); } void PG::reject_reservation() { osd->send_message_osd_cluster( primary.osd, new MBackfillReserve( MBackfillReserve::REJECT, spg_t(info.pgid.pgid, primary.shard), get_osdmap()->get_epoch()), get_osdmap()->get_epoch()); } void PG::schedule_backfill_full_retry() { Mutex::Locker lock(osd->backfill_request_lock); osd->backfill_request_timer.add_event_after( cct->_conf->osd_backfill_retry_interval, new QueuePeeringEvt( this, get_osdmap()->get_epoch(), RequestBackfill())); } void PG::clear_scrub_reserved() { osd->scrub_wq.dequeue(this); scrubber.reserved_peers.clear(); scrubber.reserve_failed = false; if (scrubber.reserved) { scrubber.reserved = false; osd->dec_scrubs_pending(); } } void PG::scrub_reserve_replicas() { assert(backfill_targets.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; dout(10) << "scrub requesting reserve from osd." << *i << dendl; vector scrub(1); scrub[0].op.op = CEPH_OSD_OP_SCRUB_RESERVE; hobject_t poid; eversion_t v; osd_reqid_t reqid; MOSDSubOp *subop = new MOSDSubOp( reqid, pg_whoami, spg_t(info.pgid.pgid, i->shard), poid, false, 0, get_osdmap()->get_epoch(), osd->get_tid(), v); subop->ops = scrub; osd->send_message_osd_cluster( i->osd, subop, get_osdmap()->get_epoch()); } } void PG::scrub_unreserve_replicas() { assert(backfill_targets.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; dout(10) << "scrub requesting unreserve from osd." << *i << dendl; vector scrub(1); scrub[0].op.op = CEPH_OSD_OP_SCRUB_UNRESERVE; hobject_t poid; eversion_t v; osd_reqid_t reqid; MOSDSubOp *subop = new MOSDSubOp( reqid, pg_whoami, spg_t(info.pgid.pgid, i->shard), poid, false, 0, get_osdmap()->get_epoch(), osd->get_tid(), v); subop->ops = scrub; osd->send_message_osd_cluster(i->osd, subop, get_osdmap()->get_epoch()); } } void PG::_scan_rollback_obs( const vector &rollback_obs, ThreadPool::TPHandle &handle) { ObjectStore::Transaction *t = NULL; eversion_t trimmed_to = last_rollback_info_trimmed_to_applied; for (vector::const_iterator i = rollback_obs.begin(); i != rollback_obs.end(); ++i) { if (i->generation < trimmed_to.version) { osd->clog.error() << "osd." << osd->whoami << " pg " << info.pgid << " found obsolete rollback obj " << *i << " generation < trimmed_to " << trimmed_to << "...repaired"; if (!t) t = new ObjectStore::Transaction; t->remove(coll, *i); } } if (t) { derr << __func__ << ": queueing trans to clean up obsolete rollback objs" << dendl; osd->store->queue_transaction_and_cleanup(osr.get(), t); } } void PG::_scan_snaps(ScrubMap &smap) { for (map::iterator i = smap.objects.begin(); i != smap.objects.end(); ++i) { const hobject_t &hoid = i->first; ScrubMap::object &o = i->second; if (hoid.snap < CEPH_MAXSNAP) { // fake nlinks for old primaries bufferlist bl; bl.push_back(o.attrs[OI_ATTR]); object_info_t oi(bl); if (oi.snaps.empty()) { // Just head o.nlinks = 1; } else if (oi.snaps.size() == 1) { // Just head + only snap o.nlinks = 2; } else { // Just head + 1st and last snaps o.nlinks = 3; } // check and if necessary fix snap_mapper set oi_snaps(oi.snaps.begin(), oi.snaps.end()); set cur_snaps; int r = snap_mapper.get_snaps(hoid, &cur_snaps); if (r != 0 && r != -ENOENT) { derr << __func__ << ": get_snaps returned " << cpp_strerror(r) << dendl; assert(0); } if (r == -ENOENT || cur_snaps != oi_snaps) { ObjectStore::Transaction t; OSDriver::OSTransaction _t(osdriver.get_transaction(&t)); if (r == 0) { r = snap_mapper.remove_oid(hoid, &_t); if (r != 0) { derr << __func__ << ": remove_oid returned " << cpp_strerror(r) << dendl; assert(0); } osd->clog.error() << "osd." << osd->whoami << " found snap mapper error on pg " << info.pgid << " oid " << hoid << " snaps in mapper: " << cur_snaps << ", oi: " << oi_snaps << "...repaired"; } else { osd->clog.error() << "osd." << osd->whoami << " found snap mapper error on pg " << info.pgid << " oid " << hoid << " snaps missing in mapper" << ", should be: " << oi_snaps << "...repaired"; } snap_mapper.add_oid(hoid, oi_snaps, &_t); r = osd->store->apply_transaction(t); if (r != 0) { derr << __func__ << ": apply_transaction got " << cpp_strerror(r) << dendl; } } } else { o.nlinks = 1; } } } /* * build a scrub map over a chunk without releasing the lock * only used by chunky scrub */ int PG::build_scrub_map_chunk( ScrubMap &map, hobject_t start, hobject_t end, bool deep, ThreadPool::TPHandle &handle) { dout(10) << "build_scrub_map" << dendl; dout(20) << "scrub_map_chunk [" << start << "," << end << ")" << dendl; map.valid_through = info.last_update; // objects vector ls; vector rollback_obs; int ret = get_pgbackend()->objects_list_range( start, end, 0, &ls, &rollback_obs); if (ret < 0) { dout(5) << "objects_list_range error: " << ret << dendl; return ret; } get_pgbackend()->be_scan_list(map, ls, deep, handle); _scan_rollback_obs(rollback_obs, handle); _scan_snaps(map); // pg attrs osd->store->collection_getattrs(coll, map.attrs); dout(10) << __func__ << " done." << dendl; return 0; } /* * build a (sorted) summary of pg content for purposes of scrubbing * called while holding pg lock */ void PG::build_scrub_map(ScrubMap &map, ThreadPool::TPHandle &handle) { dout(10) << "build_scrub_map" << dendl; map.valid_through = info.last_update; epoch_t epoch = get_osdmap()->get_epoch(); unlock(); // wait for any writes on our pg to flush to disk first. this avoids races // with scrub starting immediately after trim or recovery completion. osr->flush(); // objects vector ls; osd->store->collection_list(coll, ls); get_pgbackend()->be_scan_list(map, ls, false, handle); lock(); _scan_snaps(map); if (pg_has_reset_since(epoch)) { dout(10) << "scrub pg changed, aborting" << dendl; return; } dout(10) << "PG relocked, finalizing" << dendl; // pg attrs osd->store->collection_getattrs(coll, map.attrs); dout(10) << __func__ << " done." << dendl; } /* * build a summary of pg content changed starting after v * called while holding pg lock */ void PG::build_inc_scrub_map( ScrubMap &map, eversion_t v, ThreadPool::TPHandle &handle) { map.valid_through = last_update_applied; map.incr_since = v; vector ls; list::const_iterator p; if (v == pg_log.get_tail()) { p = pg_log.get_log().log.begin(); } else if (v > pg_log.get_tail()) { p = pg_log.get_log().find_entry(v); ++p; } else { assert(0); } for (; p != pg_log.get_log().log.end(); ++p) { if (p->is_update()) { ls.push_back(p->soid); map.objects[p->soid].negative = false; } else if (p->is_delete()) { map.objects[p->soid].negative = true; } } get_pgbackend()->be_scan_list(map, ls, false, handle); // pg attrs osd->store->collection_getattrs(coll, map.attrs); } void PG::repair_object( const hobject_t& soid, ScrubMap::object *po, pg_shard_t bad_peer, pg_shard_t ok_peer) { dout(10) << "repair_object " << soid << " bad_peer osd." << bad_peer << " ok_peer osd." << ok_peer << dendl; eversion_t v; bufferlist bv; bv.push_back(po->attrs[OI_ATTR]); object_info_t oi(bv); if (bad_peer != primary) { peer_missing[bad_peer].add(soid, oi.version, eversion_t()); } else { // We should only be scrubbing if the PG is clean. assert(waiting_for_unreadable_object.empty()); pg_log.missing_add(soid, oi.version, eversion_t()); missing_loc.add_missing(soid, oi.version, eversion_t()); missing_loc.add_location(soid, ok_peer); pg_log.set_last_requested(0); } } /* replica_scrub * * Classic behavior: * * If msg->scrub_from is not set, replica_scrub calls build_scrubmap to * build a complete map (with the pg lock dropped). * * If msg->scrub_from is set, replica_scrub sets scrubber.finalizing. * Similarly to scrub, if last_update_applied is behind info.last_update * replica_scrub returns to be requeued by sub_op_modify_applied. * replica_scrub then builds an incremental scrub map with the * pg lock held. * * Chunky behavior: * * Wait for last_update_applied to match msg->scrub_to as above. Wait * for pushes to complete in case of recent recovery. Build a single * scrubmap of objects that are in the range [msg->start, msg->end). */ void PG::replica_scrub( MOSDRepScrub *msg, ThreadPool::TPHandle &handle) { assert(!scrubber.active_rep_scrub); dout(7) << "replica_scrub" << dendl; if (msg->map_epoch < info.history.same_interval_since) { if (scrubber.finalizing) { dout(10) << "scrub pg changed, aborting" << dendl; scrubber.finalizing = 0; } else { dout(10) << "replica_scrub discarding old replica_scrub from " << msg->map_epoch << " < " << info.history.same_interval_since << dendl; } return; } ScrubMap map; if (msg->chunky) { // chunky scrub if (last_update_applied < msg->scrub_to) { dout(10) << "waiting for last_update_applied to catch up" << dendl; scrubber.active_rep_scrub = msg; msg->get(); return; } if (active_pushes > 0) { dout(10) << "waiting for active pushes to finish" << dendl; scrubber.active_rep_scrub = msg; msg->get(); return; } build_scrub_map_chunk( map, msg->start, msg->end, msg->deep, handle); } else { if (msg->scrub_from > eversion_t()) { if (scrubber.finalizing) { assert(last_update_applied == info.last_update); assert(last_update_applied == msg->scrub_to); } else { scrubber.finalizing = 1; if (last_update_applied != msg->scrub_to) { scrubber.active_rep_scrub = msg; msg->get(); return; } } build_inc_scrub_map(map, msg->scrub_from, handle); scrubber.finalizing = 0; } else { build_scrub_map(map, handle); } if (msg->map_epoch < info.history.same_interval_since) { dout(10) << "scrub pg changed, aborting" << dendl; return; } } vector scrub(1); scrub[0].op.op = CEPH_OSD_OP_SCRUB_MAP; hobject_t poid; eversion_t v; osd_reqid_t reqid; MOSDSubOp *subop = new MOSDSubOp( reqid, pg_whoami, spg_t(info.pgid.pgid, get_primary().shard), poid, false, 0, msg->map_epoch, osd->get_tid(), v); ::encode(map, subop->get_data()); subop->ops = scrub; osd->send_message_osd_cluster(subop, msg->get_connection()); } /* Scrub: * PG_STATE_SCRUBBING is set when the scrub is queued * * scrub will be chunky if all OSDs in PG support chunky scrub * scrub will fall back to classic in any other case */ void PG::scrub(ThreadPool::TPHandle &handle) { lock(); if (g_conf->osd_scrub_sleep > 0 && (scrubber.state == PG::Scrubber::NEW_CHUNK || scrubber.state == PG::Scrubber::INACTIVE)) { dout(20) << __func__ << " state is INACTIVE|NEW_CHUNK, sleeping" << dendl; unlock(); utime_t t; t.set_from_double(g_conf->osd_scrub_sleep); t.sleep(); lock(); dout(20) << __func__ << " slept for " << t << dendl; } if (deleting) { unlock(); return; } if (!is_primary() || !is_active() || !is_clean() || !is_scrubbing()) { dout(10) << "scrub -- not primary or active or not clean" << dendl; state_clear(PG_STATE_SCRUBBING); state_clear(PG_STATE_REPAIR); state_clear(PG_STATE_DEEP_SCRUB); publish_stats_to_osd(); unlock(); return; } // when we're starting a scrub, we need to determine which type of scrub to do if (!scrubber.active) { OSDMapRef curmap = osd->get_osdmap(); scrubber.is_chunky = true; assert(backfill_targets.empty()); for (unsigned i=0; iget_con_osd_cluster(acting[i], get_osdmap()->get_epoch()); if (!con) continue; if (!con->has_feature(CEPH_FEATURE_CHUNKY_SCRUB)) { dout(20) << "OSD " << acting[i] << " does not support chunky scrubs, falling back to classic" << dendl; scrubber.is_chunky = false; break; } } if (scrubber.is_chunky) { scrubber.deep = state_test(PG_STATE_DEEP_SCRUB); } else { state_clear(PG_STATE_DEEP_SCRUB); } dout(10) << "starting a new " << (scrubber.is_chunky ? "chunky" : "classic") << " scrub" << dendl; } if (scrubber.is_chunky) { chunky_scrub(handle); } else { classic_scrub(handle); } unlock(); } /* * Classic scrub is a two stage scrub: an initial scrub with writes enabled * followed by a finalize with writes blocked. * * A request is sent out to all replicas for initial scrub maps. Once they reply * (sub_op_scrub_map) writes are blocked for all objects in the PG. * * Finalize: Primaries and replicas wait for all writes in the log to be applied * (op_applied), then builds an incremental scrub of all the changes since the * beginning of the scrub. * * Once the primary has received all maps, it compares them and performs * repairs. * * The initial stage of the scrub is handled by scrub_wq and the final stage by * scrub_finalize_wq. * * Relevant variables: * * scrubber.waiting_on (int) * scrubber.waiting_on_whom * Number of people who still need to build an initial/incremental scrub map. * This is decremented in sub_op_scrub_map. * * last_update_applied * The last update that's hit the disk. In the finalize stage, we block * writes and wait for all writes to flush by checking: * * last_update_appied == info.last_update * * This is checked in op_applied. * * scrubber.block_writes * Flag to determine if writes are blocked. * * finalizing scrub * Flag set when we're in the finalize stage. * */ void PG::classic_scrub(ThreadPool::TPHandle &handle) { assert(pool.info.type == pg_pool_t::TYPE_REPLICATED); if (!scrubber.active) { dout(10) << "scrub start" << dendl; scrubber.active = true; scrubber.classic = true; publish_stats_to_osd(); scrubber.received_maps.clear(); scrubber.epoch_start = info.history.same_interval_since; osd->inc_scrubs_active(scrubber.reserved); if (scrubber.reserved) { scrubber.reserved = false; scrubber.reserved_peers.clear(); } /* scrubber.waiting_on == 0 iff all replicas have sent the requested maps and * the primary has done a final scrub (which in turn can only happen if * last_update_applied == info.last_update) */ scrubber.waiting_on = acting.size(); scrubber.waiting_on_whom.insert( actingbackfill.begin(), actingbackfill.end()); scrubber.waiting_on_whom.erase(pg_whoami); // request maps from replicas for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; _request_scrub_map_classic(*i, eversion_t()); } // Unlocks and relocks... scrubber.primary_scrubmap = ScrubMap(); build_scrub_map(scrubber.primary_scrubmap, handle); if (scrubber.epoch_start != info.history.same_interval_since) { dout(10) << "scrub pg changed, aborting" << dendl; scrub_clear_state(); scrub_unreserve_replicas(); return; } --scrubber.waiting_on; scrubber.waiting_on_whom.erase(pg_whoami); if (scrubber.waiting_on == 0) { // the replicas have completed their scrub map, so lock out writes scrubber.block_writes = true; } else { dout(10) << "wait for replicas to build initial scrub map" << dendl; return; } if (last_update_applied != info.last_update) { dout(10) << "wait for cleanup" << dendl; return; } // fall through if last_update_applied == info.last_update and scrubber.waiting_on == 0 // request incrementals from replicas scrub_gather_replica_maps(); ++scrubber.waiting_on; scrubber.waiting_on_whom.insert(pg_whoami); } dout(10) << "clean up scrub" << dendl; assert(last_update_applied == info.last_update); scrubber.finalizing = true; if (scrubber.epoch_start != info.history.same_interval_since) { dout(10) << "scrub pg changed, aborting" << dendl; scrub_clear_state(); scrub_unreserve_replicas(); return; } if (scrubber.primary_scrubmap.valid_through != pg_log.get_head()) { ScrubMap incr; build_inc_scrub_map(incr, scrubber.primary_scrubmap.valid_through, handle); scrubber.primary_scrubmap.merge_incr(incr); } --scrubber.waiting_on; scrubber.waiting_on_whom.erase(pg_whoami); if (scrubber.waiting_on == 0) { assert(last_update_applied == info.last_update); osd->scrub_finalize_wq.queue(this); } } /* * Chunky scrub scrubs objects one chunk at a time with writes blocked for that * chunk. * * The object store is partitioned into chunks which end on hash boundaries. For * each chunk, the following logic is performed: * * (1) Block writes on the chunk * (2) Request maps from replicas * (3) Wait for pushes to be applied (after recovery) * (4) Wait for writes to flush on the chunk * (5) Wait for maps from replicas * (6) Compare / repair all scrub maps * * This logic is encoded in the very linear state machine: * * +------------------+ * _________v__________ | * | | | * | INACTIVE | | * |____________________| | * | | * | +----------+ | * _________v___v______ | | * | | | | * | NEW_CHUNK | | | * |____________________| | | * | | | * _________v__________ | | * | | | | * | WAIT_PUSHES | | | * |____________________| | | * | | | * _________v__________ | | * | | | | * | WAIT_LAST_UPDATE | | | * |____________________| | | * | | | * _________v__________ | | * | | | | * | BUILD_MAP | | | * |____________________| | | * | | | * _________v__________ | | * | | | | * | WAIT_REPLICAS | | | * |____________________| | | * | | | * _________v__________ | | * | | | | * | COMPARE_MAPS | | | * |____________________| | | * | | | | * | +----------+ | * _________v__________ | * | | | * | FINISH | | * |____________________| | * | | * +------------------+ * * The primary determines the last update from the subset by walking the log. If * it sees a log entry pertaining to a file in the chunk, it tells the replicas * to wait until that update is applied before building a scrub map. Both the * primary and replicas will wait for any active pushes to be applied. * * In contrast to classic_scrub, chunky_scrub is entirely handled by scrub_wq. * * scrubber.state encodes the current state of the scrub (refer to state diagram * for details). */ void PG::chunky_scrub(ThreadPool::TPHandle &handle) { // check for map changes if (scrubber.is_chunky_scrub_active()) { if (scrubber.epoch_start != info.history.same_interval_since) { dout(10) << "scrub pg changed, aborting" << dendl; scrub_clear_state(); scrub_unreserve_replicas(); return; } } bool done = false; int ret; while (!done) { dout(20) << "scrub state " << Scrubber::state_string(scrubber.state) << dendl; switch (scrubber.state) { case PG::Scrubber::INACTIVE: dout(10) << "scrub start" << dendl; publish_stats_to_osd(); scrubber.epoch_start = info.history.same_interval_since; scrubber.active = true; osd->inc_scrubs_active(scrubber.reserved); if (scrubber.reserved) { scrubber.reserved = false; scrubber.reserved_peers.clear(); } scrubber.start = hobject_t(); scrubber.state = PG::Scrubber::NEW_CHUNK; break; case PG::Scrubber::NEW_CHUNK: scrubber.primary_scrubmap = ScrubMap(); scrubber.received_maps.clear(); { hobject_t candidate_end; // get the start and end of our scrub chunk // // start and end need to lie on a hash boundary. We test for this by // requesting a list and searching backward from the end looking for a // boundary. If there's no boundary, we request a list after the first // list, and so forth. bool boundary_found = false; hobject_t start = scrubber.start; while (!boundary_found) { vector objects; ret = get_pgbackend()->objects_list_partial( start, cct->_conf->osd_scrub_chunk_min, cct->_conf->osd_scrub_chunk_max, 0, &objects, &candidate_end); assert(ret >= 0); // in case we don't find a boundary: start again at the end start = candidate_end; // special case: reached end of file store, implicitly a boundary if (objects.empty()) { break; } // search backward from the end looking for a boundary objects.push_back(candidate_end); while (!boundary_found && objects.size() > 1) { hobject_t end = objects.back().get_boundary(); objects.pop_back(); if (objects.back().get_filestore_key() != end.get_filestore_key()) { candidate_end = end; boundary_found = true; } } } if (!_range_available_for_scrub(scrubber.start, candidate_end)) { // we'll be requeued by whatever made us unavailable for scrub dout(10) << __func__ << ": scrub blocked somewhere in range " << "[" << scrubber.start << ", " << candidate_end << ")" << dendl; done = true; break; } scrubber.end = candidate_end; } scrubber.block_writes = true; // walk the log to find the latest update that affects our chunk scrubber.subset_last_update = pg_log.get_tail(); for (list::const_iterator p = pg_log.get_log().log.begin(); p != pg_log.get_log().log.end(); ++p) { if (p->soid >= scrubber.start && p->soid < scrubber.end) scrubber.subset_last_update = p->version; } // ask replicas to wait until last_update_applied >= scrubber.subset_last_update and then scan scrubber.waiting_on_whom.insert(pg_whoami); ++scrubber.waiting_on; // request maps from replicas for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; _request_scrub_map(*i, scrubber.subset_last_update, scrubber.start, scrubber.end, scrubber.deep); scrubber.waiting_on_whom.insert(*i); ++scrubber.waiting_on; } scrubber.state = PG::Scrubber::WAIT_PUSHES; break; case PG::Scrubber::WAIT_PUSHES: if (active_pushes == 0) { scrubber.state = PG::Scrubber::WAIT_LAST_UPDATE; } else { dout(15) << "wait for pushes to apply" << dendl; done = true; } break; case PG::Scrubber::WAIT_LAST_UPDATE: if (last_update_applied >= scrubber.subset_last_update) { scrubber.state = PG::Scrubber::BUILD_MAP; } else { // will be requeued by op_applied dout(15) << "wait for writes to flush" << dendl; done = true; } break; case PG::Scrubber::BUILD_MAP: assert(last_update_applied >= scrubber.subset_last_update); // build my own scrub map ret = build_scrub_map_chunk(scrubber.primary_scrubmap, scrubber.start, scrubber.end, scrubber.deep, handle); if (ret < 0) { dout(5) << "error building scrub map: " << ret << ", aborting" << dendl; scrub_clear_state(); scrub_unreserve_replicas(); return; } --scrubber.waiting_on; scrubber.waiting_on_whom.erase(pg_whoami); scrubber.state = PG::Scrubber::WAIT_REPLICAS; break; case PG::Scrubber::WAIT_REPLICAS: if (scrubber.waiting_on > 0) { // will be requeued by sub_op_scrub_map dout(10) << "wait for replicas to build scrub map" << dendl; done = true; } else { scrubber.state = PG::Scrubber::COMPARE_MAPS; } break; case PG::Scrubber::COMPARE_MAPS: assert(last_update_applied >= scrubber.subset_last_update); assert(scrubber.waiting_on == 0); scrub_compare_maps(); scrubber.block_writes = false; scrubber.run_callbacks(); // requeue the writes from the chunk that just finished requeue_ops(waiting_for_active); if (scrubber.end < hobject_t::get_max()) { // schedule another leg of the scrub scrubber.start = scrubber.end; scrubber.state = PG::Scrubber::NEW_CHUNK; osd->scrub_wq.queue(this); done = true; } else { scrubber.state = PG::Scrubber::FINISH; } break; case PG::Scrubber::FINISH: scrub_finish(); scrubber.state = PG::Scrubber::INACTIVE; done = true; break; default: assert(0); } } } void PG::scrub_clear_state() { assert(_lock.is_locked()); state_clear(PG_STATE_SCRUBBING); state_clear(PG_STATE_REPAIR); state_clear(PG_STATE_DEEP_SCRUB); publish_stats_to_osd(); // active -> nothing. if (scrubber.active) osd->dec_scrubs_active(); requeue_ops(waiting_for_active); if (scrubber.queue_snap_trim) { dout(10) << "scrub finished, requeuing snap_trimmer" << dendl; queue_snap_trim(); } scrubber.reset(); // type-specific state clear _scrub_clear_state(); } bool PG::scrub_gather_replica_maps() { assert(scrubber.waiting_on == 0); assert(_lock.is_locked()); for (map::iterator p = scrubber.received_maps.begin(); p != scrubber.received_maps.end(); ++p) { if (scrubber.received_maps[p->first].valid_through != pg_log.get_head()) { scrubber.waiting_on++; scrubber.waiting_on_whom.insert(p->first); // Need to request another incremental map _request_scrub_map_classic(p->first, p->second.valid_through); } } if (scrubber.waiting_on > 0) { return false; } else { return true; } } void PG::scrub_compare_maps() { dout(10) << "scrub_compare_maps has maps, analyzing" << dendl; // construct authoritative scrub map for type specific scrubbing ScrubMap authmap(scrubber.primary_scrubmap); if (acting.size() > 1) { dout(10) << "scrub comparing replica scrub maps" << dendl; stringstream ss; // Map from object with errors to good peer map authoritative; map maps; dout(2) << "scrub osd." << acting[0] << " has " << scrubber.primary_scrubmap.objects.size() << " items" << dendl; maps[pg_whoami] = &scrubber.primary_scrubmap; for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; dout(2) << "scrub replica " << *i << " has " << scrubber.received_maps[*i].objects.size() << " items" << dendl; maps[*i] = &scrubber.received_maps[*i]; } get_pgbackend()->be_compare_scrubmaps( maps, scrubber.missing, scrubber.inconsistent, authoritative, scrubber.inconsistent_snapcolls, scrubber.shallow_errors, scrubber.deep_errors, info.pgid, acting, ss); dout(2) << ss.str() << dendl; if (!authoritative.empty() || !scrubber.inconsistent_snapcolls.empty()) { osd->clog.error(ss); } for (map::iterator i = authoritative.begin(); i != authoritative.end(); ++i) { scrubber.authoritative.insert( make_pair( i->first, make_pair(maps[i->second]->objects[i->first], i->second))); } for (map::iterator i = authoritative.begin(); i != authoritative.end(); ++i) { authmap.objects.erase(i->first); authmap.objects.insert(*(maps[i->second]->objects.find(i->first))); } } // ok, do the pg-type specific scrubbing _scrub(authmap); } void PG::scrub_process_inconsistent() { dout(10) << "process_inconsistent() checking authoritative" << dendl; bool repair = state_test(PG_STATE_REPAIR); bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); const char *mode = (repair ? "repair": (deep_scrub ? "deep-scrub" : "scrub")); if (!scrubber.authoritative.empty() || !scrubber.inconsistent.empty()) { stringstream ss; for (map >::iterator obj = scrubber.inconsistent_snapcolls.begin(); obj != scrubber.inconsistent_snapcolls.end(); ++obj) { for (set::iterator j = obj->second.begin(); j != obj->second.end(); ++j) { ++scrubber.shallow_errors; ss << info.pgid << " " << mode << " " << " object " << obj->first << " has inconsistent snapcolls on " << *j << std::endl; } } ss << info.pgid << " " << mode << " " << scrubber.missing.size() << " missing, " << scrubber.inconsistent.size() << " inconsistent objects\n"; dout(2) << ss.str() << dendl; osd->clog.error(ss); if (repair) { state_clear(PG_STATE_CLEAN); for (map >::iterator i = scrubber.authoritative.begin(); i != scrubber.authoritative.end(); ++i) { set::iterator j; if (scrubber.missing.count(i->first)) { for (j = scrubber.missing[i->first].begin(); j != scrubber.missing[i->first].end(); ++j) { repair_object( i->first, &(i->second.first), *j, i->second.second); ++scrubber.fixed; } } if (scrubber.inconsistent.count(i->first)) { for (j = scrubber.inconsistent[i->first].begin(); j != scrubber.inconsistent[i->first].end(); ++j) { repair_object(i->first, &(i->second.first), *j, i->second.second); ++scrubber.fixed; } } } } } } void PG::scrub_finalize() { lock(); if (deleting) { unlock(); return; } assert(last_update_applied == info.last_update); if (scrubber.epoch_start != info.history.same_interval_since) { dout(10) << "scrub pg changed, aborting" << dendl; scrub_clear_state(); scrub_unreserve_replicas(); unlock(); return; } if (!scrub_gather_replica_maps()) { dout(10) << "maps not yet up to date, sent out new requests" << dendl; unlock(); return; } scrub_compare_maps(); scrub_finish(); dout(10) << "scrub done" << dendl; unlock(); } // the part that actually finalizes a scrub void PG::scrub_finish() { bool repair = state_test(PG_STATE_REPAIR); bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); const char *mode = (repair ? "repair": (deep_scrub ? "deep-scrub" : "scrub")); // type-specific finish (can tally more errors) _scrub_finish(); scrub_process_inconsistent(); { stringstream oss; oss << info.pgid.pgid << " " << mode << " "; int total_errors = scrubber.shallow_errors + scrubber.deep_errors; if (total_errors) oss << total_errors << " errors"; else oss << "ok"; if (!deep_scrub && info.stats.stats.sum.num_deep_scrub_errors) oss << " ( " << info.stats.stats.sum.num_deep_scrub_errors << " remaining deep scrub error(s) )"; if (repair) oss << ", " << scrubber.fixed << " fixed"; oss << "\n"; if (total_errors) osd->clog.error(oss); else osd->clog.info(oss); } // finish up unreg_next_scrub(); utime_t now = ceph_clock_now(cct); info.history.last_scrub = info.last_update; info.history.last_scrub_stamp = now; if (scrubber.deep) { info.history.last_deep_scrub = info.last_update; info.history.last_deep_scrub_stamp = now; } // Since we don't know which errors were fixed, we can only clear them // when every one has been fixed. if (repair) { if (scrubber.fixed == scrubber.shallow_errors + scrubber.deep_errors) { assert(deep_scrub); scrubber.shallow_errors = scrubber.deep_errors = 0; } else { // Deep scrub in order to get corrected error counts scrub_after_recovery = true; } } if (deep_scrub) { if ((scrubber.shallow_errors == 0) && (scrubber.deep_errors == 0)) info.history.last_clean_scrub_stamp = now; info.stats.stats.sum.num_shallow_scrub_errors = scrubber.shallow_errors; info.stats.stats.sum.num_deep_scrub_errors = scrubber.deep_errors; } else { info.stats.stats.sum.num_shallow_scrub_errors = scrubber.shallow_errors; // XXX: last_clean_scrub_stamp doesn't mean the pg is not inconsistent // because of deep-scrub errors if (scrubber.shallow_errors == 0) info.history.last_clean_scrub_stamp = now; } info.stats.stats.sum.num_scrub_errors = info.stats.stats.sum.num_shallow_scrub_errors + info.stats.stats.sum.num_deep_scrub_errors; reg_next_scrub(); { ObjectStore::Transaction *t = new ObjectStore::Transaction; dirty_info = true; write_if_dirty(*t); int tr = osd->store->queue_transaction_and_cleanup(osr.get(), t); assert(tr == 0); } if (repair) { queue_peering_event( CephPeeringEvtRef( new CephPeeringEvt( get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), DoRecovery()))); } scrub_clear_state(); scrub_unreserve_replicas(); if (is_active() && is_primary()) { share_pg_info(); } } void PG::share_pg_info() { dout(10) << "share_pg_info" << dendl; // share new pg_info_t with replicas assert(!actingbackfill.empty()); for (set::iterator i = actingbackfill.begin(); i != actingbackfill.end(); ++i) { if (*i == pg_whoami) continue; pg_shard_t peer = *i; if (peer_info.count(peer)) { peer_info[peer].last_epoch_started = info.last_epoch_started; peer_info[peer].history.merge(info.history); } MOSDPGInfo *m = new MOSDPGInfo(get_osdmap()->get_epoch()); m->pg_list.push_back( make_pair( pg_notify_t( peer.shard, pg_whoami.shard, get_osdmap()->get_epoch(), get_osdmap()->get_epoch(), info), pg_interval_map_t())); osd->send_message_osd_cluster(peer.osd, m, get_osdmap()->get_epoch()); } } /* * Share a new segment of this PG's log with some replicas, after PG is active. * * Updates peer_missing and peer_info. */ void PG::share_pg_log() { dout(10) << __func__ << dendl; assert(is_primary()); set::const_iterator a = actingbackfill.begin(); assert(a != actingbackfill.end()); set::const_iterator end = actingbackfill.end(); while (a != end) { pg_shard_t peer(*a); ++a; if (peer == pg_whoami) continue; pg_missing_t& pmissing(peer_missing[peer]); pg_info_t& pinfo(peer_info[peer]); MOSDPGLog *m = new MOSDPGLog( peer.shard, pg_whoami.shard, info.last_update.epoch, info); m->log.copy_after(pg_log.get_log(), pinfo.last_update); for (list::const_iterator i = m->log.log.begin(); i != m->log.log.end(); ++i) { pmissing.add_next_event(*i); } pinfo.last_update = m->log.head; osd->send_message_osd_cluster(peer.osd, m, get_osdmap()->get_epoch()); } } void PG::update_history_from_master(pg_history_t new_history) { unreg_next_scrub(); info.history.merge(new_history); reg_next_scrub(); } void PG::fulfill_info( pg_shard_t from, const pg_query_t &query, pair ¬ify_info) { assert(from == primary); assert(query.type == pg_query_t::INFO); // info dout(10) << "sending info" << dendl; notify_info = make_pair(from, info); } void PG::fulfill_log( pg_shard_t from, const pg_query_t &query, epoch_t query_epoch) { dout(10) << "log request from " << from << dendl; assert(from == primary); assert(query.type != pg_query_t::INFO); MOSDPGLog *mlog = new MOSDPGLog( from.shard, pg_whoami.shard, get_osdmap()->get_epoch(), info, query_epoch); mlog->missing = pg_log.get_missing(); // primary -> other, when building master log if (query.type == pg_query_t::LOG) { dout(10) << " sending info+missing+log since " << query.since << dendl; if (query.since != eversion_t() && query.since < pg_log.get_tail()) { osd->clog.error() << info.pgid << " got broken pg_query_t::LOG since " << query.since << " when my log.tail is " << pg_log.get_tail() << ", sending full log instead\n"; mlog->log = pg_log.get_log(); // primary should not have requested this!! } else mlog->log.copy_after(pg_log.get_log(), query.since); } else if (query.type == pg_query_t::FULLLOG) { dout(10) << " sending info+missing+full log" << dendl; mlog->log = pg_log.get_log(); } dout(10) << " sending " << mlog->log << " " << mlog->missing << dendl; ConnectionRef con = osd->get_con_osd_cluster( from.osd, get_osdmap()->get_epoch()); if (con) { osd->osd->_share_map_outgoing(from.osd, con.get(), get_osdmap()); osd->send_message_osd_cluster(mlog, con.get()); } else { mlog->put(); } } // true if all OSDs in prior intervals may have crashed, and we need to replay // false positives are okay, false negatives are not. bool PG::may_need_replay(const OSDMapRef osdmap) const { bool crashed = false; for (map::const_reverse_iterator p = past_intervals.rbegin(); p != past_intervals.rend(); ++p) { const pg_interval_t &interval = p->second; dout(10) << "may_need_replay " << interval << dendl; if (interval.last < info.history.last_epoch_started) break; // we don't care if (interval.acting.empty()) continue; if (!interval.maybe_went_rw) continue; // look at whether any of the osds during this interval survived // past the end of the interval (i.e., didn't crash and // potentially fail to COMMIT a write that it ACKed). bool any_survived_interval = false; // consider ACTING osds for (unsigned i=0; iexists(o)) pinfo = &osdmap->get_info(o); // does this osd appear to have survived through the end of the // interval? if (pinfo) { if (pinfo->up_from <= interval.first && pinfo->up_thru > interval.last) { dout(10) << "may_need_replay osd." << o << " up_from " << pinfo->up_from << " up_thru " << pinfo->up_thru << " survived the interval" << dendl; any_survived_interval = true; } else if (pinfo->up_from <= interval.first && (std::find(acting.begin(), acting.end(), o) != acting.end() || std::find(up.begin(), up.end(), o) != up.end())) { dout(10) << "may_need_replay osd." << o << " up_from " << pinfo->up_from << " and is in acting|up," << " assumed to have survived the interval" << dendl; // (if it hasn't, we will rebuild PriorSet) any_survived_interval = true; } else if (pinfo->up_from > interval.last && pinfo->last_clean_begin <= interval.first && pinfo->last_clean_end > interval.last) { dout(10) << "may_need_replay prior osd." << o << " up_from " << pinfo->up_from << " and last clean interval [" << pinfo->last_clean_begin << "," << pinfo->last_clean_end << ") survived the interval" << dendl; any_survived_interval = true; } } } if (!any_survived_interval) { dout(3) << "may_need_replay no known survivors of interval " << interval.first << "-" << interval.last << ", may need replay" << dendl; crashed = true; break; } } return crashed; } bool PG::is_split(OSDMapRef lastmap, OSDMapRef nextmap) { return info.pgid.is_split( lastmap->get_pg_num(pool.id), nextmap->get_pg_num(pool.id), 0); } bool PG::acting_up_affected( int newupprimary, int newactingprimary, const vector& newup, const vector& newacting) { if (newupprimary != up_primary.osd || newactingprimary != primary.osd || acting != newacting || up != newup) { dout(20) << "acting_up_affected newup " << newup << " newacting " << newacting << dendl; return true; } else { return false; } } bool PG::old_peering_msg(epoch_t reply_epoch, epoch_t query_epoch) { if (last_peering_reset > reply_epoch || last_peering_reset > query_epoch) { dout(10) << "old_peering_msg reply_epoch " << reply_epoch << " query_epoch " << query_epoch << " last_peering_reset " << last_peering_reset << dendl; return true; } return false; } void PG::set_last_peering_reset() { dout(20) << "set_last_peering_reset " << get_osdmap()->get_epoch() << dendl; if (last_peering_reset != get_osdmap()->get_epoch()) { last_peering_reset = get_osdmap()->get_epoch(); reset_interval_flush(); } } struct FlushState { PGRef pg; epoch_t epoch; FlushState(PG *pg, epoch_t epoch) : pg(pg), epoch(epoch) {} ~FlushState() { pg->lock(); if (!pg->pg_has_reset_since(epoch)) pg->queue_flushed(epoch); pg->unlock(); } }; typedef ceph::shared_ptr FlushStateRef; void PG::start_flush(ObjectStore::Transaction *t, list *on_applied, list *on_safe) { // flush in progress ops FlushStateRef flush_trigger( new FlushState(this, get_osdmap()->get_epoch())); t->nop(); flushes_in_progress++; on_applied->push_back(new ContainerContext(flush_trigger)); on_safe->push_back(new ContainerContext(flush_trigger)); } void PG::reset_interval_flush() { dout(10) << "Clearing blocked outgoing recovery messages" << dendl; recovery_state.clear_blocked_outgoing(); if (!osr->flush_commit( new QueuePeeringEvt( this, get_osdmap()->get_epoch(), IntervalFlush()))) { dout(10) << "Beginning to block outgoing recovery messages" << dendl; recovery_state.begin_block_outgoing(); } else { dout(10) << "Not blocking outgoing recovery messages" << dendl; } } /* Called before initializing peering during advance_map */ void PG::start_peering_interval( const OSDMapRef lastmap, const vector& newup, int new_up_primary, const vector& newacting, int new_acting_primary, ObjectStore::Transaction *t) { const OSDMapRef osdmap = get_osdmap(); set_last_peering_reset(); vector oldacting, oldup; int oldrole = get_role(); unreg_next_scrub(); pg_shard_t old_acting_primary = get_primary(); pg_shard_t old_up_primary = up_primary; bool was_old_primary = is_primary(); acting.swap(oldacting); up.swap(oldup); init_primary_up_acting( newup, newacting, new_up_primary, new_acting_primary); if (info.stats.up != up || info.stats.acting != acting || info.stats.up_primary != new_up_primary || info.stats.acting_primary != new_acting_primary) { info.stats.up = up; info.stats.up_primary = new_up_primary; info.stats.acting = acting; info.stats.acting_primary = new_acting_primary; info.stats.mapping_epoch = info.history.same_interval_since; } // This will now be remapped during a backfill in cases // that it would not have been before. if (up != acting) state_set(PG_STATE_REMAPPED); else state_clear(PG_STATE_REMAPPED); int role = osdmap->calc_pg_role(osd->whoami, acting, acting.size()); if (pool.info.is_replicated() || role == pg_whoami.shard) set_role(role); else set_role(-1); reg_next_scrub(); // did acting, up, primary|acker change? if (!lastmap) { dout(10) << " no lastmap" << dendl; dirty_info = true; dirty_big_info = true; } else { std::stringstream debug; bool new_interval = pg_interval_t::check_new_interval( old_acting_primary.osd, new_acting_primary, oldacting, newacting, old_up_primary.osd, new_up_primary, oldup, newup, info.history.same_interval_since, info.history.last_epoch_clean, osdmap, lastmap, info.pgid.pool(), info.pgid.pgid, &past_intervals, &debug); dout(10) << __func__ << ": check_new_interval output: " << debug.str() << dendl; if (new_interval) { dout(10) << " noting past " << past_intervals.rbegin()->second << dendl; dirty_info = true; dirty_big_info = true; } } if (old_up_primary != up_primary || old_acting_primary != primary || oldacting != acting || oldup != up || is_split(lastmap, osdmap)) { info.history.same_interval_since = osdmap->get_epoch(); } if (old_up_primary != up_primary || oldup != up) { info.history.same_up_since = osdmap->get_epoch(); } // this comparison includes primary rank via pg_shard_t if (old_acting_primary != get_primary()) { info.history.same_primary_since = osdmap->get_epoch(); } dout(10) << " up " << oldup << " -> " << up << ", acting " << oldacting << " -> " << acting << ", acting_primary " << old_acting_primary << " -> " << new_acting_primary << ", up_primary " << old_up_primary << " -> " << new_up_primary << ", role " << oldrole << " -> " << role << dendl; // deactivate. state_clear(PG_STATE_ACTIVE); state_clear(PG_STATE_DOWN); state_clear(PG_STATE_RECOVERY_WAIT); state_clear(PG_STATE_RECOVERING); peer_missing.clear(); peer_purged.clear(); actingbackfill.clear(); // reset primary state? if (was_old_primary || is_primary()) { osd->remove_want_pg_temp(info.pgid.pgid); } clear_primary_state(); // pg->on_* on_change(t); assert(!deleting); // should we tell the primary we are here? send_notify = !is_primary(); if (role != oldrole || was_old_primary != is_primary()) { // did primary change? if (was_old_primary != is_primary()) { state_clear(PG_STATE_CLEAN); clear_publish_stats(); // take replay queue waiters list ls; for (map::iterator it = replay_queue.begin(); it != replay_queue.end(); ++it) ls.push_back(it->second); replay_queue.clear(); requeue_ops(ls); } on_role_change(); // take active waiters requeue_ops(waiting_for_active); } else { // no role change. // did primary change? if (get_primary() != old_acting_primary) { dout(10) << *this << " " << oldacting << " -> " << acting << ", acting primary " << old_acting_primary << " -> " << get_primary() << dendl; } else { // primary is the same. if (is_primary()) { // i am (still) primary. but my replica set changed. state_clear(PG_STATE_CLEAN); dout(10) << oldacting << " -> " << acting << ", replicas changed" << dendl; } } } cancel_recovery(); if (acting.empty() && !up.empty() && up_primary == pg_whoami) { dout(10) << " acting empty, but i am up[0], clearing pg_temp" << dendl; osd->queue_want_pg_temp(info.pgid.pgid, acting); } } void PG::proc_primary_info(ObjectStore::Transaction &t, const pg_info_t &oinfo) { assert(!is_primary()); unreg_next_scrub(); if (info.history.merge(oinfo.history)) dirty_info = true; reg_next_scrub(); if (last_complete_ondisk.epoch >= info.history.last_epoch_started) { // DEBUG: verify that the snaps are empty in snap_mapper if (cct->_conf->osd_debug_verify_snaps_on_info) { interval_set p; p.union_of(oinfo.purged_snaps, info.purged_snaps); p.subtract(info.purged_snaps); if (!p.empty()) { for (interval_set::iterator i = p.begin(); i != p.end(); ++i) { for (snapid_t snap = i.get_start(); snap != i.get_len() + i.get_start(); ++snap) { hobject_t hoid; int r = snap_mapper.get_next_object_to_trim(snap, &hoid); if (r != 0 && r != -ENOENT) { derr << __func__ << ": snap_mapper get_next_object_to_trim returned " << cpp_strerror(r) << dendl; assert(0); } else if (r != -ENOENT) { derr << __func__ << ": snap_mapper get_next_object_to_trim returned " << cpp_strerror(r) << " for object " << hoid << " on snap " << snap << " which should have been fully trimmed " << dendl; assert(0); } } } } } info.purged_snaps = oinfo.purged_snaps; dirty_info = true; dirty_big_info = true; } } ostream& operator<<(ostream& out, const PG& pg) { out << "pg[" << pg.info << " " << pg.up; if (pg.acting != pg.up) out << "/" << pg.acting; out << " r=" << pg.get_role(); out << " lpr=" << pg.get_last_peering_reset(); if (!pg.past_intervals.empty()) { out << " pi=" << pg.past_intervals.begin()->first << "-" << pg.past_intervals.rbegin()->second.last << "/" << pg.past_intervals.size(); } if (pg.is_active() && pg.last_update_ondisk != pg.info.last_update) out << " luod=" << pg.last_update_ondisk; if (pg.recovery_ops_active) out << " rops=" << pg.recovery_ops_active; if (pg.pg_log.get_tail() != pg.info.log_tail || pg.pg_log.get_head() != pg.info.last_update) out << " (info mismatch, " << pg.pg_log.get_log() << ")"; if (!pg.pg_log.get_log().empty()) { if ((pg.pg_log.get_log().log.begin()->version <= pg.pg_log.get_tail())) { out << " (log bound mismatch, actual=[" << pg.pg_log.get_log().log.begin()->version << "," << pg.pg_log.get_log().log.rbegin()->version << "]"; out << ")"; } } if (!pg.backfill_targets.empty()) out << " bft=" << pg.backfill_targets; out << " crt=" << pg.pg_log.get_log().can_rollback_to; if (pg.last_complete_ondisk != pg.info.last_complete) out << " lcod " << pg.last_complete_ondisk; if (pg.is_primary()) { out << " mlcod " << pg.min_last_complete_ondisk; } out << " " << pg_state_string(pg.get_state()); if (pg.should_send_notify()) out << " NOTIFY"; if (pg.scrubber.must_repair) out << " MUST_REPAIR"; if (pg.scrubber.must_deep_scrub) out << " MUST_DEEP_SCRUB"; if (pg.scrubber.must_scrub) out << " MUST_SCRUB"; //out << " (" << pg.pg_log.get_tail() << "," << pg.pg_log.get_head() << "]"; if (pg.pg_log.get_missing().num_missing()) { out << " m=" << pg.pg_log.get_missing().num_missing(); if (pg.is_primary()) { int unfound = pg.get_num_unfound(); if (unfound) out << " u=" << unfound; } } if (pg.snap_trimq.size()) out << " snaptrimq=" << pg.snap_trimq; out << "]"; return out; } bool PG::can_discard_op(OpRequestRef op) { MOSDOp *m = static_cast(op->get_req()); if (OSD::op_is_discardable(m)) { dout(20) << " discard " << *m << dendl; return true; } if (m->get_map_epoch() < info.history.same_primary_since) { dout(7) << " changed after " << m->get_map_epoch() << ", dropping " << *m << dendl; return true; } if (m->get_map_epoch() < pool.info.last_force_op_resend && m->get_connection()->has_feature(CEPH_FEATURE_OSD_POOLRESEND)) { dout(7) << __func__ << " sent before last_force_op_resend " << pool.info.last_force_op_resend << ", dropping" << *m << dendl; return true; } if ((m->get_flags() & (CEPH_OSD_FLAG_BALANCE_READS | CEPH_OSD_FLAG_LOCALIZE_READS)) && op->may_read() && !(op->may_write() || op->may_cache())) { // balanced reads; any replica will do if (!(is_primary() || is_replica())) { osd->handle_misdirected_op(this, op); return true; } } else { // normal case; must be primary if (!is_primary()) { osd->handle_misdirected_op(this, op); return true; } } if (is_replay()) { if (m->get_version().version > 0) { dout(7) << " queueing replay at " << m->get_version() << " for " << *m << dendl; replay_queue[m->get_version()] = op; op->mark_delayed("waiting for replay"); return true; } } return false; } template bool PG::can_discard_replica_op(OpRequestRef op) { T *m = static_cast(op->get_req()); assert(m->get_header().type == MSGTYPE); /* Mostly, this overlaps with the old_peering_msg * condition. An important exception is pushes * sent by replicas not in the acting set, since * if such a replica goes down it does not cause * a new interval. */ int from = m->get_source().num(); if (get_osdmap()->get_down_at(from) >= m->map_epoch) return true; // same pg? // if pg changes _at all_, we reset and repeer! if (old_peering_msg(m->map_epoch, m->map_epoch)) { dout(10) << "can_discard_replica_op pg changed " << info.history << " after " << m->map_epoch << ", dropping" << dendl; return true; } return false; } bool PG::can_discard_scan(OpRequestRef op) { MOSDPGScan *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_SCAN); if (old_peering_msg(m->map_epoch, m->query_epoch)) { dout(10) << " got old scan, ignoring" << dendl; return true; } return false; } bool PG::can_discard_backfill(OpRequestRef op) { MOSDPGBackfill *m = static_cast(op->get_req()); assert(m->get_header().type == MSG_OSD_PG_BACKFILL); if (old_peering_msg(m->map_epoch, m->query_epoch)) { dout(10) << " got old backfill, ignoring" << dendl; return true; } return false; } bool PG::can_discard_request(OpRequestRef op) { switch (op->get_req()->get_type()) { case CEPH_MSG_OSD_OP: return can_discard_op(op); case MSG_OSD_SUBOP: return can_discard_replica_op(op); case MSG_OSD_PG_PUSH: return can_discard_replica_op(op); case MSG_OSD_PG_PULL: return can_discard_replica_op(op); case MSG_OSD_PG_PUSH_REPLY: return can_discard_replica_op(op); case MSG_OSD_SUBOPREPLY: return can_discard_replica_op(op); case MSG_OSD_EC_WRITE: return can_discard_replica_op(op); case MSG_OSD_EC_WRITE_REPLY: return can_discard_replica_op(op); case MSG_OSD_EC_READ: return can_discard_replica_op(op); case MSG_OSD_EC_READ_REPLY: return can_discard_replica_op(op); case MSG_OSD_PG_SCAN: return can_discard_scan(op); case MSG_OSD_PG_BACKFILL: return can_discard_backfill(op); } return true; } bool PG::split_request(OpRequestRef op, unsigned match, unsigned bits) { unsigned mask = ~((~0)<get_req()->get_type()) { case CEPH_MSG_OSD_OP: return (static_cast(op->get_req())->get_pg().m_seed & mask) == match; } return false; } bool PG::op_must_wait_for_map(OSDMapRef curmap, OpRequestRef op) { switch (op->get_req()->get_type()) { case CEPH_MSG_OSD_OP: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->get_map_epoch()); case MSG_OSD_SUBOP: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_SUBOPREPLY: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_PG_SCAN: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_PG_BACKFILL: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_PG_PUSH: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_PG_PULL: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_PG_PUSH_REPLY: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_EC_WRITE: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_EC_WRITE_REPLY: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_EC_READ: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); case MSG_OSD_EC_READ_REPLY: return !have_same_or_newer_map( curmap, static_cast(op->get_req())->map_epoch); } assert(0); return false; } void PG::take_waiters() { dout(10) << "take_waiters" << dendl; take_op_map_waiters(); for (list::iterator i = peering_waiters.begin(); i != peering_waiters.end(); ++i) osd->queue_for_peering(this); peering_queue.splice(peering_queue.begin(), peering_waiters, peering_waiters.begin(), peering_waiters.end()); } void PG::handle_peering_event(CephPeeringEvtRef evt, RecoveryCtx *rctx) { dout(10) << "handle_peering_event: " << evt->get_desc() << dendl; if (!have_same_or_newer_map(evt->get_epoch_sent())) { dout(10) << "deferring event " << evt->get_desc() << dendl; peering_waiters.push_back(evt); return; } if (old_peering_evt(evt)) return; recovery_state.handle_event(evt, rctx); } void PG::queue_peering_event(CephPeeringEvtRef evt) { if (old_peering_evt(evt)) return; peering_queue.push_back(evt); osd->queue_for_peering(this); } void PG::queue_null(epoch_t msg_epoch, epoch_t query_epoch) { dout(10) << "null" << dendl; queue_peering_event( CephPeeringEvtRef(new CephPeeringEvt(msg_epoch, query_epoch, NullEvt()))); } void PG::queue_flushed(epoch_t e) { dout(10) << "flushed" << dendl; queue_peering_event( CephPeeringEvtRef(new CephPeeringEvt(e, e, FlushedEvt()))); } void PG::queue_query(epoch_t msg_epoch, epoch_t query_epoch, pg_shard_t from, const pg_query_t& q) { dout(10) << "handle_query " << q << " from replica " << from << dendl; queue_peering_event( CephPeeringEvtRef(new CephPeeringEvt(msg_epoch, query_epoch, MQuery(from, q, query_epoch)))); } void PG::handle_advance_map( OSDMapRef osdmap, OSDMapRef lastmap, vector& newup, int up_primary, vector& newacting, int acting_primary, RecoveryCtx *rctx) { assert(lastmap->get_epoch() == osdmap_ref->get_epoch()); assert(lastmap == osdmap_ref); dout(10) << "handle_advance_map " << newup << "/" << newacting << " -- " << up_primary << "/" << acting_primary << dendl; update_osdmap_ref(osdmap); pool.update(osdmap); AdvMap evt( osdmap, lastmap, newup, up_primary, newacting, acting_primary); recovery_state.handle_event(evt, rctx); if (pool.info.last_change == osdmap_ref->get_epoch()) on_pool_change(); } void PG::handle_activate_map(RecoveryCtx *rctx) { dout(10) << "handle_activate_map " << dendl; ActMap evt; recovery_state.handle_event(evt, rctx); if (osdmap_ref->get_epoch() - last_persisted_osdmap_ref->get_epoch() > cct->_conf->osd_pg_epoch_persisted_max_stale) { dout(20) << __func__ << ": Dirtying info: last_persisted is " << last_persisted_osdmap_ref->get_epoch() << " while current is " << osdmap_ref->get_epoch() << dendl; dirty_info = true; } else { dout(20) << __func__ << ": Not dirtying info: last_persisted is " << last_persisted_osdmap_ref->get_epoch() << " while current is " << osdmap_ref->get_epoch() << dendl; } if (osdmap_ref->check_new_blacklist_entries()) check_blacklisted_watchers(); } void PG::handle_loaded(RecoveryCtx *rctx) { dout(10) << "handle_loaded" << dendl; Load evt; recovery_state.handle_event(evt, rctx); } void PG::handle_create(RecoveryCtx *rctx) { dout(10) << "handle_create" << dendl; Initialize evt; recovery_state.handle_event(evt, rctx); ActMap evt2; recovery_state.handle_event(evt2, rctx); } void PG::handle_query_state(Formatter *f) { dout(10) << "handle_query_state" << dendl; QueryState q(f); recovery_state.handle_event(q, 0); } std::ostream& operator<<(std::ostream& oss, const struct PG::PriorSet &prior) { oss << "PriorSet[probe=" << prior.probe << " " << "down=" << prior.down << " " << "blocked_by=" << prior.blocked_by << "]"; return oss; } /*------------ Recovery State Machine----------------*/ #undef dout_prefix #define dout_prefix (*_dout << context< RecoveryMachine >().pg->gen_prefix() \ << "state<" << get_state_name() << ">: ") /*------Crashed-------*/ PG::RecoveryState::Crashed::Crashed(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Crashed") { context< RecoveryMachine >().log_enter(state_name); assert(0 == "we got a bad state machine event"); } /*------Initial-------*/ PG::RecoveryState::Initial::Initial(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Initial") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::Initial::react(const Load& l) { PG *pg = context< RecoveryMachine >().pg; // do we tell someone we're here? pg->send_notify = (!pg->is_primary()); return transit< Reset >(); } boost::statechart::result PG::RecoveryState::Initial::react(const MNotifyRec& notify) { PG *pg = context< RecoveryMachine >().pg; pg->proc_replica_info(notify.from, notify.notify.info); pg->update_heartbeat_peers(); pg->set_last_peering_reset(); return transit< Primary >(); } boost::statechart::result PG::RecoveryState::Initial::react(const MInfoRec& i) { PG *pg = context< RecoveryMachine >().pg; assert(!pg->is_primary()); post_event(i); return transit< Stray >(); } boost::statechart::result PG::RecoveryState::Initial::react(const MLogRec& i) { PG *pg = context< RecoveryMachine >().pg; assert(!pg->is_primary()); post_event(i); return transit< Stray >(); } void PG::RecoveryState::Initial::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_initial_latency, dur); } /*------Started-------*/ PG::RecoveryState::Started::Started(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::Started::react(const IntervalFlush&) { dout(10) << "Ending blocked outgoing recovery messages" << dendl; context< RecoveryMachine >().pg->recovery_state.end_block_outgoing(); return discard_event(); } boost::statechart::result PG::RecoveryState::Started::react(const FlushedEvt&) { PG *pg = context< RecoveryMachine >().pg; pg->on_flushed(); return discard_event(); } boost::statechart::result PG::RecoveryState::Started::react(const AdvMap& advmap) { dout(10) << "Started advmap" << dendl; PG *pg = context< RecoveryMachine >().pg; if (pg->acting_up_affected( advmap.up_primary, advmap.acting_primary, advmap.newup, advmap.newacting) || pg->is_split(advmap.lastmap, advmap.osdmap)) { dout(10) << "up or acting affected, transitioning to Reset" << dendl; post_event(advmap); return transit< Reset >(); } pg->remove_down_peer_info(advmap.osdmap); return discard_event(); } boost::statechart::result PG::RecoveryState::Started::react(const QueryState& q) { q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->close_section(); return discard_event(); } void PG::RecoveryState::Started::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_started_latency, dur); } /*--------Reset---------*/ PG::RecoveryState::Reset::Reset(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Reset") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->flushes_in_progress = 0; pg->set_last_peering_reset(); } boost::statechart::result PG::RecoveryState::Reset::react(const FlushedEvt&) { PG *pg = context< RecoveryMachine >().pg; pg->on_flushed(); return discard_event(); } boost::statechart::result PG::RecoveryState::Reset::react(const IntervalFlush&) { dout(10) << "Ending blocked outgoing recovery messages" << dendl; context< RecoveryMachine >().pg->recovery_state.end_block_outgoing(); return discard_event(); } boost::statechart::result PG::RecoveryState::Reset::react(const AdvMap& advmap) { PG *pg = context< RecoveryMachine >().pg; dout(10) << "Reset advmap" << dendl; // make sure we have past_intervals filled in. hopefully this will happen // _before_ we are active. pg->generate_past_intervals(); if (pg->acting_up_affected( advmap.up_primary, advmap.acting_primary, advmap.newup, advmap.newacting) || pg->is_split(advmap.lastmap, advmap.osdmap)) { dout(10) << "up or acting affected, calling start_peering_interval again" << dendl; pg->start_peering_interval( advmap.lastmap, advmap.newup, advmap.up_primary, advmap.newacting, advmap.acting_primary, context< RecoveryMachine >().get_cur_transaction()); } pg->remove_down_peer_info(advmap.osdmap); return discard_event(); } boost::statechart::result PG::RecoveryState::Reset::react(const ActMap&) { PG *pg = context< RecoveryMachine >().pg; if (pg->should_send_notify() && pg->get_primary().osd >= 0) { context< RecoveryMachine >().send_notify( pg->get_primary(), pg_notify_t( pg->get_primary().shard, pg->pg_whoami.shard, pg->get_osdmap()->get_epoch(), pg->get_osdmap()->get_epoch(), pg->info), pg->past_intervals); } pg->update_heartbeat_peers(); pg->take_waiters(); return transit< Started >(); } boost::statechart::result PG::RecoveryState::Reset::react(const QueryState& q) { q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->close_section(); return discard_event(); } void PG::RecoveryState::Reset::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_reset_latency, dur); } /*-------Start---------*/ PG::RecoveryState::Start::Start(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Start") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; if (pg->is_primary()) { dout(1) << "transitioning to Primary" << dendl; post_event(MakePrimary()); } else { //is_stray dout(1) << "transitioning to Stray" << dendl; post_event(MakeStray()); } } void PG::RecoveryState::Start::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_start_latency, dur); } /*---------Primary--------*/ PG::RecoveryState::Primary::Primary(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; assert(pg->want_acting.empty()); // set CREATING bit until we have peered for the first time. if (pg->info.history.last_epoch_started == 0) pg->state_set(PG_STATE_CREATING); } boost::statechart::result PG::RecoveryState::Primary::react(const MNotifyRec& notevt) { dout(7) << "handle_pg_notify from osd." << notevt.from << dendl; PG *pg = context< RecoveryMachine >().pg; if (pg->peer_info.count(notevt.from) && pg->peer_info[notevt.from].last_update == notevt.notify.info.last_update) { dout(10) << *pg << " got dup osd." << notevt.from << " info " << notevt.notify.info << ", identical to ours" << dendl; } else { pg->proc_replica_info(notevt.from, notevt.notify.info); } return discard_event(); } boost::statechart::result PG::RecoveryState::Primary::react(const ActMap&) { dout(7) << "handle ActMap primary" << dendl; PG *pg = context< RecoveryMachine >().pg; pg->publish_stats_to_osd(); pg->take_waiters(); return discard_event(); } void PG::RecoveryState::Primary::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->want_acting.clear(); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_primary_latency, dur); pg->clear_primary_state(); pg->state_clear(PG_STATE_CREATING); } /*---------Peering--------*/ PG::RecoveryState::Peering::Peering(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Peering") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; assert(!pg->is_active()); assert(!pg->is_peering()); assert(pg->is_primary()); pg->state_set(PG_STATE_PEERING); } boost::statechart::result PG::RecoveryState::Peering::react(const AdvMap& advmap) { PG *pg = context< RecoveryMachine >().pg; dout(10) << "Peering advmap" << dendl; if (prior_set.get()->affected_by_map(advmap.osdmap, pg)) { dout(1) << "Peering, affected_by_map, going to Reset" << dendl; post_event(advmap); return transit< Reset >(); } pg->adjust_need_up_thru(advmap.osdmap); return forward_event(); } boost::statechart::result PG::RecoveryState::Peering::react(const QueryState& q) { PG *pg = context< RecoveryMachine >().pg; q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->open_array_section("past_intervals"); for (map::iterator p = pg->past_intervals.begin(); p != pg->past_intervals.end(); ++p) { q.f->open_object_section("past_interval"); p->second.dump(q.f); q.f->close_section(); } q.f->close_section(); q.f->open_array_section("probing_osds"); for (set::iterator p = prior_set->probe.begin(); p != prior_set->probe.end(); ++p) q.f->dump_stream("osd") << *p; q.f->close_section(); if (prior_set->pg_down) q.f->dump_string("blocked", "peering is blocked due to down osds"); q.f->open_array_section("down_osds_we_would_probe"); for (set::iterator p = prior_set->down.begin(); p != prior_set->down.end(); ++p) q.f->dump_int("osd", *p); q.f->close_section(); q.f->open_array_section("peering_blocked_by"); for (map::iterator p = prior_set->blocked_by.begin(); p != prior_set->blocked_by.end(); ++p) { q.f->open_object_section("osd"); q.f->dump_int("osd", p->first); q.f->dump_int("current_lost_at", p->second); q.f->dump_string("comment", "starting or marking this osd lost may let us proceed"); q.f->close_section(); } q.f->close_section(); q.f->close_section(); return forward_event(); } void PG::RecoveryState::Peering::exit() { dout(10) << "Leaving Peering" << dendl; context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_PEERING); pg->clear_probe_targets(); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_peering_latency, dur); } /*------Backfilling-------*/ PG::RecoveryState::Backfilling::Backfilling(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/Backfilling") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->backfill_reserved = true; pg->osd->queue_for_recovery(pg); pg->state_clear(PG_STATE_BACKFILL_TOOFULL); pg->state_clear(PG_STATE_BACKFILL_WAIT); pg->state_set(PG_STATE_BACKFILL); } boost::statechart::result PG::RecoveryState::Backfilling::react(const RemoteReservationRejected &) { PG *pg = context< RecoveryMachine >().pg; pg->osd->local_reserver.cancel_reservation(pg->info.pgid); pg->state_set(PG_STATE_BACKFILL_TOOFULL); for (set::iterator it = pg->backfill_targets.begin(); it != pg->backfill_targets.end(); ++it) { assert(*it != pg->pg_whoami); ConnectionRef con = pg->osd->get_con_osd_cluster( it->osd, pg->get_osdmap()->get_epoch()); if (con) { if (con->has_feature(CEPH_FEATURE_BACKFILL_RESERVATION)) { pg->osd->send_message_osd_cluster( new MBackfillReserve( MBackfillReserve::REJECT, spg_t(pg->info.pgid.pgid, it->shard), pg->get_osdmap()->get_epoch()), con.get()); } } } pg->osd->recovery_wq.dequeue(pg); pg->waiting_on_backfill.clear(); pg->finish_recovery_op(hobject_t::get_max()); pg->schedule_backfill_full_retry(); return transit(); } void PG::RecoveryState::Backfilling::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->backfill_reserved = false; pg->backfill_reserving = false; pg->state_clear(PG_STATE_BACKFILL); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_backfilling_latency, dur); } /*--WaitRemoteBackfillReserved--*/ PG::RecoveryState::WaitRemoteBackfillReserved::WaitRemoteBackfillReserved(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/WaitRemoteBackfillReserved"), backfill_osd_it(context< Active >().remote_shards_to_reserve_backfill.begin()) { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->state_set(PG_STATE_BACKFILL_WAIT); post_event(RemoteBackfillReserved()); } boost::statechart::result PG::RecoveryState::WaitRemoteBackfillReserved::react(const RemoteBackfillReserved &evt) { PG *pg = context< RecoveryMachine >().pg; if (backfill_osd_it != context< Active >().remote_shards_to_reserve_backfill.end()) { //The primary never backfills itself assert(*backfill_osd_it != pg->pg_whoami); ConnectionRef con = pg->osd->get_con_osd_cluster( backfill_osd_it->osd, pg->get_osdmap()->get_epoch()); if (con) { if (con->has_feature(CEPH_FEATURE_BACKFILL_RESERVATION)) { unsigned priority = pg->is_degraded() ? OSDService::BACKFILL_HIGH : OSDService::BACKFILL_LOW; pg->osd->send_message_osd_cluster( new MBackfillReserve( MBackfillReserve::REQUEST, spg_t(pg->info.pgid.pgid, backfill_osd_it->shard), pg->get_osdmap()->get_epoch(), priority), con.get()); } else { post_event(RemoteBackfillReserved()); } } ++backfill_osd_it; } else { post_event(AllBackfillsReserved()); } return discard_event(); } void PG::RecoveryState::WaitRemoteBackfillReserved::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_waitremotebackfillreserved_latency, dur); } boost::statechart::result PG::RecoveryState::WaitRemoteBackfillReserved::react(const RemoteReservationRejected &evt) { PG *pg = context< RecoveryMachine >().pg; pg->osd->local_reserver.cancel_reservation(pg->info.pgid); // Send REJECT to all previously acquired reservations set::const_iterator it, begin, end, next; begin = context< Active >().remote_shards_to_reserve_backfill.begin(); end = context< Active >().remote_shards_to_reserve_backfill.end(); assert(begin != end); for (next = it = begin, ++next ; next != backfill_osd_it; ++it, ++next) { //The primary never backfills itself assert(*it != pg->pg_whoami); ConnectionRef con = pg->osd->get_con_osd_cluster( it->osd, pg->get_osdmap()->get_epoch()); if (con) { if (con->has_feature(CEPH_FEATURE_BACKFILL_RESERVATION)) { pg->osd->send_message_osd_cluster( new MBackfillReserve( MBackfillReserve::REJECT, spg_t(pg->info.pgid.pgid, it->shard), pg->get_osdmap()->get_epoch()), con.get()); } } } pg->state_clear(PG_STATE_BACKFILL_WAIT); pg->state_set(PG_STATE_BACKFILL_TOOFULL); pg->schedule_backfill_full_retry(); return transit(); } /*--WaitLocalBackfillReserved--*/ PG::RecoveryState::WaitLocalBackfillReserved::WaitLocalBackfillReserved(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/WaitLocalBackfillReserved") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->state_set(PG_STATE_BACKFILL_WAIT); pg->osd->local_reserver.request_reservation( pg->info.pgid, new QueuePeeringEvt( pg, pg->get_osdmap()->get_epoch(), LocalBackfillReserved()), pg->is_degraded() ? OSDService::BACKFILL_HIGH : OSDService::BACKFILL_LOW); } void PG::RecoveryState::WaitLocalBackfillReserved::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_waitlocalbackfillreserved_latency, dur); } /*----NotBackfilling------*/ PG::RecoveryState::NotBackfilling::NotBackfilling(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/NotBackfilling") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::NotBackfilling::react(const RemoteBackfillReserved &evt) { return discard_event(); } boost::statechart::result PG::RecoveryState::NotBackfilling::react(const RemoteReservationRejected &evt) { return discard_event(); } void PG::RecoveryState::NotBackfilling::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_notbackfilling_latency, dur); } /*---RepNotRecovering----*/ PG::RecoveryState::RepNotRecovering::RepNotRecovering(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/ReplicaActive/RepNotRecovering") { context< RecoveryMachine >().log_enter(state_name); } void PG::RecoveryState::RepNotRecovering::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_repnotrecovering_latency, dur); } /*---RepWaitRecoveryReserved--*/ PG::RecoveryState::RepWaitRecoveryReserved::RepWaitRecoveryReserved(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/ReplicaActive/RepWaitRecoveryReserved") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->osd->remote_reserver.request_reservation( pg->info.pgid, new QueuePeeringEvt( pg, pg->get_osdmap()->get_epoch(), RemoteRecoveryReserved()), OSDService::RECOVERY); } boost::statechart::result PG::RecoveryState::RepWaitRecoveryReserved::react(const RemoteRecoveryReserved &evt) { PG *pg = context< RecoveryMachine >().pg; pg->osd->send_message_osd_cluster( pg->primary.osd, new MRecoveryReserve( MRecoveryReserve::GRANT, spg_t(pg->info.pgid.pgid, pg->primary.shard), pg->get_osdmap()->get_epoch()), pg->get_osdmap()->get_epoch()); return transit(); } void PG::RecoveryState::RepWaitRecoveryReserved::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_repwaitrecoveryreserved_latency, dur); } /*-RepWaitBackfillReserved*/ PG::RecoveryState::RepWaitBackfillReserved::RepWaitBackfillReserved(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/ReplicaActive/RepWaitBackfillReserved") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::RepNotRecovering::react(const RequestBackfillPrio &evt) { PG *pg = context< RecoveryMachine >().pg; double ratio, max_ratio; if (g_conf->osd_debug_reject_backfill_probability > 0 && (rand()%1000 < (g_conf->osd_debug_reject_backfill_probability*1000.0))) { dout(10) << "backfill reservation rejected: failure injection" << dendl; post_event(RemoteReservationRejected()); } else if (pg->osd->too_full_for_backfill(&ratio, &max_ratio) && !pg->cct->_conf->osd_debug_skip_full_check_in_backfill_reservation) { dout(10) << "backfill reservation rejected: full ratio is " << ratio << ", which is greater than max allowed ratio " << max_ratio << dendl; post_event(RemoteReservationRejected()); } else { pg->osd->remote_reserver.request_reservation( pg->info.pgid, new QueuePeeringEvt( pg, pg->get_osdmap()->get_epoch(), RemoteBackfillReserved()), evt.priority); } return transit(); } void PG::RecoveryState::RepWaitBackfillReserved::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_repwaitbackfillreserved_latency, dur); } boost::statechart::result PG::RecoveryState::RepWaitBackfillReserved::react(const RemoteBackfillReserved &evt) { PG *pg = context< RecoveryMachine >().pg; double ratio, max_ratio; if (g_conf->osd_debug_reject_backfill_probability > 0 && (rand()%1000 < (g_conf->osd_debug_reject_backfill_probability*1000.0))) { dout(10) << "backfill reservation rejected after reservation: " << "failure injection" << dendl; pg->osd->remote_reserver.cancel_reservation(pg->info.pgid); post_event(RemoteReservationRejected()); return discard_event(); } else if (pg->osd->too_full_for_backfill(&ratio, &max_ratio) && !pg->cct->_conf->osd_debug_skip_full_check_in_backfill_reservation) { dout(10) << "backfill reservation rejected after reservation: full ratio is " << ratio << ", which is greater than max allowed ratio " << max_ratio << dendl; pg->osd->remote_reserver.cancel_reservation(pg->info.pgid); post_event(RemoteReservationRejected()); return discard_event(); } else { pg->osd->send_message_osd_cluster( pg->primary.osd, new MBackfillReserve( MBackfillReserve::GRANT, spg_t(pg->info.pgid.pgid, pg->primary.shard), pg->get_osdmap()->get_epoch()), pg->get_osdmap()->get_epoch()); return transit(); } } boost::statechart::result PG::RecoveryState::RepWaitBackfillReserved::react(const RemoteReservationRejected &evt) { PG *pg = context< RecoveryMachine >().pg; pg->reject_reservation(); return transit(); } /*---RepRecovering-------*/ PG::RecoveryState::RepRecovering::RepRecovering(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/ReplicaActive/RepRecovering") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::RepRecovering::react(const BackfillTooFull &) { PG *pg = context< RecoveryMachine >().pg; pg->reject_reservation(); return discard_event(); } void PG::RecoveryState::RepRecovering::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->osd->remote_reserver.cancel_reservation(pg->info.pgid); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_RepRecovering_latency, dur); } /*------Activating--------*/ PG::RecoveryState::Activating::Activating(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/Activating") { context< RecoveryMachine >().log_enter(state_name); } void PG::RecoveryState::Activating::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_activating_latency, dur); } PG::RecoveryState::WaitLocalRecoveryReserved::WaitLocalRecoveryReserved(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/WaitLocalRecoveryReserved") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->state_set(PG_STATE_RECOVERY_WAIT); pg->osd->local_reserver.request_reservation( pg->info.pgid, new QueuePeeringEvt( pg, pg->get_osdmap()->get_epoch(), LocalRecoveryReserved()), OSDService::RECOVERY); } void PG::RecoveryState::WaitLocalRecoveryReserved::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_waitlocalrecoveryreserved_latency, dur); } PG::RecoveryState::WaitRemoteRecoveryReserved::WaitRemoteRecoveryReserved(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/WaitRemoteRecoveryReserved"), remote_recovery_reservation_it(context< Active >().remote_shards_to_reserve_recovery.begin()) { context< RecoveryMachine >().log_enter(state_name); post_event(RemoteRecoveryReserved()); } boost::statechart::result PG::RecoveryState::WaitRemoteRecoveryReserved::react(const RemoteRecoveryReserved &evt) { PG *pg = context< RecoveryMachine >().pg; if (remote_recovery_reservation_it != context< Active >().remote_shards_to_reserve_recovery.end()) { assert(*remote_recovery_reservation_it != pg->pg_whoami); } if (remote_recovery_reservation_it != context< Active >().remote_shards_to_reserve_recovery.end()) { ConnectionRef con = pg->osd->get_con_osd_cluster( remote_recovery_reservation_it->osd, pg->get_osdmap()->get_epoch()); if (con) { if (con->has_feature(CEPH_FEATURE_RECOVERY_RESERVATION)) { pg->osd->send_message_osd_cluster( new MRecoveryReserve( MRecoveryReserve::REQUEST, spg_t(pg->info.pgid.pgid, remote_recovery_reservation_it->shard), pg->get_osdmap()->get_epoch()), con.get()); } else { post_event(RemoteRecoveryReserved()); } } ++remote_recovery_reservation_it; } else { post_event(AllRemotesReserved()); } return discard_event(); } void PG::RecoveryState::WaitRemoteRecoveryReserved::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_waitremoterecoveryreserved_latency, dur); } PG::RecoveryState::Recovering::Recovering(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/Recovering") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_RECOVERY_WAIT); pg->state_set(PG_STATE_RECOVERING); pg->osd->queue_for_recovery(pg); } void PG::RecoveryState::Recovering::release_reservations() { PG *pg = context< RecoveryMachine >().pg; assert(!pg->pg_log.get_missing().have_missing()); // release remote reservations for (set::const_iterator i = context< Active >().remote_shards_to_reserve_recovery.begin(); i != context< Active >().remote_shards_to_reserve_recovery.end(); ++i) { if (*i == pg->pg_whoami) // skip myself continue; ConnectionRef con = pg->osd->get_con_osd_cluster( i->osd, pg->get_osdmap()->get_epoch()); if (con) { if (con->has_feature(CEPH_FEATURE_RECOVERY_RESERVATION)) { pg->osd->send_message_osd_cluster( new MRecoveryReserve( MRecoveryReserve::RELEASE, spg_t(pg->info.pgid.pgid, i->shard), pg->get_osdmap()->get_epoch()), con.get()); } } } } boost::statechart::result PG::RecoveryState::Recovering::react(const AllReplicasRecovered &evt) { PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_RECOVERING); release_reservations(); return transit(); } boost::statechart::result PG::RecoveryState::Recovering::react(const RequestBackfill &evt) { PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_RECOVERING); release_reservations(); return transit(); } void PG::RecoveryState::Recovering::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_recovering_latency, dur); } PG::RecoveryState::Recovered::Recovered(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/Recovered") { pg_shard_t auth_log_shard; context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->osd->local_reserver.cancel_reservation(pg->info.pgid); // if we finished backfill, all acting are active; recheck if // DEGRADED is appropriate. assert(!pg->actingbackfill.empty()); if (pg->get_osdmap()->get_pg_size(pg->info.pgid.pgid) <= pg->actingbackfill.size()) pg->state_clear(PG_STATE_DEGRADED); // adjust acting set? (e.g. because backfill completed...) if (pg->acting != pg->up && !pg->choose_acting(auth_log_shard)) assert(pg->want_acting.size()); assert(!pg->needs_recovery()); if (context< Active >().all_replicas_activated) post_event(GoClean()); } void PG::RecoveryState::Recovered::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_recovered_latency, dur); } PG::RecoveryState::Clean::Clean(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active/Clean") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; if (pg->info.last_complete != pg->info.last_update) { assert(0); } pg->finish_recovery(*context< RecoveryMachine >().get_on_safe_context_list()); pg->mark_clean(); pg->share_pg_info(); pg->publish_stats_to_osd(); } void PG::RecoveryState::Clean::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_CLEAN); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_clean_latency, dur); } template set unique_osd_shard_set(const pg_shard_t & skip, const T &in) { set osds_found; set out; for (typename T::const_iterator i = in.begin(); i != in.end(); ++i) { if (*i != skip && !osds_found.count(i->osd)) { osds_found.insert(i->osd); out.insert(*i); } } return out; } /*---------Active---------*/ PG::RecoveryState::Active::Active(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Active"), remote_shards_to_reserve_recovery( unique_osd_shard_set( context< RecoveryMachine >().pg->pg_whoami, context< RecoveryMachine >().pg->actingbackfill)), remote_shards_to_reserve_backfill( unique_osd_shard_set( context< RecoveryMachine >().pg->pg_whoami, context< RecoveryMachine >().pg->backfill_targets)), all_replicas_activated(false) { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; assert(!pg->backfill_reserving); assert(!pg->backfill_reserved); assert(pg->is_primary()); dout(10) << "In Active, about to call activate" << dendl; pg->start_flush( context< RecoveryMachine >().get_cur_transaction(), context< RecoveryMachine >().get_on_applied_context_list(), context< RecoveryMachine >().get_on_safe_context_list()); pg->activate(*context< RecoveryMachine >().get_cur_transaction(), pg->get_osdmap()->get_epoch(), *context< RecoveryMachine >().get_on_safe_context_list(), *context< RecoveryMachine >().get_query_map(), context< RecoveryMachine >().get_info_map(), context< RecoveryMachine >().get_recovery_ctx()); dout(10) << "Activate Finished" << dendl; } boost::statechart::result PG::RecoveryState::Active::react(const AdvMap& advmap) { PG *pg = context< RecoveryMachine >().pg; dout(10) << "Active advmap" << dendl; if (!pg->pool.newly_removed_snaps.empty()) { pg->snap_trimq.union_of(pg->pool.newly_removed_snaps); dout(10) << *pg << " snap_trimq now " << pg->snap_trimq << dendl; pg->dirty_info = true; pg->dirty_big_info = true; } for (size_t i = 0; i < pg->want_acting.size(); i++) { int osd = pg->want_acting[i]; if (!advmap.osdmap->is_up(osd)) { pg_shard_t osd_with_shard(osd, shard_id_t(i)); assert(pg->is_acting(osd_with_shard) || pg->is_up(osd_with_shard)); } } /* Check for changes in pool size (if the acting set changed as a result, * this does not matter) */ if (advmap.lastmap->get_pg_size(pg->info.pgid.pgid) != pg->get_osdmap()->get_pg_size(pg->info.pgid.pgid)) { if (pg->get_osdmap()->get_pg_size(pg->info.pgid.pgid) <= pg->actingset.size()) pg->state_clear(PG_STATE_DEGRADED); else pg->state_set(PG_STATE_DEGRADED); pg->publish_stats_to_osd(); // degraded may have changed } // if we haven't reported our PG stats in a long time, do so now. if (pg->info.stats.reported_epoch + pg->cct->_conf->osd_pg_stat_report_interval_max < advmap.osdmap->get_epoch()) { dout(20) << "reporting stats to osd after " << (advmap.osdmap->get_epoch() - pg->info.stats.reported_epoch) << " epochs" << dendl; pg->publish_stats_to_osd(); } return forward_event(); } boost::statechart::result PG::RecoveryState::Active::react(const ActMap&) { PG *pg = context< RecoveryMachine >().pg; dout(10) << "Active: handling ActMap" << dendl; assert(pg->is_primary()); if (pg->have_unfound()) { // object may have become unfound pg->discover_all_missing(*context< RecoveryMachine >().get_query_map()); } if (pg->cct->_conf->osd_check_for_log_corruption) pg->check_log_for_corruption(pg->osd->store); int unfound = pg->missing_loc.num_unfound(); if (unfound > 0 && pg->all_unfound_are_queried_or_lost(pg->get_osdmap())) { if (pg->cct->_conf->osd_auto_mark_unfound_lost) { pg->osd->clog.error() << pg->info.pgid << " has " << unfound << " objects unfound and apparently lost, would automatically marking lost but NOT IMPLEMENTED\n"; //pg->mark_all_unfound_lost(*context< RecoveryMachine >().get_cur_transaction()); } else pg->osd->clog.error() << pg->info.pgid << " has " << unfound << " objects unfound and apparently lost\n"; } if (!pg->snap_trimq.empty() && pg->is_clean()) { dout(10) << "Active: queuing snap trim" << dendl; pg->queue_snap_trim(); } if (!pg->is_clean() && !pg->get_osdmap()->test_flag(CEPH_OSDMAP_NOBACKFILL)) { pg->osd->queue_for_recovery(pg); } return forward_event(); } boost::statechart::result PG::RecoveryState::Active::react(const MNotifyRec& notevt) { PG *pg = context< RecoveryMachine >().pg; assert(pg->is_primary()); if (pg->peer_info.count(notevt.from)) { dout(10) << "Active: got notify from " << notevt.from << ", already have info from that osd, ignoring" << dendl; } else if (pg->peer_purged.count(notevt.from)) { dout(10) << "Active: got notify from " << notevt.from << ", already purged that peer, ignoring" << dendl; } else { dout(10) << "Active: got notify from " << notevt.from << ", calling proc_replica_info and discover_all_missing" << dendl; pg->proc_replica_info(notevt.from, notevt.notify.info); if (pg->have_unfound()) { pg->discover_all_missing(*context< RecoveryMachine >().get_query_map()); } } return discard_event(); } boost::statechart::result PG::RecoveryState::Active::react(const MInfoRec& infoevt) { PG *pg = context< RecoveryMachine >().pg; assert(pg->is_primary()); assert(!pg->actingbackfill.empty()); // don't update history (yet) if we are active and primary; the replica // may be telling us they have activated (and committed) but we can't // share that until _everyone_ does the same. if (pg->is_actingbackfill(infoevt.from)) { assert(pg->info.history.last_epoch_started < pg->info.history.same_interval_since); assert(infoevt.info.history.last_epoch_started >= pg->info.history.same_interval_since); dout(10) << " peer osd." << infoevt.from << " activated and committed" << dendl; pg->peer_activated.insert(infoevt.from); if (pg->peer_activated.size() == pg->actingbackfill.size()) { pg->all_activated_and_committed(); } } return discard_event(); } boost::statechart::result PG::RecoveryState::Active::react(const MLogRec& logevt) { dout(10) << "searching osd." << logevt.from << " log for unfound items" << dendl; PG *pg = context< RecoveryMachine >().pg; pg->proc_replica_log( *context().get_cur_transaction(), logevt.msg->info, logevt.msg->log, logevt.msg->missing, logevt.from); bool got_missing = pg->search_for_missing( pg->peer_info[logevt.from], pg->peer_missing[logevt.from], logevt.from, context< RecoveryMachine >().get_recovery_ctx()); if (got_missing) pg->osd->queue_for_recovery(pg); return discard_event(); } boost::statechart::result PG::RecoveryState::Active::react(const QueryState& q) { PG *pg = context< RecoveryMachine >().pg; q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; { q.f->open_array_section("might_have_unfound"); for (set::iterator p = pg->might_have_unfound.begin(); p != pg->might_have_unfound.end(); ++p) { q.f->open_object_section("osd"); q.f->dump_stream("osd") << *p; if (pg->peer_missing.count(*p)) { q.f->dump_string("status", "already probed"); } else if (pg->peer_missing_requested.count(*p)) { q.f->dump_string("status", "querying"); } else if (!pg->get_osdmap()->is_up(p->osd)) { q.f->dump_string("status", "osd is down"); } else { q.f->dump_string("status", "not queried"); } q.f->close_section(); } q.f->close_section(); } { q.f->open_object_section("recovery_progress"); pg->dump_recovery_info(q.f); q.f->close_section(); } { q.f->open_object_section("scrub"); q.f->dump_stream("scrubber.epoch_start") << pg->scrubber.epoch_start; q.f->dump_int("scrubber.active", pg->scrubber.active); q.f->dump_int("scrubber.block_writes", pg->scrubber.block_writes); q.f->dump_int("scrubber.finalizing", pg->scrubber.finalizing); q.f->dump_int("scrubber.waiting_on", pg->scrubber.waiting_on); { q.f->open_array_section("scrubber.waiting_on_whom"); for (set::iterator p = pg->scrubber.waiting_on_whom.begin(); p != pg->scrubber.waiting_on_whom.end(); ++p) { q.f->dump_stream("shard") << *p; } q.f->close_section(); } q.f->close_section(); } q.f->close_section(); return forward_event(); } boost::statechart::result PG::RecoveryState::Active::react(const AllReplicasActivated &evt) { PG *pg = context< RecoveryMachine >().pg; all_replicas_activated = true; pg->state_set(PG_STATE_ACTIVE); pg->check_local(); // waiters if (!pg->is_replay() && pg->flushes_in_progress == 0) { pg->requeue_ops(pg->waiting_for_active); } pg->on_activate(); return discard_event(); } void PG::RecoveryState::Active::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->osd->local_reserver.cancel_reservation(pg->info.pgid); pg->backfill_reserved = false; pg->backfill_reserving = false; pg->state_clear(PG_STATE_DEGRADED); pg->state_clear(PG_STATE_BACKFILL_TOOFULL); pg->state_clear(PG_STATE_BACKFILL_WAIT); pg->state_clear(PG_STATE_RECOVERY_WAIT); pg->state_clear(PG_STATE_REPLAY); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_active_latency, dur); pg->agent_stop(); } /*------ReplicaActive-----*/ PG::RecoveryState::ReplicaActive::ReplicaActive(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/ReplicaActive") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->start_flush( context< RecoveryMachine >().get_cur_transaction(), context< RecoveryMachine >().get_on_applied_context_list(), context< RecoveryMachine >().get_on_safe_context_list()); } boost::statechart::result PG::RecoveryState::ReplicaActive::react( const Activate& actevt) { dout(10) << "In ReplicaActive, about to call activate" << dendl; PG *pg = context< RecoveryMachine >().pg; map > query_map; pg->activate(*context< RecoveryMachine >().get_cur_transaction(), actevt.query_epoch, *context< RecoveryMachine >().get_on_safe_context_list(), query_map, NULL, NULL); dout(10) << "Activate Finished" << dendl; return discard_event(); } boost::statechart::result PG::RecoveryState::ReplicaActive::react(const MInfoRec& infoevt) { PG *pg = context< RecoveryMachine >().pg; pg->proc_primary_info(*context().get_cur_transaction(), infoevt.info); return discard_event(); } boost::statechart::result PG::RecoveryState::ReplicaActive::react(const MLogRec& logevt) { PG *pg = context< RecoveryMachine >().pg; dout(10) << "received log from " << logevt.from << dendl; ObjectStore::Transaction* t = context().get_cur_transaction(); pg->merge_log(*t,logevt.msg->info, logevt.msg->log, logevt.from); assert(pg->pg_log.get_head() == pg->info.last_update); return discard_event(); } boost::statechart::result PG::RecoveryState::ReplicaActive::react(const ActMap&) { PG *pg = context< RecoveryMachine >().pg; if (pg->should_send_notify() && pg->get_primary().osd >= 0) { context< RecoveryMachine >().send_notify( pg->get_primary(), pg_notify_t( pg->get_primary().shard, pg->pg_whoami.shard, pg->get_osdmap()->get_epoch(), pg->get_osdmap()->get_epoch(), pg->info), pg->past_intervals); } pg->take_waiters(); return discard_event(); } boost::statechart::result PG::RecoveryState::ReplicaActive::react(const MQuery& query) { PG *pg = context< RecoveryMachine >().pg; if (query.query.type == pg_query_t::MISSING) { pg->update_history_from_master(query.query.history); pg->fulfill_log(query.from, query.query, query.query_epoch); } // else: from prior to activation, safe to ignore return discard_event(); } boost::statechart::result PG::RecoveryState::ReplicaActive::react(const QueryState& q) { PG *pg = context< RecoveryMachine >().pg; q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->dump_int("scrubber.finalizing", pg->scrubber.finalizing); q.f->close_section(); return forward_event(); } void PG::RecoveryState::ReplicaActive::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->osd->remote_reserver.cancel_reservation(pg->info.pgid); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_replicaactive_latency, dur); } /*-------Stray---*/ PG::RecoveryState::Stray::Stray(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Stray") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; assert(!pg->is_active()); assert(!pg->is_peering()); assert(!pg->is_primary()); pg->start_flush( context< RecoveryMachine >().get_cur_transaction(), context< RecoveryMachine >().get_on_applied_context_list(), context< RecoveryMachine >().get_on_safe_context_list()); } boost::statechart::result PG::RecoveryState::Stray::react(const MLogRec& logevt) { PG *pg = context< RecoveryMachine >().pg; MOSDPGLog *msg = logevt.msg.get(); dout(10) << "got info+log from osd." << logevt.from << " " << msg->info << " " << msg->log << dendl; ObjectStore::Transaction* t = context().get_cur_transaction(); if (msg->info.last_backfill == hobject_t()) { // restart backfill pg->unreg_next_scrub(); pg->info = msg->info; pg->reg_next_scrub(); pg->dirty_info = true; pg->dirty_big_info = true; // maybe. PGLogEntryHandler rollbacker; pg->pg_log.claim_log_and_clear_rollback_info(msg->log, &rollbacker); rollbacker.apply(pg, t); pg->pg_log.reset_backfill(); } else { pg->merge_log(*t, msg->info, msg->log, logevt.from); } assert(pg->pg_log.get_head() == pg->info.last_update); post_event(Activate(logevt.msg->get_epoch())); return transit(); } boost::statechart::result PG::RecoveryState::Stray::react(const MInfoRec& infoevt) { PG *pg = context< RecoveryMachine >().pg; dout(10) << "got info from osd." << infoevt.from << " " << infoevt.info << dendl; if (pg->info.last_update > infoevt.info.last_update) { // rewind divergent log entries ObjectStore::Transaction* t = context().get_cur_transaction(); pg->rewind_divergent_log(*t, infoevt.info.last_update); pg->info.stats = infoevt.info.stats; pg->info.hit_set = infoevt.info.hit_set; } assert(infoevt.info.last_update == pg->info.last_update); assert(pg->pg_log.get_head() == pg->info.last_update); post_event(Activate(infoevt.msg_epoch)); return transit(); } boost::statechart::result PG::RecoveryState::Stray::react(const MQuery& query) { PG *pg = context< RecoveryMachine >().pg; if (query.query.type == pg_query_t::INFO) { pair notify_info; pg->update_history_from_master(query.query.history); pg->fulfill_info(query.from, query.query, notify_info); context< RecoveryMachine >().send_notify( notify_info.first, pg_notify_t( notify_info.first.shard, pg->pg_whoami.shard, query.query_epoch, pg->get_osdmap()->get_epoch(), notify_info.second), pg->past_intervals); } else { pg->fulfill_log(query.from, query.query, query.query_epoch); } return discard_event(); } boost::statechart::result PG::RecoveryState::Stray::react(const ActMap&) { PG *pg = context< RecoveryMachine >().pg; if (pg->should_send_notify() && pg->get_primary().osd >= 0) { context< RecoveryMachine >().send_notify( pg->get_primary(), pg_notify_t( pg->get_primary().shard, pg->pg_whoami.shard, pg->get_osdmap()->get_epoch(), pg->get_osdmap()->get_epoch(), pg->info), pg->past_intervals); } pg->take_waiters(); return discard_event(); } void PG::RecoveryState::Stray::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_stray_latency, dur); } /*--------GetInfo---------*/ PG::RecoveryState::GetInfo::GetInfo(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Peering/GetInfo") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->generate_past_intervals(); auto_ptr &prior_set = context< Peering >().prior_set; if (!prior_set.get()) pg->build_prior(prior_set); pg->publish_stats_to_osd(); pg->reset_peer_features(); get_infos(); if (peer_info_requested.empty() && !prior_set->pg_down) { post_event(GotInfo()); } } void PG::RecoveryState::GetInfo::get_infos() { PG *pg = context< RecoveryMachine >().pg; auto_ptr &prior_set = context< Peering >().prior_set; for (set::const_iterator it = prior_set->probe.begin(); it != prior_set->probe.end(); ++it) { pg_shard_t peer = *it; if (peer == pg->pg_whoami) { continue; } if (pg->peer_info.count(peer)) { dout(10) << " have osd." << peer << " info " << pg->peer_info[peer] << dendl; continue; } if (peer_info_requested.count(peer)) { dout(10) << " already requested info from osd." << peer << dendl; } else if (!pg->get_osdmap()->is_up(peer.osd)) { dout(10) << " not querying info from down osd." << peer << dendl; } else { dout(10) << " querying info from osd." << peer << dendl; context< RecoveryMachine >().send_query( peer, pg_query_t(pg_query_t::INFO, it->shard, pg->pg_whoami.shard, pg->info.history, pg->get_osdmap()->get_epoch())); peer_info_requested.insert(peer); } } } boost::statechart::result PG::RecoveryState::GetInfo::react(const MNotifyRec& infoevt) { set::iterator p = peer_info_requested.find(infoevt.from); if (p != peer_info_requested.end()) peer_info_requested.erase(p); PG *pg = context< RecoveryMachine >().pg; epoch_t old_start = pg->info.history.last_epoch_started; if (pg->proc_replica_info(infoevt.from, infoevt.notify.info)) { // we got something new ... auto_ptr &prior_set = context< Peering >().prior_set; if (old_start < pg->info.history.last_epoch_started) { dout(10) << " last_epoch_started moved forward, rebuilding prior" << dendl; pg->build_prior(prior_set); // filter out any osds that got dropped from the probe set from // peer_info_requested. this is less expensive than restarting // peering (which would re-probe everyone). set::iterator p = peer_info_requested.begin(); while (p != peer_info_requested.end()) { if (prior_set->probe.count(*p) == 0) { dout(20) << " dropping osd." << *p << " from info_requested, no longer in probe set" << dendl; peer_info_requested.erase(p++); } else { ++p; } } get_infos(); } dout(20) << "Adding osd: " << infoevt.from.osd << " features: " << hex << infoevt.features << dec << dendl; pg->apply_peer_features(infoevt.features); // are we done getting everything? if (peer_info_requested.empty() && !prior_set->pg_down) { /* * make sure we have at least one !incomplete() osd from the * last rw interval. the incomplete (backfilling) replicas * get a copy of the log, but they don't get all the object * updates, so they are insufficient to recover changes during * that interval. */ if (pg->info.history.last_epoch_started) { for (map::reverse_iterator p = pg->past_intervals.rbegin(); p != pg->past_intervals.rend(); ++p) { if (p->first < pg->info.history.last_epoch_started) break; if (!p->second.maybe_went_rw) continue; pg_interval_t& interval = p->second; dout(10) << " last maybe_went_rw interval was " << interval << dendl; OSDMapRef osdmap = pg->get_osdmap(); /* * this mirrors the PriorSet calculation: we wait if we * don't have an up (AND !incomplete) node AND there are * nodes down that might be usable. */ bool any_up_complete_now = false; bool any_down_now = false; for (unsigned i=0; ipool.info.ec_pool() ? i : ghobject_t::NO_SHARD); if (!osdmap->exists(o) || osdmap->get_info(o).lost_at > interval.first) continue; // dne or lost if (osdmap->is_up(o)) { pg_info_t *pinfo; if (so == pg->pg_whoami) { pinfo = &pg->info; } else { assert(pg->peer_info.count(so)); pinfo = &pg->peer_info[so]; } if (!pinfo->is_incomplete()) any_up_complete_now = true; } else { any_down_now = true; } } if (!any_up_complete_now && any_down_now) { dout(10) << " no osds up+complete from interval " << interval << dendl; pg->state_set(PG_STATE_DOWN); return discard_event(); } break; } } dout(20) << "Common features: " << hex << pg->get_min_peer_features() << dec << dendl; post_event(GotInfo()); } } return discard_event(); } boost::statechart::result PG::RecoveryState::GetInfo::react(const QueryState& q) { PG *pg = context< RecoveryMachine >().pg; q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->open_array_section("requested_info_from"); for (set::iterator p = peer_info_requested.begin(); p != peer_info_requested.end(); ++p) { q.f->open_object_section("osd"); q.f->dump_stream("osd") << *p; if (pg->peer_info.count(*p)) { q.f->open_object_section("got_info"); pg->peer_info[*p].dump(q.f); q.f->close_section(); } q.f->close_section(); } q.f->close_section(); q.f->close_section(); return forward_event(); } void PG::RecoveryState::GetInfo::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_getinfo_latency, dur); } /*------GetLog------------*/ PG::RecoveryState::GetLog::GetLog(my_context ctx) : my_base(ctx), NamedState( context< RecoveryMachine >().pg->cct, "Started/Primary/Peering/GetLog"), msg(0) { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; // adjust acting? if (!pg->choose_acting(auth_log_shard)) { if (!pg->want_acting.empty()) { post_event(NeedActingChange()); } else { post_event(IsIncomplete()); } return; } // am i the best? if (auth_log_shard == pg->pg_whoami) { post_event(GotLog()); return; } const pg_info_t& best = pg->peer_info[auth_log_shard]; // am i broken? if (pg->info.last_update < best.log_tail) { dout(10) << " not contiguous with osd." << auth_log_shard << ", down" << dendl; post_event(IsIncomplete()); return; } // how much log to request? eversion_t request_log_from = pg->info.last_update; assert(!pg->actingbackfill.empty()); for (set::iterator p = pg->actingbackfill.begin(); p != pg->actingbackfill.end(); ++p) { if (*p == pg->pg_whoami) continue; pg_info_t& ri = pg->peer_info[*p]; if (ri.last_update >= best.log_tail && ri.last_update < request_log_from) request_log_from = ri.last_update; } // how much? dout(10) << " requesting log from osd." << auth_log_shard << dendl; context().send_query( auth_log_shard, pg_query_t( pg_query_t::LOG, auth_log_shard.shard, pg->pg_whoami.shard, request_log_from, pg->info.history, pg->get_osdmap()->get_epoch())); } boost::statechart::result PG::RecoveryState::GetLog::react(const AdvMap& advmap) { // make sure our log source didn't go down. we need to check // explicitly because it may not be part of the prior set, which // means the Peering state check won't catch it going down. if (!advmap.osdmap->is_up(auth_log_shard.osd)) { dout(10) << "GetLog: auth_log_shard osd." << auth_log_shard.osd << " went down" << dendl; post_event(advmap); return transit< Reset >(); } // let the Peering state do its checks. return forward_event(); } boost::statechart::result PG::RecoveryState::GetLog::react(const MLogRec& logevt) { assert(!msg); if (logevt.from != auth_log_shard) { dout(10) << "GetLog: discarding log from " << "non-auth_log_shard osd." << logevt.from << dendl; return discard_event(); } dout(10) << "GetLog: received master log from osd" << logevt.from << dendl; msg = logevt.msg; post_event(GotLog()); return discard_event(); } boost::statechart::result PG::RecoveryState::GetLog::react(const GotLog&) { dout(10) << "leaving GetLog" << dendl; PG *pg = context< RecoveryMachine >().pg; if (msg) { dout(10) << "processing master log" << dendl; pg->proc_master_log(*context().get_cur_transaction(), msg->info, msg->log, msg->missing, auth_log_shard); } pg->start_flush( context< RecoveryMachine >().get_cur_transaction(), context< RecoveryMachine >().get_on_applied_context_list(), context< RecoveryMachine >().get_on_safe_context_list()); return transit< GetMissing >(); } boost::statechart::result PG::RecoveryState::GetLog::react(const QueryState& q) { q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->dump_stream("auth_log_shard") << auth_log_shard; q.f->close_section(); return forward_event(); } void PG::RecoveryState::GetLog::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_getlog_latency, dur); } /*------WaitActingChange--------*/ PG::RecoveryState::WaitActingChange::WaitActingChange(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Peering/WaitActingChange") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::WaitActingChange::react(const AdvMap& advmap) { PG *pg = context< RecoveryMachine >().pg; OSDMapRef osdmap = advmap.osdmap; dout(10) << "verifying no want_acting " << pg->want_acting << " targets didn't go down" << dendl; for (vector::iterator p = pg->want_acting.begin(); p != pg->want_acting.end(); ++p) { if (!osdmap->is_up(*p)) { dout(10) << " want_acting target osd." << *p << " went down, resetting" << dendl; post_event(advmap); return transit< Reset >(); } } return forward_event(); } boost::statechart::result PG::RecoveryState::WaitActingChange::react(const MLogRec& logevt) { dout(10) << "In WaitActingChange, ignoring MLocRec" << dendl; return discard_event(); } boost::statechart::result PG::RecoveryState::WaitActingChange::react(const MInfoRec& evt) { dout(10) << "In WaitActingChange, ignoring MInfoRec" << dendl; return discard_event(); } boost::statechart::result PG::RecoveryState::WaitActingChange::react(const MNotifyRec& evt) { dout(10) << "In WaitActingChange, ignoring MNotifyRec" << dendl; return discard_event(); } boost::statechart::result PG::RecoveryState::WaitActingChange::react(const QueryState& q) { q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->dump_string("comment", "waiting for pg acting set to change"); q.f->close_section(); return forward_event(); } void PG::RecoveryState::WaitActingChange::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_waitactingchange_latency, dur); } /*------Incomplete--------*/ PG::RecoveryState::Incomplete::Incomplete(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Peering/Incomplete") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_PEERING); pg->state_set(PG_STATE_INCOMPLETE); pg->publish_stats_to_osd(); } boost::statechart::result PG::RecoveryState::Incomplete::react(const AdvMap &advmap) { PG *pg = context< RecoveryMachine >().pg; int64_t poolnum = pg->info.pgid.pool(); // Reset if min_size changed, pg might now be able to go active if (advmap.lastmap->get_pools().find(poolnum)->second.min_size != advmap.osdmap->get_pools().find(poolnum)->second.min_size) { post_event(advmap); return transit< Reset >(); } return forward_event(); } boost::statechart::result PG::RecoveryState::Incomplete::react(const MNotifyRec& notevt) { dout(7) << "handle_pg_notify from osd." << notevt.from << dendl; PG *pg = context< RecoveryMachine >().pg; if (pg->peer_info.count(notevt.from) && pg->peer_info[notevt.from].last_update == notevt.notify.info.last_update) { dout(10) << *pg << " got dup osd." << notevt.from << " info " << notevt.notify.info << ", identical to ours" << dendl; return discard_event(); } else { pg->proc_replica_info(notevt.from, notevt.notify.info); // try again! return transit< GetLog >(); } } void PG::RecoveryState::Incomplete::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; pg->state_clear(PG_STATE_INCOMPLETE); utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_incomplete_latency, dur); } /*------GetMissing--------*/ PG::RecoveryState::GetMissing::GetMissing(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Peering/GetMissing") { context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; assert(!pg->actingbackfill.empty()); for (set::iterator i = pg->actingbackfill.begin(); i != pg->actingbackfill.end(); ++i) { if (*i == pg->get_primary()) continue; const pg_info_t& pi = pg->peer_info[*i]; if (pi.is_empty()) continue; // no pg data, nothing divergent if (pi.last_update < pg->pg_log.get_tail()) { dout(10) << " osd." << *i << " is not contiguous, will restart backfill" << dendl; pg->peer_missing[*i]; continue; } if (pi.last_backfill == hobject_t()) { dout(10) << " osd." << *i << " will fully backfill; can infer empty missing set" << dendl; pg->peer_missing[*i]; continue; } if (pi.last_update == pi.last_complete && // peer has no missing pi.last_update == pg->info.last_update) { // peer is up to date // replica has no missing and identical log as us. no need to // pull anything. // FIXME: we can do better here. if last_update==last_complete we // can infer the rest! dout(10) << " osd." << *i << " has no missing, identical log" << dendl; pg->peer_missing[*i]; continue; } // We pull the log from the peer's last_epoch_started to ensure we // get enough log to detect divergent updates. eversion_t since(pi.last_epoch_started, 0); assert(pi.last_update >= pg->info.log_tail); // or else choose_acting() did a bad thing if (pi.log_tail <= since) { dout(10) << " requesting log+missing since " << since << " from osd." << *i << dendl; context< RecoveryMachine >().send_query( *i, pg_query_t( pg_query_t::LOG, i->shard, pg->pg_whoami.shard, since, pg->info.history, pg->get_osdmap()->get_epoch())); } else { dout(10) << " requesting fulllog+missing from osd." << *i << " (want since " << since << " < log.tail " << pi.log_tail << ")" << dendl; context< RecoveryMachine >().send_query( *i, pg_query_t( pg_query_t::FULLLOG, i->shard, pg->pg_whoami.shard, pg->info.history, pg->get_osdmap()->get_epoch())); } peer_missing_requested.insert(*i); } if (peer_missing_requested.empty()) { if (pg->need_up_thru) { dout(10) << " still need up_thru update before going active" << dendl; post_event(NeedUpThru()); return; } // all good! post_event(Activate(pg->get_osdmap()->get_epoch())); } } boost::statechart::result PG::RecoveryState::GetMissing::react(const MLogRec& logevt) { PG *pg = context< RecoveryMachine >().pg; peer_missing_requested.erase(logevt.from); pg->proc_replica_log(*context().get_cur_transaction(), logevt.msg->info, logevt.msg->log, logevt.msg->missing, logevt.from); if (peer_missing_requested.empty()) { if (pg->need_up_thru) { dout(10) << " still need up_thru update before going active" << dendl; post_event(NeedUpThru()); } else { dout(10) << "Got last missing, don't need missing " << "posting CheckRepops" << dendl; post_event(Activate(pg->get_osdmap()->get_epoch())); } } return discard_event(); }; boost::statechart::result PG::RecoveryState::GetMissing::react(const QueryState& q) { PG *pg = context< RecoveryMachine >().pg; q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->open_array_section("peer_missing_requested"); for (set::iterator p = peer_missing_requested.begin(); p != peer_missing_requested.end(); ++p) { q.f->open_object_section("osd"); q.f->dump_stream("osd") << *p; if (pg->peer_missing.count(*p)) { q.f->open_object_section("got_missing"); pg->peer_missing[*p].dump(q.f); q.f->close_section(); } q.f->close_section(); } q.f->close_section(); q.f->close_section(); return forward_event(); } void PG::RecoveryState::GetMissing::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_getmissing_latency, dur); } /*------WaitUpThru--------*/ PG::RecoveryState::WaitUpThru::WaitUpThru(my_context ctx) : my_base(ctx), NamedState(context< RecoveryMachine >().pg->cct, "Started/Primary/Peering/WaitUpThru") { context< RecoveryMachine >().log_enter(state_name); } boost::statechart::result PG::RecoveryState::WaitUpThru::react(const ActMap& am) { PG *pg = context< RecoveryMachine >().pg; if (!pg->need_up_thru) { post_event(Activate(pg->get_osdmap()->get_epoch())); } return forward_event(); } boost::statechart::result PG::RecoveryState::WaitUpThru::react(const MLogRec& logevt) { dout(10) << "Noting missing from osd." << logevt.from << dendl; PG *pg = context< RecoveryMachine >().pg; pg->peer_missing[logevt.from].swap(logevt.msg->missing); pg->peer_info[logevt.from] = logevt.msg->info; return discard_event(); } boost::statechart::result PG::RecoveryState::WaitUpThru::react(const QueryState& q) { q.f->open_object_section("state"); q.f->dump_string("name", state_name); q.f->dump_stream("enter_time") << enter_time; q.f->dump_string("comment", "waiting for osdmap to reflect a new up_thru for this osd"); q.f->close_section(); return forward_event(); } void PG::RecoveryState::WaitUpThru::exit() { context< RecoveryMachine >().log_exit(state_name, enter_time); PG *pg = context< RecoveryMachine >().pg; utime_t dur = ceph_clock_now(pg->cct) - enter_time; pg->osd->recoverystate_perf->tinc(rs_waitupthru_latency, dur); } /*----RecoveryState::RecoveryMachine Methods-----*/ #undef dout_prefix #define dout_prefix *_dout << pg->gen_prefix() void PG::RecoveryState::RecoveryMachine::log_enter(const char *state_name) { dout(5) << "enter " << state_name << dendl; pg->osd->pg_recovery_stats.log_enter(state_name); } void PG::RecoveryState::RecoveryMachine::log_exit(const char *state_name, utime_t enter_time) { utime_t dur = ceph_clock_now(pg->cct) - enter_time; dout(5) << "exit " << state_name << " " << dur << " " << event_count << " " << event_time << dendl; pg->osd->pg_recovery_stats.log_exit(state_name, ceph_clock_now(pg->cct) - enter_time, event_count, event_time); event_count = 0; event_time = utime_t(); } /*---------------------------------------------------*/ #undef dout_prefix #define dout_prefix (*_dout << (debug_pg ? debug_pg->gen_prefix() : string()) << " PriorSet: ") PG::PriorSet::PriorSet(bool ec_pool, PGBackend::IsRecoverablePredicate *c, const OSDMap &osdmap, const map &past_intervals, const vector &up, const vector &acting, const pg_info_t &info, const PG *debug_pg) : ec_pool(ec_pool), pg_down(false), pcontdec(c) { /* * We have to be careful to gracefully deal with situations like * so. Say we have a power outage or something that takes out both * OSDs, but the monitor doesn't mark them down in the same epoch. * The history may look like * * 1: A B * 2: B * 3: let's say B dies for good, too (say, from the power spike) * 4: A * * which makes it look like B may have applied updates to the PG * that we need in order to proceed. This sucks... * * To minimize the risk of this happening, we CANNOT go active if * _any_ OSDs in the prior set are down until we send an MOSDAlive * to the monitor such that the OSDMap sets osd_up_thru to an epoch. * Then, we have something like * * 1: A B * 2: B up_thru[B]=0 * 3: * 4: A * * -> we can ignore B, bc it couldn't have gone active (alive_thru * still 0). * * or, * * 1: A B * 2: B up_thru[B]=0 * 3: B up_thru[B]=2 * 4: * 5: A * * -> we must wait for B, bc it was alive through 2, and could have * written to the pg. * * If B is really dead, then an administrator will need to manually * intervene by marking the OSD as "lost." */ // Include current acting and up nodes... not because they may // contain old data (this interval hasn't gone active, obviously), // but because we want their pg_info to inform choose_acting(), and // so that we know what they do/do not have explicitly before // sending them any new info/logs/whatever. for (unsigned i=0; i::const_reverse_iterator p = past_intervals.rbegin(); p != past_intervals.rend(); ++p) { const pg_interval_t &interval = p->second; dout(10) << "build_prior " << interval << dendl; if (interval.last < info.history.last_epoch_started) break; // we don't care if (interval.acting.empty()) continue; if (!interval.maybe_went_rw) continue; // look at candidate osds during this interval. each falls into // one of three categories: up, down (but potentially // interesting), or lost (down, but we won't wait for it). set up_now; bool any_down_now = false; // any candidates down now (that might have useful data) // consider ACTING osds for (unsigned i=0; ilost_at > interval.first) { dout(10) << "build_prior prior osd." << o << " is down, but lost_at " << pinfo->lost_at << dendl; up_now.insert(so); down.insert(o); } else { dout(10) << "build_prior prior osd." << o << " is down" << dendl; down.insert(o); any_down_now = true; } } // if not enough osds survived this interval, and we may have gone rw, // then we need to wait for one of those osds to recover to // ensure that we haven't lost any information. if (!(*pcontdec)(up_now) && any_down_now) { // fixme: how do we identify a "clean" shutdown anyway? dout(10) << "build_prior possibly went active+rw, insufficient up;" << " including down osds" << dendl; for (vector::const_iterator i = interval.acting.begin(); i != interval.acting.end(); ++i) { if (osdmap.exists(*i) && // if it doesn't exist, we already consider it lost. osdmap.is_down(*i)) { pg_down = true; // make note of when any down osd in the cur set was lost, so that // we can notice changes in prior_set_affected. blocked_by[*i] = osdmap.get_info(*i).lost_at; } } } } dout(10) << "build_prior final: probe " << probe << " down " << down << " blocked_by " << blocked_by << (pg_down ? " pg_down":"") << dendl; } // true if the given map affects the prior set bool PG::PriorSet::affected_by_map(const OSDMapRef osdmap, const PG *debug_pg) const { for (set::iterator p = probe.begin(); p != probe.end(); ++p) { int o = p->osd; // did someone in the prior set go down? if (osdmap->is_down(o) && down.count(o) == 0) { dout(10) << "affected_by_map osd." << o << " now down" << dendl; return true; } // did a down osd in cur get (re)marked as lost? map::const_iterator r = blocked_by.find(o); if (r != blocked_by.end()) { if (!osdmap->exists(o)) { dout(10) << "affected_by_map osd." << o << " no longer exists" << dendl; return true; } if (osdmap->get_info(o).lost_at != r->second) { dout(10) << "affected_by_map osd." << o << " (re)marked as lost" << dendl; return true; } } } // did someone in the prior down set go up? for (set::const_iterator p = down.begin(); p != down.end(); ++p) { int o = *p; if (osdmap->is_up(o)) { dout(10) << "affected_by_map osd." << *p << " now up" << dendl; return true; } // did someone in the prior set get lost or destroyed? if (!osdmap->exists(o)) { dout(10) << "affected_by_map osd." << o << " no longer exists" << dendl; return true; } } return false; } void PG::RecoveryState::start_handle(RecoveryCtx *new_ctx) { assert(!rctx); assert(!orig_ctx); orig_ctx = new_ctx; if (new_ctx) { if (messages_pending_flush) { rctx = RecoveryCtx(*messages_pending_flush, *new_ctx); } else { rctx = *new_ctx; } rctx->start_time = ceph_clock_now(pg->cct); } } void PG::RecoveryState::begin_block_outgoing() { assert(!messages_pending_flush); assert(orig_ctx); assert(rctx); messages_pending_flush = BufferedRecoveryMessages(); rctx = RecoveryCtx(*messages_pending_flush, *orig_ctx); } void PG::RecoveryState::clear_blocked_outgoing() { assert(orig_ctx); assert(rctx); messages_pending_flush = boost::optional(); } void PG::RecoveryState::end_block_outgoing() { assert(messages_pending_flush); assert(orig_ctx); assert(rctx); rctx = RecoveryCtx(*orig_ctx); rctx->accept_buffered_messages(*messages_pending_flush); messages_pending_flush = boost::optional(); } void PG::RecoveryState::end_handle() { if (rctx) { utime_t dur = ceph_clock_now(pg->cct) - rctx->start_time; machine.event_time += dur; } machine.event_count++; rctx = boost::optional(); orig_ctx = NULL; } void intrusive_ptr_add_ref(PG *pg) { pg->get("intptr"); } void intrusive_ptr_release(PG *pg) { pg->put("intptr"); } #ifdef PG_DEBUG_REFS uint64_t get_with_id(PG *pg) { return pg->get_with_id(); } void put_with_id(PG *pg, uint64_t id) { return pg->put_with_id(id); } #endif ceph-0.80.11/src/osd/HitSet.h0000664000175100017510000003104312623076744017623 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OSD_HITSET_H #define CEPH_OSD_HITSET_H #include #include "include/encoding.h" #include "include/unordered_set.h" #include "common/bloom_filter.hpp" #include "common/hobject.h" #include "common/Formatter.h" /** * generic container for a HitSet * * Encapsulate a HitSetImpl of any type. Expose a generic interface * to users and wrap the encoded object with a type so that it can be * safely decoded later. */ class HitSet { public: typedef enum { TYPE_NONE = 0, TYPE_EXPLICIT_HASH = 1, TYPE_EXPLICIT_OBJECT = 2, TYPE_BLOOM = 3 } impl_type_t; static const char *get_type_name(impl_type_t t) { switch (t) { case TYPE_NONE: return "none"; case TYPE_EXPLICIT_HASH: return "explicit_hash"; case TYPE_EXPLICIT_OBJECT: return "explicit_object"; case TYPE_BLOOM: return "bloom"; default: return "???"; } } const char *get_type_name() const { if (impl) return get_type_name(impl->get_type()); return get_type_name(TYPE_NONE); } /// abstract interface for a HitSet implementation class Impl { public: virtual impl_type_t get_type() const = 0; virtual bool is_full() const = 0; virtual void insert(const hobject_t& o) = 0; virtual bool contains(const hobject_t& o) const = 0; virtual unsigned insert_count() const = 0; virtual unsigned approx_unique_insert_count() const = 0; virtual void encode(bufferlist &bl) const = 0; virtual void decode(bufferlist::iterator& p) = 0; virtual void dump(Formatter *f) const = 0; virtual Impl* clone() const = 0; virtual void seal() {} virtual ~Impl() {} }; boost::scoped_ptr impl; bool sealed; class Params { /// create an Impl* of the given type bool create_impl(impl_type_t t); public: class Impl { public: virtual impl_type_t get_type() const = 0; virtual HitSet::Impl *get_new_impl() const = 0; virtual void encode(bufferlist &bl) const {} virtual void decode(bufferlist::iterator& p) {} virtual void dump(Formatter *f) const {} virtual void dump_stream(ostream& o) const {} virtual ~Impl() {} }; Params() {} Params(Impl *i) : impl(i) {} virtual ~Params() {} boost::scoped_ptr impl; impl_type_t get_type() const { if (impl) return impl->get_type(); return TYPE_NONE; } Params(const Params& o); const Params& operator=(const Params& o); void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); friend ostream& operator<<(ostream& out, const HitSet::Params& p); }; HitSet() : impl(NULL), sealed(false) {} HitSet(Impl *i) : impl(i), sealed(false) {} HitSet(const HitSet::Params& params); HitSet(const HitSet& o) { sealed = o.sealed; if (o.impl) impl.reset(o.impl->clone()); else impl.reset(NULL); } const HitSet& operator=(const HitSet& o) { sealed = o.sealed; if (o.impl) impl.reset(o.impl->clone()); else impl.reset(NULL); return *this; } bool is_full() const { return impl->is_full(); } /// insert a hash into the set void insert(const hobject_t& o) { impl->insert(o); } /// query whether a hash is in the set bool contains(const hobject_t& o) const { return impl->contains(o); } unsigned insert_count() const { return impl->insert_count(); } unsigned approx_unique_insert_count() const { return impl->approx_unique_insert_count(); } void seal() { assert(!sealed); sealed = true; impl->seal(); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); private: void reset_to_type(impl_type_t type); }; WRITE_CLASS_ENCODER(HitSet); WRITE_CLASS_ENCODER(HitSet::Params); typedef boost::shared_ptr HitSetRef; ostream& operator<<(ostream& out, const HitSet::Params& p); /** * explicitly enumerate hash hits in the set */ class ExplicitHashHitSet : public HitSet::Impl { uint64_t count; ceph::unordered_set hits; public: class Params : public HitSet::Params::Impl { public: virtual HitSet::impl_type_t get_type() const { return HitSet::TYPE_EXPLICIT_HASH; } virtual HitSet::Impl *get_new_impl() const { return new ExplicitHashHitSet; } static void generate_test_instances(list& o) { o.push_back(new Params); } }; ExplicitHashHitSet() : count(0) {} ExplicitHashHitSet(const ExplicitHashHitSet::Params *p) : count(0) {} ExplicitHashHitSet(const ExplicitHashHitSet &o) : count(o.count), hits(o.hits) {} HitSet::Impl *clone() const { return new ExplicitHashHitSet(*this); } HitSet::impl_type_t get_type() const { return HitSet::TYPE_EXPLICIT_HASH; } bool is_full() const { return false; } void insert(const hobject_t& o) { hits.insert(o.hash); ++count; } bool contains(const hobject_t& o) const { return hits.count(o.hash); } unsigned insert_count() const { return count; } unsigned approx_unique_insert_count() const { return hits.size(); } void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(count, bl); ::encode(hits, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(count, bl); ::decode(hits, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_unsigned("insert_count", count); f->open_array_section("hash_set"); for (ceph::unordered_set::const_iterator p = hits.begin(); p != hits.end(); ++p) f->dump_unsigned("hash", *p); f->close_section(); } static void generate_test_instances(list& o) { o.push_back(new ExplicitHashHitSet); o.push_back(new ExplicitHashHitSet); o.back()->insert(hobject_t()); o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, "")); o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, "")); } }; WRITE_CLASS_ENCODER(ExplicitHashHitSet) /** * explicitly enumerate objects in the set */ class ExplicitObjectHitSet : public HitSet::Impl { uint64_t count; ceph::unordered_set hits; public: class Params : public HitSet::Params::Impl { public: virtual HitSet::impl_type_t get_type() const { return HitSet::TYPE_EXPLICIT_OBJECT; } virtual HitSet::Impl *get_new_impl() const { return new ExplicitObjectHitSet; } static void generate_test_instances(list& o) { o.push_back(new Params); } }; ExplicitObjectHitSet() : count(0) {} ExplicitObjectHitSet(const ExplicitObjectHitSet::Params *p) : count(0) {} ExplicitObjectHitSet(const ExplicitObjectHitSet &o) : count(o.count), hits(o.hits) {} HitSet::Impl *clone() const { return new ExplicitObjectHitSet(*this); } HitSet::impl_type_t get_type() const { return HitSet::TYPE_EXPLICIT_OBJECT; } bool is_full() const { return false; } void insert(const hobject_t& o) { hits.insert(o); ++count; } bool contains(const hobject_t& o) const { return hits.count(o); } unsigned insert_count() const { return count; } unsigned approx_unique_insert_count() const { return hits.size(); } void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(count, bl); ::encode(hits, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(count, bl); ::decode(hits, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_unsigned("insert_count", count); f->open_array_section("set"); for (ceph::unordered_set::const_iterator p = hits.begin(); p != hits.end(); ++p) { f->open_object_section("object"); p->dump(f); f->close_section(); } f->close_section(); } static void generate_test_instances(list& o) { o.push_back(new ExplicitObjectHitSet); o.push_back(new ExplicitObjectHitSet); o.back()->insert(hobject_t()); o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, "")); o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, "")); } }; WRITE_CLASS_ENCODER(ExplicitObjectHitSet) /** * use a bloom_filter to track hits to the set */ class BloomHitSet : public HitSet::Impl { compressible_bloom_filter bloom; public: HitSet::impl_type_t get_type() const { return HitSet::TYPE_BLOOM; } class Params : public HitSet::Params::Impl { public: virtual HitSet::impl_type_t get_type() const { return HitSet::TYPE_BLOOM; } virtual HitSet::Impl *get_new_impl() const { return new BloomHitSet; } uint32_t fpp_micro; ///< false positive probability / 1M uint64_t target_size; ///< number of unique insertions we expect to this HitSet uint64_t seed; ///< seed to use when initializing the bloom filter Params() : fpp_micro(0), target_size(0), seed(0) {} Params(double fpp, uint64_t t, uint64_t s) : fpp_micro(fpp * 1000000.0), target_size(t), seed(s) {} Params(const Params &o) : fpp_micro(o.fpp_micro), target_size(o.target_size), seed(o.seed) {} ~Params() {} double get_fpp() const { return (double)fpp_micro / 1000000.0; } void set_fpp(double f) { fpp_micro = (unsigned)(llrintl(f * (double)1000000.0)); } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(fpp_micro, bl); ::encode(target_size, bl); ::encode(seed, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(fpp_micro, bl); ::decode(target_size, bl); ::decode(seed, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_float("false_positive_probability", get_fpp()); f->dump_int("target_size", target_size); f->dump_int("seed", seed); } void dump_stream(ostream& o) const { o << "false_positive_probability: " << get_fpp() << ", target_size: " << target_size << ", seed: " << seed; } static void generate_test_instances(list& o) { o.push_back(new Params); o.push_back(new Params); (*o.rbegin())->fpp_micro = 123456; (*o.rbegin())->target_size = 300; (*o.rbegin())->seed = 99; } }; BloomHitSet() {} BloomHitSet(unsigned inserts, double fpp, int seed) : bloom(inserts, fpp, seed) {} BloomHitSet(const BloomHitSet::Params *p) : bloom(p->target_size, p->get_fpp(), p->seed) {} BloomHitSet(const BloomHitSet &o) { // oh god bufferlist bl; o.encode(bl); bufferlist::iterator bli = bl.begin(); this->decode(bli); } HitSet::Impl *clone() const { return new BloomHitSet(*this); } bool is_full() const { return bloom.is_full(); } void insert(const hobject_t& o) { bloom.insert(o.hash); } bool contains(const hobject_t& o) const { return bloom.contains(o.hash); } unsigned insert_count() const { return bloom.element_count(); } unsigned approx_unique_insert_count() const { return bloom.approx_unique_element_count(); } void seal() { // aim for a density of .5 (50% of bit set) double pc = (double)bloom.density() * 2.0; if (pc < 1.0) bloom.compress(pc); } void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(bloom, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(bloom, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->open_object_section("bloom_filter"); bloom.dump(f); f->close_section(); } static void generate_test_instances(list& o) { o.push_back(new BloomHitSet); o.push_back(new BloomHitSet(10, .1, 1)); o.back()->insert(hobject_t()); o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, "")); o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, "")); } }; WRITE_CLASS_ENCODER(BloomHitSet) #endif ceph-0.80.11/src/osd/OpRequest.h0000664000175100017510000001200012623076744020342 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network/Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef OPREQUEST_H_ #define OPREQUEST_H_ #include #include #include #include #include "common/Mutex.h" #include "include/xlist.h" #include "msg/Message.h" #include "include/memory.h" #include "common/TrackedOp.h" /** * osd request identifier * * caller name + incarnation# + tid to unique identify this request. */ struct osd_reqid_t { entity_name_t name; // who ceph_tid_t tid; int32_t inc; // incarnation osd_reqid_t() : tid(0), inc(0) {} osd_reqid_t(const entity_name_t& a, int i, ceph_tid_t t) : name(a), tid(t), inc(i) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(osd_reqid_t) /** * The OpRequest takes in a Message* and takes over a single reference * to it, which it puts() when destroyed. */ struct OpRequest : public TrackedOp { friend class OpTracker; // rmw flags int rmw_flags; bool check_rmw(int flag); bool may_read(); bool may_write(); bool may_cache(); bool includes_pg_op(); bool need_read_cap(); bool need_write_cap(); bool need_class_read_cap(); bool need_class_write_cap(); void set_read(); void set_write(); void set_cache(); void set_class_read(); void set_class_write(); void set_pg_op(); void _dump(utime_t now, Formatter *f) const; bool has_feature(uint64_t f) const { return request->get_connection()->has_feature(f); } private: osd_reqid_t reqid; uint8_t hit_flag_points; uint8_t latest_flag_point; utime_t dequeued_time; static const uint8_t flag_queued_for_pg=1 << 0; static const uint8_t flag_reached_pg = 1 << 1; static const uint8_t flag_delayed = 1 << 2; static const uint8_t flag_started = 1 << 3; static const uint8_t flag_sub_op_sent = 1 << 4; static const uint8_t flag_commit_sent = 1 << 5; OpRequest(Message *req, OpTracker *tracker); public: bool been_queued_for_pg() { return hit_flag_points & flag_queued_for_pg; } bool been_reached_pg() { return hit_flag_points & flag_reached_pg; } bool been_delayed() { return hit_flag_points & flag_delayed; } bool been_started() { return hit_flag_points & flag_started; } bool been_sub_op_sent() { return hit_flag_points & flag_sub_op_sent; } bool been_commit_sent() { return hit_flag_points & flag_commit_sent; } bool currently_queued_for_pg() { return latest_flag_point & flag_queued_for_pg; } bool currently_reached_pg() { return latest_flag_point & flag_reached_pg; } bool currently_delayed() { return latest_flag_point & flag_delayed; } bool currently_started() { return latest_flag_point & flag_started; } bool currently_sub_op_sent() { return latest_flag_point & flag_sub_op_sent; } bool currently_commit_sent() { return latest_flag_point & flag_commit_sent; } const char *state_string() const { switch(latest_flag_point) { case flag_queued_for_pg: return "queued for pg"; case flag_reached_pg: return "reached pg"; case flag_delayed: return "delayed"; case flag_started: return "started"; case flag_sub_op_sent: return "waiting for sub ops"; case flag_commit_sent: return "commit sent; apply or cleanup"; default: break; } return "no flag points reached"; } void mark_queued_for_pg() { mark_event("queued_for_pg"); current = "queued for pg"; hit_flag_points |= flag_queued_for_pg; latest_flag_point = flag_queued_for_pg; } void mark_reached_pg() { mark_event("reached_pg"); current = "reached pg"; hit_flag_points |= flag_reached_pg; latest_flag_point = flag_reached_pg; } void mark_delayed(string s) { mark_event(s); current = s; hit_flag_points |= flag_delayed; latest_flag_point = flag_delayed; } void mark_started() { mark_event("started"); current = "started"; hit_flag_points |= flag_started; latest_flag_point = flag_started; } void mark_sub_op_sent(string s) { mark_event(s); current = s; hit_flag_points |= flag_sub_op_sent; latest_flag_point = flag_sub_op_sent; } void mark_commit_sent() { mark_event("commit_sent"); current = "commit sent"; hit_flag_points |= flag_commit_sent; latest_flag_point = flag_commit_sent; } utime_t get_dequeued_time() const { return dequeued_time; } void set_dequeued_time(utime_t deq_time) { dequeued_time = deq_time; } osd_reqid_t get_reqid() const { return reqid; } void init_from_message(); typedef ceph::shared_ptr Ref; }; typedef OpRequest::Ref OpRequestRef; #endif /* OPREQUEST_H_ */ ceph-0.80.11/src/osd/OSDMap.h0000664000175100017510000006514312623076744017516 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013,2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OSDMAP_H #define CEPH_OSDMAP_H /* * describe properties of the OSD cluster. * disks, disk groups, total # osds, * */ #include "common/config.h" #include "include/types.h" #include "osd_types.h" #include "msg/Message.h" #include "common/Mutex.h" #include "common/Clock.h" #include "include/ceph_features.h" #include "crush/CrushWrapper.h" #include "include/interval_set.h" #include #include #include #include #include "include/memory.h" using namespace std; #include "include/unordered_set.h" /* * we track up to two intervals during which the osd was alive and * healthy. the most recent is [up_from,up_thru), where up_thru is * the last epoch the osd is known to have _started_. i.e., a lower * bound on the actual osd death. down_at (if it is > up_from) is an * upper bound on the actual osd death. * * the second is the last_clean interval [first,last]. in that case, * the last interval is the last epoch known to have been either * _finished_, or during which the osd cleanly shut down. when * possible, we push this forward to the epoch the osd was eventually * marked down. * * the lost_at is used to allow build_prior to proceed without waiting * for an osd to recover. In certain cases, progress may be blocked * because an osd is down that may contain updates (i.e., a pg may have * gone rw during an interval). If the osd can't be brought online, we * can force things to proceed knowing that we _might_ be losing some * acked writes. If the osd comes back to life later, that's fine to, * but those writes will still be lost (the divergent objects will be * thrown out). */ struct osd_info_t { epoch_t last_clean_begin; // last interval that ended with a clean osd shutdown epoch_t last_clean_end; epoch_t up_from; // epoch osd marked up epoch_t up_thru; // lower bound on actual osd death (if > up_from) epoch_t down_at; // upper bound on actual osd death (if > up_from) epoch_t lost_at; // last epoch we decided data was "lost" osd_info_t() : last_clean_begin(0), last_clean_end(0), up_from(0), up_thru(0), down_at(0), lost_at(0) {} void dump(Formatter *f) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(osd_info_t) ostream& operator<<(ostream& out, const osd_info_t& info); struct osd_xinfo_t { utime_t down_stamp; ///< timestamp when we were last marked down float laggy_probability; ///< encoded as __u32: 0 = definitely not laggy, 0xffffffff definitely laggy __u32 laggy_interval; ///< average interval between being marked laggy and recovering uint64_t features; ///< features supported by this osd we should know about osd_xinfo_t() : laggy_probability(0), laggy_interval(0), features(0) {} void dump(Formatter *f) const; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(osd_xinfo_t) ostream& operator<<(ostream& out, const osd_xinfo_t& xi); /** OSDMap */ class OSDMap { public: class Incremental { public: /// feature bits we were encoded with. the subsequent OSDMap /// encoding should match. uint64_t encode_features; uuid_d fsid; epoch_t epoch; // new epoch; we are a diff from epoch-1 to epoch utime_t modified; int64_t new_pool_max; //incremented by the OSDMonitor on each pool create int32_t new_flags; // full (rare) bufferlist fullmap; // in leiu of below. bufferlist crush; // incremental int32_t new_max_osd; map new_pools; map new_pool_names; set old_pools; map > new_erasure_code_profiles; vector old_erasure_code_profiles; map new_up_client; map new_up_cluster; map new_state; // XORed onto previous state. map new_weight; map > new_pg_temp; // [] to remove map new_primary_temp; // [-1] to remove map new_primary_affinity; map new_up_thru; map > new_last_clean_interval; map new_lost; map new_uuid; map new_xinfo; map new_blacklist; vector old_blacklist; map new_hb_back_up; map new_hb_front_up; string cluster_snapshot; int get_net_marked_out(const OSDMap *previous) const; int get_net_marked_down(const OSDMap *previous) const; int identify_osd(uuid_d u) const; void encode_client_old(bufferlist& bl) const; void encode_classic(bufferlist& bl, uint64_t features) const; void encode(bufferlist& bl, uint64_t features=CEPH_FEATURES_ALL) const; void decode_classic(bufferlist::iterator &p); void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); Incremental(epoch_t e=0) : encode_features(0), epoch(e), new_pool_max(-1), new_flags(-1), new_max_osd(-1) { memset(&fsid, 0, sizeof(fsid)); } Incremental(bufferlist &bl) { bufferlist::iterator p = bl.begin(); decode(p); } Incremental(bufferlist::iterator &p) { decode(p); } pg_pool_t *get_new_pool(int64_t pool, const pg_pool_t *orig) { if (new_pools.count(pool) == 0) new_pools[pool] = *orig; return &new_pools[pool]; } bool has_erasure_code_profile(const string &name) const { map >::const_iterator i = new_erasure_code_profiles.find(name); return i != new_erasure_code_profiles.end(); } void set_erasure_code_profile(const string &name, const map &profile) { new_erasure_code_profiles[name] = profile; } /// propage update pools' snap metadata to any of their tiers int propagate_snaps_to_tiers(CephContext *cct, const OSDMap &base); }; private: uuid_d fsid; epoch_t epoch; // what epoch of the osd cluster descriptor is this utime_t created, modified; // epoch start time int32_t pool_max; // the largest pool num, ever uint32_t flags; int num_osd; // not saved int32_t max_osd; vector osd_state; struct addrs_s { vector > client_addr; vector > cluster_addr; vector > hb_back_addr; vector > hb_front_addr; entity_addr_t blank; }; ceph::shared_ptr osd_addrs; vector<__u32> osd_weight; // 16.16 fixed point, 0x10000 = "in", 0 = "out" vector osd_info; ceph::shared_ptr< map > > pg_temp; // temp pg mapping (e.g. while we rebuild) ceph::shared_ptr< map > primary_temp; // temp primary mapping (e.g. while we rebuild) ceph::shared_ptr< vector<__u32> > osd_primary_affinity; ///< 16.16 fixed point, 0x10000 = baseline map pools; map pool_name; map > erasure_code_profiles; map name_pool; ceph::shared_ptr< vector > osd_uuid; vector osd_xinfo; ceph::unordered_map blacklist; epoch_t cluster_snapshot_epoch; string cluster_snapshot; bool new_blacklist_entries; public: ceph::shared_ptr crush; // hierarchical map friend class OSDMonitor; friend class PGMonitor; friend class MDS; public: OSDMap() : epoch(0), pool_max(-1), flags(0), num_osd(0), max_osd(0), osd_addrs(new addrs_s), pg_temp(new map >), primary_temp(new map), osd_uuid(new vector), cluster_snapshot_epoch(0), new_blacklist_entries(false), crush(new CrushWrapper) { memset(&fsid, 0, sizeof(fsid)); } // no copying /* oh, how i long for c++11... private: OSDMap(const OSDMap& other) = default; const OSDMap& operator=(const OSDMap& other) = default; public: */ void deepish_copy_from(const OSDMap& o) { *this = o; primary_temp.reset(new map(*o.primary_temp)); pg_temp.reset(new map >(*o.pg_temp)); osd_uuid.reset(new vector(*o.osd_uuid)); // NOTE: this still references shared entity_addr_t's. osd_addrs.reset(new addrs_s(*o.osd_addrs)); // NOTE: we do not copy crush. note that apply_incremental will // allocate a new CrushWrapper, though. } // map info const uuid_d& get_fsid() const { return fsid; } void set_fsid(uuid_d& f) { fsid = f; } epoch_t get_epoch() const { return epoch; } void inc_epoch() { epoch++; } void set_epoch(epoch_t e); /* stamps etc */ const utime_t& get_created() const { return created; } const utime_t& get_modified() const { return modified; } bool is_blacklisted(const entity_addr_t& a) const; void get_blacklist(list > *bl) const; string get_cluster_snapshot() const { if (cluster_snapshot_epoch == epoch) return cluster_snapshot; return string(); } /***** cluster state *****/ /* osds */ int get_max_osd() const { return max_osd; } void set_max_osd(int m); unsigned get_num_osds() const { return num_osd; } int calc_num_osds(); void get_all_osds(set& ls) const; void get_up_osds(set& ls) const; unsigned get_num_up_osds() const; unsigned get_num_in_osds() const; int get_flags() const { return flags; } int test_flag(int f) const { return flags & f; } void set_flag(int f) { flags |= f; } void clear_flag(int f) { flags &= ~f; } static void calc_state_set(int state, set& st); int get_state(int o) const { assert(o < max_osd); return osd_state[o]; } int get_state(int o, set& st) const { assert(o < max_osd); unsigned t = osd_state[o]; calc_state_set(t, st); return osd_state[o]; } void set_state(int o, unsigned s) { assert(o < max_osd); osd_state[o] = s; } void set_weightf(int o, float w) { set_weight(o, (int)((float)CEPH_OSD_IN * w)); } void set_weight(int o, unsigned w) { assert(o < max_osd); osd_weight[o] = w; if (w) osd_state[o] |= CEPH_OSD_EXISTS; } unsigned get_weight(int o) const { assert(o < max_osd); return osd_weight[o]; } float get_weightf(int o) const { return (float)get_weight(o) / (float)CEPH_OSD_IN; } void adjust_osd_weights(const map& weights, Incremental& inc) const; void set_primary_affinity(int o, int w) { assert(o < max_osd); if (!osd_primary_affinity) osd_primary_affinity.reset(new vector<__u32>(max_osd, CEPH_OSD_DEFAULT_PRIMARY_AFFINITY)); (*osd_primary_affinity)[o] = w; } unsigned get_primary_affinity(int o) const { assert(o < max_osd); if (!osd_primary_affinity) return CEPH_OSD_DEFAULT_PRIMARY_AFFINITY; return (*osd_primary_affinity)[o]; } float get_primary_affinityf(int o) const { return (float)get_primary_affinity(o) / (float)CEPH_OSD_MAX_PRIMARY_AFFINITY; } bool has_erasure_code_profile(const string &name) const { map >::const_iterator i = erasure_code_profiles.find(name); return i != erasure_code_profiles.end(); } int get_erasure_code_profile_default(CephContext *cct, map &profile_map, ostream *ss); void set_erasure_code_profile(const string &name, const map &profile) { erasure_code_profiles[name] = profile; } const map &get_erasure_code_profile(const string &name) const { map >::const_iterator i = erasure_code_profiles.find(name); static map empty; if (i == erasure_code_profiles.end()) return empty; else return i->second; } map &get_erasure_code_profile(const string &name) { return erasure_code_profiles[name]; } const map > &get_erasure_code_profiles() const { return erasure_code_profiles; } bool exists(int osd) const { //assert(osd >= 0); return osd >= 0 && osd < max_osd && (osd_state[osd] & CEPH_OSD_EXISTS); } bool is_up(int osd) const { return exists(osd) && (osd_state[osd] & CEPH_OSD_UP); } bool is_down(int osd) const { return !is_up(osd); } bool is_out(int osd) const { return !exists(osd) || get_weight(osd) == CEPH_OSD_OUT; } bool is_in(int osd) const { return !is_out(osd); } /** * check if an entire crush subtre is down */ bool subtree_is_down(int id, set *down_cache) const; bool containing_subtree_is_down(CephContext *cct, int osd, int subtree_type, set *down_cache) const; int identify_osd(const entity_addr_t& addr) const; int identify_osd(const uuid_d& u) const; bool have_addr(const entity_addr_t& addr) const { return identify_osd(addr) >= 0; } bool find_osd_on_ip(const entity_addr_t& ip) const; bool have_inst(int osd) const { return exists(osd) && is_up(osd); } const entity_addr_t &get_addr(int osd) const { assert(exists(osd)); return osd_addrs->client_addr[osd] ? *osd_addrs->client_addr[osd] : osd_addrs->blank; } const entity_addr_t &get_cluster_addr(int osd) const { assert(exists(osd)); if (!osd_addrs->cluster_addr[osd] || *osd_addrs->cluster_addr[osd] == entity_addr_t()) return get_addr(osd); return *osd_addrs->cluster_addr[osd]; } const entity_addr_t &get_hb_back_addr(int osd) const { assert(exists(osd)); return osd_addrs->hb_back_addr[osd] ? *osd_addrs->hb_back_addr[osd] : osd_addrs->blank; } const entity_addr_t &get_hb_front_addr(int osd) const { assert(exists(osd)); return osd_addrs->hb_front_addr[osd] ? *osd_addrs->hb_front_addr[osd] : osd_addrs->blank; } entity_inst_t get_inst(int osd) const { assert(is_up(osd)); return entity_inst_t(entity_name_t::OSD(osd), get_addr(osd)); } entity_inst_t get_cluster_inst(int osd) const { assert(is_up(osd)); return entity_inst_t(entity_name_t::OSD(osd), get_cluster_addr(osd)); } entity_inst_t get_hb_back_inst(int osd) const { assert(is_up(osd)); return entity_inst_t(entity_name_t::OSD(osd), get_hb_back_addr(osd)); } entity_inst_t get_hb_front_inst(int osd) const { assert(is_up(osd)); return entity_inst_t(entity_name_t::OSD(osd), get_hb_front_addr(osd)); } const uuid_d& get_uuid(int osd) const { assert(exists(osd)); return (*osd_uuid)[osd]; } const epoch_t& get_up_from(int osd) const { assert(exists(osd)); return osd_info[osd].up_from; } const epoch_t& get_up_thru(int osd) const { assert(exists(osd)); return osd_info[osd].up_thru; } const epoch_t& get_down_at(int osd) const { assert(exists(osd)); return osd_info[osd].down_at; } const osd_info_t& get_info(int osd) const { assert(osd < max_osd); return osd_info[osd]; } const osd_xinfo_t& get_xinfo(int osd) const { assert(osd < max_osd); return osd_xinfo[osd]; } int get_any_up_osd() const { for (int i=0; i= get_max_osd()) i = 0; if (i == n) break; if (is_up(i)) return i; } return -1; } int get_previous_up_osd_before(int n) const { for (int i = n - 1; i != n; --i) { if (i < 0) i = get_max_osd() - 1; if (i == n) break; if (is_up(i)) return i; } return -1; } /** * get feature bits required by the current structure * * @param entity_type [in] what entity type we are asking about * @param mask [out] set of all possible map-related features we could set * @return feature bits used by this map */ uint64_t get_features(int entity_type, uint64_t *mask) const; /** * get intersection of features supported by up osds */ uint64_t get_up_osd_features() const; int apply_incremental(const Incremental &inc); /// try to re-use/reference addrs in oldmap from newmap static void dedup(const OSDMap *oldmap, OSDMap *newmap); static void remove_redundant_temporaries(CephContext *cct, const OSDMap& osdmap, Incremental *pending_inc); static void remove_down_temps(CephContext *cct, const OSDMap& osdmap, Incremental *pending_inc); // serialize, unserialize private: void encode_client_old(bufferlist& bl) const; void encode_classic(bufferlist& bl, uint64_t features) const; void decode_classic(bufferlist::iterator& p); void post_decode(); public: void encode(bufferlist& bl, uint64_t features=CEPH_FEATURES_ALL) const; void decode(bufferlist& bl); void decode(bufferlist::iterator& bl); /**** mapping facilities ****/ int object_locator_to_pg(const object_t& oid, const object_locator_t& loc, pg_t &pg) const; pg_t object_locator_to_pg(const object_t& oid, const object_locator_t& loc) const { pg_t pg; int ret = object_locator_to_pg(oid, loc, pg); assert(ret == 0); return pg; } static object_locator_t file_to_object_locator(const ceph_file_layout& layout) { return object_locator_t(layout.fl_pg_pool); } // XXX: not used, mentioned in psim.cc comment // oid -> pg ceph_object_layout file_to_object_layout(object_t oid, ceph_file_layout& layout, string nspace) const { return make_object_layout(oid, layout.fl_pg_pool, nspace); } ceph_object_layout make_object_layout(object_t oid, int pg_pool, string nspace) const; int get_pg_num(int pg_pool) const { const pg_pool_t *pool = get_pg_pool(pg_pool); return pool->get_pg_num(); } private: /// pg -> (raw osd list) int _pg_to_osds(const pg_pool_t& pool, pg_t pg, vector *osds, int *primary, ps_t *ppps) const; void _remove_nonexistent_osds(const pg_pool_t& pool, vector& osds) const; void _apply_primary_affinity(ps_t seed, const pg_pool_t& pool, vector *osds, int *primary) const; /// pg -> (up osd list) void _raw_to_up_osds(const pg_pool_t& pool, const vector& raw, vector *up, int *primary) const; /** * Get the pg and primary temp, if they are specified. * @param temp_pg [out] Will be empty or contain the temp PG mapping on return * @param temp_primary [out] Will be the value in primary_temp, or a value derived * from the pg_temp (if specified), or -1 if you should use the calculated (up_)primary. */ void _get_temp_osds(const pg_pool_t& pool, pg_t pg, vector *temp_pg, int *temp_primary) const; /** * map to up and acting. Fills in whatever fields are non-NULL. */ void _pg_to_up_acting_osds(pg_t pg, vector *up, int *up_primary, vector *acting, int *acting_primary) const; public: /*** * This is suitable only for looking at raw CRUSH outputs. It skips * applying the temp and up checks and should not be used * by anybody for data mapping purposes. * raw and primary must be non-NULL */ int pg_to_osds(pg_t pg, vector *raw, int *primary) const; /// map a pg to its acting set. @return acting set size int pg_to_acting_osds(pg_t pg, vector *acting, int *acting_primary) const { _pg_to_up_acting_osds(pg, NULL, NULL, acting, acting_primary); return acting->size(); } int pg_to_acting_osds(pg_t pg, vector& acting) const { int primary; int r = pg_to_acting_osds(pg, &acting, &primary); return r; } /** * This does not apply temp overrides and should not be used * by anybody for data mapping purposes. Specify both pointers. */ void pg_to_raw_up(pg_t pg, vector *up, int *primary) const; /** * map a pg to its acting set as well as its up set. You must use * the acting set for data mapping purposes, but some users will * also find the up set useful for things like deciding what to * set as pg_temp. * Each of these pointers must be non-NULL. */ void pg_to_up_acting_osds(pg_t pg, vector *up, int *up_primary, vector *acting, int *acting_primary) const { _pg_to_up_acting_osds(pg, up, up_primary, acting, acting_primary); } void pg_to_up_acting_osds(pg_t pg, vector& up, vector& acting) const { int up_primary, acting_primary; pg_to_up_acting_osds(pg, &up, &up_primary, &acting, &acting_primary); } bool pg_is_ec(pg_t pg) const { map::const_iterator i = pools.find(pg.pool()); assert(i != pools.end()); return i->second.ec_pool(); } bool get_primary_shard(pg_t pgid, spg_t *out) const { map::const_iterator i = get_pools().find(pgid.pool()); if (i == get_pools().end()) { return false; } int primary; vector acting; pg_to_acting_osds(pgid, &acting, &primary); if (i->second.ec_pool()) { for (shard_id_t i = 0; i < acting.size(); ++i) { if (acting[i] == primary) { *out = spg_t(pgid, i); return true; } } } else { *out = spg_t(pgid); return true; } return false; } int64_t lookup_pg_pool_name(const string& name) { if (name_pool.count(name)) return name_pool[name]; return -ENOENT; } int64_t const_lookup_pg_pool_name(const char *name) const { return const_cast(this)->lookup_pg_pool_name(name); } int64_t get_pool_max() const { return pool_max; } const map& get_pools() const { return pools; } const char *get_pool_name(int64_t p) const { map::const_iterator i = pool_name.find(p); if (i != pool_name.end()) return i->second.c_str(); return 0; } bool have_pg_pool(int64_t p) const { return pools.count(p); } const pg_pool_t* get_pg_pool(int64_t p) const { map::const_iterator i = pools.find(p); if (i != pools.end()) return &i->second; return NULL; } unsigned get_pg_size(pg_t pg) const { map::const_iterator p = pools.find(pg.pool()); assert(p != pools.end()); return p->second.get_size(); } int get_pg_type(pg_t pg) const { assert(pools.count(pg.pool())); return pools.find(pg.pool())->second.get_type(); } pg_t raw_pg_to_pg(pg_t pg) const { assert(pools.count(pg.pool())); return pools.find(pg.pool())->second.raw_pg_to_pg(pg); } // pg -> acting primary osd int get_pg_acting_primary(pg_t pg) const { vector group; int nrep = pg_to_acting_osds(pg, group); if (nrep > 0) return group[0]; return -1; // we fail! } int get_pg_acting_tail(pg_t pg) const { vector group; int nrep = pg_to_acting_osds(pg, group); if (nrep > 0) return group[group.size()-1]; return -1; // we fail! } /* what replica # is a given osd? 0 primary, -1 for none. */ static int calc_pg_rank(int osd, const vector& acting, int nrep=0); static int calc_pg_role(int osd, const vector& acting, int nrep=0); static bool primary_changed( int oldprimary, const vector &oldacting, int newprimary, const vector &newacting); /* rank is -1 (stray), 0 (primary), 1,2,3,... (replica) */ int get_pg_acting_rank(pg_t pg, int osd) const { vector group; int nrep = pg_to_acting_osds(pg, group); return calc_pg_rank(osd, group, nrep); } /* role is -1 (stray), 0 (primary), 1 (replica) */ int get_pg_acting_role(pg_t pg, int osd) const { vector group; int nrep = pg_to_acting_osds(pg, group); return calc_pg_role(osd, group, nrep); } bool osd_is_valid_op_target(pg_t pg, int osd) const { int primary; vector group; int nrep = pg_to_acting_osds(pg, &group, &primary); if (osd == primary) return true; if (pg_is_ec(pg)) return false; return calc_pg_role(osd, group, nrep) >= 0; } /* * handy helpers to build simple maps... */ /** * Build an OSD map suitable for basic usage. If **num_osd** is >= 0 * it will be initialized with the specified number of OSDs in a * single host. If **num_osd** is < 0 the layout of the OSD map will * be built by reading the content of the configuration file. * * @param cct [in] in core ceph context * @param e [in] initial epoch * @param fsid [in] id of the cluster * @param num_osd [in] number of OSDs if >= 0 or read from conf if < 0 * @return **0** on success, negative errno on error. */ int build_simple(CephContext *cct, epoch_t e, uuid_d &fsid, int num_osd, int pg_bits, int pgp_bits); static int _build_crush_types(CrushWrapper& crush); static int build_simple_crush_map(CephContext *cct, CrushWrapper& crush, int num_osd, ostream *ss); static int build_simple_crush_map_from_conf(CephContext *cct, CrushWrapper& crush, ostream *ss); static int build_simple_crush_rulesets(CephContext *cct, CrushWrapper& crush, const string& root, ostream *ss); bool crush_ruleset_in_use(int ruleset) const; void clear_temp() { pg_temp->clear(); primary_temp->clear(); } private: void print_osd_line(int cur, ostream *out, Formatter *f) const; public: void print(ostream& out) const; void print_summary(Formatter *f, ostream& out) const; void print_oneline_summary(ostream& out) const; void print_tree(ostream *out, Formatter *f) const; string get_flag_string() const; static string get_flag_string(unsigned flags); static void dump_erasure_code_profiles(const map > &profiles, Formatter *f); void dump_json(ostream& out) const; void dump(Formatter *f) const; static void generate_test_instances(list& o); bool check_new_blacklist_entries() const { return new_blacklist_entries; } }; WRITE_CLASS_ENCODER_FEATURES(OSDMap) WRITE_CLASS_ENCODER_FEATURES(OSDMap::Incremental) typedef ceph::shared_ptr OSDMapRef; inline ostream& operator<<(ostream& out, const OSDMap& m) { m.print_oneline_summary(out); return out; } #endif ceph-0.80.11/src/osd/ReplicatedPG.h0000664000175100017510000012636112623076744020736 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_REPLICATEDPG_H #define CEPH_REPLICATEDPG_H #include #include #include "include/assert.h" #include "common/cmdparse.h" #include "HitSet.h" #include "OSD.h" #include "PG.h" #include "Watch.h" #include "OpRequest.h" #include "TierAgentState.h" #include "messages/MOSDOp.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDSubOp.h" #include "common/sharedptr_registry.hpp" #include "PGBackend.h" #include "ReplicatedBackend.h" #include "ECBackend.h" class MOSDSubOpReply; class CopyFromCallback; class PromoteCallback; class ReplicatedPG; void intrusive_ptr_add_ref(ReplicatedPG *pg); void intrusive_ptr_release(ReplicatedPG *pg); uint64_t get_with_id(ReplicatedPG *pg); void put_with_id(ReplicatedPG *pg, uint64_t id); #ifdef PG_DEBUG_REFS typedef TrackedIntPtr ReplicatedPGRef; #else typedef boost::intrusive_ptr ReplicatedPGRef; #endif class PGLSFilter { protected: string xattr; public: PGLSFilter(); virtual ~PGLSFilter(); virtual bool filter(bufferlist& xattr_data, bufferlist& outdata) = 0; virtual string& get_xattr() { return xattr; } }; class PGLSPlainFilter : public PGLSFilter { string val; public: PGLSPlainFilter(bufferlist::iterator& params) { ::decode(xattr, params); ::decode(val, params); } virtual ~PGLSPlainFilter() {} virtual bool filter(bufferlist& xattr_data, bufferlist& outdata); }; class PGLSParentFilter : public PGLSFilter { inodeno_t parent_ino; public: PGLSParentFilter(bufferlist::iterator& params) { xattr = "_parent"; ::decode(parent_ino, params); generic_dout(0) << "parent_ino=" << parent_ino << dendl; } virtual ~PGLSParentFilter() {} virtual bool filter(bufferlist& xattr_data, bufferlist& outdata); }; class ReplicatedPG : public PG, public PGBackend::Listener { friend class OSD; friend class Watch; public: /* * state associated with a copy operation */ struct OpContext; class CopyCallback; /** * CopyResults stores the object metadata of interest to a copy initiator. */ struct CopyResults { utime_t mtime; ///< the copy source's mtime uint64_t object_size; ///< the copied object's size bool started_temp_obj; ///< true if the callback needs to delete temp object hobject_t temp_oid; ///< temp object (if any) /** * Final transaction; if non-empty the callback must execute it before any * other accesses to the object (in order to complete the copy). */ PGBackend::PGTransaction *final_tx; string category; ///< The copy source's category version_t user_version; ///< The copy source's user version bool should_requeue; ///< op should be requeued on cancel vector snaps; ///< src's snaps (if clone) snapid_t snap_seq; ///< src's snap_seq (if head) librados::snap_set_t snapset; ///< src snapset (if head) bool mirror_snapset; map attrs; ///< src user attrs bool has_omap; CopyResults() : object_size(0), started_temp_obj(false), final_tx(NULL), user_version(0), should_requeue(false), mirror_snapset(false), has_omap(false) {} }; struct CopyOp { CopyCallback *cb; ObjectContextRef obc; hobject_t src; object_locator_t oloc; unsigned flags; bool mirror_snapset; CopyResults results; ceph_tid_t objecter_tid; ceph_tid_t objecter_tid2; object_copy_cursor_t cursor; map attrs; bufferlist data; bufferlist omap_header; map omap; int rval; object_copy_cursor_t temp_cursor; CopyOp(CopyCallback *cb_, ObjectContextRef _obc, hobject_t s, object_locator_t l, version_t v, unsigned f, bool ms) : cb(cb_), obc(_obc), src(s), oloc(l), flags(f), mirror_snapset(ms), objecter_tid(0), objecter_tid2(0), rval(-1) { results.user_version = v; results.mirror_snapset = mirror_snapset; } }; typedef boost::shared_ptr CopyOpRef; /** * The CopyCallback class defines an interface for completions to the * copy_start code. Users of the copy infrastructure must implement * one and give an instance of the class to start_copy. * * The implementer is responsible for making sure that the CopyCallback * can associate itself with the correct copy operation. */ typedef boost::tuple CopyCallbackResults; class CopyCallback : public GenContext { protected: CopyCallback() {} /** * results.get<0>() is the return code: 0 for success; -ECANCELLED if * the operation was cancelled by the local OSD; -errno for other issues. * results.get<1>() is a pointer to a CopyResults object, which you are * responsible for deleting. */ virtual void finish(CopyCallbackResults results_) = 0; public: /// Provide the final size of the copied object to the CopyCallback virtual ~CopyCallback() {}; }; friend class CopyFromCallback; friend class PromoteCallback; struct FlushOp { ObjectContextRef obc; ///< obc we are flushing OpRequestRef op; ///< initiating op list dup_ops; ///< bandwagon jumpers version_t flushed_version; ///< user version we are flushing ceph_tid_t objecter_tid; ///< copy-from request tid int rval; ///< copy-from result bool blocking; ///< whether we are blocking updates bool removal; ///< we are removing the backend object Context *on_flush; ///< callback, may be null FlushOp() : objecter_tid(0), rval(0), blocking(false), removal(false), on_flush(NULL) {} ~FlushOp() { assert(!on_flush); } }; typedef boost::shared_ptr FlushOpRef; boost::scoped_ptr pgbackend; PGBackend *get_pgbackend() { return pgbackend.get(); } /// Listener methods void on_local_recover_start( const hobject_t &oid, ObjectStore::Transaction *t); void on_local_recover( const hobject_t &oid, const object_stat_sum_t &stat_diff, const ObjectRecoveryInfo &recovery_info, ObjectContextRef obc, ObjectStore::Transaction *t ); void on_peer_recover( pg_shard_t peer, const hobject_t &oid, const ObjectRecoveryInfo &recovery_info, const object_stat_sum_t &stat ); void begin_peer_recover( pg_shard_t peer, const hobject_t oid); void on_global_recover( const hobject_t &oid); void failed_push(pg_shard_t from, const hobject_t &soid); void cancel_pull(const hobject_t &soid); template class BlessedGenContext : public GenContext { ReplicatedPGRef pg; GenContext *c; epoch_t e; public: BlessedGenContext(ReplicatedPG *pg, GenContext *c, epoch_t e) : pg(pg), c(c), e(e) {} void finish(T t) { pg->lock(); if (pg->pg_has_reset_since(e)) delete c; else c->complete(t); pg->unlock(); } }; class BlessedContext : public Context { ReplicatedPGRef pg; Context *c; epoch_t e; public: BlessedContext(ReplicatedPG *pg, Context *c, epoch_t e) : pg(pg), c(c), e(e) {} void finish(int r) { pg->lock(); if (pg->pg_has_reset_since(e)) delete c; else c->complete(r); pg->unlock(); } }; Context *bless_context(Context *c) { return new BlessedContext(this, c, get_osdmap()->get_epoch()); } GenContext *bless_gencontext( GenContext *c) { return new BlessedGenContext( this, c, get_osdmap()->get_epoch()); } void send_message(int to_osd, Message *m) { osd->send_message_osd_cluster(to_osd, m, get_osdmap()->get_epoch()); } void queue_transaction(ObjectStore::Transaction *t, OpRequestRef op) { list tls; tls.push_back(t); osd->store->queue_transaction(osr.get(), t, 0, 0, 0, op); } epoch_t get_epoch() const { return get_osdmap()->get_epoch(); } const set &get_actingbackfill_shards() const { return actingbackfill; } const set &get_acting_shards() const { return actingset; } const set &get_backfill_shards() const { return backfill_targets; } std::string gen_dbg_prefix() const { return gen_prefix(); } const map > &get_missing_loc_shards() const { return missing_loc.get_missing_locs(); } const map &get_shard_missing() const { return peer_missing; } const map &get_shard_info() const { return peer_info; } const pg_missing_t &get_local_missing() const { return pg_log.get_missing(); } const PGLog &get_log() const { return pg_log; } bool pgb_is_primary() const { return is_primary(); } OSDMapRef pgb_get_osdmap() const { return get_osdmap(); } const pg_info_t &get_info() const { return info; } const pg_pool_t &get_pool() const { return pool.info; } ObjectContextRef get_obc( const hobject_t &hoid, map &attrs) { return get_object_context(hoid, true, &attrs); } void log_operation( vector &logv, boost::optional &hset_history, const eversion_t &trim_to, const eversion_t &trim_rollback_to, bool transaction_applied, ObjectStore::Transaction *t) { if (hset_history) { info.hit_set = *hset_history; dirty_info = true; } append_log(logv, trim_to, trim_rollback_to, *t, transaction_applied); } void op_applied( const eversion_t &applied_version); bool should_send_op( pg_shard_t peer, const hobject_t &hoid) { if (peer == get_primary()) return true; assert(peer_info.count(peer)); bool should_send = hoid.pool != (int64_t)info.pgid.pool() || hoid <= MAX(last_backfill_started, peer_info[peer].last_backfill); if (!should_send) assert(is_backfill_targets(peer)); return should_send; } void update_peer_last_complete_ondisk( pg_shard_t fromosd, eversion_t lcod) { peer_last_complete_ondisk[fromosd] = lcod; } void update_last_complete_ondisk( eversion_t lcod) { last_complete_ondisk = lcod; } void update_stats( const pg_stat_t &stat) { info.stats = stat; } void schedule_work( GenContext *c); pg_shard_t whoami_shard() const { return pg_whoami; } spg_t primary_spg_t() const { return spg_t(info.pgid.pgid, primary.shard); } pg_shard_t primary_shard() const { return primary; } void send_message_osd_cluster( int peer, Message *m, epoch_t from_epoch); void send_message_osd_cluster( Message *m, Connection *con); void send_message_osd_cluster( Message *m, const ConnectionRef& con); ConnectionRef get_con_osd_cluster(int peer, epoch_t from_epoch); entity_name_t get_cluster_msgr_name() { return osd->get_cluster_msgr_name(); } PerfCounters *get_logger(); ceph_tid_t get_tid() { return osd->get_tid(); } LogClientTemp clog_error() { return osd->clog.error(); } /* * Capture all object state associated with an in-progress read or write. */ struct OpContext { OpRequestRef op; osd_reqid_t reqid; vector &ops; const ObjectState *obs; // Old objectstate const SnapSet *snapset; // Old snapset ObjectState new_obs; // resulting ObjectState SnapSet new_snapset; // resulting SnapSet (in case of a write) //pg_stat_t new_stats; // resulting Stats object_stat_sum_t delta_stats; bool modify; // (force) modification (even if op_t is empty) bool user_modify; // user-visible modification bool undirty; // user explicitly un-dirtying this object bool cache_evict; ///< true if this is a cache eviction bool ignore_cache; ///< true if IGNORE_CACHE flag is set // side effects list watch_connects; list watch_disconnects; list notifies; struct NotifyAck { boost::optional watch_cookie; uint64_t notify_id; NotifyAck(uint64_t notify_id) : notify_id(notify_id) {} NotifyAck(uint64_t notify_id, uint64_t cookie) : watch_cookie(cookie), notify_id(notify_id) {} }; list notify_acks; uint64_t bytes_written, bytes_read; utime_t mtime; SnapContext snapc; // writer snap context eversion_t at_version; // pg's current version pointer version_t user_at_version; // pg's current user version pointer int current_osd_subop_num; PGBackend::PGTransaction *op_t; vector log; boost::optional updated_hset_history; interval_set modified_ranges; ObjectContextRef obc; map src_obc; ObjectContextRef clone_obc; // if we created a clone ObjectContextRef snapset_obc; // if we created/deleted a snapdir int data_off; // FIXME: we may want to kill this msgr hint off at some point! MOSDOpReply *reply; utime_t readable_stamp; // when applied on all replicas ReplicatedPG *pg; int num_read; ///< count read ops int num_write; ///< count update ops CopyFromCallback *copy_cb; hobject_t new_temp_oid, discard_temp_oid; ///< temp objects we should start/stop tracking // pending xattr updates map > > pending_attrs; void apply_pending_attrs() { for (map > >::iterator i = pending_attrs.begin(); i != pending_attrs.end(); ++i) { if (i->first->obs.exists) { for (map >::iterator j = i->second.begin(); j != i->second.end(); ++j) { if (j->second) i->first->attr_cache[j->first] = j->second.get(); else i->first->attr_cache.erase(j->first); } } else { i->first->attr_cache.clear(); } } pending_attrs.clear(); } // pending async reads -> list, pair > > pending_async_reads; int async_read_result; unsigned inflightreads; friend struct OnReadComplete; void start_async_reads(ReplicatedPG *pg); void finish_read(ReplicatedPG *pg); bool async_reads_complete() { return inflightreads == 0; } ObjectModDesc mod_desc; enum { W_LOCK, R_LOCK, NONE } lock_to_release; Context *on_finish; OpContext(const OpContext& other); const OpContext& operator=(const OpContext& other); bool release_snapset_obc; OpContext(OpRequestRef _op, osd_reqid_t _reqid, vector& _ops, ObjectState *_obs, SnapSetContext *_ssc, ReplicatedPG *_pg) : op(_op), reqid(_reqid), ops(_ops), obs(_obs), snapset(0), new_obs(_obs->oi, _obs->exists), modify(false), user_modify(false), undirty(false), cache_evict(false), ignore_cache(false), bytes_written(0), bytes_read(0), user_at_version(0), current_osd_subop_num(0), op_t(NULL), data_off(0), reply(NULL), pg(_pg), num_read(0), num_write(0), copy_cb(NULL), async_read_result(0), inflightreads(0), lock_to_release(NONE), on_finish(NULL), release_snapset_obc(false) { if (_ssc) { new_snapset = _ssc->snapset; snapset = &_ssc->snapset; } } void reset_obs(ObjectContextRef obc) { new_obs = ObjectState(obc->obs.oi, obc->obs.exists); if (obc->ssc) { new_snapset = obc->ssc->snapset; snapset = &obc->ssc->snapset; } } ~OpContext() { assert(!op_t); assert(lock_to_release == NONE); if (reply) reply->put(); for (list, pair > >::iterator i = pending_async_reads.begin(); i != pending_async_reads.end(); pending_async_reads.erase(i++)) { delete i->second.second; } assert(on_finish == NULL); } void finish(int r) { if (on_finish) { on_finish->complete(r); on_finish = NULL; } } }; friend struct OpContext; /* * State on the PG primary associated with the replicated mutation */ class RepGather { public: xlist::item queue_item; int nref; eversion_t v; OpContext *ctx; ObjectContextRef obc; map src_obc; ceph_tid_t rep_tid; bool rep_aborted, rep_done; bool all_applied; bool all_committed; bool sent_ack; //bool sent_nvram; bool sent_disk; utime_t start; eversion_t pg_local_last_complete; bool queue_snap_trimmer; Context *on_applied; RepGather(OpContext *c, ObjectContextRef pi, ceph_tid_t rt, eversion_t lc) : queue_item(this), nref(1), ctx(c), obc(pi), rep_tid(rt), rep_aborted(false), rep_done(false), all_applied(false), all_committed(false), sent_ack(false), //sent_nvram(false), sent_disk(false), pg_local_last_complete(lc), queue_snap_trimmer(false), on_applied(NULL) { } RepGather *get() { nref++; return this; } void put() { assert(nref > 0); if (--nref == 0) { delete ctx; // must already be unlocked assert(on_applied == NULL); delete this; //generic_dout(0) << "deleting " << this << dendl; } } }; protected: /** * Grabs locks for OpContext, should be cleaned up in close_op_ctx * * @param ctx [in,out] ctx to get locks for * @return true on success, false if we are queued */ bool get_rw_locks(OpContext *ctx) { /* If snapset_obc, !obc->obs->exists and we will always take the * snapdir lock *before* the head lock. Since all callers will do * this (read or write) if we get the first we will be guaranteed * to get the second. */ if (ctx->snapset_obc) { assert(!ctx->obc->obs.exists); if (ctx->op->may_write() || ctx->op->may_cache()) { if (ctx->snapset_obc->get_write(ctx->op)) { ctx->release_snapset_obc = true; ctx->lock_to_release = OpContext::W_LOCK; } else { return false; } } else { assert(ctx->op->may_read()); if (ctx->snapset_obc->get_read(ctx->op)) { ctx->release_snapset_obc = true; ctx->lock_to_release = OpContext::R_LOCK; } else { return false; } } } if (ctx->op->may_write() || ctx->op->may_cache()) { if (ctx->obc->get_write(ctx->op)) { ctx->lock_to_release = OpContext::W_LOCK; return true; } else { assert(!ctx->snapset_obc); return false; } } else { assert(ctx->op->may_read()); if (ctx->obc->get_read(ctx->op)) { ctx->lock_to_release = OpContext::R_LOCK; return true; } else { assert(!ctx->snapset_obc); return false; } } } /** * Cleans up OpContext * * @param ctx [in] ctx to clean up */ void close_op_ctx(OpContext *ctx, int r) { release_op_ctx_locks(ctx); delete ctx->op_t; ctx->op_t = NULL; ctx->finish(r); delete ctx; } /** * Releases ctx locks * * @param ctx [in] ctx to clean up */ void release_op_ctx_locks(OpContext *ctx) { list to_req; bool requeue_recovery = false; bool requeue_recovery_clone = false; bool requeue_recovery_snapset = false; bool requeue_snaptrimmer = false; bool requeue_snaptrimmer_clone = false; bool requeue_snaptrimmer_snapset = false; switch (ctx->lock_to_release) { case OpContext::W_LOCK: if (ctx->snapset_obc && ctx->release_snapset_obc) { ctx->snapset_obc->put_write( &to_req, &requeue_recovery_snapset, &requeue_snaptrimmer_snapset); ctx->release_snapset_obc = false; } ctx->obc->put_write( &to_req, &requeue_recovery, &requeue_snaptrimmer); if (ctx->clone_obc) ctx->clone_obc->put_write( &to_req, &requeue_recovery_clone, &requeue_snaptrimmer_clone); break; case OpContext::R_LOCK: if (ctx->snapset_obc && ctx->release_snapset_obc) { ctx->snapset_obc->put_read(&to_req); ctx->release_snapset_obc = false; } ctx->obc->put_read(&to_req); break; case OpContext::NONE: break; default: assert(0); }; assert(ctx->release_snapset_obc == false); ctx->lock_to_release = OpContext::NONE; if (requeue_recovery || requeue_recovery_clone || requeue_recovery_snapset) osd->recovery_wq.queue(this); if (requeue_snaptrimmer || requeue_snaptrimmer_clone || requeue_snaptrimmer_snapset) queue_snap_trim(); requeue_ops(to_req); } // replica ops // [primary|tail] xlist repop_queue; map repop_map; friend class C_OSD_RepopApplied; friend class C_OSD_RepopCommit; void repop_all_applied(RepGather *repop); void repop_all_committed(RepGather *repop); void eval_repop(RepGather*); void issue_repop(RepGather *repop, utime_t now); RepGather *new_repop(OpContext *ctx, ObjectContextRef obc, ceph_tid_t rep_tid); void remove_repop(RepGather *repop); RepGather *simple_repop_create(ObjectContextRef obc); void simple_repop_submit(RepGather *repop); // hot/cold tracking HitSetRef hit_set; ///< currently accumulating HitSet utime_t hit_set_start_stamp; ///< time the current HitSet started recording map hit_set_flushing; ///< currently being written, not yet readable void hit_set_clear(); ///< discard any HitSet state void hit_set_setup(); ///< initialize HitSet state void hit_set_create(); ///< create a new HitSet void hit_set_persist(); ///< persist hit info bool hit_set_apply_log(); ///< apply log entries to update in-memory HitSet void hit_set_trim(RepGather *repop, unsigned max); ///< discard old HitSets void hit_set_in_memory_trim(); ///< discard old in memory HitSets hobject_t get_hit_set_current_object(utime_t stamp); hobject_t get_hit_set_archive_object(utime_t start, utime_t end); // agent boost::scoped_ptr agent_state; friend class C_AgentFlushStartStop; friend class C_HitSetFlushing; void agent_setup(); ///< initialize agent state bool agent_work(int max); ///< entry point to do some agent work bool agent_maybe_flush(ObjectContextRef& obc); ///< maybe flush bool agent_maybe_evict(ObjectContextRef& obc); ///< maybe evict void agent_load_hit_sets(); ///< load HitSets, if needed /// estimate object atime and temperature /// /// @param oid [in] object name /// @param atime [out] seconds since last access (lower bound) /// @param temperature [out] relative temperature (# hitset bins we appear in) void agent_estimate_atime_temp(const hobject_t& oid, int *atime, int *temperature); /// stop the agent void agent_stop(); void agent_delay(); /// clear agent state void agent_clear(); void agent_choose_mode(bool restart = false); ///< choose (new) agent mode(s) void agent_choose_mode_restart(); /// true if we can send an ondisk/commit for v bool already_complete(eversion_t v) { for (xlist::iterator i = repop_queue.begin(); !i.end(); ++i) { // skip copy from temp object ops if ((*i)->v == eversion_t()) continue; if ((*i)->v > v) break; if (!(*i)->all_committed) return false; } return true; } /// true if we can send an ack for v bool already_ack(eversion_t v) { for (xlist::iterator i = repop_queue.begin(); !i.end(); ++i) { // skip copy from temp object ops if ((*i)->v == eversion_t()) continue; if ((*i)->v > v) break; if (!(*i)->all_applied) return false; } return true; } friend struct C_OnPushCommit; // projected object info SharedPtrRegistry object_contexts; // map from oid.snapdir() to SnapSetContext * map snapset_contexts; Mutex snapset_contexts_lock; // debug order that client ops are applied map > debug_op_order; void populate_obc_watchers(ObjectContextRef obc); void check_blacklisted_obc_watchers(ObjectContextRef obc); void check_blacklisted_watchers(); void get_watchers(list &pg_watchers); void get_obc_watchers(ObjectContextRef obc, list &pg_watchers); public: void handle_watch_timeout(WatchRef watch); protected: ObjectContextRef create_object_context(const object_info_t& oi, SnapSetContext *ssc); ObjectContextRef get_object_context( const hobject_t& soid, bool can_create, map *attrs = 0 ); void context_registry_on_change(); void object_context_destructor_callback(ObjectContext *obc); struct C_PG_ObjectContext : public Context { ReplicatedPGRef pg; ObjectContext *obc; C_PG_ObjectContext(ReplicatedPG *p, ObjectContext *o) : pg(p), obc(o) {} void finish(int r) { pg->object_context_destructor_callback(obc); } }; int find_object_context(const hobject_t& oid, ObjectContextRef *pobc, bool can_create, bool map_snapid_to_clone=false, hobject_t *missing_oid=NULL); void add_object_context_to_pg_stat(ObjectContextRef obc, pg_stat_t *stat); void get_src_oloc(const object_t& oid, const object_locator_t& oloc, object_locator_t& src_oloc); SnapSetContext *create_snapset_context(const hobject_t& oid); SnapSetContext *get_snapset_context( const hobject_t& oid, bool can_create, map *attrs = 0 ); void register_snapset_context(SnapSetContext *ssc) { Mutex::Locker l(snapset_contexts_lock); _register_snapset_context(ssc); } void _register_snapset_context(SnapSetContext *ssc) { assert(snapset_contexts_lock.is_locked()); if (!ssc->registered) { assert(snapset_contexts.count(ssc->oid) == 0); ssc->registered = true; snapset_contexts[ssc->oid] = ssc; } } void put_snapset_context(SnapSetContext *ssc); map recovering; /* * Backfill * * peer_info[backfill_target].last_backfill == info.last_backfill on the peer. * * objects prior to peer_info[backfill_target].last_backfill * - are on the peer * - are included in the peer stats * * objects \in (last_backfill, last_backfill_started] * - are on the peer or are in backfills_in_flight * - are not included in pg stats (yet) * - have their stats in pending_backfill_updates on the primary */ set backfills_in_flight; map pending_backfill_updates; void dump_recovery_info(Formatter *f) const { f->open_array_section("backfill_targets"); for (set::const_iterator p = backfill_targets.begin(); p != backfill_targets.end(); ++p) f->dump_stream("replica") << *p; f->close_section(); f->open_array_section("waiting_on_backfill"); for (set::const_iterator p = waiting_on_backfill.begin(); p != waiting_on_backfill.end(); ++p) f->dump_stream("osd") << *p; f->close_section(); f->dump_stream("last_backfill_started") << last_backfill_started; { f->open_object_section("backfill_info"); backfill_info.dump(f); f->close_section(); } { f->open_array_section("peer_backfill_info"); for (map::const_iterator pbi = peer_backfill_info.begin(); pbi != peer_backfill_info.end(); ++pbi) { f->dump_stream("osd") << pbi->first; f->open_object_section("BackfillInterval"); pbi->second.dump(f); f->close_section(); } f->close_section(); } { f->open_array_section("backfills_in_flight"); for (set::const_iterator i = backfills_in_flight.begin(); i != backfills_in_flight.end(); ++i) { f->dump_stream("object") << *i; } f->close_section(); } { f->open_array_section("recovering"); for (map::const_iterator i = recovering.begin(); i != recovering.end(); ++i) { f->dump_stream("object") << i->first; } f->close_section(); } { f->open_object_section("pg_backend"); pgbackend->dump_recovery_info(f); f->close_section(); } } /// last backfill operation started hobject_t last_backfill_started; bool new_backfill; int prep_object_replica_pushes(const hobject_t& soid, eversion_t v, PGBackend::RecoveryHandle *h); void finish_degraded_object(const hobject_t& oid); // Cancels/resets pulls from peer void check_recovery_sources(const OSDMapRef map); int recover_missing( const hobject_t& oid, eversion_t v, int priority, PGBackend::RecoveryHandle *h); // low level ops void _make_clone( OpContext *ctx, PGBackend::PGTransaction* t, ObjectContextRef obc, const hobject_t& head, const hobject_t& coid, object_info_t *poi); void execute_ctx(OpContext *ctx); void finish_ctx(OpContext *ctx, int log_op_type, bool maintain_ssc=true); void reply_ctx(OpContext *ctx, int err); void reply_ctx(OpContext *ctx, int err, eversion_t v, version_t uv); void make_writeable(OpContext *ctx); void log_op_stats(OpContext *ctx); void write_update_size_and_usage(object_stat_sum_t& stats, object_info_t& oi, SnapSet& ss, interval_set& modified, uint64_t offset, uint64_t length, bool count_bytes); void add_interval_usage(interval_set& s, object_stat_sum_t& st); /** * This helper function is called from do_op if the ObjectContext lookup fails. * @returns true if the caching code is handling the Op, false otherwise. */ inline bool maybe_handle_cache(OpRequestRef op, bool write_ordered, ObjectContextRef obc, int r, const hobject_t& missing_oid, bool must_promote, bool in_hit_set = false); /** * This helper function tells the client to redirect their request elsewhere. */ void do_cache_redirect(OpRequestRef op, ObjectContextRef obc); /** * This function attempts to start a promote. Either it succeeds, * or places op on a wait list. If op is null, failure means that * this is a noop. If a future user wants to be able to distinguish * these cases, a return value should be added. */ void promote_object(OpRequestRef op, ObjectContextRef obc, const hobject_t& missing_object); /** * Check if the op is such that we can skip promote (e.g., DELETE) */ bool can_skip_promote(OpRequestRef op, ObjectContextRef obc); int prepare_transaction(OpContext *ctx); list > in_progress_async_reads; void complete_read_ctx(int result, OpContext *ctx); // pg on-disk content void check_local(); void _clear_recovery_state(); void queue_for_recovery(); bool start_recovery_ops( int max, RecoveryCtx *prctx, ThreadPool::TPHandle &handle, int *started); int recover_primary(int max, ThreadPool::TPHandle &handle); int recover_replicas(int max, ThreadPool::TPHandle &handle); hobject_t earliest_peer_backfill() const; bool all_peer_done() const; /** * @param work_started will be set to true if recover_backfill got anywhere * @returns the number of operations started */ int recover_backfill(int max, ThreadPool::TPHandle &handle, bool *work_started); /** * scan a (hash) range of objects in the current pg * * @begin first item should be >= this value * @min return at least this many items, unless we are done * @max return no more than this many items * @bi [out] resulting map of objects to eversion_t's */ void scan_range( int min, int max, BackfillInterval *bi, ThreadPool::TPHandle &handle ); /// Update a hash range to reflect changes since the last scan void update_range( BackfillInterval *bi, ///< [in,out] interval to update ThreadPool::TPHandle &handle ///< [in] tp handle ); void prep_backfill_object_push( hobject_t oid, eversion_t v, ObjectContextRef obc, vector peers, PGBackend::RecoveryHandle *h); void send_remove_op(const hobject_t& oid, eversion_t v, pg_shard_t peer); struct C_OSD_OndiskWriteUnlock : public Context { ObjectContextRef obc, obc2, obc3; C_OSD_OndiskWriteUnlock( ObjectContextRef o, ObjectContextRef o2 = ObjectContextRef(), ObjectContextRef o3 = ObjectContextRef()) : obc(o), obc2(o2), obc3(o3) {} void finish(int r) { obc->ondisk_write_unlock(); if (obc2) obc2->ondisk_write_unlock(); if (obc3) obc3->ondisk_write_unlock(); } }; struct C_OSD_OndiskWriteUnlockList : public Context { list *pls; C_OSD_OndiskWriteUnlockList(list *l) : pls(l) {} void finish(int r) { for (list::iterator p = pls->begin(); p != pls->end(); ++p) (*p)->ondisk_write_unlock(); } }; struct C_OSD_AppliedRecoveredObject : public Context { ReplicatedPGRef pg; ObjectContextRef obc; C_OSD_AppliedRecoveredObject(ReplicatedPG *p, ObjectContextRef o) : pg(p), obc(o) {} void finish(int r) { pg->_applied_recovered_object(obc); } }; struct C_OSD_CommittedPushedObject : public Context { ReplicatedPGRef pg; epoch_t epoch; eversion_t last_complete; C_OSD_CommittedPushedObject( ReplicatedPG *p, epoch_t epoch, eversion_t lc) : pg(p), epoch(epoch), last_complete(lc) { } void finish(int r) { pg->_committed_pushed_object(epoch, last_complete); } }; struct C_OSD_AppliedRecoveredObjectReplica : public Context { ReplicatedPGRef pg; C_OSD_AppliedRecoveredObjectReplica(ReplicatedPG *p) : pg(p) {} void finish(int r) { pg->_applied_recovered_object_replica(); } }; void sub_op_remove(OpRequestRef op); void _applied_recovered_object(ObjectContextRef obc); void _applied_recovered_object_replica(); void _committed_pushed_object(epoch_t epoch, eversion_t lc); void recover_got(hobject_t oid, eversion_t v); // -- copyfrom -- map copy_ops; int fill_in_copy_get( OpContext *ctx, bufferlist::iterator& bp, OSDOp& op, ObjectContextRef& obc, bool classic); /** * To copy an object, call start_copy. * * @param cb: The CopyCallback to be activated when the copy is complete * @param obc: The ObjectContext we are copying into * @param src: The source object * @param oloc: the source object locator * @param version: the version of the source object to copy (0 for any) * @param temp_dest_oid: the temporary object to use for large objects */ void start_copy(CopyCallback *cb, ObjectContextRef obc, hobject_t src, object_locator_t oloc, version_t version, unsigned flags, bool mirror_snapset); void process_copy_chunk(hobject_t oid, ceph_tid_t tid, int r); void _write_copy_chunk(CopyOpRef cop, PGBackend::PGTransaction *t); uint64_t get_copy_chunk_size() const { uint64_t size = cct->_conf->osd_copyfrom_max_chunk; if (pool.info.requires_aligned_append()) { uint64_t alignment = pool.info.required_alignment(); if (size % alignment) { size += alignment - (size % alignment); } } return size; } void _copy_some(ObjectContextRef obc, CopyOpRef cop); void _build_finish_copy_transaction(CopyOpRef cop, PGBackend::PGTransaction *t); void finish_copyfrom(OpContext *ctx); void finish_promote(int r, OpRequestRef op, CopyResults *results, ObjectContextRef obc); void cancel_copy(CopyOpRef cop, bool requeue); void cancel_copy_ops(bool requeue); friend struct C_Copyfrom; // -- flush -- map flush_ops; /// start_flush takes ownership of on_flush iff ret == -EINPROGRESS int start_flush( OpRequestRef op, ObjectContextRef obc, bool blocking, hobject_t *pmissing, Context *on_flush); void finish_flush(hobject_t oid, ceph_tid_t tid, int r); int try_flush_mark_clean(FlushOpRef fop); void cancel_flush(FlushOpRef fop, bool requeue); void cancel_flush_ops(bool requeue); /// @return false if clone is has been evicted bool is_present_clone(hobject_t coid); friend struct C_Flush; // -- scrub -- virtual bool _range_available_for_scrub( const hobject_t &begin, const hobject_t &end); virtual void _scrub(ScrubMap& map); virtual void _scrub_clear_state(); virtual void _scrub_finish(); object_stat_collection_t scrub_cstat; virtual void _split_into(pg_t child_pgid, PG *child, unsigned split_bits); void apply_and_flush_repops(bool requeue); void calc_trim_to(); int do_xattr_cmp_u64(int op, __u64 v1, bufferlist& xattr); int do_xattr_cmp_str(int op, string& v1s, bufferlist& xattr); bool pgls_filter(PGLSFilter *filter, hobject_t& sobj, bufferlist& outdata); int get_pgls_filter(bufferlist::iterator& iter, PGLSFilter **pfilter); public: ReplicatedPG(OSDService *o, OSDMapRef curmap, const PGPool &_pool, spg_t p, const hobject_t& oid, const hobject_t& ioid); ~ReplicatedPG() {} int do_command(cmdmap_t cmdmap, ostream& ss, bufferlist& idata, bufferlist& odata); void do_request( OpRequestRef op, ThreadPool::TPHandle &handle); void do_op(OpRequestRef op); bool pg_op_must_wait(MOSDOp *op); void do_pg_op(OpRequestRef op); void do_sub_op(OpRequestRef op); void do_sub_op_reply(OpRequestRef op); void do_scan( OpRequestRef op, ThreadPool::TPHandle &handle); void do_backfill(OpRequestRef op); RepGather *trim_object(const hobject_t &coid); void snap_trimmer(); int do_osd_ops(OpContext *ctx, vector& ops); int _get_tmap(OpContext *ctx, bufferlist *header, bufferlist *vals); int do_tmap2omap(OpContext *ctx, unsigned flags); int do_tmapup(OpContext *ctx, bufferlist::iterator& bp, OSDOp& osd_op); int do_tmapup_slow(OpContext *ctx, bufferlist::iterator& bp, OSDOp& osd_op, bufferlist& bl); void do_osd_op_effects(OpContext *ctx); private: hobject_t earliest_backfill() const; bool check_src_targ(const hobject_t& soid, const hobject_t& toid) const; uint64_t temp_seq; ///< last id for naming temp objects coll_t get_temp_coll(ObjectStore::Transaction *t); hobject_t generate_temp_object(); ///< generate a new temp object name public: void get_colls(list *out) { out->push_back(coll); return pgbackend->temp_colls(out); } void split_colls( spg_t child, int split_bits, int seed, ObjectStore::Transaction *t) { coll_t target = coll_t(child); t->create_collection(target); t->split_collection( coll, split_bits, seed, target); pgbackend->split_colls(child, split_bits, seed, t); } private: struct NotTrimming; struct SnapTrim : boost::statechart::event< SnapTrim > { SnapTrim() : boost::statechart::event < SnapTrim >() {} }; struct Reset : boost::statechart::event< Reset > { Reset() : boost::statechart::event< Reset >() {} }; struct SnapTrimmer : public boost::statechart::state_machine< SnapTrimmer, NotTrimming > { ReplicatedPG *pg; set repops; snapid_t snap_to_trim; bool need_share_pg_info; SnapTrimmer(ReplicatedPG *pg) : pg(pg), need_share_pg_info(false) {} ~SnapTrimmer(); void log_enter(const char *state_name); void log_exit(const char *state_name, utime_t duration); } snap_trimmer_machine; /* SnapTrimmerStates */ struct TrimmingObjects : boost::statechart::state< TrimmingObjects, SnapTrimmer >, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< SnapTrim >, boost::statechart::transition< Reset, NotTrimming > > reactions; hobject_t pos; TrimmingObjects(my_context ctx); void exit(); boost::statechart::result react(const SnapTrim&); }; struct WaitingOnReplicas : boost::statechart::state< WaitingOnReplicas, SnapTrimmer >, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< SnapTrim >, boost::statechart::transition< Reset, NotTrimming > > reactions; WaitingOnReplicas(my_context ctx); void exit(); boost::statechart::result react(const SnapTrim&); }; struct NotTrimming : boost::statechart::state< NotTrimming, SnapTrimmer >, NamedState { typedef boost::mpl::list < boost::statechart::custom_reaction< SnapTrim >, boost::statechart::transition< Reset, NotTrimming > > reactions; NotTrimming(my_context ctx); void exit(); boost::statechart::result react(const SnapTrim&); }; int _verify_no_head_clones(const hobject_t& soid, const SnapSet& ss); int _delete_oid(OpContext *ctx, bool no_whiteout); int _rollback_to(OpContext *ctx, ceph_osd_op& op); public: bool is_missing_object(const hobject_t& oid) const; bool is_unreadable_object(const hobject_t &oid) const { return is_missing_object(oid) || !missing_loc.readable_with_acting(oid, actingset); } void wait_for_unreadable_object(const hobject_t& oid, OpRequestRef op); void wait_for_all_missing(OpRequestRef op); bool is_degraded_object(const hobject_t& oid); void wait_for_degraded_object(const hobject_t& oid, OpRequestRef op); bool maybe_await_blocked_snapset(const hobject_t &soid, OpRequestRef op); void wait_for_blocked_object(const hobject_t& soid, OpRequestRef op); void kick_object_context_blocked(ObjectContextRef obc); void mark_all_unfound_lost(int what); eversion_t pick_newest_available(const hobject_t& oid); ObjectContextRef mark_object_lost(ObjectStore::Transaction *t, const hobject_t& oid, eversion_t version, utime_t mtime, int what); void _finish_mark_all_unfound_lost(list& obcs); void on_role_change(); void on_pool_change(); void on_change(ObjectStore::Transaction *t); void on_activate(); void on_flushed(); void on_removal(ObjectStore::Transaction *t); void on_shutdown(); // attr cache handling void replace_cached_attrs( OpContext *ctx, ObjectContextRef obc, const map &new_attrs); void setattr_maybe_cache( ObjectContextRef obc, OpContext *op, PGBackend::PGTransaction *t, const string &key, bufferlist &val); void rmattr_maybe_cache( ObjectContextRef obc, OpContext *op, PGBackend::PGTransaction *t, const string &key); int getattr_maybe_cache( ObjectContextRef obc, const string &key, bufferlist *val); int getattrs_maybe_cache( ObjectContextRef obc, map *out, bool user_only = false); }; inline ostream& operator<<(ostream& out, ReplicatedPG::RepGather& repop) { out << "repgather(" << &repop << " " << repop.v << " rep_tid=" << repop.rep_tid << " committed?=" << repop.all_committed << " applied?=" << repop.all_applied; if (repop.ctx->lock_to_release != ReplicatedPG::OpContext::NONE) out << " lock=" << (int)repop.ctx->lock_to_release; if (repop.ctx->op) out << " op=" << *(repop.ctx->op->get_req()); out << ")"; return out; } void intrusive_ptr_add_ref(ReplicatedPG::RepGather *repop); void intrusive_ptr_release(ReplicatedPG::RepGather *repop); #endif ceph-0.80.11/src/osd/Watch.cc0000664000175100017510000002404712623076744017635 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "PG.h" #include "include/types.h" #include "messages/MWatchNotify.h" #include #include "OSD.h" #include "ReplicatedPG.h" #include "Watch.h" #include "common/config.h" struct CancelableContext : public Context { virtual void cancel() = 0; }; #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout, this) static ostream& _prefix( std::ostream* _dout, Notify *notify) { return *_dout << notify->gen_dbg_prefix(); } Notify::Notify( ConnectionRef client, unsigned num_watchers, bufferlist &payload, uint32_t timeout, uint64_t cookie, uint64_t notify_id, uint64_t version, OSDService *osd) : client(client), in_progress_watchers(num_watchers), complete(false), discarded(false), payload(payload), timeout(timeout), cookie(cookie), notify_id(notify_id), version(version), osd(osd), cb(NULL), lock("Notify::lock") {} NotifyRef Notify::makeNotifyRef( ConnectionRef client, unsigned num_watchers, bufferlist &payload, uint32_t timeout, uint64_t cookie, uint64_t notify_id, uint64_t version, OSDService *osd) { NotifyRef ret( new Notify( client, num_watchers, payload, timeout, cookie, notify_id, version, osd)); ret->set_self(ret); return ret; } class NotifyTimeoutCB : public CancelableContext { NotifyRef notif; bool canceled; // protected by notif lock public: NotifyTimeoutCB(NotifyRef notif) : notif(notif), canceled(false) {} void finish(int) { notif->osd->watch_lock.Unlock(); notif->lock.Lock(); if (!canceled) notif->do_timeout(); // drops lock else notif->lock.Unlock(); notif->osd->watch_lock.Lock(); } void cancel() { assert(notif->lock.is_locked_by_me()); canceled = true; } }; void Notify::do_timeout() { assert(lock.is_locked_by_me()); dout(10) << "timeout" << dendl; cb = NULL; if (is_discarded()) { lock.Unlock(); return; } in_progress_watchers = 0; // we give up TODO: we should return an error code maybe_complete_notify(); assert(complete); set _watchers; _watchers.swap(watchers); lock.Unlock(); for (set::iterator i = _watchers.begin(); i != _watchers.end(); ++i) { boost::intrusive_ptr pg((*i)->get_pg()); pg->lock(); if (!(*i)->is_discarded()) { (*i)->cancel_notify(self.lock()); } pg->unlock(); } } void Notify::register_cb() { assert(lock.is_locked_by_me()); { osd->watch_lock.Lock(); cb = new NotifyTimeoutCB(self.lock()); osd->watch_timer.add_event_after( timeout, cb); osd->watch_lock.Unlock(); } } void Notify::unregister_cb() { assert(lock.is_locked_by_me()); if (!cb) return; cb->cancel(); { osd->watch_lock.Lock(); osd->watch_timer.cancel_event(cb); cb = NULL; osd->watch_lock.Unlock(); } } void Notify::start_watcher(WatchRef watch) { Mutex::Locker l(lock); dout(10) << "start_watcher" << dendl; watchers.insert(watch); } void Notify::complete_watcher(WatchRef watch) { Mutex::Locker l(lock); dout(10) << "complete_watcher" << dendl; if (is_discarded()) return; assert(in_progress_watchers > 0); watchers.erase(watch); --in_progress_watchers; maybe_complete_notify(); } void Notify::maybe_complete_notify() { dout(10) << "maybe_complete_notify -- " << in_progress_watchers << " in progress watchers " << dendl; if (!in_progress_watchers) { MWatchNotify *reply(new MWatchNotify(cookie, version, notify_id, WATCH_NOTIFY, payload)); osd->send_message_osd_client(reply, client.get()); unregister_cb(); complete = true; } } void Notify::discard() { Mutex::Locker l(lock); discarded = true; unregister_cb(); watchers.clear(); } void Notify::init() { Mutex::Locker l(lock); register_cb(); maybe_complete_notify(); assert(in_progress_watchers == watchers.size()); } #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout, watch.get()) static ostream& _prefix( std::ostream* _dout, Watch *watch) { return *_dout << watch->gen_dbg_prefix(); } class HandleWatchTimeout : public CancelableContext { WatchRef watch; public: bool canceled; // protected by watch->pg->lock HandleWatchTimeout(WatchRef watch) : watch(watch), canceled(false) {} void cancel() { canceled = true; } void finish(int) { assert(0); /* not used */ } void complete(int) { dout(10) << "HandleWatchTimeout" << dendl; boost::intrusive_ptr pg(watch->pg); OSDService *osd(watch->osd); osd->watch_lock.Unlock(); pg->lock(); watch->cb = NULL; if (!watch->is_discarded() && !canceled) watch->pg->handle_watch_timeout(watch); delete this; // ~Watch requires pg lock! pg->unlock(); osd->watch_lock.Lock(); } }; class HandleDelayedWatchTimeout : public CancelableContext { WatchRef watch; public: bool canceled; HandleDelayedWatchTimeout(WatchRef watch) : watch(watch), canceled(false) {} void cancel() { canceled = true; } void finish(int) { dout(10) << "HandleWatchTimeoutDelayed" << dendl; assert(watch->pg->is_locked()); watch->cb = NULL; if (!watch->is_discarded() && !canceled) watch->pg->handle_watch_timeout(watch); } }; #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _prefix(_dout, this) string Watch::gen_dbg_prefix() { stringstream ss; ss << pg->gen_prefix() << " -- Watch(" << make_pair(cookie, entity) << ") "; return ss.str(); } Watch::Watch( ReplicatedPG *pg, OSDService *osd, ObjectContextRef obc, uint32_t timeout, uint64_t cookie, entity_name_t entity, const entity_addr_t &addr) : cb(NULL), osd(osd), pg(pg), obc(obc), timeout(timeout), cookie(cookie), addr(addr), entity(entity), discarded(false) { dout(10) << "Watch()" << dendl; } Watch::~Watch() { dout(10) << "~Watch" << dendl; // users must have called remove() or discard() prior to this point assert(!obc); assert(!conn); } bool Watch::connected() { return conn; } Context *Watch::get_delayed_cb() { assert(!cb); cb = new HandleDelayedWatchTimeout(self.lock()); return cb; } void Watch::register_cb() { Mutex::Locker l(osd->watch_lock); dout(15) << "registering callback, timeout: " << timeout << dendl; cb = new HandleWatchTimeout(self.lock()); osd->watch_timer.add_event_after( timeout, cb); } void Watch::unregister_cb() { dout(15) << "unregister_cb" << dendl; if (!cb) return; dout(15) << "actually registered, cancelling" << dendl; cb->cancel(); { Mutex::Locker l(osd->watch_lock); osd->watch_timer.cancel_event(cb); // harmless if not registered with timer } cb = NULL; } void Watch::connect(ConnectionRef con) { dout(10) << "connecting" << dendl; conn = con; OSD::Session* sessionref(static_cast(con->get_priv())); sessionref->wstate.addWatch(self.lock()); sessionref->put(); for (map::iterator i = in_progress_notifies.begin(); i != in_progress_notifies.end(); ++i) { send_notify(i->second); } unregister_cb(); } void Watch::disconnect() { dout(10) << "disconnect" << dendl; conn = ConnectionRef(); register_cb(); } void Watch::discard() { dout(10) << "discard" << dendl; for (map::iterator i = in_progress_notifies.begin(); i != in_progress_notifies.end(); ++i) { i->second->discard(); } discard_state(); } void Watch::discard_state() { assert(pg->is_locked()); assert(!discarded); assert(obc); in_progress_notifies.clear(); unregister_cb(); discarded = true; if (conn) { OSD::Session* sessionref(static_cast(conn->get_priv())); sessionref->wstate.removeWatch(self.lock()); sessionref->put(); conn = ConnectionRef(); } obc = ObjectContextRef(); } bool Watch::is_discarded() { return discarded; } void Watch::remove() { dout(10) << "remove" << dendl; for (map::iterator i = in_progress_notifies.begin(); i != in_progress_notifies.end(); ++i) { i->second->complete_watcher(self.lock()); } discard_state(); } void Watch::start_notify(NotifyRef notif) { dout(10) << "start_notify " << notif->notify_id << dendl; assert(in_progress_notifies.find(notif->notify_id) == in_progress_notifies.end()); in_progress_notifies[notif->notify_id] = notif; notif->start_watcher(self.lock()); if (connected()) send_notify(notif); } void Watch::cancel_notify(NotifyRef notif) { dout(10) << "cancel_notify " << notif->notify_id << dendl; in_progress_notifies.erase(notif->notify_id); } void Watch::send_notify(NotifyRef notif) { dout(10) << "send_notify" << dendl; MWatchNotify *notify_msg = new MWatchNotify( cookie, notif->version, notif->notify_id, WATCH_NOTIFY, notif->payload); osd->send_message_osd_client(notify_msg, conn.get()); } void Watch::notify_ack(uint64_t notify_id) { dout(10) << "notify_ack" << dendl; map::iterator i = in_progress_notifies.find(notify_id); if (i != in_progress_notifies.end()) { i->second->complete_watcher(self.lock()); in_progress_notifies.erase(i); } } WatchRef Watch::makeWatchRef( ReplicatedPG *pg, OSDService *osd, ObjectContextRef obc, uint32_t timeout, uint64_t cookie, entity_name_t entity, const entity_addr_t& addr) { WatchRef ret(new Watch(pg, osd, obc, timeout, cookie, entity, addr)); ret->set_self(ret); return ret; } void WatchConState::addWatch(WatchRef watch) { Mutex::Locker l(lock); watches.insert(watch); } void WatchConState::removeWatch(WatchRef watch) { Mutex::Locker l(lock); watches.erase(watch); } void WatchConState::reset() { set _watches; { Mutex::Locker l(lock); _watches.swap(watches); } for (set::iterator i = _watches.begin(); i != _watches.end(); ++i) { boost::intrusive_ptr pg((*i)->get_pg()); pg->lock(); if (!(*i)->is_discarded()) { (*i)->disconnect(); } pg->unlock(); } } ceph-0.80.11/src/osd/ECTransaction.cc0000664000175100017510000002065112623076744021261 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "ECBackend.h" #include "ECUtil.h" #include "os/ObjectStore.h" struct AppendObjectsGenerator: public boost::static_visitor { typedef void result_type; set *out; AppendObjectsGenerator(set *out) : out(out) {} void operator()(const ECTransaction::AppendOp &op) { out->insert(op.oid); } void operator()(const ECTransaction::TouchOp &op) {} void operator()(const ECTransaction::CloneOp &op) { out->insert(op.source); out->insert(op.target); } void operator()(const ECTransaction::RenameOp &op) { out->insert(op.source); out->insert(op.destination); } void operator()(const ECTransaction::StashOp &op) { out->insert(op.oid); } void operator()(const ECTransaction::RemoveOp &op) { out->insert(op.oid); } void operator()(const ECTransaction::SetAttrsOp &op) {} void operator()(const ECTransaction::RmAttrOp &op) {} void operator()(const ECTransaction::AllocHintOp &op) {} void operator()(const ECTransaction::NoOp &op) {} }; void ECTransaction::get_append_objects( set *out) const { AppendObjectsGenerator gen(out); reverse_visit(gen); } struct TransGenerator : public boost::static_visitor { typedef void result_type; map &hash_infos; ErasureCodeInterfaceRef &ecimpl; const pg_t pgid; const ECUtil::stripe_info_t sinfo; map *trans; set want; set *temp_added; set *temp_removed; stringstream *out; TransGenerator( map &hash_infos, ErasureCodeInterfaceRef &ecimpl, pg_t pgid, const ECUtil::stripe_info_t &sinfo, map *trans, set *temp_added, set *temp_removed, stringstream *out) : hash_infos(hash_infos), ecimpl(ecimpl), pgid(pgid), sinfo(sinfo), trans(trans), temp_added(temp_added), temp_removed(temp_removed), out(out) { for (unsigned i = 0; i < ecimpl->get_chunk_count(); ++i) { want.insert(i); } } coll_t get_coll_ct(shard_id_t shard, const hobject_t &hoid) { if (hoid.is_temp()) { temp_removed->erase(hoid); temp_added->insert(hoid); } return get_coll(shard, hoid); } coll_t get_coll_rm(shard_id_t shard, const hobject_t &hoid) { if (hoid.is_temp()) { temp_added->erase(hoid); temp_removed->insert(hoid); } return get_coll(shard, hoid); } coll_t get_coll(shard_id_t shard, const hobject_t &hoid) { if (hoid.is_temp()) return coll_t::make_temp_coll(spg_t(pgid, shard)); else return coll_t(spg_t(pgid, shard)); } void operator()(const ECTransaction::TouchOp &op) { for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.touch( get_coll_ct(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first)); } } void operator()(const ECTransaction::AppendOp &op) { uint64_t offset = op.off; bufferlist bl(op.bl); assert(bl.length()); assert(offset % sinfo.get_stripe_width() == 0); map buffers; assert(hash_infos.count(op.oid)); ECUtil::HashInfoRef hinfo = hash_infos[op.oid]; // align if (bl.length() % sinfo.get_stripe_width()) bl.append_zero( sinfo.get_stripe_width() - ((offset + bl.length()) % sinfo.get_stripe_width())); assert(bl.length() - op.bl.length() < sinfo.get_stripe_width()); int r = ECUtil::encode( sinfo, ecimpl, bl, want, &buffers); hinfo->append( sinfo.aligned_logical_offset_to_chunk_offset(op.off), buffers); bufferlist hbuf; ::encode( *hinfo, hbuf); assert(r == 0); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { assert(buffers.count(i->first)); bufferlist &enc_bl = buffers[i->first]; i->second.write( get_coll_ct(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first), sinfo.logical_to_prev_chunk_offset( offset), enc_bl.length(), enc_bl); i->second.setattr( get_coll_ct(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first), ECUtil::get_hinfo_key(), hbuf); } } void operator()(const ECTransaction::CloneOp &op) { assert(hash_infos.count(op.source)); assert(hash_infos.count(op.target)); *(hash_infos[op.target]) = *(hash_infos[op.source]); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.clone( get_coll_ct(i->first, op.source), ghobject_t(op.source, ghobject_t::NO_GEN, i->first), ghobject_t(op.target, ghobject_t::NO_GEN, i->first)); } } void operator()(const ECTransaction::RenameOp &op) { assert(hash_infos.count(op.source)); assert(hash_infos.count(op.destination)); *(hash_infos[op.destination]) = *(hash_infos[op.source]); hash_infos[op.source]->clear(); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.collection_move_rename( get_coll_rm(i->first, op.source), ghobject_t(op.source, ghobject_t::NO_GEN, i->first), get_coll_ct(i->first, op.destination), ghobject_t(op.destination, ghobject_t::NO_GEN, i->first)); } } void operator()(const ECTransaction::StashOp &op) { assert(hash_infos.count(op.oid)); hash_infos[op.oid]->clear(); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { coll_t cid(get_coll_rm(i->first, op.oid)); i->second.collection_move_rename( cid, ghobject_t(op.oid, ghobject_t::NO_GEN, i->first), cid, ghobject_t(op.oid, op.version, i->first)); } } void operator()(const ECTransaction::RemoveOp &op) { assert(hash_infos.count(op.oid)); hash_infos[op.oid]->clear(); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.remove( get_coll_rm(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first)); } } void operator()(const ECTransaction::SetAttrsOp &op) { map attrs(op.attrs); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.setattrs( get_coll_ct(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first), attrs); } } void operator()(const ECTransaction::RmAttrOp &op) { for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.rmattr( get_coll_ct(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first), op.key); } } void operator()(const ECTransaction::AllocHintOp &op) { // logical_to_next_chunk_offset() scales down both aligned and // unaligned offsets uint64_t object_size = sinfo.logical_to_next_chunk_offset( op.expected_object_size); uint64_t write_size = sinfo.logical_to_next_chunk_offset( op.expected_write_size); for (map::iterator i = trans->begin(); i != trans->end(); ++i) { i->second.set_alloc_hint( get_coll_ct(i->first, op.oid), ghobject_t(op.oid, ghobject_t::NO_GEN, i->first), object_size, write_size); } } void operator()(const ECTransaction::NoOp &op) {} }; void ECTransaction::generate_transactions( map &hash_infos, ErasureCodeInterfaceRef &ecimpl, pg_t pgid, const ECUtil::stripe_info_t &sinfo, map *transactions, set *temp_added, set *temp_removed, stringstream *out) const { TransGenerator gen( hash_infos, ecimpl, pgid, sinfo, transactions, temp_added, temp_removed, out); visit(gen); } ceph-0.80.11/src/osd/PGLog.h0000664000175100017510000004303612623076744017400 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_PG_LOG_H #define CEPH_PG_LOG_H // re-include our assert to clobber boost's #include "include/assert.h" #include "osd_types.h" #include "os/ObjectStore.h" #include "common/ceph_context.h" #include using namespace std; struct PGLog { ////////////////////////////// sub classes ////////////////////////////// struct LogEntryHandler { virtual void rollback( const pg_log_entry_t &entry) = 0; virtual void remove( const hobject_t &hoid) = 0; virtual void trim( const pg_log_entry_t &entry) = 0; virtual ~LogEntryHandler() {} }; /* Exceptions */ class read_log_error : public buffer::error { public: explicit read_log_error(const char *what) { snprintf(buf, sizeof(buf), "read_log_error: %s", what); } const char *what() const throw () { return buf; } private: char buf[512]; }; /** * IndexLog - adds in-memory index of the log, by oid. * plus some methods to manipulate it all. */ struct IndexedLog : public pg_log_t { ceph::unordered_map objects; // ptrs into log. be careful! ceph::unordered_map caller_ops; // recovery pointers list::iterator complete_to; // not inclusive of referenced item version_t last_requested; // last object requested by primary // private: /** * rollback_info_trimmed_to_riter points to the first log entry <= * rollback_info_trimmed_to * * It's a reverse_iterator because rend() is a natural representation for * tail, and rbegin() works nicely for head. */ list::reverse_iterator rollback_info_trimmed_to_riter; public: void advance_rollback_info_trimmed_to(eversion_t to, LogEntryHandler *h); /****/ IndexedLog() : complete_to(log.end()), last_requested(0), rollback_info_trimmed_to_riter(log.rbegin()) {} void claim_log_and_clear_rollback_info(const pg_log_t& o) { // we must have already trimmed the old entries assert(rollback_info_trimmed_to == head); assert(rollback_info_trimmed_to_riter == log.rbegin()); log = o.log; head = o.head; rollback_info_trimmed_to = head; tail = o.tail; index(); } void split_into( pg_t child_pgid, unsigned split_bits, IndexedLog *olog); void zero() { // we must have already trimmed the old entries assert(rollback_info_trimmed_to == head); assert(rollback_info_trimmed_to_riter == log.rbegin()); unindex(); pg_log_t::clear(); rollback_info_trimmed_to_riter = log.rbegin(); reset_recovery_pointers(); } void clear() { rollback_info_trimmed_to = head; rollback_info_trimmed_to_riter = log.rbegin(); zero(); } void reset_recovery_pointers() { complete_to = log.end(); last_requested = 0; } bool logged_object(const hobject_t& oid) const { return objects.count(oid); } bool logged_req(const osd_reqid_t &r) const { return caller_ops.count(r); } const pg_log_entry_t *get_request(const osd_reqid_t &r) const { ceph::unordered_map::const_iterator p = caller_ops.find(r); if (p == caller_ops.end()) return NULL; return p->second; } void index() { objects.clear(); caller_ops.clear(); for (list::iterator i = log.begin(); i != log.end(); ++i) { objects[i->soid] = &(*i); if (i->reqid_is_indexed()) { //assert(caller_ops.count(i->reqid) == 0); // divergent merge_log indexes new before unindexing old caller_ops[i->reqid] = &(*i); } } rollback_info_trimmed_to_riter = log.rbegin(); while (rollback_info_trimmed_to_riter != log.rend() && rollback_info_trimmed_to_riter->version > rollback_info_trimmed_to) rollback_info_trimmed_to_riter++; } void index(pg_log_entry_t& e) { if (objects.count(e.soid) == 0 || objects[e.soid]->version < e.version) objects[e.soid] = &e; if (e.reqid_is_indexed()) { //assert(caller_ops.count(i->reqid) == 0); // divergent merge_log indexes new before unindexing old caller_ops[e.reqid] = &e; } } void unindex() { objects.clear(); caller_ops.clear(); } void unindex(pg_log_entry_t& e) { // NOTE: this only works if we remove from the _tail_ of the log! if (objects.count(e.soid) && objects[e.soid]->version == e.version) objects.erase(e.soid); if (e.reqid_is_indexed() && caller_ops.count(e.reqid) && // divergent merge_log indexes new before unindexing old caller_ops[e.reqid] == &e) caller_ops.erase(e.reqid); } // actors void add(pg_log_entry_t& e) { // add to log log.push_back(e); // riter previously pointed to the previous entry if (rollback_info_trimmed_to_riter == log.rbegin()) ++rollback_info_trimmed_to_riter; assert(e.version > head); assert(head.version == 0 || e.version.version > head.version); head = e.version; // to our index objects[e.soid] = &(log.back()); if (e.reqid_is_indexed()) caller_ops[e.reqid] = &(log.back()); } void trim( LogEntryHandler *handler, eversion_t s, set *trimmed); ostream& print(ostream& out) const; }; protected: //////////////////// data members //////////////////// bool pg_log_debug; map divergent_priors; pg_missing_t missing; IndexedLog log; /// Log is clean on [dirty_to, dirty_from) bool touched_log; eversion_t dirty_to; ///< must clear/writeout all keys <= dirty_to eversion_t dirty_from; ///< must clear/writeout all keys >= dirty_from eversion_t writeout_from; ///< must writout keys >= writeout_from set trimmed; ///< must clear keys in trimmed bool dirty_divergent_priors; CephContext *cct; bool is_dirty() const { return !touched_log || (dirty_to != eversion_t()) || (dirty_from != eversion_t::max()) || dirty_divergent_priors || (writeout_from != eversion_t::max()) || !(trimmed.empty()); } void mark_dirty_to(eversion_t to) { if (to > dirty_to) dirty_to = to; } void mark_dirty_from(eversion_t from) { if (from < dirty_from) dirty_from = from; } void mark_writeout_from(eversion_t from) { if (from < writeout_from) writeout_from = from; } void add_divergent_prior(eversion_t version, hobject_t obj) { divergent_priors.insert(make_pair(version, obj)); dirty_divergent_priors = true; } public: void mark_log_for_rewrite() { mark_dirty_to(eversion_t::max()); mark_dirty_from(eversion_t()); touched_log = false; } protected: /// DEBUG set log_keys_debug; static void clear_after(set *log_keys_debug, const string &lb) { if (!log_keys_debug) return; for (set::iterator i = log_keys_debug->lower_bound(lb); i != log_keys_debug->end(); log_keys_debug->erase(i++)); } static void clear_up_to(set *log_keys_debug, const string &ub) { if (!log_keys_debug) return; for (set::iterator i = log_keys_debug->begin(); i != log_keys_debug->end() && *i < ub; log_keys_debug->erase(i++)); } void check(); void undirty() { dirty_to = eversion_t(); dirty_from = eversion_t::max(); dirty_divergent_priors = false; touched_log = true; trimmed.clear(); writeout_from = eversion_t::max(); check(); } public: PGLog(CephContext *cct = 0) : pg_log_debug(!(cct && !(cct->_conf->osd_debug_pg_log_writeout))), touched_log(false), dirty_from(eversion_t::max()), writeout_from(eversion_t::max()), dirty_divergent_priors(false), cct(cct) {} void reset_backfill(); void clear(); //////////////////// get or set missing //////////////////// const pg_missing_t& get_missing() const { return missing; } void missing_got(map::const_iterator m) { map::iterator p = missing.missing.find(m->first); missing.got(p); } void revise_have(hobject_t oid, eversion_t have) { missing.revise_have(oid, have); } void revise_need(hobject_t oid, eversion_t need) { missing.revise_need(oid, need); } void missing_add(const hobject_t& oid, eversion_t need, eversion_t have) { missing.add(oid, need, have); } void missing_rm(map::const_iterator m) { map::iterator p = missing.missing.find(m->first); missing.rm(p); } void missing_add_event(const pg_log_entry_t &e) { missing.add_next_event(e); } //////////////////// get or set log //////////////////// const IndexedLog &get_log() const { return log; } const eversion_t &get_tail() const { return log.tail; } void set_tail(eversion_t tail) { log.tail = tail; } const eversion_t &get_head() const { return log.head; } void set_head(eversion_t head) { log.head = head; } void set_last_requested(version_t last_requested) { log.last_requested = last_requested; } void index() { log.index(); } void unindex() { log.unindex(); } void add(pg_log_entry_t& e) { mark_writeout_from(e.version); log.add(e); } void reset_recovery_pointers() { log.reset_recovery_pointers(); } static void clear_info_log( spg_t pgid, const hobject_t &infos_oid, const hobject_t &log_oid, ObjectStore::Transaction *t); void trim( LogEntryHandler *handler, eversion_t trim_to, pg_info_t &info); void trim_rollback_info( eversion_t trim_rollback_to, LogEntryHandler *h) { if (trim_rollback_to > log.can_rollback_to) log.can_rollback_to = trim_rollback_to; log.advance_rollback_info_trimmed_to( trim_rollback_to, h); } eversion_t get_rollback_trimmed_to() const { return log.rollback_info_trimmed_to; } void clear_can_rollback_to(LogEntryHandler *h) { log.can_rollback_to = log.head; log.advance_rollback_info_trimmed_to( log.head, h); } //////////////////// get or set log & missing //////////////////// void claim_log_and_clear_rollback_info(const pg_log_t &o, LogEntryHandler *h) { log.can_rollback_to = log.head; log.advance_rollback_info_trimmed_to(log.head, h); log.claim_log_and_clear_rollback_info(o); missing.clear(); mark_dirty_to(eversion_t::max()); } void split_into( pg_t child_pgid, unsigned split_bits, PGLog *opg_log) { log.split_into(child_pgid, split_bits, &(opg_log->log)); missing.split_into(child_pgid, split_bits, &(opg_log->missing)); opg_log->mark_dirty_to(eversion_t::max()); mark_dirty_to(eversion_t::max()); unsigned mask = ~((~0)<::iterator i = divergent_priors.begin(); i != divergent_priors.end(); ) { if ((i->second.hash & mask) == child_pgid.m_seed) { opg_log->add_divergent_prior(i->first, i->second); divergent_priors.erase(i++); dirty_divergent_priors = true; } else { ++i; } } } void recover_got(hobject_t oid, eversion_t v, pg_info_t &info) { if (missing.is_missing(oid, v)) { missing.got(oid, v); // raise last_complete? if (missing.missing.empty()) { log.complete_to = log.log.end(); info.last_complete = info.last_update; } while (log.complete_to != log.log.end()) { if (missing.missing[missing.rmissing.begin()->second].need <= log.complete_to->version) break; if (info.last_complete < log.complete_to->version) info.last_complete = log.complete_to->version; ++log.complete_to; } } if (log.can_rollback_to < v) log.can_rollback_to = v; } void activate_not_complete(pg_info_t &info) { log.complete_to = log.log.begin(); while (log.complete_to->version < missing.missing[missing.rmissing.begin()->second].need) ++log.complete_to; assert(log.complete_to != log.log.end()); if (log.complete_to == log.log.begin()) { info.last_complete = eversion_t(); } else { --log.complete_to; info.last_complete = log.complete_to->version; ++log.complete_to; } log.last_requested = 0; } void proc_replica_log(ObjectStore::Transaction& t, pg_info_t &oinfo, const pg_log_t &olog, pg_missing_t& omissing, pg_shard_t from) const; protected: static void split_by_object( list &entries, map > *out_entries) { while (!entries.empty()) { list &out_list = (*out_entries)[entries.front().soid]; out_list.splice(out_list.end(), entries, entries.begin()); } } /** * Merge complete list of divergent entries for an object * * @param new_divergent_prior [out] filled out for a new divergent prior */ static void _merge_object_divergent_entries( const IndexedLog &log, ///< [in] log to merge against const hobject_t &hoid, ///< [in] object we are merging const list &entries, ///< [in] entries for hoid to merge const pg_info_t &oinfo, ///< [in] info for merging entries eversion_t olog_can_rollback_to, ///< [in] rollback boundary pg_missing_t &omissing, ///< [in,out] missing to adjust, use boost::optional > *new_divergent_prior, LogEntryHandler *rollbacker ///< [in] optional rollbacker object ); /// Merge all entries using above static void _merge_divergent_entries( const IndexedLog &log, ///< [in] log to merge against list &entries, ///< [in] entries to merge const pg_info_t &oinfo, ///< [in] info for merging entries eversion_t olog_can_rollback_to, ///< [in] rollback boundary pg_missing_t &omissing, ///< [in,out] missing to adjust, use map *priors, ///< [out] target for new priors LogEntryHandler *rollbacker ///< [in] optional rollbacker object ) { map > split; split_by_object(entries, &split); for (map >::iterator i = split.begin(); i != split.end(); ++i) { boost::optional > new_divergent_prior; _merge_object_divergent_entries( log, i->first, i->second, oinfo, olog_can_rollback_to, omissing, &new_divergent_prior, rollbacker); if (priors && new_divergent_prior) { (*priors)[new_divergent_prior->first] = new_divergent_prior->second; } } } /** * Exists for use in TestPGLog for simply testing single divergent log * cases */ void merge_old_entry( ObjectStore::Transaction& t, const pg_log_entry_t& oe, const pg_info_t& info, LogEntryHandler *rollbacker) { boost::optional > new_divergent_prior; list entries; entries.push_back(oe); _merge_object_divergent_entries( log, oe.soid, entries, info, log.can_rollback_to, missing, &new_divergent_prior, rollbacker); if (new_divergent_prior) add_divergent_prior( (*new_divergent_prior).first, (*new_divergent_prior).second); } public: void rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead, pg_info_t &info, LogEntryHandler *rollbacker, bool &dirty_info, bool &dirty_big_info); void merge_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, pg_shard_t from, pg_info_t &info, LogEntryHandler *rollbacker, bool &dirty_info, bool &dirty_big_info); void write_log(ObjectStore::Transaction& t, const hobject_t &log_oid); static void write_log(ObjectStore::Transaction& t, pg_log_t &log, const hobject_t &log_oid, map &divergent_priors); static void _write_log( ObjectStore::Transaction& t, pg_log_t &log, const hobject_t &log_oid, map &divergent_priors, eversion_t dirty_to, eversion_t dirty_from, eversion_t writeout_from, const set &trimmed, bool dirty_divergent_priors, bool touch_log, set *log_keys_debug ); bool read_log(ObjectStore *store, coll_t coll, hobject_t log_oid, const pg_info_t &info, ostringstream &oss) { return read_log( store, coll, log_oid, info, divergent_priors, log, missing, oss, (pg_log_debug ? &log_keys_debug : 0)); } /// return true if the log should be rewritten static bool read_log(ObjectStore *store, coll_t coll, hobject_t log_oid, const pg_info_t &info, map &divergent_priors, IndexedLog &log, pg_missing_t &missing, ostringstream &oss, set *log_keys_debug = 0 ); protected: static void read_log_old(ObjectStore *store, coll_t coll, hobject_t log_oid, const pg_info_t &info, map &divergent_priors, IndexedLog &log, pg_missing_t &missing, ostringstream &oss, set *log_keys_debug); }; #endif // CEPH_PG_LOG_H ceph-0.80.11/src/cls_crypto.cc0000664000175100017510000000302612623076744020155 0ustar jenkins-buildjenkins-build#include #include #include #include #include #include #include "include/types.h" #include "objclass/objclass.h" CLS_VER(1,0) CLS_NAME(crypto) cls_handle_t h_class; cls_method_handle_t h_md5; cls_method_handle_t h_sha1; int md5_method(cls_method_context_t ctx, char *indata, int datalen, char **outdata, int *outdatalen) { MD5_CTX c; unsigned char *md; cls_log("md5 method"); cls_log("indata=%.*s data_len=%d", datalen, indata, datalen); md = (unsigned char *)cls_alloc(MD5_DIGEST_LENGTH); if (!md) return -ENOMEM; MD5_Init(&c); MD5_Update(&c, indata, (unsigned long)datalen); MD5_Final(md,&c); *outdata = (char *)md; *outdatalen = MD5_DIGEST_LENGTH; return 0; } int sha1_method(cls_method_context_t ctx, char *indata, int datalen, char **outdata, int *outdatalen) { SHA_CTX c; unsigned char *md; cls_log("sha1 method"); cls_log("indata=%.*s data_len=%d", datalen, indata, datalen); md = (unsigned char *)cls_alloc(SHA_DIGEST_LENGTH); if (!md) return -ENOMEM; SHA1_Init(&c); SHA1_Update(&c, indata, (unsigned long)datalen); SHA1_Final(md,&c); *outdata = (char *)md; *outdatalen = SHA_DIGEST_LENGTH; return 0; } void __cls_init() { cls_log("Loaded crypto class!"); cls_register("crypto", &h_class); cls_register_method(h_class, "md5", CLS_METHOD_RD, md5_method, &h_md5); cls_register_method(h_class, "sha1", CLS_METHOD_RD, sha1_method, &h_sha1); return; } ceph-0.80.11/src/mds/0000775000175100017510000000000012623077035016241 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/mds/LogEvent.h0000664000175100017510000000524512623076744020151 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOGEVENT_H #define CEPH_LOGEVENT_H #define EVENT_NEW_ENCODING 0 // indicates that the encoding is versioned #define EVENT_UNUSED 1 // was previously EVENT_STRING #define EVENT_SUBTREEMAP 2 #define EVENT_EXPORT 3 #define EVENT_IMPORTSTART 4 #define EVENT_IMPORTFINISH 5 #define EVENT_FRAGMENT 6 #define EVENT_RESETJOURNAL 9 #define EVENT_SESSION 10 #define EVENT_SESSIONS_OLD 11 #define EVENT_SESSIONS 12 #define EVENT_UPDATE 20 #define EVENT_SLAVEUPDATE 21 #define EVENT_OPEN 22 #define EVENT_COMMITTED 23 #define EVENT_TABLECLIENT 42 #define EVENT_TABLESERVER 43 #define EVENT_SUBTREEMAP_TEST 50 #include using namespace std; #include "include/buffer.h" #include "include/Context.h" #include "include/utime.h" class MDS; class LogSegment; // generic log event class LogEvent { private: __u32 _type; uint64_t _start_off; static LogEvent *decode_event(bufferlist& bl, bufferlist::iterator& p, __u32 type); protected: utime_t stamp; friend class MDLog; public: LogSegment *_segment; LogEvent(int t) : _type(t), _start_off(0), _segment(0) { } virtual ~LogEvent() { } int get_type() const { return _type; } void set_type(int t) { _type = t; } uint64_t get_start_off() const { return _start_off; } void set_start_off(uint64_t o) { _start_off = o; } utime_t get_stamp() const { return stamp; } void set_stamp(utime_t t) { stamp = t; } // encoding virtual void encode(bufferlist& bl) const = 0; virtual void decode(bufferlist::iterator &bl) = 0; static LogEvent *decode(bufferlist &bl); virtual void dump(Formatter *f) const = 0; void encode_with_header(bufferlist& bl) { ::encode(EVENT_NEW_ENCODING, bl); ENCODE_START(1, 1, bl) ::encode(_type, bl); encode(bl); ENCODE_FINISH(bl); } virtual void print(ostream& out) const { out << "event(" << _type << ")"; } /*** live journal ***/ /* update_segment() - adjust any state we need to in the LogSegment */ virtual void update_segment() { } /*** recovery ***/ /* replay() - replay given event. this is idempotent. */ virtual void replay(MDS *m) { assert(0); } }; inline ostream& operator<<(ostream& out, LogEvent& le) { le.print(out); return out; } #endif ceph-0.80.11/src/mds/MDCache.cc0000664000175100017510000132065612623076744020017 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include "MDCache.h" #include "MDS.h" #include "Server.h" #include "Locker.h" #include "MDLog.h" #include "MDBalancer.h" #include "Migrator.h" #include "AnchorClient.h" #include "SnapClient.h" #include "MDSMap.h" #include "CInode.h" #include "CDir.h" #include "Mutation.h" #include "include/ceph_fs.h" #include "include/filepath.h" #include "msg/Message.h" #include "msg/Messenger.h" #include "common/errno.h" #include "common/safe_io.h" #include "common/perf_counters.h" #include "common/MemoryModel.h" #include "osdc/Journaler.h" #include "osdc/Filer.h" #include "events/ESubtreeMap.h" #include "events/EUpdate.h" #include "events/ESlaveUpdate.h" #include "events/EImportFinish.h" #include "events/EFragment.h" #include "events/ECommitted.h" #include "events/ESessions.h" #include "messages/MGenericMessage.h" #include "messages/MMDSResolve.h" #include "messages/MMDSResolveAck.h" #include "messages/MMDSCacheRejoin.h" #include "messages/MDiscover.h" #include "messages/MDiscoverReply.h" //#include "messages/MInodeUpdate.h" #include "messages/MDirUpdate.h" #include "messages/MCacheExpire.h" #include "messages/MInodeFileCaps.h" #include "messages/MLock.h" #include "messages/MDentryLink.h" #include "messages/MDentryUnlink.h" #include "messages/MMDSFindIno.h" #include "messages/MMDSFindInoReply.h" #include "messages/MMDSOpenIno.h" #include "messages/MMDSOpenInoReply.h" #include "messages/MClientRequest.h" #include "messages/MClientCaps.h" #include "messages/MClientSnap.h" #include "messages/MMDSSlaveRequest.h" #include "messages/MMDSFragmentNotify.h" #include "InoTable.h" #include "common/Timer.h" using namespace std; extern struct ceph_file_layout g_default_file_layout; #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix _prefix(_dout, mds) static ostream& _prefix(std::ostream *_dout, MDS *mds) { return *_dout << "mds." << mds->get_nodeid() << ".cache "; } long g_num_ino = 0; long g_num_dir = 0; long g_num_dn = 0; long g_num_cap = 0; long g_num_inoa = 0; long g_num_dira = 0; long g_num_dna = 0; long g_num_capa = 0; long g_num_inos = 0; long g_num_dirs = 0; long g_num_dns = 0; long g_num_caps = 0; set SimpleLock::empty_gather_set; MDCache::MDCache(MDS *m) : delayed_eval_stray(member_offset(CDentry, item_stray)) { mds = m; migrator = new Migrator(mds, this); root = NULL; myin = NULL; stray_index = 0; for (int i = 0; i < NUM_STRAY; ++i) { strays[i] = NULL; } num_inodes_with_caps = 0; num_caps = 0; max_dir_commit_size = g_conf->mds_dir_max_commit_size ? (g_conf->mds_dir_max_commit_size << 20) : (0.9 *(g_conf->osd_max_write_size << 20)); discover_last_tid = 0; open_ino_last_tid = 0; find_ino_peer_last_tid = 0; last_cap_id = 0; client_lease_durations[0] = 5.0; client_lease_durations[1] = 30.0; client_lease_durations[2] = 300.0; resolves_pending = false; rejoins_pending = false; cap_imports_num_opening = 0; opening_root = open = false; lru.lru_set_max(g_conf->mds_cache_size); lru.lru_set_midpoint(g_conf->mds_cache_mid); decayrate.set_halflife(g_conf->mds_decay_halflife); memset(&default_log_layout, 0, sizeof(default_log_layout)); did_shutdown_log_cap = false; } MDCache::~MDCache() { delete migrator; //delete renamer; } void MDCache::log_stat() { mds->logger->set(l_mds_imax, g_conf->mds_cache_size); mds->logger->set(l_mds_i, lru.lru_get_size()); mds->logger->set(l_mds_ipin, lru.lru_get_num_pinned()); mds->logger->set(l_mds_itop, lru.lru_get_top()); mds->logger->set(l_mds_ibot, lru.lru_get_bot()); mds->logger->set(l_mds_iptail, lru.lru_get_pintail()); mds->logger->set(l_mds_icap, num_inodes_with_caps); mds->logger->set(l_mds_cap, num_caps); } // bool MDCache::shutdown() { if (lru.lru_get_size() > 0) { dout(7) << "WARNING: mdcache shutdown with non-empty cache" << dendl; //show_cache(); show_subtrees(); //dump(); } return true; } // ==================================================================== // some inode functions void MDCache::add_inode(CInode *in) { // add to lru, inode map assert(inode_map.count(in->vino()) == 0); // should be no dup inos! inode_map[ in->vino() ] = in; if (in->ino() < MDS_INO_SYSTEM_BASE) { if (in->ino() == MDS_INO_ROOT) root = in; else if (in->ino() == MDS_INO_MDSDIR(mds->get_nodeid())) myin = in; else if (in->is_stray()) { if (MDS_INO_STRAY_OWNER(in->ino()) == mds->get_nodeid()) { strays[MDS_INO_STRAY_INDEX(in->ino())] = in; } } if (in->is_base()) base_inodes.insert(in); } } void MDCache::remove_inode(CInode *o) { dout(14) << "remove_inode " << *o << dendl; if (o->get_parent_dn()) { // FIXME: multiple parents? CDentry *dn = o->get_parent_dn(); assert(!dn->is_dirty()); dn->dir->unlink_inode(dn); // leave dentry ... FIXME? } if (o->is_dirty()) o->mark_clean(); if (o->is_dirty_parent()) o->clear_dirty_parent(); o->filelock.remove_dirty(); o->nestlock.remove_dirty(); o->dirfragtreelock.remove_dirty(); o->item_open_file.remove_myself(); // remove from inode map inode_map.erase(o->vino()); if (o->ino() < MDS_INO_SYSTEM_BASE) { if (o == root) root = 0; if (o == myin) myin = 0; if (o->is_stray()) { if (MDS_INO_STRAY_OWNER(o->ino()) == mds->get_nodeid()) { strays[MDS_INO_STRAY_INDEX(o->ino())] = 0; } } if (o->is_base()) base_inodes.erase(o); } // delete it assert(o->get_num_ref() == 0); delete o; } void MDCache::init_layouts() { default_file_layout = g_default_file_layout; default_file_layout.fl_pg_pool = mds->mdsmap->get_first_data_pool(); default_log_layout = g_default_file_layout; default_log_layout.fl_pg_pool = mds->mdsmap->get_metadata_pool(); if (g_conf->mds_log_segment_size > 0) { default_log_layout.fl_object_size = g_conf->mds_log_segment_size; default_log_layout.fl_stripe_unit = g_conf->mds_log_segment_size; } } CInode *MDCache::create_system_inode(inodeno_t ino, int mode) { dout(0) << "creating system inode with ino:" << ino << dendl; CInode *in = new CInode(this); in->inode.ino = ino; in->inode.version = 1; in->inode.mode = 0500 | mode; in->inode.size = 0; in->inode.ctime = in->inode.mtime = ceph_clock_now(g_ceph_context); in->inode.nlink = 1; in->inode.truncate_size = -1ull; memset(&in->inode.dir_layout, 0, sizeof(in->inode.dir_layout)); if (in->inode.is_dir()) { memset(&in->inode.layout, 0, sizeof(in->inode.layout)); in->inode.dir_layout.dl_dir_hash = g_conf->mds_default_dir_hash; ++in->inode.rstat.rsubdirs; } else { in->inode.layout = default_file_layout; ++in->inode.rstat.rfiles; } in->inode.accounted_rstat = in->inode.rstat; if (in->is_base()) { if (in->is_root()) in->inode_auth = pair(mds->whoami, CDIR_AUTH_UNKNOWN); else in->inode_auth = pair(in->ino() - MDS_INO_MDSDIR_OFFSET, CDIR_AUTH_UNKNOWN); in->open_snaprealm(); // empty snaprealm in->snaprealm->srnode.seq = 1; } add_inode(in); return in; } CInode *MDCache::create_root_inode() { CInode *i = create_system_inode(MDS_INO_ROOT, S_IFDIR|0755); i->inode.layout = default_file_layout; i->inode.layout.fl_pg_pool = mds->mdsmap->get_first_data_pool(); return i; } void MDCache::create_empty_hierarchy(C_Gather *gather) { // create root dir CInode *root = create_root_inode(); // force empty root dir CDir *rootdir = root->get_or_open_dirfrag(this, frag_t()); adjust_subtree_auth(rootdir, mds->whoami); rootdir->dir_rep = CDir::REP_ALL; //NONE; rootdir->fnode.accounted_fragstat = rootdir->fnode.fragstat; rootdir->fnode.accounted_rstat = rootdir->fnode.rstat; root->inode.dirstat = rootdir->fnode.fragstat; root->inode.rstat = rootdir->fnode.rstat; ++root->inode.rstat.rsubdirs; root->inode.accounted_rstat = root->inode.rstat; rootdir->mark_complete(); rootdir->mark_dirty(rootdir->pre_dirty(), mds->mdlog->get_current_segment()); rootdir->commit(0, gather->new_sub()); root->store(gather->new_sub()); } void MDCache::create_mydir_hierarchy(C_Gather *gather) { // create mds dir char myname[10]; snprintf(myname, sizeof(myname), "mds%d", mds->whoami); CInode *my = create_system_inode(MDS_INO_MDSDIR(mds->whoami), S_IFDIR); CDir *mydir = my->get_or_open_dirfrag(this, frag_t()); adjust_subtree_auth(mydir, mds->whoami); LogSegment *ls = mds->mdlog->get_current_segment(); // stray dir for (int i = 0; i < NUM_STRAY; ++i) { CInode *stray = create_system_inode(MDS_INO_STRAY(mds->whoami, i), S_IFDIR); CDir *straydir = stray->get_or_open_dirfrag(this, frag_t()); stringstream name; name << "stray" << i; CDentry *sdn = mydir->add_primary_dentry(name.str(), stray); sdn->_mark_dirty(mds->mdlog->get_current_segment()); stray->inode.dirstat = straydir->fnode.fragstat; mydir->fnode.rstat.add(stray->inode.rstat); mydir->fnode.fragstat.nsubdirs++; // save them straydir->mark_complete(); straydir->mark_dirty(straydir->pre_dirty(), ls); straydir->commit(0, gather->new_sub()); stray->_mark_dirty_parent(ls, true); stray->store_backtrace(gather->new_sub()); } CInode *journal = create_system_inode(MDS_INO_LOG_OFFSET + mds->whoami, S_IFREG); string name = "journal"; CDentry *jdn = mydir->add_primary_dentry(name, journal); jdn->_mark_dirty(mds->mdlog->get_current_segment()); mydir->fnode.fragstat.nfiles++; mydir->fnode.rstat.rfiles++; mydir->fnode.accounted_fragstat = mydir->fnode.fragstat; mydir->fnode.accounted_rstat = mydir->fnode.rstat; myin->inode.dirstat = mydir->fnode.fragstat; myin->inode.rstat = mydir->fnode.rstat; ++myin->inode.rstat.rsubdirs; myin->inode.accounted_rstat = myin->inode.rstat; mydir->mark_complete(); mydir->mark_dirty(mydir->pre_dirty(), ls); mydir->commit(0, gather->new_sub()); myin->store(gather->new_sub()); } struct C_MDC_CreateSystemFile : public Context { MDCache *cache; MutationRef mut; CDentry *dn; version_t dpv; Context *fin; C_MDC_CreateSystemFile(MDCache *c, MutationRef& mu, CDentry *d, version_t v, Context *f) : cache(c), mut(mu), dn(d), dpv(v), fin(f) {} void finish(int r) { cache->_create_system_file_finish(mut, dn, dpv, fin); } }; void MDCache::_create_system_file(CDir *dir, const char *name, CInode *in, Context *fin) { dout(10) << "_create_system_file " << name << " in " << *dir << dendl; CDentry *dn = dir->add_null_dentry(name); dn->push_projected_linkage(in); version_t dpv = dn->pre_dirty(); CDir *mdir = 0; if (in->inode.is_dir()) { in->inode.rstat.rsubdirs = 1; mdir = in->get_or_open_dirfrag(this, frag_t()); mdir->mark_complete(); mdir->pre_dirty(); } else in->inode.rstat.rfiles = 1; in->inode.version = dn->pre_dirty(); SnapRealm *realm = dir->get_inode()->find_snaprealm(); dn->first = in->first = realm->get_newest_seq() + 1; MutationRef mut(new MutationImpl); // force some locks. hacky. mds->locker->wrlock_force(&dir->inode->filelock, mut); mds->locker->wrlock_force(&dir->inode->nestlock, mut); mut->ls = mds->mdlog->get_current_segment(); EUpdate *le = new EUpdate(mds->mdlog, "create system file"); mds->mdlog->start_entry(le); if (!in->is_mdsdir()) { predirty_journal_parents(mut, &le->metablob, in, dir, PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); le->metablob.add_primary_dentry(dn, in, true); } else { predirty_journal_parents(mut, &le->metablob, in, dir, PREDIRTY_DIR, 1); journal_dirty_inode(mut.get(), &le->metablob, in); dn->push_projected_linkage(in->ino(), in->d_type()); le->metablob.add_remote_dentry(dn, true, in->ino(), in->d_type()); le->metablob.add_root(true, in); } if (mdir) le->metablob.add_new_dir(mdir); // dirty AND complete AND new mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(new C_MDC_CreateSystemFile(this, mut, dn, dpv, fin)); mds->mdlog->flush(); } void MDCache::_create_system_file_finish(MutationRef& mut, CDentry *dn, version_t dpv, Context *fin) { dout(10) << "_create_system_file_finish " << *dn << dendl; dn->pop_projected_linkage(); dn->mark_dirty(dpv, mut->ls); CInode *in = dn->get_linkage()->get_inode(); in->inode.version--; in->mark_dirty(in->inode.version + 1, mut->ls); if (in->inode.is_dir()) { CDir *dir = in->get_dirfrag(frag_t()); assert(dir); dir->mark_dirty(1, mut->ls); dir->mark_new(mut->ls); } mut->apply(); mds->locker->drop_locks(mut.get()); mut->cleanup(); fin->complete(0); //if (dir && MDS_INO_IS_MDSDIR(in->ino())) //migrator->export_dir(dir, (int)in->ino() - MDS_INO_MDSDIR_OFFSET); } struct C_MDS_RetryOpenRoot : public Context { MDCache *cache; C_MDS_RetryOpenRoot(MDCache *c) : cache(c) {} void finish(int r) { if (r < 0) cache->mds->suicide(); else cache->open_root(); } }; void MDCache::open_root_inode(Context *c) { if (mds->whoami == mds->mdsmap->get_root()) { CInode *in; in = create_system_inode(MDS_INO_ROOT, S_IFDIR|0755); // initially inaccurate! in->fetch(c); } else { discover_base_ino(MDS_INO_ROOT, c, mds->mdsmap->get_root()); } } void MDCache::open_mydir_inode(Context *c) { CInode *in = create_system_inode(MDS_INO_MDSDIR(mds->whoami), S_IFDIR|0755); // initially inaccurate! in->fetch(c); } void MDCache::open_root() { dout(10) << "open_root" << dendl; if (!root) { open_root_inode(new C_MDS_RetryOpenRoot(this)); return; } if (mds->whoami == mds->mdsmap->get_root()) { assert(root->is_auth()); CDir *rootdir = root->get_or_open_dirfrag(this, frag_t()); assert(rootdir); if (!rootdir->is_subtree_root()) adjust_subtree_auth(rootdir, mds->whoami); if (!rootdir->is_complete()) { rootdir->fetch(new C_MDS_RetryOpenRoot(this)); return; } } else { assert(!root->is_auth()); CDir *rootdir = root->get_dirfrag(frag_t()); if (!rootdir) { discover_dir_frag(root, frag_t(), new C_MDS_RetryOpenRoot(this)); return; } } if (!myin) { CInode *in = create_system_inode(MDS_INO_MDSDIR(mds->whoami), S_IFDIR|0755); // initially inaccurate! in->fetch(new C_MDS_RetryOpenRoot(this)); return; } CDir *mydir = myin->get_or_open_dirfrag(this, frag_t()); assert(mydir); adjust_subtree_auth(mydir, mds->whoami); populate_mydir(); } void MDCache::populate_mydir() { assert(myin); CDir *mydir = myin->get_or_open_dirfrag(this, frag_t()); assert(mydir); dout(10) << "populate_mydir " << *mydir << dendl; if (!mydir->is_complete()) { mydir->fetch(new C_MDS_RetryOpenRoot(this)); return; } // open or create stray for (int i = 0; i < NUM_STRAY; ++i) { stringstream name; name << "stray" << i; CDentry *straydn = mydir->lookup(name.str()); // allow for older fs's with stray instead of stray0 if (straydn == NULL && i == 0) straydn = mydir->lookup("stray"); if (!straydn || !straydn->get_linkage()->get_inode()) { _create_system_file(mydir, name.str().c_str(), create_system_inode(MDS_INO_STRAY(mds->whoami, i), S_IFDIR), new C_MDS_RetryOpenRoot(this)); return; } assert(straydn); assert(strays[i]); // we make multiple passes through this method; make sure we only pin each stray once. if (!strays[i]->state_test(CInode::STATE_STRAYPINNED)) { strays[i]->get(CInode::PIN_STRAY); strays[i]->state_set(CInode::STATE_STRAYPINNED); strays[i]->get_stickydirs(); } dout(20) << " stray num " << i << " is " << *strays[i] << dendl; // open all frags list ls; strays[i]->dirfragtree.get_leaves(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { frag_t fg = *p; CDir *dir = strays[i]->get_dirfrag(fg); if (!dir) dir = strays[i]->get_or_open_dirfrag(this, fg); if (dir->get_version() == 0) { dir->fetch(new C_MDS_RetryOpenRoot(this)); return; } } } // open or create journal file string jname("journal"); CDentry *jdn = mydir->lookup(jname); if (!jdn || !jdn->get_linkage()->get_inode()) { _create_system_file(mydir, jname.c_str(), create_system_inode(MDS_INO_LOG_OFFSET + mds->whoami, S_IFREG), new C_MDS_RetryOpenRoot(this)); return; } // okay! dout(10) << "populate_mydir done" << dendl; assert(!open); open = true; mds->queue_waiters(waiting_for_open); scan_stray_dir(); } void MDCache::open_foreign_mdsdir(inodeno_t ino, Context *fin) { discover_base_ino(ino, fin, ino & (MAX_MDS-1)); } CDentry *MDCache::get_or_create_stray_dentry(CInode *in) { string straydname; in->name_stray_dentry(straydname); CInode *strayi = get_stray(); assert(strayi); frag_t fg = strayi->pick_dirfrag(straydname); CDir *straydir = strayi->get_dirfrag(fg); assert(straydir); CDentry *straydn = straydir->lookup(straydname); if (!straydn) { straydn = straydir->add_null_dentry(straydname); straydn->mark_new(); } else assert(straydn->get_projected_linkage()->is_null()); straydn->state_set(CDentry::STATE_STRAY); return straydn; } MDSCacheObject *MDCache::get_object(MDSCacheObjectInfo &info) { // inode? if (info.ino) return get_inode(info.ino, info.snapid); // dir or dentry. CDir *dir = get_dirfrag(info.dirfrag); if (!dir) return 0; if (info.dname.length()) return dir->lookup(info.dname, info.snapid); else return dir; } // ==================================================================== // subtree management void MDCache::list_subtrees(list& ls) { for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) ls.push_back(p->first); } /* * adjust the dir_auth of a subtree. * merge with parent and/or child subtrees, if is it appropriate. * merge can ONLY happen if both parent and child have unambiguous auth. */ void MDCache::adjust_subtree_auth(CDir *dir, pair auth, bool do_eval) { dout(7) << "adjust_subtree_auth " << dir->get_dir_auth() << " -> " << auth << " on " << *dir << dendl; if (mds->is_any_replay() || mds->is_resolve()) do_eval = false; show_subtrees(); CDir *root; if (dir->inode->is_base()) { root = dir; // bootstrap hack. if (subtrees.count(root) == 0) { subtrees[root].clear(); root->get(CDir::PIN_SUBTREE); } } else { root = get_subtree_root(dir); // subtree root } assert(root); assert(subtrees.count(root)); dout(7) << " current root is " << *root << dendl; if (root == dir) { // i am already a subtree. dir->set_dir_auth(auth); } else { // i am a new subtree. dout(10) << " new subtree at " << *dir << dendl; assert(subtrees.count(dir) == 0); subtrees[dir].clear(); // create empty subtree bounds list for me. dir->get(CDir::PIN_SUBTREE); // set dir_auth dir->set_dir_auth(auth); // move items nested beneath me, under me. set::iterator p = subtrees[root].begin(); while (p != subtrees[root].end()) { set::iterator next = p; ++next; if (get_subtree_root((*p)->get_parent_dir()) == dir) { // move under me dout(10) << " claiming child bound " << **p << dendl; subtrees[dir].insert(*p); subtrees[root].erase(p); } p = next; } // i am a bound of the parent subtree. subtrees[root].insert(dir); // i am now the subtree root. root = dir; // adjust recursive pop counters if (dir->is_auth()) { utime_t now = ceph_clock_now(g_ceph_context); CDir *p = dir->get_parent_dir(); while (p) { p->pop_auth_subtree.sub(now, decayrate, dir->pop_auth_subtree); if (p->is_subtree_root()) break; p = p->inode->get_parent_dir(); } } if (do_eval) eval_subtree_root(dir->get_inode()); } show_subtrees(); } void MDCache::try_subtree_merge(CDir *dir) { dout(7) << "try_subtree_merge " << *dir << dendl; assert(subtrees.count(dir)); set oldbounds = subtrees[dir]; // try merge at my root try_subtree_merge_at(dir); // try merge at my old bounds for (set::iterator p = oldbounds.begin(); p != oldbounds.end(); ++p) try_subtree_merge_at(*p); } class C_MDC_SubtreeMergeWB : public Context { MDCache *mdcache; CInode *in; MutationRef mut; public: C_MDC_SubtreeMergeWB(MDCache *mdc, CInode *i, MutationRef& m) : mdcache(mdc), in(i), mut(m) {} void finish(int r) { mdcache->subtree_merge_writebehind_finish(in, mut); } }; void MDCache::try_subtree_merge_at(CDir *dir, bool do_eval) { dout(10) << "try_subtree_merge_at " << *dir << dendl; assert(subtrees.count(dir)); if (mds->is_any_replay() || mds->is_resolve()) do_eval = false; // merge with parent? CDir *parent = dir; if (!dir->inode->is_base()) parent = get_subtree_root(dir->get_parent_dir()); if (parent != dir && // we have a parent, parent->dir_auth == dir->dir_auth && // auth matches, dir->dir_auth.second == CDIR_AUTH_UNKNOWN && // auth is unambiguous, !dir->state_test(CDir::STATE_EXPORTBOUND)) { // not an exportbound, // merge with parent. dout(10) << " subtree merge at " << *dir << dendl; dir->set_dir_auth(CDIR_AUTH_DEFAULT); // move our bounds under the parent for (set::iterator p = subtrees[dir].begin(); p != subtrees[dir].end(); ++p) subtrees[parent].insert(*p); // we are no longer a subtree or bound dir->put(CDir::PIN_SUBTREE); subtrees.erase(dir); subtrees[parent].erase(dir); // adjust popularity? if (dir->is_auth()) { utime_t now = ceph_clock_now(g_ceph_context); CDir *p = dir->get_parent_dir(); while (p) { p->pop_auth_subtree.add(now, decayrate, dir->pop_auth_subtree); if (p->is_subtree_root()) break; p = p->inode->get_parent_dir(); } } if (do_eval) eval_subtree_root(dir->get_inode()); // journal inode? // (this is a large hammer to ensure that dirfragtree updates will // hit the disk before the relevant dirfrags ever close) if (dir->inode->is_auth() && dir->inode->can_auth_pin() && (mds->is_clientreplay() || mds->is_active() || mds->is_stopping())) { CInode *in = dir->inode; dout(10) << "try_subtree_merge_at journaling merged bound " << *in << dendl; in->auth_pin(this); // journal write-behind. inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); EUpdate *le = new EUpdate(mds->mdlog, "subtree merge writebehind"); mds->mdlog->start_entry(le); le->metablob.add_dir_context(in->get_parent_dn()->get_dir()); journal_dirty_inode(mut.get(), &le->metablob, in); mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(new C_MDC_SubtreeMergeWB(this, in, mut)); mds->mdlog->flush(); } } show_subtrees(15); } void MDCache::subtree_merge_writebehind_finish(CInode *in, MutationRef& mut) { dout(10) << "subtree_merge_writebehind_finish on " << in << dendl; in->pop_and_dirty_projected_inode(mut->ls); mut->apply(); mds->locker->drop_locks(mut.get()); mut->cleanup(); in->auth_unpin(this); } void MDCache::eval_subtree_root(CInode *diri) { // evaluate subtree inode filelock? // (we should scatter the filelock on subtree bounds) if (diri->is_auth()) mds->locker->try_eval(diri, CEPH_LOCK_IFILE | CEPH_LOCK_INEST); } void MDCache::adjust_bounded_subtree_auth(CDir *dir, set& bounds, pair auth) { dout(7) << "adjust_bounded_subtree_auth " << dir->get_dir_auth() << " -> " << auth << " on " << *dir << " bounds " << bounds << dendl; show_subtrees(); CDir *root; if (dir->ino() == MDS_INO_ROOT) { root = dir; // bootstrap hack. if (subtrees.count(root) == 0) { subtrees[root].clear(); root->get(CDir::PIN_SUBTREE); } } else { root = get_subtree_root(dir); // subtree root } assert(root); assert(subtrees.count(root)); dout(7) << " current root is " << *root << dendl; pair oldauth = dir->authority(); if (root == dir) { // i am already a subtree. dir->set_dir_auth(auth); } else { // i am a new subtree. dout(10) << " new subtree at " << *dir << dendl; assert(subtrees.count(dir) == 0); subtrees[dir].clear(); // create empty subtree bounds list for me. dir->get(CDir::PIN_SUBTREE); // set dir_auth dir->set_dir_auth(auth); // move items nested beneath me, under me. set::iterator p = subtrees[root].begin(); while (p != subtrees[root].end()) { set::iterator next = p; ++next; if (get_subtree_root((*p)->get_parent_dir()) == dir) { // move under me dout(10) << " claiming child bound " << **p << dendl; subtrees[dir].insert(*p); subtrees[root].erase(p); } p = next; } // i am a bound of the parent subtree. subtrees[root].insert(dir); // i am now the subtree root. root = dir; } // verify/adjust bounds. // - these may be new, or // - beneath existing ambiguous bounds (which will be collapsed), // - but NOT beneath unambiguous bounds. for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bound = *p; // new bound? if (subtrees[dir].count(bound) == 0) { if (get_subtree_root(bound) == dir) { dout(10) << " new bound " << *bound << ", adjusting auth back to old " << oldauth << dendl; adjust_subtree_auth(bound, oldauth); // otherwise, adjust at bound. } else { dout(10) << " want bound " << *bound << dendl; CDir *t = get_subtree_root(bound->get_parent_dir()); if (subtrees[t].count(bound) == 0) { assert(t != dir); dout(10) << " new bound " << *bound << dendl; adjust_subtree_auth(bound, t->authority()); } // make sure it's nested beneath ambiguous subtree(s) while (1) { while (subtrees[dir].count(t) == 0) t = get_subtree_root(t->get_parent_dir()); dout(10) << " swallowing intervening subtree at " << *t << dendl; adjust_subtree_auth(t, auth); try_subtree_merge_at(t); t = get_subtree_root(bound->get_parent_dir()); if (t == dir) break; } } } else { dout(10) << " already have bound " << *bound << dendl; } } // merge stray bounds? while (!subtrees[dir].empty()) { set copy = subtrees[dir]; for (set::iterator p = copy.begin(); p != copy.end(); ++p) { if (bounds.count(*p) == 0) { CDir *stray = *p; dout(10) << " swallowing extra subtree at " << *stray << dendl; adjust_subtree_auth(stray, auth); try_subtree_merge_at(stray); } } // swallowing subtree may add new subtree bounds if (copy == subtrees[dir]) break; } // bound should now match. verify_subtree_bounds(dir, bounds); show_subtrees(); } /* * return a set of CDir*'s that correspond to the given bound set. Only adjust * fragmentation as necessary to get an equivalent bounding set. That is, only * split if one of our frags spans the provided bounding set. Never merge. */ void MDCache::get_force_dirfrag_bound_set(vector& dfs, set& bounds) { dout(10) << "get_force_dirfrag_bound_set " << dfs << dendl; // sort by ino map byino; for (vector::iterator p = dfs.begin(); p != dfs.end(); ++p) byino[p->ino].insert(p->frag); dout(10) << " by ino: " << byino << dendl; for (map::iterator p = byino.begin(); p != byino.end(); ++p) { CInode *diri = get_inode(p->first); if (!diri) continue; dout(10) << " checking fragset " << p->second.get() << " on " << *diri << dendl; fragtree_t tmpdft; for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) tmpdft.force_to_leaf(g_ceph_context, *q); for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { frag_t fg = *q; list fgls; diri->dirfragtree.get_leaves_under(fg, fgls); if (fgls.empty()) { bool all = true; frag_t approx_fg = diri->dirfragtree[fg.value()]; list ls; tmpdft.get_leaves_under(approx_fg, ls); for (list::iterator r = ls.begin(); r != ls.end(); ++r) { if (p->second.get().count(*r) == 0) { // not bound, so the resolve message is from auth MDS of the dirfrag force_dir_fragment(diri, *r); all = false; } } if (all) fgls.push_back(approx_fg); else diri->dirfragtree.get_leaves_under(fg, fgls); } dout(10) << " frag " << fg << " contains " << fgls << dendl; for (list::iterator r = fgls.begin(); r != fgls.end(); ++r) { CDir *dir = diri->get_dirfrag(*r); if (dir) bounds.insert(dir); } } } } void MDCache::adjust_bounded_subtree_auth(CDir *dir, vector& bound_dfs, pair auth) { dout(7) << "adjust_bounded_subtree_auth " << dir->get_dir_auth() << " -> " << auth << " on " << *dir << " bound_dfs " << bound_dfs << dendl; set bounds; get_force_dirfrag_bound_set(bound_dfs, bounds); adjust_bounded_subtree_auth(dir, bounds, auth); } void MDCache::map_dirfrag_set(list& dfs, set& result) { dout(10) << "map_dirfrag_set " << dfs << dendl; // group by inode map ino_fragset; for (list::iterator p = dfs.begin(); p != dfs.end(); ++p) ino_fragset[p->ino].insert(p->frag); // get frags for (map::iterator p = ino_fragset.begin(); p != ino_fragset.end(); ++p) { CInode *in = get_inode(p->first); if (!in) continue; list fglist; for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) in->dirfragtree.get_leaves_under(*q, fglist); dout(15) << "map_dirfrag_set " << p->second << " -> " << fglist << " on " << *in << dendl; for (list::iterator q = fglist.begin(); q != fglist.end(); ++q) { CDir *dir = in->get_dirfrag(*q); if (dir) result.insert(dir); } } } CDir *MDCache::get_subtree_root(CDir *dir) { // find the underlying dir that delegates (or is about to delegate) auth while (true) { if (dir->is_subtree_root()) return dir; dir = dir->get_inode()->get_parent_dir(); if (!dir) return 0; // none } } CDir *MDCache::get_projected_subtree_root(CDir *dir) { // find the underlying dir that delegates (or is about to delegate) auth while (true) { if (dir->is_subtree_root()) return dir; dir = dir->get_inode()->get_projected_parent_dir(); if (!dir) return 0; // none } } void MDCache::remove_subtree(CDir *dir) { dout(10) << "remove_subtree " << *dir << dendl; assert(subtrees.count(dir)); assert(subtrees[dir].empty()); subtrees.erase(dir); dir->put(CDir::PIN_SUBTREE); if (dir->get_parent_dir()) { CDir *p = get_subtree_root(dir->get_parent_dir()); assert(subtrees[p].count(dir)); subtrees[p].erase(dir); } } void MDCache::get_subtree_bounds(CDir *dir, set& bounds) { assert(subtrees.count(dir)); bounds = subtrees[dir]; } void MDCache::get_wouldbe_subtree_bounds(CDir *dir, set& bounds) { if (subtrees.count(dir)) { // just copy them, dir is a subtree. get_subtree_bounds(dir, bounds); } else { // find them CDir *root = get_subtree_root(dir); for (set::iterator p = subtrees[root].begin(); p != subtrees[root].end(); ++p) { CDir *t = *p; while (t != root) { t = t->get_parent_dir(); assert(t); if (t == dir) { bounds.insert(*p); continue; } } } } } void MDCache::verify_subtree_bounds(CDir *dir, const set& bounds) { // for debugging only. assert(subtrees.count(dir)); if (bounds != subtrees[dir]) { dout(0) << "verify_subtree_bounds failed" << dendl; set b = bounds; for (set::iterator p = subtrees[dir].begin(); p != subtrees[dir].end(); ++p) { if (bounds.count(*p)) { b.erase(*p); continue; } dout(0) << " missing bound " << **p << dendl; } for (set::iterator p = b.begin(); p != b.end(); ++p) dout(0) << " extra bound " << **p << dendl; } assert(bounds == subtrees[dir]); } void MDCache::verify_subtree_bounds(CDir *dir, const list& bounds) { // for debugging only. assert(subtrees.count(dir)); // make sure that any bounds i do have are properly noted as such. int failed = 0; for (list::const_iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bd = get_dirfrag(*p); if (!bd) continue; if (subtrees[dir].count(bd) == 0) { dout(0) << "verify_subtree_bounds failed: extra bound " << *bd << dendl; failed++; } } assert(failed == 0); } void MDCache::project_subtree_rename(CInode *diri, CDir *olddir, CDir *newdir) { dout(10) << "project_subtree_rename " << *diri << " from " << *olddir << " to " << *newdir << dendl; projected_subtree_renames[diri].push_back(pair(olddir, newdir)); } void MDCache::adjust_subtree_after_rename(CInode *diri, CDir *olddir, bool pop, bool imported) { dout(10) << "adjust_subtree_after_rename " << *diri << " from " << *olddir << dendl; //show_subtrees(); CDir *newdir = diri->get_parent_dir(); if (pop) { map > >::iterator p = projected_subtree_renames.find(diri); assert(p != projected_subtree_renames.end()); assert(!p->second.empty()); assert(p->second.front().first == olddir); assert(p->second.front().second == newdir); p->second.pop_front(); if (p->second.empty()) projected_subtree_renames.erase(p); } // adjust subtree list dfls; // make sure subtree dirfrags are at the front of the list diri->get_subtree_dirfrags(dfls); diri->get_nested_dirfrags(dfls); for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) { CDir *dir = *p; dout(10) << "dirfrag " << *dir << dendl; CDir *oldparent = get_subtree_root(olddir); dout(10) << " old parent " << *oldparent << dendl; CDir *newparent = get_subtree_root(newdir); dout(10) << " new parent " << *newparent << dendl; if (oldparent == newparent) { dout(10) << "parent unchanged for " << *dir << " at " << *oldparent << dendl; continue; } if (dir->is_subtree_root()) { // children are fine. change parent. dout(10) << "moving " << *dir << " from " << *oldparent << " to " << *newparent << dendl; assert(subtrees[oldparent].count(dir)); subtrees[oldparent].erase(dir); assert(subtrees.count(newparent)); subtrees[newparent].insert(dir); try_subtree_merge_at(dir, !imported); } else { // mid-subtree. // see if any old bounds move to the new parent. list tomove; for (set::iterator p = subtrees[oldparent].begin(); p != subtrees[oldparent].end(); ++p) { CDir *bound = *p; CDir *broot = get_subtree_root(bound->get_parent_dir()); if (broot != oldparent) { assert(broot == newparent); tomove.push_back(bound); } } for (list::iterator p = tomove.begin(); p != tomove.end(); ++p) { CDir *bound = *p; dout(10) << "moving bound " << *bound << " from " << *oldparent << " to " << *newparent << dendl; subtrees[oldparent].erase(bound); subtrees[newparent].insert(bound); } // did auth change? if (oldparent->authority() != newparent->authority()) { adjust_subtree_auth(dir, oldparent->authority(), !imported); // caller is responsible for *diri. try_subtree_merge_at(dir, !imported); } } } show_subtrees(); } void MDCache::get_fullauth_subtrees(set& s) { for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *root = p->first; if (root->is_full_dir_auth()) s.insert(root); } } void MDCache::get_auth_subtrees(set& s) { for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *root = p->first; if (root->is_auth()) s.insert(root); } } // count. int MDCache::num_subtrees() { return subtrees.size(); } int MDCache::num_subtrees_fullauth() { int n = 0; for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *root = p->first; if (root->is_full_dir_auth()) n++; } return n; } int MDCache::num_subtrees_fullnonauth() { int n = 0; for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *root = p->first; if (root->is_full_dir_nonauth()) n++; } return n; } // =================================== // journal and snap/cow helpers /* * find first inode in cache that follows given snapid. otherwise, return current. */ CInode *MDCache::pick_inode_snap(CInode *in, snapid_t follows) { dout(10) << "pick_inode_snap follows " << follows << " on " << *in << dendl; assert(in->last == CEPH_NOSNAP); SnapRealm *realm = in->find_snaprealm(); const set& snaps = realm->get_snaps(); dout(10) << " realm " << *realm << " " << *realm->inode << dendl; dout(10) << " snaps " << snaps << dendl; if (snaps.empty()) return in; for (set::const_iterator p = snaps.upper_bound(follows); // first item > follows p != snaps.end(); ++p) { CInode *t = get_inode(in->ino(), *p); if (t) { in = t; dout(10) << "pick_inode_snap snap " << *p << " found " << *in << dendl; break; } } return in; } /* * note: i'm currently cheating wrt dirty and inode.version on cow * items. instead of doing a full dir predirty, i just take the * original item's version, and set the dirty flag (via * mutation::add_cow_{inode,dentry}() and mutation::apply(). that * means a special case in the dir commit clean sweep assertions. * bah. */ CInode *MDCache::cow_inode(CInode *in, snapid_t last) { assert(last >= in->first); CInode *oldin = new CInode(this, true, in->first, last); oldin->inode = *in->get_previous_projected_inode(); oldin->symlink = in->symlink; oldin->xattrs = *in->get_previous_projected_xattrs(); oldin->inode.trim_client_ranges(last); in->first = last+1; dout(10) << "cow_inode " << *in << " to " << *oldin << dendl; add_inode(oldin); SnapRealm *realm = in->find_snaprealm(); const set& snaps = realm->get_snaps(); // clone caps? for (map::iterator p = in->client_caps.begin(); p != in->client_caps.end(); ++p) { client_t client = p->first; Capability *cap = p->second; int issued = cap->issued(); if ((issued & CEPH_CAP_ANY_WR) && cap->client_follows < last) { // note in oldin for (int i = 0; i < num_cinode_locks; i++) { if (issued & cinode_lock_info[i].wr_caps) { int lockid = cinode_lock_info[i].lock; SimpleLock *lock = oldin->get_lock(lockid); assert(lock); oldin->client_snap_caps[lockid].insert(client); oldin->auth_pin(lock); lock->set_state(LOCK_SNAP_SYNC); // gathering lock->get_wrlock(true); dout(10) << " client." << client << " cap " << ccap_string(issued & cinode_lock_info[i].wr_caps) << " wrlock lock " << *lock << " on " << *oldin << dendl; } } cap->client_follows = last; // we need snapflushes for any intervening snaps dout(10) << " snaps " << snaps << dendl; for (set::const_iterator q = snaps.lower_bound(oldin->first); q != snaps.end() && *q <= last; ++q) { in->add_need_snapflush(oldin, *q, client); } } else { dout(10) << " ignoring client." << client << " cap follows " << cap->client_follows << dendl; } } return oldin; } void MDCache::journal_cow_dentry(MutationImpl *mut, EMetaBlob *metablob, CDentry *dn, snapid_t follows, CInode **pcow_inode, CDentry::linkage_t *dnl) { if (!dn) { dout(10) << "journal_cow_dentry got null CDentry, returning" << dendl; return; } dout(10) << "journal_cow_dentry follows " << follows << " on " << *dn << dendl; assert(dn->is_auth()); // nothing to cow on a null dentry, fix caller if (!dnl) dnl = dn->get_projected_linkage(); assert(!dnl->is_null()); if (dnl->is_primary() && dnl->get_inode()->is_multiversion()) { // multiversion inode. CInode *in = dnl->get_inode(); if (follows == CEPH_NOSNAP) follows = in->find_snaprealm()->get_newest_seq(); if (in->get_projected_parent_dn() != dn && follows+1 > dn->first) { snapid_t oldfirst = dn->first; dn->first = follows+1; CDentry *olddn = dn->dir->add_remote_dentry(dn->name, in->ino(), in->d_type(), oldfirst, follows); olddn->pre_dirty(); dout(10) << " olddn " << *olddn << dendl; metablob->add_remote_dentry(olddn, true); mut->add_cow_dentry(olddn); // FIXME: adjust link count here? hmm. } // already cloned? if (follows < in->first) { dout(10) << "journal_cow_dentry follows " << follows << " < first on " << *in << dendl; return; } in->cow_old_inode(follows, false); } else { if (follows == CEPH_NOSNAP) follows = dn->dir->inode->find_snaprealm()->get_newest_seq(); // already cloned? if (follows < dn->first) { dout(10) << "journal_cow_dentry follows " << follows << " < first on " << *dn << dendl; return; } // update dn.first before adding old dentry to cdir's map snapid_t oldfirst = dn->first; dn->first = follows+1; dout(10) << " dn " << *dn << dendl; if (dnl->is_primary()) { assert(oldfirst == dnl->get_inode()->first); CInode *oldin = cow_inode(dnl->get_inode(), follows); mut->add_cow_inode(oldin); if (pcow_inode) *pcow_inode = oldin; CDentry *olddn = dn->dir->add_primary_dentry(dn->name, oldin, oldfirst, follows); oldin->inode.version = olddn->pre_dirty(); dout(10) << " olddn " << *olddn << dendl; metablob->add_primary_dentry(olddn, 0, true); mut->add_cow_dentry(olddn); } else { assert(dnl->is_remote()); CDentry *olddn = dn->dir->add_remote_dentry(dn->name, dnl->get_remote_ino(), dnl->get_remote_d_type(), oldfirst, follows); olddn->pre_dirty(); dout(10) << " olddn " << *olddn << dendl; metablob->add_remote_dentry(olddn, true); mut->add_cow_dentry(olddn); } } } void MDCache::journal_cow_inode(MutationRef& mut, EMetaBlob *metablob, CInode *in, snapid_t follows, CInode **pcow_inode) { dout(10) << "journal_cow_inode follows " << follows << " on " << *in << dendl; CDentry *dn = in->get_projected_parent_dn(); journal_cow_dentry(mut.get(), metablob, dn, follows, pcow_inode); } void MDCache::journal_dirty_inode(MutationImpl *mut, EMetaBlob *metablob, CInode *in, snapid_t follows) { if (in->is_base()) { metablob->add_root(true, in, in->get_projected_inode()); } else { if (follows == CEPH_NOSNAP && in->last != CEPH_NOSNAP) follows = in->first - 1; CDentry *dn = in->get_projected_parent_dn(); if (!dn->get_projected_linkage()->is_null()) // no need to cow a null dentry journal_cow_dentry(mut, metablob, dn, follows); if (in->get_projected_inode()->is_backtrace_updated()) { bool dirty_pool = in->get_projected_inode()->layout.fl_pg_pool != in->get_previous_projected_inode()->layout.fl_pg_pool; metablob->add_primary_dentry(dn, in, true, true, dirty_pool); } else { metablob->add_primary_dentry(dn, in, true); } } } // nested --------------------------------------------------------------- void MDCache::project_rstat_inode_to_frag(CInode *cur, CDir *parent, snapid_t first, int linkunlink) { CDentry *parentdn = cur->get_projected_parent_dn(); inode_t *curi = cur->get_projected_inode(); if (cur->first > first) first = cur->first; dout(10) << "projected_rstat_inode_to_frag first " << first << " linkunlink " << linkunlink << " " << *cur << dendl; dout(20) << " frag head is [" << parent->first << ",head] " << dendl; dout(20) << " inode update is [" << first << "," << cur->last << "]" << dendl; /* * FIXME. this incompletely propagates rstats to _old_ parents * (i.e. shortly after a directory rename). but we need full * blown hard link backpointers to make this work properly... */ snapid_t floor = parentdn->first; dout(20) << " floor of " << floor << " from parent dn " << *parentdn << dendl; if (cur->last >= floor) _project_rstat_inode_to_frag(*curi, MAX(first, floor), cur->last, parent, linkunlink); for (set::iterator p = cur->dirty_old_rstats.begin(); p != cur->dirty_old_rstats.end(); ++p) { old_inode_t& old = cur->old_inodes[*p]; if (*p >= floor) _project_rstat_inode_to_frag(old.inode, MAX(old.first, floor), *p, parent); } cur->dirty_old_rstats.clear(); } void MDCache::_project_rstat_inode_to_frag(inode_t& inode, snapid_t ofirst, snapid_t last, CDir *parent, int linkunlink) { dout(10) << "_project_rstat_inode_to_frag [" << ofirst << "," << last << "]" << dendl; dout(20) << " inode rstat " << inode.rstat << dendl; dout(20) << " inode accounted_rstat " << inode.accounted_rstat << dendl; nest_info_t delta; if (linkunlink == 0) { delta.add(inode.rstat); delta.sub(inode.accounted_rstat); } else if (linkunlink < 0) { delta.sub(inode.accounted_rstat); } else { delta.add(inode.rstat); } dout(20) << " delta " << delta << dendl; inode.accounted_rstat = inode.rstat; while (last >= ofirst) { /* * pick fnode version to update. at each iteration, we want to * pick a segment ending in 'last' to update. split as necessary * to make that work. then, adjust first up so that we only * update one segment at a time. then loop to cover the whole * [ofirst,last] interval. */ nest_info_t *prstat; snapid_t first; fnode_t *pf = parent->get_projected_fnode(); if (last == CEPH_NOSNAP) { first = MAX(ofirst, parent->first); prstat = &pf->rstat; dout(20) << " projecting to head [" << first << "," << last << "] " << *prstat << dendl; if (first > parent->first && !(pf->rstat == pf->accounted_rstat)) { dout(10) << " target snapped and not fully accounted, cow to dirty_old_rstat [" << parent->first << "," << (first-1) << "] " << " " << *prstat << "/" << pf->accounted_rstat << dendl; parent->dirty_old_rstat[first-1].first = parent->first; parent->dirty_old_rstat[first-1].rstat = pf->rstat; parent->dirty_old_rstat[first-1].accounted_rstat = pf->accounted_rstat; } parent->first = first; } else if (last >= parent->first) { first = parent->first; parent->dirty_old_rstat[last].first = first; parent->dirty_old_rstat[last].rstat = pf->rstat; parent->dirty_old_rstat[last].accounted_rstat = pf->accounted_rstat; prstat = &parent->dirty_old_rstat[last].rstat; dout(10) << " projecting to newly split dirty_old_fnode [" << first << "," << last << "] " << " " << *prstat << "/" << pf->accounted_rstat << dendl; } else { // be careful, dirty_old_rstat is a _sparse_ map. // sorry, this is ugly. first = ofirst; // find any intersection with last map::iterator p = parent->dirty_old_rstat.lower_bound(last); if (p == parent->dirty_old_rstat.end()) { dout(20) << " no dirty_old_rstat with last >= last " << last << dendl; if (!parent->dirty_old_rstat.empty() && parent->dirty_old_rstat.rbegin()->first >= first) { dout(20) << " last dirty_old_rstat ends at " << parent->dirty_old_rstat.rbegin()->first << dendl; first = parent->dirty_old_rstat.rbegin()->first+1; } } else { // *p last is >= last if (p->second.first <= last) { // *p intersects [first,last] if (p->second.first < first) { dout(10) << " splitting off left bit [" << p->second.first << "," << first-1 << "]" << dendl; parent->dirty_old_rstat[first-1] = p->second; p->second.first = first; } if (p->second.first > first) first = p->second.first; if (last < p->first) { dout(10) << " splitting off right bit [" << last+1 << "," << p->first << "]" << dendl; parent->dirty_old_rstat[last] = p->second; p->second.first = last+1; } } else { // *p is to the _right_ of [first,last] p = parent->dirty_old_rstat.lower_bound(first); // new *p last is >= first if (p->second.first <= last && // new *p isn't also to the right, and p->first >= first) { // it intersects our first bit, dout(10) << " staying to the right of [" << p->second.first << "," << p->first << "]..." << dendl; first = p->first+1; } dout(10) << " projecting to new dirty_old_rstat [" << first << "," << last << "]" << dendl; } } dout(20) << " projecting to dirty_old_rstat [" << first << "," << last << "]" << dendl; parent->dirty_old_rstat[last].first = first; prstat = &parent->dirty_old_rstat[last].rstat; } // apply dout(20) << " project to [" << first << "," << last << "] " << *prstat << dendl; assert(last >= first); prstat->add(delta); inode.accounted_rstat = inode.rstat; dout(20) << " result [" << first << "," << last << "] " << *prstat << " " << *parent << dendl; last = first-1; } } void MDCache::project_rstat_frag_to_inode(nest_info_t& rstat, nest_info_t& accounted_rstat, snapid_t ofirst, snapid_t last, CInode *pin, bool cow_head) { dout(10) << "project_rstat_frag_to_inode [" << ofirst << "," << last << "]" << dendl; dout(20) << " frag rstat " << rstat << dendl; dout(20) << " frag accounted_rstat " << accounted_rstat << dendl; nest_info_t delta = rstat; delta.sub(accounted_rstat); dout(20) << " delta " << delta << dendl; while (last >= ofirst) { inode_t *pi; snapid_t first; if (last == pin->last) { pi = pin->get_projected_inode(); first = MAX(ofirst, pin->first); if (first > pin->first) { old_inode_t& old = pin->cow_old_inode(first-1, cow_head); dout(20) << " cloned old_inode rstat is " << old.inode.rstat << dendl; } } else { if (last >= pin->first) { first = pin->first; pin->cow_old_inode(last, cow_head); } else { // our life is easier here because old_inodes is not sparse // (although it may not begin at snapid 1) map::iterator p = pin->old_inodes.lower_bound(last); if (p == pin->old_inodes.end()) { dout(10) << " no old_inode <= " << last << ", done." << dendl; break; } first = p->second.first; if (first > last) { dout(10) << " oldest old_inode is [" << first << "," << p->first << "], done." << dendl; assert(p == pin->old_inodes.begin()); break; } if (p->first > last) { dout(10) << " splitting right old_inode [" << first << "," << p->first << "] to [" << (last+1) << "," << p->first << "]" << dendl; pin->old_inodes[last] = p->second; p->second.first = last+1; pin->dirty_old_rstats.insert(p->first); } } if (first < ofirst) { dout(10) << " splitting left old_inode [" << first << "," << last << "] to [" << first << "," << ofirst-1 << "]" << dendl; pin->old_inodes[ofirst-1] = pin->old_inodes[last]; pin->dirty_old_rstats.insert(ofirst-1); pin->old_inodes[last].first = first = ofirst; } pi = &pin->old_inodes[last].inode; pin->dirty_old_rstats.insert(last); } dout(20) << " projecting to [" << first << "," << last << "] " << pi->rstat << dendl; pi->rstat.add(delta); dout(20) << " result [" << first << "," << last << "] " << pi->rstat << dendl; if (pi->rstat.rbytes < 0 && pin->dirfragtree.is_leaf(frag_t())) assert(!"negative rstat rbytes" == g_conf->mds_verify_scatter); last = first-1; } } /* * NOTE: we _have_ to delay the scatter if we are called during a * rejoin, because we can't twiddle locks between when the * rejoin_(weak|strong) is received and when we send the rejoin_ack. * normally, this isn't a problem: a recover mds doesn't twiddle locks * (no requests), and a survivor acks immediately. _except_ that * during rejoin_(weak|strong) processing, we may complete a lock * gather, and do a scatter_writebehind.. and we _can't_ twiddle the * scatterlock state in that case or the lock states will get out of * sync between the auth and replica. * * the simple solution is to never do the scatter here. instead, put * the scatterlock on a list if it isn't already wrlockable. this is * probably the best plan anyway, since we avoid too many * scatters/locks under normal usage. */ /* * some notes on dirlock/nestlock scatterlock semantics: * * the fragstat (dirlock) will never be updated without * dirlock+nestlock wrlock held by the caller. * * the rstat (nestlock) _may_ get updated without a wrlock when nested * data is pushed up the tree. this could be changed with some * restructuring here, but in its current form we ensure that the * fragstat+rstat _always_ reflect an accurrate summation over the dir * frag, which is nice. and, we only need to track frags that need to * be nudged (and not inodes with pending rstat changes that need to * be pushed into the frag). a consequence of this is that the * accounted_rstat on scatterlock sync may not match our current * rstat. this is normal and expected. */ void MDCache::predirty_journal_parents(MutationRef mut, EMetaBlob *blob, CInode *in, CDir *parent, int flags, int linkunlink, snapid_t cfollows) { bool primary_dn = flags & PREDIRTY_PRIMARY; bool do_parent_mtime = flags & PREDIRTY_DIR; bool shallow = flags & PREDIRTY_SHALLOW; assert(mds->mdlog->entry_is_open()); // declare now? if (mut->now == utime_t()) mut->now = ceph_clock_now(g_ceph_context); if (in->is_base()) return; dout(10) << "predirty_journal_parents" << (do_parent_mtime ? " do_parent_mtime":"") << " linkunlink=" << linkunlink << (primary_dn ? " primary_dn":" remote_dn") << (shallow ? " SHALLOW":"") << " follows " << cfollows << " " << *in << dendl; if (!parent) { assert(primary_dn); parent = in->get_projected_parent_dn()->get_dir(); } if (flags == 0 && linkunlink == 0) { dout(10) << " no flags/linkunlink, just adding dir context to blob(s)" << dendl; blob->add_dir_context(parent); return; } // build list of inodes to wrlock, dirty, and update list lsi; CInode *cur = in; CDentry *parentdn = NULL; bool first = true; while (parent) { //assert(cur->is_auth() || !primary_dn); // this breaks the rename auth twiddle hack assert(parent->is_auth()); // opportunistically adjust parent dirfrag CInode *pin = parent->get_inode(); // inode -> dirfrag mut->auth_pin(parent); mut->add_projected_fnode(parent); fnode_t *pf = parent->project_fnode(); pf->version = parent->pre_dirty(); if (do_parent_mtime || linkunlink) { assert(mut->wrlocks.count(&pin->filelock)); assert(cfollows == CEPH_NOSNAP); // update stale fragstat? parent->resync_accounted_fragstat(); if (do_parent_mtime) { pf->fragstat.mtime = mut->now; if (mut->now > pf->rstat.rctime) { dout(10) << "predirty_journal_parents updating mtime on " << *parent << dendl; pf->rstat.rctime = mut->now; } else { dout(10) << "predirty_journal_parents updating mtime UNDERWATER on " << *parent << dendl; } } if (linkunlink) { dout(10) << "predirty_journal_parents updating size on " << *parent << dendl; if (in->is_dir()) { pf->fragstat.nsubdirs += linkunlink; //pf->rstat.rsubdirs += linkunlink; } else { pf->fragstat.nfiles += linkunlink; //pf->rstat.rfiles += linkunlink; } } } // rstat if (!primary_dn) { // don't update parent this pass } else if (!linkunlink && !(parent->inode->nestlock.can_wrlock(-1) && parent->inode->versionlock.can_wrlock())) { dout(20) << " unwritable parent nestlock " << parent->inode->nestlock << ", marking dirty rstat on " << *cur << dendl; cur->mark_dirty_rstat(); } else { // if we don't hold a wrlock reference on this nestlock, take one, // because we are about to write into the dirfrag fnode and that needs // to commit before the lock can cycle. if (linkunlink) { assert(parent->inode->nestlock.get_num_wrlocks() || mut->is_slave()); } if (mut->wrlocks.count(&parent->inode->nestlock) == 0) { dout(10) << " taking wrlock on " << parent->inode->nestlock << " on " << *parent->inode << dendl; mds->locker->wrlock_force(&parent->inode->nestlock, mut); } // now we can project the inode rstat diff the dirfrag SnapRealm *prealm = parent->inode->find_snaprealm(); snapid_t follows = cfollows; if (follows == CEPH_NOSNAP) follows = prealm->get_newest_seq(); snapid_t first = follows+1; // first, if the frag is stale, bring it back in sync. parent->resync_accounted_rstat(); // now push inode rstats into frag project_rstat_inode_to_frag(cur, parent, first, linkunlink); cur->clear_dirty_rstat(); } bool stop = false; if (!pin->is_auth() || (!mut->is_auth_pinned(pin) && !pin->can_auth_pin())) { dout(10) << "predirty_journal_parents !auth or ambig or can't authpin on " << *pin << dendl; stop = true; } // delay propagating until later? if (!stop && !first && g_conf->mds_dirstat_min_interval > 0) { if (pin->last_dirstat_prop.sec() > 0) { double since_last_prop = mut->now - pin->last_dirstat_prop; if (since_last_prop < g_conf->mds_dirstat_min_interval) { dout(10) << "predirty_journal_parents last prop " << since_last_prop << " < " << g_conf->mds_dirstat_min_interval << ", stopping" << dendl; stop = true; } else { dout(10) << "predirty_journal_parents last prop " << since_last_prop << " ago, continuing" << dendl; } } else { dout(10) << "predirty_journal_parents last prop never, stopping" << dendl; stop = true; } } // can cast only because i'm passing nowait=true in the sole user MDRequestRef mdmut = ceph::static_pointer_cast(mut); if (!stop && mut->wrlocks.count(&pin->nestlock) == 0 && (!pin->versionlock.can_wrlock() || // make sure we can take versionlock, too //true !mds->locker->wrlock_start(&pin->nestlock, mdmut, true) )) { // ** do not initiate.. see above comment ** dout(10) << "predirty_journal_parents can't wrlock one of " << pin->versionlock << " or " << pin->nestlock << " on " << *pin << dendl; stop = true; } if (stop) { dout(10) << "predirty_journal_parents stop. marking nestlock on " << *pin << dendl; mds->locker->mark_updated_scatterlock(&pin->nestlock); mut->ls->dirty_dirfrag_nest.push_back(&pin->item_dirty_dirfrag_nest); mut->add_updated_lock(&pin->nestlock); if (do_parent_mtime || linkunlink) { mds->locker->mark_updated_scatterlock(&pin->filelock); mut->ls->dirty_dirfrag_dir.push_back(&pin->item_dirty_dirfrag_dir); mut->add_updated_lock(&pin->filelock); } break; } if (!mut->wrlocks.count(&pin->versionlock)) mds->locker->local_wrlock_grab(&pin->versionlock, mut); assert(mut->wrlocks.count(&pin->nestlock) || mut->is_slave()); pin->last_dirstat_prop = mut->now; // dirfrag -> diri mut->auth_pin(pin); mut->add_projected_inode(pin); lsi.push_front(pin); pin->pre_cow_old_inode(); // avoid cow mayhem! inode_t *pi = pin->project_inode(); pi->version = pin->pre_dirty(); // dirstat if (do_parent_mtime || linkunlink) { dout(20) << "predirty_journal_parents add_delta " << pf->fragstat << dendl; dout(20) << "predirty_journal_parents - " << pf->accounted_fragstat << dendl; bool touched_mtime = false; pi->dirstat.add_delta(pf->fragstat, pf->accounted_fragstat, touched_mtime); pf->accounted_fragstat = pf->fragstat; if (touched_mtime) pi->mtime = pi->ctime = pi->dirstat.mtime; dout(20) << "predirty_journal_parents gives " << pi->dirstat << " on " << *pin << dendl; if (parent->get_frag() == frag_t()) { // i.e., we are the only frag if (pi->dirstat.size() < 0) assert(!"negative dirstat size" == g_conf->mds_verify_scatter); if (pi->dirstat.size() != pf->fragstat.size()) { mds->clog.error() << "unmatched fragstat size on single dirfrag " << parent->dirfrag() << ", inode has " << pi->dirstat << ", dirfrag has " << pf->fragstat << "\n"; // trust the dirfrag for now pi->dirstat = pf->fragstat; assert(!"unmatched fragstat size" == g_conf->mds_verify_scatter); } } } /* * the rule here is to follow the _oldest_ parent with dirty rstat * data. if we don't propagate all data, we add ourselves to the * nudge list. that way all rstat data will (eventually) get * pushed up the tree. * * actually, no. for now, silently drop rstats for old parents. we need * hard link backpointers to do the above properly. */ // stop? if (pin->is_base()) break; parentdn = pin->get_projected_parent_dn(); assert(parentdn); // rstat if (primary_dn) { dout(10) << "predirty_journal_parents frag->inode on " << *parent << dendl; // first, if the frag is stale, bring it back in sync. parent->resync_accounted_rstat(); for (map::iterator p = parent->dirty_old_rstat.begin(); p != parent->dirty_old_rstat.end(); ++p) project_rstat_frag_to_inode(p->second.rstat, p->second.accounted_rstat, p->second.first, p->first, pin, true);//false); parent->dirty_old_rstat.clear(); project_rstat_frag_to_inode(pf->rstat, pf->accounted_rstat, parent->first, CEPH_NOSNAP, pin, true);//false); pf->accounted_rstat = pf->rstat; if (parent->get_frag() == frag_t()) { // i.e., we are the only frag if (pi->rstat.rbytes != pf->rstat.rbytes) { mds->clog.error() << "unmatched rstat rbytes on single dirfrag " << parent->dirfrag() << ", inode has " << pi->rstat << ", dirfrag has " << pf->rstat << "\n"; // trust the dirfrag for now pi->rstat = pf->rstat; assert(!"unmatched rstat rbytes" == g_conf->mds_verify_scatter); } } } parent->check_rstats(); // next parent! cur = pin; parent = parentdn->get_dir(); linkunlink = 0; do_parent_mtime = false; primary_dn = true; first = false; } // now, stick it in the blob assert(parent); assert(parent->is_auth()); blob->add_dir_context(parent); blob->add_dir(parent, true); for (list::iterator p = lsi.begin(); p != lsi.end(); ++p) { CInode *cur = *p; journal_dirty_inode(mut.get(), blob, cur); } } // =================================== // slave requests /* * some handlers for master requests with slaves. we need to make * sure slaves journal commits before we forget we mastered them and * remove them from the uncommitted_masters map (used during recovery * to commit|abort slaves). */ struct C_MDC_CommittedMaster : public Context { MDCache *cache; metareqid_t reqid; C_MDC_CommittedMaster(MDCache *s, metareqid_t r) : cache(s), reqid(r) {} void finish(int r) { cache->_logged_master_commit(reqid); } }; void MDCache::log_master_commit(metareqid_t reqid) { dout(10) << "log_master_commit " << reqid << dendl; uncommitted_masters[reqid].committing = true; mds->mdlog->start_submit_entry(new ECommitted(reqid), new C_MDC_CommittedMaster(this, reqid)); } void MDCache::_logged_master_commit(metareqid_t reqid) { dout(10) << "_logged_master_commit " << reqid << dendl; assert(uncommitted_masters.count(reqid)); uncommitted_masters[reqid].ls->uncommitted_masters.erase(reqid); mds->queue_waiters(uncommitted_masters[reqid].waiters); uncommitted_masters.erase(reqid); } // while active... void MDCache::committed_master_slave(metareqid_t r, int from) { dout(10) << "committed_master_slave mds." << from << " on " << r << dendl; assert(uncommitted_masters.count(r)); uncommitted_masters[r].slaves.erase(from); if (!uncommitted_masters[r].recovering && uncommitted_masters[r].slaves.empty()) log_master_commit(r); } void MDCache::logged_master_update(metareqid_t reqid) { dout(10) << "logged_master_update " << reqid << dendl; assert(uncommitted_masters.count(reqid)); uncommitted_masters[reqid].safe = true; if (pending_masters.count(reqid)) { pending_masters.erase(reqid); if (pending_masters.empty()) process_delayed_resolve(); } } /* * Master may crash after receiving all slaves' commit acks, but before journalling * the final commit. Slaves may crash after journalling the slave commit, but before * sending commit ack to the master. Commit masters with no uncommitted slave when * resolve finishes. */ void MDCache::finish_committed_masters() { for (map::iterator p = uncommitted_masters.begin(); p != uncommitted_masters.end(); ++p) { p->second.recovering = false; if (!p->second.committing && p->second.slaves.empty()) { dout(10) << "finish_committed_masters " << p->first << dendl; log_master_commit(p->first); } } } /* * at end of resolve... we must journal a commit|abort for all slave * updates, before moving on. * * this is so that the master can safely journal ECommitted on ops it * masters when it reaches up:active (all other recovering nodes must * complete resolve before that happens). */ struct C_MDC_SlaveCommit : public Context { MDCache *cache; int from; metareqid_t reqid; C_MDC_SlaveCommit(MDCache *c, int f, metareqid_t r) : cache(c), from(f), reqid(r) {} void finish(int r) { cache->_logged_slave_commit(from, reqid); } }; void MDCache::_logged_slave_commit(int from, metareqid_t reqid) { dout(10) << "_logged_slave_commit from mds." << from << " " << reqid << dendl; // send a message MMDSSlaveRequest *req = new MMDSSlaveRequest(reqid, 0, MMDSSlaveRequest::OP_COMMITTED); mds->send_message_mds(req, from); } // ==================================================================== // import map, recovery void MDCache::_move_subtree_map_bound(dirfrag_t df, dirfrag_t oldparent, dirfrag_t newparent, map >& subtrees) { if (subtrees.count(oldparent)) { vector& v = subtrees[oldparent]; dout(10) << " removing " << df << " from " << oldparent << " bounds " << v << dendl; for (vector::iterator it = v.begin(); it != v.end(); ++it) if (*it == df) { v.erase(it); break; } } if (subtrees.count(newparent)) { vector& v = subtrees[newparent]; dout(10) << " adding " << df << " to " << newparent << " bounds " << v << dendl; v.push_back(df); } } ESubtreeMap *MDCache::create_subtree_map() { dout(10) << "create_subtree_map " << num_subtrees() << " subtrees, " << num_subtrees_fullauth() << " fullauth" << dendl; show_subtrees(); ESubtreeMap *le = new ESubtreeMap(); mds->mdlog->start_entry(le); CDir *mydir = 0; if (myin) { mydir = myin->get_dirfrag(frag_t()); } // include all auth subtrees, and their bounds. // and a spanning tree to tie it to the root. for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = p->first; // journal subtree as "ours" if we are // me, -2 // me, me // me, !me (may be importing and ambiguous!) // so not // !me, * if (dir->get_dir_auth().first != mds->whoami) continue; if (migrator->is_ambiguous_import(dir->dirfrag()) || my_ambiguous_imports.count(dir->dirfrag())) { dout(15) << " ambig subtree " << *dir << dendl; le->ambiguous_subtrees.insert(dir->dirfrag()); } else { dout(15) << " subtree " << *dir << dendl; } le->subtrees[dir->dirfrag()].clear(); le->metablob.add_dir_context(dir, EMetaBlob::TO_ROOT); le->metablob.add_dir(dir, false); if (mydir == dir) mydir = NULL; // bounds for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { CDir *bound = *q; dout(15) << " subtree bound " << *bound << dendl; le->subtrees[dir->dirfrag()].push_back(bound->dirfrag()); le->metablob.add_dir_context(bound, EMetaBlob::TO_ROOT); le->metablob.add_dir(bound, false); } } // apply projected renames for (map > >::iterator p = projected_subtree_renames.begin(); p != projected_subtree_renames.end(); ++p) { for (list >::iterator q = p->second.begin(); q != p->second.end(); ++q) { CInode *diri = p->first; CDir *olddir = q->first; CDir *newdir = q->second; dout(10) << " adjusting for projected rename of " << *diri << " to " << *newdir << dendl; list dfls; diri->get_dirfrags(dfls); for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) { CDir *dir = *p; dout(10) << "dirfrag " << dir->dirfrag() << " " << *dir << dendl; CDir *oldparent = get_projected_subtree_root(olddir); dout(10) << " old parent " << oldparent->dirfrag() << " " << *oldparent << dendl; CDir *newparent = get_projected_subtree_root(newdir); dout(10) << " new parent " << newparent->dirfrag() << " " << *newparent << dendl; if (oldparent == newparent) { dout(10) << "parent unchanged for " << dir->dirfrag() << " at " << oldparent->dirfrag() << dendl; continue; } bool journal_dir = false; if (dir->is_subtree_root()) { if (le->subtrees.count(newparent->dirfrag()) && oldparent->get_dir_auth() != newparent->get_dir_auth()) journal_dir = true; // children are fine. change parent. _move_subtree_map_bound(dir->dirfrag(), oldparent->dirfrag(), newparent->dirfrag(), le->subtrees); } else { // mid-subtree. if (oldparent->get_dir_auth() != newparent->get_dir_auth()) { dout(10) << " creating subtree for " << dir->dirfrag() << dendl; // if oldparent is auth, subtree is mine; include it. if (le->subtrees.count(oldparent->dirfrag())) { le->subtrees[dir->dirfrag()].clear(); journal_dir = true; } // if newparent is auth, subtree is a new bound if (le->subtrees.count(newparent->dirfrag())) { le->subtrees[newparent->dirfrag()].push_back(dir->dirfrag()); // newparent is auth; new bound journal_dir = true; } newparent = dir; } // see if any old bounds move to the new parent. for (set::iterator p = subtrees[oldparent].begin(); p != subtrees[oldparent].end(); ++p) { CDir *bound = *p; if (dir->contains(bound->get_parent_dir())) _move_subtree_map_bound(bound->dirfrag(), oldparent->dirfrag(), newparent->dirfrag(), le->subtrees); } } if (journal_dir) { le->metablob.add_dir_context(dir, EMetaBlob::TO_ROOT); le->metablob.add_dir(dir, false); } } } } // simplify the journaled map. our in memory map may have more // subtrees than needed due to migrations that are just getting // started or just completing. but on replay, the "live" map will // be simple and we can do a straight comparison. for (map >::iterator p = le->subtrees.begin(); p != le->subtrees.end(); ++p) { if (le->ambiguous_subtrees.count(p->first)) continue; unsigned i = 0; while (i < p->second.size()) { dirfrag_t b = p->second[i]; if (le->subtrees.count(b) && le->ambiguous_subtrees.count(b) == 0) { vector& bb = le->subtrees[b]; dout(10) << "simplify: " << p->first << " swallowing " << b << " with bounds " << bb << dendl; for (vector::iterator r = bb.begin(); r != bb.end(); ++r) p->second.push_back(*r); le->subtrees.erase(b); p->second.erase(p->second.begin() + i); } else { ++i; } } } dout(15) << " subtrees " << le->subtrees << dendl; dout(15) << " ambiguous_subtrees " << le->ambiguous_subtrees << dendl; if (mydir) { // include my dir le->metablob.add_dir_context(mydir, EMetaBlob::TO_ROOT); le->metablob.add_dir(mydir, false); } //le->metablob.print(cout); le->expire_pos = mds->mdlog->journaler->get_expire_pos(); return le; } void MDCache::resolve_start() { dout(10) << "resolve_start" << dendl; if (mds->mdsmap->get_root() != mds->whoami) { // if we don't have the root dir, adjust it to UNKNOWN. during // resolve we want mds0 to explicit claim the portion of it that // it owns, so that anything beyond its bounds get left as // unknown. CDir *rootdir = root->get_dirfrag(frag_t()); if (rootdir) adjust_subtree_auth(rootdir, CDIR_AUTH_UNKNOWN); } resolve_gather = recovery_set; } void MDCache::send_resolves() { send_slave_resolves(); if (!resolve_ack_gather.empty()) { dout(10) << "send_resolves still waiting for resolve ack from (" << resolve_ack_gather << ")" << dendl; return; } if (!need_resolve_rollback.empty()) { dout(10) << "send_resolves still waiting for rollback to commit on (" << need_resolve_rollback << ")" << dendl; return; } send_subtree_resolves(); } void MDCache::send_slave_resolves() { dout(10) << "send_slave_resolves" << dendl; map resolves; if (mds->is_resolve()) { for (map >::iterator p = uncommitted_slave_updates.begin(); p != uncommitted_slave_updates.end(); ++p) { resolves[p->first] = new MMDSResolve; for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(10) << " including uncommitted " << q->first << dendl; resolves[p->first]->add_slave_request(q->first); } } } else { set resolve_set; mds->mdsmap->get_mds_set(resolve_set, MDSMap::STATE_RESOLVE); for (ceph::unordered_map::iterator p = active_requests.begin(); p != active_requests.end(); ++p) { MDRequestRef& mdr = p->second; if (!mdr->is_slave() || !mdr->slave_did_prepare()) continue; int master = mdr->slave_to_mds; if (resolve_set.count(master) || is_ambiguous_slave_update(p->first, master)) { dout(10) << " including uncommitted " << *mdr << dendl; if (!resolves.count(master)) resolves[master] = new MMDSResolve; if (mdr->has_more() && mdr->more()->is_inode_exporter) { // re-send cap exports CInode *in = mdr->more()->rename_inode; map cap_map; in->export_client_caps(cap_map); bufferlist bl; ::encode(in->ino(), bl); ::encode(cap_map, bl); resolves[master]->add_slave_request(p->first, bl); } else { resolves[master]->add_slave_request(p->first); } } } } for (map::iterator p = resolves.begin(); p != resolves.end(); ++p) { dout(10) << "sending slave resolve to mds." << p->first << dendl; mds->send_message_mds(p->second, p->first); resolve_ack_gather.insert(p->first); } } void MDCache::send_subtree_resolves() { dout(10) << "send_subtree_resolves" << dendl; if (migrator->is_exporting() || migrator->is_importing()) { dout(7) << "send_subtree_resolves waiting, imports/exports still in progress" << dendl; migrator->show_importing(); migrator->show_exporting(); resolves_pending = true; return; // not now } map resolves; for (set::iterator p = recovery_set.begin(); p != recovery_set.end(); ++p) { if (*p == mds->whoami) continue; if (mds->is_resolve() || mds->mdsmap->is_resolve(*p)) resolves[*p] = new MMDSResolve; } // known for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = p->first; // only our subtrees if (dir->authority().first != mds->get_nodeid()) continue; if (mds->is_resolve() && my_ambiguous_imports.count(dir->dirfrag())) continue; // we'll add it below if (migrator->is_ambiguous_import(dir->dirfrag())) { // ambiguous (mid-import) set bounds; get_subtree_bounds(dir, bounds); vector dfls; for (set::iterator q = bounds.begin(); q != bounds.end(); ++q) dfls.push_back((*q)->dirfrag()); for (map::iterator q = resolves.begin(); q != resolves.end(); ++q) resolves[q->first]->add_ambiguous_import(dir->dirfrag(), dfls); dout(10) << " ambig " << dir->dirfrag() << " " << dfls << dendl; } else { // not ambiguous. for (map::iterator q = resolves.begin(); q != resolves.end(); ++q) resolves[q->first]->add_subtree(dir->dirfrag()); // bounds too vector dfls; for (set::iterator q = subtrees[dir].begin(); q != subtrees[dir].end(); ++q) { CDir *bound = *q; dfls.push_back(bound->dirfrag()); for (map::iterator r = resolves.begin(); r != resolves.end(); ++r) resolves[r->first]->add_subtree_bound(dir->dirfrag(), bound->dirfrag()); } dout(10) << " claim " << dir->dirfrag() << " " << dfls << dendl; } } // ambiguous for (map >::iterator p = my_ambiguous_imports.begin(); p != my_ambiguous_imports.end(); ++p) { for (map::iterator q = resolves.begin(); q != resolves.end(); ++q) resolves[q->first]->add_ambiguous_import(p->first, p->second); dout(10) << " ambig " << p->first << " " << p->second << dendl; } // send for (map::iterator p = resolves.begin(); p != resolves.end(); ++p) { dout(10) << "sending subtee resolve to mds." << p->first << dendl; mds->send_message_mds(p->second, p->first); } resolves_pending = false; } void MDCache::handle_mds_failure(int who) { dout(7) << "handle_mds_failure mds." << who << dendl; // make note of recovery set mds->mdsmap->get_recovery_mds_set(recovery_set); recovery_set.erase(mds->get_nodeid()); dout(1) << "handle_mds_failure mds." << who << " : recovery peers are " << recovery_set << dendl; resolve_gather.insert(who); discard_delayed_resolve(who); ambiguous_slave_updates.erase(who); rejoin_gather.insert(who); rejoin_sent.erase(who); // i need to send another rejoin_ack_gather.erase(who); // i'll need/get another. dout(10) << " resolve_gather " << resolve_gather << dendl; dout(10) << " resolve_ack_gather " << resolve_ack_gather << dendl; dout(10) << " rejoin_sent " << rejoin_sent << dendl; dout(10) << " rejoin_gather " << rejoin_gather << dendl; dout(10) << " rejoin_ack_gather " << rejoin_ack_gather << dendl; // tell the migrator too. migrator->handle_mds_failure_or_stop(who); // clean up any requests slave to/from this node list finish; for (ceph::unordered_map::iterator p = active_requests.begin(); p != active_requests.end(); ++p) { MDRequestRef& mdr = p->second;; // slave to the failed node? if (mdr->slave_to_mds == who) { if (mdr->slave_did_prepare()) { dout(10) << " slave request " << *mdr << " uncommitted, will resolve shortly" << dendl; if (!mdr->more()->waiting_on_slave.empty()) { assert(mdr->more()->srcdn_auth_mds == mds->get_nodeid()); // will rollback, no need to wait if (mdr->slave_request) { mdr->slave_request->put(); mdr->slave_request = 0; } mdr->more()->waiting_on_slave.clear(); } } else { dout(10) << " slave request " << *mdr << " has no prepare, finishing up" << dendl; if (mdr->slave_request) mdr->aborted = true; else finish.push_back(mdr); } } if (mdr->is_slave() && mdr->slave_did_prepare()) { if (mdr->more()->waiting_on_slave.count(who)) { assert(mdr->more()->srcdn_auth_mds == mds->get_nodeid()); dout(10) << " slave request " << *mdr << " no longer need rename notity ack from mds." << who << dendl; mdr->more()->waiting_on_slave.erase(who); if (mdr->more()->waiting_on_slave.empty() && mdr->slave_request) mds->queue_waiter(new C_MDS_RetryRequest(this, mdr)); } if (mdr->more()->srcdn_auth_mds == who && mds->mdsmap->is_clientreplay_or_active_or_stopping(mdr->slave_to_mds)) { // rename srcdn's auth mds failed, resolve even I'm a survivor. dout(10) << " slave request " << *mdr << " uncommitted, will resolve shortly" << dendl; add_ambiguous_slave_update(p->first, mdr->slave_to_mds); } } // failed node is slave? if (mdr->is_master() && !mdr->committing) { if (mdr->more()->srcdn_auth_mds == who) { dout(10) << " master request " << *mdr << " waiting for rename srcdn's auth mds." << who << " to recover" << dendl; assert(mdr->more()->witnessed.count(who) == 0); if (mdr->more()->is_ambiguous_auth) mdr->clear_ambiguous_auth(); // rename srcdn's auth mds failed, all witnesses will rollback mdr->more()->witnessed.clear(); pending_masters.erase(p->first); } if (mdr->more()->witnessed.count(who)) { int srcdn_auth = mdr->more()->srcdn_auth_mds; if (srcdn_auth >= 0 && mdr->more()->waiting_on_slave.count(srcdn_auth)) { dout(10) << " master request " << *mdr << " waiting for rename srcdn's auth mds." << mdr->more()->srcdn_auth_mds << " to reply" << dendl; // waiting for the slave (rename srcdn's auth mds), delay sending resolve ack // until either the request is committing or the slave also fails. assert(mdr->more()->waiting_on_slave.size() == 1); pending_masters.insert(p->first); } else { dout(10) << " master request " << *mdr << " no longer witnessed by slave mds." << who << " to recover" << dendl; if (srcdn_auth >= 0) assert(mdr->more()->witnessed.count(srcdn_auth) == 0); // discard this peer's prepare (if any) mdr->more()->witnessed.erase(who); } } if (mdr->more()->waiting_on_slave.count(who)) { dout(10) << " master request " << *mdr << " waiting for slave mds." << who << " to recover" << dendl; // retry request when peer recovers mdr->more()->waiting_on_slave.erase(who); if (mdr->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(who, new C_MDS_RetryRequest(this, mdr)); } if (mdr->locking && mdr->locking_target_mds == who) mdr->finish_locking(mdr->locking); } } for (map::iterator p = uncommitted_masters.begin(); p != uncommitted_masters.end(); ++p) { // The failed MDS may have already committed the slave update if (p->second.slaves.count(who)) { p->second.recovering = true; p->second.slaves.erase(who); } } while (!finish.empty()) { dout(10) << "cleaning up slave request " << *finish.front() << dendl; request_finish(finish.front()); finish.pop_front(); } kick_find_ino_peers(who); kick_open_ino_peers(who); show_subtrees(); } /* * handle_mds_recovery - called on another node's transition * from resolve -> active. */ void MDCache::handle_mds_recovery(int who) { dout(7) << "handle_mds_recovery mds." << who << dendl; // exclude all discover waiters. kick_discovers() will do the job static const uint64_t i_mask = CInode::WAIT_ANY_MASK & ~CInode::WAIT_DIR; static const uint64_t d_mask = CDir::WAIT_ANY_MASK & ~CDir::WAIT_DENTRY; list waiters; // wake up any waiters in their subtrees for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = p->first; if (dir->authority().first != who || dir->authority().second == mds->whoami) continue; assert(!dir->is_auth()); // wake any waiters list q; q.push_back(dir); while (!q.empty()) { CDir *d = q.front(); q.pop_front(); d->take_waiting(d_mask, waiters); // inode waiters too for (CDir::map_t::iterator p = d->items.begin(); p != d->items.end(); ++p) { CDentry *dn = p->second; CDentry::linkage_t *dnl = dn->get_linkage(); if (dnl->is_primary()) { dnl->get_inode()->take_waiting(i_mask, waiters); // recurse? list ls; dnl->get_inode()->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *subdir = *p; if (!subdir->is_subtree_root()) q.push_back(subdir); } } } } } kick_discovers(who); kick_open_ino_peers(who); kick_find_ino_peers(who); // queue them up. mds->queue_waiters(waiters); } void MDCache::set_recovery_set(set& s) { dout(7) << "set_recovery_set " << s << dendl; recovery_set = s; } /* * during resolve state, we share resolves to determine who * is authoritative for which trees. we expect to get an resolve * from _everyone_ in the recovery_set (the mds cluster at the time of * the first failure). * * This functions puts the passed message before returning */ void MDCache::handle_resolve(MMDSResolve *m) { dout(7) << "handle_resolve from " << m->get_source() << dendl; int from = m->get_source().num(); if (mds->get_state() < MDSMap::STATE_RESOLVE) { if (mds->get_want_state() == CEPH_MDS_STATE_RESOLVE) { mds->wait_for_resolve(new C_MDS_RetryMessage(mds, m)); return; } // wait until we reach the resolve stage! m->put(); return; } discard_delayed_resolve(from); // ambiguous slave requests? if (!m->slave_requests.empty()) { for (map::iterator p = m->slave_requests.begin(); p != m->slave_requests.end(); ++p) { if (uncommitted_masters.count(p->first) && !uncommitted_masters[p->first].safe) pending_masters.insert(p->first); } if (!pending_masters.empty()) { dout(10) << " still have pending updates, delay processing slave resolve" << dendl; delayed_resolve[from] = m; return; } MMDSResolveAck *ack = new MMDSResolveAck; for (map::iterator p = m->slave_requests.begin(); p != m->slave_requests.end(); ++p) { if (uncommitted_masters.count(p->first)) { //mds->sessionmap.have_completed_request(p->first)) { // COMMIT dout(10) << " ambiguous slave request " << *p << " will COMMIT" << dendl; ack->add_commit(p->first); uncommitted_masters[p->first].slaves.insert(from); // wait for slave OP_COMMITTED before we log ECommitted if (p->second.length() > 0) { // slave wants to export caps (rename) assert(mds->is_resolve()); inodeno_t ino; map cap_exports; bufferlist::iterator q = p->second.begin(); ::decode(ino, q); ::decode(cap_exports, q); assert(get_inode(ino)); for (map::iterator q = cap_exports.begin(); q != cap_exports.end(); ++q) { Capability::Import& im = rejoin_imported_caps[from][ino][q->first]; im.cap_id = ++last_cap_id; // assign a new cap ID im.issue_seq = 1; im.mseq = q->second.mseq; } // will process these caps in rejoin stage rejoin_slave_exports[ino].first = from; rejoin_slave_exports[ino].second.swap(cap_exports); // send information of imported caps back to slave ::encode(rejoin_imported_caps[from][ino], ack->commit[p->first]); } } else { // ABORT dout(10) << " ambiguous slave request " << *p << " will ABORT" << dendl; ack->add_abort(p->first); } } mds->send_message(ack, m->get_connection()); m->put(); return; } if (!resolve_ack_gather.empty() || !need_resolve_rollback.empty()) { dout(10) << "delay processing subtree resolve" << dendl; delayed_resolve[from] = m; return; } // am i a surviving ambiguous importer? if (mds->is_clientreplay() || mds->is_active() || mds->is_stopping()) { // check for any import success/failure (from this node) map >::iterator p = my_ambiguous_imports.begin(); while (p != my_ambiguous_imports.end()) { map >::iterator next = p; ++next; CDir *dir = get_dirfrag(p->first); assert(dir); dout(10) << "checking ambiguous import " << *dir << dendl; if (migrator->is_importing(dir->dirfrag()) && migrator->get_import_peer(dir->dirfrag()) == from) { assert(migrator->get_import_state(dir->dirfrag()) == Migrator::IMPORT_ACKING); // check if sender claims the subtree bool claimed_by_sender = false; for (map >::iterator q = m->subtrees.begin(); q != m->subtrees.end(); ++q) { // an ambiguous import won't race with a refragmentation; it's appropriate to force here. CDir *base = get_force_dirfrag(q->first); if (!base || !base->contains(dir)) continue; // base not dir or an ancestor of dir, clearly doesn't claim dir. bool inside = true; set bounds; get_force_dirfrag_bound_set(q->second, bounds); for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bound = *p; if (bound->contains(dir)) { inside = false; // nope, bound is dir or parent of dir, not inside. break; } } if (inside) claimed_by_sender = true; } if (claimed_by_sender) { dout(7) << "ambiguous import failed on " << *dir << dendl; migrator->import_reverse(dir); } else { dout(7) << "ambiguous import succeeded on " << *dir << dendl; migrator->import_finish(dir, true); } my_ambiguous_imports.erase(p); // no longer ambiguous. } p = next; } } // update my dir_auth values // need to do this on recoverying nodes _and_ bystanders (to resolve ambiguous // migrations between other nodes) for (map >::iterator pi = m->subtrees.begin(); pi != m->subtrees.end(); ++pi) { dout(10) << "peer claims " << pi->first << " bounds " << pi->second << dendl; CDir *dir = get_force_dirfrag(pi->first); if (!dir) continue; adjust_bounded_subtree_auth(dir, pi->second, from); try_subtree_merge(dir); } show_subtrees(); // note ambiguous imports too for (map >::iterator pi = m->ambiguous_imports.begin(); pi != m->ambiguous_imports.end(); ++pi) { dout(10) << "noting ambiguous import on " << pi->first << " bounds " << pi->second << dendl; other_ambiguous_imports[from][pi->first].swap( pi->second ); } // did i get them all? resolve_gather.erase(from); maybe_resolve_finish(); m->put(); } void MDCache::process_delayed_resolve() { dout(10) << "process_delayed_resolve" << dendl; map tmp; tmp.swap(delayed_resolve); for (map::iterator p = tmp.begin(); p != tmp.end(); ++p) handle_resolve(p->second); } void MDCache::discard_delayed_resolve(int who) { if (delayed_resolve.count(who)) { delayed_resolve[who]->put(); delayed_resolve.erase(who); } } void MDCache::maybe_resolve_finish() { assert(resolve_ack_gather.empty()); assert(need_resolve_rollback.empty()); if (!resolve_gather.empty()) { dout(10) << "maybe_resolve_finish still waiting for resolves (" << resolve_gather << ")" << dendl; return; } dout(10) << "maybe_resolve_finish got all resolves+resolve_acks, done." << dendl; disambiguate_imports(); finish_committed_masters(); if (mds->is_resolve()) { trim_unlinked_inodes(); recalc_auth_bits(); mds->resolve_done(); } else { maybe_send_pending_rejoins(); } } /* This functions puts the passed message before returning */ void MDCache::handle_resolve_ack(MMDSResolveAck *ack) { dout(10) << "handle_resolve_ack " << *ack << " from " << ack->get_source() << dendl; int from = ack->get_source().num(); if (!resolve_ack_gather.count(from) || mds->mdsmap->get_state(from) < MDSMap::STATE_RESOLVE) { ack->put(); return; } if (ambiguous_slave_updates.count(from)) { assert(mds->mdsmap->is_clientreplay_or_active_or_stopping(from)); assert(mds->is_clientreplay() || mds->is_active() || mds->is_stopping()); } for (map::iterator p = ack->commit.begin(); p != ack->commit.end(); ++p) { dout(10) << " commit on slave " << p->first << dendl; if (ambiguous_slave_updates.count(from)) { remove_ambiguous_slave_update(p->first, from); continue; } if (mds->is_resolve()) { // replay MDSlaveUpdate *su = get_uncommitted_slave_update(p->first, from); assert(su); // log commit mds->mdlog->start_submit_entry(new ESlaveUpdate(mds->mdlog, "unknown", p->first, from, ESlaveUpdate::OP_COMMIT, su->origop)); mds->mdlog->wait_for_safe(new C_MDC_SlaveCommit(this, from, p->first)); mds->mdlog->flush(); finish_uncommitted_slave_update(p->first, from); } else { MDRequestRef mdr = request_get(p->first); // information about master imported caps if (p->second.length() > 0) mdr->more()->inode_import.claim(p->second); assert(mdr->slave_request == 0); // shouldn't be doing anything! request_finish(mdr); } } for (vector::iterator p = ack->abort.begin(); p != ack->abort.end(); ++p) { dout(10) << " abort on slave " << *p << dendl; if (mds->is_resolve()) { MDSlaveUpdate *su = get_uncommitted_slave_update(*p, from); assert(su); // perform rollback (and journal a rollback entry) // note: this will hold up the resolve a bit, until the rollback entries journal. MDRequestRef null_ref; switch (su->origop) { case ESlaveUpdate::LINK: mds->server->do_link_rollback(su->rollback, from, null_ref); break; case ESlaveUpdate::RENAME: mds->server->do_rename_rollback(su->rollback, from, null_ref); break; case ESlaveUpdate::RMDIR: mds->server->do_rmdir_rollback(su->rollback, from, null_ref); break; default: assert(0); } } else { MDRequestRef mdr = request_get(*p); mdr->aborted = true; if (mdr->slave_request) { if (mdr->more()->slave_commit) // journaling slave prepare ? add_rollback(*p, from); } else { request_finish(mdr); } } } if (!ambiguous_slave_updates.count(from)) resolve_ack_gather.erase(from); if (resolve_ack_gather.empty() && need_resolve_rollback.empty()) { send_subtree_resolves(); process_delayed_resolve(); } ack->put(); } void MDCache::add_uncommitted_slave_update(metareqid_t reqid, int master, MDSlaveUpdate *su) { assert(uncommitted_slave_updates[master].count(reqid) == 0); uncommitted_slave_updates[master][reqid] = su; for(set::iterator p = su->olddirs.begin(); p != su->olddirs.end(); ++p) uncommitted_slave_rename_olddir[*p]++; for(set::iterator p = su->unlinked.begin(); p != su->unlinked.end(); ++p) uncommitted_slave_unlink[*p]++; } void MDCache::finish_uncommitted_slave_update(metareqid_t reqid, int master) { assert(uncommitted_slave_updates[master].count(reqid)); MDSlaveUpdate* su = uncommitted_slave_updates[master][reqid]; uncommitted_slave_updates[master].erase(reqid); if (uncommitted_slave_updates[master].empty()) uncommitted_slave_updates.erase(master); // discard the non-auth subtree we renamed out of for(set::iterator p = su->olddirs.begin(); p != su->olddirs.end(); ++p) { CInode *diri = *p; map::iterator it = uncommitted_slave_rename_olddir.find(diri); assert(it != uncommitted_slave_rename_olddir.end()); it->second--; if (it->second == 0) { uncommitted_slave_rename_olddir.erase(it); list ls; diri->get_dirfrags(ls); for (list::iterator q = ls.begin(); q != ls.end(); ++q) { CDir *root = get_subtree_root(*q); if (root->get_dir_auth() == CDIR_AUTH_UNDEF) { try_trim_non_auth_subtree(root); if (*q != root) break; } } } else assert(it->second > 0); } // removed the inodes that were unlinked by slave update for(set::iterator p = su->unlinked.begin(); p != su->unlinked.end(); ++p) { CInode *in = *p; map::iterator it = uncommitted_slave_unlink.find(in); assert(it != uncommitted_slave_unlink.end()); it->second--; if (it->second == 0) { uncommitted_slave_unlink.erase(it); if (!in->get_projected_parent_dn()) mds->mdcache->remove_inode_recursive(in); } else assert(it->second > 0); } delete su; } MDSlaveUpdate* MDCache::get_uncommitted_slave_update(metareqid_t reqid, int master) { MDSlaveUpdate* su = NULL; if (uncommitted_slave_updates.count(master) && uncommitted_slave_updates[master].count(reqid)) { su = uncommitted_slave_updates[master][reqid]; assert(su); } return su; } void MDCache::finish_rollback(metareqid_t reqid) { assert(need_resolve_rollback.count(reqid)); if (mds->is_resolve()) finish_uncommitted_slave_update(reqid, need_resolve_rollback[reqid]); need_resolve_rollback.erase(reqid); if (resolve_ack_gather.empty() && need_resolve_rollback.empty()) { send_subtree_resolves(); process_delayed_resolve(); } } void MDCache::disambiguate_imports() { dout(10) << "disambiguate_imports" << dendl; // other nodes' ambiguous imports for (map > >::iterator p = other_ambiguous_imports.begin(); p != other_ambiguous_imports.end(); ++p) { int who = p->first; dout(10) << "ambiguous imports for mds." << who << dendl; for (map >::iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(10) << " ambiguous import " << q->first << " bounds " << q->second << dendl; // an ambiguous import will not race with a refragmentation; it's appropriate to force here. CDir *dir = get_force_dirfrag(q->first); if (!dir) continue; if (dir->is_ambiguous_auth() || // works for me_ambig or if i am a surviving bystander dir->authority() == CDIR_AUTH_UNDEF) { // resolving dout(10) << " mds." << who << " did import " << *dir << dendl; adjust_bounded_subtree_auth(dir, q->second, who); try_subtree_merge(dir); } else { dout(10) << " mds." << who << " did not import " << *dir << dendl; } } } other_ambiguous_imports.clear(); // my ambiguous imports pair me_ambig(mds->whoami, mds->whoami); while (!my_ambiguous_imports.empty()) { map >::iterator q = my_ambiguous_imports.begin(); CDir *dir = get_dirfrag(q->first); if (!dir) continue; if (dir->authority() != me_ambig) { dout(10) << "ambiguous import auth known, must not be me " << *dir << dendl; cancel_ambiguous_import(dir); // subtree may have been swallowed by another node claiming dir // as their own. CDir *root = get_subtree_root(dir); if (root != dir) dout(10) << " subtree root is " << *root << dendl; assert(root->dir_auth.first != mds->whoami); // no us! try_trim_non_auth_subtree(root); mds->mdlog->start_submit_entry(new EImportFinish(dir, false)); } else { dout(10) << "ambiguous import auth unclaimed, must be me " << *dir << dendl; finish_ambiguous_import(q->first); mds->mdlog->start_submit_entry(new EImportFinish(dir, true)); } } assert(my_ambiguous_imports.empty()); mds->mdlog->flush(); if (mds->is_resolve()) { // verify all my subtrees are unambiguous! for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = p->first; if (dir->is_ambiguous_dir_auth()) { dout(0) << "disambiguate_imports uh oh, dir_auth is still ambiguous for " << *dir << dendl; show_subtrees(); } assert(!dir->is_ambiguous_dir_auth()); } } show_subtrees(); } void MDCache::add_ambiguous_import(dirfrag_t base, const vector& bounds) { assert(my_ambiguous_imports.count(base) == 0); my_ambiguous_imports[base] = bounds; } void MDCache::add_ambiguous_import(CDir *base, const set& bounds) { // make a list vector binos; for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) binos.push_back((*p)->dirfrag()); // note: this can get called twice if the exporter fails during recovery if (my_ambiguous_imports.count(base->dirfrag())) my_ambiguous_imports.erase(base->dirfrag()); add_ambiguous_import(base->dirfrag(), binos); } void MDCache::cancel_ambiguous_import(CDir *dir) { dirfrag_t df = dir->dirfrag(); assert(my_ambiguous_imports.count(df)); dout(10) << "cancel_ambiguous_import " << df << " bounds " << my_ambiguous_imports[df] << " " << *dir << dendl; my_ambiguous_imports.erase(df); } void MDCache::finish_ambiguous_import(dirfrag_t df) { assert(my_ambiguous_imports.count(df)); vector bounds; bounds.swap(my_ambiguous_imports[df]); my_ambiguous_imports.erase(df); dout(10) << "finish_ambiguous_import " << df << " bounds " << bounds << dendl; CDir *dir = get_dirfrag(df); assert(dir); // adjust dir_auth, import maps adjust_bounded_subtree_auth(dir, bounds, mds->get_nodeid()); try_subtree_merge(dir); } void MDCache::remove_inode_recursive(CInode *in) { dout(10) << "remove_inode_recursive " << *in << dendl; list ls; in->get_dirfrags(ls); list::iterator p = ls.begin(); while (p != ls.end()) { CDir *subdir = *p++; dout(10) << " removing dirfrag " << subdir << dendl; CDir::map_t::iterator q = subdir->items.begin(); while (q != subdir->items.end()) { CDentry *dn = q->second; ++q; CDentry::linkage_t *dnl = dn->get_linkage(); if (dnl->is_primary()) { CInode *tin = dnl->get_inode(); subdir->unlink_inode(dn); remove_inode_recursive(tin); } subdir->remove_dentry(dn); } if (subdir->is_subtree_root()) remove_subtree(subdir); in->close_dirfrag(subdir->dirfrag().frag); } remove_inode(in); } void MDCache::trim_unlinked_inodes() { dout(7) << "trim_unlinked_inodes" << dendl; list q; for (ceph::unordered_map::iterator p = inode_map.begin(); p != inode_map.end(); ++p) { CInode *in = p->second; if (in->get_parent_dn() == NULL && !in->is_base()) { dout(7) << " will trim from " << *in << dendl; q.push_back(in); } } for (list::iterator p = q.begin(); p != q.end(); ++p) remove_inode_recursive(*p); } /** recalc_auth_bits() * once subtree auth is disambiguated, we need to adjust all the * auth and dirty bits in our cache before moving on. */ void MDCache::recalc_auth_bits() { dout(7) << "recalc_auth_bits" << dendl; if (root) { root->inode_auth.first = mds->mdsmap->get_root(); if (mds->whoami != root->inode_auth.first) { root->state_clear(CInode::STATE_AUTH); root->state_set(CInode::STATE_REJOINING); } } set subtree_inodes; for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { if (p->first->dir_auth.first == mds->get_nodeid()) subtree_inodes.insert(p->first->inode); } for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CInode *inode = p->first->get_inode(); if (inode->is_mdsdir() && inode->ino() != MDS_INO_MDSDIR(mds->get_nodeid())) { inode->state_clear(CInode::STATE_AUTH); inode->state_set(CInode::STATE_REJOINING); } list dfq; // dirfrag queue dfq.push_back(p->first); bool auth = p->first->authority().first == mds->get_nodeid(); dout(10) << " subtree auth=" << auth << " for " << *p->first << dendl; while (!dfq.empty()) { CDir *dir = dfq.front(); dfq.pop_front(); // dir if (auth) { dir->state_set(CDir::STATE_AUTH); } else { // close empty non-auth dirfrag if (!dir->is_subtree_root() && dir->get_num_any() == 0) { dir->inode->close_dirfrag(dir->get_frag()); continue; } dir->state_set(CDir::STATE_REJOINING); dir->state_clear(CDir::STATE_AUTH); dir->state_clear(CDir::STATE_COMPLETE); if (dir->is_dirty()) dir->mark_clean(); } // dentries in this dir for (CDir::map_t::iterator q = dir->items.begin(); q != dir->items.end(); ++q) { // dn CDentry *dn = q->second; CDentry::linkage_t *dnl = dn->get_linkage(); if (auth) dn->state_set(CDentry::STATE_AUTH); else { dn->state_set(CDentry::STATE_REJOINING); dn->state_clear(CDentry::STATE_AUTH); if (dn->is_dirty()) dn->mark_clean(); } if (dnl->is_primary()) { // inode if (auth) dnl->get_inode()->state_set(CInode::STATE_AUTH); else { dnl->get_inode()->state_set(CInode::STATE_REJOINING); dnl->get_inode()->state_clear(CInode::STATE_AUTH); if (dnl->get_inode()->is_dirty()) dnl->get_inode()->mark_clean(); if (dnl->get_inode()->is_dirty_parent()) dnl->get_inode()->clear_dirty_parent(); // avoid touching scatterlocks for our subtree roots! if (subtree_inodes.count(dnl->get_inode()) == 0) dnl->get_inode()->clear_scatter_dirty(); } // recurse? if (dnl->get_inode()->is_dir()) dnl->get_inode()->get_nested_dirfrags(dfq); } } } } show_subtrees(); show_cache(); } // =========================================================================== // REJOIN /* * notes on scatterlock recovery: * * - recovering inode replica sends scatterlock data for any subtree * roots (the only ones that are possibly dirty). * * - surviving auth incorporates any provided scatterlock data. any * pending gathers are then finished, as with the other lock types. * * that takes care of surviving auth + (recovering replica)*. * * - surviving replica sends strong_inode, which includes current * scatterlock state, AND any dirty scatterlock data. this * provides the recovering auth with everything it might need. * * - recovering auth must pick initial scatterlock state based on * (weak|strong) rejoins. * - always assimilate scatterlock data (it can't hurt) * - any surviving replica in SCATTER state -> SCATTER. otherwise, SYNC. * - include base inode in ack for all inodes that saw scatterlock content * * also, for scatter gather, * * - auth increments {frag,r}stat.version on completion of any gather. * * - auth incorporates changes in a gather _only_ if the version * matches. * * - replica discards changes any time the scatterlock syncs, and * after recovery. */ void MDCache::rejoin_start() { dout(10) << "rejoin_start" << dendl; rejoin_gather = recovery_set; // need finish opening cap inodes before sending cache rejoins rejoin_gather.insert(mds->get_nodeid()); process_imported_caps(); } /* * rejoin phase! * * this initiates rejoin. it shoudl be called before we get any * rejoin or rejoin_ack messages (or else mdsmap distribution is broken). * * we start out by sending rejoins to everyone in the recovery set. * * if we are rejoin, send for all regions in our cache. * if we are active|stopping, send only to nodes that are are rejoining. */ void MDCache::rejoin_send_rejoins() { dout(10) << "rejoin_send_rejoins with recovery_set " << recovery_set << dendl; if (rejoin_gather.count(mds->get_nodeid())) { dout(7) << "rejoin_send_rejoins still processing imported caps, delaying" << dendl; rejoins_pending = true; return; } if (!resolve_gather.empty()) { dout(7) << "rejoin_send_rejoins still waiting for resolves (" << resolve_gather << ")" << dendl; rejoins_pending = true; return; } map rejoins; // if i am rejoining, send a rejoin to everyone. // otherwise, just send to others who are rejoining. for (set::iterator p = recovery_set.begin(); p != recovery_set.end(); ++p) { if (*p == mds->get_nodeid()) continue; // nothing to myself! if (rejoin_sent.count(*p)) continue; // already sent a rejoin to this node! if (mds->is_rejoin()) rejoins[*p] = new MMDSCacheRejoin(MMDSCacheRejoin::OP_WEAK); else if (mds->mdsmap->is_rejoin(*p)) rejoins[*p] = new MMDSCacheRejoin(MMDSCacheRejoin::OP_STRONG); } if (mds->is_rejoin()) { map > client_exports; for (map >::iterator p = cap_exports.begin(); p != cap_exports.end(); ++p) { assert(cap_export_targets.count(p->first)); int target = cap_export_targets[p->first]; if (rejoins.count(target) == 0) continue; rejoins[target]->cap_exports[p->first] = p->second; for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) client_exports[q->first].insert(target); } for (map >::iterator p = client_exports.begin(); p != client_exports.end(); ++p) { entity_inst_t inst = mds->sessionmap.get_inst(entity_name_t::CLIENT(p->first.v)); for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) rejoins[*q]->client_map[p->first] = inst; } } assert(!migrator->is_importing()); assert(!migrator->is_exporting()); // check all subtrees for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = p->first; assert(dir->is_subtree_root()); if (dir->is_ambiguous_dir_auth()) { // exporter is recovering, importer is survivor. assert(rejoins.count(dir->authority().first)); assert(!rejoins.count(dir->authority().second)); continue; } // my subtree? if (dir->is_auth()) continue; // skip my own regions! int auth = dir->get_dir_auth().first; assert(auth >= 0); if (rejoins.count(auth) == 0) continue; // don't care about this node's subtrees rejoin_walk(dir, rejoins[auth]); } // rejoin root inodes, too for (map::iterator p = rejoins.begin(); p != rejoins.end(); ++p) { if (mds->is_rejoin()) { // weak if (p->first == 0 && root) { p->second->add_weak_inode(root->vino()); if (root->is_dirty_scattered()) { dout(10) << " sending scatterlock state on root " << *root << dendl; p->second->add_scatterlock_state(root); } } if (CInode *in = get_inode(MDS_INO_MDSDIR(p->first))) { if (in) p->second->add_weak_inode(in->vino()); } } else { // strong if (p->first == 0 && root) { p->second->add_strong_inode(root->vino(), root->get_replica_nonce(), root->get_caps_wanted(), root->filelock.get_state(), root->nestlock.get_state(), root->dirfragtreelock.get_state()); root->state_set(CInode::STATE_REJOINING); if (root->is_dirty_scattered()) { dout(10) << " sending scatterlock state on root " << *root << dendl; p->second->add_scatterlock_state(root); } } if (CInode *in = get_inode(MDS_INO_MDSDIR(p->first))) { p->second->add_strong_inode(in->vino(), in->get_replica_nonce(), in->get_caps_wanted(), in->filelock.get_state(), in->nestlock.get_state(), in->dirfragtreelock.get_state()); in->state_set(CInode::STATE_REJOINING); } } } if (!mds->is_rejoin()) { // i am survivor. send strong rejoin. // note request remote_auth_pins, xlocks for (ceph::unordered_map::iterator p = active_requests.begin(); p != active_requests.end(); ++p) { MDRequestRef& mdr = p->second; if (mdr->is_slave()) continue; // auth pins for (set::iterator q = mdr->remote_auth_pins.begin(); q != mdr->remote_auth_pins.end(); ++q) { if (!(*q)->is_auth()) { int who = (*q)->authority().first; if (rejoins.count(who) == 0) continue; MMDSCacheRejoin *rejoin = rejoins[who]; dout(15) << " " << *mdr << " authpin on " << **q << dendl; MDSCacheObjectInfo i; (*q)->set_object_info(i); if (i.ino) rejoin->add_inode_authpin(vinodeno_t(i.ino, i.snapid), mdr->reqid, mdr->attempt); else rejoin->add_dentry_authpin(i.dirfrag, i.dname, i.snapid, mdr->reqid, mdr->attempt); if (mdr->has_more() && mdr->more()->is_remote_frozen_authpin && mdr->more()->rename_inode == (*q)) rejoin->add_inode_frozen_authpin(vinodeno_t(i.ino, i.snapid), mdr->reqid, mdr->attempt); } } // xlocks for (set::iterator q = mdr->xlocks.begin(); q != mdr->xlocks.end(); ++q) { if (!(*q)->get_parent()->is_auth()) { int who = (*q)->get_parent()->authority().first; if (rejoins.count(who) == 0) continue; MMDSCacheRejoin *rejoin = rejoins[who]; dout(15) << " " << *mdr << " xlock on " << **q << " " << *(*q)->get_parent() << dendl; MDSCacheObjectInfo i; (*q)->get_parent()->set_object_info(i); if (i.ino) rejoin->add_inode_xlock(vinodeno_t(i.ino, i.snapid), (*q)->get_type(), mdr->reqid, mdr->attempt); else rejoin->add_dentry_xlock(i.dirfrag, i.dname, i.snapid, mdr->reqid, mdr->attempt); } } // remote wrlocks for (map::iterator q = mdr->remote_wrlocks.begin(); q != mdr->remote_wrlocks.end(); ++q) { int who = q->second; if (rejoins.count(who) == 0) continue; MMDSCacheRejoin *rejoin = rejoins[who]; dout(15) << " " << *mdr << " wrlock on " << q->second << " " << q->first->get_parent() << dendl; MDSCacheObjectInfo i; q->first->get_parent()->set_object_info(i); assert(i.ino); rejoin->add_inode_wrlock(vinodeno_t(i.ino, i.snapid), q->first->get_type(), mdr->reqid, mdr->attempt); } } } // send the messages for (map::iterator p = rejoins.begin(); p != rejoins.end(); ++p) { assert(rejoin_sent.count(p->first) == 0); assert(rejoin_ack_gather.count(p->first) == 0); rejoin_sent.insert(p->first); rejoin_ack_gather.insert(p->first); mds->send_message_mds(p->second, p->first); } rejoin_ack_gather.insert(mds->whoami); // we need to complete rejoin_gather_finish, too rejoins_pending = false; // nothing? if (mds->is_rejoin() && rejoins.empty()) { dout(10) << "nothing to rejoin" << dendl; rejoin_gather_finish(); } } /** * rejoin_walk - build rejoin declarations for a subtree * * @param dir subtree root * @param rejoin rejoin message * * from a rejoining node: * weak dirfrag * weak dentries (w/ connectivity) * * from a surviving node: * strong dirfrag * strong dentries (no connectivity!) * strong inodes */ void MDCache::rejoin_walk(CDir *dir, MMDSCacheRejoin *rejoin) { dout(10) << "rejoin_walk " << *dir << dendl; list nested; // finish this dir, then do nested items if (mds->is_rejoin()) { // WEAK rejoin->add_weak_dirfrag(dir->dirfrag()); for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; CDentry::linkage_t *dnl = dn->get_linkage(); dout(15) << " add_weak_primary_dentry " << *dn << dendl; assert(dnl->is_primary()); CInode *in = dnl->get_inode(); assert(dnl->get_inode()->is_dir()); rejoin->add_weak_primary_dentry(dir->ino(), dn->name.c_str(), dn->first, dn->last, in->ino()); in->get_nested_dirfrags(nested); if (in->is_dirty_scattered()) { dout(10) << " sending scatterlock state on " << *in << dendl; rejoin->add_scatterlock_state(in); } } } else { // STRONG dout(15) << " add_strong_dirfrag " << *dir << dendl; rejoin->add_strong_dirfrag(dir->dirfrag(), dir->get_replica_nonce(), dir->get_dir_rep()); dir->state_set(CDir::STATE_REJOINING); for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; CDentry::linkage_t *dnl = dn->get_linkage(); dout(15) << " add_strong_dentry " << *dn << dendl; rejoin->add_strong_dentry(dir->dirfrag(), dn->name, dn->first, dn->last, dnl->is_primary() ? dnl->get_inode()->ino():inodeno_t(0), dnl->is_remote() ? dnl->get_remote_ino():inodeno_t(0), dnl->is_remote() ? dnl->get_remote_d_type():0, dn->get_replica_nonce(), dn->lock.get_state()); dn->state_set(CDentry::STATE_REJOINING); if (dnl->is_primary()) { CInode *in = dnl->get_inode(); dout(15) << " add_strong_inode " << *in << dendl; rejoin->add_strong_inode(in->vino(), in->get_replica_nonce(), in->get_caps_wanted(), in->filelock.get_state(), in->nestlock.get_state(), in->dirfragtreelock.get_state()); in->state_set(CInode::STATE_REJOINING); in->get_nested_dirfrags(nested); if (in->is_dirty_scattered()) { dout(10) << " sending scatterlock state on " << *in << dendl; rejoin->add_scatterlock_state(in); } } } } // recurse into nested dirs for (list::iterator p = nested.begin(); p != nested.end(); ++p) rejoin_walk(*p, rejoin); } /* * i got a rejoin. * - reply with the lockstate * * if i am active|stopping, * - remove source from replica list for everything not referenced here. * This function puts the passed message before returning. */ void MDCache::handle_cache_rejoin(MMDSCacheRejoin *m) { dout(7) << "handle_cache_rejoin " << *m << " from " << m->get_source() << " (" << m->get_payload().length() << " bytes)" << dendl; switch (m->op) { case MMDSCacheRejoin::OP_WEAK: handle_cache_rejoin_weak(m); break; case MMDSCacheRejoin::OP_STRONG: handle_cache_rejoin_strong(m); break; case MMDSCacheRejoin::OP_ACK: handle_cache_rejoin_ack(m); break; case MMDSCacheRejoin::OP_MISSING: handle_cache_rejoin_missing(m); break; case MMDSCacheRejoin::OP_FULL: handle_cache_rejoin_full(m); break; default: assert(0); } m->put(); } /* * handle_cache_rejoin_weak * * the sender * - is recovering from their journal. * - may have incorrect (out of date) inode contents * - will include weak dirfrag if sender is dirfrag auth and parent inode auth is recipient * * if the sender didn't trim_non_auth(), they * - may have incorrect (out of date) dentry/inode linkage * - may have deleted/purged inodes * and i may have to go to disk to get accurate inode contents. yuck. * This functions DOES NOT put the passed message before returning */ void MDCache::handle_cache_rejoin_weak(MMDSCacheRejoin *weak) { int from = weak->get_source().num(); // possible response(s) MMDSCacheRejoin *ack = 0; // if survivor set acked_inodes; // if survivor set gather_locks; // if survivor bool survivor = false; // am i a survivor? if (mds->is_clientreplay() || mds->is_active() || mds->is_stopping()) { survivor = true; dout(10) << "i am a surivivor, and will ack immediately" << dendl; ack = new MMDSCacheRejoin(MMDSCacheRejoin::OP_ACK); map > imported_caps; // check cap exports for (map >::iterator p = weak->cap_exports.begin(); p != weak->cap_exports.end(); ++p) { CInode *in = get_inode(p->first); assert(!in || in->is_auth()); for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(10) << " claiming cap import " << p->first << " client." << q->first << " on " << *in << dendl; Capability *cap = rejoin_import_cap(in, q->first, q->second, from); Capability::Import& im = imported_caps[p->first][q->first]; im.cap_id = cap->get_cap_id(); im.issue_seq = cap->get_last_seq(); im.mseq = cap->get_mseq(); } mds->locker->eval(in, CEPH_CAP_LOCKS, true); } ::encode(imported_caps, ack->imported_caps); } else { assert(mds->is_rejoin()); // we may have already received a strong rejoin from the sender. rejoin_scour_survivor_replicas(from, NULL, acked_inodes, gather_locks); assert(gather_locks.empty()); // check cap exports. rejoin_client_map.insert(weak->client_map.begin(), weak->client_map.end()); for (map >::iterator p = weak->cap_exports.begin(); p != weak->cap_exports.end(); ++p) { CInode *in = get_inode(p->first); assert(in && in->is_auth()); // note for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(10) << " claiming cap import " << p->first << " client." << q->first << dendl; cap_imports[p->first][q->first][from] = q->second; } } } // assimilate any potentially dirty scatterlock state for (map::iterator p = weak->inode_scatterlocks.begin(); p != weak->inode_scatterlocks.end(); ++p) { CInode *in = get_inode(p->first); assert(in); in->decode_lock_state(CEPH_LOCK_IFILE, p->second.file); in->decode_lock_state(CEPH_LOCK_INEST, p->second.nest); in->decode_lock_state(CEPH_LOCK_IDFT, p->second.dft); if (!survivor) rejoin_potential_updated_scatterlocks.insert(in); } // recovering peer may send incorrect dirfrags here. we need to // infer which dirfrag they meant. the ack will include a // strong_dirfrag that will set them straight on the fragmentation. // walk weak map set dirs_to_share; for (set::iterator p = weak->weak_dirfrags.begin(); p != weak->weak_dirfrags.end(); ++p) { CInode *diri = get_inode(p->ino); if (!diri) dout(0) << " missing dir ino " << p->ino << dendl; assert(diri); list ls; if (diri->dirfragtree.is_leaf(p->frag)) { ls.push_back(p->frag); } else { diri->dirfragtree.get_leaves_under(p->frag, ls); if (ls.empty()) ls.push_back(diri->dirfragtree[p->frag.value()]); } for (list::iterator q = ls.begin(); q != ls.end(); ++q) { frag_t fg = *q; CDir *dir = diri->get_dirfrag(fg); if (!dir) { dout(0) << " missing dir for " << p->frag << " (which maps to " << fg << ") on " << *diri << dendl; continue; } assert(dir); if (dirs_to_share.count(dir)) { dout(10) << " already have " << p->frag << " -> " << fg << " " << *dir << dendl; } else { dirs_to_share.insert(dir); unsigned nonce = dir->add_replica(from); dout(10) << " have " << p->frag << " -> " << fg << " " << *dir << dendl; if (ack) ack->add_strong_dirfrag(dir->dirfrag(), nonce, dir->dir_rep); } } } for (map >::iterator p = weak->weak.begin(); p != weak->weak.end(); ++p) { CInode *diri = get_inode(p->first); if (!diri) dout(0) << " missing dir ino " << p->first << dendl; assert(diri); // weak dentries CDir *dir = 0; for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { // locate proper dirfrag. // optimize for common case (one dirfrag) to avoid dirs_to_share set check frag_t fg = diri->pick_dirfrag(q->first.name); if (!dir || dir->get_frag() != fg) { dir = diri->get_dirfrag(fg); if (!dir) dout(0) << " missing dir frag " << fg << " on " << *diri << dendl; assert(dir); assert(dirs_to_share.count(dir)); } // and dentry CDentry *dn = dir->lookup(q->first.name, q->first.snapid); assert(dn); CDentry::linkage_t *dnl = dn->get_linkage(); assert(dnl->is_primary()); if (survivor && dn->is_replica(from)) dentry_remove_replica(dn, from, gather_locks); unsigned dnonce = dn->add_replica(from); dout(10) << " have " << *dn << dendl; if (ack) ack->add_strong_dentry(dir->dirfrag(), dn->name, dn->first, dn->last, dnl->get_inode()->ino(), inodeno_t(0), 0, dnonce, dn->lock.get_replica_state()); // inode CInode *in = dnl->get_inode(); assert(in); if (survivor && in->is_replica(from)) inode_remove_replica(in, from, true, gather_locks); unsigned inonce = in->add_replica(from); dout(10) << " have " << *in << dendl; // scatter the dirlock, just in case? if (!survivor && in->is_dir() && in->has_subtree_root_dirfrag()) in->filelock.set_state(LOCK_MIX); if (ack) { acked_inodes.insert(in->vino()); ack->add_inode_base(in); bufferlist bl; in->_encode_locks_state_for_rejoin(bl, from); ack->add_inode_locks(in, inonce, bl); } } } // weak base inodes? (root, stray, etc.) for (set::iterator p = weak->weak_inodes.begin(); p != weak->weak_inodes.end(); ++p) { CInode *in = get_inode(*p); assert(in); // hmm fixme wrt stray? if (survivor && in->is_replica(from)) inode_remove_replica(in, from, true, gather_locks); unsigned inonce = in->add_replica(from); dout(10) << " have base " << *in << dendl; if (ack) { acked_inodes.insert(in->vino()); ack->add_inode_base(in); bufferlist bl; in->_encode_locks_state_for_rejoin(bl, from); ack->add_inode_locks(in, inonce, bl); } } assert(rejoin_gather.count(from)); rejoin_gather.erase(from); if (survivor) { // survivor. do everything now. for (map::iterator p = weak->inode_scatterlocks.begin(); p != weak->inode_scatterlocks.end(); ++p) { CInode *in = get_inode(p->first); assert(in); dout(10) << " including base inode (due to potential scatterlock update) " << *in << dendl; acked_inodes.insert(in->vino()); ack->add_inode_base(in); } rejoin_scour_survivor_replicas(from, ack, acked_inodes, gather_locks); mds->send_message(ack, weak->get_connection()); for (set::iterator p = gather_locks.begin(); p != gather_locks.end(); ++p) { if (!(*p)->is_stable()) mds->locker->eval_gather(*p); } } else { // done? if (rejoin_gather.empty()) { rejoin_gather_finish(); } else { dout(7) << "still need rejoin from (" << rejoin_gather << ")" << dendl; } } } class C_MDC_RejoinGatherFinish : public Context { MDCache *cache; public: C_MDC_RejoinGatherFinish(MDCache *c) : cache(c) {} void finish(int r) { cache->rejoin_gather_finish(); } }; #if 0 /** * parallel_fetch -- make a pass at fetching a bunch of paths in parallel * * @param pathmap map of inodeno to full pathnames. we remove items * from this map as we discover we have them. * * returns true if there is work to do, false otherwise. */ bool MDCache::parallel_fetch(map& pathmap, set& missing) { dout(10) << "parallel_fetch on " << pathmap.size() << " paths" << dendl; C_GatherBuilder gather_bld(g_ceph_context, new C_MDC_RejoinGatherFinish(this)); // scan list set fetch_queue; map::iterator p = pathmap.begin(); while (p != pathmap.end()) { // do we have the target already? CInode *cur = get_inode(p->first); if (cur) { dout(15) << " have " << *cur << dendl; pathmap.erase(p++); continue; } // traverse dout(17) << " missing " << p->first << " at " << p->second << dendl; if (parallel_fetch_traverse_dir(p->first, p->second, fetch_queue, missing, gather_bld)) pathmap.erase(p++); else ++p; } if (pathmap.empty() && (!gather_bld.has_subs())) { dout(10) << "parallel_fetch done" << dendl; assert(fetch_queue.empty()); return false; } // do a parallel fetch for (set::iterator p = fetch_queue.begin(); p != fetch_queue.end(); ++p) { dout(10) << "parallel_fetch fetching " << **p << dendl; (*p)->fetch(gather_bld.new_sub()); } if (gather_bld.get()) { gather_bld.activate(); return true; } return false; } // true if we're done with this path bool MDCache::parallel_fetch_traverse_dir(inodeno_t ino, filepath& path, set& fetch_queue, set& missing, C_GatherBuilder &gather_bld) { CInode *cur = get_inode(path.get_ino()); if (!cur) { dout(5) << " missing " << path << " base ino " << path.get_ino() << dendl; missing.insert(ino); return true; } for (unsigned i=0; iis_dir()) { dout(5) << " bad path " << path << " ENOTDIR at " << path[i] << dendl; missing.insert(ino); return true; } frag_t fg = cur->pick_dirfrag(path[i]); CDir *dir = cur->get_or_open_dirfrag(this, fg); CDentry *dn = dir->lookup(path[i]); CDentry::linkage_t *dnl = dn ? dn->get_linkage() : NULL; if (!dnl || dnl->is_null()) { if (!dir->is_auth()) { dout(10) << " not dirfrag auth " << *dir << dendl; return true; } if (dnl || dir->is_complete()) { // probably because the client created it and held a cap but it never committed // to the journal, and the op hasn't replayed yet. dout(5) << " dne (not created yet?) " << ino << " at " << path << dendl; missing.insert(ino); return true; } // fetch dir fetch_queue.insert(dir); return false; } cur = dnl->get_inode(); if (!cur) { assert(dnl->is_remote()); cur = get_inode(dnl->get_remote_ino()); if (cur) { dn->link_remote(dnl, cur); } else { // open remote ino open_remote_ino(dnl->get_remote_ino(), gather_bld.new_sub()); return false; } } } dout(5) << " ino not found " << ino << " at " << path << dendl; missing.insert(ino); return true; } #endif /* * rejoin_scour_survivor_replica - remove source from replica list on unmentioned objects * * all validated replicas are acked with a strong nonce, etc. if that isn't in the * ack, the replica dne, and we can remove it from our replica maps. */ void MDCache::rejoin_scour_survivor_replicas(int from, MMDSCacheRejoin *ack, set& acked_inodes, set& gather_locks) { dout(10) << "rejoin_scour_survivor_replicas from mds." << from << dendl; for (ceph::unordered_map::iterator p = inode_map.begin(); p != inode_map.end(); ++p) { CInode *in = p->second; // inode? if (in->is_auth() && in->is_replica(from) && (ack == NULL || acked_inodes.count(p->second->vino()) == 0)) { inode_remove_replica(in, from, false, gather_locks); dout(10) << " rem " << *in << dendl; } if (!in->is_dir()) continue; list dfs; in->get_dirfrags(dfs); for (list::iterator p = dfs.begin(); p != dfs.end(); ++p) { CDir *dir = *p; if (dir->is_auth() && dir->is_replica(from) && (ack == NULL || ack->strong_dirfrags.count(dir->dirfrag()) == 0)) { dir->remove_replica(from); dout(10) << " rem " << *dir << dendl; } // dentries for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; if (dn->is_replica(from) && (ack == NULL || ack->strong_dentries.count(dir->dirfrag()) == 0 || ack->strong_dentries[dir->dirfrag()].count(string_snap_t(dn->name, dn->last)) == 0)) { dentry_remove_replica(dn, from, gather_locks); dout(10) << " rem " << *dn << dendl; } } } } } CInode *MDCache::rejoin_invent_inode(inodeno_t ino, snapid_t last) { CInode *in = new CInode(this, true, 1, last); in->inode.ino = ino; in->state_set(CInode::STATE_REJOINUNDEF); add_inode(in); rejoin_undef_inodes.insert(in); dout(10) << " invented " << *in << dendl; return in; } CDir *MDCache::rejoin_invent_dirfrag(dirfrag_t df) { CInode *in = get_inode(df.ino); if (!in) in = rejoin_invent_inode(df.ino, CEPH_NOSNAP); if (!in->is_dir()) { assert(in->state_test(CInode::STATE_REJOINUNDEF)); in->inode.mode = S_IFDIR; } CDir *dir = in->get_or_open_dirfrag(this, df.frag); dir->state_set(CDir::STATE_REJOINUNDEF); rejoin_undef_dirfrags.insert(dir); dout(10) << " invented " << *dir << dendl; return dir; } /* This functions DOES NOT put the passed message before returning */ void MDCache::handle_cache_rejoin_strong(MMDSCacheRejoin *strong) { int from = strong->get_source().num(); // only a recovering node will get a strong rejoin. assert(mds->is_rejoin()); // assimilate any potentially dirty scatterlock state for (map::iterator p = strong->inode_scatterlocks.begin(); p != strong->inode_scatterlocks.end(); ++p) { CInode *in = get_inode(p->first); assert(in); in->decode_lock_state(CEPH_LOCK_IFILE, p->second.file); in->decode_lock_state(CEPH_LOCK_INEST, p->second.nest); in->decode_lock_state(CEPH_LOCK_IDFT, p->second.dft); rejoin_potential_updated_scatterlocks.insert(in); } rejoin_unlinked_inodes[from].clear(); // surviving peer may send incorrect dirfrag here (maybe they didn't // get the fragment notify, or maybe we rolled back?). we need to // infer the right frag and get them with the program. somehow. // we don't normally send ACK.. so we'll need to bundle this with // MISSING or something. // strong dirfrags/dentries. // also process auth_pins, xlocks. for (map::iterator p = strong->strong_dirfrags.begin(); p != strong->strong_dirfrags.end(); ++p) { CInode *diri = get_inode(p->first.ino); if (!diri) diri = rejoin_invent_inode(p->first.ino, CEPH_NOSNAP); CDir *dir = diri->get_dirfrag(p->first.frag); bool refragged = false; if (dir) { dout(10) << " have " << *dir << dendl; } else { if (diri->state_test(CInode::STATE_REJOINUNDEF)) dir = rejoin_invent_dirfrag(dirfrag_t(diri->ino(), frag_t())); else if (diri->dirfragtree.is_leaf(p->first.frag)) dir = rejoin_invent_dirfrag(p->first); } if (dir) { dir->add_replica(from, p->second.nonce); dir->dir_rep = p->second.dir_rep; } else { dout(10) << " frag " << p->first << " doesn't match dirfragtree " << *diri << dendl; list ls; diri->dirfragtree.get_leaves_under(p->first.frag, ls); if (ls.empty()) ls.push_back(diri->dirfragtree[p->first.frag.value()]); dout(10) << " maps to frag(s) " << ls << dendl; for (list::iterator q = ls.begin(); q != ls.end(); ++q) { CDir *dir = diri->get_dirfrag(*q); if (!dir) dir = rejoin_invent_dirfrag(dirfrag_t(diri->ino(), *q)); else dout(10) << " have(approx) " << *dir << dendl; dir->add_replica(from, p->second.nonce); dir->dir_rep = p->second.dir_rep; } refragged = true; } map& dmap = strong->strong_dentries[p->first]; for (map::iterator q = dmap.begin(); q != dmap.end(); ++q) { CDentry *dn; if (!refragged) dn = dir->lookup(q->first.name, q->first.snapid); else { frag_t fg = diri->pick_dirfrag(q->first.name); dir = diri->get_dirfrag(fg); assert(dir); dn = dir->lookup(q->first.name, q->first.snapid); } if (!dn) { if (q->second.is_remote()) { dn = dir->add_remote_dentry(q->first.name, q->second.remote_ino, q->second.remote_d_type, q->second.first, q->first.snapid); } else if (q->second.is_null()) { dn = dir->add_null_dentry(q->first.name, q->second.first, q->first.snapid); } else { CInode *in = get_inode(q->second.ino, q->first.snapid); if (!in) in = rejoin_invent_inode(q->second.ino, q->first.snapid); dn = dir->add_primary_dentry(q->first.name, in, q->second.first, q->first.snapid); } dout(10) << " invented " << *dn << dendl; } CDentry::linkage_t *dnl = dn->get_linkage(); // dn auth_pin? if (strong->authpinned_dentries.count(p->first) && strong->authpinned_dentries[p->first].count(q->first)) { for (list::iterator r = strong->authpinned_dentries[p->first][q->first].begin(); r != strong->authpinned_dentries[p->first][q->first].end(); ++r) { dout(10) << " dn authpin by " << *r << " on " << *dn << dendl; // get/create slave mdrequest MDRequestRef mdr; if (have_request(r->reqid)) mdr = request_get(r->reqid); else mdr = request_start_slave(r->reqid, r->attempt, from); mdr->auth_pin(dn); } } // dn xlock? if (strong->xlocked_dentries.count(p->first) && strong->xlocked_dentries[p->first].count(q->first)) { MMDSCacheRejoin::slave_reqid r = strong->xlocked_dentries[p->first][q->first]; dout(10) << " dn xlock by " << r << " on " << *dn << dendl; MDRequestRef mdr = request_get(r.reqid); // should have this from auth_pin above. assert(mdr->is_auth_pinned(dn)); if (!mdr->xlocks.count(&dn->versionlock)) { assert(dn->versionlock.can_xlock_local()); dn->versionlock.get_xlock(mdr, mdr->get_client()); mdr->xlocks.insert(&dn->versionlock); mdr->locks.insert(&dn->versionlock); } if (dn->lock.is_stable()) dn->auth_pin(&dn->lock); dn->lock.set_state(LOCK_XLOCK); dn->lock.get_xlock(mdr, mdr->get_client()); mdr->xlocks.insert(&dn->lock); mdr->locks.insert(&dn->lock); } dn->add_replica(from, q->second.nonce); dout(10) << " have " << *dn << dendl; if (dnl->is_primary()) { if (q->second.is_primary()) { if (vinodeno_t(q->second.ino, q->first.snapid) != dnl->get_inode()->vino()) { // the survivor missed MDentryUnlink+MDentryLink messages ? assert(strong->strong_inodes.count(dnl->get_inode()->vino()) == 0); CInode *in = get_inode(q->second.ino, q->first.snapid); assert(in); assert(in->get_parent_dn()); rejoin_unlinked_inodes[from].insert(in); dout(7) << " sender has primary dentry but wrong inode" << dendl; } } else { // the survivor missed MDentryLink message ? assert(strong->strong_inodes.count(dnl->get_inode()->vino()) == 0); dout(7) << " sender doesn't have primay dentry" << dendl; } } else { if (q->second.is_primary()) { // the survivor missed MDentryUnlink message ? CInode *in = get_inode(q->second.ino, q->first.snapid); assert(in); assert(in->get_parent_dn()); rejoin_unlinked_inodes[from].insert(in); dout(7) << " sender has primary dentry but we don't" << dendl; } } } } for (map::iterator p = strong->strong_inodes.begin(); p != strong->strong_inodes.end(); ++p) { CInode *in = get_inode(p->first); assert(in); in->add_replica(from, p->second.nonce); dout(10) << " have " << *in << dendl; MMDSCacheRejoin::inode_strong &is = p->second; // caps_wanted if (is.caps_wanted) { in->mds_caps_wanted[from] = is.caps_wanted; dout(15) << " inode caps_wanted " << ccap_string(is.caps_wanted) << " on " << *in << dendl; } // scatterlocks? // infer state from replica state: // * go to MIX if they might have wrlocks // * go to LOCK if they are LOCK (just bc identify_files_to_recover might start twiddling filelock) in->filelock.infer_state_from_strong_rejoin(is.filelock, true); // maybe also go to LOCK in->nestlock.infer_state_from_strong_rejoin(is.nestlock, false); in->dirfragtreelock.infer_state_from_strong_rejoin(is.dftlock, false); // auth pin? if (strong->authpinned_inodes.count(in->vino())) { for (list::iterator r = strong->authpinned_inodes[in->vino()].begin(); r != strong->authpinned_inodes[in->vino()].end(); ++r) { dout(10) << " inode authpin by " << *r << " on " << *in << dendl; // get/create slave mdrequest MDRequestRef mdr; if (have_request(r->reqid)) mdr = request_get(r->reqid); else mdr = request_start_slave(r->reqid, r->attempt, from); if (strong->frozen_authpin_inodes.count(in->vino())) { assert(!in->get_num_auth_pins()); mdr->freeze_auth_pin(in); } else { assert(!in->is_frozen_auth_pin()); } mdr->auth_pin(in); } } // xlock(s)? if (strong->xlocked_inodes.count(in->vino())) { for (map::iterator q = strong->xlocked_inodes[in->vino()].begin(); q != strong->xlocked_inodes[in->vino()].end(); ++q) { SimpleLock *lock = in->get_lock(q->first); dout(10) << " inode xlock by " << q->second << " on " << *lock << " on " << *in << dendl; MDRequestRef mdr = request_get(q->second.reqid); // should have this from auth_pin above. assert(mdr->is_auth_pinned(in)); if (!mdr->xlocks.count(&in->versionlock)) { assert(in->versionlock.can_xlock_local()); in->versionlock.get_xlock(mdr, mdr->get_client()); mdr->xlocks.insert(&in->versionlock); mdr->locks.insert(&in->versionlock); } if (lock->is_stable()) in->auth_pin(lock); lock->set_state(LOCK_XLOCK); if (lock == &in->filelock) in->loner_cap = -1; lock->get_xlock(mdr, mdr->get_client()); mdr->xlocks.insert(lock); mdr->locks.insert(lock); } } } // wrlock(s)? for (map > >::iterator p = strong->wrlocked_inodes.begin(); p != strong->wrlocked_inodes.end(); ++p) { CInode *in = get_inode(p->first); for (map >::iterator q = p->second.begin(); q != p->second.end(); ++q) { SimpleLock *lock = in->get_lock(q->first); for (list::iterator r = q->second.begin(); r != q->second.end(); ++r) { dout(10) << " inode wrlock by " << *r << " on " << *lock << " on " << *in << dendl; MDRequestRef mdr = request_get(r->reqid); // should have this from auth_pin above. if (in->is_auth()) assert(mdr->is_auth_pinned(in)); lock->set_state(LOCK_MIX); if (lock == &in->filelock) in->loner_cap = -1; lock->get_wrlock(true); mdr->wrlocks.insert(lock); mdr->locks.insert(lock); } } } // done? assert(rejoin_gather.count(from)); rejoin_gather.erase(from); if (rejoin_gather.empty()) { rejoin_gather_finish(); } else { dout(7) << "still need rejoin from (" << rejoin_gather << ")" << dendl; } } /* This functions DOES NOT put the passed message before returning */ void MDCache::handle_cache_rejoin_ack(MMDSCacheRejoin *ack) { dout(7) << "handle_cache_rejoin_ack from " << ack->get_source() << dendl; int from = ack->get_source().num(); // for sending cache expire message set isolated_inodes; set refragged_inodes; // dirs for (map::iterator p = ack->strong_dirfrags.begin(); p != ack->strong_dirfrags.end(); ++p) { // we may have had incorrect dir fragmentation; refragment based // on what they auth tells us. CInode *diri = get_inode(p->first.ino); CDir *dir = NULL; if (diri) { dir = diri->get_dirfrag(p->first.frag); if (!dir) { dir = force_dir_fragment(diri, p->first.frag, false); if (dir) refragged_inodes.insert(dir->get_inode()); } } if (!dir) { if (!diri) { // barebones inode; the full inode loop below will clean up. diri = new CInode(this, false); diri->inode.ino = p->first.ino; diri->inode.mode = S_IFDIR; add_inode(diri); if (MDS_INO_MDSDIR(from) == p->first.ino) { diri->inode_auth = pair(from, CDIR_AUTH_UNKNOWN); dout(10) << " add inode " << *diri << dendl; } else { diri->inode_auth = CDIR_AUTH_DEFAULT; isolated_inodes.insert(diri); dout(10) << " unconnected dirfrag " << p->first << dendl; } } // barebones dirfrag; the full dirfrag loop below will clean up. dir = diri->add_dirfrag(new CDir(diri, p->first.frag, this, false)); if (MDS_INO_MDSDIR(from) == p->first.ino || (dir->authority() != CDIR_AUTH_UNDEF && dir->authority().first != from)) adjust_subtree_auth(dir, from); dout(10) << " add dirfrag " << *dir << dendl; } dir->set_replica_nonce(p->second.nonce); dir->state_clear(CDir::STATE_REJOINING); dout(10) << " got " << *dir << dendl; // dentries map& dmap = ack->strong_dentries[p->first]; for (map::iterator q = dmap.begin(); q != dmap.end(); ++q) { CDentry *dn = dir->lookup(q->first.name, q->first.snapid); if(!dn) dn = dir->add_null_dentry(q->first.name, q->second.first, q->first.snapid); CDentry::linkage_t *dnl = dn->get_linkage(); assert(dn->last == q->first.snapid); if (dn->first != q->second.first) { dout(10) << " adjust dn.first " << dn->first << " -> " << q->second.first << " on " << *dn << dendl; dn->first = q->second.first; } // may have bad linkage if we missed dentry link/unlink messages if (dnl->is_primary()) { CInode *in = dnl->get_inode(); if (!q->second.is_primary() || vinodeno_t(q->second.ino, q->first.snapid) != in->vino()) { dout(10) << " had bad linkage for " << *dn << ", unlinking " << *in << dendl; dir->unlink_inode(dn); } } else if (dnl->is_remote()) { if (!q->second.is_remote() || q->second.remote_ino != dnl->get_remote_ino() || q->second.remote_d_type != dnl->get_remote_d_type()) { dout(10) << " had bad linkage for " << *dn << dendl; dir->unlink_inode(dn); } } else { if (!q->second.is_null()) dout(10) << " had bad linkage for " << *dn << dendl; } // hmm, did we have the proper linkage here? if (dnl->is_null() && !q->second.is_null()) { if (q->second.is_remote()) { dn->dir->link_remote_inode(dn, q->second.remote_ino, q->second.remote_d_type); } else { CInode *in = get_inode(q->second.ino, q->first.snapid); if (!in) { // barebones inode; assume it's dir, the full inode loop below will clean up. in = new CInode(this, false, q->second.first, q->first.snapid); in->inode.ino = q->second.ino; in->inode.mode = S_IFDIR; add_inode(in); dout(10) << " add inode " << *in << dendl; } else if (in->get_parent_dn()) { dout(10) << " had bad linkage for " << *(in->get_parent_dn()) << ", unlinking " << *in << dendl; in->get_parent_dir()->unlink_inode(in->get_parent_dn()); } dn->dir->link_primary_inode(dn, in); isolated_inodes.erase(in); } } dn->set_replica_nonce(q->second.nonce); dn->lock.set_state_rejoin(q->second.lock, rejoin_waiters); dn->state_clear(CDentry::STATE_REJOINING); dout(10) << " got " << *dn << dendl; } } for (set::iterator p = refragged_inodes.begin(); p != refragged_inodes.end(); ++p) { list ls; (*p)->get_nested_dirfrags(ls); for (list::iterator q = ls.begin(); q != ls.end(); ++q) { if ((*q)->is_auth() || ack->strong_dirfrags.count((*q)->dirfrag())) continue; assert((*q)->get_num_any() == 0); (*p)->close_dirfrag((*q)->get_frag()); } } // full dirfrags for (map::iterator p = ack->dirfrag_bases.begin(); p != ack->dirfrag_bases.end(); ++p) { CDir *dir = get_dirfrag(p->first); assert(dir); bufferlist::iterator q = p->second.begin(); dir->_decode_base(q); dout(10) << " got dir replica " << *dir << dendl; } // full inodes bufferlist::iterator p = ack->inode_base.begin(); while (!p.end()) { inodeno_t ino; snapid_t last; bufferlist basebl; ::decode(ino, p); ::decode(last, p); ::decode(basebl, p); CInode *in = get_inode(ino, last); assert(in); bufferlist::iterator q = basebl.begin(); in->_decode_base(q); dout(10) << " got inode base " << *in << dendl; } // inodes p = ack->inode_locks.begin(); //dout(10) << "inode_locks len " << ack->inode_locks.length() << " is " << ack->inode_locks << dendl; while (!p.end()) { inodeno_t ino; snapid_t last; __u32 nonce; bufferlist lockbl; ::decode(ino, p); ::decode(last, p); ::decode(nonce, p); ::decode(lockbl, p); CInode *in = get_inode(ino, last); assert(in); in->set_replica_nonce(nonce); bufferlist::iterator q = lockbl.begin(); in->_decode_locks_rejoin(q, rejoin_waiters, rejoin_eval_locks); in->state_clear(CInode::STATE_REJOINING); dout(10) << " got inode locks " << *in << dendl; } // FIXME: This can happen if entire subtree, together with the inode subtree root // belongs to, were trimmed between sending cache rejoin and receiving rejoin ack. assert(isolated_inodes.empty()); map > peer_imported; bufferlist::iterator bp = ack->imported_caps.begin(); ::decode(peer_imported, bp); for (map >::iterator p = peer_imported.begin(); p != peer_imported.end(); ++p) { assert(cap_exports.count(p->first)); assert(cap_export_targets.count(p->first)); assert(cap_export_targets[p->first] == from); for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { assert(cap_exports[p->first].count(q->first)); dout(10) << " exporting caps for client." << q->first << " ino " << p->first << dendl; Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(q->first.v)); assert(session); // mark client caps stale. MClientCaps *m = new MClientCaps(CEPH_CAP_OP_EXPORT, p->first, 0, cap_exports[p->first][q->first].cap_id, 0); m->set_cap_peer(q->second.cap_id, q->second.issue_seq, q->second.mseq, from, 0); mds->send_message_client_counted(m, session); cap_exports[p->first].erase(q->first); } assert(cap_exports[p->first].empty()); } // done? assert(rejoin_ack_gather.count(from)); rejoin_ack_gather.erase(from); if (mds->is_rejoin()) { if (rejoin_gather.empty()) { // eval unstable scatter locks after all wrlocks are rejoined. while (!rejoin_eval_locks.empty()) { SimpleLock *lock = rejoin_eval_locks.front(); rejoin_eval_locks.pop_front(); if (!lock->is_stable()) mds->locker->eval_gather(lock); } } if (rejoin_gather.empty() && // make sure we've gotten our FULL inodes, too. rejoin_ack_gather.empty()) { // finally, kickstart past snap parent opens open_snap_parents(); } else { dout(7) << "still need rejoin from (" << rejoin_gather << ")" << ", rejoin_ack from (" << rejoin_ack_gather << ")" << dendl; } } else { // survivor. mds->queue_waiters(rejoin_waiters); } } /* This functions DOES NOT put the passed message before returning */ void MDCache::handle_cache_rejoin_missing(MMDSCacheRejoin *missing) { dout(7) << "handle_cache_rejoin_missing from " << missing->get_source() << dendl; MMDSCacheRejoin *full = new MMDSCacheRejoin(MMDSCacheRejoin::OP_FULL); // dirs for (map::iterator p = missing->strong_dirfrags.begin(); p != missing->strong_dirfrags.end(); ++p) { // we may have had incorrect dir fragmentation; refragment based // on what they auth tells us. CDir *dir = get_force_dirfrag(p->first); assert(dir); dir->set_replica_nonce(p->second.nonce); dir->state_clear(CDir::STATE_REJOINING); dout(10) << " adjusted frag on " << *dir << dendl; } // inodes for (set::iterator p = missing->weak_inodes.begin(); p != missing->weak_inodes.end(); ++p) { CInode *in = get_inode(*p); if (!in) { dout(10) << " don't have inode " << *p << dendl; continue; // we must have trimmed it after the originalo rejoin } dout(10) << " sending " << *in << dendl; full->add_inode_base(in); } mds->send_message(full, missing->get_connection()); } /* This function DOES NOT put the passed message before returning */ void MDCache::handle_cache_rejoin_full(MMDSCacheRejoin *full) { dout(7) << "handle_cache_rejoin_full from " << full->get_source() << dendl; int from = full->get_source().num(); // integrate full inodes bufferlist::iterator p = full->inode_base.begin(); while (!p.end()) { inodeno_t ino; snapid_t last; bufferlist basebl; ::decode(ino, p); ::decode(last, p); ::decode(basebl, p); CInode *in = get_inode(ino); assert(in); bufferlist::iterator pp = basebl.begin(); in->_decode_base(pp); set::iterator q = rejoin_undef_inodes.find(in); if (q != rejoin_undef_inodes.end()) { CInode *in = *q; in->state_clear(CInode::STATE_REJOINUNDEF); dout(10) << " got full " << *in << dendl; rejoin_undef_inodes.erase(q); } else { dout(10) << " had full " << *in << dendl; } } // done? assert(rejoin_gather.count(from)); rejoin_gather.erase(from); if (rejoin_gather.empty()) { rejoin_gather_finish(); } else { dout(7) << "still need rejoin from (" << rejoin_gather << ")" << dendl; } } /** * rejoin_trim_undef_inodes() -- remove REJOINUNDEF flagged inodes * * FIXME: wait, can this actually happen? a survivor should generate cache trim * messages that clean these guys up... */ void MDCache::rejoin_trim_undef_inodes() { dout(10) << "rejoin_trim_undef_inodes" << dendl; while (!rejoin_undef_inodes.empty()) { set::iterator p = rejoin_undef_inodes.begin(); CInode *in = *p; rejoin_undef_inodes.erase(p); in->clear_replica_map(); // close out dirfrags if (in->is_dir()) { list dfls; in->get_dirfrags(dfls); for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) { CDir *dir = *p; dir->clear_replica_map(); for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; dn->clear_replica_map(); dout(10) << " trimming " << *dn << dendl; dir->remove_dentry(dn); } dout(10) << " trimming " << *dir << dendl; in->close_dirfrag(dir->dirfrag().frag); } } CDentry *dn = in->get_parent_dn(); if (dn) { dn->clear_replica_map(); dout(10) << " trimming " << *dn << dendl; dn->dir->remove_dentry(dn); } else { dout(10) << " trimming " << *in << dendl; remove_inode(in); } } assert(rejoin_undef_inodes.empty()); } void MDCache::rejoin_gather_finish() { dout(10) << "rejoin_gather_finish" << dendl; assert(mds->is_rejoin()); if (open_undef_inodes_dirfrags()) return; if (process_imported_caps()) return; choose_lock_states_and_reconnect_caps(); identify_files_to_recover(rejoin_recover_q, rejoin_check_q); rejoin_send_acks(); // signal completion of fetches, rejoin_gather_finish, etc. assert(rejoin_ack_gather.count(mds->whoami)); rejoin_ack_gather.erase(mds->whoami); // did we already get our acks too? // this happens when the rejoin_gather has to wait on a MISSING/FULL exchange. if (rejoin_ack_gather.empty()) { // finally, kickstart past snap parent opens open_snap_parents(); } } class C_MDC_RejoinOpenInoFinish: public Context { MDCache *cache; inodeno_t ino; public: C_MDC_RejoinOpenInoFinish(MDCache *c, inodeno_t i) : cache(c), ino(i) {} void finish(int r) { cache->rejoin_open_ino_finish(ino, r); } }; void MDCache::rejoin_open_ino_finish(inodeno_t ino, int ret) { dout(10) << "open_caps_inode_finish ino " << ino << " ret " << ret << dendl; if (ret < 0) { cap_imports_missing.insert(ino); } else if (ret == mds->get_nodeid()) { assert(get_inode(ino)); } else { map > >::iterator p; p = cap_imports.find(ino); assert(p != cap_imports.end()); for (map >::iterator q = p->second.begin(); q != p->second.end(); ++q) { assert(q->second.count(-1)); assert(q->second.size() == 1); rejoin_export_caps(p->first, q->first, q->second[-1], ret); } cap_imports.erase(p); } assert(cap_imports_num_opening > 0); cap_imports_num_opening--; if (cap_imports_num_opening == 0) { if (rejoin_gather.empty()) rejoin_gather_finish(); else if (rejoin_gather.count(mds->get_nodeid())) process_imported_caps(); } } class C_MDC_RejoinSessionsOpened : public Context { MDCache *cache; public: map client_map; map sseqmap; C_MDC_RejoinSessionsOpened(MDCache *c, map& cm) : cache(c), client_map(cm) {} void finish(int r) { assert(r == 0); cache->rejoin_open_sessions_finish(client_map, sseqmap); } }; void MDCache::rejoin_open_sessions_finish(map client_map, map& sseqmap) { dout(10) << "rejoin_open_sessions_finish" << dendl; mds->server->finish_force_open_sessions(client_map, sseqmap); if (rejoin_gather.empty()) rejoin_gather_finish(); } bool MDCache::process_imported_caps() { dout(10) << "process_imported_caps" << dendl; for (map > >::iterator p = cap_imports.begin(); p != cap_imports.end(); ++p) { CInode *in = get_inode(p->first); if (in) { assert(in->is_auth()); cap_imports_missing.erase(p->first); continue; } if (cap_imports_missing.count(p->first) > 0) continue; cap_imports_num_opening++; dout(10) << " opening missing ino " << p->first << dendl; open_ino(p->first, (int64_t)-1, new C_MDC_RejoinOpenInoFinish(this, p->first), false); } if (cap_imports_num_opening > 0) return true; // called by rejoin_gather_finish() ? if (rejoin_gather.count(mds->get_nodeid()) == 0) { // if sessions for imported caps are all open ? for (map::iterator p = rejoin_client_map.begin(); p != rejoin_client_map.end(); ++p) { if (!mds->sessionmap.have_session(entity_name_t::CLIENT(p->first.v))) { C_MDC_RejoinSessionsOpened *finish = new C_MDC_RejoinSessionsOpened(this, rejoin_client_map); version_t pv = mds->server->prepare_force_open_sessions(rejoin_client_map, finish->sseqmap); ESessions *le = new ESessions(pv, rejoin_client_map); mds->mdlog->start_submit_entry(le, finish); mds->mdlog->flush(); rejoin_client_map.clear(); return true; } } rejoin_client_map.clear(); // process caps that were exported by slave rename for (map > >::iterator p = rejoin_slave_exports.begin(); p != rejoin_slave_exports.end(); ++p) { CInode *in = get_inode(p->first); assert(in); for (map::iterator q = p->second.second.begin(); q != p->second.second.end(); ++q) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(q->first.v)); assert(session); Capability *cap = in->get_client_cap(q->first); if (!cap) cap = in->add_client_cap(q->first, session); cap->merge(q->second, true); Capability::Import& im = rejoin_imported_caps[p->second.first][p->first][q->first]; assert(cap->get_last_seq() == im.issue_seq); assert(cap->get_mseq() == im.mseq); cap->set_cap_id(im.cap_id); // send cap import because we assigned a new cap ID do_cap_import(session, in, cap, q->second.cap_id, q->second.seq, q->second.mseq - 1, p->second.first, CEPH_CAP_FLAG_AUTH); } } rejoin_slave_exports.clear(); rejoin_imported_caps.clear(); // process cap imports // ino -> client -> frommds -> capex for (map > >::iterator p = cap_imports.begin(); p != cap_imports.end(); ) { CInode *in = get_inode(p->first); if (!in) { dout(10) << " still missing ino " << p->first << ", will try again after replayed client requests" << dendl; ++p; continue; } assert(in->is_auth()); for (map >::iterator q = p->second.begin(); q != p->second.end(); ++q) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(q->first.v)); assert(session); for (map::iterator r = q->second.begin(); r != q->second.end(); ++r) { add_reconnected_cap(in, q->first, inodeno_t(r->second.snaprealm)); Capability *cap = in->reconnect_cap(q->first, r->second, session); if (r->first >= 0) { if (cap->get_last_seq() == 0) // don't increase mseq if cap already exists cap->inc_mseq(); do_cap_import(session, in, cap, r->second.cap_id, 0, 0, r->first, 0); Capability::Import& im = rejoin_imported_caps[r->first][p->first][q->first]; im.cap_id = cap->get_cap_id(); im.issue_seq = cap->get_last_seq(); im.mseq = cap->get_mseq(); } } } cap_imports.erase(p++); // remove and move on } } else { trim_non_auth(); rejoin_gather.erase(mds->get_nodeid()); maybe_send_pending_rejoins(); if (rejoin_gather.empty() && rejoin_ack_gather.count(mds->get_nodeid())) rejoin_gather_finish(); } return false; } void MDCache::check_realm_past_parents(SnapRealm *realm) { // are this realm's parents fully open? if (realm->have_past_parents_open()) { dout(10) << " have past snap parents for realm " << *realm << " on " << *realm->inode << dendl; } else { if (!missing_snap_parents.count(realm->inode)) { dout(10) << " MISSING past snap parents for realm " << *realm << " on " << *realm->inode << dendl; realm->inode->get(CInode::PIN_OPENINGSNAPPARENTS); missing_snap_parents[realm->inode].size(); // just to get it into the map! } else { dout(10) << " (already) MISSING past snap parents for realm " << *realm << " on " << *realm->inode << dendl; } } } /* * choose lock states based on reconnected caps */ void MDCache::choose_lock_states_and_reconnect_caps() { dout(10) << "choose_lock_states_and_reconnect_caps" << dendl; map splits; for (ceph::unordered_map::iterator i = inode_map.begin(); i != inode_map.end(); ++i) { CInode *in = i->second; if (in->is_auth() && !in->is_base() && in->inode.is_dirty_rstat()) in->mark_dirty_rstat(); in->choose_lock_states(); dout(15) << " chose lock states on " << *in << dendl; SnapRealm *realm = in->find_snaprealm(); check_realm_past_parents(realm); map >::iterator p = reconnected_caps.find(in); if (p != reconnected_caps.end()) { // also, make sure client's cap is in the correct snaprealm. for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { if (q->second == realm->inode->ino()) { dout(15) << " client." << q->first << " has correct realm " << q->second << dendl; } else { dout(15) << " client." << q->first << " has wrong realm " << q->second << " != " << realm->inode->ino() << dendl; if (realm->have_past_parents_open()) { // ok, include in a split message _now_. prepare_realm_split(realm, q->first, in->ino(), splits); } else { // send the split later. missing_snap_parents[realm->inode][q->first].insert(in->ino()); } } } } } reconnected_caps.clear(); send_snaps(splits); } void MDCache::prepare_realm_split(SnapRealm *realm, client_t client, inodeno_t ino, map& splits) { MClientSnap *snap; if (splits.count(client) == 0) { splits[client] = snap = new MClientSnap(CEPH_SNAP_OP_SPLIT); snap->head.split = realm->inode->ino(); realm->build_snap_trace(snap->bl); for (set::iterator p = realm->open_children.begin(); p != realm->open_children.end(); ++p) snap->split_realms.push_back((*p)->inode->ino()); } else snap = splits[client]; snap->split_inos.push_back(ino); } void MDCache::send_snaps(map& splits) { dout(10) << "send_snaps" << dendl; for (map::iterator p = splits.begin(); p != splits.end(); ++p) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(p->first.v)); if (session) { dout(10) << " client." << p->first << " split " << p->second->head.split << " inos " << p->second->split_inos << dendl; mds->send_message_client_counted(p->second, session); } else { dout(10) << " no session for client." << p->first << dendl; p->second->put(); } } splits.clear(); } /* * remove any items from logsegment open_file lists that don't have * any caps */ void MDCache::clean_open_file_lists() { dout(10) << "clean_open_file_lists" << dendl; for (map::iterator p = mds->mdlog->segments.begin(); p != mds->mdlog->segments.end(); ++p) { LogSegment *ls = p->second; elist::iterator q = ls->open_files.begin(member_offset(CInode, item_open_file)); while (!q.end()) { CInode *in = *q; ++q; if (!in->is_any_caps_wanted()) { dout(10) << " unlisting unwanted/capless inode " << *in << dendl; in->item_open_file.remove_myself(); } } } } Capability* MDCache::rejoin_import_cap(CInode *in, client_t client, ceph_mds_cap_reconnect& icr, int frommds) { dout(10) << "rejoin_import_cap for client." << client << " from mds." << frommds << " on " << *in << dendl; Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(client.v)); assert(session); Capability *cap = in->reconnect_cap(client, icr, session); if (frommds >= 0) { if (cap->get_last_seq() == 0) // don't increase mseq if cap already exists cap->inc_mseq(); do_cap_import(session, in, cap, icr.cap_id, 0, 0, frommds, 0); } return cap; } void MDCache::export_remaining_imported_caps() { dout(10) << "export_remaining_imported_caps" << dendl; stringstream warn_str; for (map > >::iterator p = cap_imports.begin(); p != cap_imports.end(); ++p) { warn_str << " ino " << p->first << "\n"; for (map >::iterator q = p->second.begin(); q != p->second.end(); ++q) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(q->first.v)); if (session) { // mark client caps stale. MClientCaps *stale = new MClientCaps(CEPH_CAP_OP_EXPORT, p->first, 0, 0, 0); stale->set_cap_peer(0, 0, 0, -1, 0); mds->send_message_client_counted(stale, q->first); } } } cap_imports.clear(); if (warn_str.peek() != EOF) { mds->clog.warn() << "failed to reconnect caps for missing inodes:" << "\n"; mds->clog.warn(warn_str); } } void MDCache::try_reconnect_cap(CInode *in, Session *session) { client_t client = session->info.get_client(); ceph_mds_cap_reconnect *rc = get_replay_cap_reconnect(in->ino(), client); if (rc) { in->reconnect_cap(client, *rc, session); dout(10) << "try_reconnect_cap client." << client << " reconnect wanted " << ccap_string(rc->wanted) << " issue " << ccap_string(rc->issued) << " on " << *in << dendl; remove_replay_cap_reconnect(in->ino(), client); if (in->is_replicated()) { mds->locker->try_eval(in, CEPH_CAP_LOCKS); } else { in->choose_lock_states(); dout(15) << " chose lock states on " << *in << dendl; } } } // ------- // cap imports and delayed snap parent opens void MDCache::do_cap_import(Session *session, CInode *in, Capability *cap, uint64_t p_cap_id, ceph_seq_t p_seq, ceph_seq_t p_mseq, int peer, int p_flags) { client_t client = session->info.inst.name.num(); SnapRealm *realm = in->find_snaprealm(); if (realm->have_past_parents_open()) { dout(10) << "do_cap_import " << session->info.inst.name << " mseq " << cap->get_mseq() << " on " << *in << dendl; if (cap->get_last_seq() == 0) // reconnected cap cap->inc_last_seq(); cap->set_last_issue(); cap->set_last_issue_stamp(ceph_clock_now(g_ceph_context)); cap->clear_new(); MClientCaps *reap = new MClientCaps(CEPH_CAP_OP_IMPORT, in->ino(), realm->inode->ino(), cap->get_cap_id(), cap->get_last_seq(), cap->pending(), cap->wanted(), 0, cap->get_mseq()); in->encode_cap_message(reap, cap); realm->build_snap_trace(reap->snapbl); reap->set_cap_peer(p_cap_id, p_seq, p_mseq, peer, p_flags); mds->send_message_client_counted(reap, session); } else { dout(10) << "do_cap_import missing past snap parents, delaying " << session->info.inst.name << " mseq " << cap->get_mseq() << " on " << *in << dendl; in->auth_pin(this); cap->inc_suppress(); delayed_imported_caps[client].insert(in); missing_snap_parents[in].size(); } } void MDCache::do_delayed_cap_imports() { dout(10) << "do_delayed_cap_imports" << dendl; assert(delayed_imported_caps.empty()); #if 0 map > d; d.swap(delayed_imported_caps); for (map >::iterator p = d.begin(); p != d.end(); ++p) { for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { CInode *in = *q; Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(p->first.v)); if (session) { Capability *cap = in->get_client_cap(p->first); if (cap) { do_cap_import(session, in, cap); // note: this may fail and requeue! cap->dec_suppress(); } } in->auth_unpin(this); if (in->is_head()) mds->locker->issue_caps(in); } } #endif } struct C_MDC_OpenSnapParents : public Context { MDCache *mdcache; C_MDC_OpenSnapParents(MDCache *c) : mdcache(c) {} void finish(int r) { mdcache->open_snap_parents(); } }; void MDCache::open_snap_parents() { dout(10) << "open_snap_parents" << dendl; map splits; C_GatherBuilder gather(g_ceph_context); map > >::iterator p = missing_snap_parents.begin(); while (p != missing_snap_parents.end()) { CInode *in = p->first; assert(in->snaprealm); if (in->snaprealm->open_parents(gather.new_sub())) { dout(10) << " past parents now open on " << *in << dendl; // include in a (now safe) snap split? for (map >::iterator q = p->second.begin(); q != p->second.end(); ++q) for (set::iterator r = q->second.begin(); r != q->second.end(); ++r) prepare_realm_split(in->snaprealm, q->first, *r, splits); missing_snap_parents.erase(p++); in->put(CInode::PIN_OPENINGSNAPPARENTS); // finish off client snaprealm reconnects? map >::iterator q = reconnected_snaprealms.find(in->ino()); if (q != reconnected_snaprealms.end()) { for (map::iterator r = q->second.begin(); r != q->second.end(); ++r) finish_snaprealm_reconnect(r->first, in->snaprealm, r->second); reconnected_snaprealms.erase(q); } } else { dout(10) << " opening past parents on " << *in << dendl; ++p; } } send_snaps(splits); if (gather.has_subs()) { dout(10) << "open_snap_parents - waiting for " << gather.num_subs_remaining() << dendl; gather.set_finisher(new C_MDC_OpenSnapParents(this)); gather.activate(); } else { if (!reconnected_snaprealms.empty()) { stringstream warn_str; for (map >::iterator p = reconnected_snaprealms.begin(); p != reconnected_snaprealms.end(); ++p) { warn_str << " unconnected snaprealm " << p->first << "\n"; for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) warn_str << " client." << q->first << " snapid " << q->second << "\n"; } mds->clog.warn() << "open_snap_parents has:" << "\n"; mds->clog.warn(warn_str); } assert(rejoin_waiters.empty()); assert(missing_snap_parents.empty()); dout(10) << "open_snap_parents - all open" << dendl; do_delayed_cap_imports(); start_files_to_recover(rejoin_recover_q, rejoin_check_q); mds->rejoin_done(); } } bool MDCache::open_undef_inodes_dirfrags() { dout(10) << "open_undef_inodes_dirfrags " << rejoin_undef_inodes.size() << " inodes " << rejoin_undef_dirfrags.size() << " dirfrags" << dendl; set fetch_queue = rejoin_undef_dirfrags; for (set::iterator p = rejoin_undef_inodes.begin(); p != rejoin_undef_inodes.end(); ++p) { CInode *in = *p; assert(!in->is_base()); fetch_queue.insert(in->get_parent_dir()); } if (fetch_queue.empty()) return false; C_GatherBuilder gather(g_ceph_context, new C_MDC_RejoinGatherFinish(this)); for (set::iterator p = fetch_queue.begin(); p != fetch_queue.end(); ++p) { CDir *dir = *p; CInode *diri = dir->get_inode(); if (diri->state_test(CInode::STATE_REJOINUNDEF)) continue; if (dir->state_test(CDir::STATE_REJOINUNDEF)) assert(diri->dirfragtree.is_leaf(dir->get_frag())); dir->fetch(gather.new_sub()); } assert(gather.has_subs()); gather.activate(); return true; } void MDCache::opened_undef_inode(CInode *in) { dout(10) << "opened_undef_inode " << *in << dendl; rejoin_undef_inodes.erase(in); if (in->is_dir()) { if (in->has_dirfrags() && !in->dirfragtree.is_leaf(frag_t())) { CDir *dir = in->get_dirfrag(frag_t()); assert(dir); rejoin_undef_dirfrags.erase(dir); in->force_dirfrags(); list ls; in->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) rejoin_undef_dirfrags.insert(*p); } } } void MDCache::finish_snaprealm_reconnect(client_t client, SnapRealm *realm, snapid_t seq) { if (seq < realm->get_newest_seq()) { dout(10) << "finish_snaprealm_reconnect client." << client << " has old seq " << seq << " < " << realm->get_newest_seq() << " on " << *realm << dendl; // send an update Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(client.v)); if (session) { MClientSnap *snap = new MClientSnap(CEPH_SNAP_OP_UPDATE); realm->build_snap_trace(snap->bl); mds->send_message_client_counted(snap, session); } else { dout(10) << " ...or not, no session for this client!" << dendl; } } else { dout(10) << "finish_snaprealm_reconnect client." << client << " up to date" << " on " << *realm << dendl; } } void MDCache::rejoin_send_acks() { dout(7) << "rejoin_send_acks" << dendl; // replicate stray for (map >::iterator p = rejoin_unlinked_inodes.begin(); p != rejoin_unlinked_inodes.end(); ++p) { for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { CInode *in = *q; dout(7) << " unlinked inode " << *in << dendl; // inode expired if (!in->is_replica(p->first)) continue; while (1) { CDentry *dn = in->get_parent_dn(); if (dn->is_replica(p->first)) break; dn->add_replica(p->first); CDir *dir = dn->get_dir(); if (dir->is_replica(p->first)) break; dir->add_replica(p->first); in = dir->get_inode(); if (in->is_replica(p->first)) break; if (in->is_base()) break; } } } rejoin_unlinked_inodes.clear(); // send acks to everyone in the recovery set map ack; for (set::iterator p = recovery_set.begin(); p != recovery_set.end(); ++p) ack[*p] = new MMDSCacheRejoin(MMDSCacheRejoin::OP_ACK); // walk subtrees for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = p->first; if (!dir->is_auth()) continue; dout(10) << "subtree " << *dir << dendl; // auth items in this subtree list dq; dq.push_back(dir); while (!dq.empty()) { CDir *dir = dq.front(); dq.pop_front(); // dir for (map::iterator r = dir->replicas_begin(); r != dir->replicas_end(); ++r) { ack[r->first]->add_strong_dirfrag(dir->dirfrag(), ++r->second, dir->dir_rep); ack[r->first]->add_dirfrag_base(dir); } for (CDir::map_t::iterator q = dir->items.begin(); q != dir->items.end(); ++q) { CDentry *dn = q->second; CDentry::linkage_t *dnl = dn->get_linkage(); // inode CInode *in = NULL; if (dnl->is_primary()) in = dnl->get_inode(); // dentry for (map::iterator r = dn->replicas_begin(); r != dn->replicas_end(); ++r) { ack[r->first]->add_strong_dentry(dir->dirfrag(), dn->name, dn->first, dn->last, dnl->is_primary() ? dnl->get_inode()->ino():inodeno_t(0), dnl->is_remote() ? dnl->get_remote_ino():inodeno_t(0), dnl->is_remote() ? dnl->get_remote_d_type():0, ++r->second, dn->lock.get_replica_state()); // peer missed MDentrylink message ? if (in && !in->is_replica(r->first)) in->add_replica(r->first); } if (!in) continue; for (map::iterator r = in->replicas_begin(); r != in->replicas_end(); ++r) { ack[r->first]->add_inode_base(in); bufferlist bl; in->_encode_locks_state_for_rejoin(bl, r->first); ack[r->first]->add_inode_locks(in, ++r->second, bl); } // subdirs in this subtree? in->get_nested_dirfrags(dq); } } } // base inodes too if (root && root->is_auth()) for (map::iterator r = root->replicas_begin(); r != root->replicas_end(); ++r) { ack[r->first]->add_inode_base(root); bufferlist bl; root->_encode_locks_state_for_rejoin(bl, r->first); ack[r->first]->add_inode_locks(root, ++r->second, bl); } if (myin) for (map::iterator r = myin->replicas_begin(); r != myin->replicas_end(); ++r) { ack[r->first]->add_inode_base(myin); bufferlist bl; myin->_encode_locks_state_for_rejoin(bl, r->first); ack[r->first]->add_inode_locks(myin, ++r->second, bl); } // include inode base for any inodes whose scatterlocks may have updated for (set::iterator p = rejoin_potential_updated_scatterlocks.begin(); p != rejoin_potential_updated_scatterlocks.end(); ++p) { CInode *in = *p; for (map::iterator r = in->replicas_begin(); r != in->replicas_end(); ++r) ack[r->first]->add_inode_base(in); } // send acks for (map::iterator p = ack.begin(); p != ack.end(); ++p) { ::encode(rejoin_imported_caps[p->first], p->second->imported_caps); mds->send_message_mds(p->second, p->first); } rejoin_imported_caps.clear(); } void MDCache::reissue_all_caps() { dout(10) << "reissue_all_caps" << dendl; for (ceph::unordered_map::iterator p = inode_map.begin(); p != inode_map.end(); ++p) { CInode *in = p->second; if (in->is_head() && in->is_any_caps()) { if (!mds->locker->eval(in, CEPH_CAP_LOCKS)) mds->locker->issue_caps(in); } } } // =============================================================================== struct C_MDC_QueuedCow : public Context { MDCache *mdcache; CInode *in; MutationRef mut; C_MDC_QueuedCow(MDCache *mdc, CInode *i, MutationRef& m) : mdcache(mdc), in(i), mut(m) {} void finish(int r) { mdcache->_queued_file_recover_cow(in, mut); } }; void MDCache::queue_file_recover(CInode *in) { dout(10) << "queue_file_recover " << *in << dendl; assert(in->is_auth()); // cow? SnapRealm *realm = in->find_snaprealm(); set s = realm->get_snaps(); while (!s.empty() && *s.begin() < in->first) s.erase(s.begin()); while (!s.empty() && *s.rbegin() > in->last) s.erase(*s.rbegin()); dout(10) << " snaps in [" << in->first << "," << in->last << "] are " << s << dendl; if (s.size() > 1) { inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); EUpdate *le = new EUpdate(mds->mdlog, "queue_file_recover cow"); mds->mdlog->start_entry(le); predirty_journal_parents(mut, &le->metablob, in, 0, PREDIRTY_PRIMARY); s.erase(*s.begin()); while (!s.empty()) { snapid_t snapid = *s.begin(); CInode *cow_inode = 0; journal_cow_inode(mut, &le->metablob, in, snapid-1, &cow_inode); assert(cow_inode); _queue_file_recover(cow_inode); s.erase(*s.begin()); } in->parent->first = in->first; le->metablob.add_primary_dentry(in->parent, in, true); mds->mdlog->submit_entry(le, new C_MDC_QueuedCow(this, in, mut)); mds->mdlog->flush(); } _queue_file_recover(in); } void MDCache::_queued_file_recover_cow(CInode *in, MutationRef& mut) { in->pop_and_dirty_projected_inode(mut->ls); mut->apply(); mds->locker->drop_locks(mut.get()); mut->cleanup(); } void MDCache::_queue_file_recover(CInode *in) { dout(15) << "_queue_file_recover " << *in << dendl; assert(in->is_auth()); in->state_clear(CInode::STATE_NEEDSRECOVER); if (!in->state_test(CInode::STATE_RECOVERING)) { in->state_set(CInode::STATE_RECOVERING); in->auth_pin(this); } file_recover_queue.insert(in); } void MDCache::unqueue_file_recover(CInode *in) { dout(15) << "unqueue_file_recover " << *in << dendl; in->state_clear(CInode::STATE_RECOVERING); in->auth_unpin(this); file_recover_queue.erase(in); } /* * called after recovery to recover file sizes for previously opened (for write) * files. that is, those where max_size > size. */ void MDCache::identify_files_to_recover(vector& recover_q, vector& check_q) { dout(10) << "identify_files_to_recover" << dendl; for (ceph::unordered_map::iterator p = inode_map.begin(); p != inode_map.end(); ++p) { CInode *in = p->second; if (!in->is_auth()) continue; bool recover = false; for (map::iterator p = in->inode.client_ranges.begin(); p != in->inode.client_ranges.end(); ++p) { Capability *cap = in->get_client_cap(p->first); if (!cap) { dout(10) << " client." << p->first << " has range " << p->second << " but no cap on " << *in << dendl; recover = true; break; } } if (recover) { in->auth_pin(&in->filelock); in->filelock.set_state(LOCK_PRE_SCAN); recover_q.push_back(in); // make sure past parents are open/get opened SnapRealm *realm = in->find_snaprealm(); check_realm_past_parents(realm); } else { check_q.push_back(in); } } } void MDCache::start_files_to_recover(vector& recover_q, vector& check_q) { for (vector::iterator p = check_q.begin(); p != check_q.end(); ++p) { CInode *in = *p; mds->locker->check_inode_max_size(in); } for (vector::iterator p = recover_q.begin(); p != recover_q.end(); ++p) { CInode *in = *p; mds->locker->file_recover(&in->filelock); } } struct C_MDC_Recover : public Context { MDCache *mdc; CInode *in; uint64_t size; utime_t mtime; C_MDC_Recover(MDCache *m, CInode *i) : mdc(m), in(i), size(0) {} void finish(int r) { mdc->_recovered(in, r, size, mtime); } }; void MDCache::do_file_recover() { dout(10) << "do_file_recover " << file_recover_queue.size() << " queued, " << file_recovering.size() << " recovering" << dendl; while (file_recovering.size() < 5 && !file_recover_queue.empty()) { CInode *in = *file_recover_queue.begin(); file_recover_queue.erase(in); inode_t *pi = in->get_projected_inode(); // blech if (pi->client_ranges.size() && !pi->get_max_size()) { mds->clog.warn() << "bad client_range " << pi->client_ranges << " on ino " << pi->ino << "\n"; } if (pi->client_ranges.size() && pi->get_max_size()) { dout(10) << "do_file_recover starting " << in->inode.size << " " << pi->client_ranges << " " << *in << dendl; file_recovering.insert(in); C_MDC_Recover *fin = new C_MDC_Recover(this, in); mds->filer->probe(in->inode.ino, &in->inode.layout, in->last, pi->get_max_size(), &fin->size, &fin->mtime, false, 0, fin); } else { dout(10) << "do_file_recover skipping " << in->inode.size << " " << *in << dendl; in->state_clear(CInode::STATE_RECOVERING); mds->locker->eval(in, CEPH_LOCK_IFILE); in->auth_unpin(this); } } } void MDCache::_recovered(CInode *in, int r, uint64_t size, utime_t mtime) { dout(10) << "_recovered r=" << r << " size=" << size << " mtime=" << mtime << " for " << *in << dendl; if (r != 0) { dout(0) << "recovery error! " << r << dendl; if (r == -EBLACKLISTED) { mds->suicide(); return; } assert(0 == "unexpected error from osd during recovery"); } file_recovering.erase(in); in->state_clear(CInode::STATE_RECOVERING); if (!in->get_parent_dn() && !in->get_projected_parent_dn()) { dout(10) << " inode has no parents, killing it off" << dendl; in->auth_unpin(this); remove_inode(in); } else { // journal mds->locker->check_inode_max_size(in, true, true, size, false, 0, mtime); mds->locker->eval(in, CEPH_LOCK_IFILE); in->auth_unpin(this); } do_file_recover(); } void MDCache::purge_prealloc_ino(inodeno_t ino, Context *fin) { object_t oid = CInode::get_object_name(ino, frag_t(), ""); object_locator_t oloc(mds->mdsmap->get_metadata_pool()); dout(10) << "purge_prealloc_ino " << ino << " oid " << oid << dendl; SnapContext snapc; mds->objecter->remove(oid, oloc, snapc, ceph_clock_now(g_ceph_context), 0, 0, fin); } // =============================================================================== // ---------------------------- // truncate void MDCache::truncate_inode(CInode *in, LogSegment *ls) { inode_t *pi = in->get_projected_inode(); dout(10) << "truncate_inode " << pi->truncate_from << " -> " << pi->truncate_size << " on " << *in << dendl; ls->truncating_inodes.insert(in); in->get(CInode::PIN_TRUNCATING); _truncate_inode(in, ls); } struct C_MDC_TruncateFinish : public Context { MDCache *mdc; CInode *in; LogSegment *ls; C_MDC_TruncateFinish(MDCache *c, CInode *i, LogSegment *l) : mdc(c), in(i), ls(l) {} void finish(int r) { assert(r == 0 || r == -ENOENT); mdc->truncate_inode_finish(in, ls); } }; void MDCache::_truncate_inode(CInode *in, LogSegment *ls) { inode_t *pi = &in->inode; dout(10) << "_truncate_inode " << pi->truncate_from << " -> " << pi->truncate_size << " on " << *in << dendl; assert(pi->is_truncating()); assert(pi->truncate_size < (1ULL << 63)); assert(pi->truncate_from < (1ULL << 63)); assert(pi->truncate_size < pi->truncate_from); in->auth_pin(this); SnapRealm *realm = in->find_snaprealm(); SnapContext nullsnap; const SnapContext *snapc; if (realm) { dout(10) << " realm " << *realm << dendl; snapc = &realm->get_snap_context(); } else { dout(10) << " NO realm, using null context" << dendl; snapc = &nullsnap; assert(in->last == CEPH_NOSNAP); } dout(10) << "_truncate_inode snapc " << snapc << " on " << *in << dendl; mds->filer->truncate(in->inode.ino, &in->inode.layout, *snapc, pi->truncate_size, pi->truncate_from-pi->truncate_size, pi->truncate_seq, utime_t(), 0, 0, new C_MDC_TruncateFinish(this, in, ls)); } struct C_MDC_TruncateLogged : public Context { MDCache *mdc; CInode *in; MutationRef mut; C_MDC_TruncateLogged(MDCache *m, CInode *i, MutationRef& mu) : mdc(m), in(i), mut(mu) {} void finish(int r) { mdc->truncate_inode_logged(in, mut); } }; void MDCache::truncate_inode_finish(CInode *in, LogSegment *ls) { dout(10) << "truncate_inode_finish " << *in << dendl; set::iterator p = ls->truncating_inodes.find(in); assert(p != ls->truncating_inodes.end()); ls->truncating_inodes.erase(p); // update inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); pi->truncate_from = 0; pi->truncate_pending--; MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); mut->add_projected_inode(in); EUpdate *le = new EUpdate(mds->mdlog, "truncate finish"); mds->mdlog->start_entry(le); CDentry *dn = in->get_projected_parent_dn(); le->metablob.add_dir_context(dn->get_dir()); le->metablob.add_primary_dentry(dn, in, true); le->metablob.add_truncate_finish(in->ino(), ls->offset); journal_dirty_inode(mut.get(), &le->metablob, in); mds->mdlog->submit_entry(le, new C_MDC_TruncateLogged(this, in, mut)); // flush immediately if there are readers/writers waiting if (in->get_caps_wanted() & (CEPH_CAP_FILE_RD|CEPH_CAP_FILE_WR)) mds->mdlog->flush(); } void MDCache::truncate_inode_logged(CInode *in, MutationRef& mut) { dout(10) << "truncate_inode_logged " << *in << dendl; mut->apply(); mds->locker->drop_locks(mut.get()); mut->cleanup(); in->put(CInode::PIN_TRUNCATING); in->auth_unpin(this); list waiters; in->take_waiting(CInode::WAIT_TRUNC, waiters); mds->queue_waiters(waiters); } void MDCache::add_recovered_truncate(CInode *in, LogSegment *ls) { dout(20) << "add_recovered_truncate " << *in << " in " << ls << " offset " << ls->offset << dendl; ls->truncating_inodes.insert(in); in->get(CInode::PIN_TRUNCATING); } void MDCache::remove_recovered_truncate(CInode *in, LogSegment *ls) { dout(20) << "remove_recovered_truncate " << *in << " in " << ls << " offset " << ls->offset << dendl; // if we have the logseg the truncate started in, it must be in our list. set::iterator p = ls->truncating_inodes.find(in); assert(p != ls->truncating_inodes.end()); ls->truncating_inodes.erase(p); in->put(CInode::PIN_TRUNCATING); } void MDCache::start_recovered_truncates() { dout(10) << "start_recovered_truncates" << dendl; for (map::iterator p = mds->mdlog->segments.begin(); p != mds->mdlog->segments.end(); ++p) { LogSegment *ls = p->second; for (set::iterator q = ls->truncating_inodes.begin(); q != ls->truncating_inodes.end(); ++q) _truncate_inode(*q, ls); } } // ================================================================================ // cache trimming /* * note: only called while MDS is active or stopping... NOT during recovery. * however, we may expire a replica whose authority is recovering. * */ bool MDCache::trim(int max) { // trim LRU if (max < 0) { max = g_conf->mds_cache_size; if (!max) return false; } dout(7) << "trim max=" << max << " cur=" << lru.lru_get_size() << dendl; // process delayed eval_stray() for (elist::iterator p = delayed_eval_stray.begin(); !p.end(); ) { CDentry *dn = *p; ++p; dn->item_stray.remove_myself(); eval_stray(dn); } map expiremap; bool is_standby_replay = mds->is_standby_replay(); int unexpirable = 0; list unexpirables; // trim dentries from the LRU while (lru.lru_get_size() + unexpirable > (unsigned)max) { CDentry *dn = static_cast(lru.lru_expire()); if (!dn) break; if ((is_standby_replay && dn->get_linkage() && dn->get_linkage()->inode->item_open_file.is_on_list()) || trim_dentry(dn, expiremap)) { unexpirables.push_back(dn); ++unexpirable; } } for(list::iterator i = unexpirables.begin(); i != unexpirables.end(); ++i) lru.lru_insert_mid(*i); // trim non-auth, non-bound subtrees for (map >::iterator p = subtrees.begin(); p != subtrees.end();) { CDir *dir = p->first; ++p; if (!dir->is_auth() && !dir->get_inode()->is_auth()) { // don't trim subtree root if its auth MDS is recovering. // This simplify the cache rejoin code. if (dir->is_subtree_root() && rejoin_ack_gather.count(dir->get_dir_auth().first)) continue; if (dir->get_num_ref() == 1) // subtree pin trim_dirfrag(dir, 0, expiremap); } } // trim root? if (max == 0 && root) { list ls; root->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; if (dir->get_num_ref() == 1) // subtree pin trim_dirfrag(dir, 0, expiremap); } if (root->get_num_ref() == 0) trim_inode(0, root, 0, expiremap); } // send any expire messages send_expire_messages(expiremap); return true; } void MDCache::send_expire_messages(map& expiremap) { // send expires for (map::iterator it = expiremap.begin(); it != expiremap.end(); ++it) { if (mds->mdsmap->get_state(it->first) < MDSMap::STATE_REJOIN || (mds->mdsmap->get_state(it->first) == MDSMap::STATE_REJOIN && rejoin_sent.count(it->first) == 0)) { it->second->put(); continue; } dout(7) << "sending cache_expire to " << it->first << dendl; mds->send_message_mds(it->second, it->first); } } bool MDCache::trim_dentry(CDentry *dn, map& expiremap) { dout(12) << "trim_dentry " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_linkage(); CDir *dir = dn->get_dir(); assert(dir); CDir *con = get_subtree_root(dir); if (con) dout(12) << " in container " << *con << dendl; else { dout(12) << " no container; under a not-yet-linked dir" << dendl; assert(dn->is_auth()); } // adjust the dir state // NOTE: we can safely remove a clean, null dentry without effecting // directory completeness. // (check this _before_ we unlink the inode, below!) bool null_dentry = false; bool clear_complete = false; if (!(dnl->is_null() && dn->is_clean())) clear_complete = true; // unlink the dentry if (dnl->is_remote()) { // just unlink. dir->unlink_inode(dn); } else if (dnl->is_primary()) { // expire the inode, too. CInode *in = dnl->get_inode(); assert(in); if (trim_inode(dn, in, con, expiremap)) return true; // purging stray instead of trimming } else { assert(dnl->is_null()); null_dentry = true; } // notify dentry authority? if (!dn->is_auth()) { // If null replica dentry is not readable, it's likely we will // receive a MDentryLink message soon. MDentryLink message only // replicates an inode, so we should avoid trimming the inode's // parent dentry. This is because that unconnected replicas are // problematic for subtree migration. if (null_dentry && !dn->lock.can_read(-1) && !dn->get_dir()->get_inode()->is_stray()) return true; pair auth = dn->authority(); for (int p=0; p<2; p++) { int a = auth.first; if (p) a = auth.second; if (a < 0 || (p == 1 && auth.second == auth.first)) break; if (mds->get_nodeid() == auth.second && con->is_importing()) break; // don't send any expire while importing. if (a == mds->get_nodeid()) continue; // on export, ignore myself. dout(12) << " sending expire to mds." << a << " on " << *dn << dendl; assert(a != mds->get_nodeid()); if (expiremap.count(a) == 0) expiremap[a] = new MCacheExpire(mds->get_nodeid()); expiremap[a]->add_dentry(con->dirfrag(), dir->dirfrag(), dn->name, dn->last, dn->get_replica_nonce()); } } // remove dentry if (dir->is_auth()) dir->add_to_bloom(dn); dir->remove_dentry(dn); if (clear_complete) dir->state_clear(CDir::STATE_COMPLETE); // reexport? if (dir->get_num_head_items() == 0 && dir->is_subtree_root()) migrator->export_empty_import(dir); if (mds->logger) mds->logger->inc(l_mds_iex); return false; } void MDCache::trim_dirfrag(CDir *dir, CDir *con, map& expiremap) { dout(15) << "trim_dirfrag " << *dir << dendl; if (dir->is_subtree_root()) { assert(!dir->is_auth() || (!dir->is_replicated() && dir->inode->is_base())); remove_subtree(dir); // remove from subtree map } assert(dir->get_num_ref() == 0); CInode *in = dir->get_inode(); if (!dir->is_auth()) { pair auth = dir->authority(); // was this an auth delegation? (if so, slightly modified container) dirfrag_t condf; if (dir->is_subtree_root()) { dout(12) << " subtree root, container is " << *dir << dendl; con = dir; condf = dir->dirfrag(); } else { condf = con->dirfrag(); } for (int p=0; p<2; p++) { int a = auth.first; if (p) a = auth.second; if (a < 0 || (p == 1 && auth.second == auth.first)) break; if (mds->get_nodeid() == auth.second && con->is_importing()) break; // don't send any expire while importing. if (a == mds->get_nodeid()) continue; // on export, ignore myself. dout(12) << " sending expire to mds." << a << " on " << *dir << dendl; assert(a != mds->get_nodeid()); if (expiremap.count(a) == 0) expiremap[a] = new MCacheExpire(mds->get_nodeid()); expiremap[a]->add_dir(condf, dir->dirfrag(), dir->replica_nonce); } } in->close_dirfrag(dir->dirfrag().frag); } bool MDCache::trim_inode(CDentry *dn, CInode *in, CDir *con, map& expiremap) { dout(15) << "trim_inode " << *in << dendl; assert(in->get_num_ref() == 0); if (in->is_dir()) { // If replica inode's dirfragtreelock is not readable, it's likely // some dirfrags of the inode are being fragmented and we will receive // MMDSFragmentNotify soon. MMDSFragmentNotify only replicates the new // dirfrags, so we should avoid trimming these dirfrags' parent inode. // This is because that unconnected replicas are problematic for // subtree migration. // if (!in->is_auth() && !in->dirfragtreelock.can_read(-1)) return true; // DIR list dfls; in->get_dirfrags(dfls); for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) { CDir *dir = *p; assert(!dir->is_subtree_root()); trim_dirfrag(dir, con ? con:dir, expiremap); // if no container (e.g. root dirfrag), use *p } } // INODE if (in->is_auth()) { // eval stray after closing dirfrags if (dn) { maybe_eval_stray(in); if (dn->get_num_ref() > 0) return true; } } else { pair auth = in->authority(); dirfrag_t df; if (con) df = con->dirfrag(); else df = dirfrag_t(0,frag_t()); // must be a root or stray inode. for (int p=0; p<2; p++) { int a = auth.first; if (p) a = auth.second; if (a < 0 || (p == 1 && auth.second == auth.first)) break; if (con && mds->get_nodeid() == auth.second && con->is_importing()) break; // don't send any expire while importing. if (a == mds->get_nodeid()) continue; // on export, ignore myself. dout(12) << " sending expire to mds." << a << " on " << *in << dendl; assert(a != mds->get_nodeid()); if (expiremap.count(a) == 0) expiremap[a] = new MCacheExpire(mds->get_nodeid()); expiremap[a]->add_inode(df, in->vino(), in->get_replica_nonce()); } } /* if (in->is_auth()) { if (in->hack_accessed) mds->logger->inc("outt"); else { mds->logger->inc("outut"); mds->logger->fset("oututl", ceph_clock_now(g_ceph_context) - in->hack_load_stamp); } } */ // unlink if (dn) dn->get_dir()->unlink_inode(dn); remove_inode(in); return false; } /** * trim_non_auth - remove any non-auth items from our cache * * this reduces the amount of non-auth metadata in our cache, reducing the * load incurred by the rejoin phase. * * the only non-auth items that remain are those that are needed to * attach our own subtrees to the root. * * when we are done, all dentries will be in the top bit of the lru. * * why we have to do this: * we may not have accurate linkage for non-auth items. which means we will * know which subtree it falls into, and can not be sure to declare it to the * correct authority. */ void MDCache::trim_non_auth() { dout(7) << "trim_non_auth" << dendl; // temporarily pin all subtree roots for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) p->first->get(CDir::PIN_SUBTREETEMP); // note first auth item we see. // when we see it the second time, stop. CDentry *first_auth = 0; // trim non-auth items from the lru while (lru.lru_get_size() > 0) { CDentry *dn = static_cast(lru.lru_expire()); if (!dn) break; CDentry::linkage_t *dnl = dn->get_linkage(); if (dn->is_auth()) { // add back into lru (at the top) lru.lru_insert_top(dn); if (dnl->is_remote() && dnl->get_inode() && !dnl->get_inode()->is_auth()) dn->unlink_remote(dnl); if (dn->get_dir()->get_inode()->is_stray()) { dn->state_set(CDentry::STATE_STRAY); if (dnl->is_primary() && dnl->get_inode()->inode.nlink == 0) dnl->get_inode()->state_set(CInode::STATE_ORPHAN); } if (!first_auth) { first_auth = dn; } else { if (first_auth == dn) break; } } else { // non-auth. expire. CDir *dir = dn->get_dir(); assert(dir); // unlink the dentry dout(10) << " removing " << *dn << dendl; if (dnl->is_remote()) { dir->unlink_inode(dn); } else if (dnl->is_primary()) { CInode *in = dnl->get_inode(); dout(10) << " removing " << *in << dendl; list ls; in->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *subdir = *p; assert(!subdir->is_subtree_root()); in->close_dirfrag(subdir->dirfrag().frag); } dir->unlink_inode(dn); remove_inode(in); } else { assert(dnl->is_null()); } assert(!dir->has_bloom()); dir->remove_dentry(dn); // adjust the dir state dir->state_clear(CDir::STATE_COMPLETE); // dir incomplete! // close empty non-auth dirfrag if (!dir->is_subtree_root() && dir->get_num_any() == 0) dir->inode->close_dirfrag(dir->get_frag()); } } // move everything in the pintail to the top bit of the lru. lru.lru_touch_entire_pintail(); // unpin all subtrees for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) p->first->put(CDir::PIN_SUBTREETEMP); if (lru.lru_get_size() == 0) { // root, stray, etc.? ceph::unordered_map::iterator p = inode_map.begin(); while (p != inode_map.end()) { ceph::unordered_map::iterator next = p; ++next; CInode *in = p->second; if (!in->is_auth()) { list ls; in->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { dout(10) << " removing " << **p << dendl; assert((*p)->get_num_ref() == 1); // SUBTREE remove_subtree((*p)); in->close_dirfrag((*p)->dirfrag().frag); } dout(10) << " removing " << *in << dendl; assert(!in->get_parent_dn()); assert(in->get_num_ref() == 0); remove_inode(in); } p = next; } } show_subtrees(); } /** * Recursively trim the subtree rooted at directory to remove all * CInodes/CDentrys/CDirs that aren't links to remote MDSes, or ancestors * of those links. This is used to clear invalid data out of the cache. * Note that it doesn't clear the passed-in directory, since that's not * always safe. */ bool MDCache::trim_non_auth_subtree(CDir *dir) { dout(10) << "trim_non_auth_subtree(" << dir << ") " << *dir << dendl; bool keep_dir = !can_trim_non_auth_dirfrag(dir); CDir::map_t::iterator j = dir->begin(); CDir::map_t::iterator i = j; while (j != dir->end()) { i = j++; CDentry *dn = i->second; dout(10) << "trim_non_auth_subtree(" << dir << ") Checking dentry " << dn << dendl; CDentry::linkage_t *dnl = dn->get_linkage(); if (dnl->is_primary()) { // check for subdirectories, etc CInode *in = dnl->get_inode(); bool keep_inode = false; if (in->is_dir()) { list subdirs; in->get_dirfrags(subdirs); for (list::iterator subdir = subdirs.begin(); subdir != subdirs.end(); ++subdir) { if ((*subdir)->is_subtree_root()) { keep_inode = true; dout(10) << "trim_non_auth_subtree(" << dir << ") keeping " << **subdir << dendl; } else { if (trim_non_auth_subtree(*subdir)) keep_inode = true; else { in->close_dirfrag((*subdir)->get_frag()); dir->state_clear(CDir::STATE_COMPLETE); // now incomplete! } } } } if (!keep_inode) { // remove it! dout(20) << "trim_non_auth_subtree(" << dir << ") removing inode " << in << " with dentry" << dn << dendl; dir->unlink_inode(dn); remove_inode(in); assert(!dir->has_bloom()); dir->remove_dentry(dn); } else { dout(20) << "trim_non_auth_subtree(" << dir << ") keeping inode " << in << " with dentry " << dn <is_null()) { // keep null dentry for slave rollback dout(20) << "trim_non_auth_subtree(" << dir << ") keeping dentry " << dn <is_remote()) dir->unlink_inode(dn); dir->remove_dentry(dn); } } /** * We've now checked all our children and deleted those that need it. * Now return to caller, and tell them if *we're* a keeper. */ return keep_dir || dir->get_num_any(); } /* * during replay, when we determine a subtree is no longer ours, we * try to trim it from our cache. because subtrees must be connected * to the root, the fact that we can trim this tree may mean that our * children or parents can also be trimmed. */ void MDCache::try_trim_non_auth_subtree(CDir *dir) { dout(10) << "try_trim_nonauth_subtree " << *dir << dendl; // can we now trim child subtrees? set bounds; get_subtree_bounds(dir, bounds); for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bd = *p; if (bd->get_dir_auth().first != mds->whoami && // we are not auth bd->get_num_any() == 0 && // and empty can_trim_non_auth_dirfrag(bd)) { CInode *bi = bd->get_inode(); dout(10) << " closing empty non-auth child subtree " << *bd << dendl; remove_subtree(bd); bd->mark_clean(); bi->close_dirfrag(bd->get_frag()); } } if (trim_non_auth_subtree(dir)) { // keep try_subtree_merge(dir); } else { // can we trim this subtree (and possibly our ancestors) too? while (true) { CInode *diri = dir->get_inode(); if (diri->is_base()) { if (!diri->is_root() && diri->authority().first != mds->whoami) { dout(10) << " closing empty non-auth subtree " << *dir << dendl; remove_subtree(dir); dir->mark_clean(); diri->close_dirfrag(dir->get_frag()); dout(10) << " removing " << *diri << dendl; assert(!diri->get_parent_dn()); assert(diri->get_num_ref() == 0); remove_inode(diri); } break; } CDir *psub = get_subtree_root(diri->get_parent_dir()); dout(10) << " parent subtree is " << *psub << dendl; if (psub->get_dir_auth().first == mds->whoami) break; // we are auth, keep. dout(10) << " closing empty non-auth subtree " << *dir << dendl; remove_subtree(dir); dir->mark_clean(); diri->close_dirfrag(dir->get_frag()); dout(10) << " parent subtree also non-auth: " << *psub << dendl; if (trim_non_auth_subtree(psub)) break; dir = psub; } } show_subtrees(); } /* This function DOES put the passed message before returning */ void MDCache::handle_cache_expire(MCacheExpire *m) { int from = m->get_from(); dout(7) << "cache_expire from mds." << from << dendl; if (mds->get_state() < MDSMap::STATE_REJOIN) { m->put(); return; } set gather_locks; // loop over realms for (map::iterator p = m->realms.begin(); p != m->realms.end(); ++p) { // check container? if (p->first.ino > 0) { CInode *expired_inode = get_inode(p->first.ino); assert(expired_inode); // we had better have this. CDir *parent_dir = expired_inode->get_approx_dirfrag(p->first.frag); assert(parent_dir); int export_state = -1; if (parent_dir->is_auth() && parent_dir->is_exporting()) { export_state = migrator->get_export_state(parent_dir); assert(export_state >= 0); } if (!parent_dir->is_auth() || (export_state != -1 && ((export_state == Migrator::EXPORT_WARNING && migrator->export_has_warned(parent_dir,from)) || export_state == Migrator::EXPORT_EXPORTING || export_state == Migrator::EXPORT_LOGGINGFINISH || (export_state == Migrator::EXPORT_NOTIFYING && !migrator->export_has_notified(parent_dir,from))))) { // not auth. dout(7) << "delaying nonauth|warned expires for " << *parent_dir << dendl; assert(parent_dir->is_frozen_tree_root()); // make a message container if (delayed_expire[parent_dir].count(from) == 0) delayed_expire[parent_dir][from] = new MCacheExpire(from); // merge these expires into it delayed_expire[parent_dir][from]->add_realm(p->first, p->second); continue; } assert(export_state <= Migrator::EXPORT_PREPPING || (export_state == Migrator::EXPORT_WARNING && !migrator->export_has_warned(parent_dir, from))); dout(7) << "expires for " << *parent_dir << dendl; } else { dout(7) << "containerless expires (root, stray inodes)" << dendl; } // INODES for (map::iterator it = p->second.inodes.begin(); it != p->second.inodes.end(); ++it) { CInode *in = get_inode(it->first); unsigned nonce = it->second; if (!in) { dout(0) << " inode expire on " << it->first << " from " << from << ", don't have it" << dendl; assert(in); } assert(in->is_auth()); // check nonce if (nonce == in->get_replica_nonce(from)) { // remove from our cached_by dout(7) << " inode expire on " << *in << " from mds." << from << " cached_by was " << in->get_replicas() << dendl; inode_remove_replica(in, from, false, gather_locks); } else { // this is an old nonce, ignore expire. dout(7) << " inode expire on " << *in << " from mds." << from << " with old nonce " << nonce << " (current " << in->get_replica_nonce(from) << "), dropping" << dendl; } } // DIRS for (map::iterator it = p->second.dirs.begin(); it != p->second.dirs.end(); ++it) { CDir *dir = get_dirfrag(it->first); unsigned nonce = it->second; if (!dir) { CInode *diri = get_inode(it->first.ino); if (diri) { if (mds->is_rejoin() && rejoin_ack_gather.count(mds->whoami) && // haven't sent rejoin ack yet !diri->is_replica(from)) { list ls; diri->get_nested_dirfrags(ls); dout(7) << " dir expire on dirfrag " << it->first << " from mds." << from << " while rejoining, inode isn't replicated" << dendl; for (list::iterator q = ls.begin(); q != ls.end(); ++q) { dir = *q; if (dir->is_replica(from)) { dout(7) << " dir expire on " << *dir << " from mds." << from << dendl; dir->remove_replica(from); } } continue; } CDir *other = diri->get_approx_dirfrag(it->first.frag); if (other) { dout(7) << " dir expire on dirfrag " << it->first << " from mds." << from << " have " << *other << ", mismatched frags, dropping" << dendl; continue; } } dout(0) << " dir expire on " << it->first << " from " << from << ", don't have it" << dendl; assert(dir); } assert(dir->is_auth()); // check nonce if (nonce == dir->get_replica_nonce(from)) { // remove from our cached_by dout(7) << " dir expire on " << *dir << " from mds." << from << " replicas was " << dir->replica_map << dendl; dir->remove_replica(from); } else { // this is an old nonce, ignore expire. dout(7) << " dir expire on " << *dir << " from mds." << from << " with old nonce " << nonce << " (current " << dir->get_replica_nonce(from) << "), dropping" << dendl; } } // DENTRIES for (map,uint32_t> >::iterator pd = p->second.dentries.begin(); pd != p->second.dentries.end(); ++pd) { dout(10) << " dn expires in dir " << pd->first << dendl; CInode *diri = get_inode(pd->first.ino); assert(diri); CDir *dir = diri->get_dirfrag(pd->first.frag); if (!dir) { dout(0) << " dn expires on " << pd->first << " from " << from << ", must have refragmented" << dendl; } else { assert(dir->is_auth()); } for (map,uint32_t>::iterator p = pd->second.begin(); p != pd->second.end(); ++p) { unsigned nonce = p->second; CDentry *dn; if (dir) { dn = dir->lookup(p->first.first, p->first.second); } else { // which dirfrag for this dentry? CDir *dir = diri->get_dirfrag(diri->pick_dirfrag(p->first.first)); assert(dir); assert(dir->is_auth()); dn = dir->lookup(p->first.first, p->first.second); } if (!dn) { if (dir) dout(0) << " missing dentry for " << p->first.first << " snap " << p->first.second << " in " << *dir << dendl; else dout(0) << " missing dentry for " << p->first.first << " snap " << p->first.second << dendl; } assert(dn); if (nonce == dn->get_replica_nonce(from)) { dout(7) << " dentry_expire on " << *dn << " from mds." << from << dendl; dentry_remove_replica(dn, from, gather_locks); } else { dout(7) << " dentry_expire on " << *dn << " from mds." << from << " with old nonce " << nonce << " (current " << dn->get_replica_nonce(from) << "), dropping" << dendl; } } } } // done m->put(); for (set::iterator p = gather_locks.begin(); p != gather_locks.end(); ++p) { if (!(*p)->is_stable()) mds->locker->eval_gather(*p); } } void MDCache::process_delayed_expire(CDir *dir) { dout(7) << "process_delayed_expire on " << *dir << dendl; for (map::iterator p = delayed_expire[dir].begin(); p != delayed_expire[dir].end(); ++p) handle_cache_expire(p->second); delayed_expire.erase(dir); } void MDCache::discard_delayed_expire(CDir *dir) { dout(7) << "discard_delayed_expire on " << *dir << dendl; for (map::iterator p = delayed_expire[dir].begin(); p != delayed_expire[dir].end(); ++p) p->second->put(); delayed_expire.erase(dir); } void MDCache::inode_remove_replica(CInode *in, int from, bool rejoin, set& gather_locks) { in->remove_replica(from); in->mds_caps_wanted.erase(from); // note: this code calls _eval more often than it needs to! // fix lock if (in->authlock.remove_replica(from)) gather_locks.insert(&in->authlock); if (in->linklock.remove_replica(from)) gather_locks.insert(&in->linklock); if (in->snaplock.remove_replica(from)) gather_locks.insert(&in->snaplock); if (in->xattrlock.remove_replica(from)) gather_locks.insert(&in->xattrlock); if (in->flocklock.remove_replica(from)) gather_locks.insert(&in->flocklock); if (in->policylock.remove_replica(from)) gather_locks.insert(&in->policylock); // If 'rejoin' is true and the scatter lock is in LOCK_MIX_* state. // Don't remove the recovering mds from lock's gathering list because // it may hold rejoined wrlocks. if (in->dirfragtreelock.remove_replica(from, rejoin)) gather_locks.insert(&in->dirfragtreelock); if (in->filelock.remove_replica(from, rejoin)) gather_locks.insert(&in->filelock); if (in->nestlock.remove_replica(from, rejoin)) gather_locks.insert(&in->nestlock); } void MDCache::dentry_remove_replica(CDentry *dn, int from, set& gather_locks) { dn->remove_replica(from); // fix lock if (dn->lock.remove_replica(from)) gather_locks.insert(&dn->lock); } void MDCache::trim_client_leases() { utime_t now = ceph_clock_now(g_ceph_context); dout(10) << "trim_client_leases" << dendl; for (int pool=0; poolttl > now) break; CDentry *dn = static_cast(r->parent); dout(10) << " expiring client." << r->client << " lease of " << *dn << dendl; dn->remove_client_lease(r, mds->locker); } int after = client_leases[pool].size(); dout(10) << "trim_client_leases pool " << pool << " trimmed " << (before-after) << " leases, " << after << " left" << dendl; } } void MDCache::check_memory_usage() { static MemoryModel mm(g_ceph_context); static MemoryModel::snap last; mm.sample(&last); static MemoryModel::snap baseline = last; // check client caps int num_inodes = inode_map.size(); float caps_per_inode = (float)num_caps / (float)num_inodes; //float cap_rate = (float)num_inodes_with_caps / (float)inode_map.size(); dout(2) << "check_memory_usage" << " total " << last.get_total() << ", rss " << last.get_rss() << ", heap " << last.get_heap() << ", malloc " << last.malloc << " mmap " << last.mmap << ", baseline " << baseline.get_heap() << ", buffers " << (buffer::get_total_alloc() >> 10) << ", max " << g_conf->mds_mem_max << ", " << num_inodes_with_caps << " / " << inode_map.size() << " inodes have caps" << ", " << num_caps << " caps, " << caps_per_inode << " caps per inode" << dendl; mds->mlogger->set(l_mdm_rss, last.get_rss()); mds->mlogger->set(l_mdm_heap, last.get_heap()); mds->mlogger->set(l_mdm_malloc, last.malloc); /*int size = last.get_total(); if (size > g_conf->mds_mem_max * .9) { float ratio = (float)g_conf->mds_mem_max * .9 / (float)size; if (ratio < 1.0) mds->server->recall_client_state(ratio); } else */ if (num_inodes_with_caps > g_conf->mds_cache_size) { float ratio = (float)g_conf->mds_cache_size * .9 / (float)num_inodes_with_caps; if (ratio < 1.0) mds->server->recall_client_state(ratio); } } // ========================================================================================= // shutdown class C_MDC_ShutdownCheck : public Context { MDCache *mdc; public: C_MDC_ShutdownCheck(MDCache *m) : mdc(m) {} void finish(int) { mdc->shutdown_check(); } }; void MDCache::shutdown_check() { dout(0) << "shutdown_check at " << ceph_clock_now(g_ceph_context) << dendl; // cache char old_val[32] = { 0 }; char *o = old_val; g_conf->get_val("debug_mds", &o, sizeof(old_val)); g_conf->set_val("debug_mds", "10"); g_conf->apply_changes(NULL); show_cache(); g_conf->set_val("debug_mds", old_val); g_conf->apply_changes(NULL); mds->timer.add_event_after(g_conf->mds_shutdown_check, new C_MDC_ShutdownCheck(this)); // this dout(0) << "lru size now " << lru.lru_get_size() << dendl; dout(0) << "log len " << mds->mdlog->get_num_events() << dendl; if (mds->objecter->is_active()) { dout(0) << "objecter still active" << dendl; mds->objecter->dump_active(); } } void MDCache::shutdown_start() { dout(2) << "shutdown_start" << dendl; if (g_conf->mds_shutdown_check) mds->timer.add_event_after(g_conf->mds_shutdown_check, new C_MDC_ShutdownCheck(this)); // g_conf->debug_mds = 10; } bool MDCache::shutdown_pass() { dout(7) << "shutdown_pass" << dendl; if (mds->is_stopped()) { dout(7) << " already shut down" << dendl; show_cache(); show_subtrees(); return true; } // close out any sessions (and open files!) before we try to trim the log, etc. if (!mds->server->terminating_sessions && mds->sessionmap.have_unclosed_sessions()) { mds->server->terminate_sessions(); return false; } // flush what we can from the log mds->mdlog->trim(0); if (mds->mdlog->get_num_segments() > 1) { dout(7) << "still >1 segments, waiting for log to trim" << dendl; return false; } // empty stray dir if (!shutdown_export_strays()) { dout(7) << "waiting for strays to migrate" << dendl; return false; } // drop our reference to our stray dir inode for (int i = 0; i < NUM_STRAY; ++i) { if (strays[i] && strays[i]->state_test(CInode::STATE_STRAYPINNED)) { strays[i]->state_clear(CInode::STATE_STRAYPINNED); strays[i]->put(CInode::PIN_STRAY); strays[i]->put_stickydirs(); } } // trim cache trim(0); dout(5) << "lru size now " << lru.lru_get_size() << dendl; // SUBTREES if (!subtrees.empty() && mds->get_nodeid() != 0 && !migrator->is_exporting() //&& //!migrator->is_importing() ) { dout(7) << "looking for subtrees to export to mds0" << dendl; list ls; for (map >::iterator it = subtrees.begin(); it != subtrees.end(); ++it) { CDir *dir = it->first; if (dir->get_inode()->is_mdsdir()) continue; if (dir->is_frozen() || dir->is_freezing()) continue; if (!dir->is_full_dir_auth()) continue; ls.push_back(dir); } int max = 5; // throttle shutdown exports.. hack! for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; int dest = dir->get_inode()->authority().first; if (dest > 0 && !mds->mdsmap->is_active(dest)) dest = 0; dout(7) << "sending " << *dir << " back to mds." << dest << dendl; migrator->export_dir(dir, dest); if (--max == 0) break; } } if (!shutdown_export_caps()) { dout(7) << "waiting for residual caps to export" << dendl; return false; } CDir *mydir = myin ? myin->get_dirfrag(frag_t()) : NULL; if (mydir && !mydir->is_subtree_root()) mydir = NULL; // subtrees map not empty yet? if (subtrees.size() > (mydir ? 1 : 0)) { dout(7) << "still have " << num_subtrees() << " subtrees" << dendl; show_subtrees(); migrator->show_importing(); migrator->show_exporting(); if (!migrator->is_importing() && !migrator->is_exporting()) show_cache(); return false; } assert(!migrator->is_exporting()); assert(!migrator->is_importing()); // make mydir subtree go away if (mydir) { adjust_subtree_auth(mydir, CDIR_AUTH_UNKNOWN); remove_subtree(mydir); } assert(subtrees.empty()); // (only do this once!) if (!mds->mdlog->is_capped()) { dout(7) << "capping the log" << dendl; mds->mdlog->cap(); mds->mdlog->trim(); } if (!mds->mdlog->empty()) { dout(7) << "waiting for log to flush.. " << mds->mdlog->get_num_events() << " in " << mds->mdlog->get_num_segments() << " segments" << dendl; return false; } if (!did_shutdown_log_cap) { // flush journal header dout(7) << "writing header for (now-empty) journal" << dendl; assert(mds->mdlog->empty()); mds->mdlog->write_head(0); // NOTE: filer active checker below will block us until this completes. did_shutdown_log_cap = true; return false; } // filer active? if (mds->objecter->is_active()) { dout(7) << "objecter still active" << dendl; mds->objecter->dump_active(); return false; } // trim what we can from the cache if (lru.lru_get_size() > 0) { dout(7) << "there's still stuff in the cache: " << lru.lru_get_size() << dendl; show_cache(); //dump(); return false; } // done! dout(2) << "shutdown done." << dendl; return true; } bool MDCache::shutdown_export_strays() { if (mds->get_nodeid() == 0) return true; dout(10) << "shutdown_export_strays" << dendl; bool done = true; static set exported_strays; list dfs; for (int i = 0; i < NUM_STRAY; ++i) { if (!strays[i]) { continue; } strays[i]->get_dirfrags(dfs); } while (!dfs.empty()) { CDir *dir = dfs.front(); dfs.pop_front(); if (!dir->is_complete()) { dir->fetch(0); done = false; } for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; CDentry::linkage_t *dnl = dn->get_linkage(); if (dnl->is_null()) continue; done = false; // FIXME: we'll deadlock if a rename fails. if (exported_strays.count(dnl->get_inode()->ino()) == 0) { exported_strays.insert(dnl->get_inode()->ino()); migrate_stray(dn, 0); // send to root! } else { dout(10) << "already exporting " << *dn << dendl; } } } return done; } bool MDCache::shutdown_export_caps() { // export caps? // note: this runs more often than it should. static bool exported_caps = false; static set exported_caps_in; if (!exported_caps) { dout(7) << "searching for caps to export" << dendl; exported_caps = true; list dirq; for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { if (exported_caps_in.count(p->first)) continue; if (p->first->is_auth() || p->first->is_ambiguous_auth()) exported_caps = false; // we'll have to try again else { dirq.push_back(p->first); exported_caps_in.insert(p->first); } } while (!dirq.empty()) { CDir *dir = dirq.front(); dirq.pop_front(); for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; CDentry::linkage_t *dnl = dn->get_linkage(); if (!dnl->is_primary()) continue; CInode *in = dnl->get_inode(); if (in->is_dir()) in->get_nested_dirfrags(dirq); if (in->is_any_caps() && !in->state_test(CInode::STATE_EXPORTINGCAPS)) migrator->export_caps(in); } } } return true; } // ========= messaging ============== /* This function DOES put the passed message before returning */ void MDCache::dispatch(Message *m) { switch (m->get_type()) { // RESOLVE case MSG_MDS_RESOLVE: handle_resolve(static_cast(m)); break; case MSG_MDS_RESOLVEACK: handle_resolve_ack(static_cast(m)); break; // REJOIN case MSG_MDS_CACHEREJOIN: handle_cache_rejoin(static_cast(m)); break; case MSG_MDS_DISCOVER: handle_discover(static_cast(m)); break; case MSG_MDS_DISCOVERREPLY: handle_discover_reply(static_cast(m)); break; case MSG_MDS_DIRUPDATE: handle_dir_update(static_cast(m)); break; case MSG_MDS_CACHEEXPIRE: handle_cache_expire(static_cast(m)); break; case MSG_MDS_DENTRYLINK: handle_dentry_link(static_cast(m)); break; case MSG_MDS_DENTRYUNLINK: handle_dentry_unlink(static_cast(m)); break; case MSG_MDS_FRAGMENTNOTIFY: handle_fragment_notify(static_cast(m)); break; case MSG_MDS_FINDINO: handle_find_ino(static_cast(m)); break; case MSG_MDS_FINDINOREPLY: handle_find_ino_reply(static_cast(m)); break; case MSG_MDS_OPENINO: handle_open_ino(static_cast(m)); break; case MSG_MDS_OPENINOREPLY: handle_open_ino_reply(static_cast(m)); break; default: dout(7) << "cache unknown message " << m->get_type() << dendl; assert(0); m->put(); break; } } Context *MDCache::_get_waiter(MDRequestRef& mdr, Message *req, Context *fin) { if (mdr) { dout(20) << "_get_waiter retryrequest" << dendl; return new C_MDS_RetryRequest(this, mdr); } else if (req) { dout(20) << "_get_waiter retrymessage" << dendl; return new C_MDS_RetryMessage(mds, req); } else { return fin; } } int MDCache::path_traverse(MDRequestRef& mdr, Message *req, Context *fin, // who const filepath& path, // what vector *pdnvec, // result CInode **pin, int onfail) { bool discover = (onfail == MDS_TRAVERSE_DISCOVER); bool null_okay = (onfail == MDS_TRAVERSE_DISCOVERXLOCK); bool forward = (onfail == MDS_TRAVERSE_FORWARD); assert(mdr || req || fin); assert(!forward || mdr || req); // forward requires a request snapid_t snapid = CEPH_NOSNAP; if (mdr) mdr->snapid = snapid; client_t client = (mdr && mdr->reqid.name.is_client()) ? mdr->reqid.name.num() : -1; if (mds->logger) mds->logger->inc(l_mds_t); dout(7) << "traverse: opening base ino " << path.get_ino() << " snap " << snapid << dendl; CInode *cur = get_inode(path.get_ino()); if (cur == NULL) { if (MDS_INO_IS_MDSDIR(path.get_ino())) open_foreign_mdsdir(path.get_ino(), _get_waiter(mdr, req, fin)); else { //assert(0); // hrm.. broken return -ESTALE; } return 1; } if (cur->state_test(CInode::STATE_PURGING)) return -ESTALE; // start trace if (pdnvec) pdnvec->clear(); if (pin) *pin = cur; unsigned depth = 0; while (depth < path.depth()) { dout(12) << "traverse: path seg depth " << depth << " '" << path[depth] << "' snapid " << snapid << dendl; if (!cur->is_dir()) { dout(7) << "traverse: " << *cur << " not a dir " << dendl; return -ENOTDIR; } // walk into snapdir? if (path[depth].length() == 0) { dout(10) << "traverse: snapdir" << dendl; if (!mdr) return -EINVAL; snapid = CEPH_SNAPDIR; mdr->snapid = snapid; depth++; continue; } // walk thru snapdir? if (snapid == CEPH_SNAPDIR) { if (!mdr) return -EINVAL; SnapRealm *realm = cur->find_snaprealm(); snapid = realm->resolve_snapname(path[depth], cur->ino()); dout(10) << "traverse: snap " << path[depth] << " -> " << snapid << dendl; if (!snapid) return -ENOENT; mdr->snapid = snapid; depth++; continue; } // open dir frag_t fg = cur->pick_dirfrag(path[depth]); CDir *curdir = cur->get_dirfrag(fg); if (!curdir) { if (cur->is_auth()) { // parent dir frozen_dir? if (cur->is_frozen()) { dout(7) << "traverse: " << *cur << " is frozen, waiting" << dendl; cur->add_waiter(CDir::WAIT_UNFREEZE, _get_waiter(mdr, req, fin)); return 1; } curdir = cur->get_or_open_dirfrag(this, fg); } else { // discover? dout(10) << "traverse: need dirfrag " << fg << ", doing discover from " << *cur << dendl; discover_path(cur, snapid, path.postfixpath(depth), _get_waiter(mdr, req, fin), null_okay); if (mds->logger) mds->logger->inc(l_mds_tdis); return 1; } } assert(curdir); #ifdef MDS_VERIFY_FRAGSTAT if (curdir->is_complete()) curdir->verify_fragstat(); #endif // frozen? /* if (curdir->is_frozen()) { // doh! // FIXME: traverse is allowed? dout(7) << "traverse: " << *curdir << " is frozen, waiting" << dendl; curdir->add_waiter(CDir::WAIT_UNFREEZE, _get_waiter(mdr, req, fin)); if (onfinish) delete onfinish; return 1; } */ // must read directory hard data (permissions, x bit) to traverse #if 0 if (!noperm && !mds->locker->rdlock_try(&cur->authlock, client, 0)) { dout(7) << "traverse: waiting on authlock rdlock on " << *cur << dendl; cur->authlock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req, fin)); return 1; } #endif // make sure snaprealm parents are open... if (cur->snaprealm && !cur->snaprealm->open && mdr && !cur->snaprealm->open_parents(_get_waiter(mdr, req, fin))) { return 1; } // dentry CDentry *dn = curdir->lookup(path[depth], snapid); CDentry::linkage_t *dnl = dn ? dn->get_projected_linkage() : 0; // null and last_bit and xlocked by me? if (dnl && dnl->is_null() && null_okay) { dout(10) << "traverse: hit null dentry at tail of traverse, succeeding" << dendl; if (pdnvec) pdnvec->push_back(dn); if (pin) *pin = 0; break; // done! } if (dnl && dn->lock.is_xlocked() && dn->lock.get_xlock_by() != mdr && !dn->lock.can_read(client) && (dnl->is_null() || forward)) { dout(10) << "traverse: xlocked dentry at " << *dn << dendl; dn->lock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req, fin)); if (mds->logger) mds->logger->inc(l_mds_tlock); mds->mdlog->flush(); return 1; } // can we conclude ENOENT? if (dnl && dnl->is_null()) { if (dn->lock.can_read(client) || (dn->lock.is_xlocked() && dn->lock.get_xlock_by() == mdr)) { dout(10) << "traverse: miss on null+readable dentry " << path[depth] << " " << *dn << dendl; return -ENOENT; } else { dout(10) << "miss on dentry " << *dn << ", can't read due to lock" << dendl; dn->lock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req, fin)); return 1; } } if (dnl && !dnl->is_null()) { CInode *in = dnl->get_inode(); // do we have inode? if (!in) { assert(dnl->is_remote()); // do i have it? in = get_inode(dnl->get_remote_ino()); if (in) { dout(7) << "linking in remote in " << *in << dendl; dn->link_remote(dnl, in); } else { dout(7) << "remote link to " << dnl->get_remote_ino() << ", which i don't have" << dendl; assert(mdr); // we shouldn't hit non-primary dentries doing a non-mdr traversal! open_remote_dentry(dn, true, _get_waiter(mdr, req, fin), (null_okay && depth == path.depth() - 1)); if (mds->logger) mds->logger->inc(l_mds_trino); return 1; } } // forwarder wants replicas? #if 0 if (mdr && mdr->client_request && mdr->client_request->get_mds_wants_replica_in_dirino()) { dout(30) << "traverse: REP is here, " << mdr->client_request->get_mds_wants_replica_in_dirino() << " vs " << curdir->dirfrag() << dendl; if (mdr->client_request->get_mds_wants_replica_in_dirino() == curdir->ino() && curdir->is_auth() && curdir->is_rep() && curdir->is_replica(req->get_source().num()) && dn->is_auth() ) { assert(req->get_source().is_mds()); int from = req->get_source().num(); if (dn->is_replica(from)) { dout(15) << "traverse: REP would replicate to mds." << from << ", but already cached_by " << req->get_source() << " dn " << *dn << dendl; } else { dout(10) << "traverse: REP replicating to " << req->get_source() << " dn " << *dn << dendl; MDiscoverReply *reply = new MDiscoverReply(curdir->dirfrag()); reply->mark_unsolicited(); reply->starts_with = MDiscoverReply::DENTRY; replicate_dentry(dn, from, reply->trace); if (dnl->is_primary()) replicate_inode(in, from, reply->trace); if (req->get_source() != req->get_orig_source()) mds->send_message_mds(reply, req->get_source().num()); else mds->send_message(reply->req->get_connnection()); } } } #endif // add to trace, continue. cur = in; touch_inode(cur); if (pdnvec) pdnvec->push_back(dn); if (pin) *pin = cur; depth++; continue; } // MISS. dentry doesn't exist. dout(12) << "traverse: miss on dentry " << path[depth] << " in " << *curdir << dendl; if (curdir->is_auth()) { // dentry is mine. if (curdir->is_complete() || (curdir->has_bloom() && !curdir->is_in_bloom(path[depth]))){ // file not found if (pdnvec) { // instantiate a null dn? if (depth < path.depth()-1){ dout(20) << " didn't traverse full path; not returning pdnvec" << dendl; dn = NULL; } else if (dn) { assert(0); // should have fallen out in ->is_null() check above } else if (curdir->is_frozen()) { dout(20) << " not adding null to frozen dir " << dendl; } else if (snapid < CEPH_MAXSNAP) { dout(20) << " not adding null for snapid " << snapid << dendl; } else { // create a null dentry dn = curdir->add_null_dentry(path[depth]); dout(20) << " added null " << *dn << dendl; } if (dn) pdnvec->push_back(dn); else pdnvec->clear(); // do not confuse likes of rdlock_path_pin_ref(); } return -ENOENT; } else { // directory isn't complete; reload dout(7) << "traverse: incomplete dir contents for " << *cur << ", fetching" << dendl; touch_inode(cur); curdir->fetch(_get_waiter(mdr, req, fin), path[depth]); if (mds->logger) mds->logger->inc(l_mds_tdirf); return 1; } } else { // dirfrag/dentry is not mine. pair dauth = curdir->authority(); if (forward && snapid && mdr && mdr->client_request && (int)depth < mdr->client_request->get_num_fwd()) { dout(7) << "traverse: snap " << snapid << " and depth " << depth << " < fwd " << mdr->client_request->get_num_fwd() << ", discovering instead of forwarding" << dendl; discover = true; } if ((discover || null_okay)) { dout(7) << "traverse: discover from " << path[depth] << " from " << *curdir << dendl; discover_path(curdir, snapid, path.postfixpath(depth), _get_waiter(mdr, req, fin), null_okay); if (mds->logger) mds->logger->inc(l_mds_tdis); return 1; } if (forward) { // forward dout(7) << "traverse: not auth for " << path << " in " << *curdir << dendl; if (curdir->is_ambiguous_auth()) { // wait dout(7) << "traverse: waiting for single auth in " << *curdir << dendl; curdir->add_waiter(CDir::WAIT_SINGLEAUTH, _get_waiter(mdr, req, fin)); return 1; } dout(7) << "traverse: forwarding, not auth for " << *curdir << dendl; #if 0 // request replication? if (mdr && mdr->client_request && curdir->is_rep()) { dout(15) << "traverse: REP fw to mds." << dauth << ", requesting rep under " << *curdir << " req " << *(MClientRequest*)req << dendl; mdr->client_request->set_mds_wants_replica_in_dirino(curdir->ino()); req->clear_payload(); // reencode! } #endif if (mdr) request_forward(mdr, dauth.first); else mds->forward_message_mds(req, dauth.first); if (mds->logger) mds->logger->inc(l_mds_tfw); assert(fin == NULL); return 2; } } assert(0); // i shouldn't get here } // success. if (mds->logger) mds->logger->inc(l_mds_thit); dout(10) << "path_traverse finish on snapid " << snapid << dendl; if (mdr) assert(mdr->snapid == snapid); return 0; } #if 0 /** * Find out if the MDS is auth for a given path. * * Returns true if: * 1) The full path DNE and we are auth for the deepest existing piece * 2) We are auth for the inode linked to by the last dentry. */ bool MDCache::path_is_mine(filepath& path) { dout(15) << "path_is_mine " << path.get_ino() << " " << path << dendl; CInode *cur = get_inode(path.get_ino()); if (!cur) return false; // who knows! for (unsigned i=0; ipick_dirfrag(path[i]); CDir *dir = cur->get_dirfrag(fg); if (!dir) return cur->is_auth(); CDentry *dn = dir->lookup(path[i]); CDentry::linkage_t *dnl = dn->get_linkage(); if (!dn || dnl->is_null()) return dir->is_auth(); if (!dnl->is_primary()) return false; cur = dnl->get_inode(); } return cur->is_auth(); } #endif CInode *MDCache::cache_traverse(const filepath& fp) { dout(10) << "cache_traverse " << fp << dendl; CInode *in; if (fp.get_ino()) in = get_inode(fp.get_ino()); else in = root; if (!in) return NULL; for (unsigned i = 0; i < fp.depth(); i++) { const string& dname = fp[i]; frag_t fg = in->pick_dirfrag(dname); dout(20) << " " << i << " " << dname << " frag " << fg << " from " << *in << dendl; CDir *curdir = in->get_dirfrag(fg); if (!curdir) return NULL; CDentry *dn = curdir->lookup(dname, CEPH_NOSNAP); if (!dn) return NULL; in = dn->get_linkage()->get_inode(); if (!in) return NULL; } dout(10) << " got " << *in << dendl; return in; } /** * open_remote_dir -- open up a remote dirfrag * * @param diri base inode * @param approxfg approximate fragment. * @param fin completion callback */ void MDCache::open_remote_dirfrag(CInode *diri, frag_t approxfg, Context *fin) { dout(10) << "open_remote_dir on " << *diri << dendl; assert(diri->is_dir()); assert(!diri->is_auth()); assert(diri->get_dirfrag(approxfg) == 0); int auth = diri->authority().first; if (mds->mdsmap->get_state(auth) >= MDSMap::STATE_REJOIN) { discover_dir_frag(diri, approxfg, fin); } else { // mds is down or recovering. forge a replica! forge_replica_dir(diri, approxfg, auth); if (fin) mds->queue_waiter(fin); } } /** * get_dentry_inode - get or open inode * * @param dn the dentry * @param mdr current request * * will return inode for primary, or link up/open up remote link's inode as necessary. * If it's not available right now, puts mdr on wait list and returns null. */ CInode *MDCache::get_dentry_inode(CDentry *dn, MDRequestRef& mdr, bool projected) { CDentry::linkage_t *dnl; if (projected) dnl = dn->get_projected_linkage(); else dnl = dn->get_linkage(); assert(!dnl->is_null()); if (dnl->is_primary()) return dnl->inode; assert(dnl->is_remote()); CInode *in = get_inode(dnl->get_remote_ino()); if (in) { dout(7) << "get_dentry_inode linking in remote in " << *in << dendl; dn->link_remote(dnl, in); return in; } else { dout(10) << "get_dentry_inode on remote dn, opening inode for " << *dn << dendl; open_remote_ino(dnl->remote_ino, new C_MDS_RetryRequest(this, mdr)); return 0; } } class C_MDC_RetryOpenRemoteIno : public Context { MDCache *mdcache; inodeno_t ino; bool want_xlocked; Context *onfinish; public: C_MDC_RetryOpenRemoteIno(MDCache *mdc, inodeno_t i, Context *c, bool wx) : mdcache(mdc), ino(i), want_xlocked(wx), onfinish(c) {} void finish(int r) { if (mdcache->get_inode(ino)) { onfinish->complete(0); } else mdcache->open_remote_ino(ino, onfinish, want_xlocked); } }; class C_MDC_OpenRemoteIno : public Context { MDCache *mdcache; inodeno_t ino; inodeno_t hadino; version_t hadv; bool want_xlocked; Context *onfinish; public: vector anchortrace; C_MDC_OpenRemoteIno(MDCache *mdc, inodeno_t i, bool wx, inodeno_t hi, version_t hv, Context *c) : mdcache(mdc), ino(i), hadino(hi), hadv(hv), want_xlocked(wx), onfinish(c) {} C_MDC_OpenRemoteIno(MDCache *mdc, inodeno_t i, bool wx, vector& at, Context *c) : mdcache(mdc), ino(i), hadino(0), hadv(0), want_xlocked(wx), onfinish(c), anchortrace(at) {} void finish(int r) { assert(r == 0); if (r == 0) mdcache->open_remote_ino_2(ino, anchortrace, want_xlocked, hadino, hadv, onfinish); else { onfinish->complete(r); } } }; void MDCache::open_remote_ino(inodeno_t ino, Context *onfinish, bool want_xlocked, inodeno_t hadino, version_t hadv) { dout(7) << "open_remote_ino on " << ino << (want_xlocked ? " want_xlocked":"") << dendl; C_MDC_OpenRemoteIno *c = new C_MDC_OpenRemoteIno(this, ino, want_xlocked, hadino, hadv, onfinish); mds->anchorclient->lookup(ino, c->anchortrace, c); } void MDCache::open_remote_ino_2(inodeno_t ino, vector& anchortrace, bool want_xlocked, inodeno_t hadino, version_t hadv, Context *onfinish) { dout(7) << "open_remote_ino_2 on " << ino << ", trace depth is " << anchortrace.size() << dendl; // find deepest cached inode in prefix unsigned i = anchortrace.size(); // i := array index + 1 CInode *in = 0; while (1) { // inode? dout(10) << " " << i << ": " << anchortrace[i-1] << dendl; in = get_inode(anchortrace[i-1].ino); if (in) break; i--; if (!i) { in = get_inode(anchortrace[i].dirino); if (!in) { dout(0) << "open_remote_ino_2 don't have dir inode " << anchortrace[i].dirino << dendl; if (MDS_INO_IS_MDSDIR(anchortrace[i].dirino)) { open_foreign_mdsdir(anchortrace[i].dirino, onfinish); return; } assert(in); // hrm! } break; } } dout(10) << "deepest cached inode at " << i << " is " << *in << dendl; if (in->ino() == ino) { // success dout(10) << "open_remote_ino_2 have " << *in << dendl; onfinish->complete(0); return; } // open dirfrag beneath *in frag_t frag = in->dirfragtree[anchortrace[i].dn_hash]; if (!in->dirfragtree.contains(frag)) { dout(10) << "frag " << frag << " not valid, requerying anchortable" << dendl; open_remote_ino(ino, onfinish, want_xlocked); return; } CDir *dir = in->get_dirfrag(frag); if (!dir && !in->is_auth()) { dout(10) << "opening remote dirfrag " << frag << " under " << *in << dendl; /* we re-query the anchortable just to avoid a fragtree update race */ open_remote_dirfrag(in, frag, new C_MDC_RetryOpenRemoteIno(this, ino, onfinish, want_xlocked)); return; } if (!dir && in->is_auth()) { if (in->is_frozen_dir()) { dout(7) << "traverse: " << *in << " is frozen_dir, waiting" << dendl; in->parent->dir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDC_RetryOpenRemoteIno(this, ino, onfinish, want_xlocked)); return; } dir = in->get_or_open_dirfrag(this, frag); } assert(dir); if (dir->is_auth()) { if (dir->is_complete()) { // make sure we didn't get to the same version anchor 2x in a row if (hadv && hadino == anchortrace[i].ino && hadv == anchortrace[i].updated) { dout(10) << "expected ino " << anchortrace[i].ino << " in complete dir " << *dir << ", got same anchor " << anchortrace[i] << " 2x in a row" << dendl; onfinish->complete(-ENOENT); } else { // hrm. requery anchor table. dout(10) << "expected ino " << anchortrace[i].ino << " in complete dir " << *dir << ", requerying anchortable" << dendl; open_remote_ino(ino, onfinish, want_xlocked, anchortrace[i].ino, anchortrace[i].updated); } } else { dout(10) << "need ino " << anchortrace[i].ino << ", fetching incomplete dir " << *dir << dendl; dir->fetch(new C_MDC_OpenRemoteIno(this, ino, want_xlocked, anchortrace, onfinish)); } } else { // hmm, discover. dout(10) << "have remote dirfrag " << *dir << ", discovering " << anchortrace[i].ino << dendl; discover_ino(dir, anchortrace[i].ino, new C_MDC_RetryOpenRemoteIno(this, ino, onfinish, want_xlocked), (want_xlocked && i == anchortrace.size() - 1)); } } struct C_MDC_OpenRemoteDentry : public Context { MDCache *mdc; CDentry *dn; inodeno_t ino; Context *onfinish; bool want_xlocked; int mode; C_MDC_OpenRemoteDentry(MDCache *m, CDentry *d, inodeno_t i, Context *f, bool wx, int md) : mdc(m), dn(d), ino(i), onfinish(f), want_xlocked(wx), mode(md) {} void finish(int r) { mdc->_open_remote_dentry_finish(dn, ino, onfinish, want_xlocked, mode, r); } }; void MDCache::open_remote_dentry(CDentry *dn, bool projected, Context *fin, bool want_xlocked) { dout(10) << "open_remote_dentry " << *dn << dendl; CDentry::linkage_t *dnl = projected ? dn->get_projected_linkage() : dn->get_linkage(); inodeno_t ino = dnl->get_remote_ino(); int mode = g_conf->mds_open_remote_link_mode; Context *fin2 = new C_MDC_OpenRemoteDentry(this, dn, ino, fin, want_xlocked, mode); if (mode == 0) open_remote_ino(ino, fin2, want_xlocked); // anchor else open_ino(ino, -1, fin2, true, want_xlocked); // backtrace } void MDCache::_open_remote_dentry_finish(CDentry *dn, inodeno_t ino, Context *fin, bool want_xlocked, int mode, int r) { if (r < 0) { if (mode == 0) { dout(0) << "open_remote_dentry_finish bad remote dentry " << *dn << dendl; dn->state_set(CDentry::STATE_BADREMOTEINO); } else { dout(7) << "open_remote_dentry_finish failed to open ino " << ino << " for " << *dn << ", retry using anchortable" << dendl; assert(mode == 1); Context *fin2 = new C_MDC_OpenRemoteDentry(this, dn, ino, fin, want_xlocked, 0); open_remote_ino(ino, fin2, want_xlocked); return; } } fin->complete(r < 0 ? r : 0); } void MDCache::make_trace(vector& trace, CInode *in) { // empty trace if we're a base inode if (in->is_base()) return; CInode *parent = in->get_parent_inode(); assert(parent); make_trace(trace, parent); CDentry *dn = in->get_parent_dn(); dout(15) << "make_trace adding " << *dn << dendl; trace.push_back(dn); } // ------------------------------------------------------------------------------- // Open inode by inode number class C_MDC_OpenInoBacktraceFetched : public Context { MDCache *cache; inodeno_t ino; public: bufferlist bl; C_MDC_OpenInoBacktraceFetched(MDCache *c, inodeno_t i) : cache(c), ino(i) {} void finish(int r) { cache->_open_ino_backtrace_fetched(ino, bl, r); } }; struct C_MDC_OpenInoTraverseDir : public Context { MDCache *cache; inodeno_t ino; public: C_MDC_OpenInoTraverseDir(MDCache *c, inodeno_t i) : cache(c), ino(i) {} void finish(int r) { assert(cache->opening_inodes.count(ino)); cache->_open_ino_traverse_dir(ino, cache->opening_inodes[ino], r); } }; struct C_MDC_OpenInoParentOpened : public Context { MDCache *cache; inodeno_t ino; public: C_MDC_OpenInoParentOpened(MDCache *c, inodeno_t i) : cache(c), ino(i) {} void finish(int r) { cache->_open_ino_parent_opened(ino, r); } }; void MDCache::_open_ino_backtrace_fetched(inodeno_t ino, bufferlist& bl, int err) { dout(10) << "_open_ino_backtrace_fetched ino " << ino << " errno " << err << dendl; assert(opening_inodes.count(ino)); open_ino_info_t& info = opening_inodes[ino]; CInode *in = get_inode(ino); if (in) { dout(10) << " found cached " << *in << dendl; open_ino_finish(ino, info, in->authority().first); return; } inode_backtrace_t backtrace; if (err == 0) { ::decode(backtrace, bl); if (backtrace.pool != info.pool && backtrace.pool != -1) { dout(10) << " old object in pool " << info.pool << ", retrying pool " << backtrace.pool << dendl; info.pool = backtrace.pool; C_MDC_OpenInoBacktraceFetched *fin = new C_MDC_OpenInoBacktraceFetched(this, ino); fetch_backtrace(ino, info.pool, fin->bl, fin); return; } } else if (err == -ENOENT) { int64_t meta_pool = mds->mdsmap->get_metadata_pool(); if (info.pool != meta_pool) { dout(10) << " no object in pool " << info.pool << ", retrying pool " << meta_pool << dendl; info.pool = meta_pool; C_MDC_OpenInoBacktraceFetched *fin = new C_MDC_OpenInoBacktraceFetched(this, ino); fetch_backtrace(ino, info.pool, fin->bl, fin); return; } } if (err == 0) { if (backtrace.ancestors.empty()) { dout(10) << " got empty backtrace " << dendl; err = -EIO; } else if (!info.ancestors.empty()) { if (info.ancestors[0] == backtrace.ancestors[0]) { dout(10) << " got same parents " << info.ancestors[0] << " 2 times" << dendl; err = -EINVAL; } } } if (err) { dout(10) << " failed to open ino " << ino << dendl; open_ino_finish(ino, info, err); return; } dout(10) << " got backtrace " << backtrace << dendl; info.ancestors = backtrace.ancestors; _open_ino_traverse_dir(ino, info, 0); } void MDCache::_open_ino_parent_opened(inodeno_t ino, int ret) { dout(10) << "_open_ino_parent_opened ino " << ino << " ret " << ret << dendl; assert(opening_inodes.count(ino)); open_ino_info_t& info = opening_inodes[ino]; CInode *in = get_inode(ino); if (in) { dout(10) << " found cached " << *in << dendl; open_ino_finish(ino, info, in->authority().first); return; } if (ret == mds->get_nodeid()) { _open_ino_traverse_dir(ino, info, 0); } else { if (ret >= 0) { info.check_peers = true; info.auth_hint = ret; info.checked.erase(ret); } do_open_ino(ino, info, ret); } } Context* MDCache::_open_ino_get_waiter(inodeno_t ino, MMDSOpenIno *m) { if (m) return new C_MDS_RetryMessage(mds, m); else return new C_MDC_OpenInoTraverseDir(this, ino); } void MDCache::_open_ino_traverse_dir(inodeno_t ino, open_ino_info_t& info, int ret) { dout(10) << "_open_ino_trvserse_dir ino " << ino << " ret " << ret << dendl; CInode *in = get_inode(ino); if (in) { dout(10) << " found cached " << *in << dendl; open_ino_finish(ino, info, in->authority().first); return; } if (ret) { do_open_ino(ino, info, ret); return; } int hint = info.auth_hint; ret = open_ino_traverse_dir(ino, NULL, info.ancestors, info.discover, info.want_xlocked, &hint); if (ret > 0) return; if (hint != mds->get_nodeid()) info.auth_hint = hint; do_open_ino(ino, info, ret); } void MDCache::_open_ino_fetch_dir(inodeno_t ino, MMDSOpenIno *m, CDir *dir) { if (dir->state_test(CDir::STATE_REJOINUNDEF)) assert(dir->get_inode()->dirfragtree.is_leaf(dir->get_frag())); dir->fetch(_open_ino_get_waiter(ino, m)); } int MDCache::open_ino_traverse_dir(inodeno_t ino, MMDSOpenIno *m, vector& ancestors, bool discover, bool want_xlocked, int *hint) { dout(10) << "open_ino_traverse_dir ino " << ino << " " << ancestors << dendl; int err = 0; for (unsigned i = 0; i < ancestors.size(); i++) { CInode *diri = get_inode(ancestors[i].dirino); if (!diri) { if (discover && MDS_INO_IS_MDSDIR(ancestors[i].dirino)) { open_foreign_mdsdir(ancestors[i].dirino, _open_ino_get_waiter(ino, m)); return 1; } continue; } if (diri->state_test(CInode::STATE_REJOINUNDEF)) { CDir *dir = diri->get_parent_dir(); while (dir->state_test(CDir::STATE_REJOINUNDEF) && dir->get_inode()->state_test(CInode::STATE_REJOINUNDEF)) dir = dir->get_inode()->get_parent_dir(); _open_ino_fetch_dir(ino, m, dir); return 1; } if (!diri->is_dir()) { dout(10) << " " << *diri << " is not dir" << dendl; if (i == 0) err = -ENOTDIR; break; } string &name = ancestors[i].dname; frag_t fg = diri->pick_dirfrag(name); CDir *dir = diri->get_dirfrag(fg); if (!dir) { if (diri->is_auth()) { if (diri->is_frozen()) { dout(10) << " " << *diri << " is frozen, waiting " << dendl; diri->add_waiter(CDir::WAIT_UNFREEZE, _open_ino_get_waiter(ino, m)); return 1; } dir = diri->get_or_open_dirfrag(this, fg); } else if (discover) { open_remote_dirfrag(diri, fg, _open_ino_get_waiter(ino, m)); return 1; } } if (dir) { inodeno_t next_ino = i > 0 ? ancestors[i - 1].dirino : ino; CDentry *dn = dir->lookup(name); CDentry::linkage_t *dnl = dn ? dn->get_linkage() : NULL; if (dir->is_auth()) { if (dnl && dnl->is_primary() && dnl->get_inode()->state_test(CInode::STATE_REJOINUNDEF)) { dout(10) << " fetching undef " << *dnl->get_inode() << dendl; _open_ino_fetch_dir(ino, m, dir); return 1; } if (!dnl && !dir->is_complete() && (!dir->has_bloom() || dir->is_in_bloom(name))) { dout(10) << " fetching incomplete " << *dir << dendl; _open_ino_fetch_dir(ino, m, dir); return 1; } dout(10) << " no ino " << next_ino << " in " << *dir << dendl; if (i == 0) err = -ENOENT; } else if (discover) { if (!dnl) { filepath path(name, 0); discover_path(dir, CEPH_NOSNAP, path, _open_ino_get_waiter(ino, m), (i == 0 && want_xlocked)); return 1; } if (dnl->is_null() && !dn->lock.can_read(-1)) { dout(10) << " null " << *dn << " is not readable, waiting" << dendl; dn->lock.add_waiter(SimpleLock::WAIT_RD, _open_ino_get_waiter(ino, m)); return 1; } dout(10) << " no ino " << next_ino << " in " << *dir << dendl; if (i == 0) err = -ENOENT; } } if (hint && i == 0) *hint = dir ? dir->authority().first : diri->authority().first; break; } return err; } void MDCache::open_ino_finish(inodeno_t ino, open_ino_info_t& info, int ret) { dout(10) << "open_ino_finish ino " << ino << " ret " << ret << dendl; list waiters; waiters.swap(info.waiters); opening_inodes.erase(ino); finish_contexts(g_ceph_context, waiters, ret); } void MDCache::do_open_ino(inodeno_t ino, open_ino_info_t& info, int err) { if (err < 0) { info.checked.clear(); info.checked.insert(mds->get_nodeid()); info.checking = -1; info.check_peers = true; info.fetch_backtrace = true; if (info.discover) { info.discover = false; info.ancestors.clear(); } } if (info.check_peers) { info.check_peers = false; info.checking = -1; do_open_ino_peer(ino, info); } else if (info.fetch_backtrace) { info.check_peers = true; info.fetch_backtrace = false; info.checking = mds->get_nodeid(); info.checked.clear(); info.checked.insert(mds->get_nodeid()); C_MDC_OpenInoBacktraceFetched *fin = new C_MDC_OpenInoBacktraceFetched(this, ino); fetch_backtrace(ino, info.pool, fin->bl, fin); } else { assert(!info.ancestors.empty()); info.checking = mds->get_nodeid(); open_ino(info.ancestors[0].dirino, mds->mdsmap->get_metadata_pool(), new C_MDC_OpenInoParentOpened(this, ino), info.want_replica); } } void MDCache::do_open_ino_peer(inodeno_t ino, open_ino_info_t& info) { set all, active; mds->mdsmap->get_mds_set(all); mds->mdsmap->get_clientreplay_or_active_or_stopping_mds_set(active); if (mds->get_state() == MDSMap::STATE_REJOIN) mds->mdsmap->get_mds_set(active, MDSMap::STATE_REJOIN); dout(10) << "do_open_ino_peer " << ino << " active " << active << " all " << all << " checked " << info.checked << dendl; int peer = -1; if (info.auth_hint >= 0) { if (active.count(info.auth_hint)) { peer = info.auth_hint; info.auth_hint = -1; } } else { for (set::iterator p = active.begin(); p != active.end(); ++p) if (*p != mds->get_nodeid() && info.checked.count(*p) == 0) { peer = *p; break; } } if (peer < 0) { if (all.size() > active.size() && all != info.checked) { dout(10) << " waiting for more peers to be active" << dendl; } else { dout(10) << " all MDS peers have been checked " << dendl; do_open_ino(ino, info, 0); } } else { info.checking = peer; mds->send_message_mds(new MMDSOpenIno(info.tid, ino, info.ancestors), peer); } } void MDCache::handle_open_ino(MMDSOpenIno *m) { dout(10) << "handle_open_ino " << *m << dendl; inodeno_t ino = m->ino; MMDSOpenInoReply *reply; CInode *in = get_inode(ino); if (in) { dout(10) << " have " << *in << dendl; reply = new MMDSOpenInoReply(m->get_tid(), ino, 0); if (in->is_auth()) { touch_inode(in); while (1) { CDentry *pdn = in->get_parent_dn(); if (!pdn) break; CInode *diri = pdn->get_dir()->get_inode(); reply->ancestors.push_back(inode_backpointer_t(diri->ino(), pdn->name, in->inode.version)); in = diri; } } else { reply->hint = in->authority().first; } } else { int hint = -1; int ret = open_ino_traverse_dir(ino, m, m->ancestors, false, false, &hint); if (ret > 0) return; reply = new MMDSOpenInoReply(m->get_tid(), ino, hint, ret); } mds->messenger->send_message(reply, m->get_connection()); m->put(); } void MDCache::handle_open_ino_reply(MMDSOpenInoReply *m) { dout(10) << "handle_open_ino_reply " << *m << dendl; inodeno_t ino = m->ino; int from = m->get_source().num(); if (opening_inodes.count(ino)) { open_ino_info_t& info = opening_inodes[ino]; if (info.checking == from) info.checking = -1; info.checked.insert(from); CInode *in = get_inode(ino); if (in) { dout(10) << " found cached " << *in << dendl; open_ino_finish(ino, info, in->authority().first); } else if (!m->ancestors.empty()) { dout(10) << " found ino " << ino << " on mds." << from << dendl; if (!info.want_replica) { open_ino_finish(ino, info, from); return; } info.ancestors = m->ancestors; info.auth_hint = from; info.checking = mds->get_nodeid(); info.discover = true; _open_ino_traverse_dir(ino, info, 0); } else if (m->error) { dout(10) << " error " << m->error << " from mds." << from << dendl; do_open_ino(ino, info, m->error); } else { if (m->hint >= 0 && m->hint != mds->get_nodeid()) { info.auth_hint = m->hint; info.checked.erase(m->hint); } do_open_ino_peer(ino, info); } } m->put(); } void MDCache::kick_open_ino_peers(int who) { dout(10) << "kick_open_ino_peers mds." << who << dendl; for (map::iterator p = opening_inodes.begin(); p != opening_inodes.end(); ++p) { open_ino_info_t& info = p->second; if (info.checking == who) { dout(10) << " kicking ino " << p->first << " who was checking mds." << who << dendl; info.checking = -1; do_open_ino_peer(p->first, info); } else if (info.checking == -1) { dout(10) << " kicking ino " << p->first << " who was waiting" << dendl; do_open_ino_peer(p->first, info); } } } void MDCache::open_ino(inodeno_t ino, int64_t pool, Context* fin, bool want_replica, bool want_xlocked) { dout(10) << "open_ino " << ino << " pool " << pool << " want_replica " << want_replica << dendl; if (opening_inodes.count(ino)) { open_ino_info_t& info = opening_inodes[ino]; if (want_replica) { info.want_replica = true; if (want_xlocked && !info.want_xlocked) { if (!info.ancestors.empty()) { CInode *diri = get_inode(info.ancestors[0].dirino); if (diri) { frag_t fg = diri->pick_dirfrag(info.ancestors[0].dname); CDir *dir = diri->get_dirfrag(fg); if (dir && !dir->is_auth()) { filepath path(info.ancestors[0].dname, 0); discover_path(dir, CEPH_NOSNAP, path, NULL, true); } } } info.want_xlocked = true; } } info.waiters.push_back(fin); } else { open_ino_info_t& info = opening_inodes[ino]; info.checked.insert(mds->get_nodeid()); info.want_replica = want_replica; info.want_xlocked = want_xlocked; info.tid = ++open_ino_last_tid; info.pool = pool >= 0 ? pool : default_file_layout.fl_pg_pool; info.waiters.push_back(fin); do_open_ino(ino, info, 0); } } /* ---------------------------- */ /* * search for a given inode on MDS peers. optionally start with the given node. TODO - recover from mds node failure, recovery - traverse path */ void MDCache::find_ino_peers(inodeno_t ino, Context *c, int hint) { dout(5) << "find_ino_peers " << ino << " hint " << hint << dendl; assert(!have_inode(ino)); ceph_tid_t tid = ++find_ino_peer_last_tid; find_ino_peer_info_t& fip = find_ino_peer[tid]; fip.ino = ino; fip.tid = tid; fip.fin = c; fip.hint = hint; fip.checked.insert(mds->whoami); _do_find_ino_peer(fip); } void MDCache::_do_find_ino_peer(find_ino_peer_info_t& fip) { set all, active; mds->mdsmap->get_mds_set(all); mds->mdsmap->get_clientreplay_or_active_or_stopping_mds_set(active); dout(10) << "_do_find_ino_peer " << fip.tid << " " << fip.ino << " active " << active << " all " << all << " checked " << fip.checked << dendl; int m = -1; if (fip.hint >= 0) { m = fip.hint; fip.hint = -1; } else { for (set::iterator p = active.begin(); p != active.end(); ++p) if (*p != mds->whoami && fip.checked.count(*p) == 0) { m = *p; break; } } if (m < 0) { if (all.size() > active.size()) { dout(10) << "_do_find_ino_peer waiting for more peers to be active" << dendl; } else { dout(10) << "_do_find_ino_peer failed on " << fip.ino << dendl; fip.fin->complete(-ESTALE); find_ino_peer.erase(fip.tid); } } else { fip.checking = m; mds->send_message_mds(new MMDSFindIno(fip.tid, fip.ino), m); } } void MDCache::handle_find_ino(MMDSFindIno *m) { dout(10) << "handle_find_ino " << *m << dendl; MMDSFindInoReply *r = new MMDSFindInoReply(m->tid); CInode *in = get_inode(m->ino); if (in) { in->make_path(r->path); dout(10) << " have " << r->path << " " << *in << dendl; } mds->messenger->send_message(r, m->get_connection()); m->put(); } void MDCache::handle_find_ino_reply(MMDSFindInoReply *m) { map::iterator p = find_ino_peer.find(m->tid); if (p != find_ino_peer.end()) { dout(10) << "handle_find_ino_reply " << *m << dendl; find_ino_peer_info_t& fip = p->second; // success? if (get_inode(fip.ino)) { dout(10) << "handle_find_ino_reply successfully found " << fip.ino << dendl; mds->queue_waiter(fip.fin); find_ino_peer.erase(p); m->put(); return; } int from = m->get_source().num(); if (fip.checking == from) fip.checking = -1; fip.checked.insert(from); if (!m->path.empty()) { // we got a path! vector trace; MDRequestRef null_ref; int r = path_traverse(null_ref, m, NULL, m->path, &trace, NULL, MDS_TRAVERSE_DISCOVER); if (r > 0) return; dout(0) << "handle_find_ino_reply failed with " << r << " on " << m->path << ", retrying" << dendl; fip.checked.clear(); _do_find_ino_peer(fip); } else { // nope, continue. _do_find_ino_peer(fip); } } else { dout(10) << "handle_find_ino_reply tid " << m->tid << " dne" << dendl; } m->put(); } void MDCache::kick_find_ino_peers(int who) { // find_ino_peers requests we should move on from for (map::iterator p = find_ino_peer.begin(); p != find_ino_peer.end(); ++p) { find_ino_peer_info_t& fip = p->second; if (fip.checking == who) { dout(10) << "kicking find_ino_peer " << fip.tid << " who was checking mds." << who << dendl; fip.checking = -1; _do_find_ino_peer(fip); } else if (fip.checking == -1) { dout(10) << "kicking find_ino_peer " << fip.tid << " who was waiting" << dendl; _do_find_ino_peer(fip); } } } /* ---------------------------- */ int MDCache::get_num_client_requests() { int count = 0; for (ceph::unordered_map::iterator p = active_requests.begin(); p != active_requests.end(); ++p) { MDRequestRef& mdr = p->second; if (mdr->reqid.name.is_client() && !mdr->is_slave()) count++; } return count; } /* This function takes over the reference to the passed Message */ MDRequestRef MDCache::request_start(MClientRequest *req) { // did we win a forward race against a slave? if (active_requests.count(req->get_reqid())) { MDRequestRef& mdr = active_requests[req->get_reqid()]; assert(mdr); if (mdr->is_slave()) { dout(10) << "request_start already had " << *mdr << ", waiting for finish" << dendl; mdr->more()->waiting_for_finish.push_back(new C_MDS_RetryMessage(mds, req)); } else { dout(10) << "request_start already processing " << *mdr << ", dropping new msg" << dendl; req->put(); } return MDRequestRef(); } // register new client request MDRequestRef mdr(new MDRequestImpl(req->get_reqid(), req->get_num_fwd(), req)); active_requests[req->get_reqid()] = mdr; dout(7) << "request_start " << *mdr << dendl; return mdr; } MDRequestRef MDCache::request_start_slave(metareqid_t ri, __u32 attempt, int by) { MDRequestRef mdr(new MDRequestImpl(ri, attempt, by)); assert(active_requests.count(mdr->reqid) == 0); active_requests[mdr->reqid] = mdr; dout(7) << "request_start_slave " << *mdr << " by mds." << by << dendl; return mdr; } MDRequestRef MDCache::request_start_internal(int op) { MDRequestRef mdr(new MDRequestImpl); mdr->reqid.name = entity_name_t::MDS(mds->get_nodeid()); mdr->reqid.tid = mds->issue_tid(); mdr->internal_op = op; assert(active_requests.count(mdr->reqid) == 0); active_requests[mdr->reqid] = mdr; dout(7) << "request_start_internal " << *mdr << " op " << op << dendl; return mdr; } MDRequestRef MDCache::request_get(metareqid_t rid) { ceph::unordered_map::iterator p = active_requests.find(rid); assert(p != active_requests.end()); dout(7) << "request_get " << rid << " " << *p->second << dendl; return p->second; } void MDCache::request_finish(MDRequestRef& mdr) { dout(7) << "request_finish " << *mdr << dendl; // slave finisher? if (mdr->has_more() && mdr->more()->slave_commit) { Context *fin = mdr->more()->slave_commit; mdr->more()->slave_commit = 0; fin->complete(mdr->aborted ? -1 : 0); // this must re-call request_finish. return; } request_cleanup(mdr); } void MDCache::request_forward(MDRequestRef& mdr, int who, int port) { if (mdr->client_request->get_source().is_client()) { dout(7) << "request_forward " << *mdr << " to mds." << who << " req " << *mdr->client_request << dendl; mds->forward_message_mds(mdr->client_request, who); mdr->client_request = 0; if (mds->logger) mds->logger->inc(l_mds_fw); } else { dout(7) << "request_forward drop " << *mdr << " req " << *mdr->client_request << " was from mds" << dendl; } request_cleanup(mdr); } void MDCache::dispatch_request(MDRequestRef& mdr) { if (mdr->killed) { dout(10) << "request " << *mdr << " was killed" << dendl; return; } if (mdr->client_request) { mds->server->dispatch_client_request(mdr); } else if (mdr->slave_request) { mds->server->dispatch_slave_request(mdr); } else { switch (mdr->internal_op) { case CEPH_MDS_OP_FRAGMENTDIR: dispatch_fragment_dir(mdr); break; case CEPH_MDS_OP_EXPORTDIR: migrator->dispatch_export_dir(mdr); break; default: assert(0); } } } void MDCache::request_drop_foreign_locks(MDRequestRef& mdr) { if (!mdr->has_more()) return; // clean up slaves // (will implicitly drop remote dn pins) for (set::iterator p = mdr->more()->slaves.begin(); p != mdr->more()->slaves.end(); ++p) { MMDSSlaveRequest *r = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_FINISH); // information about rename imported caps if (mdr->more()->srcdn_auth_mds == *p && mdr->more()->inode_import.length() > 0) r->inode_export.claim(mdr->more()->inode_import); mds->send_message_mds(r, *p); } /* strip foreign xlocks out of lock lists, since the OP_FINISH drops them * implicitly. Note that we don't call the finishers -- there shouldn't * be any on a remote lock and the request finish wakes up all * the waiters anyway! */ set::iterator p = mdr->xlocks.begin(); while (p != mdr->xlocks.end()) { if ((*p)->get_parent()->is_auth()) ++p; else { dout(10) << "request_drop_foreign_locks forgetting lock " << **p << " on " << *(*p)->get_parent() << dendl; (*p)->put_xlock(); mdr->locks.erase(*p); mdr->xlocks.erase(p++); } } map::iterator q = mdr->remote_wrlocks.begin(); while (q != mdr->remote_wrlocks.end()) { dout(10) << "request_drop_foreign_locks forgetting remote_wrlock " << *q->first << " on mds." << q->second << " on " << *(q->first)->get_parent() << dendl; mdr->locks.erase(q->first); mdr->remote_wrlocks.erase(q++); } mdr->more()->slaves.clear(); /* we no longer have requests out to them, and * leaving them in can cause double-notifies as * this function can get called more than once */ } void MDCache::request_drop_non_rdlocks(MDRequestRef& mdr) { request_drop_foreign_locks(mdr); mds->locker->drop_non_rdlocks(mdr.get()); } void MDCache::request_drop_locks(MDRequestRef& mdr) { request_drop_foreign_locks(mdr); mds->locker->drop_locks(mdr.get()); } void MDCache::request_cleanup(MDRequestRef& mdr) { dout(15) << "request_cleanup " << *mdr << dendl; if (mdr->has_more()) { if (mdr->more()->is_ambiguous_auth) mdr->clear_ambiguous_auth(); if (!mdr->more()->waiting_for_finish.empty()) mds->queue_waiters(mdr->more()->waiting_for_finish); } request_drop_locks(mdr); // drop (local) auth pins mdr->drop_local_auth_pins(); // drop stickydirs for (set::iterator p = mdr->stickydirs.begin(); p != mdr->stickydirs.end(); ++p) (*p)->put_stickydirs(); mds->locker->kick_cap_releases(mdr); // drop cache pins mdr->drop_pins(); // remove from session mdr->item_session_request.remove_myself(); bool was_replay = mdr->client_request && mdr->client_request->is_replay(); // remove from map active_requests.erase(mdr->reqid); // fail-safe! if (was_replay && active_requests.empty()) { dout(10) << " fail-safe queueing next replay op" << dendl; mds->queue_one_replay(); } if (mds->logger) log_stat(); } void MDCache::request_kill(MDRequestRef& mdr) { mdr->killed = true; if (!mdr->committing) { dout(10) << "request_kill " << *mdr << dendl; request_cleanup(mdr); } else { dout(10) << "request_kill " << *mdr << " -- already committing, no-op" << dendl; } } // -------------------------------------------------------------------- // ANCHORS class C_MDC_AnchorPrepared : public Context { MDCache *cache; CInode *in; bool add; public: version_t atid; C_MDC_AnchorPrepared(MDCache *c, CInode *i, bool a) : cache(c), in(i), add(a), atid(0) {} void finish(int r) { cache->_anchor_prepared(in, atid, add); } }; void MDCache::anchor_create_prep_locks(MDRequestRef& mdr, CInode *in, set& rdlocks, set& xlocks) { dout(10) << "anchor_create_prep_locks " << *in << dendl; if (in->is_anchored()) { // caller may have already xlocked it.. if so, that will suffice! if (xlocks.count(&in->linklock) == 0) rdlocks.insert(&in->linklock); } else { xlocks.insert(&in->linklock); // path components too! CDentry *dn = in->get_projected_parent_dn(); while (dn) { rdlocks.insert(&dn->lock); dn = dn->get_dir()->get_inode()->get_parent_dn(); } } } void MDCache::anchor_create(MDRequestRef& mdr, CInode *in, Context *onfinish) { assert(in->is_auth()); dout(10) << "anchor_create " << *in << dendl; // auth pin if (!in->can_auth_pin() && !mdr->is_auth_pinned(in)) { dout(7) << "anchor_create not authpinnable, waiting on " << *in << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, onfinish); return; } // wait in->add_waiter(CInode::WAIT_ANCHORED, onfinish); // already anchoring? if (in->state_test(CInode::STATE_ANCHORING)) { dout(7) << "anchor_create already anchoring " << *in << dendl; return; } dout(7) << "anchor_create " << *in << dendl; // auth: do it in->state_set(CInode::STATE_ANCHORING); in->get(CInode::PIN_ANCHORING); in->auth_pin(this); // make trace vector trace; in->make_anchor_trace(trace); if (trace.empty()) { assert(MDS_INO_IS_BASE(in->ino())); trace.push_back(Anchor(in->ino(), in->ino(), 0, 0, 0)); } // do it C_MDC_AnchorPrepared *fin = new C_MDC_AnchorPrepared(this, in, true); mds->anchorclient->prepare_create(in->ino(), trace, &fin->atid, fin); } void MDCache::anchor_destroy(CInode *in, Context *onfinish) { assert(in->is_auth()); // auth pin if (!in->can_auth_pin()/* && !mdr->is_auth_pinned(in)*/) { dout(7) << "anchor_destroy not authpinnable, waiting on " << *in << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, onfinish); return; } dout(7) << "anchor_destroy " << *in << dendl; // wait if (onfinish) in->add_waiter(CInode::WAIT_UNANCHORED, onfinish); // already anchoring? if (in->state_test(CInode::STATE_UNANCHORING)) { dout(7) << "anchor_destroy already unanchoring " << *in << dendl; return; } // auth: do it in->state_set(CInode::STATE_UNANCHORING); in->get(CInode::PIN_UNANCHORING); in->auth_pin(this); // do it C_MDC_AnchorPrepared *fin = new C_MDC_AnchorPrepared(this, in, false); mds->anchorclient->prepare_destroy(in->ino(), &fin->atid, fin); } class C_MDC_AnchorLogged : public Context { MDCache *cache; CInode *in; version_t atid; MutationRef mut; public: C_MDC_AnchorLogged(MDCache *c, CInode *i, version_t t, MutationRef& m) : cache(c), in(i), atid(t), mut(m) {} void finish(int r) { cache->_anchor_logged(in, atid, mut); } }; void MDCache::_anchor_prepared(CInode *in, version_t atid, bool add) { dout(10) << "_anchor_prepared " << *in << " atid " << atid << " " << (add ? "create":"destroy") << dendl; assert(in->inode.anchored == !add); // update the logged inode copy inode_t *pi = in->project_inode(); if (add) { pi->anchored = true; pi->rstat.ranchors++; } else { pi->anchored = false; pi->rstat.ranchors--; } pi->version = in->pre_dirty(); MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); EUpdate *le = new EUpdate(mds->mdlog, add ? "anchor_create":"anchor_destroy"); mds->mdlog->start_entry(le); predirty_journal_parents(mut, &le->metablob, in, 0, PREDIRTY_PRIMARY); journal_dirty_inode(mut.get(), &le->metablob, in); le->metablob.add_table_transaction(TABLE_ANCHOR, atid); mds->mdlog->submit_entry(le, new C_MDC_AnchorLogged(this, in, atid, mut)); mds->mdlog->flush(); } void MDCache::_anchor_logged(CInode *in, version_t atid, MutationRef& mut) { dout(10) << "_anchor_logged on " << *in << dendl; // unpin if (in->state_test(CInode::STATE_ANCHORING)) { in->state_clear(CInode::STATE_ANCHORING); in->put(CInode::PIN_ANCHORING); if (in->parent) in->parent->adjust_nested_anchors(1); } else if (in->state_test(CInode::STATE_UNANCHORING)) { in->state_clear(CInode::STATE_UNANCHORING); in->put(CInode::PIN_UNANCHORING); if (in->parent) in->parent->adjust_nested_anchors(-1); } in->auth_unpin(this); // apply update to cache in->pop_and_dirty_projected_inode(mut->ls); mut->apply(); // tell the anchortable we've committed mds->anchorclient->commit(atid, mut->ls); // drop locks and finish mds->locker->drop_locks(mut.get()); mut->cleanup(); // trigger waiters in->finish_waiting(CInode::WAIT_ANCHORED|CInode::WAIT_UNANCHORED, 0); } // ------------------------------------------------------------------------------- // SNAPREALMS struct C_MDC_snaprealm_create_finish : public Context { MDCache *cache; MDRequestRef mdr; MutationRef mut; CInode *in; C_MDC_snaprealm_create_finish(MDCache *c, MDRequestRef& m, MutationRef& mu, CInode *i) : cache(c), mdr(m), mut(mu), in(i) {} void finish(int r) { cache->_snaprealm_create_finish(mdr, mut, in); } }; void MDCache::snaprealm_create(MDRequestRef& mdr, CInode *in) { dout(10) << "snaprealm_create " << *in << dendl; assert(!in->snaprealm); if (!in->inode.anchored) { mds->mdcache->anchor_create(mdr, in, new C_MDS_RetryRequest(mds->mdcache, mdr)); return; } // allocate an id.. if (!mdr->more()->stid) { mds->snapclient->prepare_create_realm(in->ino(), &mdr->more()->stid, &mdr->more()->snapidbl, new C_MDS_RetryRequest(this, mdr)); return; } MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); EUpdate *le = new EUpdate(mds->mdlog, "snaprealm_create"); mds->mdlog->start_entry(le); le->metablob.add_table_transaction(TABLE_SNAP, mdr->more()->stid); inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); pi->rstat.rsnaprealms++; bufferlist::iterator p = mdr->more()->snapidbl.begin(); snapid_t seq; ::decode(seq, p); sr_t *newsnap = in->project_snaprealm(seq); newsnap->seq = seq; newsnap->last_created = seq; predirty_journal_parents(mut, &le->metablob, in, 0, PREDIRTY_PRIMARY); journal_cow_inode(mut, &le->metablob, in); le->metablob.add_primary_dentry(in->get_projected_parent_dn(), in, true); mds->mdlog->submit_entry(le, new C_MDC_snaprealm_create_finish(this, mdr, mut, in)); mds->mdlog->flush(); } void MDCache::do_realm_invalidate_and_update_notify(CInode *in, int snapop, bool nosend) { dout(10) << "do_realm_invalidate_and_update_notify " << *in->snaprealm << " " << *in << dendl; vector split_inos; vector split_realms; if (snapop == CEPH_SNAP_OP_SPLIT) { // notify clients of update|split for (elist::iterator p = in->snaprealm->inodes_with_caps.begin(member_offset(CInode, item_caps)); !p.end(); ++p) split_inos.push_back((*p)->ino()); for (set::iterator p = in->snaprealm->open_children.begin(); p != in->snaprealm->open_children.end(); ++p) split_realms.push_back((*p)->inode->ino()); } bufferlist snapbl; in->snaprealm->build_snap_trace(snapbl); map updates; list q; q.push_back(in->snaprealm); while (!q.empty()) { SnapRealm *realm = q.front(); q.pop_front(); dout(10) << " realm " << *realm << " on " << *realm->inode << dendl; realm->invalidate_cached_snaps(); for (map* >::iterator p = realm->client_caps.begin(); p != realm->client_caps.end(); ++p) { assert(!p->second->empty()); if (!nosend && updates.count(p->first) == 0) { MClientSnap *update = new MClientSnap(snapop); update->head.split = in->ino(); update->split_inos = split_inos; update->split_realms = split_realms; update->bl = snapbl; updates[p->first] = update; } } // notify for active children, too. dout(10) << " " << realm << " open_children are " << realm->open_children << dendl; for (set::iterator p = realm->open_children.begin(); p != realm->open_children.end(); ++p) q.push_back(*p); } if (!nosend) send_snaps(updates); } void MDCache::_snaprealm_create_finish(MDRequestRef& mdr, MutationRef& mut, CInode *in) { dout(10) << "_snaprealm_create_finish " << *in << dendl; // apply in->pop_and_dirty_projected_inode(mut->ls); mut->apply(); mds->locker->drop_locks(mut.get()); mut->cleanup(); // tell table we've committed mds->snapclient->commit(mdr->more()->stid, mut->ls); // create bufferlist::iterator p = mdr->more()->snapidbl.begin(); snapid_t seq; ::decode(seq, p); in->open_snaprealm(); in->snaprealm->open = true; in->snaprealm->srnode.seq = seq; in->snaprealm->srnode.created = seq; in->snaprealm->srnode.current_parent_since = seq; do_realm_invalidate_and_update_notify(in, CEPH_SNAP_OP_SPLIT); /* static int count = 5; if (--count == 0) assert(0); // hack test test ********** */ // done. mdr->more()->stid = 0; // caller will likely need to reuse this dispatch_request(mdr); } // ------------------------------------------------------------------------------- // STRAYS struct C_MDC_RetryScanStray : public Context { MDCache *cache; dirfrag_t next; C_MDC_RetryScanStray(MDCache *c, dirfrag_t n) : cache(c), next(n) { } void finish(int r) { cache->scan_stray_dir(next); } }; void MDCache::scan_stray_dir(dirfrag_t next) { dout(10) << "scan_stray_dir " << next << dendl; list ls; for (int i = 0; i < NUM_STRAY; ++i) { if (strays[i]->ino() < next.ino) continue; strays[i]->get_dirfrags(ls); } for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; if (dir->dirfrag() < next) continue; if (!dir->is_complete()) { dir->fetch(new C_MDC_RetryScanStray(this, dir->dirfrag())); return; } for (CDir::map_t::iterator q = dir->items.begin(); q != dir->items.end(); ++q) { CDentry *dn = q->second; CDentry::linkage_t *dnl = dn->get_projected_linkage(); if (dnl->is_primary()) maybe_eval_stray(dnl->get_inode()); } } } struct C_MDC_EvalStray : public Context { MDCache *mdcache; CDentry *dn; C_MDC_EvalStray(MDCache *c, CDentry *d) : mdcache(c), dn(d) {} void finish(int r) { mdcache->eval_stray(dn); } }; void MDCache::eval_stray(CDentry *dn, bool delay) { dout(10) << "eval_stray " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_projected_linkage(); dout(10) << " inode is " << *dnl->get_inode() << dendl; assert(dnl->is_primary()); CInode *in = dnl->get_inode(); assert(in); assert(dn->get_dir()->get_inode()->is_stray()); if (!dn->is_auth()) { // has to be mine // move to bottom of lru so that we trim quickly! touch_dentry_bottom(dn); return; } // purge? if (in->inode.nlink == 0) { if (in->is_dir()) { // past snaprealm parents imply snapped dentry remote links. // only important for directories. normal file data snaps are handled // by the object store. if (in->snaprealm && in->snaprealm->has_past_parents()) { if (!in->snaprealm->have_past_parents_open() && !in->snaprealm->open_parents(new C_MDC_EvalStray(this, dn))) return; in->snaprealm->prune_past_parents(); if (in->snaprealm->has_past_parents()) { dout(20) << " has past parents " << in->snaprealm->srnode.past_parents << dendl; return; // not until some snaps are deleted. } } } if (dn->is_replicated()) { dout(20) << " replicated" << dendl; return; } if (dn->is_any_leases() || in->is_any_caps()) { dout(20) << " caps | leases" << dendl; return; // wait } if (!in->dirfrags.empty()) { dout(20) << " open dirfrags" << dendl; return; // wait for dirs to close/trim } if (dn->state_test(CDentry::STATE_PURGING)) { dout(20) << " already purging" << dendl; return; // already purging } if (in->state_test(CInode::STATE_NEEDSRECOVER) || in->state_test(CInode::STATE_RECOVERING)) { dout(20) << " pending recovery" << dendl; return; // don't mess with file size probing } if (in->get_num_ref() > (int)in->is_dirty() + (int)in->is_dirty_parent()) { dout(20) << " too many inode refs" << dendl; return; } if (dn->get_num_ref() > (int)dn->is_dirty() + !!in->get_num_ref()) { dout(20) << " too many dn refs" << dendl; return; } if (delay) { if (!dn->item_stray.is_on_list()) delayed_eval_stray.push_back(&dn->item_stray); } else purge_stray(dn); } else if (in->inode.nlink >= 1) { // trivial reintegrate? if (!in->remote_parents.empty()) { CDentry *rlink = *in->remote_parents.begin(); // don't do anything if the remote parent is projected, or we may // break user-visible semantics! // NOTE: we repeat this check in _rename(), since our submission path is racey. if (!rlink->is_projected()) { if (rlink->is_auth() && rlink->dir->can_auth_pin()) reintegrate_stray(dn, rlink); if (!rlink->is_auth() && dn->is_auth()) migrate_stray(dn, rlink->authority().first); } } } else { // wait for next use. } } void MDCache::eval_remote(CDentry *dn) { dout(10) << "eval_remote " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_projected_linkage(); assert(dnl->is_remote()); CInode *in = dnl->get_inode(); if (!in) return; // refers to stray? if (in->get_parent_dn()->get_dir()->get_inode()->is_stray()) { if (in->is_auth()) eval_stray(in->get_parent_dn()); else migrate_stray(in->get_parent_dn(), mds->get_nodeid()); } } void MDCache::fetch_backtrace(inodeno_t ino, int64_t pool, bufferlist& bl, Context *fin) { object_t oid = CInode::get_object_name(ino, frag_t(), ""); mds->objecter->getxattr(oid, object_locator_t(pool), "parent", CEPH_NOSNAP, &bl, 0, fin); } class C_MDC_PurgeStrayPurged : public Context { MDCache *cache; CDentry *dn; public: C_MDC_PurgeStrayPurged(MDCache *c, CDentry *d) : cache(c), dn(d) { } void finish(int r) { assert(r == 0 || r == -ENOENT); cache->_purge_stray_purged(dn, r); } }; void MDCache::purge_stray(CDentry *dn) { CDentry::linkage_t *dnl = dn->get_projected_linkage(); CInode *in = dnl->get_inode(); dout(10) << "purge_stray " << *dn << " " << *in << dendl; assert(!dn->is_replicated()); // anchored? if (in->inode.anchored) { anchor_destroy(in, new C_MDC_EvalStray(this, dn)); return; } dn->state_set(CDentry::STATE_PURGING); dn->get(CDentry::PIN_PURGING); in->state_set(CInode::STATE_PURGING); if (dn->item_stray.is_on_list()) dn->item_stray.remove_myself(); if (in->is_dirty_parent()) in->clear_dirty_parent(); // CHEAT. there's no real need to journal our intent to purge, since // that is implicit in the dentry's presence and non-use in the stray // dir. on recovery, we'll need to re-eval all strays anyway. SnapContext nullsnapc; C_GatherBuilder gather(g_ceph_context, new C_MDC_PurgeStrayPurged(this, dn)); if (in->is_dir()) { object_locator_t oloc(mds->mdsmap->get_metadata_pool()); list ls; if (!in->dirfragtree.is_leaf(frag_t())) in->dirfragtree.get_leaves(ls); ls.push_back(frag_t()); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { object_t oid = CInode::get_object_name(in->inode.ino, *p, ""); dout(10) << "purge_stray remove dirfrag " << oid << dendl; mds->objecter->remove(oid, oloc, nullsnapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); } assert(gather.has_subs()); gather.activate(); return; } const SnapContext *snapc; SnapRealm *realm = in->find_snaprealm(); if (realm) { dout(10) << " realm " << *realm << dendl; snapc = &realm->get_snap_context(); } else { dout(10) << " NO realm, using null context" << dendl; snapc = &nullsnapc; assert(in->last == CEPH_NOSNAP); } if (in->is_file()) { uint64_t period = (uint64_t)in->inode.layout.fl_object_size * (uint64_t)in->inode.layout.fl_stripe_count; uint64_t to = in->inode.get_max_size(); to = MAX(in->inode.size, to); // when truncating a file, the filer does not delete stripe objects that are // truncated to zero. so we need to purge stripe objects up to the max size // the file has ever been. to = MAX(in->inode.max_size_ever, to); if (to && period) { uint64_t num = (to + period - 1) / period; dout(10) << "purge_stray 0~" << to << " objects 0~" << num << " snapc " << snapc << " on " << *in << dendl; mds->filer->purge_range(in->inode.ino, &in->inode.layout, *snapc, 0, num, ceph_clock_now(g_ceph_context), 0, gather.new_sub()); } } inode_t *pi = in->get_projected_inode(); object_t oid = CInode::get_object_name(pi->ino, frag_t(), ""); // remove the backtrace object if it was not purged if (!gather.has_subs()) { object_locator_t oloc(pi->layout.fl_pg_pool); dout(10) << "purge_stray remove backtrace object " << oid << " pool " << oloc.pool << " snapc " << snapc << dendl; mds->objecter->remove(oid, oloc, *snapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); } // remove old backtrace objects for (vector::iterator p = pi->old_pools.begin(); p != pi->old_pools.end(); ++p) { object_locator_t oloc(*p); dout(10) << "purge_stray remove backtrace object " << oid << " old pool " << *p << " snapc " << snapc << dendl; mds->objecter->remove(oid, oloc, *snapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); } assert(gather.has_subs()); gather.activate(); } class C_MDC_PurgeStrayLogged : public Context { MDCache *cache; CDentry *dn; version_t pdv; LogSegment *ls; public: C_MDC_PurgeStrayLogged(MDCache *c, CDentry *d, version_t v, LogSegment *s) : cache(c), dn(d), pdv(v), ls(s) { } void finish(int r) { cache->_purge_stray_logged(dn, pdv, ls); } }; class C_MDC_PurgeStrayLoggedTruncate : public Context { MDCache *cache; CDentry *dn; LogSegment *ls; public: C_MDC_PurgeStrayLoggedTruncate(MDCache *c, CDentry *d, LogSegment *s) : cache(c), dn(d), ls(s) { } void finish(int r) { cache->_purge_stray_logged_truncate(dn, ls); } }; void MDCache::_purge_stray_purged(CDentry *dn, int r) { assert (r == 0 || r == -ENOENT); CInode *in = dn->get_projected_linkage()->get_inode(); dout(10) << "_purge_stray_purged " << *dn << " " << *in << dendl; if (in->get_num_ref() == (int)in->is_dirty() && dn->get_num_ref() == (int)dn->is_dirty() + !!in->get_num_ref() + 1/*PIN_PURGING*/) { // kill dentry. version_t pdv = dn->pre_dirty(); dn->push_projected_linkage(); // NULL EUpdate *le = new EUpdate(mds->mdlog, "purge_stray"); mds->mdlog->start_entry(le); // update dirfrag fragstat, rstat CDir *dir = dn->get_dir(); fnode_t *pf = dir->project_fnode(); pf->version = dir->pre_dirty(); if (in->is_dir()) pf->fragstat.nsubdirs--; else pf->fragstat.nfiles--; pf->rstat.sub(in->inode.accounted_rstat); le->metablob.add_dir_context(dn->dir); EMetaBlob::dirlump& dl = le->metablob.add_dir(dn->dir, true); le->metablob.add_null_dentry(dl, dn, true); le->metablob.add_destroyed_inode(in->ino()); mds->mdlog->submit_entry(le, new C_MDC_PurgeStrayLogged(this, dn, pdv, mds->mdlog->get_current_segment())); } else { // new refs.. just truncate to 0 EUpdate *le = new EUpdate(mds->mdlog, "purge_stray truncate"); mds->mdlog->start_entry(le); inode_t *pi = in->project_inode(); pi->size = 0; pi->client_ranges.clear(); pi->truncate_size = 0; pi->truncate_from = 0; pi->version = in->pre_dirty(); le->metablob.add_dir_context(dn->dir); le->metablob.add_primary_dentry(dn, in, true); mds->mdlog->submit_entry(le, new C_MDC_PurgeStrayLoggedTruncate(this, dn, mds->mdlog->get_current_segment())); } } void MDCache::_purge_stray_logged(CDentry *dn, version_t pdv, LogSegment *ls) { CInode *in = dn->get_linkage()->get_inode(); dout(10) << "_purge_stray_logged " << *dn << " " << *in << dendl; assert(!in->state_test(CInode::STATE_RECOVERING)); // unlink assert(dn->get_projected_linkage()->is_null()); dn->dir->unlink_inode(dn); dn->pop_projected_linkage(); dn->mark_dirty(pdv, ls); dn->dir->pop_and_dirty_projected_fnode(ls); in->state_clear(CInode::STATE_ORPHAN); dn->state_clear(CDentry::STATE_PURGING); dn->put(CDentry::PIN_PURGING); // drop inode if (in->is_dirty()) in->mark_clean(); remove_inode(in); // drop dentry? if (dn->is_new()) { dout(20) << " dn is new, removing" << dendl; dn->mark_clean(); dn->dir->remove_dentry(dn); } else touch_dentry_bottom(dn); // drop dn as quickly as possible. } void MDCache::_purge_stray_logged_truncate(CDentry *dn, LogSegment *ls) { CInode *in = dn->get_projected_linkage()->get_inode(); dout(10) << "_purge_stray_logged_truncate " << *dn << " " << *in << dendl; dn->state_clear(CDentry::STATE_PURGING); dn->put(CDentry::PIN_PURGING); in->pop_and_dirty_projected_inode(ls); eval_stray(dn); } void MDCache::reintegrate_stray(CDentry *straydn, CDentry *rdn) { dout(10) << "reintegrate_stray " << *straydn << " into " << *rdn << dendl; // rename it to another mds. filepath src; straydn->make_path(src); filepath dst; rdn->make_path(dst); MClientRequest *req = new MClientRequest(CEPH_MDS_OP_RENAME); req->set_filepath(dst); req->set_filepath2(src); req->set_tid(mds->issue_tid()); mds->send_message_mds(req, rdn->authority().first); } void MDCache::migrate_stray(CDentry *dn, int to) { CInode *in = dn->get_linkage()->get_inode(); assert(in); CInode *diri = dn->dir->get_inode(); assert(diri->is_stray()); dout(10) << "migrate_stray from mds." << MDS_INO_STRAY_OWNER(diri->inode.ino) << " to mds." << to << " " << *dn << " " << *in << dendl; // rename it to another mds. filepath src; dn->make_path(src); string dname; in->name_stray_dentry(dname); filepath dst(dname, MDS_INO_STRAY(to, 0)); MClientRequest *req = new MClientRequest(CEPH_MDS_OP_RENAME); req->set_filepath(dst); req->set_filepath2(src); req->set_tid(mds->issue_tid()); mds->send_message_mds(req, to); } // ======================================================================================== // DISCOVER /* - for all discovers (except base_inos, e.g. root, stray), waiters are attached to the parent metadata object in the cache (pinning it). - all discovers are tracked by tid, so that we can ignore potentially dup replies. */ void MDCache::_send_discover(discover_info_t& d) { MDiscover *dis = new MDiscover(d.ino, d.frag, d.snap, d.want_path, d.want_ino, d.want_base_dir, d.want_xlocked); dis->set_tid(d.tid); mds->send_message_mds(dis, d.mds); } void MDCache::discover_base_ino(inodeno_t want_ino, Context *onfinish, int from) { dout(7) << "discover_base_ino " << want_ino << " from mds." << from << dendl; if (waiting_for_base_ino[from].count(want_ino) == 0) { discover_info_t& d = _create_discover(from); d.ino = want_ino; _send_discover(d); } waiting_for_base_ino[from][want_ino].push_back(onfinish); } void MDCache::discover_dir_frag(CInode *base, frag_t approx_fg, Context *onfinish, int from) { if (from < 0) from = base->authority().first; dirfrag_t df(base->ino(), approx_fg); dout(7) << "discover_dir_frag " << df << " from mds." << from << dendl; if (!base->is_waiting_for_dir(approx_fg) || !onfinish) { discover_info_t& d = _create_discover(from); d.ino = base->ino(); d.frag = approx_fg; d.want_base_dir = true; _send_discover(d); } if (onfinish) base->add_dir_waiter(approx_fg, onfinish); } struct C_MDC_RetryDiscoverPath : public Context { MDCache *mdc; CInode *base; snapid_t snapid; filepath path; int from; C_MDC_RetryDiscoverPath(MDCache *c, CInode *b, snapid_t s, filepath &p, int f) : mdc(c), base(b), snapid(s), path(p), from(f) {} void finish(int r) { mdc->discover_path(base, snapid, path, 0, from); } }; void MDCache::discover_path(CInode *base, snapid_t snap, filepath want_path, Context *onfinish, bool want_xlocked, int from) { if (from < 0) from = base->authority().first; dout(7) << "discover_path " << base->ino() << " " << want_path << " snap " << snap << " from mds." << from << (want_xlocked ? " want_xlocked":"") << dendl; if (base->is_ambiguous_auth()) { dout(10) << " waiting for single auth on " << *base << dendl; if (!onfinish) onfinish = new C_MDC_RetryDiscoverPath(this, base, snap, want_path, from); base->add_waiter(CInode::WAIT_SINGLEAUTH, onfinish); return; } else if (from == mds->get_nodeid()) { list finished; base->take_waiting(CInode::WAIT_DIR, finished); mds->queue_waiters(finished); return; } frag_t fg = base->pick_dirfrag(want_path[0]); if ((want_xlocked && want_path.depth() == 1) || !base->is_waiting_for_dir(fg) || !onfinish) { discover_info_t& d = _create_discover(from); d.ino = base->ino(); d.frag = fg; d.snap = snap; d.want_path = want_path; d.want_base_dir = true; d.want_xlocked = want_xlocked; _send_discover(d); } // register + wait if (onfinish) base->add_dir_waiter(fg, onfinish); } struct C_MDC_RetryDiscoverPath2 : public Context { MDCache *mdc; CDir *base; snapid_t snapid; filepath path; C_MDC_RetryDiscoverPath2(MDCache *c, CDir *b, snapid_t s, filepath &p) : mdc(c), base(b), snapid(s), path(p) {} void finish(int r) { mdc->discover_path(base, snapid, path, 0); } }; void MDCache::discover_path(CDir *base, snapid_t snap, filepath want_path, Context *onfinish, bool want_xlocked) { int from = base->authority().first; dout(7) << "discover_path " << base->dirfrag() << " " << want_path << " snap " << snap << " from mds." << from << (want_xlocked ? " want_xlocked":"") << dendl; if (base->is_ambiguous_auth()) { dout(7) << " waiting for single auth on " << *base << dendl; if (!onfinish) onfinish = new C_MDC_RetryDiscoverPath2(this, base, snap, want_path); base->add_waiter(CDir::WAIT_SINGLEAUTH, onfinish); return; } else if (from == mds->get_nodeid()) { list finished; base->take_sub_waiting(finished); mds->queue_waiters(finished); return; } if ((want_xlocked && want_path.depth() == 1) || !base->is_waiting_for_dentry(want_path[0].c_str(), snap) || !onfinish) { discover_info_t& d = _create_discover(from); d.ino = base->ino(); d.frag = base->get_frag(); d.snap = snap; d.want_path = want_path; d.want_base_dir = false; d.want_xlocked = want_xlocked; _send_discover(d); } // register + wait if (onfinish) base->add_dentry_waiter(want_path[0], snap, onfinish); } struct C_MDC_RetryDiscoverIno : public Context { MDCache *mdc; CDir *base; inodeno_t want_ino; C_MDC_RetryDiscoverIno(MDCache *c, CDir *b, inodeno_t i) : mdc(c), base(b), want_ino(i) {} void finish(int r) { mdc->discover_ino(base, want_ino, 0); } }; void MDCache::discover_ino(CDir *base, inodeno_t want_ino, Context *onfinish, bool want_xlocked) { int from = base->authority().first; dout(7) << "discover_ino " << base->dirfrag() << " " << want_ino << " from mds." << from << (want_xlocked ? " want_xlocked":"") << dendl; if (base->is_ambiguous_auth()) { dout(10) << " waiting for single auth on " << *base << dendl; if (!onfinish) onfinish = new C_MDC_RetryDiscoverIno(this, base, want_ino); base->add_waiter(CDir::WAIT_SINGLEAUTH, onfinish); return; } else if (from == mds->get_nodeid()) { list finished; base->take_sub_waiting(finished); mds->queue_waiters(finished); return; } if (want_xlocked || !base->is_waiting_for_ino(want_ino) || !onfinish) { discover_info_t& d = _create_discover(from); d.ino = base->ino(); d.frag = base->get_frag(); d.want_ino = want_ino; d.want_base_dir = false; d.want_xlocked = want_xlocked; _send_discover(d); } // register + wait if (onfinish) base->add_ino_waiter(want_ino, onfinish); } void MDCache::kick_discovers(int who) { for (map::iterator p = discovers.begin(); p != discovers.end(); ++p) { if (p->second.mds != who) continue; _send_discover(p->second); } } /* This function DOES put the passed message before returning */ void MDCache::handle_discover(MDiscover *dis) { int whoami = mds->get_nodeid(); int from = dis->get_source_inst().name._num; assert(from != whoami); if (mds->get_state() <= MDSMap::STATE_REJOIN) { int from = dis->get_source().num(); // proceed if requester is in the REJOIN stage, the request is from parallel_fetch(). // delay processing request from survivor because we may not yet choose lock states. if (mds->get_state() < MDSMap::STATE_REJOIN || !mds->mdsmap->is_rejoin(from)) { dout(0) << "discover_reply not yet active(|still rejoining), delaying" << dendl; mds->wait_for_active(new C_MDS_RetryMessage(mds, dis)); return; } } CInode *cur = 0; MDiscoverReply *reply = new MDiscoverReply(dis); snapid_t snapid = dis->get_snapid(); // get started. if (MDS_INO_IS_BASE(dis->get_base_ino()) && !dis->wants_base_dir() && dis->get_want().depth() == 0) { // wants root dout(7) << "handle_discover from mds." << from << " wants base + " << dis->get_want().get_path() << " snap " << snapid << dendl; cur = get_inode(dis->get_base_ino()); assert(cur); // add root reply->starts_with = MDiscoverReply::INODE; replicate_inode(cur, from, reply->trace); dout(10) << "added base " << *cur << dendl; } else { // there's a base inode cur = get_inode(dis->get_base_ino(), snapid); if (!cur && snapid != CEPH_NOSNAP) { cur = get_inode(dis->get_base_ino()); if (cur && !cur->is_multiversion()) cur = NULL; // nope! } if (!cur) { dout(7) << "handle_discover mds." << from << " don't have base ino " << dis->get_base_ino() << "." << snapid << dendl; if (!dis->wants_base_dir() && dis->get_want().depth() > 0) reply->set_error_dentry(dis->get_dentry(0)); reply->set_flag_error_dir(); } else if (dis->wants_base_dir()) { dout(7) << "handle_discover mds." << from << " wants basedir+" << dis->get_want().get_path() << " has " << *cur << dendl; } else { dout(7) << "handle_discover mds." << from << " wants " << dis->get_want().get_path() << " has " << *cur << dendl; } } assert(reply); // add content // do some fidgeting to include a dir if they asked for the base dir, or just root. for (unsigned i = 0; cur && (i < dis->get_want().depth() || dis->get_want().depth() == 0); i++) { // -- figure out the dir // is *cur even a dir at all? if (!cur->is_dir()) { dout(7) << *cur << " not a dir" << dendl; reply->set_flag_error_dir(); break; } // pick frag frag_t fg; if (dis->get_want().depth()) { // dentry specifies fg = cur->pick_dirfrag(dis->get_dentry(i)); } else { // requester explicity specified the frag assert(dis->wants_base_dir() || dis->get_want_ino() || MDS_INO_IS_BASE(dis->get_base_ino())); fg = dis->get_base_dir_frag(); if (!cur->dirfragtree.is_leaf(fg)) fg = cur->dirfragtree[fg.value()]; } CDir *curdir = cur->get_dirfrag(fg); if ((!curdir && !cur->is_auth()) || (curdir && !curdir->is_auth())) { /* before: * ONLY set flag if empty!! * otherwise requester will wake up waiter(s) _and_ continue with discover, * resulting in duplicate discovers in flight, * which can wreak havoc when discovering rename srcdn (which may move) */ if (reply->is_empty()) { // only hint if empty. // someday this could be better, but right now the waiter logic isn't smart enough. // hint if (curdir) { dout(7) << " not dirfrag auth, setting dir_auth_hint for " << *curdir << dendl; reply->set_dir_auth_hint(curdir->authority().first); } else { dout(7) << " dirfrag not open, not inode auth, setting dir_auth_hint for " << *cur << dendl; reply->set_dir_auth_hint(cur->authority().first); } // note error dentry, if any // NOTE: important, as it allows requester to issue an equivalent discover // to whomever we hint at. if (dis->get_want().depth() > i) reply->set_error_dentry(dis->get_dentry(i)); } break; } if (!curdir) { // open dir? if (cur->is_frozen()) { if (!reply->is_empty()) { dout(7) << *cur << " is frozen, non-empty reply, stopping" << dendl; break; } dout(7) << *cur << " is frozen, empty reply, waiting" << dendl; cur->add_waiter(CInode::WAIT_UNFREEZE, new C_MDS_RetryMessage(mds, dis)); reply->put(); return; } curdir = cur->get_or_open_dirfrag(this, fg); } else if (curdir->is_frozen_tree() || (curdir->is_frozen_dir() && fragment_are_all_frozen(curdir))) { if (dis->wants_base_dir() && dis->get_base_dir_frag() != curdir->get_frag()) { dout(7) << *curdir << " is frozen, dirfrag mismatch, stopping" << dendl; reply->set_flag_error_dir(); break; } if (!reply->is_empty()) { dout(7) << *curdir << " is frozen, non-empty reply, stopping" << dendl; break; } dout(7) << *curdir << " is frozen, empty reply, waiting" << dendl; curdir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryMessage(mds, dis)); reply->put(); return; } // add dir if (curdir->get_version() == 0) { // fetch newly opened dir } else if (reply->is_empty() && !dis->wants_base_dir()) { dout(7) << "handle_discover not adding unwanted base dir " << *curdir << dendl; // make sure the base frag is correct, though, in there was a refragment since the // original request was sent. reply->set_base_dir_frag(curdir->get_frag()); } else { assert(!curdir->is_ambiguous_auth()); // would be frozen. if (!reply->trace.length()) reply->starts_with = MDiscoverReply::DIR; replicate_dir(curdir, from, reply->trace); dout(7) << "handle_discover added dir " << *curdir << dendl; } // lookup CDentry *dn = 0; if (curdir->get_version() == 0) { // fetch newly opened dir } else if (dis->get_want_ino()) { // lookup by ino CInode *in = get_inode(dis->get_want_ino(), snapid); if (in && in->is_auth() && in->get_parent_dn()->get_dir() == curdir) { dn = in->get_parent_dn(); if (dn->state_test(CDentry::STATE_PURGING)) { // set error flag in reply dout(7) << "dentry " << *dn << " is purging, flagging error ino" << dendl; reply->set_flag_error_ino(); break; } } } else if (dis->get_want().depth() > 0) { // lookup dentry dn = curdir->lookup(dis->get_dentry(i), snapid); } else break; // done! // incomplete dir? if (!dn) { if (!curdir->is_complete()) { // readdir dout(7) << "incomplete dir contents for " << *curdir << ", fetching" << dendl; if (reply->is_empty()) { // fetch and wait curdir->fetch(new C_MDS_RetryMessage(mds, dis), dis->wants_base_dir() && curdir->get_version() == 0); reply->put(); return; } else { // initiate fetch, but send what we have so far curdir->fetch(0); break; } } // don't have wanted ino in this dir? if (dis->get_want_ino()) { // set error flag in reply dout(7) << "no ino " << dis->get_want_ino() << " in this dir, flagging error in " << *curdir << dendl; reply->set_flag_error_ino(); break; } // send null dentry dout(7) << "dentry " << dis->get_dentry(i) << " dne, returning null in " << *curdir << dendl; dn = curdir->add_null_dentry(dis->get_dentry(i)); } assert(dn); CDentry::linkage_t *dnl = dn->get_linkage(); // xlocked dentry? // ...always block on non-tail items (they are unrelated) // ...allow xlocked tail disocvery _only_ if explicitly requested bool tailitem = (dis->get_want().depth() == 0) || (i == dis->get_want().depth() - 1); if (dn->lock.is_xlocked()) { // is this the last (tail) item in the discover traversal? if (tailitem && dis->wants_xlocked()) { dout(7) << "handle_discover allowing discovery of xlocked tail " << *dn << dendl; } else if (reply->is_empty()) { dout(7) << "handle_discover blocking on xlocked " << *dn << dendl; dn->lock.add_waiter(SimpleLock::WAIT_RD, new C_MDS_RetryMessage(mds, dis)); reply->put(); return; } else { dout(7) << "handle_discover non-empty reply, xlocked tail " << *dn << dendl; break; } } // frozen inode? if (dnl->is_primary() && dnl->get_inode()->is_frozen()) { if (tailitem && dis->wants_xlocked()) { dout(7) << "handle_discover allowing discovery of frozen tail " << *dnl->get_inode() << dendl; } else if (reply->is_empty()) { dout(7) << *dnl->get_inode() << " is frozen, empty reply, waiting" << dendl; dnl->get_inode()->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryMessage(mds, dis)); reply->put(); return; } else { dout(7) << *dnl->get_inode() << " is frozen, non-empty reply, stopping" << dendl; break; } } // add dentry if (!reply->trace.length()) reply->starts_with = MDiscoverReply::DENTRY; replicate_dentry(dn, from, reply->trace); dout(7) << "handle_discover added dentry " << *dn << dendl; if (!dnl->is_primary()) break; // stop on null or remote link. // add inode CInode *next = dnl->get_inode(); assert(next->is_auth()); replicate_inode(next, from, reply->trace); dout(7) << "handle_discover added inode " << *next << dendl; // descend, keep going. cur = next; continue; } // how did we do? assert(!reply->is_empty()); dout(7) << "handle_discover sending result back to asker mds." << from << dendl; mds->send_message(reply, dis->get_connection()); dis->put(); } /* This function DOES put the passed message before returning */ void MDCache::handle_discover_reply(MDiscoverReply *m) { /* if (mds->get_state() < MDSMap::STATE_ACTIVE) { dout(0) << "discover_reply NOT ACTIVE YET" << dendl; m->put(); return; } */ dout(7) << "discover_reply " << *m << dendl; if (m->is_flag_error_dir()) dout(7) << " flag error, dir" << dendl; if (m->is_flag_error_dn()) dout(7) << " flag error, dentry = " << m->get_error_dentry() << dendl; if (m->is_flag_error_ino()) dout(7) << " flag error, ino = " << m->get_wanted_ino() << dendl; list finished, error; int from = m->get_source().num(); // starting point CInode *cur = get_inode(m->get_base_ino()); bufferlist::iterator p = m->trace.begin(); int next = m->starts_with; // decrement discover counters if (m->get_tid()) { map::iterator p = discovers.find(m->get_tid()); if (p != discovers.end()) { dout(10) << " found tid " << m->get_tid() << dendl; discovers.erase(p); } else { dout(10) << " tid " << m->get_tid() << " not found, must be dup reply" << dendl; } } // discover ino error if (p.end() && m->is_flag_error_ino()) { assert(cur); assert(cur->is_dir()); CDir *dir = cur->get_dirfrag(m->get_base_dir_frag()); if (dir) { dout(7) << " flag_error on ino " << m->get_wanted_ino() << ", triggering ino" << dendl; dir->take_ino_waiting(m->get_wanted_ino(), error); } else assert(0); } // discover may start with an inode if (!p.end() && next == MDiscoverReply::INODE) { cur = add_replica_inode(p, NULL, finished); dout(7) << "discover_reply got base inode " << *cur << dendl; assert(cur->is_base()); next = MDiscoverReply::DIR; // take waiters? if (cur->is_base() && waiting_for_base_ino[from].count(cur->ino())) { finished.swap(waiting_for_base_ino[from][cur->ino()]); waiting_for_base_ino[from].erase(cur->ino()); } } assert(cur); // loop over discover results. // indexes follow each ([[dir] dentry] inode) // can start, end with any type. while (!p.end()) { // dir frag_t fg; CDir *curdir = 0; if (next == MDiscoverReply::DIR) { curdir = add_replica_dir(p, cur, m->get_source().num(), finished); if (cur->ino() == m->get_base_ino() && curdir->get_frag() != m->get_base_dir_frag()) { assert(m->get_wanted_base_dir()); cur->take_dir_waiting(m->get_base_dir_frag(), finished); } } else { // note: this can only happen our first way around this loop. if (p.end() && m->is_flag_error_dn()) { fg = cur->pick_dirfrag(m->get_error_dentry()); curdir = cur->get_dirfrag(fg); } else curdir = cur->get_dirfrag(m->get_base_dir_frag()); } if (p.end()) break; // dentry CDentry *dn = add_replica_dentry(p, curdir, finished); if (p.end()) break; // inode cur = add_replica_inode(p, dn, finished); next = MDiscoverReply::DIR; } // dir error? // or dir_auth hint? if (m->is_flag_error_dir() && !cur->is_dir()) { // not a dir. cur->take_waiting(CInode::WAIT_DIR, error); } else if (m->is_flag_error_dir() || m->get_dir_auth_hint() != CDIR_AUTH_UNKNOWN) { int who = m->get_dir_auth_hint(); if (who == mds->get_nodeid()) who = -1; if (who >= 0) dout(7) << " dir_auth_hint is " << m->get_dir_auth_hint() << dendl; frag_t fg = m->get_base_dir_frag(); CDir *dir = cur->get_dirfrag(fg); if (m->get_wanted_base_dir()) { if (cur->is_waiting_for_dir(fg)) { if (cur->is_auth()) cur->take_waiting(CInode::WAIT_DIR, finished); else if (dir || !cur->dirfragtree.is_leaf(fg)) cur->take_dir_waiting(fg, finished); else discover_dir_frag(cur, fg, 0, who); } else dout(7) << " doing nothing, nobody is waiting for dir" << dendl; } // try again? if (m->get_error_dentry().length()) { // wanted a dentry if (dir && dir->is_waiting_for_dentry(m->get_error_dentry(), m->get_wanted_snapid())) { if (dir->is_auth() || dir->lookup(m->get_error_dentry())) { dir->take_dentry_waiting(m->get_error_dentry(), m->get_wanted_snapid(), m->get_wanted_snapid(), finished); } else { filepath relpath(m->get_error_dentry(), 0); discover_path(dir, m->get_wanted_snapid(), relpath, 0, m->get_wanted_xlocked()); } } else dout(7) << " doing nothing, have dir but nobody is waiting on dentry " << m->get_error_dentry() << dendl; } else { if (dir && m->get_wanted_ino() && dir->is_waiting_for_ino(m->get_wanted_ino())) { if (dir->is_auth() || get_inode(m->get_wanted_ino())) dir->take_ino_waiting(m->get_wanted_ino(), finished); else discover_ino(dir, m->get_wanted_ino(), 0, m->get_wanted_xlocked()); } else dout(7) << " doing nothing, nobody is waiting for ino" << dendl; } } // waiters finish_contexts(g_ceph_context, error, -ENOENT); // finish errors directly mds->queue_waiters(finished); // done m->put(); } // ---------------------------- // REPLICAS CDir *MDCache::add_replica_dir(bufferlist::iterator& p, CInode *diri, int from, list& finished) { dirfrag_t df; ::decode(df, p); assert(diri->ino() == df.ino); // add it (_replica_) CDir *dir = diri->get_dirfrag(df.frag); if (dir) { // had replica. update w/ new nonce. dir->decode_replica(p); dout(7) << "add_replica_dir had " << *dir << " nonce " << dir->replica_nonce << dendl; } else { // force frag to leaf in the diri tree if (!diri->dirfragtree.is_leaf(df.frag)) { dout(7) << "add_replica_dir forcing frag " << df.frag << " to leaf in the fragtree " << diri->dirfragtree << dendl; diri->dirfragtree.force_to_leaf(g_ceph_context, df.frag); } // add replica. dir = diri->add_dirfrag( new CDir(diri, df.frag, this, false) ); dir->decode_replica(p); // is this a dir_auth delegation boundary? if (from != diri->authority().first || diri->is_ambiguous_auth() || diri->is_base()) adjust_subtree_auth(dir, from); dout(7) << "add_replica_dir added " << *dir << " nonce " << dir->replica_nonce << dendl; // get waiters diri->take_dir_waiting(df.frag, finished); } return dir; } CDir *MDCache::forge_replica_dir(CInode *diri, frag_t fg, int from) { assert(mds->mdsmap->get_state(from) < MDSMap::STATE_REJOIN); // forge a replica. CDir *dir = diri->add_dirfrag( new CDir(diri, fg, this, false) ); // i'm assuming this is a subtree root. adjust_subtree_auth(dir, from); dout(7) << "forge_replica_dir added " << *dir << " while mds." << from << " is down" << dendl; return dir; } CDentry *MDCache::add_replica_dentry(bufferlist::iterator& p, CDir *dir, list& finished) { string name; snapid_t last; ::decode(name, p); ::decode(last, p); CDentry *dn = dir->lookup(name, last); // have it? if (dn) { dn->decode_replica(p, false); dout(7) << "add_replica_dentry had " << *dn << dendl; } else { dn = dir->add_null_dentry(name, 1 /* this will get updated below */, last); dn->decode_replica(p, true); dout(7) << "add_replica_dentry added " << *dn << dendl; } dir->take_dentry_waiting(name, dn->first, dn->last, finished); return dn; } CInode *MDCache::add_replica_inode(bufferlist::iterator& p, CDentry *dn, list& finished) { inodeno_t ino; snapid_t last; ::decode(ino, p); ::decode(last, p); CInode *in = get_inode(ino, last); if (!in) { in = new CInode(this, false, 1, last); in->decode_replica(p, true); add_inode(in); if (in->ino() == MDS_INO_ROOT) in->inode_auth.first = 0; else if (in->is_mdsdir()) in->inode_auth.first = in->ino() - MDS_INO_MDSDIR_OFFSET; dout(10) << "add_replica_inode added " << *in << dendl; if (dn) { assert(dn->get_linkage()->is_null()); dn->dir->link_primary_inode(dn, in); } } else { in->decode_replica(p, false); dout(10) << "add_replica_inode had " << *in << dendl; } if (dn) { if (!dn->get_linkage()->is_primary() || dn->get_linkage()->get_inode() != in) dout(10) << "add_replica_inode different linkage in dentry " << *dn << dendl; dn->get_dir()->take_ino_waiting(in->ino(), finished); } return in; } void MDCache::replicate_stray(CDentry *straydn, int who, bufferlist& bl) { replicate_inode(get_myin(), who, bl); replicate_dir(straydn->get_dir()->inode->get_parent_dn()->get_dir(), who, bl); replicate_dentry(straydn->get_dir()->inode->get_parent_dn(), who, bl); replicate_inode(straydn->get_dir()->inode, who, bl); replicate_dir(straydn->get_dir(), who, bl); replicate_dentry(straydn, who, bl); } CDentry *MDCache::add_replica_stray(bufferlist &bl, int from) { list finished; bufferlist::iterator p = bl.begin(); CInode *mdsin = add_replica_inode(p, NULL, finished); CDir *mdsdir = add_replica_dir(p, mdsin, from, finished); CDentry *straydirdn = add_replica_dentry(p, mdsdir, finished); CInode *strayin = add_replica_inode(p, straydirdn, finished); CDir *straydir = add_replica_dir(p, strayin, from, finished); CDentry *straydn = add_replica_dentry(p, straydir, finished); if (!finished.empty()) mds->queue_waiters(finished); return straydn; } int MDCache::send_dir_updates(CDir *dir, bool bcast) { // this is an FYI, re: replication set who; if (bcast) { mds->get_mds_map()->get_active_mds_set(who); } else { for (map::iterator p = dir->replicas_begin(); p != dir->replicas_end(); ++p) who.insert(p->first); } dout(7) << "sending dir_update on " << *dir << " bcast " << bcast << " to " << who << dendl; filepath path; dir->inode->make_path(path); int whoami = mds->get_nodeid(); for (set::iterator it = who.begin(); it != who.end(); ++it) { if (*it == whoami) continue; //if (*it == except) continue; dout(7) << "sending dir_update on " << *dir << " to " << *it << dendl; mds->send_message_mds(new MDirUpdate(mds->get_nodeid(), dir->dirfrag(), dir->dir_rep, dir->dir_rep_by, path, bcast), *it); } return 0; } /* This function DOES put the passed message before returning */ void MDCache::handle_dir_update(MDirUpdate *m) { CDir *dir = get_dirfrag(m->get_dirfrag()); if (!dir) { dout(5) << "dir_update on " << m->get_dirfrag() << ", don't have it" << dendl; // discover it? if (m->should_discover()) { // only try once! // this is key to avoid a fragtree update race, among other things. m->tried_discover(); vector trace; CInode *in; filepath path = m->get_path(); dout(5) << "trying discover on dir_update for " << path << dendl; MDRequestRef null_ref; int r = path_traverse(null_ref, m, NULL, path, &trace, &in, MDS_TRAVERSE_DISCOVER); if (r > 0) return; assert(r == 0); open_remote_dirfrag(in, m->get_dirfrag().frag, new C_MDS_RetryMessage(mds, m)); return; } m->put(); return; } // update dout(5) << "dir_update on " << *dir << dendl; dir->dir_rep = m->get_dir_rep(); dir->dir_rep_by = m->get_dir_rep_by(); // done m->put(); } // LINK void MDCache::send_dentry_link(CDentry *dn) { dout(7) << "send_dentry_link " << *dn << dendl; CDir *subtree = get_subtree_root(dn->get_dir()); for (map::iterator p = dn->replicas_begin(); p != dn->replicas_end(); ++p) { if (mds->mdsmap->get_state(p->first) < MDSMap::STATE_REJOIN || (mds->mdsmap->get_state(p->first) == MDSMap::STATE_REJOIN && rejoin_gather.count(p->first))) continue; CDentry::linkage_t *dnl = dn->get_linkage(); MDentryLink *m = new MDentryLink(subtree->dirfrag(), dn->get_dir()->dirfrag(), dn->name, dnl->is_primary()); if (dnl->is_primary()) { dout(10) << " primary " << *dnl->get_inode() << dendl; replicate_inode(dnl->get_inode(), p->first, m->bl); } else if (dnl->is_remote()) { inodeno_t ino = dnl->get_remote_ino(); __u8 d_type = dnl->get_remote_d_type(); dout(10) << " remote " << ino << " " << d_type << dendl; ::encode(ino, m->bl); ::encode(d_type, m->bl); } else assert(0); // aie, bad caller! mds->send_message_mds(m, p->first); } } /* This function DOES put the passed message before returning */ void MDCache::handle_dentry_link(MDentryLink *m) { CDentry *dn = NULL; CDir *dir = get_dirfrag(m->get_dirfrag()); if (!dir) { dout(7) << "handle_dentry_link don't have dirfrag " << m->get_dirfrag() << dendl; } else { dn = dir->lookup(m->get_dn()); if (!dn) { dout(7) << "handle_dentry_link don't have dentry " << *dir << " dn " << m->get_dn() << dendl; } else { dout(7) << "handle_dentry_link on " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_linkage(); assert(!dn->is_auth()); assert(dnl->is_null()); } } bufferlist::iterator p = m->bl.begin(); list finished; if (dn) { if (m->get_is_primary()) { // primary link. add_replica_inode(p, dn, finished); } else { // remote link, easy enough. inodeno_t ino; __u8 d_type; ::decode(ino, p); ::decode(d_type, p); dir->link_remote_inode(dn, ino, d_type); } } else { assert(0); } if (!finished.empty()) mds->queue_waiters(finished); m->put(); return; } // UNLINK void MDCache::send_dentry_unlink(CDentry *dn, CDentry *straydn, MDRequestRef& mdr) { dout(10) << "send_dentry_unlink " << *dn << dendl; // share unlink news with replicas for (map::iterator it = dn->replicas_begin(); it != dn->replicas_end(); ++it) { // don't tell (rmdir) witnesses; they already know if (mdr && mdr->more()->witnessed.count(it->first)) continue; if (mds->mdsmap->get_state(it->first) < MDSMap::STATE_REJOIN || (mds->mdsmap->get_state(it->first) == MDSMap::STATE_REJOIN && rejoin_gather.count(it->first))) continue; MDentryUnlink *unlink = new MDentryUnlink(dn->get_dir()->dirfrag(), dn->name); if (straydn) replicate_stray(straydn, it->first, unlink->straybl); mds->send_message_mds(unlink, it->first); } } /* This function DOES put the passed message before returning */ void MDCache::handle_dentry_unlink(MDentryUnlink *m) { // straydn CDentry *straydn = NULL; if (m->straybl.length()) straydn = add_replica_stray(m->straybl, m->get_source().num()); CDir *dir = get_dirfrag(m->get_dirfrag()); if (!dir) { dout(7) << "handle_dentry_unlink don't have dirfrag " << m->get_dirfrag() << dendl; } else { CDentry *dn = dir->lookup(m->get_dn()); if (!dn) { dout(7) << "handle_dentry_unlink don't have dentry " << *dir << " dn " << m->get_dn() << dendl; } else { dout(7) << "handle_dentry_unlink on " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_linkage(); // open inode? if (dnl->is_primary()) { CInode *in = dnl->get_inode(); dn->dir->unlink_inode(dn); assert(straydn); straydn->dir->link_primary_inode(straydn, in); // in->first is lazily updated on replica; drag it forward so // that we always keep it in sync with the dnq assert(straydn->first >= in->first); in->first = straydn->first; // update subtree map? if (in->is_dir()) adjust_subtree_after_rename(in, dir, false); // send caps to auth (if we're not already) if (in->is_any_caps() && !in->state_test(CInode::STATE_EXPORTINGCAPS)) migrator->export_caps(in); touch_dentry_bottom(straydn); // move stray to end of lru straydn = NULL; } else { assert(!straydn); assert(dnl->is_remote()); dn->dir->unlink_inode(dn); } assert(dnl->is_null()); // move to bottom of lru touch_dentry_bottom(dn); } } // race with trim_dentry() if (straydn) { assert(straydn->get_num_ref() == 0); assert(straydn->get_linkage()->is_null()); map expiremap; trim_dentry(straydn, expiremap); send_expire_messages(expiremap); } m->put(); return; } // =================================================================== // =================================================================== // FRAGMENT /** * adjust_dir_fragments -- adjust fragmentation for a directory * * @param diri directory inode * @param basefrag base fragment * @param bits bit adjustment. positive for split, negative for merge. */ void MDCache::adjust_dir_fragments(CInode *diri, frag_t basefrag, int bits, list& resultfrags, list& waiters, bool replay) { dout(10) << "adjust_dir_fragments " << basefrag << " " << bits << " on " << *diri << dendl; list srcfrags; diri->get_dirfrags_under(basefrag, srcfrags); adjust_dir_fragments(diri, srcfrags, basefrag, bits, resultfrags, waiters, replay); } CDir *MDCache::force_dir_fragment(CInode *diri, frag_t fg, bool replay) { CDir *dir = diri->get_dirfrag(fg); if (dir) return dir; dout(10) << "force_dir_fragment " << fg << " on " << *diri << dendl; list src, result; list waiters; // split a parent? frag_t parent = diri->dirfragtree.get_branch_or_leaf(fg); while (1) { CDir *pdir = diri->get_dirfrag(parent); if (pdir) { int split = fg.bits() - parent.bits(); dout(10) << " splitting parent by " << split << " " << *pdir << dendl; src.push_back(pdir); adjust_dir_fragments(diri, src, parent, split, result, waiters, replay); dir = diri->get_dirfrag(fg); if (dir) dout(10) << "force_dir_fragment result " << *dir << dendl; return dir; } if (parent == frag_t()) break; frag_t last = parent; parent = parent.parent(); dout(10) << " " << last << " parent is " << parent << dendl; } // hoover up things under fg? diri->get_dirfrags_under(fg, src); if (src.empty()) { dout(10) << "force_dir_fragment no frags under " << fg << dendl; return NULL; } dout(10) << " will combine frags under " << fg << ": " << src << dendl; adjust_dir_fragments(diri, src, fg, 0, result, waiters, replay); dir = result.front(); dout(10) << "force_dir_fragment result " << *dir << dendl; return dir; } void MDCache::adjust_dir_fragments(CInode *diri, list& srcfrags, frag_t basefrag, int bits, list& resultfrags, list& waiters, bool replay) { dout(10) << "adjust_dir_fragments " << basefrag << " bits " << bits << " srcfrags " << srcfrags << " on " << *diri << dendl; // adjust fragtree // yuck. we may have discovered the inode while it was being fragmented. if (!diri->dirfragtree.is_leaf(basefrag)) diri->dirfragtree.force_to_leaf(g_ceph_context, basefrag); if (bits > 0) diri->dirfragtree.split(basefrag, bits); dout(10) << " new fragtree is " << diri->dirfragtree << dendl; if (srcfrags.empty()) return; // split CDir *parent_dir = diri->get_parent_dir(); CDir *parent_subtree = 0; if (parent_dir) parent_subtree = get_subtree_root(parent_dir); if (bits > 0) { // SPLIT assert(srcfrags.size() == 1); CDir *dir = srcfrags.front(); dir->split(bits, resultfrags, waiters, replay); // did i change the subtree map? if (dir->is_subtree_root()) { // new frags are now separate subtrees for (list::iterator p = resultfrags.begin(); p != resultfrags.end(); ++p) subtrees[*p].clear(); // new frag is now its own subtree // was i a bound? if (parent_subtree) { assert(subtrees[parent_subtree].count(dir)); subtrees[parent_subtree].erase(dir); for (list::iterator p = resultfrags.begin(); p != resultfrags.end(); ++p) subtrees[parent_subtree].insert(*p); } // adjust my bounds. set bounds; bounds.swap(subtrees[dir]); subtrees.erase(dir); for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *frag = get_subtree_root((*p)->get_parent_dir()); subtrees[frag].insert(*p); } show_subtrees(10); // dir has no PIN_SUBTREE; CDir::purge_stolen() drops it. dir->dir_auth = CDIR_AUTH_DEFAULT; } diri->close_dirfrag(dir->get_frag()); } else { // MERGE // are my constituent bits subtrees? if so, i will be too. // (it's all or none, actually.) bool was_subtree = false; set new_bounds; for (list::iterator p = srcfrags.begin(); p != srcfrags.end(); ++p) { CDir *dir = *p; if (dir->is_subtree_root()) { dout(10) << " taking srcfrag subtree bounds from " << *dir << dendl; was_subtree = true; map >::iterator q = subtrees.find(dir); set::iterator r = q->second.begin(); while (r != subtrees[dir].end()) { new_bounds.insert(*r); subtrees[dir].erase(r++); } subtrees.erase(q); // remove myself as my parent's bound if (parent_subtree) subtrees[parent_subtree].erase(dir); } } // merge CDir *f = new CDir(diri, basefrag, this, srcfrags.front()->is_auth()); f->merge(srcfrags, waiters, replay); diri->add_dirfrag(f); if (was_subtree) { subtrees[f].swap(new_bounds); if (parent_subtree) subtrees[parent_subtree].insert(f); show_subtrees(10); } resultfrags.push_back(f); } } class C_MDC_FragmentFrozen : public Context { MDCache *mdcache; dirfrag_t basedirfrag; public: C_MDC_FragmentFrozen(MDCache *m, dirfrag_t df) : mdcache(m), basedirfrag(df) {} virtual void finish(int r) { mdcache->fragment_frozen(basedirfrag, r); } }; bool MDCache::can_fragment(CInode *diri, list& dirs) { if (mds->mdsmap->is_degraded()) { dout(7) << "can_fragment: cluster degraded, no fragmenting for now" << dendl; return false; } if (diri->get_parent_dir() && diri->get_parent_dir()->get_inode()->is_stray()) { dout(7) << "can_fragment: i won't merge|split anything in stray" << dendl; return false; } if (diri->is_mdsdir() || diri->is_stray() || diri->ino() == MDS_INO_CEPH) { dout(7) << "can_fragment: i won't fragment the mdsdir or straydir or .ceph" << dendl; return false; } for (list::iterator p = dirs.begin(); p != dirs.end(); ++p) { CDir *dir = *p; if (dir->state_test(CDir::STATE_FRAGMENTING)) { dout(7) << "can_fragment: already fragmenting " << *dir << dendl; return false; } if (!dir->is_auth()) { dout(7) << "can_fragment: not auth on " << *dir << dendl; return false; } if (dir->is_frozen() || dir->is_freezing()) { dout(7) << "can_fragment: can't merge, freezing|frozen. wait for other exports to finish first." << dendl; return false; } } return true; } void MDCache::split_dir(CDir *dir, int bits) { dout(7) << "split_dir " << *dir << " bits " << bits << dendl; assert(dir->is_auth()); CInode *diri = dir->inode; list dirs; dirs.push_back(dir); if (!can_fragment(diri, dirs)) return; assert(fragments.count(dir->dirfrag()) == 0); fragment_info_t& info = fragments[dir->dirfrag()]; info.dirs.push_back(dir); info.bits = bits; info.last_cum_auth_pins_change = ceph_clock_now(g_ceph_context); C_GatherBuilder gather(g_ceph_context, new C_MDC_FragmentFrozen(this, dir->dirfrag())); fragment_freeze_dirs(dirs, gather); gather.activate(); // initial mark+complete pass fragment_mark_and_complete(dirs); } void MDCache::merge_dir(CInode *diri, frag_t frag) { dout(7) << "merge_dir to " << frag << " on " << *diri << dendl; list dirs; if (!diri->get_dirfrags_under(frag, dirs)) { dout(7) << "don't have all frags under " << frag << " for " << *diri << dendl; return; } if (diri->dirfragtree.is_leaf(frag)) { dout(10) << " " << frag << " already a leaf for " << *diri << dendl; return; } if (!can_fragment(diri, dirs)) return; CDir *first = dirs.front(); int bits = first->get_frag().bits() - frag.bits(); dout(10) << " we are merginb by " << bits << " bits" << dendl; dirfrag_t df(diri->ino(), frag); assert(fragments.count(df) == 0); fragment_info_t& info = fragments[df]; info.dirs = dirs; info.bits = -bits; info.last_cum_auth_pins_change = ceph_clock_now(g_ceph_context); C_GatherBuilder gather(g_ceph_context, new C_MDC_FragmentFrozen(this, dirfrag_t(diri->ino(), frag))); fragment_freeze_dirs(dirs, gather); gather.activate(); // initial mark+complete pass fragment_mark_and_complete(dirs); } void MDCache::fragment_freeze_dirs(list& dirs, C_GatherBuilder &gather) { for (list::iterator p = dirs.begin(); p != dirs.end(); ++p) { CDir *dir = *p; dir->auth_pin(dir); // until we mark and complete them dir->state_set(CDir::STATE_FRAGMENTING); dir->freeze_dir(); assert(dir->is_freezing_dir()); dir->add_waiter(CDir::WAIT_FROZEN, gather.new_sub()); } } class C_MDC_FragmentMarking : public Context { MDCache *mdcache; list dirs; public: C_MDC_FragmentMarking(MDCache *m, list& d) : mdcache(m), dirs(d) {} virtual void finish(int r) { mdcache->fragment_mark_and_complete(dirs); } }; void MDCache::fragment_mark_and_complete(list& dirs) { CInode *diri = dirs.front()->get_inode(); dout(10) << "fragment_mark_and_complete " << dirs << " on " << *diri << dendl; C_GatherBuilder gather(g_ceph_context); for (list::iterator p = dirs.begin(); p != dirs.end(); ++p) { CDir *dir = *p; bool ready = true; if (!dir->is_complete()) { dout(15) << " fetching incomplete " << *dir << dendl; dir->fetch(gather.new_sub(), true); // ignore authpinnability ready = false; } if (dir->get_frag() == frag_t() && dir->is_new()) { // The COMPLETE flag gets lost if we fragment a new dirfrag, then rollback // the operation. To avoid CDir::fetch() complaining about missing object, // we commit new dirfrag first. dout(15) << " committing new " << *dir << dendl; assert(dir->is_dirty()); dir->commit(0, gather.new_sub(), true); ready = false; } if (!ready) continue; if (!dir->state_test(CDir::STATE_DNPINNEDFRAG)) { dout(15) << " marking " << *dir << dendl; for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; dn->get(CDentry::PIN_FRAGMENTING); assert(!dn->state_test(CDentry::STATE_FRAGMENTING)); dn->state_set(CDentry::STATE_FRAGMENTING); } dir->state_set(CDir::STATE_DNPINNEDFRAG); dir->auth_unpin(dir); } else { dout(15) << " already marked " << *dir << dendl; } } if (gather.has_subs()) { gather.set_finisher(new C_MDC_FragmentMarking(this, dirs)); gather.activate(); } // flush log so that request auth_pins are retired mds->mdlog->flush(); } void MDCache::fragment_unmark_unfreeze_dirs(list& dirs) { dout(10) << "fragment_unmark_unfreeze_dirs " << dirs << dendl; for (list::iterator p = dirs.begin(); p != dirs.end(); ++p) { CDir *dir = *p; dout(10) << " frag " << *dir << dendl; assert(dir->state_test(CDir::STATE_DNPINNEDFRAG)); dir->state_clear(CDir::STATE_DNPINNEDFRAG); assert(dir->state_test(CDir::STATE_FRAGMENTING)); dir->state_clear(CDir::STATE_FRAGMENTING); for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; assert(dn->state_test(CDentry::STATE_FRAGMENTING)); dn->state_clear(CDentry::STATE_FRAGMENTING); dn->put(CDentry::PIN_FRAGMENTING); } dir->unfreeze_dir(); } } bool MDCache::fragment_are_all_frozen(CDir *dir) { assert(dir->is_frozen_dir()); map::iterator p; for (p = fragments.lower_bound(dirfrag_t(dir->ino(), 0)); p != fragments.end() && p->first.ino == dir->ino(); ++p) { if (p->first.frag.contains(dir->get_frag())) return p->second.has_frozen; } assert(0); return false; } void MDCache::fragment_freeze_inc_num_waiters(CDir *dir) { map::iterator p; for (p = fragments.lower_bound(dirfrag_t(dir->ino(), 0)); p != fragments.end() && p->first.ino == dir->ino(); ++p) { if (p->first.frag.contains(dir->get_frag())) { p->second.num_remote_waiters++; return; } } assert(0); } void MDCache::find_stale_fragment_freeze() { dout(10) << "find_stale_fragment_freeze" << dendl; // see comment in Migrator::find_stale_export_freeze() utime_t now = ceph_clock_now(g_ceph_context); utime_t cutoff = now; cutoff -= g_conf->mds_freeze_tree_timeout; for (map::iterator p = fragments.begin(); p != fragments.end(); ) { dirfrag_t df = p->first; fragment_info_t& info = p->second; ++p; if (info.has_frozen) continue; CDir *dir; int total_auth_pins = 0; for (list::iterator q = info.dirs.begin(); q != info.dirs.end(); ++q) { dir = *q; if (!dir->state_test(CDir::STATE_DNPINNEDFRAG)) { total_auth_pins = -1; break; } if (dir->is_frozen_dir()) continue; total_auth_pins += dir->get_auth_pins() + dir->get_dir_auth_pins(); } if (total_auth_pins < 0) continue; if (info.last_cum_auth_pins != total_auth_pins) { info.last_cum_auth_pins = total_auth_pins; info.last_cum_auth_pins_change = now; continue; } if (info.last_cum_auth_pins_change >= cutoff) continue; dir = info.dirs.front(); if (info.num_remote_waiters > 0 || (!dir->inode->is_root() && dir->get_parent_dir()->is_freezing())) { dout(10) << " cancel fragmenting " << df << " bit " << info.bits << dendl; list dirs; dirs.swap(info.dirs); fragments.erase(df); fragment_unmark_unfreeze_dirs(dirs); } } } class C_MDC_FragmentPrep : public Context { MDCache *mdcache; MDRequestRef mdr; public: C_MDC_FragmentPrep(MDCache *m, MDRequestRef& r) : mdcache(m), mdr(r) {} virtual void finish(int r) { mdcache->_fragment_logged(mdr); } }; class C_MDC_FragmentStore : public Context { MDCache *mdcache; MDRequestRef mdr; public: C_MDC_FragmentStore(MDCache *m, MDRequestRef& r) : mdcache(m), mdr(r) {} virtual void finish(int r) { mdcache->_fragment_stored(mdr); } }; class C_MDC_FragmentCommit : public Context { MDCache *mdcache; dirfrag_t basedirfrag; list resultfrags; public: C_MDC_FragmentCommit(MDCache *m, dirfrag_t df, list& l) : mdcache(m), basedirfrag(df), resultfrags(l) {} virtual void finish(int r) { mdcache->_fragment_committed(basedirfrag, resultfrags); } }; class C_MDC_FragmentFinish : public Context { MDCache *mdcache; dirfrag_t basedirfrag; list resultfrags; public: C_MDC_FragmentFinish(MDCache *m, dirfrag_t f, list& l) : mdcache(m), basedirfrag(f) { resultfrags.swap(l); } virtual void finish(int r) { assert(r == 0 || r == -ENOENT); mdcache->_fragment_finish(basedirfrag, resultfrags); } }; void MDCache::fragment_frozen(dirfrag_t basedirfrag, int r) { map::iterator it = fragments.find(basedirfrag); if (r < 0) { dout(7) << "fragment_frozen " << basedirfrag << " must have aborted" << dendl; assert(it == fragments.end()); return; } assert(it != fragments.end()); fragment_info_t& info = it->second; dout(10) << "fragment_frozen " << basedirfrag.frag << " by " << info.bits << " on " << info.dirs.front()->get_inode() << dendl; info.has_frozen = true; MDRequestRef mdr = request_start_internal(CEPH_MDS_OP_FRAGMENTDIR); mdr->more()->fragment_base = basedirfrag; dispatch_fragment_dir(mdr); } void MDCache::dispatch_fragment_dir(MDRequestRef& mdr) { dirfrag_t basedirfrag = mdr->more()->fragment_base; map::iterator it = fragments.find(basedirfrag); assert(it != fragments.end()); fragment_info_t& info = it->second; CInode *diri = info.dirs.front()->get_inode(); dout(10) << "dispatch_fragment_dir " << basedirfrag << " bits " << info.bits << " on " << *diri << dendl; if (!mdr->aborted) { set rdlocks, wrlocks, xlocks; wrlocks.insert(&diri->dirfragtreelock); // prevent a racing gather on any other scatterlocks too wrlocks.insert(&diri->nestlock); wrlocks.insert(&diri->filelock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks, NULL, NULL, true)) if (!mdr->aborted) return; } if (mdr->aborted) { dout(10) << " can't auth_pin " << *diri << ", requeuing dir " << info.dirs.front()->dirfrag() << dendl; if (info.bits > 0) mds->balancer->queue_split(info.dirs.front()); else mds->balancer->queue_merge(info.dirs.front()); fragment_unmark_unfreeze_dirs(info.dirs); fragments.erase(it); request_finish(mdr); return; } mdr->ls = mds->mdlog->get_current_segment(); EFragment *le = new EFragment(mds->mdlog, EFragment::OP_PREPARE, basedirfrag, info.bits); mds->mdlog->start_entry(le); for (list::iterator p = info.dirs.begin(); p != info.dirs.end(); ++p) { CDir *dir = *p; dirfrag_rollback rollback; rollback.fnode = dir->fnode; le->add_orig_frag(dir->get_frag(), &rollback); } // refragment list waiters; adjust_dir_fragments(diri, info.dirs, basedirfrag.frag, info.bits, info.resultfrags, waiters, false); if (g_conf->mds_debug_frag) diri->verify_dirfrags(); mds->queue_waiters(waiters); for (list::iterator p = le->orig_frags.begin(); p != le->orig_frags.end(); ++p) assert(!diri->dirfragtree.is_leaf(*p)); le->metablob.add_dir_context(*info.resultfrags.begin()); for (list::iterator p = info.resultfrags.begin(); p != info.resultfrags.end(); ++p) { if (diri->is_auth()) { le->metablob.add_fragmented_dir(*p, false, false); } else { (*p)->state_set(CDir::STATE_DIRTYDFT); le->metablob.add_fragmented_dir(*p, false, true); } } // dft lock if (diri->is_auth()) { // journal dirfragtree inode_t *pi = diri->project_inode(); pi->version = diri->pre_dirty(); journal_dirty_inode(mdr.get(), &le->metablob, diri); } else { mds->locker->mark_updated_scatterlock(&diri->dirfragtreelock); mdr->ls->dirty_dirfrag_dirfragtree.push_back(&diri->item_dirty_dirfrag_dirfragtree); mdr->add_updated_lock(&diri->dirfragtreelock); } /* // filelock mds->locker->mark_updated_scatterlock(&diri->filelock); mut->ls->dirty_dirfrag_dir.push_back(&diri->item_dirty_dirfrag_dir); mut->add_updated_lock(&diri->filelock); // dirlock mds->locker->mark_updated_scatterlock(&diri->nestlock); mut->ls->dirty_dirfrag_nest.push_back(&diri->item_dirty_dirfrag_nest); mut->add_updated_lock(&diri->nestlock); */ add_uncommitted_fragment(basedirfrag, info.bits, le->orig_frags, mdr->ls); mds->mdlog->submit_entry(le, new C_MDC_FragmentPrep(this, mdr)); mds->mdlog->flush(); } void MDCache::_fragment_logged(MDRequestRef& mdr) { dirfrag_t basedirfrag = mdr->more()->fragment_base; map::iterator it = fragments.find(basedirfrag); assert(it != fragments.end()); fragment_info_t &info = it->second; CInode *diri = info.resultfrags.front()->get_inode(); dout(10) << "fragment_logged " << basedirfrag << " bits " << info.bits << " on " << *diri << dendl; if (diri->is_auth()) diri->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); // mark scatterlock // store resulting frags C_GatherBuilder gather(g_ceph_context, new C_MDC_FragmentStore(this, mdr)); for (list::iterator p = info.resultfrags.begin(); p != info.resultfrags.end(); ++p) { CDir *dir = *p; dout(10) << " storing result frag " << *dir << dendl; // freeze and store them too dir->auth_pin(this); dir->state_set(CDir::STATE_FRAGMENTING); dir->commit(0, gather.new_sub(), true); // ignore authpinnability } gather.activate(); } void MDCache::_fragment_stored(MDRequestRef& mdr) { dirfrag_t basedirfrag = mdr->more()->fragment_base; map::iterator it = fragments.find(basedirfrag); assert(it != fragments.end()); fragment_info_t &info = it->second; CInode *diri = info.resultfrags.front()->get_inode(); dout(10) << "fragment_stored " << basedirfrag << " bits " << info.bits << " on " << *diri << dendl; // tell peers CDir *first = *info.resultfrags.begin(); for (map::iterator p = first->replicas_begin(); p != first->replica_map.end(); ++p) { if (mds->mdsmap->get_state(p->first) < MDSMap::STATE_REJOIN || (mds->mdsmap->get_state(p->first) == MDSMap::STATE_REJOIN && rejoin_gather.count(p->first))) continue; MMDSFragmentNotify *notify = new MMDSFragmentNotify(basedirfrag, info.bits); // freshly replicate new dirs to peers for (list::iterator q = info.resultfrags.begin(); q != info.resultfrags.end(); ++q) replicate_dir(*q, p->first, notify->basebl); mds->send_message_mds(notify, p->first); } // journal commit EFragment *le = new EFragment(mds->mdlog, EFragment::OP_COMMIT, basedirfrag, info.bits); mds->mdlog->start_submit_entry(le, new C_MDC_FragmentCommit(this, basedirfrag, info.resultfrags)); mds->locker->drop_locks(mdr.get()); // unfreeze resulting frags for (list::iterator p = info.resultfrags.begin(); p != info.resultfrags.end(); ++p) { CDir *dir = *p; dout(10) << " result frag " << *dir << dendl; for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; assert(dn->state_test(CDentry::STATE_FRAGMENTING)); dn->state_clear(CDentry::STATE_FRAGMENTING); dn->put(CDentry::PIN_FRAGMENTING); } // unfreeze dir->unfreeze_dir(); } fragments.erase(it); request_finish(mdr); } void MDCache::_fragment_committed(dirfrag_t basedirfrag, list& resultfrags) { dout(10) << "fragment_committed " << basedirfrag << dendl; map::iterator it = uncommitted_fragments.find(basedirfrag); assert(it != uncommitted_fragments.end()); ufragment &uf = it->second; // remove old frags C_GatherBuilder gather(g_ceph_context, new C_MDC_FragmentFinish(this, basedirfrag, resultfrags)); SnapContext nullsnapc; object_locator_t oloc(mds->mdsmap->get_metadata_pool()); for (list::iterator p = uf.old_frags.begin(); p != uf.old_frags.end(); ++p) { object_t oid = CInode::get_object_name(basedirfrag.ino, *p, ""); ObjectOperation op; if (*p == frag_t()) { // backtrace object dout(10) << " truncate orphan dirfrag " << oid << dendl; op.truncate(0); op.omap_clear(); } else { dout(10) << " removing orphan dirfrag " << oid << dendl; op.remove(); } mds->objecter->mutate(oid, oloc, op, nullsnapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); } assert(gather.has_subs()); gather.activate(); } void MDCache::_fragment_finish(dirfrag_t basedirfrag, list& resultfrags) { dout(10) << "fragment_finish " << basedirfrag << dendl; map::iterator it = uncommitted_fragments.find(basedirfrag); assert(it != uncommitted_fragments.end()); ufragment &uf = it->second; // unmark & auth_unpin for (list::iterator p = resultfrags.begin(); p != resultfrags.end(); ++p) { (*p)->state_clear(CDir::STATE_FRAGMENTING); (*p)->auth_unpin(this); } EFragment *le = new EFragment(mds->mdlog, EFragment::OP_FINISH, basedirfrag, uf.bits); mds->mdlog->start_submit_entry(le); finish_uncommitted_fragment(basedirfrag, EFragment::OP_FINISH); } /* This function DOES put the passed message before returning */ void MDCache::handle_fragment_notify(MMDSFragmentNotify *notify) { dout(10) << "handle_fragment_notify " << *notify << " from " << notify->get_source() << dendl; if (mds->get_state() < MDSMap::STATE_REJOIN) { notify->put(); return; } CInode *diri = get_inode(notify->get_ino()); if (diri) { frag_t base = notify->get_basefrag(); int bits = notify->get_bits(); /* if ((bits < 0 && diri->dirfragtree.is_leaf(base)) || (bits > 0 && !diri->dirfragtree.is_leaf(base))) { dout(10) << " dft " << diri->dirfragtree << " state doesn't match " << base << " by " << bits << ", must have found out during resolve/rejoin? ignoring. " << *diri << dendl; notify->put(); return; } */ // refragment list waiters; list resultfrags; adjust_dir_fragments(diri, base, bits, resultfrags, waiters, false); if (g_conf->mds_debug_frag) diri->verify_dirfrags(); for (list::iterator p = resultfrags.begin(); p != resultfrags.end(); ++p) diri->take_dir_waiting((*p)->get_frag(), waiters); // add new replica dirs values bufferlist::iterator p = notify->basebl.begin(); while (!p.end()) add_replica_dir(p, diri, notify->get_source().num(), waiters); mds->queue_waiters(waiters); } else { assert(0); } notify->put(); } void MDCache::add_uncommitted_fragment(dirfrag_t basedirfrag, int bits, list& old_frags, LogSegment *ls, bufferlist *rollback) { dout(10) << "add_uncommitted_fragment: base dirfrag " << basedirfrag << " bits " << bits << dendl; assert(!uncommitted_fragments.count(basedirfrag)); ufragment& uf = uncommitted_fragments[basedirfrag]; uf.old_frags = old_frags; uf.bits = bits; uf.ls = ls; ls->uncommitted_fragments.insert(basedirfrag); if (rollback) uf.rollback.swap(*rollback); } void MDCache::finish_uncommitted_fragment(dirfrag_t basedirfrag, int op) { dout(10) << "finish_uncommitted_fragments: base dirfrag " << basedirfrag << " op " << EFragment::op_name(op) << dendl; map::iterator it = uncommitted_fragments.find(basedirfrag); if (it != uncommitted_fragments.end()) { ufragment& uf = it->second; if (op != EFragment::OP_FINISH && !uf.old_frags.empty()) { uf.committed = true; } else { uf.ls->uncommitted_fragments.erase(basedirfrag); mds->queue_waiters(uf.waiters); uncommitted_fragments.erase(it); } } } void MDCache::rollback_uncommitted_fragment(dirfrag_t basedirfrag, list& old_frags) { dout(10) << "rollback_uncommitted_fragment: base dirfrag " << basedirfrag << " old_frags (" << old_frags << ")" << dendl; map::iterator it = uncommitted_fragments.find(basedirfrag); if (it != uncommitted_fragments.end()) { ufragment& uf = it->second; if (!uf.old_frags.empty()) { uf.old_frags.swap(old_frags); uf.committed = true; } else { uf.ls->uncommitted_fragments.erase(basedirfrag); uncommitted_fragments.erase(it); } } } void MDCache::rollback_uncommitted_fragments() { dout(10) << "rollback_uncommitted_fragments: " << uncommitted_fragments.size() << " pending" << dendl; for (map::iterator p = uncommitted_fragments.begin(); p != uncommitted_fragments.end(); ++p) { ufragment &uf = p->second; CInode *diri = get_inode(p->first.ino); assert(diri); if (uf.committed) { list frags; diri->get_dirfrags_under(p->first.frag, frags); for (list::iterator q = frags.begin(); q != frags.end(); ++q) { CDir *dir = *q; dir->auth_pin(this); dir->state_set(CDir::STATE_FRAGMENTING); } _fragment_committed(p->first, frags); continue; } dout(10) << " rolling back " << p->first << " refragment by " << uf.bits << " bits" << dendl; LogSegment *ls = mds->mdlog->get_current_segment(); EFragment *le = new EFragment(mds->mdlog, EFragment::OP_ROLLBACK, p->first, uf.bits); mds->mdlog->start_entry(le); bool diri_auth = (diri->authority() != CDIR_AUTH_UNDEF); list old_frags; diri->dirfragtree.get_leaves_under(p->first.frag, old_frags); list resultfrags; if (uf.old_frags.empty()) { // created by old format EFragment list waiters; adjust_dir_fragments(diri, p->first.frag, -uf.bits, resultfrags, waiters, true); } else { bufferlist::iterator bp = uf.rollback.begin(); for (list::iterator q = uf.old_frags.begin(); q != uf.old_frags.end(); ++q) { CDir *dir = force_dir_fragment(diri, *q); resultfrags.push_back(dir); dirfrag_rollback rollback; ::decode(rollback, bp); dir->set_version(rollback.fnode.version); dir->fnode = rollback.fnode; dir->_mark_dirty(ls); if (!(dir->fnode.rstat == dir->fnode.accounted_rstat)) { dout(10) << " dirty nestinfo on " << *dir << dendl; mds->locker->mark_updated_scatterlock(&dir->inode->nestlock); ls->dirty_dirfrag_nest.push_back(&dir->inode->item_dirty_dirfrag_nest); } if (!(dir->fnode.fragstat == dir->fnode.accounted_fragstat)) { dout(10) << " dirty fragstat on " << *dir << dendl; mds->locker->mark_updated_scatterlock(&dir->inode->filelock); ls->dirty_dirfrag_dir.push_back(&dir->inode->item_dirty_dirfrag_dir); } le->add_orig_frag(dir->get_frag()); le->metablob.add_dir_context(dir); if (diri_auth) { le->metablob.add_fragmented_dir(dir, true, false); } else { dout(10) << " dirty dirfragtree on " << *dir << dendl; dir->state_set(CDir::STATE_DIRTYDFT); le->metablob.add_fragmented_dir(dir, true, true); } } } if (diri_auth) { diri->project_inode()->version = diri->pre_dirty(); diri->pop_and_dirty_projected_inode(ls); // hacky le->metablob.add_primary_dentry(diri->get_projected_parent_dn(), diri, true); } else { mds->locker->mark_updated_scatterlock(&diri->dirfragtreelock); ls->dirty_dirfrag_dirfragtree.push_back(&diri->item_dirty_dirfrag_dirfragtree); } if (g_conf->mds_debug_frag) diri->verify_dirfrags(); for (list::iterator q = old_frags.begin(); q != old_frags.end(); ++q) assert(!diri->dirfragtree.is_leaf(*q)); for (list::iterator q = resultfrags.begin(); q != resultfrags.end(); ++q) { CDir *dir = *q; dir->auth_pin(this); dir->state_set(CDir::STATE_FRAGMENTING); } mds->mdlog->submit_entry(le); uf.old_frags.swap(old_frags); _fragment_committed(p->first, resultfrags); } } // ============================================================== // debug crap void MDCache::show_subtrees(int dbl) { //dout(10) << "show_subtrees" << dendl; if (!g_conf->subsys.should_gather(ceph_subsys_mds, dbl)) return; // i won't print anything. if (subtrees.empty()) { dout(dbl) << "show_subtrees - no subtrees" << dendl; return; } // root frags list basefrags; for (set::iterator p = base_inodes.begin(); p != base_inodes.end(); ++p) (*p)->get_dirfrags(basefrags); //dout(15) << "show_subtrees, base dirfrags " << basefrags << dendl; dout(15) << "show_subtrees" << dendl; // queue stuff list > q; string indent; set seen; // calc max depth for (list::iterator p = basefrags.begin(); p != basefrags.end(); ++p) q.push_back(pair(*p, 0)); set subtrees_seen; int depth = 0; while (!q.empty()) { CDir *dir = q.front().first; int d = q.front().second; q.pop_front(); if (subtrees.count(dir) == 0) continue; subtrees_seen.insert(dir); if (d > depth) depth = d; // sanity check //dout(25) << "saw depth " << d << " " << *dir << dendl; if (seen.count(dir)) dout(0) << "aah, already seen " << *dir << dendl; assert(seen.count(dir) == 0); seen.insert(dir); // nested items? if (!subtrees[dir].empty()) { for (set::iterator p = subtrees[dir].begin(); p != subtrees[dir].end(); ++p) { //dout(25) << " saw sub " << **p << dendl; q.push_front(pair(*p, d+1)); } } } // print tree for (list::iterator p = basefrags.begin(); p != basefrags.end(); ++p) q.push_back(pair(*p, 0)); while (!q.empty()) { CDir *dir = q.front().first; int d = q.front().second; q.pop_front(); if (subtrees.count(dir) == 0) continue; // adjust indenter while ((unsigned)d < indent.size()) indent.resize(d); // pad string pad = "______________________________________"; pad.resize(depth*2+1-indent.size()); if (!subtrees[dir].empty()) pad[0] = '.'; // parent string auth; if (dir->is_auth()) auth = "auth "; else auth = " rep "; char s[10]; if (dir->get_dir_auth().second == CDIR_AUTH_UNKNOWN) snprintf(s, sizeof(s), "%2d ", dir->get_dir_auth().first); else snprintf(s, sizeof(s), "%2d,%2d", dir->get_dir_auth().first, dir->get_dir_auth().second); // print dout(dbl) << indent << "|_" << pad << s << " " << auth << *dir << dendl; if (dir->ino() == MDS_INO_ROOT) assert(dir->inode == root); if (dir->ino() == MDS_INO_MDSDIR(mds->get_nodeid())) assert(dir->inode == myin); if (dir->inode->is_stray() && (MDS_INO_STRAY_OWNER(dir->ino()) == mds->get_nodeid())) assert(strays[MDS_INO_STRAY_INDEX(dir->ino())] == dir->inode); // nested items? if (!subtrees[dir].empty()) { // more at my level? if (!q.empty() && q.front().second == d) indent += "| "; else indent += " "; for (set::iterator p = subtrees[dir].begin(); p != subtrees[dir].end(); ++p) q.push_front(pair(*p, d+2)); } } // verify there isn't stray crap in subtree map int lost = 0; for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { if (subtrees_seen.count(p->first)) continue; dout(10) << "*** stray/lost entry in subtree map: " << *p->first << dendl; lost++; } assert(lost == 0); } void MDCache::show_cache() { dout(7) << "show_cache" << dendl; for (ceph::unordered_map::iterator it = inode_map.begin(); it != inode_map.end(); ++it) { // unlinked? if (!it->second->parent) dout(7) << " unlinked " << *it->second << dendl; // dirfrags? list dfs; it->second->get_dirfrags(dfs); for (list::iterator p = dfs.begin(); p != dfs.end(); ++p) { CDir *dir = *p; dout(7) << " dirfrag " << *dir << dendl; for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) { CDentry *dn = p->second; dout(7) << " dentry " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_linkage(); if (dnl->is_primary() && dnl->get_inode()) dout(7) << " inode " << *dnl->get_inode() << dendl; } } } } void MDCache::dump_cache(const char *fn) { int r; char deffn[200]; if (!fn) { snprintf(deffn, sizeof(deffn), "cachedump.%d.mds%d", (int)mds->mdsmap->get_epoch(), mds->get_nodeid()); fn = deffn; } dout(1) << "dump_cache to " << fn << dendl; int fd = ::open(fn, O_WRONLY|O_CREAT|O_EXCL, 0600); if (fd < 0) { derr << "failed to open " << fn << ": " << cpp_strerror(errno) << dendl; return; } for (ceph::unordered_map::iterator it = inode_map.begin(); it != inode_map.end(); ++it) { CInode *in = it->second; ostringstream ss; ss << *in << std::endl; std::string s = ss.str(); r = safe_write(fd, s.c_str(), s.length()); if (r < 0) goto out; list dfs; in->get_dirfrags(dfs); for (list::iterator p = dfs.begin(); p != dfs.end(); ++p) { CDir *dir = *p; ostringstream tt; tt << " " << *dir << std::endl; string t = tt.str(); r = safe_write(fd, t.c_str(), t.length()); if (r < 0) goto out; for (CDir::map_t::iterator q = dir->items.begin(); q != dir->items.end(); ++q) { CDentry *dn = q->second; ostringstream uu; uu << " " << *dn << std::endl; string u = uu.str(); r = safe_write(fd, u.c_str(), u.length()); if (r < 0) goto out; } dir->check_rstats(); } } out: ::close(fd); } C_MDS_RetryRequest::C_MDS_RetryRequest(MDCache *c, MDRequestRef& r) : cache(c), mdr(r) {} void C_MDS_RetryRequest::finish(int r) { mdr->retry++; cache->dispatch_request(mdr); } ceph-0.80.11/src/mds/flock.h0000664000175100017510000002120412623076744017515 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_MDS_FLOCK_H #define CEPH_MDS_FLOCK_H #include #include "common/debug.h" #include "mdstypes.h" inline ostream& operator<<(ostream& out, ceph_filelock& l) { out << "start: " << l.start << ", length: " << l.length << ", client: " << l.client << ", owner: " << l.owner << ", pid: " << l.pid << ", type: " << (int)l.type << std::endl; return out; } inline bool ceph_filelock_owner_equal(ceph_filelock& l, ceph_filelock& r) { if (l.client != r.client || l.owner != r.owner) return false; // The file lock is from old client if the most significant bit of // 'owner' is not set. Old clients use both 'owner' and 'pid' to // identify the owner of lock. if (l.owner & (1ULL << 63)) return true; return l.pid == r.pid; } inline bool operator==(ceph_filelock& l, ceph_filelock& r) { return l.length == r.length && l.type == r.type && ceph_filelock_owner_equal(l, r); } class ceph_lock_state_t { CephContext *cct; public: ceph_lock_state_t(CephContext *cct_) : cct(cct_) {} multimap held_locks; // current locks multimap waiting_locks; // locks waiting for other locks // both of the above are keyed by starting offset map client_held_lock_counts; map client_waiting_lock_counts; /** * Check if a lock is on the waiting_locks list. * * @param fl The filelock to check for * @returns True if the lock is waiting, false otherwise */ bool is_waiting(ceph_filelock &fl); /** * Remove a lock from the waiting_locks list * * @param fl The filelock to remove */ void remove_waiting(ceph_filelock& fl); /* * Try to set a new lock. If it's blocked and wait_on_fail is true, * add the lock to waiting_locks. * The lock needs to be of type CEPH_LOCK_EXCL or CEPH_LOCK_SHARED. * This may merge previous locks, or convert the type of already-owned * locks. * * @param new_lock The lock to set * @param wait_on_fail whether to wait until the lock can be set. * Otherwise it fails immediately when blocked. * * @returns true if set, false if not set. */ bool add_lock(ceph_filelock& new_lock, bool wait_on_fail, bool replay); /** * See if a lock is blocked by existing locks. If the lock is blocked, * it will be set to the value of the first blocking lock. Otherwise, * it will be returned unchanged, except for setting the type field * to CEPH_LOCK_UNLOCK. * * @param testing_lock The lock to check for conflicts on. */ void look_for_lock(ceph_filelock& testing_lock); /* * Remove lock(s) described in old_lock. This may involve splitting a * previous lock or making a previous lock smaller. * * @param removal_lock The lock to remove * @param activated_locks A return parameter, holding activated wait locks. */ void remove_lock(ceph_filelock removal_lock, list& activated_locks); bool remove_all_from(client_t client); private: /** * Adjust old locks owned by a single process so that process can set * a new lock of different type. Handle any changes needed to the old locks * (and the new lock) so that once the new lock is inserted into the * held_locks list the process has a coherent, non-fragmented set of lock * ranges. Make sure any overlapping locks are combined, trimmed, and removed * as needed. * This function should only be called once you know the lock will be * inserted, as it DOES adjust new_lock. You can call this function * on an empty list, in which case it does nothing. * This function does not remove elements from old_locks, so regard the list * as bad information following function invocation. * * @param new_lock The new lock the process has requested. * @param old_locks list of all locks currently held by same * client/process that overlap new_lock. * @param neighbor_locks locks owned by same process that neighbor new_lock on * left or right side. */ void adjust_locks(list::iterator> old_locks, ceph_filelock& new_lock, list::iterator> neighbor_locks); //this won't reset the counter map value, do that yourself void remove_all_from(client_t client, multimap& locks); //get last lock prior to start position multimap::iterator get_lower_bound(uint64_t start, multimap& lock_map); //get latest-starting lock that goes over the byte "end" multimap::iterator get_last_before(uint64_t end, multimap& lock_map); /* * See if an iterator's lock covers any of the same bounds as a given range * Rules: locks cover "length" bytes from "start", so the last covered * byte is at start + length - 1. * If the length is 0, the lock covers from "start" to the end of the file. */ bool share_space(multimap::iterator& iter, uint64_t start, uint64_t end); bool share_space(multimap::iterator& iter, ceph_filelock &lock) { uint64_t end = lock.start; if (lock.length) { end += lock.length - 1; } else { // zero length means end of file end = uint64_t(-1); } return share_space(iter, lock.start, end); } /* *get a list of all locks overlapping with the given lock's range * lock: the lock to compare with. * overlaps: an empty list, to be filled. * Returns: true if at least one lock overlaps. */ bool get_overlapping_locks(ceph_filelock& lock, list::iterator> & overlaps, list::iterator> *self_neighbors); bool get_overlapping_locks(ceph_filelock& lock, list::iterator>& overlaps) { return get_overlapping_locks(lock, overlaps, NULL); } /** * Get a list of all waiting locks that overlap with the given lock's range. * lock: specifies the range to compare with * overlaps: an empty list, to be filled * Returns: true if at least one waiting_lock overlaps */ bool get_waiting_overlaps(ceph_filelock& lock, list::iterator>& overlaps); /* * split a list of locks up by whether they're owned by same * process as given lock * owner: the owning lock * locks: the list of locks (obtained from get_overlapping_locks, probably) * Will have all locks owned by owner removed * owned_locks: an empty list, to be filled with the locks owned by owner */ void split_by_owner(ceph_filelock& owner, list::iterator> & locks, list::iterator> & owned_locks); ceph_filelock *contains_exclusive_lock(list::iterator>& locks); public: void encode(bufferlist& bl) const { ::encode(held_locks, bl); ::encode(waiting_locks, bl); ::encode(client_held_lock_counts, bl); ::encode(client_waiting_lock_counts, bl); } void decode(bufferlist::iterator& bl) { ::decode(held_locks, bl); ::decode(waiting_locks, bl); ::decode(client_held_lock_counts, bl); ::decode(client_waiting_lock_counts, bl); } void clear() { held_locks.clear(); waiting_locks.clear(); client_held_lock_counts.clear(); client_waiting_lock_counts.clear(); } }; WRITE_CLASS_ENCODER(ceph_lock_state_t) inline ostream& operator<<(ostream& out, ceph_lock_state_t& l) { out << "ceph_lock_state_t. held_locks.size()=" << l.held_locks.size() << ", waiting_locks.size()=" << l.waiting_locks.size() << ", client_held_lock_counts -- " << l.client_held_lock_counts << "\n client_waiting_lock_counts -- " << l.client_waiting_lock_counts << "\n held_locks -- "; for (multimap::iterator iter = l.held_locks.begin(); iter != l.held_locks.end(); ++iter) out << iter->second; out << "\n waiting_locks -- "; for (multimap::iterator iter =l.waiting_locks.begin(); iter != l.waiting_locks.end(); ++iter) out << iter->second << "\n"; return out; } #endif ceph-0.80.11/src/mds/MDSTableServer.cc0000664000175100017510000001225012623076744021340 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDSTableServer.h" #include "MDS.h" #include "MDLog.h" #include "msg/Messenger.h" #include "messages/MMDSTableRequest.h" #include "events/ETableServer.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".tableserver(" << get_mdstable_name(table) << ") " /* This function DOES put the passed message before returning */ void MDSTableServer::handle_request(MMDSTableRequest *req) { assert(req->op >= 0); switch (req->op) { case TABLESERVER_OP_QUERY: return handle_query(req); case TABLESERVER_OP_PREPARE: return handle_prepare(req); case TABLESERVER_OP_COMMIT: return handle_commit(req); case TABLESERVER_OP_ROLLBACK: return handle_rollback(req); default: assert(0); } } // prepare /* This function DOES put the passed message before returning */ void MDSTableServer::handle_prepare(MMDSTableRequest *req) { dout(7) << "handle_prepare " << *req << dendl; int from = req->get_source().num(); bufferlist bl = req->bl; _prepare(req->bl, req->reqid, from); _note_prepare(from, req->reqid); assert(g_conf->mds_kill_mdstable_at != 1); ETableServer *le = new ETableServer(table, TABLESERVER_OP_PREPARE, req->reqid, from, version, version); mds->mdlog->start_entry(le); le->mutation = bl; // original request, NOT modified return value coming out of _prepare! mds->mdlog->submit_entry(le, new C_Prepare(this, req, version)); mds->mdlog->flush(); } void MDSTableServer::_prepare_logged(MMDSTableRequest *req, version_t tid) { dout(7) << "_create_logged " << *req << " tid " << tid << dendl; assert(g_conf->mds_kill_mdstable_at != 2); MMDSTableRequest *reply = new MMDSTableRequest(table, TABLESERVER_OP_AGREE, req->reqid, tid); reply->bl = req->bl; mds->send_message_mds(reply, req->get_source().num()); req->put(); } // commit /* This function DOES put the passed message before returning */ void MDSTableServer::handle_commit(MMDSTableRequest *req) { dout(7) << "handle_commit " << *req << dendl; version_t tid = req->get_tid(); if (pending_for_mds.count(tid)) { assert(g_conf->mds_kill_mdstable_at != 5); if (!_commit(tid, req)) return; _note_commit(tid); mds->mdlog->start_submit_entry(new ETableServer(table, TABLESERVER_OP_COMMIT, 0, -1, tid, version)); mds->mdlog->wait_for_safe(new C_Commit(this, req)); } else if (tid <= version) { dout(0) << "got commit for tid " << tid << " <= " << version << ", already committed, sending ack." << dendl; _commit_logged(req); } else { // wtf. dout(0) << "got commit for tid " << tid << " > " << version << dendl; assert(tid <= version); } } /* This function DOES put the passed message before returning */ void MDSTableServer::_commit_logged(MMDSTableRequest *req) { dout(7) << "_commit_logged, sending ACK" << dendl; assert(g_conf->mds_kill_mdstable_at != 6); MMDSTableRequest *reply = new MMDSTableRequest(table, TABLESERVER_OP_ACK, req->reqid, req->get_tid()); mds->send_message_mds(reply, req->get_source().num()); req->put(); } // ROLLBACK /* This function DOES put the passed message before returning */ void MDSTableServer::handle_rollback(MMDSTableRequest *req) { dout(7) << "handle_rollback " << *req << dendl; version_t tid = req->get_tid(); assert(pending_for_mds.count(tid)); _rollback(tid); _note_rollback(tid); mds->mdlog->start_submit_entry(new ETableServer(table, TABLESERVER_OP_ROLLBACK, 0, -1, tid, version)); req->put(); } // SERVER UPDATE void MDSTableServer::do_server_update(bufferlist& bl) { dout(10) << "do_server_update len " << bl.length() << dendl; _server_update(bl); ETableServer *le = new ETableServer(table, TABLESERVER_OP_SERVER_UPDATE, 0, -1, 0, version); mds->mdlog->start_entry(le); le->mutation = bl; mds->mdlog->submit_entry(le); } // recovery void MDSTableServer::finish_recovery(set& active) { dout(7) << "finish_recovery" << dendl; for (set::iterator p = active.begin(); p != active.end(); ++p) handle_mds_recovery(*p); // resend agrees for everyone. } void MDSTableServer::handle_mds_recovery(int who) { dout(7) << "handle_mds_recovery mds." << who << dendl; uint64_t next_reqid = 0; // resend agrees for recovered mds for (map::iterator p = pending_for_mds.begin(); p != pending_for_mds.end(); ++p) { if (p->second.mds != who) continue; if (p->second.reqid >= next_reqid) next_reqid = p->second.reqid + 1; MMDSTableRequest *reply = new MMDSTableRequest(table, TABLESERVER_OP_AGREE, p->second.reqid, p->second.tid); mds->send_message_mds(reply, who); } MMDSTableRequest *reply = new MMDSTableRequest(table, TABLESERVER_OP_SERVER_READY, next_reqid); mds->send_message_mds(reply, who); } ceph-0.80.11/src/mds/CDir.cc0000664000175100017510000021131412623076744017401 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "CDir.h" #include "CDentry.h" #include "CInode.h" #include "Mutation.h" #include "MDSMap.h" #include "MDS.h" #include "MDCache.h" #include "Locker.h" #include "MDLog.h" #include "LogSegment.h" #include "common/bloom_filter.hpp" #include "include/Context.h" #include "common/Clock.h" #include "osdc/Objecter.h" #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << cache->mds->get_nodeid() << ".cache.dir(" << this->dirfrag() << ") " // PINS //int cdir_pins[CDIR_NUM_PINS] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; boost::pool<> CDir::pool(sizeof(CDir)); ostream& operator<<(ostream& out, CDir& dir) { string path; dir.get_inode()->make_path_string_projected(path); out << "[dir " << dir.dirfrag() << " " << path << "/" << " [" << dir.first << ",head]"; if (dir.is_auth()) { out << " auth"; if (dir.is_replicated()) out << dir.get_replicas(); if (dir.is_projected()) out << " pv=" << dir.get_projected_version(); out << " v=" << dir.get_version(); out << " cv=" << dir.get_committing_version(); out << "/" << dir.get_committed_version(); } else { pair a = dir.authority(); out << " rep@" << a.first; if (a.second != CDIR_AUTH_UNKNOWN) out << "," << a.second; out << "." << dir.get_replica_nonce(); } if (dir.is_rep()) out << " REP"; if (dir.get_dir_auth() != CDIR_AUTH_DEFAULT) { if (dir.get_dir_auth().second == CDIR_AUTH_UNKNOWN) out << " dir_auth=" << dir.get_dir_auth().first; else out << " dir_auth=" << dir.get_dir_auth(); } if (dir.get_cum_auth_pins()) out << " ap=" << dir.get_auth_pins() << "+" << dir.get_dir_auth_pins() << "+" << dir.get_nested_auth_pins(); if (dir.get_nested_anchors()) out << " na=" << dir.get_nested_anchors(); out << " state=" << dir.get_state(); if (dir.state_test(CDir::STATE_COMPLETE)) out << "|complete"; if (dir.state_test(CDir::STATE_FREEZINGTREE)) out << "|freezingtree"; if (dir.state_test(CDir::STATE_FROZENTREE)) out << "|frozentree"; //if (dir.state_test(CDir::STATE_FROZENTREELEAF)) out << "|frozentreeleaf"; if (dir.state_test(CDir::STATE_FROZENDIR)) out << "|frozendir"; if (dir.state_test(CDir::STATE_FREEZINGDIR)) out << "|freezingdir"; if (dir.state_test(CDir::STATE_EXPORTBOUND)) out << "|exportbound"; if (dir.state_test(CDir::STATE_IMPORTBOUND)) out << "|importbound"; // fragstat out << " " << dir.fnode.fragstat; if (!(dir.fnode.fragstat == dir.fnode.accounted_fragstat)) out << "/" << dir.fnode.accounted_fragstat; if (g_conf->mds_debug_scatterstat && dir.is_projected()) { fnode_t *pf = dir.get_projected_fnode(); out << "->" << pf->fragstat; if (!(pf->fragstat == pf->accounted_fragstat)) out << "/" << pf->accounted_fragstat; } // rstat out << " " << dir.fnode.rstat; if (!(dir.fnode.rstat == dir.fnode.accounted_rstat)) out << "/" << dir.fnode.accounted_rstat; if (g_conf->mds_debug_scatterstat && dir.is_projected()) { fnode_t *pf = dir.get_projected_fnode(); out << "->" << pf->rstat; if (!(pf->rstat == pf->accounted_rstat)) out << "/" << pf->accounted_rstat; } out << " hs=" << dir.get_num_head_items() << "+" << dir.get_num_head_null(); out << ",ss=" << dir.get_num_snap_items() << "+" << dir.get_num_snap_null(); if (dir.get_num_dirty()) out << " dirty=" << dir.get_num_dirty(); if (dir.get_num_ref()) { out << " |"; dir.print_pin_set(out); } out << " " << &dir; return out << "]"; } void CDir::print(ostream& out) { out << *this; } ostream& CDir::print_db_line_prefix(ostream& out) { return out << ceph_clock_now(g_ceph_context) << " mds." << cache->mds->get_nodeid() << ".cache.dir(" << this->dirfrag() << ") "; } // ------------------------------------------------------------------- // CDir CDir::CDir(CInode *in, frag_t fg, MDCache *mdcache, bool auth) : dirty_rstat_inodes(member_offset(CInode, dirty_rstat_item)), item_dirty(this), item_new(this), pop_me(ceph_clock_now(g_ceph_context)), pop_nested(ceph_clock_now(g_ceph_context)), pop_auth_subtree(ceph_clock_now(g_ceph_context)), pop_auth_subtree_nested(ceph_clock_now(g_ceph_context)), bloom(NULL) { g_num_dir++; g_num_dira++; inode = in; frag = fg; this->cache = mdcache; first = 2; num_head_items = num_head_null = 0; num_snap_items = num_snap_null = 0; num_dirty = 0; num_dentries_nested = 0; num_dentries_auth_subtree = 0; num_dentries_auth_subtree_nested = 0; state = STATE_INITIAL; memset(&fnode, 0, sizeof(fnode)); projected_version = 0; committing_version = 0; committed_version = 0; // dir_auth dir_auth = CDIR_AUTH_DEFAULT; // auth assert(in->is_dir()); if (auth) state |= STATE_AUTH; auth_pins = 0; nested_auth_pins = 0; dir_auth_pins = 0; request_pins = 0; nested_anchors = 0; dir_rep = REP_NONE; } /** * Check the recursive statistics on size for consistency. * If mds_debug_scatterstat is enabled, assert for correctness, * otherwise just print out the mismatch and continue. */ bool CDir::check_rstats() { if (!g_conf->mds_debug_scatterstat) return true; dout(25) << "check_rstats on " << this << dendl; if (!is_complete() || !is_auth() || is_frozen()) { dout(10) << "check_rstats bailing out -- incomplete or non-auth or frozen dir!" << dendl; return true; } // fragstat if(!(get_num_head_items()== (fnode.fragstat.nfiles + fnode.fragstat.nsubdirs))) { dout(1) << "mismatch between head items and fnode.fragstat! printing dentries" << dendl; dout(1) << "get_num_head_items() = " << get_num_head_items() << "; fnode.fragstat.nfiles=" << fnode.fragstat.nfiles << " fnode.fragstat.nsubdirs=" << fnode.fragstat.nsubdirs << dendl; for (map_t::iterator i = items.begin(); i != items.end(); ++i) { //if (i->second->get_linkage()->is_primary()) dout(1) << *(i->second) << dendl; } assert(get_num_head_items() == (fnode.fragstat.nfiles + fnode.fragstat.nsubdirs)); } else { dout(20) << "get_num_head_items() = " << get_num_head_items() << "; fnode.fragstat.nfiles=" << fnode.fragstat.nfiles << " fnode.fragstat.nsubdirs=" << fnode.fragstat.nsubdirs << dendl; } // rstat nest_info_t sub_info; for (map_t::iterator i = items.begin(); i != items.end(); ++i) { if (i->second->get_linkage()->is_primary() && i->second->last == CEPH_NOSNAP) { sub_info.add(i->second->get_linkage()->inode->inode.accounted_rstat); } } if ((!(sub_info.rbytes == fnode.rstat.rbytes)) || (!(sub_info.rfiles == fnode.rstat.rfiles)) || (!(sub_info.rsubdirs == fnode.rstat.rsubdirs))) { dout(1) << "mismatch between child accounted_rstats and my rstats!" << dendl; dout(1) << "total of child dentrys: " << sub_info << dendl; dout(1) << "my rstats: " << fnode.rstat << dendl; for (map_t::iterator i = items.begin(); i != items.end(); ++i) { if (i->second->get_linkage()->is_primary()) { dout(1) << *(i->second) << " " << i->second->get_linkage()->inode->inode.accounted_rstat << dendl; } } } else { dout(25) << "total of child dentrys: " << sub_info << dendl; dout(25) << "my rstats: " << fnode.rstat << dendl; } assert(sub_info.rbytes == fnode.rstat.rbytes); assert(sub_info.rfiles == fnode.rstat.rfiles); assert(sub_info.rsubdirs == fnode.rstat.rsubdirs); dout(10) << "check_rstats complete on " << this << dendl; return true; } CDentry *CDir::lookup(const char *name, snapid_t snap) { dout(20) << "lookup (" << snap << ", '" << name << "')" << dendl; map_t::iterator iter = items.lower_bound(dentry_key_t(snap, name)); if (iter == items.end()) return 0; if (iter->second->name == name && iter->second->first <= snap) { dout(20) << " hit -> " << iter->first << dendl; return iter->second; } dout(20) << " miss -> " << iter->first << dendl; return 0; } /*** * linking fun */ CDentry* CDir::add_null_dentry(const string& dname, snapid_t first, snapid_t last) { // foreign assert(lookup_exact_snap(dname, last) == 0); // create dentry CDentry* dn = new CDentry(dname, inode->hash_dentry_name(dname), first, last); if (is_auth()) dn->state_set(CDentry::STATE_AUTH); cache->lru.lru_insert_mid(dn); dn->dir = this; dn->version = get_projected_version(); // add to dir assert(items.count(dn->key()) == 0); //assert(null_items.count(dn->name) == 0); items[dn->key()] = dn; if (last == CEPH_NOSNAP) num_head_null++; else num_snap_null++; if (state_test(CDir::STATE_DNPINNEDFRAG)) { dn->get(CDentry::PIN_FRAGMENTING); dn->state_set(CDentry::STATE_FRAGMENTING); } dout(12) << "add_null_dentry " << *dn << dendl; // pin? if (get_num_any() == 1) get(PIN_CHILD); assert(get_num_any() == items.size()); return dn; } CDentry* CDir::add_primary_dentry(const string& dname, CInode *in, snapid_t first, snapid_t last) { // primary assert(lookup_exact_snap(dname, last) == 0); // create dentry CDentry* dn = new CDentry(dname, inode->hash_dentry_name(dname), first, last); if (is_auth()) dn->state_set(CDentry::STATE_AUTH); cache->lru.lru_insert_mid(dn); dn->dir = this; dn->version = get_projected_version(); // add to dir assert(items.count(dn->key()) == 0); //assert(null_items.count(dn->name) == 0); items[dn->key()] = dn; dn->get_linkage()->inode = in; in->set_primary_parent(dn); link_inode_work(dn, in); if (dn->last == CEPH_NOSNAP) num_head_items++; else num_snap_items++; if (state_test(CDir::STATE_DNPINNEDFRAG)) { dn->get(CDentry::PIN_FRAGMENTING); dn->state_set(CDentry::STATE_FRAGMENTING); } dout(12) << "add_primary_dentry " << *dn << dendl; // pin? if (get_num_any() == 1) get(PIN_CHILD); assert(get_num_any() == items.size()); return dn; } CDentry* CDir::add_remote_dentry(const string& dname, inodeno_t ino, unsigned char d_type, snapid_t first, snapid_t last) { // foreign assert(lookup_exact_snap(dname, last) == 0); // create dentry CDentry* dn = new CDentry(dname, inode->hash_dentry_name(dname), ino, d_type, first, last); if (is_auth()) dn->state_set(CDentry::STATE_AUTH); cache->lru.lru_insert_mid(dn); dn->dir = this; dn->version = get_projected_version(); // add to dir assert(items.count(dn->key()) == 0); //assert(null_items.count(dn->name) == 0); items[dn->key()] = dn; if (last == CEPH_NOSNAP) num_head_items++; else num_snap_items++; if (state_test(CDir::STATE_DNPINNEDFRAG)) { dn->get(CDentry::PIN_FRAGMENTING); dn->state_set(CDentry::STATE_FRAGMENTING); } dout(12) << "add_remote_dentry " << *dn << dendl; // pin? if (get_num_any() == 1) get(PIN_CHILD); assert(get_num_any() == items.size()); return dn; } void CDir::remove_dentry(CDentry *dn) { dout(12) << "remove_dentry " << *dn << dendl; // there should be no client leases at this point! assert(dn->client_lease_map.empty()); if (state_test(CDir::STATE_DNPINNEDFRAG)) { dn->put(CDentry::PIN_FRAGMENTING); dn->state_clear(CDentry::STATE_FRAGMENTING); } if (dn->get_linkage()->is_null()) { if (dn->last == CEPH_NOSNAP) num_head_null--; else num_snap_null--; } else { if (dn->last == CEPH_NOSNAP) num_head_items--; else num_snap_items--; } if (!dn->get_linkage()->is_null()) // detach inode and dentry unlink_inode_work(dn); // remove from list assert(items.count(dn->key()) == 1); items.erase(dn->key()); // clean? if (dn->is_dirty()) dn->mark_clean(); cache->lru.lru_remove(dn); delete dn; // unpin? if (get_num_any() == 0) put(PIN_CHILD); assert(get_num_any() == items.size()); } void CDir::link_remote_inode(CDentry *dn, CInode *in) { link_remote_inode(dn, in->ino(), IFTODT(in->get_projected_inode()->mode)); } void CDir::link_remote_inode(CDentry *dn, inodeno_t ino, unsigned char d_type) { dout(12) << "link_remote_inode " << *dn << " remote " << ino << dendl; assert(dn->get_linkage()->is_null()); dn->get_linkage()->set_remote(ino, d_type); if (dn->last == CEPH_NOSNAP) { num_head_items++; num_head_null--; } else { num_snap_items++; num_snap_null--; } assert(get_num_any() == items.size()); } void CDir::link_primary_inode(CDentry *dn, CInode *in) { dout(12) << "link_primary_inode " << *dn << " " << *in << dendl; assert(dn->get_linkage()->is_null()); dn->get_linkage()->inode = in; in->set_primary_parent(dn); link_inode_work(dn, in); if (dn->last == CEPH_NOSNAP) { num_head_items++; num_head_null--; } else { num_snap_items++; num_snap_null--; } assert(get_num_any() == items.size()); } void CDir::link_inode_work( CDentry *dn, CInode *in) { assert(dn->get_linkage()->get_inode() == in); assert(in->get_parent_dn() == dn); // set inode version //in->inode.version = dn->get_version(); // pin dentry? if (in->get_num_ref()) dn->get(CDentry::PIN_INODEPIN); // adjust auth pin count if (in->auth_pins + in->nested_auth_pins) dn->adjust_nested_auth_pins(in->auth_pins + in->nested_auth_pins, in->auth_pins, NULL); if (in->inode.anchored + in->nested_anchors) dn->adjust_nested_anchors(in->nested_anchors + in->inode.anchored); // verify open snaprealm parent if (in->snaprealm) in->snaprealm->adjust_parent(); } void CDir::unlink_inode(CDentry *dn) { if (dn->get_linkage()->is_remote()) { dout(12) << "unlink_inode " << *dn << dendl; } else { dout(12) << "unlink_inode " << *dn << " " << *dn->get_linkage()->get_inode() << dendl; } unlink_inode_work(dn); if (dn->last == CEPH_NOSNAP) { num_head_items--; num_head_null++; } else { num_snap_items--; num_snap_null++; } assert(get_num_any() == items.size()); } void CDir::try_remove_unlinked_dn(CDentry *dn) { assert(dn->dir == this); assert(dn->get_linkage()->is_null()); // no pins (besides dirty)? if (dn->get_num_ref() != dn->is_dirty()) return; // was the dn new? if (dn->is_new()) { dout(10) << "try_remove_unlinked_dn " << *dn << " in " << *this << dendl; if (dn->is_dirty()) dn->mark_clean(); remove_dentry(dn); // NOTE: we may not have any more dirty dentries, but the fnode // still changed, so the directory must remain dirty. } } void CDir::unlink_inode_work( CDentry *dn ) { CInode *in = dn->get_linkage()->get_inode(); if (dn->get_linkage()->is_remote()) { // remote if (in) dn->unlink_remote(dn->get_linkage()); dn->get_linkage()->set_remote(0, 0); } else { // primary assert(dn->get_linkage()->is_primary()); // unpin dentry? if (in->get_num_ref()) dn->put(CDentry::PIN_INODEPIN); // unlink auth_pin count if (in->auth_pins + in->nested_auth_pins) dn->adjust_nested_auth_pins(0 - (in->auth_pins + in->nested_auth_pins), 0 - in->auth_pins, NULL); if (in->inode.anchored + in->nested_anchors) dn->adjust_nested_anchors(0 - (in->nested_anchors + in->inode.anchored)); // detach inode in->remove_primary_parent(dn); dn->get_linkage()->inode = 0; } } void CDir::add_to_bloom(CDentry *dn) { if (!bloom) { /* not create bloom filter for incomplete dir that was added by log replay */ if (!is_complete()) return; unsigned size = get_num_head_items() + get_num_snap_items(); if (size < 100) size = 100; bloom = new bloom_filter(size, 1.0 / size, 0); } /* This size and false positive probability is completely random.*/ bloom->insert(dn->name.c_str(), dn->name.size()); } bool CDir::is_in_bloom(const string& name) { if (!bloom) return false; return bloom->contains(name.c_str(), name.size()); } void CDir::remove_bloom() { delete bloom; bloom = NULL; } void CDir::remove_null_dentries() { dout(12) << "remove_null_dentries " << *this << dendl; CDir::map_t::iterator p = items.begin(); while (p != items.end()) { CDentry *dn = p->second; ++p; if (dn->get_linkage()->is_null() && !dn->is_projected()) remove_dentry(dn); } assert(num_snap_null == 0); assert(num_head_null == 0); assert(get_num_any() == items.size()); } void CDir::touch_dentries_bottom() { dout(12) << "touch_dentries_bottom " << *this << dendl; for (CDir::map_t::iterator p = items.begin(); p != items.end(); ++p) inode->mdcache->touch_dentry_bottom(p->second); } bool CDir::try_trim_snap_dentry(CDentry *dn, const set& snaps) { assert(dn->last != CEPH_NOSNAP); set::const_iterator p = snaps.lower_bound(dn->first); CDentry::linkage_t *dnl= dn->get_linkage(); CInode *in = 0; if (dnl->is_primary()) in = dnl->get_inode(); if ((p == snaps.end() || *p > dn->last) && (dn->get_num_ref() == dn->is_dirty()) && (!in || in->get_num_ref() == in->is_dirty())) { dout(10) << " purging snapped " << *dn << dendl; if (in && in->is_dirty()) in->mark_clean(); remove_dentry(dn); if (in) { dout(10) << " purging snapped " << *in << dendl; cache->remove_inode(in); } return true; } return false; } void CDir::purge_stale_snap_data(const set& snaps) { dout(10) << "purge_stale_snap_data " << snaps << dendl; CDir::map_t::iterator p = items.begin(); while (p != items.end()) { CDentry *dn = p->second; ++p; if (dn->last == CEPH_NOSNAP) continue; try_trim_snap_dentry(dn, snaps); } } /** * steal_dentry -- semi-violently move a dentry from one CDir to another * (*) violently, in that nitems, most pins, etc. are not correctly maintained * on the old CDir corpse; must call finish_old_fragment() when finished. */ void CDir::steal_dentry(CDentry *dn) { dout(15) << "steal_dentry " << *dn << dendl; items[dn->key()] = dn; dn->dir->items.erase(dn->key()); if (dn->dir->items.empty()) dn->dir->put(PIN_CHILD); if (get_num_any() == 0) get(PIN_CHILD); if (dn->get_linkage()->is_null()) { if (dn->last == CEPH_NOSNAP) num_head_null++; else num_snap_null++; } else { if (dn->last == CEPH_NOSNAP) num_head_items++; else num_snap_items++; if (dn->get_linkage()->is_primary()) { CInode *in = dn->get_linkage()->get_inode(); inode_t *pi = in->get_projected_inode(); if (dn->get_linkage()->get_inode()->is_dir()) fnode.fragstat.nsubdirs++; else fnode.fragstat.nfiles++; fnode.rstat.rbytes += pi->accounted_rstat.rbytes; fnode.rstat.rfiles += pi->accounted_rstat.rfiles; fnode.rstat.rsubdirs += pi->accounted_rstat.rsubdirs; fnode.rstat.ranchors += pi->accounted_rstat.ranchors; fnode.rstat.rsnaprealms += pi->accounted_rstat.ranchors; if (pi->accounted_rstat.rctime > fnode.rstat.rctime) fnode.rstat.rctime = pi->accounted_rstat.rctime; // move dirty inode rstat to new dirfrag if (in->is_dirty_rstat()) dirty_rstat_inodes.push_back(&in->dirty_rstat_item); } else if (dn->get_linkage()->is_remote()) { if (dn->get_linkage()->get_remote_d_type() == DT_DIR) fnode.fragstat.nsubdirs++; else fnode.fragstat.nfiles++; } } if (dn->auth_pins || dn->nested_auth_pins) { // use the helpers here to maintain the auth_pin invariants on the dir inode int ap = dn->get_num_auth_pins() + dn->get_num_nested_auth_pins(); int dap = dn->get_num_dir_auth_pins(); assert(dap <= ap); adjust_nested_auth_pins(ap, dap, NULL); dn->dir->adjust_nested_auth_pins(-ap, -dap, NULL); } nested_anchors += dn->nested_anchors; if (dn->is_dirty()) num_dirty++; dn->dir = this; } void CDir::prepare_old_fragment(bool replay) { // auth_pin old fragment for duration so that any auth_pinning // during the dentry migration doesn't trigger side effects if (!replay && is_auth()) auth_pin(this); } void CDir::prepare_new_fragment(bool replay) { if (!replay && is_auth()) { _freeze_dir(); mark_complete(); } } void CDir::finish_old_fragment(list& waiters, bool replay) { // take waiters _before_ unfreeze... if (!replay) { take_waiting(WAIT_ANY_MASK, waiters); if (is_auth()) { auth_unpin(this); // pinned in prepare_old_fragment assert(is_frozen_dir()); unfreeze_dir(); } } assert(nested_auth_pins == 0); assert(dir_auth_pins == 0); assert(auth_pins == 0); num_head_items = num_head_null = 0; num_snap_items = num_snap_null = 0; // this mirrors init_fragment_pins() if (is_auth()) clear_replica_map(); if (is_dirty()) mark_clean(); if (state_test(STATE_IMPORTBOUND)) put(PIN_IMPORTBOUND); if (state_test(STATE_EXPORTBOUND)) put(PIN_EXPORTBOUND); if (is_subtree_root()) put(PIN_SUBTREE); if (auth_pins > 0) put(PIN_AUTHPIN); assert(get_num_ref() == (state_test(STATE_STICKY) ? 1:0)); } void CDir::init_fragment_pins() { if (!replica_map.empty()) get(PIN_REPLICATED); if (state_test(STATE_DIRTY)) get(PIN_DIRTY); if (state_test(STATE_EXPORTBOUND)) get(PIN_EXPORTBOUND); if (state_test(STATE_IMPORTBOUND)) get(PIN_IMPORTBOUND); if (is_subtree_root()) get(PIN_SUBTREE); } void CDir::split(int bits, list& subs, list& waiters, bool replay) { dout(10) << "split by " << bits << " bits on " << *this << dendl; if (cache->mds->logger) cache->mds->logger->inc(l_mds_dir_sp); assert(replay || is_complete() || !is_auth()); list frags; frag.split(bits, frags); vector subfrags(1 << bits); double fac = 1.0 / (double)(1 << bits); // for scaling load vecs dout(15) << " rstat " << fnode.rstat << dendl; dout(15) << " accounted_rstat " << fnode.accounted_rstat << dendl; nest_info_t rstatdiff; rstatdiff.add_delta(fnode.accounted_rstat, fnode.rstat); dout(15) << " fragstat " << fnode.fragstat << dendl; dout(15) << " accounted_fragstat " << fnode.accounted_fragstat << dendl; frag_info_t fragstatdiff; bool touched_mtime; fragstatdiff.add_delta(fnode.accounted_fragstat, fnode.fragstat, touched_mtime); dout(10) << " rstatdiff " << rstatdiff << " fragstatdiff " << fragstatdiff << dendl; prepare_old_fragment(replay); // create subfrag dirs int n = 0; for (list::iterator p = frags.begin(); p != frags.end(); ++p) { CDir *f = new CDir(inode, *p, cache, is_auth()); f->state_set(state & (MASK_STATE_FRAGMENT_KEPT | STATE_COMPLETE)); f->replica_map = replica_map; f->dir_auth = dir_auth; f->init_fragment_pins(); f->set_version(get_version()); f->pop_me = pop_me; f->pop_me.scale(fac); // FIXME; this is an approximation f->pop_nested = pop_nested; f->pop_nested.scale(fac); f->pop_auth_subtree = pop_auth_subtree; f->pop_auth_subtree.scale(fac); f->pop_auth_subtree_nested = pop_auth_subtree_nested; f->pop_auth_subtree_nested.scale(fac); dout(10) << " subfrag " << *p << " " << *f << dendl; subfrags[n++] = f; subs.push_back(f); inode->add_dirfrag(f); f->set_dir_auth(get_dir_auth()); f->prepare_new_fragment(replay); } // repartition dentries while (!items.empty()) { CDir::map_t::iterator p = items.begin(); CDentry *dn = p->second; frag_t subfrag = inode->pick_dirfrag(dn->name); int n = (subfrag.value() & (subfrag.mask() ^ frag.mask())) >> subfrag.mask_shift(); dout(15) << " subfrag " << subfrag << " n=" << n << " for " << p->first << dendl; CDir *f = subfrags[n]; f->steal_dentry(dn); } // FIXME: handle dirty old rstat // fix up new frag fragstats for (int i=0; ifnode.rstat.version = fnode.rstat.version; f->fnode.accounted_rstat = f->fnode.rstat; f->fnode.fragstat.version = fnode.fragstat.version; f->fnode.accounted_fragstat = f->fnode.fragstat; dout(10) << " rstat " << f->fnode.rstat << " fragstat " << f->fnode.fragstat << " on " << *f << dendl; } // give any outstanding frag stat differential to first frag dout(10) << " giving rstatdiff " << rstatdiff << " fragstatdiff" << fragstatdiff << " to " << *subfrags[0] << dendl; subfrags[0]->fnode.accounted_rstat.add(rstatdiff); subfrags[0]->fnode.accounted_fragstat.add(fragstatdiff); finish_old_fragment(waiters, replay); } void CDir::merge(list& subs, list& waiters, bool replay) { dout(10) << "merge " << subs << dendl; set_dir_auth(subs.front()->get_dir_auth()); prepare_new_fragment(replay); nest_info_t rstatdiff; frag_info_t fragstatdiff; bool touched_mtime; version_t rstat_version = inode->get_projected_inode()->rstat.version; version_t dirstat_version = inode->get_projected_inode()->dirstat.version; for (list::iterator p = subs.begin(); p != subs.end(); ++p) { CDir *dir = *p; dout(10) << " subfrag " << dir->get_frag() << " " << *dir << dendl; assert(!dir->is_auth() || dir->is_complete() || replay); if (dir->fnode.accounted_rstat.version == rstat_version) rstatdiff.add_delta(dir->fnode.accounted_rstat, dir->fnode.rstat); if (dir->fnode.accounted_fragstat.version == dirstat_version) fragstatdiff.add_delta(dir->fnode.accounted_fragstat, dir->fnode.fragstat, touched_mtime); dir->prepare_old_fragment(replay); // steal dentries while (!dir->items.empty()) steal_dentry(dir->items.begin()->second); // merge replica map for (map::iterator p = dir->replicas_begin(); p != dir->replica_map.end(); ++p) { unsigned cur = replica_map[p->first]; if (p->second > cur) replica_map[p->first] = p->second; } // merge version if (dir->get_version() > get_version()) set_version(dir->get_version()); // merge state state_set(dir->get_state() & MASK_STATE_FRAGMENT_KEPT); dir_auth = dir->dir_auth; dir->finish_old_fragment(waiters, replay); inode->close_dirfrag(dir->get_frag()); } if (is_auth() && !replay) mark_complete(); // FIXME: merge dirty old rstat fnode.rstat.version = rstat_version; fnode.accounted_rstat = fnode.rstat; fnode.accounted_rstat.add(rstatdiff); fnode.fragstat.version = dirstat_version; fnode.accounted_fragstat = fnode.fragstat; fnode.accounted_fragstat.add(fragstatdiff); init_fragment_pins(); } void CDir::resync_accounted_fragstat() { fnode_t *pf = get_projected_fnode(); inode_t *pi = inode->get_projected_inode(); if (pf->accounted_fragstat.version != pi->dirstat.version) { pf->fragstat.version = pi->dirstat.version; dout(10) << "resync_accounted_fragstat " << pf->accounted_fragstat << " -> " << pf->fragstat << dendl; pf->accounted_fragstat = pf->fragstat; } } /* * resync rstat and accounted_rstat with inode */ void CDir::resync_accounted_rstat() { fnode_t *pf = get_projected_fnode(); inode_t *pi = inode->get_projected_inode(); if (pf->accounted_rstat.version != pi->rstat.version) { pf->rstat.version = pi->rstat.version; dout(10) << "resync_accounted_rstat " << pf->accounted_rstat << " -> " << pf->rstat << dendl; pf->accounted_rstat = pf->rstat; dirty_old_rstat.clear(); } } void CDir::assimilate_dirty_rstat_inodes() { dout(10) << "assimilate_dirty_rstat_inodes" << dendl; for (elist::iterator p = dirty_rstat_inodes.begin_use_current(); !p.end(); ++p) { CInode *in = *p; assert(in->is_auth()); if (in->is_frozen()) continue; inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); inode->mdcache->project_rstat_inode_to_frag(in, this, 0, 0); } state_set(STATE_ASSIMRSTAT); dout(10) << "assimilate_dirty_rstat_inodes done" << dendl; } void CDir::assimilate_dirty_rstat_inodes_finish(MutationRef& mut, EMetaBlob *blob) { if (!state_test(STATE_ASSIMRSTAT)) return; state_clear(STATE_ASSIMRSTAT); dout(10) << "assimilate_dirty_rstat_inodes_finish" << dendl; elist::iterator p = dirty_rstat_inodes.begin_use_current(); while (!p.end()) { CInode *in = *p; ++p; if (in->is_frozen()) continue; CDentry *dn = in->get_projected_parent_dn(); mut->auth_pin(in); mut->add_projected_inode(in); in->clear_dirty_rstat(); blob->add_primary_dentry(dn, in, true); } if (!dirty_rstat_inodes.empty()) inode->mdcache->mds->locker->mark_updated_scatterlock(&inode->nestlock); } /**************************************** * WAITING */ void CDir::add_dentry_waiter(const string& dname, snapid_t snapid, Context *c) { if (waiting_on_dentry.empty()) get(PIN_DNWAITER); waiting_on_dentry[string_snap_t(dname, snapid)].push_back(c); dout(10) << "add_dentry_waiter dentry " << dname << " snap " << snapid << " " << c << " on " << *this << dendl; } void CDir::take_dentry_waiting(const string& dname, snapid_t first, snapid_t last, list& ls) { if (waiting_on_dentry.empty()) return; string_snap_t lb(dname, first); string_snap_t ub(dname, last); map >::iterator p = waiting_on_dentry.lower_bound(lb); while (p != waiting_on_dentry.end() && !(ub < p->first)) { dout(10) << "take_dentry_waiting dentry " << dname << " [" << first << "," << last << "] found waiter on snap " << p->first.snapid << " on " << *this << dendl; ls.splice(ls.end(), p->second); waiting_on_dentry.erase(p++); } if (waiting_on_dentry.empty()) put(PIN_DNWAITER); } void CDir::add_ino_waiter(inodeno_t ino, Context *c) { if (waiting_on_ino.empty()) get(PIN_INOWAITER); waiting_on_ino[ino].push_back(c); dout(10) << "add_ino_waiter ino " << ino << " " << c << " on " << *this << dendl; } void CDir::take_ino_waiting(inodeno_t ino, list& ls) { if (waiting_on_ino.empty()) return; if (waiting_on_ino.count(ino) == 0) return; dout(10) << "take_ino_waiting ino " << ino << " x " << waiting_on_ino[ino].size() << " on " << *this << dendl; ls.splice(ls.end(), waiting_on_ino[ino]); waiting_on_ino.erase(ino); if (waiting_on_ino.empty()) put(PIN_INOWAITER); } void CDir::take_sub_waiting(list& ls) { dout(10) << "take_sub_waiting" << dendl; if (!waiting_on_dentry.empty()) { for (map >::iterator p = waiting_on_dentry.begin(); p != waiting_on_dentry.end(); ++p) ls.splice(ls.end(), p->second); waiting_on_dentry.clear(); put(PIN_DNWAITER); } if (!waiting_on_ino.empty()) { for (map >::iterator p = waiting_on_ino.begin(); p != waiting_on_ino.end(); ++p) ls.splice(ls.end(), p->second); waiting_on_ino.clear(); put(PIN_INOWAITER); } } void CDir::add_waiter(uint64_t tag, Context *c) { // hierarchical? // at free root? if (tag & WAIT_ATFREEZEROOT) { if (!(is_freezing_tree_root() || is_frozen_tree_root() || is_freezing_dir() || is_frozen_dir())) { // try parent dout(10) << "add_waiter " << std::hex << tag << std::dec << " " << c << " should be ATFREEZEROOT, " << *this << " is not root, trying parent" << dendl; inode->parent->dir->add_waiter(tag, c); return; } } // at subtree root? if (tag & WAIT_ATSUBTREEROOT) { if (!is_subtree_root()) { // try parent dout(10) << "add_waiter " << std::hex << tag << std::dec << " " << c << " should be ATSUBTREEROOT, " << *this << " is not root, trying parent" << dendl; inode->parent->dir->add_waiter(tag, c); return; } } MDSCacheObject::add_waiter(tag, c); } /* NOTE: this checks dentry waiters too */ void CDir::take_waiting(uint64_t mask, list& ls) { if ((mask & WAIT_DENTRY) && !waiting_on_dentry.empty()) { // take all dentry waiters while (!waiting_on_dentry.empty()) { map >::iterator p = waiting_on_dentry.begin(); dout(10) << "take_waiting dentry " << p->first.name << " snap " << p->first.snapid << " on " << *this << dendl; ls.splice(ls.end(), p->second); waiting_on_dentry.erase(p); } put(PIN_DNWAITER); } // waiting MDSCacheObject::take_waiting(mask, ls); } void CDir::finish_waiting(uint64_t mask, int result) { dout(11) << "finish_waiting mask " << hex << mask << dec << " result " << result << " on " << *this << dendl; list finished; take_waiting(mask, finished); if (result < 0) finish_contexts(g_ceph_context, finished, result); else cache->mds->queue_waiters(finished); } // dirty/clean fnode_t *CDir::project_fnode() { assert(get_version() != 0); fnode_t *p = new fnode_t; *p = *get_projected_fnode(); projected_fnode.push_back(p); dout(10) << "project_fnode " << p << dendl; return p; } void CDir::pop_and_dirty_projected_fnode(LogSegment *ls) { assert(!projected_fnode.empty()); dout(15) << "pop_and_dirty_projected_fnode " << projected_fnode.front() << " v" << projected_fnode.front()->version << dendl; fnode = *projected_fnode.front(); _mark_dirty(ls); delete projected_fnode.front(); projected_fnode.pop_front(); } version_t CDir::pre_dirty(version_t min) { if (min > projected_version) projected_version = min; ++projected_version; dout(10) << "pre_dirty " << projected_version << dendl; return projected_version; } void CDir::mark_dirty(version_t pv, LogSegment *ls) { assert(get_version() < pv); assert(pv <= projected_version); fnode.version = pv; _mark_dirty(ls); } void CDir::_mark_dirty(LogSegment *ls) { if (!state_test(STATE_DIRTY)) { dout(10) << "mark_dirty (was clean) " << *this << " version " << get_version() << dendl; _set_dirty_flag(); assert(ls); } else { dout(10) << "mark_dirty (already dirty) " << *this << " version " << get_version() << dendl; } if (ls) { ls->dirty_dirfrags.push_back(&item_dirty); // if i've never committed, i need to be before _any_ mention of me is trimmed from the journal. if (committed_version == 0 && !item_new.is_on_list()) ls->new_dirfrags.push_back(&item_new); } } void CDir::mark_new(LogSegment *ls) { ls->new_dirfrags.push_back(&item_new); } void CDir::mark_clean() { dout(10) << "mark_clean " << *this << " version " << get_version() << dendl; if (state_test(STATE_DIRTY)) { state_clear(STATE_DIRTY); put(PIN_DIRTY); item_dirty.remove_myself(); item_new.remove_myself(); } } struct C_Dir_Dirty : public Context { CDir *dir; version_t pv; LogSegment *ls; C_Dir_Dirty(CDir *d, version_t p, LogSegment *l) : dir(d), pv(p), ls(l) {} void finish(int r) { dir->mark_dirty(pv, ls); } }; void CDir::log_mark_dirty() { MDLog *mdlog = inode->mdcache->mds->mdlog; version_t pv = pre_dirty(); mdlog->flush(); mdlog->wait_for_safe(new C_Dir_Dirty(this, pv, mdlog->get_current_segment())); } void CDir::mark_complete() { state_set(STATE_COMPLETE); remove_bloom(); } void CDir::first_get() { inode->get(CInode::PIN_DIRFRAG); } void CDir::last_put() { inode->put(CInode::PIN_DIRFRAG); } /****************************************************************************** * FETCH and COMMIT */ // ----------------------- // FETCH void CDir::fetch(Context *c, bool ignore_authpinnability) { string want; return fetch(c, want, ignore_authpinnability); } void CDir::fetch(Context *c, const string& want_dn, bool ignore_authpinnability) { dout(10) << "fetch on " << *this << dendl; assert(is_auth()); assert(!is_complete()); if (!can_auth_pin() && !ignore_authpinnability) { if (c) { dout(7) << "fetch waiting for authpinnable" << dendl; add_waiter(WAIT_UNFREEZE, c); } else dout(7) << "fetch not authpinnable and no context" << dendl; return; } if (c) add_waiter(WAIT_COMPLETE, c); // already fetching? if (state_test(CDir::STATE_FETCHING)) { dout(7) << "already fetching; waiting" << dendl; return; } auth_pin(this); state_set(CDir::STATE_FETCHING); if (cache->mds->logger) cache->mds->logger->inc(l_mds_dir_f); _omap_fetch(want_dn); } class C_Dir_TMAP_Fetched : public Context { protected: CDir *dir; string want_dn; public: bufferlist bl; C_Dir_TMAP_Fetched(CDir *d, const string& w) : dir(d), want_dn(w) { } void finish(int r) { dir->_tmap_fetched(bl, want_dn, r); } }; void CDir::_tmap_fetch(const string& want_dn) { // start by reading the first hunk of it C_Dir_TMAP_Fetched *fin = new C_Dir_TMAP_Fetched(this, want_dn); object_t oid = get_ondisk_object(); object_locator_t oloc(cache->mds->mdsmap->get_metadata_pool()); ObjectOperation rd; rd.tmap_get(&fin->bl, NULL); cache->mds->objecter->read(oid, oloc, rd, CEPH_NOSNAP, NULL, 0, fin); } void CDir::_tmap_fetched(bufferlist& bl, const string& want_dn, int r) { LogClient &clog = cache->mds->clog; dout(10) << "_tmap_fetched " << bl.length() << " bytes for " << *this << " want_dn=" << want_dn << dendl; assert(r == 0 || r == -ENOENT); assert(is_auth()); assert(!is_frozen()); bufferlist header; map omap; if (bl.length() == 0) { r = -ENODATA; } else { bufferlist::iterator p = bl.begin(); ::decode(header, p); ::decode(omap, p); if (!p.end()) { clog.warn() << "tmap buffer of dir " << dirfrag() << " has " << bl.length() - p.get_off() << " extra bytes\n"; } bl.clear(); } _omap_fetched(header, omap, want_dn, r); } class C_Dir_OMAP_Fetched : public Context { protected: CDir *dir; string want_dn; public: bufferlist hdrbl; map omap; int ret1, ret2; C_Dir_OMAP_Fetched(CDir *d, const string& w) : dir(d), want_dn(w) { } void finish(int r) { if (r >= 0) r = ret1; if (r >= 0) r = ret2; dir->_omap_fetched(hdrbl, omap, want_dn, r); } }; void CDir::_omap_fetch(const string& want_dn) { C_Dir_OMAP_Fetched *fin = new C_Dir_OMAP_Fetched(this, want_dn); object_t oid = get_ondisk_object(); object_locator_t oloc(cache->mds->mdsmap->get_metadata_pool()); ObjectOperation rd; rd.omap_get_header(&fin->hdrbl, &fin->ret1); rd.omap_get_vals("", "", (uint64_t)-1, &fin->omap, &fin->ret2); cache->mds->objecter->read(oid, oloc, rd, CEPH_NOSNAP, NULL, 0, fin); } void CDir::_omap_fetched(bufferlist& hdrbl, map& omap, const string& want_dn, int r) { LogClient &clog = cache->mds->clog; dout(10) << "_fetched header " << hdrbl.length() << " bytes " << omap.size() << " keys for " << *this << " want_dn=" << want_dn << dendl; assert(r == 0 || r == -ENOENT || r == -ENODATA); assert(is_auth()); assert(!is_frozen()); if (hdrbl.length() == 0) { if (r != -ENODATA) { // called by _tmap_fetched() ? dout(10) << "_fetched 0 byte from omap, retry tmap" << dendl; _tmap_fetch(want_dn); return; } dout(0) << "_fetched missing object for " << *this << dendl; clog.error() << "dir " << dirfrag() << " object missing on disk; some files may be lost\n"; log_mark_dirty(); // mark complete, !fetching mark_complete(); state_clear(STATE_FETCHING); auth_unpin(this); // kick waiters finish_waiting(WAIT_COMPLETE, 0); return; } fnode_t got_fnode; { bufferlist::iterator p = hdrbl.begin(); ::decode(got_fnode, p); if (!p.end()) { clog.warn() << "header buffer of dir " << dirfrag() << " has " << hdrbl.length() - p.get_off() << " extra bytes\n"; } } dout(10) << "_fetched version " << got_fnode.version << dendl; // take the loaded fnode? // only if we are a fresh CDir* with no prior state. if (get_version() == 0) { assert(!is_projected()); assert(!state_test(STATE_COMMITTING)); fnode = got_fnode; projected_version = committing_version = committed_version = got_fnode.version; if (state_test(STATE_REJOINUNDEF)) { assert(cache->mds->is_rejoin()); state_clear(STATE_REJOINUNDEF); cache->opened_undef_dirfrag(this); } } list undef_inodes; // purge stale snaps? // only if we have past_parents open! bool purged_any = false; const set *snaps = NULL; SnapRealm *realm = inode->find_snaprealm(); if (!realm->have_past_parents_open()) { dout(10) << " no snap purge, one or more past parents NOT open" << dendl; } else if (fnode.snap_purged_thru < realm->get_last_destroyed()) { snaps = &realm->get_snaps(); dout(10) << " snap_purged_thru " << fnode.snap_purged_thru << " < " << realm->get_last_destroyed() << ", snap purge based on " << *snaps << dendl; fnode.snap_purged_thru = realm->get_last_destroyed(); } bool stray = inode->is_stray(); unsigned pos = omap.size() - 1; for (map::reverse_iterator p = omap.rbegin(); p != omap.rend(); ++p, --pos) { // dname string dname; snapid_t first, last; dentry_key_t::decode_helper(p->first, dname, last); bufferlist::iterator q = p->second.begin(); ::decode(first, q); // marker char type; ::decode(type, q); dout(20) << "_fetched pos " << pos << " marker '" << type << "' dname '" << dname << " [" << first << "," << last << "]" << dendl; bool stale = false; if (snaps && last != CEPH_NOSNAP) { set::const_iterator p = snaps->lower_bound(first); if (p == snaps->end() || *p > last) { dout(10) << " skipping stale dentry on [" << first << "," << last << "]" << dendl; stale = true; purged_any = true; } } /* * look for existing dentry for _last_ snap, because unlink + * create may leave a "hole" (epochs during which the dentry * doesn't exist) but for which no explicit negative dentry is in * the cache. */ CDentry *dn = NULL; if (!stale) dn = lookup(dname, last); if (type == 'L') { // hard link inodeno_t ino; unsigned char d_type; ::decode(ino, q); ::decode(d_type, q); if (stale) continue; if (dn) { if (dn->get_linkage()->get_inode() == 0) { dout(12) << "_fetched had NEG dentry " << *dn << dendl; } else { dout(12) << "_fetched had dentry " << *dn << dendl; } } else { // (remote) link dn = add_remote_dentry(dname, ino, d_type, first, last); // link to inode? CInode *in = cache->get_inode(ino); // we may or may not have it. if (in) { dn->link_remote(dn->get_linkage(), in); dout(12) << "_fetched got remote link " << ino << " which we have " << *in << dendl; } else { dout(12) << "_fetched got remote link " << ino << " (dont' have it)" << dendl; } } } else if (type == 'I') { // inode // parse out inode inode_t inode; string symlink; fragtree_t fragtree; map xattrs; bufferlist snapbl; map old_inodes; ::decode(inode, q); if (inode.is_symlink()) ::decode(symlink, q); ::decode(fragtree, q); ::decode(xattrs, q); ::decode(snapbl, q); ::decode(old_inodes, q); if (stale) continue; bool undef_inode = false; if (dn) { CInode *in = dn->get_linkage()->get_inode(); if (in) { dout(12) << "_fetched had dentry " << *dn << dendl; if (in->state_test(CInode::STATE_REJOINUNDEF)) { undef_inodes.push_back(in); undef_inode = true; } } else dout(12) << "_fetched had NEG dentry " << *dn << dendl; } if (!dn || undef_inode) { // add inode CInode *in = cache->get_inode(inode.ino, last); if (!in || undef_inode) { if (undef_inode && in) in->first = first; else in = new CInode(cache, true, first, last); in->inode = inode; // symlink? if (in->is_symlink()) in->symlink = symlink; in->dirfragtree.swap(fragtree); in->xattrs.swap(xattrs); in->decode_snap_blob(snapbl); in->old_inodes.swap(old_inodes); if (snaps) in->purge_stale_snap_data(*snaps); if (undef_inode) { if (inode.anchored) dn->adjust_nested_anchors(1); } else { cache->add_inode( in ); // add dn = add_primary_dentry(dname, in, first, last); // link } dout(12) << "_fetched got " << *dn << " " << *in << dendl; if (in->inode.is_dirty_rstat()) in->mark_dirty_rstat(); if (stray) { dn->state_set(CDentry::STATE_STRAY); if (in->inode.nlink == 0) in->state_set(CInode::STATE_ORPHAN); } //in->hack_accessed = false; //in->hack_load_stamp = ceph_clock_now(g_ceph_context); //num_new_inodes_loaded++; } else { dout(0) << "_fetched badness: got (but i already had) " << *in << " mode " << in->inode.mode << " mtime " << in->inode.mtime << dendl; string dirpath, inopath; this->inode->make_path_string(dirpath); in->make_path_string(inopath); clog.error() << "loaded dup inode " << inode.ino << " [" << first << "," << last << "] v" << inode.version << " at " << dirpath << "/" << dname << ", but inode " << in->vino() << " v" << in->inode.version << " already exists at " << inopath << "\n"; continue; } } } else { dout(1) << "corrupt directory, i got tag char '" << type << "' pos " << pos << dendl; assert(0); } if (dn && want_dn.length() && want_dn == dname) { dout(10) << " touching wanted dn " << *dn << dendl; inode->mdcache->touch_dentry(dn); } /** clean underwater item? * Underwater item is something that is dirty in our cache from * journal replay, but was previously flushed to disk before the * mds failed. * * We only do this is committed_version == 0. that implies either * - this is a fetch after from a clean/empty CDir is created * (and has no effect, since the dn won't exist); or * - this is a fetch after _recovery_, which is what we're worried * about. Items that are marked dirty from the journal should be * marked clean if they appear on disk. */ if (committed_version == 0 && dn && dn->get_version() <= got_fnode.version && dn->is_dirty()) { dout(10) << "_fetched had underwater dentry " << *dn << ", marking clean" << dendl; dn->mark_clean(); if (dn->get_linkage()->is_primary()) { assert(dn->get_linkage()->get_inode()->get_version() <= got_fnode.version); dout(10) << "_fetched had underwater inode " << *dn->get_linkage()->get_inode() << ", marking clean" << dendl; dn->get_linkage()->get_inode()->mark_clean(); } } } //cache->mds->logger->inc("newin", num_new_inodes_loaded); if (purged_any) log_mark_dirty(); // mark complete, !fetching mark_complete(); state_clear(STATE_FETCHING); // open & force frags while (!undef_inodes.empty()) { CInode *in = undef_inodes.front(); undef_inodes.pop_front(); in->state_clear(CInode::STATE_REJOINUNDEF); cache->opened_undef_inode(in); } auth_unpin(this); // kick waiters finish_waiting(WAIT_COMPLETE, 0); } // ----------------------- // COMMIT /** * commit * * @param want - min version i want committed * @param c - callback for completion */ void CDir::commit(version_t want, Context *c, bool ignore_authpinnability, int op_prio) { dout(10) << "commit want " << want << " on " << *this << dendl; if (want == 0) want = get_version(); // preconditions assert(want <= get_version() || get_version() == 0); // can't commit the future assert(want > committed_version); // the caller is stupid assert(is_auth()); assert(ignore_authpinnability || can_auth_pin()); // note: queue up a noop if necessary, so that we always // get an auth_pin. if (!c) c = new C_NoopContext; // auth_pin on first waiter if (waiting_for_commit.empty()) auth_pin(this); waiting_for_commit[want].push_back(c); // ok. _commit(want, op_prio); } class C_Dir_Committed : public Context { CDir *dir; version_t version; public: C_Dir_Committed(CDir *d, version_t v) : dir(d), version(v) { } void finish(int r) { assert(r == 0); dir->_committed(version); } }; /** * Flush out the modified dentries in this dir. Keep the bufferlist * below max_write_size; */ void CDir::_omap_commit(int op_prio) { dout(10) << "_omap_commit" << dendl; unsigned max_write_size = cache->max_dir_commit_size; unsigned write_size = 0; if (op_prio < 0) op_prio = CEPH_MSG_PRIO_DEFAULT; // snap purge? const set *snaps = NULL; SnapRealm *realm = inode->find_snaprealm(); if (!realm->have_past_parents_open()) { dout(10) << " no snap purge, one or more past parents NOT open" << dendl; } else if (fnode.snap_purged_thru < realm->get_last_destroyed()) { snaps = &realm->get_snaps(); dout(10) << " snap_purged_thru " << fnode.snap_purged_thru << " < " << realm->get_last_destroyed() << ", snap purge based on " << *snaps << dendl; } set to_remove; map to_set; C_GatherBuilder gather(g_ceph_context, new C_Dir_Committed(this, get_version())); SnapContext snapc; object_t oid = get_ondisk_object(); object_locator_t oloc(cache->mds->mdsmap->get_metadata_pool()); for (map_t::iterator p = items.begin(); p != items.end(); ) { CDentry *dn = p->second; ++p; string key; dn->key().encode(key); if (dn->last != CEPH_NOSNAP && snaps && try_trim_snap_dentry(dn, *snaps)) { dout(10) << " rm " << dn->name << " " << *dn << dendl; write_size += key.length(); to_remove.insert(key); continue; } if (!dn->is_dirty() && (!dn->state_test(CDentry::STATE_FRAGMENTING) || dn->get_linkage()->is_null())) continue; // skip clean dentries if (dn->get_linkage()->is_null()) { dout(10) << " rm " << dn->name << " " << *dn << dendl; write_size += key.length(); to_remove.insert(key); } else { dout(10) << " set " << dn->name << " " << *dn << dendl; bufferlist dnbl; _encode_dentry(dn, dnbl, snaps); write_size += key.length() + dnbl.length(); to_set[key].swap(dnbl); } if (write_size >= max_write_size) { ObjectOperation op; op.priority = op_prio; op.tmap_to_omap(true); // convert tmap to omap if (!to_set.empty()) op.omap_set(to_set); if (!to_remove.empty()) op.omap_rm_keys(to_remove); cache->mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); write_size = 0; to_set.clear(); to_remove.clear(); } } ObjectOperation op; op.priority = op_prio; op.tmap_to_omap(true); // convert tmap to omap /* * save the header at the last moment.. If we were to send it off before other * updates, but die before sending them all, we'd think that the on-disk state * was fully committed even though it wasn't! However, since the messages are * strictly ordered between the MDS and the OSD, and since messages to a given * PG are strictly ordered, if we simply send the message containing the header * off last, we cannot get our header into an incorrect state. */ bufferlist header; ::encode(fnode, header); op.omap_set_header(header); if (!to_set.empty()) op.omap_set(to_set); if (!to_remove.empty()) op.omap_rm_keys(to_remove); cache->mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); gather.activate(); } void CDir::_encode_dentry(CDentry *dn, bufferlist& bl, const set *snaps) { // clear dentry NEW flag, if any. we can no longer silently drop it. dn->clear_new(); ::encode(dn->first, bl); // primary or remote? if (dn->linkage.is_remote()) { inodeno_t ino = dn->linkage.get_remote_ino(); unsigned char d_type = dn->linkage.get_remote_d_type(); dout(14) << " pos " << bl.length() << " dn '" << dn->name << "' remote ino " << ino << dendl; // marker, name, ino bl.append('L'); // remote link ::encode(ino, bl); ::encode(d_type, bl); } else { // primary link CInode *in = dn->linkage.get_inode(); assert(in); dout(14) << " pos " << bl.length() << " dn '" << dn->name << "' inode " << *in << dendl; // marker, name, inode, [symlink string] bl.append('I'); // inode ::encode(in->inode, bl); if (in->is_symlink()) { // include symlink destination! dout(18) << " including symlink ptr " << in->symlink << dendl; ::encode(in->symlink, bl); } ::encode(in->dirfragtree, bl); ::encode(in->xattrs, bl); bufferlist snapbl; in->encode_snap_blob(snapbl); ::encode(snapbl, bl); if (in->is_multiversion() && snaps) in->purge_stale_snap_data(*snaps); ::encode(in->old_inodes, bl); } } void CDir::_commit(version_t want, int op_prio) { dout(10) << "_commit want " << want << " on " << *this << dendl; // we can't commit things in the future. // (even the projected future.) assert(want <= get_version() || get_version() == 0); // check pre+postconditions. assert(is_auth()); // already committed? if (committed_version >= want) { dout(10) << "already committed " << committed_version << " >= " << want << dendl; return; } // already committing >= want? if (committing_version >= want) { dout(10) << "already committing " << committing_version << " >= " << want << dendl; assert(state_test(STATE_COMMITTING)); return; } // alrady committed an older version? if (committing_version > committed_version) { dout(10) << "already committing older " << committing_version << ", waiting for that to finish" << dendl; return; } // commit. committing_version = get_version(); // mark committing (if not already) if (!state_test(STATE_COMMITTING)) { dout(10) << "marking committing" << dendl; state_set(STATE_COMMITTING); } if (cache->mds->logger) cache->mds->logger->inc(l_mds_dir_c); _omap_commit(op_prio); } /** * _committed * * @param v version i just committed */ void CDir::_committed(version_t v) { dout(10) << "_committed v " << v << " on " << *this << dendl; assert(is_auth()); bool stray = inode->is_stray(); // take note. assert(v > committed_version); assert(v <= committing_version); committed_version = v; // _all_ commits done? if (committing_version == committed_version) state_clear(CDir::STATE_COMMITTING); // _any_ commit, even if we've been redirtied, means we're no longer new. item_new.remove_myself(); // dir clean? if (committed_version == get_version()) mark_clean(); // dentries clean? for (map_t::iterator it = items.begin(); it != items.end(); ) { CDentry *dn = it->second; ++it; // inode? if (dn->linkage.is_primary()) { CInode *in = dn->linkage.get_inode(); assert(in); assert(in->is_auth()); if (committed_version >= in->get_version()) { if (in->is_dirty()) { dout(15) << " dir " << committed_version << " >= inode " << in->get_version() << " now clean " << *in << dendl; in->mark_clean(); } } else { dout(15) << " dir " << committed_version << " < inode " << in->get_version() << " still dirty " << *in << dendl; assert(in->is_dirty() || in->last < CEPH_NOSNAP); // special case for cow snap items (not predirtied) } } // dentry if (committed_version >= dn->get_version()) { if (dn->is_dirty()) { dout(15) << " dir " << committed_version << " >= dn " << dn->get_version() << " now clean " << *dn << dendl; dn->mark_clean(); // drop clean null stray dentries immediately if (stray && dn->get_num_ref() == 0 && !dn->is_projected() && dn->get_linkage()->is_null()) remove_dentry(dn); } } else { dout(15) << " dir " << committed_version << " < dn " << dn->get_version() << " still dirty " << *dn << dendl; } } // finishers? bool were_waiters = !waiting_for_commit.empty(); map >::iterator p = waiting_for_commit.begin(); while (p != waiting_for_commit.end()) { map >::iterator n = p; ++n; if (p->first > committed_version) { dout(10) << " there are waiters for " << p->first << ", committing again" << dendl; _commit(p->first, -1); break; } cache->mds->queue_waiters(p->second); waiting_for_commit.erase(p); p = n; } // unpin if we kicked the last waiter. if (were_waiters && waiting_for_commit.empty()) auth_unpin(this); } // IMPORT/EXPORT void CDir::encode_export(bufferlist& bl) { assert(!is_projected()); ::encode(first, bl); ::encode(fnode, bl); ::encode(dirty_old_rstat, bl); ::encode(committed_version, bl); ::encode(state, bl); ::encode(dir_rep, bl); ::encode(pop_me, bl); ::encode(pop_auth_subtree, bl); ::encode(dir_rep_by, bl); ::encode(replica_map, bl); get(PIN_TEMPEXPORTING); } void CDir::finish_export(utime_t now) { state &= MASK_STATE_EXPORT_KEPT; pop_auth_subtree_nested.sub(now, cache->decayrate, pop_auth_subtree); pop_me.zero(now); pop_auth_subtree.zero(now); put(PIN_TEMPEXPORTING); dirty_old_rstat.clear(); } void CDir::decode_import(bufferlist::iterator& blp, utime_t now, LogSegment *ls) { ::decode(first, blp); ::decode(fnode, blp); ::decode(dirty_old_rstat, blp); projected_version = fnode.version; ::decode(committed_version, blp); committing_version = committed_version; unsigned s; ::decode(s, blp); state &= MASK_STATE_IMPORT_KEPT; state |= (s & MASK_STATE_EXPORTED); if (is_dirty()) { get(PIN_DIRTY); _mark_dirty(ls); } ::decode(dir_rep, blp); ::decode(pop_me, now, blp); ::decode(pop_auth_subtree, now, blp); pop_auth_subtree_nested.add(now, cache->decayrate, pop_auth_subtree); ::decode(dir_rep_by, blp); ::decode(replica_map, blp); if (!replica_map.empty()) get(PIN_REPLICATED); replica_nonce = 0; // no longer defined // did we import some dirty scatterlock data? if (dirty_old_rstat.size() || !(fnode.rstat == fnode.accounted_rstat)) { cache->mds->locker->mark_updated_scatterlock(&inode->nestlock); ls->dirty_dirfrag_nest.push_back(&inode->item_dirty_dirfrag_nest); } if (!(fnode.fragstat == fnode.accounted_fragstat)) { cache->mds->locker->mark_updated_scatterlock(&inode->filelock); ls->dirty_dirfrag_dir.push_back(&inode->item_dirty_dirfrag_dir); } if (is_dirty_dft()) { if (inode->dirfragtreelock.get_state() != LOCK_MIX && inode->dirfragtreelock.is_stable()) { // clear stale dirtydft state_clear(STATE_DIRTYDFT); } else { cache->mds->locker->mark_updated_scatterlock(&inode->dirfragtreelock); ls->dirty_dirfrag_dirfragtree.push_back(&inode->item_dirty_dirfrag_dirfragtree); } } } /******************************** * AUTHORITY */ /* * if dir_auth.first == parent, auth is same as inode. * unless .second != unknown, in which case that sticks. */ pair CDir::authority() { if (is_subtree_root()) return dir_auth; else return inode->authority(); } /** is_subtree_root() * true if this is an auth delegation point. * that is, dir_auth != default (parent,unknown) * * some key observations: * if i am auth: * - any region bound will be an export, or frozen. * * note that this DOES heed dir_auth.pending */ /* bool CDir::is_subtree_root() { if (dir_auth == CDIR_AUTH_DEFAULT) { //dout(10) << "is_subtree_root false " << dir_auth << " != " << CDIR_AUTH_DEFAULT //<< " on " << ino() << dendl; return false; } else { //dout(10) << "is_subtree_root true " << dir_auth << " != " << CDIR_AUTH_DEFAULT //<< " on " << ino() << dendl; return true; } } */ /** contains(x) * true if we are x, or an ancestor of x */ bool CDir::contains(CDir *x) { while (1) { if (x == this) return true; x = x->get_inode()->get_projected_parent_dir(); if (x == 0) return false; } } /** set_dir_auth */ void CDir::set_dir_auth(pair a) { dout(10) << "setting dir_auth=" << a << " from " << dir_auth << " on " << *this << dendl; bool was_subtree = is_subtree_root(); bool was_ambiguous = dir_auth.second >= 0; // set it. dir_auth = a; // new subtree root? if (!was_subtree && is_subtree_root()) { dout(10) << " new subtree root, adjusting auth_pins" << dendl; // adjust nested auth pins if (get_cum_auth_pins()) inode->adjust_nested_auth_pins(-1, NULL); // unpin parent of frozen dir/tree? if (inode->is_auth() && (is_frozen_tree_root() || is_frozen_dir())) inode->auth_unpin(this); } if (was_subtree && !is_subtree_root()) { dout(10) << " old subtree root, adjusting auth_pins" << dendl; // adjust nested auth pins if (get_cum_auth_pins()) inode->adjust_nested_auth_pins(1, NULL); // pin parent of frozen dir/tree? if (inode->is_auth() && (is_frozen_tree_root() || is_frozen_dir())) inode->auth_pin(this); } // newly single auth? if (was_ambiguous && dir_auth.second == CDIR_AUTH_UNKNOWN) { list ls; take_waiting(WAIT_SINGLEAUTH, ls); cache->mds->queue_waiters(ls); } } /***************************************** * AUTH PINS and FREEZING * * the basic plan is that auth_pins only exist in auth regions, and they * prevent a freeze (and subsequent auth change). * * however, we also need to prevent a parent from freezing if a child is frozen. * for that reason, the parent inode of a frozen directory is auth_pinned. * * the oddity is when the frozen directory is a subtree root. if that's the case, * the parent inode isn't frozen. which means that when subtree authority is adjusted * at the bounds, inodes for any frozen bound directories need to get auth_pins at that * time. * */ void CDir::auth_pin(void *by) { if (auth_pins == 0) get(PIN_AUTHPIN); auth_pins++; #ifdef MDS_AUTHPIN_SET auth_pin_set.insert(by); #endif dout(10) << "auth_pin by " << by << " on " << *this << " count now " << auth_pins << " + " << nested_auth_pins << dendl; // nest pins? if (!is_subtree_root() && get_cum_auth_pins() == 1) inode->adjust_nested_auth_pins(1, by); } void CDir::auth_unpin(void *by) { auth_pins--; #ifdef MDS_AUTHPIN_SET assert(auth_pin_set.count(by)); auth_pin_set.erase(auth_pin_set.find(by)); #endif if (auth_pins == 0) put(PIN_AUTHPIN); dout(10) << "auth_unpin by " << by << " on " << *this << " count now " << auth_pins << " + " << nested_auth_pins << dendl; assert(auth_pins >= 0); int newcum = get_cum_auth_pins(); maybe_finish_freeze(); // pending freeze? // nest? if (!is_subtree_root() && newcum == 0) inode->adjust_nested_auth_pins(-1, by); } void CDir::adjust_nested_auth_pins(int inc, int dirinc, void *by) { assert(inc); nested_auth_pins += inc; dir_auth_pins += dirinc; dout(15) << "adjust_nested_auth_pins " << inc << "/" << dirinc << " on " << *this << " by " << by << " count now " << auth_pins << " + " << nested_auth_pins << dendl; assert(nested_auth_pins >= 0); assert(dir_auth_pins >= 0); int newcum = get_cum_auth_pins(); maybe_finish_freeze(); // pending freeze? // nest? if (!is_subtree_root()) { if (newcum == 0) inode->adjust_nested_auth_pins(-1, by); else if (newcum == inc) inode->adjust_nested_auth_pins(1, by); } } void CDir::adjust_nested_anchors(int by) { assert(by); nested_anchors += by; dout(20) << "adjust_nested_anchors by " << by << " -> " << nested_anchors << dendl; assert(nested_anchors >= 0); inode->adjust_nested_anchors(by); } #ifdef MDS_VERIFY_FRAGSTAT void CDir::verify_fragstat() { assert(is_complete()); if (inode->is_stray()) return; frag_info_t c; memset(&c, 0, sizeof(c)); for (map_t::iterator it = items.begin(); it != items.end(); ++it) { CDentry *dn = it->second; if (dn->is_null()) continue; dout(10) << " " << *dn << dendl; if (dn->is_primary()) dout(10) << " " << *dn->inode << dendl; if (dn->is_primary()) { if (dn->inode->is_dir()) c.nsubdirs++; else c.nfiles++; } if (dn->is_remote()) { if (dn->get_remote_d_type() == DT_DIR) c.nsubdirs++; else c.nfiles++; } } if (c.nsubdirs != fnode.fragstat.nsubdirs || c.nfiles != fnode.fragstat.nfiles) { dout(0) << "verify_fragstat failed " << fnode.fragstat << " on " << *this << dendl; dout(0) << " i count " << c << dendl; assert(0); } else { dout(0) << "verify_fragstat ok " << fnode.fragstat << " on " << *this << dendl; } } #endif /***************************************************************************** * FREEZING */ // FREEZE TREE bool CDir::freeze_tree() { assert(!is_frozen()); assert(!is_freezing()); auth_pin(this); if (is_freezeable(true)) { _freeze_tree(); auth_unpin(this); return true; } else { state_set(STATE_FREEZINGTREE); dout(10) << "freeze_tree waiting " << *this << dendl; return false; } } void CDir::_freeze_tree() { dout(10) << "_freeze_tree " << *this << dendl; assert(is_freezeable(true)); // twiddle state state_clear(STATE_FREEZINGTREE); // actually, this may get set again by next context? state_set(STATE_FROZENTREE); get(PIN_FROZEN); // auth_pin inode for duration of freeze, if we are not a subtree root. if (is_auth() && !is_subtree_root()) inode->auth_pin(this); } void CDir::unfreeze_tree() { dout(10) << "unfreeze_tree " << *this << dendl; if (state_test(STATE_FROZENTREE)) { // frozen. unfreeze. state_clear(STATE_FROZENTREE); put(PIN_FROZEN); // unpin (may => FREEZEABLE) FIXME: is this order good? if (is_auth() && !is_subtree_root()) inode->auth_unpin(this); // waiters? finish_waiting(WAIT_UNFREEZE); } else { finish_waiting(WAIT_FROZEN, -1); // freezing. stop it. assert(state_test(STATE_FREEZINGTREE)); state_clear(STATE_FREEZINGTREE); auth_unpin(this); finish_waiting(WAIT_UNFREEZE); } } bool CDir::is_freezing_tree() { CDir *dir = this; while (1) { if (dir->is_freezing_tree_root()) return true; if (dir->is_subtree_root()) return false; if (dir->inode->parent) dir = dir->inode->parent->dir; else return false; // root on replica } } bool CDir::is_frozen_tree() { CDir *dir = this; while (1) { if (dir->is_frozen_tree_root()) return true; if (dir->is_subtree_root()) return false; if (dir->inode->parent) dir = dir->inode->parent->dir; else return false; // root on replica } } CDir *CDir::get_frozen_tree_root() { assert(is_frozen()); CDir *dir = this; while (1) { if (dir->is_frozen_tree_root()) return dir; if (dir->inode->parent) dir = dir->inode->parent->dir; else assert(0); } } struct C_Dir_AuthUnpin : public Context { CDir *dir; C_Dir_AuthUnpin(CDir *d) : dir(d) {} void finish(int r) { dir->auth_unpin(dir->get_inode()); } }; void CDir::maybe_finish_freeze() { if (auth_pins != 1 || dir_auth_pins != 0) return; // we can freeze the _dir_ even with nested pins... if (state_test(STATE_FREEZINGDIR)) { _freeze_dir(); auth_unpin(this); finish_waiting(WAIT_FROZEN); } if (nested_auth_pins != 0) return; if (state_test(STATE_FREEZINGTREE)) { if (!is_subtree_root() && inode->is_frozen()) { dout(10) << "maybe_finish_freeze !subtree root and frozen inode, waiting for unfreeze on " << inode << dendl; // retake an auth_pin... auth_pin(inode); // and release it when the parent inode unfreezes inode->add_waiter(WAIT_UNFREEZE, new C_Dir_AuthUnpin(this)); return; } _freeze_tree(); auth_unpin(this); finish_waiting(WAIT_FROZEN); } } // FREEZE DIR bool CDir::freeze_dir() { assert(!is_frozen()); assert(!is_freezing()); auth_pin(this); if (is_freezeable_dir(true)) { _freeze_dir(); auth_unpin(this); return true; } else { state_set(STATE_FREEZINGDIR); dout(10) << "freeze_dir + wait " << *this << dendl; return false; } } void CDir::_freeze_dir() { dout(10) << "_freeze_dir " << *this << dendl; //assert(is_freezeable_dir(true)); // not always true during split because the original fragment may have frozen a while // ago and we're just now getting around to breaking it up. state_clear(STATE_FREEZINGDIR); state_set(STATE_FROZENDIR); get(PIN_FROZEN); if (is_auth() && !is_subtree_root()) inode->auth_pin(this); // auth_pin for duration of freeze } void CDir::unfreeze_dir() { dout(10) << "unfreeze_dir " << *this << dendl; if (state_test(STATE_FROZENDIR)) { state_clear(STATE_FROZENDIR); put(PIN_FROZEN); // unpin (may => FREEZEABLE) FIXME: is this order good? if (is_auth() && !is_subtree_root()) inode->auth_unpin(this); finish_waiting(WAIT_UNFREEZE); } else { finish_waiting(WAIT_FROZEN, -1); // still freezing. stop. assert(state_test(STATE_FREEZINGDIR)); state_clear(STATE_FREEZINGDIR); auth_unpin(this); finish_waiting(WAIT_UNFREEZE); } } ceph-0.80.11/src/mds/flock.cc0000664000175100017510000004604412623076744017664 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "common/debug.h" #include "mdstypes.h" #include "mds/flock.h" #define dout_subsys ceph_subsys_mds bool ceph_lock_state_t::is_waiting(ceph_filelock &fl) { multimap::iterator p = waiting_locks.find(fl.start); while (p != waiting_locks.end()) { if (p->second.start > fl.start) return false; if (p->second.length == fl.length && ceph_filelock_owner_equal(p->second, fl)) return true; ++p; } return false; } void ceph_lock_state_t::remove_waiting(ceph_filelock& fl) { multimap::iterator p = waiting_locks.find(fl.start); while (p != waiting_locks.end()) { if (p->second.start > fl.start) return; if (p->second.length == fl.length && ceph_filelock_owner_equal(p->second, fl)) { waiting_locks.erase(p); --client_waiting_lock_counts[(client_t)fl.client]; if (!client_waiting_lock_counts[(client_t)fl.client]) { client_waiting_lock_counts.erase((client_t)fl.client); } return; } ++p; } } bool ceph_lock_state_t::add_lock(ceph_filelock& new_lock, bool wait_on_fail, bool replay) { ldout(cct,15) << "add_lock " << new_lock << dendl; bool ret = false; list::iterator> overlapping_locks, self_overlapping_locks, neighbor_locks; // first, get any overlapping locks and split them into owned-by-us and not if (get_overlapping_locks(new_lock, overlapping_locks, &neighbor_locks)) { ldout(cct,15) << "got overlapping lock, splitting by owner" << dendl; split_by_owner(new_lock, overlapping_locks, self_overlapping_locks); } if (!overlapping_locks.empty()) { //overlapping locks owned by others :( if (CEPH_LOCK_EXCL == new_lock.type) { //can't set, we want an exclusive ldout(cct,15) << "overlapping lock, and this lock is exclusive, can't set" << dendl; if (wait_on_fail && !replay) { waiting_locks.insert(pair(new_lock.start, new_lock)); } } else { //shared lock, check for any exclusive locks blocking us if (contains_exclusive_lock(overlapping_locks)) { //blocked :( ldout(cct,15) << " blocked by exclusive lock in overlapping_locks" << dendl; if (wait_on_fail && !replay) { waiting_locks.insert(pair(new_lock.start, new_lock)); } } else { //yay, we can insert a shared lock ldout(cct,15) << "inserting shared lock" << dendl; remove_waiting(new_lock); adjust_locks(self_overlapping_locks, new_lock, neighbor_locks); held_locks.insert(pair(new_lock.start, new_lock)); ret = true; } } } else { //no overlapping locks except our own remove_waiting(new_lock); adjust_locks(self_overlapping_locks, new_lock, neighbor_locks); ldout(cct,15) << "no conflicts, inserting " << new_lock << dendl; held_locks.insert(pair (new_lock.start, new_lock)); ret = true; } if (ret) { ++client_held_lock_counts[(client_t)new_lock.client]; } else if (wait_on_fail && !replay) ++client_waiting_lock_counts[(client_t)new_lock.client]; return ret; } void ceph_lock_state_t::look_for_lock(ceph_filelock& testing_lock) { list::iterator> overlapping_locks, self_overlapping_locks; if (get_overlapping_locks(testing_lock, overlapping_locks)) { split_by_owner(testing_lock, overlapping_locks, self_overlapping_locks); } if (!overlapping_locks.empty()) { //somebody else owns overlapping lock if (CEPH_LOCK_EXCL == testing_lock.type) { //any lock blocks it testing_lock = (*overlapping_locks.begin())->second; } else { ceph_filelock *blocking_lock; if ((blocking_lock = contains_exclusive_lock(overlapping_locks))) { testing_lock = *blocking_lock; } else { //nothing blocking! testing_lock.type = CEPH_LOCK_UNLOCK; } } return; } //if we get here, only our own locks block testing_lock.type = CEPH_LOCK_UNLOCK; } void ceph_lock_state_t::remove_lock(ceph_filelock removal_lock, list& activated_locks) { list::iterator> overlapping_locks, self_overlapping_locks; if (get_overlapping_locks(removal_lock, overlapping_locks)) { ldout(cct,15) << "splitting by owner" << dendl; split_by_owner(removal_lock, overlapping_locks, self_overlapping_locks); } else ldout(cct,15) << "attempt to remove lock at " << removal_lock.start << " but no locks there!" << dendl; bool remove_to_end = (0 == removal_lock.length); uint64_t removal_start = removal_lock.start; uint64_t removal_end = removal_start + removal_lock.length - 1; uint64_t old_lock_end; __s64 old_lock_client = 0; ceph_filelock *old_lock; ldout(cct,15) << "examining " << self_overlapping_locks.size() << " self-overlapping locks for removal" << dendl; for (list::iterator>::iterator iter = self_overlapping_locks.begin(); iter != self_overlapping_locks.end(); ++iter) { ldout(cct,15) << "self overlapping lock " << (*iter)->second << dendl; old_lock = &(*iter)->second; bool old_lock_to_end = (0 == old_lock->length); old_lock_end = old_lock->start + old_lock->length - 1; old_lock_client = old_lock->client; if (remove_to_end) { if (old_lock->start < removal_start) { old_lock->length = removal_start - old_lock->start; } else { ldout(cct,15) << "erasing " << (*iter)->second << dendl; held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } } else if (old_lock_to_end) { ceph_filelock append_lock = *old_lock; append_lock.start = removal_end+1; held_locks.insert(pair (append_lock.start, append_lock)); ++client_held_lock_counts[(client_t)old_lock->client]; if (old_lock->start >= removal_start) { ldout(cct,15) << "erasing " << (*iter)->second << dendl; held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } else old_lock->length = removal_start - old_lock->start; } else { if (old_lock_end > removal_end) { ceph_filelock append_lock = *old_lock; append_lock.start = removal_end + 1; append_lock.length = old_lock_end - append_lock.start + 1; held_locks.insert(pair (append_lock.start, append_lock)); ++client_held_lock_counts[(client_t)old_lock->client]; } if (old_lock->start < removal_start) { old_lock->length = removal_start - old_lock->start; } else { ldout(cct,15) << "erasing " << (*iter)->second << dendl; held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } } if (!client_held_lock_counts[old_lock_client]) { client_held_lock_counts.erase(old_lock_client); } } } bool ceph_lock_state_t::remove_all_from (client_t client) { bool cleared_any = false; if (client_held_lock_counts.count(client)) { remove_all_from(client, held_locks); client_held_lock_counts.erase(client); cleared_any = true; } if (client_waiting_lock_counts.count(client)) { remove_all_from(client, waiting_locks); client_waiting_lock_counts.erase(client); } return cleared_any; } void ceph_lock_state_t::adjust_locks(list::iterator> old_locks, ceph_filelock& new_lock, list::iterator> neighbor_locks) { ldout(cct,15) << "adjust_locks" << dendl; bool new_lock_to_end = (0 == new_lock.length); uint64_t new_lock_start = new_lock.start; uint64_t new_lock_end = new_lock.start + new_lock.length - 1; uint64_t old_lock_start, old_lock_end; __s64 old_lock_client = 0; ceph_filelock *old_lock; for (list::iterator>::iterator iter = old_locks.begin(); iter != old_locks.end(); ++iter) { old_lock = &(*iter)->second; ldout(cct,15) << "adjusting lock: " << *old_lock << dendl; bool old_lock_to_end = (0 == old_lock->length); old_lock_start = old_lock->start; old_lock_end = old_lock->start + old_lock->length - 1; new_lock_start = new_lock.start; new_lock_end = new_lock.start + new_lock.length - 1; old_lock_client = old_lock->client; if (new_lock_to_end || old_lock_to_end) { //special code path to deal with a length set at 0 ldout(cct,15) << "one lock extends forever" << dendl; if (old_lock->type == new_lock.type) { //just unify them in new lock, remove old lock ldout(cct,15) << "same lock type, unifying" << dendl; new_lock.start = (new_lock_start < old_lock_start) ? new_lock_start : old_lock_start; new_lock.length = 0; held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } else { //not same type, have to keep any remains of old lock around ldout(cct,15) << "shrinking old lock" << dendl; if (new_lock_to_end) { if (old_lock_start < new_lock_start) { old_lock->length = new_lock_start - old_lock_start; } else { held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } } else { //old lock extends past end of new lock ceph_filelock appended_lock = *old_lock; appended_lock.start = new_lock_end + 1; held_locks.insert(pair (appended_lock.start, appended_lock)); ++client_held_lock_counts[(client_t)old_lock->client]; if (old_lock_start < new_lock_start) { old_lock->length = new_lock_start - old_lock_start; } else { held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } } } } else { if (old_lock->type == new_lock.type) { //just merge them! ldout(cct,15) << "merging locks, they're the same type" << dendl; new_lock.start = (old_lock_start < new_lock_start ) ? old_lock_start : new_lock_start; int new_end = (new_lock_end > old_lock_end) ? new_lock_end : old_lock_end; new_lock.length = new_end - new_lock.start + 1; ldout(cct,15) << "erasing lock " << (*iter)->second << dendl; held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } else { //we'll have to update sizes and maybe make new locks ldout(cct,15) << "locks aren't same type, changing sizes" << dendl; if (old_lock_end > new_lock_end) { //add extra lock after new_lock ceph_filelock appended_lock = *old_lock; appended_lock.start = new_lock_end + 1; appended_lock.length = old_lock_end - appended_lock.start + 1; held_locks.insert(pair (appended_lock.start, appended_lock)); ++client_held_lock_counts[(client_t)old_lock->client]; } if (old_lock_start < new_lock_start) { old_lock->length = new_lock_start - old_lock_start; } else { //old_lock starts inside new_lock, so remove it //if it extended past new_lock_end it's been replaced held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } } } if (!client_held_lock_counts[old_lock_client]) { client_held_lock_counts.erase(old_lock_client); } } //make sure to coalesce neighboring locks for (list::iterator>::iterator iter = neighbor_locks.begin(); iter != neighbor_locks.end(); ++iter) { old_lock = &(*iter)->second; old_lock_client = old_lock->client; ldout(cct,15) << "lock to coalesce: " << *old_lock << dendl; /* because if it's a neighboring lock there can't be any self-overlapping locks that covered it */ if (old_lock->type == new_lock.type) { //merge them if (0 == new_lock.length) { if (old_lock->start + old_lock->length == new_lock.start) { new_lock.start = old_lock->start; } else assert(0); /* if there's no end to new_lock, the neighbor HAS TO be to left side */ } else if (0 == old_lock->length) { if (new_lock.start + new_lock.length == old_lock->start) { new_lock.length = 0; } else assert(0); //same as before, but reversed } else { if (old_lock->start + old_lock->length == new_lock.start) { new_lock.start = old_lock->start; new_lock.length = old_lock->length + new_lock.length; } else if (new_lock.start + new_lock.length == old_lock->start) { new_lock.length = old_lock->length + new_lock.length; } } held_locks.erase(*iter); --client_held_lock_counts[old_lock_client]; } if (!client_held_lock_counts[old_lock_client]) { client_held_lock_counts.erase(old_lock_client); } } } void ceph_lock_state_t::remove_all_from(client_t client, multimap& locks) { multimap::iterator iter = locks.begin(); while (iter != locks.end()) { if ((client_t)iter->second.client == client) { locks.erase(iter++); } else ++iter; } } multimap::iterator ceph_lock_state_t::get_lower_bound(uint64_t start, multimap& lock_map) { multimap::iterator lower_bound = lock_map.lower_bound(start); if ((lower_bound->first != start) && (start != 0) && (lower_bound != lock_map.begin())) --lower_bound; if (lock_map.end() == lower_bound) ldout(cct,15) << "get_lower_dout(15)eturning end()" << dendl; else ldout(cct,15) << "get_lower_bound returning iterator pointing to " << lower_bound->second << dendl; return lower_bound; } multimap::iterator ceph_lock_state_t::get_last_before(uint64_t end, multimap& lock_map) { multimap::iterator last = lock_map.upper_bound(end); if (last != lock_map.begin()) --last; if (lock_map.end() == last) ldout(cct,15) << "get_last_before returning end()" << dendl; else ldout(cct,15) << "get_last_before returning iterator pointing to " << last->second << dendl; return last; } bool ceph_lock_state_t::share_space( multimap::iterator& iter, uint64_t start, uint64_t end) { bool ret = ((iter->first >= start && iter->first <= end) || ((iter->first < start) && (((iter->first + iter->second.length - 1) >= start) || (0 == iter->second.length)))); ldout(cct,15) << "share_space got start: " << start << ", end: " << end << ", lock: " << iter->second << ", returning " << ret << dendl; return ret; } bool ceph_lock_state_t::get_overlapping_locks(ceph_filelock& lock, list::iterator> & overlaps, list::iterator> *self_neighbors) { ldout(cct,15) << "get_overlapping_locks" << dendl; // create a lock starting one earlier and ending one later // to check for neighbors ceph_filelock neighbor_check_lock = lock; if (neighbor_check_lock.start != 0) { neighbor_check_lock.start = neighbor_check_lock.start - 1; if (neighbor_check_lock.length) neighbor_check_lock.length = neighbor_check_lock.length + 2; } else { if (neighbor_check_lock.length) neighbor_check_lock.length = neighbor_check_lock.length + 1; } //find the last held lock starting at the point after lock uint64_t endpoint = lock.start; if (lock.length) { endpoint += lock.length; } else { endpoint = uint64_t(-1); // max offset } multimap::iterator iter = get_last_before(endpoint, held_locks); bool cont = iter != held_locks.end(); while(cont) { if (share_space(iter, lock)) { overlaps.push_front(iter); } else if (self_neighbors && ceph_filelock_owner_equal(neighbor_check_lock, iter->second) && share_space(iter, neighbor_check_lock)) { self_neighbors->push_front(iter); } if ((iter->first < lock.start) && (CEPH_LOCK_EXCL == iter->second.type)) { //can't be any more overlapping locks or they'd interfere with this one cont = false; } else if (held_locks.begin() == iter) cont = false; else --iter; } return !overlaps.empty(); } bool ceph_lock_state_t::get_waiting_overlaps(ceph_filelock& lock, list::iterator>& overlaps) { ldout(cct,15) << "get_waiting_overlaps" << dendl; multimap::iterator iter = get_last_before(lock.start + lock.length - 1, waiting_locks); bool cont = iter != waiting_locks.end(); while(cont) { if (share_space(iter, lock)) overlaps.push_front(iter); if (waiting_locks.begin() == iter) cont = false; --iter; } return !overlaps.empty(); } void ceph_lock_state_t::split_by_owner(ceph_filelock& owner, list::iterator>& locks, list::iterator>& owned_locks) { list::iterator>::iterator iter = locks.begin(); ldout(cct,15) << "owner lock: " << owner << dendl; while (iter != locks.end()) { ldout(cct,15) << "comparing to " << (*iter)->second << dendl; if (ceph_filelock_owner_equal((*iter)->second, owner)) { ldout(cct,15) << "success, pushing to owned_locks" << dendl; owned_locks.push_back(*iter); iter = locks.erase(iter); } else { ldout(cct,15) << "failure, something not equal in this group " << (*iter)->second.client << ":" << owner.client << "," << (*iter)->second.owner << ":" << owner.owner << "," << (*iter)->second.pid << ":" << owner.pid << dendl; ++iter; } } } ceph_filelock * ceph_lock_state_t::contains_exclusive_lock(list::iterator>& locks) { for (list::iterator>::iterator iter = locks.begin(); iter != locks.end(); ++iter) { if (CEPH_LOCK_EXCL == (*iter)->second.type) return &(*iter)->second; } return NULL; } ceph-0.80.11/src/mds/Migrator.h0000664000175100017510000002706512623076744020216 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Handles the import and export of mds authorities and actual cache data. * See src/doc/exports.txt for a description. */ #ifndef CEPH_MDS_MIGRATOR_H #define CEPH_MDS_MIGRATOR_H #include "include/types.h" #include #include #include using std::map; using std::list; using std::set; class MDS; class CDir; class CInode; class CDentry; class MExportDirDiscover; class MExportDirDiscoverAck; class MExportDirCancel; class MExportDirPrep; class MExportDirPrepAck; class MExportDir; class MExportDirAck; class MExportDirNotify; class MExportDirNotifyAck; class MExportDirFinish; class MExportCaps; class MExportCapsAck; class EImportStart; class Migrator { private: MDS *mds; MDCache *cache; // -- exports -- public: // export stages. used to clean up intelligently if there's a failure. const static int EXPORT_CANCELLED = 0; // cancelled const static int EXPORT_LOCKING = 1; // acquiring locks const static int EXPORT_DISCOVERING = 2; // dest is disovering export dir const static int EXPORT_FREEZING = 3; // we're freezing the dir tree const static int EXPORT_PREPPING = 4; // sending dest spanning tree to export bounds const static int EXPORT_WARNING = 5; // warning bystanders of dir_auth_pending const static int EXPORT_EXPORTING = 6; // sent actual export, waiting for ack const static int EXPORT_LOGGINGFINISH = 7; // logging EExportFinish const static int EXPORT_NOTIFYING = 8; // waiting for notifyacks static const char *get_export_statename(int s) { switch (s) { case EXPORT_LOCKING: return "locking"; case EXPORT_DISCOVERING: return "discovering"; case EXPORT_FREEZING: return "freezing"; case EXPORT_PREPPING: return "prepping"; case EXPORT_WARNING: return "warning"; case EXPORT_EXPORTING: return "exporting"; case EXPORT_LOGGINGFINISH: return "loggingfinish"; case EXPORT_NOTIFYING: return "notifying"; default: assert(0); return 0; } } protected: // export fun struct export_state_t { int state; int peer; uint64_t tid; set warning_ack_waiting; set notify_ack_waiting; map > peer_imported; list waiting_for_finish; MutationRef mut; // for freeze tree deadlock detection utime_t last_cum_auth_pins_change; int last_cum_auth_pins; int num_remote_waiters; // number of remote authpin waiters export_state_t() : state(0), peer(0), tid(0), mut(), last_cum_auth_pins(0), num_remote_waiters(0) {} }; map export_state; list > export_queue; // -- imports -- public: const static int IMPORT_DISCOVERING = 1; // waiting for prep const static int IMPORT_DISCOVERED = 2; // waiting for prep const static int IMPORT_PREPPING = 3; // opening dirs on bounds const static int IMPORT_PREPPED = 4; // opened bounds, waiting for import const static int IMPORT_LOGGINGSTART = 5; // got import, logging EImportStart const static int IMPORT_ACKING = 6; // logged EImportStart, sent ack, waiting for finish const static int IMPORT_FINISHING = 7; // sent cap imports, waiting for finish const static int IMPORT_ABORTING = 8; // notifying bystanders of an abort before unfreezing static const char *get_import_statename(int s) { switch (s) { case IMPORT_DISCOVERING: return "discovering"; case IMPORT_DISCOVERED: return "discovered"; case IMPORT_PREPPING: return "prepping"; case IMPORT_PREPPED: return "prepped"; case IMPORT_LOGGINGSTART: return "loggingstart"; case IMPORT_ACKING: return "acking"; case IMPORT_FINISHING: return "finishing"; case IMPORT_ABORTING: return "aborting"; default: assert(0); return 0; } } protected: struct import_state_t { int state; int peer; uint64_t tid; set bystanders; list bound_ls; list updated_scatterlocks; map client_map; map > peer_exports; MutationRef mut; import_state_t() : state(0), peer(0), tid(0), mut() {} }; map import_state; public: // -- cons -- Migrator(MDS *m, MDCache *c) : mds(m), cache(c) {} void dispatch(Message*); void show_importing(); void show_exporting(); // -- status -- int is_exporting(CDir *dir) { map::iterator it = export_state.find(dir); if (it != export_state.end()) return it->second.state; return 0; } bool is_exporting() { return !export_state.empty(); } int is_importing(dirfrag_t df) { map::iterator it = import_state.find(df); if (it != import_state.end()) return it->second.state; return 0; } bool is_importing() { return !import_state.empty(); } bool is_ambiguous_import(dirfrag_t df) { map::iterator p = import_state.find(df); if (p == import_state.end()) return false; if (p->second.state >= IMPORT_LOGGINGSTART && p->second.state < IMPORT_ABORTING) return true; return false; } int get_import_state(dirfrag_t df) { map::iterator it = import_state.find(df); assert(it != import_state.end()); return it->second.state; } int get_import_peer(dirfrag_t df) { map::iterator it = import_state.find(df); assert(it != import_state.end()); return it->second.peer; } int get_export_state(CDir *dir) { map::iterator it = export_state.find(dir); assert(it != export_state.end()); return it->second.state; } // this returns true if we are export @dir, // and are not waiting for @who to be // be warned of ambiguous auth. // only returns meaningful results during EXPORT_WARNING state. bool export_has_warned(CDir *dir, int who) { map::iterator it = export_state.find(dir); assert(it != export_state.end()); assert(it->second.state == EXPORT_WARNING); return (it->second.warning_ack_waiting.count(who) == 0); } bool export_has_notified(CDir *dir, int who) { map::iterator it = export_state.find(dir); assert(it != export_state.end()); assert(it->second.state == EXPORT_NOTIFYING); return (it->second.notify_ack_waiting.count(who) == 0); } void export_freeze_inc_num_waiters(CDir *dir) { map::iterator it = export_state.find(dir); assert(it != export_state.end()); it->second.num_remote_waiters++; } void find_stale_export_freeze(); // -- misc -- void handle_mds_failure_or_stop(int who); void audit(); // -- import/export -- // exporter public: void dispatch_export_dir(MDRequestRef& mdr); void export_dir(CDir *dir, int dest); void export_empty_import(CDir *dir); void export_dir_nicely(CDir *dir, int dest); void maybe_do_queued_export(); void clear_export_queue() { export_queue.clear(); } void get_export_lock_set(CDir *dir, set& locks); void get_export_client_set(CDir *dir, set &client_set); void get_export_client_set(CInode *in, set &client_set); void encode_export_inode(CInode *in, bufferlist& bl, map& exported_client_map); void encode_export_inode_caps(CInode *in, bool auth_cap, bufferlist& bl, map& exported_client_map); void finish_export_inode(CInode *in, utime_t now, int target, map& peer_imported, list& finished); void finish_export_inode_caps(CInode *in, int target, map& peer_imported); int encode_export_dir(bufferlist& exportbl, CDir *dir, map& exported_client_map, utime_t now); void finish_export_dir(CDir *dir, utime_t now, int target, map >& peer_imported, list& finished); void add_export_finish_waiter(CDir *dir, Context *c) { map::iterator it = export_state.find(dir); assert(it != export_state.end()); it->second.waiting_for_finish.push_back(c); } void clear_export_proxy_pins(CDir *dir); void export_caps(CInode *in); protected: void handle_export_discover_ack(MExportDirDiscoverAck *m); void export_frozen(CDir *dir); void handle_export_prep_ack(MExportDirPrepAck *m); void export_sessions_flushed(CDir *dir, uint64_t tid); void export_go(CDir *dir); void export_go_synced(CDir *dir, uint64_t tid); void export_try_cancel(CDir *dir, bool notify_peer=true); void export_reverse(CDir *dir); void export_notify_abort(CDir *dir, set& bounds); void handle_export_ack(MExportDirAck *m); void export_logged_finish(CDir *dir); void handle_export_notify_ack(MExportDirNotifyAck *m); void export_finish(CDir *dir); friend class C_MDC_ExportFreeze; friend class C_MDS_ExportFinishLogged; friend class C_M_ExportGo; friend class C_M_ExportSessionsFlushed; // importer void handle_export_discover(MExportDirDiscover *m); void handle_export_cancel(MExportDirCancel *m); void handle_export_prep(MExportDirPrep *m); void handle_export_dir(MExportDir *m); public: void decode_import_inode(CDentry *dn, bufferlist::iterator& blp, int oldauth, LogSegment *ls, uint64_t log_offset, map >& cap_imports, list& updated_scatterlocks); void decode_import_inode_caps(CInode *in, bool auth_cap, bufferlist::iterator &blp, map >& cap_imports); void finish_import_inode_caps(CInode *in, int from, bool auth_cap, map &export_map, map &import_map); int decode_import_dir(bufferlist::iterator& blp, int oldauth, CDir *import_root, EImportStart *le, LogSegment *ls, map >& cap_imports, list& updated_scatterlocks, utime_t now); public: void import_reverse(CDir *dir); protected: void import_reverse_discovering(dirfrag_t df); void import_reverse_discovered(dirfrag_t df, CInode *diri); void import_reverse_prepping(CDir *dir); void import_remove_pins(CDir *dir, set& bounds); void import_reverse_unfreeze(CDir *dir); void import_reverse_final(CDir *dir); void import_notify_abort(CDir *dir, set& bounds); void import_notify_finish(CDir *dir, set& bounds); void import_logged_start(dirfrag_t df, CDir *dir, int from, map &imported_client_map, map& sseqmap); void handle_export_finish(MExportDirFinish *m); public: void import_finish(CDir *dir, bool notify, bool last=true); protected: void handle_export_caps(MExportCaps *m); void logged_import_caps(CInode *in, int from, map >& cap_imports, map& client_map, map& sseqmap); friend class C_MDS_ImportDirLoggedStart; friend class C_MDS_ImportDirLoggedFinish; friend class C_M_LoggedImportCaps; // bystander void handle_export_notify(MExportDirNotify *m); }; #endif ceph-0.80.11/src/mds/CDentry.h0000664000175100017510000002416312623076744017776 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CDENTRY_H #define CEPH_CDENTRY_H #include #include using namespace std; #include "include/types.h" #include "include/buffer.h" #include "include/lru.h" #include "include/elist.h" #include "include/filepath.h" #include "mdstypes.h" #include "SimpleLock.h" #include "LocalLock.h" class CInode; class CDir; struct MDRequest; class Message; class Anchor; class CDentry; class LogSegment; class Session; // define an ordering bool operator<(const CDentry& l, const CDentry& r); // dentry class CDentry : public MDSCacheObject, public LRUObject { /* * This class uses a boost::pool to handle allocation. This is *not* * thread-safe, so don't do allocations from multiple threads! * * Alternatively, switch the pool to use a boost::singleton_pool. */ private: static boost::pool<> pool; public: static void *operator new(size_t num_bytes) { void *n = pool.malloc(); if (!n) throw std::bad_alloc(); return n; } void operator delete(void *p) { pool.free(p); } public: // -- state -- static const int STATE_NEW = (1<<0); static const int STATE_FRAGMENTING = (1<<1); static const int STATE_PURGING = (1<<2); static const int STATE_BADREMOTEINO = (1<<3); // stray dentry needs notification of releasing reference static const int STATE_STRAY = STATE_NOTIFYREF; // -- pins -- static const int PIN_INODEPIN = 1; // linked inode is pinned static const int PIN_FRAGMENTING = -2; // containing dir is refragmenting static const int PIN_PURGING = 3; const char *pin_name(int p) { switch (p) { case PIN_INODEPIN: return "inodepin"; case PIN_FRAGMENTING: return "fragmenting"; case PIN_PURGING: return "purging"; default: return generic_pin_name(p); } }; // -- wait -- //static const int WAIT_LOCK_OFFSET = 8; void add_waiter(uint64_t tag, Context *c); static const unsigned EXPORT_NONCE = 1; bool is_lt(const MDSCacheObject *r) const { return *this < *static_cast(r); } public: string name; __u32 hash; snapid_t first, last; dentry_key_t key() { return dentry_key_t(last, name.c_str()); } public: struct linkage_t { CInode *inode; inodeno_t remote_ino; unsigned char remote_d_type; linkage_t() : inode(0), remote_ino(0), remote_d_type(0) {} // dentry type is primary || remote || null // inode ptr is required for primary, optional for remote, undefined for null bool is_primary() { return remote_ino == 0 && inode != 0; } bool is_remote() { return remote_ino > 0; } bool is_null() { return remote_ino == 0 && inode == 0; } CInode *get_inode() { return inode; } inodeno_t get_remote_ino() { return remote_ino; } unsigned char get_remote_d_type() { return remote_d_type; } void set_remote(inodeno_t ino, unsigned char d_type) { remote_ino = ino; remote_d_type = d_type; inode = 0; } void link_remote(CInode *in); }; protected: CDir *dir; // containing dirfrag linkage_t linkage; list projected; version_t version; // dir version when last touched. version_t projected_version; // what it will be when i unlock/commit. public: elist::item item_dirty; elist::item item_stray; protected: int auth_pins, nested_auth_pins; #ifdef MDS_AUTHPIN_SET multiset auth_pin_set; #endif int nested_anchors; friend class Migrator; friend class Locker; friend class MDCache; friend class CInode; friend class C_MDC_XlockRequest; public: // lock static LockType lock_type; static LockType versionlock_type; SimpleLock lock; LocalLock versionlock; public: // cons CDentry(const string& n, __u32 h, snapid_t f, snapid_t l) : name(n), hash(h), first(f), last(l), dir(0), version(0), projected_version(0), item_dirty(this), auth_pins(0), nested_auth_pins(0), nested_anchors(0), lock(this, &lock_type), versionlock(this, &versionlock_type) { g_num_dn++; g_num_dna++; } CDentry(const string& n, __u32 h, inodeno_t ino, unsigned char dt, snapid_t f, snapid_t l) : name(n), hash(h), first(f), last(l), dir(0), version(0), projected_version(0), item_dirty(this), auth_pins(0), nested_auth_pins(0), nested_anchors(0), lock(this, &lock_type), versionlock(this, &versionlock_type) { g_num_dn++; g_num_dna++; linkage.remote_ino = ino; linkage.remote_d_type = dt; } ~CDentry() { g_num_dn--; g_num_dns++; } CDir *get_dir() const { return dir; } const string& get_name() const { return name; } __u32 get_hash() const { return hash; } // linkage linkage_t *get_linkage() { return &linkage; } linkage_t *_project_linkage() { projected.push_back(linkage_t()); return &projected.back(); } void push_projected_linkage() { _project_linkage(); } void push_projected_linkage(inodeno_t ino, char d_type) { linkage_t *p = _project_linkage(); p->remote_ino = ino; p->remote_d_type = d_type; } void push_projected_linkage(CInode *inode); linkage_t *pop_projected_linkage(); bool is_projected() { return projected.size(); } linkage_t *get_projected_linkage() { if (!projected.empty()) return &projected.back(); return &linkage; } CInode *get_projected_inode() { return get_projected_linkage()->inode; } bool use_projected(client_t client, const MutationRef& mut) const { return lock.can_read_projected(client) || lock.get_xlock_by() == mut; } linkage_t *get_linkage(client_t client, const MutationRef& mut) { return use_projected(client, mut) ? get_projected_linkage() : get_linkage(); } // ref counts: pin ourselves in the LRU when we're pinned. void first_get() { lru_pin(); } void last_put() { lru_unpin(); } void _put(); // auth pins bool can_auth_pin(); void auth_pin(void *by); void auth_unpin(void *by); void adjust_nested_auth_pins(int adjustment, int diradj, void *by); bool is_frozen(); bool is_freezing(); bool is_auth_pinned() { return auth_pins || nested_auth_pins; } int get_num_auth_pins() { return auth_pins; } int get_num_dir_auth_pins(); int get_num_nested_auth_pins() { return nested_auth_pins; } void adjust_nested_anchors(int by); // remote links void link_remote(linkage_t *dnl, CInode *in); void unlink_remote(linkage_t *dnl); // copy cons CDentry(const CDentry& m); const CDentry& operator= (const CDentry& right); // misc void make_path_string(string& s); void make_path(filepath& fp); void make_anchor_trace(vector& trace, CInode *in); // -- version -- version_t get_version() { return version; } void set_version(version_t v) { projected_version = version = v; } version_t get_projected_version() { return projected_version; } void set_projected_version(version_t v) { projected_version = v; } pair authority(); version_t pre_dirty(version_t min=0); void _mark_dirty(LogSegment *ls); void mark_dirty(version_t projected_dirv, LogSegment *ls); void mark_clean(); void mark_new(); bool is_new() { return state_test(STATE_NEW); } void clear_new() { state_clear(STATE_NEW); } // -- replication void encode_replica(int mds, bufferlist& bl) { if (!is_replicated()) lock.replicate_relax(); __u32 nonce = add_replica(mds); ::encode(nonce, bl); ::encode(first, bl); ::encode(linkage.remote_ino, bl); ::encode(linkage.remote_d_type, bl); __s32 ls = lock.get_replica_state(); ::encode(ls, bl); } void decode_replica(bufferlist::iterator& p, bool is_new); // -- exporting // note: this assumes the dentry already exists. // i.e., the name is already extracted... so we just need the other state. void encode_export(bufferlist& bl) { ::encode(first, bl); ::encode(state, bl); ::encode(version, bl); ::encode(projected_version, bl); ::encode(lock, bl); ::encode(replica_map, bl); get(PIN_TEMPEXPORTING); } void finish_export() { // twiddle clear_replica_map(); replica_nonce = EXPORT_NONCE; state_clear(CDentry::STATE_AUTH); if (is_dirty()) mark_clean(); put(PIN_TEMPEXPORTING); } void abort_export() { put(PIN_TEMPEXPORTING); } void decode_import(bufferlist::iterator& blp, LogSegment *ls) { ::decode(first, blp); __u32 nstate; ::decode(nstate, blp); ::decode(version, blp); ::decode(projected_version, blp); ::decode(lock, blp); ::decode(replica_map, blp); // twiddle state = 0; state_set(CDentry::STATE_AUTH); if (nstate & STATE_DIRTY) _mark_dirty(ls); if (!replica_map.empty()) get(PIN_REPLICATED); } // -- locking -- SimpleLock* get_lock(int type) { assert(type == CEPH_LOCK_DN); return &lock; } void set_object_info(MDSCacheObjectInfo &info); void encode_lock_state(int type, bufferlist& bl); void decode_lock_state(int type, bufferlist& bl); // --------------------------------------------- // replicas (on clients) public: map client_lease_map; bool is_any_leases() { return !client_lease_map.empty(); } ClientLease *get_client_lease(client_t c) { if (client_lease_map.count(c)) return client_lease_map[c]; return 0; } bool have_client_lease(client_t c) { ClientLease *l = get_client_lease(c); if (l) return true; else return false; } ClientLease *add_client_lease(client_t c, Session *session); void remove_client_lease(ClientLease *r, class Locker *locker); // returns remaining mask (if any), and kicks locker eval_gathers ostream& print_db_line_prefix(ostream& out); void print(ostream& out); friend class CDir; }; ostream& operator<<(ostream& out, CDentry& dn); #endif ceph-0.80.11/src/mds/locks.h0000664000175100017510000000631712623076744017542 0ustar jenkins-buildjenkins-build #ifndef CEPH_MDS_LOCKS_H #define CEPH_MDS_LOCKS_H struct sm_state_t { int next; // 0 if stable char loner; int replica_state; char can_read; char can_read_projected; char can_rdlock; char can_wrlock; char can_force_wrlock; char can_lease; char can_xlock; int caps; int loner_caps; int xlocker_caps; int replica_caps; }; struct sm_t { const struct sm_state_t *states; int allowed_ever_auth; int allowed_ever_replica; int careful; int can_remote_xlock; }; #define ANY 1 // auth or replica #define AUTH 2 // auth only #define XCL 3 // auth or exclusive client //#define FW 4 // fw to auth, if replica #define REQ 5 // req state change from auth, if replica extern const struct sm_t sm_simplelock; extern const struct sm_t sm_filelock; extern const struct sm_t sm_scatterlock; extern const struct sm_t sm_locallock; // -- lock states -- // sync <-> lock enum { LOCK_UNDEF = 0, // auth rep LOCK_SYNC, // AR R . RD L . / C . R RD L . / C . LOCK_LOCK, // AR R . .. . X / . . . .. . . / . . LOCK_PREXLOCK, // A . . .. . . / . . (lock) LOCK_XLOCK, // A . . .. . . / . . (lock) LOCK_XLOCKDONE, // A r p rd l x / . . (lock) <-- by same client only!! LOCK_LOCK_XLOCK, LOCK_SYNC_LOCK, // AR R . .. . . / . . R .. . . / . . LOCK_LOCK_SYNC, // A R p rd l . / . . (lock) <-- lc by same client only LOCK_EXCL, // A . . .. . . / c x * (lock) LOCK_EXCL_SYNC, // A . . .. . . / c . * (lock) LOCK_EXCL_LOCK, // A . . .. . . / . . (lock) LOCK_SYNC_EXCL, // Ar R . .. . . / c . * (sync->lock) LOCK_LOCK_EXCL, // A R . .. . . / . . (lock) LOCK_REMOTEXLOCK, // on NON-auth // * = loner mode LOCK_MIX, LOCK_SYNC_MIX, LOCK_SYNC_MIX2, LOCK_LOCK_MIX, LOCK_EXCL_MIX, LOCK_MIX_SYNC, LOCK_MIX_SYNC2, LOCK_MIX_LOCK, LOCK_MIX_LOCK2, LOCK_MIX_EXCL, LOCK_TSYN, LOCK_TSYN_LOCK, LOCK_TSYN_MIX, LOCK_LOCK_TSYN, LOCK_MIX_TSYN, LOCK_PRE_SCAN, LOCK_SCAN, LOCK_SNAP_SYNC, LOCK_XSYN, LOCK_XSYN_EXCL, LOCK_EXCL_XSYN, LOCK_XSYN_SYNC, LOCK_MAX, }; // ------------------------- // lock actions // for replicas #define LOCK_AC_SYNC -1 #define LOCK_AC_MIX -2 #define LOCK_AC_LOCK -3 #define LOCK_AC_LOCKFLUSHED -4 // for auth #define LOCK_AC_SYNCACK 1 #define LOCK_AC_MIXACK 2 #define LOCK_AC_LOCKACK 3 #define LOCK_AC_REQSCATTER 7 #define LOCK_AC_REQUNSCATTER 8 #define LOCK_AC_NUDGE 9 #define LOCK_AC_REQRDLOCK 10 #define LOCK_AC_FOR_REPLICA(a) ((a) < 0) #define LOCK_AC_FOR_AUTH(a) ((a) > 0) static inline const char *get_lock_action_name(int a) { switch (a) { case LOCK_AC_SYNC: return "sync"; case LOCK_AC_MIX: return "mix"; case LOCK_AC_LOCK: return "lock"; case LOCK_AC_LOCKFLUSHED: return "lockflushed"; case LOCK_AC_SYNCACK: return "syncack"; case LOCK_AC_MIXACK: return "mixack"; case LOCK_AC_LOCKACK: return "lockack"; case LOCK_AC_REQSCATTER: return "reqscatter"; case LOCK_AC_REQUNSCATTER: return "requnscatter"; case LOCK_AC_NUDGE: return "nudge"; case LOCK_AC_REQRDLOCK: return "reqrdlock"; default: return "???"; } } #endif ceph-0.80.11/src/mds/CInode.h0000664000175100017510000006401012623076744017562 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CINODE_H #define CEPH_CINODE_H #include "common/config.h" #include "include/dlist.h" #include "include/elist.h" #include "include/types.h" #include "include/lru.h" #include "mdstypes.h" #include "flock.h" #include "CDentry.h" #include "SimpleLock.h" #include "ScatterLock.h" #include "LocalLock.h" #include "Capability.h" #include "SnapRealm.h" #include #include #include #include #include using namespace std; class Context; class CDentry; class CDir; class Message; class CInode; class MDCache; class LogSegment; struct SnapRealm; class Session; class MClientCaps; struct ObjectOperation; class EMetaBlob; ostream& operator<<(ostream& out, CInode& in); struct cinode_lock_info_t { int lock; int wr_caps; }; extern cinode_lock_info_t cinode_lock_info[]; extern int num_cinode_locks; // cached inode wrapper class CInode : public MDSCacheObject { /* * This class uses a boost::pool to handle allocation. This is *not* * thread-safe, so don't do allocations from multiple threads! * * Alternatively, switch the pool to use a boost::singleton_pool. */ private: static boost::pool<> pool; public: static void *operator new(size_t num_bytes) { void *n = pool.malloc(); if (!n) throw std::bad_alloc(); return n; } void operator delete(void *p) { pool.free(p); } public: // -- pins -- static const int PIN_DIRFRAG = -1; static const int PIN_CAPS = 2; // client caps static const int PIN_IMPORTING = -4; // importing static const int PIN_ANCHORING = 5; static const int PIN_UNANCHORING = 6; static const int PIN_OPENINGDIR = 7; static const int PIN_REMOTEPARENT = 8; static const int PIN_BATCHOPENJOURNAL = 9; static const int PIN_SCATTERED = 10; static const int PIN_STICKYDIRS = 11; //static const int PIN_PURGING = -12; static const int PIN_FREEZING = 13; static const int PIN_FROZEN = 14; static const int PIN_IMPORTINGCAPS = -15; static const int PIN_PASTSNAPPARENT = -16; static const int PIN_OPENINGSNAPPARENTS = 17; static const int PIN_TRUNCATING = 18; static const int PIN_STRAY = 19; // we pin our stray inode while active static const int PIN_NEEDSNAPFLUSH = 20; static const int PIN_DIRTYRSTAT = 21; static const int PIN_EXPORTINGCAPS = 22; static const int PIN_DIRTYPARENT = 23; static const int PIN_DIRWAITER = 24; const char *pin_name(int p) { switch (p) { case PIN_DIRFRAG: return "dirfrag"; case PIN_CAPS: return "caps"; case PIN_IMPORTING: return "importing"; case PIN_ANCHORING: return "anchoring"; case PIN_UNANCHORING: return "unanchoring"; case PIN_OPENINGDIR: return "openingdir"; case PIN_REMOTEPARENT: return "remoteparent"; case PIN_BATCHOPENJOURNAL: return "batchopenjournal"; case PIN_SCATTERED: return "scattered"; case PIN_STICKYDIRS: return "stickydirs"; //case PIN_PURGING: return "purging"; case PIN_FREEZING: return "freezing"; case PIN_FROZEN: return "frozen"; case PIN_IMPORTINGCAPS: return "importingcaps"; case PIN_EXPORTINGCAPS: return "exportingcaps"; case PIN_PASTSNAPPARENT: return "pastsnapparent"; case PIN_OPENINGSNAPPARENTS: return "openingsnapparents"; case PIN_TRUNCATING: return "truncating"; case PIN_STRAY: return "stray"; case PIN_NEEDSNAPFLUSH: return "needsnapflush"; case PIN_DIRTYRSTAT: return "dirtyrstat"; case PIN_DIRTYPARENT: return "dirtyparent"; case PIN_DIRWAITER: return "dirwaiter"; default: return generic_pin_name(p); } } // -- state -- static const int STATE_EXPORTING = (1<<2); // on nonauth bystander. static const int STATE_ANCHORING = (1<<3); static const int STATE_UNANCHORING = (1<<4); static const int STATE_OPENINGDIR = (1<<5); static const int STATE_FREEZING = (1<<7); static const int STATE_FROZEN = (1<<8); static const int STATE_AMBIGUOUSAUTH = (1<<9); static const int STATE_EXPORTINGCAPS = (1<<10); static const int STATE_NEEDSRECOVER = (1<<11); static const int STATE_RECOVERING = (1<<12); static const int STATE_PURGING = (1<<13); static const int STATE_DIRTYPARENT = (1<<14); static const int STATE_DIRTYRSTAT = (1<<15); static const int STATE_STRAYPINNED = (1<<16); static const int STATE_FROZENAUTHPIN = (1<<17); static const int STATE_DIRTYPOOL = (1<<18); // orphan inode needs notification of releasing reference static const int STATE_ORPHAN = STATE_NOTIFYREF; static const int MASK_STATE_EXPORTED = (STATE_DIRTY|STATE_NEEDSRECOVER|STATE_DIRTYPARENT|STATE_DIRTYPOOL); static const int MASK_STATE_EXPORT_KEPT = (STATE_FROZEN|STATE_AMBIGUOUSAUTH|STATE_EXPORTINGCAPS); // -- waiters -- static const uint64_t WAIT_DIR = (1<<0); static const uint64_t WAIT_ANCHORED = (1<<1); static const uint64_t WAIT_UNANCHORED = (1<<2); static const uint64_t WAIT_FROZEN = (1<<3); static const uint64_t WAIT_TRUNC = (1<<4); static const uint64_t WAIT_FLOCK = (1<<5); static const uint64_t WAIT_ANY_MASK = (uint64_t)(-1); // misc static const unsigned EXPORT_NONCE = 1; // nonce given to replicas created by export ostream& print_db_line_prefix(ostream& out); public: MDCache *mdcache; // inode contents proper inode_t inode; // the inode itself string symlink; // symlink dest, if symlink map xattrs; fragtree_t dirfragtree; // dir frag tree, if any. always consistent with our dirfrag map. SnapRealm *snaprealm; SnapRealm *containing_realm; snapid_t first, last; map old_inodes; // key = last, value.first = first set dirty_old_rstats; bool is_multiversion() { return snaprealm || // other snaprealms will link to me inode.is_dir() || // links to me in other snaps inode.nlink > 1 || // there are remote links, possibly snapped, that will need to find me !old_inodes.empty(); // once multiversion, always multiversion. until old_inodes gets cleaned out. } snapid_t get_oldest_snap(); uint64_t last_journaled; // log offset for the last time i was journaled //loff_t last_open_journaled; // log offset for the last journaled EOpen utime_t last_dirstat_prop; // list item node for when we have unpropagated rstat data elist::item dirty_rstat_item; bool is_dirty_rstat() { return state_test(STATE_DIRTYRSTAT); } void mark_dirty_rstat(); void clear_dirty_rstat(); //bool hack_accessed; //utime_t hack_load_stamp; /** * Projection methods, used to store inode changes until they have been journaled, * at which point they are popped. * Usage: * project_inode as needed. If you're also projecting xattrs, pass * in an xattr map (by pointer), then edit the map. * If you're also projecting the snaprealm, call project_snaprealm after * calling project_inode, and modify the snaprealm as necessary. * * Then, journal. Once journaling is done, pop_and_dirty_projected_inode. * This function will take care of the inode itself, the xattrs, and the snaprealm. */ struct projected_inode_t { inode_t *inode; map *xattrs; sr_t *snapnode; projected_inode_t() : inode(NULL), xattrs(NULL), snapnode(NULL) {} projected_inode_t(inode_t *in, sr_t *sn) : inode(in), xattrs(NULL), snapnode(sn) {} projected_inode_t(inode_t *in, map *xp = NULL, sr_t *sn = NULL) : inode(in), xattrs(xp), snapnode(sn) {} }; list projected_nodes; // projected values (only defined while dirty) inode_t *project_inode(map *px=0); void pop_and_dirty_projected_inode(LogSegment *ls); projected_inode_t *get_projected_node() { if (projected_nodes.empty()) return NULL; else return projected_nodes.back(); } version_t get_projected_version() { if (projected_nodes.empty()) return inode.version; else return projected_nodes.back()->inode->version; } bool is_projected() { return !projected_nodes.empty(); } inode_t *get_projected_inode() { if (projected_nodes.empty()) return &inode; else return projected_nodes.back()->inode; } inode_t *get_previous_projected_inode() { assert(!projected_nodes.empty()); list::reverse_iterator p = projected_nodes.rbegin(); ++p; if (p != projected_nodes.rend()) return (*p)->inode; else return &inode; } map *get_projected_xattrs() { for (list::reverse_iterator p = projected_nodes.rbegin(); p != projected_nodes.rend(); ++p) if ((*p)->xattrs) return (*p)->xattrs; return &xattrs; } map *get_previous_projected_xattrs() { list::reverse_iterator p = projected_nodes.rbegin(); for (p++; // skip the most recent projected value p != projected_nodes.rend(); ++p) if ((*p)->xattrs) return (*p)->xattrs; return &xattrs; } sr_t *project_snaprealm(snapid_t snapid=0); sr_t *get_projected_srnode() { if (projected_nodes.empty()) { if (snaprealm) return &snaprealm->srnode; else return NULL; } else { for (list::reverse_iterator p = projected_nodes.rbegin(); p != projected_nodes.rend(); ++p) if ((*p)->snapnode) return (*p)->snapnode; } return &snaprealm->srnode; } void project_past_snaprealm_parent(SnapRealm *newparent); private: void pop_projected_snaprealm(sr_t *next_snaprealm); public: old_inode_t& cow_old_inode(snapid_t follows, bool cow_head); old_inode_t *pick_old_inode(snapid_t last); void pre_cow_old_inode(); void purge_stale_snap_data(const set& snaps); // -- cache infrastructure -- private: map dirfrags; // cached dir fragments under this Inode int stickydir_ref; public: __u32 hash_dentry_name(const string &dn); frag_t pick_dirfrag(const string &dn); bool has_dirfrags() { return !dirfrags.empty(); } CDir* get_dirfrag(frag_t fg) { if (dirfrags.count(fg)) { //assert(g_conf->debug_mds < 2 || dirfragtree.is_leaf(fg)); // performance hack FIXME return dirfrags[fg]; } else return NULL; } bool get_dirfrags_under(frag_t fg, list& ls); CDir* get_approx_dirfrag(frag_t fg); void get_dirfrags(list& ls); void get_nested_dirfrags(list& ls); void get_subtree_dirfrags(list& ls); CDir *get_or_open_dirfrag(MDCache *mdcache, frag_t fg); CDir *add_dirfrag(CDir *dir); void close_dirfrag(frag_t fg); void close_dirfrags(); bool has_subtree_root_dirfrag(int auth=-1); bool has_subtree_or_exporting_dirfrag(); void force_dirfrags(); void verify_dirfrags(); void get_stickydirs(); void put_stickydirs(); protected: // parent dentries in cache CDentry *parent; // primary link set remote_parents; // if hard linked list projected_parent; // for in-progress rename, (un)link, etc. pair inode_auth; // -- distributed state -- protected: // file capabilities map client_caps; // client -> caps map mds_caps_wanted; // [auth] mds -> caps wanted int replica_caps_wanted; // [replica] what i've requested from auth map > client_snap_caps; // [auth] [snap] dirty metadata we still need from the head public: map > client_need_snapflush; void add_need_snapflush(CInode *snapin, snapid_t snapid, client_t client); void remove_need_snapflush(CInode *snapin, snapid_t snapid, client_t client); protected: ceph_lock_state_t fcntl_locks; ceph_lock_state_t flock_locks; void clear_file_locks() { fcntl_locks.clear(); flock_locks.clear(); } // LogSegment dlists i (may) belong to public: elist::item item_dirty; elist::item item_caps; elist::item item_open_file; elist::item item_dirty_parent; elist::item item_dirty_dirfrag_dir; elist::item item_dirty_dirfrag_nest; elist::item item_dirty_dirfrag_dirfragtree; private: // auth pin int auth_pins; int nested_auth_pins; public: #ifdef MDS_AUTHPIN_SET multiset auth_pin_set; #endif int auth_pin_freeze_allowance; private: int nested_anchors; // _NOT_ including me! public: inode_load_vec_t pop; // friends friend class Server; friend class Locker; friend class Migrator; friend class MDCache; friend class CDir; friend class CInodeExport; public: // --------------------------- CInode(MDCache *c, bool auth=true, snapid_t f=2, snapid_t l=CEPH_NOSNAP) : mdcache(c), snaprealm(0), containing_realm(0), first(f), last(l), last_journaled(0), //last_open_journaled(0), //hack_accessed(true), stickydir_ref(0), parent(0), inode_auth(CDIR_AUTH_DEFAULT), replica_caps_wanted(0), fcntl_locks(g_ceph_context), flock_locks(g_ceph_context), item_dirty(this), item_caps(this), item_open_file(this), item_dirty_parent(this), item_dirty_dirfrag_dir(this), item_dirty_dirfrag_nest(this), item_dirty_dirfrag_dirfragtree(this), auth_pins(0), nested_auth_pins(0), auth_pin_freeze_allowance(0), nested_anchors(0), pop(ceph_clock_now(g_ceph_context)), versionlock(this, &versionlock_type), authlock(this, &authlock_type), linklock(this, &linklock_type), dirfragtreelock(this, &dirfragtreelock_type), filelock(this, &filelock_type), xattrlock(this, &xattrlock_type), snaplock(this, &snaplock_type), nestlock(this, &nestlock_type), flocklock(this, &flocklock_type), policylock(this, &policylock_type), loner_cap(-1), want_loner_cap(-1) { g_num_ino++; g_num_inoa++; state = 0; if (auth) state_set(STATE_AUTH); }; ~CInode() { g_num_ino--; g_num_inos++; close_dirfrags(); close_snaprealm(); } // -- accessors -- bool is_file() { return inode.is_file(); } bool is_symlink() { return inode.is_symlink(); } bool is_dir() { return inode.is_dir(); } bool is_anchored() { return inode.anchored; } bool is_anchoring() { return state_test(STATE_ANCHORING); } bool is_unanchoring() { return state_test(STATE_UNANCHORING); } bool is_root() { return inode.ino == MDS_INO_ROOT; } bool is_stray() { return MDS_INO_IS_STRAY(inode.ino); } bool is_mdsdir() { return MDS_INO_IS_MDSDIR(inode.ino); } bool is_base() { return is_root() || is_mdsdir(); } bool is_system() { return inode.ino < MDS_INO_SYSTEM_BASE; } bool is_head() { return last == CEPH_NOSNAP; } // note: this overloads MDSCacheObject bool is_ambiguous_auth() { return state_test(STATE_AMBIGUOUSAUTH) || MDSCacheObject::is_ambiguous_auth(); } void set_ambiguous_auth() { state_set(STATE_AMBIGUOUSAUTH); } void clear_ambiguous_auth(list& finished); void clear_ambiguous_auth(); inodeno_t ino() const { return inode.ino; } vinodeno_t vino() const { return vinodeno_t(inode.ino, last); } int d_type() const { return IFTODT(inode.mode); } inode_t& get_inode() { return inode; } CDentry* get_parent_dn() { return parent; } CDentry* get_projected_parent_dn() { return !projected_parent.empty() ? projected_parent.back() : parent; } CDir *get_parent_dir(); CDir *get_projected_parent_dir(); CInode *get_parent_inode(); bool is_lt(const MDSCacheObject *r) const { const CInode *o = static_cast(r); return ino() < o->ino() || (ino() == o->ino() && last < o->last); } // -- misc -- bool is_projected_ancestor_of(CInode *other); void make_path_string(string& s, bool force=false, CDentry *use_parent=NULL); void make_path_string_projected(string& s); void make_path(filepath& s); void make_anchor_trace(vector& trace); void name_stray_dentry(string& dname); static object_t get_object_name(inodeno_t ino, frag_t fg, const char *suffix); // -- dirtyness -- version_t get_version() { return inode.version; } version_t pre_dirty(); void _mark_dirty(LogSegment *ls); void mark_dirty(version_t projected_dirv, LogSegment *ls); void mark_clean(); void store(Context *fin); void _stored(version_t cv, Context *fin); void fetch(Context *fin); void _fetched(bufferlist& bl, bufferlist& bl2, Context *fin); void build_backtrace(int64_t pool, inode_backtrace_t& bt); void store_backtrace(Context *fin); void _stored_backtrace(version_t v, Context *fin); void _mark_dirty_parent(LogSegment *ls, bool dirty_pool=false); void clear_dirty_parent(); bool is_dirty_parent() { return state_test(STATE_DIRTYPARENT); } bool is_dirty_pool() { return state_test(STATE_DIRTYPOOL); } void encode_store(bufferlist& bl); void decode_store(bufferlist::iterator& bl); void encode_replica(int rep, bufferlist& bl) { assert(is_auth()); // relax locks? if (!is_replicated()) replicate_relax_locks(); __u32 nonce = add_replica(rep); ::encode(nonce, bl); _encode_base(bl); _encode_locks_state_for_replica(bl); } void decode_replica(bufferlist::iterator& p, bool is_new) { __u32 nonce; ::decode(nonce, p); replica_nonce = nonce; _decode_base(p); _decode_locks_state(p, is_new); } // -- waiting -- protected: map > waiting_on_dir; public: void add_dir_waiter(frag_t fg, Context *c); void take_dir_waiting(frag_t fg, list& ls); bool is_waiting_for_dir(frag_t fg) { return waiting_on_dir.count(fg); } void add_waiter(uint64_t tag, Context *c); void take_waiting(uint64_t tag, list& ls); // -- encode/decode helpers -- void _encode_base(bufferlist& bl); void _decode_base(bufferlist::iterator& p); void _encode_locks_full(bufferlist& bl); void _decode_locks_full(bufferlist::iterator& p); void _encode_locks_state_for_replica(bufferlist& bl); void _encode_locks_state_for_rejoin(bufferlist& bl, int rep); void _decode_locks_state(bufferlist::iterator& p, bool is_new); void _decode_locks_rejoin(bufferlist::iterator& p, list& waiters, list& eval_locks); // -- import/export -- void encode_export(bufferlist& bl); void finish_export(utime_t now); void abort_export() { put(PIN_TEMPEXPORTING); assert(state_test(STATE_EXPORTINGCAPS)); state_clear(STATE_EXPORTINGCAPS); put(PIN_EXPORTINGCAPS); } void decode_import(bufferlist::iterator& p, LogSegment *ls); // for giving to clients int encode_inodestat(bufferlist& bl, Session *session, SnapRealm *realm, snapid_t snapid=CEPH_NOSNAP, unsigned max_bytes=0, int getattr_wants=0); void encode_cap_message(MClientCaps *m, Capability *cap); // -- locks -- public: static LockType versionlock_type; static LockType authlock_type; static LockType linklock_type; static LockType dirfragtreelock_type; static LockType filelock_type; static LockType xattrlock_type; static LockType snaplock_type; static LockType nestlock_type; static LockType flocklock_type; static LockType policylock_type; LocalLock versionlock; SimpleLock authlock; SimpleLock linklock; ScatterLock dirfragtreelock; ScatterLock filelock; SimpleLock xattrlock; SimpleLock snaplock; ScatterLock nestlock; SimpleLock flocklock; SimpleLock policylock; SimpleLock* get_lock(int type) { switch (type) { case CEPH_LOCK_IFILE: return &filelock; case CEPH_LOCK_IAUTH: return &authlock; case CEPH_LOCK_ILINK: return &linklock; case CEPH_LOCK_IDFT: return &dirfragtreelock; case CEPH_LOCK_IXATTR: return &xattrlock; case CEPH_LOCK_ISNAP: return &snaplock; case CEPH_LOCK_INEST: return &nestlock; case CEPH_LOCK_IFLOCK: return &flocklock; case CEPH_LOCK_IPOLICY: return &policylock; } return 0; } void set_object_info(MDSCacheObjectInfo &info); void encode_lock_state(int type, bufferlist& bl); void decode_lock_state(int type, bufferlist& bl); void _finish_frag_update(CDir *dir, MutationRef& mut); void clear_dirty_scattered(int type); bool is_dirty_scattered(); void clear_scatter_dirty(); // on rejoin ack void start_scatter(ScatterLock *lock); void finish_scatter_update(ScatterLock *lock, CDir *dir, version_t inode_version, version_t dir_accounted_version); void finish_scatter_gather_update(int type); void finish_scatter_gather_update_accounted(int type, MutationRef& mut, EMetaBlob *metablob); // -- snap -- void open_snaprealm(bool no_split=false); void close_snaprealm(bool no_join=false); SnapRealm *find_snaprealm(); void encode_snap_blob(bufferlist &bl); void decode_snap_blob(bufferlist &bl); void encode_snap(bufferlist& bl); void decode_snap(bufferlist::iterator& p); // -- caps -- (new) // client caps client_t loner_cap, want_loner_cap; client_t get_loner() { return loner_cap; } client_t get_wanted_loner() { return want_loner_cap; } // this is the loner state our locks should aim for client_t get_target_loner() { if (loner_cap == want_loner_cap) return loner_cap; else return -1; } client_t calc_ideal_loner(); client_t choose_ideal_loner(); bool try_set_loner(); void set_loner_cap(client_t l); bool try_drop_loner(); // choose new lock state during recovery, based on issued caps void choose_lock_state(SimpleLock *lock, int allissued); void choose_lock_states(); int count_nonstale_caps() { int n = 0; for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) if (!it->second->is_stale()) n++; return n; } bool multiple_nonstale_caps() { int n = 0; for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) if (!it->second->is_stale()) { if (n) return true; n++; } return false; } bool is_any_caps() { return !client_caps.empty(); } bool is_any_nonstale_caps() { return count_nonstale_caps(); } map& get_mds_caps_wanted() { return mds_caps_wanted; } map& get_client_caps() { return client_caps; } Capability *get_client_cap(client_t client) { if (client_caps.count(client)) return client_caps[client]; return 0; } int get_client_cap_pending(client_t client) { Capability *c = get_client_cap(client); if (c) return c->pending(); return 0; } Capability *add_client_cap(client_t client, Session *session, SnapRealm *conrealm=0); void remove_client_cap(client_t client); void move_to_realm(SnapRealm *realm); Capability *reconnect_cap(client_t client, ceph_mds_cap_reconnect& icr, Session *session); void clear_client_caps_after_export(); void export_client_caps(map& cl); // caps allowed int get_caps_liked(); int get_caps_allowed_ever(); int get_caps_allowed_by_type(int type); int get_caps_careful(); int get_xlocker_mask(client_t client); int get_caps_allowed_for_client(client_t client); // caps issued, wanted int get_caps_issued(int *ploner = 0, int *pother = 0, int *pxlocker = 0, int shift = 0, int mask = -1); bool is_any_caps_wanted(); int get_caps_wanted(int *ploner = 0, int *pother = 0, int shift = 0, int mask = -1); bool issued_caps_need_gather(SimpleLock *lock); void replicate_relax_locks(); // -- authority -- pair authority(); // -- auth pins -- bool is_auth_pinned() { return auth_pins || nested_auth_pins; } int get_num_auth_pins() { return auth_pins; } int get_num_nested_auth_pins() { return nested_auth_pins; } void adjust_nested_auth_pins(int a, void *by); bool can_auth_pin(); void auth_pin(void *by); void auth_unpin(void *by); void adjust_nested_anchors(int by); int get_nested_anchors() { return nested_anchors; } // -- freeze -- bool is_freezing_inode() { return state_test(STATE_FREEZING); } bool is_frozen_inode() { return state_test(STATE_FROZEN); } bool is_frozen_auth_pin() { return state_test(STATE_FROZENAUTHPIN); } bool is_frozen(); bool is_frozen_dir(); bool is_freezing(); /* Freeze the inode. auth_pin_allowance lets the caller account for any * auth_pins it is itself holding/responsible for. */ bool freeze_inode(int auth_pin_allowance=0); void unfreeze_inode(list& finished); void unfreeze_inode(); void freeze_auth_pin(); void unfreeze_auth_pin(); // -- reference counting -- void bad_put(int by) { generic_dout(0) << " bad put " << *this << " by " << by << " " << pin_name(by) << " was " << ref #ifdef MDS_REF_SET << " (" << ref_map << ")" #endif << dendl; #ifdef MDS_REF_SET assert(ref_map[by] > 0); #endif assert(ref > 0); } void bad_get(int by) { generic_dout(0) << " bad get " << *this << " by " << by << " " << pin_name(by) << " was " << ref #ifdef MDS_REF_SET << " (" << ref_map << ")" #endif << dendl; #ifdef MDS_REF_SET assert(ref_map[by] >= 0); #endif } void first_get(); void last_put(); void _put(); // -- hierarchy stuff -- public: void set_primary_parent(CDentry *p) { assert(parent == 0); parent = p; } void remove_primary_parent(CDentry *dn) { assert(dn == parent); parent = 0; } void add_remote_parent(CDentry *p); void remove_remote_parent(CDentry *p); int num_remote_parents() { return remote_parents.size(); } void push_projected_parent(CDentry *dn) { projected_parent.push_back(dn); } void pop_projected_parent() { assert(projected_parent.size()); parent = projected_parent.front(); projected_parent.pop_front(); } void print(ostream& out); }; #endif ceph-0.80.11/src/mds/SnapClient.h0000664000175100017510000000312612623076744020462 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SNAPCLIENT_H #define CEPH_SNAPCLIENT_H #include "MDSTableClient.h" #include "snap.h" class Context; class MDS; class LogSegment; class SnapClient : public MDSTableClient { public: SnapClient(MDS *m) : MDSTableClient(m, TABLE_SNAP) {} void resend_queries() {} void handle_query_result(MMDSTableRequest *m) {} void prepare_create(inodeno_t dirino, const string& name, utime_t stamp, version_t *pstid, bufferlist *pbl, Context *onfinish) { bufferlist bl; __u32 op = TABLE_OP_CREATE; ::encode(op, bl); ::encode(dirino, bl); ::encode(name, bl); ::encode(stamp, bl); _prepare(bl, pstid, pbl, onfinish); } void prepare_create_realm(inodeno_t ino, version_t *pstid, bufferlist *pbl, Context *onfinish) { bufferlist bl; __u32 op = TABLE_OP_CREATE; ::encode(op, bl); ::encode(ino, bl); _prepare(bl, pstid, pbl, onfinish); } void prepare_destroy(inodeno_t ino, snapid_t snapid, version_t *pstid, bufferlist *pbl, Context *onfinish) { bufferlist bl; __u32 op = TABLE_OP_DESTROY; ::encode(op, bl); ::encode(ino, bl); ::encode(snapid, bl); _prepare(bl, pstid, pbl, onfinish); } }; #endif ceph-0.80.11/src/mds/SessionMap.cc0000664000175100017510000001501712623076744020643 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDS.h" #include "MDCache.h" #include "SessionMap.h" #include "osdc/Filer.h" #include "common/config.h" #include "common/errno.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".sessionmap " void SessionMap::dump() { dout(10) << "dump" << dendl; for (ceph::unordered_map::iterator p = session_map.begin(); p != session_map.end(); ++p) dout(10) << p->first << " " << p->second << " state " << p->second->get_state_name() << " completed " << p->second->info.completed_requests << " prealloc_inos " << p->second->info.prealloc_inos << " used_ions " << p->second->info.used_inos << dendl; } // ---------------- // LOAD object_t SessionMap::get_object_name() { char s[30]; snprintf(s, sizeof(s), "mds%d_sessionmap", mds->whoami); return object_t(s); } class C_SM_Load : public Context { SessionMap *sessionmap; public: bufferlist bl; C_SM_Load(SessionMap *cm) : sessionmap(cm) {} void finish(int r) { sessionmap->_load_finish(r, bl); } }; void SessionMap::load(Context *onload) { dout(10) << "load" << dendl; if (onload) waiting_for_load.push_back(onload); C_SM_Load *c = new C_SM_Load(this); object_t oid = get_object_name(); object_locator_t oloc(mds->mdsmap->get_metadata_pool()); mds->objecter->read_full(oid, oloc, CEPH_NOSNAP, &c->bl, 0, c); } void SessionMap::_load_finish(int r, bufferlist &bl) { bufferlist::iterator blp = bl.begin(); if (r < 0) { derr << "_load_finish got " << cpp_strerror(r) << dendl; assert(0 == "failed to load sessionmap"); } dump(); decode(blp); // note: this sets last_cap_renew = now() dout(10) << "_load_finish v " << version << ", " << session_map.size() << " sessions, " << bl.length() << " bytes" << dendl; projected = committing = committed = version; dump(); finish_contexts(g_ceph_context, waiting_for_load); } // ---------------- // SAVE class C_SM_Save : public Context { SessionMap *sessionmap; version_t version; public: C_SM_Save(SessionMap *cm, version_t v) : sessionmap(cm), version(v) {} void finish(int r) { assert(r == 0); sessionmap->_save_finish(version); } }; void SessionMap::save(Context *onsave, version_t needv) { dout(10) << "save needv " << needv << ", v " << version << dendl; if (needv && committing >= needv) { assert(committing > committed); commit_waiters[committing].push_back(onsave); return; } commit_waiters[version].push_back(onsave); bufferlist bl; encode(bl); committing = version; SnapContext snapc; object_t oid = get_object_name(); object_locator_t oloc(mds->mdsmap->get_metadata_pool()); mds->objecter->write_full(oid, oloc, snapc, bl, ceph_clock_now(g_ceph_context), 0, NULL, new C_SM_Save(this, version)); } void SessionMap::_save_finish(version_t v) { dout(10) << "_save_finish v" << v << dendl; committed = v; finish_contexts(g_ceph_context, commit_waiters[v]); commit_waiters.erase(v); } // ------------------- void SessionMap::encode(bufferlist& bl) const { uint64_t pre = -1; // for 0.19 compatibility; we forgot an encoding prefix. ::encode(pre, bl); ENCODE_START(3, 3, bl); ::encode(version, bl); for (ceph::unordered_map::const_iterator p = session_map.begin(); p != session_map.end(); ++p) { if (p->second->is_open() || p->second->is_closing() || p->second->is_stale() || p->second->is_killing()) { ::encode(p->first, bl); p->second->info.encode(bl); } } ENCODE_FINISH(bl); } void SessionMap::decode(bufferlist::iterator& p) { utime_t now = ceph_clock_now(g_ceph_context); uint64_t pre; ::decode(pre, p); if (pre == (uint64_t)-1) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, p); assert(struct_v >= 2); ::decode(version, p); while (!p.end()) { entity_inst_t inst; ::decode(inst.name, p); Session *s = get_or_add_session(inst); if (s->is_closed()) set_state(s, Session::STATE_OPEN); s->info.decode(p); } DECODE_FINISH(p); } else { // --- old format ---- version = pre; // this is a meaningless upper bound. can be ignored. __u32 n; ::decode(n, p); while (n-- && !p.end()) { bufferlist::iterator p2 = p; Session *s = new Session; s->info.decode(p); if (session_map.count(s->info.inst.name)) { // eager client connected too fast! aie. dout(10) << " already had session for " << s->info.inst.name << ", recovering" << dendl; entity_name_t n = s->info.inst.name; delete s; s = session_map[n]; p = p2; s->info.decode(p); } else { session_map[s->info.inst.name] = s; } set_state(s, Session::STATE_OPEN); s->last_cap_renew = now; } } } void SessionMap::dump(Formatter *f) const { f->open_array_section("Sessions"); for (ceph::unordered_map::const_iterator p = session_map.begin(); p != session_map.end(); ++p) { f->open_object_section("Session"); f->open_object_section("entity name"); p->first.dump(f); f->close_section(); // entity name f->open_object_section("Session info"); p->second->info.dump(f); f->close_section(); // Session info f->close_section(); // Session } f->close_section(); // Sessions } void SessionMap::generate_test_instances(list& ls) { // pretty boring for now ls.push_back(new SessionMap(NULL)); } void SessionMap::wipe() { dout(1) << "wipe start" << dendl; dump(); while (!session_map.empty()) { Session *s = session_map.begin()->second; remove_session(s); } version = ++projected; dout(1) << "wipe result" << dendl; dump(); dout(1) << "wipe done" << dendl; } void SessionMap::wipe_ino_prealloc() { for (ceph::unordered_map::iterator p = session_map.begin(); p != session_map.end(); ++p) { p->second->pending_prealloc_inos.clear(); p->second->info.prealloc_inos.clear(); p->second->info.used_inos.clear(); } projected = ++version; } ceph-0.80.11/src/mds/MDS.cc0000664000175100017510000017773612623076744017226 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "global/signal_handler.h" #include "include/types.h" #include "common/entity_name.h" #include "common/Clock.h" #include "common/signal.h" #include "common/ceph_argparse.h" #include "common/errno.h" #include "msg/Messenger.h" #include "mon/MonClient.h" #include "osd/OSDMap.h" #include "osdc/Objecter.h" #include "osdc/Filer.h" #include "osdc/Journaler.h" #include "MDSMap.h" #include "MDS.h" #include "Server.h" #include "Locker.h" #include "MDCache.h" #include "MDLog.h" #include "MDBalancer.h" #include "Migrator.h" #include "AnchorServer.h" #include "AnchorClient.h" #include "SnapServer.h" #include "SnapClient.h" #include "InoTable.h" #include "common/perf_counters.h" #include "common/Timer.h" #include "events/ESession.h" #include "messages/MMDSMap.h" #include "messages/MMDSBeacon.h" #include "messages/MGenericMessage.h" #include "messages/MOSDMap.h" #include "messages/MClientRequest.h" #include "messages/MClientRequestForward.h" #include "messages/MMDSTableRequest.h" #include "messages/MMonCommand.h" #include "auth/AuthAuthorizeHandler.h" #include "auth/KeyRing.h" #include "common/config.h" #include "perfglue/cpu_profiler.h" #include "perfglue/heap_profiler.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << whoami << '.' << incarnation << ' ' // cons/des MDS::MDS(const std::string &n, Messenger *m, MonClient *mc) : Dispatcher(m->cct), mds_lock("MDS::mds_lock"), timer(m->cct, mds_lock), authorize_handler_cluster_registry(new AuthAuthorizeHandlerRegistry(m->cct, m->cct->_conf->auth_supported.length() ? m->cct->_conf->auth_supported : m->cct->_conf->auth_cluster_required)), authorize_handler_service_registry(new AuthAuthorizeHandlerRegistry(m->cct, m->cct->_conf->auth_supported.length() ? m->cct->_conf->auth_supported : m->cct->_conf->auth_service_required)), name(n), whoami(-1), incarnation(0), standby_for_rank(MDSMap::MDS_NO_STANDBY_PREF), standby_type(0), standby_replaying(false), messenger(m), monc(mc), clog(m->cct, messenger, &mc->monmap, LogClient::NO_FLAGS), sessionmap(this) { orig_argc = 0; orig_argv = NULL; last_tid = 0; monc->set_messenger(messenger); mdsmap = new MDSMap; osdmap = new OSDMap; objecter = new Objecter(m->cct, messenger, monc, osdmap, mds_lock, timer, 0, 0); objecter->unset_honor_osdmap_full(); filer = new Filer(objecter); mdcache = new MDCache(this); mdlog = new MDLog(this); balancer = new MDBalancer(this); inotable = new InoTable(this); snapserver = new SnapServer(this); snapclient = new SnapClient(this); anchorserver = new AnchorServer(this); anchorclient = new AnchorClient(this); server = new Server(this); locker = new Locker(this, mdcache); dispatch_depth = 0; // clients last_client_mdsmap_bcast = 0; // beacon beacon_last_seq = 0; beacon_sender = 0; was_laggy = false; // tick tick_event = 0; req_rate = 0; last_state = want_state = state = MDSMap::STATE_BOOT; logger = 0; mlogger = 0; } MDS::~MDS() { Mutex::Locker lock(mds_lock); delete authorize_handler_service_registry; delete authorize_handler_cluster_registry; if (mdcache) { delete mdcache; mdcache = NULL; } if (mdlog) { delete mdlog; mdlog = NULL; } if (balancer) { delete balancer; balancer = NULL; } if (inotable) { delete inotable; inotable = NULL; } if (anchorserver) { delete anchorserver; anchorserver = NULL; } if (snapserver) { delete snapserver; snapserver = NULL; } if (snapclient) { delete snapclient; snapclient = NULL; } if (anchorclient) { delete anchorclient; anchorclient = NULL; } if (osdmap) { delete osdmap; osdmap = 0; } if (mdsmap) { delete mdsmap; mdsmap = 0; } if (server) { delete server; server = 0; } if (locker) { delete locker; locker = 0; } if (filer) { delete filer; filer = 0; } if (objecter) { delete objecter; objecter = 0; } if (logger) { g_ceph_context->get_perfcounters_collection()->remove(logger); delete logger; logger = 0; } if (mlogger) { g_ceph_context->get_perfcounters_collection()->remove(mlogger); delete mlogger; mlogger = 0; } if (messenger) delete messenger; } void MDS::create_logger() { dout(10) << "create_logger" << dendl; { PerfCountersBuilder mds_plb(g_ceph_context, "mds", l_mds_first, l_mds_last); mds_plb.add_u64_counter(l_mds_req, "req"); // FIXME: nobody is actually setting this mds_plb.add_u64_counter(l_mds_reply, "reply"); mds_plb.add_time_avg(l_mds_replyl, "replyl"); mds_plb.add_u64_counter(l_mds_fw, "fw"); mds_plb.add_u64_counter(l_mds_dir_f, "dir_f"); mds_plb.add_u64_counter(l_mds_dir_c, "dir_c"); mds_plb.add_u64_counter(l_mds_dir_sp, "dir_sp"); mds_plb.add_u64_counter(l_mds_dir_ffc, "dir_ffc"); //mds_plb.add_u64_counter("mkdir"); /* mds_plb.add_u64_counter("newin"); // new inodes (pre)loaded mds_plb.add_u64_counter("newt"); // inodes first touched/used mds_plb.add_u64_counter("outt"); // trimmed touched mds_plb.add_u64_counter("outut"); // trimmed untouched (wasted effort) mds_plb.add_fl_avg("oututl"); // avg trim latency for untouched mds_plb.add_u64_counter("dirt1"); mds_plb.add_u64_counter("dirt2"); mds_plb.add_u64_counter("dirt3"); mds_plb.add_u64_counter("dirt4"); mds_plb.add_u64_counter("dirt5"); */ mds_plb.add_u64(l_mds_imax, "imax"); mds_plb.add_u64(l_mds_i, "i"); mds_plb.add_u64(l_mds_itop, "itop"); mds_plb.add_u64(l_mds_ibot, "ibot"); mds_plb.add_u64(l_mds_iptail, "iptail"); mds_plb.add_u64(l_mds_ipin, "ipin"); mds_plb.add_u64_counter(l_mds_iex, "iex"); mds_plb.add_u64_counter(l_mds_icap, "icap"); mds_plb.add_u64_counter(l_mds_cap, "cap"); mds_plb.add_u64_counter(l_mds_dis, "dis"); // FIXME: unused mds_plb.add_u64_counter(l_mds_t, "t"); mds_plb.add_u64_counter(l_mds_thit, "thit"); mds_plb.add_u64_counter(l_mds_tfw, "tfw"); mds_plb.add_u64_counter(l_mds_tdis, "tdis"); mds_plb.add_u64_counter(l_mds_tdirf, "tdirf"); mds_plb.add_u64_counter(l_mds_trino, "trino"); mds_plb.add_u64_counter(l_mds_tlock, "tlock"); mds_plb.add_u64(l_mds_l, "l"); mds_plb.add_u64(l_mds_q, "q"); mds_plb.add_u64(l_mds_popanyd, "popanyd"); // FIXME: unused mds_plb.add_u64(l_mds_popnest, "popnest"); mds_plb.add_u64(l_mds_sm, "sm"); mds_plb.add_u64_counter(l_mds_ex, "ex"); mds_plb.add_u64_counter(l_mds_iexp, "iexp"); mds_plb.add_u64_counter(l_mds_im, "im"); mds_plb.add_u64_counter(l_mds_iim, "iim"); logger = mds_plb.create_perf_counters(); g_ceph_context->get_perfcounters_collection()->add(logger); } { PerfCountersBuilder mdm_plb(g_ceph_context, "mds_mem", l_mdm_first, l_mdm_last); mdm_plb.add_u64(l_mdm_ino, "ino"); mdm_plb.add_u64_counter(l_mdm_inoa, "ino+"); mdm_plb.add_u64_counter(l_mdm_inos, "ino-"); mdm_plb.add_u64(l_mdm_dir, "dir"); mdm_plb.add_u64_counter(l_mdm_dira, "dir+"); mdm_plb.add_u64_counter(l_mdm_dirs, "dir-"); mdm_plb.add_u64(l_mdm_dn, "dn"); mdm_plb.add_u64_counter(l_mdm_dna, "dn+"); mdm_plb.add_u64_counter(l_mdm_dns, "dn-"); mdm_plb.add_u64(l_mdm_cap, "cap"); mdm_plb.add_u64_counter(l_mdm_capa, "cap+"); mdm_plb.add_u64_counter(l_mdm_caps, "cap-"); mdm_plb.add_u64(l_mdm_rss, "rss"); mdm_plb.add_u64(l_mdm_heap, "heap"); mdm_plb.add_u64(l_mdm_malloc, "malloc"); mdm_plb.add_u64(l_mdm_buf, "buf"); mlogger = mdm_plb.create_perf_counters(); g_ceph_context->get_perfcounters_collection()->add(mlogger); } mdlog->create_logger(); server->create_logger(); } MDSTableClient *MDS::get_table_client(int t) { switch (t) { case TABLE_ANCHOR: return anchorclient; case TABLE_SNAP: return snapclient; default: assert(0); } } MDSTableServer *MDS::get_table_server(int t) { switch (t) { case TABLE_ANCHOR: return anchorserver; case TABLE_SNAP: return snapserver; default: assert(0); } } void MDS::send_message(Message *m, Connection *c) { assert(c); messenger->send_message(m, c); } void MDS::send_message_mds(Message *m, int mds) { if (!mdsmap->is_up(mds)) { dout(10) << "send_message_mds mds." << mds << " not up, dropping " << *m << dendl; m->put(); return; } // send mdsmap first? if (mds != whoami && peer_mdsmap_epoch[mds] < mdsmap->get_epoch()) { messenger->send_message(new MMDSMap(monc->get_fsid(), mdsmap), mdsmap->get_inst(mds)); peer_mdsmap_epoch[mds] = mdsmap->get_epoch(); } // send message messenger->send_message(m, mdsmap->get_inst(mds)); } void MDS::forward_message_mds(Message *m, int mds) { assert(mds != whoami); // client request? if (m->get_type() == CEPH_MSG_CLIENT_REQUEST && (static_cast(m))->get_source().is_client()) { MClientRequest *creq = static_cast(m); creq->inc_num_fwd(); // inc forward counter /* * don't actually forward if non-idempotent! * client has to do it. although the MDS will ignore duplicate requests, * the affected metadata may migrate, in which case the new authority * won't have the metareq_id in the completed request map. */ // NEW: always make the client resend! bool client_must_resend = true; //!creq->can_forward(); // tell the client where it should go messenger->send_message(new MClientRequestForward(creq->get_tid(), mds, creq->get_num_fwd(), client_must_resend), creq->get_source_inst()); if (client_must_resend) { m->put(); return; } } // these are the only types of messages we should be 'forwarding'; they // explicitly encode their source mds, which gets clobbered when we resend // them here. assert(m->get_type() == MSG_MDS_DIRUPDATE || m->get_type() == MSG_MDS_EXPORTDIRDISCOVER); // send mdsmap first? if (peer_mdsmap_epoch[mds] < mdsmap->get_epoch()) { messenger->send_message(new MMDSMap(monc->get_fsid(), mdsmap), mdsmap->get_inst(mds)); peer_mdsmap_epoch[mds] = mdsmap->get_epoch(); } messenger->send_message(m, mdsmap->get_inst(mds)); } void MDS::send_message_client_counted(Message *m, client_t client) { Session *session = sessionmap.get_session(entity_name_t::CLIENT(client.v)); if (session) { send_message_client_counted(m, session); } else { dout(10) << "send_message_client_counted no session for client." << client << " " << *m << dendl; } } void MDS::send_message_client_counted(Message *m, Connection *connection) { Session *session = static_cast(connection->get_priv()); if (session) { session->put(); // do not carry ref send_message_client_counted(m, session); } else { dout(10) << "send_message_client_counted has no session for " << m->get_source_inst() << dendl; // another Connection took over the Session } } void MDS::send_message_client_counted(Message *m, Session *session) { version_t seq = session->inc_push_seq(); dout(10) << "send_message_client_counted " << session->info.inst.name << " seq " << seq << " " << *m << dendl; if (session->connection) { messenger->send_message(m, session->connection); } else { session->preopen_out_queue.push_back(m); } } void MDS::send_message_client(Message *m, Session *session) { dout(10) << "send_message_client " << session->info.inst << " " << *m << dendl; if (session->connection) { messenger->send_message(m, session->connection); } else { session->preopen_out_queue.push_back(m); } } int MDS::init(int wanted_state) { dout(10) << sizeof(MDSCacheObject) << "\tMDSCacheObject" << dendl; dout(10) << sizeof(CInode) << "\tCInode" << dendl; dout(10) << sizeof(elist::item) << "\t elist<>::item *7=" << 7*sizeof(elist::item) << dendl; dout(10) << sizeof(inode_t) << "\t inode_t " << dendl; dout(10) << sizeof(nest_info_t) << "\t nest_info_t " << dendl; dout(10) << sizeof(frag_info_t) << "\t frag_info_t " << dendl; dout(10) << sizeof(SimpleLock) << "\t SimpleLock *5=" << 5*sizeof(SimpleLock) << dendl; dout(10) << sizeof(ScatterLock) << "\t ScatterLock *3=" << 3*sizeof(ScatterLock) << dendl; dout(10) << sizeof(CDentry) << "\tCDentry" << dendl; dout(10) << sizeof(elist::item) << "\t elist<>::item" << dendl; dout(10) << sizeof(SimpleLock) << "\t SimpleLock" << dendl; dout(10) << sizeof(CDir) << "\tCDir " << dendl; dout(10) << sizeof(elist::item) << "\t elist<>::item *2=" << 2*sizeof(elist::item) << dendl; dout(10) << sizeof(fnode_t) << "\t fnode_t " << dendl; dout(10) << sizeof(nest_info_t) << "\t nest_info_t *2" << dendl; dout(10) << sizeof(frag_info_t) << "\t frag_info_t *2" << dendl; dout(10) << sizeof(Capability) << "\tCapability " << dendl; dout(10) << sizeof(xlist::item) << "\t xlist<>::item *2=" << 2*sizeof(xlist::item) << dendl; messenger->add_dispatcher_tail(this); // get monmap monc->set_messenger(messenger); monc->set_want_keys(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD | CEPH_ENTITY_TYPE_MDS); monc->init(); // tell monc about log_client so it will know about mon session resets monc->set_log_client(&clog); int r = monc->authenticate(); if (r < 0) { derr << "ERROR: failed to authenticate: " << cpp_strerror(-r) << dendl; mds_lock.Lock(); suicide(); mds_lock.Unlock(); return r; } while (monc->wait_auth_rotating(30.0) < 0) { derr << "unable to obtain rotating service keys; retrying" << dendl; } objecter->init_unlocked(); mds_lock.Lock(); if (want_state == CEPH_MDS_STATE_DNE) { mds_lock.Unlock(); return 0; } objecter->init_locked(); monc->sub_want("mdsmap", 0, 0); monc->renew_subs(); mds_lock.Unlock(); // verify that osds support tmap2omap while (true) { objecter->maybe_request_map(); objecter->wait_for_osd_map(); uint64_t osd_features = objecter->osdmap->get_up_osd_features(); if (osd_features & CEPH_FEATURE_OSD_TMAP2OMAP) break; if (objecter->osdmap->get_num_up_osds() > 0) { derr << "*** one or more OSDs do not support TMAP2OMAP; upgrade OSDs before starting MDS (or downgrade MDS) ***" << dendl; } else { derr << "*** no OSDs are up as of epoch " << objecter->osdmap->get_epoch() << ", waiting" << dendl; } sleep(10); } mds_lock.Lock(); if (want_state == CEPH_MDS_STATE_DNE) { suicide(); // we could do something more graceful here } timer.init(); if (wanted_state==MDSMap::STATE_BOOT && g_conf->mds_standby_replay) wanted_state = MDSMap::STATE_STANDBY_REPLAY; // starting beacon. this will induce an MDSMap from the monitor want_state = wanted_state; if (wanted_state==MDSMap::STATE_STANDBY_REPLAY || wanted_state==MDSMap::STATE_ONESHOT_REPLAY) { g_conf->set_val_or_die("mds_standby_replay", "true"); g_conf->apply_changes(NULL); if ( wanted_state == MDSMap::STATE_ONESHOT_REPLAY && (g_conf->mds_standby_for_rank == -1) && g_conf->mds_standby_for_name.empty()) { // uh-oh, must specify one or the other! dout(0) << "Specified oneshot replay mode but not an MDS!" << dendl; suicide(); } want_state = MDSMap::STATE_BOOT; standby_type = wanted_state; } standby_for_rank = g_conf->mds_standby_for_rank; standby_for_name.assign(g_conf->mds_standby_for_name); if (wanted_state == MDSMap::STATE_STANDBY_REPLAY && standby_for_rank == -1) { if (standby_for_name.empty()) standby_for_rank = MDSMap::MDS_STANDBY_ANY; else standby_for_rank = MDSMap::MDS_STANDBY_NAME; } else if (!standby_type && !standby_for_name.empty()) standby_for_rank = MDSMap::MDS_MATCHED_ACTIVE; beacon_start(); whoami = -1; messenger->set_myname(entity_name_t::MDS(whoami)); // schedule tick reset_tick(); create_logger(); mds_lock.Unlock(); return 0; } void MDS::reset_tick() { // cancel old if (tick_event) timer.cancel_event(tick_event); // schedule tick_event = new C_MDS_Tick(this); timer.add_event_after(g_conf->mds_tick_interval, tick_event); } void MDS::tick() { tick_event = 0; // reschedule reset_tick(); if (is_laggy()) { dout(5) << "tick bailing out since we seem laggy" << dendl; return; } // make sure mds log flushes, trims periodically mdlog->flush(); if (is_active() || is_stopping()) { mdcache->trim(); mdcache->trim_client_leases(); mdcache->check_memory_usage(); mdlog->trim(); // NOT during recovery! } // log utime_t now = ceph_clock_now(g_ceph_context); mds_load_t load = balancer->get_load(now); if (logger) { req_rate = logger->get(l_mds_req); logger->set(l_mds_l, 100 * load.mds_load()); logger->set(l_mds_q, messenger->get_dispatch_queue_len()); logger->set(l_mds_sm, mdcache->num_subtrees()); mdcache->log_stat(); } // ... if (is_clientreplay() || is_active() || is_stopping()) { locker->scatter_tick(); server->find_idle_sessions(); } if (is_reconnect()) server->reconnect_tick(); if (is_active()) { balancer->tick(); mdcache->find_stale_fragment_freeze(); mdcache->migrator->find_stale_export_freeze(); if (snapserver) snapserver->check_osd_map(false); } } // ----------------------- // beacons void MDS::beacon_start() { beacon_send(); // send first beacon } void MDS::beacon_send() { ++beacon_last_seq; dout(10) << "beacon_send " << ceph_mds_state_name(want_state) << " seq " << beacon_last_seq << " (currently " << ceph_mds_state_name(state) << ")" << dendl; beacon_seq_stamp[beacon_last_seq] = ceph_clock_now(g_ceph_context); MMDSBeacon *beacon = new MMDSBeacon(monc->get_fsid(), monc->get_global_id(), name, mdsmap->get_epoch(), want_state, beacon_last_seq); beacon->set_standby_for_rank(standby_for_rank); beacon->set_standby_for_name(standby_for_name); // include _my_ feature set CompatSet mdsmap_compat(get_mdsmap_compat_set_default()); mdsmap_compat.merge(mdsmap->compat); beacon->set_compat(mdsmap_compat); monc->send_mon_message(beacon); // schedule next sender if (beacon_sender) timer.cancel_event(beacon_sender); beacon_sender = new C_MDS_BeaconSender(this); timer.add_event_after(g_conf->mds_beacon_interval, beacon_sender); } bool MDS::is_laggy() { if (beacon_last_acked_stamp == utime_t()) return false; utime_t now = ceph_clock_now(g_ceph_context); utime_t since = now - beacon_last_acked_stamp; if (since > g_conf->mds_beacon_grace) { dout(5) << "is_laggy " << since << " > " << g_conf->mds_beacon_grace << " since last acked beacon" << dendl; was_laggy = true; if (since > (g_conf->mds_beacon_grace*2)) { // maybe it's not us? dout(5) << "initiating monitor reconnect; maybe we're not the slow one" << dendl; monc->reopen_session(); } return true; } return false; } /* This fuction puts the passed message before returning */ void MDS::handle_mds_beacon(MMDSBeacon *m) { version_t seq = m->get_seq(); // update lab if (beacon_seq_stamp.count(seq)) { utime_t now = ceph_clock_now(g_ceph_context); if (beacon_seq_stamp[seq] > beacon_last_acked_stamp) { beacon_last_acked_stamp = beacon_seq_stamp[seq]; utime_t rtt = now - beacon_last_acked_stamp; dout(10) << "handle_mds_beacon " << ceph_mds_state_name(m->get_state()) << " seq " << m->get_seq() << " rtt " << rtt << dendl; if (was_laggy && rtt < g_conf->mds_beacon_grace) { dout(0) << "handle_mds_beacon no longer laggy" << dendl; was_laggy = false; laggy_until = now; } } else { // Mark myself laggy if system clock goes backwards. Hopping // later beacons will clear it. dout(1) << "handle_mds_beacon system clock goes backwards, " << "mark myself laggy" << dendl; beacon_last_acked_stamp = now - utime_t(g_conf->mds_beacon_grace + 1, 0); was_laggy = true; } // clean up seq_stamp map while (!beacon_seq_stamp.empty() && beacon_seq_stamp.begin()->first <= seq) beacon_seq_stamp.erase(beacon_seq_stamp.begin()); } else { dout(10) << "handle_mds_beacon " << ceph_mds_state_name(m->get_state()) << " seq " << m->get_seq() << " dne" << dendl; } m->put(); } void MDS::request_osdmap(Context *c) { objecter->wait_for_new_map(c, osdmap->get_epoch()); } /* This function DOES put the passed message before returning*/ void MDS::handle_command(MMonCommand *m) { dout(10) << "handle_command args: " << m->cmd << dendl; if (m->cmd[0] == "injectargs") { if (m->cmd.size() < 2) { derr << "Ignoring empty injectargs!" << dendl; } else { std::ostringstream oss; mds_lock.Unlock(); g_conf->injectargs(m->cmd[1], &oss); mds_lock.Lock(); derr << "injectargs:" << dendl; derr << oss.str() << dendl; } } else if (m->cmd[0] == "dumpcache") { if (m->cmd.size() > 1) mdcache->dump_cache(m->cmd[1].c_str()); else mdcache->dump_cache(); } else if (m->cmd[0] == "exit") { suicide(); } else if (m->cmd[0] == "respawn") { respawn(); } else if (m->cmd[0] == "session" && m->cmd[1] == "kill") { Session *session = sessionmap.get_session(entity_name_t(CEPH_ENTITY_TYPE_CLIENT, strtol(m->cmd[2].c_str(), 0, 10))); if (session) server->kill_session(session); else dout(15) << "session " << session << " not in sessionmap!" << dendl; } else if (m->cmd[0] == "issue_caps") { long inum = strtol(m->cmd[1].c_str(), 0, 10); CInode *in = mdcache->get_inode(inodeno_t(inum)); if (in) { bool r = locker->issue_caps(in); dout(20) << "called issue_caps on inode " << inum << " with result " << r << dendl; } else dout(15) << "inode " << inum << " not in mdcache!" << dendl; } else if (m->cmd[0] == "try_eval") { long inum = strtol(m->cmd[1].c_str(), 0, 10); int mask = strtol(m->cmd[2].c_str(), 0, 10); CInode * ino = mdcache->get_inode(inodeno_t(inum)); if (ino) { locker->try_eval(ino, mask); dout(20) << "try_eval(" << inum << ", " << mask << ")" << dendl; } else dout(15) << "inode " << inum << " not in mdcache!" << dendl; } else if (m->cmd[0] == "fragment_dir") { if (m->cmd.size() == 4) { filepath fp(m->cmd[1].c_str()); CInode *in = mdcache->cache_traverse(fp); if (in) { frag_t fg; if (fg.parse(m->cmd[2].c_str())) { CDir *dir = in->get_dirfrag(fg); if (dir) { if (dir->is_auth()) { int by = atoi(m->cmd[3].c_str()); if (by) mdcache->split_dir(dir, by); else dout(0) << "need to split by >0 bits" << dendl; } else dout(0) << "dir " << dir->dirfrag() << " not auth" << dendl; } else dout(0) << "dir " << in->ino() << " " << fg << " dne" << dendl; } else dout(0) << " frag " << m->cmd[2] << " does not parse" << dendl; } else dout(0) << "path " << fp << " not found" << dendl; } else dout(0) << "bad syntax" << dendl; } else if (m->cmd[0] == "merge_dir") { if (m->cmd.size() == 3) { filepath fp(m->cmd[1].c_str()); CInode *in = mdcache->cache_traverse(fp); if (in) { frag_t fg; if (fg.parse(m->cmd[2].c_str())) { mdcache->merge_dir(in, fg); } else dout(0) << " frag " << m->cmd[2] << " does not parse" << dendl; } else dout(0) << "path " << fp << " not found" << dendl; } else dout(0) << "bad syntax" << dendl; } else if (m->cmd[0] == "export_dir") { if (m->cmd.size() == 3) { filepath fp(m->cmd[1].c_str()); int target = atoi(m->cmd[2].c_str()); if (target != whoami && mdsmap->is_up(target) && mdsmap->is_in(target)) { CInode *in = mdcache->cache_traverse(fp); if (in) { CDir *dir = in->get_dirfrag(frag_t()); if (dir && dir->is_auth()) { mdcache->migrator->export_dir(dir, target); } else dout(0) << "bad export_dir path dirfrag frag_t() or dir not auth" << dendl; } else dout(0) << "bad export_dir path" << dendl; } else dout(0) << "bad export_dir target syntax" << dendl; } else dout(0) << "bad export_dir syntax" << dendl; } else if (m->cmd[0] == "cpu_profiler") { ostringstream ss; cpu_profiler_handle_command(m->cmd, ss); clog.info() << ss.str(); } else if (m->cmd[0] == "heap") { if (!ceph_using_tcmalloc()) clog.info() << "tcmalloc not enabled, can't use heap profiler commands\n"; else { ostringstream ss; vector cmdargs; cmdargs.insert(cmdargs.begin(), m->cmd.begin()+1, m->cmd.end()); ceph_heap_profiler_handle_command(cmdargs, ss); clog.info() << ss.str(); } } else dout(0) << "unrecognized command! " << m->cmd << dendl; m->put(); } /* This function deletes the passed message before returning. */ void MDS::handle_mds_map(MMDSMap *m) { version_t epoch = m->get_epoch(); dout(5) << "handle_mds_map epoch " << epoch << " from " << m->get_source() << dendl; // note source's map version if (m->get_source().is_mds() && peer_mdsmap_epoch[m->get_source().num()] < epoch) { dout(15) << " peer " << m->get_source() << " has mdsmap epoch >= " << epoch << dendl; peer_mdsmap_epoch[m->get_source().num()] = epoch; } // is it new? if (epoch <= mdsmap->get_epoch()) { dout(5) << " old map epoch " << epoch << " <= " << mdsmap->get_epoch() << ", discarding" << dendl; m->put(); return; } // keep old map, for a moment MDSMap *oldmap = mdsmap; int oldwhoami = whoami; int oldstate = state; entity_addr_t addr; // decode and process mdsmap = new MDSMap; mdsmap->decode(m->get_encoded()); monc->sub_got("mdsmap", mdsmap->get_epoch()); // verify compatset CompatSet mdsmap_compat(get_mdsmap_compat_set_all()); dout(10) << " my compat " << mdsmap_compat << dendl; dout(10) << " mdsmap compat " << mdsmap->compat << dendl; if (!mdsmap_compat.writeable(mdsmap->compat)) { dout(0) << "handle_mds_map mdsmap compatset " << mdsmap->compat << " not writeable with daemon features " << mdsmap_compat << ", killing myself" << dendl; suicide(); goto out; } // see who i am addr = messenger->get_myaddr(); whoami = mdsmap->get_rank_gid(monc->get_global_id()); state = mdsmap->get_state_gid(monc->get_global_id()); incarnation = mdsmap->get_inc_gid(monc->get_global_id()); dout(10) << "map says i am " << addr << " mds." << whoami << "." << incarnation << " state " << ceph_mds_state_name(state) << dendl; // mark down any failed peers for (map::const_iterator p = oldmap->get_mds_info().begin(); p != oldmap->get_mds_info().end(); ++p) { if (mdsmap->get_mds_info().count(p->first) == 0) { dout(10) << " peer mds gid " << p->first << " removed from map" << dendl; messenger->mark_down(p->second.addr); } } if (state != oldstate) last_state = oldstate; if (state == MDSMap::STATE_STANDBY) { want_state = state = MDSMap::STATE_STANDBY; dout(1) << "handle_mds_map standby" << dendl; if (standby_type) // we want to be in standby_replay or oneshot_replay! request_state(standby_type); goto out; } else if (state == MDSMap::STATE_STANDBY_REPLAY) { if (standby_type && standby_type != MDSMap::STATE_STANDBY_REPLAY) { want_state = standby_type; beacon_send(); state = oldstate; goto out; } } if (whoami < 0) { if (state == MDSMap::STATE_STANDBY_REPLAY || state == MDSMap::STATE_ONESHOT_REPLAY) { // fill in whoami from standby-for-rank. If we let this be changed // the logic used to set it here will need to be adjusted. whoami = mdsmap->get_mds_info_gid(monc->get_global_id()).standby_for_rank; } else { if (want_state == MDSMap::STATE_STANDBY) { dout(10) << "dropped out of mdsmap, try to re-add myself" << dendl; want_state = state = MDSMap::STATE_BOOT; goto out; } if (want_state == MDSMap::STATE_BOOT) { dout(10) << "not in map yet" << dendl; } else { // did i get kicked by someone else? if (g_conf->mds_enforce_unique_name) { if (uint64_t existing = mdsmap->find_mds_gid_by_name(name)) { MDSMap::mds_info_t& i = mdsmap->get_info_gid(existing); if (i.global_id > monc->get_global_id()) { dout(1) << "handle_mds_map i (" << addr << ") dne in the mdsmap, new instance has larger gid " << i.global_id << ", suicide" << dendl; suicide(); goto out; } } } dout(1) << "handle_mds_map i (" << addr << ") dne in the mdsmap, respawning myself" << dendl; respawn(); } goto out; } } // ?? if (oldwhoami != whoami || oldstate != state) { // update messenger. if (state == MDSMap::STATE_STANDBY_REPLAY || state == MDSMap::STATE_ONESHOT_REPLAY) { dout(1) << "handle_mds_map i am now mds." << monc->get_global_id() << "." << incarnation << "replaying mds." << whoami << "." << incarnation << dendl; messenger->set_myname(entity_name_t::MDS(monc->get_global_id())); } else { dout(1) << "handle_mds_map i am now mds." << whoami << "." << incarnation << dendl; messenger->set_myname(entity_name_t::MDS(whoami)); } } // tell objecter my incarnation if (objecter->get_client_incarnation() != incarnation) objecter->set_client_incarnation(incarnation); // for debug if (g_conf->mds_dump_cache_on_map) mdcache->dump_cache(); // did it change? if (oldstate != state) { dout(1) << "handle_mds_map state change " << ceph_mds_state_name(oldstate) << " --> " << ceph_mds_state_name(state) << dendl; want_state = state; if (oldstate == MDSMap::STATE_STANDBY_REPLAY) { dout(10) << "Monitor activated us! Deactivating replay loop" << dendl; assert (state == MDSMap::STATE_REPLAY); } else { // did i just recover? if ((is_active() || is_clientreplay()) && (oldstate == MDSMap::STATE_CREATING || oldstate == MDSMap::STATE_REJOIN || oldstate == MDSMap::STATE_RECONNECT)) recovery_done(oldstate); if (is_active()) { active_start(); } else if (is_any_replay()) { replay_start(); } else if (is_resolve()) { resolve_start(); } else if (is_reconnect()) { reconnect_start(); } else if (is_rejoin()) { rejoin_start(); } else if (is_clientreplay()) { clientreplay_start(); } else if (is_creating()) { boot_create(); } else if (is_starting()) { boot_start(); } else if (is_stopping()) { assert(oldstate == MDSMap::STATE_ACTIVE); stopping_start(); } } } // RESOLVE // is someone else newly resolving? if (is_resolve() || is_reconnect() || is_rejoin() || is_clientreplay() || is_active() || is_stopping()) { if (!oldmap->is_resolving() && mdsmap->is_resolving()) { set resolve; mdsmap->get_mds_set(resolve, MDSMap::STATE_RESOLVE); dout(10) << " resolve set is " << resolve << dendl; calc_recovery_set(); mdcache->send_resolves(); } } // REJOIN // is everybody finally rejoining? if (is_rejoin() || is_clientreplay() || is_active() || is_stopping()) { // did we start? if (!oldmap->is_rejoining() && mdsmap->is_rejoining()) rejoin_joint_start(); // did we finish? if (g_conf->mds_dump_cache_after_rejoin && oldmap->is_rejoining() && !mdsmap->is_rejoining()) mdcache->dump_cache(); // for DEBUG only if (oldstate >= MDSMap::STATE_REJOIN) { // ACTIVE|CLIENTREPLAY|REJOIN => we can discover from them. set olddis, dis; oldmap->get_mds_set(olddis, MDSMap::STATE_ACTIVE); oldmap->get_mds_set(olddis, MDSMap::STATE_CLIENTREPLAY); oldmap->get_mds_set(olddis, MDSMap::STATE_REJOIN); mdsmap->get_mds_set(dis, MDSMap::STATE_ACTIVE); mdsmap->get_mds_set(dis, MDSMap::STATE_CLIENTREPLAY); mdsmap->get_mds_set(dis, MDSMap::STATE_REJOIN); for (set::iterator p = dis.begin(); p != dis.end(); ++p) if (*p != whoami && // not me olddis.count(*p) == 0) { // newly so? mdcache->kick_discovers(*p); mdcache->kick_open_ino_peers(*p); } } } if (oldmap->is_degraded() && !mdsmap->is_degraded() && state >= MDSMap::STATE_ACTIVE) dout(1) << "cluster recovered." << dendl; // did someone go active? if (oldstate >= MDSMap::STATE_CLIENTREPLAY && (is_clientreplay() || is_active() || is_stopping())) { set oldactive, active; oldmap->get_mds_set(oldactive, MDSMap::STATE_ACTIVE); oldmap->get_mds_set(oldactive, MDSMap::STATE_CLIENTREPLAY); mdsmap->get_mds_set(active, MDSMap::STATE_ACTIVE); mdsmap->get_mds_set(active, MDSMap::STATE_CLIENTREPLAY); for (set::iterator p = active.begin(); p != active.end(); ++p) if (*p != whoami && // not me oldactive.count(*p) == 0) // newly so? handle_mds_recovery(*p); } // did someone fail? if (true) { // new failed? set oldfailed, failed; oldmap->get_failed_mds_set(oldfailed); mdsmap->get_failed_mds_set(failed); for (set::iterator p = failed.begin(); p != failed.end(); ++p) if (oldfailed.count(*p) == 0) { messenger->mark_down(oldmap->get_inst(*p).addr); handle_mds_failure(*p); } // or down then up? // did their addr/inst change? set up; mdsmap->get_up_mds_set(up); for (set::iterator p = up.begin(); p != up.end(); ++p) if (oldmap->have_inst(*p) && oldmap->get_inst(*p) != mdsmap->get_inst(*p)) { messenger->mark_down(oldmap->get_inst(*p).addr); handle_mds_failure(*p); } } if (is_clientreplay() || is_active() || is_stopping()) { // did anyone stop? set oldstopped, stopped; oldmap->get_stopped_mds_set(oldstopped); mdsmap->get_stopped_mds_set(stopped); for (set::iterator p = stopped.begin(); p != stopped.end(); ++p) if (oldstopped.count(*p) == 0) // newly so? mdcache->migrator->handle_mds_failure_or_stop(*p); } if (!is_any_replay()) balancer->try_rebalance(); { map >::iterator p = waiting_for_mdsmap.begin(); while (p != waiting_for_mdsmap.end() && p->first <= mdsmap->get_epoch()) { list ls; ls.swap(p->second); waiting_for_mdsmap.erase(p++); finish_contexts(g_ceph_context, ls); } } out: m->put(); delete oldmap; } void MDS::bcast_mds_map() { dout(7) << "bcast_mds_map " << mdsmap->get_epoch() << dendl; // share the map with mounted clients set clients; sessionmap.get_client_session_set(clients); for (set::const_iterator p = clients.begin(); p != clients.end(); ++p) messenger->send_message(new MMDSMap(monc->get_fsid(), mdsmap), (*p)->connection); last_client_mdsmap_bcast = mdsmap->get_epoch(); } void MDS::request_state(int s) { dout(3) << "request_state " << ceph_mds_state_name(s) << dendl; want_state = s; beacon_send(); } class C_MDS_CreateFinish : public Context { MDS *mds; public: C_MDS_CreateFinish(MDS *m) : mds(m) {} void finish(int r) { mds->creating_done(); } }; void MDS::boot_create() { dout(3) << "boot_create" << dendl; C_GatherBuilder fin(g_ceph_context, new C_MDS_CreateFinish(this)); mdcache->init_layouts(); // start with a fresh journal dout(10) << "boot_create creating fresh journal" << dendl; mdlog->create(fin.new_sub()); // open new journal segment, but do not journal subtree map (yet) mdlog->prepare_new_segment(); if (whoami == mdsmap->get_root()) { dout(3) << "boot_create creating fresh hierarchy" << dendl; mdcache->create_empty_hierarchy(fin.get()); } dout(3) << "boot_create creating mydir hierarchy" << dendl; mdcache->create_mydir_hierarchy(fin.get()); // fixme: fake out inotable (reset, pretend loaded) dout(10) << "boot_create creating fresh inotable table" << dendl; inotable->reset(); inotable->save(fin.new_sub()); // write empty sessionmap sessionmap.save(fin.new_sub()); // initialize tables if (mdsmap->get_tableserver() == whoami) { dout(10) << "boot_create creating fresh anchortable" << dendl; anchorserver->reset(); anchorserver->save(fin.new_sub()); dout(10) << "boot_create creating fresh snaptable" << dendl; snapserver->reset(); snapserver->save(fin.new_sub()); } assert(g_conf->mds_kill_create_at != 1); // ok now journal it mdlog->journal_segment_subtree_map(); mdlog->wait_for_safe(fin.new_sub()); mdlog->flush(); fin.activate(); } void MDS::creating_done() { dout(1)<< "creating_done" << dendl; request_state(MDSMap::STATE_ACTIVE); } class C_MDS_BootStart : public Context { MDS *mds; int nextstep; public: C_MDS_BootStart(MDS *m, int n) : mds(m), nextstep(n) {} void finish(int r) { mds->boot_start(nextstep, r); } }; void MDS::boot_start(int step, int r) { if (r < 0) { if (is_standby_replay() && (r == -EAGAIN)) { dout(0) << "boot_start encountered an error EAGAIN" << ", respawning since we fell behind journal" << dendl; respawn(); } else { dout(0) << "boot_start encountered an error, failing" << dendl; suicide(); return; } } switch (step) { case 0: mdcache->init_layouts(); step = 1; // fall-thru. case 1: { C_GatherBuilder gather(g_ceph_context, new C_MDS_BootStart(this, 2)); dout(2) << "boot_start " << step << ": opening inotable" << dendl; inotable->load(gather.new_sub()); dout(2) << "boot_start " << step << ": opening sessionmap" << dendl; sessionmap.load(gather.new_sub()); if (mdsmap->get_tableserver() == whoami) { dout(2) << "boot_start " << step << ": opening anchor table" << dendl; anchorserver->load(gather.new_sub()); dout(2) << "boot_start " << step << ": opening snap table" << dendl; snapserver->load(gather.new_sub()); } dout(2) << "boot_start " << step << ": opening mds log" << dendl; mdlog->open(gather.new_sub()); gather.activate(); } break; case 2: { dout(2) << "boot_start " << step << ": loading/discovering base inodes" << dendl; C_GatherBuilder gather(g_ceph_context, new C_MDS_BootStart(this, 3)); mdcache->open_mydir_inode(gather.new_sub()); if (is_starting() || whoami == mdsmap->get_root()) { // load root inode off disk if we are auth mdcache->open_root_inode(gather.new_sub()); } else { // replay. make up fake root inode to start with mdcache->create_root_inode(); } gather.activate(); } break; case 3: if (is_any_replay()) { dout(2) << "boot_start " << step << ": replaying mds log" << dendl; mdlog->replay(new C_MDS_BootStart(this, 4)); break; } else { dout(2) << "boot_start " << step << ": positioning at end of old mds log" << dendl; mdlog->append(); step++; } case 4: if (is_any_replay()) { replay_done(); break; } step++; starting_done(); break; } } void MDS::starting_done() { dout(3) << "starting_done" << dendl; assert(is_starting()); request_state(MDSMap::STATE_ACTIVE); mdcache->open_root(); // start new segment mdlog->start_new_segment(0); } void MDS::calc_recovery_set() { // initialize gather sets set rs; mdsmap->get_recovery_mds_set(rs); rs.erase(whoami); mdcache->set_recovery_set(rs); dout(1) << " recovery set is " << rs << dendl; } void MDS::replay_start() { dout(1) << "replay_start" << dendl; if (is_standby_replay()) standby_replaying = true; standby_type = 0; calc_recovery_set(); dout(1) << " need osdmap epoch " << mdsmap->get_last_failure_osd_epoch() <<", have " << osdmap->get_epoch() << dendl; // start? if (osdmap->get_epoch() >= mdsmap->get_last_failure_osd_epoch()) { boot_start(); } else { dout(1) << " waiting for osdmap " << mdsmap->get_last_failure_osd_epoch() << " (which blacklists prior instance)" << dendl; objecter->wait_for_new_map(new C_MDS_BootStart(this, 0), mdsmap->get_last_failure_osd_epoch()); } } class MDS::C_MDS_StandbyReplayRestartFinish : public Context { MDS *mds; uint64_t old_read_pos; public: C_MDS_StandbyReplayRestartFinish(MDS *mds_, uint64_t old_read_pos_) : mds(mds_), old_read_pos(old_read_pos_) {} void finish(int r) { mds->_standby_replay_restart_finish(r, old_read_pos); } }; void MDS::_standby_replay_restart_finish(int r, uint64_t old_read_pos) { if (old_read_pos < mdlog->get_journaler()->get_trimmed_pos()) { dout(0) << "standby MDS fell behind active MDS journal's expire_pos, restarting" << dendl; respawn(); /* we're too far back, and this is easier than trying to reset everything in the cache, etc */ } else { mdlog->standby_trim_segments(); boot_start(3, r); } } inline void MDS::standby_replay_restart() { dout(1) << "standby_replay_restart" << (standby_replaying ? " (as standby)":" (final takeover pass)") << dendl; if (!standby_replaying && osdmap->get_epoch() < mdsmap->get_last_failure_osd_epoch()) { dout(1) << " waiting for osdmap " << mdsmap->get_last_failure_osd_epoch() << " (which blacklists prior instance)" << dendl; objecter->wait_for_new_map(new C_MDS_BootStart(this, 3), mdsmap->get_last_failure_osd_epoch()); } else { mdlog->get_journaler()->reread_head_and_probe( new C_MDS_StandbyReplayRestartFinish(this, mdlog->get_journaler()->get_read_pos())); } } class MDS::C_MDS_StandbyReplayRestart : public Context { MDS *mds; public: C_MDS_StandbyReplayRestart(MDS *m) : mds(m) {} void finish(int r) { assert(!r); mds->standby_replay_restart(); } }; void MDS::replay_done() { dout(1) << "replay_done" << (standby_replaying ? " (as standby)" : "") << dendl; if (is_oneshot_replay()) { dout(2) << "hack. journal looks ok. shutting down." << dendl; suicide(); return; } if (is_standby_replay()) { dout(10) << "setting replay timer" << dendl; timer.add_event_after(g_conf->mds_replay_interval, new C_MDS_StandbyReplayRestart(this)); return; } if (standby_replaying) { dout(10) << " last replay pass was as a standby; making final pass" << dendl; standby_replaying = false; standby_replay_restart(); return; } dout(1) << "making mds journal writeable" << dendl; mdlog->get_journaler()->set_writeable(); mdlog->get_journaler()->trim_tail(); if (g_conf->mds_wipe_sessions) { dout(1) << "wiping out client sessions" << dendl; sessionmap.wipe(); sessionmap.save(new C_NoopContext); } if (g_conf->mds_wipe_ino_prealloc) { dout(1) << "wiping out ino prealloc from sessions" << dendl; sessionmap.wipe_ino_prealloc(); sessionmap.save(new C_NoopContext); } if (g_conf->mds_skip_ino) { inodeno_t i = g_conf->mds_skip_ino; dout(1) << "skipping " << i << " inodes" << dendl; inotable->skip_inos(i); inotable->save(new C_NoopContext); } if (mdsmap->get_num_in_mds() == 1 && mdsmap->get_num_failed_mds() == 0) { // just me! dout(2) << "i am alone, moving to state reconnect" << dendl; request_state(MDSMap::STATE_RECONNECT); } else { dout(2) << "i am not alone, moving to state resolve" << dendl; request_state(MDSMap::STATE_RESOLVE); } } void MDS::reopen_log() { dout(1) << "reopen_log" << dendl; mdcache->rollback_uncommitted_fragments(); } void MDS::resolve_start() { dout(1) << "resolve_start" << dendl; reopen_log(); mdcache->resolve_start(); finish_contexts(g_ceph_context, waiting_for_resolve); } void MDS::resolve_done() { dout(1) << "resolve_done" << dendl; request_state(MDSMap::STATE_RECONNECT); } void MDS::reconnect_start() { dout(1) << "reconnect_start" << dendl; if (last_state == MDSMap::STATE_REPLAY) reopen_log(); server->reconnect_clients(); finish_contexts(g_ceph_context, waiting_for_reconnect); } void MDS::reconnect_done() { dout(1) << "reconnect_done" << dendl; request_state(MDSMap::STATE_REJOIN); // move to rejoin state } void MDS::rejoin_joint_start() { dout(1) << "rejoin_joint_start" << dendl; mdcache->rejoin_send_rejoins(); } void MDS::rejoin_start() { dout(1) << "rejoin_start" << dendl; mdcache->rejoin_start(); } void MDS::rejoin_done() { dout(1) << "rejoin_done" << dendl; mdcache->show_subtrees(); mdcache->show_cache(); // funny case: is our cache empty? no subtrees? if (!mdcache->is_subtrees()) { dout(1) << " empty cache, no subtrees, leaving cluster" << dendl; request_state(MDSMap::STATE_STOPPED); return; } if (replay_queue.empty()) request_state(MDSMap::STATE_ACTIVE); else request_state(MDSMap::STATE_CLIENTREPLAY); } void MDS::clientreplay_start() { dout(1) << "clientreplay_start" << dendl; finish_contexts(g_ceph_context, waiting_for_replay); // kick waiters queue_one_replay(); } void MDS::clientreplay_done() { dout(1) << "clientreplay_done" << dendl; request_state(MDSMap::STATE_ACTIVE); } void MDS::active_start() { dout(1) << "active_start" << dendl; if (last_state == MDSMap::STATE_CREATING) mdcache->open_root(); mdcache->clean_open_file_lists(); mdcache->export_remaining_imported_caps(); finish_contexts(g_ceph_context, waiting_for_replay); // kick waiters finish_contexts(g_ceph_context, waiting_for_active); // kick waiters } void MDS::recovery_done(int oldstate) { dout(1) << "recovery_done -- successful recovery!" << dendl; assert(is_clientreplay() || is_active()); // kick anchortable (resent AGREEs) if (mdsmap->get_tableserver() == whoami) { set active; mdsmap->get_mds_set(active, MDSMap::STATE_CLIENTREPLAY); mdsmap->get_mds_set(active, MDSMap::STATE_ACTIVE); mdsmap->get_mds_set(active, MDSMap::STATE_STOPPING); anchorserver->finish_recovery(active); snapserver->finish_recovery(active); } if (oldstate == MDSMap::STATE_CREATING) return; mdcache->start_recovered_truncates(); mdcache->do_file_recover(); mdcache->reissue_all_caps(); // tell connected clients //bcast_mds_map(); // not anymore, they get this from the monitor mdcache->populate_mydir(); } void MDS::handle_mds_recovery(int who) { dout(5) << "handle_mds_recovery mds." << who << dendl; mdcache->handle_mds_recovery(who); if (mdsmap->get_tableserver() == whoami) { anchorserver->handle_mds_recovery(who); snapserver->handle_mds_recovery(who); } queue_waiters(waiting_for_active_peer[who]); waiting_for_active_peer.erase(who); } void MDS::handle_mds_failure(int who) { if (who == whoami) { dout(5) << "handle_mds_failure for myself; not doing anything" << dendl; return; } dout(5) << "handle_mds_failure mds." << who << dendl; mdcache->handle_mds_failure(who); anchorclient->handle_mds_failure(who); snapclient->handle_mds_failure(who); } void MDS::stopping_start() { dout(2) << "stopping_start" << dendl; if (mdsmap->get_num_in_mds() == 1 && !sessionmap.empty()) { // we're the only mds up! dout(0) << "we are the last MDS, and have mounted clients: we cannot flush our journal. suicide!" << dendl; suicide(); } mdcache->shutdown_start(); } void MDS::stopping_done() { dout(2) << "stopping_done" << dendl; // tell monitor we shut down cleanly. request_state(MDSMap::STATE_STOPPED); } void MDS::handle_signal(int signum) { assert(signum == SIGINT || signum == SIGTERM); derr << "*** got signal " << sys_siglist[signum] << " ***" << dendl; mds_lock.Lock(); suicide(); mds_lock.Unlock(); } void MDS::suicide() { assert(mds_lock.is_locked()); want_state = CEPH_MDS_STATE_DNE; // whatever. dout(1) << "suicide. wanted " << ceph_mds_state_name(want_state) << ", now " << ceph_mds_state_name(state) << dendl; // stop timers if (beacon_sender) { timer.cancel_event(beacon_sender); beacon_sender = 0; } if (tick_event) { timer.cancel_event(tick_event); tick_event = 0; } timer.cancel_all_events(); //timer.join(); timer.shutdown(); // shut down cache mdcache->shutdown(); if (objecter->initialized) objecter->shutdown_locked(); monc->shutdown(); // shut down messenger messenger->shutdown(); } void MDS::respawn() { dout(1) << "respawn" << dendl; char *new_argv[orig_argc+1]; dout(1) << " e: '" << orig_argv[0] << "'" << dendl; for (int i=0; iput(); ret = true; } else { inc_dispatch_depth(); ret = _dispatch(m); dec_dispatch_depth(); } mds_lock.Unlock(); return ret; } bool MDS::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) { dout(10) << "MDS::ms_get_authorizer type=" << ceph_entity_type_name(dest_type) << dendl; /* monitor authorization is being handled on different layer */ if (dest_type == CEPH_ENTITY_TYPE_MON) return true; if (force_new) { if (monc->wait_auth_rotating(10) < 0) return false; } *authorizer = monc->auth->build_authorizer(dest_type); return *authorizer != NULL; } #define ALLOW_MESSAGES_FROM(peers) \ do { \ if (m->get_connection() && (m->get_connection()->get_peer_type() & (peers)) == 0) { \ dout(0) << __FILE__ << "." << __LINE__ << ": filtered out request, peer=" << m->get_connection()->get_peer_type() \ << " allowing=" << #peers << " message=" << *m << dendl; \ m->put(); \ return true; \ } \ } while (0) /* * high priority messages we always process */ bool MDS::handle_core_message(Message *m) { switch (m->get_type()) { case CEPH_MSG_MON_MAP: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON); m->put(); break; // MDS case CEPH_MSG_MDS_MAP: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_MDS); handle_mds_map(static_cast(m)); break; case MSG_MDS_BEACON: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON); handle_mds_beacon(static_cast(m)); break; // misc case MSG_MON_COMMAND: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON); handle_command(static_cast(m)); break; // OSD case CEPH_MSG_OSD_OPREPLY: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_OSD); objecter->handle_osd_op_reply((class MOSDOpReply*)m); break; case CEPH_MSG_OSD_MAP: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD); objecter->handle_osd_map((MOSDMap*)m); if (is_active() && snapserver) snapserver->check_osd_map(true); break; default: return false; } return true; } /* * lower priority messages we defer if we seem laggy */ bool MDS::handle_deferrable_message(Message *m) { int port = m->get_type() & 0xff00; switch (port) { case MDS_PORT_CACHE: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS); mdcache->dispatch(m); break; case MDS_PORT_MIGRATOR: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS); mdcache->migrator->dispatch(m); break; default: switch (m->get_type()) { // SERVER case CEPH_MSG_CLIENT_SESSION: case CEPH_MSG_CLIENT_RECONNECT: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_CLIENT); // fall-thru case CEPH_MSG_CLIENT_REQUEST: server->dispatch(m); break; case MSG_MDS_SLAVE_REQUEST: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS); server->dispatch(m); break; case MSG_MDS_HEARTBEAT: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS); balancer->proc_message(m); break; case MSG_MDS_TABLE_REQUEST: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS); { MMDSTableRequest *req = static_cast(m); if (req->op < 0) { MDSTableClient *client = get_table_client(req->table); client->handle_request(req); } else { MDSTableServer *server = get_table_server(req->table); server->handle_request(req); } } break; case MSG_MDS_LOCK: case MSG_MDS_INODEFILECAPS: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MDS); locker->dispatch(m); break; case CEPH_MSG_CLIENT_CAPS: case CEPH_MSG_CLIENT_CAPRELEASE: case CEPH_MSG_CLIENT_LEASE: ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_CLIENT); locker->dispatch(m); break; default: return false; } } return true; } bool MDS::is_stale_message(Message *m) { // from bad mds? if (m->get_source().is_mds()) { int from = m->get_source().num(); if (!mdsmap->have_inst(from) || mdsmap->get_inst(from) != m->get_source_inst() || mdsmap->is_down(from)) { // bogus mds? if (m->get_type() == CEPH_MSG_MDS_MAP) { dout(5) << "got " << *m << " from old/bad/imposter mds " << m->get_source() << ", but it's an mdsmap, looking at it" << dendl; } else if (m->get_type() == MSG_MDS_CACHEEXPIRE && mdsmap->get_inst(from) == m->get_source_inst()) { dout(5) << "got " << *m << " from down mds " << m->get_source() << ", but it's a cache_expire, looking at it" << dendl; } else { dout(5) << "got " << *m << " from down/old/bad/imposter mds " << m->get_source() << ", dropping" << dendl; return true; } } } return false; } /* If this function returns true, it has put the message. If it returns false, * it has not put the message. */ bool MDS::_dispatch(Message *m) { if (is_stale_message(m)) { m->put(); return true; } // core if (!handle_core_message(m)) { if (is_laggy()) { dout(10) << " laggy, deferring " << *m << dendl; waiting_for_nolaggy.push_back(m); } else { if (!handle_deferrable_message(m)) { dout(0) << "unrecognized message " << *m << dendl; m->put(); return false; } } } if (dispatch_depth > 1) return true; // finish any triggered contexts while (!finished_queue.empty()) { dout(7) << "mds has " << finished_queue.size() << " queued contexts" << dendl; dout(10) << finished_queue << dendl; list ls; ls.swap(finished_queue); while (!ls.empty()) { dout(10) << " finish " << ls.front() << dendl; ls.front()->complete(0); ls.pop_front(); // give other threads (beacon!) a chance mds_lock.Unlock(); mds_lock.Lock(); } } while (!waiting_for_nolaggy.empty()) { // stop if we're laggy now! if (is_laggy()) return true; Message *old = waiting_for_nolaggy.front(); waiting_for_nolaggy.pop_front(); if (is_stale_message(old)) { old->put(); } else { dout(7) << " processing laggy deferred " << *old << dendl; handle_deferrable_message(old); } // give other threads (beacon!) a chance mds_lock.Unlock(); mds_lock.Lock(); } // done with all client replayed requests? if (is_clientreplay() && mdcache->is_open() && replay_queue.empty() && want_state == MDSMap::STATE_CLIENTREPLAY) { int num_requests = mdcache->get_num_client_requests(); dout(10) << " still have " << num_requests << " active replay requests" << dendl; if (num_requests == 0) clientreplay_done(); } // hack: thrash exports static utime_t start; utime_t now = ceph_clock_now(g_ceph_context); if (start == utime_t()) start = now; /*double el = now - start; if (el > 30.0 && el < 60.0)*/ for (int i=0; imds_thrash_exports; i++) { set s; if (!is_active()) break; mdsmap->get_mds_set(s, MDSMap::STATE_ACTIVE); if (s.size() < 2 || mdcache->get_num_inodes() < 10) break; // need peers for this to work. dout(7) << "mds thrashing exports pass " << (i+1) << "/" << g_conf->mds_thrash_exports << dendl; // pick a random dir inode CInode *in = mdcache->hack_pick_random_inode(); list ls; in->get_dirfrags(ls); if (ls.empty()) continue; // must be an open dir. list::iterator p = ls.begin(); int n = rand() % ls.size(); while (n--) ++p; CDir *dir = *p; if (!dir->get_parent_dir()) continue; // must be linked. if (!dir->is_auth()) continue; // must be auth. int dest; do { int k = rand() % s.size(); set::iterator p = s.begin(); while (k--) ++p; dest = *p; } while (dest == whoami); mdcache->migrator->export_dir_nicely(dir,dest); } // hack: thrash fragments for (int i=0; imds_thrash_fragments; i++) { if (!is_active()) break; if (mdcache->get_num_fragmenting_dirs() > 5) break; dout(7) << "mds thrashing fragments pass " << (i+1) << "/" << g_conf->mds_thrash_fragments << dendl; // pick a random dir inode CInode *in = mdcache->hack_pick_random_inode(); list ls; in->get_dirfrags(ls); if (ls.empty()) continue; // must be an open dir. CDir *dir = ls.front(); if (!dir->get_parent_dir()) continue; // must be linked. if (!dir->is_auth()) continue; // must be auth. frag_t fg = dir->get_frag(); if (fg == frag_t() || (rand() % (1 << fg.bits()) == 0)) mdcache->split_dir(dir, 1); else balancer->queue_merge(dir); } // hack: force hash root? /* if (false && mdcache->get_root() && mdcache->get_root()->dir && !(mdcache->get_root()->dir->is_hashed() || mdcache->get_root()->dir->is_hashing())) { dout(0) << "hashing root" << dendl; mdcache->migrator->hash_dir(mdcache->get_root()->dir); } */ if (mlogger) { mlogger->set(l_mdm_ino, g_num_ino); mlogger->set(l_mdm_dir, g_num_dir); mlogger->set(l_mdm_dn, g_num_dn); mlogger->set(l_mdm_cap, g_num_cap); mlogger->inc(l_mdm_inoa, g_num_inoa); g_num_inoa = 0; mlogger->inc(l_mdm_inos, g_num_inos); g_num_inos = 0; mlogger->inc(l_mdm_dira, g_num_dira); g_num_dira = 0; mlogger->inc(l_mdm_dirs, g_num_dirs); g_num_dirs = 0; mlogger->inc(l_mdm_dna, g_num_dna); g_num_dna = 0; mlogger->inc(l_mdm_dns, g_num_dns); g_num_dns = 0; mlogger->inc(l_mdm_capa, g_num_capa); g_num_capa = 0; mlogger->inc(l_mdm_caps, g_num_caps); g_num_caps = 0; mlogger->set(l_mdm_buf, buffer::get_total_alloc()); } // shut down? if (is_stopping()) { mdlog->trim(); if (mdcache->shutdown_pass()) { dout(7) << "shutdown_pass=true, finished w/ shutdown, moving to down:stopped" << dendl; stopping_done(); } else { dout(7) << "shutdown_pass=false" << dendl; } } return true; } void MDS::ms_handle_connect(Connection *con) { Mutex::Locker l(mds_lock); dout(5) << "ms_handle_connect on " << con->get_peer_addr() << dendl; if (want_state == CEPH_MDS_STATE_DNE) return; objecter->ms_handle_connect(con); } bool MDS::ms_handle_reset(Connection *con) { Mutex::Locker l(mds_lock); dout(5) << "ms_handle_reset on " << con->get_peer_addr() << dendl; if (want_state == CEPH_MDS_STATE_DNE) return false; if (con->get_peer_type() == CEPH_ENTITY_TYPE_OSD) { objecter->ms_handle_reset(con); } else if (con->get_peer_type() == CEPH_ENTITY_TYPE_CLIENT) { Session *session = static_cast(con->get_priv()); if (session) { if (session->is_closed()) { dout(3) << "ms_handle_reset closing connection for session " << session->info.inst << dendl; messenger->mark_down(con); con->set_priv(NULL); sessionmap.remove_session(session); } session->put(); } else { messenger->mark_down(con); } } return false; } void MDS::ms_handle_remote_reset(Connection *con) { Mutex::Locker l(mds_lock); dout(5) << "ms_handle_remote_reset on " << con->get_peer_addr() << dendl; if (want_state == CEPH_MDS_STATE_DNE) return; switch (con->get_peer_type()) { case CEPH_ENTITY_TYPE_OSD: objecter->ms_handle_remote_reset(con); break; case CEPH_ENTITY_TYPE_CLIENT: Session *session = static_cast(con->get_priv()); if (session) { if (session->is_closed()) { dout(3) << "ms_handle_remote_reset closing connection for session " << session->info.inst << dendl; messenger->mark_down(con); con->set_priv(NULL); sessionmap.remove_session(session); } session->put(); } break; } } bool MDS::ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply, bool& is_valid, CryptoKey& session_key) { Mutex::Locker l(mds_lock); if (want_state == CEPH_MDS_STATE_DNE) return false; AuthAuthorizeHandler *authorize_handler = 0; switch (peer_type) { case CEPH_ENTITY_TYPE_MDS: authorize_handler = authorize_handler_cluster_registry->get_handler(protocol); break; default: authorize_handler = authorize_handler_service_registry->get_handler(protocol); } if (!authorize_handler) { dout(0) << "No AuthAuthorizeHandler found for protocol " << protocol << dendl; is_valid = false; return true; } AuthCapsInfo caps_info; EntityName name; uint64_t global_id; is_valid = authorize_handler->verify_authorizer(cct, monc->rotating_secrets, authorizer_data, authorizer_reply, name, global_id, caps_info, session_key); if (is_valid) { // wire up a Session* to this connection, and add it to the session map entity_name_t n(con->get_peer_type(), global_id); Session *s = sessionmap.get_session(n); if (!s) { s = new Session; s->info.inst.addr = con->get_peer_addr(); s->info.inst.name = n; dout(10) << " new session " << s << " for " << s->info.inst << " con " << con << dendl; con->set_priv(s); s->connection = con; sessionmap.add_session(s); } else { dout(10) << " existing session " << s << " for " << s->info.inst << " existing con " << s->connection << ", new/authorizing con " << con << dendl; con->set_priv(s->get()); // Wait until we fully accept the connection before setting // s->connection. In particular, if there are multiple incoming // connection attempts, they will all get their authorizer // validated, but some of them may "lose the race" and get // dropped. We only want to consider the winner(s). See // ms_handle_accept(). This is important for Sessions we replay // from the journal on recovery that don't have established // messenger state; we want the con from only the winning // connect attempt(s). (Normal reconnects that don't follow MDS // recovery are reconnected to the existing con by the // messenger.) } /* s->caps.set_allow_all(caps_info.allow_all); if (caps_info.caps.length() > 0) { bufferlist::iterator iter = caps_info.caps.begin(); s->caps.parse(iter); dout(10) << " session " << s << " has caps " << s->caps << dendl; } */ } return true; // we made a decision (see is_valid) }; void MDS::ms_handle_accept(Connection *con) { Mutex::Locker l(mds_lock); Session *s = static_cast(con->get_priv()); dout(10) << "ms_handle_accept " << con->get_peer_addr() << " con " << con << " session " << s << dendl; if (s) { if (s->connection != con) { dout(10) << " session connection " << s->connection << " -> " << con << dendl; s->connection = con; // send out any queued messages while (!s->preopen_out_queue.empty()) { messenger->send_message(s->preopen_out_queue.front(), con); s->preopen_out_queue.pop_front(); } } s->put(); } } ceph-0.80.11/src/mds/AnchorClient.cc0000664000175100017510000000621412623076744021132 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "AnchorClient.h" #include "MDSMap.h" #include "LogSegment.h" #include "MDS.h" #include "msg/Messenger.h" #include "messages/MMDSTableRequest.h" #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".anchorclient " // LOOKUPS /* This function DOES NOT put the passed message before returning */ void AnchorClient::handle_query_result(class MMDSTableRequest *m) { dout(10) << "handle_anchor_reply " << *m << dendl; inodeno_t ino; vector trace; bufferlist::iterator p = m->bl.begin(); ::decode(ino, p); ::decode(trace, p); if (!pending_lookup.count(ino)) return; list<_pending_lookup> ls; ls.swap(pending_lookup[ino]); pending_lookup.erase(ino); for (list<_pending_lookup>::iterator q = ls.begin(); q != ls.end(); ++q) { *q->trace = trace; if (q->onfinish) { q->onfinish->complete(0); } } } void AnchorClient::resend_queries() { // resend any pending lookups. for (map >::iterator p = pending_lookup.begin(); p != pending_lookup.end(); ++p) { dout(10) << "resending lookup on " << p->first << dendl; _lookup(p->first); } } void AnchorClient::lookup(inodeno_t ino, vector& trace, Context *onfinish) { _pending_lookup l; l.onfinish = onfinish; l.trace = &trace; bool isnew = (pending_lookup.count(ino) == 0); pending_lookup[ino].push_back(l); if (isnew) _lookup(ino); } void AnchorClient::_lookup(inodeno_t ino) { int ts = mds->mdsmap->get_tableserver(); if (mds->mdsmap->get_state(ts) < MDSMap::STATE_REJOIN) return; MMDSTableRequest *req = new MMDSTableRequest(table, TABLESERVER_OP_QUERY, 0, 0); ::encode(ino, req->bl); mds->send_message_mds(req, ts); } // FRIENDLY PREPARE void AnchorClient::prepare_create(inodeno_t ino, vector& trace, version_t *patid, Context *onfinish) { dout(10) << "prepare_create " << ino << " " << trace << dendl; bufferlist bl; __u32 op = TABLE_OP_CREATE; ::encode(op, bl); ::encode(ino, bl); ::encode(trace, bl); _prepare(bl, patid, 0, onfinish); } void AnchorClient::prepare_destroy(inodeno_t ino, version_t *patid, Context *onfinish) { dout(10) << "prepare_destroy " << ino << dendl; bufferlist bl; __u32 op = TABLE_OP_DESTROY; ::encode(op, bl); ::encode(ino, bl); _prepare(bl, patid, 0, onfinish); } void AnchorClient::prepare_update(inodeno_t ino, vector& trace, version_t *patid, Context *onfinish) { dout(10) << "prepare_update " << ino << " " << trace << dendl; bufferlist bl; __u32 op = TABLE_OP_UPDATE; ::encode(op, bl); ::encode(ino, bl); ::encode(trace, bl); _prepare(bl, patid, 0, onfinish); } ceph-0.80.11/src/mds/Capability.h0000664000175100017510000002305012623076744020501 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CAPABILITY_H #define CEPH_CAPABILITY_H #include "include/buffer.h" #include "include/xlist.h" #include "common/config.h" #include "mdstypes.h" /* Capability protocol notes. - two types of cap events from mds -> client: - cap "issue" in a MClientReply, or an MClientCaps IMPORT op. - cap "update" (revocation or grant) .. an MClientCaps message. - if client has cap, the mds should have it too. - if client has no dirty data, it can release it without waiting for an mds ack. - client may thus get a cap _update_ and not have the cap. ignore it. - mds should track seq of last issue. any release attempt will only succeed if the client has seen the latest. - a UPDATE updates the clients issued caps, wanted, etc. it may also flush dirty metadata. - 'caps' are which caps the client retains. - if 0, client wishes to release the cap - 'wanted' is which caps the client wants. - 'dirty' is which metadata is to be written. - client gets a FLUSH_ACK with matching dirty flags indicating which caps were written. - a FLUSH_ACK acks a FLUSH. - 'dirty' is the _original_ FLUSH's dirty (i.e., which metadata was written back) - 'seq' is the _original_ FLUSH's seq. - 'caps' is the _original_ FLUSH's caps (not actually important) - client can conclude that (dirty & ~caps) bits were successfully cleaned. - a FLUSHSNAP flushes snapshot metadata. - 'dirty' indicates which caps, were dirty, if any. - mds writes metadata. if dirty!=0, replies with FLUSHSNAP_ACK. */ class CInode; namespace ceph { class Formatter; } class Capability { private: static boost::pool<> pool; public: static void *operator new(size_t num_bytes) { void *n = pool.malloc(); if (!n) throw std::bad_alloc(); return n; } void operator delete(void *p) { pool.free(p); } public: struct Export { int64_t cap_id; int32_t wanted; int32_t issued; int32_t pending; snapid_t client_follows; ceph_seq_t seq; ceph_seq_t mseq; utime_t last_issue_stamp; Export() {} Export(int64_t id, int w, int i, int p, snapid_t cf, ceph_seq_t s, ceph_seq_t m, utime_t lis) : cap_id(id), wanted(w), issued(i), pending(p), client_follows(cf), seq(s), mseq(m), last_issue_stamp(lis) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &p); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; struct Import { int64_t cap_id; ceph_seq_t issue_seq; ceph_seq_t mseq; Import() {} Import(int64_t i, ceph_seq_t s, ceph_seq_t m) : cap_id(i), issue_seq(s), mseq(m) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &p); void dump(Formatter *f) const; }; private: CInode *inode; client_t client; uint64_t cap_id; __u32 _wanted; // what the client wants (ideally) utime_t last_issue_stamp; // track in-flight caps -------------- // - add new caps to _pending // - track revocations in _revokes list public: struct revoke_info { __u32 before; ceph_seq_t seq, last_issue; revoke_info() {} revoke_info(__u32 b, ceph_seq_t s, ceph_seq_t li) : before(b), seq(s), last_issue(li) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; private: __u32 _pending, _issued; list _revokes; public: int pending() { return _pending; } int issued() { return _issued; } bool is_null() { return !_pending && _revokes.empty(); } ceph_seq_t issue(unsigned c) { if (_pending & ~c) { // revoking (and maybe adding) bits. note caps prior to this revocation _revokes.push_back(revoke_info(_pending, last_sent, last_issue)); _pending = c; _issued |= c; } else if (~_pending & c) { // adding bits only. remove obsolete revocations? _pending |= c; _issued |= c; // drop old _revokes with no bits we don't have while (!_revokes.empty() && (_revokes.back().before & ~_pending) == 0) _revokes.pop_back(); } else { // no change. assert(_pending == c); } //last_issue = ++last_sent; return last_sent; } ceph_seq_t issue_norevoke(unsigned c) { _pending |= c; _issued |= c; //check_rdcaps_list(); ++last_sent; return last_sent; } void _calc_issued() { _issued = _pending; for (list::iterator p = _revokes.begin(); p != _revokes.end(); ++p) _issued |= p->before; } void confirm_receipt(ceph_seq_t seq, unsigned caps) { if (seq == last_sent) { _revokes.clear(); _issued = caps; // don't add bits _pending &= caps; } else { // can i forget any revocations? while (!_revokes.empty() && _revokes.front().seq < seq) _revokes.pop_front(); if (!_revokes.empty()) { if (_revokes.front().seq == seq) _revokes.begin()->before = caps; _calc_issued(); } else { // seq < last_sent _issued = caps | _pending; } } //check_rdcaps_list(); } // we may get a release racing with revocations, which means our revokes will be ignored // by the client. clean them out of our _revokes history so we don't wait on them. void clean_revoke_from(ceph_seq_t li) { bool changed = false; while (!_revokes.empty() && _revokes.front().last_issue <= li) { _revokes.pop_front(); changed = true; } if (changed) _calc_issued(); } private: ceph_seq_t last_sent; ceph_seq_t last_issue; ceph_seq_t mseq; int suppress; unsigned state; const static unsigned STATE_STALE = (1<<0); const static unsigned STATE_NEW = (1<<1); public: snapid_t client_follows; version_t client_xattr_version; version_t client_inline_version; xlist::item item_session_caps; xlist::item item_snaprealm_caps; Capability(CInode *i = NULL, uint64_t id = 0, client_t c = 0) : inode(i), client(c), cap_id(id), _wanted(0), _pending(0), _issued(0), last_sent(0), last_issue(0), mseq(0), suppress(0), state(0), client_follows(0), client_xattr_version(0), client_inline_version(0), item_session_caps(this), item_snaprealm_caps(this) { g_num_cap++; g_num_capa++; } ~Capability() { g_num_cap--; g_num_caps++; } Capability(const Capability& other); // no copying const Capability& operator=(const Capability& other); // no copying ceph_seq_t get_mseq() { return mseq; } void inc_mseq() { mseq++; } ceph_seq_t get_last_sent() { return last_sent; } utime_t get_last_issue_stamp() { return last_issue_stamp; } void set_last_issue() { last_issue = last_sent; } void set_last_issue_stamp(utime_t t) { last_issue_stamp = t; } void set_cap_id(uint64_t i) { cap_id = i; } uint64_t get_cap_id() { return cap_id; } //ceph_seq_t get_last_issue() { return last_issue; } bool is_suppress() { return suppress > 0; } void inc_suppress() { suppress++; } void dec_suppress() { suppress--; } bool is_stale() { return state & STATE_STALE; } void mark_stale() { state |= STATE_STALE; } void clear_stale() { state &= ~STATE_STALE; } bool is_new() { return state & STATE_NEW; } void mark_new() { state |= STATE_NEW; } void clear_new() { state &= ~STATE_NEW; } CInode *get_inode() { return inode; } client_t get_client() { return client; } // caps this client wants to hold int wanted() { return _wanted; } void set_wanted(int w) { _wanted = w; //check_rdcaps_list(); } void inc_last_seq() { last_sent++; }; ceph_seq_t get_last_seq() { return last_sent; } ceph_seq_t get_last_issue() { return last_issue; } void reset_seq() { last_sent = 0; last_issue = 0; } // -- exports -- Export make_export() { return Export(cap_id, _wanted, issued(), pending(), client_follows, last_sent, mseq+1, last_issue_stamp); } void merge(Export& other, bool auth_cap) { if (!is_stale()) { // issued + pending int newpending = other.pending | pending(); if (other.issued & ~newpending) issue(other.issued | newpending); else issue(newpending); last_issue_stamp = other.last_issue_stamp; } else { issue(CEPH_CAP_PIN); } client_follows = other.client_follows; // wanted _wanted = _wanted | other.wanted; if (auth_cap) mseq = other.mseq; } void merge(int otherwanted, int otherissued) { if (!is_stale()) { // issued + pending int newpending = pending(); if (otherissued & ~newpending) issue(otherissued | newpending); else issue(newpending); } else { issue(CEPH_CAP_PIN); } // wanted _wanted = _wanted | otherwanted; } void revoke() { if (pending() & ~CEPH_CAP_PIN) issue(CEPH_CAP_PIN); confirm_receipt(last_sent, CEPH_CAP_PIN); } // serializers void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(Capability::Export) WRITE_CLASS_ENCODER(Capability::Import) WRITE_CLASS_ENCODER(Capability::revoke_info) WRITE_CLASS_ENCODER(Capability) #endif ceph-0.80.11/src/mds/CDir.h0000664000175100017510000004417412623076744017253 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CDIR_H #define CEPH_CDIR_H #include "include/types.h" #include "include/buffer.h" #include "mdstypes.h" #include "common/config.h" #include "common/DecayCounter.h" #include #include #include #include #include using namespace std; #include "CInode.h" class CDentry; class MDCache; class MDCluster; class Context; class bloom_filter; struct ObjectOperation; ostream& operator<<(ostream& out, class CDir& dir); class CDir : public MDSCacheObject { /* * This class uses a boost::pool to handle allocation. This is *not* * thread-safe, so don't do allocations from multiple threads! * * Alternatively, switch the pool to use a boost::singleton_pool. */ private: static boost::pool<> pool; public: static void *operator new(size_t num_bytes) { void *n = pool.malloc(); if (!n) throw std::bad_alloc(); return n; } void operator delete(void *p) { pool.free(p); } public: // -- pins -- static const int PIN_DNWAITER = 1; static const int PIN_INOWAITER = 2; static const int PIN_CHILD = 3; static const int PIN_FROZEN = 4; static const int PIN_SUBTREE = 5; static const int PIN_IMPORTING = 7; static const int PIN_IMPORTBOUND = 9; static const int PIN_EXPORTBOUND = 10; static const int PIN_STICKY = 11; static const int PIN_SUBTREETEMP = 12; // used by MDCache::trim_non_auth() const char *pin_name(int p) { switch (p) { case PIN_DNWAITER: return "dnwaiter"; case PIN_INOWAITER: return "inowaiter"; case PIN_CHILD: return "child"; case PIN_FROZEN: return "frozen"; case PIN_SUBTREE: return "subtree"; case PIN_IMPORTING: return "importing"; case PIN_IMPORTBOUND: return "importbound"; case PIN_EXPORTBOUND: return "exportbound"; case PIN_STICKY: return "sticky"; case PIN_SUBTREETEMP: return "subtreetemp"; default: return generic_pin_name(p); } } // -- state -- static const unsigned STATE_COMPLETE = (1<< 1); // the complete contents are in cache static const unsigned STATE_FROZENTREE = (1<< 2); // root of tree (bounded by exports) static const unsigned STATE_FREEZINGTREE = (1<< 3); // in process of freezing static const unsigned STATE_FROZENDIR = (1<< 4); static const unsigned STATE_FREEZINGDIR = (1<< 5); static const unsigned STATE_COMMITTING = (1<< 6); // mid-commit static const unsigned STATE_FETCHING = (1<< 7); // currenting fetching static const unsigned STATE_IMPORTBOUND = (1<<10); static const unsigned STATE_EXPORTBOUND = (1<<11); static const unsigned STATE_EXPORTING = (1<<12); static const unsigned STATE_IMPORTING = (1<<13); static const unsigned STATE_FRAGMENTING = (1<<14); static const unsigned STATE_STICKY = (1<<15); // sticky pin due to inode stickydirs static const unsigned STATE_DNPINNEDFRAG = (1<<16); // dir is refragmenting static const unsigned STATE_ASSIMRSTAT = (1<<17); // assimilating inode->frag rstats static const unsigned STATE_DIRTYDFT = (1<<18); // dirty dirfragtree // common states static const unsigned STATE_CLEAN = 0; static const unsigned STATE_INITIAL = 0; // these state bits are preserved by an import/export // ...except if the directory is hashed, in which case none of them are! static const unsigned MASK_STATE_EXPORTED = (STATE_COMPLETE|STATE_DIRTY|STATE_DIRTYDFT); static const unsigned MASK_STATE_IMPORT_KEPT = ( STATE_IMPORTING |STATE_IMPORTBOUND|STATE_EXPORTBOUND |STATE_FROZENTREE |STATE_STICKY); static const unsigned MASK_STATE_EXPORT_KEPT = (STATE_EXPORTING |STATE_IMPORTBOUND|STATE_EXPORTBOUND |STATE_FROZENTREE |STATE_FROZENDIR |STATE_STICKY); static const unsigned MASK_STATE_FRAGMENT_KEPT = (STATE_DIRTY| STATE_EXPORTBOUND | STATE_IMPORTBOUND | STATE_REJOINUNDEF); // -- rep spec -- static const int REP_NONE = 0; static const int REP_ALL = 1; static const int REP_LIST = 2; static const unsigned EXPORT_NONCE = 1; // -- wait masks -- static const uint64_t WAIT_DENTRY = (1<<0); // wait for item to be in cache static const uint64_t WAIT_COMPLETE = (1<<1); // wait for complete dir contents static const uint64_t WAIT_FROZEN = (1<<2); // auth pins removed static const int WAIT_DNLOCK_OFFSET = 4; static const uint64_t WAIT_ANY_MASK = (uint64_t)(-1); static const uint64_t WAIT_ATFREEZEROOT = (WAIT_UNFREEZE); static const uint64_t WAIT_ATSUBTREEROOT = (WAIT_SINGLEAUTH); public: // context MDCache *cache; CInode *inode; // my inode frag_t frag; // my frag bool is_lt(const MDSCacheObject *r) const { return dirfrag() < (static_cast(r))->dirfrag(); } fnode_t fnode; snapid_t first; map dirty_old_rstat; // [value.first,key] // my inodes with dirty rstat data elist dirty_rstat_inodes; void resync_accounted_fragstat(); void resync_accounted_rstat(); void assimilate_dirty_rstat_inodes(); void assimilate_dirty_rstat_inodes_finish(MutationRef& mut, EMetaBlob *blob); protected: version_t projected_version; list projected_fnode; public: elist::item item_dirty, item_new; public: version_t get_version() { return fnode.version; } void set_version(version_t v) { assert(projected_fnode.empty()); projected_version = fnode.version = v; } version_t get_projected_version() { return projected_version; } fnode_t *get_projected_fnode() { if (projected_fnode.empty()) return &fnode; else return projected_fnode.back(); } fnode_t *project_fnode(); void pop_and_dirty_projected_fnode(LogSegment *ls); bool is_projected() { return !projected_fnode.empty(); } version_t pre_dirty(version_t min=0); void _mark_dirty(LogSegment *ls); void _set_dirty_flag() { if (!state_test(STATE_DIRTY)) { state_set(STATE_DIRTY); get(PIN_DIRTY); } } void mark_dirty(version_t pv, LogSegment *ls); void log_mark_dirty(); void mark_clean(); bool is_new() { return item_new.is_on_list(); } void mark_new(LogSegment *ls); public: typedef map map_t; protected: // contents of this directory map_t items; // non-null AND null unsigned num_head_items; unsigned num_head_null; unsigned num_snap_items; unsigned num_snap_null; int num_dirty; // state version_t committing_version; version_t committed_version; // lock nesting, freeze int auth_pins; #ifdef MDS_AUTHPIN_SET multiset auth_pin_set; #endif int nested_auth_pins, dir_auth_pins; int request_pins; int nested_anchors; // cache control (defined for authority; hints for replicas) __s32 dir_rep; set<__s32> dir_rep_by; // if dir_rep == REP_LIST // popularity dirfrag_load_vec_t pop_me; dirfrag_load_vec_t pop_nested; dirfrag_load_vec_t pop_auth_subtree; dirfrag_load_vec_t pop_auth_subtree_nested; utime_t last_popularity_sample; load_spread_t pop_spread; // and to provide density int num_dentries_nested; int num_dentries_auth_subtree; int num_dentries_auth_subtree_nested; // friends friend class Migrator; friend class CInode; friend class MDCache; friend class MDiscover; friend class MDBalancer; friend class CDirDiscover; friend class CDirExport; friend class C_Dir_TMAP_Fetched; friend class C_Dir_OMAP_Fetched; friend class C_Dir_Committed; bloom_filter *bloom; /* If you set up the bloom filter, you must keep it accurate! * It's deleted when you mark_complete() and is deliberately not serialized.*/ public: CDir(CInode *in, frag_t fg, MDCache *mdcache, bool auth); ~CDir() { remove_bloom(); g_num_dir--; g_num_dirs++; } // -- accessors -- inodeno_t ino() const { return inode->ino(); } // deprecate me? frag_t get_frag() const { return frag; } dirfrag_t dirfrag() const { return dirfrag_t(inode->ino(), frag); } CInode *get_inode() { return inode; } CDir *get_parent_dir() { return inode->get_parent_dir(); } map_t::iterator begin() { return items.begin(); } map_t::iterator end() { return items.end(); } unsigned get_num_head_items() { return num_head_items; } unsigned get_num_head_null() { return num_head_null; } unsigned get_num_snap_items() { return num_snap_items; } unsigned get_num_snap_null() { return num_snap_null; } unsigned get_num_any() { return num_head_items + num_head_null + num_snap_items + num_snap_null; } bool check_rstats(); void inc_num_dirty() { num_dirty++; } void dec_num_dirty() { assert(num_dirty > 0); num_dirty--; } int get_num_dirty() { return num_dirty; } int64_t get_frag_size() { return get_projected_fnode()->fragstat.size(); } // -- dentries and inodes -- public: CDentry* lookup_exact_snap(const string& dname, snapid_t last) { map_t::iterator p = items.find(dentry_key_t(last, dname.c_str())); if (p == items.end()) return NULL; return p->second; } CDentry* lookup(const string& n, snapid_t snap=CEPH_NOSNAP) { return lookup(n.c_str(), snap); } CDentry* lookup(const char *n, snapid_t snap=CEPH_NOSNAP); CDentry* add_null_dentry(const string& dname, snapid_t first=2, snapid_t last=CEPH_NOSNAP); CDentry* add_primary_dentry(const string& dname, CInode *in, snapid_t first=2, snapid_t last=CEPH_NOSNAP); CDentry* add_remote_dentry(const string& dname, inodeno_t ino, unsigned char d_type, snapid_t first=2, snapid_t last=CEPH_NOSNAP); void remove_dentry( CDentry *dn ); // delete dentry void link_remote_inode( CDentry *dn, inodeno_t ino, unsigned char d_type); void link_remote_inode( CDentry *dn, CInode *in ); void link_primary_inode( CDentry *dn, CInode *in ); void unlink_inode( CDentry *dn ); void try_remove_unlinked_dn(CDentry *dn); void add_to_bloom(CDentry *dn); bool is_in_bloom(const string& name); bool has_bloom() { return (bloom ? true : false); } void remove_bloom(); private: void link_inode_work( CDentry *dn, CInode *in ); void unlink_inode_work( CDentry *dn ); void remove_null_dentries(); void purge_stale_snap_data(const set& snaps); public: void touch_dentries_bottom(); bool try_trim_snap_dentry(CDentry *dn, const set& snaps); public: void split(int bits, list& subs, list& waiters, bool replay); void merge(list& subs, list& waiters, bool replay); bool should_split() { return (int)get_frag_size() > g_conf->mds_bal_split_size; } bool should_merge() { return (int)get_frag_size() < g_conf->mds_bal_merge_size; } private: void prepare_new_fragment(bool replay); void prepare_old_fragment(bool replay); void steal_dentry(CDentry *dn); // from another dir. used by merge/split. void finish_old_fragment(list& waiters, bool replay); void init_fragment_pins(); // -- authority -- /* * normal: !subtree_root * delegation: subtree_root * ambiguous: subtree_root * subtree_root */ pair dir_auth; public: pair authority(); pair get_dir_auth() { return dir_auth; } void set_dir_auth(pair a); void set_dir_auth(int a) { set_dir_auth(pair(a, CDIR_AUTH_UNKNOWN)); } bool is_ambiguous_dir_auth() { return dir_auth.second != CDIR_AUTH_UNKNOWN; } bool is_full_dir_auth() { return is_auth() && !is_ambiguous_dir_auth(); } bool is_full_dir_nonauth() { return !is_auth() && !is_ambiguous_dir_auth(); } bool is_subtree_root() { return dir_auth != CDIR_AUTH_DEFAULT; } bool contains(CDir *x); // true if we are x or an ancestor of x // for giving to clients void get_dist_spec(set& ls, int auth) { if (is_rep()) { for (map::iterator p = replicas_begin(); p != replicas_end(); ++p) ls.insert(p->first); if (!ls.empty()) ls.insert(auth); } } void encode_dirstat(bufferlist& bl, int whoami) { /* * note: encoding matches struct ceph_client_reply_dirfrag */ frag_t frag = get_frag(); __s32 auth; set<__s32> dist; auth = dir_auth.first; if (is_auth()) get_dist_spec(dist, whoami); ::encode(frag, bl); ::encode(auth, bl); ::encode(dist, bl); } void _encode_base(bufferlist& bl) { ::encode(first, bl); ::encode(fnode, bl); ::encode(dir_rep, bl); ::encode(dir_rep_by, bl); } void _decode_base(bufferlist::iterator& p) { ::decode(first, p); ::decode(fnode, p); ::decode(dir_rep, p); ::decode(dir_rep_by, p); } void encode_replica(int who, bufferlist& bl) { __u32 nonce = add_replica(who); ::encode(nonce, bl); _encode_base(bl); } void decode_replica(bufferlist::iterator& p) { __u32 nonce; ::decode(nonce, p); replica_nonce = nonce; _decode_base(p); } // -- state -- bool is_complete() { return state & STATE_COMPLETE; } bool is_exporting() { return state & STATE_EXPORTING; } bool is_importing() { return state & STATE_IMPORTING; } bool is_dirty_dft() { return state & STATE_DIRTYDFT; } int get_dir_rep() { return dir_rep; } bool is_rep() { if (dir_rep == REP_NONE) return false; return true; } // -- fetch -- object_t get_ondisk_object() { return file_object_t(ino(), frag); } void fetch(Context *c, bool ignore_authpinnability=false); void fetch(Context *c, const string& want_dn, bool ignore_authpinnability=false); protected: void _omap_fetch(const string& want_dn); void _omap_fetched(bufferlist& hdrbl, map& omap, const string& want_dn, int r); void _tmap_fetch(const string& want_dn); void _tmap_fetched(bufferlist &bl, const string& want_dn, int r); // -- commit -- map > waiting_for_commit; void _commit(version_t want, int op_prio); void _omap_commit(int op_prio); void _encode_dentry(CDentry *dn, bufferlist& bl, const set *snaps); void _committed(version_t v); public: void wait_for_commit(Context *c, version_t v=0); void commit_to(version_t want); void commit(version_t want, Context *c, bool ignore_authpinnability=false, int op_prio=-1); // -- dirtyness -- version_t get_committing_version() { return committing_version; } version_t get_committed_version() { return committed_version; } void set_committed_version(version_t v) { committed_version = v; } void mark_complete(); // -- reference counting -- void first_get(); void last_put(); void request_pin_get() { if (request_pins == 0) get(PIN_REQUEST); request_pins++; } void request_pin_put() { request_pins--; if (request_pins == 0) put(PIN_REQUEST); } // -- waiters -- protected: map< string_snap_t, list > waiting_on_dentry; map< inodeno_t, list > waiting_on_ino; public: bool is_waiting_for_dentry(const string& dname, snapid_t snap) { return waiting_on_dentry.count(string_snap_t(dname, snap)); } void add_dentry_waiter(const string& dentry, snapid_t snap, Context *c); void take_dentry_waiting(const string& dentry, snapid_t first, snapid_t last, list& ls); bool is_waiting_for_ino(inodeno_t ino) { return waiting_on_ino.count(ino); } void add_ino_waiter(inodeno_t ino, Context *c); void take_ino_waiting(inodeno_t ino, list& ls); void take_sub_waiting(list& ls); // dentry or ino void add_waiter(uint64_t mask, Context *c); void take_waiting(uint64_t mask, list& ls); // may include dentry waiters void finish_waiting(uint64_t mask, int result = 0); // ditto // -- import/export -- void encode_export(bufferlist& bl); void finish_export(utime_t now); void abort_export() { put(PIN_TEMPEXPORTING); } void decode_import(bufferlist::iterator& blp, utime_t now, LogSegment *ls); // -- auth pins -- bool can_auth_pin() { return is_auth() && !(is_frozen() || is_freezing()); } int get_cum_auth_pins() { return auth_pins + nested_auth_pins; } int get_auth_pins() { return auth_pins; } int get_nested_auth_pins() { return nested_auth_pins; } int get_dir_auth_pins() { return dir_auth_pins; } void auth_pin(void *who); void auth_unpin(void *who); void adjust_nested_auth_pins(int inc, int dirinc, void *by); void verify_fragstat(); int get_nested_anchors() { return nested_anchors; } void adjust_nested_anchors(int by); // -- freezing -- bool freeze_tree(); void _freeze_tree(); void unfreeze_tree(); bool freeze_dir(); void _freeze_dir(); void unfreeze_dir(); void maybe_finish_freeze(); bool is_freezing() { return is_freezing_tree() || is_freezing_dir(); } bool is_freezing_tree(); bool is_freezing_tree_root() { return state & STATE_FREEZINGTREE; } bool is_freezing_dir() { return state & STATE_FREEZINGDIR; } bool is_frozen() { return is_frozen_dir() || is_frozen_tree(); } bool is_frozen_tree(); bool is_frozen_tree_root() { return state & STATE_FROZENTREE; } bool is_frozen_dir() { return state & STATE_FROZENDIR; } bool is_freezeable(bool freezing=false) { // no nested auth pins. if ((auth_pins-freezing) > 0 || nested_auth_pins > 0) return false; // inode must not be frozen. if (!is_subtree_root() && inode->is_frozen()) return false; return true; } bool is_freezeable_dir(bool freezing=false) { if ((auth_pins-freezing) > 0 || dir_auth_pins > 0) return false; // if not subtree root, inode must not be frozen (tree--frozen_dir is okay). if (!is_subtree_root() && inode->is_frozen() && !inode->is_frozen_dir()) return false; return true; } CDir *get_frozen_tree_root(); ostream& print_db_line_prefix(ostream& out); void print(ostream& out); }; #endif ceph-0.80.11/src/mds/SnapRealm.cc0000664000175100017510000003572512623076744020454 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "SnapRealm.h" #include "MDCache.h" #include "MDS.h" #include "messages/MClientSnap.h" /* * SnapRealm */ #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix _prefix(_dout, mdcache->mds->get_nodeid(), inode, srnode.seq, this) static ostream& _prefix(std::ostream *_dout, int whoami, CInode *inode, uint64_t seq, SnapRealm *realm) { return *_dout << " mds." << whoami << ".cache.snaprealm(" << inode->ino() << " seq " << seq << " " << realm << ") "; } ostream& operator<<(ostream& out, const SnapRealm& realm) { out << "snaprealm(" << realm.inode->ino() << " seq " << realm.srnode.seq << " lc " << realm.srnode.last_created << " cr " << realm.srnode.created; if (realm.srnode.created != realm.srnode.current_parent_since) out << " cps " << realm.srnode.current_parent_since; out << " snaps=" << realm.srnode.snaps; if (realm.srnode.past_parents.size()) { out << " past_parents=("; for (map::const_iterator p = realm.srnode.past_parents.begin(); p != realm.srnode.past_parents.end(); ++p) { if (p != realm.srnode.past_parents.begin()) out << ","; out << p->second.first << "-" << p->first << "=" << p->second.ino; } out << ")"; } out << " " << &realm << ")"; return out; } void SnapRealm::add_open_past_parent(SnapRealm *parent) { open_past_parents[parent->inode->ino()] = parent; parent->inode->get(CInode::PIN_PASTSNAPPARENT); } bool SnapRealm::_open_parents(Context *finish, snapid_t first, snapid_t last) { dout(10) << "open_parents [" << first << "," << last << "]" << dendl; if (open) return true; // make sure my current parents' parents are open... if (parent) { dout(10) << " current parent [" << srnode.current_parent_since << ",head] is " << *parent << " on " << *parent->inode << dendl; if (last >= srnode.current_parent_since && !parent->_open_parents(finish, MAX(first, srnode.current_parent_since), last)) return false; } // and my past parents too! assert(srnode.past_parents.size() >= open_past_parents.size()); if (srnode.past_parents.size() > open_past_parents.size()) { for (map::iterator p = srnode.past_parents.begin(); p != srnode.past_parents.end(); ++p) { dout(10) << " past_parent [" << p->second.first << "," << p->first << "] is " << p->second.ino << dendl; CInode *parent = mdcache->get_inode(p->second.ino); if (!parent) { mdcache->open_remote_ino(p->second.ino, finish); return false; } assert(parent->snaprealm); // hmm! if (!open_past_parents.count(p->second.ino)) { add_open_past_parent(parent->snaprealm); } if (!parent->snaprealm->_open_parents(finish, p->second.first, p->first)) return false; } } open = true; return true; } bool SnapRealm::have_past_parents_open(snapid_t first, snapid_t last) { dout(10) << "have_past_parents_open [" << first << "," << last << "]" << dendl; if (open) return true; for (map::iterator p = srnode.past_parents.lower_bound(first); p != srnode.past_parents.end(); ++p) { if (p->second.first > last) break; dout(10) << " past parent [" << p->second.first << "," << p->first << "] was " << p->second.ino << dendl; if (open_past_parents.count(p->second.ino) == 0) { dout(10) << " past parent " << p->second.ino << " is not open" << dendl; return false; } if (!open_past_parents[p->second.ino]->have_past_parents_open(MAX(first, p->second.first), MIN(last, p->first))) return false; } open = true; return true; } void SnapRealm::close_parents() { for (map::iterator p = open_past_parents.begin(); p != open_past_parents.end(); ++p) p->second->inode->put(CInode::PIN_PASTSNAPPARENT); open_past_parents.clear(); } /* * get list of snaps for this realm. we must include parents' snaps * for the intervals during which they were our parent. */ void SnapRealm::build_snap_set(set &s, snapid_t& max_seq, snapid_t& max_last_created, snapid_t& max_last_destroyed, snapid_t first, snapid_t last) { dout(10) << "build_snap_set [" << first << "," << last << "] on " << *this << dendl; if (srnode.seq > max_seq) max_seq = srnode.seq; if (srnode.last_created > max_last_created) max_last_created = srnode.last_created; if (srnode.last_destroyed > max_last_destroyed) max_last_destroyed = srnode.last_destroyed; // include my snaps within interval [first,last] for (map::iterator p = srnode.snaps.lower_bound(first); // first element >= first p != srnode.snaps.end() && p->first <= last; ++p) s.insert(p->first); // include snaps for parents during intervals that intersect [first,last] for (map::iterator p = srnode.past_parents.lower_bound(first); p != srnode.past_parents.end() && p->first >= first && p->second.first <= last; ++p) { CInode *oldparent = mdcache->get_inode(p->second.ino); assert(oldparent); // call open_parents first! assert(oldparent->snaprealm); oldparent->snaprealm->build_snap_set(s, max_seq, max_last_created, max_last_destroyed, MAX(first, p->second.first), MIN(last, p->first)); } if (srnode.current_parent_since <= last && parent) parent->build_snap_set(s, max_seq, max_last_created, max_last_destroyed, MAX(first, srnode.current_parent_since), last); } void SnapRealm::check_cache() { if (cached_seq >= srnode.seq) return; cached_snaps.clear(); cached_snap_context.clear(); cached_last_created = srnode.last_created; cached_last_destroyed = srnode.last_destroyed; cached_seq = srnode.seq; build_snap_set(cached_snaps, cached_seq, cached_last_created, cached_last_destroyed, 0, CEPH_NOSNAP); cached_snap_trace.clear(); build_snap_trace(cached_snap_trace); dout(10) << "check_cache rebuilt " << cached_snaps << " seq " << srnode.seq << " cached_seq " << cached_seq << " cached_last_created " << cached_last_created << " cached_last_destroyed " << cached_last_destroyed << ")" << dendl; } const set& SnapRealm::get_snaps() { check_cache(); dout(10) << "get_snaps " << cached_snaps << " (seq " << srnode.seq << " cached_seq " << cached_seq << ")" << dendl; return cached_snaps; } /* * build vector in reverse sorted order */ const SnapContext& SnapRealm::get_snap_context() { check_cache(); if (!cached_snap_context.seq) { cached_snap_context.seq = cached_seq; cached_snap_context.snaps.resize(cached_snaps.size()); unsigned i = 0; for (set::reverse_iterator p = cached_snaps.rbegin(); p != cached_snaps.rend(); ++p) cached_snap_context.snaps[i++] = *p; } return cached_snap_context; } void SnapRealm::get_snap_info(map& infomap, snapid_t first, snapid_t last) { const set& snaps = get_snaps(); dout(10) << "get_snap_info snaps " << snaps << dendl; // include my snaps within interval [first,last] for (map::iterator p = srnode.snaps.lower_bound(first); // first element >= first p != srnode.snaps.end() && p->first <= last; ++p) infomap[p->first] = &p->second; // include snaps for parents during intervals that intersect [first,last] for (map::iterator p = srnode.past_parents.lower_bound(first); p != srnode.past_parents.end() && p->first >= first && p->second.first <= last; ++p) { CInode *oldparent = mdcache->get_inode(p->second.ino); assert(oldparent); // call open_parents first! assert(oldparent->snaprealm); oldparent->snaprealm->get_snap_info(infomap, MAX(first, p->second.first), MIN(last, p->first)); } if (srnode.current_parent_since <= last && parent) parent->get_snap_info(infomap, MAX(first, srnode.current_parent_since), last); } const string& SnapRealm::get_snapname(snapid_t snapid, inodeno_t atino) { if (srnode.snaps.count(snapid)) { if (atino == inode->ino()) return srnode.snaps[snapid].name; else return srnode.snaps[snapid].get_long_name(); } map::iterator p = srnode.past_parents.lower_bound(snapid); if (p != srnode.past_parents.end() && p->second.first <= snapid) { CInode *oldparent = mdcache->get_inode(p->second.ino); assert(oldparent); // call open_parents first! assert(oldparent->snaprealm); return oldparent->snaprealm->get_snapname(snapid, atino); } assert(srnode.current_parent_since <= snapid); assert(parent); return parent->get_snapname(snapid, atino); } snapid_t SnapRealm::resolve_snapname(const string& n, inodeno_t atino, snapid_t first, snapid_t last) { // first try me dout(10) << "resolve_snapname '" << n << "' in [" << first << "," << last << "]" << dendl; //snapid_t num; //if (n[0] == '~') num = atoll(n.c_str()+1); bool actual = (atino == inode->ino()); string pname; inodeno_t pino; if (!actual) { if (!n.length() || n[0] != '_') return 0; int next_ = n.find('_', 1); if (next_ < 0) return 0; pname = n.substr(1, next_ - 1); pino = atoll(n.c_str() + next_ + 1); dout(10) << " " << n << " parses to name '" << pname << "' dirino " << pino << dendl; } for (map::iterator p = srnode.snaps.lower_bound(first); // first element >= first p != srnode.snaps.end() && p->first <= last; ++p) { dout(15) << " ? " << p->second << dendl; //if (num && p->second.snapid == num) //return p->first; if (actual && p->second.name == n) return p->first; if (!actual && p->second.name == pname && p->second.ino == pino) return p->first; } // include snaps for parents during intervals that intersect [first,last] for (map::iterator p = srnode.past_parents.lower_bound(first); p != srnode.past_parents.end() && p->first >= first && p->second.first <= last; ++p) { CInode *oldparent = mdcache->get_inode(p->second.ino); assert(oldparent); // call open_parents first! assert(oldparent->snaprealm); snapid_t r = oldparent->snaprealm->resolve_snapname(n, atino, MAX(first, p->second.first), MIN(last, p->first)); if (r) return r; } if (parent && srnode.current_parent_since <= last) return parent->resolve_snapname(n, atino, MAX(first, srnode.current_parent_since), last); return 0; } void SnapRealm::adjust_parent() { SnapRealm *newparent = inode->get_parent_dn()->get_dir()->get_inode()->find_snaprealm(); if (newparent != parent) { dout(10) << "adjust_parent " << parent << " -> " << newparent << dendl; if (parent) parent->open_children.erase(this); parent = newparent; if (parent) parent->open_children.insert(this); invalidate_cached_snaps(); } } void SnapRealm::split_at(SnapRealm *child) { dout(10) << "split_at " << *child << " on " << *child->inode << dendl; if (!child->inode->is_dir()) { // it's not a dir. if (child->inode->containing_realm) { // - no open children. // - only need to move this child's inode's caps. child->inode->move_to_realm(child); } else { // no caps, nothing to move/split. dout(20) << " split no-op, no caps to move on file " << *child->inode << dendl; assert(!child->inode->is_any_caps()); } return; } // it's a dir. // split open_children dout(10) << " open_children are " << open_children << dendl; for (set::iterator p = open_children.begin(); p != open_children.end(); ) { SnapRealm *realm = *p; if (realm != child && child->inode->is_projected_ancestor_of(realm->inode)) { dout(20) << " child gets child realm " << *realm << " on " << *realm->inode << dendl; realm->parent = child; child->open_children.insert(realm); open_children.erase(p++); } else { dout(20) << " keeping child realm " << *realm << " on " << *realm->inode << dendl; ++p; } } // split inodes_with_caps elist::iterator p = inodes_with_caps.begin(member_offset(CInode, item_caps)); while (!p.end()) { CInode *in = *p; ++p; // does inode fall within the child realm? bool under_child = false; if (in == child->inode) { under_child = true; } else { CInode *t = in; while (t->get_parent_dn()) { t = t->get_parent_dn()->get_dir()->get_inode(); if (t == child->inode) { under_child = true; break; } if (t == in) break; } } if (under_child) { dout(20) << " child gets " << *in << dendl; in->move_to_realm(child); } else { dout(20) << " keeping " << *in << dendl; } } } const bufferlist& SnapRealm::get_snap_trace() { check_cache(); return cached_snap_trace; } void SnapRealm::build_snap_trace(bufferlist& snapbl) { SnapRealmInfo info(inode->ino(), srnode.created, srnode.seq, srnode.current_parent_since); if (parent) { info.h.parent = parent->inode->ino(); if (!srnode.past_parents.empty()) { snapid_t last = srnode.past_parents.rbegin()->first; set past; snapid_t max_seq, max_last_created, max_last_destroyed; build_snap_set(past, max_seq, max_last_created, max_last_destroyed, 0, last); info.prior_parent_snaps.reserve(past.size()); for (set::reverse_iterator p = past.rbegin(); p != past.rend(); ++p) info.prior_parent_snaps.push_back(*p); dout(10) << "build_snap_trace prior_parent_snaps from [1," << last << "] " << info.prior_parent_snaps << dendl; } } else info.h.parent = 0; info.my_snaps.reserve(srnode.snaps.size()); for (map::reverse_iterator p = srnode.snaps.rbegin(); p != srnode.snaps.rend(); ++p) info.my_snaps.push_back(p->first); dout(10) << "build_snap_trace my_snaps " << info.my_snaps << dendl; ::encode(info, snapbl); if (parent) parent->build_snap_trace(snapbl); } void SnapRealm::prune_past_parents() { dout(10) << "prune_past_parents" << dendl; check_cache(); assert(open); map::iterator p = srnode.past_parents.begin(); while (p != srnode.past_parents.end()) { set::iterator q = cached_snaps.lower_bound(p->second.first); if (q == cached_snaps.end() || *q > p->first) { dout(10) << "prune_past_parents pruning [" << p->second.first << "," << p->first << "] " << p->second.ino << dendl; srnode.past_parents.erase(p++); } else { dout(10) << "prune_past_parents keeping [" << p->second.first << "," << p->first << "] " << p->second.ino << dendl; ++p; } } } ceph-0.80.11/src/mds/inode_backtrace.h0000664000175100017510000000440712623076744021522 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_INODE_BACKTRACE_H #define CEPH_INODE_BACKTRACE_H #include "mdstypes.h" namespace ceph { class Formatter; } /** metadata backpointers **/ /* * - inode_backpointer_t is just the _pointer_ portion; it doesn't * tell us who we point _from_. * * - it _does_ include a version of the source object, so we can look * at two different pointers (from the same inode) and tell which is * newer. */ struct inode_backpointer_t { inodeno_t dirino; // containing directory ino string dname; // linking dentry name version_t version; // child's version at time of backpointer creation inode_backpointer_t() : version(0) {} inode_backpointer_t(inodeno_t i, const string &d, version_t v) : dirino(i), dname(d), version(v) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void decode_old(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(inode_backpointer_t) inline bool operator==(const inode_backpointer_t& l, const inode_backpointer_t& r) { return l.dirino == r.dirino && l.version == r.version && l.dname == r.dname; } inline ostream& operator<<(ostream& out, const inode_backpointer_t& ib) { return out << "<" << ib.dirino << "/" << ib.dname << " v" << ib.version << ">"; } /* * inode_backtrace_t is a complete ancestor backtraces for a given inode. * we include who _we_ are, so that the backtrace can stand alone (as, say, * an xattr on an object). */ struct inode_backtrace_t { inodeno_t ino; // my ino vector ancestors; int64_t pool; // we use a set for old_pools to avoid duplicate entries, e.g. setlayout 0, 1, 0 set old_pools; inode_backtrace_t() : pool(-1) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(inode_backtrace_t) inline ostream& operator<<(ostream& out, const inode_backtrace_t& it) { return out << "(" << it.pool << ")" << it.ino << ":" << it.ancestors << "//" << it.old_pools; } #endif ceph-0.80.11/src/mds/snap.cc0000664000175100017510000001070512623076744017522 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004- Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "snap.h" #include "common/Formatter.h" /* * SnapInfo */ void SnapInfo::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(snapid, bl); ::encode(ino, bl); ::encode(stamp, bl); ::encode(name, bl); ENCODE_FINISH(bl); } void SnapInfo::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(snapid, bl); ::decode(ino, bl); ::decode(stamp, bl); ::decode(name, bl); DECODE_FINISH(bl); } void SnapInfo::dump(Formatter *f) const { f->dump_unsigned("snapid", snapid); f->dump_unsigned("ino", ino); f->dump_stream("stamp") << stamp; f->dump_string("name", name); } void SnapInfo::generate_test_instances(list& ls) { ls.push_back(new SnapInfo); ls.push_back(new SnapInfo); ls.back()->snapid = 1; ls.back()->ino = 2; ls.back()->stamp = utime_t(3, 4); ls.back()->name = "foo"; } ostream& operator<<(ostream& out, const SnapInfo &sn) { return out << "snap(" << sn.snapid << " " << sn.ino << " '" << sn.name << "' " << sn.stamp << ")"; } const string& SnapInfo::get_long_name() { if (long_name.length() == 0) { char nm[80]; snprintf(nm, sizeof(nm), "_%s_%llu", name.c_str(), (unsigned long long)ino); long_name = nm; } return long_name; } /* * snaplink_t */ void snaplink_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(ino, bl); ::encode(first, bl); ENCODE_FINISH(bl); } void snaplink_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(ino, bl); ::decode(first, bl); DECODE_FINISH(bl); } void snaplink_t::dump(Formatter *f) const { f->dump_unsigned("ino", ino); f->dump_unsigned("first", first); } void snaplink_t::generate_test_instances(list& ls) { ls.push_back(new snaplink_t); ls.push_back(new snaplink_t); ls.back()->ino = 2; ls.back()->first = 123; } ostream& operator<<(ostream& out, const snaplink_t &l) { return out << l.ino << "@" << l.first; } /* * sr_t */ void sr_t::encode(bufferlist& bl) const { ENCODE_START(4, 4, bl); ::encode(seq, bl); ::encode(created, bl); ::encode(last_created, bl); ::encode(last_destroyed, bl); ::encode(current_parent_since, bl); ::encode(snaps, bl); ::encode(past_parents, bl); ENCODE_FINISH(bl); } void sr_t::decode(bufferlist::iterator& p) { DECODE_START_LEGACY_COMPAT_LEN(4, 4, 4, p); if (struct_v == 2) { __u8 struct_v; ::decode(struct_v, p); // yes, really: extra byte for v2 encoding only, see 6ee52e7d. } ::decode(seq, p); ::decode(created, p); ::decode(last_created, p); ::decode(last_destroyed, p); ::decode(current_parent_since, p); ::decode(snaps, p); ::decode(past_parents, p); DECODE_FINISH(p); } void sr_t::dump(Formatter *f) const { f->dump_unsigned("seq", seq); f->dump_unsigned("created", created); f->dump_unsigned("last_created", last_created); f->dump_unsigned("last_destroyed", last_destroyed); f->dump_unsigned("current_parent_since", current_parent_since); f->open_array_section("snaps"); for (map::const_iterator p = snaps.begin(); p != snaps.end(); ++p) { f->open_object_section("snapinfo"); f->dump_unsigned("last", p->first); p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("past_parents"); for (map::const_iterator p = past_parents.begin(); p != past_parents.end(); ++p) { f->open_object_section("past_parent"); f->dump_unsigned("last", p->first); p->second.dump(f); f->close_section(); } f->close_section(); } void sr_t::generate_test_instances(list& ls) { ls.push_back(new sr_t); ls.push_back(new sr_t); ls.back()->seq = 1; ls.back()->created = 2; ls.back()->last_created = 3; ls.back()->last_destroyed = 4; ls.back()->current_parent_since = 5; ls.back()->snaps[123].snapid = 7; ls.back()->snaps[123].ino = 8; ls.back()->snaps[123].stamp = utime_t(9, 10); ls.back()->snaps[123].name = "name1"; ls.back()->past_parents[12].ino = 12; ls.back()->past_parents[12].first = 3; } ceph-0.80.11/src/mds/Mutation.cc0000664000175100017510000001425712623076744020367 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Mutation.h" #include "ScatterLock.h" #include "CDir.h" #include "messages/MClientRequest.h" #include "messages/MMDSSlaveRequest.h" // MutationImpl void MutationImpl::pin(MDSCacheObject *o) { if (pins.count(o) == 0) { o->get(MDSCacheObject::PIN_REQUEST); pins.insert(o); } } void MutationImpl::unpin(MDSCacheObject *o) { assert(pins.count(o)); o->put(MDSCacheObject::PIN_REQUEST); pins.erase(o); } void MutationImpl::set_stickydirs(CInode *in) { if (stickydirs.count(in) == 0) { in->get_stickydirs(); stickydirs.insert(in); } } void MutationImpl::drop_pins() { for (set::iterator it = pins.begin(); it != pins.end(); ++it) (*it)->put(MDSCacheObject::PIN_REQUEST); pins.clear(); } void MutationImpl::start_locking(SimpleLock *lock, int target) { assert(locking == NULL); pin(lock->get_parent()); locking = lock; locking_target_mds = target; } void MutationImpl::finish_locking(SimpleLock *lock) { assert(locking == lock); locking = NULL; locking_target_mds = -1; } // auth pins bool MutationImpl::is_auth_pinned(MDSCacheObject *object) { return auth_pins.count(object) || remote_auth_pins.count(object); } void MutationImpl::auth_pin(MDSCacheObject *object) { if (!is_auth_pinned(object)) { object->auth_pin(this); auth_pins.insert(object); } } void MutationImpl::auth_unpin(MDSCacheObject *object) { assert(auth_pins.count(object)); object->auth_unpin(this); auth_pins.erase(object); } void MutationImpl::drop_local_auth_pins() { for (set::iterator it = auth_pins.begin(); it != auth_pins.end(); ++it) { assert((*it)->is_auth()); (*it)->auth_unpin(this); } auth_pins.clear(); } void MutationImpl::add_projected_inode(CInode *in) { projected_inodes.push_back(in); } void MutationImpl::pop_and_dirty_projected_inodes() { while (!projected_inodes.empty()) { CInode *in = projected_inodes.front(); projected_inodes.pop_front(); in->pop_and_dirty_projected_inode(ls); } } void MutationImpl::add_projected_fnode(CDir *dir) { projected_fnodes.push_back(dir); } void MutationImpl::pop_and_dirty_projected_fnodes() { while (!projected_fnodes.empty()) { CDir *dir = projected_fnodes.front(); projected_fnodes.pop_front(); dir->pop_and_dirty_projected_fnode(ls); } } void MutationImpl::add_updated_lock(ScatterLock *lock) { updated_locks.push_back(lock); } void MutationImpl::add_cow_inode(CInode *in) { pin(in); dirty_cow_inodes.push_back(in); } void MutationImpl::add_cow_dentry(CDentry *dn) { pin(dn); dirty_cow_dentries.push_back(pair(dn, dn->get_projected_version())); } void MutationImpl::apply() { pop_and_dirty_projected_inodes(); pop_and_dirty_projected_fnodes(); for (list::iterator p = dirty_cow_inodes.begin(); p != dirty_cow_inodes.end(); ++p) (*p)->_mark_dirty(ls); for (list >::iterator p = dirty_cow_dentries.begin(); p != dirty_cow_dentries.end(); ++p) p->first->mark_dirty(p->second, ls); for (list::iterator p = updated_locks.begin(); p != updated_locks.end(); ++p) (*p)->mark_dirty(); } void MutationImpl::cleanup() { drop_local_auth_pins(); drop_pins(); } // MDRequestImpl MDRequestImpl::~MDRequestImpl() { if (client_request) client_request->put(); if (slave_request) slave_request->put(); delete _more; } MDRequestImpl::More* MDRequestImpl::more() { if (!_more) _more = new More(); return _more; } bool MDRequestImpl::has_more() { return _more; } bool MDRequestImpl::are_slaves() { return _more && !_more->slaves.empty(); } bool MDRequestImpl::slave_did_prepare() { return more()->slave_commit; } bool MDRequestImpl::did_ino_allocation() { return alloc_ino || used_prealloc_ino || prealloc_inos.size(); } bool MDRequestImpl::freeze_auth_pin(CInode *inode) { assert(!more()->rename_inode || more()->rename_inode == inode); more()->rename_inode = inode; more()->is_freeze_authpin = true; auth_pin(inode); if (!inode->freeze_inode(1)) { return false; } inode->freeze_auth_pin(); inode->unfreeze_inode(); return true; } void MDRequestImpl::unfreeze_auth_pin(bool clear_inode) { assert(more()->is_freeze_authpin); CInode *inode = more()->rename_inode; if (inode->is_frozen_auth_pin()) inode->unfreeze_auth_pin(); else inode->unfreeze_inode(); more()->is_freeze_authpin = false; if (clear_inode) more()->rename_inode = NULL; } void MDRequestImpl::set_remote_frozen_auth_pin(CInode *inode) { more()->rename_inode = inode; more()->is_remote_frozen_authpin = true; } void MDRequestImpl::set_ambiguous_auth(CInode *inode) { assert(!more()->rename_inode || more()->rename_inode == inode); assert(!more()->is_ambiguous_auth); inode->set_ambiguous_auth(); more()->rename_inode = inode; more()->is_ambiguous_auth = true; } void MDRequestImpl::clear_ambiguous_auth() { CInode *inode = more()->rename_inode; assert(inode && more()->is_ambiguous_auth); inode->clear_ambiguous_auth(); more()->is_ambiguous_auth = false; } bool MDRequestImpl::can_auth_pin(MDSCacheObject *object) { return object->can_auth_pin() || (is_auth_pinned(object) && has_more() && more()->is_freeze_authpin && more()->rename_inode == object); } void MDRequestImpl::drop_local_auth_pins() { if (has_more() && more()->is_freeze_authpin) unfreeze_auth_pin(true); MutationImpl::drop_local_auth_pins(); } void MDRequestImpl::print(ostream &out) { out << "request(" << reqid; //if (request) out << " " << *request; if (is_slave()) out << " slave_to mds." << slave_to_mds; if (client_request) out << " cr=" << client_request; if (slave_request) out << " sr=" << slave_request; out << ")"; } ceph-0.80.11/src/mds/Resetter.h0000664000175100017510000000162112623076744020215 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Greg Farnum * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef JOURNAL_RESETTER_H_ #define JOURNAL_RESETTER_H_ #include "osdc/Journaler.h" #include "mds/MDSUtility.h" /** * This class lets you reset an mds journal for troubleshooting or whatever. * * To use, create a Resetter, call init(), and then call reset() with the name * of the file to dump to. */ class Resetter : public MDSUtility { public: Journaler *journaler; Resetter() : journaler(NULL) {} int init(int rank); void reset(); }; #endif /* JOURNAL_RESETTER_H_ */ ceph-0.80.11/src/mds/snap.h0000664000175100017510000000443212623076744017364 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_SNAP_H #define CEPH_MDS_SNAP_H #include "mdstypes.h" #include "common/snap_types.h" /* * generic snap descriptor. */ struct SnapInfo { snapid_t snapid; inodeno_t ino; utime_t stamp; string name; string long_name; ///< cached _$ino_$name void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); const string& get_long_name(); }; WRITE_CLASS_ENCODER(SnapInfo) ostream& operator<<(ostream& out, const SnapInfo &sn); /* * SnapRealm - a subtree that shares the same set of snapshots. */ struct SnapRealm; struct CapabilityGroup; class CInode; class MDCache; struct MDRequest; #include "Capability.h" struct snaplink_t { inodeno_t ino; snapid_t first; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(snaplink_t) ostream& operator<<(ostream& out, const snaplink_t &l); // carry data about a specific version of a SnapRealm struct sr_t { snapid_t seq; // basically, a version/seq # for changes to _this_ realm. snapid_t created; // when this realm was created. snapid_t last_created; // last snap created in _this_ realm. snapid_t last_destroyed; // seq for last removal snapid_t current_parent_since; map snaps; map past_parents; // key is "last" (or NOSNAP) sr_t() : seq(0), created(0), last_created(0), last_destroyed(0), current_parent_since(1) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(sr_t); #endif ceph-0.80.11/src/mds/LogSegment.h0000664000175100017510000000467112623076744020474 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOGSEGMENT_H #define CEPH_LOGSEGMENT_H #include "include/dlist.h" #include "include/elist.h" #include "include/interval_set.h" #include "include/Context.h" #include "mdstypes.h" #include "CInode.h" #include "CDentry.h" #include "CDir.h" #include "include/unordered_set.h" using ceph::unordered_set; class CDir; class CInode; class CDentry; class MDS; struct MDSlaveUpdate; class LogSegment { public: uint64_t offset, end; int num_events; uint64_t trimmable_at; // dirty items elist dirty_dirfrags, new_dirfrags; elist dirty_inodes; elist dirty_dentries; elist open_files; elist dirty_parent_inodes; elist dirty_dirfrag_dir; elist dirty_dirfrag_nest; elist dirty_dirfrag_dirfragtree; elist slave_updates; set truncating_inodes; map > pending_commit_tids; // mdstable set uncommitted_masters; set uncommitted_fragments; // client request ids map last_client_tids; // table version version_t inotablev; version_t sessionmapv; map tablev; // try to expire void try_to_expire(MDS *mds, C_GatherBuilder &gather_bld, int op_prio); // cons LogSegment(loff_t off) : offset(off), end(off), num_events(0), trimmable_at(0), dirty_dirfrags(member_offset(CDir, item_dirty)), new_dirfrags(member_offset(CDir, item_new)), dirty_inodes(member_offset(CInode, item_dirty)), dirty_dentries(member_offset(CDentry, item_dirty)), open_files(member_offset(CInode, item_open_file)), dirty_parent_inodes(member_offset(CInode, item_dirty_parent)), dirty_dirfrag_dir(member_offset(CInode, item_dirty_dirfrag_dir)), dirty_dirfrag_nest(member_offset(CInode, item_dirty_dirfrag_nest)), dirty_dirfrag_dirfragtree(member_offset(CInode, item_dirty_dirfrag_dirfragtree)), slave_updates(0), // passed to begin() manually inotablev(0), sessionmapv(0) { } }; #endif ceph-0.80.11/src/mds/Server.h0000664000175100017510000002376512623076744017703 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_SERVER_H #define CEPH_MDS_SERVER_H #include "MDS.h" class PerfCounters; class LogEvent; class EMetaBlob; class EUpdate; class MMDSSlaveRequest; struct SnapInfo; struct MutationImpl; struct MDRequestImpl; typedef ceph::shared_ptr MutationRef; typedef ceph::shared_ptr MDRequestRef; enum { l_mdss_first = 1000, l_mdss_hcreq, l_mdss_hsreq, l_mdss_hcsess, l_mdss_dcreq, l_mdss_dsreq, l_mdss_last, }; class Server { MDS *mds; MDCache *mdcache; MDLog *mdlog; Messenger *messenger; PerfCounters *logger; public: int failed_reconnects; bool terminating_sessions; Server(MDS *m) : mds(m), mdcache(mds->mdcache), mdlog(mds->mdlog), messenger(mds->messenger), logger(0), failed_reconnects(0), terminating_sessions(false) { } ~Server() { g_ceph_context->get_perfcounters_collection()->remove(logger); delete logger; } void create_logger(); // message handler void dispatch(Message *m); // -- sessions and recovery -- utime_t reconnect_start; set client_reconnect_gather; // clients i need a reconnect msg from. Session *get_session(Message *m); void handle_client_session(class MClientSession *m); void _session_logged(Session *session, uint64_t state_seq, bool open, version_t pv, interval_set& inos,version_t piv); version_t prepare_force_open_sessions(map &cm, map& sseqmap); void finish_force_open_sessions(map &cm, map& sseqmap, bool dec_import=true); void flush_client_sessions(set& client_set, C_GatherBuilder& gather); void finish_flush_session(Session *session, version_t seq); void terminate_sessions(); void find_idle_sessions(); void kill_session(Session *session); void journal_close_session(Session *session, int state); void reconnect_clients(); void handle_client_reconnect(class MClientReconnect *m); //void process_reconnect_cap(CInode *in, int from, ceph_mds_cap_reconnect& capinfo); void reconnect_gather_finish(); void reconnect_tick(); void recover_filelocks(CInode *in, bufferlist locks, int64_t client); void recall_client_state(float ratio); // -- requests -- void handle_client_request(MClientRequest *m); void journal_and_reply(MDRequestRef& mdr, CInode *tracei, CDentry *tracedn, LogEvent *le, Context *fin); void dispatch_client_request(MDRequestRef& mdr); void early_reply(MDRequestRef& mdr, CInode *tracei, CDentry *tracedn); void reply_request(MDRequestRef& mdr, int r = 0, CInode *tracei = 0, CDentry *tracedn = 0); void reply_request(MDRequestRef& mdr, MClientReply *reply, CInode *tracei = 0, CDentry *tracedn = 0); void set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn, snapid_t snapid, int num_dentries_wanted, MDRequestRef& mdr); void encode_empty_dirstat(bufferlist& bl); void encode_infinite_lease(bufferlist& bl); void encode_null_lease(bufferlist& bl); void handle_slave_request(MMDSSlaveRequest *m); void handle_slave_request_reply(MMDSSlaveRequest *m); void dispatch_slave_request(MDRequestRef& mdr); void handle_slave_auth_pin(MDRequestRef& mdr); void handle_slave_auth_pin_ack(MDRequestRef& mdr, MMDSSlaveRequest *ack); // some helpers CDir *validate_dentry_dir(MDRequestRef& mdr, CInode *diri, const string& dname); CDir *traverse_to_auth_dir(MDRequestRef& mdr, vector &trace, filepath refpath); CDentry *prepare_null_dentry(MDRequestRef& mdr, CDir *dir, const string& dname, bool okexist=false); CDentry *prepare_stray_dentry(MDRequestRef& mdr, CInode *in); CInode* prepare_new_inode(MDRequestRef& mdr, CDir *dir, inodeno_t useino, unsigned mode, ceph_file_layout *layout=NULL); void journal_allocated_inos(MDRequestRef& mdr, EMetaBlob *blob); void apply_allocated_inos(MDRequestRef& mdr); CInode* rdlock_path_pin_ref(MDRequestRef& mdr, int n, set& rdlocks, bool want_auth, bool no_want_auth=false, ceph_file_layout **layout=NULL, bool no_lookup=false); CDentry* rdlock_path_xlock_dentry(MDRequestRef& mdr, int n, set& rdlocks, set& wrlocks, set& xlocks, bool okexist, bool mustexist, bool alwaysxlock, ceph_file_layout **layout=NULL); CDir* try_open_auth_dirfrag(CInode *diri, frag_t fg, MDRequestRef& mdr); // requests on existing inodes. void handle_client_getattr(MDRequestRef& mdr, bool is_lookup); void handle_client_lookup_ino(MDRequestRef& mdr, bool want_parent, bool want_dentry); void _lookup_ino_2(MDRequestRef& mdr, int r); void handle_client_readdir(MDRequestRef& mdr); void handle_client_file_setlock(MDRequestRef& mdr); void handle_client_file_readlock(MDRequestRef& mdr); void handle_client_setattr(MDRequestRef& mdr); void handle_client_setlayout(MDRequestRef& mdr); void handle_client_setdirlayout(MDRequestRef& mdr); int parse_layout_vxattr(string name, string value, ceph_file_layout *layout); void handle_set_vxattr(MDRequestRef& mdr, CInode *cur, ceph_file_layout *dir_layout, set rdlocks, set wrlocks, set xlocks); void handle_remove_vxattr(MDRequestRef& mdr, CInode *cur, set rdlocks, set wrlocks, set xlocks); void handle_client_setxattr(MDRequestRef& mdr); void handle_client_removexattr(MDRequestRef& mdr); void handle_client_fsync(MDRequestRef& mdr); // open void handle_client_open(MDRequestRef& mdr); void handle_client_openc(MDRequestRef& mdr); // O_CREAT variant. void do_open_truncate(MDRequestRef& mdr, int cmode); // O_TRUNC variant. // namespace changes void handle_client_mknod(MDRequestRef& mdr); void handle_client_mkdir(MDRequestRef& mdr); void handle_client_symlink(MDRequestRef& mdr); // link void handle_client_link(MDRequestRef& mdr); void _link_local(MDRequestRef& mdr, CDentry *dn, CInode *targeti); void _link_local_finish(MDRequestRef& mdr, CDentry *dn, CInode *targeti, version_t, version_t); void _link_remote(MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti); void _link_remote_finish(MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti, version_t); void handle_slave_link_prep(MDRequestRef& mdr); void _logged_slave_link(MDRequestRef& mdr, CInode *targeti); void _commit_slave_link(MDRequestRef& mdr, int r, CInode *targeti); void _committed_slave(MDRequestRef& mdr); // use for rename, too void handle_slave_link_prep_ack(MDRequestRef& mdr, MMDSSlaveRequest *m); void do_link_rollback(bufferlist &rbl, int master, MDRequestRef& mdr); void _link_rollback_finish(MutationRef& mut, MDRequestRef& mdr); // unlink void handle_client_unlink(MDRequestRef& mdr); bool _dir_is_nonempty_unlocked(MDRequestRef& mdr, CInode *rmdiri); bool _dir_is_nonempty(MDRequestRef& mdr, CInode *rmdiri); void _unlink_local(MDRequestRef& mdr, CDentry *dn, CDentry *straydn); void _unlink_local_finish(MDRequestRef& mdr, CDentry *dn, CDentry *straydn, version_t); bool _rmdir_prepare_witness(MDRequestRef& mdr, int who, CDentry *dn, CDentry *straydn); void handle_slave_rmdir_prep(MDRequestRef& mdr); void _logged_slave_rmdir(MDRequestRef& mdr, CDentry *srcdn, CDentry *straydn); void _commit_slave_rmdir(MDRequestRef& mdr, int r); void handle_slave_rmdir_prep_ack(MDRequestRef& mdr, MMDSSlaveRequest *ack); void do_rmdir_rollback(bufferlist &rbl, int master, MDRequestRef& mdr); void _rmdir_rollback_finish(MDRequestRef& mdr, metareqid_t reqid, CDentry *dn, CDentry *straydn); // rename void handle_client_rename(MDRequestRef& mdr); void _rename_finish(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, CDentry *straydn); void handle_client_lssnap(MDRequestRef& mdr); void handle_client_mksnap(MDRequestRef& mdr); void _mksnap_finish(MDRequestRef& mdr, CInode *diri, SnapInfo &info); void handle_client_rmsnap(MDRequestRef& mdr); void _rmsnap_finish(MDRequestRef& mdr, CInode *diri, snapid_t snapid); // helpers bool _rename_prepare_witness(MDRequestRef& mdr, int who, set &witnesse, CDentry *srcdn, CDentry *destdn, CDentry *straydn); version_t _rename_prepare_import(MDRequestRef& mdr, CDentry *srcdn, bufferlist *client_map_bl); bool _need_force_journal(CInode *diri, bool empty); void _rename_prepare(MDRequestRef& mdr, EMetaBlob *metablob, bufferlist *client_map_bl, CDentry *srcdn, CDentry *destdn, CDentry *straydn); /* set not_journaling=true if you're going to discard the results -- * this bypasses the asserts to make sure we're journaling the right * things on the right nodes */ void _rename_apply(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, CDentry *straydn); // slaving void handle_slave_rename_prep(MDRequestRef& mdr); void handle_slave_rename_prep_ack(MDRequestRef& mdr, MMDSSlaveRequest *m); void handle_slave_rename_notify_ack(MDRequestRef& mdr, MMDSSlaveRequest *m); void _slave_rename_sessions_flushed(MDRequestRef& mdr); void _logged_slave_rename(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, CDentry *straydn); void _commit_slave_rename(MDRequestRef& mdr, int r, CDentry *srcdn, CDentry *destdn, CDentry *straydn); void do_rename_rollback(bufferlist &rbl, int master, MDRequestRef& mdr, bool finish_mdr=false); void _rename_rollback_finish(MutationRef& mut, MDRequestRef& mdr, CDentry *srcdn, version_t srcdnpv, CDentry *destdn, CDentry *staydn, bool finish_mdr); }; #endif ceph-0.80.11/src/mds/MDSMap.h0000664000175100017510000004474412623076744017516 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSMAP_H #define CEPH_MDSMAP_H #include #include "include/types.h" #include "common/Clock.h" #include "msg/Message.h" #include #include #include using namespace std; #include "common/config.h" #include "include/CompatSet.h" #include "include/ceph_features.h" #include "common/Formatter.h" /* boot --> standby, creating, or starting. dne ----> creating -----> active* ^ ^___________/ / ^ ^ | / / | destroying / / | ^ / / | | / / | stopped <---- stopping* <-/ / | \ / | ----- starting* ----/ | | failed | \ | \--> replay* --> reconnect* --> rejoin* * = can fail */ class CephContext; extern CompatSet get_mdsmap_compat_set_all(); extern CompatSet get_mdsmap_compat_set_default(); extern CompatSet get_mdsmap_compat_set_base(); // pre v0.20 #define MDS_FEATURE_INCOMPAT_BASE CompatSet::Feature(1, "base v0.20") #define MDS_FEATURE_INCOMPAT_CLIENTRANGES CompatSet::Feature(2, "client writeable ranges") #define MDS_FEATURE_INCOMPAT_FILELAYOUT CompatSet::Feature(3, "default file layouts on dirs") #define MDS_FEATURE_INCOMPAT_DIRINODE CompatSet::Feature(4, "dir inode in separate object") #define MDS_FEATURE_INCOMPAT_ENCODING CompatSet::Feature(5, "mds uses versioned encoding") #define MDS_FEATURE_INCOMPAT_OMAPDIRFRAG CompatSet::Feature(6, "dirfrag is stored in omap") #define MDS_FEATURE_INCOMPAT_INLINE CompatSet::Feature(7, "mds uses inline data") class MDSMap { public: // mds states /* static const int STATE_DNE = CEPH_MDS_STATE_DNE; // down, never existed. static const int STATE_DESTROYING = CEPH_MDS_STATE_DESTROYING; // down, existing, semi-destroyed. static const int STATE_FAILED = CEPH_MDS_STATE_FAILED; // down, active subtrees; needs to be recovered. */ static const int STATE_STOPPED = CEPH_MDS_STATE_STOPPED; // down, once existed, but no subtrees. empty log. static const int STATE_BOOT = CEPH_MDS_STATE_BOOT; // up, boot announcement. destiny unknown. static const int STATE_STANDBY = CEPH_MDS_STATE_STANDBY; // up, idle. waiting for assignment by monitor. static const int STATE_STANDBY_REPLAY = CEPH_MDS_STATE_STANDBY_REPLAY; // up, replaying active node; ready to take over. static const int STATE_ONESHOT_REPLAY = CEPH_MDS_STATE_REPLAYONCE; //up, replaying active node journal to verify it, then shutting down static const int STATE_CREATING = CEPH_MDS_STATE_CREATING; // up, creating MDS instance (new journal, idalloc..). static const int STATE_STARTING = CEPH_MDS_STATE_STARTING; // up, starting prior stopped MDS instance. static const int STATE_REPLAY = CEPH_MDS_STATE_REPLAY; // up, starting prior failed instance. scanning journal. static const int STATE_RESOLVE = CEPH_MDS_STATE_RESOLVE; // up, disambiguating distributed operations (import, rename, etc.) static const int STATE_RECONNECT = CEPH_MDS_STATE_RECONNECT; // up, reconnect to clients static const int STATE_REJOIN = CEPH_MDS_STATE_REJOIN; // up, replayed journal, rejoining distributed cache static const int STATE_CLIENTREPLAY = CEPH_MDS_STATE_CLIENTREPLAY; // up, active static const int STATE_ACTIVE = CEPH_MDS_STATE_ACTIVE; // up, active static const int STATE_STOPPING = CEPH_MDS_STATE_STOPPING; // up, exporting metadata (-> standby or out) // indicate startup standby preferences for MDS // of course, if they have a specific rank to follow, they just set that! static const int MDS_NO_STANDBY_PREF = -1; // doesn't have instructions to do anything static const int MDS_STANDBY_ANY = -2; // is instructed to be standby-replay, may // or may not have specific name to follow static const int MDS_STANDBY_NAME = -3; // standby for a named MDS static const int MDS_MATCHED_ACTIVE = -4; // has a matched standby, which if up // it should follow, but otherwise should // be assigned a rank struct mds_info_t { uint64_t global_id; string name; int32_t rank; int32_t inc; int32_t state; version_t state_seq; entity_addr_t addr; utime_t laggy_since; int32_t standby_for_rank; string standby_for_name; set export_targets; mds_info_t() : global_id(0), rank(-1), inc(0), state(STATE_STANDBY), state_seq(0), standby_for_rank(MDS_NO_STANDBY_PREF) { } bool laggy() const { return !(laggy_since == utime_t()); } void clear_laggy() { laggy_since = utime_t(); } entity_inst_t get_inst() const { return entity_inst_t(entity_name_t::MDS(rank), addr); } void encode(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_MDSENC) == 0 ) encode_unversioned(bl); else encode_versioned(bl, features); } void decode(bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& ls); private: void encode_versioned(bufferlist& bl, uint64_t features) const; void encode_unversioned(bufferlist& bl) const; }; protected: // base map epoch_t epoch; uint32_t flags; // flags epoch_t last_failure; // mds epoch of last failure epoch_t last_failure_osd_epoch; // osd epoch of last failure; any mds entering replay needs // at least this osdmap to ensure the blacklist propagates. utime_t created, modified; int32_t tableserver; // which MDS has anchortable, snaptable int32_t root; // which MDS has root directory __u32 session_timeout; __u32 session_autoclose; uint64_t max_file_size; set data_pools; // file data pools available to clients (via an ioctl). first is the default. int64_t cas_pool; // where CAS objects go int64_t metadata_pool; // where fs metadata objects go /* * in: the set of logical mds #'s that define the cluster. this is the set * of mds's the metadata may be distributed over. * up: map from logical mds #'s to the addrs filling those roles. * failed: subset of @in that are failed. * stopped: set of nodes that have been initialized, but are not active. * * @up + @failed = @in. @in * @stopped = {}. */ uint32_t max_mds; /* The maximum number of active MDSes. Also, the maximum rank. */ set in; // currently defined cluster map inc; // most recent incarnation. set failed, stopped; // which roles are failed or stopped map up; // who is in those roles map mds_info; bool ever_allowed_snaps; //< the cluster has ever allowed snap creation bool explicitly_allowed_snaps; //< the user has explicitly enabled snap creation bool inline_data_enabled; public: CompatSet compat; friend class MDSMonitor; public: MDSMap() : epoch(0), flags(0), last_failure(0), last_failure_osd_epoch(0), tableserver(0), root(0), session_timeout(0), session_autoclose(0), max_file_size(0), cas_pool(-1), metadata_pool(0), max_mds(0), ever_allowed_snaps(false), explicitly_allowed_snaps(false), inline_data_enabled(false) { } bool get_inline_data_enabled() { return inline_data_enabled; } void set_inline_data_enabled(bool enabled) { inline_data_enabled = enabled; } utime_t get_session_timeout() { return utime_t(session_timeout,0); } uint64_t get_max_filesize() { return max_file_size; } int get_flags() const { return flags; } int test_flag(int f) const { return flags & f; } void set_flag(int f) { flags |= f; } void clear_flag(int f) { flags &= ~f; } void set_snaps_allowed() { set_flag(CEPH_MDSMAP_ALLOW_SNAPS); ever_allowed_snaps = true; explicitly_allowed_snaps = true; } bool allows_snaps() { return test_flag(CEPH_MDSMAP_ALLOW_SNAPS); } void clear_snaps_allowed() { clear_flag(CEPH_MDSMAP_ALLOW_SNAPS); } epoch_t get_epoch() const { return epoch; } void inc_epoch() { epoch++; } const utime_t& get_created() const { return created; } void set_created(utime_t ct) { modified = created = ct; } const utime_t& get_modified() const { return modified; } void set_modified(utime_t mt) { modified = mt; } epoch_t get_last_failure() const { return last_failure; } epoch_t get_last_failure_osd_epoch() const { return last_failure_osd_epoch; } unsigned get_max_mds() const { return max_mds; } void set_max_mds(int m) { max_mds = m; } int get_tableserver() const { return tableserver; } int get_root() const { return root; } const set &get_data_pools() const { return data_pools; } int64_t get_first_data_pool() const { return *data_pools.begin(); } int64_t get_cas_pool() const { return cas_pool; } int64_t get_metadata_pool() const { return metadata_pool; } bool is_data_pool(int64_t poolid) const { return data_pools.count(poolid); } const map& get_mds_info() { return mds_info; } const mds_info_t& get_mds_info_gid(uint64_t gid) { assert(mds_info.count(gid)); return mds_info[gid]; } const mds_info_t& get_mds_info(int m) { assert(up.count(m) && mds_info.count(up[m])); return mds_info[up[m]]; } uint64_t find_mds_gid_by_name(const string& s) { for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) { if (p->second.name == s) { return p->first; } } return 0; } // counts unsigned get_num_in_mds() { return in.size(); } unsigned get_num_up_mds() { return up.size(); } int get_num_failed_mds() { return failed.size(); } unsigned get_num_mds(int state) const { unsigned n = 0; for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) if (p->second.state == state) ++n; return n; } // data pools void add_data_pool(int64_t poolid) { data_pools.insert(poolid); } int remove_data_pool(int64_t poolid) { set::iterator p = data_pools.find(poolid); if (p == data_pools.end()) return -ENOENT; data_pools.erase(p); return 0; } // sets void get_mds_set(set& s) { s = in; } void get_up_mds_set(set& s) { for (map::const_iterator p = up.begin(); p != up.end(); ++p) s.insert(p->first); } void get_active_mds_set(set& s) { get_mds_set(s, MDSMap::STATE_ACTIVE); } void get_failed_mds_set(set& s) { s = failed; } int get_failed() { if (!failed.empty()) return *failed.begin(); return -1; } void get_stopped_mds_set(set& s) { s = stopped; } void get_recovery_mds_set(set& s) { s = failed; for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) if (p->second.state >= STATE_REPLAY && p->second.state <= STATE_STOPPING) s.insert(p->second.rank); } void get_clientreplay_or_active_or_stopping_mds_set(set& s) { for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) if (p->second.state >= STATE_CLIENTREPLAY && p->second.state <= STATE_STOPPING) s.insert(p->second.rank); } void get_mds_set(set& s, int state) { for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) if (p->second.state == state) s.insert(p->second.rank); } int get_random_up_mds() { if (up.empty()) return -1; map::iterator p = up.begin(); for (int n = rand() % up.size(); n; n--) ++p; return p->first; } const mds_info_t* find_by_name(const string& name) const { for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) { if (p->second.name == name) return &p->second; } return NULL; } uint64_t find_standby_for(int mds, string& name) { map::const_iterator generic_standby = mds_info.end(); for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) { if ((p->second.state != MDSMap::STATE_STANDBY && p->second.state != MDSMap::STATE_STANDBY_REPLAY) || p->second.laggy() || p->second.rank >= 0) continue; if (p->second.standby_for_rank == mds || (name.length() && p->second.standby_for_name == name)) return p->first; if (p->second.standby_for_rank < 0 && p->second.standby_for_name.length() == 0) generic_standby = p; } if (generic_standby != mds_info.end()) return generic_standby->first; return 0; } uint64_t find_unused_for(int mds, string& name) { for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) { if (p->second.state != MDSMap::STATE_STANDBY || p->second.laggy() || p->second.rank >= 0) continue; if ((p->second.standby_for_rank == MDS_NO_STANDBY_PREF || p->second.standby_for_rank == MDS_MATCHED_ACTIVE || (p->second.standby_for_rank == MDS_STANDBY_ANY && g_conf->mon_force_standby_active))) { return p->first; } } return 0; } uint64_t find_replacement_for(int mds, string& name) { uint64_t standby = find_standby_for(mds, name); if (standby) return standby; else return find_unused_for(mds, name); } void get_health(list >& summary, list > *detail) const; // mds states bool is_down(int m) const { return up.count(m) == 0; } bool is_up(int m) const { return up.count(m); } bool is_in(int m) const { return up.count(m) || failed.count(m); } bool is_out(int m) const { return !is_in(m); } bool is_failed(int m) const { return failed.count(m); } bool is_stopped(int m) const { return stopped.count(m); } bool is_dne(int m) const { return in.count(m) == 0; } bool is_dne_gid(uint64_t gid) const { return mds_info.count(gid) == 0; } int get_state(int m) const { map::const_iterator u = up.find(m); if (u == up.end()) return 0; return get_state_gid(u->second); } int get_state_gid(uint64_t gid) const { map::const_iterator i = mds_info.find(gid); if (i == mds_info.end()) return 0; return i->second.state; } mds_info_t& get_info(int m) { assert(up.count(m)); return mds_info[up[m]]; } mds_info_t& get_info_gid(uint64_t gid) { assert(mds_info.count(gid)); return mds_info[gid]; } bool is_boot(int m) const { return get_state(m) == STATE_BOOT; } bool is_creating(int m) const { return get_state(m) == STATE_CREATING; } bool is_starting(int m) const { return get_state(m) == STATE_STARTING; } bool is_replay(int m) const { return get_state(m) == STATE_REPLAY; } bool is_resolve(int m) const { return get_state(m) == STATE_RESOLVE; } bool is_reconnect(int m) const { return get_state(m) == STATE_RECONNECT; } bool is_rejoin(int m) const { return get_state(m) == STATE_REJOIN; } bool is_clientreplay(int m) const { return get_state(m) == STATE_CLIENTREPLAY; } bool is_active(int m) const { return get_state(m) == STATE_ACTIVE; } bool is_stopping(int m) const { return get_state(m) == STATE_STOPPING; } bool is_active_or_stopping(int m) const { return is_active(m) || is_stopping(m); } bool is_clientreplay_or_active_or_stopping(int m) const { return is_clientreplay(m) || is_active(m) || is_stopping(m); } bool is_followable(int m) const { return (is_resolve(m) || is_replay(m) || is_rejoin(m) || is_clientreplay(m) || is_active(m) || is_stopping(m)); } bool is_laggy_gid(uint64_t gid) const { if (!mds_info.count(gid)) return false; map::const_iterator p = mds_info.find(gid); return p->second.laggy(); } // cluster states bool is_full() const { return in.size() >= max_mds; } bool is_degraded() const { // degraded = some recovery in process. fixes active membership and recovery_set. if (!failed.empty()) return true; for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) if (p->second.state >= STATE_REPLAY && p->second.state <= STATE_CLIENTREPLAY) return true; return false; } bool is_any_failed() { return failed.size(); } bool is_resolving() { return get_num_mds(STATE_RESOLVE) > 0 && get_num_mds(STATE_REPLAY) == 0 && failed.empty(); } bool is_rejoining() { // nodes are rejoining cache state return get_num_mds(STATE_REJOIN) > 0 && get_num_mds(STATE_REPLAY) == 0 && get_num_mds(STATE_RECONNECT) == 0 && get_num_mds(STATE_RESOLVE) == 0 && failed.empty(); } bool is_stopped() { return up.empty(); } // inst bool have_inst(int m) { return up.count(m); } const entity_inst_t get_inst(int m) { assert(up.count(m)); return mds_info[up[m]].get_inst(); } const entity_addr_t get_addr(int m) { assert(up.count(m)); return mds_info[up[m]].addr; } bool get_inst(int m, entity_inst_t& inst) { if (up.count(m)) { inst = get_inst(m); return true; } return false; } int get_rank_gid(uint64_t gid) { if (mds_info.count(gid)) return mds_info[gid].rank; return -1; } int get_inc(int m) { if (up.count(m)) return mds_info[up[m]].inc; return 0; } int get_inc_gid(uint64_t gid) { if (mds_info.count(gid)) return mds_info[gid].inc; return -1; } void encode(bufferlist& bl, uint64_t features) const; void decode(bufferlist::iterator& p); void decode(bufferlist& bl) { bufferlist::iterator p = bl.begin(); decode(p); } void print(ostream& out); void print_summary(Formatter *f, ostream *out); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER_FEATURES(MDSMap::mds_info_t) WRITE_CLASS_ENCODER_FEATURES(MDSMap) inline ostream& operator<<(ostream& out, MDSMap& m) { m.print_summary(NULL, &out); return out; } #endif ceph-0.80.11/src/mds/CInode.cc0000664000175100017510000026534212623076744017733 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include #include #include "CInode.h" #include "CDir.h" #include "CDentry.h" #include "MDS.h" #include "MDCache.h" #include "MDLog.h" #include "Locker.h" #include "Mutation.h" #include "events/EUpdate.h" #include "osdc/Objecter.h" #include "snap.h" #include "LogSegment.h" #include "common/Clock.h" #include "messages/MLock.h" #include "messages/MClientCaps.h" #include "common/config.h" #include "global/global_context.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mdcache->mds->get_nodeid() << ".cache.ino(" << inode.ino << ") " boost::pool<> CInode::pool(sizeof(CInode)); boost::pool<> Capability::pool(sizeof(Capability)); LockType CInode::versionlock_type(CEPH_LOCK_IVERSION); LockType CInode::authlock_type(CEPH_LOCK_IAUTH); LockType CInode::linklock_type(CEPH_LOCK_ILINK); LockType CInode::dirfragtreelock_type(CEPH_LOCK_IDFT); LockType CInode::filelock_type(CEPH_LOCK_IFILE); LockType CInode::xattrlock_type(CEPH_LOCK_IXATTR); LockType CInode::snaplock_type(CEPH_LOCK_ISNAP); LockType CInode::nestlock_type(CEPH_LOCK_INEST); LockType CInode::flocklock_type(CEPH_LOCK_IFLOCK); LockType CInode::policylock_type(CEPH_LOCK_IPOLICY); //int cinode_pins[CINODE_NUM_PINS]; // counts ostream& CInode::print_db_line_prefix(ostream& out) { return out << ceph_clock_now(g_ceph_context) << " mds." << mdcache->mds->get_nodeid() << ".cache.ino(" << inode.ino << ") "; } /* * write caps and lock ids */ struct cinode_lock_info_t cinode_lock_info[] = { { CEPH_LOCK_IFILE, CEPH_CAP_ANY_FILE_WR }, { CEPH_LOCK_IAUTH, CEPH_CAP_AUTH_EXCL }, { CEPH_LOCK_ILINK, CEPH_CAP_LINK_EXCL }, { CEPH_LOCK_IXATTR, CEPH_CAP_XATTR_EXCL }, { CEPH_LOCK_IFLOCK, CEPH_CAP_FLOCK_EXCL } }; int num_cinode_locks = 5; ostream& operator<<(ostream& out, CInode& in) { string path; in.make_path_string_projected(path); out << "[inode " << in.inode.ino; out << " [" << (in.is_multiversion() ? "...":"") << in.first << "," << in.last << "]"; out << " " << path << (in.is_dir() ? "/":""); if (in.is_auth()) { out << " auth"; if (in.is_replicated()) out << in.get_replicas(); } else { pair a = in.authority(); out << " rep@" << a.first; if (a.second != CDIR_AUTH_UNKNOWN) out << "," << a.second; out << "." << in.get_replica_nonce(); } if (in.is_symlink()) out << " symlink='" << in.symlink << "'"; if (in.is_dir() && !in.dirfragtree.empty()) out << " " << in.dirfragtree; out << " v" << in.get_version(); if (in.get_projected_version() > in.get_version()) out << " pv" << in.get_projected_version(); if (in.is_auth_pinned()) { out << " ap=" << in.get_num_auth_pins() << "+" << in.get_num_nested_auth_pins(); #ifdef MDS_AUTHPIN_SET out << "(" << in.auth_pin_set << ")"; #endif } if (in.snaprealm) out << " snaprealm=" << in.snaprealm; if (in.state_test(CInode::STATE_AMBIGUOUSAUTH)) out << " AMBIGAUTH"; if (in.state_test(CInode::STATE_NEEDSRECOVER)) out << " needsrecover"; if (in.state_test(CInode::STATE_RECOVERING)) out << " recovering"; if (in.state_test(CInode::STATE_DIRTYPARENT)) out << " dirtyparent"; if (in.is_freezing_inode()) out << " FREEZING=" << in.auth_pin_freeze_allowance; if (in.is_frozen_inode()) out << " FROZEN"; if (in.is_frozen_auth_pin()) out << " FROZEN_AUTHPIN"; inode_t *pi = in.get_projected_inode(); if (pi->is_truncating()) out << " truncating(" << pi->truncate_from << " to " << pi->truncate_size << ")"; // anchors if (in.is_anchored()) out << " anc"; if (in.get_nested_anchors()) out << " na=" << in.get_nested_anchors(); if (in.inode.is_dir()) { out << " " << in.inode.dirstat; if (g_conf->mds_debug_scatterstat && in.is_projected()) { inode_t *pi = in.get_projected_inode(); out << "->" << pi->dirstat; } } else { out << " s=" << in.inode.size; if (in.inode.nlink != 1) out << " nl=" << in.inode.nlink; } // rstat out << " " << in.inode.rstat; if (!(in.inode.rstat == in.inode.accounted_rstat)) out << "/" << in.inode.accounted_rstat; if (g_conf->mds_debug_scatterstat && in.is_projected()) { inode_t *pi = in.get_projected_inode(); out << "->" << pi->rstat; if (!(pi->rstat == pi->accounted_rstat)) out << "/" << pi->accounted_rstat; } if (!in.client_need_snapflush.empty()) out << " need_snapflush=" << in.client_need_snapflush; // locks if (!in.authlock.is_sync_and_unlocked()) out << " " << in.authlock; if (!in.linklock.is_sync_and_unlocked()) out << " " << in.linklock; if (in.inode.is_dir()) { if (!in.dirfragtreelock.is_sync_and_unlocked()) out << " " << in.dirfragtreelock; if (!in.snaplock.is_sync_and_unlocked()) out << " " << in.snaplock; if (!in.nestlock.is_sync_and_unlocked()) out << " " << in.nestlock; if (!in.policylock.is_sync_and_unlocked()) out << " " << in.policylock; } else { if (!in.flocklock.is_sync_and_unlocked()) out << " " << in.flocklock; } if (!in.filelock.is_sync_and_unlocked()) out << " " << in.filelock; if (!in.xattrlock.is_sync_and_unlocked()) out << " " << in.xattrlock; if (!in.versionlock.is_sync_and_unlocked()) out << " " << in.versionlock; // hack: spit out crap on which clients have caps if (in.inode.client_ranges.size()) out << " cr=" << in.inode.client_ranges; if (!in.get_client_caps().empty()) { out << " caps={"; for (map::iterator it = in.get_client_caps().begin(); it != in.get_client_caps().end(); ++it) { if (it != in.get_client_caps().begin()) out << ","; out << it->first << "=" << ccap_string(it->second->pending()); if (it->second->issued() != it->second->pending()) out << "/" << ccap_string(it->second->issued()); out << "/" << ccap_string(it->second->wanted()) << "@" << it->second->get_last_sent(); } out << "}"; if (in.get_loner() >= 0 || in.get_wanted_loner() >= 0) { out << ",l=" << in.get_loner(); if (in.get_loner() != in.get_wanted_loner()) out << "(" << in.get_wanted_loner() << ")"; } } if (!in.get_mds_caps_wanted().empty()) { out << " mcw={"; for (map::iterator p = in.get_mds_caps_wanted().begin(); p != in.get_mds_caps_wanted().end(); ++p) { if (p != in.get_mds_caps_wanted().begin()) out << ','; out << p->first << '=' << ccap_string(p->second); } out << '}'; } if (in.get_num_ref()) { out << " |"; in.print_pin_set(out); } out << " " << ∈ out << "]"; return out; } void CInode::print(ostream& out) { out << *this; } void CInode::add_need_snapflush(CInode *snapin, snapid_t snapid, client_t client) { dout(10) << "add_need_snapflush client." << client << " snapid " << snapid << " on " << snapin << dendl; if (client_need_snapflush.empty()) { get(CInode::PIN_NEEDSNAPFLUSH); // FIXME: this is non-optimal, as we'll block freezes/migrations for potentially // long periods waiting for clients to flush their snaps. auth_pin(this); // pin head inode... } set& clients = client_need_snapflush[snapid]; if (clients.empty()) snapin->auth_pin(this); // ...and pin snapped/old inode! clients.insert(client); } void CInode::remove_need_snapflush(CInode *snapin, snapid_t snapid, client_t client) { dout(10) << "remove_need_snapflush client." << client << " snapid " << snapid << " on " << snapin << dendl; set& clients = client_need_snapflush[snapid]; clients.erase(client); if (clients.empty()) { client_need_snapflush.erase(snapid); snapin->auth_unpin(this); if (client_need_snapflush.empty()) { put(CInode::PIN_NEEDSNAPFLUSH); auth_unpin(this); } } } void CInode::mark_dirty_rstat() { if (!state_test(STATE_DIRTYRSTAT)) { dout(10) << "mark_dirty_rstat" << dendl; state_set(STATE_DIRTYRSTAT); get(PIN_DIRTYRSTAT); CDentry *dn = get_projected_parent_dn(); CDir *pdir = dn->dir; pdir->dirty_rstat_inodes.push_back(&dirty_rstat_item); mdcache->mds->locker->mark_updated_scatterlock(&pdir->inode->nestlock); } } void CInode::clear_dirty_rstat() { if (state_test(STATE_DIRTYRSTAT)) { dout(10) << "clear_dirty_rstat" << dendl; state_clear(STATE_DIRTYRSTAT); put(PIN_DIRTYRSTAT); dirty_rstat_item.remove_myself(); } } inode_t *CInode::project_inode(map *px) { if (projected_nodes.empty()) { projected_nodes.push_back(new projected_inode_t(new inode_t(inode))); if (px) *px = xattrs; } else { projected_nodes.push_back(new projected_inode_t( new inode_t(*projected_nodes.back()->inode))); if (px) *px = *get_projected_xattrs(); } projected_nodes.back()->xattrs = px; dout(15) << "project_inode " << projected_nodes.back()->inode << dendl; return projected_nodes.back()->inode; } void CInode::pop_and_dirty_projected_inode(LogSegment *ls) { assert(!projected_nodes.empty()); dout(15) << "pop_and_dirty_projected_inode " << projected_nodes.front()->inode << " v" << projected_nodes.front()->inode->version << dendl; int64_t old_pool = inode.layout.fl_pg_pool; mark_dirty(projected_nodes.front()->inode->version, ls); inode = *projected_nodes.front()->inode; if (inode.is_backtrace_updated()) _mark_dirty_parent(ls, old_pool != inode.layout.fl_pg_pool); map *px = projected_nodes.front()->xattrs; if (px) { xattrs = *px; delete px; } if (projected_nodes.front()->snapnode) pop_projected_snaprealm(projected_nodes.front()->snapnode); delete projected_nodes.front()->inode; delete projected_nodes.front(); projected_nodes.pop_front(); } sr_t *CInode::project_snaprealm(snapid_t snapid) { sr_t *cur_srnode = get_projected_srnode(); sr_t *new_srnode; if (cur_srnode) { new_srnode = new sr_t(*cur_srnode); } else { new_srnode = new sr_t(); new_srnode->created = snapid; new_srnode->current_parent_since = snapid; } dout(10) << "project_snaprealm " << new_srnode << dendl; projected_nodes.back()->snapnode = new_srnode; return new_srnode; } /* if newparent != parent, add parent to past_parents if parent DNE, we need to find what the parent actually is and fill that in */ void CInode::project_past_snaprealm_parent(SnapRealm *newparent) { sr_t *new_snap = project_snaprealm(); SnapRealm *oldparent; if (!snaprealm) { oldparent = find_snaprealm(); new_snap->seq = oldparent->get_newest_seq(); } else oldparent = snaprealm->parent; if (newparent != oldparent) { snapid_t oldparentseq = oldparent->get_newest_seq(); if (oldparentseq + 1 > new_snap->current_parent_since) { new_snap->past_parents[oldparentseq].ino = oldparent->inode->ino(); new_snap->past_parents[oldparentseq].first = new_snap->current_parent_since; } new_snap->current_parent_since = MAX(oldparentseq, newparent->get_last_created()) + 1; } } void CInode::pop_projected_snaprealm(sr_t *next_snaprealm) { assert(next_snaprealm); dout(10) << "pop_projected_snaprealm " << next_snaprealm << " seq" << next_snaprealm->seq << dendl; bool invalidate_cached_snaps = false; if (!snaprealm) { open_snaprealm(); } else if (next_snaprealm->past_parents.size() != snaprealm->srnode.past_parents.size()) { invalidate_cached_snaps = true; // update parent pointer assert(snaprealm->open); assert(snaprealm->parent); // had a parent before SnapRealm *new_parent = get_parent_inode()->find_snaprealm(); assert(new_parent); CInode *parenti = new_parent->inode; assert(parenti); assert(parenti->snaprealm); snaprealm->parent = new_parent; snaprealm->add_open_past_parent(new_parent); dout(10) << " realm " << *snaprealm << " past_parents " << snaprealm->srnode.past_parents << " -> " << next_snaprealm->past_parents << dendl; dout(10) << " pinning new parent " << *parenti << dendl; } snaprealm->srnode = *next_snaprealm; delete next_snaprealm; // we should be able to open these up (or have them already be open). bool ok = snaprealm->_open_parents(NULL); assert(ok); if (invalidate_cached_snaps) snaprealm->invalidate_cached_snaps(); if (snaprealm->parent) dout(10) << " realm " << *snaprealm << " parent " << *snaprealm->parent << dendl; } // ====== CInode ======= // dirfrags __u32 CInode::hash_dentry_name(const string &dn) { int which = inode.dir_layout.dl_dir_hash; if (!which) which = CEPH_STR_HASH_LINUX; return ceph_str_hash(which, dn.data(), dn.length()); } frag_t CInode::pick_dirfrag(const string& dn) { if (dirfragtree.empty()) return frag_t(); // avoid the string hash if we can. __u32 h = hash_dentry_name(dn); return dirfragtree[h]; } bool CInode::get_dirfrags_under(frag_t fg, list& ls) { bool all = true; list fglist; dirfragtree.get_leaves_under(fg, fglist); for (list::iterator p = fglist.begin(); p != fglist.end(); ++p) if (dirfrags.count(*p)) ls.push_back(dirfrags[*p]); else all = false; if (all) return all; fragtree_t tmpdft; tmpdft.force_to_leaf(g_ceph_context, fg); for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { tmpdft.force_to_leaf(g_ceph_context, p->first); if (fg.contains(p->first) && !dirfragtree.is_leaf(p->first)) ls.push_back(p->second); } all = true; tmpdft.get_leaves_under(fg, fglist); for (list::iterator p = fglist.begin(); p != fglist.end(); ++p) if (!dirfrags.count(*p)) { all = false; break; } return all; } void CInode::verify_dirfrags() { bool bad = false; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { if (!dirfragtree.is_leaf(p->first)) { dout(0) << "have open dirfrag " << p->first << " but not leaf in " << dirfragtree << ": " << *p->second << dendl; bad = true; } } assert(!bad); } void CInode::force_dirfrags() { bool bad = false; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { if (!dirfragtree.is_leaf(p->first)) { dout(0) << "have open dirfrag " << p->first << " but not leaf in " << dirfragtree << ": " << *p->second << dendl; bad = true; } } if (bad) { list leaves; dirfragtree.get_leaves(leaves); for (list::iterator p = leaves.begin(); p != leaves.end(); ++p) mdcache->get_force_dirfrag(dirfrag_t(ino(),*p)); } verify_dirfrags(); } CDir *CInode::get_approx_dirfrag(frag_t fg) { CDir *dir = get_dirfrag(fg); if (dir) return dir; // find a child? list ls; get_dirfrags_under(fg, ls); if (!ls.empty()) return ls.front(); // try parents? while (fg.bits() > 0) { fg = fg.parent(); dir = get_dirfrag(fg); if (dir) return dir; } return NULL; } void CInode::get_dirfrags(list& ls) { // all dirfrags for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) ls.push_back(p->second); } void CInode::get_nested_dirfrags(list& ls) { // dirfrags in same subtree for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) if (!p->second->is_subtree_root()) ls.push_back(p->second); } void CInode::get_subtree_dirfrags(list& ls) { // dirfrags that are roots of new subtrees for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) if (p->second->is_subtree_root()) ls.push_back(p->second); } CDir *CInode::get_or_open_dirfrag(MDCache *mdcache, frag_t fg) { assert(is_dir()); // have it? CDir *dir = get_dirfrag(fg); if (!dir) { // create it. assert(is_auth()); dir = new CDir(this, fg, mdcache, true); add_dirfrag(dir); } return dir; } CDir *CInode::add_dirfrag(CDir *dir) { assert(dirfrags.count(dir->dirfrag().frag) == 0); dirfrags[dir->dirfrag().frag] = dir; if (stickydir_ref > 0) { dir->state_set(CDir::STATE_STICKY); dir->get(CDir::PIN_STICKY); } return dir; } void CInode::close_dirfrag(frag_t fg) { dout(14) << "close_dirfrag " << fg << dendl; assert(dirfrags.count(fg)); CDir *dir = dirfrags[fg]; dir->remove_null_dentries(); // clear dirty flag if (dir->is_dirty()) dir->mark_clean(); if (stickydir_ref > 0) { dir->state_clear(CDir::STATE_STICKY); dir->put(CDir::PIN_STICKY); } // dump any remaining dentries, for debugging purposes for (CDir::map_t::iterator p = dir->items.begin(); p != dir->items.end(); ++p) dout(14) << "close_dirfrag LEFTOVER dn " << *p->second << dendl; assert(dir->get_num_ref() == 0); delete dir; dirfrags.erase(fg); } void CInode::close_dirfrags() { while (!dirfrags.empty()) close_dirfrag(dirfrags.begin()->first); } bool CInode::has_subtree_root_dirfrag(int auth) { for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) if (p->second->is_subtree_root() && (auth == -1 || p->second->dir_auth.first == auth)) return true; return false; } bool CInode::has_subtree_or_exporting_dirfrag() { for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) if (p->second->is_subtree_root() || p->second->state_test(CDir::STATE_EXPORTING)) return true; return false; } void CInode::get_stickydirs() { if (stickydir_ref == 0) { get(PIN_STICKYDIRS); for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { p->second->state_set(CDir::STATE_STICKY); p->second->get(CDir::PIN_STICKY); } } stickydir_ref++; } void CInode::put_stickydirs() { assert(stickydir_ref > 0); stickydir_ref--; if (stickydir_ref == 0) { put(PIN_STICKYDIRS); for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { p->second->state_clear(CDir::STATE_STICKY); p->second->put(CDir::PIN_STICKY); } } } // pins void CInode::first_get() { // pin my dentry? if (parent) parent->get(CDentry::PIN_INODEPIN); } void CInode::last_put() { // unpin my dentry? if (parent) parent->put(CDentry::PIN_INODEPIN); } void CInode::_put() { if (get_num_ref() == (int)is_dirty() + (int)is_dirty_parent()) mdcache->maybe_eval_stray(this, true); } void CInode::add_remote_parent(CDentry *p) { if (remote_parents.empty()) get(PIN_REMOTEPARENT); remote_parents.insert(p); } void CInode::remove_remote_parent(CDentry *p) { remote_parents.erase(p); if (remote_parents.empty()) put(PIN_REMOTEPARENT); } CDir *CInode::get_parent_dir() { if (parent) return parent->dir; return NULL; } CDir *CInode::get_projected_parent_dir() { CDentry *p = get_projected_parent_dn(); if (p) return p->dir; return NULL; } CInode *CInode::get_parent_inode() { if (parent) return parent->dir->inode; return NULL; } bool CInode::is_projected_ancestor_of(CInode *other) { while (other) { if (other == this) return true; if (!other->get_projected_parent_dn()) break; other = other->get_projected_parent_dn()->get_dir()->get_inode(); } return false; } void CInode::make_path_string(string& s, bool force, CDentry *use_parent) { if (!force) use_parent = parent; if (use_parent) { use_parent->make_path_string(s); } else if (is_root()) { s = ""; // root } else if (is_mdsdir()) { char t[40]; uint64_t eino(ino()); eino -= MDS_INO_MDSDIR_OFFSET; snprintf(t, sizeof(t), "~mds%" PRId64, eino); s = t; } else { char n[40]; uint64_t eino(ino()); snprintf(n, sizeof(n), "#%" PRIx64, eino); s += n; } } void CInode::make_path_string_projected(string& s) { make_path_string(s); if (!projected_parent.empty()) { string q; q.swap(s); s = "{" + q; for (list::iterator p = projected_parent.begin(); p != projected_parent.end(); ++p) { string q; make_path_string(q, true, *p); s += " "; s += q; } s += "}"; } } void CInode::make_path(filepath& fp) { if (parent) parent->make_path(fp); else fp = filepath(ino()); } void CInode::make_anchor_trace(vector& trace) { if (get_projected_parent_dn()) get_projected_parent_dn()->make_anchor_trace(trace, this); else assert(is_base()); } void CInode::name_stray_dentry(string& dname) { char s[20]; snprintf(s, sizeof(s), "%llx", (unsigned long long)inode.ino.val); dname = s; } version_t CInode::pre_dirty() { version_t pv; if (parent || !projected_parent.empty()) { pv = get_projected_parent_dn()->pre_dirty(get_projected_version()); dout(10) << "pre_dirty " << pv << " (current v " << inode.version << ")" << dendl; } else { assert(is_base()); pv = get_projected_version() + 1; } // force update backtrace for old format inode (see inode_t::decode) if (inode.backtrace_version == 0 && !projected_nodes.empty()) { inode_t *pi = projected_nodes.back()->inode; if (pi->backtrace_version == 0) pi->update_backtrace(pv); } return pv; } void CInode::_mark_dirty(LogSegment *ls) { if (!state_test(STATE_DIRTY)) { state_set(STATE_DIRTY); get(PIN_DIRTY); assert(ls); } // move myself to this segment's dirty list if (ls) ls->dirty_inodes.push_back(&item_dirty); } void CInode::mark_dirty(version_t pv, LogSegment *ls) { dout(10) << "mark_dirty " << *this << dendl; /* NOTE: I may already be dirty, but this fn _still_ needs to be called so that the directory is (perhaps newly) dirtied, and so that parent_dir_version is updated below. */ // only auth can get dirty. "dirty" async data in replicas is relative to // filelock state, not the dirty flag. assert(is_auth()); // touch my private version assert(inode.version < pv); inode.version = pv; _mark_dirty(ls); // mark dentry too if (parent) parent->mark_dirty(pv, ls); } void CInode::mark_clean() { dout(10) << " mark_clean " << *this << dendl; if (state_test(STATE_DIRTY)) { state_clear(STATE_DIRTY); put(PIN_DIRTY); // remove myself from ls dirty list item_dirty.remove_myself(); } } // -------------- // per-inode storage // (currently for root inode only) struct C_Inode_Stored : public Context { CInode *in; version_t version; Context *fin; C_Inode_Stored(CInode *i, version_t v, Context *f) : in(i), version(v), fin(f) {} void finish(int r) { assert(r == 0); in->_stored(version, fin); } }; object_t CInode::get_object_name(inodeno_t ino, frag_t fg, const char *suffix) { char n[60]; snprintf(n, sizeof(n), "%llx.%08llx%s", (long long unsigned)ino, (long long unsigned)fg, suffix ? suffix : ""); return object_t(n); } void CInode::store(Context *fin) { dout(10) << "store " << get_version() << dendl; assert(is_base()); // encode bufferlist bl; string magic = CEPH_FS_ONDISK_MAGIC; ::encode(magic, bl); encode_store(bl); // write it. SnapContext snapc; ObjectOperation m; m.write_full(bl); object_t oid = CInode::get_object_name(ino(), frag_t(), ".inode"); object_locator_t oloc(mdcache->mds->mdsmap->get_metadata_pool()); mdcache->mds->objecter->mutate(oid, oloc, m, snapc, ceph_clock_now(g_ceph_context), 0, NULL, new C_Inode_Stored(this, get_version(), fin) ); } void CInode::_stored(version_t v, Context *fin) { dout(10) << "_stored " << v << " " << *this << dendl; if (v == get_projected_version()) mark_clean(); fin->complete(0); } struct C_Inode_Fetched : public Context { CInode *in; bufferlist bl, bl2; Context *fin; C_Inode_Fetched(CInode *i, Context *f) : in(i), fin(f) {} void finish(int r) { in->_fetched(bl, bl2, fin); } }; void CInode::fetch(Context *fin) { dout(10) << "fetch" << dendl; C_Inode_Fetched *c = new C_Inode_Fetched(this, fin); C_GatherBuilder gather(g_ceph_context, c); object_t oid = CInode::get_object_name(ino(), frag_t(), ""); object_locator_t oloc(mdcache->mds->mdsmap->get_metadata_pool()); ObjectOperation rd; rd.getxattr("inode", &c->bl, NULL); mdcache->mds->objecter->read(oid, oloc, rd, CEPH_NOSNAP, (bufferlist*)NULL, 0, gather.new_sub()); // read from separate object too object_t oid2 = CInode::get_object_name(ino(), frag_t(), ".inode"); mdcache->mds->objecter->read(oid2, oloc, 0, 0, CEPH_NOSNAP, &c->bl2, 0, gather.new_sub()); gather.activate(); } void CInode::_fetched(bufferlist& bl, bufferlist& bl2, Context *fin) { dout(10) << "_fetched got " << bl.length() << " and " << bl2.length() << dendl; bufferlist::iterator p; if (bl2.length()) p = bl2.begin(); else p = bl.begin(); string magic; ::decode(magic, p); dout(10) << " magic is '" << magic << "' (expecting '" << CEPH_FS_ONDISK_MAGIC << "')" << dendl; if (magic != CEPH_FS_ONDISK_MAGIC) { dout(0) << "on disk magic '" << magic << "' != my magic '" << CEPH_FS_ONDISK_MAGIC << "'" << dendl; fin->complete(-EINVAL); } else { decode_store(p); dout(10) << "_fetched " << *this << dendl; fin->complete(0); } } void CInode::build_backtrace(int64_t pool, inode_backtrace_t& bt) { bt.ino = inode.ino; bt.ancestors.clear(); bt.pool = pool; CInode *in = this; CDentry *pdn = get_parent_dn(); while (pdn) { CInode *diri = pdn->get_dir()->get_inode(); bt.ancestors.push_back(inode_backpointer_t(diri->ino(), pdn->name, in->inode.version)); in = diri; pdn = in->get_parent_dn(); } vector::iterator i = inode.old_pools.begin(); while(i != inode.old_pools.end()) { // don't add our own pool id to old_pools to avoid looping (e.g. setlayout 0, 1, 0) if (*i == pool) { ++i; continue; } bt.old_pools.insert(*i); ++i; } } struct C_Inode_StoredBacktrace : public Context { CInode *in; version_t version; Context *fin; C_Inode_StoredBacktrace(CInode *i, version_t v, Context *f) : in(i), version(v), fin(f) {} void finish(int r) { assert(r == 0); in->_stored_backtrace(version, fin); } }; void CInode::store_backtrace(Context *fin) { dout(10) << "store_backtrace on " << *this << dendl; assert(is_dirty_parent()); auth_pin(this); int64_t pool; if (is_dir()) pool = mdcache->mds->mdsmap->get_metadata_pool(); else pool = inode.layout.fl_pg_pool; inode_backtrace_t bt; build_backtrace(pool, bt); bufferlist bl; ::encode(bt, bl); ObjectOperation op; op.create(false); op.setxattr("parent", bl); SnapContext snapc; object_t oid = get_object_name(ino(), frag_t(), ""); object_locator_t oloc(pool); Context *fin2 = new C_Inode_StoredBacktrace(this, inode.backtrace_version, fin); if (!state_test(STATE_DIRTYPOOL) || inode.old_pools.empty()) { mdcache->mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), 0, NULL, fin2); return; } C_GatherBuilder gather(g_ceph_context, fin2); mdcache->mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); set old_pools; for (vector::iterator p = inode.old_pools.begin(); p != inode.old_pools.end(); ++p) { if (*p == pool || old_pools.count(*p)) continue; ObjectOperation op; op.create(false); op.setxattr("parent", bl); object_locator_t oloc(*p); mdcache->mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), 0, NULL, gather.new_sub()); old_pools.insert(*p); } gather.activate(); } void CInode::_stored_backtrace(version_t v, Context *fin) { dout(10) << "_stored_backtrace" << dendl; auth_unpin(this); if (v == inode.backtrace_version) clear_dirty_parent(); if (fin) fin->complete(0); } void CInode::_mark_dirty_parent(LogSegment *ls, bool dirty_pool) { if (!state_test(STATE_DIRTYPARENT)) { dout(10) << "mark_dirty_parent" << dendl; state_set(STATE_DIRTYPARENT); get(PIN_DIRTYPARENT); assert(ls); } if (dirty_pool) state_set(STATE_DIRTYPOOL); if (ls) ls->dirty_parent_inodes.push_back(&item_dirty_parent); } void CInode::clear_dirty_parent() { if (state_test(STATE_DIRTYPARENT)) { dout(10) << "clear_dirty_parent" << dendl; state_clear(STATE_DIRTYPARENT); state_clear(STATE_DIRTYPOOL); put(PIN_DIRTYPARENT); item_dirty_parent.remove_myself(); } } // ------------------ // parent dir void CInode::encode_store(bufferlist& bl) { ENCODE_START(4, 4, bl); ::encode(inode, bl); if (is_symlink()) ::encode(symlink, bl); ::encode(dirfragtree, bl); ::encode(xattrs, bl); bufferlist snapbl; encode_snap_blob(snapbl); ::encode(snapbl, bl); ::encode(old_inodes, bl); ENCODE_FINISH(bl); } void CInode::decode_store(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 4, 4, bl); ::decode(inode, bl); if (is_symlink()) ::decode(symlink, bl); ::decode(dirfragtree, bl); ::decode(xattrs, bl); bufferlist snapbl; ::decode(snapbl, bl); decode_snap_blob(snapbl); ::decode(old_inodes, bl); if (struct_v == 2 && inode.is_dir()) { bool default_layout_exists; ::decode(default_layout_exists, bl); if (default_layout_exists) { ::decode(struct_v, bl); // this was a default_file_layout ::decode(inode.layout, bl); // but we only care about the layout portion } } DECODE_FINISH(bl); } // ------------------ // locking void CInode::set_object_info(MDSCacheObjectInfo &info) { info.ino = ino(); info.snapid = last; } void CInode::encode_lock_state(int type, bufferlist& bl) { ::encode(first, bl); switch (type) { case CEPH_LOCK_IAUTH: ::encode(inode.version, bl); ::encode(inode.ctime, bl); ::encode(inode.mode, bl); ::encode(inode.uid, bl); ::encode(inode.gid, bl); break; case CEPH_LOCK_ILINK: ::encode(inode.version, bl); ::encode(inode.ctime, bl); ::encode(inode.nlink, bl); ::encode(inode.anchored, bl); break; case CEPH_LOCK_IDFT: if (is_auth()) { ::encode(inode.version, bl); } else { // treat flushing as dirty when rejoining cache bool dirty = dirfragtreelock.is_dirty_or_flushing(); ::encode(dirty, bl); } { // encode the raw tree ::encode(dirfragtree, bl); // also specify which frags are mine set myfrags; list dfls; get_dirfrags(dfls); for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) if ((*p)->is_auth()) { frag_t fg = (*p)->get_frag(); myfrags.insert(fg); } ::encode(myfrags, bl); } break; case CEPH_LOCK_IFILE: if (is_auth()) { ::encode(inode.version, bl); ::encode(inode.mtime, bl); ::encode(inode.atime, bl); ::encode(inode.time_warp_seq, bl); if (!is_dir()) { ::encode(inode.layout, bl); ::encode(inode.size, bl); ::encode(inode.truncate_seq, bl); ::encode(inode.truncate_size, bl); ::encode(inode.client_ranges, bl); ::encode(inode.inline_data, bl); ::encode(inode.inline_version, bl); } } else { // treat flushing as dirty when rejoining cache bool dirty = filelock.is_dirty_or_flushing(); ::encode(dirty, bl); } { dout(15) << "encode_lock_state inode.dirstat is " << inode.dirstat << dendl; ::encode(inode.dirstat, bl); // only meaningful if i am auth. bufferlist tmp; __u32 n = 0; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { frag_t fg = p->first; CDir *dir = p->second; if (is_auth() || dir->is_auth()) { fnode_t *pf = dir->get_projected_fnode(); dout(15) << fg << " " << *dir << dendl; dout(20) << fg << " fragstat " << pf->fragstat << dendl; dout(20) << fg << " accounted_fragstat " << pf->accounted_fragstat << dendl; ::encode(fg, tmp); ::encode(dir->first, tmp); ::encode(pf->fragstat, tmp); ::encode(pf->accounted_fragstat, tmp); n++; } } ::encode(n, bl); bl.claim_append(tmp); } break; case CEPH_LOCK_INEST: if (is_auth()) { ::encode(inode.version, bl); } else { // treat flushing as dirty when rejoining cache bool dirty = nestlock.is_dirty_or_flushing(); ::encode(dirty, bl); } { dout(15) << "encode_lock_state inode.rstat is " << inode.rstat << dendl; ::encode(inode.rstat, bl); // only meaningful if i am auth. bufferlist tmp; __u32 n = 0; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { frag_t fg = p->first; CDir *dir = p->second; if (is_auth() || dir->is_auth()) { fnode_t *pf = dir->get_projected_fnode(); dout(10) << fg << " " << *dir << dendl; dout(10) << fg << " " << pf->rstat << dendl; dout(10) << fg << " " << pf->rstat << dendl; dout(10) << fg << " " << dir->dirty_old_rstat << dendl; ::encode(fg, tmp); ::encode(dir->first, tmp); ::encode(pf->rstat, tmp); ::encode(pf->accounted_rstat, tmp); ::encode(dir->dirty_old_rstat, tmp); n++; } } ::encode(n, bl); bl.claim_append(tmp); } break; case CEPH_LOCK_IXATTR: ::encode(inode.version, bl); ::encode(xattrs, bl); break; case CEPH_LOCK_ISNAP: ::encode(inode.version, bl); encode_snap(bl); break; case CEPH_LOCK_IFLOCK: ::encode(inode.version, bl); ::encode(fcntl_locks, bl); ::encode(flock_locks, bl); break; case CEPH_LOCK_IPOLICY: if (inode.is_dir()) { ::encode(inode.version, bl); ::encode(inode.layout, bl); } break; default: assert(0); } } /* for more info on scatterlocks, see comments by Locker::scatter_writebehind */ void CInode::decode_lock_state(int type, bufferlist& bl) { bufferlist::iterator p = bl.begin(); utime_t tm; snapid_t newfirst; ::decode(newfirst, p); if (!is_auth() && newfirst != first) { dout(10) << "decode_lock_state first " << first << " -> " << newfirst << dendl; assert(newfirst > first); if (!is_multiversion() && parent) { assert(parent->first == first); parent->first = newfirst; } first = newfirst; } switch (type) { case CEPH_LOCK_IAUTH: ::decode(inode.version, p); ::decode(tm, p); if (inode.ctime < tm) inode.ctime = tm; ::decode(inode.mode, p); ::decode(inode.uid, p); ::decode(inode.gid, p); break; case CEPH_LOCK_ILINK: ::decode(inode.version, p); ::decode(tm, p); if (inode.ctime < tm) inode.ctime = tm; ::decode(inode.nlink, p); { bool was_anchored = inode.anchored; ::decode(inode.anchored, p); if (parent && was_anchored != inode.anchored) parent->adjust_nested_anchors((int)inode.anchored - (int)was_anchored); } break; case CEPH_LOCK_IDFT: if (is_auth()) { bool replica_dirty; ::decode(replica_dirty, p); if (replica_dirty) { dout(10) << "decode_lock_state setting dftlock dirty flag" << dendl; dirfragtreelock.mark_dirty(); // ok bc we're auth and caller will handle } } else { ::decode(inode.version, p); } { fragtree_t temp; ::decode(temp, p); set authfrags; ::decode(authfrags, p); if (is_auth()) { // auth. believe replica's auth frags only. for (set::iterator p = authfrags.begin(); p != authfrags.end(); ++p) if (!dirfragtree.is_leaf(*p)) { dout(10) << " forcing frag " << *p << " to leaf (split|merge)" << dendl; dirfragtree.force_to_leaf(g_ceph_context, *p); dirfragtreelock.mark_dirty(); // ok bc we're auth and caller will handle } } else { // replica. take the new tree, BUT make sure any open // dirfrags remain leaves (they may have split _after_ this // dft was scattered, or we may still be be waiting on the // notify from the auth) dirfragtree.swap(temp); for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { if (!dirfragtree.is_leaf(p->first)) { dout(10) << " forcing open dirfrag " << p->first << " to leaf (racing with split|merge)" << dendl; dirfragtree.force_to_leaf(g_ceph_context, p->first); } if (p->second->is_auth()) p->second->state_clear(CDir::STATE_DIRTYDFT); } } if (g_conf->mds_debug_frag) verify_dirfrags(); } break; case CEPH_LOCK_IFILE: if (!is_auth()) { ::decode(inode.version, p); ::decode(inode.mtime, p); ::decode(inode.atime, p); ::decode(inode.time_warp_seq, p); if (!is_dir()) { ::decode(inode.layout, p); ::decode(inode.size, p); ::decode(inode.truncate_seq, p); ::decode(inode.truncate_size, p); ::decode(inode.client_ranges, p); ::decode(inode.inline_data, p); ::decode(inode.inline_version, p); } } else { bool replica_dirty; ::decode(replica_dirty, p); if (replica_dirty) { dout(10) << "decode_lock_state setting filelock dirty flag" << dendl; filelock.mark_dirty(); // ok bc we're auth and caller will handle } } { frag_info_t dirstat; ::decode(dirstat, p); if (!is_auth()) { dout(10) << " taking inode dirstat " << dirstat << " for " << *this << dendl; inode.dirstat = dirstat; // take inode summation if replica } __u32 n; ::decode(n, p); dout(10) << " ...got " << n << " fragstats on " << *this << dendl; while (n--) { frag_t fg; snapid_t fgfirst; frag_info_t fragstat; frag_info_t accounted_fragstat; ::decode(fg, p); ::decode(fgfirst, p); ::decode(fragstat, p); ::decode(accounted_fragstat, p); dout(10) << fg << " [" << fgfirst << ",head] " << dendl; dout(10) << fg << " fragstat " << fragstat << dendl; dout(20) << fg << " accounted_fragstat " << accounted_fragstat << dendl; CDir *dir = get_dirfrag(fg); if (is_auth()) { assert(dir); // i am auth; i had better have this dir open dout(10) << fg << " first " << dir->first << " -> " << fgfirst << " on " << *dir << dendl; dir->first = fgfirst; dir->fnode.fragstat = fragstat; dir->fnode.accounted_fragstat = accounted_fragstat; dir->first = fgfirst; if (!(fragstat == accounted_fragstat)) { dout(10) << fg << " setting filelock updated flag" << dendl; filelock.mark_dirty(); // ok bc we're auth and caller will handle } } else { if (dir && dir->is_auth()) { dout(10) << fg << " first " << dir->first << " -> " << fgfirst << " on " << *dir << dendl; dir->first = fgfirst; fnode_t *pf = dir->get_projected_fnode(); finish_scatter_update(&filelock, dir, inode.dirstat.version, pf->accounted_fragstat.version); } } } } break; case CEPH_LOCK_INEST: if (is_auth()) { bool replica_dirty; ::decode(replica_dirty, p); if (replica_dirty) { dout(10) << "decode_lock_state setting nestlock dirty flag" << dendl; nestlock.mark_dirty(); // ok bc we're auth and caller will handle } } else { ::decode(inode.version, p); } { nest_info_t rstat; ::decode(rstat, p); if (!is_auth()) { dout(10) << " taking inode rstat " << rstat << " for " << *this << dendl; inode.rstat = rstat; // take inode summation if replica } __u32 n; ::decode(n, p); while (n--) { frag_t fg; snapid_t fgfirst; nest_info_t rstat; nest_info_t accounted_rstat; map dirty_old_rstat; ::decode(fg, p); ::decode(fgfirst, p); ::decode(rstat, p); ::decode(accounted_rstat, p); ::decode(dirty_old_rstat, p); dout(10) << fg << " [" << fgfirst << ",head]" << dendl; dout(10) << fg << " rstat " << rstat << dendl; dout(10) << fg << " accounted_rstat " << accounted_rstat << dendl; dout(10) << fg << " dirty_old_rstat " << dirty_old_rstat << dendl; CDir *dir = get_dirfrag(fg); if (is_auth()) { assert(dir); // i am auth; i had better have this dir open dout(10) << fg << " first " << dir->first << " -> " << fgfirst << " on " << *dir << dendl; dir->first = fgfirst; dir->fnode.rstat = rstat; dir->fnode.accounted_rstat = accounted_rstat; dir->dirty_old_rstat.swap(dirty_old_rstat); if (!(rstat == accounted_rstat) || !dir->dirty_old_rstat.empty()) { dout(10) << fg << " setting nestlock updated flag" << dendl; nestlock.mark_dirty(); // ok bc we're auth and caller will handle } } else { if (dir && dir->is_auth()) { dout(10) << fg << " first " << dir->first << " -> " << fgfirst << " on " << *dir << dendl; dir->first = fgfirst; fnode_t *pf = dir->get_projected_fnode(); finish_scatter_update(&nestlock, dir, inode.rstat.version, pf->accounted_rstat.version); } } } } break; case CEPH_LOCK_IXATTR: ::decode(inode.version, p); ::decode(xattrs, p); break; case CEPH_LOCK_ISNAP: { ::decode(inode.version, p); snapid_t seq = 0; if (snaprealm) seq = snaprealm->srnode.seq; decode_snap(p); if (snaprealm && snaprealm->srnode.seq != seq) mdcache->do_realm_invalidate_and_update_notify(this, seq ? CEPH_SNAP_OP_UPDATE:CEPH_SNAP_OP_SPLIT); } break; case CEPH_LOCK_IFLOCK: ::decode(inode.version, p); ::decode(fcntl_locks, p); ::decode(flock_locks, p); break; case CEPH_LOCK_IPOLICY: if (inode.is_dir()) { ::decode(inode.version, p); ::decode(inode.layout, p); } break; default: assert(0); } } bool CInode::is_dirty_scattered() { return filelock.is_dirty_or_flushing() || nestlock.is_dirty_or_flushing() || dirfragtreelock.is_dirty_or_flushing(); } void CInode::clear_scatter_dirty() { filelock.remove_dirty(); nestlock.remove_dirty(); dirfragtreelock.remove_dirty(); } void CInode::clear_dirty_scattered(int type) { dout(10) << "clear_dirty_scattered " << type << " on " << *this << dendl; switch (type) { case CEPH_LOCK_IFILE: item_dirty_dirfrag_dir.remove_myself(); break; case CEPH_LOCK_INEST: item_dirty_dirfrag_nest.remove_myself(); break; case CEPH_LOCK_IDFT: item_dirty_dirfrag_dirfragtree.remove_myself(); break; default: assert(0); } } /* * when we initially scatter a lock, we need to check if any of the dirfrags * have out of date accounted_rstat/fragstat. if so, mark the lock stale. */ /* for more info on scatterlocks, see comments by Locker::scatter_writebehind */ void CInode::start_scatter(ScatterLock *lock) { dout(10) << "start_scatter " << *lock << " on " << *this << dendl; assert(is_auth()); inode_t *pi = get_projected_inode(); for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { frag_t fg = p->first; CDir *dir = p->second; fnode_t *pf = dir->get_projected_fnode(); dout(20) << fg << " " << *dir << dendl; if (!dir->is_auth()) continue; switch (lock->get_type()) { case CEPH_LOCK_IFILE: finish_scatter_update(lock, dir, pi->dirstat.version, pf->accounted_fragstat.version); break; case CEPH_LOCK_INEST: finish_scatter_update(lock, dir, pi->rstat.version, pf->accounted_rstat.version); break; case CEPH_LOCK_IDFT: dir->state_clear(CDir::STATE_DIRTYDFT); break; } } } struct C_Inode_FragUpdate : public Context { CInode *in; CDir *dir; MutationRef mut; C_Inode_FragUpdate(CInode *i, CDir *d, MutationRef& m) : in(i), dir(d), mut(m) {} void finish(int r) { in->_finish_frag_update(dir, mut); } }; void CInode::finish_scatter_update(ScatterLock *lock, CDir *dir, version_t inode_version, version_t dir_accounted_version) { frag_t fg = dir->get_frag(); assert(dir->is_auth()); if (dir->is_frozen()) { dout(10) << "finish_scatter_update " << fg << " frozen, marking " << *lock << " stale " << *dir << dendl; } else if (dir->get_version() == 0) { dout(10) << "finish_scatter_update " << fg << " not loaded, marking " << *lock << " stale " << *dir << dendl; } else { if (dir_accounted_version != inode_version) { dout(10) << "finish_scatter_update " << fg << " journaling accounted scatterstat update v" << inode_version << dendl; MDLog *mdlog = mdcache->mds->mdlog; MutationRef mut(new MutationImpl); mut->ls = mdlog->get_current_segment(); inode_t *pi = get_projected_inode(); fnode_t *pf = dir->project_fnode(); pf->version = dir->pre_dirty(); const char *ename = 0; switch (lock->get_type()) { case CEPH_LOCK_IFILE: pf->fragstat.version = pi->dirstat.version; pf->accounted_fragstat = pf->fragstat; ename = "lock ifile accounted scatter stat update"; break; case CEPH_LOCK_INEST: pf->rstat.version = pi->rstat.version; pf->accounted_rstat = pf->rstat; ename = "lock inest accounted scatter stat update"; break; default: assert(0); } mut->add_projected_fnode(dir); EUpdate *le = new EUpdate(mdlog, ename); mdlog->start_entry(le); le->metablob.add_dir_context(dir); le->metablob.add_dir(dir, true); assert(!dir->is_frozen()); mut->auth_pin(dir); mdlog->submit_entry(le, new C_Inode_FragUpdate(this, dir, mut)); } else { dout(10) << "finish_scatter_update " << fg << " accounted " << *lock << " scatter stat unchanged at v" << dir_accounted_version << dendl; } } } void CInode::_finish_frag_update(CDir *dir, MutationRef& mut) { dout(10) << "_finish_frag_update on " << *dir << dendl; mut->apply(); mut->cleanup(); } /* * when we gather a lock, we need to assimilate dirfrag changes into the inode * state. it's possible we can't update the dirfrag accounted_rstat/fragstat * because the frag is auth and frozen, or that the replica couldn't for the same * reason. hopefully it will get updated the next time the lock cycles. * * we have two dimensions of behavior: * - we may be (auth and !frozen), and able to update, or not. * - the frag may be stale, or not. * * if the frag is non-stale, we want to assimilate the diff into the * inode, regardless of whether it's auth or updateable. * * if we update the frag, we want to set accounted_fragstat = frag, * both if we took the diff or it was stale and we are making it * un-stale. */ /* for more info on scatterlocks, see comments by Locker::scatter_writebehind */ void CInode::finish_scatter_gather_update(int type) { LogClient &clog = mdcache->mds->clog; dout(10) << "finish_scatter_gather_update " << type << " on " << *this << dendl; assert(is_auth()); switch (type) { case CEPH_LOCK_IFILE: { // adjust summation assert(is_auth()); inode_t *pi = get_projected_inode(); bool touched_mtime = false; dout(20) << " orig dirstat " << pi->dirstat << dendl; pi->dirstat.version++; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { frag_t fg = p->first; CDir *dir = p->second; dout(20) << fg << " " << *dir << dendl; bool update = dir->is_auth() && dir->get_version() != 0 && !dir->is_frozen(); fnode_t *pf = dir->get_projected_fnode(); if (update) pf = dir->project_fnode(); if (pf->accounted_fragstat.version == pi->dirstat.version - 1) { dout(20) << fg << " fragstat " << pf->fragstat << dendl; dout(20) << fg << " accounted_fragstat " << pf->accounted_fragstat << dendl; pi->dirstat.add_delta(pf->fragstat, pf->accounted_fragstat, touched_mtime); } else { dout(20) << fg << " skipping STALE accounted_fragstat " << pf->accounted_fragstat << dendl; } if (pf->fragstat.nfiles < 0 || pf->fragstat.nsubdirs < 0) { clog.error() << "bad/negative dir size on " << dir->dirfrag() << " " << pf->fragstat << "\n"; if (pf->fragstat.nfiles < 0) pf->fragstat.nfiles = 0; if (pf->fragstat.nsubdirs < 0) pf->fragstat.nsubdirs = 0; assert(!"bad/negative frag size" == g_conf->mds_verify_scatter); } if (update) { pf->accounted_fragstat = pf->fragstat; pf->fragstat.version = pf->accounted_fragstat.version = pi->dirstat.version; dout(10) << fg << " updated accounted_fragstat " << pf->fragstat << " on " << *dir << dendl; } if (fg == frag_t()) { // i.e., we are the only frag if (pi->dirstat.size() != pf->fragstat.size()) { clog.error() << "unmatched fragstat size on single " << "dirfrag " << dir->dirfrag() << ", inode has " << pi->dirstat << ", dirfrag has " << pf->fragstat << "\n"; // trust the dirfrag for now version_t v = pi->dirstat.version; pi->dirstat = pf->fragstat; pi->dirstat.version = v; assert(!"unmatched fragstat size" == g_conf->mds_verify_scatter); } } } if (touched_mtime) pi->mtime = pi->ctime = pi->dirstat.mtime; dout(20) << " final dirstat " << pi->dirstat << dendl; if (pi->dirstat.nfiles < 0 || pi->dirstat.nsubdirs < 0) { clog.error() << "bad/negative dir size on " << ino() << ", inode has " << pi->dirstat << "\n"; if (pi->dirstat.nfiles < 0) pi->dirstat.nfiles = 0; if (pi->dirstat.nsubdirs < 0) pi->dirstat.nsubdirs = 0; assert(!"bad/negative dir size" == g_conf->mds_verify_scatter); } } break; case CEPH_LOCK_INEST: { // adjust summation assert(is_auth()); inode_t *pi = get_projected_inode(); dout(20) << " orig rstat " << pi->rstat << dendl; pi->rstat.version++; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { frag_t fg = p->first; CDir *dir = p->second; dout(20) << fg << " " << *dir << dendl; bool update = dir->is_auth() && dir->get_version() != 0 && !dir->is_frozen(); fnode_t *pf = dir->get_projected_fnode(); if (update) pf = dir->project_fnode(); if (pf->accounted_rstat.version == pi->rstat.version-1) { // only pull this frag's dirty rstat inodes into the frag if // the frag is non-stale and updateable. if it's stale, // that info will just get thrown out! if (update) dir->assimilate_dirty_rstat_inodes(); dout(20) << fg << " rstat " << pf->rstat << dendl; dout(20) << fg << " accounted_rstat " << pf->accounted_rstat << dendl; dout(20) << fg << " dirty_old_rstat " << dir->dirty_old_rstat << dendl; mdcache->project_rstat_frag_to_inode(pf->rstat, pf->accounted_rstat, dir->first, CEPH_NOSNAP, this, true); for (map::iterator q = dir->dirty_old_rstat.begin(); q != dir->dirty_old_rstat.end(); ++q) mdcache->project_rstat_frag_to_inode(q->second.rstat, q->second.accounted_rstat, q->second.first, q->first, this, true); if (update) // dir contents not valid if frozen or non-auth dir->check_rstats(); } else { dout(20) << fg << " skipping STALE accounted_rstat " << pf->accounted_rstat << dendl; } if (update) { pf->accounted_rstat = pf->rstat; dir->dirty_old_rstat.clear(); pf->rstat.version = pf->accounted_rstat.version = pi->rstat.version; dout(10) << fg << " updated accounted_rstat " << pf->rstat << " on " << *dir << dendl; } if (fg == frag_t()) { // i.e., we are the only frag if (pi->rstat.rbytes != pf->rstat.rbytes) { clog.error() << "unmatched rstat rbytes on single dirfrag " << dir->dirfrag() << ", inode has " << pi->rstat << ", dirfrag has " << pf->rstat << "\n"; // trust the dirfrag for now version_t v = pi->rstat.version; pi->rstat = pf->rstat; pi->rstat.version = v; assert(!"unmatched rstat rbytes" == g_conf->mds_verify_scatter); } } if (update) dir->check_rstats(); } dout(20) << " final rstat " << pi->rstat << dendl; //assert(pi->rstat.rfiles >= 0); if (pi->rstat.rfiles < 0) { clog.error() << "rfiles underflow " << pi->rstat.rfiles << " on " << *this << "\n"; pi->rstat.rfiles = 0; } //assert(pi->rstat.rsubdirs >= 0); if (pi->rstat.rsubdirs < 0) { clog.error() << "rsubdirs underflow " << pi->rstat.rsubdirs << " on " << *this << "\n"; pi->rstat.rsubdirs = 0; } } break; case CEPH_LOCK_IDFT: break; default: assert(0); } } void CInode::finish_scatter_gather_update_accounted(int type, MutationRef& mut, EMetaBlob *metablob) { dout(10) << "finish_scatter_gather_update_accounted " << type << " on " << *this << dendl; assert(is_auth()); for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { CDir *dir = p->second; if (!dir->is_auth() || dir->get_version() == 0 || dir->is_frozen()) continue; if (type == CEPH_LOCK_IDFT) continue; // nothing to do. dout(10) << " journaling updated frag accounted_ on " << *dir << dendl; assert(dir->is_projected()); fnode_t *pf = dir->get_projected_fnode(); pf->version = dir->pre_dirty(); mut->add_projected_fnode(dir); metablob->add_dir(dir, true); mut->auth_pin(dir); if (type == CEPH_LOCK_INEST) dir->assimilate_dirty_rstat_inodes_finish(mut, metablob); } } // waiting bool CInode::is_frozen() { if (is_frozen_inode()) return true; if (parent && parent->dir->is_frozen()) return true; return false; } bool CInode::is_frozen_dir() { if (parent && parent->dir->is_frozen_dir()) return true; return false; } bool CInode::is_freezing() { if (is_freezing_inode()) return true; if (parent && parent->dir->is_freezing()) return true; return false; } void CInode::add_dir_waiter(frag_t fg, Context *c) { if (waiting_on_dir.empty()) get(PIN_DIRWAITER); waiting_on_dir[fg].push_back(c); dout(10) << "add_dir_waiter frag " << fg << " " << c << " on " << *this << dendl; } void CInode::take_dir_waiting(frag_t fg, list& ls) { if (waiting_on_dir.empty()) return; map >::iterator p = waiting_on_dir.find(fg); if (p != waiting_on_dir.end()) { dout(10) << "take_dir_waiting frag " << fg << " on " << *this << dendl; ls.splice(ls.end(), p->second); waiting_on_dir.erase(p); if (waiting_on_dir.empty()) put(PIN_DIRWAITER); } } void CInode::add_waiter(uint64_t tag, Context *c) { dout(10) << "add_waiter tag " << std::hex << tag << std::dec << " " << c << " !ambig " << !state_test(STATE_AMBIGUOUSAUTH) << " !frozen " << !is_frozen_inode() << " !freezing " << !is_freezing_inode() << dendl; // wait on the directory? // make sure its not the inode that is explicitly ambiguous|freezing|frozen if (((tag & WAIT_SINGLEAUTH) && !state_test(STATE_AMBIGUOUSAUTH)) || ((tag & WAIT_UNFREEZE) && !is_frozen_inode() && !is_freezing_inode() && !is_frozen_auth_pin())) { dout(15) << "passing waiter up tree" << dendl; parent->dir->add_waiter(tag, c); return; } dout(15) << "taking waiter here" << dendl; MDSCacheObject::add_waiter(tag, c); } void CInode::take_waiting(uint64_t mask, list& ls) { if ((mask & WAIT_DIR) && !waiting_on_dir.empty()) { // take all dentry waiters while (!waiting_on_dir.empty()) { map >::iterator p = waiting_on_dir.begin(); dout(10) << "take_waiting dirfrag " << p->first << " on " << *this << dendl; ls.splice(ls.end(), p->second); waiting_on_dir.erase(p); } put(PIN_DIRWAITER); } // waiting MDSCacheObject::take_waiting(mask, ls); } bool CInode::freeze_inode(int auth_pin_allowance) { assert(auth_pin_allowance > 0); // otherwise we need to adjust parent's nested_auth_pins assert(auth_pins >= auth_pin_allowance); if (auth_pins > auth_pin_allowance) { dout(10) << "freeze_inode - waiting for auth_pins to drop to " << auth_pin_allowance << dendl; auth_pin_freeze_allowance = auth_pin_allowance; get(PIN_FREEZING); state_set(STATE_FREEZING); return false; } dout(10) << "freeze_inode - frozen" << dendl; assert(auth_pins == auth_pin_allowance); if (!state_test(STATE_FROZEN)) { get(PIN_FROZEN); state_set(STATE_FROZEN); } return true; } void CInode::unfreeze_inode(list& finished) { dout(10) << "unfreeze_inode" << dendl; if (state_test(STATE_FREEZING)) { state_clear(STATE_FREEZING); put(PIN_FREEZING); } else if (state_test(STATE_FROZEN)) { state_clear(STATE_FROZEN); put(PIN_FROZEN); } else assert(0); take_waiting(WAIT_UNFREEZE, finished); } void CInode::unfreeze_inode() { list finished; unfreeze_inode(finished); mdcache->mds->queue_waiters(finished); } void CInode::freeze_auth_pin() { assert(state_test(CInode::STATE_FROZEN)); state_set(CInode::STATE_FROZENAUTHPIN); } void CInode::unfreeze_auth_pin() { assert(state_test(CInode::STATE_FROZENAUTHPIN)); state_clear(CInode::STATE_FROZENAUTHPIN); if (!state_test(STATE_FREEZING|STATE_FROZEN)) { list finished; take_waiting(WAIT_UNFREEZE, finished); mdcache->mds->queue_waiters(finished); } } void CInode::clear_ambiguous_auth(list& finished) { assert(state_test(CInode::STATE_AMBIGUOUSAUTH)); state_clear(CInode::STATE_AMBIGUOUSAUTH); take_waiting(CInode::WAIT_SINGLEAUTH, finished); } void CInode::clear_ambiguous_auth() { list finished; clear_ambiguous_auth(finished); mdcache->mds->queue_waiters(finished); } // auth_pins bool CInode::can_auth_pin() { if (!is_auth() || is_freezing_inode() || is_frozen_inode() || is_frozen_auth_pin()) return false; if (parent) return parent->can_auth_pin(); return true; } void CInode::auth_pin(void *by) { if (auth_pins == 0) get(PIN_AUTHPIN); auth_pins++; #ifdef MDS_AUTHPIN_SET auth_pin_set.insert(by); #endif dout(10) << "auth_pin by " << by << " on " << *this << " now " << auth_pins << "+" << nested_auth_pins << dendl; if (parent) parent->adjust_nested_auth_pins(1, 1, this); } void CInode::auth_unpin(void *by) { auth_pins--; #ifdef MDS_AUTHPIN_SET assert(auth_pin_set.count(by)); auth_pin_set.erase(auth_pin_set.find(by)); #endif if (auth_pins == 0) put(PIN_AUTHPIN); dout(10) << "auth_unpin by " << by << " on " << *this << " now " << auth_pins << "+" << nested_auth_pins << dendl; assert(auth_pins >= 0); if (parent) parent->adjust_nested_auth_pins(-1, -1, by); if (is_freezing_inode() && auth_pins == auth_pin_freeze_allowance) { dout(10) << "auth_unpin freezing!" << dendl; get(PIN_FROZEN); put(PIN_FREEZING); state_clear(STATE_FREEZING); state_set(STATE_FROZEN); finish_waiting(WAIT_FROZEN); } } void CInode::adjust_nested_auth_pins(int a, void *by) { assert(a); nested_auth_pins += a; dout(35) << "adjust_nested_auth_pins by " << by << " change " << a << " yields " << auth_pins << "+" << nested_auth_pins << dendl; assert(nested_auth_pins >= 0); if (g_conf->mds_debug_auth_pins) { // audit int s = 0; for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { CDir *dir = p->second; if (!dir->is_subtree_root() && dir->get_cum_auth_pins()) s++; } assert(s == nested_auth_pins); } if (parent) parent->adjust_nested_auth_pins(a, 0, by); } void CInode::adjust_nested_anchors(int by) { assert(by); nested_anchors += by; dout(20) << "adjust_nested_anchors by " << by << " -> " << nested_anchors << dendl; assert(nested_anchors >= 0); if (parent) parent->adjust_nested_anchors(by); } // authority pair CInode::authority() { if (inode_auth.first >= 0) return inode_auth; if (parent) return parent->dir->authority(); // new items that are not yet linked in (in the committed plane) belong // to their first parent. if (!projected_parent.empty()) return projected_parent.front()->dir->authority(); return CDIR_AUTH_UNDEF; } // SNAP snapid_t CInode::get_oldest_snap() { snapid_t t = first; if (!old_inodes.empty()) t = old_inodes.begin()->second.first; return MIN(t, first); } old_inode_t& CInode::cow_old_inode(snapid_t follows, bool cow_head) { assert(follows >= first); inode_t *pi = cow_head ? get_projected_inode() : get_previous_projected_inode(); map *px = cow_head ? get_projected_xattrs() : get_previous_projected_xattrs(); old_inode_t &old = old_inodes[follows]; old.first = first; old.inode = *pi; old.xattrs = *px; dout(10) << " " << px->size() << " xattrs cowed, " << *px << dendl; old.inode.trim_client_ranges(follows); if (!(old.inode.rstat == old.inode.accounted_rstat)) dirty_old_rstats.insert(follows); first = follows+1; dout(10) << "cow_old_inode " << (cow_head ? "head" : "previous_head" ) << " to [" << old.first << "," << follows << "] on " << *this << dendl; return old; } void CInode::pre_cow_old_inode() { snapid_t follows = find_snaprealm()->get_newest_seq(); if (first <= follows) cow_old_inode(follows, true); } void CInode::purge_stale_snap_data(const set& snaps) { dout(10) << "purge_stale_snap_data " << snaps << dendl; if (old_inodes.empty()) return; map::iterator p = old_inodes.begin(); while (p != old_inodes.end()) { set::const_iterator q = snaps.lower_bound(p->second.first); if (q == snaps.end() || *q > p->first) { dout(10) << " purging old_inode [" << p->second.first << "," << p->first << "]" << dendl; old_inodes.erase(p++); } else ++p; } } /* * pick/create an old_inode */ old_inode_t * CInode::pick_old_inode(snapid_t snap) { map::iterator p = old_inodes.lower_bound(snap); // p is first key >= to snap if (p != old_inodes.end() && p->second.first <= snap) { dout(10) << "pick_old_inode snap " << snap << " -> [" << p->second.first << "," << p->first << "]" << dendl; return &p->second; } dout(10) << "pick_old_inode snap " << snap << " -> nothing" << dendl; return NULL; } void CInode::open_snaprealm(bool nosplit) { if (!snaprealm) { SnapRealm *parent = find_snaprealm(); snaprealm = new SnapRealm(mdcache, this); if (parent) { dout(10) << "open_snaprealm " << snaprealm << " parent is " << parent << dendl; dout(30) << " siblings are " << parent->open_children << dendl; snaprealm->parent = parent; if (!nosplit) parent->split_at(snaprealm); parent->open_children.insert(snaprealm); } } } void CInode::close_snaprealm(bool nojoin) { if (snaprealm) { dout(15) << "close_snaprealm " << *snaprealm << dendl; snaprealm->close_parents(); if (snaprealm->parent) { snaprealm->parent->open_children.erase(snaprealm); //if (!nojoin) //snaprealm->parent->join(snaprealm); } delete snaprealm; snaprealm = 0; } } SnapRealm *CInode::find_snaprealm() { CInode *cur = this; while (!cur->snaprealm) { if (cur->get_parent_dn()) cur = cur->get_parent_dn()->get_dir()->get_inode(); else if (get_projected_parent_dn()) cur = cur->get_projected_parent_dn()->get_dir()->get_inode(); else break; } return cur->snaprealm; } void CInode::encode_snap_blob(bufferlist &snapbl) { if (snaprealm) { ::encode(snaprealm->srnode, snapbl); dout(20) << "encode_snap_blob " << *snaprealm << dendl; } } void CInode::decode_snap_blob(bufferlist& snapbl) { if (snapbl.length()) { open_snaprealm(); bufferlist::iterator p = snapbl.begin(); ::decode(snaprealm->srnode, p); dout(20) << "decode_snap_blob " << *snaprealm << dendl; } } void CInode::encode_snap(bufferlist& bl) { bufferlist snapbl; encode_snap_blob(snapbl); ::encode(snapbl, bl); } void CInode::decode_snap(bufferlist::iterator& p) { bufferlist snapbl; ::decode(snapbl, p); decode_snap_blob(snapbl); } // ============================================= client_t CInode::calc_ideal_loner() { if (!mds_caps_wanted.empty()) return -1; int n = 0; client_t loner = -1; for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) if (!it->second->is_stale() && ((it->second->wanted() & (CEPH_CAP_ANY_WR|CEPH_CAP_FILE_WR|CEPH_CAP_FILE_RD)) || (inode.is_dir() && !has_subtree_root_dirfrag()))) { if (n) return -1; n++; loner = it->first; } return loner; } client_t CInode::choose_ideal_loner() { want_loner_cap = calc_ideal_loner(); return want_loner_cap; } bool CInode::try_set_loner() { assert(want_loner_cap >= 0); if (loner_cap >= 0 && loner_cap != want_loner_cap) return false; set_loner_cap(want_loner_cap); return true; } void CInode::set_loner_cap(client_t l) { loner_cap = l; authlock.set_excl_client(loner_cap); filelock.set_excl_client(loner_cap); linklock.set_excl_client(loner_cap); xattrlock.set_excl_client(loner_cap); } bool CInode::try_drop_loner() { if (loner_cap < 0) return true; int other_allowed = get_caps_allowed_by_type(CAP_ANY); Capability *cap = get_client_cap(loner_cap); if (!cap || (cap->issued() & ~other_allowed) == 0) { set_loner_cap(-1); return true; } return false; } // choose new lock state during recovery, based on issued caps void CInode::choose_lock_state(SimpleLock *lock, int allissued) { int shift = lock->get_cap_shift(); int issued = (allissued >> shift) & lock->get_cap_mask(); if (is_auth()) { if (lock->is_xlocked()) { // do nothing here } else { if (issued & CEPH_CAP_GEXCL) lock->set_state(LOCK_EXCL); else if (issued & CEPH_CAP_GWR) lock->set_state(LOCK_MIX); else if (lock->is_dirty()) { if (is_replicated()) lock->set_state(LOCK_MIX); else lock->set_state(LOCK_LOCK); } else lock->set_state(LOCK_SYNC); } } else { // our states have already been chosen during rejoin. if (lock->is_xlocked()) assert(lock->get_state() == LOCK_LOCK); } } void CInode::choose_lock_states() { int issued = get_caps_issued(); if (is_auth() && (issued & (CEPH_CAP_ANY_EXCL|CEPH_CAP_ANY_WR)) && choose_ideal_loner() >= 0) try_set_loner(); choose_lock_state(&filelock, issued); choose_lock_state(&nestlock, issued); choose_lock_state(&dirfragtreelock, issued); choose_lock_state(&authlock, issued); choose_lock_state(&xattrlock, issued); choose_lock_state(&linklock, issued); } Capability *CInode::add_client_cap(client_t client, Session *session, SnapRealm *conrealm) { if (client_caps.empty()) { get(PIN_CAPS); if (conrealm) containing_realm = conrealm; else containing_realm = find_snaprealm(); containing_realm->inodes_with_caps.push_back(&item_caps); dout(10) << "add_client_cap first cap, joining realm " << *containing_realm << dendl; } mdcache->num_caps++; if (client_caps.empty()) mdcache->num_inodes_with_caps++; Capability *cap = new Capability(this, ++mdcache->last_cap_id, client); assert(client_caps.count(client) == 0); client_caps[client] = cap; session->add_cap(cap); if (session->is_stale()) cap->mark_stale(); cap->client_follows = first-1; containing_realm->add_cap(client, cap); return cap; } void CInode::remove_client_cap(client_t client) { assert(client_caps.count(client) == 1); Capability *cap = client_caps[client]; cap->item_session_caps.remove_myself(); containing_realm->remove_cap(client, cap); if (client == loner_cap) loner_cap = -1; delete cap; client_caps.erase(client); if (client_caps.empty()) { dout(10) << "remove_client_cap last cap, leaving realm " << *containing_realm << dendl; put(PIN_CAPS); item_caps.remove_myself(); containing_realm = NULL; item_open_file.remove_myself(); // unpin logsegment mdcache->num_inodes_with_caps--; } mdcache->num_caps--; //clean up advisory locks bool fcntl_removed = fcntl_locks.remove_all_from(client); bool flock_removed = flock_locks.remove_all_from(client); if (fcntl_removed || flock_removed) { list waiters; take_waiting(CInode::WAIT_FLOCK, waiters); mdcache->mds->queue_waiters(waiters); } } void CInode::move_to_realm(SnapRealm *realm) { dout(10) << "move_to_realm joining realm " << *realm << ", leaving realm " << *containing_realm << dendl; for (map::iterator q = client_caps.begin(); q != client_caps.end(); ++q) { containing_realm->remove_cap(q->first, q->second); realm->add_cap(q->first, q->second); } item_caps.remove_myself(); realm->inodes_with_caps.push_back(&item_caps); containing_realm = realm; } Capability *CInode::reconnect_cap(client_t client, ceph_mds_cap_reconnect& icr, Session *session) { Capability *cap = get_client_cap(client); if (cap) { // FIXME? cap->merge(icr.wanted, icr.issued); } else { cap = add_client_cap(client, session); cap->set_wanted(icr.wanted); cap->issue_norevoke(icr.issued); cap->reset_seq(); cap->set_cap_id(icr.cap_id); } cap->set_last_issue_stamp(ceph_clock_now(g_ceph_context)); return cap; } void CInode::clear_client_caps_after_export() { while (!client_caps.empty()) remove_client_cap(client_caps.begin()->first); loner_cap = -1; want_loner_cap = -1; mds_caps_wanted.clear(); } void CInode::export_client_caps(map& cl) { for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) { cl[it->first] = it->second->make_export(); } } // caps allowed int CInode::get_caps_liked() { if (is_dir()) return CEPH_CAP_PIN | CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_SHARED; // but not, say, FILE_RD|WR|WRBUFFER else return CEPH_CAP_ANY & ~CEPH_CAP_FILE_LAZYIO; } int CInode::get_caps_allowed_ever() { int allowed; if (is_dir()) allowed = CEPH_CAP_PIN | CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_SHARED; else allowed = CEPH_CAP_ANY; return allowed & (CEPH_CAP_PIN | (filelock.gcaps_allowed_ever() << filelock.get_cap_shift()) | (authlock.gcaps_allowed_ever() << authlock.get_cap_shift()) | (xattrlock.gcaps_allowed_ever() << xattrlock.get_cap_shift()) | (linklock.gcaps_allowed_ever() << linklock.get_cap_shift())); } int CInode::get_caps_allowed_by_type(int type) { return CEPH_CAP_PIN | (filelock.gcaps_allowed(type) << filelock.get_cap_shift()) | (authlock.gcaps_allowed(type) << authlock.get_cap_shift()) | (xattrlock.gcaps_allowed(type) << xattrlock.get_cap_shift()) | (linklock.gcaps_allowed(type) << linklock.get_cap_shift()); } int CInode::get_caps_careful() { return (filelock.gcaps_careful() << filelock.get_cap_shift()) | (authlock.gcaps_careful() << authlock.get_cap_shift()) | (xattrlock.gcaps_careful() << xattrlock.get_cap_shift()) | (linklock.gcaps_careful() << linklock.get_cap_shift()); } int CInode::get_xlocker_mask(client_t client) { return (filelock.gcaps_xlocker_mask(client) << filelock.get_cap_shift()) | (authlock.gcaps_xlocker_mask(client) << authlock.get_cap_shift()) | (xattrlock.gcaps_xlocker_mask(client) << xattrlock.get_cap_shift()) | (linklock.gcaps_xlocker_mask(client) << linklock.get_cap_shift()); } int CInode::get_caps_allowed_for_client(client_t client) { int allowed; if (client == get_loner()) { // as the loner, we get the loner_caps AND any xlocker_caps for things we have xlocked allowed = get_caps_allowed_by_type(CAP_LONER) | (get_caps_allowed_by_type(CAP_XLOCKER) & get_xlocker_mask(client)); } else { allowed = get_caps_allowed_by_type(CAP_ANY); } if (inode.inline_version != CEPH_INLINE_NONE && !mdcache->mds->get_session(client)->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR); return allowed; } // caps issued, wanted int CInode::get_caps_issued(int *ploner, int *pother, int *pxlocker, int shift, int mask) { int c = 0; int loner = 0, other = 0, xlocker = 0; if (!is_auth()) loner_cap = -1; for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) { int i = it->second->issued(); c |= i; if (it->first == loner_cap) loner |= i; else other |= i; xlocker |= get_xlocker_mask(it->first) & i; } if (ploner) *ploner = (loner >> shift) & mask; if (pother) *pother = (other >> shift) & mask; if (pxlocker) *pxlocker = (xlocker >> shift) & mask; return (c >> shift) & mask; } bool CInode::is_any_caps_wanted() { for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) if (it->second->wanted()) return true; return false; } int CInode::get_caps_wanted(int *ploner, int *pother, int shift, int mask) { int w = 0; int loner = 0, other = 0; for (map::iterator it = client_caps.begin(); it != client_caps.end(); ++it) { if (!it->second->is_stale()) { int t = it->second->wanted(); w |= t; if (it->first == loner_cap) loner |= t; else other |= t; } //cout << " get_caps_wanted client " << it->first << " " << cap_string(it->second.wanted()) << endl; } if (is_auth()) for (map::iterator it = mds_caps_wanted.begin(); it != mds_caps_wanted.end(); ++it) { w |= it->second; other |= it->second; //cout << " get_caps_wanted mds " << it->first << " " << cap_string(it->second) << endl; } if (ploner) *ploner = (loner >> shift) & mask; if (pother) *pother = (other >> shift) & mask; return (w >> shift) & mask; } bool CInode::issued_caps_need_gather(SimpleLock *lock) { int loner_issued, other_issued, xlocker_issued; get_caps_issued(&loner_issued, &other_issued, &xlocker_issued, lock->get_cap_shift(), lock->get_cap_mask()); if ((loner_issued & ~lock->gcaps_allowed(CAP_LONER)) || (other_issued & ~lock->gcaps_allowed(CAP_ANY)) || (xlocker_issued & ~lock->gcaps_allowed(CAP_XLOCKER))) return true; return false; } void CInode::replicate_relax_locks() { //dout(10) << " relaxing locks on " << *this << dendl; assert(is_auth()); assert(!is_replicated()); authlock.replicate_relax(); linklock.replicate_relax(); dirfragtreelock.replicate_relax(); filelock.replicate_relax(); xattrlock.replicate_relax(); snaplock.replicate_relax(); nestlock.replicate_relax(); flocklock.replicate_relax(); policylock.replicate_relax(); } // ============================================= int CInode::encode_inodestat(bufferlist& bl, Session *session, SnapRealm *dir_realm, snapid_t snapid, unsigned max_bytes, int getattr_caps) { int client = session->info.inst.name.num(); assert(snapid); assert(session->connection); bool valid = true; // do not issue caps if inode differs from readdir snaprealm SnapRealm *realm = find_snaprealm(); bool no_caps = session->is_stale() || (realm && dir_realm && realm != dir_realm) || is_frozen() || state_test(CInode::STATE_EXPORTINGCAPS); if (no_caps) dout(20) << "encode_inodestat no caps" << (session->is_stale()?", session stale ":"") << ((realm && dir_realm && realm != dir_realm)?", snaprealm differs ":"") << (state_test(CInode::STATE_EXPORTINGCAPS)?", exporting caps":"") << (is_frozen()?", frozen inode":"") << dendl; // pick a version! inode_t *oi = &inode; inode_t *pi = get_projected_inode(); map *pxattrs = 0; if (snapid != CEPH_NOSNAP && is_multiversion()) { // for now at least, old_inodes is only defined/valid on the auth if (!is_auth()) valid = false; map::iterator p = old_inodes.lower_bound(snapid); if (p != old_inodes.end()) { if (p->second.first > snapid) { if (p != old_inodes.begin()) --p; else dout(0) << "old_inode lower_bound starts after snapid!" << dendl; } dout(15) << "encode_inodestat snapid " << snapid << " to old_inode [" << p->second.first << "," << p->first << "]" << " " << p->second.inode.rstat << dendl; assert(p->second.first <= snapid && snapid <= p->first); pi = oi = &p->second.inode; pxattrs = &p->second.xattrs; } } /* * note: encoding matches struct ceph_client_reply_inode */ struct ceph_mds_reply_inode e; memset(&e, 0, sizeof(e)); e.ino = oi->ino; e.snapid = snapid; // 0 -> NOSNAP e.rdev = oi->rdev; // "fake" a version that is old (stable) version, +1 if projected. e.version = (oi->version * 2) + is_projected(); Capability *cap = get_client_cap(client); bool pfile = filelock.is_xlocked_by_client(client) || get_loner() == client; //(cap && (cap->issued() & CEPH_CAP_FILE_EXCL)); bool pauth = authlock.is_xlocked_by_client(client) || get_loner() == client; bool plink = linklock.is_xlocked_by_client(client) || get_loner() == client; bool pxattr = xattrlock.is_xlocked_by_client(client) || get_loner() == client; bool plocal = versionlock.get_last_wrlock_client() == client; bool ppolicy = policylock.is_xlocked_by_client(client) || get_loner()==client; inode_t *i = (pfile|pauth|plink|pxattr|plocal) ? pi : oi; i->ctime.encode_timeval(&e.ctime); dout(20) << " pfile " << pfile << " pauth " << pauth << " plink " << plink << " pxattr " << pxattr << " plocal " << plocal << " ctime " << i->ctime << " valid=" << valid << dendl; // file i = pfile ? pi:oi; if (is_dir()) { e.layout = (ppolicy ? pi : oi)->layout; } else { e.layout = i->layout; } e.size = i->size; e.truncate_seq = i->truncate_seq; e.truncate_size = i->truncate_size; i->mtime.encode_timeval(&e.mtime); i->atime.encode_timeval(&e.atime); e.time_warp_seq = i->time_warp_seq; // max_size is min of projected, actual e.max_size = MIN(oi->client_ranges.count(client) ? oi->client_ranges[client].range.last : 0, pi->client_ranges.count(client) ? pi->client_ranges[client].range.last : 0); e.files = i->dirstat.nfiles; e.subdirs = i->dirstat.nsubdirs; // inline data version_t inline_version = 0; bufferlist inline_data; if (i->inline_version == CEPH_INLINE_NONE) { inline_version = CEPH_INLINE_NONE; } else if ((!cap && !no_caps) || (cap && cap->client_inline_version < i->inline_version) || (getattr_caps & CEPH_CAP_FILE_RD)) { // client requests inline data inline_version = i->inline_version; inline_data = i->inline_data; } // nest (do same as file... :/) i->rstat.rctime.encode_timeval(&e.rctime); e.rbytes = i->rstat.rbytes; e.rfiles = i->rstat.rfiles; e.rsubdirs = i->rstat.rsubdirs; // auth i = pauth ? pi:oi; e.mode = i->mode; e.uid = i->uid; e.gid = i->gid; // link i = plink ? pi:oi; e.nlink = i->nlink; // xattr i = pxattr ? pi:oi; bool had_latest_xattrs = cap && (cap->issued() & CEPH_CAP_XATTR_SHARED) && cap->client_xattr_version == i->xattr_version && snapid == CEPH_NOSNAP; // xattr bufferlist xbl; e.xattr_version = i->xattr_version; if (!had_latest_xattrs) { if (!pxattrs) pxattrs = pxattr ? get_projected_xattrs() : &xattrs; ::encode(*pxattrs, xbl); } // do we have room? if (max_bytes) { unsigned bytes = sizeof(e); bytes += sizeof(__u32); bytes += (sizeof(__u32) + sizeof(__u32)) * dirfragtree._splits.size(); bytes += sizeof(__u32) + symlink.length(); bytes += sizeof(__u32) + xbl.length(); bytes += sizeof(version_t) + sizeof(__u32) + inline_data.length(); if (bytes > max_bytes) return -ENOSPC; } // encode caps if (snapid != CEPH_NOSNAP) { /* * snapped inodes (files or dirs) only get read-only caps. always * issue everything possible, since it is read only. * * if a snapped inode has caps, limit issued caps based on the * lock state. * * if it is a live inode, limit issued caps based on the lock * state. * * do NOT adjust cap issued state, because the client always * tracks caps per-snap and the mds does either per-interval or * multiversion. */ e.cap.caps = valid ? get_caps_allowed_by_type(CAP_ANY) : CEPH_STAT_CAP_INODE; if (last == CEPH_NOSNAP || is_any_caps()) e.cap.caps = e.cap.caps & get_caps_allowed_for_client(client); e.cap.seq = 0; e.cap.mseq = 0; e.cap.realm = 0; } else { if (!no_caps && valid && !cap) { // add a new cap cap = add_client_cap(client, session, realm); if (is_auth()) { if (choose_ideal_loner() >= 0) try_set_loner(); else if (get_wanted_loner() < 0) try_drop_loner(); } } if (!no_caps && valid && cap) { int likes = get_caps_liked(); int allowed = get_caps_allowed_for_client(client); int issue = (cap->wanted() | likes) & allowed; cap->issue_norevoke(issue); issue = cap->pending(); cap->set_last_issue(); cap->set_last_issue_stamp(ceph_clock_now(g_ceph_context)); cap->clear_new(); e.cap.caps = issue; e.cap.wanted = cap->wanted(); e.cap.cap_id = cap->get_cap_id(); e.cap.seq = cap->get_last_seq(); dout(10) << "encode_inodestat issueing " << ccap_string(issue) << " seq " << cap->get_last_seq() << dendl; e.cap.mseq = cap->get_mseq(); e.cap.realm = realm->inode->ino(); } else { e.cap.cap_id = 0; e.cap.caps = 0; e.cap.seq = 0; e.cap.mseq = 0; e.cap.realm = 0; e.cap.wanted = 0; } } e.cap.flags = is_auth() ? CEPH_CAP_FLAG_AUTH:0; dout(10) << "encode_inodestat caps " << ccap_string(e.cap.caps) << " seq " << e.cap.seq << " mseq " << e.cap.mseq << " xattrv " << e.xattr_version << " len " << xbl.length() << dendl; if (inline_data.length() && cap) { if ((cap->pending() | getattr_caps) & CEPH_CAP_FILE_SHARED) { dout(10) << "including inline version " << inline_version << dendl; cap->client_inline_version = inline_version; } else { dout(10) << "dropping inline version " << inline_version << dendl; inline_version = 0; inline_data.clear(); } } // include those xattrs? if (xbl.length() && cap) { if ((cap->pending() | getattr_caps) & CEPH_CAP_XATTR_SHARED) { dout(10) << "including xattrs version " << i->xattr_version << dendl; cap->client_xattr_version = i->xattr_version; } else { dout(10) << "dropping xattrs version " << i->xattr_version << dendl; xbl.clear(); // no xattrs .. XXX what's this about?!? } } // encode e.fragtree.nsplits = dirfragtree._splits.size(); ::encode(e, bl); for (map::iterator p = dirfragtree._splits.begin(); p != dirfragtree._splits.end(); ++p) { ::encode(p->first, bl); ::encode(p->second, bl); } ::encode(symlink, bl); if (session->connection->has_feature(CEPH_FEATURE_DIRLAYOUTHASH)) { i = pfile ? pi : oi; ::encode(i->dir_layout, bl); } ::encode(xbl, bl); if (session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) { ::encode(inline_version, bl); ::encode(inline_data, bl); } return valid; } void CInode::encode_cap_message(MClientCaps *m, Capability *cap) { assert(cap); client_t client = cap->get_client(); bool pfile = filelock.is_xlocked_by_client(client) || (cap->issued() & CEPH_CAP_FILE_EXCL); bool pauth = authlock.is_xlocked_by_client(client); bool plink = linklock.is_xlocked_by_client(client); bool pxattr = xattrlock.is_xlocked_by_client(client); inode_t *oi = &inode; inode_t *pi = get_projected_inode(); inode_t *i = (pfile|pauth|plink|pxattr) ? pi : oi; i->ctime.encode_timeval(&m->head.ctime); dout(20) << "encode_cap_message pfile " << pfile << " pauth " << pauth << " plink " << plink << " pxattr " << pxattr << " ctime " << i->ctime << dendl; i = pfile ? pi:oi; m->head.layout = i->layout; m->head.size = i->size; m->head.truncate_seq = i->truncate_seq; m->head.truncate_size = i->truncate_size; i->mtime.encode_timeval(&m->head.mtime); i->atime.encode_timeval(&m->head.atime); m->head.time_warp_seq = i->time_warp_seq; if (cap->client_inline_version < i->inline_version) { m->inline_version = cap->client_inline_version = i->inline_version; m->inline_data = i->inline_data; } else { m->inline_version = 0; } // max_size is min of projected, actual. uint64_t oldms = oi->client_ranges.count(client) ? oi->client_ranges[client].range.last : 0; uint64_t newms = pi->client_ranges.count(client) ? pi->client_ranges[client].range.last : 0; m->head.max_size = MIN(oldms, newms); i = pauth ? pi:oi; m->head.mode = i->mode; m->head.uid = i->uid; m->head.gid = i->gid; i = plink ? pi:oi; m->head.nlink = i->nlink; i = pxattr ? pi:oi; map *ix = pxattr ? get_projected_xattrs() : &xattrs; if ((cap->pending() & CEPH_CAP_XATTR_SHARED) && i->xattr_version > cap->client_xattr_version) { dout(10) << " including xattrs v " << i->xattr_version << dendl; ::encode(*ix, m->xattrbl); m->head.xattr_version = i->xattr_version; cap->client_xattr_version = i->xattr_version; } } void CInode::_encode_base(bufferlist& bl) { ::encode(first, bl); ::encode(inode, bl); ::encode(symlink, bl); ::encode(dirfragtree, bl); ::encode(xattrs, bl); ::encode(old_inodes, bl); encode_snap(bl); } void CInode::_decode_base(bufferlist::iterator& p) { ::decode(first, p); bool was_anchored = inode.anchored; ::decode(inode, p); if (parent && was_anchored != inode.anchored) parent->adjust_nested_anchors((int)inode.anchored - (int)was_anchored); ::decode(symlink, p); ::decode(dirfragtree, p); ::decode(xattrs, p); ::decode(old_inodes, p); decode_snap(p); } void CInode::_encode_locks_full(bufferlist& bl) { ::encode(authlock, bl); ::encode(linklock, bl); ::encode(dirfragtreelock, bl); ::encode(filelock, bl); ::encode(xattrlock, bl); ::encode(snaplock, bl); ::encode(nestlock, bl); ::encode(flocklock, bl); ::encode(policylock, bl); ::encode(loner_cap, bl); } void CInode::_decode_locks_full(bufferlist::iterator& p) { ::decode(authlock, p); ::decode(linklock, p); ::decode(dirfragtreelock, p); ::decode(filelock, p); ::decode(xattrlock, p); ::decode(snaplock, p); ::decode(nestlock, p); ::decode(flocklock, p); ::decode(policylock, p); ::decode(loner_cap, p); set_loner_cap(loner_cap); want_loner_cap = loner_cap; // for now, we'll eval() shortly. } void CInode::_encode_locks_state_for_replica(bufferlist& bl) { authlock.encode_state_for_replica(bl); linklock.encode_state_for_replica(bl); dirfragtreelock.encode_state_for_replica(bl); filelock.encode_state_for_replica(bl); nestlock.encode_state_for_replica(bl); xattrlock.encode_state_for_replica(bl); snaplock.encode_state_for_replica(bl); flocklock.encode_state_for_replica(bl); policylock.encode_state_for_replica(bl); } void CInode::_encode_locks_state_for_rejoin(bufferlist& bl, int rep) { authlock.encode_state_for_replica(bl); linklock.encode_state_for_replica(bl); dirfragtreelock.encode_state_for_rejoin(bl, rep); filelock.encode_state_for_rejoin(bl, rep); nestlock.encode_state_for_rejoin(bl, rep); xattrlock.encode_state_for_replica(bl); snaplock.encode_state_for_replica(bl); flocklock.encode_state_for_replica(bl); policylock.encode_state_for_replica(bl); } void CInode::_decode_locks_state(bufferlist::iterator& p, bool is_new) { authlock.decode_state(p, is_new); linklock.decode_state(p, is_new); dirfragtreelock.decode_state(p, is_new); filelock.decode_state(p, is_new); nestlock.decode_state(p, is_new); xattrlock.decode_state(p, is_new); snaplock.decode_state(p, is_new); flocklock.decode_state(p, is_new); policylock.decode_state(p, is_new); } void CInode::_decode_locks_rejoin(bufferlist::iterator& p, list& waiters, list& eval_locks) { authlock.decode_state_rejoin(p, waiters); linklock.decode_state_rejoin(p, waiters); dirfragtreelock.decode_state_rejoin(p, waiters); filelock.decode_state_rejoin(p, waiters); nestlock.decode_state_rejoin(p, waiters); xattrlock.decode_state_rejoin(p, waiters); snaplock.decode_state_rejoin(p, waiters); flocklock.decode_state_rejoin(p, waiters); policylock.decode_state_rejoin(p, waiters); if (!dirfragtreelock.is_stable() && !dirfragtreelock.is_wrlocked()) eval_locks.push_back(&dirfragtreelock); if (!filelock.is_stable() && !filelock.is_wrlocked()) eval_locks.push_back(&filelock); if (!nestlock.is_stable() && !nestlock.is_wrlocked()) eval_locks.push_back(&nestlock); } // IMPORT/EXPORT void CInode::encode_export(bufferlist& bl) { ENCODE_START(5, 4, bl) _encode_base(bl); ::encode(state, bl); ::encode(pop, bl); ::encode(replica_map, bl); // include scatterlock info for any bounding CDirs bufferlist bounding; if (inode.is_dir()) for (map::iterator p = dirfrags.begin(); p != dirfrags.end(); ++p) { CDir *dir = p->second; if (dir->state_test(CDir::STATE_EXPORTBOUND)) { ::encode(p->first, bounding); ::encode(dir->fnode.fragstat, bounding); ::encode(dir->fnode.accounted_fragstat, bounding); ::encode(dir->fnode.rstat, bounding); ::encode(dir->fnode.accounted_rstat, bounding); dout(10) << " encoded fragstat/rstat info for " << *dir << dendl; } } ::encode(bounding, bl); _encode_locks_full(bl); ::encode(fcntl_locks, bl); ::encode(flock_locks, bl); ENCODE_FINISH(bl); get(PIN_TEMPEXPORTING); } void CInode::finish_export(utime_t now) { state &= MASK_STATE_EXPORT_KEPT; pop.zero(now); // just in case! //dirlock.clear_updated(); loner_cap = -1; put(PIN_TEMPEXPORTING); } void CInode::decode_import(bufferlist::iterator& p, LogSegment *ls) { DECODE_START(5, p); _decode_base(p); unsigned s; ::decode(s, p); state |= (s & MASK_STATE_EXPORTED); if (is_dirty()) { get(PIN_DIRTY); _mark_dirty(ls); } if (is_dirty_parent()) { get(PIN_DIRTYPARENT); _mark_dirty_parent(ls); } ::decode(pop, ceph_clock_now(g_ceph_context), p); ::decode(replica_map, p); if (!replica_map.empty()) get(PIN_REPLICATED); // decode fragstat info on bounding cdirs bufferlist bounding; ::decode(bounding, p); bufferlist::iterator q = bounding.begin(); while (!q.end()) { frag_t fg; ::decode(fg, q); CDir *dir = get_dirfrag(fg); assert(dir); // we should have all bounds open // Only take the remote's fragstat/rstat if we are non-auth for // this dirfrag AND the lock is NOT in a scattered (MIX) state. // We know lock is stable, and MIX is the only state in which // the inode auth (who sent us this data) may not have the best // info. // HMM: Are there cases where dir->is_auth() is an insufficient // check because the dirfrag is under migration? That implies // it is frozen (and in a SYNC or LOCK state). FIXME. if (dir->is_auth() || filelock.get_state() == LOCK_MIX) { dout(10) << " skipped fragstat info for " << *dir << dendl; frag_info_t f; ::decode(f, q); ::decode(f, q); } else { ::decode(dir->fnode.fragstat, q); ::decode(dir->fnode.accounted_fragstat, q); dout(10) << " took fragstat info for " << *dir << dendl; } if (dir->is_auth() || nestlock.get_state() == LOCK_MIX) { dout(10) << " skipped rstat info for " << *dir << dendl; nest_info_t n; ::decode(n, q); ::decode(n, q); } else { ::decode(dir->fnode.rstat, q); ::decode(dir->fnode.accounted_rstat, q); dout(10) << " took rstat info for " << *dir << dendl; } } _decode_locks_full(p); if (struct_v >= 5) { ::decode(fcntl_locks, p); ::decode(flock_locks, p); } DECODE_FINISH(p); } ceph-0.80.11/src/mds/Server.cc0000664000175100017510000073132012623076744020032 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "include/assert.h" // lexical_cast includes system assert.h #include #include #include #include "MDS.h" #include "Server.h" #include "Locker.h" #include "MDCache.h" #include "MDLog.h" #include "Migrator.h" #include "MDBalancer.h" #include "AnchorClient.h" #include "InoTable.h" #include "SnapClient.h" #include "Mutation.h" #include "msg/Messenger.h" #include "messages/MClientSession.h" #include "messages/MClientRequest.h" #include "messages/MClientReply.h" #include "messages/MClientReconnect.h" #include "messages/MClientCaps.h" #include "messages/MClientSnap.h" #include "messages/MMDSSlaveRequest.h" #include "messages/MLock.h" #include "messages/MDentryUnlink.h" #include "events/EUpdate.h" #include "events/ESlaveUpdate.h" #include "events/ESession.h" #include "events/EOpen.h" #include "events/ECommitted.h" #include "include/filepath.h" #include "common/errno.h" #include "common/Timer.h" #include "common/perf_counters.h" #include "include/compat.h" #include "osd/OSDMap.h" #include #include #include #include using namespace std; #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".server " void Server::create_logger() { PerfCountersBuilder plb(g_ceph_context, "mds_server", l_mdss_first, l_mdss_last); plb.add_u64_counter(l_mdss_hcreq,"hcreq"); // handle client req plb.add_u64_counter(l_mdss_hsreq, "hsreq"); // slave plb.add_u64_counter(l_mdss_hcsess, "hcsess"); // client session plb.add_u64_counter(l_mdss_dcreq, "dcreq"); // dispatch client req plb.add_u64_counter(l_mdss_dsreq, "dsreq"); // slave logger = plb.create_perf_counters(); g_ceph_context->get_perfcounters_collection()->add(logger); } /* This function DOES put the passed message before returning*/ void Server::dispatch(Message *m) { switch (m->get_type()) { case CEPH_MSG_CLIENT_RECONNECT: handle_client_reconnect(static_cast(m)); return; } // active? if (!mds->is_active() && !(mds->is_stopping() && m->get_source().is_mds())) { if ((mds->is_reconnect() || mds->get_want_state() == CEPH_MDS_STATE_RECONNECT) && m->get_type() == CEPH_MSG_CLIENT_REQUEST && (static_cast(m))->is_replay()) { dout(3) << "queuing replayed op" << dendl; mds->enqueue_replay(new C_MDS_RetryMessage(mds, m)); return; } else if (mds->is_clientreplay() && // session open requests need to be handled during replay, // close requests need to be delayed ((m->get_type() == CEPH_MSG_CLIENT_SESSION && (static_cast(m))->get_op() != CEPH_SESSION_REQUEST_CLOSE) || (m->get_type() == CEPH_MSG_CLIENT_REQUEST && (static_cast(m))->is_replay()))) { // replaying! } else if (m->get_type() == MSG_MDS_SLAVE_REQUEST) { // handle_slave_request() will wait if necessary } else { dout(3) << "not active yet, waiting" << dendl; mds->wait_for_active(new C_MDS_RetryMessage(mds, m)); return; } } switch (m->get_type()) { case CEPH_MSG_CLIENT_SESSION: handle_client_session(static_cast(m)); return; case CEPH_MSG_CLIENT_REQUEST: handle_client_request(static_cast(m)); return; case MSG_MDS_SLAVE_REQUEST: handle_slave_request(static_cast(m)); return; } dout(1) << "server unknown message " << m->get_type() << dendl; assert(0); } // ---------------------------------------------------------- // SESSION management class C_MDS_session_finish : public Context { MDS *mds; Session *session; uint64_t state_seq; bool open; version_t cmapv; interval_set inos; version_t inotablev; public: C_MDS_session_finish(MDS *m, Session *se, uint64_t sseq, bool s, version_t mv) : mds(m), session(se), state_seq(sseq), open(s), cmapv(mv), inotablev(0) { } C_MDS_session_finish(MDS *m, Session *se, uint64_t sseq, bool s, version_t mv, interval_set& i, version_t iv) : mds(m), session(se), state_seq(sseq), open(s), cmapv(mv), inos(i), inotablev(iv) { } void finish(int r) { assert(r == 0); mds->server->_session_logged(session, state_seq, open, cmapv, inos, inotablev); } }; Session *Server::get_session(Message *m) { Session *session = static_cast(m->get_connection()->get_priv()); if (session) { dout(20) << "get_session have " << session << " " << session->info.inst << " state " << session->get_state_name() << dendl; session->put(); // not carry ref } else { dout(20) << "get_session dne for " << m->get_source_inst() << dendl; } return session; } /* This function DOES put the passed message before returning*/ void Server::handle_client_session(MClientSession *m) { version_t pv; Session *session = get_session(m); dout(3) << "handle_client_session " << *m << " from " << m->get_source() << dendl; assert(m->get_source().is_client()); // should _not_ come from an mds! if (!session) { dout(0) << " ignoring sessionless msg " << *m << dendl; m->put(); return; } uint64_t sseq = 0; switch (m->get_op()) { case CEPH_SESSION_REQUEST_OPEN: if (session->is_opening() || session->is_open() || session->is_stale() || session->is_killing()) { dout(10) << "currently open|opening|stale|killing, dropping this req" << dendl; m->put(); return; } assert(session->is_closed() || session->is_closing()); sseq = mds->sessionmap.set_state(session, Session::STATE_OPENING); mds->sessionmap.touch_session(session); pv = ++mds->sessionmap.projected; mdlog->start_submit_entry(new ESession(m->get_source_inst(), true, pv), new C_MDS_session_finish(mds, session, sseq, true, pv)); mdlog->flush(); break; case CEPH_SESSION_REQUEST_RENEWCAPS: if (session->is_open() || session->is_stale()) { mds->sessionmap.touch_session(session); if (session->is_stale()) { mds->sessionmap.set_state(session, Session::STATE_OPEN); mds->locker->resume_stale_caps(session); mds->sessionmap.touch_session(session); } mds->messenger->send_message(new MClientSession(CEPH_SESSION_RENEWCAPS, m->get_seq()), m->get_connection()); } else { dout(10) << "ignoring renewcaps on non open|stale session (" << session->get_state_name() << ")" << dendl; } break; case CEPH_SESSION_REQUEST_CLOSE: { if (session->is_closed() || session->is_closing() || session->is_killing()) { dout(10) << "already closed|closing|killing, dropping this req" << dendl; m->put(); return; } if (session->is_importing()) { dout(10) << "ignoring close req on importing session" << dendl; m->put(); return; } assert(session->is_open() || session->is_stale() || session->is_opening()); if (m->get_seq() < session->get_push_seq()) { dout(10) << "old push seq " << m->get_seq() << " < " << session->get_push_seq() << ", dropping" << dendl; m->put(); return; } if (m->get_seq() != session->get_push_seq()) { dout(0) << "old push seq " << m->get_seq() << " != " << session->get_push_seq() << ", BUGGY!" << dendl; assert(0); } journal_close_session(session, Session::STATE_CLOSING); } break; case CEPH_SESSION_FLUSHMSG_ACK: finish_flush_session(session, m->get_seq()); break; default: assert(0); } m->put(); } void Server::flush_client_sessions(set& client_set, C_GatherBuilder& gather) { for (set::iterator p = client_set.begin(); p != client_set.end(); ++p) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(p->v)); assert(session); if (!session->is_open() || !session->connection.get() || !session->connection->has_feature(CEPH_FEATURE_EXPORT_PEER)) continue; version_t seq = session->wait_for_flush(gather.new_sub()); mds->send_message_client(new MClientSession(CEPH_SESSION_FLUSHMSG, seq), session); } } void Server::finish_flush_session(Session *session, version_t seq) { list finished; session->finish_flush(seq, finished); mds->queue_waiters(finished); } void Server::_session_logged(Session *session, uint64_t state_seq, bool open, version_t pv, interval_set& inos, version_t piv) { dout(10) << "_session_logged " << session->info.inst << " state_seq " << state_seq << " " << (open ? "open":"close") << " " << pv << dendl; if (piv) { mds->inotable->apply_release_ids(inos); assert(mds->inotable->get_version() == piv); } // apply if (session->get_state_seq() != state_seq) { dout(10) << " journaled state_seq " << state_seq << " != current " << session->get_state_seq() << ", noop" << dendl; // close must have been canceled (by an import?), or any number of other things.. } else if (open) { assert(session->is_opening()); mds->sessionmap.set_state(session, Session::STATE_OPEN); mds->sessionmap.touch_session(session); mds->messenger->send_message(new MClientSession(CEPH_SESSION_OPEN), session->connection); } else if (session->is_closing() || session->is_killing()) { // kill any lingering capabilities, leases, requests while (!session->caps.empty()) { Capability *cap = session->caps.front(); CInode *in = cap->get_inode(); dout(20) << " killing capability " << ccap_string(cap->issued()) << " on " << *in << dendl; mds->locker->remove_client_cap(in, session->info.inst.name.num()); } while (!session->leases.empty()) { ClientLease *r = session->leases.front(); CDentry *dn = static_cast(r->parent); dout(20) << " killing client lease of " << *dn << dendl; dn->remove_client_lease(r, mds->locker); } if (session->is_closing()) { // mark con disposable. if there is a fault, we will get a // reset and clean it up. if the client hasn't received the // CLOSE message yet, they will reconnect and get an // ms_handle_remote_reset() and realize they had in fact closed. // do this *before* sending the message to avoid a possible // race. mds->messenger->mark_disposable(session->connection.get()); // reset session mds->send_message_client(new MClientSession(CEPH_SESSION_CLOSE), session); mds->sessionmap.set_state(session, Session::STATE_CLOSED); session->clear(); } else if (session->is_killing()) { // destroy session, close connection mds->messenger->mark_down(session->connection); mds->sessionmap.remove_session(session); } else { assert(0); } } else { assert(0); } mds->sessionmap.version++; // noop } version_t Server::prepare_force_open_sessions(map& cm, map& sseqmap) { version_t pv = ++mds->sessionmap.projected; dout(10) << "prepare_force_open_sessions " << pv << " on " << cm.size() << " clients" << dendl; for (map::iterator p = cm.begin(); p != cm.end(); ++p) { Session *session = mds->sessionmap.get_or_add_session(p->second); if (session->is_closed() || session->is_closing() || session->is_killing()) sseqmap[p->first] = mds->sessionmap.set_state(session, Session::STATE_OPENING); else assert(session->is_open() || session->is_opening() || session->is_stale()); session->inc_importing(); // mds->sessionmap.touch_session(session); } return pv; } void Server::finish_force_open_sessions(map& cm, map& sseqmap, bool dec_import) { /* * FIXME: need to carefully consider the race conditions between a * client trying to close a session and an MDS doing an import * trying to force open a session... */ dout(10) << "finish_force_open_sessions on " << cm.size() << " clients," << " v " << mds->sessionmap.version << " -> " << (mds->sessionmap.version+1) << dendl; for (map::iterator p = cm.begin(); p != cm.end(); ++p) { Session *session = mds->sessionmap.get_session(p->second.name); assert(session); if (sseqmap.count(p->first)) { uint64_t sseq = sseqmap[p->first]; if (session->get_state_seq() != sseq) { dout(10) << "force_open_sessions skipping changed " << session->info.inst << dendl; } else { dout(10) << "force_open_sessions opened " << session->info.inst << dendl; mds->sessionmap.set_state(session, Session::STATE_OPEN); mds->sessionmap.touch_session(session); Message *m = new MClientSession(CEPH_SESSION_OPEN); if (session->connection) messenger->send_message(m, session->connection); else session->preopen_out_queue.push_back(m); } } else { dout(10) << "force_open_sessions skipping already-open " << session->info.inst << dendl; assert(session->is_open() || session->is_stale()); } if (dec_import) session->dec_importing(); } mds->sessionmap.version++; } struct C_MDS_TerminatedSessions : public Context { Server *server; C_MDS_TerminatedSessions(Server *s) : server(s) {} void finish(int r) { server->terminating_sessions = false; } }; void Server::terminate_sessions() { dout(2) << "terminate_sessions" << dendl; // kill them off. clients will retry etc. set sessions; mds->sessionmap.get_client_session_set(sessions); for (set::const_iterator p = sessions.begin(); p != sessions.end(); ++p) { Session *session = *p; if (session->is_closing() || session->is_killing() || session->is_closed()) continue; journal_close_session(session, Session::STATE_CLOSING); } mdlog->wait_for_safe(new C_MDS_TerminatedSessions(this)); } void Server::find_idle_sessions() { dout(10) << "find_idle_sessions. laggy until " << mds->laggy_until << dendl; // timeout/stale // (caps go stale, lease die) utime_t now = ceph_clock_now(g_ceph_context); utime_t cutoff = now; cutoff -= g_conf->mds_session_timeout; while (1) { Session *session = mds->sessionmap.get_oldest_session(Session::STATE_OPEN); if (!session) break; dout(20) << "laggiest active session is " << session->info.inst << dendl; if (session->last_cap_renew >= cutoff) { dout(20) << "laggiest active session is " << session->info.inst << " and sufficiently new (" << session->last_cap_renew << ")" << dendl; break; } dout(10) << "new stale session " << session->info.inst << " last " << session->last_cap_renew << dendl; mds->sessionmap.set_state(session, Session::STATE_STALE); mds->locker->revoke_stale_caps(session); mds->locker->remove_stale_leases(session); mds->send_message_client(new MClientSession(CEPH_SESSION_STALE, session->get_push_seq()), session); finish_flush_session(session, session->get_push_seq()); } // autoclose cutoff = now; cutoff -= g_conf->mds_session_autoclose; // don't kick clients if we've been laggy if (mds->laggy_until > cutoff) { dout(10) << " laggy_until " << mds->laggy_until << " > cutoff " << cutoff << ", not kicking any clients to be safe" << dendl; return; } while (1) { Session *session = mds->sessionmap.get_oldest_session(Session::STATE_STALE); if (!session) break; if (session->is_importing()) { dout(10) << "stopping at importing session " << session->info.inst << dendl; break; } assert(session->is_stale()); if (session->last_cap_renew >= cutoff) { dout(20) << "oldest stale session is " << session->info.inst << " and sufficiently new (" << session->last_cap_renew << ")" << dendl; break; } utime_t age = now; age -= session->last_cap_renew; mds->clog.info() << "closing stale session " << session->info.inst << " after " << age << "\n"; dout(10) << "autoclosing stale session " << session->info.inst << " last " << session->last_cap_renew << dendl; kill_session(session); } } void Server::kill_session(Session *session) { if ((session->is_opening() || session->is_open() || session->is_stale()) && !session->is_importing()) { dout(10) << "kill_session " << session << dendl; journal_close_session(session, Session::STATE_KILLING); } else { dout(10) << "kill_session importing or already closing/killing " << session << dendl; assert(session->is_closing() || session->is_closed() || session->is_killing() || session->is_importing()); } } void Server::journal_close_session(Session *session, int state) { uint64_t sseq = mds->sessionmap.set_state(session, state); version_t pv = ++mds->sessionmap.projected; version_t piv = 0; // release alloc and pending-alloc inos for this session // and wipe out session state, in case the session close aborts for some reason interval_set both; both.swap(session->info.prealloc_inos); both.insert(session->pending_prealloc_inos); session->pending_prealloc_inos.clear(); if (both.size()) { mds->inotable->project_release_ids(both); piv = mds->inotable->get_projected_version(); } else piv = 0; mdlog->start_submit_entry(new ESession(session->info.inst, false, pv, both, piv), new C_MDS_session_finish(mds, session, sseq, false, pv, both, piv)); mdlog->flush(); // clean up requests, too elist::iterator p = session->requests.begin(member_offset(MDRequestImpl, item_session_request)); while (!p.end()) { MDRequestRef mdr = mdcache->request_get((*p)->reqid); ++p; mdcache->request_kill(mdr); } finish_flush_session(session, session->get_push_seq()); } void Server::reconnect_clients() { mds->sessionmap.get_client_set(client_reconnect_gather); if (client_reconnect_gather.empty()) { dout(7) << "reconnect_clients -- no sessions, doing nothing." << dendl; reconnect_gather_finish(); return; } // clients will get the mdsmap and discover we're reconnecting via the monitor. reconnect_start = ceph_clock_now(g_ceph_context); dout(1) << "reconnect_clients -- " << client_reconnect_gather.size() << " sessions" << dendl; mds->sessionmap.dump(); } /* This function DOES put the passed message before returning*/ void Server::handle_client_reconnect(MClientReconnect *m) { dout(7) << "handle_client_reconnect " << m->get_source() << dendl; int from = m->get_source().num(); Session *session = get_session(m); assert(session); if (!mds->is_reconnect() && mds->get_want_state() == CEPH_MDS_STATE_RECONNECT) { dout(10) << " we're almost in reconnect state (mdsmap delivery race?); waiting" << dendl; mds->wait_for_reconnect(new C_MDS_RetryMessage(mds, m)); return; } utime_t delay = ceph_clock_now(g_ceph_context); delay -= reconnect_start; dout(10) << " reconnect_start " << reconnect_start << " delay " << delay << dendl; if (!mds->is_reconnect()) { // XXX maybe in the future we can do better than this? dout(1) << " no longer in reconnect state, ignoring reconnect, sending close" << dendl; mds->clog.info() << "denied reconnect attempt (mds is " << ceph_mds_state_name(mds->get_state()) << ") from " << m->get_source_inst() << " after " << delay << " (allowed interval " << g_conf->mds_reconnect_timeout << ")\n"; mds->messenger->send_message(new MClientSession(CEPH_SESSION_CLOSE), m->get_connection()); m->put(); return; } // notify client of success with an OPEN mds->messenger->send_message(new MClientSession(CEPH_SESSION_OPEN), m->get_connection()); if (session->is_closed()) { dout(10) << " session is closed, will make best effort to reconnect " << m->get_source_inst() << dendl; mds->sessionmap.set_state(session, Session::STATE_OPENING); version_t pv = ++mds->sessionmap.projected; uint64_t sseq = session->get_state_seq(); mdlog->start_submit_entry(new ESession(session->info.inst, true, pv), new C_MDS_session_finish(mds, session, sseq, true, pv)); mdlog->flush(); mds->clog.debug() << "reconnect by new " << session->info.inst << " after " << delay << "\n"; } else { mds->clog.debug() << "reconnect by " << session->info.inst << " after " << delay << "\n"; } // snaprealms for (vector::iterator p = m->realms.begin(); p != m->realms.end(); ++p) { CInode *in = mdcache->get_inode(inodeno_t(p->ino)); if (in && in->state_test(CInode::STATE_PURGING)) continue; if (in) { assert(in->snaprealm); if (in->snaprealm->have_past_parents_open()) { dout(15) << "open snaprealm (w/ past parents) on " << *in << dendl; mdcache->finish_snaprealm_reconnect(from, in->snaprealm, snapid_t(p->seq)); } else { dout(15) << "open snaprealm (w/o past parents) on " << *in << dendl; mdcache->add_reconnected_snaprealm(from, inodeno_t(p->ino), snapid_t(p->seq)); } } else { dout(15) << "open snaprealm (w/o inode) on " << inodeno_t(p->ino) << " seq " << p->seq << dendl; mdcache->add_reconnected_snaprealm(from, inodeno_t(p->ino), snapid_t(p->seq)); } } // caps for (map::iterator p = m->caps.begin(); p != m->caps.end(); ++p) { // make sure our last_cap_id is MAX over all issued caps if (p->second.capinfo.cap_id > mdcache->last_cap_id) mdcache->last_cap_id = p->second.capinfo.cap_id; CInode *in = mdcache->get_inode(p->first); if (in && in->state_test(CInode::STATE_PURGING)) continue; if (in && in->is_auth()) { // we recovered it, and it's ours. take note. dout(15) << "open cap realm " << inodeno_t(p->second.capinfo.snaprealm) << " on " << *in << dendl; in->reconnect_cap(from, p->second.capinfo, session); mds->mdcache->add_reconnected_cap(in, from, inodeno_t(p->second.capinfo.snaprealm)); recover_filelocks(in, p->second.flockbl, m->get_orig_source().num()); continue; } if (in && !in->is_auth()) { // not mine. dout(10) << "non-auth " << *in << ", will pass off to authority" << dendl; // add to cap export list. mdcache->rejoin_export_caps(p->first, from, p->second.capinfo, in->authority().first); } else { // don't know if the inode is mine dout(10) << "missing ino " << p->first << ", will load later" << dendl; mdcache->rejoin_recovered_caps(p->first, from, p->second, -1); } } // remove from gather set client_reconnect_gather.erase(from); if (client_reconnect_gather.empty()) reconnect_gather_finish(); m->put(); } void Server::reconnect_gather_finish() { dout(7) << "reconnect_gather_finish. failed on " << failed_reconnects << " clients" << dendl; mds->reconnect_done(); } void Server::reconnect_tick() { utime_t reconnect_end = reconnect_start; reconnect_end += g_conf->mds_reconnect_timeout; if (ceph_clock_now(g_ceph_context) >= reconnect_end && !client_reconnect_gather.empty()) { dout(10) << "reconnect timed out" << dendl; for (set::iterator p = client_reconnect_gather.begin(); p != client_reconnect_gather.end(); ++p) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(p->v)); assert(session); dout(1) << "reconnect gave up on " << session->info.inst << dendl; kill_session(session); failed_reconnects++; } client_reconnect_gather.clear(); reconnect_gather_finish(); } } void Server::recover_filelocks(CInode *in, bufferlist locks, int64_t client) { if (!locks.length()) return; int numlocks; ceph_filelock lock; bufferlist::iterator p = locks.begin(); ::decode(numlocks, p); for (int i = 0; i < numlocks; ++i) { ::decode(lock, p); lock.client = client; in->fcntl_locks.held_locks.insert(pair (lock.start, lock)); ++in->fcntl_locks.client_held_lock_counts[client]; } ::decode(numlocks, p); for (int i = 0; i < numlocks; ++i) { ::decode(lock, p); lock.client = client; in->flock_locks.held_locks.insert(pair (lock.start, lock)); ++in->flock_locks.client_held_lock_counts[client]; } } void Server::recall_client_state(float ratio) { int max_caps_per_client = (int)(g_conf->mds_cache_size * .8); int min_caps_per_client = 100; dout(10) << "recall_client_state " << ratio << ", caps per client " << min_caps_per_client << "-" << max_caps_per_client << dendl; set sessions; mds->sessionmap.get_client_session_set(sessions); for (set::const_iterator p = sessions.begin(); p != sessions.end(); ++p) { Session *session = *p; if (!session->is_open() || !session->info.inst.name.is_client()) continue; dout(10) << " session " << session->info.inst << " caps " << session->caps.size() << ", leases " << session->leases.size() << dendl; if (session->caps.size() > min_caps_per_client) { int newlim = (int)(session->caps.size() * ratio); if (newlim > max_caps_per_client) newlim = max_caps_per_client; MClientSession *m = new MClientSession(CEPH_SESSION_RECALL_STATE); m->head.max_caps = newlim; mds->send_message_client(m, session); } } } /******* * some generic stuff for finishing off requests */ void Server::journal_and_reply(MDRequestRef& mdr, CInode *in, CDentry *dn, LogEvent *le, Context *fin) { dout(10) << "journal_and_reply tracei " << in << " tracedn " << dn << dendl; // note trace items for eventual reply. mdr->tracei = in; if (in) mdr->pin(in); mdr->tracedn = dn; if (dn) mdr->pin(dn); early_reply(mdr, in, dn); mdr->committing = true; mdlog->submit_entry(le, fin); if (mdr->client_request && mdr->client_request->is_replay()) { if (mds->queue_one_replay()) { dout(10) << " queued next replay op" << dendl; } else { dout(10) << " journaled last replay op, flushing" << dendl; mdlog->flush(); } } else if (mdr->did_early_reply) mds->locker->drop_rdlocks(mdr.get()); else mdlog->flush(); } /* * send generic response (just an error code), clean up mdr */ void Server::reply_request(MDRequestRef& mdr, int r, CInode *tracei, CDentry *tracedn) { reply_request(mdr, new MClientReply(mdr->client_request, r), tracei, tracedn); } void Server::early_reply(MDRequestRef& mdr, CInode *tracei, CDentry *tracedn) { if (!g_conf->mds_early_reply) return; if (mdr->are_slaves()) { dout(10) << "early_reply - there are slaves, not allowed." << dendl; mds->mdlog->flush(); return; } if (mdr->alloc_ino) { dout(10) << "early_reply - allocated ino, not allowed" << dendl; return; } MClientRequest *req = mdr->client_request; entity_inst_t client_inst = req->get_source_inst(); if (client_inst.name.is_mds()) return; if (req->is_replay()) { dout(10) << " no early reply on replay op" << dendl; mds->mdlog->flush(); return; } MClientReply *reply = new MClientReply(mdr->client_request, 0); reply->set_unsafe(); // mark xlocks "done", indicating that we are exposing uncommitted changes. // //_rename_finish() does not send dentry link/unlink message to replicas. // so do not set xlocks on dentries "done", the xlocks prevent dentries // that have projected linkages from getting new replica. mds->locker->set_xlocks_done(mdr.get(), mdr->client_request->get_op() == CEPH_MDS_OP_RENAME); dout(10) << "early_reply " << reply->get_result() << " (" << cpp_strerror(reply->get_result()) << ") " << *req << dendl; if (tracei || tracedn) { if (tracei) mdr->cap_releases.erase(tracei->vino()); if (tracedn) mdr->cap_releases.erase(tracedn->get_dir()->get_inode()->vino()); set_trace_dist(mdr->session, reply, tracei, tracedn, mdr->snapid, mdr->client_request->get_dentry_wanted(), mdr); } reply->set_extra_bl(mdr->reply_extra_bl); messenger->send_message(reply, req->get_connection()); mdr->did_early_reply = true; mds->logger->inc(l_mds_reply); utime_t lat = ceph_clock_now(g_ceph_context) - mdr->client_request->get_recv_stamp(); mds->logger->tinc(l_mds_replyl, lat); dout(20) << "lat " << lat << dendl; } /* * send given reply * include a trace to tracei * Clean up mdr */ void Server::reply_request(MDRequestRef& mdr, MClientReply *reply, CInode *tracei, CDentry *tracedn) { assert(mdr.get()); MClientRequest *req = mdr->client_request; dout(10) << "reply_request " << reply->get_result() << " (" << cpp_strerror(reply->get_result()) << ") " << *req << dendl; // note successful request in session map? if (req->may_write() && mdr->session && reply->get_result() == 0) mdr->session->add_completed_request(mdr->reqid.tid, mdr->alloc_ino); // give any preallocated inos to the session apply_allocated_inos(mdr); // get tracei/tracedn from mdr? snapid_t snapid = mdr->snapid; if (!tracei) tracei = mdr->tracei; if (!tracedn) tracedn = mdr->tracedn; bool is_replay = mdr->client_request->is_replay(); bool did_early_reply = mdr->did_early_reply; Session *session = mdr->session; entity_inst_t client_inst = req->get_source_inst(); int dentry_wanted = req->get_dentry_wanted(); if (!did_early_reply && !is_replay) { mds->logger->inc(l_mds_reply); utime_t lat = ceph_clock_now(g_ceph_context) - mdr->client_request->get_recv_stamp(); mds->logger->tinc(l_mds_replyl, lat); dout(20) << "lat " << lat << dendl; if (tracei) mdr->cap_releases.erase(tracei->vino()); if (tracedn) mdr->cap_releases.erase(tracedn->get_dir()->get_inode()->vino()); } // note client connection to direct my reply ConnectionRef client_con = req->get_connection(); // drop non-rdlocks before replying, so that we can issue leases mdcache->request_drop_non_rdlocks(mdr); // reply at all? if (client_inst.name.is_mds()) { reply->put(); // mds doesn't need a reply reply = 0; } else { // send reply. if (!did_early_reply && // don't issue leases if we sent an earlier reply already (tracei || tracedn)) { if (is_replay) { if (tracei) mdcache->try_reconnect_cap(tracei, session); } else { // include metadata in reply set_trace_dist(session, reply, tracei, tracedn, snapid, dentry_wanted, mdr); } } reply->set_mdsmap_epoch(mds->mdsmap->get_epoch()); messenger->send_message(reply, client_con); } // clean up request mdcache->request_finish(mdr); // take a closer look at tracei, if it happens to be a remote link if (tracei && tracei->get_parent_dn() && tracei->get_parent_dn()->get_projected_linkage()->is_remote()) mdcache->eval_remote(tracei->get_parent_dn()); } void Server::encode_empty_dirstat(bufferlist& bl) { static DirStat empty; empty.encode(bl); } void Server::encode_infinite_lease(bufferlist& bl) { LeaseStat e; e.seq = 0; e.mask = -1; e.duration_ms = -1; ::encode(e, bl); dout(20) << "encode_infinite_lease " << e << dendl; } void Server::encode_null_lease(bufferlist& bl) { LeaseStat e; e.seq = 0; e.mask = 0; e.duration_ms = 0; ::encode(e, bl); dout(20) << "encode_null_lease " << e << dendl; } /* * pass inode OR dentry (not both, or we may get confused) * * trace is in reverse order (i.e. root inode comes last) */ void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn, snapid_t snapid, int dentry_wanted, MDRequestRef& mdr) { // skip doing this for debugging purposes? if (g_conf->mds_inject_traceless_reply_probability && mdr->ls && !mdr->o_trunc && (rand() % 10000 < g_conf->mds_inject_traceless_reply_probability * 10000.0)) { dout(5) << "deliberately skipping trace for " << *reply << dendl; return; } // inode, dentry, dir, ..., inode bufferlist bl; int whoami = mds->get_nodeid(); client_t client = session->get_client(); utime_t now = ceph_clock_now(g_ceph_context); dout(20) << "set_trace_dist snapid " << snapid << dendl; //assert((bool)dn == (bool)dentry_wanted); // not true for snapshot lookups // realm SnapRealm *realm = 0; if (in) realm = in->find_snaprealm(); else realm = dn->get_dir()->get_inode()->find_snaprealm(); reply->snapbl = realm->get_snap_trace(); dout(10) << "set_trace_dist snaprealm " << *realm << " len=" << reply->snapbl.length() << dendl; // dir + dentry? if (dn) { reply->head.is_dentry = 1; CDir *dir = dn->get_dir(); CInode *diri = dir->get_inode(); diri->encode_inodestat(bl, session, NULL, snapid); dout(20) << "set_trace_dist added diri " << *diri << dendl; #ifdef MDS_VERIFY_FRAGSTAT if (dir->is_complete()) dir->verify_fragstat(); #endif dir->encode_dirstat(bl, whoami); dout(20) << "set_trace_dist added dir " << *dir << dendl; ::encode(dn->get_name(), bl); if (snapid == CEPH_NOSNAP) mds->locker->issue_client_lease(dn, client, bl, now, session); else encode_null_lease(bl); dout(20) << "set_trace_dist added dn " << snapid << " " << *dn << dendl; } else reply->head.is_dentry = 0; // inode if (in) { in->encode_inodestat(bl, session, NULL, snapid, 0, mdr->getattr_caps); dout(20) << "set_trace_dist added in " << *in << dendl; reply->head.is_target = 1; } else reply->head.is_target = 0; reply->set_trace(bl); } /*** * process a client request * This function DOES put the passed message before returning */ void Server::handle_client_request(MClientRequest *req) { dout(4) << "handle_client_request " << *req << dendl; if (logger) logger->inc(l_mdss_hcreq); if (!mdcache->is_open()) { dout(5) << "waiting for root" << dendl; mdcache->wait_for_open(new C_MDS_RetryMessage(mds, req)); return; } // active session? Session *session = 0; if (req->get_source().is_client()) { session = get_session(req); if (!session) { dout(5) << "no session for " << req->get_source() << ", dropping" << dendl; req->put(); return; } if (session->is_closed() || session->is_closing() || session->is_killing()) { dout(5) << "session closed|closing|killing, dropping" << dendl; req->put(); return; } } // old mdsmap? if (req->get_mdsmap_epoch() < mds->mdsmap->get_epoch()) { // send it? hrm, this isn't ideal; they may get a lot of copies if // they have a high request rate. } // completed request? if (req->is_replay() || (req->get_retry_attempt() && req->get_op() != CEPH_MDS_OP_OPEN && req->get_op() != CEPH_MDS_OP_CREATE)) { assert(session); inodeno_t created; if (session->have_completed_request(req->get_reqid().tid, &created)) { dout(5) << "already completed " << req->get_reqid() << dendl; MClientReply *reply = new MClientReply(req, 0); if (created != inodeno_t()) { bufferlist extra; ::encode(created, extra); reply->set_extra_bl(extra); } mds->messenger->send_message(reply, req->get_connection()); if (req->is_replay()) mds->queue_one_replay(); req->put(); return; } } // trim completed_request list if (req->get_oldest_client_tid() > 0) { dout(15) << " oldest_client_tid=" << req->get_oldest_client_tid() << dendl; assert(session); session->trim_completed_requests(req->get_oldest_client_tid()); } // register + dispatch MDRequestRef mdr = mdcache->request_start(req); if (mdr.get()) { if (session) { mdr->session = session; session->requests.push_back(&mdr->item_session_request); } } // process embedded cap releases? // (only if NOT replay!) if (!req->releases.empty() && req->get_source().is_client() && !req->is_replay()) { client_t client = req->get_source().num(); for (vector::iterator p = req->releases.begin(); p != req->releases.end(); ++p) mds->locker->process_request_cap_release(mdr, client, p->item, p->dname); req->releases.clear(); } if (mdr.get()) dispatch_client_request(mdr); return; } void Server::dispatch_client_request(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; if (logger) logger->inc(l_mdss_dcreq); dout(7) << "dispatch_client_request " << *req << dendl; // we shouldn't be waiting on anyone. assert(mdr->more()->waiting_on_slave.empty()); switch (req->get_op()) { case CEPH_MDS_OP_LOOKUPHASH: case CEPH_MDS_OP_LOOKUPINO: handle_client_lookup_ino(mdr, false, false); break; case CEPH_MDS_OP_LOOKUPPARENT: handle_client_lookup_ino(mdr, true, false); break; case CEPH_MDS_OP_LOOKUPNAME: handle_client_lookup_ino(mdr, false, true); break; // inodes ops. case CEPH_MDS_OP_LOOKUP: handle_client_getattr(mdr, true); break; case CEPH_MDS_OP_LOOKUPSNAP: // lookupsnap does not reference a CDentry; treat it as a getattr case CEPH_MDS_OP_GETATTR: handle_client_getattr(mdr, false); break; case CEPH_MDS_OP_SETATTR: handle_client_setattr(mdr); break; case CEPH_MDS_OP_SETLAYOUT: handle_client_setlayout(mdr); break; case CEPH_MDS_OP_SETDIRLAYOUT: handle_client_setdirlayout(mdr); break; case CEPH_MDS_OP_SETXATTR: handle_client_setxattr(mdr); break; case CEPH_MDS_OP_RMXATTR: handle_client_removexattr(mdr); break; case CEPH_MDS_OP_READDIR: handle_client_readdir(mdr); break; case CEPH_MDS_OP_SETFILELOCK: handle_client_file_setlock(mdr); break; case CEPH_MDS_OP_GETFILELOCK: handle_client_file_readlock(mdr); break; // funky. case CEPH_MDS_OP_CREATE: if (req->get_retry_attempt() && mdr->session->have_completed_request(req->get_reqid().tid, NULL)) handle_client_open(mdr); // already created.. just open else handle_client_openc(mdr); break; case CEPH_MDS_OP_OPEN: handle_client_open(mdr); break; // namespace. // no prior locks. case CEPH_MDS_OP_MKNOD: handle_client_mknod(mdr); break; case CEPH_MDS_OP_LINK: handle_client_link(mdr); break; case CEPH_MDS_OP_UNLINK: case CEPH_MDS_OP_RMDIR: handle_client_unlink(mdr); break; case CEPH_MDS_OP_RENAME: handle_client_rename(mdr); break; case CEPH_MDS_OP_MKDIR: handle_client_mkdir(mdr); break; case CEPH_MDS_OP_SYMLINK: handle_client_symlink(mdr); break; // snaps case CEPH_MDS_OP_LSSNAP: handle_client_lssnap(mdr); break; case CEPH_MDS_OP_MKSNAP: handle_client_mksnap(mdr); break; case CEPH_MDS_OP_RMSNAP: handle_client_rmsnap(mdr); break; default: dout(1) << " unknown client op " << req->get_op() << dendl; reply_request(mdr, -EOPNOTSUPP); } } // --------------------------------------- // SLAVE REQUESTS /* This function DOES put the passed message before returning*/ void Server::handle_slave_request(MMDSSlaveRequest *m) { dout(4) << "handle_slave_request " << m->get_reqid() << " from " << m->get_source() << dendl; int from = m->get_source().num(); if (logger) logger->inc(l_mdss_hsreq); // reply? if (m->is_reply()) return handle_slave_request_reply(m); // the purpose of rename notify is enforcing causal message ordering. making sure // bystanders have received all messages from rename srcdn's auth MDS. if (m->get_op() == MMDSSlaveRequest::OP_RENAMENOTIFY) { MMDSSlaveRequest *reply = new MMDSSlaveRequest(m->get_reqid(), m->get_attempt(), MMDSSlaveRequest::OP_RENAMENOTIFYACK); mds->send_message(reply, m->get_connection()); m->put(); return; } CDentry *straydn = NULL; if (m->stray.length() > 0) { straydn = mdcache->add_replica_stray(m->stray, from); assert(straydn); m->stray.clear(); } // am i a new slave? MDRequestRef mdr; if (mdcache->have_request(m->get_reqid())) { // existing? mdr = mdcache->request_get(m->get_reqid()); // is my request newer? if (mdr->attempt > m->get_attempt()) { dout(10) << "local request " << *mdr << " attempt " << mdr->attempt << " > " << m->get_attempt() << ", dropping " << *m << dendl; m->put(); return; } if (mdr->attempt < m->get_attempt()) { // mine is old, close it out dout(10) << "local request " << *mdr << " attempt " << mdr->attempt << " < " << m->get_attempt() << ", closing out" << dendl; mdcache->request_finish(mdr); mdr.reset(); } else if (mdr->slave_to_mds != from) { dout(10) << "local request " << *mdr << " not slave to mds." << from << dendl; m->put(); return; } } if (!mdr.get()) { // new? if (m->get_op() == MMDSSlaveRequest::OP_FINISH) { dout(10) << "missing slave request for " << m->get_reqid() << " OP_FINISH, must have lost race with a forward" << dendl; m->put(); return; } mdr = mdcache->request_start_slave(m->get_reqid(), m->get_attempt(), from); } assert(mdr->slave_request == 0); // only one at a time, please! if (straydn) { mdr->pin(straydn); mdr->straydn = straydn; } if (!mds->is_clientreplay() && !mds->is_active() && !mds->is_stopping()) { dout(3) << "not clientreplay|active yet, waiting" << dendl; mds->wait_for_replay(new C_MDS_RetryMessage(mds, m)); return; } else if (mds->is_clientreplay() && !mds->mdsmap->is_clientreplay(from) && mdr->locks.empty()) { dout(3) << "not active yet, waiting" << dendl; mds->wait_for_active(new C_MDS_RetryMessage(mds, m)); return; } mdr->slave_request = m; dispatch_slave_request(mdr); } /* This function DOES put the passed message before returning*/ void Server::handle_slave_request_reply(MMDSSlaveRequest *m) { int from = m->get_source().num(); if (!mds->is_clientreplay() && !mds->is_active() && !mds->is_stopping()) { dout(3) << "not clientreplay|active yet, waiting" << dendl; mds->wait_for_replay(new C_MDS_RetryMessage(mds, m)); return; } if (m->get_op() == MMDSSlaveRequest::OP_COMMITTED) { metareqid_t r = m->get_reqid(); mds->mdcache->committed_master_slave(r, from); m->put(); return; } MDRequestRef mdr = mdcache->request_get(m->get_reqid()); if (!mdr.get()) { dout(10) << "handle_slave_request_reply ignoring reply from unknown reqid " << m->get_reqid() << dendl; m->put(); return; } if (m->get_attempt() != mdr->attempt) { dout(10) << "handle_slave_request_reply " << *mdr << " ignoring reply from other attempt " << m->get_attempt() << dendl; m->put(); return; } switch (m->get_op()) { case MMDSSlaveRequest::OP_XLOCKACK: { // identify lock, master request SimpleLock *lock = mds->locker->get_lock(m->get_lock_type(), m->get_object_info()); mdr->more()->slaves.insert(from); dout(10) << "got remote xlock on " << *lock << " on " << *lock->get_parent() << dendl; mdr->xlocks.insert(lock); mdr->locks.insert(lock); mdr->finish_locking(lock); lock->get_xlock(mdr, mdr->get_client()); assert(mdr->more()->waiting_on_slave.count(from)); mdr->more()->waiting_on_slave.erase(from); assert(mdr->more()->waiting_on_slave.empty()); mdcache->dispatch_request(mdr); } break; case MMDSSlaveRequest::OP_WRLOCKACK: { // identify lock, master request SimpleLock *lock = mds->locker->get_lock(m->get_lock_type(), m->get_object_info()); mdr->more()->slaves.insert(from); dout(10) << "got remote wrlock on " << *lock << " on " << *lock->get_parent() << dendl; mdr->remote_wrlocks[lock] = from; mdr->locks.insert(lock); mdr->finish_locking(lock); assert(mdr->more()->waiting_on_slave.count(from)); mdr->more()->waiting_on_slave.erase(from); assert(mdr->more()->waiting_on_slave.empty()); mdcache->dispatch_request(mdr); } break; case MMDSSlaveRequest::OP_AUTHPINACK: handle_slave_auth_pin_ack(mdr, m); break; case MMDSSlaveRequest::OP_LINKPREPACK: handle_slave_link_prep_ack(mdr, m); break; case MMDSSlaveRequest::OP_RMDIRPREPACK: handle_slave_rmdir_prep_ack(mdr, m); break; case MMDSSlaveRequest::OP_RENAMEPREPACK: handle_slave_rename_prep_ack(mdr, m); break; case MMDSSlaveRequest::OP_RENAMENOTIFYACK: handle_slave_rename_notify_ack(mdr, m); break; default: assert(0); } // done with reply. m->put(); } /* This function DOES put the mdr->slave_request before returning*/ void Server::dispatch_slave_request(MDRequestRef& mdr) { dout(7) << "dispatch_slave_request " << *mdr << " " << *mdr->slave_request << dendl; if (mdr->aborted) { dout(7) << " abort flag set, finishing" << dendl; mdcache->request_finish(mdr); return; } if (logger) logger->inc(l_mdss_dsreq); int op = mdr->slave_request->get_op(); switch (op) { case MMDSSlaveRequest::OP_XLOCK: case MMDSSlaveRequest::OP_WRLOCK: { // identify object SimpleLock *lock = mds->locker->get_lock(mdr->slave_request->get_lock_type(), mdr->slave_request->get_object_info()); if (!lock) { dout(10) << "don't have object, dropping" << dendl; assert(0); // can this happen, if we auth pinned properly. } if (op == MMDSSlaveRequest::OP_XLOCK && !lock->get_parent()->is_auth()) { dout(10) << "not auth for remote xlock attempt, dropping on " << *lock << " on " << *lock->get_parent() << dendl; } else { // use acquire_locks so that we get auth_pinning. set rdlocks; set wrlocks = mdr->wrlocks; set xlocks = mdr->xlocks; int replycode = 0; switch (op) { case MMDSSlaveRequest::OP_XLOCK: xlocks.insert(lock); replycode = MMDSSlaveRequest::OP_XLOCKACK; break; case MMDSSlaveRequest::OP_WRLOCK: wrlocks.insert(lock); replycode = MMDSSlaveRequest::OP_WRLOCKACK; break; } if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // ack MMDSSlaveRequest *r = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, replycode); r->set_lock_type(lock->get_type()); lock->get_parent()->set_object_info(r->get_object_info()); mds->send_message(r, mdr->slave_request->get_connection()); } // done. mdr->slave_request->put(); mdr->slave_request = 0; } break; case MMDSSlaveRequest::OP_UNXLOCK: case MMDSSlaveRequest::OP_UNWRLOCK: { SimpleLock *lock = mds->locker->get_lock(mdr->slave_request->get_lock_type(), mdr->slave_request->get_object_info()); assert(lock); bool need_issue = false; switch (op) { case MMDSSlaveRequest::OP_UNXLOCK: mds->locker->xlock_finish(lock, mdr.get(), &need_issue); break; case MMDSSlaveRequest::OP_UNWRLOCK: mds->locker->wrlock_finish(lock, mdr.get(), &need_issue); break; } if (need_issue) mds->locker->issue_caps(static_cast(lock->get_parent())); // done. no ack necessary. mdr->slave_request->put(); mdr->slave_request = 0; } break; case MMDSSlaveRequest::OP_DROPLOCKS: mds->locker->drop_locks(mdr.get()); mdr->slave_request->put(); mdr->slave_request = 0; break; case MMDSSlaveRequest::OP_AUTHPIN: handle_slave_auth_pin(mdr); break; case MMDSSlaveRequest::OP_LINKPREP: case MMDSSlaveRequest::OP_UNLINKPREP: handle_slave_link_prep(mdr); break; case MMDSSlaveRequest::OP_RMDIRPREP: handle_slave_rmdir_prep(mdr); break; case MMDSSlaveRequest::OP_RENAMEPREP: handle_slave_rename_prep(mdr); break; case MMDSSlaveRequest::OP_FINISH: // information about rename imported caps if (mdr->slave_request->inode_export.length() > 0) mdr->more()->inode_import.claim(mdr->slave_request->inode_export); // finish off request. mdcache->request_finish(mdr); break; default: assert(0); } } /* This function DOES put the mdr->slave_request before returning*/ void Server::handle_slave_auth_pin(MDRequestRef& mdr) { dout(10) << "handle_slave_auth_pin " << *mdr << dendl; // build list of objects list objects; CInode *auth_pin_freeze = NULL; bool fail = false, wouldblock = false; for (vector::iterator p = mdr->slave_request->get_authpins().begin(); p != mdr->slave_request->get_authpins().end(); ++p) { MDSCacheObject *object = mdcache->get_object(*p); if (!object) { dout(10) << " don't have " << *p << dendl; fail = true; break; } objects.push_back(object); if (*p == mdr->slave_request->get_authpin_freeze()) auth_pin_freeze = static_cast(object); } // can we auth pin them? if (!fail) { for (list::iterator p = objects.begin(); p != objects.end(); ++p) { if (!(*p)->is_auth()) { dout(10) << " not auth for " << **p << dendl; fail = true; break; } if (!mdr->can_auth_pin(*p)) { if (mdr->slave_request->is_nonblock()) { dout(10) << " can't auth_pin (freezing?) " << **p << " nonblocking" << dendl; fail = true; wouldblock = true; break; } // wait dout(10) << " waiting for authpinnable on " << **p << dendl; (*p)->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); mdr->drop_local_auth_pins(); CDir *dir = NULL; if (CInode *in = dynamic_cast(*p)) { if (!in->is_root()) dir = in->get_parent_dir(); } else if (CDentry *dn = dynamic_cast(*p)) { dir = dn->get_dir(); } else { assert(0); } if (dir) { if (dir->is_freezing_dir()) mdcache->fragment_freeze_inc_num_waiters(dir); if (dir->is_freezing_tree()) { while (!dir->is_freezing_tree_root()) dir = dir->get_parent_dir(); mdcache->migrator->export_freeze_inc_num_waiters(dir); } } return; } } } // auth pin! if (fail) { mdr->drop_local_auth_pins(); // just in case } else { /* freeze authpin wrong inode */ if (mdr->has_more() && mdr->more()->is_freeze_authpin && mdr->more()->rename_inode != auth_pin_freeze) mdr->unfreeze_auth_pin(true); /* handle_slave_rename_prep() call freeze_inode() to wait for all other operations * on the source inode to complete. This happens after all locks for the rename * operation are acquired. But to acquire locks, we need auth pin locks' parent * objects first. So there is an ABBA deadlock if someone auth pins the source inode * after locks are acquired and before Server::handle_slave_rename_prep() is called. * The solution is freeze the inode and prevent other MDRequests from getting new * auth pins. */ if (auth_pin_freeze) { dout(10) << " freezing auth pin on " << *auth_pin_freeze << dendl; if (!mdr->freeze_auth_pin(auth_pin_freeze)) { auth_pin_freeze->add_waiter(CInode::WAIT_FROZEN, new C_MDS_RetryRequest(mdcache, mdr)); mds->mdlog->flush(); return; } } for (list::iterator p = objects.begin(); p != objects.end(); ++p) { dout(10) << "auth_pinning " << **p << dendl; mdr->auth_pin(*p); } } // ack! MMDSSlaveRequest *reply = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_AUTHPINACK); // return list of my auth_pins (if any) for (set::iterator p = mdr->auth_pins.begin(); p != mdr->auth_pins.end(); ++p) { MDSCacheObjectInfo info; (*p)->set_object_info(info); reply->get_authpins().push_back(info); } if (auth_pin_freeze) auth_pin_freeze->set_object_info(reply->get_authpin_freeze()); if (wouldblock) reply->mark_error_wouldblock(); mds->send_message_mds(reply, mdr->slave_to_mds); // clean up this request mdr->slave_request->put(); mdr->slave_request = 0; return; } /* This function DOES NOT put the passed ack before returning*/ void Server::handle_slave_auth_pin_ack(MDRequestRef& mdr, MMDSSlaveRequest *ack) { dout(10) << "handle_slave_auth_pin_ack on " << *mdr << " " << *ack << dendl; int from = ack->get_source().num(); // added auth pins? set pinned; for (vector::iterator p = ack->get_authpins().begin(); p != ack->get_authpins().end(); ++p) { MDSCacheObject *object = mdcache->get_object(*p); assert(object); // we pinned it dout(10) << " remote has pinned " << *object << dendl; if (!mdr->is_auth_pinned(object)) mdr->remote_auth_pins.insert(object); if (*p == ack->get_authpin_freeze()) mdr->set_remote_frozen_auth_pin(static_cast(object)); pinned.insert(object); } // removed auth pins? set::iterator p = mdr->remote_auth_pins.begin(); while (p != mdr->remote_auth_pins.end()) { if ((*p)->authority().first == from && pinned.count(*p) == 0) { dout(10) << " remote has unpinned " << **p << dendl; set::iterator o = p; ++p; mdr->remote_auth_pins.erase(o); } else { ++p; } } if (ack->is_error_wouldblock()) mdr->aborted = true; // note slave mdr->more()->slaves.insert(from); // clear from waiting list assert(mdr->more()->waiting_on_slave.count(from)); mdr->more()->waiting_on_slave.erase(from); // go again? if (mdr->more()->waiting_on_slave.empty()) mdcache->dispatch_request(mdr); else dout(10) << "still waiting on slaves " << mdr->more()->waiting_on_slave << dendl; } // --------------------------------------- // HELPERS /** validate_dentry_dir * * verify that the dir exists and would own the dname. * do not check if the dentry exists. */ CDir *Server::validate_dentry_dir(MDRequestRef& mdr, CInode *diri, const string& dname) { // make sure parent is a dir? if (!diri->is_dir()) { dout(7) << "validate_dentry_dir: not a dir" << dendl; reply_request(mdr, -ENOTDIR); return NULL; } // which dirfrag? frag_t fg = diri->pick_dirfrag(dname); CDir *dir = try_open_auth_dirfrag(diri, fg, mdr); if (!dir) return 0; // frozen? if (dir->is_frozen()) { dout(7) << "dir is frozen " << *dir << dendl; dir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); return NULL; } return dir; } /** prepare_null_dentry * prepare a null (or existing) dentry in given dir. * wait for any dn lock. */ CDentry* Server::prepare_null_dentry(MDRequestRef& mdr, CDir *dir, const string& dname, bool okexist) { dout(10) << "prepare_null_dentry " << dname << " in " << *dir << dendl; assert(dir->is_auth()); client_t client = mdr->get_client(); // does it already exist? CDentry *dn = dir->lookup(dname); if (dn) { /* if (dn->lock.is_xlocked_by_other(mdr)) { dout(10) << "waiting on xlocked dentry " << *dn << dendl; dn->lock.add_waiter(SimpleLock::WAIT_RD, new C_MDS_RetryRequest(mdcache, mdr)); return 0; } */ if (!dn->get_linkage(client, mdr)->is_null()) { // name already exists dout(10) << "dentry " << dname << " exists in " << *dir << dendl; if (!okexist) { reply_request(mdr, -EEXIST); return 0; } } return dn; } // make sure dir is complete if (!dir->is_complete() && (!dir->has_bloom() || dir->is_in_bloom(dname))) { dout(7) << " incomplete dir contents for " << *dir << ", fetching" << dendl; dir->fetch(new C_MDS_RetryRequest(mdcache, mdr)); return 0; } // create dn = dir->add_null_dentry(dname); dn->mark_new(); dout(10) << "prepare_null_dentry added " << *dn << dendl; return dn; } CDentry* Server::prepare_stray_dentry(MDRequestRef& mdr, CInode *in) { CDentry *straydn = mdr->straydn; if (straydn) { string name; in->name_stray_dentry(name); if (straydn->get_name() == name) return straydn; assert(!mdr->done_locking); mdr->unpin(straydn); } straydn = mdcache->get_or_create_stray_dentry(in); mdr->straydn = straydn; mdr->pin(straydn); return straydn; } /** prepare_new_inode * * create a new inode. set c/m/atime. hit dir pop. */ CInode* Server::prepare_new_inode(MDRequestRef& mdr, CDir *dir, inodeno_t useino, unsigned mode, ceph_file_layout *layout) { CInode *in = new CInode(mdcache); // assign ino if (mdr->session->info.prealloc_inos.size()) { mdr->used_prealloc_ino = in->inode.ino = mdr->session->take_ino(useino); // prealloc -> used mds->sessionmap.projected++; dout(10) << "prepare_new_inode used_prealloc " << mdr->used_prealloc_ino << " (" << mdr->session->info.prealloc_inos << ", " << mdr->session->info.prealloc_inos.size() << " left)" << dendl; } else { mdr->alloc_ino = in->inode.ino = mds->inotable->project_alloc_id(); dout(10) << "prepare_new_inode alloc " << mdr->alloc_ino << dendl; } if (useino && useino != in->inode.ino) { dout(0) << "WARNING: client specified " << useino << " and i allocated " << in->inode.ino << dendl; mds->clog.error() << mdr->client_request->get_source() << " specified ino " << useino << " but mds." << mds->whoami << " allocated " << in->inode.ino << "\n"; //assert(0); // just for now. } int got = g_conf->mds_client_prealloc_inos - mdr->session->get_num_projected_prealloc_inos(); if (got > 0) { mds->inotable->project_alloc_ids(mdr->prealloc_inos, got); assert(mdr->prealloc_inos.size()); // or else fix projected increment semantics mdr->session->pending_prealloc_inos.insert(mdr->prealloc_inos); mds->sessionmap.projected++; dout(10) << "prepare_new_inode prealloc " << mdr->prealloc_inos << dendl; } in->inode.version = 1; in->inode.nlink = 1; // FIXME in->inode.mode = mode; memset(&in->inode.dir_layout, 0, sizeof(in->inode.dir_layout)); if (in->inode.is_dir()) { in->inode.dir_layout.dl_dir_hash = g_conf->mds_default_dir_hash; memset(&in->inode.layout, 0, sizeof(in->inode.layout)); } else if (layout) { in->inode.layout = *layout; } else { in->inode.layout = mds->mdcache->default_file_layout; } in->inode.truncate_size = -1ull; // not truncated, yet! in->inode.truncate_seq = 1; /* starting with 1, 0 is kept for no-truncation logic */ CInode *diri = dir->get_inode(); dout(10) << oct << " dir mode 0" << diri->inode.mode << " new mode 0" << mode << dec << dendl; if (diri->inode.mode & S_ISGID) { dout(10) << " dir is sticky" << dendl; in->inode.gid = diri->inode.gid; if (S_ISDIR(mode)) { dout(10) << " new dir also sticky" << dendl; in->inode.mode |= S_ISGID; } } else in->inode.gid = mdr->client_request->get_caller_gid(); in->inode.uid = mdr->client_request->get_caller_uid(); in->inode.ctime = in->inode.mtime = in->inode.atime = mdr->now; // now MClientRequest *req = mdr->client_request; if (req->get_data().length()) { bufferlist::iterator p = req->get_data().begin(); // xattrs on new inode? map xattrs; ::decode(xattrs, p); for (map::iterator p = xattrs.begin(); p != xattrs.end(); ++p) { dout(10) << "prepare_new_inode setting xattr " << p->first << dendl; in->xattrs[p->first] = p->second; } } if (!mds->mdsmap->get_inline_data_enabled() || !mdr->session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) in->inode.inline_version = CEPH_INLINE_NONE; mdcache->add_inode(in); // add dout(10) << "prepare_new_inode " << *in << dendl; return in; } void Server::journal_allocated_inos(MDRequestRef& mdr, EMetaBlob *blob) { dout(20) << "journal_allocated_inos sessionmapv " << mds->sessionmap.projected << " inotablev " << mds->inotable->get_projected_version() << dendl; blob->set_ino_alloc(mdr->alloc_ino, mdr->used_prealloc_ino, mdr->prealloc_inos, mdr->client_request->get_source(), mds->sessionmap.projected, mds->inotable->get_projected_version()); } void Server::apply_allocated_inos(MDRequestRef& mdr) { Session *session = mdr->session; dout(10) << "apply_allocated_inos " << mdr->alloc_ino << " / " << mdr->prealloc_inos << " / " << mdr->used_prealloc_ino << dendl; if (mdr->alloc_ino) { mds->inotable->apply_alloc_id(mdr->alloc_ino); } if (mdr->prealloc_inos.size()) { assert(session); session->pending_prealloc_inos.subtract(mdr->prealloc_inos); session->info.prealloc_inos.insert(mdr->prealloc_inos); mds->sessionmap.version++; mds->inotable->apply_alloc_ids(mdr->prealloc_inos); } if (mdr->used_prealloc_ino) { assert(session); session->info.used_inos.erase(mdr->used_prealloc_ino); mds->sessionmap.version++; } } CDir *Server::traverse_to_auth_dir(MDRequestRef& mdr, vector &trace, filepath refpath) { // figure parent dir vs dname if (refpath.depth() == 0) { dout(7) << "can't do that to root" << dendl; reply_request(mdr, -EINVAL); return 0; } string dname = refpath.last_dentry(); refpath.pop_dentry(); dout(10) << "traverse_to_auth_dir dirpath " << refpath << " dname " << dname << dendl; // traverse to parent dir CInode *diri; int r = mdcache->path_traverse(mdr, NULL, NULL, refpath, &trace, &diri, MDS_TRAVERSE_FORWARD); if (r > 0) return 0; // delayed if (r < 0) { reply_request(mdr, r); return 0; } // is it an auth dir? CDir *dir = validate_dentry_dir(mdr, diri, dname); if (!dir) return 0; // forwarded or waiting for freeze dout(10) << "traverse_to_auth_dir " << *dir << dendl; return dir; } class C_MDS_TryFindInode : public Context { Server *server; MDRequestRef mdr; public: C_MDS_TryFindInode(Server *s, MDRequestRef& r) : server(s), mdr(r) {} virtual void finish(int r) { if (r == -ESTALE) // :( find_ino_peers failed server->reply_request(mdr, r); else server->dispatch_client_request(mdr); } }; /* If this returns null, the request has been handled * as appropriate: forwarded on, or the client's been replied to */ CInode* Server::rdlock_path_pin_ref(MDRequestRef& mdr, int n, set &rdlocks, bool want_auth, bool no_want_auth, /* for readdir, who doesn't want auth _even_if_ it's a snapped dir */ ceph_file_layout **layout, bool no_lookup) // true if we cannot return a null dentry lease { MClientRequest *req = mdr->client_request; const filepath& refpath = n ? req->get_filepath2() : req->get_filepath(); dout(10) << "rdlock_path_pin_ref " << *mdr << " " << refpath << dendl; if (mdr->done_locking) return mdr->in[n]; // traverse int r = mdcache->path_traverse(mdr, NULL, NULL, refpath, &mdr->dn[n], &mdr->in[n], MDS_TRAVERSE_FORWARD); if (r > 0) return NULL; // delayed if (r < 0) { // error if (r == -ENOENT && n == 0 && mdr->dn[n].size()) { reply_request(mdr, r, NULL, no_lookup ? NULL : mdr->dn[n][mdr->dn[n].size()-1]); } else if (r == -ESTALE) { dout(10) << "FAIL on ESTALE but attempting recovery" << dendl; Context *c = new C_MDS_TryFindInode(this, mdr); mdcache->find_ino_peers(refpath.get_ino(), c); } else { dout(10) << "FAIL on error " << r << dendl; reply_request(mdr, r); } return 0; } CInode *ref = mdr->in[n]; dout(10) << "ref is " << *ref << dendl; // fw to inode auth? if (mdr->snapid != CEPH_NOSNAP && !no_want_auth) want_auth = true; if (want_auth) { if (ref->is_ambiguous_auth()) { dout(10) << "waiting for single auth on " << *ref << dendl; ref->add_waiter(CInode::WAIT_SINGLEAUTH, new C_MDS_RetryRequest(mdcache, mdr)); return 0; } if (!ref->is_auth()) { dout(10) << "fw to auth for " << *ref << dendl; mdcache->request_forward(mdr, ref->authority().first); return 0; } // auth_pin? // do NOT proceed if freezing, as cap release may defer in that case, and // we could deadlock when we try to lock @ref. // if we're already auth_pinned, continue; the release has already been processed. if (ref->is_frozen() || ref->is_frozen_auth_pin() || (ref->is_freezing() && !mdr->is_auth_pinned(ref))) { dout(7) << "waiting for !frozen/authpinnable on " << *ref << dendl; ref->add_waiter(CInode::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); /* If we have any auth pins, this will deadlock. * But the only way to get here if we've already got auth pins * is because we're on an inode with snapshots that got updated * between dispatches of this request. So we're going to drop * our locks and our auth pins and reacquire them later. * * This is safe since we're only in this function when working on * a single MDS request; otherwise we'd be in * rdlock_path_xlock_dentry. */ mds->locker->drop_locks(mdr.get(), NULL); mdr->drop_local_auth_pins(); return 0; } mdr->auth_pin(ref); } for (int i=0; i<(int)mdr->dn[n].size(); i++) rdlocks.insert(&mdr->dn[n][i]->lock); if (layout) mds->locker->include_snap_rdlocks_wlayout(rdlocks, ref, layout); else mds->locker->include_snap_rdlocks(rdlocks, ref); // set and pin ref mdr->pin(ref); return ref; } /** rdlock_path_xlock_dentry * traverse path to the directory that could/would contain dentry. * make sure i am auth for that dentry, forward as necessary. * create null dentry in place (or use existing if okexist). * get rdlocks on traversed dentries, xlock on new dentry. */ CDentry* Server::rdlock_path_xlock_dentry(MDRequestRef& mdr, int n, set& rdlocks, set& wrlocks, set& xlocks, bool okexist, bool mustexist, bool alwaysxlock, ceph_file_layout **layout) { MClientRequest *req = mdr->client_request; const filepath& refpath = n ? req->get_filepath2() : req->get_filepath(); dout(10) << "rdlock_path_xlock_dentry " << *mdr << " " << refpath << dendl; client_t client = mdr->get_client(); if (mdr->done_locking) return mdr->dn[n].back(); CDir *dir = traverse_to_auth_dir(mdr, mdr->dn[n], refpath); if (!dir) return 0; dout(10) << "rdlock_path_xlock_dentry dir " << *dir << dendl; // make sure we can auth_pin (or have already authpinned) dir if (dir->is_frozen()) { dout(7) << "waiting for !frozen/authpinnable on " << *dir << dendl; dir->add_waiter(CInode::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); return 0; } CInode *diri = dir->get_inode(); if (!mdr->reqid.name.is_mds()) { if (diri->is_system() && !diri->is_root()) { reply_request(mdr, -EROFS); return 0; } if (!diri->is_base() && diri->get_projected_parent_dir()->inode->is_stray()) { reply_request(mdr, -ENOENT); return 0; } } // make a null dentry? const string &dname = refpath.last_dentry(); CDentry *dn; if (mustexist) { dn = dir->lookup(dname); // make sure dir is complete if (!dn && !dir->is_complete() && (!dir->has_bloom() || dir->is_in_bloom(dname))) { dout(7) << " incomplete dir contents for " << *dir << ", fetching" << dendl; dir->fetch(new C_MDS_RetryRequest(mdcache, mdr)); return 0; } // readable? if (dn && !dn->lock.can_read(client) && dn->lock.get_xlock_by() != mdr) { dout(10) << "waiting on xlocked dentry " << *dn << dendl; dn->lock.add_waiter(SimpleLock::WAIT_RD, new C_MDS_RetryRequest(mdcache, mdr)); return 0; } // exists? if (!dn || dn->get_linkage(client, mdr)->is_null()) { dout(7) << "dentry " << dname << " dne in " << *dir << dendl; reply_request(mdr, -ENOENT); return 0; } } else { dn = prepare_null_dentry(mdr, dir, dname, okexist); if (!dn) return 0; } mdr->dn[n].push_back(dn); mdr->in[n] = dn->get_projected_linkage()->get_inode(); // -- lock -- // NOTE: rename takes the same set of locks for srcdn for (int i=0; i<(int)mdr->dn[n].size(); i++) rdlocks.insert(&mdr->dn[n][i]->lock); if (alwaysxlock || dn->get_linkage(client, mdr)->is_null()) xlocks.insert(&dn->lock); // new dn, xlock else rdlocks.insert(&dn->lock); // existing dn, rdlock wrlocks.insert(&dn->get_dir()->inode->filelock); // also, wrlock on dir mtime wrlocks.insert(&dn->get_dir()->inode->nestlock); // also, wrlock on dir mtime if (layout) mds->locker->include_snap_rdlocks_wlayout(rdlocks, dn->get_dir()->inode, layout); else mds->locker->include_snap_rdlocks(rdlocks, dn->get_dir()->inode); return dn; } /** * try_open_auth_dirfrag -- open dirfrag, or forward to dirfrag auth * * @param diri base inode * @param fg the exact frag we want * @param mdr request * @returns the pointer, or NULL if it had to be delayed (but mdr is taken care of) */ CDir* Server::try_open_auth_dirfrag(CInode *diri, frag_t fg, MDRequestRef& mdr) { CDir *dir = diri->get_dirfrag(fg); // not open and inode not mine? if (!dir && !diri->is_auth()) { int inauth = diri->authority().first; dout(7) << "try_open_auth_dirfrag: not open, not inode auth, fw to mds." << inauth << dendl; mdcache->request_forward(mdr, inauth); return 0; } // not open and inode frozen? if (!dir && diri->is_frozen()) { dout(10) << "try_open_auth_dirfrag: dir inode is frozen, waiting " << *diri << dendl; assert(diri->get_parent_dir()); diri->get_parent_dir()->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); return 0; } // invent? if (!dir) dir = diri->get_or_open_dirfrag(mds->mdcache, fg); // am i auth for the dirfrag? if (!dir->is_auth()) { int auth = dir->authority().first; dout(7) << "try_open_auth_dirfrag: not auth for " << *dir << ", fw to mds." << auth << dendl; mdcache->request_forward(mdr, auth); return 0; } return dir; } // =============================================================================== // STAT void Server::handle_client_getattr(MDRequestRef& mdr, bool is_lookup) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; if (req->get_filepath().depth() == 0 && is_lookup) { // refpath can't be empty for lookup but it can for // getattr (we do getattr with empty refpath for mount of '/') reply_request(mdr, -EINVAL); return; } CInode *ref = rdlock_path_pin_ref(mdr, 0, rdlocks, false, false, NULL, !is_lookup); if (!ref) return; /* * if client currently holds the EXCL cap on a field, do not rdlock * it; client's stat() will result in valid info if _either_ EXCL * cap is held or MDS rdlocks and reads the value here. * * handling this case here is easier than weakening rdlock * semantics... that would cause problems elsewhere. */ client_t client = mdr->get_client(); int issued = 0; Capability *cap = ref->get_client_cap(client); if (cap && (mdr->snapid == CEPH_NOSNAP || mdr->snapid <= cap->client_follows)) issued = cap->issued(); int mask = req->head.args.getattr.mask; if ((mask & CEPH_CAP_LINK_SHARED) && (issued & CEPH_CAP_LINK_EXCL) == 0) rdlocks.insert(&ref->linklock); if ((mask & CEPH_CAP_AUTH_SHARED) && (issued & CEPH_CAP_AUTH_EXCL) == 0) rdlocks.insert(&ref->authlock); if ((mask & CEPH_CAP_FILE_SHARED) && (issued & CEPH_CAP_FILE_EXCL) == 0) rdlocks.insert(&ref->filelock); if ((mask & CEPH_CAP_XATTR_SHARED) && (issued & CEPH_CAP_XATTR_EXCL) == 0) rdlocks.insert(&ref->xattrlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // note which caps are requested, so we return at least a snapshot // value for them. (currently this matters for xattrs and inline data) mdr->getattr_caps = mask; mds->balancer->hit_inode(ceph_clock_now(g_ceph_context), ref, META_POP_IRD, mdr->client_request->get_source().num()); // reply dout(10) << "reply to stat on " << *req << dendl; reply_request(mdr, 0, ref, is_lookup ? mdr->dn[0].back() : 0); } struct C_MDS_LookupIno2 : public Context { Server *server; MDRequestRef mdr; C_MDS_LookupIno2(Server *s, MDRequestRef& r) : server(s), mdr(r) {} void finish(int r) { server->_lookup_ino_2(mdr, r); } }; /* This function DOES clean up the mdr before returning*/ /* * filepath: ino */ void Server::handle_client_lookup_ino(MDRequestRef& mdr, bool want_parent, bool want_dentry) { MClientRequest *req = mdr->client_request; inodeno_t ino = req->get_filepath().get_ino(); CInode *in = mdcache->get_inode(ino); if (in && in->state_test(CInode::STATE_PURGING)) { reply_request(mdr, -ESTALE); return; } if (!in) { mdcache->open_ino(ino, (int64_t)-1, new C_MDS_LookupIno2(this, mdr), false); return; } CDentry *dn = in->get_projected_parent_dn(); CInode *diri = dn ? dn->get_dir()->inode : NULL; if (dn && (want_parent || want_dentry)) { mdr->pin(dn); set rdlocks, wrlocks, xlocks; rdlocks.insert(&dn->lock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; } if (want_parent) { if (in->is_base()) { reply_request(mdr, -EINVAL); return; } if (!diri || diri->is_stray()) { reply_request(mdr, -ESTALE); return; } dout(10) << "reply to lookup_parent " << *in << dendl; reply_request(mdr, 0, diri); } else { if (want_dentry) { inodeno_t dirino = req->get_filepath2().get_ino(); if (!diri || (dirino != inodeno_t() && diri->ino() != dirino)) { reply_request(mdr, -ENOENT); return; } dout(10) << "reply to lookup_name " << *in << dendl; } else dout(10) << "reply to lookup_ino " << *in << dendl; reply_request(mdr, 0, in, want_dentry ? dn : NULL); } } void Server::_lookup_ino_2(MDRequestRef& mdr, int r) { inodeno_t ino = mdr->client_request->get_filepath().get_ino(); dout(10) << "_lookup_ino_2 " << mdr.get() << " ino " << ino << " r=" << r << dendl; if (r >= 0) { if (r == mds->get_nodeid()) dispatch_client_request(mdr); else mdcache->request_forward(mdr, r); return; } // give up if (r == -ENOENT || r == -ENODATA) r = -ESTALE; reply_request(mdr, r); } /* This function takes responsibility for the passed mdr*/ void Server::handle_client_open(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; int flags = req->head.args.open.flags; int cmode = ceph_flags_to_mode(req->head.args.open.flags); bool need_auth = !file_mode_is_readonly(cmode) || (flags & O_TRUNC); dout(7) << "open on " << req->get_filepath() << dendl; if (cmode < 0) { reply_request(mdr, -EINVAL); return; } set rdlocks, wrlocks, xlocks; CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, need_auth); if (!cur) return; if (cur->is_frozen() || cur->state_test(CInode::STATE_EXPORTINGCAPS)) { assert(!need_auth); mdr->done_locking = false; CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; } if (mdr->snapid != CEPH_NOSNAP && mdr->client_request->may_write()) { reply_request(mdr, -EROFS); return; } // can only open a dir with mode FILE_MODE_PIN, at least for now. if (cur->inode.is_dir()) cmode = CEPH_FILE_MODE_PIN; dout(10) << "open flags = " << flags << ", filemode = " << cmode << ", need_auth = " << need_auth << dendl; // regular file? /*if (!cur->inode.is_file() && !cur->inode.is_dir()) { dout(7) << "not a file or dir " << *cur << dendl; reply_request(mdr, -ENXIO); // FIXME what error do we want? return; }*/ if ((req->head.args.open.flags & O_DIRECTORY) && !cur->inode.is_dir()) { dout(7) << "specified O_DIRECTORY on non-directory " << *cur << dendl; reply_request(mdr, -EINVAL); return; } if (cur->inode.inline_version != CEPH_INLINE_NONE && !mdr->session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) { dout(7) << "old client cannot open inline data file " << *cur << dendl; reply_request(mdr, -EPERM); return; } // snapped data is read only if (mdr->snapid != CEPH_NOSNAP && (cmode & CEPH_FILE_MODE_WR)) { dout(7) << "snap " << mdr->snapid << " is read-only " << *cur << dendl; reply_request(mdr, -EPERM); return; } // O_TRUNC if ((flags & O_TRUNC) && !(req->get_retry_attempt() && mdr->session->have_completed_request(req->get_reqid().tid, NULL))) { assert(cur->is_auth()); xlocks.insert(&cur->filelock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // wait for pending truncate? inode_t *pi = cur->get_projected_inode(); if (pi->is_truncating()) { dout(10) << " waiting for pending truncate from " << pi->truncate_from << " to " << pi->truncate_size << " to complete on " << *cur << dendl; cur->add_waiter(CInode::WAIT_TRUNC, new C_MDS_RetryRequest(mdcache, mdr)); return; } do_open_truncate(mdr, cmode); return; } // sync filelock if snapped. // this makes us wait for writers to flushsnaps, ensuring we get accurate metadata, // and that data itself is flushed so that we can read the snapped data off disk. if (mdr->snapid != CEPH_NOSNAP && !cur->is_dir()) { rdlocks.insert(&cur->filelock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; } if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; if (cur->is_file() || cur->is_dir()) { if (mdr->snapid == CEPH_NOSNAP) { // register new cap Capability *cap = mds->locker->issue_new_caps(cur, cmode, mdr->session, 0, req->is_replay()); if (cap) dout(12) << "open issued caps " << ccap_string(cap->pending()) << " for " << req->get_source() << " on " << *cur << dendl; } else { int caps = ceph_caps_for_mode(cmode); dout(12) << "open issued IMMUTABLE SNAP caps " << ccap_string(caps) << " for " << req->get_source() << " snapid " << mdr->snapid << " on " << *cur << dendl; mdr->snap_caps = caps; } } // increase max_size? if (cmode & CEPH_FILE_MODE_WR) mds->locker->check_inode_max_size(cur); // make sure this inode gets into the journal if (cur->is_auth() && cur->last == CEPH_NOSNAP && !cur->item_open_file.is_on_list()) { LogSegment *ls = mds->mdlog->get_current_segment(); EOpen *le = new EOpen(mds->mdlog); mdlog->start_entry(le); le->add_clean_inode(cur); ls->open_files.push_back(&cur->item_open_file); mds->mdlog->submit_entry(le); } // hit pop mdr->now = ceph_clock_now(g_ceph_context); if (cmode == CEPH_FILE_MODE_RDWR || cmode == CEPH_FILE_MODE_WR) mds->balancer->hit_inode(mdr->now, cur, META_POP_IWR); else mds->balancer->hit_inode(mdr->now, cur, META_POP_IRD, mdr->client_request->get_source().num()); CDentry *dn = 0; if (req->get_dentry_wanted()) { assert(mdr->dn[0].size()); dn = mdr->dn[0].back(); } reply_request(mdr, 0, cur, dn); } class C_MDS_openc_finish : public Context { MDS *mds; MDRequestRef mdr; CDentry *dn; CInode *newi; snapid_t follows; public: C_MDS_openc_finish(MDS *m, MDRequestRef& r, CDentry *d, CInode *ni, snapid_t f) : mds(m), mdr(r), dn(d), newi(ni), follows(f) {} void finish(int r) { assert(r == 0); dn->pop_projected_linkage(); // dirty inode, dn, dir newi->inode.version--; // a bit hacky, see C_MDS_mknod_finish newi->mark_dirty(newi->inode.version+1, mdr->ls); newi->_mark_dirty_parent(mdr->ls, true); mdr->apply(); mds->locker->share_inode_max_size(newi); mds->mdcache->send_dentry_link(dn); mds->balancer->hit_inode(mdr->now, newi, META_POP_IWR); MClientReply *reply = new MClientReply(mdr->client_request, 0); reply->set_extra_bl(mdr->reply_extra_bl); mds->server->reply_request(mdr, reply); assert(g_conf->mds_kill_openc_at != 1); } }; /* This function takes responsibility for the passed mdr*/ void Server::handle_client_openc(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; client_t client = mdr->get_client(); dout(7) << "open w/ O_CREAT on " << req->get_filepath() << dendl; int cmode = ceph_flags_to_mode(req->head.args.open.flags); if (cmode < 0) { reply_request(mdr, -EINVAL); return; } if (!(req->head.args.open.flags & O_EXCL)) { int r = mdcache->path_traverse(mdr, NULL, NULL, req->get_filepath(), &mdr->dn[0], NULL, MDS_TRAVERSE_FORWARD); if (r > 0) return; if (r == 0) { // it existed. handle_client_open(mdr); return; } if (r < 0 && r != -ENOENT) { if (r == -ESTALE) { dout(10) << "FAIL on ESTALE but attempting recovery" << dendl; Context *c = new C_MDS_TryFindInode(this, mdr); mdcache->find_ino_peers(req->get_filepath().get_ino(), c); } else { dout(10) << "FAIL on error " << r << dendl; reply_request(mdr, r); } return; } // r == -ENOENT } bool excl = (req->head.args.open.flags & O_EXCL); set rdlocks, wrlocks, xlocks; ceph_file_layout *dir_layout = NULL; CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, !excl, false, false, &dir_layout); if (!dn) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } // set layout ceph_file_layout layout; if (dir_layout) layout = *dir_layout; else layout = mds->mdcache->default_file_layout; // fill in any special params from client if (req->head.args.open.stripe_unit) layout.fl_stripe_unit = req->head.args.open.stripe_unit; if (req->head.args.open.stripe_count) layout.fl_stripe_count = req->head.args.open.stripe_count; if (req->head.args.open.object_size) layout.fl_object_size = req->head.args.open.object_size; if (req->get_connection()->has_feature(CEPH_FEATURE_CREATEPOOLID) && (__s32)req->head.args.open.pool >= 0) { layout.fl_pg_pool = req->head.args.open.pool; // make sure we have as new a map as the client if (req->get_mdsmap_epoch() > mds->mdsmap->get_epoch()) { mds->wait_for_mdsmap(req->get_mdsmap_epoch(), new C_MDS_RetryRequest(mdcache, mdr)); return; } } if (!ceph_file_layout_is_valid(&layout)) { dout(10) << " invalid initial file layout" << dendl; reply_request(mdr, -EINVAL); return; } if (!mds->mdsmap->is_data_pool(layout.fl_pg_pool)) { dout(10) << " invalid data pool " << layout.fl_pg_pool << dendl; reply_request(mdr, -EINVAL); return; } CInode *diri = dn->get_dir()->get_inode(); rdlocks.insert(&diri->authlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; CDentry::linkage_t *dnl = dn->get_projected_linkage(); if (!dnl->is_null()) { // it existed. assert(req->head.args.open.flags & O_EXCL); dout(10) << "O_EXCL, target exists, failing with -EEXIST" << dendl; reply_request(mdr, -EEXIST, dnl->get_inode(), dn); return; } // created null dn. // create inode. mdr->now = ceph_clock_now(g_ceph_context); SnapRealm *realm = diri->find_snaprealm(); // use directory's realm; inode isn't attached yet. snapid_t follows = realm->get_newest_seq(); CInode *in = prepare_new_inode(mdr, dn->get_dir(), inodeno_t(req->head.ino), req->head.args.open.mode | S_IFREG, &layout); assert(in); // it's a file. dn->push_projected_linkage(in); in->inode.version = dn->pre_dirty(); if (layout.fl_pg_pool != mdcache->default_file_layout.fl_pg_pool) in->inode.add_old_pool(mdcache->default_file_layout.fl_pg_pool); in->inode.update_backtrace(); if (cmode & CEPH_FILE_MODE_WR) { in->inode.client_ranges[client].range.first = 0; in->inode.client_ranges[client].range.last = in->inode.get_layout_size_increment(); in->inode.client_ranges[client].follows = follows; } in->inode.rstat.rfiles = 1; if (follows >= dn->first) dn->first = follows+1; in->first = dn->first; // prepare finisher mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "openc"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); journal_allocated_inos(mdr, &le->metablob); mdcache->predirty_journal_parents(mdr, &le->metablob, in, dn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); le->metablob.add_primary_dentry(dn, in, true, true, true); // do the open mds->locker->issue_new_caps(in, cmode, mdr->session, realm, req->is_replay()); in->authlock.set_state(LOCK_EXCL); in->xattrlock.set_state(LOCK_EXCL); // make sure this inode gets into the journal le->metablob.add_opened_ino(in->ino()); LogSegment *ls = mds->mdlog->get_current_segment(); ls->open_files.push_back(&in->item_open_file); C_MDS_openc_finish *fin = new C_MDS_openc_finish(mds, mdr, dn, in, follows); if (mdr->client_request->get_connection()->has_feature(CEPH_FEATURE_REPLY_CREATE_INODE)) { dout(10) << "adding ino to reply to indicate inode was created" << dendl; // add the file created flag onto the reply if create_flags features is supported ::encode(in->inode.ino, mdr->reply_extra_bl); } journal_and_reply(mdr, in, dn, le, fin); } void Server::handle_client_readdir(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; client_t client = req->get_source().num(); set rdlocks, wrlocks, xlocks; CInode *diri = rdlock_path_pin_ref(mdr, 0, rdlocks, false, true); if (!diri) return; // it's a directory, right? if (!diri->is_dir()) { // not a dir dout(10) << "reply to " << *req << " readdir -ENOTDIR" << dendl; reply_request(mdr, -ENOTDIR); return; } rdlocks.insert(&diri->filelock); rdlocks.insert(&diri->dirfragtreelock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // which frag? frag_t fg = (__u32)req->head.args.readdir.frag; string offset_str = req->get_path2(); dout(10) << " frag " << fg << " offset '" << offset_str << "'" << dendl; // does the frag exist? if (diri->dirfragtree[fg.value()] != fg) { frag_t newfg = diri->dirfragtree[fg.value()]; dout(10) << " adjust frag " << fg << " -> " << newfg << " " << diri->dirfragtree << dendl; fg = newfg; offset_str.clear(); } CDir *dir = try_open_auth_dirfrag(diri, fg, mdr); if (!dir) return; // ok! dout(10) << "handle_client_readdir on " << *dir << dendl; assert(dir->is_auth()); if (!dir->is_complete()) { if (dir->is_frozen()) { dout(7) << "dir is frozen " << *dir << dendl; mds->locker->drop_locks(mdr.get()); mdr->drop_local_auth_pins(); dir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); return; } // fetch dout(10) << " incomplete dir contents for readdir on " << *dir << ", fetching" << dendl; dir->fetch(new C_MDS_RetryRequest(mdcache, mdr), true); return; } #ifdef MDS_VERIFY_FRAGSTAT dir->verify_fragstat(); #endif mdr->now = ceph_clock_now(g_ceph_context); snapid_t snapid = mdr->snapid; dout(10) << "snapid " << snapid << dendl; // purge stale snap data? const set *snaps = 0; SnapRealm *realm = diri->find_snaprealm(); if (realm->get_last_destroyed() > dir->fnode.snap_purged_thru) { snaps = &realm->get_snaps(); dout(10) << " last_destroyed " << realm->get_last_destroyed() << " > " << dir->fnode.snap_purged_thru << ", doing snap purge with " << *snaps << dendl; dir->fnode.snap_purged_thru = realm->get_last_destroyed(); assert(snapid == CEPH_NOSNAP || snaps->count(snapid)); // just checkin'! } unsigned max = req->head.args.readdir.max_entries; if (!max) max = dir->get_num_any(); // whatever, something big. unsigned max_bytes = req->head.args.readdir.max_bytes; if (!max_bytes) max_bytes = 512 << 10; // 512 KB? // start final blob bufferlist dirbl; dir->encode_dirstat(dirbl, mds->get_nodeid()); // count bytes available. // this isn't perfect, but we should capture the main variable/unbounded size items! int front_bytes = dirbl.length() + sizeof(__u32) + sizeof(__u8)*2; int bytes_left = max_bytes - front_bytes; bytes_left -= realm->get_snap_trace().length(); // build dir contents bufferlist dnbl; __u32 numfiles = 0; __u8 end = (dir->begin() == dir->end()); for (CDir::map_t::iterator it = dir->begin(); !end && numfiles < max; end = (it == dir->end())) { CDentry *dn = it->second; ++it; if (dn->state_test(CDentry::STATE_PURGING)) continue; bool dnp = dn->use_projected(client, mdr); CDentry::linkage_t *dnl = dnp ? dn->get_projected_linkage() : dn->get_linkage(); if (dnl->is_null()) continue; if (snaps && dn->last != CEPH_NOSNAP) if (dir->try_trim_snap_dentry(dn, *snaps)) continue; if (dn->last < snapid || dn->first > snapid) { dout(20) << "skipping non-overlapping snap " << *dn << dendl; continue; } if (!offset_str.empty() && dn->get_name().compare(offset_str) <= 0) continue; CInode *in = dnl->get_inode(); if (in && in->ino() == CEPH_INO_CEPH) continue; // remote link? // better for the MDS to do the work, if we think the client will stat any of these files. if (dnl->is_remote() && !in) { in = mdcache->get_inode(dnl->get_remote_ino()); if (in) { dn->link_remote(dnl, in); } else if (dn->state_test(CDentry::STATE_BADREMOTEINO)) { dout(10) << "skipping bad remote ino on " << *dn << dendl; continue; } else { // touch everything i _do_ have for (CDir::map_t::iterator p = dir->begin(); p != dir->end(); ++p) if (!p->second->get_linkage()->is_null()) mdcache->lru.lru_touch(p->second); // already issued caps and leases, reply immediately. if (dnbl.length() > 0) { mdcache->open_remote_dentry(dn, dnp, new C_NoopContext); dout(10) << " open remote dentry after caps were issued, stopping at " << dnbl.length() << " < " << bytes_left << dendl; break; } mds->locker->drop_locks(mdr.get()); mdr->drop_local_auth_pins(); mdcache->open_remote_dentry(dn, dnp, new C_MDS_RetryRequest(mdcache, mdr)); return; } } assert(in); if ((int)(dnbl.length() + dn->name.length() + sizeof(__u32) + sizeof(LeaseStat)) > bytes_left) { dout(10) << " ran out of room, stopping at " << dnbl.length() << " < " << bytes_left << dendl; break; } unsigned start_len = dnbl.length(); // dentry dout(12) << "including dn " << *dn << dendl; ::encode(dn->name, dnbl); mds->locker->issue_client_lease(dn, client, dnbl, mdr->now, mdr->session); // inode dout(12) << "including inode " << *in << dendl; int r = in->encode_inodestat(dnbl, mdr->session, realm, snapid, bytes_left - (int)dnbl.length()); if (r < 0) { // chop off dn->name, lease dout(10) << " ran out of room, stopping at " << start_len << " < " << bytes_left << dendl; bufferlist keep; keep.substr_of(dnbl, 0, start_len); dnbl.swap(keep); break; } assert(r >= 0); numfiles++; // touch dn mdcache->lru.lru_touch(dn); } __u8 complete = (end && offset_str.empty()); // FIXME: what purpose does this serve // finish final blob ::encode(numfiles, dirbl); ::encode(end, dirbl); ::encode(complete, dirbl); dirbl.claim_append(dnbl); if (snaps) dir->log_mark_dirty(); // yay, reply dout(10) << "reply to " << *req << " readdir num=" << numfiles << " bytes=" << dirbl.length() << " end=" << (int)end << " complete=" << (int)complete << dendl; MClientReply *reply = new MClientReply(req, 0); reply->set_extra_bl(dirbl); dout(10) << "reply to " << *req << " readdir num=" << numfiles << " end=" << (int)end << " complete=" << (int)complete << dendl; // bump popularity. NOTE: this doesn't quite capture it. mds->balancer->hit_dir(ceph_clock_now(g_ceph_context), dir, META_POP_IRD, -1, numfiles); // reply reply_request(mdr, reply, diri); } // =============================================================================== // INODE UPDATES /* * finisher for basic inode updates */ class C_MDS_inode_update_finish : public Context { MDS *mds; MDRequestRef mdr; CInode *in; bool truncating_smaller, changed_ranges; public: C_MDS_inode_update_finish(MDS *m, MDRequestRef& r, CInode *i, bool sm=false, bool cr=false) : mds(m), mdr(r), in(i), truncating_smaller(sm), changed_ranges(cr) { } void finish(int r) { assert(r == 0); // apply in->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); // notify any clients if (truncating_smaller && in->inode.is_truncating()) { mds->locker->issue_truncate(in); mds->mdcache->truncate_inode(in, mdr->ls); } mds->balancer->hit_inode(mdr->now, in, META_POP_IWR); mds->server->reply_request(mdr, 0); if (changed_ranges) mds->locker->share_inode_max_size(in); } }; void Server::handle_client_file_setlock(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; // get the inode to operate on, and set up any locks needed for that CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; xlocks.insert(&cur->flocklock); /* acquire_locks will return true if it gets the locks. If it fails, it will redeliver this request at a later date, so drop the request. */ if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) { dout(0) << "handle_client_file_setlock could not get locks!" << dendl; return; } // copy the lock change into a ceph_filelock so we can store/apply it ceph_filelock set_lock; set_lock.start = req->head.args.filelock_change.start; set_lock.length = req->head.args.filelock_change.length; set_lock.client = req->get_orig_source().num(); set_lock.owner = req->head.args.filelock_change.owner; set_lock.pid = req->head.args.filelock_change.pid; set_lock.type = req->head.args.filelock_change.type; bool will_wait = req->head.args.filelock_change.wait; dout(0) << "handle_client_file_setlock: " << set_lock << dendl; ceph_lock_state_t *lock_state = NULL; bool interrupt = false; // get the appropriate lock state switch (req->head.args.filelock_change.rule) { case CEPH_LOCK_FLOCK_INTR: interrupt = true; // fall-thru case CEPH_LOCK_FLOCK: lock_state = &cur->flock_locks; break; case CEPH_LOCK_FCNTL_INTR: interrupt = true; // fall-thru case CEPH_LOCK_FCNTL: lock_state = &cur->fcntl_locks; break; default: dout(10) << "got unknown lock type " << set_lock.type << ", dropping request!" << dendl; reply_request(mdr, -EOPNOTSUPP); return; } dout(10) << " state prior to lock change: " << *lock_state << dendl;; if (CEPH_LOCK_UNLOCK == set_lock.type) { list activated_locks; list waiters; if (lock_state->is_waiting(set_lock)) { dout(10) << " unlock removing waiting lock " << set_lock << dendl; lock_state->remove_waiting(set_lock); cur->take_waiting(CInode::WAIT_FLOCK, waiters); } else if (!interrupt) { dout(10) << " unlock attempt on " << set_lock << dendl; lock_state->remove_lock(set_lock, activated_locks); cur->take_waiting(CInode::WAIT_FLOCK, waiters); } mds->queue_waiters(waiters); reply_request(mdr, 0); } else { dout(10) << " lock attempt on " << set_lock << dendl; if (mdr->more()->flock_was_waiting && !lock_state->is_waiting(set_lock)) { dout(10) << " was waiting for lock but not anymore, must have been canceled " << set_lock << dendl; reply_request(mdr, -EINTR); } else if (!lock_state->add_lock(set_lock, will_wait, mdr->more()->flock_was_waiting)) { dout(10) << " it failed on this attempt" << dendl; // couldn't set lock right now if (!will_wait) { reply_request(mdr, -EWOULDBLOCK); } else { dout(10) << " added to waiting list" << dendl; assert(lock_state->is_waiting(set_lock)); mdr->more()->flock_was_waiting = true; mds->locker->drop_locks(mdr.get()); mdr->drop_local_auth_pins(); cur->add_waiter(CInode::WAIT_FLOCK, new C_MDS_RetryRequest(mdcache, mdr)); } } else reply_request(mdr, 0); } dout(10) << " state after lock change: " << *lock_state << dendl; } void Server::handle_client_file_readlock(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; // get the inode to operate on, and set up any locks needed for that CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; /* acquire_locks will return true if it gets the locks. If it fails, it will redeliver this request at a later date, so drop the request. */ rdlocks.insert(&cur->flocklock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) { dout(0) << "handle_client_file_readlock could not get locks!" << dendl; return; } // copy the lock change into a ceph_filelock so we can store/apply it ceph_filelock checking_lock; checking_lock.start = req->head.args.filelock_change.start; checking_lock.length = req->head.args.filelock_change.length; checking_lock.client = req->get_orig_source().num(); checking_lock.owner = req->head.args.filelock_change.owner; checking_lock.pid = req->head.args.filelock_change.pid; checking_lock.type = req->head.args.filelock_change.type; // get the appropriate lock state ceph_lock_state_t *lock_state = NULL; switch (req->head.args.filelock_change.rule) { case CEPH_LOCK_FLOCK: lock_state = &cur->flock_locks; break; case CEPH_LOCK_FCNTL: lock_state = &cur->fcntl_locks; break; default: dout(0) << "got unknown lock type " << checking_lock.type << ", dropping request!" << dendl; return; } lock_state->look_for_lock(checking_lock); bufferlist lock_bl; ::encode(checking_lock, lock_bl); MClientReply *reply = new MClientReply(req); reply->set_extra_bl(lock_bl); reply_request(mdr, reply); } void Server::handle_client_setattr(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } if (cur->ino() < MDS_INO_SYSTEM_BASE && !cur->is_base()) { reply_request(mdr, -EPERM); return; } __u32 mask = req->head.args.setattr.mask; // xlock inode if (mask & (CEPH_SETATTR_MODE|CEPH_SETATTR_UID|CEPH_SETATTR_GID)) xlocks.insert(&cur->authlock); if (mask & (CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME|CEPH_SETATTR_SIZE)) xlocks.insert(&cur->filelock); if (mask & CEPH_SETATTR_CTIME) wrlocks.insert(&cur->versionlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // trunc from bigger -> smaller? inode_t *pi = cur->get_projected_inode(); uint64_t old_size = MAX(pi->size, req->head.args.setattr.old_size); bool truncating_smaller = false; if (mask & CEPH_SETATTR_SIZE) { truncating_smaller = req->head.args.setattr.size < old_size; if (truncating_smaller && pi->is_truncating()) { dout(10) << " waiting for pending truncate from " << pi->truncate_from << " to " << pi->truncate_size << " to complete on " << *cur << dendl; cur->add_waiter(CInode::WAIT_TRUNC, new C_MDS_RetryRequest(mdcache, mdr)); mds->mdlog->flush(); return; } } bool changed_ranges = false; // project update mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "setattr"); mdlog->start_entry(le); pi = cur->project_inode(); utime_t now = ceph_clock_now(g_ceph_context); if (mask & CEPH_SETATTR_MODE) pi->mode = (pi->mode & ~07777) | (req->head.args.setattr.mode & 07777); if (mask & CEPH_SETATTR_UID) pi->uid = req->head.args.setattr.uid; if (mask & CEPH_SETATTR_GID) pi->gid = req->head.args.setattr.gid; if (mask & CEPH_SETATTR_MTIME) pi->mtime = req->head.args.setattr.mtime; if (mask & CEPH_SETATTR_ATIME) pi->atime = req->head.args.setattr.atime; if (mask & (CEPH_SETATTR_ATIME | CEPH_SETATTR_MTIME)) pi->time_warp_seq++; // maybe not a timewarp, but still a serialization point. if (mask & CEPH_SETATTR_SIZE) { if (truncating_smaller) { pi->truncate(old_size, req->head.args.setattr.size); le->metablob.add_truncate_start(cur->ino()); } else { pi->size = req->head.args.setattr.size; pi->rstat.rbytes = pi->size; } pi->mtime = now; // adjust client's max_size? map new_ranges; mds->locker->calc_new_client_ranges(cur, pi->size, new_ranges); if (pi->client_ranges != new_ranges) { dout(10) << " client_ranges " << pi->client_ranges << " -> " << new_ranges << dendl; pi->client_ranges = new_ranges; changed_ranges = true; } } pi->version = cur->pre_dirty(); pi->ctime = now; // log + wait le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur, truncating_smaller, changed_ranges)); // flush immediately if there are readers/writers waiting if (cur->get_caps_wanted() & (CEPH_CAP_FILE_RD|CEPH_CAP_FILE_WR)) mds->mdlog->flush(); } /* Takes responsibility for mdr */ void Server::do_open_truncate(MDRequestRef& mdr, int cmode) { CInode *in = mdr->in[0]; client_t client = mdr->get_client(); assert(in); dout(10) << "do_open_truncate " << *in << dendl; SnapRealm *realm = in->find_snaprealm(); mds->locker->issue_new_caps(in, cmode, mdr->session, realm, mdr->client_request->is_replay()); mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "open_truncate"); mdlog->start_entry(le); // prepare inode_t *pi = in->project_inode(); pi->mtime = pi->ctime = ceph_clock_now(g_ceph_context); pi->version = in->pre_dirty(); uint64_t old_size = MAX(pi->size, mdr->client_request->head.args.open.old_size); if (old_size > 0) { pi->truncate(old_size, 0); le->metablob.add_truncate_start(in->ino()); } bool changed_ranges = false; if (cmode & CEPH_FILE_MODE_WR) { pi->client_ranges[client].range.first = 0; pi->client_ranges[client].range.last = pi->get_layout_size_increment(); pi->client_ranges[client].follows = in->find_snaprealm()->get_newest_seq(); changed_ranges = true; } le->metablob.add_client_req(mdr->reqid, mdr->client_request->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, in, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, in); // make sure ino gets into the journal le->metablob.add_opened_ino(in->ino()); LogSegment *ls = mds->mdlog->get_current_segment(); ls->open_files.push_back(&in->item_open_file); mdr->o_trunc = true; CDentry *dn = 0; if (mdr->client_request->get_dentry_wanted()) { assert(mdr->dn[0].size()); dn = mdr->dn[0].back(); } journal_and_reply(mdr, in, dn, le, new C_MDS_inode_update_finish(mds, mdr, in, old_size > 0, changed_ranges)); } /* This function cleans up the passed mdr */ void Server::handle_client_setlayout(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } if (!cur->is_file()) { reply_request(mdr, -EINVAL); return; } if (cur->get_projected_inode()->size || cur->get_projected_inode()->truncate_seq > 1) { reply_request(mdr, -ENOTEMPTY); return; } // validate layout ceph_file_layout layout = cur->get_projected_inode()->layout; // save existing layout for later int64_t old_pool = layout.fl_pg_pool; if (req->head.args.setlayout.layout.fl_object_size > 0) layout.fl_object_size = req->head.args.setlayout.layout.fl_object_size; if (req->head.args.setlayout.layout.fl_stripe_unit > 0) layout.fl_stripe_unit = req->head.args.setlayout.layout.fl_stripe_unit; if (req->head.args.setlayout.layout.fl_stripe_count > 0) layout.fl_stripe_count=req->head.args.setlayout.layout.fl_stripe_count; if (req->head.args.setlayout.layout.fl_cas_hash > 0) layout.fl_cas_hash = req->head.args.setlayout.layout.fl_cas_hash; if (req->head.args.setlayout.layout.fl_object_stripe_unit > 0) layout.fl_object_stripe_unit = req->head.args.setlayout.layout.fl_object_stripe_unit; if (req->head.args.setlayout.layout.fl_pg_pool > 0) { layout.fl_pg_pool = req->head.args.setlayout.layout.fl_pg_pool; // make sure we have as new a map as the client if (req->get_mdsmap_epoch() > mds->mdsmap->get_epoch()) { mds->wait_for_mdsmap(req->get_mdsmap_epoch(), new C_MDS_RetryRequest(mdcache, mdr)); return; } } if (!ceph_file_layout_is_valid(&layout)) { dout(10) << "bad layout" << dendl; reply_request(mdr, -EINVAL); return; } if (!mds->mdsmap->is_data_pool(layout.fl_pg_pool)) { dout(10) << " invalid data pool " << layout.fl_pg_pool << dendl; reply_request(mdr, -EINVAL); return; } xlocks.insert(&cur->filelock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // project update inode_t *pi = cur->project_inode(); pi->layout = layout; // add the old pool to the inode pi->add_old_pool(old_pool); pi->version = cur->pre_dirty(); pi->ctime = ceph_clock_now(g_ceph_context); // log + wait mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "setlayout"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur)); } void Server::handle_client_setdirlayout(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; ceph_file_layout *dir_layout = NULL; CInode *cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true, false, &dir_layout); if (!cur) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } if (!cur->is_dir()) { reply_request(mdr, -ENOTDIR); return; } xlocks.insert(&cur->policylock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // validate layout inode_t *pi = cur->get_projected_inode(); ceph_file_layout layout; if (pi->has_layout()) layout = pi->layout; else if (dir_layout) layout = *dir_layout; else layout = mds->mdcache->default_file_layout; if (req->head.args.setlayout.layout.fl_object_size > 0) layout.fl_object_size = req->head.args.setlayout.layout.fl_object_size; if (req->head.args.setlayout.layout.fl_stripe_unit > 0) layout.fl_stripe_unit = req->head.args.setlayout.layout.fl_stripe_unit; if (req->head.args.setlayout.layout.fl_stripe_count > 0) layout.fl_stripe_count=req->head.args.setlayout.layout.fl_stripe_count; if (req->head.args.setlayout.layout.fl_cas_hash > 0) layout.fl_cas_hash = req->head.args.setlayout.layout.fl_cas_hash; if (req->head.args.setlayout.layout.fl_object_stripe_unit > 0) layout.fl_object_stripe_unit = req->head.args.setlayout.layout.fl_object_stripe_unit; if (req->head.args.setlayout.layout.fl_pg_pool > 0) { layout.fl_pg_pool = req->head.args.setlayout.layout.fl_pg_pool; // make sure we have as new a map as the client if (req->get_mdsmap_epoch() > mds->mdsmap->get_epoch()) { mds->wait_for_mdsmap(req->get_mdsmap_epoch(), new C_MDS_RetryRequest(mdcache, mdr)); return; } } if (!ceph_file_layout_is_valid(&layout)) { dout(10) << "bad layout" << dendl; reply_request(mdr, -EINVAL); return; } if (!mds->mdsmap->is_data_pool(layout.fl_pg_pool)) { dout(10) << " invalid data pool " << layout.fl_pg_pool << dendl; reply_request(mdr, -EINVAL); return; } pi = cur->project_inode(); pi->layout = layout; pi->version = cur->pre_dirty(); // log + wait mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "setlayout"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur)); } // XATTRS // parse a map of keys/values. namespace qi = boost::spirit::qi; template struct keys_and_values : qi::grammar()> { keys_and_values() : keys_and_values::base_type(query) { query = pair >> *(qi::lit(' ') >> pair); pair = key >> '=' >> value; key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"); value = +qi::char_("a-zA-Z_0-9"); } qi::rule()> query; qi::rule()> pair; qi::rule key, value; }; int Server::parse_layout_vxattr(string name, string value, ceph_file_layout *layout) { dout(20) << "parse_layout_vxattr name " << name << " value '" << value << "'" << dendl; try { if (name == "layout") { string::iterator begin = value.begin(); string::iterator end = value.end(); keys_and_values p; // create instance of parser std::map m; // map to receive results if (!qi::parse(begin, end, p, m)) { // returns true if successful return -EINVAL; } string left(begin, end); dout(10) << " parsed " << m << " left '" << left << "'" << dendl; if (begin != end) return -EINVAL; for (map::iterator q = m.begin(); q != m.end(); ++q) { int r = parse_layout_vxattr(string("layout.") + q->first, q->second, layout); if (r < 0) return r; } } else if (name == "layout.object_size") { layout->fl_object_size = boost::lexical_cast(value); } else if (name == "layout.stripe_unit") { layout->fl_stripe_unit = boost::lexical_cast(value); } else if (name == "layout.stripe_count") { layout->fl_stripe_count = boost::lexical_cast(value); } else if (name == "layout.pool") { try { layout->fl_pg_pool = boost::lexical_cast(value); } catch (boost::bad_lexical_cast const&) { int64_t pool = mds->osdmap->lookup_pg_pool_name(value); if (pool < 0) { dout(10) << " unknown pool " << value << dendl; return -ENOENT; } layout->fl_pg_pool = pool; } } else { dout(10) << " unknown layout vxattr " << name << dendl; return -EINVAL; } } catch (boost::bad_lexical_cast const&) { dout(10) << "bad vxattr value, unable to parse int for " << name << dendl; return -EINVAL; } if (!ceph_file_layout_is_valid(layout)) { dout(10) << "bad layout" << dendl; return -EINVAL; } if (!mds->mdsmap->is_data_pool(layout->fl_pg_pool)) { dout(10) << " invalid data pool " << layout->fl_pg_pool << dendl; return -EINVAL; } return 0; } void Server::handle_set_vxattr(MDRequestRef& mdr, CInode *cur, ceph_file_layout *dir_layout, set rdlocks, set wrlocks, set xlocks) { MClientRequest *req = mdr->client_request; string name(req->get_path2()); bufferlist bl = req->get_data(); string value (bl.c_str(), bl.length()); dout(10) << "handle_set_vxattr " << name << " val " << value.length() << " bytes on " << *cur << dendl; // layout? if (name.find("ceph.file.layout") == 0 || name.find("ceph.dir.layout") == 0) { inode_t *pi; string rest; int64_t old_pool = -1; if (name.find("ceph.dir.layout") == 0) { if (!cur->is_dir()) { reply_request(mdr, -EINVAL); return; } ceph_file_layout layout; if (cur->get_projected_inode()->has_layout()) layout = cur->get_projected_inode()->layout; else if (dir_layout) layout = *dir_layout; else layout = mds->mdcache->default_file_layout; rest = name.substr(name.find("layout")); int r = parse_layout_vxattr(rest, value, &layout); if (r < 0) { if (r == -ENOENT) { if (!mdr->waited_for_osdmap) { // send request to get latest map, but don't wait if // we don't get anything newer than what we have mdr->waited_for_osdmap = true; mds->request_osdmap( new C_MDS_RetryRequest(mdcache, mdr)); return; } r = -EINVAL; } reply_request(mdr, r); return; } xlocks.insert(&cur->policylock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; pi = cur->project_inode(); cur->get_projected_inode()->layout = layout; } else { if (!cur->is_file()) { reply_request(mdr, -EINVAL); return; } ceph_file_layout layout = cur->get_projected_inode()->layout; rest = name.substr(name.find("layout")); int r = parse_layout_vxattr(rest, value, &layout); if (r < 0) { if (r == -ENOENT) { if (!mdr->waited_for_osdmap) { // send request to get latest map, but don't wait if // we don't get anything newer than what we have mdr->waited_for_osdmap = true; mds->request_osdmap( new C_MDS_RetryRequest(mdcache, mdr)); return; } r = -EINVAL; } reply_request(mdr, r); return; } xlocks.insert(&cur->filelock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; pi = cur->project_inode(); old_pool = pi->layout.fl_pg_pool; pi->add_old_pool(old_pool); pi->layout = layout; pi->ctime = ceph_clock_now(g_ceph_context); } pi->version = cur->pre_dirty(); if (cur->is_file()) pi->update_backtrace(); // log + wait mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "set vxattr layout"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur)); return; } dout(10) << " unknown vxattr " << name << dendl; reply_request(mdr, -EINVAL); } void Server::handle_remove_vxattr(MDRequestRef& mdr, CInode *cur, set rdlocks, set wrlocks, set xlocks) { MClientRequest *req = mdr->client_request; string name(req->get_path2()); if (name == "ceph.dir.layout") { if (!cur->is_dir()) { reply_request(mdr, -ENODATA); return; } if (cur->is_root()) { dout(10) << "can't remove layout policy on the root directory" << dendl; reply_request(mdr, -EINVAL); return; } if (!cur->get_projected_inode()->has_layout()) { reply_request(mdr, -ENODATA); return; } xlocks.insert(&cur->policylock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; cur->project_inode(); cur->get_projected_inode()->clear_layout(); cur->get_projected_inode()->version = cur->pre_dirty(); // log + wait mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "remove dir layout vxattr"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur)); return; } reply_request(mdr, -ENODATA); } class C_MDS_inode_xattr_update_finish : public Context { MDS *mds; MDRequestRef mdr; CInode *in; public: C_MDS_inode_xattr_update_finish(MDS *m, MDRequestRef& r, CInode *i) : mds(m), mdr(r), in(i) { } void finish(int r) { assert(r == 0); // apply in->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); mds->balancer->hit_inode(mdr->now, in, META_POP_IWR); mds->server->reply_request(mdr, 0); } }; void Server::handle_client_setxattr(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; string name(req->get_path2()); set rdlocks, wrlocks, xlocks; CInode *cur; ceph_file_layout *dir_layout = NULL; if (name.find("ceph.dir.layout") == 0) cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true, false, &dir_layout); else cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } int flags = req->head.args.setxattr.flags; // magic ceph.* namespace? if (name.find("ceph.") == 0) { handle_set_vxattr(mdr, cur, dir_layout, rdlocks, wrlocks, xlocks); return; } xlocks.insert(&cur->xattrlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; map *pxattrs = cur->get_projected_xattrs(); if ((flags & CEPH_XATTR_CREATE) && pxattrs->count(name)) { dout(10) << "setxattr '" << name << "' XATTR_CREATE and EEXIST on " << *cur << dendl; reply_request(mdr, -EEXIST); return; } if ((flags & CEPH_XATTR_REPLACE) && !pxattrs->count(name)) { dout(10) << "setxattr '" << name << "' XATTR_REPLACE and ENODATA on " << *cur << dendl; reply_request(mdr, -ENODATA); return; } int len = req->get_data().length(); dout(10) << "setxattr '" << name << "' len " << len << " on " << *cur << dendl; // project update map *px = new map; inode_t *pi = cur->project_inode(px); pi->version = cur->pre_dirty(); pi->ctime = ceph_clock_now(g_ceph_context); pi->xattr_version++; px->erase(name); if (!(flags & CEPH_XATTR_REMOVE)) { (*px)[name] = buffer::create(len); if (len) req->get_data().copy(0, len, (*px)[name].c_str()); } // log + wait mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "setxattr"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur)); } void Server::handle_client_removexattr(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; string name(req->get_path2()); set rdlocks, wrlocks, xlocks; ceph_file_layout *dir_layout = NULL; CInode *cur; if (name == "ceph.dir.layout") cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true, false, &dir_layout); else cur = rdlock_path_pin_ref(mdr, 0, rdlocks, true); if (!cur) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } if (name.find("ceph.") == 0) { handle_remove_vxattr(mdr, cur, rdlocks, wrlocks, xlocks); return; } xlocks.insert(&cur->xattrlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; map *pxattrs = cur->get_projected_xattrs(); if (pxattrs->count(name) == 0) { dout(10) << "removexattr '" << name << "' and ENODATA on " << *cur << dendl; reply_request(mdr, -ENODATA); return; } dout(10) << "removexattr '" << name << "' on " << *cur << dendl; // project update map *px = new map; inode_t *pi = cur->project_inode(px); pi->version = cur->pre_dirty(); pi->ctime = ceph_clock_now(g_ceph_context); pi->xattr_version++; px->erase(name); // log + wait mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "removexattr"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, cur, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(mds, mdr, cur)); } // ================================================================= // DIRECTORY and NAMESPACE OPS // ------------------------------------------------ // MKNOD class C_MDS_mknod_finish : public Context { MDS *mds; MDRequestRef mdr; CDentry *dn; CInode *newi; snapid_t follows; public: C_MDS_mknod_finish(MDS *m, MDRequestRef& r, CDentry *d, CInode *ni, snapid_t f) : mds(m), mdr(r), dn(d), newi(ni), follows(f) {} void finish(int r) { assert(r == 0); // link the inode dn->pop_projected_linkage(); // be a bit hacky with the inode version, here.. we decrement it // just to keep mark_dirty() happen. (we didn't bother projecting // a new version of hte inode since it's just been created) newi->inode.version--; newi->mark_dirty(newi->inode.version + 1, mdr->ls); newi->_mark_dirty_parent(mdr->ls, true); // mkdir? if (newi->inode.is_dir()) { CDir *dir = newi->get_dirfrag(frag_t()); assert(dir); dir->fnode.version--; dir->mark_dirty(dir->fnode.version + 1, mdr->ls); dir->mark_new(mdr->ls); } mdr->apply(); mds->mdcache->send_dentry_link(dn); if (newi->inode.is_file()) mds->locker->share_inode_max_size(newi); // hit pop mds->balancer->hit_inode(mdr->now, newi, META_POP_IWR); // reply MClientReply *reply = new MClientReply(mdr->client_request, 0); reply->set_result(0); mds->server->reply_request(mdr, reply); } }; void Server::handle_client_mknod(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; client_t client = mdr->get_client(); set rdlocks, wrlocks, xlocks; ceph_file_layout *dir_layout = NULL; CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, false, false, false, &dir_layout); if (!dn) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CInode *diri = dn->get_dir()->get_inode(); rdlocks.insert(&diri->authlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; unsigned mode = req->head.args.mknod.mode; if ((mode & S_IFMT) == 0) mode |= S_IFREG; // set layout ceph_file_layout layout; if (dir_layout && S_ISREG(mode)) layout = *dir_layout; else layout = mds->mdcache->default_file_layout; SnapRealm *realm = dn->get_dir()->inode->find_snaprealm(); snapid_t follows = realm->get_newest_seq(); mdr->now = ceph_clock_now(g_ceph_context); CInode *newi = prepare_new_inode(mdr, dn->get_dir(), inodeno_t(req->head.ino), mode, &layout); assert(newi); dn->push_projected_linkage(newi); newi->inode.rdev = req->head.args.mknod.rdev; newi->inode.version = dn->pre_dirty(); newi->inode.rstat.rfiles = 1; if (layout.fl_pg_pool != mdcache->default_file_layout.fl_pg_pool) newi->inode.add_old_pool(mdcache->default_file_layout.fl_pg_pool); newi->inode.update_backtrace(); // if the client created a _regular_ file via MKNOD, it's highly likely they'll // want to write to it (e.g., if they are reexporting NFS) if (S_ISREG(newi->inode.mode)) { dout(15) << " setting a client_range too, since this is a regular file" << dendl; newi->inode.client_ranges[client].range.first = 0; newi->inode.client_ranges[client].range.last = newi->inode.get_layout_size_increment(); newi->inode.client_ranges[client].follows = follows; // issue a cap on the file int cmode = CEPH_FILE_MODE_RDWR; Capability *cap = mds->locker->issue_new_caps(newi, cmode, mdr->session, realm, req->is_replay()); if (cap) { cap->set_wanted(0); // put locks in excl mode newi->filelock.set_state(LOCK_EXCL); newi->authlock.set_state(LOCK_EXCL); newi->xattrlock.set_state(LOCK_EXCL); cap->issue_norevoke(CEPH_CAP_AUTH_EXCL|CEPH_CAP_AUTH_SHARED| CEPH_CAP_XATTR_EXCL|CEPH_CAP_XATTR_SHARED| CEPH_CAP_ANY_FILE_WR); } } if (follows >= dn->first) dn->first = follows + 1; newi->first = dn->first; dout(10) << "mknod mode " << newi->inode.mode << " rdev " << newi->inode.rdev << dendl; // prepare finisher mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "mknod"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); journal_allocated_inos(mdr, &le->metablob); mdcache->predirty_journal_parents(mdr, &le->metablob, newi, dn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); le->metablob.add_primary_dentry(dn, newi, true, true, true); journal_and_reply(mdr, newi, dn, le, new C_MDS_mknod_finish(mds, mdr, dn, newi, follows)); } // MKDIR /* This function takes responsibility for the passed mdr*/ void Server::handle_client_mkdir(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, false, false, false); if (!dn) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CInode *diri = dn->get_dir()->get_inode(); rdlocks.insert(&diri->authlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // new inode SnapRealm *realm = dn->get_dir()->inode->find_snaprealm(); snapid_t follows = realm->get_newest_seq(); mdr->now = ceph_clock_now(g_ceph_context); unsigned mode = req->head.args.mkdir.mode; mode &= ~S_IFMT; mode |= S_IFDIR; CInode *newi = prepare_new_inode(mdr, dn->get_dir(), inodeno_t(req->head.ino), mode); assert(newi); // it's a directory. dn->push_projected_linkage(newi); newi->inode.version = dn->pre_dirty(); newi->inode.rstat.rsubdirs = 1; newi->inode.update_backtrace(); dout(12) << " follows " << follows << dendl; if (follows >= dn->first) dn->first = follows + 1; newi->first = dn->first; // ...and that new dir is empty. CDir *newdir = newi->get_or_open_dirfrag(mds->mdcache, frag_t()); newdir->mark_complete(); newdir->fnode.version = newdir->pre_dirty(); // prepare finisher mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "mkdir"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); journal_allocated_inos(mdr, &le->metablob); mdcache->predirty_journal_parents(mdr, &le->metablob, newi, dn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); le->metablob.add_primary_dentry(dn, newi, true, true); le->metablob.add_new_dir(newdir); // dirty AND complete AND new // issue a cap on the directory int cmode = CEPH_FILE_MODE_RDWR; Capability *cap = mds->locker->issue_new_caps(newi, cmode, mdr->session, realm, req->is_replay()); if (cap) { cap->set_wanted(0); // put locks in excl mode newi->filelock.set_state(LOCK_EXCL); newi->authlock.set_state(LOCK_EXCL); newi->xattrlock.set_state(LOCK_EXCL); cap->issue_norevoke(CEPH_CAP_AUTH_EXCL|CEPH_CAP_AUTH_SHARED| CEPH_CAP_XATTR_EXCL|CEPH_CAP_XATTR_SHARED); } // make sure this inode gets into the journal le->metablob.add_opened_ino(newi->ino()); LogSegment *ls = mds->mdlog->get_current_segment(); ls->open_files.push_back(&newi->item_open_file); journal_and_reply(mdr, newi, dn, le, new C_MDS_mknod_finish(mds, mdr, dn, newi, follows)); } // SYMLINK void Server::handle_client_symlink(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; set rdlocks, wrlocks, xlocks; CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, false, false, false); if (!dn) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CInode *diri = dn->get_dir()->get_inode(); rdlocks.insert(&diri->authlock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; mdr->now = ceph_clock_now(g_ceph_context); snapid_t follows = dn->get_dir()->inode->find_snaprealm()->get_newest_seq(); unsigned mode = S_IFLNK | 0777; CInode *newi = prepare_new_inode(mdr, dn->get_dir(), inodeno_t(req->head.ino), mode); assert(newi); // it's a symlink dn->push_projected_linkage(newi); newi->symlink = req->get_path2(); newi->inode.size = newi->symlink.length(); newi->inode.rstat.rbytes = newi->inode.size; newi->inode.rstat.rfiles = 1; newi->inode.version = dn->pre_dirty(); newi->inode.update_backtrace(); if (follows >= dn->first) dn->first = follows + 1; newi->first = dn->first; // prepare finisher mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "symlink"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); journal_allocated_inos(mdr, &le->metablob); mdcache->predirty_journal_parents(mdr, &le->metablob, newi, dn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); le->metablob.add_primary_dentry(dn, newi, true, true); journal_and_reply(mdr, newi, dn, le, new C_MDS_mknod_finish(mds, mdr, dn, newi, follows)); } // LINK void Server::handle_client_link(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; dout(7) << "handle_client_link " << req->get_filepath() << " to " << req->get_filepath2() << dendl; set rdlocks, wrlocks, xlocks; CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, false, false, false); if (!dn) return; CInode *targeti = rdlock_path_pin_ref(mdr, 1, rdlocks, false); if (!targeti) return; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CDir *dir = dn->get_dir(); dout(7) << "handle_client_link link " << dn->get_name() << " in " << *dir << dendl; dout(7) << "target is " << *targeti << dendl; if (targeti->is_dir()) { dout(7) << "target is a dir, failing..." << dendl; reply_request(mdr, -EINVAL); return; } xlocks.insert(&targeti->linklock); // take any locks needed for anchor creation/verification // NOTE: we do this on the master even if the anchor/link update may happen // on the slave. That means we may have out of date anchor state on our // end. That's fine: either, we xlock when we don't need to (slow but // not a problem), or we rdlock when we need to xlock, but then discover we // need to xlock and on our next pass through we adjust the locks (this works // as long as the linklock rdlock isn't the very last lock we take). mds->mdcache->anchor_create_prep_locks(mdr, targeti, rdlocks, xlocks); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // pick mtime if (mdr->now == utime_t()) mdr->now = ceph_clock_now(g_ceph_context); // does the target need an anchor? if (targeti->is_auth()) { if (targeti->is_anchored()) { dout(7) << "target anchored already (nlink=" << targeti->inode.nlink << "), sweet" << dendl; } else { dout(7) << "target needs anchor, nlink=" << targeti->inode.nlink << ", creating anchor" << dendl; mdcache->anchor_create(mdr, targeti, new C_MDS_RetryRequest(mdcache, mdr)); return; } } // go! assert(g_conf->mds_kill_link_at != 1); // local or remote? if (targeti->is_auth()) _link_local(mdr, dn, targeti); else _link_remote(mdr, true, dn, targeti); } class C_MDS_link_local_finish : public Context { MDS *mds; MDRequestRef mdr; CDentry *dn; CInode *targeti; version_t dnpv; version_t tipv; public: C_MDS_link_local_finish(MDS *m, MDRequestRef& r, CDentry *d, CInode *ti, version_t dnpv_, version_t tipv_) : mds(m), mdr(r), dn(d), targeti(ti), dnpv(dnpv_), tipv(tipv_) { } void finish(int r) { assert(r == 0); mds->server->_link_local_finish(mdr, dn, targeti, dnpv, tipv); } }; void Server::_link_local(MDRequestRef& mdr, CDentry *dn, CInode *targeti) { dout(10) << "_link_local " << *dn << " to " << *targeti << dendl; mdr->ls = mdlog->get_current_segment(); // predirty NEW dentry version_t dnpv = dn->pre_dirty(); version_t tipv = targeti->pre_dirty(); // project inode update inode_t *pi = targeti->project_inode(); pi->nlink++; pi->ctime = mdr->now; pi->version = tipv; snapid_t follows = dn->get_dir()->inode->find_snaprealm()->get_newest_seq(); if (follows >= dn->first) dn->first = follows; // log + wait EUpdate *le = new EUpdate(mdlog, "link_local"); mdlog->start_entry(le); le->metablob.add_client_req(mdr->reqid, mdr->client_request->get_oldest_client_tid()); mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, 1); // new dn mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, 0, PREDIRTY_PRIMARY); // targeti le->metablob.add_remote_dentry(dn, true, targeti->ino(), targeti->d_type()); // new remote mdcache->journal_dirty_inode(mdr.get(), &le->metablob, targeti); // do this after predirty_*, to avoid funky extra dnl arg dn->push_projected_linkage(targeti->ino(), targeti->d_type()); journal_and_reply(mdr, targeti, dn, le, new C_MDS_link_local_finish(mds, mdr, dn, targeti, dnpv, tipv)); } void Server::_link_local_finish(MDRequestRef& mdr, CDentry *dn, CInode *targeti, version_t dnpv, version_t tipv) { dout(10) << "_link_local_finish " << *dn << " to " << *targeti << dendl; // link and unlock the NEW dentry dn->pop_projected_linkage(); dn->mark_dirty(dnpv, mdr->ls); // target inode targeti->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); mds->mdcache->send_dentry_link(dn); // bump target popularity mds->balancer->hit_inode(mdr->now, targeti, META_POP_IWR); mds->balancer->hit_dir(mdr->now, dn->get_dir(), META_POP_IWR); // reply MClientReply *reply = new MClientReply(mdr->client_request, 0); reply_request(mdr, reply); } // link / unlink remote class C_MDS_link_remote_finish : public Context { MDS *mds; MDRequestRef mdr; bool inc; CDentry *dn; CInode *targeti; version_t dpv; public: C_MDS_link_remote_finish(MDS *m, MDRequestRef& r, bool i, CDentry *d, CInode *ti) : mds(m), mdr(r), inc(i), dn(d), targeti(ti), dpv(d->get_projected_version()) {} void finish(int r) { assert(r == 0); mds->server->_link_remote_finish(mdr, inc, dn, targeti, dpv); } }; void Server::_link_remote(MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti) { dout(10) << "_link_remote " << (inc ? "link ":"unlink ") << *dn << " to " << *targeti << dendl; // 1. send LinkPrepare to dest (journal nlink++ prepare) int linkauth = targeti->authority().first; if (mdr->more()->witnessed.count(linkauth) == 0) { if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(linkauth)) { dout(10) << " targeti auth mds." << linkauth << " is not active" << dendl; if (mdr->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(linkauth, new C_MDS_RetryRequest(mdcache, mdr)); return; } dout(10) << " targeti auth must prepare nlink++/--" << dendl; int op; if (inc) op = MMDSSlaveRequest::OP_LINKPREP; else op = MMDSSlaveRequest::OP_UNLINKPREP; MMDSSlaveRequest *req = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, op); targeti->set_object_info(req->get_object_info()); req->now = mdr->now; mds->send_message_mds(req, linkauth); assert(mdr->more()->waiting_on_slave.count(linkauth) == 0); mdr->more()->waiting_on_slave.insert(linkauth); return; } dout(10) << " targeti auth has prepared nlink++/--" << dendl; assert(g_conf->mds_kill_link_at != 2); // add to event mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, inc ? "link_remote":"unlink_remote"); mdlog->start_entry(le); le->metablob.add_client_req(mdr->reqid, mdr->client_request->get_oldest_client_tid()); if (!mdr->more()->witnessed.empty()) { dout(20) << " noting uncommitted_slaves " << mdr->more()->witnessed << dendl; le->reqid = mdr->reqid; le->had_slaves = true; mds->mdcache->add_uncommitted_master(mdr->reqid, mdr->ls, mdr->more()->witnessed); } if (inc) { dn->pre_dirty(); mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, 1); le->metablob.add_remote_dentry(dn, true, targeti->ino(), targeti->d_type()); // new remote dn->push_projected_linkage(targeti->ino(), targeti->d_type()); } else { dn->pre_dirty(); mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, -1); mdcache->journal_cow_dentry(mdr.get(), &le->metablob, dn); le->metablob.add_null_dentry(dn, true); } if (mdr->more()->dst_reanchor_atid) le->metablob.add_table_transaction(TABLE_ANCHOR, mdr->more()->dst_reanchor_atid); journal_and_reply(mdr, targeti, dn, le, new C_MDS_link_remote_finish(mds, mdr, inc, dn, targeti)); } void Server::_link_remote_finish(MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti, version_t dpv) { dout(10) << "_link_remote_finish " << (inc ? "link ":"unlink ") << *dn << " to " << *targeti << dendl; assert(g_conf->mds_kill_link_at != 3); if (!mdr->more()->witnessed.empty()) mdcache->logged_master_update(mdr->reqid); if (inc) { // link the new dentry dn->pop_projected_linkage(); dn->mark_dirty(dpv, mdr->ls); } else { // unlink main dentry dn->get_dir()->unlink_inode(dn); dn->mark_dirty(dn->get_projected_version(), mdr->ls); // dirty old dentry } mdr->apply(); if (inc) mds->mdcache->send_dentry_link(dn); else { MDRequestRef null_ref; mds->mdcache->send_dentry_unlink(dn, NULL, null_ref); } // commit anchor update? if (mdr->more()->dst_reanchor_atid) mds->anchorclient->commit(mdr->more()->dst_reanchor_atid, mdr->ls); // bump target popularity mds->balancer->hit_inode(mdr->now, targeti, META_POP_IWR); mds->balancer->hit_dir(mdr->now, dn->get_dir(), META_POP_IWR); // reply MClientReply *reply = new MClientReply(mdr->client_request, 0); reply_request(mdr, reply); if (!inc) // removing a new dn? dn->get_dir()->try_remove_unlinked_dn(dn); } // remote linking/unlinking class C_MDS_SlaveLinkPrep : public Context { Server *server; MDRequestRef mdr; CInode *targeti; public: C_MDS_SlaveLinkPrep(Server *s, MDRequestRef& r, CInode *t) : server(s), mdr(r), targeti(t) { } void finish(int r) { assert(r == 0); server->_logged_slave_link(mdr, targeti); } }; class C_MDS_SlaveLinkCommit : public Context { Server *server; MDRequestRef mdr; CInode *targeti; public: C_MDS_SlaveLinkCommit(Server *s, MDRequestRef& r, CInode *t) : server(s), mdr(r), targeti(t) { } void finish(int r) { server->_commit_slave_link(mdr, r, targeti); } }; /* This function DOES put the mdr->slave_request before returning*/ void Server::handle_slave_link_prep(MDRequestRef& mdr) { dout(10) << "handle_slave_link_prep " << *mdr << " on " << mdr->slave_request->get_object_info() << dendl; assert(g_conf->mds_kill_link_at != 4); CInode *targeti = mdcache->get_inode(mdr->slave_request->get_object_info().ino); assert(targeti); dout(10) << "targeti " << *targeti << dendl; CDentry *dn = targeti->get_parent_dn(); CDentry::linkage_t *dnl = dn->get_linkage(); assert(dnl->is_primary()); mdr->now = mdr->slave_request->now; mdr->auth_pin(targeti); //assert(0); // test hack: make sure master can handle a slave that fails to prepare... // anchor? if (mdr->slave_request->get_op() == MMDSSlaveRequest::OP_LINKPREP) { // NOTE: the master took any locks needed for anchor creation/verification. if (targeti->is_anchored()) { dout(7) << "target anchored already (nlink=" << targeti->inode.nlink << "), sweet" << dendl; } else { dout(7) << "target needs anchor, nlink=" << targeti->inode.nlink << ", creating anchor" << dendl; mdcache->anchor_create(mdr, targeti, new C_MDS_RetryRequest(mdcache, mdr)); return; } } assert(g_conf->mds_kill_link_at != 5); // journal it mdr->ls = mdlog->get_current_segment(); ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_link_prep", mdr->reqid, mdr->slave_to_mds, ESlaveUpdate::OP_PREPARE, ESlaveUpdate::LINK); mdlog->start_entry(le); inode_t *pi = dnl->get_inode()->project_inode(); // update journaled target inode bool inc; if (mdr->slave_request->get_op() == MMDSSlaveRequest::OP_LINKPREP) { inc = true; pi->nlink++; } else { inc = false; pi->nlink--; } link_rollback rollback; rollback.reqid = mdr->reqid; rollback.ino = targeti->ino(); rollback.old_ctime = targeti->inode.ctime; // we hold versionlock xlock; no concorrent projections fnode_t *pf = targeti->get_parent_dn()->get_dir()->get_projected_fnode(); rollback.old_dir_mtime = pf->fragstat.mtime; rollback.old_dir_rctime = pf->rstat.rctime; rollback.was_inc = inc; ::encode(rollback, le->rollback); mdr->more()->rollback_bl = le->rollback; pi->ctime = mdr->now; pi->version = targeti->pre_dirty(); dout(10) << " projected inode " << pi << " v " << pi->version << dendl; // commit case mdcache->predirty_journal_parents(mdr, &le->commit, dnl->get_inode(), 0, PREDIRTY_SHALLOW|PREDIRTY_PRIMARY, 0); mdcache->journal_dirty_inode(mdr.get(), &le->commit, targeti); // set up commit waiter mdr->more()->slave_commit = new C_MDS_SlaveLinkCommit(this, mdr, targeti); mdlog->submit_entry(le, new C_MDS_SlaveLinkPrep(this, mdr, targeti)); mdlog->flush(); } void Server::_logged_slave_link(MDRequestRef& mdr, CInode *targeti) { dout(10) << "_logged_slave_link " << *mdr << " " << *targeti << dendl; assert(g_conf->mds_kill_link_at != 6); // update the target targeti->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); // hit pop mds->balancer->hit_inode(mdr->now, targeti, META_POP_IWR); // done. mdr->slave_request->put(); mdr->slave_request = 0; // ack if (!mdr->aborted) { MMDSSlaveRequest *reply = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_LINKPREPACK); mds->send_message_mds(reply, mdr->slave_to_mds); } else { dout(10) << " abort flag set, finishing" << dendl; mdcache->request_finish(mdr); } } struct C_MDS_CommittedSlave : public Context { Server *server; MDRequestRef mdr; C_MDS_CommittedSlave(Server *s, MDRequestRef& m) : server(s), mdr(m) {} void finish(int r) { server->_committed_slave(mdr); } }; void Server::_commit_slave_link(MDRequestRef& mdr, int r, CInode *targeti) { dout(10) << "_commit_slave_link " << *mdr << " r=" << r << " " << *targeti << dendl; assert(g_conf->mds_kill_link_at != 7); if (r == 0) { // drop our pins, etc. mdr->cleanup(); // write a commit to the journal ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_link_commit", mdr->reqid, mdr->slave_to_mds, ESlaveUpdate::OP_COMMIT, ESlaveUpdate::LINK); mdlog->start_submit_entry(le, new C_MDS_CommittedSlave(this, mdr)); mdlog->flush(); } else { do_link_rollback(mdr->more()->rollback_bl, mdr->slave_to_mds, mdr); } } void Server::_committed_slave(MDRequestRef& mdr) { dout(10) << "_committed_slave " << *mdr << dendl; assert(g_conf->mds_kill_link_at != 8); MMDSSlaveRequest *req = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_COMMITTED); mds->send_message_mds(req, mdr->slave_to_mds); mds->mdcache->request_finish(mdr); } struct C_MDS_LoggedLinkRollback : public Context { Server *server; MutationRef mut; MDRequestRef mdr; C_MDS_LoggedLinkRollback(Server *s, MutationRef& m, MDRequestRef& r) : server(s), mut(m), mdr(r) {} void finish(int r) { server->_link_rollback_finish(mut, mdr); } }; void Server::do_link_rollback(bufferlist &rbl, int master, MDRequestRef& mdr) { link_rollback rollback; bufferlist::iterator p = rbl.begin(); ::decode(rollback, p); dout(10) << "do_link_rollback on " << rollback.reqid << (rollback.was_inc ? " inc":" dec") << " ino " << rollback.ino << dendl; assert(g_conf->mds_kill_link_at != 9); mds->mdcache->add_rollback(rollback.reqid, master); // need to finish this update before resolve finishes assert(mdr || mds->is_resolve()); MutationRef mut(new MutationImpl(rollback.reqid)); mut->ls = mds->mdlog->get_current_segment(); CInode *in = mds->mdcache->get_inode(rollback.ino); assert(in); dout(10) << " target is " << *in << dendl; assert(!in->is_projected()); // live slave request hold versionlock xlock. inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); mut->add_projected_inode(in); // parent dir rctime CDir *parent = in->get_projected_parent_dn()->get_dir(); fnode_t *pf = parent->project_fnode(); mut->add_projected_fnode(parent); pf->version = parent->pre_dirty(); if (pf->fragstat.mtime == pi->ctime) { pf->fragstat.mtime = rollback.old_dir_mtime; if (pf->rstat.rctime == pi->ctime) pf->rstat.rctime = rollback.old_dir_rctime; mut->add_updated_lock(&parent->get_inode()->filelock); mut->add_updated_lock(&parent->get_inode()->nestlock); } // inode pi->ctime = rollback.old_ctime; if (rollback.was_inc) pi->nlink--; else pi->nlink++; // journal it ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_link_rollback", rollback.reqid, master, ESlaveUpdate::OP_ROLLBACK, ESlaveUpdate::LINK); mdlog->start_entry(le); le->commit.add_dir_context(parent); le->commit.add_dir(parent, true); le->commit.add_primary_dentry(in->get_projected_parent_dn(), 0, true); mdlog->submit_entry(le, new C_MDS_LoggedLinkRollback(this, mut, mdr)); mdlog->flush(); } void Server::_link_rollback_finish(MutationRef& mut, MDRequestRef& mdr) { dout(10) << "_link_rollback_finish" << dendl; assert(g_conf->mds_kill_link_at != 10); mut->apply(); if (mdr) mds->mdcache->request_finish(mdr); mds->mdcache->finish_rollback(mut->reqid); mut->cleanup(); } /* This function DOES NOT put the passed message before returning*/ void Server::handle_slave_link_prep_ack(MDRequestRef& mdr, MMDSSlaveRequest *m) { dout(10) << "handle_slave_link_prep_ack " << *mdr << " " << *m << dendl; int from = m->get_source().num(); assert(g_conf->mds_kill_link_at != 11); // note slave mdr->more()->slaves.insert(from); // witnessed! assert(mdr->more()->witnessed.count(from) == 0); mdr->more()->witnessed.insert(from); // remove from waiting list assert(mdr->more()->waiting_on_slave.count(from)); mdr->more()->waiting_on_slave.erase(from); assert(mdr->more()->waiting_on_slave.empty()); dispatch_client_request(mdr); // go again! } // UNLINK void Server::handle_client_unlink(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; client_t client = mdr->get_client(); // rmdir or unlink? bool rmdir = false; if (req->get_op() == CEPH_MDS_OP_RMDIR) rmdir = true; if (req->get_filepath().depth() == 0) { reply_request(mdr, -EINVAL); return; } // traverse to path vector trace; CInode *in; int r = mdcache->path_traverse(mdr, NULL, NULL, req->get_filepath(), &trace, &in, MDS_TRAVERSE_FORWARD); if (r > 0) return; if (r < 0) { reply_request(mdr, r); return; } if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CDentry *dn = trace[trace.size()-1]; assert(dn); if (!dn->is_auth()) { mdcache->request_forward(mdr, dn->authority().first); return; } CDentry::linkage_t *dnl = dn->get_linkage(client, mdr); assert(!dnl->is_null()); if (rmdir) { dout(7) << "handle_client_rmdir on " << *dn << dendl; } else { dout(7) << "handle_client_unlink on " << *dn << dendl; } dout(7) << "dn links to " << *in << dendl; // rmdir vs is_dir if (in->is_dir()) { if (rmdir) { // do empty directory checks if (_dir_is_nonempty_unlocked(mdr, in)) { reply_request(mdr, -ENOTEMPTY); return; } } else { dout(7) << "handle_client_unlink on dir " << *in << ", returning error" << dendl; reply_request(mdr, -EISDIR); return; } } else { if (rmdir) { // unlink dout(7) << "handle_client_rmdir on non-dir " << *in << ", returning error" << dendl; reply_request(mdr, -ENOTDIR); return; } } // -- create stray dentry? -- CDentry *straydn = NULL; if (dnl->is_primary()) { straydn = prepare_stray_dentry(mdr, dnl->get_inode()); dout(10) << " straydn is " << *straydn << dendl; } else if (mdr->straydn) { mdr->unpin(mdr->straydn); mdr->straydn = NULL; } // lock set rdlocks, wrlocks, xlocks; for (int i=0; i<(int)trace.size()-1; i++) rdlocks.insert(&trace[i]->lock); xlocks.insert(&dn->lock); wrlocks.insert(&dn->get_dir()->inode->filelock); wrlocks.insert(&dn->get_dir()->inode->nestlock); xlocks.insert(&in->linklock); if (straydn) { wrlocks.insert(&straydn->get_dir()->inode->filelock); wrlocks.insert(&straydn->get_dir()->inode->nestlock); xlocks.insert(&straydn->lock); } if (in->is_dir()) rdlocks.insert(&in->filelock); // to verify it's empty mds->locker->include_snap_rdlocks(rdlocks, dnl->get_inode()); // if we unlink a snapped multiversion inode and are creating a // remote link to it, it must be anchored. this mirrors the logic // in MDCache::journal_cow_dentry(). bool need_snap_dentry = dnl->is_primary() && in->is_multiversion() && in->find_snaprealm()->get_newest_seq() + 1 > dn->first; if (need_snap_dentry) { dout(10) << " i need to be anchored because i am multiversion and will get a remote cow dentry" << dendl; mds->mdcache->anchor_create_prep_locks(mdr, in, rdlocks, xlocks); } if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; if (in->is_dir() && _dir_is_nonempty(mdr, in)) { reply_request(mdr, -ENOTEMPTY); return; } // yay! if (mdr->now == utime_t()) mdr->now = ceph_clock_now(g_ceph_context); // NOTE: this is non-optimal. we create an anchor at the old // location, and then change it. we can do better, but it's more // complicated. this is fine for now. if (need_snap_dentry && !in->is_anchored()) { mdcache->anchor_create(mdr, in, new C_MDS_RetryRequest(mdcache, mdr)); return; } // get stray dn ready? if (dnl->is_primary()) { if (!mdr->more()->dst_reanchor_atid && in->is_anchored()) { dout(10) << "reanchoring to stray " << *dnl->get_inode() << dendl; vector trace; straydn->make_anchor_trace(trace, dnl->get_inode()); mds->anchorclient->prepare_update(dnl->get_inode()->ino(), trace, &mdr->more()->dst_reanchor_atid, new C_MDS_RetryRequest(mdcache, mdr)); return; } } if (in->is_dir() && in->has_subtree_root_dirfrag()) { // subtree root auths need to be witnesses set witnesses; list ls; in->get_subtree_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; int auth = dir->authority().first; witnesses.insert(auth); dout(10) << " need mds." << auth << " to witness for dirfrag " << *dir << dendl; } dout(10) << " witnesses " << witnesses << ", have " << mdr->more()->witnessed << dendl; for (set::iterator p = witnesses.begin(); p != witnesses.end(); ++p) { if (mdr->more()->witnessed.count(*p)) { dout(10) << " already witnessed by mds." << *p << dendl; } else if (mdr->more()->waiting_on_slave.count(*p)) { dout(10) << " already waiting on witness mds." << *p << dendl; } else { if (!_rmdir_prepare_witness(mdr, *p, dn, straydn)) return; } } if (!mdr->more()->waiting_on_slave.empty()) return; // we're waiting for a witness. } // ok! if (dnl->is_remote() && !dnl->get_inode()->is_auth()) _link_remote(mdr, false, dn, dnl->get_inode()); else _unlink_local(mdr, dn, straydn); } class C_MDS_unlink_local_finish : public Context { MDS *mds; MDRequestRef mdr; CDentry *dn; CDentry *straydn; version_t dnpv; // deleted dentry public: C_MDS_unlink_local_finish(MDS *m, MDRequestRef& r, CDentry *d, CDentry *sd) : mds(m), mdr(r), dn(d), straydn(sd), dnpv(d->get_projected_version()) {} void finish(int r) { assert(r == 0); mds->server->_unlink_local_finish(mdr, dn, straydn, dnpv); } }; void Server::_unlink_local(MDRequestRef& mdr, CDentry *dn, CDentry *straydn) { dout(10) << "_unlink_local " << *dn << dendl; CDentry::linkage_t *dnl = dn->get_projected_linkage(); CInode *in = dnl->get_inode(); SnapRealm *realm = in->find_snaprealm(); snapid_t follows = realm->get_newest_seq(); // ok, let's do it. mdr->ls = mdlog->get_current_segment(); // prepare log entry EUpdate *le = new EUpdate(mdlog, "unlink_local"); mdlog->start_entry(le); le->metablob.add_client_req(mdr->reqid, mdr->client_request->get_oldest_client_tid()); if (!mdr->more()->witnessed.empty()) { dout(20) << " noting uncommitted_slaves " << mdr->more()->witnessed << dendl; le->reqid = mdr->reqid; le->had_slaves = true; mds->mdcache->add_uncommitted_master(mdr->reqid, mdr->ls, mdr->more()->witnessed); } if (straydn) { assert(dnl->is_primary()); straydn->push_projected_linkage(in); straydn->first = follows + 1; } // the unlinked dentry dn->pre_dirty(); inode_t *pi = in->project_inode(); mdr->add_projected_inode(in); // do this _after_ my dn->pre_dirty().. we apply that one manually. pi->version = in->pre_dirty(); pi->ctime = mdr->now; pi->nlink--; if (pi->nlink == 0) in->state_set(CInode::STATE_ORPHAN); if (dnl->is_primary()) { // primary link. add stray dentry. assert(straydn); mdcache->predirty_journal_parents(mdr, &le->metablob, in, dn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, -1); mdcache->predirty_journal_parents(mdr, &le->metablob, in, straydn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); // project snaprealm, too if (in->snaprealm || follows + 1 > dn->first) in->project_past_snaprealm_parent(straydn->get_dir()->inode->find_snaprealm()); pi->update_backtrace(); le->metablob.add_primary_dentry(straydn, in, true, true); } else { // remote link. update remote inode. mdcache->predirty_journal_parents(mdr, &le->metablob, in, dn->get_dir(), PREDIRTY_DIR, -1); mdcache->predirty_journal_parents(mdr, &le->metablob, in, 0, PREDIRTY_PRIMARY); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, in); } mdcache->journal_cow_dentry(mdr.get(), &le->metablob, dn); le->metablob.add_null_dentry(dn, true); if (in->is_dir()) { dout(10) << " noting renamed (unlinked) dir ino " << in->ino() << " in metablob" << dendl; le->metablob.renamed_dirino = in->ino(); } if (mdr->more()->dst_reanchor_atid) le->metablob.add_table_transaction(TABLE_ANCHOR, mdr->more()->dst_reanchor_atid); dn->push_projected_linkage(); if (in->is_dir()) { assert(straydn); mds->mdcache->project_subtree_rename(in, dn->get_dir(), straydn->get_dir()); } journal_and_reply(mdr, 0, dn, le, new C_MDS_unlink_local_finish(mds, mdr, dn, straydn)); } void Server::_unlink_local_finish(MDRequestRef& mdr, CDentry *dn, CDentry *straydn, version_t dnpv) { dout(10) << "_unlink_local_finish " << *dn << dendl; if (!mdr->more()->witnessed.empty()) mdcache->logged_master_update(mdr->reqid); // unlink main dentry dn->get_dir()->unlink_inode(dn); dn->pop_projected_linkage(); // relink as stray? (i.e. was primary link?) CDentry::linkage_t *straydnl = 0; bool snap_is_new = false; if (straydn) { dout(20) << " straydn is " << *straydn << dendl; straydnl = straydn->pop_projected_linkage(); snap_is_new = straydnl->get_inode()->snaprealm ? true : false; mdcache->touch_dentry_bottom(straydn); } dn->mark_dirty(dnpv, mdr->ls); mdr->apply(); if (snap_is_new) //only new if straydnl exists mdcache->do_realm_invalidate_and_update_notify(straydnl->get_inode(), CEPH_SNAP_OP_SPLIT, true); mds->mdcache->send_dentry_unlink(dn, straydn, mdr); // update subtree map? if (straydn && straydnl->get_inode()->is_dir()) mdcache->adjust_subtree_after_rename(straydnl->get_inode(), dn->get_dir(), true); // commit anchor update? if (mdr->more()->dst_reanchor_atid) mds->anchorclient->commit(mdr->more()->dst_reanchor_atid, mdr->ls); // bump pop mds->balancer->hit_dir(mdr->now, dn->get_dir(), META_POP_IWR); // reply MClientReply *reply = new MClientReply(mdr->client_request, 0); reply_request(mdr, reply); // clean up? if (straydn) mdcache->eval_stray(straydn); // removing a new dn? dn->get_dir()->try_remove_unlinked_dn(dn); } bool Server::_rmdir_prepare_witness(MDRequestRef& mdr, int who, CDentry *dn, CDentry *straydn) { if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(who)) { dout(10) << "_rmdir_prepare_witness mds." << who << " is not active" << dendl; if (mdr->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(who, new C_MDS_RetryRequest(mdcache, mdr)); return false; } dout(10) << "_rmdir_prepare_witness mds." << who << dendl; MMDSSlaveRequest *req = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_RMDIRPREP); dn->make_path(req->srcdnpath); straydn->make_path(req->destdnpath); req->now = mdr->now; mdcache->replicate_stray(straydn, who, req->stray); mds->send_message_mds(req, who); assert(mdr->more()->waiting_on_slave.count(who) == 0); mdr->more()->waiting_on_slave.insert(who); return true; } struct C_MDS_SlaveRmdirPrep : public Context { Server *server; MDRequestRef mdr; CDentry *dn, *straydn; C_MDS_SlaveRmdirPrep(Server *s, MDRequestRef& r, CDentry *d, CDentry *st) : server(s), mdr(r), dn(d), straydn(st) {} void finish(int r) { server->_logged_slave_rmdir(mdr, dn, straydn); } }; struct C_MDS_SlaveRmdirCommit : public Context { Server *server; MDRequestRef mdr; C_MDS_SlaveRmdirCommit(Server *s, MDRequestRef& r) : server(s), mdr(r) { } void finish(int r) { server->_commit_slave_rmdir(mdr, r); } }; void Server::handle_slave_rmdir_prep(MDRequestRef& mdr) { dout(10) << "handle_slave_rmdir_prep " << *mdr << " " << mdr->slave_request->srcdnpath << " to " << mdr->slave_request->destdnpath << dendl; vector trace; filepath srcpath(mdr->slave_request->srcdnpath); dout(10) << " src " << srcpath << dendl; CInode *in; int r = mdcache->path_traverse(mdr, NULL, NULL, srcpath, &trace, &in, MDS_TRAVERSE_DISCOVERXLOCK); assert(r == 0); CDentry *dn = trace[trace.size()-1]; dout(10) << " dn " << *dn << dendl; mdr->pin(dn); assert(mdr->straydn); CDentry *straydn = mdr->straydn; dout(10) << " straydn " << *straydn << dendl; mdr->now = mdr->slave_request->now; rmdir_rollback rollback; rollback.reqid = mdr->reqid; rollback.src_dir = dn->get_dir()->dirfrag(); rollback.src_dname = dn->name; rollback.dest_dir = straydn->get_dir()->dirfrag(); rollback.dest_dname = straydn->name; ::encode(rollback, mdr->more()->rollback_bl); dout(20) << " rollback is " << mdr->more()->rollback_bl.length() << " bytes" << dendl; straydn->push_projected_linkage(in); dn->push_projected_linkage(); ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_rmdir", mdr->reqid, mdr->slave_to_mds, ESlaveUpdate::OP_PREPARE, ESlaveUpdate::RMDIR); mdlog->start_entry(le); le->rollback = mdr->more()->rollback_bl; le->commit.add_dir_context(straydn->get_dir()); le->commit.add_primary_dentry(straydn, in, true); // slave: no need to journal original dentry dout(10) << " noting renamed (unlinked) dir ino " << in->ino() << " in metablob" << dendl; le->commit.renamed_dirino = in->ino(); mds->mdcache->project_subtree_rename(in, dn->get_dir(), straydn->get_dir()); // set up commit waiter mdr->more()->slave_commit = new C_MDS_SlaveRmdirCommit(this, mdr); mdlog->submit_entry(le, new C_MDS_SlaveRmdirPrep(this, mdr, dn, straydn)); mdlog->flush(); } void Server::_logged_slave_rmdir(MDRequestRef& mdr, CDentry *dn, CDentry *straydn) { dout(10) << "_logged_slave_rmdir " << *mdr << " on " << *dn << dendl; // update our cache now, so we are consistent with what is in the journal // when we journal a subtree map CInode *in = dn->get_linkage()->get_inode(); dn->get_dir()->unlink_inode(dn); straydn->pop_projected_linkage(); dn->pop_projected_linkage(); mdcache->adjust_subtree_after_rename(in, dn->get_dir(), true); // done. mdr->slave_request->put(); mdr->slave_request = 0; mdr->straydn = 0; if (!mdr->aborted) { MMDSSlaveRequest *reply = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_RMDIRPREPACK); mds->send_message_mds(reply, mdr->slave_to_mds); } else { dout(10) << " abort flag set, finishing" << dendl; mdcache->request_finish(mdr); } } void Server::handle_slave_rmdir_prep_ack(MDRequestRef& mdr, MMDSSlaveRequest *ack) { dout(10) << "handle_slave_rmdir_prep_ack " << *mdr << " " << *ack << dendl; int from = ack->get_source().num(); mdr->more()->slaves.insert(from); mdr->more()->witnessed.insert(from); // remove from waiting list assert(mdr->more()->waiting_on_slave.count(from)); mdr->more()->waiting_on_slave.erase(from); if (mdr->more()->waiting_on_slave.empty()) dispatch_client_request(mdr); // go again! else dout(10) << "still waiting on slaves " << mdr->more()->waiting_on_slave << dendl; } void Server::_commit_slave_rmdir(MDRequestRef& mdr, int r) { dout(10) << "_commit_slave_rmdir " << *mdr << " r=" << r << dendl; if (r == 0) { // write a commit to the journal ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_rmdir_commit", mdr->reqid, mdr->slave_to_mds, ESlaveUpdate::OP_COMMIT, ESlaveUpdate::RMDIR); mdlog->start_entry(le); mdr->cleanup(); mdlog->submit_entry(le, new C_MDS_CommittedSlave(this, mdr)); mdlog->flush(); } else { // abort do_rmdir_rollback(mdr->more()->rollback_bl, mdr->slave_to_mds, mdr); } } struct C_MDS_LoggedRmdirRollback : public Context { Server *server; MDRequestRef mdr; metareqid_t reqid; CDentry *dn; CDentry *straydn; C_MDS_LoggedRmdirRollback(Server *s, MDRequestRef& m, metareqid_t mr, CDentry *d, CDentry *st) : server(s), mdr(m), reqid(mr), dn(d), straydn(st) {} void finish(int r) { server->_rmdir_rollback_finish(mdr, reqid, dn, straydn); } }; void Server::do_rmdir_rollback(bufferlist &rbl, int master, MDRequestRef& mdr) { // unlink the other rollback methods, the rmdir rollback is only // needed to record the subtree changes in the journal for inode // replicas who are auth for empty dirfrags. no actual changes to // the file system are taking place here, so there is no Mutation. rmdir_rollback rollback; bufferlist::iterator p = rbl.begin(); ::decode(rollback, p); dout(10) << "do_rmdir_rollback on " << rollback.reqid << dendl; mds->mdcache->add_rollback(rollback.reqid, master); // need to finish this update before resolve finishes assert(mdr || mds->is_resolve()); CDir *dir = mds->mdcache->get_dirfrag(rollback.src_dir); if (!dir) dir = mds->mdcache->get_dirfrag(rollback.src_dir.ino, rollback.src_dname); assert(dir); CDentry *dn = dir->lookup(rollback.src_dname); assert(dn); dout(10) << " dn " << *dn << dendl; dir = mds->mdcache->get_dirfrag(rollback.dest_dir); assert(dir); CDentry *straydn = dir->lookup(rollback.dest_dname); assert(straydn); dout(10) << " straydn " << *dn << dendl; CInode *in = straydn->get_linkage()->get_inode(); dn->push_projected_linkage(in); straydn->push_projected_linkage(); ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_rmdir_rollback", rollback.reqid, master, ESlaveUpdate::OP_ROLLBACK, ESlaveUpdate::RMDIR); mdlog->start_entry(le); le->commit.add_dir_context(dn->get_dir()); le->commit.add_primary_dentry(dn, in, true); // slave: no need to journal straydn dout(10) << " noting renamed (unlinked) dir ino " << in->ino() << " in metablob" << dendl; le->commit.renamed_dirino = in->ino(); mdcache->project_subtree_rename(in, straydn->get_dir(), dn->get_dir()); mdlog->submit_entry(le, new C_MDS_LoggedRmdirRollback(this, mdr, rollback.reqid, dn, straydn)); mdlog->flush(); } void Server::_rmdir_rollback_finish(MDRequestRef& mdr, metareqid_t reqid, CDentry *dn, CDentry *straydn) { dout(10) << "_rmdir_rollback_finish " << reqid << dendl; straydn->get_dir()->unlink_inode(straydn); dn->pop_projected_linkage(); straydn->pop_projected_linkage(); CInode *in = dn->get_linkage()->get_inode(); mdcache->adjust_subtree_after_rename(in, straydn->get_dir(), true); if (mds->is_resolve()) { CDir *root = mdcache->get_subtree_root(straydn->get_dir()); mdcache->try_trim_non_auth_subtree(root); } if (mdr) mds->mdcache->request_finish(mdr); mds->mdcache->finish_rollback(reqid); } /** _dir_is_nonempty[_unlocked] * * check if a directory is non-empty (i.e. we can rmdir it). * * the unlocked varient this is a fastpath check. we can't really be * sure until we rdlock the filelock. */ bool Server::_dir_is_nonempty_unlocked(MDRequestRef& mdr, CInode *in) { dout(10) << "dir_is_nonempty_unlocked " << *in << dendl; assert(in->is_auth()); if (in->snaprealm && in->snaprealm->srnode.snaps.size()) return true; // in a snapshot! list ls; in->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; // is the frag obviously non-empty? if (dir->is_auth()) { if (dir->get_projected_fnode()->fragstat.size()) { dout(10) << "dir_is_nonempty_unlocked dirstat has " << dir->get_projected_fnode()->fragstat.size() << " items " << *dir << dendl; return true; } } } return false; } bool Server::_dir_is_nonempty(MDRequestRef& mdr, CInode *in) { dout(10) << "dir_is_nonempty " << *in << dendl; assert(in->is_auth()); assert(in->filelock.can_read(-1)); frag_info_t dirstat; version_t dirstat_version = in->get_projected_inode()->dirstat.version; list ls; in->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; fnode_t *pf = dir->get_projected_fnode(); if (pf->fragstat.size()) { dout(10) << "dir_is_nonempty_unlocked dirstat has " << pf->fragstat.size() << " items " << *dir << dendl; return true; } if (pf->accounted_fragstat.version == dirstat_version) dirstat.add(pf->accounted_fragstat); else dirstat.add(pf->fragstat); } return dirstat.size() != in->get_projected_inode()->dirstat.size(); } // ====================================================== class C_MDS_rename_finish : public Context { MDS *mds; MDRequestRef mdr; CDentry *srcdn; CDentry *destdn; CDentry *straydn; public: C_MDS_rename_finish(MDS *m, MDRequestRef& r, CDentry *sdn, CDentry *ddn, CDentry *stdn) : mds(m), mdr(r), srcdn(sdn), destdn(ddn), straydn(stdn) { } void finish(int r) { assert(r == 0); mds->server->_rename_finish(mdr, srcdn, destdn, straydn); } }; /** handle_client_rename * * rename master is the destdn auth. this is because cached inodes * must remain connected. thus, any replica of srci, must also * replicate destdn, and possibly straydn, so that srci (and * destdn->inode) remain connected during the rename. * * to do this, we freeze srci, then master (destdn auth) verifies that * all other nodes have also replciated destdn and straydn. note that * destdn replicas need not also replicate srci. this only works when * destdn is master. * * This function takes responsibility for the passed mdr. */ void Server::handle_client_rename(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; dout(7) << "handle_client_rename " << *req << dendl; filepath destpath = req->get_filepath(); filepath srcpath = req->get_filepath2(); if (destpath.depth() == 0 || srcpath.depth() == 0) { reply_request(mdr, -EINVAL); return; } const string &destname = destpath.last_dentry(); vector& srctrace = mdr->dn[1]; vector& desttrace = mdr->dn[0]; set rdlocks, wrlocks, xlocks; CDentry *destdn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, true, false, true); if (!destdn) return; dout(10) << " destdn " << *destdn << dendl; if (mdr->snapid != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CDentry::linkage_t *destdnl = destdn->get_projected_linkage(); CDir *destdir = destdn->get_dir(); assert(destdir->is_auth()); int r = mdcache->path_traverse(mdr, NULL, NULL, srcpath, &srctrace, NULL, MDS_TRAVERSE_DISCOVER); if (r > 0) return; // delayed if (r < 0) { if (r == -ESTALE) { dout(10) << "FAIL on ESTALE but attempting recovery" << dendl; Context *c = new C_MDS_TryFindInode(this, mdr); mdcache->find_ino_peers(srcpath.get_ino(), c); } else { dout(10) << "FAIL on error " << r << dendl; reply_request(mdr, r); } return; } assert(!srctrace.empty()); CDentry *srcdn = srctrace[srctrace.size()-1]; dout(10) << " srcdn " << *srcdn << dendl; if (srcdn->last != CEPH_NOSNAP) { reply_request(mdr, -EROFS); return; } CDentry::linkage_t *srcdnl = srcdn->get_projected_linkage(); CInode *srci = srcdnl->get_inode(); dout(10) << " srci " << *srci << dendl; CInode *oldin = 0; if (!destdnl->is_null()) { //dout(10) << "dest dn exists " << *destdn << dendl; oldin = mdcache->get_dentry_inode(destdn, mdr, true); if (!oldin) return; dout(10) << " oldin " << *oldin << dendl; // mv /some/thing /to/some/existing_other_thing if (oldin->is_dir() && !srci->is_dir()) { reply_request(mdr, -EISDIR); return; } if (!oldin->is_dir() && srci->is_dir()) { reply_request(mdr, -ENOTDIR); return; } // non-empty dir? if (oldin->is_dir() && _dir_is_nonempty_unlocked(mdr, oldin)) { reply_request(mdr, -ENOTEMPTY); return; } if (srci == oldin && !srcdn->get_dir()->inode->is_stray()) { reply_request(mdr, 0); // no-op. POSIX makes no sense. return; } } // -- some sanity checks -- // src+dest traces _must_ share a common ancestor for locking to prevent orphans if (destpath.get_ino() != srcpath.get_ino() && !(req->get_source().is_mds() && MDS_INO_IS_MDSDIR(srcpath.get_ino()))) { // <-- mds 'rename' out of stray dir is ok! // do traces share a dentry? CDentry *common = 0; for (unsigned i=0; i < srctrace.size(); i++) { for (unsigned j=0; j < desttrace.size(); j++) { if (srctrace[i] == desttrace[j]) { common = srctrace[i]; break; } } if (common) break; } if (common) { dout(10) << "rename src and dest traces share common dentry " << *common << dendl; } else { CInode *srcbase = srctrace[0]->get_dir()->get_inode(); CInode *destbase = destdir->get_inode(); if (!desttrace.empty()) destbase = desttrace[0]->get_dir()->get_inode(); // ok, extend srctrace toward root until it is an ancestor of desttrace. while (srcbase != destbase && !srcbase->is_projected_ancestor_of(destbase)) { srctrace.insert(srctrace.begin(), srcbase->get_projected_parent_dn()); dout(10) << "rename prepending srctrace with " << *srctrace[0] << dendl; srcbase = srcbase->get_projected_parent_dn()->get_dir()->get_inode(); } // then, extend destpath until it shares the same parent inode as srcpath. while (destbase != srcbase) { desttrace.insert(desttrace.begin(), destbase->get_projected_parent_dn()); rdlocks.insert(&desttrace[0]->lock); dout(10) << "rename prepending desttrace with " << *desttrace[0] << dendl; destbase = destbase->get_projected_parent_dn()->get_dir()->get_inode(); } dout(10) << "rename src and dest traces now share common ancestor " << *destbase << dendl; } } // src == dest? if (srcdn->get_dir() == destdir && srcdn->name == destname) { dout(7) << "rename src=dest, noop" << dendl; reply_request(mdr, 0); return; } // dest a child of src? // e.g. mv /usr /usr/foo CDentry *pdn = destdir->inode->parent; while (pdn) { if (pdn == srcdn) { dout(7) << "cannot rename item to be a child of itself" << dendl; reply_request(mdr, -EINVAL); return; } pdn = pdn->get_dir()->inode->parent; } // is this a stray migration, reintegration or merge? (sanity checks!) if (mdr->reqid.name.is_mds() && !(MDS_INO_IS_MDSDIR(srcpath.get_ino()) && MDS_INO_IS_STRAY(destpath.get_ino())) && !(destdnl->is_remote() && destdnl->get_remote_ino() == srci->ino())) { reply_request(mdr, -EINVAL); // actually, this won't reply, but whatev. return; } bool linkmerge = (srcdnl->get_inode() == destdnl->get_inode() && (srcdnl->is_primary() || destdnl->is_primary())); if (linkmerge) dout(10) << " this is a link merge" << dendl; // -- create stray dentry? -- CDentry *straydn = NULL; if (destdnl->is_primary() && !linkmerge) { straydn = prepare_stray_dentry(mdr, destdnl->get_inode()); dout(10) << " straydn is " << *straydn << dendl; } else if (mdr->straydn) { mdr->unpin(mdr->straydn); mdr->straydn = NULL; } // -- prepare witness list -- /* * NOTE: we use _all_ replicas as witnesses. * this probably isn't totally necessary (esp for file renames), * but if/when we change that, we have to make sure rejoin is * sufficiently robust to handle strong rejoins from survivors * with totally wrong dentry->inode linkage. * (currently, it can ignore rename effects, because the resolve * stage will sort them out.) */ set witnesses = mdr->more()->extra_witnesses; if (srcdn->is_auth()) srcdn->list_replicas(witnesses); else witnesses.insert(srcdn->authority().first); destdn->list_replicas(witnesses); if (destdnl->is_remote() && !oldin->is_auth()) witnesses.insert(oldin->authority().first); dout(10) << " witnesses " << witnesses << ", have " << mdr->more()->witnessed << dendl; // -- locks -- map remote_wrlocks; // srctrace items. this mirrors locks taken in rdlock_path_xlock_dentry for (int i=0; i<(int)srctrace.size(); i++) rdlocks.insert(&srctrace[i]->lock); xlocks.insert(&srcdn->lock); int srcdirauth = srcdn->get_dir()->authority().first; if (srcdirauth != mds->whoami) { dout(10) << " will remote_wrlock srcdir scatterlocks on mds." << srcdirauth << dendl; remote_wrlocks[&srcdn->get_dir()->inode->filelock] = srcdirauth; remote_wrlocks[&srcdn->get_dir()->inode->nestlock] = srcdirauth; if (srci->is_dir()) rdlocks.insert(&srci->dirfragtreelock); } else { wrlocks.insert(&srcdn->get_dir()->inode->filelock); wrlocks.insert(&srcdn->get_dir()->inode->nestlock); } mds->locker->include_snap_rdlocks(rdlocks, srcdn->get_dir()->inode); // straydn? if (straydn) { wrlocks.insert(&straydn->get_dir()->inode->filelock); wrlocks.insert(&straydn->get_dir()->inode->nestlock); xlocks.insert(&straydn->lock); } // xlock versionlock on dentries if there are witnesses. // replicas can't see projected dentry linkages, and will get // confused if we try to pipeline things. if (!witnesses.empty()) { // take xlock on all projected ancestor dentries for srcdn and destdn. // this ensures the srcdn and destdn can be traversed to by the witnesses. for (int i= 0; i<(int)srctrace.size(); i++) { if (srctrace[i]->is_auth() && srctrace[i]->is_projected()) xlocks.insert(&srctrace[i]->versionlock); } for (int i=0; i<(int)desttrace.size(); i++) { if (desttrace[i]->is_auth() && desttrace[i]->is_projected()) xlocks.insert(&desttrace[i]->versionlock); } // xlock srci and oldin's primary dentries, so witnesses can call // open_remote_ino() with 'want_locked=true' when the srcdn or destdn // is traversed. if (srcdnl->is_remote()) xlocks.insert(&srci->get_projected_parent_dn()->lock); if (destdnl->is_remote()) xlocks.insert(&oldin->get_projected_parent_dn()->lock); } // we need to update srci's ctime. xlock its least contended lock to do that... xlocks.insert(&srci->linklock); // xlock oldin (for nlink--) if (oldin) { xlocks.insert(&oldin->linklock); if (oldin->is_dir()) rdlocks.insert(&oldin->filelock); } if (srcdnl->is_primary() && srci->is_dir()) // FIXME: this should happen whenever we are renamning between // realms, regardless of the file type // FIXME: If/when this changes, make sure to update the // "allowance" in handle_slave_rename_prep xlocks.insert(&srci->snaplock); // FIXME: an auth bcast could be sufficient? else rdlocks.insert(&srci->snaplock); // take any locks needed for anchor creation/verification mds->mdcache->anchor_create_prep_locks(mdr, srci, rdlocks, xlocks); CInode *auth_pin_freeze = !srcdn->is_auth() && srcdnl->is_primary() ? srci : NULL; if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks, &remote_wrlocks, auth_pin_freeze)) return; if (oldin && oldin->is_dir() && _dir_is_nonempty(mdr, oldin)) { reply_request(mdr, -ENOTEMPTY); return; } // moving between snaprealms? if (srcdnl->is_primary() && srci->is_multiversion() && !srci->snaprealm) { SnapRealm *srcrealm = srci->find_snaprealm(); SnapRealm *destrealm = destdn->get_dir()->inode->find_snaprealm(); if (srcrealm != destrealm && (srcrealm->get_newest_seq() + 1 > srcdn->first || destrealm->get_newest_seq() + 1 > srcdn->first)) { dout(10) << " renaming between snaprealms, creating snaprealm for " << *srci << dendl; mds->mdcache->snaprealm_create(mdr, srci); return; } } assert(g_conf->mds_kill_rename_at != 1); // -- open all srcdn inode frags, if any -- // we need these open so that auth can properly delegate from inode to dirfrags // after the inode is _ours_. if (srcdnl->is_primary() && !srcdn->is_auth() && srci->is_dir()) { dout(10) << "srci is remote dir, setting stickydirs and opening all frags" << dendl; mdr->set_stickydirs(srci); list frags; srci->dirfragtree.get_leaves(frags); for (list::iterator p = frags.begin(); p != frags.end(); ++p) { CDir *dir = srci->get_dirfrag(*p); if (!dir) { dout(10) << " opening " << *p << " under " << *srci << dendl; mdcache->open_remote_dirfrag(srci, *p, new C_MDS_RetryRequest(mdcache, mdr)); return; } } } // -- declare now -- if (mdr->now == utime_t()) mdr->now = ceph_clock_now(g_ceph_context); // -- prepare anchor updates -- if (!linkmerge || srcdnl->is_primary()) { C_GatherBuilder anchorgather(g_ceph_context); if (srcdnl->is_primary() && (srcdnl->get_inode()->is_anchored() || (srcdnl->get_inode()->is_dir() && (srcdnl->get_inode()->inode.rstat.ranchors || srcdnl->get_inode()->nested_anchors || !mdcache->is_leaf_subtree(mdcache->get_projected_subtree_root(srcdn->get_dir()))))) && !mdr->more()->src_reanchor_atid) { dout(10) << "reanchoring src->dst " << *srcdnl->get_inode() << dendl; vector trace; destdn->make_anchor_trace(trace, srcdnl->get_inode()); mds->anchorclient->prepare_update(srcdnl->get_inode()->ino(), trace, &mdr->more()->src_reanchor_atid, anchorgather.new_sub()); } if (destdnl->is_primary() && destdnl->get_inode()->is_anchored() && !mdr->more()->dst_reanchor_atid) { dout(10) << "reanchoring dst->stray " << *destdnl->get_inode() << dendl; assert(straydn); vector trace; straydn->make_anchor_trace(trace, destdnl->get_inode()); mds->anchorclient->prepare_update(destdnl->get_inode()->ino(), trace, &mdr->more()->dst_reanchor_atid, anchorgather.new_sub()); } if (anchorgather.has_subs()) { anchorgather.set_finisher(new C_MDS_RetryRequest(mdcache, mdr)); anchorgather.activate(); return; // waiting for anchor prepares } assert(g_conf->mds_kill_rename_at != 2); } // -- prepare witnesses -- // do srcdn auth last int last = -1; if (!srcdn->is_auth()) { last = srcdn->authority().first; mdr->more()->srcdn_auth_mds = last; // ask auth of srci to mark srci as ambiguous auth if more than two MDS // are involved in the rename operation. if (srcdnl->is_primary() && !mdr->more()->is_ambiguous_auth) { dout(10) << " preparing ambiguous auth for srci" << dendl; mdr->set_ambiguous_auth(srci); _rename_prepare_witness(mdr, last, witnesses, srcdn, destdn, straydn); return; } } for (set::iterator p = witnesses.begin(); p != witnesses.end(); ++p) { if (*p == last) continue; // do it last! if (mdr->more()->witnessed.count(*p)) { dout(10) << " already witnessed by mds." << *p << dendl; } else if (mdr->more()->waiting_on_slave.count(*p)) { dout(10) << " already waiting on witness mds." << *p << dendl; } else { if (!_rename_prepare_witness(mdr, *p, witnesses, srcdn, destdn, straydn)) return; } } if (!mdr->more()->waiting_on_slave.empty()) return; // we're waiting for a witness. if (last >= 0 && mdr->more()->witnessed.count(last) == 0) { dout(10) << " preparing last witness (srcdn auth)" << dendl; assert(mdr->more()->waiting_on_slave.count(last) == 0); _rename_prepare_witness(mdr, last, witnesses, srcdn, destdn, straydn); return; } // test hack: bail after slave does prepare, so we can verify it's _live_ rollback. if (!mdr->more()->slaves.empty() && !srci->is_dir()) assert(g_conf->mds_kill_rename_at != 3); if (!mdr->more()->slaves.empty() && srci->is_dir()) assert(g_conf->mds_kill_rename_at != 4); // -- prepare journal entry -- mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "rename"); mdlog->start_entry(le); le->metablob.add_client_req(mdr->reqid, mdr->client_request->get_oldest_client_tid()); if (!mdr->more()->witnessed.empty()) { dout(20) << " noting uncommitted_slaves " << mdr->more()->witnessed << dendl; le->reqid = mdr->reqid; le->had_slaves = true; mds->mdcache->add_uncommitted_master(mdr->reqid, mdr->ls, mdr->more()->witnessed); // no need to send frozen auth pin to recovring auth MDS of srci mdr->more()->is_remote_frozen_authpin = false; } _rename_prepare(mdr, &le->metablob, &le->client_map, srcdn, destdn, straydn); if (le->client_map.length()) le->cmapv = mds->sessionmap.projected; // -- commit locally -- C_MDS_rename_finish *fin = new C_MDS_rename_finish(mds, mdr, srcdn, destdn, straydn); journal_and_reply(mdr, srci, destdn, le, fin); } void Server::_rename_finish(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, CDentry *straydn) { dout(10) << "_rename_finish " << *mdr << dendl; if (!mdr->more()->witnessed.empty()) mdcache->logged_master_update(mdr->reqid); // apply _rename_apply(mdr, srcdn, destdn, straydn); CDentry::linkage_t *destdnl = destdn->get_linkage(); CInode *in = destdnl->get_inode(); bool need_eval = mdr->more()->cap_imports.count(in); // test hack: test slave commit if (!mdr->more()->slaves.empty() && !in->is_dir()) assert(g_conf->mds_kill_rename_at != 5); if (!mdr->more()->slaves.empty() && in->is_dir()) assert(g_conf->mds_kill_rename_at != 6); // commit anchor updates? if (mdr->more()->src_reanchor_atid) mds->anchorclient->commit(mdr->more()->src_reanchor_atid, mdr->ls); if (mdr->more()->dst_reanchor_atid) mds->anchorclient->commit(mdr->more()->dst_reanchor_atid, mdr->ls); // bump popularity mds->balancer->hit_dir(mdr->now, srcdn->get_dir(), META_POP_IWR); if (destdnl->is_remote() && in->is_auth()) mds->balancer->hit_inode(mdr->now, in, META_POP_IWR); // did we import srci? if so, explicitly ack that import that, before we unlock and reply. assert(g_conf->mds_kill_rename_at != 7); // reply MClientReply *reply = new MClientReply(mdr->client_request, 0); reply_request(mdr, reply); if (need_eval) mds->locker->eval(in, CEPH_CAP_LOCKS, true); // clean up? if (straydn) mdcache->eval_stray(straydn); } // helpers bool Server::_rename_prepare_witness(MDRequestRef& mdr, int who, set &witnesse, CDentry *srcdn, CDentry *destdn, CDentry *straydn) { if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(who)) { dout(10) << "_rename_prepare_witness mds." << who << " is not active" << dendl; if (mdr->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(who, new C_MDS_RetryRequest(mdcache, mdr)); return false; } dout(10) << "_rename_prepare_witness mds." << who << dendl; MMDSSlaveRequest *req = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_RENAMEPREP); srcdn->make_path(req->srcdnpath); destdn->make_path(req->destdnpath); req->now = mdr->now; if (straydn) mdcache->replicate_stray(straydn, who, req->stray); // srcdn auth will verify our current witness list is sufficient req->witnesses = witnesse; mds->send_message_mds(req, who); assert(mdr->more()->waiting_on_slave.count(who) == 0); mdr->more()->waiting_on_slave.insert(who); return true; } version_t Server::_rename_prepare_import(MDRequestRef& mdr, CDentry *srcdn, bufferlist *client_map_bl) { version_t oldpv = mdr->more()->inode_import_v; CDentry::linkage_t *srcdnl = srcdn->get_linkage(); /* import node */ bufferlist::iterator blp = mdr->more()->inode_import.begin(); // imported caps ::decode(mdr->more()->imported_client_map, blp); ::encode(mdr->more()->imported_client_map, *client_map_bl); prepare_force_open_sessions(mdr->more()->imported_client_map, mdr->more()->sseq_map); list updated_scatterlocks; // we clear_updated explicitly below mdcache->migrator->decode_import_inode(srcdn, blp, srcdn->authority().first, mdr->ls, 0, mdr->more()->cap_imports, updated_scatterlocks); srcdnl->get_inode()->filelock.remove_dirty(); srcdnl->get_inode()->nestlock.remove_dirty(); // hack: force back to !auth and clean, temporarily srcdnl->get_inode()->state_clear(CInode::STATE_AUTH); srcdnl->get_inode()->mark_clean(); return oldpv; } bool Server::_need_force_journal(CInode *diri, bool empty) { list ls; diri->get_dirfrags(ls); bool force_journal = false; if (empty) { for (list::iterator p = ls.begin(); p != ls.end(); ++p) { if ((*p)->is_subtree_root() && (*p)->get_dir_auth().first == mds->whoami) { dout(10) << " frag " << (*p)->get_frag() << " is auth subtree dirfrag, will force journal" << dendl; force_journal = true; break; } else dout(20) << " frag " << (*p)->get_frag() << " is not auth subtree dirfrag" << dendl; } } else { // see if any children of our frags are auth subtrees. list subtrees; mds->mdcache->list_subtrees(subtrees); dout(10) << " subtrees " << subtrees << " frags " << ls << dendl; for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; for (list::iterator q = subtrees.begin(); q != subtrees.end(); ++q) { if (dir->contains(*q)) { if ((*q)->get_dir_auth().first == mds->whoami) { dout(10) << " frag " << (*p)->get_frag() << " contains (maybe) auth subtree, will force journal " << **q << dendl; force_journal = true; break; } else dout(20) << " frag " << (*p)->get_frag() << " contains but isn't auth for " << **q << dendl; } else dout(20) << " frag " << (*p)->get_frag() << " does not contain " << **q << dendl; } if (force_journal) break; } } return force_journal; } void Server::_rename_prepare(MDRequestRef& mdr, EMetaBlob *metablob, bufferlist *client_map_bl, CDentry *srcdn, CDentry *destdn, CDentry *straydn) { dout(10) << "_rename_prepare " << *mdr << " " << *srcdn << " " << *destdn << dendl; if (straydn) dout(10) << " straydn " << *straydn << dendl; CDentry::linkage_t *srcdnl = srcdn->get_projected_linkage(); CDentry::linkage_t *destdnl = destdn->get_projected_linkage(); CInode *srci = srcdnl->get_inode(); CInode *oldin = destdnl->get_inode(); // primary+remote link merge? bool linkmerge = (srci == destdnl->get_inode() && (srcdnl->is_primary() || destdnl->is_primary())); bool silent = srcdn->get_dir()->inode->is_stray(); bool force_journal_dest = false; if (srci->is_dir() && !destdn->is_auth()) { if (srci->is_auth()) { // if we are auth for srci and exporting it, force journal because journal replay needs // the source inode to create auth subtrees. dout(10) << " we are exporting srci, will force journal destdn" << dendl; force_journal_dest = true; } else force_journal_dest = _need_force_journal(srci, false); } bool force_journal_stray = false; if (oldin && oldin->is_dir() && straydn && !straydn->is_auth()) force_journal_stray = _need_force_journal(oldin, true); if (linkmerge) dout(10) << " merging remote and primary links to the same inode" << dendl; if (silent) dout(10) << " reintegrating stray; will avoid changing nlink or dir mtime" << dendl; if (force_journal_dest) dout(10) << " forcing journal destdn because we (will) have auth subtrees nested beneath it" << dendl; if (force_journal_stray) dout(10) << " forcing journal straydn because we (will) have auth subtrees nested beneath it" << dendl; if (srci->is_dir() && (destdn->is_auth() || force_journal_dest)) { dout(10) << " noting renamed dir ino " << srci->ino() << " in metablob" << dendl; metablob->renamed_dirino = srci->ino(); } else if (oldin && oldin->is_dir() && force_journal_stray) { dout(10) << " noting rename target dir " << oldin->ino() << " in metablob" << dendl; metablob->renamed_dirino = oldin->ino(); } // prepare inode_t *pi = 0; // renamed inode inode_t *tpi = 0; // target/overwritten inode // target inode if (!linkmerge) { if (destdnl->is_primary()) { assert(straydn); // moving to straydn. // link--, and move. if (destdn->is_auth()) { tpi = oldin->project_inode(); //project_snaprealm tpi->version = straydn->pre_dirty(tpi->version); tpi->update_backtrace(); } straydn->push_projected_linkage(oldin); } else if (destdnl->is_remote()) { // nlink-- targeti if (oldin->is_auth()) { tpi = oldin->project_inode(); tpi->version = oldin->pre_dirty(); } } } // dest if (srcdnl->is_remote()) { if (!linkmerge) { // destdn if (destdn->is_auth()) mdr->more()->pvmap[destdn] = destdn->pre_dirty(); destdn->push_projected_linkage(srcdnl->get_remote_ino(), srcdnl->get_remote_d_type()); // srci if (srci->is_auth()) { pi = srci->project_inode(); pi->version = srci->pre_dirty(); } } else { dout(10) << " will merge remote onto primary link" << dendl; if (destdn->is_auth()) { pi = oldin->project_inode(); pi->version = mdr->more()->pvmap[destdn] = destdn->pre_dirty(oldin->inode.version); } } } else { // primary if (destdn->is_auth()) { version_t oldpv; if (srcdn->is_auth()) oldpv = srci->get_projected_version(); else { oldpv = _rename_prepare_import(mdr, srcdn, client_map_bl); // note which dirfrags have child subtrees in the journal // event, so that we can open those (as bounds) during replay. if (srci->is_dir()) { list ls; srci->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; if (!dir->is_auth()) metablob->renamed_dir_frags.push_back(dir->get_frag()); } dout(10) << " noting renamed dir open frags " << metablob->renamed_dir_frags << dendl; } } pi = srci->project_inode(); // project snaprealm if srcdnl->is_primary // & srcdnl->snaprealm pi->version = mdr->more()->pvmap[destdn] = destdn->pre_dirty(oldpv); pi->update_backtrace(); } destdn->push_projected_linkage(srci); } // src if (srcdn->is_auth()) mdr->more()->pvmap[srcdn] = srcdn->pre_dirty(); srcdn->push_projected_linkage(); // push null linkage if (!silent) { if (pi) { pi->ctime = mdr->now; if (linkmerge) pi->nlink--; } if (tpi) { tpi->ctime = mdr->now; tpi->nlink--; if (tpi->nlink == 0) oldin->state_set(CInode::STATE_ORPHAN); } } // prepare nesting, mtime updates int predirty_dir = silent ? 0:PREDIRTY_DIR; // guarantee stray dir is processed first during journal replay. unlink the old inode, // then link the source inode to destdn if (destdnl->is_primary()) { assert(straydn); if (straydn->is_auth()) { metablob->add_dir_context(straydn->get_dir()); metablob->add_dir(straydn->get_dir(), true); } } // sub off target if (destdn->is_auth() && !destdnl->is_null()) { mdcache->predirty_journal_parents(mdr, metablob, oldin, destdn->get_dir(), (destdnl->is_primary() ? PREDIRTY_PRIMARY:0)|predirty_dir, -1); if (destdnl->is_primary()) mdcache->predirty_journal_parents(mdr, metablob, oldin, straydn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); } // move srcdn int predirty_primary = (srcdnl->is_primary() && srcdn->get_dir() != destdn->get_dir()) ? PREDIRTY_PRIMARY:0; int flags = predirty_dir | predirty_primary; if (srcdn->is_auth()) mdcache->predirty_journal_parents(mdr, metablob, srci, srcdn->get_dir(), PREDIRTY_SHALLOW|flags, -1); if (destdn->is_auth()) mdcache->predirty_journal_parents(mdr, metablob, srci, destdn->get_dir(), flags, 1); SnapRealm *src_realm = srci->find_snaprealm(); SnapRealm *dest_realm = destdn->get_dir()->inode->find_snaprealm(); snapid_t next_dest_snap = dest_realm->get_newest_seq() + 1; // add it all to the metablob // target inode if (!linkmerge) { if (destdnl->is_primary()) { if (destdn->is_auth()) { // project snaprealm, too if (oldin->snaprealm || src_realm->get_newest_seq() + 1 > srcdn->first) oldin->project_past_snaprealm_parent(straydn->get_dir()->inode->find_snaprealm()); straydn->first = MAX(oldin->first, next_dest_snap); metablob->add_primary_dentry(straydn, oldin, true, true); } else if (force_journal_stray) { dout(10) << " forced journaling straydn " << *straydn << dendl; metablob->add_dir_context(straydn->get_dir()); metablob->add_primary_dentry(straydn, oldin, true); } } else if (destdnl->is_remote()) { if (oldin->is_auth()) { // auth for targeti metablob->add_dir_context(oldin->get_projected_parent_dir()); mdcache->journal_cow_dentry(mdr.get(), metablob, oldin->get_projected_parent_dn(), CEPH_NOSNAP, 0, destdnl); metablob->add_primary_dentry(oldin->get_projected_parent_dn(), oldin, true); } } } // dest if (srcdnl->is_remote()) { if (!linkmerge) { if (destdn->is_auth() && !destdnl->is_null()) mdcache->journal_cow_dentry(mdr.get(), metablob, destdn, CEPH_NOSNAP, 0, destdnl); else destdn->first = MAX(destdn->first, next_dest_snap); if (destdn->is_auth()) metablob->add_remote_dentry(destdn, true, srcdnl->get_remote_ino(), srcdnl->get_remote_d_type()); if (srci->get_projected_parent_dn()->is_auth()) { // it's remote metablob->add_dir_context(srci->get_projected_parent_dir()); mdcache->journal_cow_dentry(mdr.get(), metablob, srci->get_projected_parent_dn(), CEPH_NOSNAP, 0, srcdnl); metablob->add_primary_dentry(srci->get_projected_parent_dn(), srci, true); } } else { if (destdn->is_auth() && !destdnl->is_null()) mdcache->journal_cow_dentry(mdr.get(), metablob, destdn, CEPH_NOSNAP, 0, destdnl); else destdn->first = MAX(destdn->first, next_dest_snap); if (destdn->is_auth()) metablob->add_primary_dentry(destdn, destdnl->get_inode(), true, true); } } else if (srcdnl->is_primary()) { // project snap parent update? if (destdn->is_auth() && (srci->snaprealm || src_realm->get_newest_seq() + 1 > srcdn->first)) srci->project_past_snaprealm_parent(dest_realm); if (destdn->is_auth() && !destdnl->is_null()) mdcache->journal_cow_dentry(mdr.get(), metablob, destdn, CEPH_NOSNAP, 0, destdnl); else destdn->first = MAX(destdn->first, next_dest_snap); if (destdn->is_auth()) metablob->add_primary_dentry(destdn, srci, true, true); else if (force_journal_dest) { dout(10) << " forced journaling destdn " << *destdn << dendl; metablob->add_dir_context(destdn->get_dir()); metablob->add_primary_dentry(destdn, srci, true); if (srcdn->is_auth() && srci->is_dir()) { // journal new subtrees root dirfrags list ls; srci->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; if (dir->is_auth()) metablob->add_dir(dir, true); } } } } // src if (srcdn->is_auth()) { dout(10) << " journaling srcdn " << *srcdn << dendl; mdcache->journal_cow_dentry(mdr.get(), metablob, srcdn, CEPH_NOSNAP, 0, srcdnl); // also journal the inode in case we need do slave rename rollback. It is Ok to add // both primary and NULL dentries. Because during journal replay, null dentry is // processed after primary dentry. if (srcdnl->is_primary() && !srci->is_dir() && !destdn->is_auth()) metablob->add_primary_dentry(srcdn, srci, true); metablob->add_null_dentry(srcdn, true); } else dout(10) << " NOT journaling srcdn " << *srcdn << dendl; // make renamed inode first track the dn if (srcdnl->is_primary() && destdn->is_auth()) srci->first = destdn->first; // anchor updates? if (mdr->more()->src_reanchor_atid) metablob->add_table_transaction(TABLE_ANCHOR, mdr->more()->src_reanchor_atid); if (mdr->more()->dst_reanchor_atid) metablob->add_table_transaction(TABLE_ANCHOR, mdr->more()->dst_reanchor_atid); if (oldin && oldin->is_dir()) mdcache->project_subtree_rename(oldin, destdn->get_dir(), straydn->get_dir()); if (srci->is_dir()) mdcache->project_subtree_rename(srci, srcdn->get_dir(), destdn->get_dir()); } void Server::_rename_apply(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, CDentry *straydn) { dout(10) << "_rename_apply " << *mdr << " " << *srcdn << " " << *destdn << dendl; dout(10) << " pvs " << mdr->more()->pvmap << dendl; CDentry::linkage_t *srcdnl = srcdn->get_linkage(); CDentry::linkage_t *destdnl = destdn->get_linkage(); CInode *oldin = destdnl->get_inode(); bool imported_inode = false; // primary+remote link merge? bool linkmerge = (srcdnl->get_inode() == destdnl->get_inode() && (srcdnl->is_primary() || destdnl->is_primary())); // target inode if (!linkmerge) { if (destdnl->is_primary()) { assert(straydn); dout(10) << "straydn is " << *straydn << dendl; destdn->get_dir()->unlink_inode(destdn); straydn->pop_projected_linkage(); mdcache->touch_dentry_bottom(straydn); // drop dn as quickly as possible. // nlink-- targeti if (destdn->is_auth()) { bool hadrealm = (oldin->snaprealm ? true : false); oldin->pop_and_dirty_projected_inode(mdr->ls); if (oldin->snaprealm && !hadrealm) mdcache->do_realm_invalidate_and_update_notify(oldin, CEPH_SNAP_OP_SPLIT); } else { // FIXME this snaprealm is not filled out correctly //oldin->open_snaprealm(); might be sufficient.. } } else if (destdnl->is_remote()) { destdn->get_dir()->unlink_inode(destdn); if (oldin->is_auth()) oldin->pop_and_dirty_projected_inode(mdr->ls); } } // unlink src before we relink it at dest CInode *in = srcdnl->get_inode(); assert(in); bool srcdn_was_remote = srcdnl->is_remote(); srcdn->get_dir()->unlink_inode(srcdn); // dest if (srcdn_was_remote) { if (!linkmerge) { // destdn destdnl = destdn->pop_projected_linkage(); destdn->link_remote(destdnl, in); if (destdn->is_auth()) destdn->mark_dirty(mdr->more()->pvmap[destdn], mdr->ls); // in if (in->is_auth()) in->pop_and_dirty_projected_inode(mdr->ls); } else { dout(10) << "merging remote onto primary link" << dendl; oldin->pop_and_dirty_projected_inode(mdr->ls); } } else { // primary if (linkmerge) { dout(10) << "merging primary onto remote link" << dendl; destdn->get_dir()->unlink_inode(destdn); } destdnl = destdn->pop_projected_linkage(); // srcdn inode import? if (!srcdn->is_auth() && destdn->is_auth()) { assert(mdr->more()->inode_import.length() > 0); map imported_caps; // finish cap imports finish_force_open_sessions(mdr->more()->imported_client_map, mdr->more()->sseq_map); if (mdr->more()->cap_imports.count(destdnl->get_inode())) { mds->mdcache->migrator->finish_import_inode_caps(destdnl->get_inode(), mdr->more()->srcdn_auth_mds, true, mdr->more()->cap_imports[destdnl->get_inode()], imported_caps); } mdr->more()->inode_import.clear(); ::encode(imported_caps, mdr->more()->inode_import); /* hack: add an auth pin for each xlock we hold. These were * remote xlocks previously but now they're local and * we're going to try and unpin when we xlock_finish. */ for (set::iterator i = mdr->xlocks.begin(); i != mdr->xlocks.end(); ++i) if ((*i)->get_parent() == destdnl->get_inode() && !(*i)->is_locallock()) mds->locker->xlock_import(*i); // hack: fix auth bit in->state_set(CInode::STATE_AUTH); imported_inode = true; mdr->clear_ambiguous_auth(); } if (destdn->is_auth()) { in->pop_and_dirty_projected_inode(mdr->ls); } else { // FIXME: fix up snaprealm! } } // src if (srcdn->is_auth()) srcdn->mark_dirty(mdr->more()->pvmap[srcdn], mdr->ls); srcdn->pop_projected_linkage(); // apply remaining projected inodes (nested) mdr->apply(); // update subtree map? if (destdnl->is_primary() && in->is_dir()) mdcache->adjust_subtree_after_rename(in, srcdn->get_dir(), true, imported_inode); if (straydn && oldin->is_dir()) mdcache->adjust_subtree_after_rename(oldin, destdn->get_dir(), true); // removing a new dn? if (srcdn->is_auth()) srcdn->get_dir()->try_remove_unlinked_dn(srcdn); } // ------------ // SLAVE class C_MDS_SlaveRenamePrep : public Context { Server *server; MDRequestRef mdr; CDentry *srcdn, *destdn, *straydn; public: C_MDS_SlaveRenamePrep(Server *s, MDRequestRef& m, CDentry *sr, CDentry *de, CDentry *st) : server(s), mdr(m), srcdn(sr), destdn(de), straydn(st) {} void finish(int r) { server->_logged_slave_rename(mdr, srcdn, destdn, straydn); } }; class C_MDS_SlaveRenameCommit : public Context { Server *server; MDRequestRef mdr; CDentry *srcdn, *destdn, *straydn; public: C_MDS_SlaveRenameCommit(Server *s, MDRequestRef& m, CDentry *sr, CDentry *de, CDentry *st) : server(s), mdr(m), srcdn(sr), destdn(de), straydn(st) {} void finish(int r) { server->_commit_slave_rename(mdr, r, srcdn, destdn, straydn); } }; class C_MDS_SlaveRenameSessionsFlushed : public Context { Server *server; MDRequestRef mdr; public: C_MDS_SlaveRenameSessionsFlushed(Server *s, MDRequestRef& r) : server(s), mdr(r) {} void finish(int r) { server->_slave_rename_sessions_flushed(mdr); } }; /* This function DOES put the mdr->slave_request before returning*/ void Server::handle_slave_rename_prep(MDRequestRef& mdr) { dout(10) << "handle_slave_rename_prep " << *mdr << " " << mdr->slave_request->srcdnpath << " to " << mdr->slave_request->destdnpath << dendl; // discover destdn filepath destpath(mdr->slave_request->destdnpath); dout(10) << " dest " << destpath << dendl; vector trace; int r = mdcache->path_traverse(mdr, NULL, NULL, destpath, &trace, NULL, MDS_TRAVERSE_DISCOVERXLOCK); if (r > 0) return; assert(r == 0); // we shouldn't get an error here! CDentry *destdn = trace[trace.size()-1]; CDentry::linkage_t *destdnl = destdn->get_projected_linkage(); dout(10) << " destdn " << *destdn << dendl; mdr->pin(destdn); // discover srcdn filepath srcpath(mdr->slave_request->srcdnpath); dout(10) << " src " << srcpath << dendl; CInode *srci; r = mdcache->path_traverse(mdr, NULL, NULL, srcpath, &trace, &srci, MDS_TRAVERSE_DISCOVERXLOCK); if (r > 0) return; assert(r == 0); CDentry *srcdn = trace[trace.size()-1]; CDentry::linkage_t *srcdnl = srcdn->get_projected_linkage(); dout(10) << " srcdn " << *srcdn << dendl; mdr->pin(srcdn); mdr->pin(srci); // stray? bool linkmerge = (srcdnl->get_inode() == destdnl->get_inode() && (srcdnl->is_primary() || destdnl->is_primary())); CDentry *straydn = mdr->straydn; if (destdnl->is_primary() && !linkmerge) assert(straydn); mdr->now = mdr->slave_request->now; mdr->more()->srcdn_auth_mds = srcdn->authority().first; // set up commit waiter (early, to clean up any freezing etc we do) if (!mdr->more()->slave_commit) mdr->more()->slave_commit = new C_MDS_SlaveRenameCommit(this, mdr, srcdn, destdn, straydn); // am i srcdn auth? if (srcdn->is_auth()) { set srcdnrep; srcdn->list_replicas(srcdnrep); bool reply_witness = false; if (srcdnl->is_primary() && !srcdnl->get_inode()->state_test(CInode::STATE_AMBIGUOUSAUTH)) { // freeze? // we need this to // - avoid conflicting lock state changes // - avoid concurrent updates to the inode // (this could also be accomplished with the versionlock) int allowance = 2; // 1 for the mdr auth_pin, 1 for the link lock allowance += srcdnl->get_inode()->is_dir(); // for the snap lock dout(10) << " freezing srci " << *srcdnl->get_inode() << " with allowance " << allowance << dendl; bool frozen_inode = srcdnl->get_inode()->freeze_inode(allowance); // unfreeze auth pin after freezing the inode to avoid queueing waiters if (srcdnl->get_inode()->is_frozen_auth_pin()) mdr->unfreeze_auth_pin(); if (!frozen_inode) { srcdnl->get_inode()->add_waiter(CInode::WAIT_FROZEN, new C_MDS_RetryRequest(mdcache, mdr)); return; } /* * set ambiguous auth for srci * NOTE: we don't worry about ambiguous cache expire as we do * with subtree migrations because all slaves will pin * srcdn->get_inode() for duration of this rename. */ mdr->set_ambiguous_auth(srcdnl->get_inode()); // just mark the source inode as ambiguous auth if more than two MDS are involved. // the master will send another OP_RENAMEPREP slave request later. if (mdr->slave_request->witnesses.size() > 1) { dout(10) << " set srci ambiguous auth; providing srcdn replica list" << dendl; reply_witness = true; } // make sure bystanders have received all lock related messages for (set::iterator p = srcdnrep.begin(); p != srcdnrep.end(); ++p) { if (*p == mdr->slave_to_mds || !mds->mdsmap->is_clientreplay_or_active_or_stopping(*p)) continue; MMDSSlaveRequest *notify = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_RENAMENOTIFY); mds->send_message_mds(notify, *p); mdr->more()->waiting_on_slave.insert(*p); } // make sure clients have received all cap related messages set export_client_set; mdcache->migrator->get_export_client_set(srcdnl->get_inode(), export_client_set); C_GatherBuilder gather(g_ceph_context); flush_client_sessions(export_client_set, gather); if (gather.has_subs()) { mdr->more()->waiting_on_slave.insert(-1); gather.set_finisher(new C_MDS_SlaveRenameSessionsFlushed(this, mdr)); gather.activate(); } } // is witness list sufficient? for (set::iterator p = srcdnrep.begin(); p != srcdnrep.end(); ++p) { if (*p == mdr->slave_to_mds || mdr->slave_request->witnesses.count(*p)) continue; dout(10) << " witness list insufficient; providing srcdn replica list" << dendl; reply_witness = true; break; } if (reply_witness) { assert(srcdnrep.size()); MMDSSlaveRequest *reply = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_RENAMEPREPACK); reply->witnesses.swap(srcdnrep); mds->send_message_mds(reply, mdr->slave_to_mds); mdr->slave_request->put(); mdr->slave_request = 0; return; } dout(10) << " witness list sufficient: includes all srcdn replicas" << dendl; if (!mdr->more()->waiting_on_slave.empty()) { dout(10) << " still waiting for rename notify acks from " << mdr->more()->waiting_on_slave << dendl; return; } } else if (srcdnl->is_primary() && srcdn->authority() != destdn->authority()) { // set ambiguous auth for srci on witnesses mdr->set_ambiguous_auth(srcdnl->get_inode()); } // encode everything we'd need to roll this back... basically, just the original state. rename_rollback rollback; rollback.reqid = mdr->reqid; rollback.orig_src.dirfrag = srcdn->get_dir()->dirfrag(); rollback.orig_src.dirfrag_old_mtime = srcdn->get_dir()->get_projected_fnode()->fragstat.mtime; rollback.orig_src.dirfrag_old_rctime = srcdn->get_dir()->get_projected_fnode()->rstat.rctime; rollback.orig_src.dname = srcdn->name; if (srcdnl->is_primary()) rollback.orig_src.ino = srcdnl->get_inode()->ino(); else { assert(srcdnl->is_remote()); rollback.orig_src.remote_ino = srcdnl->get_remote_ino(); rollback.orig_src.remote_d_type = srcdnl->get_remote_d_type(); } rollback.orig_dest.dirfrag = destdn->get_dir()->dirfrag(); rollback.orig_dest.dirfrag_old_mtime = destdn->get_dir()->get_projected_fnode()->fragstat.mtime; rollback.orig_dest.dirfrag_old_rctime = destdn->get_dir()->get_projected_fnode()->rstat.rctime; rollback.orig_dest.dname = destdn->name; if (destdnl->is_primary()) rollback.orig_dest.ino = destdnl->get_inode()->ino(); else if (destdnl->is_remote()) { rollback.orig_dest.remote_ino = destdnl->get_remote_ino(); rollback.orig_dest.remote_d_type = destdnl->get_remote_d_type(); } if (straydn) { rollback.stray.dirfrag = straydn->get_dir()->dirfrag(); rollback.stray.dirfrag_old_mtime = straydn->get_dir()->get_projected_fnode()->fragstat.mtime; rollback.stray.dirfrag_old_rctime = straydn->get_dir()->get_projected_fnode()->rstat.rctime; rollback.stray.dname = straydn->name; } ::encode(rollback, mdr->more()->rollback_bl); dout(20) << " rollback is " << mdr->more()->rollback_bl.length() << " bytes" << dendl; // journal. mdr->ls = mdlog->get_current_segment(); ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_rename_prep", mdr->reqid, mdr->slave_to_mds, ESlaveUpdate::OP_PREPARE, ESlaveUpdate::RENAME); mdlog->start_entry(le); le->rollback = mdr->more()->rollback_bl; bufferlist blah; // inode import data... obviously not used if we're the slave _rename_prepare(mdr, &le->commit, &blah, srcdn, destdn, straydn); mdlog->submit_entry(le, new C_MDS_SlaveRenamePrep(this, mdr, srcdn, destdn, straydn)); mdlog->flush(); } void Server::_logged_slave_rename(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, CDentry *straydn) { dout(10) << "_logged_slave_rename " << *mdr << dendl; // prepare ack MMDSSlaveRequest *reply = NULL; if (!mdr->aborted) reply= new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_RENAMEPREPACK); CDentry::linkage_t *srcdnl = srcdn->get_linkage(); CDentry::linkage_t *destdnl = destdn->get_linkage(); //CDentry::linkage_t *straydnl = straydn ? straydn->get_linkage() : 0; // export srci? if (srcdn->is_auth() && srcdnl->is_primary()) { // set export bounds for CInode::encode_export() list bounds; if (srcdnl->get_inode()->is_dir()) { srcdnl->get_inode()->get_dirfrags(bounds); for (list::iterator p = bounds.begin(); p != bounds.end(); ++p) (*p)->state_set(CDir::STATE_EXPORTBOUND); } map exported_client_map; bufferlist inodebl; mdcache->migrator->encode_export_inode(srcdnl->get_inode(), inodebl, exported_client_map); for (list::iterator p = bounds.begin(); p != bounds.end(); ++p) (*p)->state_clear(CDir::STATE_EXPORTBOUND); if (reply) { ::encode(exported_client_map, reply->inode_export); reply->inode_export.claim_append(inodebl); reply->inode_export_v = srcdnl->get_inode()->inode.version; } // remove mdr auth pin mdr->auth_unpin(srcdnl->get_inode()); mdr->more()->is_inode_exporter = true; if (srcdnl->get_inode()->is_dirty()) srcdnl->get_inode()->mark_clean(); dout(10) << " exported srci " << *srcdnl->get_inode() << dendl; } // apply _rename_apply(mdr, srcdn, destdn, straydn); destdnl = destdn->get_linkage(); // bump popularity mds->balancer->hit_dir(mdr->now, srcdn->get_dir(), META_POP_IWR); if (destdnl->get_inode() && destdnl->get_inode()->is_auth()) mds->balancer->hit_inode(mdr->now, destdnl->get_inode(), META_POP_IWR); // done. mdr->slave_request->put(); mdr->slave_request = 0; mdr->straydn = 0; if (reply) { mds->send_message_mds(reply, mdr->slave_to_mds); } else { assert(mdr->aborted); dout(10) << " abort flag set, finishing" << dendl; mdcache->request_finish(mdr); } } void Server::_commit_slave_rename(MDRequestRef& mdr, int r, CDentry *srcdn, CDentry *destdn, CDentry *straydn) { dout(10) << "_commit_slave_rename " << *mdr << " r=" << r << dendl; CDentry::linkage_t *destdnl = destdn->get_linkage(); list finished; if (r == 0) { // write a commit to the journal ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_rename_commit", mdr->reqid, mdr->slave_to_mds, ESlaveUpdate::OP_COMMIT, ESlaveUpdate::RENAME); mdlog->start_entry(le); // unfreeze+singleauth inode // hmm, do i really need to delay this? if (mdr->more()->is_inode_exporter) { CInode *in = destdnl->get_inode(); // drop our pins // we exported, clear out any xlocks that we moved to another MDS set::iterator i = mdr->xlocks.begin(); while (i != mdr->xlocks.end()) { SimpleLock *lock = *i++; // we only care about xlocks on the exported inode if (lock->get_parent() == in && !lock->is_locallock()) mds->locker->xlock_export(lock, mdr.get()); } map peer_imported; bufferlist::iterator bp = mdr->more()->inode_import.begin(); ::decode(peer_imported, bp); dout(10) << " finishing inode export on " << *destdnl->get_inode() << dendl; mdcache->migrator->finish_export_inode(destdnl->get_inode(), mdr->now, mdr->slave_to_mds, peer_imported, finished); mds->queue_waiters(finished); // this includes SINGLEAUTH waiters. // unfreeze assert(destdnl->get_inode()->is_frozen_inode()); destdnl->get_inode()->unfreeze_inode(finished); } // singleauth if (mdr->more()->is_ambiguous_auth) { mdr->more()->rename_inode->clear_ambiguous_auth(finished); mdr->more()->is_ambiguous_auth = false; } mds->queue_waiters(finished); mdr->cleanup(); mdlog->submit_entry(le, new C_MDS_CommittedSlave(this, mdr)); mdlog->flush(); } else { // abort // rollback_bl may be empty if we froze the inode but had to provide an expanded // witness list from the master, and they failed before we tried prep again. if (mdr->more()->rollback_bl.length()) { if (mdr->more()->is_inode_exporter) { dout(10) << " reversing inode export of " << *destdnl->get_inode() << dendl; destdnl->get_inode()->abort_export(); } if (mdcache->is_ambiguous_slave_update(mdr->reqid, mdr->slave_to_mds)) { mdcache->remove_ambiguous_slave_update(mdr->reqid, mdr->slave_to_mds); // rollback but preserve the slave request do_rename_rollback(mdr->more()->rollback_bl, mdr->slave_to_mds, mdr, false); mdr->more()->rollback_bl.clear(); } else do_rename_rollback(mdr->more()->rollback_bl, mdr->slave_to_mds, mdr, true); } else { dout(10) << " rollback_bl empty, not rollback back rename (master failed after getting extra witnesses?)" << dendl; // singleauth if (mdr->more()->is_ambiguous_auth) { if (srcdn->is_auth()) mdr->more()->rename_inode->unfreeze_inode(finished); mdr->more()->rename_inode->clear_ambiguous_auth(finished); mdr->more()->is_ambiguous_auth = false; } mds->queue_waiters(finished); mds->mdcache->request_finish(mdr); } } } void _rollback_repair_dir(MutationRef& mut, CDir *dir, rename_rollback::drec &r, utime_t ctime, bool isdir, int linkunlink, nest_info_t &rstat) { fnode_t *pf; pf = dir->project_fnode(); mut->add_projected_fnode(dir); pf->version = dir->pre_dirty(); if (isdir) { pf->fragstat.nsubdirs += linkunlink; pf->rstat.rsubdirs += linkunlink; } else { pf->fragstat.nfiles += linkunlink; pf->rstat.rfiles += linkunlink; } if (r.ino) { pf->rstat.rbytes += linkunlink * rstat.rbytes; pf->rstat.rfiles += linkunlink * rstat.rfiles; pf->rstat.rsubdirs += linkunlink * rstat.rsubdirs; pf->rstat.ranchors += linkunlink * rstat.ranchors; pf->rstat.rsnaprealms += linkunlink * rstat.rsnaprealms; } if (pf->fragstat.mtime == ctime) { pf->fragstat.mtime = r.dirfrag_old_mtime; if (pf->rstat.rctime == ctime) pf->rstat.rctime = r.dirfrag_old_rctime; } mut->add_updated_lock(&dir->get_inode()->filelock); mut->add_updated_lock(&dir->get_inode()->nestlock); } struct C_MDS_LoggedRenameRollback : public Context { Server *server; MutationRef mut; MDRequestRef mdr; CDentry *srcdn; version_t srcdnpv; CDentry *destdn; CDentry *straydn; bool finish_mdr; C_MDS_LoggedRenameRollback(Server *s, MutationRef& m, MDRequestRef& r, CDentry *sd, version_t pv, CDentry *dd, CDentry *st, bool f) : server(s), mut(m), mdr(r), srcdn(sd), srcdnpv(pv), destdn(dd), straydn(st), finish_mdr(f) {} void finish(int r) { server->_rename_rollback_finish(mut, mdr, srcdn, srcdnpv, destdn, straydn, finish_mdr); } }; void Server::do_rename_rollback(bufferlist &rbl, int master, MDRequestRef& mdr, bool finish_mdr) { rename_rollback rollback; bufferlist::iterator p = rbl.begin(); ::decode(rollback, p); dout(10) << "do_rename_rollback on " << rollback.reqid << dendl; // need to finish this update before sending resolve to claim the subtree mds->mdcache->add_rollback(rollback.reqid, master); MutationRef mut(new MutationImpl(rollback.reqid)); mut->ls = mds->mdlog->get_current_segment(); CDentry *srcdn = NULL; CDir *srcdir = mds->mdcache->get_dirfrag(rollback.orig_src.dirfrag); if (!srcdir) srcdir = mds->mdcache->get_dirfrag(rollback.orig_src.dirfrag.ino, rollback.orig_src.dname); if (srcdir) { dout(10) << " srcdir " << *srcdir << dendl; srcdn = srcdir->lookup(rollback.orig_src.dname); if (srcdn) { dout(10) << " srcdn " << *srcdn << dendl; assert(srcdn->get_linkage()->is_null()); } else dout(10) << " srcdn not found" << dendl; } else dout(10) << " srcdir not found" << dendl; CDentry *destdn = NULL; CDir *destdir = mds->mdcache->get_dirfrag(rollback.orig_dest.dirfrag); if (!destdir) destdir = mds->mdcache->get_dirfrag(rollback.orig_dest.dirfrag.ino, rollback.orig_dest.dname); if (destdir) { dout(10) << " destdir " << *destdir << dendl; destdn = destdir->lookup(rollback.orig_dest.dname); if (destdn) dout(10) << " destdn " << *destdn << dendl; else dout(10) << " destdn not found" << dendl; } else dout(10) << " destdir not found" << dendl; CInode *in = NULL; if (rollback.orig_src.ino) { in = mds->mdcache->get_inode(rollback.orig_src.ino); if (in && in->is_dir()) assert(srcdn && destdn); } else in = mds->mdcache->get_inode(rollback.orig_src.remote_ino); CDir *straydir = NULL; CDentry *straydn = NULL; if (rollback.stray.dirfrag.ino) { straydir = mds->mdcache->get_dirfrag(rollback.stray.dirfrag); if (straydir) { dout(10) << "straydir " << *straydir << dendl; straydn = straydir->lookup(rollback.stray.dname); if (straydn) { dout(10) << " straydn " << *straydn << dendl; assert(straydn->get_linkage()->is_primary()); } else dout(10) << " straydn not found" << dendl; } else dout(10) << "straydir not found" << dendl; } CInode *target = NULL; if (rollback.orig_dest.ino) { target = mds->mdcache->get_inode(rollback.orig_dest.ino); if (target) assert(destdn && straydn); } else if (rollback.orig_dest.remote_ino) target = mds->mdcache->get_inode(rollback.orig_dest.remote_ino); // can't use is_auth() in the resolve stage int whoami = mds->get_nodeid(); // slave assert(!destdn || destdn->authority().first != whoami); assert(!straydn || straydn->authority().first != whoami); bool force_journal_src = false; bool force_journal_dest = false; if (in && in->is_dir() && srcdn->authority().first != whoami) force_journal_src = _need_force_journal(in, false); if (in && target && target->is_dir()) force_journal_dest = _need_force_journal(in, true); version_t srcdnpv = 0; // repair src if (srcdn) { if (srcdn->authority().first == whoami) srcdnpv = srcdn->pre_dirty(); if (rollback.orig_src.ino) { assert(in); srcdn->push_projected_linkage(in); } else srcdn->push_projected_linkage(rollback.orig_src.remote_ino, rollback.orig_src.remote_d_type); } inode_t *pi = 0; if (in) { if (in->authority().first == whoami) { pi = in->project_inode(); mut->add_projected_inode(in); pi->version = in->pre_dirty(); } else pi = in->get_projected_inode(); if (pi->ctime == rollback.ctime) pi->ctime = rollback.orig_src.old_ctime; } if (srcdn && srcdn->authority().first == whoami) { nest_info_t blah; _rollback_repair_dir(mut, srcdir, rollback.orig_src, rollback.ctime, in ? in->is_dir() : false, 1, pi ? pi->rstat : blah); } // repair dest if (destdn) { if (rollback.orig_dest.ino && target) { destdn->push_projected_linkage(target); } else if (rollback.orig_dest.remote_ino) { destdn->push_projected_linkage(rollback.orig_dest.remote_ino, rollback.orig_dest.remote_d_type); } else { // the dentry will be trimmed soon, it's ok to have wrong linkage if (rollback.orig_dest.ino) assert(mds->is_resolve()); destdn->push_projected_linkage(); } } if (straydn) straydn->push_projected_linkage(); if (target) { inode_t *ti = NULL; if (target->authority().first == whoami) { ti = target->project_inode(); mut->add_projected_inode(target); ti->version = target->pre_dirty(); } else ti = target->get_projected_inode(); if (ti->ctime == rollback.ctime) ti->ctime = rollback.orig_dest.old_ctime; if (MDS_INO_IS_STRAY(rollback.orig_src.dirfrag.ino)) { if (MDS_INO_IS_STRAY(rollback.orig_dest.dirfrag.ino)) assert(!rollback.orig_dest.ino && !rollback.orig_dest.remote_ino); else assert(rollback.orig_dest.remote_ino && rollback.orig_dest.remote_ino == rollback.orig_src.ino); } else ti->nlink++; } if (srcdn) dout(0) << " srcdn back to " << *srcdn << dendl; if (in) dout(0) << " srci back to " << *in << dendl; if (destdn) dout(0) << " destdn back to " << *destdn << dendl; if (target) dout(0) << " desti back to " << *target << dendl; // journal it ESlaveUpdate *le = new ESlaveUpdate(mdlog, "slave_rename_rollback", rollback.reqid, master, ESlaveUpdate::OP_ROLLBACK, ESlaveUpdate::RENAME); mdlog->start_entry(le); if (srcdn && (srcdn->authority().first == whoami || force_journal_src)) { le->commit.add_dir_context(srcdir); if (rollback.orig_src.ino) le->commit.add_primary_dentry(srcdn, 0, true); else le->commit.add_remote_dentry(srcdn, true); } if (force_journal_dest) { assert(rollback.orig_dest.ino); le->commit.add_dir_context(destdir); le->commit.add_primary_dentry(destdn, 0, true); } // slave: no need to journal straydn if (target && target->authority().first == whoami) { assert(rollback.orig_dest.remote_ino); le->commit.add_dir_context(target->get_projected_parent_dir()); le->commit.add_primary_dentry(target->get_projected_parent_dn(), target, true); } if (force_journal_dest) { dout(10) << " noting rename target ino " << target->ino() << " in metablob" << dendl; le->commit.renamed_dirino = target->ino(); } else if (force_journal_src || (in && in->is_dir() && srcdn->authority().first == whoami)) { dout(10) << " noting renamed dir ino " << in->ino() << " in metablob" << dendl; le->commit.renamed_dirino = in->ino(); } if (target && target->is_dir()) { assert(destdn); mdcache->project_subtree_rename(target, straydir, destdir); } if (in && in->is_dir()) { assert(srcdn); mdcache->project_subtree_rename(in, destdir, srcdir); } mdlog->submit_entry(le, new C_MDS_LoggedRenameRollback(this, mut, mdr, srcdn, srcdnpv, destdn, straydn, finish_mdr)); mdlog->flush(); } void Server::_rename_rollback_finish(MutationRef& mut, MDRequestRef& mdr, CDentry *srcdn, version_t srcdnpv, CDentry *destdn, CDentry *straydn, bool finish_mdr) { dout(10) << "_rename_rollback_finish " << mut->reqid << dendl; if (straydn) { straydn->get_dir()->unlink_inode(straydn); straydn->pop_projected_linkage(); } if (destdn) { destdn->get_dir()->unlink_inode(destdn); destdn->pop_projected_linkage(); } if (srcdn) { srcdn->pop_projected_linkage(); if (srcdn->authority().first == mds->get_nodeid()) srcdn->mark_dirty(srcdnpv, mut->ls); } mut->apply(); if (srcdn) { CInode *in = srcdn->get_linkage()->get_inode(); // update subtree map? if (in && in->is_dir()) { assert(destdn); mdcache->adjust_subtree_after_rename(in, destdn->get_dir(), true); } } if (destdn) { CInode *oldin = destdn->get_linkage()->get_inode(); // update subtree map? if (oldin && oldin->is_dir()) { assert(straydn); mdcache->adjust_subtree_after_rename(oldin, straydn->get_dir(), true); } } if (mds->is_resolve()) { CDir *root = NULL; if (straydn) root = mdcache->get_subtree_root(straydn->get_dir()); else if (destdn) root = mdcache->get_subtree_root(destdn->get_dir()); if (root) mdcache->try_trim_non_auth_subtree(root); } if (mdr) { list finished; if (mdr->more()->is_ambiguous_auth) { if (srcdn->is_auth()) mdr->more()->rename_inode->unfreeze_inode(finished); mdr->more()->rename_inode->clear_ambiguous_auth(finished); mdr->more()->is_ambiguous_auth = false; } mds->queue_waiters(finished); if (finish_mdr) mds->mdcache->request_finish(mdr); } mds->mdcache->finish_rollback(mut->reqid); mut->cleanup(); } /* This function DOES put the passed message before returning*/ void Server::handle_slave_rename_prep_ack(MDRequestRef& mdr, MMDSSlaveRequest *ack) { dout(10) << "handle_slave_rename_prep_ack " << *mdr << " witnessed by " << ack->get_source() << " " << *ack << dendl; int from = ack->get_source().num(); // note slave mdr->more()->slaves.insert(from); // witnessed? or add extra witnesses? assert(mdr->more()->witnessed.count(from) == 0); if (ack->witnesses.empty()) { mdr->more()->witnessed.insert(from); } else { dout(10) << " extra witnesses (srcdn replicas) are " << ack->witnesses << dendl; mdr->more()->extra_witnesses.swap(ack->witnesses); mdr->more()->extra_witnesses.erase(mds->get_nodeid()); // not me! } // srci import? if (ack->inode_export.length()) { dout(10) << " got srci import" << dendl; mdr->more()->inode_import.claim(ack->inode_export); mdr->more()->inode_import_v = ack->inode_export_v; } // remove from waiting list assert(mdr->more()->waiting_on_slave.count(from)); mdr->more()->waiting_on_slave.erase(from); if (mdr->more()->waiting_on_slave.empty()) dispatch_client_request(mdr); // go again! else dout(10) << "still waiting on slaves " << mdr->more()->waiting_on_slave << dendl; } void Server::handle_slave_rename_notify_ack(MDRequestRef& mdr, MMDSSlaveRequest *ack) { dout(10) << "handle_slave_rename_notify_ack " << *mdr << " from mds." << ack->get_source() << dendl; assert(mdr->is_slave()); int from = ack->get_source().num(); if (mdr->more()->waiting_on_slave.count(from)) { mdr->more()->waiting_on_slave.erase(from); if (mdr->more()->waiting_on_slave.empty()) { if (mdr->slave_request) dispatch_slave_request(mdr); } else dout(10) << " still waiting for rename notify acks from " << mdr->more()->waiting_on_slave << dendl; } } void Server::_slave_rename_sessions_flushed(MDRequestRef& mdr) { dout(10) << "_slave_rename_sessions_flushed " << *mdr << dendl; if (mdr->more()->waiting_on_slave.count(-1)) { mdr->more()->waiting_on_slave.erase(-1); if (mdr->more()->waiting_on_slave.empty()) { if (mdr->slave_request) dispatch_slave_request(mdr); } else dout(10) << " still waiting for rename notify acks from " << mdr->more()->waiting_on_slave << dendl; } } // snaps /* This function takes responsibility for the passed mdr*/ void Server::handle_client_lssnap(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; // traverse to path CInode *diri = mdcache->get_inode(req->get_filepath().get_ino()); if (!diri || diri->state_test(CInode::STATE_PURGING)) { reply_request(mdr, -ESTALE); return; } if (!diri->is_auth()) { mdcache->request_forward(mdr, diri->authority().first); return; } if (!diri->is_dir()) { reply_request(mdr, -ENOTDIR); return; } dout(10) << "lssnap on " << *diri << dendl; // lock snap set rdlocks, wrlocks, xlocks; mds->locker->include_snap_rdlocks(rdlocks, diri); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; SnapRealm *realm = diri->find_snaprealm(); map infomap; realm->get_snap_info(infomap, diri->get_oldest_snap()); __u32 num = 0; bufferlist dnbl; for (map::iterator p = infomap.begin(); p != infomap.end(); ++p) { dout(10) << p->first << " -> " << *p->second << dendl; // actual if (p->second->ino == diri->ino()) ::encode(p->second->name, dnbl); else ::encode(p->second->get_long_name(), dnbl); encode_infinite_lease(dnbl); diri->encode_inodestat(dnbl, mdr->session, realm, p->first); num++; } bufferlist dirbl; encode_empty_dirstat(dirbl); ::encode(num, dirbl); __u8 t = 1; ::encode(t, dirbl); // end ::encode(t, dirbl); // complete dirbl.claim_append(dnbl); MClientReply *reply = new MClientReply(req); reply->set_extra_bl(dirbl); reply_request(mdr, reply, diri); } // MKSNAP struct C_MDS_mksnap_finish : public Context { MDS *mds; MDRequestRef mdr; CInode *diri; SnapInfo info; C_MDS_mksnap_finish(MDS *m, MDRequestRef& r, CInode *di, SnapInfo &i) : mds(m), mdr(r), diri(di), info(i) {} void finish(int r) { mds->server->_mksnap_finish(mdr, diri, info); } }; /* This function takes responsibility for the passed mdr*/ void Server::handle_client_mksnap(MDRequestRef& mdr) { if (!mds->mdsmap->allows_snaps()) { // you can't make snapshots until you set an option right now reply_request(mdr, -EPERM); return; } MClientRequest *req = mdr->client_request; CInode *diri = mdcache->get_inode(req->get_filepath().get_ino()); if (!diri || diri->state_test(CInode::STATE_PURGING)) { reply_request(mdr, -ESTALE); return; } if (!diri->is_auth()) { // fw to auth? mdcache->request_forward(mdr, diri->authority().first); return; } // dir only if (!diri->is_dir()) { reply_request(mdr, -ENOTDIR); return; } if (diri->is_system() && !diri->is_root()) { // no snaps in system dirs (root is ok) reply_request(mdr, -EPERM); return; } const string &snapname = req->get_filepath().last_dentry(); dout(10) << "mksnap " << snapname << " on " << *diri << dendl; // lock snap set rdlocks, wrlocks, xlocks; mds->locker->include_snap_rdlocks(rdlocks, diri); rdlocks.erase(&diri->snaplock); xlocks.insert(&diri->snaplock); // we need to anchor... get these locks up front! mds->mdcache->anchor_create_prep_locks(mdr, diri, rdlocks, xlocks); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // make sure name is unique if (diri->snaprealm && diri->snaprealm->exists(snapname)) { reply_request(mdr, -EEXIST); return; } if (snapname.length() == 0 || snapname[0] == '_') { reply_request(mdr, -EINVAL); return; } if (mdr->now == utime_t()) mdr->now = ceph_clock_now(g_ceph_context); // anchor if (!diri->is_anchored()) { mdcache->anchor_create(mdr, diri, new C_MDS_RetryRequest(mdcache, mdr)); return; } // allocate a snapid if (!mdr->more()->stid) { // prepare an stid mds->snapclient->prepare_create(diri->ino(), snapname, mdr->now, &mdr->more()->stid, &mdr->more()->snapidbl, new C_MDS_RetryRequest(mds->mdcache, mdr)); return; } version_t stid = mdr->more()->stid; snapid_t snapid; bufferlist::iterator p = mdr->more()->snapidbl.begin(); ::decode(snapid, p); dout(10) << " stid " << stid << " snapid " << snapid << dendl; // journal SnapInfo info; info.ino = diri->ino(); info.snapid = snapid; info.name = snapname; info.stamp = mdr->now; inode_t *pi = diri->project_inode(); pi->ctime = info.stamp; pi->version = diri->pre_dirty(); // project the snaprealm sr_t *newsnap = diri->project_snaprealm(snapid); newsnap->snaps[snapid] = info; newsnap->seq = snapid; newsnap->last_created = snapid; // journal the inode changes mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "mksnap"); mdlog->start_entry(le); le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); le->metablob.add_table_transaction(TABLE_SNAP, stid); mdcache->predirty_journal_parents(mdr, &le->metablob, diri, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, diri); // journal the snaprealm changes mdlog->submit_entry(le, new C_MDS_mksnap_finish(mds, mdr, diri, info)); mdlog->flush(); } void Server::_mksnap_finish(MDRequestRef& mdr, CInode *diri, SnapInfo &info) { dout(10) << "_mksnap_finish " << *mdr << " " << info << dendl; int op = (diri->snaprealm? CEPH_SNAP_OP_CREATE : CEPH_SNAP_OP_SPLIT); diri->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); mds->snapclient->commit(mdr->more()->stid, mdr->ls); // create snap dout(10) << "snaprealm now " << *diri->snaprealm << dendl; mdcache->do_realm_invalidate_and_update_notify(diri, op); // yay mdr->in[0] = diri; mdr->snapid = info.snapid; MClientReply *reply = new MClientReply(mdr->client_request, 0); reply->snapbl = diri->snaprealm->get_snap_trace(); reply_request(mdr, reply, diri); } // RMSNAP struct C_MDS_rmsnap_finish : public Context { MDS *mds; MDRequestRef mdr; CInode *diri; snapid_t snapid; C_MDS_rmsnap_finish(MDS *m, MDRequestRef& r, CInode *di, snapid_t sn) : mds(m), mdr(r), diri(di), snapid(sn) {} void finish(int r) { mds->server->_rmsnap_finish(mdr, diri, snapid); } }; /* This function takes responsibility for the passed mdr*/ void Server::handle_client_rmsnap(MDRequestRef& mdr) { MClientRequest *req = mdr->client_request; CInode *diri = mdcache->get_inode(req->get_filepath().get_ino()); if (!diri || diri->state_test(CInode::STATE_PURGING)) { reply_request(mdr, -ESTALE); return; } if (!diri->is_auth()) { // fw to auth? mdcache->request_forward(mdr, diri->authority().first); return; } if (!diri->is_dir()) { reply_request(mdr, -ENOTDIR); return; } const string &snapname = req->get_filepath().last_dentry(); dout(10) << "rmsnap " << snapname << " on " << *diri << dendl; // does snap exist? if (snapname.length() == 0 || snapname[0] == '_') { reply_request(mdr, -EINVAL); // can't prune a parent snap, currently. return; } if (!diri->snaprealm || !diri->snaprealm->exists(snapname)) { reply_request(mdr, -ENOENT); return; } snapid_t snapid = diri->snaprealm->resolve_snapname(snapname, diri->ino()); dout(10) << " snapname " << snapname << " is " << snapid << dendl; set rdlocks, wrlocks, xlocks; mds->locker->include_snap_rdlocks(rdlocks, diri); rdlocks.erase(&diri->snaplock); xlocks.insert(&diri->snaplock); if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) return; // prepare if (!mdr->more()->stid) { mds->snapclient->prepare_destroy(diri->ino(), snapid, &mdr->more()->stid, &mdr->more()->snapidbl, new C_MDS_RetryRequest(mds->mdcache, mdr)); return; } version_t stid = mdr->more()->stid; bufferlist::iterator p = mdr->more()->snapidbl.begin(); snapid_t seq; ::decode(seq, p); dout(10) << " stid is " << stid << ", seq is " << seq << dendl; // journal inode_t *pi = diri->project_inode(); pi->ctime = ceph_clock_now(g_ceph_context); pi->version = diri->pre_dirty(); mdr->ls = mdlog->get_current_segment(); EUpdate *le = new EUpdate(mdlog, "rmsnap"); mdlog->start_entry(le); // project the snaprealm sr_t *newnode = diri->project_snaprealm(); newnode->snaps.erase(snapid); newnode->seq = seq; newnode->last_destroyed = seq; le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid()); le->metablob.add_table_transaction(TABLE_SNAP, stid); mdcache->predirty_journal_parents(mdr, &le->metablob, diri, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mdr.get(), &le->metablob, diri); mdlog->submit_entry(le, new C_MDS_rmsnap_finish(mds, mdr, diri, snapid)); mdlog->flush(); } void Server::_rmsnap_finish(MDRequestRef& mdr, CInode *diri, snapid_t snapid) { dout(10) << "_rmsnap_finish " << *mdr << " " << snapid << dendl; snapid_t stid = mdr->more()->stid; bufferlist::iterator p = mdr->more()->snapidbl.begin(); snapid_t seq; ::decode(seq, p); diri->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); mds->snapclient->commit(stid, mdr->ls); dout(10) << "snaprealm now " << *diri->snaprealm << dendl; mdcache->do_realm_invalidate_and_update_notify(diri, CEPH_SNAP_OP_DESTROY); // yay mdr->in[0] = diri; MClientReply *reply = new MClientReply(mdr->client_request, 0); reply_request(mdr, reply); } ceph-0.80.11/src/mds/Locker.h0000664000175100017510000002314412623076744017643 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_LOCKER_H #define CEPH_MDS_LOCKER_H #include "include/types.h" #include #include #include using std::map; using std::list; using std::set; class MDS; class Session; class CDir; class CInode; class CDentry; class EMetaBlob; struct SnapRealm; class Message; class MDiscover; class MDiscoverReply; class MCacheExpire; class MDirUpdate; class MDentryUnlink; class MLock; class MClientRequest; class Anchor; class Capability; class LogSegment; class SimpleLock; class ScatterLock; class LocalLock; class MDCache; #include "SimpleLock.h" class Locker { private: MDS *mds; MDCache *mdcache; public: Locker(MDS *m, MDCache *c) : mds(m), mdcache(c) {} SimpleLock *get_lock(int lock_type, MDSCacheObjectInfo &info); void dispatch(Message *m); void handle_lock(MLock *m); void nudge_log(SimpleLock *lock); protected: void send_lock_message(SimpleLock *lock, int msg); void send_lock_message(SimpleLock *lock, int msg, const bufferlist &data); // -- locks -- void _drop_rdlocks(MutationImpl *mut, set *pneed_issue); void _drop_non_rdlocks(MutationImpl *mut, set *pneed_issue); public: void include_snap_rdlocks(set& rdlocks, CInode *in); void include_snap_rdlocks_wlayout(set& rdlocks, CInode *in, ceph_file_layout **layout); bool acquire_locks(MDRequestRef& mdr, set &rdlocks, set &wrlocks, set &xlocks, map *remote_wrlocks=NULL, CInode *auth_pin_freeze=NULL, bool auth_pin_nonblock=false); void cancel_locking(MutationImpl *mut, set *pneed_issue); void drop_locks(MutationImpl *mut, set *pneed_issue=0); void set_xlocks_done(MutationImpl *mut, bool skip_dentry=false); void drop_non_rdlocks(MutationImpl *mut, set *pneed_issue=0); void drop_rdlocks(MutationImpl *mut, set *pneed_issue=0); void eval_gather(SimpleLock *lock, bool first=false, bool *need_issue=0, list *pfinishers=0); void eval(SimpleLock *lock, bool *need_issue); void eval_any(SimpleLock *lock, bool *need_issue, list *pfinishers=0, bool first=false) { if (!lock->is_stable()) eval_gather(lock, first, need_issue, pfinishers); else if (lock->get_parent()->is_auth()) eval(lock, need_issue); } class C_EvalScatterGathers : public Context { Locker *locker; CInode *in; public: C_EvalScatterGathers(Locker *l, CInode *i) : locker(l), in(i) { in->get(CInode::PIN_PTRWAITER); } void finish(int r) { in->put(CInode::PIN_PTRWAITER); locker->eval_scatter_gathers(in); } }; void eval_scatter_gathers(CInode *in); void eval_cap_gather(CInode *in, set *issue_set=0); bool eval(CInode *in, int mask, bool caps_imported=false); void try_eval(MDSCacheObject *p, int mask); void try_eval(SimpleLock *lock, bool *pneed_issue); bool _rdlock_kick(SimpleLock *lock, bool as_anon); bool rdlock_try(SimpleLock *lock, client_t client, Context *c); bool rdlock_start(SimpleLock *lock, MDRequestRef& mut, bool as_anon=false); void rdlock_finish(SimpleLock *lock, MutationImpl *mut, bool *pneed_issue); bool can_rdlock_set(set& locks); bool rdlock_try_set(set& locks); void rdlock_take_set(set& locks, MutationRef& mut); void wrlock_force(SimpleLock *lock, MutationRef& mut); bool wrlock_start(SimpleLock *lock, MDRequestRef& mut, bool nowait=false); void wrlock_finish(SimpleLock *lock, MutationImpl *mut, bool *pneed_issue); void remote_wrlock_start(SimpleLock *lock, int target, MDRequestRef& mut); void remote_wrlock_finish(SimpleLock *lock, int target, MutationImpl *mut); bool xlock_start(SimpleLock *lock, MDRequestRef& mut); void _finish_xlock(SimpleLock *lock, client_t xlocker, bool *pneed_issue); void xlock_finish(SimpleLock *lock, MutationImpl *mut, bool *pneed_issue); void xlock_export(SimpleLock *lock, MutationImpl *mut); void xlock_import(SimpleLock *lock); // simple public: void try_simple_eval(SimpleLock *lock); bool simple_rdlock_try(SimpleLock *lock, Context *con); protected: void simple_eval(SimpleLock *lock, bool *need_issue); void handle_simple_lock(SimpleLock *lock, MLock *m); public: bool simple_sync(SimpleLock *lock, bool *need_issue=0); protected: void simple_lock(SimpleLock *lock, bool *need_issue=0); void simple_excl(SimpleLock *lock, bool *need_issue=0); void simple_xlock(SimpleLock *lock); // scatter public: void scatter_eval(ScatterLock *lock, bool *need_issue); // public for MDCache::adjust_subtree_auth() void scatter_tick(); void scatter_nudge(ScatterLock *lock, Context *c, bool forcelockchange=false); protected: void handle_scatter_lock(ScatterLock *lock, MLock *m); void _scatter_replica_lock(ScatterLock *lock, int auth); bool scatter_scatter_fastpath(ScatterLock *lock); void scatter_scatter(ScatterLock *lock, bool nowait=false); void scatter_tempsync(ScatterLock *lock, bool *need_issue=0); void scatter_writebehind(ScatterLock *lock); class C_Locker_ScatterWB : public Context { Locker *locker; ScatterLock *lock; MutationRef mut; public: C_Locker_ScatterWB(Locker *l, ScatterLock *sl, MutationRef& m) : locker(l), lock(sl), mut(m) {} void finish(int r) { locker->scatter_writebehind_finish(lock, mut); } }; void scatter_writebehind_finish(ScatterLock *lock, MutationRef& mut); xlist updated_scatterlocks; public: void mark_updated_scatterlock(ScatterLock *lock); void handle_reqrdlock(SimpleLock *lock, MLock *m); // caps // when to defer processing client cap release or writeback due to being // frozen. the condition must be consistent across handle_client_caps and // process_request_cap_release to preserve ordering. bool should_defer_client_cap_frozen(CInode *in); void process_request_cap_release(MDRequestRef& mdr, client_t client, const ceph_mds_request_release& r, const string &dname); void kick_cap_releases(MDRequestRef& mdr); void kick_issue_caps(CInode *in, client_t client, ceph_seq_t seq); void remove_client_cap(CInode *in, client_t client); protected: void adjust_cap_wanted(Capability *cap, int wanted, int issue_seq); void handle_client_caps(class MClientCaps *m); void _update_cap_fields(CInode *in, int dirty, MClientCaps *m, inode_t *pi); void _do_snap_update(CInode *in, snapid_t snap, int dirty, snapid_t follows, client_t client, MClientCaps *m, MClientCaps *ack); void _do_null_snapflush(CInode *head_in, client_t client, snapid_t follows); bool _do_cap_update(CInode *in, Capability *cap, int dirty, snapid_t follows, MClientCaps *m, MClientCaps *ack=0); void handle_client_cap_release(class MClientCapRelease *m); void _do_cap_release(client_t client, inodeno_t ino, uint64_t cap_id, ceph_seq_t mseq, ceph_seq_t seq); // local public: void local_wrlock_grab(LocalLock *lock, MutationRef& mut); protected: bool local_wrlock_start(LocalLock *lock, MDRequestRef& mut); void local_wrlock_finish(LocalLock *lock, MutationImpl *mut); bool local_xlock_start(LocalLock *lock, MDRequestRef& mut); void local_xlock_finish(LocalLock *lock, MutationImpl *mut); // file public: void file_eval(ScatterLock *lock, bool *need_issue); protected: void handle_file_lock(ScatterLock *lock, MLock *m); void scatter_mix(ScatterLock *lock, bool *need_issue=0); void file_excl(ScatterLock *lock, bool *need_issue=0); void file_xsyn(SimpleLock *lock, bool *need_issue=0); public: void file_recover(ScatterLock *lock); private: xlist updated_filelocks; public: void mark_updated_Filelock(ScatterLock *lock); // -- file i/o -- public: version_t issue_file_data_version(CInode *in); Capability* issue_new_caps(CInode *in, int mode, Session *session, SnapRealm *conrealm, bool is_replay); bool issue_caps(CInode *in, Capability *only_cap=0); void issue_caps_set(set& inset); void issue_truncate(CInode *in); void revoke_stale_caps(Session *session); void resume_stale_caps(Session *session); void remove_stale_leases(Session *session); public: void request_inode_file_caps(CInode *in); protected: void handle_inode_file_caps(class MInodeFileCaps *m); void file_update_finish(CInode *in, MutationRef& mut, bool share, client_t client, Capability *cap, MClientCaps *ack); public: void calc_new_client_ranges(CInode *in, uint64_t size, map& new_ranges); bool check_inode_max_size(CInode *in, bool force_wrlock=false, bool update_size=false, uint64_t newsize=0, bool update_max=false, uint64_t newmax=0, utime_t mtime=utime_t()); void share_inode_max_size(CInode *in, Capability *only_cap=0); private: friend class C_MDL_CheckMaxSize; friend class C_MDL_RequestInodeFileCaps; friend struct C_Locker_FileUpdate_finish; friend class C_Locker_RetryCapRelease; // -- client leases -- public: void handle_client_lease(struct MClientLease *m); void issue_client_lease(CDentry *dn, client_t client, bufferlist &bl, utime_t now, Session *session); void revoke_client_leases(SimpleLock *lock); }; #endif ceph-0.80.11/src/mds/MDS.h0000664000175100017510000002464412623076744017055 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_H #define CEPH_MDS_H #include "mdstypes.h" #include "msg/Dispatcher.h" #include "include/CompatSet.h" #include "include/types.h" #include "include/Context.h" #include "common/DecayCounter.h" #include "common/perf_counters.h" #include "common/Mutex.h" #include "common/Cond.h" #include "common/Timer.h" #include "common/LogClient.h" #include "MDSMap.h" #include "SessionMap.h" #define CEPH_MDS_PROTOCOL 23 /* cluster internal */ enum { l_mds_first = 2000, l_mds_req, l_mds_reply, l_mds_replyl, l_mds_fw, l_mds_dir_f, l_mds_dir_c, l_mds_dir_sp, l_mds_dir_ffc, l_mds_imax, l_mds_i, l_mds_itop, l_mds_ibot, l_mds_iptail, l_mds_ipin, l_mds_iex, l_mds_icap, l_mds_cap, l_mds_dis, l_mds_t, l_mds_thit, l_mds_tfw, l_mds_tdis, l_mds_tdirf, l_mds_trino, l_mds_tlock, l_mds_l, l_mds_q, l_mds_popanyd, l_mds_popnest, l_mds_sm, l_mds_ex, l_mds_iexp, l_mds_im, l_mds_iim, l_mds_last, }; enum { l_mdc_first = 3000, l_mdc_last, }; enum { l_mdm_first = 2500, l_mdm_ino, l_mdm_inoa, l_mdm_inos, l_mdm_dir, l_mdm_dira, l_mdm_dirs, l_mdm_dn, l_mdm_dna, l_mdm_dns, l_mdm_cap, l_mdm_capa, l_mdm_caps, l_mdm_rss, l_mdm_heap, l_mdm_malloc, l_mdm_buf, l_mdm_last, }; class filepath; class MonClient; class OSDMap; class Objecter; class Filer; class Server; class Locker; class MDCache; class MDLog; class MDBalancer; class CInode; class CDir; class CDentry; class Messenger; class Message; class MClientRequest; class MClientReply; class MMDSBeacon; class InoTable; class SnapServer; class SnapClient; class AnchorServer; class AnchorClient; class MDSTableServer; class MDSTableClient; class AuthAuthorizeHandlerRegistry; class MDS : public Dispatcher { public: Mutex mds_lock; SafeTimer timer; AuthAuthorizeHandlerRegistry *authorize_handler_cluster_registry; AuthAuthorizeHandlerRegistry *authorize_handler_service_registry; string name; int whoami; int incarnation; int standby_for_rank; int standby_type; string standby_for_name; bool standby_replaying; // true if current replay pass is in standby-replay mode Messenger *messenger; MonClient *monc; MDSMap *mdsmap; OSDMap *osdmap; Objecter *objecter; Filer *filer; // for reading/writing to/from osds LogClient clog; // sub systems Server *server; MDCache *mdcache; Locker *locker; MDLog *mdlog; MDBalancer *balancer; InoTable *inotable; AnchorServer *anchorserver; AnchorClient *anchorclient; SnapServer *snapserver; SnapClient *snapclient; MDSTableClient *get_table_client(int t); MDSTableServer *get_table_server(int t); PerfCounters *logger, *mlogger; int orig_argc; const char **orig_argv; protected: // -- MDS state -- int last_state; int state; // my confirmed state int want_state; // the state i want list waiting_for_active, waiting_for_replay, waiting_for_reconnect, waiting_for_resolve; list replay_queue; map > waiting_for_active_peer; list waiting_for_nolaggy; map > waiting_for_mdsmap; map peer_mdsmap_epoch; ceph_tid_t last_tid; // for mds-initiated requests (e.g. stray rename) public: void wait_for_active(Context *c) { waiting_for_active.push_back(c); } void wait_for_active_peer(int who, Context *c) { waiting_for_active_peer[who].push_back(c); } void wait_for_replay(Context *c) { waiting_for_replay.push_back(c); } void wait_for_reconnect(Context *c) { waiting_for_reconnect.push_back(c); } void wait_for_resolve(Context *c) { waiting_for_resolve.push_back(c); } void wait_for_mdsmap(epoch_t e, Context *c) { waiting_for_mdsmap[e].push_back(c); } void enqueue_replay(Context *c) { replay_queue.push_back(c); } int get_state() { return state; } int get_want_state() { return want_state; } bool is_creating() { return state == MDSMap::STATE_CREATING; } bool is_starting() { return state == MDSMap::STATE_STARTING; } bool is_standby() { return state == MDSMap::STATE_STANDBY; } bool is_replay() { return state == MDSMap::STATE_REPLAY; } bool is_standby_replay() { return state == MDSMap::STATE_STANDBY_REPLAY; } bool is_resolve() { return state == MDSMap::STATE_RESOLVE; } bool is_reconnect() { return state == MDSMap::STATE_RECONNECT; } bool is_rejoin() { return state == MDSMap::STATE_REJOIN; } bool is_clientreplay() { return state == MDSMap::STATE_CLIENTREPLAY; } bool is_active() { return state == MDSMap::STATE_ACTIVE; } bool is_stopping() { return state == MDSMap::STATE_STOPPING; } bool is_oneshot_replay() { return state == MDSMap::STATE_ONESHOT_REPLAY; } bool is_any_replay() { return (is_replay() || is_standby_replay() || is_oneshot_replay()); } bool is_stopped() { return mdsmap->is_stopped(whoami); } void request_state(int s); ceph_tid_t issue_tid() { return ++last_tid; } // -- waiters -- list finished_queue; void queue_waiter(Context *c) { finished_queue.push_back(c); } void queue_waiters(list& ls) { finished_queue.splice( finished_queue.end(), ls ); } bool queue_one_replay() { if (replay_queue.empty()) return false; queue_waiter(replay_queue.front()); replay_queue.pop_front(); return true; } // -- keepalive beacon -- version_t beacon_last_seq; // last seq sent to monitor map beacon_seq_stamp; // seq # -> time sent utime_t beacon_last_acked_stamp; // last time we sent a beacon that got acked bool was_laggy; utime_t laggy_until; bool is_laggy(); utime_t get_laggy_until() { return laggy_until; } class C_MDS_BeaconSender : public Context { MDS *mds; public: C_MDS_BeaconSender(MDS *m) : mds(m) {} void finish(int r) { mds->beacon_sender = 0; mds->beacon_send(); } } *beacon_sender; // tick and other timer fun class C_MDS_Tick : public Context { MDS *mds; public: C_MDS_Tick(MDS *m) : mds(m) {} void finish(int r) { mds->tick_event = 0; mds->tick(); } } *tick_event; void reset_tick(); // -- client map -- SessionMap sessionmap; epoch_t last_client_mdsmap_bcast; //void log_clientmap(Context *c); // shutdown crap int req_rate; // ino's and fh's public: int get_req_rate() { return req_rate; } Session *get_session(client_t client) { return sessionmap.get_session(entity_name_t::CLIENT(client.v)); } private: int dispatch_depth; bool ms_dispatch(Message *m); bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); bool ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key); void ms_handle_accept(Connection *con); void ms_handle_connect(Connection *con); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con); public: MDS(const std::string &n, Messenger *m, MonClient *mc); ~MDS(); // handle a signal (e.g., SIGTERM) void handle_signal(int signum); // who am i etc int get_nodeid() { return whoami; } MDSMap *get_mds_map() { return mdsmap; } OSDMap *get_osd_map() { return osdmap; } void send_message_mds(Message *m, int mds); void forward_message_mds(Message *req, int mds); void send_message_client_counted(Message *m, client_t client); void send_message_client_counted(Message *m, Session *session); void send_message_client_counted(Message *m, Connection *connection); void send_message_client_counted(Message *m, const ConnectionRef& con) { send_message_client_counted(m, con.get()); } void send_message_client(Message *m, Session *session); void send_message(Message *m, Connection *c); void send_message(Message *m, const ConnectionRef& c) { send_message(m, c.get()); } // start up, shutdown int init(int wanted_state=MDSMap::STATE_BOOT); void create_logger(); void bcast_mds_map(); // to mounted clients void boot_create(); // i am new mds. void boot_start(int step=0, int r=0); // starting|replay void calc_recovery_set(); void replay_start(); void creating_done(); void starting_done(); void replay_done(); void standby_replay_restart(); void _standby_replay_restart_finish(int r, uint64_t old_read_pos); class C_MDS_StandbyReplayRestart; class C_MDS_StandbyReplayRestartFinish; void reopen_log(); void resolve_start(); void resolve_done(); void reconnect_start(); void reconnect_done(); void rejoin_joint_start(); void rejoin_start(); void rejoin_done(); void recovery_done(int oldstate); void clientreplay_start(); void clientreplay_done(); void active_start(); void stopping_start(); void stopping_done(); void handle_mds_recovery(int who); void handle_mds_failure(int who); void suicide(); void respawn(); void tick(); void beacon_start(); void beacon_send(); void handle_mds_beacon(MMDSBeacon *m); void request_osdmap(Context *c); void inc_dispatch_depth() { ++dispatch_depth; } void dec_dispatch_depth() { --dispatch_depth; } // messages bool _dispatch(Message *m); bool is_stale_message(Message *m); bool handle_core_message(Message *m); bool handle_deferrable_message(Message *m); // special message types void handle_command(class MMonCommand *m); void handle_mds_map(class MMDSMap *m); }; /* This expects to be given a reference which it is responsible for. * The finish function calls functions which * will put the Message exactly once.*/ class C_MDS_RetryMessage : public Context { Message *m; MDS *mds; public: C_MDS_RetryMessage(MDS *mds, Message *m) { assert(m); this->m = m; this->mds = mds; } virtual void finish(int r) { mds->inc_dispatch_depth(); mds->_dispatch(m); mds->dec_dispatch_depth(); } }; #endif ceph-0.80.11/src/mds/CDentry.cc0000664000175100017510000003061012623076744020126 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "CDentry.h" #include "CInode.h" #include "CDir.h" #include "Anchor.h" #include "MDS.h" #include "MDCache.h" #include "Locker.h" #include "LogSegment.h" #include "messages/MLock.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << dir->cache->mds->get_nodeid() << ".cache.den(" << dir->dirfrag() << " " << name << ") " ostream& CDentry::print_db_line_prefix(ostream& out) { return out << ceph_clock_now(g_ceph_context) << " mds." << dir->cache->mds->get_nodeid() << ".cache.den(" << dir->ino() << " " << name << ") "; } boost::pool<> CDentry::pool(sizeof(CDentry)); LockType CDentry::lock_type(CEPH_LOCK_DN); LockType CDentry::versionlock_type(CEPH_LOCK_DVERSION); // CDentry ostream& operator<<(ostream& out, CDentry& dn) { filepath path; dn.make_path(path); out << "[dentry " << path; if (true || dn.first != 0 || dn.last != CEPH_NOSNAP) { out << " [" << dn.first << ","; if (dn.last == CEPH_NOSNAP) out << "head"; else out << dn.last; out << ']'; } if (dn.is_auth()) { out << " auth"; if (dn.is_replicated()) out << dn.get_replicas(); } else { out << " rep@" << dn.authority(); out << "." << dn.get_replica_nonce(); } if (dn.get_linkage()->is_null()) out << " NULL"; if (dn.get_linkage()->is_remote()) { out << " REMOTE("; switch (DTTOIF(dn.get_linkage()->get_remote_d_type())) { case S_IFSOCK: out << "sock"; break; case S_IFLNK: out << "lnk"; break; case S_IFREG: out << "reg"; break; case S_IFBLK: out << "blk"; break; case S_IFDIR: out << "dir"; break; case S_IFCHR: out << "chr"; break; case S_IFIFO: out << "fifo"; break; default: assert(0); } out << ")"; } if (!dn.lock.is_sync_and_unlocked()) out << " " << dn.lock; if (!dn.versionlock.is_sync_and_unlocked()) out << " " << dn.versionlock; if (dn.get_projected_version() != dn.get_version()) out << " pv=" << dn.get_projected_version(); out << " v=" << dn.get_version(); if (dn.is_auth_pinned()) out << " ap=" << dn.get_num_auth_pins() << "+" << dn.get_num_nested_auth_pins(); out << " inode=" << dn.get_linkage()->get_inode(); if (dn.is_new()) out << " state=new"; if (dn.get_num_ref()) { out << " |"; dn.print_pin_set(out); } out << " " << &dn; out << "]"; return out; } bool operator<(const CDentry& l, const CDentry& r) { if ((l.get_dir()->ino() < r.get_dir()->ino()) || (l.get_dir()->ino() == r.get_dir()->ino() && (l.get_name() < r.get_name() || (l.get_name() == r.get_name() && l.last < r.last)))) return true; return false; } void CDentry::print(ostream& out) { out << *this; } /* inodeno_t CDentry::get_ino() { if (get_inode()) return get_inode()->ino(); return inodeno_t(); } */ pair CDentry::authority() { return dir->authority(); } void CDentry::add_waiter(uint64_t tag, Context *c) { // wait on the directory? if (tag & (WAIT_UNFREEZE|WAIT_SINGLEAUTH)) { dir->add_waiter(tag, c); return; } MDSCacheObject::add_waiter(tag, c); } version_t CDentry::pre_dirty(version_t min) { projected_version = dir->pre_dirty(min); dout(10) << " pre_dirty " << *this << dendl; return projected_version; } void CDentry::_mark_dirty(LogSegment *ls) { // state+pin if (!state_test(STATE_DIRTY)) { state_set(STATE_DIRTY); dir->inc_num_dirty(); get(PIN_DIRTY); assert(ls); } if (ls) ls->dirty_dentries.push_back(&item_dirty); } void CDentry::mark_dirty(version_t pv, LogSegment *ls) { dout(10) << " mark_dirty " << *this << dendl; // i now live in this new dir version assert(pv <= projected_version); version = pv; _mark_dirty(ls); // mark dir too dir->mark_dirty(pv, ls); } void CDentry::mark_clean() { dout(10) << " mark_clean " << *this << dendl; assert(is_dirty()); // not always true for recalc_auth_bits during resolve finish //assert(dir->get_version() == 0 || version <= dir->get_version()); // hmm? // state+pin state_clear(STATE_DIRTY); dir->dec_num_dirty(); put(PIN_DIRTY); item_dirty.remove_myself(); clear_new(); } void CDentry::mark_new() { dout(10) << " mark_new " << *this << dendl; state_set(STATE_NEW); } void CDentry::make_path_string(string& s) { if (dir) { dir->inode->make_path_string(s); } else { s = "???"; } s += "/"; s.append(name.data(), name.length()); } void CDentry::make_path(filepath& fp) { assert(dir); if (dir->inode->is_base()) fp = filepath(dir->inode->ino()); // base case else if (dir->inode->get_parent_dn()) dir->inode->get_parent_dn()->make_path(fp); // recurse else fp = filepath(dir->inode->ino()); // relative but not base? hrm! fp.push_dentry(name); } /* void CDentry::make_path(string& s, inodeno_t tobase) { assert(dir); if (dir->inode->is_root()) { s += "/"; // make it an absolute path (no matter what) if we hit the root. } else if (dir->inode->get_parent_dn() && dir->inode->ino() != tobase) { dir->inode->get_parent_dn()->make_path(s, tobase); s += "/"; } s += name; } */ /** make_anchor_trace * construct an anchor trace for this dentry, as if it were linked to *in. */ void CDentry::make_anchor_trace(vector& trace, CInode *in) { // start with parent dir inode dir->inode->make_anchor_trace(trace); // add this inode (in my dirfrag) to the end trace.push_back(Anchor(in->ino(), dir->ino(), get_hash(), 0, 0)); dout(10) << "make_anchor_trace added " << trace.back() << dendl; } /* * we only add ourselves to remote_parents when the linkage is * active (no longer projected). if the passed dnl is projected, * don't link in, and do that work later in pop_projected_linkage(). */ void CDentry::link_remote(CDentry::linkage_t *dnl, CInode *in) { assert(dnl->is_remote()); assert(in->ino() == dnl->get_remote_ino()); dnl->inode = in; if (dnl == &linkage) in->add_remote_parent(this); } void CDentry::unlink_remote(CDentry::linkage_t *dnl) { assert(dnl->is_remote()); assert(dnl->inode); if (dnl == &linkage) dnl->inode->remove_remote_parent(this); dnl->inode = 0; } void CDentry::push_projected_linkage(CInode *inode) { // dirty rstat tracking is in the projected plane bool dirty_rstat = inode->is_dirty_rstat(); if (dirty_rstat) inode->clear_dirty_rstat(); _project_linkage()->inode = inode; inode->push_projected_parent(this); if (dirty_rstat) inode->mark_dirty_rstat(); } CDentry::linkage_t *CDentry::pop_projected_linkage() { assert(projected.size()); linkage_t& n = projected.front(); /* * the idea here is that the link_remote_inode(), link_primary_inode(), * etc. calls should make linkage identical to &n (and we assert as * much). */ if (n.remote_ino) { dir->link_remote_inode(this, n.remote_ino, n.remote_d_type); if (n.inode) { linkage.inode = n.inode; linkage.inode->add_remote_parent(this); } } else if (n.inode) { dir->link_primary_inode(this, n.inode); n.inode->pop_projected_parent(); } assert(n.inode == linkage.inode); assert(n.remote_ino == linkage.remote_ino); assert(n.remote_d_type == linkage.remote_d_type); projected.pop_front(); return &linkage; } // ---------------------------- // auth pins int CDentry::get_num_dir_auth_pins() { assert(!is_projected()); if (get_linkage()->is_primary()) return auth_pins + get_linkage()->get_inode()->get_num_auth_pins(); return auth_pins; } bool CDentry::can_auth_pin() { assert(dir); return dir->can_auth_pin(); } void CDentry::auth_pin(void *by) { if (auth_pins == 0) get(PIN_AUTHPIN); auth_pins++; #ifdef MDS_AUTHPIN_SET auth_pin_set.insert(by); #endif dout(10) << "auth_pin by " << by << " on " << *this << " now " << auth_pins << "+" << nested_auth_pins << dendl; dir->adjust_nested_auth_pins(1, 1, by); } void CDentry::auth_unpin(void *by) { auth_pins--; #ifdef MDS_AUTHPIN_SET assert(auth_pin_set.count(by)); auth_pin_set.erase(auth_pin_set.find(by)); #endif if (auth_pins == 0) put(PIN_AUTHPIN); dout(10) << "auth_unpin by " << by << " on " << *this << " now " << auth_pins << "+" << nested_auth_pins << dendl; assert(auth_pins >= 0); dir->adjust_nested_auth_pins(-1, -1, by); } void CDentry::adjust_nested_auth_pins(int adjustment, int diradj, void *by) { nested_auth_pins += adjustment; dout(35) << "adjust_nested_auth_pins by " << by << ", change " << adjustment << " yields " << auth_pins << "+" << nested_auth_pins << dendl; assert(nested_auth_pins >= 0); dir->adjust_nested_auth_pins(adjustment, diradj, by); } bool CDentry::is_frozen() { return dir->is_frozen(); } bool CDentry::is_freezing() { return dir->is_freezing(); } void CDentry::adjust_nested_anchors(int by) { nested_anchors += by; dout(20) << "adjust_nested_anchors by " << by << " -> " << nested_anchors << dendl; assert(nested_anchors >= 0); dir->adjust_nested_anchors(by); } void CDentry::decode_replica(bufferlist::iterator& p, bool is_new) { __u32 nonce; ::decode(nonce, p); replica_nonce = nonce; ::decode(first, p); inodeno_t rino; unsigned char rdtype; __s32 ls; ::decode(rino, p); ::decode(rdtype, p); ::decode(ls, p); if (is_new) { if (rino) dir->link_remote_inode(this, rino, rdtype); lock.set_state(ls); } } // ---------------------------- // locking void CDentry::set_object_info(MDSCacheObjectInfo &info) { info.dirfrag = dir->dirfrag(); info.dname = name; info.snapid = last; } void CDentry::encode_lock_state(int type, bufferlist& bl) { ::encode(first, bl); // null, ino, or remote_ino? char c; if (linkage.is_primary()) { c = 1; ::encode(c, bl); ::encode(linkage.get_inode()->inode.ino, bl); } else if (linkage.is_remote()) { c = 2; ::encode(c, bl); ::encode(linkage.get_remote_ino(), bl); } else if (linkage.is_null()) { // encode nothing. } else assert(0); } void CDentry::decode_lock_state(int type, bufferlist& bl) { bufferlist::iterator p = bl.begin(); snapid_t newfirst; ::decode(newfirst, p); if (!is_auth() && newfirst != first) { dout(10) << "decode_lock_state first " << first << " -> " << newfirst << dendl; assert(newfirst > first); first = newfirst; } if (p.end()) { // null assert(linkage.is_null()); return; } char c; inodeno_t ino; ::decode(c, p); switch (c) { case 1: case 2: ::decode(ino, p); // newly linked? if (linkage.is_null() && !is_auth()) { // force trim from cache! dout(10) << "decode_lock_state replica dentry null -> non-null, must trim" << dendl; //assert(get_num_ref() == 0); } else { // verify? } break; default: assert(0); } } ClientLease *CDentry::add_client_lease(client_t c, Session *session) { ClientLease *l; if (client_lease_map.count(c)) l = client_lease_map[c]; else { dout(20) << "add_client_lease client." << c << " on " << lock << dendl; if (client_lease_map.empty()) get(PIN_CLIENTLEASE); l = client_lease_map[c] = new ClientLease(c, this); l->seq = ++session->lease_seq; lock.get_client_lease(); } return l; } void CDentry::remove_client_lease(ClientLease *l, Locker *locker) { assert(l->parent == this); bool gather = false; dout(20) << "remove_client_lease client." << l->client << " on " << lock << dendl; lock.put_client_lease(); if (lock.get_num_client_lease() == 0 && !lock.is_stable()) gather = true; client_lease_map.erase(l->client); l->item_lease.remove_myself(); l->item_session_lease.remove_myself(); delete l; if (client_lease_map.empty()) put(PIN_CLIENTLEASE); if (gather) locker->eval_gather(&lock); } void CDentry::_put() { if (get_num_ref() <= (int)is_dirty() + 1) { CDentry::linkage_t *dnl = get_projected_linkage(); if (dnl->is_primary()) { CInode *in = dnl->get_inode(); if (get_num_ref() == (int)is_dirty() + !!in->get_num_ref()) in->mdcache->maybe_eval_stray(in, true); } } } ceph-0.80.11/src/mds/MDSTable.h0000664000175100017510000000444512623076744020022 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSTABLE_H #define CEPH_MDSTABLE_H #include "mdstypes.h" #include "mds_table_types.h" #include "include/buffer.h" #include "include/Context.h" class MDS; class MDSTable { protected: MDS *mds; const char *table_name; bool per_mds; object_t get_object_name(); static const int STATE_UNDEF = 0; static const int STATE_OPENING = 1; static const int STATE_ACTIVE = 2; //static const int STATE_COMMITTING = 3; int state; version_t version, committing_version, committed_version, projected_version; map > waitfor_save; public: MDSTable(MDS *m, const char *n, bool is_per_mds) : mds(m), table_name(n), per_mds(is_per_mds), state(STATE_UNDEF), version(0), committing_version(0), committed_version(0), projected_version(0) {} virtual ~MDSTable() {} version_t get_version() { return version; } version_t get_committed_version() { return committed_version; } version_t get_committing_version() { return committing_version; } version_t get_projected_version() { return projected_version; } void force_replay_version(version_t v) { version = projected_version = v; } //version_t project_version() { return ++projected_version; } //version_t inc_version() { return ++version; } // load/save from disk (hack) bool is_undef() { return state == STATE_UNDEF; } bool is_active() { return state == STATE_ACTIVE; } bool is_opening() { return state == STATE_OPENING; } void reset(); void save(Context *onfinish=0, version_t need=0); void save_2(int r, version_t v); void shutdown() { if (is_active()) save(0); } void load(Context *onfinish); void load_2(int, bufferlist&, Context *onfinish); // child must overload these virtual void reset_state() = 0; virtual void decode_state(bufferlist::iterator& p) = 0; virtual void encode_state(bufferlist& bl) const = 0; }; #endif ceph-0.80.11/src/mds/Dumper.cc0000664000175100017510000001554412623076744020023 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Greg Farnum * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef _BACKWARD_BACKWARD_WARNING_H #define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_* #endif #include "include/compat.h" #include "common/entity_name.h" #include "common/errno.h" #include "common/safe_io.h" #include "mds/Dumper.h" #include "mds/mdstypes.h" #include "mds/LogEvent.h" #include "osdc/Journaler.h" #define dout_subsys ceph_subsys_mds int Dumper::init(int rank_) { rank = rank_; int r = MDSUtility::init(); if (r < 0) { return r; } inodeno_t ino = MDS_INO_LOG_OFFSET + rank; journaler = new Journaler(ino, mdsmap->get_metadata_pool(), CEPH_FS_ONDISK_MAGIC, objecter, 0, 0, &timer); return 0; } int Dumper::recover_journal() { bool done = false; Cond cond; Mutex localLock("dump:recover_journal"); int r; lock.Lock(); journaler->recover(new C_SafeCond(&localLock, &cond, &done, &r)); lock.Unlock(); localLock.Lock(); while (!done) cond.Wait(localLock); localLock.Unlock(); if (r < 0) { // Error derr << "error on recovery: " << cpp_strerror(r) << dendl; return r; } else { dout(10) << "completed journal recovery" << dendl; return 0; } } void Dumper::dump(const char *dump_file) { bool done = false; int r = 0; Cond cond; Mutex localLock("dump:lock"); r = recover_journal(); if (r) { return; } uint64_t start = journaler->get_read_pos(); uint64_t end = journaler->get_write_pos(); uint64_t len = end-start; inodeno_t ino = MDS_INO_LOG_OFFSET + rank; cout << "journal is " << start << "~" << len << std::endl; Filer filer(objecter); bufferlist bl; lock.Lock(); filer.read(ino, &journaler->get_layout(), CEPH_NOSNAP, start, len, &bl, 0, new C_SafeCond(&localLock, &cond, &done)); lock.Unlock(); localLock.Lock(); while (!done) cond.Wait(localLock); localLock.Unlock(); cout << "read " << bl.length() << " bytes at offset " << start << std::endl; int fd = ::open(dump_file, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd >= 0) { // include an informative header char buf[200]; memset(buf, 0, sizeof(buf)); sprintf(buf, "Ceph mds%d journal dump\n start offset %llu (0x%llx)\n length %llu (0x%llx)\n%c", rank, (unsigned long long)start, (unsigned long long)start, (unsigned long long)bl.length(), (unsigned long long)bl.length(), 4); int r = safe_write(fd, buf, sizeof(buf)); if (r) ceph_abort(); // write the data ::lseek64(fd, start, SEEK_SET); bl.write_fd(fd); ::close(fd); cout << "wrote " << bl.length() << " bytes at offset " << start << " to " << dump_file << "\n" << "NOTE: this is a _sparse_ file; you can\n" << "\t$ tar cSzf " << dump_file << ".tgz " << dump_file << "\n" << " to efficiently compress it while preserving sparseness." << std::endl; } else { int err = errno; derr << "unable to open " << dump_file << ": " << cpp_strerror(err) << dendl; } } void Dumper::undump(const char *dump_file) { cout << "undump " << dump_file << std::endl; int fd = ::open(dump_file, O_RDONLY); if (fd < 0) { derr << "couldn't open " << dump_file << ": " << cpp_strerror(errno) << dendl; return; } // Ceph mds0 journal dump // start offset 232401996 (0xdda2c4c) // length 1097504 (0x10bf20) char buf[200]; int r = safe_read(fd, buf, sizeof(buf)); if (r < 0) { VOID_TEMP_FAILURE_RETRY(::close(fd)); return; } long long unsigned start, len; sscanf(strstr(buf, "start offset"), "start offset %llu", &start); sscanf(strstr(buf, "length"), "length %llu", &len); cout << "start " << start << " len " << len << std::endl; inodeno_t ino = MDS_INO_LOG_OFFSET + rank; Journaler::Header h; h.trimmed_pos = start - (start % g_default_file_layout.fl_object_size); h.expire_pos = start; h.write_pos = start+len; h.magic = CEPH_FS_ONDISK_MAGIC; h.layout = g_default_file_layout; h.layout.fl_pg_pool = mdsmap->get_metadata_pool(); bufferlist hbl; ::encode(h, hbl); object_t oid = file_object_t(ino, 0); object_locator_t oloc(mdsmap->get_metadata_pool()); SnapContext snapc; cout << "writing header " << oid << std::endl; C_SaferCond header_cond; lock.Lock(); objecter->write_full(oid, oloc, snapc, hbl, ceph_clock_now(g_ceph_context), 0, NULL, &header_cond); lock.Unlock(); header_cond.wait(); // read Filer filer(objecter); uint64_t pos = start; uint64_t left = len; while (left > 0) { bufferlist j; lseek64(fd, pos, SEEK_SET); uint64_t l = MIN(left, 1024*1024); j.read_fd(fd, l); cout << " writing " << pos << "~" << l << std::endl; C_SaferCond body_cond; lock.Lock(); filer.write(ino, &h.layout, snapc, pos, l, j, ceph_clock_now(g_ceph_context), 0, NULL, &body_cond); lock.Unlock(); body_cond.wait(); pos += l; left -= l; } VOID_TEMP_FAILURE_RETRY(::close(fd)); cout << "done." << std::endl; } /** * Write JSON-formatted log entries to standard out. */ void Dumper::dump_entries() { Mutex localLock("dump_entries"); JSONFormatter jf(true); int r = recover_journal(); if (r) { return; } jf.open_array_section("log"); bool got_data = true; lock.Lock(); // Until the journal is empty, pop an event or wait for one to // be available. dout(10) << "Journaler read/write/size: " << journaler->get_read_pos() << "/" << journaler->get_write_pos() << "/" << journaler->get_write_pos() - journaler->get_read_pos() << dendl; while (journaler->get_read_pos() != journaler->get_write_pos()) { bufferlist entry_bl; got_data = journaler->try_read_entry(entry_bl); dout(10) << "try_read_entry: " << got_data << dendl; if (got_data) { LogEvent *le = LogEvent::decode(entry_bl); if (!le) { dout(0) << "Error decoding LogEvent" << dendl; break; } else { jf.open_object_section("log_event"); jf.dump_unsigned("type", le->get_type()); jf.dump_unsigned("start_off", le->get_start_off()); jf.dump_unsigned("stamp_sec", le->get_stamp().tv.tv_sec); jf.dump_unsigned("stamp_nsec", le->get_stamp().tv.tv_nsec); le->dump(&jf); jf.close_section(); delete le; } } else { bool done = false; Cond cond; journaler->wait_for_readable(new C_SafeCond(&localLock, &cond, &done)); lock.Unlock(); localLock.Lock(); while (!done) cond.Wait(localLock); localLock.Unlock(); lock.Lock(); } } lock.Unlock(); jf.close_section(); jf.flush(cout); return; } ceph-0.80.11/src/mds/events/0000775000175100017510000000000012623077034017544 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/mds/events/ESubtreeMap.h0000664000175100017510000000221612623076744022101 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ESUBTREEMAP_H #define CEPH_MDS_ESUBTREEMAP_H #include "../LogEvent.h" #include "EMetaBlob.h" class ESubtreeMap : public LogEvent { public: EMetaBlob metablob; map > subtrees; set ambiguous_subtrees; uint64_t expire_pos; ESubtreeMap() : LogEvent(EVENT_SUBTREEMAP), expire_pos(0) { } void print(ostream& out) const { out << "ESubtreeMap " << subtrees.size() << " subtrees " << ", " << ambiguous_subtrees.size() << " ambiguous " << metablob; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EImportFinish.h0000664000175100017510000000237012623076744022446 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_EIMPORTFINISH_H #define CEPH_EIMPORTFINISH_H #include "common/config.h" #include "include/types.h" #include "../MDS.h" #include "../LogEvent.h" class EImportFinish : public LogEvent { protected: dirfrag_t base; // imported dir bool success; public: EImportFinish(CDir *dir, bool s) : LogEvent(EVENT_IMPORTFINISH), base(dir->dirfrag()), success(s) { } EImportFinish() : LogEvent(EVENT_IMPORTFINISH), base(), success(false) { } void print(ostream& out) const { out << "EImportFinish " << base; if (success) out << " success"; else out << " failed"; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/ESession.h0000664000175100017510000000333112623076744021454 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ESESSION_H #define CEPH_MDS_ESESSION_H #include "common/config.h" #include "include/types.h" #include "../LogEvent.h" class ESession : public LogEvent { protected: entity_inst_t client_inst; bool open; // open or close version_t cmapv; // client map version interval_set inos; version_t inotablev; public: ESession() : LogEvent(EVENT_SESSION), open(false) { } ESession(const entity_inst_t& inst, bool o, version_t v) : LogEvent(EVENT_SESSION), client_inst(inst), open(o), cmapv(v), inotablev(0) { } ESession(const entity_inst_t& inst, bool o, version_t v, const interval_set& i, version_t iv) : LogEvent(EVENT_SESSION), client_inst(inst), open(o), cmapv(v), inos(i), inotablev(iv) { } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void print(ostream& out) const { if (open) out << "ESession " << client_inst << " open cmapv " << cmapv; else out << "ESession " << client_inst << " close cmapv " << cmapv; if (inos.size()) out << " (" << inos.size() << " inos, v" << inotablev << ")"; } void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EResetJournal.h0000664000175100017510000000166512623076744022456 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ERESETJOURNAL_H #define CEPH_MDS_ERESETJOURNAL_H #include "../LogEvent.h" // generic log event class EResetJournal : public LogEvent { public: EResetJournal() : LogEvent(EVENT_RESETJOURNAL) { } ~EResetJournal() {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void print(ostream& out) const { out << "EResetJournal"; } void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EExport.h0000664000175100017510000000235112623076744021313 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_EEXPORT_H #define CEPH_EEXPORT_H #include "common/config.h" #include "include/types.h" #include "../MDS.h" #include "EMetaBlob.h" #include "../LogEvent.h" class EExport : public LogEvent { public: EMetaBlob metablob; // exported dir protected: dirfrag_t base; set bounds; public: EExport() : LogEvent(EVENT_EXPORT) { } EExport(MDLog *mdlog, CDir *dir) : LogEvent(EVENT_EXPORT), metablob(mdlog), base(dir->dirfrag()) { } set &get_bounds() { return bounds; } void print(ostream& out) const { out << "EExport " << base << " " << metablob; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EMetaBlob.h0000664000175100017510000004476412623076744021535 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_EMETABLOB_H #define CEPH_MDS_EMETABLOB_H #include #include "../CInode.h" #include "../CDir.h" #include "../CDentry.h" #include "include/triple.h" #include "include/interval_set.h" class MDS; class MDLog; class LogSegment; struct MDSlaveUpdate; /* * a bunch of metadata in the journal */ /* notes: * * - make sure you adjust the inode.version for any modified inode you * journal. CDir and CDentry maintain a projected_version, but CInode * doesn't, since the journaled inode usually has to be modifed * manually anyway (to delay the change in the MDS's cache until after * it is journaled). * */ class EMetaBlob { public: /* fullbit - a regular dentry + inode * * We encode this one a bit weirdly, just because (also, it's marginally faster * on multiple encodes, which I think can happen): * Encode a bufferlist on struct creation with all data members, without a struct_v. * When encode is called, encode struct_v and then append the bufferlist. * Decode straight into the appropriate variables. * * So, if you add members, encode them in the constructor and then change * the struct_v in the encode function! */ struct fullbit { static const int STATE_DIRTY = (1<<0); static const int STATE_DIRTYPARENT = (1<<1); static const int STATE_DIRTYPOOL = (1<<2); string dn; // dentry snapid_t dnfirst, dnlast; version_t dnv; inode_t inode; // if it's not fragtree_t dirfragtree; map xattrs; string symlink; bufferlist snapbl; __u8 state; typedef map old_inodes_t; old_inodes_t old_inodes; bufferlist _enc; fullbit(const fullbit& o); const fullbit& operator=(const fullbit& o); fullbit(const string& d, snapid_t df, snapid_t dl, version_t v, const inode_t& i, const fragtree_t &dft, const map &xa, const string& sym, const bufferlist &sbl, __u8 st, const old_inodes_t *oi = NULL) : //dn(d), dnfirst(df), dnlast(dl), dnv(v), //inode(i), dirfragtree(dft), xattrs(xa), symlink(sym), snapbl(sbl), dirty(dr) _enc(1024) { ::encode(d, _enc); ::encode(df, _enc); ::encode(dl, _enc); ::encode(v, _enc); ::encode(i, _enc); ::encode(xa, _enc); if (i.is_symlink()) ::encode(sym, _enc); if (i.is_dir()) { ::encode(dft, _enc); ::encode(sbl, _enc); } ::encode(st, _enc); ::encode(oi ? true : false, _enc); if (oi) ::encode(*oi, _enc); } fullbit(bufferlist::iterator &p) { decode(p); } fullbit() {} ~fullbit() {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void update_inode(MDS *mds, CInode *in); bool is_dirty() const { return (state & STATE_DIRTY); } bool is_dirty_parent() const { return (state & STATE_DIRTYPARENT); } bool is_dirty_pool() const { return (state & STATE_DIRTYPOOL); } void print(ostream& out) const { out << " fullbit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv << " inode " << inode.ino << " state=" << state << std::endl; } string state_string() const { string state_string; bool marked_already = false; if (is_dirty()) { state_string.append("dirty"); marked_already = true; } if (is_dirty_parent()) { state_string.append(marked_already ? "+dirty_parent" : "dirty_parent"); if (is_dirty_pool()) state_string.append("+dirty_pool"); } return state_string; } }; WRITE_CLASS_ENCODER(fullbit) /* remotebit - a dentry + remote inode link (i.e. just an ino) */ struct remotebit { string dn; snapid_t dnfirst, dnlast; version_t dnv; inodeno_t ino; unsigned char d_type; bool dirty; bufferlist _enc; remotebit(const string& d, snapid_t df, snapid_t dl, version_t v, inodeno_t i, unsigned char dt, bool dr) : //dn(d), dnfirst(df), dnlast(dl), dnv(v), ino(i), d_type(dt), dirty(dr) { } _enc(256) { ::encode(d, _enc); ::encode(df, _enc); ::encode(dl, _enc); ::encode(v, _enc); ::encode(i, _enc); ::encode(dt, _enc); ::encode(dr, _enc); } remotebit(bufferlist::iterator &p) { decode(p); } remotebit(): dnfirst(0), dnlast(0), dnv(0), ino(0), d_type('\0'), dirty(false) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void print(ostream& out) const { out << " remotebit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv << " ino " << ino << " dirty=" << dirty << std::endl; } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(remotebit) /* * nullbit - a null dentry */ struct nullbit { string dn; snapid_t dnfirst, dnlast; version_t dnv; bool dirty; bufferlist _enc; nullbit(const string& d, snapid_t df, snapid_t dl, version_t v, bool dr) : //dn(d), dnfirst(df), dnlast(dl), dnv(v), dirty(dr) { } _enc(128) { ::encode(d, _enc); ::encode(df, _enc); ::encode(dl, _enc); ::encode(v, _enc); ::encode(dr, _enc); } nullbit(bufferlist::iterator &p) { decode(p); } nullbit(): dnfirst(0), dnlast(0), dnv(0), dirty(false) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void print(ostream& out) { out << " nullbit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv << " dirty=" << dirty << std::endl; } }; WRITE_CLASS_ENCODER(nullbit) /* dirlump - contains metadata for any dir we have contents for. */ public: struct dirlump { static const int STATE_COMPLETE = (1<<1); static const int STATE_DIRTY = (1<<2); // dirty due to THIS journal item, that is! static const int STATE_NEW = (1<<3); // new directory static const int STATE_IMPORTING = (1<<4); // importing directory static const int STATE_DIRTYDFT = (1<<5); // dirty dirfragtree //version_t dirv; fnode_t fnode; __u32 state; __u32 nfull, nremote, nnull; private: mutable bufferlist dnbl; bool dn_decoded; list > dfull; list dremote; list dnull; public: dirlump() : state(0), nfull(0), nremote(0), nnull(0), dn_decoded(true) { } bool is_complete() const { return state & STATE_COMPLETE; } void mark_complete() { state |= STATE_COMPLETE; } bool is_dirty() const { return state & STATE_DIRTY; } void mark_dirty() { state |= STATE_DIRTY; } bool is_new() const { return state & STATE_NEW; } void mark_new() { state |= STATE_NEW; } bool is_importing() { return state & STATE_IMPORTING; } void mark_importing() { state |= STATE_IMPORTING; } bool is_dirty_dft() { return state & STATE_DIRTYDFT; } void mark_dirty_dft() { state |= STATE_DIRTYDFT; } list > &get_dfull() { return dfull; } list &get_dremote() { return dremote; } list &get_dnull() { return dnull; } void print(dirfrag_t dirfrag, ostream& out) { out << "dirlump " << dirfrag << " v " << fnode.version << " state " << state << " num " << nfull << "/" << nremote << "/" << nnull << std::endl; _decode_bits(); for (list >::iterator p = dfull.begin(); p != dfull.end(); ++p) (*p)->print(out); for (list::iterator p = dremote.begin(); p != dremote.end(); ++p) p->print(out); for (list::iterator p = dnull.begin(); p != dnull.end(); ++p) p->print(out); } string state_string() const { string state_string; bool marked_already = false; if (is_complete()) { state_string.append("complete"); marked_already = true; } if (is_dirty()) { state_string.append(marked_already ? "+dirty" : "dirty"); marked_already = true; } if (is_new()) { state_string.append(marked_already ? "+new" : "new"); } return state_string; } // if this changes, update the versioning in encode for it! void _encode_bits() const { if (!dn_decoded) return; ::encode(dfull, dnbl); ::encode(dremote, dnbl); ::encode(dnull, dnbl); } void _decode_bits() { if (dn_decoded) return; bufferlist::iterator p = dnbl.begin(); ::decode(dfull, p); ::decode(dremote, p); ::decode(dnull, p); dn_decoded = true; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(dirlump) private: // my lumps. preserve the order we added them in a list. list lump_order; map lump_map; list > roots; list > table_tids; // tableclient transactions inodeno_t opened_ino; public: inodeno_t renamed_dirino; list renamed_dir_frags; private: // ino (pre)allocation. may involve both inotable AND session state. version_t inotablev, sessionmapv; inodeno_t allocated_ino; // inotable interval_set preallocated_inos; // inotable + session inodeno_t used_preallocated_ino; // session entity_name_t client_name; // session // inodes i've truncated list truncate_start; // start truncate map truncate_finish; // finished truncate (started in segment blah) vector destroyed_inodes; // idempotent op(s) list > client_reqs; public: void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); // soft stateadd uint64_t last_subtree_map; uint64_t my_offset; // for replay, in certain cases //LogSegment *_segment; EMetaBlob(MDLog *mdl = 0); // defined in journal.cc ~EMetaBlob() { } void print(ostream& out) { for (list::iterator p = lump_order.begin(); p != lump_order.end(); ++p) { lump_map[*p].print(*p, out); } } void add_client_req(metareqid_t r, uint64_t tid=0) { client_reqs.push_back(pair(r, tid)); } void add_table_transaction(int table, version_t tid) { table_tids.push_back(pair<__u8, version_t>(table, tid)); } void add_opened_ino(inodeno_t ino) { assert(!opened_ino); opened_ino = ino; } void set_ino_alloc(inodeno_t alloc, inodeno_t used_prealloc, interval_set& prealloc, entity_name_t client, version_t sv, version_t iv) { allocated_ino = alloc; used_preallocated_ino = used_prealloc; preallocated_inos = prealloc; client_name = client; sessionmapv = sv; inotablev = iv; } void add_truncate_start(inodeno_t ino) { truncate_start.push_back(ino); } void add_truncate_finish(inodeno_t ino, uint64_t segoff) { truncate_finish[ino] = segoff; } void add_destroyed_inode(inodeno_t ino) { destroyed_inodes.push_back(ino); } void add_null_dentry(CDentry *dn, bool dirty) { add_null_dentry(add_dir(dn->get_dir(), false), dn, dirty); } void add_null_dentry(dirlump& lump, CDentry *dn, bool dirty) { // add the dir lump.nnull++; lump.get_dnull().push_back(nullbit(dn->get_name(), dn->first, dn->last, dn->get_projected_version(), dirty)); } void add_remote_dentry(CDentry *dn, bool dirty) { add_remote_dentry(add_dir(dn->get_dir(), false), dn, dirty, 0, 0); } void add_remote_dentry(CDentry *dn, bool dirty, inodeno_t rino, int rdt) { add_remote_dentry(add_dir(dn->get_dir(), false), dn, dirty, rino, rdt); } void add_remote_dentry(dirlump& lump, CDentry *dn, bool dirty, inodeno_t rino=0, unsigned char rdt=0) { if (!rino) { rino = dn->get_projected_linkage()->get_remote_ino(); rdt = dn->get_projected_linkage()->get_remote_d_type(); } lump.nremote++; lump.get_dremote().push_back(remotebit(dn->get_name(), dn->first, dn->last, dn->get_projected_version(), rino, rdt, dirty)); } // return remote pointer to to-be-journaled inode void add_primary_dentry(CDentry *dn, CInode *in, bool dirty, bool dirty_parent=false, bool dirty_pool=false) { __u8 state = 0; if (dirty) state |= fullbit::STATE_DIRTY; if (dirty_parent) state |= fullbit::STATE_DIRTYPARENT; if (dirty_pool) state |= fullbit::STATE_DIRTYPOOL; add_primary_dentry(add_dir(dn->get_dir(), false), dn, in, state); } void add_primary_dentry(dirlump& lump, CDentry *dn, CInode *in, __u8 state) { if (!in) in = dn->get_projected_linkage()->get_inode(); // make note of where this inode was last journaled in->last_journaled = my_offset; //cout << "journaling " << in->inode.ino << " at " << my_offset << std::endl; inode_t *pi = in->get_projected_inode(); if ((state & fullbit::STATE_DIRTY) && pi->is_backtrace_updated()) state |= fullbit::STATE_DIRTYPARENT; bufferlist snapbl; sr_t *sr = in->get_projected_srnode(); if (sr) sr->encode(snapbl); lump.nfull++; lump.get_dfull().push_back(ceph::shared_ptr(new fullbit(dn->get_name(), dn->first, dn->last, dn->get_projected_version(), *pi, in->dirfragtree, *in->get_projected_xattrs(), in->symlink, snapbl, state, &in->old_inodes))); } // convenience: primary or remote? figure it out. void add_dentry(CDentry *dn, bool dirty) { dirlump& lump = add_dir(dn->get_dir(), false); add_dentry(lump, dn, dirty, false, false); } void add_import_dentry(CDentry *dn) { bool dirty_parent = false; bool dirty_pool = false; if (dn->get_linkage()->is_primary()) { dirty_parent = dn->get_linkage()->get_inode()->is_dirty_parent(); dirty_pool = dn->get_linkage()->get_inode()->is_dirty_pool(); } dirlump& lump = add_dir(dn->get_dir(), false); add_dentry(lump, dn, dn->is_dirty(), dirty_parent, dirty_pool); } void add_dentry(dirlump& lump, CDentry *dn, bool dirty, bool dirty_parent, bool dirty_pool) { // primary or remote if (dn->get_projected_linkage()->is_remote()) { add_remote_dentry(dn, dirty); return; } else if (dn->get_projected_linkage()->is_null()) { add_null_dentry(dn, dirty); return; } assert(dn->get_projected_linkage()->is_primary()); add_primary_dentry(dn, 0, dirty, dirty_parent, dirty_pool); } void add_root(bool dirty, CInode *in, inode_t *pi=0, fragtree_t *pdft=0, bufferlist *psnapbl=0, map *px=0) { in->last_journaled = my_offset; //cout << "journaling " << in->inode.ino << " at " << my_offset << std::endl; if (!pi) pi = in->get_projected_inode(); if (!pdft) pdft = &in->dirfragtree; if (!px) px = in->get_projected_xattrs(); bufferlist snapbl; if (psnapbl) snapbl = *psnapbl; else in->encode_snap_blob(snapbl); for (list >::iterator p = roots.begin(); p != roots.end(); ++p) { if ((*p)->inode.ino == in->ino()) { roots.erase(p); break; } } string empty; roots.push_back(ceph::shared_ptr(new fullbit(empty, in->first, in->last, 0, *pi, *pdft, *px, in->symlink, snapbl, dirty ? fullbit::STATE_DIRTY : 0, &in->old_inodes))); } dirlump& add_dir(CDir *dir, bool dirty, bool complete=false) { return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(), dirty, complete); } dirlump& add_new_dir(CDir *dir) { return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(), true, true, true); // dirty AND complete AND new } dirlump& add_import_dir(CDir *dir) { // dirty=false would be okay in some cases return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(), dir->is_dirty(), dir->is_complete(), false, true, dir->is_dirty_dft()); } dirlump& add_fragmented_dir(CDir *dir, bool dirty, bool dirtydft) { return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(), dirty, false, false, false, dirtydft); } dirlump& add_dir(dirfrag_t df, fnode_t *pf, version_t pv, bool dirty, bool complete=false, bool isnew=false, bool importing=false, bool dirty_dft=false) { if (lump_map.count(df) == 0) lump_order.push_back(df); dirlump& l = lump_map[df]; l.fnode = *pf; l.fnode.version = pv; if (complete) l.mark_complete(); if (dirty) l.mark_dirty(); if (isnew) l.mark_new(); if (importing) l.mark_importing(); if (dirty_dft) l.mark_dirty_dft(); return l; } static const int TO_AUTH_SUBTREE_ROOT = 0; // default. static const int TO_ROOT = 1; void add_dir_context(CDir *dir, int mode = TO_AUTH_SUBTREE_ROOT); void print(ostream& out) const { out << "[metablob"; if (!lump_order.empty()) out << " " << lump_order.front() << ", " << lump_map.size() << " dirs"; if (!table_tids.empty()) out << " table_tids=" << table_tids; if (allocated_ino || preallocated_inos.size()) { if (allocated_ino) out << " alloc_ino=" << allocated_ino; if (preallocated_inos.size()) out << " prealloc_ino=" << preallocated_inos; if (used_preallocated_ino) out << " used_prealloc_ino=" << used_preallocated_ino; out << " v" << inotablev; } out << "]"; } void update_segment(LogSegment *ls); void replay(MDS *mds, LogSegment *ls, MDSlaveUpdate *su=NULL); }; WRITE_CLASS_ENCODER(EMetaBlob) WRITE_CLASS_ENCODER(EMetaBlob::fullbit) WRITE_CLASS_ENCODER(EMetaBlob::remotebit) WRITE_CLASS_ENCODER(EMetaBlob::nullbit) WRITE_CLASS_ENCODER(EMetaBlob::dirlump) inline ostream& operator<<(ostream& out, const EMetaBlob& t) { t.print(out); return out; } #endif ceph-0.80.11/src/mds/events/EOpen.h0000664000175100017510000000255412623076744020740 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_EOPEN_H #define CEPH_MDS_EOPEN_H #include "../LogEvent.h" #include "EMetaBlob.h" class EOpen : public LogEvent { public: EMetaBlob metablob; vector inos; EOpen() : LogEvent(EVENT_OPEN) { } EOpen(MDLog *mdlog) : LogEvent(EVENT_OPEN), metablob(mdlog) { } void print(ostream& out) const { out << "EOpen " << metablob << ", " << inos.size() << " open files"; } void add_clean_inode(CInode *in) { if (!in->is_base()) { metablob.add_dir_context(in->get_projected_parent_dn()->get_dir()); metablob.add_primary_dentry(in->get_projected_parent_dn(), 0, false); inos.push_back(in->ino()); } } void add_ino(inodeno_t ino) { inos.push_back(ino); } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/ECommitted.h0000664000175100017510000000202112623076744021751 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ECOMMITTED_H #define CEPH_MDS_ECOMMITTED_H #include "../LogEvent.h" #include "EMetaBlob.h" class ECommitted : public LogEvent { public: metareqid_t reqid; ECommitted() : LogEvent(EVENT_COMMITTED) { } ECommitted(metareqid_t r) : LogEvent(EVENT_COMMITTED), reqid(r) { } void print(ostream& out) const { out << "ECommitted " << reqid; } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void update_segment() {} void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EFragment.h0000664000175100017510000000407712623076744021604 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_EFRAGMENT_H #define CEPH_MDS_EFRAGMENT_H #include "../LogEvent.h" #include "EMetaBlob.h" struct dirfrag_rollback { fnode_t fnode; dirfrag_rollback() { } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); }; WRITE_CLASS_ENCODER(dirfrag_rollback) class EFragment : public LogEvent { public: EMetaBlob metablob; __u8 op; inodeno_t ino; frag_t basefrag; __s32 bits; // positive for split (from basefrag), negative for merge (to basefrag) list orig_frags; bufferlist rollback; EFragment() : LogEvent(EVENT_FRAGMENT) { } EFragment(MDLog *mdlog, int o, dirfrag_t df, int b) : LogEvent(EVENT_FRAGMENT), metablob(mdlog), op(o), ino(df.ino), basefrag(df.frag), bits(b) { } void print(ostream& out) const { out << "EFragment " << op_name(op) << " " << ino << " " << basefrag << " by " << bits << " " << metablob; } enum { OP_PREPARE = 1, OP_COMMIT = 2, OP_ROLLBACK = 3, OP_FINISH = 4, // finish deleting orphan dirfrags OP_ONESHOT = 5, // (legacy) PREPARE+COMMIT }; static const char *op_name(int o) { switch (o) { case OP_PREPARE: return "prepare"; case OP_COMMIT: return "commit"; case OP_ROLLBACK: return "rollback"; case OP_FINISH: return "finish"; default: return "???"; } } void add_orig_frag(frag_t df, dirfrag_rollback *drb=NULL) { orig_frags.push_back(df); if (drb) ::encode(*drb, rollback); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/ETableServer.h0000664000175100017510000000323312623076744022250 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ETABLESERVER_H #define CEPH_MDS_ETABLESERVER_H #include "common/config.h" #include "include/types.h" #include "../mds_table_types.h" #include "../LogEvent.h" struct ETableServer : public LogEvent { __u16 table; __s16 op; uint64_t reqid; __s32 bymds; bufferlist mutation; version_t tid; version_t version; ETableServer() : LogEvent(EVENT_TABLESERVER), table(0), op(0), reqid(0), bymds(0), tid(0), version(0) { } ETableServer(int t, int o, uint64_t ri, int m, version_t ti, version_t v) : LogEvent(EVENT_TABLESERVER), table(t), op(o), reqid(ri), bymds(m), tid(ti), version(v) { } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void print(ostream& out) const { out << "ETableServer " << get_mdstable_name(table) << " " << get_mdstableserver_opname(op); if (reqid) out << " reqid " << reqid; if (bymds >= 0) out << " mds." << bymds; if (tid) out << " tid " << tid; if (version) out << " version " << version; if (mutation.length()) out << " mutation=" << mutation.length() << " bytes"; } void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EUpdate.h0000664000175100017510000000235212623076744021255 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_EUPDATE_H #define CEPH_MDS_EUPDATE_H #include "../LogEvent.h" #include "EMetaBlob.h" class EUpdate : public LogEvent { public: EMetaBlob metablob; string type; bufferlist client_map; version_t cmapv; metareqid_t reqid; bool had_slaves; EUpdate() : LogEvent(EVENT_UPDATE), cmapv(0), had_slaves(false) { } EUpdate(MDLog *mdlog, const char *s) : LogEvent(EVENT_UPDATE), metablob(mdlog), type(s), cmapv(0), had_slaves(false) { } void print(ostream& out) const { if (type.length()) out << "EUpdate " << type << " "; out << metablob; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/ETableClient.h0000664000175100017510000000241712623076744022223 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ETABLECLIENT_H #define CEPH_MDS_ETABLECLIENT_H #include "common/config.h" #include "include/types.h" #include "../mds_table_types.h" #include "../LogEvent.h" struct ETableClient : public LogEvent { __u16 table; __s16 op; version_t tid; ETableClient() : LogEvent(EVENT_TABLECLIENT), table(0), op(0), tid(0) { } ETableClient(int t, int o, version_t ti) : LogEvent(EVENT_TABLECLIENT), table(t), op(o), tid(ti) { } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void print(ostream& out) const { out << "ETableClient " << get_mdstable_name(table) << " " << get_mdstableserver_opname(op); if (tid) out << " tid " << tid; } //void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/ESessions.h0000664000175100017510000000300612623076744021636 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ESESSIONS_H #define CEPH_MDS_ESESSIONS_H #include "common/config.h" #include "include/types.h" #include "../LogEvent.h" class ESessions : public LogEvent { protected: version_t cmapv; // client map version public: map client_map; bool old_style_encode; ESessions() : LogEvent(EVENT_SESSIONS), old_style_encode(false) { } ESessions(version_t pv, map& cm) : LogEvent(EVENT_SESSIONS), cmapv(pv), old_style_encode(false) { client_map.swap(cm); } void mark_old_encoding() { old_style_encode = true; } void encode(bufferlist &bl) const; void decode_old(bufferlist::iterator &bl); void decode_new(bufferlist::iterator &bl); void decode(bufferlist::iterator &bl) { if (old_style_encode) decode_old(bl); else decode_new(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); void print(ostream& out) const { out << "ESessions " << client_map.size() << " opens cmapv " << cmapv; } void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/EImportStart.h0000664000175100017510000000255012623076744022323 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_EIMPORTSTART_H #define CEPH_EIMPORTSTART_H #include "common/config.h" #include "include/types.h" #include "../MDS.h" #include "EMetaBlob.h" #include "../LogEvent.h" class EImportStart : public LogEvent { protected: dirfrag_t base; vector bounds; public: EMetaBlob metablob; bufferlist client_map; // encoded map<__u32,entity_inst_t> version_t cmapv; EImportStart(MDLog *log, dirfrag_t di, vector& b) : LogEvent(EVENT_IMPORTSTART), base(di), bounds(b), metablob(log) { } EImportStart() : LogEvent(EVENT_IMPORTSTART) { } void print(ostream& out) const { out << "EImportStart " << base << " " << metablob; } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void update_segment(); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/events/ESlaveUpdate.h0000664000175100017510000001010112623076744022237 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_ESLAVEUPDATE_H #define CEPH_MDS_ESLAVEUPDATE_H #include "../LogEvent.h" #include "EMetaBlob.h" /* * rollback records, for remote/slave updates, which may need to be manually * rolled back during journal replay. (or while active if master fails, but in * that case these records aren't needed.) */ struct link_rollback { metareqid_t reqid; inodeno_t ino; bool was_inc; utime_t old_ctime; utime_t old_dir_mtime; utime_t old_dir_rctime; link_rollback() : ino(0), was_inc(false) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(link_rollback) /* * this is only used on an empty dir with a dirfrag on a remote node. * we are auth for nothing. all we need to do is relink the directory * in the hierarchy properly during replay to avoid breaking the * subtree map. */ struct rmdir_rollback { metareqid_t reqid; dirfrag_t src_dir; string src_dname; dirfrag_t dest_dir; string dest_dname; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(rmdir_rollback) struct rename_rollback { struct drec { dirfrag_t dirfrag; utime_t dirfrag_old_mtime; utime_t dirfrag_old_rctime; inodeno_t ino, remote_ino; string dname; char remote_d_type; utime_t old_ctime; drec() : remote_d_type((char)S_IFREG) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_MEMBER_ENCODER(drec) metareqid_t reqid; drec orig_src, orig_dest; drec stray; // we know this is null, but we want dname, old mtime/rctime utime_t ctime; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(rename_rollback) class ESlaveUpdate : public LogEvent { public: const static int OP_PREPARE = 1; const static int OP_COMMIT = 2; const static int OP_ROLLBACK = 3; const static int LINK = 1; const static int RENAME = 2; const static int RMDIR = 3; /* * we journal a rollback metablob that contains the unmodified metadata * too, because we may be updating previously dirty metadata, which * will allow old log segments to be trimmed. if we end of rolling back, * those updates could be lost.. so we re-journal the unmodified metadata, * and replay will apply _either_ commit or rollback. */ EMetaBlob commit; bufferlist rollback; string type; metareqid_t reqid; __s32 master; __u8 op; // prepare, commit, abort __u8 origop; // link | rename ESlaveUpdate() : LogEvent(EVENT_SLAVEUPDATE), master(0), op(0), origop(0) { } ESlaveUpdate(MDLog *mdlog, const char *s, metareqid_t ri, int mastermds, int o, int oo) : LogEvent(EVENT_SLAVEUPDATE), commit(mdlog), type(s), reqid(ri), master(mastermds), op(o), origop(oo) { } void print(ostream& out) const { if (type.length()) out << type << " "; out << " " << (int)op; if (origop == LINK) out << " link"; if (origop == RENAME) out << " rename"; out << " " << reqid; out << " for mds." << master; out << commit; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); void replay(MDS *mds); }; #endif ceph-0.80.11/src/mds/MDSTableServer.h0000664000175100017510000000533712623076744021212 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSTABLESERVER_H #define CEPH_MDSTABLESERVER_H #include "MDSTable.h" class MMDSTableRequest; class MDSTableServer : public MDSTable { public: int table; map pending_for_mds; // ** child should encode this! ** private: void handle_prepare(MMDSTableRequest *m); void _prepare_logged(MMDSTableRequest *m, version_t tid); struct C_Prepare : public Context { MDSTableServer *server; MMDSTableRequest *req; version_t tid; C_Prepare(MDSTableServer *s, MMDSTableRequest *r, version_t v) : server(s), req(r), tid(v) {} void finish(int r) { server->_prepare_logged(req, tid); } }; void handle_commit(MMDSTableRequest *m); void _commit_logged(MMDSTableRequest *m); struct C_Commit : public Context { MDSTableServer *server; MMDSTableRequest *req; C_Commit(MDSTableServer *s, MMDSTableRequest *r) : server(s), req(r) {} void finish(int r) { server->_commit_logged(req); } }; void handle_rollback(MMDSTableRequest *m); public: virtual void handle_query(MMDSTableRequest *m) = 0; virtual void _prepare(bufferlist &bl, uint64_t reqid, int bymds) = 0; virtual bool _commit(version_t tid, MMDSTableRequest *req=NULL) = 0; virtual void _rollback(version_t tid) = 0; virtual void _server_update(bufferlist& bl) { assert(0); } void _note_prepare(int mds, uint64_t reqid) { pending_for_mds[version].mds = mds; pending_for_mds[version].reqid = reqid; pending_for_mds[version].tid = version; } void _note_commit(uint64_t tid) { pending_for_mds.erase(tid); } void _note_rollback(uint64_t tid) { pending_for_mds.erase(tid); } MDSTableServer(MDS *m, int tab) : MDSTable(m, get_mdstable_name(tab), false), table(tab) {} virtual ~MDSTableServer() {} void handle_request(MMDSTableRequest *m); void do_server_update(bufferlist& bl); virtual void encode_server_state(bufferlist& bl) const = 0; virtual void decode_server_state(bufferlist::iterator& bl) = 0; void encode_state(bufferlist& bl) const { encode_server_state(bl); ::encode(pending_for_mds, bl); } void decode_state(bufferlist::iterator& bl) { decode_server_state(bl); ::decode(pending_for_mds, bl); } // recovery void finish_recovery(set& active); void handle_mds_recovery(int who); }; #endif ceph-0.80.11/src/mds/MDLog.cc0000664000175100017510000004347112623076744017531 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDLog.h" #include "MDS.h" #include "MDCache.h" #include "LogEvent.h" #include "osdc/Journaler.h" #include "common/entity_name.h" #include "common/perf_counters.h" #include "events/ESubtreeMap.h" #include "common/config.h" #include "common/errno.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef DOUT_COND #define DOUT_COND(cct, l) l<=cct->_conf->debug_mds || l <= cct->_conf->debug_mds_log #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".log " // cons/des MDLog::~MDLog() { if (journaler) { delete journaler; journaler = 0; } if (logger) { g_ceph_context->get_perfcounters_collection()->remove(logger); delete logger; logger = 0; } } void MDLog::create_logger() { PerfCountersBuilder plb(g_ceph_context, "mds_log", l_mdl_first, l_mdl_last); plb.add_u64_counter(l_mdl_evadd, "evadd"); plb.add_u64_counter(l_mdl_evex, "evex"); plb.add_u64_counter(l_mdl_evtrm, "evtrm"); plb.add_u64(l_mdl_ev, "ev"); plb.add_u64(l_mdl_evexg, "evexg"); plb.add_u64(l_mdl_evexd, "evexd"); plb.add_u64_counter(l_mdl_segadd, "segadd"); plb.add_u64_counter(l_mdl_segex, "segex"); plb.add_u64_counter(l_mdl_segtrm, "segtrm"); plb.add_u64(l_mdl_seg, "seg"); plb.add_u64(l_mdl_segexg, "segexg"); plb.add_u64(l_mdl_segexd, "segexd"); plb.add_u64(l_mdl_expos, "expos"); plb.add_u64(l_mdl_wrpos, "wrpos"); plb.add_u64(l_mdl_rdpos, "rdpos"); plb.add_u64(l_mdl_jlat, "jlat"); // logger logger = plb.create_perf_counters(); g_ceph_context->get_perfcounters_collection()->add(logger); } void MDLog::init_journaler() { // inode ino = MDS_INO_LOG_OFFSET + mds->get_nodeid(); // log streamer if (journaler) delete journaler; journaler = new Journaler(ino, mds->mdsmap->get_metadata_pool(), CEPH_FS_ONDISK_MAGIC, mds->objecter, logger, l_mdl_jlat, &mds->timer); assert(journaler->is_readonly()); journaler->set_write_error_handler(new C_MDL_WriteError(this)); } void MDLog::handle_journaler_write_error(int r) { if (r == -EBLACKLISTED) { derr << "we have been blacklisted (fenced), respawning..." << dendl; mds->respawn(); } else { derr << "unhandled error " << cpp_strerror(r) << ", shutting down..." << dendl; mds->suicide(); } } void MDLog::write_head(Context *c) { journaler->write_head(c); } uint64_t MDLog::get_read_pos() { return journaler->get_read_pos(); } uint64_t MDLog::get_write_pos() { return journaler->get_write_pos(); } uint64_t MDLog::get_safe_pos() { return journaler->get_write_safe_pos(); } void MDLog::create(Context *c) { dout(5) << "create empty log" << dendl; init_journaler(); journaler->set_writeable(); journaler->create(&mds->mdcache->default_log_layout); journaler->write_head(c); logger->set(l_mdl_expos, journaler->get_expire_pos()); logger->set(l_mdl_wrpos, journaler->get_write_pos()); } void MDLog::open(Context *c) { dout(5) << "open discovering log bounds" << dendl; init_journaler(); journaler->recover(c); // either append() or replay() will follow. } void MDLog::append() { dout(5) << "append positioning at end and marking writeable" << dendl; journaler->set_read_pos(journaler->get_write_pos()); journaler->set_expire_pos(journaler->get_write_pos()); journaler->set_writeable(); logger->set(l_mdl_expos, journaler->get_write_pos()); } // ------------------------------------------------- void MDLog::start_entry(LogEvent *e) { assert(cur_event == NULL); cur_event = e; e->set_start_off(get_write_pos()); } void MDLog::submit_entry(LogEvent *le, Context *c) { assert(!mds->is_any_replay()); assert(le == cur_event); cur_event = NULL; if (!g_conf->mds_log) { // hack: log is disabled. if (c) { c->complete(0); } return; } // let the event register itself in the segment assert(!segments.empty()); le->_segment = segments.rbegin()->second; le->_segment->num_events++; le->update_segment(); le->set_stamp(ceph_clock_now(g_ceph_context)); num_events++; assert(!capped); // encode it, with event type { bufferlist bl; le->encode_with_header(bl); dout(5) << "submit_entry " << journaler->get_write_pos() << "~" << bl.length() << " : " << *le << dendl; // journal it. journaler->append_entry(bl); // bl is destroyed. } le->_segment->end = journaler->get_write_pos(); if (logger) { logger->inc(l_mdl_evadd); logger->set(l_mdl_ev, num_events); logger->set(l_mdl_wrpos, journaler->get_write_pos()); } unflushed++; if (c) journaler->wait_for_flush(c); // start a new segment? // FIXME: should this go elsewhere? uint64_t last_seg = get_last_segment_offset(); uint64_t period = journaler->get_layout_period(); // start a new segment if there are none or if we reach end of last segment if (le->get_type() == EVENT_SUBTREEMAP || (le->get_type() == EVENT_IMPORTFINISH && mds->is_resolve())) { // avoid infinite loop when ESubtreeMap is very large. // don not insert ESubtreeMap among EImportFinish events that finish // disambiguate imports. Because the ESubtreeMap reflects the subtree // state when all EImportFinish events are replayed. } else if (journaler->get_write_pos()/period != last_seg/period) { dout(10) << "submit_entry also starting new segment: last = " << last_seg << ", cur pos = " << journaler->get_write_pos() << dendl; start_new_segment(); } else if (g_conf->mds_debug_subtrees && le->get_type() != EVENT_SUBTREEMAP_TEST) { // debug: journal this every time to catch subtree replay bugs. // use a different event id so it doesn't get interpreted as a // LogSegment boundary on replay. LogEvent *sle = mds->mdcache->create_subtree_map(); sle->set_type(EVENT_SUBTREEMAP_TEST); submit_entry(sle); } delete le; } void MDLog::wait_for_safe(Context *c) { if (g_conf->mds_log) { // wait journaler->wait_for_flush(c); } else { // hack: bypass. c->complete(0); } } void MDLog::flush() { if (unflushed) journaler->flush(); unflushed = 0; } void MDLog::cap() { dout(5) << "cap" << dendl; capped = true; } // ----------------------------- // segments void MDLog::start_new_segment(Context *onsync) { prepare_new_segment(); journal_segment_subtree_map(); if (onsync) { wait_for_safe(onsync); flush(); } } void MDLog::prepare_new_segment() { dout(7) << __func__ << " at " << journaler->get_write_pos() << dendl; segments[journaler->get_write_pos()] = new LogSegment(journaler->get_write_pos()); logger->inc(l_mdl_segadd); logger->set(l_mdl_seg, segments.size()); // Adjust to next stray dir dout(10) << "Advancing to next stray directory on mds " << mds->get_nodeid() << dendl; mds->mdcache->advance_stray(); } void MDLog::journal_segment_subtree_map() { dout(7) << __func__ << dendl; submit_entry(mds->mdcache->create_subtree_map()); } void MDLog::trim(int m) { int max_segments = g_conf->mds_log_max_segments; int max_events = g_conf->mds_log_max_events; if (m >= 0) max_events = m; // trim! dout(10) << "trim " << segments.size() << " / " << max_segments << " segments, " << num_events << " / " << max_events << " events" << ", " << expiring_segments.size() << " (" << expiring_events << ") expiring" << ", " << expired_segments.size() << " (" << expired_events << ") expired" << dendl; if (segments.empty()) return; // hack: only trim for a few seconds at a time utime_t stop = ceph_clock_now(g_ceph_context); stop += 2.0; map::iterator p = segments.begin(); while (p != segments.end() && ((max_events >= 0 && num_events - expiring_events - expired_events > max_events) || (max_segments >= 0 && segments.size() - expiring_segments.size() - expired_segments.size() > (unsigned)max_segments))) { if (stop < ceph_clock_now(g_ceph_context)) break; int num_expiring_segments = (int)expiring_segments.size(); if (num_expiring_segments >= g_conf->mds_log_max_expiring) break; int op_prio = CEPH_MSG_PRIO_LOW + (CEPH_MSG_PRIO_HIGH - CEPH_MSG_PRIO_LOW) * num_expiring_segments / g_conf->mds_log_max_expiring; // look at first segment LogSegment *ls = p->second; assert(ls); ++p; if (ls->end > journaler->get_write_safe_pos()) { dout(5) << "trim segment " << ls->offset << ", not fully flushed yet, safe " << journaler->get_write_safe_pos() << " < end " << ls->end << dendl; break; } if (expiring_segments.count(ls)) { dout(5) << "trim already expiring segment " << ls->offset << ", " << ls->num_events << " events" << dendl; } else if (expired_segments.count(ls)) { dout(5) << "trim already expired segment " << ls->offset << ", " << ls->num_events << " events" << dendl; } else { try_expire(ls, op_prio); } } // discard expired segments _trim_expired_segments(); } void MDLog::try_expire(LogSegment *ls, int op_prio) { C_GatherBuilder gather_bld(g_ceph_context); ls->try_to_expire(mds, gather_bld, op_prio); if (gather_bld.has_subs()) { assert(expiring_segments.count(ls) == 0); expiring_segments.insert(ls); expiring_events += ls->num_events; dout(5) << "try_expire expiring segment " << ls->offset << dendl; gather_bld.set_finisher(new C_MaybeExpiredSegment(this, ls, op_prio)); gather_bld.activate(); } else { dout(10) << "try_expire expired segment " << ls->offset << dendl; _expired(ls); } logger->set(l_mdl_segexg, expiring_segments.size()); logger->set(l_mdl_evexg, expiring_events); } void MDLog::_maybe_expired(LogSegment *ls, int op_prio) { dout(10) << "_maybe_expired segment " << ls->offset << " " << ls->num_events << " events" << dendl; assert(expiring_segments.count(ls)); expiring_segments.erase(ls); expiring_events -= ls->num_events; try_expire(ls, op_prio); } void MDLog::_trim_expired_segments() { // trim expired segments? bool trimmed = false; while (!segments.empty()) { LogSegment *ls = segments.begin()->second; if (!expired_segments.count(ls)) { dout(10) << "_trim_expired_segments waiting for " << ls->offset << " to expire" << dendl; break; } dout(10) << "_trim_expired_segments trimming expired " << ls->offset << dendl; expired_events -= ls->num_events; expired_segments.erase(ls); num_events -= ls->num_events; // this was the oldest segment, adjust expire pos if (journaler->get_expire_pos() < ls->offset) journaler->set_expire_pos(ls->offset); logger->set(l_mdl_expos, ls->offset); logger->inc(l_mdl_segtrm); logger->inc(l_mdl_evtrm, ls->num_events); segments.erase(ls->offset); delete ls; trimmed = true; } if (trimmed) journaler->write_head(0); } void MDLog::_expired(LogSegment *ls) { dout(5) << "_expired segment " << ls->offset << " " << ls->num_events << " events" << dendl; if (!capped && ls == peek_current_segment()) { dout(5) << "_expired not expiring " << ls->offset << ", last one and !capped" << dendl; } else { // expired. expired_segments.insert(ls); expired_events += ls->num_events; logger->inc(l_mdl_evex, ls->num_events); logger->inc(l_mdl_segex); } logger->set(l_mdl_ev, num_events); logger->set(l_mdl_evexd, expired_events); logger->set(l_mdl_seg, segments.size()); logger->set(l_mdl_segexd, expired_segments.size()); } void MDLog::replay(Context *c) { assert(journaler->is_active()); assert(journaler->is_readonly()); // empty? if (journaler->get_read_pos() == journaler->get_write_pos()) { dout(10) << "replay - journal empty, done." << dendl; if (c) { c->complete(0); } return; } // add waiter if (c) waitfor_replay.push_back(c); // go! dout(10) << "replay start, from " << journaler->get_read_pos() << " to " << journaler->get_write_pos() << dendl; assert(num_events == 0 || already_replayed); already_replayed = true; replay_thread.create(); replay_thread.detach(); } class C_MDL_Replay : public Context { MDLog *mdlog; public: C_MDL_Replay(MDLog *l) : mdlog(l) {} void finish(int r) { mdlog->replay_cond.Signal(); } }; // i am a separate thread void MDLog::_replay_thread() { mds->mds_lock.Lock(); dout(10) << "_replay_thread start" << dendl; // loop int r = 0; while (1) { // wait for read? while (!journaler->is_readable() && journaler->get_read_pos() < journaler->get_write_pos() && !journaler->get_error()) { journaler->wait_for_readable(new C_MDL_Replay(this)); replay_cond.Wait(mds->mds_lock); } if (journaler->get_error()) { r = journaler->get_error(); dout(0) << "_replay journaler got error " << r << ", aborting" << dendl; if (r == -ENOENT) { // journal has been trimmed by somebody else? assert(journaler->is_readonly()); r = -EAGAIN; } else if (r == -EINVAL) { if (journaler->get_read_pos() < journaler->get_expire_pos()) { // this should only happen if you're following somebody else assert(journaler->is_readonly()); dout(0) << "expire_pos is higher than read_pos, returning EAGAIN" << dendl; r = -EAGAIN; } else { /* re-read head and check it * Given that replay happens in a separate thread and * the MDS is going to either shut down or restart when * we return this error, doing it synchronously is fine * -- as long as we drop the main mds lock--. */ Mutex mylock("MDLog::_replay_thread lock"); Cond cond; bool done = false; int err = 0; journaler->reread_head(new C_SafeCond(&mylock, &cond, &done, &err)); mds->mds_lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); if (err) { // well, crap dout(0) << "got error while reading head: " << cpp_strerror(err) << dendl; mds->suicide(); } mds->mds_lock.Lock(); standby_trim_segments(); if (journaler->get_read_pos() < journaler->get_expire_pos()) { dout(0) << "expire_pos is higher than read_pos, returning EAGAIN" << dendl; r = -EAGAIN; } } } break; } if (!journaler->is_readable() && journaler->get_read_pos() == journaler->get_write_pos()) break; assert(journaler->is_readable()); // read it uint64_t pos = journaler->get_read_pos(); bufferlist bl; bool r = journaler->try_read_entry(bl); if (!r && journaler->get_error()) continue; assert(r); // unpack event LogEvent *le = LogEvent::decode(bl); if (!le) { dout(0) << "_replay " << pos << "~" << bl.length() << " / " << journaler->get_write_pos() << " -- unable to decode event" << dendl; dout(0) << "dump of unknown or corrupt event:\n"; bl.hexdump(*_dout); *_dout << dendl; assert(!!"corrupt log event" == g_conf->mds_log_skip_corrupt_events); continue; } le->set_start_off(pos); // new segment? if (le->get_type() == EVENT_SUBTREEMAP || le->get_type() == EVENT_RESETJOURNAL) { segments[pos] = new LogSegment(pos); logger->set(l_mdl_seg, segments.size()); } // have we seen an import map yet? if (segments.empty()) { dout(10) << "_replay " << pos << "~" << bl.length() << " / " << journaler->get_write_pos() << " " << le->get_stamp() << " -- waiting for subtree_map. (skipping " << *le << ")" << dendl; } else { dout(10) << "_replay " << pos << "~" << bl.length() << " / " << journaler->get_write_pos() << " " << le->get_stamp() << ": " << *le << dendl; le->_segment = get_current_segment(); // replay may need this le->_segment->num_events++; le->_segment->end = journaler->get_read_pos(); num_events++; le->replay(mds); } delete le; logger->set(l_mdl_rdpos, pos); // drop lock for a second, so other events/messages (e.g. beacon timer!) can go off mds->mds_lock.Unlock(); mds->mds_lock.Lock(); } // done! if (r == 0) { assert(journaler->get_read_pos() == journaler->get_write_pos()); dout(10) << "_replay - complete, " << num_events << " events" << dendl; logger->set(l_mdl_expos, journaler->get_expire_pos()); } dout(10) << "_replay_thread kicking waiters" << dendl; finish_contexts(g_ceph_context, waitfor_replay, r); dout(10) << "_replay_thread finish" << dendl; mds->mds_lock.Unlock(); } void MDLog::standby_trim_segments() { dout(10) << "standby_trim_segments" << dendl; uint64_t expire_pos = journaler->get_expire_pos(); dout(10) << " expire_pos=" << expire_pos << dendl; bool removed_segment = false; while (have_any_segments()) { LogSegment *seg = get_oldest_segment(); if (seg->end > expire_pos) break; dout(10) << " removing segment " << seg->offset << dendl; seg->dirty_dirfrags.clear_list(); seg->new_dirfrags.clear_list(); seg->dirty_inodes.clear_list(); seg->dirty_dentries.clear_list(); seg->open_files.clear_list(); seg->dirty_parent_inodes.clear_list(); seg->dirty_dirfrag_dir.clear_list(); seg->dirty_dirfrag_nest.clear_list(); seg->dirty_dirfrag_dirfragtree.clear_list(); remove_oldest_segment(); removed_segment = true; } if (removed_segment) { dout(20) << " calling mdcache->trim!" << dendl; mds->mdcache->trim(-1); } else dout(20) << " removed no segments!" << dendl; } ceph-0.80.11/src/mds/MDSUtility.h0000664000175100017510000000266412623076744020437 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 John Spray * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef MDS_UTILITY_H_ #define MDS_UTILITY_H_ #include "osd/OSDMap.h" #include "osdc/Objecter.h" #include "mds/MDSMap.h" #include "messages/MMDSMap.h" #include "msg/Dispatcher.h" #include "msg/Messenger.h" #include "auth/Auth.h" /// MDS Utility /** * This class is the parent for MDS utilities, i.e. classes that * need access the objects belonging to the MDS without actually * acting as an MDS daemon themselves. */ class MDSUtility : public Dispatcher { protected: Objecter *objecter; OSDMap *osdmap; MDSMap *mdsmap; Messenger *messenger; MonClient *monc; Mutex lock; SafeTimer timer; Context *waiting_for_mds_map; public: MDSUtility(); ~MDSUtility(); void handle_mds_map(MMDSMap* m); bool ms_dispatch(Message *m); bool ms_handle_reset(Connection *con) { return false; } void ms_handle_remote_reset(Connection *con) {} bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); int init(); void shutdown(); }; #endif /* MDS_UTILITY_H_ */ ceph-0.80.11/src/mds/Migrator.cc0000664000175100017510000026173012623076744020353 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDS.h" #include "MDCache.h" #include "CInode.h" #include "CDir.h" #include "CDentry.h" #include "Migrator.h" #include "Locker.h" #include "Server.h" #include "MDBalancer.h" #include "MDLog.h" #include "MDSMap.h" #include "Mutation.h" #include "include/filepath.h" #include "events/EExport.h" #include "events/EImportStart.h" #include "events/EImportFinish.h" #include "events/ESessions.h" #include "msg/Messenger.h" #include "messages/MClientCaps.h" #include "messages/MExportDirDiscover.h" #include "messages/MExportDirDiscoverAck.h" #include "messages/MExportDirCancel.h" #include "messages/MExportDirPrep.h" #include "messages/MExportDirPrepAck.h" #include "messages/MExportDir.h" #include "messages/MExportDirAck.h" #include "messages/MExportDirNotify.h" #include "messages/MExportDirNotifyAck.h" #include "messages/MExportDirFinish.h" #include "messages/MExportCaps.h" #include "messages/MExportCapsAck.h" /* * this is what the dir->dir_auth values look like * * dir_auth authbits * export * me me - before * me, me me - still me, but preparing for export * me, them me - send MExportDir (peer is preparing) * them, me me - journaled EExport * them them - done * * import: * them them - before * me, them me - journaled EImportStart * me me - done * * which implies: * - auth bit is set if i am listed as first _or_ second dir_auth. */ #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef DOUT_COND #define DOUT_COND(cct, l) (l <= cct->_conf->debug_mds || l <= cct->_conf->debug_mds_migrator) #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".migrator " /* This function DOES put the passed message before returning*/ void Migrator::dispatch(Message *m) { switch (m->get_type()) { // import case MSG_MDS_EXPORTDIRDISCOVER: handle_export_discover(static_cast(m)); break; case MSG_MDS_EXPORTDIRPREP: handle_export_prep(static_cast(m)); break; case MSG_MDS_EXPORTDIR: handle_export_dir(static_cast(m)); break; case MSG_MDS_EXPORTDIRFINISH: handle_export_finish(static_cast(m)); break; case MSG_MDS_EXPORTDIRCANCEL: handle_export_cancel(static_cast(m)); break; // export case MSG_MDS_EXPORTDIRDISCOVERACK: handle_export_discover_ack(static_cast(m)); break; case MSG_MDS_EXPORTDIRPREPACK: handle_export_prep_ack(static_cast(m)); break; case MSG_MDS_EXPORTDIRACK: handle_export_ack(static_cast(m)); break; case MSG_MDS_EXPORTDIRNOTIFYACK: handle_export_notify_ack(static_cast(m)); break; // export 3rd party (dir_auth adjustments) case MSG_MDS_EXPORTDIRNOTIFY: handle_export_notify(static_cast(m)); break; // caps case MSG_MDS_EXPORTCAPS: handle_export_caps(static_cast(m)); break; default: assert(0); } } class C_MDC_EmptyImport : public Context { Migrator *mig; CDir *dir; public: C_MDC_EmptyImport(Migrator *m, CDir *d) : mig(m), dir(d) {} void finish(int r) { mig->export_empty_import(dir); } }; void Migrator::export_empty_import(CDir *dir) { dout(7) << "export_empty_import " << *dir << dendl; assert(dir->is_subtree_root()); if (dir->inode->is_auth()) { dout(7) << " inode is auth" << dendl; return; } if (!dir->is_auth()) { dout(7) << " not auth" << dendl; return; } if (dir->is_freezing() || dir->is_frozen()) { dout(7) << " freezing or frozen" << dendl; return; } if (dir->get_num_head_items() > 0) { dout(7) << " not actually empty" << dendl; return; } if (dir->inode->is_root()) { dout(7) << " root" << dendl; return; } int dest = dir->inode->authority().first; //if (mds->is_shutting_down()) dest = 0; // this is more efficient. dout(7) << " really empty, exporting to " << dest << dendl; assert (dest != mds->get_nodeid()); dout(7) << "exporting to mds." << dest << " empty import " << *dir << dendl; export_dir( dir, dest ); } void Migrator::find_stale_export_freeze() { utime_t now = ceph_clock_now(g_ceph_context); utime_t cutoff = now; cutoff -= g_conf->mds_freeze_tree_timeout; /* * We could have situations like: * * - mds.0 authpins an item in subtree A * - mds.0 sends request to mds.1 to authpin an item in subtree B * - mds.0 freezes subtree A * - mds.1 authpins an item in subtree B * - mds.1 sends request to mds.0 to authpin an item in subtree A * - mds.1 freezes subtree B * - mds.1 receives the remote authpin request from mds.0 * (wait because subtree B is freezing) * - mds.0 receives the remote authpin request from mds.1 * (wait because subtree A is freezing) * * * - client request authpins items in subtree B * - freeze subtree B * - import subtree A which is parent of subtree B * (authpins parent inode of subtree B, see CDir::set_dir_auth()) * - freeze subtree A * - client request tries authpinning items in subtree A * (wait because subtree A is freezing) */ for (map::iterator p = export_state.begin(); p != export_state.end(); ) { CDir* dir = p->first; export_state_t& stat = p->second; ++p; if (p->second.state != EXPORT_DISCOVERING && p->second.state != EXPORT_FREEZING) continue; if (stat.last_cum_auth_pins != dir->get_cum_auth_pins()) { stat.last_cum_auth_pins = dir->get_cum_auth_pins(); stat.last_cum_auth_pins_change = now; continue; } if (stat.last_cum_auth_pins_change >= cutoff) continue; if (stat.num_remote_waiters > 0 || (!dir->inode->is_root() && dir->get_parent_dir()->is_freezing())) { export_try_cancel(dir); } } } void Migrator::export_try_cancel(CDir *dir, bool notify_peer) { dout(10) << "export_try_cancel " << *dir << dendl; map::iterator it = export_state.find(dir); assert(it != export_state.end()); int state = it->second.state; switch (state) { case EXPORT_LOCKING: dout(10) << "export state=locking : dropping locks and removing auth_pin" << dendl; it->second.state = EXPORT_CANCELLED; dir->auth_unpin(this); dir->state_clear(CDir::STATE_EXPORTING); break; case EXPORT_DISCOVERING: dout(10) << "export state=discovering : canceling freeze and removing auth_pin" << dendl; it->second.state = EXPORT_CANCELLED; dir->unfreeze_tree(); // cancel the freeze dir->auth_unpin(this); dir->state_clear(CDir::STATE_EXPORTING); if (notify_peer && mds->mdsmap->is_clientreplay_or_active_or_stopping(it->second.peer)) // tell them. mds->send_message_mds(new MExportDirCancel(dir->dirfrag(), it->second.tid), it->second.peer); break; case EXPORT_FREEZING: dout(10) << "export state=freezing : canceling freeze" << dendl; it->second.state = EXPORT_CANCELLED; dir->unfreeze_tree(); // cancel the freeze dir->state_clear(CDir::STATE_EXPORTING); if (notify_peer && mds->mdsmap->is_clientreplay_or_active_or_stopping(it->second.peer)) // tell them. mds->send_message_mds(new MExportDirCancel(dir->dirfrag(), it->second.tid), it->second.peer); break; // NOTE: state order reversal, warning comes after prepping case EXPORT_WARNING: dout(10) << "export state=warning : unpinning bounds, unfreezing, notifying" << dendl; // fall-thru case EXPORT_PREPPING: if (state != EXPORT_WARNING) dout(10) << "export state=prepping : unpinning bounds, unfreezing" << dendl; it->second.state = EXPORT_CANCELLED; { // unpin bounds set bounds; cache->get_subtree_bounds(dir, bounds); for (set::iterator q = bounds.begin(); q != bounds.end(); ++q) { CDir *bd = *q; bd->put(CDir::PIN_EXPORTBOUND); bd->state_clear(CDir::STATE_EXPORTBOUND); } if (state == EXPORT_WARNING) { // notify bystanders export_notify_abort(dir, bounds); // process delayed expires cache->process_delayed_expire(dir); } } dir->unfreeze_tree(); cache->adjust_subtree_auth(dir, mds->get_nodeid()); cache->try_subtree_merge(dir); // NOTE: this may journal subtree_map as side effect dir->state_clear(CDir::STATE_EXPORTING); if (notify_peer && mds->mdsmap->is_clientreplay_or_active_or_stopping(it->second.peer)) // tell them. mds->send_message_mds(new MExportDirCancel(dir->dirfrag(), it->second.tid), it->second.peer); break; case EXPORT_EXPORTING: dout(10) << "export state=exporting : reversing, and unfreezing" << dendl; it->second.state = EXPORT_CANCELLED; export_reverse(dir); dir->state_clear(CDir::STATE_EXPORTING); break; case EXPORT_LOGGINGFINISH: case EXPORT_NOTIFYING: dout(10) << "export state=loggingfinish|notifying : ignoring dest failure, we were successful." << dendl; // leave export_state, don't clean up now. break; default: assert(0); } // finish clean-up? if (it->second.state == EXPORT_CANCELLED) { // wake up any waiters mds->queue_waiters(it->second.waiting_for_finish); // drop locks if (state == EXPORT_LOCKING || state == EXPORT_DISCOVERING) { MDRequestRef mdr = ceph::static_pointer_cast(it->second.mut); assert(mdr); if (mdr->more()->waiting_on_slave.empty()) mds->mdcache->request_finish(mdr); } else if (it->second.mut) { MutationRef& mut = it->second.mut; mds->locker->drop_locks(mut.get()); mut->cleanup(); } export_state.erase(it); // send pending import_maps? (these need to go out when all exports have finished.) cache->maybe_send_pending_resolves(); cache->show_subtrees(); maybe_do_queued_export(); } } // ========================================================== // mds failure handling void Migrator::handle_mds_failure_or_stop(int who) { dout(5) << "handle_mds_failure_or_stop mds." << who << dendl; // check my exports // first add an extra auth_pin on any freezes, so that canceling a // nested freeze doesn't complete one further up the hierarchy and // confuse the shit out of us. we'll remove it after canceling the // freeze. this way no freeze completions run before we want them // to. list pinned_dirs; for (map::iterator p = export_state.begin(); p != export_state.end(); ++p) { if (p->second.state == EXPORT_FREEZING) { CDir *dir = p->first; dout(10) << "adding temp auth_pin on freezing " << *dir << dendl; dir->auth_pin(this); pinned_dirs.push_back(dir); } } map::iterator p = export_state.begin(); while (p != export_state.end()) { map::iterator next = p; ++next; CDir *dir = p->first; // abort exports: // - that are going to the failed node // - that aren't frozen yet (to avoid auth_pin deadlock) // - they havne't prepped yet (they may need to discover bounds to do that) if (p->second.peer == who || p->second.state == EXPORT_LOCKING || p->second.state == EXPORT_DISCOVERING || p->second.state == EXPORT_FREEZING || p->second.state == EXPORT_PREPPING) { // the guy i'm exporting to failed, or we're just freezing. dout(10) << "cleaning up export state (" << p->second.state << ")" << get_export_statename(p->second.state) << " of " << *dir << dendl; export_try_cancel(dir); } else { // bystander failed. if (p->second.warning_ack_waiting.count(who)) { p->second.warning_ack_waiting.erase(who); p->second.notify_ack_waiting.erase(who); // they won't get a notify either. if (p->second.state == EXPORT_WARNING) { // exporter waiting for warning acks, let's fake theirs. dout(10) << "faking export_warning_ack from mds." << who << " on " << *dir << " to mds." << p->second.peer << dendl; if (p->second.warning_ack_waiting.empty()) export_go(dir); } } if (p->second.notify_ack_waiting.count(who)) { p->second.notify_ack_waiting.erase(who); if (p->second.state == EXPORT_NOTIFYING) { // exporter is waiting for notify acks, fake it dout(10) << "faking export_notify_ack from mds." << who << " on " << *dir << " to mds." << p->second.peer << dendl; if (p->second.notify_ack_waiting.empty()) export_finish(dir); } } } // next! p = next; } // check my imports map::iterator q = import_state.begin(); while (q != import_state.end()) { map::iterator next = q; ++next; dirfrag_t df = q->first; CInode *diri = mds->mdcache->get_inode(df.ino); CDir *dir = mds->mdcache->get_dirfrag(df); if (q->second.peer == who) { if (dir) dout(10) << "cleaning up import state (" << q->second.state << ")" << get_import_statename(q->second.state) << " of " << *dir << dendl; else dout(10) << "cleaning up import state (" << q->second.state << ")" << get_import_statename(q->second.state) << " of " << df << dendl; switch (q->second.state) { case IMPORT_DISCOVERING: dout(10) << "import state=discovering : clearing state" << dendl; import_reverse_discovering(df); break; case IMPORT_DISCOVERED: assert(diri); dout(10) << "import state=discovered : unpinning inode " << *diri << dendl; import_reverse_discovered(df, diri); break; case IMPORT_PREPPING: assert(dir); dout(10) << "import state=prepping : unpinning base+bounds " << *dir << dendl; import_reverse_prepping(dir); break; case IMPORT_PREPPED: assert(dir); dout(10) << "import state=prepped : unpinning base+bounds, unfreezing " << *dir << dendl; { set bounds; cache->get_subtree_bounds(dir, bounds); import_remove_pins(dir, bounds); // adjust auth back to the exporter cache->adjust_subtree_auth(dir, q->second.peer); cache->try_subtree_merge(dir); // NOTE: may journal subtree_map as side-effect // bystanders? if (q->second.bystanders.empty()) { import_reverse_unfreeze(dir); } else { // notify them; wait in aborting state import_notify_abort(dir, bounds); import_state[df].state = IMPORT_ABORTING; assert(g_conf->mds_kill_import_at != 10); } } break; case IMPORT_LOGGINGSTART: assert(dir); dout(10) << "import state=loggingstart : reversing import on " << *dir << dendl; import_reverse(dir); break; case IMPORT_ACKING: assert(dir); // hrm. make this an ambiguous import, and wait for exporter recovery to disambiguate dout(10) << "import state=acking : noting ambiguous import " << *dir << dendl; { set bounds; cache->get_subtree_bounds(dir, bounds); cache->add_ambiguous_import(dir, bounds); } break; case IMPORT_FINISHING: assert(dir); dout(10) << "import state=finishing : finishing import on " << *dir << dendl; import_finish(dir, true); break; case IMPORT_ABORTING: assert(dir); dout(10) << "import state=aborting : ignoring repeat failure " << *dir << dendl; break; } } else { if (q->second.bystanders.count(who)) { q->second.bystanders.erase(who); if (q->second.state == IMPORT_ABORTING) { assert(dir); dout(10) << "faking export_notify_ack from mds." << who << " on aborting import " << *dir << " from mds." << q->second.peer << dendl; if (q->second.bystanders.empty()) { import_reverse_unfreeze(dir); } } } } // next! q = next; } while (!pinned_dirs.empty()) { CDir *dir = pinned_dirs.front(); dout(10) << "removing temp auth_pin on " << *dir << dendl; dir->auth_unpin(this); pinned_dirs.pop_front(); } } void Migrator::show_importing() { dout(10) << "show_importing" << dendl; for (map::iterator p = import_state.begin(); p != import_state.end(); ++p) { CDir *dir = mds->mdcache->get_dirfrag(p->first); if (dir) { dout(10) << " importing from " << p->second.peer << ": (" << p->second.state << ") " << get_import_statename(p->second.state) << " " << p->first << " " << *dir << dendl; } else { dout(10) << " importing from " << p->second.peer << ": (" << p->second.state << ") " << get_import_statename(p->second.state) << " " << p->first << dendl; } } } void Migrator::show_exporting() { dout(10) << "show_exporting" << dendl; for (map::iterator p = export_state.begin(); p != export_state.end(); ++p) dout(10) << " exporting to " << p->second.peer << ": (" << p->second.state << ") " << get_export_statename(p->second.state) << " " << p->first->dirfrag() << " " << *p->first << dendl; } void Migrator::audit() { if (!g_conf->subsys.should_gather(ceph_subsys_mds, 5)) return; // hrm. // import_state show_importing(); for (map::iterator p = import_state.begin(); p != import_state.end(); ++p) { if (p->second.state == IMPORT_DISCOVERING) continue; if (p->second.state == IMPORT_DISCOVERED) { CInode *in = cache->get_inode(p->first.ino); assert(in); continue; } CDir *dir = cache->get_dirfrag(p->first); assert(dir); if (p->second.state == IMPORT_PREPPING) continue; if (p->second.state == IMPORT_ABORTING) { assert(!dir->is_ambiguous_dir_auth()); assert(dir->get_dir_auth().first != mds->get_nodeid()); continue; } assert(dir->is_ambiguous_dir_auth()); assert(dir->authority().first == mds->get_nodeid() || dir->authority().second == mds->get_nodeid()); } // export_state show_exporting(); for (map::iterator p = export_state.begin(); p != export_state.end(); ++p) { CDir *dir = p->first; if (p->second.state == EXPORT_LOCKING || p->second.state == EXPORT_DISCOVERING || p->second.state == EXPORT_FREEZING) continue; assert(dir->is_ambiguous_dir_auth()); assert(dir->authority().first == mds->get_nodeid() || dir->authority().second == mds->get_nodeid()); } // ambiguous+me subtrees should be importing|exporting // write me } // ========================================================== // EXPORT void Migrator::export_dir_nicely(CDir *dir, int dest) { // enqueue dout(7) << "export_dir_nicely " << *dir << " to " << dest << dendl; export_queue.push_back(pair(dir->dirfrag(), dest)); maybe_do_queued_export(); } void Migrator::maybe_do_queued_export() { static bool running; if (running) return; running = true; while (!export_queue.empty() && export_state.size() <= 4) { dirfrag_t df = export_queue.front().first; int dest = export_queue.front().second; export_queue.pop_front(); CDir *dir = mds->mdcache->get_dirfrag(df); if (!dir) continue; if (!dir->is_auth()) continue; dout(0) << "nicely exporting to mds." << dest << " " << *dir << dendl; export_dir(dir, dest); } running = false; } class C_MDC_ExportFreeze : public Context { Migrator *mig; CDir *ex; // dir i'm exporting public: C_MDC_ExportFreeze(Migrator *m, CDir *e) : mig(m), ex(e) {} virtual void finish(int r) { if (r >= 0) mig->export_frozen(ex); } }; void Migrator::get_export_lock_set(CDir *dir, set& locks) { // path vector trace; cache->make_trace(trace, dir->inode); for (vector::iterator it = trace.begin(); it != trace.end(); ++it) locks.insert(&(*it)->lock); // prevent scatter gather race locks.insert(&dir->get_inode()->dirfragtreelock); // bound dftlocks: // NOTE: We need to take an rdlock on bounding dirfrags during // migration for a rather irritating reason: when we export the // bound inode, we need to send scatterlock state for the dirfrags // as well, so that the new auth also gets the correct info. If we // race with a refragment, this info is useless, as we can't // redivvy it up. And it's needed for the scatterlocks to work // properly: when the auth is in a sync/lock state it keeps each // dirfrag's portion in the local (auth OR replica) dirfrag. set wouldbe_bounds; cache->get_wouldbe_subtree_bounds(dir, wouldbe_bounds); for (set::iterator p = wouldbe_bounds.begin(); p != wouldbe_bounds.end(); ++p) locks.insert(&(*p)->get_inode()->dirfragtreelock); } /** export_dir(dir, dest) * public method to initiate an export. * will fail if the directory is freezing, frozen, unpinnable, or root. */ void Migrator::export_dir(CDir *dir, int dest) { dout(7) << "export_dir " << *dir << " to " << dest << dendl; assert(dir->is_auth()); assert(dest != mds->get_nodeid()); if (mds->mdsmap->is_degraded()) { dout(7) << "cluster degraded, no exports for now" << dendl; return; } if (dir->inode->is_system()) { dout(7) << "i won't export system dirs (root, mdsdirs, stray, /.ceph, etc.)" << dendl; //assert(0); return; } if (!dir->inode->is_base() && dir->get_parent_dir()->get_inode()->is_stray() && dir->get_parent_dir()->get_parent_dir()->ino() != MDS_INO_MDSDIR(dest)) { dout(7) << "i won't export anything in stray" << dendl; return; } if (dir->is_frozen() || dir->is_freezing()) { dout(7) << " can't export, freezing|frozen. wait for other exports to finish first." << dendl; return; } if (dir->state_test(CDir::STATE_EXPORTING)) { dout(7) << "already exporting" << dendl; return; } dir->auth_pin(this); dir->state_set(CDir::STATE_EXPORTING); MDRequestRef mdr = mds->mdcache->request_start_internal(CEPH_MDS_OP_EXPORTDIR); mdr->more()->export_dir = dir; assert(export_state.count(dir) == 0); export_state_t& stat = export_state[dir]; stat.state = EXPORT_LOCKING; stat.peer = dest; stat.tid = mdr->reqid.tid; stat.mut = mdr; dispatch_export_dir(mdr); } void Migrator::dispatch_export_dir(MDRequestRef& mdr) { dout(7) << "dispatch_export_dir " << *mdr << dendl; CDir *dir = mdr->more()->export_dir; map::iterator it = export_state.find(dir); if (it == export_state.end() || it->second.tid != mdr->reqid.tid) { // export must have aborted. dout(7) << "export must have aborted " << *mdr << dendl; mds->mdcache->request_finish(mdr); return; } assert(it->second.state == EXPORT_LOCKING); if (mdr->aborted || dir->is_frozen() || dir->is_freezing()) { dout(7) << "wouldblock|freezing|frozen, canceling export" << dendl; export_try_cancel(dir); return; } // locks? set rdlocks; set xlocks; set wrlocks; get_export_lock_set(dir, rdlocks); // If auth MDS of the subtree root inode is neither the exporter MDS // nor the importer MDS and it gathers subtree root's fragstat/neststat // while the subtree is exporting. It's possible that the exporter MDS // and the importer MDS both are auth MDS of the subtree root or both // are not auth MDS of the subtree root at the time they receive the // lock messages. So the auth MDS of the subtree root inode may get no // or duplicated fragstat/neststat for the subtree root dirfrag. wrlocks.insert(&dir->get_inode()->filelock); wrlocks.insert(&dir->get_inode()->nestlock); if (dir->get_inode()->is_auth()) { dir->get_inode()->filelock.set_scatter_wanted(); dir->get_inode()->nestlock.set_scatter_wanted(); } if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks, NULL, NULL, true)) { if (mdr->aborted) export_try_cancel(dir); return; } assert(g_conf->mds_kill_export_at != 1); it->second.state = EXPORT_DISCOVERING; // send ExportDirDiscover (ask target) filepath path; dir->inode->make_path(path); MExportDirDiscover *discover = new MExportDirDiscover(dir->dirfrag(), path, mds->get_nodeid(), it->second.tid); mds->send_message_mds(discover, it->second.peer); assert(g_conf->mds_kill_export_at != 2); it->second.last_cum_auth_pins_change = ceph_clock_now(g_ceph_context); // start the freeze, but hold it up with an auth_pin. dir->freeze_tree(); assert(dir->is_freezing_tree()); dir->add_waiter(CDir::WAIT_FROZEN, new C_MDC_ExportFreeze(this, dir)); } /* * called on receipt of MExportDirDiscoverAck * the importer now has the directory's _inode_ in memory, and pinned. * * This function DOES put the passed message before returning */ void Migrator::handle_export_discover_ack(MExportDirDiscoverAck *m) { CDir *dir = cache->get_dirfrag(m->get_dirfrag()); assert(dir); dout(7) << "export_discover_ack from " << m->get_source() << " on " << *dir << dendl; map::iterator it = export_state.find(dir); if (it == export_state.end() || it->second.tid != m->get_tid() || it->second.peer != m->get_source().num()) { dout(7) << "must have aborted" << dendl; } else { assert(it->second.state == EXPORT_DISCOVERING); // release locks to avoid deadlock MDRequestRef mdr = ceph::static_pointer_cast(it->second.mut); assert(mdr); mds->mdcache->request_finish(mdr); it->second.mut.reset(); // freeze the subtree it->second.state = EXPORT_FREEZING; dir->auth_unpin(this); assert(g_conf->mds_kill_export_at != 3); } m->put(); // done } class C_M_ExportSessionsFlushed : public Context { Migrator *migrator; CDir *dir; uint64_t tid; public: C_M_ExportSessionsFlushed(Migrator *m, CDir *d, uint64_t t) : migrator(m), dir(d), tid(t) {} void finish(int r) { migrator->export_sessions_flushed(dir, tid); } }; void Migrator::export_sessions_flushed(CDir *dir, uint64_t tid) { dout(7) << "export_sessions_flushed " << *dir << dendl; map::iterator it = export_state.find(dir); if (it == export_state.end() || it->second.tid != tid) { // export must have aborted. dout(7) << "export must have aborted on " << dir << dendl; return; } assert(it->second.state == EXPORT_PREPPING || it->second.state == EXPORT_WARNING); assert(it->second.warning_ack_waiting.count(-1) > 0); it->second.warning_ack_waiting.erase(-1); if (it->second.state == EXPORT_WARNING && it->second.warning_ack_waiting.empty()) export_go(dir); // start export. } void Migrator::export_frozen(CDir *dir) { dout(7) << "export_frozen on " << *dir << dendl; assert(dir->is_frozen()); assert(dir->get_cum_auth_pins() == 0); map::iterator it = export_state.find(dir); assert(it != export_state.end()); assert(it->second.state == EXPORT_FREEZING); CInode *diri = dir->get_inode(); // ok, try to grab all my locks. set rdlocks; get_export_lock_set(dir, rdlocks); if ((diri->is_auth() && diri->is_frozen()) || !mds->locker->can_rdlock_set(rdlocks) || !diri->filelock.can_wrlock(-1) || !diri->nestlock.can_wrlock(-1)) { dout(7) << "export_dir couldn't acquire all needed locks, failing. " << *dir << dendl; // .. unwind .. dir->unfreeze_tree(); dir->state_clear(CDir::STATE_EXPORTING); mds->queue_waiters(it->second.waiting_for_finish); mds->send_message_mds(new MExportDirCancel(dir->dirfrag(), it->second.tid), it->second.peer); export_state.erase(it); return; } it->second.mut = MutationRef(new MutationImpl); if (diri->is_auth()) it->second.mut->auth_pin(diri); mds->locker->rdlock_take_set(rdlocks, it->second.mut); mds->locker->wrlock_force(&diri->filelock, it->second.mut); mds->locker->wrlock_force(&diri->nestlock, it->second.mut); cache->show_subtrees(); // note the bounds. // force it into a subtree by listing auth as . cache->adjust_subtree_auth(dir, mds->get_nodeid(), mds->get_nodeid()); set bounds; cache->get_subtree_bounds(dir, bounds); // generate prep message, log entry. MExportDirPrep *prep = new MExportDirPrep(dir->dirfrag(), it->second.tid); // include list of bystanders for (map::iterator p = dir->replicas_begin(); p != dir->replicas_end(); ++p) { if (p->first != it->second.peer) { dout(10) << "bystander mds." << p->first << dendl; prep->add_bystander(p->first); } } // include base dirfrag cache->replicate_dir(dir, it->second.peer, prep->basedir); /* * include spanning tree for all nested exports. * these need to be on the destination _before_ the final export so that * dir_auth updates on any nested exports are properly absorbed. * this includes inodes and dirfrags included in the subtree, but * only the inodes at the bounds. * * each trace is: df ('-' | ('f' dir | 'd') dentry inode (dir dentry inode)*) */ set inodes_added; set dirfrags_added; // check bounds for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bound = *p; // pin it. bound->get(CDir::PIN_EXPORTBOUND); bound->state_set(CDir::STATE_EXPORTBOUND); dout(7) << " export bound " << *bound << dendl; prep->add_bound( bound->dirfrag() ); // trace to bound bufferlist tracebl; CDir *cur = bound; char start = '-'; while (1) { // don't repeat inodes if (inodes_added.count(cur->inode->ino())) break; inodes_added.insert(cur->inode->ino()); // prepend dentry + inode assert(cur->inode->is_auth()); bufferlist bl; cache->replicate_dentry(cur->inode->parent, it->second.peer, bl); dout(7) << " added " << *cur->inode->parent << dendl; cache->replicate_inode(cur->inode, it->second.peer, bl); dout(7) << " added " << *cur->inode << dendl; bl.claim_append(tracebl); tracebl.claim(bl); cur = cur->get_parent_dir(); // don't repeat dirfrags if (dirfrags_added.count(cur->dirfrag()) || cur == dir) { start = 'd'; // start with dentry break; } dirfrags_added.insert(cur->dirfrag()); // prepend dir cache->replicate_dir(cur, it->second.peer, bl); dout(7) << " added " << *cur << dendl; bl.claim_append(tracebl); tracebl.claim(bl); start = 'f'; // start with dirfrag } bufferlist final; dirfrag_t df = cur->dirfrag(); ::encode(df, final); ::encode(start, final); final.claim_append(tracebl); prep->add_trace(final); } // send. it->second.state = EXPORT_PREPPING; mds->send_message_mds(prep, it->second.peer); assert (g_conf->mds_kill_export_at != 4); // make sure any new instantiations of caps are flushed out assert(it->second.warning_ack_waiting.empty()); set export_client_set; get_export_client_set(dir, export_client_set); C_GatherBuilder gather(g_ceph_context); mds->server->flush_client_sessions(export_client_set, gather); if (gather.has_subs()) { it->second.warning_ack_waiting.insert(-1); gather.set_finisher(new C_M_ExportSessionsFlushed(this, dir, it->second.tid)); gather.activate(); } } void Migrator::get_export_client_set(CDir *dir, set& client_set) { list dfs; dfs.push_back(dir); while (!dfs.empty()) { CDir *dir = dfs.front(); dfs.pop_front(); for (CDir::map_t::iterator p = dir->begin(); p != dir->end(); ++p) { CDentry *dn = p->second; if (!dn->get_linkage()->is_primary()) continue; CInode *in = dn->get_linkage()->get_inode(); if (in->is_dir()) { // directory? list ls; in->get_dirfrags(ls); for (list::iterator q = ls.begin(); q != ls.end(); ++q) { if (!(*q)->state_test(CDir::STATE_EXPORTBOUND)) { // include nested dirfrag assert((*q)->get_dir_auth().first == CDIR_AUTH_PARENT); dfs.push_back(*q); // it's ours, recurse (later) } } } for (map::iterator q = in->client_caps.begin(); q != in->client_caps.end(); ++q) client_set.insert(q->first); } } } void Migrator::get_export_client_set(CInode *in, set& client_set) { for (map::iterator q = in->client_caps.begin(); q != in->client_caps.end(); ++q) client_set.insert(q->first); } /* This function DOES put the passed message before returning*/ void Migrator::handle_export_prep_ack(MExportDirPrepAck *m) { CDir *dir = cache->get_dirfrag(m->get_dirfrag()); assert(dir); dout(7) << "export_prep_ack " << *dir << dendl; map::iterator it = export_state.find(dir); if (it == export_state.end() || it->second.tid != m->get_tid() || it->second.peer != m->get_source().num()) { // export must have aborted. dout(7) << "export must have aborted" << dendl; m->put(); return; } assert(it->second.state == EXPORT_PREPPING); if (!m->is_success()) { dout(7) << "peer couldn't acquire all needed locks, canceling" << dendl; export_try_cancel(dir, false); m->put(); return; } assert (g_conf->mds_kill_export_at != 5); // send warnings set bounds; cache->get_subtree_bounds(dir, bounds); assert(it->second.warning_ack_waiting.empty() || (it->second.warning_ack_waiting.size() == 1 && it->second.warning_ack_waiting.count(-1) > 0)); assert(it->second.notify_ack_waiting.empty()); for (map::iterator p = dir->replicas_begin(); p != dir->replicas_end(); ++p) { if (p->first == it->second.peer) continue; if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(p->first)) continue; // only if active it->second.warning_ack_waiting.insert(p->first); it->second.notify_ack_waiting.insert(p->first); // we'll eventually get a notifyack, too! MExportDirNotify *notify = new MExportDirNotify(dir->dirfrag(), it->second.tid, true, pair(mds->get_nodeid(),CDIR_AUTH_UNKNOWN), pair(mds->get_nodeid(),it->second.peer)); for (set::iterator q = bounds.begin(); q != bounds.end(); ++q) notify->get_bounds().push_back((*q)->dirfrag()); mds->send_message_mds(notify, p->first); } it->second.state = EXPORT_WARNING; assert(g_conf->mds_kill_export_at != 6); // nobody to warn? if (it->second.warning_ack_waiting.empty()) export_go(dir); // start export. // done. m->put(); } class C_M_ExportGo : public Context { Migrator *migrator; CDir *dir; uint64_t tid; public: C_M_ExportGo(Migrator *m, CDir *d, uint64_t t) : migrator(m), dir(d), tid(t) {} void finish(int r) { migrator->export_go_synced(dir, tid); } }; void Migrator::export_go(CDir *dir) { assert(export_state.count(dir)); dout(7) << "export_go " << *dir << " to " << export_state[dir].peer << dendl; // first sync log to flush out e.g. any cap imports mds->mdlog->wait_for_safe(new C_M_ExportGo(this, dir, export_state[dir].tid)); mds->mdlog->flush(); } void Migrator::export_go_synced(CDir *dir, uint64_t tid) { map::iterator it = export_state.find(dir); if (it == export_state.end() || it->second.tid != tid) { // export must have aborted. dout(7) << "export must have aborted on " << dir << dendl; return; } assert(it->second.state == EXPORT_WARNING); dout(7) << "export_go_synced " << *dir << " to " << it->second.peer << dendl; cache->show_subtrees(); it->second.state = EXPORT_EXPORTING; assert(g_conf->mds_kill_export_at != 7); assert(dir->get_cum_auth_pins() == 0); // set ambiguous auth cache->adjust_subtree_auth(dir, mds->get_nodeid(), it->second.peer); // take away the popularity we're sending. utime_t now = ceph_clock_now(g_ceph_context); mds->balancer->subtract_export(dir, now); // fill export message with cache data MExportDir *req = new MExportDir(dir->dirfrag(), it->second.tid); map exported_client_map; int num_exported_inodes = encode_export_dir(req->export_data, dir, // recur start point exported_client_map, now); ::encode(exported_client_map, req->client_map); // add bounds to message set bounds; cache->get_subtree_bounds(dir, bounds); for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) req->add_export((*p)->dirfrag()); // send mds->send_message_mds(req, it->second.peer); assert(g_conf->mds_kill_export_at != 8); // stats if (mds->logger) mds->logger->inc(l_mds_ex); if (mds->logger) mds->logger->inc(l_mds_iexp, num_exported_inodes); cache->show_subtrees(); } /** encode_export_inode * update our local state for this inode to export. * encode relevant state to be sent over the wire. * used by: encode_export_dir, file_rename (if foreign) * * FIXME: the separation between CInode.encode_export and these methods * is pretty arbitrary and dumb. */ void Migrator::encode_export_inode(CInode *in, bufferlist& enc_state, map& exported_client_map) { dout(7) << "encode_export_inode " << *in << dendl; assert(!in->is_replica(mds->get_nodeid())); // relax locks? if (!in->is_replicated()) { in->replicate_relax_locks(); dout(20) << " did replicate_relax_locks, now " << *in << dendl; } ::encode(in->inode.ino, enc_state); ::encode(in->last, enc_state); in->encode_export(enc_state); // caps encode_export_inode_caps(in, true, enc_state, exported_client_map); } void Migrator::encode_export_inode_caps(CInode *in, bool auth_cap, bufferlist& bl, map& exported_client_map) { dout(20) << "encode_export_inode_caps " << *in << dendl; // encode caps map cap_map; in->export_client_caps(cap_map); ::encode(cap_map, bl); if (auth_cap) { ::encode(in->get_mds_caps_wanted(), bl); in->state_set(CInode::STATE_EXPORTINGCAPS); in->get(CInode::PIN_EXPORTINGCAPS); } // make note of clients named by exported capabilities for (map::iterator it = in->client_caps.begin(); it != in->client_caps.end(); ++it) exported_client_map[it->first] = mds->sessionmap.get_inst(entity_name_t::CLIENT(it->first.v)); } void Migrator::finish_export_inode_caps(CInode *in, int peer, map& peer_imported) { dout(20) << "finish_export_inode_caps " << *in << dendl; in->state_clear(CInode::STATE_EXPORTINGCAPS); in->put(CInode::PIN_EXPORTINGCAPS); // tell (all) clients about migrating caps.. for (map::iterator it = in->client_caps.begin(); it != in->client_caps.end(); ++it) { Capability *cap = it->second; dout(7) << "finish_export_inode_caps telling client." << it->first << " exported caps on " << *in << dendl; MClientCaps *m = new MClientCaps(CEPH_CAP_OP_EXPORT, in->ino(), 0, cap->get_cap_id(), cap->get_mseq()); map::iterator q = peer_imported.find(it->first); assert(q != peer_imported.end()); m->set_cap_peer(q->second.cap_id, q->second.issue_seq, q->second.mseq, peer, 0); mds->send_message_client_counted(m, it->first); } in->clear_client_caps_after_export(); mds->locker->eval(in, CEPH_CAP_LOCKS); } void Migrator::finish_export_inode(CInode *in, utime_t now, int peer, map& peer_imported, list& finished) { dout(12) << "finish_export_inode " << *in << dendl; // clean if (in->is_dirty()) in->mark_clean(); // clear/unpin cached_by (we're no longer the authority) in->clear_replica_map(); // twiddle lock states for auth -> replica transition in->authlock.export_twiddle(); in->linklock.export_twiddle(); in->dirfragtreelock.export_twiddle(); in->filelock.export_twiddle(); in->nestlock.export_twiddle(); in->xattrlock.export_twiddle(); in->snaplock.export_twiddle(); in->flocklock.export_twiddle(); in->policylock.export_twiddle(); // mark auth assert(in->is_auth()); in->state_clear(CInode::STATE_AUTH); in->replica_nonce = CInode::EXPORT_NONCE; in->clear_dirty_rstat(); // no more auth subtree? clear scatter dirty if (!in->has_subtree_root_dirfrag(mds->get_nodeid())) in->clear_scatter_dirty(); in->item_open_file.remove_myself(); in->clear_dirty_parent(); in->clear_file_locks(); // waiters in->take_waiting(CInode::WAIT_ANY_MASK, finished); in->finish_export(now); finish_export_inode_caps(in, peer, peer_imported); // *** other state too? // move to end of LRU so we drop out of cache quickly! if (in->get_parent_dn()) cache->lru.lru_bottouch(in->get_parent_dn()); } int Migrator::encode_export_dir(bufferlist& exportbl, CDir *dir, map& exported_client_map, utime_t now) { int num_exported = 0; dout(7) << "encode_export_dir " << *dir << " " << dir->get_num_head_items() << " head items" << dendl; assert(dir->get_projected_version() == dir->get_version()); #ifdef MDS_VERIFY_FRAGSTAT if (dir->is_complete()) dir->verify_fragstat(); #endif // dir dirfrag_t df = dir->dirfrag(); ::encode(df, exportbl); dir->encode_export(exportbl); __u32 nden = dir->items.size(); ::encode(nden, exportbl); // dentries list subdirs; CDir::map_t::iterator it; for (it = dir->begin(); it != dir->end(); ++it) { CDentry *dn = it->second; CInode *in = dn->get_linkage()->get_inode(); if (!dn->is_replicated()) dn->lock.replicate_relax(); num_exported++; // -- dentry dout(7) << "encode_export_dir exporting " << *dn << dendl; // dn name ::encode(dn->name, exportbl); ::encode(dn->last, exportbl); // state dn->encode_export(exportbl); // points to... // null dentry? if (dn->get_linkage()->is_null()) { exportbl.append("N", 1); // null dentry continue; } if (dn->get_linkage()->is_remote()) { // remote link exportbl.append("L", 1); // remote link inodeno_t ino = dn->get_linkage()->get_remote_ino(); unsigned char d_type = dn->get_linkage()->get_remote_d_type(); ::encode(ino, exportbl); ::encode(d_type, exportbl); continue; } // primary link // -- inode exportbl.append("I", 1); // inode dentry encode_export_inode(in, exportbl, exported_client_map); // encode, and (update state for) export // directory? list dfs; in->get_dirfrags(dfs); for (list::iterator p = dfs.begin(); p != dfs.end(); ++p) { CDir *t = *p; if (!t->state_test(CDir::STATE_EXPORTBOUND)) { // include nested dirfrag assert(t->get_dir_auth().first == CDIR_AUTH_PARENT); subdirs.push_back(t); // it's ours, recurse (later) } } } // subdirs for (list::iterator it = subdirs.begin(); it != subdirs.end(); ++it) num_exported += encode_export_dir(exportbl, *it, exported_client_map, now); return num_exported; } void Migrator::finish_export_dir(CDir *dir, utime_t now, int peer, map >& peer_imported, list& finished) { dout(10) << "finish_export_dir " << *dir << dendl; // release open_by dir->clear_replica_map(); // mark assert(dir->is_auth()); dir->state_clear(CDir::STATE_AUTH); dir->remove_bloom(); dir->replica_nonce = CDir::EXPORT_NONCE; if (dir->is_dirty()) dir->mark_clean(); // suck up all waiters dir->take_waiting(CDir::WAIT_ANY_MASK, finished); // all dir waiters // pop dir->finish_export(now); // dentries list subdirs; CDir::map_t::iterator it; for (it = dir->begin(); it != dir->end(); ++it) { CDentry *dn = it->second; CInode *in = dn->get_linkage()->get_inode(); // dentry dn->finish_export(); // inode? if (dn->get_linkage()->is_primary()) { finish_export_inode(in, now, peer, peer_imported[in->ino()], finished); // subdirs? in->get_nested_dirfrags(subdirs); } } // subdirs for (list::iterator it = subdirs.begin(); it != subdirs.end(); ++it) finish_export_dir(*it, now, peer, peer_imported, finished); } class C_MDS_ExportFinishLogged : public Context { Migrator *migrator; CDir *dir; public: C_MDS_ExportFinishLogged(Migrator *m, CDir *d) : migrator(m), dir(d) {} void finish(int r) { migrator->export_logged_finish(dir); } }; /* * i should get an export_ack from the export target. * * This function DOES put the passed message before returning */ void Migrator::handle_export_ack(MExportDirAck *m) { CDir *dir = cache->get_dirfrag(m->get_dirfrag()); assert(dir); assert(dir->is_frozen_tree_root()); // i'm exporting! // yay! dout(7) << "handle_export_ack " << *dir << dendl; map::iterator it = export_state.find(dir); assert(it != export_state.end()); assert(it->second.state == EXPORT_EXPORTING); assert(it->second.tid == m->get_tid()); bufferlist::iterator bp = m->imported_caps.begin(); ::decode(it->second.peer_imported, bp); it->second.state = EXPORT_LOGGINGFINISH; assert (g_conf->mds_kill_export_at != 9); set bounds; cache->get_subtree_bounds(dir, bounds); // list us second, them first. // this keeps authority().first in sync with subtree auth state in the journal. cache->adjust_subtree_auth(dir, it->second.peer, mds->get_nodeid()); // log completion. // include export bounds, to ensure they're in the journal. EExport *le = new EExport(mds->mdlog, dir); mds->mdlog->start_entry(le); le->metablob.add_dir_context(dir, EMetaBlob::TO_ROOT); le->metablob.add_dir( dir, false ); for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bound = *p; le->get_bounds().insert(bound->dirfrag()); le->metablob.add_dir_context(bound); le->metablob.add_dir(bound, false); } // log export completion, then finish (unfreeze, trigger finish context, etc.) mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(new C_MDS_ExportFinishLogged(this, dir)); mds->mdlog->flush(); assert (g_conf->mds_kill_export_at != 10); m->put(); } void Migrator::export_notify_abort(CDir *dir, set& bounds) { dout(7) << "export_notify_abort " << *dir << dendl; export_state_t& stat = export_state[dir]; for (set::iterator p = stat.notify_ack_waiting.begin(); p != stat.notify_ack_waiting.end(); ++p) { MExportDirNotify *notify = new MExportDirNotify(dir->dirfrag(),stat.tid,false, pair(mds->get_nodeid(),stat.peer), pair(mds->get_nodeid(),CDIR_AUTH_UNKNOWN)); for (set::iterator i = bounds.begin(); i != bounds.end(); ++i) notify->get_bounds().push_back((*i)->dirfrag()); mds->send_message_mds(notify, *p); } } /* * this happens if hte dest failes after i send teh export data but before it is acked * that is, we don't know they safely received and logged it, so we reverse our changes * and go on. */ void Migrator::export_reverse(CDir *dir) { dout(7) << "export_reverse " << *dir << dendl; set bounds; cache->get_subtree_bounds(dir, bounds); // remove exporting pins list rq; rq.push_back(dir); while (!rq.empty()) { CDir *t = rq.front(); rq.pop_front(); t->abort_export(); for (CDir::map_t::iterator p = t->items.begin(); p != t->items.end(); ++p) { p->second->abort_export(); if (!p->second->get_linkage()->is_primary()) continue; CInode *in = p->second->get_linkage()->get_inode(); in->abort_export(); if (in->is_dir()) in->get_nested_dirfrags(rq); } } // unpin bounds for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bd = *p; bd->put(CDir::PIN_EXPORTBOUND); bd->state_clear(CDir::STATE_EXPORTBOUND); } // adjust auth, with possible subtree merge. cache->adjust_subtree_auth(dir, mds->get_nodeid()); cache->try_subtree_merge(dir); // NOTE: may journal subtree_map as side-effect // notify bystanders export_notify_abort(dir, bounds); // process delayed expires cache->process_delayed_expire(dir); // unfreeze dir->unfreeze_tree(); cache->show_cache(); } /* * once i get the ack, and logged the EExportFinish(true), * send notifies (if any), otherwise go straight to finish. * */ void Migrator::export_logged_finish(CDir *dir) { dout(7) << "export_logged_finish " << *dir << dendl; export_state_t& stat = export_state[dir]; // send notifies set bounds; cache->get_subtree_bounds(dir, bounds); for (set::iterator p = stat.notify_ack_waiting.begin(); p != stat.notify_ack_waiting.end(); ++p) { MExportDirNotify *notify = new MExportDirNotify(dir->dirfrag(), stat.tid, true, pair(mds->get_nodeid(), stat.peer), pair(stat.peer, CDIR_AUTH_UNKNOWN)); for (set::iterator i = bounds.begin(); i != bounds.end(); ++i) notify->get_bounds().push_back((*i)->dirfrag()); mds->send_message_mds(notify, *p); } // wait for notifyacks stat.state = EXPORT_NOTIFYING; assert (g_conf->mds_kill_export_at != 11); // no notifies to wait for? if (stat.notify_ack_waiting.empty()) { export_finish(dir); // skip notify/notify_ack stage. } else { // notify peer to send cap import messages to clients if (mds->mdsmap->is_clientreplay_or_active_or_stopping(stat.peer)) { mds->send_message_mds(new MExportDirFinish(dir->dirfrag(), false, stat.tid), stat.peer); } else { dout(7) << "not sending MExportDirFinish, dest has failed" << dendl; } } } /* * warning: * i'll get an ack from each bystander. * when i get them all, do the export. * notify: * i'll get an ack from each bystander. * when i get them all, unfreeze and send the finish. * * This function DOES put the passed message before returning */ void Migrator::handle_export_notify_ack(MExportDirNotifyAck *m) { CDir *dir = cache->get_dirfrag(m->get_dirfrag()); assert(dir); int from = m->get_source().num(); if (export_state.count(dir)) { export_state_t& stat = export_state[dir]; if (stat.state == EXPORT_WARNING) { // exporting. process warning. dout(7) << "handle_export_notify_ack from " << m->get_source() << ": exporting, processing warning on " << *dir << dendl; stat.warning_ack_waiting.erase(from); if (stat.warning_ack_waiting.empty()) export_go(dir); // start export. } else if (stat.state == EXPORT_NOTIFYING) { // exporting. process notify. dout(7) << "handle_export_notify_ack from " << m->get_source() << ": exporting, processing notify on " << *dir << dendl; stat.notify_ack_waiting.erase(from); if (stat.notify_ack_waiting.empty()) export_finish(dir); } } else if (import_state.count(dir->dirfrag())) { import_state_t& stat = import_state[dir->dirfrag()]; if (stat.state == IMPORT_ABORTING) { // reversing import dout(7) << "handle_export_notify_ack from " << m->get_source() << ": aborting import on " << *dir << dendl; assert(stat.bystanders.count(from)); stat.bystanders.erase(from); if (stat.bystanders.empty()) import_reverse_unfreeze(dir); } } m->put(); } void Migrator::export_finish(CDir *dir) { dout(5) << "export_finish " << *dir << dendl; assert (g_conf->mds_kill_export_at != 12); map::iterator it = export_state.find(dir); if (it == export_state.end()) { dout(7) << "target must have failed, not sending final commit message. export succeeded anyway." << dendl; return; } // send finish/commit to new auth if (mds->mdsmap->is_clientreplay_or_active_or_stopping(it->second.peer)) { mds->send_message_mds(new MExportDirFinish(dir->dirfrag(), true, it->second.tid), it->second.peer); } else { dout(7) << "not sending MExportDirFinish last, dest has failed" << dendl; } assert(g_conf->mds_kill_export_at != 13); // finish export (adjust local cache state) C_Contexts *fin = new C_Contexts(g_ceph_context); finish_export_dir(dir, ceph_clock_now(g_ceph_context), it->second.peer, it->second.peer_imported, fin->contexts); dir->add_waiter(CDir::WAIT_UNFREEZE, fin); // unfreeze dout(7) << "export_finish unfreezing" << dendl; dir->unfreeze_tree(); // unpin bounds set bounds; cache->get_subtree_bounds(dir, bounds); for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bd = *p; bd->put(CDir::PIN_EXPORTBOUND); bd->state_clear(CDir::STATE_EXPORTBOUND); } // adjust auth, with possible subtree merge. // (we do this _after_ removing EXPORTBOUND pins, to allow merges) cache->adjust_subtree_auth(dir, it->second.peer); cache->try_subtree_merge(dir); // NOTE: may journal subtree_map as sideeffect // no more auth subtree? clear scatter dirty if (!dir->get_inode()->is_auth() && !dir->get_inode()->has_subtree_root_dirfrag(mds->get_nodeid())) dir->get_inode()->clear_scatter_dirty(); // discard delayed expires cache->discard_delayed_expire(dir); // remove from exporting list, clean up state dir->state_clear(CDir::STATE_EXPORTING); // queue finishers mds->queue_waiters(it->second.waiting_for_finish); // unpin path MutationRef& mut = it->second.mut; if (mut) { mds->locker->drop_locks(mut.get()); mut->cleanup(); } export_state.erase(it); cache->show_subtrees(); audit(); // send pending import_maps? mds->mdcache->maybe_send_pending_resolves(); maybe_do_queued_export(); } // ========================================================== // IMPORT void Migrator::handle_export_discover(MExportDirDiscover *m) { int from = m->get_source_mds(); assert(from != mds->get_nodeid()); dout(7) << "handle_export_discover on " << m->get_path() << dendl; // note import state dirfrag_t df = m->get_dirfrag(); // only start discovering on this message once. map::iterator it = import_state.find(df); if (!m->started) { assert(it == import_state.end()); m->started = true; import_state[df].state = IMPORT_DISCOVERING; import_state[df].peer = from; import_state[df].tid = m->get_tid(); } else { // am i retrying after ancient path_traverse results? if (it == import_state.end() || it->second.peer != from || it->second.tid != m->get_tid()) { dout(7) << " dropping obsolete message" << dendl; m->put(); return; } assert(it->second.state == IMPORT_DISCOVERING); } if (!mds->mdcache->is_open()) { dout(5) << " waiting for root" << dendl; mds->mdcache->wait_for_open(new C_MDS_RetryMessage(mds, m)); return; } assert (g_conf->mds_kill_import_at != 1); // do we have it? CInode *in = cache->get_inode(m->get_dirfrag().ino); if (!in) { // must discover it! filepath fpath(m->get_path()); vector trace; MDRequestRef null_ref; int r = cache->path_traverse(null_ref, m, NULL, fpath, &trace, NULL, MDS_TRAVERSE_DISCOVER); if (r > 0) return; if (r < 0) { dout(7) << "handle_export_discover_2 failed to discover or not dir " << m->get_path() << ", NAK" << dendl; assert(0); // this shouldn't happen if the auth pins his path properly!!!! } assert(0); // this shouldn't happen; the get_inode above would have succeeded. } // yay dout(7) << "handle_export_discover have " << df << " inode " << *in << dendl; import_state[df].state = IMPORT_DISCOVERED; // pin inode in the cache (for now) assert(in->is_dir()); in->get(CInode::PIN_IMPORTING); // reply dout(7) << " sending export_discover_ack on " << *in << dendl; mds->send_message_mds(new MExportDirDiscoverAck(df, m->get_tid()), import_state[df].peer); m->put(); assert (g_conf->mds_kill_import_at != 2); } void Migrator::import_reverse_discovering(dirfrag_t df) { import_state.erase(df); } void Migrator::import_reverse_discovered(dirfrag_t df, CInode *diri) { // unpin base diri->put(CInode::PIN_IMPORTING); import_state.erase(df); } void Migrator::import_reverse_prepping(CDir *dir) { set bounds; cache->map_dirfrag_set(import_state[dir->dirfrag()].bound_ls, bounds); import_remove_pins(dir, bounds); import_reverse_final(dir); } /* This function DOES put the passed message before returning*/ void Migrator::handle_export_cancel(MExportDirCancel *m) { dout(7) << "handle_export_cancel on " << m->get_dirfrag() << dendl; dirfrag_t df = m->get_dirfrag(); map::iterator it = import_state.find(df); if (it == import_state.end()) { assert(0 == "got export_cancel in weird state"); } else if (it->second.state == IMPORT_DISCOVERING) { import_reverse_discovering(df); } else if (it->second.state == IMPORT_DISCOVERED) { CInode *in = cache->get_inode(df.ino); assert(in); import_reverse_discovered(df, in); } else if (it->second.state == IMPORT_PREPPING) { CDir *dir = mds->mdcache->get_dirfrag(df); assert(dir); import_reverse_prepping(dir); } else if (it->second.state == IMPORT_PREPPED) { CDir *dir = mds->mdcache->get_dirfrag(df); assert(dir); set bounds; cache->get_subtree_bounds(dir, bounds); import_remove_pins(dir, bounds); // adjust auth back to the exportor cache->adjust_subtree_auth(dir, it->second.peer); cache->try_subtree_merge(dir); import_reverse_unfreeze(dir); } else { assert(0 == "got export_cancel in weird state"); } m->put(); } /* This function DOES put the passed message before returning*/ void Migrator::handle_export_prep(MExportDirPrep *m) { int oldauth = m->get_source().num(); assert(oldauth != mds->get_nodeid()); CDir *dir; CInode *diri; list finished; // assimilate root dir. map::iterator it = import_state.find(m->get_dirfrag()); if (!m->did_assim()) { assert(it != import_state.end()); assert(it->second.state == IMPORT_DISCOVERED); diri = cache->get_inode(m->get_dirfrag().ino); assert(diri); bufferlist::iterator p = m->basedir.begin(); dir = cache->add_replica_dir(p, diri, oldauth, finished); dout(7) << "handle_export_prep on " << *dir << " (first pass)" << dendl; } else { if (it == import_state.end() || it->second.peer != oldauth || it->second.tid != m->get_tid()) { dout(7) << "handle_export_prep obsolete message, dropping" << dendl; m->put(); return; } assert(it->second.state == IMPORT_PREPPING); dir = cache->get_dirfrag(m->get_dirfrag()); assert(dir); dout(7) << "handle_export_prep on " << *dir << " (subsequent pass)" << dendl; diri = dir->get_inode(); } assert(dir->is_auth() == false); cache->show_subtrees(); // build import bound map map import_bound_fragset; for (list::iterator p = m->get_bounds().begin(); p != m->get_bounds().end(); ++p) { dout(10) << " bound " << *p << dendl; import_bound_fragset[p->ino].insert(p->frag); } // assimilate contents? if (!m->did_assim()) { dout(7) << "doing assim on " << *dir << dendl; m->mark_assim(); // only do this the first time! // change import state it->second.state = IMPORT_PREPPING; it->second.bound_ls = m->get_bounds(); it->second.bystanders = m->get_bystanders(); assert(g_conf->mds_kill_import_at != 3); // bystander list dout(7) << "bystanders are " << it->second.bystanders << dendl; // move pin to dir diri->put(CInode::PIN_IMPORTING); dir->get(CDir::PIN_IMPORTING); dir->state_set(CDir::STATE_IMPORTING); // assimilate traces to exports // each trace is: df ('-' | ('f' dir | 'd') dentry inode (dir dentry inode)*) for (list::iterator p = m->traces.begin(); p != m->traces.end(); ++p) { bufferlist::iterator q = p->begin(); dirfrag_t df; ::decode(df, q); char start; ::decode(start, q); dout(10) << " trace from " << df << " start " << start << " len " << p->length() << dendl; CDir *cur = 0; if (start == 'd') { cur = cache->get_dirfrag(df); assert(cur); dout(10) << " had " << *cur << dendl; } else if (start == 'f') { CInode *in = cache->get_inode(df.ino); assert(in); dout(10) << " had " << *in << dendl; cur = cache->add_replica_dir(q, in, oldauth, finished); dout(10) << " added " << *cur << dendl; } else if (start == '-') { // nothing } else assert(0 == "unrecognized start char"); while (start != '-') { CDentry *dn = cache->add_replica_dentry(q, cur, finished); dout(10) << " added " << *dn << dendl; CInode *in = cache->add_replica_inode(q, dn, finished); dout(10) << " added " << *in << dendl; if (q.end()) break; cur = cache->add_replica_dir(q, in, oldauth, finished); dout(10) << " added " << *cur << dendl; } } // make bound sticky for (map::iterator p = import_bound_fragset.begin(); p != import_bound_fragset.end(); ++p) { CInode *in = cache->get_inode(p->first); assert(in); in->get_stickydirs(); dout(7) << " set stickydirs on bound inode " << *in << dendl; } } else { dout(7) << " not doing assim on " << *dir << dendl; } if (!finished.empty()) mds->queue_waiters(finished); // open all bounds set import_bounds; for (map::iterator p = import_bound_fragset.begin(); p != import_bound_fragset.end(); ++p) { CInode *in = cache->get_inode(p->first); assert(in); // map fragset into a frag_t list, based on the inode fragtree list fglist; for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) in->dirfragtree.get_leaves_under(*q, fglist); dout(10) << " bound inode " << p->first << " fragset " << p->second << " maps to " << fglist << dendl; for (list::iterator q = fglist.begin(); q != fglist.end(); ++q) { CDir *bound = cache->get_dirfrag(dirfrag_t(p->first, *q)); if (!bound) { dout(7) << " opening bounding dirfrag " << *q << " on " << *in << dendl; cache->open_remote_dirfrag(in, *q, new C_MDS_RetryMessage(mds, m)); return; } if (!bound->state_test(CDir::STATE_IMPORTBOUND)) { dout(7) << " pinning import bound " << *bound << dendl; bound->get(CDir::PIN_IMPORTBOUND); bound->state_set(CDir::STATE_IMPORTBOUND); } else { dout(7) << " already pinned import bound " << *bound << dendl; } import_bounds.insert(bound); } } dout(7) << " all ready, noting auth and freezing import region" << dendl; bool success = true; if (dir->get_inode()->filelock.can_wrlock(-1) && dir->get_inode()->nestlock.can_wrlock(-1)) { it->second.mut = MutationRef(new MutationImpl); // force some locks. hacky. mds->locker->wrlock_force(&dir->inode->filelock, it->second.mut); mds->locker->wrlock_force(&dir->inode->nestlock, it->second.mut); // note that i am an ambiguous auth for this subtree. // specify bounds, since the exporter explicitly defines the region. cache->adjust_bounded_subtree_auth(dir, import_bounds, pair(oldauth, mds->get_nodeid())); cache->verify_subtree_bounds(dir, import_bounds); // freeze. dir->_freeze_tree(); // note new state it->second.state = IMPORT_PREPPED; } else { dout(7) << " couldn't acquire all needed locks, failing. " << *dir << dendl; success = false; import_reverse_prepping(dir); } // ok! dout(7) << " sending export_prep_ack on " << *dir << dendl; mds->send_message(new MExportDirPrepAck(dir->dirfrag(), success, m->get_tid()), m->get_connection()); assert(g_conf->mds_kill_import_at != 4); // done m->put(); } class C_MDS_ImportDirLoggedStart : public Context { Migrator *migrator; dirfrag_t df; CDir *dir; int from; public: map imported_client_map; map sseqmap; C_MDS_ImportDirLoggedStart(Migrator *m, CDir *d, int f) : migrator(m), df(d->dirfrag()), dir(d), from(f) { } void finish(int r) { migrator->import_logged_start(df, dir, from, imported_client_map, sseqmap); } }; /* This function DOES put the passed message before returning*/ void Migrator::handle_export_dir(MExportDir *m) { assert (g_conf->mds_kill_import_at != 5); CDir *dir = cache->get_dirfrag(m->dirfrag); assert(dir); map::iterator it = import_state.find(m->dirfrag); assert(it != import_state.end()); assert(it->second.state == IMPORT_PREPPED); assert(it->second.tid == m->get_tid()); utime_t now = ceph_clock_now(g_ceph_context); int oldauth = m->get_source().num(); dout(7) << "handle_export_dir importing " << *dir << " from " << oldauth << dendl; assert(dir->is_auth() == false); if (!dir->get_inode()->dirfragtree.is_leaf(dir->get_frag())) dir->get_inode()->dirfragtree.force_to_leaf(g_ceph_context, dir->get_frag()); cache->show_subtrees(); C_MDS_ImportDirLoggedStart *onlogged = new C_MDS_ImportDirLoggedStart(this, dir, m->get_source().num()); // start the journal entry EImportStart *le = new EImportStart(mds->mdlog, dir->dirfrag(), m->bounds); mds->mdlog->start_entry(le); le->metablob.add_dir_context(dir); // adjust auth (list us _first_) cache->adjust_subtree_auth(dir, mds->get_nodeid(), oldauth); // new client sessions, open these after we journal // include imported sessions in EImportStart bufferlist::iterator cmp = m->client_map.begin(); ::decode(onlogged->imported_client_map, cmp); assert(cmp.end()); le->cmapv = mds->server->prepare_force_open_sessions(onlogged->imported_client_map, onlogged->sseqmap); le->client_map.claim(m->client_map); bufferlist::iterator blp = m->export_data.begin(); int num_imported_inodes = 0; while (!blp.end()) { num_imported_inodes += decode_import_dir(blp, oldauth, dir, // import root le, mds->mdlog->get_current_segment(), it->second.peer_exports, it->second.updated_scatterlocks, now); } dout(10) << " " << m->bounds.size() << " imported bounds" << dendl; // include bounds in EImportStart set import_bounds; cache->get_subtree_bounds(dir, import_bounds); for (set::iterator it = import_bounds.begin(); it != import_bounds.end(); ++it) le->metablob.add_dir(*it, false); // note that parent metadata is already in the event // adjust popularity mds->balancer->add_import(dir, now); dout(7) << "handle_export_dir did " << *dir << dendl; // note state it->second.state = IMPORT_LOGGINGSTART; assert (g_conf->mds_kill_import_at != 6); // log it mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(onlogged); mds->mdlog->flush(); // some stats if (mds->logger) { mds->logger->inc(l_mds_im); mds->logger->inc(l_mds_iim, num_imported_inodes); } m->put(); } /* * this is an import helper * called by import_finish, and import_reverse and friends. */ void Migrator::import_remove_pins(CDir *dir, set& bounds) { import_state_t& stat = import_state[dir->dirfrag()]; // root dir->put(CDir::PIN_IMPORTING); dir->state_clear(CDir::STATE_IMPORTING); // bounding inodes set did; for (list::iterator p = stat.bound_ls.begin(); p != stat.bound_ls.end(); ++p) { if (did.count(p->ino)) continue; did.insert(p->ino); CInode *in = cache->get_inode(p->ino); assert(in); in->put_stickydirs(); } if (stat.state >= IMPORT_PREPPED) { // bounding dirfrags for (set::iterator it = bounds.begin(); it != bounds.end(); ++it) { CDir *bd = *it; bd->put(CDir::PIN_IMPORTBOUND); bd->state_clear(CDir::STATE_IMPORTBOUND); } } } /* * note: this does teh full work of reversing and import and cleaning up * state. * called by both handle_mds_failure and by handle_resolve (if we are * a survivor coping with an exporter failure+recovery). */ void Migrator::import_reverse(CDir *dir) { dout(7) << "import_reverse " << *dir << dendl; import_state_t& stat = import_state[dir->dirfrag()]; set bounds; cache->get_subtree_bounds(dir, bounds); // remove pins import_remove_pins(dir, bounds); // update auth, with possible subtree merge. assert(dir->is_subtree_root()); if (mds->is_resolve()) cache->trim_non_auth_subtree(dir); cache->adjust_subtree_auth(dir, stat.peer); if (!dir->get_inode()->is_auth() && !dir->get_inode()->has_subtree_root_dirfrag(mds->get_nodeid())) dir->get_inode()->clear_scatter_dirty(); // adjust auth bits. list q; q.push_back(dir); while (!q.empty()) { CDir *cur = q.front(); q.pop_front(); // dir assert(cur->is_auth()); cur->state_clear(CDir::STATE_AUTH); cur->remove_bloom(); cur->clear_replica_map(); if (cur->is_dirty()) cur->mark_clean(); CDir::map_t::iterator it; for (it = cur->begin(); it != cur->end(); ++it) { CDentry *dn = it->second; // dentry dn->state_clear(CDentry::STATE_AUTH); dn->clear_replica_map(); if (dn->is_dirty()) dn->mark_clean(); // inode? if (dn->get_linkage()->is_primary()) { CInode *in = dn->get_linkage()->get_inode(); in->state_clear(CDentry::STATE_AUTH); in->clear_replica_map(); if (in->is_dirty()) in->mark_clean(); in->clear_dirty_rstat(); if (!in->has_subtree_root_dirfrag(mds->get_nodeid())) in->clear_scatter_dirty(); in->clear_dirty_parent(); in->authlock.clear_gather(); in->linklock.clear_gather(); in->dirfragtreelock.clear_gather(); in->filelock.clear_gather(); in->clear_file_locks(); // non-bounding dir? list dfs; in->get_dirfrags(dfs); for (list::iterator p = dfs.begin(); p != dfs.end(); ++p) if (bounds.count(*p) == 0) q.push_back(*p); } } } if (stat.state == IMPORT_ACKING) { // remove imported caps for (map >::iterator p = stat.peer_exports.begin(); p != stat.peer_exports.end(); ++p) { CInode *in = p->first; for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { Capability *cap = in->get_client_cap(q->first); assert(cap); if (cap->is_new()) in->remove_client_cap(q->first); } in->put(CInode::PIN_IMPORTINGCAPS); } for (map::iterator p = stat.client_map.begin(); p != stat.client_map.end(); ++p) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(p->first.v)); assert(session); session->dec_importing(); } } // log our failure mds->mdlog->start_submit_entry(new EImportFinish(dir, false)); // log failure cache->try_subtree_merge(dir); // NOTE: this may journal subtree map as side effect // bystanders? if (stat.bystanders.empty()) { dout(7) << "no bystanders, finishing reverse now" << dendl; import_reverse_unfreeze(dir); } else { // notify them; wait in aborting state dout(7) << "notifying bystanders of abort" << dendl; import_notify_abort(dir, bounds); stat.state = IMPORT_ABORTING; assert (g_conf->mds_kill_import_at != 10); } } void Migrator::import_notify_finish(CDir *dir, set& bounds) { dout(7) << "import_notify_finish " << *dir << dendl; import_state_t& stat = import_state[dir->dirfrag()]; for (set::iterator p = stat.bystanders.begin(); p != stat.bystanders.end(); ++p) { MExportDirNotify *notify = new MExportDirNotify(dir->dirfrag(), stat.tid, false, pair(stat.peer, mds->get_nodeid()), pair(mds->get_nodeid(), CDIR_AUTH_UNKNOWN)); for (set::iterator i = bounds.begin(); i != bounds.end(); ++i) notify->get_bounds().push_back((*i)->dirfrag()); mds->send_message_mds(notify, *p); } } void Migrator::import_notify_abort(CDir *dir, set& bounds) { dout(7) << "import_notify_abort " << *dir << dendl; import_state_t& stat = import_state[dir->dirfrag()]; for (set::iterator p = stat.bystanders.begin(); p != stat.bystanders.end(); ++p) { MExportDirNotify *notify = new MExportDirNotify(dir->dirfrag(), stat.tid, true, pair(stat.peer, mds->get_nodeid()), pair(stat.peer, CDIR_AUTH_UNKNOWN)); for (set::iterator i = bounds.begin(); i != bounds.end(); ++i) notify->get_bounds().push_back((*i)->dirfrag()); mds->send_message_mds(notify, *p); } } void Migrator::import_reverse_unfreeze(CDir *dir) { assert(dir); dout(7) << "import_reverse_unfreeze " << *dir << dendl; dir->unfreeze_tree(); list ls; mds->queue_waiters(ls); cache->discard_delayed_expire(dir); import_reverse_final(dir); } void Migrator::import_reverse_final(CDir *dir) { dout(7) << "import_reverse_final " << *dir << dendl; // clean up map::iterator it = import_state.find(dir->dirfrag()); if (it->second.mut) { mds->locker->drop_locks(it->second.mut.get()); it->second.mut->cleanup(); } import_state.erase(it); // send pending import_maps? mds->mdcache->maybe_send_pending_resolves(); cache->show_subtrees(); //audit(); // this fails, bc we munge up the subtree map during handle_import_map (resolve phase) } void Migrator::import_logged_start(dirfrag_t df, CDir *dir, int from, map& imported_client_map, map& sseqmap) { map::iterator it = import_state.find(dir->dirfrag()); if (it == import_state.end() || it->second.state != IMPORT_LOGGINGSTART) { dout(7) << "import " << df << " must have aborted" << dendl; mds->server->finish_force_open_sessions(imported_client_map, sseqmap); return; } dout(7) << "import_logged " << *dir << dendl; // note state it->second.state = IMPORT_ACKING; assert (g_conf->mds_kill_import_at != 7); // force open client sessions and finish cap import mds->server->finish_force_open_sessions(imported_client_map, sseqmap, false); it->second.client_map.swap(imported_client_map); map > imported_caps; for (map >::iterator p = it->second.peer_exports.begin(); p != it->second.peer_exports.end(); ++p) { // parameter 'peer' is -1, delay sending cap import messages to client finish_import_inode_caps(p->first, -1, true, p->second, imported_caps[p->first->ino()]); } // send notify's etc. dout(7) << "sending ack for " << *dir << " to old auth mds." << from << dendl; // test surviving observer of a failed migration that did not complete //assert(dir->replica_map.size() < 2 || mds->whoami != 0); MExportDirAck *ack = new MExportDirAck(dir->dirfrag(), it->second.tid); ::encode(imported_caps, ack->imported_caps); mds->send_message_mds(ack, from); assert (g_conf->mds_kill_import_at != 8); cache->show_subtrees(); } /* This function DOES put the passed message before returning*/ void Migrator::handle_export_finish(MExportDirFinish *m) { CDir *dir = cache->get_dirfrag(m->get_dirfrag()); assert(dir); dout(7) << "handle_export_finish on " << *dir << (m->is_last() ? " last" : "") << dendl; map::iterator it = import_state.find(m->get_dirfrag()); assert(it != import_state.end()); assert(it->second.tid == m->get_tid()); import_finish(dir, false, m->is_last()); m->put(); } void Migrator::import_finish(CDir *dir, bool notify, bool last) { dout(7) << "import_finish on " << *dir << dendl; map::iterator it = import_state.find(dir->dirfrag()); assert(it != import_state.end()); assert(it->second.state == IMPORT_ACKING || it->second.state == IMPORT_FINISHING); // log finish assert(g_conf->mds_kill_import_at != 9); if (it->second.state == IMPORT_ACKING) { for (map >::iterator p = it->second.peer_exports.begin(); p != it->second.peer_exports.end(); ++p) { CInode *in = p->first; assert(in->is_auth()); for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(q->first.v)); assert(session); Capability *cap = in->get_client_cap(q->first); assert(cap); cap->merge(q->second, true); mds->mdcache->do_cap_import(session, in, cap, q->second.cap_id, q->second.seq, q->second.mseq - 1, it->second.peer, CEPH_CAP_FLAG_AUTH); } p->second.clear(); in->replica_caps_wanted = 0; } for (map::iterator p = it->second.client_map.begin(); p != it->second.client_map.end(); ++p) { Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(p->first.v)); assert(session); session->dec_importing(); } } if (!last) { assert(it->second.state == IMPORT_ACKING); it->second.state = IMPORT_FINISHING; return; } // clear updated scatterlocks /* for (list::iterator p = import_updated_scatterlocks[dir].begin(); p != import_updated_scatterlocks[dir].end(); ++p) (*p)->clear_updated(); */ // remove pins set bounds; cache->get_subtree_bounds(dir, bounds); if (notify) import_notify_finish(dir, bounds); import_remove_pins(dir, bounds); map > peer_exports; it->second.peer_exports.swap(peer_exports); // clear import state (we're done!) MutationRef mut = it->second.mut; import_state.erase(it); mds->mdlog->start_submit_entry(new EImportFinish(dir, true)); // adjust auth, with possible subtree merge. cache->adjust_subtree_auth(dir, mds->get_nodeid()); cache->try_subtree_merge(dir); // NOTE: this may journal subtree_map as sideffect // process delayed expires cache->process_delayed_expire(dir); // ok now unfreeze (and thus kick waiters) dir->unfreeze_tree(); cache->show_subtrees(); //audit(); // this fails, bc we munge up the subtree map during handle_import_map (resolve phase) if (mut) { mds->locker->drop_locks(mut.get()); mut->cleanup(); } // re-eval imported caps for (map >::iterator p = peer_exports.begin(); p != peer_exports.end(); ++p) { if (p->first->is_auth()) mds->locker->eval(p->first, CEPH_CAP_LOCKS, true); p->first->put(CInode::PIN_IMPORTINGCAPS); } // send pending import_maps? mds->mdcache->maybe_send_pending_resolves(); // did i just import mydir? if (dir->ino() == MDS_INO_MDSDIR(mds->whoami)) cache->populate_mydir(); // is it empty? if (dir->get_num_head_items() == 0 && !dir->inode->is_auth()) { // reexport! export_empty_import(dir); } } void Migrator::decode_import_inode(CDentry *dn, bufferlist::iterator& blp, int oldauth, LogSegment *ls, uint64_t log_offset, map >& peer_exports, list& updated_scatterlocks) { dout(15) << "decode_import_inode on " << *dn << dendl; inodeno_t ino; snapid_t last; ::decode(ino, blp); ::decode(last, blp); bool added = false; CInode *in = cache->get_inode(ino, last); if (!in) { in = new CInode(mds->mdcache, true, 1, last); added = true; } else { in->state_set(CInode::STATE_AUTH); } // state after link -- or not! -sage in->decode_import(blp, ls); // cap imports are noted for later action // note that we are journaled at this log offset in->last_journaled = log_offset; // caps decode_import_inode_caps(in, true, blp, peer_exports); // link before state -- or not! -sage if (dn->get_linkage()->get_inode() != in) { assert(!dn->get_linkage()->get_inode()); dn->dir->link_primary_inode(dn, in); } // add inode? if (added) { cache->add_inode(in); dout(10) << "added " << *in << dendl; } else { dout(10) << " had " << *in << dendl; } if (in->inode.is_dirty_rstat()) in->mark_dirty_rstat(); // clear if dirtyscattered, since we're going to journal this // but not until we _actually_ finish the import... if (in->filelock.is_dirty()) { updated_scatterlocks.push_back(&in->filelock); mds->locker->mark_updated_scatterlock(&in->filelock); } if (in->dirfragtreelock.is_dirty()) { updated_scatterlocks.push_back(&in->dirfragtreelock); mds->locker->mark_updated_scatterlock(&in->dirfragtreelock); } // adjust replica list //assert(!in->is_replica(oldauth)); // not true on failed export in->add_replica(oldauth, CInode::EXPORT_NONCE); if (in->is_replica(mds->get_nodeid())) in->remove_replica(mds->get_nodeid()); } void Migrator::decode_import_inode_caps(CInode *in, bool auth_cap, bufferlist::iterator &blp, map >& peer_exports) { map cap_map; ::decode(cap_map, blp); if (auth_cap) ::decode(in->get_mds_caps_wanted(), blp); if (!cap_map.empty() || (auth_cap && !in->get_mds_caps_wanted().empty())) { peer_exports[in].swap(cap_map); in->get(CInode::PIN_IMPORTINGCAPS); } } void Migrator::finish_import_inode_caps(CInode *in, int peer, bool auth_cap, map &export_map, map &import_map) { for (map::iterator it = export_map.begin(); it != export_map.end(); ++it) { dout(10) << "finish_import_inode_caps for client." << it->first << " on " << *in << dendl; Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(it->first.v)); assert(session); Capability *cap = in->get_client_cap(it->first); if (!cap) { cap = in->add_client_cap(it->first, session); if (peer < 0) cap->mark_new(); } Capability::Import& im = import_map[it->first]; im.cap_id = cap->get_cap_id(); im.mseq = auth_cap ? it->second.mseq : cap->get_mseq(); im.issue_seq = cap->get_last_seq() + 1; if (peer >= 0) { cap->merge(it->second, auth_cap); mds->mdcache->do_cap_import(session, in, cap, it->second.cap_id, it->second.seq, it->second.mseq - 1, peer, auth_cap ? CEPH_CAP_FLAG_AUTH : CEPH_CAP_FLAG_RELEASE); } } if (peer >= 0) { in->replica_caps_wanted = 0; in->put(CInode::PIN_IMPORTINGCAPS); } } int Migrator::decode_import_dir(bufferlist::iterator& blp, int oldauth, CDir *import_root, EImportStart *le, LogSegment *ls, map >& peer_exports, list& updated_scatterlocks, utime_t now) { // set up dir dirfrag_t df; ::decode(df, blp); CInode *diri = cache->get_inode(df.ino); assert(diri); CDir *dir = diri->get_or_open_dirfrag(mds->mdcache, df.frag); assert(dir); dout(7) << "decode_import_dir " << *dir << dendl; // assimilate state dir->decode_import(blp, now, ls); // mark (may already be marked from get_or_open_dir() above) if (!dir->is_auth()) dir->state_set(CDir::STATE_AUTH); // adjust replica list //assert(!dir->is_replica(oldauth)); // not true on failed export dir->add_replica(oldauth, CDir::EXPORT_NONCE); if (dir->is_replica(mds->get_nodeid())) dir->remove_replica(mds->get_nodeid()); // add to journal entry if (le) le->metablob.add_import_dir(dir); int num_imported = 0; // take all waiters on this dir // NOTE: a pass of imported data is guaranteed to get all of my waiters because // a replica's presense in my cache implies/forces it's presense in authority's. list waiters; dir->take_waiting(CDir::WAIT_ANY_MASK, waiters); for (list::iterator it = waiters.begin(); it != waiters.end(); ++it) import_root->add_waiter(CDir::WAIT_UNFREEZE, *it); // UNFREEZE will get kicked both on success or failure dout(15) << "doing contents" << dendl; // contents __u32 nden; ::decode(nden, blp); for (; nden>0; nden--) { num_imported++; // dentry string dname; snapid_t last; ::decode(dname, blp); ::decode(last, blp); CDentry *dn = dir->lookup_exact_snap(dname, last); if (!dn) dn = dir->add_null_dentry(dname, 1, last); dn->decode_import(blp, ls); dn->add_replica(oldauth, CDentry::EXPORT_NONCE); if (dn->is_replica(mds->get_nodeid())) dn->remove_replica(mds->get_nodeid()); // dentry lock in unreadable state can block path traverse if (dn->lock.get_state() != LOCK_SYNC) mds->locker->try_eval(&dn->lock, NULL); dout(15) << "decode_import_dir got " << *dn << dendl; // points to... char icode; ::decode(icode, blp); if (icode == 'N') { // null dentry assert(dn->get_linkage()->is_null()); // fall thru } else if (icode == 'L') { // remote link inodeno_t ino; unsigned char d_type; ::decode(ino, blp); ::decode(d_type, blp); if (dn->get_linkage()->is_remote()) { assert(dn->get_linkage()->get_remote_ino() == ino); } else { dir->link_remote_inode(dn, ino, d_type); } } else if (icode == 'I') { // inode assert(le); decode_import_inode(dn, blp, oldauth, ls, le->get_start_off(), peer_exports, updated_scatterlocks); } // add dentry to journal entry if (le) le->metablob.add_import_dentry(dn); } #ifdef MDS_VERIFY_FRAGSTAT if (dir->is_complete()) dir->verify_fragstat(); #endif dout(7) << "decode_import_dir done " << *dir << dendl; return num_imported; } // authority bystander /* This function DOES put the passed message before returning*/ void Migrator::handle_export_notify(MExportDirNotify *m) { CDir *dir = cache->get_dirfrag(m->get_dirfrag()); int from = m->get_source().num(); pair old_auth = m->get_old_auth(); pair new_auth = m->get_new_auth(); if (!dir) { dout(7) << "handle_export_notify " << old_auth << " -> " << new_auth << " on missing dir " << m->get_dirfrag() << dendl; } else if (dir->authority() != old_auth) { dout(7) << "handle_export_notify old_auth was " << dir->authority() << " != " << old_auth << " -> " << new_auth << " on " << *dir << dendl; } else { dout(7) << "handle_export_notify " << old_auth << " -> " << new_auth << " on " << *dir << dendl; // adjust auth set have; cache->map_dirfrag_set(m->get_bounds(), have); cache->adjust_bounded_subtree_auth(dir, have, new_auth); // induce a merge? cache->try_subtree_merge(dir); } // send ack if (m->wants_ack()) { mds->send_message_mds(new MExportDirNotifyAck(m->get_dirfrag(), m->get_tid()), from); } else { // aborted. no ack. dout(7) << "handle_export_notify no ack requested" << dendl; } m->put(); } /** cap exports **/ void Migrator::export_caps(CInode *in) { int dest = in->authority().first; dout(7) << "export_caps to mds." << dest << " " << *in << dendl; assert(in->is_any_caps()); assert(!in->is_auth()); assert(!in->is_ambiguous_auth()); assert(!in->state_test(CInode::STATE_EXPORTINGCAPS)); MExportCaps *ex = new MExportCaps; ex->ino = in->ino(); encode_export_inode_caps(in, false, ex->cap_bl, ex->client_map); mds->send_message_mds(ex, dest); } class C_M_LoggedImportCaps : public Context { Migrator *migrator; CInode *in; int from; public: map > peer_exports; map client_map; map sseqmap; C_M_LoggedImportCaps(Migrator *m, CInode *i, int f) : migrator(m), in(i), from(f) {} void finish(int r) { migrator->logged_import_caps(in, from, peer_exports, client_map, sseqmap); } }; /* This function DOES put the passed message before returning*/ void Migrator::handle_export_caps(MExportCaps *ex) { dout(10) << "handle_export_caps " << *ex << " from " << ex->get_source() << dendl; CInode *in = cache->get_inode(ex->ino); assert(in); assert(in->is_auth()); // FIXME if (in->is_frozen()) return; C_M_LoggedImportCaps *finish = new C_M_LoggedImportCaps(this, in, ex->get_source().num()); finish->client_map = ex->client_map; // decode new caps bufferlist::iterator blp = ex->cap_bl.begin(); decode_import_inode_caps(in, false, blp, finish->peer_exports); assert(!finish->peer_exports.empty()); // thus, inode is pinned. // journal open client sessions version_t pv = mds->server->prepare_force_open_sessions(finish->client_map, finish->sseqmap); ESessions *le = new ESessions(pv, ex->client_map); mds->mdlog->start_entry(le); mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(finish); mds->mdlog->flush(); ex->put(); } void Migrator::logged_import_caps(CInode *in, int from, map >& peer_exports, map& client_map, map& sseqmap) { dout(10) << "logged_import_caps on " << *in << dendl; // see export_go() vs export_go_synced() assert(in->is_auth()); // force open client sessions and finish cap import mds->server->finish_force_open_sessions(client_map, sseqmap); map imported_caps; assert(peer_exports.count(in)); // clients will release caps from the exporter when they receive the cap import message. finish_import_inode_caps(in, from, false, peer_exports[in], imported_caps); mds->locker->eval(in, CEPH_CAP_LOCKS, true); } ceph-0.80.11/src/mds/SnapServer.cc0000664000175100017510000002140512623076744020650 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "SnapServer.h" #include "MDS.h" #include "osd/OSDMap.h" #include "mon/MonClient.h" #include "include/types.h" #include "messages/MMDSTableRequest.h" #include "messages/MRemoveSnaps.h" #include "msg/Messenger.h" #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".snap " void SnapServer::reset_state() { last_snap = 1; /* snapid 1 reserved for initial root snaprealm */ snaps.clear(); need_to_purge.clear(); } // SERVER void SnapServer::_prepare(bufferlist &bl, uint64_t reqid, int bymds) { bufferlist::iterator p = bl.begin(); __u32 op; ::decode(op, p); switch (op) { case TABLE_OP_CREATE: { version++; SnapInfo info; ::decode(info.ino, p); if (!p.end()) { ::decode(info.name, p); ::decode(info.stamp, p); info.snapid = ++last_snap; pending_create[version] = info; dout(10) << "prepare v" << version << " create " << info << dendl; } else { pending_noop.insert(version); dout(10) << "prepare v" << version << " noop" << dendl; } bl.clear(); ::encode(last_snap, bl); } break; case TABLE_OP_DESTROY: { inodeno_t ino; snapid_t snapid; ::decode(ino, p); // not used, currently. ::decode(snapid, p); version++; // bump last_snap... we use it as a version value on the snaprealm. ++last_snap; pending_destroy[version] = pair(snapid, last_snap); dout(10) << "prepare v" << version << " destroy " << snapid << " seq " << last_snap << dendl; bl.clear(); ::encode(last_snap, bl); } break; default: assert(0); } //dump(); } bool SnapServer::_is_prepared(version_t tid) { return pending_create.count(tid) || pending_destroy.count(tid); } bool SnapServer::_commit(version_t tid, MMDSTableRequest *req) { if (pending_create.count(tid)) { dout(7) << "commit " << tid << " create " << pending_create[tid] << dendl; snaps[pending_create[tid].snapid] = pending_create[tid]; pending_create.erase(tid); } else if (pending_destroy.count(tid)) { snapid_t sn = pending_destroy[tid].first; snapid_t seq = pending_destroy[tid].second; dout(7) << "commit " << tid << " destroy " << sn << " seq " << seq << dendl; snaps.erase(sn); for (set::const_iterator p = mds->mdsmap->get_data_pools().begin(); p != mds->mdsmap->get_data_pools().end(); ++p) { need_to_purge[*p].insert(sn); need_to_purge[*p].insert(seq); } pending_destroy.erase(tid); } else if (pending_noop.count(tid)) { dout(7) << "commit " << tid << " noop" << dendl; pending_noop.erase(tid); } else assert(0); // bump version. version++; //dump(); return true; } void SnapServer::_rollback(version_t tid) { if (pending_create.count(tid)) { dout(7) << "rollback " << tid << " create " << pending_create[tid] << dendl; pending_create.erase(tid); } else if (pending_destroy.count(tid)) { dout(7) << "rollback " << tid << " destroy " << pending_destroy[tid] << dendl; pending_destroy.erase(tid); } else if (pending_noop.count(tid)) { dout(7) << "rollback " << tid << " noop" << dendl; pending_noop.erase(tid); } else assert(0); // bump version. version++; //dump(); } void SnapServer::_server_update(bufferlist& bl) { bufferlist::iterator p = bl.begin(); map > purge; ::decode(purge, p); dout(7) << "_server_update purged " << purge << dendl; for (map >::iterator p = purge.begin(); p != purge.end(); ++p) { for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) need_to_purge[p->first].erase(*q); if (need_to_purge[p->first].empty()) need_to_purge.erase(p->first); } version++; } void SnapServer::handle_query(MMDSTableRequest *req) { /* bufferlist::iterator p = req->bl.begin(); inodeno_t curino; ::decode(curino, p); dout(7) << "handle_lookup " << *req << " ino " << curino << dendl; vector trace; while (true) { assert(anchor_map.count(curino) == 1); Anchor &anchor = anchor_map[curino]; dout(10) << "handle_lookup adding " << anchor << dendl; trace.insert(trace.begin(), anchor); // lame FIXME if (anchor.dirino < MDS_INO_BASE) break; curino = anchor.dirino; } // reply MMDSTableRequest *reply = new MMDSTableRequest(table, TABLE_OP_QUERY_REPLY, req->reqid, version); ::encode(curino, req->bl); ::encode(trace, req->bl); mds->send_message_mds(reply, req->get_source().num()); */ req->put(); } void SnapServer::check_osd_map(bool force) { if (!force && version == last_checked_osdmap) { dout(10) << "check_osd_map - version unchanged" << dendl; return; } dout(10) << "check_osd_map need_to_purge=" << need_to_purge << dendl; map > all_purge; map > all_purged; for (map >::iterator p = need_to_purge.begin(); p != need_to_purge.end(); ++p) { int id = p->first; const pg_pool_t *pi = mds->osdmap->get_pg_pool(id); for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { if (pi->is_removed_snap(*q)) { dout(10) << " osdmap marks " << *q << " as removed" << dendl; all_purged[id].push_back(*q); } else { all_purge[id].push_back(*q); } } } if (!all_purged.empty()) { // prepare to remove from need_to_purge list bufferlist bl; ::encode(all_purged, bl); do_server_update(bl); } if (!all_purge.empty()) { dout(10) << "requesting removal of " << all_purge << dendl; MRemoveSnaps *m = new MRemoveSnaps(all_purge); mds->monc->send_mon_message(m); } last_checked_osdmap = version; } void SnapServer::dump(Formatter *f) const { f->open_object_section("snapserver"); f->dump_int("last_snap", last_snap.val); f->open_array_section("pending_noop"); for(set::const_iterator i = pending_noop.begin(); i != pending_noop.end(); ++i) { f->dump_unsigned("version", *i); } f->close_section(); f->open_array_section("snaps"); for (map::const_iterator i = snaps.begin(); i != snaps.end(); ++i) { f->open_object_section("snap"); i->second.dump(f); f->close_section(); } f->close_section(); f->open_object_section("need_to_purge"); for (map >::const_iterator i = need_to_purge.begin(); i != need_to_purge.end(); ++i) { stringstream pool_id; pool_id << i->first; f->open_array_section(pool_id.str().c_str()); for (set::const_iterator s = i->second.begin(); s != i->second.end(); ++s) { f->dump_unsigned("snapid", s->val); } f->close_section(); } f->close_section(); f->open_array_section("pending_create"); for(map::const_iterator i = pending_create.begin(); i != pending_create.end(); ++i) { f->open_object_section("snap"); f->dump_unsigned("version", i->first); f->open_object_section("snapinfo"); i->second.dump(f); f->close_section(); f->close_section(); } f->close_section(); f->open_array_section("pending_destroy"); for(map >::const_iterator i = pending_destroy.begin(); i != pending_destroy.end(); ++i) { f->open_object_section("snap"); f->dump_unsigned("version", i->first); f->dump_unsigned("removed_snap", i->second.first); f->dump_unsigned("seq", i->second.second); f->close_section(); } f->close_section(); f->close_section(); } void SnapServer::generate_test_instances(list& ls) { list snapinfo_instances; SnapInfo::generate_test_instances(snapinfo_instances); SnapInfo populated_snapinfo = *(snapinfo_instances.back()); for (list::iterator i = snapinfo_instances.begin(); i != snapinfo_instances.end(); ++i) { delete *i; } SnapServer *blank = new SnapServer(); ls.push_back(blank); SnapServer *populated = new SnapServer(); populated->last_snap = 123; populated->snaps[456] = populated_snapinfo; populated->need_to_purge[2].insert(012); populated->pending_create[234] = populated_snapinfo; populated->pending_destroy[345].first = 567; populated->pending_destroy[345].second = 768; populated->pending_noop.insert(890); ls.push_back(populated); } ceph-0.80.11/src/mds/SnapRealm.h0000664000175100017510000001021412623076744020300 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_SNAPREALM_H #define CEPH_MDS_SNAPREALM_H #include "mdstypes.h" #include "snap.h" #include "include/xlist.h" #include "include/elist.h" #include "common/snap_types.h" struct SnapRealm { // realm state sr_t srnode; // in-memory state MDCache *mdcache; CInode *inode; bool open; // set to true once all past_parents are opened SnapRealm *parent; set open_children; // active children that are currently open map open_past_parents; // these are explicitly pinned. // cache snapid_t cached_seq; // max seq over self and all past+present parents. snapid_t cached_last_created; // max last_created over all past+present parents snapid_t cached_last_destroyed; set cached_snaps; SnapContext cached_snap_context; bufferlist cached_snap_trace; elist inodes_with_caps; // for efficient realm splits map* > client_caps; // to identify clients who need snap notifications SnapRealm(MDCache *c, CInode *in) : srnode(), mdcache(c), inode(in), open(false), parent(0), inodes_with_caps(0) { } bool exists(const string &name) { for (map::iterator p = srnode.snaps.begin(); p != srnode.snaps.end(); ++p) { if (p->second.name == name) return true; } return false; } bool _open_parents(Context *retryorfinish, snapid_t first=1, snapid_t last=CEPH_NOSNAP); bool open_parents(Context *retryorfinish) { if (!_open_parents(retryorfinish)) return false; delete retryorfinish; return true; } bool have_past_parents_open(snapid_t first=1, snapid_t last=CEPH_NOSNAP); void add_open_past_parent(SnapRealm *parent); void close_parents(); void prune_past_parents(); bool has_past_parents() { return !srnode.past_parents.empty(); } void build_snap_set(set& s, snapid_t& max_seq, snapid_t& max_last_created, snapid_t& max_last_destroyed, snapid_t first, snapid_t last); void get_snap_info(map& infomap, snapid_t first=0, snapid_t last=CEPH_NOSNAP); const bufferlist& get_snap_trace(); void build_snap_trace(bufferlist& snapbl); const string& get_snapname(snapid_t snapid, inodeno_t atino); snapid_t resolve_snapname(const string &name, inodeno_t atino, snapid_t first=0, snapid_t last=CEPH_NOSNAP); void check_cache(); const set& get_snaps(); const SnapContext& get_snap_context(); void invalidate_cached_snaps() { cached_seq = 0; } snapid_t get_last_created() { check_cache(); return cached_last_created; } snapid_t get_last_destroyed() { check_cache(); return cached_last_destroyed; } snapid_t get_newest_snap() { check_cache(); if (cached_snaps.empty()) return 0; else return *cached_snaps.rbegin(); } snapid_t get_newest_seq() { check_cache(); return cached_seq; } snapid_t get_snap_following(snapid_t follows) { check_cache(); set s = get_snaps(); set::iterator p = s.upper_bound(follows); if (p != s.end()) return *p; return CEPH_NOSNAP; } void adjust_parent(); void split_at(SnapRealm *child); void join(SnapRealm *child); void add_cap(client_t client, Capability *cap) { if (client_caps.count(client) == 0) client_caps[client] = new xlist; client_caps[client]->push_back(&cap->item_snaprealm_caps); } void remove_cap(client_t client, Capability *cap) { cap->item_snaprealm_caps.remove_myself(); if (client_caps[client]->empty()) { delete client_caps[client]; client_caps.erase(client); } } }; ostream& operator<<(ostream& out, const SnapRealm &realm); #endif ceph-0.80.11/src/mds/InoTable.cc0000664000175100017510000001200612623076744020252 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "InoTable.h" #include "MDS.h" #include "include/types.h" #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << "." << table_name << ": " void InoTable::reset_state() { // use generic range. FIXME THIS IS CRAP free.clear(); //#ifdef __LP64__ uint64_t start = (uint64_t)(mds->get_nodeid()+1) << 40; uint64_t end = ((uint64_t)(mds->get_nodeid()+2) << 40) - 1; //#else //# warning this looks like a 32-bit system, using small inode numbers. // uint64_t start = (uint64_t)(mds->get_nodeid()+1) << 25; // uint64_t end = ((uint64_t)(mds->get_nodeid()+2) << 25) - 1; //#endif free.insert(start, end); projected_free = free; } inodeno_t InoTable::project_alloc_id(inodeno_t id) { dout(10) << "project_alloc_id " << id << " to " << projected_free << "/" << free << dendl; assert(is_active()); if (!id) id = projected_free.range_start(); projected_free.erase(id); ++projected_version; return id; } void InoTable::apply_alloc_id(inodeno_t id) { dout(10) << "apply_alloc_id " << id << " to " << projected_free << "/" << free << dendl; free.erase(id); ++version; } void InoTable::project_alloc_ids(interval_set& ids, int want) { assert(is_active()); while (want > 0) { inodeno_t start = projected_free.range_start(); inodeno_t end = projected_free.end_after(start); inodeno_t num = end - start; if (num > (inodeno_t)want) num = want; projected_free.erase(start, num); ids.insert(start, num); want -= num; } dout(10) << "project_alloc_ids " << ids << " to " << projected_free << "/" << free << dendl; ++projected_version; } void InoTable::apply_alloc_ids(interval_set& ids) { dout(10) << "apply_alloc_ids " << ids << " to " << projected_free << "/" << free << dendl; free.subtract(ids); ++version; } void InoTable::project_release_ids(interval_set& ids) { dout(10) << "project_release_ids " << ids << " to " << projected_free << "/" << free << dendl; projected_free.insert(ids); ++projected_version; } void InoTable::apply_release_ids(interval_set& ids) { dout(10) << "apply_release_ids " << ids << " to " << projected_free << "/" << free << dendl; free.insert(ids); ++version; } // void InoTable::replay_alloc_id(inodeno_t id) { dout(10) << "replay_alloc_id " << id << dendl; if (free.contains(id)) { free.erase(id); projected_free.erase(id); } else { mds->clog.error() << "journal replay alloc " << id << " not in free " << free << "\n"; } projected_version = ++version; } void InoTable::replay_alloc_ids(interval_set& ids) { dout(10) << "replay_alloc_ids " << ids << dendl; interval_set is; is.intersection_of(free, ids); if (is == ids) { free.subtract(ids); projected_free.subtract(ids); } else { mds->clog.error() << "journal replay alloc " << ids << ", only " << is << " is in free " << free << "\n"; free.subtract(is); projected_free.subtract(is); } projected_version = ++version; } void InoTable::replay_release_ids(interval_set& ids) { dout(10) << "replay_release_ids " << ids << dendl; free.insert(ids); projected_free.insert(ids); projected_version = ++version; } void InoTable::replay_reset() { dout(10) << "replay_reset " << free << dendl; skip_inos(inodeno_t(10000000)); // a lot! projected_free = free; projected_version = ++version; } void InoTable::skip_inos(inodeno_t i) { dout(10) << "skip_inos was " << free << dendl; inodeno_t first = free.range_start(); inodeno_t last = first + i; interval_set s; s.insert(first, last); s.intersection_of(free); free.subtract(s); projected_free = free; projected_version = ++version; dout(10) << "skip_inos now " << free << dendl; } void InoTable::dump(Formatter *f) const { f->open_object_section("inotable"); f->open_array_section("projected_free"); for (interval_set::const_iterator i = projected_free.begin(); i != projected_free.end(); ++i) { f->open_object_section("range"); f->dump_int("start", (*i).first); f->dump_int("len", (*i).second); f->close_section(); } f->close_section(); f->open_array_section("free"); for (interval_set::const_iterator i = free.begin(); i != free.end(); ++i) { f->open_object_section("range"); f->dump_int("start", (*i).first); f->dump_int("len", (*i).second); f->close_section(); } f->close_section(); f->close_section(); } void InoTable::generate_test_instances(list& ls) { ls.push_back(new InoTable()); } ceph-0.80.11/src/mds/mdstypes.h0000664000175100017510000011471512623076744020301 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_MDSTYPES_H #define CEPH_MDSTYPES_H #include "include/int_types.h" #include #include #include #include using namespace std; #include "common/config.h" #include "common/Clock.h" #include "common/DecayCounter.h" #include "include/Context.h" #include "include/frag.h" #include "include/xlist.h" #include "include/interval_set.h" #include "inode_backtrace.h" #include #include "include/assert.h" #include "include/hash_namespace.h" #define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011" #define MDS_REF_SET // define me for improved debug output, sanity checking //#define MDS_AUTHPIN_SET // define me for debugging auth pin leaks //#define MDS_VERIFY_FRAGSTAT // do do (slow) sanity checking on frags #define MDS_PORT_CACHE 0x200 #define MDS_PORT_LOCKER 0x300 #define MDS_PORT_MIGRATOR 0x400 // FIXME: this should not be hardcoded #define MDS_DATA_POOL 0 #define MDS_METADATA_POOL 1 #define MAX_MDS 0x100 #define NUM_STRAY 10 #define MDS_INO_ROOT 1 // No longer created but recognised in existing filesystems // so that we don't try to fragment it. #define MDS_INO_CEPH 2 #define MDS_INO_MDSDIR_OFFSET (1*MAX_MDS) #define MDS_INO_LOG_OFFSET (2*MAX_MDS) #define MDS_INO_STRAY_OFFSET (6*MAX_MDS) #define MDS_INO_SYSTEM_BASE ((6*MAX_MDS) + (MAX_MDS * NUM_STRAY)) #define MDS_INO_STRAY(x,i) (MDS_INO_STRAY_OFFSET+((((unsigned)(x))*NUM_STRAY)+((unsigned)(i)))) #define MDS_INO_MDSDIR(x) (MDS_INO_MDSDIR_OFFSET+((unsigned)x)) #define MDS_INO_IS_STRAY(i) ((i) >= MDS_INO_STRAY_OFFSET && (i) < (MDS_INO_STRAY_OFFSET+(MAX_MDS*NUM_STRAY))) #define MDS_INO_IS_MDSDIR(i) ((i) >= MDS_INO_MDSDIR_OFFSET && (i) < (MDS_INO_MDSDIR_OFFSET+MAX_MDS)) #define MDS_INO_IS_BASE(i) (MDS_INO_ROOT == (i) || MDS_INO_IS_MDSDIR(i)) #define MDS_INO_STRAY_OWNER(i) (signed (((unsigned (i)) - MDS_INO_STRAY_OFFSET) / NUM_STRAY)) #define MDS_INO_STRAY_INDEX(i) (((unsigned (i)) - MDS_INO_STRAY_OFFSET) % NUM_STRAY) #define MDS_TRAVERSE_FORWARD 1 #define MDS_TRAVERSE_DISCOVER 2 // skips permissions checks etc. #define MDS_TRAVERSE_DISCOVERXLOCK 3 // succeeds on (foreign?) null, xlocked dentries. extern long g_num_ino, g_num_dir, g_num_dn, g_num_cap; extern long g_num_inoa, g_num_dira, g_num_dna, g_num_capa; extern long g_num_inos, g_num_dirs, g_num_dns, g_num_caps; // CAPS inline string gcap_string(int cap) { string s; if (cap & CEPH_CAP_GSHARED) s += "s"; if (cap & CEPH_CAP_GEXCL) s += "x"; if (cap & CEPH_CAP_GCACHE) s += "c"; if (cap & CEPH_CAP_GRD) s += "r"; if (cap & CEPH_CAP_GWR) s += "w"; if (cap & CEPH_CAP_GBUFFER) s += "b"; if (cap & CEPH_CAP_GWREXTEND) s += "a"; if (cap & CEPH_CAP_GLAZYIO) s += "l"; return s; } inline string ccap_string(int cap) { string s; if (cap & CEPH_CAP_PIN) s += "p"; int a = (cap >> CEPH_CAP_SAUTH) & 3; if (a) s += 'A' + gcap_string(a); a = (cap >> CEPH_CAP_SLINK) & 3; if (a) s += 'L' + gcap_string(a); a = (cap >> CEPH_CAP_SXATTR) & 3; if (a) s += 'X' + gcap_string(a); a = cap >> CEPH_CAP_SFILE; if (a) s += 'F' + gcap_string(a); if (s.length() == 0) s = "-"; return s; } struct scatter_info_t { version_t version; scatter_info_t() : version(0) {} }; struct frag_info_t : public scatter_info_t { // this frag utime_t mtime; int64_t nfiles; // files int64_t nsubdirs; // subdirs frag_info_t() : nfiles(0), nsubdirs(0) {} int64_t size() const { return nfiles + nsubdirs; } void zero() { *this = frag_info_t(); } // *this += cur - acc; void add_delta(const frag_info_t &cur, frag_info_t &acc, bool& touched_mtime) { if (!(cur.mtime == acc.mtime)) { mtime = cur.mtime; touched_mtime = true; } nfiles += cur.nfiles - acc.nfiles; nsubdirs += cur.nsubdirs - acc.nsubdirs; } void add(const frag_info_t& other) { if (other.mtime > mtime) mtime = other.mtime; nfiles += other.nfiles; nsubdirs += other.nsubdirs; } void encode(bufferlist &bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(frag_info_t) inline bool operator==(const frag_info_t &l, const frag_info_t &r) { return memcmp(&l, &r, sizeof(l)) == 0; } ostream& operator<<(ostream &out, const frag_info_t &f); struct nest_info_t : public scatter_info_t { // this frag + children utime_t rctime; int64_t rbytes; int64_t rfiles; int64_t rsubdirs; int64_t rsize() const { return rfiles + rsubdirs; } int64_t ranchors; // for dirstat, includes inode's anchored flag. int64_t rsnaprealms; nest_info_t() : rbytes(0), rfiles(0), rsubdirs(0), ranchors(0), rsnaprealms(0) {} void zero() { *this = nest_info_t(); } void sub(const nest_info_t &other) { add(other, -1); } void add(const nest_info_t &other, int fac=1) { if (other.rctime > rctime) rctime = other.rctime; rbytes += fac*other.rbytes; rfiles += fac*other.rfiles; rsubdirs += fac*other.rsubdirs; ranchors += fac*other.ranchors; rsnaprealms += fac*other.rsnaprealms; } // *this += cur - acc; void add_delta(const nest_info_t &cur, nest_info_t &acc) { if (cur.rctime > rctime) rctime = cur.rctime; rbytes += cur.rbytes - acc.rbytes; rfiles += cur.rfiles - acc.rfiles; rsubdirs += cur.rsubdirs - acc.rsubdirs; ranchors += cur.ranchors - acc.ranchors; rsnaprealms += cur.rsnaprealms - acc.rsnaprealms; } void encode(bufferlist &bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(nest_info_t) inline bool operator==(const nest_info_t &l, const nest_info_t &r) { return memcmp(&l, &r, sizeof(l)) == 0; } ostream& operator<<(ostream &out, const nest_info_t &n); struct vinodeno_t { inodeno_t ino; snapid_t snapid; vinodeno_t() {} vinodeno_t(inodeno_t i, snapid_t s) : ino(i), snapid(s) {} void encode(bufferlist& bl) const { ::encode(ino, bl); ::encode(snapid, bl); } void decode(bufferlist::iterator& p) { ::decode(ino, p); ::decode(snapid, p); } }; WRITE_CLASS_ENCODER(vinodeno_t) inline bool operator==(const vinodeno_t &l, const vinodeno_t &r) { return l.ino == r.ino && l.snapid == r.snapid; } inline bool operator!=(const vinodeno_t &l, const vinodeno_t &r) { return !(l == r); } inline bool operator<(const vinodeno_t &l, const vinodeno_t &r) { return l.ino < r.ino || (l.ino == r.ino && l.snapid < r.snapid); } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const vinodeno_t &vino) const { hash H; hash I; return H(vino.ino) ^ I(vino.snapid); } }; CEPH_HASH_NAMESPACE_END inline ostream& operator<<(ostream &out, const vinodeno_t &vino) { out << vino.ino; if (vino.snapid == CEPH_NOSNAP) out << ".head"; else if (vino.snapid) out << '.' << vino.snapid; return out; } /* * client_writeable_range_t */ struct client_writeable_range_t { struct byte_range_t { uint64_t first, last; // interval client can write to byte_range_t() : first(0), last(0) {} }; byte_range_t range; snapid_t follows; // aka "data+metadata flushed thru" client_writeable_range_t() : follows(0) {} void encode(bufferlist &bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; inline void decode(client_writeable_range_t::byte_range_t& range, bufferlist::iterator& bl) { ::decode(range.first, bl); ::decode(range.last, bl); } WRITE_CLASS_ENCODER(client_writeable_range_t) ostream& operator<<(ostream& out, const client_writeable_range_t& r); inline bool operator==(const client_writeable_range_t& l, const client_writeable_range_t& r) { return l.range.first == r.range.first && l.range.last == r.range.last && l.follows == r.follows; } /* * inode_t */ struct inode_t { // base (immutable) inodeno_t ino; uint32_t rdev; // if special file // affected by any inode change... utime_t ctime; // inode change time // perm (namespace permissions) uint32_t mode; uid_t uid; gid_t gid; // nlink int32_t nlink; bool anchored; // auth only? // file (data access) ceph_dir_layout dir_layout; // [dir only] ceph_file_layout layout; vector old_pools; uint64_t size; // on directory, # dentries uint64_t max_size_ever; // max size the file has ever been uint32_t truncate_seq; uint64_t truncate_size, truncate_from; uint32_t truncate_pending; utime_t mtime; // file data modify time. utime_t atime; // file data access time. uint32_t time_warp_seq; // count of (potential) mtime/atime timewarps (i.e., utimes()) bufferlist inline_data; version_t inline_version; map client_ranges; // client(s) can write to these ranges // dirfrag, recursive accountin frag_info_t dirstat; // protected by my filelock nest_info_t rstat; // protected by my nestlock nest_info_t accounted_rstat; // protected by parent's nestlock // special stuff version_t version; // auth only version_t file_data_version; // auth only version_t xattr_version; version_t backtrace_version; inode_t() : ino(0), rdev(0), mode(0), uid(0), gid(0), nlink(0), anchored(false), size(0), max_size_ever(0), truncate_seq(0), truncate_size(0), truncate_from(0), truncate_pending(0), time_warp_seq(0), inline_version(1), version(0), file_data_version(0), xattr_version(0), backtrace_version(0) { clear_layout(); memset(&dir_layout, 0, sizeof(dir_layout)); } // file type bool is_symlink() const { return (mode & S_IFMT) == S_IFLNK; } bool is_dir() const { return (mode & S_IFMT) == S_IFDIR; } bool is_file() const { return (mode & S_IFMT) == S_IFREG; } bool is_truncating() const { return (truncate_pending > 0); } void truncate(uint64_t old_size, uint64_t new_size) { assert(new_size < old_size); if (old_size > max_size_ever) max_size_ever = old_size; truncate_from = old_size; size = new_size; rstat.rbytes = new_size; truncate_size = size; truncate_seq++; truncate_pending++; } bool has_layout() const { // why on earth is there no converse of memchr() in string.h? const char *p = (const char *)&layout; for (size_t i = 0; i < sizeof(layout); i++) if (p[i] != '\0') return true; return false; } void clear_layout() { memset(&layout, 0, sizeof(layout)); } uint64_t get_layout_size_increment() { return (uint64_t)layout.fl_object_size * (uint64_t)layout.fl_stripe_count; } bool is_dirty_rstat() const { return !(rstat == accounted_rstat); } uint64_t get_max_size() const { uint64_t max = 0; for (map::const_iterator p = client_ranges.begin(); p != client_ranges.end(); ++p) if (p->second.range.last > max) max = p->second.range.last; return max; } void set_max_size(uint64_t new_max) { if (new_max == 0) { client_ranges.clear(); } else { for (map::iterator p = client_ranges.begin(); p != client_ranges.end(); ++p) p->second.range.last = new_max; } } void trim_client_ranges(snapid_t last) { map::iterator p = client_ranges.begin(); while (p != client_ranges.end()) { if (p->second.follows >= last) client_ranges.erase(p++); else ++p; } } bool is_backtrace_updated() { return backtrace_version == version; } void update_backtrace(version_t pv=0) { backtrace_version = pv ? pv : version; } void add_old_pool(int64_t l) { backtrace_version = version; old_pools.push_back(l); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(inode_t) /* * old_inode_t */ struct old_inode_t { snapid_t first; inode_t inode; map xattrs; void encode(bufferlist &bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(old_inode_t) /* * like an inode, but for a dir frag */ struct fnode_t { version_t version; snapid_t snap_purged_thru; // the max_last_destroy snapid we've been purged thru frag_info_t fragstat, accounted_fragstat; nest_info_t rstat, accounted_rstat; void encode(bufferlist &bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); fnode_t() : version(0) {}; }; WRITE_CLASS_ENCODER(fnode_t) struct old_rstat_t { snapid_t first; nest_info_t rstat, accounted_rstat; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(old_rstat_t) inline ostream& operator<<(ostream& out, const old_rstat_t& o) { return out << "old_rstat(first " << o.first << " " << o.rstat << " " << o.accounted_rstat << ")"; } /* * session_info_t */ struct session_info_t { entity_inst_t inst; map completed_requests; interval_set prealloc_inos; // preallocated, ready to use. interval_set used_inos; // journaling use client_t get_client() const { return client_t(inst.name.num()); } void clear_meta() { prealloc_inos.clear(); used_inos.clear(); completed_requests.clear(); } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(session_info_t) // ======= // dentries struct dentry_key_t { snapid_t snapid; const char *name; dentry_key_t() : snapid(0), name(0) {} dentry_key_t(snapid_t s, const char *n) : snapid(s), name(n) {} // encode into something that can be decoded as a string. // name_ (head) or name_%x (!head) void encode(bufferlist& bl) const { string key; encode(key); ::encode(key, bl); } void encode(string& key) const { char b[20]; if (snapid != CEPH_NOSNAP) { uint64_t val(snapid); snprintf(b, sizeof(b), "%" PRIx64, val); } else { snprintf(b, sizeof(b), "%s", "head"); } ostringstream oss; oss << name << "_" << b; key = oss.str(); } static void decode_helper(bufferlist::iterator& bl, string& nm, snapid_t& sn) { string key; ::decode(key, bl); decode_helper(key, nm, sn); } static void decode_helper(const string& key, string& nm, snapid_t& sn) { size_t i = key.find_last_of('_'); assert(i != string::npos); if (key.compare(i+1, string::npos, "head") == 0) { // name_head sn = CEPH_NOSNAP; } else { // name_%x long long unsigned x = 0; sscanf(key.c_str() + i + 1, "%llx", &x); sn = x; } nm = string(key.c_str(), i); } }; inline ostream& operator<<(ostream& out, const dentry_key_t &k) { return out << "(" << k.name << "," << k.snapid << ")"; } inline bool operator<(const dentry_key_t& k1, const dentry_key_t& k2) { /* * order by name, then snap */ int c = strcmp(k1.name, k2.name); return c < 0 || (c == 0 && k1.snapid < k2.snapid); } /* * string_snap_t is a simple (string, snapid_t) pair */ struct string_snap_t { string name; snapid_t snapid; string_snap_t() {} string_snap_t(const string& n, snapid_t s) : name(n), snapid(s) {} string_snap_t(const char *n, snapid_t s) : name(n), snapid(s) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(string_snap_t) inline bool operator<(const string_snap_t& l, const string_snap_t& r) { int c = strcmp(l.name.c_str(), r.name.c_str()); return c < 0 || (c == 0 && l.snapid < r.snapid); } inline ostream& operator<<(ostream& out, const string_snap_t &k) { return out << "(" << k.name << "," << k.snapid << ")"; } /* * mds_table_pending_t * * mds's requesting any pending ops. child needs to encode the corresponding * pending mutation state in the table. */ struct mds_table_pending_t { uint64_t reqid; __s32 mds; version_t tid; mds_table_pending_t() : reqid(0), mds(0), tid(0) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(mds_table_pending_t) // ========= // requests struct metareqid_t { entity_name_t name; uint64_t tid; metareqid_t() : tid(0) {} metareqid_t(entity_name_t n, ceph_tid_t t) : name(n), tid(t) {} void encode(bufferlist& bl) const { ::encode(name, bl); ::encode(tid, bl); } void decode(bufferlist::iterator &p) { ::decode(name, p); ::decode(tid, p); } }; WRITE_CLASS_ENCODER(metareqid_t) inline ostream& operator<<(ostream& out, const metareqid_t& r) { return out << r.name << ":" << r.tid; } inline bool operator==(const metareqid_t& l, const metareqid_t& r) { return (l.name == r.name) && (l.tid == r.tid); } inline bool operator!=(const metareqid_t& l, const metareqid_t& r) { return (l.name != r.name) || (l.tid != r.tid); } inline bool operator<(const metareqid_t& l, const metareqid_t& r) { return (l.name < r.name) || (l.name == r.name && l.tid < r.tid); } inline bool operator<=(const metareqid_t& l, const metareqid_t& r) { return (l.name < r.name) || (l.name == r.name && l.tid <= r.tid); } inline bool operator>(const metareqid_t& l, const metareqid_t& r) { return !(l <= r); } inline bool operator>=(const metareqid_t& l, const metareqid_t& r) { return !(l < r); } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const metareqid_t &r) const { hash H; return H(r.name.num()) ^ H(r.name.type()) ^ H(r.tid); } }; CEPH_HASH_NAMESPACE_END // cap info for client reconnect struct cap_reconnect_t { string path; mutable ceph_mds_cap_reconnect capinfo; bufferlist flockbl; cap_reconnect_t() { memset(&capinfo, 0, sizeof(capinfo)); } cap_reconnect_t(uint64_t cap_id, inodeno_t pino, const string& p, int w, int i, inodeno_t sr, bufferlist& lb) : path(p) { capinfo.cap_id = cap_id; capinfo.wanted = w; capinfo.issued = i; capinfo.snaprealm = sr; capinfo.pathbase = pino; capinfo.flock_len = 0; flockbl.claim(lb); } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void encode_old(bufferlist& bl) const; void decode_old(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cap_reconnect_t) // compat for pre-FLOCK feature struct old_ceph_mds_cap_reconnect { __le64 cap_id; __le32 wanted; __le32 issued; __le64 old_size; struct ceph_timespec old_mtime, old_atime; __le64 snaprealm; __le64 pathbase; /* base ino for our path to this ino */ } __attribute__ ((packed)); WRITE_RAW_ENCODER(old_ceph_mds_cap_reconnect) struct old_cap_reconnect_t { string path; old_ceph_mds_cap_reconnect capinfo; const old_cap_reconnect_t& operator=(const cap_reconnect_t& n) { path = n.path; capinfo.cap_id = n.capinfo.cap_id; capinfo.wanted = n.capinfo.wanted; capinfo.issued = n.capinfo.issued; capinfo.snaprealm = n.capinfo.snaprealm; capinfo.pathbase = n.capinfo.pathbase; return *this; } operator cap_reconnect_t() { cap_reconnect_t n; n.path = path; n.capinfo.cap_id = capinfo.cap_id; n.capinfo.wanted = capinfo.wanted; n.capinfo.issued = capinfo.issued; n.capinfo.snaprealm = capinfo.snaprealm; n.capinfo.pathbase = capinfo.pathbase; return n; } void encode(bufferlist& bl) const { ::encode(path, bl); ::encode(capinfo, bl); } void decode(bufferlist::iterator& bl) { ::decode(path, bl); ::decode(capinfo, bl); } }; WRITE_CLASS_ENCODER(old_cap_reconnect_t) // ================================================================ // dir frag struct dirfrag_t { inodeno_t ino; frag_t frag; dirfrag_t() : ino(0) { } dirfrag_t(inodeno_t i, frag_t f) : ino(i), frag(f) { } void encode(bufferlist& bl) const { ::encode(ino, bl); ::encode(frag, bl); } void decode(bufferlist::iterator& bl) { ::decode(ino, bl); ::decode(frag, bl); } }; WRITE_CLASS_ENCODER(dirfrag_t) inline ostream& operator<<(ostream& out, const dirfrag_t df) { out << df.ino; if (!df.frag.is_root()) out << "." << df.frag; return out; } inline bool operator<(dirfrag_t l, dirfrag_t r) { if (l.ino < r.ino) return true; if (l.ino == r.ino && l.frag < r.frag) return true; return false; } inline bool operator==(dirfrag_t l, dirfrag_t r) { return l.ino == r.ino && l.frag == r.frag; } CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const dirfrag_t &df) const { static rjhash H; static rjhash I; return H(df.ino) ^ I(df.frag); } }; CEPH_HASH_NAMESPACE_END // ================================================================ #define META_POP_IRD 0 #define META_POP_IWR 1 #define META_POP_READDIR 2 #define META_POP_FETCH 3 #define META_POP_STORE 4 #define META_NPOP 5 class inode_load_vec_t { static const int NUM = 2; std::vector < DecayCounter > vec; public: inode_load_vec_t(const utime_t &now) : vec(NUM, DecayCounter(now)) {} // for dencoder infrastructure inode_load_vec_t() : vec(NUM, DecayCounter()) {} DecayCounter &get(int t) { assert(t < NUM); return vec[t]; } void zero(utime_t now) { for (int i=0; i& ls); }; inline void encode(const inode_load_vec_t &c, bufferlist &bl) { c.encode(bl); } inline void decode(inode_load_vec_t & c, const utime_t &t, bufferlist::iterator &p) { c.decode(t, p); } class dirfrag_load_vec_t { public: static const int NUM = 5; std::vector < DecayCounter > vec; dirfrag_load_vec_t(const utime_t &now) : vec(NUM, DecayCounter(now)) { } // for dencoder infrastructure dirfrag_load_vec_t() : vec(NUM, DecayCounter()) {} void encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); for (int i=0; i& ls); DecayCounter &get(int t) { assert(t < NUM); return vec[t]; } void adjust(utime_t now, const DecayRate& rate, double d) { for (int i=0; imds_decay_halflife); return out << "[" << dl.vec[0].get(now, rate) << "," << dl.vec[1].get(now, rate) << " " << dl.meta_load(now, rate) << "]"; } /* mds_load_t * mds load */ struct mds_load_t { dirfrag_load_vec_t auth; dirfrag_load_vec_t all; double req_rate; double cache_hit_rate; double queue_len; double cpu_load_avg; mds_load_t(const utime_t &t) : auth(t), all(t), req_rate(0), cache_hit_rate(0), queue_len(0), cpu_load_avg(0) {} // mostly for the dencoder infrastructure mds_load_t() : auth(), all(), req_rate(0), cache_hit_rate(0), queue_len(0), cpu_load_avg(0) {} double mds_load(); // defiend in MDBalancer.cc void encode(bufferlist& bl) const; void decode(const utime_t& now, bufferlist::iterator& bl); //this one is for dencoder infrastructure void decode(bufferlist::iterator& bl) { utime_t sample; decode(sample, bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; inline void encode(const mds_load_t &c, bufferlist &bl) { c.encode(bl); } inline void decode(mds_load_t &c, const utime_t &t, bufferlist::iterator &p) { c.decode(t, p); } inline ostream& operator<<( ostream& out, mds_load_t& load ) { return out << "mdsload<" << load.auth << "/" << load.all << ", req " << load.req_rate << ", hr " << load.cache_hit_rate << ", qlen " << load.queue_len << ", cpu " << load.cpu_load_avg << ">"; } class load_spread_t { public: static const int MAX = 4; int last[MAX]; int p, n; DecayCounter count; public: load_spread_t() : p(0), n(0), count(ceph_clock_now(g_ceph_context)) { for (int i=0; i= 0 is the auth mds #define CDIR_AUTH_PARENT -1 // default #define CDIR_AUTH_UNKNOWN -2 #define CDIR_AUTH_DEFAULT pair(-1, -2) #define CDIR_AUTH_UNDEF pair(-2, -2) //#define CDIR_AUTH_ROOTINODE pair( 0, -2) /* * for metadata leases to clients */ struct ClientLease { client_t client; MDSCacheObject *parent; ceph_seq_t seq; utime_t ttl; xlist::item item_session_lease; // per-session list xlist::item item_lease; // global list ClientLease(client_t c, MDSCacheObject *p) : client(c), parent(p), seq(0), item_session_lease(this), item_lease(this) { } }; // print hack struct mdsco_db_line_prefix { MDSCacheObject *object; mdsco_db_line_prefix(MDSCacheObject *o) : object(o) {} }; ostream& operator<<(ostream& out, mdsco_db_line_prefix o); // printer ostream& operator<<(ostream& out, MDSCacheObject &o); class MDSCacheObjectInfo { public: inodeno_t ino; dirfrag_t dirfrag; string dname; snapid_t snapid; MDSCacheObjectInfo() : ino(0) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; inline bool operator==(const MDSCacheObjectInfo& l, const MDSCacheObjectInfo& r) { if (l.ino || r.ino) return l.ino == r.ino && l.snapid == r.snapid; else return l.dirfrag == r.dirfrag && l.dname == r.dname; } WRITE_CLASS_ENCODER(MDSCacheObjectInfo) class MDSCacheObject { public: // -- pins -- const static int PIN_REPLICATED = 1000; const static int PIN_DIRTY = 1001; const static int PIN_LOCK = -1002; const static int PIN_REQUEST = -1003; const static int PIN_WAITER = 1004; const static int PIN_DIRTYSCATTERED = -1005; static const int PIN_AUTHPIN = 1006; static const int PIN_PTRWAITER = -1007; const static int PIN_TEMPEXPORTING = 1008; // temp pin between encode_ and finish_export static const int PIN_CLIENTLEASE = 1009; const char *generic_pin_name(int p) { switch (p) { case PIN_REPLICATED: return "replicated"; case PIN_DIRTY: return "dirty"; case PIN_LOCK: return "lock"; case PIN_REQUEST: return "request"; case PIN_WAITER: return "waiter"; case PIN_DIRTYSCATTERED: return "dirtyscattered"; case PIN_AUTHPIN: return "authpin"; case PIN_PTRWAITER: return "ptrwaiter"; case PIN_TEMPEXPORTING: return "tempexporting"; case PIN_CLIENTLEASE: return "clientlease"; default: assert(0); return 0; } } // -- state -- const static int STATE_AUTH = (1<<30); const static int STATE_DIRTY = (1<<29); const static int STATE_NOTIFYREF = (1<<28); // notify dropping ref drop through _put() const static int STATE_REJOINING = (1<<27); // replica has not joined w/ primary copy const static int STATE_REJOINUNDEF = (1<<26); // contents undefined. // -- wait -- const static uint64_t WAIT_SINGLEAUTH = (1ull<<60); const static uint64_t WAIT_UNFREEZE = (1ull<<59); // pka AUTHPINNABLE // ============================================ // cons public: MDSCacheObject() : state(0), ref(0), replica_nonce(0) {} virtual ~MDSCacheObject() {} // printing virtual void print(ostream& out) = 0; virtual ostream& print_db_line_prefix(ostream& out) { return out << "mdscacheobject(" << this << ") "; } // -------------------------------------------- // state protected: __u32 state; // state bits public: unsigned get_state() const { return state; } unsigned state_test(unsigned mask) const { return (state & mask); } void state_clear(unsigned mask) { state &= ~mask; } void state_set(unsigned mask) { state |= mask; } void state_reset(unsigned s) { state = s; } bool is_auth() const { return state_test(STATE_AUTH); } bool is_dirty() const { return state_test(STATE_DIRTY); } bool is_clean() const { return !is_dirty(); } bool is_rejoining() const { return state_test(STATE_REJOINING); } // -------------------------------------------- // authority virtual pair authority() = 0; bool is_ambiguous_auth() { return authority().second != CDIR_AUTH_UNKNOWN; } // -------------------------------------------- // pins protected: __s32 ref; // reference count #ifdef MDS_REF_SET map ref_map; #endif public: int get_num_ref(int by = -1) { #ifdef MDS_REF_SET if (by >= 0) { if (ref_map.find(by) == ref_map.end()) return 0; return ref_map[by]; } #endif return ref; } #ifdef MDS_REF_SET int get_pin_totals() { int total = 0; for(map::iterator i = ref_map.begin(); i != ref_map.end(); ++i) { total += i->second; } return total; } #endif virtual const char *pin_name(int by) = 0; //bool is_pinned_by(int by) { return ref_set.count(by); } //multiset& get_ref_set() { return ref_set; } virtual void last_put() {} virtual void bad_put(int by) { #ifdef MDS_REF_SET assert(ref_map[by] > 0); #endif assert(ref > 0); } virtual void _put() {} void put(int by) { #ifdef MDS_REF_SET if (ref == 0 || ref_map[by] == 0) { #else if (ref == 0) { #endif bad_put(by); } else { ref--; #ifdef MDS_REF_SET ref_map[by]--; assert(ref == get_pin_totals()); #endif if (ref == 0) last_put(); if (state_test(STATE_NOTIFYREF)) _put(); } } virtual void first_get() {} virtual void bad_get(int by) { #ifdef MDS_REF_SET assert(by < 0 || ref_map[by] == 0); #endif assert(0); } void get(int by) { if (ref == 0) first_get(); ref++; #ifdef MDS_REF_SET if (ref_map.find(by) == ref_map.end()) ref_map[by] = 0; ref_map[by]++; assert(ref == get_pin_totals()); #endif } void print_pin_set(ostream& out) { #ifdef MDS_REF_SET map::iterator it = ref_map.begin(); while (it != ref_map.end()) { out << " " << pin_name(it->first) << "=" << it->second; ++it; } #else out << " nref=" << ref; #endif } // -------------------------------------------- // auth pins virtual bool can_auth_pin() = 0; virtual void auth_pin(void *who) = 0; virtual void auth_unpin(void *who) = 0; virtual bool is_frozen() = 0; virtual bool is_freezing() = 0; virtual bool is_freezing_or_frozen() { return is_frozen() || is_freezing(); } // -------------------------------------------- // replication (across mds cluster) protected: unsigned replica_nonce; // [replica] defined on replica map replica_map; // [auth] mds -> nonce public: bool is_replicated() { return !replica_map.empty(); } bool is_replica(int mds) { return replica_map.count(mds); } int num_replicas() { return replica_map.size(); } unsigned add_replica(int mds) { if (replica_map.count(mds)) return ++replica_map[mds]; // inc nonce if (replica_map.empty()) get(PIN_REPLICATED); return replica_map[mds] = 1; } void add_replica(int mds, unsigned nonce) { if (replica_map.empty()) get(PIN_REPLICATED); replica_map[mds] = nonce; } unsigned get_replica_nonce(int mds) { assert(replica_map.count(mds)); return replica_map[mds]; } void remove_replica(int mds) { assert(replica_map.count(mds)); replica_map.erase(mds); if (replica_map.empty()) put(PIN_REPLICATED); } void clear_replica_map() { if (!replica_map.empty()) put(PIN_REPLICATED); replica_map.clear(); } map::iterator replicas_begin() { return replica_map.begin(); } map::iterator replicas_end() { return replica_map.end(); } const map& get_replicas() { return replica_map; } void list_replicas(set& ls) { for (map::const_iterator p = replica_map.begin(); p != replica_map.end(); ++p) ls.insert(p->first); } unsigned get_replica_nonce() { return replica_nonce; } void set_replica_nonce(unsigned n) { replica_nonce = n; } // --------------------------------------------- // waiting protected: multimap waiting; public: bool is_waiter_for(uint64_t mask, uint64_t min=0) { if (!min) { min = mask; while (min & (min-1)) // if more than one bit is set min &= min-1; // clear LSB } for (multimap::iterator p = waiting.lower_bound(min); p != waiting.end(); ++p) { if (p->first & mask) return true; if (p->first > mask) return false; } return false; } virtual void add_waiter(uint64_t mask, Context *c) { if (waiting.empty()) get(PIN_WAITER); waiting.insert(pair(mask, c)); // pdout(10,g_conf->debug_mds) << (mdsco_db_line_prefix(this)) // << "add_waiter " << hex << mask << dec << " " << c // << " on " << *this // << dendl; } virtual void take_waiting(uint64_t mask, list& ls) { if (waiting.empty()) return; multimap::iterator it = waiting.begin(); while (it != waiting.end()) { if (it->first & mask) { ls.push_back(it->second); // pdout(10,g_conf->debug_mds) << (mdsco_db_line_prefix(this)) // << "take_waiting mask " << hex << mask << dec << " took " << it->second // << " tag " << hex << it->first << dec // << " on " << *this // << dendl; waiting.erase(it++); } else { // pdout(10,g_conf->debug_mds) << "take_waiting mask " << hex << mask << dec << " SKIPPING " << it->second // << " tag " << hex << it->first << dec // << " on " << *this // << dendl; ++it; } } if (waiting.empty()) put(PIN_WAITER); } void finish_waiting(uint64_t mask, int result = 0) { list finished; take_waiting(mask, finished); finish_contexts(g_ceph_context, finished, result); } // --------------------------------------------- // locking // noop unless overloaded. virtual SimpleLock* get_lock(int type) { assert(0); return 0; } virtual void set_object_info(MDSCacheObjectInfo &info) { assert(0); } virtual void encode_lock_state(int type, bufferlist& bl) { assert(0); } virtual void decode_lock_state(int type, bufferlist& bl) { assert(0); } virtual void finish_lock_waiters(int type, uint64_t mask, int r=0) { assert(0); } virtual void add_lock_waiter(int type, uint64_t mask, Context *c) { assert(0); } virtual bool is_lock_waiting(int type, uint64_t mask) { assert(0); return false; } virtual void clear_dirty_scattered(int type) { assert(0); } // --------------------------------------------- // ordering virtual bool is_lt(const MDSCacheObject *r) const = 0; struct ptr_lt { bool operator()(const MDSCacheObject* l, const MDSCacheObject* r) const { return l->is_lt(r); } }; }; inline ostream& operator<<(ostream& out, MDSCacheObject &o) { o.print(out); return out; } inline ostream& operator<<(ostream& out, const MDSCacheObjectInfo &info) { if (info.ino) return out << info.ino << "." << info.snapid; if (info.dname.length()) return out << info.dirfrag << "/" << info.dname << " snap " << info.snapid; return out << info.dirfrag; } inline ostream& operator<<(ostream& out, mdsco_db_line_prefix o) { o.object->print_db_line_prefix(out); return out; } #endif ceph-0.80.11/src/mds/inode_backtrace.cc0000664000175100017510000000550112623076744021654 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "inode_backtrace.h" #include "common/Formatter.h" /* inode_backpointer_t */ void inode_backpointer_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(dirino, bl); ::encode(dname, bl); ::encode(version, bl); ENCODE_FINISH(bl); } void inode_backpointer_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(dirino, bl); ::decode(dname, bl); ::decode(version, bl); DECODE_FINISH(bl); } void inode_backpointer_t::decode_old(bufferlist::iterator& bl) { ::decode(dirino, bl); ::decode(dname, bl); ::decode(version, bl); } void inode_backpointer_t::dump(Formatter *f) const { f->dump_unsigned("dirino", dirino); f->dump_string("dname", dname); f->dump_unsigned("version", version); } void inode_backpointer_t::generate_test_instances(list& ls) { ls.push_back(new inode_backpointer_t); ls.push_back(new inode_backpointer_t); ls.back()->dirino = 1; ls.back()->dname = "foo"; ls.back()->version = 123; } /* * inode_backtrace_t */ void inode_backtrace_t::encode(bufferlist& bl) const { ENCODE_START(5, 4, bl); ::encode(ino, bl); ::encode(ancestors, bl); ::encode(pool, bl); ::encode(old_pools, bl); ENCODE_FINISH(bl); } void inode_backtrace_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 4, 4, bl); if (struct_v < 3) return; // sorry, the old data was crap ::decode(ino, bl); if (struct_v >= 4) { ::decode(ancestors, bl); } else { __u32 n; ::decode(n, bl); while (n--) { ancestors.push_back(inode_backpointer_t()); ancestors.back().decode_old(bl); } } if (struct_v >= 5) { ::decode(pool, bl); ::decode(old_pools, bl); } DECODE_FINISH(bl); } void inode_backtrace_t::dump(Formatter *f) const { f->dump_unsigned("ino", ino); f->open_array_section("ancestors"); for (vector::const_iterator p = ancestors.begin(); p != ancestors.end(); ++p) { f->open_object_section("backpointer"); p->dump(f); f->close_section(); } f->close_section(); f->dump_int("pool", pool); f->open_array_section("old_pools"); for (set::iterator p = old_pools.begin(); p != old_pools.end(); ++p) { f->dump_int("old_pool", *p); } f->close_section(); } void inode_backtrace_t::generate_test_instances(list& ls) { ls.push_back(new inode_backtrace_t); ls.push_back(new inode_backtrace_t); ls.back()->ino = 1; ls.back()->ancestors.push_back(inode_backpointer_t()); ls.back()->ancestors.back().dirino = 123; ls.back()->ancestors.back().dname = "bar"; ls.back()->ancestors.back().version = 456; ls.back()->pool = 0; ls.back()->old_pools.insert(10); ls.back()->old_pools.insert(7); } ceph-0.80.11/src/mds/Locker.cc0000664000175100017510000043512712623076744020011 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDS.h" #include "MDCache.h" #include "Locker.h" #include "CInode.h" #include "CDir.h" #include "CDentry.h" #include "Mutation.h" #include "MDLog.h" #include "MDSMap.h" #include "include/filepath.h" #include "events/EUpdate.h" #include "events/EOpen.h" #include "msg/Messenger.h" #include "messages/MGenericMessage.h" #include "messages/MDiscover.h" #include "messages/MDiscoverReply.h" #include "messages/MDirUpdate.h" #include "messages/MInodeFileCaps.h" #include "messages/MLock.h" #include "messages/MClientLease.h" #include "messages/MDentryUnlink.h" #include "messages/MClientRequest.h" #include "messages/MClientReply.h" #include "messages/MClientCaps.h" #include "messages/MClientCapRelease.h" #include "messages/MMDSSlaveRequest.h" #include #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #undef DOUT_COND #define DOUT_COND(cct, l) l<=cct->_conf->debug_mds || l <= cct->_conf->debug_mds_locker #define dout_prefix _prefix(_dout, mds) static ostream& _prefix(std::ostream *_dout, MDS *mds) { return *_dout << "mds." << mds->get_nodeid() << ".locker "; } /* This function DOES put the passed message before returning */ void Locker::dispatch(Message *m) { switch (m->get_type()) { // inter-mds locking case MSG_MDS_LOCK: handle_lock(static_cast(m)); break; // inter-mds caps case MSG_MDS_INODEFILECAPS: handle_inode_file_caps(static_cast(m)); break; // client sync case CEPH_MSG_CLIENT_CAPS: handle_client_caps(static_cast(m)); break; case CEPH_MSG_CLIENT_CAPRELEASE: handle_client_cap_release(static_cast(m)); break; case CEPH_MSG_CLIENT_LEASE: handle_client_lease(static_cast(m)); break; default: assert(0); } } /* * locks vs rejoin * * * */ void Locker::send_lock_message(SimpleLock *lock, int msg) { for (map::iterator it = lock->get_parent()->replicas_begin(); it != lock->get_parent()->replicas_end(); ++it) { if (mds->mdsmap->get_state(it->first) < MDSMap::STATE_REJOIN) continue; MLock *m = new MLock(lock, msg, mds->get_nodeid()); mds->send_message_mds(m, it->first); } } void Locker::send_lock_message(SimpleLock *lock, int msg, const bufferlist &data) { for (map::iterator it = lock->get_parent()->replicas_begin(); it != lock->get_parent()->replicas_end(); ++it) { if (mds->mdsmap->get_state(it->first) < MDSMap::STATE_REJOIN) continue; MLock *m = new MLock(lock, msg, mds->get_nodeid()); m->set_data(data); mds->send_message_mds(m, it->first); } } void Locker::include_snap_rdlocks(set& rdlocks, CInode *in) { // rdlock ancestor snaps CInode *t = in; rdlocks.insert(&in->snaplock); while (t->get_projected_parent_dn()) { t = t->get_projected_parent_dn()->get_dir()->get_inode(); rdlocks.insert(&t->snaplock); } } void Locker::include_snap_rdlocks_wlayout(set& rdlocks, CInode *in, ceph_file_layout **layout) { //rdlock ancestor snaps CInode *t = in; rdlocks.insert(&in->snaplock); rdlocks.insert(&in->policylock); bool found_layout = false; while (t) { rdlocks.insert(&t->snaplock); if (!found_layout) { rdlocks.insert(&t->policylock); if (t->get_projected_inode()->has_layout()) { *layout = &t->get_projected_inode()->layout; found_layout = true; } } if (t->get_projected_parent_dn() && t->get_projected_parent_dn()->get_dir()) t = t->get_projected_parent_dn()->get_dir()->get_inode(); else t = NULL; } } /* If this function returns false, the mdr has been placed * on the appropriate wait list */ bool Locker::acquire_locks(MDRequestRef& mdr, set &rdlocks, set &wrlocks, set &xlocks, map *remote_wrlocks, CInode *auth_pin_freeze, bool auth_pin_nonblock) { if (mdr->done_locking && !mdr->is_slave()) { // not on slaves! master requests locks piecemeal. dout(10) << "acquire_locks " << *mdr << " - done locking" << dendl; return true; // at least we had better be! } dout(10) << "acquire_locks " << *mdr << dendl; client_t client = mdr->get_client(); set sorted; // sort everything we will lock set mustpin = xlocks; // items to authpin // xlocks for (set::iterator p = xlocks.begin(); p != xlocks.end(); ++p) { dout(20) << " must xlock " << **p << " " << *(*p)->get_parent() << dendl; sorted.insert(*p); // augment xlock with a versionlock? if ((*p)->get_type() == CEPH_LOCK_DN) { CDentry *dn = (CDentry*)(*p)->get_parent(); if (!dn->is_auth()) continue; if (xlocks.count(&dn->versionlock)) continue; // we're xlocking the versionlock too; don't wrlock it! if (mdr->is_master()) { // master. wrlock versionlock so we can pipeline dentry updates to journal. wrlocks.insert(&dn->versionlock); } else { // slave. exclusively lock the dentry version (i.e. block other journal updates). // this makes rollback safe. xlocks.insert(&dn->versionlock); sorted.insert(&dn->versionlock); } } if ((*p)->get_type() > CEPH_LOCK_IVERSION) { // inode version lock? CInode *in = (CInode*)(*p)->get_parent(); if (!in->is_auth()) continue; if (mdr->is_master()) { // master. wrlock versionlock so we can pipeline inode updates to journal. wrlocks.insert(&in->versionlock); } else { // slave. exclusively lock the inode version (i.e. block other journal updates). // this makes rollback safe. xlocks.insert(&in->versionlock); sorted.insert(&in->versionlock); } } } // wrlocks for (set::iterator p = wrlocks.begin(); p != wrlocks.end(); ++p) { dout(20) << " must wrlock " << **p << " " << *(*p)->get_parent() << dendl; sorted.insert(*p); if ((*p)->get_parent()->is_auth()) mustpin.insert(*p); else if (!(*p)->get_parent()->is_auth() && !(*p)->can_wrlock(client) && // we might have to request a scatter !mdr->is_slave()) { // if we are slave (remote_wrlock), the master already authpinned dout(15) << " will also auth_pin " << *(*p)->get_parent() << " in case we need to request a scatter" << dendl; mustpin.insert(*p); } } // remote_wrlocks if (remote_wrlocks) { for (map::iterator p = remote_wrlocks->begin(); p != remote_wrlocks->end(); ++p) { dout(20) << " must remote_wrlock on mds." << p->second << " " << *p->first << " " << *(p->first)->get_parent() << dendl; sorted.insert(p->first); mustpin.insert(p->first); } } // rdlocks for (set::iterator p = rdlocks.begin(); p != rdlocks.end(); ++p) { dout(20) << " must rdlock " << **p << " " << *(*p)->get_parent() << dendl; sorted.insert(*p); if ((*p)->get_parent()->is_auth()) mustpin.insert(*p); else if (!(*p)->get_parent()->is_auth() && !(*p)->can_rdlock(client)) { // we might have to request an rdlock dout(15) << " will also auth_pin " << *(*p)->get_parent() << " in case we need to request a rdlock" << dendl; mustpin.insert(*p); } } // AUTH PINS map > mustpin_remote; // mds -> (object set) // can i auth pin them all now? for (set::iterator p = mustpin.begin(); p != mustpin.end(); ++p) { MDSCacheObject *object = (*p)->get_parent(); dout(10) << " must authpin " << *object << dendl; if (mdr->is_auth_pinned(object)) continue; if (!object->is_auth()) { if (!mdr->locks.empty()) mds->locker->drop_locks(mdr.get()); if (object->is_ambiguous_auth()) { // wait dout(10) << " ambiguous auth, waiting to authpin " << *object << dendl; object->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, new C_MDS_RetryRequest(mdcache, mdr)); mdr->drop_local_auth_pins(); return false; } mustpin_remote[object->authority().first].insert(object); continue; } if (!object->can_auth_pin()) { // wait mds->locker->drop_locks(mdr.get()); mdr->drop_local_auth_pins(); if (auth_pin_nonblock) { dout(10) << " can't auth_pin (freezing?) " << *object << ", nonblocking" << dendl; mdr->aborted = true; return false; } dout(10) << " can't auth_pin (freezing?), waiting to authpin " << *object << dendl; object->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr)); return false; } } // ok, grab local auth pins for (set::iterator p = mustpin.begin(); p != mustpin.end(); ++p) { MDSCacheObject *object = (*p)->get_parent(); if (mdr->is_auth_pinned(object)) { dout(10) << " already auth_pinned " << *object << dendl; } else if (object->is_auth()) { dout(10) << " auth_pinning " << *object << dendl; mdr->auth_pin(object); } } // request remote auth_pins if (!mustpin_remote.empty()) { for (map >::iterator p = mustpin_remote.begin(); p != mustpin_remote.end(); ++p) { dout(10) << "requesting remote auth_pins from mds." << p->first << dendl; // wait for active auth if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(p->first)) { dout(10) << " mds." << p->first << " is not active" << dendl; if (mdr->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(p->first, new C_MDS_RetryRequest(mdcache, mdr)); return false; } MMDSSlaveRequest *req = new MMDSSlaveRequest(mdr->reqid, mdr->attempt, MMDSSlaveRequest::OP_AUTHPIN); for (set::iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(10) << " req remote auth_pin of " << **q << dendl; MDSCacheObjectInfo info; (*q)->set_object_info(info); req->get_authpins().push_back(info); if (*q == auth_pin_freeze) (*q)->set_object_info(req->get_authpin_freeze()); mdr->pin(*q); } if (auth_pin_nonblock) req->mark_nonblock(); mds->send_message_mds(req, p->first); // put in waiting list assert(mdr->more()->waiting_on_slave.count(p->first) == 0); mdr->more()->waiting_on_slave.insert(p->first); } return false; } // caps i'll need to issue set issue_set; bool result = false; // acquire locks. // make sure they match currently acquired locks. set::iterator existing = mdr->locks.begin(); for (set::iterator p = sorted.begin(); p != sorted.end(); ++p) { bool need_wrlock = !!wrlocks.count(*p); bool need_remote_wrlock = !!(remote_wrlocks && remote_wrlocks->count(*p)); // already locked? if (existing != mdr->locks.end() && *existing == *p) { // right kind? SimpleLock *have = *existing; ++existing; if (xlocks.count(have) && mdr->xlocks.count(have)) { dout(10) << " already xlocked " << *have << " " << *have->get_parent() << dendl; continue; } if (mdr->remote_wrlocks.count(have)) { if (!need_remote_wrlock || mdr->remote_wrlocks[have] != (*remote_wrlocks)[have]) { dout(10) << " unlocking remote_wrlock on wrong mds." << mdr->remote_wrlocks[have] << " " << *have << " " << *have->get_parent() << dendl; remote_wrlock_finish(have, mdr->remote_wrlocks[have], mdr.get()); } } if (need_wrlock || need_remote_wrlock) { if (need_wrlock == !!mdr->wrlocks.count(have) && need_remote_wrlock == !!mdr->remote_wrlocks.count(have)) { if (need_wrlock) dout(10) << " already wrlocked " << *have << " " << *have->get_parent() << dendl; if (need_remote_wrlock) dout(10) << " already remote_wrlocked " << *have << " " << *have->get_parent() << dendl; continue; } } if (rdlocks.count(have) && mdr->rdlocks.count(have)) { dout(10) << " already rdlocked " << *have << " " << *have->get_parent() << dendl; continue; } } // hose any stray locks if (*existing == *p) { assert(need_wrlock || need_remote_wrlock); SimpleLock *lock = *existing; if (mdr->wrlocks.count(lock)) { if (!need_wrlock) dout(10) << " unlocking extra " << *lock << " " << *lock->get_parent() << dendl; else if (need_remote_wrlock) // acquire remote_wrlock first dout(10) << " unlocking out-of-order " << *lock << " " << *lock->get_parent() << dendl; bool need_issue = false; wrlock_finish(lock, mdr.get(), &need_issue); if (need_issue) issue_set.insert(static_cast(lock->get_parent())); } ++existing; } while (existing != mdr->locks.end()) { SimpleLock *stray = *existing; ++existing; dout(10) << " unlocking out-of-order " << *stray << " " << *stray->get_parent() << dendl; bool need_issue = false; if (mdr->xlocks.count(stray)) { xlock_finish(stray, mdr.get(), &need_issue); } else if (mdr->rdlocks.count(stray)) { rdlock_finish(stray, mdr.get(), &need_issue); } else { // may have acquired both wrlock and remore wrlock if (mdr->wrlocks.count(stray)) wrlock_finish(stray, mdr.get(), &need_issue); if (mdr->remote_wrlocks.count(stray)) remote_wrlock_finish(stray, mdr->remote_wrlocks[stray], mdr.get()); } if (need_issue) issue_set.insert(static_cast(stray->get_parent())); } // lock if (mdr->locking && *p != mdr->locking) { cancel_locking(mdr.get(), &issue_set); } if (xlocks.count(*p)) { if (!xlock_start(*p, mdr)) goto out; dout(10) << " got xlock on " << **p << " " << *(*p)->get_parent() << dendl; } else if (need_wrlock || need_remote_wrlock) { if (need_remote_wrlock && !mdr->remote_wrlocks.count(*p)) { remote_wrlock_start(*p, (*remote_wrlocks)[*p], mdr); goto out; } if (need_wrlock && !mdr->wrlocks.count(*p)) { if (need_remote_wrlock && !(*p)->can_wrlock(mdr->get_client())) { // can't take the wrlock because the scatter lock is gathering. need to // release the remote wrlock, so that the gathering process can finish. remote_wrlock_finish(*p, mdr->remote_wrlocks[*p], mdr.get()); remote_wrlock_start(*p, (*remote_wrlocks)[*p], mdr); goto out; } if (!wrlock_start(*p, mdr)) goto out; dout(10) << " got wrlock on " << **p << " " << *(*p)->get_parent() << dendl; } } else { if (!rdlock_start(*p, mdr)) goto out; dout(10) << " got rdlock on " << **p << " " << *(*p)->get_parent() << dendl; } } // any extra unneeded locks? while (existing != mdr->locks.end()) { SimpleLock *stray = *existing; ++existing; dout(10) << " unlocking extra " << *stray << " " << *stray->get_parent() << dendl; bool need_issue = false; if (mdr->xlocks.count(stray)) { xlock_finish(stray, mdr.get(), &need_issue); } else if (mdr->rdlocks.count(stray)) { rdlock_finish(stray, mdr.get(), &need_issue); } else { // may have acquired both wrlock and remore wrlock if (mdr->wrlocks.count(stray)) wrlock_finish(stray, mdr.get(), &need_issue); if (mdr->remote_wrlocks.count(stray)) remote_wrlock_finish(stray, mdr->remote_wrlocks[stray], mdr.get()); } if (need_issue) issue_set.insert(static_cast(stray->get_parent())); } mdr->done_locking = true; result = true; out: issue_caps_set(issue_set); return result; } void Locker::set_xlocks_done(MutationImpl *mut, bool skip_dentry) { for (set::iterator p = mut->xlocks.begin(); p != mut->xlocks.end(); ++p) { if (skip_dentry && ((*p)->get_type() == CEPH_LOCK_DN || (*p)->get_type() == CEPH_LOCK_DVERSION)) continue; dout(10) << "set_xlocks_done on " << **p << " " << *(*p)->get_parent() << dendl; (*p)->set_xlock_done(); } } void Locker::_drop_rdlocks(MutationImpl *mut, set *pneed_issue) { while (!mut->rdlocks.empty()) { bool ni = false; MDSCacheObject *p = (*mut->rdlocks.begin())->get_parent(); rdlock_finish(*mut->rdlocks.begin(), mut, &ni); if (ni) pneed_issue->insert(static_cast(p)); } } void Locker::_drop_non_rdlocks(MutationImpl *mut, set *pneed_issue) { set slaves; while (!mut->xlocks.empty()) { SimpleLock *lock = *mut->xlocks.begin(); MDSCacheObject *p = lock->get_parent(); if (!p->is_auth()) { assert(lock->get_sm()->can_remote_xlock); slaves.insert(p->authority().first); lock->put_xlock(); mut->locks.erase(lock); mut->xlocks.erase(lock); continue; } bool ni = false; xlock_finish(lock, mut, &ni); if (ni) pneed_issue->insert(static_cast(p)); } while (!mut->remote_wrlocks.empty()) { map::iterator p = mut->remote_wrlocks.begin(); slaves.insert(p->second); if (mut->wrlocks.count(p->first) == 0) mut->locks.erase(p->first); mut->remote_wrlocks.erase(p); } while (!mut->wrlocks.empty()) { bool ni = false; MDSCacheObject *p = (*mut->wrlocks.begin())->get_parent(); wrlock_finish(*mut->wrlocks.begin(), mut, &ni); if (ni) pneed_issue->insert(static_cast(p)); } for (set::iterator p = slaves.begin(); p != slaves.end(); ++p) { if (mds->mdsmap->get_state(*p) >= MDSMap::STATE_REJOIN) { dout(10) << "_drop_non_rdlocks dropping remote locks on mds." << *p << dendl; MMDSSlaveRequest *slavereq = new MMDSSlaveRequest(mut->reqid, mut->attempt, MMDSSlaveRequest::OP_DROPLOCKS); mds->send_message_mds(slavereq, *p); } } } void Locker::cancel_locking(MutationImpl *mut, set *pneed_issue) { SimpleLock *lock = mut->locking; assert(lock); dout(10) << "cancel_locking " << *lock << " on " << *mut << dendl; if (lock->get_parent()->is_auth()) { bool need_issue = false; if (lock->get_state() == LOCK_PREXLOCK) { _finish_xlock(lock, -1, &need_issue); } else if (lock->get_state() == LOCK_LOCK_XLOCK && lock->get_num_xlocks() == 0) { lock->set_state(LOCK_XLOCKDONE); eval_gather(lock, true, &need_issue); } if (need_issue) pneed_issue->insert(static_cast(lock->get_parent())); } mut->finish_locking(lock); } void Locker::drop_locks(MutationImpl *mut, set *pneed_issue) { // leftover locks set my_need_issue; if (!pneed_issue) pneed_issue = &my_need_issue; if (mut->locking) cancel_locking(mut, pneed_issue); _drop_non_rdlocks(mut, pneed_issue); _drop_rdlocks(mut, pneed_issue); if (pneed_issue == &my_need_issue) issue_caps_set(*pneed_issue); mut->done_locking = false; } void Locker::drop_non_rdlocks(MutationImpl *mut, set *pneed_issue) { set my_need_issue; if (!pneed_issue) pneed_issue = &my_need_issue; _drop_non_rdlocks(mut, pneed_issue); if (pneed_issue == &my_need_issue) issue_caps_set(*pneed_issue); } void Locker::drop_rdlocks(MutationImpl *mut, set *pneed_issue) { set my_need_issue; if (!pneed_issue) pneed_issue = &my_need_issue; _drop_rdlocks(mut, pneed_issue); if (pneed_issue == &my_need_issue) issue_caps_set(*pneed_issue); } // generics void Locker::eval_gather(SimpleLock *lock, bool first, bool *pneed_issue, list *pfinishers) { dout(10) << "eval_gather " << *lock << " on " << *lock->get_parent() << dendl; assert(!lock->is_stable()); int next = lock->get_next_state(); CInode *in = 0; bool caps = lock->get_cap_shift(); if (lock->get_type() != CEPH_LOCK_DN) in = static_cast(lock->get_parent()); bool need_issue = false; int loner_issued = 0, other_issued = 0, xlocker_issued = 0; assert(!caps || in != NULL); if (caps && in->is_head()) { in->get_caps_issued(&loner_issued, &other_issued, &xlocker_issued, lock->get_cap_shift(), lock->get_cap_mask()); dout(10) << " next state is " << lock->get_state_name(next) << " issued/allows loner " << gcap_string(loner_issued) << "/" << gcap_string(lock->gcaps_allowed(CAP_LONER, next)) << " xlocker " << gcap_string(xlocker_issued) << "/" << gcap_string(lock->gcaps_allowed(CAP_XLOCKER, next)) << " other " << gcap_string(other_issued) << "/" << gcap_string(lock->gcaps_allowed(CAP_ANY, next)) << dendl; if (first && ((~lock->gcaps_allowed(CAP_ANY, next) & other_issued) || (~lock->gcaps_allowed(CAP_LONER, next) & loner_issued) || (~lock->gcaps_allowed(CAP_XLOCKER, next) & xlocker_issued))) need_issue = true; } #define IS_TRUE_AND_LT_AUTH(x, auth) (x && ((auth && x <= AUTH) || (!auth && x < AUTH))) bool auth = lock->get_parent()->is_auth(); if (!lock->is_gathering() && (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_rdlock, auth) || !lock->is_rdlocked()) && (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_wrlock, auth) || !lock->is_wrlocked()) && (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_xlock, auth) || !lock->is_xlocked()) && (IS_TRUE_AND_LT_AUTH(lock->get_sm()->states[next].can_lease, auth) || !lock->is_leased()) && !(lock->get_parent()->is_auth() && lock->is_flushing()) && // i.e. wait for scatter_writebehind! (!caps || ((~lock->gcaps_allowed(CAP_ANY, next) & other_issued) == 0 && (~lock->gcaps_allowed(CAP_LONER, next) & loner_issued) == 0 && (~lock->gcaps_allowed(CAP_XLOCKER, next) & xlocker_issued) == 0)) && lock->get_state() != LOCK_SYNC_MIX2 && // these states need an explicit trigger from the auth mds lock->get_state() != LOCK_MIX_SYNC2 ) { dout(7) << "eval_gather finished gather on " << *lock << " on " << *lock->get_parent() << dendl; if (lock->get_sm() == &sm_filelock) { assert(in); if (in->state_test(CInode::STATE_RECOVERING)) { dout(7) << "eval_gather finished gather, but still recovering" << dendl; return; } else if (in->state_test(CInode::STATE_NEEDSRECOVER)) { dout(7) << "eval_gather finished gather, but need to recover" << dendl; mds->mdcache->queue_file_recover(in); mds->mdcache->do_file_recover(); return; } } if (!lock->get_parent()->is_auth()) { // replica: tell auth int auth = lock->get_parent()->authority().first; if (lock->get_parent()->is_rejoining() && mds->mdsmap->get_state(auth) == MDSMap::STATE_REJOIN) { dout(7) << "eval_gather finished gather, but still rejoining " << *lock->get_parent() << dendl; return; } if (mds->mdsmap->get_state(auth) >= MDSMap::STATE_REJOIN) { switch (lock->get_state()) { case LOCK_SYNC_LOCK: mds->send_message_mds(new MLock(lock, LOCK_AC_LOCKACK, mds->get_nodeid()), auth); break; case LOCK_MIX_SYNC: { MLock *reply = new MLock(lock, LOCK_AC_SYNCACK, mds->get_nodeid()); lock->encode_locked_state(reply->get_data()); mds->send_message_mds(reply, auth); next = LOCK_MIX_SYNC2; (static_cast(lock))->start_flush(); } break; case LOCK_MIX_SYNC2: (static_cast(lock))->finish_flush(); (static_cast(lock))->clear_flushed(); case LOCK_SYNC_MIX2: // do nothing, we already acked break; case LOCK_SYNC_MIX: { MLock *reply = new MLock(lock, LOCK_AC_MIXACK, mds->get_nodeid()); mds->send_message_mds(reply, auth); next = LOCK_SYNC_MIX2; } break; case LOCK_MIX_LOCK: { bufferlist data; lock->encode_locked_state(data); mds->send_message_mds(new MLock(lock, LOCK_AC_LOCKACK, mds->get_nodeid(), data), auth); (static_cast(lock))->start_flush(); // we'll get an AC_LOCKFLUSHED to complete } break; default: assert(0); } } } else { // auth // once the first (local) stage of mix->lock gather complete we can // gather from replicas if (lock->get_state() == LOCK_MIX_LOCK && lock->get_parent()->is_replicated()) { dout(10) << " finished (local) gather for mix->lock, now gathering from replicas" << dendl; send_lock_message(lock, LOCK_AC_LOCK); lock->init_gather(); lock->set_state(LOCK_MIX_LOCK2); return; } if (lock->is_dirty() && !lock->is_flushed()) { scatter_writebehind(static_cast(lock)); mds->mdlog->flush(); return; } lock->clear_flushed(); switch (lock->get_state()) { // to mixed case LOCK_TSYN_MIX: case LOCK_SYNC_MIX: case LOCK_EXCL_MIX: in->start_scatter(static_cast(lock)); if (lock->get_parent()->is_replicated()) { bufferlist softdata; lock->encode_locked_state(softdata); send_lock_message(lock, LOCK_AC_MIX, softdata); } (static_cast(lock))->clear_scatter_wanted(); break; case LOCK_XLOCK: case LOCK_XLOCKDONE: if (next != LOCK_SYNC) break; // fall-thru // to sync case LOCK_EXCL_SYNC: case LOCK_LOCK_SYNC: case LOCK_MIX_SYNC: case LOCK_XSYN_SYNC: if (lock->get_parent()->is_replicated()) { bufferlist softdata; lock->encode_locked_state(softdata); send_lock_message(lock, LOCK_AC_SYNC, softdata); } break; } } lock->set_state(next); if (lock->get_parent()->is_auth() && lock->is_stable()) lock->get_parent()->auth_unpin(lock); // drop loner before doing waiters if (caps && in->is_head() && in->is_auth() && in->get_wanted_loner() != in->get_loner()) { dout(10) << " trying to drop loner" << dendl; if (in->try_drop_loner()) { dout(10) << " dropped loner" << dendl; need_issue = true; } } if (pfinishers) lock->take_waiting(SimpleLock::WAIT_STABLE|SimpleLock::WAIT_WR|SimpleLock::WAIT_RD|SimpleLock::WAIT_XLOCK, *pfinishers); else lock->finish_waiters(SimpleLock::WAIT_STABLE|SimpleLock::WAIT_WR|SimpleLock::WAIT_RD|SimpleLock::WAIT_XLOCK); if (caps && in->is_head()) need_issue = true; if (lock->get_parent()->is_auth() && lock->is_stable()) try_eval(lock, &need_issue); } if (need_issue) { if (pneed_issue) *pneed_issue = true; else if (in->is_head()) issue_caps(in); } } bool Locker::eval(CInode *in, int mask, bool caps_imported) { bool need_issue = caps_imported; list finishers; dout(10) << "eval " << mask << " " << *in << dendl; // choose loner? if (in->is_auth() && in->is_head()) { if (in->choose_ideal_loner() >= 0) { if (in->try_set_loner()) { dout(10) << "eval set loner to client." << in->get_loner() << dendl; need_issue = true; mask = -1; } else dout(10) << "eval want loner client." << in->get_wanted_loner() << " but failed to set it" << dendl; } else dout(10) << "eval doesn't want loner" << dendl; } retry: if (mask & CEPH_LOCK_IFILE) eval_any(&in->filelock, &need_issue, &finishers, caps_imported); if (mask & CEPH_LOCK_IAUTH) eval_any(&in->authlock, &need_issue, &finishers, caps_imported); if (mask & CEPH_LOCK_ILINK) eval_any(&in->linklock, &need_issue, &finishers, caps_imported); if (mask & CEPH_LOCK_IXATTR) eval_any(&in->xattrlock, &need_issue, &finishers, caps_imported); if (mask & CEPH_LOCK_INEST) eval_any(&in->nestlock, &need_issue, &finishers, caps_imported); if (mask & CEPH_LOCK_IFLOCK) eval_any(&in->flocklock, &need_issue, &finishers, caps_imported); if (mask & CEPH_LOCK_IPOLICY) eval_any(&in->policylock, &need_issue, &finishers, caps_imported); // drop loner? if (in->is_auth() && in->is_head() && in->get_wanted_loner() != in->get_loner()) { dout(10) << " trying to drop loner" << dendl; if (in->try_drop_loner()) { dout(10) << " dropped loner" << dendl; need_issue = true; if (in->get_wanted_loner() >= 0) { if (in->try_set_loner()) { dout(10) << "eval end set loner to client." << in->get_loner() << dendl; mask = -1; goto retry; } else { dout(10) << "eval want loner client." << in->get_wanted_loner() << " but failed to set it" << dendl; } } } } finish_contexts(g_ceph_context, finishers); if (need_issue && in->is_head()) issue_caps(in); dout(10) << "eval done" << dendl; return need_issue; } class C_Locker_Eval : public Context { Locker *locker; MDSCacheObject *p; int mask; public: C_Locker_Eval(Locker *l, MDSCacheObject *pp, int m) : locker(l), p(pp), mask(m) { p->get(MDSCacheObject::PIN_PTRWAITER); } void finish(int r) { p->put(MDSCacheObject::PIN_PTRWAITER); locker->try_eval(p, mask); } }; void Locker::try_eval(MDSCacheObject *p, int mask) { // unstable and ambiguous auth? if (p->is_ambiguous_auth()) { dout(7) << "try_eval ambiguous auth, waiting on " << *p << dendl; p->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, new C_Locker_Eval(this, p, mask)); return; } if (p->is_auth() && p->is_frozen()) { dout(7) << "try_eval frozen, waiting on " << *p << dendl; p->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_Locker_Eval(this, p, mask)); return; } if (mask & CEPH_LOCK_DN) { assert(mask == CEPH_LOCK_DN); bool need_issue = false; // ignore this, no caps on dentries CDentry *dn = static_cast(p); eval_any(&dn->lock, &need_issue); } else { CInode *in = static_cast(p); eval(in, mask); } } void Locker::try_eval(SimpleLock *lock, bool *pneed_issue) { MDSCacheObject *p = lock->get_parent(); // unstable and ambiguous auth? if (p->is_ambiguous_auth()) { dout(7) << "try_eval " << *lock << " ambiguousauth, waiting on " << *p << dendl; p->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, new C_Locker_Eval(this, p, lock->get_type())); return; } if (!p->is_auth()) { dout(7) << "try_eval " << *lock << " not auth for " << *p << dendl; return; } if (p->is_frozen()) { dout(7) << "try_eval " << *lock << " frozen, waiting on " << *p << dendl; p->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_Locker_Eval(this, p, lock->get_type())); return; } /* * We could have a situation like: * * - mds A authpins item on mds B * - mds B starts to freeze tree containing item * - mds A tries wrlock_start on A, sends REQSCATTER to B * - mds B lock is unstable, sets scatter_wanted * - mds B lock stabilizes, calls try_eval. * * We can defer while freezing without causing a deadlock. Honor * scatter_wanted flag here. This will never get deferred by the * checks above due to the auth_pin held by the master. */ if (lock->is_scatterlock()) { ScatterLock *slock = static_cast(lock); if (slock->get_scatter_wanted() && slock->get_state() != LOCK_MIX) { scatter_mix(slock, pneed_issue); if (!lock->is_stable()) return; } else if (slock->get_unscatter_wanted() && slock->get_state() != LOCK_LOCK) { simple_lock(slock, pneed_issue); if (!lock->is_stable()) { return; } } } if (lock->get_type() != CEPH_LOCK_DN && p->is_freezing()) { dout(7) << "try_eval " << *lock << " freezing, waiting on " << *p << dendl; p->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_Locker_Eval(this, p, lock->get_type())); return; } eval(lock, pneed_issue); } void Locker::eval_cap_gather(CInode *in, set *issue_set) { bool need_issue = false; list finishers; // kick locks now if (!in->filelock.is_stable()) eval_gather(&in->filelock, false, &need_issue, &finishers); if (!in->authlock.is_stable()) eval_gather(&in->authlock, false, &need_issue, &finishers); if (!in->linklock.is_stable()) eval_gather(&in->linklock, false, &need_issue, &finishers); if (!in->xattrlock.is_stable()) eval_gather(&in->xattrlock, false, &need_issue, &finishers); if (need_issue && in->is_head()) { if (issue_set) issue_set->insert(in); else issue_caps(in); } finish_contexts(g_ceph_context, finishers); } void Locker::eval_scatter_gathers(CInode *in) { bool need_issue = false; list finishers; dout(10) << "eval_scatter_gathers " << *in << dendl; // kick locks now if (!in->filelock.is_stable()) eval_gather(&in->filelock, false, &need_issue, &finishers); if (!in->nestlock.is_stable()) eval_gather(&in->nestlock, false, &need_issue, &finishers); if (!in->dirfragtreelock.is_stable()) eval_gather(&in->dirfragtreelock, false, &need_issue, &finishers); if (need_issue && in->is_head()) issue_caps(in); finish_contexts(g_ceph_context, finishers); } void Locker::eval(SimpleLock *lock, bool *need_issue) { switch (lock->get_type()) { case CEPH_LOCK_IFILE: return file_eval(static_cast(lock), need_issue); case CEPH_LOCK_IDFT: case CEPH_LOCK_INEST: return scatter_eval(static_cast(lock), need_issue); default: return simple_eval(lock, need_issue); } } // ------------------ // rdlock bool Locker::_rdlock_kick(SimpleLock *lock, bool as_anon) { // kick the lock if (lock->is_stable()) { if (lock->get_parent()->is_auth()) { if (lock->get_sm() == &sm_scatterlock) { // not until tempsync is fully implemented //if (lock->get_parent()->is_replicated()) //scatter_tempsync((ScatterLock*)lock); //else simple_sync(lock); } else if (lock->get_sm() == &sm_filelock) { CInode *in = static_cast(lock->get_parent()); if (lock->get_state() == LOCK_EXCL && in->get_target_loner() >= 0 && !as_anon) // as_anon => caller wants SYNC, not XSYN file_xsyn(lock); else simple_sync(lock); } else simple_sync(lock); return true; } else { // request rdlock state change from auth int auth = lock->get_parent()->authority().first; if (mds->mdsmap->is_clientreplay_or_active_or_stopping(auth)) { dout(10) << "requesting rdlock from auth on " << *lock << " on " << *lock->get_parent() << dendl; mds->send_message_mds(new MLock(lock, LOCK_AC_REQRDLOCK, mds->get_nodeid()), auth); } return false; } } return false; } bool Locker::rdlock_try(SimpleLock *lock, client_t client, Context *con) { dout(7) << "rdlock_try on " << *lock << " on " << *lock->get_parent() << dendl; // can read? grab ref. if (lock->can_rdlock(client)) return true; _rdlock_kick(lock, false); if (lock->can_rdlock(client)) return true; // wait! if (con) { dout(7) << "rdlock_try waiting on " << *lock << " on " << *lock->get_parent() << dendl; lock->add_waiter(SimpleLock::WAIT_STABLE|SimpleLock::WAIT_RD, con); } return false; } bool Locker::rdlock_start(SimpleLock *lock, MDRequestRef& mut, bool as_anon) { dout(7) << "rdlock_start on " << *lock << " on " << *lock->get_parent() << dendl; // client may be allowed to rdlock the same item it has xlocked. // UNLESS someone passes in as_anon, or we're reading snapped version here. if (mut->snapid != CEPH_NOSNAP) as_anon = true; client_t client = as_anon ? -1 : mut->get_client(); CInode *in = 0; if (lock->get_type() != CEPH_LOCK_DN) in = static_cast(lock->get_parent()); /* if (!lock->get_parent()->is_auth() && lock->fw_rdlock_to_auth()) { mdcache->request_forward(mut, lock->get_parent()->authority().first); return false; } */ while (1) { // can read? grab ref. if (lock->can_rdlock(client)) { lock->get_rdlock(); mut->rdlocks.insert(lock); mut->locks.insert(lock); return true; } if (!_rdlock_kick(lock, as_anon)) break; // hmm, wait a second. if (in && !in->is_head() && in->is_auth() && lock->get_state() == LOCK_SNAP_SYNC) { // okay, we actually need to kick the head's lock to get ourselves synced up. CInode *head = mdcache->get_inode(in->ino()); assert(head); SimpleLock *hlock = head->get_lock(lock->get_type()); if (hlock->get_state() != LOCK_SYNC) { dout(10) << "rdlock_start trying head inode " << *head << dendl; if (!rdlock_start(head->get_lock(lock->get_type()), mut, true)) // ** as_anon, no rdlock on EXCL ** return false; // oh, check our lock again then } } } // wait! int wait_on; if (lock->get_parent()->is_auth() && lock->is_stable()) wait_on = SimpleLock::WAIT_RD; else wait_on = SimpleLock::WAIT_STABLE; // REQRDLOCK is ignored if lock is unstable, so we need to retry. dout(7) << "rdlock_start waiting on " << *lock << " on " << *lock->get_parent() << dendl; lock->add_waiter(wait_on, new C_MDS_RetryRequest(mdcache, mut)); nudge_log(lock); return false; } void Locker::nudge_log(SimpleLock *lock) { dout(10) << "nudge_log " << *lock << " on " << *lock->get_parent() << dendl; if (lock->get_parent()->is_auth() && !lock->is_stable()) // as with xlockdone, or cap flush mds->mdlog->flush(); } void Locker::rdlock_finish(SimpleLock *lock, MutationImpl *mut, bool *pneed_issue) { // drop ref lock->put_rdlock(); if (mut) { mut->rdlocks.erase(lock); mut->locks.erase(lock); } dout(7) << "rdlock_finish on " << *lock << " on " << *lock->get_parent() << dendl; // last one? if (!lock->is_rdlocked()) { if (!lock->is_stable()) eval_gather(lock, false, pneed_issue); else if (lock->get_parent()->is_auth()) try_eval(lock, pneed_issue); } } bool Locker::can_rdlock_set(set& locks) { dout(10) << "can_rdlock_set " << locks << dendl; for (set::iterator p = locks.begin(); p != locks.end(); ++p) if (!(*p)->can_rdlock(-1)) { dout(10) << "can_rdlock_set can't rdlock " << *p << " on " << *(*p)->get_parent() << dendl; return false; } return true; } bool Locker::rdlock_try_set(set& locks) { dout(10) << "rdlock_try_set " << locks << dendl; for (set::iterator p = locks.begin(); p != locks.end(); ++p) if (!rdlock_try(*p, -1, NULL)) { dout(10) << "rdlock_try_set can't rdlock " << *p << " on " << *(*p)->get_parent() << dendl; return false; } return true; } void Locker::rdlock_take_set(set& locks, MutationRef& mut) { dout(10) << "rdlock_take_set " << locks << dendl; for (set::iterator p = locks.begin(); p != locks.end(); ++p) { (*p)->get_rdlock(); mut->rdlocks.insert(*p); mut->locks.insert(*p); } } // ------------------ // wrlock void Locker::wrlock_force(SimpleLock *lock, MutationRef& mut) { if (lock->get_type() == CEPH_LOCK_IVERSION || lock->get_type() == CEPH_LOCK_DVERSION) return local_wrlock_grab(static_cast(lock), mut); dout(7) << "wrlock_force on " << *lock << " on " << *lock->get_parent() << dendl; lock->get_wrlock(true); mut->wrlocks.insert(lock); mut->locks.insert(lock); } bool Locker::wrlock_start(SimpleLock *lock, MDRequestRef& mut, bool nowait) { if (lock->get_type() == CEPH_LOCK_IVERSION || lock->get_type() == CEPH_LOCK_DVERSION) return local_wrlock_start(static_cast(lock), mut); dout(10) << "wrlock_start " << *lock << " on " << *lock->get_parent() << dendl; CInode *in = static_cast(lock->get_parent()); client_t client = mut->get_client(); bool want_scatter = !nowait && lock->get_parent()->is_auth() && (in->has_subtree_or_exporting_dirfrag() || static_cast(lock)->get_scatter_wanted()); while (1) { // wrlock? if (lock->can_wrlock(client) && (!want_scatter || lock->get_state() == LOCK_MIX)) { lock->get_wrlock(); mut->wrlocks.insert(lock); mut->locks.insert(lock); return true; } if (!lock->is_stable()) break; if (in->is_auth()) { // don't do nested lock state change if we have dirty scatterdata and // may scatter_writebehind or start_scatter, because nowait==true implies // that the caller already has a log entry open! if (nowait && lock->is_dirty()) return false; if (want_scatter) scatter_mix(static_cast(lock)); else simple_lock(lock); if (nowait && !lock->can_wrlock(client)) return false; } else { // replica. // auth should be auth_pinned (see acquire_locks wrlock weird mustpin case). int auth = lock->get_parent()->authority().first; if (mds->mdsmap->is_clientreplay_or_active_or_stopping(auth)) { dout(10) << "requesting scatter from auth on " << *lock << " on " << *lock->get_parent() << dendl; mds->send_message_mds(new MLock(lock, LOCK_AC_REQSCATTER, mds->get_nodeid()), auth); } break; } } if (!nowait) { dout(7) << "wrlock_start waiting on " << *lock << " on " << *lock->get_parent() << dendl; lock->add_waiter(SimpleLock::WAIT_STABLE, new C_MDS_RetryRequest(mdcache, mut)); nudge_log(lock); } return false; } void Locker::wrlock_finish(SimpleLock *lock, MutationImpl *mut, bool *pneed_issue) { if (lock->get_type() == CEPH_LOCK_IVERSION || lock->get_type() == CEPH_LOCK_DVERSION) return local_wrlock_finish(static_cast(lock), mut); dout(7) << "wrlock_finish on " << *lock << " on " << *lock->get_parent() << dendl; lock->put_wrlock(); if (mut) { mut->wrlocks.erase(lock); if (mut->remote_wrlocks.count(lock) == 0) mut->locks.erase(lock); } if (!lock->is_wrlocked()) { if (!lock->is_stable()) eval_gather(lock, false, pneed_issue); else if (lock->get_parent()->is_auth()) try_eval(lock, pneed_issue); } } // remote wrlock void Locker::remote_wrlock_start(SimpleLock *lock, int target, MDRequestRef& mut) { dout(7) << "remote_wrlock_start mds." << target << " on " << *lock << " on " << *lock->get_parent() << dendl; // wait for active target if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(target)) { dout(7) << " mds." << target << " is not active" << dendl; if (mut->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(target, new C_MDS_RetryRequest(mdcache, mut)); return; } // send lock request mut->start_locking(lock, target); mut->more()->slaves.insert(target); MMDSSlaveRequest *r = new MMDSSlaveRequest(mut->reqid, mut->attempt, MMDSSlaveRequest::OP_WRLOCK); r->set_lock_type(lock->get_type()); lock->get_parent()->set_object_info(r->get_object_info()); mds->send_message_mds(r, target); assert(mut->more()->waiting_on_slave.count(target) == 0); mut->more()->waiting_on_slave.insert(target); } void Locker::remote_wrlock_finish(SimpleLock *lock, int target, MutationImpl *mut) { // drop ref mut->remote_wrlocks.erase(lock); if (mut->wrlocks.count(lock) == 0) mut->locks.erase(lock); dout(7) << "remote_wrlock_finish releasing remote wrlock on mds." << target << " " << *lock->get_parent() << dendl; if (mds->mdsmap->get_state(target) >= MDSMap::STATE_REJOIN) { MMDSSlaveRequest *slavereq = new MMDSSlaveRequest(mut->reqid, mut->attempt, MMDSSlaveRequest::OP_UNWRLOCK); slavereq->set_lock_type(lock->get_type()); lock->get_parent()->set_object_info(slavereq->get_object_info()); mds->send_message_mds(slavereq, target); } } // ------------------ // xlock bool Locker::xlock_start(SimpleLock *lock, MDRequestRef& mut) { if (lock->get_type() == CEPH_LOCK_IVERSION || lock->get_type() == CEPH_LOCK_DVERSION) return local_xlock_start(static_cast(lock), mut); dout(7) << "xlock_start on " << *lock << " on " << *lock->get_parent() << dendl; client_t client = mut->get_client(); // auth? if (lock->get_parent()->is_auth()) { // auth while (1) { if (lock->can_xlock(client)) { lock->set_state(LOCK_XLOCK); lock->get_xlock(mut, client); mut->xlocks.insert(lock); mut->locks.insert(lock); mut->finish_locking(lock); return true; } if (!lock->is_stable() && !(lock->get_state() == LOCK_XLOCKDONE && lock->get_xlock_by_client() == client)) break; if (lock->get_state() == LOCK_LOCK || lock->get_state() == LOCK_XLOCKDONE) { mut->start_locking(lock); simple_xlock(lock); } else { simple_lock(lock); } } lock->add_waiter(SimpleLock::WAIT_WR|SimpleLock::WAIT_STABLE, new C_MDS_RetryRequest(mdcache, mut)); nudge_log(lock); return false; } else { // replica assert(lock->get_sm()->can_remote_xlock); assert(!mut->slave_request); // wait for single auth if (lock->get_parent()->is_ambiguous_auth()) { lock->get_parent()->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, new C_MDS_RetryRequest(mdcache, mut)); return false; } // wait for active auth int auth = lock->get_parent()->authority().first; if (!mds->mdsmap->is_clientreplay_or_active_or_stopping(auth)) { dout(7) << " mds." << auth << " is not active" << dendl; if (mut->more()->waiting_on_slave.empty()) mds->wait_for_active_peer(auth, new C_MDS_RetryRequest(mdcache, mut)); return false; } // send lock request mut->more()->slaves.insert(auth); mut->start_locking(lock, auth); MMDSSlaveRequest *r = new MMDSSlaveRequest(mut->reqid, mut->attempt, MMDSSlaveRequest::OP_XLOCK); r->set_lock_type(lock->get_type()); lock->get_parent()->set_object_info(r->get_object_info()); mds->send_message_mds(r, auth); assert(mut->more()->waiting_on_slave.count(auth) == 0); mut->more()->waiting_on_slave.insert(auth); return false; } } void Locker::_finish_xlock(SimpleLock *lock, client_t xlocker, bool *pneed_issue) { assert(!lock->is_stable()); if (lock->get_num_rdlocks() == 0 && lock->get_num_wrlocks() == 0 && lock->get_num_client_lease() == 0 && lock->get_type() != CEPH_LOCK_DN) { CInode *in = static_cast(lock->get_parent()); client_t loner = in->get_target_loner(); if (loner >= 0 && (xlocker < 0 || xlocker == loner)) { lock->set_state(LOCK_EXCL); lock->get_parent()->auth_unpin(lock); lock->finish_waiters(SimpleLock::WAIT_STABLE|SimpleLock::WAIT_WR|SimpleLock::WAIT_RD); if (lock->get_cap_shift()) *pneed_issue = true; if (lock->get_parent()->is_auth() && lock->is_stable()) try_eval(lock, pneed_issue); return; } } // the xlocker may have CEPH_CAP_GSHARED, need to revoke it if next state is LOCK_LOCK eval_gather(lock, true, pneed_issue); } void Locker::xlock_finish(SimpleLock *lock, MutationImpl *mut, bool *pneed_issue) { if (lock->get_type() == CEPH_LOCK_IVERSION || lock->get_type() == CEPH_LOCK_DVERSION) return local_xlock_finish(static_cast(lock), mut); dout(10) << "xlock_finish on " << *lock << " " << *lock->get_parent() << dendl; client_t xlocker = lock->get_xlock_by_client(); // drop ref lock->put_xlock(); assert(mut); mut->xlocks.erase(lock); mut->locks.erase(lock); bool do_issue = false; // remote xlock? if (!lock->get_parent()->is_auth()) { assert(lock->get_sm()->can_remote_xlock); // tell auth dout(7) << "xlock_finish releasing remote xlock on " << *lock->get_parent() << dendl; int auth = lock->get_parent()->authority().first; if (mds->mdsmap->get_state(auth) >= MDSMap::STATE_REJOIN) { MMDSSlaveRequest *slavereq = new MMDSSlaveRequest(mut->reqid, mut->attempt, MMDSSlaveRequest::OP_UNXLOCK); slavereq->set_lock_type(lock->get_type()); lock->get_parent()->set_object_info(slavereq->get_object_info()); mds->send_message_mds(slavereq, auth); } // others waiting? lock->finish_waiters(SimpleLock::WAIT_STABLE | SimpleLock::WAIT_WR | SimpleLock::WAIT_RD, 0); } else { if (lock->get_num_xlocks() == 0) { if (lock->get_state() == LOCK_LOCK_XLOCK) lock->set_state(LOCK_XLOCKDONE); _finish_xlock(lock, xlocker, &do_issue); } } if (do_issue) { CInode *in = static_cast(lock->get_parent()); if (in->is_head()) { if (pneed_issue) *pneed_issue = true; else issue_caps(in); } } } void Locker::xlock_export(SimpleLock *lock, MutationImpl *mut) { dout(10) << "xlock_export on " << *lock << " " << *lock->get_parent() << dendl; lock->put_xlock(); mut->xlocks.erase(lock); mut->locks.erase(lock); MDSCacheObject *p = lock->get_parent(); assert(p->state_test(CInode::STATE_AMBIGUOUSAUTH)); // we are exporting this (inode) if (!lock->is_stable()) lock->get_parent()->auth_unpin(lock); lock->set_state(LOCK_LOCK); } void Locker::xlock_import(SimpleLock *lock) { dout(10) << "xlock_import on " << *lock << " " << *lock->get_parent() << dendl; lock->get_parent()->auth_pin(lock); } // file i/o ----------------------------------------- version_t Locker::issue_file_data_version(CInode *in) { dout(7) << "issue_file_data_version on " << *in << dendl; return in->inode.file_data_version; } struct C_Locker_FileUpdate_finish : public Context { Locker *locker; CInode *in; MutationRef mut; bool share; client_t client; Capability *cap; MClientCaps *ack; C_Locker_FileUpdate_finish(Locker *l, CInode *i, MutationRef& m, bool e=false, client_t c=-1, Capability *cp = 0, MClientCaps *ac = 0) : locker(l), in(i), mut(m), share(e), client(c), cap(cp), ack(ac) { in->get(CInode::PIN_PTRWAITER); } void finish(int r) { locker->file_update_finish(in, mut, share, client, cap, ack); } }; void Locker::file_update_finish(CInode *in, MutationRef& mut, bool share, client_t client, Capability *cap, MClientCaps *ack) { dout(10) << "file_update_finish on " << *in << dendl; in->pop_and_dirty_projected_inode(mut->ls); in->put(CInode::PIN_PTRWAITER); mut->apply(); if (ack) mds->send_message_client_counted(ack, client); set need_issue; drop_locks(mut.get(), &need_issue); if (!in->is_head() && !in->client_snap_caps.empty()) { dout(10) << " client_snap_caps " << in->client_snap_caps << dendl; // check for snap writeback completion bool gather = false; map >::iterator p = in->client_snap_caps.begin(); while (p != in->client_snap_caps.end()) { SimpleLock *lock = in->get_lock(p->first); assert(lock); dout(10) << " completing client_snap_caps for " << ccap_string(p->first) << " lock " << *lock << " on " << *in << dendl; lock->put_wrlock(); p->second.erase(client); if (p->second.empty()) { gather = true; in->client_snap_caps.erase(p++); } else ++p; } if (gather) eval_cap_gather(in, &need_issue); } else { if (cap && (cap->wanted() & ~cap->pending()) && need_issue.count(in) == 0) { // if we won't issue below anyway issue_caps(in, cap); } if (share && in->is_auth() && (in->filelock.gcaps_allowed(CAP_LONER) & (CEPH_CAP_GWR|CEPH_CAP_GBUFFER))) share_inode_max_size(in); } issue_caps_set(need_issue); // auth unpin after issuing caps mut->cleanup(); } Capability* Locker::issue_new_caps(CInode *in, int mode, Session *session, SnapRealm *realm, bool is_replay) { dout(7) << "issue_new_caps for mode " << mode << " on " << *in << dendl; bool is_new; // if replay, try to reconnect cap, and otherwise do nothing. if (is_replay) { mds->mdcache->try_reconnect_cap(in, session); return 0; } // my needs assert(session->info.inst.name.is_client()); int my_client = session->info.inst.name.num(); int my_want = ceph_caps_for_mode(mode); // register a capability Capability *cap = in->get_client_cap(my_client); if (!cap) { // new cap cap = in->add_client_cap(my_client, session, realm); cap->set_wanted(my_want); cap->mark_new(); cap->inc_suppress(); // suppress file cap messages for new cap (we'll bundle with the open() reply) is_new = true; } else { is_new = false; // make sure it wants sufficient caps if (my_want & ~cap->wanted()) { // augment wanted caps for this client cap->set_wanted(cap->wanted() | my_want); } } if (in->is_auth()) { // [auth] twiddle mode? eval(in, CEPH_CAP_LOCKS); if (!in->filelock.is_stable() || !in->authlock.is_stable() || !in->linklock.is_stable() || !in->xattrlock.is_stable()) mds->mdlog->flush(); } else { // [replica] tell auth about any new caps wanted request_inode_file_caps(in); } // issue caps (pot. incl new one) //issue_caps(in); // note: _eval above may have done this already... // re-issue whatever we can //cap->issue(cap->pending()); if (is_new) cap->dec_suppress(); return cap; } void Locker::issue_caps_set(set& inset) { for (set::iterator p = inset.begin(); p != inset.end(); ++p) issue_caps(*p); } bool Locker::issue_caps(CInode *in, Capability *only_cap) { // allowed caps are determined by the lock mode. int all_allowed = in->get_caps_allowed_by_type(CAP_ANY); int loner_allowed = in->get_caps_allowed_by_type(CAP_LONER); int xlocker_allowed = in->get_caps_allowed_by_type(CAP_XLOCKER); client_t loner = in->get_loner(); if (loner >= 0) { dout(7) << "issue_caps loner client." << loner << " allowed=" << ccap_string(loner_allowed) << ", xlocker allowed=" << ccap_string(xlocker_allowed) << ", others allowed=" << ccap_string(all_allowed) << " on " << *in << dendl; } else { dout(7) << "issue_caps allowed=" << ccap_string(all_allowed) << ", xlocker allowed=" << ccap_string(xlocker_allowed) << " on " << *in << dendl; } assert(in->is_head()); // count conflicts with int nissued = 0; // client caps map::iterator it; if (only_cap) it = in->client_caps.find(only_cap->get_client()); else it = in->client_caps.begin(); for (; it != in->client_caps.end(); ++it) { Capability *cap = it->second; if (cap->is_stale()) continue; // do not issue _new_ bits when size|mtime is projected int allowed; if (loner == it->first) allowed = loner_allowed; else allowed = all_allowed; // add in any xlocker-only caps (for locks this client is the xlocker for) allowed |= xlocker_allowed & in->get_xlocker_mask(it->first); Session *session = mds->get_session(it->first); if (in->inode.inline_version != CEPH_INLINE_NONE && !(session && session->connection && session->connection->has_feature(CEPH_FEATURE_MDS_INLINE_DATA))) allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR); int pending = cap->pending(); int wanted = cap->wanted(); dout(20) << " client." << it->first << " pending " << ccap_string(pending) << " allowed " << ccap_string(allowed) << " wanted " << ccap_string(wanted) << dendl; // skip if suppress, and not revocation if (cap->is_suppress() && !(pending & ~allowed)) { dout(20) << " suppressed and !revoke, skipping client." << it->first << dendl; continue; } // notify clients about deleted inode, to make sure they release caps ASAP. if (in->inode.nlink == 0) wanted |= CEPH_CAP_LINK_SHARED; // are there caps that the client _wants_ and can have, but aren't pending? // or do we need to revoke? if (((wanted & allowed) & ~pending) || // missing wanted+allowed caps (pending & ~allowed)) { // need to revoke ~allowed caps. // issue nissued++; // include caps that clients generally like, while we're at it. int likes = in->get_caps_liked(); int before = pending; long seq; if (pending & ~allowed) seq = cap->issue((wanted|likes) & allowed & pending); // if revoking, don't issue anything new. else seq = cap->issue((wanted|likes) & allowed); int after = cap->pending(); if (cap->is_new()) { // haven't send caps to client yet if (before & ~after) cap->confirm_receipt(seq, after); } else { dout(7) << " sending MClientCaps to client." << it->first << " seq " << cap->get_last_seq() << " new pending " << ccap_string(after) << " was " << ccap_string(before) << dendl; MClientCaps *m = new MClientCaps((before & ~after) ? CEPH_CAP_OP_REVOKE:CEPH_CAP_OP_GRANT, in->ino(), in->find_snaprealm()->inode->ino(), cap->get_cap_id(), cap->get_last_seq(), after, wanted, 0, cap->get_mseq()); in->encode_cap_message(m, cap); mds->send_message_client_counted(m, it->first); } } if (only_cap) break; } return (nissued == 0); // true if no re-issued, no callbacks } void Locker::issue_truncate(CInode *in) { dout(7) << "issue_truncate on " << *in << dendl; for (map::iterator it = in->client_caps.begin(); it != in->client_caps.end(); ++it) { Capability *cap = it->second; MClientCaps *m = new MClientCaps(CEPH_CAP_OP_TRUNC, in->ino(), in->find_snaprealm()->inode->ino(), cap->get_cap_id(), cap->get_last_seq(), cap->pending(), cap->wanted(), 0, cap->get_mseq()); in->encode_cap_message(m, cap); mds->send_message_client_counted(m, it->first); } // should we increase max_size? if (in->is_auth() && in->is_file()) check_inode_max_size(in); } void Locker::revoke_stale_caps(Session *session) { dout(10) << "revoke_stale_caps for " << session->info.inst.name << dendl; client_t client = session->get_client(); for (xlist::iterator p = session->caps.begin(); !p.end(); ++p) { Capability *cap = *p; cap->mark_stale(); CInode *in = cap->get_inode(); int issued = cap->issued(); if (issued & ~CEPH_CAP_PIN) { dout(10) << " revoking " << ccap_string(issued) << " on " << *in << dendl; cap->revoke(); if (in->is_auth() && in->inode.client_ranges.count(client)) in->state_set(CInode::STATE_NEEDSRECOVER); if (!in->filelock.is_stable()) eval_gather(&in->filelock); if (!in->linklock.is_stable()) eval_gather(&in->linklock); if (!in->authlock.is_stable()) eval_gather(&in->authlock); if (!in->xattrlock.is_stable()) eval_gather(&in->xattrlock); if (in->is_auth()) { try_eval(in, CEPH_CAP_LOCKS); } else { request_inode_file_caps(in); } } else { dout(10) << " nothing issued on " << *in << dendl; } } } void Locker::resume_stale_caps(Session *session) { dout(10) << "resume_stale_caps for " << session->info.inst.name << dendl; for (xlist::iterator p = session->caps.begin(); !p.end(); ++p) { Capability *cap = *p; CInode *in = cap->get_inode(); assert(in->is_head()); if (cap->is_stale()) { dout(10) << " clearing stale flag on " << *in << dendl; cap->clear_stale(); if (!in->is_auth() || !eval(in, CEPH_CAP_LOCKS)) issue_caps(in, cap); } } } void Locker::remove_stale_leases(Session *session) { dout(10) << "remove_stale_leases for " << session->info.inst.name << dendl; xlist::iterator p = session->leases.begin(); while (!p.end()) { ClientLease *l = *p; ++p; CDentry *parent = static_cast(l->parent); dout(15) << " removing lease on " << *parent << dendl; parent->remove_client_lease(l, this); } } class C_MDL_RequestInodeFileCaps : public Context { Locker *locker; CInode *in; public: C_MDL_RequestInodeFileCaps(Locker *l, CInode *i) : locker(l), in(i) { in->get(CInode::PIN_PTRWAITER); } void finish(int r) { in->put(CInode::PIN_PTRWAITER); if (!in->is_auth()) locker->request_inode_file_caps(in); } }; void Locker::request_inode_file_caps(CInode *in) { assert(!in->is_auth()); int wanted = in->get_caps_wanted() & ~CEPH_CAP_PIN; if (wanted != in->replica_caps_wanted) { // wait for single auth if (in->is_ambiguous_auth()) { in->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, new C_MDL_RequestInodeFileCaps(this, in)); return; } int auth = in->authority().first; if (mds->mdsmap->get_state(auth) == MDSMap::STATE_REJOIN) { mds->wait_for_active_peer(auth, new C_MDL_RequestInodeFileCaps(this, in)); return; } dout(7) << "request_inode_file_caps " << ccap_string(wanted) << " was " << ccap_string(in->replica_caps_wanted) << " on " << *in << " to mds." << auth << dendl; in->replica_caps_wanted = wanted; if (mds->mdsmap->is_clientreplay_or_active_or_stopping(auth)) mds->send_message_mds(new MInodeFileCaps(in->ino(), in->replica_caps_wanted), auth); } } /* This function DOES put the passed message before returning */ void Locker::handle_inode_file_caps(MInodeFileCaps *m) { // nobody should be talking to us during recovery. assert(mds->is_clientreplay() || mds->is_active() || mds->is_stopping()); // ok CInode *in = mdcache->get_inode(m->get_ino()); int from = m->get_source().num(); assert(in); assert(in->is_auth()); dout(7) << "handle_inode_file_caps replica mds." << from << " wants caps " << ccap_string(m->get_caps()) << " on " << *in << dendl; if (m->get_caps()) in->mds_caps_wanted[from] = m->get_caps(); else in->mds_caps_wanted.erase(from); try_eval(in, CEPH_CAP_LOCKS); m->put(); } class C_MDL_CheckMaxSize : public Context { Locker *locker; CInode *in; bool update_size; uint64_t newsize; bool update_max; uint64_t new_max_size; utime_t mtime; public: C_MDL_CheckMaxSize(Locker *l, CInode *i, bool _update_size, uint64_t _newsize, bool _update_max, uint64_t _new_max_size, utime_t _mtime) : locker(l), in(i), update_size(_update_size), newsize(_newsize), update_max(_update_max), new_max_size(_new_max_size), mtime(_mtime) { in->get(CInode::PIN_PTRWAITER); } void finish(int r) { in->put(CInode::PIN_PTRWAITER); if (in->is_auth()) locker->check_inode_max_size(in, false, update_size, newsize, update_max, new_max_size, mtime); } }; void Locker::calc_new_client_ranges(CInode *in, uint64_t size, map& new_ranges) { inode_t *latest = in->get_projected_inode(); uint64_t ms; if(latest->has_layout()) { ms = ROUND_UP_TO((size+1)<<1, latest->get_layout_size_increment()); } else { // Layout-less directories like ~mds0/, have zero size ms = 0; } // increase ranges as appropriate. // shrink to 0 if no WR|BUFFER caps issued. for (map::iterator p = in->client_caps.begin(); p != in->client_caps.end(); ++p) { if ((p->second->issued() | p->second->wanted()) & (CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER)) { client_writeable_range_t& nr = new_ranges[p->first]; nr.range.first = 0; if (latest->client_ranges.count(p->first)) { client_writeable_range_t& oldr = latest->client_ranges[p->first]; nr.range.last = MAX(ms, oldr.range.last); nr.follows = oldr.follows; } else { nr.range.last = ms; nr.follows = in->first - 1; } } } } bool Locker::check_inode_max_size(CInode *in, bool force_wrlock, bool update_size, uint64_t new_size, bool update_max, uint64_t new_max_size, utime_t new_mtime) { assert(in->is_auth()); inode_t *latest = in->get_projected_inode(); map new_ranges; uint64_t size = latest->size; bool new_max = update_max; if (update_size) { new_size = size = MAX(size, new_size); new_mtime = MAX(new_mtime, latest->mtime); if (latest->size == new_size && latest->mtime == new_mtime) update_size = false; } uint64_t client_range_size = update_max ? new_max_size : size; calc_new_client_ranges(in, client_range_size, new_ranges); if (latest->client_ranges != new_ranges) new_max = true; if (!update_size && !new_max) { dout(20) << "check_inode_max_size no-op on " << *in << dendl; return false; } dout(10) << "check_inode_max_size new_ranges " << new_ranges << " update_size " << update_size << " on " << *in << dendl; if (in->is_frozen()) { dout(10) << "check_inode_max_size frozen, waiting on " << *in << dendl; C_MDL_CheckMaxSize *cms = new C_MDL_CheckMaxSize(this, in, update_size, new_size, update_max, new_max_size, new_mtime); in->add_waiter(CInode::WAIT_UNFREEZE, cms); return false; } if (!force_wrlock && !in->filelock.can_wrlock(in->get_loner())) { // lock? if (in->filelock.is_stable()) { if (in->get_target_loner() >= 0) file_excl(&in->filelock); else simple_lock(&in->filelock); } if (!in->filelock.can_wrlock(in->get_loner())) { // try again later C_MDL_CheckMaxSize *cms = new C_MDL_CheckMaxSize(this, in, update_size, new_size, update_max, new_max_size, new_mtime); in->filelock.add_waiter(SimpleLock::WAIT_STABLE, cms); dout(10) << "check_inode_max_size can't wrlock, waiting on " << *in << dendl; return false; } } MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); if (new_max) { dout(10) << "check_inode_max_size client_ranges " << pi->client_ranges << " -> " << new_ranges << dendl; pi->client_ranges = new_ranges; } if (update_size) { dout(10) << "check_inode_max_size size " << pi->size << " -> " << new_size << dendl; pi->size = new_size; pi->rstat.rbytes = new_size; dout(10) << "check_inode_max_size mtime " << pi->mtime << " -> " << new_mtime << dendl; pi->mtime = new_mtime; } // use EOpen if the file is still open; otherwise, use EUpdate. // this is just an optimization to push open files forward into // newer log segments. LogEvent *le; EMetaBlob *metablob; if (in->is_any_caps_wanted() && in->last == CEPH_NOSNAP) { EOpen *eo = new EOpen(mds->mdlog); eo->add_ino(in->ino()); metablob = &eo->metablob; le = eo; mut->ls->open_files.push_back(&in->item_open_file); } else { EUpdate *eu = new EUpdate(mds->mdlog, "check_inode_max_size"); metablob = &eu->metablob; le = eu; } mds->mdlog->start_entry(le); if (update_size) { // FIXME if/when we do max_size nested accounting mdcache->predirty_journal_parents(mut, metablob, in, 0, PREDIRTY_PRIMARY); // no cow, here! CDentry *parent = in->get_projected_parent_dn(); metablob->add_primary_dentry(parent, in, true); } else { metablob->add_dir_context(in->get_projected_parent_dn()->get_dir()); mdcache->journal_dirty_inode(mut.get(), metablob, in); } mds->mdlog->submit_entry(le, new C_Locker_FileUpdate_finish(this, in, mut, true)); wrlock_force(&in->filelock, mut); // wrlock for duration of journal mut->auth_pin(in); // make max_size _increase_ timely if (new_max) mds->mdlog->flush(); return true; } void Locker::share_inode_max_size(CInode *in, Capability *only_cap) { /* * only share if currently issued a WR cap. if client doesn't have it, * file_max doesn't matter, and the client will get it if/when they get * the cap later. */ dout(10) << "share_inode_max_size on " << *in << dendl; map::iterator it; if (only_cap) it = in->client_caps.find(only_cap->get_client()); else it = in->client_caps.begin(); for (; it != in->client_caps.end(); ++it) { const client_t client = it->first; Capability *cap = it->second; if (cap->is_suppress()) continue; if (cap->pending() & (CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER)) { dout(10) << "share_inode_max_size with client." << client << dendl; cap->inc_last_seq(); MClientCaps *m = new MClientCaps(CEPH_CAP_OP_GRANT, in->ino(), in->find_snaprealm()->inode->ino(), cap->get_cap_id(), cap->get_last_seq(), cap->pending(), cap->wanted(), 0, cap->get_mseq()); in->encode_cap_message(m, cap); mds->send_message_client_counted(m, client); } if (only_cap) break; } } void Locker::adjust_cap_wanted(Capability *cap, int wanted, int issue_seq) { if (ceph_seq_cmp(issue_seq, cap->get_last_issue()) == 0) { dout(10) << " wanted " << ccap_string(cap->wanted()) << " -> " << ccap_string(wanted) << dendl; cap->set_wanted(wanted); } else if (wanted & ~cap->wanted()) { dout(10) << " wanted " << ccap_string(cap->wanted()) << " -> " << ccap_string(wanted) << " (added caps even though we had seq mismatch!)" << dendl; cap->set_wanted(wanted | cap->wanted()); } else { dout(10) << " NOT changing wanted " << ccap_string(cap->wanted()) << " -> " << ccap_string(wanted) << " (issue_seq " << issue_seq << " != last_issue " << cap->get_last_issue() << ")" << dendl; return; } CInode *cur = cap->get_inode(); if (!cur->is_auth()) { request_inode_file_caps(cur); return; } if (cap->wanted() == 0) { if (cur->item_open_file.is_on_list() && !cur->is_any_caps_wanted()) { dout(10) << " removing unwanted file from open file list " << *cur << dendl; cur->item_open_file.remove_myself(); } } else { if (!cur->item_open_file.is_on_list()) { dout(10) << " adding to open file list " << *cur << dendl; assert(cur->last == CEPH_NOSNAP); LogSegment *ls = mds->mdlog->get_current_segment(); EOpen *le = new EOpen(mds->mdlog); mds->mdlog->start_entry(le); le->add_clean_inode(cur); ls->open_files.push_back(&cur->item_open_file); mds->mdlog->submit_entry(le); } } } void Locker::_do_null_snapflush(CInode *head_in, client_t client, snapid_t follows) { dout(10) << "_do_null_snapflish client." << client << " follows " << follows << " on " << *head_in << dendl; map >::iterator p = head_in->client_need_snapflush.begin(); while (p != head_in->client_need_snapflush.end()) { snapid_t snapid = p->first; set& clients = p->second; ++p; // be careful, q loop below depends on this // snapid is the snap inode's ->last if (follows > snapid) break; if (clients.count(client)) { dout(10) << " doing async NULL snapflush on " << snapid << " from client." << client << dendl; CInode *sin = mdcache->get_inode(head_in->ino(), snapid); if (!sin) { // hrm, look forward until we find the inode. // (we can only look it up by the last snapid it is valid for) dout(10) << " didn't have " << head_in->ino() << " snapid " << snapid << dendl; for (map >::iterator q = p; // p is already at next entry q != head_in->client_need_snapflush.end(); ++q) { dout(10) << " trying snapid " << q->first << dendl; sin = mdcache->get_inode(head_in->ino(), q->first); if (sin) { assert(sin->first <= snapid); break; } dout(10) << " didn't have " << head_in->ino() << " snapid " << q->first << dendl; } if (!sin && head_in->is_multiversion()) sin = head_in; assert(sin); } _do_snap_update(sin, snapid, 0, sin->first - 1, client, NULL, NULL); head_in->remove_need_snapflush(sin, snapid, client); } } } bool Locker::should_defer_client_cap_frozen(CInode *in) { /* * This policy needs to be AT LEAST as permissive as allowing a client request * to go forward, or else a client request can release something, the release * gets deferred, but the request gets processed and deadlocks because when the * caps can't get revoked. * * Currently, a request wait if anything locked is freezing (can't * auth_pin), which would avoid any deadlock with cap release. Thus @in * _MUST_ be in the lock/auth_pin set. * * auth_pins==0 implies no unstable lock and not auth pinnned by * client request, otherwise continue even it's freezing. */ return (in->is_freezing() && in->get_num_auth_pins() == 0) || in->is_frozen(); } /* * This function DOES put the passed message before returning */ void Locker::handle_client_caps(MClientCaps *m) { client_t client = m->get_source().num(); snapid_t follows = m->get_snap_follows(); dout(7) << "handle_client_caps on " << m->get_ino() << " follows " << follows << " op " << ceph_cap_op_name(m->get_op()) << dendl; if (!mds->is_clientreplay() && !mds->is_active() && !mds->is_stopping()) { mds->wait_for_replay(new C_MDS_RetryMessage(mds, m)); return; } CInode *head_in = mdcache->get_inode(m->get_ino()); if (!head_in) { dout(7) << "handle_client_caps on unknown ino " << m->get_ino() << ", dropping" << dendl; m->put(); return; } CInode *in = mdcache->pick_inode_snap(head_in, follows); if (in != head_in) dout(10) << " head inode " << *head_in << dendl; dout(10) << " cap inode " << *in << dendl; Capability *cap = 0; cap = in->get_client_cap(client); if (!cap && in != head_in) cap = head_in->get_client_cap(client); if (!cap) { dout(7) << "handle_client_caps no cap for client." << client << " on " << *in << dendl; m->put(); return; } assert(cap); // freezing|frozen? if (should_defer_client_cap_frozen(in)) { dout(7) << "handle_client_caps freezing|frozen on " << *in << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, new C_MDS_RetryMessage(mds, m)); return; } if (ceph_seq_cmp(m->get_mseq(), cap->get_mseq()) < 0) { dout(7) << "handle_client_caps mseq " << m->get_mseq() << " < " << cap->get_mseq() << ", dropping" << dendl; m->put(); return; } int op = m->get_op(); // flushsnap? if (op == CEPH_CAP_OP_FLUSHSNAP) { if (!in->is_auth()) { dout(7) << " not auth, ignoring flushsnap on " << *in << dendl; goto out; } SnapRealm *realm = in->find_snaprealm(); snapid_t snap = realm->get_snap_following(follows); dout(10) << " flushsnap follows " << follows << " -> snap " << snap << dendl; if (in == head_in || (head_in->client_need_snapflush.count(snap) && head_in->client_need_snapflush[snap].count(client))) { dout(7) << " flushsnap snap " << snap << " client." << client << " on " << *in << dendl; // this cap now follows a later snap (i.e. the one initiating this flush, or later) cap->client_follows = MAX(follows, in->first) + 1; // we can prepare the ack now, since this FLUSHEDSNAP is independent of any // other cap ops. (except possibly duplicate FLUSHSNAP requests, but worst // case we get a dup response, so whatever.) MClientCaps *ack = 0; if (m->get_dirty()) { ack = new MClientCaps(CEPH_CAP_OP_FLUSHSNAP_ACK, in->ino(), 0, 0, 0, 0, 0, m->get_dirty(), 0); ack->set_snap_follows(follows); ack->set_client_tid(m->get_client_tid()); } _do_snap_update(in, snap, m->get_dirty(), follows, client, m, ack); if (in != head_in) head_in->remove_need_snapflush(in, snap, client); } else dout(7) << " not expecting flushsnap " << snap << " from client." << client << " on " << *in << dendl; goto out; } if (cap->get_cap_id() != m->get_cap_id()) { dout(7) << " ignoring client capid " << m->get_cap_id() << " != my " << cap->get_cap_id() << dendl; } else { // intermediate snap inodes while (in != head_in) { assert(in->last != CEPH_NOSNAP); if (in->is_auth() && m->get_dirty()) { dout(10) << " updating intermediate snapped inode " << *in << dendl; _do_cap_update(in, NULL, m->get_dirty(), follows, m, NULL); } in = mdcache->pick_inode_snap(head_in, in->last); } // head inode, and cap MClientCaps *ack = 0; int caps = m->get_caps(); if (caps & ~cap->issued()) { dout(10) << " confirming not issued caps " << ccap_string(caps & ~cap->issued()) << dendl; caps &= cap->issued(); } cap->confirm_receipt(m->get_seq(), caps); dout(10) << " follows " << follows << " retains " << ccap_string(m->get_caps()) << " dirty " << ccap_string(m->get_dirty()) << " on " << *in << dendl; // missing/skipped snapflush? // The client MAY send a snapflush if it is issued WR/EXCL caps, but // presently only does so when it has actual dirty metadata. But, we // set up the need_snapflush stuff based on the issued caps. // We can infer that the client WONT send a FLUSHSNAP once they have // released all WR/EXCL caps (the FLUSHSNAP always comes before the cap // update/release). if (!head_in->client_need_snapflush.empty()) { if ((cap->issued() & CEPH_CAP_ANY_FILE_WR) == 0) { _do_null_snapflush(head_in, client, follows); } else { dout(10) << " revocation in progress, not making any conclusions about null snapflushes" << dendl; } } if (m->get_dirty() && in->is_auth()) { dout(7) << " flush client." << client << " dirty " << ccap_string(m->get_dirty()) << " seq " << m->get_seq() << " on " << *in << dendl; ack = new MClientCaps(CEPH_CAP_OP_FLUSH_ACK, in->ino(), 0, cap->get_cap_id(), m->get_seq(), m->get_caps(), 0, m->get_dirty(), 0); ack->set_client_tid(m->get_client_tid()); } // filter wanted based on what we could ever give out (given auth/replica status) int new_wanted = m->get_wanted() & head_in->get_caps_allowed_ever(); if (new_wanted != cap->wanted()) { if (new_wanted & ~cap->wanted()) { // exapnding caps. make sure we aren't waiting for a log flush if (!in->filelock.is_stable() || !in->authlock.is_stable() || !in->xattrlock.is_stable()) mds->mdlog->flush(); } adjust_cap_wanted(cap, new_wanted, m->get_issue_seq()); } if (in->is_auth() && _do_cap_update(in, cap, m->get_dirty(), follows, m, ack)) { // updated eval(in, CEPH_CAP_LOCKS); if (cap->wanted() & ~cap->pending()) mds->mdlog->flush(); } else { // no update, ack now. if (ack) mds->send_message_client_counted(ack, m->get_connection()); bool did_issue = eval(in, CEPH_CAP_LOCKS); if (!did_issue && (cap->wanted() & ~cap->pending())) issue_caps(in, cap); if (cap->get_last_seq() == 0 && (cap->pending() & (CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER))) { cap->issue_norevoke(cap->issued()); share_inode_max_size(in, cap); } } } out: m->put(); } class C_Locker_RetryRequestCapRelease : public Context { Locker *locker; client_t client; ceph_mds_request_release item; public: C_Locker_RetryRequestCapRelease(Locker *l, client_t c, const ceph_mds_request_release& it) : locker(l), client(c), item(it) { } void finish(int r) { string dname; MDRequestRef null_ref; locker->process_request_cap_release(null_ref, client, item, dname); } }; void Locker::process_request_cap_release(MDRequestRef& mdr, client_t client, const ceph_mds_request_release& item, const string &dname) { inodeno_t ino = (uint64_t)item.ino; uint64_t cap_id = item.cap_id; int caps = item.caps; int wanted = item.wanted; int seq = item.seq; int issue_seq = item.issue_seq; int mseq = item.mseq; CInode *in = mdcache->get_inode(ino); if (!in) return; if (dname.length()) { frag_t fg = in->pick_dirfrag(dname); CDir *dir = in->get_dirfrag(fg); if (dir) { CDentry *dn = dir->lookup(dname); if (dn) { ClientLease *l = dn->get_client_lease(client); if (l) { dout(10) << "process_cap_release removing lease on " << *dn << dendl; dn->remove_client_lease(l, this); } else { dout(7) << "process_cap_release client." << client << " doesn't have lease on " << *dn << dendl; } } else { dout(7) << "process_cap_release client." << client << " released lease on dn " << dir->dirfrag() << "/" << dname << " which dne" << dendl; } } } Capability *cap = in->get_client_cap(client); if (!cap) return; dout(10) << "process_cap_release client." << client << " " << ccap_string(caps) << " on " << *in << (mdr ? "" : " (DEFERRED, no mdr)") << dendl; if (ceph_seq_cmp(mseq, cap->get_mseq()) < 0) { dout(7) << " mseq " << mseq << " < " << cap->get_mseq() << ", dropping" << dendl; return; } if (cap->get_cap_id() != cap_id) { dout(7) << " cap_id " << cap_id << " != " << cap->get_cap_id() << ", dropping" << dendl; return; } if (should_defer_client_cap_frozen(in)) { dout(7) << " frozen, deferring" << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, new C_Locker_RetryRequestCapRelease(this, client, item)); return; } if (caps & ~cap->issued()) { dout(10) << " confirming not issued caps " << ccap_string(caps & ~cap->issued()) << dendl; caps &= cap->issued(); } cap->confirm_receipt(seq, caps); adjust_cap_wanted(cap, wanted, issue_seq); if (mdr) cap->inc_suppress(); eval(in, CEPH_CAP_LOCKS); if (mdr) cap->dec_suppress(); // take note; we may need to reissue on this cap later if (mdr) mdr->cap_releases[in->vino()] = cap->get_last_seq(); } class C_Locker_RetryKickIssueCaps : public Context { Locker *locker; CInode *in; client_t client; ceph_seq_t seq; public: C_Locker_RetryKickIssueCaps(Locker *l, CInode *i, client_t c, ceph_seq_t s) : locker(l), in(i), client(c), seq(s) { in->get(CInode::PIN_PTRWAITER); } void finish(int r) { locker->kick_issue_caps(in, client, seq); in->put(CInode::PIN_PTRWAITER); } }; void Locker::kick_issue_caps(CInode *in, client_t client, ceph_seq_t seq) { Capability *cap = in->get_client_cap(client); if (!cap || cap->get_last_sent() != seq) return; if (in->is_frozen()) { dout(10) << "kick_issue_caps waiting for unfreeze on " << *in << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, new C_Locker_RetryKickIssueCaps(this, in, client, seq)); return; } dout(10) << "kick_issue_caps released at current seq " << seq << ", reissuing" << dendl; issue_caps(in, cap); } void Locker::kick_cap_releases(MDRequestRef& mdr) { client_t client = mdr->get_client(); for (map::iterator p = mdr->cap_releases.begin(); p != mdr->cap_releases.end(); ++p) { CInode *in = mdcache->get_inode(p->first); if (!in) continue; kick_issue_caps(in, client, p->second); } } static uint64_t calc_bounding(uint64_t t) { t |= t >> 1; t |= t >> 2; t |= t >> 4; t |= t >> 8; t |= t >> 16; t |= t >> 32; return t + 1; } /** * m and ack might be NULL, so don't dereference them unless dirty != 0 */ void Locker::_do_snap_update(CInode *in, snapid_t snap, int dirty, snapid_t follows, client_t client, MClientCaps *m, MClientCaps *ack) { dout(10) << "_do_snap_update dirty " << ccap_string(dirty) << " follows " << follows << " snap " << snap << " on " << *in << dendl; if (snap == CEPH_NOSNAP) { // hmm, i guess snap was already deleted? just ack! dout(10) << " wow, the snap following " << follows << " was already deleted. nothing to record, just ack." << dendl; if (ack) mds->send_message_client_counted(ack, m->get_connection()); return; } EUpdate *le = new EUpdate(mds->mdlog, "snap flush"); mds->mdlog->start_entry(le); MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); // normal metadata updates that we can apply to the head as well. // update xattrs? bool xattrs = false; map *px = 0; if ((dirty & CEPH_CAP_XATTR_EXCL) && m->xattrbl.length() && m->head.xattr_version > in->get_projected_inode()->xattr_version) xattrs = true; old_inode_t *oi = 0; if (in->is_multiversion()) { oi = in->pick_old_inode(snap); if (oi) { dout(10) << " writing into old inode" << dendl; if (xattrs) px = &oi->xattrs; } } if (xattrs && !px) px = new map; inode_t *pi = in->project_inode(px); pi->version = in->pre_dirty(); if (oi) pi = &oi->inode; _update_cap_fields(in, dirty, m, pi); // xattr if (px) { dout(7) << " xattrs v" << pi->xattr_version << " -> " << m->head.xattr_version << " len " << m->xattrbl.length() << dendl; pi->xattr_version = m->head.xattr_version; bufferlist::iterator p = m->xattrbl.begin(); ::decode(*px, p); } if (pi->client_ranges.count(client)) { if (in->last == follows+1) { dout(10) << " removing client_range entirely" << dendl; pi->client_ranges.erase(client); } else { dout(10) << " client_range now follows " << snap << dendl; pi->client_ranges[client].follows = snap; } } mut->auth_pin(in); mdcache->predirty_journal_parents(mut, &le->metablob, in, 0, PREDIRTY_PRIMARY, 0, follows); mdcache->journal_dirty_inode(mut.get(), &le->metablob, in, follows); mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(new C_Locker_FileUpdate_finish(this, in, mut, false, client, NULL, ack)); } /** * m might be NULL, so don't dereference it unless dirty != 0. */ void Locker::_update_cap_fields(CInode *in, int dirty, MClientCaps *m, inode_t *pi) { if (dirty && m->get_ctime() > pi->ctime) { dout(7) << " ctime " << pi->ctime << " -> " << m->get_ctime() << " for " << *in << dendl; pi->ctime = m->get_ctime(); } // file if (dirty & (CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR)) { utime_t atime = m->get_atime(); utime_t mtime = m->get_mtime(); uint64_t size = m->get_size(); version_t inline_version = m->inline_version; if (((dirty & CEPH_CAP_FILE_WR) && mtime > pi->mtime) || ((dirty & CEPH_CAP_FILE_EXCL) && mtime != pi->mtime)) { dout(7) << " mtime " << pi->mtime << " -> " << mtime << " for " << *in << dendl; pi->mtime = mtime; } if (in->inode.is_file() && // ONLY if regular file size > pi->size) { dout(7) << " size " << pi->size << " -> " << size << " for " << *in << dendl; pi->size = size; pi->rstat.rbytes = size; } if (in->inode.is_file() && (dirty & CEPH_CAP_FILE_WR) && inline_version > pi->inline_version) { pi->inline_version = inline_version; pi->inline_data = m->inline_data; } if ((dirty & CEPH_CAP_FILE_EXCL) && atime != pi->atime) { dout(7) << " atime " << pi->atime << " -> " << atime << " for " << *in << dendl; pi->atime = atime; } if ((dirty & CEPH_CAP_FILE_EXCL) && ceph_seq_cmp(pi->time_warp_seq, m->get_time_warp_seq()) < 0) { dout(7) << " time_warp_seq " << pi->time_warp_seq << " -> " << m->get_time_warp_seq() << " for " << *in << dendl; pi->time_warp_seq = m->get_time_warp_seq(); } } // auth if (dirty & CEPH_CAP_AUTH_EXCL) { if (m->head.uid != pi->uid) { dout(7) << " uid " << pi->uid << " -> " << m->head.uid << " for " << *in << dendl; pi->uid = m->head.uid; } if (m->head.gid != pi->gid) { dout(7) << " gid " << pi->gid << " -> " << m->head.gid << " for " << *in << dendl; pi->gid = m->head.gid; } if (m->head.mode != pi->mode) { dout(7) << " mode " << oct << pi->mode << " -> " << m->head.mode << dec << " for " << *in << dendl; pi->mode = m->head.mode; } } } /* * update inode based on cap flush|flushsnap|wanted. * adjust max_size, if needed. * if we update, return true; otherwise, false (no updated needed). */ bool Locker::_do_cap_update(CInode *in, Capability *cap, int dirty, snapid_t follows, MClientCaps *m, MClientCaps *ack) { dout(10) << "_do_cap_update dirty " << ccap_string(dirty) << " issued " << ccap_string(cap ? cap->issued() : 0) << " wanted " << ccap_string(cap ? cap->wanted() : 0) << " on " << *in << dendl; assert(in->is_auth()); client_t client = m->get_source().num(); inode_t *latest = in->get_projected_inode(); // increase or zero max_size? uint64_t size = m->get_size(); bool change_max = false; uint64_t old_max = latest->client_ranges.count(client) ? latest->client_ranges[client].range.last : 0; uint64_t new_max = old_max; if (in->is_file()) { bool forced_change_max = false; dout(20) << "inode is file" << dendl; if (cap && ((cap->issued() | cap->wanted()) & CEPH_CAP_ANY_FILE_WR)) { dout(20) << "client has write caps; m->get_max_size=" << m->get_max_size() << "; old_max=" << old_max << dendl; if (m->get_max_size() > new_max) { dout(10) << "client requests file_max " << m->get_max_size() << " > max " << old_max << dendl; change_max = true; forced_change_max = true; new_max = ROUND_UP_TO((m->get_max_size()+1) << 1, latest->get_layout_size_increment()); } else { new_max = calc_bounding(size * 2); if (new_max < latest->get_layout_size_increment()) new_max = latest->get_layout_size_increment(); if (new_max > old_max) change_max = true; else new_max = old_max; } } else { if (old_max) { change_max = true; new_max = 0; } } if (in->last == CEPH_NOSNAP && change_max && !in->filelock.can_wrlock(client) && !in->filelock.can_force_wrlock(client)) { dout(10) << " i want to change file_max, but lock won't allow it (yet)" << dendl; if (in->filelock.is_stable()) { bool need_issue = false; if (cap) cap->inc_suppress(); if (in->mds_caps_wanted.empty() && (in->get_loner() >= 0 || (in->get_wanted_loner() >= 0 && in->try_set_loner()))) { if (in->filelock.get_state() != LOCK_EXCL) file_excl(&in->filelock, &need_issue); } else simple_lock(&in->filelock, &need_issue); if (need_issue) issue_caps(in); if (cap) cap->dec_suppress(); } if (!in->filelock.can_wrlock(client) && !in->filelock.can_force_wrlock(client)) { C_MDL_CheckMaxSize *cms = new C_MDL_CheckMaxSize(this, in, false, 0, forced_change_max, new_max, utime_t()); in->filelock.add_waiter(SimpleLock::WAIT_STABLE, cms); change_max = false; } } } if (m->flockbl.length()) { int32_t num_locks; bufferlist::iterator bli = m->flockbl.begin(); ::decode(num_locks, bli); for ( int i=0; i < num_locks; ++i) { ceph_filelock decoded_lock; ::decode(decoded_lock, bli); in->fcntl_locks.held_locks. insert(pair(decoded_lock.start, decoded_lock)); ++in->fcntl_locks.client_held_lock_counts[(client_t)(decoded_lock.client)]; } ::decode(num_locks, bli); for ( int i=0; i < num_locks; ++i) { ceph_filelock decoded_lock; ::decode(decoded_lock, bli); in->flock_locks.held_locks. insert(pair(decoded_lock.start, decoded_lock)); ++in->flock_locks.client_held_lock_counts[(client_t)(decoded_lock.client)]; } } if (!dirty && !change_max) return false; // do the update. EUpdate *le = new EUpdate(mds->mdlog, "cap update"); mds->mdlog->start_entry(le); // xattrs update? map *px = 0; if ((dirty & CEPH_CAP_XATTR_EXCL) && m->xattrbl.length() && m->head.xattr_version > in->get_projected_inode()->xattr_version) px = new map; inode_t *pi = in->project_inode(px); pi->version = in->pre_dirty(); MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); _update_cap_fields(in, dirty, m, pi); if (change_max) { dout(7) << " max_size " << old_max << " -> " << new_max << " for " << *in << dendl; if (new_max) { pi->client_ranges[client].range.first = 0; pi->client_ranges[client].range.last = new_max; pi->client_ranges[client].follows = in->first - 1; } else pi->client_ranges.erase(client); } if (change_max || (dirty & (CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR))) wrlock_force(&in->filelock, mut); // wrlock for duration of journal // auth if (dirty & CEPH_CAP_AUTH_EXCL) wrlock_force(&in->authlock, mut); // xattr if (px) { dout(7) << " xattrs v" << pi->xattr_version << " -> " << m->head.xattr_version << dendl; pi->xattr_version = m->head.xattr_version; bufferlist::iterator p = m->xattrbl.begin(); ::decode(*px, p); wrlock_force(&in->xattrlock, mut); } mut->auth_pin(in); mdcache->predirty_journal_parents(mut, &le->metablob, in, 0, PREDIRTY_PRIMARY, 0, follows); mdcache->journal_dirty_inode(mut.get(), &le->metablob, in, follows); mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(new C_Locker_FileUpdate_finish(this, in, mut, change_max, client, cap, ack)); // only flush immediately if the lock is unstable, or unissued caps are wanted, or max_size is // changing if (((dirty & (CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR)) && !in->filelock.is_stable()) || ((dirty & CEPH_CAP_AUTH_EXCL) && !in->authlock.is_stable()) || ((dirty & CEPH_CAP_XATTR_EXCL) && !in->xattrlock.is_stable()) || (!dirty && (!in->filelock.is_stable() || !in->authlock.is_stable() || !in->xattrlock.is_stable())) || // nothing dirty + unstable lock -> probably a revoke? (change_max && new_max) || // max INCREASE (cap && (cap->wanted() & ~cap->pending()))) mds->mdlog->flush(); return true; } /* This function DOES put the passed message before returning */ void Locker::handle_client_cap_release(MClientCapRelease *m) { client_t client = m->get_source().num(); dout(10) << "handle_client_cap_release " << *m << dendl; if (!mds->is_clientreplay() && !mds->is_active() && !mds->is_stopping()) { mds->wait_for_replay(new C_MDS_RetryMessage(mds, m)); return; } for (vector::iterator p = m->caps.begin(); p != m->caps.end(); ++p) _do_cap_release(client, inodeno_t((uint64_t)p->ino) , p->cap_id, p->migrate_seq, p->seq); m->put(); } class C_Locker_RetryCapRelease : public Context { Locker *locker; client_t client; inodeno_t ino; uint64_t cap_id; ceph_seq_t migrate_seq; ceph_seq_t issue_seq; public: C_Locker_RetryCapRelease(Locker *l, client_t c, inodeno_t i, uint64_t id, ceph_seq_t mseq, ceph_seq_t seq) : locker(l), client(c), ino(i), cap_id(id), migrate_seq(mseq), issue_seq(seq) {} void finish(int r) { locker->_do_cap_release(client, ino, cap_id, migrate_seq, issue_seq); } }; void Locker::_do_cap_release(client_t client, inodeno_t ino, uint64_t cap_id, ceph_seq_t mseq, ceph_seq_t seq) { CInode *in = mdcache->get_inode(ino); if (!in) { dout(7) << "_do_cap_release missing ino " << ino << dendl; return; } Capability *cap = in->get_client_cap(client); if (!cap) { dout(7) << "_do_cap_release no cap for client" << client << " on "<< *in << dendl; return; } dout(7) << "_do_cap_release for client." << client << " on "<< *in << dendl; if (cap->get_cap_id() != cap_id) { dout(7) << " capid " << cap_id << " != " << cap->get_cap_id() << ", ignore" << dendl; return; } if (ceph_seq_cmp(mseq, cap->get_mseq()) < 0) { dout(7) << " mseq " << mseq << " < " << cap->get_mseq() << ", ignore" << dendl; return; } if (should_defer_client_cap_frozen(in)) { dout(7) << " freezing|frozen, deferring" << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, new C_Locker_RetryCapRelease(this, client, ino, cap_id, mseq, seq)); return; } if (seq != cap->get_last_issue()) { dout(7) << " issue_seq " << seq << " != " << cap->get_last_issue() << dendl; // clean out any old revoke history cap->clean_revoke_from(seq); eval_cap_gather(in); return; } remove_client_cap(in, client); } /* This function DOES put the passed message before returning */ void Locker::remove_client_cap(CInode *in, client_t client) { // clean out any pending snapflush state if (!in->client_need_snapflush.empty()) _do_null_snapflush(in, client, 0); in->remove_client_cap(client); if (in->is_auth()) { // make sure we clear out the client byte range if (in->get_projected_inode()->client_ranges.count(client) && !(in->inode.nlink == 0 && !in->is_any_caps())) // unless it's unlink + stray check_inode_max_size(in); } else { request_inode_file_caps(in); } try_eval(in, CEPH_CAP_LOCKS); } void Locker::handle_client_lease(MClientLease *m) { dout(10) << "handle_client_lease " << *m << dendl; assert(m->get_source().is_client()); client_t client = m->get_source().num(); CInode *in = mdcache->get_inode(m->get_ino(), m->get_last()); if (!in) { dout(7) << "handle_client_lease don't have ino " << m->get_ino() << "." << m->get_last() << dendl; m->put(); return; } CDentry *dn = 0; frag_t fg = in->pick_dirfrag(m->dname); CDir *dir = in->get_dirfrag(fg); if (dir) dn = dir->lookup(m->dname); if (!dn) { dout(7) << "handle_client_lease don't have dn " << m->get_ino() << " " << m->dname << dendl; m->put(); return; } dout(10) << " on " << *dn << dendl; // replica and lock ClientLease *l = dn->get_client_lease(client); if (!l) { dout(7) << "handle_client_lease didn't have lease for client." << client << " of " << *dn << dendl; m->put(); return; } switch (m->get_action()) { case CEPH_MDS_LEASE_REVOKE_ACK: case CEPH_MDS_LEASE_RELEASE: if (l->seq != m->get_seq()) { dout(7) << "handle_client_lease release - seq " << l->seq << " != provided " << m->get_seq() << dendl; } else { dout(7) << "handle_client_lease client." << client << " on " << *dn << dendl; dn->remove_client_lease(l, this); } m->put(); break; case CEPH_MDS_LEASE_RENEW: { dout(7) << "handle_client_lease client." << client << " renew on " << *dn << (!dn->lock.can_lease(client)?", revoking lease":"") << dendl; if (dn->lock.can_lease(client)) { int pool = 1; // fixme.. do something smart! m->h.duration_ms = (int)(1000 * mdcache->client_lease_durations[pool]); m->h.seq = ++l->seq; m->clear_payload(); utime_t now = ceph_clock_now(g_ceph_context); now += mdcache->client_lease_durations[pool]; mdcache->touch_client_lease(l, pool, now); mds->send_message_client_counted(m, m->get_connection()); } } break; default: assert(0); // implement me break; } } void Locker::issue_client_lease(CDentry *dn, client_t client, bufferlist &bl, utime_t now, Session *session) { CInode *diri = dn->get_dir()->get_inode(); if (!diri->is_stray() && // do not issue dn leases in stray dir! ((!diri->filelock.can_lease(client) && (diri->get_client_cap_pending(client) & (CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL)) == 0)) && dn->lock.can_lease(client)) { int pool = 1; // fixme.. do something smart! // issue a dentry lease ClientLease *l = dn->add_client_lease(client, session); session->touch_lease(l); now += mdcache->client_lease_durations[pool]; mdcache->touch_client_lease(l, pool, now); LeaseStat e; e.mask = 1 | CEPH_LOCK_DN; // old and new bit values e.seq = ++l->seq; e.duration_ms = (int)(1000 * mdcache->client_lease_durations[pool]); ::encode(e, bl); dout(20) << "issue_client_lease seq " << e.seq << " dur " << e.duration_ms << "ms " << " on " << *dn << dendl; } else { // null lease LeaseStat e; e.mask = 0; e.seq = 0; e.duration_ms = 0; ::encode(e, bl); dout(20) << "issue_client_lease no/null lease on " << *dn << dendl; } } void Locker::revoke_client_leases(SimpleLock *lock) { int n = 0; CDentry *dn = static_cast(lock->get_parent()); for (map::iterator p = dn->client_lease_map.begin(); p != dn->client_lease_map.end(); ++p) { ClientLease *l = p->second; n++; assert(lock->get_type() == CEPH_LOCK_DN); CDentry *dn = static_cast(lock->get_parent()); int mask = 1 | CEPH_LOCK_DN; // old and new bits // i should also revoke the dir ICONTENT lease, if they have it! CInode *diri = dn->get_dir()->get_inode(); mds->send_message_client_counted(new MClientLease(CEPH_MDS_LEASE_REVOKE, l->seq, mask, diri->ino(), diri->first, CEPH_NOSNAP, dn->get_name()), l->client); } assert(n == lock->get_num_client_lease()); } // locks ---------------------------------------------------------------- SimpleLock *Locker::get_lock(int lock_type, MDSCacheObjectInfo &info) { switch (lock_type) { case CEPH_LOCK_DN: { // be careful; info.dirfrag may have incorrect frag; recalculate based on dname. CInode *diri = mdcache->get_inode(info.dirfrag.ino); frag_t fg; CDir *dir = 0; CDentry *dn = 0; if (diri) { fg = diri->pick_dirfrag(info.dname); dir = diri->get_dirfrag(fg); if (dir) dn = dir->lookup(info.dname, info.snapid); } if (!dn) { dout(7) << "get_lock don't have dn " << info.dirfrag.ino << " " << info.dname << dendl; return 0; } return &dn->lock; } case CEPH_LOCK_IAUTH: case CEPH_LOCK_ILINK: case CEPH_LOCK_IDFT: case CEPH_LOCK_IFILE: case CEPH_LOCK_INEST: case CEPH_LOCK_IXATTR: case CEPH_LOCK_ISNAP: case CEPH_LOCK_IFLOCK: case CEPH_LOCK_IPOLICY: { CInode *in = mdcache->get_inode(info.ino, info.snapid); if (!in) { dout(7) << "get_lock don't have ino " << info.ino << dendl; return 0; } switch (lock_type) { case CEPH_LOCK_IAUTH: return &in->authlock; case CEPH_LOCK_ILINK: return &in->linklock; case CEPH_LOCK_IDFT: return &in->dirfragtreelock; case CEPH_LOCK_IFILE: return &in->filelock; case CEPH_LOCK_INEST: return &in->nestlock; case CEPH_LOCK_IXATTR: return &in->xattrlock; case CEPH_LOCK_ISNAP: return &in->snaplock; case CEPH_LOCK_IFLOCK: return &in->flocklock; case CEPH_LOCK_IPOLICY: return &in->policylock; } } default: dout(7) << "get_lock don't know lock_type " << lock_type << dendl; assert(0); break; } return 0; } /* This function DOES put the passed message before returning */ void Locker::handle_lock(MLock *m) { // nobody should be talking to us during recovery. assert(mds->is_rejoin() || mds->is_clientreplay() || mds->is_active() || mds->is_stopping()); SimpleLock *lock = get_lock(m->get_lock_type(), m->get_object_info()); if (!lock) { dout(10) << "don't have object " << m->get_object_info() << ", must have trimmed, dropping" << dendl; m->put(); return; } switch (lock->get_type()) { case CEPH_LOCK_DN: case CEPH_LOCK_IAUTH: case CEPH_LOCK_ILINK: case CEPH_LOCK_ISNAP: case CEPH_LOCK_IXATTR: case CEPH_LOCK_IFLOCK: case CEPH_LOCK_IPOLICY: handle_simple_lock(lock, m); break; case CEPH_LOCK_IDFT: case CEPH_LOCK_INEST: //handle_scatter_lock((ScatterLock*)lock, m); //break; case CEPH_LOCK_IFILE: handle_file_lock(static_cast(lock), m); break; default: dout(7) << "handle_lock got otype " << m->get_lock_type() << dendl; assert(0); break; } } // ========================================================================== // simple lock /** This function may take a reference to m if it needs one, but does * not put references. */ void Locker::handle_reqrdlock(SimpleLock *lock, MLock *m) { MDSCacheObject *parent = lock->get_parent(); if (parent->is_auth() && lock->get_state() != LOCK_SYNC && !parent->is_frozen()) { dout(7) << "handle_reqrdlock got rdlock request on " << *lock << " on " << *parent << dendl; assert(parent->is_auth()); // replica auth pinned if they're doing this! if (lock->is_stable()) { simple_sync(lock); } else { dout(7) << "handle_reqrdlock delaying request until lock is stable" << dendl; lock->add_waiter(SimpleLock::WAIT_STABLE | MDSCacheObject::WAIT_UNFREEZE, new C_MDS_RetryMessage(mds, m->get())); } } else { dout(7) << "handle_reqrdlock dropping rdlock request on " << *lock << " on " << *parent << dendl; // replica should retry } } /* This function DOES put the passed message before returning */ void Locker::handle_simple_lock(SimpleLock *lock, MLock *m) { int from = m->get_asker(); dout(10) << "handle_simple_lock " << *m << " on " << *lock << " " << *lock->get_parent() << dendl; if (mds->is_rejoin()) { if (lock->get_parent()->is_rejoining()) { dout(7) << "handle_simple_lock still rejoining " << *lock->get_parent() << ", dropping " << *m << dendl; m->put(); return; } } switch (m->get_action()) { // -- replica -- case LOCK_AC_SYNC: assert(lock->get_state() == LOCK_LOCK); lock->decode_locked_state(m->get_data()); lock->set_state(LOCK_SYNC); lock->finish_waiters(SimpleLock::WAIT_RD|SimpleLock::WAIT_STABLE); break; case LOCK_AC_LOCK: assert(lock->get_state() == LOCK_SYNC); lock->set_state(LOCK_SYNC_LOCK); if (lock->is_leased()) revoke_client_leases(lock); eval_gather(lock, true); break; // -- auth -- case LOCK_AC_LOCKACK: assert(lock->get_state() == LOCK_SYNC_LOCK || lock->get_state() == LOCK_SYNC_EXCL); assert(lock->is_gathering(from)); lock->remove_gather(from); if (lock->is_gathering()) { dout(7) << "handle_simple_lock " << *lock << " on " << *lock->get_parent() << " from " << from << ", still gathering " << lock->get_gather_set() << dendl; } else { dout(7) << "handle_simple_lock " << *lock << " on " << *lock->get_parent() << " from " << from << ", last one" << dendl; eval_gather(lock); } break; case LOCK_AC_REQRDLOCK: handle_reqrdlock(lock, m); break; } m->put(); } /* unused, currently. class C_Locker_SimpleEval : public Context { Locker *locker; SimpleLock *lock; public: C_Locker_SimpleEval(Locker *l, SimpleLock *lk) : locker(l), lock(lk) {} void finish(int r) { locker->try_simple_eval(lock); } }; void Locker::try_simple_eval(SimpleLock *lock) { // unstable and ambiguous auth? if (!lock->is_stable() && lock->get_parent()->is_ambiguous_auth()) { dout(7) << "simple_eval not stable and ambiguous auth, waiting on " << *lock->get_parent() << dendl; //if (!lock->get_parent()->is_waiter(MDSCacheObject::WAIT_SINGLEAUTH)) lock->get_parent()->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, new C_Locker_SimpleEval(this, lock)); return; } if (!lock->get_parent()->is_auth()) { dout(7) << "try_simple_eval not auth for " << *lock->get_parent() << dendl; return; } if (!lock->get_parent()->can_auth_pin()) { dout(7) << "try_simple_eval can't auth_pin, waiting on " << *lock->get_parent() << dendl; //if (!lock->get_parent()->is_waiter(MDSCacheObject::WAIT_SINGLEAUTH)) lock->get_parent()->add_waiter(MDSCacheObject::WAIT_UNFREEZE, new C_Locker_SimpleEval(this, lock)); return; } if (lock->is_stable()) simple_eval(lock); } */ void Locker::simple_eval(SimpleLock *lock, bool *need_issue) { dout(10) << "simple_eval " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); if (lock->get_parent()->is_freezing_or_frozen()) { // dentry lock in unreadable state can block path traverse if ((lock->get_type() != CEPH_LOCK_DN || lock->get_state() == LOCK_SYNC || lock->get_parent()->is_frozen())) return; } CInode *in = 0; int wanted = 0; if (lock->get_type() != CEPH_LOCK_DN) { in = static_cast(lock->get_parent()); in->get_caps_wanted(&wanted, NULL, lock->get_cap_shift()); } // -> excl? if (lock->get_state() != LOCK_EXCL && in && in->get_target_loner() >= 0 && (wanted & CEPH_CAP_GEXCL)) { dout(7) << "simple_eval stable, going to excl " << *lock << " on " << *lock->get_parent() << dendl; simple_excl(lock, need_issue); } // stable -> sync? else if (lock->get_state() != LOCK_SYNC && !lock->is_wrlocked() && ((!(wanted & CEPH_CAP_GEXCL) && !lock->is_waiter_for(SimpleLock::WAIT_WR)) || (lock->get_state() == LOCK_EXCL && in && in->get_target_loner() < 0))) { dout(7) << "simple_eval stable, syncing " << *lock << " on " << *lock->get_parent() << dendl; simple_sync(lock, need_issue); } } // mid bool Locker::simple_sync(SimpleLock *lock, bool *need_issue) { dout(7) << "simple_sync on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); CInode *in = 0; if (lock->get_cap_shift()) in = static_cast(lock->get_parent()); int old_state = lock->get_state(); if (old_state != LOCK_TSYN) { switch (lock->get_state()) { case LOCK_MIX: lock->set_state(LOCK_MIX_SYNC); break; case LOCK_LOCK: lock->set_state(LOCK_LOCK_SYNC); break; case LOCK_XSYN: lock->set_state(LOCK_XSYN_SYNC); break; case LOCK_EXCL: lock->set_state(LOCK_EXCL_SYNC); break; default: assert(0); } int gather = 0; if (lock->is_wrlocked()) gather++; if (lock->get_parent()->is_replicated() && old_state == LOCK_MIX) { send_lock_message(lock, LOCK_AC_SYNC); lock->init_gather(); gather++; } if (in && in->is_head()) { if (in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } } bool need_recover = false; if (lock->get_type() == CEPH_LOCK_IFILE) { assert(in); if (in->state_test(CInode::STATE_NEEDSRECOVER)) { mds->mdcache->queue_file_recover(in); need_recover = true; gather++; } } if (!gather && lock->is_dirty()) { lock->get_parent()->auth_pin(lock); scatter_writebehind(static_cast(lock)); mds->mdlog->flush(); return false; } if (gather) { lock->get_parent()->auth_pin(lock); if (need_recover) mds->mdcache->do_file_recover(); return false; } } if (lock->get_parent()->is_replicated()) { // FIXME bufferlist data; lock->encode_locked_state(data); send_lock_message(lock, LOCK_AC_SYNC, data); } lock->set_state(LOCK_SYNC); lock->finish_waiters(SimpleLock::WAIT_RD|SimpleLock::WAIT_STABLE); if (in && in->is_head()) { if (need_issue) *need_issue = true; else issue_caps(in); } return true; } void Locker::simple_excl(SimpleLock *lock, bool *need_issue) { dout(7) << "simple_excl on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); CInode *in = 0; if (lock->get_cap_shift()) in = static_cast(lock->get_parent()); switch (lock->get_state()) { case LOCK_LOCK: lock->set_state(LOCK_LOCK_EXCL); break; case LOCK_SYNC: lock->set_state(LOCK_SYNC_EXCL); break; case LOCK_XSYN: lock->set_state(LOCK_XSYN_EXCL); break; default: assert(0); } int gather = 0; if (lock->is_rdlocked()) gather++; if (lock->is_wrlocked()) gather++; if (lock->get_parent()->is_replicated() && lock->get_state() != LOCK_LOCK_EXCL && lock->get_state() != LOCK_XSYN_EXCL) { send_lock_message(lock, LOCK_AC_LOCK); lock->init_gather(); gather++; } if (in && in->is_head()) { if (in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } } if (gather) { lock->get_parent()->auth_pin(lock); } else { lock->set_state(LOCK_EXCL); lock->finish_waiters(SimpleLock::WAIT_WR|SimpleLock::WAIT_STABLE); if (in) { if (need_issue) *need_issue = true; else issue_caps(in); } } } void Locker::simple_lock(SimpleLock *lock, bool *need_issue) { dout(7) << "simple_lock on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); assert(lock->get_state() != LOCK_LOCK); CInode *in = 0; if (lock->get_cap_shift()) in = static_cast(lock->get_parent()); int old_state = lock->get_state(); switch (lock->get_state()) { case LOCK_SYNC: lock->set_state(LOCK_SYNC_LOCK); break; case LOCK_XSYN: file_excl(static_cast(lock), need_issue); if (lock->get_state() != LOCK_EXCL) return; // fall-thru case LOCK_EXCL: lock->set_state(LOCK_EXCL_LOCK); break; case LOCK_MIX: lock->set_state(LOCK_MIX_LOCK); (static_cast(lock))->clear_unscatter_wanted(); break; case LOCK_TSYN: lock->set_state(LOCK_TSYN_LOCK); break; default: assert(0); } int gather = 0; if (lock->is_leased()) { gather++; revoke_client_leases(lock); } if (lock->is_rdlocked()) gather++; if (in && in->is_head()) { if (in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } } bool need_recover = false; if (lock->get_type() == CEPH_LOCK_IFILE) { assert(in); if(in->state_test(CInode::STATE_NEEDSRECOVER)) { mds->mdcache->queue_file_recover(in); need_recover = true; gather++; } } if (lock->get_parent()->is_replicated() && lock->get_state() == LOCK_MIX_LOCK && gather) { dout(10) << " doing local stage of mix->lock gather before gathering from replicas" << dendl; } else { // move to second stage of gather now, so we don't send the lock action later. if (lock->get_state() == LOCK_MIX_LOCK) lock->set_state(LOCK_MIX_LOCK2); if (lock->get_parent()->is_replicated() && lock->get_sm()->states[old_state].replica_state != LOCK_LOCK) { // replica may already be LOCK gather++; send_lock_message(lock, LOCK_AC_LOCK); lock->init_gather(); } } if (!gather && lock->is_dirty()) { lock->get_parent()->auth_pin(lock); scatter_writebehind(static_cast(lock)); mds->mdlog->flush(); return; } if (gather) { lock->get_parent()->auth_pin(lock); if (need_recover) mds->mdcache->do_file_recover(); } else { lock->set_state(LOCK_LOCK); lock->finish_waiters(ScatterLock::WAIT_XLOCK|ScatterLock::WAIT_WR|ScatterLock::WAIT_STABLE); } } void Locker::simple_xlock(SimpleLock *lock) { dout(7) << "simple_xlock on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); //assert(lock->is_stable()); assert(lock->get_state() != LOCK_XLOCK); CInode *in = 0; if (lock->get_cap_shift()) in = static_cast(lock->get_parent()); if (lock->is_stable()) lock->get_parent()->auth_pin(lock); switch (lock->get_state()) { case LOCK_LOCK: case LOCK_XLOCKDONE: lock->set_state(LOCK_LOCK_XLOCK); break; default: assert(0); } int gather = 0; if (lock->is_rdlocked()) gather++; if (lock->is_wrlocked()) gather++; if (in && in->is_head()) { if (in->issued_caps_need_gather(lock)) { issue_caps(in); gather++; } } if (!gather) { lock->set_state(LOCK_PREXLOCK); //assert("shouldn't be called if we are already xlockable" == 0); } } // ========================================================================== // scatter lock /* Some notes on scatterlocks. - The scatter/gather is driven by the inode lock. The scatter always brings in the latest metadata from the fragments. - When in a scattered/MIX state, fragments are only allowed to update/be written to if the accounted stat matches the inode's current version. - That means, on gather, we _only_ assimilate diffs for frag metadata that match the current version, because those are the only ones written during this scatter/gather cycle. (Others didn't permit it.) We increment the version and journal this to disk. - When possible, we also simultaneously update our local frag accounted stats to match. - On scatter, the new inode info is broadcast to frags, both local and remote. If possible (auth and !frozen), the dirfrag auth should update the accounted state (if it isn't already up to date). Note that this may occur on both the local inode auth node and inode replicas, so there are two potential paths. If it is NOT possible, they need to mark_stale to prevent any possible writes. - A scatter can be to MIX (potentially writeable) or to SYNC (read only). Both are opportunities to update the frag accounted stats, even though only the MIX case is affected by a stale dirfrag. - Because many scatter/gather cycles can potentially go by without a frag being able to update its accounted stats (due to being frozen by exports/refragments in progress), the frag may have (even very) old stat versions. That's fine. If when we do want to update it, we can update accounted_* and the version first. */ void Locker::scatter_writebehind(ScatterLock *lock) { CInode *in = static_cast(lock->get_parent()); dout(10) << "scatter_writebehind " << in->inode.mtime << " on " << *lock << " on " << *in << dendl; // journal MutationRef mut(new MutationImpl); mut->ls = mds->mdlog->get_current_segment(); // forcefully take a wrlock lock->get_wrlock(true); mut->wrlocks.insert(lock); mut->locks.insert(lock); in->pre_cow_old_inode(); // avoid cow mayhem inode_t *pi = in->project_inode(); pi->version = in->pre_dirty(); in->finish_scatter_gather_update(lock->get_type()); lock->start_flush(); EUpdate *le = new EUpdate(mds->mdlog, "scatter_writebehind"); mds->mdlog->start_entry(le); mdcache->predirty_journal_parents(mut, &le->metablob, in, 0, PREDIRTY_PRIMARY, false); mdcache->journal_dirty_inode(mut.get(), &le->metablob, in); in->finish_scatter_gather_update_accounted(lock->get_type(), mut, &le->metablob); mds->mdlog->submit_entry(le); mds->mdlog->wait_for_safe(new C_Locker_ScatterWB(this, lock, mut)); } void Locker::scatter_writebehind_finish(ScatterLock *lock, MutationRef& mut) { CInode *in = static_cast(lock->get_parent()); dout(10) << "scatter_writebehind_finish on " << *lock << " on " << *in << dendl; in->pop_and_dirty_projected_inode(mut->ls); lock->finish_flush(); // if replicas may have flushed in a mix->lock state, send another // message so they can finish_flush(). if (in->is_replicated()) { switch (lock->get_state()) { case LOCK_MIX_LOCK: case LOCK_MIX_LOCK2: case LOCK_MIX_EXCL: case LOCK_MIX_TSYN: send_lock_message(lock, LOCK_AC_LOCKFLUSHED); } } mut->apply(); drop_locks(mut.get()); mut->cleanup(); if (lock->is_stable()) lock->finish_waiters(ScatterLock::WAIT_STABLE); //scatter_eval_gather(lock); } void Locker::scatter_eval(ScatterLock *lock, bool *need_issue) { dout(10) << "scatter_eval " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); if (lock->get_parent()->is_freezing_or_frozen()) { dout(20) << " freezing|frozen" << dendl; return; } if (!lock->is_rdlocked() && lock->get_state() != LOCK_MIX && lock->get_scatter_wanted()) { dout(10) << "scatter_eval scatter_wanted, bump to mix " << *lock << " on " << *lock->get_parent() << dendl; scatter_mix(lock, need_issue); return; } if (lock->get_type() == CEPH_LOCK_INEST) { // in general, we want to keep INEST writable at all times. if (!lock->is_rdlocked()) { if (lock->get_parent()->is_replicated()) { if (lock->get_state() != LOCK_MIX) scatter_mix(lock, need_issue); } else { if (lock->get_state() != LOCK_LOCK) simple_lock(lock, need_issue); } } return; } CInode *in = static_cast(lock->get_parent()); if (!in->has_subtree_or_exporting_dirfrag() || in->is_base()) { // i _should_ be sync. if (!lock->is_wrlocked() && lock->get_state() != LOCK_SYNC) { dout(10) << "scatter_eval no wrlocks|xlocks, not subtree root inode, syncing" << dendl; simple_sync(lock, need_issue); } } } /* * mark a scatterlock to indicate that the dir fnode has some dirty data */ void Locker::mark_updated_scatterlock(ScatterLock *lock) { lock->mark_dirty(); if (lock->get_updated_item()->is_on_list()) { dout(10) << "mark_updated_scatterlock " << *lock << " - already on list since " << lock->get_update_stamp() << dendl; } else { updated_scatterlocks.push_back(lock->get_updated_item()); utime_t now = ceph_clock_now(g_ceph_context); lock->set_update_stamp(now); dout(10) << "mark_updated_scatterlock " << *lock << " - added at " << now << dendl; } } /* * this is called by scatter_tick and LogSegment::try_to_trim() when * trying to flush dirty scattered data (i.e. updated fnode) back to * the inode. * * we need to lock|scatter in order to push fnode changes into the * inode.dirstat. */ void Locker::scatter_nudge(ScatterLock *lock, Context *c, bool forcelockchange) { CInode *p = static_cast(lock->get_parent()); if (p->is_frozen() || p->is_freezing()) { dout(10) << "scatter_nudge waiting for unfreeze on " << *p << dendl; if (c) p->add_waiter(MDSCacheObject::WAIT_UNFREEZE, c); else // just requeue. not ideal.. starvation prone.. updated_scatterlocks.push_back(lock->get_updated_item()); return; } if (p->is_ambiguous_auth()) { dout(10) << "scatter_nudge waiting for single auth on " << *p << dendl; if (c) p->add_waiter(MDSCacheObject::WAIT_SINGLEAUTH, c); else // just requeue. not ideal.. starvation prone.. updated_scatterlocks.push_back(lock->get_updated_item()); return; } if (p->is_auth()) { int count = 0; while (true) { if (lock->is_stable()) { // can we do it now? // (only if we're not replicated.. if we are, we really do need // to nudge the lock state!) /* actually, even if we're not replicated, we can't stay in MIX, because another mds could discover and replicate us at any time. if that happens while we're flushing, they end up in MIX but their inode has the old scatterstat version. if (!forcelockchange && !lock->get_parent()->is_replicated() && lock->can_wrlock(-1)) { dout(10) << "scatter_nudge auth, propagating " << *lock << " on " << *p << dendl; scatter_writebehind(lock); if (c) lock->add_waiter(SimpleLock::WAIT_STABLE, c); return; } */ // adjust lock state dout(10) << "scatter_nudge auth, scatter/unscattering " << *lock << " on " << *p << dendl; switch (lock->get_type()) { case CEPH_LOCK_IFILE: if (p->is_replicated() && lock->get_state() != LOCK_MIX) scatter_mix(static_cast(lock)); else if (lock->get_state() != LOCK_LOCK) simple_lock(static_cast(lock)); else simple_sync(static_cast(lock)); break; case CEPH_LOCK_IDFT: case CEPH_LOCK_INEST: if (p->is_replicated() && lock->get_state() != LOCK_MIX) scatter_mix(lock); else if (lock->get_state() != LOCK_LOCK) simple_lock(lock); else simple_sync(lock); break; default: assert(0); } ++count; if (lock->is_stable() && count == 2) { dout(10) << "scatter_nudge oh, stable after two cycles." << dendl; // this should only realy happen when called via // handle_file_lock due to AC_NUDGE, because the rest of the // time we are replicated or have dirty data and won't get // called. bailing here avoids an infinite loop. assert(!c); break; } } else { dout(10) << "scatter_nudge auth, waiting for stable " << *lock << " on " << *p << dendl; if (c) lock->add_waiter(SimpleLock::WAIT_STABLE, c); return; } } } else { dout(10) << "scatter_nudge replica, requesting scatter/unscatter of " << *lock << " on " << *p << dendl; // request unscatter? int auth = lock->get_parent()->authority().first; if (mds->mdsmap->is_clientreplay_or_active_or_stopping(auth)) mds->send_message_mds(new MLock(lock, LOCK_AC_NUDGE, mds->get_nodeid()), auth); // wait... if (c) lock->add_waiter(SimpleLock::WAIT_STABLE, c); // also, requeue, in case we had wrong auth or something updated_scatterlocks.push_back(lock->get_updated_item()); } } void Locker::scatter_tick() { dout(10) << "scatter_tick" << dendl; // updated utime_t now = ceph_clock_now(g_ceph_context); int n = updated_scatterlocks.size(); while (!updated_scatterlocks.empty()) { ScatterLock *lock = updated_scatterlocks.front(); if (n-- == 0) break; // scatter_nudge() may requeue; avoid looping if (!lock->is_dirty()) { updated_scatterlocks.pop_front(); dout(10) << " removing from updated_scatterlocks " << *lock << " " << *lock->get_parent() << dendl; continue; } if (now - lock->get_update_stamp() < g_conf->mds_scatter_nudge_interval) break; updated_scatterlocks.pop_front(); scatter_nudge(lock, 0); } mds->mdlog->flush(); } void Locker::scatter_tempsync(ScatterLock *lock, bool *need_issue) { dout(10) << "scatter_tempsync " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); assert(0 == "not fully implemented, at least not for filelock"); CInode *in = static_cast(lock->get_parent()); switch (lock->get_state()) { case LOCK_SYNC: assert(0); // this shouldn't happen case LOCK_LOCK: lock->set_state(LOCK_LOCK_TSYN); break; case LOCK_MIX: lock->set_state(LOCK_MIX_TSYN); break; default: assert(0); } int gather = 0; if (lock->is_wrlocked()) gather++; if (lock->get_cap_shift() && in->is_head() && in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } if (lock->get_state() == LOCK_MIX_TSYN && in->is_replicated()) { lock->init_gather(); send_lock_message(lock, LOCK_AC_LOCK); gather++; } if (gather) { in->auth_pin(lock); } else { // do tempsync lock->set_state(LOCK_TSYN); lock->finish_waiters(ScatterLock::WAIT_RD|ScatterLock::WAIT_STABLE); if (lock->get_cap_shift()) { if (need_issue) *need_issue = true; else issue_caps(in); } } } // ========================================================================== // local lock void Locker::local_wrlock_grab(LocalLock *lock, MutationRef& mut) { dout(7) << "local_wrlock_grab on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->can_wrlock()); assert(!mut->wrlocks.count(lock)); lock->get_wrlock(mut->get_client()); mut->wrlocks.insert(lock); mut->locks.insert(lock); } bool Locker::local_wrlock_start(LocalLock *lock, MDRequestRef& mut) { dout(7) << "local_wrlock_start on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); if (lock->can_wrlock()) { assert(!mut->wrlocks.count(lock)); lock->get_wrlock(mut->get_client()); mut->wrlocks.insert(lock); mut->locks.insert(lock); return true; } else { lock->add_waiter(SimpleLock::WAIT_WR|SimpleLock::WAIT_STABLE, new C_MDS_RetryRequest(mdcache, mut)); return false; } } void Locker::local_wrlock_finish(LocalLock *lock, MutationImpl *mut) { dout(7) << "local_wrlock_finish on " << *lock << " on " << *lock->get_parent() << dendl; lock->put_wrlock(); mut->wrlocks.erase(lock); mut->locks.erase(lock); if (lock->get_num_wrlocks() == 0) { lock->finish_waiters(SimpleLock::WAIT_STABLE | SimpleLock::WAIT_WR | SimpleLock::WAIT_RD); } } bool Locker::local_xlock_start(LocalLock *lock, MDRequestRef& mut) { dout(7) << "local_xlock_start on " << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); if (!lock->can_xlock_local()) { lock->add_waiter(SimpleLock::WAIT_WR|SimpleLock::WAIT_STABLE, new C_MDS_RetryRequest(mdcache, mut)); return false; } lock->get_xlock(mut, mut->get_client()); mut->xlocks.insert(lock); mut->locks.insert(lock); return true; } void Locker::local_xlock_finish(LocalLock *lock, MutationImpl *mut) { dout(7) << "local_xlock_finish on " << *lock << " on " << *lock->get_parent() << dendl; lock->put_xlock(); mut->xlocks.erase(lock); mut->locks.erase(lock); lock->finish_waiters(SimpleLock::WAIT_STABLE | SimpleLock::WAIT_WR | SimpleLock::WAIT_RD); } // ========================================================================== // file lock void Locker::file_eval(ScatterLock *lock, bool *need_issue) { CInode *in = static_cast(lock->get_parent()); int loner_wanted, other_wanted; int wanted = in->get_caps_wanted(&loner_wanted, &other_wanted, CEPH_CAP_SFILE); dout(7) << "file_eval wanted=" << gcap_string(wanted) << " loner_wanted=" << gcap_string(loner_wanted) << " other_wanted=" << gcap_string(other_wanted) << " filelock=" << *lock << " on " << *lock->get_parent() << dendl; assert(lock->get_parent()->is_auth()); assert(lock->is_stable()); if (lock->get_parent()->is_freezing_or_frozen()) return; // excl -> *? if (lock->get_state() == LOCK_EXCL) { dout(20) << " is excl" << dendl; int loner_issued, other_issued, xlocker_issued; in->get_caps_issued(&loner_issued, &other_issued, &xlocker_issued, CEPH_CAP_SFILE); dout(7) << "file_eval loner_issued=" << gcap_string(loner_issued) << " other_issued=" << gcap_string(other_issued) << " xlocker_issued=" << gcap_string(xlocker_issued) << dendl; if (!((loner_wanted|loner_issued) & (CEPH_CAP_GEXCL|CEPH_CAP_GWR|CEPH_CAP_GBUFFER)) || (other_wanted & (CEPH_CAP_GEXCL|CEPH_CAP_GWR|CEPH_CAP_GRD)) || (in->inode.is_dir() && in->multiple_nonstale_caps())) { // FIXME.. :/ dout(20) << " should lose it" << dendl; // we should lose it. // loner other want // R R SYNC // R R|W MIX // R W MIX // R|W R MIX // R|W R|W MIX // R|W W MIX // W R MIX // W R|W MIX // W W MIX // -> any writer means MIX; RD doesn't matter. if (((other_wanted|loner_wanted) & CEPH_CAP_GWR) || lock->is_waiter_for(SimpleLock::WAIT_WR)) scatter_mix(lock, need_issue); else if (!lock->is_wrlocked()) // let excl wrlocks drain first simple_sync(lock, need_issue); else dout(10) << " waiting for wrlock to drain" << dendl; } } // * -> excl? else if (lock->get_state() != LOCK_EXCL && !lock->is_rdlocked() && //!lock->is_waiter_for(SimpleLock::WAIT_WR) && ((wanted & (CEPH_CAP_GWR|CEPH_CAP_GBUFFER)) || (in->inode.is_dir() && !in->has_subtree_or_exporting_dirfrag())) && in->get_target_loner() >= 0) { dout(7) << "file_eval stable, bump to loner " << *lock << " on " << *lock->get_parent() << dendl; file_excl(lock, need_issue); } // * -> mixed? else if (lock->get_state() != LOCK_MIX && !lock->is_rdlocked() && //!lock->is_waiter_for(SimpleLock::WAIT_WR) && (lock->get_scatter_wanted() || (in->get_wanted_loner() < 0 && (wanted & CEPH_CAP_GWR)))) { dout(7) << "file_eval stable, bump to mixed " << *lock << " on " << *lock->get_parent() << dendl; scatter_mix(lock, need_issue); } // * -> sync? else if (lock->get_state() != LOCK_SYNC && !lock->is_wrlocked() && // drain wrlocks first! !lock->is_waiter_for(SimpleLock::WAIT_WR) && !(wanted & (CEPH_CAP_GWR|CEPH_CAP_GBUFFER)) && !((lock->get_state() == LOCK_MIX) && in->is_dir() && in->has_subtree_or_exporting_dirfrag()) // if we are a delegation point, stay where we are //((wanted & CEPH_CAP_RD) || //in->is_replicated() || //lock->get_num_client_lease() || //(!loner && lock->get_state() == LOCK_EXCL)) && ) { dout(7) << "file_eval stable, bump to sync " << *lock << " on " << *lock->get_parent() << dendl; simple_sync(lock, need_issue); } } void Locker::scatter_mix(ScatterLock *lock, bool *need_issue) { dout(7) << "scatter_mix " << *lock << " on " << *lock->get_parent() << dendl; CInode *in = static_cast(lock->get_parent()); assert(in->is_auth()); assert(lock->is_stable()); if (lock->get_state() == LOCK_LOCK) { in->start_scatter(lock); if (in->is_replicated()) { // data bufferlist softdata; lock->encode_locked_state(softdata); // bcast to replicas send_lock_message(lock, LOCK_AC_MIX, softdata); } // change lock lock->set_state(LOCK_MIX); lock->clear_scatter_wanted(); if (lock->get_cap_shift()) { if (need_issue) *need_issue = true; else issue_caps(in); } } else { // gather? switch (lock->get_state()) { case LOCK_SYNC: lock->set_state(LOCK_SYNC_MIX); break; case LOCK_XSYN: file_excl(lock, need_issue); if (lock->get_state() != LOCK_EXCL) return; // fall-thru case LOCK_EXCL: lock->set_state(LOCK_EXCL_MIX); break; case LOCK_TSYN: lock->set_state(LOCK_TSYN_MIX); break; default: assert(0); } int gather = 0; if (lock->is_rdlocked()) gather++; if (in->is_replicated()) { if (lock->get_state() != LOCK_EXCL_MIX && // EXCL replica is already LOCK lock->get_state() != LOCK_XSYN_EXCL) { // XSYN replica is already LOCK; ** FIXME here too! send_lock_message(lock, LOCK_AC_MIX); lock->init_gather(); gather++; } } if (lock->is_leased()) { revoke_client_leases(lock); gather++; } if (lock->get_cap_shift() && in->is_head() && in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } bool need_recover = false; if (in->state_test(CInode::STATE_NEEDSRECOVER)) { mds->mdcache->queue_file_recover(in); need_recover = true; gather++; } if (gather) { lock->get_parent()->auth_pin(lock); if (need_recover) mds->mdcache->do_file_recover(); } else { in->start_scatter(lock); lock->set_state(LOCK_MIX); lock->clear_scatter_wanted(); if (in->is_replicated()) { bufferlist softdata; lock->encode_locked_state(softdata); send_lock_message(lock, LOCK_AC_MIX, softdata); } if (lock->get_cap_shift()) { if (need_issue) *need_issue = true; else issue_caps(in); } } } } void Locker::file_excl(ScatterLock *lock, bool *need_issue) { CInode *in = static_cast(lock->get_parent()); dout(7) << "file_excl " << *lock << " on " << *lock->get_parent() << dendl; assert(in->is_auth()); assert(lock->is_stable()); assert((in->get_loner() >= 0 && in->mds_caps_wanted.empty()) || (lock->get_state() == LOCK_XSYN)); // must do xsyn -> excl -> switch (lock->get_state()) { case LOCK_SYNC: lock->set_state(LOCK_SYNC_EXCL); break; case LOCK_MIX: lock->set_state(LOCK_MIX_EXCL); break; case LOCK_LOCK: lock->set_state(LOCK_LOCK_EXCL); break; case LOCK_XSYN: lock->set_state(LOCK_XSYN_EXCL); break; default: assert(0); } int gather = 0; if (lock->is_rdlocked()) gather++; if (lock->is_wrlocked()) gather++; if (in->is_replicated() && lock->get_state() != LOCK_LOCK_EXCL && lock->get_state() != LOCK_XSYN_EXCL) { // if we were lock, replicas are already lock. send_lock_message(lock, LOCK_AC_LOCK); lock->init_gather(); gather++; } if (lock->is_leased()) { revoke_client_leases(lock); gather++; } if (in->is_head() && in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } bool need_recover = false; if (in->state_test(CInode::STATE_NEEDSRECOVER)) { mds->mdcache->queue_file_recover(in); need_recover = true; gather++; } if (gather) { lock->get_parent()->auth_pin(lock); if (need_recover) mds->mdcache->do_file_recover(); } else { lock->set_state(LOCK_EXCL); if (need_issue) *need_issue = true; else issue_caps(in); } } void Locker::file_xsyn(SimpleLock *lock, bool *need_issue) { dout(7) << "file_xsyn on " << *lock << " on " << *lock->get_parent() << dendl; CInode *in = static_cast(lock->get_parent()); assert(in->is_auth()); assert(in->get_loner() >= 0 && in->mds_caps_wanted.empty()); switch (lock->get_state()) { case LOCK_EXCL: lock->set_state(LOCK_EXCL_XSYN); break; default: assert(0); } int gather = 0; if (lock->is_wrlocked()) gather++; if (in->is_head() && in->issued_caps_need_gather(lock)) { if (need_issue) *need_issue = true; else issue_caps(in); gather++; } if (gather) { lock->get_parent()->auth_pin(lock); } else { lock->set_state(LOCK_XSYN); lock->finish_waiters(SimpleLock::WAIT_RD|SimpleLock::WAIT_STABLE); if (need_issue) *need_issue = true; else issue_caps(in); } } void Locker::file_recover(ScatterLock *lock) { CInode *in = static_cast(lock->get_parent()); dout(7) << "file_recover " << *lock << " on " << *in << dendl; assert(in->is_auth()); //assert(lock->is_stable()); assert(lock->get_state() == LOCK_PRE_SCAN); // only called from MDCache::start_files_to_recover() int gather = 0; /* if (in->is_replicated() lock->get_sm()->states[oldstate].replica_state != LOCK_LOCK) { send_lock_message(lock, LOCK_AC_LOCK); lock->init_gather(); gather++; } */ if (in->is_head() && in->issued_caps_need_gather(lock)) { issue_caps(in); gather++; } lock->set_state(LOCK_SCAN); if (gather) in->state_set(CInode::STATE_NEEDSRECOVER); else mds->mdcache->queue_file_recover(in); } // messenger /* This function DOES put the passed message before returning */ void Locker::handle_file_lock(ScatterLock *lock, MLock *m) { CInode *in = static_cast(lock->get_parent()); int from = m->get_asker(); if (mds->is_rejoin()) { if (in->is_rejoining()) { dout(7) << "handle_file_lock still rejoining " << *in << ", dropping " << *m << dendl; m->put(); return; } } dout(7) << "handle_file_lock a=" << get_lock_action_name(m->get_action()) << " on " << *lock << " from mds." << from << " " << *in << dendl; bool caps = lock->get_cap_shift(); switch (m->get_action()) { // -- replica -- case LOCK_AC_SYNC: assert(lock->get_state() == LOCK_LOCK || lock->get_state() == LOCK_MIX || lock->get_state() == LOCK_MIX_SYNC2); if (lock->get_state() == LOCK_MIX) { lock->set_state(LOCK_MIX_SYNC); eval_gather(lock, true); break; } (static_cast(lock))->finish_flush(); (static_cast(lock))->clear_flushed(); // ok lock->decode_locked_state(m->get_data()); lock->set_state(LOCK_SYNC); lock->get_rdlock(); if (caps) issue_caps(in); lock->finish_waiters(SimpleLock::WAIT_RD|SimpleLock::WAIT_STABLE); lock->put_rdlock(); break; case LOCK_AC_LOCK: switch (lock->get_state()) { case LOCK_SYNC: lock->set_state(LOCK_SYNC_LOCK); break; case LOCK_MIX: lock->set_state(LOCK_MIX_LOCK); break; default: assert(0); } eval_gather(lock, true); break; case LOCK_AC_LOCKFLUSHED: (static_cast(lock))->finish_flush(); (static_cast(lock))->clear_flushed(); break; case LOCK_AC_MIX: assert(lock->get_state() == LOCK_SYNC || lock->get_state() == LOCK_LOCK || lock->get_state() == LOCK_SYNC_MIX2); if (lock->get_state() == LOCK_SYNC) { // MIXED lock->set_state(LOCK_SYNC_MIX); eval_gather(lock, true); break; } // ok lock->decode_locked_state(m->get_data()); lock->set_state(LOCK_MIX); if (caps) issue_caps(in); lock->finish_waiters(SimpleLock::WAIT_WR|SimpleLock::WAIT_STABLE); break; // -- auth -- case LOCK_AC_LOCKACK: assert(lock->get_state() == LOCK_SYNC_LOCK || lock->get_state() == LOCK_MIX_LOCK || lock->get_state() == LOCK_MIX_LOCK2 || lock->get_state() == LOCK_MIX_EXCL || lock->get_state() == LOCK_SYNC_EXCL || lock->get_state() == LOCK_SYNC_MIX || lock->get_state() == LOCK_MIX_TSYN); assert(lock->is_gathering(from)); lock->remove_gather(from); if (lock->get_state() == LOCK_MIX_LOCK || lock->get_state() == LOCK_MIX_LOCK2 || lock->get_state() == LOCK_MIX_EXCL || lock->get_state() == LOCK_MIX_TSYN) { lock->decode_locked_state(m->get_data()); // replica is waiting for AC_LOCKFLUSHED, eval_gather() should not // delay calling scatter_writebehind(). lock->clear_flushed(); } if (lock->is_gathering()) { dout(7) << "handle_file_lock " << *in << " from " << from << ", still gathering " << lock->get_gather_set() << dendl; } else { dout(7) << "handle_file_lock " << *in << " from " << from << ", last one" << dendl; eval_gather(lock); } break; case LOCK_AC_SYNCACK: assert(lock->get_state() == LOCK_MIX_SYNC); assert(lock->is_gathering(from)); lock->remove_gather(from); lock->decode_locked_state(m->get_data()); if (lock->is_gathering()) { dout(7) << "handle_file_lock " << *in << " from " << from << ", still gathering " << lock->get_gather_set() << dendl; } else { dout(7) << "handle_file_lock " << *in << " from " << from << ", last one" << dendl; eval_gather(lock); } break; case LOCK_AC_MIXACK: assert(lock->get_state() == LOCK_SYNC_MIX); assert(lock->is_gathering(from)); lock->remove_gather(from); if (lock->is_gathering()) { dout(7) << "handle_file_lock " << *in << " from " << from << ", still gathering " << lock->get_gather_set() << dendl; } else { dout(7) << "handle_file_lock " << *in << " from " << from << ", last one" << dendl; eval_gather(lock); } break; // requests.... case LOCK_AC_REQSCATTER: if (lock->is_stable()) { /* NOTE: we can do this _even_ if !can_auth_pin (i.e. freezing) * because the replica should be holding an auth_pin if they're * doing this (and thus, we are freezing, not frozen, and indefinite * starvation isn't an issue). */ dout(7) << "handle_file_lock got scatter request on " << *lock << " on " << *lock->get_parent() << dendl; if (lock->get_state() != LOCK_MIX) // i.e., the reqscatter didn't race with an actual mix/scatter scatter_mix(lock); } else { dout(7) << "handle_file_lock got scatter request, !stable, marking scatter_wanted on " << *lock << " on " << *lock->get_parent() << dendl; lock->set_scatter_wanted(); } break; case LOCK_AC_REQUNSCATTER: if (lock->is_stable()) { /* NOTE: we can do this _even_ if !can_auth_pin (i.e. freezing) * because the replica should be holding an auth_pin if they're * doing this (and thus, we are freezing, not frozen, and indefinite * starvation isn't an issue). */ dout(7) << "handle_file_lock got unscatter request on " << *lock << " on " << *lock->get_parent() << dendl; if (lock->get_state() == LOCK_MIX) // i.e., the reqscatter didn't race with an actual mix/scatter simple_lock(lock); // FIXME tempsync? } else { dout(7) << "handle_file_lock ignoring unscatter request on " << *lock << " on " << *lock->get_parent() << dendl; lock->set_unscatter_wanted(); } break; case LOCK_AC_REQRDLOCK: handle_reqrdlock(lock, m); break; case LOCK_AC_NUDGE: if (!lock->get_parent()->is_auth()) { dout(7) << "handle_file_lock IGNORING nudge on non-auth " << *lock << " on " << *lock->get_parent() << dendl; } else if (!lock->get_parent()->is_replicated()) { dout(7) << "handle_file_lock IGNORING nudge on non-replicated " << *lock << " on " << *lock->get_parent() << dendl; } else { dout(7) << "handle_file_lock trying nudge on " << *lock << " on " << *lock->get_parent() << dendl; scatter_nudge(lock, 0, true); mds->mdlog->flush(); } break; default: assert(0); } m->put(); } ceph-0.80.11/src/mds/locks.c0000664000175100017510000002250212623076744017527 0ustar jenkins-buildjenkins-build// there must be a better way? typedef char bool; #define false 0 #define true 1 #include "include/int_types.h" #include #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #endif #include #include #include "include/ceph_fs.h" #include "locks.h" static const struct sm_state_t simplelock[LOCK_MAX] = { // stable loner rep state r rp rd wr fwr l x caps,other [LOCK_SYNC] = { 0, false, LOCK_SYNC, ANY, 0, ANY, 0, 0, ANY, 0, CEPH_CAP_GSHARED,0,0,CEPH_CAP_GSHARED }, [LOCK_LOCK_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, ANY, XCL, XCL, 0, 0, XCL, 0, 0,0,0,0 }, [LOCK_EXCL_SYNC] = { LOCK_SYNC, true, LOCK_LOCK, 0, 0, 0, 0, XCL, 0, 0, 0,CEPH_CAP_GSHARED,0,0 }, [LOCK_SNAP_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, 0, 0, 0, 0, AUTH,0, 0, 0,0,0,0 }, [LOCK_LOCK] = { 0, false, LOCK_LOCK, AUTH, 0, REQ, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_SYNC_LOCK] = { LOCK_LOCK, false, LOCK_LOCK, ANY, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_EXCL_LOCK] = { LOCK_LOCK, false, LOCK_LOCK, 0, 0, 0, 0, XCL, 0, 0, 0,0,0,0 }, [LOCK_PREXLOCK] = { LOCK_LOCK, false, LOCK_LOCK, 0, XCL, 0, 0, 0, 0, ANY, 0,0,0,0 }, [LOCK_XLOCK] = { LOCK_SYNC, false, LOCK_LOCK, 0, XCL, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_XLOCKDONE] = { LOCK_SYNC, false, LOCK_LOCK, XCL, XCL, XCL, 0, 0, XCL, 0, 0,0,CEPH_CAP_GSHARED,0 }, [LOCK_LOCK_XLOCK]= { LOCK_PREXLOCK,false,LOCK_LOCK,0, XCL, 0, 0, 0, 0, XCL, 0,0,0,0 }, [LOCK_EXCL] = { 0, true, LOCK_LOCK, 0, 0, REQ, XCL, 0, 0, 0, 0,CEPH_CAP_GEXCL|CEPH_CAP_GSHARED,0,0 }, [LOCK_SYNC_EXCL] = { LOCK_EXCL, true, LOCK_LOCK, ANY, 0, 0, 0, 0, 0, 0, 0,CEPH_CAP_GSHARED,0,0 }, [LOCK_LOCK_EXCL] = { LOCK_EXCL, false, LOCK_LOCK, ANY, 0, 0, 0, 0, 0, 0, CEPH_CAP_GSHARED,0,0,0 }, [LOCK_REMOTEXLOCK]={ LOCK_LOCK, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, }; const struct sm_t sm_simplelock = { .states = simplelock, .allowed_ever_auth = CEPH_CAP_GSHARED | CEPH_CAP_GEXCL, .allowed_ever_replica = CEPH_CAP_GSHARED, .careful = CEPH_CAP_GSHARED | CEPH_CAP_GEXCL, .can_remote_xlock = 1, }; // lock state machine states: // Sync -- Lock -- sCatter // Tempsync _/ // (out of date) static const struct sm_state_t scatterlock[LOCK_MAX] = { // stable loner rep state r rp rd wr fwr l x caps,other [LOCK_SYNC] = { 0, false, LOCK_SYNC, ANY, 0, ANY, 0, 0, ANY, 0, CEPH_CAP_GSHARED,0,0,CEPH_CAP_GSHARED }, [LOCK_LOCK_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, AUTH, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_MIX_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_SNAP_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, 0, 0, 0, 0, AUTH,0, 0, 0,0,0,0 }, [LOCK_LOCK] = { 0, false, LOCK_LOCK, AUTH, 0, REQ, AUTH,0, 0, ANY, 0,0,0,0 }, [LOCK_SYNC_LOCK] = { LOCK_LOCK, false, LOCK_LOCK, AUTH, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_MIX_LOCK] = { LOCK_LOCK, false, LOCK_MIX, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_MIX_LOCK2] = { LOCK_LOCK, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_TSYN_LOCK] = { LOCK_LOCK, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_TSYN] = { 0, false, LOCK_LOCK, AUTH, 0, AUTH,0, 0, 0, 0, 0,0,0,0 }, [LOCK_LOCK_TSYN] = { LOCK_TSYN, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_MIX_TSYN] = { LOCK_TSYN, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_MIX] = { 0, false, LOCK_MIX, 0, 0, REQ, ANY, 0, 0, 0, 0,0,0,0 }, [LOCK_TSYN_MIX] = { LOCK_MIX, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_SYNC_MIX] = { LOCK_MIX, false, LOCK_SYNC_MIX2,0,0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_SYNC_MIX2] = { LOCK_MIX, false, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, }; const struct sm_t sm_scatterlock = { .states = scatterlock, .allowed_ever_auth = CEPH_CAP_GSHARED | CEPH_CAP_GEXCL, .allowed_ever_replica = CEPH_CAP_GSHARED, .careful = CEPH_CAP_GSHARED | CEPH_CAP_GEXCL, .can_remote_xlock = 0, }; const struct sm_state_t filelock[LOCK_MAX] = { // stable loner rep state r rp rd wr fwr l x caps(any,loner,xlocker,replica) [LOCK_SYNC] = { 0, false, LOCK_SYNC, ANY, 0, ANY, 0, 0, ANY, 0, CEPH_CAP_GSHARED|CEPH_CAP_GCACHE|CEPH_CAP_GRD,0,0,CEPH_CAP_GSHARED|CEPH_CAP_GCACHE|CEPH_CAP_GRD }, [LOCK_LOCK_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, AUTH, 0, 0, 0, 0, 0, 0, CEPH_CAP_GCACHE,0,0,0 }, [LOCK_EXCL_SYNC] = { LOCK_SYNC, true, LOCK_LOCK, 0, 0, 0, 0, XCL, 0, 0, 0,CEPH_CAP_GSHARED|CEPH_CAP_GCACHE|CEPH_CAP_GRD,0,0 }, [LOCK_MIX_SYNC] = { LOCK_SYNC, false, LOCK_MIX_SYNC2,0,0, 0, 0, 0, 0, 0, CEPH_CAP_GRD|CEPH_CAP_GLAZYIO,0,0,CEPH_CAP_GRD }, [LOCK_MIX_SYNC2] = { LOCK_SYNC, false, 0, 0, 0, 0, 0, 0, 0, 0, CEPH_CAP_GRD|CEPH_CAP_GLAZYIO,0,0,CEPH_CAP_GRD }, [LOCK_SNAP_SYNC] = { LOCK_SYNC, false, LOCK_LOCK, 0, 0, 0, 0, AUTH,0, 0, 0,0,0,0 }, [LOCK_XSYN_SYNC] = { LOCK_SYNC, true, LOCK_LOCK, AUTH, 0, AUTH,0, 0, 0, 0, 0,CEPH_CAP_GCACHE,0,0 }, [LOCK_LOCK] = { 0, false, LOCK_LOCK, AUTH, 0, REQ, AUTH,0, 0, 0, CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0,0 }, [LOCK_SYNC_LOCK] = { LOCK_LOCK, false, LOCK_LOCK, AUTH, 0, REQ, 0, 0, 0, 0, CEPH_CAP_GCACHE,0,0,0 }, [LOCK_EXCL_LOCK] = { LOCK_LOCK, false, LOCK_LOCK, 0, 0, 0, 0, XCL, 0, 0, CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0,0 }, [LOCK_MIX_LOCK] = { LOCK_LOCK, false, LOCK_MIX, AUTH, 0, REQ, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_MIX_LOCK2] = { LOCK_LOCK, false, LOCK_LOCK, AUTH, 0, REQ, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_PREXLOCK] = { LOCK_LOCK, false, LOCK_LOCK, 0, XCL, 0, 0, 0, 0, ANY, CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0,0 }, [LOCK_XLOCK] = { LOCK_LOCK, false, LOCK_LOCK, 0, XCL, 0, 0, 0, 0, 0, CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0,0 }, [LOCK_XLOCKDONE] = { LOCK_LOCK, false, LOCK_LOCK, XCL, XCL, XCL, 0, 0, XCL, 0, CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,CEPH_CAP_GSHARED,0 }, [LOCK_LOCK_XLOCK]= { LOCK_PREXLOCK,false,LOCK_LOCK,0, XCL, 0, 0, 0, 0, XCL, CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0,0 }, [LOCK_MIX] = { 0, false, LOCK_MIX, 0, 0, REQ, ANY, 0, 0, 0, CEPH_CAP_GRD|CEPH_CAP_GWR|CEPH_CAP_GLAZYIO,0,0,CEPH_CAP_GRD }, [LOCK_SYNC_MIX] = { LOCK_MIX, false, LOCK_SYNC_MIX2,ANY,0, 0, 0, 0, 0, 0, CEPH_CAP_GRD|CEPH_CAP_GLAZYIO,0,0,CEPH_CAP_GRD }, [LOCK_SYNC_MIX2] = { LOCK_MIX, false, 0, 0, 0, 0, 0, 0, 0, 0, CEPH_CAP_GRD|CEPH_CAP_GLAZYIO,0,0,CEPH_CAP_GRD }, [LOCK_EXCL_MIX] = { LOCK_MIX, true, LOCK_LOCK, 0, 0, 0, XCL, 0, 0, 0, 0,CEPH_CAP_GRD|CEPH_CAP_GWR|CEPH_CAP_GLAZYIO,0,0 }, [LOCK_EXCL] = { 0, true, LOCK_LOCK, 0, 0, XCL, XCL, 0, 0, 0, 0,CEPH_CAP_GSHARED|CEPH_CAP_GEXCL|CEPH_CAP_GCACHE|CEPH_CAP_GRD|CEPH_CAP_GWR|CEPH_CAP_GBUFFER|CEPH_CAP_GLAZYIO,0,0 }, [LOCK_SYNC_EXCL] = { LOCK_EXCL, true, LOCK_LOCK, AUTH, 0, 0, 0, 0, 0, 0, 0,CEPH_CAP_GSHARED|CEPH_CAP_GCACHE|CEPH_CAP_GRD,0,0 }, [LOCK_MIX_EXCL] = { LOCK_EXCL, true, LOCK_LOCK, 0, 0, 0, XCL, 0, 0, 0, 0,CEPH_CAP_GRD|CEPH_CAP_GWR|CEPH_CAP_GLAZYIO,0,0 }, [LOCK_LOCK_EXCL] = { LOCK_EXCL, true, LOCK_LOCK, AUTH, 0, 0, 0, 0, 0, 0, 0,CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0 }, [LOCK_XSYN_EXCL] = { LOCK_EXCL, true, LOCK_LOCK, AUTH, 0, XCL, 0, 0, 0, 0, 0,CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0 }, [LOCK_XSYN] = { 0, true, LOCK_LOCK, AUTH, AUTH,AUTH,XCL, 0, 0, 0, 0,CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0 }, [LOCK_EXCL_XSYN] = { LOCK_XSYN, false, LOCK_LOCK, 0, 0, XCL, 0, 0, 0, 0, 0,CEPH_CAP_GCACHE|CEPH_CAP_GBUFFER,0,0 }, [LOCK_PRE_SCAN] = { LOCK_SCAN, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, [LOCK_SCAN] = { LOCK_LOCK, false, LOCK_LOCK, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }, }; const struct sm_t sm_filelock = { .states = filelock, .allowed_ever_auth = (CEPH_CAP_GSHARED | CEPH_CAP_GEXCL | CEPH_CAP_GCACHE | CEPH_CAP_GRD | CEPH_CAP_GWR | CEPH_CAP_GWREXTEND | CEPH_CAP_GBUFFER | CEPH_CAP_GLAZYIO), .allowed_ever_replica = (CEPH_CAP_GSHARED | CEPH_CAP_GCACHE | CEPH_CAP_GRD | CEPH_CAP_GLAZYIO), .careful = (CEPH_CAP_GSHARED | CEPH_CAP_GEXCL | CEPH_CAP_GCACHE | CEPH_CAP_GBUFFER), .can_remote_xlock = 0, }; const struct sm_state_t locallock[LOCK_MAX] = { // stable loner rep state r rp rd wr fwr l x caps(any,loner,xlocker,replica) [LOCK_LOCK] = { 0, false, LOCK_LOCK, ANY, 0, ANY, 0, 0, ANY, AUTH,0,0,0,0 }, }; const struct sm_t sm_locallock = { .states = locallock, .allowed_ever_auth = 0, .allowed_ever_replica = 0, .careful = 0, .can_remote_xlock = 0, }; ceph-0.80.11/src/mds/MDBalancer.cc0000664000175100017510000007744712623076744020531 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "mdstypes.h" #include "MDBalancer.h" #include "MDS.h" #include "mon/MonClient.h" #include "MDSMap.h" #include "CInode.h" #include "CDir.h" #include "MDCache.h" #include "Migrator.h" #include "include/Context.h" #include "msg/Messenger.h" #include "messages/MHeartbeat.h" #include "messages/MMDSLoadTargets.h" #include #include #include #include using std::map; using std::vector; #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef DOUT_COND #define DOUT_COND(cct, l) l<=cct->_conf->debug_mds || l <= cct->_conf->debug_mds_balancer #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".bal " #define MIN_LOAD 50 // ?? #define MIN_REEXPORT 5 // will automatically reexport #define MIN_OFFLOAD 10 // point at which i stop trying, close enough /* This function DOES put the passed message before returning */ int MDBalancer::proc_message(Message *m) { switch (m->get_type()) { case MSG_MDS_HEARTBEAT: handle_heartbeat(static_cast(m)); break; default: dout(1) << " balancer unknown message " << m->get_type() << dendl; assert(0); m->put(); break; } return 0; } void MDBalancer::tick() { static int num_bal_times = g_conf->mds_bal_max; static utime_t first = ceph_clock_now(g_ceph_context); utime_t now = ceph_clock_now(g_ceph_context); utime_t elapsed = now; elapsed -= first; // sample? if ((double)now - (double)last_sample > g_conf->mds_bal_sample_interval) { dout(15) << "tick last_sample now " << now << dendl; last_sample = now; } // balance? if (last_heartbeat == utime_t()) last_heartbeat = now; if (mds->get_nodeid() == 0 && g_conf->mds_bal_interval > 0 && (num_bal_times || (g_conf->mds_bal_max_until >= 0 && elapsed.sec() > g_conf->mds_bal_max_until)) && mds->is_active() && now.sec() - last_heartbeat.sec() >= g_conf->mds_bal_interval) { last_heartbeat = now; send_heartbeat(); num_bal_times--; } // hash? if ((g_conf->mds_bal_frag || g_conf->mds_thrash_fragments) && g_conf->mds_bal_fragment_interval > 0 && now.sec() - last_fragment.sec() > g_conf->mds_bal_fragment_interval) { last_fragment = now; do_fragmenting(); } } class C_Bal_SendHeartbeat : public Context { public: MDS *mds; C_Bal_SendHeartbeat(MDS *mds) { this->mds = mds; } virtual void finish(int f) { mds->balancer->send_heartbeat(); } }; double mds_load_t::mds_load() { switch(g_conf->mds_bal_mode) { case 0: return .8 * auth.meta_load() + .2 * all.meta_load() + req_rate + 10.0 * queue_len; case 1: return req_rate + 10.0*queue_len; case 2: return cpu_load_avg; } assert(0); return 0; } mds_load_t MDBalancer::get_load(utime_t now) { mds_load_t load(now); if (mds->mdcache->get_root()) { list ls; mds->mdcache->get_root()->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { load.auth.add(now, mds->mdcache->decayrate, (*p)->pop_auth_subtree_nested); load.all.add(now, mds->mdcache->decayrate, (*p)->pop_nested); } } else { dout(20) << "get_load no root, no load" << dendl; } load.req_rate = mds->get_req_rate(); load.queue_len = mds->messenger->get_dispatch_queue_len(); ifstream cpu("/proc/loadavg"); if (cpu.is_open()) cpu >> load.cpu_load_avg; dout(15) << "get_load " << load << dendl; return load; } void MDBalancer::send_heartbeat() { utime_t now = ceph_clock_now(g_ceph_context); if (mds->mdsmap->is_degraded()) { dout(10) << "send_heartbeat degraded" << dendl; return; } if (!mds->mdcache->is_open()) { dout(5) << "not open" << dendl; mds->mdcache->wait_for_open(new C_Bal_SendHeartbeat(mds)); return; } mds_load.clear(); if (mds->get_nodeid() == 0) beat_epoch++; // my load mds_load_t load = get_load(now); map::value_type val(mds->get_nodeid(), load); mds_load.insert(val); // import_map -- how much do i import from whom map import_map; set authsubs; mds->mdcache->get_auth_subtrees(authsubs); for (set::iterator it = authsubs.begin(); it != authsubs.end(); ++it) { CDir *im = *it; int from = im->inode->authority().first; if (from == mds->get_nodeid()) continue; if (im->get_inode()->is_stray()) continue; import_map[from] += im->pop_auth_subtree.meta_load(now, mds->mdcache->decayrate); } mds_import_map[ mds->get_nodeid() ] = import_map; dout(5) << "mds." << mds->get_nodeid() << " epoch " << beat_epoch << " load " << load << dendl; for (map::iterator it = import_map.begin(); it != import_map.end(); ++it) { dout(5) << " import_map from " << it->first << " -> " << it->second << dendl; } set up; mds->get_mds_map()->get_mds_set(up); for (set::iterator p = up.begin(); p != up.end(); ++p) { if (*p == mds->get_nodeid()) continue; MHeartbeat *hb = new MHeartbeat(load, beat_epoch); hb->get_import_map() = import_map; mds->messenger->send_message(hb, mds->mdsmap->get_inst(*p)); } } /* This function DOES put the passed message before returning */ void MDBalancer::handle_heartbeat(MHeartbeat *m) { typedef map mds_load_map_t; int who = m->get_source().num(); dout(25) << "=== got heartbeat " << m->get_beat() << " from " << m->get_source().num() << " " << m->get_load() << dendl; if (!mds->is_active()) goto out; if (!mds->mdcache->is_open()) { dout(10) << "opening root on handle_heartbeat" << dendl; mds->mdcache->wait_for_open(new C_MDS_RetryMessage(mds, m)); return; } if (mds->mdsmap->is_degraded()) { dout(10) << " degraded, ignoring" << dendl; goto out; } if (who == 0) { dout(20) << " from mds0, new epoch" << dendl; beat_epoch = m->get_beat(); send_heartbeat(); show_imports(); } { // set mds_load[who] mds_load_map_t::value_type val(who, m->get_load()); pair < mds_load_map_t::iterator, bool > rval (mds_load.insert(val)); if (!rval.second) { rval.first->second = val.second; } } mds_import_map[ who ] = m->get_import_map(); //dout(0) << " load is " << load << " have " << mds_load.size() << dendl; { unsigned cluster_size = mds->get_mds_map()->get_num_in_mds(); if (mds_load.size() == cluster_size) { // let's go! //export_empties(); // no! prep_rebalance(m->get_beat()); } } // done out: m->put(); } void MDBalancer::export_empties() { dout(5) << "export_empties checking for empty imports" << dendl; for (map >::iterator it = mds->mdcache->subtrees.begin(); it != mds->mdcache->subtrees.end(); ++it) { CDir *dir = it->first; if (!dir->is_auth() || dir->is_ambiguous_auth() || dir->is_freezing() || dir->is_frozen()) continue; if (!dir->inode->is_base() && !dir->inode->is_stray() && dir->get_num_head_items() == 0) mds->mdcache->migrator->export_empty_import(dir); } } double MDBalancer::try_match(int ex, double& maxex, int im, double& maxim) { if (maxex <= 0 || maxim <= 0) return 0.0; double howmuch = MIN(maxex, maxim); if (howmuch <= 0) return 0.0; dout(5) << " - mds." << ex << " exports " << howmuch << " to mds." << im << dendl; if (ex == mds->get_nodeid()) my_targets[im] += howmuch; exported[ex] += howmuch; imported[im] += howmuch; maxex -= howmuch; maxim -= howmuch; return howmuch; } void MDBalancer::queue_split(CDir *dir) { split_queue.insert(dir->dirfrag()); } void MDBalancer::queue_merge(CDir *dir) { merge_queue.insert(dir->dirfrag()); } void MDBalancer::do_fragmenting() { if (split_queue.empty() && merge_queue.empty()) { dout(20) << "do_fragmenting has nothing to do" << dendl; return; } if (!split_queue.empty()) { dout(10) << "do_fragmenting " << split_queue.size() << " dirs marked for possible splitting" << dendl; set q; q.swap(split_queue); for (set::iterator i = q.begin(); i != q.end(); ++i) { CDir *dir = mds->mdcache->get_dirfrag(*i); if (!dir || !dir->is_auth()) continue; dout(10) << "do_fragmenting splitting " << *dir << dendl; mds->mdcache->split_dir(dir, g_conf->mds_bal_split_bits); } } if (!merge_queue.empty()) { dout(10) << "do_fragmenting " << merge_queue.size() << " dirs marked for possible merging" << dendl; set q; q.swap(merge_queue); for (set::iterator i = q.begin(); i != q.end(); ++i) { CDir *dir = mds->mdcache->get_dirfrag(*i); if (!dir || !dir->is_auth() || dir->get_frag() == frag_t()) // ok who's the joker? continue; dout(10) << "do_fragmenting merging " << *dir << dendl; CInode *diri = dir->get_inode(); frag_t fg = dir->get_frag(); while (fg != frag_t()) { frag_t sibfg = fg.get_sibling(); list sibs; bool complete = diri->get_dirfrags_under(sibfg, sibs); if (!complete) { dout(10) << " not all sibs under " << sibfg << " in cache (have " << sibs << ")" << dendl; break; } bool all = true; for (list::iterator p = sibs.begin(); p != sibs.end(); ++p) { CDir *sib = *p; if (!sib->is_auth() || !sib->should_merge()) { all = false; break; } } if (!all) { dout(10) << " not all sibs under " << sibfg << " " << sibs << " should_merge" << dendl; break; } dout(10) << " all sibs under " << sibfg << " " << sibs << " should merge" << dendl; fg = fg.parent(); } if (fg != dir->get_frag()) mds->mdcache->merge_dir(diri, fg); } } } void MDBalancer::prep_rebalance(int beat) { if (g_conf->mds_thrash_exports) { //we're going to randomly export to all the mds in the cluster my_targets.clear(); set up_mds; mds->get_mds_map()->get_up_mds_set(up_mds); for (set::iterator i = up_mds.begin(); i != up_mds.end(); ++i) my_targets[*i] = 0.0; } else { int cluster_size = mds->get_mds_map()->get_num_in_mds(); int whoami = mds->get_nodeid(); rebalance_time = ceph_clock_now(g_ceph_context); // reset my_targets.clear(); imported.clear(); exported.clear(); dout(5) << " prep_rebalance: cluster loads are" << dendl; mds->mdcache->migrator->clear_export_queue(); // rescale! turn my mds_load back into meta_load units double load_fac = 1.0; map::iterator m = mds_load.find(whoami); if ((m != mds_load.end()) && (m->second.mds_load() > 0)) { double metald = m->second.auth.meta_load(rebalance_time, mds->mdcache->decayrate); double mdsld = m->second.mds_load(); load_fac = metald / mdsld; dout(7) << " load_fac is " << load_fac << " <- " << m->second.auth << " " << metald << " / " << mdsld << dendl; } double total_load = 0; multimap load_map; for (int i=0; i::value_type val(i, mds_load_t(ceph_clock_now(g_ceph_context))); std::pair < map::iterator, bool > r(mds_load.insert(val)); mds_load_t &load(r.first->second); double l = load.mds_load() * load_fac; mds_meta_load[i] = l; if (whoami == 0) dout(0) << " mds." << i << " " << load << " = " << load.mds_load() << " ~ " << l << dendl; if (whoami == i) my_load = l; total_load += l; load_map.insert(pair( l, i )); } // target load target_load = total_load / (double)cluster_size; dout(5) << "prep_rebalance: my load " << my_load << " target " << target_load << " total " << total_load << dendl; // under or over? if (my_load < target_load * (1.0 + g_conf->mds_bal_min_rebalance)) { dout(5) << " i am underloaded or barely overloaded, doing nothing." << dendl; last_epoch_under = beat_epoch; show_imports(); return; } last_epoch_over = beat_epoch; // am i over long enough? if (last_epoch_under && beat_epoch - last_epoch_under < 2) { dout(5) << " i am overloaded, but only for " << (beat_epoch - last_epoch_under) << " epochs" << dendl; return; } dout(5) << " i am sufficiently overloaded" << dendl; // first separate exporters and importers multimap importers; multimap exporters; set importer_set; set exporter_set; for (multimap::iterator it = load_map.begin(); it != load_map.end(); ++it) { if (it->first < target_load) { dout(15) << " mds." << it->second << " is importer" << dendl; importers.insert(pair(it->first,it->second)); importer_set.insert(it->second); } else { dout(15) << " mds." << it->second << " is exporter" << dendl; exporters.insert(pair(it->first,it->second)); exporter_set.insert(it->second); } } // determine load transfer mapping if (true) { // analyze import_map; do any matches i can dout(15) << " matching exporters to import sources" << dendl; // big -> small exporters for (multimap::reverse_iterator ex = exporters.rbegin(); ex != exporters.rend(); ++ex) { double maxex = get_maxex(ex->second); if (maxex <= .001) continue; // check importers. for now, just in arbitrary order (no intelligent matching). for (map::iterator im = mds_import_map[ex->second].begin(); im != mds_import_map[ex->second].end(); ++im) { double maxim = get_maxim(im->first); if (maxim <= .001) continue; try_match(ex->second, maxex, im->first, maxim); if (maxex <= .001) break;; } } } if (1) { if (beat % 2 == 1) { // old way dout(15) << " matching big exporters to big importers" << dendl; // big exporters to big importers multimap::reverse_iterator ex = exporters.rbegin(); multimap::iterator im = importers.begin(); while (ex != exporters.rend() && im != importers.end()) { double maxex = get_maxex(ex->second); double maxim = get_maxim(im->second); if (maxex < .001 || maxim < .001) break; try_match(ex->second, maxex, im->second, maxim); if (maxex <= .001) ++ex; if (maxim <= .001) ++im; } } else { // new way dout(15) << " matching small exporters to big importers" << dendl; // small exporters to big importers multimap::iterator ex = exporters.begin(); multimap::iterator im = importers.begin(); while (ex != exporters.end() && im != importers.end()) { double maxex = get_maxex(ex->second); double maxim = get_maxim(im->second); if (maxex < .001 || maxim < .001) break; try_match(ex->second, maxex, im->second, maxim); if (maxex <= .001) ++ex; if (maxim <= .001) ++im; } } } } try_rebalance(); } void MDBalancer::try_rebalance() { if (!check_targets()) return; if (g_conf->mds_thrash_exports) { dout(5) << "mds_thrash is on; not performing standard rebalance operation!" << dendl; return; } // make a sorted list of my imports map import_pop_map; multimap import_from_map; set fullauthsubs; mds->mdcache->get_fullauth_subtrees(fullauthsubs); for (set::iterator it = fullauthsubs.begin(); it != fullauthsubs.end(); ++it) { CDir *im = *it; if (im->get_inode()->is_stray()) continue; double pop = im->pop_auth_subtree.meta_load(rebalance_time, mds->mdcache->decayrate); if (g_conf->mds_bal_idle_threshold > 0 && pop < g_conf->mds_bal_idle_threshold && im->inode != mds->mdcache->get_root() && im->inode->authority().first != mds->get_nodeid()) { dout(0) << " exporting idle (" << pop << ") import " << *im << " back to mds." << im->inode->authority().first << dendl; mds->mdcache->migrator->export_dir_nicely(im, im->inode->authority().first); continue; } import_pop_map[ pop ] = im; int from = im->inode->authority().first; dout(15) << " map: i imported " << *im << " from " << from << dendl; import_from_map.insert(pair(from, im)); } // do my exports! set already_exporting; double total_sent = 0; double total_goal = 0; for (map::iterator it = my_targets.begin(); it != my_targets.end(); ++it) { /* double fac = 1.0; if (false && total_goal > 0 && total_sent > 0) { fac = total_goal / total_sent; dout(0) << " total sent is " << total_sent << " / " << total_goal << " -> fac 1/ " << fac << dendl; if (fac > 1.0) fac = 1.0; } fac = .9 - .4 * ((float)g_conf->num_mds / 128.0); // hack magic fixme */ int target = (*it).first; double amount = (*it).second; total_goal += amount; if (amount < MIN_OFFLOAD) continue; if (amount / target_load < .2) continue; dout(5) << "want to send " << amount << " to mds." << target //<< " .. " << (*it).second << " * " << load_fac << " -> " << amount << dendl;//" .. fudge is " << fudge << dendl; double have = 0; show_imports(); // search imports from target if (import_from_map.count(target)) { dout(5) << " aha, looking through imports from target mds." << target << dendl; pair::iterator, multimap::iterator> p = import_from_map.equal_range(target); while (p.first != p.second) { CDir *dir = (*p.first).second; dout(5) << "considering " << *dir << " from " << (*p.first).first << dendl; multimap::iterator plast = p.first++; if (dir->inode->is_base() || dir->inode->is_stray()) continue; if (dir->is_freezing() || dir->is_frozen()) continue; // export pbly already in progress double pop = dir->pop_auth_subtree.meta_load(rebalance_time, mds->mdcache->decayrate); assert(dir->inode->authority().first == target); // cuz that's how i put it in the map, dummy if (pop <= amount-have) { dout(0) << "reexporting " << *dir << " pop " << pop << " back to mds." << target << dendl; mds->mdcache->migrator->export_dir_nicely(dir, target); have += pop; import_from_map.erase(plast); import_pop_map.erase(pop); } else { dout(5) << "can't reexport " << *dir << ", too big " << pop << dendl; } if (amount-have < MIN_OFFLOAD) break; } } if (amount-have < MIN_OFFLOAD) { total_sent += have; continue; } // any other imports if (false) for (map::iterator import = import_pop_map.begin(); import != import_pop_map.end(); import++) { CDir *imp = (*import).second; if (imp->inode->is_base() || imp->inode->is_stray()) continue; double pop = (*import).first; if (pop < amount-have || pop < MIN_REEXPORT) { dout(0) << "reexporting " << *imp << " pop " << pop << " back to mds." << imp->inode->authority() << dendl; have += pop; mds->mdcache->migrator->export_dir_nicely(imp, imp->inode->authority().first); } if (amount-have < MIN_OFFLOAD) break; } if (amount-have < MIN_OFFLOAD) { //fudge = amount-have; total_sent += have; continue; } // okay, search for fragments of my workload set candidates; mds->mdcache->get_fullauth_subtrees(candidates); list exports; for (set::iterator pot = candidates.begin(); pot != candidates.end(); ++pot) { if ((*pot)->get_inode()->is_stray()) continue; find_exports(*pot, amount, exports, have, already_exporting); if (have > amount-MIN_OFFLOAD) break; } //fudge = amount - have; total_sent += have; for (list::iterator it = exports.begin(); it != exports.end(); ++it) { dout(0) << " - exporting " << (*it)->pop_auth_subtree << " " << (*it)->pop_auth_subtree.meta_load(rebalance_time, mds->mdcache->decayrate) << " to mds." << target << " " << **it << dendl; mds->mdcache->migrator->export_dir_nicely(*it, target); } } dout(5) << "rebalance done" << dendl; show_imports(); } /* returns true if all my_target MDS are in the MDSMap. */ bool MDBalancer::check_targets() { // get MonMap's idea of my_targets const set& map_targets = mds->mdsmap->get_mds_info(mds->whoami).export_targets; bool send = false; bool ok = true; // make sure map targets are in the old_prev_targets map for (set::iterator p = map_targets.begin(); p != map_targets.end(); ++p) { if (old_prev_targets.count(*p) == 0) old_prev_targets[*p] = 0; if (my_targets.count(*p) == 0) old_prev_targets[*p]++; } // check if the current MonMap has all our targets set need_targets; for (map::iterator i = my_targets.begin(); i != my_targets.end(); ++i) { need_targets.insert(i->first); old_prev_targets[i->first] = 0; if (!map_targets.count(i->first)) { dout(20) << " target mds." << i->first << " not in map's export_targets" << dendl; send = true; ok = false; } } set want_targets = need_targets; map::iterator p = old_prev_targets.begin(); while (p != old_prev_targets.end()) { if (map_targets.count(p->first) == 0 && need_targets.count(p->first) == 0) { old_prev_targets.erase(p++); continue; } dout(20) << " target mds." << p->first << " has been non-target for " << p->second << dendl; if (p->second < g_conf->mds_bal_target_removal_min) want_targets.insert(p->first); if (p->second >= g_conf->mds_bal_target_removal_max) send = true; ++p; } dout(10) << "check_targets have " << map_targets << " need " << need_targets << " want " << want_targets << dendl; if (send) { MMDSLoadTargets* m = new MMDSLoadTargets(mds->monc->get_global_id(), want_targets); mds->monc->send_mon_message(m); } return ok; } void MDBalancer::find_exports(CDir *dir, double amount, list& exports, double& have, set& already_exporting) { double need = amount - have; if (need < amount * g_conf->mds_bal_min_start) return; // good enough! double needmax = need * g_conf->mds_bal_need_max; double needmin = need * g_conf->mds_bal_need_min; double midchunk = need * g_conf->mds_bal_midchunk; double minchunk = need * g_conf->mds_bal_minchunk; list bigger_rep, bigger_unrep; multimap smaller; double dir_pop = dir->pop_auth_subtree.meta_load(rebalance_time, mds->mdcache->decayrate); dout(7) << " find_exports in " << dir_pop << " " << *dir << " need " << need << " (" << needmin << " - " << needmax << ")" << dendl; double subdir_sum = 0; for (CDir::map_t::iterator it = dir->begin(); it != dir->end(); ++it) { CInode *in = it->second->get_linkage()->get_inode(); if (!in) continue; if (!in->is_dir()) continue; list dfls; in->get_dirfrags(dfls); for (list::iterator p = dfls.begin(); p != dfls.end(); ++p) { CDir *subdir = *p; if (!subdir->is_auth()) continue; if (already_exporting.count(subdir)) continue; if (subdir->is_frozen()) continue; // can't export this right now! // how popular? double pop = subdir->pop_auth_subtree.meta_load(rebalance_time, mds->mdcache->decayrate); subdir_sum += pop; dout(15) << " subdir pop " << pop << " " << *subdir << dendl; if (pop < minchunk) continue; // lucky find? if (pop > needmin && pop < needmax) { exports.push_back(subdir); already_exporting.insert(subdir); have += pop; return; } if (pop > need) { if (subdir->is_rep()) bigger_rep.push_back(subdir); else bigger_unrep.push_back(subdir); } else smaller.insert(pair(pop, subdir)); } } dout(15) << " sum " << subdir_sum << " / " << dir_pop << dendl; // grab some sufficiently big small items multimap::reverse_iterator it; for (it = smaller.rbegin(); it != smaller.rend(); ++it) { if ((*it).first < midchunk) break; // try later dout(7) << " taking smaller " << *(*it).second << dendl; exports.push_back((*it).second); already_exporting.insert((*it).second); have += (*it).first; if (have > needmin) return; } // apprently not enough; drill deeper into the hierarchy (if non-replicated) for (list::iterator it = bigger_unrep.begin(); it != bigger_unrep.end(); ++it) { dout(15) << " descending into " << **it << dendl; find_exports(*it, amount, exports, have, already_exporting); if (have > needmin) return; } // ok fine, use smaller bits for (; it != smaller.rend(); ++it) { dout(7) << " taking (much) smaller " << it->first << " " << *(*it).second << dendl; exports.push_back((*it).second); already_exporting.insert((*it).second); have += (*it).first; if (have > needmin) return; } // ok fine, drill into replicated dirs for (list::iterator it = bigger_rep.begin(); it != bigger_rep.end(); ++it) { dout(7) << " descending into replicated " << **it << dendl; find_exports(*it, amount, exports, have, already_exporting); if (have > needmin) return; } } void MDBalancer::hit_inode(utime_t now, CInode *in, int type, int who) { // hit inode in->pop.get(type).hit(now, mds->mdcache->decayrate); if (in->get_parent_dn()) hit_dir(now, in->get_parent_dn()->get_dir(), type, who); } /* // hit me in->popularity[MDS_POP_JUSTME].pop[type].hit(now); in->popularity[MDS_POP_NESTED].pop[type].hit(now); if (in->is_auth()) { in->popularity[MDS_POP_CURDOM].pop[type].hit(now); in->popularity[MDS_POP_ANYDOM].pop[type].hit(now); dout(20) << "hit_inode " << type << " pop " << in->popularity[MDS_POP_JUSTME].pop[type].get(now) << " me, " << in->popularity[MDS_POP_NESTED].pop[type].get(now) << " nested, " << in->popularity[MDS_POP_CURDOM].pop[type].get(now) << " curdom, " << in->popularity[MDS_POP_CURDOM].pop[type].get(now) << " anydom" << " on " << *in << dendl; } else { dout(20) << "hit_inode " << type << " pop " << in->popularity[MDS_POP_JUSTME].pop[type].get(now) << " me, " << in->popularity[MDS_POP_NESTED].pop[type].get(now) << " nested, " << " on " << *in << dendl; } // hit auth up to import CDir *dir = in->get_parent_dir(); if (dir) hit_dir(now, dir, type); */ void MDBalancer::hit_dir(utime_t now, CDir *dir, int type, int who, double amount) { // hit me double v = dir->pop_me.get(type).hit(now, amount); //if (dir->ino() == inodeno_t(0x10000000000)) //dout(0) << "hit_dir " << type << " pop " << v << " in " << *dir << dendl; // split/merge if (g_conf->mds_bal_frag && g_conf->mds_bal_fragment_interval > 0 && !dir->inode->is_base() && // not root/base (for now at least) dir->is_auth()) { dout(20) << "hit_dir " << type << " pop is " << v << ", frag " << dir->get_frag() << " size " << dir->get_frag_size() << dendl; // split if (g_conf->mds_bal_split_size > 0 && (dir->should_split() || (v > g_conf->mds_bal_split_rd && type == META_POP_IRD) || (v > g_conf->mds_bal_split_wr && type == META_POP_IWR)) && split_queue.count(dir->dirfrag()) == 0) { dout(10) << "hit_dir " << type << " pop is " << v << ", putting in split_queue: " << *dir << dendl; split_queue.insert(dir->dirfrag()); } // merge? if (dir->get_frag() != frag_t() && dir->should_merge() && merge_queue.count(dir->dirfrag()) == 0) { dout(10) << "hit_dir " << type << " pop is " << v << ", putting in merge_queue: " << *dir << dendl; merge_queue.insert(dir->dirfrag()); } } // replicate? if (type == META_POP_IRD && who >= 0) { dir->pop_spread.hit(now, mds->mdcache->decayrate, who); } double rd_adj = 0; if (type == META_POP_IRD && dir->last_popularity_sample < last_sample) { float dir_pop = dir->pop_auth_subtree.get(type).get(now, mds->mdcache->decayrate); // hmm?? dir->last_popularity_sample = last_sample; float pop_sp = dir->pop_spread.get(now, mds->mdcache->decayrate); dir_pop += pop_sp * 10; //if (dir->ino() == inodeno_t(0x10000000002)) if (pop_sp > 0) { dout(20) << "hit_dir " << type << " pop " << dir_pop << " spread " << pop_sp << " " << dir->pop_spread.last[0] << " " << dir->pop_spread.last[1] << " " << dir->pop_spread.last[2] << " " << dir->pop_spread.last[3] << " in " << *dir << dendl; } if (dir->is_auth() && !dir->is_ambiguous_auth()) { if (!dir->is_rep() && dir_pop >= g_conf->mds_bal_replicate_threshold) { // replicate float rdp = dir->pop_me.get(META_POP_IRD).get(now, mds->mdcache->decayrate); rd_adj = rdp / mds->get_mds_map()->get_num_in_mds() - rdp; rd_adj /= 2.0; // temper somewhat dout(0) << "replicating dir " << *dir << " pop " << dir_pop << " .. rdp " << rdp << " adj " << rd_adj << dendl; dir->dir_rep = CDir::REP_ALL; mds->mdcache->send_dir_updates(dir, true); // fixme this should adjust the whole pop hierarchy dir->pop_me.get(META_POP_IRD).adjust(rd_adj); dir->pop_auth_subtree.get(META_POP_IRD).adjust(rd_adj); } if (dir->ino() != 1 && dir->is_rep() && dir_pop < g_conf->mds_bal_unreplicate_threshold) { // unreplicate dout(0) << "unreplicating dir " << *dir << " pop " << dir_pop << dendl; dir->dir_rep = CDir::REP_NONE; mds->mdcache->send_dir_updates(dir); } } } // adjust ancestors bool hit_subtree = dir->is_auth(); // current auth subtree (if any) bool hit_subtree_nested = dir->is_auth(); // all nested auth subtrees while (1) { dir->pop_nested.get(type).hit(now, amount); if (rd_adj != 0.0) dir->pop_nested.get(META_POP_IRD).adjust(now, mds->mdcache->decayrate, rd_adj); if (hit_subtree) { dir->pop_auth_subtree.get(type).hit(now, amount); if (rd_adj != 0.0) dir->pop_auth_subtree.get(META_POP_IRD).adjust(now, mds->mdcache->decayrate, rd_adj); } if (hit_subtree_nested) { dir->pop_auth_subtree_nested.get(type).hit(now, mds->mdcache->decayrate, amount); if (rd_adj != 0.0) dir->pop_auth_subtree_nested.get(META_POP_IRD).adjust(now, mds->mdcache->decayrate, rd_adj); } if (dir->is_subtree_root()) hit_subtree = false; // end of auth domain, stop hitting auth counters. if (dir->inode->get_parent_dn() == 0) break; dir = dir->inode->get_parent_dn()->get_dir(); } } /* * subtract off an exported chunk. * this excludes *dir itself (encode_export_dir should have take care of that) * we _just_ do the parents' nested counters. * * NOTE: call me _after_ forcing *dir into a subtree root, * but _before_ doing the encode_export_dirs. */ void MDBalancer::subtract_export(CDir *dir, utime_t now) { dirfrag_load_vec_t subload = dir->pop_auth_subtree; while (true) { dir = dir->inode->get_parent_dir(); if (!dir) break; dir->pop_nested.sub(now, mds->mdcache->decayrate, subload); dir->pop_auth_subtree_nested.sub(now, mds->mdcache->decayrate, subload); } } void MDBalancer::add_import(CDir *dir, utime_t now) { dirfrag_load_vec_t subload = dir->pop_auth_subtree; while (true) { dir = dir->inode->get_parent_dir(); if (!dir) break; dir->pop_nested.add(now, mds->mdcache->decayrate, subload); dir->pop_auth_subtree_nested.add(now, mds->mdcache->decayrate, subload); } } void MDBalancer::show_imports(bool external) { mds->mdcache->show_subtrees(); } ceph-0.80.11/src/mds/SnapServer.h0000664000175100017510000000502212623076744020507 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SNAPSERVER_H #define CEPH_SNAPSERVER_H #include "MDSTableServer.h" #include "snap.h" class MDS; class SnapServer : public MDSTableServer { public: protected: snapid_t last_snap; map snaps; map > need_to_purge; map pending_create; map > pending_destroy; // (removed_snap, seq) set pending_noop; version_t last_checked_osdmap; public: SnapServer(MDS *m) : MDSTableServer(m, TABLE_SNAP), last_checked_osdmap(0) { } void reset_state(); void encode_server_state(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(last_snap, bl); ::encode(snaps, bl); ::encode(need_to_purge, bl); ::encode(pending_create, bl); ::encode(pending_destroy, bl); ::encode(pending_noop, bl); ENCODE_FINISH(bl); } void decode_server_state(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); ::decode(last_snap, bl); ::decode(snaps, bl); ::decode(need_to_purge, bl); ::decode(pending_create, bl); if (struct_v >= 2) ::decode(pending_destroy, bl); else { map t; ::decode(t, bl); for (map::iterator p = t.begin(); p != t.end(); ++p) pending_destroy[p->first].first = p->second; } ::decode(pending_noop, bl); DECODE_FINISH(bl); } // To permit enc/decoding in isolation in dencoder SnapServer() : MDSTableServer(NULL, TABLE_SNAP), last_checked_osdmap(0) {} void encode(bufferlist& bl) const { encode_server_state(bl); } void decode(bufferlist::iterator& bl) { decode_server_state(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); // server bits void _prepare(bufferlist &bl, uint64_t reqid, int bymds); bool _is_prepared(version_t tid); bool _commit(version_t tid, MMDSTableRequest *req=NULL); void _rollback(version_t tid); void _server_update(bufferlist& bl); void handle_query(MMDSTableRequest *m); void check_osd_map(bool force); }; #endif ceph-0.80.11/src/mds/InoTable.h0000664000175100017510000000361512623076744020122 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_INOTABLE_H #define CEPH_INOTABLE_H #include "MDSTable.h" #include "include/interval_set.h" class MDS; class InoTable : public MDSTable { interval_set free; // unused ids interval_set projected_free; public: InoTable(MDS *m) : MDSTable(m, "inotable", true) { } inodeno_t project_alloc_id(inodeno_t id=0); void apply_alloc_id(inodeno_t id); void project_alloc_ids(interval_set& inos, int want); void apply_alloc_ids(interval_set& inos); void project_release_ids(interval_set& inos); void apply_release_ids(interval_set& inos); void replay_alloc_id(inodeno_t ino); void replay_alloc_ids(interval_set& inos); void replay_release_ids(interval_set& inos); void replay_reset(); void reset_state(); void encode_state(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(free, bl); ENCODE_FINISH(bl); } void decode_state(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(free, bl); projected_free = free; DECODE_FINISH(bl); } // To permit enc/decoding in isolation in dencoder InoTable() : MDSTable(NULL, "inotable", true) {} void encode(bufferlist& bl) const { encode_state(bl); } void decode(bufferlist::iterator& bl) { decode_state(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); void skip_inos(inodeno_t i); }; #endif ceph-0.80.11/src/mds/mdstypes.cc0000664000175100017510000005225712623076744020441 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "mdstypes.h" #include "common/Formatter.h" void dump(const ceph_file_layout& l, Formatter *f) { f->dump_unsigned("stripe_unit", l.fl_stripe_unit); f->dump_unsigned("stripe_count", l.fl_stripe_count); f->dump_unsigned("object_size", l.fl_object_size); if (l.fl_cas_hash) f->dump_unsigned("cas_hash", l.fl_cas_hash); if (l.fl_object_stripe_unit) f->dump_unsigned("object_stripe_unit", l.fl_object_stripe_unit); if (l.fl_pg_pool) f->dump_unsigned("pg_pool", l.fl_pg_pool); } void dump(const ceph_dir_layout& l, Formatter *f) { f->dump_unsigned("dir_hash", l.dl_dir_hash); } /* * frag_info_t */ void frag_info_t::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(version, bl); ::encode(mtime, bl); ::encode(nfiles, bl); ::encode(nsubdirs, bl); ENCODE_FINISH(bl); } void frag_info_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(version, bl); ::decode(mtime, bl); ::decode(nfiles, bl); ::decode(nsubdirs, bl); DECODE_FINISH(bl); } void frag_info_t::dump(Formatter *f) const { f->dump_unsigned("version", version); f->dump_stream("mtime") << mtime; f->dump_unsigned("num_files", nfiles); f->dump_unsigned("num_subdirs", nsubdirs); } void frag_info_t::generate_test_instances(list& ls) { ls.push_back(new frag_info_t); ls.push_back(new frag_info_t); ls.back()->version = 1; ls.back()->mtime = utime_t(2, 3); ls.back()->nfiles = 4; ls.back()->nsubdirs = 5; } ostream& operator<<(ostream &out, const frag_info_t &f) { if (f == frag_info_t()) return out << "f()"; out << "f(v" << f.version; if (f.mtime != utime_t()) out << " m" << f.mtime; if (f.nfiles || f.nsubdirs) out << " " << f.size() << "=" << f.nfiles << "+" << f.nsubdirs; out << ")"; return out; } /* * nest_info_t */ void nest_info_t::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(version, bl); ::encode(rbytes, bl); ::encode(rfiles, bl); ::encode(rsubdirs, bl); ::encode(ranchors, bl); ::encode(rsnaprealms, bl); ::encode(rctime, bl); ENCODE_FINISH(bl); } void nest_info_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(version, bl); ::decode(rbytes, bl); ::decode(rfiles, bl); ::decode(rsubdirs, bl); ::decode(ranchors, bl); ::decode(rsnaprealms, bl); ::decode(rctime, bl); DECODE_FINISH(bl); } void nest_info_t::dump(Formatter *f) const { f->dump_unsigned("version", version); f->dump_unsigned("rbytes", rbytes); f->dump_unsigned("rfiles", rfiles); f->dump_unsigned("rsubdirs", rsubdirs); f->dump_unsigned("ranchors", ranchors); f->dump_unsigned("rsnaprealms", rsnaprealms); f->dump_stream("rctime") << rctime; } void nest_info_t::generate_test_instances(list& ls) { ls.push_back(new nest_info_t); ls.push_back(new nest_info_t); ls.back()->version = 1; ls.back()->rbytes = 2; ls.back()->rfiles = 3; ls.back()->rsubdirs = 4; ls.back()->ranchors = 5; ls.back()->rsnaprealms = 6; ls.back()->rctime = utime_t(7, 8); } ostream& operator<<(ostream &out, const nest_info_t &n) { if (n == nest_info_t()) return out << "n()"; out << "n(v" << n.version; if (n.rctime != utime_t()) out << " rc" << n.rctime; if (n.rbytes) out << " b" << n.rbytes; if (n.ranchors) out << " a" << n.ranchors; if (n.rsnaprealms) out << " sr" << n.rsnaprealms; if (n.rfiles || n.rsubdirs) out << " " << n.rsize() << "=" << n.rfiles << "+" << n.rsubdirs; out << ")"; return out; } /* * client_writeable_range_t */ void client_writeable_range_t::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(range.first, bl); ::encode(range.last, bl); ::encode(follows, bl); ENCODE_FINISH(bl); } void client_writeable_range_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(range.first, bl); ::decode(range.last, bl); ::decode(follows, bl); DECODE_FINISH(bl); } void client_writeable_range_t::dump(Formatter *f) const { f->open_object_section("byte range"); f->dump_unsigned("first", range.first); f->dump_unsigned("last", range.last); f->close_section(); f->dump_unsigned("follows", follows); } void client_writeable_range_t::generate_test_instances(list& ls) { ls.push_back(new client_writeable_range_t); ls.push_back(new client_writeable_range_t); ls.back()->range.first = 123; ls.back()->range.last = 456; ls.back()->follows = 12; } ostream& operator<<(ostream& out, const client_writeable_range_t& r) { return out << r.range.first << '-' << r.range.last << "@" << r.follows; } /* * inode_t */ void inode_t::encode(bufferlist &bl) const { ENCODE_START(10, 6, bl); ::encode(ino, bl); ::encode(rdev, bl); ::encode(ctime, bl); ::encode(mode, bl); ::encode(uid, bl); ::encode(gid, bl); ::encode(nlink, bl); ::encode(anchored, bl); ::encode(dir_layout, bl); ::encode(layout, bl); ::encode(size, bl); ::encode(truncate_seq, bl); ::encode(truncate_size, bl); ::encode(truncate_from, bl); ::encode(truncate_pending, bl); ::encode(mtime, bl); ::encode(atime, bl); ::encode(time_warp_seq, bl); ::encode(client_ranges, bl); ::encode(dirstat, bl); ::encode(rstat, bl); ::encode(accounted_rstat, bl); ::encode(version, bl); ::encode(file_data_version, bl); ::encode(xattr_version, bl); ::encode(backtrace_version, bl); ::encode(old_pools, bl); ::encode(max_size_ever, bl); ::encode(inline_version, bl); ::encode(inline_data, bl); ENCODE_FINISH(bl); } void inode_t::decode(bufferlist::iterator &p) { DECODE_START_LEGACY_COMPAT_LEN(10, 6, 6, p); ::decode(ino, p); ::decode(rdev, p); ::decode(ctime, p); ::decode(mode, p); ::decode(uid, p); ::decode(gid, p); ::decode(nlink, p); ::decode(anchored, p); if (struct_v >= 4) ::decode(dir_layout, p); else memset(&dir_layout, 0, sizeof(dir_layout)); ::decode(layout, p); ::decode(size, p); ::decode(truncate_seq, p); ::decode(truncate_size, p); ::decode(truncate_from, p); if (struct_v >= 5) ::decode(truncate_pending, p); else truncate_pending = 0; ::decode(mtime, p); ::decode(atime, p); ::decode(time_warp_seq, p); if (struct_v >= 3) { ::decode(client_ranges, p); } else { map m; ::decode(m, p); for (map::iterator q = m.begin(); q != m.end(); ++q) client_ranges[q->first].range = q->second; } ::decode(dirstat, p); ::decode(rstat, p); ::decode(accounted_rstat, p); ::decode(version, p); ::decode(file_data_version, p); ::decode(xattr_version, p); if (struct_v >= 2) ::decode(backtrace_version, p); if (struct_v >= 7) ::decode(old_pools, p); if (struct_v >= 8) ::decode(max_size_ever, p); if (struct_v >= 9) { ::decode(inline_version, p); ::decode(inline_data, p); } else { inline_version = CEPH_INLINE_NONE; } if (struct_v < 10) backtrace_version = 0; // force update backtrace DECODE_FINISH(p); } void inode_t::dump(Formatter *f) const { f->dump_unsigned("ino", ino); f->dump_unsigned("rdev", rdev); f->dump_stream("ctime") << ctime; f->dump_unsigned("mode", mode); f->dump_unsigned("uid", uid); f->dump_unsigned("gid", gid); f->dump_unsigned("nlink", nlink); f->dump_unsigned("anchored", (int)anchored); f->open_object_section("dir_layout"); ::dump(dir_layout, f); f->close_section(); f->open_object_section("layout"); ::dump(layout, f); f->close_section(); f->open_array_section("old_pools"); vector::const_iterator i = old_pools.begin(); while(i != old_pools.end()) { f->dump_int("pool", *i); } f->close_section(); f->dump_unsigned("size", size); f->dump_unsigned("truncate_seq", truncate_seq); f->dump_unsigned("truncate_size", truncate_size); f->dump_unsigned("truncate_from", truncate_from); f->dump_unsigned("truncate_pending", truncate_pending); f->dump_stream("mtime") << mtime; f->dump_stream("atime") << atime; f->dump_unsigned("time_warp_seq", time_warp_seq); f->open_array_section("client_ranges"); for (map::const_iterator p = client_ranges.begin(); p != client_ranges.end(); ++p) { f->open_object_section("client"); f->dump_unsigned("client", p->first.v); p->second.dump(f); f->close_section(); } f->close_section(); f->open_object_section("dirstat"); dirstat.dump(f); f->close_section(); f->open_object_section("rstat"); rstat.dump(f); f->close_section(); f->open_object_section("accounted_rstat"); accounted_rstat.dump(f); f->close_section(); f->dump_unsigned("version", version); f->dump_unsigned("file_data_version", file_data_version); f->dump_unsigned("xattr_version", xattr_version); f->dump_unsigned("backtrace_version", backtrace_version); } void inode_t::generate_test_instances(list& ls) { ls.push_back(new inode_t); ls.push_back(new inode_t); ls.back()->ino = 1; // i am lazy. } /* * old_inode_t */ void old_inode_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(first, bl); ::encode(inode, bl); ::encode(xattrs, bl); ENCODE_FINISH(bl); } void old_inode_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(first, bl); ::decode(inode, bl); ::decode(xattrs, bl); DECODE_FINISH(bl); } void old_inode_t::dump(Formatter *f) const { f->dump_unsigned("first", first); inode.dump(f); f->open_object_section("xattrs"); for (map::const_iterator p = xattrs.begin(); p != xattrs.end(); ++p) { string v(p->second.c_str(), p->second.length()); f->dump_string(p->first.c_str(), v); } f->close_section(); } void old_inode_t::generate_test_instances(list& ls) { ls.push_back(new old_inode_t); ls.push_back(new old_inode_t); ls.back()->first = 2; list ils; inode_t::generate_test_instances(ils); ls.back()->inode = *ils.back(); ls.back()->xattrs["user.foo"] = buffer::copy("asdf", 4); ls.back()->xattrs["user.unprintable"] = buffer::copy("\000\001\002", 3); } /* * fnode_t */ void fnode_t::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(version, bl); ::encode(snap_purged_thru, bl); ::encode(fragstat, bl); ::encode(accounted_fragstat, bl); ::encode(rstat, bl); ::encode(accounted_rstat, bl); ENCODE_FINISH(bl); } void fnode_t::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(version, bl); ::decode(snap_purged_thru, bl); ::decode(fragstat, bl); ::decode(accounted_fragstat, bl); ::decode(rstat, bl); ::decode(accounted_rstat, bl); DECODE_FINISH(bl); } void fnode_t::dump(Formatter *f) const { f->dump_unsigned("version", version); f->dump_unsigned("snap_purged_thru", snap_purged_thru); f->open_object_section("fragstat"); fragstat.dump(f); f->close_section(); f->open_object_section("accounted_fragstat"); accounted_fragstat.dump(f); f->close_section(); f->open_object_section("rstat"); rstat.dump(f); f->close_section(); f->open_object_section("accounted_rstat"); accounted_rstat.dump(f); f->close_section(); } void fnode_t::generate_test_instances(list& ls) { ls.push_back(new fnode_t); ls.push_back(new fnode_t); ls.back()->version = 1; ls.back()->snap_purged_thru = 2; list fls; frag_info_t::generate_test_instances(fls); ls.back()->fragstat = *fls.back(); ls.back()->accounted_fragstat = *fls.front(); list nls; nest_info_t::generate_test_instances(nls); ls.back()->rstat = *nls.front(); ls.back()->accounted_rstat = *nls.back(); } /* * old_rstat_t */ void old_rstat_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(first, bl); ::encode(rstat, bl); ::encode(accounted_rstat, bl); ENCODE_FINISH(bl); } void old_rstat_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(first, bl); ::decode(rstat, bl); ::decode(accounted_rstat, bl); DECODE_FINISH(bl); } void old_rstat_t::dump(Formatter *f) const { f->dump_unsigned("snapid", first); f->open_object_section("rstat"); rstat.dump(f); f->close_section(); f->open_object_section("accounted_rstat"); accounted_rstat.dump(f); f->close_section(); } void old_rstat_t::generate_test_instances(list& ls) { ls.push_back(new old_rstat_t()); ls.push_back(new old_rstat_t()); ls.back()->first = 12; list nls; nest_info_t::generate_test_instances(nls); ls.back()->rstat = *nls.back(); ls.back()->accounted_rstat = *nls.front(); } /* * session_info_t */ void session_info_t::encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(inst, bl); ::encode(completed_requests, bl); ::encode(prealloc_inos, bl); // hacky, see below. ::encode(used_inos, bl); ENCODE_FINISH(bl); } void session_info_t::decode(bufferlist::iterator& p) { DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, p); ::decode(inst, p); if (struct_v <= 2) { set s; ::decode(s, p); while (!s.empty()) { completed_requests[*s.begin()] = inodeno_t(); s.erase(s.begin()); } } else { ::decode(completed_requests, p); } ::decode(prealloc_inos, p); ::decode(used_inos, p); prealloc_inos.insert(used_inos); used_inos.clear(); DECODE_FINISH(p); } void session_info_t::dump(Formatter *f) const { f->dump_stream("inst") << inst; f->open_array_section("completed_requests"); for (map::const_iterator p = completed_requests.begin(); p != completed_requests.end(); ++p) { f->open_object_section("request"); f->dump_unsigned("tid", p->first); f->dump_stream("created_ino") << p->second; f->close_section(); } f->close_section(); f->open_array_section("prealloc_inos"); for (interval_set::const_iterator p = prealloc_inos.begin(); p != prealloc_inos.end(); ++p) { f->open_object_section("ino_range"); f->dump_unsigned("start", p.get_start()); f->dump_unsigned("length", p.get_len()); f->close_section(); } f->close_section(); f->open_array_section("used_inos"); for (interval_set::const_iterator p = prealloc_inos.begin(); p != prealloc_inos.end(); ++p) { f->open_object_section("ino_range"); f->dump_unsigned("start", p.get_start()); f->dump_unsigned("length", p.get_len()); f->close_section(); } f->close_section(); } void session_info_t::generate_test_instances(list& ls) { ls.push_back(new session_info_t); ls.push_back(new session_info_t); ls.back()->inst = entity_inst_t(entity_name_t::MDS(12), entity_addr_t()); ls.back()->completed_requests.insert(make_pair(234, inodeno_t(111222))); ls.back()->completed_requests.insert(make_pair(237, inodeno_t(222333))); ls.back()->prealloc_inos.insert(333, 12); ls.back()->prealloc_inos.insert(377, 112); // we can't add used inos; they're cleared on decode } /* * string_snap_t */ void string_snap_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(name, bl); ::encode(snapid, bl); ENCODE_FINISH(bl); } void string_snap_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(name, bl); ::decode(snapid, bl); DECODE_FINISH(bl); } void string_snap_t::dump(Formatter *f) const { f->dump_string("name", name); f->dump_unsigned("snapid", snapid); } void string_snap_t::generate_test_instances(list& ls) { ls.push_back(new string_snap_t); ls.push_back(new string_snap_t); ls.back()->name = "foo"; ls.back()->snapid = 123; ls.push_back(new string_snap_t); ls.back()->name = "bar"; ls.back()->snapid = 456; } /* * MDSCacheObjectInfo */ void MDSCacheObjectInfo::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(ino, bl); ::encode(dirfrag, bl); ::encode(dname, bl); ::encode(snapid, bl); ENCODE_FINISH(bl); } void MDSCacheObjectInfo::decode(bufferlist::iterator& p) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, p); ::decode(ino, p); ::decode(dirfrag, p); ::decode(dname, p); ::decode(snapid, p); DECODE_FINISH(p); } void MDSCacheObjectInfo::dump(Formatter *f) const { f->dump_unsigned("ino", ino); f->dump_stream("dirfrag") << dirfrag; f->dump_string("name", dname); f->dump_unsigned("snapid", snapid); } void MDSCacheObjectInfo::generate_test_instances(list& ls) { ls.push_back(new MDSCacheObjectInfo); ls.push_back(new MDSCacheObjectInfo); ls.back()->ino = 1; ls.back()->dirfrag = dirfrag_t(2, 3); ls.back()->dname = "fooname"; ls.back()->snapid = CEPH_NOSNAP; ls.push_back(new MDSCacheObjectInfo); ls.back()->ino = 121; ls.back()->dirfrag = dirfrag_t(222, 0); ls.back()->dname = "bar foo"; ls.back()->snapid = 21322; } /* * mds_table_pending_t */ void mds_table_pending_t::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(reqid, bl); ::encode(mds, bl); ::encode(tid, bl); ENCODE_FINISH(bl); } void mds_table_pending_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(reqid, bl); ::decode(mds, bl); ::decode(tid, bl); DECODE_FINISH(bl); } void mds_table_pending_t::dump(Formatter *f) const { f->dump_unsigned("reqid", reqid); f->dump_unsigned("mds", mds); f->dump_unsigned("tid", tid); } void mds_table_pending_t::generate_test_instances(list& ls) { ls.push_back(new mds_table_pending_t); ls.push_back(new mds_table_pending_t); ls.back()->reqid = 234; ls.back()->mds = 2; ls.back()->tid = 35434; } /* * inode_load_vec_t */ void inode_load_vec_t::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); for (int i=0; iopen_array_section("Decay Counters"); for (vector::const_iterator i = vec.begin(); i != vec.end(); ++i) { f->open_object_section("Decay Counter"); i->dump(f); f->close_section(); } f->close_section(); } void inode_load_vec_t::generate_test_instances(list& ls) { utime_t sample; ls.push_back(new inode_load_vec_t(sample)); } /* * dirfrag_load_vec_t */ void dirfrag_load_vec_t::dump(Formatter *f) const { f->open_array_section("Decay Counters"); for (vector::const_iterator i = vec.begin(); i != vec.end(); ++i) { f->open_object_section("Decay Counter"); i->dump(f); f->close_section(); } f->close_section(); } void dirfrag_load_vec_t::generate_test_instances(list& ls) { utime_t sample; ls.push_back(new dirfrag_load_vec_t(sample)); } /* * mds_load_t */ void mds_load_t::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(auth, bl); ::encode(all, bl); ::encode(req_rate, bl); ::encode(cache_hit_rate, bl); ::encode(queue_len, bl); ::encode(cpu_load_avg, bl); ENCODE_FINISH(bl); } void mds_load_t::decode(const utime_t &t, bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(auth, t, bl); ::decode(all, t, bl); ::decode(req_rate, bl); ::decode(cache_hit_rate, bl); ::decode(queue_len, bl); ::decode(cpu_load_avg, bl); DECODE_FINISH(bl); } void mds_load_t::dump(Formatter *f) const { f->dump_float("request rate", req_rate); f->dump_float("cache hit rate", cache_hit_rate); f->dump_float("queue length", queue_len); f->dump_float("cpu load", cpu_load_avg); f->open_object_section("auth dirfrag"); auth.dump(f); f->close_section(); f->open_object_section("all dirfrags"); all.dump(f); f->close_section(); } void mds_load_t::generate_test_instances(list& ls) { utime_t sample; ls.push_back(new mds_load_t(sample)); } /* * cap_reconnect_t */ void cap_reconnect_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); encode_old(bl); // extract out when something changes ENCODE_FINISH(bl); } void cap_reconnect_t::encode_old(bufferlist& bl) const { ::encode(path, bl); capinfo.flock_len = flockbl.length(); ::encode(capinfo, bl); ::encode_nohead(flockbl, bl); } void cap_reconnect_t::decode(bufferlist::iterator& bl) { DECODE_START(1, bl); decode_old(bl); // extract out when something changes DECODE_FINISH(bl); } void cap_reconnect_t::decode_old(bufferlist::iterator& bl) { ::decode(path, bl); ::decode(capinfo, bl); ::decode_nohead(capinfo.flock_len, flockbl, bl); } void cap_reconnect_t::dump(Formatter *f) const { f->dump_string("path", path); f->dump_int("cap_id", capinfo.cap_id); f->dump_string("cap wanted", ccap_string(capinfo.wanted)); f->dump_string("cap issued", ccap_string(capinfo.issued)); f->dump_int("snaprealm", capinfo.snaprealm); f->dump_int("path base ino", capinfo.pathbase); f->dump_string("has file locks", capinfo.flock_len ? "true" : "false"); } void cap_reconnect_t::generate_test_instances(list& ls) { ls.push_back(new cap_reconnect_t); ls.back()->path = "/test/path"; ls.back()->capinfo.cap_id = 1; } ceph-0.80.11/src/mds/LocalLock.h0000664000175100017510000000262612623076744020271 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOCALLOCK_H #define CEPH_LOCALLOCK_H #include "SimpleLock.h" class LocalLock : public SimpleLock { public: client_t last_wrlock_client; LocalLock(MDSCacheObject *o, LockType *t) : SimpleLock(o, t) { set_state(LOCK_LOCK); // always. } bool is_locallock() const { return true; } bool can_xlock_local() const { return !is_wrlocked() && (get_xlock_by() == 0); } bool can_wrlock() const { return !is_xlocked(); } void get_wrlock(client_t client) { assert(can_wrlock()); SimpleLock::get_wrlock(); last_wrlock_client = client; } void put_wrlock() { SimpleLock::put_wrlock(); if (get_num_wrlocks() == 0) last_wrlock_client = client_t(); } client_t get_last_wrlock_client() const { return last_wrlock_client; } virtual void print(ostream& out) const { out << "("; _print(out); if (last_wrlock_client >= 0) out << " last_client=" << last_wrlock_client; out << ")"; } }; #endif ceph-0.80.11/src/mds/Resetter.cc0000664000175100017510000000520212623076744020352 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Greg Farnum * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "mds/Resetter.h" #include "osdc/Journaler.h" #include "mds/mdstypes.h" #include "mon/MonClient.h" #include "mds/events/EResetJournal.h" int Resetter::init(int rank) { int r = MDSUtility::init(); if (r < 0) { return r; } inodeno_t ino = MDS_INO_LOG_OFFSET + rank; journaler = new Journaler(ino, mdsmap->get_metadata_pool(), CEPH_FS_ONDISK_MAGIC, objecter, 0, 0, &timer); return 0; } void Resetter::reset() { Mutex mylock("Resetter::reset::lock"); Cond cond; bool done; int r; lock.Lock(); journaler->recover(new C_SafeCond(&mylock, &cond, &done, &r)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); if (r != 0) { if (r == -ENOENT) { cerr << "journal does not exist on-disk. Did you set a bad rank?" << std::endl; shutdown(); return; } else { cerr << "got error " << r << "from Journaler, failling" << std::endl; shutdown(); return; } } lock.Lock(); uint64_t old_start = journaler->get_read_pos(); uint64_t old_end = journaler->get_write_pos(); uint64_t old_len = old_end - old_start; cout << "old journal was " << old_start << "~" << old_len << std::endl; uint64_t new_start = ROUND_UP_TO(old_end+1, journaler->get_layout_period()); cout << "new journal start will be " << new_start << " (" << (new_start - old_end) << " bytes past old end)" << std::endl; journaler->set_read_pos(new_start); journaler->set_write_pos(new_start); journaler->set_expire_pos(new_start); journaler->set_trimmed_pos(new_start); journaler->set_writeable(); cout << "writing journal head" << std::endl; journaler->write_head(new C_SafeCond(&mylock, &cond, &done, &r)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); lock.Lock(); assert(r == 0); LogEvent *le = new EResetJournal; bufferlist bl; le->encode_with_header(bl); cout << "writing EResetJournal entry" << std::endl; journaler->append_entry(bl); journaler->flush(new C_SafeCond(&mylock, &cond, &done,&r)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); assert(r == 0); cout << "done" << std::endl; } ceph-0.80.11/src/mds/Anchor.cc0000664000175100017510000000304312623076744017770 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "mds/Anchor.h" #include "common/Formatter.h" void Anchor::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(ino, bl); ::encode(dirino, bl); ::encode(dn_hash, bl); ::encode(nref, bl); ::encode(updated, bl); ENCODE_FINISH(bl); } void Anchor::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(ino, bl); ::decode(dirino, bl); ::decode(dn_hash, bl); ::decode(nref, bl); ::decode(updated, bl); DECODE_FINISH(bl); } void Anchor::dump(Formatter *f) const { f->dump_unsigned("ino", ino); f->dump_unsigned("dirino", dirino); f->dump_unsigned("dn_hash", dn_hash); f->dump_unsigned("num_ref", nref); f->dump_unsigned("updated", updated); } void Anchor::generate_test_instances(list& ls) { ls.push_back(new Anchor); ls.push_back(new Anchor); ls.back()->ino = 1; ls.back()->dirino = 2; ls.back()->dn_hash = 3; ls.back()->nref = 4; ls.back()->updated = 5; } ostream& operator<<(ostream& out, const Anchor &a) { return out << "a(" << a.ino << " " << a.dirino << "/" << a.dn_hash << " " << a.nref << " v" << a.updated << ")"; } ceph-0.80.11/src/mds/Makefile.am0000664000175100017510000000343212623076744020305 0ustar jenkins-buildjenkins-buildlibmds_la_SOURCES = \ mds/Anchor.cc \ mds/Capability.cc \ mds/Dumper.cc \ mds/Resetter.cc \ mds/MDS.cc \ mds/locks.c \ mds/journal.cc \ mds/Server.cc \ mds/Mutation.cc \ mds/MDCache.cc \ mds/Locker.cc \ mds/Migrator.cc \ mds/MDBalancer.cc \ mds/CDentry.cc \ mds/CDir.cc \ mds/CInode.cc \ mds/LogEvent.cc \ mds/MDSTable.cc \ mds/InoTable.cc \ mds/MDSTableClient.cc \ mds/MDSTableServer.cc \ mds/AnchorServer.cc \ mds/AnchorClient.cc \ mds/SnapRealm.cc \ mds/SnapServer.cc \ mds/snap.cc \ mds/SessionMap.cc \ mds/MDLog.cc \ mds/MDSUtility.cc libmds_la_LIBADD = $(LIBOSDC) noinst_LTLIBRARIES += libmds.la noinst_HEADERS += \ mds/inode_backtrace.h \ mds/flock.h \ mds/locks.c \ mds/locks.h \ mds/Anchor.h \ mds/AnchorClient.h \ mds/AnchorServer.h \ mds/CDentry.h \ mds/CDir.h \ mds/CInode.h \ mds/Capability.h \ mds/Dumper.h \ mds/InoTable.h \ mds/LocalLock.h \ mds/Locker.h \ mds/LogEvent.h \ mds/LogSegment.h \ mds/MDBalancer.h \ mds/MDCache.h \ mds/MDLog.h \ mds/MDS.h \ mds/MDSMap.h \ mds/MDSTable.h \ mds/MDSTableServer.h \ mds/MDSTableClient.h \ mds/MDSUtility.h \ mds/Mutation.h \ mds/Migrator.h \ mds/Resetter.h \ mds/ScatterLock.h \ mds/Server.h \ mds/SessionMap.h \ mds/SimpleLock.h \ mds/SnapClient.h \ mds/SnapRealm.h \ mds/SnapServer.h \ mds/inode_backtrace.h \ mds/mds_table_types.h \ mds/mdstypes.h \ mds/snap.h noinst_HEADERS += \ mds/events/ECommitted.h \ mds/events/EExport.h \ mds/events/EFragment.h \ mds/events/EImportFinish.h \ mds/events/EImportStart.h \ mds/events/EMetaBlob.h \ mds/events/EOpen.h \ mds/events/EResetJournal.h \ mds/events/ESession.h \ mds/events/ESessions.h \ mds/events/ESlaveUpdate.h \ mds/events/ESubtreeMap.h \ mds/events/ETableClient.h \ mds/events/ETableServer.h \ mds/events/EUpdate.h ceph-0.80.11/src/mds/Dumper.h0000664000175100017510000000220112623076744017647 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Greg Farnum * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef JOURNAL_DUMPER_H_ #define JOURNAL_DUMPER_H_ #include "mds/MDSUtility.h" #include "osdc/Journaler.h" /** * This class lets you dump out an mds journal for troubleshooting or whatever. * * It was built to work with cmds so some of the design choices are random. * To use, create a Dumper, call init(), and then call dump() with the name * of the file to dump to. */ class Dumper : public MDSUtility { private: Journaler *journaler; int rank; public: Dumper() : journaler(NULL), rank(-1) {} void handle_mds_map(MMDSMap* m); int init(int rank); int recover_journal(); void dump(const char *dumpfile); void undump(const char *dumpfile); void dump_entries(); }; #endif /* JOURNAL_DUMPER_H_ */ ceph-0.80.11/src/mds/SessionMap.h0000664000175100017510000002517712623076744020515 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_SESSIONMAP_H #define CEPH_MDS_SESSIONMAP_H #include using std::set; #include "include/unordered_map.h" #include "include/Context.h" #include "include/xlist.h" #include "include/elist.h" #include "include/interval_set.h" #include "mdstypes.h" class CInode; struct MDRequestImpl; #include "CInode.h" #include "Capability.h" #include "msg/Message.h" /* * session */ class Session : public RefCountedObject { // -- state etc -- public: /* <-- closed <------------+ ^ | | | v | killing <-- opening <----+ | ^ | | | | v | | stale <--> open --> closing ---+ + additional dimension of 'importing' (with counter) */ enum { STATE_CLOSED = 0, STATE_OPENING = 1, // journaling open STATE_OPEN = 2, STATE_CLOSING = 3, // journaling close STATE_STALE = 4, STATE_KILLING = 5 }; const char *get_state_name(int s) { switch (s) { case STATE_CLOSED: return "closed"; case STATE_OPENING: return "opening"; case STATE_OPEN: return "open"; case STATE_CLOSING: return "closing"; case STATE_STALE: return "stale"; case STATE_KILLING: return "killing"; default: return "???"; } } private: int state; uint64_t state_seq; int importing_count; friend class SessionMap; public: session_info_t info; ///< durable bits ConnectionRef connection; xlist::item item_session_list; list preopen_out_queue; ///< messages for client, queued before they connect elist requests; interval_set pending_prealloc_inos; // journaling prealloc, will be added to prealloc_inos inodeno_t next_ino() { if (info.prealloc_inos.empty()) return 0; return info.prealloc_inos.range_start(); } inodeno_t take_ino(inodeno_t ino = 0) { assert(!info.prealloc_inos.empty()); if (ino) { if (info.prealloc_inos.contains(ino)) info.prealloc_inos.erase(ino); else ino = 0; } if (!ino) { ino = info.prealloc_inos.range_start(); info.prealloc_inos.erase(ino); } info.used_inos.insert(ino, 1); return ino; } int get_num_projected_prealloc_inos() { return info.prealloc_inos.size() + pending_prealloc_inos.size(); } client_t get_client() { return info.get_client(); } int get_state() { return state; } const char *get_state_name() { return get_state_name(state); } uint64_t get_state_seq() { return state_seq; } bool is_closed() { return state == STATE_CLOSED; } bool is_opening() { return state == STATE_OPENING; } bool is_open() { return state == STATE_OPEN; } bool is_closing() { return state == STATE_CLOSING; } bool is_stale() { return state == STATE_STALE; } bool is_killing() { return state == STATE_KILLING; } void inc_importing() { ++importing_count; } void dec_importing() { assert(importing_count); --importing_count; } bool is_importing() { return importing_count > 0; } // -- caps -- private: version_t cap_push_seq; // cap push seq # map > waitfor_flush; // flush session messages public: xlist caps; // inodes with caps; front=most recently used xlist leases; // metadata leases to clients utime_t last_cap_renew; public: version_t inc_push_seq() { return ++cap_push_seq; } version_t get_push_seq() const { return cap_push_seq; } version_t wait_for_flush(Context* c) { waitfor_flush[get_push_seq()].push_back(c); return get_push_seq(); } void finish_flush(version_t seq, list& ls) { while (!waitfor_flush.empty()) { if (waitfor_flush.begin()->first > seq) break; ls.splice(ls.end(), waitfor_flush.begin()->second); waitfor_flush.erase(waitfor_flush.begin()); } } void add_cap(Capability *cap) { caps.push_back(&cap->item_session_caps); } void touch_lease(ClientLease *r) { leases.push_back(&r->item_session_lease); } // -- leases -- uint32_t lease_seq; // -- completed requests -- private: public: void add_completed_request(ceph_tid_t t, inodeno_t created) { info.completed_requests[t] = created; } void trim_completed_requests(ceph_tid_t mintid) { // trim while (!info.completed_requests.empty() && (mintid == 0 || info.completed_requests.begin()->first < mintid)) info.completed_requests.erase(info.completed_requests.begin()); } bool have_completed_request(ceph_tid_t tid, inodeno_t *pcreated) const { map::const_iterator p = info.completed_requests.find(tid); if (p == info.completed_requests.end()) return false; if (pcreated) *pcreated = p->second; return true; } Session() : state(STATE_CLOSED), state_seq(0), importing_count(0), connection(NULL), item_session_list(this), requests(0), // member_offset passed to front() manually cap_push_seq(0), lease_seq(0) { } ~Session() { assert(!item_session_list.is_on_list()); while (!preopen_out_queue.empty()) { preopen_out_queue.front()->put(); preopen_out_queue.pop_front(); } } void clear() { pending_prealloc_inos.clear(); info.clear_meta(); cap_push_seq = 0; last_cap_renew = utime_t(); } }; /* * session map */ class MDS; class SessionMap { private: MDS *mds; ceph::unordered_map session_map; public: map* > by_state; public: // i am lazy version_t version, projected, committing, committed; map > commit_waiters; public: SessionMap(MDS *m) : mds(m), version(0), projected(0), committing(0), committed(0) { } //for the dencoder SessionMap() : mds(NULL), version(0), projected(0), committing(0), committed(0) {} // sessions bool empty() { return session_map.empty(); } bool is_any_state(int state) { map* >::iterator p = by_state.find(state); if (p == by_state.end() || p->second->empty()) return false; return true; } bool have_unclosed_sessions() { return is_any_state(Session::STATE_OPENING) || is_any_state(Session::STATE_OPENING) || is_any_state(Session::STATE_OPEN) || is_any_state(Session::STATE_CLOSING) || is_any_state(Session::STATE_STALE) || is_any_state(Session::STATE_KILLING); } bool have_session(entity_name_t w) { return session_map.count(w); } Session* get_session(entity_name_t w) { if (session_map.count(w)) return session_map[w]; return 0; } Session* get_or_add_session(const entity_inst_t& i) { Session *s; if (session_map.count(i.name)) { s = session_map[i.name]; } else { s = session_map[i.name] = new Session; s->info.inst = i; s->last_cap_renew = ceph_clock_now(g_ceph_context); } return s; } void add_session(Session *s) { assert(session_map.count(s->info.inst.name) == 0); session_map[s->info.inst.name] = s; if (by_state.count(s->state) == 0) by_state[s->state] = new xlist; by_state[s->state]->push_back(&s->item_session_list); s->get(); } void remove_session(Session *s) { s->trim_completed_requests(0); s->item_session_list.remove_myself(); session_map.erase(s->info.inst.name); s->put(); } void touch_session(Session *session) { if (session->item_session_list.is_on_list()) { if (by_state.count(session->state) == 0) by_state[session->state] = new xlist; by_state[session->state]->push_back(&session->item_session_list); session->last_cap_renew = ceph_clock_now(g_ceph_context); } else { assert(0); // hrm, should happen? } } Session *get_oldest_session(int state) { if (by_state.count(state) == 0 || by_state[state]->empty()) return 0; return by_state[state]->front(); } uint64_t set_state(Session *session, int s) { if (session->state != s) { session->state = s; session->state_seq++; if (by_state.count(s) == 0) by_state[s] = new xlist; by_state[s]->push_back(&session->item_session_list); } return session->state_seq; } void dump(); void get_client_set(set& s) { for (ceph::unordered_map::iterator p = session_map.begin(); p != session_map.end(); ++p) if (p->second->info.inst.name.is_client()) s.insert(p->second->info.inst.name.num()); } void get_client_session_set(set& s) { for (ceph::unordered_map::iterator p = session_map.begin(); p != session_map.end(); ++p) if (p->second->info.inst.name.is_client()) s.insert(p->second); } void open_sessions(map& client_map) { for (map::iterator p = client_map.begin(); p != client_map.end(); ++p) { Session *s = get_or_add_session(p->second); set_state(s, Session::STATE_OPEN); } version++; } // helpers entity_inst_t& get_inst(entity_name_t w) { assert(session_map.count(w)); return session_map[w]->info.inst; } version_t inc_push_seq(client_t client) { return get_session(entity_name_t::CLIENT(client.v))->inc_push_seq(); } version_t get_push_seq(client_t client) { return get_session(entity_name_t::CLIENT(client.v))->get_push_seq(); } bool have_completed_request(metareqid_t rid) { Session *session = get_session(rid.name); return session && session->have_completed_request(rid.tid, NULL); } void trim_completed_requests(entity_name_t c, ceph_tid_t tid) { Session *session = get_session(c); assert(session); session->trim_completed_requests(tid); } void wipe(); void wipe_ino_prealloc(); // -- loading, saving -- inodeno_t ino; list waiting_for_load; void encode(bufferlist& bl) const; void decode(bufferlist::iterator& blp); void dump(Formatter *f) const; static void generate_test_instances(list& ls); object_t get_object_name(); void load(Context *onload); void _load_finish(int r, bufferlist &bl); void save(Context *onsave, version_t needv=0); void _save_finish(version_t v); }; #endif ceph-0.80.11/src/mds/MDBalancer.h0000664000175100017510000000575112623076744020360 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDBALANCER_H #define CEPH_MDBALANCER_H #include #include using std::list; using std::map; #include "include/types.h" #include "common/Clock.h" #include "CInode.h" class MDS; class Message; class MHeartbeat; class CInode; class Context; class CDir; class MDBalancer { protected: MDS *mds; int beat_epoch; int last_epoch_under; int last_epoch_over; utime_t last_heartbeat; utime_t last_fragment; utime_t last_sample; utime_t rebalance_time; //ensure a consistent view of load for rebalance // todo set split_queue, merge_queue; // per-epoch scatter/gathered info map mds_load; map mds_meta_load; map > mds_import_map; // per-epoch state double my_load, target_load; map my_targets; map imported; map exported; map old_prev_targets; // # iterations they _haven't_ been targets bool check_targets(); double try_match(int ex, double& maxex, int im, double& maxim); double get_maxim(int im) { return target_load - mds_meta_load[im] - imported[im]; } double get_maxex(int ex) { return mds_meta_load[ex] - target_load - exported[ex]; } public: MDBalancer(MDS *m) : mds(m), beat_epoch(0), last_epoch_under(0), last_epoch_over(0), my_load(0.0), target_load(0.0) { } mds_load_t get_load(utime_t); int proc_message(Message *m); void send_heartbeat(); void handle_heartbeat(MHeartbeat *m); void tick(); void do_fragmenting(); void export_empties(); //set up the rebalancing targets for export and do one if the //MDSMap is up to date void prep_rebalance(int beat); /*check if the monitor has recorded the current export targets; if it has then do the actual export. Otherwise send off our export targets message again*/ void try_rebalance(); void find_exports(CDir *dir, double amount, list& exports, double& have, set& already_exporting); void subtract_export(class CDir *ex, utime_t now); void add_import(class CDir *im, utime_t now); void hit_inode(utime_t now, class CInode *in, int type, int who=-1); void hit_dir(utime_t now, class CDir *dir, int type, int who=-1, double amount=1.0); void hit_recursive(utime_t now, class CDir *dir, int type, double amount, double rd_adj); void show_imports(bool external=false); void queue_split(CDir *dir); void queue_merge(CDir *dir); }; #endif ceph-0.80.11/src/mds/AnchorClient.h0000664000175100017510000000243312623076744020773 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_ANCHORCLIENT_H #define CEPH_ANCHORCLIENT_H #include "MDSTableClient.h" #include "Anchor.h" class Context; class MDS; class LogSegment; class AnchorClient : public MDSTableClient { // lookups struct _pending_lookup { vector *trace; Context *onfinish; }; map > pending_lookup; public: AnchorClient(MDS *m) : MDSTableClient(m, TABLE_ANCHOR) {} void handle_query_result(MMDSTableRequest *m); void lookup(inodeno_t ino, vector& trace, Context *onfinish); void _lookup(inodeno_t ino); void resend_queries(); void prepare_create(inodeno_t ino, vector& trace, version_t *atid, Context *onfinish); void prepare_destroy(inodeno_t ino, version_t *atid, Context *onfinish); void prepare_update(inodeno_t ino, vector& trace, version_t *atid, Context *onfinish); }; #endif ceph-0.80.11/src/mds/MDSTable.cc0000664000175100017510000000725012623076744020155 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDSTable.h" #include "MDS.h" #include "MDLog.h" #include "osdc/Filer.h" #include "include/types.h" #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << (mds ? mds->get_nodeid() : -1) << "." << table_name << ": " class C_MT_Save : public Context { MDSTable *ida; version_t version; public: C_MT_Save(MDSTable *i, version_t v) : ida(i), version(v) {} void finish(int r) { ida->save_2(r, version); } }; void MDSTable::save(Context *onfinish, version_t v) { if (v > 0 && v <= committing_version) { dout(10) << "save v " << version << " - already saving " << committing_version << " >= needed " << v << dendl; waitfor_save[v].push_back(onfinish); return; } dout(10) << "save v " << version << dendl; assert(is_active()); bufferlist bl; ::encode(version, bl); encode_state(bl); committing_version = version; if (onfinish) waitfor_save[version].push_back(onfinish); // write (async) SnapContext snapc; object_t oid = get_object_name(); object_locator_t oloc(mds->mdsmap->get_metadata_pool()); mds->objecter->write_full(oid, oloc, snapc, bl, ceph_clock_now(g_ceph_context), 0, NULL, new C_MT_Save(this, version)); } void MDSTable::save_2(int r, version_t v) { dout(10) << "save_2 v " << v << dendl; if (r == -EBLACKLISTED) { mds->suicide(); return; } if (r < 0) { dout(10) << "save_2 could not write table: " << r << dendl; assert(r >= 0); } assert(r >= 0); committed_version = v; list ls; while (!waitfor_save.empty()) { if (waitfor_save.begin()->first > v) break; ls.splice(ls.end(), waitfor_save.begin()->second); waitfor_save.erase(waitfor_save.begin()); } finish_contexts(g_ceph_context, ls,0); } void MDSTable::reset() { reset_state(); state = STATE_ACTIVE; } // ----------------------- class C_MT_Load : public Context { public: MDSTable *ida; Context *onfinish; bufferlist bl; C_MT_Load(MDSTable *i, Context *o) : ida(i), onfinish(o) {} void finish(int r) { ida->load_2(r, bl, onfinish); } }; object_t MDSTable::get_object_name() { char n[50]; if (per_mds) snprintf(n, sizeof(n), "mds%d_%s", mds->whoami, table_name); else snprintf(n, sizeof(n), "mds_%s", table_name); return object_t(n); } void MDSTable::load(Context *onfinish) { dout(10) << "load" << dendl; assert(is_undef()); state = STATE_OPENING; C_MT_Load *c = new C_MT_Load(this, onfinish); object_t oid = get_object_name(); object_locator_t oloc(mds->mdsmap->get_metadata_pool()); mds->objecter->read_full(oid, oloc, CEPH_NOSNAP, &c->bl, 0, c); } void MDSTable::load_2(int r, bufferlist& bl, Context *onfinish) { assert(is_opening()); state = STATE_ACTIVE; if (r == -EBLACKLISTED) { mds->suicide(); return; } if (r < 0) { derr << "load_2 could not read table: " << r << dendl; assert(r >= 0); } dout(10) << "load_2 got " << bl.length() << " bytes" << dendl; bufferlist::iterator p = bl.begin(); ::decode(version, p); projected_version = committed_version = version; dout(10) << "load_2 loaded v" << version << dendl; decode_state(p); if (onfinish) { onfinish->complete(0); } } ceph-0.80.11/src/mds/Mutation.h0000664000175100017510000002241512623076744020224 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDS_MUTATION_H #define CEPH_MDS_MUTATION_H #include "include/interval_set.h" #include "include/elist.h" #include "mdstypes.h" #include "SimpleLock.h" #include "Capability.h" class LogSegment; class Capability; class CInode; class CDir; class CDentry; class Session; class ScatterLock; class MClientRequest; class MMDSSlaveRequest; struct MutationImpl { metareqid_t reqid; __u32 attempt; // which attempt for this request LogSegment *ls; // the log segment i'm committing to utime_t now; // flag mutation as slave int slave_to_mds; // this is a slave request if >= 0. // -- my pins and locks -- // cache pins (so things don't expire) set< MDSCacheObject* > pins; set stickydirs; // auth pins set< MDSCacheObject* > remote_auth_pins; set< MDSCacheObject* > auth_pins; // held locks set< SimpleLock* > rdlocks; // always local. set< SimpleLock* > wrlocks; // always local. map< SimpleLock*, int > remote_wrlocks; set< SimpleLock* > xlocks; // local or remote. set< SimpleLock*, SimpleLock::ptr_lt > locks; // full ordering // lock we are currently trying to acquire. if we give up for some reason, // be sure to eval() this. SimpleLock *locking; int locking_target_mds; // if this flag is set, do not attempt to acquire further locks. // (useful for wrlock, which may be a moving auth target) bool done_locking; bool committing; bool aborted; bool killed; // for applying projected inode changes list projected_inodes; list projected_fnodes; list updated_locks; list dirty_cow_inodes; list > dirty_cow_dentries; MutationImpl() : attempt(0), ls(0), slave_to_mds(-1), locking(NULL), locking_target_mds(-1), done_locking(false), committing(false), aborted(false), killed(false) { } MutationImpl(metareqid_t ri, __u32 att=0, int slave_to=-1) : reqid(ri), attempt(att), ls(0), slave_to_mds(slave_to), locking(NULL), locking_target_mds(-1), done_locking(false), committing(false), aborted(false), killed(false) { } virtual ~MutationImpl() { assert(locking == NULL); assert(pins.empty()); assert(auth_pins.empty()); assert(xlocks.empty()); assert(rdlocks.empty()); assert(wrlocks.empty()); assert(remote_wrlocks.empty()); } bool is_master() { return slave_to_mds < 0; } bool is_slave() { return slave_to_mds >= 0; } client_t get_client() { if (reqid.name.is_client()) return client_t(reqid.name.num()); return -1; } // pin items in cache void pin(MDSCacheObject *o); void unpin(MDSCacheObject *o); void set_stickydirs(CInode *in); void drop_pins(); void start_locking(SimpleLock *lock, int target=-1); void finish_locking(SimpleLock *lock); // auth pins bool is_auth_pinned(MDSCacheObject *object); void auth_pin(MDSCacheObject *object); void auth_unpin(MDSCacheObject *object); void drop_local_auth_pins(); void add_projected_inode(CInode *in); void pop_and_dirty_projected_inodes(); void add_projected_fnode(CDir *dir); void pop_and_dirty_projected_fnodes(); void add_updated_lock(ScatterLock *lock); void add_cow_inode(CInode *in); void add_cow_dentry(CDentry *dn); void apply(); void cleanup(); virtual void print(ostream &out) { out << "mutation(" << this << ")"; } }; inline ostream& operator<<(ostream& out, MutationImpl &mut) { mut.print(out); return out; } typedef ceph::shared_ptr MutationRef; /** active_request_t * state we track for requests we are currently processing. * mostly information about locks held, so that we can drop them all * the request is finished or forwarded. see request_*(). */ struct MDRequestImpl : public MutationImpl { Session *session; elist::item item_session_request; // if not on list, op is aborted. // -- i am a client (master) request MClientRequest *client_request; // client request (if any) // store up to two sets of dn vectors, inode pointers, for request path1 and path2. vector dn[2]; CDentry *straydn; CInode *in[2]; snapid_t snapid; CInode *tracei; CDentry *tracedn; inodeno_t alloc_ino, used_prealloc_ino; interval_set prealloc_inos; int snap_caps; bool did_early_reply; bool o_trunc; ///< request is an O_TRUNC mutation int getattr_caps; ///< caps requested by getattr bufferlist reply_extra_bl; // inos we did a embedded cap release on, and may need to eval if we haven't since reissued map cap_releases; // -- i am a slave request MMDSSlaveRequest *slave_request; // slave request (if one is pending; implies slave == true) // -- i am an internal op int internal_op; // indicates how may retries of request have been made int retry; // indicator for vxattr osdmap update bool waited_for_osdmap; // break rarely-used fields into a separately allocated structure // to save memory for most ops struct More { set slaves; // mds nodes that have slave requests to me (implies client_request) set waiting_on_slave; // peers i'm waiting for slavereq replies from. // for rename/link/unlink set witnessed; // nodes who have journaled a RenamePrepare map pvmap; // for rename set extra_witnesses; // replica list from srcdn auth (rename) int srcdn_auth_mds; version_t src_reanchor_atid; // src->dst version_t dst_reanchor_atid; // dst->stray bufferlist inode_import; version_t inode_import_v; CInode* rename_inode; bool is_freeze_authpin; bool is_ambiguous_auth; bool is_remote_frozen_authpin; bool is_inode_exporter; map imported_client_map; map sseq_map; map > cap_imports; // for lock/flock bool flock_was_waiting; // for snaps version_t stid; bufferlist snapidbl; // called when slave commits or aborts Context *slave_commit; bufferlist rollback_bl; list waiting_for_finish; // export & fragment CDir* export_dir; dirfrag_t fragment_base; More() : srcdn_auth_mds(-1), src_reanchor_atid(0), dst_reanchor_atid(0), inode_import_v(0), rename_inode(0), is_freeze_authpin(false), is_ambiguous_auth(false), is_remote_frozen_authpin(false), is_inode_exporter(false), flock_was_waiting(false), stid(0), slave_commit(0), export_dir(NULL) { } } *_more; // --------------------------------------------------- MDRequestImpl() : session(0), item_session_request(this), client_request(0), straydn(NULL), snapid(CEPH_NOSNAP), tracei(0), tracedn(0), alloc_ino(0), used_prealloc_ino(0), snap_caps(0), did_early_reply(false), o_trunc(false), getattr_caps(0), slave_request(0), internal_op(-1), retry(0), waited_for_osdmap(false), _more(0) { in[0] = in[1] = 0; } MDRequestImpl(metareqid_t ri, __u32 attempt, MClientRequest *req) : MutationImpl(ri, attempt), session(0), item_session_request(this), client_request(req), straydn(NULL), snapid(CEPH_NOSNAP), tracei(0), tracedn(0), alloc_ino(0), used_prealloc_ino(0), snap_caps(0), did_early_reply(false), o_trunc(false), getattr_caps(0), slave_request(0), internal_op(-1), retry(0), waited_for_osdmap(false), _more(0) { in[0] = in[1] = 0; } MDRequestImpl(metareqid_t ri, __u32 attempt, int by) : MutationImpl(ri, attempt, by), session(0), item_session_request(this), client_request(0), straydn(NULL), snapid(CEPH_NOSNAP), tracei(0), tracedn(0), alloc_ino(0), used_prealloc_ino(0), snap_caps(0), did_early_reply(false), o_trunc(false), getattr_caps(0), slave_request(0), internal_op(-1), retry(0), waited_for_osdmap(false), _more(0) { in[0] = in[1] = 0; } ~MDRequestImpl(); More* more(); bool has_more(); bool are_slaves(); bool slave_did_prepare(); bool did_ino_allocation(); bool freeze_auth_pin(CInode *inode); void unfreeze_auth_pin(bool clear_inode=false); void set_remote_frozen_auth_pin(CInode *inode); bool can_auth_pin(MDSCacheObject *object); void drop_local_auth_pins(); void set_ambiguous_auth(CInode *inode); void clear_ambiguous_auth(); void print(ostream &out); }; typedef ceph::shared_ptr MDRequestRef; struct MDSlaveUpdate { int origop; bufferlist rollback; elist::item item; Context *waiter; set olddirs; set unlinked; MDSlaveUpdate(int oo, bufferlist &rbl, elist &list) : origop(oo), item(this), waiter(0) { rollback.claim(rbl); list.push_back(&item); } ~MDSlaveUpdate() { item.remove_myself(); if (waiter) waiter->complete(0); } }; #endif ceph-0.80.11/src/mds/Capability.cc0000664000175100017510000001137612623076744020647 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Capability.h" #include "common/Formatter.h" /* * Capability::Export */ void Capability::Export::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(cap_id, bl); ::encode(wanted, bl); ::encode(issued, bl); ::encode(pending, bl); ::encode(client_follows, bl); ::encode(seq, bl); ::encode(mseq, bl); ::encode(last_issue_stamp, bl); ENCODE_FINISH(bl); } void Capability::Export::decode(bufferlist::iterator &p) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, p); ::decode(cap_id, p); ::decode(wanted, p); ::decode(issued, p); ::decode(pending, p); ::decode(client_follows, p); ::decode(seq, p); ::decode(mseq, p); ::decode(last_issue_stamp, p); DECODE_FINISH(p); } void Capability::Export::dump(Formatter *f) const { f->dump_unsigned("cap_id", cap_id); f->dump_unsigned("wanted", wanted); f->dump_unsigned("issued", issued); f->dump_unsigned("pending", pending); f->dump_unsigned("client_follows", client_follows); f->dump_unsigned("seq", seq); f->dump_unsigned("migrate_seq", mseq); f->dump_stream("last_issue_stamp") << last_issue_stamp; } void Capability::Export::generate_test_instances(list& ls) { ls.push_back(new Export); ls.push_back(new Export); ls.back()->wanted = 1; ls.back()->issued = 2; ls.back()->pending = 3; ls.back()->client_follows = 4; ls.back()->mseq = 5; ls.back()->last_issue_stamp = utime_t(6, 7); } void Capability::Import::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(cap_id, bl); ::encode(issue_seq, bl); ::encode(mseq, bl); ENCODE_FINISH(bl); } void Capability::Import::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(cap_id, bl); ::decode(issue_seq, bl); ::decode(mseq, bl); DECODE_FINISH(bl); } void Capability::Import::dump(Formatter *f) const { f->dump_unsigned("cap_id", cap_id); f->dump_unsigned("issue_seq", issue_seq); f->dump_unsigned("migrate_seq", mseq); } /* * Capability::revoke_info */ void Capability::revoke_info::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl) ::encode(before, bl); ::encode(seq, bl); ::encode(last_issue, bl); ENCODE_FINISH(bl); } void Capability::revoke_info::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(before, bl); ::decode(seq, bl); ::decode(last_issue, bl); DECODE_FINISH(bl); } void Capability::revoke_info::dump(Formatter *f) const { f->dump_unsigned("before", before); f->dump_unsigned("seq", seq); f->dump_unsigned("last_issue", last_issue); } void Capability::revoke_info::generate_test_instances(list& ls) { ls.push_back(new revoke_info); ls.push_back(new revoke_info); ls.back()->before = 1; ls.back()->seq = 2; ls.back()->last_issue = 3; } /* * Capability */ void Capability::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl) ::encode(last_sent, bl); ::encode(last_issue_stamp, bl); ::encode(_wanted, bl); ::encode(_pending, bl); ::encode(_revokes, bl); ENCODE_FINISH(bl); } void Capability::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl) ::decode(last_sent, bl); ::decode(last_issue_stamp, bl); ::decode(_wanted, bl); ::decode(_pending, bl); ::decode(_revokes, bl); DECODE_FINISH(bl); _calc_issued(); } void Capability::dump(Formatter *f) const { f->dump_unsigned("last_sent", last_sent); f->dump_unsigned("last_issue_stamp", last_issue_stamp); f->dump_unsigned("wanted", _wanted); f->dump_unsigned("pending", _pending); f->open_array_section("revokes"); for (list::const_iterator p = _revokes.begin(); p != _revokes.end(); ++p) { f->open_object_section("revoke"); p->dump(f); f->close_section(); } f->close_section(); } void Capability::generate_test_instances(list& ls) { ls.push_back(new Capability); ls.push_back(new Capability); ls.back()->last_sent = 11; ls.back()->last_issue_stamp = utime_t(12, 13); ls.back()->_wanted = 14; ls.back()->_pending = 15; ls.back()->_revokes.push_back(revoke_info()); ls.back()->_revokes.back().before = 16; ls.back()->_revokes.back().seq = 17; ls.back()->_revokes.back().last_issue = 18; ls.back()->_revokes.push_back(revoke_info()); ls.back()->_revokes.back().before = 19; ls.back()->_revokes.back().seq = 20; ls.back()->_revokes.back().last_issue = 21; } ceph-0.80.11/src/mds/journal.cc0000664000175100017510000024011012623076744020226 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/config.h" #include "osdc/Journaler.h" #include "events/ESubtreeMap.h" #include "events/ESession.h" #include "events/ESessions.h" #include "events/EMetaBlob.h" #include "events/EResetJournal.h" #include "events/EUpdate.h" #include "events/ESlaveUpdate.h" #include "events/EOpen.h" #include "events/ECommitted.h" #include "events/EExport.h" #include "events/EImportStart.h" #include "events/EImportFinish.h" #include "events/EFragment.h" #include "events/ETableClient.h" #include "events/ETableServer.h" #include "include/stringify.h" #include "LogSegment.h" #include "MDS.h" #include "MDLog.h" #include "MDCache.h" #include "Server.h" #include "Migrator.h" #include "Mutation.h" #include "InoTable.h" #include "MDSTableClient.h" #include "MDSTableServer.h" #include "Locker.h" #define dout_subsys ceph_subsys_mds #undef DOUT_COND #define DOUT_COND(cct, l) (l<=cct->_conf->debug_mds || l <= cct->_conf->debug_mds_log \ || l <= cct->_conf->debug_mds_log_expire) #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".journal " // ----------------------- // LogSegment void LogSegment::try_to_expire(MDS *mds, C_GatherBuilder &gather_bld, int op_prio) { set commit; dout(6) << "LogSegment(" << offset << ").try_to_expire" << dendl; assert(g_conf->mds_kill_journal_expire_at != 1); // commit dirs for (elist::iterator p = new_dirfrags.begin(); !p.end(); ++p) { dout(20) << " new_dirfrag " << **p << dendl; assert((*p)->is_auth()); commit.insert(*p); } for (elist::iterator p = dirty_dirfrags.begin(); !p.end(); ++p) { dout(20) << " dirty_dirfrag " << **p << dendl; assert((*p)->is_auth()); commit.insert(*p); } for (elist::iterator p = dirty_dentries.begin(); !p.end(); ++p) { dout(20) << " dirty_dentry " << **p << dendl; assert((*p)->is_auth()); commit.insert((*p)->get_dir()); } for (elist::iterator p = dirty_inodes.begin(); !p.end(); ++p) { dout(20) << " dirty_inode " << **p << dendl; assert((*p)->is_auth()); if ((*p)->is_base()) { (*p)->store(gather_bld.new_sub()); } else commit.insert((*p)->get_parent_dn()->get_dir()); } if (!commit.empty()) { for (set::iterator p = commit.begin(); p != commit.end(); ++p) { CDir *dir = *p; assert(dir->is_auth()); if (dir->can_auth_pin()) { dout(15) << "try_to_expire committing " << *dir << dendl; dir->commit(0, gather_bld.new_sub(), false, op_prio); } else { dout(15) << "try_to_expire waiting for unfreeze on " << *dir << dendl; dir->add_waiter(CDir::WAIT_UNFREEZE, gather_bld.new_sub()); } } } // master ops with possibly uncommitted slaves for (set::iterator p = uncommitted_masters.begin(); p != uncommitted_masters.end(); ++p) { dout(10) << "try_to_expire waiting for slaves to ack commit on " << *p << dendl; mds->mdcache->wait_for_uncommitted_master(*p, gather_bld.new_sub()); } // uncommitted fragments for (set::iterator p = uncommitted_fragments.begin(); p != uncommitted_fragments.end(); ++p) { dout(10) << "try_to_expire waiting for uncommitted fragment " << *p << dendl; mds->mdcache->wait_for_uncommitted_fragment(*p, gather_bld.new_sub()); } // nudge scatterlocks for (elist::iterator p = dirty_dirfrag_dir.begin(); !p.end(); ++p) { CInode *in = *p; dout(10) << "try_to_expire waiting for dirlock flush on " << *in << dendl; mds->locker->scatter_nudge(&in->filelock, gather_bld.new_sub()); } for (elist::iterator p = dirty_dirfrag_dirfragtree.begin(); !p.end(); ++p) { CInode *in = *p; dout(10) << "try_to_expire waiting for dirfragtreelock flush on " << *in << dendl; mds->locker->scatter_nudge(&in->dirfragtreelock, gather_bld.new_sub()); } for (elist::iterator p = dirty_dirfrag_nest.begin(); !p.end(); ++p) { CInode *in = *p; dout(10) << "try_to_expire waiting for nest flush on " << *in << dendl; mds->locker->scatter_nudge(&in->nestlock, gather_bld.new_sub()); } assert(g_conf->mds_kill_journal_expire_at != 2); // open files if (!open_files.empty()) { assert(!mds->mdlog->is_capped()); // hmm FIXME EOpen *le = 0; LogSegment *ls = mds->mdlog->get_current_segment(); assert(ls != this); elist::iterator p = open_files.begin(member_offset(CInode, item_open_file)); while (!p.end()) { CInode *in = *p; assert(in->last == CEPH_NOSNAP); ++p; if (in->is_auth() && !in->is_ambiguous_auth() && in->is_any_caps()) { if (in->is_any_caps_wanted()) { dout(20) << "try_to_expire requeueing open file " << *in << dendl; if (!le) { le = new EOpen(mds->mdlog); mds->mdlog->start_entry(le); } le->add_clean_inode(in); ls->open_files.push_back(&in->item_open_file); } else { // drop inodes that aren't wanted dout(20) << "try_to_expire not requeueing and delisting unwanted file " << *in << dendl; in->item_open_file.remove_myself(); } } else { /* * we can get a capless inode here if we replay an open file, the client fails to * reconnect it, but does REPLAY an open request (that adds it to the logseg). AFAICS * it's ok for the client to replay an open on a file it doesn't have in it's cache * anymore. * * this makes the mds less sensitive to strict open_file consistency, although it does * make it easier to miss subtle problems. */ dout(20) << "try_to_expire not requeueing and delisting capless file " << *in << dendl; in->item_open_file.remove_myself(); } } if (le) { mds->mdlog->submit_entry(le, gather_bld.new_sub()); dout(10) << "try_to_expire waiting for open files to rejournal" << dendl; } } assert(g_conf->mds_kill_journal_expire_at != 3); // backtraces to be stored/updated for (elist::iterator p = dirty_parent_inodes.begin(); !p.end(); ++p) { CInode *in = *p; assert(in->is_auth()); if (in->can_auth_pin()) { dout(15) << "try_to_expire waiting for storing backtrace on " << *in << dendl; in->store_backtrace(gather_bld.new_sub()); } else { dout(15) << "try_to_expire waiting for unfreeze on " << *in << dendl; in->add_waiter(CInode::WAIT_UNFREEZE, gather_bld.new_sub()); } } assert(g_conf->mds_kill_journal_expire_at != 4); // slave updates for (elist::iterator p = slave_updates.begin(member_offset(MDSlaveUpdate, item)); !p.end(); ++p) { MDSlaveUpdate *su = *p; dout(10) << "try_to_expire waiting on slave update " << su << dendl; assert(su->waiter == 0); su->waiter = gather_bld.new_sub(); } // idalloc if (inotablev > mds->inotable->get_committed_version()) { dout(10) << "try_to_expire saving inotable table, need " << inotablev << ", committed is " << mds->inotable->get_committed_version() << " (" << mds->inotable->get_committing_version() << ")" << dendl; mds->inotable->save(gather_bld.new_sub(), inotablev); } // sessionmap if (sessionmapv > mds->sessionmap.committed) { dout(10) << "try_to_expire saving sessionmap, need " << sessionmapv << ", committed is " << mds->sessionmap.committed << " (" << mds->sessionmap.committing << ")" << dendl; mds->sessionmap.save(gather_bld.new_sub(), sessionmapv); } // pending commit atids for (map >::iterator p = pending_commit_tids.begin(); p != pending_commit_tids.end(); ++p) { MDSTableClient *client = mds->get_table_client(p->first); for (ceph::unordered_set::iterator q = p->second.begin(); q != p->second.end(); ++q) { dout(10) << "try_to_expire " << get_mdstable_name(p->first) << " transaction " << *q << " pending commit (not yet acked), waiting" << dendl; assert(!client->has_committed(*q)); client->wait_for_ack(*q, gather_bld.new_sub()); } } // table servers for (map::iterator p = tablev.begin(); p != tablev.end(); ++p) { MDSTableServer *server = mds->get_table_server(p->first); if (p->second > server->get_committed_version()) { dout(10) << "try_to_expire waiting for " << get_mdstable_name(p->first) << " to save, need " << p->second << dendl; server->save(gather_bld.new_sub()); } } // truncating for (set::iterator p = truncating_inodes.begin(); p != truncating_inodes.end(); ++p) { dout(10) << "try_to_expire waiting for truncate of " << **p << dendl; (*p)->add_waiter(CInode::WAIT_TRUNC, gather_bld.new_sub()); } // FIXME client requests...? // audit handling of anchor transactions? if (gather_bld.has_subs()) { dout(6) << "LogSegment(" << offset << ").try_to_expire waiting" << dendl; mds->mdlog->flush(); } else { assert(g_conf->mds_kill_journal_expire_at != 5); dout(6) << "LogSegment(" << offset << ").try_to_expire success" << dendl; } } #undef DOUT_COND #define DOUT_COND(cct, l) (l<=cct->_conf->debug_mds || l <= cct->_conf->debug_mds_log) // ----------------------- // EMetaBlob EMetaBlob::EMetaBlob(MDLog *mdlog) : opened_ino(0), renamed_dirino(0), inotablev(0), sessionmapv(0), allocated_ino(0), last_subtree_map(mdlog ? mdlog->get_last_segment_offset() : 0), my_offset(mdlog ? mdlog->get_write_pos() : 0) //, _segment(0) { } void EMetaBlob::add_dir_context(CDir *dir, int mode) { MDS *mds = dir->cache->mds; list parents; // it may be okay not to include the maybe items, if // - we journaled the maybe child inode in this segment // - that subtree turns out to be unambiguously auth list maybe; bool maybenot = false; while (true) { // already have this dir? (we must always add in order) if (lump_map.count(dir->dirfrag())) { dout(20) << "EMetaBlob::add_dir_context(" << dir << ") have lump " << dir->dirfrag() << dendl; break; } // stop at root/stray CInode *diri = dir->get_inode(); CDentry *parent = diri->get_projected_parent_dn(); if (!parent) break; if (mode == TO_AUTH_SUBTREE_ROOT) { // subtree root? if (dir->is_subtree_root() && !dir->state_test(CDir::STATE_EXPORTBOUND)) { if (dir->is_auth() && !dir->is_ambiguous_auth()) { // it's an auth subtree, we don't need maybe (if any), and we're done. dout(20) << "EMetaBlob::add_dir_context(" << dir << ") reached unambig auth subtree, don't need " << maybe << " at " << *dir << dendl; maybe.clear(); break; } else { dout(20) << "EMetaBlob::add_dir_context(" << dir << ") reached ambig or !auth subtree, need " << maybe << " at " << *dir << dendl; // we need the maybe list after all! parents.splice(parents.begin(), maybe); maybenot = false; } } // was the inode journaled in this blob? if (my_offset && diri->last_journaled == my_offset) { dout(20) << "EMetaBlob::add_dir_context(" << dir << ") already have diri this blob " << *diri << dendl; break; } // have we journaled this inode since the last subtree map? if (!maybenot && last_subtree_map && diri->last_journaled >= last_subtree_map) { dout(20) << "EMetaBlob::add_dir_context(" << dir << ") already have diri in this segment (" << diri->last_journaled << " >= " << last_subtree_map << "), setting maybenot flag " << *diri << dendl; maybenot = true; } } if (maybenot) { dout(25) << "EMetaBlob::add_dir_context(" << dir << ") maybe " << *parent << dendl; maybe.push_front(parent); } else { dout(25) << "EMetaBlob::add_dir_context(" << dir << ") definitely " << *parent << dendl; parents.push_front(parent); } dir = parent->get_dir(); } parents.splice(parents.begin(), maybe); dout(20) << "EMetaBlob::add_dir_context final: " << parents << dendl; for (list::iterator p = parents.begin(); p != parents.end(); ++p) { assert((*p)->get_projected_linkage()->is_primary()); add_dentry(*p, false); } } void EMetaBlob::update_segment(LogSegment *ls) { // atids? //for (list::iterator p = atids.begin(); p != atids.end(); ++p) // ls->pending_commit_atids[*p] = ls; // -> handled directly by AnchorClient // dirty inode mtimes // -> handled directly by Server.cc, replay() // alloc table update? if (inotablev) ls->inotablev = inotablev; if (sessionmapv) ls->sessionmapv = sessionmapv; // truncated inodes // -> handled directly by Server.cc // client requests // note the newest request per client //if (!client_reqs.empty()) // ls->last_client_tid[client_reqs.rbegin()->client] = client_reqs.rbegin()->tid); } // EMetaBlob::fullbit void EMetaBlob::fullbit::encode(bufferlist& bl) const { ENCODE_START(6, 5, bl); if (!_enc.length()) { fullbit copy(dn, dnfirst, dnlast, dnv, inode, dirfragtree, xattrs, symlink, snapbl, state, &old_inodes); bl.append(copy._enc); } else { bl.append(_enc); } ENCODE_FINISH(bl); } void EMetaBlob::fullbit::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 5, 5, bl); ::decode(dn, bl); ::decode(dnfirst, bl); ::decode(dnlast, bl); ::decode(dnv, bl); ::decode(inode, bl); ::decode(xattrs, bl); if (inode.is_symlink()) ::decode(symlink, bl); if (inode.is_dir()) { ::decode(dirfragtree, bl); ::decode(snapbl, bl); if ((struct_v == 2) || (struct_v == 3)) { bool dir_layout_exists; ::decode(dir_layout_exists, bl); if (dir_layout_exists) { __u8 dir_struct_v; ::decode(dir_struct_v, bl); // default_file_layout version ::decode(inode.layout, bl); // and actual layout, that we care about } } } if (struct_v >= 6) { ::decode(state, bl); } else { bool dirty; ::decode(dirty, bl); state = dirty ? EMetaBlob::fullbit::STATE_DIRTY : 0; } if (struct_v >= 3) { bool old_inodes_present; ::decode(old_inodes_present, bl); if (old_inodes_present) { ::decode(old_inodes, bl); } } DECODE_FINISH(bl); } void EMetaBlob::fullbit::dump(Formatter *f) const { if (_enc.length() && !dn.length()) { /* if our bufferlist has data but our name is empty, we * haven't initialized ourselves; do so in order to print members! * We use const_cast here because the whole point is we aren't * fully set up and this isn't changing who we "are", just our * representation. */ EMetaBlob::fullbit *me = const_cast(this); bufferlist encoded; encode(encoded); bufferlist::iterator p = encoded.begin(); me->decode(p); } f->dump_string("dentry", dn); f->dump_stream("snapid.first") << dnfirst; f->dump_stream("snapid.last") << dnlast; f->dump_int("dentry version", dnv); f->open_object_section("inode"); inode.dump(f); f->close_section(); // inode f->open_array_section("xattrs"); for (map::const_iterator iter = xattrs.begin(); iter != xattrs.end(); ++iter) { f->dump_string(iter->first.c_str(), iter->second.c_str()); } f->close_section(); // xattrs if (inode.is_symlink()) { f->dump_string("symlink", symlink); } if (inode.is_dir()) { f->dump_stream("frag tree") << dirfragtree; f->dump_string("has_snapbl", snapbl.length() ? "true" : "false"); if (inode.has_layout()) { f->open_object_section("file layout policy"); // FIXME f->dump_string("layout", "the layout exists"); f->close_section(); // file layout policy } } f->dump_string("state", state_string()); if (!old_inodes.empty()) { f->open_array_section("old inodes"); for (old_inodes_t::const_iterator iter = old_inodes.begin(); iter != old_inodes.end(); ++iter) { f->open_object_section("inode"); f->dump_int("snapid", iter->first); iter->second.dump(f); f->close_section(); // inode } f->close_section(); // old inodes } } void EMetaBlob::fullbit::generate_test_instances(list& ls) { inode_t inode; fragtree_t fragtree; map empty_xattrs; bufferlist empty_snapbl; fullbit *sample = new fullbit("/testdn", 0, 0, 0, inode, fragtree, empty_xattrs, "", empty_snapbl, false, NULL); ls.push_back(sample); } void EMetaBlob::fullbit::update_inode(MDS *mds, CInode *in) { in->inode = inode; in->xattrs = xattrs; if (in->inode.is_dir()) { if (!(in->dirfragtree == dirfragtree)) { dout(10) << "EMetaBlob::fullbit::update_inode dft " << in->dirfragtree << " -> " << dirfragtree << " on " << *in << dendl; in->dirfragtree = dirfragtree; in->force_dirfrags(); if (in->has_dirfrags() && in->authority() == CDIR_AUTH_UNDEF) { list ls; in->get_nested_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) { CDir *dir = *p; if (dir->get_num_any() == 0 && mds->mdcache->can_trim_non_auth_dirfrag(dir)) { dout(10) << " closing empty non-auth dirfrag " << *dir << dendl; in->close_dirfrag(dir->get_frag()); } } } } /* * we can do this before linking hte inode bc the split_at would * be a no-op.. we have no children (namely open snaprealms) to * divy up */ in->decode_snap_blob(snapbl); } else if (in->inode.is_symlink()) { in->symlink = symlink; } in->old_inodes = old_inodes; } // EMetaBlob::remotebit void EMetaBlob::remotebit::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); if (!_enc.length()) { remotebit copy(dn, dnfirst, dnlast, dnv, ino, d_type, dirty); bl.append(copy._enc); } else { bl.append(_enc); } ENCODE_FINISH(bl); } void EMetaBlob::remotebit::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(dn, bl); ::decode(dnfirst, bl); ::decode(dnlast, bl); ::decode(dnv, bl); ::decode(ino, bl); ::decode(d_type, bl); ::decode(dirty, bl); DECODE_FINISH(bl); } void EMetaBlob::remotebit::dump(Formatter *f) const { if (_enc.length() && !dn.length()) { /* if our bufferlist has data but our name is empty, we * haven't initialized ourselves; do so in order to print members! * We use const_cast here because the whole point is we aren't * fully set up and this isn't changing who we "are", just our * representation. */ EMetaBlob::remotebit *me = const_cast(this); bufferlist encoded; encode(encoded); bufferlist::iterator p = encoded.begin(); me->decode(p); } f->dump_string("dentry", dn); f->dump_int("snapid.first", dnfirst); f->dump_int("snapid.last", dnlast); f->dump_int("dentry version", dnv); f->dump_int("inodeno", ino); uint32_t type = DTTOIF(d_type) & S_IFMT; // convert to type entries string type_string; switch(type) { case S_IFREG: type_string = "file"; break; case S_IFLNK: type_string = "symlink"; break; case S_IFDIR: type_string = "directory"; break; case S_IFIFO: type_string = "fifo"; break; case S_IFCHR: type_string = "chr"; break; case S_IFBLK: type_string = "blk"; break; case S_IFSOCK: type_string = "sock"; break; default: assert (0 == "unknown d_type!"); } f->dump_string("d_type", type_string); f->dump_string("dirty", dirty ? "true" : "false"); } void EMetaBlob::remotebit:: generate_test_instances(list& ls) { remotebit *remote = new remotebit("/test/dn", 0, 10, 15, 1, IFTODT(S_IFREG), false); ls.push_back(remote); } // EMetaBlob::nullbit void EMetaBlob::nullbit::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); if (!_enc.length()) { nullbit copy(dn, dnfirst, dnlast, dnv, dirty); bl.append(copy._enc); } else { bl.append(_enc); } ENCODE_FINISH(bl); } void EMetaBlob::nullbit::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(dn, bl); ::decode(dnfirst, bl); ::decode(dnlast, bl); ::decode(dnv, bl); ::decode(dirty, bl); DECODE_FINISH(bl); } void EMetaBlob::nullbit::dump(Formatter *f) const { if (_enc.length() && !dn.length()) { /* if our bufferlist has data but our name is empty, we * haven't initialized ourselves; do so in order to print members! * We use const_cast here because the whole point is we aren't * fully set up and this isn't changing who we "are", just our * representation. */ EMetaBlob::nullbit *me = const_cast(this); bufferlist encoded; encode(encoded); bufferlist::iterator p = encoded.begin(); me->decode(p); } f->dump_string("dentry", dn); f->dump_int("snapid.first", dnfirst); f->dump_int("snapid.last", dnlast); f->dump_int("dentry version", dnv); f->dump_string("dirty", dirty ? "true" : "false"); } void EMetaBlob::nullbit::generate_test_instances(list& ls) { nullbit *sample = new nullbit("/test/dentry", 0, 10, 15, false); nullbit *sample2 = new nullbit("/test/dirty", 10, 20, 25, true); ls.push_back(sample); ls.push_back(sample2); } // EMetaBlob::dirlump void EMetaBlob::dirlump::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(fnode, bl); ::encode(state, bl); ::encode(nfull, bl); ::encode(nremote, bl); ::encode(nnull, bl); _encode_bits(); ::encode(dnbl, bl); ENCODE_FINISH(bl); } void EMetaBlob::dirlump::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl) ::decode(fnode, bl); ::decode(state, bl); ::decode(nfull, bl); ::decode(nremote, bl); ::decode(nnull, bl); ::decode(dnbl, bl); dn_decoded = false; // don't decode bits unless we need them. DECODE_FINISH(bl); } void EMetaBlob::dirlump::dump(Formatter *f) const { if (!dn_decoded) { dirlump *me = const_cast(this); me->_decode_bits(); } f->open_object_section("fnode"); fnode.dump(f); f->close_section(); // fnode f->dump_string("state", state_string()); f->dump_int("nfull", nfull); f->dump_int("nremote", nremote); f->dump_int("nnull", nnull); f->open_array_section("full bits"); for (list >::const_iterator iter = dfull.begin(); iter != dfull.end(); ++iter) { f->open_object_section("fullbit"); (*iter)->dump(f); f->close_section(); // fullbit } f->close_section(); // full bits f->open_array_section("remote bits"); for (list::const_iterator iter = dremote.begin(); iter != dremote.end(); ++iter) { f->open_object_section("remotebit"); (*iter).dump(f); f->close_section(); // remotebit } f->close_section(); // remote bits f->open_array_section("null bits"); for (list::const_iterator iter = dnull.begin(); iter != dnull.end(); ++iter) { f->open_object_section("null bit"); (*iter).dump(f); f->close_section(); // null bit } f->close_section(); // null bits } void EMetaBlob::dirlump::generate_test_instances(list& ls) { ls.push_back(new dirlump()); } /** * EMetaBlob proper */ void EMetaBlob::encode(bufferlist& bl) const { ENCODE_START(7, 5, bl); ::encode(lump_order, bl); ::encode(lump_map, bl); ::encode(roots, bl); ::encode(table_tids, bl); ::encode(opened_ino, bl); ::encode(allocated_ino, bl); ::encode(used_preallocated_ino, bl); ::encode(preallocated_inos, bl); ::encode(client_name, bl); ::encode(inotablev, bl); ::encode(sessionmapv, bl); ::encode(truncate_start, bl); ::encode(truncate_finish, bl); ::encode(destroyed_inodes, bl); ::encode(client_reqs, bl); ::encode(renamed_dirino, bl); ::encode(renamed_dir_frags, bl); { // make MDS use v6 format happy int64_t i = -1; bool b = false; ::encode(i, bl); ::encode(b, bl); } ENCODE_FINISH(bl); } void EMetaBlob::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(7, 5, 5, bl); ::decode(lump_order, bl); ::decode(lump_map, bl); if (struct_v >= 4) { ::decode(roots, bl); } else { bufferlist rootbl; ::decode(rootbl, bl); if (rootbl.length()) { bufferlist::iterator p = rootbl.begin(); roots.push_back(ceph::shared_ptr(new fullbit(p))); } } ::decode(table_tids, bl); ::decode(opened_ino, bl); ::decode(allocated_ino, bl); ::decode(used_preallocated_ino, bl); ::decode(preallocated_inos, bl); ::decode(client_name, bl); ::decode(inotablev, bl); ::decode(sessionmapv, bl); ::decode(truncate_start, bl); ::decode(truncate_finish, bl); ::decode(destroyed_inodes, bl); if (struct_v >= 2) { ::decode(client_reqs, bl); } else { list r; ::decode(r, bl); while (!r.empty()) { client_reqs.push_back(pair(r.front(), 0)); r.pop_front(); } } if (struct_v >= 3) { ::decode(renamed_dirino, bl); ::decode(renamed_dir_frags, bl); } if (struct_v >= 6) { // ignore int64_t i; bool b; ::decode(i, bl); ::decode(b, bl); } DECODE_FINISH(bl); } void EMetaBlob::dump(Formatter *f) const { f->open_array_section("lumps"); for (list::const_iterator i = lump_order.begin(); i != lump_order.end(); ++i) { f->open_object_section("lump"); f->open_object_section("dirfrag"); f->dump_stream("dirfrag") << *i; f->close_section(); // dirfrag f->open_object_section("dirlump"); lump_map.at(*i).dump(f); f->close_section(); // dirlump f->close_section(); // lump } f->close_section(); // lumps f->open_array_section("roots"); for (list >::const_iterator i = roots.begin(); i != roots.end(); ++i) { f->open_object_section("root"); (*i)->dump(f); f->close_section(); // root } f->close_section(); // roots f->open_array_section("tableclient tranactions"); for (list >::const_iterator i = table_tids.begin(); i != table_tids.end(); ++i) { f->open_object_section("transaction"); f->dump_int("tid", i->first); f->dump_int("version", i->second); f->close_section(); // transaction } f->close_section(); // tableclient transactions f->dump_int("renamed directory inodeno", renamed_dirino); f->open_array_section("renamed directory fragments"); for (list::const_iterator i = renamed_dir_frags.begin(); i != renamed_dir_frags.end(); ++i) { f->dump_int("frag", *i); } f->close_section(); // renamed directory fragments f->dump_int("inotable version", inotablev); f->dump_int("SesionMap version", sessionmapv); f->dump_int("allocated ino", allocated_ino); f->dump_stream("preallocated inos") << preallocated_inos; f->dump_int("used preallocated ino", used_preallocated_ino); f->open_object_section("client name"); client_name.dump(f); f->close_section(); // client name f->open_array_section("inodes starting a truncate"); for(list::const_iterator i = truncate_start.begin(); i != truncate_start.end(); ++i) { f->dump_int("inodeno", *i); } f->close_section(); // truncate inodes f->open_array_section("inodes finishing a truncated"); for(map::const_iterator i = truncate_finish.begin(); i != truncate_finish.end(); ++i) { f->open_object_section("inode+segment"); f->dump_int("inodeno", i->first); f->dump_int("truncate starting segment", i->second); f->close_section(); // truncated inode } f->close_section(); // truncate finish inodes f->open_array_section("destroyed inodes"); for(vector::const_iterator i = destroyed_inodes.begin(); i != destroyed_inodes.end(); ++i) { f->dump_int("inodeno", *i); } f->close_section(); // destroyed inodes f->open_array_section("client requests"); for(list >::const_iterator i = client_reqs.begin(); i != client_reqs.end(); ++i) { f->open_object_section("Client request"); f->dump_stream("request ID") << i->first; f->dump_int("oldest request on client", i->second); f->close_section(); // request } f->close_section(); // client requests } void EMetaBlob::generate_test_instances(list& ls) { ls.push_back(new EMetaBlob()); } void EMetaBlob::replay(MDS *mds, LogSegment *logseg, MDSlaveUpdate *slaveup) { dout(10) << "EMetaBlob.replay " << lump_map.size() << " dirlumps by " << client_name << dendl; assert(logseg); assert(g_conf->mds_kill_journal_replay_at != 1); for (list >::iterator p = roots.begin(); p != roots.end(); ++p) { CInode *in = mds->mdcache->get_inode((*p)->inode.ino); bool isnew = in ? false:true; if (!in) in = new CInode(mds->mdcache, true); (*p)->update_inode(mds, in); if (isnew) mds->mdcache->add_inode(in); if ((*p)->is_dirty()) in->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay " << (isnew ? " added root ":" updated root ") << *in << dendl; } CInode *renamed_diri = 0; CDir *olddir = 0; if (renamed_dirino) { renamed_diri = mds->mdcache->get_inode(renamed_dirino); if (renamed_diri) dout(10) << "EMetaBlob.replay renamed inode is " << *renamed_diri << dendl; else dout(10) << "EMetaBlob.replay don't have renamed ino " << renamed_dirino << dendl; int nnull = 0; for (list::iterator lp = lump_order.begin(); lp != lump_order.end(); ++lp) { dirlump &lump = lump_map[*lp]; if (lump.nnull) { dout(10) << "EMetaBlob.replay found null dentry in dir " << *lp << dendl; nnull += lump.nnull; } } assert(nnull <= 1); } // keep track of any inodes we unlink and don't relink elsewhere map unlinked; set linked; // walk through my dirs (in order!) for (list::iterator lp = lump_order.begin(); lp != lump_order.end(); ++lp) { dout(10) << "EMetaBlob.replay dir " << *lp << dendl; dirlump &lump = lump_map[*lp]; // the dir CDir *dir = mds->mdcache->get_force_dirfrag(*lp); if (!dir) { // hmm. do i have the inode? CInode *diri = mds->mdcache->get_inode((*lp).ino); if (!diri) { if (MDS_INO_IS_BASE(lp->ino)) { diri = mds->mdcache->create_system_inode(lp->ino, S_IFDIR|0755); dout(10) << "EMetaBlob.replay created base " << *diri << dendl; } else { dout(0) << "EMetaBlob.replay missing dir ino " << (*lp).ino << dendl; assert(0); } } // create the dirfrag dir = diri->get_or_open_dirfrag(mds->mdcache, (*lp).frag); if (MDS_INO_IS_BASE(lp->ino)) mds->mdcache->adjust_subtree_auth(dir, CDIR_AUTH_UNKNOWN); dout(10) << "EMetaBlob.replay added dir " << *dir << dendl; } dir->set_version( lump.fnode.version ); dir->fnode = lump.fnode; if (lump.is_dirty()) { dir->_mark_dirty(logseg); if (!(dir->fnode.rstat == dir->fnode.accounted_rstat)) { dout(10) << "EMetaBlob.replay dirty nestinfo on " << *dir << dendl; mds->locker->mark_updated_scatterlock(&dir->inode->nestlock); logseg->dirty_dirfrag_nest.push_back(&dir->inode->item_dirty_dirfrag_nest); } else { dout(10) << "EMetaBlob.replay clean nestinfo on " << *dir << dendl; } if (!(dir->fnode.fragstat == dir->fnode.accounted_fragstat)) { dout(10) << "EMetaBlob.replay dirty fragstat on " << *dir << dendl; mds->locker->mark_updated_scatterlock(&dir->inode->filelock); logseg->dirty_dirfrag_dir.push_back(&dir->inode->item_dirty_dirfrag_dir); } else { dout(10) << "EMetaBlob.replay clean fragstat on " << *dir << dendl; } } if (lump.is_dirty_dft()) { dout(10) << "EMetaBlob.replay dirty dirfragtree on " << *dir << dendl; dir->state_set(CDir::STATE_DIRTYDFT); mds->locker->mark_updated_scatterlock(&dir->inode->dirfragtreelock); logseg->dirty_dirfrag_dirfragtree.push_back(&dir->inode->item_dirty_dirfrag_dirfragtree); } if (lump.is_new()) dir->mark_new(logseg); if (lump.is_complete()) dir->mark_complete(); else if (lump.is_importing()) dir->state_clear(CDir::STATE_COMPLETE); dout(10) << "EMetaBlob.replay updated dir " << *dir << dendl; // decode bits lump._decode_bits(); // full dentry+inode pairs for (list >::iterator pp = lump.get_dfull().begin(); pp != lump.get_dfull().end(); ++pp) { ceph::shared_ptr p = *pp; CDentry *dn = dir->lookup_exact_snap(p->dn, p->dnlast); if (!dn) { dn = dir->add_null_dentry(p->dn, p->dnfirst, p->dnlast); dn->set_version(p->dnv); if (p->is_dirty()) dn->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay added " << *dn << dendl; } else { dn->set_version(p->dnv); if (p->is_dirty()) dn->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay for [" << p->dnfirst << "," << p->dnlast << "] had " << *dn << dendl; dn->first = p->dnfirst; assert(dn->last == p->dnlast); } CInode *in = mds->mdcache->get_inode(p->inode.ino, p->dnlast); if (!in) { in = new CInode(mds->mdcache, true, p->dnfirst, p->dnlast); p->update_inode(mds, in); mds->mdcache->add_inode(in); if (!dn->get_linkage()->is_null()) { if (dn->get_linkage()->is_primary()) { unlinked[dn->get_linkage()->get_inode()] = dir; stringstream ss; ss << "EMetaBlob.replay FIXME had dentry linked to wrong inode " << *dn << " " << *dn->get_linkage()->get_inode() << " should be " << p->inode.ino; dout(0) << ss.str() << dendl; mds->clog.warn(ss); } dir->unlink_inode(dn); } if (unlinked.count(in)) linked.insert(in); dir->link_primary_inode(dn, in); if (p->is_dirty()) in->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay added " << *in << dendl; } else { if (in->get_parent_dn() && in->inode.anchored != p->inode.anchored) in->get_parent_dn()->adjust_nested_anchors((int)p->inode.anchored - (int)in->inode.anchored); p->update_inode(mds, in); if (dn->get_linkage()->get_inode() != in && in->get_parent_dn()) { dout(10) << "EMetaBlob.replay unlinking " << *in << dendl; unlinked[in] = in->get_parent_dir(); in->get_parent_dir()->unlink_inode(in->get_parent_dn()); } if (dn->get_linkage()->get_inode() != in) { if (!dn->get_linkage()->is_null()) { // note: might be remote. as with stray reintegration. if (dn->get_linkage()->is_primary()) { unlinked[dn->get_linkage()->get_inode()] = dir; stringstream ss; ss << "EMetaBlob.replay FIXME had dentry linked to wrong inode " << *dn << " " << *dn->get_linkage()->get_inode() << " should be " << p->inode.ino; dout(0) << ss.str() << dendl; mds->clog.warn(ss); } dir->unlink_inode(dn); } if (unlinked.count(in)) linked.insert(in); dir->link_primary_inode(dn, in); dout(10) << "EMetaBlob.replay linked " << *in << dendl; } else { dout(10) << "EMetaBlob.replay for [" << p->dnfirst << "," << p->dnlast << "] had " << *in << dendl; } if (p->is_dirty()) in->_mark_dirty(logseg); assert(in->first == p->dnfirst || (in->is_multiversion() && in->first > p->dnfirst)); } if (p->is_dirty_parent()) in->_mark_dirty_parent(logseg, p->is_dirty_pool()); assert(g_conf->mds_kill_journal_replay_at != 2); } // remote dentries for (list::iterator p = lump.get_dremote().begin(); p != lump.get_dremote().end(); ++p) { CDentry *dn = dir->lookup_exact_snap(p->dn, p->dnlast); if (!dn) { dn = dir->add_remote_dentry(p->dn, p->ino, p->d_type, p->dnfirst, p->dnlast); dn->set_version(p->dnv); if (p->dirty) dn->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay added " << *dn << dendl; } else { if (!dn->get_linkage()->is_null()) { dout(10) << "EMetaBlob.replay unlinking " << *dn << dendl; if (dn->get_linkage()->is_primary()) { unlinked[dn->get_linkage()->get_inode()] = dir; stringstream ss; ss << "EMetaBlob.replay FIXME had dentry linked to wrong inode " << *dn << " " << *dn->get_linkage()->get_inode() << " should be remote " << p->ino; dout(0) << ss.str() << dendl; } dir->unlink_inode(dn); } dir->link_remote_inode(dn, p->ino, p->d_type); dn->set_version(p->dnv); if (p->dirty) dn->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay for [" << p->dnfirst << "," << p->dnlast << "] had " << *dn << dendl; dn->first = p->dnfirst; assert(dn->last == p->dnlast); } } // null dentries for (list::iterator p = lump.get_dnull().begin(); p != lump.get_dnull().end(); ++p) { CDentry *dn = dir->lookup_exact_snap(p->dn, p->dnlast); if (!dn) { dn = dir->add_null_dentry(p->dn, p->dnfirst, p->dnlast); dn->set_version(p->dnv); if (p->dirty) dn->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay added " << *dn << dendl; } else { dn->first = p->dnfirst; if (!dn->get_linkage()->is_null()) { dout(10) << "EMetaBlob.replay unlinking " << *dn << dendl; CInode *in = dn->get_linkage()->get_inode(); // For renamed inode, We may call CInode::force_dirfrag() later. // CInode::force_dirfrag() doesn't work well when inode is detached // from the hierarchy. if (!renamed_diri || renamed_diri != in) { if (dn->get_linkage()->is_primary()) unlinked[in] = dir; dir->unlink_inode(dn); } } dn->set_version(p->dnv); if (p->dirty) dn->_mark_dirty(logseg); dout(10) << "EMetaBlob.replay had " << *dn << dendl; assert(dn->last == p->dnlast); } olddir = dir; } } assert(g_conf->mds_kill_journal_replay_at != 3); if (renamed_dirino) { if (renamed_diri) { assert(unlinked.count(renamed_diri)); assert(linked.count(renamed_diri)); olddir = unlinked[renamed_diri]; } else { // we imported a diri we haven't seen before renamed_diri = mds->mdcache->get_inode(renamed_dirino); assert(renamed_diri); // it was in the metablob } if (olddir) { if (olddir->authority() != CDIR_AUTH_UNDEF && renamed_diri->authority() == CDIR_AUTH_UNDEF) { assert(slaveup); // auth to non-auth, must be slave prepare list leaves; renamed_diri->dirfragtree.get_leaves(leaves); for (list::iterator p = leaves.begin(); p != leaves.end(); ++p) { CDir *dir = renamed_diri->get_dirfrag(*p); assert(dir); // preserve subtree bound until slave commit if (dir->get_dir_auth() == CDIR_AUTH_UNDEF) slaveup->olddirs.insert(dir->inode); } } mds->mdcache->adjust_subtree_after_rename(renamed_diri, olddir, false); // see if we can discard the subtree we renamed out of CDir *root = mds->mdcache->get_subtree_root(olddir); if (root->get_dir_auth() == CDIR_AUTH_UNDEF) { if (slaveup) // preserve the old dir until slave commit slaveup->olddirs.insert(olddir->inode); else mds->mdcache->try_trim_non_auth_subtree(root); } } // if we are the srci importer, we'll also have some dirfrags we have to open up... if (renamed_diri->authority() != CDIR_AUTH_UNDEF) { for (list::iterator p = renamed_dir_frags.begin(); p != renamed_dir_frags.end(); ++p) { CDir *dir = renamed_diri->get_dirfrag(*p); if (dir) { // we already had the inode before, and we already adjusted this subtree accordingly. dout(10) << " already had+adjusted rename import bound " << *dir << dendl; assert(olddir); continue; } dir = renamed_diri->get_or_open_dirfrag(mds->mdcache, *p); dout(10) << " creating new rename import bound " << *dir << dendl; mds->mdcache->adjust_subtree_auth(dir, CDIR_AUTH_UNDEF, false); } } // rename may overwrite an empty directory and move it into stray dir. unlinked.erase(renamed_diri); for (map::iterator p = unlinked.begin(); p != unlinked.end(); ++p) { if (!linked.count(p->first)) continue; assert(p->first->is_dir()); mds->mdcache->adjust_subtree_after_rename(p->first, p->second, false); } } if (!unlinked.empty()) { for (set::iterator p = linked.begin(); p != linked.end(); ++p) unlinked.erase(*p); dout(10) << " unlinked set contains " << unlinked << dendl; for (map::iterator p = unlinked.begin(); p != unlinked.end(); ++p) { if (slaveup) // preserve unlinked inodes until slave commit slaveup->unlinked.insert(p->first); else mds->mdcache->remove_inode_recursive(p->first); } } // table client transactions for (list >::iterator p = table_tids.begin(); p != table_tids.end(); ++p) { dout(10) << "EMetaBlob.replay noting " << get_mdstable_name(p->first) << " transaction " << p->second << dendl; MDSTableClient *client = mds->get_table_client(p->first); client->got_journaled_agree(p->second, logseg); } // opened ino? if (opened_ino) { CInode *in = mds->mdcache->get_inode(opened_ino); assert(in); dout(10) << "EMetaBlob.replay noting opened inode " << *in << dendl; logseg->open_files.push_back(&in->item_open_file); } // allocated_inos if (inotablev) { if (mds->inotable->get_version() >= inotablev) { dout(10) << "EMetaBlob.replay inotable tablev " << inotablev << " <= table " << mds->inotable->get_version() << dendl; } else { dout(10) << "EMetaBlob.replay inotable v " << inotablev << " - 1 == table " << mds->inotable->get_version() << " allocated+used " << allocated_ino << " prealloc " << preallocated_inos << dendl; if (allocated_ino) mds->inotable->replay_alloc_id(allocated_ino); if (preallocated_inos.size()) mds->inotable->replay_alloc_ids(preallocated_inos); // [repair bad inotable updates] if (inotablev > mds->inotable->get_version()) { mds->clog.error() << "journal replay inotablev mismatch " << mds->inotable->get_version() << " -> " << inotablev << "\n"; mds->inotable->force_replay_version(inotablev); } assert(inotablev == mds->inotable->get_version()); } } if (sessionmapv) { if (mds->sessionmap.version >= sessionmapv) { dout(10) << "EMetaBlob.replay sessionmap v " << sessionmapv << " <= table " << mds->sessionmap.version << dendl; } else { dout(10) << "EMetaBlob.replay sessionmap v" << sessionmapv << " -(1|2) == table " << mds->sessionmap.version << " prealloc " << preallocated_inos << " used " << used_preallocated_ino << dendl; Session *session = mds->sessionmap.get_session(client_name); assert(session); dout(20) << " (session prealloc " << session->info.prealloc_inos << ")" << dendl; if (used_preallocated_ino) { if (session->info.prealloc_inos.empty()) { // HRM: badness in the journal mds->clog.warn() << " replayed op " << client_reqs << " on session for " << client_name << " with empty prealloc_inos\n"; } else { inodeno_t next = session->next_ino(); inodeno_t i = session->take_ino(used_preallocated_ino); if (next != i) mds->clog.warn() << " replayed op " << client_reqs << " used ino " << i << " but session next is " << next << "\n"; assert(i == used_preallocated_ino); session->info.used_inos.clear(); } mds->sessionmap.projected = ++mds->sessionmap.version; } if (preallocated_inos.size()) { session->info.prealloc_inos.insert(preallocated_inos); mds->sessionmap.projected = ++mds->sessionmap.version; } assert(sessionmapv == mds->sessionmap.version); } } // truncating inodes for (list::iterator p = truncate_start.begin(); p != truncate_start.end(); ++p) { CInode *in = mds->mdcache->get_inode(*p); assert(in); mds->mdcache->add_recovered_truncate(in, logseg); } for (map::iterator p = truncate_finish.begin(); p != truncate_finish.end(); ++p) { LogSegment *ls = mds->mdlog->get_segment(p->second); if (ls) { CInode *in = mds->mdcache->get_inode(p->first); assert(in); mds->mdcache->remove_recovered_truncate(in, ls); } } // destroyed inodes for (vector::iterator p = destroyed_inodes.begin(); p != destroyed_inodes.end(); ++p) { CInode *in = mds->mdcache->get_inode(*p); if (in) { dout(10) << "EMetaBlob.replay destroyed " << *p << ", dropping " << *in << dendl; mds->mdcache->remove_inode(in); } else { dout(10) << "EMetaBlob.replay destroyed " << *p << ", not in cache" << dendl; } } // client requests for (list >::iterator p = client_reqs.begin(); p != client_reqs.end(); ++p) { if (p->first.name.is_client()) { dout(10) << "EMetaBlob.replay request " << p->first << " trim_to " << p->second << dendl; // if we allocated an inode, there should be exactly one client request id. assert(allocated_ino == inodeno_t() || client_reqs.size() == 1); Session *session = mds->sessionmap.get_session(p->first.name); if (session) { session->add_completed_request(p->first.tid, allocated_ino); if (p->second) session->trim_completed_requests(p->second); } } } // update segment update_segment(logseg); assert(g_conf->mds_kill_journal_replay_at != 4); } // ----------------------- // ESession void ESession::update_segment() { _segment->sessionmapv = cmapv; if (inos.size() && inotablev) _segment->inotablev = inotablev; } void ESession::replay(MDS *mds) { if (mds->sessionmap.version >= cmapv) { dout(10) << "ESession.replay sessionmap " << mds->sessionmap.version << " >= " << cmapv << ", noop" << dendl; } else { dout(10) << "ESession.replay sessionmap " << mds->sessionmap.version << " < " << cmapv << " " << (open ? "open":"close") << " " << client_inst << dendl; mds->sessionmap.projected = ++mds->sessionmap.version; assert(mds->sessionmap.version == cmapv); Session *session; if (open) { session = mds->sessionmap.get_or_add_session(client_inst); mds->sessionmap.set_state(session, Session::STATE_OPEN); dout(10) << " opened session " << session->info.inst << dendl; } else { session = mds->sessionmap.get_session(client_inst.name); if (session) { // there always should be a session, but there's a bug if (session->connection == NULL) { dout(10) << " removed session " << session->info.inst << dendl; mds->sessionmap.remove_session(session); } else { session->clear(); // the client has reconnected; keep the Session, but reset dout(10) << " reset session " << session->info.inst << " (they reconnected)" << dendl; } } else { mds->clog.error() << "replayed stray Session close event for " << client_inst << " from time " << stamp << ", ignoring"; } } } if (inos.size() && inotablev) { if (mds->inotable->get_version() >= inotablev) { dout(10) << "ESession.replay inotable " << mds->inotable->get_version() << " >= " << inotablev << ", noop" << dendl; } else { dout(10) << "ESession.replay inotable " << mds->inotable->get_version() << " < " << inotablev << " " << (open ? "add":"remove") << dendl; assert(!open); // for now mds->inotable->replay_release_ids(inos); assert(mds->inotable->get_version() == inotablev); } } update_segment(); } void ESession::encode(bufferlist &bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(client_inst, bl); ::encode(open, bl); ::encode(cmapv, bl); ::encode(inos, bl); ::encode(inotablev, bl); ENCODE_FINISH(bl); } void ESession::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(client_inst, bl); ::decode(open, bl); ::decode(cmapv, bl); ::decode(inos, bl); ::decode(inotablev, bl); DECODE_FINISH(bl); } void ESession::dump(Formatter *f) const { f->dump_stream("client instance") << client_inst; f->dump_string("open", open ? "true" : "false"); f->dump_int("client map version", cmapv); f->dump_stream("inos") << inos; f->dump_int("inotable version", inotablev); } void ESession::generate_test_instances(list& ls) { ls.push_back(new ESession); } // ----------------------- // ESessions void ESessions::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(client_map, bl); ::encode(cmapv, bl); ::encode(stamp, bl); ENCODE_FINISH(bl); } void ESessions::decode_old(bufferlist::iterator &bl) { ::decode(client_map, bl); ::decode(cmapv, bl); if (!bl.end()) ::decode(stamp, bl); } void ESessions::decode_new(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(client_map, bl); ::decode(cmapv, bl); if (!bl.end()) ::decode(stamp, bl); DECODE_FINISH(bl); } void ESessions::dump(Formatter *f) const { f->dump_int("client map version", cmapv); f->open_array_section("client map"); for (map::const_iterator i = client_map.begin(); i != client_map.end(); ++i) { f->open_object_section("client"); f->dump_int("client id", i->first.v); f->dump_stream("client entity") << i->second; f->close_section(); // client } f->close_section(); // client map } void ESessions::generate_test_instances(list& ls) { ls.push_back(new ESessions()); } void ESessions::update_segment() { _segment->sessionmapv = cmapv; } void ESessions::replay(MDS *mds) { if (mds->sessionmap.version >= cmapv) { dout(10) << "ESessions.replay sessionmap " << mds->sessionmap.version << " >= " << cmapv << ", noop" << dendl; } else { dout(10) << "ESessions.replay sessionmap " << mds->sessionmap.version << " < " << cmapv << dendl; mds->sessionmap.open_sessions(client_map); assert(mds->sessionmap.version == cmapv); mds->sessionmap.projected = mds->sessionmap.version; } update_segment(); } // ----------------------- // ETableServer void ETableServer::encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(table, bl); ::encode(op, bl); ::encode(reqid, bl); ::encode(bymds, bl); ::encode(mutation, bl); ::encode(tid, bl); ::encode(version, bl); ENCODE_FINISH(bl); } void ETableServer::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(table, bl); ::decode(op, bl); ::decode(reqid, bl); ::decode(bymds, bl); ::decode(mutation, bl); ::decode(tid, bl); ::decode(version, bl); DECODE_FINISH(bl); } void ETableServer::dump(Formatter *f) const { f->dump_int("table id", table); f->dump_int("op", op); f->dump_int("request id", reqid); f->dump_int("by mds", bymds); f->dump_int("tid", tid); f->dump_int("version", version); } void ETableServer::generate_test_instances(list& ls) { ls.push_back(new ETableServer()); } void ETableServer::update_segment() { _segment->tablev[table] = version; } void ETableServer::replay(MDS *mds) { MDSTableServer *server = mds->get_table_server(table); if (server->get_version() >= version) { dout(10) << "ETableServer.replay " << get_mdstable_name(table) << " " << get_mdstableserver_opname(op) << " event " << version << " <= table " << server->get_version() << dendl; return; } dout(10) << " ETableServer.replay " << get_mdstable_name(table) << " " << get_mdstableserver_opname(op) << " event " << version << " - 1 == table " << server->get_version() << dendl; assert(version-1 == server->get_version()); switch (op) { case TABLESERVER_OP_PREPARE: server->_prepare(mutation, reqid, bymds); server->_note_prepare(bymds, reqid); break; case TABLESERVER_OP_COMMIT: server->_commit(tid); server->_note_commit(tid); break; case TABLESERVER_OP_ROLLBACK: server->_rollback(tid); server->_note_rollback(tid); break; case TABLESERVER_OP_SERVER_UPDATE: server->_server_update(mutation); break; default: assert(0); } assert(version == server->get_version()); update_segment(); } // --------------------- // ETableClient void ETableClient::encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(table, bl); ::encode(op, bl); ::encode(tid, bl); ENCODE_FINISH(bl); } void ETableClient::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(table, bl); ::decode(op, bl); ::decode(tid, bl); DECODE_FINISH(bl); } void ETableClient::dump(Formatter *f) const { f->dump_int("table", table); f->dump_int("op", op); f->dump_int("tid", tid); } void ETableClient::generate_test_instances(list& ls) { ls.push_back(new ETableClient()); } void ETableClient::replay(MDS *mds) { dout(10) << " ETableClient.replay " << get_mdstable_name(table) << " op " << get_mdstableserver_opname(op) << " tid " << tid << dendl; MDSTableClient *client = mds->get_table_client(table); assert(op == TABLESERVER_OP_ACK); client->got_journaled_ack(tid); } // ----------------------- // ESnap /* void ESnap::update_segment() { _segment->tablev[TABLE_SNAP] = version; } void ESnap::replay(MDS *mds) { if (mds->snaptable->get_version() >= version) { dout(10) << "ESnap.replay event " << version << " <= table " << mds->snaptable->get_version() << dendl; return; } dout(10) << " ESnap.replay event " << version << " - 1 == table " << mds->snaptable->get_version() << dendl; assert(version-1 == mds->snaptable->get_version()); if (create) { version_t v; snapid_t s = mds->snaptable->create(snap.dirino, snap.name, snap.stamp, &v); assert(s == snap.snapid); } else { mds->snaptable->remove(snap.snapid); } assert(version == mds->snaptable->get_version()); } */ // ----------------------- // EUpdate void EUpdate::encode(bufferlist &bl) const { ENCODE_START(4, 4, bl); ::encode(stamp, bl); ::encode(type, bl); ::encode(metablob, bl); ::encode(client_map, bl); ::encode(cmapv, bl); ::encode(reqid, bl); ::encode(had_slaves, bl); ENCODE_FINISH(bl); } void EUpdate::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 4, 4, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(type, bl); ::decode(metablob, bl); ::decode(client_map, bl); if (struct_v >= 3) ::decode(cmapv, bl); ::decode(reqid, bl); ::decode(had_slaves, bl); DECODE_FINISH(bl); } void EUpdate::dump(Formatter *f) const { f->open_object_section("metablob"); metablob.dump(f); f->close_section(); // metablob f->dump_string("type", type); f->dump_int("client map length", client_map.length()); f->dump_int("client map version", cmapv); f->dump_stream("reqid") << reqid; f->dump_string("had slaves", had_slaves ? "true" : "false"); } void EUpdate::generate_test_instances(list& ls) { ls.push_back(new EUpdate()); } void EUpdate::update_segment() { metablob.update_segment(_segment); if (had_slaves) _segment->uncommitted_masters.insert(reqid); } void EUpdate::replay(MDS *mds) { metablob.replay(mds, _segment); if (had_slaves) { dout(10) << "EUpdate.replay " << reqid << " had slaves, expecting a matching ECommitted" << dendl; _segment->uncommitted_masters.insert(reqid); set slaves; mds->mdcache->add_uncommitted_master(reqid, _segment, slaves, true); } if (client_map.length()) { if (mds->sessionmap.version >= cmapv) { dout(10) << "EUpdate.replay sessionmap v " << cmapv << " <= table " << mds->sessionmap.version << dendl; } else { dout(10) << "EUpdate.replay sessionmap " << mds->sessionmap.version << " < " << cmapv << dendl; // open client sessions? map cm; map seqm; bufferlist::iterator blp = client_map.begin(); ::decode(cm, blp); mds->server->prepare_force_open_sessions(cm, seqm); mds->server->finish_force_open_sessions(cm, seqm); assert(mds->sessionmap.version == cmapv); mds->sessionmap.projected = mds->sessionmap.version; } } } // ------------------------ // EOpen void EOpen::encode(bufferlist &bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(metablob, bl); ::encode(inos, bl); ENCODE_FINISH(bl); } void EOpen::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(metablob, bl); ::decode(inos, bl); DECODE_FINISH(bl); } void EOpen::dump(Formatter *f) const { f->open_object_section("metablob"); metablob.dump(f); f->close_section(); // metablob f->open_array_section("inos involved"); for (vector::const_iterator i = inos.begin(); i != inos.end(); ++i) { f->dump_int("ino", *i); } f->close_section(); // inos } void EOpen::generate_test_instances(list& ls) { ls.push_back(new EOpen()); ls.push_back(new EOpen()); ls.back()->add_ino(0); } void EOpen::update_segment() { // ?? } void EOpen::replay(MDS *mds) { dout(10) << "EOpen.replay " << dendl; metablob.replay(mds, _segment); // note which segments inodes belong to, so we don't have to start rejournaling them for (vector::iterator p = inos.begin(); p != inos.end(); ++p) { CInode *in = mds->mdcache->get_inode(*p); if (!in) { dout(0) << "EOpen.replay ino " << *p << " not in metablob" << dendl; assert(in); } _segment->open_files.push_back(&in->item_open_file); } } // ----------------------- // ECommitted void ECommitted::replay(MDS *mds) { if (mds->mdcache->uncommitted_masters.count(reqid)) { dout(10) << "ECommitted.replay " << reqid << dendl; mds->mdcache->uncommitted_masters[reqid].ls->uncommitted_masters.erase(reqid); mds->mdcache->uncommitted_masters.erase(reqid); } else { dout(10) << "ECommitted.replay " << reqid << " -- didn't see original op" << dendl; } } void ECommitted::encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(reqid, bl); ENCODE_FINISH(bl); } void ECommitted::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(reqid, bl); DECODE_FINISH(bl); } void ECommitted::dump(Formatter *f) const { f->dump_stream("stamp") << stamp; f->dump_stream("reqid") << reqid; } void ECommitted::generate_test_instances(list& ls) { ls.push_back(new ECommitted); ls.push_back(new ECommitted); ls.back()->stamp = utime_t(1, 2); ls.back()->reqid = metareqid_t(entity_name_t::CLIENT(123), 456); } // ----------------------- // ESlaveUpdate void link_rollback::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(reqid, bl); ::encode(ino, bl); ::encode(was_inc, bl); ::encode(old_ctime, bl); ::encode(old_dir_mtime, bl); ::encode(old_dir_rctime, bl); ENCODE_FINISH(bl); } void link_rollback::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(reqid, bl); ::decode(ino, bl); ::decode(was_inc, bl); ::decode(old_ctime, bl); ::decode(old_dir_mtime, bl); ::decode(old_dir_rctime, bl); DECODE_FINISH(bl); } void link_rollback::dump(Formatter *f) const { f->dump_stream("metareqid") << reqid; f->dump_int("ino", ino); f->dump_string("was incremented", was_inc ? "true" : "false"); f->dump_stream("old_ctime") << old_ctime; f->dump_stream("old_dir_mtime") << old_dir_mtime; f->dump_stream("old_dir_rctime") << old_dir_rctime; } void link_rollback::generate_test_instances(list& ls) { ls.push_back(new link_rollback()); } void rmdir_rollback::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(reqid, bl); ::encode(src_dir, bl); ::encode(src_dname, bl); ::encode(dest_dir, bl); ::encode(dest_dname, bl); ENCODE_FINISH(bl); } void rmdir_rollback::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(reqid, bl); ::decode(src_dir, bl); ::decode(src_dname, bl); ::decode(dest_dir, bl); ::decode(dest_dname, bl); DECODE_FINISH(bl); } void rmdir_rollback::dump(Formatter *f) const { f->dump_stream("metareqid") << reqid; f->dump_stream("source directory") << src_dir; f->dump_string("source dname", src_dname); f->dump_stream("destination directory") << dest_dir; f->dump_string("destination dname", dest_dname); } void rmdir_rollback::generate_test_instances(list& ls) { ls.push_back(new rmdir_rollback()); } void rename_rollback::drec::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(dirfrag, bl); ::encode(dirfrag_old_mtime, bl); ::encode(dirfrag_old_rctime, bl); ::encode(ino, bl); ::encode(remote_ino, bl); ::encode(dname, bl); ::encode(remote_d_type, bl); ::encode(old_ctime, bl); ENCODE_FINISH(bl); } void rename_rollback::drec::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(dirfrag, bl); ::decode(dirfrag_old_mtime, bl); ::decode(dirfrag_old_rctime, bl); ::decode(ino, bl); ::decode(remote_ino, bl); ::decode(dname, bl); ::decode(remote_d_type, bl); ::decode(old_ctime, bl); DECODE_FINISH(bl); } void rename_rollback::drec::dump(Formatter *f) const { f->dump_stream("directory fragment") << dirfrag; f->dump_stream("directory old mtime") << dirfrag_old_mtime; f->dump_stream("directory old rctime") << dirfrag_old_rctime; f->dump_int("ino", ino); f->dump_int("remote ino", remote_ino); f->dump_string("dname", dname); uint32_t type = DTTOIF(remote_d_type) & S_IFMT; // convert to type entries string type_string; switch(type) { case S_IFREG: type_string = "file"; break; case S_IFLNK: type_string = "symlink"; break; case S_IFDIR: type_string = "directory"; break; default: type_string = "UNKNOWN-" + stringify((int)type); break; } f->dump_string("remote dtype", type_string); f->dump_stream("old ctime") << old_ctime; } void rename_rollback::drec::generate_test_instances(list& ls) { ls.push_back(new drec()); ls.back()->remote_d_type = IFTODT(S_IFREG); } void rename_rollback::encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(reqid, bl); encode(orig_src, bl); encode(orig_dest, bl); encode(stray, bl); ::encode(ctime, bl); ENCODE_FINISH(bl); } void rename_rollback::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(reqid, bl); decode(orig_src, bl); decode(orig_dest, bl); decode(stray, bl); ::decode(ctime, bl); DECODE_FINISH(bl); } void rename_rollback::dump(Formatter *f) const { f->dump_stream("request id") << reqid; f->open_object_section("original src drec"); orig_src.dump(f); f->close_section(); // original src drec f->open_object_section("original dest drec"); orig_dest.dump(f); f->close_section(); // original dest drec f->open_object_section("stray drec"); stray.dump(f); f->close_section(); // stray drec f->dump_stream("ctime") << ctime; } void rename_rollback::generate_test_instances(list& ls) { ls.push_back(new rename_rollback()); ls.back()->orig_src.remote_d_type = IFTODT(S_IFREG); ls.back()->orig_dest.remote_d_type = IFTODT(S_IFREG); ls.back()->stray.remote_d_type = IFTODT(S_IFREG); } void ESlaveUpdate::encode(bufferlist &bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(type, bl); ::encode(reqid, bl); ::encode(master, bl); ::encode(op, bl); ::encode(origop, bl); ::encode(commit, bl); ::encode(rollback, bl); ENCODE_FINISH(bl); } void ESlaveUpdate::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(type, bl); ::decode(reqid, bl); ::decode(master, bl); ::decode(op, bl); ::decode(origop, bl); ::decode(commit, bl); ::decode(rollback, bl); DECODE_FINISH(bl); } void ESlaveUpdate::dump(Formatter *f) const { f->open_object_section("metablob"); commit.dump(f); f->close_section(); // metablob f->dump_int("rollback length", rollback.length()); f->dump_string("type", type); f->dump_stream("metareqid") << reqid; f->dump_int("master", master); f->dump_int("op", op); f->dump_int("original op", origop); } void ESlaveUpdate::generate_test_instances(list& ls) { ls.push_back(new ESlaveUpdate()); } void ESlaveUpdate::replay(MDS *mds) { MDSlaveUpdate *su; switch (op) { case ESlaveUpdate::OP_PREPARE: dout(10) << "ESlaveUpdate.replay prepare " << reqid << " for mds." << master << ": applying commit, saving rollback info" << dendl; su = new MDSlaveUpdate(origop, rollback, _segment->slave_updates); commit.replay(mds, _segment, su); mds->mdcache->add_uncommitted_slave_update(reqid, master, su); break; case ESlaveUpdate::OP_COMMIT: su = mds->mdcache->get_uncommitted_slave_update(reqid, master); if (su) { dout(10) << "ESlaveUpdate.replay commit " << reqid << " for mds." << master << dendl; mds->mdcache->finish_uncommitted_slave_update(reqid, master); } else { dout(10) << "ESlaveUpdate.replay commit " << reqid << " for mds." << master << ": ignoring, no previously saved prepare" << dendl; } break; case ESlaveUpdate::OP_ROLLBACK: dout(10) << "ESlaveUpdate.replay abort " << reqid << " for mds." << master << ": applying rollback commit blob" << dendl; commit.replay(mds, _segment); su = mds->mdcache->get_uncommitted_slave_update(reqid, master); if (su) mds->mdcache->finish_uncommitted_slave_update(reqid, master); break; default: assert(0); } } // ----------------------- // ESubtreeMap void ESubtreeMap::encode(bufferlist& bl) const { ENCODE_START(5, 5, bl); ::encode(stamp, bl); ::encode(metablob, bl); ::encode(subtrees, bl); ::encode(ambiguous_subtrees, bl); ::encode(expire_pos, bl); ENCODE_FINISH(bl); } void ESubtreeMap::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 5, 5, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(metablob, bl); ::decode(subtrees, bl); if (struct_v >= 4) ::decode(ambiguous_subtrees, bl); if (struct_v >= 3) ::decode(expire_pos, bl); DECODE_FINISH(bl); } void ESubtreeMap::dump(Formatter *f) const { f->open_object_section("metablob"); metablob.dump(f); f->close_section(); // metablob f->open_array_section("subtrees"); for(map >::const_iterator i = subtrees.begin(); i != subtrees.end(); ++i) { f->open_object_section("tree"); f->dump_stream("root dirfrag") << i->first; for (vector::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { f->dump_stream("bound dirfrag") << *j; } f->close_section(); // tree } f->close_section(); // subtrees f->open_array_section("ambiguous subtrees"); for(set::const_iterator i = ambiguous_subtrees.begin(); i != ambiguous_subtrees.end(); ++i) { f->dump_stream("dirfrag") << *i; } f->close_section(); // ambiguous subtrees f->dump_int("expire position", expire_pos); } void ESubtreeMap::generate_test_instances(list& ls) { ls.push_back(new ESubtreeMap()); } void ESubtreeMap::replay(MDS *mds) { if (expire_pos && expire_pos > mds->mdlog->journaler->get_expire_pos()) mds->mdlog->journaler->set_expire_pos(expire_pos); // suck up the subtree map? if (mds->mdcache->is_subtrees()) { dout(10) << "ESubtreeMap.replay -- i already have import map; verifying" << dendl; int errors = 0; for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = mds->mdcache->get_dirfrag(p->first); if (!dir) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree root " << p->first << " not in cache"; ++errors; continue; } if (!mds->mdcache->is_subtree(dir)) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree root " << p->first << " not a subtree in cache"; ++errors; continue; } if (dir->get_dir_auth().first != mds->whoami) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree root " << p->first << " is not mine in cache (it's " << dir->get_dir_auth() << ")"; ++errors; continue; } for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) mds->mdcache->get_force_dirfrag(*q); set bounds; mds->mdcache->get_subtree_bounds(dir, bounds); for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { CDir *b = mds->mdcache->get_dirfrag(*q); if (!b) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree " << p->first << " bound " << *q << " not in cache"; ++errors; continue; } if (bounds.count(b) == 0) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree " << p->first << " bound " << *q << " not a bound in cache"; ++errors; continue; } bounds.erase(b); } for (set::iterator q = bounds.begin(); q != bounds.end(); ++q) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree " << p->first << " has extra bound in cache " << (*q)->dirfrag(); ++errors; } if (ambiguous_subtrees.count(p->first)) { if (!mds->mdcache->have_ambiguous_import(p->first)) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree " << p->first << " is ambiguous but is not in our cache"; ++errors; } } else { if (mds->mdcache->have_ambiguous_import(p->first)) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " subtree " << p->first << " is not ambiguous but is in our cache"; ++errors; } } } list subs; mds->mdcache->list_subtrees(subs); for (list::iterator p = subs.begin(); p != subs.end(); ++p) { CDir *dir = *p; if (dir->get_dir_auth().first != mds->whoami) continue; if (subtrees.count(dir->dirfrag()) == 0) { mds->clog.error() << " replayed ESubtreeMap at " << get_start_off() << " does not include cache subtree " << dir->dirfrag(); ++errors; } } if (errors) { dout(0) << "journal subtrees: " << subtrees << dendl; dout(0) << "journal ambig_subtrees: " << ambiguous_subtrees << dendl; mds->mdcache->show_subtrees(); assert(!g_conf->mds_debug_subtrees || errors == 0); } return; } dout(10) << "ESubtreeMap.replay -- reconstructing (auth) subtree spanning tree" << dendl; // first, stick the spanning tree in my cache //metablob.print(*_dout); metablob.replay(mds, _segment); // restore import/export maps for (map >::iterator p = subtrees.begin(); p != subtrees.end(); ++p) { CDir *dir = mds->mdcache->get_dirfrag(p->first); assert(dir); if (ambiguous_subtrees.count(p->first)) { // ambiguous! mds->mdcache->add_ambiguous_import(p->first, p->second); mds->mdcache->adjust_bounded_subtree_auth(dir, p->second, pair(mds->get_nodeid(), mds->get_nodeid())); } else { // not ambiguous mds->mdcache->adjust_bounded_subtree_auth(dir, p->second, mds->get_nodeid()); } } mds->mdcache->show_subtrees(); } // ----------------------- // EFragment void EFragment::replay(MDS *mds) { dout(10) << "EFragment.replay " << op_name(op) << " " << ino << " " << basefrag << " by " << bits << dendl; list resultfrags; list waiters; list old_frags; // in may be NULL if it wasn't in our cache yet. if it's a prepare // it will be once we replay the metablob , but first we need to // refragment anything we already have in the cache. CInode *in = mds->mdcache->get_inode(ino); switch (op) { case OP_PREPARE: mds->mdcache->add_uncommitted_fragment(dirfrag_t(ino, basefrag), bits, orig_frags, _segment, &rollback); // fall-thru case OP_ONESHOT: if (in) mds->mdcache->adjust_dir_fragments(in, basefrag, bits, resultfrags, waiters, true); break; case OP_ROLLBACK: if (in) { in->dirfragtree.get_leaves_under(basefrag, old_frags); if (orig_frags.empty()) { // old format EFragment mds->mdcache->adjust_dir_fragments(in, basefrag, -bits, resultfrags, waiters, true); } else { for (list::iterator p = orig_frags.begin(); p != orig_frags.end(); ++p) mds->mdcache->force_dir_fragment(in, *p); } } mds->mdcache->rollback_uncommitted_fragment(dirfrag_t(ino, basefrag), old_frags); break; case OP_COMMIT: case OP_FINISH: mds->mdcache->finish_uncommitted_fragment(dirfrag_t(ino, basefrag), op); break; default: assert(0); } metablob.replay(mds, _segment); if (in && g_conf->mds_debug_frag) in->verify_dirfrags(); } void EFragment::encode(bufferlist &bl) const { ENCODE_START(5, 4, bl); ::encode(stamp, bl); ::encode(op, bl); ::encode(ino, bl); ::encode(basefrag, bl); ::encode(bits, bl); ::encode(metablob, bl); ::encode(orig_frags, bl); ::encode(rollback, bl); ENCODE_FINISH(bl); } void EFragment::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 4, 4, bl); if (struct_v >= 2) ::decode(stamp, bl); if (struct_v >= 3) ::decode(op, bl); else op = OP_ONESHOT; ::decode(ino, bl); ::decode(basefrag, bl); ::decode(bits, bl); ::decode(metablob, bl); if (struct_v >= 5) { ::decode(orig_frags, bl); ::decode(rollback, bl); } DECODE_FINISH(bl); } void EFragment::dump(Formatter *f) const { /*f->open_object_section("Metablob"); metablob.dump(f); // sadly we don't have this; dunno if we'll get it f->close_section();*/ f->dump_string("op", op_name(op)); f->dump_stream("ino") << ino; f->dump_stream("base frag") << basefrag; f->dump_int("bits", bits); } void EFragment::generate_test_instances(list& ls) { ls.push_back(new EFragment); ls.push_back(new EFragment); ls.back()->op = OP_PREPARE; ls.back()->ino = 1; ls.back()->bits = 5; } void dirfrag_rollback::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(fnode, bl); ENCODE_FINISH(bl); } void dirfrag_rollback::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(fnode, bl); DECODE_FINISH(bl); } // ========================================================================= // ----------------------- // EExport void EExport::replay(MDS *mds) { dout(10) << "EExport.replay " << base << dendl; metablob.replay(mds, _segment); CDir *dir = mds->mdcache->get_dirfrag(base); assert(dir); set realbounds; for (set::iterator p = bounds.begin(); p != bounds.end(); ++p) { CDir *bd = mds->mdcache->get_dirfrag(*p); assert(bd); realbounds.insert(bd); } // adjust auth away mds->mdcache->adjust_bounded_subtree_auth(dir, realbounds, CDIR_AUTH_UNDEF); mds->mdcache->try_trim_non_auth_subtree(dir); } void EExport::encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(metablob, bl); ::encode(base, bl); ::encode(bounds, bl); ENCODE_FINISH(bl); } void EExport::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(metablob, bl); ::decode(base, bl); ::decode(bounds, bl); DECODE_FINISH(bl); } void EExport::dump(Formatter *f) const { f->dump_float("stamp", (double)stamp); /*f->open_object_section("Metablob"); metablob.dump(f); // sadly we don't have this; dunno if we'll get it f->close_section();*/ f->dump_stream("base dirfrag") << base; f->open_array_section("bounds dirfrags"); for (set::const_iterator i = bounds.begin(); i != bounds.end(); ++i) { f->dump_stream("dirfrag") << *i; } f->close_section(); // bounds dirfrags } void EExport::generate_test_instances(list& ls) { EExport *sample = new EExport(); ls.push_back(sample); } // ----------------------- // EImportStart void EImportStart::update_segment() { _segment->sessionmapv = cmapv; } void EImportStart::replay(MDS *mds) { dout(10) << "EImportStart.replay " << base << " bounds " << bounds << dendl; //metablob.print(*_dout); metablob.replay(mds, _segment); // put in ambiguous import list mds->mdcache->add_ambiguous_import(base, bounds); // set auth partially to us so we don't trim it CDir *dir = mds->mdcache->get_dirfrag(base); assert(dir); mds->mdcache->adjust_bounded_subtree_auth(dir, bounds, pair(mds->get_nodeid(), mds->get_nodeid())); // open client sessions? if (mds->sessionmap.version >= cmapv) { dout(10) << "EImportStart.replay sessionmap " << mds->sessionmap.version << " >= " << cmapv << ", noop" << dendl; } else { dout(10) << "EImportStart.replay sessionmap " << mds->sessionmap.version << " < " << cmapv << dendl; map cm; bufferlist::iterator blp = client_map.begin(); ::decode(cm, blp); mds->sessionmap.open_sessions(cm); assert(mds->sessionmap.version == cmapv); mds->sessionmap.projected = mds->sessionmap.version; } update_segment(); } void EImportStart::encode(bufferlist &bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(base, bl); ::encode(metablob, bl); ::encode(bounds, bl); ::encode(cmapv, bl); ::encode(client_map, bl); ENCODE_FINISH(bl); } void EImportStart::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(base, bl); ::decode(metablob, bl); ::decode(bounds, bl); ::decode(cmapv, bl); ::decode(client_map, bl); DECODE_FINISH(bl); } void EImportStart::dump(Formatter *f) const { f->dump_stream("base dirfrag") << base; f->open_array_section("boundary dirfrags"); for (vector::const_iterator iter = bounds.begin(); iter != bounds.end(); ++iter) { f->dump_stream("frag") << *iter; } f->close_section(); } void EImportStart::generate_test_instances(list& ls) { ls.push_back(new EImportStart); } // ----------------------- // EImportFinish void EImportFinish::replay(MDS *mds) { if (mds->mdcache->have_ambiguous_import(base)) { dout(10) << "EImportFinish.replay " << base << " success=" << success << dendl; if (success) { mds->mdcache->finish_ambiguous_import(base); } else { CDir *dir = mds->mdcache->get_dirfrag(base); assert(dir); vector bounds; mds->mdcache->get_ambiguous_import_bounds(base, bounds); mds->mdcache->adjust_bounded_subtree_auth(dir, bounds, CDIR_AUTH_UNDEF); mds->mdcache->cancel_ambiguous_import(dir); mds->mdcache->try_trim_non_auth_subtree(dir); } } else { dout(10) << "EImportFinish.replay " << base << " success=" << success << " on subtree not marked as ambiguous" << dendl; assert(0 == "this shouldn't happen unless this is an old journal"); } } void EImportFinish::encode(bufferlist& bl) const { ENCODE_START(3, 3, bl); ::encode(stamp, bl); ::encode(base, bl); ::encode(success, bl); ENCODE_FINISH(bl); } void EImportFinish::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); if (struct_v >= 2) ::decode(stamp, bl); ::decode(base, bl); ::decode(success, bl); DECODE_FINISH(bl); } void EImportFinish::dump(Formatter *f) const { f->dump_stream("base dirfrag") << base; f->dump_string("success", success ? "true" : "false"); } void EImportFinish::generate_test_instances(list& ls) { ls.push_back(new EImportFinish); ls.push_back(new EImportFinish); ls.back()->success = true; } // ------------------------ // EResetJournal void EResetJournal::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(stamp, bl); ENCODE_FINISH(bl); } void EResetJournal::decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(stamp, bl); DECODE_FINISH(bl); } void EResetJournal::dump(Formatter *f) const { f->dump_stream("timestamp") << stamp; } void EResetJournal::generate_test_instances(list& ls) { ls.push_back(new EResetJournal()); } void EResetJournal::replay(MDS *mds) { dout(1) << "EResetJournal" << dendl; mds->sessionmap.wipe(); mds->inotable->replay_reset(); if (mds->mdsmap->get_root() == mds->whoami) { CDir *rootdir = mds->mdcache->get_root()->get_or_open_dirfrag(mds->mdcache, frag_t()); mds->mdcache->adjust_subtree_auth(rootdir, mds->whoami); } CDir *mydir = mds->mdcache->get_myin()->get_or_open_dirfrag(mds->mdcache, frag_t()); mds->mdcache->adjust_subtree_auth(mydir, mds->whoami); mds->mdcache->show_subtrees(); } ceph-0.80.11/src/mds/MDSMap.cc0000664000175100017510000004126112623076744017643 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "MDSMap.h" #include using std::stringstream; // features CompatSet get_mdsmap_compat_set_all() { CompatSet::FeatureSet feature_compat; CompatSet::FeatureSet feature_ro_compat; CompatSet::FeatureSet feature_incompat; feature_incompat.insert(MDS_FEATURE_INCOMPAT_BASE); feature_incompat.insert(MDS_FEATURE_INCOMPAT_CLIENTRANGES); feature_incompat.insert(MDS_FEATURE_INCOMPAT_FILELAYOUT); feature_incompat.insert(MDS_FEATURE_INCOMPAT_DIRINODE); feature_incompat.insert(MDS_FEATURE_INCOMPAT_ENCODING); feature_incompat.insert(MDS_FEATURE_INCOMPAT_OMAPDIRFRAG); feature_incompat.insert(MDS_FEATURE_INCOMPAT_INLINE); return CompatSet(feature_compat, feature_ro_compat, feature_incompat); } CompatSet get_mdsmap_compat_set_default() { CompatSet::FeatureSet feature_compat; CompatSet::FeatureSet feature_ro_compat; CompatSet::FeatureSet feature_incompat; feature_incompat.insert(MDS_FEATURE_INCOMPAT_BASE); feature_incompat.insert(MDS_FEATURE_INCOMPAT_CLIENTRANGES); feature_incompat.insert(MDS_FEATURE_INCOMPAT_FILELAYOUT); feature_incompat.insert(MDS_FEATURE_INCOMPAT_DIRINODE); feature_incompat.insert(MDS_FEATURE_INCOMPAT_ENCODING); feature_incompat.insert(MDS_FEATURE_INCOMPAT_OMAPDIRFRAG); return CompatSet(feature_compat, feature_ro_compat, feature_incompat); } // base (pre v0.20) CompatSet get_mdsmap_compat_set_base() { CompatSet::FeatureSet feature_compat_base; CompatSet::FeatureSet feature_incompat_base; feature_incompat_base.insert(MDS_FEATURE_INCOMPAT_BASE); CompatSet::FeatureSet feature_ro_compat_base; return CompatSet(feature_compat_base, feature_incompat_base, feature_ro_compat_base); } void MDSMap::mds_info_t::dump(Formatter *f) const { f->dump_unsigned("gid", global_id); f->dump_string("name", name); f->dump_int("rank", rank); f->dump_int("incarnation", inc); f->dump_stream("state") << ceph_mds_state_name(state); f->dump_int("state_seq", state_seq); f->dump_stream("addr") << addr; if (laggy_since != utime_t()) f->dump_stream("laggy_since") << laggy_since; f->dump_int("standby_for_rank", standby_for_rank); f->dump_string("standby_for_name", standby_for_name); f->open_array_section("export_targets"); for (set::iterator p = export_targets.begin(); p != export_targets.end(); ++p) { f->dump_int("mds", *p); } f->close_section(); } void MDSMap::mds_info_t::generate_test_instances(list& ls) { mds_info_t *sample = new mds_info_t(); ls.push_back(sample); sample = new mds_info_t(); sample->global_id = 1; sample->name = "test_instance"; sample->rank = 0; ls.push_back(sample); } void MDSMap::dump(Formatter *f) const { f->dump_int("epoch", epoch); f->dump_unsigned("flags", flags); f->dump_stream("created") << created; f->dump_stream("modified") << modified; f->dump_int("tableserver", tableserver); f->dump_int("root", root); f->dump_int("session_timeout", session_timeout); f->dump_int("session_autoclose", session_autoclose); f->dump_int("max_file_size", max_file_size); f->dump_int("last_failure", last_failure); f->dump_int("last_failure_osd_epoch", last_failure_osd_epoch); f->open_object_section("compat"); compat.dump(f); f->close_section(); f->dump_int("max_mds", max_mds); f->open_array_section("in"); for (set::const_iterator p = in.begin(); p != in.end(); ++p) f->dump_int("mds", *p); f->close_section(); f->open_object_section("up"); for (map::const_iterator p = up.begin(); p != up.end(); ++p) { char s[10]; sprintf(s, "mds_%d", p->first); f->dump_int(s, p->second); } f->close_section(); f->open_array_section("failed"); for (set::const_iterator p = failed.begin(); p != failed.end(); ++p) f->dump_int("mds", *p); f->close_section(); f->open_array_section("stopped"); for (set::const_iterator p = stopped.begin(); p != stopped.end(); ++p) f->dump_int("mds", *p); f->close_section(); f->open_object_section("info"); for (map::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) { char s[25]; // 'gid_' + len(str(ULLONG_MAX)) + '\0' sprintf(s, "gid_%llu", (long long unsigned)p->first); f->open_object_section(s); p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("data_pools"); for (set::const_iterator p = data_pools.begin(); p != data_pools.end(); ++p) f->dump_int("pool", *p); f->close_section(); f->dump_int("metadata_pool", metadata_pool); } void MDSMap::generate_test_instances(list& ls) { MDSMap *m = new MDSMap(); m->max_mds = 1; m->data_pools.insert(0); m->metadata_pool = 1; m->cas_pool = 2; m->compat = get_mdsmap_compat_set_all(); // these aren't the defaults, just in case anybody gets confused m->session_timeout = 61; m->session_autoclose = 301; m->max_file_size = 1<<24; ls.push_back(m); } void MDSMap::print(ostream& out) { out << "epoch\t" << epoch << "\n"; out << "flags\t" << hex << flags << dec << "\n"; out << "created\t" << created << "\n"; out << "modified\t" << modified << "\n"; out << "tableserver\t" << tableserver << "\n"; out << "root\t" << root << "\n"; out << "session_timeout\t" << session_timeout << "\n" << "session_autoclose\t" << session_autoclose << "\n"; out << "max_file_size\t" << max_file_size << "\n"; out << "last_failure\t" << last_failure << "\n" << "last_failure_osd_epoch\t" << last_failure_osd_epoch << "\n"; out << "compat\t" << compat << "\n"; out << "max_mds\t" << max_mds << "\n"; out << "in\t" << in << "\n" << "up\t" << up << "\n" << "failed\t" << failed << "\n" << "stopped\t" << stopped << "\n"; out << "data_pools\t" << data_pools << "\n"; out << "metadata_pool\t" << metadata_pool << "\n"; out << "inline_data\t" << (inline_data_enabled ? "enabled" : "disabled") << "\n"; multimap< pair, uint64_t > foo; for (map::iterator p = mds_info.begin(); p != mds_info.end(); ++p) foo.insert(pair,uint64_t>(pair(p->second.rank, p->second.inc-1), p->first)); for (multimap< pair, uint64_t >::iterator p = foo.begin(); p != foo.end(); ++p) { mds_info_t& info = mds_info[p->second]; out << p->second << ":\t" << info.addr << " '" << info.name << "'" << " mds." << info.rank << "." << info.inc << " " << ceph_mds_state_name(info.state) << " seq " << info.state_seq; if (info.laggy()) out << " laggy since " << info.laggy_since; if (info.standby_for_rank != -1 || !info.standby_for_name.empty()) { out << " (standby for"; //if (info.standby_for_rank >= 0) out << " rank " << info.standby_for_rank; if (!info.standby_for_name.empty()) out << " '" << info.standby_for_name << "'"; out << ")"; } if (!info.export_targets.empty()) out << " export_targets=" << info.export_targets; out << "\n"; } } void MDSMap::print_summary(Formatter *f, ostream *out) { map by_rank; map by_state; if (f) { f->dump_unsigned("epoch", get_epoch()); f->dump_unsigned("up", up.size()); f->dump_unsigned("in", in.size()); f->dump_unsigned("max", max_mds); } else { *out << "e" << get_epoch() << ": " << up.size() << "/" << in.size() << "/" << max_mds << " up"; } if (f) f->open_array_section("by_rank"); for (map::iterator p = mds_info.begin(); p != mds_info.end(); ++p) { string s = ceph_mds_state_name(p->second.state); if (p->second.laggy()) s += "(laggy or crashed)"; if (p->second.rank >= 0) { if (f) { f->open_object_section("mds"); f->dump_unsigned("rank", p->second.rank); f->dump_string("name", p->second.name); f->dump_string("status", s); f->close_section(); } else { by_rank[p->second.rank] = p->second.name + "=" + s; } } else { by_state[s]++; } } if (f) { f->close_section(); } else { if (!by_rank.empty()) *out << " " << by_rank; } for (map::reverse_iterator p = by_state.rbegin(); p != by_state.rend(); ++p) { if (f) { f->dump_unsigned(p->first.c_str(), p->second); } else { *out << ", " << p->second << " " << p->first; } } if (!failed.empty()) { if (f) { f->dump_unsigned("failed", failed.size()); } else { *out << ", " << failed.size() << " failed"; } } //if (stopped.size()) //out << ", " << stopped.size() << " stopped"; } void MDSMap::get_health(list >& summary, list > *detail) const { if (!failed.empty()) { std::ostringstream oss; oss << "mds rank" << ((failed.size() > 1) ? "s ":" ") << failed << ((failed.size() > 1) ? " have":" has") << " failed"; summary.push_back(make_pair(HEALTH_ERR, oss.str())); if (detail) { for (set::const_iterator p = failed.begin(); p != failed.end(); ++p) { std::ostringstream oss; oss << "mds." << *p << " has failed"; detail->push_back(make_pair(HEALTH_ERR, oss.str())); } } } if (is_degraded()) { summary.push_back(make_pair(HEALTH_WARN, "mds cluster is degraded")); if (detail) { detail->push_back(make_pair(HEALTH_WARN, "mds cluster is degraded")); for (unsigned i=0; i< get_max_mds(); i++) { if (!is_up(i)) continue; uint64_t gid = up.find(i)->second; map::const_iterator info = mds_info.find(gid); stringstream ss; if (is_resolve(i)) ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is resolving"; if (is_replay(i)) ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is replaying journal"; if (is_rejoin(i)) ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is rejoining"; if (is_reconnect(i)) ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is reconnecting to clients"; if (ss.str().length()) detail->push_back(make_pair(HEALTH_WARN, ss.str())); } } } map::const_iterator u = up.begin(); map::const_iterator u_end = up.end(); map::const_iterator m_end = mds_info.end(); set laggy; for (; u != u_end; ++u) { map::const_iterator m = mds_info.find(u->second); assert(m != m_end); const mds_info_t &mds_info(m->second); if (mds_info.laggy()) { laggy.insert(mds_info.name); if (detail) { std::ostringstream oss; oss << "mds." << mds_info.name << " at " << mds_info.addr << " is laggy/unresponsive"; detail->push_back(make_pair(HEALTH_WARN, oss.str())); } } } if (!laggy.empty()) { std::ostringstream oss; oss << "mds " << laggy << ((laggy.size() > 1) ? " are":" is") << " laggy"; summary.push_back(make_pair(HEALTH_WARN, oss.str())); } } void MDSMap::mds_info_t::encode_versioned(bufferlist& bl, uint64_t features) const { ENCODE_START(4, 4, bl); ::encode(global_id, bl); ::encode(name, bl); ::encode(rank, bl); ::encode(inc, bl); ::encode(state, bl); ::encode(state_seq, bl); ::encode(addr, bl); ::encode(laggy_since, bl); ::encode(standby_for_rank, bl); ::encode(standby_for_name, bl); ::encode(export_targets, bl); ENCODE_FINISH(bl); } void MDSMap::mds_info_t::encode_unversioned(bufferlist& bl) const { __u8 struct_v = 3; ::encode(struct_v, bl); ::encode(global_id, bl); ::encode(name, bl); ::encode(rank, bl); ::encode(inc, bl); ::encode(state, bl); ::encode(state_seq, bl); ::encode(addr, bl); ::encode(laggy_since, bl); ::encode(standby_for_rank, bl); ::encode(standby_for_name, bl); ::encode(export_targets, bl); } void MDSMap::mds_info_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 4, 4, bl); ::decode(global_id, bl); ::decode(name, bl); ::decode(rank, bl); ::decode(inc, bl); ::decode(state, bl); ::decode(state_seq, bl); ::decode(addr, bl); ::decode(laggy_since, bl); ::decode(standby_for_rank, bl); ::decode(standby_for_name, bl); if (struct_v >= 2) ::decode(export_targets, bl); DECODE_FINISH(bl); } void MDSMap::encode(bufferlist& bl, uint64_t features) const { if ((features & CEPH_FEATURE_PGID64) == 0) { __u16 v = 2; ::encode(v, bl); ::encode(epoch, bl); ::encode(flags, bl); ::encode(last_failure, bl); ::encode(root, bl); ::encode(session_timeout, bl); ::encode(session_autoclose, bl); ::encode(max_file_size, bl); ::encode(max_mds, bl); __u32 n = mds_info.size(); ::encode(n, bl); for (map::const_iterator i = mds_info.begin(); i != mds_info.end(); ++i) { ::encode(i->first, bl); ::encode(i->second, bl, features); } n = data_pools.size(); ::encode(n, bl); for (set::const_iterator p = data_pools.begin(); p != data_pools.end(); ++p) { n = *p; ::encode(n, bl); } int32_t m = cas_pool; ::encode(m, bl); return; } else if ((features & CEPH_FEATURE_MDSENC) == 0) { __u16 v = 3; ::encode(v, bl); ::encode(epoch, bl); ::encode(flags, bl); ::encode(last_failure, bl); ::encode(root, bl); ::encode(session_timeout, bl); ::encode(session_autoclose, bl); ::encode(max_file_size, bl); ::encode(max_mds, bl); __u32 n = mds_info.size(); ::encode(n, bl); for (map::const_iterator i = mds_info.begin(); i != mds_info.end(); ++i) { ::encode(i->first, bl); ::encode(i->second, bl, features); } ::encode(data_pools, bl); ::encode(cas_pool, bl); // kclient ignores everything from here __u16 ev = 5; ::encode(ev, bl); ::encode(compat, bl); ::encode(metadata_pool, bl); ::encode(created, bl); ::encode(modified, bl); ::encode(tableserver, bl); ::encode(in, bl); ::encode(inc, bl); ::encode(up, bl); ::encode(failed, bl); ::encode(stopped, bl); ::encode(last_failure_osd_epoch, bl); } else {// have MDS encoding feature! ENCODE_START(4, 4, bl); ::encode(epoch, bl); ::encode(flags, bl); ::encode(last_failure, bl); ::encode(root, bl); ::encode(session_timeout, bl); ::encode(session_autoclose, bl); ::encode(max_file_size, bl); ::encode(max_mds, bl); ::encode(mds_info, bl, features); ::encode(data_pools, bl); ::encode(cas_pool, bl); // kclient ignores everything from here __u16 ev = 7; ::encode(ev, bl); ::encode(compat, bl); ::encode(metadata_pool, bl); ::encode(created, bl); ::encode(modified, bl); ::encode(tableserver, bl); ::encode(in, bl); ::encode(inc, bl); ::encode(up, bl); ::encode(failed, bl); ::encode(stopped, bl); ::encode(last_failure_osd_epoch, bl); ::encode(ever_allowed_snaps, bl); ::encode(explicitly_allowed_snaps, bl); ::encode(inline_data_enabled, bl); ENCODE_FINISH(bl); } } void MDSMap::decode(bufferlist::iterator& p) { DECODE_START_LEGACY_COMPAT_LEN_16(4, 4, 4, p); ::decode(epoch, p); ::decode(flags, p); ::decode(last_failure, p); ::decode(root, p); ::decode(session_timeout, p); ::decode(session_autoclose, p); ::decode(max_file_size, p); ::decode(max_mds, p); ::decode(mds_info, p); if (struct_v < 3) { __u32 n; ::decode(n, p); while (n--) { __u32 m; ::decode(m, p); data_pools.insert(m); } __s32 s; ::decode(s, p); cas_pool = s; } else { ::decode(data_pools, p); ::decode(cas_pool, p); } // kclient ignores everything from here __u16 ev = 1; if (struct_v >= 2) ::decode(ev, p); if (ev >= 3) ::decode(compat, p); else compat = get_mdsmap_compat_set_base(); if (ev < 5) { __u32 n; ::decode(n, p); metadata_pool = n; } else { ::decode(metadata_pool, p); } ::decode(created, p); ::decode(modified, p); ::decode(tableserver, p); ::decode(in, p); ::decode(inc, p); ::decode(up, p); ::decode(failed, p); ::decode(stopped, p); if (ev >= 4) ::decode(last_failure_osd_epoch, p); if (ev >= 6) { ::decode(ever_allowed_snaps, p); ::decode(explicitly_allowed_snaps, p); } else { ever_allowed_snaps = true; explicitly_allowed_snaps = false; } if (ev >= 7) ::decode(inline_data_enabled, p); DECODE_FINISH(p); } ceph-0.80.11/src/mds/mds_table_types.h0000664000175100017510000000360312623076744021600 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSTABLETYPES_H #define CEPH_MDSTABLETYPES_H // MDS TABLES enum { TABLE_ANCHOR, TABLE_SNAP, }; inline const char *get_mdstable_name(int t) { switch (t) { case TABLE_ANCHOR: return "anchortable"; case TABLE_SNAP: return "snaptable"; default: assert(0); } } enum { TABLESERVER_OP_QUERY = 1, TABLESERVER_OP_QUERY_REPLY = -2, TABLESERVER_OP_PREPARE = 3, TABLESERVER_OP_AGREE = -4, TABLESERVER_OP_COMMIT = 5, TABLESERVER_OP_ACK = -6, TABLESERVER_OP_ROLLBACK = 7, TABLESERVER_OP_SERVER_UPDATE = 8, TABLESERVER_OP_SERVER_READY = -9, }; inline const char *get_mdstableserver_opname(int op) { switch (op) { case TABLESERVER_OP_QUERY: return "query"; case TABLESERVER_OP_QUERY_REPLY: return "query_reply"; case TABLESERVER_OP_PREPARE: return "prepare"; case TABLESERVER_OP_AGREE: return "agree"; case TABLESERVER_OP_COMMIT: return "commit"; case TABLESERVER_OP_ACK: return "ack"; case TABLESERVER_OP_ROLLBACK: return "rollback"; case TABLESERVER_OP_SERVER_UPDATE: return "server_update"; case TABLESERVER_OP_SERVER_READY: return "server_ready"; default: assert(0); return 0; } }; enum { TABLE_OP_CREATE, TABLE_OP_UPDATE, TABLE_OP_DESTROY, }; inline const char *get_mdstable_opname(int op) { switch (op) { case TABLE_OP_CREATE: return "create"; case TABLE_OP_UPDATE: return "update"; case TABLE_OP_DESTROY: return "destroy"; default: assert(0); return 0; } }; #endif ceph-0.80.11/src/mds/MDSTableClient.h0000664000175100017510000000473512623076744021163 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDSTABLECLIENT_H #define CEPH_MDSTABLECLIENT_H #include "include/types.h" #include "include/Context.h" #include "mds_table_types.h" class MDS; class LogSegment; class MMDSTableRequest; class MDSTableClient { protected: MDS *mds; int table; uint64_t last_reqid; bool server_ready; // prepares struct _pending_prepare { Context *onfinish; version_t *ptid; bufferlist *pbl; bufferlist mutation; _pending_prepare() : onfinish(0), ptid(0), pbl(0) {} _pending_prepare(Context *c, version_t *pt, bufferlist *pb, bufferlist& m) : onfinish(c), ptid(pt), pbl(pb), mutation(m) {} }; map pending_prepare; map prepared_update; list<_pending_prepare> waiting_for_reqid; // pending commits map pending_commit; map > ack_waiters; void handle_reply(class MMDSTableQuery *m); class C_LoggedAck : public Context { MDSTableClient *tc; version_t tid; public: C_LoggedAck(MDSTableClient *a, version_t t) : tc(a), tid(t) {} void finish(int r) { tc->_logged_ack(tid); } }; void _logged_ack(version_t tid); public: MDSTableClient(MDS *m, int tab) : mds(m), table(tab), last_reqid(~0ULL), server_ready(false) {} virtual ~MDSTableClient() {} void handle_request(MMDSTableRequest *m); void _prepare(bufferlist& mutation, version_t *ptid, bufferlist *pbl, Context *onfinish); void commit(version_t tid, LogSegment *ls); void resend_commits(); void resend_prepares(); // for recovery (by me) void got_journaled_agree(version_t tid, LogSegment *ls); void got_journaled_ack(version_t tid); bool has_committed(version_t tid) { return pending_commit.count(tid) == 0; } void wait_for_ack(version_t tid, Context *c) { ack_waiters[tid].push_back(c); } void handle_mds_failure(int mds); // child must implement virtual void resend_queries() = 0; virtual void handle_query_result(MMDSTableRequest *m) = 0; // and friendly front-end for _prepare. }; #endif ceph-0.80.11/src/mds/AnchorServer.cc0000664000175100017510000002116712623076744021166 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "AnchorServer.h" #include "MDS.h" #include "msg/Messenger.h" #include "messages/MMDSTableRequest.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".anchorserver " // table void AnchorServer::reset_state() { anchor_map.clear(); pending_create.clear(); pending_destroy.clear(); pending_update.clear(); pending_for_mds.clear(); } void AnchorServer::dump() { dout(7) << "dump v " << version << dendl; for (map::iterator it = anchor_map.begin(); it != anchor_map.end(); ++it) dout(15) << "dump " << it->second << dendl; } void AnchorServer::dump(Formatter *f) const { f->open_array_section("anchor map"); for (map::const_iterator i = anchor_map.begin(); i != anchor_map.end(); ++i) { f->open_object_section("entry"); f->dump_int("ino", i->first); f->open_object_section("Anchor"); i->second.dump(f); f->close_section(); // Anchor f->close_section(); // entry } f->close_section(); // anchor map } void AnchorServer::generate_test_instances(list& ls) { AnchorServer *sample = new AnchorServer(); sample->pending_create[0] = 0; sample->pending_destroy[0] = 1; sample->anchor_map[0] = Anchor(); ls.push_back(sample); } /* * basic updates * Returns true if it changed the anchor_map contents. */ bool AnchorServer::add(inodeno_t ino, inodeno_t dirino, __u32 dn_hash, bool replace) { //dout(17) << "add " << ino << " dirfrag " << dirfrag << dendl; // parent should be there assert(MDS_INO_IS_BASE(dirino) || // base case, anchor_map.count(dirino)); // or have it if (anchor_map.count(ino) == 0) { // new item anchor_map[ino] = Anchor(ino, dirino, dn_hash, 0, version); dout(7) << "add added " << anchor_map[ino] << dendl; } else if (replace) { anchor_map[ino].dirino = dirino; anchor_map[ino].dn_hash = dn_hash; dout(7) << "add had old Anchor, updated it to " << anchor_map[ino] << dendl; } else { dout(7) << "add had " << anchor_map[ino] << dendl; return false; } return true; } void AnchorServer::inc(inodeno_t ino, int ref) { dout(7) << "inc " << ino << dendl; assert(anchor_map.count(ino)); while (1) { Anchor &anchor = anchor_map[ino]; anchor.nref += ref; anchor.updated = version; dout(10) << "inc now " << anchor << dendl; ino = anchor.dirino; if (ino == 0 || MDS_INO_IS_BASE(ino)) break; if (anchor_map.count(ino) == 0) break; } } void AnchorServer::dec(inodeno_t ino, int ref) { dout(7) << "dec " << ino << dendl; assert(anchor_map.count(ino)); while (true) { Anchor &anchor = anchor_map[ino]; anchor.nref -= ref; anchor.updated = version; if (anchor.nref == 0) { dout(10) << "dec removing " << anchor << dendl; inodeno_t dirino = anchor.dirino; anchor_map.erase(ino); ino = dirino; } else { dout(10) << "dec now " << anchor << dendl; ino = anchor.dirino; } if (ino == 0) break; if (anchor_map.count(ino) == 0) break; } } // server void AnchorServer::_prepare(bufferlist &bl, uint64_t reqid, int bymds) { bufferlist::iterator p = bl.begin(); __u32 what; inodeno_t ino; vector trace; ::decode(what, p); ::decode(ino, p); switch (what) { case TABLE_OP_CREATE: ::decode(trace, p); version++; // make sure trace is in table dout(25) << "trace.size=" << trace.size() << dendl; for (unsigned i=0; i(version, NULL)); break; case TABLE_OP_DESTROY: version++; pending_destroy[version] = ino; pending_ops[ino].push_back(pair(version, NULL)); break; case TABLE_OP_UPDATE: ::decode(trace, p); version++; pending_update[version].first = ino; pending_update[version].second = trace; pending_ops[ino].push_back(pair(version, NULL)); break; default: assert(0); } //dump(); } bool AnchorServer::check_pending(version_t tid, MMDSTableRequest *req, list& finished) { inodeno_t ino; if (pending_create.count(tid)) ino = pending_create[tid]; else if (pending_destroy.count(tid)) ino = pending_destroy[tid]; else if (pending_update.count(tid)) ino = pending_update[tid].first; else assert(0); assert(pending_ops.count(ino)); list< pair >& pending = pending_ops[ino]; list< pair >::iterator p = pending.begin(); if (p->first == tid) { assert(p->second == NULL); } else { while (p != pending.end()) { if (p->first == tid) break; ++p; } assert(p != pending.end()); assert(p->second == NULL); // not the earliest pending operation, wait if it's a commit if (req) { p->second = new C_MDS_RetryMessage(mds, req); return false; } } pending.erase(p); if (pending.empty()) { pending_ops.erase(ino); } else { for (p = pending.begin(); p != pending.end() && p->second; ++p) { finished.push_back(p->second); p->second = NULL; } } return true; } bool AnchorServer::_commit(version_t tid, MMDSTableRequest *req) { list finished; if (!check_pending(tid, req, finished)) return false; if (pending_create.count(tid)) { dout(7) << "commit " << tid << " create " << pending_create[tid] << dendl; pending_create.erase(tid); } else if (pending_destroy.count(tid)) { inodeno_t ino = pending_destroy[tid]; dout(7) << "commit " << tid << " destroy " << ino << dendl; dec(ino); // destroy pending_destroy.erase(tid); } else if (pending_update.count(tid)) { inodeno_t ino = pending_update[tid].first; vector &trace = pending_update[tid].second; if (anchor_map.count(ino)) { dout(7) << "commit " << tid << " update " << ino << dendl; int ref = anchor_map[ino].nref; // remove old dec(ino, ref); // add new for (unsigned i=0; iqueue_waiters(finished); return true; } void AnchorServer::_rollback(version_t tid) { list finished; check_pending(tid, NULL, finished); if (pending_create.count(tid)) { inodeno_t ino = pending_create[tid]; dout(7) << "rollback " << tid << " create " << ino << dendl; dec(ino); pending_create.erase(tid); } else if (pending_destroy.count(tid)) { inodeno_t ino = pending_destroy[tid]; dout(7) << "rollback " << tid << " destroy " << ino << dendl; pending_destroy.erase(tid); } else if (pending_update.count(tid)) { inodeno_t ino = pending_update[tid].first; dout(7) << "rollback " << tid << " update " << ino << dendl; pending_update.erase(tid); } else assert(0); // bump version. version++; //dump(); mds->queue_waiters(finished); } /* This function DOES put the passed message before returning */ void AnchorServer::handle_query(MMDSTableRequest *req) { bufferlist::iterator p = req->bl.begin(); inodeno_t ino; ::decode(ino, p); dout(7) << "handle_lookup " << *req << " ino " << ino << dendl; vector trace; inodeno_t curino = ino; while (true) { assert(anchor_map.count(curino) == 1); Anchor &anchor = anchor_map[curino]; dout(10) << "handle_lookup adding " << anchor << dendl; trace.insert(trace.begin(), anchor); // lame FIXME if (MDS_INO_IS_BASE(anchor.dirino)) break; curino = anchor.dirino; } // reply MMDSTableRequest *reply = new MMDSTableRequest(table, TABLESERVER_OP_QUERY_REPLY, req->reqid, version); ::encode(ino, reply->bl); ::encode(trace, reply->bl); mds->send_message(reply, req->get_connection()); req->put(); } ceph-0.80.11/src/mds/SimpleLock.h0000664000175100017510000004505612623076744020474 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SIMPLELOCK_H #define CEPH_SIMPLELOCK_H // -- lock types -- // see CEPH_LOCK_* inline const char *get_lock_type_name(int t) { switch (t) { case CEPH_LOCK_DN: return "dn"; case CEPH_LOCK_DVERSION: return "dversion"; case CEPH_LOCK_IVERSION: return "iversion"; case CEPH_LOCK_IFILE: return "ifile"; case CEPH_LOCK_IAUTH: return "iauth"; case CEPH_LOCK_ILINK: return "ilink"; case CEPH_LOCK_IDFT: return "idft"; case CEPH_LOCK_INEST: return "inest"; case CEPH_LOCK_IXATTR: return "ixattr"; case CEPH_LOCK_ISNAP: return "isnap"; case CEPH_LOCK_INO: return "ino"; case CEPH_LOCK_IFLOCK: return "iflock"; case CEPH_LOCK_IPOLICY: return "ipolicy"; default: assert(0); return 0; } } #include "include/memory.h" struct MutationImpl; typedef ceph::shared_ptr MutationRef; extern "C" { #include "locks.h" } #define CAP_ANY 0 #define CAP_LONER 1 #define CAP_XLOCKER 2 struct LockType { int type; const sm_t *sm; LockType(int t) : type(t) { switch (type) { case CEPH_LOCK_DN: case CEPH_LOCK_IAUTH: case CEPH_LOCK_ILINK: case CEPH_LOCK_IXATTR: case CEPH_LOCK_ISNAP: case CEPH_LOCK_IFLOCK: case CEPH_LOCK_IPOLICY: sm = &sm_simplelock; break; case CEPH_LOCK_IDFT: case CEPH_LOCK_INEST: sm = &sm_scatterlock; break; case CEPH_LOCK_IFILE: sm = &sm_filelock; break; case CEPH_LOCK_DVERSION: case CEPH_LOCK_IVERSION: sm = &sm_locallock; break; default: sm = 0; } } }; class SimpleLock { public: LockType *type; const char *get_state_name(int n) const { switch (n) { case LOCK_UNDEF: return "UNDEF"; case LOCK_SYNC: return "sync"; case LOCK_LOCK: return "lock"; case LOCK_PREXLOCK: return "prexlock"; case LOCK_XLOCK: return "xlock"; case LOCK_XLOCKDONE: return "xlockdone"; case LOCK_LOCK_XLOCK: return "lock->xlock"; case LOCK_SYNC_LOCK: return "sync->lock"; case LOCK_LOCK_SYNC: return "lock->sync"; case LOCK_REMOTEXLOCK: return "remote_xlock"; case LOCK_EXCL: return "excl"; case LOCK_EXCL_SYNC: return "excl->sync"; case LOCK_EXCL_LOCK: return "excl->lock"; case LOCK_SYNC_EXCL: return "sync->excl"; case LOCK_LOCK_EXCL: return "lock->excl"; case LOCK_XSYN: return "xsyn"; case LOCK_XSYN_EXCL: return "xsyn->excl"; case LOCK_EXCL_XSYN: return "excl->xsyn"; case LOCK_XSYN_SYNC: return "xsyn->sync"; case LOCK_SYNC_MIX: return "sync->mix"; case LOCK_SYNC_MIX2: return "sync->mix(2)"; case LOCK_LOCK_TSYN: return "lock->tsyn"; case LOCK_MIX_LOCK: return "mix->lock"; case LOCK_MIX_LOCK2: return "mix->lock(2)"; case LOCK_MIX: return "mix"; case LOCK_MIX_TSYN: return "mix->tsyn"; case LOCK_TSYN_MIX: return "tsyn->mix"; case LOCK_TSYN_LOCK: return "tsyn->lock"; case LOCK_TSYN: return "tsyn"; case LOCK_MIX_SYNC: return "mix->sync"; case LOCK_MIX_SYNC2: return "mix->sync(2)"; case LOCK_EXCL_MIX: return "excl->mix"; case LOCK_MIX_EXCL: return "mix->excl"; case LOCK_PRE_SCAN: return "*->scan"; case LOCK_SCAN: return "scan"; case LOCK_SNAP_SYNC: return "snap->sync"; default: assert(0); return 0; } } // waiting static const uint64_t WAIT_RD = (1<<0); // to read static const uint64_t WAIT_WR = (1<<1); // to write static const uint64_t WAIT_XLOCK = (1<<2); // to xlock (** dup) static const uint64_t WAIT_STABLE = (1<<2); // for a stable state static const uint64_t WAIT_REMOTEXLOCK = (1<<3); // for a remote xlock static const int WAIT_BITS = 4; static const uint64_t WAIT_ALL = ((1< gather_set; // auth+rep. >= 0 is mds, < 0 is client // local state int num_wrlock, num_xlock; MutationRef xlock_by; client_t xlock_by_client; client_t excl_client; bool empty() { return gather_set.empty() && num_wrlock == 0 && num_xlock == 0 && xlock_by.get() == NULL && xlock_by_client == -1 && excl_client == -1; } unstable_bits_t() : num_wrlock(0), num_xlock(0), xlock_by(), xlock_by_client(-1), excl_client(-1) {} }; mutable unstable_bits_t *_unstable; bool have_more() const { return _unstable ? true : false; } unstable_bits_t *more() const { if (!_unstable) _unstable = new unstable_bits_t; return _unstable; } void clear_more() { if (_unstable) { assert(_unstable->empty()); delete _unstable; _unstable = NULL; } } void try_clear_more() { if (_unstable && _unstable->empty()) { delete _unstable; _unstable = NULL; } } public: client_t get_excl_client() const { return have_more() ? more()->excl_client : -1; } void set_excl_client(client_t c) { if (c < 0 && !have_more()) return; // default is -1 more()->excl_client = c; } SimpleLock(MDSCacheObject *o, LockType *lt) : type(lt), parent(o), state(LOCK_SYNC), num_rdlock(0), num_client_lease(0), _unstable(NULL) {} virtual ~SimpleLock() { delete _unstable; } virtual bool is_scatterlock() const { return false; } virtual bool is_locallock() const { return false; } // parent MDSCacheObject *get_parent() { return parent; } int get_type() const { return type->type; } const sm_t* get_sm() const { return type->sm; } int get_wait_shift() const { switch (get_type()) { case CEPH_LOCK_DN: return 8; case CEPH_LOCK_DVERSION: return 8 + 1*SimpleLock::WAIT_BITS; case CEPH_LOCK_IAUTH: return 8 + 2*SimpleLock::WAIT_BITS; case CEPH_LOCK_ILINK: return 8 + 3*SimpleLock::WAIT_BITS; case CEPH_LOCK_IDFT: return 8 + 4*SimpleLock::WAIT_BITS; case CEPH_LOCK_IFILE: return 8 + 5*SimpleLock::WAIT_BITS; case CEPH_LOCK_IVERSION: return 8 + 6*SimpleLock::WAIT_BITS; case CEPH_LOCK_IXATTR: return 8 + 7*SimpleLock::WAIT_BITS; case CEPH_LOCK_ISNAP: return 8 + 8*SimpleLock::WAIT_BITS; case CEPH_LOCK_INEST: return 8 + 9*SimpleLock::WAIT_BITS; case CEPH_LOCK_IFLOCK: return 8 +10*SimpleLock::WAIT_BITS; case CEPH_LOCK_IPOLICY: return 8 +11*SimpleLock::WAIT_BITS; default: assert(0); } } int get_cap_shift() const { switch (get_type()) { case CEPH_LOCK_IAUTH: return CEPH_CAP_SAUTH; case CEPH_LOCK_ILINK: return CEPH_CAP_SLINK; case CEPH_LOCK_IFILE: return CEPH_CAP_SFILE; case CEPH_LOCK_IXATTR: return CEPH_CAP_SXATTR; default: return 0; } } int get_cap_mask() const { switch (get_type()) { case CEPH_LOCK_IFILE: return (1 << CEPH_CAP_FILE_BITS) - 1; default: return (1 << CEPH_CAP_SIMPLE_BITS) - 1; } } struct ptr_lt { bool operator()(const SimpleLock* l, const SimpleLock* r) const { // first sort by object type (dn < inode) if ((l->type->type>CEPH_LOCK_DN) < (r->type->type>CEPH_LOCK_DN)) return true; if ((l->type->type>CEPH_LOCK_DN) == (r->type->type>CEPH_LOCK_DN)) { // then sort by object if (l->parent->is_lt(r->parent)) return true; if (l->parent == r->parent) { // then sort by (inode) lock type if (l->type->type < r->type->type) return true; } } return false; } }; void decode_locked_state(bufferlist& bl) { parent->decode_lock_state(type->type, bl); } void encode_locked_state(bufferlist& bl) { parent->encode_lock_state(type->type, bl); } void finish_waiters(uint64_t mask, int r=0) { parent->finish_waiting(mask << get_wait_shift(), r); } void take_waiting(uint64_t mask, list& ls) { parent->take_waiting(mask << get_wait_shift(), ls); } void add_waiter(uint64_t mask, Context *c) { parent->add_waiter(mask << get_wait_shift(), c); } bool is_waiter_for(uint64_t mask) const { return parent->is_waiter_for(mask << get_wait_shift()); } // state int get_state() const { return state; } int set_state(int s) { state = s; //assert(!is_stable() || gather_set.size() == 0); // gather should be empty in stable states. return s; } void set_state_rejoin(int s, list& waiters) { if (!is_stable() && get_parent()->is_auth()) { state = s; get_parent()->auth_unpin(this); } else { state = s; } if (is_stable()) take_waiting(SimpleLock::WAIT_ALL, waiters); } bool is_stable() const { return get_sm()->states[state].next == 0; } int get_next_state() { return get_sm()->states[state].next; } bool is_sync_and_unlocked() const { return get_state() == LOCK_SYNC && !is_rdlocked() && !is_leased() && !is_wrlocked() && !is_xlocked(); } /* bool fw_rdlock_to_auth() { return get_sm()->states[state].can_rdlock == FW; } */ bool req_rdlock_from_auth() { return get_sm()->states[state].can_rdlock == REQ; } // gather set static set empty_gather_set; const set& get_gather_set() const { return have_more() ? more()->gather_set : empty_gather_set; } void init_gather() { for (map::const_iterator p = parent->replicas_begin(); p != parent->replicas_end(); ++p) more()->gather_set.insert(p->first); } bool is_gathering() const { return have_more() && !more()->gather_set.empty(); } bool is_gathering(int i) const { return have_more() && more()->gather_set.count(i); } void clear_gather() { if (have_more()) more()->gather_set.clear(); } void remove_gather(int i) { if (have_more()) more()->gather_set.erase(i); } virtual bool is_dirty() const { return false; } virtual bool is_stale() const { return false; } virtual bool is_flushing() const { return false; } virtual bool is_flushed() const { return false; } virtual void clear_flushed() { } // can_* bool can_lease(client_t client) const { return get_sm()->states[state].can_lease == ANY || (get_sm()->states[state].can_lease == AUTH && parent->is_auth()) || (get_sm()->states[state].can_lease == XCL && client >= 0 && get_xlock_by_client() == client); } bool can_read(client_t client) const { return get_sm()->states[state].can_read == ANY || (get_sm()->states[state].can_read == AUTH && parent->is_auth()) || (get_sm()->states[state].can_read == XCL && client >= 0 && get_xlock_by_client() == client); } bool can_read_projected(client_t client) const { return get_sm()->states[state].can_read_projected == ANY || (get_sm()->states[state].can_read_projected == AUTH && parent->is_auth()) || (get_sm()->states[state].can_read_projected == XCL && client >= 0 && get_xlock_by_client() == client); } bool can_rdlock(client_t client) const { return get_sm()->states[state].can_rdlock == ANY || (get_sm()->states[state].can_rdlock == AUTH && parent->is_auth()) || (get_sm()->states[state].can_rdlock == XCL && client >= 0 && get_xlock_by_client() == client); } bool can_wrlock(client_t client) const { return get_sm()->states[state].can_wrlock == ANY || (get_sm()->states[state].can_wrlock == AUTH && parent->is_auth()) || (get_sm()->states[state].can_wrlock == XCL && client >= 0 && (get_xlock_by_client() == client || get_excl_client() == client)); } bool can_force_wrlock(client_t client) const { return get_sm()->states[state].can_force_wrlock == ANY || (get_sm()->states[state].can_force_wrlock == AUTH && parent->is_auth()) || (get_sm()->states[state].can_force_wrlock == XCL && client >= 0 && (get_xlock_by_client() == client || get_excl_client() == client)); } bool can_xlock(client_t client) const { return get_sm()->states[state].can_xlock == ANY || (get_sm()->states[state].can_xlock == AUTH && parent->is_auth()) || (get_sm()->states[state].can_xlock == XCL && client >= 0 && get_xlock_by_client() == client); } // rdlock bool is_rdlocked() const { return num_rdlock > 0; } int get_rdlock() { if (!num_rdlock) parent->get(MDSCacheObject::PIN_LOCK); return ++num_rdlock; } int put_rdlock() { assert(num_rdlock>0); --num_rdlock; if (num_rdlock == 0) parent->put(MDSCacheObject::PIN_LOCK); return num_rdlock; } int get_num_rdlocks() const { return num_rdlock; } // wrlock void get_wrlock(bool force=false) { //assert(can_wrlock() || force); if (more()->num_wrlock == 0) parent->get(MDSCacheObject::PIN_LOCK); ++more()->num_wrlock; } void put_wrlock() { --more()->num_wrlock; if (more()->num_wrlock == 0) { parent->put(MDSCacheObject::PIN_LOCK); try_clear_more(); } } bool is_wrlocked() const { return have_more() && more()->num_wrlock > 0; } int get_num_wrlocks() const { return have_more() ? more()->num_wrlock : 0; } // xlock void get_xlock(MutationRef who, client_t client) { assert(get_xlock_by() == 0); assert(state == LOCK_XLOCK || is_locallock() || state == LOCK_LOCK /* if we are a slave */); parent->get(MDSCacheObject::PIN_LOCK); more()->num_xlock++; more()->xlock_by = who; more()->xlock_by_client = client; } void set_xlock_done() { assert(more()->xlock_by); assert(state == LOCK_XLOCK || is_locallock() || state == LOCK_LOCK /* if we are a slave */); if (!is_locallock()) state = LOCK_XLOCKDONE; more()->xlock_by.reset(); } void put_xlock() { assert(state == LOCK_XLOCK || state == LOCK_XLOCKDONE || is_locallock() || state == LOCK_LOCK /* if we are a master of a slave */); --more()->num_xlock; parent->put(MDSCacheObject::PIN_LOCK); if (more()->num_xlock == 0) { more()->xlock_by.reset(); more()->xlock_by_client = -1; try_clear_more(); } } bool is_xlocked() const { return have_more() && more()->num_xlock > 0; } int get_num_xlocks() const { return have_more() ? more()->num_xlock : 0; } client_t get_xlock_by_client() const { return have_more() ? more()->xlock_by_client : -1; } bool is_xlocked_by_client(client_t c) const { return have_more() ? more()->xlock_by_client == c : false; } MutationRef get_xlock_by() const { return have_more() ? more()->xlock_by : MutationRef(); } // lease void get_client_lease() { num_client_lease++; } void put_client_lease() { assert(num_client_lease > 0); num_client_lease--; if (num_client_lease == 0) { try_clear_more(); } } bool is_leased() const { return num_client_lease > 0; } int get_num_client_lease() const { return num_client_lease; } bool is_used() const { return is_xlocked() || is_rdlocked() || is_wrlocked() || num_client_lease; } // encode/decode void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(state, bl); if (have_more()) ::encode(more()->gather_set, bl); else ::encode(empty_gather_set, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& p) { DECODE_START(2, p); ::decode(state, p); set g; ::decode(g, p); if (!g.empty()) more()->gather_set.swap(g); DECODE_FINISH(p); } void encode_state_for_replica(bufferlist& bl) const { __s16 s = get_replica_state(); ::encode(s, bl); } void decode_state(bufferlist::iterator& p, bool is_new=true) { __s16 s; ::decode(s, p); if (is_new) state = s; } void decode_state_rejoin(bufferlist::iterator& p, list& waiters) { __s16 s; ::decode(s, p); set_state_rejoin(s, waiters); } // caps bool is_loner_mode() { return get_sm()->states[state].loner; } int gcaps_allowed_ever() { return parent->is_auth() ? get_sm()->allowed_ever_auth : get_sm()->allowed_ever_replica; } int gcaps_allowed(int who, int s=-1) { if (s < 0) s = state; if (parent->is_auth()) { if (get_xlock_by_client() >= 0 && who == CAP_XLOCKER) return get_sm()->states[s].xlocker_caps | get_sm()->states[s].caps; // xlocker always gets more else if (is_loner_mode() && who == CAP_ANY) return get_sm()->states[s].caps; else return get_sm()->states[s].loner_caps | get_sm()->states[s].caps; // loner always gets more } else return get_sm()->states[s].replica_caps; } int gcaps_careful() { if (get_num_wrlocks()) return get_sm()->careful; return 0; } int gcaps_xlocker_mask(client_t client) { if (client == get_xlock_by_client()) return type->type == CEPH_LOCK_IFILE ? 0xf : (CEPH_CAP_GSHARED|CEPH_CAP_GEXCL); return 0; } // simplelock specifics int get_replica_state() const { return get_sm()->states[state].replica_state; } void export_twiddle() { clear_gather(); state = get_replica_state(); } /** replicate_relax * called on first replica creation. */ void replicate_relax() { assert(parent->is_auth()); assert(!parent->is_replicated()); if (state == LOCK_LOCK && !is_used()) state = LOCK_SYNC; } bool remove_replica(int from) { if (is_gathering(from)) { remove_gather(from); if (!is_gathering()) return true; } return false; } bool do_import(int from, int to) { if (!is_stable()) { remove_gather(from); remove_gather(to); if (!is_gathering()) return true; } if (!is_stable() && !is_gathering()) return true; return false; } void _print(ostream& out) const { out << get_lock_type_name(get_type()) << " "; out << get_state_name(get_state()); if (!get_gather_set().empty()) out << " g=" << get_gather_set(); if (num_client_lease) out << " l=" << num_client_lease; if (is_rdlocked()) out << " r=" << get_num_rdlocks(); if (is_wrlocked()) out << " w=" << get_num_wrlocks(); if (is_xlocked()) { out << " x=" << get_num_xlocks(); if (get_xlock_by()) out << " by " << get_xlock_by(); } /*if (is_stable()) out << " stable"; else out << " unstable"; */ } virtual void print(ostream& out) const { out << "("; _print(out); out << ")"; } }; WRITE_CLASS_ENCODER(SimpleLock) inline ostream& operator<<(ostream& out, const SimpleLock& l) { l.print(out); return out; } #endif ceph-0.80.11/src/mds/LogEvent.cc0000664000175100017510000000605212623076744020304 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/config.h" #include "LogEvent.h" #include "MDS.h" // events i know of #include "events/ESubtreeMap.h" #include "events/EExport.h" #include "events/EImportStart.h" #include "events/EImportFinish.h" #include "events/EFragment.h" #include "events/EResetJournal.h" #include "events/ESession.h" #include "events/ESessions.h" #include "events/EUpdate.h" #include "events/ESlaveUpdate.h" #include "events/EOpen.h" #include "events/ECommitted.h" #include "events/ETableClient.h" #include "events/ETableServer.h" LogEvent *LogEvent::decode(bufferlist& bl) { // parse type, length bufferlist::iterator p = bl.begin(); __u32 type; LogEvent *event = NULL; ::decode(type, p); if (EVENT_NEW_ENCODING == type) { try { DECODE_START(1, p); ::decode(type, p); event = decode_event(bl, p, type); DECODE_FINISH(p); } catch (const buffer::error &e) { generic_dout(0) << "failed to decode LogEvent (type maybe " << type << ")" << dendl; return NULL; } } else { // we are using classic encoding event = decode_event(bl, p, type); } return event; } LogEvent *LogEvent::decode_event(bufferlist& bl, bufferlist::iterator& p, __u32 type) { int length = bl.length() - p.get_off(); generic_dout(15) << "decode_log_event type " << type << ", size " << length << dendl; // create event LogEvent *le; switch (type) { case EVENT_SUBTREEMAP: le = new ESubtreeMap; break; case EVENT_SUBTREEMAP_TEST: le = new ESubtreeMap; le->set_type(type); break; case EVENT_EXPORT: le = new EExport; break; case EVENT_IMPORTSTART: le = new EImportStart; break; case EVENT_IMPORTFINISH: le = new EImportFinish; break; case EVENT_FRAGMENT: le = new EFragment; break; case EVENT_RESETJOURNAL: le = new EResetJournal; break; case EVENT_SESSION: le = new ESession; break; case EVENT_SESSIONS_OLD: le = new ESessions; (static_cast(le))->mark_old_encoding(); break; case EVENT_SESSIONS: le = new ESessions; break; case EVENT_UPDATE: le = new EUpdate; break; case EVENT_SLAVEUPDATE: le = new ESlaveUpdate; break; case EVENT_OPEN: le = new EOpen; break; case EVENT_COMMITTED: le = new ECommitted; break; case EVENT_TABLECLIENT: le = new ETableClient; break; case EVENT_TABLESERVER: le = new ETableServer; break; default: generic_dout(0) << "uh oh, unknown log event type " << type << " length " << length << dendl; return NULL; } // decode try { le->decode(p); } catch (const buffer::error &e) { generic_dout(0) << "failed to decode LogEvent type " << type << dendl; delete le; return NULL; } assert(p.end()); return le; } ceph-0.80.11/src/mds/ScatterLock.h0000664000175100017510000001341412623076744020641 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SCATTERLOCK_H #define CEPH_SCATTERLOCK_H #include "SimpleLock.h" class ScatterLock : public SimpleLock { struct more_bits_t { int state_flags; utime_t last_scatter; xlist::item item_updated; utime_t update_stamp; more_bits_t(ScatterLock *lock) : state_flags(0), item_updated(lock) {} bool empty() const { return !state_flags && !item_updated.is_on_list(); } }; more_bits_t *_more; bool have_more() const { return _more ? true : false; } void try_clear_more() { if (_more && _more->empty()) { delete _more; _more = NULL; } } more_bits_t *more() { if (!_more) _more = new more_bits_t(this); return _more; } enum flag_values { // flag values for more_bits_t state SCATTER_WANTED = 1 << 0, UNSCATTER_WANTED = 1 << 1, DIRTY = 1 << 2, FLUSHING = 1 << 3, FLUSHED = 1 << 4, }; public: ScatterLock(MDSCacheObject *o, LockType *lt) : SimpleLock(o, lt), _more(NULL) {} ~ScatterLock() { if (_more) { _more->item_updated.remove_myself(); // FIXME this should happen sooner, i think... delete _more; } } bool is_scatterlock() const { return true; } bool is_sync_and_unlocked() const { return SimpleLock::is_sync_and_unlocked() && !is_dirty() && !is_flushing(); } bool can_scatter_pin(client_t loner) { /* LOCK : NOT okay because it can MIX and force replicas to journal something TSYN : also not okay for same reason EXCL : also not okay MIX : okay, replica can stall before sending AC_SYNCACK SYNC : okay, replica can stall before sending AC_MIXACK or AC_LOCKACK */ return get_state() == LOCK_SYNC || get_state() == LOCK_MIX; } xlist::item *get_updated_item() { return &more()->item_updated; } utime_t get_update_stamp() { return more()->update_stamp; } void set_update_stamp(utime_t t) { more()->update_stamp = t; } void set_scatter_wanted() { more()->state_flags |= SCATTER_WANTED; } void set_unscatter_wanted() { more()->state_flags |= UNSCATTER_WANTED; } void clear_scatter_wanted() { if (have_more()) _more->state_flags &= ~SCATTER_WANTED; try_clear_more(); } void clear_unscatter_wanted() { if (have_more()) _more->state_flags &= ~UNSCATTER_WANTED; try_clear_more(); } bool get_scatter_wanted() const { return have_more() ? _more->state_flags & SCATTER_WANTED : false; } bool get_unscatter_wanted() const { return have_more() ? _more->state_flags & UNSCATTER_WANTED : false; } bool is_dirty() const { return have_more() ? _more->state_flags & DIRTY : false; } bool is_flushing() const { return have_more() ? _more->state_flags & FLUSHING: false; } bool is_flushed() const { return have_more() ? _more->state_flags & FLUSHED: false; } bool is_dirty_or_flushing() const { return have_more() ? (is_dirty() || is_flushing()) : false; } void mark_dirty() { if (!is_dirty()) { if (!is_flushing()) parent->get(MDSCacheObject::PIN_DIRTYSCATTERED); set_dirty(); } } void start_flush() { if (is_dirty()) { set_flushing(); clear_dirty(); } } void finish_flush() { if (is_flushing()) { clear_flushing(); set_flushed(); if (!is_dirty()) { parent->put(MDSCacheObject::PIN_DIRTYSCATTERED); parent->clear_dirty_scattered(get_type()); } } } void remove_dirty() { start_flush(); finish_flush(); } void clear_flushed() { if (have_more()) { _more->state_flags &= ~FLUSHED; try_clear_more(); } } void set_last_scatter(utime_t t) { more()->last_scatter = t; } utime_t get_last_scatter() { return more()->last_scatter; } void infer_state_from_strong_rejoin(int rstate, bool locktoo) { if (rstate == LOCK_MIX || rstate == LOCK_MIX_LOCK || // replica still has wrlocks? rstate == LOCK_MIX_SYNC || // " rstate == LOCK_MIX_TSYN) // " state = LOCK_MIX; else if (locktoo && rstate == LOCK_LOCK) state = LOCK_LOCK; } void encode_state_for_rejoin(bufferlist& bl, int rep) const { __s16 s = get_replica_state(); if (is_gathering(rep)) { // the recovering mds may hold rejoined wrlocks if (state == LOCK_MIX_SYNC) s = LOCK_MIX_SYNC; else s = LOCK_MIX_LOCK; } ::encode(s, bl); } bool remove_replica(int from, bool rejoin) { if (rejoin && (state == LOCK_MIX || state == LOCK_MIX_SYNC || state == LOCK_MIX_LOCK2 || state == LOCK_MIX_TSYN || state == LOCK_MIX_EXCL)) return false; return SimpleLock::remove_replica(from); } virtual void print(ostream& out) const { out << "("; _print(out); if (is_dirty()) out << " dirty"; if (is_flushing()) out << " flushing"; if (is_flushed()) out << " flushed"; if (get_scatter_wanted()) out << " scatter_wanted"; out << ")"; } private: void set_flushing() { more()->state_flags |= FLUSHING; } void clear_flushing() { if (have_more()) { _more->state_flags &= ~FLUSHING; } } void set_flushed() { more()->state_flags |= FLUSHED; } void set_dirty() { more()->state_flags |= DIRTY; } void clear_dirty() { if (have_more()) { _more->state_flags &= ~DIRTY; } } }; #endif ceph-0.80.11/src/mds/MDLog.h0000664000175100017510000001163212623076744017365 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDLOG_H #define CEPH_MDLOG_H enum { l_mdl_first = 5000, l_mdl_evadd, l_mdl_evex, l_mdl_evtrm, l_mdl_ev, l_mdl_evexg, l_mdl_evexd, l_mdl_segadd, l_mdl_segex, l_mdl_segtrm, l_mdl_seg, l_mdl_segexg, l_mdl_segexd, l_mdl_expos, l_mdl_wrpos, l_mdl_rdpos, l_mdl_jlat, l_mdl_last, }; #include "include/types.h" #include "include/Context.h" #include "common/Thread.h" #include "common/Cond.h" #include "LogSegment.h" #include class Journaler; class LogEvent; class MDS; class LogSegment; class ESubtreeMap; class PerfCounters; #include using std::map; class MDLog { public: MDS *mds; protected: int num_events; // in events int unflushed; bool capped; inodeno_t ino; Journaler *journaler; PerfCounters *logger; // -- replay -- Cond replay_cond; class ReplayThread : public Thread { MDLog *log; public: ReplayThread(MDLog *l) : log(l) {} void* entry() { log->_replay_thread(); return 0; } } replay_thread; bool already_replayed; friend class ReplayThread; friend class C_MDL_Replay; list waitfor_replay; void _replay(); // old way void _replay_thread(); // new way // -- segments -- map segments; set expiring_segments; set expired_segments; int expiring_events; int expired_events; // -- subtreemaps -- friend class ESubtreeMap; friend class C_MDS_WroteImportMap; friend class MDCache; public: uint64_t get_last_segment_offset() { assert(!segments.empty()); return segments.rbegin()->first; } LogSegment *get_oldest_segment() { return segments.begin()->second; } void remove_oldest_segment() { map::iterator p = segments.begin(); delete p->second; segments.erase(p); } private: void init_journaler(); struct C_MDL_WriteError : public Context { MDLog *mdlog; C_MDL_WriteError(MDLog *m) : mdlog(m) {} void finish(int r) { mdlog->handle_journaler_write_error(r); } }; void handle_journaler_write_error(int r); public: void create_logger(); // replay state map > pending_exports; public: MDLog(MDS *m) : mds(m), num_events(0), unflushed(0), capped(false), journaler(0), logger(0), replay_thread(this), already_replayed(false), expiring_events(0), expired_events(0), cur_event(NULL) { } ~MDLog(); // -- segments -- void start_new_segment(Context *onsync=0); void prepare_new_segment(); void journal_segment_subtree_map(); LogSegment *peek_current_segment() { return segments.empty() ? NULL : segments.rbegin()->second; } LogSegment *get_current_segment() { assert(!segments.empty()); return segments.rbegin()->second; } LogSegment *get_segment(uint64_t off) { if (segments.count(off)) return segments[off]; return NULL; } bool have_any_segments() { return !segments.empty(); } void flush_logger(); size_t get_num_events() { return num_events; } size_t get_num_segments() { return segments.size(); } uint64_t get_read_pos(); uint64_t get_write_pos(); uint64_t get_safe_pos(); Journaler *get_journaler() { return journaler; } bool empty() { return segments.empty(); } bool is_capped() { return capped; } void cap(); // -- events -- private: LogEvent *cur_event; public: void start_entry(LogEvent *e); void submit_entry(LogEvent *e, Context *c = 0); void start_submit_entry(LogEvent *e, Context *c = 0) { start_entry(e); submit_entry(e, c); } bool entry_is_open() { return cur_event != NULL; } void wait_for_safe( Context *c ); void flush(); bool is_flushed() { return unflushed == 0; } private: class C_MaybeExpiredSegment : public Context { MDLog *mdlog; LogSegment *ls; int op_prio; public: C_MaybeExpiredSegment(MDLog *mdl, LogSegment *s, int p) : mdlog(mdl), ls(s), op_prio(p) {} void finish(int res) { mdlog->_maybe_expired(ls, op_prio); } }; void try_expire(LogSegment *ls, int op_prio); void _maybe_expired(LogSegment *ls, int op_prio); void _expired(LogSegment *ls); void _trim_expired_segments(); public: void trim(int max=-1); private: void write_head(Context *onfinish); public: void create(Context *onfinish); // fresh, empty log! void open(Context *onopen); // append() or replay() to follow! void append(); void replay(Context *onfinish); void standby_trim_segments(); }; #endif ceph-0.80.11/src/mds/MDSTableClient.cc0000664000175100017510000001535512623076744021321 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "MDSMap.h" #include "include/Context.h" #include "msg/Messenger.h" #include "MDS.h" #include "MDLog.h" #include "LogSegment.h" #include "MDSTableClient.h" #include "events/ETableClient.h" #include "messages/MMDSTableRequest.h" #include "common/config.h" #define dout_subsys ceph_subsys_mds #undef dout_prefix #define dout_prefix *_dout << "mds." << mds->get_nodeid() << ".tableclient(" << get_mdstable_name(table) << ") " void MDSTableClient::handle_request(class MMDSTableRequest *m) { dout(10) << "handle_request " << *m << dendl; assert(m->table == table); version_t tid = m->get_tid(); uint64_t reqid = m->reqid; switch (m->op) { case TABLESERVER_OP_QUERY_REPLY: handle_query_result(m); break; case TABLESERVER_OP_AGREE: if (pending_prepare.count(reqid)) { dout(10) << "got agree on " << reqid << " atid " << tid << dendl; assert(g_conf->mds_kill_mdstable_at != 3); Context *onfinish = pending_prepare[reqid].onfinish; *pending_prepare[reqid].ptid = tid; if (pending_prepare[reqid].pbl) *pending_prepare[reqid].pbl = m->bl; pending_prepare.erase(reqid); prepared_update[tid] = reqid; if (onfinish) { onfinish->complete(0); } } else if (prepared_update.count(tid)) { dout(10) << "got duplicated agree on " << reqid << " atid " << tid << dendl; assert(prepared_update[tid] == reqid); assert(!server_ready); } else if (pending_commit.count(tid)) { dout(10) << "stray agree on " << reqid << " tid " << tid << ", already committing, will resend COMMIT" << dendl; assert(!server_ready); // will re-send commit when receiving the server ready message } else { dout(10) << "stray agree on " << reqid << " tid " << tid << ", sending ROLLBACK" << dendl; assert(!server_ready); MMDSTableRequest *req = new MMDSTableRequest(table, TABLESERVER_OP_ROLLBACK, 0, tid); mds->send_message_mds(req, mds->mdsmap->get_tableserver()); } break; case TABLESERVER_OP_ACK: if (pending_commit.count(tid) && pending_commit[tid]->pending_commit_tids[table].count(tid)) { dout(10) << "got ack on tid " << tid << ", logging" << dendl; assert(g_conf->mds_kill_mdstable_at != 7); // remove from committing list pending_commit[tid]->pending_commit_tids[table].erase(tid); pending_commit.erase(tid); // log ACK. mds->mdlog->start_submit_entry(new ETableClient(table, TABLESERVER_OP_ACK, tid), new C_LoggedAck(this, tid)); } else { dout(10) << "got stray ack on tid " << tid << ", ignoring" << dendl; } break; case TABLESERVER_OP_SERVER_READY: assert(!server_ready); server_ready = true; if (last_reqid == ~0ULL) last_reqid = reqid; resend_queries(); resend_prepares(); resend_commits(); break; default: assert(0); } m->put(); } void MDSTableClient::_logged_ack(version_t tid) { dout(10) << "_logged_ack " << tid << dendl; assert(g_conf->mds_kill_mdstable_at != 8); // kick any waiters (LogSegment trim) if (ack_waiters.count(tid)) { dout(15) << "kicking ack waiters on tid " << tid << dendl; mds->queue_waiters(ack_waiters[tid]); ack_waiters.erase(tid); } } void MDSTableClient::_prepare(bufferlist& mutation, version_t *ptid, bufferlist *pbl, Context *onfinish) { if (last_reqid == ~0ULL) { dout(10) << "tableserver is not ready yet, waiting for request id" << dendl; waiting_for_reqid.push_back(_pending_prepare(onfinish, ptid, pbl, mutation)); return; } uint64_t reqid = ++last_reqid; dout(10) << "_prepare " << reqid << dendl; pending_prepare[reqid].mutation = mutation; pending_prepare[reqid].ptid = ptid; pending_prepare[reqid].pbl = pbl; pending_prepare[reqid].onfinish = onfinish; if (server_ready) { // send message MMDSTableRequest *req = new MMDSTableRequest(table, TABLESERVER_OP_PREPARE, reqid); req->bl = mutation; mds->send_message_mds(req, mds->mdsmap->get_tableserver()); } else dout(10) << "tableserver is not ready yet, deferring request" << dendl; } void MDSTableClient::commit(version_t tid, LogSegment *ls) { dout(10) << "commit " << tid << dendl; assert(prepared_update.count(tid)); prepared_update.erase(tid); assert(pending_commit.count(tid) == 0); pending_commit[tid] = ls; ls->pending_commit_tids[table].insert(tid); assert(g_conf->mds_kill_mdstable_at != 4); if (server_ready) { // send message MMDSTableRequest *req = new MMDSTableRequest(table, TABLESERVER_OP_COMMIT, 0, tid); mds->send_message_mds(req, mds->mdsmap->get_tableserver()); } else dout(10) << "tableserver is not ready yet, deferring request" << dendl; } // recovery void MDSTableClient::got_journaled_agree(version_t tid, LogSegment *ls) { dout(10) << "got_journaled_agree " << tid << dendl; ls->pending_commit_tids[table].insert(tid); pending_commit[tid] = ls; } void MDSTableClient::got_journaled_ack(version_t tid) { dout(10) << "got_journaled_ack " << tid << dendl; if (pending_commit.count(tid)) { pending_commit[tid]->pending_commit_tids[table].erase(tid); pending_commit.erase(tid); } } void MDSTableClient::resend_commits() { for (map::iterator p = pending_commit.begin(); p != pending_commit.end(); ++p) { dout(10) << "resending commit on " << p->first << dendl; MMDSTableRequest *req = new MMDSTableRequest(table, TABLESERVER_OP_COMMIT, 0, p->first); mds->send_message_mds(req, mds->mdsmap->get_tableserver()); } } void MDSTableClient::resend_prepares() { while (!waiting_for_reqid.empty()) { pending_prepare[++last_reqid] = waiting_for_reqid.front(); waiting_for_reqid.pop_front(); } for (map::iterator p = pending_prepare.begin(); p != pending_prepare.end(); ++p) { dout(10) << "resending prepare on " << p->first << dendl; MMDSTableRequest *req = new MMDSTableRequest(table, TABLESERVER_OP_PREPARE, p->first); req->bl = p->second.mutation; mds->send_message_mds(req, mds->mdsmap->get_tableserver()); } } void MDSTableClient::handle_mds_failure(int who) { if (who != mds->mdsmap->get_tableserver()) return; // do nothing. dout(7) << "tableserver mds." << who << " fails" << dendl; server_ready = false; } ceph-0.80.11/src/mds/Anchor.h0000664000175100017510000000242112623076744017631 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_ANCHOR_H #define CEPH_ANCHOR_H #include using std::string; #include "include/types.h" #include "mdstypes.h" #include "include/buffer.h" // identifies a anchor table mutation namespace ceph { class Formatter; } // anchor type class Anchor { public: inodeno_t ino; // anchored ino inodeno_t dirino; __u32 dn_hash; int nref; // reference count version_t updated; Anchor() : dn_hash(0), nref(0), updated(0) {} Anchor(inodeno_t i, inodeno_t di, __u32 hash, int nr, version_t u) : ino(i), dirino(di), dn_hash(hash), nref(nr), updated(u) { } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(Anchor) ostream& operator<<(ostream& out, const Anchor &a); #endif ceph-0.80.11/src/mds/MDCache.h0000664000175100017510000010740112623076744017647 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MDCACHE_H #define CEPH_MDCACHE_H #include "include/types.h" #include "include/filepath.h" #include "include/elist.h" #include "CInode.h" #include "CDentry.h" #include "CDir.h" #include "include/Context.h" #include "events/EMetaBlob.h" #include "messages/MClientRequest.h" #include "messages/MMDSSlaveRequest.h" class PerfCounters; class MDS; class Session; class Migrator; class Message; class Session; class MMDSResolve; class MMDSResolveAck; class MMDSCacheRejoin; class MMDSCacheRejoinAck; class MJoin; class MJoinAck; class MDiscover; class MDiscoverReply; class MCacheExpire; class MDirUpdate; class MDentryLink; class MDentryUnlink; class MLock; struct MMDSFindIno; struct MMDSFindInoReply; struct MMDSOpenIno; struct MMDSOpenInoReply; class Message; class MClientRequest; class MMDSSlaveRequest; struct MClientSnap; class MMDSFragmentNotify; class ESubtreeMap; struct MDRequestImpl; typedef ceph::shared_ptr MDRequestRef; struct MDSlaveUpdate; // flags for predirty_journal_parents() static const int PREDIRTY_PRIMARY = 1; // primary dn, adjust nested accounting static const int PREDIRTY_DIR = 2; // update parent dir mtime/size static const int PREDIRTY_SHALLOW = 4; // only go to immediate parent (for easier rollback) class MDCache { public: // my master MDS *mds; // -- my cache -- LRU lru; // dentry lru for expiring items from cache protected: ceph::unordered_map inode_map; // map of inodes by ino CInode *root; // root inode CInode *myin; // .ceph/mds%d dir CInode *strays[NUM_STRAY]; // my stray dir int stray_index; CInode *get_stray() { return strays[stray_index]; } set base_inodes; public: void advance_stray() { stray_index = (stray_index+1)%NUM_STRAY; } DecayRate decayrate; int num_inodes_with_caps; int num_caps; unsigned max_dir_commit_size; ceph_file_layout default_file_layout; ceph_file_layout default_log_layout; // -- client leases -- public: static const int client_lease_pools = 3; float client_lease_durations[client_lease_pools]; protected: xlist client_leases[client_lease_pools]; public: void touch_client_lease(ClientLease *r, int pool, utime_t ttl) { client_leases[pool].push_back(&r->item_lease); r->ttl = ttl; } // -- client caps -- uint64_t last_cap_id; // -- discover -- struct discover_info_t { ceph_tid_t tid; int mds; inodeno_t ino; frag_t frag; snapid_t snap; filepath want_path; inodeno_t want_ino; bool want_base_dir; bool want_xlocked; discover_info_t() : tid(0), mds(-1), snap(CEPH_NOSNAP), want_base_dir(false), want_xlocked(false) {} }; map discovers; ceph_tid_t discover_last_tid; void _send_discover(discover_info_t& dis); discover_info_t& _create_discover(int mds) { ceph_tid_t t = ++discover_last_tid; discover_info_t& d = discovers[t]; d.tid = t; d.mds = mds; return d; } // waiters map > > waiting_for_base_ino; void discover_base_ino(inodeno_t want_ino, Context *onfinish, int from=-1); void discover_dir_frag(CInode *base, frag_t approx_fg, Context *onfinish, int from=-1); void discover_path(CInode *base, snapid_t snap, filepath want_path, Context *onfinish, bool want_xlocked=false, int from=-1); void discover_path(CDir *base, snapid_t snap, filepath want_path, Context *onfinish, bool want_xlocked=false); void discover_ino(CDir *base, inodeno_t want_ino, Context *onfinish, bool want_xlocked=false); void kick_discovers(int who); // after a failure. public: int get_num_inodes() { return inode_map.size(); } int get_num_dentries() { return lru.lru_get_size(); } // -- subtrees -- protected: map > subtrees; // nested bounds on subtrees. map > > projected_subtree_renames; // renamed ino -> target dir // adjust subtree auth specification // dir->dir_auth // imports/exports/nested_exports // join/split subtrees as appropriate public: bool is_subtrees() { return !subtrees.empty(); } void list_subtrees(list& ls); void adjust_subtree_auth(CDir *root, pair auth, bool do_eval=true); void adjust_subtree_auth(CDir *root, int a, int b=CDIR_AUTH_UNKNOWN, bool do_eval=true) { adjust_subtree_auth(root, pair(a,b), do_eval); } void adjust_bounded_subtree_auth(CDir *dir, set& bounds, pair auth); void adjust_bounded_subtree_auth(CDir *dir, set& bounds, int a) { adjust_bounded_subtree_auth(dir, bounds, pair(a, CDIR_AUTH_UNKNOWN)); } void adjust_bounded_subtree_auth(CDir *dir, vector& bounds, pair auth); void adjust_bounded_subtree_auth(CDir *dir, vector& bounds, int a) { adjust_bounded_subtree_auth(dir, bounds, pair(a, CDIR_AUTH_UNKNOWN)); } void map_dirfrag_set(list& dfs, set& result); void try_subtree_merge(CDir *root); void try_subtree_merge_at(CDir *root, bool do_eval=true); void subtree_merge_writebehind_finish(CInode *in, MutationRef& mut); void eval_subtree_root(CInode *diri); CDir *get_subtree_root(CDir *dir); CDir *get_projected_subtree_root(CDir *dir); bool is_leaf_subtree(CDir *dir) { assert(subtrees.count(dir)); return subtrees[dir].empty(); } void remove_subtree(CDir *dir); bool is_subtree(CDir *root) { return subtrees.count(root); } void get_subtree_bounds(CDir *root, set& bounds); void get_wouldbe_subtree_bounds(CDir *root, set& bounds); void verify_subtree_bounds(CDir *root, const set& bounds); void verify_subtree_bounds(CDir *root, const list& bounds); void project_subtree_rename(CInode *diri, CDir *olddir, CDir *newdir); void adjust_subtree_after_rename(CInode *diri, CDir *olddir, bool pop, bool imported = false); void get_auth_subtrees(set& s); void get_fullauth_subtrees(set& s); int num_subtrees(); int num_subtrees_fullauth(); int num_subtrees_fullnonauth(); protected: // delayed cache expire map > delayed_expire; // subtree root -> expire msg // -- requests -- protected: ceph::unordered_map active_requests; public: int get_num_client_requests(); MDRequestRef request_start(MClientRequest *req); MDRequestRef request_start_slave(metareqid_t rid, __u32 attempt, int by); MDRequestRef request_start_internal(int op); bool have_request(metareqid_t rid) { return active_requests.count(rid); } MDRequestRef request_get(metareqid_t rid); void request_pin_ref(MDRequestRef& r, CInode *ref, vector& trace); void request_finish(MDRequestRef& mdr); void request_forward(MDRequestRef& mdr, int mds, int port=0); void dispatch_request(MDRequestRef& mdr); void request_drop_foreign_locks(MDRequestRef& mdr); void request_drop_non_rdlocks(MDRequestRef& r); void request_drop_locks(MDRequestRef& r); void request_cleanup(MDRequestRef& r); void request_kill(MDRequestRef& r); // called when session closes // journal/snap helpers CInode *pick_inode_snap(CInode *in, snapid_t follows); CInode *cow_inode(CInode *in, snapid_t last); void journal_cow_dentry(MutationImpl *mut, EMetaBlob *metablob, CDentry *dn, snapid_t follows=CEPH_NOSNAP, CInode **pcow_inode=0, CDentry::linkage_t *dnl=0); void journal_cow_inode(MutationRef& mut, EMetaBlob *metablob, CInode *in, snapid_t follows=CEPH_NOSNAP, CInode **pcow_inode=0); void journal_dirty_inode(MutationImpl *mut, EMetaBlob *metablob, CInode *in, snapid_t follows=CEPH_NOSNAP); void project_rstat_inode_to_frag(CInode *cur, CDir *parent, snapid_t first, int linkunlink); void _project_rstat_inode_to_frag(inode_t& inode, snapid_t ofirst, snapid_t last, CDir *parent, int linkunlink=0); void project_rstat_frag_to_inode(nest_info_t& rstat, nest_info_t& accounted_rstat, snapid_t ofirst, snapid_t last, CInode *pin, bool cow_head); void predirty_journal_parents(MutationRef mut, EMetaBlob *blob, CInode *in, CDir *parent, int flags, int linkunlink=0, snapid_t follows=CEPH_NOSNAP); // slaves void add_uncommitted_master(metareqid_t reqid, LogSegment *ls, set &slaves, bool safe=false) { uncommitted_masters[reqid].ls = ls; uncommitted_masters[reqid].slaves = slaves; uncommitted_masters[reqid].safe = safe; } void wait_for_uncommitted_master(metareqid_t reqid, Context *c) { uncommitted_masters[reqid].waiters.push_back(c); } void log_master_commit(metareqid_t reqid); void logged_master_update(metareqid_t reqid); void _logged_master_commit(metareqid_t reqid); void committed_master_slave(metareqid_t r, int from); void finish_committed_masters(); void _logged_slave_commit(int from, metareqid_t reqid); // -- recovery -- protected: set recovery_set; public: void set_recovery_set(set& s); void handle_mds_failure(int who); void handle_mds_recovery(int who); protected: // [resolve] // from EImportStart w/o EImportFinish during journal replay map > my_ambiguous_imports; // from MMDSResolves map > > other_ambiguous_imports; map > uncommitted_slave_updates; // slave: for replay. map uncommitted_slave_rename_olddir; // slave: preserve the non-auth dir until seeing commit. map uncommitted_slave_unlink; // slave: preserve the unlinked inode until seeing commit. // track master requests whose slaves haven't acknowledged commit struct umaster { set slaves; LogSegment *ls; list waiters; bool safe; bool committing; bool recovering; umaster() : committing(false), recovering(false) {} }; map uncommitted_masters; // master: req -> slave set set pending_masters; map > ambiguous_slave_updates; friend class ESlaveUpdate; friend class ECommitted; bool resolves_pending; set resolve_gather; // nodes i need resolves from set resolve_ack_gather; // nodes i need a resolve_ack from map need_resolve_rollback; // rollbacks i'm writing to the journal map delayed_resolve; void handle_resolve(MMDSResolve *m); void handle_resolve_ack(MMDSResolveAck *m); void process_delayed_resolve(); void discard_delayed_resolve(int who); void maybe_resolve_finish(); void disambiguate_imports(); void recalc_auth_bits(); void trim_unlinked_inodes(); void add_uncommitted_slave_update(metareqid_t reqid, int master, MDSlaveUpdate*); void finish_uncommitted_slave_update(metareqid_t reqid, int master); MDSlaveUpdate* get_uncommitted_slave_update(metareqid_t reqid, int master); public: void remove_inode_recursive(CInode *in); bool is_ambiguous_slave_update(metareqid_t reqid, int master) { return ambiguous_slave_updates.count(master) && ambiguous_slave_updates[master].count(reqid); } void add_ambiguous_slave_update(metareqid_t reqid, int master) { ambiguous_slave_updates[master].insert(reqid); } void remove_ambiguous_slave_update(metareqid_t reqid, int master) { assert(ambiguous_slave_updates[master].count(reqid)); ambiguous_slave_updates[master].erase(reqid); if (ambiguous_slave_updates[master].empty()) ambiguous_slave_updates.erase(master); } void add_rollback(metareqid_t reqid, int master) { need_resolve_rollback[reqid] = master; } void finish_rollback(metareqid_t reqid); // ambiguous imports void add_ambiguous_import(dirfrag_t base, const vector& bounds); void add_ambiguous_import(CDir *base, const set& bounds); bool have_ambiguous_import(dirfrag_t base) { return my_ambiguous_imports.count(base); } void get_ambiguous_import_bounds(dirfrag_t base, vector& bounds) { assert(my_ambiguous_imports.count(base)); bounds = my_ambiguous_imports[base]; } void cancel_ambiguous_import(CDir *); void finish_ambiguous_import(dirfrag_t dirino); void resolve_start(); void send_resolves(); void send_slave_resolves(); void send_subtree_resolves(); void maybe_send_pending_resolves() { if (resolves_pending) send_subtree_resolves(); } void _move_subtree_map_bound(dirfrag_t df, dirfrag_t oldparent, dirfrag_t newparent, map >& subtrees); ESubtreeMap *create_subtree_map(); void clean_open_file_lists(); protected: // [rejoin] bool rejoins_pending; set rejoin_gather; // nodes from whom i need a rejoin set rejoin_sent; // nodes i sent a rejoin to set rejoin_ack_gather; // nodes from whom i need a rejoin ack map > > rejoin_imported_caps; map > > rejoin_slave_exports; map rejoin_client_map; map > cap_exports; // ino -> client -> capex map cap_export_targets; // ino -> auth mds map > > cap_imports; // ino -> client -> frommds -> capex map cap_import_paths; set cap_imports_missing; int cap_imports_num_opening; set rejoin_undef_inodes; set rejoin_potential_updated_scatterlocks; set rejoin_undef_dirfrags; map > rejoin_unlinked_inodes; vector rejoin_recover_q, rejoin_check_q; list rejoin_eval_locks; list rejoin_waiters; void rejoin_walk(CDir *dir, MMDSCacheRejoin *rejoin); void handle_cache_rejoin(MMDSCacheRejoin *m); void handle_cache_rejoin_weak(MMDSCacheRejoin *m); CInode* rejoin_invent_inode(inodeno_t ino, snapid_t last); CDir* rejoin_invent_dirfrag(dirfrag_t df); void handle_cache_rejoin_strong(MMDSCacheRejoin *m); void rejoin_scour_survivor_replicas(int from, MMDSCacheRejoin *ack, set& acked_inodes, set& gather_locks); void handle_cache_rejoin_ack(MMDSCacheRejoin *m); void handle_cache_rejoin_purge(MMDSCacheRejoin *m); void handle_cache_rejoin_missing(MMDSCacheRejoin *m); void handle_cache_rejoin_full(MMDSCacheRejoin *m); void rejoin_send_acks(); void rejoin_trim_undef_inodes(); void maybe_send_pending_rejoins() { if (rejoins_pending) rejoin_send_rejoins(); } public: void rejoin_start(); void rejoin_gather_finish(); void rejoin_send_rejoins(); void rejoin_export_caps(inodeno_t ino, client_t client, ceph_mds_cap_reconnect& capinfo, int target=-1) { cap_exports[ino][client] = capinfo; cap_export_targets[ino] = target; } void rejoin_recovered_caps(inodeno_t ino, client_t client, cap_reconnect_t& icr, int frommds=-1) { cap_imports[ino][client][frommds] = icr.capinfo; cap_import_paths[ino] = filepath(icr.path, (uint64_t)icr.capinfo.pathbase); } ceph_mds_cap_reconnect *get_replay_cap_reconnect(inodeno_t ino, client_t client) { if (cap_imports.count(ino) && cap_imports[ino].count(client) && cap_imports[ino][client].count(-1)) { return &cap_imports[ino][client][-1]; } return NULL; } void remove_replay_cap_reconnect(inodeno_t ino, client_t client) { assert(cap_imports[ino].size() == 1); assert(cap_imports[ino][client].size() == 1); cap_imports.erase(ino); } // [reconnect/rejoin caps] map > reconnected_caps; // inode -> client -> realmino map > reconnected_snaprealms; // realmino -> client -> realmseq void add_reconnected_cap(CInode *in, client_t client, inodeno_t realm) { reconnected_caps[in][client] = realm; } void add_reconnected_snaprealm(client_t client, inodeno_t ino, snapid_t seq) { reconnected_snaprealms[ino][client] = seq; } friend class C_MDC_RejoinOpenInoFinish; friend class C_MDC_RejoinSessionsOpened; void rejoin_open_ino_finish(inodeno_t ino, int ret); void rejoin_open_sessions_finish(map client_map, map& sseqmap); bool process_imported_caps(); void choose_lock_states_and_reconnect_caps(); void prepare_realm_split(SnapRealm *realm, client_t client, inodeno_t ino, map& splits); void do_realm_invalidate_and_update_notify(CInode *in, int snapop, bool nosend=false); void send_snaps(map& splits); Capability* rejoin_import_cap(CInode *in, client_t client, ceph_mds_cap_reconnect& icr, int frommds); void finish_snaprealm_reconnect(client_t client, SnapRealm *realm, snapid_t seq); void try_reconnect_cap(CInode *in, Session *session); void export_remaining_imported_caps(); // cap imports. delayed snap parent opens. // realm inode -> client -> cap inodes needing to split to this realm map > > missing_snap_parents; map > delayed_imported_caps; void do_cap_import(Session *session, CInode *in, Capability *cap, uint64_t p_cap_id, ceph_seq_t p_seq, ceph_seq_t p_mseq, int peer, int p_flags); void do_delayed_cap_imports(); void check_realm_past_parents(SnapRealm *realm); void open_snap_parents(); bool open_undef_inodes_dirfrags(); void opened_undef_inode(CInode *in); void opened_undef_dirfrag(CDir *dir) { rejoin_undef_dirfrags.erase(dir); } void reissue_all_caps(); friend class Locker; friend class Migrator; friend class MDBalancer; // file size recovery set file_recover_queue; set file_recovering; void queue_file_recover(CInode *in); void unqueue_file_recover(CInode *in); void _queued_file_recover_cow(CInode *in, MutationRef& mut); void _queue_file_recover(CInode *in); void identify_files_to_recover(vector& recover_q, vector& check_q); void start_files_to_recover(vector& recover_q, vector& check_q); void do_file_recover(); void _recovered(CInode *in, int r, uint64_t size, utime_t mtime); void purge_prealloc_ino(inodeno_t ino, Context *fin); public: // subsystems Migrator *migrator; public: MDCache(MDS *m); ~MDCache(); // debug void log_stat(); // root inode CInode *get_root() { return root; } CInode *get_myin() { return myin; } // cache void set_cache_size(size_t max) { lru.lru_set_max(max); } size_t get_cache_size() { return lru.lru_get_size(); } // trimming bool trim(int max = -1); // trim cache bool trim_dentry(CDentry *dn, map& expiremap); void trim_dirfrag(CDir *dir, CDir *con, map& expiremap); bool trim_inode(CDentry *dn, CInode *in, CDir *con, map& expiremap); void send_expire_messages(map& expiremap); void trim_non_auth(); // trim out trimmable non-auth items bool trim_non_auth_subtree(CDir *directory); void try_trim_non_auth_subtree(CDir *dir); bool can_trim_non_auth_dirfrag(CDir *dir) { return my_ambiguous_imports.count((dir)->dirfrag()) == 0 && uncommitted_slave_rename_olddir.count(dir->inode) == 0; } void trim_client_leases(); void check_memory_usage(); // shutdown void shutdown_start(); void shutdown_check(); bool shutdown_pass(); bool shutdown_export_strays(); bool shutdown_export_caps(); bool shutdown(); // clear cache (ie at shutodwn) bool did_shutdown_log_cap; // inode_map bool have_inode(vinodeno_t vino) { return inode_map.count(vino) ? true:false; } bool have_inode(inodeno_t ino, snapid_t snap=CEPH_NOSNAP) { return have_inode(vinodeno_t(ino, snap)); } CInode* get_inode(vinodeno_t vino) { if (have_inode(vino)) return inode_map[vino]; return NULL; } CInode* get_inode(inodeno_t ino, snapid_t s=CEPH_NOSNAP) { return get_inode(vinodeno_t(ino, s)); } CDir* get_dirfrag(dirfrag_t df) { CInode *in = get_inode(df.ino); if (!in) return NULL; return in->get_dirfrag(df.frag); } CDir* get_dirfrag(inodeno_t ino, const string& dn) { CInode *in = get_inode(ino); if (!in) return NULL; frag_t fg = in->pick_dirfrag(dn); return in->get_dirfrag(fg); } CDir* get_force_dirfrag(dirfrag_t df) { CInode *diri = get_inode(df.ino); if (!diri) return NULL; CDir *dir = force_dir_fragment(diri, df.frag); if (!dir) dir = diri->get_dirfrag(df.frag); return dir; } MDSCacheObject *get_object(MDSCacheObjectInfo &info); public: void add_inode(CInode *in); void remove_inode(CInode *in); protected: void touch_inode(CInode *in) { if (in->get_parent_dn()) touch_dentry(in->get_projected_parent_dn()); } public: void touch_dentry(CDentry *dn) { // touch ancestors if (dn->get_dir()->get_inode()->get_projected_parent_dn()) touch_dentry(dn->get_dir()->get_inode()->get_projected_parent_dn()); // touch me if (dn->is_auth()) lru.lru_touch(dn); else lru.lru_midtouch(dn); } void touch_dentry_bottom(CDentry *dn) { lru.lru_bottouch(dn); if (dn->get_projected_linkage()->is_primary()) { CInode *in = dn->get_projected_linkage()->get_inode(); if (in->has_dirfrags()) { list ls; in->get_dirfrags(ls); for (list::iterator p = ls.begin(); p != ls.end(); ++p) (*p)->touch_dentries_bottom(); } } } protected: void inode_remove_replica(CInode *in, int rep, bool rejoin, set& gather_locks); void dentry_remove_replica(CDentry *dn, int rep, set& gather_locks); void rename_file(CDentry *srcdn, CDentry *destdn); public: // truncate void truncate_inode(CInode *in, LogSegment *ls); void _truncate_inode(CInode *in, LogSegment *ls); void truncate_inode_finish(CInode *in, LogSegment *ls); void truncate_inode_logged(CInode *in, MutationRef& mut); void add_recovered_truncate(CInode *in, LogSegment *ls); void remove_recovered_truncate(CInode *in, LogSegment *ls); void start_recovered_truncates(); public: CDir *get_auth_container(CDir *in); CDir *get_export_container(CDir *dir); void find_nested_exports(CDir *dir, set& s); void find_nested_exports_under(CDir *import, CDir *dir, set& s); private: bool opening_root, open; list waiting_for_open; public: void init_layouts(); CInode *create_system_inode(inodeno_t ino, int mode); CInode *create_root_inode(); void create_empty_hierarchy(C_Gather *gather); void create_mydir_hierarchy(C_Gather *gather); bool is_open() { return open; } void wait_for_open(Context *c) { waiting_for_open.push_back(c); } void open_root_inode(Context *c); void open_root(); void open_mydir_inode(Context *c); void populate_mydir(); void _create_system_file(CDir *dir, const char *name, CInode *in, Context *fin); void _create_system_file_finish(MutationRef& mut, CDentry *dn, version_t dpv, Context *fin); void open_foreign_mdsdir(inodeno_t ino, Context *c); CDentry *get_or_create_stray_dentry(CInode *in); Context *_get_waiter(MDRequestRef& mdr, Message *req, Context *fin); /** * Find the given dentry (and whether it exists or not), its ancestors, * and get them all into memory and usable on this MDS. This function * makes a best-effort attempt to load everything; if it needs to * go away and do something then it will put the request on a waitlist. * It prefers the mdr, then the req, then the fin. (At least one of these * must be non-null.) * * At least one of the params mdr, req, and fin must be non-null. * * @param mdr The MDRequest associated with the path. Can be null. * @param req The Message associated with the path. Can be null. * @param fin The Context associated with the path. Can be null. * @param path The path to traverse to. * @param pdnvec Data return parameter -- on success, contains a * vector of dentries. On failure, is either empty or contains the * full trace of traversable dentries. * @param pin Data return parameter -- if successful, points to the inode * associated with filepath. If unsuccessful, is null. * @param onfail Specifies different lookup failure behaviors. If set to * MDS_TRAVERSE_DISCOVERXLOCK, path_traverse will succeed on null * dentries (instead of returning -ENOENT). If set to * MDS_TRAVERSE_FORWARD, it will forward the request to the auth * MDS if that becomes appropriate (ie, if it doesn't know the contents * of a directory). If set to MDS_TRAVERSE_DISCOVER, it * will attempt to look up the path from a different MDS (and bring them * into its cache as replicas). * * @returns 0 on success, 1 on "not done yet", 2 on "forwarding", -errno otherwise. * If it returns 1, the requester associated with this call has been placed * on the appropriate waitlist, and it should unwind itself and back out. * If it returns 2 the request has been forwarded, and again the requester * should unwind itself and back out. */ int path_traverse(MDRequestRef& mdr, Message *req, Context *fin, const filepath& path, vector *pdnvec, CInode **pin, int onfail); bool path_is_mine(filepath& path); bool path_is_mine(string& p) { filepath path(p, 1); return path_is_mine(path); } CInode *cache_traverse(const filepath& path); void open_remote_dirfrag(CInode *diri, frag_t fg, Context *fin); CInode *get_dentry_inode(CDentry *dn, MDRequestRef& mdr, bool projected=false); void open_remote_ino(inodeno_t ino, Context *fin, bool want_xlocked=false, inodeno_t hadino=0, version_t hadv=0); void open_remote_ino_2(inodeno_t ino, vector& anchortrace, bool want_xlocked, inodeno_t hadino, version_t hadv, Context *onfinish); bool parallel_fetch(map& pathmap, set& missing); bool parallel_fetch_traverse_dir(inodeno_t ino, filepath& path, set& fetch_queue, set& missing, C_GatherBuilder &gather_bld); void open_remote_dentry(CDentry *dn, bool projected, Context *fin, bool want_xlocked=false); void _open_remote_dentry_finish(CDentry *dn, inodeno_t ino, Context *fin, bool want_xlocked, int mode, int r); void make_trace(vector& trace, CInode *in); protected: struct open_ino_info_t { vector ancestors; set checked; int checking; int auth_hint; bool check_peers; bool fetch_backtrace; bool discover; bool want_replica; bool want_xlocked; version_t tid; int64_t pool; list waiters; open_ino_info_t() : checking(-1), auth_hint(-1), check_peers(true), fetch_backtrace(true), discover(false) {} }; ceph_tid_t open_ino_last_tid; map opening_inodes; void _open_ino_backtrace_fetched(inodeno_t ino, bufferlist& bl, int err); void _open_ino_parent_opened(inodeno_t ino, int ret); void _open_ino_traverse_dir(inodeno_t ino, open_ino_info_t& info, int err); void _open_ino_fetch_dir(inodeno_t ino, MMDSOpenIno *m, CDir *dir); Context* _open_ino_get_waiter(inodeno_t ino, MMDSOpenIno *m); int open_ino_traverse_dir(inodeno_t ino, MMDSOpenIno *m, vector& ancestors, bool discover, bool want_xlocked, int *hint); void open_ino_finish(inodeno_t ino, open_ino_info_t& info, int err); void do_open_ino(inodeno_t ino, open_ino_info_t& info, int err); void do_open_ino_peer(inodeno_t ino, open_ino_info_t& info); void handle_open_ino(MMDSOpenIno *m); void handle_open_ino_reply(MMDSOpenInoReply *m); friend class C_MDC_OpenInoBacktraceFetched; friend struct C_MDC_OpenInoTraverseDir; friend struct C_MDC_OpenInoParentOpened; public: void kick_open_ino_peers(int who); void open_ino(inodeno_t ino, int64_t pool, Context *fin, bool want_replica=true, bool want_xlocked=false); // -- find_ino_peer -- struct find_ino_peer_info_t { inodeno_t ino; ceph_tid_t tid; Context *fin; int hint; int checking; set checked; find_ino_peer_info_t() : tid(0), fin(NULL), hint(-1), checking(-1) {} }; map find_ino_peer; ceph_tid_t find_ino_peer_last_tid; void find_ino_peers(inodeno_t ino, Context *c, int hint=-1); void _do_find_ino_peer(find_ino_peer_info_t& fip); void handle_find_ino(MMDSFindIno *m); void handle_find_ino_reply(MMDSFindInoReply *m); void kick_find_ino_peers(int who); // -- anchors -- public: void anchor_create_prep_locks(MDRequestRef& mdr, CInode *in, set& rdlocks, set& xlocks); void anchor_create(MDRequestRef& mdr, CInode *in, Context *onfinish); void anchor_destroy(CInode *in, Context *onfinish); protected: void _anchor_prepared(CInode *in, version_t atid, bool add); void _anchor_logged(CInode *in, version_t atid, MutationRef& mut); friend class C_MDC_AnchorPrepared; friend class C_MDC_AnchorLogged; // -- snaprealms -- public: void snaprealm_create(MDRequestRef& mdr, CInode *in); void _snaprealm_create_finish(MDRequestRef& mdr, MutationRef& mut, CInode *in); // -- stray -- public: elist delayed_eval_stray; void eval_stray(CDentry *dn, bool delay=false); void eval_remote(CDentry *dn); void maybe_eval_stray(CInode *in, bool delay=false) { if (in->inode.nlink > 0 || in->is_base()) return; CDentry *dn = in->get_projected_parent_dn(); if (!dn->state_test(CDentry::STATE_PURGING) && dn->get_projected_linkage()->is_primary() && dn->get_dir()->get_inode()->is_stray()) eval_stray(dn, delay); } protected: void scan_stray_dir(dirfrag_t next=dirfrag_t()); void fetch_backtrace(inodeno_t ino, int64_t pool, bufferlist& bl, Context *fin); void purge_stray(CDentry *dn); void _purge_stray_purged(CDentry *dn, int r=0); void _purge_stray_logged(CDentry *dn, version_t pdv, LogSegment *ls); void _purge_stray_logged_truncate(CDentry *dn, LogSegment *ls); friend struct C_MDC_RetryScanStray; friend class C_MDC_FetchedBacktrace; friend class C_MDC_PurgeStrayLogged; friend class C_MDC_PurgeStrayLoggedTruncate; friend class C_MDC_PurgeStrayPurged; void reintegrate_stray(CDentry *dn, CDentry *rlink); void migrate_stray(CDentry *dn, int dest); // == messages == public: void dispatch(Message *m); protected: // -- replicas -- void handle_discover(MDiscover *dis); void handle_discover_reply(MDiscoverReply *m); friend class C_MDC_Join; public: void replicate_dir(CDir *dir, int to, bufferlist& bl) { dirfrag_t df = dir->dirfrag(); ::encode(df, bl); dir->encode_replica(to, bl); } void replicate_dentry(CDentry *dn, int to, bufferlist& bl) { ::encode(dn->name, bl); ::encode(dn->last, bl); dn->encode_replica(to, bl); } void replicate_inode(CInode *in, int to, bufferlist& bl) { ::encode(in->inode.ino, bl); // bleh, minor assymetry here ::encode(in->last, bl); in->encode_replica(to, bl); } CDir* add_replica_dir(bufferlist::iterator& p, CInode *diri, int from, list& finished); CDir* forge_replica_dir(CInode *diri, frag_t fg, int from); CDentry *add_replica_dentry(bufferlist::iterator& p, CDir *dir, list& finished); CInode *add_replica_inode(bufferlist::iterator& p, CDentry *dn, list& finished); void replicate_stray(CDentry *straydn, int who, bufferlist& bl); CDentry *add_replica_stray(bufferlist &bl, int from); // -- namespace -- public: void send_dentry_link(CDentry *dn); void send_dentry_unlink(CDentry *dn, CDentry *straydn, MDRequestRef& mdr); protected: void handle_dentry_link(MDentryLink *m); void handle_dentry_unlink(MDentryUnlink *m); // -- fragmenting -- private: struct ufragment { int bits; bool committed; LogSegment *ls; list waiters; list old_frags; bufferlist rollback; ufragment() : bits(0), committed(false), ls(NULL) {} }; map uncommitted_fragments; struct fragment_info_t { int bits; list dirs; list resultfrags; MDRequestRef mdr; // for deadlock detection bool has_frozen; utime_t last_cum_auth_pins_change; int last_cum_auth_pins; int num_remote_waiters; // number of remote authpin waiters fragment_info_t() : has_frozen(false), last_cum_auth_pins(0), num_remote_waiters(0) {} }; map fragments; void adjust_dir_fragments(CInode *diri, frag_t basefrag, int bits, list& frags, list& waiters, bool replay); void adjust_dir_fragments(CInode *diri, list& srcfrags, frag_t basefrag, int bits, list& resultfrags, list& waiters, bool replay); CDir *force_dir_fragment(CInode *diri, frag_t fg, bool replay=true); void get_force_dirfrag_bound_set(vector& dfs, set& bounds); bool can_fragment(CInode *diri, list& dirs); void fragment_freeze_dirs(list& dirs, C_GatherBuilder &gather); void fragment_mark_and_complete(list& dirs); void fragment_frozen(dirfrag_t basedirfrag, int r); void fragment_unmark_unfreeze_dirs(list& dirs); void dispatch_fragment_dir(MDRequestRef& mdr); void _fragment_logged(MDRequestRef& mdr); void _fragment_stored(MDRequestRef& mdr); void _fragment_committed(dirfrag_t f, list& resultfrags); void _fragment_finish(dirfrag_t f, list& resultfrags); friend class EFragment; friend class C_MDC_FragmentFrozen; friend class C_MDC_FragmentMarking; friend class C_MDC_FragmentPrep; friend class C_MDC_FragmentStore; friend class C_MDC_FragmentCommit; friend class C_MDC_FragmentFinish; void handle_fragment_notify(MMDSFragmentNotify *m); void add_uncommitted_fragment(dirfrag_t basedirfrag, int bits, list& old_frag, LogSegment *ls, bufferlist *rollback=NULL); void finish_uncommitted_fragment(dirfrag_t basedirfrag, int op); void rollback_uncommitted_fragment(dirfrag_t basedirfrag, list& old_frags); public: void wait_for_uncommitted_fragment(dirfrag_t dirfrag, Context *c) { assert(uncommitted_fragments.count(dirfrag)); uncommitted_fragments[dirfrag].waiters.push_back(c); } void split_dir(CDir *dir, int byn); void merge_dir(CInode *diri, frag_t fg); void rollback_uncommitted_fragments(); void find_stale_fragment_freeze(); void fragment_freeze_inc_num_waiters(CDir *dir); bool fragment_are_all_frozen(CDir *dir); int get_num_fragmenting_dirs() { return fragments.size(); } // -- updates -- //int send_inode_updates(CInode *in); //void handle_inode_update(MInodeUpdate *m); int send_dir_updates(CDir *in, bool bcast=false); void handle_dir_update(MDirUpdate *m); // -- cache expiration -- void handle_cache_expire(MCacheExpire *m); void process_delayed_expire(CDir *dir); void discard_delayed_expire(CDir *dir); // == crap fns == public: void show_cache(); void dump_cache(const char *fn=0); void show_subtrees(int dbl=10); CInode *hack_pick_random_inode() { assert(!inode_map.empty()); int n = rand() % inode_map.size(); ceph::unordered_map::iterator p = inode_map.begin(); while (n--) ++p; return p->second; } }; class C_MDS_RetryRequest : public Context { MDCache *cache; MDRequestRef mdr; public: C_MDS_RetryRequest(MDCache *c, MDRequestRef& r); virtual void finish(int r); }; #endif ceph-0.80.11/src/mds/MDSUtility.cc0000664000175100017510000000720712623076744020573 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 John Spray * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include "mds/MDSUtility.h" #include "mon/MonClient.h" #define dout_subsys ceph_subsys_mds MDSUtility::MDSUtility() : Dispatcher(g_ceph_context), objecter(NULL), lock("MDSUtility::lock"), timer(g_ceph_context, lock), waiting_for_mds_map(NULL) { monc = new MonClient(g_ceph_context); messenger = Messenger::create_client_messenger(g_ceph_context, "mds"); mdsmap = new MDSMap(); osdmap = new OSDMap(); objecter = new Objecter(g_ceph_context, messenger, monc, osdmap, lock, timer, 0, 0); } MDSUtility::~MDSUtility() { delete objecter; delete monc; delete messenger; delete osdmap; delete mdsmap; assert(waiting_for_mds_map == NULL); } int MDSUtility::init() { // Initialize Messenger int r = messenger->bind(g_conf->public_addr); if (r < 0) return r; messenger->add_dispatcher_head(this); messenger->start(); // Initialize MonClient if (monc->build_initial_monmap() < 0) return -1; monc->set_want_keys(CEPH_ENTITY_TYPE_MON|CEPH_ENTITY_TYPE_OSD|CEPH_ENTITY_TYPE_MDS); monc->set_messenger(messenger); monc->init(); r = monc->authenticate(); if (r < 0) { derr << "Authentication failed, did you specify an MDS ID with a valid keyring?" << dendl; return r; } client_t whoami = monc->get_global_id(); messenger->set_myname(entity_name_t::CLIENT(whoami.v)); // Initialize Objecter and wait for OSD map objecter->set_client_incarnation(0); objecter->init_unlocked(); lock.Lock(); objecter->init_locked(); lock.Unlock(); objecter->wait_for_osd_map(); timer.init(); // Prepare to receive MDS map and request it Mutex init_lock("MDSUtility:init"); Cond cond; bool done = false; assert(!mdsmap->get_epoch()); lock.Lock(); waiting_for_mds_map = new C_SafeCond(&init_lock, &cond, &done, NULL); lock.Unlock(); monc->sub_want("mdsmap", 0, CEPH_SUBSCRIBE_ONETIME); monc->renew_subs(); // Wait for MDS map dout(4) << "waiting for MDS map..." << dendl; init_lock.Lock(); while (!done) cond.Wait(init_lock); init_lock.Unlock(); dout(4) << "Got MDS map " << mdsmap->get_epoch() << dendl; return 0; } void MDSUtility::shutdown() { lock.Lock(); timer.shutdown(); objecter->shutdown_locked(); lock.Unlock(); objecter->shutdown_unlocked(); monc->shutdown(); messenger->shutdown(); messenger->wait(); } bool MDSUtility::ms_dispatch(Message *m) { Mutex::Locker locker(lock); switch (m->get_type()) { case CEPH_MSG_OSD_OPREPLY: objecter->handle_osd_op_reply((MOSDOpReply *)m); break; case CEPH_MSG_OSD_MAP: objecter->handle_osd_map((MOSDMap*)m); break; case CEPH_MSG_MDS_MAP: handle_mds_map((MMDSMap*)m); break; default: return false; } return true; } void MDSUtility::handle_mds_map(MMDSMap* m) { mdsmap->decode(m->get_encoded()); if (waiting_for_mds_map) { waiting_for_mds_map->complete(0); waiting_for_mds_map = NULL; } } bool MDSUtility::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) { if (dest_type == CEPH_ENTITY_TYPE_MON) return true; if (force_new) { if (monc->wait_auth_rotating(10) < 0) return false; } *authorizer = monc->auth->build_authorizer(dest_type); return *authorizer != NULL; } ceph-0.80.11/src/mds/AnchorServer.h0000664000175100017510000000534212623076744021025 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_ANCHORSERVER_H #define CEPH_ANCHORSERVER_H #include "MDSTableServer.h" #include "Anchor.h" class AnchorServer : public MDSTableServer { public: AnchorServer(MDS *mds) : MDSTableServer(mds, TABLE_ANCHOR) {} // table bits map anchor_map; // uncommitted operations map pending_create; map pending_destroy; map > > pending_update; map > > pending_ops; void reset_state(); void encode_server_state(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(anchor_map, bl); ::encode(pending_create, bl); ::encode(pending_destroy, bl); ::encode(pending_update, bl); ENCODE_FINISH(bl); } void decode_server_state(bufferlist::iterator& p) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, p); ::decode(anchor_map, p); ::decode(pending_create, p); ::decode(pending_destroy, p); ::decode(pending_update, p); DECODE_FINISH(p); map sort; sort.insert(pending_create.begin(), pending_create.end()); sort.insert(pending_destroy.begin(), pending_destroy.end()); for (map > >::iterator p = pending_update.begin(); p != pending_update.end(); ++p) sort[p->first] = p->second.first; for (map::iterator p = sort.begin(); p != sort.end(); ++p) pending_ops[p->second].push_back(pair(p->first, NULL)); } bool add(inodeno_t ino, inodeno_t dirino, __u32 dn_hash, bool replace); void inc(inodeno_t ino, int ref=1); void dec(inodeno_t ino, int ref=1); bool check_pending(version_t tid, MMDSTableRequest *req, list& finished); void dump(); void dump(Formatter *f) const; static void generate_test_instances(list& ls); // for the dencoder AnchorServer() : MDSTableServer(NULL, TABLE_ANCHOR) {} void encode(bufferlist& bl) const { encode_server_state(bl); } void decode(bufferlist::iterator& bl) { decode_server_state(bl); } // server bits void _prepare(bufferlist &bl, uint64_t reqid, int bymds); bool _commit(version_t tid, MMDSTableRequest *req=NULL); void _rollback(version_t tid); void handle_query(MMDSTableRequest *m); }; #endif ceph-0.80.11/src/bash_completion/0000775000175100017510000000000012623077035020624 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/bash_completion/rados0000664000175100017510000000225212623076744021666 0ustar jenkins-buildjenkins-build# # Ceph - scalable distributed file system # # Copyright (C) 2011 Wido den Hollander # # This is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License version 2.1, as published by the Free Software # Foundation. See file COPYING. # _rados() { local cur prev COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "-c --conf -m -d -f -p --pool -b --snap -i -o --create" -- ${cur}) ) return 0 fi case "${prev}" in --conf | -c | -o | -i) COMPREPLY=( $(compgen -f ${cur}) ) return 0 ;; -m) COMPREPLY=( $(compgen -A hostname ${cur}) ) return 0 ;; *) COMPREPLY=( $(compgen -W "lspools mkpool rmpool df ls chown get put create rm listxattr getxattr setxattr rmxattr stat mapext lssnap mksnap rmsnap rollback bench" -- ${cur}) ) return 0 ;; esac } complete -F _rados rados ceph-0.80.11/src/bash_completion/radosgw-admin0000664000175100017510000000344112623076744023313 0ustar jenkins-buildjenkins-build# # Ceph - scalable distributed file system # # Copyright (C) 2011 Wido den Hollander # # This is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License version 2.1, as published by the Free Software # Foundation. See file COPYING. # _radosgw_admin() { local cur prev COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "--uid --subuser --access-key --os-user --email --auth_uid --secret --os-secret --gen-access-key --gen-secret \ --access --display-name --bucket --object --date --conf --name --id --version -s -w" -- ${cur}) ) return 0 fi case "${prev}" in --conf | -c) COMPREPLY=( $(compgen -f ${cur}) ) return 0 ;; -m) COMPREPLY=( $(compgen -A hostname ${cur}) ) return 0 ;; user) COMPREPLY=( $(compgen -W "create modify info rm" -- ${cur}) ) return 0 ;; subuser) COMPREPLY=( $(compgen -W "create modify rm" -- ${cur}) ) return 0 ;; key) COMPREPLY=( $(compgen -W "create rm" -- ${cur}) ) return 0 ;; buckets) COMPREPLY=( $(compgen -W "list unlink" -- ${cur}) ) return 0 ;; *) COMPREPLY=( $(compgen -W "user subuser key buckets policy log" -- ${cur}) ) return 0 ;; esac } complete -F _radosgw_admin radosgw-admin ceph-0.80.11/src/bash_completion/ceph0000664000175100017510000000355712623076744021506 0ustar jenkins-buildjenkins-build# # Ceph - scalable distributed file system # # Copyright (C) 2011 Wido den Hollander # # This is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License version 2.1, as published by the Free Software # Foundation. See file COPYING. # _ceph() { local cur prev COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "--conf -c --name --id -m --version -s --status -w --watch -o --out-file -i --in-file" -- ${cur}) ) return 0 fi case "${prev}" in -o | --out-file | -i | --in-file | --conf | -c) COMPREPLY=( $(compgen -f ${cur}) ) return 0 ;; -m) COMPREPLY=( $(compgen -A hostname ${cur}) ) return 0 ;; auth) COMPREPLY=( $(compgen -W "list add del" -- ${cur}) ) return 0 ;; pg) COMPREPLY=( $(compgen -W "stat dump getmap map send_pg_creates scrub deep-scrub repair" -- ${cur}) ) return 0 ;; osd) COMPREPLY=( $(compgen -W "tell stat pool dump getmaxosd tree getmap getcrushmap lspools" -- ${cur}) ) return 0 ;; mon) COMPREPLY=( $(compgen -W "tell stat getmap" -- ${cur}) ) return 0 ;; mds) COMPREPLY=( $(compgen -W "tell stat stat getmap dump compat" -- ${cur}) ) return 0 ;; *) COMPREPLY=( $(compgen -W "osd mon mds pg auth" -- ${cur}) ) return 0 ;; esac } complete -F _ceph ceph ceph-0.80.11/src/bash_completion/rbd0000664000175100017510000000251112623076744021323 0ustar jenkins-buildjenkins-build# # Ceph - scalable distributed file system # # Copyright (C) 2011 Wido den Hollander # # This is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License version 2.1, as published by the Free Software # Foundation. See file COPYING. # _rbd() { local cur prev COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "-c --conf -m -d -f -p --pool --snap -i -o --image --dest --dest-pool --path --size --id --keyfile" -- ${cur}) ) return 0 fi case "${prev}" in --conf | -c | --path | --keyfile | --keyring) COMPREPLY=( $(compgen -f ${cur}) ) return 0 ;; -m) COMPREPLY=( $(compgen -A hostname ${cur}) ) return 0 ;; snap) COMPREPLY=( $(compgen -W "ls create rollback rm" -- ${cur}) ) return 0 ;; *) COMPREPLY=( $(compgen -W "ls list info create resize rm export import cp copy mv rename snap watch map unmap showmapped" -- ${cur}) ) return 0 ;; esac } complete -F _rbd rbd ceph-0.80.11/src/upstart/0000775000175100017510000000000012623077036017161 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/upstart/radosgw-all-starter.conf0000664000175100017510000000101012623076744023723 0ustar jenkins-buildjenkins-builddescription "Ceph radosgw (task to start all instances)" start on starting radosgw-all task script set -e # TODO what's the valid charset for cluster names and daemon ids? find -L /var/lib/ceph/radosgw/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -printf '%P\n' \ | while read f; do if [ -e "/var/lib/ceph/radosgw/$f/done" ]; then cluster="${f%%-*}" id="${f#*-}" initctl emit radosgw cluster="$cluster" id="$id" fi done end script ceph-0.80.11/src/upstart/ceph-osd.conf0000664000175100017510000000335412623076744021544 0ustar jenkins-buildjenkins-builddescription "Ceph OSD" start on ceph-osd stop on runlevel [!2345] or stopping ceph-osd-all respawn respawn limit 3 1800 limit nofile 32768 32768 pre-start script set -e test -x /usr/bin/ceph-osd || { stop; exit 0; } test -d "/var/lib/ceph/osd/${cluster:-ceph}-$id" || { stop; exit 0; } install -d -m0755 /var/run/ceph update="$(ceph-conf --cluster=${cluster:-ceph} --name=osd.$id --lookup osd_crush_update_on_start || :)" if [ "${update:-1}" = "1" -o "${update:-1}" = "true" ]; then # update location in crush hook="$(ceph-conf --cluster=${cluster:-ceph} --name=osd.$id --lookup osd_crush_location_hook || :)" if [ -z "$hook" ]; then hook="/usr/bin/ceph-crush-location" fi location="$($hook --cluster ${cluster:-ceph} --id $id --type osd)" weight="$(ceph-conf --cluster=${cluster:-ceph} --name=osd.$id --lookup osd_crush_initial_weight || :)" defaultweight=`df -P -k /var/lib/ceph/osd/${cluster:-ceph}-$id/ | tail -1 | awk '{ d= $2/1073741824 ; r = sprintf("%.2f", d); print r }'` ceph \ --cluster="${cluster:-ceph}" \ --name="osd.$id" \ --keyring="/var/lib/ceph/osd/${cluster:-ceph}-$id/keyring" \ osd crush create-or-move \ -- \ "$id" \ "${weight:-${defaultweight:-1}}" \ $location fi journal="/var/lib/ceph/osd/${cluster:-ceph}-$id/journal" if [ -L "$journal" -a ! -e "$journal" ]; then udevadm settle --timeout=5 || : if [ -L "$journal" -a ! -e "$journal" ]; then echo "ceph-osd($UPSTART_INSTANCE): journal not present, not starting yet." 1>&2 stop exit 0 fi fi end script instance ${cluster:-ceph}/$id export cluster export id exec /usr/bin/ceph-osd --cluster="${cluster:-ceph}" -i "$id" -f ceph-0.80.11/src/upstart/ceph-mon.conf0000664000175100017510000000126212623076744021544 0ustar jenkins-buildjenkins-builddescription "Ceph MON" start on ceph-mon stop on runlevel [!2345] or stopping ceph-mon-all respawn respawn limit 3 1800 limit nofile 16384 16384 pre-start script set -e test -x /usr/bin/ceph-mon || { stop; exit 0; } test -d "/var/lib/ceph/mon/${cluster:-ceph}-$id" || { stop; exit 0; } install -d -m0755 /var/run/ceph end script instance ${cluster:-ceph}/$id export cluster export id # this breaks oneiric #usage "cluster = name of cluster (defaults to 'ceph'); id = monitor instance id" exec /usr/bin/ceph-mon --cluster="${cluster:-ceph}" -i "$id" -f post-stop script # Cleanup socket in case of segfault rm -f "/var/run/ceph/ceph-mon.$id.asok" end script ceph-0.80.11/src/upstart/ceph-mds-all.conf0000664000175100017510000000013512623076744022302 0ustar jenkins-buildjenkins-builddescription "Ceph MDS (all instances)" start on starting ceph-all stop on stopping ceph-all ceph-0.80.11/src/upstart/rbdmap.conf0000664000175100017510000000213512623076744021303 0ustar jenkins-buildjenkins-build# rbdmap - Ceph RBD Mapping # # This script does not manage mount and unmount fs which depends on rbd device. # You should use _netdev option in fstab to mount and umount in the correct order. description "ceph rbd mapping" start on (started networking and remote-filesystems) stop on unmounted-remote-filesystems env RBDMAPFILE="/etc/ceph/rbdmap" pre-start script if [ ! -f "$RBDMAPFILE" ]; then exit 0 fi while read DEV PARAMS; do case "$DEV" in ""|\#*) continue ;; */*) ;; *) DEV=rbd/$DEV ;; esac for PARAM in $(echo $PARAMS | tr ',' '\n'); do CMDPARAMS="$CMDPARAMS --$(echo $PARAM | tr '=' ' ')" done if [ ! -b /dev/rbd/$DEV ]; then echo "rbd map $DEV" rbd map $DEV $CMDPARAMS fi done < $RBDMAPFILE end script post-stop script if ls /dev/rbd[0-9]* >/dev/null 2>&1; then for DEV in /dev/rbd[0-9]*; do echo "rbd unmap $DEV" rbd unmap $DEV done fi end script ceph-0.80.11/src/upstart/ceph-all.conf0000664000175100017510000000010612623076744021517 0ustar jenkins-buildjenkins-builddescription "Ceph" start on runlevel [2345] stop on runlevel [!2345] ceph-0.80.11/src/upstart/ceph-osd-all-starter.conf0000664000175100017510000000117712623076744023775 0ustar jenkins-buildjenkins-builddescription "Ceph OSD (start all instances)" start on starting ceph-osd-all task script set -e # first activate any partitions ceph-disk activate-all # TODO what's the valid charset for cluster names and osd ids? find -L /var/lib/ceph/osd/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -printf '%P\n' \ | while read f; do if [ -e "/var/lib/ceph/osd/$f/ready" ] && [ -e "/var/lib/ceph/osd/$f/upstart" ] && [ ! -e "/var/lib/ceph/osd/$f/sysvinit" ]; then cluster="${f%%-*}" id="${f#*-}" initctl emit ceph-osd cluster="$cluster" id="$id" fi done end script ceph-0.80.11/src/upstart/radosgw.conf0000664000175100017510000000107712623076744021510 0ustar jenkins-buildjenkins-builddescription "Ceph radosgw" start on radosgw stop on runlevel [!2345] or stopping radosgw-all respawn respawn limit 5 30 limit nofile 8096 65536 pre-start script set -e test -x /usr/bin/radosgw || { stop; exit 0; } test -d "/var/lib/ceph/radosgw/${cluster:-ceph}-$id" || { stop; exit 0; } install -d -m0755 /var/run/ceph end script instance ${cluster:-ceph}/$id export cluster export id # this breaks oneiric #usage "cluster = name of cluster (defaults to 'ceph'); id = mds instance id" exec /usr/bin/radosgw --cluster="${cluster:-ceph}" --id "$id" -f ceph-0.80.11/src/upstart/radosgw-all.conf0000664000175100017510000000016512623076744022253 0ustar jenkins-buildjenkins-builddescription "Ceph radosgw (all instances)" start on starting ceph-all stop on runlevel [!2345] or stopping ceph-all ceph-0.80.11/src/upstart/ceph-mon-all.conf0000664000175100017510000000016512623076744022313 0ustar jenkins-buildjenkins-builddescription "Ceph monitor (all instances)" start on starting ceph-all stop on runlevel [!2345] or stopping ceph-all ceph-0.80.11/src/upstart/ceph-osd-all.conf0000664000175100017510000000016112623076744022303 0ustar jenkins-buildjenkins-builddescription "Ceph OSD (all instances)" start on starting ceph-all stop on runlevel [!2345] or stopping ceph-all ceph-0.80.11/src/upstart/ceph-mon-all-starter.conf0000664000175100017510000000110212623076744023765 0ustar jenkins-buildjenkins-builddescription "Ceph MON (start all instances)" start on starting ceph-mon-all task script set -e # TODO what's the valid charset for cluster names and mon ids? find -L /var/lib/ceph/mon/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -printf '%P\n' \ | while read f; do if [ -e "/var/lib/ceph/mon/$f/done" ] && [ -e "/var/lib/ceph/mon/$f/upstart" ] && [ ! -e "/var/lib/ceph/mon/$f/sysvinit" ]; then cluster="${f%%-*}" id="${f#*-}" initctl emit ceph-mon cluster="$cluster" id="$id" fi done end script ceph-0.80.11/src/upstart/ceph-create-keys.conf0000664000175100017510000000031212623076744023162 0ustar jenkins-buildjenkins-builddescription "Create Ceph client.admin key when possible" start on started ceph-mon stop on stopping ceph-mon task exec /usr/sbin/ceph-create-keys --cluster="${cluster:-ceph}" -i "${id:-$(hostname)}" ceph-0.80.11/src/upstart/ceph-mds-all-starter.conf0000664000175100017510000000111012623076744023756 0ustar jenkins-buildjenkins-builddescription "Ceph MDS (start all instances)" start on starting ceph-mds-all task script set -e # TODO what's the valid charset for cluster names and mds ids? find -L /var/lib/ceph/mds/ -mindepth 1 -maxdepth 1 -regextype posix-egrep -regex '.*/[A-Za-z0-9]+-[A-Za-z0-9._-]+' -printf '%P\n' \ | while read f; do if [ -e "/var/lib/ceph/mds/$f/done" ] && [ -e "/var/lib/ceph/mds/$f/upstart" ] && [ ! -e "/var/lib/ceph/mds/$f/sysvinit" ]; then cluster="${f%%-*}" id="${f#*-}" initctl emit ceph-mds cluster="$cluster" id="$id" fi done end script ceph-0.80.11/src/upstart/ceph-mds.conf0000664000175100017510000000107412623076744021537 0ustar jenkins-buildjenkins-builddescription "Ceph MDS" start on ceph-mds stop on runlevel [!2345] or stopping ceph-mds-all respawn respawn limit 3 1800 limit nofile 16384 16384 pre-start script set -e test -x /usr/bin/ceph-mds || { stop; exit 0; } test -d "/var/lib/ceph/mds/${cluster:-ceph}-$id" || { stop; exit 0; } install -d -m0755 /var/run/ceph end script instance ${cluster:-ceph}/$id export cluster export id # this breaks oneiric #usage "cluster = name of cluster (defaults to 'ceph'); id = mds instance id" exec /usr/bin/ceph-mds --cluster="${cluster:-ceph}" -i "$id" -f ceph-0.80.11/src/stop.sh0000775000175100017510000000502512623076744017012 0ustar jenkins-buildjenkins-build#!/bin/bash # # Copyright (C) 2013 Inktank # Copyright (C) 2013 Cloudwatt # # Author: Loic Dachary # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library Public License for more details. # test -d dev/osd0/. && test -e dev/sudo && SUDO="sudo" [ -z "$CEPH_BIN" ] && CEPH_BIN=. do_killall() { pg=`pgrep -f ceph-run.*$1` [ -n "$pg" ] && kill $pg $SUDO killall $1 } usage="usage: $0 [all] [mon] [mds] [osd]\n" stop_all=1 stop_mon=0 stop_mds=0 stop_osd=0 stop_rgw=0 while [ $# -ge 1 ]; do case $1 in all ) stop_all=1 ;; mon | ceph-mon ) stop_mon=1 stop_all=0 ;; mds | ceph-mds ) stop_mds=1 stop_all=0 ;; osd | ceph-osd ) stop_osd=1 stop_all=0 ;; * ) printf "$usage" exit esac shift done if [ $stop_all -eq 1 ]; then while read DEV; do # While it is currently possible to create an rbd image with # whitespace chars in its name, krbd will refuse mapping such # an image, so we can safely split on whitespace here. (The # same goes for whitespace chars in names of the pools that # contain rbd images). DEV="$(echo "${DEV}" | tr -s '[:space:]' | awk '{ print $5 }')" sudo "${CEPH_BIN}"/rbd unmap "${DEV}" done < <("${CEPH_BIN}"/rbd showmapped | tail -n +2) if [ -n "$("${CEPH_BIN}"/rbd showmapped)" ]; then echo "WARNING: Some rbd images are still mapped!" >&2 fi for p in ceph-mon ceph-mds ceph-osd radosgw lt-radosgw apache2 ; do for try in 0 1 1 1 1 ; do if ! pkill $p ; then break fi sleep $try done done pkill -f valgrind.bin.\*ceph-mon $SUDO pkill -f valgrind.bin.\*ceph-osd pkill -f valgrind.bin.\*ceph-mds else [ $stop_mon -eq 1 ] && do_killall ceph-mon [ $stop_mds -eq 1 ] && do_killall ceph-mds [ $stop_osd -eq 1 ] && do_killall ceph-osd [ $stop_rgw -eq 1 ] && do_killall radosgw lt-radosgw apache2 fi ceph-0.80.11/src/pybind/0000775000175100017510000000000012623077033016741 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/pybind/ceph_rest_api.py0000775000175100017510000004101412623076744022133 0ustar jenkins-buildjenkins-build# vim: ts=4 sw=4 smarttab expandtab import errno import json import logging import logging.handlers import os import rados import textwrap import xml.etree.ElementTree import xml.sax.saxutils import flask from ceph_argparse import \ ArgumentError, CephPgid, CephOsdName, CephChoices, CephPrefix, \ concise_sig, descsort, parse_funcsig, parse_json_funcsigs, \ validate, json_command # # Globals and defaults # DEFAULT_ADDR = '0.0.0.0' DEFAULT_PORT = '5000' DEFAULT_ID = 'restapi' DEFAULT_BASEURL = '/api/v0.1' DEFAULT_LOG_LEVEL = 'warning' DEFAULT_LOGDIR = '/var/log/ceph' # default client name will be 'client.' # 'app' must be global for decorators, etc. APPNAME = '__main__' app = flask.Flask(APPNAME) LOGLEVELS = { 'critical':logging.CRITICAL, 'error':logging.ERROR, 'warning':logging.WARNING, 'info':logging.INFO, 'debug':logging.DEBUG, } def find_up_osd(app): ''' Find an up OSD. Return the last one that's up. Returns id as an int. ''' ret, outbuf, outs = json_command(app.ceph_cluster, prefix="osd dump", argdict=dict(format='json')) if ret: raise EnvironmentError(ret, 'Can\'t get osd dump output') try: osddump = json.loads(outbuf) except: raise EnvironmentError(errno.EINVAL, 'Invalid JSON back from osd dump') osds = [osd['osd'] for osd in osddump['osds'] if osd['up']] if not osds: return None return int(osds[-1]) METHOD_DICT = {'r':['GET'], 'w':['PUT', 'DELETE']} def api_setup(app, conf, cluster, clientname, clientid, args): ''' This is done globally, and cluster connection kept open for the lifetime of the daemon. librados should assure that even if the cluster goes away and comes back, our connection remains. Initialize the running instance. Open the cluster, get the command signatures, module, perms, and help; stuff them away in the app.ceph_urls dict. Also save app.ceph_sigdict for help() handling. ''' def get_command_descriptions(cluster, target=('mon','')): ret, outbuf, outs = json_command(cluster, target, prefix='get_command_descriptions', timeout=30) if ret: err = "Can't get command descriptions: {0}".format(outs) app.logger.error(err) raise EnvironmentError(ret, err) try: sigdict = parse_json_funcsigs(outbuf, 'rest') except Exception as e: err = "Can't parse command descriptions: {}".format(e) app.logger.error(err) raise EnvironmentError(err) return sigdict app.ceph_cluster = cluster or 'ceph' app.ceph_urls = {} app.ceph_sigdict = {} app.ceph_baseurl = '' conf = conf or '' cluster = cluster or 'ceph' clientid = clientid or DEFAULT_ID clientname = clientname or 'client.' + clientid app.ceph_cluster = rados.Rados(name=clientname, conffile=conf) app.ceph_cluster.conf_parse_argv(args) app.ceph_cluster.connect() app.ceph_baseurl = app.ceph_cluster.conf_get('restapi_base_url') \ or DEFAULT_BASEURL if app.ceph_baseurl.endswith('/'): app.ceph_baseurl = app.ceph_baseurl[:-1] addr = app.ceph_cluster.conf_get('public_addr') or DEFAULT_ADDR # remove any nonce from the conf value addr = addr.split('/')[0] addr, port = addr.rsplit(':', 1) addr = addr or DEFAULT_ADDR port = port or DEFAULT_PORT port = int(port) loglevel = app.ceph_cluster.conf_get('restapi_log_level') \ or DEFAULT_LOG_LEVEL # ceph has a default log file for daemons only; clients (like this) # default to "". Override that for this particular client. logfile = app.ceph_cluster.conf_get('log_file') if not logfile: logfile = os.path.join( DEFAULT_LOGDIR, '{cluster}-{clientname}.{pid}.log'.format( cluster=cluster, clientname=clientname, pid=os.getpid() ) ) app.logger.addHandler(logging.handlers.WatchedFileHandler(logfile)) app.logger.setLevel(LOGLEVELS[loglevel.lower()]) for h in app.logger.handlers: h.setFormatter(logging.Formatter( '%(asctime)s %(name)s %(levelname)s: %(message)s')) app.ceph_sigdict = get_command_descriptions(app.ceph_cluster) osdid = find_up_osd(app) if osdid is not None: osd_sigdict = get_command_descriptions(app.ceph_cluster, target=('osd', int(osdid))) # shift osd_sigdict keys up to fit at the end of the mon's app.ceph_sigdict maxkey = sorted(app.ceph_sigdict.keys())[-1] maxkey = int(maxkey.replace('cmd', '')) osdkey = maxkey + 1 for k, v in osd_sigdict.iteritems(): newv = v newv['flavor'] = 'tell' globk = 'cmd' + str(osdkey) app.ceph_sigdict[globk] = newv osdkey += 1 # app.ceph_sigdict maps "cmdNNN" to a dict containing: # 'sig', an array of argdescs # 'help', the helptext # 'module', the Ceph module this command relates to # 'perm', a 'rwx*' string representing required permissions, and also # a hint as to whether this is a GET or POST/PUT operation # 'avail', a comma-separated list of strings of consumers that should # display this command (filtered by parse_json_funcsigs() above) app.ceph_urls = {} for cmdnum, cmddict in app.ceph_sigdict.iteritems(): cmdsig = cmddict['sig'] flavor = cmddict.get('flavor', 'mon') url, params = generate_url_and_params(app, cmdsig, flavor) perm = cmddict['perm'] for k in METHOD_DICT.iterkeys(): if k in perm: methods = METHOD_DICT[k] urldict = {'paramsig':params, 'help':cmddict['help'], 'module':cmddict['module'], 'perm':perm, 'flavor':flavor, 'methods':methods, } # app.ceph_urls contains a list of urldicts (usually only one long) if url not in app.ceph_urls: app.ceph_urls[url] = [urldict] else: # If more than one, need to make union of methods of all. # Method must be checked in handler methodset = set(methods) for old_urldict in app.ceph_urls[url]: methodset |= set(old_urldict['methods']) methods = list(methodset) app.ceph_urls[url].append(urldict) # add, or re-add, rule with all methods and urldicts app.add_url_rule(url, url, handler, methods=methods) url += '.' app.add_url_rule(url, url, handler, methods=methods) app.logger.debug("urls added: %d", len(app.ceph_urls)) app.add_url_rule('/', '/', handler, methods=['GET', 'PUT']) return addr, port def generate_url_and_params(app, sig, flavor): ''' Digest command signature from cluster; generate an absolute (including app.ceph_baseurl) endpoint from all the prefix words, and a list of non-prefix param descs ''' url = '' params = [] # the OSD command descriptors don't include the 'tell ', so # tack it onto the front of sig if flavor == 'tell': tellsig = parse_funcsig(['tell', {'name':'target', 'type':'CephOsdName'}]) sig = tellsig + sig for desc in sig: # prefixes go in the URL path if desc.t == CephPrefix: url += '/' + desc.instance.prefix # CephChoices with 1 required string (not --) do too, unless # we've already started collecting params, in which case they # too are params elif desc.t == CephChoices and \ len(desc.instance.strings) == 1 and \ desc.req and \ not str(desc.instance).startswith('--') and \ not params: url += '/' + str(desc.instance) else: # tell/ is a weird case; the URL includes what # would everywhere else be a parameter if flavor == 'tell' and \ (desc.t, desc.name) == (CephOsdName, 'target'): url += '/' else: params.append(desc) return app.ceph_baseurl + url, params # # end setup (import-time) functions, begin request-time functions # def concise_sig_for_uri(sig, flavor): ''' Return a generic description of how one would send a REST request for sig ''' prefix = [] args = [] ret = '' if flavor == 'tell': ret = 'tell//' for d in sig: if d.t == CephPrefix: prefix.append(d.instance.prefix) else: args.append(d.name + '=' + str(d)) ret += '/'.join(prefix) if args: ret += '?' + '&'.join(args) return ret def show_human_help(prefix): ''' Dump table showing commands matching prefix ''' # XXX There ought to be a better discovery mechanism than an HTML table s = '' permmap = {'r':'GET', 'rw':'PUT', 'rx':'GET', 'rwx':'PUT'} line = '' for cmdsig in sorted(app.ceph_sigdict.itervalues(), cmp=descsort): concise = concise_sig(cmdsig['sig']) flavor = cmdsig.get('flavor', 'mon') if flavor == 'tell': concise = 'tell//' + concise if concise.startswith(prefix): line = ['\n') s += ''.join(line) s += '
Possible commands:MethodDescription
'] wrapped_sig = textwrap.wrap( concise_sig_for_uri(cmdsig['sig'], flavor), 40 ) for sigline in wrapped_sig: line.append(flask.escape(sigline) + '\n') line.append('') line.append(permmap[cmdsig['perm']]) line.append('') line.append(flask.escape(cmdsig['help'])) line.append('
' if line: return s else: return '' @app.before_request def log_request(): ''' For every request, log it. XXX Probably overkill for production ''' app.logger.info(flask.request.url + " from " + flask.request.remote_addr + " " + flask.request.user_agent.string) app.logger.debug("Accept: %s", flask.request.accept_mimetypes.values()) @app.route('/') def root_redir(): return flask.redirect(app.ceph_baseurl) def make_response(fmt, output, statusmsg, errorcode): ''' If formatted output, cobble up a response object that contains the output and status wrapped in enclosing objects; if nonformatted, just use output+status. Return HTTP status errorcode in any event. ''' response = output if fmt: if 'json' in fmt: try: native_output = json.loads(output or '[]') response = json.dumps({"output":native_output, "status":statusmsg}) except: return flask.make_response("Error decoding JSON from " + output, 500) elif 'xml' in fmt: # XXX # one is tempted to do this with xml.etree, but figuring out how # to 'un-XML' the XML-dumped output so it can be reassembled into # a piece of the tree here is beyond me right now. #ET = xml.etree.ElementTree #resp_elem = ET.Element('response') #o = ET.SubElement(resp_elem, 'output') #o.text = output #s = ET.SubElement(resp_elem, 'status') #s.text = statusmsg #response = ET.tostring(resp_elem) response = ''' {0} {1} '''.format(response, xml.sax.saxutils.escape(statusmsg)) else: if not 200 <= errorcode < 300: response = response + '\n' + statusmsg + '\n' return flask.make_response(response, errorcode) def handler(catchall_path=None, fmt=None, target=None): ''' Main endpoint handler; generic for every endpoint, including catchall. Handles the catchall, anything with <.fmt>, anything with embedded . Partial match or ?help cause the HTML-table "show_human_help" output. ''' ep = catchall_path or flask.request.endpoint ep = ep.replace('.', '') if ep[0] != '/': ep = '/' + ep # demand that endpoint begin with app.ceph_baseurl if not ep.startswith(app.ceph_baseurl): return make_response(fmt, '', 'Page not found', 404) rel_ep = ep[len(app.ceph_baseurl)+1:] # Extensions override Accept: headers override defaults if not fmt: if 'application/json' in flask.request.accept_mimetypes.values(): fmt = 'json' elif 'application/xml' in flask.request.accept_mimetypes.values(): fmt = 'xml' prefix = '' pgid = None cmdtarget = 'mon', '' if target: # got tell/; validate osdid or pgid name = CephOsdName() pgidobj = CephPgid() try: name.valid(target) except ArgumentError: # try pgid try: pgidobj.valid(target) except ArgumentError: return flask.make_response("invalid osdid or pgid", 400) else: # it's a pgid pgid = pgidobj.val cmdtarget = 'pg', pgid else: # it's an osd cmdtarget = name.nametype, name.nameid # prefix does not include tell// prefix = ' '.join(rel_ep.split('/')[2:]).strip() else: # non-target command: prefix is entire path prefix = ' '.join(rel_ep.split('/')).strip() # show "match as much as you gave me" help for unknown endpoints if not ep in app.ceph_urls: helptext = show_human_help(prefix) if helptext: resp = flask.make_response(helptext, 400) resp.headers['Content-Type'] = 'text/html' return resp else: return make_response(fmt, '', 'Invalid endpoint ' + ep, 400) found = None exc = '' for urldict in app.ceph_urls[ep]: if flask.request.method not in urldict['methods']: continue paramsig = urldict['paramsig'] # allow '?help' for any specifically-known endpoint if 'help' in flask.request.args: response = flask.make_response('{0}: {1}'.\ format(prefix + concise_sig(paramsig), urldict['help'])) response.headers['Content-Type'] = 'text/plain' return response # if there are parameters for this endpoint, process them if paramsig: args = {} for k, l in flask.request.args.iterlists(): if len(l) == 1: args[k] = l[0] else: args[k] = l # is this a valid set of params? try: argdict = validate(args, paramsig) found = urldict break except Exception as e: exc += str(e) continue else: if flask.request.args: continue found = urldict argdict = {} break if not found: return make_response(fmt, '', exc + '\n', 400) argdict['format'] = fmt or 'plain' argdict['module'] = found['module'] argdict['perm'] = found['perm'] if pgid: argdict['pgid'] = pgid if not cmdtarget: cmdtarget = ('mon', '') app.logger.debug('sending command prefix %s argdict %s', prefix, argdict) ret, outbuf, outs = json_command(app.ceph_cluster, prefix=prefix, target=cmdtarget, inbuf=flask.request.data, argdict=argdict) if ret: return make_response(fmt, '', 'Error: {0} ({1})'.format(outs, ret), 400) response = make_response(fmt, outbuf, outs or 'OK', 200) if fmt: contenttype = 'application/' + fmt.replace('-pretty','') else: contenttype = 'text/plain' response.headers['Content-Type'] = contenttype return response # # Main entry point from wrapper/WSGI server: call with cmdline args, # get back the WSGI app entry point # def generate_app(conf, cluster, clientname, clientid, args): addr, port = api_setup(app, conf, cluster, clientname, clientid, args) app.ceph_addr = addr app.ceph_port = port return app ceph-0.80.11/src/pybind/cephfs.py0000664000175100017510000002757412623076744020612 0ustar jenkins-buildjenkins-build""" This module is a thin wrapper around libcephfs. """ from ctypes import CDLL, c_char_p, c_size_t, c_void_p, c_int, c_long, c_uint, c_ulong, \ create_string_buffer, byref, Structure from ctypes.util import find_library import errno class Error(Exception): pass class PermissionError(Error): pass class ObjectNotFound(Error): pass class NoData(Error): pass class ObjectExists(Error): pass class IOError(Error): pass class NoSpace(Error): pass class IncompleteWriteError(Error): pass class LibCephFSStateError(Error): pass def make_ex(ret, msg): """ Translate a libcephfs return code into an exception. :param ret: the return code :type ret: int :param msg: the error message to use :type msg: str :returns: a subclass of :class:`Error` """ errors = { errno.EPERM : PermissionError, errno.ENOENT : ObjectNotFound, errno.EIO : IOError, errno.ENOSPC : NoSpace, errno.EEXIST : ObjectExists, errno.ENODATA : NoData } ret = abs(ret) if ret in errors: return errors[ret](msg) else: return Error(msg + (": error code %d" % ret)) class cephfs_statvfs(Structure): _fields_ = [("f_bsize", c_uint), ("f_frsize", c_uint), ("f_blocks", c_uint), ("f_bfree", c_uint), ("f_bavail", c_uint), ("f_files", c_uint), ("f_ffree", c_uint), ("f_favail", c_uint), ("f_fsid", c_uint), ("f_flag", c_uint), ("f_namemax", c_uint)] # struct timespec { # long int tv_sec; # long int tv_nsec; # } class cephfs_timespec(Structure): _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)] # struct stat { # unsigned long st_dev; # unsigned long st_ino; # unsigned long st_nlink; # unsigned int st_mode; # unsigned int st_uid; # unsigned int st_gid; # int __pad0; # unsigned long st_rdev; # long int st_size; # long int st_blksize; # long int st_blocks; # struct timespec st_atim; # struct timespec st_mtim; # struct timespec st_ctim; # long int __unused[3]; # }; class cephfs_stat(Structure): _fields_ = [('st_dev', c_ulong), # ID of device containing file ('st_ino', c_ulong), # inode number ('st_nlink', c_ulong), # number of hard links ('st_mode', c_uint), # protection ('st_uid', c_uint), # user ID of owner ('st_gid', c_uint), # group ID of owner ('__pad0', c_int), ('st_rdev', c_ulong), # device ID (if special file) ('st_size', c_long), # total size, in bytes ('st_blksize', c_long), # blocksize for file system I/O ('st_blocks', c_long), # number of 512B blocks allocated ('st_atime', cephfs_timespec), # time of last access ('st_mtime', cephfs_timespec), # time of last modification ('st_ctime', cephfs_timespec), # time of last status change ('__unused1', c_long), ('__unused2', c_long), ('__unused3', c_long) ] def load_libcephfs(): """ Load the libcephfs shared library. """ libcephfs_path = find_library('cephfs') if libcephfs_path: return CDLL(libcephfs_path) # try harder, find_library() doesn't search LD_LIBRARY_PATH # in addition, it doesn't seem work on centos 6.4 (see e46d2ca067b5) try: return CDLL('libcephfs.so.1') except OSError as e: raise EnvironmentError("Unable to load libcephfs: %s" % e) class LibCephFS(object): """libcephfs python wrapper""" def require_state(self, *args): for a in args: if self.state == a: return raise LibCephFSStateError("You cannot perform that operation on a " "CephFS object in state %s." % (self.state)) def __init__(self, conf=None, conffile=None): self.libcephfs = load_libcephfs() self.cluster = c_void_p() if conffile is not None and not isinstance(conffile, str): raise TypeError('conffile must be a string or None') ret = self.libcephfs.ceph_create(byref(self.cluster), c_char_p(0)) if ret != 0: raise Error("libcephfs_initialize failed with error code: %d" %ret) self.state = "configuring" if conffile is not None: # read the default conf file when '' is given if conffile == '': conffile = None self.conf_read_file(conffile) if conf is not None: for key, value in conf.iteritems(): self.conf_set(key, value) def conf_read_file(self, conffile=None): if conffile is not None and not isinstance(conffile, str): raise TypeError('conffile param must be a string') ret = self.libcephfs.ceph_conf_read_file(self.cluster, c_char_p(conffile)) if ret != 0: raise make_ex(ret, "error calling conf_read_file") def shutdown(self): """ Unmount and destroy the ceph mount handle. """ if self.state != "shutdown": self.libcephfs.ceph_shutdown(self.cluster) self.state = "shutdown" def __enter__(self): self.mount() return self def __exit__(self, type_, value, traceback): self.shutdown() return False def __del__(self): self.shutdown() def version(self): """ Get the version number of the ``libcephfs`` C library. :returns: a tuple of ``(major, minor, extra)`` components of the libcephfs version """ major = c_int(0) minor = c_int(0) extra = c_int(0) self.libcephfs.ceph_version(byref(major), byref(minor), byref(extra)) return (major.value, minor.value, extra.value) def conf_get(self, option): self.require_state("configuring", "connected") if not isinstance(option, str): raise TypeError('option must be a string') length = 20 while True: ret_buf = create_string_buffer(length) ret = self.libcephfs.ceph_conf_get(self.cluster, option, ret_buf, c_size_t(length)) if ret == 0: return ret_buf.value elif ret == -errno.ENAMETOOLONG: length = length * 2 elif ret == -errno.ENOENT: return None else: raise make_ex(ret, "error calling conf_get") def conf_set(self, option, val): self.require_state("configuring", "connected") if not isinstance(option, str): raise TypeError('option must be a string') if not isinstance(val, str): raise TypeError('val must be a string') ret = self.libcephfs.ceph_conf_set(self.cluster, c_char_p(option), c_char_p(val)) if ret != 0: raise make_ex(ret, "error calling conf_set") def mount(self): self.require_state("configuring") ret = self.libcephfs.ceph_mount(self.cluster, "/") if ret != 0: raise make_ex(ret, "error calling ceph_mount") self.state = "mounted" def statfs(self, path): self.require_state("mounted") statbuf = cephfs_statvfs() ret = self.libcephfs.ceph_statfs(self.cluster, c_char_p(path), byref(statbuf)) if ret < 0: raise make_ex(ret, "statfs failed: %s" % path) return {'f_bsize': statbuf.f_bsize, 'f_frsize': statbuf.f_frsize, 'f_blocks': statbuf.f_blocks, 'f_bfree': statbuf.f_bfree, 'f_bavail': statbuf.f_bavail, 'f_files': statbuf.f_files, 'f_ffree': statbuf.f_ffree, 'f_favail': statbuf.f_favail, 'f_fsid': statbuf.f_fsid, 'f_flag': statbuf.f_flag, 'f_namemax': statbuf.f_namemax } def sync_fs(self): self.require_state("mounted") ret = self.libcephfs.ceph_sync_fs(self.cluster) if ret < 0: raise make_ex(ret, "sync_fs failed") def getcwd(self): self.require_state("mounted") return self.libcephfs.ceph_getcwd(self.cluster) def chdir(self, path): self.require_state("mounted") ret = self.libcephfs.ceph_chdir(self.cluster, c_char_p(path)) if ret < 0: raise make_ex(ret, "chdir failed") def mkdir(self, path, mode): self.require_state("mounted") if not isinstance(path, str): raise TypeError('path must be a string') ret = self.libcephfs.ceph_mkdir(self.cluster, c_char_p(path), c_int(mode)) if ret < 0: raise make_ex(ret, "error in mkdir '%s'" % path) def mkdirs(self, path, mode): self.require_state("mounted") if not isinstance(path, str): raise TypeError('path must be a string') if not isinstance(mode, int): raise TypeError('mode must be an int') ret = self.libcephfs.ceph_mkdir(self.cluster, c_char_p(path), c_int(mode)) if ret < 0: raise make_ex(ret, "error in mkdirs '%s'" % path) def open(self, path, flags, mode): self.require_state("mounted") if not isinstance(path, str): raise TypeError('path must be a string') if not isinstance(mode, int): raise TypeError('mode must be an int') if not isinstance(flags, int): raise TypeError('flags must be an int') ret = self.libcephfs.ceph_open(self.cluster, c_char_p(path), c_int(flags), c_int(mode)) if ret < 0: raise make_ex(ret, "error in open '%s'" % path) return ret def close(self, fd): self.require_state("mounted") ret = self.libcephfs.ceph_close(self.cluster, c_int(fd)) if ret < 0: raise make_ex(ret, "error in close") def setxattr(self, path, name, value, flags): if not isinstance(path, str): raise TypeError('path must be a string') if not isinstance(name, str): raise TypeError('name must be a string') if not isinstance(value, str): raise TypeError('value must be a string') self.require_state("mounted") ret = self.libcephfs.ceph_setxattr( self.cluster, c_char_p(path), c_char_p(name), c_void_p(value), c_size_t(len(value)), c_int(flags)) if ret < 0: raise make_ex(ret, "error in setxattr") def stat(self, path): self.require_state("mounted") if not isinstance(path, str): raise TypeError('path must be a string') statbuf = cephfs_stat() ret = self.libcephfs.ceph_stat( self.cluster, c_char_p(path), byref(statbuf)) if ret < 0: raise make_ex(ret, "error in stat: %s" % path) return {'st_dev': statbuf.st_dev, 'st_ino': statbuf.st_ino, 'st_mode': statbuf.st_mode, 'st_nlink': statbuf.st_nlink, 'st_uid': statbuf.st_uid, 'st_gid': statbuf.st_gid, 'st_rdev': statbuf.st_rdev, 'st_size': statbuf.st_size, 'st_blksize': statbuf.st_blksize, 'st_blocks': statbuf.st_blocks, 'st_atime': statbuf.st_atime, 'st_mtime': statbuf.st_mtime, 'st_ctime': statbuf.st_ctime } def unlink(self, path): self.require_state("mounted") ret = self.libcephfs.ceph_unlink( self.cluster, c_char_p(path)) if ret < 0: raise make_ex(ret, "error in unlink: %s" % path) ceph-0.80.11/src/pybind/rbd.py0000664000175100017510000010511212623076744020072 0ustar jenkins-buildjenkins-build""" This module is a thin wrapper around librbd. It currently provides all the synchronous methods of librbd that do not use callbacks. Error codes from librbd are turned into exceptions that subclass :class:`Error`. Almost all methods may raise :class:`Error` (the base class of all rbd exceptions), :class:`PermissionError` and :class:`IOError`, in addition to those documented for the method. A number of methods have string arguments, which must not be unicode to interact correctly with librbd. If unicode is passed to these methods, a :class:`TypeError` will be raised. """ # Copyright 2011 Josh Durgin from ctypes import CDLL, c_char, c_char_p, c_size_t, c_void_p, c_int, \ create_string_buffer, byref, Structure, c_uint64, c_int64, c_uint8, \ CFUNCTYPE from ctypes.util import find_library import ctypes import errno ANONYMOUS_AUID = 0xffffffffffffffff ADMIN_AUID = 0 RBD_FEATURE_LAYERING = 1 RBD_FEATURE_STRIPINGV2 = 2 class Error(Exception): pass class PermissionError(Error): pass class ImageNotFound(Error): pass class ImageExists(Error): pass class IOError(Error): pass class NoSpace(Error): pass class IncompleteWriteError(Error): pass class InvalidArgument(Error): pass class LogicError(Error): pass class ReadOnlyImage(Error): pass class ImageBusy(Error): pass class ImageHasSnapshots(Error): pass class FunctionNotSupported(Error): pass class ArgumentOutOfRange(Error): pass class ConnectionShutdown(Error): pass class Timeout(Error): pass def make_ex(ret, msg): """ Translate a librbd return code into an exception. :param ret: the return code :type ret: int :param msg: the error message to use :type msg: str :returns: a subclass of :class:`Error` """ errors = { errno.EPERM : PermissionError, errno.ENOENT : ImageNotFound, errno.EIO : IOError, errno.ENOSPC : NoSpace, errno.EEXIST : ImageExists, errno.EINVAL : InvalidArgument, errno.EROFS : ReadOnlyImage, errno.EBUSY : ImageBusy, errno.ENOTEMPTY : ImageHasSnapshots, errno.ENOSYS : FunctionNotSupported, errno.EDOM : ArgumentOutOfRange, errno.ESHUTDOWN : ConnectionShutdown, errno.ETIMEDOUT : Timeout, } ret = abs(ret) if ret in errors: return errors[ret](msg) else: return Error(msg + (": error code %d" % ret)) class rbd_image_info_t(Structure): _fields_ = [("size", c_uint64), ("obj_size", c_uint64), ("num_objs", c_uint64), ("order", c_int), ("block_name_prefix", c_char * 24), ("parent_pool", c_int64), ("parent_name", c_char * 96)] class rbd_snap_info_t(Structure): _fields_ = [("id", c_uint64), ("size", c_uint64), ("name", c_char_p)] def load_librbd(): """ Load the librbd shared library. """ librbd_path = find_library('rbd') if librbd_path: return CDLL(librbd_path) # try harder, find_library() doesn't search LD_LIBRARY_PATH # in addition, it doesn't seem work on centos 6.4 (see e46d2ca067b5) try: return CDLL('librbd.so.1') except OSError as e: raise EnvironmentError("Unable to load librbd: %s" % e) class RBD(object): """ This class wraps librbd CRUD functions. """ def __init__(self): self.librbd = load_librbd() def version(self): """ Get the version number of the ``librbd`` C library. :returns: a tuple of ``(major, minor, extra)`` components of the librbd version """ major = c_int(0) minor = c_int(0) extra = c_int(0) self.librbd.rbd_version(byref(major), byref(minor), byref(extra)) return (major.value, minor.value, extra.value) def create(self, ioctx, name, size, order=None, old_format=True, features=0, stripe_unit=0, stripe_count=0): """ Create an rbd image. :param ioctx: the context in which to create the image :type ioctx: :class:`rados.Ioctx` :param name: what the image is called :type name: str :param size: how big the image is in bytes :type size: int :param order: the image is split into (2**order) byte objects :type order: int :param old_format: whether to create an old-style image that is accessible by old clients, but can't use more advanced features like layering. :type old_format: bool :param features: bitmask of features to enable :type features: int :param stripe_unit: stripe unit in bytes (default 0 for object size) :type stripe_unit: int :param stripe_count: objects to stripe over before looping :type stripe_count: int :raises: :class:`ImageExists` :raises: :class:`TypeError` :raises: :class:`InvalidArgument` :raises: :class:`FunctionNotSupported` """ if order is None: order = 0 if not isinstance(name, str): raise TypeError('name must be a string') if old_format: if features != 0 or stripe_unit != 0 or stripe_count != 0: raise InvalidArgument('format 1 images do not support feature' ' masks or non-default striping') ret = self.librbd.rbd_create(ioctx.io, c_char_p(name), c_uint64(size), byref(c_int(order))) else: if not hasattr(self.librbd, 'rbd_create2'): raise FunctionNotSupported('installed version of librbd does' ' not support format 2 images') has_create3 = hasattr(self.librbd, 'rbd_create3') if (stripe_unit != 0 or stripe_count != 0) and not has_create3: raise FunctionNotSupported('installed version of librbd does' ' not support stripe unit or count') if has_create3: ret = self.librbd.rbd_create3(ioctx.io, c_char_p(name), c_uint64(size), c_uint64(features), byref(c_int(order)), c_uint64(stripe_unit), c_uint64(stripe_count)) else: ret = self.librbd.rbd_create2(ioctx.io, c_char_p(name), c_uint64(size), c_uint64(features), byref(c_int(order))) if ret < 0: raise make_ex(ret, 'error creating image') def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name, features=0, order=None): """ Clone a parent rbd snapshot into a COW sparse child. :param p_ioctx: the parent context that represents the parent snap :type ioctx: :class:`rados.Ioctx` :param p_name: the parent image name :type name: str :param p_snapname: the parent image snapshot name :type name: str :param c_ioctx: the child context that represents the new clone :type ioctx: :class:`rados.Ioctx` :param c_name: the clone (child) name :type name: str :param features: bitmask of features to enable; if set, must include layering :type features: int :param order: the image is split into (2**order) byte objects :type order: int :raises: :class:`TypeError` :raises: :class:`InvalidArgument` :raises: :class:`ImageExists` :raises: :class:`FunctionNotSupported` :raises: :class:`ArgumentOutOfRange` """ if order is None: order = 0 if not isinstance(p_snapname, str) or not isinstance(p_name, str): raise TypeError('parent name and snapname must be strings') if not isinstance(c_name, str): raise TypeError('child name must be a string') ret = self.librbd.rbd_clone(p_ioctx.io, c_char_p(p_name), c_char_p(p_snapname), c_ioctx.io, c_char_p(c_name), c_uint64(features), byref(c_int(order))) if ret < 0: raise make_ex(ret, 'error creating clone') def list(self, ioctx): """ List image names. :param ioctx: determines which RADOS pool is read :type ioctx: :class:`rados.Ioctx` :returns: list -- a list of image names """ size = c_size_t(512) while True: c_names = create_string_buffer(size.value) ret = self.librbd.rbd_list(ioctx.io, byref(c_names), byref(size)) if ret >= 0: break elif ret != -errno.ERANGE: raise make_ex(ret, 'error listing images') return filter(lambda name: name != '', c_names.raw.split('\0')) def remove(self, ioctx, name): """ Delete an RBD image. This may take a long time, since it does not return until every object that comprises the image has been deleted. Note that all snapshots must be deleted before the image can be removed. If there are snapshots left, :class:`ImageHasSnapshots` is raised. If the image is still open, or the watch from a crashed client has not expired, :class:`ImageBusy` is raised. :param ioctx: determines which RADOS pool the image is in :type ioctx: :class:`rados.Ioctx` :param name: the name of the image to remove :type name: str :raises: :class:`ImageNotFound`, :class:`ImageBusy`, :class:`ImageHasSnapshots` """ if not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_remove(ioctx.io, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error removing image') def rename(self, ioctx, src, dest): """ Rename an RBD image. :param ioctx: determines which RADOS pool the image is in :type ioctx: :class:`rados.Ioctx` :param src: the current name of the image :type src: str :param dest: the new name of the image :type dest: str :raises: :class:`ImageNotFound`, :class:`ImageExists` """ if not isinstance(src, str) or not isinstance(dest, str): raise TypeError('src and dest must be strings') ret = self.librbd.rbd_rename(ioctx.io, c_char_p(src), c_char_p(dest)) if ret != 0: raise make_ex(ret, 'error renaming image') class Image(object): """ This class represents an RBD image. It is used to perform I/O on the image and interact with snapshots. **Note**: Any method of this class may raise :class:`ImageNotFound` if the image has been deleted. """ def __init__(self, ioctx, name, snapshot=None, read_only=False): """ Open the image at the given snapshot. If a snapshot is specified, the image will be read-only, unless :func:`Image.set_snap` is called later. If read-only mode is used, metadata for the :class:`Image` object (such as which snapshots exist) may become obsolete. See the C api for more details. To clean up from opening the image, :func:`Image.close` should be called. For ease of use, this is done automatically when an :class:`Image` is used as a context manager (see :pep:`343`). :param ioctx: determines which RADOS pool the image is in :type ioctx: :class:`rados.Ioctx` :param name: the name of the image :type name: str :param snapshot: which snapshot to read from :type snaphshot: str :param read_only: whether to open the image in read-only mode :type read_only: bool """ self.closed = True self.librbd = load_librbd() self.image = c_void_p() self.name = name if not isinstance(name, str): raise TypeError('name must be a string') if snapshot is not None and not isinstance(snapshot, str): raise TypeError('snapshot must be a string or None') if read_only: if not hasattr(self.librbd, 'rbd_open_read_only'): raise FunctionNotSupported('installed version of librbd does ' 'not support open in read-only mode') ret = self.librbd.rbd_open_read_only(ioctx.io, c_char_p(name), byref(self.image), c_char_p(snapshot)) else: ret = self.librbd.rbd_open(ioctx.io, c_char_p(name), byref(self.image), c_char_p(snapshot)) if ret != 0: raise make_ex(ret, 'error opening image %s at snapshot %s' % (name, snapshot)) self.closed = False def __enter__(self): return self def __exit__(self, type_, value, traceback): """ Closes the image. See :func:`close` """ self.close() return False def close(self): """ Release the resources used by this image object. After this is called, this object should not be used. """ if not self.closed: self.closed = True self.librbd.rbd_close(self.image) def __del__(self): self.close() def __str__(self): s = "rbd.Image(" + dict.__repr__(self.__dict__) + ")" return s def resize(self, size): """ Change the size of the image. :param size: the new size of the image :type size: int """ ret = self.librbd.rbd_resize(self.image, c_uint64(size)) if ret < 0: raise make_ex(ret, 'error resizing image %s' % (self.name,)) def stat(self): """ Get information about the image. Currently parent pool and parent name are always -1 and ''. :returns: dict - contains the following keys: * ``size`` (int) - the size of the image in bytes * ``obj_size`` (int) - the size of each object that comprises the image * ``num_objs`` (int) - the number of objects in the image * ``order`` (int) - log_2(object_size) * ``block_name_prefix`` (str) - the prefix of the RADOS objects used to store the image * ``parent_pool`` (int) - deprecated * ``parent_name`` (str) - deprecated See also :meth:`format` and :meth:`features`. """ info = rbd_image_info_t() ret = self.librbd.rbd_stat(self.image, byref(info), ctypes.sizeof(info)) if ret != 0: raise make_ex(ret, 'error getting info for image %s' % (self.name,)) return { 'size' : info.size, 'obj_size' : info.obj_size, 'num_objs' : info.num_objs, 'order' : info.order, 'block_name_prefix' : info.block_name_prefix, 'parent_pool' : info.parent_pool, 'parent_name' : info.parent_name } def parent_info(self): ret = -errno.ERANGE size = 8 while ret == -errno.ERANGE and size <= 4096: pool = create_string_buffer(size) name = create_string_buffer(size) snapname = create_string_buffer(size) ret = self.librbd.rbd_get_parent_info(self.image, pool, len(pool), name, len(name), snapname, len(snapname)) if ret == -errno.ERANGE: size *= 2 if (ret != 0): raise make_ex(ret, 'error getting parent info for image %s' % (self.name,)) return (pool.value, name.value, snapname.value) def old_format(self): old = c_uint8() ret = self.librbd.rbd_get_old_format(self.image, byref(old)) if (ret != 0): raise make_ex(ret, 'error getting old_format for image' % (self.name)) return old.value != 0 def size(self): """ Get the size of the image. If open to a snapshot, returns the size of that snapshot. :returns: the size of the image in bytes """ image_size = c_uint64() ret = self.librbd.rbd_get_size(self.image, byref(image_size)) if (ret != 0): raise make_ex(ret, 'error getting size for image' % (self.name)) return image_size.value def features(self): features = c_uint64() ret = self.librbd.rbd_get_features(self.image, byref(features)) if (ret != 0): raise make_ex(ret, 'error getting features for image' % (self.name)) return features.value def overlap(self): overlap = c_uint64() ret = self.librbd.rbd_get_overlap(self.image, byref(overlap)) if (ret != 0): raise make_ex(ret, 'error getting overlap for image' % (self.name)) return overlap.value def copy(self, dest_ioctx, dest_name): """ Copy the image to another location. :param dest_ioctx: determines which pool to copy into :type dest_ioctx: :class:`rados.Ioctx` :param dest_name: the name of the copy :type dest_name: str :raises: :class:`ImageExists` """ if not isinstance(dest_name, str): raise TypeError('dest_name must be a string') ret = self.librbd.rbd_copy(self.image, dest_ioctx.io, c_char_p(dest_name)) if ret < 0: raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name)) def list_snaps(self): """ Iterate over the snapshots of an image. :returns: :class:`SnapIterator` """ return SnapIterator(self) def create_snap(self, name): """ Create a snapshot of the image. :param name: the name of the snapshot :type name: str :raises: :class:`ImageExists` """ if not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_snap_create(self.image, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name)) def remove_snap(self, name): """ Delete a snapshot of the image. :param name: the name of the snapshot :type name: str :raises: :class:`IOError`, :class:`ImageBusy` """ if not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_snap_remove(self.image, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name)) def rollback_to_snap(self, name): """ Revert the image to its contents at a snapshot. This is a potentially expensive operation, since it rolls back each object individually. :param name: the snapshot to rollback to :type name: str :raises: :class:`IOError` """ if not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_snap_rollback(self.image, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name)) def protect_snap(self, name): """ Mark a snapshot as protected. This means it can't be deleted until it is unprotected. :param name: the snapshot to protect :type name: str :raises: :class:`IOError`, :class:`ImageNotFound` """ if not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_snap_protect(self.image, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name)) def unprotect_snap(self, name): """ Mark a snapshot unprotected. This allows it to be deleted if it was protected. :param name: the snapshot to unprotect :type name: str :raises: :class:`IOError`, :class:`ImageNotFound` """ if not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_snap_unprotect(self.image, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name)) def is_protected_snap(self, name): """ Find out whether a snapshot is protected from deletion. :param name: the snapshot to check :type name: str :returns: bool - whether the snapshot is protected :raises: :class:`IOError`, :class:`ImageNotFound` """ if not isinstance(name, str): raise TypeError('name must be a string') is_protected = c_int() ret = self.librbd.rbd_snap_is_protected(self.image, c_char_p(name), byref(is_protected)) if ret != 0: raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name)) return is_protected.value == 1 def set_snap(self, name): """ Set the snapshot to read from. Writes will raise ReadOnlyImage while a snapshot is set. Pass None to unset the snapshot (reads come from the current image) , and allow writing again. :param name: the snapshot to read from, or None to unset the snapshot :type name: str or None """ if name is not None and not isinstance(name, str): raise TypeError('name must be a string') ret = self.librbd.rbd_snap_set(self.image, c_char_p(name)) if ret != 0: raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name)) def read(self, offset, length): """ Read data from the image. Raises :class:`InvalidArgument` if part of the range specified is outside the image. :param offset: the offset to start reading at :type offset: int :param length: how many bytes to read :type length: int :returns: str - the data read :raises: :class:`InvalidArgument`, :class:`IOError` """ ret_buf = create_string_buffer(length) ret = self.librbd.rbd_read(self.image, c_uint64(offset), c_size_t(length), byref(ret_buf)) if ret < 0: raise make_ex(ret, 'error reading %s %ld~%ld' % (self.image, offset, length)) return ctypes.string_at(ret_buf, ret) def diff_iterate(self, offset, length, from_snapshot, iterate_cb): """ Iterate over the changed extents of an image. This will call iterate_cb with three arguments: (offset, length, exists) where the changed extent starts at offset bytes, continues for length bytes, and is full of data (if exists is True) or zeroes (if exists is False). If from_snapshot is None, it is interpreted as the beginning of time and this generates all allocated extents. The end version is whatever is currently selected (via set_snap) for the image. Raises :class:`InvalidArgument` if from_snapshot is after the currently set snapshot. Raises :class:`ImageNotFound` if from_snapshot is not the name of a snapshot of the image. :param offset: start offset in bytes :type offset: int :param length: size of region to report on, in bytes :type length: int :param from_snapshot: starting snapshot name, or None :type from_snapshot: str or None :param iterate_cb: function to call for each extent :type iterate_cb: function acception arguments for offset, length, and exists :raises: :class:`InvalidArgument`, :class:`IOError`, :class:`ImageNotFound` """ if from_snapshot is not None and not isinstance(from_snapshot, str): raise TypeError('client must be a string') RBD_DIFF_CB = CFUNCTYPE(c_int, c_uint64, c_size_t, c_int, c_void_p) cb_holder = DiffIterateCB(iterate_cb) cb = RBD_DIFF_CB(cb_holder.callback) ret = self.librbd.rbd_diff_iterate(self.image, c_char_p(from_snapshot), c_uint64(offset), c_uint64(length), cb, c_void_p(None)) if ret < 0: msg = 'error generating diff from snapshot %s' % from_snapshot raise make_ex(ret, msg) def write(self, data, offset): """ Write data to the image. Raises :class:`InvalidArgument` if part of the write would fall outside the image. :param data: the data to be written :type data: str :param offset: where to start writing data :type offset: int :returns: int - the number of bytes written :raises: :class:`IncompleteWriteError`, :class:`LogicError`, :class:`InvalidArgument`, :class:`IOError` """ if not isinstance(data, str): raise TypeError('data must be a string') length = len(data) ret = self.librbd.rbd_write(self.image, c_uint64(offset), c_size_t(length), c_char_p(data)) if ret == length: return ret elif ret < 0: raise make_ex(ret, "error writing to %s" % (self.name,)) elif ret < length: raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length)) else: raise LogicError("logic error: rbd_write(%s) \ returned %d, but %d was the maximum number of bytes it could have \ written." % (self.name, ret, length)) def discard(self, offset, length): """ Trim the range from the image. It will be logically filled with zeroes. """ ret = self.librbd.rbd_discard(self.image, c_uint64(offset), c_uint64(length)) if ret < 0: msg = 'error discarding region %d~%d' % (offset, length) raise make_ex(ret, msg) def flush(self): """ Block until all writes are fully flushed if caching is enabled. """ ret = self.librbd.rbd_flush(self.image) if ret < 0: raise make_ex(ret, 'error flushing image') def invalidate_cache(self): """ Drop any cached data for the image. """ ret = self.librbd.rbd_invalidate_cache(self.image) if ret < 0: raise make_ex(ret, 'error invalidating cache') def stripe_unit(self): """ Returns the stripe unit used for the image. """ stripe_unit = c_uint64() ret = self.librbd.rbd_get_stripe_unit(self.image, byref(stripe_unit)) if ret != 0: raise make_ex(ret, 'error getting stripe unit for image' % (self.name)) return stripe_unit.value def stripe_count(self): """ Returns the stripe count used for the image. """ stripe_count = c_uint64() ret = self.librbd.rbd_get_stripe_count(self.image, byref(stripe_count)) if ret != 0: raise make_ex(ret, 'error getting stripe count for image' % (self.name)) return stripe_count.value def flatten(self): """ Flatten clone image (copy all blocks from parent to child) """ ret = self.librbd.rbd_flatten(self.image) if (ret < 0): raise make_ex(ret, "error flattening %s" % self.name) def list_children(self): """ List children of the currently set snapshot (set via set_snap()). :returns: list - a list of (pool name, image name) tuples """ pools_size = c_size_t(512) images_size = c_size_t(512) while True: c_pools = create_string_buffer(pools_size.value) c_images = create_string_buffer(images_size.value) ret = self.librbd.rbd_list_children(self.image, byref(c_pools), byref(pools_size), byref(c_images), byref(images_size)) if ret >= 0: break elif ret != -errno.ERANGE: raise make_ex(ret, 'error listing images') if ret == 0: return [] pools = c_pools.raw[:pools_size.value - 1].split('\0') images = c_images.raw[:images_size.value - 1].split('\0') return zip(pools, images) def list_lockers(self): """ List clients that have locked the image and information about the lock. :returns: dict - contains the following keys: * ``tag`` - the tag associated with the lock (every additional locker must use the same tag) * ``exclusive`` - boolean indicating whether the lock is exclusive or shared * ``lockers`` - a list of (client, cookie, address) tuples """ clients_size = c_size_t(512) cookies_size = c_size_t(512) addrs_size = c_size_t(512) tag_size = c_size_t(512) exclusive = c_int(0) while True: c_clients = create_string_buffer(clients_size.value) c_cookies = create_string_buffer(cookies_size.value) c_addrs = create_string_buffer(addrs_size.value) c_tag = create_string_buffer(tag_size.value) ret = self.librbd.rbd_list_lockers(self.image, byref(exclusive), byref(c_tag), byref(tag_size), byref(c_clients), byref(clients_size), byref(c_cookies), byref(cookies_size), byref(c_addrs), byref(addrs_size)) if ret >= 0: break elif ret != -errno.ERANGE: raise make_ex(ret, 'error listing images') if ret == 0: return [] clients = c_clients.raw[:clients_size.value - 1].split('\0') cookies = c_cookies.raw[:cookies_size.value - 1].split('\0') addrs = c_addrs.raw[:addrs_size.value - 1].split('\0') return { 'tag' : c_tag.value, 'exclusive' : exclusive.value == 1, 'lockers' : zip(clients, cookies, addrs), } def lock_exclusive(self, cookie): """ Take an exclusive lock on the image. :raises: :class:`ImageBusy` if a different client or cookie locked it :class:`ImageExists` if the same client and cookie locked it """ if not isinstance(cookie, str): raise TypeError('cookie must be a string') ret = self.librbd.rbd_lock_exclusive(self.image, c_char_p(cookie)) if ret < 0: raise make_ex(ret, 'error acquiring exclusive lock on image') def lock_shared(self, cookie, tag): """ Take a shared lock on the image. The tag must match that of the existing lockers, if any. :raises: :class:`ImageBusy` if a different client or cookie locked it :class:`ImageExists` if the same client and cookie locked it """ if not isinstance(cookie, str): raise TypeError('cookie must be a string') if not isinstance(tag, str): raise TypeError('tag must be a string') ret = self.librbd.rbd_lock_shared(self.image, c_char_p(cookie), c_char_p(tag)) if ret < 0: raise make_ex(ret, 'error acquiring shared lock on image') def unlock(self, cookie): """ Release a lock on the image that was locked by this rados client. """ if not isinstance(cookie, str): raise TypeError('cookie must be a string') ret = self.librbd.rbd_unlock(self.image, c_char_p(cookie)) if ret < 0: raise make_ex(ret, 'error unlocking image') def break_lock(self, client, cookie): """ Release a lock held by another rados client. """ if not isinstance(client, str): raise TypeError('client must be a string') if not isinstance(cookie, str): raise TypeError('cookie must be a string') ret = self.librbd.rbd_break_lock(self.image, c_char_p(client), c_char_p(cookie)) if ret < 0: raise make_ex(ret, 'error unlocking image') class DiffIterateCB(object): def __init__(self, cb): self.cb = cb def callback(self, offset, length, exists, unused): self.cb(offset, length, exists == 1) return 0 class SnapIterator(object): """ Iterator over snapshot info for an image. Yields a dictionary containing information about a snapshot. Keys are: * ``id`` (int) - numeric identifier of the snapshot * ``size`` (int) - size of the image at the time of snapshot (in bytes) * ``name`` (str) - name of the snapshot """ def __init__(self, image): self.librbd = image.librbd num_snaps = c_int(10) while True: self.snaps = (rbd_snap_info_t * num_snaps.value)() ret = self.librbd.rbd_snap_list(image.image, byref(self.snaps), byref(num_snaps)) if ret >= 0: self.num_snaps = ret break elif ret != -errno.ERANGE: raise make_ex(ret, 'error listing snapshots for image %s' % (image.name,)) def __iter__(self): for i in xrange(self.num_snaps): yield { 'id' : self.snaps[i].id, 'size' : self.snaps[i].size, 'name' : self.snaps[i].name, } def __del__(self): self.librbd.rbd_snap_list_end(self.snaps) ceph-0.80.11/src/pybind/ceph_argparse.py0000664000175100017510000010726112623076744022135 0ustar jenkins-buildjenkins-build""" Types and routines used by the ceph CLI as well as the RESTful interface. These have to do with querying the daemons for command-description information, validating user command input against those descriptions, and submitting the command to the appropriate daemon. Copyright (C) 2013 Inktank Storage, Inc. LGPL2. See file COPYING. """ import copy import json import os import pprint import re import socket import stat import sys import types import uuid class ArgumentError(Exception): """ Something wrong with arguments """ pass class ArgumentNumber(ArgumentError): """ Wrong number of a repeated argument """ pass class ArgumentFormat(ArgumentError): """ Argument value has wrong format """ pass class ArgumentValid(ArgumentError): """ Argument value is otherwise invalid (doesn't match choices, for instance) """ pass class ArgumentTooFew(ArgumentError): """ Fewer arguments than descriptors in signature; may mean to continue the search, so gets a special exception type """ class ArgumentPrefix(ArgumentError): """ Special for mismatched prefix; less severe, don't report by default """ pass class JsonFormat(Exception): """ some syntactic or semantic issue with the JSON """ pass class CephArgtype(object): """ Base class for all Ceph argument types Instantiating an object sets any validation parameters (allowable strings, numeric ranges, etc.). The 'valid' method validates a string against that initialized instance, throwing ArgumentError if there's a problem. """ def __init__(self, **kwargs): """ set any per-instance validation parameters here from kwargs (fixed string sets, integer ranges, etc) """ pass def valid(self, s, partial=False): """ Run validation against given string s (generally one word); partial means to accept partial string matches (begins-with). If cool, set self.val to the value that should be returned (a copy of the input string, or a numeric or boolean interpretation thereof, for example) if not, throw ArgumentError(msg-as-to-why) """ self.val = s def __repr__(self): """ return string representation of description of type. Note, this is not a representation of the actual value. Subclasses probably also override __str__() to give a more user-friendly 'name/type' description for use in command format help messages. """ a = '' if hasattr(self, 'typeargs'): a = self.typeargs return '{0}(\'{1}\')'.format(self.__class__.__name__, a) def __str__(self): """ where __repr__ (ideally) returns a string that could be used to reproduce the object, __str__ returns one you'd like to see in print messages. Use __str__ to format the argtype descriptor as it would be useful in a command usage message. """ return '<{0}>'.format(self.__class__.__name__) class CephInt(CephArgtype): """ range-limited integers, [+|-][0-9]+ or 0x[0-9a-f]+ range: list of 1 or 2 ints, [min] or [min,max] """ def __init__(self, range=''): if range == '': self.range = list() else: self.range = list(range.split('|')) self.range = map(long, self.range) def valid(self, s, partial=False): try: val = long(s) except ValueError: raise ArgumentValid("{0} doesn't represent an int".format(s)) if len(self.range) == 2: if val < self.range[0] or val > self.range[1]: raise ArgumentValid("{0} not in range {1}".format(val, self.range)) elif len(self.range) == 1: if val < self.range[0]: raise ArgumentValid("{0} not in range {1}".format(val, self.range)) self.val = val def __str__(self): r = '' if len(self.range) == 1: r = '[{0}-]'.format(self.range[0]) if len(self.range) == 2: r = '[{0}-{1}]'.format(self.range[0], self.range[1]) return ''.format(r) class CephFloat(CephArgtype): """ range-limited float type range: list of 1 or 2 floats, [min] or [min, max] """ def __init__(self, range=''): if range == '': self.range = list() else: self.range = list(range.split('|')) self.range = map(float, self.range) def valid(self, s, partial=False): try: val = float(s) except ValueError: raise ArgumentValid("{0} doesn't represent a float".format(s)) if len(self.range) == 2: if val < self.range[0] or val > self.range[1]: raise ArgumentValid("{0} not in range {1}".format(val, self.range)) elif len(self.range) == 1: if val < self.range[0]: raise ArgumentValid("{0} not in range {1}".format(val, self.range)) self.val = val def __str__(self): r = '' if len(self.range) == 1: r = '[{0}-]'.format(self.range[0]) if len(self.range) == 2: r = '[{0}-{1}]'.format(self.range[0], self.range[1]) return ''.format(r) class CephString(CephArgtype): """ String; pretty generic. goodchars is a RE char class of valid chars """ def __init__(self, goodchars=''): from string import printable try: re.compile(goodchars) except: raise ValueError('CephString(): "{0}" is not a valid RE'.\ format(goodchars)) self.goodchars = goodchars self.goodset = frozenset( [c for c in printable if re.match(goodchars, c)] ) def valid(self, s, partial=False): sset = set(s) if self.goodset and not sset <= self.goodset: raise ArgumentFormat("invalid chars {0} in {1}".\ format(''.join(sset - self.goodset), s)) self.val = s def __str__(self): b = '' if self.goodchars: b += '(goodchars {0})'.format(self.goodchars) return ''.format(b) class CephSocketpath(CephArgtype): """ Admin socket path; check that it's readable and S_ISSOCK """ def valid(self, s, partial=False): mode = os.stat(s).st_mode if not stat.S_ISSOCK(mode): raise ArgumentValid('socket path {0} is not a socket'.format(s)) self.val = s def __str__(self): return '' class CephIPAddr(CephArgtype): """ IP address (v4 or v6) with optional port """ def valid(self, s, partial=False): # parse off port, use socket to validate addr type = 6 if s.startswith('['): type = 6 elif s.find('.') != -1: type = 4 if type == 4: port = s.find(':') if (port != -1): a = s[:port] p = s[port+1:] if int(p) > 65535: raise ArgumentValid('{0}: invalid IPv4 port'.format(p)) else: a = s p = None try: socket.inet_pton(socket.AF_INET, a) except: raise ArgumentValid('{0}: invalid IPv4 address'.format(a)) else: # v6 if s.startswith('['): end = s.find(']') if end == -1: raise ArgumentFormat('{0} missing terminating ]'.format(s)) if s[end+1] == ':': try: p = int(s[end+2]) except: raise ArgumentValid('{0}: bad port number'.format(s)) a = s[1:end] else: a = s p = None try: socket.inet_pton(socket.AF_INET6, a) except: raise ArgumentValid('{0} not valid IPv6 address'.format(s)) if p is not None and long(p) > 65535: raise ArgumentValid("{0} not a valid port number".format(p)) self.val = s self.addr = a self.port = p def __str__(self): return '' class CephEntityAddr(CephIPAddr): """ EntityAddress, that is, IP address[/nonce] """ def valid(self, s, partial=False): nonce = None if '/' in s: ip, nonce = s.split('/') else: ip = s super(self.__class__, self).valid(ip) if nonce: nonce_long = None try: nonce_long = long(nonce) except ValueError: pass if nonce_long is None or nonce_long < 0: raise ArgumentValid( '{0}: invalid entity, nonce {1} not integer > 0'.\ format(s, nonce) ) self.val = s def __str__(self): return '' class CephPoolname(CephArgtype): """ Pool name; very little utility """ def __str__(self): return '' class CephObjectname(CephArgtype): """ Object name. Maybe should be combined with Pool name as they're always present in pairs, and then could be checked for presence """ def __str__(self): return '' class CephPgid(CephArgtype): """ pgid, in form N.xxx (N = pool number, xxx = hex pgnum) """ def valid(self, s, partial=False): if s.find('.') == -1: raise ArgumentFormat('pgid has no .') poolid, pgnum = s.split('.') if poolid < 0: raise ArgumentFormat('pool {0} < 0'.format(poolid)) try: pgnum = int(pgnum, 16) except: raise ArgumentFormat('pgnum {0} not hex integer'.format(pgnum)) self.val = s def __str__(self): return '' class CephName(CephArgtype): """ Name (type.id) where: type is osd|mon|client|mds id is a base10 int, if type == osd, or a string otherwise Also accept '*' """ def __init__(self): self.nametype = None self.nameid = None def valid(self, s, partial=False): if s == '*': self.val = s return if s.find('.') == -1: raise ArgumentFormat('CephName: no . in {0}'.format(s)) else: t, i = s.split('.') if not t in ('osd', 'mon', 'client', 'mds'): raise ArgumentValid('unknown type ' + t) if t == 'osd': if i != '*': try: i = int(i) except: raise ArgumentFormat('osd id ' + i + ' not integer') self.nametype = t self.val = s self.nameid = i def __str__(self): return '' class CephOsdName(CephArgtype): """ Like CephName, but specific to osds: allow alone osd., or , or *, where id is a base10 int """ def __init__(self): self.nametype = None self.nameid = None def valid(self, s, partial=False): if s == '*': self.val = s return if s.find('.') != -1: t, i = s.split('.') if t != 'osd': raise ArgumentValid('unknown type ' + t) else: t = 'osd' i = s try: i = int(i) except: raise ArgumentFormat('osd id ' + i + ' not integer') self.nametype = t self.nameid = i self.val = i def __str__(self): return '' class CephChoices(CephArgtype): """ Set of string literals; init with valid choices """ def __init__(self, strings='', **kwargs): self.strings = strings.split('|') def valid(self, s, partial=False): if not partial: if not s in self.strings: # show as __str__ does: {s1|s2..} raise ArgumentValid("{0} not in {1}".format(s, self)) self.val = s return # partial for t in self.strings: if t.startswith(s): self.val = s return raise ArgumentValid("{0} not in {1}". format(s, self)) def __str__(self): if len(self.strings) == 1: return '{0}'.format(self.strings[0]) else: return '{0}'.format('|'.join(self.strings)) class CephFilepath(CephArgtype): """ Openable file """ def valid(self, s, partial=False): try: f = open(s, 'a+') except Exception as e: raise ArgumentValid('can\'t open {0}: {1}'.format(s, e)) f.close() self.val = s def __str__(self): return '' class CephFragment(CephArgtype): """ 'Fragment' ??? XXX """ def valid(self, s, partial=False): if s.find('/') == -1: raise ArgumentFormat('{0}: no /'.format(s)) val, bits = s.split('/') # XXX is this right? if not val.startswith('0x'): raise ArgumentFormat("{0} not a hex integer".format(val)) try: long(val) except: raise ArgumentFormat('can\'t convert {0} to integer'.format(val)) try: long(bits) except: raise ArgumentFormat('can\'t convert {0} to integer'.format(bits)) self.val = s def __str__(self): return "" class CephUUID(CephArgtype): """ CephUUID: pretty self-explanatory """ def valid(self, s, partial=False): try: uuid.UUID(s) except Exception as e: raise ArgumentFormat('invalid UUID {0}: {1}'.format(s, e)) self.val = s def __str__(self): return '' class CephPrefix(CephArgtype): """ CephPrefix: magic type for "all the first n fixed strings" """ def __init__(self, prefix=''): self.prefix = prefix def valid(self, s, partial=False): if partial: if self.prefix.startswith(s): self.val = s return else: if (s == self.prefix): self.val = s return raise ArgumentPrefix("no match for {0}".format(s)) def __str__(self): return self.prefix class argdesc(object): """ argdesc(typename, name='name', n=numallowed|N, req=False, helptext=helptext, **kwargs (type-specific)) validation rules: typename: type(**kwargs) will be constructed later, type.valid(w) will be called with a word in that position name is used for parse errors and for constructing JSON output n is a numeric literal or 'n|N', meaning "at least one, but maybe more" req=False means the argument need not be present in the list helptext is the associated help for the command anything else are arguments to pass to the type constructor. self.instance is an instance of type t constructed with typeargs. valid() will later be called with input to validate against it, and will store the validated value in self.instance.val for extraction. """ def __init__(self, t, name=None, n=1, req=True, **kwargs): if isinstance(t, types.StringTypes): self.t = CephPrefix self.typeargs = {'prefix':t} self.req = True else: self.t = t self.typeargs = kwargs self.req = bool(req == True or req == 'True') self.name = name self.N = (n in ['n', 'N']) if self.N: self.n = 1 else: self.n = int(n) self.instance = self.t(**self.typeargs) def __repr__(self): r = 'argdesc(' + str(self.t) + ', ' internals = ['N', 'typeargs', 'instance', 't'] for (k, v) in self.__dict__.iteritems(): if k.startswith('__') or k in internals: pass else: # undo modification from __init__ if k == 'n' and self.N: v = 'N' r += '{0}={1}, '.format(k, v) for (k, v) in self.typeargs.iteritems(): r += '{0}={1}, '.format(k, v) return r[:-2] + ')' def __str__(self): if ((self.t == CephChoices and len(self.instance.strings) == 1) or (self.t == CephPrefix)): s = str(self.instance) else: s = '{0}({1})'.format(self.name, str(self.instance)) if self.N: s += ' [' + str(self.instance) + '...]' if not self.req: s = '{' + s + '}' return s def helpstr(self): """ like str(), but omit parameter names (except for CephString, which really needs them) """ if self.t == CephString: chunk = '<{0}>'.format(self.name) else: chunk = str(self.instance) s = chunk if self.N: s += ' [' + chunk + '...]' if not self.req: s = '{' + s + '}' return s def concise_sig(sig): """ Return string representation of sig useful for syntax reference in help """ return ' '.join([d.helpstr() for d in sig]) def descsort(sh1, sh2): """ sort descriptors by prefixes, defined as the concatenation of all simple strings in the descriptor; this works out to just the leading strings. """ return cmp(concise_sig(sh1['sig']), concise_sig(sh2['sig'])) def parse_funcsig(sig): """ parse a single descriptor (array of strings or dicts) into a dict of function descriptor/validators (objects of CephXXX type) """ newsig = [] argnum = 0 for desc in sig: argnum += 1 if isinstance(desc, types.StringTypes): t = CephPrefix desc = {'type':t, 'name':'prefix', 'prefix':desc} else: # not a simple string, must be dict if not 'type' in desc: s = 'JSON descriptor {0} has no type'.format(sig) raise JsonFormat(s) # look up type string in our globals() dict; if it's an # object of type types.TypeType, it must be a # locally-defined class. otherwise, we haven't a clue. if desc['type'] in globals(): t = globals()[desc['type']] if type(t) != types.TypeType: s = 'unknown type {0}'.format(desc['type']) raise JsonFormat(s) else: s = 'unknown type {0}'.format(desc['type']) raise JsonFormat(s) kwargs = dict() for key, val in desc.items(): if key not in ['type', 'name', 'n', 'req']: kwargs[key] = val newsig.append(argdesc(t, name=desc.get('name', None), n=desc.get('n', 1), req=desc.get('req', True), **kwargs)) return newsig def parse_json_funcsigs(s, consumer): """ A function signature is mostly an array of argdesc; it's represented in JSON as { "cmd001": {"sig":[ "type": type, "name": name, "n": num, "req":true|false ], "help":helptext, "module":modulename, "perm":perms, "avail":availability} . . . ] A set of sigs is in an dict mapped by a unique number: { "cmd1": { "sig": ["type.. ], "help":helptext... } "cmd2"{ "sig": [.. ], "help":helptext... } } Parse the string s and return a dict of dicts, keyed by opcode; each dict contains 'sig' with the array of descriptors, and 'help' with the helptext, 'module' with the module name, 'perm' with a string representing required permissions in that module to execute this command (and also whether it is a read or write command from the cluster state perspective), and 'avail' as a hint for whether the command should be advertised by CLI, REST, or both. If avail does not contain 'consumer', don't include the command in the returned dict. """ try: overall = json.loads(s) except Exception as e: print >> sys.stderr, "Couldn't parse JSON {0}: {1}".format(s, e) raise e sigdict = {} for cmdtag, cmd in overall.iteritems(): if not 'sig' in cmd: s = "JSON descriptor {0} has no 'sig'".format(cmdtag) raise JsonFormat(s) # check 'avail' and possibly ignore this command if 'avail' in cmd: if not consumer in cmd['avail']: continue # rewrite the 'sig' item with the argdesc-ized version, and... cmd['sig'] = parse_funcsig(cmd['sig']) # just take everything else as given sigdict[cmdtag] = cmd return sigdict def validate_one(word, desc, partial=False): """ validate_one(word, desc, partial=False) validate word against the constructed instance of the type in desc. May raise exception. If it returns false (and doesn't raise an exception), desc.instance.val will contain the validated value (in the appropriate type). """ desc.instance.valid(word, partial) desc.numseen += 1 if desc.N: desc.n = desc.numseen + 1 def matchnum(args, signature, partial=False): """ matchnum(s, signature, partial=False) Returns number of arguments matched in s against signature. Can be used to determine most-likely command for full or partial matches (partial applies to string matches). """ words = args[:] mysig = copy.deepcopy(signature) matchcnt = 0 for desc in mysig: setattr(desc, 'numseen', 0) while desc.numseen < desc.n: # if there are no more arguments, return if not words: return matchcnt word = words.pop(0) try: validate_one(word, desc, partial) valid = True except ArgumentError: # matchnum doesn't care about type of error valid = False if not valid: if not desc.req: # this wasn't required, so word may match the next desc words.insert(0, word) break else: # it was required, and didn't match, return return matchcnt if desc.req: matchcnt += 1 return matchcnt def get_next_arg(desc, args): ''' Get either the value matching key 'desc.name' or the next arg in the non-dict list. Return None if args are exhausted. Used in validate() below. ''' arg = None if isinstance(args, dict): arg = args.pop(desc.name, None) # allow 'param=param' to be expressed as 'param' if arg == '': arg = desc.name # Hack, or clever? If value is a list, keep the first element, # push rest back onto myargs for later processing. # Could process list directly, but nesting here is already bad if arg and isinstance(arg, list): args[desc.name] = arg[1:] arg = arg[0] elif args: arg = args.pop(0) if arg and isinstance(arg, list): args = arg[1:] + args arg = arg[0] return arg def store_arg(desc, d): ''' Store argument described by, and held in, thanks to valid(), desc into the dictionary d, keyed by desc.name. Three cases: 1) desc.N is set: value in d is a list 2) prefix: multiple args are joined with ' ' into one d{} item 3) single prefix or other arg: store as simple value Used in validate() below. ''' if desc.N: # value should be a list if desc.name in d: d[desc.name] += [desc.instance.val] else: d[desc.name] = [desc.instance.val] elif (desc.t == CephPrefix) and (desc.name in d): # prefixes' values should be a space-joined concatenation d[desc.name] += ' ' + desc.instance.val else: # if first CephPrefix or any other type, just set it d[desc.name] = desc.instance.val def validate(args, signature, partial=False): """ validate(args, signature, partial=False) args is a list of either words or k,v pairs representing a possible command input following format of signature. Runs a validation; no exception means it's OK. Return a dict containing all arguments keyed by their descriptor name, with duplicate args per name accumulated into a list (or space-separated value for CephPrefix). Mismatches of prefix are non-fatal, as this probably just means the search hasn't hit the correct command. Mismatches of non-prefix arguments are treated as fatal, and an exception raised. This matching is modified if partial is set: allow partial matching (with partial dict returned); in this case, there are no exceptions raised. """ myargs = copy.deepcopy(args) mysig = copy.deepcopy(signature) reqsiglen = len([desc for desc in mysig if desc.req]) matchcnt = 0 d = dict() for desc in mysig: setattr(desc, 'numseen', 0) while desc.numseen < desc.n: myarg = get_next_arg(desc, myargs) # no arg, but not required? Continue consuming mysig # in case there are later required args if not myarg and not desc.req: break # out of arguments for a required param? # Either return (if partial validation) or raise if not myarg and desc.req: if desc.N and desc.numseen < 1: # wanted N, didn't even get 1 if partial: return d raise ArgumentNumber( 'saw {0} of {1}, expected at least 1'.\ format(desc.numseen, desc) ) elif not desc.N and desc.numseen < desc.n: # wanted n, got too few if partial: return d # special-case the "0 expected 1" case if desc.numseen == 0 and desc.n == 1: raise ArgumentNumber( 'missing required parameter {0}'.format(desc) ) raise ArgumentNumber( 'saw {0} of {1}, expected {2}'.\ format(desc.numseen, desc, desc.n) ) break # Have an arg; validate it try: validate_one(myarg, desc) valid = True except ArgumentError as e: valid = False if not valid: # argument mismatch if not desc.req: # if not required, just push back; it might match # the next arg print >> sys.stderr, myarg, 'not valid: ', str(e) myargs.insert(0, myarg) break else: # hm, it was required, so time to return/raise if partial: return d raise e # Whew, valid arg acquired. Store in dict matchcnt += 1 store_arg(desc, d) # Done with entire list of argdescs if matchcnt < reqsiglen: raise ArgumentTooFew("not enough arguments given") if myargs and not partial: raise ArgumentError("unused arguments: " + str(myargs)) # Finally, success return d def cmdsiglen(sig): sigdict = sig.values() assert len(sigdict) == 1 return len(sig.values()[0]['sig']) def validate_command(sigdict, args, verbose=False): """ turn args into a valid dictionary ready to be sent off as JSON, validated against sigdict. """ found = [] valid_dict = {} if args: # look for best match, accumulate possibles in bestcmds # (so we can maybe give a more-useful error message) best_match_cnt = 0 bestcmds = [] for cmdtag, cmd in sigdict.iteritems(): sig = cmd['sig'] matched = matchnum(args, sig, partial=True) if (matched > best_match_cnt): if verbose: print >> sys.stderr, \ "better match: {0} > {1}: {2}:{3} ".format(matched, best_match_cnt, cmdtag, concise_sig(sig)) best_match_cnt = matched bestcmds = [{cmdtag:cmd}] elif matched == best_match_cnt: if verbose: print >> sys.stderr, \ "equal match: {0} > {1}: {2}:{3} ".format(matched, best_match_cnt, cmdtag, concise_sig(sig)) bestcmds.append({cmdtag:cmd}) # Sort bestcmds by number of args so we can try shortest first # (relies on a cmdsig being key,val where val is a list of len 1) bestcmds_sorted = sorted(bestcmds, cmp=lambda x,y:cmp(cmdsiglen(x), cmdsiglen(y))) if verbose: print >> sys.stderr, "bestcmds_sorted: " pprint.PrettyPrinter(stream=sys.stderr).pprint(bestcmds_sorted) # for everything in bestcmds, look for a true match for cmdsig in bestcmds_sorted: for cmd in cmdsig.itervalues(): sig = cmd['sig'] try: valid_dict = validate(args, sig) found = cmd break except ArgumentPrefix: # ignore prefix mismatches; we just haven't found # the right command yet pass except ArgumentTooFew: # It looked like this matched the beginning, but it # didn't have enough args supplied. If we're out of # cmdsigs we'll fall out unfound; if we're not, maybe # the next one matches completely. Whine, but pass. if verbose: print >> sys.stderr, 'Not enough args supplied for ', \ concise_sig(sig) except ArgumentError as e: # Solid mismatch on an arg (type, range, etc.) # Stop now, because we have the right command but # some other input is invalid print >> sys.stderr, "Invalid command: ", str(e) print >> sys.stderr, concise_sig(sig), ': ', cmd['help'] return {} if found: break if not found: print >> sys.stderr, 'no valid command found; 10 closest matches:' for cmdsig in bestcmds[:10]: for (cmdtag, cmd) in cmdsig.iteritems(): print >> sys.stderr, concise_sig(cmd['sig']) return None return valid_dict def find_cmd_target(childargs): """ Using a minimal validation, figure out whether the command should be sent to a monitor or an osd. We do this before even asking for the 'real' set of command signatures, so we can ask the right daemon. Returns ('osd', osdid), ('pg', pgid), or ('mon', '') """ sig = parse_funcsig(['tell', {'name':'target', 'type':'CephName'}]) try: valid_dict = validate(childargs, sig, partial=True) except ArgumentError: pass else: if len(valid_dict) == 2: # revalidate to isolate type and id name = CephName() # if this fails, something is horribly wrong, as it just # validated successfully above name.valid(valid_dict['target']) return name.nametype, name.nameid sig = parse_funcsig(['tell', {'name':'pgid', 'type':'CephPgid'}]) try: valid_dict = validate(childargs, sig, partial=True) except ArgumentError: pass else: if len(valid_dict) == 2: # pg doesn't need revalidation; the string is fine return 'pg', valid_dict['pgid'] sig = parse_funcsig(['pg', {'name':'pgid', 'type':'CephPgid'}]) try: valid_dict = validate(childargs, sig, partial=True) except ArgumentError: pass else: if len(valid_dict) == 2: return 'pg', valid_dict['pgid'] return 'mon', '' def send_command(cluster, target=('mon', ''), cmd=None, inbuf='', timeout=0, verbose=False): """ Send a command to a daemon using librados's mon_command, osd_command, or pg_command. Any bulk input data comes in inbuf. Returns (ret, outbuf, outs); ret is the return code, outbuf is the outbl "bulk useful output" buffer, and outs is any status or error message (intended for stderr). If target is osd.N, send command to that osd (except for pgid cmds) """ cmd = cmd or [] try: if target[0] == 'osd': osdid = target[1] if verbose: print >> sys.stderr, 'submit {0} to osd.{1}'.\ format(cmd, osdid) ret, outbuf, outs = \ cluster.osd_command(osdid, cmd, inbuf, timeout) elif target[0] == 'pg': pgid = target[1] # pgid will already be in the command for the pg # form, but for tell , we need to put it in if cmd: cmddict = json.loads(cmd[0]) cmddict['pgid'] = pgid else: cmddict = dict(pgid=pgid) cmd = [json.dumps(cmddict)] if verbose: print >> sys.stderr, 'submit {0} for pgid {1}'.\ format(cmd, pgid) ret, outbuf, outs = \ cluster.pg_command(pgid, cmd, inbuf, timeout) elif target[0] == 'mon': if verbose: print >> sys.stderr, '{0} to {1}'.\ format(cmd, target[0]) if target[1] == '': ret, outbuf, outs = cluster.mon_command(cmd, inbuf, timeout) else: ret, outbuf, outs = cluster.mon_command(cmd, inbuf, timeout, target[1]) else: raise ArgumentValid("Bad target type '{0}'".format(target[0])) except Exception as e: if not isinstance(e, ArgumentError): raise RuntimeError('"{0}": exception {1}'.format(cmd, e)) else: raise return ret, outbuf, outs def json_command(cluster, target=('mon', ''), prefix=None, argdict=None, inbuf='', timeout=0, verbose=False): """ Format up a JSON command and send it with send_command() above. Prefix may be supplied separately or in argdict. Any bulk input data comes in inbuf. If target is osd.N, send command to that osd (except for pgid cmds) """ cmddict = {} if prefix: cmddict.update({'prefix':prefix}) if argdict: cmddict.update(argdict) # grab prefix for error messages prefix = cmddict['prefix'] try: if target[0] == 'osd': osdtarg = CephName() osdtarget = '{0}.{1}'.format(*target) # prefer target from cmddict if present and valid if 'target' in cmddict: osdtarget = cmddict.pop('target') try: osdtarg.valid(osdtarget) target = ('osd', osdtarg.nameid) except: # use the target we were originally given pass ret, outbuf, outs = send_command(cluster, target, [json.dumps(cmddict)], inbuf, timeout, verbose) except Exception as e: if not isinstance(e, ArgumentError): raise RuntimeError('"{0}": exception {1}'.format(cmd, e)) else: raise return ret, outbuf, outs ceph-0.80.11/src/pybind/rados.py0000664000175100017510000017173612623076744020452 0ustar jenkins-buildjenkins-build""" This module is a thin wrapper around librados. Copyright 2011, Hannu Valtonen """ from ctypes import CDLL, c_char_p, c_size_t, c_void_p, c_char, c_int, c_long, \ c_ulong, create_string_buffer, byref, Structure, c_uint64, c_ubyte, \ pointer, CFUNCTYPE from ctypes.util import find_library import ctypes import errno import threading import time from datetime import datetime ANONYMOUS_AUID = 0xffffffffffffffff ADMIN_AUID = 0 class Error(Exception): """ `Error` class, derived from `Exception` """ pass class InterruptedOrTimeoutError(Error): """ `InterruptedOrTimeoutError` class, derived from `Error` """ pass class PermissionError(Error): """ `PermissionError` class, derived from `Error` """ pass class ObjectNotFound(Error): """ `ObjectNotFound` class, derived from `Error` """ pass class NoData(Error): """ `NoData` class, derived from `Error` """ pass class ObjectExists(Error): """ `ObjectExists` class, derived from `Error` """ pass class IOError(Error): """ `IOError` class, derived from `Error` """ pass class NoSpace(Error): """ `NoSpace` class, derived from `Error` """ pass class IncompleteWriteError(Error): """ `IncompleteWriteError` class, derived from `Error` """ pass class RadosStateError(Error): """ `RadosStateError` class, derived from `Error` """ pass class IoctxStateError(Error): """ `IoctxStateError` class, derived from `Error` """ pass class ObjectStateError(Error): """ `ObjectStateError` class, derived from `Error` """ pass class LogicError(Error): """ `` class, derived from `Error` """ pass class TimedOut(Error): """ `TimedOut` class, derived from `Error` """ pass def make_ex(ret, msg): """ Translate a librados return code into an exception. :param ret: the return code :type ret: int :param msg: the error message to use :type msg: str :returns: a subclass of :class:`Error` """ errors = { errno.EPERM : PermissionError, errno.ENOENT : ObjectNotFound, errno.EIO : IOError, errno.ENOSPC : NoSpace, errno.EEXIST : ObjectExists, errno.ENODATA : NoData, errno.EINTR : InterruptedOrTimeoutError, errno.ETIMEDOUT : TimedOut } ret = abs(ret) if ret in errors: return errors[ret](msg) else: return Error(msg + (": errno %s" % errno.errorcode[ret])) class rados_pool_stat_t(Structure): """ Usage information for a pool """ _fields_ = [("num_bytes", c_uint64), ("num_kb", c_uint64), ("num_objects", c_uint64), ("num_object_clones", c_uint64), ("num_object_copies", c_uint64), ("num_objects_missing_on_primary", c_uint64), ("num_objects_unfound", c_uint64), ("num_objects_degraded", c_uint64), ("num_rd", c_uint64), ("num_rd_kb", c_uint64), ("num_wr", c_uint64), ("num_wr_kb", c_uint64)] class rados_cluster_stat_t(Structure): """ Cluster-wide usage information """ _fields_ = [("kb", c_uint64), ("kb_used", c_uint64), ("kb_avail", c_uint64), ("num_objects", c_uint64)] class Version(object): """ Version information """ def __init__(self, major, minor, extra): self.major = major self.minor = minor self.extra = extra def __str__(self): return "%d.%d.%d" % (self.major, self.minor, self.extra) class RadosThread(threading.Thread): def __init__(self, target, args=None): self.args = args self.target = target threading.Thread.__init__(self) def run(self): self.retval = self.target(*self.args) # time in seconds between each call to t.join() for child thread POLL_TIME_INCR = 0.5 def run_in_thread(target, args, timeout=0): import sys interrupt = False countdown = timeout t = RadosThread(target, args) # allow the main thread to exit (presumably, avoid a join() on this # subthread) before this thread terminates. This allows SIGINT # exit of a blocked call. See below. t.daemon = True t.start() try: # poll for thread exit while t.is_alive(): t.join(POLL_TIME_INCR) if timeout: countdown = countdown - POLL_TIME_INCR if countdown <= 0: raise KeyboardInterrupt t.join() # in case t exits before reaching the join() above except KeyboardInterrupt: # ..but allow SIGINT to terminate the waiting. Note: this # relies on the Linux kernel behavior of delivering the signal # to the main thread in preference to any subthread (all that's # strictly guaranteed is that *some* thread that has the signal # unblocked will receive it). But there doesn't seem to be # any interface to create t with SIGINT blocked. interrupt = True if interrupt: t.retval = -errno.EINTR return t.retval class Rados(object): """librados python wrapper""" def require_state(self, *args): """ Checks if the Rados object is in a special state :raises: RadosStateError """ for a in args: if self.state == a: return raise RadosStateError("You cannot perform that operation on a \ Rados object in state %s." % (self.state)) def __init__(self, rados_id=None, name=None, clustername=None, conf_defaults=None, conffile=None, conf=None, flags=0): librados_path = find_library('rados') if not librados_path: #maybe find_library can not find it correctly on all platforms. try: self.librados = CDLL('librados.so.2') except OSError as e: raise EnvironmentError("Unable to load librados: %s" % e) except: raise Error("Unexpected error") else: self.librados = CDLL(librados_path) self.cluster = c_void_p() self.rados_id = rados_id if rados_id is not None and not isinstance(rados_id, str): raise TypeError('rados_id must be a string or None') if conffile is not None and not isinstance(conffile, str): raise TypeError('conffile must be a string or None') if name is not None and not isinstance(name, str): raise TypeError('name must be a string or None') if clustername is not None and not isinstance(clustername, str): raise TypeError('clustername must be a string or None') if rados_id and name: raise Error("Rados(): can't supply both rados_id and name") if rados_id: name = 'client.' + rados_id if name is None: name = 'client.admin' if clustername is None: clustername = 'ceph' ret = run_in_thread(self.librados.rados_create2, (byref(self.cluster), c_char_p(clustername), c_char_p(name), c_uint64(flags))) if ret != 0: raise Error("rados_initialize failed with error code: %d" % ret) self.state = "configuring" # order is important: conf_defaults, then conffile, then conf if conf_defaults: for key, value in conf_defaults.iteritems(): self.conf_set(key, value) if conffile is not None: # read the default conf file when '' is given if conffile == '': conffile = None self.conf_read_file(conffile) if conf: for key, value in conf.iteritems(): self.conf_set(key, value) def shutdown(self): """ Disconnects from the cluster. Call this explicitly when a Rados.connect()ed object is no longer used. """ if (self.__dict__.has_key("state") and self.state != "shutdown"): run_in_thread(self.librados.rados_shutdown, (self.cluster,)) self.state = "shutdown" def __enter__(self): self.connect() return self def __exit__(self, type_, value, traceback): self.shutdown() return False def version(self): """ Get the version number of the ``librados`` C library. :returns: a tuple of ``(major, minor, extra)`` components of the librados version """ major = c_int(0) minor = c_int(0) extra = c_int(0) run_in_thread(self.librados.rados_version, (byref(major), byref(minor), byref(extra))) return Version(major.value, minor.value, extra.value) def conf_read_file(self, path=None): """ Configure the cluster handle using a Ceph config file. :param path: path to the config file :type path: str """ self.require_state("configuring", "connected") if path is not None and not isinstance(path, str): raise TypeError('path must be a string') ret = run_in_thread(self.librados.rados_conf_read_file, (self.cluster, c_char_p(path))) if (ret != 0): raise make_ex(ret, "error calling conf_read_file") def conf_parse_argv(self, args): """ Parse known arguments from args, and remove; returned args contain only those unknown to ceph """ self.require_state("configuring", "connected") if not args: return # create instances of arrays of c_char_p's, both len(args) long # cretargs will always be a subset of cargs (perhaps identical) cargs = (c_char_p * len(args))(*args) cretargs = (c_char_p * len(args))() ret = run_in_thread(self.librados.rados_conf_parse_argv_remainder, (self.cluster, len(args), cargs, cretargs)) if ret: raise make_ex(ret, "error calling conf_parse_argv_remainder") # cretargs was allocated with fixed length; collapse return # list to eliminate any missing args retargs = [a for a in cretargs if a is not None] return retargs def conf_parse_env(self, var='CEPH_ARGS'): """ Parse known arguments from an environment variable, normally CEPH_ARGS. """ self.require_state("configuring", "connected") if not var: return ret = run_in_thread(self.librados.rados_conf_parse_env, (self.cluster, c_char_p(var))) if (ret != 0): raise make_ex(ret, "error calling conf_parse_env") def conf_get(self, option): """ Get the value of a configuration option :param option: which option to read :type option: str :returns: str - value of the option or None :raises: :class:`TypeError` """ self.require_state("configuring", "connected") if not isinstance(option, str): raise TypeError('option must be a string') length = 20 while True: ret_buf = create_string_buffer(length) ret = run_in_thread(self.librados.rados_conf_get, (self.cluster, c_char_p(option), ret_buf, c_size_t(length))) if (ret == 0): return ret_buf.value elif (ret == -errno.ENAMETOOLONG): length = length * 2 elif (ret == -errno.ENOENT): return None else: raise make_ex(ret, "error calling conf_get") def conf_set(self, option, val): """ Set the value of a configuration option :param option: which option to set :type option: str :param option: value of the option :type option: str :raises: :class:`TypeError`, :class:`ObjectNotFound` """ self.require_state("configuring", "connected") if not isinstance(option, str): raise TypeError('option must be a string') if not isinstance(val, str): raise TypeError('val must be a string') ret = run_in_thread(self.librados.rados_conf_set, (self.cluster, c_char_p(option), c_char_p(val))) if (ret != 0): raise make_ex(ret, "error calling conf_set") def ping_monitor(self, mon_id): """ Ping a monitor to assess liveness May be used as a simply way to assess liveness, or to obtain information about the monitor in a simple way even in the absence of quorum. :param mon_id: the ID portion of the monitor's name (i.e., mon.) :type mon_id: str :returns: the string reply from the monitor """ self.require_state("configuring", "connected") outstrp = pointer(pointer(c_char())) outstrlen = c_long() ret = run_in_thread(self.librados.rados_ping_monitor, (self.cluster, c_char_p(mon_id), outstrp, byref(outstrlen))) my_outstr = outstrp.contents[:(outstrlen.value)] if outstrlen.value: run_in_thread(self.librados.rados_buffer_free, (outstrp.contents,)) if ret != 0: raise make_ex(ret, "error calling ping_monitor") return my_outstr def connect(self, timeout=0): """ Connect to the cluster. Use shutdown() to release resources. """ self.require_state("configuring") ret = run_in_thread(self.librados.rados_connect, (self.cluster,), timeout) if (ret != 0): raise make_ex(ret, "error calling connect") self.state = "connected" def get_cluster_stats(self): """ Read usage info about the cluster This tells you total space, space used, space available, and number of objects. These are not updated immediately when data is written, they are eventually consistent. :returns: dict - contains the following keys: - ``kb`` (int) - total space - ``kb_used`` (int) - space used - ``kb_avail`` (int) - free space available - ``num_objects`` (int) - number of objects """ stats = rados_cluster_stat_t() ret = run_in_thread(self.librados.rados_cluster_stat, (self.cluster, byref(stats))) if ret < 0: raise make_ex( ret, "Rados.get_cluster_stats(%s): get_stats failed" % self.rados_id) return {'kb': stats.kb, 'kb_used': stats.kb_used, 'kb_avail': stats.kb_avail, 'num_objects': stats.num_objects} def pool_exists(self, pool_name): """ Checks if a given pool exists. :param pool_name: name of the pool to check :type pool_name: str :raises: :class:`TypeError`, :class:`Error` :returns: bool - whether the pool exists, false otherwise. """ self.require_state("connected") if not isinstance(pool_name, str): raise TypeError('pool_name must be a string') ret = run_in_thread(self.librados.rados_pool_lookup, (self.cluster, c_char_p(pool_name))) if (ret >= 0): return True elif (ret == -errno.ENOENT): return False else: raise make_ex(ret, "error looking up pool '%s'" % pool_name) def create_pool(self, pool_name, auid=None, crush_rule=None): """ Create a pool: - with default settings: if auid=None and crush_rule=None - owned by a specific auid: auid given and crush_rule=None - with a specific CRUSH rule: if auid=None and crush_rule given - with a specific CRUSH rule and auid: if auid and crush_rule given :param pool_name: name of the pool to create :type pool_name: str :param auid: the id of the owner of the new pool :type auid: int :param crush_rule: rule to use for placement in the new pool :type crush_rule: str :raises: :class:`TypeError`, :class:`Error` """ self.require_state("connected") if not isinstance(pool_name, str): raise TypeError('pool_name must be a string') if crush_rule is not None and not isinstance(crush_rule, str): raise TypeError('cruse_rule must be a string') if (auid == None): if (crush_rule == None): ret = run_in_thread(self.librados.rados_pool_create, (self.cluster, c_char_p(pool_name))) else: ret = run_in_thread(self.librados.\ rados_pool_create_with_crush_rule, (self.cluster, c_char_p(pool_name), c_ubyte(crush_rule))) elif (crush_rule == None): ret = run_in_thread(self.librados.rados_pool_create_with_auid, (self.cluster, c_char_p(pool_name), c_uint64(auid))) else: ret = run_in_thread(self.librados.rados_pool_create_with_all, (self.cluster, c_char_p(pool_name), c_uint64(auid), c_ubyte(crush_rule))) if ret < 0: raise make_ex(ret, "error creating pool '%s'" % pool_name) def delete_pool(self, pool_name): """ Delete a pool and all data inside it. The pool is removed from the cluster immediately, but the actual data is deleted in the background. :param pool_name: name of the pool to delete :type pool_name: str :raises: :class:`TypeError`, :class:`Error` """ self.require_state("connected") if not isinstance(pool_name, str): raise TypeError('pool_name must be a string') ret = run_in_thread(self.librados.rados_pool_delete, (self.cluster, c_char_p(pool_name))) if ret < 0: raise make_ex(ret, "error deleting pool '%s'" % pool_name) def list_pools(self): """ Gets a list of pool names. :returns: list - of pool names. """ self.require_state("connected") size = c_size_t(512) while True: c_names = create_string_buffer(size.value) ret = run_in_thread(self.librados.rados_pool_list, (self.cluster, byref(c_names), size)) if ret > size.value: size = c_size_t(ret) else: break return filter(lambda name: name != '', c_names.raw.split('\0')) def get_fsid(self): """ Get the fsid of the cluster as a hexadecimal string. :raises: :class:`Error` :returns: str - cluster fsid """ self.require_state("connected") buf_len = 37 fsid = create_string_buffer(buf_len) ret = run_in_thread(self.librados.rados_cluster_fsid, (self.cluster, byref(fsid), c_size_t(buf_len))) if ret < 0: raise make_ex(ret, "error getting cluster fsid") return fsid.value def open_ioctx(self, ioctx_name): """ Create an io context The io context allows you to perform operations within a particular pool. :param ioctx_name: name of the pool :type ioctx_name: str :raises: :class:`TypeError`, :class:`Error` :returns: Ioctx - Rados Ioctx object """ self.require_state("connected") if not isinstance(ioctx_name, str): raise TypeError('ioctx_name must be a string') ioctx = c_void_p() ret = run_in_thread(self.librados.rados_ioctx_create, (self.cluster, c_char_p(ioctx_name), byref(ioctx))) if ret < 0: raise make_ex(ret, "error opening ioctx '%s'" % ioctx_name) return Ioctx(ioctx_name, self.librados, ioctx) def mon_command(self, cmd, inbuf, timeout=0, target=None): """ mon_command[_target](cmd, inbuf, outbuf, outbuflen, outs, outslen) returns (int ret, string outbuf, string outs) """ import sys self.require_state("connected") outbufp = pointer(pointer(c_char())) outbuflen = c_long() outsp = pointer(pointer(c_char())) outslen = c_long() cmdarr = (c_char_p * len(cmd))(*cmd) if target: ret = run_in_thread(self.librados.rados_mon_command_target, (self.cluster, c_char_p(target), cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), outbufp, byref(outbuflen), outsp, byref(outslen)), timeout) else: ret = run_in_thread(self.librados.rados_mon_command, (self.cluster, cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), outbufp, byref(outbuflen), outsp, byref(outslen)), timeout) # copy returned memory (ctypes makes a copy, not a reference) my_outbuf = outbufp.contents[:(outbuflen.value)] my_outs = outsp.contents[:(outslen.value)] # free callee's allocations if outbuflen.value: run_in_thread(self.librados.rados_buffer_free, (outbufp.contents,)) if outslen.value: run_in_thread(self.librados.rados_buffer_free, (outsp.contents,)) return (ret, my_outbuf, my_outs) def osd_command(self, osdid, cmd, inbuf, timeout=0): """ osd_command(osdid, cmd, inbuf, outbuf, outbuflen, outs, outslen) returns (int ret, string outbuf, string outs) """ import sys self.require_state("connected") outbufp = pointer(pointer(c_char())) outbuflen = c_long() outsp = pointer(pointer(c_char())) outslen = c_long() cmdarr = (c_char_p * len(cmd))(*cmd) ret = run_in_thread(self.librados.rados_osd_command, (self.cluster, osdid, cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), outbufp, byref(outbuflen), outsp, byref(outslen)), timeout) # copy returned memory (ctypes makes a copy, not a reference) my_outbuf = outbufp.contents[:(outbuflen.value)] my_outs = outsp.contents[:(outslen.value)] # free callee's allocations if outbuflen.value: run_in_thread(self.librados.rados_buffer_free, (outbufp.contents,)) if outslen.value: run_in_thread(self.librados.rados_buffer_free, (outsp.contents,)) return (ret, my_outbuf, my_outs) def pg_command(self, pgid, cmd, inbuf, timeout=0): """ pg_command(pgid, cmd, inbuf, outbuf, outbuflen, outs, outslen) returns (int ret, string outbuf, string outs) """ import sys self.require_state("connected") outbufp = pointer(pointer(c_char())) outbuflen = c_long() outsp = pointer(pointer(c_char())) outslen = c_long() cmdarr = (c_char_p * len(cmd))(*cmd) ret = run_in_thread(self.librados.rados_pg_command, (self.cluster, c_char_p(pgid), cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), outbufp, byref(outbuflen), outsp, byref(outslen)), timeout) # copy returned memory (ctypes makes a copy, not a reference) my_outbuf = outbufp.contents[:(outbuflen.value)] my_outs = outsp.contents[:(outslen.value)] # free callee's allocations if outbuflen.value: run_in_thread(self.librados.rados_buffer_free, (outbufp.contents,)) if outslen.value: run_in_thread(self.librados.rados_buffer_free, (outsp.contents,)) return (ret, my_outbuf, my_outs) class ObjectIterator(object): """rados.Ioctx Object iterator""" def __init__(self, ioctx): self.ioctx = ioctx self.ctx = c_void_p() ret = run_in_thread(self.ioctx.librados.rados_objects_list_open, (self.ioctx.io, byref(self.ctx))) if ret < 0: raise make_ex(ret, "error iterating over the objects in ioctx '%s'" \ % self.ioctx.name) def __iter__(self): return self def next(self): """ Get the next object name and locator in the pool :raises: StopIteration :returns: next rados.Ioctx Object """ key = c_char_p() locator = c_char_p() ret = run_in_thread(self.ioctx.librados.rados_objects_list_next, (self.ctx, byref(key), byref(locator))) if ret < 0: raise StopIteration() return Object(self.ioctx, key.value, locator.value) def __del__(self): run_in_thread(self.ioctx.librados.rados_objects_list_close, (self.ctx,)) class XattrIterator(object): """Extended attribute iterator""" def __init__(self, ioctx, it, oid): self.ioctx = ioctx self.it = it self.oid = oid def __iter__(self): return self def next(self): """ Get the next xattr on the object :raises: StopIteration :returns: pair - of name and value of the next Xattr """ name_ = c_char_p(0) val_ = c_char_p(0) len_ = c_int(0) ret = run_in_thread(self.ioctx.librados.rados_getxattrs_next, (self.it, byref(name_), byref(val_), byref(len_))) if (ret != 0): raise make_ex(ret, "error iterating over the extended attributes \ in '%s'" % self.oid) if name_.value == None: raise StopIteration() name = ctypes.string_at(name_) val = ctypes.string_at(val_, len_) return (name, val) def __del__(self): run_in_thread(self.ioctx.librados.rados_getxattrs_end, (self.it,)) class SnapIterator(object): """Snapshot iterator""" def __init__(self, ioctx): self.ioctx = ioctx # We don't know how big a buffer we need until we've called the # function. So use the exponential doubling strategy. num_snaps = 10 while True: self.snaps = (ctypes.c_uint64 * num_snaps)() ret = run_in_thread(self.ioctx.librados.rados_ioctx_snap_list, (self.ioctx.io, self.snaps, c_int(num_snaps))) if (ret >= 0): self.max_snap = ret break elif (ret != -errno.ERANGE): raise make_ex(ret, "error calling rados_snap_list for \ ioctx '%s'" % self.ioctx.name) num_snaps = num_snaps * 2 self.cur_snap = 0 def __iter__(self): return self def next(self): """ Get the next Snapshot :raises: :class:`Error`, StopIteration :returns: Snap - next snapshot """ if (self.cur_snap >= self.max_snap): raise StopIteration snap_id = self.snaps[self.cur_snap] name_len = 10 while True: name = create_string_buffer(name_len) ret = run_in_thread(self.ioctx.librados.rados_ioctx_snap_get_name, (self.ioctx.io, c_uint64(snap_id), byref(name), c_int(name_len))) if (ret == 0): name_len = ret break elif (ret != -errno.ERANGE): raise make_ex(ret, "rados_snap_get_name error") name_len = name_len * 2 snap = Snap(self.ioctx, name.value, snap_id) self.cur_snap = self.cur_snap + 1 return snap class Snap(object): """Snapshot object""" def __init__(self, ioctx, name, snap_id): self.ioctx = ioctx self.name = name self.snap_id = snap_id def __str__(self): return "rados.Snap(ioctx=%s,name=%s,snap_id=%d)" \ % (str(self.ioctx), self.name, self.snap_id) def get_timestamp(self): """ Find when a snapshot in the current pool occurred :raises: :class:`Error` :returns: datetime - the data and time the snapshot was created """ snap_time = c_long(0) ret = run_in_thread(self.ioctx.librados.rados_ioctx_snap_get_stamp, (self.ioctx.io, self.snap_id, byref(snap_time))) if (ret != 0): raise make_ex(ret, "rados_ioctx_snap_get_stamp error") return datetime.fromtimestamp(snap_time.value) class Completion(object): """completion object""" def __init__(self, ioctx, rados_comp, oncomplete, onsafe, complete_cb, safe_cb): self.rados_comp = rados_comp self.oncomplete = oncomplete self.onsafe = onsafe self.ioctx = ioctx self.complete_cb = complete_cb self.safe_cb = safe_cb def wait_for_safe(self): """ Is an asynchronous operation safe? This does not imply that the safe callback has finished. :returns: whether the operation is safe """ return run_in_thread(self.ioctx.librados.rados_aio_is_safe, (self.rados_comp,)) def wait_for_complete(self): """ Has an asynchronous operation completed? This does not imply that the safe callback has finished. :returns: whether the operation is completed """ return run_in_thread(self.ioctx.librados.rados_aio_is_complete, (self.rados_comp,)) def get_return_value(self): """ Get the return value of an asychronous operation The return value is set when the operation is complete or safe, whichever comes first. :returns: int - return value of the operation """ return run_in_thread(self.ioctx.librados.rados_aio_get_return_value, (self.rados_comp,)) def __del__(self): """ Release a completion Call this when you no longer need the completion. It may not be freed immediately if the operation is not acked and committed. """ run_in_thread(self.ioctx.librados.rados_aio_release, (self.rados_comp,)) RADOS_CB = CFUNCTYPE(c_int, c_void_p, c_void_p) class Ioctx(object): """rados.Ioctx object""" def __init__(self, name, librados, io): self.name = name self.librados = librados self.io = io self.state = "open" self.locator_key = "" self.safe_cbs = {} self.complete_cbs = {} self.lock = threading.Lock() def __enter__(self): return self def __exit__(self, type_, value, traceback): self.close() return False def __del__(self): self.close() def __aio_safe_cb(self, completion, _): """ Callback to onsafe() for asynchronous operations """ cb = None with self.lock: cb = self.safe_cbs[completion] del self.safe_cbs[completion] cb.onsafe(cb) return 0 def __aio_complete_cb(self, completion, _): """ Callback to oncomplete() for asynchronous operations """ cb = None with self.lock: cb = self.complete_cbs[completion] del self.complete_cbs[completion] cb.oncomplete(cb) return 0 def __get_completion(self, oncomplete, onsafe): """ Constructs a completion to use with asynchronous operations :param oncomplete: what to do when the write is safe and complete in memory on all replicas :type oncomplete: completion :param onsafe: what to do when the write is safe and complete on storage on all replicas :type onsafe: completion :raises: :class:`Error` :returns: completion object """ completion = c_void_p(0) complete_cb = None safe_cb = None if oncomplete: complete_cb = RADOS_CB(self.__aio_complete_cb) if onsafe: safe_cb = RADOS_CB(self.__aio_safe_cb) ret = run_in_thread(self.librados.rados_aio_create_completion, (c_void_p(0), complete_cb, safe_cb, byref(completion))) if ret < 0: raise make_ex(ret, "error getting a completion") with self.lock: completion_obj = Completion(self, completion, oncomplete, onsafe, complete_cb, safe_cb) if oncomplete: self.complete_cbs[completion.value] = completion_obj if onsafe: self.safe_cbs[completion.value] = completion_obj return completion_obj def aio_write(self, object_name, to_write, offset=0, oncomplete=None, onsafe=None): """ Write data to an object asynchronously Queues the write and returns. :param object_name: name of the object :type object_name: str :param to_write: data to write :type to_write: str :param offset: byte offset in the object to begin writing at :type offset: int :param oncomplete: what to do when the write is safe and complete in memory on all replicas :type oncomplete: completion :param onsafe: what to do when the write is safe and complete on storage on all replicas :type onsafe: completion :raises: :class:`Error` :returns: completion object """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_write, (self.io, c_char_p(object_name), completion.rados_comp, c_char_p(to_write), c_size_t(len(to_write)), c_uint64(offset))) if ret < 0: raise make_ex(ret, "error writing object %s" % object_name) return completion def aio_write_full(self, object_name, to_write, oncomplete=None, onsafe=None): """ Asychronously write an entire object The object is filled with the provided data. If the object exists, it is atomically truncated and then written. Queues the write and returns. :param object_name: name of the object :type object_name: str :param to_write: data to write :type to_write: str :param oncomplete: what to do when the write is safe and complete in memory on all replicas :type oncomplete: completion :param onsafe: what to do when the write is safe and complete on storage on all replicas :type onsafe: completion :raises: :class:`Error` :returns: completion object """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_write_full, (self.io, c_char_p(object_name), completion.rados_comp, c_char_p(to_write), c_size_t(len(to_write)))) if ret < 0: raise make_ex(ret, "error writing object %s" % object_name) return completion def aio_append(self, object_name, to_append, oncomplete=None, onsafe=None): """ Asychronously append data to an object Queues the write and returns. :param object_name: name of the object :type object_name: str :param to_append: data to append :type to_append: str :param offset: byte offset in the object to begin writing at :type offset: int :param oncomplete: what to do when the write is safe and complete in memory on all replicas :type oncomplete: completion :param onsafe: what to do when the write is safe and complete on storage on all replicas :type onsafe: completion :raises: :class:`Error` :returns: completion object """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_append, (self.io, c_char_p(object_name), completion.rados_comp, c_char_p(to_append), c_size_t(len(to_append)))) if ret < 0: raise make_ex(ret, "error appending to object %s" % object_name) return completion def aio_flush(self): """ Block until all pending writes in an io context are safe :raises: :class:`Error` """ ret = run_in_thread(self.librados.rados_aio_flush, (self.io,)) if ret < 0: raise make_ex(ret, "error flushing") def aio_read(self, object_name, length, offset, oncomplete): """ Asychronously read data from an object oncomplete will be called with the returned read value as well as the completion: oncomplete(completion, data_read) :param object_name: name of the object to read from :type object_name: str :param length: the number of bytes to read :type length: int :param offset: byte offset in the object to begin reading from :type offset: int :param oncomplete: what to do when the read is complete :type oncomplete: completion :raises: :class:`Error` :returns: completion object """ buf = create_string_buffer(length) def oncomplete_(completion_v): return_value = completion_v.get_return_value() return oncomplete(completion_v, ctypes.string_at(buf, return_value) if return_value >= 0 else None) completion = self.__get_completion(oncomplete_, None) ret = run_in_thread(self.librados.rados_aio_read, (self.io, c_char_p(object_name), completion.rados_comp, buf, c_size_t(length), c_uint64(offset))) if ret < 0: raise make_ex(ret, "error reading %s" % object_name) return completion def aio_remove(self, object_name, oncomplete=None, onsafe=None): """ Asychronously remove an object :param object_name: name of the object to remove :type object_name: str :param oncomplete: what to do when the remove is safe and complete in memory on all replicas :type oncomplete: completion :param onsafe: what to do when the remove is safe and complete on storage on all replicas :type onsafe: completion :raises: :class:`Error` :returns: completion object """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_remove, (self.io, c_char_p(object_name), completion.rados_comp)) if ret < 0: raise make_ex(ret, "error removing %s" % object_name) return completion def require_ioctx_open(self): """ Checks if the rados.Ioctx object state is 'open' :raises: IoctxStateError """ if self.state != "open": raise IoctxStateError("The pool is %s" % self.state) def change_auid(self, auid): """ Attempt to change an io context's associated auid "owner." Requires that you have write permission on both the current and new auid. :raises: :class:`Error` """ self.require_ioctx_open() ret = run_in_thread(self.librados.rados_ioctx_pool_set_auid, (self.io, ctypes.c_uint64(auid))) if ret < 0: raise make_ex(ret, "error changing auid of '%s' to %d" %\ (self.name, auid)) def set_locator_key(self, loc_key): """ Set the key for mapping objects to pgs within an io context. The key is used instead of the object name to determine which placement groups an object is put in. This affects all subsequent operations of the io context - until a different locator key is set, all objects in this io context will be placed in the same pg. :param loc_key: the key to use as the object locator, or NULL to discard any previously set key :type loc_key: str :raises: :class:`TypeError` """ self.require_ioctx_open() if not isinstance(loc_key, str): raise TypeError('loc_key must be a string') run_in_thread(self.librados.rados_ioctx_locator_set_key, (self.io, c_char_p(loc_key))) self.locator_key = loc_key def get_locator_key(self): """ Get the locator_key of context :returns: locator_key """ return self.locator_key def close(self): """ Close a rados.Ioctx object. This just tells librados that you no longer need to use the io context. It may not be freed immediately if there are pending asynchronous requests on it, but you should not use an io context again after calling this function on it. """ if self.state == "open": self.require_ioctx_open() run_in_thread(self.librados.rados_ioctx_destroy, (self.io,)) self.state = "closed" def write(self, key, data, offset=0): """ Write data to an object synchronously :param key: name of the object :type key: str :param data: data to write :type data: str :param offset: byte offset in the object to begin writing at :type offset: int :raises: :class:`TypeError` :raises: :class:`LogicError` :returns: int - number of bytes written """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') if not isinstance(data, str): raise TypeError('data must be a string') length = len(data) ret = run_in_thread(self.librados.rados_write, (self.io, c_char_p(key), c_char_p(data), c_size_t(length), c_uint64(offset))) if ret == 0: return ret elif ret < 0: raise make_ex(ret, "Ioctx.write(%s): failed to write %s" % \ (self.name, key)) else: raise LogicError("Ioctx.write(%s): rados_write \ returned %d, but should return zero on success." % (self.name, ret)) def write_full(self, key, data): """ Write an entire object synchronously. The object is filled with the provided data. If the object exists, it is atomically truncated and then written. :param key: name of the object :type key: str :param data: data to write :type data: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: int - 0 on success """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') if not isinstance(data, str): raise TypeError('data must be a string') length = len(data) ret = run_in_thread(self.librados.rados_write_full, (self.io, c_char_p(key), c_char_p(data), c_size_t(length))) if ret == 0: return ret elif ret < 0: raise make_ex(ret, "Ioctx.write_full(%s): failed to write %s" % \ (self.name, key)) else: raise LogicError("Ioctx.write_full(%s): rados_write_full \ returned %d, but should return zero on success." % (self.name, ret)) def append(self, key, data): """ Append data to an object synchronously :param key: name of the object :type key: str :param data: data to write :type data: str :raises: :class:`TypeError` :raises: :class:`LogicError` :returns: int - number of bytes written """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') if not isinstance(data, str): raise TypeError('data must be a string') length = len(data) ret = run_in_thread(self.librados.rados_append, (self.io, c_char_p(key), c_char_p(data), c_size_t(length))) if ret == 0: return ret elif ret < 0: raise make_ex(ret, "Ioctx.append(%s): failed to append %s" % \ (self.name, key)) else: raise LogicError("Ioctx.append(%s): rados_append \ returned %d, but should return zero on success." % (self.name, ret)) def read(self, key, length=8192, offset=0): """ Read data from an object synchronously :param key: name of the object :type key: str :param length: the number of bytes to read (default=8192) :type length: int :param offset: byte offset in the object to begin reading at :type offset: int :raises: :class:`TypeError` :raises: :class:`Error` :returns: str - data read from object """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') ret_buf = create_string_buffer(length) ret = run_in_thread(self.librados.rados_read, (self.io, c_char_p(key), ret_buf, c_size_t(length), c_uint64(offset))) if ret < 0: raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key)) return ctypes.string_at(ret_buf, ret) def get_stats(self): """ Get pool usage statistics :returns: dict - contains the following keys: - ``num_bytes`` (int) - size of pool in bytes - ``num_kb`` (int) - size of pool in kbytes - ``num_objects`` (int) - number of objects in the pool - ``num_object_clones`` (int) - number of object clones - ``num_object_copies`` (int) - number of object copies - ``num_objects_missing_on_primary`` (int) - number of objets missing on primary - ``num_objects_unfound`` (int) - number of unfound objects - ``num_objects_degraded`` (int) - number of degraded objects - ``num_rd`` (int) - bytes read - ``num_rd_kb`` (int) - kbytes read - ``num_wr`` (int) - bytes written - ``num_wr_kb`` (int) - kbytes written """ self.require_ioctx_open() stats = rados_pool_stat_t() ret = run_in_thread(self.librados.rados_ioctx_pool_stat, (self.io, byref(stats))) if ret < 0: raise make_ex(ret, "Ioctx.get_stats(%s): get_stats failed" % self.name) return {'num_bytes': stats.num_bytes, 'num_kb': stats.num_kb, 'num_objects': stats.num_objects, 'num_object_clones': stats.num_object_clones, 'num_object_copies': stats.num_object_copies, "num_objects_missing_on_primary": stats.num_objects_missing_on_primary, "num_objects_unfound": stats.num_objects_unfound, "num_objects_degraded": stats.num_objects_degraded, "num_rd": stats.num_rd, "num_rd_kb": stats.num_rd_kb, "num_wr": stats.num_wr, "num_wr_kb": stats.num_wr_kb } def remove_object(self, key): """ Delete an object This does not delete any snapshots of the object. :param key: the name of the object to delete :type key: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: bool - True on success """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') ret = run_in_thread(self.librados.rados_remove, (self.io, c_char_p(key))) if ret < 0: raise make_ex(ret, "Failed to remove '%s'" % key) return True def trunc(self, key, size): """ Resize an object If this enlarges the object, the new area is logically filled with zeroes. If this shrinks the object, the excess data is removed. :param key: the name of the object to resize :type key: str :param size: the new size of the object in bytes :type size: int :raises: :class:`TypeError` :raises: :class:`Error` :returns: int - 0 on success, otherwise raises error """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') ret = run_in_thread(self.librados.rados_trunc, (self.io, c_char_p(key), c_uint64(size))) if ret < 0: raise make_ex(ret, "Ioctx.trunc(%s): failed to truncate %s" % (self.name, key)) return ret def stat(self, key): """ Get object stats (size/mtime) :param key: the name of the object to get stats from :type key: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: (size,timestamp) """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') psize = c_uint64() pmtime = c_uint64() ret = run_in_thread(self.librados.rados_stat, (self.io, c_char_p(key), pointer(psize), pointer(pmtime))) if ret < 0: raise make_ex(ret, "Failed to stat %r" % key) return psize.value, time.localtime(pmtime.value) def get_xattr(self, key, xattr_name): """ Get the value of an extended attribute on an object. :param key: the name of the object to get xattr from :type key: str :param xattr_name: which extended attribute to read :type xattr_name: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: str - value of the xattr """ self.require_ioctx_open() if not isinstance(xattr_name, str): raise TypeError('xattr_name must be a string') ret_length = 4096 while ret_length < 4096 * 1024 * 1024: ret_buf = create_string_buffer(ret_length) ret = run_in_thread(self.librados.rados_getxattr, (self.io, c_char_p(key), c_char_p(xattr_name), ret_buf, c_size_t(ret_length))) if (ret == -errno.ERANGE): ret_length *= 2 elif ret < 0: raise make_ex(ret, "Failed to get xattr %r" % xattr_name) else: break return ctypes.string_at(ret_buf, ret) def get_xattrs(self, oid): """ Start iterating over xattrs on an object. :param oid: the name of the object to get xattrs from :type key: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: XattrIterator """ self.require_ioctx_open() if not isinstance(oid, str): raise TypeError('oid must be a string') it = c_void_p(0) ret = run_in_thread(self.librados.rados_getxattrs, (self.io, oid, byref(it))) if ret != 0: raise make_ex(ret, "Failed to get rados xattrs for object %r" % oid) return XattrIterator(self, it, oid) def set_xattr(self, key, xattr_name, xattr_value): """ Set an extended attribute on an object. :param key: the name of the object to set xattr to :type key: str :param xattr_name: which extended attribute to set :type xattr_name: str :param xattr_value: the value of the extended attribute :type xattr_value: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: bool - True on success, otherwise raise an error """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') if not isinstance(xattr_name, str): raise TypeError('xattr_name must be a string') if not isinstance(xattr_value, str): raise TypeError('xattr_value must be a string') ret = run_in_thread(self.librados.rados_setxattr, (self.io, c_char_p(key), c_char_p(xattr_name), c_char_p(xattr_value), c_size_t(len(xattr_value)))) if ret < 0: raise make_ex(ret, "Failed to set xattr %r" % xattr_name) return True def rm_xattr(self, key, xattr_name): """ Removes an extended attribute on from an object. :param key: the name of the object to remove xattr from :type key: str :param xattr_name: which extended attribute to remove :type xattr_name: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: bool - True on success, otherwise raise an error """ self.require_ioctx_open() if not isinstance(key, str): raise TypeError('key must be a string') if not isinstance(xattr_name, str): raise TypeError('xattr_name must be a string') ret = run_in_thread(self.librados.rados_rmxattr, (self.io, c_char_p(key), c_char_p(xattr_name))) if ret < 0: raise make_ex(ret, "Failed to delete key %r xattr %r" % (key, xattr_name)) return True def list_objects(self): """ Get ObjectIterator on rados.Ioctx object. :returns: ObjectIterator """ self.require_ioctx_open() return ObjectIterator(self) def list_snaps(self): """ Get SnapIterator on rados.Ioctx object. :returns: SnapIterator """ self.require_ioctx_open() return SnapIterator(self) def create_snap(self, snap_name): """ Create a pool-wide snapshot :param snap_name: the name of the snapshot :type snap_name: str :raises: :class:`TypeError` :raises: :class:`Error` """ self.require_ioctx_open() if not isinstance(snap_name, str): raise TypeError('snap_name must be a string') ret = run_in_thread(self.librados.rados_ioctx_snap_create, (self.io, c_char_p(snap_name))) if (ret != 0): raise make_ex(ret, "Failed to create snap %s" % snap_name) def remove_snap(self, snap_name): """ Removes a pool-wide snapshot :param snap_name: the name of the snapshot :type snap_name: str :raises: :class:`TypeError` :raises: :class:`Error` """ self.require_ioctx_open() if not isinstance(snap_name, str): raise TypeError('snap_name must be a string') ret = run_in_thread(self.librados.rados_ioctx_snap_remove, (self.io, c_char_p(snap_name))) if (ret != 0): raise make_ex(ret, "Failed to remove snap %s" % snap_name) def lookup_snap(self, snap_name): """ Get the id of a pool snapshot :param snap_name: the name of the snapshot to lookop :type snap_name: str :raises: :class:`TypeError` :raises: :class:`Error` :returns: Snap - on success """ self.require_ioctx_open() if not isinstance(snap_name, str): raise TypeError('snap_name must be a string') snap_id = c_uint64() ret = run_in_thread(self.librados.rados_ioctx_snap_lookup, (self.io, c_char_p(snap_name), byref(snap_id))) if (ret != 0): raise make_ex(ret, "Failed to lookup snap %s" % snap_name) return Snap(self, snap_name, snap_id) def get_last_version(self): """ Return the version of the last object read or written to. This exposes the internal version number of the last object read or written via this io context :returns: version of the last object used """ self.require_ioctx_open() return run_in_thread(self.librados.rados_get_last_version, (self.io,)) def set_object_locator(func): def retfunc(self, *args, **kwargs): if self.locator_key is not None: old_locator = self.ioctx.get_locator_key() self.ioctx.set_locator_key(self.locator_key) retval = func(self, *args, **kwargs) self.ioctx.set_locator_key(old_locator) return retval else: return func(self, *args, **kwargs) return retfunc class Object(object): """Rados object wrapper, makes the object look like a file""" def __init__(self, ioctx, key, locator_key=None): self.key = key self.ioctx = ioctx self.offset = 0 self.state = "exists" self.locator_key = locator_key def __str__(self): return "rados.Object(ioctx=%s,key=%s)" % (str(self.ioctx), self.key) def require_object_exists(self): if self.state != "exists": raise ObjectStateError("The object is %s" % self.state) @set_object_locator def read(self, length = 1024*1024): self.require_object_exists() ret = self.ioctx.read(self.key, length, self.offset) self.offset += len(ret) return ret @set_object_locator def write(self, string_to_write): self.require_object_exists() ret = self.ioctx.write(self.key, string_to_write, self.offset) self.offset += ret return ret @set_object_locator def remove(self): self.require_object_exists() self.ioctx.remove_object(self.key) self.state = "removed" @set_object_locator def stat(self): self.require_object_exists() return self.ioctx.stat(self.key) def seek(self, position): self.require_object_exists() self.offset = position @set_object_locator def get_xattr(self, xattr_name): self.require_object_exists() return self.ioctx.get_xattr(self.key, xattr_name) @set_object_locator def get_xattrs(self): self.require_object_exists() return self.ioctx.get_xattrs(self.key) @set_object_locator def set_xattr(self, xattr_name, xattr_value): self.require_object_exists() return self.ioctx.set_xattr(self.key, xattr_name, xattr_value) @set_object_locator def rm_xattr(self, xattr_name): self.require_object_exists() return self.ioctx.rm_xattr(self.key, xattr_name) MONITOR_LEVELS = [ "debug", "info", "warn", "warning", "err", "error", "sec", ] class MonitorLog(object): """ For watching cluster log messages. Instantiate an object and keep it around while callback is periodically called. Construct with 'level' to monitor 'level' messages (one of MONITOR_LEVELS). arg will be passed to the callback. callback will be called with: arg (given to __init__) line (the full line, including timestamp, who, level, msg) who (which entity issued the log message) timestamp_sec (sec of a struct timespec) timestamp_nsec (sec of a struct timespec) seq (sequence number) level (string representing the level of the log message) msg (the message itself) callback's return value is ignored """ def monitor_log_callback(self, arg, line, who, sec, nsec, seq, level, msg): """ Local callback wrapper, in case we decide to do something """ self.callback(arg, line, who, sec, nsec, seq, level, msg) return 0 def __init__(self, cluster, level, callback, arg): if level not in MONITOR_LEVELS: raise LogicError("invalid monitor level " + level) if not callable(callback): raise LogicError("callback must be a callable function") self.level = level self.callback = callback self.arg = arg callback_factory = CFUNCTYPE(c_int, # return type (really void) c_void_p, # arg c_char_p, # line c_char_p, # who c_uint64, # timestamp_sec c_uint64, # timestamp_nsec c_ulong, # seq c_char_p, # level c_char_p) # msg self.internal_callback = callback_factory(self.monitor_log_callback) r = run_in_thread(cluster.librados.rados_monitor_log, (cluster.cluster, level, self.internal_callback, arg)) if r: raise make_ex(r, 'error calling rados_monitor_log') ceph-0.80.11/src/TODO0000664000175100017510000000006612623076744016156 0ustar jenkins-buildjenkins-build See http://tracker.newdream.net/projects/ceph/roadmapceph-0.80.11/src/ceph-crush-location.in0000775000175100017510000000347012623076744021672 0ustar jenkins-buildjenkins-build#!/bin/sh # # Generate a CRUSH location for the given entity # # The CRUSH location consists of a list of key=value pairs, separated # by spaces, all on a single line. This describes where in CRUSH # hierarhcy this entity should be placed. # # Arguments: # --cluster name of the cluster (see /etc/ceph/$cluster.conf) # --type daemon/entity type # --id id (osd number, mds name, client name) # # if we start up as ./ceph-crush-location, assume everything else is # in the current directory too. if [ `dirname $0` = "." ] && [ $PWD != "/usr/bin" ]; then BINDIR=. SBINDIR=. LIBDIR=. ETCDIR=. else BINDIR=@bindir@ SBINDIR=@prefix@/sbin LIBDIR=@libdir@/ceph ETCDIR=@sysconfdir@/ceph fi usage_exit() { echo "usage: $0 [--cluster ] --id --type " exit } cluster="ceph" type="" id="" while [ $# -ge 1 ]; do case $1 in --cluster | -C) shift cluster="$1" shift ;; --id | -i) shift id="$1" shift ;; --type | -t) shift type="$1" shift ;; *) echo "unrecognized option '$1'" usage_exit ;; esac done if [ -z "$type" ]; then echo "must specify entity type" usage_exit fi if [ -z "$id" ]; then echo "must specify id" usage_exit fi # try a type-specific config, e.g. 'osd crush location' location="$($BINDIR/ceph-conf --cluster=${cluster:-ceph} --name=$type.$id --lookup ${type}_crush_location || :)" if [ -n "$location" ]; then echo $location exit 0 fi # try a generic location location="$($BINDIR/ceph-conf --cluster=${cluster:-ceph} --name=$type.$id --lookup crush_location || :)" if [ -n "$location" ]; then echo $location exit 0 fi # spit out something generic echo "host=$(hostname -s) root=default" ceph-0.80.11/src/cephfs.cc0000664000175100017510000002225012623076744017244 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2010 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Simple little program to let you: * 1) View the layout information on a file or directory, * 2) Modify the layout information on an empty file, * 3) Modify the default layout on a directory */ #include #include #include #include #include #include #include #include #include #include #include "client/ioctl.h" #include "common/errno.h" using namespace std; #define CMD_SHOW_LAYOUT 1 #define CMD_SHOW_LOC 2 #define CMD_SET_LAYOUT 3 #define CMD_MAP 4 void usage(); int init_options(int argc, char **argv, int *fd, char **path, int *cmd, int *stripe_unit, int *stripe_count, int *object_size, int64_t *pool, int *file_offset, bool *dir); int main (int argc, char **argv) { int fd = 0; int err = 0; char *path = 0; int cmd = 0; int stripe_unit = 0; int stripe_count = 0; int object_size = 0; int64_t pool = 0; int file_offset = 0; bool dir = false; if (init_options(argc, argv, &fd, &path, &cmd, &stripe_unit, &stripe_count, &object_size, &pool, &file_offset, &dir)){ usage(); return 0; } if (CMD_SHOW_LAYOUT == cmd) { struct ceph_ioctl_layout layout; memset(&layout, 0, sizeof(layout)); err = ioctl(fd, CEPH_IOC_GET_LAYOUT, (unsigned long)&layout); if (err) { cerr << "Error getting layout: " << cpp_strerror(errno) << endl; return 1; } if (layout.stripe_unit == 0) { cerr << "layout not specified" << endl; } else { cout << "layout.data_pool: " << layout.data_pool << endl; cout << "layout.object_size: " << layout.object_size << endl; cout << "layout.stripe_unit: " << layout.stripe_unit << endl; cout << "layout.stripe_count: " << layout.stripe_count << endl; } } else if (CMD_SHOW_LOC == cmd) { struct ceph_ioctl_dataloc location; location.file_offset = file_offset; err = ioctl(fd, CEPH_IOC_GET_DATALOC, (unsigned long)&location); if (err) { cerr << "Error getting location: " << cpp_strerror(err) << endl; return 1; } cout << "location.file_offset: " << location.file_offset << endl; cout << "location.object_offset:" << location.object_offset << endl; cout << "location.object_no: " << location.object_no << endl; cout << "location.object_size: " << location.object_size << endl; cout << "location.object_name: " << location.object_name << endl; cout << "location.block_offset: " << location.block_offset << endl; cout << "location.block_size: " << location.block_size << endl; cout << "location.osd: " << location.osd << endl; // cout << "osd address: " << location.osd_addr << endl; } else if (CMD_SET_LAYOUT == cmd) { struct ceph_ioctl_layout layout; memset(&layout, 0, sizeof(layout)); int ioctl_num = (dir ? CEPH_IOC_SET_LAYOUT_POLICY : CEPH_IOC_SET_LAYOUT); layout.data_pool = pool; layout.object_size = object_size; layout.stripe_count = stripe_count; layout.stripe_unit = stripe_unit; layout.unused = -1; /* used to be preferred_osd */ err = ioctl(fd, ioctl_num, (unsigned long)&layout); if (err) { cerr << "Error setting layout: " << cpp_strerror(errno) << endl; return 1; } } else if (CMD_MAP == cmd) { struct stat st; err = ::fstat(fd, &st); if (err < 0) { cerr << "error statting file: " << cpp_strerror(errno) << endl; return 1; } struct ceph_ioctl_layout layout; memset(&layout, 0, sizeof(layout)); err = ioctl(fd, CEPH_IOC_GET_LAYOUT, (unsigned long)&layout); if (err) { cerr << "Error getting layout: " << cpp_strerror(errno) << endl; return 1; } printf("%15s %24s %12s %12s %s\n", "FILE OFFSET", "OBJECT", "OFFSET", "LENGTH", "OSD"); for (long long off = 0; off < st.st_size; off += layout.stripe_unit) { struct ceph_ioctl_dataloc location; location.file_offset = off; err = ioctl(fd, CEPH_IOC_GET_DATALOC, (unsigned long)&location); if (err) { cerr << "Error getting location: " << cpp_strerror(errno) << endl; return 1; } printf("%15lld %24s %12lld %12lld %d\n", off, location.object_name, (long long)location.object_offset, (long long)location.block_size, (int)location.osd); } } else { cerr << "unknown cmd somehow set!" << endl; usage(); return 1; } return 0; } void usage() { cerr << "usage: cephfs path command [options]*" << endl; cerr << "Commands:" << endl; cerr << " show_layout -- view the layout information on a file or dir" << endl; cerr << " set_layout -- set the layout on an empty file,\n" << " or the default layout on a directory" << endl; cerr << " show_location -- view the location information on a file" << endl; cerr << " map -- display file objects, pgs, osds" << endl; cerr << "Options:" << endl; cerr << " Useful for setting layouts:" << endl; cerr << " --stripe_unit, -u: set the size of each stripe" << endl; cerr << " --stripe_count, -c: set the number of objects to stripe across" << endl; cerr << " --object_size, -s: set the size of the objects to stripe across" << endl; cerr << " --pool, -p: set the pool to use" << endl; cerr << endl; cerr << " Useful for getting location data:" << endl; cerr << " --offset, -l: the offset to retrieve location data for" << endl; cerr << endl; } int init_options(int argc, char **argv, int *fd, char **path, int *cmd, int *stripe_unit, int *stripe_count, int *object_size, int64_t *pool, int *file_offset, bool *dir) { // look through the options, make sure they're valid, // and set the variables from them int i = 3; struct stat stat_field; if (argc < 3) { cerr << "not enough parameters!" << endl; return 1; } *path = argv[1]; *fd = open(argv[1], O_RDONLY); if (*fd < 0) { cerr << "error opening path: " << cpp_strerror(*fd) << endl; return 1; } if (!strcmp(argv[2], "show_layout")) { *cmd = CMD_SHOW_LAYOUT; if (argc > 4) return 1; } else if (!strcmp(argv[2], "set_layout")) { *cmd = CMD_SET_LAYOUT; } else if (!strcmp(argv[2], "show_location")){ *cmd = CMD_SHOW_LOC; } else if (!strcmp(argv[2], "map")) { *cmd = CMD_MAP; } else { cerr << "invalid command" << endl; return 1; } // okay, fill in options while (i < argc) { if (i == argc-1) { // there's an option without an associated value! cerr << "not all options are paired with a value!" << endl; return 1; } if (!strcmp(argv[i], "--stripe_unit") || argv[i][1] == 'u') { if (*cmd != CMD_SET_LAYOUT) { cerr << "Invalid option for command!" << endl; return 1; } *stripe_unit = strtol(argv[i+1], NULL, 0); if (!*stripe_unit) { cerr << "invalid value for stripe unit" << endl; return 1; } } else if (!strcmp(argv[i], "--stripe_count") || argv[i][1] == 'c') { if (*cmd != CMD_SET_LAYOUT) { cerr << "Invalid option for command!" << endl; return 1; } *stripe_count = strtol(argv[i+1], NULL, 0); if (!*stripe_count) { cerr << "invalid value for stripe count" << endl; return 1; } } else if (!strcmp(argv[i], "--object_size") || argv[i][1] == 's') { if (*cmd != CMD_SET_LAYOUT) { cerr << "Invalid option for command!" << endl; return 1; } *object_size = strtol(argv[i+1], NULL, 0); if (!*object_size) { cerr << "invalid value for object size" << endl; return 1; } } else if (!strcmp(argv[i], "--pool") || argv[i][1] == 'p') { if (*cmd != CMD_SET_LAYOUT) { cerr << "Invalid option for command!" << endl; return 1; } errno = 0; *pool= strtol(argv[i+1], NULL, 0); if (!*pool && errno) { cerr << "invalid value for pool" << endl; return 1; } } else if (!strcmp(argv[i], "--offset") || argv[i][1] == 'l') { if (*cmd != CMD_SHOW_LOC) { cerr << "Invalid option for command!" << endl; return 1; } errno = 0; *file_offset = strtol(argv[i+1], NULL, 0); if (!*file_offset && errno) { cerr << "invalid value for offset" << endl; return 1; } } i += 2; } int r = fstat (*fd, &stat_field); if (r < 0) { int err = errno; cerr << "error doing stat file: " << cpp_strerror(err) << endl; return 1; } if (S_ISREG(stat_field.st_mode)) { // open read-write to set layout close(*fd); *fd = open(argv[1], O_RDWR); if (*fd < 0) { cerr << "error opening file" << endl; return 1; } } else { *dir = true; } return 0; } ceph-0.80.11/src/common/0000775000175100017510000000000012623077036016747 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/common/version.cc0000664000175100017510000000161312623076744020751 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "acconfig.h" #include "ceph_ver.h" #include "common/version.h" #include #include #define _STR(x) #x #define STRINGIFY(x) _STR(x) const char *ceph_version_to_str(void) { return CEPH_GIT_NICE_VER; } const char *git_version_to_str(void) { return STRINGIFY(CEPH_GIT_VER); } std::string const pretty_version_to_str(void) { std::ostringstream oss; oss << "ceph version " << CEPH_GIT_NICE_VER << " (" << STRINGIFY(CEPH_GIT_VER) << ")"; return oss.str(); } ceph-0.80.11/src/common/LogEntry.h0000664000175100017510000000576212623076744020702 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOGENTRY_H #define CEPH_LOGENTRY_H #include "include/types.h" #include "include/utime.h" #include "include/encoding.h" #include "msg/msg_types.h" // for entity_inst_t namespace ceph { class Formatter; } typedef enum { CLOG_DEBUG = 0, CLOG_INFO = 1, CLOG_SEC = 2, CLOG_WARN = 3, CLOG_ERROR = 4, } clog_type; /* * Given a clog log_type, return the equivalent syslog priority */ int clog_type_to_syslog_level(clog_type t); int string_to_syslog_level(string s); int string_to_syslog_facility(string s); struct LogEntryKey { entity_inst_t who; utime_t stamp; uint64_t seq; LogEntryKey() : seq(0) {} LogEntryKey(const entity_inst_t& w, utime_t t, uint64_t s) : who(w), stamp(t), seq(s) {} void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(LogEntryKey) static inline bool operator==(const LogEntryKey& l, const LogEntryKey& r) { return l.who == r.who && l.stamp == r.stamp && l.seq == r.seq; } struct LogEntry { entity_inst_t who; utime_t stamp; uint64_t seq; clog_type type; string msg; LogEntryKey key() const { return LogEntryKey(who, stamp, seq); } void log_to_syslog(string level, string facility); void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(LogEntry) struct LogSummary { version_t version; list tail; LogSummary() : version(0) {} void add(const LogEntry& e) { tail.push_back(e); while (tail.size() > 50) tail.pop_front(); } bool contains(const LogEntryKey& k) const { for (list::const_iterator p = tail.begin(); p != tail.end(); ++p) if (p->key() == k) return true; return false; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(LogSummary) inline ostream& operator<<(ostream& out, clog_type t) { switch (t) { case CLOG_DEBUG: return out << "[DBG]"; case CLOG_INFO: return out << "[INF]"; case CLOG_WARN: return out << "[WRN]"; case CLOG_ERROR: return out << "[ERR]"; case CLOG_SEC: return out << "[SEC]"; default: return out << "[???]"; } } inline ostream& operator<<(ostream& out, const LogEntry& e) { return out << e.stamp << " " << e.who << " " << e.seq << " : " << e.type << " " << e.msg; } #endif ceph-0.80.11/src/common/histogram.h0000664000175100017510000000571712623076744021134 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * Copyright 2013 Inktank */ #ifndef CEPH_HISTOGRAM_H #define CEPH_HISTOGRAM_H #include #include #include "include/encoding.h" namespace ceph { class Formatter; } /** * power of 2 histogram */ struct pow2_hist_t { // /** * histogram * * bin size is 2^index * value is count of elements that are <= the current bin but > the previous bin. */ std::vector h; private: /// expand to at least another's size void _expand_to(unsigned s) { if (s > h.size()) h.resize(s, 0); } /// drop useless trailing 0's void _contract() { unsigned p = h.size(); while (p > 0 && h[p-1] == 0) --p; h.resize(p); } public: void clear() { h.clear(); } void set_bin(int bin, int32_t count) { _expand_to(bin + 1); h[bin] = count; _contract(); } void add(int32_t v) { int bin = calc_bits_of(v); _expand_to(bin + 1); h[bin]++; _contract(); } static int calc_bits_of(int t) { int b = 0; while (t > 0) { t = t >> 1; b++; } return b; } bool operator==(const pow2_hist_t &r) const { return h == r.h; } /// get a value's position in the histogram. /// /// positions are represented as values in the range [0..1000000] /// (millionths on the unit interval). /// /// @param v [in] value (non-negative) /// @param lower [out] pointer to lower-bound (0..1000000) /// @param upper [out] pointer to the upper bound (0..1000000) int get_position_micro(int32_t v, uint64_t *lower, uint64_t *upper) { if (v < 0) return -1; unsigned bin = calc_bits_of(v); uint64_t lower_sum = 0, upper_sum = 0, total = 0; for (unsigned i=0; i 0) { *lower = lower_sum * 1000000 / total; *upper = upper_sum * 1000000 / total; } return 0; } void add(const pow2_hist_t& o) { _expand_to(o.h.size()); for (unsigned p = 0; p < o.h.size(); ++p) h[p] += o.h[p]; _contract(); } void sub(const pow2_hist_t& o) { _expand_to(o.h.size()); for (unsigned p = 0; p < o.h.size(); ++p) h[p] -= o.h[p]; _contract(); } int32_t upper_bound() const { return 1 << h.size(); } /// decay histogram by N bits (default 1, for a halflife) void decay(int bits = 1); void dump(Formatter *f) const; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); static void generate_test_instances(std::list& o); }; WRITE_CLASS_ENCODER(pow2_hist_t) #endif /* CEPH_HISTOGRAM_H */ ceph-0.80.11/src/common/utf8.c0000664000175100017510000000770312623076744020015 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/utf8.h" #include #include #define MAX_UTF8_SZ 6 #define INVALID_UTF8_CHAR 0xfffffffful static int high_bits_set(int c) { int ret = 0; while (1) { if ((c & 0x80) != 0x080) break; c <<= 1; ++ret; } return ret; } /* Encode a 31-bit UTF8 code point to 'buf'. * Assumes buf is of size MAX_UTF8_SZ * Returns -1 on failure; number of bytes in the encoded value otherwise. */ int encode_utf8(unsigned long u, unsigned char *buf) { int i; unsigned long max_val[MAX_UTF8_SZ] = { 0x0000007ful, 0x000007fful, 0x0000fffful, 0x001ffffful, 0x03fffffful, 0x7ffffffful }; static const int MAX_VAL_SZ = sizeof(max_val) / sizeof(max_val[0]); for (i = 0; i < MAX_VAL_SZ; ++i) { if (u <= max_val[i]) break; } if (i == MAX_VAL_SZ) { // This code point is too big to encode. return -1; } if (i == 0) { buf[0] = u; } else { signed int j; for (j = i; j > 0; --j) { buf[j] = 0x80 | (u & 0x3f); u >>= 6; } unsigned char mask = ~(0xFF >> (i + 1)); buf[0] = mask | u; } return i + 1; } /* * Decode a UTF8 character from an array of bytes. Return character code. * Upon error, return INVALID_UTF8_CHAR. */ unsigned long decode_utf8(unsigned char *buf, int nbytes) { unsigned long code; int i, j; if (nbytes <= 0) return INVALID_UTF8_CHAR; if (nbytes == 1) { if (buf[0] >= 0x80) return INVALID_UTF8_CHAR; return buf[0]; } i = high_bits_set(buf[0]); if (i != nbytes) return INVALID_UTF8_CHAR; code = buf[0] & (0xff >> i); for (j = 1; j < nbytes; ++j) { if ((buf[j] & 0xc0) != 0x80) return INVALID_UTF8_CHAR; code = (code << 6) | (buf[j] & 0x3f); } // Check for invalid code points if (code == 0xFFFE) return INVALID_UTF8_CHAR; if (code == 0xFFFF) return INVALID_UTF8_CHAR; if (code >= 0xD800 && code <= 0xDFFF) return INVALID_UTF8_CHAR; return code; } int check_utf8(const char *buf, int len) { unsigned char u[MAX_UTF8_SZ]; int enc_len = 0; int i = 0; while (1) { unsigned int c = buf[i]; if (i >= len || c < 0x80 || (c & 0xC0) != 0x80) { // the start of a new character. Process what we have // in the buffer. if (enc_len > 0) { int re_encoded_len; unsigned char re_encoded[MAX_UTF8_SZ]; unsigned long code = decode_utf8(u, enc_len); if (code == INVALID_UTF8_CHAR) { //printf("decoded to invalid utf8"); return i + 1; } re_encoded_len = encode_utf8(code, re_encoded); if (enc_len != re_encoded_len) { //printf("originally encoded as %d bytes, " // "but was re-encoded to %d!\n", // enc_len, re_encoded_len); return i + 1; } if (memcmp(u, re_encoded, enc_len) != 0) { //printf("re-encoded to a different " // "byte stream!"); return i + 1; } //printf("code_point %lu\n", code); } enc_len = 0; if (i >= len) break; // start collecting again? if (c >= 0x80) u[enc_len++] = c; } else { if (enc_len == MAX_UTF8_SZ) { //printf("too many enc_len in utf character!\n"); return i + 1; } //printf("continuation byte...\n"); u[enc_len++] = c; } ++i; } return 0; } int check_utf8_cstr(const char *buf) { return check_utf8(buf, strlen(buf)); } int is_control_character(int c) { return (((c != 0) && (c < 0x20)) || (c == 0x7f)); } int check_for_control_characters(const char *buf, int len) { int i; for (i = 0; i < len; ++i) { if (is_control_character((int)(unsigned char)buf[i])) { return i + 1; } } return 0; } int check_for_control_characters_cstr(const char *buf) { return check_for_control_characters(buf, strlen(buf)); } ceph-0.80.11/src/common/TextTable.cc0000664000175100017510000000413312623076744021160 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "TextTable.h" using namespace std; void TextTable::define_column(const string &heading, enum TextTable::Align hd_align, enum TextTable::Align col_align) { TextTableColumn def(heading, heading.length(), hd_align, col_align); col.push_back(def); } void TextTable::clear() { currow = curcol = 0; indent = 0; row.clear(); // reset widths to heading widths for (unsigned int i = 0; i < col.size(); i++) col[i].width = col[i].heading.size(); } /** * Pad s with space to appropriate alignment * * @param s string to pad * @param width width of field to contain padded string * @param align desired alignment (LEFT, CENTER, RIGHT) * * @return padded string */ static string pad(string s, int width, TextTable::Align align) { int lpad, rpad; lpad = rpad = 0; switch (align) { case TextTable::LEFT: rpad = width - s.length(); break; case TextTable::CENTER: lpad = width / 2 - s.length() / 2; rpad = width - lpad - s.length(); break; case TextTable::RIGHT: lpad = width - s.length(); break; } return string(lpad, ' ') + s + string(rpad, ' '); } std::ostream &operator<<(std::ostream& out, TextTable &t) { for (unsigned int i = 0; i < t.col.size(); i++) { TextTable::TextTableColumn col = t.col[i]; out << string(t.indent, ' ') << pad(col.heading, col.width, col.hd_align) << ' '; } out << endl; for (unsigned int i = 0; i < t.row.size(); i++) { for (unsigned int j = 0; j < t.row[i].size(); j++) { TextTable::TextTableColumn col = t.col[j]; out << string(t.indent, ' ') << pad(t.row[i][j], col.width, col.col_align) << ' '; } out << endl; } return out; } ceph-0.80.11/src/common/histogram.cc0000664000175100017510000000255712623076744021271 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/histogram.h" #include "common/Formatter.h" // -- pow2_hist_t -- void pow2_hist_t::dump(Formatter *f) const { f->open_array_section("histogram"); for (std::vector::const_iterator p = h.begin(); p != h.end(); ++p) f->dump_int("count", *p); f->close_section(); f->dump_int("upper_bound", upper_bound()); } void pow2_hist_t::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(h, bl); ENCODE_FINISH(bl); } void pow2_hist_t::decode(bufferlist::iterator& p) { DECODE_START(1, p); ::decode(h, p); DECODE_FINISH(p); } void pow2_hist_t::generate_test_instances(std::list& ls) { ls.push_back(new pow2_hist_t); ls.push_back(new pow2_hist_t); ls.back()->h.push_back(1); ls.back()->h.push_back(3); ls.back()->h.push_back(0); ls.back()->h.push_back(2); } void pow2_hist_t::decay(int bits) { for (std::vector::iterator p = h.begin(); p != h.end(); ++p) { *p >>= bits; } _contract(); } ceph-0.80.11/src/common/ceph_crypto.cc0000664000175100017510000000272212623076744021605 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010-2011 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/config.h" #include "common/ceph_context.h" #include "ceph_crypto.h" #include "auth/Crypto.h" #include #include #ifdef USE_CRYPTOPP void ceph::crypto::init(CephContext *cct) { } void ceph::crypto::shutdown() { } // nothing ceph::crypto::HMACSHA1::~HMACSHA1() { } #elif USE_NSS // Initialization of NSS requires a mutex due to a race condition in // NSS_NoDB_Init. static pthread_mutex_t crypto_init_mutex = PTHREAD_MUTEX_INITIALIZER; void ceph::crypto::init(CephContext *cct) { SECStatus s; pthread_mutex_lock(&crypto_init_mutex); if (cct->_conf->nss_db_path.empty()) { s = NSS_NoDB_Init(NULL); } else { s = NSS_Init(cct->_conf->nss_db_path.c_str()); } pthread_mutex_unlock(&crypto_init_mutex); assert(s == SECSuccess); } void ceph::crypto::shutdown() { SECStatus s; s = NSS_Shutdown(); assert(s == SECSuccess); } ceph::crypto::HMACSHA1::~HMACSHA1() { PK11_DestroyContext(ctx, PR_TRUE); PK11_FreeSymKey(symkey); PK11_FreeSlot(slot); } #else # error "No supported crypto implementation found." #endif ceph-0.80.11/src/common/ceph_hash.cc0000664000175100017510000000525512623076744021214 0ustar jenkins-buildjenkins-build #include "include/types.h" /* * Robert Jenkin's hash function. * http://burtleburtle.net/bob/hash/evahash.html * This is in the public domain. */ #define mix(a, b, c) \ do { \ a = a - b; a = a - c; a = a ^ (c >> 13); \ b = b - c; b = b - a; b = b ^ (a << 8); \ c = c - a; c = c - b; c = c ^ (b >> 13); \ a = a - b; a = a - c; a = a ^ (c >> 12); \ b = b - c; b = b - a; b = b ^ (a << 16); \ c = c - a; c = c - b; c = c ^ (b >> 5); \ a = a - b; a = a - c; a = a ^ (c >> 3); \ b = b - c; b = b - a; b = b ^ (a << 10); \ c = c - a; c = c - b; c = c ^ (b >> 15); \ } while (0) unsigned ceph_str_hash_rjenkins(const char *str, unsigned length) { const unsigned char *k = (const unsigned char *)str; __u32 a, b, c; /* the internal state */ __u32 len; /* how many key bytes still need mixing */ /* Set up the internal state */ len = length; a = 0x9e3779b9; /* the golden ratio; an arbitrary value */ b = a; c = 0; /* variable initialization of internal state */ /* handle most of the key */ while (len >= 12) { a = a + (k[0] + ((__u32)k[1] << 8) + ((__u32)k[2] << 16) + ((__u32)k[3] << 24)); b = b + (k[4] + ((__u32)k[5] << 8) + ((__u32)k[6] << 16) + ((__u32)k[7] << 24)); c = c + (k[8] + ((__u32)k[9] << 8) + ((__u32)k[10] << 16) + ((__u32)k[11] << 24)); mix(a, b, c); k = k + 12; len = len - 12; } /* handle the last 11 bytes */ c = c + length; switch (len) { /* all the case statements fall through */ case 11: c = c + ((__u32)k[10] << 24); case 10: c = c + ((__u32)k[9] << 16); case 9: c = c + ((__u32)k[8] << 8); /* the first byte of c is reserved for the length */ case 8: b = b + ((__u32)k[7] << 24); case 7: b = b + ((__u32)k[6] << 16); case 6: b = b + ((__u32)k[5] << 8); case 5: b = b + k[4]; case 4: a = a + ((__u32)k[3] << 24); case 3: a = a + ((__u32)k[2] << 16); case 2: a = a + ((__u32)k[1] << 8); case 1: a = a + k[0]; /* case 0: nothing left to add */ } mix(a, b, c); return c; } /* * linux dcache hash */ unsigned ceph_str_hash_linux(const char *str, unsigned length) { unsigned long hash = 0; while (length--) { unsigned char c = *str++; hash = (hash + (c << 4) + (c >> 4)) * 11; } return hash; } unsigned ceph_str_hash(int type, const char *s, unsigned len) { switch (type) { case CEPH_STR_HASH_LINUX: return ceph_str_hash_linux(s, len); case CEPH_STR_HASH_RJENKINS: return ceph_str_hash_rjenkins(s, len); default: return -1; } } const char *ceph_str_hash_name(int type) { switch (type) { case CEPH_STR_HASH_LINUX: return "linux"; case CEPH_STR_HASH_RJENKINS: return "rjenkins"; default: return "unknown"; } } ceph-0.80.11/src/common/Timer.cc0000664000175100017510000001106712623076744020350 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Cond.h" #include "Mutex.h" #include "Thread.h" #include "Timer.h" #include "common/config.h" #include "include/Context.h" #define dout_subsys ceph_subsys_timer #undef dout_prefix #define dout_prefix *_dout << "timer(" << this << ")." #include #include #include #include class SafeTimerThread : public Thread { SafeTimer *parent; public: SafeTimerThread(SafeTimer *s) : parent(s) {} void *entry() { parent->timer_thread(); return NULL; } }; typedef std::multimap < utime_t, Context *> scheduled_map_t; typedef std::map < Context*, scheduled_map_t::iterator > event_lookup_map_t; SafeTimer::SafeTimer(CephContext *cct_, Mutex &l, bool safe_callbacks) : cct(cct_), lock(l), safe_callbacks(safe_callbacks), thread(NULL), stopping(false) { } SafeTimer::~SafeTimer() { assert(thread == NULL); } void SafeTimer::init() { ldout(cct,10) << "init" << dendl; thread = new SafeTimerThread(this); thread->create(); } void SafeTimer::shutdown() { ldout(cct,10) << "shutdown" << dendl; if (thread) { assert(lock.is_locked()); cancel_all_events(); stopping = true; cond.Signal(); lock.Unlock(); thread->join(); lock.Lock(); delete thread; thread = NULL; } } void SafeTimer::timer_thread() { lock.Lock(); ldout(cct,10) << "timer_thread starting" << dendl; while (!stopping) { utime_t now = ceph_clock_now(cct); while (!schedule.empty()) { scheduled_map_t::iterator p = schedule.begin(); // is the future now? if (p->first > now) break; Context *callback = p->second; events.erase(callback); schedule.erase(p); ldout(cct,10) << "timer_thread executing " << callback << dendl; if (!safe_callbacks) lock.Unlock(); callback->complete(0); if (!safe_callbacks) lock.Lock(); } ldout(cct,20) << "timer_thread going to sleep" << dendl; if (schedule.empty()) cond.Wait(lock); else cond.WaitUntil(lock, schedule.begin()->first); ldout(cct,20) << "timer_thread awake" << dendl; } ldout(cct,10) << "timer_thread exiting" << dendl; lock.Unlock(); } void SafeTimer::add_event_after(double seconds, Context *callback) { assert(lock.is_locked()); utime_t when = ceph_clock_now(cct); when += seconds; add_event_at(when, callback); } void SafeTimer::add_event_at(utime_t when, Context *callback) { assert(lock.is_locked()); ldout(cct,10) << "add_event_at " << when << " -> " << callback << dendl; scheduled_map_t::value_type s_val(when, callback); scheduled_map_t::iterator i = schedule.insert(s_val); event_lookup_map_t::value_type e_val(callback, i); pair < event_lookup_map_t::iterator, bool > rval(events.insert(e_val)); /* If you hit this, you tried to insert the same Context* twice. */ assert(rval.second); /* If the event we have just inserted comes before everything else, we need to * adjust our timeout. */ if (i == schedule.begin()) cond.Signal(); } bool SafeTimer::cancel_event(Context *callback) { assert(lock.is_locked()); std::map::iterator>::iterator p = events.find(callback); if (p == events.end()) { ldout(cct,10) << "cancel_event " << callback << " not found" << dendl; return false; } ldout(cct,10) << "cancel_event " << p->second->first << " -> " << callback << dendl; delete p->first; schedule.erase(p->second); events.erase(p); return true; } void SafeTimer::cancel_all_events() { ldout(cct,10) << "cancel_all_events" << dendl; assert(lock.is_locked()); while (!events.empty()) { std::map::iterator>::iterator p = events.begin(); ldout(cct,10) << " cancelled " << p->second->first << " -> " << p->first << dendl; delete p->first; schedule.erase(p->second); events.erase(p); } } void SafeTimer::dump(const char *caller) const { if (!caller) caller = ""; ldout(cct,10) << "dump " << caller << dendl; for (scheduled_map_t::const_iterator s = schedule.begin(); s != schedule.end(); ++s) ldout(cct,10) << " " << s->first << "->" << s->second << dendl; } ceph-0.80.11/src/common/addr_parsing.c0000664000175100017510000000725112623076744021562 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #if defined(__FreeBSD__) #include #include #endif #include #define BUF_SIZE 128 int safe_cat(char **pstr, int *plen, int pos, const char *str2) { int len2 = strlen(str2); //printf("safe_cat '%s' max %d pos %d '%s' len %d\n", *pstr, *plen, pos, str2, len2); while (*plen < pos + len2 + 1) { *plen += BUF_SIZE; *pstr = (char *)realloc(*pstr, (size_t)*plen); if (!*pstr) { printf("Out of memory\n"); exit(1); } //printf("safe_cat '%s' max %d pos %d '%s' len %d\n", *pstr, *plen, pos, str2, len2); } strncpy((*pstr)+pos, str2, len2); (*pstr)[pos+len2] = '\0'; return pos + len2; } char *resolve_addrs(const char *orig_str) { char *new_str; char *tok, *saveptr = NULL; int len, pos; char *buf = strdup(orig_str); const char *delim = ",; "; len = BUF_SIZE; new_str = (char *)malloc(len); if (!new_str) { free(buf); return NULL; } pos = 0; tok = strtok_r(buf, delim, &saveptr); while (tok) { struct addrinfo hint; struct addrinfo *res, *ores; char *firstcolon, *lastcolon, *bracecolon; int r; int brackets = 0; firstcolon = strchr(tok, ':'); lastcolon = strrchr(tok, ':'); bracecolon = strstr(tok, "]:"); char *port_str = 0; if (firstcolon && firstcolon == lastcolon) { /* host:port or a.b.c.d:port */ *firstcolon = 0; port_str = firstcolon + 1; } else if (bracecolon) { /* [ipv6addr]:port */ port_str = bracecolon + 1; *port_str = 0; port_str++; } if (port_str && !*port_str) port_str = NULL; if (*tok == '[' && tok[strlen(tok)-1] == ']') { tok[strlen(tok)-1] = 0; tok++; brackets = 1; } //printf("name '%s' port '%s'\n", tok, port_str); memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = IPPROTO_TCP; r = getaddrinfo(tok, port_str, &hint, &res); if (r < 0) { printf("server name not found: %s (%s)\n", tok, gai_strerror(r)); free(new_str); free(buf); return 0; } /* build resolved addr list */ ores = res; while (res) { char host[40], port[40]; getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host), port, sizeof(port), NI_NUMERICSERV | NI_NUMERICHOST); /*printf(" host %s port %s flags %d family %d socktype %d proto %d sanonname %s\n", host, port, res->ai_flags, res->ai_family, res->ai_socktype, res->ai_protocol, res->ai_canonname);*/ if (res->ai_family == AF_INET6) brackets = 1; /* always surround ipv6 addrs with brackets */ if (brackets) pos = safe_cat(&new_str, &len, pos, "["); pos = safe_cat(&new_str, &len, pos, host); if (brackets) pos = safe_cat(&new_str, &len, pos, "]"); if (port_str) { pos = safe_cat(&new_str, &len, pos, ":"); pos = safe_cat(&new_str, &len, pos, port); } res = res->ai_next; if (res) pos = safe_cat(&new_str, &len, pos, ","); } freeaddrinfo(ores); tok = strtok_r(NULL, delim, &saveptr); if (tok) pos = safe_cat(&new_str, &len, pos, ","); } //printf("new_str is '%s'\n", new_str); free(buf); return new_str; } ceph-0.80.11/src/common/Finisher.cc0000664000175100017510000000410612623076744021033 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/config.h" #include "Finisher.h" #include "common/debug.h" #define dout_subsys ceph_subsys_finisher #undef dout_prefix #define dout_prefix *_dout << "finisher(" << this << ") " void Finisher::start() { finisher_thread.create(); } void Finisher::stop() { finisher_lock.Lock(); finisher_stop = true; finisher_cond.Signal(); finisher_lock.Unlock(); finisher_thread.join(); } void Finisher::wait_for_empty() { finisher_lock.Lock(); while (!finisher_queue.empty() || finisher_running) { ldout(cct, 10) << "wait_for_empty waiting" << dendl; finisher_empty_cond.Wait(finisher_lock); } ldout(cct, 10) << "wait_for_empty empty" << dendl; finisher_lock.Unlock(); } void *Finisher::finisher_thread_entry() { finisher_lock.Lock(); ldout(cct, 10) << "finisher_thread start" << dendl; while (!finisher_stop) { while (!finisher_queue.empty()) { vector ls; list > ls_rval; ls.swap(finisher_queue); ls_rval.swap(finisher_queue_rval); finisher_running = true; finisher_lock.Unlock(); ldout(cct, 10) << "finisher_thread doing " << ls << dendl; for (vector::iterator p = ls.begin(); p != ls.end(); ++p) { if (*p) { (*p)->complete(0); } else { assert(!ls_rval.empty()); Context *c = ls_rval.front().first; c->complete(ls_rval.front().second); ls_rval.pop_front(); } if (logger) logger->dec(l_finisher_queue_len); } ldout(cct, 10) << "finisher_thread done with " << ls << dendl; ls.clear(); finisher_lock.Lock(); finisher_running = false; } ldout(cct, 10) << "finisher_thread empty" << dendl; finisher_empty_cond.Signal(); if (finisher_stop) break; ldout(cct, 10) << "finisher_thread sleeping" << dendl; finisher_cond.Wait(finisher_lock); } finisher_empty_cond.Signal(); ldout(cct, 10) << "finisher_thread stop" << dendl; finisher_stop = false; finisher_lock.Unlock(); return 0; } ceph-0.80.11/src/common/armor.c0000664000175100017510000000462312623076744020245 0ustar jenkins-buildjenkins-build #if defined(__linux__) #include #else #include #endif /* * base64 encode/decode. */ const char *pem_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static int encode_bits(int c) { return pem_key[c]; } static int decode_bits(char c) { if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '+' || c == '-') return 62; if (c == '/' || c == '_') return 63; if (c == '=') return 0; /* just non-negative, please */ return -EINVAL; } static int set_str_val(char **pdst, const char *end, char c) { if (*pdst < end) { char *p = *pdst; *p = c; (*pdst)++; } else return -ERANGE; return 0; } int ceph_armor_line_break(char *dst, const char *dst_end, const char *src, const char *end, int line_width) { int olen = 0; int line = 0; #define SET_DST(c) do { \ int __ret = set_str_val(&dst, dst_end, c); \ if (__ret < 0) \ return __ret; \ } while (0); while (src < end) { unsigned char a; a = *src++; SET_DST(encode_bits(a >> 2)); if (src < end) { unsigned char b; b = *src++; SET_DST(encode_bits(((a & 3) << 4) | (b >> 4))); if (src < end) { unsigned char c; c = *src++; SET_DST(encode_bits(((b & 15) << 2) | (c >> 6))); SET_DST(encode_bits(c & 63)); } else { SET_DST(encode_bits((b & 15) << 2)); SET_DST('='); } } else { SET_DST(encode_bits(((a & 3) << 4))); SET_DST('='); SET_DST('='); } olen += 4; line += 4; if (line_width && line == line_width) { line = 0; SET_DST('\n'); olen++; } } return olen; } int ceph_armor(char *dst, const char *dst_end, const char *src, const char *end) { return ceph_armor_line_break(dst, dst_end, src, end, 0); } int ceph_unarmor(char *dst, const char *dst_end, const char *src, const char *end) { int olen = 0; while (src < end) { int a, b, c, d; if (src[0] == '\n') { src++; continue; } if (src + 4 > end) return -EINVAL; a = decode_bits(src[0]); b = decode_bits(src[1]); c = decode_bits(src[2]); d = decode_bits(src[3]); if (a < 0 || b < 0 || c < 0 || d < 0) return -EINVAL; SET_DST((a << 2) | (b >> 4)); if (src[2] == '=') return olen + 1; SET_DST(((b & 15) << 4) | (c >> 2)); if (src[3] == '=') return olen + 2; SET_DST(((c & 3) << 6) | d); olen += 3; src += 4; } return olen; } ceph-0.80.11/src/common/pipe.h0000664000175100017510000000132612623076744020064 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_PIPE_H #define CEPH_COMMON_PIPE_H #ifdef __cplusplus extern "C" { #endif /** Create a pipe and set both ends to have F_CLOEXEC * * @param pipefd pipe array, just as in pipe(2) * @return 0 on success, errno otherwise */ int pipe_cloexec(int pipefd[2]); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/common_init.cc0000664000175100017510000000720412623076744021601 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010-2011 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_argparse.h" #include "common/ceph_context.h" #include "common/ceph_crypto.h" #include "common/code_environment.h" #include "common/common_init.h" #include "common/config.h" #include "common/dout.h" #include "common/errno.h" #include "common/safe_io.h" #include "common/version.h" #include "include/color.h" #include #include #define dout_subsys ceph_subsys_ #define _STR(x) #x #define STRINGIFY(x) _STR(x) CephContext *common_preinit(const CephInitParameters &iparams, enum code_environment_t code_env, int flags) { // set code environment g_code_env = code_env; // Create a configuration object CephContext *cct = new CephContext(iparams.module_type); md_config_t *conf = cct->_conf; // add config observers here // Set up our entity name. conf->name = iparams.name; // Set some defaults based on code type switch (code_env) { case CODE_ENVIRONMENT_DAEMON: conf->set_val_or_die("daemonize", "true"); conf->set_val_or_die("log_to_stderr", "false"); conf->set_val_or_die("err_to_stderr", "true"); // different default keyring locations for osd and mds. this is // for backward compatibility. moving forward, we want all keyrings // in these locations. the mon already forces $mon_data/keyring. if (conf->name.is_mds()) conf->set_val("keyring", "$mds_data/keyring", false); else if (conf->name.is_osd()) conf->set_val("keyring", "$osd_data/keyring", false); break; case CODE_ENVIRONMENT_UTILITY_NODOUT: case CODE_ENVIRONMENT_LIBRARY: conf->set_val_or_die("log_to_stderr", "false"); conf->set_val_or_die("err_to_stderr", "false"); conf->set_val_or_die("log_flush_on_exit", "false"); break; default: break; } if (flags & CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS) { // do nothing special! we used to do no default log, pid_file, // admin_socket, but changed our minds. let's make ceph-fuse // and radosgw use the same defaults as ceph-{osd,mon,mds,...} } else if (code_env != CODE_ENVIRONMENT_DAEMON) { // no default log, pid_file, admin_socket conf->set_val_or_die("pid_file", ""); conf->set_val_or_die("admin_socket", ""); conf->set_val_or_die("log_file", ""); // use less memory for logs conf->set_val_or_die("log_max_recent", "500"); } return cct; } void complain_about_parse_errors(CephContext *cct, std::deque *parse_errors) { if (parse_errors->empty()) return; lderr(cct) << "Errors while parsing config file!" << dendl; int cur_err = 0; static const int MAX_PARSE_ERRORS = 20; for (std::deque::const_iterator p = parse_errors->begin(); p != parse_errors->end(); ++p) { lderr(cct) << *p << dendl; if (cur_err == MAX_PARSE_ERRORS) { lderr(cct) << "Suppressed " << (parse_errors->size() - MAX_PARSE_ERRORS) << " more errors." << dendl; break; } ++cur_err; } } /* Please be sure that this can safely be called multiple times by the * same application. */ void common_init_finish(CephContext *cct, int flags) { ceph::crypto::init(cct); if (!(flags & CINIT_FLAG_NO_DAEMON_ACTIONS)) cct->start_service_thread(); if (cct->_conf->lockdep) { g_lockdep = true; lockdep_register_ceph_context(cct); } } ceph-0.80.11/src/common/WorkQueue.h0000664000175100017510000002531712623076744021064 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_WORKQUEUE_H #define CEPH_WORKQUEUE_H #include "Mutex.h" #include "Cond.h" #include "Thread.h" #include "common/config_obs.h" #include "common/HeartbeatMap.h" class CephContext; class ThreadPool : public md_config_obs_t { CephContext *cct; string name; string lockname; Mutex _lock; Cond _cond; bool _stop; int _pause; int _draining; Cond _wait_cond; int ioprio_class, ioprio_priority; public: class TPHandle { friend class ThreadPool; CephContext *cct; heartbeat_handle_d *hb; time_t grace; time_t suicide_grace; TPHandle( CephContext *cct, heartbeat_handle_d *hb, time_t grace, time_t suicide_grace) : cct(cct), hb(hb), grace(grace), suicide_grace(suicide_grace) {} public: void reset_tp_timeout(); void suspend_tp_timeout(); }; private: struct WorkQueue_ { string name; time_t timeout_interval, suicide_interval; WorkQueue_(string n, time_t ti, time_t sti) : name(n), timeout_interval(ti), suicide_interval(sti) { } virtual ~WorkQueue_() {} virtual void _clear() = 0; virtual bool _empty() = 0; virtual void *_void_dequeue() = 0; virtual void _void_process(void *item, TPHandle &handle) = 0; virtual void _void_process_finish(void *) = 0; }; // track thread pool size changes unsigned _num_threads; string _thread_num_option; const char **_conf_keys; const char **get_tracked_conf_keys() const { return _conf_keys; } void handle_conf_change(const struct md_config_t *conf, const std::set &changed); public: template class BatchWorkQueue : public WorkQueue_ { ThreadPool *pool; virtual bool _enqueue(T *) = 0; virtual void _dequeue(T *) = 0; virtual void _dequeue(list *) = 0; virtual void _process(const list &) { assert(0); } virtual void _process(const list &items, TPHandle &handle) { _process(items); } virtual void _process_finish(const list &) {} void *_void_dequeue() { list *out(new list); _dequeue(out); if (!out->empty()) { return (void *)out; } else { delete out; return 0; } } void _void_process(void *p, TPHandle &handle) { _process(*((list*)p), handle); } void _void_process_finish(void *p) { _process_finish(*(list*)p); delete (list *)p; } public: BatchWorkQueue(string n, time_t ti, time_t sti, ThreadPool* p) : WorkQueue_(n, ti, sti), pool(p) { pool->add_work_queue(this); } ~BatchWorkQueue() { pool->remove_work_queue(this); } bool queue(T *item) { pool->_lock.Lock(); bool r = _enqueue(item); pool->_cond.SignalOne(); pool->_lock.Unlock(); return r; } void dequeue(T *item) { pool->_lock.Lock(); _dequeue(item); pool->_lock.Unlock(); } void clear() { pool->_lock.Lock(); _clear(); pool->_lock.Unlock(); } void lock() { pool->lock(); } void unlock() { pool->unlock(); } void wake() { pool->wake(); } void _wake() { pool->_wake(); } void drain() { pool->drain(this); } }; template class WorkQueueVal : public WorkQueue_ { Mutex _lock; ThreadPool *pool; list to_process; list to_finish; virtual void _enqueue(T) = 0; virtual void _enqueue_front(T) = 0; virtual bool _empty() = 0; virtual U _dequeue() = 0; virtual void _process(U) { assert(0); } virtual void _process(U u, TPHandle &) { _process(u); } virtual void _process_finish(U) {} void *_void_dequeue() { { Mutex::Locker l(_lock); if (_empty()) return 0; U u = _dequeue(); to_process.push_back(u); } return ((void*)1); // Not used } void _void_process(void *, TPHandle &handle) { _lock.Lock(); assert(!to_process.empty()); U u = to_process.front(); to_process.pop_front(); _lock.Unlock(); _process(u, handle); _lock.Lock(); to_finish.push_back(u); _lock.Unlock(); } void _void_process_finish(void *) { _lock.Lock(); assert(!to_finish.empty()); U u = to_finish.front(); to_finish.pop_front(); _lock.Unlock(); _process_finish(u); } void _clear() {} public: WorkQueueVal(string n, time_t ti, time_t sti, ThreadPool *p) : WorkQueue_(n, ti, sti), _lock("WorkQueueVal::lock"), pool(p) { pool->add_work_queue(this); } ~WorkQueueVal() { pool->remove_work_queue(this); } void queue(T item) { Mutex::Locker l(pool->_lock); _enqueue(item); pool->_cond.SignalOne(); } void queue_front(T item) { Mutex::Locker l(pool->_lock); _enqueue_front(item); pool->_cond.SignalOne(); } void drain() { pool->drain(this); } protected: void lock() { pool->lock(); } void unlock() { pool->unlock(); } }; template class WorkQueue : public WorkQueue_ { ThreadPool *pool; virtual bool _enqueue(T *) = 0; virtual void _dequeue(T *) = 0; virtual T *_dequeue() = 0; virtual void _process(T *t) { assert(0); } virtual void _process(T *t, TPHandle &) { _process(t); } virtual void _process_finish(T *) {} void *_void_dequeue() { return (void *)_dequeue(); } void _void_process(void *p, TPHandle &handle) { _process(static_cast(p), handle); } void _void_process_finish(void *p) { _process_finish(static_cast(p)); } public: WorkQueue(string n, time_t ti, time_t sti, ThreadPool* p) : WorkQueue_(n, ti, sti), pool(p) { pool->add_work_queue(this); } ~WorkQueue() { pool->remove_work_queue(this); } bool queue(T *item) { pool->_lock.Lock(); bool r = _enqueue(item); pool->_cond.SignalOne(); pool->_lock.Unlock(); return r; } void dequeue(T *item) { pool->_lock.Lock(); _dequeue(item); pool->_lock.Unlock(); } void clear() { pool->_lock.Lock(); _clear(); pool->_lock.Unlock(); } void lock() { pool->lock(); } void unlock() { pool->unlock(); } /// wake up the thread pool (without lock held) void wake() { pool->wake(); } /// wake up the thread pool (with lock already held) void _wake() { pool->_wake(); } void drain() { pool->drain(this); } }; private: vector work_queues; int last_work_queue; // threads struct WorkThread : public Thread { ThreadPool *pool; WorkThread(ThreadPool *p) : pool(p) {} void *entry() { pool->worker(this); return 0; } }; set _threads; list _old_threads; ///< need to be joined int processing; void start_threads(); void join_old_threads(); void worker(WorkThread *wt); public: ThreadPool(CephContext *cct_, string nm, int n, const char *option = NULL); virtual ~ThreadPool(); /// return number of threads currently running int get_num_threads() { Mutex::Locker l(_lock); return _num_threads; } /// assign a work queue to this thread pool void add_work_queue(WorkQueue_* wq) { Mutex::Locker l(_lock); work_queues.push_back(wq); } /// remove a work queue from this thread pool void remove_work_queue(WorkQueue_* wq) { Mutex::Locker l(_lock); unsigned i = 0; while (work_queues[i] != wq) i++; for (i++; i < work_queues.size(); i++) work_queues[i-1] = work_queues[i]; assert(i == work_queues.size()); work_queues.resize(i-1); } /// take thread pool lock void lock() { _lock.Lock(); } /// release thread pool lock void unlock() { _lock.Unlock(); } /// wait for a kick on this thread pool void wait(Cond &c) { c.Wait(_lock); } /// wake up a waiter (with lock already held) void _wake() { _cond.Signal(); } /// wake up a waiter (without lock held) void wake() { Mutex::Locker l(_lock); _cond.Signal(); } /// start thread pool thread void start(); /// stop thread pool thread void stop(bool clear_after=true); /// pause thread pool (if it not already paused) void pause(); /// pause initiation of new work void pause_new(); /// resume work in thread pool. must match each pause() call 1:1 to resume. void unpause(); /// wait for all work to complete void drain(WorkQueue_* wq = 0); /// set io priority void set_ioprio(int cls, int priority); }; class GenContextWQ : public ThreadPool::WorkQueueVal*> { list*> _queue; public: GenContextWQ(const string &name, time_t ti, ThreadPool *tp) : ThreadPool::WorkQueueVal< GenContext*>(name, ti, ti*10, tp) {} void _enqueue(GenContext *c) { _queue.push_back(c); }; void _enqueue_front(GenContext *c) { _queue.push_front(c); } bool _empty() { return _queue.empty(); } GenContext *_dequeue() { assert(!_queue.empty()); GenContext *c = _queue.front(); _queue.pop_front(); return c; } void _process(GenContext *c, ThreadPool::TPHandle &tp) { c->complete(tp); } }; class C_QueueInWQ : public Context { GenContextWQ *wq; GenContext *c; public: C_QueueInWQ(GenContextWQ *wq, GenContext *c) : wq(wq), c(c) {} void finish(int) { wq->queue(c); } }; class ContextWQ : public ThreadPool::WorkQueueVal { public: ContextWQ(const string &name, time_t ti, ThreadPool *tp) : ThreadPool::WorkQueueVal(name, ti, 0, tp) {} void queue(Context *ctx) { ThreadPool::WorkQueueVal::queue(ctx); } protected: virtual void _enqueue(Context *item) { _queue.push_back(item); } virtual void _enqueue_front(Context *item) { _queue.push_front(item); } virtual bool _empty() { return _queue.empty(); } virtual Context *_dequeue() { Context *item = _queue.front(); _queue.pop_front(); return item; } virtual void _process(Context *item) { item->complete(0); } private: list _queue; }; #endif ceph-0.80.11/src/common/perf_counters.cc0000664000175100017510000002141712623076744022146 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "common/perf_counters.h" #include "common/dout.h" #include "common/errno.h" #include "common/Formatter.h" #include #include #include #include #include #include using std::ostringstream; PerfCountersCollection::PerfCountersCollection(CephContext *cct) : m_cct(cct), m_lock("PerfCountersCollection") { } PerfCountersCollection::~PerfCountersCollection() { clear(); } void PerfCountersCollection::add(class PerfCounters *l) { Mutex::Locker lck(m_lock); // make sure the name is unique perf_counters_set_t::iterator i; i = m_loggers.find(l); while (i != m_loggers.end()) { ostringstream ss; ss << l->get_name() << "-" << (void*)l; l->set_name(ss.str()); i = m_loggers.find(l); } m_loggers.insert(l); } void PerfCountersCollection::remove(class PerfCounters *l) { Mutex::Locker lck(m_lock); perf_counters_set_t::iterator i = m_loggers.find(l); assert(i != m_loggers.end()); m_loggers.erase(i); } void PerfCountersCollection::clear() { Mutex::Locker lck(m_lock); perf_counters_set_t::iterator i = m_loggers.begin(); perf_counters_set_t::iterator i_end = m_loggers.end(); for (; i != i_end; ) { m_loggers.erase(i++); } } void PerfCountersCollection::dump_formatted(Formatter *f, bool schema) { Mutex::Locker lck(m_lock); f->open_object_section("perfcounter_collection"); perf_counters_set_t::iterator l = m_loggers.begin(); perf_counters_set_t::iterator l_end = m_loggers.end(); if (l != l_end) { while (true) { (*l)->dump_formatted(f, schema); if (++l == l_end) break; } } f->close_section(); } // --------------------------- PerfCounters::~PerfCounters() { } void PerfCounters::inc(int idx, uint64_t amt) { if (!m_cct->_conf->perf) return; Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_U64)) return; data.u64 += amt; if (data.type & PERFCOUNTER_LONGRUNAVG) data.avgcount++; } void PerfCounters::dec(int idx, uint64_t amt) { if (!m_cct->_conf->perf) return; Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); assert(!(data.type & PERFCOUNTER_LONGRUNAVG)); if (!(data.type & PERFCOUNTER_U64)) return; assert(data.u64 >= amt); data.u64 -= amt; } void PerfCounters::set(int idx, uint64_t amt) { if (!m_cct->_conf->perf) return; Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_U64)) return; data.u64 = amt; if (data.type & PERFCOUNTER_LONGRUNAVG) data.avgcount++; } uint64_t PerfCounters::get(int idx) const { if (!m_cct->_conf->perf) return 0; Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_U64)) return 0; return data.u64; } void PerfCounters::tinc(int idx, utime_t amt) { if (!m_cct->_conf->perf) return; Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_TIME)) return; data.u64 += amt.to_nsec(); if (data.type & PERFCOUNTER_LONGRUNAVG) data.avgcount++; } void PerfCounters::tset(int idx, utime_t amt) { if (!m_cct->_conf->perf) return; Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_TIME)) return; data.u64 = amt.to_nsec(); if (data.type & PERFCOUNTER_LONGRUNAVG) assert(0); } utime_t PerfCounters::tget(int idx) const { if (!m_cct->_conf->perf) return utime_t(); Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_TIME)) return utime_t(); return utime_t(data.u64 / 1000000000ull, data.u64 % 1000000000ull); } pair PerfCounters::get_tavg_ms(int idx) const { if (!m_cct->_conf->perf) return make_pair(0, 0); Mutex::Locker lck(m_lock); assert(idx > m_lower_bound); assert(idx < m_upper_bound); const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); if (!(data.type & PERFCOUNTER_TIME)) return make_pair(0, 0); if (!(data.type & PERFCOUNTER_LONGRUNAVG)) return make_pair(0, 0); return make_pair(data.avgcount, data.u64/1000000); } void PerfCounters::dump_formatted(Formatter *f, bool schema) { Mutex::Locker lck(m_lock); f->open_object_section(m_name.c_str()); perf_counter_data_vec_t::const_iterator d = m_data.begin(); perf_counter_data_vec_t::const_iterator d_end = m_data.end(); if (d == d_end) { f->close_section(); return; } while (true) { if (schema) { f->open_object_section(d->name); f->dump_int("type", d->type); f->close_section(); } else { if (d->type & PERFCOUNTER_LONGRUNAVG) { f->open_object_section(d->name); if (d->type & PERFCOUNTER_U64) { f->dump_unsigned("avgcount", d->avgcount); f->dump_unsigned("sum", d->u64); } else if (d->type & PERFCOUNTER_TIME) { f->dump_unsigned("avgcount", d->avgcount); f->dump_format_unquoted("sum", "%"PRId64".%09"PRId64, d->u64 / 1000000000ull, d->u64 % 1000000000ull); } else { assert(0); } f->close_section(); } else { if (d->type & PERFCOUNTER_U64) { f->dump_unsigned(d->name, d->u64); } else if (d->type & PERFCOUNTER_TIME) { f->dump_format_unquoted(d->name, "%"PRId64".%09"PRId64, d->u64 / 1000000000ull, d->u64 % 1000000000ull); } else { assert(0); } } } if (++d == d_end) break; } f->close_section(); } const std::string &PerfCounters::get_name() const { return m_name; } PerfCounters::PerfCounters(CephContext *cct, const std::string &name, int lower_bound, int upper_bound) : m_cct(cct), m_lower_bound(lower_bound), m_upper_bound(upper_bound), m_name(name.c_str()), m_lock_name(std::string("PerfCounters::") + name.c_str()), m_lock(m_lock_name.c_str()) { m_data.resize(upper_bound - lower_bound - 1); } PerfCounters::perf_counter_data_any_d::perf_counter_data_any_d() : name(NULL), type(PERFCOUNTER_NONE), u64(0), avgcount(0) { } PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name, int first, int last) : m_perf_counters(new PerfCounters(cct, name, first, last)) { } PerfCountersBuilder::~PerfCountersBuilder() { if (m_perf_counters) delete m_perf_counters; m_perf_counters = NULL; } void PerfCountersBuilder::add_u64_counter(int idx, const char *name) { add_impl(idx, name, PERFCOUNTER_U64 | PERFCOUNTER_COUNTER); } void PerfCountersBuilder::add_u64(int idx, const char *name) { add_impl(idx, name, PERFCOUNTER_U64); } void PerfCountersBuilder::add_u64_avg(int idx, const char *name) { add_impl(idx, name, PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG); } void PerfCountersBuilder::add_time(int idx, const char *name) { add_impl(idx, name, PERFCOUNTER_TIME); } void PerfCountersBuilder::add_time_avg(int idx, const char *name) { add_impl(idx, name, PERFCOUNTER_TIME | PERFCOUNTER_LONGRUNAVG); } void PerfCountersBuilder::add_impl(int idx, const char *name, int ty) { assert(idx > m_perf_counters->m_lower_bound); assert(idx < m_perf_counters->m_upper_bound); PerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data); PerfCounters::perf_counter_data_any_d &data(vec[idx - m_perf_counters->m_lower_bound - 1]); assert(data.type == PERFCOUNTER_NONE); data.name = name; data.type = (enum perfcounter_type_d)ty; } PerfCounters *PerfCountersBuilder::create_perf_counters() { PerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin(); PerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end(); for (; d != d_end; ++d) { if (d->type == PERFCOUNTER_NONE) { assert(d->type != PERFCOUNTER_NONE); } } PerfCounters *ret = m_perf_counters; m_perf_counters = NULL; return ret; } ceph-0.80.11/src/common/ceph_fs.cc0000664000175100017510000000322112623076744020670 0ustar jenkins-buildjenkins-build/* * ceph_fs.cc - Some Ceph functions that are shared between kernel space and * user space. * */ #include /* * Some non-inline ceph helpers */ #include "include/types.h" /* * return true if @layout appears to be valid */ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout) { __u32 su = le32_to_cpu(layout->fl_stripe_unit); __u32 sc = le32_to_cpu(layout->fl_stripe_count); __u32 os = le32_to_cpu(layout->fl_object_size); /* stripe unit, object size must be non-zero, 64k increment */ if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1))) return 0; if (!os || (os & (CEPH_MIN_STRIPE_UNIT-1))) return 0; /* object size must be a multiple of stripe unit */ if (os < su || os % su) return 0; /* stripe count must be non-zero */ if (!sc) return 0; return 1; } int ceph_flags_to_mode(int flags) { int mode = 0; #ifdef O_DIRECTORY /* fixme */ if ((flags & O_DIRECTORY) == O_DIRECTORY) return CEPH_FILE_MODE_PIN; #endif switch (flags & O_ACCMODE) { case O_WRONLY: mode = CEPH_FILE_MODE_WR; break; case O_RDONLY: mode = CEPH_FILE_MODE_RD; break; case O_RDWR: case O_ACCMODE: /* this is what the VFS does */ mode = CEPH_FILE_MODE_RDWR; break; } return mode; } int ceph_caps_for_mode(int mode) { int caps = CEPH_CAP_PIN; if (mode & CEPH_FILE_MODE_RD) caps |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE; if (mode & CEPH_FILE_MODE_WR) caps |= CEPH_CAP_FILE_EXCL | CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL | CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL; if (mode & CEPH_FILE_MODE_LAZY) caps |= CEPH_CAP_FILE_LAZYIO; return caps; } ceph-0.80.11/src/common/secret.c0000664000175100017510000000603212623076744020406 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include #include "common/armor.h" #include "common/safe_io.h" int read_secret_from_file(const char *filename, char *secret, size_t max_len) { char *end; int fd; int len; fd = open(filename, O_RDONLY); if (fd < 0) { perror("unable to read secretfile"); return -1; } len = safe_read(fd, secret, max_len); if (len <= 0) { perror("unable to read secret from file"); close(fd); return -1; } end = secret; while (end < secret + len && *end && *end != '\n' && *end != '\r') end++; *end = '\0'; close(fd); return 0; } int set_kernel_secret(const char *secret, const char *key_name) { /* try to submit key to kernel via the keys api */ key_serial_t serial; int ret; int secret_len = strlen(secret); char payload[((secret_len * 3) / 4) + 4]; if (!secret_len) { fprintf(stderr, "secret is empty.\n"); return -EINVAL; } ret = ceph_unarmor(payload, payload+sizeof(payload), secret, secret+secret_len); if (ret < 0) { char error_buf[80]; fprintf(stderr, "secret is not valid base64: %s.\n", strerror_r(-ret, error_buf, sizeof(error_buf))); return ret; } serial = add_key("ceph", key_name, payload, sizeof(payload), KEY_SPEC_PROCESS_KEYRING); if (serial == -1) { ret = -errno; } return ret; } int is_kernel_secret(const char *key_name) { key_serial_t serial; serial = request_key("ceph", key_name, NULL, KEY_SPEC_USER_KEYRING); return serial != -1; } int get_secret_option(const char *secret, const char *key_name, char *secret_option, size_t max_len) { if (!key_name) { return -EINVAL; } int ret = 0; int olen = strlen(key_name) + 7; if (secret) { olen += strlen(secret); } char option[olen+1]; int use_key = 1; option[olen] = '\0'; if (secret) { ret = set_kernel_secret(secret, key_name); if (ret < 0) { if (ret == -ENODEV || ret == -ENOSYS) { /* running against older kernel; fall back to secret= in options */ snprintf(option, olen, "secret=%s", secret); ret = 0; use_key = 0; } else { char error_buf[80]; fprintf(stderr, "adding ceph secret key to kernel failed: %s.\n", strerror_r(-ret, error_buf, sizeof(error_buf))); return ret; } } } if (use_key) { /* add key= option to identify key to use */ snprintf(option, olen, "key=%s", key_name); } if (strlen(option) + 1 > max_len) { ret = -ERANGE; } else { secret_option[max_len-1] = '\0'; strncpy(secret_option, option, max_len-1); } return ret; } ceph-0.80.11/src/common/MemoryModel.h0000664000175100017510000000206312623076744021357 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MEMORYMODEL_H #define CEPH_MEMORYMODEL_H class CephContext; class MemoryModel { public: struct snap { int peak; int size; int hwm; int rss; int data; int lib; int heap, malloc, mmap; snap() : peak(0), size(0), hwm(0), rss(0), data(0), lib(0), heap(0), malloc(0), mmap(0) {} int get_total() { return size; } int get_rss() { return rss; } int get_heap() { return heap; } } last; private: CephContext *cct; void _sample(snap *p); public: MemoryModel(CephContext *cct); void sample(snap *p = 0) { _sample(&last); if (p) *p = last; } }; #endif ceph-0.80.11/src/common/cmdparse.cc0000664000175100017510000001471212623076744021066 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "common/cmdparse.h" #include "include/str_list.h" #include "json_spirit/json_spirit.h" #include "common/debug.h" using namespace std; /** * Read a command description list out of cmd, and dump it to f. * A signature description is a set of space-separated words; * see MonCommands.h for more info. */ void dump_cmd_to_json(Formatter *f, const string& cmd) { // put whole command signature in an already-opened container // elements are: "name", meaning "the typeless name that means a literal" // an object {} with key:value pairs representing an argument int argnum = 0; stringstream ss(cmd); std::string word; while (std::getline(ss, word, ' ')) { argnum++; // if no , or =, must be a plain word to put out if (word.find_first_of(",=") == string::npos) { f->dump_string("arg", word); continue; } // Snarf up all the key=val,key=val pairs, put 'em in a dict. // no '=val' implies '=True'. std::stringstream argdesc(word); std::string keyval; std::mapdesckv; // accumulate descriptor keywords in desckv while (std::getline(argdesc, keyval, ',')) { // key=value; key by itself implies value is bool true // name="name" means arg dict will be titled 'name' size_t pos = keyval.find('='); std::string key, val; if (pos != std::string::npos) { key = keyval.substr(0, pos); val = keyval.substr(pos+1); } else { key = keyval; val = true; } desckv.insert(std::pair (key, val)); } // name the individual desc object based on the name key f->open_object_section(desckv["name"].c_str()); // dump all the keys including name into the array for (std::map::iterator it = desckv.begin(); it != desckv.end(); ++it) { f->dump_string(it->first.c_str(), it->second); } f->close_section(); // attribute object for individual desc } } void dump_cmd_and_help_to_json(Formatter *jf, const string& secname, const string& cmdsig, const string& helptext) { jf->open_object_section(secname.c_str()); jf->open_array_section("sig"); dump_cmd_to_json(jf, cmdsig); jf->close_section(); // sig array jf->dump_string("help", helptext.c_str()); jf->close_section(); // cmd } void dump_cmddesc_to_json(Formatter *jf, const string& secname, const string& cmdsig, const string& helptext, const string& module, const string& perm, const string& avail) { jf->open_object_section(secname.c_str()); jf->open_array_section("sig"); dump_cmd_to_json(jf, cmdsig); jf->close_section(); // sig array jf->dump_string("help", helptext.c_str()); jf->dump_string("module", module.c_str()); jf->dump_string("perm", perm.c_str()); jf->dump_string("avail", avail.c_str()); jf->close_section(); // cmd } /** Parse JSON in vector cmd into a map from field to map of values * (use mValue/mObject) * 'cmd' should not disappear over lifetime of map * 'mapp' points to the caller's map * 'ss' captures any errors during JSON parsing; if function returns * false, ss is valid */ bool cmdmap_from_json(vector cmd, map *mapp, stringstream &ss) { json_spirit::mValue v; string fullcmd; // First, join all cmd strings for (vector::iterator it = cmd.begin(); it != cmd.end(); ++it) fullcmd += *it; try { if (!json_spirit::read(fullcmd, v)) throw runtime_error("unparseable JSON " + fullcmd); if (v.type() != json_spirit::obj_type) throw(runtime_error("not JSON object " + fullcmd)); // allocate new mObject (map) to return // make sure all contents are simple types (not arrays or objects) json_spirit::mObject o = v.get_obj(); for (map::iterator it = o.begin(); it != o.end(); ++it) { // ok, marshal it into our string->cmd_vartype map, or throw an // exception if it's not a simple datatype. This is kind of // annoying, since json_spirit has a boost::variant inside it // already, but it's not public. Oh well. switch (it->second.type()) { case json_spirit::obj_type: default: throw(runtime_error("JSON array/object not allowed " + fullcmd)); break; case json_spirit::array_type: { // array is a vector of values. Unpack it to a vector // of strings, the only type we handle. vector spvals = it->second.get_array(); vector outv; for (vector::iterator sv = spvals.begin(); sv != spvals.end(); ++sv) { if (sv->type() != json_spirit::str_type) throw(runtime_error("Can't handle arrays of non-strings")); outv.push_back(sv->get_str()); } (*mapp)[it->first] = outv; } break; case json_spirit::str_type: (*mapp)[it->first] = it->second.get_str(); break; case json_spirit::bool_type: (*mapp)[it->first] = it->second.get_bool(); break; case json_spirit::int_type: (*mapp)[it->first] = it->second.get_int64(); break; case json_spirit::real_type: (*mapp)[it->first] = it->second.get_real(); break; } } return true; } catch (runtime_error &e) { ss << e.what(); return false; } } class stringify_visitor : public boost::static_visitor { public: template string operator()(T &operand) const { ostringstream oss; oss << operand; return oss.str(); } }; string cmd_vartype_stringify(const cmd_vartype &v) { return boost::apply_visitor(stringify_visitor(), v); } void handle_bad_get(CephContext *cct, string k, const char *tname) { ostringstream errstr; int status; const char *typestr = abi::__cxa_demangle(tname, 0, 0, &status); if (status != 0) typestr = tname; errstr << "bad boost::get: key " << k << " is not type " << typestr; lderr(cct) << errstr.str() << dendl; BackTrace bt(1); ostringstream oss; bt.print(oss); lderr(cct) << oss << dendl; if (status == 0) free((char *)typestr); } ceph-0.80.11/src/common/page.cc0000664000175100017510000000053412623076744020201 0ustar jenkins-buildjenkins-build#include namespace ceph { // page size crap, see page.h int _get_bits_of(int v) { int n = 0; while (v) { n++; v = v >> 1; } return n; } unsigned _page_size = sysconf(_SC_PAGESIZE); unsigned long _page_mask = ~(unsigned long)(_page_size - 1); unsigned _page_shift = _get_bits_of(_page_size); } ceph-0.80.11/src/common/simple_spin.cc0000664000175100017510000000170012623076744021603 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/simple_spin.h" #include #include #include static uint32_t bar = 13; static uint32_t *foo = &bar; void simple_spin_lock(simple_spinlock_t *lock) { while(1) { __sync_synchronize(); uint32_t oldval = *lock; if (oldval == 0) { if (__sync_bool_compare_and_swap(lock, 0, 1)) return; } // delay for (int i = 0; i < 100000; i++) { *foo = (*foo * 33) + 17; } } } void simple_spin_unlock(simple_spinlock_t *lock) { __sync_bool_compare_and_swap(lock, 1, 0); } ceph-0.80.11/src/common/util.cc0000664000175100017510000000523312623076744020243 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "include/util.h" #include "common/errno.h" #include "common/strtol.h" #ifdef HAVE_SYS_VFS_H #include #endif // test if an entire buf is zero in 8-byte chunks bool buf_is_zero(const char *buf, size_t len) { size_t ofs; int chunk = sizeof(uint64_t); for (ofs = 0; ofs < len; ofs += sizeof(uint64_t)) { if (*(uint64_t *)(buf + ofs) != 0) { return false; } } for (ofs = (len / chunk) * chunk; ofs < len; ofs++) { if (buf[ofs] != '\0') { return false; } } return true; } int64_t unit_to_bytesize(string val, ostream *pss) { if (val.empty()) { if (pss) *pss << "value is empty!"; return -EINVAL; } char c = val[val.length()-1]; int modifier = 0; if (!::isdigit(c)) { if (val.length() < 2) { if (pss) *pss << "invalid value: " << val; return -EINVAL; } val = val.substr(0,val.length()-1); switch (c) { case 'B': break; case 'k': case 'K': modifier = 10; break; case 'M': modifier = 20; break; case 'G': modifier = 30; break; case 'T': modifier = 40; break; case 'P': modifier = 50; break; case 'E': modifier = 60; break; default: if (pss) *pss << "unrecognized modifier '" << c << "'" << std::endl; return -EINVAL; } } if (val[0] == '+' || val[0] == '-') { if (pss) *pss << "expected numerical value, got: " << val; return -EINVAL; } string err; int64_t r = strict_strtoll(val.c_str(), 10, &err); if ((r == 0) && !err.empty()) { if (pss) *pss << err; return -1; } if (r < 0) { if (pss) *pss << "unable to parse positive integer '" << val << "'"; return -1; } return (r * (1LL << modifier)); } int get_fs_stats(ceph_data_stats_t &stats, const char *path) { if (!path) return -EINVAL; struct statfs stbuf; int err = ::statfs(path, &stbuf); if (err < 0) { return -errno; } stats.byte_total = stbuf.f_blocks * stbuf.f_bsize; stats.byte_used = (stbuf.f_blocks - stbuf.f_bfree) * stbuf.f_bsize; stats.byte_avail = stbuf.f_bavail * stbuf.f_bsize; stats.avail_percent = (((float)stats.byte_avail/stats.byte_total)*100); return 0; } ceph-0.80.11/src/common/common_init.h0000664000175100017510000000501712623076744021443 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_INIT_H #define CEPH_COMMON_INIT_H #include #include #include #include #include "common/code_environment.h" class CephContext; class CephInitParameters; enum common_init_flags_t { // Set up defaults that make sense for an unprivileged deamon CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS = 0x1, // By default, don't read a configuration file CINIT_FLAG_NO_DEFAULT_CONFIG_FILE = 0x2, // Don't close stderr (in daemonize) CINIT_FLAG_NO_CLOSE_STDERR = 0x4, // don't do anything daemonish, like create /var/run/ceph, or print a banner CINIT_FLAG_NO_DAEMON_ACTIONS = 0x8, }; /* * NOTE: If you are writing a Ceph daemon, ignore this function and call * global_init instead. It will call common_preinit for you. * * common_preinit creates the CephContext. * * After this function gives you a CephContext, you need to set up the * Ceph configuration, which lives inside the CephContext as md_config_t. * The initial settings are not very useful because they do not reflect what * the user asked for. * * This is usually done by something like this: * cct->_conf->parse_env(); * cct->_conf->apply_changes(); * * Your library may also supply functions to read a configuration file. */ CephContext *common_preinit(const CephInitParameters &iparams, enum code_environment_t code_env, int flags); /* Print out some parse errors. */ void complain_about_parse_errors(CephContext *cct, std::deque *parse_errors); /* This function is called after you have done your last * fork. When you make this call, the system will initialize everything that * cannot be initialized before a fork. * * This includes things like starting threads, initializing libraries that * can't handle forking, and so forth. * * If you are writing a Ceph library, you can call this pretty much any time. * We do not allow our library users to fork and continue using the Ceph * libraries. The most obvious reason for this is that the threads started by * the Ceph libraries would be destroyed by a fork(). */ void common_init_finish(CephContext *cct, int flags = 0); #endif ceph-0.80.11/src/common/SimpleRNG.h0000664000175100017510000000102712623076744020725 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef __CEPH_COMMON_SIMPLERNG_H_ #define __CEPH_COMMON_SIMPLERNG_H_ /* * rand() is not thread-safe. random_r family segfaults. * boost::random::* have build issues. */ class SimpleRNG { unsigned m_z, m_w; public: SimpleRNG(int seed) : m_z(seed), m_w(123) {} unsigned operator()() { m_z = 36969 * (m_z & 65535) + (m_z >> 16); m_w = 18000 * (m_w & 65535) + (m_w >> 16); return (m_z << 16) + m_w; } }; #endif ceph-0.80.11/src/common/blkdev.cc0000664000175100017510000000225612623076744020537 0ustar jenkins-buildjenkins-build#include #include #include #include "include/int_types.h" #ifdef __linux__ #include int get_block_device_size(int fd, int64_t *psize) { #ifdef BLKGETSIZE64 int ret = ::ioctl(fd, BLKGETSIZE64, psize); #elif defined(BLKGETSIZE) unsigned long sectors = 0; int ret = ::ioctl(fd, BLKGETSIZE, §ors); *psize = sectors * 512ULL; #else # error "Linux configuration error (get_block_device_size)" #endif if (ret < 0) ret = -errno; return ret; } #elif defined(__APPLE__) #include int get_block_device_size(int fd, int64_t *psize) { unsigned long blocksize = 0; int ret = ::ioctl(fd, DKIOCGETBLOCKSIZE, &blocksize); if (!ret) { unsigned long nblocks; ret = ::ioctl(fd, DKIOCGETBLOCKCOUNT, &nblocks); if (!ret) *psize = (int64_t)nblocks * blocksize; } if (ret < 0) ret = -errno; return ret; } #elif defined(__FreeBSD__) #include int get_block_device_size(int fd, int64_t *psize) { int ret = ::ioctl(fd, DIOCGMEDIASIZE, psize); if (ret < 0) ret = -errno; return ret; } #else # error "Unable to query block device size: unsupported platform, please report." #endif ceph-0.80.11/src/common/environment.cc0000664000175100017510000000165612623076744021637 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/environment.h" #include #include bool get_env_bool(const char *key) { const char *val = getenv(key); if (!val) return false; if (strcasecmp(val, "off") == 0) return false; if (strcasecmp(val, "no") == 0) return false; if (strcasecmp(val, "false") == 0) return false; if (strcasecmp(val, "0") == 0) return false; return true; } int get_env_int(const char *key) { const char *val = getenv(key); if (!val) return 0; int v = atoi(val); return v; } ceph-0.80.11/src/common/lockdep.cc0000664000175100017510000001642612623076744020715 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2008-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "BackTrace.h" #include "Clock.h" #include "common/dout.h" #include "common/environment.h" #include "include/types.h" #include "lockdep.h" #include "include/unordered_map.h" #include "include/hash_namespace.h" #if defined(__FreeBSD__) && defined(__LP64__) // On FreeBSD pthread_t is a pointer. CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(pthread_t __x) const { return (uintptr_t)__x; } }; CEPH_HASH_NAMESPACE_END #endif /******* Constants **********/ #undef DOUT_COND #define DOUT_COND(cct, l) cct && l <= XDOUT_CONDVAR(cct, dout_subsys) #define lockdep_dout(v) lsubdout(g_lockdep_ceph_ctx, lockdep, v) #define MAX_LOCKS 1000 // increase me as needed #define BACKTRACE_SKIP 2 /******* Globals **********/ int g_lockdep = get_env_int("CEPH_LOCKDEP"); struct lockdep_stopper_t { // disable lockdep when this module destructs. ~lockdep_stopper_t() { g_lockdep = 0; } }; static pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER; static CephContext *g_lockdep_ceph_ctx = NULL; static lockdep_stopper_t lockdep_stopper; static ceph::unordered_map lock_ids; static map lock_names; static int last_id = 0; static ceph::unordered_map > held; static BackTrace *follows[MAX_LOCKS][MAX_LOCKS]; // follows[a][b] means b taken after a /******* Functions **********/ void lockdep_register_ceph_context(CephContext *cct) { pthread_mutex_lock(&lockdep_mutex); if (g_lockdep_ceph_ctx == NULL) { g_lockdep_ceph_ctx = cct; lockdep_dout(0) << "lockdep start" << dendl; } pthread_mutex_unlock(&lockdep_mutex); } void lockdep_unregister_ceph_context(CephContext *cct) { pthread_mutex_lock(&lockdep_mutex); if (cct == g_lockdep_ceph_ctx) { lockdep_dout(0) << "lockdep stop" << dendl; // this cct is going away; shut it down! g_lockdep = false; g_lockdep_ceph_ctx = NULL; // blow away all of our state, too, in case it starts up again. held.clear(); for (unsigned i = 0; i < MAX_LOCKS; ++i) for (unsigned j = 0; j < MAX_LOCKS; ++j) follows[i][j] = NULL; lock_names.clear(); lock_ids.clear(); last_id = 0; } pthread_mutex_unlock(&lockdep_mutex); } int lockdep_dump_locks() { pthread_mutex_lock(&lockdep_mutex); for (ceph::unordered_map >::iterator p = held.begin(); p != held.end(); ++p) { lockdep_dout(0) << "--- thread " << p->first << " ---" << dendl; for (map::iterator q = p->second.begin(); q != p->second.end(); ++q) { lockdep_dout(0) << " * " << lock_names[q->first] << "\n"; if (q->second) q->second->print(*_dout); *_dout << dendl; } } pthread_mutex_unlock(&lockdep_mutex); return 0; } int lockdep_register(const char *name) { int id; pthread_mutex_lock(&lockdep_mutex); if (last_id == 0) for (int i=0; i::iterator p = lock_ids.find(name); if (p == lock_ids.end()) { assert(last_id < MAX_LOCKS); id = last_id++; lock_ids[name] = id; lock_names[id] = name; lockdep_dout(10) << "registered '" << name << "' as " << id << dendl; } else { id = p->second; lockdep_dout(20) << "had '" << name << "' as " << id << dendl; } pthread_mutex_unlock(&lockdep_mutex); return id; } // does a follow b? static bool does_follow(int a, int b) { if (follows[a][b]) { lockdep_dout(0) << "\n"; *_dout << "------------------------------------" << "\n"; *_dout << "existing dependency " << lock_names[a] << " (" << a << ") -> " << lock_names[b] << " (" << b << ") at:\n"; follows[a][b]->print(*_dout); *_dout << dendl; return true; } for (int i=0; i " << lock_names[i] << " (" << i << ") at:\n"; follows[a][i]->print(*_dout); *_dout << dendl; return true; } } return false; } int lockdep_will_lock(const char *name, int id) { pthread_t p = pthread_self(); if (id < 0) id = lockdep_register(name); pthread_mutex_lock(&lockdep_mutex); lockdep_dout(20) << "_will_lock " << name << " (" << id << ")" << dendl; // check dependency graph map &m = held[p]; for (map::iterator p = m.begin(); p != m.end(); ++p) { if (p->first == id) { lockdep_dout(0) << "\n"; *_dout << "recursive lock of " << name << " (" << id << ")\n"; BackTrace *bt = new BackTrace(BACKTRACE_SKIP); bt->print(*_dout); if (p->second) { *_dout << "\npreviously locked at\n"; p->second->print(*_dout); } delete bt; *_dout << dendl; assert(0); } else if (!follows[p->first][id]) { // new dependency // did we just create a cycle? BackTrace *bt = new BackTrace(BACKTRACE_SKIP); if (does_follow(id, p->first)) { lockdep_dout(0) << "new dependency " << lock_names[p->first] << " (" << p->first << ") -> " << name << " (" << id << ")" << " creates a cycle at\n"; bt->print(*_dout); *_dout << dendl; lockdep_dout(0) << "btw, i am holding these locks:" << dendl; for (map::iterator q = m.begin(); q != m.end(); ++q) { lockdep_dout(0) << " " << lock_names[q->first] << " (" << q->first << ")" << dendl; if (q->second) { lockdep_dout(0) << " "; q->second->print(*_dout); *_dout << dendl; } } lockdep_dout(0) << "\n" << dendl; // don't add this dependency, or we'll get aMutex. cycle in the graph, and // does_follow() won't terminate. assert(0); // actually, we should just die here. } else { follows[p->first][id] = bt; lockdep_dout(10) << lock_names[p->first] << " -> " << name << " at" << dendl; //bt->print(*_dout); } } } pthread_mutex_unlock(&lockdep_mutex); return id; } int lockdep_locked(const char *name, int id, bool force_backtrace) { pthread_t p = pthread_self(); if (id < 0) id = lockdep_register(name); pthread_mutex_lock(&lockdep_mutex); lockdep_dout(20) << "_locked " << name << dendl; if (g_lockdep >= 2 || force_backtrace) held[p][id] = new BackTrace(BACKTRACE_SKIP); else held[p][id] = 0; pthread_mutex_unlock(&lockdep_mutex); return id; } int lockdep_will_unlock(const char *name, int id) { pthread_t p = pthread_self(); if (id < 0) { //id = lockdep_register(name); assert(id == -1); return id; } pthread_mutex_lock(&lockdep_mutex); lockdep_dout(20) << "_will_unlock " << name << dendl; // don't assert.. lockdep may be enabled at any point in time //assert(held.count(p)); //assert(held[p].count(id)); delete held[p][id]; held[p].erase(id); pthread_mutex_unlock(&lockdep_mutex); return id; } ceph-0.80.11/src/common/LogClient.h0000664000175100017510000000450712623076744021013 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOGCLIENT_H #define CEPH_LOGCLIENT_H #include "common/LogEntry.h" #include "common/Mutex.h" #include #include class LogClient; class MLog; class MLogAck; class Messenger; class MonMap; class Message; struct Connection; class LogClientTemp { public: LogClientTemp(clog_type type_, LogClient &parent_); LogClientTemp(const LogClientTemp &rhs); ~LogClientTemp(); template std::ostream& operator<<(const T& rhs) { return ss << rhs; } private: clog_type type; LogClient &parent; stringstream ss; }; class LogClient { public: enum logclient_flag_t { NO_FLAGS = 0, FLAG_MON = 0x1, }; LogClient(CephContext *cct, Messenger *m, MonMap *mm, enum logclient_flag_t flags); void handle_log_ack(MLogAck *m); LogClientTemp debug() { return LogClientTemp(CLOG_DEBUG, *this); } void debug(std::stringstream &s) { do_log(CLOG_DEBUG, s); } LogClientTemp info() { return LogClientTemp(CLOG_INFO, *this); } void info(std::stringstream &s) { do_log(CLOG_INFO, s); } LogClientTemp warn() { return LogClientTemp(CLOG_WARN, *this); } void warn(std::stringstream &s) { do_log(CLOG_WARN, s); } LogClientTemp error() { return LogClientTemp(CLOG_ERROR, *this); } void error(std::stringstream &s) { do_log(CLOG_ERROR, s); } LogClientTemp sec() { return LogClientTemp(CLOG_SEC, *this); } void sec(std::stringstream &s) { do_log(CLOG_SEC, s); } void reset_session(); Message *get_mon_log_message(); bool are_pending(); private: void do_log(clog_type type, std::stringstream& ss); void do_log(clog_type type, const std::string& s); Message *_get_mon_log_message(); CephContext *cct; Messenger *messenger; MonMap *monmap; bool is_mon; Mutex log_lock; version_t last_log_sent; version_t last_log; std::deque log_queue; friend class LogClientTemp; }; #endif ceph-0.80.11/src/common/str_list.cc0000664000175100017510000000426412623076744021134 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2009-2010 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/str_list.h" using std::string; using std::vector; using std::set; using std::list; static bool get_next_token(const string &s, size_t& pos, const char *delims, string& token) { int start = s.find_first_not_of(delims, pos); int end; if (start < 0){ pos = s.size(); return false; } end = s.find_first_of(delims, start); if (end >= 0) pos = end + 1; else { pos = end = s.size(); } token = s.substr(start, end - start); return true; } void get_str_list(const string& str, const char *delims, list& str_list) { size_t pos = 0; string token; str_list.clear(); while (pos < str.size()) { if (get_next_token(str, pos, delims, token)) { if (token.size() > 0) { str_list.push_back(token); } } } } void get_str_list(const string& str, list& str_list) { const char *delims = ";,= \t"; return get_str_list(str, delims, str_list); } void get_str_vec(const string& str, const char *delims, vector& str_vec) { size_t pos = 0; string token; str_vec.clear(); while (pos < str.size()) { if (get_next_token(str, pos, delims, token)) { if (token.size() > 0) { str_vec.push_back(token); } } } } void get_str_vec(const string& str, vector& str_vec) { const char *delims = ";,= \t"; return get_str_vec(str, delims, str_vec); } void get_str_set(const string& str, const char *delims, set& str_set) { size_t pos = 0; string token; str_set.clear(); while (pos < str.size()) { if (get_next_token(str, pos, delims, token)) { if (token.size() > 0) { str_set.insert(token); } } } } void get_str_set(const string& str, set& str_set) { const char *delims = ";,= \t"; return get_str_set(str, delims, str_set); } ceph-0.80.11/src/common/Cond.h0000664000175100017510000001060512623076744020012 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COND_H #define CEPH_COND_H #include #include "Mutex.h" #include "Clock.h" #include "include/Context.h" #include class Cond { // my bits pthread_cond_t _c; Mutex *waiter_mutex; // don't allow copying. void operator=(Cond &C); Cond(const Cond &C); public: Cond() : waiter_mutex(NULL) { int r = pthread_cond_init(&_c,NULL); assert(r == 0); } virtual ~Cond() { pthread_cond_destroy(&_c); } int Wait(Mutex &mutex) { // make sure this cond is used with one mutex only assert(waiter_mutex == NULL || waiter_mutex == &mutex); waiter_mutex = &mutex; assert(mutex.is_locked()); mutex._pre_unlock(); int r = pthread_cond_wait(&_c, &mutex._m); mutex._post_lock(); return r; } int WaitUntil(Mutex &mutex, utime_t when) { // make sure this cond is used with one mutex only assert(waiter_mutex == NULL || waiter_mutex == &mutex); waiter_mutex = &mutex; assert(mutex.is_locked()); struct timespec ts; when.to_timespec(&ts); mutex._pre_unlock(); int r = pthread_cond_timedwait(&_c, &mutex._m, &ts); mutex._post_lock(); return r; } int WaitInterval(CephContext *cct, Mutex &mutex, utime_t interval) { utime_t when = ceph_clock_now(cct); when += interval; return WaitUntil(mutex, when); } int SloppySignal() { int r = pthread_cond_broadcast(&_c); return r; } int Signal() { // make sure signaler is holding the waiter's lock. assert(waiter_mutex == NULL || waiter_mutex->is_locked()); int r = pthread_cond_broadcast(&_c); return r; } int SignalOne() { // make sure signaler is holding the waiter's lock. assert(waiter_mutex == NULL || waiter_mutex->is_locked()); int r = pthread_cond_signal(&_c); return r; } int SignalAll() { // make sure signaler is holding the waiter's lock. assert(waiter_mutex == NULL || waiter_mutex->is_locked()); int r = pthread_cond_broadcast(&_c); return r; } }; /** * context to signal a cond * * Generic context to signal a cond and store the return value. We * assume the caller is holding the appropriate lock. */ class C_Cond : public Context { Cond *cond; ///< Cond to signal bool *done; ///< true if finish() has been called int *rval; ///< return value public: C_Cond(Cond *c, bool *d, int *r) : cond(c), done(d), rval(r) { *done = false; } void finish(int r) { *done = true; *rval = r; cond->Signal(); } }; /** * context to signal a cond, protected by a lock * * Generic context to signal a cond under a specific lock. We take the * lock in the finish() callback, so the finish() caller must not * already hold it. */ class C_SafeCond : public Context { Mutex *lock; ///< Mutex to take Cond *cond; ///< Cond to signal bool *done; ///< true after finish() has been called int *rval; ///< return value (optional) public: C_SafeCond(Mutex *l, Cond *c, bool *d, int *r=0) : lock(l), cond(c), done(d), rval(r) { *done = false; } void finish(int r) { lock->Lock(); if (rval) *rval = r; *done = true; cond->Signal(); lock->Unlock(); } }; /** * Context providing a simple wait() mechanism to wait for completion * * The context will not be deleted as part of complete and must live * until wait() returns. */ class C_SaferCond : public Context { Mutex lock; ///< Mutex to take Cond cond; ///< Cond to signal bool done; ///< true after finish() has been called int rval; ///< return value public: C_SaferCond() : lock("C_SaferCond"), done(false), rval(0) {} void finish(int r) { complete(r); } /// We overload complete in order to not delete the context void complete(int r) { Mutex::Locker l(lock); done = true; rval = r; cond.Signal(); } /// Returns rval once the Context is called int wait() { Mutex::Locker l(lock); while (!done) cond.Wait(lock); return rval; } }; #endif ceph-0.80.11/src/common/ConfUtils.cc0000664000175100017510000003474612623076744021207 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "include/buffer.h" #include "common/errno.h" #include "common/utf8.h" #include "common/ConfUtils.h" using std::cerr; using std::ostringstream; using std::pair; using std::string; #define MAX_CONFIG_FILE_SZ 0x40000000 ////////////////////////////// ConfLine ////////////////////////////// ConfLine:: ConfLine(const std::string &key_, const std::string val_, const std::string newsection_, const std::string comment_, int line_no_) : key(key_), val(val_), newsection(newsection_) { // If you want to implement writable ConfFile support, you'll need to save // the comment and line_no arguments here. } bool ConfLine:: operator<(const ConfLine &rhs) const { // We only compare keys. // If you have more than one line with the same key in a given section, the // last one wins. if (key < rhs.key) return true; else return false; } std::ostream &operator<<(std::ostream& oss, const ConfLine &l) { oss << "ConfLine(key = '" << l.key << "', val='" << l.val << "', newsection='" << l.newsection << "')"; return oss; } ///////////////////////// ConfFile ////////////////////////// ConfFile:: ConfFile() { } ConfFile:: ~ConfFile() { } void ConfFile:: clear() { sections.clear(); } /* We load the whole file into memory and then parse it. Although this is not * the optimal approach, it does mean that most of this code can be shared with * the bufferlist loading function. Since bufferlists are always in-memory, the * load_from_buffer interface works well for them. * In general, configuration files should be a few kilobytes at maximum, so * loading the whole configuration into memory shouldn't be a problem. */ int ConfFile:: parse_file(const std::string &fname, std::deque *errors, std::ostream *warnings) { clear(); int ret = 0; size_t sz; char *buf = NULL; FILE *fp = fopen(fname.c_str(), "r"); if (!fp) { ret = -errno; return ret; } struct stat st_buf; if (fstat(fileno(fp), &st_buf)) { ret = -errno; ostringstream oss; oss << "read_conf: failed to fstat '" << fname << "': " << cpp_strerror(ret); errors->push_back(oss.str()); goto done; } if (st_buf.st_size > MAX_CONFIG_FILE_SZ) { ostringstream oss; oss << "read_conf: config file '" << fname << "' is " << st_buf.st_size << " bytes, but the maximum is " << MAX_CONFIG_FILE_SZ; errors->push_back(oss.str()); ret = -EINVAL; goto done; } sz = (size_t)st_buf.st_size; buf = (char*)malloc(sz); if (!buf) { ret = -ENOMEM; goto done; } if (fread(buf, 1, sz, fp) != sz) { if (ferror(fp)) { ret = -errno; ostringstream oss; oss << "read_conf: fread error while reading '" << fname << "': " << cpp_strerror(ret); errors->push_back(oss.str()); goto done; } else { ostringstream oss; oss << "read_conf: unexpected EOF while reading '" << fname << "': " << "possible concurrent modification?"; errors->push_back(oss.str()); ret = -EIO; goto done; } } load_from_buffer(buf, sz, errors, warnings); ret = 0; done: free(buf); fclose(fp); return ret; } int ConfFile:: parse_bufferlist(ceph::bufferlist *bl, std::deque *errors, std::ostream *warnings) { clear(); load_from_buffer(bl->c_str(), bl->length(), errors, warnings); return 0; } int ConfFile:: read(const std::string §ion, const std::string &key, std::string &val) const { string k(normalize_key_name(key)); const_section_iter_t s = sections.find(section); if (s == sections.end()) return -ENOENT; ConfLine exemplar(k, "", "", "", 0); ConfSection::const_line_iter_t l = s->second.lines.find(exemplar); if (l == s->second.lines.end()) return -ENOENT; val = l->val; return 0; } ConfFile::const_section_iter_t ConfFile:: sections_begin() const { return sections.begin(); } ConfFile::const_section_iter_t ConfFile:: sections_end() const { return sections.end(); } void ConfFile:: trim_whitespace(std::string &str, bool strip_internal) { // strip preceding const char *in = str.c_str(); while (true) { char c = *in; if ((!c) || (!isspace(c))) break; ++in; } char output[strlen(in) + 1]; strcpy(output, in); // strip trailing char *o = output + strlen(output); while (true) { if (o == output) break; --o; if (!isspace(*o)) { ++o; *o = '\0'; break; } } if (!strip_internal) { str.assign(output); return; } // strip internal char output2[strlen(output) + 1]; char *out2 = output2; bool prev_was_space = false; for (char *u = output; *u; ++u) { char c = *u; if (isspace(c)) { if (!prev_was_space) *out2++ = c; prev_was_space = true; } else { *out2++ = c; prev_was_space = false; } } *out2++ = '\0'; str.assign(output2); } /* Normalize a key name. * * Normalized key names have no leading or trailing whitespace, and all * whitespace is stored as underscores. The main reason for selecting this * normal form is so that in common/config.cc, we can use a macro to stringify * the field names of md_config_t and get a key in normal form. */ std::string ConfFile:: normalize_key_name(const std::string &key) { string k(key); ConfFile::trim_whitespace(k, true); std::replace(k.begin(), k.end(), ' ', '_'); return k; } std::ostream &operator<<(std::ostream &oss, const ConfFile &cf) { for (ConfFile::const_section_iter_t s = cf.sections_begin(); s != cf.sections_end(); ++s) { oss << "[" << s->first << "]\n"; for (ConfSection::const_line_iter_t l = s->second.lines.begin(); l != s->second.lines.end(); ++l) { if (!l->key.empty()) { oss << "\t" << l->key << " = \"" << l->val << "\"\n"; } } } return oss; } void ConfFile:: load_from_buffer(const char *buf, size_t sz, std::deque *errors, std::ostream *warnings) { errors->clear(); section_iter_t::value_type vt("global", ConfSection()); pair < section_iter_t, bool > vr(sections.insert(vt)); assert(vr.second); section_iter_t cur_section = vr.first; std::string acc; const char *b = buf; int line_no = 0; size_t line_len = -1; size_t rem = sz; while (1) { b += line_len + 1; rem -= line_len + 1; if (rem == 0) break; line_no++; // look for the next newline const char *end = (const char*)memchr(b, '\n', rem); if (!end) { ostringstream oss; oss << "read_conf: ignoring line " << line_no << " because it doesn't " << "end with a newline! Please end the config file with a newline."; errors->push_back(oss.str()); break; } // find length of line, and search for NULLs line_len = 0; bool found_null = false; for (const char *tmp = b; tmp != end; ++tmp) { line_len++; if (*tmp == '\0') { found_null = true; } } if (found_null) { ostringstream oss; oss << "read_conf: ignoring line " << line_no << " because it has " << "an embedded null."; errors->push_back(oss.str()); acc.clear(); continue; } if (check_utf8(b, line_len)) { ostringstream oss; oss << "read_conf: ignoring line " << line_no << " because it is not " << "valid UTF8."; errors->push_back(oss.str()); acc.clear(); continue; } if ((line_len >= 1) && (b[line_len-1] == '\\')) { // A backslash at the end of a line serves as a line continuation marker. // Combine the next line with this one. // Remove the backslash itself from the text. acc.append(b, line_len - 1); continue; } acc.append(b, line_len); //cerr << "acc = '" << acc << "'" << std::endl; ConfLine *cline = process_line(line_no, acc.c_str(), errors); acc.clear(); if (!cline) continue; const std::string &csection(cline->newsection); if (!csection.empty()) { std::map ::value_type nt(csection, ConfSection()); pair < section_iter_t, bool > nr(sections.insert(nt)); cur_section = nr.first; } else { if (cur_section->second.lines.count(*cline)) { // replace an existing key/line in this section, so that // [mysection] // foo = 1 // foo = 2 // will result in foo = 2. cur_section->second.lines.erase(*cline); if (cline->key.length() && warnings) *warnings << "warning: line " << line_no << ": '" << cline->key << "' in section '" << cur_section->first << "' redefined " << std::endl; } // add line to current section //std::cerr << "cur_section = " << cur_section->first << ", " << *cline << std::endl; cur_section->second.lines.insert(*cline); } delete cline; } if (!acc.empty()) { ostringstream oss; oss << "read_conf: don't end with lines that end in backslashes!"; errors->push_back(oss.str()); } } /* * A simple state-machine based parser. * This probably could/should be rewritten with something like boost::spirit * or yacc if the grammar ever gets more complex. */ ConfLine* ConfFile:: process_line(int line_no, const char *line, std::deque *errors) { enum acceptor_state_t { ACCEPT_INIT, ACCEPT_SECTION_NAME, ACCEPT_KEY, ACCEPT_VAL_START, ACCEPT_UNQUOTED_VAL, ACCEPT_QUOTED_VAL, ACCEPT_COMMENT_START, ACCEPT_COMMENT_TEXT, }; const char *l = line; acceptor_state_t state = ACCEPT_INIT; string key, val, newsection, comment; bool escaping = false; while (true) { char c = *l++; switch (state) { case ACCEPT_INIT: if (c == '\0') return NULL; // blank line. Not an error, but not interesting either. else if (c == '[') state = ACCEPT_SECTION_NAME; else if ((c == '#') || (c == ';')) state = ACCEPT_COMMENT_TEXT; else if (c == ']') { ostringstream oss; oss << "unexpected right bracket at char " << (l - line) << ", line " << line_no; errors->push_back(oss.str()); return NULL; } else if (isspace(c)) { // ignore whitespace here } else { // try to accept this character as a key state = ACCEPT_KEY; --l; } break; case ACCEPT_SECTION_NAME: if (c == '\0') { ostringstream oss; oss << "error parsing new section name: expected right bracket " << "at char " << (l - line) << ", line " << line_no; errors->push_back(oss.str()); return NULL; } else if ((c == ']') && (!escaping)) { trim_whitespace(newsection, true); if (newsection.empty()) { ostringstream oss; oss << "error parsing new section name: no section name found? " << "at char " << (l - line) << ", line " << line_no; errors->push_back(oss.str()); return NULL; } state = ACCEPT_COMMENT_START; } else if (((c == '#') || (c == ';')) && (!escaping)) { ostringstream oss; oss << "unexpected comment marker while parsing new section name, at " << "char " << (l - line) << ", line " << line_no; errors->push_back(oss.str()); return NULL; } else if ((c == '\\') && (!escaping)) { escaping = true; } else { escaping = false; newsection += c; } break; case ACCEPT_KEY: if ((((c == '#') || (c == ';')) && (!escaping)) || (c == '\0')) { ostringstream oss; if (c == '\0') { oss << "end of key=val line " << line_no << " reached, no \"=val\" found...missing =?"; } else { oss << "unexpected character while parsing putative key value, " << "at char " << (l - line) << ", line " << line_no; } errors->push_back(oss.str()); return NULL; } else if ((c == '=') && (!escaping)) { key = normalize_key_name(key); if (key.empty()) { ostringstream oss; oss << "error parsing key name: no key name found? " << "at char " << (l - line) << ", line " << line_no; errors->push_back(oss.str()); return NULL; } state = ACCEPT_VAL_START; } else if ((c == '\\') && (!escaping)) { escaping = true; } else { escaping = false; key += c; } break; case ACCEPT_VAL_START: if (c == '\0') return new ConfLine(key, val, newsection, comment, line_no); else if ((c == '#') || (c == ';')) state = ACCEPT_COMMENT_TEXT; else if (c == '"') state = ACCEPT_QUOTED_VAL; else if (isspace(c)) { // ignore whitespace } else { // try to accept character as a val state = ACCEPT_UNQUOTED_VAL; --l; } break; case ACCEPT_UNQUOTED_VAL: if (c == '\0') { if (escaping) { ostringstream oss; oss << "error parsing value name: unterminated escape sequence " << "at char " << (l - line) << ", line " << line_no; errors->push_back(oss.str()); return NULL; } trim_whitespace(val, false); return new ConfLine(key, val, newsection, comment, line_no); } else if (((c == '#') || (c == ';')) && (!escaping)) { trim_whitespace(val, false); state = ACCEPT_COMMENT_TEXT; } else if ((c == '\\') && (!escaping)) { escaping = true; } else { escaping = false; val += c; } break; case ACCEPT_QUOTED_VAL: if (c == '\0') { ostringstream oss; oss << "found opening quote for value, but not the closing quote. " << "line " << line_no; errors->push_back(oss.str()); return NULL; } else if ((c == '"') && (!escaping)) { state = ACCEPT_COMMENT_START; } else if ((c == '\\') && (!escaping)) { escaping = true; } else { escaping = false; // Add anything, including whitespace. val += c; } break; case ACCEPT_COMMENT_START: if (c == '\0') { return new ConfLine(key, val, newsection, comment, line_no); } else if ((c == '#') || (c == ';')) { state = ACCEPT_COMMENT_TEXT; } else if (isspace(c)) { // ignore whitespace } else { ostringstream oss; oss << "unexpected character at char " << (l - line) << " of line " << line_no; errors->push_back(oss.str()); return NULL; } break; case ACCEPT_COMMENT_TEXT: if (c == '\0') return new ConfLine(key, val, newsection, comment, line_no); else comment += c; break; default: assert(0); break; } assert(c != '\0'); // We better not go past the end of the input string. } } ceph-0.80.11/src/common/admin_socket.cc0000664000175100017510000003740712623076744021736 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "common/Thread.h" #include "common/admin_socket.h" #include "common/admin_socket_client.h" #include "common/config.h" #include "common/cmdparse.h" #include "common/dout.h" #include "common/errno.h" #include "common/perf_counters.h" #include "common/pipe.h" #include "common/safe_io.h" #include "common/version.h" #include "common/Formatter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "include/compat.h" #define dout_subsys ceph_subsys_asok #undef dout_prefix #define dout_prefix *_dout << "asok(" << (void*)m_cct << ") " using std::ostringstream; /* * UNIX domain sockets created by an application persist even after that * application closes, unless they're explicitly unlinked. This is because the * directory containing the socket keeps a reference to the socket. * * This code makes things a little nicer by unlinking those dead sockets when * the application exits normally. */ static pthread_mutex_t cleanup_lock = PTHREAD_MUTEX_INITIALIZER; static std::vector cleanup_files; static bool cleanup_atexit = false; static void remove_cleanup_file(const char *file) { pthread_mutex_lock(&cleanup_lock); VOID_TEMP_FAILURE_RETRY(unlink(file)); for (std::vector ::iterator i = cleanup_files.begin(); i != cleanup_files.end(); ++i) { if (strcmp(file, *i) == 0) { free((void*)*i); cleanup_files.erase(i); break; } } pthread_mutex_unlock(&cleanup_lock); } static void remove_all_cleanup_files() { pthread_mutex_lock(&cleanup_lock); for (std::vector ::iterator i = cleanup_files.begin(); i != cleanup_files.end(); ++i) { VOID_TEMP_FAILURE_RETRY(unlink(*i)); free((void*)*i); } cleanup_files.clear(); pthread_mutex_unlock(&cleanup_lock); } static void add_cleanup_file(const char *file) { char *fname = strdup(file); if (!fname) return; pthread_mutex_lock(&cleanup_lock); cleanup_files.push_back(fname); if (!cleanup_atexit) { atexit(remove_all_cleanup_files); cleanup_atexit = true; } pthread_mutex_unlock(&cleanup_lock); } AdminSocket::AdminSocket(CephContext *cct) : m_cct(cct), m_sock_fd(-1), m_shutdown_rd_fd(-1), m_shutdown_wr_fd(-1), m_lock("AdminSocket::m_lock"), m_version_hook(NULL), m_help_hook(NULL), m_getdescs_hook(NULL) { } AdminSocket::~AdminSocket() { shutdown(); } /* * This thread listens on the UNIX domain socket for incoming connections. * It only handles one connection at a time at the moment. All I/O is nonblocking, * so that we can implement sensible timeouts. [TODO: make all I/O nonblocking] * * This thread also listens to m_shutdown_rd_fd. If there is any data sent to this * pipe, the thread terminates itself gracefully, allowing the * AdminSocketConfigObs class to join() it. */ #define PFL_SUCCESS ((void*)(intptr_t)0) #define PFL_FAIL ((void*)(intptr_t)1) std::string AdminSocket::create_shutdown_pipe(int *pipe_rd, int *pipe_wr) { int pipefd[2]; int ret = pipe_cloexec(pipefd); if (ret < 0) { ostringstream oss; oss << "AdminSocket::create_shutdown_pipe error: " << cpp_strerror(ret); return oss.str(); } *pipe_rd = pipefd[0]; *pipe_wr = pipefd[1]; return ""; } std::string AdminSocket::destroy_shutdown_pipe() { // Send a byte to the shutdown pipe that the thread is listening to char buf[1] = { 0x0 }; int ret = safe_write(m_shutdown_wr_fd, buf, sizeof(buf)); // Close write end VOID_TEMP_FAILURE_RETRY(close(m_shutdown_wr_fd)); m_shutdown_wr_fd = -1; if (ret != 0) { ostringstream oss; oss << "AdminSocket::destroy_shutdown_pipe error: failed to write" "to thread shutdown pipe: error " << ret; return oss.str(); } join(); // Close read end. Doing this before join() blocks the listenter and prevents // joining. VOID_TEMP_FAILURE_RETRY(close(m_shutdown_rd_fd)); m_shutdown_rd_fd = -1; return ""; } std::string AdminSocket::bind_and_listen(const std::string &sock_path, int *fd) { ldout(m_cct, 5) << "bind_and_listen " << sock_path << dendl; struct sockaddr_un address; if (sock_path.size() > sizeof(address.sun_path) - 1) { ostringstream oss; oss << "AdminSocket::bind_and_listen: " << "The UNIX domain socket path " << sock_path << " is too long! The " << "maximum length on this system is " << (sizeof(address.sun_path) - 1); return oss.str(); } int sock_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (sock_fd < 0) { int err = errno; ostringstream oss; oss << "AdminSocket::bind_and_listen: " << "failed to create socket: " << cpp_strerror(err); return oss.str(); } int r = fcntl(sock_fd, F_SETFD, FD_CLOEXEC); if (r < 0) { r = errno; VOID_TEMP_FAILURE_RETRY(::close(sock_fd)); ostringstream oss; oss << "AdminSocket::bind_and_listen: failed to fcntl on socket: " << cpp_strerror(r); return oss.str(); } memset(&address, 0, sizeof(struct sockaddr_un)); address.sun_family = AF_UNIX; snprintf(address.sun_path, sizeof(address.sun_path), "%s", sock_path.c_str()); if (bind(sock_fd, (struct sockaddr*)&address, sizeof(struct sockaddr_un)) != 0) { int err = errno; if (err == EADDRINUSE) { AdminSocketClient client(sock_path); bool ok; client.ping(&ok); if (ok) { ldout(m_cct, 20) << "socket " << sock_path << " is in use" << dendl; err = EEXIST; } else { ldout(m_cct, 20) << "unlink stale file " << sock_path << dendl; VOID_TEMP_FAILURE_RETRY(unlink(sock_path.c_str())); if (bind(sock_fd, (struct sockaddr*)&address, sizeof(struct sockaddr_un)) == 0) { err = 0; } else { err = errno; } } } if (err != 0) { ostringstream oss; oss << "AdminSocket::bind_and_listen: " << "failed to bind the UNIX domain socket to '" << sock_path << "': " << cpp_strerror(err); close(sock_fd); return oss.str(); } } if (listen(sock_fd, 5) != 0) { int err = errno; ostringstream oss; oss << "AdminSocket::bind_and_listen: " << "failed to listen to socket: " << cpp_strerror(err); close(sock_fd); VOID_TEMP_FAILURE_RETRY(unlink(sock_path.c_str())); return oss.str(); } *fd = sock_fd; return ""; } void* AdminSocket::entry() { ldout(m_cct, 5) << "entry start" << dendl; while (true) { struct pollfd fds[2]; memset(fds, 0, sizeof(fds)); fds[0].fd = m_sock_fd; fds[0].events = POLLIN | POLLRDBAND; fds[1].fd = m_shutdown_rd_fd; fds[1].events = POLLIN | POLLRDBAND; int ret = poll(fds, 2, -1); if (ret < 0) { int err = errno; if (err == EINTR) { continue; } lderr(m_cct) << "AdminSocket: poll(2) error: '" << cpp_strerror(err) << dendl; return PFL_FAIL; } if (fds[0].revents & POLLIN) { // Send out some data do_accept(); } if (fds[1].revents & POLLIN) { // Parent wants us to shut down return PFL_SUCCESS; } } ldout(m_cct, 5) << "entry exit" << dendl; } bool AdminSocket::do_accept() { struct sockaddr_un address; socklen_t address_length = sizeof(address); ldout(m_cct, 30) << "AdminSocket: calling accept" << dendl; int connection_fd = accept(m_sock_fd, (struct sockaddr*) &address, &address_length); ldout(m_cct, 30) << "AdminSocket: finished accept" << dendl; if (connection_fd < 0) { int err = errno; lderr(m_cct) << "AdminSocket: do_accept error: '" << cpp_strerror(err) << dendl; return false; } char cmd[1024]; int pos = 0; string c; while (1) { int ret = safe_read(connection_fd, &cmd[pos], 1); if (ret <= 0) { lderr(m_cct) << "AdminSocket: error reading request code: " << cpp_strerror(ret) << dendl; close(connection_fd); return false; } //ldout(m_cct, 0) << "AdminSocket read byte " << (int)cmd[pos] << " pos " << pos << dendl; if (cmd[0] == '\0') { // old protocol: __be32 if (pos == 3 && cmd[0] == '\0') { switch (cmd[3]) { case 0: c = "0"; break; case 1: c = "perfcounters_dump"; break; case 2: c = "perfcounters_schema"; break; default: c = "foo"; break; } break; } } else { // new protocol: null or \n terminated string if (cmd[pos] == '\n' || cmd[pos] == '\0') { cmd[pos] = '\0'; c = cmd; break; } } pos++; } bool rval = false; map cmdmap; string format; vector cmdvec; stringstream errss; cmdvec.push_back(cmd); if (!cmdmap_from_json(cmdvec, &cmdmap, errss)) { ldout(m_cct, 0) << "AdminSocket: " << errss << dendl; return false; } cmd_getval(m_cct, cmdmap, "format", format); if (format != "json" && format != "json-pretty" && format != "xml" && format != "xml-pretty") format = "json-pretty"; cmd_getval(m_cct, cmdmap, "prefix", c); string firstword; if (c.find(" ") == string::npos) firstword = c; else firstword = c.substr(0, c.find(" ")); m_lock.Lock(); map::iterator p; string match = c; while (match.size()) { p = m_hooks.find(match); if (p != m_hooks.end()) break; // drop right-most word size_t pos = match.rfind(' '); if (pos == std::string::npos) { match.clear(); // we fail break; } else { match.resize(pos); } } bufferlist out; if (p == m_hooks.end()) { lderr(m_cct) << "AdminSocket: request '" << c << "' not defined" << dendl; } else { string args; if (match != c) args = c.substr(match.length() + 1); bool success = p->second->call(match, cmdmap, format, out); if (!success) { ldout(m_cct, 0) << "AdminSocket: request '" << match << "' args '" << args << "' to " << p->second << " failed" << dendl; out.append("failed"); } else { ldout(m_cct, 5) << "AdminSocket: request '" << match << "' '" << args << "' to " << p->second << " returned " << out.length() << " bytes" << dendl; } uint32_t len = htonl(out.length()); int ret = safe_write(connection_fd, &len, sizeof(len)); if (ret < 0) { lderr(m_cct) << "AdminSocket: error writing response length " << cpp_strerror(ret) << dendl; } else { if (out.write_fd(connection_fd) >= 0) rval = true; } } m_lock.Unlock(); VOID_TEMP_FAILURE_RETRY(close(connection_fd)); return rval; } int AdminSocket::register_command(std::string command, std::string cmddesc, AdminSocketHook *hook, std::string help) { int ret; m_lock.Lock(); if (m_hooks.count(command)) { ldout(m_cct, 5) << "register_command " << command << " hook " << hook << " EEXIST" << dendl; ret = -EEXIST; } else { ldout(m_cct, 5) << "register_command " << command << " hook " << hook << dendl; m_hooks[command] = hook; m_descs[command] = cmddesc; m_help[command] = help; ret = 0; } m_lock.Unlock(); return ret; } int AdminSocket::unregister_command(std::string command) { int ret; m_lock.Lock(); if (m_hooks.count(command)) { ldout(m_cct, 5) << "unregister_command " << command << dendl; m_hooks.erase(command); m_descs.erase(command); m_help.erase(command); ret = 0; } else { ldout(m_cct, 5) << "unregister_command " << command << " ENOENT" << dendl; ret = -ENOENT; } m_lock.Unlock(); return ret; } class VersionHook : public AdminSocketHook { public: virtual bool call(std::string command, cmdmap_t &cmdmap, std::string format, bufferlist& out) { if (command == "0") { out.append(CEPH_ADMIN_SOCK_VERSION); } else { JSONFormatter jf; jf.open_object_section("version"); if (command == "version") jf.dump_string("version", ceph_version_to_str()); else if (command == "git_version") jf.dump_string("git_version", git_version_to_str()); ostringstream ss; jf.close_section(); jf.flush(ss); out.append(ss.str()); } return true; } }; class HelpHook : public AdminSocketHook { AdminSocket *m_as; public: HelpHook(AdminSocket *as) : m_as(as) {} bool call(string command, cmdmap_t &cmdmap, string format, bufferlist& out) { Formatter *f = new_formatter(format); if (!f) f = new_formatter("json-pretty"); f->open_object_section("help"); for (map::iterator p = m_as->m_help.begin(); p != m_as->m_help.end(); ++p) { if (p->second.length()) f->dump_string(p->first.c_str(), p->second); } f->close_section(); ostringstream ss; f->flush(ss); out.append(ss.str()); delete f; return true; } }; class GetdescsHook : public AdminSocketHook { AdminSocket *m_as; public: GetdescsHook(AdminSocket *as) : m_as(as) {} bool call(string command, cmdmap_t &cmdmap, string format, bufferlist& out) { int cmdnum = 0; JSONFormatter jf(false); jf.open_object_section("command_descriptions"); for (map::iterator p = m_as->m_descs.begin(); p != m_as->m_descs.end(); ++p) { ostringstream secname; secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; dump_cmd_and_help_to_json(&jf, secname.str().c_str(), p->second.c_str(), m_as->m_help[p->first]); cmdnum++; } jf.close_section(); // command_descriptions ostringstream ss; jf.flush(ss); out.append(ss.str()); return true; } }; bool AdminSocket::init(const std::string &path) { ldout(m_cct, 5) << "init " << path << dendl; /* Set up things for the new thread */ std::string err; int pipe_rd = -1, pipe_wr = -1; err = create_shutdown_pipe(&pipe_rd, &pipe_wr); if (!err.empty()) { lderr(m_cct) << "AdminSocketConfigObs::init: error: " << err << dendl; return false; } int sock_fd; err = bind_and_listen(path, &sock_fd); if (!err.empty()) { lderr(m_cct) << "AdminSocketConfigObs::init: failed: " << err << dendl; close(pipe_rd); close(pipe_wr); return false; } /* Create new thread */ m_sock_fd = sock_fd; m_shutdown_rd_fd = pipe_rd; m_shutdown_wr_fd = pipe_wr; m_path = path; m_version_hook = new VersionHook; register_command("0", "0", m_version_hook, ""); register_command("version", "version", m_version_hook, "get ceph version"); register_command("git_version", "git_version", m_version_hook, "get git sha1"); m_help_hook = new HelpHook(this); register_command("help", "help", m_help_hook, "list available commands"); m_getdescs_hook = new GetdescsHook(this); register_command("get_command_descriptions", "get_command_descriptions", m_getdescs_hook, "list available commands"); create(); add_cleanup_file(m_path.c_str()); return true; } void AdminSocket::shutdown() { std::string err; // Under normal operation this is unlikely to occur. However for some unit // tests, some object members are not initialized and so cannot be deleted // without fault. if (m_shutdown_wr_fd < 0) return; ldout(m_cct, 5) << "shutdown" << dendl; err = destroy_shutdown_pipe(); if (!err.empty()) { lderr(m_cct) << "AdminSocket::shutdown: error: " << err << dendl; } VOID_TEMP_FAILURE_RETRY(close(m_sock_fd)); unregister_command("version"); unregister_command("git_version"); unregister_command("0"); delete m_version_hook; unregister_command("help"); delete m_help_hook; unregister_command("get_command_descriptions"); delete m_getdescs_hook; remove_cleanup_file(m_path.c_str()); m_path.clear(); } ceph-0.80.11/src/common/pick_address.h0000664000175100017510000000224012623076744021556 0ustar jenkins-buildjenkins-build#ifndef CEPH_PICK_ADDRESS_H #define CEPH_PICK_ADDRESS_H #include "common/config.h" class CephContext; #define CEPH_PICK_ADDRESS_PUBLIC 0x01 #define CEPH_PICK_ADDRESS_CLUSTER 0x02 /* Pick addresses based on subnets if needed. If an address is not explicitly given, and a list of subnets is given, find an assigned IP address in the subnets and set that. cluster_addr is set based on cluster_network, public_addr is set based on public_network. cluster_network and public_network are a list of ip/prefix pairs. All IP addresses assigned to all local network interfaces are potential matches. If multiple IP addresses match the subnet, one of them will be picked, effectively randomly. This function will exit on error. */ void pick_addresses(CephContext *cct, int needs); /** * check for a locally configured address * * check if any of the listed addresses is configured on the local host. * * @param cct context * @param ls list of addresses * @param match [out] pointer to match, if an item in @a ls is found configured locally. */ bool have_local_addr(CephContext *cct, const list& ls, entity_addr_t *match); #endif ceph-0.80.11/src/common/Clock.cc0000664000175100017510000000156012623076744020320 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/Clock.h" #include "common/ceph_context.h" #include "common/config.h" #include "include/utime.h" #include utime_t ceph_clock_now(CephContext *cct) { struct timeval tv; gettimeofday(&tv, NULL); utime_t n(&tv); if (cct) n += cct->_conf->clock_offset; return n; } time_t ceph_clock_gettime(CephContext *cct) { time_t ret = time(NULL); if (cct) ret += ((time_t)cct->_conf->clock_offset); return ret; } ceph-0.80.11/src/common/entity_name.h0000664000175100017510000000452312623076744021445 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_ENTITY_NAME_H #define CEPH_COMMON_ENTITY_NAME_H #include #include #include #include "include/encoding.h" #include "include/buffer.h" #include "msg/msg_types.h" /* Represents a Ceph entity name. * * For example, mds.0 is the name of the first metadata server. * client */ struct EntityName { EntityName(); void encode(bufferlist& bl) const { ::encode(type, bl); ::encode(id, bl); } void decode(bufferlist::iterator& bl) { uint32_t type_; std::string id_; ::decode(type_, bl); ::decode(id_, bl); set(type_, id_); } const std::string& to_str() const; const char *to_cstr() const; bool from_str(const std::string& s); void set(uint32_t type_, const std::string &id_); int set(const std::string &type_, const std::string &id_); void set_type(uint32_t type_); int set_type(const char *type); void set_id(const std::string &id_); void set_name(entity_name_t n); const char* get_type_str() const; uint32_t get_type() const { return type; } bool is_osd() const { return get_type() == CEPH_ENTITY_TYPE_OSD; } bool is_mds() const { return get_type() == CEPH_ENTITY_TYPE_MDS; } bool is_client() const { return get_type() == CEPH_ENTITY_TYPE_CLIENT; } bool is_mon() const { return get_type() == CEPH_ENTITY_TYPE_MON; } const char * get_type_name() const; const std::string &get_id() const; bool has_default_id() const; static std::string get_valid_types_as_str(); friend bool operator<(const EntityName& a, const EntityName& b); friend std::ostream& operator<<(std::ostream& out, const EntityName& n); friend bool operator==(const EntityName& a, const EntityName& b); friend bool operator!=(const EntityName& a, const EntityName& b); private: uint32_t type; std::string id; std::string type_id; }; uint32_t str_to_ceph_entity_type(const char * str); WRITE_CLASS_ENCODER(EntityName); WRITE_EQ_OPERATORS_2(EntityName, type, id) #endif ceph-0.80.11/src/common/code_environment.cc0000664000175100017510000000336612623076744022631 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "acconfig.h" #include "common/code_environment.h" #include #include #include #include #include #ifdef HAVE_SYS_PRCTL_H #include #endif code_environment_t g_code_env = CODE_ENVIRONMENT_UTILITY; extern "C" const char *code_environment_to_str(enum code_environment_t e) { switch (e) { case CODE_ENVIRONMENT_UTILITY: return "CODE_ENVIRONMENT_UTILITY"; case CODE_ENVIRONMENT_DAEMON: return "CODE_ENVIRONMENT_DAEMON"; case CODE_ENVIRONMENT_LIBRARY: return "CODE_ENVIRONMENT_LIBRARY"; default: return NULL; } } std::ostream &operator<<(std::ostream &oss, enum code_environment_t e) { oss << code_environment_to_str(e); return oss; } #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME) /* Since 2.6.11 */ int get_process_name(char *buf, int len) { if (len <= 16) { /* The man page discourages using this prctl with a buffer shorter * than 16 bytes. With a 16-byte buffer, it might not be * null-terminated. */ return -ENAMETOOLONG; } memset(buf, 0, len); return prctl(PR_GET_NAME, buf); } #else int get_process_name(char *buf, int len) { return -ENOSYS; } #endif std::string get_process_name_cpp() { char buf[32]; if (get_process_name(buf, sizeof(buf))) { return "(unknown)"; } return std::string(buf); } ceph-0.80.11/src/common/HeartbeatMap.h0000664000175100017510000000406512623076744021467 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_HEARTBEATMAP_H #define CEPH_HEARTBEATMAP_H #include #include #include #include #include "include/atomic.h" #include "RWLock.h" class CephContext; namespace ceph { /* * HeartbeatMap - * * Maintain a set of handles for internal subsystems to periodically * check in with a health check and timeout. Each user can register * and get a handle they can use to set or reset a timeout. * * A simple is_healthy() method checks for any users who are not within * their grace period for a heartbeat. */ struct heartbeat_handle_d { std::string name; atomic_t timeout, suicide_timeout; time_t grace, suicide_grace; std::list::iterator list_item; heartbeat_handle_d(const std::string& n) : name(n), grace(0), suicide_grace(0) { } }; class HeartbeatMap { public: // register/unregister heartbeat_handle_d *add_worker(std::string name); void remove_worker(heartbeat_handle_d *h); // reset the timeout so that it expects another touch within grace amount of time void reset_timeout(heartbeat_handle_d *h, time_t grace, time_t suicide_grace); // clear the timeout so that it's not checked on void clear_timeout(heartbeat_handle_d *h); // return false if any of the timeouts are currently expired. bool is_healthy(); // touch cct->_conf->heartbeat_file if is_healthy() void check_touch_file(); HeartbeatMap(CephContext *cct); ~HeartbeatMap(); private: CephContext *m_cct; RWLock m_rwlock; time_t m_inject_unhealthy_until; std::list m_workers; bool _check(heartbeat_handle_d *h, const char *who, time_t now); }; } #endif ceph-0.80.11/src/common/dout.h0000664000175100017510000000437512623076744020111 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2010 Sage Weil * Copyright (C) 2010 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DOUT_H #define CEPH_DOUT_H #include "global/global_context.h" #include "common/config.h" #include "common/likely.h" #include "common/Clock.h" #include "log/Log.h" #include "include/assert.h" #include #include #include #include extern void dout_emergency(const char * const str); extern void dout_emergency(const std::string &str); // intentionally conflict with endl class _bad_endl_use_dendl_t { public: _bad_endl_use_dendl_t(int) {} }; static const _bad_endl_use_dendl_t endl = 0; inline std::ostream& operator<<(std::ostream& out, _bad_endl_use_dendl_t) { assert(0 && "you are using the wrong endl.. use std::endl or dendl"); return out; } // generic macros #define dout_prefix *_dout #define dout_impl(cct, sub, v) \ do { \ if (cct->_conf->subsys.should_gather(sub, v)) { \ if (0) { \ char __array[((v >= -1) && (v <= 200)) ? 0 : -1] __attribute__((unused)); \ } \ ceph::log::Entry *_dout_e = cct->_log->create_entry(v, sub); \ ostream _dout_os(&_dout_e->m_streambuf); \ CephContext *_dout_cct = cct; \ std::ostream* _dout = &_dout_os; #define lsubdout(cct, sub, v) dout_impl(cct, ceph_subsys_##sub, v) dout_prefix #define ldout(cct, v) dout_impl(cct, dout_subsys, v) dout_prefix #define lderr(cct) dout_impl(cct, ceph_subsys_, -1) dout_prefix #define lgeneric_subdout(cct, sub, v) dout_impl(cct, ceph_subsys_##sub, v) *_dout #define lgeneric_dout(cct, v) dout_impl(cct, ceph_subsys_, v) *_dout #define lgeneric_derr(cct) dout_impl(cct, ceph_subsys_, -1) *_dout // NOTE: depend on magic value in _ASSERT_H so that we detect when // /usr/include/assert.h clobbers our fancier version. #define dendl std::flush; \ _ASSERT_H->_log->submit_entry(_dout_e); \ } \ } while (0) #endif ceph-0.80.11/src/common/DecayCounter.cc0000664000175100017510000000350712623076744021655 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "DecayCounter.h" #include "Formatter.h" void DecayCounter::encode(bufferlist& bl) const { ENCODE_START(4, 4, bl); ::encode(val, bl); ::encode(delta, bl); ::encode(vel, bl); ENCODE_FINISH(bl); } void DecayCounter::decode(const utime_t &t, bufferlist::iterator &p) { DECODE_START_LEGACY_COMPAT_LEN(4, 4, 4, p); if (struct_v < 2) { double half_life; ::decode(half_life, p); } if (struct_v < 3) { double k; ::decode(k, p); } ::decode(val, p); ::decode(delta, p); ::decode(vel, p); DECODE_FINISH(p); } void DecayCounter::dump(Formatter *f) const { f->dump_float("value", val); f->dump_float("delta", delta); f->dump_float("velocity", vel); } void DecayCounter::generate_test_instances(list& ls) { utime_t fake_time; DecayCounter *counter = new DecayCounter(fake_time); counter->val = 3.0; counter->delta = 2.0; counter->vel = 1.0; ls.push_back(counter); counter = new DecayCounter(fake_time); ls.push_back(counter); } void DecayCounter::decay(utime_t now, const DecayRate &rate) { utime_t el = now; el -= last_decay; if (el.sec() >= 1) { // calculate new value double newval = (val+delta) * exp((double)el * rate.k); if (newval < .01) newval = 0.0; // calculate velocity approx vel += (newval - val) * (double)el; vel *= exp((double)el * rate.k); val = newval; delta = 0; last_decay = now; } } ceph-0.80.11/src/common/pipe.c0000664000175100017510000000227412623076744020062 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "acconfig.h" #include "common/pipe.h" #include "include/compat.h" #include #include #include int pipe_cloexec(int pipefd[2]) { int ret; #if defined(HAVE_PIPE2) && defined(O_CLOEXEC) ret = pipe2(pipefd, O_CLOEXEC); if (ret == -1) return -errno; return 0; #else ret = pipe(pipefd); if (ret == -1) return -errno; /* * The old-fashioned, race-condition prone way that we have to fall * back on if O_CLOEXEC does not exist. */ ret = fcntl(pipefd[0], F_SETFD, FD_CLOEXEC); if (ret == -1) { ret = -errno; goto out; } ret = fcntl(pipefd[1], F_SETFD, FD_CLOEXEC); if (ret == -1) { ret = -errno; goto out; } return 0; out: VOID_TEMP_FAILURE_RETRY(close(pipefd[0])); VOID_TEMP_FAILURE_RETRY(close(pipefd[1])); return ret; #endif } ceph-0.80.11/src/common/lru_map.h0000664000175100017510000000536212623076744020572 0ustar jenkins-buildjenkins-build#ifndef CEPH_LRU_MAP_H #define CEPH_LRU_MAP_H #include #include #include "common/Mutex.h" template class lru_map { struct entry { V value; typename std::list::iterator lru_iter; }; std::map entries; std::list entries_lru; Mutex lock; size_t max; public: class UpdateContext { public: virtual ~UpdateContext() {} /* update should return true if object is updated */ virtual bool update(V *v) = 0; }; bool _find(const K& key, V *value, UpdateContext *ctx); void _add(const K& key, V& value); public: lru_map(int _max) : lock("lru_map"), max(_max) {} virtual ~lru_map() {} bool find(const K& key, V& value); /* * find_and_update() * * - will return true if object is found * - if ctx is set will return true if object is found and updated */ bool find_and_update(const K& key, V *value, UpdateContext *ctx); void add(const K& key, V& value); void erase(const K& key); }; template bool lru_map::_find(const K& key, V *value, UpdateContext *ctx) { typename std::map::iterator iter = entries.find(key); if (iter == entries.end()) { return false; } entry& e = iter->second; entries_lru.erase(e.lru_iter); bool r = true; if (ctx) r = ctx->update(&e.value); if (value) *value = e.value; entries_lru.push_front(key); e.lru_iter = entries_lru.begin(); return r; } template bool lru_map::find(const K& key, V& value) { Mutex::Locker l(lock); return _find(key, &value, NULL); } template bool lru_map::find_and_update(const K& key, V *value, UpdateContext *ctx) { Mutex::Locker l(lock); return _find(key, value, ctx); } template void lru_map::_add(const K& key, V& value) { typename std::map::iterator iter = entries.find(key); if (iter != entries.end()) { entry& e = iter->second; entries_lru.erase(e.lru_iter); } entries_lru.push_front(key); entry& e = entries[key]; e.value = value; e.lru_iter = entries_lru.begin(); while (entries.size() > max) { typename std::list::reverse_iterator riter = entries_lru.rbegin(); iter = entries.find(*riter); // assert(iter != entries.end()); entries.erase(iter); entries_lru.pop_back(); } } template void lru_map::add(const K& key, V& value) { Mutex::Locker l(lock); _add(key, value); } template void lru_map::erase(const K& key) { Mutex::Locker l(lock); typename std::map::iterator iter = entries.find(key); if (iter == entries.end()) return; entry& e = iter->second; entries_lru.erase(e.lru_iter); entries.erase(iter); } #endif ceph-0.80.11/src/common/utf8.h0000664000175100017510000000323412623076744020015 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_UTF8_H #define CEPH_COMMON_UTF8_H #ifdef __cplusplus extern "C" { #endif /* Checks if a buffer is valid UTF-8. * Returns 0 if it is, and one plus the offset of the first invalid byte * if it is not. */ int check_utf8(const char *buf, int len); /* Checks if a null-terminated string is valid UTF-8. * Returns 0 if it is, and one plus the offset of the first invalid byte * if it is not. */ int check_utf8_cstr(const char *buf); /* Returns true if 'ch' is a control character. * We do count newline as a control character, but not NULL. */ int is_control_character(int ch); /* Checks if a buffer contains control characters. */ int check_for_control_characters(const char *buf, int len); /* Checks if a null-terminated string contains control characters. */ int check_for_control_characters_cstr(const char *buf); /* Encode a 31-bit UTF8 code point to 'buf'. * Assumes buf is of size MAX_UTF8_SZ * Returns -1 on failure; number of bytes in the encoded value otherwise. */ int encode_utf8(unsigned long u, unsigned char *buf); /* * Decode a UTF8 character from an array of bytes. Return character code. * Upon error, return INVALID_UTF8_CHAR. */ unsigned long decode_utf8(unsigned char *buf, int nbytes); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/shared_cache.hpp0000664000175100017510000000747212623076744022070 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SHAREDCACHE_H #define CEPH_SHAREDCACHE_H #include #include #include #include #include "common/Mutex.h" #include "common/Cond.h" template class SharedLRU { typedef ceph::shared_ptr VPtr; typedef ceph::weak_ptr WeakVPtr; Mutex lock; size_t max_size; Cond cond; unsigned size; map >::iterator > contents; list > lru; map weak_refs; void trim_cache(list *to_release) { while (size > max_size) { to_release->push_back(lru.back().second); lru_remove(lru.back().first); } } void lru_remove(K key) { typename map >::iterator>::iterator i = contents.find(key); if (i == contents.end()) return; lru.erase(i->second); --size; contents.erase(i); } void lru_add(K key, VPtr val, list *to_release) { typename map >::iterator>::iterator i = contents.find(key); if (i != contents.end()) { lru.splice(lru.begin(), lru, i->second); } else { ++size; lru.push_front(make_pair(key, val)); contents[key] = lru.begin(); trim_cache(to_release); } } void remove(K key) { Mutex::Locker l(lock); weak_refs.erase(key); cond.Signal(); } class Cleanup { public: SharedLRU *cache; K key; Cleanup(SharedLRU *cache, K key) : cache(cache), key(key) {} void operator()(V *ptr) { cache->remove(key); delete ptr; } }; public: SharedLRU(size_t max_size = 20) : lock("SharedLRU::lock"), max_size(max_size), size(0) {} ~SharedLRU() { contents.clear(); lru.clear(); assert(weak_refs.empty()); } void clear(K key) { VPtr val; // release any ref we have after we drop the lock { Mutex::Locker l(lock); if (weak_refs.count(key)) { val = weak_refs[key].lock(); } lru_remove(key); } } void set_size(size_t new_size) { list to_release; { Mutex::Locker l(lock); max_size = new_size; trim_cache(&to_release); } } // Returns K key s.t. key <= k for all currently cached k,v K cached_key_lower_bound() { Mutex::Locker l(lock); return weak_refs.begin()->first; } VPtr lower_bound(K key) { VPtr val; list to_release; { Mutex::Locker l(lock); bool retry = false; do { retry = false; if (weak_refs.empty()) break; typename map::iterator i = weak_refs.lower_bound(key); if (i == weak_refs.end()) --i; val = i->second.lock(); if (val) { lru_add(i->first, val, &to_release); } else { retry = true; } if (retry) cond.Wait(lock); } while (retry); } return val; } VPtr lookup(K key) { VPtr val; list to_release; { Mutex::Locker l(lock); bool retry = false; do { retry = false; if (weak_refs.count(key)) { val = weak_refs[key].lock(); if (val) { lru_add(key, val, &to_release); } else { retry = true; } } if (retry) cond.Wait(lock); } while (retry); } return val; } VPtr add(K key, V *value) { VPtr val(value, Cleanup(this, key)); list to_release; { Mutex::Locker l(lock); weak_refs.insert(make_pair(key, val)); lru_add(key, val, &to_release); } return val; } }; #endif ceph-0.80.11/src/common/Timer.h0000664000175100017510000000466412623076744020217 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_TIMER_H #define CEPH_TIMER_H #include "Cond.h" #include "Mutex.h" #include class CephContext; class Context; class SafeTimerThread; class SafeTimer { // This class isn't supposed to be copied SafeTimer(const SafeTimer &rhs); SafeTimer& operator=(const SafeTimer &rhs); CephContext *cct; Mutex& lock; Cond cond; bool safe_callbacks; friend class SafeTimerThread; SafeTimerThread *thread; void timer_thread(); void _shutdown(); std::multimap schedule; std::map::iterator> events; bool stopping; void dump(const char *caller = 0) const; public: /* Safe callbacks determines whether callbacks are called with the lock * held. * * safe_callbacks = true (default option) guarantees that a cancelled * event's callback will never be called. * * Under some circumstances, holding the lock can cause lock cycles. * If you are able to relax requirements on cancelled callbacks, then * setting safe_callbacks = false eliminates the lock cycle issue. * */ SafeTimer(CephContext *cct, Mutex &l, bool safe_callbacks=true); ~SafeTimer(); /* Call with the event_lock UNLOCKED. * * Cancel all events and stop the timer thread. * * If there are any events that still have to run, they will need to take * the event_lock first. */ void init(); void shutdown(); /* Schedule an event in the future * Call with the event_lock LOCKED */ void add_event_after(double seconds, Context *callback); void add_event_at(utime_t when, Context *callback); /* Cancel an event. * Call with the event_lock LOCKED * * Returns true if the callback was cancelled. * Returns false if you never addded the callback in the first place. */ bool cancel_event(Context *callback); /* Cancel all events. * Call with the event_lock LOCKED * * When this function returns, all events have been cancelled, and there are no * more in progress. */ void cancel_all_events(); }; #endif ceph-0.80.11/src/common/snap_types.cc0000664000175100017510000000463712623076744021462 0ustar jenkins-buildjenkins-build #include "snap_types.h" #include "common/Formatter.h" void SnapRealmInfo::encode(bufferlist& bl) const { h.num_snaps = my_snaps.size(); h.num_prior_parent_snaps = prior_parent_snaps.size(); ::encode(h, bl); ::encode_nohead(my_snaps, bl); ::encode_nohead(prior_parent_snaps, bl); } void SnapRealmInfo::decode(bufferlist::iterator& bl) { ::decode(h, bl); ::decode_nohead(h.num_snaps, my_snaps, bl); ::decode_nohead(h.num_prior_parent_snaps, prior_parent_snaps, bl); } void SnapRealmInfo::dump(Formatter *f) const { f->dump_unsigned("ino", ino()); f->dump_unsigned("parent", parent()); f->dump_unsigned("seq", seq()); f->dump_unsigned("parent_since", parent_since()); f->dump_unsigned("created", created()); f->open_array_section("snaps"); for (vector::const_iterator p = my_snaps.begin(); p != my_snaps.end(); ++p) f->dump_unsigned("snap", *p); f->close_section(); f->open_array_section("prior_parent_snaps"); for (vector::const_iterator p = prior_parent_snaps.begin(); p != prior_parent_snaps.end(); ++p) f->dump_unsigned("snap", *p); f->close_section(); } void SnapRealmInfo::generate_test_instances(list& o) { o.push_back(new SnapRealmInfo); o.push_back(new SnapRealmInfo(1, 10, 10, 0)); o.push_back(new SnapRealmInfo(1, 10, 10, 0)); o.back()->my_snaps.push_back(10); o.push_back(new SnapRealmInfo(1, 10, 10, 5)); o.back()->my_snaps.push_back(10); o.back()->prior_parent_snaps.push_back(3); o.back()->prior_parent_snaps.push_back(5); } // ----- bool SnapContext::is_valid() const { // seq is a valid snapid if (seq > CEPH_MAXSNAP) return false; if (!snaps.empty()) { // seq >= snaps[0] if (snaps[0] > seq) return false; // snaps[] is descending snapid_t t = snaps[0]; for (unsigned i=1; i= t || t == 0) return false; t = snaps[i]; } } return true; } void SnapContext::dump(Formatter *f) const { f->dump_unsigned("seq", seq); f->open_array_section("snaps"); for (vector::const_iterator p = snaps.begin(); p != snaps.end(); ++p) f->dump_unsigned("snap", *p); f->close_section(); } void SnapContext::generate_test_instances(list& o) { o.push_back(new SnapContext); vector v; o.push_back(new SnapContext(10, v)); v.push_back(18); v.push_back(3); v.push_back(1); o.push_back(new SnapContext(20, v)); } ceph-0.80.11/src/common/bloom_filter.cc0000664000175100017510000000671112623076744021745 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "common/bloom_filter.hpp" void bloom_filter::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode((uint64_t)salt_count_, bl); ::encode((uint64_t)insert_count_, bl); ::encode((uint64_t)target_element_count_, bl); ::encode((uint64_t)random_seed_, bl); bufferptr bp((const char*)bit_table_, table_size_); ::encode(bp, bl); ENCODE_FINISH(bl); } void bloom_filter::decode(bufferlist::iterator& p) { DECODE_START(2, p); uint64_t v; ::decode(v, p); salt_count_ = v; ::decode(v, p); insert_count_ = v; ::decode(v, p); target_element_count_ = v; ::decode(v, p); random_seed_ = v; bufferlist t; ::decode(t, p); salt_.clear(); generate_unique_salt(); table_size_ = t.length(); delete bit_table_; if (table_size_) { bit_table_ = new cell_type[table_size_]; t.copy(0, table_size_, (char *)bit_table_); } else { bit_table_ = NULL; } DECODE_FINISH(p); } void bloom_filter::dump(Formatter *f) const { f->dump_unsigned("salt_count", salt_count_); f->dump_unsigned("table_size", table_size_); f->dump_unsigned("insert_count", insert_count_); f->dump_unsigned("target_element_count", target_element_count_); f->dump_unsigned("random_seed", random_seed_); f->open_array_section("salt_table"); for (std::vector::const_iterator i = salt_.begin(); i != salt_.end(); ++i) f->dump_unsigned("salt", *i); f->close_section(); f->open_array_section("bit_table"); for (unsigned i = 0; i < table_size_; ++i) f->dump_unsigned("byte", (unsigned)bit_table_[i]); f->close_section(); } void bloom_filter::generate_test_instances(list& ls) { ls.push_back(new bloom_filter(10, .5, 1)); ls.push_back(new bloom_filter(10, .5, 1)); ls.back()->insert("foo"); ls.back()->insert("bar"); ls.push_back(new bloom_filter(50, .5, 1)); ls.back()->insert("foo"); ls.back()->insert("bar"); ls.back()->insert("baz"); ls.back()->insert("boof"); ls.back()->insert("boogggg"); } void compressible_bloom_filter::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); bloom_filter::encode(bl); uint32_t s = size_list.size(); ::encode(s, bl); for (vector::const_iterator p = size_list.begin(); p != size_list.end(); ++p) ::encode((uint64_t)*p, bl); ENCODE_FINISH(bl); } void compressible_bloom_filter::decode(bufferlist::iterator& p) { DECODE_START(2, p); bloom_filter::decode(p); uint32_t s; ::decode(s, p); size_list.resize(s); for (unsigned i = 0; i < s; i++) { uint64_t v; ::decode(v, p); size_list[i] = v; } DECODE_FINISH(p); } void compressible_bloom_filter::dump(Formatter *f) const { bloom_filter::dump(f); f->open_array_section("table_sizes"); for (vector::const_iterator p = size_list.begin(); p != size_list.end(); ++p) f->dump_unsigned("size", (uint64_t)*p); f->close_section(); } void compressible_bloom_filter::generate_test_instances(list& ls) { ls.push_back(new compressible_bloom_filter(10, .5, 1)); ls.push_back(new compressible_bloom_filter(10, .5, 1)); ls.back()->insert("foo"); ls.back()->insert("bar"); ls.push_back(new compressible_bloom_filter(50, .5, 1)); ls.back()->insert("foo"); ls.back()->insert("bar"); ls.back()->insert("baz"); ls.back()->insert("boof"); ls.back()->compress(20); ls.back()->insert("boogggg"); } ceph-0.80.11/src/common/TrackedOp.h0000664000175100017510000001231612623076744021004 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network/Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef TRACKEDREQUEST_H_ #define TRACKEDREQUEST_H_ #include #include #include #include "common/Mutex.h" #include "common/histogram.h" #include "include/xlist.h" #include "msg/Message.h" #include "include/memory.h" class TrackedOp; typedef ceph::shared_ptr TrackedOpRef; class OpTracker; class OpHistory { set > arrived; set > duration; void cleanup(utime_t now); bool shutdown; uint32_t history_size; uint32_t history_duration; public: OpHistory() : shutdown(false), history_size(0), history_duration(0) {} ~OpHistory() { assert(arrived.empty()); assert(duration.empty()); } void insert(utime_t now, TrackedOpRef op); void dump_ops(utime_t now, Formatter *f); void on_shutdown(); void set_size_and_duration(uint32_t new_size, uint32_t new_duration) { history_size = new_size; history_duration = new_duration; } }; class OpTracker { class RemoveOnDelete { OpTracker *tracker; public: RemoveOnDelete(OpTracker *tracker) : tracker(tracker) {} void operator()(TrackedOp *op); }; friend class RemoveOnDelete; friend class OpHistory; uint64_t seq; Mutex ops_in_flight_lock; xlist ops_in_flight; OpHistory history; float complaint_time; int log_threshold; public: bool tracking_enabled; CephContext *cct; OpTracker(CephContext *cct_, bool tracking) : seq(0), ops_in_flight_lock("OpTracker mutex"), complaint_time(0), log_threshold(0), tracking_enabled(tracking), cct(cct_) {} void set_complaint_and_threshold(float time, int threshold) { complaint_time = time; log_threshold = threshold; } void set_history_size_and_duration(uint32_t new_size, uint32_t new_duration) { history.set_size_and_duration(new_size, new_duration); } void dump_ops_in_flight(Formatter *f); void dump_historic_ops(Formatter *f); void register_inflight_op(xlist::item *i); void unregister_inflight_op(TrackedOp *i); void get_age_ms_histogram(pow2_hist_t *h); /** * Look for Ops which are too old, and insert warning * strings for each Op that is too old. * * @param warning_strings A vector reference which is filled * with a warning string for each old Op. * @return True if there are any Ops to warn on, false otherwise. */ bool check_ops_in_flight(std::vector &warning_strings); void mark_event(TrackedOp *op, const string &evt); void _mark_event(TrackedOp *op, const string &evt, utime_t now); void on_shutdown() { Mutex::Locker l(ops_in_flight_lock); history.on_shutdown(); } ~OpTracker() { assert(ops_in_flight.empty()); } template typename T::Ref create_request(Message *ref) { typename T::Ref retval(new T(ref, this), RemoveOnDelete(this)); _mark_event(retval.get(), "header_read", ref->get_recv_stamp()); _mark_event(retval.get(), "throttled", ref->get_throttle_stamp()); _mark_event(retval.get(), "all_read", ref->get_recv_complete_stamp()); _mark_event(retval.get(), "dispatched", ref->get_dispatch_stamp()); retval->init_from_message(); return retval; } }; class TrackedOp { private: friend class OpHistory; friend class OpTracker; xlist::item xitem; protected: Message *request; /// the logical request we are tracking OpTracker *tracker; /// the tracker we are associated with list > events; /// list of events and their times Mutex lock; /// to protect the events list string current; /// the current state the event is in uint64_t seq; /// a unique value set by the OpTracker uint32_t warn_interval_multiplier; // limits output of a given op warning TrackedOp(Message *req, OpTracker *_tracker) : xitem(this), request(req), tracker(_tracker), lock("TrackedOp::lock"), seq(0), warn_interval_multiplier(1) { tracker->register_inflight_op(&xitem); } virtual void init_from_message() {} /// output any type-specific data you want to get when dump() is called virtual void _dump(utime_t now, Formatter *f) const {} /// if you want something else to happen when events are marked, implement virtual void _event_marked() {} public: virtual ~TrackedOp() { assert(request); request->put(); } utime_t get_arrived() const { return request->get_recv_stamp(); } // This function maybe needs some work; assumes last event is completion time double get_duration() const { return events.size() ? (events.rbegin()->first - get_arrived()) : 0.0; } Message *get_req() const { return request; } void mark_event(const string &event); virtual const char *state_string() const { return events.rbegin()->second.c_str(); } void dump(utime_t now, Formatter *f) const; }; #endif ceph-0.80.11/src/common/sharedptr_registry.hpp0000664000175100017510000001011212623076744023404 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SHAREDPTR_REGISTRY_H #define CEPH_SHAREDPTR_REGISTRY_H #include #include #include "common/Mutex.h" #include "common/Cond.h" /** * Provides a registry of shared_ptr indexed by K while * the references are alive. */ template class SharedPtrRegistry { public: typedef ceph::shared_ptr VPtr; typedef ceph::weak_ptr WeakVPtr; int waiting; private: Mutex lock; Cond cond; map > contents; class OnRemoval { SharedPtrRegistry *parent; K key; public: OnRemoval(SharedPtrRegistry *parent, K key) : parent(parent), key(key) {} void operator()(V *to_remove) { { Mutex::Locker l(parent->lock); typename map >::iterator i = parent->contents.find(key); if (i != parent->contents.end() && i->second.second == to_remove) { parent->contents.erase(i); parent->cond.Signal(); } } delete to_remove; } }; friend class OnRemoval; public: SharedPtrRegistry() : waiting(0), lock("SharedPtrRegistry::lock") {} bool empty() { Mutex::Locker l(lock); return contents.empty(); } bool get_next(const K &key, pair *next) { pair r; { Mutex::Locker l(lock); VPtr next_val; typename map >::iterator i = contents.upper_bound(key); while (i != contents.end() && !(next_val = i->second.first.lock())) ++i; if (i == contents.end()) return false; if (next) r = make_pair(i->first, next_val); } if (next) *next = r; return true; } bool get_next(const K &key, pair *next) { VPtr next_val; Mutex::Locker l(lock); typename map >::iterator i = contents.upper_bound(key); while (i != contents.end() && !(next_val = i->second.first.lock())) ++i; if (i == contents.end()) return false; if (next) *next = make_pair(i->first, *next_val); return true; } VPtr lookup(const K &key) { Mutex::Locker l(lock); waiting++; while (1) { typename map >::iterator i = contents.find(key); if (i != contents.end()) { VPtr retval = i->second.first.lock(); if (retval) { waiting--; return retval; } } else { break; } cond.Wait(lock); } waiting--; return VPtr(); } VPtr lookup_or_create(const K &key) { Mutex::Locker l(lock); waiting++; while (1) { typename map >::iterator i = contents.find(key); if (i != contents.end()) { VPtr retval = i->second.first.lock(); if (retval) { waiting--; return retval; } } else { break; } cond.Wait(lock); } V *ptr = new V(); VPtr retval(ptr, OnRemoval(this, key)); contents.insert(make_pair(key, make_pair(retval, ptr))); waiting--; return retval; } unsigned size() { Mutex::Locker l(lock); return contents.size(); } void remove(const K &key) { Mutex::Locker l(lock); contents.erase(key); cond.Signal(); } template VPtr lookup_or_create(const K &key, const A &arg) { Mutex::Locker l(lock); waiting++; while (1) { typename map >::iterator i = contents.find(key); if (i != contents.end()) { VPtr retval = i->second.first.lock(); if (retval) { waiting--; return retval; } } else { break; } cond.Wait(lock); } V *ptr = new V(arg); VPtr retval(ptr, OnRemoval(this, key)); contents.insert(make_pair(key, make_pair(retval, ptr))); waiting--; return retval; } friend class SharedPtrRegistryTest; }; #endif ceph-0.80.11/src/common/linux_version.c0000664000175100017510000000064212623076744022026 0ustar jenkins-buildjenkins-build#include "common/linux_version.h" #include #include #include int get_linux_version(void) { struct utsname ubuf; int a, b, c; int n; if (uname(&ubuf) || strcmp(ubuf.sysname, "Linux")) return 0; n = sscanf(ubuf.release, "%d.%d.%d", &a, &b, &c); switch (n) { case 3: return KERNEL_VERSION(a, b, c); case 2: return KERNEL_VERSION(a, b, 0); default: return 0; } } ceph-0.80.11/src/common/RefCountedObj.h0000664000175100017510000000540112623076744021616 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_REFCOUNTEDOBJ_H #define CEPH_REFCOUNTEDOBJ_H #include "common/Mutex.h" #include "common/Cond.h" #include "include/atomic.h" struct RefCountedObject { atomic_t nref; RefCountedObject() : nref(1) {} virtual ~RefCountedObject() {} RefCountedObject *get() { //generic_dout(0) << "RefCountedObject::get " << this << " " << nref.read() << " -> " << (nref.read() + 1) << dendl; nref.inc(); return this; } void put() { //generic_dout(0) << "RefCountedObject::put " << this << " " << nref.read() << " -> " << (nref.read() - 1) << dendl; if (nref.dec() == 0) delete this; } }; /** * RefCountedCond * * a refcounted condition, will be removed when all references are dropped */ struct RefCountedCond : public RefCountedObject { bool complete; Mutex lock; Cond cond; int rval; RefCountedCond() : complete(false), lock("RefCountedCond"), rval(0) {} int wait() { Mutex::Locker l(lock); while (!complete) { cond.Wait(lock); } return rval; } void done(int r) { Mutex::Locker l(lock); rval = r; complete = true; cond.SignalAll(); } void done() { done(0); } }; /** * RefCountedWaitObject * * refcounted object that allows waiting for the object's last reference. * Any referrer can either put or put_wait(). A simple put() will return * immediately, a put_wait() will return only when the object is destroyed. * e.g., useful when we want to wait for a specific event completion. We * use RefCountedCond, as the condition can be referenced after the object * destruction. * */ struct RefCountedWaitObject { atomic_t nref; RefCountedCond *c; RefCountedWaitObject() : nref(1) { c = new RefCountedCond; } virtual ~RefCountedWaitObject() { c->put(); } RefCountedWaitObject *get() { nref.inc(); return this; } bool put() { bool ret = false; RefCountedCond *cond = c; cond->get(); if (nref.dec() == 0) { cond->done(); delete this; ret = true; } cond->put(); return ret; } void put_wait() { RefCountedCond *cond = c; cond->get(); if (nref.dec() == 0) { cond->done(); delete this; } else { cond->wait(); } cond->put(); } }; void intrusive_ptr_add_ref(RefCountedObject *p); void intrusive_ptr_release(RefCountedObject *p); #endif ceph-0.80.11/src/common/ipaddr.cc0000664000175100017510000000700512623076744020530 0ustar jenkins-buildjenkins-build#include "include/ipaddr.h" #include #include #include static void netmask_ipv4(const struct in_addr *addr, unsigned int prefix_len, struct in_addr *out) { uint32_t mask; if (prefix_len >= 32) { // also handle 32 in this branch, because >>32 is not defined by // the C standards mask = ~uint32_t(0); } else { mask = htonl(~(~uint32_t(0) >> prefix_len)); } out->s_addr = addr->s_addr & mask; } const struct sockaddr *find_ipv4_in_subnet(const struct ifaddrs *addrs, const struct sockaddr_in *net, unsigned int prefix_len) { struct in_addr want, temp; netmask_ipv4(&net->sin_addr, prefix_len, &want); for (; addrs != NULL; addrs = addrs->ifa_next) { if (addrs->ifa_addr == NULL) continue; if (addrs->ifa_addr->sa_family != net->sin_family) continue; struct in_addr *cur = &((struct sockaddr_in*)addrs->ifa_addr)->sin_addr; netmask_ipv4(cur, prefix_len, &temp); if (temp.s_addr == want.s_addr) { return addrs->ifa_addr; } } return NULL; } static void netmask_ipv6(const struct in6_addr *addr, unsigned int prefix_len, struct in6_addr *out) { if (prefix_len > 128) prefix_len = 128; memcpy(out->s6_addr, addr->s6_addr, prefix_len/8); if (prefix_len < 128) out->s6_addr[prefix_len/8] = addr->s6_addr[prefix_len/8] & ~( 0xFF >> (prefix_len % 8) ); if (prefix_len/8 < 15) memset(out->s6_addr+prefix_len/8+1, 0, 16-prefix_len/8-1); } const struct sockaddr *find_ipv6_in_subnet(const struct ifaddrs *addrs, const struct sockaddr_in6 *net, unsigned int prefix_len) { struct in6_addr want, temp; netmask_ipv6(&net->sin6_addr, prefix_len, &want); for (; addrs != NULL; addrs = addrs->ifa_next) { if (addrs->ifa_addr == NULL) continue; if (addrs->ifa_addr->sa_family != net->sin6_family) continue; struct in6_addr *cur = &((struct sockaddr_in6*)addrs->ifa_addr)->sin6_addr; netmask_ipv6(cur, prefix_len, &temp); if (IN6_ARE_ADDR_EQUAL(&temp, &want)) return addrs->ifa_addr; } return NULL; } const struct sockaddr *find_ip_in_subnet(const struct ifaddrs *addrs, const struct sockaddr *net, unsigned int prefix_len) { switch (net->sa_family) { case AF_INET: return find_ipv4_in_subnet(addrs, (struct sockaddr_in*)net, prefix_len); case AF_INET6: return find_ipv6_in_subnet(addrs, (struct sockaddr_in6*)net, prefix_len); } return NULL; } bool parse_network(const char *s, struct sockaddr *network, unsigned int *prefix_len) { char *slash = strchr((char*)s, '/'); if (!slash) { // no slash return false; } if (*(slash+1) == '\0') { // slash is the last character return false; } char *end; long int num = strtol(slash+1, &end, 10); if (*end != '\0') { // junk after the prefix_len return false; } if (num < 0) { return false; } *prefix_len = num; // copy the part before slash to get nil termination char *addr = (char*)alloca(slash-s + 1); strncpy(addr, s, slash-s); addr[slash-s] = '\0'; // caller expects ports etc to be zero memset(network, 0, sizeof(*network)); // try parsing as ipv4 int ok; ok = inet_pton(AF_INET, addr, &((struct sockaddr_in*)network)->sin_addr); if (ok) { network->sa_family = AF_INET; return true; } // try parsing as ipv6 ok = inet_pton(AF_INET6, addr, &((struct sockaddr_in6*)network)->sin6_addr); if (ok) { network->sa_family = AF_INET6; return true; } return false; } ceph-0.80.11/src/common/SloppyCRCMap.h0000664000175100017510000000366012623076744021406 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_COMMON_SLOPPYCRCMAP_H #define CEPH_COMMON_SLOPPYCRCMAP_H #include "include/types.h" #include "include/encoding.h" #include #include /** * SloppyCRCMap * * Opportunistically track CRCs on any reads or writes that cover full * blocks. Verify read results when we have CRC data available for * the given extent. */ class SloppyCRCMap { static const int crc_iv = 0xffffffff; std::map crc_map; // offset -> crc(-1) uint32_t block_size; uint32_t zero_crc; public: SloppyCRCMap(uint32_t b=0) { set_block_size(b); } void set_block_size(uint32_t b) { block_size = b; //zero_crc = ceph_crc32c(0xffffffff, NULL, block_size); if (b) { bufferlist bl; bufferptr bp(block_size); bp.zero(); bl.append(bp); zero_crc = bl.crc32c(crc_iv); } else { zero_crc = crc_iv; } } /// update based on a write void write(uint64_t offset, uint64_t len, const bufferlist& bl, std::ostream *out = NULL); /// update based on a truncate void truncate(uint64_t offset); /// update based on a zero/punch_hole void zero(uint64_t offset, uint64_t len); /// update based on a zero/punch_hole void clone_range(uint64_t offset, uint64_t len, uint64_t srcoff, const SloppyCRCMap& src, std::ostream *out = NULL); /** * validate a read result * * @param offset offset * @param length length * @param bl data read * @param err option ostream to describe errors in detail * @returns error count, 0 for success */ int read(uint64_t offset, uint64_t len, const bufferlist& bl, std::ostream *err); void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(SloppyCRCMap) #endif ceph-0.80.11/src/common/xattr.c0000664000175100017510000001255312623076744020270 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * Copyright (C) 2011 Stanislav Sedov * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #if defined(__FreeBSD__) #include #include #include #include #include #include #elif defined(__linux__) #include #include #elif defined(DARWIN) #include #else #error "Your system is not supported!" #endif #include "common/xattr.h" /* * Sets extended attribute on a file. * Returns 0 on success, -1 on failure. */ int ceph_os_setxattr(const char *path, const char *name, const void *value, size_t size) { int error = -1; #if defined(__FreeBSD__) error = extattr_set_file(path, EXTATTR_NAMESPACE_USER, name, value, size); if (error > 0) error = 0; #elif defined(__linux__) || defined(DARWIN) error = setxattr(path, name, value, size, 0); #endif return (error); } int ceph_os_fsetxattr(int fd, const char *name, const void *value, size_t size) { int error = -1; #if defined(__FreeBSD__) error = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, name, value, size); if (error > 0) error = 0; #elif defined(__linux__) || defined(DARWIN) error = fsetxattr(fd, name, value, size, 0); #endif return (error); } ssize_t ceph_os_getxattr(const char *path, const char *name, void *value, size_t size) { ssize_t error = -1; #if defined(__FreeBSD__) if (value == NULL || size == 0) { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } else { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, NULL, 0); if (error > 0) { if (error > size) { errno = ERANGE; error = -1; } else { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } } } #elif defined(__linux__) error = getxattr(path, name, value, size); #elif defined(DARWIN) error = getxattr(path, name, value, size, 0); #endif return (error); } ssize_t ceph_os_fgetxattr(int fd, const char *name, void *value, size_t size) { ssize_t error = -1; #if defined(__FreeBSD__) if (value == NULL || size == 0) { error = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, value, size); } else { error = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, NULL, 0); if (error > 0) { if (error > size) { errno = ERANGE; error = -1; } else { error = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, value, size); } } } #elif defined(__linux__) error = fgetxattr(fd, name, value, size); #elif defined(DARWIN) error = fgetxattr(fd, name, value, size, 0); #endif return (error); } ssize_t ceph_os_listxattr(const char *path, char *list, size_t size) { ssize_t error = -1; #if defined(__FreeBSD__) /* * XXX. The format of the list FreeBSD returns differs * from the Linux ones. We have to perform the conversion. :-( */ char *newlist, *p, *p1; if (size != 0) { newlist = malloc(size); if (newlist != NULL) { error = extattr_list_file(path, EXTATTR_NAMESPACE_USER, newlist, size); if (error > 0) { p = newlist; p1 = list; while ((p - newlist) < error) { uint8_t len = *(uint8_t *)p; p++; if ((p + len - newlist) > error) break; if (len > 0) { bcopy(p, p1, len); p += len; p1 += len; *p1++ = '\0'; } } error = p1 - list; } free(newlist); } } else { error = extattr_list_file(path, EXTATTR_NAMESPACE_USER, list, size); } #elif defined(__linux__) error = listxattr(path, list, size); #elif defined(DARWIN) error = listxattr(path, list, size, 0); #endif return (error); } ssize_t ceph_os_flistxattr(int fd, char *list, size_t size) { ssize_t error = -1; #if defined(__FreeBSD__) /* * XXX. The format of the list FreeBSD returns differs * from the Linux ones. We have to perform the conversion. :-( */ char *newlist, *p, *p1; if (size != 0) { newlist = malloc(size); if (newlist != NULL) { error = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, newlist, size); if (error > 0) { p = newlist; p1 = list; while ((p - newlist) < error) { uint8_t len = *(uint8_t *)p; p++; if ((p + len - newlist) > error) break; if (len > 0) { bcopy(p, p1, len); p += len; p1 += len; *p1++ = '\0'; } } error = p1 - list; } free(newlist); } } else { error = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, list, size); } #elif defined(__linux__) error = flistxattr(fd, list, size); #elif defined(DARWIN) error = flistxattr(fd, list, size, 0); #endif return (error); } int ceph_os_removexattr(const char *path, const char *name) { int error = -1; #if defined(__FreeBSD__) error = extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name); #elif defined(__linux__) error = removexattr(path, name); #elif defined(DARWIN) error = removexattr(path, name, 0); #endif return (error); } int ceph_os_fremovexattr(int fd, const char *name) { int error = -1; #if defined(__FreeBSD__) error = extattr_delete_fd(fd, EXTATTR_NAMESPACE_USER, name); #elif defined(__linux__) error = fremovexattr(fd, name); #elif defined(DARWIN) error = fremovexattr(fd, name, 0); #endif return (error); } ceph-0.80.11/src/common/admin_socket_client.h0000664000175100017510000000164012623076744023124 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_ADMIN_SOCKET_CLIENT_H #define CEPH_COMMON_ADMIN_SOCKET_CLIENT_H #include #include /* This is a simple client that talks to an AdminSocket using blocking I/O. * We put a 5-second timeout on send and recv operations. */ class AdminSocketClient { public: AdminSocketClient(const std::string &path); std::string do_request(std::string request, std::string *result); std::string ping(bool *ok); private: std::string m_path; }; const char* get_rand_socket_path(); #endif ceph-0.80.11/src/common/assert.cc0000664000175100017510000000510012623076744020560 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2008-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "BackTrace.h" #include "common/ceph_context.h" #include "common/config.h" #include "common/debug.h" #include "common/Clock.h" #include "include/assert.h" #include #include #include #include #include namespace ceph { static CephContext *g_assert_context = NULL; /* If you register an assert context, assert() will try to lock the dout * stream of that context before starting an assert. This is nice because the * output looks better. Your assert will not be interleaved with other dout * statements. * * However, this is strictly optional and library code currently does not * register an assert context. The extra complexity of supporting this * wouldn't really be worth it. */ void register_assert_context(CephContext *cct) { assert(!g_assert_context); g_assert_context = cct; } void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *func) { ostringstream tss; tss << ceph_clock_now(g_assert_context); char buf[8096]; BackTrace *bt = new BackTrace(1); snprintf(buf, sizeof(buf), "%s: In function '%s' thread %llx time %s\n" "%s: %d: FAILED assert(%s)\n", file, func, (unsigned long long)pthread_self(), tss.str().c_str(), file, line, assertion); dout_emergency(buf); // TODO: get rid of this memory allocation. ostringstream oss; bt->print(oss); dout_emergency(oss.str()); dout_emergency(" NOTE: a copy of the executable, or `objdump -rdS ` " "is needed to interpret this.\n"); if (g_assert_context) { lderr(g_assert_context) << buf << std::endl; bt->print(*_dout); *_dout << " NOTE: a copy of the executable, or `objdump -rdS ` " << "is needed to interpret this.\n" << dendl; g_assert_context->_log->dump_recent(); } throw FailedAssertion(bt); } void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *func) { char buf[8096]; snprintf(buf, sizeof(buf), "WARNING: assert(%s) at: %s: %d: %s()\n", assertion, file, line, func); dout_emergency(buf); } } ceph-0.80.11/src/common/static_assert.h0000664000175100017510000000132412623076744021775 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_STATIC_ASSERT #define CEPH_COMMON_STATIC_ASSERT /* Create a compiler error if condition is false. * Also produce a result of value 0 and type size_t. * This expression can be used anywhere, even in structure initializers. */ #define STATIC_ASSERT(x) (sizeof(int[((x)==0) ? -1 : 0])) #endif ceph-0.80.11/src/common/simple_spin.h0000664000175100017510000000224312623076744021450 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SIMPLE_SPIN_H #define CEPH_SIMPLE_SPIN_H /* This is a simple spinlock implementation based on atomic compare-and-swap. * Like all spinlocks, it is intended to protect short, simple critical * sections. It is signal-safe. Unlike pthread_spin_lock and friends, it has a * static initializer so you can write: * * simple_spinlock_t my_spinlock = SIMPLE_SPINLOCK_INITIALIZER * * This allows you to use the lock anywhere you want-- even in global * constructors. Since simple_spinlock_t is a primitive type, it will start out * correctly initialized. */ #include typedef uint32_t simple_spinlock_t; #define SIMPLE_SPINLOCK_INITIALIZER 0 void simple_spin_lock(simple_spinlock_t *lock); void simple_spin_unlock(simple_spinlock_t *lock); #endif ceph-0.80.11/src/common/strtol.cc0000664000175100017510000000772712623076744020627 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include extern "C" { #include } using std::ostringstream; long long strict_strtoll(const char *str, int base, std::string *err) { char *endptr; errno = 0; /* To distinguish success/failure after call (see man page) */ long long ret = strtoll(str, &endptr, base); if ((errno == ERANGE && (ret == LLONG_MAX || ret == LLONG_MIN)) || (errno != 0 && ret == 0)) { ostringstream oss; oss << "strict_strtoll: integer underflow or overflow parsing '" << str << "'"; *err = oss.str(); return 0; } if (endptr == str) { ostringstream oss; oss << "strict_strtoll: expected integer, got: '" << str << "'"; *err = oss.str(); return 0; } if (*endptr != '\0') { ostringstream oss; oss << "strict_strtoll: garbage at end of string. got: '" << str << "'"; *err = oss.str(); return 0; } *err = ""; return ret; } int strict_strtol(const char *str, int base, std::string *err) { long long ret = strict_strtoll(str, base, err); if (!err->empty()) return 0; if (ret <= INT_MIN) { ostringstream oss; oss << "strict_strtol: integer underflow parsing '" << str << "'"; *err = oss.str(); return 0; } if (ret >= INT_MAX) { ostringstream oss; oss << "strict_strtol: integer overflow parsing '" << str << "'"; *err = oss.str(); return 0; } return static_cast(ret); } double strict_strtod(const char *str, std::string *err) { char *endptr; errno = 0; /* To distinguish success/failure after call (see man page) */ double ret = strtod(str, &endptr); if (errno == ERANGE) { ostringstream oss; oss << "strict_strtod: floating point overflow or underflow parsing '" << str << "'"; *err = oss.str(); return 0.0; } if (endptr == str) { ostringstream oss; oss << "strict_strtod: expected double, got: '" << str << "'"; *err = oss.str(); return 0; } if (*endptr != '\0') { ostringstream oss; oss << "strict_strtod: garbage at end of string. got: '" << str << "'"; *err = oss.str(); return 0; } *err = ""; return ret; } float strict_strtof(const char *str, std::string *err) { char *endptr; errno = 0; /* To distinguish success/failure after call (see man page) */ float ret = strtof(str, &endptr); if (errno == ERANGE) { ostringstream oss; oss << "strict_strtof: floating point overflow or underflow parsing '" << str << "'"; *err = oss.str(); return 0.0; } if (endptr == str) { ostringstream oss; oss << "strict_strtof: expected float, got: '" << str << "'"; *err = oss.str(); return 0; } if (*endptr != '\0') { ostringstream oss; oss << "strict_strtof: garbage at end of string. got: '" << str << "'"; *err = oss.str(); return 0; } *err = ""; return ret; } uint64_t strict_sistrtoll(const char *str, std::string *err) { std::string s(str); if (s.size() == 0) { ostringstream oss; oss << "strict_sistrtoll: value not specified"; *err = oss.str(); return 0; } const char &u = s.at(s.size()-1); //str[std::strlen(str)-1]; int m = 0; if (u == 'B') m = 0; else if (u == 'K') m = 10; else if (u == 'M') m = 20; else if (u == 'G') m = 30; else if (u == 'T') m = 40; else if (u == 'P') m = 50; else if (u == 'E') m = 60; else m = -1; const char *v = NULL; if (m >= 0) s = std::string(str, s.size()-1); v = s.c_str(); uint64_t r = strict_strtoll(v, 10, err); if (err->empty() && m > 0) { r = (r << m); } return r; } ceph-0.80.11/src/common/crc32c_intel_fast_asm.S0000664000175100017510000006310512623076744023234 0ustar jenkins-buildjenkins-build; ; Copyright 2012-2013 Intel Corporation All Rights Reserved. ; All rights reserved. ; ; http://opensource.org/licenses/BSD-3-Clause ; ; 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 the Intel Corporation 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 HOLDER 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. ; ; Function to compute iscsi CRC32 with table-based recombination ; crc done "by 3" with block sizes 1920, 960, 480, 240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; crcB3 MACRO to implement crc32 on 3 %%bSize-byte blocks %macro crcB3 3 %define %%bSize %1 ; 1/3 of buffer size %define %%td2 %2 ; table offset for crc0 (2/3 of buffer) %define %%td1 %3 ; table offset for crc1 (1/3 of buffer) %IF %%bSize=640 sub len, %%bSize*3 js %%crcB3_end ;; jump to next level if 3*blockSize > len %ELSE cmp len, %%bSize*3 jnae %%crcB3_end ;; jump to next level if 3*blockSize > len %ENDIF ;;;;;; Calculate CRC of 3 blocks of the buffer ;;;;;; %%crcB3_loop: ;; rax = crc0 = initial crc xor rbx, rbx ;; rbx = crc1 = 0; xor r10, r10 ;; r10 = crc2 = 0; %assign i 0 %rep %%bSize/8 - 1 crc32 rax, [bufptmp+i + 0*%%bSize] ;; update crc0 crc32 rbx, [bufptmp+i + 1*%%bSize] ;; update crc1 crc32 r10, [bufptmp+i + 2*%%bSize] ;; update crc2 %assign i (i+8) %endrep crc32 rax, [bufptmp+i + 0*%%bSize] ;; update crc0 crc32 rbx, [bufptmp+i + 1*%%bSize] ;; update crc1 ; SKIP ;crc32 r10, [bufptmp+i + 2*%%bSize] ;; update crc2 ; merge in crc0 movzx bufp_dw, al mov r9d, [crc_init + bufp*4 + %%td2] movzx bufp_dw, ah shr eax, 16 mov r11d, [crc_init + bufp*4 + %%td2] shl r11, 8 xor r9, r11 movzx bufp_dw, al mov r11d, [crc_init + bufp*4 + %%td2] movzx bufp_dw, ah shl r11, 16 xor r9, r11 mov r11d, [crc_init + bufp*4 + %%td2] shl r11, 24 xor r9, r11 ; merge in crc1 movzx bufp_dw, bl mov r11d, [crc_init + bufp*4 + %%td1] movzx bufp_dw, bh shr ebx, 16 xor r9, r11 mov r11d, [crc_init + bufp*4 + %%td1] shl r11, 8 xor r9, r11 movzx bufp_dw, bl mov r11d, [crc_init + bufp*4 + %%td1] movzx bufp_dw, bh shl r11, 16 xor r9, r11 mov r11d, [crc_init + bufp*4 + %%td1] shl r11, 24 xor r9, r11 xor r9, [bufptmp+i + 2*%%bSize] crc32 r10, r9 mov rax, r10 add bufptmp, %%bSize*3 ;; move to next block sub len, %%bSize*3 %IF %%bSize=640 jns %%crcB3_loop %ENDIF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %%crcB3_end: %IF %%bSize=640 add len, %%bSize*3 %ENDIF je do_return ;; return if remaining data is zero %endmacro ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ISCSI CRC 32 Implementation with crc32 Instruction ;;; unsigned int crc32_iscsi_00(unsigned char * buffer, int len, unsigned int crc_init); ;;; ;;; *buf = rcx ;;; len = rdx ;;; crc_init = r8 ;;; global crc32_iscsi_00:function crc32_iscsi_00: %ifidn __OUTPUT_FORMAT__, elf64 %define bufp rdi %define bufp_dw edi %define bufp_w di %define bufp_b dil %define bufptmp rcx %define block_0 rcx %define block_1 r8 %define block_2 r11 %define len rsi %define len_dw esi %define len_w si %define len_b sil %define crc_init rdx %define crc_init_dw edx %else %define bufp rcx %define bufp_dw ecx %define bufp_w cx %define bufp_b cl %define bufptmp rdi %define block_0 rdi %define block_1 rsi %define block_2 r11 %define len rdx %define len_dw edx %define len_w dx %define len_b dl %define crc_init r8 %define crc_init_dw r8d %endif push rdi push rbx mov rax, crc_init ;; rax = crc_init; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 1) ALIGN: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov bufptmp, bufp ;; rdi = *buf neg bufp and bufp, 7 ;; calculate the unalignment ;; amount of the address je proc_block ;; Skip if aligned cmp len, 8 jb less_than_8 ;;;; Calculate CRC of unaligned bytes of the buffer (if any) ;;;; mov rbx, [bufptmp] ;; load a quadword from the buffer add bufptmp, bufp ;; align buffer pointer for ;; quadword processing sub len, bufp ;; update buffer length align_loop: crc32 eax, bl ;; compute crc32 of 1-byte shr rbx, 8 ;; get next byte dec bufp jne align_loop ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 2) BLOCK LEVEL: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; proc_block: cmp len, 240 jb bit8 lea crc_init, [mul_table_72 wrt rip] ;; load table base address crcB3 640, 0x1000, 0x0c00 ; 640*3 = 1920 (Tables 1280, 640) crcB3 320, 0x0c00, 0x0800 ; 320*3 = 960 (Tables 640, 320) crcB3 160, 0x0800, 0x0400 ; 160*3 = 480 (Tables 320, 160) crcB3 80, 0x0400, 0x0000 ; 80*3 = 240 (Tables 160, 80) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;4) LESS THAN 256-bytes REMAIN AT THIS POINT (8-bits of rdx are full) bit8: shl len_b, 1 ;; shift-out MSB (bit-7) jnc bit7 ;; jump to bit-6 if bit-7 == 0 %assign i 0 %rep 16 crc32 rax, [bufptmp+i] ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero add bufptmp, 128 ;; buf +=64; (next 64 bytes) bit7: shl len_b, 1 ;; shift-out MSB (bit-7) jnc bit6 ;; jump to bit-6 if bit-7 == 0 %assign i 0 %rep 8 crc32 rax, [bufptmp+i] ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero add bufptmp, 64 ;; buf +=64; (next 64 bytes) bit6: shl len_b, 1 ;; shift-out MSB (bit-6) jnc bit5 ;; jump to bit-5 if bit-6 == 0 %assign i 0 %rep 4 crc32 rax, [bufptmp+i] ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero add bufptmp, 32 ;; buf +=32; (next 32 bytes) bit5: shl len_b, 1 ;; shift-out MSB (bit-5) jnc bit4 ;; jump to bit-4 if bit-5 == 0 %assign i 0 %rep 2 crc32 rax, [bufptmp+i] ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero add bufptmp, 16 ;; buf +=16; (next 16 bytes) bit4: shl len_b, 1 ;; shift-out MSB (bit-4) jnc bit3 ;; jump to bit-3 if bit-4 == 0 crc32 rax, [bufptmp] ;; compute crc32 of 8-byte data je do_return ;; return if remaining data is zero add bufptmp, 8 ;; buf +=8; (next 8 bytes) bit3: mov rbx, [bufptmp] ;; load a 8-bytes from the buffer: shl len_b, 1 ;; shift-out MSB (bit-3) jnc bit2 ;; jump to bit-2 if bit-3 == 0 crc32 eax, ebx ;; compute crc32 of 4-byte data je do_return ;; return if remaining data is zero shr rbx, 32 ;; get next 3 bytes bit2: shl len_b, 1 ;; shift-out MSB (bit-2) jnc bit1 ;; jump to bit-1 if bit-2 == 0 crc32 eax, bx ;; compute crc32 of 2-byte data je do_return ;; return if remaining data is zero shr rbx, 16 ;; next byte bit1: test len_b,len_b je do_return crc32 eax, bl ;; compute crc32 of 1-byte data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do_return: pop rbx pop rdi ret less_than_8: test len,4 jz less_than_4 crc32 eax, dword[bufptmp] add bufptmp,4 less_than_4: test len,2 jz less_than_2 crc32 eax, word[bufptmp] add bufptmp,2 less_than_2: test len,1 jz do_return crc32 rax, byte[bufptmp] pop rbx pop bufptmp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; global mul_table_72, mul_table_152, mul_table_312, mul_table_632, mul_table_1272 section .data align 8 mul_table_72: DD 0x00000000,0x39d3b296,0x73a7652c,0x4a74d7ba DD 0xe74eca58,0xde9d78ce,0x94e9af74,0xad3a1de2 DD 0xcb71e241,0xf2a250d7,0xb8d6876d,0x810535fb DD 0x2c3f2819,0x15ec9a8f,0x5f984d35,0x664bffa3 DD 0x930fb273,0xaadc00e5,0xe0a8d75f,0xd97b65c9 DD 0x7441782b,0x4d92cabd,0x07e61d07,0x3e35af91 DD 0x587e5032,0x61ade2a4,0x2bd9351e,0x120a8788 DD 0xbf309a6a,0x86e328fc,0xcc97ff46,0xf5444dd0 DD 0x23f31217,0x1a20a081,0x5054773b,0x6987c5ad DD 0xc4bdd84f,0xfd6e6ad9,0xb71abd63,0x8ec90ff5 DD 0xe882f056,0xd15142c0,0x9b25957a,0xa2f627ec DD 0x0fcc3a0e,0x361f8898,0x7c6b5f22,0x45b8edb4 DD 0xb0fca064,0x892f12f2,0xc35bc548,0xfa8877de DD 0x57b26a3c,0x6e61d8aa,0x24150f10,0x1dc6bd86 DD 0x7b8d4225,0x425ef0b3,0x082a2709,0x31f9959f DD 0x9cc3887d,0xa5103aeb,0xef64ed51,0xd6b75fc7 DD 0x47e6242e,0x7e3596b8,0x34414102,0x0d92f394 DD 0xa0a8ee76,0x997b5ce0,0xd30f8b5a,0xeadc39cc DD 0x8c97c66f,0xb54474f9,0xff30a343,0xc6e311d5 DD 0x6bd90c37,0x520abea1,0x187e691b,0x21addb8d DD 0xd4e9965d,0xed3a24cb,0xa74ef371,0x9e9d41e7 DD 0x33a75c05,0x0a74ee93,0x40003929,0x79d38bbf DD 0x1f98741c,0x264bc68a,0x6c3f1130,0x55eca3a6 DD 0xf8d6be44,0xc1050cd2,0x8b71db68,0xb2a269fe DD 0x64153639,0x5dc684af,0x17b25315,0x2e61e183 DD 0x835bfc61,0xba884ef7,0xf0fc994d,0xc92f2bdb DD 0xaf64d478,0x96b766ee,0xdcc3b154,0xe51003c2 DD 0x482a1e20,0x71f9acb6,0x3b8d7b0c,0x025ec99a DD 0xf71a844a,0xcec936dc,0x84bde166,0xbd6e53f0 DD 0x10544e12,0x2987fc84,0x63f32b3e,0x5a2099a8 DD 0x3c6b660b,0x05b8d49d,0x4fcc0327,0x761fb1b1 DD 0xdb25ac53,0xe2f61ec5,0xa882c97f,0x91517be9 DD 0x8fcc485c,0xb61ffaca,0xfc6b2d70,0xc5b89fe6 DD 0x68828204,0x51513092,0x1b25e728,0x22f655be DD 0x44bdaa1d,0x7d6e188b,0x371acf31,0x0ec97da7 DD 0xa3f36045,0x9a20d2d3,0xd0540569,0xe987b7ff DD 0x1cc3fa2f,0x251048b9,0x6f649f03,0x56b72d95 DD 0xfb8d3077,0xc25e82e1,0x882a555b,0xb1f9e7cd DD 0xd7b2186e,0xee61aaf8,0xa4157d42,0x9dc6cfd4 DD 0x30fcd236,0x092f60a0,0x435bb71a,0x7a88058c DD 0xac3f5a4b,0x95ece8dd,0xdf983f67,0xe64b8df1 DD 0x4b719013,0x72a22285,0x38d6f53f,0x010547a9 DD 0x674eb80a,0x5e9d0a9c,0x14e9dd26,0x2d3a6fb0 DD 0x80007252,0xb9d3c0c4,0xf3a7177e,0xca74a5e8 DD 0x3f30e838,0x06e35aae,0x4c978d14,0x75443f82 DD 0xd87e2260,0xe1ad90f6,0xabd9474c,0x920af5da DD 0xf4410a79,0xcd92b8ef,0x87e66f55,0xbe35ddc3 DD 0x130fc021,0x2adc72b7,0x60a8a50d,0x597b179b DD 0xc82a6c72,0xf1f9dee4,0xbb8d095e,0x825ebbc8 DD 0x2f64a62a,0x16b714bc,0x5cc3c306,0x65107190 DD 0x035b8e33,0x3a883ca5,0x70fceb1f,0x492f5989 DD 0xe415446b,0xddc6f6fd,0x97b22147,0xae6193d1 DD 0x5b25de01,0x62f66c97,0x2882bb2d,0x115109bb DD 0xbc6b1459,0x85b8a6cf,0xcfcc7175,0xf61fc3e3 DD 0x90543c40,0xa9878ed6,0xe3f3596c,0xda20ebfa DD 0x771af618,0x4ec9448e,0x04bd9334,0x3d6e21a2 DD 0xebd97e65,0xd20accf3,0x987e1b49,0xa1ada9df DD 0x0c97b43d,0x354406ab,0x7f30d111,0x46e36387 DD 0x20a89c24,0x197b2eb2,0x530ff908,0x6adc4b9e DD 0xc7e6567c,0xfe35e4ea,0xb4413350,0x8d9281c6 DD 0x78d6cc16,0x41057e80,0x0b71a93a,0x32a21bac DD 0x9f98064e,0xa64bb4d8,0xec3f6362,0xd5ecd1f4 DD 0xb3a72e57,0x8a749cc1,0xc0004b7b,0xf9d3f9ed DD 0x54e9e40f,0x6d3a5699,0x274e8123,0x1e9d33b5 mul_table_152: DD 0x00000000,0x878a92a7,0x0af953bf,0x8d73c118 DD 0x15f2a77e,0x927835d9,0x1f0bf4c1,0x98816666 DD 0x2be54efc,0xac6fdc5b,0x211c1d43,0xa6968fe4 DD 0x3e17e982,0xb99d7b25,0x34eeba3d,0xb364289a DD 0x57ca9df8,0xd0400f5f,0x5d33ce47,0xdab95ce0 DD 0x42383a86,0xc5b2a821,0x48c16939,0xcf4bfb9e DD 0x7c2fd304,0xfba541a3,0x76d680bb,0xf15c121c DD 0x69dd747a,0xee57e6dd,0x632427c5,0xe4aeb562 DD 0xaf953bf0,0x281fa957,0xa56c684f,0x22e6fae8 DD 0xba679c8e,0x3ded0e29,0xb09ecf31,0x37145d96 DD 0x8470750c,0x03fae7ab,0x8e8926b3,0x0903b414 DD 0x9182d272,0x160840d5,0x9b7b81cd,0x1cf1136a DD 0xf85fa608,0x7fd534af,0xf2a6f5b7,0x752c6710 DD 0xedad0176,0x6a2793d1,0xe75452c9,0x60dec06e DD 0xd3bae8f4,0x54307a53,0xd943bb4b,0x5ec929ec DD 0xc6484f8a,0x41c2dd2d,0xccb11c35,0x4b3b8e92 DD 0x5ac60111,0xdd4c93b6,0x503f52ae,0xd7b5c009 DD 0x4f34a66f,0xc8be34c8,0x45cdf5d0,0xc2476777 DD 0x71234fed,0xf6a9dd4a,0x7bda1c52,0xfc508ef5 DD 0x64d1e893,0xe35b7a34,0x6e28bb2c,0xe9a2298b DD 0x0d0c9ce9,0x8a860e4e,0x07f5cf56,0x807f5df1 DD 0x18fe3b97,0x9f74a930,0x12076828,0x958dfa8f DD 0x26e9d215,0xa16340b2,0x2c1081aa,0xab9a130d DD 0x331b756b,0xb491e7cc,0x39e226d4,0xbe68b473 DD 0xf5533ae1,0x72d9a846,0xffaa695e,0x7820fbf9 DD 0xe0a19d9f,0x672b0f38,0xea58ce20,0x6dd25c87 DD 0xdeb6741d,0x593ce6ba,0xd44f27a2,0x53c5b505 DD 0xcb44d363,0x4cce41c4,0xc1bd80dc,0x4637127b DD 0xa299a719,0x251335be,0xa860f4a6,0x2fea6601 DD 0xb76b0067,0x30e192c0,0xbd9253d8,0x3a18c17f DD 0x897ce9e5,0x0ef67b42,0x8385ba5a,0x040f28fd DD 0x9c8e4e9b,0x1b04dc3c,0x96771d24,0x11fd8f83 DD 0xb58c0222,0x32069085,0xbf75519d,0x38ffc33a DD 0xa07ea55c,0x27f437fb,0xaa87f6e3,0x2d0d6444 DD 0x9e694cde,0x19e3de79,0x94901f61,0x131a8dc6 DD 0x8b9beba0,0x0c117907,0x8162b81f,0x06e82ab8 DD 0xe2469fda,0x65cc0d7d,0xe8bfcc65,0x6f355ec2 DD 0xf7b438a4,0x703eaa03,0xfd4d6b1b,0x7ac7f9bc DD 0xc9a3d126,0x4e294381,0xc35a8299,0x44d0103e DD 0xdc517658,0x5bdbe4ff,0xd6a825e7,0x5122b740 DD 0x1a1939d2,0x9d93ab75,0x10e06a6d,0x976af8ca DD 0x0feb9eac,0x88610c0b,0x0512cd13,0x82985fb4 DD 0x31fc772e,0xb676e589,0x3b052491,0xbc8fb636 DD 0x240ed050,0xa38442f7,0x2ef783ef,0xa97d1148 DD 0x4dd3a42a,0xca59368d,0x472af795,0xc0a06532 DD 0x58210354,0xdfab91f3,0x52d850eb,0xd552c24c DD 0x6636ead6,0xe1bc7871,0x6ccfb969,0xeb452bce DD 0x73c44da8,0xf44edf0f,0x793d1e17,0xfeb78cb0 DD 0xef4a0333,0x68c09194,0xe5b3508c,0x6239c22b DD 0xfab8a44d,0x7d3236ea,0xf041f7f2,0x77cb6555 DD 0xc4af4dcf,0x4325df68,0xce561e70,0x49dc8cd7 DD 0xd15deab1,0x56d77816,0xdba4b90e,0x5c2e2ba9 DD 0xb8809ecb,0x3f0a0c6c,0xb279cd74,0x35f35fd3 DD 0xad7239b5,0x2af8ab12,0xa78b6a0a,0x2001f8ad DD 0x9365d037,0x14ef4290,0x999c8388,0x1e16112f DD 0x86977749,0x011de5ee,0x8c6e24f6,0x0be4b651 DD 0x40df38c3,0xc755aa64,0x4a266b7c,0xcdacf9db DD 0x552d9fbd,0xd2a70d1a,0x5fd4cc02,0xd85e5ea5 DD 0x6b3a763f,0xecb0e498,0x61c32580,0xe649b727 DD 0x7ec8d141,0xf94243e6,0x743182fe,0xf3bb1059 DD 0x1715a53b,0x909f379c,0x1decf684,0x9a666423 DD 0x02e70245,0x856d90e2,0x081e51fa,0x8f94c35d DD 0x3cf0ebc7,0xbb7a7960,0x3609b878,0xb1832adf DD 0x29024cb9,0xae88de1e,0x23fb1f06,0xa4718da1 mul_table_312: DD 0x00000000,0xbac2fd7b,0x70698c07,0xcaab717c DD 0xe0d3180e,0x5a11e575,0x90ba9409,0x2a786972 DD 0xc44a46ed,0x7e88bb96,0xb423caea,0x0ee13791 DD 0x24995ee3,0x9e5ba398,0x54f0d2e4,0xee322f9f DD 0x8d78fb2b,0x37ba0650,0xfd11772c,0x47d38a57 DD 0x6dabe325,0xd7691e5e,0x1dc26f22,0xa7009259 DD 0x4932bdc6,0xf3f040bd,0x395b31c1,0x8399ccba DD 0xa9e1a5c8,0x132358b3,0xd98829cf,0x634ad4b4 DD 0x1f1d80a7,0xa5df7ddc,0x6f740ca0,0xd5b6f1db DD 0xffce98a9,0x450c65d2,0x8fa714ae,0x3565e9d5 DD 0xdb57c64a,0x61953b31,0xab3e4a4d,0x11fcb736 DD 0x3b84de44,0x8146233f,0x4bed5243,0xf12faf38 DD 0x92657b8c,0x28a786f7,0xe20cf78b,0x58ce0af0 DD 0x72b66382,0xc8749ef9,0x02dfef85,0xb81d12fe DD 0x562f3d61,0xecedc01a,0x2646b166,0x9c844c1d DD 0xb6fc256f,0x0c3ed814,0xc695a968,0x7c575413 DD 0x3e3b014e,0x84f9fc35,0x4e528d49,0xf4907032 DD 0xdee81940,0x642ae43b,0xae819547,0x1443683c DD 0xfa7147a3,0x40b3bad8,0x8a18cba4,0x30da36df DD 0x1aa25fad,0xa060a2d6,0x6acbd3aa,0xd0092ed1 DD 0xb343fa65,0x0981071e,0xc32a7662,0x79e88b19 DD 0x5390e26b,0xe9521f10,0x23f96e6c,0x993b9317 DD 0x7709bc88,0xcdcb41f3,0x0760308f,0xbda2cdf4 DD 0x97daa486,0x2d1859fd,0xe7b32881,0x5d71d5fa DD 0x212681e9,0x9be47c92,0x514f0dee,0xeb8df095 DD 0xc1f599e7,0x7b37649c,0xb19c15e0,0x0b5ee89b DD 0xe56cc704,0x5fae3a7f,0x95054b03,0x2fc7b678 DD 0x05bfdf0a,0xbf7d2271,0x75d6530d,0xcf14ae76 DD 0xac5e7ac2,0x169c87b9,0xdc37f6c5,0x66f50bbe DD 0x4c8d62cc,0xf64f9fb7,0x3ce4eecb,0x862613b0 DD 0x68143c2f,0xd2d6c154,0x187db028,0xa2bf4d53 DD 0x88c72421,0x3205d95a,0xf8aea826,0x426c555d DD 0x7c76029c,0xc6b4ffe7,0x0c1f8e9b,0xb6dd73e0 DD 0x9ca51a92,0x2667e7e9,0xeccc9695,0x560e6bee DD 0xb83c4471,0x02feb90a,0xc855c876,0x7297350d DD 0x58ef5c7f,0xe22da104,0x2886d078,0x92442d03 DD 0xf10ef9b7,0x4bcc04cc,0x816775b0,0x3ba588cb DD 0x11dde1b9,0xab1f1cc2,0x61b46dbe,0xdb7690c5 DD 0x3544bf5a,0x8f864221,0x452d335d,0xffefce26 DD 0xd597a754,0x6f555a2f,0xa5fe2b53,0x1f3cd628 DD 0x636b823b,0xd9a97f40,0x13020e3c,0xa9c0f347 DD 0x83b89a35,0x397a674e,0xf3d11632,0x4913eb49 DD 0xa721c4d6,0x1de339ad,0xd74848d1,0x6d8ab5aa DD 0x47f2dcd8,0xfd3021a3,0x379b50df,0x8d59ada4 DD 0xee137910,0x54d1846b,0x9e7af517,0x24b8086c DD 0x0ec0611e,0xb4029c65,0x7ea9ed19,0xc46b1062 DD 0x2a593ffd,0x909bc286,0x5a30b3fa,0xe0f24e81 DD 0xca8a27f3,0x7048da88,0xbae3abf4,0x0021568f DD 0x424d03d2,0xf88ffea9,0x32248fd5,0x88e672ae DD 0xa29e1bdc,0x185ce6a7,0xd2f797db,0x68356aa0 DD 0x8607453f,0x3cc5b844,0xf66ec938,0x4cac3443 DD 0x66d45d31,0xdc16a04a,0x16bdd136,0xac7f2c4d DD 0xcf35f8f9,0x75f70582,0xbf5c74fe,0x059e8985 DD 0x2fe6e0f7,0x95241d8c,0x5f8f6cf0,0xe54d918b DD 0x0b7fbe14,0xb1bd436f,0x7b163213,0xc1d4cf68 DD 0xebaca61a,0x516e5b61,0x9bc52a1d,0x2107d766 DD 0x5d508375,0xe7927e0e,0x2d390f72,0x97fbf209 DD 0xbd839b7b,0x07416600,0xcdea177c,0x7728ea07 DD 0x991ac598,0x23d838e3,0xe973499f,0x53b1b4e4 DD 0x79c9dd96,0xc30b20ed,0x09a05191,0xb362acea DD 0xd028785e,0x6aea8525,0xa041f459,0x1a830922 DD 0x30fb6050,0x8a399d2b,0x4092ec57,0xfa50112c DD 0x14623eb3,0xaea0c3c8,0x640bb2b4,0xdec94fcf DD 0xf4b126bd,0x4e73dbc6,0x84d8aaba,0x3e1a57c1 mul_table_632: DD 0x00000000,0x6b749fb2,0xd6e93f64,0xbd9da0d6 DD 0xa83e0839,0xc34a978b,0x7ed7375d,0x15a3a8ef DD 0x55906683,0x3ee4f931,0x837959e7,0xe80dc655 DD 0xfdae6eba,0x96daf108,0x2b4751de,0x4033ce6c DD 0xab20cd06,0xc05452b4,0x7dc9f262,0x16bd6dd0 DD 0x031ec53f,0x686a5a8d,0xd5f7fa5b,0xbe8365e9 DD 0xfeb0ab85,0x95c43437,0x285994e1,0x432d0b53 DD 0x568ea3bc,0x3dfa3c0e,0x80679cd8,0xeb13036a DD 0x53adecfd,0x38d9734f,0x8544d399,0xee304c2b DD 0xfb93e4c4,0x90e77b76,0x2d7adba0,0x460e4412 DD 0x063d8a7e,0x6d4915cc,0xd0d4b51a,0xbba02aa8 DD 0xae038247,0xc5771df5,0x78eabd23,0x139e2291 DD 0xf88d21fb,0x93f9be49,0x2e641e9f,0x4510812d DD 0x50b329c2,0x3bc7b670,0x865a16a6,0xed2e8914 DD 0xad1d4778,0xc669d8ca,0x7bf4781c,0x1080e7ae DD 0x05234f41,0x6e57d0f3,0xd3ca7025,0xb8beef97 DD 0xa75bd9fa,0xcc2f4648,0x71b2e69e,0x1ac6792c DD 0x0f65d1c3,0x64114e71,0xd98ceea7,0xb2f87115 DD 0xf2cbbf79,0x99bf20cb,0x2422801d,0x4f561faf DD 0x5af5b740,0x318128f2,0x8c1c8824,0xe7681796 DD 0x0c7b14fc,0x670f8b4e,0xda922b98,0xb1e6b42a DD 0xa4451cc5,0xcf318377,0x72ac23a1,0x19d8bc13 DD 0x59eb727f,0x329fedcd,0x8f024d1b,0xe476d2a9 DD 0xf1d57a46,0x9aa1e5f4,0x273c4522,0x4c48da90 DD 0xf4f63507,0x9f82aab5,0x221f0a63,0x496b95d1 DD 0x5cc83d3e,0x37bca28c,0x8a21025a,0xe1559de8 DD 0xa1665384,0xca12cc36,0x778f6ce0,0x1cfbf352 DD 0x09585bbd,0x622cc40f,0xdfb164d9,0xb4c5fb6b DD 0x5fd6f801,0x34a267b3,0x893fc765,0xe24b58d7 DD 0xf7e8f038,0x9c9c6f8a,0x2101cf5c,0x4a7550ee DD 0x0a469e82,0x61320130,0xdcafa1e6,0xb7db3e54 DD 0xa27896bb,0xc90c0909,0x7491a9df,0x1fe5366d DD 0x4b5bc505,0x202f5ab7,0x9db2fa61,0xf6c665d3 DD 0xe365cd3c,0x8811528e,0x358cf258,0x5ef86dea DD 0x1ecba386,0x75bf3c34,0xc8229ce2,0xa3560350 DD 0xb6f5abbf,0xdd81340d,0x601c94db,0x0b680b69 DD 0xe07b0803,0x8b0f97b1,0x36923767,0x5de6a8d5 DD 0x4845003a,0x23319f88,0x9eac3f5e,0xf5d8a0ec DD 0xb5eb6e80,0xde9ff132,0x630251e4,0x0876ce56 DD 0x1dd566b9,0x76a1f90b,0xcb3c59dd,0xa048c66f DD 0x18f629f8,0x7382b64a,0xce1f169c,0xa56b892e DD 0xb0c821c1,0xdbbcbe73,0x66211ea5,0x0d558117 DD 0x4d664f7b,0x2612d0c9,0x9b8f701f,0xf0fbefad DD 0xe5584742,0x8e2cd8f0,0x33b17826,0x58c5e794 DD 0xb3d6e4fe,0xd8a27b4c,0x653fdb9a,0x0e4b4428 DD 0x1be8ecc7,0x709c7375,0xcd01d3a3,0xa6754c11 DD 0xe646827d,0x8d321dcf,0x30afbd19,0x5bdb22ab DD 0x4e788a44,0x250c15f6,0x9891b520,0xf3e52a92 DD 0xec001cff,0x8774834d,0x3ae9239b,0x519dbc29 DD 0x443e14c6,0x2f4a8b74,0x92d72ba2,0xf9a3b410 DD 0xb9907a7c,0xd2e4e5ce,0x6f794518,0x040ddaaa DD 0x11ae7245,0x7adaedf7,0xc7474d21,0xac33d293 DD 0x4720d1f9,0x2c544e4b,0x91c9ee9d,0xfabd712f DD 0xef1ed9c0,0x846a4672,0x39f7e6a4,0x52837916 DD 0x12b0b77a,0x79c428c8,0xc459881e,0xaf2d17ac DD 0xba8ebf43,0xd1fa20f1,0x6c678027,0x07131f95 DD 0xbfadf002,0xd4d96fb0,0x6944cf66,0x023050d4 DD 0x1793f83b,0x7ce76789,0xc17ac75f,0xaa0e58ed DD 0xea3d9681,0x81490933,0x3cd4a9e5,0x57a03657 DD 0x42039eb8,0x2977010a,0x94eaa1dc,0xff9e3e6e DD 0x148d3d04,0x7ff9a2b6,0xc2640260,0xa9109dd2 DD 0xbcb3353d,0xd7c7aa8f,0x6a5a0a59,0x012e95eb DD 0x411d5b87,0x2a69c435,0x97f464e3,0xfc80fb51 DD 0xe92353be,0x8257cc0c,0x3fca6cda,0x54bef368 mul_table_1272: DD 0x00000000,0xdd66cbbb,0xbf21e187,0x62472a3c DD 0x7bafb5ff,0xa6c97e44,0xc48e5478,0x19e89fc3 DD 0xf75f6bfe,0x2a39a045,0x487e8a79,0x951841c2 DD 0x8cf0de01,0x519615ba,0x33d13f86,0xeeb7f43d DD 0xeb52a10d,0x36346ab6,0x5473408a,0x89158b31 DD 0x90fd14f2,0x4d9bdf49,0x2fdcf575,0xf2ba3ece DD 0x1c0dcaf3,0xc16b0148,0xa32c2b74,0x7e4ae0cf DD 0x67a27f0c,0xbac4b4b7,0xd8839e8b,0x05e55530 DD 0xd34934eb,0x0e2fff50,0x6c68d56c,0xb10e1ed7 DD 0xa8e68114,0x75804aaf,0x17c76093,0xcaa1ab28 DD 0x24165f15,0xf97094ae,0x9b37be92,0x46517529 DD 0x5fb9eaea,0x82df2151,0xe0980b6d,0x3dfec0d6 DD 0x381b95e6,0xe57d5e5d,0x873a7461,0x5a5cbfda DD 0x43b42019,0x9ed2eba2,0xfc95c19e,0x21f30a25 DD 0xcf44fe18,0x122235a3,0x70651f9f,0xad03d424 DD 0xb4eb4be7,0x698d805c,0x0bcaaa60,0xd6ac61db DD 0xa37e1f27,0x7e18d49c,0x1c5ffea0,0xc139351b DD 0xd8d1aad8,0x05b76163,0x67f04b5f,0xba9680e4 DD 0x542174d9,0x8947bf62,0xeb00955e,0x36665ee5 DD 0x2f8ec126,0xf2e80a9d,0x90af20a1,0x4dc9eb1a DD 0x482cbe2a,0x954a7591,0xf70d5fad,0x2a6b9416 DD 0x33830bd5,0xeee5c06e,0x8ca2ea52,0x51c421e9 DD 0xbf73d5d4,0x62151e6f,0x00523453,0xdd34ffe8 DD 0xc4dc602b,0x19baab90,0x7bfd81ac,0xa69b4a17 DD 0x70372bcc,0xad51e077,0xcf16ca4b,0x127001f0 DD 0x0b989e33,0xd6fe5588,0xb4b97fb4,0x69dfb40f DD 0x87684032,0x5a0e8b89,0x3849a1b5,0xe52f6a0e DD 0xfcc7f5cd,0x21a13e76,0x43e6144a,0x9e80dff1 DD 0x9b658ac1,0x4603417a,0x24446b46,0xf922a0fd DD 0xe0ca3f3e,0x3dacf485,0x5febdeb9,0x828d1502 DD 0x6c3ae13f,0xb15c2a84,0xd31b00b8,0x0e7dcb03 DD 0x179554c0,0xcaf39f7b,0xa8b4b547,0x75d27efc DD 0x431048bf,0x9e768304,0xfc31a938,0x21576283 DD 0x38bffd40,0xe5d936fb,0x879e1cc7,0x5af8d77c DD 0xb44f2341,0x6929e8fa,0x0b6ec2c6,0xd608097d DD 0xcfe096be,0x12865d05,0x70c17739,0xada7bc82 DD 0xa842e9b2,0x75242209,0x17630835,0xca05c38e DD 0xd3ed5c4d,0x0e8b97f6,0x6cccbdca,0xb1aa7671 DD 0x5f1d824c,0x827b49f7,0xe03c63cb,0x3d5aa870 DD 0x24b237b3,0xf9d4fc08,0x9b93d634,0x46f51d8f DD 0x90597c54,0x4d3fb7ef,0x2f789dd3,0xf21e5668 DD 0xebf6c9ab,0x36900210,0x54d7282c,0x89b1e397 DD 0x670617aa,0xba60dc11,0xd827f62d,0x05413d96 DD 0x1ca9a255,0xc1cf69ee,0xa38843d2,0x7eee8869 DD 0x7b0bdd59,0xa66d16e2,0xc42a3cde,0x194cf765 DD 0x00a468a6,0xddc2a31d,0xbf858921,0x62e3429a DD 0x8c54b6a7,0x51327d1c,0x33755720,0xee139c9b DD 0xf7fb0358,0x2a9dc8e3,0x48dae2df,0x95bc2964 DD 0xe06e5798,0x3d089c23,0x5f4fb61f,0x82297da4 DD 0x9bc1e267,0x46a729dc,0x24e003e0,0xf986c85b DD 0x17313c66,0xca57f7dd,0xa810dde1,0x7576165a DD 0x6c9e8999,0xb1f84222,0xd3bf681e,0x0ed9a3a5 DD 0x0b3cf695,0xd65a3d2e,0xb41d1712,0x697bdca9 DD 0x7093436a,0xadf588d1,0xcfb2a2ed,0x12d46956 DD 0xfc639d6b,0x210556d0,0x43427cec,0x9e24b757 DD 0x87cc2894,0x5aaae32f,0x38edc913,0xe58b02a8 DD 0x33276373,0xee41a8c8,0x8c0682f4,0x5160494f DD 0x4888d68c,0x95ee1d37,0xf7a9370b,0x2acffcb0 DD 0xc478088d,0x191ec336,0x7b59e90a,0xa63f22b1 DD 0xbfd7bd72,0x62b176c9,0x00f65cf5,0xdd90974e DD 0xd875c27e,0x051309c5,0x675423f9,0xba32e842 DD 0xa3da7781,0x7ebcbc3a,0x1cfb9606,0xc19d5dbd DD 0x2f2aa980,0xf24c623b,0x900b4807,0x4d6d83bc DD 0x54851c7f,0x89e3d7c4,0xeba4fdf8,0x36c23643 %macro slversion 4 global %1_slver_%2%3%4 global %1_slver %1_slver: %1_slver_%2%3%4: dw 0x%4 db 0x%3, 0x%2 %endmacro ;;; func core, ver, snum slversion crc32_iscsi_00, 00, 02, 0014 ; inform linker that this doesn't require executable stack section .note.GNU-stack noalloc noexec nowrite progbits ceph-0.80.11/src/common/mime.h0000664000175100017510000000330412623076744020054 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_MIME_H #define CEPH_COMMON_MIME_H #ifdef __cplusplus extern "C" { #endif /* Encode a buffer as quoted-printable. * * The input is a null-terminated string. * The output is a null-terminated string representing the input encoded as * a MIME quoted-printable. * * Returns the length of the buffer we would need to do the encoding. * If we don't have enough buffer space, the output will be truncated. * * You may call mime_encode_as_qp(input, NULL, 0) to find the size of the * buffer you will need. */ signed int mime_encode_as_qp(const char *input, char *output, int outlen); /* Decode a quoted-printable buffer. * * The input is a null-terminated string encoded as a MIME quoted-printable. * The output is a null-terminated string representing the input decoded. * * Returns a negative error code if the input is not a valid quoted-printable * buffer. * Returns the length of the buffer we would need to do the encoding. * If we don't have enough buffer space, the output will be truncated. * * You may call mime_decode_as_qp(input, NULL, 0) to find the size of the * buffer you will need. The output will never be longer than the input for * this function. */ signed int mime_decode_from_qp(const char *input, char *output, int outlen); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/sctp_crc32.h0000664000175100017510000000035412623076744021074 0ustar jenkins-buildjenkins-build#ifndef CEPH_COMMON_SCTP_CRC32_H #define CEPH_COMMON_SCTP_CRC32_H #ifdef __cplusplus extern "C" { #endif extern uint32_t ceph_crc32c_sctp(uint32_t crc, unsigned char const *data, unsigned length); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/config.h0000664000175100017510000002113212623076744020371 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CONFIG_H #define CEPH_CONFIG_H extern struct ceph_file_layout g_default_file_layout; #include #include #include #include #include "common/ConfUtils.h" #include "common/entity_name.h" #include "common/Mutex.h" #include "log/SubsystemMap.h" #include "common/config_obs.h" #include "msg/msg_types.h" enum { CEPH_DEFAULT_CRUSH_REPLICATED_RULESET, CEPH_DEFAULT_CRUSH_ERASURE_RULESET, }; #define OSD_REP_PRIMARY 0 #define OSD_REP_SPLAY 1 #define OSD_REP_CHAIN 2 #define OSD_POOL_ERASURE_CODE_STRIPE_WIDTH 4096 struct config_option; class CephContext; extern const char *CEPH_CONF_FILE_DEFAULT; #define LOG_TO_STDERR_NONE 0 #define LOG_TO_STDERR_SOME 1 #define LOG_TO_STDERR_ALL 2 /** This class represents the current Ceph configuration. * * For Ceph daemons, this is the daemon configuration. Log levels, caching * settings, btrfs settings, and so forth can all be found here. For libcephfs * and librados users, this is the configuration associated with their context. * * For information about how this class is loaded from a configuration file, * see common/ConfUtils. * * ACCESS * * There are two ways to read the ceph context-- the old way and the new way. * In the old way, code would simply read the public variables of the * configuration, without taking a lock. In the new way, code registers a * configuration obserever which receives callbacks when a value changes. These * callbacks take place under the md_config_t lock. * * To prevent serious problems resulting from thread-safety issues, we disallow * changing std::string configuration values after * md_config_t::internal_safe_to_start_threads becomes true. You can still * change integer or floating point values, however. * * FIXME: really we shouldn't allow changing integer or floating point values * while another thread is reading them, either. */ struct md_config_t { public: /* Maps configuration options to the observer listening for them. */ typedef std::multimap obs_map_t; /* Set of configuration options that have changed since the last * apply_changes */ typedef std::set < std::string > changed_set_t; // Create a new md_config_t structure. md_config_t(); ~md_config_t(); // Adds a new observer to this configuration. You can do this at any time, // but it will only receive notifications for the changes that happen after // you attach it, obviously. // // Most developers will probably attach their observers after global_init, // but before anyone can call injectargs. // // The caller is responsible for allocating observers. void add_observer(md_config_obs_t* observer_); // Remove an observer from this configuration. // This doesn't delete the observer! If you allocated it with new(), // you need to delete it yourself. // This function will assert if you try to delete an observer that isn't // there. void remove_observer(md_config_obs_t* observer_); // Parse a config file int parse_config_files(const char *conf_files, std::deque *parse_errors, std::ostream *warnings, int flags); // Absorb config settings from the environment void parse_env(); // Absorb config settings from argv int parse_argv(std::vector& args); // Expand all metavariables. Make any pending observer callbacks. void apply_changes(std::ostream *oss); void _apply_changes(std::ostream *oss); bool _internal_field(const string& k); void call_all_observers(); // Called by the Ceph daemons to make configuration changes at runtime int injectargs(const std::string &s, std::ostream *oss); // Set a configuration value, or crash // Metavariables will be expanded. void set_val_or_die(const char *key, const char *val); // Set a configuration value. // Metavariables will be expanded. int set_val(const char *key, const char *val, bool meta=true); // Get a configuration value. // No metavariables will be returned (they will have already been expanded) int get_val(const char *key, char **buf, int len) const; int _get_val(const char *key, char **buf, int len) const; // Return a list of all the sections that the current entity is a member of. void get_my_sections(std::vector §ions) const; // Return a list of all sections int get_all_sections(std::vector §ions) const; // Get a value from the configuration file that we read earlier. // Metavariables will be expanded if emeta is true. int get_val_from_conf_file(const std::vector §ions, const char *key, std::string &out, bool emeta) const; /// dump all config values to a stream void show_config(std::ostream& out); /// dump all config values to a formatter void show_config(Formatter *f); private: void _show_config(std::ostream *out, Formatter *f); void _get_my_sections(std::vector §ions) const; int _get_val_from_conf_file(const std::vector §ions, const char *key, std::string &out, bool emeta) const; int parse_option(std::vector& args, std::vector::iterator& i, std::ostream *oss); int parse_injectargs(std::vector& args, std::ostream *oss); int parse_config_files_impl(const std::list &conf_files, std::deque *parse_errors, std::ostream *warnings); int set_val_impl(const char *val, const config_option *opt); int set_val_raw(const char *val, const config_option *opt); void init_subsys(); bool expand_meta(std::string &val, std::ostream *oss) const; bool expand_meta(std::string &val, config_option *opt, std::list stack, std::ostream *oss) const; /// expand all metavariables in config structure. void expand_all_meta(); // The configuration file we read, or NULL if we haven't read one. ConfFile cf; obs_map_t observers; changed_set_t changed; public: ceph::log::SubsystemMap subsys; EntityName name; /// cluster name string cluster; #define OPTION_OPT_INT(name) const int name; #define OPTION_OPT_LONGLONG(name) const long long name; #define OPTION_OPT_STR(name) const std::string name; #define OPTION_OPT_DOUBLE(name) const double name; #define OPTION_OPT_FLOAT(name) const float name; #define OPTION_OPT_BOOL(name) const bool name; #define OPTION_OPT_ADDR(name) const entity_addr_t name; #define OPTION_OPT_U32(name) const uint32_t name; #define OPTION_OPT_U64(name) const uint64_t name; #define OPTION_OPT_UUID(name) const uuid_d name; #define OPTION(name, ty, init) OPTION_##ty(name) #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" #undef OPTION_OPT_INT #undef OPTION_OPT_LONGLONG #undef OPTION_OPT_STR #undef OPTION_OPT_DOUBLE #undef OPTION_OPT_FLOAT #undef OPTION_OPT_BOOL #undef OPTION_OPT_ADDR #undef OPTION_OPT_U32 #undef OPTION_OPT_U64 #undef OPTION_OPT_UUID #undef OPTION #undef SUBSYS #undef DEFAULT_SUBSYS unsigned get_osd_pool_default_min_size() const { return osd_pool_default_min_size ? MIN(osd_pool_default_min_size, osd_pool_default_size) : osd_pool_default_size - osd_pool_default_size / 2; } /** A lock that protects the md_config_t internals. It is * recursive, for simplicity. * It is best if this lock comes first in the lock hierarchy. We will * hold this lock when calling configuration observers. */ mutable Mutex lock; friend class test_md_config_t; }; typedef enum { OPT_INT, OPT_LONGLONG, OPT_STR, OPT_DOUBLE, OPT_FLOAT, OPT_BOOL, OPT_ADDR, OPT_U32, OPT_U64, OPT_UUID } opt_type_t; bool ceph_resolve_file_search(const std::string& filename_list, std::string& result); struct config_option { const char *name; opt_type_t type; size_t md_conf_off; // Given a configuration, return a pointer to this option inside // that configuration. void *conf_ptr(md_config_t *conf) const; const void *conf_ptr(const md_config_t *conf) const; }; enum config_subsys_id { ceph_subsys_, // default #define OPTION(a,b,c) #define SUBSYS(name, log, gather) \ ceph_subsys_##name, #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" #undef SUBSYS #undef OPTION #undef DEFAULT_SUBSYS ceph_subsys_max }; #endif ceph-0.80.11/src/common/OutputDataSocket.cc0000664000175100017510000002462212623076744022534 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "common/Thread.h" #include "common/OutputDataSocket.h" #include "common/config.h" #include "common/dout.h" #include "common/errno.h" #include "common/perf_counters.h" #include "common/pipe.h" #include "common/safe_io.h" #include "common/version.h" #include "common/Formatter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "include/compat.h" #define dout_subsys ceph_subsys_asok #undef dout_prefix #define dout_prefix *_dout << "asok(" << (void*)m_cct << ") " using std::ostringstream; /* * UNIX domain sockets created by an application persist even after that * application closes, unless they're explicitly unlinked. This is because the * directory containing the socket keeps a reference to the socket. * * This code makes things a little nicer by unlinking those dead sockets when * the application exits normally. */ static pthread_mutex_t cleanup_lock = PTHREAD_MUTEX_INITIALIZER; static std::vector cleanup_files; static bool cleanup_atexit = false; static void remove_cleanup_file(const char *file) { pthread_mutex_lock(&cleanup_lock); VOID_TEMP_FAILURE_RETRY(unlink(file)); for (std::vector ::iterator i = cleanup_files.begin(); i != cleanup_files.end(); ++i) { if (strcmp(file, *i) == 0) { free((void*)*i); cleanup_files.erase(i); break; } } pthread_mutex_unlock(&cleanup_lock); } static void remove_all_cleanup_files() { pthread_mutex_lock(&cleanup_lock); for (std::vector ::iterator i = cleanup_files.begin(); i != cleanup_files.end(); ++i) { VOID_TEMP_FAILURE_RETRY(unlink(*i)); free((void*)*i); } cleanup_files.clear(); pthread_mutex_unlock(&cleanup_lock); } static void add_cleanup_file(const char *file) { char *fname = strdup(file); if (!fname) return; pthread_mutex_lock(&cleanup_lock); cleanup_files.push_back(fname); if (!cleanup_atexit) { atexit(remove_all_cleanup_files); cleanup_atexit = true; } pthread_mutex_unlock(&cleanup_lock); } OutputDataSocket::OutputDataSocket(CephContext *cct, uint64_t _backlog) : m_cct(cct), data_max_backlog(_backlog), m_sock_fd(-1), m_shutdown_rd_fd(-1), m_shutdown_wr_fd(-1), going_down(false), data_size(0), m_lock("OutputDataSocket::m_lock") { } OutputDataSocket::~OutputDataSocket() { shutdown(); } /* * This thread listens on the UNIX domain socket for incoming connections. * It only handles one connection at a time at the moment. All I/O is nonblocking, * so that we can implement sensible timeouts. [TODO: make all I/O nonblocking] * * This thread also listens to m_shutdown_rd_fd. If there is any data sent to this * pipe, the thread terminates itself gracefully, allowing the * OutputDataSocketConfigObs class to join() it. */ #define PFL_SUCCESS ((void*)(intptr_t)0) #define PFL_FAIL ((void*)(intptr_t)1) std::string OutputDataSocket::create_shutdown_pipe(int *pipe_rd, int *pipe_wr) { int pipefd[2]; int ret = pipe_cloexec(pipefd); if (ret < 0) { ostringstream oss; oss << "OutputDataSocket::create_shutdown_pipe error: " << cpp_strerror(ret); return oss.str(); } *pipe_rd = pipefd[0]; *pipe_wr = pipefd[1]; return ""; } std::string OutputDataSocket::bind_and_listen(const std::string &sock_path, int *fd) { ldout(m_cct, 5) << "bind_and_listen " << sock_path << dendl; struct sockaddr_un address; if (sock_path.size() > sizeof(address.sun_path) - 1) { ostringstream oss; oss << "OutputDataSocket::bind_and_listen: " << "The UNIX domain socket path " << sock_path << " is too long! The " << "maximum length on this system is " << (sizeof(address.sun_path) - 1); return oss.str(); } int sock_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (sock_fd < 0) { int err = errno; ostringstream oss; oss << "OutputDataSocket::bind_and_listen: " << "failed to create socket: " << cpp_strerror(err); return oss.str(); } int r = fcntl(sock_fd, F_SETFD, FD_CLOEXEC); if (r < 0) { r = errno; VOID_TEMP_FAILURE_RETRY(::close(sock_fd)); ostringstream oss; oss << "OutputDataSocket::bind_and_listen: failed to fcntl on socket: " << cpp_strerror(r); return oss.str(); } memset(&address, 0, sizeof(struct sockaddr_un)); address.sun_family = AF_UNIX; snprintf(address.sun_path, sizeof(address.sun_path), "%s", sock_path.c_str()); if (bind(sock_fd, (struct sockaddr*)&address, sizeof(struct sockaddr_un)) != 0) { int err = errno; if (err == EADDRINUSE) { // The old UNIX domain socket must still be there. // Let's unlink it and try again. VOID_TEMP_FAILURE_RETRY(unlink(sock_path.c_str())); if (bind(sock_fd, (struct sockaddr*)&address, sizeof(struct sockaddr_un)) == 0) { err = 0; } else { err = errno; } } if (err != 0) { ostringstream oss; oss << "OutputDataSocket::bind_and_listen: " << "failed to bind the UNIX domain socket to '" << sock_path << "': " << cpp_strerror(err); close(sock_fd); return oss.str(); } } if (listen(sock_fd, 5) != 0) { int err = errno; ostringstream oss; oss << "OutputDataSocket::bind_and_listen: " << "failed to listen to socket: " << cpp_strerror(err); close(sock_fd); VOID_TEMP_FAILURE_RETRY(unlink(sock_path.c_str())); return oss.str(); } *fd = sock_fd; return ""; } void* OutputDataSocket::entry() { ldout(m_cct, 5) << "entry start" << dendl; while (true) { struct pollfd fds[2]; memset(fds, 0, sizeof(fds)); fds[0].fd = m_sock_fd; fds[0].events = POLLIN | POLLRDBAND; fds[1].fd = m_shutdown_rd_fd; fds[1].events = POLLIN | POLLRDBAND; int ret = poll(fds, 2, -1); if (ret < 0) { int err = errno; if (err == EINTR) { continue; } lderr(m_cct) << "OutputDataSocket: poll(2) error: '" << cpp_strerror(err) << dendl; return PFL_FAIL; } if (fds[0].revents & POLLIN) { // Send out some data do_accept(); } if (fds[1].revents & POLLIN) { // Parent wants us to shut down return PFL_SUCCESS; } } ldout(m_cct, 5) << "entry exit" << dendl; return PFL_SUCCESS; // unreachable } bool OutputDataSocket::do_accept() { struct sockaddr_un address; socklen_t address_length = sizeof(address); ldout(m_cct, 30) << "OutputDataSocket: calling accept" << dendl; int connection_fd = accept(m_sock_fd, (struct sockaddr*) &address, &address_length); ldout(m_cct, 30) << "OutputDataSocket: finished accept" << dendl; if (connection_fd < 0) { int err = errno; lderr(m_cct) << "OutputDataSocket: do_accept error: '" << cpp_strerror(err) << dendl; return false; } handle_connection(connection_fd); close_connection(connection_fd); return 0; } void OutputDataSocket::handle_connection(int fd) { bufferlist bl; m_lock.Lock(); init_connection(bl); m_lock.Unlock(); if (bl.length()) { /* need to special case the connection init buffer output, as it needs * to be dumped before any data, including older data that was sent * before the connection was established, or before we identified * older connection was broken */ int ret = safe_write(fd, bl.c_str(), bl.length()); if (ret < 0) { return; } } int ret = dump_data(fd); if (ret < 0) return; do { m_lock.Lock(); cond.Wait(m_lock); if (going_down) { m_lock.Unlock(); break; } m_lock.Unlock(); ret = dump_data(fd); } while (ret >= 0); } int OutputDataSocket::dump_data(int fd) { m_lock.Lock(); list l; l = data; data.clear(); data_size = 0; m_lock.Unlock(); for (list::iterator iter = l.begin(); iter != l.end(); ++iter) { bufferlist& bl = *iter; int ret = safe_write(fd, bl.c_str(), bl.length()); if (ret >= 0) { ret = safe_write(fd, delim.c_str(), delim.length()); } if (ret < 0) { for (; iter != l.end(); ++iter) { bufferlist& bl = *iter; data.push_back(bl); data_size += bl.length(); } return ret; } } return 0; } void OutputDataSocket::close_connection(int fd) { VOID_TEMP_FAILURE_RETRY(close(fd)); } bool OutputDataSocket::init(const std::string &path) { ldout(m_cct, 5) << "init " << path << dendl; /* Set up things for the new thread */ std::string err; int pipe_rd = -1, pipe_wr = -1; err = create_shutdown_pipe(&pipe_rd, &pipe_wr); if (!err.empty()) { lderr(m_cct) << "OutputDataSocketConfigObs::init: error: " << err << dendl; return false; } int sock_fd; err = bind_and_listen(path, &sock_fd); if (!err.empty()) { lderr(m_cct) << "OutputDataSocketConfigObs::init: failed: " << err << dendl; close(pipe_rd); close(pipe_wr); return false; } /* Create new thread */ m_sock_fd = sock_fd; m_shutdown_rd_fd = pipe_rd; m_shutdown_wr_fd = pipe_wr; m_path = path; create(); add_cleanup_file(m_path.c_str()); return true; } void OutputDataSocket::shutdown() { m_lock.Lock(); going_down = true; cond.Signal(); m_lock.Unlock(); if (m_shutdown_wr_fd < 0) return; ldout(m_cct, 5) << "shutdown" << dendl; // Send a byte to the shutdown pipe that the thread is listening to char buf[1] = { 0x0 }; int ret = safe_write(m_shutdown_wr_fd, buf, sizeof(buf)); VOID_TEMP_FAILURE_RETRY(close(m_shutdown_wr_fd)); m_shutdown_wr_fd = -1; if (ret == 0) { join(); } else { lderr(m_cct) << "OutputDataSocket::shutdown: failed to write " "to thread shutdown pipe: error " << ret << dendl; } remove_cleanup_file(m_path.c_str()); m_path.clear(); } void OutputDataSocket::append_output(bufferlist& bl) { Mutex::Locker l(m_lock); if (data_size + bl.length() > data_max_backlog) { ldout(m_cct, 20) << "dropping data output, max backlog reached" << dendl; } data.push_back(bl); data_size += bl.length(); cond.Signal(); } ceph-0.80.11/src/common/Semaphore.h0000664000175100017510000000147512623076744021057 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_Sem_Posix__H #define CEPH_Sem_Posix__H class Semaphore { Mutex m; Cond c; int count; public: Semaphore() : m("Semaphore::m") { count = 0; } void Put() { m.Lock(); count++; c.Signal(); m.Unlock(); } void Get() { m.Lock(); while(count <= 0) { c.Wait(m); } count--; m.Unlock(); } }; #endif // !_Mutex_Posix_ ceph-0.80.11/src/common/signal.h0000664000175100017510000000260212623076744020402 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_SIGNAL_H #define CEPH_COMMON_SIGNAL_H #include #include // Returns a string showing the set of blocked signals for the calling thread. // Other threads may have a different set (this is per-thread thing). extern std::string signal_mask_to_str(); // Block a list of signals. If siglist == NULL, blocks all signals. // If not, the list is terminated with a 0 element. // // On success, stores the old set of blocked signals in // old_sigset. On failure, stores an invalid set of blocked signals in // old_sigset. extern void block_signals(const int *siglist, sigset_t *old_sigset); // Restore the set of blocked signals. Will not restore an invalid set of // blocked signals. extern void restore_sigset(const sigset_t *old_sigset); // Unblock all signals. On success, stores the old set of blocked signals in // old_sigset. On failure, stores an invalid set of blocked signals in // old_sigset. extern void unblock_all_signals(sigset_t *old_sigset); #endif ceph-0.80.11/src/common/ceph_json.h0000664000175100017510000002140612623076744021100 0ustar jenkins-buildjenkins-build#ifndef CEPH_JSON_H #define CEPH_JSON_H #include #include #include #include "json_spirit/json_spirit.h" #include "Formatter.h" using namespace json_spirit; class JSONObj; class JSONObjIter { typedef map::iterator map_iter_t; map_iter_t cur; map_iter_t last; public: JSONObjIter(); ~JSONObjIter(); void set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_end); void operator++(); JSONObj *operator*(); bool end() { return (cur == last); } }; class JSONObj { JSONObj *parent; protected: string name; // corresponds to obj_type in XMLObj Value data; string data_string; multimap children; map attr_map; void handle_value(Value v); public: JSONObj() : parent(NULL){}; virtual ~JSONObj(); void init(JSONObj *p, Value v, string n); string& get_name() { return name; } string& get_data() { return data_string; } bool get_data(const string& key, string *dest); JSONObj *get_parent(); void add_child(string el, JSONObj *child); bool get_attr(string name, string& attr); JSONObjIter find(const string& name); JSONObjIter find_first(); JSONObjIter find_first(const string& name); JSONObj *find_obj(const string& name); friend ostream& operator<<(ostream& out, JSONObj& obj); // does not work, FIXME bool is_array(); bool is_object(); vector get_array_elements(); }; class JSONParser : public JSONObj { int buf_len; string json_buffer; bool success; public: JSONParser(); virtual ~JSONParser(); void handle_data(const char *s, int len); bool parse(const char *buf_, int len); bool parse(int len); bool parse(); bool parse(const char *file_name); const char *get_json() { return json_buffer.c_str(); } void set_failure() { success = false; } }; class JSONDecoder { public: struct err { string message; err(const string& m) : message(m) {} }; JSONParser parser; JSONDecoder(bufferlist& bl) { if (!parser.parse(bl.c_str(), bl.length())) { cout << "JSONDecoder::err()" << std::endl; throw JSONDecoder::err("failed to parse JSON input"); } } template static bool decode_json(const char *name, T& val, JSONObj *obj, bool mandatory = false); template static bool decode_json(const char *name, C& container, void (*cb)(C&, JSONObj *obj), JSONObj *obj, bool mandatory = false); template static void decode_json(const char *name, T& val, T& default_val, JSONObj *obj); }; template void decode_json_obj(T& val, JSONObj *obj) { val.decode_json(obj); } static inline void decode_json_obj(string& val, JSONObj *obj) { val = obj->get_data(); } void decode_json_obj(unsigned long long& val, JSONObj *obj); void decode_json_obj(long long& val, JSONObj *obj); void decode_json_obj(unsigned long& val, JSONObj *obj); void decode_json_obj(long& val, JSONObj *obj); void decode_json_obj(unsigned& val, JSONObj *obj); void decode_json_obj(int& val, JSONObj *obj); void decode_json_obj(bool& val, JSONObj *obj); void decode_json_obj(bufferlist& val, JSONObj *obj); class utime_t; void decode_json_obj(utime_t& val, JSONObj *obj); template void decode_json_obj(list& l, JSONObj *obj) { l.clear(); JSONObjIter iter = obj->find_first(); for (; !iter.end(); ++iter) { T val; JSONObj *o = *iter; decode_json_obj(val, o); l.push_back(val); } } template void decode_json_obj(map& m, JSONObj *obj) { m.clear(); JSONObjIter iter = obj->find_first(); for (; !iter.end(); ++iter) { K key; V val; JSONObj *o = *iter; JSONDecoder::decode_json("key", key, o); JSONDecoder::decode_json("val", val, o); m[key] = val; } } template void decode_json_obj(C& container, void (*cb)(C&, JSONObj *obj), JSONObj *obj) { container.clear(); JSONObjIter iter = obj->find_first(); for (; !iter.end(); ++iter) { JSONObj *o = *iter; cb(container, o); } } template bool JSONDecoder::decode_json(const char *name, T& val, JSONObj *obj, bool mandatory) { JSONObjIter iter = obj->find_first(name); if (iter.end()) { if (mandatory) { string s = "missing mandatory field " + string(name); throw err(s); } val = T(); return false; } try { decode_json_obj(val, *iter); } catch (err& e) { string s = string(name) + ": "; s.append(e.message); throw err(s); } return true; } template bool JSONDecoder::decode_json(const char *name, C& container, void (*cb)(C&, JSONObj *), JSONObj *obj, bool mandatory) { container.clear(); JSONObjIter iter = obj->find_first(name); if (iter.end()) { if (mandatory) { string s = "missing mandatory field " + string(name); throw err(s); } return false; } try { decode_json_obj(container, cb, *iter); } catch (err& e) { string s = string(name) + ": "; s.append(e.message); throw err(s); } return true; } template void JSONDecoder::decode_json(const char *name, T& val, T& default_val, JSONObj *obj) { JSONObjIter iter = obj->find_first(name); if (iter.end()) { val = default_val; return; } try { decode_json_obj(val, *iter); } catch (err& e) { val = default_val; string s = string(name) + ": "; s.append(e.message); throw err(s); } } template static void encode_json(const char *name, const T& val, ceph::Formatter *f) { f->open_object_section(name); val.dump(f); f->close_section(); } class utime_t; void encode_json(const char *name, const string& val, ceph::Formatter *f); void encode_json(const char *name, const char *val, ceph::Formatter *f); void encode_json(const char *name, bool val, ceph::Formatter *f); void encode_json(const char *name, int val, ceph::Formatter *f); void encode_json(const char *name, unsigned val, ceph::Formatter *f); void encode_json(const char *name, long val, ceph::Formatter *f); void encode_json(const char *name, unsigned long val, ceph::Formatter *f); void encode_json(const char *name, long long val, ceph::Formatter *f); void encode_json(const char *name, const utime_t& val, ceph::Formatter *f); void encode_json(const char *name, const bufferlist& bl, ceph::Formatter *f); void encode_json(const char *name, long long val, ceph::Formatter *f); void encode_json(const char *name, long long unsigned val, ceph::Formatter *f); template static void encode_json(const char *name, const std::map& m, ceph::Formatter *f) { f->open_array_section(name); for (typename std::map::const_iterator i = m.begin(); i != m.end(); ++i) { f->open_object_section("entry"); encode_json("key", i->first, f); encode_json("val", i->second, f); f->close_section(); } f->close_section(); } template static void encode_json(const char *name, const std::list& l, ceph::Formatter *f) { f->open_array_section(name); for (typename std::list::const_iterator iter = l.begin(); iter != l.end(); ++iter) { encode_json("obj", *iter, f); } f->close_section(); } template void encode_json_map(const char *name, const map& m, ceph::Formatter *f) { f->open_array_section(name); typename map::const_iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { encode_json("obj", iter->second, f); } f->close_section(); } template void encode_json_map(const char *name, const char *index_name, const char *object_name, const char *value_name, void (*cb)(const char *, const V&, ceph::Formatter *, void *), void *parent, const map& m, ceph::Formatter *f) { f->open_array_section(name); typename map::const_iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { if (index_name) { f->open_object_section("key_value"); f->dump_string(index_name, iter->first); } if (object_name) { f->open_object_section(object_name); } if (cb) { cb(value_name, iter->second, f, parent); } else { encode_json(value_name, iter->second, f); } if (object_name) { f->close_section(); } if (index_name) { f->close_section(); } } f->close_section(); } template void encode_json_map(const char *name, const char *index_name, const char *object_name, const char *value_name, const map& m, ceph::Formatter *f) { encode_json_map(name, index_name, object_name, value_name, NULL, NULL, m, f); } template void encode_json_map(const char *name, const char *index_name, const char *value_name, const map& m, ceph::Formatter *f) { encode_json_map(name, index_name, NULL, value_name, NULL, NULL, m, f); } #endif ceph-0.80.11/src/common/arch.h0000664000175100017510000000031212623076744020036 0ustar jenkins-buildjenkins-build#ifndef CEPH_ARCH_H #define CEPH_ARCH_H static const char *get_arch() { #if defined(__i386__) return "i386"; #elif defined(__x86_64__) return "x86-64"; #else return "unknown"; #endif } #endif ceph-0.80.11/src/common/crc32c_intel_fast.c0000664000175100017510000000214412623076744022410 0ustar jenkins-buildjenkins-build#include "acconfig.h" #include "include/int_types.h" #include "common/crc32c_intel_baseline.h" extern unsigned int crc32_iscsi_00(unsigned char const *buffer, int len, unsigned int crc); extern unsigned int crc32_iscsi_zero_00(unsigned char const *buffer, int len, unsigned int crc); #ifdef HAVE_GOOD_YASM_ELF64 uint32_t ceph_crc32c_intel_fast(uint32_t crc, unsigned char const *buffer, unsigned len) { uint32_t v; unsigned left; if (!buffer) return crc32_iscsi_zero_00(buffer, len, crc); /* * the crc32_iscsi_00 method reads past buffer+len (because it * reads full words) which makes valgrind unhappy. don't do * that. */ if (len < 16) return ceph_crc32c_intel_baseline(crc, buffer, len); left = ((unsigned long)buffer + len) & 7; len -= left; v = crc32_iscsi_00(buffer, len, crc); if (left) v = ceph_crc32c_intel_baseline(v, buffer + len, left); return v; } int ceph_crc32c_intel_fast_exists(void) { return 1; } #else int ceph_crc32c_intel_fast_exists(void) { return 0; } uint32_t ceph_crc32c_intel_fast(uint32_t crc, unsigned char const *buffer, unsigned len) { return 0; } #endif ceph-0.80.11/src/common/errno.h0000664000175100017510000000022512623076744020251 0ustar jenkins-buildjenkins-build#ifndef CEPH_ERRNO_H #define CEPH_ERRNO_H #include /* Return a given error code as a string */ std::string cpp_strerror(int err); #endif ceph-0.80.11/src/common/HeartbeatMap.cc0000664000175100017510000001002612623076744021617 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "HeartbeatMap.h" #include "ceph_context.h" #include "common/errno.h" #include "debug.h" #define dout_subsys ceph_subsys_heartbeatmap #undef dout_prefix #define dout_prefix *_dout << "heartbeat_map " namespace ceph { HeartbeatMap::HeartbeatMap(CephContext *cct) : m_cct(cct), m_rwlock("HeartbeatMap::m_rwlock"), m_inject_unhealthy_until(0) { } HeartbeatMap::~HeartbeatMap() { assert(m_workers.empty()); } heartbeat_handle_d *HeartbeatMap::add_worker(string name) { m_rwlock.get_write(); ldout(m_cct, 10) << "add_worker '" << name << "'" << dendl; heartbeat_handle_d *h = new heartbeat_handle_d(name); m_workers.push_front(h); h->list_item = m_workers.begin(); m_rwlock.put_write(); return h; } void HeartbeatMap::remove_worker(heartbeat_handle_d *h) { m_rwlock.get_write(); ldout(m_cct, 10) << "remove_worker '" << h->name << "'" << dendl; m_workers.erase(h->list_item); m_rwlock.put_write(); delete h; } bool HeartbeatMap::_check(heartbeat_handle_d *h, const char *who, time_t now) { bool healthy = true; time_t was; was = h->timeout.read(); if (was && was < now) { ldout(m_cct, 1) << who << " '" << h->name << "'" << " had timed out after " << h->grace << dendl; healthy = false; } was = h->suicide_timeout.read(); if (was && was < now) { ldout(m_cct, 1) << who << " '" << h->name << "'" << " had suicide timed out after " << h->suicide_grace << dendl; assert(0 == "hit suicide timeout"); } return healthy; } void HeartbeatMap::reset_timeout(heartbeat_handle_d *h, time_t grace, time_t suicide_grace) { ldout(m_cct, 20) << "reset_timeout '" << h->name << "' grace " << grace << " suicide " << suicide_grace << dendl; time_t now = time(NULL); _check(h, "reset_timeout", now); h->timeout.set(now + grace); h->grace = grace; if (suicide_grace) h->suicide_timeout.set(now + suicide_grace); else h->suicide_timeout.set(0); h->suicide_grace = suicide_grace; } void HeartbeatMap::clear_timeout(heartbeat_handle_d *h) { ldout(m_cct, 20) << "clear_timeout '" << h->name << "'" << dendl; time_t now = time(NULL); _check(h, "clear_timeout", now); h->timeout.set(0); h->suicide_timeout.set(0); } bool HeartbeatMap::is_healthy() { m_rwlock.get_read(); time_t now = time(NULL); if (m_cct->_conf->heartbeat_inject_failure) { ldout(m_cct, 0) << "is_healthy injecting failure for next " << m_cct->_conf->heartbeat_inject_failure << " seconds" << dendl; m_inject_unhealthy_until = now + m_cct->_conf->heartbeat_inject_failure; m_cct->_conf->set_val("heartbeat_inject_failure", "0"); } bool healthy = true; if (now < m_inject_unhealthy_until) { ldout(m_cct, 0) << "is_healthy = false, injected failure for next " << (m_inject_unhealthy_until - now) << " seconds" << dendl; healthy = false; } for (list::iterator p = m_workers.begin(); p != m_workers.end(); ++p) { heartbeat_handle_d *h = *p; if (!_check(h, "is_healthy", now)) { healthy = false; } } m_rwlock.put_read(); ldout(m_cct, 20) << "is_healthy = " << (healthy ? "healthy" : "NOT HEALTHY") << dendl; return healthy; } void HeartbeatMap::check_touch_file() { if (is_healthy()) { string path = m_cct->_conf->heartbeat_file; if (path.length()) { int fd = ::open(path.c_str(), O_WRONLY|O_CREAT, 0644); if (fd >= 0) { ::utimes(path.c_str(), NULL); ::close(fd); } else { ldout(m_cct, 0) << "unable to touch " << path << ": " << cpp_strerror(errno) << dendl; } } } } } ceph-0.80.11/src/common/DecayCounter.h0000664000175100017510000000533512623076744021520 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DECAYCOUNTER_H #define CEPH_DECAYCOUNTER_H #include "include/utime.h" #include /** * * TODO: normalize value based on some fucntion of half_life, * so that it can be interpreted as an approximation of a * moving average of N seconds. currently, changing half-life * skews the scale of the value, even at steady state. * */ class DecayRate { double k; // k = ln(.5)/half_life friend class DecayCounter; public: DecayRate() : k(0) {} DecayRate(double hl) { set_halflife(hl); } void set_halflife(double hl) { k = ::log(.5) / hl; } }; class DecayCounter { protected: public: double val; // value double delta; // delta since last decay double vel; // recent velocity utime_t last_decay; // time of last decay public: void encode(bufferlist& bl) const; void decode(const utime_t &t, bufferlist::iterator& p); void dump(Formatter *f) const; static void generate_test_instances(list& ls); DecayCounter(const utime_t &now) : val(0), delta(0), vel(0), last_decay(now) { } // these two functions are for the use of our dencoder testing infrastructure DecayCounter() : val(0), delta(0), vel(0), last_decay() {} void decode(bufferlist::iterator& p) { utime_t fake_time; decode(fake_time, p); } /** * reading */ double get(utime_t now, const DecayRate& rate) { decay(now, rate); return val; } double get_last() { return val; } double get_last_vel() { return vel; } utime_t get_last_decay() { return last_decay; } /** * adjusting */ double hit(utime_t now, const DecayRate& rate, double v = 1.0) { decay(now, rate); delta += v; return val+delta; } void adjust(double a) { val += a; } void adjust(utime_t now, const DecayRate& rate, double a) { decay(now, rate); val += a; } void scale(double f) { val *= f; delta *= f; vel *= f; } /** * decay etc. */ void reset(utime_t now) { last_decay = now; val = delta = 0; } void decay(utime_t now, const DecayRate &rate); }; inline void encode(const DecayCounter &c, bufferlist &bl) { c.encode(bl); } inline void decode(DecayCounter &c, const utime_t &t, bufferlist::iterator &p) { c.decode(t, p); } #endif ceph-0.80.11/src/common/safe_io.c0000664000175100017510000001066612623076744020536 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include "common/safe_io.h" #include "include/compat.h" ssize_t safe_read(int fd, void *buf, size_t count) { size_t cnt = 0; while (cnt < count) { ssize_t r = read(fd, buf, count - cnt); if (r <= 0) { if (r == 0) { // EOF return cnt; } if (errno == EINTR) continue; return -errno; } cnt += r; buf = (char *)buf + r; } return cnt; } ssize_t safe_read_exact(int fd, void *buf, size_t count) { ssize_t ret = safe_read(fd, buf, count); if (ret < 0) return ret; if ((size_t)ret != count) return -EDOM; return 0; } ssize_t safe_write(int fd, const void *buf, size_t count) { while (count > 0) { ssize_t r = write(fd, buf, count); if (r < 0) { if (errno == EINTR) continue; return -errno; } count -= r; buf = (char *)buf + r; } return 0; } ssize_t safe_pread(int fd, void *buf, size_t count, off_t offset) { size_t cnt = 0; char *b = (char*)buf; while (cnt < count) { ssize_t r = pread(fd, b + cnt, count - cnt, offset + cnt); if (r <= 0) { if (r == 0) { // EOF return cnt; } if (errno == EINTR) continue; return -errno; } cnt += r; } return cnt; } ssize_t safe_pread_exact(int fd, void *buf, size_t count, off_t offset) { ssize_t ret = safe_pread(fd, buf, count, offset); if (ret < 0) return ret; if ((size_t)ret != count) return -EDOM; return 0; } ssize_t safe_pwrite(int fd, const void *buf, size_t count, off_t offset) { while (count > 0) { ssize_t r = pwrite(fd, buf, count, offset); if (r < 0) { if (errno == EINTR) continue; return -errno; } count -= r; buf = (char *)buf + r; offset += r; } return 0; } #ifdef CEPH_HAVE_SPLICE ssize_t safe_splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) { size_t cnt = 0; while (cnt < len) { ssize_t r = splice(fd_in, off_in, fd_out, off_out, len - cnt, flags); if (r <= 0) { if (r == 0) { // EOF return cnt; } if (errno == EINTR) continue; return -errno; } cnt += r; } return cnt; } ssize_t safe_splice_exact(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) { ssize_t ret = safe_splice(fd_in, off_in, fd_out, off_out, len, flags); if (ret < 0) return ret; if ((size_t)ret != len) return -EDOM; return 0; } #endif int safe_write_file(const char *base, const char *file, const char *val, size_t vallen) { int ret; char fn[PATH_MAX]; char tmp[PATH_MAX]; int fd; // does the file already have correct content? char oldval[80]; ret = safe_read_file(base, file, oldval, sizeof(oldval)); if (ret == (int)vallen && memcmp(oldval, val, vallen) == 0) return 0; // yes. snprintf(fn, sizeof(fn), "%s/%s", base, file); snprintf(tmp, sizeof(tmp), "%s/%s.tmp", base, file); fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd < 0) { ret = errno; return -ret; } ret = safe_write(fd, val, vallen); if (ret) { VOID_TEMP_FAILURE_RETRY(close(fd)); return ret; } ret = fsync(fd); if (ret < 0) ret = -errno; VOID_TEMP_FAILURE_RETRY(close(fd)); if (ret < 0) { unlink(tmp); return ret; } ret = rename(tmp, fn); if (ret < 0) { ret = -errno; unlink(tmp); return ret; } fd = open(base, O_RDONLY); if (fd < 0) { ret = -errno; return ret; } ret = fsync(fd); if (ret < 0) ret = -errno; VOID_TEMP_FAILURE_RETRY(close(fd)); return ret; } int safe_read_file(const char *base, const char *file, char *val, size_t vallen) { char fn[PATH_MAX]; int fd, len; snprintf(fn, sizeof(fn), "%s/%s", base, file); fd = open(fn, O_RDONLY); if (fd < 0) { return -errno; } len = safe_read(fd, val, vallen - 1); if (len < 0) { VOID_TEMP_FAILURE_RETRY(close(fd)); return len; } // close sometimes returns errors, but only after write() VOID_TEMP_FAILURE_RETRY(close(fd)); val[len] = 0; return len; } ceph-0.80.11/src/common/linux_version.h0000664000175100017510000000053712623076744022036 0ustar jenkins-buildjenkins-build#ifndef CEPH_LINUX_VERSION_H #define CEPH_LINUX_VERSION_H #ifdef __cplusplus extern "C" { #endif #ifdef HAVE_LINUX_VERSION_H # include #endif #ifndef KERNEL_VERSION # define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #endif int get_linux_version(void); #ifdef __cplusplus } #endif #endif /* CEPH_LINUX_VERSION_H */ ceph-0.80.11/src/common/escape.h0000664000175100017510000000263612623076744020374 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RGW_ESCAPE_H #define CEPH_RGW_ESCAPE_H #ifdef __cplusplus extern "C" { #endif /* Returns the length of a buffer that would be needed to escape 'buf' * as an XML attrribute */ int escape_xml_attr_len(const char *buf); /* Escapes 'buf' as an XML attribute. Assumes that 'out' is at least long * enough to fit the output. You can find out the required length by calling * escape_xml_attr_len first. */ void escape_xml_attr(const char *buf, char *out); /* Returns the length of a buffer that would be needed to escape 'buf' * as an JSON attrribute */ int escape_json_attr_len(const char *buf); /* Escapes 'buf' as an JSON attribute. Assumes that 'out' is at least long * enough to fit the output. You can find out the required length by calling * escape_json_attr_len first. */ void escape_json_attr(const char *buf, char *out); /* Note: we escape control characters. Although the XML spec doesn't actually * require this, Amazon does it in their XML responses. */ #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/ceph_frag.cc0000664000175100017510000000052012623076744021176 0ustar jenkins-buildjenkins-build/* * Ceph 'frag' type */ #include "include/types.h" int ceph_frag_compare(__u32 a, __u32 b) { unsigned va = ceph_frag_value(a); unsigned vb = ceph_frag_value(b); if (va < vb) return -1; if (va > vb) return 1; va = ceph_frag_bits(a); vb = ceph_frag_bits(b); if (va < vb) return -1; if (va > vb) return 1; return 0; } ceph-0.80.11/src/common/BackTrace.cc0000664000175100017510000000323412623076744021104 0ustar jenkins-buildjenkins-build #include #include #include #include #include "BackTrace.h" #include "common/version.h" #include "acconfig.h" #define _STR(x) #x #define STRINGIFY(x) _STR(x) namespace ceph { void BackTrace::print(std::ostream& out) { out << " " << pretty_version_to_str() << std::endl; for (size_t i = skip; i < size; i++) { // out << " " << (i-skip+1) << ": " << strings[i] << std::endl; size_t sz = 1024; // just a guess, template names will go much wider char *function = (char *)malloc(sz); if (!function) return; char *begin = 0, *end = 0; // find the parentheses and address offset surrounding the mangled name for (char *j = strings[i]; *j; ++j) { if (*j == '(') begin = j+1; else if (*j == '+') end = j; } if (begin && end) { int len = end - begin; char *foo = (char *)malloc(len+1); if (!foo) { free(function); return; } memcpy(foo, begin, len); foo[len] = 0; int status; char *ret = abi::__cxa_demangle(foo, function, &sz, &status); if (ret) { // return value may be a realloc() of the input function = ret; } else { // demangling failed, just pretend it's a C function with no args strncpy(function, foo, sz); strncat(function, "()", sz); function[sz-1] = 0; } out << " " << (i-skip+1) << ": (" << function << end << std::endl; //fprintf(out, " %s:%s\n", stack.strings[i], function); free(foo); } else { // didn't find the mangled name, just print the whole line out << " " << (i-skip+1) << ": " << strings[i] << std::endl; } free(function); } }; } ceph-0.80.11/src/common/snap_types.h0000664000175100017510000000351612623076744021317 0ustar jenkins-buildjenkins-build#ifndef __CEPH_SNAP_TYPES_H #define __CEPH_SNAP_TYPES_H #include "include/types.h" namespace ceph { class Formatter; } struct SnapRealmInfo { mutable ceph_mds_snap_realm h; vector my_snaps; vector prior_parent_snaps; // before parent_since SnapRealmInfo() { memset(&h, 0, sizeof(h)); } SnapRealmInfo(inodeno_t ino_, snapid_t created_, snapid_t seq_, snapid_t current_parent_since_) { memset(&h, 0, sizeof(h)); h.ino = ino_; h.created = created_; h.seq = seq_; h.parent_since = current_parent_since_; } inodeno_t ino() const { return inodeno_t(h.ino); } inodeno_t parent() const { return inodeno_t(h.parent); } snapid_t seq() const { return snapid_t(h.seq); } snapid_t parent_since() const { return snapid_t(h.parent_since); } snapid_t created() const { return snapid_t(h.created); } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(SnapRealmInfo) struct SnapContext { snapid_t seq; // 'time' stamp vector snaps; // existent snaps, in descending order SnapContext() {} SnapContext(snapid_t s, const vector& v) : seq(s), snaps(v) {} bool is_valid() const; void clear() { seq = 0; snaps.clear(); } bool empty() { return seq == 0; } void encode(bufferlist& bl) const { ::encode(seq, bl); ::encode(snaps, bl); } void decode(bufferlist::iterator& bl) { ::decode(seq, bl); ::decode(snaps, bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(SnapContext) inline ostream& operator<<(ostream& out, const SnapContext& snapc) { return out << snapc.seq << "=" << snapc.snaps; } //} #endif ceph-0.80.11/src/common/simple_cache.hpp0000664000175100017510000000407612623076744022110 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SIMPLECACHE_H #define CEPH_SIMPLECACHE_H #include #include #include #include "common/Mutex.h" #include "common/Cond.h" template class SimpleLRU { Mutex lock; size_t max_size; map >::iterator> contents; list > lru; map pinned; void trim_cache() { while (lru.size() > max_size) { contents.erase(lru.back().first); lru.pop_back(); } } void _add(K key, V value) { lru.push_front(make_pair(key, value)); contents[key] = lru.begin(); trim_cache(); } public: SimpleLRU(size_t max_size) : lock("SimpleLRU::lock"), max_size(max_size) {} void pin(K key, V val) { Mutex::Locker l(lock); pinned.insert(make_pair(key, val)); } void clear_pinned(K e) { Mutex::Locker l(lock); for (typename map::iterator i = pinned.begin(); i != pinned.end() && i->first <= e; pinned.erase(i++)) { if (!contents.count(i->first)) _add(i->first, i->second); else lru.splice(lru.begin(), lru, contents[i->first]); } } void set_size(size_t new_size) { Mutex::Locker l(lock); max_size = new_size; trim_cache(); } bool lookup(K key, V *out) { Mutex::Locker l(lock); typename list >::iterator loc = contents.count(key) ? contents[key] : lru.end(); if (loc != lru.end()) { *out = loc->second; lru.splice(lru.begin(), lru, loc); return true; } if (pinned.count(key)) { *out = pinned[key]; return true; } return false; } void add(K key, V value) { Mutex::Locker l(lock); _add(key, value); } }; #endif ceph-0.80.11/src/common/LogClient.cc0000664000175100017510000001061212623076744021143 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "msg/Messenger.h" #include "msg/Message.h" #include "messages/MLog.h" #include "messages/MLogAck.h" #include "mon/MonMap.h" #include #include #include #include #ifdef DARWIN #include #include #endif // DARWIN #include "common/LogClient.h" #include "common/config.h" #define dout_subsys ceph_subsys_monc LogClient::LogClient(CephContext *cct, Messenger *m, MonMap *mm, enum logclient_flag_t flags) : cct(cct), messenger(m), monmap(mm), is_mon(flags & FLAG_MON), log_lock("LogClient::log_lock"), last_log_sent(0), last_log(0) { } LogClientTemp::LogClientTemp(clog_type type_, LogClient &parent_) : type(type_), parent(parent_) { } LogClientTemp::LogClientTemp(const LogClientTemp &rhs) : type(rhs.type), parent(rhs.parent) { // don't want to-- nor can we-- copy the ostringstream } LogClientTemp::~LogClientTemp() { if (ss.peek() != EOF) parent.do_log(type, ss); } void LogClient::do_log(clog_type type, std::stringstream& ss) { while (!ss.eof()) { string s; getline(ss, s); if (!s.empty()) do_log(type, s); } } void LogClient::do_log(clog_type type, const std::string& s) { Mutex::Locker l(log_lock); ldout(cct,0) << "log " << type << " : " << s << dendl; LogEntry e; e.who = messenger->get_myinst(); e.stamp = ceph_clock_now(cct); e.seq = ++last_log; e.type = type; e.msg = s; // log to syslog? if (cct->_conf->clog_to_syslog) { e.log_to_syslog(cct->_conf->clog_to_syslog_level, cct->_conf->clog_to_syslog_facility); } // log to monitor? if (cct->_conf->clog_to_monitors) { log_queue.push_back(e); // if we are a monitor, queue for ourselves, synchronously if (is_mon) { assert(messenger->get_myname().is_mon()); ldout(cct,10) << "send_log to self" << dendl; Message *log = _get_mon_log_message(); messenger->send_message(log, messenger->get_myinst()); } } } void LogClient::reset_session() { Mutex::Locker l(log_lock); last_log_sent = last_log - log_queue.size(); } Message *LogClient::get_mon_log_message() { Mutex::Locker l(log_lock); return _get_mon_log_message(); } bool LogClient::are_pending() { Mutex::Locker l(log_lock); return last_log > last_log_sent; } Message *LogClient::_get_mon_log_message() { assert(log_lock.is_locked()); if (log_queue.empty()) return NULL; // only send entries that haven't been sent yet during this mon // session! monclient needs to call reset_session() on mon session // reset for this to work right. if (last_log_sent == last_log) return NULL; // limit entries per message unsigned num_unsent = last_log - last_log_sent; unsigned num_send; if (cct->_conf->mon_client_max_log_entries_per_message > 0) num_send = MIN(num_unsent, (unsigned)cct->_conf->mon_client_max_log_entries_per_message); else num_send = num_unsent; ldout(cct,10) << " log_queue is " << log_queue.size() << " last_log " << last_log << " sent " << last_log_sent << " num " << log_queue.size() << " unsent " << num_unsent << " sending " << num_send << dendl; assert(num_unsent <= log_queue.size()); std::deque::iterator p = log_queue.begin(); std::deque o; while (p->seq <= last_log_sent) { ++p; assert(p != log_queue.end()); } while (num_send--) { assert(p != log_queue.end()); o.push_back(*p); last_log_sent = p->seq; ldout(cct,10) << " will send " << *p << dendl; ++p; } MLog *log = new MLog(monmap->get_fsid()); log->entries.swap(o); return log; } void LogClient::handle_log_ack(MLogAck *m) { Mutex::Locker l(log_lock); ldout(cct,10) << "handle_log_ack " << *m << dendl; version_t last = m->last; deque::iterator q = log_queue.begin(); while (q != log_queue.end()) { const LogEntry &entry(*q); if (entry.seq > last) break; ldout(cct,10) << " logged " << entry << dendl; q = log_queue.erase(q); } m->put(); } ceph-0.80.11/src/common/PrioritizedQueue.h0000664000175100017510000002430312623076744022440 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef PRIORITY_QUEUE_H #define PRIORITY_QUEUE_H #include "common/Mutex.h" #include "common/Formatter.h" #include #include #include #include /** * Manages queue for normal and strict priority items * * On dequeue, the queue will select the lowest priority queue * such that the q has bucket > cost of front queue item. * * If there is no such queue, we choose the next queue item for * the highest priority queue. * * Before returning a dequeued item, we place into each bucket * cost * (priority/total_priority) tokens. * * enqueue_strict and enqueue_strict_front queue items into queues * which are serviced in strict priority order before items queued * with enqueue and enqueue_front * * Within a priority class, we schedule round robin based on the class * of type K used to enqueue items. e.g. you could use entity_inst_t * to provide fairness for different clients. */ template class PrioritizedQueue { int64_t total_priority; int64_t max_tokens_per_subqueue; int64_t min_cost; template static unsigned filter_list_pairs( list > *l, F f, list *out) { unsigned ret = 0; if (out) { for (typename list >::reverse_iterator i = l->rbegin(); i != l->rend(); ++i) { if (f(i->second)) { out->push_front(i->second); } } } for (typename list >::iterator i = l->begin(); i != l->end(); ) { if (f(i->second)) { l->erase(i++); ++ret; } else { ++i; } } return ret; } struct SubQueue { private: map > > q; unsigned tokens, max_tokens; int64_t size; typename map > >::iterator cur; public: SubQueue(const SubQueue &other) : q(other.q), tokens(other.tokens), max_tokens(other.max_tokens), size(other.size), cur(q.begin()) {} SubQueue() : tokens(0), max_tokens(0), size(0), cur(q.begin()) {} void set_max_tokens(unsigned mt) { max_tokens = mt; } unsigned get_max_tokens() const { return max_tokens; } unsigned num_tokens() const { return tokens; } void put_tokens(unsigned t) { tokens += t; if (tokens > max_tokens) tokens = max_tokens; } void take_tokens(unsigned t) { if (tokens > t) tokens -= t; else tokens = 0; } void enqueue(K cl, unsigned cost, T item) { q[cl].push_back(make_pair(cost, item)); if (cur == q.end()) cur = q.begin(); size++; } void enqueue_front(K cl, unsigned cost, T item) { q[cl].push_front(make_pair(cost, item)); if (cur == q.end()) cur = q.begin(); size++; } pair front() const { assert(!(q.empty())); assert(cur != q.end()); return cur->second.front(); } void pop_front() { assert(!(q.empty())); assert(cur != q.end()); cur->second.pop_front(); if (cur->second.empty()) q.erase(cur++); else ++cur; if (cur == q.end()) cur = q.begin(); size--; } unsigned length() const { assert(size >= 0); return (unsigned)size; } bool empty() const { return q.empty(); } template void remove_by_filter(F f, list *out) { for (typename map > >::iterator i = q.begin(); i != q.end(); ) { size -= filter_list_pairs(&(i->second), f, out); if (i->second.empty()) { if (cur == i) ++cur; q.erase(i++); } else { ++i; } } if (cur == q.end()) cur = q.begin(); } void remove_by_class(K k, list *out) { typename map > >::iterator i = q.find(k); if (i == q.end()) return; size -= i->second.size(); if (i == cur) ++cur; if (out) { for (typename list >::reverse_iterator j = i->second.rbegin(); j != i->second.rend(); ++j) { out->push_front(j->second); } } q.erase(i); if (cur == q.end()) cur = q.begin(); } void dump(Formatter *f) const { f->dump_int("tokens", tokens); f->dump_int("max_tokens", max_tokens); f->dump_int("size", size); f->dump_int("num_keys", q.size()); if (!empty()) f->dump_int("first_item_cost", front().first); } }; map high_queue; map queue; SubQueue *create_queue(unsigned priority) { typename map::iterator p = queue.find(priority); if (p != queue.end()) return &p->second; total_priority += priority; SubQueue *sq = &queue[priority]; sq->set_max_tokens(max_tokens_per_subqueue); return sq; } void remove_queue(unsigned priority) { assert(queue.count(priority)); queue.erase(priority); total_priority -= priority; assert(total_priority >= 0); } void distribute_tokens(unsigned cost) { if (total_priority == 0) return; for (typename map::iterator i = queue.begin(); i != queue.end(); ++i) { i->second.put_tokens(((i->first * cost) / total_priority) + 1); } } public: PrioritizedQueue(unsigned max_per, unsigned min_c) : total_priority(0), max_tokens_per_subqueue(max_per), min_cost(min_c) {} unsigned length() const { unsigned total = 0; for (typename map::const_iterator i = queue.begin(); i != queue.end(); ++i) { assert(i->second.length()); total += i->second.length(); } for (typename map::const_iterator i = high_queue.begin(); i != high_queue.end(); ++i) { assert(i->second.length()); total += i->second.length(); } return total; } template void remove_by_filter(F f, list *removed = 0) { for (typename map::iterator i = queue.begin(); i != queue.end(); ) { unsigned priority = i->first; i->second.remove_by_filter(f, removed); if (i->second.empty()) { ++i; remove_queue(priority); } else { ++i; } } for (typename map::iterator i = high_queue.begin(); i != high_queue.end(); ) { i->second.remove_by_filter(f, removed); if (i->second.empty()) { high_queue.erase(i++); } else { ++i; } } } void remove_by_class(K k, list *out = 0) { for (typename map::iterator i = queue.begin(); i != queue.end(); ) { i->second.remove_by_class(k, out); if (i->second.empty()) { unsigned priority = i->first; ++i; remove_queue(priority); } else { ++i; } } for (typename map::iterator i = high_queue.begin(); i != high_queue.end(); ) { i->second.remove_by_class(k, out); if (i->second.empty()) { high_queue.erase(i++); } else { ++i; } } } void enqueue_strict(K cl, unsigned priority, T item) { high_queue[priority].enqueue(cl, 0, item); } void enqueue_strict_front(K cl, unsigned priority, T item) { high_queue[priority].enqueue_front(cl, 0, item); } void enqueue(K cl, unsigned priority, unsigned cost, T item) { if (cost < min_cost) cost = min_cost; if (cost > max_tokens_per_subqueue) cost = max_tokens_per_subqueue; create_queue(priority)->enqueue(cl, cost, item); } void enqueue_front(K cl, unsigned priority, unsigned cost, T item) { if (cost < min_cost) cost = min_cost; if (cost > max_tokens_per_subqueue) cost = max_tokens_per_subqueue; create_queue(priority)->enqueue_front(cl, cost, item); } bool empty() const { assert(total_priority >= 0); assert((total_priority == 0) || !(queue.empty())); return queue.empty() && high_queue.empty(); } T dequeue() { assert(!empty()); if (!(high_queue.empty())) { T ret = high_queue.rbegin()->second.front().second; high_queue.rbegin()->second.pop_front(); if (high_queue.rbegin()->second.empty()) high_queue.erase(high_queue.rbegin()->first); return ret; } // if there are multiple buckets/subqueues with sufficient tokens, // we behave like a strict priority queue among all subqueues that // are eligible to run. for (typename map::iterator i = queue.begin(); i != queue.end(); ++i) { assert(!(i->second.empty())); if (i->second.front().first < i->second.num_tokens()) { T ret = i->second.front().second; unsigned cost = i->second.front().first; i->second.take_tokens(cost); i->second.pop_front(); if (i->second.empty()) remove_queue(i->first); distribute_tokens(cost); return ret; } } // if no subqueues have sufficient tokens, we behave like a strict // priority queue. T ret = queue.rbegin()->second.front().second; unsigned cost = queue.rbegin()->second.front().first; queue.rbegin()->second.pop_front(); if (queue.rbegin()->second.empty()) remove_queue(queue.rbegin()->first); distribute_tokens(cost); return ret; } void dump(Formatter *f) const { f->dump_int("total_priority", total_priority); f->dump_int("max_tokens_per_subqueue", max_tokens_per_subqueue); f->dump_int("min_cost", min_cost); f->open_array_section("high_queues"); for (typename map::const_iterator p = high_queue.begin(); p != high_queue.end(); ++p) { f->open_object_section("subqueue"); f->dump_int("priority", p->first); p->second.dump(f); f->close_section(); } f->close_section(); f->open_array_section("queues"); for (typename map::const_iterator p = queue.begin(); p != queue.end(); ++p) { f->open_object_section("subqueue"); f->dump_int("priority", p->first); p->second.dump(f); f->close_section(); } f->close_section(); } }; #endif ceph-0.80.11/src/common/run_cmd.cc0000664000175100017510000000367112623076744020721 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/errno.h" #include #include #include #include #include #include #include #include using std::ostringstream; std::string run_cmd(const char *cmd, ...) { std::vector arr; va_list ap; va_start(ap, cmd); const char *c = cmd; do { arr.push_back(c); c = va_arg(ap, const char*); } while (c != NULL); va_end(ap); arr.push_back(NULL); int fret = fork(); if (fret == -1) { int err = errno; ostringstream oss; oss << "run_cmd(" << cmd << "): unable to fork(): " << cpp_strerror(err); return oss.str(); } else if (fret == 0) { // execvp doesn't modify its arguments, so the const-cast here is safe. execvp(cmd, (char * const*)&arr[0]); _exit(127); } int status; while (waitpid(fret, &status, 0) == -1) { int err = errno; if (err == EINTR) continue; ostringstream oss; oss << "run_cmd(" << cmd << "): waitpid error: " << cpp_strerror(err); return oss.str(); } if (WIFEXITED(status)) { int wexitstatus = WEXITSTATUS(status); if (wexitstatus != 0) { ostringstream oss; oss << "run_cmd(" << cmd << "): exited with status " << wexitstatus; return oss.str(); } return ""; } else if (WIFSIGNALED(status)) { ostringstream oss; oss << "run_cmd(" << cmd << "): terminated by signal"; return oss.str(); } ostringstream oss; oss << "run_cmd(" << cmd << "): terminated by unknown mechanism"; return oss.str(); } ceph-0.80.11/src/common/crc32c_intel_baseline.c0000664000175100017510000001271112623076744023236 0ustar jenkins-buildjenkins-build/* * Copyright 2012-2013 Intel Corporation All Rights Reserved. * All rights reserved. * * http://opensource.org/licenses/BSD-3-Clause * * 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 the Intel Corporation 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 HOLDER 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. */ #include "include/int_types.h" #include #define MAX_ITER 8 unsigned long crc32_table_iscsi_base[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, }; // iSCSI CRC baseline function uint32_t ceph_crc32c_intel_baseline(uint32_t crc_init2, unsigned char const *buffer, unsigned len) { unsigned int crc_init = crc_init2; unsigned int crc; unsigned char* p_buf; if (buffer) { p_buf = (unsigned char*)buffer; unsigned char const * p_end = buffer + len; crc = crc_init; while (p_buf < (unsigned char *) p_end ){ crc = (crc >> 8) ^ crc32_table_iscsi_base[(crc & 0x000000FF) ^ *p_buf++]; } } else { crc = crc_init; while (len--) { crc = (crc >> 8) ^ crc32_table_iscsi_base[(crc & 0x000000FF)]; } } return crc; } ceph-0.80.11/src/common/signal.cc0000664000175100017510000000352412623076744020544 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/BackTrace.h" #include "common/perf_counters.h" #include "global/pidfile.h" #include "common/debug.h" #include "common/signal.h" #include "common/config.h" #include #include #include #include #include std::string signal_mask_to_str() { sigset_t old_sigset; if (pthread_sigmask(SIG_SETMASK, NULL, &old_sigset)) { return "(pthread_signmask failed)"; } ostringstream oss; oss << "show_signal_mask: { "; string sep(""); for (int signum = 0; signum < NSIG; ++signum) { if (sigismember(&old_sigset, signum) == 1) { oss << sep << signum; sep = ", "; } } oss << " }"; return oss.str(); } /* Block the signals in 'siglist'. If siglist == NULL, block all signals. */ void block_signals(const int *siglist, sigset_t *old_sigset) { sigset_t sigset; if (!siglist) { sigfillset(&sigset); } else { int i = 0; sigemptyset(&sigset); while (siglist[i]) { sigaddset(&sigset, siglist[i]); ++i; } } int ret = pthread_sigmask(SIG_BLOCK, &sigset, old_sigset); assert(ret == 0); } void restore_sigset(const sigset_t *old_sigset) { int ret = pthread_sigmask(SIG_SETMASK, old_sigset, NULL); assert(ret == 0); } void unblock_all_signals(sigset_t *old_sigset) { sigset_t sigset; sigfillset(&sigset); sigdelset(&sigset, SIGKILL); int ret = pthread_sigmask(SIG_UNBLOCK, &sigset, old_sigset); assert(ret == 0); } ceph-0.80.11/src/common/ceph_argparse.h0000664000175100017510000000523612623076744021736 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2008-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_ARGPARSE_H #define CEPH_ARGPARSE_H /* * Ceph argument parsing library * * We probably should eventually replace this with something standard like popt. * Until we do that, though, this file is the place for argv parsing * stuff to live. */ #include #include #include #include #include "common/entity_name.h" #include "msg/msg_types.h" /////////////////////// Types /////////////////////// class CephInitParameters { public: CephInitParameters(uint32_t module_type_); std::list get_conf_files() const; uint32_t module_type; EntityName name; }; /////////////////////// Functions /////////////////////// extern void string_to_vec(std::vector& args, std::string argstr); extern void env_to_vec(std::vector& args, const char *name=NULL); extern void argv_to_vec(int argc, const char **argv, std::vector& args); extern void vec_to_argv(const char *argv0, std::vector& args, int *argc, const char ***argv); extern bool parse_ip_port_vec(const char *s, std::vector& vec); bool ceph_argparse_double_dash(std::vector &args, std::vector::iterator &i); bool ceph_argparse_flag(std::vector &args, std::vector::iterator &i, ...); bool ceph_argparse_witharg(std::vector &args, std::vector::iterator &i, std::string *ret, ...); bool ceph_argparse_binary_flag(std::vector &args, std::vector::iterator &i, int *ret, std::ostream *oss, ...); extern CephInitParameters ceph_argparse_early_args (std::vector& args, uint32_t module_type, int flags, std::string *cluster, std::string *conf_file_list); extern bool ceph_argparse_withint(std::vector &args, std::vector::iterator &i, int *ret, std::ostream *oss, ...); extern bool ceph_argparse_withfloat(std::vector &args, std::vector::iterator &i, float *ret, std::ostream *oss, ...); extern bool ceph_argparse_withlonglong(std::vector &args, std::vector::iterator &i, long long *ret, std::ostream *oss, ...); extern void generic_server_usage(); extern void generic_client_usage(); #endif ceph-0.80.11/src/common/hex.h0000664000175100017510000000116612623076744017715 0ustar jenkins-buildjenkins-build // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_HEX_H #define CEPH_COMMON_HEX_H #include extern void hex2str(const char *s, int len, char *buf, int dest_len); extern std::string hexdump(std::string msg, const char *s, int len); #endif ceph-0.80.11/src/common/Preforker.h0000664000175100017510000000432612623076744021071 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_COMMON_PREFORKER_H #define CEPH_COMMON_PREFORKER_H #include #include #include #include #include #include "common/safe_io.h" #include "common/errno.h" /** * pre-fork fork/daemonize helper class * * Hide the details of letting a process fork early, do a bunch of * initialization work that may spam stdout or exit with an error, and * then daemonize. The exit() method will either exit directly (if we * haven't forked) or pass a message to the parent with the error if * we have. */ class Preforker { pid_t childpid; bool forked; int fd[2]; // parent's, child's public: Preforker() : childpid(0), forked(false) {} void prefork() { assert(!forked); int r = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); if (r < 0) { cerr << "[" << getpid() << "]: unable to create socketpair: " << cpp_strerror(errno) << std::endl; exit(errno); } forked = true; childpid = fork(); if (childpid == 0) { ::close(fd[0]); } else { ::close(fd[1]); } } bool is_child() { return childpid == 0; } bool is_parent() { return childpid != 0; } int parent_wait() { assert(forked); int r = -1; int err = safe_read_exact(fd[0], &r, sizeof(r)); if (err == 0 && r == -1) { // daemonize ::close(0); ::close(1); ::close(2); r = 0; } else if (err) { cerr << "[" << getpid() << "]: " << cpp_strerror(err) << std::endl; } else { // wait for child to exit waitpid(childpid, NULL, 0); } return r; } int signal_exit(int r) { if (forked) { // tell parent. this shouldn't fail, but if it does, pass the // error back to the parent. int ret = safe_write(fd[1], &r, sizeof(r)); if (ret <= 0) return ret; } return r; } void exit(int r) { signal_exit(r); ::exit(r); } void daemonize() { assert(forked); static int r = -1; int r2 = ::write(fd[1], &r, sizeof(r)); r += r2; // make the compiler shut up about the unused return code from ::write(2). } }; #endif ceph-0.80.11/src/common/buffer.cc0000664000175100017510000012527712623076744020552 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "armor.h" #include "common/environment.h" #include "common/errno.h" #include "common/safe_io.h" #include "common/simple_spin.h" #include "common/strtol.h" #include "include/atomic.h" #include "common/Mutex.h" #include "include/types.h" #include "include/compat.h" #include #include #include #include #include namespace ceph { #ifdef BUFFER_DEBUG static uint32_t simple_spinlock_t buffer_debug_lock = SIMPLE_SPINLOCK_INITIALIZER; # define bdout { simple_spin_lock(&buffer_debug_lock); std::cout # define bendl std::endl; simple_spin_unlock(&buffer_debug_lock); } #else # define bdout if (0) { std::cout # define bendl std::endl; } #endif atomic_t buffer_total_alloc; bool buffer_track_alloc = get_env_bool("CEPH_BUFFER_TRACK"); void buffer::inc_total_alloc(unsigned len) { if (buffer_track_alloc) buffer_total_alloc.add(len); } void buffer::dec_total_alloc(unsigned len) { if (buffer_track_alloc) buffer_total_alloc.sub(len); } int buffer::get_total_alloc() { return buffer_total_alloc.read(); } atomic_t buffer_cached_crc; atomic_t buffer_cached_crc_adjusted; bool buffer_track_crc = get_env_bool("CEPH_BUFFER_TRACK"); void buffer::track_cached_crc(bool b) { buffer_track_crc = b; } int buffer::get_cached_crc() { return buffer_cached_crc.read(); } int buffer::get_cached_crc_adjusted() { return buffer_cached_crc_adjusted.read(); } atomic_t buffer_c_str_accesses; bool buffer_track_c_str = get_env_bool("CEPH_BUFFER_TRACK"); void buffer::track_c_str(bool b) { buffer_track_c_str = b; } int buffer::get_c_str_accesses() { return buffer_c_str_accesses.read(); } atomic_t buffer_max_pipe_size; int update_max_pipe_size() { #ifdef CEPH_HAVE_SETPIPE_SZ char buf[32]; int r; std::string err; struct stat stat_result; if (::stat("/proc/sys/fs/pipe-max-size", &stat_result) == -1) return -errno; r = safe_read_file("/proc/sys/fs/", "pipe-max-size", buf, sizeof(buf) - 1); if (r < 0) return r; buf[r] = '\0'; size_t size = strict_strtol(buf, 10, &err); if (!err.empty()) return -EIO; buffer_max_pipe_size.set(size); #endif return 0; } size_t get_max_pipe_size() { #ifdef CEPH_HAVE_SETPIPE_SZ size_t size = buffer_max_pipe_size.read(); if (size) return size; if (update_max_pipe_size() == 0) return buffer_max_pipe_size.read(); #endif // this is the max size hardcoded in linux before 2.6.35 return 65536; } buffer::error_code::error_code(int error) : buffer::malformed_input(cpp_strerror(error).c_str()), code(error) {} class buffer::raw { public: char *data; unsigned len; atomic_t nref; mutable Mutex crc_lock; map, pair > crc_map; raw(unsigned l) : data(NULL), len(l), nref(0), crc_lock("buffer::raw::crc_lock", false, false) { } raw(char *c, unsigned l) : data(c), len(l), nref(0), crc_lock("buffer::raw::crc_lock", false, false) { } virtual ~raw() {}; // no copying. raw(const raw &other); const raw& operator=(const raw &other); virtual char *get_data() { return data; } virtual raw* clone_empty() = 0; raw *clone() { raw *c = clone_empty(); memcpy(c->data, data, len); return c; } virtual bool can_zero_copy() const { return false; } virtual int zero_copy_to_fd(int fd, loff_t *offset) { return -ENOTSUP; } virtual bool is_page_aligned() { return ((long)data & ~CEPH_PAGE_MASK) == 0; } bool is_n_page_sized() { return (len & ~CEPH_PAGE_MASK) == 0; } bool get_crc(const pair &fromto, pair *crc) const { Mutex::Locker l(crc_lock); map, pair >::const_iterator i = crc_map.find(fromto); if (i == crc_map.end()) return false; *crc = i->second; return true; } void set_crc(const pair &fromto, const pair &crc) { Mutex::Locker l(crc_lock); crc_map[fromto] = crc; } void invalidate_crc() { Mutex::Locker l(crc_lock); crc_map.clear(); } }; class buffer::raw_malloc : public buffer::raw { public: raw_malloc(unsigned l) : raw(l) { if (len) { data = (char *)malloc(len); if (!data) throw bad_alloc(); } else { data = 0; } inc_total_alloc(len); bdout << "raw_malloc " << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl; } raw_malloc(unsigned l, char *b) : raw(b, l) { inc_total_alloc(len); bdout << "raw_malloc " << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl; } ~raw_malloc() { free(data); dec_total_alloc(len); bdout << "raw_malloc " << this << " free " << (void *)data << " " << buffer::get_total_alloc() << bendl; } raw* clone_empty() { return new raw_malloc(len); } }; #ifndef __CYGWIN__ class buffer::raw_mmap_pages : public buffer::raw { public: raw_mmap_pages(unsigned l) : raw(l) { data = (char*)::mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (!data) throw bad_alloc(); inc_total_alloc(len); bdout << "raw_mmap " << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl; } ~raw_mmap_pages() { ::munmap(data, len); dec_total_alloc(len); bdout << "raw_mmap " << this << " free " << (void *)data << " " << buffer::get_total_alloc() << bendl; } raw* clone_empty() { return new raw_mmap_pages(len); } }; class buffer::raw_posix_aligned : public buffer::raw { public: raw_posix_aligned(unsigned l) : raw(l) { #ifdef DARWIN data = (char *) valloc (len); #else data = 0; int r = ::posix_memalign((void**)(void*)&data, CEPH_PAGE_SIZE, len); if (r) throw bad_alloc(); #endif /* DARWIN */ if (!data) throw bad_alloc(); inc_total_alloc(len); bdout << "raw_posix_aligned " << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl; } ~raw_posix_aligned() { ::free((void*)data); dec_total_alloc(len); bdout << "raw_posix_aligned " << this << " free " << (void *)data << " " << buffer::get_total_alloc() << bendl; } raw* clone_empty() { return new raw_posix_aligned(len); } }; #endif #ifdef __CYGWIN__ class buffer::raw_hack_aligned : public buffer::raw { char *realdata; public: raw_hack_aligned(unsigned l) : raw(l) { realdata = new char[len+CEPH_PAGE_SIZE-1]; unsigned off = ((unsigned)realdata) & ~CEPH_PAGE_MASK; if (off) data = realdata + CEPH_PAGE_SIZE - off; else data = realdata; inc_total_alloc(len+CEPH_PAGE_SIZE-1); //cout << "hack aligned " << (unsigned)data //<< " in raw " << (unsigned)realdata //<< " off " << off << std::endl; assert(((unsigned)data & (CEPH_PAGE_SIZE-1)) == 0); } ~raw_hack_aligned() { delete[] realdata; dec_total_alloc(len+CEPH_PAGE_SIZE-1); } raw* clone_empty() { return new raw_hack_aligned(len); } }; #endif #ifdef CEPH_HAVE_SPLICE class buffer::raw_pipe : public buffer::raw { public: raw_pipe(unsigned len) : raw(len), source_consumed(false) { size_t max = get_max_pipe_size(); if (len > max) { bdout << "raw_pipe: requested length " << len << " > max length " << max << bendl; throw malformed_input("length larger than max pipe size"); } pipefds[0] = -1; pipefds[1] = -1; int r; if (::pipe(pipefds) == -1) { r = -errno; bdout << "raw_pipe: error creating pipe: " << cpp_strerror(r) << bendl; throw error_code(r); } r = set_nonblocking(pipefds); if (r < 0) { bdout << "raw_pipe: error setting nonblocking flag on temp pipe: " << cpp_strerror(r) << bendl; throw error_code(r); } r = set_pipe_size(pipefds, len); if (r < 0) { bdout << "raw_pipe: could not set pipe size" << bendl; // continue, since the pipe should become large enough as needed } inc_total_alloc(len); bdout << "raw_pipe " << this << " alloc " << len << " " << buffer::get_total_alloc() << bendl; } ~raw_pipe() { if (data) delete data; close_pipe(pipefds); dec_total_alloc(len); bdout << "raw_pipe " << this << " free " << (void *)data << " " << buffer::get_total_alloc() << bendl; } bool can_zero_copy() const { return true; } bool is_page_aligned() { return false; } int set_source(int fd, loff_t *off) { int flags = SPLICE_F_NONBLOCK; ssize_t r = safe_splice(fd, off, pipefds[1], NULL, len, flags); if (r < 0) { bdout << "raw_pipe: error splicing into pipe: " << cpp_strerror(r) << bendl; return r; } // update length with actual amount read len = r; return 0; } int zero_copy_to_fd(int fd, loff_t *offset) { assert(!source_consumed); int flags = SPLICE_F_NONBLOCK; ssize_t r = safe_splice_exact(pipefds[0], NULL, fd, offset, len, flags); if (r < 0) { bdout << "raw_pipe: error splicing from pipe to fd: " << cpp_strerror(r) << bendl; return r; } source_consumed = true; return 0; } buffer::raw* clone_empty() { // cloning doesn't make sense for pipe-based buffers, // and is only used by unit tests for other types of buffers return NULL; } char *get_data() { if (data) return data; return copy_pipe(pipefds); } private: int set_pipe_size(int *fds, long length) { #ifdef CEPH_HAVE_SETPIPE_SZ if (::fcntl(fds[1], F_SETPIPE_SZ, length) == -1) { int r = -errno; if (r == -EPERM) { // pipe limit must have changed - EPERM means we requested // more than the maximum size as an unprivileged user update_max_pipe_size(); throw malformed_input("length larger than new max pipe size"); } return r; } #endif return 0; } int set_nonblocking(int *fds) { if (::fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1) return -errno; if (::fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1) return -errno; return 0; } void close_pipe(int *fds) { if (fds[0] >= 0) VOID_TEMP_FAILURE_RETRY(::close(fds[0])); if (fds[1] >= 0) VOID_TEMP_FAILURE_RETRY(::close(fds[1])); } char *copy_pipe(int *fds) { /* preserve original pipe contents by copying into a temporary * pipe before reading. */ int tmpfd[2]; int r; assert(!source_consumed); assert(fds[0] >= 0); if (::pipe(tmpfd) == -1) { r = -errno; bdout << "raw_pipe: error creating temp pipe: " << cpp_strerror(r) << bendl; throw error_code(r); } r = set_nonblocking(tmpfd); if (r < 0) { bdout << "raw_pipe: error setting nonblocking flag on temp pipe: " << cpp_strerror(r) << bendl; throw error_code(r); } r = set_pipe_size(tmpfd, len); if (r < 0) { bdout << "raw_pipe: error setting pipe size on temp pipe: " << cpp_strerror(r) << bendl; } int flags = SPLICE_F_NONBLOCK; if (::tee(fds[0], tmpfd[1], len, flags) == -1) { r = errno; bdout << "raw_pipe: error tee'ing into temp pipe: " << cpp_strerror(r) << bendl; close_pipe(tmpfd); throw error_code(r); } data = (char *)malloc(len); if (!data) { close_pipe(tmpfd); throw bad_alloc(); } r = safe_read(tmpfd[0], data, len); if (r < (ssize_t)len) { bdout << "raw_pipe: error reading from temp pipe:" << cpp_strerror(r) << bendl; free(data); data = NULL; close_pipe(tmpfd); throw error_code(r); } close_pipe(tmpfd); return data; } bool source_consumed; int pipefds[2]; }; #endif // CEPH_HAVE_SPLICE /* * primitive buffer types */ class buffer::raw_char : public buffer::raw { public: raw_char(unsigned l) : raw(l) { if (len) data = new char[len]; else data = 0; inc_total_alloc(len); bdout << "raw_char " << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl; } raw_char(unsigned l, char *b) : raw(b, l) { inc_total_alloc(len); bdout << "raw_char " << this << " alloc " << (void *)data << " " << l << " " << buffer::get_total_alloc() << bendl; } ~raw_char() { delete[] data; dec_total_alloc(len); bdout << "raw_char " << this << " free " << (void *)data << " " << buffer::get_total_alloc() << bendl; } raw* clone_empty() { return new raw_char(len); } }; class buffer::raw_static : public buffer::raw { public: raw_static(const char *d, unsigned l) : raw((char*)d, l) { } ~raw_static() {} raw* clone_empty() { return new buffer::raw_char(len); } }; buffer::raw* buffer::copy(const char *c, unsigned len) { raw* r = new raw_char(len); memcpy(r->data, c, len); return r; } buffer::raw* buffer::create(unsigned len) { return new raw_char(len); } buffer::raw* buffer::claim_char(unsigned len, char *buf) { return new raw_char(len, buf); } buffer::raw* buffer::create_malloc(unsigned len) { return new raw_malloc(len); } buffer::raw* buffer::claim_malloc(unsigned len, char *buf) { return new raw_malloc(len, buf); } buffer::raw* buffer::create_static(unsigned len, char *buf) { return new raw_static(buf, len); } buffer::raw* buffer::create_page_aligned(unsigned len) { #ifndef __CYGWIN__ //return new raw_mmap_pages(len); return new raw_posix_aligned(len); #else return new raw_hack_aligned(len); #endif } buffer::raw* buffer::create_zero_copy(unsigned len, int fd, int64_t *offset) { #ifdef CEPH_HAVE_SPLICE buffer::raw_pipe* buf = new raw_pipe(len); int r = buf->set_source(fd, (loff_t*)offset); if (r < 0) { delete buf; throw error_code(r); } return buf; #else throw error_code(-ENOTSUP); #endif } buffer::ptr::ptr(raw *r) : _raw(r), _off(0), _len(r->len) // no lock needed; this is an unref raw. { r->nref.inc(); bdout << "ptr " << this << " get " << _raw << bendl; } buffer::ptr::ptr(unsigned l) : _off(0), _len(l) { _raw = create(l); _raw->nref.inc(); bdout << "ptr " << this << " get " << _raw << bendl; } buffer::ptr::ptr(const char *d, unsigned l) : _off(0), _len(l) // ditto. { _raw = copy(d, l); _raw->nref.inc(); bdout << "ptr " << this << " get " << _raw << bendl; } buffer::ptr::ptr(const ptr& p) : _raw(p._raw), _off(p._off), _len(p._len) { if (_raw) { _raw->nref.inc(); bdout << "ptr " << this << " get " << _raw << bendl; } } buffer::ptr::ptr(const ptr& p, unsigned o, unsigned l) : _raw(p._raw), _off(p._off + o), _len(l) { assert(o+l <= p._len); assert(_raw); _raw->nref.inc(); bdout << "ptr " << this << " get " << _raw << bendl; } buffer::ptr& buffer::ptr::operator= (const ptr& p) { if (p._raw) { p._raw->nref.inc(); bdout << "ptr " << this << " get " << _raw << bendl; } buffer::raw *raw = p._raw; release(); if (raw) { _raw = raw; _off = p._off; _len = p._len; } else { _off = _len = 0; } return *this; } buffer::raw *buffer::ptr::clone() { return _raw->clone(); } void buffer::ptr::swap(ptr& other) { raw *r = _raw; unsigned o = _off; unsigned l = _len; _raw = other._raw; _off = other._off; _len = other._len; other._raw = r; other._off = o; other._len = l; } void buffer::ptr::release() { if (_raw) { bdout << "ptr " << this << " release " << _raw << bendl; if (_raw->nref.dec() == 0) { //cout << "hosing raw " << (void*)_raw << " len " << _raw->len << std::endl; delete _raw; // dealloc old (if any) } _raw = 0; } } bool buffer::ptr::at_buffer_tail() const { return _off + _len == _raw->len; } const char *buffer::ptr::c_str() const { assert(_raw); if (buffer_track_c_str) buffer_c_str_accesses.inc(); return _raw->get_data() + _off; } char *buffer::ptr::c_str() { assert(_raw); if (buffer_track_c_str) buffer_c_str_accesses.inc(); return _raw->get_data() + _off; } unsigned buffer::ptr::unused_tail_length() const { if (_raw) return _raw->len - (_off+_len); else return 0; } const char& buffer::ptr::operator[](unsigned n) const { assert(_raw); assert(n < _len); return _raw->get_data()[_off + n]; } char& buffer::ptr::operator[](unsigned n) { assert(_raw); assert(n < _len); return _raw->get_data()[_off + n]; } const char *buffer::ptr::raw_c_str() const { assert(_raw); return _raw->data; } unsigned buffer::ptr::raw_length() const { assert(_raw); return _raw->len; } int buffer::ptr::raw_nref() const { assert(_raw); return _raw->nref.read(); } unsigned buffer::ptr::wasted() { assert(_raw); return _raw->len - _len; } int buffer::ptr::cmp(const ptr& o) const { int l = _len < o._len ? _len : o._len; if (l) { int r = memcmp(c_str(), o.c_str(), l); if (r) return r; } if (_len < o._len) return -1; if (_len > o._len) return 1; return 0; } bool buffer::ptr::is_zero() const { const char *data = c_str(); for (size_t p = 0; p < _len; p++) { if (data[p] != 0) { return false; } } return true; } void buffer::ptr::append(char c) { assert(_raw); assert(1 <= unused_tail_length()); (c_str())[_len] = c; _len++; } void buffer::ptr::append(const char *p, unsigned l) { assert(_raw); assert(l <= unused_tail_length()); memcpy(c_str() + _len, p, l); _len += l; } void buffer::ptr::copy_in(unsigned o, unsigned l, const char *src) { assert(_raw); assert(o <= _len); assert(o+l <= _len); _raw->invalidate_crc(); memcpy(c_str()+o, src, l); } void buffer::ptr::zero() { _raw->invalidate_crc(); memset(c_str(), 0, _len); } void buffer::ptr::zero(unsigned o, unsigned l) { assert(o+l <= _len); _raw->invalidate_crc(); memset(c_str()+o, 0, l); } bool buffer::ptr::can_zero_copy() const { return _raw->can_zero_copy(); } int buffer::ptr::zero_copy_to_fd(int fd, int64_t *offset) const { return _raw->zero_copy_to_fd(fd, (loff_t*)offset); } // -- buffer::list::iterator -- /* buffer::list::iterator operator=(const buffer::list::iterator& other) { if (this != &other) { bl = other.bl; ls = other.ls; off = other.off; p = other.p; p_off = other.p_off; } return *this; }*/ void buffer::list::iterator::advance(int o) { //cout << this << " advance " << o << " from " << off << " (p_off " << p_off << " in " << p->length() << ")" << std::endl; if (o > 0) { p_off += o; while (p_off > 0) { if (p == ls->end()) throw end_of_buffer(); if (p_off >= p->length()) { // skip this buffer p_off -= p->length(); p++; } else { // somewhere in this buffer! break; } } off += o; return; } while (o < 0) { if (p_off) { unsigned d = -o; if (d > p_off) d = p_off; p_off -= d; off -= d; o += d; } else if (off > 0) { assert(p != ls->begin()); p--; p_off = p->length(); } else { throw end_of_buffer(); } } } void buffer::list::iterator::seek(unsigned o) { //cout << this << " seek " << o << std::endl; p = ls->begin(); off = p_off = 0; advance(o); } char buffer::list::iterator::operator*() { if (p == ls->end()) throw end_of_buffer(); return (*p)[p_off]; } buffer::list::iterator& buffer::list::iterator::operator++() { if (p == ls->end()) throw end_of_buffer(); advance(1); return *this; } buffer::ptr buffer::list::iterator::get_current_ptr() { if (p == ls->end()) throw end_of_buffer(); return ptr(*p, p_off, p->length() - p_off); } // copy data out. // note that these all _append_ to dest! void buffer::list::iterator::copy(unsigned len, char *dest) { if (p == ls->end()) seek(off); while (len > 0) { if (p == ls->end()) throw end_of_buffer(); assert(p->length() > 0); unsigned howmuch = p->length() - p_off; if (len < howmuch) howmuch = len; p->copy_out(p_off, howmuch, dest); dest += howmuch; len -= howmuch; advance(howmuch); } } void buffer::list::iterator::copy(unsigned len, ptr &dest) { dest = create(len); copy(len, dest.c_str()); } void buffer::list::iterator::copy(unsigned len, list &dest) { if (p == ls->end()) seek(off); while (len > 0) { if (p == ls->end()) throw end_of_buffer(); unsigned howmuch = p->length() - p_off; if (len < howmuch) howmuch = len; dest.append(*p, p_off, howmuch); len -= howmuch; advance(howmuch); } } void buffer::list::iterator::copy(unsigned len, std::string &dest) { if (p == ls->end()) seek(off); while (len > 0) { if (p == ls->end()) throw end_of_buffer(); unsigned howmuch = p->length() - p_off; const char *c_str = p->c_str(); if (len < howmuch) howmuch = len; dest.append(c_str + p_off, howmuch); len -= howmuch; advance(howmuch); } } void buffer::list::iterator::copy_all(list &dest) { if (p == ls->end()) seek(off); while (1) { if (p == ls->end()) return; assert(p->length() > 0); unsigned howmuch = p->length() - p_off; const char *c_str = p->c_str(); dest.append(c_str + p_off, howmuch); advance(howmuch); } } // copy data in void buffer::list::iterator::copy_in(unsigned len, const char *src) { // copy if (p == ls->end()) seek(off); while (len > 0) { if (p == ls->end()) throw end_of_buffer(); unsigned howmuch = p->length() - p_off; if (len < howmuch) howmuch = len; p->copy_in(p_off, howmuch, src); src += howmuch; len -= howmuch; advance(howmuch); } } void buffer::list::iterator::copy_in(unsigned len, const list& otherl) { if (p == ls->end()) seek(off); unsigned left = len; for (std::list::const_iterator i = otherl._buffers.begin(); i != otherl._buffers.end(); ++i) { unsigned l = (*i).length(); if (left < l) l = left; copy_in(l, i->c_str()); left -= l; if (left == 0) break; } } // -- buffer::list -- void buffer::list::swap(list& other) { std::swap(_len, other._len); _buffers.swap(other._buffers); append_buffer.swap(other.append_buffer); //last_p.swap(other.last_p); last_p = begin(); other.last_p = other.begin(); } bool buffer::list::contents_equal(ceph::buffer::list& other) { if (length() != other.length()) return false; // buffer-wise comparison if (true) { std::list::const_iterator a = _buffers.begin(); std::list::const_iterator b = other._buffers.begin(); unsigned aoff = 0, boff = 0; while (a != _buffers.end()) { unsigned len = a->length() - aoff; if (len > b->length() - boff) len = b->length() - boff; if (memcmp(a->c_str() + aoff, b->c_str() + boff, len) != 0) return false; aoff += len; if (aoff == a->length()) { aoff = 0; ++a; } boff += len; if (boff == b->length()) { boff = 0; ++b; } } assert(b == other._buffers.end()); return true; } // byte-wise comparison if (false) { bufferlist::iterator me = begin(); bufferlist::iterator him = other.begin(); while (!me.end()) { if (*me != *him) return false; ++me; ++him; } return true; } } bool buffer::list::can_zero_copy() const { for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); ++it) if (!it->can_zero_copy()) return false; return true; } bool buffer::list::is_page_aligned() const { for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); ++it) if (!it->is_page_aligned()) return false; return true; } bool buffer::list::is_n_page_sized() const { for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); ++it) if (!it->is_n_page_sized()) return false; return true; } bool buffer::list::is_zero() const { for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); ++it) { if (!it->is_zero()) { return false; } } return true; } void buffer::list::zero() { for (std::list::iterator it = _buffers.begin(); it != _buffers.end(); ++it) it->zero(); } void buffer::list::zero(unsigned o, unsigned l) { assert(o+l <= _len); unsigned p = 0; for (std::list::iterator it = _buffers.begin(); it != _buffers.end(); ++it) { if (p + it->length() > o) { if (p >= o && p+it->length() <= o+l) { // 'o'------------- l -----------| // 'p'-- it->length() --| it->zero(); } else if (p >= o) { // 'o'------------- l -----------| // 'p'------- it->length() -------| it->zero(0, o+l-p); } else if (p + it->length() <= o+l) { // 'o'------------- l -----------| // 'p'------- it->length() -------| it->zero(o-p, it->length()-(o-p)); } else { // 'o'----------- l -----------| // 'p'---------- it->length() ----------| it->zero(o-p, l); } } p += it->length(); if (o+l <= p) break; // done } } bool buffer::list::is_contiguous() { return &(*_buffers.begin()) == &(*_buffers.rbegin()); } void buffer::list::rebuild() { ptr nb; if ((_len & ~CEPH_PAGE_MASK) == 0) nb = buffer::create_page_aligned(_len); else nb = buffer::create(_len); rebuild(nb); } void buffer::list::rebuild(ptr& nb) { unsigned pos = 0; for (std::list::iterator it = _buffers.begin(); it != _buffers.end(); ++it) { nb.copy_in(pos, it->length(), it->c_str()); pos += it->length(); } _buffers.clear(); _buffers.push_back(nb); } void buffer::list::rebuild_page_aligned() { std::list::iterator p = _buffers.begin(); while (p != _buffers.end()) { // keep anything that's already page sized+aligned if (p->is_page_aligned() && p->is_n_page_sized()) { /*cout << " segment " << (void*)p->c_str() << " offset " << ((unsigned long)p->c_str() & ~CEPH_PAGE_MASK) << " length " << p->length() << " " << (p->length() & ~CEPH_PAGE_MASK) << " ok" << std::endl; */ ++p; continue; } // consolidate unaligned items, until we get something that is sized+aligned list unaligned; unsigned offset = 0; do { /*cout << " segment " << (void*)p->c_str() << " offset " << ((unsigned long)p->c_str() & ~CEPH_PAGE_MASK) << " length " << p->length() << " " << (p->length() & ~CEPH_PAGE_MASK) << " overall offset " << offset << " " << (offset & ~CEPH_PAGE_MASK) << " not ok" << std::endl; */ offset += p->length(); unaligned.push_back(*p); _buffers.erase(p++); } while (p != _buffers.end() && (!p->is_page_aligned() || !p->is_n_page_sized() || (offset & ~CEPH_PAGE_MASK))); ptr nb(buffer::create_page_aligned(unaligned._len)); unaligned.rebuild(nb); _buffers.insert(p, unaligned._buffers.front()); } } // sort-of-like-assignment-op void buffer::list::claim(list& bl) { // free my buffers clear(); claim_append(bl); } void buffer::list::claim_append(list& bl) { // steal the other guy's buffers _len += bl._len; _buffers.splice( _buffers.end(), bl._buffers ); bl._len = 0; bl.last_p = bl.begin(); } void buffer::list::claim_prepend(list& bl) { // steal the other guy's buffers _len += bl._len; _buffers.splice( _buffers.begin(), bl._buffers ); bl._len = 0; bl.last_p = bl.begin(); } void buffer::list::copy(unsigned off, unsigned len, char *dest) const { if (off + len > length()) throw end_of_buffer(); if (last_p.get_off() != off) last_p.seek(off); last_p.copy(len, dest); } void buffer::list::copy(unsigned off, unsigned len, list &dest) const { if (off + len > length()) throw end_of_buffer(); if (last_p.get_off() != off) last_p.seek(off); last_p.copy(len, dest); } void buffer::list::copy(unsigned off, unsigned len, std::string& dest) const { if (last_p.get_off() != off) last_p.seek(off); return last_p.copy(len, dest); } void buffer::list::copy_in(unsigned off, unsigned len, const char *src) { if (off + len > length()) throw end_of_buffer(); if (last_p.get_off() != off) last_p.seek(off); last_p.copy_in(len, src); } void buffer::list::copy_in(unsigned off, unsigned len, const list& src) { if (last_p.get_off() != off) last_p.seek(off); last_p.copy_in(len, src); } void buffer::list::append(char c) { // put what we can into the existing append_buffer. unsigned gap = append_buffer.unused_tail_length(); if (!gap) { // make a new append_buffer! unsigned alen = CEPH_PAGE_SIZE; append_buffer = create_page_aligned(alen); append_buffer.set_length(0); // unused, so far. } append_buffer.append(c); append(append_buffer, append_buffer.end() - 1, 1); // add segment to the list } void buffer::list::append(const char *data, unsigned len) { while (len > 0) { // put what we can into the existing append_buffer. unsigned gap = append_buffer.unused_tail_length(); if (gap > 0) { if (gap > len) gap = len; //cout << "append first char is " << data[0] << ", last char is " << data[len-1] << std::endl; append_buffer.append(data, gap); append(append_buffer, append_buffer.end() - gap, gap); // add segment to the list len -= gap; data += gap; } if (len == 0) break; // done! // make a new append_buffer! unsigned alen = CEPH_PAGE_SIZE * (((len-1) / CEPH_PAGE_SIZE) + 1); append_buffer = create_page_aligned(alen); append_buffer.set_length(0); // unused, so far. } } void buffer::list::append(const ptr& bp) { if (bp.length()) push_back(bp); } void buffer::list::append(const ptr& bp, unsigned off, unsigned len) { assert(len+off <= bp.length()); if (!_buffers.empty()) { ptr &l = _buffers.back(); if (l.get_raw() == bp.get_raw() && l.end() == bp.start() + off) { // yay contiguous with tail bp! l.set_length(l.length()+len); _len += len; return; } } // add new item to list ptr tempbp(bp, off, len); push_back(tempbp); } void buffer::list::append(const list& bl) { _len += bl._len; for (std::list::const_iterator p = bl._buffers.begin(); p != bl._buffers.end(); ++p) _buffers.push_back(*p); } void buffer::list::append(std::istream& in) { while (!in.eof()) { std::string s; getline(in, s); append(s.c_str(), s.length()); if (s.length()) append("\n", 1); } } void buffer::list::append_zero(unsigned len) { ptr bp(len); bp.zero(); append(bp); } /* * get a char */ const char& buffer::list::operator[](unsigned n) const { if (n >= _len) throw end_of_buffer(); for (std::list::const_iterator p = _buffers.begin(); p != _buffers.end(); ++p) { if (n >= p->length()) { n -= p->length(); continue; } return (*p)[n]; } assert(0); } /* * return a contiguous ptr to whole bufferlist contents. */ char *buffer::list::c_str() { if (_buffers.empty()) return 0; // no buffers std::list::const_iterator iter = _buffers.begin(); ++iter; if (iter != _buffers.end()) rebuild(); return _buffers.front().c_str(); // good, we're already contiguous. } void buffer::list::substr_of(const list& other, unsigned off, unsigned len) { if (off + len > other.length()) throw end_of_buffer(); clear(); // skip off std::list::const_iterator curbuf = other._buffers.begin(); while (off > 0 && off >= curbuf->length()) { // skip this buffer //cout << "skipping over " << *curbuf << std::endl; off -= (*curbuf).length(); ++curbuf; } assert(len == 0 || curbuf != other._buffers.end()); while (len > 0) { // partial? if (off + len < curbuf->length()) { //cout << "copying partial of " << *curbuf << std::endl; _buffers.push_back( ptr( *curbuf, off, len ) ); _len += len; break; } // through end //cout << "copying end (all?) of " << *curbuf << std::endl; unsigned howmuch = curbuf->length() - off; _buffers.push_back( ptr( *curbuf, off, howmuch ) ); _len += howmuch; len -= howmuch; off = 0; ++curbuf; } } // funky modifer void buffer::list::splice(unsigned off, unsigned len, list *claim_by /*, bufferlist& replace_with */) { // fixme? if (len == 0) return; if (off >= length()) throw end_of_buffer(); assert(len > 0); //cout << "splice off " << off << " len " << len << " ... mylen = " << length() << std::endl; // skip off std::list::iterator curbuf = _buffers.begin(); while (off > 0) { assert(curbuf != _buffers.end()); if (off >= (*curbuf).length()) { // skip this buffer //cout << "off = " << off << " skipping over " << *curbuf << std::endl; off -= (*curbuf).length(); ++curbuf; } else { // somewhere in this buffer! //cout << "off = " << off << " somewhere in " << *curbuf << std::endl; break; } } if (off) { // add a reference to the front bit // insert it before curbuf (which we'll hose) //cout << "keeping front " << off << " of " << *curbuf << std::endl; _buffers.insert( curbuf, ptr( *curbuf, 0, off ) ); _len += off; } while (len > 0) { // partial? if (off + len < (*curbuf).length()) { //cout << "keeping end of " << *curbuf << ", losing first " << off+len << std::endl; if (claim_by) claim_by->append( *curbuf, off, len ); (*curbuf).set_offset( off+len + (*curbuf).offset() ); // ignore beginning big (*curbuf).set_length( (*curbuf).length() - (len+off) ); _len -= off+len; //cout << " now " << *curbuf << std::endl; break; } // hose though the end unsigned howmuch = (*curbuf).length() - off; //cout << "discarding " << howmuch << " of " << *curbuf << std::endl; if (claim_by) claim_by->append( *curbuf, off, howmuch ); _len -= (*curbuf).length(); _buffers.erase( curbuf++ ); len -= howmuch; off = 0; } // splice in *replace (implement me later?) last_p = begin(); // just in case we were in the removed region. }; void buffer::list::write(int off, int len, std::ostream& out) const { list s; s.substr_of(*this, off, len); for (std::list::const_iterator it = s._buffers.begin(); it != s._buffers.end(); ++it) if (it->length()) out.write(it->c_str(), it->length()); /*iterator p(this, off); while (len > 0 && !p.end()) { int l = p.left_in_this_buf(); if (l > len) l = len; out.write(p.c_str(), l); len -= l; }*/ } void buffer::list::encode_base64(buffer::list& o) { bufferptr bp(length() * 4 / 3 + 3); int l = ceph_armor(bp.c_str(), bp.c_str() + bp.length(), c_str(), c_str() + length()); bp.set_length(l); o.push_back(bp); } void buffer::list::decode_base64(buffer::list& e) { bufferptr bp(4 + ((e.length() * 3) / 4)); int l = ceph_unarmor(bp.c_str(), bp.c_str() + bp.length(), e.c_str(), e.c_str() + e.length()); if (l < 0) { std::ostringstream oss; oss << "decode_base64: decoding failed:\n"; hexdump(oss); throw buffer::malformed_input(oss.str().c_str()); } assert(l <= (int)bp.length()); bp.set_length(l); push_back(bp); } int buffer::list::read_file(const char *fn, std::string *error) { int fd = TEMP_FAILURE_RETRY(::open(fn, O_RDONLY)); if (fd < 0) { int err = errno; std::ostringstream oss; oss << "can't open " << fn << ": " << cpp_strerror(err); *error = oss.str(); return -err; } struct stat st; memset(&st, 0, sizeof(st)); ::fstat(fd, &st); ssize_t ret = read_fd(fd, st.st_size); if (ret < 0) { std::ostringstream oss; oss << "bufferlist::read_file(" << fn << "): read error:" << cpp_strerror(ret); *error = oss.str(); VOID_TEMP_FAILURE_RETRY(::close(fd)); return ret; } else if (ret != st.st_size) { // Premature EOF. // Perhaps the file changed between stat() and read()? std::ostringstream oss; oss << "bufferlist::read_file(" << fn << "): warning: got premature EOF."; *error = oss.str(); // not actually an error, but weird } VOID_TEMP_FAILURE_RETRY(::close(fd)); return 0; } ssize_t buffer::list::read_fd(int fd, size_t len) { // try zero copy first if (false && read_fd_zero_copy(fd, len) == 0) { // TODO fix callers to not require correct read size, which is not // available for raw_pipe until we actually inspect the data return 0; } int s = ROUND_UP_TO(len, CEPH_PAGE_SIZE); bufferptr bp = buffer::create_page_aligned(s); ssize_t ret = safe_read(fd, (void*)bp.c_str(), len); if (ret >= 0) { bp.set_length(ret); append(bp); } return ret; } int buffer::list::read_fd_zero_copy(int fd, size_t len) { #ifdef CEPH_HAVE_SPLICE try { bufferptr bp = buffer::create_zero_copy(len, fd, NULL); append(bp); } catch (buffer::error_code e) { return e.code; } catch (buffer::malformed_input) { return -EIO; } return 0; #else return -ENOTSUP; #endif } int buffer::list::write_file(const char *fn, int mode) { int fd = TEMP_FAILURE_RETRY(::open(fn, O_WRONLY|O_CREAT|O_TRUNC, mode)); if (fd < 0) { int err = errno; cerr << "bufferlist::write_file(" << fn << "): failed to open file: " << cpp_strerror(err) << std::endl; return -err; } int ret = write_fd(fd); if (ret) { cerr << "bufferlist::write_fd(" << fn << "): write_fd error: " << cpp_strerror(ret) << std::endl; VOID_TEMP_FAILURE_RETRY(::close(fd)); return ret; } if (TEMP_FAILURE_RETRY(::close(fd))) { int err = errno; cerr << "bufferlist::write_file(" << fn << "): close error: " << cpp_strerror(err) << std::endl; return -err; } return 0; } int buffer::list::write_fd(int fd) const { if (can_zero_copy()) return write_fd_zero_copy(fd); // use writev! iovec iov[IOV_MAX]; int iovlen = 0; ssize_t bytes = 0; std::list::const_iterator p = _buffers.begin(); while (p != _buffers.end()) { if (p->length() > 0) { iov[iovlen].iov_base = (void *)p->c_str(); iov[iovlen].iov_len = p->length(); bytes += p->length(); iovlen++; } ++p; if (iovlen == IOV_MAX-1 || p == _buffers.end()) { iovec *start = iov; int num = iovlen; ssize_t wrote; retry: wrote = ::writev(fd, start, num); if (wrote < 0) { int err = errno; if (err == EINTR) goto retry; return -err; } if (wrote < bytes) { // partial write, recover! while ((size_t)wrote >= start[0].iov_len) { wrote -= start[0].iov_len; bytes -= start[0].iov_len; start++; num--; } if (wrote > 0) { start[0].iov_len -= wrote; start[0].iov_base = (char *)start[0].iov_base + wrote; bytes -= wrote; } goto retry; } iovlen = 0; bytes = 0; } } return 0; } int buffer::list::write_fd_zero_copy(int fd) const { if (!can_zero_copy()) return -ENOTSUP; /* pass offset to each call to avoid races updating the fd seek * position, since the I/O may be non-blocking */ int64_t offset = ::lseek(fd, 0, SEEK_CUR); int64_t *off_p = &offset; if (offset < 0 && offset != ESPIPE) return (int) offset; if (offset == ESPIPE) off_p = NULL; for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); ++it) { int r = it->zero_copy_to_fd(fd, off_p); if (r < 0) return r; if (off_p) offset += it->length(); } return 0; } __u32 buffer::list::crc32c(__u32 crc) const { for (std::list::const_iterator it = _buffers.begin(); it != _buffers.end(); ++it) { if (it->length()) { raw *r = it->get_raw(); pair ofs(it->offset(), it->offset() + it->length()); pair ccrc; if (r->get_crc(ofs, &ccrc)) { if (ccrc.first == crc) { // got it already crc = ccrc.second; if (buffer_track_crc) buffer_cached_crc.inc(); } else { /* If we have cached crc32c(buf, v) for initial value v, * we can convert this to a different initial value v' by: * crc32c(buf, v') = crc32c(buf, v) ^ adjustment * where adjustment = crc32c(0*len(buf), v ^ v') * * http://crcutil.googlecode.com/files/crc-doc.1.0.pdf * note, u for our crc32c implementation is 0 */ crc = ccrc.second ^ ceph_crc32c(ccrc.first ^ crc, NULL, it->length()); if (buffer_track_crc) buffer_cached_crc_adjusted.inc(); } } else { uint32_t base = crc; crc = ceph_crc32c(crc, (unsigned char*)it->c_str(), it->length()); r->set_crc(ofs, make_pair(base, crc)); } } } return crc; } void buffer::list::hexdump(std::ostream &out) const { std::ios_base::fmtflags original_flags = out.flags(); out.setf(std::ios::right); out.fill('0'); unsigned per = 16; for (unsigned o=0; o #include void hex2str(const char *s, int len, char *buf, int dest_len) { int pos = 0; for (int i=0; i #include #include std::string cpp_strerror(int err) { char buf[128]; char *errmsg; if (err < 0) err = -err; std::ostringstream oss; buf[0] = '\0'; // strerror_r returns char * on Linux, and does not always fill buf #ifdef STRERROR_R_CHAR_P errmsg = strerror_r(err, buf, sizeof(buf)); #else strerror_r(err, buf, sizeof(buf)); errmsg = buf; #endif oss << "(" << err << ") " << errmsg; return oss.str(); } ceph-0.80.11/src/common/Formatter.h0000664000175100017510000001160312623076744021071 0ustar jenkins-buildjenkins-build#ifndef CEPH_FORMATTER_H #define CEPH_FORMATTER_H #include "include/int_types.h" #include #include #include #include #include #include #include #include "include/buffer.h" namespace ceph { struct FormatterAttrs { std::list< std::pair > attrs; FormatterAttrs(const char *attr, ...); }; class Formatter { public: Formatter(); virtual ~Formatter(); virtual void flush(std::ostream& os) = 0; void flush(bufferlist &bl) { std::stringstream os; flush(os); bl.append(os.str()); } virtual void reset() = 0; virtual void open_array_section(const char *name) = 0; virtual void open_array_section_in_ns(const char *name, const char *ns) = 0; virtual void open_object_section(const char *name) = 0; virtual void open_object_section_in_ns(const char *name, const char *ns) = 0; virtual void close_section() = 0; virtual void dump_unsigned(const char *name, uint64_t u) = 0; virtual void dump_int(const char *name, int64_t s) = 0; virtual void dump_float(const char *name, double d) = 0; virtual void dump_string(const char *name, std::string s) = 0; virtual void dump_bool(const char *name, bool b) { dump_format_unquoted(name, "%s", (b ? "true" : "false")); } virtual std::ostream& dump_stream(const char *name) = 0; virtual void dump_format(const char *name, const char *fmt, ...) = 0; virtual void dump_format_unquoted(const char *name, const char *fmt, ...) = 0; virtual int get_len() const = 0; virtual void write_raw_data(const char *data) = 0; /* with attrs */ virtual void open_array_section_with_attrs(const char *name, const FormatterAttrs& attrs) { open_array_section(name); } virtual void open_object_section_with_attrs(const char *name, const FormatterAttrs& attrs) { open_object_section(name); } virtual void dump_string_with_attrs(const char *name, std::string s, const FormatterAttrs& attrs) { dump_string(name, s); } }; Formatter *new_formatter(const std::string &type); class JSONFormatter : public Formatter { public: JSONFormatter(bool p=false); void flush(std::ostream& os); void reset(); virtual void open_array_section(const char *name); void open_array_section_in_ns(const char *name, const char *ns); void open_object_section(const char *name); void open_object_section_in_ns(const char *name, const char *ns); void close_section(); void dump_unsigned(const char *name, uint64_t u); void dump_int(const char *name, int64_t u); void dump_float(const char *name, double d); void dump_string(const char *name, std::string s); std::ostream& dump_stream(const char *name); void dump_format(const char *name, const char *fmt, ...); void dump_format_unquoted(const char *name, const char *fmt, ...); int get_len() const; void write_raw_data(const char *data); private: struct json_formatter_stack_entry_d { int size; bool is_array; json_formatter_stack_entry_d() : size(0), is_array(false) {} }; bool m_pretty; void open_section(const char *name, bool is_array); void print_quoted_string(const char *s); void print_name(const char *name); void print_comma(json_formatter_stack_entry_d& entry); void finish_pending_string(); std::stringstream m_ss, m_pending_string; std::list m_stack; bool m_is_pending_string; }; class XMLFormatter : public Formatter { public: static const char *XML_1_DTD; XMLFormatter(bool pretty = false); void flush(std::ostream& os); void reset(); void open_array_section(const char *name); void open_array_section_in_ns(const char *name, const char *ns); void open_object_section(const char *name); void open_object_section_in_ns(const char *name, const char *ns); void close_section(); void dump_unsigned(const char *name, uint64_t u); void dump_int(const char *name, int64_t u); void dump_float(const char *name, double d); void dump_string(const char *name, std::string s); std::ostream& dump_stream(const char *name); void dump_format(const char *name, const char *fmt, ...); void dump_format_unquoted(const char *name, const char *fmt, ...); int get_len() const; void write_raw_data(const char *data); /* with attrs */ void open_array_section_with_attrs(const char *name, const FormatterAttrs& attrs); void open_object_section_with_attrs(const char *name, const FormatterAttrs& attrs); void dump_string_with_attrs(const char *name, std::string s, const FormatterAttrs& attrs); private: void open_section_in_ns(const char *name, const char *ns, const FormatterAttrs *attrs); void finish_pending_string(); void print_spaces(); static std::string escape_xml_str(const char *str); void get_attrs_str(const FormatterAttrs *attrs, std::string& attrs_str); std::stringstream m_ss, m_pending_string; std::deque m_sections; bool m_pretty; std::string m_pending_string_name; }; } #endif ceph-0.80.11/src/common/config.cc0000664000175100017510000007167612623076744020551 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "auth/Auth.h" #include "common/ConfUtils.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/config.h" #include "common/static_assert.h" #include "common/strtol.h" #include "common/version.h" #include "include/str_list.h" #include "include/types.h" #include "include/stringify.h" #include "msg/msg_types.h" #include "osd/osd_types.h" #include "common/errno.h" #include "include/assert.h" #include #include #include #include #include #include /* Don't use standard Ceph logging in this file. * We can't use logging until it's initialized, and a lot of the necessary * initialization happens here. */ #undef dout #undef ldout #undef pdout #undef derr #undef lderr #undef generic_dout #undef dendl using std::map; using std::list; using std::multimap; using std::ostringstream; using std::pair; using std::set; using std::string; const char *CEPH_CONF_FILE_DEFAULT = "/etc/ceph/$cluster.conf, ~/.ceph/$cluster.conf, $cluster.conf"; // file layouts struct ceph_file_layout g_default_file_layout = { fl_stripe_unit: init_le32(1<<22), fl_stripe_count: init_le32(1), fl_object_size: init_le32(1<<22), fl_cas_hash: init_le32(0), fl_object_stripe_unit: init_le32(0), fl_unused: init_le32(-1), fl_pg_pool : init_le32(-1), }; #define _STR(x) #x #define STRINGIFY(x) _STR(x) void *config_option::conf_ptr(md_config_t *conf) const { void *v = (void*)(((char*)conf) + md_conf_off); return v; } const void *config_option::conf_ptr(const md_config_t *conf) const { const void *v = (const void*)(((const char*)conf) + md_conf_off); return v; } struct config_option config_optionsp[] = { #define OPTION(name, type, def_val) \ { STRINGIFY(name), type, offsetof(struct md_config_t, name) }, #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" #undef OPTION #undef SUBSYS #undef DEFAULT_SUBSYS }; const int NUM_CONFIG_OPTIONS = sizeof(config_optionsp) / sizeof(config_option); bool ceph_resolve_file_search(const std::string& filename_list, std::string& result) { list ls; get_str_list(filename_list, ls); list::iterator iter; for (iter = ls.begin(); iter != ls.end(); ++iter) { int fd = ::open(iter->c_str(), O_RDONLY); if (fd < 0) continue; close(fd); result = *iter; return true; } return false; } md_config_t::md_config_t() : cluster("ceph"), #define OPTION_OPT_INT(name, def_val) name(def_val), #define OPTION_OPT_LONGLONG(name, def_val) name((1LL) * def_val), #define OPTION_OPT_STR(name, def_val) name(def_val), #define OPTION_OPT_DOUBLE(name, def_val) name(def_val), #define OPTION_OPT_FLOAT(name, def_val) name(def_val), #define OPTION_OPT_BOOL(name, def_val) name(def_val), #define OPTION_OPT_ADDR(name, def_val) name(def_val), #define OPTION_OPT_U32(name, def_val) name(def_val), #define OPTION_OPT_U64(name, def_val) name(((uint64_t)1) * def_val), #define OPTION_OPT_UUID(name, def_val) name(def_val), #define OPTION(name, type, def_val) OPTION_##type(name, def_val) #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" #undef OPTION_OPT_INT #undef OPTION_OPT_LONGLONG #undef OPTION_OPT_STR #undef OPTION_OPT_DOUBLE #undef OPTION_OPT_FLOAT #undef OPTION_OPT_BOOL #undef OPTION_OPT_ADDR #undef OPTION_OPT_U32 #undef OPTION_OPT_U64 #undef OPTION_OPT_UUID #undef OPTION #undef SUBSYS #undef DEFAULT_SUBSYS lock("md_config_t", true, false) { init_subsys(); } void md_config_t::init_subsys() { #define SUBSYS(name, log, gather) \ subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather); #define DEFAULT_SUBSYS(log, gather) \ subsys.add(ceph_subsys_, "none", log, gather); #define OPTION(a, b, c) #include "common/config_opts.h" #undef OPTION #undef SUBSYS #undef DEFAULT_SUBSYS } md_config_t::~md_config_t() { } void md_config_t::add_observer(md_config_obs_t* observer_) { Mutex::Locker l(lock); const char **keys = observer_->get_tracked_conf_keys(); for (const char ** k = keys; *k; ++k) { obs_map_t::value_type val(*k, observer_); observers.insert(val); } } void md_config_t::remove_observer(md_config_obs_t* observer_) { Mutex::Locker l(lock); bool found_obs = false; for (obs_map_t::iterator o = observers.begin(); o != observers.end(); ) { if (o->second == observer_) { observers.erase(o++); found_obs = true; } else { ++o; } } assert(found_obs); } int md_config_t::parse_config_files(const char *conf_files, std::deque *parse_errors, std::ostream *warnings, int flags) { Mutex::Locker l(lock); if (internal_safe_to_start_threads) return -ENOSYS; if (!conf_files) { const char *c = getenv("CEPH_CONF"); if (c) { conf_files = c; } else { if (flags & CINIT_FLAG_NO_DEFAULT_CONFIG_FILE) return 0; conf_files = CEPH_CONF_FILE_DEFAULT; } } std::list cfl; get_str_list(conf_files, cfl); return parse_config_files_impl(cfl, parse_errors, warnings); } int md_config_t::parse_config_files_impl(const std::list &conf_files, std::deque *parse_errors, std::ostream *warnings) { assert(lock.is_locked()); // open new conf list::const_iterator c; for (c = conf_files.begin(); c != conf_files.end(); ++c) { cf.clear(); string fn = *c; expand_meta(fn, warnings); int ret = cf.parse_file(fn.c_str(), parse_errors, warnings); if (ret == 0) break; else if (ret != -ENOENT) return ret; } if (c == conf_files.end()) return -EINVAL; std::vector my_sections; _get_my_sections(my_sections); for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) { config_option *opt = &config_optionsp[i]; std::string val; int ret = _get_val_from_conf_file(my_sections, opt->name, val, false); if (ret == 0) { set_val_impl(val.c_str(), opt); } } // subsystems? for (int o = 0; o < subsys.get_num(); o++) { std::string as_option("debug_"); as_option += subsys.get_name(o); std::string val; int ret = _get_val_from_conf_file(my_sections, as_option.c_str(), val, false); if (ret == 0) { int log, gather; int r = sscanf(val.c_str(), "%d/%d", &log, &gather); if (r >= 1) { if (r < 2) gather = log; // cout << "config subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl; subsys.set_log_level(o, log); subsys.set_gather_level(o, gather); } } } // Warn about section names that look like old-style section names std::deque < std::string > old_style_section_names; for (ConfFile::const_section_iter_t s = cf.sections_begin(); s != cf.sections_end(); ++s) { const string &str(s->first); if (((str.find("mds") == 0) || (str.find("mon") == 0) || (str.find("osd") == 0)) && (str.size() > 3) && (str[3] != '.')) { old_style_section_names.push_back(str); } } if (!old_style_section_names.empty()) { ostringstream oss; oss << "ERROR! old-style section name(s) found: "; string sep; for (std::deque < std::string >::const_iterator os = old_style_section_names.begin(); os != old_style_section_names.end(); ++os) { oss << sep << *os; sep = ", "; } oss << ". Please use the new style section names that include a period."; parse_errors->push_back(oss.str()); } return 0; } void md_config_t::parse_env() { Mutex::Locker l(lock); if (internal_safe_to_start_threads) return; if (getenv("CEPH_KEYRING")) { set_val_or_die("keyring", getenv("CEPH_KEYRING")); } } void md_config_t::show_config(std::ostream& out) { Mutex::Locker l(lock); _show_config(&out, NULL); } void md_config_t::show_config(Formatter *f) { Mutex::Locker l(lock); _show_config(NULL, f); } void md_config_t::_show_config(std::ostream *out, Formatter *f) { if (out) { *out << "name = " << name << std::endl; *out << "cluster = " << cluster << std::endl; } if (f) { f->dump_string("name", stringify(name)); f->dump_string("cluster", cluster); } for (int o = 0; o < subsys.get_num(); o++) { if (out) *out << "debug_" << subsys.get_name(o) << " = " << subsys.get_log_level(o) << "/" << subsys.get_gather_level(o) << std::endl; if (f) { ostringstream ss; std::string debug_name = "debug_"; debug_name += subsys.get_name(o); ss << subsys.get_log_level(o) << "/" << subsys.get_gather_level(o); f->dump_string(debug_name.c_str(), ss.str()); } } for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) { config_option *opt = config_optionsp + i; char *buf; _get_val(opt->name, &buf, -1); if (out) *out << opt->name << " = " << buf << std::endl; if (f) f->dump_string(opt->name, buf); free(buf); } } int md_config_t::parse_argv(std::vector& args) { Mutex::Locker l(lock); if (internal_safe_to_start_threads) { return -ENOSYS; } bool show_config = false; bool show_config_value = false; string show_config_value_arg; // In this function, don't change any parts of the configuration directly. // Instead, use set_val to set them. This will allow us to send the proper // observer notifications later. std::string val; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (strcmp(*i, "--") == 0) { /* Normally we would use ceph_argparse_double_dash. However, in this * function we *don't* want to remove the double dash, because later * argument parses will still need to see it. */ break; } else if (ceph_argparse_flag(args, i, "--show_conf", (char*)NULL)) { cerr << cf << std::endl; _exit(0); } else if (ceph_argparse_flag(args, i, "--show_config", (char*)NULL)) { show_config = true; } else if (ceph_argparse_witharg(args, i, &val, "--show_config_value", (char*)NULL)) { show_config_value = true; show_config_value_arg = val; } else if (ceph_argparse_flag(args, i, "--foreground", "-f", (char*)NULL)) { set_val_or_die("daemonize", "false"); } else if (ceph_argparse_flag(args, i, "-d", (char*)NULL)) { set_val_or_die("daemonize", "false"); set_val_or_die("log_file", ""); set_val_or_die("log_to_stderr", "true"); set_val_or_die("err_to_stderr", "true"); set_val_or_die("log_to_syslog", "false"); } // Some stuff that we wanted to give universal single-character options for // Careful: you can burn through the alphabet pretty quickly by adding // to this list. else if (ceph_argparse_witharg(args, i, &val, "--monmap", "-M", (char*)NULL)) { set_val_or_die("monmap", val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--mon_host", "-m", (char*)NULL)) { set_val_or_die("mon_host", val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--bind", (char*)NULL)) { set_val_or_die("public_addr", val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--keyfile", "-K", (char*)NULL)) { set_val_or_die("keyfile", val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--keyring", "-k", (char*)NULL)) { set_val_or_die("keyring", val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--client_mountpoint", "-r", (char*)NULL)) { set_val_or_die("client_mountpoint", val.c_str()); } else { parse_option(args, i, NULL); } } if (show_config) { expand_all_meta(); _show_config(&cout, NULL); _exit(0); } if (show_config_value) { char *buf = 0; int r = _get_val(show_config_value_arg.c_str(), &buf, -1); if (r < 0) { if (r == -ENOENT) std::cerr << "failed to get config option '" << show_config_value_arg << "': option not found" << std::endl; else std::cerr << "failed to get config option '" << show_config_value_arg << "': " << cpp_strerror(r) << std::endl; _exit(1); } string s = buf; expand_meta(s, &std::cerr); std::cout << s << std::endl; _exit(0); } return 0; } int md_config_t::parse_option(std::vector& args, std::vector::iterator& i, ostream *oss) { int ret = 0; int o; std::string val; // subsystems? for (o = 0; o < subsys.get_num(); o++) { std::string as_option("--"); as_option += "debug_"; as_option += subsys.get_name(o); if (ceph_argparse_witharg(args, i, &val, as_option.c_str(), (char*)NULL)) { int log, gather; int r = sscanf(val.c_str(), "%d/%d", &log, &gather); if (r >= 1) { if (r < 2) gather = log; // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl; subsys.set_log_level(o, log); subsys.set_gather_level(o, gather); if (oss) *oss << "debug_" << subsys.get_name(o) << "=" << log << "/" << gather << " "; } break; } } if (o < subsys.get_num()) { return ret; } for (o = 0; o < NUM_CONFIG_OPTIONS; ++o) { const config_option *opt = config_optionsp + o; std::string as_option("--"); as_option += opt->name; if (opt->type == OPT_BOOL) { int res; if (ceph_argparse_binary_flag(args, i, &res, oss, as_option.c_str(), (char*)NULL)) { if (res == 0) set_val_impl("false", opt); else if (res == 1) set_val_impl("true", opt); else ret = res; break; } else { std::string no("--no-"); no += opt->name; if (ceph_argparse_flag(args, i, no.c_str(), (char*)NULL)) { set_val_impl("false", opt); break; } } } else if (ceph_argparse_witharg(args, i, &val, as_option.c_str(), (char*)NULL)) { if (oss && ( ((opt->type == OPT_STR) || (opt->type == OPT_ADDR) || (opt->type == OPT_UUID)) && (observers.find(opt->name) == observers.end()))) { *oss << "You cannot change " << opt->name << " using injectargs.\n"; ret = -ENOSYS; break; } int res = set_val_impl(val.c_str(), opt); if (res) { if (oss) { *oss << "Parse error setting " << opt->name << " to '" << val << "' using injectargs.\n"; ret = res; break; } else { cerr << "parse error setting '" << opt->name << "' to '" << val << "'\n" << std::endl; } } break; } } if (o == NUM_CONFIG_OPTIONS) { // ignore ++i; } return ret; } int md_config_t::parse_injectargs(std::vector& args, std::ostream *oss) { assert(lock.is_locked()); int ret = 0; for (std::vector::iterator i = args.begin(); i != args.end(); ) { int r = parse_option(args, i, oss); if (r < 0) ret = r; } return ret; } void md_config_t::apply_changes(std::ostream *oss) { Mutex::Locker l(lock); _apply_changes(oss); } bool md_config_t::_internal_field(const string& s) { if (s == "internal_safe_to_start_threads") return true; return false; } void md_config_t::_apply_changes(std::ostream *oss) { /* Maps observers to the configuration options that they care about which * have changed. */ typedef std::map < md_config_obs_t*, std::set > rev_obs_map_t; expand_all_meta(); // create the reverse observer mapping, mapping observers to the set of // changed keys that they'll get. rev_obs_map_t robs; std::set empty_set; char buf[128]; char *bufptr = (char*)buf; for (changed_set_t::const_iterator c = changed.begin(); c != changed.end(); ++c) { const std::string &key(*c); if ((oss) && (!_get_val(key.c_str(), &bufptr, sizeof(buf))) && !_internal_field(key)) { (*oss) << key << " = '" << buf << "' "; } pair < obs_map_t::iterator, obs_map_t::iterator > range(observers.equal_range(key)); for (obs_map_t::iterator r = range.first; r != range.second; ++r) { rev_obs_map_t::value_type robs_val(r->second, empty_set); pair < rev_obs_map_t::iterator, bool > robs_ret(robs.insert(robs_val)); std::set &keys(robs_ret.first->second); keys.insert(key); } } // Make any pending observer callbacks for (rev_obs_map_t::const_iterator r = robs.begin(); r != robs.end(); ++r) { md_config_obs_t *obs = r->first; obs->handle_conf_change(this, r->second); } changed.clear(); } void md_config_t::call_all_observers() { Mutex::Locker l(lock); expand_all_meta(); std::map > obs; for (obs_map_t::iterator r = observers.begin(); r != observers.end(); ++r) obs[r->second].insert(r->first); for (std::map >::iterator p = obs.begin(); p != obs.end(); ++p) p->first->handle_conf_change(this, p->second); } int md_config_t::injectargs(const std::string& s, std::ostream *oss) { int ret; Mutex::Locker l(lock); char b[s.length()+1]; strcpy(b, s.c_str()); std::vector nargs; char *p = b; while (*p) { nargs.push_back(p); while (*p && *p != ' ') p++; if (!*p) break; *p++ = 0; while (*p && *p == ' ') p++; } ret = parse_injectargs(nargs, oss); if (!nargs.empty()) { *oss << " failed to parse arguments: "; std::string prefix; for (std::vector::const_iterator i = nargs.begin(); i != nargs.end(); ++i) { *oss << prefix << *i; prefix = ","; } *oss << "\n"; ret = -EINVAL; } _apply_changes(oss); return ret; } void md_config_t::set_val_or_die(const char *key, const char *val) { int ret = set_val(key, val); assert(ret == 0); } int md_config_t::set_val(const char *key, const char *val, bool meta) { Mutex::Locker l(lock); if (!key) return -EINVAL; if (!val) return -EINVAL; std::string v(val); if (meta) expand_meta(v, &std::cerr); string k(ConfFile::normalize_key_name(key)); // subsystems? if (strncmp(k.c_str(), "debug_", 6) == 0) { for (int o = 0; o < subsys.get_num(); o++) { std::string as_option = "debug_" + subsys.get_name(o); if (k == as_option) { int log, gather; int r = sscanf(v.c_str(), "%d/%d", &log, &gather); if (r >= 1) { if (r < 2) gather = log; // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl; subsys.set_log_level(o, log); subsys.set_gather_level(o, gather); return 0; } return -EINVAL; } } } for (int i = 0; i < NUM_CONFIG_OPTIONS; ++i) { config_option *opt = &config_optionsp[i]; if (strcmp(opt->name, k.c_str()) == 0) { if (internal_safe_to_start_threads) { // If threads have been started... if ((opt->type == OPT_STR) || (opt->type == OPT_ADDR) || (opt->type == OPT_UUID)) { // And this is NOT an integer valued variable.... if (observers.find(opt->name) == observers.end()) { // And there is no observer to safely change it... // You lose. return -ENOSYS; } } } return set_val_impl(v.c_str(), opt); } } // couldn't find a configuration option with key 'key' return -ENOENT; } int md_config_t::get_val(const char *key, char **buf, int len) const { Mutex::Locker l(lock); return _get_val(key, buf,len); } int md_config_t::_get_val(const char *key, char **buf, int len) const { assert(lock.is_locked()); if (!key) return -EINVAL; // In key names, leading and trailing whitespace are not significant. string k(ConfFile::normalize_key_name(key)); for (int i = 0; i < NUM_CONFIG_OPTIONS; ++i) { const config_option *opt = &config_optionsp[i]; if (strcmp(opt->name, k.c_str())) continue; ostringstream oss; switch (opt->type) { case OPT_INT: oss << *(int*)opt->conf_ptr(this); break; case OPT_LONGLONG: oss << *(long long*)opt->conf_ptr(this); break; case OPT_STR: oss << *((std::string*)opt->conf_ptr(this)); break; case OPT_FLOAT: oss << *(float*)opt->conf_ptr(this); break; case OPT_DOUBLE: oss << *(double*)opt->conf_ptr(this); break; case OPT_BOOL: { bool b = *(bool*)opt->conf_ptr(this); oss << (b ? "true" : "false"); } break; case OPT_U32: oss << *(uint32_t*)opt->conf_ptr(this); break; case OPT_U64: oss << *(uint64_t*)opt->conf_ptr(this); break; case OPT_ADDR: oss << *(entity_addr_t*)opt->conf_ptr(this); break; case OPT_UUID: oss << *(uuid_d*)opt->conf_ptr(this); break; } string str(oss.str()); int l = strlen(str.c_str()) + 1; if (len == -1) { *buf = (char*)malloc(l); if (!*buf) return -ENOMEM; strcpy(*buf, str.c_str()); return 0; } snprintf(*buf, len, "%s", str.c_str()); return (l > len) ? -ENAMETOOLONG : 0; } // subsys? for (int o = 0; o < subsys.get_num(); o++) { std::string as_option = "debug_" + subsys.get_name(o); if (k == as_option) { if (len == -1) { *buf = (char*)malloc(20); len = 20; } int l = snprintf(*buf, len, "%d/%d", subsys.get_log_level(o), subsys.get_gather_level(o)); return (l == len) ? -ENAMETOOLONG : 0; } } // couldn't find a configuration option with key 'k' return -ENOENT; } /* The order of the sections here is important. The first section in the * vector is the "highest priority" section; if we find it there, we'll stop * looking. The lowest priority section is the one we look in only if all * others had nothing. This should always be the global section. */ void md_config_t::get_my_sections(std::vector §ions) const { Mutex::Locker l(lock); _get_my_sections(sections); } void md_config_t::_get_my_sections(std::vector §ions) const { assert(lock.is_locked()); sections.push_back(name.to_str()); sections.push_back(name.get_type_name()); sections.push_back("global"); } // Return a list of all sections int md_config_t::get_all_sections(std::vector §ions) const { Mutex::Locker l(lock); for (ConfFile::const_section_iter_t s = cf.sections_begin(); s != cf.sections_end(); ++s) { sections.push_back(s->first); } return 0; } int md_config_t::get_val_from_conf_file(const std::vector §ions, const char *key, std::string &out, bool emeta) const { Mutex::Locker l(lock); return _get_val_from_conf_file(sections, key, out, emeta); } int md_config_t::_get_val_from_conf_file(const std::vector §ions, const char *key, std::string &out, bool emeta) const { assert(lock.is_locked()); std::vector ::const_iterator s = sections.begin(); std::vector ::const_iterator s_end = sections.end(); for (; s != s_end; ++s) { int ret = cf.read(s->c_str(), key, out); if (ret == 0) { if (emeta) expand_meta(out, &std::cerr); return 0; } else if (ret != -ENOENT) return ret; } return -ENOENT; } int md_config_t::set_val_impl(const char *val, const config_option *opt) { assert(lock.is_locked()); int ret = set_val_raw(val, opt); if (ret) return ret; changed.insert(opt->name); return 0; } int md_config_t::set_val_raw(const char *val, const config_option *opt) { assert(lock.is_locked()); switch (opt->type) { case OPT_INT: { std::string err; int f = strict_sistrtoll(val, &err); if (!err.empty()) return -EINVAL; *(int*)opt->conf_ptr(this) = f; return 0; } case OPT_LONGLONG: { std::string err; long long f = strict_sistrtoll(val, &err); if (!err.empty()) return -EINVAL; *(long long*)opt->conf_ptr(this) = f; return 0; } case OPT_STR: *(std::string*)opt->conf_ptr(this) = val ? val : ""; return 0; case OPT_FLOAT: *(float*)opt->conf_ptr(this) = atof(val); return 0; case OPT_DOUBLE: *(double*)opt->conf_ptr(this) = atof(val); return 0; case OPT_BOOL: if (strcasecmp(val, "false") == 0) *(bool*)opt->conf_ptr(this) = false; else if (strcasecmp(val, "true") == 0) *(bool*)opt->conf_ptr(this) = true; else { std::string err; int b = strict_strtol(val, 10, &err); if (!err.empty()) return -EINVAL; *(bool*)opt->conf_ptr(this) = !!b; } return 0; case OPT_U32: { std::string err; int f = strict_sistrtoll(val, &err); if (!err.empty()) return -EINVAL; *(uint32_t*)opt->conf_ptr(this) = f; return 0; } case OPT_U64: { std::string err; long long f = strict_sistrtoll(val, &err); if (!err.empty()) return -EINVAL; *(uint64_t*)opt->conf_ptr(this) = f; return 0; } case OPT_ADDR: { entity_addr_t *addr = (entity_addr_t*)opt->conf_ptr(this); if (!addr->parse(val)) { return -EINVAL; } return 0; } case OPT_UUID: { uuid_d *u = (uuid_d*)opt->conf_ptr(this); if (!u->parse(val)) return -EINVAL; return 0; } } return -ENOSYS; } static const char *CONF_METAVARIABLES[] = { "cluster", "type", "name", "host", "num", "id", "pid", "cctid" }; static const int NUM_CONF_METAVARIABLES = (sizeof(CONF_METAVARIABLES) / sizeof(CONF_METAVARIABLES[0])); void md_config_t::expand_all_meta() { // Expand all metavariables ostringstream oss; for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) { config_option *opt = config_optionsp + i; if (opt->type == OPT_STR) { std::string *str = (std::string *)opt->conf_ptr(this); list stack; expand_meta(*str, opt, stack, &oss); } } cerr << oss.str(); } bool md_config_t::expand_meta(std::string &origval, std::ostream *oss) const { list stack; return expand_meta(origval, NULL, stack, oss); } bool md_config_t::expand_meta(std::string &origval, config_option *opt, std::list stack, std::ostream *oss) const { assert(lock.is_locked()); // no $ means no variable expansion is necessary if (origval.find("$") == string::npos) return false; // ignore an expansion loop and create a human readable // message about it if (opt) { for (list::iterator i = stack.begin(); i != stack.end(); ++i) { if (strcmp(opt->name, (*i)->name) == 0) { *oss << "variable expansion loop at " << opt->name << "=" << origval << std::endl; *oss << "expansion stack: " << std::endl; for (list::iterator j = stack.begin(); j != stack.end(); ++j) { *oss << (*j)->name << "=" << *(string *)(*j)->conf_ptr(this) << std::endl; } return false; } } } if (opt) stack.push_front(opt); bool found_meta = false; string out; string val = origval; for (string::size_type s = 0; s < val.size(); ) { if (val[s] != '$') { out += val[s++]; continue; } // try to parse the variable name into var, either \$\{(.+)\} or // \$[a-z\_]+ const char *valid_chars = "abcdefghijklmnopqrstuvwxyz_"; string var; size_t endpos = 0; if (val[s+1] == '{') { // ...${foo_bar}... endpos = val.find_first_not_of(valid_chars, s+2); if (endpos != std::string::npos && val[endpos] == '}') { var = val.substr(s+2, endpos-s-2); endpos++; } } else { // ...$foo... endpos = val.find_first_not_of(valid_chars, s+1); if (endpos != std::string::npos) var = val.substr(s+1, endpos-s-1); else var = val.substr(s+1); } bool expanded = false; if (var.length()) { // special metavariable? for (int i = 0; i < NUM_CONF_METAVARIABLES; ++i) { if (var != CONF_METAVARIABLES[i]) continue; //cout << " meta match of " << var << " " << CONF_METAVARIABLES[i] << std::endl; if (var == "type") out += name.get_type_name(); else if (var == "cluster") out += cluster; else if (var == "name") out += name.to_cstr(); else if (var == "host") out += host; else if (var == "num") out += name.get_id().c_str(); else if (var == "id") out += name.get_id().c_str(); else if (var == "pid") out += stringify(getpid()); else if (var == "cctid") out += stringify((unsigned long long)this); else assert(0); // unreachable expanded = true; } if (!expanded) { // config option? for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) { config_option *opt = &config_optionsp[i]; if (var == opt->name) { if (opt->type == OPT_STR) { string *origval = (string *)opt->conf_ptr(this); expand_meta(*origval, opt, stack, oss); out += *origval; } else { char *vv = NULL; _get_val(opt->name, &vv, -1); out += vv; free(vv); } expanded = true; break; } } } } if (expanded) { found_meta = true; s = endpos; } else { out += val[s++]; } } // override the original value with the expanded value origval = out; return found_meta; } md_config_obs_t:: ~md_config_obs_t() { } ceph-0.80.11/src/common/OutputDataSocket.h0000664000175100017510000000274312623076744022376 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_OUTPUTDATASOCKET_H #define CEPH_COMMON_OUTPUTDATASOCKET_H #include "common/Thread.h" #include "common/Mutex.h" #include "common/Cond.h" #include #include #include #include "include/buffer.h" class CephContext; class OutputDataSocket : public Thread { public: OutputDataSocket(CephContext *cct, uint64_t _backlog); virtual ~OutputDataSocket(); bool init(const std::string &path); void append_output(bufferlist& bl); protected: virtual void init_connection(bufferlist& bl) {} void shutdown(); std::string create_shutdown_pipe(int *pipe_rd, int *pipe_wr); std::string bind_and_listen(const std::string &sock_path, int *fd); void *entry(); bool do_accept(); void handle_connection(int fd); void close_connection(int fd); int dump_data(int fd); CephContext *m_cct; uint64_t data_max_backlog; std::string m_path; int m_sock_fd; int m_shutdown_rd_fd; int m_shutdown_wr_fd; bool going_down; uint64_t data_size; std::list data; Mutex m_lock; Cond cond; bufferlist delim; }; #endif ceph-0.80.11/src/common/sctp_crc32.c0000664000175100017510000011747612623076744021105 0ustar jenkins-buildjenkins-build/*- * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) 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. * * c) Neither the name of Cisco Systems, 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. */ /* $KAME: sctp_crc32.c,v 1.12 2005/03/06 16:04:17 itojun Exp $ */ #include #if 0 __FBSDID("$FreeBSD: src/sys/netinet/sctp_crc32.c,v 1.8 2007/05/08 17:01:10 rrs Exp $"); #include #include #endif #include #include "include/byteorder.h" #ifndef SCTP_USE_ADLER32 /** * * Routine Description: * * Computes the CRC32c checksum for the specified buffer using the slicing by 8 * algorithm over 64 bit quantities. * * Arguments: * * p_running_crc - pointer to the initial or final remainder value * used in CRC computations. It should be set to * non-NULL if the mode argument is equal to CONT or END * p_buf - the packet buffer where crc computations are being performed * length - the length of p_buf in bytes * init_bytes - the number of initial bytes that need to be procesed before * aligning p_buf to multiples of 4 bytes * mode - can be any of the following: BEGIN, CONT, END, BODY, ALIGN * * Return value: * * The computed CRC32c value */ /* * Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved * * * This software program is licensed subject to the BSD License, available at * http://www.opensource.org/licenses/bsd-license.html. * * Abstract: * * Tables for software CRC generation */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o32[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 }; /* * end of the CRC lookup table crc_tableil8_o32 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o40[256] = { 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 }; /* * end of the CRC lookup table crc_tableil8_o40 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o48[256] = { 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 }; /* * end of the CRC lookup table crc_tableil8_o48 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o56[256] = { 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 }; /* * end of the CRC lookup table crc_tableil8_o56 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o64[256] = { 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 }; /* * end of the CRC lookup table crc_tableil8_o64 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o72[256] = { 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C }; /* * end of the CRC lookup table crc_tableil8_o72 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o80[256] = { 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F }; /* * end of the CRC lookup table crc_tableil8_o80 */ /* * The following CRC lookup table was generated automagically using the * following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial * Length = .......... 32 bits Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits Number of Slices = * ..................... 8 slices Slice Lengths = ........................ 8 * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = * ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o88[256] = { 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 }; /* * end of the CRC lookup table crc_tableil8_o88 */ static uint32_t sctp_crc32c_sb8_64_bit(uint32_t crc, unsigned char const *p_buf, uint32_t length, uint32_t offset) { uint32_t li; uint32_t term1, term2; uint32_t running_length; uint32_t end_bytes; uint32_t init_bytes; init_bytes = (4-offset) & 0x3; if (init_bytes > length) init_bytes = length; running_length = ((length - init_bytes) / 8) * 8; end_bytes = length - init_bytes - running_length; for (li = 0; li < init_bytes; li++) crc = sctp_crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); for (li = 0; li < running_length / 8; li++) { #ifdef CEPH_BIG_ENDIAN crc ^= *p_buf++; crc ^= (*p_buf++) << 8; crc ^= (*p_buf++) << 16; crc ^= (*p_buf++) << 24; #else crc ^= *(uint32_t *) p_buf; p_buf += 4; #endif term1 = sctp_crc_tableil8_o88[crc & 0x000000FF] ^ sctp_crc_tableil8_o80[(crc >> 8) & 0x000000FF]; term2 = crc >> 16; crc = term1 ^ sctp_crc_tableil8_o72[term2 & 0x000000FF] ^ sctp_crc_tableil8_o64[(term2 >> 8) & 0x000000FF]; #ifdef CEPH_BIG_ENDIAN crc ^= sctp_crc_tableil8_o56[*p_buf++]; crc ^= sctp_crc_tableil8_o48[*p_buf++]; crc ^= sctp_crc_tableil8_o40[*p_buf++]; crc ^= sctp_crc_tableil8_o32[*p_buf++]; #else term1 = sctp_crc_tableil8_o56[(*(uint32_t *) p_buf) & 0x000000FF] ^ sctp_crc_tableil8_o48[((*(uint32_t *) p_buf) >> 8) & 0x000000FF]; term2 = (*(uint32_t *) p_buf) >> 16; crc = crc ^ term1 ^ sctp_crc_tableil8_o40[term2 & 0x000000FF] ^ sctp_crc_tableil8_o32[(term2 >> 8) & 0x000000FF]; p_buf += 4; #endif } for (li = 0; li < end_bytes; li++) crc = sctp_crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); return crc; } static uint32_t sctp_crc32c_sb8_64_bit_zero(uint32_t crc, uint32_t length, uint32_t offset) { uint32_t li; uint32_t term1, term2; uint32_t running_length; uint32_t end_bytes; uint32_t init_bytes; init_bytes = (4-offset) & 0x3; if (init_bytes > length) init_bytes = length; running_length = ((length - init_bytes) / 8) * 8; end_bytes = length - init_bytes - running_length; for (li = 0; li < init_bytes; li++) crc = sctp_crc_tableil8_o32[crc & 0x000000FF] ^ (crc >> 8); for (li = 0; li < running_length / 8; li++) { term1 = sctp_crc_tableil8_o88[crc & 0x000000FF] ^ sctp_crc_tableil8_o80[(crc >> 8) & 0x000000FF]; term2 = crc >> 16; crc = term1 ^ sctp_crc_tableil8_o72[term2 & 0x000000FF] ^ sctp_crc_tableil8_o64[(term2 >> 8) & 0x000000FF]; #ifdef CEPH_BIG_ENDIAN crc ^= sctp_crc_tableil8_o56[0]; crc ^= sctp_crc_tableil8_o48[0]; crc ^= sctp_crc_tableil8_o40[0]; crc ^= sctp_crc_tableil8_o32[0]; #else term1 = sctp_crc_tableil8_o56[0] ^ sctp_crc_tableil8_o48[0]; term2 = 0; crc = crc ^ term1 ^ sctp_crc_tableil8_o40[term2 & 0x000000FF] ^ sctp_crc_tableil8_o32[(term2 >> 8) & 0x000000FF]; #endif } for (li = 0; li < end_bytes; li++) crc = sctp_crc_tableil8_o32[crc & 0x000000FF] ^ (crc >> 8); return crc; } /** * * Routine Description: * * warms the tables * * Arguments: * * none * * Return value: * * none */ static uint32_t update_crc32(uint32_t crc32c, unsigned char const *buffer, unsigned int length) { uint32_t offset; if (length == 0) { return (crc32c); } offset = ((uintptr_t) buffer) & 0x3; if (buffer) return (sctp_crc32c_sb8_64_bit(crc32c, buffer, length, offset)); else return (sctp_crc32c_sb8_64_bit_zero(crc32c, length, offset)); } uint32_t sctp_crc_c[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, }; #define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF]) #if 0 static uint32_t old_update_crc32(uint32_t crc32c, unsigned char const *buffer, unsigned int length) { unsigned int i; for (i = 0; i < length; i++) { SCTP_CRC32C(crc32c, buffer[i]); } return (crc32c); } static uint32_t sctp_csum_finalize(uint32_t crc32c) { uint32_t result; #if BYTE_ORDER == BIG_ENDIAN uint8_t byte0, byte1, byte2, byte3; #endif /* Complement the result */ result = ~crc32c; #if BYTE_ORDER == BIG_ENDIAN /* * For BIG-ENDIAN.. aka Motorola byte order the result is in * little-endian form. So we must manually swap the bytes. Then we * can call htonl() which does nothing... */ byte0 = result & 0x000000ff; byte1 = (result >> 8) & 0x000000ff; byte2 = (result >> 16) & 0x000000ff; byte3 = (result >> 24) & 0x000000ff; crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); #else /* * For INTEL platforms the result comes out in network order. No * htonl is required or the swap above. So we optimize out both the * htonl and the manual swap above. */ crc32c = result; #endif return (crc32c); } #endif uint32_t ceph_crc32c_sctp(uint32_t crc, unsigned char const *data, unsigned length) { return update_crc32(crc, data, length); } #endif ceph-0.80.11/src/common/WorkQueue.cc0000664000175100017510000001537412623076744021224 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "include/types.h" #include "include/utime.h" #include "common/errno.h" #include "WorkQueue.h" #include "common/config.h" #include "common/HeartbeatMap.h" #define dout_subsys ceph_subsys_tp #undef dout_prefix #define dout_prefix *_dout << name << " " ThreadPool::ThreadPool(CephContext *cct_, string nm, int n, const char *option) : cct(cct_), name(nm), lockname(nm + "::lock"), _lock(lockname.c_str()), // this should be safe due to declaration order _stop(false), _pause(0), _draining(0), ioprio_class(-1), ioprio_priority(-1), _num_threads(n), last_work_queue(0), processing(0) { if (option) { _thread_num_option = option; // set up conf_keys _conf_keys = new const char*[2]; _conf_keys[0] = _thread_num_option.c_str(); _conf_keys[1] = NULL; } else { _conf_keys = new const char*[1]; _conf_keys[0] = NULL; } } void ThreadPool::TPHandle::suspend_tp_timeout() { cct->get_heartbeat_map()->clear_timeout(hb); } void ThreadPool::TPHandle::reset_tp_timeout() { cct->get_heartbeat_map()->reset_timeout( hb, grace, suicide_grace); } ThreadPool::~ThreadPool() { assert(_threads.empty()); delete[] _conf_keys; } void ThreadPool::handle_conf_change(const struct md_config_t *conf, const std::set &changed) { if (changed.count(_thread_num_option)) { char *buf; int r = conf->get_val(_thread_num_option.c_str(), &buf, -1); assert(r >= 0); int v = atoi(buf); free(buf); if (v > 0) { _lock.Lock(); _num_threads = v; start_threads(); _cond.SignalAll(); _lock.Unlock(); } } } void ThreadPool::worker(WorkThread *wt) { _lock.Lock(); ldout(cct,10) << "worker start" << dendl; std::stringstream ss; ss << name << " thread " << (void*)pthread_self(); heartbeat_handle_d *hb = cct->get_heartbeat_map()->add_worker(ss.str()); while (!_stop) { // manage dynamic thread pool join_old_threads(); if (_threads.size() > _num_threads) { ldout(cct,1) << " worker shutting down; too many threads (" << _threads.size() << " > " << _num_threads << ")" << dendl; _threads.erase(wt); _old_threads.push_back(wt); break; } if (!_pause && !work_queues.empty()) { WorkQueue_* wq; int tries = work_queues.size(); bool did = false; while (tries--) { last_work_queue++; last_work_queue %= work_queues.size(); wq = work_queues[last_work_queue]; void *item = wq->_void_dequeue(); if (item) { processing++; ldout(cct,12) << "worker wq " << wq->name << " start processing " << item << " (" << processing << " active)" << dendl; TPHandle tp_handle(cct, hb, wq->timeout_interval, wq->suicide_interval); tp_handle.reset_tp_timeout(); _lock.Unlock(); wq->_void_process(item, tp_handle); _lock.Lock(); wq->_void_process_finish(item); processing--; ldout(cct,15) << "worker wq " << wq->name << " done processing " << item << " (" << processing << " active)" << dendl; if (_pause || _draining) _wait_cond.Signal(); did = true; break; } } if (did) continue; } ldout(cct,20) << "worker waiting" << dendl; cct->get_heartbeat_map()->reset_timeout( hb, cct->_conf->threadpool_default_timeout, 0); _cond.WaitInterval(cct, _lock, utime_t( cct->_conf->threadpool_empty_queue_max_wait, 0)); } ldout(cct,1) << "worker finish" << dendl; cct->get_heartbeat_map()->remove_worker(hb); _lock.Unlock(); } void ThreadPool::start_threads() { assert(_lock.is_locked()); while (_threads.size() < _num_threads) { WorkThread *wt = new WorkThread(this); ldout(cct, 10) << "start_threads creating and starting " << wt << dendl; _threads.insert(wt); int r = wt->set_ioprio(ioprio_class, ioprio_priority); if (r < 0) lderr(cct) << " set_ioprio got " << cpp_strerror(r) << dendl; wt->create(); } } void ThreadPool::join_old_threads() { assert(_lock.is_locked()); while (!_old_threads.empty()) { ldout(cct, 10) << "join_old_threads joining and deleting " << _old_threads.front() << dendl; _old_threads.front()->join(); delete _old_threads.front(); _old_threads.pop_front(); } } void ThreadPool::start() { ldout(cct,10) << "start" << dendl; if (_thread_num_option.length()) { ldout(cct, 10) << " registering config observer on " << _thread_num_option << dendl; cct->_conf->add_observer(this); } _lock.Lock(); start_threads(); _lock.Unlock(); ldout(cct,15) << "started" << dendl; } void ThreadPool::stop(bool clear_after) { ldout(cct,10) << "stop" << dendl; if (_thread_num_option.length()) { ldout(cct, 10) << " unregistering config observer on " << _thread_num_option << dendl; cct->_conf->remove_observer(this); } _lock.Lock(); _stop = true; _cond.Signal(); join_old_threads(); _lock.Unlock(); for (set::iterator p = _threads.begin(); p != _threads.end(); ++p) { (*p)->join(); delete *p; } _threads.clear(); _lock.Lock(); for (unsigned i=0; i_clear(); _stop = false; _lock.Unlock(); ldout(cct,15) << "stopped" << dendl; } void ThreadPool::pause() { ldout(cct,10) << "pause" << dendl; _lock.Lock(); _pause++; while (processing) _wait_cond.Wait(_lock); _lock.Unlock(); ldout(cct,15) << "paused" << dendl; } void ThreadPool::pause_new() { ldout(cct,10) << "pause_new" << dendl; _lock.Lock(); _pause++; _lock.Unlock(); } void ThreadPool::unpause() { ldout(cct,10) << "unpause" << dendl; _lock.Lock(); assert(_pause > 0); _pause--; _cond.Signal(); _lock.Unlock(); } void ThreadPool::drain(WorkQueue_* wq) { ldout(cct,10) << "drain" << dendl; _lock.Lock(); _draining++; while (processing || (wq != NULL && !wq->_empty())) _wait_cond.Wait(_lock); _draining--; _lock.Unlock(); } void ThreadPool::set_ioprio(int cls, int priority) { Mutex::Locker l(_lock); ioprio_class = cls; ioprio_priority = priority; for (set::iterator p = _threads.begin(); p != _threads.end(); ++p) { ldout(cct,10) << __func__ << " class " << cls << " priority " << priority << " pid " << (*p)->get_pid() << dendl; int r = (*p)->set_ioprio(cls, priority); if (r < 0) lderr(cct) << " set_ioprio got " << cpp_strerror(r) << dendl; } } ceph-0.80.11/src/common/fd.h0000664000175100017510000000101112623076744017507 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_FD_H #define CEPH_COMMON_FD_H class CephContext; void dump_open_fds(CephContext *cct); #endif ceph-0.80.11/src/common/config_obs.h0000664000175100017510000000157312623076744021243 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CONFIG_OBS_H #define CEPH_CONFIG_OBS_H #include #include struct md_config_t; class md_config_obs_t { public: virtual ~md_config_obs_t(); virtual const char** get_tracked_conf_keys() const = 0; virtual void handle_conf_change(const struct md_config_t *conf, const std::set &changed) = 0; virtual void handle_subsys_change(const struct md_config_t *conf, const std::set& changed) { } }; #endif ceph-0.80.11/src/common/Thread.h0000664000175100017510000000216212623076744020335 0ustar jenkins-buildjenkins-build // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_THREAD_H #define CEPH_THREAD_H #include class Thread { private: pthread_t thread_id; pid_t pid; int ioprio_class, ioprio_priority; void *entry_wrapper(); public: Thread(const Thread& other); const Thread& operator=(const Thread& other); Thread(); virtual ~Thread(); protected: virtual void *entry() = 0; private: static void *_entry_func(void *arg); public: const pthread_t &get_thread_id(); pid_t get_pid() const { return pid; } bool is_started(); bool am_self(); int kill(int signal); int try_create(size_t stacksize); void create(size_t stacksize = 0); int join(void **prval = 0); int detach(); int set_ioprio(int cls, int prio); }; #endif ceph-0.80.11/src/common/fd.cc0000664000175100017510000000262012623076744017654 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "fd.h" #include #include #include #include #include "debug.h" #include "errno.h" void dump_open_fds(CephContext *cct) { const char *fn = "/proc/self/fd"; DIR *d = opendir(fn); if (!d) { lderr(cct) << "dump_open_fds unable to open " << fn << dendl; return; } struct dirent de, *pde = 0; int n = 0; while (readdir_r(d, &de, &pde) >= 0) { if (pde == NULL) break; if (de.d_name[0] == '.') continue; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", fn, de.d_name); char target[PATH_MAX]; ssize_t r = readlink(path, target, sizeof(target)); if (r < 0) { r = -errno; lderr(cct) << "dump_open_fds unable to readlink " << path << ": " << cpp_strerror(r) << dendl; continue; } target[r] = 0; lderr(cct) << "dump_open_fds " << de.d_name << " -> " << target << dendl; n++; } lderr(cct) << "dump_open_fds dumped " << n << " open files" << dendl; closedir(d); } ceph-0.80.11/src/common/io_priority.cc0000664000175100017510000000232712623076744021637 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Red Hat * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include /* For SYS_xxx definitions */ #include #include #include "common/errno.h" #include "io_priority.h" pid_t ceph_gettid(void) { #ifdef __linux__ return syscall(SYS_gettid); #else return -ENOSYS; #endif } int ceph_ioprio_set(int whence, int who, int ioprio) { #ifdef __linux__ return syscall(SYS_ioprio_set, whence, who, ioprio); #else return -ENOSYS; #endif } int ceph_ioprio_string_to_class(const std::string& s) { std::string l = s; std::transform(l.begin(), l.end(), l.begin(), ::tolower); if (l == "idle") return IOPRIO_CLASS_IDLE; if (l == "be" || l == "besteffort" || l == "best effort") return IOPRIO_CLASS_BE; if (l == "rt" || l == "realtime" || l == "real time") return IOPRIO_CLASS_RT; return -EINVAL; } ceph-0.80.11/src/common/tracked_int_ptr.hpp0000664000175100017510000000271212623076744022643 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_TRACKEDINTPTR_H #define CEPH_TRACKEDINTPTR_H #include #include #include #include #include "common/Mutex.h" #include "common/Cond.h" template class TrackedIntPtr { T *ptr; uint64_t id; public: TrackedIntPtr() : ptr(NULL), id(0) {} TrackedIntPtr(T *ptr) : ptr(ptr), id(ptr ? get_with_id(ptr) : 0) {} ~TrackedIntPtr() { if (ptr) put_with_id(ptr, id); else assert(id == 0); } void swap(TrackedIntPtr &other) { T *optr = other.ptr; uint64_t oid = other.id; other.ptr = ptr; other.id = id; ptr = optr; id = oid; } TrackedIntPtr(const TrackedIntPtr &rhs) : ptr(rhs.ptr), id(ptr ? get_with_id(ptr) : 0) {} void operator=(const TrackedIntPtr &rhs) { TrackedIntPtr o(rhs.ptr); swap(o); } T &operator*() { return *ptr; } T *operator->() { return ptr; } bool operator<(const TrackedIntPtr &lhs) const { return ptr < lhs.ptr; } bool operator==(const TrackedIntPtr &lhs) const { return ptr == lhs.ptr; } }; #endif ceph-0.80.11/src/common/bloom_filter.hpp0000664000175100017510000004747612623076744022164 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* ******************************************************************* * * * Open Bloom Filter * * * * Author: Arash Partow - 2000 * * URL: http://www.partow.net/programming/hashfunctions/index.html * * * * Copyright notice: * * Free use of the Open Bloom Filter Library is permitted under * * the guidelines and in accordance with the most current version * * of the Boost Software License, Version 1.0 * * http://www.opensource.org/licenses/bsl1.0.html * * * ******************************************************************* */ #ifndef COMMON_BLOOM_FILTER_HPP #define COMMON_BLOOM_FILTER_HPP #include #include #include #include #include #include #include #include "include/encoding.h" #include "common/Formatter.h" static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned) static const unsigned char bit_mask[bits_per_char] = { 0x01, //00000001 0x02, //00000010 0x04, //00000100 0x08, //00001000 0x10, //00010000 0x20, //00100000 0x40, //01000000 0x80 //10000000 }; class bloom_filter { protected: typedef unsigned int bloom_type; typedef unsigned char cell_type; unsigned char* bit_table_; ///< pointer to bit map std::vector salt_; ///< vector of salts std::size_t salt_count_; ///< number of salts std::size_t table_size_; ///< bit table size in bytes std::size_t insert_count_; ///< insertion count std::size_t target_element_count_; ///< target number of unique insertions std::size_t random_seed_; ///< random seed public: bloom_filter() : bit_table_(0), salt_count_(0), table_size_(0), insert_count_(0), target_element_count_(0), random_seed_(0) {} bloom_filter(const std::size_t& predicted_inserted_element_count, const double& false_positive_probability, const std::size_t& random_seed) : bit_table_(0), insert_count_(0), target_element_count_(predicted_inserted_element_count), random_seed_((random_seed) ? random_seed : 0xA5A5A5A5) { assert(false_positive_probability > 0.0); find_optimal_parameters(predicted_inserted_element_count, false_positive_probability, &salt_count_, &table_size_); init(); } bloom_filter(const std::size_t& salt_count, std::size_t table_size, const std::size_t& random_seed, std::size_t target_element_count) : bit_table_(0), salt_count_(salt_count), table_size_(table_size), insert_count_(0), target_element_count_(target_element_count), random_seed_((random_seed) ? random_seed : 0xA5A5A5A5) { init(); } void init() { generate_unique_salt(); if (table_size_) { bit_table_ = new cell_type[table_size_]; std::fill_n(bit_table_, table_size_, 0x00); } else { bit_table_ = NULL; } } bloom_filter(const bloom_filter& filter) : bit_table_(0) { this->operator=(filter); } bloom_filter& operator = (const bloom_filter& filter) { if (this != &filter) { salt_count_ = filter.salt_count_; table_size_ = filter.table_size_; insert_count_ = filter.insert_count_; target_element_count_ = filter.target_element_count_; random_seed_ = filter.random_seed_; delete[] bit_table_; bit_table_ = new cell_type[table_size_]; std::copy(filter.bit_table_, filter.bit_table_ + table_size_, bit_table_); salt_ = filter.salt_; } return *this; } virtual ~bloom_filter() { delete[] bit_table_; } inline bool operator!() const { return (0 == table_size_); } inline void clear() { if (bit_table_) std::fill_n(bit_table_, table_size_, 0x00); insert_count_ = 0; } /** * insert a u32 into the set * * NOTE: the internal hash is weak enough that consecutive inputs do * not achieve the desired fpp. Well-mixed values should be used * here (e.g., put rjhash(x) into the filter instead of just x). * * @param val integer value to insert */ inline void insert(uint32_t val) { assert(bit_table_); std::size_t bit_index = 0; std::size_t bit = 0; for (std::size_t i = 0; i < salt_.size(); ++i) { compute_indices(hash_ap(val,salt_[i]),bit_index,bit); bit_table_[bit_index >> 3] |= bit_mask[bit]; } ++insert_count_; } inline void insert(const unsigned char* key_begin, const std::size_t& length) { assert(bit_table_); std::size_t bit_index = 0; std::size_t bit = 0; for (std::size_t i = 0; i < salt_.size(); ++i) { compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit); bit_table_[bit_index >> 3] |= bit_mask[bit]; } ++insert_count_; } template inline void insert(const T& t) { // Note: T must be a C++ POD type. insert(reinterpret_cast(&t),sizeof(T)); } inline void insert(const std::string& key) { insert(reinterpret_cast(key.c_str()),key.size()); } inline void insert(const char* data, const std::size_t& length) { insert(reinterpret_cast(data),length); } template inline void insert(const InputIterator begin, const InputIterator end) { InputIterator itr = begin; while (end != itr) { insert(*(itr++)); } } /** * check if a u32 is contained by set * * NOTE: the internal hash is weak enough that consecutive inputs do * not achieve the desired fpp. Well-mixed values should be used * here (e.g., put rjhash(x) into the filter instead of just x). * * @param val integer value to query * @returns true if value is (probably) in the set, false if it definitely is not */ inline virtual bool contains(uint32_t val) const { if (!bit_table_) return false; std::size_t bit_index = 0; std::size_t bit = 0; for (std::size_t i = 0; i < salt_.size(); ++i) { compute_indices(hash_ap(val,salt_[i]),bit_index,bit); if ((bit_table_[bit_index >> 3] & bit_mask[bit]) != bit_mask[bit]) { return false; } } return true; } inline virtual bool contains(const unsigned char* key_begin, const std::size_t length) const { if (!bit_table_) return false; std::size_t bit_index = 0; std::size_t bit = 0; for (std::size_t i = 0; i < salt_.size(); ++i) { compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit); if ((bit_table_[bit_index >> 3] & bit_mask[bit]) != bit_mask[bit]) { return false; } } return true; } template inline bool contains(const T& t) const { return contains(reinterpret_cast(&t),static_cast(sizeof(T))); } inline bool contains(const std::string& key) const { return contains(reinterpret_cast(key.c_str()),key.size()); } inline bool contains(const char* data, const std::size_t& length) const { return contains(reinterpret_cast(data),length); } template inline InputIterator contains_all(const InputIterator begin, const InputIterator end) const { InputIterator itr = begin; while (end != itr) { if (!contains(*itr)) { return itr; } ++itr; } return end; } template inline InputIterator contains_none(const InputIterator begin, const InputIterator end) const { InputIterator itr = begin; while (end != itr) { if (contains(*itr)) { return itr; } ++itr; } return end; } inline virtual std::size_t size() const { return table_size_ * bits_per_char; } inline std::size_t element_count() const { return insert_count_; } inline bool is_full() const { return insert_count_ >= target_element_count_; } /* * density of bits set. inconvenient units, but: * .3 = ~50% target insertions * .5 = 100% target insertions, "perfectly full" * .75 = 200% target insertions * 1.0 = all bits set... infinite insertions */ inline double density() const { if (!bit_table_) return 0.0; size_t set = 0; uint8_t *p = bit_table_; size_t left = table_size_; while (left-- > 0) { uint8_t c = *p; for (; c; ++set) c &= c - 1; ++p; } return (double)set / (double)(table_size_ << 3); } virtual inline double approx_unique_element_count() const { // this is not a very good estimate; a better solution should have // some asymptotic behavior as density() approaches 1.0. return (double)target_element_count_ * 2.0 * density(); } inline double effective_fpp() const { /* Note: The effective false positive probability is calculated using the designated table size and hash function count in conjunction with the current number of inserted elements - not the user defined predicated/expected number of inserted elements. */ return std::pow(1.0 - std::exp(-1.0 * salt_.size() * insert_count_ / size()), 1.0 * salt_.size()); } inline bloom_filter& operator &= (const bloom_filter& filter) { /* intersection */ if ( (salt_count_ == filter.salt_count_) && (table_size_ == filter.table_size_) && (random_seed_ == filter.random_seed_) ) { for (std::size_t i = 0; i < table_size_; ++i) { bit_table_[i] &= filter.bit_table_[i]; } } return *this; } inline bloom_filter& operator |= (const bloom_filter& filter) { /* union */ if ( (salt_count_ == filter.salt_count_) && (table_size_ == filter.table_size_) && (random_seed_ == filter.random_seed_) ) { for (std::size_t i = 0; i < table_size_; ++i) { bit_table_[i] |= filter.bit_table_[i]; } } return *this; } inline bloom_filter& operator ^= (const bloom_filter& filter) { /* difference */ if ( (salt_count_ == filter.salt_count_) && (table_size_ == filter.table_size_) && (random_seed_ == filter.random_seed_) ) { for (std::size_t i = 0; i < table_size_; ++i) { bit_table_[i] ^= filter.bit_table_[i]; } } return *this; } inline const cell_type* table() const { return bit_table_; } protected: inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const { bit_index = hash % (table_size_ << 3); bit = bit_index & 7; } void generate_unique_salt() { /* Note: A distinct hash function need not be implementation-wise distinct. In the current implementation "seeding" a common hash function with different values seems to be adequate. */ const unsigned int predef_salt_count = 128; static const bloom_type predef_salt[predef_salt_count] = { 0xAAAAAAAA, 0x55555555, 0x33333333, 0xCCCCCCCC, 0x66666666, 0x99999999, 0xB5B5B5B5, 0x4B4B4B4B, 0xAA55AA55, 0x55335533, 0x33CC33CC, 0xCC66CC66, 0x66996699, 0x99B599B5, 0xB54BB54B, 0x4BAA4BAA, 0xAA33AA33, 0x55CC55CC, 0x33663366, 0xCC99CC99, 0x66B566B5, 0x994B994B, 0xB5AAB5AA, 0xAAAAAA33, 0x555555CC, 0x33333366, 0xCCCCCC99, 0x666666B5, 0x9999994B, 0xB5B5B5AA, 0xFFFFFFFF, 0xFFFF0000, 0xB823D5EB, 0xC1191CDF, 0xF623AEB3, 0xDB58499F, 0xC8D42E70, 0xB173F616, 0xA91A5967, 0xDA427D63, 0xB1E8A2EA, 0xF6C0D155, 0x4909FEA3, 0xA68CC6A7, 0xC395E782, 0xA26057EB, 0x0CD5DA28, 0x467C5492, 0xF15E6982, 0x61C6FAD3, 0x9615E352, 0x6E9E355A, 0x689B563E, 0x0C9831A8, 0x6753C18B, 0xA622689B, 0x8CA63C47, 0x42CC2884, 0x8E89919B, 0x6EDBD7D3, 0x15B6796C, 0x1D6FDFE4, 0x63FF9092, 0xE7401432, 0xEFFE9412, 0xAEAEDF79, 0x9F245A31, 0x83C136FC, 0xC3DA4A8C, 0xA5112C8C, 0x5271F491, 0x9A948DAB, 0xCEE59A8D, 0xB5F525AB, 0x59D13217, 0x24E7C331, 0x697C2103, 0x84B0A460, 0x86156DA9, 0xAEF2AC68, 0x23243DA5, 0x3F649643, 0x5FA495A8, 0x67710DF8, 0x9A6C499E, 0xDCFB0227, 0x46A43433, 0x1832B07A, 0xC46AFF3C, 0xB9C8FFF0, 0xC9500467, 0x34431BDF, 0xB652432B, 0xE367F12B, 0x427F4C1B, 0x224C006E, 0x2E7E5A89, 0x96F99AA5, 0x0BEB452A, 0x2FD87C39, 0x74B2E1FB, 0x222EFD24, 0xF357F60C, 0x440FCB1E, 0x8BBE030F, 0x6704DC29, 0x1144D12F, 0x948B1355, 0x6D8FD7E9, 0x1C11A014, 0xADD1592F, 0xFB3C712E, 0xFC77642F, 0xF9C4CE8C, 0x31312FB9, 0x08B0DD79, 0x318FA6E7, 0xC040D23D, 0xC0589AA7, 0x0CA5C075, 0xF874B172, 0x0CF914D5, 0x784D3280, 0x4E8CFEBC, 0xC569F575, 0xCDB2A091, 0x2CC016B4, 0x5C5F4421 }; if (salt_count_ <= predef_salt_count) { std::copy(predef_salt, predef_salt + salt_count_, std::back_inserter(salt_)); for (unsigned int i = 0; i < salt_.size(); ++i) { /* Note: This is done to integrate the user defined random seed, so as to allow for the generation of unique bloom filter instances. */ salt_[i] = salt_[i] * salt_[(i + 3) % salt_.size()] + random_seed_; } } else { std::copy(predef_salt,predef_salt + predef_salt_count, std::back_inserter(salt_)); srand(static_cast(random_seed_)); while (salt_.size() < salt_count_) { bloom_type current_salt = static_cast(rand()) * static_cast(rand()); if (0 == current_salt) continue; if (salt_.end() == std::find(salt_.begin(), salt_.end(), current_salt)) { salt_.push_back(current_salt); } } } } static void find_optimal_parameters(std::size_t target_insert_count, double target_fpp, std::size_t *salt_count, std::size_t *table_size) { /* Note: The following will attempt to find the number of hash functions and minimum amount of storage bits required to construct a bloom filter consistent with the user defined false positive probability and estimated element insertion count. */ double min_m = std::numeric_limits::infinity(); double min_k = 0.0; double curr_m = 0.0; double k = 1.0; while (k < 1000.0) { double numerator = (- k * target_insert_count); double denominator = std::log(1.0 - std::pow(target_fpp, 1.0 / k)); curr_m = numerator / denominator; if (curr_m < min_m) { min_m = curr_m; min_k = k; } k += 1.0; } *salt_count = static_cast(min_k); size_t t = static_cast(min_m); t += (((t & 7) != 0) ? (bits_per_char - (t & 7)) : 0); *table_size = t >> 3; } inline bloom_type hash_ap(uint32_t val, bloom_type hash) const { hash ^= (hash << 7) ^ ((val & 0xff000000) >> 24) * (hash >> 3); hash ^= (~((hash << 11) + (((val & 0xff0000) >> 16) ^ (hash >> 5)))); hash ^= (hash << 7) ^ ((val & 0xff00) >> 8) * (hash >> 3); hash ^= (~((hash << 11) + (((val & 0xff)) ^ (hash >> 5)))); return hash; } inline bloom_type hash_ap(const unsigned char* begin, std::size_t remaining_length, bloom_type hash) const { const unsigned char* itr = begin; while (remaining_length >= 4) { hash ^= (hash << 7) ^ (*itr++) * (hash >> 3); hash ^= (~((hash << 11) + ((*itr++) ^ (hash >> 5)))); hash ^= (hash << 7) ^ (*itr++) * (hash >> 3); hash ^= (~((hash << 11) + ((*itr++) ^ (hash >> 5)))); remaining_length -= 4; } while (remaining_length >= 2) { hash ^= (hash << 7) ^ (*itr++) * (hash >> 3); hash ^= (~((hash << 11) + ((*itr++) ^ (hash >> 5)))); remaining_length -= 2; } if (remaining_length) { hash ^= (hash << 7) ^ (*itr) * (hash >> 3); } return hash; } public: void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(bloom_filter) inline bloom_filter operator & (const bloom_filter& a, const bloom_filter& b) { bloom_filter result = a; result &= b; return result; } inline bloom_filter operator | (const bloom_filter& a, const bloom_filter& b) { bloom_filter result = a; result |= b; return result; } inline bloom_filter operator ^ (const bloom_filter& a, const bloom_filter& b) { bloom_filter result = a; result ^= b; return result; } class compressible_bloom_filter : public bloom_filter { public: compressible_bloom_filter() : bloom_filter() {} compressible_bloom_filter(const std::size_t& predicted_element_count, const double& false_positive_probability, const std::size_t& random_seed) : bloom_filter(predicted_element_count, false_positive_probability, random_seed) { size_list.push_back(table_size_); } compressible_bloom_filter(const std::size_t& salt_count, std::size_t table_size, const std::size_t& random_seed, std::size_t target_count) : bloom_filter(salt_count, table_size, random_seed, target_count) { size_list.push_back(table_size_); } inline virtual std::size_t size() const { return size_list.back() * bits_per_char; } inline bool compress(const double& target_ratio) { if (!bit_table_) return false; if ((0.0 >= target_ratio) || (target_ratio >= 1.0)) { return false; } std::size_t original_table_size = size_list.back(); std::size_t new_table_size = static_cast(size_list.back() * target_ratio); if ((!new_table_size) || (new_table_size >= original_table_size)) { return false; } cell_type* tmp = new cell_type[new_table_size]; std::copy(bit_table_, bit_table_ + (new_table_size), tmp); cell_type* itr = bit_table_ + (new_table_size); cell_type* end = bit_table_ + (original_table_size); cell_type* itr_tmp = tmp; cell_type* itr_end = tmp + (new_table_size); while (end != itr) { *(itr_tmp++) |= (*itr++); if (itr_tmp == itr_end) itr_tmp = tmp; } delete[] bit_table_; bit_table_ = tmp; size_list.push_back(new_table_size); table_size_ = new_table_size; return true; } virtual inline double approx_unique_element_count() const { // this is not a very good estimate; a better solution should have // some asymptotic behavior as density() approaches 1.0. // // the compress() correction is also bad; it tends to under-estimate. return (double)target_element_count_ * 2.0 * density() * (double)size_list.back() / (double)size_list.front(); } private: inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const { bit_index = hash; for (std::size_t i = 0; i < size_list.size(); ++i) { bit_index %= size_list[i] << 3; } bit = bit_index & 7; } std::vector size_list; public: void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void dump(Formatter *f) const; static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(compressible_bloom_filter) #endif /* Note 1: If it can be guaranteed that bits_per_char will be of the form 2^n then the following optimization can be used: hash_table[bit_index >> n] |= bit_mask[bit_index & (bits_per_char - 1)]; Note 2: For performance reasons where possible when allocating memory it should be aligned (aligned_alloc) according to the architecture being used. */ ceph-0.80.11/src/common/pick_address.cc0000664000175100017510000000754412623076744021730 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/pick_address.h" #include #include #include "include/ipaddr.h" #include "include/str_list.h" #include "common/debug.h" #include "common/errno.h" #define dout_subsys ceph_subsys_ static const struct sockaddr *find_ip_in_subnet_list(CephContext *cct, const struct ifaddrs *ifa, const std::string &networks) { std::list nets; get_str_list(networks, nets); for(std::list::iterator s = nets.begin(); s != nets.end(); ++s) { struct sockaddr net; unsigned int prefix_len; if (!parse_network(s->c_str(), &net, &prefix_len)) { lderr(cct) << "unable to parse network: " << *s << dendl; exit(1); } const struct sockaddr *found = find_ip_in_subnet(ifa, &net, prefix_len); if (found) return found; } return NULL; } // observe this change struct Observer : public md_config_obs_t { const char *keys[2]; Observer(const char *c) { keys[0] = c; keys[1] = NULL; } const char** get_tracked_conf_keys() const { return (const char **)keys; } void handle_conf_change(const struct md_config_t *conf, const std::set &changed) { // do nothing. } }; static void fill_in_one_address(CephContext *cct, const struct ifaddrs *ifa, const string networks, const char *conf_var) { const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, networks); if (!found) { lderr(cct) << "unable to find any IP address in networks: " << networks << dendl; exit(1); } char buf[INET6_ADDRSTRLEN]; int err; err = getnameinfo(found, (found->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); if (err != 0) { lderr(cct) << "unable to convert chosen address to string: " << gai_strerror(err) << dendl; exit(1); } Observer obs(conf_var); cct->_conf->add_observer(&obs); cct->_conf->set_val_or_die(conf_var, buf); cct->_conf->apply_changes(NULL); cct->_conf->remove_observer(&obs); } void pick_addresses(CephContext *cct, int needs) { struct ifaddrs *ifa; int r = getifaddrs(&ifa); if (r<0) { string err = cpp_strerror(errno); lderr(cct) << "unable to fetch interfaces and addresses: " << err << dendl; exit(1); } if ((needs & CEPH_PICK_ADDRESS_PUBLIC) && cct->_conf->public_addr.is_blank_ip() && !cct->_conf->public_network.empty()) { fill_in_one_address(cct, ifa, cct->_conf->public_network, "public_addr"); } if ((needs & CEPH_PICK_ADDRESS_CLUSTER) && cct->_conf->cluster_addr.is_blank_ip() && !cct->_conf->cluster_network.empty()) { fill_in_one_address(cct, ifa, cct->_conf->cluster_network, "cluster_addr"); } freeifaddrs(ifa); } bool have_local_addr(CephContext *cct, const list& ls, entity_addr_t *match) { struct ifaddrs *ifa; int r = getifaddrs(&ifa); if (r < 0) { lderr(cct) << "unable to fetch interfaces and addresses: " << cpp_strerror(errno) << dendl; exit(1); } bool found = false; for (struct ifaddrs *addrs = ifa; addrs != NULL; addrs = addrs->ifa_next) { if (addrs->ifa_addr) { entity_addr_t a; a.set_sockaddr(addrs->ifa_addr); for (list::const_iterator p = ls.begin(); p != ls.end(); ++p) { if (a.is_same_host(*p)) { *match = *p; found = true; goto out; } } } } out: freeifaddrs(ifa); return found; } ceph-0.80.11/src/common/ceph_json.cc0000664000175100017510000002353612623076744021244 0ustar jenkins-buildjenkins-build#include #include #include #include #include "common/ceph_json.h" #include "include/utime.h" // for testing DELETE ME #include using namespace std; using namespace json_spirit; #define dout_subsys ceph_subsys_rgw JSONObjIter::JSONObjIter() { } JSONObjIter::~JSONObjIter() { } void JSONObjIter::set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_last) { cur = _cur; last = _last; } void JSONObjIter::operator++() { if (cur != last) ++cur; }; JSONObj *JSONObjIter::operator*() { return cur->second; }; // does not work, FIXME ostream& operator<<(ostream& out, JSONObj& obj) { out << obj.name << ": " << obj.data_string; return out; } JSONObj::~JSONObj() { multimap::iterator iter; for (iter = children.begin(); iter != children.end(); ++iter) { JSONObj *obj = iter->second; delete obj; } } void JSONObj::add_child(string el, JSONObj *obj) { children.insert(pair(el, obj)); } bool JSONObj::get_attr(string name, string& attr) { map::iterator iter = attr_map.find(name); if (iter == attr_map.end()) return false; attr = iter->second; return true; } JSONObjIter JSONObj::find(const string& name) { JSONObjIter iter; map::iterator first; map::iterator last; first = children.find(name); if (first != children.end()) { last = children.upper_bound(name); iter.set(first, last); } return iter; } JSONObjIter JSONObj::find_first() { JSONObjIter iter; iter.set(children.begin(), children.end()); return iter; } JSONObjIter JSONObj::find_first(const string& name) { JSONObjIter iter; map::iterator first; first = children.find(name); iter.set(first, children.end()); return iter; } JSONObj *JSONObj::find_obj(const string& name) { JSONObjIter iter = find(name); if (iter.end()) return NULL; return *iter; } bool JSONObj::get_data(const string& key, string *dest) { JSONObj *obj = find_obj(key); if (!obj) return false; *dest = obj->get_data(); return true; } /* accepts a JSON Array or JSON Object contained in * a JSON Spirit Value, v, and creates a JSONObj for each * child contained in v */ void JSONObj::handle_value(Value v) { if (v.type() == obj_type) { Object temp_obj = v.get_obj(); for (Object::size_type i = 0; i < temp_obj.size(); i++) { Pair temp_pair = temp_obj[i]; string temp_name = temp_pair.name_; Value temp_value = temp_pair.value_; JSONObj *child = new JSONObj; child->init(this, temp_value, temp_name); add_child(temp_name, child); } } else if (v.type() == array_type) { Array temp_array = v.get_array(); Value value; for (unsigned j = 0; j < temp_array.size(); j++) { Value cur = temp_array[j]; string temp_name; JSONObj *child = new JSONObj; child->init(this, cur, temp_name); add_child(child->get_name(), child); } } } void JSONObj::init(JSONObj *p, Value v, string n) { name = n; parent = p; data = v; handle_value(v); if (v.type() == str_type) data_string = v.get_str(); else data_string = write(v, raw_utf8); attr_map.insert(pair(name, data_string)); } JSONObj *JSONObj::get_parent() { return parent; } bool JSONObj::is_object() { return (data.type() == obj_type); } bool JSONObj::is_array() { return (data.type() == array_type); } vector JSONObj::get_array_elements() { vector elements; Array temp_array; if (data.type() == array_type) temp_array = data.get_array(); int array_size = temp_array.size(); if (array_size > 0) for (int i = 0; i < array_size; i++) { Value temp_value = temp_array[i]; string temp_string; temp_string = write(temp_value, raw_utf8); elements.push_back(temp_string); } return elements; } JSONParser::JSONParser() : buf_len(0), success(true) { } JSONParser::~JSONParser() { } void JSONParser::handle_data(const char *s, int len) { json_buffer.append(s, len); // check for problems with null termination FIXME buf_len += len; } // parse a supplied JSON fragment bool JSONParser::parse(const char *buf_, int len) { if (!buf_) { set_failure(); return false; } string json_string(buf_, len); success = read(json_string, data); if (success) handle_value(data); else set_failure(); return success; } // parse the internal json_buffer up to len bool JSONParser::parse(int len) { string json_string = json_buffer.substr(0, len); success = read(json_string, data); if (success) handle_value(data); else set_failure(); return success; } // parse the complete internal json_buffer bool JSONParser::parse() { success = read(json_buffer, data); if (success) handle_value(data); else set_failure(); return success; } // parse a supplied ifstream, for testing. DELETE ME bool JSONParser::parse(const char *file_name) { ifstream is(file_name); success = read(is, data); if (success) handle_value(data); else set_failure(); return success; } void decode_json_obj(long& val, JSONObj *obj) { string s = obj->get_data(); const char *start = s.c_str(); char *p; errno = 0; val = strtol(start, &p, 10); /* Check for various possible errors */ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) { throw JSONDecoder::err("failed to parse number"); } if (p == start) { throw JSONDecoder::err("failed to parse number"); } while (*p != '\0') { if (!isspace(*p)) { throw JSONDecoder::err("failed to parse number"); } p++; } } void decode_json_obj(unsigned long& val, JSONObj *obj) { string s = obj->get_data(); const char *start = s.c_str(); char *p; errno = 0; val = strtoul(start, &p, 10); /* Check for various possible errors */ if ((errno == ERANGE && val == ULONG_MAX) || (errno != 0 && val == 0)) { throw JSONDecoder::err("failed to number"); } if (p == start) { throw JSONDecoder::err("failed to parse number"); } while (*p != '\0') { if (!isspace(*p)) { throw JSONDecoder::err("failed to parse number"); } p++; } } void decode_json_obj(long long& val, JSONObj *obj) { string s = obj->get_data(); const char *start = s.c_str(); char *p; errno = 0; val = strtoll(start, &p, 10); /* Check for various possible errors */ if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) || (errno != 0 && val == 0)) { throw JSONDecoder::err("failed to parse number"); } if (p == start) { throw JSONDecoder::err("failed to parse number"); } while (*p != '\0') { if (!isspace(*p)) { throw JSONDecoder::err("failed to parse number"); } p++; } } void decode_json_obj(unsigned long long& val, JSONObj *obj) { string s = obj->get_data(); const char *start = s.c_str(); char *p; errno = 0; val = strtoull(start, &p, 10); /* Check for various possible errors */ if ((errno == ERANGE && val == ULLONG_MAX) || (errno != 0 && val == 0)) { throw JSONDecoder::err("failed to number"); } if (p == start) { throw JSONDecoder::err("failed to parse number"); } while (*p != '\0') { if (!isspace(*p)) { throw JSONDecoder::err("failed to parse number"); } p++; } } void decode_json_obj(int& val, JSONObj *obj) { long l; decode_json_obj(l, obj); #if LONG_MAX > INT_MAX if (l > INT_MAX || l < INT_MIN) { throw JSONDecoder::err("integer out of range"); } #endif val = (int)l; } void decode_json_obj(unsigned& val, JSONObj *obj) { unsigned long l; decode_json_obj(l, obj); #if ULONG_MAX > UINT_MAX if (l > UINT_MAX) { throw JSONDecoder::err("unsigned integer out of range"); } #endif val = (unsigned)l; } void decode_json_obj(bool& val, JSONObj *obj) { string s = obj->get_data(); if (strcasecmp(s.c_str(), "true") == 0) { val = true; return; } if (strcasecmp(s.c_str(), "false") == 0) { val = false; return; } int i; decode_json_obj(i, obj); val = (bool)i; } void decode_json_obj(bufferlist& val, JSONObj *obj) { string s = obj->get_data(); bufferlist bl; bl.append(s.c_str(), s.size()); try { val.decode_base64(bl); } catch (buffer::error& err) { throw JSONDecoder::err("failed to decode base64"); } } void decode_json_obj(utime_t& val, JSONObj *obj) { string s = obj->get_data(); uint64_t epoch; uint64_t nsec; int r = utime_t::parse_date(s, &epoch, &nsec); if (r == 0) { val = utime_t(epoch, nsec); } else { throw JSONDecoder::err("failed to decode utime_t"); } } void encode_json(const char *name, const string& val, Formatter *f) { f->dump_string(name, val); } void encode_json(const char *name, const char *val, Formatter *f) { f->dump_string(name, val); } void encode_json(const char *name, bool val, Formatter *f) { string s; if (val) s = "true"; else s = "false"; f->dump_string(name, s); } void encode_json(const char *name, int val, Formatter *f) { f->dump_int(name, val); } void encode_json(const char *name, long val, Formatter *f) { f->dump_int(name, val); } void encode_json(const char *name, unsigned val, Formatter *f) { f->dump_unsigned(name, val); } void encode_json(const char *name, unsigned long val, Formatter *f) { f->dump_unsigned(name, val); } void encode_json(const char *name, unsigned long long val, Formatter *f) { f->dump_unsigned(name, val); } void encode_json(const char *name, long long val, Formatter *f) { f->dump_int(name, val); } void encode_json(const char *name, const utime_t& val, Formatter *f) { val.gmtime(f->dump_stream(name)); } void encode_json(const char *name, const bufferlist& bl, Formatter *f) { /* need to copy data from bl, as it is const bufferlist */ bufferlist src = bl; bufferlist b64; src.encode_base64(b64); string s(b64.c_str(), b64.length()); encode_json(name, s, f); } ceph-0.80.11/src/common/mime.c0000664000175100017510000000433512623076744020054 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/utf8.h" #include #include #include int mime_encode_as_qp(const char *input, char *output, int outlen) { int ret = 1; char *o = output; const unsigned char *i = (const unsigned char*)input; while (1) { int c = *i; if (c == '\0') { break; } else if ((c & 0x80) || (c == '=') || (is_control_character(c))) { if (outlen >= 3) { snprintf(o, outlen, "=%02X", c); outlen -= 3; o += 3; } else outlen = 0; ret += 3; } else { if (outlen >= 1) { snprintf(o, outlen, "%c", c); outlen -= 1; o += 1; } ret += 1; } ++i; } return ret; } static inline signed int hexchar_to_int(unsigned int c) { switch(c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; case '\0': default: return -EDOM; } } int mime_decode_from_qp(const char *input, char *output, int outlen) { int ret = 1; char *o = output; const unsigned char *i = (const unsigned char*)input; while (1) { unsigned int c = *i; if (c == '\0') { break; } else if (c & 0x80) { /* The high bit is never set in quoted-printable encoding! */ return -EDOM; } else if (c == '=') { int high = hexchar_to_int(*++i); if (high < 0) return -EINVAL; int low = hexchar_to_int(*++i); if (low < 0) return -EINVAL; c = (high << 4) + low; } ++i; if (outlen >= 1) { snprintf(o, outlen, "%c", c); outlen -= 1; o += 1; } ret += 1; } return ret; } ceph-0.80.11/src/common/xattr.h0000664000175100017510000000221512623076744020267 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * Copyright (C) 2011 Stanislav Sedov * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CEPH_EXTATTR_H #define CEPH_EXTATTR_H #include #ifdef __cplusplus extern "C" { #endif int ceph_os_setxattr(const char *path, const char *name, const void *value, size_t size); int ceph_os_fsetxattr(int fd, const char *name, const void *value, size_t size); ssize_t ceph_os_getxattr(const char *path, const char *name, void *value, size_t size); ssize_t ceph_os_fgetxattr(int fd, const char *name, void *value, size_t size); ssize_t ceph_os_listxattr(const char *path, char *list, size_t size); ssize_t ceph_os_flistxattr(int fd, char *list, size_t size); int ceph_os_removexattr(const char *path, const char *name); int ceph_os_fremovexattr(int fd, const char *name); #ifdef __cplusplus } #endif #endif /* !CEPH_EXTATTR_H */ ceph-0.80.11/src/common/cmdparse.h0000664000175100017510000000366412623076744020734 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_COMMON_CMDPARSE_H #define CEPH_COMMON_CMDPARSE_H #include #include #include #include #include #include #include "common/Formatter.h" #include "common/BackTrace.h" class CephContext; /* this is handy; can't believe it's not standard */ #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) typedef boost::variant > cmd_vartype; typedef std::map cmdmap_t; void dump_cmd_to_json(ceph::Formatter *f, const std::string& cmd); void dump_cmd_and_help_to_json(ceph::Formatter *f, const std::string& secname, const std::string& cmd, const std::string& helptext); void dump_cmddesc_to_json(ceph::Formatter *jf, const std::string& secname, const std::string& cmdsig, const std::string& helptext, const std::string& module, const std::string& perm, const std::string& avail); bool cmdmap_from_json(std::vector cmd, cmdmap_t *mapp, std::stringstream &ss); void handle_bad_get(CephContext *cct, std::string k, const char *name); std::string cmd_vartype_stringify(const cmd_vartype& v); template bool cmd_getval(CephContext *cct, cmdmap_t& cmdmap, std::string k, T& val) { if (cmdmap.count(k)) { try { val = boost::get(cmdmap[k]); return true; } catch (boost::bad_get) { handle_bad_get(cct, k, typeid(T).name()); } } return false; } // with default template void cmd_getval(CephContext *cct, cmdmap_t& cmdmap, std::string k, T& val, T defval) { if (!cmd_getval(cct, cmdmap, k, val)) val = defval; } template void cmd_putval(CephContext *cct, cmdmap_t& cmdmap, std::string k, T val) { cmdmap[k] = val; } #endif ceph-0.80.11/src/common/Finisher.h0000664000175100017510000000657612623076744020712 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_FINISHER_H #define CEPH_FINISHER_H #include "include/atomic.h" #include "common/Mutex.h" #include "common/Cond.h" #include "common/Thread.h" #include "common/perf_counters.h" class CephContext; enum { l_finisher_first = 997082, l_finisher_queue_len, l_finisher_last }; class Finisher { CephContext *cct; Mutex finisher_lock; Cond finisher_cond, finisher_empty_cond; bool finisher_stop, finisher_running; vector finisher_queue; list > finisher_queue_rval; PerfCounters *logger; void *finisher_thread_entry(); struct FinisherThread : public Thread { Finisher *fin; FinisherThread(Finisher *f) : fin(f) {} void* entry() { return (void*)fin->finisher_thread_entry(); } } finisher_thread; public: void queue(Context *c, int r = 0) { finisher_lock.Lock(); if (r) { finisher_queue_rval.push_back(pair(c, r)); finisher_queue.push_back(NULL); } else finisher_queue.push_back(c); finisher_cond.Signal(); finisher_lock.Unlock(); if (logger) logger->inc(l_finisher_queue_len); } void queue(vector& ls) { finisher_lock.Lock(); finisher_queue.insert(finisher_queue.end(), ls.begin(), ls.end()); finisher_cond.Signal(); finisher_lock.Unlock(); ls.clear(); if (logger) logger->inc(l_finisher_queue_len); } void queue(deque& ls) { finisher_lock.Lock(); finisher_queue.insert(finisher_queue.end(), ls.begin(), ls.end()); finisher_cond.Signal(); finisher_lock.Unlock(); ls.clear(); if (logger) logger->inc(l_finisher_queue_len); } void queue(list& ls) { finisher_lock.Lock(); finisher_queue.insert(finisher_queue.end(), ls.begin(), ls.end()); finisher_cond.Signal(); finisher_lock.Unlock(); ls.clear(); if (logger) logger->inc(l_finisher_queue_len); } void start(); void stop(); void wait_for_empty(); Finisher(CephContext *cct_) : cct(cct_), finisher_lock("Finisher::finisher_lock"), finisher_stop(false), finisher_running(false), logger(0), finisher_thread(this) {} Finisher(CephContext *cct_, string name) : cct(cct_), finisher_lock("Finisher::finisher_lock"), finisher_stop(false), finisher_running(false), logger(0), finisher_thread(this) { PerfCountersBuilder b(cct, string("finisher-") + name, l_finisher_first, l_finisher_last); b.add_time_avg(l_finisher_queue_len, "queue_len"); logger = b.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); logger->set(l_finisher_queue_len, 0); } ~Finisher() { if (logger && cct) { cct->get_perfcounters_collection()->remove(logger); delete logger; } } }; class C_OnFinisher : public Context { Context *con; Finisher *fin; public: C_OnFinisher(Context *c, Finisher *f) : con(c), fin(f) {} void finish(int r) { fin->queue(con, r); } }; #endif ceph-0.80.11/src/common/Makefile.am0000664000175100017510000001101512623076744021006 0ustar jenkins-buildjenkins-buildlibcommon_la_SOURCES = \ ceph_ver.c \ common/DecayCounter.cc \ common/LogClient.cc \ common/LogEntry.cc \ common/PrebufferedStreambuf.cc \ common/SloppyCRCMap.cc \ common/BackTrace.cc \ common/perf_counters.cc \ common/Mutex.cc \ common/OutputDataSocket.cc \ common/admin_socket.cc \ common/admin_socket_client.cc \ common/cmdparse.cc \ common/escape.c \ common/io_priority.cc \ common/Clock.cc \ common/Throttle.cc \ common/Timer.cc \ common/Finisher.cc \ common/environment.cc\ common/assert.cc \ common/run_cmd.cc \ common/WorkQueue.cc \ common/ConfUtils.cc \ common/MemoryModel.cc \ common/armor.c \ common/fd.cc \ common/xattr.c \ common/safe_io.c \ common/snap_types.cc \ common/str_list.cc \ common/str_map.cc \ common/errno.cc \ common/RefCountedObj.cc \ common/blkdev.cc \ common/common_init.cc \ common/pipe.c \ common/ceph_argparse.cc \ common/ceph_context.cc \ common/buffer.cc \ common/code_environment.cc \ common/dout.cc \ common/histogram.cc \ common/signal.cc \ common/simple_spin.cc \ common/Thread.cc \ common/Formatter.cc \ common/HeartbeatMap.cc \ common/config.cc \ common/utf8.c \ common/mime.c \ common/strtol.cc \ common/page.cc \ common/lockdep.cc \ common/version.cc \ common/hex.cc \ common/entity_name.cc \ common/ceph_crypto.cc \ common/ceph_crypto_cms.cc \ common/ceph_json.cc \ common/ipaddr.cc \ common/pick_address.cc \ common/util.cc \ common/TextTable.cc \ common/ceph_fs.cc \ common/ceph_hash.cc \ common/ceph_strings.cc \ common/ceph_frag.cc \ common/addr_parsing.c \ common/hobject.cc \ common/bloom_filter.cc \ common/linux_version.c # these should go out of libcommon libcommon_la_SOURCES += \ mon/MonCap.cc \ mon/MonClient.cc \ mon/MonMap.cc \ osd/OSDMap.cc \ osd/osd_types.cc \ osd/ECMsgTypes.cc \ osd/HitSet.cc \ mds/MDSMap.cc \ mds/inode_backtrace.cc \ mds/mdstypes.cc \ mds/flock.cc # inject crc in common libcommon_crc_la_SOURCES = \ common/sctp_crc32.c \ common/crc32c.cc \ common/crc32c_intel_baseline.c \ common/crc32c_intel_fast.c if WITH_GOOD_YASM_ELF64 libcommon_crc_la_SOURCES += common/crc32c_intel_fast_asm.S common/crc32c_intel_fast_zero_asm.S libcommon_crc_la_LIBTOOLFLAGS = --tag=CC endif LIBCOMMON_DEPS += libcommon_crc.la noinst_LTLIBRARIES += libcommon_crc.la noinst_HEADERS += \ common/bloom_filter.hpp \ common/sctp_crc32.h \ common/crc32c_intel_baseline.h \ common/crc32c_intel_fast.h # important; libmsg before libauth! LIBCOMMON_DEPS += \ $(LIBERASURE_CODE) \ $(LIBMSG) $(LIBAUTH) \ $(LIBCRUSH) $(LIBJSON_SPIRIT) $(LIBLOG) $(LIBARCH) if LINUX LIBCOMMON_DEPS += -lrt endif # LINUX libcommon_la_LIBADD = $(LIBCOMMON_DEPS) noinst_HEADERS += \ common/BackTrace.h \ common/RefCountedObj.h \ common/HeartbeatMap.h \ common/LogClient.h \ common/LogEntry.h \ common/Preforker.h \ common/SloppyCRCMap.h \ common/WorkQueue.h \ common/PrioritizedQueue.h \ common/ceph_argparse.h \ common/ceph_context.h \ common/xattr.h \ common/blkdev.h \ common/compiler_extensions.h \ common/debug.h \ common/dout.h \ common/escape.h \ common/fd.h \ common/version.h \ common/hex.h \ common/histogram.h \ common/entity_name.h \ common/errno.h \ common/environment.h \ common/likely.h \ common/lockdep.h \ common/obj_bencher.h \ common/snap_types.h \ common/Clock.h \ common/Cond.h \ common/ConfUtils.h \ common/DecayCounter.h \ common/Finisher.h \ common/Formatter.h \ common/perf_counters.h \ common/OutputDataSocket.h \ common/admin_socket.h \ common/admin_socket_client.h \ common/random_cache.hpp \ common/shared_cache.hpp \ common/tracked_int_ptr.hpp \ common/simple_cache.hpp \ common/sharedptr_registry.hpp \ common/map_cacher.hpp \ common/MemoryModel.h \ common/Mutex.h \ common/PrebufferedStreambuf.h \ common/RWLock.h \ common/Semaphore.h \ common/SimpleRNG.h \ common/TextTable.h \ common/Thread.h \ common/Throttle.h \ common/Timer.h \ common/TrackedOp.h \ common/arch.h \ common/armor.h \ common/common_init.h \ common/io_priority.h \ common/pipe.h \ common/code_environment.h \ common/signal.h \ common/simple_spin.h \ common/run_cmd.h \ common/safe_io.h \ common/config.h \ common/config_obs.h \ common/config_opts.h \ common/ceph_crypto.h \ common/ceph_crypto_cms.h \ common/ceph_json.h \ common/lru_map.h \ common/utf8.h \ common/mime.h \ common/pick_address.h \ common/secret.h \ common/strtol.h \ common/static_assert.h \ common/AsyncReserver.h \ common/sync_filesystem.h \ common/cmdparse.h \ common/hobject.h \ common/linux_version.h noinst_LTLIBRARIES += libcommon.la ceph-0.80.11/src/common/ceph_argparse.cc0000664000175100017510000002717212623076744022077 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "auth/Auth.h" #include "common/ConfUtils.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/config.h" #include "common/strtol.h" #include "common/version.h" #include "include/intarith.h" #include "include/str_list.h" #include "msg/msg_types.h" #include #include #include #include #include #include #include /* * Ceph argument parsing library * * We probably should eventually replace this with something standard like popt. * Until we do that, though, this file is the place for argv parsing * stuff to live. */ #undef dout #undef pdout #undef derr #undef generic_dout #undef dendl void string_to_vec(std::vector& args, std::string argstr) { istringstream iss(argstr); while(iss) { string sub; iss >> sub; if (sub == "") break; args.push_back(sub); } } bool split_dashdash(const std::vector& args, std::vector& options, std::vector& arguments) { bool dashdash = false; for (std::vector::const_iterator i = args.begin(); i != args.end(); ++i) { if (dashdash) { arguments.push_back(*i); } else { if (strcmp(*i, "--") == 0) dashdash = true; else options.push_back(*i); } } return dashdash; } void env_to_vec(std::vector& args, const char *name) { if (!name) name = "CEPH_ARGS"; char *p = getenv(name); if (!p) return; bool dashdash = false; std::vector options; std::vector arguments; if (split_dashdash(args, options, arguments)) dashdash = true; std::vector env_options; std::vector env_arguments; static vector str_vec; std::vector env; str_vec.clear(); get_str_vec(p, " ", str_vec); for (vector::iterator i = str_vec.begin(); i != str_vec.end(); ++i) env.push_back(i->c_str()); if (split_dashdash(env, env_options, env_arguments)) dashdash = true; args.clear(); args.insert(args.end(), options.begin(), options.end()); args.insert(args.end(), env_options.begin(), env_options.end()); if (dashdash) args.push_back("--"); args.insert(args.end(), arguments.begin(), arguments.end()); args.insert(args.end(), env_arguments.begin(), env_arguments.end()); } void argv_to_vec(int argc, const char **argv, std::vector& args) { for (int i=1; i& args, int *argc, const char ***argv) { *argv = (const char**)malloc(sizeof(char*) * (args.size() + 1)); if (!*argv) throw bad_alloc(); *argc = 1; (*argv)[0] = argv0; for (unsigned i=0; i& vec) { const char *p = s; const char *end = p + strlen(p); while (p < end) { entity_addr_t a; //cout << " parse at '" << p << "'" << std::endl; if (!a.parse(p, &p)) { //dout(0) << " failed to parse address '" << p << "'" << dendl; return false; } //cout << " got " << a << ", rest is '" << p << "'" << std::endl; vec.push_back(a); while (*p == ',' || *p == ' ' || *p == ';') p++; } return true; } // The defaults for CephInitParameters CephInitParameters::CephInitParameters(uint32_t module_type_) : module_type(module_type_) { name.set(module_type, "admin"); } static void dashes_to_underscores(const char *input, char *output) { char c = 0; char *o = output; const char *i = input; // first two characters are copied as-is *o = *i++; if (*o++ == '\0') return; *o = *i++; if (*o++ == '\0') return; for (; ((c = *i)); ++i) { if (c == '=') { strcpy(o, i); return; } if (c == '-') *o++ = '_'; else *o++ = c; } *o++ = '\0'; } /** Once we see a standalone double dash, '--', we should remove it and stop * looking for any other options and flags. */ bool ceph_argparse_double_dash(std::vector &args, std::vector::iterator &i) { if (strcmp(*i, "--") == 0) { i = args.erase(i); return true; } return false; } bool ceph_argparse_flag(std::vector &args, std::vector::iterator &i, ...) { const char *first = *i; char tmp[strlen(first)+1]; dashes_to_underscores(first, tmp); first = tmp; va_list ap; va_start(ap, i); while (1) { const char *a = va_arg(ap, char*); if (a == NULL) { va_end(ap); return false; } char a2[strlen(a)+1]; dashes_to_underscores(a, a2); if (strcmp(a2, first) == 0) { i = args.erase(i); va_end(ap); return true; } } } static bool va_ceph_argparse_binary_flag(std::vector &args, std::vector::iterator &i, int *ret, std::ostream *oss, va_list ap) { const char *first = *i; char tmp[strlen(first)+1]; dashes_to_underscores(first, tmp); first = tmp; // does this argument match any of the possibilities? while (1) { const char *a = va_arg(ap, char*); if (a == NULL) return false; int strlen_a = strlen(a); char a2[strlen_a+1]; dashes_to_underscores(a, a2); if (strncmp(a2, first, strlen(a2)) == 0) { if (first[strlen_a] == '=') { i = args.erase(i); const char *val = first + strlen_a + 1; if ((strcmp(val, "true") == 0) || (strcmp(val, "1") == 0)) { *ret = 1; return true; } else if ((strcmp(val, "false") == 0) || (strcmp(val, "0") == 0)) { *ret = 0; return true; } if (oss) { (*oss) << "Parse error parsing binary flag " << a << ". Expected true or false, but got '" << val << "'\n"; } *ret = -EINVAL; return true; } else if (first[strlen_a] == '\0') { i = args.erase(i); *ret = 1; return true; } } } } bool ceph_argparse_binary_flag(std::vector &args, std::vector::iterator &i, int *ret, std::ostream *oss, ...) { bool r; va_list ap; va_start(ap, oss); r = va_ceph_argparse_binary_flag(args, i, ret, oss, ap); va_end(ap); return r; } static bool va_ceph_argparse_witharg(std::vector &args, std::vector::iterator &i, std::string *ret, va_list ap) { const char *first = *i; char tmp[strlen(first)+1]; dashes_to_underscores(first, tmp); first = tmp; // does this argument match any of the possibilities? while (1) { const char *a = va_arg(ap, char*); if (a == NULL) return false; int strlen_a = strlen(a); char a2[strlen_a+1]; dashes_to_underscores(a, a2); if (strncmp(a2, first, strlen(a2)) == 0) { if (first[strlen_a] == '=') { *ret = first + strlen_a + 1; i = args.erase(i); return true; } else if (first[strlen_a] == '\0') { // find second part (or not) if (i+1 == args.end()) { cerr << "Option " << *i << " requires an argument." << std::endl; _exit(1); } i = args.erase(i); *ret = *i; i = args.erase(i); return true; } } } } bool ceph_argparse_witharg(std::vector &args, std::vector::iterator &i, std::string *ret, ...) { bool r; va_list ap; va_start(ap, ret); r = va_ceph_argparse_witharg(args, i, ret, ap); va_end(ap); return r; } bool ceph_argparse_withint(std::vector &args, std::vector::iterator &i, int *ret, std::ostream *oss, ...) { bool r; va_list ap; std::string str; va_start(ap, oss); r = va_ceph_argparse_witharg(args, i, &str, ap); va_end(ap); if (!r) { return false; } std::string err; int myret = strict_strtol(str.c_str(), 10, &err); *ret = myret; if (!err.empty()) { *oss << err; } return true; } bool ceph_argparse_withlonglong(std::vector &args, std::vector::iterator &i, long long *ret, std::ostream *oss, ...) { bool r; va_list ap; std::string str; va_start(ap, oss); r = va_ceph_argparse_witharg(args, i, &str, ap); va_end(ap); if (!r) { return false; } std::string err; long long myret = strict_strtoll(str.c_str(), 10, &err); *ret = myret; if (!err.empty()) { *oss << err; } return true; } bool ceph_argparse_withfloat(std::vector &args, std::vector::iterator &i, float *ret, std::ostream *oss, ...) { bool r; va_list ap; std::string str; va_start(ap, oss); r = va_ceph_argparse_witharg(args, i, &str, ap); va_end(ap); if (!r) { return false; } std::string err; float myret = strict_strtof(str.c_str(), &err); *ret = myret; if (!err.empty()) { *oss << err; } return true; } CephInitParameters ceph_argparse_early_args (std::vector& args, uint32_t module_type, int flags, std::string *cluster, std::string *conf_file_list) { CephInitParameters iparams(module_type); std::string val; vector orig_args = args; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (strcmp(*i, "--") == 0) { /* Normally we would use ceph_argparse_double_dash. However, in this * function we *don't* want to remove the double dash, because later * argument parses will still need to see it. */ break; } else if (ceph_argparse_flag(args, i, "--version", "-v", (char*)NULL)) { cout << pretty_version_to_str() << std::endl; _exit(0); } else if (ceph_argparse_witharg(args, i, &val, "--conf", "-c", (char*)NULL)) { *conf_file_list = val; } else if (ceph_argparse_witharg(args, i, &val, "--cluster", (char*)NULL)) { *cluster = val; } else if ((module_type != CEPH_ENTITY_TYPE_CLIENT) && (ceph_argparse_witharg(args, i, &val, "-i", (char*)NULL))) { iparams.name.set_id(val); } else if (ceph_argparse_witharg(args, i, &val, "--id", "--user", (char*)NULL)) { iparams.name.set_id(val); } else if (ceph_argparse_witharg(args, i, &val, "--name", "-n", (char*)NULL)) { if (!iparams.name.from_str(val)) { cerr << "error parsing '" << val << "': expected string of the form TYPE.ID, " << "valid types are: " << EntityName::get_valid_types_as_str() << std::endl; _exit(1); } } else if (ceph_argparse_flag(args, i, "--show_args", (char*)NULL)) { cout << "args: "; for (std::vector::iterator ci = orig_args.begin(); ci != orig_args.end(); ++ci) { if (ci != orig_args.begin()) cout << " "; cout << *ci; } cout << std::endl; } else { // ignore ++i; } } return iparams; } static void generic_usage(bool is_server) { cout << "\ --conf/-c FILE read configuration from the given configuration file\n\ --id/-i ID set ID portion of my name\n\ --name/-n TYPE.ID set name\n\ --cluster NAME set cluster name (default: ceph)\n\ --version show version and quit\n\ " << std::endl; if (is_server) { cout << "\ -d run in foreground, log to stderr.\n\ -f run in foreground, log to usual location.\n"; cout << "\ --debug_ms N set message debug level (e.g. 1)\n"; } } void generic_server_usage() { generic_usage(true); exit(1); } void generic_client_usage() { generic_usage(false); exit(1); } ceph-0.80.11/src/common/Throttle.cc0000664000175100017510000001424712623076744021100 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "common/Throttle.h" #include "common/dout.h" #include "common/ceph_context.h" #include "common/perf_counters.h" #define dout_subsys ceph_subsys_throttle #undef dout_prefix #define dout_prefix *_dout << "throttle(" << name << " " << (void*)this << ") " enum { l_throttle_first = 532430, l_throttle_val, l_throttle_max, l_throttle_get, l_throttle_get_sum, l_throttle_get_or_fail_fail, l_throttle_get_or_fail_success, l_throttle_take, l_throttle_take_sum, l_throttle_put, l_throttle_put_sum, l_throttle_wait, l_throttle_last, }; Throttle::Throttle(CephContext *cct, std::string n, int64_t m, bool _use_perf) : cct(cct), name(n), logger(NULL), max(m), lock("Throttle::lock"), use_perf(_use_perf) { assert(m >= 0); if (!use_perf) return; if (cct->_conf->throttler_perf_counter) { PerfCountersBuilder b(cct, string("throttle-") + name, l_throttle_first, l_throttle_last); b.add_u64_counter(l_throttle_val, "val"); b.add_u64_counter(l_throttle_max, "max"); b.add_u64_counter(l_throttle_get, "get"); b.add_u64_counter(l_throttle_get_sum, "get_sum"); b.add_u64_counter(l_throttle_get_or_fail_fail, "get_or_fail_fail"); b.add_u64_counter(l_throttle_get_or_fail_success, "get_or_fail_success"); b.add_u64_counter(l_throttle_take, "take"); b.add_u64_counter(l_throttle_take_sum, "take_sum"); b.add_u64_counter(l_throttle_put, "put"); b.add_u64_counter(l_throttle_put_sum, "put_sum"); b.add_time_avg(l_throttle_wait, "wait"); logger = b.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); logger->set(l_throttle_max, max.read()); } } Throttle::~Throttle() { while (!cond.empty()) { Cond *cv = cond.front(); delete cv; cond.pop_front(); } if (!use_perf) return; if (logger) { cct->get_perfcounters_collection()->remove(logger); delete logger; } } void Throttle::_reset_max(int64_t m) { assert(lock.is_locked()); if (!cond.empty()) cond.front()->SignalOne(); if (logger) logger->set(l_throttle_max, m); max.set((size_t)m); } bool Throttle::_wait(int64_t c) { utime_t start; bool waited = false; if (_should_wait(c) || !cond.empty()) { // always wait behind other waiters. Cond *cv = new Cond; cond.push_back(cv); do { if (!waited) { ldout(cct, 2) << "_wait waiting..." << dendl; if (logger) start = ceph_clock_now(cct); } waited = true; cv->Wait(lock); } while (_should_wait(c) || cv != cond.front()); if (waited) { ldout(cct, 3) << "_wait finished waiting" << dendl; if (logger) { utime_t dur = ceph_clock_now(cct) - start; logger->tinc(l_throttle_wait, dur); } } delete cv; cond.pop_front(); // wake up the next guy if (!cond.empty()) cond.front()->SignalOne(); } return waited; } bool Throttle::wait(int64_t m) { if (0 == max.read()) { return false; } Mutex::Locker l(lock); if (m) { assert(m > 0); _reset_max(m); } ldout(cct, 10) << "wait" << dendl; return _wait(0); } int64_t Throttle::take(int64_t c) { if (0 == max.read()) { return 0; } assert(c >= 0); ldout(cct, 10) << "take " << c << dendl; { Mutex::Locker l(lock); count.add(c); } if (logger) { logger->inc(l_throttle_take); logger->inc(l_throttle_take_sum, c); logger->set(l_throttle_val, count.read()); } return count.read(); } bool Throttle::get(int64_t c, int64_t m) { if (0 == max.read()) { return false; } assert(c >= 0); ldout(cct, 10) << "get " << c << " (" << count.read() << " -> " << (count.read() + c) << ")" << dendl; bool waited = false; { Mutex::Locker l(lock); if (m) { assert(m > 0); _reset_max(m); } waited = _wait(c); count.add(c); } if (logger) { logger->inc(l_throttle_get); logger->inc(l_throttle_get_sum, c); logger->set(l_throttle_val, count.read()); } return waited; } /* Returns true if it successfully got the requested amount, * or false if it would block. */ bool Throttle::get_or_fail(int64_t c) { if (0 == max.read()) { return true; } assert (c >= 0); Mutex::Locker l(lock); if (_should_wait(c) || !cond.empty()) { ldout(cct, 10) << "get_or_fail " << c << " failed" << dendl; if (logger) { logger->inc(l_throttle_get_or_fail_fail); } return false; } else { ldout(cct, 10) << "get_or_fail " << c << " success (" << count.read() << " -> " << (count.read() + c) << ")" << dendl; count.add(c); if (logger) { logger->inc(l_throttle_get_or_fail_success); logger->inc(l_throttle_get); logger->inc(l_throttle_get_sum, c); logger->set(l_throttle_val, count.read()); } return true; } } int64_t Throttle::put(int64_t c) { if (0 == max.read()) { return 0; } assert(c >= 0); ldout(cct, 10) << "put " << c << " (" << count.read() << " -> " << (count.read()-c) << ")" << dendl; Mutex::Locker l(lock); if (c) { if (!cond.empty()) cond.front()->SignalOne(); assert(((int64_t)count.read()) >= c); //if count goes negative, we failed somewhere! count.sub(c); if (logger) { logger->inc(l_throttle_put); logger->inc(l_throttle_put_sum, c); logger->set(l_throttle_val, count.read()); } } return count.read(); } SimpleThrottle::SimpleThrottle(uint64_t max, bool ignore_enoent) : m_lock("SimpleThrottle"), m_max(max), m_current(0), m_ret(0), m_ignore_enoent(ignore_enoent) { } SimpleThrottle::~SimpleThrottle() { Mutex::Locker l(m_lock); assert(m_current == 0); } void SimpleThrottle::start_op() { Mutex::Locker l(m_lock); while (m_max == m_current) m_cond.Wait(m_lock); ++m_current; } void SimpleThrottle::end_op(int r) { Mutex::Locker l(m_lock); --m_current; if (r < 0 && !m_ret && !(r == -ENOENT && m_ignore_enoent)) m_ret = r; m_cond.Signal(); } bool SimpleThrottle::pending_error() const { Mutex::Locker l(m_lock); return (m_ret < 0); } int SimpleThrottle::wait_for_ret() { Mutex::Locker l(m_lock); while (m_current > 0) m_cond.Wait(m_lock); return m_ret; } ceph-0.80.11/src/common/crc32c_intel_baseline.h0000664000175100017510000000045312623076744023243 0ustar jenkins-buildjenkins-build#ifndef CEPH_COMMON_CRC32C_INTEL_BASELINE_H #define CEPH_COMMON_CRC32C_INTEL_BASELINE_H #include "include/int_types.h" #ifdef __cplusplus extern "C" { #endif extern uint32_t ceph_crc32c_intel_baseline(uint32_t crc, unsigned char const *buffer, unsigned len); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/strtol.h0000664000175100017510000000151412623076744020455 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_STRTOL_H #define CEPH_COMMON_STRTOL_H #include extern "C" { #include } long long strict_strtoll(const char *str, int base, std::string *err); int strict_strtol(const char *str, int base, std::string *err); double strict_strtod(const char *str, std::string *err); float strict_strtof(const char *str, std::string *err); uint64_t strict_sistrtoll(const char *str, std::string *err); #endif ceph-0.80.11/src/common/debug.h0000664000175100017510000000142712623076744020217 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DEBUG_H #define CEPH_DEBUG_H #include "common/dout.h" /* Global version of the stuff in common/dout.h */ #define dout(v) ldout((g_ceph_context), v) #define pdout(v, p) lpdout((g_ceph_context), v, p) #define generic_dout(v) lgeneric_dout((g_ceph_context), v) #define derr lderr((g_ceph_context)) #define generic_derr lgeneric_derr((g_ceph_context)) #endif ceph-0.80.11/src/common/str_map.cc0000664000175100017510000000332012623076744020726 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include #include "include/str_map.h" #include "include/str_list.h" #include "json_spirit/json_spirit.h" using namespace std; int get_str_map(const string &str, ostream &ss, map *str_map) { json_spirit::mValue json; try { // try json parsing first json_spirit::read_or_throw(str, json); if (json.type() != json_spirit::obj_type) { ss << str << " must be a JSON object but is of type " << json.type() << " instead"; return -EINVAL; } json_spirit::mObject o = json.get_obj(); for (map::iterator i = o.begin(); i != o.end(); ++i) { (*str_map)[i->first] = i->second.get_str(); } } catch (json_spirit::Error_position &e) { // fallback to key=value format list pairs; get_str_list(str, "\t\n ", pairs); for (list::iterator i = pairs.begin(); i != pairs.end(); ++i) { size_t equal = i->find('='); if (equal == string::npos) (*str_map)[*i] = string(); else { const string key = i->substr(0, equal); equal++; const string value = i->substr(equal); (*str_map)[key] = value; } } } return 0; } ceph-0.80.11/src/common/perf_counters.h0000664000175100017510000001255512623076744022013 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_PERF_COUNTERS_H #define CEPH_COMMON_PERF_COUNTERS_H #include "common/config_obs.h" #include "common/Mutex.h" #include "include/buffer.h" #include "include/utime.h" #include #include #include class CephContext; class PerfCountersBuilder; class PerfCountersCollectionTest; enum perfcounter_type_d { PERFCOUNTER_NONE = 0, PERFCOUNTER_TIME = 0x1, PERFCOUNTER_U64 = 0x2, PERFCOUNTER_LONGRUNAVG = 0x4, PERFCOUNTER_COUNTER = 0x8, }; /* * A PerfCounters object is usually associated with a single subsystem. * It contains counters which we modify to track performance and throughput * over time. * * PerfCounters can track several different types of values: * 1) integer values & counters * 2) floating-point values & counters * 3) floating-point averages * * The difference between values and counters is in how they are initialized * and accessed. For a counter, use the inc(counter, amount) function (note * that amount defaults to 1 if you don't set it). For a value, use the * set(index, value) function. * (For time, use the tinc and tset variants.) * * If for some reason you would like to reset your counters, you can do so using * the set functions even if they are counters, and you can also * increment your values if for some reason you wish to. * * For the time average, it returns the current value and * the "avgcount" member when read off. avgcount is incremented when you call * tinc. Calling tset on an average is an error and will assert out. */ class PerfCounters { public: template struct avg_tracker { pair last; pair cur; avg_tracker() : last(0, 0), cur(0, 0) {} T avg() const { if (cur.first == last.first) return cur.first ? cur.second / cur.first : 0; // no change, report avg over all time return (cur.second - last.second) / (cur.first - last.first); } void consume_next(const pair &next) { last = cur; cur = next; } }; ~PerfCounters(); void inc(int idx, uint64_t v = 1); void dec(int idx, uint64_t v = 1); void set(int idx, uint64_t v); uint64_t get(int idx) const; void tset(int idx, utime_t v); void tinc(int idx, utime_t v); utime_t tget(int idx) const; void dump_formatted(ceph::Formatter *f, bool schema); pair get_tavg_ms(int idx) const; const std::string& get_name() const; void set_name(std::string s) { m_name = s; } private: PerfCounters(CephContext *cct, const std::string &name, int lower_bound, int upper_bound); PerfCounters(const PerfCounters &rhs); PerfCounters& operator=(const PerfCounters &rhs); /** Represents a PerfCounters data element. */ struct perf_counter_data_any_d { perf_counter_data_any_d(); void write_schema_json(char *buf, size_t buf_sz) const; void write_json(char *buf, size_t buf_sz) const; const char *name; enum perfcounter_type_d type; uint64_t u64; uint64_t avgcount; }; typedef std::vector perf_counter_data_vec_t; CephContext *m_cct; int m_lower_bound; int m_upper_bound; std::string m_name; const std::string m_lock_name; /** Protects m_data */ mutable Mutex m_lock; perf_counter_data_vec_t m_data; friend class PerfCountersBuilder; }; class SortPerfCountersByName { public: bool operator()(const PerfCounters* lhs, const PerfCounters* rhs) const { return (lhs->get_name() < rhs->get_name()); } }; typedef std::set perf_counters_set_t; /* * PerfCountersCollection manages PerfCounters objects for a Ceph process. */ class PerfCountersCollection { public: PerfCountersCollection(CephContext *cct); ~PerfCountersCollection(); void add(class PerfCounters *l); void remove(class PerfCounters *l); void clear(); void dump_formatted(ceph::Formatter *f, bool schema); private: CephContext *m_cct; /** Protects m_loggers */ mutable Mutex m_lock; perf_counters_set_t m_loggers; friend class PerfCountersCollectionTest; }; /* Class for constructing a PerfCounters object. * * This class peforms some validation that the parameters we have supplied are * correct in create_perf_counters(). * * In the future, we will probably get rid of the first/last arguments, since * PerfCountersBuilder can deduce them itself. */ class PerfCountersBuilder { public: PerfCountersBuilder(CephContext *cct, const std::string &name, int first, int last); ~PerfCountersBuilder(); void add_u64(int key, const char *name); void add_u64_counter(int key, const char *name); void add_u64_avg(int key, const char *name); void add_time(int key, const char *name); void add_time_avg(int key, const char *name); PerfCounters* create_perf_counters(); private: PerfCountersBuilder(const PerfCountersBuilder &rhs); PerfCountersBuilder& operator=(const PerfCountersBuilder &rhs); void add_impl(int idx, const char *name, int ty); PerfCounters *m_perf_counters; }; #endif ceph-0.80.11/src/common/Thread.cc0000664000175100017510000000663712623076744020506 0ustar jenkins-buildjenkins-build // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/Thread.h" #include "common/code_environment.h" #include "common/debug.h" #include "common/signal.h" #include "common/io_priority.h" #include #include #include #include #include #include #include #include #include Thread::Thread() : thread_id(0), pid(0), ioprio_class(-1), ioprio_priority(-1) { } Thread::~Thread() { } void *Thread::_entry_func(void *arg) { void *r = ((Thread*)arg)->entry_wrapper(); return r; } void *Thread::entry_wrapper() { int p = ceph_gettid(); // may return -ENOSYS on other platforms if (p > 0) pid = p; if (pid && ioprio_class >= 0 && ioprio_priority >= 0) { ceph_ioprio_set(IOPRIO_WHO_PROCESS, pid, IOPRIO_PRIO_VALUE(ioprio_class, ioprio_priority)); } return entry(); } const pthread_t &Thread::get_thread_id() { return thread_id; } bool Thread::is_started() { return thread_id != 0; } bool Thread::am_self() { return (pthread_self() == thread_id); } int Thread::kill(int signal) { if (thread_id) return pthread_kill(thread_id, signal); else return -EINVAL; } int Thread::try_create(size_t stacksize) { pthread_attr_t *thread_attr = NULL; pthread_attr_t thread_attr_loc; stacksize &= CEPH_PAGE_MASK; // must be multiple of page if (stacksize) { thread_attr = &thread_attr_loc; pthread_attr_init(thread_attr); pthread_attr_setstacksize(thread_attr, stacksize); } int r; // The child thread will inherit our signal mask. Set our signal mask to // the set of signals we want to block. (It's ok to block signals more // signals than usual for a little while-- they will just be delivered to // another thread or delieverd to this thread later.) sigset_t old_sigset; if (g_code_env == CODE_ENVIRONMENT_LIBRARY) { block_signals(NULL, &old_sigset); } else { int to_block[] = { SIGPIPE , 0 }; block_signals(to_block, &old_sigset); } r = pthread_create(&thread_id, thread_attr, _entry_func, (void*)this); restore_sigset(&old_sigset); if (thread_attr) { pthread_attr_destroy(thread_attr); } return r; } void Thread::create(size_t stacksize) { int ret = try_create(stacksize); if (ret != 0) { char buf[256]; snprintf(buf, sizeof(buf), "Thread::try_create(): pthread_create " "failed with error %d", ret); dout_emergency(buf); assert(ret == 0); } } int Thread::join(void **prval) { if (thread_id == 0) { assert("join on thread that was never started" == 0); return -EINVAL; } int status = pthread_join(thread_id, prval); assert(status == 0); thread_id = 0; return status; } int Thread::detach() { return pthread_detach(thread_id); } int Thread::set_ioprio(int cls, int prio) { // fixme, maybe: this can race with create() ioprio_class = cls; ioprio_priority = prio; if (pid && cls >= 0 && prio >= 0) return ceph_ioprio_set(IOPRIO_WHO_PROCESS, pid, IOPRIO_PRIO_VALUE(cls, prio)); return 0; } ceph-0.80.11/src/common/ceph_context.h0000664000175100017510000000774612623076744021626 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CEPHCONTEXT_H #define CEPH_CEPHCONTEXT_H #include #include #include #include "include/buffer.h" #include "include/atomic.h" #include "common/cmdparse.h" #include "include/Spinlock.h" class AdminSocket; class CephContextServiceThread; class PerfCountersCollection; class md_config_obs_t; struct md_config_t; class CephContextHook; class CryptoNone; class CryptoAES; class CryptoHandler; namespace ceph { class HeartbeatMap; namespace log { class Log; } } using ceph::bufferlist; /* A CephContext represents the context held by a single library user. * There can be multiple CephContexts in the same process. * * For daemons and utility programs, there will be only one CephContext. The * CephContext contains the configuration, the dout object, and anything else * that you might want to pass to libcommon with every function call. */ class CephContext { public: CephContext(uint32_t module_type_); // ref count! private: ~CephContext(); atomic_t nref; public: class AssociatedSingletonObject { public: virtual ~AssociatedSingletonObject() {} }; CephContext *get() { nref.inc(); return this; } void put() { if (nref.dec() == 0) delete this; } md_config_t *_conf; ceph::log::Log *_log; /* Start the Ceph Context's service thread */ void start_service_thread(); /* Reopen the log files */ void reopen_logs(); /* Get the module type (client, mon, osd, mds, etc.) */ uint32_t get_module_type() const; /* Get the PerfCountersCollection of this CephContext */ PerfCountersCollection *get_perfcounters_collection(); ceph::HeartbeatMap *get_heartbeat_map() { return _heartbeat_map; } /** * Get the admin socket associated with this CephContext. * * Currently there is always an admin socket object, * so this will never return NULL. * * @return the admin socket */ AdminSocket *get_admin_socket(); /** * process an admin socket command */ void do_command(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist *out); template void lookup_or_create_singleton_object(T*& p, const std::string &name) { ceph_spin_lock(&_associated_objs_lock); if (!_associated_objs.count(name)) { p = new T(this); _associated_objs[name] = reinterpret_cast(p); } else { p = reinterpret_cast(_associated_objs[name]); } ceph_spin_unlock(&_associated_objs_lock); } /** * get a crypto handler */ CryptoHandler *get_crypto_handler(int type); private: CephContext(const CephContext &rhs); CephContext &operator=(const CephContext &rhs); /* Stop and join the Ceph Context's service thread */ void join_service_thread(); uint32_t _module_type; /* libcommon service thread. * SIGHUP wakes this thread, which then reopens logfiles */ friend class CephContextServiceThread; CephContextServiceThread *_service_thread; md_config_obs_t *_log_obs; /* The admin socket associated with this context */ AdminSocket *_admin_socket; /* lock which protects service thread creation, destruction, etc. */ ceph_spinlock_t _service_thread_lock; /* The collection of profiling loggers associated with this context */ PerfCountersCollection *_perf_counters_collection; md_config_obs_t *_perf_counters_conf_obs; CephContextHook *_admin_hook; ceph::HeartbeatMap *_heartbeat_map; ceph_spinlock_t _associated_objs_lock; std::map _associated_objs; // crypto CryptoNone *_crypto_none; CryptoAES *_crypto_aes; }; #endif ceph-0.80.11/src/common/ceph_context.cc0000664000175100017510000002650212623076744021753 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "common/admin_socket.h" #include "common/perf_counters.h" #include "common/Thread.h" #include "common/ceph_context.h" #include "common/config.h" #include "common/debug.h" #include "common/HeartbeatMap.h" #include "common/errno.h" #include "common/lockdep.h" #include "common/Formatter.h" #include "log/Log.h" #include "auth/Crypto.h" #include "include/str_list.h" #include "common/Mutex.h" #include "common/Cond.h" #include #include #include "include/Spinlock.h" using ceph::HeartbeatMap; class CephContextServiceThread : public Thread { public: CephContextServiceThread(CephContext *cct) : _lock("CephContextServiceThread::_lock"), _reopen_logs(false), _exit_thread(false), _cct(cct) { } ~CephContextServiceThread() {} void *entry() { while (1) { Mutex::Locker l(_lock); if (_cct->_conf->heartbeat_interval) { utime_t interval(_cct->_conf->heartbeat_interval, 0); _cond.WaitInterval(_cct, _lock, interval); } else _cond.Wait(_lock); if (_exit_thread) { break; } if (_reopen_logs) { _cct->_log->reopen_log_file(); _reopen_logs = false; } _cct->_heartbeat_map->check_touch_file(); } return NULL; } void reopen_logs() { Mutex::Locker l(_lock); _reopen_logs = true; _cond.Signal(); } void exit_thread() { Mutex::Locker l(_lock); _exit_thread = true; _cond.Signal(); } private: Mutex _lock; Cond _cond; bool _reopen_logs; bool _exit_thread; CephContext *_cct; }; /** * observe logging config changes * * The logging subsystem sits below most of the ceph code, including * the config subsystem, to keep it simple and self-contained. Feed * logging-related config changes to the log. */ class LogObs : public md_config_obs_t { ceph::log::Log *log; public: LogObs(ceph::log::Log *l) : log(l) {} const char** get_tracked_conf_keys() const { static const char *KEYS[] = { "log_file", "log_max_new", "log_max_recent", "log_to_syslog", "err_to_syslog", "log_to_stderr", "err_to_stderr", NULL }; return KEYS; } void handle_conf_change(const md_config_t *conf, const std::set &changed) { // stderr if (changed.count("log_to_stderr") || changed.count("err_to_stderr")) { int l = conf->log_to_stderr ? 99 : (conf->err_to_stderr ? -1 : -2); log->set_stderr_level(l, l); } // syslog if (changed.count("log_to_syslog")) { int l = conf->log_to_syslog ? 99 : (conf->err_to_syslog ? -1 : -2); log->set_syslog_level(l, l); } // file if (changed.count("log_file")) { log->set_log_file(conf->log_file); log->reopen_log_file(); } if (changed.count("log_max_new")) { log->set_max_new(conf->log_max_new); } if (changed.count("log_max_recent")) { log->set_max_recent(conf->log_max_recent); } } }; // perfcounter hooks class CephContextHook : public AdminSocketHook { CephContext *m_cct; public: CephContextHook(CephContext *cct) : m_cct(cct) {} bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out) { m_cct->do_command(command, cmdmap, format, &out); return true; } }; void CephContext::do_command(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist *out) { Formatter *f = new_formatter(format); if (!f) f = new_formatter("json-pretty"); stringstream ss; for (cmdmap_t::iterator it = cmdmap.begin(); it != cmdmap.end(); ++it) { if (it->first != "prefix") { ss << it->first << ":" << cmd_vartype_stringify(it->second) << " "; } } lgeneric_dout(this, 1) << "do_command '" << command << "' '" << ss.str() << dendl; if (command == "perfcounters_dump" || command == "1" || command == "perf dump") { _perf_counters_collection->dump_formatted(f, false); } else if (command == "perfcounters_schema" || command == "2" || command == "perf schema") { _perf_counters_collection->dump_formatted(f, true); } else { f->open_object_section(command.c_str()); if (command == "config show") { _conf->show_config(f); } else if (command == "config set") { std::string var; std::vector val; if (!(cmd_getval(this, cmdmap, "var", var)) || !(cmd_getval(this, cmdmap, "val", val))) { f->dump_string("error", "syntax error: 'config set '"); } else { // val may be multiple words string valstr = str_join(val, " "); int r = _conf->set_val(var.c_str(), valstr.c_str()); if (r < 0) { f->dump_stream("error") << "error setting '" << var << "' to '" << valstr << "': " << cpp_strerror(r); } else { ostringstream ss; _conf->apply_changes(&ss); f->dump_string("success", ss.str()); } } } else if (command == "config get") { std::string var; if (!cmd_getval(this, cmdmap, "var", var)) { f->dump_string("error", "syntax error: 'config get '"); } else { char buf[4096]; memset(buf, 0, sizeof(buf)); char *tmp = buf; int r = _conf->get_val(var.c_str(), &tmp, sizeof(buf)); if (r < 0) { f->dump_stream("error") << "error getting '" << var << "': " << cpp_strerror(r); } else { f->dump_string(var.c_str(), buf); } } } else if (command == "log flush") { _log->flush(); } else if (command == "log dump") { _log->dump_recent(); } else if (command == "log reopen") { _log->reopen_log_file(); } else { assert(0 == "registered under wrong command?"); } f->close_section(); } f->flush(*out); delete f; lgeneric_dout(this, 1) << "do_command '" << command << "' '" << ss.str() << "result is " << out->length() << " bytes" << dendl; }; CephContext::CephContext(uint32_t module_type_) : nref(1), _conf(new md_config_t()), _log(NULL), _module_type(module_type_), _service_thread(NULL), _log_obs(NULL), _admin_socket(NULL), _perf_counters_collection(NULL), _perf_counters_conf_obs(NULL), _heartbeat_map(NULL), _crypto_none(NULL), _crypto_aes(NULL) { ceph_spin_init(&_service_thread_lock); ceph_spin_init(&_associated_objs_lock); _log = new ceph::log::Log(&_conf->subsys); _log->start(); _log_obs = new LogObs(_log); _conf->add_observer(_log_obs); _perf_counters_collection = new PerfCountersCollection(this); _admin_socket = new AdminSocket(this); _heartbeat_map = new HeartbeatMap(this); _admin_hook = new CephContextHook(this); _admin_socket->register_command("perfcounters_dump", "perfcounters_dump", _admin_hook, ""); _admin_socket->register_command("1", "1", _admin_hook, ""); _admin_socket->register_command("perf dump", "perf dump", _admin_hook, "dump perfcounters value"); _admin_socket->register_command("perfcounters_schema", "perfcounters_schema", _admin_hook, ""); _admin_socket->register_command("2", "2", _admin_hook, ""); _admin_socket->register_command("perf schema", "perf schema", _admin_hook, "dump perfcounters schema"); _admin_socket->register_command("config show", "config show", _admin_hook, "dump current config settings"); _admin_socket->register_command("config set", "config set name=var,type=CephString name=val,type=CephString,n=N", _admin_hook, "config set [ ...]: set a config variable"); _admin_socket->register_command("config get", "config get name=var,type=CephString", _admin_hook, "config get : get the config value"); _admin_socket->register_command("log flush", "log flush", _admin_hook, "flush log entries to log file"); _admin_socket->register_command("log dump", "log dump", _admin_hook, "dump recent log entries to log file"); _admin_socket->register_command("log reopen", "log reopen", _admin_hook, "reopen log file"); _crypto_none = new CryptoNone; _crypto_aes = new CryptoAES; } CephContext::~CephContext() { join_service_thread(); for (map::iterator it = _associated_objs.begin(); it != _associated_objs.end(); it++) delete it->second; if (_conf->lockdep) { lockdep_unregister_ceph_context(this); } _admin_socket->unregister_command("perfcounters_dump"); _admin_socket->unregister_command("perf dump"); _admin_socket->unregister_command("1"); _admin_socket->unregister_command("perfcounters_schema"); _admin_socket->unregister_command("perf schema"); _admin_socket->unregister_command("2"); _admin_socket->unregister_command("config show"); _admin_socket->unregister_command("config set"); _admin_socket->unregister_command("config get"); _admin_socket->unregister_command("log flush"); _admin_socket->unregister_command("log dump"); _admin_socket->unregister_command("log reopen"); delete _admin_hook; delete _admin_socket; delete _heartbeat_map; delete _perf_counters_collection; _perf_counters_collection = NULL; delete _perf_counters_conf_obs; _perf_counters_conf_obs = NULL; _conf->remove_observer(_log_obs); delete _log_obs; _log_obs = NULL; _log->stop(); delete _log; _log = NULL; delete _conf; ceph_spin_destroy(&_service_thread_lock); ceph_spin_destroy(&_associated_objs_lock); delete _crypto_none; delete _crypto_aes; } void CephContext::start_service_thread() { ceph_spin_lock(&_service_thread_lock); if (_service_thread) { ceph_spin_unlock(&_service_thread_lock); return; } _service_thread = new CephContextServiceThread(this); _service_thread->create(); ceph_spin_unlock(&_service_thread_lock); // make logs flush on_exit() if (_conf->log_flush_on_exit) _log->set_flush_on_exit(); // Trigger callbacks on any config observers that were waiting for // it to become safe to start threads. _conf->set_val("internal_safe_to_start_threads", "true"); _conf->call_all_observers(); // start admin socket if (_conf->admin_socket.length()) _admin_socket->init(_conf->admin_socket); } void CephContext::reopen_logs() { ceph_spin_lock(&_service_thread_lock); if (_service_thread) _service_thread->reopen_logs(); ceph_spin_unlock(&_service_thread_lock); } void CephContext::join_service_thread() { ceph_spin_lock(&_service_thread_lock); CephContextServiceThread *thread = _service_thread; if (!thread) { ceph_spin_unlock(&_service_thread_lock); return; } _service_thread = NULL; ceph_spin_unlock(&_service_thread_lock); thread->exit_thread(); thread->join(); delete thread; } uint32_t CephContext::get_module_type() const { return _module_type; } PerfCountersCollection *CephContext::get_perfcounters_collection() { return _perf_counters_collection; } AdminSocket *CephContext::get_admin_socket() { return _admin_socket; } CryptoHandler *CephContext::get_crypto_handler(int type) { switch (type) { case CEPH_CRYPTO_NONE: return _crypto_none; case CEPH_CRYPTO_AES: return _crypto_aes; default: return NULL; } } ceph-0.80.11/src/common/ceph_crypto.h0000664000175100017510000000772512623076744021457 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRYPTO_H #define CEPH_CRYPTO_H #include "acconfig.h" #define CEPH_CRYPTO_MD5_DIGESTSIZE 16 #define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20 #define CEPH_CRYPTO_SHA1_DIGESTSIZE 20 #define CEPH_CRYPTO_SHA256_DIGESTSIZE 32 #ifdef USE_CRYPTOPP # define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 #include # include # include # include // reinclude our assert to clobber the system one # include "include/assert.h" namespace ceph { namespace crypto { void assert_init(); void init(CephContext *cct); void shutdown(); using CryptoPP::Weak::MD5; using CryptoPP::SHA1; using CryptoPP::SHA256; class HMACSHA1: public CryptoPP::HMAC { public: HMACSHA1 (const byte *key, size_t length) : CryptoPP::HMAC(key, length) { } ~HMACSHA1(); }; } } #elif USE_NSS // you *must* use CRYPTO_CXXFLAGS in Makefile.am for including this include # include # include // NSS thinks a lot of fairly fundamental operations might potentially // fail, because it has been written to support e.g. smartcards doing all // the crypto operations. We don't want to contaminate too much code // with error checking, and just say these really should never fail. // This assert MUST NOT be compiled out, even on non-debug builds. # include "include/assert.h" // ugly bit of CryptoPP that we have to emulate here :( typedef unsigned char byte; namespace ceph { namespace crypto { void assert_init(); void init(CephContext *cct); void shutdown(); class Digest { private: PK11Context *ctx; SECOidTag sec_type; size_t digest_size; public: Digest (SECOidTag _type, size_t _digest_size) : sec_type(_type), digest_size(_digest_size) { ctx = PK11_CreateDigestContext(_type); assert(ctx); Restart(); } ~Digest () { PK11_DestroyContext(ctx, PR_TRUE); } void Restart() { SECStatus s; s = PK11_DigestBegin(ctx); assert(s == SECSuccess); } void Update (const byte *input, size_t length) { if (length) { SECStatus s; s = PK11_DigestOp(ctx, input, length); assert(s == SECSuccess); } } void Final (byte *digest) { SECStatus s; unsigned int dummy; s = PK11_DigestFinal(ctx, digest, &dummy, digest_size); assert(s == SECSuccess); assert(dummy == digest_size); Restart(); } }; class MD5 : public Digest { public: MD5 () : Digest(SEC_OID_MD5, CEPH_CRYPTO_MD5_DIGESTSIZE) { } }; class SHA1 : public Digest { public: SHA1 () : Digest(SEC_OID_SHA1, CEPH_CRYPTO_SHA1_DIGESTSIZE) { } }; class SHA256 : public Digest { public: SHA256 () : Digest(SEC_OID_SHA256, CEPH_CRYPTO_SHA256_DIGESTSIZE) { } }; class HMACSHA1 { private: PK11SlotInfo *slot; PK11SymKey *symkey; PK11Context *ctx; public: HMACSHA1 (const byte *key, size_t length) { slot = PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL); assert(slot); SECItem keyItem; keyItem.type = siBuffer; keyItem.data = (unsigned char*)key; keyItem.len = length; symkey = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); assert(symkey); SECItem param; param.type = siBuffer; param.data = NULL; param.len = 0; ctx = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, symkey, ¶m); assert(ctx); Restart(); } ~HMACSHA1 (); void Restart() { SECStatus s; s = PK11_DigestBegin(ctx); assert(s == SECSuccess); } void Update (const byte *input, size_t length) { SECStatus s; s = PK11_DigestOp(ctx, input, length); assert(s == SECSuccess); } void Final (byte *digest) { SECStatus s; unsigned int dummy; s = PK11_DigestFinal(ctx, digest, &dummy, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); assert(s == SECSuccess); assert(dummy == CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); Restart(); } }; } } #else # error "No supported crypto implementation found." #endif #endif ceph-0.80.11/src/common/hobject.cc0000664000175100017510000001677412623076744020720 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "hobject.h" #include "common/Formatter.h" static void append_escaped(const string &in, string *out) { for (string::const_iterator i = in.begin(); i != in.end(); ++i) { if (*i == '%') { out->push_back('%'); out->push_back('p'); } else if (*i == '.') { out->push_back('%'); out->push_back('e'); } else if (*i == '_') { out->push_back('%'); out->push_back('u'); } else { out->push_back(*i); } } } set hobject_t::get_prefixes( uint32_t bits, uint32_t mask, int64_t pool) { uint32_t len = bits; while (len % 4 /* nibbles */) len++; set from; if (bits < 32) from.insert(mask & ~((uint32_t)(~0) << bits)); else if (bits == 32) from.insert(mask); else assert(0); set to; for (uint32_t i = bits; i < len; ++i) { for (set::iterator j = from.begin(); j != from.end(); ++j) { to.insert(*j | (1 << i)); to.insert(*j); } to.swap(from); to.clear(); } char buf[20]; char *t = buf; uint64_t poolid(pool); t += snprintf(t, sizeof(buf), "%.*llX", 16, (long long unsigned)poolid); *(t++) = '.'; string poolstr(buf, t - buf); set ret; for (set::iterator i = from.begin(); i != from.end(); ++i) { uint32_t revhash(hobject_t::_reverse_nibbles(*i)); snprintf(buf, sizeof(buf), "%.*X", (int)(sizeof(revhash))*2, revhash); ret.insert(poolstr + string(buf, len/4)); } return ret; } string hobject_t::to_str() const { string out; char snap_with_hash[1000]; char *t = snap_with_hash; char *end = t + sizeof(snap_with_hash); uint64_t poolid(pool); t += snprintf(t, end - t, "%.*llX", 16, (long long unsigned)poolid); uint32_t revhash(get_filestore_key_u32()); t += snprintf(t, end - t, ".%.*X", 8, revhash); if (snap == CEPH_NOSNAP) t += snprintf(t, end - t, ".head"); else if (snap == CEPH_SNAPDIR) t += snprintf(t, end - t, ".snapdir"); else t += snprintf(t, end - t, ".%llx", (long long unsigned)snap); out += string(snap_with_hash); out.push_back('.'); append_escaped(oid.name, &out); out.push_back('.'); append_escaped(get_key(), &out); out.push_back('.'); append_escaped(nspace, &out); return out; } void hobject_t::encode(bufferlist& bl) const { ENCODE_START(4, 3, bl); ::encode(key, bl); ::encode(oid, bl); ::encode(snap, bl); ::encode(hash, bl); ::encode(max, bl); ::encode(nspace, bl); ::encode(pool, bl); ENCODE_FINISH(bl); } void hobject_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl); if (struct_v >= 1) ::decode(key, bl); ::decode(oid, bl); ::decode(snap, bl); ::decode(hash, bl); if (struct_v >= 2) ::decode(max, bl); else max = false; if (struct_v >= 4) { ::decode(nspace, bl); ::decode(pool, bl); } DECODE_FINISH(bl); } void hobject_t::decode(json_spirit::Value& v) { using namespace json_spirit; Object& o = v.get_obj(); for (Object::size_type i=0; idump_string("oid", oid.name); f->dump_string("key", key); f->dump_int("snapid", snap); f->dump_int("hash", hash); f->dump_int("max", (int)max); f->dump_int("pool", pool); f->dump_string("namespace", nspace); } void hobject_t::generate_test_instances(list& o) { o.push_back(new hobject_t); o.push_back(new hobject_t); o.back()->max = true; o.push_back(new hobject_t(object_t("oname"), string(), 1, 234, -1, "")); o.push_back(new hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP, 67, 0, "n1")); o.push_back(new hobject_t(object_t("oname3"), string("oname3"), CEPH_SNAPDIR, 910, 1, "n2")); } ostream& operator<<(ostream& out, const hobject_t& o) { if (o.is_max()) return out << "MAX"; out << std::hex << o.hash << std::dec; if (o.get_key().length()) out << "." << o.get_key(); out << "/" << o.oid << "/" << o.snap; out << "/" << o.nspace << "/" << o.pool; return out; } // This is compatible with decode for hobject_t prior to // version 5. void ghobject_t::encode(bufferlist& bl) const { ENCODE_START(5, 3, bl); ::encode(hobj.key, bl); ::encode(hobj.oid, bl); ::encode(hobj.snap, bl); ::encode(hobj.hash, bl); ::encode(hobj.max, bl); ::encode(hobj.nspace, bl); ::encode(hobj.pool, bl); ::encode(generation, bl); ::encode(shard_id, bl); ENCODE_FINISH(bl); } void ghobject_t::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl); if (struct_v >= 1) ::decode(hobj.key, bl); ::decode(hobj.oid, bl); ::decode(hobj.snap, bl); ::decode(hobj.hash, bl); if (struct_v >= 2) ::decode(hobj.max, bl); else hobj.max = false; if (struct_v >= 4) { ::decode(hobj.nspace, bl); ::decode(hobj.pool, bl); } if (struct_v >= 5) { ::decode(generation, bl); ::decode(shard_id, bl); } else { generation = ghobject_t::NO_GEN; shard_id = ghobject_t::NO_SHARD; } DECODE_FINISH(bl); } void ghobject_t::decode(json_spirit::Value& v) { hobj.decode(v); using namespace json_spirit; Object& o = v.get_obj(); for (Object::size_type i=0; idump_int("generation", generation); if (shard_id != ghobject_t::NO_SHARD) f->dump_int("shard_id", shard_id); } void ghobject_t::generate_test_instances(list& o) { o.push_back(new ghobject_t); o.push_back(new ghobject_t); o.back()->hobj.max = true; o.push_back(new ghobject_t(hobject_t(object_t("oname"), string(), 1, 234, -1, ""))); o.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP, 67, 0, "n1"), 1, 0)); o.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP, 67, 0, "n1"), 1, 1)); o.push_back(new ghobject_t(hobject_t(object_t("oname2"), string("okey"), CEPH_NOSNAP, 67, 0, "n1"), 1, 2)); o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"), CEPH_SNAPDIR, 910, 1, "n2"), 1, 0)); o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"), CEPH_SNAPDIR, 910, 1, "n2"), 2, 0)); o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"), CEPH_SNAPDIR, 910, 1, "n2"), 3, 0)); o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"), CEPH_SNAPDIR, 910, 1, "n2"), 3, 1)); o.push_back(new ghobject_t(hobject_t(object_t("oname3"), string("oname3"), CEPH_SNAPDIR, 910, 1, "n2"), 3, 2)); } ostream& operator<<(ostream& out, const ghobject_t& o) { out << o.hobj; if (o.generation != ghobject_t::NO_GEN || o.shard_id != ghobject_t::NO_SHARD) { assert(o.shard_id != ghobject_t::NO_SHARD); out << "/" << o.generation << "/" << (unsigned)(o.shard_id); } return out; } ceph-0.80.11/src/common/secret.h0000664000175100017510000000105312623076744020411 0ustar jenkins-buildjenkins-build#ifndef CEPH_SECRET_H #define CEPH_SECRET_H #ifdef __cplusplus extern "C" { #endif int read_secret_from_file(const char *filename, char *secret, size_t max_len); /* * Attempts to add the secret to the kernel, but falls back to * the old secret= option if the kernel is too old. */ int get_secret_option(const char *secret, const char *key_name, char *secret_option, size_t secret_option_len); int set_kernel_secret(const char *secret, const char *key_name); int is_kernel_secret(const char *key_name); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/ceph_crypto_cms.cc0000664000175100017510000002440012623076744022444 0ustar jenkins-buildjenkins-build/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "common/config.h" #ifdef USE_NSS #include #include #include #include #endif #include #include #include "include/buffer.h" #include "common/debug.h" #include "ceph_crypto_cms.h" #define dout_subsys ceph_subsys_crypto #ifndef USE_NSS int ceph_decode_cms(CephContext *cct, bufferlist& cms_bl, bufferlist& decoded_bl) { return -ENOTSUP; } #else static int cms_verbose = 0; static SECStatus DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input, SECAlgorithmID **algids) { NSSCMSDigestContext *digcx; SECStatus rv; digcx = NSS_CMSDigestContext_StartMultiple(algids); if (digcx == NULL) return SECFailure; NSS_CMSDigestContext_Update(digcx, input->data, input->len); rv = NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests); return rv; } struct optionsStr { SECCertUsage certUsage; CERTCertDBHandle *certHandle; }; struct decodeOptionsStr { struct optionsStr *options; SECItem content; int headerLevel; PRBool suppressContent; NSSCMSGetDecryptKeyCallback dkcb; PK11SymKey *bulkkey; PRBool keepCerts; }; static NSSCMSMessage * decode(CephContext *cct, SECItem *input, const struct decodeOptionsStr *decodeOptions, bufferlist& out) { NSSCMSDecoderContext *dcx; SECStatus rv; NSSCMSMessage *cmsg; int nlevels, i; SECItem sitem; bufferptr bp; SECItem *item; memset(&sitem, 0, sizeof(sitem)); PORT_SetError(0); dcx = NSS_CMSDecoder_Start(NULL, NULL, NULL, /* content callback */ NULL, NULL, /* password callback */ decodeOptions->dkcb, /* decrypt key callback */ decodeOptions->bulkkey); if (dcx == NULL) { ldout(cct, 0) << "ERROR: failed to set up message decoder" << dendl; return NULL; } rv = NSS_CMSDecoder_Update(dcx, (char *)input->data, input->len); if (rv != SECSuccess) { ldout(cct, 0) << "ERROR: failed to decode message" << dendl; NSS_CMSDecoder_Cancel(dcx); return NULL; } cmsg = NSS_CMSDecoder_Finish(dcx); if (cmsg == NULL) { ldout(cct, 0) << "ERROR: failed to decode message" << dendl; return NULL; } if (decodeOptions->headerLevel >= 0) { ldout(cct, 20) << "SMIME: " << dendl; } nlevels = NSS_CMSMessage_ContentLevelCount(cmsg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *cinfo; SECOidTag typetag; cinfo = NSS_CMSMessage_ContentLevel(cmsg, i); typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); ldout(cct, 20) << "level=" << decodeOptions->headerLevel << "." << nlevels - i << dendl; switch (typetag) { case SEC_OID_PKCS7_SIGNED_DATA: { NSSCMSSignedData *sigd = NULL; SECItem **digests; int nsigners; int j; if (decodeOptions->headerLevel >= 0) ldout(cct, 20) << "type=signedData; " << dendl; sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo); if (sigd == NULL) { ldout(cct, 0) << "ERROR: signedData component missing" << dendl; goto loser; } /* if we have a content file, but no digests for this signedData */ if (decodeOptions->content.data != NULL && !NSS_CMSSignedData_HasDigests(sigd)) { PLArenaPool *poolp; SECAlgorithmID **digestalgs; /* detached content: grab content file */ sitem = decodeOptions->content; if ((poolp = PORT_NewArena(1024)) == NULL) { ldout(cct, 0) << "ERROR: Out of memory" << dendl; goto loser; } digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd); if (DigestFile (poolp, &digests, &sitem, digestalgs) != SECSuccess) { ldout(cct, 0) << "ERROR: problem computing message digest" << dendl; PORT_FreeArena(poolp, PR_FALSE); goto loser; } if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) { ldout(cct, 0) << "ERROR: problem setting message digests" << dendl; PORT_FreeArena(poolp, PR_FALSE); goto loser; } PORT_FreeArena(poolp, PR_FALSE); } /* import the certificates */ if (NSS_CMSSignedData_ImportCerts(sigd, decodeOptions->options->certHandle, decodeOptions->options->certUsage, decodeOptions->keepCerts) != SECSuccess) { ldout(cct, 0) << "ERROR: cert import failed" << dendl; goto loser; } /* find out about signers */ nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); if (decodeOptions->headerLevel >= 0) ldout(cct, 20) << "nsigners=" << nsigners << dendl; if (nsigners == 0) { /* Might be a cert transport message ** or might be an invalid message, such as a QA test message ** or a message from an attacker. */ SECStatus rv; rv = NSS_CMSSignedData_VerifyCertsOnly(sigd, decodeOptions->options->certHandle, decodeOptions->options->certUsage); if (rv != SECSuccess) { ldout(cct, 0) << "ERROR: Verify certs-only failed!" << dendl; goto loser; } return cmsg; } /* still no digests? */ if (!NSS_CMSSignedData_HasDigests(sigd)) { ldout(cct, 0) << "ERROR: no message digests" << dendl; goto loser; } for (j = 0; j < nsigners; j++) { const char * svs; NSSCMSSignerInfo *si; NSSCMSVerificationStatus vs; SECStatus bad; si = NSS_CMSSignedData_GetSignerInfo(sigd, j); if (decodeOptions->headerLevel >= 0) { char *signercn; static char empty[] = { "" }; signercn = NSS_CMSSignerInfo_GetSignerCommonName(si); if (signercn == NULL) signercn = empty; ldout(cct, 20) << "\t\tsigner" << j << ".id=" << signercn << dendl; if (signercn != empty) PORT_Free(signercn); } bad = NSS_CMSSignedData_VerifySignerInfo(sigd, j, decodeOptions->options->certHandle, decodeOptions->options->certUsage); vs = NSS_CMSSignerInfo_GetVerificationStatus(si); svs = NSS_CMSUtil_VerificationStatusToString(vs); if (decodeOptions->headerLevel >= 0) { ldout(cct, 20) << "signer" << j << "status=" << svs << dendl; /* goto loser ? */ } else if (bad) { ldout(cct, 0) << "ERROR: signer " << j << " status = " << svs << dendl; goto loser; } } } break; case SEC_OID_PKCS7_ENVELOPED_DATA: { NSSCMSEnvelopedData *envd; if (decodeOptions->headerLevel >= 0) ldout(cct, 20) << "type=envelopedData; " << dendl; envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo); if (envd == NULL) { ldout(cct, 0) << "ERROR: envelopedData component missing" << dendl; goto loser; } } break; case SEC_OID_PKCS7_ENCRYPTED_DATA: { NSSCMSEncryptedData *encd; if (decodeOptions->headerLevel >= 0) ldout(cct, 20) << "type=encryptedData; " << dendl; encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo); if (encd == NULL) { ldout(cct, 0) << "ERROR: encryptedData component missing" << dendl; goto loser; } } break; case SEC_OID_PKCS7_DATA: if (decodeOptions->headerLevel >= 0) ldout(cct, 20) << "type=data; " << dendl; break; default: break; } } item = (sitem.data ? &sitem : NSS_CMSMessage_GetContent(cmsg)); out.append((char *)item->data, item->len); return cmsg; loser: if (cmsg) NSS_CMSMessage_Destroy(cmsg); return NULL; } int ceph_decode_cms(CephContext *cct, bufferlist& cms_bl, bufferlist& decoded_bl) { NSSCMSMessage *cmsg = NULL; struct decodeOptionsStr decodeOptions = { 0 }; struct optionsStr options; SECItem input; memset(&options, 0, sizeof(options)); memset(&input, 0, sizeof(input)); input.data = (unsigned char *)cms_bl.c_str(); input.len = cms_bl.length(); decodeOptions.content.data = NULL; decodeOptions.content.len = 0; decodeOptions.suppressContent = PR_FALSE; decodeOptions.headerLevel = -1; decodeOptions.keepCerts = PR_FALSE; options.certUsage = certUsageEmailSigner; options.certHandle = CERT_GetDefaultCertDB(); if (!options.certHandle) { ldout(cct, 0) << "ERROR: No default cert DB" << dendl; return -EIO; } if (cms_verbose) { fprintf(stderr, "Got default certdb\n"); } decodeOptions.options = &options; int ret = 0; cmsg = decode(cct, &input, &decodeOptions, decoded_bl); if (!cmsg) { ldout(cct, 0) << "ERROR: problem decoding" << dendl; ret = -EINVAL; } if (cmsg) NSS_CMSMessage_Destroy(cmsg); SECITEM_FreeItem(&decodeOptions.content, PR_FALSE); return ret; } #endif ceph-0.80.11/src/common/crc32c.cc0000664000175100017510000000212212623076744020337 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/crc32c.h" #include "arch/probe.h" #include "arch/intel.h" #include "common/sctp_crc32.h" #include "common/crc32c_intel_baseline.h" #include "common/crc32c_intel_fast.h" /* * choose best implementation based on the CPU architecture. */ ceph_crc32c_func_t ceph_choose_crc32(void) { // make sure we've probed cpu features; this might depend on the // link order of this file relative to arch/probe.cc. ceph_arch_probe(); // if the CPU supports it, *and* the fast version is compiled in, // use that. if (ceph_arch_intel_sse42 && ceph_crc32c_intel_fast_exists()) { return ceph_crc32c_intel_fast; } // default return ceph_crc32c_sctp; } /* * static global * * This is a bit of a no-no for shared libraries, but we don't care. * It is effectively constant for the executing process as the value * depends on the CPU architecture. * * We initialize it during program init using the magic of C++. */ ceph_crc32c_func_t ceph_crc32c_func = ceph_choose_crc32(); ceph-0.80.11/src/common/Formatter.cc0000664000175100017510000002505312623076744021233 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #define LARGE_SIZE 1024 #include "include/int_types.h" #include "assert.h" #include "Formatter.h" #include "common/escape.h" #include #include #include #include #include #include // ----------------------- namespace ceph { /* * FormatterAttrs(const char *attr, ...) * * Requires a list of of attrs followed by NULL. The attrs should be char * * pairs, first one is the name, second one is the value. E.g., * * FormatterAttrs("name1", "value1", "name2", "value2", NULL); */ FormatterAttrs::FormatterAttrs(const char *attr, ...) { const char *s = attr; va_list ap; va_start(ap, attr); do { const char *val = va_arg(ap, char *); if (!val) break; attrs.push_back(make_pair(std::string(s), std::string(val))); s = va_arg(ap, char *); } while (s); va_end(ap); } Formatter::Formatter() { } Formatter::~Formatter() { } Formatter * new_formatter(const std::string &type) { std::string mytype = type; if (mytype == "") mytype = "json-pretty"; if (mytype == "json") return new JSONFormatter(false); else if (mytype == "json-pretty") return new JSONFormatter(true); else if (mytype == "xml") return new XMLFormatter(false); else if (mytype == "xml-pretty") return new XMLFormatter(true); else return (Formatter *)NULL; } // ----------------------- JSONFormatter::JSONFormatter(bool p) : m_pretty(p), m_is_pending_string(false) { reset(); } void JSONFormatter::flush(std::ostream& os) { finish_pending_string(); os << m_ss.str(); m_ss.clear(); m_ss.str(""); } void JSONFormatter::reset() { m_stack.clear(); m_ss.clear(); m_ss.str(""); m_pending_string.clear(); m_pending_string.str(""); } void JSONFormatter::print_comma(json_formatter_stack_entry_d& entry) { if (entry.size) { if (m_pretty) { m_ss << ",\n"; for (unsigned i=1; i < m_stack.size(); i++) m_ss << " "; } else { m_ss << ","; } } else if (entry.is_array && m_pretty) { m_ss << "\n"; for (unsigned i=1; i < m_stack.size(); i++) m_ss << " "; } if (m_pretty && entry.is_array) m_ss << " "; } void JSONFormatter::print_quoted_string(const char *s) { int len = escape_json_attr_len(s); char *escaped = new char[len]; escape_json_attr(s, escaped); m_ss << '\"' << escaped << '\"'; delete[] escaped; } void JSONFormatter::print_name(const char *name) { finish_pending_string(); if (m_stack.empty()) return; struct json_formatter_stack_entry_d& entry = m_stack.back(); print_comma(entry); if (!entry.is_array) { if (m_pretty) { if (entry.size) m_ss << " "; else m_ss << " "; } m_ss << "\"" << name << "\""; if (m_pretty) m_ss << ": "; else m_ss << ':'; } ++entry.size; } void JSONFormatter::open_section(const char *name, bool is_array) { print_name(name); if (is_array) m_ss << '['; else m_ss << '{'; json_formatter_stack_entry_d n; n.is_array = is_array; m_stack.push_back(n); } void JSONFormatter::open_array_section(const char *name) { open_section(name, true); } void JSONFormatter::open_array_section_in_ns(const char *name, const char *ns) { std::ostringstream oss; oss << name << " " << ns; open_section(oss.str().c_str(), true); } void JSONFormatter::open_object_section(const char *name) { open_section(name, false); } void JSONFormatter::open_object_section_in_ns(const char *name, const char *ns) { std::ostringstream oss; oss << name << " " << ns; open_section(oss.str().c_str(), false); } void JSONFormatter::close_section() { assert(!m_stack.empty()); finish_pending_string(); struct json_formatter_stack_entry_d& entry = m_stack.back(); m_ss << (entry.is_array ? ']' : '}'); m_stack.pop_back(); } void JSONFormatter::finish_pending_string() { if (m_is_pending_string) { print_quoted_string(m_pending_string.str().c_str()); m_pending_string.str(std::string()); m_is_pending_string = false; } } void JSONFormatter::dump_unsigned(const char *name, uint64_t u) { print_name(name); m_ss << u; } void JSONFormatter::dump_int(const char *name, int64_t s) { print_name(name); m_ss << s; } void JSONFormatter::dump_float(const char *name, double d) { char foo[30]; snprintf(foo, sizeof(foo), "%lf", d); dump_string(name, foo); } void JSONFormatter::dump_string(const char *name, std::string s) { print_name(name); print_quoted_string(s.c_str()); } std::ostream& JSONFormatter::dump_stream(const char *name) { print_name(name); m_is_pending_string = true; return m_pending_string; } void JSONFormatter::dump_format(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); print_name(name); print_quoted_string(buf); } void JSONFormatter::dump_format_unquoted(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); print_name(name); m_ss << buf; } int JSONFormatter::get_len() const { return m_ss.str().size(); } void JSONFormatter::write_raw_data(const char *data) { m_ss << data; } const char *XMLFormatter::XML_1_DTD = ""; XMLFormatter::XMLFormatter(bool pretty) : m_pretty(pretty) { reset(); } void XMLFormatter::flush(std::ostream& os) { finish_pending_string(); os << m_ss.str(); m_ss.clear(); m_ss.str(""); } void XMLFormatter::reset() { m_ss.clear(); m_ss.str(""); m_pending_string.clear(); m_pending_string.str(""); m_sections.clear(); m_pending_string_name.clear(); } void XMLFormatter::open_object_section(const char *name) { open_section_in_ns(name, NULL, NULL); } void XMLFormatter::open_object_section_with_attrs(const char *name, const FormatterAttrs& attrs) { open_section_in_ns(name, NULL, &attrs); } void XMLFormatter::open_object_section_in_ns(const char *name, const char *ns) { open_section_in_ns(name, ns, NULL); } void XMLFormatter::open_array_section(const char *name) { open_section_in_ns(name, NULL, NULL); } void XMLFormatter::open_array_section_with_attrs(const char *name, const FormatterAttrs& attrs) { open_section_in_ns(name, NULL, &attrs); } void XMLFormatter::open_array_section_in_ns(const char *name, const char *ns) { open_section_in_ns(name, ns, NULL); } void XMLFormatter::close_section() { assert(!m_sections.empty()); finish_pending_string(); std::string section = m_sections.back(); m_sections.pop_back(); print_spaces(); m_ss << ""; if (m_pretty) m_ss << "\n"; } void XMLFormatter::dump_unsigned(const char *name, uint64_t u) { std::string e(name); print_spaces(); m_ss << "<" << e << ">" << u << ""; if (m_pretty) m_ss << "\n"; } void XMLFormatter::dump_int(const char *name, int64_t u) { std::string e(name); print_spaces(); m_ss << "<" << e << ">" << u << ""; if (m_pretty) m_ss << "\n"; } void XMLFormatter::dump_float(const char *name, double d) { std::string e(name); print_spaces(); m_ss << "<" << e << ">" << d << ""; if (m_pretty) m_ss << "\n"; } void XMLFormatter::dump_string(const char *name, std::string s) { std::string e(name); print_spaces(); m_ss << "<" << e << ">" << escape_xml_str(s.c_str()) << ""; if (m_pretty) m_ss << "\n"; } void XMLFormatter::dump_string_with_attrs(const char *name, std::string s, const FormatterAttrs& attrs) { std::string e(name); std::string attrs_str; get_attrs_str(&attrs, attrs_str); print_spaces(); m_ss << "<" << e << attrs_str << ">" << escape_xml_str(s.c_str()) << ""; if (m_pretty) m_ss << "\n"; } std::ostream& XMLFormatter::dump_stream(const char *name) { print_spaces(); m_pending_string_name = name; m_ss << "<" << m_pending_string_name << ">"; return m_pending_string; } void XMLFormatter::dump_format(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); std::string e(name); print_spaces(); m_ss << "<" << e << ">" << escape_xml_str(buf) << ""; if (m_pretty) m_ss << "\n"; } void XMLFormatter::dump_format_unquoted(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); std::string e(name); print_spaces(); m_ss << "<" << e << ">" << buf << ""; if (m_pretty) m_ss << "\n"; } int XMLFormatter::get_len() const { return m_ss.str().size(); } void XMLFormatter::write_raw_data(const char *data) { m_ss << data; } void XMLFormatter::get_attrs_str(const FormatterAttrs *attrs, std::string& attrs_str) { std::stringstream attrs_ss; for (std::list >::const_iterator iter = attrs->attrs.begin(); iter != attrs->attrs.end(); ++iter) { std::pair p = *iter; attrs_ss << " " << p.first << "=" << "\"" << p.second << "\""; } attrs_str = attrs_ss.str(); } void XMLFormatter::open_section_in_ns(const char *name, const char *ns, const FormatterAttrs *attrs) { print_spaces(); std::string attrs_str; if (attrs) { get_attrs_str(attrs, attrs_str); } if (ns) { m_ss << "<" << name << attrs_str << " xmlns=\"" << ns << "\">"; } else { m_ss << "<" << name << attrs_str << ">"; } if (m_pretty) m_ss << "\n"; m_sections.push_back(name); } void XMLFormatter::finish_pending_string() { if (!m_pending_string_name.empty()) { m_ss << escape_xml_str(m_pending_string.str().c_str()) << ""; m_pending_string_name.clear(); m_pending_string.str(std::string()); if (m_pretty) { m_ss << "\n"; } } } void XMLFormatter::print_spaces() { finish_pending_string(); if (m_pretty) { std::string spaces(m_sections.size(), ' '); m_ss << spaces; } } std::string XMLFormatter::escape_xml_str(const char *str) { int len = escape_xml_attr_len(str); std::vector escaped(len, '\0'); escape_xml_attr(str, &escaped[0]); return std::string(&escaped[0]); } } ceph-0.80.11/src/common/safe_io.h0000664000175100017510000000420112623076744020527 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SAFE_IO #define CEPH_SAFE_IO #include "acconfig.h" #include "common/compiler_extensions.h" #include #ifdef __cplusplus extern "C" { #endif /* * Safe functions wrapping the raw read() and write() libc functions. * These retry on EINTR, and on error return -errno instead of returning * -1 and setting errno). */ ssize_t safe_read(int fd, void *buf, size_t count) WARN_UNUSED_RESULT; ssize_t safe_write(int fd, const void *buf, size_t count) WARN_UNUSED_RESULT; ssize_t safe_pread(int fd, void *buf, size_t count, off_t offset) WARN_UNUSED_RESULT; ssize_t safe_pwrite(int fd, const void *buf, size_t count, off_t offset) WARN_UNUSED_RESULT; #ifdef CEPH_HAVE_SPLICE /* * Similar to the above (non-exact version) and below (exact version). * See splice(2) for parameter descriptions. */ ssize_t safe_splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) WARN_UNUSED_RESULT; ssize_t safe_splice_exact(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) WARN_UNUSED_RESULT; #endif /* * Same as the above functions, but return -EDOM unless exactly the requested * number of bytes can be read. */ ssize_t safe_read_exact(int fd, void *buf, size_t count) WARN_UNUSED_RESULT; ssize_t safe_pread_exact(int fd, void *buf, size_t count, off_t offset) WARN_UNUSED_RESULT; /* * Safe functions to read and write an entire file. */ int safe_write_file(const char *base, const char *file, const char *val, size_t vallen); int safe_read_file(const char *base, const char *file, char *val, size_t vallen); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/dout.cc0000664000175100017510000000031112623076744020231 0ustar jenkins-buildjenkins-build #include void dout_emergency(const char * const str) { std::cerr << str; std::cerr.flush(); } void dout_emergency(const std::string &str) { std::cerr << str; std::cerr.flush(); } ceph-0.80.11/src/common/crc32c_intel_fast.h0000664000175100017510000000075712623076744022425 0ustar jenkins-buildjenkins-build#ifndef CEPH_COMMON_CRC32C_INTEL_FAST_H #define CEPH_COMMON_CRC32C_INTEL_FAST_H #ifdef __cplusplus extern "C" { #endif /* is the fast version compiled in */ extern int ceph_crc32c_intel_fast_exists(void); #ifdef __x86_64__ extern uint32_t ceph_crc32c_intel_fast(uint32_t crc, unsigned char const *buffer, unsigned len); #else static inline uint32_t ceph_crc32c_intel_fast(uint32_t crc, unsigned char const *buffer, unsigned len) { return 0; } #endif #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/TrackedOp.cc0000664000175100017510000001616212623076744021145 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * Copyright 2013 Inktank */ #include "TrackedOp.h" #include "common/Formatter.h" #include #include #include "common/debug.h" #include "common/config.h" #include "msg/Message.h" #include "include/assert.h" #define dout_subsys ceph_subsys_optracker #undef dout_prefix #define dout_prefix _prefix(_dout) static ostream& _prefix(std::ostream* _dout) { return *_dout << "-- op tracker -- "; } void OpHistory::on_shutdown() { arrived.clear(); duration.clear(); shutdown = true; } void OpHistory::insert(utime_t now, TrackedOpRef op) { if (shutdown) return; duration.insert(make_pair(op->get_duration(), op)); arrived.insert(make_pair(op->get_arrived(), op)); cleanup(now); } void OpHistory::cleanup(utime_t now) { while (arrived.size() && (now - arrived.begin()->first > (double)(history_duration))) { duration.erase(make_pair( arrived.begin()->second->get_duration(), arrived.begin()->second)); arrived.erase(arrived.begin()); } while (duration.size() > history_size) { arrived.erase(make_pair( duration.begin()->second->get_arrived(), duration.begin()->second)); duration.erase(duration.begin()); } } void OpHistory::dump_ops(utime_t now, Formatter *f) { cleanup(now); f->open_object_section("OpHistory"); f->dump_int("num to keep", history_size); f->dump_int("duration to keep", history_duration); { f->open_array_section("Ops"); for (set >::const_iterator i = arrived.begin(); i != arrived.end(); ++i) { f->open_object_section("Op"); i->second->dump(now, f); f->close_section(); } f->close_section(); } f->close_section(); } void OpTracker::dump_historic_ops(Formatter *f) { Mutex::Locker locker(ops_in_flight_lock); utime_t now = ceph_clock_now(cct); history.dump_ops(now, f); } void OpTracker::dump_ops_in_flight(Formatter *f) { Mutex::Locker locker(ops_in_flight_lock); f->open_object_section("ops_in_flight"); // overall dump f->dump_int("num_ops", ops_in_flight.size()); f->open_array_section("ops"); // list of TrackedOps utime_t now = ceph_clock_now(cct); for (xlist::iterator p = ops_in_flight.begin(); !p.end(); ++p) { f->open_object_section("op"); (*p)->dump(now, f); f->close_section(); // this TrackedOp } f->close_section(); // list of TrackedOps f->close_section(); // overall dump } void OpTracker::register_inflight_op(xlist::item *i) { if (!tracking_enabled) return; Mutex::Locker locker(ops_in_flight_lock); ops_in_flight.push_back(i); ops_in_flight.back()->seq = seq++; } void OpTracker::unregister_inflight_op(TrackedOp *i) { // caller checks; assert(tracking_enabled); Mutex::Locker locker(ops_in_flight_lock); i->request->clear_data(); i->request->clear_payload(); assert(i->xitem.get_list() == &ops_in_flight); utime_t now = ceph_clock_now(cct); i->xitem.remove_myself(); history.insert(now, TrackedOpRef(i)); } bool OpTracker::check_ops_in_flight(std::vector &warning_vector) { Mutex::Locker locker(ops_in_flight_lock); if (!ops_in_flight.size()) // this covers tracking_enabled, too return false; utime_t now = ceph_clock_now(cct); utime_t too_old = now; too_old -= complaint_time; utime_t oldest_secs = now - ops_in_flight.front()->get_arrived(); dout(10) << "ops_in_flight.size: " << ops_in_flight.size() << "; oldest is " << oldest_secs << " seconds old" << dendl; if (oldest_secs < complaint_time) return false; xlist::iterator i = ops_in_flight.begin(); warning_vector.reserve(log_threshold + 1); int slow = 0; // total slow int warned = 0; // total logged while (!i.end() && (*i)->get_arrived() < too_old) { slow++; // exponential backoff of warning intervals if (((*i)->get_arrived() + (complaint_time * (*i)->warn_interval_multiplier)) < now) { // will warn if (warning_vector.empty()) warning_vector.push_back(""); warned++; if (warned > log_threshold) break; utime_t age = now - (*i)->get_arrived(); stringstream ss; ss << "slow request " << age << " seconds old, received at " << (*i)->get_arrived() << ": " << *((*i)->request) << " currently " << ((*i)->current.size() ? (*i)->current : (*i)->state_string()); warning_vector.push_back(ss.str()); // only those that have been shown will backoff (*i)->warn_interval_multiplier *= 2; } ++i; } // only summarize if we warn about any. if everything has backed // off, we will stay silent. if (warned > 0) { stringstream ss; ss << slow << " slow requests, " << warned << " included below; oldest blocked for > " << oldest_secs << " secs"; warning_vector[0] = ss.str(); } return warning_vector.size(); } void OpTracker::get_age_ms_histogram(pow2_hist_t *h) { Mutex::Locker locker(ops_in_flight_lock); h->clear(); utime_t now = ceph_clock_now(NULL); unsigned bin = 30; uint32_t lb = 1 << (bin-1); // lower bound for this bin int count = 0; for (xlist::iterator i = ops_in_flight.begin(); !i.end(); ++i) { utime_t age = now - (*i)->get_arrived(); uint32_t ms = (long)(age * 1000.0); if (ms >= lb) { count++; continue; } if (count) h->set_bin(bin, count); while (lb > ms) { bin--; lb >>= 1; } count = 1; } if (count) h->set_bin(bin, count); } void OpTracker::mark_event(TrackedOp *op, const string &dest) { if (!tracking_enabled) return; utime_t now = ceph_clock_now(cct); return _mark_event(op, dest, now); } void OpTracker::_mark_event(TrackedOp *op, const string &evt, utime_t time) { Mutex::Locker locker(ops_in_flight_lock); dout(5) << //"reqid: " << op->get_reqid() << ", seq: " << op->seq << ", time: " << time << ", event: " << evt << ", request: " << *op->request << dendl; } void OpTracker::RemoveOnDelete::operator()(TrackedOp *op) { if (!tracker->tracking_enabled) { op->request->clear_data(); delete op; return; } op->mark_event("done"); tracker->unregister_inflight_op(op); // Do not delete op, unregister_inflight_op took control } void TrackedOp::mark_event(const string &event) { utime_t now = ceph_clock_now(g_ceph_context); { Mutex::Locker l(lock); events.push_back(make_pair(now, event)); } tracker->mark_event(this, event); _event_marked(); } void TrackedOp::dump(utime_t now, Formatter *f) const { Message *m = request; stringstream name; m->print(name); f->dump_string("description", name.str().c_str()); // this TrackedOp f->dump_stream("received_at") << get_arrived(); f->dump_float("age", now - get_arrived()); f->dump_float("duration", get_duration()); { f->open_array_section("type_data"); _dump(now, f); f->close_section(); } } ceph-0.80.11/src/common/likely.h0000664000175100017510000000112112623076744020411 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIKELY_DOT_H #define CEPH_LIKELY_DOT_H /* * Likely / Unlikely macros */ #define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) #endif ceph-0.80.11/src/common/blkdev.h0000664000175100017510000000020112623076744020365 0ustar jenkins-buildjenkins-build#ifndef __CEPH_COMMON_BLKDEV_H #define __CEPH_COMMON_BLKDEV_H extern int get_block_device_size(int fd, int64_t *psize); #endif ceph-0.80.11/src/common/PrebufferedStreambuf.h0000664000175100017510000000214212623076744023226 0ustar jenkins-buildjenkins-build#ifndef CEPH_COMMON_PREBUFFEREDSTREAMBUF_H #define CEPH_COMMON_PREBUFFEREDSTREAMBUF_H #include #include #include /** * streambuf using existing buffer, overflowing into a std::string * * A simple streambuf that uses a preallocated buffer for small * strings, and overflows into a std::string when necessary. If the * preallocated buffer size is chosen well, we can optimize for the * common case and overflow to a slower heap-allocated buffer when * necessary. */ class PrebufferedStreambuf : public std::basic_streambuf::traits_type> { char *m_buf; size_t m_buf_len; std::string m_overflow; typedef std::char_traits traits_ty; typedef traits_ty::int_type int_type; typedef traits_ty::pos_type pos_type; typedef traits_ty::off_type off_type; public: PrebufferedStreambuf(char *buf, size_t len); // called when the buffer fills up int_type overflow(int_type c); // called when we read and need more data int_type underflow(); /// return a string copy (inefficiently) std::string get_str() const; }; #endif ceph-0.80.11/src/common/TextTable.h0000664000175100017510000000767612623076744021041 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "include/assert.h" /** * TextTable: * Manage tabular output of data. Caller defines heading of each column * and alignment of heading and column data, * then inserts rows of data including tuples of * length (ncolumns) terminated by TextTable::endrow. When all rows * are inserted, caller asks for output with ostream << * which sizes/pads/dumps the table to ostream. * * Columns autosize to largest heading or datum. One space is printed * between columns. */ class TextTable { public: enum Align {LEFT = 1, CENTER, RIGHT}; private: struct TextTableColumn { std::string heading; int width; Align hd_align; Align col_align; TextTableColumn() {}; TextTableColumn(std::string h, int w, Align ha, Align ca) : heading(h), width(w), hd_align(ha), col_align(ca) { } ~TextTableColumn() {} }; std::vector col; // column definitions std::vector > row; // row data array unsigned int curcol, currow; // col, row being inserted into unsigned int indent; // indent width when rendering public: TextTable(): curcol(0), currow(0), indent(0) {} ~TextTable() {} /** * Define a column in the table. * * @param heading Column heading string (or "") * @param hd_align Alignment for heading in column * @param col_align Data alignment * * @note alignment is of type TextTable::Align; values are * TextTable::LEFT, TextTable::CENTER, or TextTable::RIGHT * */ void define_column(const std::string& heading, Align hd_align, Align col_align); /** * Set indent for table. Only affects table output. * * @param i Number of spaces to indent */ void set_indent(int i) { indent = i; } /** * Add item to table, perhaps on new row. * table << val1 << val2 << TextTable::endrow; * * @param: value to output. * * @note: Numerics are output in decimal; strings are not truncated. * Output formatting choice is limited to alignment in define_column(). * * @return TextTable& for chaining. */ template TextTable& operator<<(const T& item) { if (row.size() < currow + 1) row.resize(currow + 1); /** * col.size() is a good guess for how big row[currow] needs to be, * so just expand it out now */ if (row[currow].size() < col.size()) { row[currow].resize(col.size()); } // inserting more items than defined columns is a coding error assert(curcol + 1 <= col.size()); // get rendered width of item alone std::ostringstream oss; oss << item; int width = oss.str().length(); oss.seekp(0); // expand column width if necessary if (width > col[curcol].width) { col[curcol].width = width; } // now store the rendered item with its proper width oss << std::setw(width) << item; row[currow][curcol] = oss.str(); curcol++; return *this; } /** * Degenerate type/variable here is just to allow selection of the * following operator<< for "<< TextTable::endrow" */ struct endrow_t {}; static endrow_t endrow; /** * Implements TextTable::endrow */ TextTable &operator<<(endrow_t) { curcol = 0; currow++; return *this; } /** * Render table to ostream (i.e. cout << table) */ friend std::ostream &operator<<(std::ostream& out, TextTable &t); /** * clear: Reset everything in a TextTable except column defs * resize cols to heading widths, clear indent */ void clear(); }; ceph-0.80.11/src/common/lockdep.h0000664000175100017510000000160312623076744020546 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2008-2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LOCKDEP_H #define CEPH_LOCKDEP_H class CephContext; extern int g_lockdep; extern void lockdep_register_ceph_context(CephContext *cct); extern void lockdep_unregister_ceph_context(CephContext *cct); extern int lockdep_register(const char *n); extern int lockdep_will_lock(const char *n, int id); extern int lockdep_locked(const char *n, int id, bool force_backtrace=false); extern int lockdep_will_unlock(const char *n, int id); extern int lockdep_dump_locks(); #endif ceph-0.80.11/src/common/admin_socket.h0000664000175100017510000000546012623076744021572 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_ADMIN_SOCKET_H #define CEPH_COMMON_ADMIN_SOCKET_H #include "common/Thread.h" #include "common/Mutex.h" #include #include #include "include/buffer.h" #include "common/cmdparse.h" class AdminSocket; class CephContext; #define CEPH_ADMIN_SOCK_VERSION "2" class AdminSocketHook { public: virtual bool call(std::string command, cmdmap_t &cmdmap, std::string format, bufferlist& out) = 0; virtual ~AdminSocketHook() {}; }; class AdminSocket : public Thread { public: AdminSocket(CephContext *cct); virtual ~AdminSocket(); /** * register an admin socket command * * The command is registered under a command string. Incoming * commands are split by space and matched against the longest * registered command. For example, if 'foo' and 'foo bar' are * registered, and an incoming command is 'foo bar baz', it is * matched with 'foo bar', while 'foo fud' will match 'foo'. * * The entire incoming command string is passed to the registred * hook. * * @param command command string * @param cmddesc command syntax descriptor * @param hook implementaiton * @param help help text. if empty, command will not be included in 'help' output. * * @return 0 for success, -EEXIST if command already registered. */ int register_command(std::string command, std::string cmddesc, AdminSocketHook *hook, std::string help); /** * unregister an admin socket command * * @param command command string * @return 0 on succest, -ENOENT if command dne. */ int unregister_command(std::string command); bool init(const std::string &path); private: AdminSocket(const AdminSocket& rhs); AdminSocket& operator=(const AdminSocket &rhs); void shutdown(); std::string create_shutdown_pipe(int *pipe_rd, int *pipe_wr); std::string destroy_shutdown_pipe(); std::string bind_and_listen(const std::string &sock_path, int *fd); void *entry(); bool do_accept(); CephContext *m_cct; std::string m_path; int m_sock_fd; int m_shutdown_rd_fd; int m_shutdown_wr_fd; Mutex m_lock; // protects m_hooks, m_descs, m_help AdminSocketHook *m_version_hook, *m_help_hook, *m_getdescs_hook; std::map m_hooks; std::map m_descs; std::map m_help; friend class AdminSocketTest; friend class HelpHook; friend class GetdescsHook; }; #endif ceph-0.80.11/src/common/version.h0000664000175100017510000000141612623076744020614 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_VERSION_H #define CEPH_COMMON_VERSION_H #include // Return a string describing the Ceph version const char *ceph_version_to_str(void); // Return a string describing the git version const char *git_version_to_str(void); // Return a formatted string describing the ceph and git versions std::string const pretty_version_to_str(void); #endif ceph-0.80.11/src/common/PrebufferedStreambuf.cc0000664000175100017510000000342012623076744023364 0ustar jenkins-buildjenkins-build #include "common/PrebufferedStreambuf.h" PrebufferedStreambuf::PrebufferedStreambuf(char *buf, size_t len) : m_buf(buf), m_buf_len(len) { // init output buffer this->setp(m_buf, m_buf + m_buf_len); // so we underflow on first read this->setg(0, 0, 0); } PrebufferedStreambuf::int_type PrebufferedStreambuf::overflow(int_type c) { int old_len = m_overflow.size(); if (old_len == 0) { m_overflow.resize(m_buf_len); } else { m_overflow.resize(old_len * 2); } m_overflow[old_len] = c; this->setp(&m_overflow[old_len + 1], &*m_overflow.begin() + m_overflow.size()); return std::char_traits::not_eof(c); } PrebufferedStreambuf::int_type PrebufferedStreambuf::underflow() { if (this->gptr() == 0) { // first read; start with the static buffer if (m_overflow.size()) // there is overflow, so start with entire prealloc buffer this->setg(m_buf, m_buf, m_buf + m_buf_len); else if (this->pptr() == m_buf) // m_buf is empty return traits_ty::eof(); // no data else // set up portion of m_buf we've filled this->setg(m_buf, m_buf, this->pptr()); return *this->gptr(); } if (this->gptr() == m_buf + m_buf_len && m_overflow.size()) { // at end of m_buf; continue with the overflow string this->setg(&m_overflow[0], &m_overflow[0], this->pptr()); return *this->gptr(); } // otherwise we must be at the end (of m_buf and/or m_overflow) return traits_ty::eof(); } std::string PrebufferedStreambuf::get_str() const { if (m_overflow.size()) { std::string s(m_buf, m_buf + m_buf_len); s.append(&m_overflow[0], this->pptr() - &m_overflow[0]); return s; } else if (this->pptr() == m_buf) { return std::string(); } else { return std::string(m_buf, this->pptr() - m_buf); } } ceph-0.80.11/src/common/random_cache.hpp0000664000175100017510000000622112623076744022071 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 UnitedStack * * Author: Haomai Wang * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RANDOMCACHE_H #define CEPH_RANDOMCACHE_H #include "common/Mutex.h" #include "include/compat.h" #include "include/unordered_map.h" // Although This is a ramdom cache implementation, here still consider to make // the trim progress more reasonable. Each item owns its lookup frequency, // when the cache is full it will randomly pick up several items and compare the // frequency associated with. The least frequency of items will be evicted. template class RandomCache { // The first element of pair is the frequency of item, it's used to evict item ceph::unordered_map > contents; Mutex lock; uint64_t max_size; K last_trim_key; // When cache reach full, consider to evict a certain number of items static const uint64_t EVICT_COUNT = 5; // Avoid too much overhead on comparing items's frequency, the number of // compare items is expected to small. static const uint64_t COMPARE_COUNT = 3; // In order to make evict cache progress more lightweight and effective, // several items are expected to evicted in one call void trim_cache(uint64_t evict_count) { typename ceph::unordered_map >::iterator it = contents.find(last_trim_key); uint64_t total_compare = evict_count * COMPARE_COUNT; map candidates; while (total_compare--) { if (it == contents.end()) { it = contents.begin(); } candidates[it->second.first] = it->first; it++; } if (it != contents.end()) last_trim_key = it->first; else last_trim_key = contents.begin()->first; for (typename map::iterator j = candidates.begin(); j != candidates.end(); j++) { contents.erase(j->second); evict_count--; if (!evict_count) break; } } public: RandomCache(size_t max_size=20) : lock("RandomCache::lock"), max_size(max_size) {} ~RandomCache() { contents.clear(); } void clear(K key) { Mutex::Locker l(lock); contents.erase(key); } void set_size(size_t new_size) { Mutex::Locker l(lock); max_size = new_size; if (max_size <= contents.size()) { trim_cache(contents.size() - max_size); } } bool lookup(K key, V *out) { Mutex::Locker l(lock); typename ceph::unordered_map >::iterator it = contents.find(key); if (it != contents.end()) { it->second.first++; *out = it->second.second; return true; } return false; } void add(K key, V value) { Mutex::Locker l(lock); if (max_size <= contents.size()) { trim_cache(EVICT_COUNT); } contents[key] = make_pair(1, value); } }; #endif ceph-0.80.11/src/common/map_cacher.hpp0000664000175100017510000001207412623076744021553 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef MAPCACHER_H #define MAPCACHER_H #include #include #include "include/memory.h" #include #include #include #include #include #include "include/Context.h" #include "common/sharedptr_registry.hpp" namespace MapCacher { /** * Abstraction for ordering key updates */ template class Transaction { public: /// Set keys according to map virtual void set_keys( const std::map &keys ///< [in] keys/values to set ) = 0; /// Remove keys virtual void remove_keys( const std::set &to_remove ///< [in] keys to remove ) = 0; /// Add context to fire when data is readable virtual void add_callback( Context *c ///< [in] Context to fire on readable ) = 0; virtual ~Transaction() {} }; /** * Abstraction for fetching keys */ template class StoreDriver { public: /// Returns requested key values virtual int get_keys( const std::set &keys, ///< [in] keys requested std::map *got ///< [out] values for keys obtained ) = 0; ///< @return error value /// Returns next key virtual int get_next( const K &key, ///< [in] key after which to get next pair *next ///< [out] first key after key ) = 0; ///< @return 0 on success, -ENOENT if there is no next virtual ~StoreDriver() {} }; /** * Uses SharedPtrRegistry to cache objects of in progress writes * allowing the user to read/write a consistent view of the map * without flushing writes. */ template class MapCacher { private: StoreDriver *driver; SharedPtrRegistry > in_progress; typedef typename SharedPtrRegistry >::VPtr VPtr; typedef ContainerContext > TransHolder; public: MapCacher(StoreDriver *driver) : driver(driver) {} /// Fetch first key/value pair after specified key int get_next( K key, ///< [in] key after which to get next pair *next ///< [out] next key ) { while (true) { pair > cached; pair store; bool got_cached = in_progress.get_next(key, &cached); bool got_store = false; int r = driver->get_next(key, &store); if (r < 0 && r != -ENOENT) { return r; } else if (r == 0) { got_store = true; } if (!got_cached && !got_store) { return -ENOENT; } else if ( got_cached && (!got_store || store.first >= cached.first)) { if (cached.second) { if (next) *next = make_pair(cached.first, cached.second.get()); return 0; } else { key = cached.first; continue; // value was cached as removed, recurse } } else { if (next) *next = store; return 0; } } assert(0); // not reachable return -EINVAL; } ///< @return error value, 0 on success, -ENOENT if no more entries /// Adds operation setting keys to Transaction void set_keys( const map &keys, ///< [in] keys/values to set Transaction *t ///< [out] transaction to use ) { std::set vptrs; for (typename map::const_iterator i = keys.begin(); i != keys.end(); ++i) { VPtr ip = in_progress.lookup_or_create(i->first, i->second); *ip = i->second; vptrs.insert(ip); } t->set_keys(keys); t->add_callback(new TransHolder(vptrs)); } /// Adds operation removing keys to Transaction void remove_keys( const set &keys, ///< [in] Transaction *t ///< [out] transaction to use ) { std::set vptrs; for (typename set::const_iterator i = keys.begin(); i != keys.end(); ++i) { boost::optional empty; VPtr ip = in_progress.lookup_or_create(*i, empty); *ip = empty; vptrs.insert(ip); } t->remove_keys(keys); t->add_callback(new TransHolder(vptrs)); } /// Gets keys, uses cached values for unstable keys int get_keys( const set &keys_to_get, ///< [in] set of keys to fetch map *got ///< [out] keys gotten ) { set to_get; map _got; for (typename set::const_iterator i = keys_to_get.begin(); i != keys_to_get.end(); ++i) { VPtr val = in_progress.lookup(*i); if (val) { if (*val) got->insert(make_pair(*i, val->get())); //else: value cached is empty, key doesn't exist } else { to_get.insert(*i); } } int r = driver->get_keys(to_get, &_got); if (r < 0) return r; for (typename map::iterator i = _got.begin(); i != _got.end(); ++i) { got->insert(*i); } return 0; } ///< @return error value, 0 on success }; }; // namespace #endif ceph-0.80.11/src/common/RWLock.h0000664000175100017510000000532512623076744020273 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RWLock_Posix__H #define CEPH_RWLock_Posix__H #include #include "lockdep.h" #include "include/assert.h" #include "include/atomic.h" class RWLock { mutable pthread_rwlock_t L; const char *name; mutable int id; mutable ceph::atomic_t nrlock, nwlock; public: RWLock(const RWLock& other); const RWLock& operator=(const RWLock& other); RWLock(const char *n) : name(n), id(-1), nrlock(0), nwlock(0) { pthread_rwlock_init(&L, NULL); if (g_lockdep) id = lockdep_register(name); } bool is_locked() const { return (nrlock.read() > 0) || (nwlock.read() > 0); } bool is_wlocked() const { return (nwlock.read() > 0); } virtual ~RWLock() { // The following check is racy but we are about to destroy // the object and we assume that there are no other users. assert(!is_locked()); pthread_rwlock_destroy(&L); } void unlock() const { if (nwlock.read() > 0) { nwlock.dec(); } else { nrlock.dec(); } if (g_lockdep) id = lockdep_will_unlock(name, id); pthread_rwlock_unlock(&L); } // read void get_read() const { if (g_lockdep) id = lockdep_will_lock(name, id); pthread_rwlock_rdlock(&L); if (g_lockdep) id = lockdep_locked(name, id); nrlock.inc(); } bool try_get_read() const { if (pthread_rwlock_tryrdlock(&L) == 0) { nrlock.inc(); if (g_lockdep) id = lockdep_locked(name, id); return true; } return false; } void put_read() const { unlock(); } // write void get_write() { if (g_lockdep) id = lockdep_will_lock(name, id); pthread_rwlock_wrlock(&L); if (g_lockdep) id = lockdep_locked(name, id); nwlock.inc(); } bool try_get_write() { if (pthread_rwlock_trywrlock(&L) == 0) { if (g_lockdep) id = lockdep_locked(name, id); nwlock.inc(); return true; } return false; } void put_write() { unlock(); } public: class RLocker { const RWLock &m_lock; public: RLocker(const RWLock& lock) : m_lock(lock) { m_lock.get_read(); } ~RLocker() { m_lock.put_read(); } }; class WLocker { RWLock &m_lock; public: WLocker(RWLock& lock) : m_lock(lock) { m_lock.get_write(); } ~WLocker() { m_lock.put_write(); } }; }; #endif // !_Mutex_Posix_ ceph-0.80.11/src/common/admin_socket_client.cc0000664000175100017510000001066312623076744023267 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "common/admin_socket.h" #include "common/ceph_context.h" #include "common/errno.h" #include "common/safe_io.h" #include "common/admin_socket_client.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using std::ostringstream; const char* get_rand_socket_path() { static char *g_socket_path = NULL; if (g_socket_path == NULL) { char buf[512]; const char *tdir = getenv("TMPDIR"); if (tdir == NULL) { tdir = "/tmp"; } snprintf(buf, sizeof(((struct sockaddr_un*)0)->sun_path), "%s/perfcounters_test_socket.%ld.%ld", tdir, (long int)getpid(), time(NULL)); g_socket_path = (char*)strdup(buf); } return g_socket_path; } static std::string asok_connect(const std::string &path, int *fd) { int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); if(socket_fd < 0) { int err = errno; ostringstream oss; oss << "socket(PF_UNIX, SOCK_STREAM, 0) failed: " << cpp_strerror(err); return oss.str(); } struct sockaddr_un address; memset(&address, 0, sizeof(struct sockaddr_un)); address.sun_family = AF_UNIX; snprintf(address.sun_path, sizeof(address.sun_path), "%s", path.c_str()); if (::connect(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) { int err = errno; ostringstream oss; oss << "connect(" << socket_fd << ") failed: " << cpp_strerror(err); close(socket_fd); return oss.str(); } struct timeval timer; timer.tv_sec = 5; timer.tv_usec = 0; if (::setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer))) { int err = errno; ostringstream oss; oss << "setsockopt(" << socket_fd << ", SO_RCVTIMEO) failed: " << cpp_strerror(err); close(socket_fd); return oss.str(); } timer.tv_sec = 5; timer.tv_usec = 0; if (::setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &timer, sizeof(timer))) { int err = errno; ostringstream oss; oss << "setsockopt(" << socket_fd << ", SO_SNDTIMEO) failed: " << cpp_strerror(err); close(socket_fd); return oss.str(); } *fd = socket_fd; return ""; } static std::string asok_request(int socket_fd, std::string request) { ssize_t res = safe_write(socket_fd, request.c_str(), request.length() + 1); if (res < 0) { int err = res; ostringstream oss; oss << "safe_write(" << socket_fd << ") failed to write request code: " << cpp_strerror(err); return oss.str(); } return ""; } AdminSocketClient:: AdminSocketClient(const std::string &path) : m_path(path) { } std::string AdminSocketClient::ping(bool *ok) { std::string version; std::string result = do_request("{\"prefix\":\"0\"}", &version); *ok = result == "" && version.length() == 1; return result; } std::string AdminSocketClient::do_request(std::string request, std::string *result) { int socket_fd = 0, res; std::vector vec(65536, 0); uint8_t *buffer = &vec[0]; uint32_t message_size_raw, message_size; std::string err = asok_connect(m_path, &socket_fd); if (!err.empty()) { goto out; } err = asok_request(socket_fd, request); if (!err.empty()) { goto done; } res = safe_read_exact(socket_fd, &message_size_raw, sizeof(message_size_raw)); if (res < 0) { int e = res; ostringstream oss; oss << "safe_read(" << socket_fd << ") failed to read message size: " << cpp_strerror(e); err = oss.str(); goto done; } message_size = ntohl(message_size_raw); res = safe_read_exact(socket_fd, buffer, message_size); if (res < 0) { int e = res; ostringstream oss; oss << "safe_read(" << socket_fd << ") failed: " << cpp_strerror(e); err = oss.str(); goto done; } //printf("MESSAGE FROM SERVER: %s\n", buffer); result->assign((const char*)buffer); done: close(socket_fd); out: return err; } ceph-0.80.11/src/common/MemoryModel.cc0000664000175100017510000000465012623076744021521 0ustar jenkins-buildjenkins-build #include "include/types.h" #include "MemoryModel.h" #include "common/config.h" #include "debug.h" #include #define dout_subsys ceph_subsys_ MemoryModel::MemoryModel(CephContext *cct_) : cct(cct_) { } void MemoryModel::_sample(snap *psnap) { ifstream f; f.open("/proc/self/status"); if (!f.is_open()) { ldout(cct, 0) << "check_memory_usage unable to open /proc/self/status" << dendl; return; } while (!f.eof()) { string line; getline(f, line); if (strncmp(line.c_str(), "VmSize:", 7) == 0) psnap->size = atoi(line.c_str() + 7); else if (strncmp(line.c_str(), "VmRSS:", 6) == 0) psnap->rss = atoi(line.c_str() + 7); else if (strncmp(line.c_str(), "VmHWM:", 6) == 0) psnap->hwm = atoi(line.c_str() + 7); else if (strncmp(line.c_str(), "VmLib:", 6) == 0) psnap->lib = atoi(line.c_str() + 7); else if (strncmp(line.c_str(), "VmPeak:", 7) == 0) psnap->peak = atoi(line.c_str() + 7); else if (strncmp(line.c_str(), "VmData:", 7) == 0) psnap->data = atoi(line.c_str() + 7); } f.close(); f.open("/proc/self/maps"); if (!f.is_open()) { ldout(cct, 0) << "check_memory_usage unable to open /proc/self/maps" << dendl; return; } int heap = 0; while (f.is_open() && !f.eof()) { string line; getline(f, line); //ldout(cct, 0) << "line is " << line << dendl; const char *start = line.c_str(); const char *dash = start; while (*dash && *dash != '-') dash++; if (!*dash) continue; const char *end = dash + 1; while (*end && *end != ' ') end++; if (!*end) continue; unsigned long long as = strtoll(start, 0, 16); unsigned long long ae = strtoll(dash+1, 0, 16); //ldout(cct, 0) << std::hex << as << " to " << ae << std::dec << dendl; end++; const char *mode = end; int skip = 4; while (skip--) { end++; while (*end && *end != ' ') end++; } if (*end) end++; int size = ae - as; //ldout(cct, 0) << "size " << size << " mode is '" << mode << "' end is '" << end << "'" << dendl; /* * anything 'rw' and anon is assumed to be heap. */ if (mode[0] == 'r' && mode[1] == 'w' && !*end) heap += size; } psnap->heap = heap >> 10; // ... #if defined(__linux__) struct mallinfo mi = mallinfo(); psnap->malloc = mi.uordblks >> 10; psnap->mmap = mi.hblks >> 10; #else #warning "mallinfo not implemented" #endif } ceph-0.80.11/src/common/run_cmd.h0000664000175100017510000000154112623076744020555 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_RUN_CMD_H #define CEPH_COMMON_RUN_CMD_H #include // // Fork a command and run it. The shell will not be invoked and shell // expansions will not be done. // This function takes a variable number of arguments. The last argument must // be NULL. // // Example: // run_cmd("rm", "-rf", "foo", NULL) // // Returns an empty string on success, and an error string otherwise. // std::string run_cmd(const char *cmd, ...); #endif ceph-0.80.11/src/common/escape.c0000664000175100017510000001000212623076744020351 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/escape.h" #include #include /* * Some functions for escaping RGW responses */ /* Static string length */ #define SSTRL(x) ((sizeof(x)/sizeof(x[0])) - 1) #define LESS_THAN_XESCAPE "<" #define AMPERSAND_XESCAPE "&" #define GREATER_THAN_XESCAPE ">" #define SGL_QUOTE_XESCAPE "'" #define DBL_QUOTE_XESCAPE """ int escape_xml_attr_len(const char *buf) { const char *b; int ret = 0; for (b = buf; *b; ++b) { unsigned char c = *b; switch (c) { case '<': ret += SSTRL(LESS_THAN_XESCAPE); break; case '&': ret += SSTRL(AMPERSAND_XESCAPE); break; case '>': ret += SSTRL(GREATER_THAN_XESCAPE); break; case '\'': ret += SSTRL(SGL_QUOTE_XESCAPE); break; case '"': ret += SSTRL(DBL_QUOTE_XESCAPE); break; default: // Escape control characters. if (((c < 0x20) && (c != 0x09) && (c != 0x0a)) || (c == 0x7f)) { ret += 6; } else { ret++; } } } // leave room for null terminator ret++; return ret; } void escape_xml_attr(const char *buf, char *out) { char *o = out; const char *b; for (b = buf; *b; ++b) { unsigned char c = *b; switch (c) { case '<': memcpy(o, LESS_THAN_XESCAPE, SSTRL(LESS_THAN_XESCAPE)); o += SSTRL(LESS_THAN_XESCAPE); break; case '&': memcpy(o, AMPERSAND_XESCAPE, SSTRL(AMPERSAND_XESCAPE)); o += SSTRL(AMPERSAND_XESCAPE); break; case '>': memcpy(o, GREATER_THAN_XESCAPE, SSTRL(GREATER_THAN_XESCAPE)); o += SSTRL(GREATER_THAN_XESCAPE); break; case '\'': memcpy(o, SGL_QUOTE_XESCAPE, SSTRL(SGL_QUOTE_XESCAPE)); o += SSTRL(SGL_QUOTE_XESCAPE); break; case '"': memcpy(o, DBL_QUOTE_XESCAPE, SSTRL(DBL_QUOTE_XESCAPE)); o += SSTRL(DBL_QUOTE_XESCAPE); break; default: // Escape control characters. if (((c < 0x20) && (c != 0x09) && (c != 0x0a)) || (c == 0x7f)) { snprintf(o, 7, "&#x%02x;", c); o += 6; } else { *o++ = c; } break; } } // null terminator *o = '\0'; } #define DBL_QUOTE_JESCAPE "\\\"" #define BACKSLASH_JESCAPE "\\\\" #define SLASH_JESCAPE "\\/" #define TAB_JESCAPE "\\t" #define NEWLINE_JESCAPE "\\n" int escape_json_attr_len(const char *buf) { const char *b; int ret = 0; for (b = buf; *b; ++b) { unsigned char c = *b; switch (c) { case '"': ret += SSTRL(DBL_QUOTE_JESCAPE); break; case '\\': ret += SSTRL(BACKSLASH_JESCAPE); break; case '/': ret += SSTRL(SLASH_JESCAPE); break; case '\t': ret += SSTRL(TAB_JESCAPE); break; case '\n': ret += SSTRL(NEWLINE_JESCAPE); break; default: // Escape control characters. if ((c < 0x20) || (c == 0x7f)) { ret += 6; } else { ret++; } } } // leave room for null terminator ret++; return ret; } void escape_json_attr(const char *buf, char *out) { char *o = out; const char *b; for (b = buf; *b; ++b) { unsigned char c = *b; switch (c) { case '"': memcpy(o, DBL_QUOTE_JESCAPE, SSTRL(DBL_QUOTE_JESCAPE)); o += SSTRL(DBL_QUOTE_JESCAPE); break; case '\\': memcpy(o, BACKSLASH_JESCAPE, SSTRL(BACKSLASH_JESCAPE)); o += SSTRL(BACKSLASH_JESCAPE); break; case '/': memcpy(o, SLASH_JESCAPE, SSTRL(SLASH_JESCAPE)); o += SSTRL(SLASH_JESCAPE); break; case '\t': memcpy(o, TAB_JESCAPE, SSTRL(TAB_JESCAPE)); o += SSTRL(TAB_JESCAPE); break; case '\n': memcpy(o, NEWLINE_JESCAPE, SSTRL(NEWLINE_JESCAPE)); o += SSTRL(NEWLINE_JESCAPE); break; default: // Escape control characters. if ((c < 0x20) || (c == 0x7f)) { snprintf(o, 7, "\\u%04x", c); o += 6; } else { *o++ = c; } break; } } // null terminator *o = '\0'; } ceph-0.80.11/src/common/ConfUtils.h0000664000175100017510000000532312623076744021036 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CONFUTILS_H #define CEPH_CONFUTILS_H #include #include #include #include #include "include/buffer.h" /* * Ceph configuration file support. * * This class loads an INI-style configuration from a file or bufferlist, and * holds it in memory. In general, an INI configuration file is composed of * sections, which contain key/value pairs. You can put comments on the end of * lines by using either a hash mark (#) or the semicolon (;). * * You can get information out of ConfFile by calling get_key or by examining * individual sections. * * This class could be extended to support modifying configuration files and * writing them back out without too much difficulty. Currently, this is not * implemented, and the file is read-only. */ class ConfLine { public: ConfLine(const std::string &key_, const std::string val_, const std::string newsection_, const std::string comment_, int line_no_); bool operator<(const ConfLine &rhs) const; friend std::ostream &operator<<(std::ostream& oss, const ConfLine &l); std::string key, val, newsection; }; class ConfSection { public: typedef std::set ::const_iterator const_line_iter_t; std::set lines; }; class ConfFile { public: typedef std::map ::iterator section_iter_t; typedef std::map ::const_iterator const_section_iter_t; ConfFile(); ~ConfFile(); void clear(); int parse_file(const std::string &fname, std::deque *errors, std::ostream *warnings); int parse_bufferlist(ceph::bufferlist *bl, std::deque *errors, std::ostream *warnings); int read(const std::string §ion, const std::string &key, std::string &val) const; const_section_iter_t sections_begin() const; const_section_iter_t sections_end() const; static void trim_whitespace(std::string &str, bool strip_internal); static std::string normalize_key_name(const std::string &key); friend std::ostream &operator<<(std::ostream &oss, const ConfFile &cf); private: void load_from_buffer(const char *buf, size_t sz, std::deque *errors, std::ostream *warnings); static ConfLine* process_line(int line_no, const char *line, std::deque *errors); std::map sections; }; #endif ceph-0.80.11/src/common/AsyncReserver.h0000664000175100017510000000622312623076744021723 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef ASYNC_RESERVER_H #define ASYNC_RESERVER_H #include #include #include #include "common/Mutex.h" #include "common/Finisher.h" /** * Manages a configurable number of asyncronous reservations. * * Memory usage is linear with the number of items queued and * linear with respect to the total number of priorities used * over all time. */ template class AsyncReserver { Finisher *f; unsigned max_allowed; Mutex lock; map > > queues; map >::iterator > > queue_pointers; set in_progress; void do_queues() { typename map > >::reverse_iterator it; for (it = queues.rbegin(); it != queues.rend() && in_progress.size() < max_allowed; ++it) { while (in_progress.size() < max_allowed && !it->second.empty()) { pair p = it->second.front(); queue_pointers.erase(p.first); it->second.pop_front(); f->queue(p.second); in_progress.insert(p.first); } } } public: AsyncReserver( Finisher *f, unsigned max_allowed) : f(f), max_allowed(max_allowed), lock("AsyncReserver::lock") {} void set_max(unsigned max) { Mutex::Locker l(lock); max_allowed = max; do_queues(); } /** * Requests a reservation * * Note, on_reserved may be called following cancel_reservation. Thus, * the callback must be safe in that case. Callback will be called * with no locks held. cancel_reservation must be called to release the * reservation slot. */ void request_reservation( T item, ///< [in] reservation key Context *on_reserved, ///< [in] callback to be called on reservation unsigned prio ) { Mutex::Locker l(lock); assert(!queue_pointers.count(item) && !in_progress.count(item)); queues[prio].push_back(make_pair(item, on_reserved)); queue_pointers.insert(make_pair(item, make_pair(prio,--(queues[prio]).end()))); do_queues(); } /** * Cancels reservation * * Frees the reservation under key for use. * Note, after cancel_reservation, the reservation_callback may or * may not still be called. */ void cancel_reservation( T item ///< [in] key for reservation to cancel ) { Mutex::Locker l(lock); if (queue_pointers.count(item)) { unsigned prio = queue_pointers[item].first; delete queue_pointers[item].second->second; queues[prio].erase(queue_pointers[item].second); queue_pointers.erase(item); } else { in_progress.erase(item); } do_queues(); } static const unsigned MAX_PRIORITY = (unsigned)-1; }; #endif ceph-0.80.11/src/common/Mutex.cc0000664000175100017510000000575112623076744020375 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "common/Mutex.h" #include "common/perf_counters.h" #include "common/ceph_context.h" #include "common/config.h" #include "include/utime.h" #include "common/Clock.h" Mutex::Mutex(const char *n, bool r, bool ld, bool bt, CephContext *cct) : name(n), id(-1), recursive(r), lockdep(ld), backtrace(bt), nlock(0), locked_by(0), cct(cct), logger(0) { if (cct) { PerfCountersBuilder b(cct, string("mutex-") + name, l_mutex_first, l_mutex_last); b.add_time_avg(l_mutex_wait, "wait"); logger = b.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); logger->set(l_mutex_wait, 0); } if (recursive) { // Mutexes of type PTHREAD_MUTEX_RECURSIVE do all the same checks as // mutexes of type PTHREAD_MUTEX_ERRORCHECK. pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&_m,&attr); pthread_mutexattr_destroy(&attr); if (g_lockdep) _register(); } else if (lockdep) { // If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error checking // shall be provided. If a thread attempts to relock a mutex that it // has already locked, an error shall be returned. If a thread // attempts to unlock a mutex that it has not locked or a mutex which // is unlocked, an error shall be returned. pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); pthread_mutex_init(&_m, &attr); pthread_mutexattr_destroy(&attr); if (g_lockdep) _register(); } else { // If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock detection // shall not be provided. Attempting to relock the mutex causes // deadlock. If a thread attempts to unlock a mutex that it has not // locked or a mutex which is unlocked, undefined behavior results. pthread_mutex_init(&_m, NULL); } } Mutex::~Mutex() { assert(nlock == 0); pthread_mutex_destroy(&_m); if (cct && logger) { cct->get_perfcounters_collection()->remove(logger); delete logger; } } void Mutex::Lock(bool no_lockdep) { if (lockdep && g_lockdep && !no_lockdep) _will_lock(); if (TryLock()) { return; } utime_t start; if (logger && cct && cct->_conf->mutex_perf_counter) start = ceph_clock_now(cct); int r = pthread_mutex_lock(&_m); if (logger && cct && cct->_conf->mutex_perf_counter) logger->tinc(l_mutex_wait, ceph_clock_now(cct) - start); assert(r == 0); if (lockdep && g_lockdep) _locked(); _post_lock(); } ceph-0.80.11/src/common/hobject.h0000664000175100017510000002143512623076744020550 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef __CEPH_OS_HOBJECT_H #define __CEPH_OS_HOBJECT_H #include #include "include/types.h" #include "include/object.h" #include "include/cmp.h" #include "json_spirit/json_spirit_value.h" #include "include/assert.h" // spirit clobbers it! typedef uint64_t filestore_hobject_key_t; namespace ceph { class Formatter; } struct hobject_t { object_t oid; snapid_t snap; uint32_t hash; private: bool max; static const int64_t POOL_IS_TEMP = -1; public: int64_t pool; string nspace; private: string key; public: const string &get_key() const { return key; } string to_str() const; static bool match_hash(uint32_t to_check, uint32_t bits, uint32_t match) { return (match & ~((~0)<hash hobject_t get_boundary() const { if (is_max()) return *this; hobject_t ret; ret.hash = hash; return ret; } /// @return head version of this hobject_t hobject_t get_head() const { hobject_t ret(*this); ret.snap = CEPH_NOSNAP; return ret; } /// @return snapdir version of this hobject_t hobject_t get_snapdir() const { hobject_t ret(*this); ret.snap = CEPH_SNAPDIR; return ret; } /// @return true if object is snapdir bool is_snapdir() const { return snap == CEPH_SNAPDIR; } /// @return true if object is head bool is_head() const { return snap == CEPH_NOSNAP; } /// @return true if object is neither head nor snapdir bool is_snap() const { return (snap != CEPH_NOSNAP) && (snap != CEPH_SNAPDIR); } /// @return true iff the object should have a snapset in it's attrs bool has_snapset() const { return !is_snap(); } /* Do not use when a particular hash function is needed */ explicit hobject_t(const sobject_t &o) : oid(o.oid), snap(o.snap), max(false), pool(-1) { hash = CEPH_HASH_NAMESPACE::hash()(o); } // maximum sorted value. static hobject_t get_max() { hobject_t h; h.max = true; return h; } bool is_max() const { return max; } bool is_min() const { // this needs to match how it's constructed return snap == 0 && hash == 0 && !max && pool == -1; } static uint32_t _reverse_nibbles(uint32_t retval) { // reverse nibbles retval = ((retval & 0x0f0f0f0f) << 4) | ((retval & 0xf0f0f0f0) >> 4); retval = ((retval & 0x00ff00ff) << 8) | ((retval & 0xff00ff00) >> 8); retval = ((retval & 0x0000ffff) << 16) | ((retval & 0xffff0000) >> 16); return retval; } /** * Returns set S of strings such that for any object * h where h.match(bits, mask), there is some string * s \in S such that s is a prefix of h.to_str(). * Furthermore, for any s \in S, s is a prefix of * h.str() implies that h.match(bits, mask). */ static set get_prefixes( uint32_t bits, uint32_t mask, int64_t pool); filestore_hobject_key_t get_filestore_key_u32() const { assert(!max); return _reverse_nibbles(hash); } filestore_hobject_key_t get_filestore_key() const { if (max) return 0x100000000ull; else return get_filestore_key_u32(); } const string& get_effective_key() const { if (key.length()) return key; return oid.name; } void swap(hobject_t &o) { hobject_t temp(o); o = (*this); (*this) = temp; } const string &get_namespace() const { return nspace; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void decode(json_spirit::Value& v); void dump(Formatter *f) const; static void generate_test_instances(list& o); friend bool operator<(const hobject_t&, const hobject_t&); friend bool operator>(const hobject_t&, const hobject_t&); friend bool operator<=(const hobject_t&, const hobject_t&); friend bool operator>=(const hobject_t&, const hobject_t&); friend bool operator==(const hobject_t&, const hobject_t&); friend bool operator!=(const hobject_t&, const hobject_t&); friend struct ghobject_t; }; WRITE_CLASS_ENCODER(hobject_t) CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const hobject_t &r) const { static hash H; static rjhash I; return H(r.oid) ^ I(r.snap); } }; CEPH_HASH_NAMESPACE_END ostream& operator<<(ostream& out, const hobject_t& o); WRITE_EQ_OPERATORS_7(hobject_t, oid, get_key(), snap, hash, max, pool, nspace) // sort hobject_t's by WRITE_CMP_OPERATORS_7(hobject_t, max, get_filestore_key(), nspace, pool, get_effective_key(), oid, snap) typedef version_t gen_t; typedef uint8_t shard_t; #ifndef UINT8_MAX #define UINT8_MAX (255) #endif #ifndef UINT64_MAX #define UINT64_MAX (18446744073709551615ULL) #endif struct ghobject_t { hobject_t hobj; gen_t generation; shard_t shard_id; public: static const shard_t NO_SHARD = UINT8_MAX; static shard_t no_shard() { return NO_SHARD; } static const gen_t NO_GEN = UINT64_MAX; ghobject_t() : generation(NO_GEN), shard_id(NO_SHARD) {} ghobject_t(const hobject_t &obj) : hobj(obj), generation(NO_GEN), shard_id(NO_SHARD) {} ghobject_t(const hobject_t &obj, gen_t gen, shard_t shard) : hobj(obj), generation(gen), shard_id(shard) {} bool match(uint32_t bits, uint32_t match) const { return hobj.match_hash(hobj.hash, bits, match); } /// @return min ghobject_t ret s.t. ret.hash == this->hash ghobject_t get_boundary() const { if (hobj.is_max()) return *this; ghobject_t ret; ret.hobj.hash = hobj.hash; return ret; } filestore_hobject_key_t get_filestore_key_u32() const { return hobj.get_filestore_key_u32(); } filestore_hobject_key_t get_filestore_key() const { return hobj.get_filestore_key(); } bool is_degenerate() const { return generation == NO_GEN && shard_id == NO_SHARD; } bool is_no_gen() const { return generation == NO_GEN; } bool is_no_shard() const { return shard_id == NO_SHARD; } // maximum sorted value. static ghobject_t get_max() { ghobject_t h(hobject_t::get_max()); return h; } bool is_max() const { return hobj.is_max(); } void swap(ghobject_t &o) { ghobject_t temp(o); o = (*this); (*this) = temp; } void encode(bufferlist& bl) const; void decode(bufferlist::iterator& bl); void decode(json_spirit::Value& v); void dump(Formatter *f) const; static void generate_test_instances(list& o); friend bool operator<(const ghobject_t&, const ghobject_t&); friend bool operator>(const ghobject_t&, const ghobject_t&); friend bool operator<=(const ghobject_t&, const ghobject_t&); friend bool operator>=(const ghobject_t&, const ghobject_t&); friend bool operator==(const ghobject_t&, const ghobject_t&); friend bool operator!=(const ghobject_t&, const ghobject_t&); }; WRITE_CLASS_ENCODER(ghobject_t) CEPH_HASH_NAMESPACE_START template<> struct hash { size_t operator()(const ghobject_t &r) const { static hash H; static rjhash I; return H(r.hobj.oid) ^ I(r.hobj.snap); } }; CEPH_HASH_NAMESPACE_END ostream& operator<<(ostream& out, const ghobject_t& o); WRITE_EQ_OPERATORS_3(ghobject_t, hobj, shard_id, generation) // sort ghobject_t's by // // Two objects which differ by generation are more related than // two objects of the same generation which differ by shard. // WRITE_CMP_OPERATORS_3(ghobject_t, hobj, shard_id, generation) #endif ceph-0.80.11/src/common/ceph_crypto_cms.h0000664000175100017510000000030112623076744022300 0ustar jenkins-buildjenkins-build#ifndef CEPH_CRYPTO_CMS_H #define CEPH_CRYPTO_CMS_H #include "include/buffer.h" class CephContext; int ceph_decode_cms(CephContext *cct, bufferlist& cms_bl, bufferlist& decoded_bl); #endif ceph-0.80.11/src/common/LogEntry.cc0000664000175100017510000001101412623076744021023 0ustar jenkins-buildjenkins-build #include #include #include "LogEntry.h" #include "Formatter.h" #include "include/stringify.h" // ---- // LogEntryKey void LogEntryKey::encode(bufferlist& bl) const { ::encode(who, bl); ::encode(stamp, bl); ::encode(seq, bl); } void LogEntryKey::decode(bufferlist::iterator& bl) { ::decode(who, bl); ::decode(stamp, bl); ::decode(seq, bl); } void LogEntryKey::dump(Formatter *f) const { f->dump_stream("who") << who; f->dump_stream("stamp") << stamp; f->dump_unsigned("seq", seq); } void LogEntryKey::generate_test_instances(list& o) { o.push_back(new LogEntryKey); o.push_back(new LogEntryKey(entity_inst_t(), utime_t(1,2), 34)); } // ---- int clog_type_to_syslog_level(clog_type t) { switch (t) { case CLOG_DEBUG: return LOG_DEBUG; case CLOG_INFO: return LOG_INFO; case CLOG_WARN: return LOG_WARNING; case CLOG_ERROR: return LOG_ERR; case CLOG_SEC: return LOG_CRIT; default: assert(0); return 0; } } int string_to_syslog_level(string s) { if (boost::iequals(s, "debug")) return LOG_DEBUG; if (boost::iequals(s, "info") || boost::iequals(s, "notice")) return LOG_INFO; if (boost::iequals(s, "warning") || boost::iequals(s, "warn")) return LOG_WARNING; if (boost::iequals(s, "error") || boost::iequals(s, "err")) return LOG_ERR; if (boost::iequals(s, "crit") || boost::iequals(s, "critical") || boost::iequals(s, "emerg")) return LOG_CRIT; // err on the side of noise! return LOG_DEBUG; } int string_to_syslog_facility(string s) { if (boost::iequals(s, "auth")) return LOG_AUTH; if (boost::iequals(s, "authpriv")) return LOG_AUTHPRIV; if (boost::iequals(s, "cron")) return LOG_CRON; if (boost::iequals(s, "daemon")) return LOG_DAEMON; if (boost::iequals(s, "ftp")) return LOG_FTP; if (boost::iequals(s, "kern")) return LOG_KERN; if (boost::iequals(s, "local0")) return LOG_LOCAL0; if (boost::iequals(s, "local1")) return LOG_LOCAL1; if (boost::iequals(s, "local2")) return LOG_LOCAL2; if (boost::iequals(s, "local3")) return LOG_LOCAL3; if (boost::iequals(s, "local4")) return LOG_LOCAL4; if (boost::iequals(s, "local5")) return LOG_LOCAL5; if (boost::iequals(s, "local6")) return LOG_LOCAL6; if (boost::iequals(s, "local7")) return LOG_LOCAL7; if (boost::iequals(s, "lpr")) return LOG_LPR; if (boost::iequals(s, "mail")) return LOG_MAIL; if (boost::iequals(s, "news")) return LOG_NEWS; if (boost::iequals(s, "syslog")) return LOG_SYSLOG; if (boost::iequals(s, "user")) return LOG_USER; if (boost::iequals(s, "uucp")) return LOG_UUCP; // default to USER return LOG_USER; } void LogEntry::log_to_syslog(string level, string facility) { int min = string_to_syslog_level(level); int l = clog_type_to_syslog_level(type); if (l <= min) { int f = string_to_syslog_facility(facility); syslog(l | f, "%s", stringify(*this).c_str()); } } void LogEntry::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); __u16 t = type; ::encode(who, bl); ::encode(stamp, bl); ::encode(seq, bl); ::encode(t, bl); ::encode(msg, bl); ENCODE_FINISH(bl); } void LogEntry::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); __u16 t; ::decode(who, bl); ::decode(stamp, bl); ::decode(seq, bl); ::decode(t, bl); type = (clog_type)t; ::decode(msg, bl); DECODE_FINISH(bl); } void LogEntry::dump(Formatter *f) const { f->dump_stream("who") << who; f->dump_stream("stamp") << stamp; f->dump_unsigned("seq", seq); f->dump_stream("type") << type; f->dump_string("message", msg); } void LogEntry::generate_test_instances(list& o) { o.push_back(new LogEntry); } // ----- void LogSummary::encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(version, bl); ::encode(tail, bl); ENCODE_FINISH(bl); } void LogSummary::decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(version, bl); ::decode(tail, bl); DECODE_FINISH(bl); } void LogSummary::dump(Formatter *f) const { f->dump_unsigned("version", version); f->open_array_section("tail"); for (list::const_iterator p = tail.begin(); p != tail.end(); ++p) { f->open_object_section("entry"); p->dump(f); f->close_section(); } f->close_section(); } void LogSummary::generate_test_instances(list& o) { o.push_back(new LogSummary); // more! } ceph-0.80.11/src/common/config_opts.h0000664000175100017510000015207412623076744021450 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* note: no header guard */ OPTION(host, OPT_STR, "localhost") OPTION(fsid, OPT_UUID, uuid_d()) OPTION(public_addr, OPT_ADDR, entity_addr_t()) OPTION(cluster_addr, OPT_ADDR, entity_addr_t()) OPTION(public_network, OPT_STR, "") OPTION(cluster_network, OPT_STR, "") OPTION(num_client, OPT_INT, 1) OPTION(monmap, OPT_STR, "") OPTION(mon_host, OPT_STR, "") OPTION(lockdep, OPT_BOOL, false) OPTION(run_dir, OPT_STR, "/var/run/ceph") // the "/var/run/ceph" dir, created on daemon startup OPTION(admin_socket, OPT_STR, "$run_dir/$cluster-$name.asok") // default changed by common_preinit() OPTION(daemonize, OPT_BOOL, false) // default changed by common_preinit() OPTION(pid_file, OPT_STR, "") // default changed by common_preinit() OPTION(chdir, OPT_STR, "/") OPTION(max_open_files, OPT_LONGLONG, 0) OPTION(restapi_log_level, OPT_STR, "") // default set by Python code OPTION(restapi_base_url, OPT_STR, "") // " OPTION(fatal_signal_handlers, OPT_BOOL, true) OPTION(log_file, OPT_STR, "/var/log/ceph/$cluster-$name.log") // default changed by common_preinit() OPTION(log_max_new, OPT_INT, 1000) // default changed by common_preinit() OPTION(log_max_recent, OPT_INT, 10000) // default changed by common_preinit() OPTION(log_to_stderr, OPT_BOOL, true) // default changed by common_preinit() OPTION(err_to_stderr, OPT_BOOL, true) // default changed by common_preinit() OPTION(log_to_syslog, OPT_BOOL, false) OPTION(err_to_syslog, OPT_BOOL, false) OPTION(log_flush_on_exit, OPT_BOOL, true) // default changed by common_preinit() OPTION(log_stop_at_utilization, OPT_FLOAT, .97) // stop logging at (near) full OPTION(clog_to_monitors, OPT_BOOL, true) OPTION(clog_to_syslog, OPT_BOOL, false) OPTION(clog_to_syslog_level, OPT_STR, "info") // this level and above OPTION(clog_to_syslog_facility, OPT_STR, "daemon") OPTION(mon_cluster_log_to_syslog, OPT_BOOL, false) OPTION(mon_cluster_log_to_syslog_level, OPT_STR, "info") // this level and above OPTION(mon_cluster_log_to_syslog_facility, OPT_STR, "daemon") OPTION(mon_cluster_log_file, OPT_STR, "/var/log/ceph/$cluster.log") OPTION(mon_cluster_log_file_level, OPT_STR, "info") DEFAULT_SUBSYS(0, 5) SUBSYS(lockdep, 0, 1) SUBSYS(context, 0, 1) SUBSYS(crush, 1, 1) SUBSYS(mds, 1, 5) SUBSYS(mds_balancer, 1, 5) SUBSYS(mds_locker, 1, 5) SUBSYS(mds_log, 1, 5) SUBSYS(mds_log_expire, 1, 5) SUBSYS(mds_migrator, 1, 5) SUBSYS(buffer, 0, 1) SUBSYS(timer, 0, 1) SUBSYS(filer, 0, 1) SUBSYS(striper, 0, 1) SUBSYS(objecter, 0, 1) SUBSYS(rados, 0, 5) SUBSYS(rbd, 0, 5) SUBSYS(journaler, 0, 5) SUBSYS(objectcacher, 0, 5) SUBSYS(client, 0, 5) SUBSYS(osd, 0, 5) SUBSYS(optracker, 0, 5) SUBSYS(objclass, 0, 5) SUBSYS(filestore, 1, 3) SUBSYS(keyvaluestore, 1, 3) SUBSYS(journal, 1, 3) SUBSYS(ms, 0, 5) SUBSYS(mon, 1, 5) SUBSYS(monc, 0, 10) SUBSYS(paxos, 1, 5) SUBSYS(tp, 0, 5) SUBSYS(auth, 1, 5) SUBSYS(crypto, 1, 5) SUBSYS(finisher, 1, 1) SUBSYS(heartbeatmap, 1, 5) SUBSYS(perfcounter, 1, 5) SUBSYS(rgw, 1, 5) // log level for the Rados gateway SUBSYS(civetweb, 1, 10) SUBSYS(javaclient, 1, 5) SUBSYS(asok, 1, 5) SUBSYS(throttle, 1, 1) OPTION(key, OPT_STR, "") OPTION(keyfile, OPT_STR, "") OPTION(keyring, OPT_STR, "/etc/ceph/$cluster.$name.keyring,/etc/ceph/$cluster.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin") // default changed by common_preinit() for mds and osd OPTION(heartbeat_interval, OPT_INT, 5) OPTION(heartbeat_file, OPT_STR, "") OPTION(heartbeat_inject_failure, OPT_INT, 0) // force an unhealthy heartbeat for N seconds OPTION(perf, OPT_BOOL, true) // enable internal perf counters OPTION(ms_tcp_nodelay, OPT_BOOL, true) OPTION(ms_tcp_rcvbuf, OPT_INT, 0) OPTION(ms_initial_backoff, OPT_DOUBLE, .2) OPTION(ms_max_backoff, OPT_DOUBLE, 15.0) OPTION(ms_nocrc, OPT_BOOL, false) OPTION(ms_die_on_bad_msg, OPT_BOOL, false) OPTION(ms_die_on_unhandled_msg, OPT_BOOL, false) OPTION(ms_die_on_old_message, OPT_BOOL, false) // assert if we get a dup incoming message and shouldn't have (may be triggered by pre-541cd3c64be0dfa04e8a2df39422e0eb9541a428 code) OPTION(ms_dispatch_throttle_bytes, OPT_U64, 100 << 20) OPTION(ms_bind_ipv6, OPT_BOOL, false) OPTION(ms_bind_port_min, OPT_INT, 6800) OPTION(ms_bind_port_max, OPT_INT, 7300) OPTION(ms_rwthread_stack_bytes, OPT_U64, 1024 << 10) OPTION(ms_tcp_read_timeout, OPT_U64, 900) OPTION(ms_pq_max_tokens_per_priority, OPT_U64, 16777216) OPTION(ms_pq_min_cost, OPT_U64, 65536) OPTION(ms_inject_socket_failures, OPT_U64, 0) OPTION(ms_inject_delay_type, OPT_STR, "") // "osd mds mon client" allowed OPTION(ms_inject_delay_msg_type, OPT_STR, "") // the type of message to delay, as returned by Message::get_type_name(). This is an additional restriction on the general type filter ms_inject_delay_type. OPTION(ms_inject_delay_max, OPT_DOUBLE, 1) // seconds OPTION(ms_inject_delay_probability, OPT_DOUBLE, 0) // range [0, 1] OPTION(ms_inject_internal_delays, OPT_DOUBLE, 0) // seconds OPTION(ms_dump_on_send, OPT_BOOL, false) // hexdump msg to log on send OPTION(inject_early_sigterm, OPT_BOOL, false) OPTION(mon_data, OPT_STR, "/var/lib/ceph/mon/$cluster-$id") OPTION(mon_initial_members, OPT_STR, "") // list of initial cluster mon ids; if specified, need majority to form initial quorum and create new cluster OPTION(mon_sync_fs_threshold, OPT_INT, 5) // sync() when writing this many objects; 0 to disable. OPTION(mon_compact_on_start, OPT_BOOL, false) // compact leveldb on ceph-mon start OPTION(mon_compact_on_bootstrap, OPT_BOOL, false) // trigger leveldb compaction on bootstrap OPTION(mon_compact_on_trim, OPT_BOOL, true) // compact (a prefix) when we trim old states OPTION(mon_osd_cache_size, OPT_INT, 10) // the size of osdmaps cache, not to rely on underlying store's cache OPTION(mon_tick_interval, OPT_INT, 5) OPTION(mon_subscribe_interval, OPT_DOUBLE, 300) OPTION(mon_delta_reset_interval, OPT_DOUBLE, 10) // seconds of inactivity before we reset the pg delta to 0 OPTION(mon_osd_laggy_halflife, OPT_INT, 60*60) // (seconds) how quickly our laggy estimations decay OPTION(mon_osd_laggy_weight, OPT_DOUBLE, .3) // weight for new 'samples's in laggy estimations OPTION(mon_osd_adjust_heartbeat_grace, OPT_BOOL, true) // true if we should scale based on laggy estimations OPTION(mon_osd_adjust_down_out_interval, OPT_BOOL, true) // true if we should scale based on laggy estimations OPTION(mon_osd_auto_mark_in, OPT_BOOL, false) // mark any booting osds 'in' OPTION(mon_osd_auto_mark_auto_out_in, OPT_BOOL, true) // mark booting auto-marked-out osds 'in' OPTION(mon_osd_auto_mark_new_in, OPT_BOOL, true) // mark booting new osds 'in' OPTION(mon_osd_down_out_interval, OPT_INT, 300) // seconds OPTION(mon_osd_down_out_subtree_limit, OPT_STR, "rack") // smallest crush unit/type that we will not automatically mark out OPTION(mon_osd_min_up_ratio, OPT_DOUBLE, .3) // min osds required to be up to mark things down OPTION(mon_osd_min_in_ratio, OPT_DOUBLE, .3) // min osds required to be in to mark things out OPTION(mon_osd_max_op_age, OPT_DOUBLE, 32) // max op age before we get concerned (make it a power of 2) OPTION(mon_osd_max_split_count, OPT_INT, 32) // largest number of PGs per "involved" OSD to let split create OPTION(mon_osd_allow_primary_temp, OPT_BOOL, false) // allow primary_temp to be set in the osdmap OPTION(mon_osd_allow_primary_affinity, OPT_BOOL, false) // allow primary_affinity to be set in the osdmap OPTION(mon_stat_smooth_intervals, OPT_INT, 2) // smooth stats over last N PGMap maps OPTION(mon_lease, OPT_FLOAT, 5) // lease interval OPTION(mon_lease_renew_interval, OPT_FLOAT, 3) // on leader, to renew the lease OPTION(mon_lease_ack_timeout, OPT_FLOAT, 10.0) // on leader, if lease isn't acked by all peons OPTION(mon_clock_drift_allowed, OPT_FLOAT, .050) // allowed clock drift between monitors OPTION(mon_clock_drift_warn_backoff, OPT_FLOAT, 5) // exponential backoff for clock drift warnings OPTION(mon_timecheck_interval, OPT_FLOAT, 300.0) // on leader, timecheck (clock drift check) interval (seconds) OPTION(mon_accept_timeout, OPT_FLOAT, 10.0) // on leader, if paxos update isn't accepted OPTION(mon_pg_create_interval, OPT_FLOAT, 30.0) // no more than every 30s OPTION(mon_pg_stuck_threshold, OPT_INT, 300) // number of seconds after which pgs can be considered inactive, unclean, or stale (see doc/control.rst under dump_stuck for more info) OPTION(mon_pg_warn_min_per_osd, OPT_INT, 20) // min # pgs per (in) osd before we warn the admin OPTION(mon_pg_warn_max_object_skew, OPT_FLOAT, 10.0) // max skew few average in objects per pg OPTION(mon_pg_warn_min_objects, OPT_INT, 10000) // do not warn below this object # OPTION(mon_pg_warn_min_pool_objects, OPT_INT, 1000) // do not warn on pools below this object # OPTION(mon_cache_target_full_warn_ratio, OPT_FLOAT, .66) // position between pool cache_target_full and max where we start warning OPTION(mon_osd_full_ratio, OPT_FLOAT, .95) // what % full makes an OSD "full" OPTION(mon_osd_nearfull_ratio, OPT_FLOAT, .85) // what % full makes an OSD near full OPTION(mon_allow_pool_delete, OPT_BOOL, true) // allow pool deletion OPTION(mon_globalid_prealloc, OPT_INT, 10000) // how many globalids to prealloc OPTION(mon_osd_report_timeout, OPT_INT, 900) // grace period before declaring unresponsive OSDs dead OPTION(mon_force_standby_active, OPT_BOOL, true) // should mons force standby-replay mds to be active OPTION(mon_warn_on_old_mons, OPT_BOOL, true) // should mons set health to WARN if part of quorum is old? OPTION(mon_warn_on_legacy_crush_tunables, OPT_BOOL, true) // warn if crush tunables are not optimal OPTION(mon_warn_on_osd_down_out_interval_zero, OPT_BOOL, true) // warn if 'mon_osd_down_out_interval == 0' OPTION(mon_warn_on_cache_pools_without_hit_sets, OPT_BOOL, true) OPTION(mon_min_osdmap_epochs, OPT_INT, 500) OPTION(mon_max_pgmap_epochs, OPT_INT, 500) OPTION(mon_max_log_epochs, OPT_INT, 500) OPTION(mon_max_mdsmap_epochs, OPT_INT, 500) OPTION(mon_max_osd, OPT_INT, 10000) OPTION(mon_probe_timeout, OPT_DOUBLE, 2.0) OPTION(mon_slurp_timeout, OPT_DOUBLE, 10.0) OPTION(mon_slurp_bytes, OPT_INT, 256*1024) // limit size of slurp messages OPTION(mon_client_bytes, OPT_U64, 100ul << 20) // client msg data allowed in memory (in bytes) OPTION(mon_daemon_bytes, OPT_U64, 400ul << 20) // mds, osd message memory cap (in bytes) OPTION(mon_max_log_entries_per_event, OPT_INT, 4096) OPTION(mon_health_data_update_interval, OPT_FLOAT, 60.0) OPTION(mon_data_avail_crit, OPT_INT, 5) OPTION(mon_data_avail_warn, OPT_INT, 30) OPTION(mon_config_key_max_entry_size, OPT_INT, 4096) // max num bytes per config-key entry OPTION(mon_sync_timeout, OPT_DOUBLE, 60.0) OPTION(mon_sync_max_payload_size, OPT_U32, 1048576) // max size for a sync chunk payload (say, 1MB) OPTION(mon_sync_debug, OPT_BOOL, false) // enable sync-specific debug OPTION(mon_sync_debug_leader, OPT_INT, -1) // monitor to be used as the sync leader OPTION(mon_sync_debug_provider, OPT_INT, -1) // monitor to be used as the sync provider OPTION(mon_sync_debug_provider_fallback, OPT_INT, -1) // monitor to be used as fallback if sync provider fails OPTION(mon_inject_sync_get_chunk_delay, OPT_DOUBLE, 0) // inject N second delay on each get_chunk request OPTION(mon_osd_min_down_reporters, OPT_INT, 1) // number of OSDs who need to report a down OSD for it to count OPTION(mon_osd_min_down_reports, OPT_INT, 3) // number of times a down OSD must be reported for it to count OPTION(mon_osd_force_trim_to, OPT_INT, 0) // force mon to trim maps to this point, regardless of min_last_epoch_clean (dangerous, use with care) OPTION(mon_mds_force_trim_to, OPT_INT, 0) // force mon to trim mdsmaps to this point (dangerous, use with care) OPTION(mon_advanced_debug_mode, OPT_BOOL, false) // true for developper oriented testing // dump transactions OPTION(mon_debug_dump_transactions, OPT_BOOL, false) OPTION(mon_debug_dump_location, OPT_STR, "/var/log/ceph/$cluster-$name.tdump") OPTION(mon_sync_provider_kill_at, OPT_INT, 0) // kill the sync provider at a specific point in the work flow OPTION(mon_sync_requester_kill_at, OPT_INT, 0) // kill the sync requester at a specific point in the work flow OPTION(mon_leveldb_write_buffer_size, OPT_U64, 32*1024*1024) // monitor's leveldb write buffer size OPTION(mon_leveldb_cache_size, OPT_U64, 512*1024*1024) // monitor's leveldb cache size OPTION(mon_leveldb_block_size, OPT_U64, 64*1024) // monitor's leveldb block size OPTION(mon_leveldb_bloom_size, OPT_INT, 0) // monitor's leveldb bloom bits per entry OPTION(mon_leveldb_max_open_files, OPT_INT, 0) // monitor's leveldb max open files OPTION(mon_leveldb_compression, OPT_BOOL, false) // monitor's leveldb uses compression OPTION(mon_leveldb_paranoid, OPT_BOOL, false) // monitor's leveldb paranoid flag OPTION(mon_leveldb_log, OPT_STR, "") OPTION(mon_leveldb_size_warn, OPT_U64, 40*1024*1024*1024) // issue a warning when the monitor's leveldb goes over 40GB (in bytes) OPTION(mon_force_quorum_join, OPT_BOOL, false) // force monitor to join quorum even if it has been previously removed from the map OPTION(paxos_stash_full_interval, OPT_INT, 25) // how often (in commits) to stash a full copy of the PaxosService state OPTION(paxos_max_join_drift, OPT_INT, 10) // max paxos iterations before we must first sync the monitor stores OPTION(paxos_propose_interval, OPT_DOUBLE, 1.0) // gather updates for this long before proposing a map update OPTION(paxos_min_wait, OPT_DOUBLE, 0.05) // min time to gather updates for after period of inactivity OPTION(paxos_min, OPT_INT, 500) // minimum number of paxos states to keep around OPTION(paxos_trim_min, OPT_INT, 250) // number of extra proposals tolerated before trimming OPTION(paxos_trim_max, OPT_INT, 500) // max number of extra proposals to trim at a time OPTION(paxos_service_trim_min, OPT_INT, 250) // minimum amount of versions to trigger a trim (0 disables it) OPTION(paxos_service_trim_max, OPT_INT, 500) // maximum amount of versions to trim during a single proposal (0 disables it) OPTION(paxos_kill_at, OPT_INT, 0) OPTION(clock_offset, OPT_DOUBLE, 0) // how much to offset the system clock in Clock.cc OPTION(auth_cluster_required, OPT_STR, "cephx") // required of mon, mds, osd daemons OPTION(auth_service_required, OPT_STR, "cephx") // required by daemons of clients OPTION(auth_client_required, OPT_STR, "cephx, none") // what clients require of daemons OPTION(auth_supported, OPT_STR, "") // deprecated; default value for above if they are not defined. OPTION(cephx_require_signatures, OPT_BOOL, false) // If true, don't talk to Cephx partners if they don't support message signing; off by default OPTION(cephx_cluster_require_signatures, OPT_BOOL, false) OPTION(cephx_service_require_signatures, OPT_BOOL, false) OPTION(cephx_sign_messages, OPT_BOOL, true) // Default to signing session messages if supported OPTION(auth_mon_ticket_ttl, OPT_DOUBLE, 60*60*12) OPTION(auth_service_ticket_ttl, OPT_DOUBLE, 60*60) OPTION(auth_debug, OPT_BOOL, false) // if true, assert when weird things happen OPTION(mon_client_hunt_interval, OPT_DOUBLE, 3.0) // try new mon every N seconds until we connect OPTION(mon_client_ping_interval, OPT_DOUBLE, 10.0) // ping every N seconds OPTION(mon_client_ping_timeout, OPT_DOUBLE, 30.0) // fail if we don't hear back OPTION(mon_client_hunt_interval_backoff, OPT_DOUBLE, 2.0) // each time we reconnect to a monitor, double our timeout OPTION(mon_client_hunt_interval_max_multiple, OPT_DOUBLE, 10.0) // up to a max of 10*default (30 seconds) OPTION(mon_client_max_log_entries_per_message, OPT_INT, 1000) OPTION(mon_max_pool_pg_num, OPT_INT, 65536) OPTION(mon_pool_quota_warn_threshold, OPT_INT, 0) // percent of quota at which to issue warnings OPTION(mon_pool_quota_crit_threshold, OPT_INT, 0) // percent of quota at which to issue errors OPTION(client_cache_size, OPT_INT, 16384) OPTION(client_cache_mid, OPT_FLOAT, .75) OPTION(client_use_random_mds, OPT_BOOL, false) OPTION(client_mount_timeout, OPT_DOUBLE, 300.0) OPTION(client_tick_interval, OPT_DOUBLE, 1.0) OPTION(client_trace, OPT_STR, "") OPTION(client_readahead_min, OPT_LONGLONG, 128*1024) // readahead at _least_ this much. OPTION(client_readahead_max_bytes, OPT_LONGLONG, 0) //8 * 1024*1024 OPTION(client_readahead_max_periods, OPT_LONGLONG, 4) // as multiple of file layout period (object size * num stripes) OPTION(client_snapdir, OPT_STR, ".snap") OPTION(client_mountpoint, OPT_STR, "/") OPTION(client_notify_timeout, OPT_INT, 10) // in seconds OPTION(osd_client_watch_timeout, OPT_INT, 30) // in seconds OPTION(client_caps_release_delay, OPT_INT, 5) // in seconds OPTION(client_oc, OPT_BOOL, true) OPTION(client_oc_size, OPT_INT, 1024*1024* 200) // MB * n OPTION(client_oc_max_dirty, OPT_INT, 1024*1024* 100) // MB * n (dirty OR tx.. bigish) OPTION(client_oc_target_dirty, OPT_INT, 1024*1024* 8) // target dirty (keep this smallish) OPTION(client_oc_max_dirty_age, OPT_DOUBLE, 5.0) // max age in cache before writeback OPTION(client_oc_max_objects, OPT_INT, 1000) // max objects in cache OPTION(client_debug_force_sync_read, OPT_BOOL, false) // always read synchronously (go to osds) OPTION(client_debug_inject_tick_delay, OPT_INT, 0) // delay the client tick for a number of seconds OPTION(client_max_inline_size, OPT_U64, 4096) // note: the max amount of "in flight" dirty data is roughly (max - target) OPTION(fuse_use_invalidate_cb, OPT_BOOL, false) // use fuse 2.8+ invalidate callback to keep page cache consistent OPTION(fuse_allow_other, OPT_BOOL, true) OPTION(fuse_default_permissions, OPT_BOOL, true) OPTION(fuse_big_writes, OPT_BOOL, true) OPTION(fuse_atomic_o_trunc, OPT_BOOL, true) OPTION(fuse_debug, OPT_BOOL, false) OPTION(fuse_multithreaded, OPT_BOOL, true) OPTION(crush_location, OPT_STR, "") // whitespace-separated list of key=value pairs describing crush location OPTION(objecter_tick_interval, OPT_DOUBLE, 5.0) OPTION(objecter_timeout, OPT_DOUBLE, 10.0) // before we ask for a map OPTION(objecter_inflight_op_bytes, OPT_U64, 1024*1024*100) // max in-flight data (both directions) OPTION(objecter_inflight_ops, OPT_U64, 1024) // max in-flight ios OPTION(journaler_allow_split_entries, OPT_BOOL, true) OPTION(journaler_write_head_interval, OPT_INT, 15) OPTION(journaler_prefetch_periods, OPT_INT, 10) // * journal object size OPTION(journaler_prezero_periods, OPT_INT, 5) // * journal object size OPTION(journaler_batch_interval, OPT_DOUBLE, .001) // seconds.. max add'l latency we artificially incur OPTION(journaler_batch_max, OPT_U64, 0) // max bytes we'll delay flushing; disable, for now.... OPTION(mds_data, OPT_STR, "/var/lib/ceph/mds/$cluster-$id") OPTION(mds_max_file_size, OPT_U64, 1ULL << 40) OPTION(mds_cache_size, OPT_INT, 100000) OPTION(mds_cache_mid, OPT_FLOAT, .7) OPTION(mds_mem_max, OPT_INT, 1048576) // KB OPTION(mds_dir_max_commit_size, OPT_INT, 10) // MB OPTION(mds_decay_halflife, OPT_FLOAT, 5) OPTION(mds_beacon_interval, OPT_FLOAT, 4) OPTION(mds_beacon_grace, OPT_FLOAT, 15) OPTION(mds_enforce_unique_name, OPT_BOOL, true) OPTION(mds_blacklist_interval, OPT_FLOAT, 24.0*60.0) // how long to blacklist failed nodes OPTION(mds_session_timeout, OPT_FLOAT, 60) // cap bits and leases time out if client idle OPTION(mds_freeze_tree_timeout, OPT_FLOAT, 30) // cap bits and leases time out if client idle OPTION(mds_session_autoclose, OPT_FLOAT, 300) // autoclose idle session OPTION(mds_reconnect_timeout, OPT_FLOAT, 45) // seconds to wait for clients during mds restart // make it (mds_session_timeout - mds_beacon_grace) OPTION(mds_tick_interval, OPT_FLOAT, 5) OPTION(mds_dirstat_min_interval, OPT_FLOAT, 1) // try to avoid propagating more often than this OPTION(mds_scatter_nudge_interval, OPT_FLOAT, 5) // how quickly dirstat changes propagate up the hierarchy OPTION(mds_client_prealloc_inos, OPT_INT, 1000) OPTION(mds_early_reply, OPT_BOOL, true) OPTION(mds_default_dir_hash, OPT_INT, CEPH_STR_HASH_RJENKINS) OPTION(mds_log, OPT_BOOL, true) OPTION(mds_log_skip_corrupt_events, OPT_BOOL, false) OPTION(mds_log_max_events, OPT_INT, -1) OPTION(mds_log_segment_size, OPT_INT, 0) // segment size for mds log, // defaults to g_default_file_layout.fl_object_size (4MB) OPTION(mds_log_max_segments, OPT_INT, 30) OPTION(mds_log_max_expiring, OPT_INT, 20) OPTION(mds_bal_sample_interval, OPT_FLOAT, 3.0) // every 5 seconds OPTION(mds_bal_replicate_threshold, OPT_FLOAT, 8000) OPTION(mds_bal_unreplicate_threshold, OPT_FLOAT, 0) OPTION(mds_bal_frag, OPT_BOOL, false) OPTION(mds_bal_split_size, OPT_INT, 10000) OPTION(mds_bal_split_rd, OPT_FLOAT, 25000) OPTION(mds_bal_split_wr, OPT_FLOAT, 10000) OPTION(mds_bal_split_bits, OPT_INT, 3) OPTION(mds_bal_merge_size, OPT_INT, 50) OPTION(mds_bal_merge_rd, OPT_FLOAT, 1000) OPTION(mds_bal_merge_wr, OPT_FLOAT, 1000) OPTION(mds_bal_interval, OPT_INT, 10) // seconds OPTION(mds_bal_fragment_interval, OPT_INT, 5) // seconds OPTION(mds_bal_idle_threshold, OPT_FLOAT, 0) OPTION(mds_bal_max, OPT_INT, -1) OPTION(mds_bal_max_until, OPT_INT, -1) OPTION(mds_bal_mode, OPT_INT, 0) OPTION(mds_bal_min_rebalance, OPT_FLOAT, .1) // must be this much above average before we export anything OPTION(mds_bal_min_start, OPT_FLOAT, .2) // if we need less than this, we don't do anything OPTION(mds_bal_need_min, OPT_FLOAT, .8) // take within this range of what we need OPTION(mds_bal_need_max, OPT_FLOAT, 1.2) OPTION(mds_bal_midchunk, OPT_FLOAT, .3) // any sub bigger than this taken in full OPTION(mds_bal_minchunk, OPT_FLOAT, .001) // never take anything smaller than this OPTION(mds_bal_target_removal_min, OPT_INT, 5) // min balance iterations before old target is removed OPTION(mds_bal_target_removal_max, OPT_INT, 10) // max balance iterations before old target is removed OPTION(mds_replay_interval, OPT_FLOAT, 1.0) // time to wait before starting replay again OPTION(mds_shutdown_check, OPT_INT, 0) OPTION(mds_thrash_exports, OPT_INT, 0) OPTION(mds_thrash_fragments, OPT_INT, 0) OPTION(mds_dump_cache_on_map, OPT_BOOL, false) OPTION(mds_dump_cache_after_rejoin, OPT_BOOL, false) OPTION(mds_verify_scatter, OPT_BOOL, false) OPTION(mds_debug_scatterstat, OPT_BOOL, false) OPTION(mds_debug_frag, OPT_BOOL, false) OPTION(mds_debug_auth_pins, OPT_BOOL, false) OPTION(mds_debug_subtrees, OPT_BOOL, false) OPTION(mds_kill_mdstable_at, OPT_INT, 0) OPTION(mds_kill_export_at, OPT_INT, 0) OPTION(mds_kill_import_at, OPT_INT, 0) OPTION(mds_kill_link_at, OPT_INT, 0) OPTION(mds_kill_rename_at, OPT_INT, 0) OPTION(mds_kill_openc_at, OPT_INT, 0) OPTION(mds_kill_journal_at, OPT_INT, 0) OPTION(mds_kill_journal_expire_at, OPT_INT, 0) OPTION(mds_kill_journal_replay_at, OPT_INT, 0) OPTION(mds_kill_create_at, OPT_INT, 0) OPTION(mds_open_remote_link_mode, OPT_INT, 0) OPTION(mds_inject_traceless_reply_probability, OPT_DOUBLE, 0) /* percentage of MDS modify replies to skip sending the client a trace on [0-1]*/ OPTION(mds_wipe_sessions, OPT_BOOL, 0) OPTION(mds_wipe_ino_prealloc, OPT_BOOL, 0) OPTION(mds_skip_ino, OPT_INT, 0) OPTION(max_mds, OPT_INT, 1) OPTION(mds_standby_for_name, OPT_STR, "") OPTION(mds_standby_for_rank, OPT_INT, -1) OPTION(mds_standby_replay, OPT_BOOL, false) // If true, compact leveldb store on mount OPTION(osd_compact_leveldb_on_mount, OPT_BOOL, false) // Maximum number of backfills to or from a single osd OPTION(osd_max_backfills, OPT_U64, 10) // Refuse backfills when OSD full ratio is above this value OPTION(osd_backfill_full_ratio, OPT_FLOAT, 0.85) // Seconds to wait before retrying refused backfills OPTION(osd_backfill_retry_interval, OPT_DOUBLE, 10.0) // max agent flush ops OPTION(osd_agent_max_ops, OPT_INT, 4) OPTION(osd_agent_min_evict_effort, OPT_FLOAT, .1) OPTION(osd_agent_quantize_effort, OPT_FLOAT, .1) OPTION(osd_agent_delay_time, OPT_FLOAT, 5.0) // decay atime and hist histograms after how many objects go by OPTION(osd_agent_hist_halflife, OPT_INT, 1000) // must be this amount over the threshold to enable, // this amount below the threshold to disable. OPTION(osd_agent_slop, OPT_FLOAT, .02) OPTION(osd_uuid, OPT_UUID, uuid_d()) OPTION(osd_data, OPT_STR, "/var/lib/ceph/osd/$cluster-$id") OPTION(osd_journal, OPT_STR, "/var/lib/ceph/osd/$cluster-$id/journal") OPTION(osd_journal_size, OPT_INT, 5120) // in mb OPTION(osd_max_write_size, OPT_INT, 90) OPTION(osd_max_pgls, OPT_U64, 1024) // max number of pgls entries to return OPTION(osd_client_message_size_cap, OPT_U64, 500*1024L*1024L) // client data allowed in-memory (in bytes) OPTION(osd_client_message_cap, OPT_U64, 100) // num client messages allowed in-memory OPTION(osd_pg_bits, OPT_INT, 6) // bits per osd OPTION(osd_pgp_bits, OPT_INT, 6) // bits per osd OPTION(osd_crush_chooseleaf_type, OPT_INT, 1) // 1 = host OPTION(osd_pool_default_crush_rule, OPT_INT, -1) // deprecated for osd_pool_default_crush_replicated_ruleset OPTION(osd_pool_default_crush_replicated_ruleset, OPT_INT, CEPH_DEFAULT_CRUSH_REPLICATED_RULESET) OPTION(osd_pool_erasure_code_stripe_width, OPT_U32, OSD_POOL_ERASURE_CODE_STRIPE_WIDTH) // in bytes OPTION(osd_pool_default_size, OPT_INT, 3) OPTION(osd_pool_default_min_size, OPT_INT, 0) // 0 means no specific default; ceph will use size-size/2 OPTION(osd_pool_default_pg_num, OPT_INT, 8) // number of PGs for new pools. Configure in global or mon section of ceph.conf OPTION(osd_pool_default_pgp_num, OPT_INT, 8) // number of PGs for placement purposes. Should be equal to pg_num OPTION(osd_pool_default_erasure_code_directory, OPT_STR, CEPH_PKGLIBDIR"/erasure-code") // default for the erasure-code-directory=XXX property of osd pool create OPTION(osd_pool_default_erasure_code_profile, OPT_STR, "plugin=jerasure " "technique=reed_sol_van " "k=2 " "m=1 " ) // default properties of osd pool create OPTION(osd_erasure_code_plugins, OPT_STR, "jerasure") // list of erasure code plugins OPTION(osd_pool_default_flags, OPT_INT, 0) // default flags for new pools OPTION(osd_pool_default_flag_hashpspool, OPT_BOOL, true) // use new pg hashing to prevent pool/pg overlap OPTION(osd_pool_default_hit_set_bloom_fpp, OPT_FLOAT, .05) OPTION(osd_pool_default_cache_target_dirty_ratio, OPT_FLOAT, .4) OPTION(osd_pool_default_cache_target_full_ratio, OPT_FLOAT, .8) OPTION(osd_pool_default_cache_min_flush_age, OPT_INT, 0) // seconds OPTION(osd_pool_default_cache_min_evict_age, OPT_INT, 0) // seconds OPTION(osd_hit_set_min_size, OPT_INT, 1000) // min target size for a HitSet OPTION(osd_hit_set_max_size, OPT_INT, 100000) // max target size for a HitSet OPTION(osd_hit_set_namespace, OPT_STR, ".ceph-internal") // rados namespace for hit_set tracking OPTION(osd_tier_default_cache_mode, OPT_STR, "writeback") OPTION(osd_tier_default_cache_hit_set_count, OPT_INT, 4) OPTION(osd_tier_default_cache_hit_set_period, OPT_INT, 1200) OPTION(osd_tier_default_cache_hit_set_type, OPT_STR, "bloom") OPTION(osd_tier_default_cache_min_read_recency_for_promote, OPT_INT, 1) // number of recent HitSets the object must appear in to be promoted (on read) OPTION(osd_map_dedup, OPT_BOOL, true) OPTION(osd_map_max_advance, OPT_INT, 200) // make this < cache_size! OPTION(osd_map_cache_size, OPT_INT, 500) OPTION(osd_map_message_max, OPT_INT, 100) // max maps per MOSDMap message OPTION(osd_map_share_max_epochs, OPT_INT, 100) // cap on # of inc maps we send to peers, clients OPTION(osd_op_threads, OPT_INT, 2) // 0 == no threading OPTION(osd_peering_wq_batch_size, OPT_U64, 20) OPTION(osd_op_pq_max_tokens_per_priority, OPT_U64, 4194304) OPTION(osd_op_pq_min_cost, OPT_U64, 65536) OPTION(osd_disk_threads, OPT_INT, 1) OPTION(osd_disk_thread_ioprio_class, OPT_STR, "") // rt realtime be besteffort best effort idle OPTION(osd_disk_thread_ioprio_priority, OPT_INT, -1) // 0-7 OPTION(osd_recovery_threads, OPT_INT, 1) OPTION(osd_recover_clone_overlap, OPT_BOOL, true) // preserve clone_overlap during recovery/migration // Only use clone_overlap for recovery if there are fewer than // osd_recover_clone_overlap_limit entries in the overlap set OPTION(osd_recover_clone_overlap_limit, OPT_INT, 10) OPTION(osd_backfill_scan_min, OPT_INT, 64) OPTION(osd_backfill_scan_max, OPT_INT, 512) OPTION(osd_op_thread_timeout, OPT_INT, 15) OPTION(osd_op_thread_suicide_timeout, OPT_INT, 150) OPTION(osd_recovery_thread_timeout, OPT_INT, 30) OPTION(osd_recovery_thread_suicide_timeout, OPT_INT, 300) OPTION(osd_snap_trim_thread_timeout, OPT_INT, 60*60*1) OPTION(osd_snap_trim_thread_suicide_timeout, OPT_INT, 60*60*10) OPTION(osd_snap_trim_sleep, OPT_FLOAT, 0) OPTION(osd_scrub_thread_timeout, OPT_INT, 60) OPTION(osd_scrub_thread_suicide_timeout, OPT_INT, 60) OPTION(osd_scrub_finalize_thread_timeout, OPT_INT, 60*10) OPTION(osd_scrub_finalize_thread_suicide_timeout, OPT_INT, 60*10*10) OPTION(osd_scrub_invalid_stats, OPT_BOOL, true) OPTION(osd_remove_thread_timeout, OPT_INT, 60*60) OPTION(osd_remove_thread_suicide_timeout, OPT_INT, 10*60*60) OPTION(osd_command_thread_timeout, OPT_INT, 10*60) OPTION(osd_command_thread_suicide_timeout, OPT_INT, 15*60) OPTION(osd_age, OPT_FLOAT, .8) OPTION(osd_age_time, OPT_INT, 0) OPTION(osd_heartbeat_addr, OPT_ADDR, entity_addr_t()) OPTION(osd_heartbeat_interval, OPT_INT, 6) // (seconds) how often we ping peers OPTION(osd_heartbeat_grace, OPT_INT, 20) // (seconds) how long before we decide a peer has failed OPTION(osd_heartbeat_min_peers, OPT_INT, 10) // minimum number of peers // max number of parallel snap trims/pg OPTION(osd_pg_max_concurrent_snap_trims, OPT_U64, 2) // minimum number of peers tha tmust be reachable to mark ourselves // back up after being wrongly marked down. OPTION(osd_heartbeat_min_healthy_ratio, OPT_FLOAT, .33) OPTION(osd_mon_heartbeat_interval, OPT_INT, 30) // (seconds) how often to ping monitor if no peers OPTION(osd_mon_report_interval_max, OPT_INT, 120) OPTION(osd_mon_report_interval_min, OPT_INT, 5) // pg stats, failures, up_thru, boot. OPTION(osd_pg_stat_report_interval_max, OPT_INT, 500) // report pg stats for any given pg at least this often OPTION(osd_mon_ack_timeout, OPT_INT, 30) // time out a mon if it doesn't ack stats OPTION(osd_default_data_pool_replay_window, OPT_INT, 45) OPTION(osd_preserve_trimmed_log, OPT_BOOL, false) OPTION(osd_auto_mark_unfound_lost, OPT_BOOL, false) OPTION(osd_recovery_delay_start, OPT_FLOAT, 0) OPTION(osd_recovery_max_active, OPT_INT, 15) OPTION(osd_recovery_max_single_start, OPT_INT, 5) OPTION(osd_recovery_max_chunk, OPT_U64, 8<<20) // max size of push chunk OPTION(osd_copyfrom_max_chunk, OPT_U64, 8<<20) // max size of a COPYFROM chunk OPTION(osd_push_per_object_cost, OPT_U64, 1000) // push cost per object OPTION(osd_max_push_cost, OPT_U64, 8<<20) // max size of push message OPTION(osd_max_push_objects, OPT_U64, 10) // max objects in single push op OPTION(osd_recovery_forget_lost_objects, OPT_BOOL, false) // off for now OPTION(osd_max_scrubs, OPT_INT, 1) OPTION(osd_scrub_load_threshold, OPT_FLOAT, 0.5) OPTION(osd_scrub_min_interval, OPT_FLOAT, 60*60*24) // if load is low OPTION(osd_scrub_max_interval, OPT_FLOAT, 7*60*60*24) // regardless of load OPTION(osd_scrub_chunk_min, OPT_INT, 5) OPTION(osd_scrub_chunk_max, OPT_INT, 25) OPTION(osd_scrub_sleep, OPT_FLOAT, 0) // sleep between [deep]scrub ops OPTION(osd_deep_scrub_interval, OPT_FLOAT, 60*60*24*7) // once a week OPTION(osd_deep_scrub_stride, OPT_INT, 524288) OPTION(osd_scan_list_ping_tp_interval, OPT_U64, 100) OPTION(osd_auto_weight, OPT_BOOL, false) OPTION(osd_class_dir, OPT_STR, CEPH_LIBDIR "/rados-classes") // where rados plugins are stored OPTION(osd_open_classes_on_start, OPT_BOOL, true) OPTION(osd_check_for_log_corruption, OPT_BOOL, false) OPTION(osd_use_stale_snap, OPT_BOOL, false) OPTION(osd_rollback_to_cluster_snap, OPT_STR, "") OPTION(osd_default_notify_timeout, OPT_U32, 30) // default notify timeout in seconds OPTION(osd_kill_backfill_at, OPT_INT, 0) // Bounds how infrequently a new map epoch will be persisted for a pg OPTION(osd_pg_epoch_persisted_max_stale, OPT_U32, 200) OPTION(osd_min_pg_log_entries, OPT_U32, 3000) // number of entries to keep in the pg log when trimming it OPTION(osd_max_pg_log_entries, OPT_U32, 10000) // max entries, say when degraded, before we trim OPTION(osd_op_complaint_time, OPT_FLOAT, 30) // how many seconds old makes an op complaint-worthy OPTION(osd_command_max_records, OPT_INT, 256) OPTION(osd_op_log_threshold, OPT_INT, 5) // how many op log messages to show in one go OPTION(osd_verify_sparse_read_holes, OPT_BOOL, false) // read fiemap-reported holes and verify they are zeros OPTION(osd_debug_drop_ping_probability, OPT_DOUBLE, 0) OPTION(osd_debug_drop_ping_duration, OPT_INT, 0) OPTION(osd_debug_drop_pg_create_probability, OPT_DOUBLE, 0) OPTION(osd_debug_drop_pg_create_duration, OPT_INT, 1) OPTION(osd_debug_drop_op_probability, OPT_DOUBLE, 0) // probability of stalling/dropping a client op OPTION(osd_debug_op_order, OPT_BOOL, false) OPTION(osd_debug_verify_snaps_on_info, OPT_BOOL, false) OPTION(osd_debug_verify_stray_on_activate, OPT_BOOL, false) OPTION(osd_debug_skip_full_check_in_backfill_reservation, OPT_BOOL, false) OPTION(osd_debug_reject_backfill_probability, OPT_DOUBLE, 0) OPTION(osd_enable_op_tracker, OPT_BOOL, true) // enable/disable OSD op tracking OPTION(osd_op_history_size, OPT_U32, 20) // Max number of completed ops to track OPTION(osd_op_history_duration, OPT_U32, 600) // Oldest completed op to track OPTION(osd_target_transaction_size, OPT_INT, 30) // to adjust various transactions that batch smaller items OPTION(osd_failsafe_full_ratio, OPT_FLOAT, .97) // what % full makes an OSD "full" (failsafe) OPTION(osd_failsafe_nearfull_ratio, OPT_FLOAT, .90) // what % full makes an OSD near full (failsafe) OPTION(osd_leveldb_write_buffer_size, OPT_U64, 0) // OSD's leveldb write buffer size OPTION(osd_leveldb_cache_size, OPT_U64, 0) // OSD's leveldb cache size OPTION(osd_leveldb_block_size, OPT_U64, 0) // OSD's leveldb block size OPTION(osd_leveldb_bloom_size, OPT_INT, 0) // OSD's leveldb bloom bits per entry OPTION(osd_leveldb_max_open_files, OPT_INT, 0) // OSD's leveldb max open files OPTION(osd_leveldb_compression, OPT_BOOL, true) // OSD's leveldb uses compression OPTION(osd_leveldb_paranoid, OPT_BOOL, false) // OSD's leveldb paranoid flag OPTION(osd_leveldb_log, OPT_STR, "") // enable OSD leveldb log file // determines whether PGLog::check() compares written out log to stored log OPTION(osd_debug_pg_log_writeout, OPT_BOOL, false) // default timeout while caling WaitInterval on an empty queue OPTION(threadpool_default_timeout, OPT_INT, 60) // default wait time for an empty queue before pinging the hb timeout OPTION(threadpool_empty_queue_max_wait, OPT_INT, 2) OPTION(leveldb_write_buffer_size, OPT_U64, 8 *1024*1024) // leveldb write buffer size OPTION(leveldb_cache_size, OPT_U64, 128 *1024*1024) // leveldb cache size OPTION(leveldb_block_size, OPT_U64, 0) // leveldb block size OPTION(leveldb_bloom_size, OPT_INT, 0) // leveldb bloom bits per entry OPTION(leveldb_max_open_files, OPT_INT, 0) // leveldb max open files OPTION(leveldb_compression, OPT_BOOL, true) // leveldb uses compression OPTION(leveldb_paranoid, OPT_BOOL, false) // leveldb paranoid flag OPTION(leveldb_log, OPT_STR, "/dev/null") // enable leveldb log file OPTION(leveldb_compact_on_mount, OPT_BOOL, false) /** * osd_client_op_priority and osd_recovery_op_priority adjust the relative * priority of client io vs recovery io. * * osd_client_op_priority/osd_recovery_op_priority determines the ratio of * available io between client and recovery. Each option may be set between * 1..63. * * osd_recovery_op_warn_multiple scales the normal warning threshhold, * osd_op_complaint_time, so that slow recovery ops won't cause noise */ OPTION(osd_client_op_priority, OPT_U32, 63) OPTION(osd_recovery_op_priority, OPT_U32, 10) OPTION(osd_recovery_op_warn_multiple, OPT_U32, 16) // Max time to wait between notifying mon of shutdown and shutting down OPTION(osd_mon_shutdown_timeout, OPT_DOUBLE, 5) OPTION(osd_max_object_size, OPT_U64, 100*1024L*1024L*1024L) // OSD's maximum object size OPTION(osd_max_attr_size, OPT_U64, 0) OPTION(osd_objectstore, OPT_STR, "filestore") // ObjectStore backend type // Override maintaining compatibility with older OSDs // Set to true for testing. Users should NOT set this. OPTION(osd_debug_override_acting_compat, OPT_BOOL, false) OPTION(osd_bench_small_size_max_iops, OPT_U32, 100) // 100 IOPS OPTION(osd_bench_large_size_max_throughput, OPT_U64, 100 << 20) // 100 MB/s OPTION(osd_bench_max_block_size, OPT_U64, 64 << 20) // cap the block size at 64MB OPTION(osd_bench_duration, OPT_U32, 30) // duration of 'osd bench', capped at 30s to avoid triggering timeouts OPTION(filestore_debug_disable_sharded_check, OPT_BOOL, false) /// filestore wb throttle limits OPTION(filestore_wbthrottle_enable, OPT_BOOL, true) OPTION(filestore_wbthrottle_btrfs_bytes_start_flusher, OPT_U64, 41943040) OPTION(filestore_wbthrottle_btrfs_bytes_hard_limit, OPT_U64, 419430400) OPTION(filestore_wbthrottle_btrfs_ios_start_flusher, OPT_U64, 500) OPTION(filestore_wbthrottle_btrfs_ios_hard_limit, OPT_U64, 5000) OPTION(filestore_wbthrottle_btrfs_inodes_start_flusher, OPT_U64, 500) OPTION(filestore_wbthrottle_xfs_bytes_start_flusher, OPT_U64, 41943040) OPTION(filestore_wbthrottle_xfs_bytes_hard_limit, OPT_U64, 419430400) OPTION(filestore_wbthrottle_xfs_ios_start_flusher, OPT_U64, 500) OPTION(filestore_wbthrottle_xfs_ios_hard_limit, OPT_U64, 5000) OPTION(filestore_wbthrottle_xfs_inodes_start_flusher, OPT_U64, 500) /// These must be less than the fd limit OPTION(filestore_wbthrottle_btrfs_inodes_hard_limit, OPT_U64, 5000) OPTION(filestore_wbthrottle_xfs_inodes_hard_limit, OPT_U64, 5000) // Tests index failure paths OPTION(filestore_index_retry_probability, OPT_DOUBLE, 0) // Allow object read error injection OPTION(filestore_debug_inject_read_err, OPT_BOOL, false) OPTION(filestore_debug_omap_check, OPT_BOOL, 0) // Expensive debugging check on sync // Use omap for xattrs for attrs over // filestore_max_inline_xattr_size or OPTION(filestore_max_inline_xattr_size, OPT_U32, 0) //Override OPTION(filestore_max_inline_xattr_size_xfs, OPT_U32, 65536) OPTION(filestore_max_inline_xattr_size_btrfs, OPT_U32, 2048) OPTION(filestore_max_inline_xattr_size_other, OPT_U32, 512) // for more than filestore_max_inline_xattrs attrs OPTION(filestore_max_inline_xattrs, OPT_U32, 0) //Override OPTION(filestore_max_inline_xattrs_xfs, OPT_U32, 10) OPTION(filestore_max_inline_xattrs_btrfs, OPT_U32, 10) OPTION(filestore_max_inline_xattrs_other, OPT_U32, 2) OPTION(filestore_sloppy_crc, OPT_BOOL, false) // track sloppy crcs OPTION(filestore_sloppy_crc_block_size, OPT_INT, 65536) OPTION(filestore_max_alloc_hint_size, OPT_U64, 1ULL << 20) // bytes OPTION(filestore_max_sync_interval, OPT_DOUBLE, 5) // seconds OPTION(filestore_min_sync_interval, OPT_DOUBLE, .01) // seconds OPTION(filestore_btrfs_snap, OPT_BOOL, true) OPTION(filestore_btrfs_clone_range, OPT_BOOL, true) OPTION(filestore_zfs_snap, OPT_BOOL, false) // zfsonlinux is still unstable OPTION(filestore_fsync_flushes_journal_data, OPT_BOOL, false) OPTION(filestore_fiemap, OPT_BOOL, false) // (try to) use fiemap // (try to) use extsize for alloc hint // WARNING: extsize seems to trigger data corruption in xfs -- that is why it is // off by default, see bug #8830 OPTION(filestore_xfs_extsize, OPT_BOOL, false) OPTION(filestore_journal_parallel, OPT_BOOL, false) OPTION(filestore_journal_writeahead, OPT_BOOL, false) OPTION(filestore_journal_trailing, OPT_BOOL, false) OPTION(filestore_queue_max_ops, OPT_INT, 50) OPTION(filestore_queue_max_bytes, OPT_INT, 100 << 20) OPTION(filestore_queue_committing_max_ops, OPT_INT, 500) // this is ON TOP of filestore_queue_max_* OPTION(filestore_queue_committing_max_bytes, OPT_INT, 100 << 20) // " OPTION(filestore_op_threads, OPT_INT, 2) OPTION(filestore_op_thread_timeout, OPT_INT, 60) OPTION(filestore_op_thread_suicide_timeout, OPT_INT, 180) OPTION(filestore_commit_timeout, OPT_FLOAT, 600) OPTION(filestore_fiemap_threshold, OPT_INT, 4096) OPTION(filestore_merge_threshold, OPT_INT, 10) OPTION(filestore_split_multiple, OPT_INT, 2) OPTION(filestore_update_to, OPT_INT, 1000) OPTION(filestore_blackhole, OPT_BOOL, false) // drop any new transactions on the floor OPTION(filestore_fd_cache_size, OPT_INT, 128) // FD lru size OPTION(filestore_dump_file, OPT_STR, "") // file onto which store transaction dumps OPTION(filestore_kill_at, OPT_INT, 0) // inject a failure at the n'th opportunity OPTION(filestore_inject_stall, OPT_INT, 0) // artificially stall for N seconds in op queue thread OPTION(filestore_fail_eio, OPT_BOOL, true) // fail/crash on EIO OPTION(filestore_replica_fadvise, OPT_BOOL, true) OPTION(filestore_debug_verify_split, OPT_BOOL, false) OPTION(journal_dio, OPT_BOOL, true) OPTION(journal_aio, OPT_BOOL, true) OPTION(journal_force_aio, OPT_BOOL, false) OPTION(keyvaluestore_queue_max_ops, OPT_INT, 50) OPTION(keyvaluestore_queue_max_bytes, OPT_INT, 100 << 20) OPTION(keyvaluestore_debug_check_backend, OPT_BOOL, 0) // Expensive debugging check on sync OPTION(keyvaluestore_op_threads, OPT_INT, 2) OPTION(keyvaluestore_op_thread_timeout, OPT_INT, 60) OPTION(keyvaluestore_op_thread_suicide_timeout, OPT_INT, 180) OPTION(keyvaluestore_default_strip_size, OPT_INT, 4096) // Only affect new object OPTION(keyvaluestore_max_expected_write_size, OPT_U64, 1ULL << 24) // bytes OPTION(keyvaluestore_header_cache_size, OPT_INT, 4096) // Header cache size // max bytes to search ahead in journal searching for corruption OPTION(journal_max_corrupt_search, OPT_U64, 10<<20) OPTION(journal_block_align, OPT_BOOL, true) OPTION(journal_write_header_frequency, OPT_U64, 0) OPTION(journal_max_write_bytes, OPT_INT, 10 << 20) OPTION(journal_max_write_entries, OPT_INT, 100) OPTION(journal_queue_max_ops, OPT_INT, 300) OPTION(journal_queue_max_bytes, OPT_INT, 32 << 20) OPTION(journal_align_min_size, OPT_INT, 64 << 10) // align data payloads >= this. OPTION(journal_replay_from, OPT_INT, 0) OPTION(journal_zero_on_create, OPT_BOOL, false) OPTION(journal_ignore_corruption, OPT_BOOL, false) // assume journal is not corrupt OPTION(rados_mon_op_timeout, OPT_DOUBLE, 0) // how many seconds to wait for a response from the monitor before returning an error from a rados operation. 0 means on limit. OPTION(rados_osd_op_timeout, OPT_DOUBLE, 0) // how many seconds to wait for a response from osds before returning an error from a rados operation. 0 means no limit. OPTION(rbd_op_threads, OPT_INT, 1) OPTION(rbd_op_thread_timeout, OPT_INT, 60) OPTION(rbd_non_blocking_aio, OPT_BOOL, true) // process AIO ops from a worker thread to prevent blocking OPTION(rbd_cache, OPT_BOOL, false) // whether to enable caching (writeback unless rbd_cache_max_dirty is 0) OPTION(rbd_cache_writethrough_until_flush, OPT_BOOL, false) // whether to make writeback caching writethrough until flush is called, to be sure the user of librbd will send flushs so that writeback is safe OPTION(rbd_cache_size, OPT_LONGLONG, 32<<20) // cache size in bytes OPTION(rbd_cache_max_dirty, OPT_LONGLONG, 24<<20) // dirty limit in bytes - set to 0 for write-through caching OPTION(rbd_cache_target_dirty, OPT_LONGLONG, 16<<20) // target dirty limit in bytes OPTION(rbd_cache_max_dirty_age, OPT_FLOAT, 1.0) // seconds in cache before writeback starts OPTION(rbd_cache_max_dirty_object, OPT_INT, 0) // dirty limit for objects - set to 0 for auto calculate from rbd_cache_size OPTION(rbd_cache_block_writes_upfront, OPT_BOOL, false) // whether to block writes to the cache before the aio_write call completes (true), or block before the aio completion is called (false) OPTION(rbd_concurrent_management_ops, OPT_INT, 10) // how many operations can be in flight for a management operation like deleting or resizing an image OPTION(rbd_balance_snap_reads, OPT_BOOL, false) OPTION(rbd_localize_snap_reads, OPT_BOOL, false) OPTION(rbd_balance_parent_reads, OPT_BOOL, false) OPTION(rbd_localize_parent_reads, OPT_BOOL, true) /* * The following options change the behavior for librbd's image creation methods that * don't require all of the parameters. These are provided so that older programs * can take advantage of newer features without being rewritten to use new versions * of the image creation functions. * * rbd_create()/RBD::create() are affected by all of these options. * * rbd_create2()/RBD::create2() and rbd_clone()/RBD::clone() are affected by: * - rbd_default_order * - rbd_default_stripe_count * - rbd_default_stripe_size * * rbd_create3()/RBD::create3() and rbd_clone2/RBD::clone2() are only * affected by rbd_default_order. */ OPTION(rbd_default_format, OPT_INT, 1) OPTION(rbd_default_order, OPT_INT, 22) OPTION(rbd_default_stripe_count, OPT_U64, 1) // changing requires stripingv2 feature OPTION(rbd_default_stripe_unit, OPT_U64, 4194304) // changing to non-object size requires stripingv2 feature OPTION(rbd_default_features, OPT_INT, 3) // 1 for layering, 3 for layering+stripingv2. only applies to format 2 images OPTION(nss_db_path, OPT_STR, "") // path to nss db OPTION(rgw_max_chunk_size, OPT_INT, 512 * 1024) OPTION(rgw_data, OPT_STR, "/var/lib/ceph/radosgw/$cluster-$id") OPTION(rgw_enable_apis, OPT_STR, "s3, swift, swift_auth, admin") OPTION(rgw_cache_enabled, OPT_BOOL, true) // rgw cache enabled OPTION(rgw_cache_lru_size, OPT_INT, 10000) // num of entries in rgw cache OPTION(rgw_socket_path, OPT_STR, "") // path to unix domain socket, if not specified, rgw will not run as external fcgi OPTION(rgw_host, OPT_STR, "") // host for radosgw, can be an IP, default is 0.0.0.0 OPTION(rgw_port, OPT_STR, "") // port to listen, format as "8080" "5000", if not specified, rgw will not run external fcgi OPTION(rgw_fcgi_explicit_free, OPT_BOOL, true) // whether to call FCGX_Free explicitly on every complete request OPTION(rgw_dns_name, OPT_STR, "") OPTION(rgw_script_uri, OPT_STR, "") // alternative value for SCRIPT_URI if not set in request OPTION(rgw_request_uri, OPT_STR, "") // alternative value for REQUEST_URI if not set in request OPTION(rgw_swift_url, OPT_STR, "") // the swift url, being published by the internal swift auth OPTION(rgw_swift_url_prefix, OPT_STR, "swift") // entry point for which a url is considered a swift url OPTION(rgw_swift_auth_url, OPT_STR, "") // default URL to go and verify tokens for v1 auth (if not using internal swift auth) OPTION(rgw_swift_auth_entry, OPT_STR, "auth") // entry point for which a url is considered a swift auth url OPTION(rgw_swift_tenant_name, OPT_STR, "") // tenant name to use for swift access OPTION(rgw_swift_enforce_content_length, OPT_BOOL, false) // enforce generation of Content-Length even in cost of performance or scalability OPTION(rgw_keystone_url, OPT_STR, "") // url for keystone server OPTION(rgw_keystone_admin_token, OPT_STR, "") // keystone admin token (shared secret) OPTION(rgw_keystone_admin_user, OPT_STR, "") // keystone admin user name OPTION(rgw_keystone_admin_password, OPT_STR, "") // keystone admin user password OPTION(rgw_keystone_admin_tenant, OPT_STR, "") // keystone admin user tenant OPTION(rgw_keystone_accepted_roles, OPT_STR, "Member, admin") // roles required to serve requests OPTION(rgw_keystone_token_cache_size, OPT_INT, 10000) // max number of entries in keystone token cache OPTION(rgw_keystone_revocation_interval, OPT_INT, 15 * 60) // seconds between tokens revocation check OPTION(rgw_s3_auth_use_rados, OPT_BOOL, true) // should we try to use the internal credentials for s3? OPTION(rgw_s3_auth_use_keystone, OPT_BOOL, false) // should we try to use keystone for s3? OPTION(rgw_admin_entry, OPT_STR, "admin") // entry point for which a url is considered an admin request OPTION(rgw_enforce_swift_acls, OPT_BOOL, true) OPTION(rgw_swift_token_expiration, OPT_INT, 24 * 3600) // time in seconds for swift token expiration OPTION(rgw_print_continue, OPT_BOOL, true) // enable if 100-Continue works OPTION(rgw_remote_addr_param, OPT_STR, "REMOTE_ADDR") // e.g. X-Forwarded-For, if you have a reverse proxy OPTION(rgw_op_thread_timeout, OPT_INT, 10*60) OPTION(rgw_op_thread_suicide_timeout, OPT_INT, 0) OPTION(rgw_thread_pool_size, OPT_INT, 100) OPTION(rgw_num_control_oids, OPT_INT, 8) OPTION(rgw_zone, OPT_STR, "") // zone name OPTION(rgw_zone_root_pool, OPT_STR, ".rgw.root") // pool where zone specific info is stored OPTION(rgw_region, OPT_STR, "") // region name OPTION(rgw_region_root_pool, OPT_STR, ".rgw.root") // pool where all region info is stored OPTION(rgw_default_region_info_oid, OPT_STR, "default.region") // oid where default region info is stored OPTION(rgw_log_nonexistent_bucket, OPT_BOOL, false) OPTION(rgw_log_object_name, OPT_STR, "%Y-%m-%d-%H-%i-%n") // man date to see codes (a subset are supported) OPTION(rgw_log_object_name_utc, OPT_BOOL, false) OPTION(rgw_usage_max_shards, OPT_INT, 32) OPTION(rgw_usage_max_user_shards, OPT_INT, 1) OPTION(rgw_enable_ops_log, OPT_BOOL, false) // enable logging every rgw operation OPTION(rgw_enable_usage_log, OPT_BOOL, false) // enable logging bandwidth usage OPTION(rgw_ops_log_rados, OPT_BOOL, true) // whether ops log should go to rados OPTION(rgw_ops_log_socket_path, OPT_STR, "") // path to unix domain socket where ops log can go OPTION(rgw_ops_log_data_backlog, OPT_INT, 5 << 20) // max data backlog for ops log OPTION(rgw_usage_log_flush_threshold, OPT_INT, 1024) // threshold to flush pending log data OPTION(rgw_usage_log_tick_interval, OPT_INT, 30) // flush pending log data every X seconds OPTION(rgw_intent_log_object_name, OPT_STR, "%Y-%m-%d-%i-%n") // man date to see codes (a subset are supported) OPTION(rgw_intent_log_object_name_utc, OPT_BOOL, false) OPTION(rgw_init_timeout, OPT_INT, 300) // time in seconds OPTION(rgw_mime_types_file, OPT_STR, "/etc/mime.types") OPTION(rgw_gc_max_objs, OPT_INT, 32) OPTION(rgw_gc_obj_min_wait, OPT_INT, 2 * 3600) // wait time before object may be handled by gc OPTION(rgw_gc_processor_max_time, OPT_INT, 3600) // total run time for a single gc processor work OPTION(rgw_gc_processor_period, OPT_INT, 3600) // gc processor cycle time OPTION(rgw_s3_success_create_obj_status, OPT_INT, 0) // alternative success status response for create-obj (0 - default) OPTION(rgw_resolve_cname, OPT_BOOL, false) // should rgw try to resolve hostname as a dns cname record OPTION(rgw_obj_stripe_size, OPT_INT, 4 << 20) OPTION(rgw_extended_http_attrs, OPT_STR, "") // list of extended attrs that can be set on objects (beyond the default) OPTION(rgw_exit_timeout_secs, OPT_INT, 120) // how many seconds to wait for process to go down before exiting unconditionally OPTION(rgw_get_obj_window_size, OPT_INT, 16 << 20) // window size in bytes for single get obj request OPTION(rgw_get_obj_max_req_size, OPT_INT, 4 << 20) // max length of a single get obj rados op OPTION(rgw_relaxed_s3_bucket_names, OPT_BOOL, false) // enable relaxed bucket name rules for US region buckets OPTION(rgw_defer_to_bucket_acls, OPT_STR, "") // if the user has bucket perms, use those before key perms (recurse and full_control) OPTION(rgw_list_buckets_max_chunk, OPT_INT, 1000) // max buckets to retrieve in a single op when listing user buckets OPTION(rgw_md_log_max_shards, OPT_INT, 64) // max shards for metadata log OPTION(rgw_num_zone_opstate_shards, OPT_INT, 128) // max shards for keeping inter-region copy progress info OPTION(rgw_opstate_ratelimit_sec, OPT_INT, 30) // min time between opstate updates on a single upload (0 for disabling ratelimit) OPTION(rgw_curl_wait_timeout_ms, OPT_INT, 1000) // timeout for certain curl calls OPTION(rgw_copy_obj_progress, OPT_BOOL, true) // should dump progress during long copy operations? OPTION(rgw_copy_obj_progress_every_bytes, OPT_INT, 1024 * 1024) // min bytes between copy progress output OPTION(rgw_data_log_window, OPT_INT, 30) // data log entries window (in seconds) OPTION(rgw_data_log_changes_size, OPT_INT, 1000) // number of in-memory entries to hold for data changes log OPTION(rgw_data_log_num_shards, OPT_INT, 128) // number of objects to keep data changes log on OPTION(rgw_data_log_obj_prefix, OPT_STR, "data_log") // OPTION(rgw_replica_log_obj_prefix, OPT_STR, "replica_log") // OPTION(rgw_bucket_quota_ttl, OPT_INT, 600) // time for cached bucket stats to be cached within rgw instance OPTION(rgw_bucket_quota_soft_threshold, OPT_DOUBLE, 0.95) // threshold from which we don't rely on cached info for quota decisions OPTION(rgw_bucket_quota_cache_size, OPT_INT, 10000) // number of entries in bucket quota cache OPTION(rgw_expose_bucket, OPT_BOOL, false) // Return the bucket name in the 'Bucket' response header OPTION(rgw_frontends, OPT_STR, "") // alternative front ends OPTION(rgw_user_quota_bucket_sync_interval, OPT_INT, 180) // time period for accumulating modified buckets before syncing stats OPTION(rgw_user_quota_sync_interval, OPT_INT, 3600 * 24) // time period for accumulating modified buckets before syncing entire user stats OPTION(rgw_user_quota_sync_idle_users, OPT_BOOL, false) // whether stats for idle users be fully synced OPTION(rgw_user_quota_sync_wait_time, OPT_INT, 3600 * 24) // min time between two full stats syc for non-idle users OPTION(rgw_multipart_min_part_size, OPT_INT, 5 * 1024 * 1024) // min size for each part (except for last one) in multipart upload OPTION(mutex_perf_counter, OPT_BOOL, false) // enable/disable mutex perf counter OPTION(throttler_perf_counter, OPT_BOOL, true) // enable/disable throttler perf counter // This will be set to true when it is safe to start threads. // Once it is true, it will never change. OPTION(internal_safe_to_start_threads, OPT_BOOL, false) ceph-0.80.11/src/common/crc32c_intel_fast_zero_asm.S0000664000175100017510000006133212623076744024273 0ustar jenkins-buildjenkins-build; ; Copyright 2012-2013 Intel Corporation All Rights Reserved. ; All rights reserved. ; ; http://opensource.org/licenses/BSD-3-Clause ; ; 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 the Intel Corporation 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 HOLDER 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. ; ; Function to compute iscsi CRC32 with table-based recombination ; crc done "by 3" with block sizes 1920, 960, 480, 240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; crcB3 MACRO to implement crc32 on 3 %%bSize-byte blocks %macro crcB3 3 %define %%bSize %1 ; 1/3 of buffer size %define %%td2 %2 ; table offset for crc0 (2/3 of buffer) %define %%td1 %3 ; table offset for crc1 (1/3 of buffer) %IF %%bSize=640 sub len, %%bSize*3 js %%crcB3_end ;; jump to next level if 3*blockSize > len %ELSE cmp len, %%bSize*3 jnae %%crcB3_end ;; jump to next level if 3*blockSize > len %ENDIF ;;;;;; Calculate CRC of 3 blocks of the buffer ;;;;;; %%crcB3_loop: ;; rax = crc0 = initial crc xor rbx, rbx ;; rbx = crc1 = 0; xor r10, r10 ;; r10 = crc2 = 0; %assign i 0 %rep %%bSize/8 - 1 crc32 rax, bufptmp ;; update crc0 crc32 rbx, bufptmp ;; update crc1 crc32 r10, bufptmp ;; update crc2 %assign i (i+8) %endrep crc32 rax, bufptmp ;; update crc0 crc32 rbx, bufptmp ;; update crc1 ; SKIP ;crc32 r10, bufptmp ;; update crc2 ; merge in crc0 movzx bufp_dw, al mov r9d, [crc_init + bufp*4 + %%td2] movzx bufp_dw, ah shr eax, 16 mov r11d, [crc_init + bufp*4 + %%td2] shl r11, 8 xor r9, r11 movzx bufp_dw, al mov r11d, [crc_init + bufp*4 + %%td2] movzx bufp_dw, ah shl r11, 16 xor r9, r11 mov r11d, [crc_init + bufp*4 + %%td2] shl r11, 24 xor r9, r11 ; merge in crc1 movzx bufp_dw, bl mov r11d, [crc_init + bufp*4 + %%td1] movzx bufp_dw, bh shr ebx, 16 xor r9, r11 mov r11d, [crc_init + bufp*4 + %%td1] shl r11, 8 xor r9, r11 movzx bufp_dw, bl mov r11d, [crc_init + bufp*4 + %%td1] movzx bufp_dw, bh shl r11, 16 xor r9, r11 mov r11d, [crc_init + bufp*4 + %%td1] shl r11, 24 xor r9, r11 ; xor r9, [bufptmp+i + 2*%%bSize] crc32 r10, r9 mov rax, r10 ; add bufptmp, %%bSize*3 ;; move to next block sub len, %%bSize*3 %IF %%bSize=640 jns %%crcB3_loop %ENDIF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %%crcB3_end: %IF %%bSize=640 add len, %%bSize*3 %ENDIF je do_return ;; return if remaining data is zero %endmacro ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ISCSI CRC 32 Implementation with crc32 Instruction ;;; unsigned int crc32_iscsi_00(unsigned char * buffer, int len, unsigned int crc_init); ;;; ;;; *buf = rcx ;;; len = rdx ;;; crc_init = r8 ;;; global crc32_iscsi_zero_00:function crc32_iscsi_zero_00: %ifidn __OUTPUT_FORMAT__, elf64 %define bufp rdi %define bufp_dw edi %define bufp_w di %define bufp_b dil %define bufptmp rcx %define block_0 rcx %define block_1 r8 %define block_2 r11 %define len rsi %define len_dw esi %define len_w si %define len_b sil %define crc_init rdx %define crc_init_dw edx %else %define bufp rcx %define bufp_dw ecx %define bufp_w cx %define bufp_b cl %define bufptmp rdi %define block_0 rdi %define block_1 rsi %define block_2 r11 %define len rdx %define len_dw edx %define len_w dx %define len_b dl %define crc_init r8 %define crc_init_dw r8d %endif push rdi push rbx mov rax, crc_init ;; rax = crc_init; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 1) ALIGN: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; no need for alignment xor bufptmp, bufptmp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 2) BLOCK LEVEL: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; proc_block: cmp len, 240 jb bit8 lea crc_init, [mul_table_72 wrt rip] ;; load table base address crcB3 640, 0x1000, 0x0c00 ; 640*3 = 1920 (Tables 1280, 640) crcB3 320, 0x0c00, 0x0800 ; 320*3 = 960 (Tables 640, 320) crcB3 160, 0x0800, 0x0400 ; 160*3 = 480 (Tables 320, 160) crcB3 80, 0x0400, 0x0000 ; 80*3 = 240 (Tables 160, 80) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;4) LESS THAN 256-bytes REMAIN AT THIS POINT (8-bits of rdx are full) bit8: shl len_b, 1 ;; shift-out MSB (bit-7) jnc bit7 ;; jump to bit-6 if bit-7 == 0 %assign i 0 %rep 16 crc32 rax, bufptmp ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero bit7: shl len_b, 1 ;; shift-out MSB (bit-7) jnc bit6 ;; jump to bit-6 if bit-7 == 0 %assign i 0 %rep 8 crc32 rax, bufptmp ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero ; add bufptmp, 64 ;; buf +=64; (next 64 bytes) bit6: shl len_b, 1 ;; shift-out MSB (bit-6) jnc bit5 ;; jump to bit-5 if bit-6 == 0 %assign i 0 %rep 4 crc32 rax, bufptmp ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero ; add bufptmp, 32 ;; buf +=32; (next 32 bytes) bit5: shl len_b, 1 ;; shift-out MSB (bit-5) jnc bit4 ;; jump to bit-4 if bit-5 == 0 %assign i 0 %rep 2 crc32 rax, bufptmp ;; compute crc32 of 8-byte data %assign i (i+8) %endrep je do_return ;; return if remaining data is zero ; add bufptmp, 16 ;; buf +=16; (next 16 bytes) bit4: shl len_b, 1 ;; shift-out MSB (bit-4) jnc bit3 ;; jump to bit-3 if bit-4 == 0 crc32 rax, bufptmp ;; compute crc32 of 8-byte data je do_return ;; return if remaining data is zero ; add bufptmp, 8 ;; buf +=8; (next 8 bytes) bit3: mov rbx, bufptmp ;; load a 8-bytes from the buffer: shl len_b, 1 ;; shift-out MSB (bit-3) jnc bit2 ;; jump to bit-2 if bit-3 == 0 crc32 eax, ebx ;; compute crc32 of 4-byte data je do_return ;; return if remaining data is zero shr rbx, 32 ;; get next 3 bytes bit2: shl len_b, 1 ;; shift-out MSB (bit-2) jnc bit1 ;; jump to bit-1 if bit-2 == 0 crc32 eax, bx ;; compute crc32 of 2-byte data je do_return ;; return if remaining data is zero shr rbx, 16 ;; next byte bit1: test len_b,len_b je do_return crc32 eax, bl ;; compute crc32 of 1-byte data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do_return: pop rbx pop rdi ret less_than_8: xor bufp, bufp test len,4 jz less_than_4 crc32 eax, bufp_dw add bufptmp,4 less_than_4: test len,2 jz less_than_2 crc32 eax, bufp_w add bufptmp,2 less_than_2: test len,1 jz do_return crc32 rax, bufp_b pop rbx pop bufptmp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; global mul_table_72, mul_table_152, mul_table_312, mul_table_632, mul_table_1272 section .data align 8 mul_table_72: DD 0x00000000,0x39d3b296,0x73a7652c,0x4a74d7ba DD 0xe74eca58,0xde9d78ce,0x94e9af74,0xad3a1de2 DD 0xcb71e241,0xf2a250d7,0xb8d6876d,0x810535fb DD 0x2c3f2819,0x15ec9a8f,0x5f984d35,0x664bffa3 DD 0x930fb273,0xaadc00e5,0xe0a8d75f,0xd97b65c9 DD 0x7441782b,0x4d92cabd,0x07e61d07,0x3e35af91 DD 0x587e5032,0x61ade2a4,0x2bd9351e,0x120a8788 DD 0xbf309a6a,0x86e328fc,0xcc97ff46,0xf5444dd0 DD 0x23f31217,0x1a20a081,0x5054773b,0x6987c5ad DD 0xc4bdd84f,0xfd6e6ad9,0xb71abd63,0x8ec90ff5 DD 0xe882f056,0xd15142c0,0x9b25957a,0xa2f627ec DD 0x0fcc3a0e,0x361f8898,0x7c6b5f22,0x45b8edb4 DD 0xb0fca064,0x892f12f2,0xc35bc548,0xfa8877de DD 0x57b26a3c,0x6e61d8aa,0x24150f10,0x1dc6bd86 DD 0x7b8d4225,0x425ef0b3,0x082a2709,0x31f9959f DD 0x9cc3887d,0xa5103aeb,0xef64ed51,0xd6b75fc7 DD 0x47e6242e,0x7e3596b8,0x34414102,0x0d92f394 DD 0xa0a8ee76,0x997b5ce0,0xd30f8b5a,0xeadc39cc DD 0x8c97c66f,0xb54474f9,0xff30a343,0xc6e311d5 DD 0x6bd90c37,0x520abea1,0x187e691b,0x21addb8d DD 0xd4e9965d,0xed3a24cb,0xa74ef371,0x9e9d41e7 DD 0x33a75c05,0x0a74ee93,0x40003929,0x79d38bbf DD 0x1f98741c,0x264bc68a,0x6c3f1130,0x55eca3a6 DD 0xf8d6be44,0xc1050cd2,0x8b71db68,0xb2a269fe DD 0x64153639,0x5dc684af,0x17b25315,0x2e61e183 DD 0x835bfc61,0xba884ef7,0xf0fc994d,0xc92f2bdb DD 0xaf64d478,0x96b766ee,0xdcc3b154,0xe51003c2 DD 0x482a1e20,0x71f9acb6,0x3b8d7b0c,0x025ec99a DD 0xf71a844a,0xcec936dc,0x84bde166,0xbd6e53f0 DD 0x10544e12,0x2987fc84,0x63f32b3e,0x5a2099a8 DD 0x3c6b660b,0x05b8d49d,0x4fcc0327,0x761fb1b1 DD 0xdb25ac53,0xe2f61ec5,0xa882c97f,0x91517be9 DD 0x8fcc485c,0xb61ffaca,0xfc6b2d70,0xc5b89fe6 DD 0x68828204,0x51513092,0x1b25e728,0x22f655be DD 0x44bdaa1d,0x7d6e188b,0x371acf31,0x0ec97da7 DD 0xa3f36045,0x9a20d2d3,0xd0540569,0xe987b7ff DD 0x1cc3fa2f,0x251048b9,0x6f649f03,0x56b72d95 DD 0xfb8d3077,0xc25e82e1,0x882a555b,0xb1f9e7cd DD 0xd7b2186e,0xee61aaf8,0xa4157d42,0x9dc6cfd4 DD 0x30fcd236,0x092f60a0,0x435bb71a,0x7a88058c DD 0xac3f5a4b,0x95ece8dd,0xdf983f67,0xe64b8df1 DD 0x4b719013,0x72a22285,0x38d6f53f,0x010547a9 DD 0x674eb80a,0x5e9d0a9c,0x14e9dd26,0x2d3a6fb0 DD 0x80007252,0xb9d3c0c4,0xf3a7177e,0xca74a5e8 DD 0x3f30e838,0x06e35aae,0x4c978d14,0x75443f82 DD 0xd87e2260,0xe1ad90f6,0xabd9474c,0x920af5da DD 0xf4410a79,0xcd92b8ef,0x87e66f55,0xbe35ddc3 DD 0x130fc021,0x2adc72b7,0x60a8a50d,0x597b179b DD 0xc82a6c72,0xf1f9dee4,0xbb8d095e,0x825ebbc8 DD 0x2f64a62a,0x16b714bc,0x5cc3c306,0x65107190 DD 0x035b8e33,0x3a883ca5,0x70fceb1f,0x492f5989 DD 0xe415446b,0xddc6f6fd,0x97b22147,0xae6193d1 DD 0x5b25de01,0x62f66c97,0x2882bb2d,0x115109bb DD 0xbc6b1459,0x85b8a6cf,0xcfcc7175,0xf61fc3e3 DD 0x90543c40,0xa9878ed6,0xe3f3596c,0xda20ebfa DD 0x771af618,0x4ec9448e,0x04bd9334,0x3d6e21a2 DD 0xebd97e65,0xd20accf3,0x987e1b49,0xa1ada9df DD 0x0c97b43d,0x354406ab,0x7f30d111,0x46e36387 DD 0x20a89c24,0x197b2eb2,0x530ff908,0x6adc4b9e DD 0xc7e6567c,0xfe35e4ea,0xb4413350,0x8d9281c6 DD 0x78d6cc16,0x41057e80,0x0b71a93a,0x32a21bac DD 0x9f98064e,0xa64bb4d8,0xec3f6362,0xd5ecd1f4 DD 0xb3a72e57,0x8a749cc1,0xc0004b7b,0xf9d3f9ed DD 0x54e9e40f,0x6d3a5699,0x274e8123,0x1e9d33b5 mul_table_152: DD 0x00000000,0x878a92a7,0x0af953bf,0x8d73c118 DD 0x15f2a77e,0x927835d9,0x1f0bf4c1,0x98816666 DD 0x2be54efc,0xac6fdc5b,0x211c1d43,0xa6968fe4 DD 0x3e17e982,0xb99d7b25,0x34eeba3d,0xb364289a DD 0x57ca9df8,0xd0400f5f,0x5d33ce47,0xdab95ce0 DD 0x42383a86,0xc5b2a821,0x48c16939,0xcf4bfb9e DD 0x7c2fd304,0xfba541a3,0x76d680bb,0xf15c121c DD 0x69dd747a,0xee57e6dd,0x632427c5,0xe4aeb562 DD 0xaf953bf0,0x281fa957,0xa56c684f,0x22e6fae8 DD 0xba679c8e,0x3ded0e29,0xb09ecf31,0x37145d96 DD 0x8470750c,0x03fae7ab,0x8e8926b3,0x0903b414 DD 0x9182d272,0x160840d5,0x9b7b81cd,0x1cf1136a DD 0xf85fa608,0x7fd534af,0xf2a6f5b7,0x752c6710 DD 0xedad0176,0x6a2793d1,0xe75452c9,0x60dec06e DD 0xd3bae8f4,0x54307a53,0xd943bb4b,0x5ec929ec DD 0xc6484f8a,0x41c2dd2d,0xccb11c35,0x4b3b8e92 DD 0x5ac60111,0xdd4c93b6,0x503f52ae,0xd7b5c009 DD 0x4f34a66f,0xc8be34c8,0x45cdf5d0,0xc2476777 DD 0x71234fed,0xf6a9dd4a,0x7bda1c52,0xfc508ef5 DD 0x64d1e893,0xe35b7a34,0x6e28bb2c,0xe9a2298b DD 0x0d0c9ce9,0x8a860e4e,0x07f5cf56,0x807f5df1 DD 0x18fe3b97,0x9f74a930,0x12076828,0x958dfa8f DD 0x26e9d215,0xa16340b2,0x2c1081aa,0xab9a130d DD 0x331b756b,0xb491e7cc,0x39e226d4,0xbe68b473 DD 0xf5533ae1,0x72d9a846,0xffaa695e,0x7820fbf9 DD 0xe0a19d9f,0x672b0f38,0xea58ce20,0x6dd25c87 DD 0xdeb6741d,0x593ce6ba,0xd44f27a2,0x53c5b505 DD 0xcb44d363,0x4cce41c4,0xc1bd80dc,0x4637127b DD 0xa299a719,0x251335be,0xa860f4a6,0x2fea6601 DD 0xb76b0067,0x30e192c0,0xbd9253d8,0x3a18c17f DD 0x897ce9e5,0x0ef67b42,0x8385ba5a,0x040f28fd DD 0x9c8e4e9b,0x1b04dc3c,0x96771d24,0x11fd8f83 DD 0xb58c0222,0x32069085,0xbf75519d,0x38ffc33a DD 0xa07ea55c,0x27f437fb,0xaa87f6e3,0x2d0d6444 DD 0x9e694cde,0x19e3de79,0x94901f61,0x131a8dc6 DD 0x8b9beba0,0x0c117907,0x8162b81f,0x06e82ab8 DD 0xe2469fda,0x65cc0d7d,0xe8bfcc65,0x6f355ec2 DD 0xf7b438a4,0x703eaa03,0xfd4d6b1b,0x7ac7f9bc DD 0xc9a3d126,0x4e294381,0xc35a8299,0x44d0103e DD 0xdc517658,0x5bdbe4ff,0xd6a825e7,0x5122b740 DD 0x1a1939d2,0x9d93ab75,0x10e06a6d,0x976af8ca DD 0x0feb9eac,0x88610c0b,0x0512cd13,0x82985fb4 DD 0x31fc772e,0xb676e589,0x3b052491,0xbc8fb636 DD 0x240ed050,0xa38442f7,0x2ef783ef,0xa97d1148 DD 0x4dd3a42a,0xca59368d,0x472af795,0xc0a06532 DD 0x58210354,0xdfab91f3,0x52d850eb,0xd552c24c DD 0x6636ead6,0xe1bc7871,0x6ccfb969,0xeb452bce DD 0x73c44da8,0xf44edf0f,0x793d1e17,0xfeb78cb0 DD 0xef4a0333,0x68c09194,0xe5b3508c,0x6239c22b DD 0xfab8a44d,0x7d3236ea,0xf041f7f2,0x77cb6555 DD 0xc4af4dcf,0x4325df68,0xce561e70,0x49dc8cd7 DD 0xd15deab1,0x56d77816,0xdba4b90e,0x5c2e2ba9 DD 0xb8809ecb,0x3f0a0c6c,0xb279cd74,0x35f35fd3 DD 0xad7239b5,0x2af8ab12,0xa78b6a0a,0x2001f8ad DD 0x9365d037,0x14ef4290,0x999c8388,0x1e16112f DD 0x86977749,0x011de5ee,0x8c6e24f6,0x0be4b651 DD 0x40df38c3,0xc755aa64,0x4a266b7c,0xcdacf9db DD 0x552d9fbd,0xd2a70d1a,0x5fd4cc02,0xd85e5ea5 DD 0x6b3a763f,0xecb0e498,0x61c32580,0xe649b727 DD 0x7ec8d141,0xf94243e6,0x743182fe,0xf3bb1059 DD 0x1715a53b,0x909f379c,0x1decf684,0x9a666423 DD 0x02e70245,0x856d90e2,0x081e51fa,0x8f94c35d DD 0x3cf0ebc7,0xbb7a7960,0x3609b878,0xb1832adf DD 0x29024cb9,0xae88de1e,0x23fb1f06,0xa4718da1 mul_table_312: DD 0x00000000,0xbac2fd7b,0x70698c07,0xcaab717c DD 0xe0d3180e,0x5a11e575,0x90ba9409,0x2a786972 DD 0xc44a46ed,0x7e88bb96,0xb423caea,0x0ee13791 DD 0x24995ee3,0x9e5ba398,0x54f0d2e4,0xee322f9f DD 0x8d78fb2b,0x37ba0650,0xfd11772c,0x47d38a57 DD 0x6dabe325,0xd7691e5e,0x1dc26f22,0xa7009259 DD 0x4932bdc6,0xf3f040bd,0x395b31c1,0x8399ccba DD 0xa9e1a5c8,0x132358b3,0xd98829cf,0x634ad4b4 DD 0x1f1d80a7,0xa5df7ddc,0x6f740ca0,0xd5b6f1db DD 0xffce98a9,0x450c65d2,0x8fa714ae,0x3565e9d5 DD 0xdb57c64a,0x61953b31,0xab3e4a4d,0x11fcb736 DD 0x3b84de44,0x8146233f,0x4bed5243,0xf12faf38 DD 0x92657b8c,0x28a786f7,0xe20cf78b,0x58ce0af0 DD 0x72b66382,0xc8749ef9,0x02dfef85,0xb81d12fe DD 0x562f3d61,0xecedc01a,0x2646b166,0x9c844c1d DD 0xb6fc256f,0x0c3ed814,0xc695a968,0x7c575413 DD 0x3e3b014e,0x84f9fc35,0x4e528d49,0xf4907032 DD 0xdee81940,0x642ae43b,0xae819547,0x1443683c DD 0xfa7147a3,0x40b3bad8,0x8a18cba4,0x30da36df DD 0x1aa25fad,0xa060a2d6,0x6acbd3aa,0xd0092ed1 DD 0xb343fa65,0x0981071e,0xc32a7662,0x79e88b19 DD 0x5390e26b,0xe9521f10,0x23f96e6c,0x993b9317 DD 0x7709bc88,0xcdcb41f3,0x0760308f,0xbda2cdf4 DD 0x97daa486,0x2d1859fd,0xe7b32881,0x5d71d5fa DD 0x212681e9,0x9be47c92,0x514f0dee,0xeb8df095 DD 0xc1f599e7,0x7b37649c,0xb19c15e0,0x0b5ee89b DD 0xe56cc704,0x5fae3a7f,0x95054b03,0x2fc7b678 DD 0x05bfdf0a,0xbf7d2271,0x75d6530d,0xcf14ae76 DD 0xac5e7ac2,0x169c87b9,0xdc37f6c5,0x66f50bbe DD 0x4c8d62cc,0xf64f9fb7,0x3ce4eecb,0x862613b0 DD 0x68143c2f,0xd2d6c154,0x187db028,0xa2bf4d53 DD 0x88c72421,0x3205d95a,0xf8aea826,0x426c555d DD 0x7c76029c,0xc6b4ffe7,0x0c1f8e9b,0xb6dd73e0 DD 0x9ca51a92,0x2667e7e9,0xeccc9695,0x560e6bee DD 0xb83c4471,0x02feb90a,0xc855c876,0x7297350d DD 0x58ef5c7f,0xe22da104,0x2886d078,0x92442d03 DD 0xf10ef9b7,0x4bcc04cc,0x816775b0,0x3ba588cb DD 0x11dde1b9,0xab1f1cc2,0x61b46dbe,0xdb7690c5 DD 0x3544bf5a,0x8f864221,0x452d335d,0xffefce26 DD 0xd597a754,0x6f555a2f,0xa5fe2b53,0x1f3cd628 DD 0x636b823b,0xd9a97f40,0x13020e3c,0xa9c0f347 DD 0x83b89a35,0x397a674e,0xf3d11632,0x4913eb49 DD 0xa721c4d6,0x1de339ad,0xd74848d1,0x6d8ab5aa DD 0x47f2dcd8,0xfd3021a3,0x379b50df,0x8d59ada4 DD 0xee137910,0x54d1846b,0x9e7af517,0x24b8086c DD 0x0ec0611e,0xb4029c65,0x7ea9ed19,0xc46b1062 DD 0x2a593ffd,0x909bc286,0x5a30b3fa,0xe0f24e81 DD 0xca8a27f3,0x7048da88,0xbae3abf4,0x0021568f DD 0x424d03d2,0xf88ffea9,0x32248fd5,0x88e672ae DD 0xa29e1bdc,0x185ce6a7,0xd2f797db,0x68356aa0 DD 0x8607453f,0x3cc5b844,0xf66ec938,0x4cac3443 DD 0x66d45d31,0xdc16a04a,0x16bdd136,0xac7f2c4d DD 0xcf35f8f9,0x75f70582,0xbf5c74fe,0x059e8985 DD 0x2fe6e0f7,0x95241d8c,0x5f8f6cf0,0xe54d918b DD 0x0b7fbe14,0xb1bd436f,0x7b163213,0xc1d4cf68 DD 0xebaca61a,0x516e5b61,0x9bc52a1d,0x2107d766 DD 0x5d508375,0xe7927e0e,0x2d390f72,0x97fbf209 DD 0xbd839b7b,0x07416600,0xcdea177c,0x7728ea07 DD 0x991ac598,0x23d838e3,0xe973499f,0x53b1b4e4 DD 0x79c9dd96,0xc30b20ed,0x09a05191,0xb362acea DD 0xd028785e,0x6aea8525,0xa041f459,0x1a830922 DD 0x30fb6050,0x8a399d2b,0x4092ec57,0xfa50112c DD 0x14623eb3,0xaea0c3c8,0x640bb2b4,0xdec94fcf DD 0xf4b126bd,0x4e73dbc6,0x84d8aaba,0x3e1a57c1 mul_table_632: DD 0x00000000,0x6b749fb2,0xd6e93f64,0xbd9da0d6 DD 0xa83e0839,0xc34a978b,0x7ed7375d,0x15a3a8ef DD 0x55906683,0x3ee4f931,0x837959e7,0xe80dc655 DD 0xfdae6eba,0x96daf108,0x2b4751de,0x4033ce6c DD 0xab20cd06,0xc05452b4,0x7dc9f262,0x16bd6dd0 DD 0x031ec53f,0x686a5a8d,0xd5f7fa5b,0xbe8365e9 DD 0xfeb0ab85,0x95c43437,0x285994e1,0x432d0b53 DD 0x568ea3bc,0x3dfa3c0e,0x80679cd8,0xeb13036a DD 0x53adecfd,0x38d9734f,0x8544d399,0xee304c2b DD 0xfb93e4c4,0x90e77b76,0x2d7adba0,0x460e4412 DD 0x063d8a7e,0x6d4915cc,0xd0d4b51a,0xbba02aa8 DD 0xae038247,0xc5771df5,0x78eabd23,0x139e2291 DD 0xf88d21fb,0x93f9be49,0x2e641e9f,0x4510812d DD 0x50b329c2,0x3bc7b670,0x865a16a6,0xed2e8914 DD 0xad1d4778,0xc669d8ca,0x7bf4781c,0x1080e7ae DD 0x05234f41,0x6e57d0f3,0xd3ca7025,0xb8beef97 DD 0xa75bd9fa,0xcc2f4648,0x71b2e69e,0x1ac6792c DD 0x0f65d1c3,0x64114e71,0xd98ceea7,0xb2f87115 DD 0xf2cbbf79,0x99bf20cb,0x2422801d,0x4f561faf DD 0x5af5b740,0x318128f2,0x8c1c8824,0xe7681796 DD 0x0c7b14fc,0x670f8b4e,0xda922b98,0xb1e6b42a DD 0xa4451cc5,0xcf318377,0x72ac23a1,0x19d8bc13 DD 0x59eb727f,0x329fedcd,0x8f024d1b,0xe476d2a9 DD 0xf1d57a46,0x9aa1e5f4,0x273c4522,0x4c48da90 DD 0xf4f63507,0x9f82aab5,0x221f0a63,0x496b95d1 DD 0x5cc83d3e,0x37bca28c,0x8a21025a,0xe1559de8 DD 0xa1665384,0xca12cc36,0x778f6ce0,0x1cfbf352 DD 0x09585bbd,0x622cc40f,0xdfb164d9,0xb4c5fb6b DD 0x5fd6f801,0x34a267b3,0x893fc765,0xe24b58d7 DD 0xf7e8f038,0x9c9c6f8a,0x2101cf5c,0x4a7550ee DD 0x0a469e82,0x61320130,0xdcafa1e6,0xb7db3e54 DD 0xa27896bb,0xc90c0909,0x7491a9df,0x1fe5366d DD 0x4b5bc505,0x202f5ab7,0x9db2fa61,0xf6c665d3 DD 0xe365cd3c,0x8811528e,0x358cf258,0x5ef86dea DD 0x1ecba386,0x75bf3c34,0xc8229ce2,0xa3560350 DD 0xb6f5abbf,0xdd81340d,0x601c94db,0x0b680b69 DD 0xe07b0803,0x8b0f97b1,0x36923767,0x5de6a8d5 DD 0x4845003a,0x23319f88,0x9eac3f5e,0xf5d8a0ec DD 0xb5eb6e80,0xde9ff132,0x630251e4,0x0876ce56 DD 0x1dd566b9,0x76a1f90b,0xcb3c59dd,0xa048c66f DD 0x18f629f8,0x7382b64a,0xce1f169c,0xa56b892e DD 0xb0c821c1,0xdbbcbe73,0x66211ea5,0x0d558117 DD 0x4d664f7b,0x2612d0c9,0x9b8f701f,0xf0fbefad DD 0xe5584742,0x8e2cd8f0,0x33b17826,0x58c5e794 DD 0xb3d6e4fe,0xd8a27b4c,0x653fdb9a,0x0e4b4428 DD 0x1be8ecc7,0x709c7375,0xcd01d3a3,0xa6754c11 DD 0xe646827d,0x8d321dcf,0x30afbd19,0x5bdb22ab DD 0x4e788a44,0x250c15f6,0x9891b520,0xf3e52a92 DD 0xec001cff,0x8774834d,0x3ae9239b,0x519dbc29 DD 0x443e14c6,0x2f4a8b74,0x92d72ba2,0xf9a3b410 DD 0xb9907a7c,0xd2e4e5ce,0x6f794518,0x040ddaaa DD 0x11ae7245,0x7adaedf7,0xc7474d21,0xac33d293 DD 0x4720d1f9,0x2c544e4b,0x91c9ee9d,0xfabd712f DD 0xef1ed9c0,0x846a4672,0x39f7e6a4,0x52837916 DD 0x12b0b77a,0x79c428c8,0xc459881e,0xaf2d17ac DD 0xba8ebf43,0xd1fa20f1,0x6c678027,0x07131f95 DD 0xbfadf002,0xd4d96fb0,0x6944cf66,0x023050d4 DD 0x1793f83b,0x7ce76789,0xc17ac75f,0xaa0e58ed DD 0xea3d9681,0x81490933,0x3cd4a9e5,0x57a03657 DD 0x42039eb8,0x2977010a,0x94eaa1dc,0xff9e3e6e DD 0x148d3d04,0x7ff9a2b6,0xc2640260,0xa9109dd2 DD 0xbcb3353d,0xd7c7aa8f,0x6a5a0a59,0x012e95eb DD 0x411d5b87,0x2a69c435,0x97f464e3,0xfc80fb51 DD 0xe92353be,0x8257cc0c,0x3fca6cda,0x54bef368 mul_table_1272: DD 0x00000000,0xdd66cbbb,0xbf21e187,0x62472a3c DD 0x7bafb5ff,0xa6c97e44,0xc48e5478,0x19e89fc3 DD 0xf75f6bfe,0x2a39a045,0x487e8a79,0x951841c2 DD 0x8cf0de01,0x519615ba,0x33d13f86,0xeeb7f43d DD 0xeb52a10d,0x36346ab6,0x5473408a,0x89158b31 DD 0x90fd14f2,0x4d9bdf49,0x2fdcf575,0xf2ba3ece DD 0x1c0dcaf3,0xc16b0148,0xa32c2b74,0x7e4ae0cf DD 0x67a27f0c,0xbac4b4b7,0xd8839e8b,0x05e55530 DD 0xd34934eb,0x0e2fff50,0x6c68d56c,0xb10e1ed7 DD 0xa8e68114,0x75804aaf,0x17c76093,0xcaa1ab28 DD 0x24165f15,0xf97094ae,0x9b37be92,0x46517529 DD 0x5fb9eaea,0x82df2151,0xe0980b6d,0x3dfec0d6 DD 0x381b95e6,0xe57d5e5d,0x873a7461,0x5a5cbfda DD 0x43b42019,0x9ed2eba2,0xfc95c19e,0x21f30a25 DD 0xcf44fe18,0x122235a3,0x70651f9f,0xad03d424 DD 0xb4eb4be7,0x698d805c,0x0bcaaa60,0xd6ac61db DD 0xa37e1f27,0x7e18d49c,0x1c5ffea0,0xc139351b DD 0xd8d1aad8,0x05b76163,0x67f04b5f,0xba9680e4 DD 0x542174d9,0x8947bf62,0xeb00955e,0x36665ee5 DD 0x2f8ec126,0xf2e80a9d,0x90af20a1,0x4dc9eb1a DD 0x482cbe2a,0x954a7591,0xf70d5fad,0x2a6b9416 DD 0x33830bd5,0xeee5c06e,0x8ca2ea52,0x51c421e9 DD 0xbf73d5d4,0x62151e6f,0x00523453,0xdd34ffe8 DD 0xc4dc602b,0x19baab90,0x7bfd81ac,0xa69b4a17 DD 0x70372bcc,0xad51e077,0xcf16ca4b,0x127001f0 DD 0x0b989e33,0xd6fe5588,0xb4b97fb4,0x69dfb40f DD 0x87684032,0x5a0e8b89,0x3849a1b5,0xe52f6a0e DD 0xfcc7f5cd,0x21a13e76,0x43e6144a,0x9e80dff1 DD 0x9b658ac1,0x4603417a,0x24446b46,0xf922a0fd DD 0xe0ca3f3e,0x3dacf485,0x5febdeb9,0x828d1502 DD 0x6c3ae13f,0xb15c2a84,0xd31b00b8,0x0e7dcb03 DD 0x179554c0,0xcaf39f7b,0xa8b4b547,0x75d27efc DD 0x431048bf,0x9e768304,0xfc31a938,0x21576283 DD 0x38bffd40,0xe5d936fb,0x879e1cc7,0x5af8d77c DD 0xb44f2341,0x6929e8fa,0x0b6ec2c6,0xd608097d DD 0xcfe096be,0x12865d05,0x70c17739,0xada7bc82 DD 0xa842e9b2,0x75242209,0x17630835,0xca05c38e DD 0xd3ed5c4d,0x0e8b97f6,0x6cccbdca,0xb1aa7671 DD 0x5f1d824c,0x827b49f7,0xe03c63cb,0x3d5aa870 DD 0x24b237b3,0xf9d4fc08,0x9b93d634,0x46f51d8f DD 0x90597c54,0x4d3fb7ef,0x2f789dd3,0xf21e5668 DD 0xebf6c9ab,0x36900210,0x54d7282c,0x89b1e397 DD 0x670617aa,0xba60dc11,0xd827f62d,0x05413d96 DD 0x1ca9a255,0xc1cf69ee,0xa38843d2,0x7eee8869 DD 0x7b0bdd59,0xa66d16e2,0xc42a3cde,0x194cf765 DD 0x00a468a6,0xddc2a31d,0xbf858921,0x62e3429a DD 0x8c54b6a7,0x51327d1c,0x33755720,0xee139c9b DD 0xf7fb0358,0x2a9dc8e3,0x48dae2df,0x95bc2964 DD 0xe06e5798,0x3d089c23,0x5f4fb61f,0x82297da4 DD 0x9bc1e267,0x46a729dc,0x24e003e0,0xf986c85b DD 0x17313c66,0xca57f7dd,0xa810dde1,0x7576165a DD 0x6c9e8999,0xb1f84222,0xd3bf681e,0x0ed9a3a5 DD 0x0b3cf695,0xd65a3d2e,0xb41d1712,0x697bdca9 DD 0x7093436a,0xadf588d1,0xcfb2a2ed,0x12d46956 DD 0xfc639d6b,0x210556d0,0x43427cec,0x9e24b757 DD 0x87cc2894,0x5aaae32f,0x38edc913,0xe58b02a8 DD 0x33276373,0xee41a8c8,0x8c0682f4,0x5160494f DD 0x4888d68c,0x95ee1d37,0xf7a9370b,0x2acffcb0 DD 0xc478088d,0x191ec336,0x7b59e90a,0xa63f22b1 DD 0xbfd7bd72,0x62b176c9,0x00f65cf5,0xdd90974e DD 0xd875c27e,0x051309c5,0x675423f9,0xba32e842 DD 0xa3da7781,0x7ebcbc3a,0x1cfb9606,0xc19d5dbd DD 0x2f2aa980,0xf24c623b,0x900b4807,0x4d6d83bc DD 0x54851c7f,0x89e3d7c4,0xeba4fdf8,0x36c23643 %macro slversion 4 global %1_slver_%2%3%4 global %1_slver %1_slver: %1_slver_%2%3%4: dw 0x%4 db 0x%3, 0x%2 %endmacro ;;; func core, ver, snum slversion crc32_iscsi_zero_00, 00, 02, 0014 ; inform linker that this doesn't require executable stack section .note.GNU-stack noalloc noexec nowrite progbits ceph-0.80.11/src/common/sync_filesystem.h0000664000175100017510000000247212623076744022352 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SYNC_FILESYSTEM_H #define CEPH_SYNC_FILESYSTEM_H #include #include #ifndef __CYGWIN__ # ifndef DARWIN # include # include "../os/btrfs_ioctl.h" # endif #endif inline int sync_filesystem(int fd) { /* On Linux, newer versions of glibc have a function called syncfs that * performs a sync on only one filesystem. If we don't have this call, we * have to fall back on sync(), which synchronizes every filesystem on the * computer. */ #ifdef HAVE_SYS_SYNCFS if (syncfs(fd) == 0) return 0; #elif defined(SYS_syncfs) if (syscall(SYS_syncfs, fd) == 0) return 0; #elif defined(__NR_syncfs) if (syscall(__NR_syncfs, fd) == 0) return 0; #endif #if defined(HAVE_SYS_SYNCFS) || defined(SYS_syncfs) || defined(__NR_syncfs) else if (errno == ENOSYS) { sync(); return 0; } else { return -errno; } #else sync(); return 0; #endif } #endif ceph-0.80.11/src/common/SloppyCRCMap.cc0000664000175100017510000001100512623076744021534 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/SloppyCRCMap.h" #include "common/Formatter.h" void SloppyCRCMap::write(uint64_t offset, uint64_t len, const bufferlist& bl, std::ostream *out) { int64_t left = len; uint64_t pos = offset; unsigned o = offset % block_size; if (o) { crc_map.erase(offset - o); if (out) *out << "write invalidate " << (offset - o) << "\n"; pos += (block_size - o); left -= (block_size - o); } while (left >= block_size) { bufferlist t; t.substr_of(bl, pos - offset, block_size); crc_map[pos] = t.crc32c(crc_iv); if (out) *out << "write set " << pos << " " << crc_map[pos] << "\n"; pos += block_size; left -= block_size; } if (left > 0) { crc_map.erase(pos); if (out) *out << "write invalidate " << pos << "\n"; } } int SloppyCRCMap::read(uint64_t offset, uint64_t len, const bufferlist& bl, std::ostream *err) { int errors = 0; int64_t left = len; uint64_t pos = offset; unsigned o = offset % block_size; if (o) { pos += (block_size - o); left -= (block_size - o); } while (left >= block_size) { // FIXME: this could be more efficient if we avoid doing a find() // on each iteration std::map::iterator p = crc_map.find(pos); if (p != crc_map.end()) { bufferlist t; t.substr_of(bl, pos - offset, block_size); uint32_t crc = t.crc32c(crc_iv); if (p->second != crc) { errors++; if (err) *err << "offset " << pos << " len " << block_size << " has crc " << crc << " expected " << p->second << "\n"; } } pos += block_size; left -= block_size; } return errors; } void SloppyCRCMap::truncate(uint64_t offset) { offset -= offset % block_size; std::map::iterator p = crc_map.lower_bound(offset); while (p != crc_map.end()) crc_map.erase(p++); } void SloppyCRCMap::zero(uint64_t offset, uint64_t len) { int64_t left = len; uint64_t pos = offset; unsigned o = offset % block_size; if (o) { crc_map.erase(offset - o); pos += (block_size - o); left -= (block_size - o); } while (left >= block_size) { crc_map[pos] = zero_crc; pos += block_size; left -= block_size; } if (left > 0) crc_map.erase(pos); } void SloppyCRCMap::clone_range(uint64_t offset, uint64_t len, uint64_t srcoff, const SloppyCRCMap& src, std::ostream *out) { int64_t left = len; uint64_t pos = offset; uint64_t srcpos = srcoff; unsigned o = offset % block_size; if (o) { crc_map.erase(offset - o); pos += (block_size - o); srcpos += (block_size - o); left -= (block_size - o); if (out) *out << "clone_range invalidate " << (offset - o) << "\n"; } while (left >= block_size) { // FIXME: this could be more efficient. if (block_size == src.block_size) { map::const_iterator p = src.crc_map.find(srcpos); if (p != src.crc_map.end()) { crc_map[pos] = p->second; if (out) *out << "clone_range copy " << pos << " " << p->second << "\n"; } else { crc_map.erase(pos); if (out) *out << "clone_range invalidate " << pos << "\n"; } } else { crc_map.erase(pos); if (out) *out << "clone_range invalidate " << pos << "\n"; } pos += block_size; srcpos += block_size; left -= block_size; } if (left > 0) { crc_map.erase(pos); if (out) *out << "clone_range invalidate " << pos << "\n"; } } void SloppyCRCMap::encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(block_size, bl); ::encode(crc_map, bl); ENCODE_FINISH(bl); } void SloppyCRCMap::decode(bufferlist::iterator& bl) { DECODE_START(1, bl); uint32_t bs; ::decode(bs, bl); set_block_size(bs); ::decode(crc_map, bl); DECODE_FINISH(bl); } void SloppyCRCMap::dump(Formatter *f) const { f->dump_unsigned("block_size", block_size); f->open_array_section("crc_map"); for (map::const_iterator p = crc_map.begin(); p != crc_map.end(); ++p) { f->open_object_section("crc"); f->dump_unsigned("offset", p->first); f->dump_unsigned("crc", p->second); f->close_section(); } f->close_section(); } void SloppyCRCMap::generate_test_instances(list& ls) { ls.push_back(new SloppyCRCMap); ls.push_back(new SloppyCRCMap(2)); bufferlist bl; bl.append("some data"); ls.back()->write(1, bl.length(), bl); ls.back()->write(10, bl.length(), bl); ls.back()->zero(4, 2); } ceph-0.80.11/src/common/environment.h0000664000175100017510000000107212623076744021471 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_ENVIRONMENT_H #define CEPH_COMMON_ENVIRONMENT_H extern bool get_env_bool(const char *key); extern int get_env_int(const char *key); #endif ceph-0.80.11/src/common/Mutex.h0000664000175100017510000000462612623076744020237 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MUTEX_H #define CEPH_MUTEX_H #include "include/assert.h" #include "lockdep.h" #include "common/ceph_context.h" #include using namespace ceph; class PerfCounters; enum { l_mutex_first = 999082, l_mutex_wait, l_mutex_last }; class Mutex { private: const char *name; int id; bool recursive; bool lockdep; bool backtrace; // gather backtrace on lock acquisition pthread_mutex_t _m; int nlock; pthread_t locked_by; CephContext *cct; PerfCounters *logger; // don't allow copying. void operator=(Mutex &M); Mutex(const Mutex &M); void _register() { id = lockdep_register(name); } void _will_lock() { // about to lock id = lockdep_will_lock(name, id); } void _locked() { // just locked id = lockdep_locked(name, id, backtrace); } void _will_unlock() { // about to unlock id = lockdep_will_unlock(name, id); } public: Mutex(const char *n, bool r = false, bool ld=true, bool bt=false, CephContext *cct = 0); ~Mutex(); bool is_locked() const { return (nlock > 0); } bool is_locked_by_me() const { return nlock > 0 && locked_by == pthread_self(); } bool TryLock() { int r = pthread_mutex_trylock(&_m); if (r == 0) { if (lockdep && g_lockdep) _locked(); _post_lock(); } return r == 0; } void Lock(bool no_lockdep=false); void _post_lock() { if (!recursive) { assert(nlock == 0); locked_by = pthread_self(); }; nlock++; } void _pre_unlock() { assert(nlock > 0); --nlock; if (!recursive) { assert(locked_by == pthread_self()); locked_by = 0; assert(nlock == 0); } } void Unlock() { _pre_unlock(); if (lockdep && g_lockdep) _will_unlock(); int r = pthread_mutex_unlock(&_m); assert(r == 0); } friend class Cond; public: class Locker { Mutex &mutex; public: Locker(Mutex& m) : mutex(m) { mutex.Lock(); } ~Locker() { mutex.Unlock(); } }; }; #endif ceph-0.80.11/src/common/BackTrace.h0000664000175100017510000000103512623076744020743 0ustar jenkins-buildjenkins-build#ifndef CEPH_BACKTRACE_H #define CEPH_BACKTRACE_H #include #include #include namespace ceph { struct BackTrace { const static int max = 100; int skip; void *array[max]; size_t size; char **strings; BackTrace(int s) : skip(s) { size = backtrace(array, max); strings = backtrace_symbols(array, size); } ~BackTrace() { free(strings); } BackTrace(const BackTrace& other); const BackTrace& operator=(const BackTrace& other); void print(std::ostream& out); }; } #endif ceph-0.80.11/src/common/compiler_extensions.h0000664000175100017510000000143412623076744023220 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMPILER_EXTENSIONS_H #define CEPH_COMPILER_EXTENSIONS_H /* We should be able to take advantage of nice nonstandard features of gcc * and other compilers, but still maintain portability. */ #ifdef __GNUC__ // GCC #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else // some other compiler - just make it a no-op #define WARN_UNUSED_RESULT #endif #endif ceph-0.80.11/src/common/obj_bencher.h0000664000175100017510000000714412623076744021373 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- /* * Ceph - scalable distributed file system * * Copyright (C) 2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OBJ_BENCHER_H #define CEPH_OBJ_BENCHER_H #include "common/config.h" #include "common/Cond.h" #include "common/ceph_context.h" struct bench_interval_data { double min_bandwidth; double max_bandwidth; }; struct bench_history { vector bandwidth; vector latency; }; struct bench_data { bool done; //is the benchmark is done int object_size; //the size of the objects int trans_size; //size of the write/read to perform // same as object_size for write tests int in_flight; //number of reads/writes being waited on int started; int finished; double min_latency; double max_latency; double avg_latency; struct bench_interval_data idata; // data that is updated by time intervals and not by events struct bench_history history; // data history, used to calculate stddev utime_t cur_latency; //latency of last completed transaction utime_t start_time; //start time for benchmark char *object_contents; //pointer to the contents written to each object }; const int OP_WRITE = 1; const int OP_SEQ_READ = 2; const int OP_RAND_READ = 3; class ObjBencher { bool show_time; public: CephContext *cct; protected: Mutex lock; static void *status_printer(void *bencher); struct bench_data data; int fetch_bench_metadata(const std::string& metadata_file, int* object_size, int* num_objects, int* prevPid); int write_bench(int secondsToRun, int maxObjects, int concurrentios, const string& run_name_meta); int seq_read_bench(int secondsToRun, int concurrentios, int num_objects, int writePid); int rand_read_bench(int secondsToRun, int num_objects, int concurrentios, int writePid); int clean_up(int num_objects, int prevPid, int concurrentios); int clean_up_slow(const std::string& prefix, int concurrentios); bool more_objects_matching_prefix(const std::string& prefix, std::list* name); virtual int completions_init(int concurrentios) = 0; virtual void completions_done() = 0; virtual int create_completion(int i, void (*cb)(void *, void*), void *arg) = 0; virtual void release_completion(int slot) = 0; virtual bool completion_is_done(int slot) = 0; virtual int completion_wait(int slot) = 0; virtual int completion_ret(int slot) = 0; virtual int aio_read(const std::string& oid, int slot, bufferlist *pbl, size_t len) = 0; virtual int aio_write(const std::string& oid, int slot, bufferlist& bl, size_t len) = 0; virtual int aio_remove(const std::string& oid, int slot) = 0; virtual int sync_read(const std::string& oid, bufferlist& bl, size_t len) = 0; virtual int sync_write(const std::string& oid, bufferlist& bl, size_t len) = 0; virtual int sync_remove(const std::string& oid) = 0; virtual bool get_objects(std::list* objects, int num) = 0; ostream& out(ostream& os); ostream& out(ostream& os, utime_t& t); public: ObjBencher(CephContext *cct_) : show_time(false), cct(cct_), lock("ObjBencher::lock") {} virtual ~ObjBencher() {} int aio_bench( int operation, int secondsToRun, int maxObjectsToCreate, int concurrentios, int op_size, bool cleanup, const char* run_name); int clean_up(const char* prefix, int concurrentios, const char* run_name); void set_show_time(bool dt) { show_time = dt; } }; #endif ceph-0.80.11/src/common/armor.h0000664000175100017510000000064512623076744020252 0ustar jenkins-buildjenkins-build#ifndef CEPH_ARMOR_H #define CEPH_ARMOR_H #ifdef __cplusplus extern "C" { #endif int ceph_armor(char *dst, const char *dst_end, const char *src, const char *end); int ceph_armor_linebreak(char *dst, const char *dst_end, const char *src, const char *end, int line_width); int ceph_unarmor(char *dst, const char *dst_end, const char *src, const char *end); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/common/Throttle.h0000664000175100017510000000427312623076744020740 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_THROTTLE_H #define CEPH_THROTTLE_H #include "Mutex.h" #include "Cond.h" #include #include "include/atomic.h" class CephContext; class PerfCounters; class Throttle { CephContext *cct; std::string name; PerfCounters *logger; ceph::atomic_t count, max; Mutex lock; list cond; bool use_perf; public: Throttle(CephContext *cct, std::string n, int64_t m = 0, bool _use_perf = true); ~Throttle(); private: void _reset_max(int64_t m); bool _should_wait(int64_t c) { int64_t m = max.read(); int64_t cur = count.read(); return m && ((c <= m && cur + c > m) || // normally stay under max (c >= m && cur > m)); // except for large c } bool _wait(int64_t c); public: int64_t get_current() { return count.read(); } int64_t get_max() { return max.read(); } bool wait(int64_t m = 0); int64_t take(int64_t c = 1); bool get(int64_t c = 1, int64_t m = 0); /** * Returns true if it successfully got the requested amount, * or false if it would block. */ bool get_or_fail(int64_t c = 1); int64_t put(int64_t c = 1); }; /** * @class SimpleThrottle * This is a simple way to bound the number of concurrent operations. * * It tracks the first error encountered, and makes it available * when all requests are complete. wait_for_ret() should be called * before the instance is destroyed. * * Re-using the same instance isn't safe if you want to check each set * of operations for errors, since the return value is not reset. */ class SimpleThrottle { public: SimpleThrottle(uint64_t max, bool ignore_enoent); ~SimpleThrottle(); void start_op(); void end_op(int r); bool pending_error() const; int wait_for_ret(); private: mutable Mutex m_lock; Cond m_cond; uint64_t m_max; uint64_t m_current; int m_ret; bool m_ignore_enoent; }; class C_SimpleThrottle : public Context { public: C_SimpleThrottle(SimpleThrottle *throttle) : m_throttle(throttle) { m_throttle->start_op(); } virtual void finish(int r) { m_throttle->end_op(r); } private: SimpleThrottle *m_throttle; }; #endif ceph-0.80.11/src/common/io_priority.h0000664000175100017510000000202212623076744021471 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Red Hat * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_IO_PRIORITY_H #define CEPH_COMMON_IO_PRIORITY_H #include extern pid_t ceph_gettid(); #ifndef IOPRIO_WHO_PROCESS # define IOPRIO_WHO_PROCESS 1 #endif #ifndef IOPRIO_PRIO_VALUE # define IOPRIO_CLASS_SHIFT 13 # define IOPRIO_PRIO_VALUE(class, data) \ (((class) << IOPRIO_CLASS_SHIFT) | (data)) #endif #ifndef IOPRIO_CLASS_RT # define IOPRIO_CLASS_RT 1 #endif #ifndef IOPRIO_CLASS_BE # define IOPRIO_CLASS_BE 2 #endif #ifndef IOPRIO_CLASS_IDLE # define IOPRIO_CLASS_IDLE 3 #endif extern int ceph_ioprio_set(int whence, int who, int ioprio); extern int ceph_ioprio_string_to_class(const std::string& s); #endif ceph-0.80.11/src/common/code_environment.h0000664000175100017510000000221112623076744022457 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_CODE_ENVIRONMENT_H #define CEPH_COMMON_CODE_ENVIRONMENT_H enum code_environment_t { CODE_ENVIRONMENT_UTILITY = 0, CODE_ENVIRONMENT_DAEMON = 1, CODE_ENVIRONMENT_LIBRARY = 2, CODE_ENVIRONMENT_UTILITY_NODOUT = 3, }; #ifdef __cplusplus #include #include extern "C" code_environment_t g_code_env; extern "C" const char *code_environment_to_str(enum code_environment_t e); std::ostream &operator<<(std::ostream &oss, enum code_environment_t e); extern "C" int get_process_name(char *buf, int len); std::string get_process_name_cpp(); #else extern code_environment_t g_code_env; const char *code_environment_to_str(enum code_environment_t e); extern int get_process_name(char *buf, int len); #endif #endif ceph-0.80.11/src/common/entity_name.cc0000664000175100017510000000615412623076744021605 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/entity_name.h" #include "include/msgr.h" #include #include #include using std::string; extern const char *ceph_entity_type_name(int type); struct str_to_entity_type_t { uint32_t type; const char *str; }; static const str_to_entity_type_t STR_TO_ENTITY_TYPE[] = { { CEPH_ENTITY_TYPE_AUTH, "auth" }, { CEPH_ENTITY_TYPE_MON, "mon" }, { CEPH_ENTITY_TYPE_OSD, "osd" }, { CEPH_ENTITY_TYPE_MDS, "mds" }, { CEPH_ENTITY_TYPE_CLIENT, "client" }, }; EntityName:: EntityName() : type(0) { } const std::string& EntityName:: to_str() const { return type_id; } const char* EntityName:: to_cstr() const { return type_id.c_str(); } bool EntityName:: from_str(const string& s) { int pos = s.find('.'); if (pos < 0) return false; string type_ = s.substr(0, pos); string id_ = s.substr(pos + 1); if (set(type_, id_)) return false; return true; } void EntityName:: set(uint32_t type_, const std::string &id_) { type = type_; id = id_; std::ostringstream oss; oss << ceph_entity_type_name(type_) << "." << id_; type_id = oss.str(); } int EntityName:: set(const std::string &type_, const std::string &id_) { uint32_t t = str_to_ceph_entity_type(type_.c_str()); if (t == CEPH_ENTITY_TYPE_ANY) return -EINVAL; set(t, id_); return 0; } void EntityName:: set_type(uint32_t type_) { set(type_, id); } int EntityName:: set_type(const char *type_) { return set(type_, id); } void EntityName:: set_id(const std::string &id_) { set(type, id_); } void EntityName::set_name(entity_name_t n) { char s[40]; sprintf(s, "%lld", (long long)n.num()); set(n.type(), s); } const char* EntityName:: get_type_str() const { return ceph_entity_type_name(type); } const char *EntityName:: get_type_name() const { return ceph_entity_type_name(type); } const std::string &EntityName:: get_id() const { return id; } bool EntityName:: has_default_id() const { return (id == "admin"); } std::string EntityName:: get_valid_types_as_str() { std::string out; size_t i; std::string sep(""); for (i = 0; i < sizeof(STR_TO_ENTITY_TYPE)/sizeof(STR_TO_ENTITY_TYPE[0]); ++i) { out += sep; out += STR_TO_ENTITY_TYPE[i].str; sep = ", "; } return out; } bool operator<(const EntityName& a, const EntityName& b) { return (a.type < b.type) || (a.type == b.type && a.id < b.id); } std::ostream& operator<<(std::ostream& out, const EntityName& n) { return out << n.to_str(); } uint32_t str_to_ceph_entity_type(const char * str) { size_t i; for (i = 0; i < sizeof(STR_TO_ENTITY_TYPE)/sizeof(STR_TO_ENTITY_TYPE[0]); ++i) { if (strcmp(str, STR_TO_ENTITY_TYPE[i].str) == 0) return STR_TO_ENTITY_TYPE[i].type; } return CEPH_ENTITY_TYPE_ANY; } ceph-0.80.11/src/common/Clock.h0000664000175100017510000000121012623076744020152 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_CLOCK_H #define CEPH_CLOCK_H #include "include/utime.h" #include class CephContext; extern utime_t ceph_clock_now(CephContext *cct); extern time_t ceph_clock_gettime(CephContext *cct); #endif ceph-0.80.11/src/common/RefCountedObj.cc0000664000175100017510000000112112623076744021747 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/RefCountedObj.h" void intrusive_ptr_add_ref(RefCountedObject *p) { p->get(); } void intrusive_ptr_release(RefCountedObject *p) { p->put(); } ceph-0.80.11/src/common/obj_bencher.cc0000664000175100017510000010072312623076744021526 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- /* * Ceph - scalable distributed file system * * Copyright (C) 2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Series of functions to test your rados installation. Notice * that this code is not terribly robust -- for instance, if you * try and bench on a pool you don't have permission to access * it will just loop forever. */ #include "common/Cond.h" #include "obj_bencher.h" #include #include #include #include #include #include #include const std::string BENCH_LASTRUN_METADATA = "benchmark_last_metadata"; const std::string BENCH_PREFIX = "benchmark_data"; static std::string generate_object_prefix(int pid = 0) { char hostname[30]; gethostname(hostname, sizeof(hostname)-1); hostname[sizeof(hostname)-1] = 0; if (!pid) pid = getpid(); std::ostringstream oss; oss << BENCH_PREFIX << "_" << hostname << "_" << pid; return oss.str(); } static std::string generate_object_name(int objnum, int pid = 0) { std::ostringstream oss; oss << generate_object_prefix(pid) << "_object" << objnum; return oss.str(); } static void sanitize_object_contents (bench_data *data, int length) { memset(data->object_contents, 'z', length); } ostream& ObjBencher::out(ostream& os, utime_t& t) { if (show_time) return t.localtime(os) << " "; else return os << " "; } ostream& ObjBencher::out(ostream& os) { utime_t cur_time = ceph_clock_now(cct); return out(os, cur_time); } void *ObjBencher::status_printer(void *_bencher) { ObjBencher *bencher = static_cast(_bencher); bench_data& data = bencher->data; Cond cond; int i = 0; int previous_writes = 0; int cycleSinceChange = 0; double bandwidth; utime_t ONE_SECOND; ONE_SECOND.set_from_double(1.0); bencher->lock.Lock(); while(!data.done) { utime_t cur_time = ceph_clock_now(bencher->cct); if (i % 20 == 0) { if (i > 0) cur_time.localtime(cout) << "min lat: " << data.min_latency << " max lat: " << data.max_latency << " avg lat: " << data.avg_latency << std::endl; //I'm naughty and don't reset the fill bencher->out(cout, cur_time) << setfill(' ') << setw(5) << "sec" << setw(8) << "Cur ops" << setw(10) << "started" << setw(10) << "finished" << setw(10) << "avg MB/s" << setw(10) << "cur MB/s" << setw(10) << "last lat" << setw(10) << "avg lat" << std::endl; } if (cycleSinceChange) bandwidth = (double)(data.finished - previous_writes) * (data.trans_size) / (1024*1024) / cycleSinceChange; else bandwidth = 0; if (!isnan(bandwidth)) { if (bandwidth > data.idata.max_bandwidth) data.idata.max_bandwidth = bandwidth; if (bandwidth < data.idata.min_bandwidth) data.idata.min_bandwidth = bandwidth; data.history.bandwidth.push_back(bandwidth); } double avg_bandwidth = (double) (data.trans_size) * (data.finished) / (double)(cur_time - data.start_time) / (1024*1024); if (previous_writes != data.finished) { previous_writes = data.finished; cycleSinceChange = 0; bencher->out(cout, cur_time) << setfill(' ') << setw(5) << i << setw(8) << data.in_flight << setw(10) << data.started << setw(10) << data.finished << setw(10) << avg_bandwidth << setw(10) << bandwidth << setw(10) << (double)data.cur_latency << setw(10) << data.avg_latency << std::endl; } else { bencher->out(cout, cur_time) << setfill(' ') << setw(5) << i << setw(8) << data.in_flight << setw(10) << data.started << setw(10) << data.finished << setw(10) << avg_bandwidth << setw(10) << '0' << setw(10) << '-' << setw(10) << data.avg_latency << std::endl; } ++i; ++cycleSinceChange; cond.WaitInterval(bencher->cct, bencher->lock, ONE_SECOND); } bencher->lock.Unlock(); return NULL; } int ObjBencher::aio_bench( int operation, int secondsToRun, int maxObjectsToCreate, int concurrentios, int op_size, bool cleanup, const char* run_name) { int object_size = op_size; int num_objects = 0; int r = 0; int prevPid = 0; // default metadata object is used if user does not specify one const std::string run_name_meta = (run_name == NULL ? BENCH_LASTRUN_METADATA : std::string(run_name)); //get data from previous write run, if available if (operation != OP_WRITE) { r = fetch_bench_metadata(run_name_meta, &object_size, &num_objects, &prevPid); if (r < 0) { if (r == -ENOENT) cerr << "Must write data before running a read benchmark!" << std::endl; return r; } } else { object_size = op_size; } char* contentsChars = new char[object_size]; lock.Lock(); data.done = false; data.object_size = object_size; data.trans_size = op_size; data.in_flight = 0; data.started = 0; data.finished = num_objects; data.min_latency = 9999.0; // this better be higher than initial latency! data.max_latency = 0; data.avg_latency = 0; data.idata.min_bandwidth = 99999999.0; data.idata.max_bandwidth = 0; data.object_contents = contentsChars; lock.Unlock(); //fill in contentsChars deterministically so we can check returns sanitize_object_contents(&data, data.object_size); if (OP_WRITE == operation) { r = write_bench(secondsToRun, maxObjectsToCreate, concurrentios, run_name_meta); if (r != 0) goto out; } else if (OP_SEQ_READ == operation) { r = seq_read_bench(secondsToRun, num_objects, concurrentios, prevPid); if (r != 0) goto out; } else if (OP_RAND_READ == operation) { r = rand_read_bench(secondsToRun, num_objects, concurrentios, prevPid); if (r != 0) goto out; } if (OP_WRITE == operation && cleanup) { r = fetch_bench_metadata(run_name_meta, &object_size, &num_objects, &prevPid); if (r < 0) { if (r == -ENOENT) cerr << "Should never happen: bench metadata missing for current run!" << std::endl; goto out; } r = clean_up(num_objects, prevPid, concurrentios); if (r != 0) goto out; // lastrun file r = sync_remove(run_name_meta); if (r != 0) goto out; } out: delete[] contentsChars; return r; } struct lock_cond { lock_cond(Mutex *_lock) : lock(_lock) {} Mutex *lock; Cond cond; }; void _aio_cb(void *cb, void *arg) { struct lock_cond *lc = (struct lock_cond *)arg; lc->lock->Lock(); lc->cond.Signal(); lc->lock->Unlock(); } static double vec_stddev(vector& v) { double mean = 0; if (v.size() < 2) return 0; vector::iterator iter; for (iter = v.begin(); iter != v.end(); ++iter) { mean += *iter; } mean /= v.size(); double stddev = 0; for (iter = v.begin(); iter != v.end(); ++iter) { double dev = *iter - mean; dev *= dev; stddev += dev; } stddev /= (v.size() - 1); return sqrt(stddev); } int ObjBencher::fetch_bench_metadata(const std::string& metadata_file, int* object_size, int* num_objects, int* prevPid) { int r = 0; bufferlist object_data; r = sync_read(metadata_file, object_data, sizeof(int)*3); if (r <= 0) { // treat an empty file as a file that does not exist if (r == 0) { r = -ENOENT; } return r; } bufferlist::iterator p = object_data.begin(); ::decode(*object_size, p); ::decode(*num_objects, p); ::decode(*prevPid, p); return 0; } int ObjBencher::write_bench(int secondsToRun, int maxObjectsToCreate, int concurrentios, const string& run_name_meta) { if (maxObjectsToCreate > 0 && concurrentios > maxObjectsToCreate) concurrentios = maxObjectsToCreate; out(cout) << "Maintaining " << concurrentios << " concurrent writes of " << data.object_size << " bytes for up to " << secondsToRun << " seconds or " << maxObjectsToCreate << " objects" << std::endl; bufferlist* newContents = 0; std::string prefix = generate_object_prefix(); out(cout) << "Object prefix: " << prefix << std::endl; std::vector name(concurrentios); std::string newName; bufferlist* contents[concurrentios]; double total_latency = 0; std::vector start_times(concurrentios); utime_t stopTime; int r = 0; bufferlist b_write; lock_cond lc(&lock); utime_t runtime; utime_t timePassed; r = completions_init(concurrentios); //set up writes so I can start them together for (int i = 0; iappend(data.object_contents, data.object_size); } pthread_t print_thread; pthread_create(&print_thread, NULL, ObjBencher::status_printer, (void *)this); lock.Lock(); data.start_time = ceph_clock_now(cct); lock.Unlock(); for (int i = 0; iappend(data.object_contents, data.object_size); completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r != 0) { lock.Unlock(); goto ERR; } data.cur_latency = ceph_clock_now(cct) - start_times[slot]; data.history.latency.push_back(data.cur_latency); total_latency += data.cur_latency; if( data.cur_latency > data.max_latency) data.max_latency = data.cur_latency; if (data.cur_latency < data.min_latency) data.min_latency = data.cur_latency; ++data.finished; data.avg_latency = total_latency / data.finished; --data.in_flight; lock.Unlock(); release_completion(slot); timePassed = ceph_clock_now(cct) - data.start_time; //write new stuff to backend, then delete old stuff //and save locations of new stuff for later deletion start_times[slot] = ceph_clock_now(cct); r = create_completion(slot, _aio_cb, &lc); if (r < 0) goto ERR; r = aio_write(newName, slot, *newContents, data.object_size); if (r < 0) {//naughty; doesn't clean up heap space. goto ERR; } delete contents[slot]; name[slot] = newName; contents[slot] = newContents; newContents = 0; lock.Lock(); ++data.started; ++data.in_flight; } lock.Unlock(); while (data.finished < data.started) { slot = data.finished % concurrentios; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r != 0) { lock.Unlock(); goto ERR; } data.cur_latency = ceph_clock_now(cct) - start_times[slot]; data.history.latency.push_back(data.cur_latency); total_latency += data.cur_latency; if (data.cur_latency > data.max_latency) data.max_latency = data.cur_latency; if (data.cur_latency < data.min_latency) data.min_latency = data.cur_latency; ++data.finished; data.avg_latency = total_latency / data.finished; --data.in_flight; lock.Unlock(); release_completion(slot); delete contents[slot]; } timePassed = ceph_clock_now(cct) - data.start_time; lock.Lock(); data.done = true; lock.Unlock(); pthread_join(print_thread, NULL); double bandwidth; bandwidth = ((double)data.finished)*((double)data.object_size)/(double)timePassed; bandwidth = bandwidth/(1024*1024); // we want it in MB/sec char bw[20]; snprintf(bw, sizeof(bw), "%.3lf \n", bandwidth); out(cout) << "Total time run: " << timePassed << std::endl << "Total writes made: " << data.finished << std::endl << "Write size: " << data.object_size << std::endl << "Bandwidth (MB/sec): " << bw << std::endl << "Stddev Bandwidth: " << vec_stddev(data.history.bandwidth) << std::endl << "Max bandwidth (MB/sec): " << data.idata.max_bandwidth << std::endl << "Min bandwidth (MB/sec): " << data.idata.min_bandwidth << std::endl << "Average Latency: " << data.avg_latency << std::endl << "Stddev Latency: " << vec_stddev(data.history.latency) << std::endl << "Max latency: " << data.max_latency << std::endl << "Min latency: " << data.min_latency << std::endl; //write object size/number data for read benchmarks ::encode(data.object_size, b_write); ::encode(data.finished, b_write); ::encode(getpid(), b_write); // persist meta-data for further cleanup or read sync_write(run_name_meta, b_write, sizeof(int)*3); completions_done(); return 0; ERR: lock.Lock(); data.done = 1; lock.Unlock(); pthread_join(print_thread, NULL); delete newContents; return -5; } int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurrentios, int pid) { lock_cond lc(&lock); std::vector name(concurrentios); std::string newName; bufferlist* contents[concurrentios]; int index[concurrentios]; int errors = 0; utime_t start_time; std::vector start_times(concurrentios); utime_t time_to_run; time_to_run.set_from_double(seconds_to_run); double total_latency = 0; int r = 0; utime_t runtime; sanitize_object_contents(&data, data.object_size); //clean it up once; subsequent //changes will be safe because string length should remain the same r = completions_init(concurrentios); if (r < 0) return r; //set up initial reads for (int i = 0; i < concurrentios; ++i) { name[i] = generate_object_name(i, pid); contents[i] = new bufferlist(); } lock.Lock(); data.finished = 0; data.start_time = ceph_clock_now(cct); lock.Unlock(); pthread_t print_thread; pthread_create(&print_thread, NULL, status_printer, (void *)this); utime_t finish_time = data.start_time + time_to_run; //start initial reads for (int i = 0; i < concurrentios; ++i) { index[i] = i; start_times[i] = ceph_clock_now(cct); create_completion(i, _aio_cb, (void *)&lc); r = aio_read(name[i], i, contents[i], data.object_size); if (r < 0) { //naughty, doesn't clean up heap -- oh, or handle the print thread! cerr << "r = " << r << std::endl; goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; lock.Unlock(); } //keep on adding new reads as old ones complete int slot; bufferlist *cur_contents; slot = 0; while (seconds_to_run && (ceph_clock_now(cct) < finish_time) && num_objects > data.started) { lock.Lock(); int old_slot = slot; bool found = false; while (1) { do { if (completion_is_done(slot)) { found = true; break; } slot++; if (slot == concurrentios) { slot = 0; } } while (slot != old_slot); if (found) { break; } lc.cond.Wait(lock); } lock.Unlock(); newName = generate_object_name(data.started, pid); int current_index = index[slot]; index[slot] = data.started; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r < 0) { cerr << "read got " << r << std::endl; lock.Unlock(); goto ERR; } data.cur_latency = ceph_clock_now(cct) - start_times[slot]; total_latency += data.cur_latency; if( data.cur_latency > data.max_latency) data.max_latency = data.cur_latency; if (data.cur_latency < data.min_latency) data.min_latency = data.cur_latency; ++data.finished; data.avg_latency = total_latency / data.finished; --data.in_flight; lock.Unlock(); release_completion(slot); cur_contents = contents[slot]; //start new read and check data if requested start_times[slot] = ceph_clock_now(cct); contents[slot] = new bufferlist(); create_completion(slot, _aio_cb, (void *)&lc); r = aio_read(newName, slot, contents[slot], data.object_size); if (r < 0) { goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; snprintf(data.object_contents, data.object_size, "I'm the %16dth object!", current_index); lock.Unlock(); if (memcmp(data.object_contents, cur_contents->c_str(), data.object_size) != 0) { cerr << name[slot] << " is not correct!" << std::endl; ++errors; } name[slot] = newName; delete cur_contents; } //wait for final reads to complete while (data.finished < data.started) { slot = data.finished % concurrentios; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r < 0) { cerr << "read got " << r << std::endl; lock.Unlock(); goto ERR; } data.cur_latency = ceph_clock_now(cct) - start_times[slot]; total_latency += data.cur_latency; if (data.cur_latency > data.max_latency) data.max_latency = data.cur_latency; if (data.cur_latency < data.min_latency) data.min_latency = data.cur_latency; ++data.finished; data.avg_latency = total_latency / data.finished; --data.in_flight; release_completion(slot); snprintf(data.object_contents, data.object_size, "I'm the %16dth object!", index[slot]); lock.Unlock(); if (memcmp(data.object_contents, contents[slot]->c_str(), data.object_size) != 0) { cerr << name[slot] << " is not correct!" << std::endl; ++errors; } delete contents[slot]; } runtime = ceph_clock_now(cct) - data.start_time; lock.Lock(); data.done = true; lock.Unlock(); pthread_join(print_thread, NULL); double bandwidth; bandwidth = ((double)data.finished)*((double)data.object_size)/(double)runtime; bandwidth = bandwidth/(1024*1024); // we want it in MB/sec char bw[20]; snprintf(bw, sizeof(bw), "%.3lf \n", bandwidth); out(cout) << "Total time run: " << runtime << std::endl << "Total reads made: " << data.finished << std::endl << "Read size: " << data.object_size << std::endl << "Bandwidth (MB/sec): " << bw << std::endl << "Average Latency: " << data.avg_latency << std::endl << "Max latency: " << data.max_latency << std::endl << "Min latency: " << data.min_latency << std::endl; completions_done(); return 0; ERR: lock.Lock(); data.done = 1; lock.Unlock(); pthread_join(print_thread, NULL); return -5; } int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurrentios, int pid) { lock_cond lc(&lock); std::vector name(concurrentios); std::string newName; bufferlist* contents[concurrentios]; int index[concurrentios]; int errors = 0; utime_t start_time; std::vector start_times(concurrentios); utime_t time_to_run; time_to_run.set_from_double(seconds_to_run); double total_latency = 0; int r = 0; utime_t runtime; sanitize_object_contents(&data, data.object_size); //clean it up once; subsequent //changes will be safe because string length should remain the same srand (time(NULL)); r = completions_init(concurrentios); if (r < 0) return r; //set up initial reads for (int i = 0; i < concurrentios; ++i) { name[i] = generate_object_name(i, pid); contents[i] = new bufferlist(); } lock.Lock(); data.finished = 0; data.start_time = ceph_clock_now(g_ceph_context); lock.Unlock(); pthread_t print_thread; pthread_create(&print_thread, NULL, status_printer, (void *)this); utime_t finish_time = data.start_time + time_to_run; //start initial reads for (int i = 0; i < concurrentios; ++i) { index[i] = i; start_times[i] = ceph_clock_now(g_ceph_context); create_completion(i, _aio_cb, (void *)&lc); r = aio_read(name[i], i, contents[i], data.object_size); if (r < 0) { //naughty, doesn't clean up heap -- oh, or handle the print thread! cerr << "r = " << r << std::endl; goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; lock.Unlock(); } //keep on adding new reads as old ones complete int slot; bufferlist *cur_contents; int rand_id; slot = 0; while (seconds_to_run && (ceph_clock_now(g_ceph_context) < finish_time)) { lock.Lock(); int old_slot = slot; bool found = false; while (1) { do { if (completion_is_done(slot)) { found = true; break; } slot++; if (slot == concurrentios) { slot = 0; } } while (slot != old_slot); if (found) { break; } lc.cond.Wait(lock); } lock.Unlock(); rand_id = rand() % num_objects; newName = generate_object_name(rand_id, pid); int current_index = index[slot]; index[slot] = rand_id; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r < 0) { cerr << "read got " << r << std::endl; lock.Unlock(); goto ERR; } data.cur_latency = ceph_clock_now(g_ceph_context) - start_times[slot]; total_latency += data.cur_latency; if( data.cur_latency > data.max_latency) data.max_latency = data.cur_latency; if (data.cur_latency < data.min_latency) data.min_latency = data.cur_latency; ++data.finished; data.avg_latency = total_latency / data.finished; --data.in_flight; lock.Unlock(); release_completion(slot); cur_contents = contents[slot]; //start new read and check data if requested start_times[slot] = ceph_clock_now(g_ceph_context); contents[slot] = new bufferlist(); create_completion(slot, _aio_cb, (void *)&lc); r = aio_read(newName, slot, contents[slot], data.object_size); if (r < 0) { goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; snprintf(data.object_contents, data.object_size, "I'm the %16dth object!", current_index); lock.Unlock(); if (memcmp(data.object_contents, cur_contents->c_str(), data.object_size) != 0) { cerr << name[slot] << " is not correct!" << std::endl; ++errors; } name[slot] = newName; delete cur_contents; } //wait for final reads to complete while (data.finished < data.started) { slot = data.finished % concurrentios; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r < 0) { cerr << "read got " << r << std::endl; lock.Unlock(); goto ERR; } data.cur_latency = ceph_clock_now(g_ceph_context) - start_times[slot]; total_latency += data.cur_latency; if (data.cur_latency > data.max_latency) data.max_latency = data.cur_latency; if (data.cur_latency < data.min_latency) data.min_latency = data.cur_latency; ++data.finished; data.avg_latency = total_latency / data.finished; --data.in_flight; release_completion(slot); snprintf(data.object_contents, data.object_size, "I'm the %16dth object!", index[slot]); lock.Unlock(); if (memcmp(data.object_contents, contents[slot]->c_str(), data.object_size) != 0) { cerr << name[slot] << " is not correct!" << std::endl; ++errors; } delete contents[slot]; } runtime = ceph_clock_now(g_ceph_context) - data.start_time; lock.Lock(); data.done = true; lock.Unlock(); pthread_join(print_thread, NULL); double bandwidth; bandwidth = ((double)data.finished)*((double)data.object_size)/(double)runtime; bandwidth = bandwidth/(1024*1024); // we want it in MB/sec char bw[20]; snprintf(bw, sizeof(bw), "%.3lf \n", bandwidth); out(cout) << "Total time run: " << runtime << std::endl << "Total reads made: " << data.finished << std::endl << "Read size: " << data.object_size << std::endl << "Bandwidth (MB/sec): " << bw << std::endl << "Average Latency: " << data.avg_latency << std::endl << "Max latency: " << data.max_latency << std::endl << "Min latency: " << data.min_latency << std::endl; completions_done(); return 0; ERR: lock.Lock(); data.done = 1; lock.Unlock(); pthread_join(print_thread, NULL); return -5; } int ObjBencher::clean_up(const char* prefix, int concurrentios, const char* run_name) { int r = 0; int object_size; int num_objects; int prevPid; // default meta object if user does not specify one const std::string run_name_meta = (run_name == NULL ? BENCH_LASTRUN_METADATA : std::string(run_name)); r = fetch_bench_metadata(run_name_meta, &object_size, &num_objects, &prevPid); if (r < 0) { // if the metadata file is not found we should try to do a linear search on the prefix if (r == -ENOENT && prefix != NULL) { return clean_up_slow(prefix, concurrentios); } else { return r; } } r = clean_up(num_objects, prevPid, concurrentios); if (r != 0) return r; r = sync_remove(run_name_meta); if (r != 0) return r; return 0; } int ObjBencher::clean_up(int num_objects, int prevPid, int concurrentios) { lock_cond lc(&lock); std::vector name(concurrentios); std::string newName; int r = 0; utime_t runtime; int slot = 0; lock.Lock(); data.done = false; data.in_flight = 0; data.started = 0; data.finished = 0; lock.Unlock(); // don't start more completions than files if (num_objects < concurrentios) { concurrentios = num_objects; } r = completions_init(concurrentios); if (r < 0) return r; //set up initial removes for (int i = 0; i < concurrentios; ++i) { name[i] = generate_object_name(i, prevPid); } //start initial removes for (int i = 0; i < concurrentios; ++i) { create_completion(i, _aio_cb, (void *)&lc); r = aio_remove(name[i], i); if (r < 0) { //naughty, doesn't clean up heap cerr << "r = " << r << std::endl; goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; lock.Unlock(); } //keep on adding new removes as old ones complete while (data.started < num_objects) { lock.Lock(); int old_slot = slot; bool found = false; while (1) { do { if (completion_is_done(slot)) { found = true; break; } slot++; if (slot == concurrentios) { slot = 0; } } while (slot != old_slot); if (found) { break; } lc.cond.Wait(lock); } lock.Unlock(); newName = generate_object_name(data.started, prevPid); completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r != 0 && r != -ENOENT) { // file does not exist cerr << "remove got " << r << std::endl; lock.Unlock(); goto ERR; } ++data.finished; --data.in_flight; lock.Unlock(); release_completion(slot); //start new remove and check data if requested create_completion(slot, _aio_cb, (void *)&lc); r = aio_remove(newName, slot); if (r < 0) { goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; lock.Unlock(); name[slot] = newName; } //wait for final removes to complete while (data.finished < data.started) { slot = data.finished % concurrentios; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r != 0 && r != -ENOENT) { // file does not exist cerr << "remove got " << r << std::endl; lock.Unlock(); goto ERR; } ++data.finished; --data.in_flight; release_completion(slot); lock.Unlock(); } lock.Lock(); data.done = true; lock.Unlock(); completions_done(); return 0; ERR: lock.Lock(); data.done = 1; lock.Unlock(); return -5; } /** * Return objects from the datastore which match a prefix. * * Clears the list and populates it with any objects which match the * prefix. The list is guaranteed to have at least one item when the * function returns true. * * @in * @param prefix the prefix to match against * @param objects return list of objects * @returns true if there are any objects in the store which match * the prefix, false if there are no more */ bool ObjBencher::more_objects_matching_prefix(const std::string& prefix, std::list* objects) { std::list unfiltered_objects; objects->clear(); while (objects->empty()) { bool objects_remain = get_objects(&unfiltered_objects, 20); if (!objects_remain) return false; std::list::const_iterator i = unfiltered_objects.begin(); for ( ; i != unfiltered_objects.end(); ++i) { const std::string& next = *i; if (next.substr(0, prefix.length()) == prefix) { objects->push_back(next); } } } return true; } int ObjBencher::clean_up_slow(const std::string& prefix, int concurrentios) { lock_cond lc(&lock); std::vector name(concurrentios); std::string newName; int r = 0; utime_t runtime; int slot = 0; std::list objects; bool objects_remain = true; lock.Lock(); data.done = false; data.in_flight = 0; data.started = 0; data.finished = 0; lock.Unlock(); out(cout) << "Warning: using slow linear search" << std::endl; r = completions_init(concurrentios); if (r < 0) return r; //set up initial removes for (int i = 0; i < concurrentios; ++i) { if (objects.empty()) { // if there are fewer objects than concurrent ios, don't generate extras bool objects_found = more_objects_matching_prefix(prefix, &objects); if (!objects_found) { concurrentios = i; objects_remain = false; break; } } name[i] = objects.front(); objects.pop_front(); } //start initial removes for (int i = 0; i < concurrentios; ++i) { create_completion(i, _aio_cb, (void *)&lc); r = aio_remove(name[i], i); if (r < 0) { //naughty, doesn't clean up heap cerr << "r = " << r << std::endl; goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; lock.Unlock(); } //keep on adding new removes as old ones complete while (objects_remain) { lock.Lock(); int old_slot = slot; bool found = false; while (1) { do { if (completion_is_done(slot)) { found = true; break; } slot++; if (slot == concurrentios) { slot = 0; } } while (slot != old_slot); if (found) { break; } lc.cond.Wait(lock); } lock.Unlock(); // get more objects if necessary if (objects.empty()) { objects_remain = more_objects_matching_prefix(prefix, &objects); // quit if there are no more if (!objects_remain) { break; } } // get the next object newName = objects.front(); objects.pop_front(); completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r != 0 && r != -ENOENT) { // file does not exist cerr << "remove got " << r << std::endl; lock.Unlock(); goto ERR; } ++data.finished; --data.in_flight; lock.Unlock(); release_completion(slot); //start new remove and check data if requested create_completion(slot, _aio_cb, (void *)&lc); r = aio_remove(newName, slot); if (r < 0) { goto ERR; } lock.Lock(); ++data.started; ++data.in_flight; lock.Unlock(); name[slot] = newName; } //wait for final removes to complete while (data.finished < data.started) { slot = data.finished % concurrentios; completion_wait(slot); lock.Lock(); r = completion_ret(slot); if (r != 0 && r != -ENOENT) { // file does not exist cerr << "remove got " << r << std::endl; lock.Unlock(); goto ERR; } ++data.finished; --data.in_flight; release_completion(slot); lock.Unlock(); } lock.Lock(); data.done = true; lock.Unlock(); completions_done(); out(cout) << "Removed " << data.finished << " object" << (data.finished != 1 ? "s" : "") << std::endl; return 0; ERR: lock.Lock(); data.done = 1; lock.Unlock(); return -5; } ceph-0.80.11/src/Makefile.am0000664000175100017510000002404512623076744017525 0ustar jenkins-buildjenkins-buildinclude Makefile-env.am SUBDIRS += ocf java DIST_SUBDIRS += gtest ocf libs3 java # subdirs include arch/Makefile.am include auth/Makefile.am include brag/Makefile.am include crush/Makefile.am include mon/Makefile.am include mds/Makefile.am include os/Makefile.am include osd/Makefile.am include erasure-code/Makefile.am include osdc/Makefile.am include client/Makefile.am include global/Makefile.am include json_spirit/Makefile.am include log/Makefile.am include perfglue/Makefile.am include common/Makefile.am include msg/Makefile.am include messages/Makefile.am include include/Makefile.am include librados/Makefile.am include librbd/Makefile.am include rgw/Makefile.am include cls/Makefile.am include key_value_store/Makefile.am include test/Makefile.am include tools/Makefile.am # core daemons ceph_mon_SOURCES = ceph_mon.cc ceph_mon_LDADD = $(LIBMON) $(LIBOS) $(CEPH_GLOBAL) $(LIBCOMMON) bin_PROGRAMS += ceph-mon ceph_osd_SOURCES = ceph_osd.cc ceph_osd_LDADD = $(LIBOSD) $(CEPH_GLOBAL) $(LIBCOMMON) bin_PROGRAMS += ceph-osd ceph_mds_SOURCES = ceph_mds.cc ceph_mds_LDADD = $(LIBMDS) $(LIBOSDC) $(CEPH_GLOBAL) $(LIBCOMMON) bin_PROGRAMS += ceph-mds # admin tools # user tools mount_ceph_SOURCES = mount/mount.ceph.c common/secret.c mount_ceph_LDADD = $(LIBCOMMON) $(KEYUTILS_LIB) if LINUX su_sbin_PROGRAMS += mount.ceph endif # LINUX su_sbin_SCRIPTS += mount.fuse.ceph cephfs_SOURCES = cephfs.cc cephfs_LDADD = $(LIBCOMMON) bin_PROGRAMS += cephfs librados_config_SOURCES = librados-config.cc librados_config_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_PROGRAMS += librados-config ceph_syn_SOURCES = ceph_syn.cc ceph_syn_SOURCES += client/SyntheticClient.cc # uses g_conf.. needs cleanup ceph_syn_LDADD = $(LIBCLIENT) $(CEPH_GLOBAL) bin_PROGRAMS += ceph-syn rbd_SOURCES = rbd.cc common/secret.c rbd_LDADD = $(LIBRBD) $(LIBRADOS) $(CEPH_GLOBAL) -lblkid $(KEYUTILS_LIB) if LINUX bin_PROGRAMS += rbd endif #LINUX # Fuse targets if WITH_FUSE ceph_fuse_SOURCES = ceph_fuse.cc ceph_fuse_LDADD = $(LIBCLIENT_FUSE) $(CEPH_GLOBAL) bin_PROGRAMS += ceph-fuse rbd_fuse_SOURCES = rbd_fuse/rbd-fuse.c rbd_fuse_LDADD = -lfuse $(LIBRBD) $(LIBRADOS) $(CEPH_GLOBAL) bin_PROGRAMS += rbd-fuse endif # WITH_FUSE # libcephfs (this should go somewhere else in the future) libcephfs_la_SOURCES = libcephfs.cc libcephfs_la_LIBADD = $(LIBCLIENT) $(LIBCOMMON) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) libcephfs_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '^ceph_.*' lib_LTLIBRARIES += libcephfs.la # jni library (java source is in src/java) if ENABLE_CEPHFS_JAVA libcephfs_jni_la_SOURCES = \ java/native/libcephfs_jni.cc \ java/native/ScopedLocalRef.h \ java/native/JniConstants.cpp \ java/native/JniConstants.h libcephfs_jni_la_LIBADD = $(LIBCEPHFS) $(EXTRALIBS) libcephfs_jni_la_CPPFLAGS = $(JDK_CPPFLAGS) $(AM_CPPFLAGS) libcephfs_jni_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 lib_LTLIBRARIES += libcephfs_jni.la endif # shell scripts editpaths = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@sbindir[@]|$(sbindir)|g' \ -e 's|@libdir[@]|$(libdir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@datadir[@]|$(pkgdatadir)|g' \ -e 's|@prefix[@]|$(prefix)|g' \ -e 's|@@GCOV_PREFIX_STRIP[@][@]|$(GCOV_PREFIX_STRIP)|g' shell_scripts = ceph-debugpack ceph-post-file ceph-crush-location $(shell_scripts): Makefile $(shell_scripts): %: %.in rm -f $@ $@.tmp $(editpaths) '$(srcdir)/$@.in' >$@.tmp chmod +x $@.tmp chmod a-w $@.tmp mv $@.tmp $@ EXTRA_DIST += $(srcdir)/$(shell_scripts:%=%.in) CLEANFILES += $(shell_scripts) # extra bits EXTRA_DIST += \ $(srcdir)/verify-mds-journal.sh \ $(srcdir)/vstart.sh \ $(srcdir)/stop.sh \ ceph-run \ $(srcdir)/ceph_common.sh \ $(srcdir)/init-radosgw \ $(srcdir)/init-radosgw.sysv \ $(srcdir)/init-rbdmap \ $(srcdir)/ceph-clsinfo \ $(srcdir)/make_version \ $(srcdir)/check_version \ $(srcdir)/.git_version \ $(srcdir)/ceph-rbdnamer \ $(srcdir)/test/encoding/readable.sh \ $(srcdir)/test/encoding/check-generated.sh \ $(srcdir)/upstart/ceph-all.conf \ $(srcdir)/upstart/ceph-mon.conf \ $(srcdir)/upstart/ceph-mon-all.conf \ $(srcdir)/upstart/ceph-mon-all-starter.conf \ $(srcdir)/upstart/ceph-create-keys.conf \ $(srcdir)/upstart/ceph-osd.conf \ $(srcdir)/upstart/ceph-osd-all.conf \ $(srcdir)/upstart/ceph-osd-all-starter.conf \ $(srcdir)/upstart/ceph-mds.conf \ $(srcdir)/upstart/ceph-mds-all.conf \ $(srcdir)/upstart/ceph-mds-all-starter.conf \ $(srcdir)/upstart/radosgw.conf \ $(srcdir)/upstart/radosgw-all.conf \ $(srcdir)/upstart/radosgw-all-starter.conf \ $(srcdir)/upstart/rbdmap.conf \ ceph.in \ ceph-disk \ ceph-disk-prepare \ ceph-disk-activate \ ceph-disk-udev \ ceph-create-keys \ ceph-rest-api \ ceph-crush-location \ mount.fuse.ceph \ rbdmap \ unittest_bufferlist.sh \ yasm-wrapper EXTRA_DIST += \ libs3/COPYING \ libs3/ChangeLog \ libs3/GNUmakefile \ libs3/GNUmakefile.mingw \ libs3/GNUmakefile.osx \ libs3/INSTALL \ libs3/LICENSE \ libs3/README \ libs3/TODO \ libs3/archlinux \ libs3/debian \ libs3/doxyfile \ libs3/inc \ libs3/libs3.spec \ libs3/mswin \ libs3/src \ libs3/test \ unittest_bufferlist.sh # work around old versions of automake that don't define $docdir # NOTE: this won't work on suse, where docdir is /usr/share/doc/packages/$package. docdir ?= ${datadir}/doc/ceph doc_DATA = $(srcdir)/sample.ceph.conf sample.fetch_config # various scripts shell_commondir = $(libdir)/ceph shell_common_SCRIPTS = ceph_common.sh bash_completiondir = $(sysconfdir)/bash_completion.d bash_completion_DATA = $(srcdir)/bash_completion/ceph \ $(srcdir)/bash_completion/rados \ $(srcdir)/bash_completion/rbd \ $(srcdir)/bash_completion/radosgw-admin ceph_sbin_SCRIPTS = \ ceph-disk \ ceph-disk-prepare \ ceph-disk-activate \ ceph-disk-udev \ ceph-create-keys bin_SCRIPTS += \ ceph \ ceph-run \ ceph-rest-api \ ceph-clsinfo \ ceph-debugpack \ ceph-rbdnamer \ ceph-post-file \ ceph-crush-location BUILT_SOURCES += init-ceph su_sbin_SCRIPTS += mkcephfs shell_scripts += init-ceph mkcephfs # tests to actually run on "make check"; if you need extra, non-test, # executables built, you need to replace this with manual assignments # target by target TESTS = \ $(check_PROGRAMS) \ $(check_SCRIPTS) check-local: $(top_srcdir)/qa/workunits/erasure-code/encode-decode-non-regression.sh $(srcdir)/test/encoding/readable.sh ../ceph-object-corpus # base targets core-daemons: ceph-mon ceph-osd ceph-mds radosgw admin-tools: monmaptool osdmaptool crushtool ceph-authtool base: core-daemons admin-tools \ cephfs ceph-syn ceph-conf \ rados librados-config \ init-ceph mkcephfs ceph_mon_store_converter ceph-post-file # version stuff FORCE: .git_version: FORCE $(srcdir)/check_version $(srcdir)/.git_version # if NO_VERSION is set, only generate a new ceph_ver.h if there currently # is none, and call "make_version -n" to fill it with a fixed string. # Otherwise, set it from the contents of .git_version. ceph_ver.h: .git_version if [ -n "$$NO_VERSION" ] ; then \ if [ ! -f ./ceph_ver.h ] ; then \ $(srcdir)/make_version -n ./ceph_ver.h ; \ fi; \ else \ $(srcdir)/make_version $(srcdir)/.git_version ./ceph_ver.h ; \ fi ceph_ver.c: ./ceph_ver.h common/version.cc: ./ceph_ver.h test/encoding/ceph_dencoder.cc: ./ceph_ver.h sample.fetch_config: fetch_config cp -f $(srcdir)/fetch_config ./sample.fetch_config dist-hook: $(srcdir)/check_version $(srcdir)/.git_version CLEANFILES += ceph_ver.h sample.fetch_config # assemble Python script with global version variables # NB: depends on format of ceph_ver.h ceph: ceph.in ./ceph_ver.h Makefile rm -f $@ $@.tmp echo "#!/usr/bin/env python" >$@.tmp grep "#define CEPH_GIT_NICE_VER" ./ceph_ver.h | \ sed -e 's/#define \(.*VER\) /\1=/' >>$@.tmp grep "#define CEPH_GIT_VER" ./ceph_ver.h | \ sed -e 's/#define \(.*VER\) /\1=/' -e 's/=\(.*\)$$/="\1"/' >>$@.tmp cat $(srcdir)/$@.in >>$@.tmp chmod a+x $@.tmp chmod a-w $@.tmp mv $@.tmp $@ # cleaning clean-local: rm -f *.so find . -name '*.gcno' -o -name '*.gcda' -o -name '*.lcov' | xargs rm -f rm -f ceph java/java/com/ceph/crush/Bucket.class # pybind python_PYTHON = pybind/rados.py \ pybind/rbd.py \ pybind/cephfs.py \ pybind/ceph_argparse.py \ pybind/ceph_rest_api.py # everything else we want to include in a 'make dist' noinst_HEADERS += \ cls_acl.cc\ cls_crypto.cc\ fetch_config\ logrotate.conf\ sample.ceph.conf\ bash_completion/ceph \ bash_completion/rados \ bash_completion/rbd \ bash_completion/radosgw-admin \ mount/canonicalize.c \ mount/mtab.c \ objclass/objclass.h # coverage shell_scripts += ceph-coverage bin_SCRIPTS += ceph-coverage if ENABLE_COVERAGE COV_DIR = $(DESTDIR)$(libdir)/ceph/coverage COV_FILES = $(srcdir)/*.gcno COV_LIB_FILES = $(srcdir)/.libs/*.gcno endif install-coverage: if ENABLE_COVERAGE -mkdir -p $(COV_DIR)/.libs -$(INSTALL_DATA) $(COV_FILES) $(COV_DIR) -$(INSTALL_DATA) $(COV_LIB_FILES) $(COV_DIR)/.libs endif uninstall-coverage: if ENABLE_COVERAGE -rm $(COV_DIR)/*.gcno -rm $(COV_DIR)/.libs/*.gcno -rmdir -p $(COV_DIR)/.libs -rmdir -p $(COV_DIR) endif check-coverage: if ENABLE_COVERAGE -test/coverage.sh -d $(srcdir) -o check-coverage make check endif install-data-local: install-coverage -mkdir -p $(DESTDIR)$(sysconfdir)/ceph -mkdir -p $(DESTDIR)$(localstatedir)/log/ceph -mkdir -p $(DESTDIR)$(localstatedir)/lib/ceph/tmp uninstall-local: uninstall-coverage -rmdir -p $(DESTDIR)$(sysconfdir)/ceph/ -rmdir -p $(DESTDIR)$(localstatedir)/log/ceph -rmdir -p $(DESTDIR)$(localstatedir)/lib/ceph/tmp # # coverity rules expect: # - cov-build to be in the path # - password in ~/coverity.build.pass.txt # - ability to scp into the ceph.com directory # project.tgz: clean rm -rf cov-int cov-build --dir cov-int make echo Sage Weil sage@newdream.net ceph >> README tar czvf project.tgz README cov-int rm -f README coverity-submit: scp project.tgz ceph.com:/home/ceph_site/ceph.com/coverity/`git describe`.tgz curl --data "project=ceph&password=`cat ~/coverity.build.pass.txt`&email=sage@newdream.net&url=http://ceph.com/coverity/`git describe`.tgz" http://scan5.coverity.com/cgi-bin/submit_build.py ceph-0.80.11/src/ceph_common.sh0000664000175100017510000001500312623076744020306 0ustar jenkins-buildjenkins-build#!/bin/sh CCONF="$BINDIR/ceph-conf" default_conf=$ETCDIR"/ceph.conf" conf=$default_conf hostname=`hostname -s` verify_conf() { # fetch conf? if [ -x "$ETCDIR/fetch_config" ] && [ "$conf" = "$default_conf" ]; then conf="/tmp/fetched.ceph.conf.$$" echo "[$ETCDIR/fetch_config $conf]" if $ETCDIR/fetch_config $conf && [ -e $conf ]; then true ; else echo "$0: failed to fetch config with '$ETCDIR/fetch_config $conf'" exit 1 fi # yay! else # make sure ceph.conf exists if [ ! -e $conf ]; then if [ "$conf" = "$default_conf" ]; then echo "$0: ceph conf $conf not found; system is not configured." exit 0 fi echo "$0: ceph conf $conf not found!" usage_exit fi fi } check_host() { # what host is this daemon assigned to? host=`$CCONF -c $conf -n $type.$id host` if [ "$host" = "localhost" ]; then echo "$0: use a proper short hostname (hostname -s), not 'localhost', in $conf section $type.$id; skipping entry" return 1 fi if expr match "$host" '.*\.' > /dev/null 2>&1; then echo "$0: $conf section $type.$id" echo "contains host=$host, which contains dots; this is probably wrong" echo "It must match the result of hostname -s" fi ssh="" rootssh="" sshdir=$PWD get_conf user "" "user" #echo host for $name is $host, i am $hostname cluster=$1 if [ -e "/var/lib/ceph/$type/$cluster-$id/upstart" ]; then return 1 fi # sysvinit managed instance in standard location? if [ -e "/var/lib/ceph/$type/$cluster-$id/sysvinit" ]; then host="$hostname" echo "=== $type.$id === " return 0 fi # ignore all sections without 'host' defined if [ -z "$host" ]; then return 1 fi if [ "$host" != "$hostname" ]; then # skip, unless we're starting remote daemons too if [ $allhosts -eq 0 ]; then return 1 fi # we'll need to ssh into that host if [ -z "$user" ]; then ssh="ssh $host" else ssh="ssh $user@$host" fi rootssh="ssh root@$host" get_conf sshdir "$sshdir" "ssh path" fi echo "=== $type.$id === " return 0 } do_cmd() { if [ -z "$ssh" ]; then [ $verbose -eq 1 ] && echo "--- $host# $1" ulimit -c unlimited whoami=`whoami` if [ "$whoami" = "$user" ] || [ -z "$user" ]; then bash -c "$1" || { [ -z "$3" ] && echo "failed: '$1'" && exit 1; } else sudo su $user -c "$1" || { [ -z "$3" ] && echo "failed: '$1'" && exit 1; } fi else [ $verbose -eq 1 ] && echo "--- $ssh $2 \"if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi; cd $sshdir ; ulimit -c unlimited ; $1\"" $ssh $2 "if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi; cd $sshdir ; ulimit -c unlimited ; $1" || { [ -z "$3" ] && echo "failed: '$ssh $1'" && exit 1; } fi } do_cmd_okfail() { ERR=0 if [ -z "$ssh" ]; then [ $verbose -eq 1 ] && echo "--- $host# $1" ulimit -c unlimited whoami=`whoami` if [ "$whoami" = "$user" ] || [ -z "$user" ]; then bash -c "$1" || { [ -z "$3" ] && echo "failed: '$1'" && ERR=1 && return 1; } else sudo su $user -c "$1" || { [ -z "$3" ] && echo "failed: '$1'" && ERR=1 && return 1; } fi else [ $verbose -eq 1 ] && echo "--- $ssh $2 \"if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi; cd $sshdir ; ulimit -c unlimited ; $1\"" $ssh $2 "if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi; cd $sshdir ; ulimit -c unlimited ; $1" || { [ -z "$3" ] && echo "failed: '$ssh $1'" && ERR=1 && return 1; } fi return 0 } do_root_cmd() { if [ -z "$ssh" ]; then [ $verbose -eq 1 ] && echo "--- $host# $1" ulimit -c unlimited whoami=`whoami` if [ "$whoami" = "root" ]; then bash -c "$1" || { echo "failed: '$1'" ; exit 1; } else sudo bash -c "$1" || { echo "failed: '$1'" ; exit 1; } fi else [ $verbose -eq 1 ] && echo "--- $rootssh $2 \"if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi ; cd $sshdir ; ulimit -c unlimited ; $1\"" $rootssh $2 "if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi ; cd $sshdir; ulimit -c unlimited ; $1" || { echo "failed: '$rootssh $1'" ; exit 1; } fi } do_root_cmd_okfail() { ERR=0 if [ -z "$ssh" ]; then [ $verbose -eq 1 ] && echo "--- $host# $1" ulimit -c unlimited whoami=`whoami` if [ "$whoami" = "root" ]; then bash -c "$1" || { [ -z "$3" ] && echo "failed: '$1'" && ERR=1 && return 1; } else sudo bash -c "$1" || { [ -z "$3" ] && echo "failed: '$1'" && ERR=1 && return 1; } fi else [ $verbose -eq 1 ] && echo "--- $rootssh $2 \"if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi; cd $sshdir ; ulimit -c unlimited ; $1\"" $rootssh $2 "if [ ! -d $sshdir ]; then mkdir -p $sshdir; fi; cd $sshdir ; ulimit -c unlimited ; $1" || { [ -z "$3" ] && echo "failed: '$rootssh $1'" && ERR=1 && return 1; } fi return 0 } get_local_daemon_list() { type=$1 if [ -d "/var/lib/ceph/$type" ]; then for i in `find -L /var/lib/ceph/$type -mindepth 1 -maxdepth 1 -type d -printf '%f\n'`; do if [ -e "/var/lib/ceph/$type/$i/sysvinit" ]; then id=`echo $i | sed 's/[^-]*-//'` local="$local $type.$id" fi done fi } get_local_name_list() { # enumerate local directories local="" get_local_daemon_list "mon" get_local_daemon_list "osd" get_local_daemon_list "mds" } get_name_list() { orig="$*" # extract list of monitors, mdss, osds defined in startup.conf allconf="$local "`$CCONF -c $conf -l mon | egrep -v '^mon$' || true ; \ $CCONF -c $conf -l mds | egrep -v '^mds$' || true ; \ $CCONF -c $conf -l osd | egrep -v '^osd$' || true` if [ -z "$orig" ]; then what="$allconf" return fi what="" for f in $orig; do type=`echo $f | cut -c 1-3` # e.g. 'mon', if $item is 'mon1' id=`echo $f | cut -c 4- | sed 's/\\.//'` case $f in mon | osd | mds) for d in $allconf; do if echo $d | grep -q ^$type; then what="$what $d" fi done ;; *) if ! echo " " $allconf $local " " | egrep -q "( $type$id | $type.$id )"; then echo "$0: $type.$id not found ($conf defines" $allconf", /var/lib/ceph defines" $local")" exit 1 fi what="$what $f" ;; esac done } get_conf() { var=$1 def=$2 key=$3 shift; shift; shift if [ -z "$1" ]; then [ "$verbose" -eq 1 ] && echo "$CCONF -c $conf -n $type.$id \"$key\"" eval "$var=\"`$CCONF -c $conf -n $type.$id \"$key\" || eval echo -n \"$def\"`\"" else [ "$verbose" -eq 1 ] && echo "$CCONF -c $conf -s $1 \"$key\"" eval "$var=\"`$CCONF -c $conf -s $1 \"$key\" || eval echo -n \"$def\"`\"" fi } get_conf_bool() { get_conf "$@" eval "val=$"$1 [ "$val" = "0" ] && export $1=0 [ "$val" = "false" ] && export $1=0 [ "$val" = "1" ] && export $1=1 [ "$val" = "true" ] && export $1=1 } ceph-0.80.11/src/ceph-disk-prepare0000775000175100017510000000006512623076744020716 0ustar jenkins-buildjenkins-build#!/bin/sh dir=`dirname $0` $dir/ceph-disk prepare $* ceph-0.80.11/src/rbd_fuse/0000775000175100017510000000000012623077036017250 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/rbd_fuse/rbd-fuse.c0000664000175100017510000003716512623076744021144 0ustar jenkins-buildjenkins-build/* * rbd-fuse */ #define FUSE_USE_VERSION 30 #include "include/int_types.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "include/rbd/librbd.h" static int gotrados = 0; char *pool_name; rados_t cluster; rados_ioctx_t ioctx; static pthread_mutex_t readdir_lock; struct rbd_stat { u_char valid; rbd_image_info_t rbd_info; }; struct rbd_options { char *ceph_config; char *pool_name; }; struct rbd_image { char *image_name; struct rbd_image *next; }; struct rbd_image *rbd_images; struct rbd_openimage { char *image_name; rbd_image_t image; struct rbd_stat rbd_stat; }; #define MAX_RBD_IMAGES 128 struct rbd_openimage opentbl[MAX_RBD_IMAGES]; struct rbd_options rbd_options = {"/etc/ceph/ceph.conf", "rbd"}; #define rbdsize(fd) opentbl[fd].rbd_stat.rbd_info.size #define rbdblksize(fd) opentbl[fd].rbd_stat.rbd_info.obj_size #define rbdblkcnt(fd) opentbl[fd].rbd_stat.rbd_info.num_objs uint64_t imagesize = 1024ULL * 1024 * 1024; uint64_t imageorder = 22ULL; uint64_t imagefeatures = 1ULL; // Minimize calls to rbd_list: marks bracketing of opendir//releasedir int in_opendir; /* prototypes */ int connect_to_cluster(rados_t *pcluster); void enumerate_images(struct rbd_image **head); int open_rbd_image(const char *image_name); int find_openrbd(const char *path); void simple_err(const char *msg, int err); void enumerate_images(struct rbd_image **head) { char *ibuf = NULL; size_t ibuf_len = 0; struct rbd_image *im, *next; char *ip; int ret; if (*head != NULL) { for (im = *head; im != NULL;) { next = im->next; free(im); im = next; } *head = NULL; } ret = rbd_list(ioctx, ibuf, &ibuf_len); if (ret == -ERANGE) { assert(ibuf_len > 0); ibuf = malloc(ibuf_len); if (!ibuf) { simple_err("Failed to get ibuf", -ENOMEM); return; } } else if (ret < 0) { simple_err("Failed to get ibuf_len", ret); return; } ret = rbd_list(ioctx, ibuf, &ibuf_len); if (ret < 0) { simple_err("Failed to populate ibuf", ret); free(ibuf); return; } assert(ret == (int)ibuf_len); fprintf(stderr, "pool %s: ", pool_name); for (ip = ibuf; ip < &ibuf[ibuf_len]; ip += strlen(ip) + 1) { fprintf(stderr, "%s, ", ip); im = malloc(sizeof(*im)); im->image_name = ip; im->next = *head; *head = im; } fprintf(stderr, "\n"); } int find_openrbd(const char *path) { int i; /* find in opentbl[] entry if already open */ for (i = 0; i < MAX_RBD_IMAGES; i++) { if ((opentbl[i].image_name != NULL) && (strcmp(opentbl[i].image_name, path) == 0)) { return i; } } return -1; } int open_rbd_image(const char *image_name) { struct rbd_image *im; struct rbd_openimage *rbd; int fd; if (image_name == (char *)NULL) return -1; // relies on caller to keep rbd_images up to date for (im = rbd_images; im != NULL; im = im->next) { if (strcmp(im->image_name, image_name) == 0) { break; } } if (im == NULL) return -1; /* find in opentbl[] entry if already open */ if ((fd = find_openrbd(image_name)) != -1) { rbd = &opentbl[fd]; } else { int i; // allocate an opentbl[] and open the image for (i = 0; i < MAX_RBD_IMAGES; i++) { if (opentbl[i].image == NULL) { fd = i; rbd = &opentbl[fd]; rbd->image_name = strdup(image_name); break; } } if (i == MAX_RBD_IMAGES) return -1; int ret = rbd_open(ioctx, rbd->image_name, &(rbd->image), NULL); if (ret < 0) { simple_err("open_rbd_image: can't open: ", ret); return ret; } } rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info), sizeof(rbd_image_info_t)); rbd->rbd_stat.valid = 1; return fd; } static void iter_images(void *cookie, void (*iter)(void *cookie, const char *image)) { struct rbd_image *im; pthread_mutex_lock(&readdir_lock); for (im = rbd_images; im != NULL; im = im->next) iter(cookie, im->image_name); pthread_mutex_unlock(&readdir_lock); } static void count_images_cb(void *cookie, const char *image) { (*((unsigned int *)cookie))++; } static int count_images(void) { unsigned int count = 0; pthread_mutex_lock(&readdir_lock); enumerate_images(&rbd_images); pthread_mutex_unlock(&readdir_lock); iter_images(&count, count_images_cb); return count; } static int rbdfs_getattr(const char *path, struct stat *stbuf) { int fd; time_t now; if (!gotrados) return -ENXIO; if (path[0] == 0) return -ENOENT; memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { now = time(NULL); stbuf->st_mode = S_IFDIR + 0755; stbuf->st_nlink = 2+count_images(); stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); stbuf->st_size = 1024; stbuf->st_blksize = 1024; stbuf->st_blocks = 1; stbuf->st_atime = now; stbuf->st_mtime = now; stbuf->st_ctime = now; return 0; } if (!in_opendir) { pthread_mutex_lock(&readdir_lock); enumerate_images(&rbd_images); pthread_mutex_unlock(&readdir_lock); } fd = open_rbd_image(path + 1); if (fd < 0) return -ENOENT; now = time(NULL); stbuf->st_mode = S_IFREG | 0666; stbuf->st_nlink = 1; stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); stbuf->st_size = rbdsize(fd); stbuf->st_blksize = rbdblksize(fd); stbuf->st_blocks = rbdblkcnt(fd); stbuf->st_atime = now; stbuf->st_mtime = now; stbuf->st_ctime = now; return 0; } static int rbdfs_open(const char *path, struct fuse_file_info *fi) { int fd; if (!gotrados) return -ENXIO; if (path[0] == 0) return -ENOENT; pthread_mutex_lock(&readdir_lock); enumerate_images(&rbd_images); pthread_mutex_unlock(&readdir_lock); fd = open_rbd_image(path + 1); if (fd < 0) return -ENOENT; fi->fh = fd; return 0; } static int rbdfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t numread; struct rbd_openimage *rbd; if (!gotrados) return -ENXIO; rbd = &opentbl[fi->fh]; numread = 0; while (size > 0) { ssize_t ret; ret = rbd_read(rbd->image, offset, size, buf); if (ret <= 0) break; buf += ret; size -= ret; offset += ret; numread += ret; } return numread; } static int rbdfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t numwritten; struct rbd_openimage *rbd; if (!gotrados) return -ENXIO; rbd = &opentbl[fi->fh]; numwritten = 0; while (size > 0) { ssize_t ret; if (offset + size > rbdsize(fi->fh)) { int r; fprintf(stderr, "rbdfs_write resizing %s to 0x%"PRIxMAX"\n", path, offset+size); r = rbd_resize(rbd->image, offset+size); if (r < 0) return r; r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info), sizeof(rbd_image_info_t)); if (r < 0) return r; } ret = rbd_write(rbd->image, offset, size, buf); if (ret < 0) break; buf += ret; size -= ret; offset += ret; numwritten += ret; } return numwritten; } static void rbdfs_statfs_image_cb(void *num, const char *image) { int fd; ((uint64_t *)num)[0]++; fd = open_rbd_image(image); if (fd >= 0) ((uint64_t *)num)[1] += rbdsize(fd); } static int rbdfs_statfs(const char *path, struct statvfs *buf) { uint64_t num[2]; if (!gotrados) return -ENXIO; num[0] = 1; num[1] = 0; pthread_mutex_lock(&readdir_lock); enumerate_images(&rbd_images); pthread_mutex_unlock(&readdir_lock); iter_images(num, rbdfs_statfs_image_cb); #define RBDFS_BSIZE 4096 buf->f_bsize = RBDFS_BSIZE; buf->f_frsize = RBDFS_BSIZE; buf->f_blocks = num[1] / RBDFS_BSIZE; buf->f_bfree = 0; buf->f_bavail = 0; buf->f_files = num[0]; buf->f_ffree = 0; buf->f_favail = 0; buf->f_fsid = 0; buf->f_flag = 0; buf->f_namemax = PATH_MAX; return 0; } static int rbdfs_fsync(const char *path, int datasync, struct fuse_file_info *fi) { if (!gotrados) return -ENXIO; rbd_flush(opentbl[fi->fh].image); return 0; } static int rbdfs_opendir(const char *path, struct fuse_file_info *fi) { // only one directory, so global "in_opendir" flag should be fine pthread_mutex_lock(&readdir_lock); in_opendir++; enumerate_images(&rbd_images); pthread_mutex_unlock(&readdir_lock); return 0; } struct rbdfs_readdir_info { void *buf; fuse_fill_dir_t filler; }; static void rbdfs_readdir_cb(void *_info, const char *name) { struct rbdfs_readdir_info *info = _info; info->filler(info->buf, name, NULL, 0); } static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { struct rbdfs_readdir_info info = { buf, filler }; if (!gotrados) return -ENXIO; if (!in_opendir) fprintf(stderr, "in readdir, but not inside opendir?\n"); if (strcmp(path, "/") != 0) return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); iter_images(&info, rbdfs_readdir_cb); return 0; } static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi) { // see opendir comments pthread_mutex_lock(&readdir_lock); in_opendir--; pthread_mutex_unlock(&readdir_lock); return 0; } void * rbdfs_init(struct fuse_conn_info *conn) { int ret; // init cannot fail, so if we fail here, gotrados remains at 0, // causing other operations to fail immediately with ENXIO ret = connect_to_cluster(&cluster); if (ret < 0) exit(90); pool_name = rbd_options.pool_name; ret = rados_ioctx_create(cluster, pool_name, &ioctx); if (ret < 0) exit(91); #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) conn->want |= FUSE_CAP_BIG_WRITES; #endif gotrados = 1; // init's return value shows up in fuse_context.private_data, // also to void (*destroy)(void *); useful? return NULL; } // return -errno on error. fi->fh is not set until open time int rbdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) { int r; int order = imageorder; r = rbd_create2(ioctx, path+1, imagesize, imagefeatures, &order); return r; } int rbdfs_utime(const char *path, struct utimbuf *utime) { // called on create; not relevant return 0; } int rbdfs_unlink(const char *path) { int fd = find_openrbd(path); if (fd != -1) { struct rbd_openimage *rbd = &opentbl[fd]; rbd_close(rbd->image); rbd->image = 0; free(rbd->image_name); rbd->rbd_stat.valid = 0; } return rbd_remove(ioctx, path+1); } int rbdfs_truncate(const char *path, off_t size) { int fd; int r; struct rbd_openimage *rbd; if ((fd = open_rbd_image(path+1)) < 0) return -ENOENT; rbd = &opentbl[fd]; fprintf(stderr, "truncate %s to %"PRIdMAX" (0x%"PRIxMAX")\n", path, size, size); r = rbd_resize(rbd->image, size); if (r < 0) return r; r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info), sizeof(rbd_image_info_t)); if (r < 0) return r; return 0; } /** * set an xattr on path, with name/value, length size. * Presumably flags are from Linux, as in XATTR_CREATE or * XATTR_REPLACE (both "set", but fail if exist vs fail if not exist. * * We accept xattrs only on the root node. * * All values converted with strtoull, so can be expressed in any base */ struct rbdfuse_attr { char *attrname; uint64_t *attrvalp; } attrs[] = { { "user.rbdfuse.imagesize", &imagesize }, { "user.rbdfuse.imageorder", &imageorder }, { "user.rbdfuse.imagefeatures", &imagefeatures }, { NULL } }; int rbdfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { struct rbdfuse_attr *ap; if (strcmp(path, "/") != 0) return -EINVAL; for (ap = attrs; ap->attrname != NULL; ap++) { if (strcmp(name, ap->attrname) == 0) { *ap->attrvalp = strtoull(value, NULL, 0); fprintf(stderr, "rbd-fuse: %s set to 0x%"PRIx64"\n", ap->attrname, *ap->attrvalp); return 0; } } return -EINVAL; } int rbdfs_getxattr(const char *path, const char *name, char *value, size_t size) { struct rbdfuse_attr *ap; char buf[128]; // allow gets on other files; ls likes to ask for things like // security.* for (ap = attrs; ap->attrname != NULL; ap++) { if (strcmp(name, ap->attrname) == 0) { sprintf(buf, "%"PRIu64, *ap->attrvalp); if (value != NULL && size >= strlen(buf)) strcpy(value, buf); fprintf(stderr, "rbd-fuse: get %s\n", ap->attrname); return (strlen(buf)); } } return 0; } int rbdfs_listxattr(const char *path, char *list, size_t len) { struct rbdfuse_attr *ap; size_t required_len = 0; if (strcmp(path, "/") != 0) return -EINVAL; for (ap = attrs; ap->attrname != NULL; ap++) required_len += strlen(ap->attrname) + 1; if (len >= required_len) { for (ap = attrs; ap->attrname != NULL; ap++) { sprintf(list, "%s", ap->attrname); list += strlen(ap->attrname) + 1; } } return required_len; } static struct fuse_operations rbdfs_oper = { .create = rbdfs_create, .fsync = rbdfs_fsync, .getattr = rbdfs_getattr, .getxattr = rbdfs_getxattr, .init = rbdfs_init, .listxattr = rbdfs_listxattr, .open = rbdfs_open, .opendir = rbdfs_opendir, .read = rbdfs_read, .readdir = rbdfs_readdir, .releasedir = rbdfs_releasedir, .setxattr = rbdfs_setxattr, .statfs = rbdfs_statfs, .truncate = rbdfs_truncate, .unlink = rbdfs_unlink, .utime = rbdfs_utime, .write = rbdfs_write, }; enum { KEY_HELP, KEY_VERSION, KEY_CEPH_CONFIG, KEY_CEPH_CONFIG_LONG, KEY_RADOS_POOLNAME, KEY_RADOS_POOLNAME_LONG }; static struct fuse_opt rbdfs_opts[] = { FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), FUSE_OPT_KEY("-V", KEY_VERSION), FUSE_OPT_KEY("--version", KEY_VERSION), {"-c %s", offsetof(struct rbd_options, ceph_config), KEY_CEPH_CONFIG}, {"--configfile=%s", offsetof(struct rbd_options, ceph_config), KEY_CEPH_CONFIG_LONG}, {"-p %s", offsetof(struct rbd_options, pool_name), KEY_RADOS_POOLNAME}, {"--poolname=%s", offsetof(struct rbd_options, pool_name), KEY_RADOS_POOLNAME_LONG}, }; static void usage(const char *progname) { fprintf(stderr, "Usage: %s mountpoint [options]\n" "\n" "General options:\n" " -h --help print help\n" " -V --version print version\n" " -c --configfile ceph configuration file [/etc/ceph/ceph.conf]\n" " -p --poolname rados pool name [rbd]\n" "\n", progname); } static int rbdfs_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { if (key == KEY_HELP) { usage(outargs->argv[0]); fuse_opt_add_arg(outargs, "-ho"); fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL); exit(1); } if (key == KEY_VERSION) { fuse_opt_add_arg(outargs, "--version"); fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL); exit(0); } if (key == KEY_CEPH_CONFIG) { if (rbd_options.ceph_config != NULL) { free(rbd_options.ceph_config); rbd_options.ceph_config = NULL; } rbd_options.ceph_config = strdup(arg+2); return 0; } if (key == KEY_RADOS_POOLNAME) { if (rbd_options.pool_name != NULL) { free(rbd_options.pool_name); rbd_options.pool_name = NULL; } rbd_options.pool_name = strdup(arg+2); return 0; } return 1; } void simple_err(const char *msg, int err) { fprintf(stderr, "%s: %s\n", msg, strerror(-err)); return; } int connect_to_cluster(rados_t *pcluster) { int r; r = rados_create(pcluster, NULL); if (r < 0) { simple_err("Could not create cluster handle", r); return r; } rados_conf_parse_env(*pcluster, NULL); r = rados_conf_read_file(*pcluster, rbd_options.ceph_config); if (r < 0) { simple_err("Error reading Ceph config file", r); goto failed_shutdown; } r = rados_connect(*pcluster); if (r < 0) { simple_err("Error connecting to cluster", r); goto failed_shutdown; } return 0; failed_shutdown: rados_shutdown(*pcluster); return r; } int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); if (fuse_opt_parse(&args, &rbd_options, rbdfs_opts, rbdfs_opt_proc) == -1) { exit(1); } pthread_mutex_init(&readdir_lock, NULL); return fuse_main(args.argc, args.argv, &rbdfs_oper, NULL); } ceph-0.80.11/src/unittest_bufferlist.sh0000775000175100017510000000126112623076744022127 0ustar jenkins-buildjenkins-build#!/bin/sh # # Ceph - scalable distributed file system # # Copyright (C) 2013 Cloudwatt # # Author: Loic Dachary # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library Public License for more details. # CEPH_BUFFER_TRACK=true ./unittest_bufferlist ceph-0.80.11/src/yasm-wrapper0000775000175100017510000000105312623076744020040 0ustar jenkins-buildjenkins-build#!/bin/sh -e # libtool and yasm do not get along. # filter out any crap that libtool feeds us that yasm does not understand. new="" touch="" while [ -n "$*" ]; do case "$1" in -f ) shift new="-f $1" shift ;; -g* | -f* | -W* | -MD | -MP | -fPIC | -c | -D* | --param* | -O* | -I* | -m* | -pipe ) shift ;; -MT ) shift shift ;; -MF ) shift touch="$1" shift ;; * ) new="$new $1" shift ;; esac done echo $0: yasm $new yasm $new [ -n "$touch" ] && touch $touch trueceph-0.80.11/src/ceph-post-file.in0000775000175100017510000000756612623076744020654 0ustar jenkins-buildjenkins-build#!/bin/bash -e # If these files exist, assume we are a source install. if [[ -f ../share/known_hosts_drop.ceph.com && -f ../share/id_dsa_drop.ceph.com ]] then # running from source install known_hosts=../share/known_hosts_drop.ceph.com ssh_key=../share/id_dsa_drop.ceph.com else # running from a pkg install known_hosts=@datadir@/known_hosts_drop.ceph.com ssh_key=@datadir@/id_dsa_drop.ceph.com fi function usage() { echo "Usage: $0 [options] file1 [dir2 ...] Easily upload files or directories to ceph.com for analysis by Ceph developers. Each invocation uploads files or directories to a separate directory with a unique tag. That tag can be passed to a developer or referenced in a bug report (http://tracker.ceph.com/). Once the upload completes, the directory is marked non-readable and non-writeable to prevent access or modification by other users. WARNING: Basic measures are taken to make posted data be visible only to developers with access to ceph.com infrastructure. However, users should think twice and/or take appropriate precautions before posting potentially sensitive data (for example, logs or data directories that contain Ceph secrets). Options: -d|--description Description for this post [Default: none] -u|--user User identifier [Default: \`whoami\`@\`hostname -f\`] -r|--remote Remote to upload to [Default: postfile@drop.ceph.com] -k|--known_hosts known_hosts file [Default: /usr/share/ceph/known_hosts_drop.ceph.com] -i Ssh identity file [Default: /usr/share/ceph/id_dsa_drop.ceph.com] -h|--help Show this usage information " } if [ -z "$*" ]; then usage exit 1 fi description="" user="`whoami`@`hostname -f`" remote="postfile@drop.ceph.com" ARGS=$(getopt -n "ceph-post-file" -o 'd:u:hk:i:r:' -l "description:,user:,help,known-hosts:,remote:" -- "$@") eval set -- $ARGS while true; do echo "args: $@" case $1 in -d | --description) description="$2" shift shift ;; -u | --user) user="$2" shift shift ;; -h | --help) usage exit 0 ;; -k | --known-hosts) known_hosts="$2" shift shift ;; -i) ssh_key="$2" shift shift ;; -r | --remote) remote="$2" shift shift ;; --) shift break ;; esac done # this id should be shared id=`uuidgen` echo "$0: upload tag $id" # this is secret goop we add to the directory so that $id is not # enough to find the data using the shared user; only ceph developers # who have access to the server and can read the post directory can # find the uploaded data. nonce=`uuidgen` # stick the user info in the dir too dir="${id}_${user}_${nonce}" t1=$(mktemp) || exit t2=$(mktemp) || exit t3=$(mktemp) || exit t4=$(mktemp) || exit trap "rm -f -- '$t1' '$t2' '$t3' '$t4'" EXIT cat > $t1 < $t3 <> $t1 if [ -n "$description" ]; then echo "$0: description: $description" cat > $t2 <> $t1 fi while [ -n "$*" ]; do if [ -d "$1" ]; then echo $0: will upload directory $1 bn=`basename "$1"` cat >> $t1 <> $t1 < #include "snap_set_diff.h" #include "common/ceph_context.h" #include "include/rados/librados.hpp" #include "include/interval_set.h" #include "common/debug.h" #define dout_subsys ceph_subsys_rados /** * calculate intervals/extents that vary between two snapshots */ void calc_snap_set_diff(CephContext *cct, const librados::snap_set_t& snap_set, librados::snap_t start, librados::snap_t end, interval_set *diff, bool *end_exists) { ldout(cct, 10) << "calc_snap_set_diff start " << start << " end " << end << ", snap_set seq " << snap_set.seq << dendl; bool saw_start = false; uint64_t start_size = 0; diff->clear(); *end_exists = false; for (vector::const_iterator r = snap_set.clones.begin(); r != snap_set.clones.end(); ) { // make an interval, and hide the fact that the HEAD doesn't // include itself in the snaps list librados::snap_t a, b; if (r->cloneid == librados::SNAP_HEAD) { // head is valid starting from right after the last seen seq a = snap_set.seq + 1; b = librados::SNAP_HEAD; } else { a = r->snaps[0]; // note: b might be < r->cloneid if a snap has been trimmed. b = r->snaps[r->snaps.size()-1]; } ldout(cct, 20) << " clone " << r->cloneid << " snaps " << r->snaps << " -> [" << a << "," << b << "]" << " size " << r->size << " overlap to next " << r->overlap << dendl; if (b < start) { // this is before start ++r; continue; } if (!saw_start) { if (start < a) { ldout(cct, 20) << " start, after " << start << dendl; // this means the object didn't exist at start if (r->size) diff->insert(0, r->size); start_size = 0; } else { ldout(cct, 20) << " start" << dendl; start_size = r->size; } saw_start = true; } if (end < a) { ldout(cct, 20) << " past end " << end << ", end object does not exist" << dendl; *end_exists = false; if (start_size) { diff->clear(); diff->insert(0, start_size); } break; } if (end <= b) { ldout(cct, 20) << " end" << dendl; *end_exists = true; break; } // start with the max(this size, next size), and subtract off any // overlap const vector > *overlap = &r->overlap; interval_set diff_to_next; uint64_t max_size = r->size; ++r; if (r != snap_set.clones.end()) { if (r->size > max_size) max_size = r->size; } if (max_size) diff_to_next.insert(0, max_size); for (vector >::const_iterator p = overlap->begin(); p != overlap->end(); ++p) { diff_to_next.erase(p->first, p->second); } ldout(cct, 20) << " diff_to_next " << diff_to_next << dendl; diff->union_of(diff_to_next); ldout(cct, 20) << " diff now " << *diff << dendl; } } ceph-0.80.11/src/librados/RadosClient.cc0000664000175100017510000005135612623076744022013 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include "common/ceph_context.h" #include "common/config.h" #include "common/common_init.h" #include "common/errno.h" #include "include/buffer.h" #include "include/stringify.h" #include "messages/MWatchNotify.h" #include "messages/MLog.h" #include "msg/Messenger.h" // needed for static_cast #include "messages/PaxosServiceMessage.h" #include "messages/MPoolOpReply.h" #include "messages/MStatfsReply.h" #include "messages/MGetPoolStatsReply.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDMap.h" #include "messages/MCommandReply.h" #include "AioCompletionImpl.h" #include "IoCtxImpl.h" #include "PoolAsyncCompletionImpl.h" #include "RadosClient.h" #include "include/assert.h" #define dout_subsys ceph_subsys_rados #undef dout_prefix #define dout_prefix *_dout << "librados: " bool librados::RadosClient::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) { //ldout(cct, 0) << "RadosClient::ms_get_authorizer type=" << dest_type << dendl; /* monitor authorization is being handled on different layer */ if (dest_type == CEPH_ENTITY_TYPE_MON) return true; *authorizer = monclient.auth->build_authorizer(dest_type); return *authorizer != NULL; } librados::RadosClient::RadosClient(CephContext *cct_) : Dispatcher(cct_), cct(cct_->get()), conf(cct_->_conf), state(DISCONNECTED), monclient(cct_), messenger(NULL), instance_id(0), objecter(NULL), osdmap_epoch(0), pool_cache_epoch(0), lock("librados::RadosClient::lock"), pool_cache_rwl("librados::RadosClient::pool_cache_rwl"), timer(cct, lock), refcnt(1), log_last_version(0), log_cb(NULL), log_cb_arg(NULL), finisher(cct), max_watch_cookie(0) { } int64_t librados::RadosClient::lookup_pool(const char *name) { pool_cache_rwl.get_read(); if (pool_cache_epoch && pool_cache_epoch == osdmap_epoch) { map::iterator iter = pool_cache.find(name); if (iter != pool_cache.end()) { uint64_t val = iter->second; pool_cache_rwl.unlock(); return val; } } pool_cache_rwl.unlock(); lock.Lock(); int r = wait_for_osdmap(); if (r < 0) { lock.Unlock(); return r; } int64_t ret = osdmap.lookup_pg_pool_name(name); pool_cache_rwl.get_write(); lock.Unlock(); if (ret < 0) { pool_cache_rwl.unlock(); return -ENOENT; } if (pool_cache_epoch != osdmap_epoch) { pool_cache.clear(); pool_cache_epoch = osdmap_epoch; } pool_cache[name] = ret; pool_cache_rwl.unlock(); return ret; } bool librados::RadosClient::pool_requires_alignment(int64_t pool_id) { Mutex::Locker l(lock); return osdmap.have_pg_pool(pool_id) && osdmap.get_pg_pool(pool_id)->requires_aligned_append(); } uint64_t librados::RadosClient::pool_required_alignment(int64_t pool_id) { Mutex::Locker l(lock); return osdmap.have_pg_pool(pool_id) ? osdmap.get_pg_pool(pool_id)->required_alignment() : 0; } const char *librados::RadosClient::get_pool_name(int64_t pool_id) { Mutex::Locker l(lock); return osdmap.get_pool_name(pool_id); } int librados::RadosClient::pool_get_auid(uint64_t pool_id, unsigned long long *auid) { Mutex::Locker l(lock); int r = wait_for_osdmap(); if (r < 0) return r; const pg_pool_t *pg = osdmap.get_pg_pool(pool_id); if (!pg) return -ENOENT; *auid = pg->auid; return 0; } int librados::RadosClient::pool_get_name(uint64_t pool_id, std::string *s) { Mutex::Locker l(lock); int r = wait_for_osdmap(); if (r < 0) return r; const char *str = osdmap.get_pool_name(pool_id); if (!str) return -ENOENT; *s = str; return 0; } int librados::RadosClient::get_fsid(std::string *s) { if (!s) return -EINVAL; Mutex::Locker l(lock); ostringstream oss; oss << monclient.get_fsid(); *s = oss.str(); return 0; } int librados::RadosClient::ping_monitor(const string mon_id, string *result) { int err = 0; /* If we haven't yet connected, we have no way of telling whether we * already built monc's initial monmap. IF we are in CONNECTED state, * then it is safe to assume that we went through connect(), which does * build a monmap. */ if (state != CONNECTED) { ldout(cct, 10) << __func__ << " build monmap" << dendl; err = monclient.build_initial_monmap(); } if (err < 0) { return err; } err = monclient.ping_monitor(mon_id, result); return err; } int librados::RadosClient::connect() { common_init_finish(cct); int err; // already connected? if (state == CONNECTING) return -EINPROGRESS; if (state == CONNECTED) return -EISCONN; state = CONNECTING; // get monmap err = monclient.build_initial_monmap(); if (err < 0) goto out; err = -ENOMEM; messenger = Messenger::create_client_messenger(cct, "radosclient"); if (!messenger) goto out; // require OSDREPLYMUX feature. this means we will fail to talk to // old servers. this is necessary because otherwise we won't know // how to decompose the reply data into its consituent pieces. messenger->set_default_policy(Messenger::Policy::lossy_client(0, CEPH_FEATURE_OSDREPLYMUX)); ldout(cct, 1) << "starting msgr at " << messenger->get_myaddr() << dendl; ldout(cct, 1) << "starting objecter" << dendl; err = -ENOMEM; objecter = new (std::nothrow) Objecter(cct, messenger, &monclient, &osdmap, lock, timer, cct->_conf->rados_mon_op_timeout, cct->_conf->rados_osd_op_timeout); if (!objecter) goto out; objecter->set_balanced_budget(); monclient.set_messenger(messenger); messenger->add_dispatcher_head(this); messenger->start(); ldout(cct, 1) << "setting wanted keys" << dendl; monclient.set_want_keys(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD); ldout(cct, 1) << "calling monclient init" << dendl; err = monclient.init(); if (err) { ldout(cct, 0) << conf->name << " initialization error " << cpp_strerror(-err) << dendl; shutdown(); goto out; } err = monclient.authenticate(conf->client_mount_timeout); if (err) { ldout(cct, 0) << conf->name << " authentication error " << cpp_strerror(-err) << dendl; shutdown(); goto out; } messenger->set_myname(entity_name_t::CLIENT(monclient.get_global_id())); objecter->init_unlocked(); lock.Lock(); timer.init(); objecter->set_client_incarnation(0); objecter->init_locked(); monclient.renew_subs(); finisher.start(); state = CONNECTED; instance_id = monclient.get_global_id(); lock.Unlock(); ldout(cct, 1) << "init done" << dendl; err = 0; out: if (err) { state = DISCONNECTED; if (objecter) { delete objecter; objecter = NULL; } if (messenger) { delete messenger; messenger = NULL; } } return err; } void librados::RadosClient::shutdown() { lock.Lock(); if (state == DISCONNECTED) { lock.Unlock(); return; } if (state == CONNECTED) { finisher.stop(); } bool need_objecter = false; if (objecter && state == CONNECTED) { need_objecter = true; objecter->shutdown_locked(); } state = DISCONNECTED; instance_id = 0; timer.shutdown(); // will drop+retake lock lock.Unlock(); monclient.shutdown(); if (need_objecter) objecter->shutdown_unlocked(); if (messenger) { messenger->shutdown(); messenger->wait(); } ldout(cct, 1) << "shutdown" << dendl; } uint64_t librados::RadosClient::get_instance_id() { return instance_id; } librados::RadosClient::~RadosClient() { if (messenger) delete messenger; if (objecter) delete objecter; cct->put(); cct = NULL; } int librados::RadosClient::create_ioctx(const char *name, IoCtxImpl **io) { int64_t poolid = lookup_pool(name); if (poolid < 0) return (int)poolid; *io = new librados::IoCtxImpl(this, objecter, &lock, poolid, name, CEPH_NOSNAP); return 0; } bool librados::RadosClient::ms_dispatch(Message *m) { Mutex::Locker l(lock); bool ret; if (state == DISCONNECTED) { ldout(cct, 10) << "disconnected, discarding " << *m << dendl; m->put(); ret = true; } else { ret = _dispatch(m); } return ret; } void librados::RadosClient::ms_handle_connect(Connection *con) { Mutex::Locker l(lock); objecter->ms_handle_connect(con); } bool librados::RadosClient::ms_handle_reset(Connection *con) { Mutex::Locker l(lock); objecter->ms_handle_reset(con); return false; } void librados::RadosClient::ms_handle_remote_reset(Connection *con) { Mutex::Locker l(lock); objecter->ms_handle_remote_reset(con); } bool librados::RadosClient::_dispatch(Message *m) { switch (m->get_type()) { // OSD case CEPH_MSG_OSD_OPREPLY: objecter->handle_osd_op_reply(static_cast(m)); break; case CEPH_MSG_OSD_MAP: objecter->handle_osd_map(static_cast(m)); pool_cache_rwl.get_write(); osdmap_epoch = osdmap.get_epoch(); pool_cache_rwl.unlock(); cond.Signal(); break; case MSG_GETPOOLSTATSREPLY: objecter->handle_get_pool_stats_reply(static_cast(m)); break; case CEPH_MSG_MDS_MAP: break; case CEPH_MSG_STATFS_REPLY: objecter->handle_fs_stats_reply(static_cast(m)); break; case CEPH_MSG_POOLOP_REPLY: objecter->handle_pool_op_reply(static_cast(m)); break; case MSG_COMMAND_REPLY: objecter->handle_command_reply(static_cast(m)); break; case CEPH_MSG_WATCH_NOTIFY: watch_notify(static_cast(m)); break; case MSG_LOG: handle_log(static_cast(m)); break; default: return false; } return true; } int librados::RadosClient::wait_for_osdmap() { assert(lock.is_locked()); if (state != CONNECTED) { return -ENOTCONN; } utime_t timeout; if (cct->_conf->rados_mon_op_timeout > 0) timeout.set_from_double(cct->_conf->rados_mon_op_timeout); if (osdmap.get_epoch() == 0) { ldout(cct, 10) << __func__ << " waiting" << dendl; utime_t start = ceph_clock_now(cct); while (osdmap.get_epoch() == 0) { cond.WaitInterval(cct, lock, timeout); utime_t elapsed = ceph_clock_now(cct) - start; if (!timeout.is_zero() && elapsed > timeout) break; } ldout(cct, 10) << __func__ << " done waiting" << dendl; if (osdmap.get_epoch() == 0) { lderr(cct) << "timed out waiting for first osdmap from monitors" << dendl; return -ETIMEDOUT; } } return 0; } int librados::RadosClient::wait_for_latest_osdmap() { Mutex mylock("RadosClient::wait_for_latest_osdmap"); Cond cond; bool done; lock.Lock(); objecter->wait_for_latest_osdmap(new C_SafeCond(&mylock, &cond, &done)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return 0; } int librados::RadosClient::pool_list(std::list& v) { Mutex::Locker l(lock); int r = wait_for_osdmap(); if (r < 0) return r; for (map::const_iterator p = osdmap.get_pools().begin(); p != osdmap.get_pools().end(); ++p) v.push_back(osdmap.get_pool_name(p->first)); return 0; } int librados::RadosClient::get_pool_stats(std::list& pools, map& result) { Mutex mylock("RadosClient::get_pool_stats::mylock"); Cond cond; bool done; int ret = 0; lock.Lock(); objecter->get_pool_stats(pools, &result, new C_SafeCond(&mylock, &cond, &done, &ret)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return ret; } int librados::RadosClient::get_fs_stats(ceph_statfs& stats) { Mutex mylock ("RadosClient::get_fs_stats::mylock"); Cond cond; bool done; int ret = 0; lock.Lock(); objecter->get_fs_stats(stats, new C_SafeCond(&mylock, &cond, &done, &ret)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return ret; } void librados::RadosClient::get() { Mutex::Locker l(lock); assert(refcnt > 0); refcnt++; } bool librados::RadosClient::put() { Mutex::Locker l(lock); assert(refcnt > 0); refcnt--; return (refcnt == 0); } int librados::RadosClient::pool_create(string& name, unsigned long long auid, __u8 crush_rule) { int reply; Mutex mylock ("RadosClient::pool_create::mylock"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &reply); lock.Lock(); reply = objecter->create_pool(name, onfinish, auid, crush_rule); lock.Unlock(); if (reply < 0) { delete onfinish; } else { mylock.Lock(); while(!done) cond.Wait(mylock); mylock.Unlock(); } return reply; } int librados::RadosClient::pool_create_async(string& name, PoolAsyncCompletionImpl *c, unsigned long long auid, __u8 crush_rule) { Mutex::Locker l(lock); Context *onfinish = new C_PoolAsync_Safe(c); int r = objecter->create_pool(name, onfinish, auid, crush_rule); if (r < 0) { delete onfinish; } return r; } int librados::RadosClient::pool_delete(const char *name) { lock.Lock(); int r = wait_for_osdmap(); if (r < 0) { lock.Unlock(); return r; } int tmp_pool_id = osdmap.lookup_pg_pool_name(name); if (tmp_pool_id < 0) { lock.Unlock(); return -ENOENT; } Mutex mylock("RadosClient::pool_delete::mylock"); Cond cond; bool done; int ret; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &ret); ret = objecter->delete_pool(tmp_pool_id, onfinish); lock.Unlock(); if (ret < 0) { delete onfinish; } else { mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); } return ret; } int librados::RadosClient::pool_delete_async(const char *name, PoolAsyncCompletionImpl *c) { Mutex::Locker l(lock); int r = wait_for_osdmap(); if (r < 0) return r; int tmp_pool_id = osdmap.lookup_pg_pool_name(name); if (tmp_pool_id < 0) return -ENOENT; Context *onfinish = new C_PoolAsync_Safe(c); r = objecter->delete_pool(tmp_pool_id, onfinish); if (r < 0) { delete onfinish; } return r; } void librados::RadosClient::register_watcher(WatchContext *wc, uint64_t *cookie) { assert(lock.is_locked()); wc->cookie = *cookie = ++max_watch_cookie; watchers[wc->cookie] = wc; } void librados::RadosClient::unregister_watcher(uint64_t cookie) { assert(lock.is_locked()); map::iterator iter = watchers.find(cookie); if (iter != watchers.end()) { WatchContext *ctx = iter->second; if (ctx->linger_id) objecter->unregister_linger(ctx->linger_id); watchers.erase(iter); lock.Unlock(); ldout(cct, 10) << "unregister_watcher, dropping reference, waiting ctx=" << (void *)ctx << dendl; ctx->put_wait(); ldout(cct, 10) << "unregister_watcher, done ctx=" << (void *)ctx << dendl; lock.Lock(); } } void librados::RadosClient::blacklist_self(bool set) { Mutex::Locker l(lock); objecter->blacklist_self(set); } class C_WatchNotify : public Context { librados::WatchContext *ctx; Mutex *client_lock; uint8_t opcode; uint64_t ver; uint64_t notify_id; bufferlist bl; public: C_WatchNotify(librados::WatchContext *_ctx, Mutex *_client_lock, uint8_t _o, uint64_t _v, uint64_t _n, bufferlist& _bl) : ctx(_ctx), client_lock(_client_lock), opcode(_o), ver(_v), notify_id(_n), bl(_bl) {} void finish(int r) { ctx->notify(client_lock, opcode, ver, notify_id, bl); ctx->put(); } }; void librados::RadosClient::watch_notify(MWatchNotify *m) { assert(lock.is_locked()); map::iterator iter = watchers.find(m->cookie); if (iter != watchers.end()) { WatchContext *wc = iter->second; assert(wc); wc->get(); finisher.queue(new C_WatchNotify(wc, &lock, m->opcode, m->ver, m->notify_id, m->bl)); } m->put(); } int librados::RadosClient::mon_command(const vector& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs) { Mutex mylock("RadosClient::mon_command::mylock"); Cond cond; bool done; int rval; lock.Lock(); monclient.start_mon_command(cmd, inbl, outbl, outs, new C_SafeCond(&mylock, &cond, &done, &rval)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return rval; } int librados::RadosClient::mon_command(int rank, const vector& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs) { Mutex mylock("RadosClient::mon_command::mylock"); Cond cond; bool done; int rval; lock.Lock(); monclient.start_mon_command(rank, cmd, inbl, outbl, outs, new C_SafeCond(&mylock, &cond, &done, &rval)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return rval; } int librados::RadosClient::mon_command(string name, const vector& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs) { Mutex mylock("RadosClient::mon_command::mylock"); Cond cond; bool done; int rval; lock.Lock(); monclient.start_mon_command(name, cmd, inbl, outbl, outs, new C_SafeCond(&mylock, &cond, &done, &rval)); lock.Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return rval; } int librados::RadosClient::osd_command(int osd, vector& cmd, const bufferlist& inbl, bufferlist *poutbl, string *prs) { Mutex mylock("RadosClient::osd_command::mylock"); Cond cond; bool done; int ret; ceph_tid_t tid; if (osd < 0) return -EINVAL; lock.Lock(); // XXX do anything with tid? int r = objecter->osd_command(osd, cmd, inbl, &tid, poutbl, prs, new C_SafeCond(&mylock, &cond, &done, &ret)); lock.Unlock(); if (r != 0) return r; mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return ret; } int librados::RadosClient::pg_command(pg_t pgid, vector& cmd, const bufferlist& inbl, bufferlist *poutbl, string *prs) { Mutex mylock("RadosClient::pg_command::mylock"); Cond cond; bool done; int ret; ceph_tid_t tid; lock.Lock(); int r = objecter->pg_command(pgid, cmd, inbl, &tid, poutbl, prs, new C_SafeCond(&mylock, &cond, &done, &ret)); lock.Unlock(); if (r != 0) return r; mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return ret; } int librados::RadosClient::monitor_log(const string& level, rados_log_callback_t cb, void *arg) { if (cb == NULL) { // stop watch ldout(cct, 10) << __func__ << " removing cb " << (void*)log_cb << dendl; monclient.sub_unwant(log_watch); log_watch.clear(); log_cb = NULL; log_cb_arg = NULL; return 0; } string watch_level; if (level == "debug") { watch_level = "log-debug"; } else if (level == "info") { watch_level = "log-info"; } else if (level == "warn" || level == "warning") { watch_level = "log-warn"; } else if (level == "err" || level == "error") { watch_level = "log-error"; } else if (level == "sec") { watch_level = "log-sec"; } else { ldout(cct, 10) << __func__ << " invalid level " << level << dendl; return -EINVAL; } if (log_cb) monclient.sub_unwant(log_watch); // (re)start watch ldout(cct, 10) << __func__ << " add cb " << (void*)cb << " level " << level << dendl; monclient.sub_want(watch_level, 0, 0); monclient.renew_subs(); log_cb = cb; log_cb_arg = arg; log_watch = watch_level; return 0; } void librados::RadosClient::handle_log(MLog *m) { ldout(cct, 10) << __func__ << " version " << m->version << dendl; if (log_last_version < m->version) { log_last_version = m->version; if (log_cb) { for (std::deque::iterator it = m->entries.begin(); it != m->entries.end(); ++it) { LogEntry e = *it; ostringstream ss; ss << e.stamp << " " << e.who.name << " " << e.type << " " << e.msg; string line = ss.str(); string who = stringify(e.who); string level = stringify(e.type); struct timespec stamp; e.stamp.to_timespec(&stamp); ldout(cct, 20) << __func__ << " delivering " << ss.str() << dendl; log_cb(log_cb_arg, line.c_str(), who.c_str(), stamp.tv_sec, stamp.tv_nsec, e.seq, level.c_str(), e.msg.c_str()); } /* this was present in the old cephtool code, but does not appear to be necessary. :/ version_t v = log_last_version + 1; ldout(cct, 10) << __func__ << " wanting " << log_watch << " ver " << v << dendl; monclient.sub_want(log_watch, v, 0); */ } } m->put(); } ceph-0.80.11/src/librados/IoCtxImpl.cc0000664000175100017510000007755012623076744021460 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "IoCtxImpl.h" #include "librados/AioCompletionImpl.h" #include "librados/PoolAsyncCompletionImpl.h" #include "librados/RadosClient.h" #include "include/assert.h" #define dout_subsys ceph_subsys_rados #undef dout_prefix #define dout_prefix *_dout << "librados: " librados::IoCtxImpl::IoCtxImpl() : ref_cnt(0), client(NULL), poolid(0), assert_ver(0), last_objver(0), notify_timeout(30), aio_write_list_lock("librados::IoCtxImpl::aio_write_list_lock"), aio_write_seq(0), lock(NULL), objecter(NULL) { } librados::IoCtxImpl::IoCtxImpl(RadosClient *c, Objecter *objecter, Mutex *client_lock, int poolid, const char *pool_name, snapid_t s) : ref_cnt(0), client(c), poolid(poolid), pool_name(pool_name), snap_seq(s), assert_ver(0), notify_timeout(c->cct->_conf->client_notify_timeout), oloc(poolid), aio_write_list_lock("librados::IoCtxImpl::aio_write_list_lock"), aio_write_seq(0), lock(client_lock), objecter(objecter) { } void librados::IoCtxImpl::set_snap_read(snapid_t s) { if (!s) s = CEPH_NOSNAP; ldout(client->cct, 10) << "set snap read " << snap_seq << " -> " << s << dendl; snap_seq = s; } int librados::IoCtxImpl::set_snap_write_context(snapid_t seq, vector& snaps) { ::SnapContext n; ldout(client->cct, 10) << "set snap write context: seq = " << seq << " and snaps = " << snaps << dendl; n.seq = seq; n.snaps = snaps; if (!n.is_valid()) return -EINVAL; snapc = n; return 0; } uint32_t librados::IoCtxImpl::get_object_hash_position(const std::string& oid) { Mutex::Locker l(*lock); return objecter->get_object_hash_position(poolid, oid, oloc.nspace); } uint32_t librados::IoCtxImpl::get_object_pg_hash_position(const std::string& oid) { Mutex::Locker l(*lock); return objecter->get_object_pg_hash_position(poolid, oid, oloc.nspace); } void librados::IoCtxImpl::queue_aio_write(AioCompletionImpl *c) { get(); aio_write_list_lock.Lock(); assert(c->io == this); c->aio_write_seq = ++aio_write_seq; ldout(client->cct, 20) << "queue_aio_write " << this << " completion " << c << " write_seq " << aio_write_seq << dendl; aio_write_list.push_back(&c->aio_write_list_item); aio_write_list_lock.Unlock(); } void librados::IoCtxImpl::complete_aio_write(AioCompletionImpl *c) { ldout(client->cct, 20) << "complete_aio_write " << c << dendl; aio_write_list_lock.Lock(); assert(c->io == this); c->aio_write_list_item.remove_myself(); map >::iterator waiters = aio_write_waiters.begin(); while (waiters != aio_write_waiters.end()) { if (!aio_write_list.empty() && aio_write_list.front()->aio_write_seq <= waiters->first) { ldout(client->cct, 20) << " next outstanding write is " << aio_write_list.front()->aio_write_seq << " <= waiter " << waiters->first << ", stopping" << dendl; break; } ldout(client->cct, 20) << " waking waiters on seq " << waiters->first << dendl; for (std::list::iterator it = waiters->second.begin(); it != waiters->second.end(); ++it) { client->finisher.queue(new C_AioCompleteAndSafe(*it)); (*it)->put(); } aio_write_waiters.erase(waiters++); } aio_write_cond.Signal(); aio_write_list_lock.Unlock(); put(); } void librados::IoCtxImpl::flush_aio_writes_async(AioCompletionImpl *c) { ldout(client->cct, 20) << "flush_aio_writes_async " << this << " completion " << c << dendl; Mutex::Locker l(aio_write_list_lock); ceph_tid_t seq = aio_write_seq; if (aio_write_list.empty()) { ldout(client->cct, 20) << "flush_aio_writes_async no writes. (tid " << seq << ")" << dendl; client->finisher.queue(new C_AioCompleteAndSafe(c)); } else { ldout(client->cct, 20) << "flush_aio_writes_async " << aio_write_list.size() << " writes in flight; waiting on tid " << seq << dendl; c->get(); aio_write_waiters[seq].push_back(c); } } void librados::IoCtxImpl::flush_aio_writes() { ldout(client->cct, 20) << "flush_aio_writes" << dendl; aio_write_list_lock.Lock(); ceph_tid_t seq = aio_write_seq; while (!aio_write_list.empty() && aio_write_list.front()->aio_write_seq <= seq) aio_write_cond.Wait(aio_write_list_lock); aio_write_list_lock.Unlock(); } // SNAPS int librados::IoCtxImpl::snap_create(const char *snapName) { int reply; string sName(snapName); Mutex mylock ("IoCtxImpl::snap_create::mylock"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &reply); lock->Lock(); reply = objecter->create_pool_snap(poolid, sName, onfinish); lock->Unlock(); if (reply < 0) { delete onfinish; } else { mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); } return reply; } int librados::IoCtxImpl::selfmanaged_snap_create(uint64_t *psnapid) { int reply; Mutex mylock("IoCtxImpl::selfmanaged_snap_create::mylock"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &reply); snapid_t snapid; lock->Lock(); reply = objecter->allocate_selfmanaged_snap(poolid, &snapid, onfinish); lock->Unlock(); if (reply < 0) { delete onfinish; } else { mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); if (reply == 0) *psnapid = snapid; } return reply; } int librados::IoCtxImpl::snap_remove(const char *snapName) { int reply; string sName(snapName); Mutex mylock ("IoCtxImpl::snap_remove::mylock"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &reply); lock->Lock(); reply = objecter->delete_pool_snap(poolid, sName, onfinish); lock->Unlock(); if (reply < 0) { delete onfinish; } else { mylock.Lock(); while(!done) cond.Wait(mylock); mylock.Unlock(); } return reply; } int librados::IoCtxImpl::selfmanaged_snap_rollback_object(const object_t& oid, ::SnapContext& snapc, uint64_t snapid) { utime_t ut = ceph_clock_now(client->cct); int reply; Mutex mylock("IoCtxImpl::snap_rollback::mylock"); Cond cond; bool done; Context *onack = new C_SafeCond(&mylock, &cond, &done, &reply); ::ObjectOperation op; prepare_assert_ops(&op); op.rollback(snapid); lock->Lock(); objecter->mutate(oid, oloc, op, snapc, ut, 0, onack, NULL, NULL); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return reply; } int librados::IoCtxImpl::rollback(const object_t& oid, const char *snapName) { string sName(snapName); lock->Lock(); snapid_t snap; const map& pools = objecter->osdmap->get_pools(); const pg_pool_t& pg_pool = pools.find(poolid)->second; map::const_iterator p; for (p = pg_pool.snaps.begin(); p != pg_pool.snaps.end(); ++p) { if (p->second.name == snapName) { snap = p->first; break; } } if (p == pg_pool.snaps.end()) { lock->Unlock(); return -ENOENT; } lock->Unlock(); return selfmanaged_snap_rollback_object(oid, snapc, snap); } int librados::IoCtxImpl::selfmanaged_snap_remove(uint64_t snapid) { int reply; Mutex mylock("IoCtxImpl::selfmanaged_snap_remove::mylock"); Cond cond; bool done; lock->Lock(); objecter->delete_selfmanaged_snap(poolid, snapid_t(snapid), new C_SafeCond(&mylock, &cond, &done, &reply)); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return (int)reply; } int librados::IoCtxImpl::pool_change_auid(unsigned long long auid) { int reply; Mutex mylock("IoCtxImpl::pool_change_auid::mylock"); Cond cond; bool done; lock->Lock(); objecter->change_pool_auid(poolid, new C_SafeCond(&mylock, &cond, &done, &reply), auid); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); return reply; } int librados::IoCtxImpl::pool_change_auid_async(unsigned long long auid, PoolAsyncCompletionImpl *c) { Mutex::Locker l(*lock); objecter->change_pool_auid(poolid, new C_PoolAsync_Safe(c), auid); return 0; } int librados::IoCtxImpl::snap_list(vector *snaps) { Mutex::Locker l(*lock); const pg_pool_t *pi = objecter->osdmap->get_pg_pool(poolid); for (map::const_iterator p = pi->snaps.begin(); p != pi->snaps.end(); ++p) snaps->push_back(p->first); return 0; } int librados::IoCtxImpl::snap_lookup(const char *name, uint64_t *snapid) { Mutex::Locker l(*lock); const pg_pool_t *pi = objecter->osdmap->get_pg_pool(poolid); for (map::const_iterator p = pi->snaps.begin(); p != pi->snaps.end(); ++p) { if (p->second.name == name) { *snapid = p->first; return 0; } } return -ENOENT; } int librados::IoCtxImpl::snap_get_name(uint64_t snapid, std::string *s) { Mutex::Locker l(*lock); const pg_pool_t *pi = objecter->osdmap->get_pg_pool(poolid); map::const_iterator p = pi->snaps.find(snapid); if (p == pi->snaps.end()) return -ENOENT; *s = p->second.name.c_str(); return 0; } int librados::IoCtxImpl::snap_get_stamp(uint64_t snapid, time_t *t) { Mutex::Locker l(*lock); const pg_pool_t *pi = objecter->osdmap->get_pg_pool(poolid); map::const_iterator p = pi->snaps.find(snapid); if (p == pi->snaps.end()) return -ENOENT; *t = p->second.stamp.sec(); return 0; } // IO int librados::IoCtxImpl::list(Objecter::ListContext *context, int max_entries) { Cond cond; bool done; int r = 0; object_t oid; Mutex mylock("IoCtxImpl::list::mylock"); if (context->at_end()) return 0; context->max_entries = max_entries; context->nspace = oloc.nspace; lock->Lock(); objecter->list_objects(context, new C_SafeCond(&mylock, &cond, &done, &r)); lock->Unlock(); mylock.Lock(); while(!done) cond.Wait(mylock); mylock.Unlock(); return r; } uint32_t librados::IoCtxImpl::list_seek(Objecter::ListContext *context, uint32_t pos) { Mutex::Locker l(*lock); context->list.clear(); return objecter->list_objects_seek(context, pos); } int librados::IoCtxImpl::create(const object_t& oid, bool exclusive) { ::ObjectOperation op; prepare_assert_ops(&op); op.create(exclusive); return operate(oid, &op, NULL); } int librados::IoCtxImpl::create(const object_t& oid, bool exclusive, const std::string& category) { ::ObjectOperation op; prepare_assert_ops(&op); op.create(exclusive, category); return operate(oid, &op, NULL); } /* * add any version assert operations that are appropriate given the * stat in the IoCtx, either the target version assert or any src * object asserts. these affect a single ioctx operation, so clear * the ioctx state when we're doing. * * return a pointer to the ObjectOperation if we added any events; * this is convenient for passing the extra_ops argument into Objecter * methods. */ ::ObjectOperation *librados::IoCtxImpl::prepare_assert_ops(::ObjectOperation *op) { ::ObjectOperation *pop = NULL; if (assert_ver) { op->assert_version(assert_ver); assert_ver = 0; pop = op; } while (!assert_src_version.empty()) { map::iterator p = assert_src_version.begin(); op->assert_src_version(p->first, CEPH_NOSNAP, p->second); assert_src_version.erase(p); pop = op; } return pop; } int librados::IoCtxImpl::write(const object_t& oid, bufferlist& bl, size_t len, uint64_t off) { ::ObjectOperation op; prepare_assert_ops(&op); bufferlist mybl; mybl.substr_of(bl, 0, len); op.write(off, mybl); return operate(oid, &op, NULL); } int librados::IoCtxImpl::append(const object_t& oid, bufferlist& bl, size_t len) { ::ObjectOperation op; prepare_assert_ops(&op); bufferlist mybl; mybl.substr_of(bl, 0, len); op.append(mybl); return operate(oid, &op, NULL); } int librados::IoCtxImpl::write_full(const object_t& oid, bufferlist& bl) { ::ObjectOperation op; prepare_assert_ops(&op); op.write_full(bl); return operate(oid, &op, NULL); } int librados::IoCtxImpl::clone_range(const object_t& dst_oid, uint64_t dst_offset, const object_t& src_oid, uint64_t src_offset, uint64_t len) { ::ObjectOperation wr; prepare_assert_ops(&wr); wr.clone_range(src_oid, src_offset, len, dst_offset); return operate(dst_oid, &wr, NULL); } int librados::IoCtxImpl::operate(const object_t& oid, ::ObjectOperation *o, time_t *pmtime, int flags) { utime_t ut; if (pmtime) { ut = utime_t(*pmtime, 0); } else { ut = ceph_clock_now(client->cct); } /* can't write to a snapshot */ if (snap_seq != CEPH_NOSNAP) return -EROFS; if (!o->size()) return 0; Mutex mylock("IoCtxImpl::operate::mylock"); Cond cond; bool done; int r; version_t ver; Context *oncommit = new C_SafeCond(&mylock, &cond, &done, &r); int op = o->ops[0].op.op; ldout(client->cct, 10) << ceph_osd_op_name(op) << " oid=" << oid << " nspace=" << oloc.nspace << dendl; Objecter::Op *objecter_op = objecter->prepare_mutate_op(oid, oloc, *o, snapc, ut, flags, NULL, oncommit, &ver); lock->Lock(); objecter->op_submit(objecter_op); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); ldout(client->cct, 10) << "Objecter returned from " << ceph_osd_op_name(op) << " r=" << r << dendl; set_sync_op_version(ver); return r; } int librados::IoCtxImpl::operate_read(const object_t& oid, ::ObjectOperation *o, bufferlist *pbl, int flags) { if (!o->size()) return 0; Mutex mylock("IoCtxImpl::operate_read::mylock"); Cond cond; bool done; int r; version_t ver; Context *onack = new C_SafeCond(&mylock, &cond, &done, &r); int op = o->ops[0].op.op; ldout(client->cct, 10) << ceph_osd_op_name(op) << " oid=" << oid << " nspace=" << oloc.nspace << dendl; Objecter::Op *objecter_op = objecter->prepare_read_op(oid, oloc, *o, snap_seq, pbl, flags, onack, &ver); lock->Lock(); objecter->op_submit(objecter_op); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); ldout(client->cct, 10) << "Objecter returned from " << ceph_osd_op_name(op) << " r=" << r << dendl; set_sync_op_version(ver); return r; } int librados::IoCtxImpl::aio_operate_read(const object_t &oid, ::ObjectOperation *o, AioCompletionImpl *c, int flags, bufferlist *pbl) { Context *onack = new C_aio_Ack(c); c->is_read = true; c->io = this; Objecter::Op *objecter_op = objecter->prepare_read_op(oid, oloc, *o, snap_seq, pbl, flags, onack, &c->objver); Mutex::Locker l(*lock); objecter->op_submit(objecter_op); return 0; } int librados::IoCtxImpl::aio_operate(const object_t& oid, ::ObjectOperation *o, AioCompletionImpl *c, const SnapContext& snap_context, int flags) { utime_t ut = ceph_clock_now(client->cct); /* can't write to a snapshot */ if (snap_seq != CEPH_NOSNAP) return -EROFS; Context *onack = new C_aio_Ack(c); Context *oncommit = new C_aio_Safe(c); c->io = this; queue_aio_write(c); Mutex::Locker l(*lock); objecter->mutate(oid, oloc, *o, snap_context, ut, flags, onack, oncommit, &c->objver); return 0; } int librados::IoCtxImpl::aio_read(const object_t oid, AioCompletionImpl *c, bufferlist *pbl, size_t len, uint64_t off, uint64_t snapid) { if (len > (size_t) INT_MAX) return -EDOM; Context *onack = new C_aio_Ack(c); c->is_read = true; c->io = this; c->blp = pbl; Mutex::Locker l(*lock); objecter->read(oid, oloc, off, len, snapid, pbl, 0, onack, &c->objver); return 0; } int librados::IoCtxImpl::aio_read(const object_t oid, AioCompletionImpl *c, char *buf, size_t len, uint64_t off, uint64_t snapid) { if (len > (size_t) INT_MAX) return -EDOM; Context *onack = new C_aio_Ack(c); c->is_read = true; c->io = this; c->bl.clear(); c->bl.push_back(buffer::create_static(len, buf)); c->blp = &c->bl; Mutex::Locker l(*lock); objecter->read(oid, oloc, off, len, snapid, &c->bl, 0, onack, &c->objver); return 0; } class C_ObjectOperation : public Context { public: ::ObjectOperation m_ops; C_ObjectOperation(Context *c) : m_ctx(c) {} virtual void finish(int r) { m_ctx->complete(r); } private: Context *m_ctx; }; int librados::IoCtxImpl::aio_sparse_read(const object_t oid, AioCompletionImpl *c, std::map *m, bufferlist *data_bl, size_t len, uint64_t off, uint64_t snapid) { if (len > (size_t) INT_MAX) return -EDOM; Context *nested = new C_aio_Ack(c); C_ObjectOperation *onack = new C_ObjectOperation(nested); c->is_read = true; c->io = this; onack->m_ops.sparse_read(off, len, m, data_bl, NULL); Mutex::Locker l(*lock); objecter->read(oid, oloc, onack->m_ops, snap_seq, NULL, 0, onack, &c->objver); return 0; } int librados::IoCtxImpl::aio_write(const object_t &oid, AioCompletionImpl *c, const bufferlist& bl, size_t len, uint64_t off) { utime_t ut = ceph_clock_now(client->cct); ldout(client->cct, 20) << "aio_write " << oid << " " << off << "~" << len << " snapc=" << snapc << " snap_seq=" << snap_seq << dendl; /* can't write to a snapshot */ if (snap_seq != CEPH_NOSNAP) return -EROFS; c->io = this; queue_aio_write(c); Context *onack = new C_aio_Ack(c); Context *onsafe = new C_aio_Safe(c); Mutex::Locker l(*lock); objecter->write(oid, oloc, off, len, snapc, bl, ut, 0, onack, onsafe, &c->objver); return 0; } int librados::IoCtxImpl::aio_append(const object_t &oid, AioCompletionImpl *c, const bufferlist& bl, size_t len) { utime_t ut = ceph_clock_now(client->cct); /* can't write to a snapshot */ if (snap_seq != CEPH_NOSNAP) return -EROFS; c->io = this; queue_aio_write(c); Context *onack = new C_aio_Ack(c); Context *onsafe = new C_aio_Safe(c); Mutex::Locker l(*lock); objecter->append(oid, oloc, len, snapc, bl, ut, 0, onack, onsafe, &c->objver); return 0; } int librados::IoCtxImpl::aio_write_full(const object_t &oid, AioCompletionImpl *c, const bufferlist& bl) { utime_t ut = ceph_clock_now(client->cct); /* can't write to a snapshot */ if (snap_seq != CEPH_NOSNAP) return -EROFS; c->io = this; queue_aio_write(c); Context *onack = new C_aio_Ack(c); Context *onsafe = new C_aio_Safe(c); Mutex::Locker l(*lock); objecter->write_full(oid, oloc, snapc, bl, ut, 0, onack, onsafe, &c->objver); return 0; } int librados::IoCtxImpl::aio_remove(const object_t &oid, AioCompletionImpl *c) { utime_t ut = ceph_clock_now(client->cct); /* can't write to a snapshot */ if (snap_seq != CEPH_NOSNAP) return -EROFS; c->io = this; queue_aio_write(c); Context *onack = new C_aio_Ack(c); Context *onsafe = new C_aio_Safe(c); Mutex::Locker l(*lock); objecter->remove(oid, oloc, snapc, ut, 0, onack, onsafe, &c->objver); return 0; } int librados::IoCtxImpl::aio_stat(const object_t& oid, AioCompletionImpl *c, uint64_t *psize, time_t *pmtime) { c->io = this; C_aio_stat_Ack *onack = new C_aio_stat_Ack(c, pmtime); Mutex::Locker l(*lock); objecter->stat(oid, oloc, snap_seq, psize, &onack->mtime, 0, onack, &c->objver); return 0; } int librados::IoCtxImpl::hit_set_list(uint32_t hash, AioCompletionImpl *c, std::list< std::pair > *pls) { Context *onack = new C_aio_Ack(c); c->is_read = true; c->io = this; Mutex::Locker l(*lock); ::ObjectOperation rd; rd.hit_set_ls(pls, NULL); object_locator_t oloc(poolid); objecter->pg_read(hash, oloc, rd, NULL, 0, onack, NULL, NULL); return 0; } int librados::IoCtxImpl::hit_set_get(uint32_t hash, AioCompletionImpl *c, time_t stamp, bufferlist *pbl) { Context *onack = new C_aio_Ack(c); c->is_read = true; c->io = this; Mutex::Locker l(*lock); ::ObjectOperation rd; rd.hit_set_get(utime_t(stamp, 0), pbl, 0); object_locator_t oloc(poolid); objecter->pg_read(hash, oloc, rd, NULL, 0, onack, NULL, NULL); return 0; } int librados::IoCtxImpl::remove(const object_t& oid) { ::ObjectOperation op; prepare_assert_ops(&op); op.remove(); return operate(oid, &op, NULL); } int librados::IoCtxImpl::trunc(const object_t& oid, uint64_t size) { ::ObjectOperation op; prepare_assert_ops(&op); op.truncate(size); return operate(oid, &op, NULL); } int librados::IoCtxImpl::tmap_update(const object_t& oid, bufferlist& cmdbl) { ::ObjectOperation wr; prepare_assert_ops(&wr); wr.tmap_update(cmdbl); return operate(oid, &wr, NULL); } int librados::IoCtxImpl::tmap_put(const object_t& oid, bufferlist& bl) { ::ObjectOperation wr; prepare_assert_ops(&wr); wr.tmap_put(bl); return operate(oid, &wr, NULL); } int librados::IoCtxImpl::tmap_get(const object_t& oid, bufferlist& bl) { ::ObjectOperation rd; prepare_assert_ops(&rd); rd.tmap_get(&bl, NULL); return operate_read(oid, &rd, NULL); } int librados::IoCtxImpl::tmap_to_omap(const object_t& oid, bool nullok) { ::ObjectOperation wr; prepare_assert_ops(&wr); wr.tmap_to_omap(nullok); return operate(oid, &wr, NULL); } int librados::IoCtxImpl::exec(const object_t& oid, const char *cls, const char *method, bufferlist& inbl, bufferlist& outbl) { ::ObjectOperation rd; prepare_assert_ops(&rd); rd.call(cls, method, inbl); return operate_read(oid, &rd, &outbl); } int librados::IoCtxImpl::aio_exec(const object_t& oid, AioCompletionImpl *c, const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl) { Context *onack = new C_aio_Ack(c); c->is_read = true; c->io = this; Mutex::Locker l(*lock); ::ObjectOperation rd; prepare_assert_ops(&rd); rd.call(cls, method, inbl); objecter->read(oid, oloc, rd, snap_seq, outbl, 0, onack, &c->objver); return 0; } int librados::IoCtxImpl::read(const object_t& oid, bufferlist& bl, size_t len, uint64_t off) { if (len > (size_t) INT_MAX) return -EDOM; ::ObjectOperation rd; prepare_assert_ops(&rd); rd.read(off, len, &bl, NULL, NULL); int r = operate_read(oid, &rd, &bl); if (r < 0) return r; if (bl.length() < len) { ldout(client->cct, 10) << "Returned length " << bl.length() << " less than original length "<< len << dendl; } return bl.length(); } int librados::IoCtxImpl::mapext(const object_t& oid, uint64_t off, size_t len, std::map& m) { bufferlist bl; Mutex mylock("IoCtxImpl::read::mylock"); Cond cond; bool done; int r; Context *onack = new C_SafeCond(&mylock, &cond, &done, &r); lock->Lock(); objecter->mapext(oid, oloc, off, len, snap_seq, &bl, 0, onack); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); ldout(client->cct, 10) << "Objecter returned from read r=" << r << dendl; if (r < 0) return r; bufferlist::iterator iter = bl.begin(); ::decode(m, iter); return m.size(); } int librados::IoCtxImpl::sparse_read(const object_t& oid, std::map& m, bufferlist& data_bl, size_t len, uint64_t off) { if (len > (size_t) INT_MAX) return -EDOM; ::ObjectOperation rd; prepare_assert_ops(&rd); rd.sparse_read(off, len, &m, &data_bl, NULL); int r = operate_read(oid, &rd, NULL); if (r < 0) return r; return m.size(); } int librados::IoCtxImpl::stat(const object_t& oid, uint64_t *psize, time_t *pmtime) { uint64_t size; utime_t mtime; if (!psize) psize = &size; ::ObjectOperation rd; prepare_assert_ops(&rd); rd.stat(psize, &mtime, NULL); int r = operate_read(oid, &rd, NULL); if (r >= 0 && pmtime) { *pmtime = mtime.sec(); } return r; } int librados::IoCtxImpl::getxattr(const object_t& oid, const char *name, bufferlist& bl) { ::ObjectOperation rd; prepare_assert_ops(&rd); rd.getxattr(name, &bl, NULL); int r = operate_read(oid, &rd, NULL); if (r < 0) return r; return bl.length(); } int librados::IoCtxImpl::rmxattr(const object_t& oid, const char *name) { ::ObjectOperation op; prepare_assert_ops(&op); op.rmxattr(name); return operate(oid, &op, NULL); } int librados::IoCtxImpl::setxattr(const object_t& oid, const char *name, bufferlist& bl) { ::ObjectOperation op; prepare_assert_ops(&op); op.setxattr(name, bl); return operate(oid, &op, NULL); } int librados::IoCtxImpl::getxattrs(const object_t& oid, map& attrset) { map aset; ::ObjectOperation rd; prepare_assert_ops(&rd); rd.getxattrs(&aset, NULL); int r = operate_read(oid, &rd, NULL); attrset.clear(); if (r >= 0) { for (map::iterator p = aset.begin(); p != aset.end(); ++p) { ldout(client->cct, 10) << "IoCtxImpl::getxattrs: xattr=" << p->first << dendl; attrset[p->first.c_str()] = p->second; } } return r; } void librados::IoCtxImpl::set_sync_op_version(version_t ver) { last_objver = ver; } int librados::IoCtxImpl::watch(const object_t& oid, uint64_t ver, uint64_t *cookie, librados::WatchCtx *ctx) { ::ObjectOperation wr; Mutex mylock("IoCtxImpl::watch::mylock"); Cond cond; bool done; int r; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &r); version_t objver; lock->Lock(); WatchContext *wc = new WatchContext(this, oid, ctx); client->register_watcher(wc, cookie); prepare_assert_ops(&wr); wr.watch(*cookie, ver, 1); bufferlist bl; wc->linger_id = objecter->linger_mutate(oid, oloc, wr, snapc, ceph_clock_now(NULL), bl, 0, NULL, onfinish, &objver); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); set_sync_op_version(objver); if (r < 0) { lock->Lock(); client->unregister_watcher(*cookie); lock->Unlock(); } return r; } /* this is called with IoCtxImpl::lock held */ int librados::IoCtxImpl::_notify_ack( const object_t& oid, uint64_t notify_id, uint64_t ver, uint64_t cookie) { ::ObjectOperation rd; prepare_assert_ops(&rd); rd.notify_ack(notify_id, ver, cookie); objecter->read(oid, oloc, rd, snap_seq, (bufferlist*)NULL, 0, 0, 0); return 0; } int librados::IoCtxImpl::unwatch(const object_t& oid, uint64_t cookie) { bufferlist inbl, outbl; Mutex mylock("IoCtxImpl::unwatch::mylock"); Cond cond; bool done; int r; Context *oncommit = new C_SafeCond(&mylock, &cond, &done, &r); version_t ver; lock->Lock(); client->unregister_watcher(cookie); ::ObjectOperation wr; prepare_assert_ops(&wr); wr.watch(cookie, 0, 0); objecter->mutate(oid, oloc, wr, snapc, ceph_clock_now(client->cct), 0, NULL, oncommit, &ver); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); set_sync_op_version(ver); return r; } int librados::IoCtxImpl::notify(const object_t& oid, uint64_t ver, bufferlist& bl) { bufferlist inbl, outbl; Mutex mylock("IoCtxImpl::notify::mylock"); Mutex mylock_all("IoCtxImpl::notify::mylock_all"); Cond cond, cond_all; bool done, done_all; int r; Context *onack = new C_SafeCond(&mylock, &cond, &done, &r); version_t objver; uint64_t cookie; C_NotifyComplete *ctx = new C_NotifyComplete(&mylock_all, &cond_all, &done_all); ::ObjectOperation rd; prepare_assert_ops(&rd); lock->Lock(); WatchContext *wc = new WatchContext(this, oid, ctx); client->register_watcher(wc, &cookie); uint32_t prot_ver = 1; uint32_t timeout = notify_timeout; ::encode(prot_ver, inbl); ::encode(timeout, inbl); ::encode(bl, inbl); rd.notify(cookie, ver, inbl); wc->linger_id = objecter->linger_read(oid, oloc, rd, snap_seq, inbl, NULL, 0, onack, &objver); lock->Unlock(); mylock.Lock(); while (!done) cond.Wait(mylock); mylock.Unlock(); mylock_all.Lock(); if (r == 0) { while (!done_all) cond_all.Wait(mylock_all); } mylock_all.Unlock(); lock->Lock(); client->unregister_watcher(cookie); lock->Unlock(); set_sync_op_version(objver); delete ctx; return r; } int librados::IoCtxImpl::set_alloc_hint(const object_t& oid, uint64_t expected_object_size, uint64_t expected_write_size) { ::ObjectOperation wr; prepare_assert_ops(&wr); wr.set_alloc_hint(expected_object_size, expected_write_size); return operate(oid, &wr, NULL); } version_t librados::IoCtxImpl::last_version() { return last_objver; } void librados::IoCtxImpl::set_assert_version(uint64_t ver) { assert_ver = ver; } void librados::IoCtxImpl::set_assert_src_version(const object_t& oid, uint64_t ver) { assert_src_version[oid] = ver; } void librados::IoCtxImpl::set_notify_timeout(uint32_t timeout) { notify_timeout = timeout; } ///////////////////////////// C_aio_Ack //////////////////////////////// librados::IoCtxImpl::C_aio_Ack::C_aio_Ack(AioCompletionImpl *_c) : c(_c) { c->get(); } void librados::IoCtxImpl::C_aio_Ack::finish(int r) { c->lock.Lock(); c->rval = r; c->ack = true; if (c->is_read) c->safe = true; c->cond.Signal(); if (r == 0 && c->blp && c->blp->length() > 0) { c->rval = c->blp->length(); } if (c->callback_complete) { c->io->client->finisher.queue(new C_AioComplete(c)); } if (c->is_read && c->callback_safe) { c->io->client->finisher.queue(new C_AioSafe(c)); } c->put_unlock(); } ///////////////////////////// C_aio_stat_Ack //////////////////////////// librados::IoCtxImpl::C_aio_stat_Ack::C_aio_stat_Ack(AioCompletionImpl *_c, time_t *pm) : c(_c), pmtime(pm) { c->get(); } void librados::IoCtxImpl::C_aio_stat_Ack::finish(int r) { c->lock.Lock(); c->rval = r; c->ack = true; c->cond.Signal(); if (r >= 0 && pmtime) { *pmtime = mtime.sec(); } if (c->callback_complete) { c->io->client->finisher.queue(new C_AioComplete(c)); } c->put_unlock(); } //////////////////////////// C_aio_Safe //////////////////////////////// librados::IoCtxImpl::C_aio_Safe::C_aio_Safe(AioCompletionImpl *_c) : c(_c) { c->get(); } void librados::IoCtxImpl::C_aio_Safe::finish(int r) { c->lock.Lock(); if (!c->ack) { c->rval = r; c->ack = true; } c->safe = true; c->cond.Signal(); if (c->callback_safe) { c->io->client->finisher.queue(new C_AioSafe(c)); } c->io->complete_aio_write(c); c->put_unlock(); } ///////////////////////// C_NotifyComplete ///////////////////////////// librados::IoCtxImpl::C_NotifyComplete::C_NotifyComplete(Mutex *_l, Cond *_c, bool *_d) : lock(_l), cond(_c), done(_d) { *done = false; } void librados::IoCtxImpl::C_NotifyComplete::notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { lock->Lock(); *done = true; cond->Signal(); lock->Unlock(); } /////////////////////////// WatchContext /////////////////////////////// librados::WatchContext::WatchContext(IoCtxImpl *io_ctx_impl_, const object_t& _oc, librados::WatchCtx *_ctx) : io_ctx_impl(io_ctx_impl_), oid(_oc), ctx(_ctx), linger_id(0), cookie(0) { io_ctx_impl->get(); } librados::WatchContext::~WatchContext() { io_ctx_impl->put(); } void librados::WatchContext::notify(Mutex *client_lock, uint8_t opcode, uint64_t ver, uint64_t notify_id, bufferlist& payload) { ctx->notify(opcode, ver, payload); if (opcode != WATCH_NOTIFY_COMPLETE) { client_lock->Lock(); io_ctx_impl->_notify_ack(oid, notify_id, ver, cookie); client_lock->Unlock(); } } ceph-0.80.11/src/librados/RadosClient.h0000664000175100017510000000755412623076744021656 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRADOS_RADOSCLIENT_H #define CEPH_LIBRADOS_RADOSCLIENT_H #include "common/Cond.h" #include "common/Mutex.h" #include "common/RWLock.h" #include "common/Timer.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "mon/MonClient.h" #include "msg/Dispatcher.h" #include "osd/OSDMap.h" #include "IoCtxImpl.h" struct AuthAuthorizer; class CephContext; struct Connection; struct md_config_t; class Message; class MWatchNotify; class MLog; class Messenger; class librados::RadosClient : public Dispatcher { public: CephContext *cct; md_config_t *conf; private: enum { DISCONNECTED, CONNECTING, CONNECTED, } state; OSDMap osdmap; MonClient monclient; Messenger *messenger; uint64_t instance_id; bool _dispatch(Message *m); bool ms_dispatch(Message *m); bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); void ms_handle_connect(Connection *con); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con); Objecter *objecter; map pool_cache; epoch_t osdmap_epoch; epoch_t pool_cache_epoch; Mutex lock; RWLock pool_cache_rwl; Cond cond; SafeTimer timer; int refcnt; version_t log_last_version; rados_log_callback_t log_cb; void *log_cb_arg; string log_watch; int wait_for_osdmap(); public: Finisher finisher; RadosClient(CephContext *cct_); ~RadosClient(); int ping_monitor(string mon_id, string *result); int connect(); void shutdown(); uint64_t get_instance_id(); int wait_for_latest_osdmap(); int create_ioctx(const char *name, IoCtxImpl **io); int get_fsid(std::string *s); int64_t lookup_pool(const char *name); const char *get_pool_name(int64_t pool_id); bool pool_requires_alignment(int64_t pool_id); uint64_t pool_required_alignment(int64_t pool_id); int pool_get_auid(uint64_t pool_id, unsigned long long *auid); int pool_get_name(uint64_t pool_id, std::string *auid); int pool_list(std::list& ls); int get_pool_stats(std::list& ls, map& result); int get_fs_stats(ceph_statfs& result); int pool_create(string& name, unsigned long long auid=0, __u8 crush_rule=0); int pool_create_async(string& name, PoolAsyncCompletionImpl *c, unsigned long long auid=0, __u8 crush_rule=0); int pool_delete(const char *name); int pool_delete_async(const char *name, PoolAsyncCompletionImpl *c); // watch/notify uint64_t max_watch_cookie; map watchers; void register_watcher(librados::WatchContext *wc, uint64_t *cookie); void unregister_watcher(uint64_t cookie); void watch_notify(MWatchNotify *m); int mon_command(const vector& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs); int mon_command(int rank, const vector& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs); int mon_command(string name, const vector& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs); int osd_command(int osd, vector& cmd, const bufferlist& inbl, bufferlist *poutbl, string *prs); int pg_command(pg_t pgid, vector& cmd, const bufferlist& inbl, bufferlist *poutbl, string *prs); void handle_log(MLog *m); int monitor_log(const string& level, rados_log_callback_t cb, void *arg); void get(); bool put(); void blacklist_self(bool set); }; #endif ceph-0.80.11/src/librados/IoCtxImpl.h0000664000175100017510000002033412623076744021306 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRADOS_IOCTXIMPL_H #define CEPH_LIBRADOS_IOCTXIMPL_H #include "common/Cond.h" #include "common/Mutex.h" #include "common/snap_types.h" #include "include/atomic.h" #include "include/types.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/xlist.h" #include "osd/osd_types.h" #include "osdc/Objecter.h" class RadosClient; struct librados::IoCtxImpl { atomic_t ref_cnt; RadosClient *client; int64_t poolid; string pool_name; snapid_t snap_seq; ::SnapContext snapc; uint64_t assert_ver; map assert_src_version; version_t last_objver; uint32_t notify_timeout; object_locator_t oloc; Mutex aio_write_list_lock; ceph_tid_t aio_write_seq; Cond aio_write_cond; xlist aio_write_list; map > aio_write_waiters; Mutex *lock; Objecter *objecter; IoCtxImpl(); IoCtxImpl(RadosClient *c, Objecter *objecter, Mutex *client_lock, int poolid, const char *pool_name, snapid_t s); void dup(const IoCtxImpl& rhs) { // Copy everything except the ref count client = rhs.client; poolid = rhs.poolid; pool_name = rhs.pool_name; snap_seq = rhs.snap_seq; snapc = rhs.snapc; assert_ver = rhs.assert_ver; assert_src_version = rhs.assert_src_version; last_objver = rhs.last_objver; notify_timeout = rhs.notify_timeout; oloc = rhs.oloc; lock = rhs.lock; objecter = rhs.objecter; } void set_snap_read(snapid_t s); int set_snap_write_context(snapid_t seq, vector& snaps); void get() { ref_cnt.inc(); } void put() { if (ref_cnt.dec() == 0) delete this; } void queue_aio_write(struct AioCompletionImpl *c); void complete_aio_write(struct AioCompletionImpl *c); void flush_aio_writes_async(AioCompletionImpl *c); void flush_aio_writes(); int64_t get_id() { return poolid; } uint32_t get_object_hash_position(const std::string& oid); uint32_t get_object_pg_hash_position(const std::string& oid); ::ObjectOperation *prepare_assert_ops(::ObjectOperation *op); // snaps int snap_list(vector *snaps); int snap_lookup(const char *name, uint64_t *snapid); int snap_get_name(uint64_t snapid, std::string *s); int snap_get_stamp(uint64_t snapid, time_t *t); int snap_create(const char* snapname); int selfmanaged_snap_create(uint64_t *snapid); int snap_remove(const char* snapname); int rollback(const object_t& oid, const char *snapName); int selfmanaged_snap_remove(uint64_t snapid); int selfmanaged_snap_rollback_object(const object_t& oid, ::SnapContext& snapc, uint64_t snapid); // io int list(Objecter::ListContext *context, int max_entries); uint32_t list_seek(Objecter::ListContext *context, uint32_t pos); int create(const object_t& oid, bool exclusive); int create(const object_t& oid, bool exclusive, const std::string& category); int write(const object_t& oid, bufferlist& bl, size_t len, uint64_t off); int append(const object_t& oid, bufferlist& bl, size_t len); int write_full(const object_t& oid, bufferlist& bl); int clone_range(const object_t& dst_oid, uint64_t dst_offset, const object_t& src_oid, uint64_t src_offset, uint64_t len); int read(const object_t& oid, bufferlist& bl, size_t len, uint64_t off); int mapext(const object_t& oid, uint64_t off, size_t len, std::map& m); int sparse_read(const object_t& oid, std::map& m, bufferlist& bl, size_t len, uint64_t off); int remove(const object_t& oid); int stat(const object_t& oid, uint64_t *psize, time_t *pmtime); int trunc(const object_t& oid, uint64_t size); int tmap_update(const object_t& oid, bufferlist& cmdbl); int tmap_put(const object_t& oid, bufferlist& bl); int tmap_get(const object_t& oid, bufferlist& bl); int tmap_to_omap(const object_t& oid, bool nullok=false); int exec(const object_t& oid, const char *cls, const char *method, bufferlist& inbl, bufferlist& outbl); int getxattr(const object_t& oid, const char *name, bufferlist& bl); int setxattr(const object_t& oid, const char *name, bufferlist& bl); int getxattrs(const object_t& oid, map& attrset); int rmxattr(const object_t& oid, const char *name); int operate(const object_t& oid, ::ObjectOperation *o, time_t *pmtime, int flags=0); int operate_read(const object_t& oid, ::ObjectOperation *o, bufferlist *pbl, int flags=0); int aio_operate(const object_t& oid, ::ObjectOperation *o, AioCompletionImpl *c, const SnapContext& snap_context, int flags); int aio_operate_read(const object_t& oid, ::ObjectOperation *o, AioCompletionImpl *c, int flags, bufferlist *pbl); struct C_aio_Ack : public Context { librados::AioCompletionImpl *c; C_aio_Ack(AioCompletionImpl *_c); void finish(int r); }; struct C_aio_stat_Ack : public Context { librados::AioCompletionImpl *c; time_t *pmtime; utime_t mtime; C_aio_stat_Ack(AioCompletionImpl *_c, time_t *pm); void finish(int r); }; struct C_aio_Safe : public Context { AioCompletionImpl *c; C_aio_Safe(AioCompletionImpl *_c); void finish(int r); }; int aio_read(const object_t oid, AioCompletionImpl *c, bufferlist *pbl, size_t len, uint64_t off, uint64_t snapid); int aio_read(object_t oid, AioCompletionImpl *c, char *buf, size_t len, uint64_t off, uint64_t snapid); int aio_sparse_read(const object_t oid, AioCompletionImpl *c, std::map *m, bufferlist *data_bl, size_t len, uint64_t off, uint64_t snapid); int aio_write(const object_t &oid, AioCompletionImpl *c, const bufferlist& bl, size_t len, uint64_t off); int aio_append(const object_t &oid, AioCompletionImpl *c, const bufferlist& bl, size_t len); int aio_write_full(const object_t &oid, AioCompletionImpl *c, const bufferlist& bl); int aio_remove(const object_t &oid, AioCompletionImpl *c); int aio_exec(const object_t& oid, AioCompletionImpl *c, const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl); int aio_stat(const object_t& oid, AioCompletionImpl *c, uint64_t *psize, time_t *pmtime); int pool_change_auid(unsigned long long auid); int pool_change_auid_async(unsigned long long auid, PoolAsyncCompletionImpl *c); int hit_set_list(uint32_t hash, AioCompletionImpl *c, std::list< std::pair > *pls); int hit_set_get(uint32_t hash, AioCompletionImpl *c, time_t stamp, bufferlist *pbl); void set_sync_op_version(version_t ver); int watch(const object_t& oid, uint64_t ver, uint64_t *cookie, librados::WatchCtx *ctx); int unwatch(const object_t& oid, uint64_t cookie); int notify(const object_t& oid, uint64_t ver, bufferlist& bl); int _notify_ack( const object_t& oid, uint64_t notify_id, uint64_t ver, uint64_t cookie); int set_alloc_hint(const object_t& oid, uint64_t expected_object_size, uint64_t expected_write_size); version_t last_version(); void set_assert_version(uint64_t ver); void set_assert_src_version(const object_t& oid, uint64_t ver); void set_notify_timeout(uint32_t timeout); struct C_NotifyComplete : public librados::WatchCtx { Mutex *lock; Cond *cond; bool *done; C_NotifyComplete(Mutex *_l, Cond *_c, bool *_d); void notify(uint8_t opcode, uint64_t ver, bufferlist& bl); }; }; namespace librados { struct WatchContext : public RefCountedWaitObject { IoCtxImpl *io_ctx_impl; const object_t oid; librados::WatchCtx *ctx; uint64_t linger_id; uint64_t cookie; WatchContext(IoCtxImpl *io_ctx_impl_, const object_t& _oc, librados::WatchCtx *_ctx); ~WatchContext(); void notify(Mutex *lock, uint8_t opcode, uint64_t ver, uint64_t notify_id, bufferlist& payload); }; } #endif ceph-0.80.11/src/librados/Makefile.am0000664000175100017510000000133312623076744021317 0ustar jenkins-buildjenkins-buildlibrados_la_SOURCES = \ librados/librados.cc \ librados/RadosClient.cc \ librados/IoCtxImpl.cc \ librados/snap_set_diff.cc # We need this to avoid basename conflicts with the librados build tests in test/Makefile.am librados_la_CXXFLAGS = ${AM_CXXFLAGS} LIBRADOS_DEPS += libcls_lock_client.la $(LIBOSDC) $(LIBCOMMON) librados_la_LIBADD = $(LIBRADOS_DEPS) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) librados_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 if LINUX librados_la_LDFLAGS += -export-symbols-regex '^rados_.*' endif lib_LTLIBRARIES += librados.la noinst_HEADERS += \ librados/snap_set_diff.h \ librados/AioCompletionImpl.h \ librados/IoCtxImpl.h \ librados/PoolAsyncCompletionImpl.h \ librados/RadosClient.h ceph-0.80.11/src/librados/PoolAsyncCompletionImpl.h0000664000175100017510000000465112623076744024225 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRADOS_POOLASYNCCOMPLETIONIMPL_H #define CEPH_LIBRADOS_POOLASYNCCOMPLETIONIMPL_H #include "common/Cond.h" #include "common/Mutex.h" #include "include/Context.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" namespace librados { struct PoolAsyncCompletionImpl { Mutex lock; Cond cond; int ref, rval; bool released; bool done; rados_callback_t callback; void *callback_arg; PoolAsyncCompletionImpl() : lock("PoolAsyncCompletionImpl lock"), ref(1), rval(0), released(false), done(false), callback(0), callback_arg(0) {} int set_callback(void *cb_arg, rados_callback_t cb) { lock.Lock(); callback = cb; callback_arg = cb_arg; lock.Unlock(); return 0; } int wait() { lock.Lock(); while (!done) cond.Wait(lock); lock.Unlock(); return 0; } int is_complete() { lock.Lock(); int r = done; lock.Unlock(); return r; } int get_return_value() { lock.Lock(); int r = rval; lock.Unlock(); return r; } void get() { lock.Lock(); assert(ref > 0); ref++; lock.Unlock(); } void release() { lock.Lock(); assert(!released); released = true; put_unlock(); } void put() { lock.Lock(); put_unlock(); } void put_unlock() { assert(ref > 0); int n = --ref; lock.Unlock(); if (!n) delete this; } }; class C_PoolAsync_Safe : public Context { PoolAsyncCompletionImpl *c; public: C_PoolAsync_Safe(PoolAsyncCompletionImpl *_c) : c(_c) { c->get(); } ~C_PoolAsync_Safe() { c->put(); } void finish(int r) { c->lock.Lock(); c->rval = r; c->done = true; c->cond.Signal(); if (c->callback) { rados_callback_t cb = c->callback; void *cb_arg = c->callback_arg; c->lock.Unlock(); cb(c, cb_arg); c->lock.Lock(); } c->lock.Unlock(); } }; } #endif ceph-0.80.11/src/librados/AioCompletionImpl.h0000664000175100017510000001210512623076744023017 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_LIBRADOS_AIOCOMPLETIONIMPL_H #define CEPH_LIBRADOS_AIOCOMPLETIONIMPL_H #include "common/Cond.h" #include "common/Mutex.h" #include "include/buffer.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/xlist.h" #include "osd/osd_types.h" class IoCtxImpl; struct librados::AioCompletionImpl { Mutex lock; Cond cond; int ref, rval; bool released; bool ack, safe; version_t objver; rados_callback_t callback_complete, callback_safe; void *callback_complete_arg, *callback_safe_arg; // for read bool is_read; bufferlist bl; bufferlist *blp; IoCtxImpl *io; ceph_tid_t aio_write_seq; xlist::item aio_write_list_item; AioCompletionImpl() : lock("AioCompletionImpl lock", false, false), ref(1), rval(0), released(false), ack(false), safe(false), objver(0), callback_complete(0), callback_safe(0), callback_complete_arg(0), callback_safe_arg(0), is_read(false), blp(NULL), io(NULL), aio_write_seq(0), aio_write_list_item(this) { } int set_complete_callback(void *cb_arg, rados_callback_t cb) { lock.Lock(); callback_complete = cb; callback_complete_arg = cb_arg; lock.Unlock(); return 0; } int set_safe_callback(void *cb_arg, rados_callback_t cb) { lock.Lock(); callback_safe = cb; callback_safe_arg = cb_arg; lock.Unlock(); return 0; } int wait_for_complete() { lock.Lock(); while (!ack) cond.Wait(lock); lock.Unlock(); return 0; } int wait_for_safe() { lock.Lock(); while (!safe) cond.Wait(lock); lock.Unlock(); return 0; } int is_complete() { lock.Lock(); int r = ack; lock.Unlock(); return r; } int is_safe() { lock.Lock(); int r = safe; lock.Unlock(); return r; } int wait_for_complete_and_cb() { lock.Lock(); while (!ack || callback_complete) cond.Wait(lock); lock.Unlock(); return 0; } int wait_for_safe_and_cb() { lock.Lock(); while (!safe || callback_safe) cond.Wait(lock); lock.Unlock(); return 0; } int is_complete_and_cb() { lock.Lock(); int r = ack && !callback_complete; lock.Unlock(); return r; } int is_safe_and_cb() { lock.Lock(); int r = safe && !callback_safe; lock.Unlock(); return r; } int get_return_value() { lock.Lock(); int r = rval; lock.Unlock(); return r; } uint64_t get_version() { lock.Lock(); version_t v = objver; lock.Unlock(); return v; } void get() { lock.Lock(); _get(); lock.Unlock(); } void _get() { assert(lock.is_locked()); assert(ref > 0); ++ref; } void release() { lock.Lock(); assert(!released); released = true; put_unlock(); } void put() { lock.Lock(); put_unlock(); } void put_unlock() { assert(ref > 0); int n = --ref; lock.Unlock(); if (!n) delete this; } }; namespace librados { struct C_AioComplete : public Context { AioCompletionImpl *c; C_AioComplete(AioCompletionImpl *cc) : c(cc) { c->_get(); } void finish(int r) { rados_callback_t cb = c->callback_complete; void *cb_arg = c->callback_complete_arg; cb(c, cb_arg); c->lock.Lock(); c->callback_complete = NULL; c->cond.Signal(); c->put_unlock(); } }; struct C_AioSafe : public Context { AioCompletionImpl *c; C_AioSafe(AioCompletionImpl *cc) : c(cc) { c->_get(); } void finish(int r) { rados_callback_t cb = c->callback_safe; void *cb_arg = c->callback_safe_arg; cb(c, cb_arg); c->lock.Lock(); c->callback_safe = NULL; c->cond.Signal(); c->put_unlock(); } }; /** * Fills in all completed request data, and calls both * complete and safe callbacks if they exist. * * Not useful for usual I/O, but for special things like * flush where we only want to wait for things to be safe, * but allow users to specify any of the callbacks. */ struct C_AioCompleteAndSafe : public Context { AioCompletionImpl *c; C_AioCompleteAndSafe(AioCompletionImpl *cc) : c(cc) { c->get(); } void finish(int r) { c->lock.Lock(); c->rval = r; c->ack = true; c->safe = true; c->lock.Unlock(); rados_callback_t cb_complete = c->callback_complete; void *cb_complete_arg = c->callback_complete_arg; if (cb_complete) cb_complete(c, cb_complete_arg); rados_callback_t cb_safe = c->callback_safe; void *cb_safe_arg = c->callback_safe_arg; if (cb_safe) cb_safe(c, cb_safe_arg); c->lock.Lock(); c->callback_complete = NULL; c->callback_safe = NULL; c->cond.Signal(); c->put_unlock(); } }; } #endif ceph-0.80.11/src/librados/librados.cc0000664000175100017510000027615412623076744021410 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "common/config.h" #include "common/errno.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/types.h" #include #include "librados/AioCompletionImpl.h" #include "librados/IoCtxImpl.h" #include "librados/PoolAsyncCompletionImpl.h" #include "librados/RadosClient.h" #include #include #include #include #include #include #include using std::string; using std::map; using std::set; using std::vector; using std::list; using std::runtime_error; #define dout_subsys ceph_subsys_rados #undef dout_prefix #define dout_prefix *_dout << "librados: " #define RADOS_LIST_MAX_ENTRIES 1024 /* * Structure of this file * * RadosClient and the related classes are the internal implementation of librados. * Above that layer sits the C API, found in include/rados/librados.h, and * the C++ API, found in include/rados/librados.hpp * * The C++ API sometimes implements things in terms of the C API. * Both the C++ and C API rely on RadosClient. * * Visually: * +--------------------------------------+ * | C++ API | * +--------------------+ | * | C API | | * +--------------------+-----------------+ * | RadosClient | * +--------------------------------------+ */ size_t librados::ObjectOperation::size() { ::ObjectOperation *o = (::ObjectOperation *)impl; return o->size(); } static void set_op_flags(::ObjectOperation *o, int flags) { int rados_flags = 0; if (flags & LIBRADOS_OP_FLAG_EXCL) rados_flags |= CEPH_OSD_OP_FLAG_EXCL; if (flags & LIBRADOS_OP_FLAG_FAILOK) rados_flags |= CEPH_OSD_OP_FLAG_FAILOK; o->set_last_op_flags(rados_flags); } void librados::ObjectOperation::set_op_flags(ObjectOperationFlags flags) { ::ObjectOperation *o = (::ObjectOperation *)impl; ::set_op_flags(o, (int)flags); } void librados::ObjectOperation::cmpxattr(const char *name, uint8_t op, const bufferlist& v) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->cmpxattr(name, op, CEPH_OSD_CMPXATTR_MODE_STRING, v); } void librados::ObjectOperation::cmpxattr(const char *name, uint8_t op, uint64_t v) { ::ObjectOperation *o = (::ObjectOperation *)impl; bufferlist bl; ::encode(v, bl); o->cmpxattr(name, op, CEPH_OSD_CMPXATTR_MODE_U64, bl); } void librados::ObjectOperation::src_cmpxattr(const std::string& src_oid, const char *name, int op, const bufferlist& v) { ::ObjectOperation *o = (::ObjectOperation *)impl; object_t oid(src_oid); o->src_cmpxattr(oid, CEPH_NOSNAP, name, v, op, CEPH_OSD_CMPXATTR_MODE_STRING); } void librados::ObjectOperation::src_cmpxattr(const std::string& src_oid, const char *name, int op, uint64_t val) { ::ObjectOperation *o = (::ObjectOperation *)impl; object_t oid(src_oid); bufferlist bl; ::encode(val, bl); o->src_cmpxattr(oid, CEPH_NOSNAP, name, bl, op, CEPH_OSD_CMPXATTR_MODE_U64); } void librados::ObjectOperation::assert_version(uint64_t ver) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->assert_version(ver); } void librados::ObjectOperation::assert_exists() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->stat(NULL, (utime_t*)NULL, NULL); } void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->call(cls, method, inbl); } void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->call(cls, method, inbl, outbl, NULL, prval); } class ObjectOpCompletionCtx : public Context { librados::ObjectOperationCompletion *completion; bufferlist bl; public: ObjectOpCompletionCtx(librados::ObjectOperationCompletion *c) : completion(c) {} void finish(int r) { completion->handle_completion(r, bl); delete completion; } bufferlist *outbl() { return &bl; } }; void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, librados::ObjectOperationCompletion *completion) { ::ObjectOperation *o = (::ObjectOperation *)impl; ObjectOpCompletionCtx *ctx = new ObjectOpCompletionCtx(completion); o->call(cls, method, inbl, ctx->outbl(), ctx, NULL); } void librados::ObjectReadOperation::stat(uint64_t *psize, time_t *pmtime, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->stat(psize, pmtime, prval); } void librados::ObjectReadOperation::read(size_t off, uint64_t len, bufferlist *pbl, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->read(off, len, pbl, prval, NULL); } void librados::ObjectReadOperation::sparse_read(uint64_t off, uint64_t len, std::map *m, bufferlist *data_bl, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->sparse_read(off, len, m, data_bl, prval); } void librados::ObjectReadOperation::tmap_get(bufferlist *pbl, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->tmap_get(pbl, prval); } void librados::ObjectReadOperation::getxattr(const char *name, bufferlist *pbl, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->getxattr(name, pbl, prval); } void librados::ObjectReadOperation::omap_get_vals( const std::string &start_after, const std::string &filter_prefix, uint64_t max_return, std::map *out_vals, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_get_vals(start_after, filter_prefix, max_return, out_vals, prval); } void librados::ObjectReadOperation::omap_get_vals( const std::string &start_after, uint64_t max_return, std::map *out_vals, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_get_vals(start_after, "", max_return, out_vals, prval); } void librados::ObjectReadOperation::omap_get_keys( const std::string &start_after, uint64_t max_return, std::set *out_keys, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_get_keys(start_after, max_return, out_keys, prval); } void librados::ObjectReadOperation::omap_get_header(bufferlist *bl, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_get_header(bl, prval); } void librados::ObjectReadOperation::omap_get_vals_by_keys( const std::set &keys, std::map *map, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_get_vals_by_keys(keys, map, prval); } void librados::ObjectOperation::omap_cmp( const std::map > &assertions, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_cmp(assertions, prval); } void librados::ObjectReadOperation::list_watchers( list *out_watchers, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->list_watchers(out_watchers, prval); } void librados::ObjectReadOperation::list_snaps( snap_set_t *out_snaps, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->list_snaps(out_snaps, prval); } void librados::ObjectReadOperation::is_dirty(bool *is_dirty, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->is_dirty(is_dirty, prval); } int librados::IoCtx::omap_get_vals(const std::string& oid, const std::string& start_after, const std::string& filter_prefix, uint64_t max_return, std::map *out_vals) { ObjectReadOperation op; int r; op.omap_get_vals(start_after, filter_prefix, max_return, out_vals, &r); bufferlist bl; int ret = operate(oid, &op, &bl); if (ret < 0) return ret; return r; } void librados::ObjectReadOperation::getxattrs(map *pattrs, int *prval) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->getxattrs(pattrs, prval); } void librados::ObjectWriteOperation::create(bool exclusive) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->create(exclusive); } void librados::ObjectWriteOperation::create(bool exclusive, const std::string& category) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->create(exclusive, category); } void librados::ObjectWriteOperation::write(uint64_t off, const bufferlist& bl) { ::ObjectOperation *o = (::ObjectOperation *)impl; bufferlist c = bl; o->write(off, c); } void librados::ObjectWriteOperation::write_full(const bufferlist& bl) { ::ObjectOperation *o = (::ObjectOperation *)impl; bufferlist c = bl; o->write_full(c); } void librados::ObjectWriteOperation::append(const bufferlist& bl) { ::ObjectOperation *o = (::ObjectOperation *)impl; bufferlist c = bl; o->append(c); } void librados::ObjectWriteOperation::remove() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->remove(); } void librados::ObjectWriteOperation::truncate(uint64_t off) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->truncate(off); } void librados::ObjectWriteOperation::zero(uint64_t off, uint64_t len) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->zero(off, len); } void librados::ObjectWriteOperation::rmxattr(const char *name) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->rmxattr(name); } void librados::ObjectWriteOperation::setxattr(const char *name, const bufferlist& v) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->setxattr(name, v); } void librados::ObjectWriteOperation::omap_set( const map &map) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_set(map); } void librados::ObjectWriteOperation::omap_set_header(const bufferlist &bl) { bufferlist c = bl; ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_set_header(c); } void librados::ObjectWriteOperation::omap_clear() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_clear(); } void librados::ObjectWriteOperation::omap_rm_keys( const std::set &to_rm) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->omap_rm_keys(to_rm); } void librados::ObjectWriteOperation::copy_from(const std::string& src, const IoCtx& src_ioctx, uint64_t src_version) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->copy_from(object_t(src), src_ioctx.io_ctx_impl->snap_seq, src_ioctx.io_ctx_impl->oloc, src_version, 0); } void librados::ObjectWriteOperation::undirty() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->undirty(); } void librados::ObjectReadOperation::cache_flush() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->cache_flush(); } void librados::ObjectReadOperation::cache_try_flush() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->cache_try_flush(); } void librados::ObjectReadOperation::cache_evict() { ::ObjectOperation *o = (::ObjectOperation *)impl; o->cache_evict(); } void librados::ObjectWriteOperation::tmap_put(const bufferlist &bl) { ::ObjectOperation *o = (::ObjectOperation *)impl; bufferlist c = bl; o->tmap_put(c); } void librados::ObjectWriteOperation::tmap_update(const bufferlist& cmdbl) { ::ObjectOperation *o = (::ObjectOperation *)impl; bufferlist c = cmdbl; o->tmap_update(c); } void librados::ObjectWriteOperation::clone_range(uint64_t dst_off, const std::string& src_oid, uint64_t src_off, size_t len) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->clone_range(src_oid, src_off, len, dst_off); } void librados::ObjectWriteOperation::selfmanaged_snap_rollback(snap_t snapid) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->rollback(snapid); } // You must specify the snapid not the name normally used with pool snapshots void librados::ObjectWriteOperation::snap_rollback(snap_t snapid) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->rollback(snapid); } void librados::ObjectWriteOperation::set_alloc_hint( uint64_t expected_object_size, uint64_t expected_write_size) { ::ObjectOperation *o = (::ObjectOperation *)impl; o->set_alloc_hint(expected_object_size, expected_write_size); } librados::WatchCtx:: ~WatchCtx() { } struct librados::ObjListCtx { librados::IoCtxImpl *ctx; Objecter::ListContext *lc; ObjListCtx(IoCtxImpl *c, Objecter::ListContext *l) : ctx(c), lc(l) {} ~ObjListCtx() { delete lc; } }; ///////////////////////////// ObjectIterator ///////////////////////////// librados::ObjectIterator::ObjectIterator(ObjListCtx *ctx_) : ctx(ctx_) { } librados::ObjectIterator::~ObjectIterator() { ctx.reset(); } librados::ObjectIterator::ObjectIterator(const ObjectIterator &rhs) { *this = rhs; } librados::ObjectIterator& librados::ObjectIterator::operator=(const librados::ObjectIterator &rhs) { if (&rhs == this) return *this; if (rhs.ctx.get() == NULL) { ctx.reset(); return *this; } Objecter::ListContext *list_ctx = new Objecter::ListContext(*rhs.ctx->lc); ctx.reset(new ObjListCtx(rhs.ctx->ctx, list_ctx)); cur_obj = rhs.cur_obj; return *this; } bool librados::ObjectIterator::operator==(const librados::ObjectIterator& rhs) const { if (ctx.get() == NULL) return rhs.ctx.get() == NULL || rhs.ctx->lc->at_end(); if (rhs.ctx.get() == NULL) return ctx.get() == NULL || ctx->lc->at_end(); return ctx.get() == rhs.ctx.get(); } bool librados::ObjectIterator::operator!=(const librados::ObjectIterator& rhs) const { return !(*this == rhs); } const pair& librados::ObjectIterator::operator*() const { return cur_obj; } const pair* librados::ObjectIterator::operator->() const { return &cur_obj; } librados::ObjectIterator& librados::ObjectIterator::operator++() { get_next(); return *this; } librados::ObjectIterator librados::ObjectIterator::operator++(int) { librados::ObjectIterator ret(*this); get_next(); return ret; } uint32_t librados::ObjectIterator::seek(uint32_t pos) { uint32_t r = rados_objects_list_seek(ctx.get(), pos); get_next(); return r; } void librados::ObjectIterator::get_next() { const char *entry, *key; if (ctx->lc->at_end()) return; int ret = rados_objects_list_next(ctx.get(), &entry, &key); if (ret == -ENOENT) { return; } else if (ret) { ostringstream oss; oss << "rados returned " << cpp_strerror(ret); throw std::runtime_error(oss.str()); } cur_obj = make_pair(entry, key ? key : string()); } uint32_t librados::ObjectIterator::get_pg_hash_position() const { return ctx->lc->get_pg_hash_position(); } const librados::ObjectIterator librados::ObjectIterator::__EndObjectIterator(NULL); ///////////////////////////// PoolAsyncCompletion ////////////////////////////// int librados::PoolAsyncCompletion::PoolAsyncCompletion::set_callback(void *cb_arg, rados_callback_t cb) { PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc; return c->set_callback(cb_arg, cb); } int librados::PoolAsyncCompletion::PoolAsyncCompletion::wait() { PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc; return c->wait(); } bool librados::PoolAsyncCompletion::PoolAsyncCompletion::is_complete() { PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc; return c->is_complete(); } int librados::PoolAsyncCompletion::PoolAsyncCompletion::get_return_value() { PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc; return c->get_return_value(); } void librados::PoolAsyncCompletion::PoolAsyncCompletion::release() { PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc; c->release(); delete this; } ///////////////////////////// AioCompletion ////////////////////////////// int librados::AioCompletion::AioCompletion::set_complete_callback(void *cb_arg, rados_callback_t cb) { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->set_complete_callback(cb_arg, cb); } int librados::AioCompletion::AioCompletion::set_safe_callback(void *cb_arg, rados_callback_t cb) { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->set_safe_callback(cb_arg, cb); } int librados::AioCompletion::AioCompletion::wait_for_complete() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->wait_for_complete(); } int librados::AioCompletion::AioCompletion::wait_for_safe() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->wait_for_safe(); } bool librados::AioCompletion::AioCompletion::is_complete() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->is_complete(); } bool librados::AioCompletion::AioCompletion::is_safe() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->is_safe(); } int librados::AioCompletion::AioCompletion::wait_for_complete_and_cb() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->wait_for_complete_and_cb(); } int librados::AioCompletion::AioCompletion::wait_for_safe_and_cb() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->wait_for_safe_and_cb(); } bool librados::AioCompletion::AioCompletion::is_complete_and_cb() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->is_complete_and_cb(); } bool librados::AioCompletion::AioCompletion::is_safe_and_cb() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->is_safe_and_cb(); } int librados::AioCompletion::AioCompletion::get_return_value() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->get_return_value(); } int librados::AioCompletion::AioCompletion::get_version() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->get_version(); } uint64_t librados::AioCompletion::AioCompletion::get_version64() { AioCompletionImpl *c = (AioCompletionImpl *)pc; return c->get_version(); } void librados::AioCompletion::AioCompletion::release() { AioCompletionImpl *c = (AioCompletionImpl *)pc; c->release(); delete this; } ///////////////////////////// IoCtx ////////////////////////////// librados::IoCtx::IoCtx() : io_ctx_impl(NULL) { } void librados::IoCtx::from_rados_ioctx_t(rados_ioctx_t p, IoCtx &io) { IoCtxImpl *io_ctx_impl = (IoCtxImpl*)p; io.io_ctx_impl = io_ctx_impl; if (io_ctx_impl) { io_ctx_impl->get(); } } librados::IoCtx::IoCtx(const IoCtx& rhs) { io_ctx_impl = rhs.io_ctx_impl; if (io_ctx_impl) { io_ctx_impl->get(); } } librados::IoCtx& librados::IoCtx::operator=(const IoCtx& rhs) { if (io_ctx_impl) io_ctx_impl->put(); io_ctx_impl = rhs.io_ctx_impl; io_ctx_impl->get(); return *this; } librados::IoCtx::~IoCtx() { close(); } void librados::IoCtx::close() { if (io_ctx_impl) io_ctx_impl->put(); io_ctx_impl = 0; } void librados::IoCtx::dup(const IoCtx& rhs) { if (io_ctx_impl) io_ctx_impl->put(); io_ctx_impl = new IoCtxImpl(); io_ctx_impl->get(); io_ctx_impl->dup(*rhs.io_ctx_impl); } int librados::IoCtx::set_auid(uint64_t auid_) { return io_ctx_impl->pool_change_auid(auid_); } int librados::IoCtx::set_auid_async(uint64_t auid_, PoolAsyncCompletion *c) { return io_ctx_impl->pool_change_auid_async(auid_, c->pc); } int librados::IoCtx::get_auid(uint64_t *auid_) { return rados_ioctx_pool_get_auid(io_ctx_impl, auid_); } bool librados::IoCtx::pool_requires_alignment() { return io_ctx_impl->client->pool_requires_alignment(get_id()); } uint64_t librados::IoCtx::pool_required_alignment() { return io_ctx_impl->client->pool_required_alignment(get_id()); } std::string librados::IoCtx::get_pool_name() { std::string s; io_ctx_impl->client->pool_get_name(get_id(), &s); return s; } int librados::IoCtx::create(const std::string& oid, bool exclusive) { object_t obj(oid); return io_ctx_impl->create(obj, exclusive); } int librados::IoCtx::create(const std::string& oid, bool exclusive, const std::string& category) { object_t obj(oid); return io_ctx_impl->create(obj, exclusive, category); } int librados::IoCtx::write(const std::string& oid, bufferlist& bl, size_t len, uint64_t off) { object_t obj(oid); return io_ctx_impl->write(obj, bl, len, off); } int librados::IoCtx::append(const std::string& oid, bufferlist& bl, size_t len) { object_t obj(oid); return io_ctx_impl->append(obj, bl, len); } int librados::IoCtx::write_full(const std::string& oid, bufferlist& bl) { object_t obj(oid); return io_ctx_impl->write_full(obj, bl); } int librados::IoCtx::clone_range(const std::string& dst_oid, uint64_t dst_off, const std::string& src_oid, uint64_t src_off, size_t len) { object_t src(src_oid), dst(dst_oid); return io_ctx_impl->clone_range(dst, dst_off, src, src_off, len); } int librados::IoCtx::read(const std::string& oid, bufferlist& bl, size_t len, uint64_t off) { object_t obj(oid); return io_ctx_impl->read(obj, bl, len, off); } int librados::IoCtx::remove(const std::string& oid) { object_t obj(oid); return io_ctx_impl->remove(obj); } int librados::IoCtx::trunc(const std::string& oid, uint64_t size) { object_t obj(oid); return io_ctx_impl->trunc(obj, size); } int librados::IoCtx::mapext(const std::string& oid, uint64_t off, size_t len, std::map& m) { object_t obj(oid); return io_ctx_impl->mapext(oid, off, len, m); } int librados::IoCtx::sparse_read(const std::string& oid, std::map& m, bufferlist& bl, size_t len, uint64_t off) { object_t obj(oid); return io_ctx_impl->sparse_read(oid, m, bl, len, off); } int librados::IoCtx::getxattr(const std::string& oid, const char *name, bufferlist& bl) { object_t obj(oid); return io_ctx_impl->getxattr(obj, name, bl); } int librados::IoCtx::getxattrs(const std::string& oid, map& attrset) { object_t obj(oid); return io_ctx_impl->getxattrs(obj, attrset); } int librados::IoCtx::setxattr(const std::string& oid, const char *name, bufferlist& bl) { object_t obj(oid); return io_ctx_impl->setxattr(obj, name, bl); } int librados::IoCtx::rmxattr(const std::string& oid, const char *name) { object_t obj(oid); return io_ctx_impl->rmxattr(obj, name); } int librados::IoCtx::stat(const std::string& oid, uint64_t *psize, time_t *pmtime) { object_t obj(oid); return io_ctx_impl->stat(oid, psize, pmtime); } int librados::IoCtx::exec(const std::string& oid, const char *cls, const char *method, bufferlist& inbl, bufferlist& outbl) { object_t obj(oid); return io_ctx_impl->exec(obj, cls, method, inbl, outbl); } int librados::IoCtx::tmap_update(const std::string& oid, bufferlist& cmdbl) { object_t obj(oid); return io_ctx_impl->tmap_update(obj, cmdbl); } int librados::IoCtx::tmap_put(const std::string& oid, bufferlist& bl) { object_t obj(oid); return io_ctx_impl->tmap_put(obj, bl); } int librados::IoCtx::tmap_get(const std::string& oid, bufferlist& bl) { object_t obj(oid); return io_ctx_impl->tmap_get(obj, bl); } int librados::IoCtx::tmap_to_omap(const std::string& oid, bool nullok) { object_t obj(oid); return io_ctx_impl->tmap_to_omap(obj, nullok); } int librados::IoCtx::omap_get_vals(const std::string& oid, const std::string& start_after, uint64_t max_return, std::map *out_vals) { ObjectReadOperation op; int r; op.omap_get_vals(start_after, max_return, out_vals, &r); bufferlist bl; int ret = operate(oid, &op, &bl); if (ret < 0) return ret; return r; } int librados::IoCtx::omap_get_keys(const std::string& oid, const std::string& start_after, uint64_t max_return, std::set *out_keys) { ObjectReadOperation op; int r; op.omap_get_keys(start_after, max_return, out_keys, &r); bufferlist bl; int ret = operate(oid, &op, &bl); if (ret < 0) return ret; return r; } int librados::IoCtx::omap_get_header(const std::string& oid, bufferlist *bl) { ObjectReadOperation op; int r; op.omap_get_header(bl, &r); bufferlist b; int ret = operate(oid, &op, &b); if (ret < 0) return ret; return r; } int librados::IoCtx::omap_get_vals_by_keys(const std::string& oid, const std::set& keys, std::map *vals) { ObjectReadOperation op; int r; bufferlist bl; op.omap_get_vals_by_keys(keys, vals, &r); int ret = operate(oid, &op, &bl); if (ret < 0) return ret; return r; } int librados::IoCtx::omap_set(const std::string& oid, const map& m) { ObjectWriteOperation op; op.omap_set(m); return operate(oid, &op); } int librados::IoCtx::omap_set_header(const std::string& oid, const bufferlist& bl) { ObjectWriteOperation op; op.omap_set_header(bl); return operate(oid, &op); } int librados::IoCtx::omap_clear(const std::string& oid) { ObjectWriteOperation op; op.omap_clear(); return operate(oid, &op); } int librados::IoCtx::omap_rm_keys(const std::string& oid, const std::set& keys) { ObjectWriteOperation op; op.omap_rm_keys(keys); return operate(oid, &op); } static int translate_flags(int flags) { int op_flags = 0; if (flags & librados::OPERATION_BALANCE_READS) op_flags |= CEPH_OSD_FLAG_BALANCE_READS; if (flags & librados::OPERATION_LOCALIZE_READS) op_flags |= CEPH_OSD_FLAG_LOCALIZE_READS; if (flags & librados::OPERATION_ORDER_READS_WRITES) op_flags |= CEPH_OSD_FLAG_RWORDERED; if (flags & librados::OPERATION_IGNORE_CACHE) op_flags |= CEPH_OSD_FLAG_IGNORE_CACHE; if (flags & librados::OPERATION_SKIPRWLOCKS) op_flags |= CEPH_OSD_FLAG_SKIPRWLOCKS; if (flags & librados::OPERATION_IGNORE_OVERLAY) op_flags |= CEPH_OSD_FLAG_IGNORE_OVERLAY; return op_flags; } int librados::IoCtx::operate(const std::string& oid, librados::ObjectWriteOperation *o) { object_t obj(oid); return io_ctx_impl->operate(obj, (::ObjectOperation*)o->impl, o->pmtime); } int librados::IoCtx::operate(const std::string& oid, librados::ObjectReadOperation *o, bufferlist *pbl) { object_t obj(oid); return io_ctx_impl->operate_read(obj, (::ObjectOperation*)o->impl, pbl); } int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c, librados::ObjectWriteOperation *o) { object_t obj(oid); return io_ctx_impl->aio_operate(obj, (::ObjectOperation*)o->impl, c->pc, io_ctx_impl->snapc, 0); } int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c, ObjectWriteOperation *o, int flags) { object_t obj(oid); return io_ctx_impl->aio_operate(obj, (::ObjectOperation*)o->impl, c->pc, io_ctx_impl->snapc, translate_flags(flags)); } int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c, librados::ObjectWriteOperation *o, snap_t snap_seq, std::vector& snaps) { object_t obj(oid); vector snv; snv.resize(snaps.size()); for (size_t i = 0; i < snaps.size(); ++i) snv[i] = snaps[i]; SnapContext snapc(snap_seq, snv); return io_ctx_impl->aio_operate(obj, (::ObjectOperation*)o->impl, c->pc, snapc, 0); } int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c, librados::ObjectReadOperation *o, bufferlist *pbl) { object_t obj(oid); return io_ctx_impl->aio_operate_read(obj, (::ObjectOperation*)o->impl, c->pc, 0, pbl); } // deprecated int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c, librados::ObjectReadOperation *o, snap_t snapid_unused_deprecated, int flags, bufferlist *pbl) { object_t obj(oid); int op_flags = 0; if (flags & OPERATION_BALANCE_READS) op_flags |= CEPH_OSD_FLAG_BALANCE_READS; if (flags & OPERATION_LOCALIZE_READS) op_flags |= CEPH_OSD_FLAG_LOCALIZE_READS; if (flags & OPERATION_ORDER_READS_WRITES) op_flags |= CEPH_OSD_FLAG_RWORDERED; return io_ctx_impl->aio_operate_read(obj, (::ObjectOperation*)o->impl, c->pc, op_flags, pbl); } int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c, librados::ObjectReadOperation *o, int flags, bufferlist *pbl) { object_t obj(oid); return io_ctx_impl->aio_operate_read(obj, (::ObjectOperation*)o->impl, c->pc, translate_flags(flags), pbl); } void librados::IoCtx::snap_set_read(snap_t seq) { io_ctx_impl->set_snap_read(seq); } int librados::IoCtx::selfmanaged_snap_set_write_ctx(snap_t seq, vector& snaps) { vector snv; snv.resize(snaps.size()); for (unsigned i=0; iset_snap_write_context(seq, snv); } int librados::IoCtx::snap_create(const char *snapname) { return io_ctx_impl->snap_create(snapname); } int librados::IoCtx::snap_lookup(const char *name, snap_t *snapid) { return io_ctx_impl->snap_lookup(name, snapid); } int librados::IoCtx::snap_get_stamp(snap_t snapid, time_t *t) { return io_ctx_impl->snap_get_stamp(snapid, t); } int librados::IoCtx::snap_get_name(snap_t snapid, std::string *s) { return io_ctx_impl->snap_get_name(snapid, s); } int librados::IoCtx::snap_remove(const char *snapname) { return io_ctx_impl->snap_remove(snapname); } int librados::IoCtx::snap_list(std::vector *snaps) { return io_ctx_impl->snap_list(snaps); } int librados::IoCtx::snap_rollback(const std::string& oid, const char *snapname) { return io_ctx_impl->rollback(oid, snapname); } // Deprecated name kept for backward compatibility int librados::IoCtx::rollback(const std::string& oid, const char *snapname) { return snap_rollback(oid, snapname); } int librados::IoCtx::selfmanaged_snap_create(uint64_t *snapid) { return io_ctx_impl->selfmanaged_snap_create(snapid); } int librados::IoCtx::selfmanaged_snap_remove(uint64_t snapid) { return io_ctx_impl->selfmanaged_snap_remove(snapid); } int librados::IoCtx::selfmanaged_snap_rollback(const std::string& oid, uint64_t snapid) { return io_ctx_impl->selfmanaged_snap_rollback_object(oid, io_ctx_impl->snapc, snapid); } int librados::IoCtx::lock_exclusive(const std::string &oid, const std::string &name, const std::string &cookie, const std::string &description, struct timeval * duration, uint8_t flags) { utime_t dur = utime_t(); if (duration) dur.set_from_timeval(duration); return rados::cls::lock::lock(this, oid, name, LOCK_EXCLUSIVE, cookie, "", description, dur, flags); } int librados::IoCtx::lock_shared(const std::string &oid, const std::string &name, const std::string &cookie, const std::string &tag, const std::string &description, struct timeval * duration, uint8_t flags) { utime_t dur = utime_t(); if (duration) dur.set_from_timeval(duration); return rados::cls::lock::lock(this, oid, name, LOCK_SHARED, cookie, tag, description, dur, flags); } int librados::IoCtx::unlock(const std::string &oid, const std::string &name, const std::string &cookie) { return rados::cls::lock::unlock(this, oid, name, cookie); } int librados::IoCtx::break_lock(const std::string &oid, const std::string &name, const std::string &client, const std::string &cookie) { entity_name_t locker; if (!locker.parse(client)) return -EINVAL; return rados::cls::lock::break_lock(this, oid, name, cookie, locker); } int librados::IoCtx::list_lockers(const std::string &oid, const std::string &name, int *exclusive, std::string *tag, std::list *lockers) { std::list tmp_lockers; map rados_lockers; std::string tmp_tag; ClsLockType tmp_type; int r = rados::cls::lock::get_lock_info(this, oid, name, &rados_lockers, &tmp_type, &tmp_tag); if (r < 0) return r; map::iterator map_it; for (map_it = rados_lockers.begin(); map_it != rados_lockers.end(); ++map_it) { librados::locker_t locker; locker.client = stringify(map_it->first.locker); locker.cookie = map_it->first.cookie; locker.address = stringify(map_it->second.addr); tmp_lockers.push_back(locker); } if (lockers) *lockers = tmp_lockers; if (tag) *tag = tmp_tag; if (exclusive) { if (tmp_type == LOCK_EXCLUSIVE) *exclusive = 1; else *exclusive = 0; } return tmp_lockers.size(); } librados::ObjectIterator librados::IoCtx::objects_begin() { rados_list_ctx_t listh; rados_objects_list_open(io_ctx_impl, &listh); ObjectIterator iter((ObjListCtx*)listh); iter.get_next(); return iter; } librados::ObjectIterator librados::IoCtx::objects_begin(uint32_t pos) { rados_list_ctx_t listh; rados_objects_list_open(io_ctx_impl, &listh); ObjectIterator iter((ObjListCtx*)listh); iter.seek(pos); return iter; } const librados::ObjectIterator& librados::IoCtx::objects_end() const { return ObjectIterator::__EndObjectIterator; } int librados::IoCtx::hit_set_list(uint32_t hash, AioCompletion *c, std::list< std::pair > *pls) { return io_ctx_impl->hit_set_list(hash, c->pc, pls); } int librados::IoCtx::hit_set_get(uint32_t hash, AioCompletion *c, time_t stamp, bufferlist *pbl) { return io_ctx_impl->hit_set_get(hash, c->pc, stamp, pbl); } uint64_t librados::IoCtx::get_last_version() { return io_ctx_impl->last_version(); } int librados::IoCtx::aio_read(const std::string& oid, librados::AioCompletion *c, bufferlist *pbl, size_t len, uint64_t off) { return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off, io_ctx_impl->snap_seq); } int librados::IoCtx::aio_read(const std::string& oid, librados::AioCompletion *c, bufferlist *pbl, size_t len, uint64_t off, uint64_t snapid) { return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off, snapid); } int librados::IoCtx::aio_exec(const std::string& oid, librados::AioCompletion *c, const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl) { object_t obj(oid); return io_ctx_impl->aio_exec(obj, c->pc, cls, method, inbl, outbl); } int librados::IoCtx::aio_sparse_read(const std::string& oid, librados::AioCompletion *c, std::map *m, bufferlist *data_bl, size_t len, uint64_t off) { return io_ctx_impl->aio_sparse_read(oid, c->pc, m, data_bl, len, off, io_ctx_impl->snap_seq); } int librados::IoCtx::aio_sparse_read(const std::string& oid, librados::AioCompletion *c, std::map *m, bufferlist *data_bl, size_t len, uint64_t off, uint64_t snapid) { return io_ctx_impl->aio_sparse_read(oid, c->pc, m, data_bl, len, off, snapid); } int librados::IoCtx::aio_write(const std::string& oid, librados::AioCompletion *c, const bufferlist& bl, size_t len, uint64_t off) { return io_ctx_impl->aio_write(oid, c->pc, bl, len, off); } int librados::IoCtx::aio_append(const std::string& oid, librados::AioCompletion *c, const bufferlist& bl, size_t len) { return io_ctx_impl->aio_append(oid, c->pc, bl, len); } int librados::IoCtx::aio_write_full(const std::string& oid, librados::AioCompletion *c, const bufferlist& bl) { object_t obj(oid); return io_ctx_impl->aio_write_full(obj, c->pc, bl); } int librados::IoCtx::aio_remove(const std::string& oid, librados::AioCompletion *c) { return io_ctx_impl->aio_remove(oid, c->pc); } int librados::IoCtx::aio_flush_async(librados::AioCompletion *c) { io_ctx_impl->flush_aio_writes_async(c->pc); return 0; } int librados::IoCtx::aio_flush() { io_ctx_impl->flush_aio_writes(); return 0; } int librados::IoCtx::aio_stat(const std::string& oid, librados::AioCompletion *c, uint64_t *psize, time_t *pmtime) { object_t obj(oid); return io_ctx_impl->aio_stat(oid, c->pc, psize, pmtime); } int librados::IoCtx::watch(const string& oid, uint64_t ver, uint64_t *cookie, librados::WatchCtx *ctx) { object_t obj(oid); return io_ctx_impl->watch(obj, ver, cookie, ctx); } int librados::IoCtx::unwatch(const string& oid, uint64_t handle) { uint64_t cookie = handle; object_t obj(oid); return io_ctx_impl->unwatch(obj, cookie); } int librados::IoCtx::notify(const string& oid, uint64_t ver, bufferlist& bl) { object_t obj(oid); return io_ctx_impl->notify(obj, ver, bl); } int librados::IoCtx::list_watchers(const std::string& oid, std::list *out_watchers) { ObjectReadOperation op; int r; op.list_watchers(out_watchers, &r); bufferlist bl; int ret = operate(oid, &op, &bl); if (ret < 0) return ret; return r; } int librados::IoCtx::list_snaps(const std::string& oid, snap_set_t *out_snaps) { ObjectReadOperation op; int r; if (io_ctx_impl->snap_seq != CEPH_SNAPDIR) return -EINVAL; op.list_snaps(out_snaps, &r); bufferlist bl; int ret = operate(oid, &op, &bl); if (ret < 0) return ret; return r; } void librados::IoCtx::set_notify_timeout(uint32_t timeout) { io_ctx_impl->set_notify_timeout(timeout); } int librados::IoCtx::set_alloc_hint(const std::string& o, uint64_t expected_object_size, uint64_t expected_write_size) { object_t oid(o); return io_ctx_impl->set_alloc_hint(oid, expected_object_size, expected_write_size); } void librados::IoCtx::set_assert_version(uint64_t ver) { io_ctx_impl->set_assert_version(ver); } void librados::IoCtx::set_assert_src_version(const std::string& oid, uint64_t ver) { object_t obj(oid); io_ctx_impl->set_assert_src_version(obj, ver); } const std::string& librados::IoCtx::get_pool_name() const { return io_ctx_impl->pool_name; } void librados::IoCtx::locator_set_key(const string& key) { io_ctx_impl->oloc.key = key; } void librados::IoCtx::set_namespace(const string& nspace) { io_ctx_impl->oloc.nspace = nspace; } int64_t librados::IoCtx::get_id() { return io_ctx_impl->get_id(); } uint32_t librados::IoCtx::get_object_hash_position(const std::string& oid) { return io_ctx_impl->get_object_hash_position(oid); } uint32_t librados::IoCtx::get_object_pg_hash_position(const std::string& oid) { return io_ctx_impl->get_object_pg_hash_position(oid); } librados::config_t librados::IoCtx::cct() { return (config_t)io_ctx_impl->client->cct; } librados::IoCtx::IoCtx(IoCtxImpl *io_ctx_impl_) : io_ctx_impl(io_ctx_impl_) { } ///////////////////////////// Rados ////////////////////////////// void librados::Rados::version(int *major, int *minor, int *extra) { rados_version(major, minor, extra); } librados::Rados::Rados() : client(NULL) { } librados::Rados::Rados(IoCtx &ioctx) { client = ioctx.io_ctx_impl->client; assert(client != NULL); client->get(); } librados::Rados::~Rados() { shutdown(); } int librados::Rados::init(const char * const id) { return rados_create((rados_t *)&client, id); } int librados::Rados::init2(const char * const name, const char * const clustername, uint64_t flags) { return rados_create2((rados_t *)&client, clustername, name, flags); } int librados::Rados::init_with_context(config_t cct_) { return rados_create_with_context((rados_t *)&client, (rados_config_t)cct_); } int librados::Rados::connect() { return client->connect(); } librados::config_t librados::Rados::cct() { return (config_t)client->cct; } void librados::Rados::shutdown() { if (!client) return; if (client->put()) { client->shutdown(); delete client; client = NULL; } } uint64_t librados::Rados::get_instance_id() { return client->get_instance_id(); } int librados::Rados::conf_read_file(const char * const path) const { return rados_conf_read_file((rados_t)client, path); } int librados::Rados::conf_parse_argv(int argc, const char ** argv) const { return rados_conf_parse_argv((rados_t)client, argc, argv); } int librados::Rados::conf_parse_argv_remainder(int argc, const char ** argv, const char ** remargv) const { return rados_conf_parse_argv_remainder((rados_t)client, argc, argv, remargv); } int librados::Rados::conf_parse_env(const char *name) const { return rados_conf_parse_env((rados_t)client, name); } int librados::Rados::conf_set(const char *option, const char *value) { return rados_conf_set((rados_t)client, option, value); } int librados::Rados::conf_get(const char *option, std::string &val) { char *str = NULL; md_config_t *conf = client->cct->_conf; int ret = conf->get_val(option, &str, -1); if (ret) { free(str); return ret; } val = str; free(str); return 0; } int librados::Rados::pool_create(const char *name) { string str(name); return client->pool_create(str); } int librados::Rados::pool_create(const char *name, uint64_t auid) { string str(name); return client->pool_create(str, auid); } int librados::Rados::pool_create(const char *name, uint64_t auid, __u8 crush_rule) { string str(name); return client->pool_create(str, auid, crush_rule); } int librados::Rados::pool_create_async(const char *name, PoolAsyncCompletion *c) { string str(name); return client->pool_create_async(str, c->pc); } int librados::Rados::pool_create_async(const char *name, uint64_t auid, PoolAsyncCompletion *c) { string str(name); return client->pool_create_async(str, c->pc, auid); } int librados::Rados::pool_create_async(const char *name, uint64_t auid, __u8 crush_rule, PoolAsyncCompletion *c) { string str(name); return client->pool_create_async(str, c->pc, auid, crush_rule); } int librados::Rados::pool_delete(const char *name) { return client->pool_delete(name); } int librados::Rados::pool_delete_async(const char *name, PoolAsyncCompletion *c) { return client->pool_delete_async(name, c->pc); } int librados::Rados::pool_list(std::list& v) { return client->pool_list(v); } int64_t librados::Rados::pool_lookup(const char *name) { return client->lookup_pool(name); } int librados::Rados::pool_reverse_lookup(int64_t id, std::string *name) { return client->pool_get_name(id, name); } int librados::Rados::mon_command(string cmd, const bufferlist& inbl, bufferlist *outbl, string *outs) { vector cmdvec; cmdvec.push_back(cmd); return client->mon_command(cmdvec, inbl, outbl, outs); } int librados::Rados::ioctx_create(const char *name, IoCtx &io) { rados_ioctx_t p; int ret = rados_ioctx_create((rados_t)client, name, &p); if (ret) return ret; io.io_ctx_impl = (IoCtxImpl*)p; return 0; } void librados::Rados::test_blacklist_self(bool set) { client->blacklist_self(set); } int librados::Rados::get_pool_stats(std::list& v, std::map& result) { string category; return get_pool_stats(v, category, result); } int librados::Rados::get_pool_stats(std::list& v, string& category, std::map& result) { map rawresult; int r = client->get_pool_stats(v, rawresult); if (r < 0) return r; for (map::iterator p = rawresult.begin(); p != rawresult.end(); ++p) { stats_map& c = result[p->first]; string cat; vector cats; if (!category.size()) { cats.push_back(cat); map::iterator iter; for (iter = p->second.stats.cat_sum.begin(); iter != p->second.stats.cat_sum.end(); ++iter) { cats.push_back(iter->first); } } else { cats.push_back(category); } vector::iterator cat_iter; for (cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter) { string& cur_category = *cat_iter; object_stat_sum_t *sum; if (!cur_category.size()) { sum = &p->second.stats.sum; } else { map::iterator iter = p->second.stats.cat_sum.find(cur_category); if (iter == p->second.stats.cat_sum.end()) continue; sum = &iter->second; } pool_stat_t& pv = c[cur_category]; pv.num_kb = SHIFT_ROUND_UP(sum->num_bytes, 10); pv.num_bytes = sum->num_bytes; pv.num_objects = sum->num_objects; pv.num_object_clones = sum->num_object_clones; pv.num_object_copies = sum->num_object_copies; pv.num_objects_missing_on_primary = sum->num_objects_missing_on_primary; pv.num_objects_unfound = sum->num_objects_unfound; pv.num_objects_degraded = sum->num_objects_degraded; pv.num_rd = sum->num_rd; pv.num_rd_kb = sum->num_rd_kb; pv.num_wr = sum->num_wr; pv.num_wr_kb = sum->num_wr_kb; } } return r; } int librados::Rados::cluster_stat(cluster_stat_t& result) { ceph_statfs stats; int r = client->get_fs_stats(stats); result.kb = stats.kb; result.kb_used = stats.kb_used; result.kb_avail = stats.kb_avail; result.num_objects = stats.num_objects; return r; } int librados::Rados::cluster_fsid(string *fsid) { return client->get_fsid(fsid); } int librados::Rados::wait_for_latest_osdmap() { return client->wait_for_latest_osdmap(); } librados::PoolAsyncCompletion *librados::Rados::pool_async_create_completion() { PoolAsyncCompletionImpl *c = new PoolAsyncCompletionImpl; return new PoolAsyncCompletion(c); } librados::AioCompletion *librados::Rados::aio_create_completion() { AioCompletionImpl *c = new AioCompletionImpl; return new AioCompletion(c); } librados::AioCompletion *librados::Rados::aio_create_completion(void *cb_arg, callback_t cb_complete, callback_t cb_safe) { AioCompletionImpl *c; int r = rados_aio_create_completion(cb_arg, cb_complete, cb_safe, (void**)&c); assert(r == 0); return new AioCompletion(c); } librados::ObjectOperation::ObjectOperation() { impl = (ObjectOperationImpl *)new ::ObjectOperation; } librados::ObjectOperation::~ObjectOperation() { ::ObjectOperation *o = (::ObjectOperation *)impl; delete o; } ///////////////////////////// C API ////////////////////////////// static int rados_create_common(rados_t *pcluster, const char * const clustername, CephInitParameters *iparams) { // missing things compared to global_init: // g_ceph_context, g_conf, g_lockdep, signal handlers CephContext *cct = common_preinit(*iparams, CODE_ENVIRONMENT_LIBRARY, 0); if (clustername) cct->_conf->cluster = clustername; cct->_conf->parse_env(); // environment variables override cct->_conf->apply_changes(NULL); librados::RadosClient *radosp = new librados::RadosClient(cct); *pcluster = (void *)radosp; cct->put(); return 0; } extern "C" int rados_create(rados_t *pcluster, const char * const id) { CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT); if (id) { iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id); } return rados_create_common(pcluster, "ceph", &iparams); } // as above, but // 1) don't assume 'client.'; name is a full type.id namestr // 2) allow setting clustername // 3) flags is for future expansion (maybe some of the global_init() // behavior is appropriate for some consumers of librados, for instance) extern "C" int rados_create2(rados_t *pcluster, const char *const clustername, const char * const name, uint64_t flags) { // client is assumed, but from_str will override CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT); if (!name || !iparams.name.from_str(name)) return -EINVAL; return rados_create_common(pcluster, clustername, &iparams); } /* This function is intended for use by Ceph daemons. These daemons have * already called global_init and want to use that particular configuration for * their cluster. */ extern "C" int rados_create_with_context(rados_t *pcluster, rados_config_t cct_) { CephContext *cct = (CephContext *)cct_; librados::RadosClient *radosp = new librados::RadosClient(cct); *pcluster = (void *)radosp; return 0; } extern "C" rados_config_t rados_cct(rados_t cluster) { librados::RadosClient *client = (librados::RadosClient *)cluster; return (rados_config_t)client->cct; } extern "C" int rados_connect(rados_t cluster) { librados::RadosClient *client = (librados::RadosClient *)cluster; return client->connect(); } extern "C" void rados_shutdown(rados_t cluster) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; radosp->shutdown(); delete radosp; } extern "C" uint64_t rados_get_instance_id(rados_t cluster) { librados::RadosClient *client = (librados::RadosClient *)cluster; return client->get_instance_id(); } extern "C" void rados_version(int *major, int *minor, int *extra) { if (major) *major = LIBRADOS_VER_MAJOR; if (minor) *minor = LIBRADOS_VER_MINOR; if (extra) *extra = LIBRADOS_VER_EXTRA; } // -- config -- extern "C" int rados_conf_read_file(rados_t cluster, const char *path_list) { librados::RadosClient *client = (librados::RadosClient *)cluster; md_config_t *conf = client->cct->_conf; std::deque parse_errors; int ret = conf->parse_config_files(path_list, &parse_errors, NULL, 0); if (ret) return ret; conf->parse_env(); // environment variables override conf->apply_changes(NULL); complain_about_parse_errors(client->cct, &parse_errors); return 0; } extern "C" int rados_conf_parse_argv(rados_t cluster, int argc, const char **argv) { librados::RadosClient *client = (librados::RadosClient *)cluster; md_config_t *conf = client->cct->_conf; vector args; argv_to_vec(argc, argv, args); int ret = conf->parse_argv(args); if (ret) return ret; conf->apply_changes(NULL); return 0; } // like above, but return the remainder of argv to contain remaining // unparsed args. Must be allocated to at least argc by caller. // remargv will contain n <= argc pointers to original argv[], the end // of which may be NULL extern "C" int rados_conf_parse_argv_remainder(rados_t cluster, int argc, const char **argv, const char **remargv) { librados::RadosClient *client = (librados::RadosClient *)cluster; md_config_t *conf = client->cct->_conf; vector args; for (int i=0; iparse_argv(args); if (ret) return ret; conf->apply_changes(NULL); assert(args.size() <= (unsigned int)argc); unsigned int i; for (i = 0; i < (unsigned int)argc; ++i) { if (i < args.size()) remargv[i] = args[i]; else remargv[i] = (const char *)NULL; } return 0; } extern "C" int rados_conf_parse_env(rados_t cluster, const char *env) { librados::RadosClient *client = (librados::RadosClient *)cluster; md_config_t *conf = client->cct->_conf; vector args; env_to_vec(args, env); int ret = conf->parse_argv(args); if (ret) return ret; conf->apply_changes(NULL); return 0; } extern "C" int rados_conf_set(rados_t cluster, const char *option, const char *value) { librados::RadosClient *client = (librados::RadosClient *)cluster; md_config_t *conf = client->cct->_conf; int ret = conf->set_val(option, value); if (ret) return ret; conf->apply_changes(NULL); return 0; } /* cluster info */ extern "C" int rados_cluster_stat(rados_t cluster, rados_cluster_stat_t *result) { librados::RadosClient *client = (librados::RadosClient *)cluster; ceph_statfs stats; int r = client->get_fs_stats(stats); result->kb = stats.kb; result->kb_used = stats.kb_used; result->kb_avail = stats.kb_avail; result->num_objects = stats.num_objects; return r; } extern "C" int rados_conf_get(rados_t cluster, const char *option, char *buf, size_t len) { char *tmp = buf; librados::RadosClient *client = (librados::RadosClient *)cluster; md_config_t *conf = client->cct->_conf; return conf->get_val(option, &tmp, len); } extern "C" int64_t rados_pool_lookup(rados_t cluster, const char *name) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; return radosp->lookup_pool(name); } extern "C" int rados_pool_reverse_lookup(rados_t cluster, int64_t id, char *buf, size_t maxlen) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; std::string name; int r = radosp->pool_get_name(id, &name); if (r < 0) return r; if (name.length() >= maxlen) return -ERANGE; strcpy(buf, name.c_str()); return name.length(); } extern "C" int rados_cluster_fsid(rados_t cluster, char *buf, size_t maxlen) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; std::string fsid; radosp->get_fsid(&fsid); if (fsid.length() >= maxlen) return -ERANGE; strcpy(buf, fsid.c_str()); return fsid.length(); } extern "C" int rados_wait_for_latest_osdmap(rados_t cluster) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; return radosp->wait_for_latest_osdmap(); } extern "C" int rados_pool_list(rados_t cluster, char *buf, size_t len) { librados::RadosClient *client = (librados::RadosClient *)cluster; std::list pools; int r = client->pool_list(pools); if (r < 0) return r; if (len > 0 && !buf) return -EINVAL; char *b = buf; if (b) memset(b, 0, len); int needed = 0; std::list::const_iterator i = pools.begin(); std::list::const_iterator p_end = pools.end(); for (; i != p_end; ++i) { int rl = i->length() + 1; if (len < (unsigned)rl) break; strncat(b, i->c_str(), rl); needed += rl; len -= rl; b += rl; } for (; i != p_end; ++i) { int rl = i->length() + 1; needed += rl; } return needed + 1; } static void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen) { if (outbuf) { if (outbl.length() > 0) { *outbuf = (char *)malloc(outbl.length()); memcpy(*outbuf, outbl.c_str(), outbl.length()); } else { *outbuf = NULL; } } if (outbuflen) *outbuflen = outbl.length(); } static void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen) { if (outbuf) { if (outbl.length() > 0) { *outbuf = (char *)malloc(outbl.length()); memcpy(*outbuf, outbl.c_str(), outbl.length()); } else { *outbuf = NULL; } } if (outbuflen) *outbuflen = outbl.length(); } extern "C" int rados_ping_monitor(rados_t cluster, const char *mon_id, char **outstr, size_t *outstrlen) { librados::RadosClient *client = (librados::RadosClient *)cluster; string str; if (!mon_id) return -EINVAL; int ret = client->ping_monitor(mon_id, &str); if (ret == 0 && !str.empty() && outstr && outstrlen) { do_out_buffer(str, outstr, outstrlen); } return ret; } extern "C" int rados_mon_command(rados_t cluster, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen) { librados::RadosClient *client = (librados::RadosClient *)cluster; bufferlist inbl; bufferlist outbl; string outstring; vector cmdvec; for (size_t i = 0; i < cmdlen; i++) cmdvec.push_back(cmd[i]); inbl.append(inbuf, inbuflen); int ret = client->mon_command(cmdvec, inbl, &outbl, &outstring); do_out_buffer(outbl, outbuf, outbuflen); do_out_buffer(outstring, outs, outslen); return ret; } extern "C" int rados_mon_command_target(rados_t cluster, const char *name, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen) { librados::RadosClient *client = (librados::RadosClient *)cluster; bufferlist inbl; bufferlist outbl; string outstring; vector cmdvec; // is this a numeric id? char *endptr; errno = 0; long rank = strtol(name, &endptr, 10); if ((errno == ERANGE && (rank == LONG_MAX || rank == LONG_MIN)) || (errno != 0 && rank == 0) || endptr == name || // no digits *endptr != '\0') { // extra characters rank = -1; } for (size_t i = 0; i < cmdlen; i++) cmdvec.push_back(cmd[i]); inbl.append(inbuf, inbuflen); int ret; if (rank >= 0) ret = client->mon_command(rank, cmdvec, inbl, &outbl, &outstring); else ret = client->mon_command(name, cmdvec, inbl, &outbl, &outstring); do_out_buffer(outbl, outbuf, outbuflen); do_out_buffer(outstring, outs, outslen); return ret; } extern "C" int rados_osd_command(rados_t cluster, int osdid, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen) { librados::RadosClient *client = (librados::RadosClient *)cluster; bufferlist inbl; bufferlist outbl; string outstring; vector cmdvec; for (size_t i = 0; i < cmdlen; i++) cmdvec.push_back(cmd[i]); inbl.append(inbuf, inbuflen); int ret = client->osd_command(osdid, cmdvec, inbl, &outbl, &outstring); do_out_buffer(outbl, outbuf, outbuflen); do_out_buffer(outstring, outs, outslen); return ret; } extern "C" int rados_pg_command(rados_t cluster, const char *pgstr, const char **cmd, size_t cmdlen, const char *inbuf, size_t inbuflen, char **outbuf, size_t *outbuflen, char **outs, size_t *outslen) { librados::RadosClient *client = (librados::RadosClient *)cluster; bufferlist inbl; bufferlist outbl; string outstring; pg_t pgid; vector cmdvec; for (size_t i = 0; i < cmdlen; i++) cmdvec.push_back(cmd[i]); inbl.append(inbuf, inbuflen); if (!pgid.parse(pgstr)) return -EINVAL; int ret = client->pg_command(pgid, cmdvec, inbl, &outbl, &outstring); do_out_buffer(outbl, outbuf, outbuflen); do_out_buffer(outstring, outs, outslen); return ret; } extern "C" void rados_buffer_free(char *buf) { if (buf) free(buf); } extern "C" int rados_monitor_log(rados_t cluster, const char *level, rados_log_callback_t cb, void *arg) { librados::RadosClient *client = (librados::RadosClient *)cluster; return client->monitor_log(level, cb, arg); } extern "C" int rados_ioctx_create(rados_t cluster, const char *name, rados_ioctx_t *io) { librados::RadosClient *client = (librados::RadosClient *)cluster; librados::IoCtxImpl *ctx; int r = client->create_ioctx(name, &ctx); if (r < 0) return r; *io = ctx; ctx->get(); return 0; } extern "C" void rados_ioctx_destroy(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; ctx->put(); } extern "C" int rados_ioctx_pool_stat(rados_ioctx_t io, struct rados_pool_stat_t *stats) { librados::IoCtxImpl *io_ctx_impl = (librados::IoCtxImpl *)io; list ls; ls.push_back(io_ctx_impl->pool_name); map rawresult; int err = io_ctx_impl->client->get_pool_stats(ls, rawresult); if (err) return err; ::pool_stat_t& r = rawresult[io_ctx_impl->pool_name]; stats->num_kb = SHIFT_ROUND_UP(r.stats.sum.num_bytes, 10); stats->num_bytes = r.stats.sum.num_bytes; stats->num_objects = r.stats.sum.num_objects; stats->num_object_clones = r.stats.sum.num_object_clones; stats->num_object_copies = r.stats.sum.num_object_copies; stats->num_objects_missing_on_primary = r.stats.sum.num_objects_missing_on_primary; stats->num_objects_unfound = r.stats.sum.num_objects_unfound; stats->num_objects_degraded = r.stats.sum.num_objects_degraded; stats->num_rd = r.stats.sum.num_rd; stats->num_rd_kb = r.stats.sum.num_rd_kb; stats->num_wr = r.stats.sum.num_wr; stats->num_wr_kb = r.stats.sum.num_wr_kb; return 0; } extern "C" rados_config_t rados_ioctx_cct(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return (rados_config_t)ctx->client->cct; } extern "C" void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t seq) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; ctx->set_snap_read((snapid_t)seq); } extern "C" int rados_ioctx_selfmanaged_snap_set_write_ctx(rados_ioctx_t io, rados_snap_t seq, rados_snap_t *snaps, int num_snaps) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; vector snv; snv.resize(num_snaps); for (int i=0; iset_snap_write_context((snapid_t)seq, snv); } extern "C" int rados_write(rados_ioctx_t io, const char *o, const char *buf, size_t len, uint64_t off) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->write(oid, bl, len, off); } extern "C" int rados_append(rados_ioctx_t io, const char *o, const char *buf, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->append(oid, bl, len); } extern "C" int rados_write_full(rados_ioctx_t io, const char *o, const char *buf, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->write_full(oid, bl); } extern "C" int rados_clone_range(rados_ioctx_t io, const char *dst, uint64_t dst_off, const char *src, uint64_t src_off, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t dst_oid(dst), src_oid(src); return ctx->clone_range(dst_oid, dst_off, src_oid, src_off, len); } extern "C" int rados_trunc(rados_ioctx_t io, const char *o, uint64_t size) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->trunc(oid, size); } extern "C" int rados_remove(rados_ioctx_t io, const char *o) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->remove(oid); } extern "C" int rados_read(rados_ioctx_t io, const char *o, char *buf, size_t len, uint64_t off) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; int ret; object_t oid(o); bufferlist bl; bufferptr bp = buffer::create_static(len, buf); bl.push_back(bp); ret = ctx->read(oid, bl, len, off); if (ret >= 0) { if (bl.length() > len) return -ERANGE; if (bl.c_str() != buf) bl.copy(0, bl.length(), buf); ret = bl.length(); // hrm :/ } return ret; } extern "C" uint64_t rados_get_last_version(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->last_version(); } extern "C" int rados_pool_create(rados_t cluster, const char *name) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; string sname(name); return radosp->pool_create(sname); } extern "C" int rados_pool_create_with_auid(rados_t cluster, const char *name, uint64_t auid) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; string sname(name); return radosp->pool_create(sname, auid); } extern "C" int rados_pool_create_with_crush_rule(rados_t cluster, const char *name, __u8 crush_rule_num) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; string sname(name); return radosp->pool_create(sname, 0, crush_rule_num); } extern "C" int rados_pool_create_with_all(rados_t cluster, const char *name, uint64_t auid, __u8 crush_rule_num) { librados::RadosClient *radosp = (librados::RadosClient *)cluster; string sname(name); return radosp->pool_create(sname, auid, crush_rule_num); } extern "C" int rados_pool_delete(rados_t cluster, const char *pool_name) { librados::RadosClient *client = (librados::RadosClient *)cluster; return client->pool_delete(pool_name); } extern "C" int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->pool_change_auid(auid); } extern "C" int rados_ioctx_pool_get_auid(rados_ioctx_t io, uint64_t *auid) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->client->pool_get_auid(ctx->get_id(), (unsigned long long *)auid); } extern "C" int rados_ioctx_pool_requires_alignment(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->client->pool_requires_alignment(ctx->get_id()); } extern "C" uint64_t rados_ioctx_pool_required_alignment(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->client->pool_required_alignment(ctx->get_id()); } extern "C" void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; if (key) ctx->oloc.key = key; else ctx->oloc.key = ""; } extern "C" void rados_ioctx_set_namespace(rados_ioctx_t io, const char *nspace) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; if (nspace) ctx->oloc.nspace = nspace; else ctx->oloc.nspace = ""; } extern "C" rados_t rados_ioctx_get_cluster(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return (rados_t)ctx->client; } extern "C" int64_t rados_ioctx_get_id(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->get_id(); } extern "C" int rados_ioctx_get_pool_name(rados_ioctx_t io, char *s, unsigned maxlen) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; if (ctx->pool_name.length() >= maxlen) return -ERANGE; strcpy(s, ctx->pool_name.c_str()); return ctx->pool_name.length(); } // snaps extern "C" int rados_ioctx_snap_create(rados_ioctx_t io, const char *snapname) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->snap_create(snapname); } extern "C" int rados_ioctx_snap_remove(rados_ioctx_t io, const char *snapname) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->snap_remove(snapname); } extern "C" int rados_ioctx_snap_rollback(rados_ioctx_t io, const char *oid, const char *snapname) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->rollback(oid, snapname); } // Deprecated name kept for backward compatibility extern "C" int rados_rollback(rados_ioctx_t io, const char *oid, const char *snapname) { return rados_ioctx_snap_rollback(io, oid, snapname); } extern "C" int rados_ioctx_selfmanaged_snap_create(rados_ioctx_t io, uint64_t *snapid) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->selfmanaged_snap_create(snapid); } extern "C" int rados_ioctx_selfmanaged_snap_remove(rados_ioctx_t io, uint64_t snapid) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->selfmanaged_snap_remove(snapid); } extern "C" int rados_ioctx_selfmanaged_snap_rollback(rados_ioctx_t io, const char *oid, uint64_t snapid) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->selfmanaged_snap_rollback_object(oid, ctx->snapc, snapid); } extern "C" int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t *snaps, int maxlen) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; vector snapvec; int r = ctx->snap_list(&snapvec); if (r < 0) return r; if ((int)snapvec.size() <= maxlen) { for (unsigned i=0; isnap_lookup(name, (uint64_t *)id); } extern "C" int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id, char *name, int maxlen) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; std::string sname; int r = ctx->snap_get_name(id, &sname); if (r < 0) return r; if ((int)sname.length() >= maxlen) return -ERANGE; strncpy(name, sname.c_str(), maxlen); return 0; } extern "C" int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t *t) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->snap_get_stamp(id, t); } extern "C" int rados_getxattr(rados_ioctx_t io, const char *o, const char *name, char *buf, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; int ret; object_t oid(o); bufferlist bl; ret = ctx->getxattr(oid, name, bl); if (ret >= 0) { if (bl.length() > len) return -ERANGE; bl.copy(0, bl.length(), buf); ret = bl.length(); } return ret; } class RadosXattrsIter { public: RadosXattrsIter() : val(NULL) { i = attrset.end(); } ~RadosXattrsIter() { free(val); val = NULL; } std::map attrset; std::map::iterator i; char *val; }; extern "C" int rados_getxattrs(rados_ioctx_t io, const char *oid, rados_xattrs_iter_t *iter) { RadosXattrsIter *it = new RadosXattrsIter(); if (!it) return -ENOMEM; librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t obj(oid); int ret = ctx->getxattrs(obj, it->attrset); if (ret) { delete it; return ret; } it->i = it->attrset.begin(); RadosXattrsIter **iret = (RadosXattrsIter**)iter; *iret = it; *iter = it; return 0; } extern "C" int rados_getxattrs_next(rados_xattrs_iter_t iter, const char **name, const char **val, size_t *len) { RadosXattrsIter *it = static_cast(iter); if (it->i == it->attrset.end()) { *name = NULL; *val = NULL; *len = 0; return 0; } free(it->val); const std::string &s(it->i->first); *name = s.c_str(); bufferlist &bl(it->i->second); size_t bl_len = bl.length(); it->val = (char*)malloc(bl_len); if (!it->val) return -ENOMEM; memcpy(it->val, bl.c_str(), bl_len); *val = it->val; *len = bl_len; ++it->i; return 0; } extern "C" void rados_getxattrs_end(rados_xattrs_iter_t iter) { RadosXattrsIter *it = static_cast(iter); delete it; } extern "C" int rados_setxattr(rados_ioctx_t io, const char *o, const char *name, const char *buf, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->setxattr(oid, name, bl); } extern "C" int rados_rmxattr(rados_ioctx_t io, const char *o, const char *name) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->rmxattr(oid, name); } extern "C" int rados_stat(rados_ioctx_t io, const char *o, uint64_t *psize, time_t *pmtime) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->stat(oid, psize, pmtime); } extern "C" int rados_tmap_update(rados_ioctx_t io, const char *o, const char *cmdbuf, size_t cmdbuflen) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist cmdbl; cmdbl.append(cmdbuf, cmdbuflen); return ctx->tmap_update(oid, cmdbl); } extern "C" int rados_tmap_put(rados_ioctx_t io, const char *o, const char *buf, size_t buflen) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, buflen); return ctx->tmap_put(oid, bl); } extern "C" int rados_tmap_get(rados_ioctx_t io, const char *o, char *buf, size_t buflen) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; int r = ctx->tmap_get(oid, bl); if (r < 0) return r; if (bl.length() > buflen) return -ERANGE; bl.copy(0, bl.length(), buf); return bl.length(); } extern "C" int rados_tmap_to_omap(rados_ioctx_t io, const char *o, bool nullok) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->tmap_to_omap(oid, nullok); } extern "C" int rados_exec(rados_ioctx_t io, const char *o, const char *cls, const char *method, const char *inbuf, size_t in_len, char *buf, size_t out_len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist inbl, outbl; int ret; inbl.append(inbuf, in_len); ret = ctx->exec(oid, cls, method, inbl, outbl); if (ret >= 0) { if (outbl.length()) { if (outbl.length() > out_len) return -ERANGE; outbl.copy(0, outbl.length(), buf); ret = outbl.length(); // hrm :/ } } return ret; } /* list objects */ extern "C" int rados_objects_list_open(rados_ioctx_t io, rados_list_ctx_t *listh) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; Objecter::ListContext *h = new Objecter::ListContext; h->pool_id = ctx->poolid; h->pool_snap_seq = ctx->snap_seq; h->nspace = ctx->oloc.nspace; *listh = (void *)new librados::ObjListCtx(ctx, h); return 0; } extern "C" void rados_objects_list_close(rados_list_ctx_t h) { librados::ObjListCtx *lh = (librados::ObjListCtx *)h; delete lh; } extern "C" uint32_t rados_objects_list_seek(rados_list_ctx_t listctx, uint32_t pos) { librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx; uint32_t r = lh->ctx->list_seek(lh->lc, pos); return r; } extern "C" uint32_t rados_objects_list_get_pg_hash_position( rados_list_ctx_t listctx) { librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx; return lh->lc->get_pg_hash_position(); } extern "C" int rados_objects_list_next(rados_list_ctx_t listctx, const char **entry, const char **key) { librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx; Objecter::ListContext *h = lh->lc; // if the list is non-empty, this method has been called before if (!h->list.empty()) // so let's kill the previously-returned object h->list.pop_front(); if (h->list.empty()) { int ret = lh->ctx->list(lh->lc, RADOS_LIST_MAX_ENTRIES); if (ret < 0) return ret; if (h->list.empty()) return -ENOENT; } *entry = h->list.front().first.name.c_str(); if (key) { if (h->list.front().second.size()) *key = h->list.front().second.c_str(); else *key = NULL; } return 0; } // ------------------------- // aio extern "C" int rados_aio_create_completion(void *cb_arg, rados_callback_t cb_complete, rados_callback_t cb_safe, rados_completion_t *pc) { librados::AioCompletionImpl *c = new librados::AioCompletionImpl; if (cb_complete) c->set_complete_callback(cb_arg, cb_complete); if (cb_safe) c->set_safe_callback(cb_arg, cb_safe); *pc = c; return 0; } extern "C" int rados_aio_wait_for_complete(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->wait_for_complete(); } extern "C" int rados_aio_wait_for_safe(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->wait_for_safe(); } extern "C" int rados_aio_is_complete(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->is_complete(); } extern "C" int rados_aio_is_safe(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->is_safe(); } extern "C" int rados_aio_wait_for_complete_and_cb(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->wait_for_complete_and_cb(); } extern "C" int rados_aio_wait_for_safe_and_cb(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->wait_for_safe_and_cb(); } extern "C" int rados_aio_is_complete_and_cb(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->is_complete_and_cb(); } extern "C" int rados_aio_is_safe_and_cb(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->is_safe_and_cb(); } extern "C" int rados_aio_get_return_value(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->get_return_value(); } extern "C" uint64_t rados_aio_get_version(rados_completion_t c) { return ((librados::AioCompletionImpl*)c)->get_version(); } extern "C" void rados_aio_release(rados_completion_t c) { ((librados::AioCompletionImpl*)c)->put(); } extern "C" int rados_aio_read(rados_ioctx_t io, const char *o, rados_completion_t completion, char *buf, size_t len, uint64_t off) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->aio_read(oid, (librados::AioCompletionImpl*)completion, buf, len, off, ctx->snap_seq); } extern "C" int rados_aio_write(rados_ioctx_t io, const char *o, rados_completion_t completion, const char *buf, size_t len, uint64_t off) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->aio_write(oid, (librados::AioCompletionImpl*)completion, bl, len, off); } extern "C" int rados_aio_append(rados_ioctx_t io, const char *o, rados_completion_t completion, const char *buf, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->aio_append(oid, (librados::AioCompletionImpl*)completion, bl, len); } extern "C" int rados_aio_write_full(rados_ioctx_t io, const char *o, rados_completion_t completion, const char *buf, size_t len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; bl.append(buf, len); return ctx->aio_write_full(oid, (librados::AioCompletionImpl*)completion, bl); } extern "C" int rados_aio_remove(rados_ioctx_t io, const char *o, rados_completion_t completion) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->aio_remove(oid, (librados::AioCompletionImpl*)completion); } extern "C" int rados_aio_flush_async(rados_ioctx_t io, rados_completion_t completion) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; ctx->flush_aio_writes_async((librados::AioCompletionImpl*)completion); return 0; } extern "C" int rados_aio_flush(rados_ioctx_t io) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; ctx->flush_aio_writes(); return 0; } extern "C" int rados_aio_stat(rados_ioctx_t io, const char *o, rados_completion_t completion, uint64_t *psize, time_t *pmtime) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->aio_stat(oid, (librados::AioCompletionImpl*)completion, psize, pmtime); } struct C_WatchCB : public librados::WatchCtx { rados_watchcb_t wcb; void *arg; C_WatchCB(rados_watchcb_t _wcb, void *_arg) : wcb(_wcb), arg(_arg) {} void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { wcb(opcode, ver, arg); } }; int rados_watch(rados_ioctx_t io, const char *o, uint64_t ver, uint64_t *handle, rados_watchcb_t watchcb, void *arg) { uint64_t *cookie = handle; librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); C_WatchCB *wc = new C_WatchCB(watchcb, arg); return ctx->watch(oid, ver, cookie, wc); } int rados_unwatch(rados_ioctx_t io, const char *o, uint64_t handle) { uint64_t cookie = handle; librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->unwatch(oid, cookie); } int rados_notify(rados_ioctx_t io, const char *o, uint64_t ver, const char *buf, int buf_len) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); bufferlist bl; if (buf) { bufferptr p = buffer::create(buf_len); memcpy(p.c_str(), buf, buf_len); bl.push_back(p); } return ctx->notify(oid, ver, bl); } extern "C" int rados_set_alloc_hint(rados_ioctx_t io, const char *o, uint64_t expected_object_size, uint64_t expected_write_size) { librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; object_t oid(o); return ctx->set_alloc_hint(oid, expected_object_size, expected_write_size); } extern "C" int rados_lock_exclusive(rados_ioctx_t io, const char * o, const char * name, const char * cookie, const char * desc, struct timeval * duration, uint8_t flags) { librados::IoCtx ctx; librados::IoCtx::from_rados_ioctx_t(io, ctx); return ctx.lock_exclusive(o, name, cookie, desc, duration, flags); } extern "C" int rados_lock_shared(rados_ioctx_t io, const char * o, const char * name, const char * cookie, const char * tag, const char * desc, struct timeval * duration, uint8_t flags) { librados::IoCtx ctx; librados::IoCtx::from_rados_ioctx_t(io, ctx); return ctx.lock_shared(o, name, cookie, tag, desc, duration, flags); } extern "C" int rados_unlock(rados_ioctx_t io, const char *o, const char *name, const char *cookie) { librados::IoCtx ctx; librados::IoCtx::from_rados_ioctx_t(io, ctx); return ctx.unlock(o, name, cookie); } extern "C" ssize_t rados_list_lockers(rados_ioctx_t io, const char *o, const char *name, int *exclusive, char *tag, size_t *tag_len, char *clients, size_t *clients_len, char *cookies, size_t *cookies_len, char *addrs, size_t *addrs_len) { librados::IoCtx ctx; librados::IoCtx::from_rados_ioctx_t(io, ctx); std::string name_str = name; std::string oid = o; std::string tag_str; int tmp_exclusive; std::list lockers; int r = ctx.list_lockers(oid, name_str, &tmp_exclusive, &tag_str, &lockers); if (r < 0) return r; size_t clients_total = 0; size_t cookies_total = 0; size_t addrs_total = 0; list::const_iterator it; for (it = lockers.begin(); it != lockers.end(); ++it) { clients_total += it->client.length() + 1; cookies_total += it->cookie.length() + 1; addrs_total += it->address.length() + 1; } bool too_short = ((clients_total > *clients_len) || (cookies_total > *cookies_len) || (addrs_total > *addrs_len) || (tag_str.length() + 1 > *tag_len)); *clients_len = clients_total; *cookies_len = cookies_total; *addrs_len = addrs_total; *tag_len = tag_str.length() + 1; if (too_short) return -ERANGE; strcpy(tag, tag_str.c_str()); char *clients_p = clients; char *cookies_p = cookies; char *addrs_p = addrs; for (it = lockers.begin(); it != lockers.end(); ++it) { strcpy(clients_p, it->client.c_str()); clients_p += it->client.length() + 1; strcpy(cookies_p, it->cookie.c_str()); cookies_p += it->cookie.length() + 1; strcpy(addrs_p, it->address.c_str()); addrs_p += it->address.length() + 1; } if (tmp_exclusive) *exclusive = 1; else *exclusive = 0; return lockers.size(); } extern "C" int rados_break_lock(rados_ioctx_t io, const char *o, const char *name, const char *client, const char *cookie) { librados::IoCtx ctx; librados::IoCtx::from_rados_ioctx_t(io, ctx); return ctx.break_lock(o, name, client, cookie); } extern "C" rados_write_op_t rados_create_write_op() { return new (std::nothrow)::ObjectOperation; } extern "C" void rados_release_write_op(rados_write_op_t write_op) { delete (::ObjectOperation*)write_op; } extern "C" void rados_write_op_set_flags(rados_write_op_t write_op, int flags) { set_op_flags((::ObjectOperation *)write_op, flags); } extern "C" void rados_write_op_assert_exists(rados_write_op_t write_op) { ((::ObjectOperation *)write_op)->stat(NULL, (utime_t *)NULL, NULL); } extern "C" void rados_write_op_cmpxattr(rados_write_op_t write_op, const char *name, uint8_t comparison_operator, const char *value, size_t value_len) { bufferlist bl; bl.append(value, value_len); ((::ObjectOperation *)write_op)->cmpxattr(name, comparison_operator, CEPH_OSD_CMPXATTR_MODE_STRING, bl); } static void rados_c_omap_cmp(ObjectOperation *op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval) { bufferlist bl; bl.append(val, val_len); std::map > assertions; assertions[key] = std::make_pair(bl, comparison_operator); op->omap_cmp(assertions, prval); } extern "C" void rados_write_op_omap_cmp(rados_write_op_t write_op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval) { rados_c_omap_cmp((::ObjectOperation *)write_op, key, comparison_operator, val, val_len, prval); } extern "C" void rados_write_op_setxattr(rados_write_op_t write_op, const char *name, const char *value, size_t value_len) { bufferlist bl; bl.append(value, value_len); ((::ObjectOperation *)write_op)->setxattr(name, bl); } extern "C" void rados_write_op_rmxattr(rados_write_op_t write_op, const char *name) { bufferlist bl; ((::ObjectOperation *)write_op)->rmxattr(name); } extern "C" void rados_write_op_create(rados_write_op_t write_op, int exclusive, const char* category) { ::ObjectOperation *oo = (::ObjectOperation *) write_op; if(category) { oo->create(exclusive, category); } else { oo->create(!!exclusive); } } extern "C" void rados_write_op_write(rados_write_op_t write_op, const char *buffer, size_t len, uint64_t offset) { bufferlist bl; bl.append(buffer,len); ((::ObjectOperation *)write_op)->write(offset, bl); } extern "C" void rados_write_op_write_full(rados_write_op_t write_op, const char *buffer, size_t len) { bufferlist bl; bl.append(buffer,len); ((::ObjectOperation *)write_op)->write_full(bl); } extern "C" void rados_write_op_append(rados_write_op_t write_op, const char *buffer, size_t len) { bufferlist bl; bl.append(buffer,len); ((::ObjectOperation *)write_op)->append(bl); } extern "C" void rados_write_op_remove(rados_write_op_t write_op) { ((::ObjectOperation *)write_op)->remove(); } extern "C" void rados_write_op_truncate(rados_write_op_t write_op, uint64_t offset) { ((::ObjectOperation *)write_op)->truncate(offset); } extern "C" void rados_write_op_zero(rados_write_op_t write_op, uint64_t offset, uint64_t len) { ((::ObjectOperation *)write_op)->zero(offset, len); } extern "C" void rados_write_op_exec(rados_write_op_t write_op, const char *cls, const char *method, const char *in_buf, size_t in_len, int *prval) { bufferlist inbl; inbl.append(in_buf, in_len); ((::ObjectOperation *)write_op)->call(cls, method, inbl, NULL, NULL, prval); } extern "C" void rados_write_op_omap_set(rados_write_op_t write_op, char const* const* keys, char const* const* vals, const size_t *lens, size_t num) { std::map entries; for (size_t i = 0; i < num; ++i) { bufferlist bl(lens[i]); bl.append(vals[i], lens[i]); entries[keys[i]] = bl; } ((::ObjectOperation *)write_op)->omap_set(entries); } extern "C" void rados_write_op_omap_rm_keys(rados_write_op_t write_op, char const* const* keys, size_t keys_len) { std::set to_remove(keys, keys + keys_len); ((::ObjectOperation *)write_op)->omap_rm_keys(to_remove); } extern "C" void rados_write_op_omap_clear(rados_write_op_t write_op) { ((::ObjectOperation *)write_op)->omap_clear(); } extern "C" void rados_write_op_set_alloc_hint(rados_write_op_t write_op, uint64_t expected_object_size, uint64_t expected_write_size) { ((::ObjectOperation *)write_op)->set_alloc_hint(expected_object_size, expected_write_size); } extern "C" int rados_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, const char *oid, time_t *mtime, int flags) { object_t obj(oid); ::ObjectOperation *oo = (::ObjectOperation *) write_op; librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->operate(obj, oo, mtime, translate_flags(flags)); } extern "C" int rados_aio_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, time_t *mtime, int flags) { object_t obj(oid); ::ObjectOperation *oo = (::ObjectOperation *) write_op; librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion; return ctx->aio_operate(obj, oo, c, ctx->snapc, translate_flags(flags)); } extern "C" rados_read_op_t rados_create_read_op() { return new (std::nothrow)::ObjectOperation; } extern "C" void rados_release_read_op(rados_read_op_t read_op) { delete (::ObjectOperation *)read_op; } extern "C" void rados_read_op_set_flags(rados_read_op_t read_op, int flags) { set_op_flags((::ObjectOperation *)read_op, flags); } extern "C" void rados_read_op_assert_exists(rados_read_op_t read_op) { ((::ObjectOperation *)read_op)->stat(NULL, (utime_t *)NULL, NULL); } extern "C" void rados_read_op_cmpxattr(rados_read_op_t read_op, const char *name, uint8_t comparison_operator, const char *value, size_t value_len) { bufferlist bl; bl.append(value, value_len); ((::ObjectOperation *)read_op)->cmpxattr(name, comparison_operator, CEPH_OSD_CMPXATTR_MODE_STRING, bl); } extern "C" void rados_read_op_omap_cmp(rados_read_op_t read_op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval) { rados_c_omap_cmp((::ObjectOperation *)read_op, key, comparison_operator, val, val_len, prval); } extern "C" void rados_read_op_stat(rados_read_op_t read_op, uint64_t *psize, time_t *pmtime, int *prval) { ((::ObjectOperation *)read_op)->stat(psize, pmtime, prval); } class C_bl_to_buf : public Context { char *out_buf; size_t out_len; size_t *bytes_read; int *prval; public: bufferlist out_bl; C_bl_to_buf(char *out_buf, size_t out_len, size_t *bytes_read, int *prval) : out_buf(out_buf), out_len(out_len), bytes_read(bytes_read), prval(prval) {} void finish(int r) { if (out_bl.length() > out_len) { if (prval) *prval = -ERANGE; if (bytes_read) *bytes_read = 0; return; } if (bytes_read) *bytes_read = out_bl.length(); if (out_buf && out_bl.c_str() != out_buf) out_bl.copy(0, out_bl.length(), out_buf); } }; extern "C" void rados_read_op_read(rados_read_op_t read_op, uint64_t offset, size_t len, char *buf, size_t *bytes_read, int *prval) { C_bl_to_buf *ctx = new C_bl_to_buf(buf, len, bytes_read, prval); ctx->out_bl.push_back(buffer::create_static(len, buf)); ((::ObjectOperation *)read_op)->read(offset, len, &ctx->out_bl, prval, ctx); } class C_out_buffer : public Context { char **out_buf; size_t *out_len; public: bufferlist out_bl; C_out_buffer(char **out_buf, size_t *out_len) : out_buf(out_buf), out_len(out_len) {} void finish(int r) { // ignore r since we don't know the meaning of return values // from custom class methods do_out_buffer(out_bl, out_buf, out_len); } }; extern "C" void rados_read_op_exec(rados_read_op_t read_op, const char *cls, const char *method, const char *in_buf, size_t in_len, char **out_buf, size_t *out_len, int *prval) { bufferlist inbl; inbl.append(in_buf, in_len); C_out_buffer *ctx = new C_out_buffer(out_buf, out_len); ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx, prval); } extern "C" void rados_read_op_exec_user_buf(rados_read_op_t read_op, const char *cls, const char *method, const char *in_buf, size_t in_len, char *out_buf, size_t out_len, size_t *used_len, int *prval) { C_bl_to_buf *ctx = new C_bl_to_buf(out_buf, out_len, used_len, prval); bufferlist inbl; inbl.append(in_buf, in_len); ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx, prval); } struct RadosOmapIter { std::map values; std::map::iterator i; }; class C_OmapIter : public Context { RadosOmapIter *iter; public: C_OmapIter(RadosOmapIter *iter) : iter(iter) {} void finish(int r) { iter->i = iter->values.begin(); } }; class C_XattrsIter : public Context { RadosXattrsIter *iter; public: C_XattrsIter(RadosXattrsIter *iter) : iter(iter) {} void finish(int r) { iter->i = iter->attrset.begin(); } }; extern "C" void rados_read_op_getxattrs(rados_read_op_t read_op, rados_xattrs_iter_t *iter, int *prval) { RadosXattrsIter *xattrs_iter = new RadosXattrsIter; ((::ObjectOperation *)read_op)->getxattrs(&xattrs_iter->attrset, prval); ((::ObjectOperation *)read_op)->add_handler(new C_XattrsIter(xattrs_iter)); *iter = xattrs_iter; } extern "C" void rados_read_op_omap_get_vals(rados_read_op_t read_op, const char *start_after, const char *filter_prefix, uint64_t max_return, rados_omap_iter_t *iter, int *prval) { RadosOmapIter *omap_iter = new RadosOmapIter; const char *start = start_after ? start_after : ""; const char *filter = filter_prefix ? filter_prefix : ""; ((::ObjectOperation *)read_op)->omap_get_vals(start, filter, max_return, &omap_iter->values, prval); ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter)); *iter = omap_iter; } struct C_OmapKeysIter : public Context { RadosOmapIter *iter; std::set keys; C_OmapKeysIter(RadosOmapIter *iter) : iter(iter) {} void finish(int r) { // map each key to an empty bl for (std::set::const_iterator i = keys.begin(); i != keys.end(); ++i) { iter->values[*i]; } iter->i = iter->values.begin(); } }; extern "C" void rados_read_op_omap_get_keys(rados_read_op_t read_op, const char *start_after, uint64_t max_return, rados_omap_iter_t *iter, int *prval) { RadosOmapIter *omap_iter = new RadosOmapIter; C_OmapKeysIter *ctx = new C_OmapKeysIter(omap_iter); ((::ObjectOperation *)read_op)->omap_get_keys(start_after ? start_after : "", max_return, &ctx->keys, prval); ((::ObjectOperation *)read_op)->add_handler(ctx); *iter = omap_iter; } extern "C" void rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op, char const* const* keys, size_t keys_len, rados_omap_iter_t *iter, int *prval) { std::set to_get(keys, keys + keys_len); RadosOmapIter *omap_iter = new RadosOmapIter; ((::ObjectOperation *)read_op)->omap_get_vals_by_keys(to_get, &omap_iter->values, prval); ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter)); *iter = omap_iter; } extern "C" int rados_omap_get_next(rados_omap_iter_t iter, char **key, char **val, size_t *len) { RadosOmapIter *it = (RadosOmapIter *)iter; if (it->i == it->values.end()) { *key = NULL; *val = NULL; *len = 0; return 0; } if (key) *key = (char*)it->i->first.c_str(); if (val) *val = it->i->second.c_str(); if (len) *len = it->i->second.length(); ++it->i; return 0; } extern "C" void rados_omap_get_end(rados_omap_iter_t iter) { RadosOmapIter *it = (RadosOmapIter *)iter; delete it; } extern "C" int rados_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, const char *oid, int flags) { object_t obj(oid); librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; return ctx->operate_read(obj, (::ObjectOperation *)read_op, NULL, translate_flags(flags)); } extern "C" int rados_aio_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, int flags) { object_t obj(oid); librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io; librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion; return ctx->aio_operate_read(obj, (::ObjectOperation *)read_op, c, translate_flags(flags), NULL); } ceph-0.80.11/src/librados/snap_set_diff.h0000664000175100017510000000071612623076744022244 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef __CEPH_OSDC_SNAP_SET_DIFF_H #define __CEPH_OSDC_SNAP_SET_DIFF_H class CephContext; #include "include/rados/rados_types.hpp" #include "include/interval_set.h" void calc_snap_set_diff(CephContext *cct, const librados::snap_set_t& snap_set, librados::snap_t start, librados::snap_t end, interval_set *diff, bool *end_exists); #endif ceph-0.80.11/src/civetweb/0000775000175100017510000000000012623077035017266 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/civetweb/civetweb.h0000664000175100017510000005266312623076750021266 0ustar jenkins-buildjenkins-build/* Copyright (c) 2013-2014 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef CIVETWEB_HEADER_INCLUDED #define CIVETWEB_HEADER_INCLUDED #ifndef CIVETWEB_VERSION #define CIVETWEB_VERSION "1.7" #endif #ifndef CIVETWEB_API #if defined(_WIN32) #if defined(CIVETWEB_DLL_EXPORTS) #define CIVETWEB_API __declspec(dllexport) #elif defined(CIVETWEB_DLL_IMPORTS) #define CIVETWEB_API __declspec(dllimport) #else #define CIVETWEB_API #endif #else #define CIVETWEB_API #endif #endif #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct mg_context; /* Handle for the HTTP service itself */ struct mg_connection; /* Handle for the individual connection */ /* This structure contains information about the HTTP request. */ struct mg_request_info { const char *request_method; /* "GET", "POST", etc */ const char *uri; /* URL-decoded URI */ const char *http_version; /* E.g. "1.0", "1.1" */ const char *query_string; /* URL part after '?', not including '?', or NULL */ const char *remote_user; /* Authenticated user, or NULL if no auth used */ long remote_ip; /* Client's IP address */ int remote_port; /* Client's port */ int is_ssl; /* 1 if SSL-ed, 0 if not */ void *user_data; /* User data pointer passed to mg_start() */ void *conn_data; /* Connection-specific user data */ int num_headers; /* Number of HTTP headers */ struct mg_header { const char *name; /* HTTP header name */ const char *value; /* HTTP header value */ } http_headers[64]; /* Maximum 64 headers */ }; /* This structure needs to be passed to mg_start(), to let civetweb know which callbacks to invoke. For detailed description, see https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md */ struct mg_callbacks { /* Called when civetweb has received new HTTP request. If callback returns non-zero, callback must process the request by sending valid HTTP headers and body, and civetweb will not do any further processing. If callback returns 0, civetweb processes the request itself. In this case, callback must not send any data to the client. */ int (*begin_request)(struct mg_connection *); /* Called when civetweb has finished processing request. */ void (*end_request)(const struct mg_connection *, int reply_status_code); /* Called when civetweb is about to log a message. If callback returns non-zero, civetweb does not log anything. */ int (*log_message)(const struct mg_connection *, const char *message); /* Called when civetweb is about to log access. If callback returns non-zero, civetweb does not log anything. */ int (*log_access)(const struct mg_connection *, const char *message); /* Called when civetweb initializes SSL library. */ int (*init_ssl)(void *ssl_context, void *user_data); /* Called when websocket request is received, before websocket handshake. If callback returns 0, civetweb proceeds with handshake, otherwise cinnection is closed immediately. */ int (*websocket_connect)(const struct mg_connection *); /* Called when websocket handshake is successfully completed, and connection is ready for data exchange. */ void (*websocket_ready)(struct mg_connection *); /* Called when data frame has been received from the client. Parameters: bits: first byte of the websocket frame, see websocket RFC at http://tools.ietf.org/html/rfc6455, section 5.2 data, data_len: payload, with mask (if any) already applied. Return value: non-0: keep this websocket connection opened. 0: close this websocket connection. */ int (*websocket_data)(struct mg_connection *, int bits, char *data, size_t data_len); /* Called when civetweb is closing a connection. The per-context mutex is locked when this is invoked. This is primarily useful for noting when a websocket is closing and removing it from any application-maintained list of clients. */ void (*connection_close)(struct mg_connection *); /* Called when civetweb tries to open a file. Used to intercept file open calls, and serve file data from memory instead. Parameters: path: Full path to the file to open. data_len: Placeholder for the file size, if file is served from memory. Return value: NULL: do not serve file from memory, proceed with normal file open. non-NULL: pointer to the file contents in memory. data_len must be initilized with the size of the memory block. */ const char * (*open_file)(const struct mg_connection *, const char *path, size_t *data_len); /* Called when civetweb is about to serve Lua server page (.lp file), if Lua support is enabled. Parameters: lua_context: "lua_State *" pointer. */ void (*init_lua)(struct mg_connection *, void *lua_context); /* Called when civetweb has uploaded a file to a temporary directory as a result of mg_upload() call. Parameters: file_file: full path name to the uploaded file. */ void (*upload)(struct mg_connection *, const char *file_name); /* Called when civetweb is about to send HTTP error to the client. Implementing this callback allows to create custom error pages. Parameters: status: HTTP error status code. */ int (*http_error)(struct mg_connection *, int status); }; /* Start web server. Parameters: callbacks: mg_callbacks structure with user-defined callbacks. options: NULL terminated list of option_name, option_value pairs that specify Civetweb configuration parameters. Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom processing is required for these, signal handlers must be set up after calling mg_start(). Example: const char *options[] = { "document_root", "/var/www", "listening_ports", "80,443s", NULL }; struct mg_context *ctx = mg_start(&my_func, NULL, options); Refer to https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md for the list of valid option and their possible values. Return: web server context, or NULL on error. */ CIVETWEB_API struct mg_context *mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **configuration_options); /* Stop the web server. Must be called last, when an application wants to stop the web server and release all associated resources. This function blocks until all Civetweb threads are stopped. Context pointer becomes invalid. */ CIVETWEB_API void mg_stop(struct mg_context *); /* mg_request_handler Called when a new request comes in. This callback is URI based and configured with mg_set_request_handler(). Parameters: conn: current connection information. cbdata: the callback data configured with mg_set_request_handler(). Returns: 0: the handler could not handle the request, so fall through. 1: the handler processed the request. */ typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata); /* mg_set_request_handler Sets or removes a URI mapping for a request handler. URI's are ordered and prefixed URI's are supported. For example, consider two URIs: /a/b and /a /a matches /a /a/b matches /a/b /a/c matches /a Parameters: ctx: server context uri: the URI to configure handler: the callback handler to use when the URI is requested. If NULL, the URI will be removed. cbdata: the callback data to give to the handler when it s requested. */ CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata); /* Get the value of particular configuration parameter. The value returned is read-only. Civetweb does not allow changing configuration at run time. If given parameter name is not valid, NULL is returned. For valid names, return value is guaranteed to be non-NULL. If parameter is not set, zero-length string is returned. */ CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx, const char *name); #if defined(MG_LEGACY_INTERFACE) /* Return array of strings that represent valid configuration options. For each option, option name and default value is returned, i.e. the number of entries in the array equals to number_of_options x 2. Array is NULL terminated. */ /* Deprecated: Use mg_get_valid_options instead. */ CIVETWEB_API const char **mg_get_valid_option_names(void); #endif struct mg_option { const char * name; int type; const char * default_value; }; enum { CONFIG_TYPE_UNKNOWN = 0x0, CONFIG_TYPE_NUMBER = 0x1, CONFIG_TYPE_STRING = 0x2, CONFIG_TYPE_FILE = 0x3, CONFIG_TYPE_DIRECTORY = 0x4, CONFIG_TYPE_BOOLEAN = 0x5, CONFIG_TYPE_EXT_PATTERN = 0x6 }; /* Return array of struct mg_option, representing all valid configuration options of civetweb.c. The array is terminated by a NULL name option. */ CIVETWEB_API const struct mg_option *mg_get_valid_options(void); /* Get the list of ports that civetweb is listening on. size is the size of the ports int array and ssl int array to fill. It is the caller's responsibility to make sure ports and ssl each contain at least size int elements worth of memory to write into. Return value is the number of ports and ssl information filled in. The value returned is read-only. Civetweb does not allow changing configuration at run time. */ CIVETWEB_API size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl); /* Add, edit or delete the entry in the passwords file. This function allows an application to manipulate .htpasswd files on the fly by adding, deleting and changing user records. This is one of the several ways of implementing authentication on the server side. For another, cookie-based way please refer to the examples/chat in the source tree. If password is not NULL, entry is added (or modified if already exists). If password is NULL, entry is deleted. Return: 1 on success, 0 on error. */ CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name, const char *domain, const char *user, const char *password); /* Return information associated with the request. */ CIVETWEB_API struct mg_request_info *mg_get_request_info(struct mg_connection *); /* Send data to the client. Return: 0 when the connection has been closed -1 on error >0 number of bytes written on success */ CIVETWEB_API int mg_write(struct mg_connection *, const void *buf, size_t len); /* Send data to a websocket client wrapped in a websocket frame. Uses mg_lock to ensure that the transmission is not interrupted, i.e., when the application is proactively communicating and responding to a request simultaneously. Send data to a websocket client wrapped in a websocket frame. This function is available when civetweb is compiled with -DUSE_WEBSOCKET Return: 0 when the connection has been closed -1 on error >0 number of bytes written on success */ CIVETWEB_API int mg_websocket_write(struct mg_connection* conn, int opcode, const char *data, size_t data_len); /* Blocks until unique access is obtained to this connection. Intended for use with websockets only. Invoke this before mg_write or mg_printf when communicating with a websocket if your code has server-initiated communication as well as communication in direct response to a message. */ CIVETWEB_API void mg_lock_connection(struct mg_connection* conn); CIVETWEB_API void mg_unlock_connection(struct mg_connection* conn); #if defined(MG_LEGACY_INTERFACE) #define mg_lock mg_lock_connection #define mg_unlock mg_unlock_connection #endif /* Lock server context. This lock may be used to protect ressources that are shared between different connection/worker threads. */ CIVETWEB_API void mg_lock_context(struct mg_context* ctx); CIVETWEB_API void mg_unlock_context(struct mg_context* ctx); /* Opcodes, from http://tools.ietf.org/html/rfc6455 */ enum { WEBSOCKET_OPCODE_CONTINUATION = 0x0, WEBSOCKET_OPCODE_TEXT = 0x1, WEBSOCKET_OPCODE_BINARY = 0x2, WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8, WEBSOCKET_OPCODE_PING = 0x9, WEBSOCKET_OPCODE_PONG = 0xa }; /* Macros for enabling compiler-specific checks for printf-like arguments. */ #undef PRINTF_FORMAT_STRING #if defined(_MSC_VER) && _MSC_VER >= 1400 #include #if defined(_MSC_VER) && _MSC_VER > 1400 #define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s #else #define PRINTF_FORMAT_STRING(s) __format_string s #endif #else #define PRINTF_FORMAT_STRING(s) s #endif #ifdef __GNUC__ #define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y))) #else #define PRINTF_ARGS(x, y) #endif /* Send data to the client using printf() semantics. Works exactly like mg_write(), but allows to do message formatting. */ CIVETWEB_API int mg_printf(struct mg_connection *, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); /* Send contents of the entire file together with HTTP headers. */ CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path); /* Read data from the remote end, return number of bytes read. Return: 0 connection has been closed by peer. No more data could be read. < 0 read error. No more data could be read from the connection. > 0 number of bytes read into the buffer. */ CIVETWEB_API int mg_read(struct mg_connection *, void *buf, size_t len); /* Get the value of particular HTTP header. This is a helper function. It traverses request_info->http_headers array, and if the header is present in the array, returns its value. If it is not present, NULL is returned. */ CIVETWEB_API const char *mg_get_header(const struct mg_connection *, const char *name); /* Get a value of particular form variable. Parameters: data: pointer to form-uri-encoded buffer. This could be either POST data, or request_info.query_string. data_len: length of the encoded data. var_name: variable name to decode from the buffer dst: destination buffer for the decoded variable dst_len: length of the destination buffer Return: On success, length of the decoded variable. On error: -1 (variable not found). -2 (destination buffer is NULL, zero length or too small to hold the decoded variable). Destination buffer is guaranteed to be '\0' - terminated if it is not NULL or zero length. */ CIVETWEB_API int mg_get_var(const char *data, size_t data_len, const char *var_name, char *dst, size_t dst_len); /* Get a value of particular form variable. Parameters: data: pointer to form-uri-encoded buffer. This could be either POST data, or request_info.query_string. data_len: length of the encoded data. var_name: variable name to decode from the buffer dst: destination buffer for the decoded variable dst_len: length of the destination buffer occurrence: which occurrence of the variable, 0 is the first, 1 the second... this makes it possible to parse a query like b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1 Return: On success, length of the decoded variable. On error: -1 (variable not found). -2 (destination buffer is NULL, zero length or too small to hold the decoded variable). Destination buffer is guaranteed to be '\0' - terminated if it is not NULL or zero length. */ CIVETWEB_API int mg_get_var2(const char *data, size_t data_len, const char *var_name, char *dst, size_t dst_len, size_t occurrence); /* Fetch value of certain cookie variable into the destination buffer. Destination buffer is guaranteed to be '\0' - terminated. In case of failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same parameter. This function returns only first occurrence. Return: On success, value length. On error: -1 (either "Cookie:" header is not present at all or the requested parameter is not found). -2 (destination buffer is NULL, zero length or too small to hold the value). */ CIVETWEB_API int mg_get_cookie(const char *cookie, const char *var_name, char *buf, size_t buf_len); /* Download data from the remote web server. host: host name to connect to, e.g. "foo.com", or "10.12.40.1". port: port number, e.g. 80. use_ssl: wether to use SSL connection. error_buffer, error_buffer_size: error message placeholder. request_fmt,...: HTTP request. Return: On success, valid pointer to the new connection, suitable for mg_read(). On error, NULL. error_buffer contains error message. Example: char ebuf[100]; struct mg_connection *conn; conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf), "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n"); */ CIVETWEB_API struct mg_connection *mg_download(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, PRINTF_FORMAT_STRING(const char *request_fmt), ...) PRINTF_ARGS(6, 7); /* Close the connection opened by mg_download(). */ CIVETWEB_API void mg_close_connection(struct mg_connection *conn); /* File upload functionality. Each uploaded file gets saved into a temporary file and MG_UPLOAD event is sent. Return number of uploaded files. */ CIVETWEB_API int mg_upload(struct mg_connection *conn, const char *destination_dir); /* Convenience function -- create detached thread. Return: 0 on success, non-0 on error. */ typedef void * (*mg_thread_func_t)(void *); CIVETWEB_API int mg_start_thread(mg_thread_func_t f, void *p); /* Return builtin mime type for the given file name. For unrecognized extensions, "text/plain" is returned. */ CIVETWEB_API const char *mg_get_builtin_mime_type(const char *file_name); /* Return Civetweb version. */ CIVETWEB_API const char *mg_version(void); /* URL-decode input buffer into destination buffer. 0-terminate the destination buffer. form-url-encoded data differs from URI encoding in a way that it uses '+' as character for space, see RFC 1866 section 8.2.1 http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt Return: length of the decoded data, or -1 if dst buffer is too small. */ CIVETWEB_API int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded); /* URL-encode input buffer into destination buffer. returns the length of the resulting buffer or -1 is the buffer is too small. */ CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len); /* MD5 hash given strings. Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of ASCIIz strings. When function returns, buf will contain human-readable MD5 hash. Example: char buf[33]; mg_md5(buf, "aa", "bb", NULL); */ CIVETWEB_API char *mg_md5(char buf[33], ...); /* Print error message to the opened error log stream. This utilizes the provided logging configuration. conn: connection fmt: format string without the line return ...: variable argument list Example: mg_cry(conn,"i like %s", "logging"); */ CIVETWEB_API void mg_cry(struct mg_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); /* utility method to compare two buffers, case incensitive. */ CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CIVETWEB_HEADER_INCLUDED */ ceph-0.80.11/src/civetweb/include/0000775000175100017510000000000012623077035020711 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/civetweb/include/civetweb.h0000664000175100017510000005266312623076750022711 0ustar jenkins-buildjenkins-build/* Copyright (c) 2013-2014 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef CIVETWEB_HEADER_INCLUDED #define CIVETWEB_HEADER_INCLUDED #ifndef CIVETWEB_VERSION #define CIVETWEB_VERSION "1.7" #endif #ifndef CIVETWEB_API #if defined(_WIN32) #if defined(CIVETWEB_DLL_EXPORTS) #define CIVETWEB_API __declspec(dllexport) #elif defined(CIVETWEB_DLL_IMPORTS) #define CIVETWEB_API __declspec(dllimport) #else #define CIVETWEB_API #endif #else #define CIVETWEB_API #endif #endif #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct mg_context; /* Handle for the HTTP service itself */ struct mg_connection; /* Handle for the individual connection */ /* This structure contains information about the HTTP request. */ struct mg_request_info { const char *request_method; /* "GET", "POST", etc */ const char *uri; /* URL-decoded URI */ const char *http_version; /* E.g. "1.0", "1.1" */ const char *query_string; /* URL part after '?', not including '?', or NULL */ const char *remote_user; /* Authenticated user, or NULL if no auth used */ long remote_ip; /* Client's IP address */ int remote_port; /* Client's port */ int is_ssl; /* 1 if SSL-ed, 0 if not */ void *user_data; /* User data pointer passed to mg_start() */ void *conn_data; /* Connection-specific user data */ int num_headers; /* Number of HTTP headers */ struct mg_header { const char *name; /* HTTP header name */ const char *value; /* HTTP header value */ } http_headers[64]; /* Maximum 64 headers */ }; /* This structure needs to be passed to mg_start(), to let civetweb know which callbacks to invoke. For detailed description, see https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md */ struct mg_callbacks { /* Called when civetweb has received new HTTP request. If callback returns non-zero, callback must process the request by sending valid HTTP headers and body, and civetweb will not do any further processing. If callback returns 0, civetweb processes the request itself. In this case, callback must not send any data to the client. */ int (*begin_request)(struct mg_connection *); /* Called when civetweb has finished processing request. */ void (*end_request)(const struct mg_connection *, int reply_status_code); /* Called when civetweb is about to log a message. If callback returns non-zero, civetweb does not log anything. */ int (*log_message)(const struct mg_connection *, const char *message); /* Called when civetweb is about to log access. If callback returns non-zero, civetweb does not log anything. */ int (*log_access)(const struct mg_connection *, const char *message); /* Called when civetweb initializes SSL library. */ int (*init_ssl)(void *ssl_context, void *user_data); /* Called when websocket request is received, before websocket handshake. If callback returns 0, civetweb proceeds with handshake, otherwise cinnection is closed immediately. */ int (*websocket_connect)(const struct mg_connection *); /* Called when websocket handshake is successfully completed, and connection is ready for data exchange. */ void (*websocket_ready)(struct mg_connection *); /* Called when data frame has been received from the client. Parameters: bits: first byte of the websocket frame, see websocket RFC at http://tools.ietf.org/html/rfc6455, section 5.2 data, data_len: payload, with mask (if any) already applied. Return value: non-0: keep this websocket connection opened. 0: close this websocket connection. */ int (*websocket_data)(struct mg_connection *, int bits, char *data, size_t data_len); /* Called when civetweb is closing a connection. The per-context mutex is locked when this is invoked. This is primarily useful for noting when a websocket is closing and removing it from any application-maintained list of clients. */ void (*connection_close)(struct mg_connection *); /* Called when civetweb tries to open a file. Used to intercept file open calls, and serve file data from memory instead. Parameters: path: Full path to the file to open. data_len: Placeholder for the file size, if file is served from memory. Return value: NULL: do not serve file from memory, proceed with normal file open. non-NULL: pointer to the file contents in memory. data_len must be initilized with the size of the memory block. */ const char * (*open_file)(const struct mg_connection *, const char *path, size_t *data_len); /* Called when civetweb is about to serve Lua server page (.lp file), if Lua support is enabled. Parameters: lua_context: "lua_State *" pointer. */ void (*init_lua)(struct mg_connection *, void *lua_context); /* Called when civetweb has uploaded a file to a temporary directory as a result of mg_upload() call. Parameters: file_file: full path name to the uploaded file. */ void (*upload)(struct mg_connection *, const char *file_name); /* Called when civetweb is about to send HTTP error to the client. Implementing this callback allows to create custom error pages. Parameters: status: HTTP error status code. */ int (*http_error)(struct mg_connection *, int status); }; /* Start web server. Parameters: callbacks: mg_callbacks structure with user-defined callbacks. options: NULL terminated list of option_name, option_value pairs that specify Civetweb configuration parameters. Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom processing is required for these, signal handlers must be set up after calling mg_start(). Example: const char *options[] = { "document_root", "/var/www", "listening_ports", "80,443s", NULL }; struct mg_context *ctx = mg_start(&my_func, NULL, options); Refer to https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md for the list of valid option and their possible values. Return: web server context, or NULL on error. */ CIVETWEB_API struct mg_context *mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **configuration_options); /* Stop the web server. Must be called last, when an application wants to stop the web server and release all associated resources. This function blocks until all Civetweb threads are stopped. Context pointer becomes invalid. */ CIVETWEB_API void mg_stop(struct mg_context *); /* mg_request_handler Called when a new request comes in. This callback is URI based and configured with mg_set_request_handler(). Parameters: conn: current connection information. cbdata: the callback data configured with mg_set_request_handler(). Returns: 0: the handler could not handle the request, so fall through. 1: the handler processed the request. */ typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata); /* mg_set_request_handler Sets or removes a URI mapping for a request handler. URI's are ordered and prefixed URI's are supported. For example, consider two URIs: /a/b and /a /a matches /a /a/b matches /a/b /a/c matches /a Parameters: ctx: server context uri: the URI to configure handler: the callback handler to use when the URI is requested. If NULL, the URI will be removed. cbdata: the callback data to give to the handler when it s requested. */ CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata); /* Get the value of particular configuration parameter. The value returned is read-only. Civetweb does not allow changing configuration at run time. If given parameter name is not valid, NULL is returned. For valid names, return value is guaranteed to be non-NULL. If parameter is not set, zero-length string is returned. */ CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx, const char *name); #if defined(MG_LEGACY_INTERFACE) /* Return array of strings that represent valid configuration options. For each option, option name and default value is returned, i.e. the number of entries in the array equals to number_of_options x 2. Array is NULL terminated. */ /* Deprecated: Use mg_get_valid_options instead. */ CIVETWEB_API const char **mg_get_valid_option_names(void); #endif struct mg_option { const char * name; int type; const char * default_value; }; enum { CONFIG_TYPE_UNKNOWN = 0x0, CONFIG_TYPE_NUMBER = 0x1, CONFIG_TYPE_STRING = 0x2, CONFIG_TYPE_FILE = 0x3, CONFIG_TYPE_DIRECTORY = 0x4, CONFIG_TYPE_BOOLEAN = 0x5, CONFIG_TYPE_EXT_PATTERN = 0x6 }; /* Return array of struct mg_option, representing all valid configuration options of civetweb.c. The array is terminated by a NULL name option. */ CIVETWEB_API const struct mg_option *mg_get_valid_options(void); /* Get the list of ports that civetweb is listening on. size is the size of the ports int array and ssl int array to fill. It is the caller's responsibility to make sure ports and ssl each contain at least size int elements worth of memory to write into. Return value is the number of ports and ssl information filled in. The value returned is read-only. Civetweb does not allow changing configuration at run time. */ CIVETWEB_API size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl); /* Add, edit or delete the entry in the passwords file. This function allows an application to manipulate .htpasswd files on the fly by adding, deleting and changing user records. This is one of the several ways of implementing authentication on the server side. For another, cookie-based way please refer to the examples/chat in the source tree. If password is not NULL, entry is added (or modified if already exists). If password is NULL, entry is deleted. Return: 1 on success, 0 on error. */ CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name, const char *domain, const char *user, const char *password); /* Return information associated with the request. */ CIVETWEB_API struct mg_request_info *mg_get_request_info(struct mg_connection *); /* Send data to the client. Return: 0 when the connection has been closed -1 on error >0 number of bytes written on success */ CIVETWEB_API int mg_write(struct mg_connection *, const void *buf, size_t len); /* Send data to a websocket client wrapped in a websocket frame. Uses mg_lock to ensure that the transmission is not interrupted, i.e., when the application is proactively communicating and responding to a request simultaneously. Send data to a websocket client wrapped in a websocket frame. This function is available when civetweb is compiled with -DUSE_WEBSOCKET Return: 0 when the connection has been closed -1 on error >0 number of bytes written on success */ CIVETWEB_API int mg_websocket_write(struct mg_connection* conn, int opcode, const char *data, size_t data_len); /* Blocks until unique access is obtained to this connection. Intended for use with websockets only. Invoke this before mg_write or mg_printf when communicating with a websocket if your code has server-initiated communication as well as communication in direct response to a message. */ CIVETWEB_API void mg_lock_connection(struct mg_connection* conn); CIVETWEB_API void mg_unlock_connection(struct mg_connection* conn); #if defined(MG_LEGACY_INTERFACE) #define mg_lock mg_lock_connection #define mg_unlock mg_unlock_connection #endif /* Lock server context. This lock may be used to protect ressources that are shared between different connection/worker threads. */ CIVETWEB_API void mg_lock_context(struct mg_context* ctx); CIVETWEB_API void mg_unlock_context(struct mg_context* ctx); /* Opcodes, from http://tools.ietf.org/html/rfc6455 */ enum { WEBSOCKET_OPCODE_CONTINUATION = 0x0, WEBSOCKET_OPCODE_TEXT = 0x1, WEBSOCKET_OPCODE_BINARY = 0x2, WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8, WEBSOCKET_OPCODE_PING = 0x9, WEBSOCKET_OPCODE_PONG = 0xa }; /* Macros for enabling compiler-specific checks for printf-like arguments. */ #undef PRINTF_FORMAT_STRING #if defined(_MSC_VER) && _MSC_VER >= 1400 #include #if defined(_MSC_VER) && _MSC_VER > 1400 #define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s #else #define PRINTF_FORMAT_STRING(s) __format_string s #endif #else #define PRINTF_FORMAT_STRING(s) s #endif #ifdef __GNUC__ #define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y))) #else #define PRINTF_ARGS(x, y) #endif /* Send data to the client using printf() semantics. Works exactly like mg_write(), but allows to do message formatting. */ CIVETWEB_API int mg_printf(struct mg_connection *, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); /* Send contents of the entire file together with HTTP headers. */ CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path); /* Read data from the remote end, return number of bytes read. Return: 0 connection has been closed by peer. No more data could be read. < 0 read error. No more data could be read from the connection. > 0 number of bytes read into the buffer. */ CIVETWEB_API int mg_read(struct mg_connection *, void *buf, size_t len); /* Get the value of particular HTTP header. This is a helper function. It traverses request_info->http_headers array, and if the header is present in the array, returns its value. If it is not present, NULL is returned. */ CIVETWEB_API const char *mg_get_header(const struct mg_connection *, const char *name); /* Get a value of particular form variable. Parameters: data: pointer to form-uri-encoded buffer. This could be either POST data, or request_info.query_string. data_len: length of the encoded data. var_name: variable name to decode from the buffer dst: destination buffer for the decoded variable dst_len: length of the destination buffer Return: On success, length of the decoded variable. On error: -1 (variable not found). -2 (destination buffer is NULL, zero length or too small to hold the decoded variable). Destination buffer is guaranteed to be '\0' - terminated if it is not NULL or zero length. */ CIVETWEB_API int mg_get_var(const char *data, size_t data_len, const char *var_name, char *dst, size_t dst_len); /* Get a value of particular form variable. Parameters: data: pointer to form-uri-encoded buffer. This could be either POST data, or request_info.query_string. data_len: length of the encoded data. var_name: variable name to decode from the buffer dst: destination buffer for the decoded variable dst_len: length of the destination buffer occurrence: which occurrence of the variable, 0 is the first, 1 the second... this makes it possible to parse a query like b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1 Return: On success, length of the decoded variable. On error: -1 (variable not found). -2 (destination buffer is NULL, zero length or too small to hold the decoded variable). Destination buffer is guaranteed to be '\0' - terminated if it is not NULL or zero length. */ CIVETWEB_API int mg_get_var2(const char *data, size_t data_len, const char *var_name, char *dst, size_t dst_len, size_t occurrence); /* Fetch value of certain cookie variable into the destination buffer. Destination buffer is guaranteed to be '\0' - terminated. In case of failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same parameter. This function returns only first occurrence. Return: On success, value length. On error: -1 (either "Cookie:" header is not present at all or the requested parameter is not found). -2 (destination buffer is NULL, zero length or too small to hold the value). */ CIVETWEB_API int mg_get_cookie(const char *cookie, const char *var_name, char *buf, size_t buf_len); /* Download data from the remote web server. host: host name to connect to, e.g. "foo.com", or "10.12.40.1". port: port number, e.g. 80. use_ssl: wether to use SSL connection. error_buffer, error_buffer_size: error message placeholder. request_fmt,...: HTTP request. Return: On success, valid pointer to the new connection, suitable for mg_read(). On error, NULL. error_buffer contains error message. Example: char ebuf[100]; struct mg_connection *conn; conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf), "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n"); */ CIVETWEB_API struct mg_connection *mg_download(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, PRINTF_FORMAT_STRING(const char *request_fmt), ...) PRINTF_ARGS(6, 7); /* Close the connection opened by mg_download(). */ CIVETWEB_API void mg_close_connection(struct mg_connection *conn); /* File upload functionality. Each uploaded file gets saved into a temporary file and MG_UPLOAD event is sent. Return number of uploaded files. */ CIVETWEB_API int mg_upload(struct mg_connection *conn, const char *destination_dir); /* Convenience function -- create detached thread. Return: 0 on success, non-0 on error. */ typedef void * (*mg_thread_func_t)(void *); CIVETWEB_API int mg_start_thread(mg_thread_func_t f, void *p); /* Return builtin mime type for the given file name. For unrecognized extensions, "text/plain" is returned. */ CIVETWEB_API const char *mg_get_builtin_mime_type(const char *file_name); /* Return Civetweb version. */ CIVETWEB_API const char *mg_version(void); /* URL-decode input buffer into destination buffer. 0-terminate the destination buffer. form-url-encoded data differs from URI encoding in a way that it uses '+' as character for space, see RFC 1866 section 8.2.1 http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt Return: length of the decoded data, or -1 if dst buffer is too small. */ CIVETWEB_API int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded); /* URL-encode input buffer into destination buffer. returns the length of the resulting buffer or -1 is the buffer is too small. */ CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len); /* MD5 hash given strings. Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of ASCIIz strings. When function returns, buf will contain human-readable MD5 hash. Example: char buf[33]; mg_md5(buf, "aa", "bb", NULL); */ CIVETWEB_API char *mg_md5(char buf[33], ...); /* Print error message to the opened error log stream. This utilizes the provided logging configuration. conn: connection fmt: format string without the line return ...: variable argument list Example: mg_cry(conn,"i like %s", "logging"); */ CIVETWEB_API void mg_cry(struct mg_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); /* utility method to compare two buffers, case incensitive. */ CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CIVETWEB_HEADER_INCLUDED */ ceph-0.80.11/src/civetweb/include/civetweb_conf.h0000664000175100017510000000011412623076750023676 0ustar jenkins-buildjenkins-build#ifndef CIVETWEB_CONF_H #define CIVETWEB_CONF_H #define USE_IPV6 1 #endif ceph-0.80.11/src/civetweb/src/0000775000175100017510000000000012623077035020055 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/civetweb/src/md5.h0000664000175100017510000003631412623076750020725 0ustar jenkins-buildjenkins-build/* * This an amalgamation of md5.c and md5.h into a single file * with all static declaration to reduce linker conflicts * in Civetweb. * * The MD5_STATIC declaration was added to facilitate static * inclusion. * No Face Press, LLC */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ MD5_STATIC void md5_init(md5_state_t *pms); /* Append a string to the message. */ MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ /* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #ifndef MD5_STATIC #include #endif #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } MD5_STATIC void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } ceph-0.80.11/src/civetweb/src/civetweb.c0000664000175100017510000071316312623076750022047 0ustar jenkins-buildjenkins-build/* Copyright (c) 2013-2014 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #define RGW 1 #if defined(_WIN32) #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */ #endif #else #ifdef __linux__ #define _XOPEN_SOURCE 600 /* For flockfile() on Linux */ #endif #ifndef _LARGEFILE_SOURCE #define _LARGEFILE_SOURCE /* For fseeko(), ftello() */ #endif #ifndef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */ #endif #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS /* wants this for C++ */ #endif #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */ #endif #endif #if defined (_MSC_VER) /* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */ #pragma warning (disable : 4306 ) /* conditional expression is constant: introduced by FD_SET(..) */ #pragma warning (disable : 4127) /* non-constant aggregate initializer: issued due to missing C99 support */ #pragma warning (disable : 4204) #endif /* Disable WIN32_LEAN_AND_MEAN. This makes windows.h always include winsock2.h */ #if defined(WIN32_LEAN_AND_MEAN) #undef WIN32_LEAN_AND_MEAN #endif #if defined USE_IPV6 && defined(_WIN32) #include #endif #if defined(__SYMBIAN32__) #define NO_SSL /* SSL is not supported */ #define NO_CGI /* CGI is not supported */ #define PATH_MAX FILENAME_MAX #endif /* __SYMBIAN32__ */ #ifndef IGNORE_UNUSED_RESULT #define IGNORE_UNUSED_RESULT(a) (void)((a) && 1) #endif #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */ #include #include #include #include #include #endif /* !_WIN32_WCE */ #include #include #include #include #include #include #include #include #include #ifndef MAX_WORKER_THREADS #define MAX_WORKER_THREADS 1024 #endif #if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */ #if defined(_MSC_VER) && _MSC_VER <= 1400 #undef _WIN32_WINNT #define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */ #endif #include #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif #ifndef _IN_PORT_T #ifndef in_port_t #define in_port_t u_short #endif #endif #ifndef _WIN32_WCE #include #include #include #else /* _WIN32_WCE */ #define NO_CGI /* WinCE has no pipes */ typedef long off_t; #define errno GetLastError() #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10) #endif /* _WIN32_WCE */ #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \ ((uint64_t)((uint32_t)(hi))) << 32)) #define RATE_DIFF 10000000 /* 100 nsecs */ #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de) #define SYS2UNIX_TIME(lo, hi) \ (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF) /* Visual Studio 6 does not know __func__ or __FUNCTION__ The rest of MS compilers use __FUNCTION__, not C99 __func__ Also use _strtoui64 on modern M$ compilers */ #if defined(_MSC_VER) && _MSC_VER < 1300 #define STRX(x) #x #define STR(x) STRX(x) #define __func__ __FILE__ ":" STR(__LINE__) #define strtoull(x, y, z) (unsigned __int64) _atoi64(x) #define strtoll(x, y, z) _atoi64(x) #else #define __func__ __FUNCTION__ #define strtoull(x, y, z) _strtoui64(x, y, z) #define strtoll(x, y, z) _strtoi64(x, y, z) #endif /* _MSC_VER */ #define ERRNO GetLastError() #define NO_SOCKLEN_T #define SSL_LIB "ssleay32.dll" #define CRYPTO_LIB "libeay32.dll" #define O_NONBLOCK 0 #if !defined(EWOULDBLOCK) #define EWOULDBLOCK WSAEWOULDBLOCK #endif /* !EWOULDBLOCK */ #define _POSIX_ #define INT64_FMT "I64d" #define WINCDECL __cdecl #define SHUT_WR 1 #define snprintf _snprintf #define vsnprintf _vsnprintf #define mg_sleep(x) Sleep(x) #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) #ifndef popen #define popen(x, y) _popen(x, y) #endif #ifndef pclose #define pclose(x) _pclose(x) #endif #define close(x) _close(x) #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) #define RTLD_LAZY 0 #define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z)) #define fdopen(x, y) _fdopen((x), (y)) #define write(x, y, z) _write((x), (y), (unsigned) z) #define read(x, y, z) _read((x), (y), (unsigned) z) #define flockfile(x) EnterCriticalSection(&global_log_file_lock) #define funlockfile(x) LeaveCriticalSection(&global_log_file_lock) #define sleep(x) Sleep((x) * 1000) #define rmdir(x) _rmdir(x) #if defined(USE_LUA) && defined(USE_WEBSOCKET) #define USE_TIMERS #endif #if !defined(va_copy) #define va_copy(x, y) x = y #endif /* !va_copy MINGW #defines va_copy */ #if !defined(fileno) #define fileno(x) _fileno(x) #endif /* !fileno MINGW #defines fileno */ typedef HANDLE pthread_mutex_t; typedef DWORD pthread_key_t; typedef HANDLE pthread_t; typedef struct { CRITICAL_SECTION threadIdSec; int waitingthreadcount; /* The number of threads queued. */ pthread_t *waitingthreadhdls; /* The thread handles. */ } pthread_cond_t; #ifndef __clockid_t_defined typedef DWORD clockid_t; #endif #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) #endif #ifndef CLOCK_REALTIME #define CLOCK_REALTIME (2) #endif #ifndef _TIMESPEC_DEFINED struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */ static int pthread_mutex_lock(pthread_mutex_t *); static int pthread_mutex_unlock(pthread_mutex_t *); static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len); struct file; static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p); #if defined(HAVE_STDINT) #include #else typedef unsigned int uint32_t; typedef unsigned short uint16_t; typedef unsigned __int64 uint64_t; typedef __int64 int64_t; #define INT64_MAX 9223372036854775807 #endif /* HAVE_STDINT */ /* POSIX dirent interface */ struct dirent { char d_name[PATH_MAX]; }; typedef struct DIR { HANDLE handle; WIN32_FIND_DATAW info; struct dirent result; } DIR; #if !defined(USE_IPV6) && defined(_WIN32) #ifndef HAVE_POLL struct pollfd { SOCKET fd; short events; short revents; }; #define POLLIN 1 #endif #endif /* Mark required libraries */ #ifdef _MSC_VER #pragma comment(lib, "Ws2_32.lib") #endif #else /* UNIX specific */ #include #include #include #include #include #include #include #include #include #include #if defined(ANDROID) typedef unsigned short int in_port_t; #endif #include #include #include #if !defined(NO_SSL_DL) && !defined(NO_SSL) #include #endif #include #if defined(__MACH__) #define SSL_LIB "libssl.dylib" #define CRYPTO_LIB "libcrypto.dylib" #else #if !defined(SSL_LIB) #define SSL_LIB "libssl.so" #endif #if !defined(CRYPTO_LIB) #define CRYPTO_LIB "libcrypto.so" #endif #endif #ifndef O_BINARY #define O_BINARY 0 #endif /* O_BINARY */ #define closesocket(a) close(a) #define mg_mkdir(x, y) mkdir(x, y) #define mg_remove(x) remove(x) #define mg_sleep(x) usleep((x) * 1000) #define ERRNO errno #define INVALID_SOCKET (-1) #define INT64_FMT PRId64 typedef int SOCKET; #define WINCDECL #endif /* End of Windows and UNIX specific includes */ #ifdef _WIN32 static CRITICAL_SECTION global_log_file_lock; static DWORD pthread_self(void) { return GetCurrentThreadId(); } int pthread_key_create(pthread_key_t *key, void (*_must_be_zero)(void*) /* destructor function not supported for windows */) { assert(_must_be_zero == NULL); if ((key!=0) && (_must_be_zero == NULL)) { *key = TlsAlloc(); return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1; } return -2; } int pthread_key_delete(pthread_key_t key) { return TlsFree(key) ? 0 : 1; } int pthread_setspecific(pthread_key_t key, void * value) { return TlsSetValue(key, value) ? 0 : 1; } void *pthread_getspecific(pthread_key_t key) { return TlsGetValue(key); } #endif /* _WIN32 */ #include "civetweb.h" #define PASSWORDS_FILE_NAME ".htpasswd" #define CGI_ENVIRONMENT_SIZE 4096 #define MAX_CGI_ENVIR_VARS 64 #define MG_BUF_LEN 8192 #ifndef MAX_REQUEST_SIZE #define MAX_REQUEST_SIZE 16384 #endif #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) #if !defined(DEBUG_TRACE) #if defined(DEBUG) static void DEBUG_TRACE_FUNC(const char *func, unsigned line, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4); static void DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) { va_list args; flockfile(stdout); printf("*** %lu.%p.%s.%u: ", (unsigned long) time(NULL), (void *) pthread_self(), func, line); va_start(args, fmt); vprintf(fmt, args); va_end(args); putchar('\n'); fflush(stdout); funlockfile(stdout); } #define DEBUG_TRACE(fmt, ...) DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) #else #define DEBUG_TRACE(fmt, ...) #endif /* DEBUG */ #endif /* DEBUG_TRACE */ #if defined(MEMORY_DEBUGGING) static unsigned long blockCount = 0; static unsigned long totalMemUsed = 0; static void * mg_malloc_ex(size_t size, const char * file, unsigned line) { void * data = malloc(size + sizeof(size_t)); void * memory = 0; char mallocStr[256]; if (data) { *(size_t*)data = size; totalMemUsed += size; blockCount++; memory = (void *)(((char*)data)+sizeof(size_t)); } sprintf(mallocStr, "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line); #if defined(_WIN32) OutputDebugStringA(mallocStr); #else DEBUG_TRACE("%s", mallocStr); #endif return memory; } static void * mg_calloc_ex(size_t count, size_t size, const char * file, unsigned line) { void * data = mg_malloc_ex(size*count, file, line); if (data) memset(data, 0, size); return data; } static void mg_free_ex(void * memory, const char * file, unsigned line) { char mallocStr[256]; void * data = (void *)(((char*)memory)-sizeof(size_t)); size_t size; if (memory) { size = *(size_t*)data; totalMemUsed -= size; blockCount--; sprintf(mallocStr, "MEM: %p %5lu free %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line); #if defined(_WIN32) OutputDebugStringA(mallocStr); #else DEBUG_TRACE("%s", mallocStr); #endif free(data); } } static void * mg_realloc_ex(void * memory, size_t newsize, const char * file, unsigned line) { char mallocStr[256]; void * data; void * _realloc; size_t oldsize; if (newsize) { if (memory) { data = (void *)(((char*)memory)-sizeof(size_t)); oldsize = *(size_t*)data; _realloc = realloc(data, newsize+sizeof(size_t)); if (_realloc) { data = _realloc; totalMemUsed -= oldsize; sprintf(mallocStr, "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", memory, (unsigned long)oldsize, totalMemUsed, blockCount, file, line); #if defined(_WIN32) OutputDebugStringA(mallocStr); #else DEBUG_TRACE("%s", mallocStr); #endif totalMemUsed += newsize; sprintf(mallocStr, "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)newsize, totalMemUsed, blockCount, file, line); #if defined(_WIN32) OutputDebugStringA(mallocStr); #else DEBUG_TRACE("%s", mallocStr); #endif *(size_t*)data = newsize; data = (void *)(((char*)data)+sizeof(size_t)); } else { #if defined(_WIN32) OutputDebugStringA("MEM: realloc failed\n"); #else DEBUG_TRACE("MEM: realloc failed\n"); #endif return _realloc; } } else { data = mg_malloc_ex(newsize, file, line); } } else { data = 0; mg_free_ex(memory, file, line); } return data; } #define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__) #define mg_calloc(a,b) mg_calloc_ex(a, b, __FILE__, __LINE__) #define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__) #define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) #else static __inline void * mg_malloc(size_t a) {return malloc(a);} static __inline void * mg_calloc(size_t a, size_t b) {return calloc(a, b);} static __inline void * mg_realloc(void * a, size_t b) {return realloc(a, b);} static __inline void mg_free(void * a) {free(a);} #endif /* This following lines are just meant as a reminder to use the mg-functions for memory management */ #ifdef malloc #undef malloc #endif #ifdef calloc #undef calloc #endif #ifdef realloc #undef realloc #endif #ifdef free #undef free #endif #define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc #define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free #define MD5_STATIC static #include "md5.h" /* Darwin prior to 7.0 and Win32 do not have socklen_t */ #ifdef NO_SOCKLEN_T typedef int socklen_t; #endif /* NO_SOCKLEN_T */ #define _DARWIN_UNLIMITED_SELECT #define IP_ADDR_STR_LEN 50 /* IPv6 hex string is 46 chars */ #if !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif #if !defined(SOMAXCONN) #define SOMAXCONN 100 #endif #if !defined(PATH_MAX) #define PATH_MAX 4096 #endif /* Size of the accepted socket queue */ #if !defined(MGSQLEN) #define MGSQLEN 20 #endif static const char *http_500_error = "Internal Server Error"; #if defined(NO_SSL_DL) #include #include #else /* SSL loaded dynamically from DLL. I put the prototypes here to be independent from OpenSSL source installation. */ typedef struct ssl_st SSL; typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_ctx_st SSL_CTX; struct ssl_func { const char *name; /* SSL function name */ void (*ptr)(void); /* Function pointer */ }; #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr) #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ const char *, int)) ssl_sw[11].ptr) #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ const char *, int)) ssl_sw[12].ptr) #define SSL_CTX_set_default_passwd_cb \ (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr) #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) #define SSL_CTX_use_certificate_chain_file \ (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) #define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr) #define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr) #define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr) #define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr) #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) #define CRYPTO_set_locking_callback \ (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) #define CRYPTO_set_id_callback \ (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr) #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr) /* set_ssl_option() function updates this array. It loads SSL library dynamically and changes NULLs to the actual addresses of respective functions. The macros above (like SSL_connect()) are really just calling these functions indirectly via the pointer. */ static struct ssl_func ssl_sw[] = { {"SSL_free", NULL}, {"SSL_accept", NULL}, {"SSL_connect", NULL}, {"SSL_read", NULL}, {"SSL_write", NULL}, {"SSL_get_error", NULL}, {"SSL_set_fd", NULL}, {"SSL_new", NULL}, {"SSL_CTX_new", NULL}, {"SSLv23_server_method", NULL}, {"SSL_library_init", NULL}, {"SSL_CTX_use_PrivateKey_file", NULL}, {"SSL_CTX_use_certificate_file",NULL}, {"SSL_CTX_set_default_passwd_cb",NULL}, {"SSL_CTX_free", NULL}, {"SSL_load_error_strings", NULL}, {"SSL_CTX_use_certificate_chain_file", NULL}, {"SSLv23_client_method", NULL}, {"SSL_pending", NULL}, {"SSL_CTX_set_verify", NULL}, {"SSL_shutdown", NULL}, {NULL, NULL} }; /* Similar array as ssl_sw. These functions could be located in different lib. */ #if !defined(NO_SSL) static struct ssl_func crypto_sw[] = { {"CRYPTO_num_locks", NULL}, {"CRYPTO_set_locking_callback", NULL}, {"CRYPTO_set_id_callback", NULL}, {"ERR_get_error", NULL}, {"ERR_error_string", NULL}, {NULL, NULL} }; #endif /* NO_SSL */ #endif /* NO_SSL_DL */ static const char *month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* Unified socket address. For IPv6 support, add IPv6 address structure in the union u. */ union usa { struct sockaddr sa; struct sockaddr_in sin; #if defined(USE_IPV6) struct sockaddr_in6 sin6; #endif }; /* Describes a string (chunk of memory). */ struct vec { const char *ptr; size_t len; }; struct file { int is_directory; time_t modification_time; int64_t size; FILE *fp; const char *membuf; /* Non-NULL if file data is in memory */ /* set to 1 if the content is gzipped in which case we need a content-encoding: gzip header */ int gzipped; }; #define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0} /* Describes listening socket, or socket which was accept()-ed by the master thread and queued for future handling by the worker thread. */ struct socket { SOCKET sock; /* Listening socket */ union usa lsa; /* Local socket address */ union usa rsa; /* Remote socket address */ unsigned is_ssl:1; /* Is port SSL-ed */ unsigned ssl_redir:1; /* Is port supposed to redirect everything to SSL port */ }; /* NOTE(lsm): this enum shoulds be in sync with the config_options below. */ enum { CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE, ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT, DECODE_URL, #if defined(USE_LUA) LUA_PRELOAD_FILE, LUA_SCRIPT_EXTENSIONS, LUA_SERVER_PAGE_EXTENSIONS, #endif #if defined(USE_WEBSOCKET) WEBSOCKET_ROOT, #endif #if defined(USE_LUA) && defined(USE_WEBSOCKET) LUA_WEBSOCKET_EXTENSIONS, #endif ACCESS_CONTROL_ALLOW_ORIGIN, ERROR_PAGES, NUM_OPTIONS }; /* TODO: replace 12345 by proper config types */ static struct mg_option config_options[] = { {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"}, {"cgi_environment", CONFIG_TYPE_STRING, NULL}, {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL}, {"cgi_interpreter", CONFIG_TYPE_FILE, NULL}, {"protect_uri", 12345, NULL}, {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"}, {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"}, {"throttle", 12345, NULL}, {"access_log_file", CONFIG_TYPE_FILE, NULL}, {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"}, {"error_log_file", CONFIG_TYPE_FILE, NULL}, {"global_auth_file", CONFIG_TYPE_FILE, NULL}, {"index_files", 12345, #ifdef USE_LUA "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,index.shtml,index.php"}, #else "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"}, #endif {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"}, {"access_control_list", 12345, NULL}, {"extra_mime_types", 12345, NULL}, {"listening_ports", 12345, "8080"}, {"document_root", CONFIG_TYPE_DIRECTORY, NULL}, {"ssl_certificate", CONFIG_TYPE_FILE, NULL}, {"num_threads", CONFIG_TYPE_NUMBER, "50"}, {"run_as_user", CONFIG_TYPE_STRING, NULL}, {"url_rewrite_patterns", 12345, NULL}, {"hide_files_patterns", 12345, NULL}, {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"}, {"decode_url", CONFIG_TYPE_BOOLEAN, "yes"}, #if defined(USE_LUA) {"lua_preload_file", CONFIG_TYPE_FILE, NULL}, {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"}, #endif #if defined(USE_WEBSOCKET) {"websocket_root", CONFIG_TYPE_DIRECTORY, NULL}, #endif #if defined(USE_LUA) && defined(USE_WEBSOCKET) {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, #endif {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"}, {"error_pages", CONFIG_TYPE_DIRECTORY, NULL}, {NULL, CONFIG_TYPE_UNKNOWN, NULL} }; struct mg_request_handler_info { char *uri; size_t uri_len; mg_request_handler handler; void *cbdata; struct mg_request_handler_info *next; }; struct mg_context { volatile int stop_flag; /* Should we stop event loop */ void *ssllib_dll_handle; /* Store the ssl library handle. */ void *cryptolib_dll_handle; /* Store the crypto library handle. */ SSL_CTX *ssl_ctx; /* SSL context */ char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */ struct mg_callbacks callbacks; /* User-defined callback function */ void *user_data; /* User-defined data */ struct socket *listening_sockets; in_port_t *listening_ports; int num_listening_sockets; volatile int num_threads; /* Number of threads */ pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */ pthread_cond_t thread_cond; /* Condvar for tracking workers terminations */ struct socket queue[MGSQLEN]; /* Accepted sockets */ volatile int sq_head; /* Head of the socket queue */ volatile int sq_tail; /* Tail of the socket queue */ pthread_cond_t sq_full; /* Signaled when socket is produced */ pthread_cond_t sq_empty; /* Signaled when socket is consumed */ pthread_t masterthreadid; /* The master thread ID */ int workerthreadcount; /* The amount of worker threads. */ pthread_t *workerthreadids; /* The worker thread IDs */ unsigned long start_time; /* Server start time, used for authentication */ pthread_mutex_t nonce_mutex; /* Protects nonce_count */ unsigned long nonce_count; /* Used nonces, used for authentication */ char *systemName; /* What operating system is running */ /* linked list of uri handlers */ struct mg_request_handler_info *request_handlers; #if defined(USE_LUA) && defined(USE_WEBSOCKET) /* linked list of shared lua websockets */ struct mg_shared_lua_websocket_list *shared_lua_websockets; #endif #ifdef USE_TIMERS struct timers * timers; #endif }; struct mg_connection { struct mg_request_info request_info; struct mg_context *ctx; SSL *ssl; /* SSL descriptor */ SSL_CTX *client_ssl_ctx; /* SSL context for client connections */ struct socket client; /* Connected client */ time_t birth_time; /* Time when request was received */ int64_t num_bytes_sent; /* Total bytes sent to client */ int64_t content_len; /* Content-Length header value */ int64_t consumed_content; /* How many bytes of content have been read */ char *buf; /* Buffer for received data */ char *path_info; /* PATH_INFO part of the URL */ int must_close; /* 1 if connection must be closed */ int in_error_handler; /* 1 if in handler for user defined error pages */ int buf_size; /* Buffer size */ int request_len; /* Size of the request + headers in a buffer */ int data_len; /* Total size of data in a buffer */ int status_code; /* HTTP reply status code, e.g. 200 */ int throttle; /* Throttling, bytes/sec. <= 0 means no throttle */ time_t last_throttle_time; /* Last time throttled data was sent */ int64_t last_throttle_bytes; /* Bytes sent this second */ pthread_mutex_t mutex; /* Used by mg_lock_connection/mg_unlock_connection to ensure atomic transmissions for websockets */ #if defined(USE_LUA) && defined(USE_WEBSOCKET) void * lua_websocket_state; /* Lua_State for a websocket connection */ #endif int is_chunked; /* transfer-encoding is chunked */ }; static pthread_key_t sTlsKey; /* Thread local storage index */ static int sTlsInit = 0; struct mg_workerTLS { int is_master; #if defined(_WIN32) && !defined(__SYMBIAN32__) HANDLE pthread_cond_helper_mutex; #endif }; /* Directory entry */ struct de { struct mg_connection *conn; char *file_name; struct file file; }; #if defined(USE_WEBSOCKET) static int is_websocket_request(const struct mg_connection *conn); #endif #if defined(MG_LEGACY_INTERFACE) const char **mg_get_valid_option_names(void) { static const char * data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0}; int i; for (i=0; config_options[i].name != NULL; i++) { data[i * 2] = config_options[i].name; data[i * 2 + 1] = config_options[i].default_value; } return data; } #endif const struct mg_option *mg_get_valid_options(void) { return config_options; } static int is_file_in_memory(struct mg_connection *conn, const char *path, struct file *filep) { size_t size = 0; if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL : conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) { /* NOTE: override filep->size only on success. Otherwise, it might break constructs like if (!mg_stat() || !mg_fopen()) ... */ filep->size = size; } return filep->membuf != NULL; } static int is_file_opened(const struct file *filep) { return filep->membuf != NULL || filep->fp != NULL; } static int mg_fopen(struct mg_connection *conn, const char *path, const char *mode, struct file *filep) { if (!is_file_in_memory(conn, path, filep)) { #ifdef _WIN32 wchar_t wbuf[PATH_MAX], wmode[20]; to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); filep->fp = _wfopen(wbuf, wmode); #else filep->fp = fopen(path, mode); #endif } return is_file_opened(filep); } static void mg_fclose(struct file *filep) { if (filep != NULL && filep->fp != NULL) { fclose(filep->fp); } } static void mg_strlcpy(register char *dst, register const char *src, size_t n) { for (; *src != '\0' && n > 1; n--) { *dst++ = *src++; } *dst = '\0'; } static int lowercase(const char *s) { return tolower(* (const unsigned char *) s); } int mg_strncasecmp(const char *s1, const char *s2, size_t len) { int diff = 0; if (len > 0) do { diff = lowercase(s1++) - lowercase(s2++); } while (diff == 0 && s1[-1] != '\0' && --len > 0); return diff; } static int mg_strcasecmp(const char *s1, const char *s2) { int diff; do { diff = lowercase(s1++) - lowercase(s2++); } while (diff == 0 && s1[-1] != '\0'); return diff; } static char * mg_strndup(const char *ptr, size_t len) { char *p; if ((p = (char *) mg_malloc(len + 1)) != NULL) { mg_strlcpy(p, ptr, len + 1); } return p; } static char * mg_strdup(const char *str) { return mg_strndup(str, strlen(str)); } static const char *mg_strcasestr(const char *big_str, const char *small_str) { int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str); for (i = 0; i <= big_len - small_len; i++) { if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) { return big_str + i; } } return NULL; } /* Like snprintf(), but never returns negative value, or a value that is larger than a supplied buffer. Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability in his audit report. */ static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, va_list ap) { int n; if (buflen == 0) return 0; n = vsnprintf(buf, buflen, fmt, ap); if (n < 0) { mg_cry(conn, "vsnprintf error"); n = 0; } else if (n >= (int) buflen) { mg_cry(conn, "truncating vsnprintf buffer: [%.*s]", n > 200 ? 200 : n, buf); n = (int) buflen - 1; } buf[n] = '\0'; return n; } static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, ...) { va_list ap; int n; va_start(ap, fmt); n = mg_vsnprintf(conn, buf, buflen, fmt, ap); va_end(ap); return n; } static int get_option_index(const char *name) { int i; for (i = 0; config_options[i].name != NULL; i++) { if (strcmp(config_options[i].name, name) == 0) { return i; } } return -1; } const char *mg_get_option(const struct mg_context *ctx, const char *name) { int i; if ((i = get_option_index(name)) == -1) { return NULL; } else if (ctx->config[i] == NULL) { return ""; } else { return ctx->config[i]; } } size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl) { size_t i; for (i = 0; i < size && i < (size_t)ctx->num_listening_sockets; i++) { ssl[i] = ctx->listening_sockets[i].is_ssl; ports[i] = ctx->listening_ports[i]; } return i; } static void sockaddr_to_string(char *buf, size_t len, const union usa *usa) { buf[0] = '\0'; #if defined(USE_IPV6) inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ? (void *) &usa->sin.sin_addr : (void *) &usa->sin6.sin6_addr, buf, len); #elif defined(_WIN32) /* Only Windows Vista (and newer) have inet_ntop() */ mg_strlcpy(buf, inet_ntoa(usa->sin.sin_addr), len); #else inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len); #endif } /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be included in all responses other than 100, 101, 5xx. */ static void gmt_time_string(char *buf, size_t buf_len, time_t *t) { struct tm *tm; tm = gmtime(t); if (tm != NULL) { strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm); } else { mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len); buf[buf_len - 1] = '\0'; } } /* Print error message to the opened error log stream. */ void mg_cry(struct mg_connection *conn, const char *fmt, ...) { char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN]; va_list ap; FILE *fp; time_t timestamp; va_start(ap, fmt); IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap)); va_end(ap); /* Do not lock when getting the callback value, here and below. I suppose this is fine, since function cannot disappear in the same way string option can. */ if (conn->ctx->callbacks.log_message == NULL || conn->ctx->callbacks.log_message(conn, buf) == 0) { fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); if (fp != NULL) { flockfile(fp); timestamp = time(NULL); sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp, src_addr); if (conn->request_info.request_method != NULL) { fprintf(fp, "%s %s: ", conn->request_info.request_method, conn->request_info.uri); } fprintf(fp, "%s", buf); fputc('\n', fp); funlockfile(fp); fclose(fp); } } } /* Return fake connection structure. Used for logging, if connection is not applicable at the moment of logging. */ static struct mg_connection *fc(struct mg_context *ctx) { static struct mg_connection fake_connection; fake_connection.ctx = ctx; return &fake_connection; } const char *mg_version(void) { return CIVETWEB_VERSION; } struct mg_request_info *mg_get_request_info(struct mg_connection *conn) { return &conn->request_info; } /* Skip the characters until one of the delimiters characters found. 0-terminate resulting word. Skip the delimiter and following whitespaces. Advance pointer to buffer to the next word. Return found 0-terminated word. Delimiters can be quoted with quotechar. */ static char *skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar) { char *p, *begin_word, *end_word, *end_whitespace; begin_word = *buf; end_word = begin_word + strcspn(begin_word, delimiters); /* Check for quotechar */ if (end_word > begin_word) { p = end_word - 1; while (*p == quotechar) { /* If there is anything beyond end_word, copy it */ if (*end_word == '\0') { *p = '\0'; break; } else { size_t end_off = strcspn(end_word + 1, delimiters); memmove (p, end_word, end_off + 1); p += end_off; /* p must correspond to end_word - 1 */ end_word += end_off + 1; } } for (p++; p < end_word; p++) { *p = '\0'; } } if (*end_word == '\0') { *buf = end_word; } else { end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); for (p = end_word; p < end_whitespace; p++) { *p = '\0'; } *buf = end_whitespace; } return begin_word; } /* Simplified version of skip_quoted without quote char and whitespace == delimiters */ static char *skip(char **buf, const char *delimiters) { return skip_quoted(buf, delimiters, delimiters, 0); } /* Return HTTP header value, or NULL if not found. */ static const char *get_header(const struct mg_request_info *ri, const char *name) { int i; for (i = 0; i < ri->num_headers; i++) if (!mg_strcasecmp(name, ri->http_headers[i].name)) return ri->http_headers[i].value; return NULL; } const char *mg_get_header(const struct mg_connection *conn, const char *name) { return get_header(&conn->request_info, name); } /* A helper function for traversing a comma separated list of values. It returns a list pointer shifted to the next value, or NULL if the end of the list found. Value is stored in val vector. If value has form "x=y", then eq_val vector is initialized to point to the "y" part, and val vector length is adjusted to point only to "x". */ static const char *next_option(const char *list, struct vec *val, struct vec *eq_val) { if (list == NULL || *list == '\0') { /* End of the list */ list = NULL; } else { val->ptr = list; if ((list = strchr(val->ptr, ',')) != NULL) { /* Comma found. Store length and shift the list ptr */ val->len = list - val->ptr; list++; } else { /* This value is the last one */ list = val->ptr + strlen(val->ptr); val->len = list - val->ptr; } if (eq_val != NULL) { /* Value has form "x=y", adjust pointers and lengths so that val points to "x", and eq_val points to "y". */ eq_val->len = 0; eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len); if (eq_val->ptr != NULL) { eq_val->ptr++; /* Skip over '=' character */ eq_val->len = val->ptr + val->len - eq_val->ptr; val->len = (eq_val->ptr - val->ptr) - 1; } } } return list; } /* Perform case-insensitive match of string against pattern */ static int match_prefix(const char *pattern, int pattern_len, const char *str) { const char *or_str; int i, j, len, res; if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) { res = match_prefix(pattern, (int)(or_str - pattern), str); return res > 0 ? res : match_prefix(or_str + 1, (int)((pattern + pattern_len) - (or_str + 1)), str); } i = j = 0; for (; i < pattern_len; i++, j++) { if (pattern[i] == '?' && str[j] != '\0') { continue; } else if (pattern[i] == '$') { return str[j] == '\0' ? j : -1; } else if (pattern[i] == '*') { i++; if (pattern[i] == '*') { i++; len = (int) strlen(str + j); } else { len = (int) strcspn(str + j, "/"); } if (i == pattern_len) { return j + len; } do { res = match_prefix(pattern + i, pattern_len - i, str + j + len); } while (res == -1 && len-- > 0); return res == -1 ? -1 : j + res + len; } else if (lowercase(&pattern[i]) != lowercase(&str[j])) { return -1; } } return j; } /* HTTP 1.1 assumes keep alive if "Connection:" header is not set This function must tolerate situations when connection info is not set up, for example if request parsing failed. */ static int should_keep_alive(const struct mg_connection *conn) { const char *http_version = conn->request_info.http_version; const char *header = mg_get_header(conn, "Connection"); if (conn->must_close || conn->status_code == 401 || mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 || (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) || (header == NULL && http_version && 0!=strcmp(http_version, "1.1"))) { return 0; } return 1; } static int should_decode_url(const struct mg_connection *conn) { return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0); } static const char *suggest_connection_header(const struct mg_connection *conn) { return should_keep_alive(conn) ? "keep-alive" : "close"; } static void handle_file_based_request(struct mg_connection *conn, const char *path, struct file *filep); static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep); static void send_http_error(struct mg_connection *, int, const char *, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); static void send_http_error(struct mg_connection *conn, int status, const char *reason, const char *fmt, ...) { char buf[MG_BUF_LEN]; va_list ap; int len = 0, i, page_handler_found, scope; char date[64]; time_t curtime = time(NULL); const char *error_handler = NULL; struct file error_page_file = STRUCT_FILE_INITIALIZER; const char *error_page_file_ext, *tstr; conn->status_code = status; if (conn->in_error_handler || conn->ctx->callbacks.http_error == NULL || conn->ctx->callbacks.http_error(conn, status)) { if (!conn->in_error_handler) { /* Send user defined error pages, if defined */ error_handler = conn->ctx->config[ERROR_PAGES]; error_page_file_ext = conn->ctx->config[INDEX_FILES]; page_handler_found = 0; if (error_handler != NULL) { for (scope=1; (scope<=3) && !page_handler_found; scope++) { switch (scope) { case 1: len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror%03u.", error_handler, status); break; case 2: len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror%01uxx.", error_handler, status/100); break; default: len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror.", error_handler); break; } tstr = strchr(error_page_file_ext, '.'); while (tstr) { for (i=1; i<32 && tstr[i]!=0 && tstr[i]!=','; i++) buf[len+i-1]=tstr[i]; buf[len+i-1]=0; if (mg_stat(conn, buf, &error_page_file)) { page_handler_found = 1; break; } tstr = strchr(tstr+i, '.'); } } } if (page_handler_found) { conn->in_error_handler = 1; handle_file_based_request(conn, buf, &error_page_file); conn->in_error_handler = 0; return; } } buf[0] = '\0'; gmt_time_string(date, sizeof(date), &curtime); /* Errors 1xx, 204 and 304 MUST NOT send a body */ if (status > 199 && status != 204 && status != 304) { len = mg_snprintf(conn, buf, sizeof(buf)-1, "Error %d: %s", status, reason); buf[len] = '\n'; len++; buf[len] = 0; va_start(ap, fmt); len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap); va_end(ap); } DEBUG_TRACE("[%s]", buf); mg_printf(conn, "HTTP/1.1 %d %s\r\n" "Content-Length: %d\r\n" "Date: %s\r\n" "Connection: %s\r\n\r\n", status, reason, len, date, suggest_connection_header(conn)); conn->num_bytes_sent += mg_printf(conn, "%s", buf); } } #if defined(_WIN32) && !defined(__SYMBIAN32__) static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) { (void) unused; *mutex = CreateMutex(NULL, FALSE, NULL); return *mutex == NULL ? -1 : 0; } static int pthread_mutex_destroy(pthread_mutex_t *mutex) { return CloseHandle(*mutex) == 0 ? -1 : 0; } static int pthread_mutex_lock(pthread_mutex_t *mutex) { return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1; } static int pthread_mutex_trylock(pthread_mutex_t *mutex) { switch (WaitForSingleObject(*mutex, 0)) { case WAIT_OBJECT_0: return 0; case WAIT_TIMEOUT: return -2; /* EBUSY */ } return -1; } static int pthread_mutex_unlock(pthread_mutex_t *mutex) { return ReleaseMutex(*mutex) == 0 ? -1 : 0; } #ifndef WIN_PTHREADS_TIME_H static int clock_gettime(clockid_t clk_id, struct timespec *tp) { FILETIME ft; ULARGE_INTEGER li; BOOL ok = FALSE; double d; static double perfcnt_per_sec = 0.0; if (tp) { if (clk_id == CLOCK_REALTIME) { GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */ tp->tv_sec = (time_t)(li.QuadPart / 10000000); tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; ok = TRUE; } else if (clk_id == CLOCK_MONOTONIC) { if (perfcnt_per_sec == 0.0) { QueryPerformanceFrequency((LARGE_INTEGER *) &li); perfcnt_per_sec = 1.0 / li.QuadPart; } if (perfcnt_per_sec != 0.0) { QueryPerformanceCounter((LARGE_INTEGER *) &li); d = li.QuadPart * perfcnt_per_sec; tp->tv_sec = (time_t)d; d -= tp->tv_sec; tp->tv_nsec = (long)(d*1.0E9); ok = TRUE; } } } return ok ? 0 : -1; } #endif static int pthread_cond_init(pthread_cond_t *cv, const void *unused) { (void) unused; InitializeCriticalSection(&cv->threadIdSec); cv->waitingthreadcount = 0; cv->waitingthreadhdls = mg_calloc(MAX_WORKER_THREADS, sizeof(pthread_t)); return (cv->waitingthreadhdls!=NULL) ? 0 : -1; } static int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec * abstime) { struct mg_workerTLS * tls = (struct mg_workerTLS *)TlsGetValue(sTlsKey); int ok; struct timespec tsnow; int64_t nsnow, nswaitabs, nswaitrel; DWORD mswaitrel; EnterCriticalSection(&cv->threadIdSec); assert(cv->waitingthreadcount < MAX_WORKER_THREADS); cv->waitingthreadhdls[cv->waitingthreadcount] = tls->pthread_cond_helper_mutex; cv->waitingthreadcount++; LeaveCriticalSection(&cv->threadIdSec); if (abstime) { clock_gettime(CLOCK_REALTIME, &tsnow); nsnow = (((uint64_t)tsnow.tv_sec)<<32) + tsnow.tv_nsec; nswaitabs = (((uint64_t)abstime->tv_sec)<<32) + abstime->tv_nsec; nswaitrel = nswaitabs - nsnow; if (nswaitrel<0) nswaitrel=0; mswaitrel = (DWORD)(nswaitrel / 1000000); } else { mswaitrel = INFINITE; } pthread_mutex_unlock(mutex); ok = (WAIT_OBJECT_0 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel)); pthread_mutex_lock(mutex); return ok ? 0 : -1; } static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) { return pthread_cond_timedwait(cv, mutex, NULL); } static int pthread_cond_signal(pthread_cond_t *cv) { int i; HANDLE wkup = NULL; BOOL ok = FALSE; EnterCriticalSection(&cv->threadIdSec); if (cv->waitingthreadcount) { wkup = cv->waitingthreadhdls[0]; ok = SetEvent(wkup); for (i=1; iwaitingthreadcount; i++) { cv->waitingthreadhdls[i-1] = cv->waitingthreadhdls[i]; } cv->waitingthreadcount--; assert(ok); } LeaveCriticalSection(&cv->threadIdSec); return ok ? 0 : 1; } static int pthread_cond_broadcast(pthread_cond_t *cv) { EnterCriticalSection(&cv->threadIdSec); while (cv->waitingthreadcount) { pthread_cond_signal(cv); } LeaveCriticalSection(&cv->threadIdSec); return 0; } static int pthread_cond_destroy(pthread_cond_t *cv) { EnterCriticalSection(&cv->threadIdSec); assert(cv->waitingthreadcount==0); mg_free(cv->waitingthreadhdls); cv->waitingthreadhdls = 0; LeaveCriticalSection(&cv->threadIdSec); DeleteCriticalSection(&cv->threadIdSec); return 0; } /* For Windows, change all slashes to backslashes in path names. */ static void change_slashes_to_backslashes(char *path) { int i; for (i = 0; path[i] != '\0'; i++) { if (path[i] == '/') path[i] = '\\'; /* i > 0 check is to preserve UNC paths, like \\server\file.txt */ if (path[i] == '\\' && i > 0) while (path[i + 1] == '\\' || path[i + 1] == '/') (void) memmove(path + i + 1, path + i + 2, strlen(path + i + 1)); } } /* Encode 'path' which is assumed UTF-8 string, into UNICODE string. wbuf and wbuf_len is a target buffer and its length. */ static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) { char buf[PATH_MAX], buf2[PATH_MAX]; mg_strlcpy(buf, path, sizeof(buf)); change_slashes_to_backslashes(buf); /* Convert to Unicode and back. If doubly-converted string does not match the original, something is fishy, reject. */ memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), NULL, NULL); if (strcmp(buf, buf2) != 0) { wbuf[0] = L'\0'; } } #if defined(_WIN32_WCE) static time_t time(time_t *ptime) { time_t t; SYSTEMTIME st; FILETIME ft; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); if (ptime != NULL) { *ptime = t; } return t; } static struct tm *localtime(const time_t *ptime, struct tm *ptm) { int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF; FILETIME ft, lft; SYSTEMTIME st; TIME_ZONE_INFORMATION tzinfo; if (ptm == NULL) { return NULL; } * (int64_t *) &ft = t; FileTimeToLocalFileTime(&ft, &lft); FileTimeToSystemTime(&lft, &st); ptm->tm_year = st.wYear - 1900; ptm->tm_mon = st.wMonth - 1; ptm->tm_wday = st.wDayOfWeek; ptm->tm_mday = st.wDay; ptm->tm_hour = st.wHour; ptm->tm_min = st.wMinute; ptm->tm_sec = st.wSecond; ptm->tm_yday = 0; /* hope nobody uses this */ ptm->tm_isdst = GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0; return ptm; } static struct tm *gmtime(const time_t *ptime, struct tm *ptm) { /* FIXME(lsm): fix this. */ return localtime(ptime, ptm); } static size_t strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm) { (void) snprintf(dst, dst_size, "implement strftime() for WinCE"); return 0; } #endif /* Windows happily opens files with some garbage at the end of file name. For example, fopen("a.cgi ", "r") on Windows successfully opens "a.cgi", despite one would expect an error back. This function returns non-0 if path ends with some garbage. */ static int path_cannot_disclose_cgi(const char *path) { static const char *allowed_last_characters = "_-"; int last = path[strlen(path) - 1]; return isalnum(last) || strchr(allowed_last_characters, last) != NULL; } static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep) { wchar_t wbuf[PATH_MAX]; WIN32_FILE_ATTRIBUTE_DATA info; if (!is_file_in_memory(conn, path, filep)) { to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) { filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh); filep->modification_time = SYS2UNIX_TIME( info.ftLastWriteTime.dwLowDateTime, info.ftLastWriteTime.dwHighDateTime); filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; /* If file name is fishy, reset the file structure and return error. Note it is important to reset, not just return the error, cause functions like is_file_opened() check the struct. */ if (!filep->is_directory && !path_cannot_disclose_cgi(path)) { memset(filep, 0, sizeof(*filep)); } } } return filep->membuf != NULL || filep->modification_time != 0; } static int mg_remove(const char *path) { wchar_t wbuf[PATH_MAX]; to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); return DeleteFileW(wbuf) ? 0 : -1; } static int mg_mkdir(const char *path, int mode) { char buf[PATH_MAX]; wchar_t wbuf[PATH_MAX]; (void) mode; mg_strlcpy(buf, path, sizeof(buf)); change_slashes_to_backslashes(buf); (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf)); return CreateDirectoryW(wbuf, NULL) ? 0 : -1; } /* Implementation of POSIX opendir/closedir/readdir for Windows. */ static DIR * opendir(const char *name) { DIR *dir = NULL; wchar_t wpath[PATH_MAX]; DWORD attrs; if (name == NULL) { SetLastError(ERROR_BAD_ARGUMENTS); } else if ((dir = (DIR *) mg_malloc(sizeof(*dir))) == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); } else { to_unicode(name, wpath, ARRAY_SIZE(wpath)); attrs = GetFileAttributesW(wpath); if (attrs != 0xFFFFFFFF && ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { (void) wcscat(wpath, L"\\*"); dir->handle = FindFirstFileW(wpath, &dir->info); dir->result.d_name[0] = '\0'; } else { mg_free(dir); dir = NULL; } } return dir; } static int closedir(DIR *dir) { int result = 0; if (dir != NULL) { if (dir->handle != INVALID_HANDLE_VALUE) result = FindClose(dir->handle) ? 0 : -1; mg_free(dir); } else { result = -1; SetLastError(ERROR_BAD_ARGUMENTS); } return result; } static struct dirent *readdir(DIR *dir) { struct dirent *result = 0; if (dir) { if (dir->handle != INVALID_HANDLE_VALUE) { result = &dir->result; (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1, result->d_name, sizeof(result->d_name), NULL, NULL); if (!FindNextFileW(dir->handle, &dir->info)) { (void) FindClose(dir->handle); dir->handle = INVALID_HANDLE_VALUE; } } else { SetLastError(ERROR_FILE_NOT_FOUND); } } else { SetLastError(ERROR_BAD_ARGUMENTS); } return result; } #ifndef HAVE_POLL static int poll(struct pollfd *pfd, int n, int milliseconds) { struct timeval tv; fd_set set; int i, result; SOCKET maxfd = 0; tv.tv_sec = milliseconds / 1000; tv.tv_usec = (milliseconds % 1000) * 1000; FD_ZERO(&set); for (i = 0; i < n; i++) { FD_SET((SOCKET) pfd[i].fd, &set); pfd[i].revents = 0; if (pfd[i].fd > maxfd) { maxfd = pfd[i].fd; } } if ((result = select((int)maxfd + 1, &set, NULL, NULL, &tv)) > 0) { for (i = 0; i < n; i++) { if (FD_ISSET(pfd[i].fd, &set)) { pfd[i].revents = POLLIN; } } } return result; } #endif /* HAVE_POLL */ static void set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */) { (void) conn; /* Unused. */ (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); } int mg_start_thread(mg_thread_func_t f, void *p) { #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 */ return ((_beginthread((void (__cdecl *)(void *)) f, USE_STACK_SIZE, p) == ((uintptr_t)(-1L))) ? -1 : 0); #else return ((_beginthread((void (__cdecl *)(void *)) f, 0, p) == ((uintptr_t)(-1L))) ? -1 : 0); #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */ } /* Start a thread storing the thread context. */ static int mg_start_thread_with_id(unsigned (__stdcall *f)(void *), void *p, pthread_t *threadidptr) { uintptr_t uip; HANDLE threadhandle; int result = -1; uip = _beginthreadex(NULL, 0, (unsigned (__stdcall *)(void *)) f, p, 0, NULL); threadhandle = (HANDLE) uip; if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) { *threadidptr = threadhandle; result = 0; } return result; } /* Wait for a thread to finish. */ static int mg_join_thread(pthread_t threadid) { int result; DWORD dwevent; result = -1; dwevent = WaitForSingleObject(threadid, INFINITE); if (dwevent == WAIT_FAILED) { int err; err = GetLastError(); DEBUG_TRACE("WaitForSingleObject() failed, error %d", err); } else { if (dwevent == WAIT_OBJECT_0) { CloseHandle(threadid); result = 0; } } return result; } static HANDLE dlopen(const char *dll_name, int flags) { wchar_t wbuf[PATH_MAX]; (void) flags; to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf)); return LoadLibraryW(wbuf); } static int dlclose(void *handle) { int result; if (FreeLibrary(handle) != 0) { result = 0; } else { result = -1; } return result; } #if !defined(NO_CGI) #define SIGKILL 0 static int kill(pid_t pid, int sig_num) { (void) TerminateProcess(pid, sig_num); (void) CloseHandle(pid); return 0; } static void trim_trailing_whitespaces(char *s) { char *e = s + strlen(s) - 1; while (e > s && isspace(* (unsigned char *) e)) { *e-- = '\0'; } } static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin, int fdout, const char *dir) { HANDLE me; char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX], cmdline[PATH_MAX], buf[PATH_MAX]; struct file file = STRUCT_FILE_INITIALIZER; STARTUPINFOA si; PROCESS_INFORMATION pi = { 0 }; (void) envp; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); /* TODO(lsm): redirect CGI errors to the error log file */ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; me = GetCurrentProcess(); DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me, &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); /* If CGI file is a script, try to read the interpreter line */ interp = conn->ctx->config[CGI_INTERPRETER]; if (interp == NULL) { buf[0] = buf[1] = '\0'; /* Read the first line of the script into the buffer */ snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog); if (mg_fopen(conn, cmdline, "r", &file)) { p = (char *) file.membuf; mg_fgets(buf, sizeof(buf), &file, &p); mg_fclose(&file); buf[sizeof(buf) - 1] = '\0'; } if (buf[0] == '#' && buf[1] == '!') { trim_trailing_whitespaces(buf + 2); } else { buf[2] = '\0'; } interp = buf + 2; } if (interp[0] != '\0') { GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL); interp = full_interp; } GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL); mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"", interp, interp[0] == '\0' ? "" : " ", full_dir, prog); DEBUG_TRACE("Running [%s]", cmdline); if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) { mg_cry(conn, "%s: CreateProcess(%s): %ld", __func__, cmdline, ERRNO); pi.hProcess = (pid_t) -1; } (void) CloseHandle(si.hStdOutput); (void) CloseHandle(si.hStdInput); if (pi.hThread != NULL) (void) CloseHandle(pi.hThread); return (pid_t) pi.hProcess; } #endif /* !NO_CGI */ static int set_non_blocking_mode(SOCKET sock) { unsigned long on = 1; return ioctlsocket(sock, FIONBIO, &on); } #else static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep) { struct stat st; if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) { filep->size = st.st_size; filep->modification_time = st.st_mtime; filep->is_directory = S_ISDIR(st.st_mode); } else { filep->modification_time = (time_t) 0; } return filep->membuf != NULL || filep->modification_time != (time_t) 0; } static void set_close_on_exec(int fd, struct mg_connection *conn /* may be null */) { if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { if (conn) { mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", __func__, strerror(ERRNO)); } } } int mg_start_thread(mg_thread_func_t func, void *param) { pthread_t thread_id; pthread_attr_t attr; int result; (void) pthread_attr_init(&attr); (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 */ (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE); #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */ result = pthread_create(&thread_id, &attr, func, param); pthread_attr_destroy(&attr); return result; } /* Start a thread storing the thread context. */ static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr) { pthread_t thread_id; pthread_attr_t attr; int result; (void) pthread_attr_init(&attr); #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 */ (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE); #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */ result = pthread_create(&thread_id, &attr, func, param); pthread_attr_destroy(&attr); if (threadidptr != NULL) { *threadidptr = thread_id; } return result; } /* Wait for a thread to finish. */ static int mg_join_thread(pthread_t threadid) { int result; result = pthread_join(threadid, NULL); return result; } #ifndef NO_CGI static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin, int fdout, const char *dir) { pid_t pid; const char *interp; (void) envblk; if ((pid = fork()) == -1) { /* Parent */ send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO)); } else if (pid == 0) { /* Child */ if (chdir(dir) != 0) { mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO)); } else if (dup2(fdin, 0) == -1) { mg_cry(conn, "%s: dup2(%d, 0): %s", __func__, fdin, strerror(ERRNO)); } else if (dup2(fdout, 1) == -1) { mg_cry(conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO)); } else { /* Not redirecting stderr to stdout, to avoid output being littered with the error messages. */ (void) close(fdin); (void) close(fdout); /* After exec, all signal handlers are restored to their default values, with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will leave unchanged after exec if it was set to be ignored. Restore it to default action. */ signal(SIGCHLD, SIG_DFL); interp = conn->ctx->config[CGI_INTERPRETER]; if (interp == NULL) { (void) execle(prog, prog, NULL, envp); mg_cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO)); } else { (void) execle(interp, interp, prog, NULL, envp); mg_cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog, strerror(ERRNO)); } } exit(EXIT_FAILURE); } return pid; } #endif /* !NO_CGI */ static int set_non_blocking_mode(SOCKET sock) { int flags; flags = fcntl(sock, F_GETFL, 0); (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK); return 0; } #endif /* _WIN32 */ /* Write data to the IO channel - opened file descriptor, socket or SSL descriptor. Return number of bytes written. */ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len) { int64_t sent; int n, k; (void) ssl; /* Get rid of warning */ sent = 0; while (sent < len) { /* How many bytes we send in this iteration */ k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent); #ifndef NO_SSL if (ssl != NULL) { n = SSL_write(ssl, buf + sent, k); } else #endif if (fp != NULL) { n = (int) fwrite(buf + sent, 1, (size_t) k, fp); if (ferror(fp)) n = -1; } else { n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL); } if (n <= 0) break; sent += n; } return sent; } /* Read from IO channel - opened file descriptor, socket, or SSL descriptor. Return negative value on error, or number of bytes read on success. */ static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) { int nread; if (fp != NULL) { /* Use read() instead of fread(), because if we're reading from the CGI pipe, fread() may block until IO buffer is filled up. We cannot afford to block and must pass all read bytes immediately to the client. */ nread = read(fileno(fp), buf, (size_t) len); #ifndef NO_SSL } else if (conn->ssl != NULL) { nread = SSL_read(conn->ssl, buf, len); #endif } else { nread = recv(conn->client.sock, buf, (size_t) len, 0); } return conn->ctx->stop_flag ? -1 : nread; } static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) { int n, nread = 0; while (len > 0 && conn->ctx->stop_flag == 0) { n = pull(fp, conn, buf + nread, len); if (n < 0) { nread = n; /* Propagate the error */ break; } else if (n == 0) { break; /* No more data to read */ } else { conn->consumed_content += n; nread += n; len -= n; } } return nread; } static void fast_forward_request(struct mg_connection *conn) { char buf[MG_BUF_LEN]; int to_read, nread; while (conn->consumed_content < conn->content_len) { to_read = sizeof(buf); if ((int64_t) to_read > conn->content_len - conn->consumed_content) { to_read = (int) (conn->content_len - conn->consumed_content); } nread = mg_read(conn, buf, to_read); if (nread <= 0) { break; } } } int mg_read_inner(struct mg_connection *conn, void *buf, size_t len) { int64_t n, buffered_len, nread; const char *body; /* If Content-Length is not set for a PUT or POST request, read until socket is closed */ if (conn->consumed_content == 0 && conn->content_len == -1) { conn->content_len = INT64_MAX; conn->must_close = 1; } nread = 0; if (conn->consumed_content < conn->content_len) { /* Adjust number of bytes to read. */ int64_t to_read = conn->content_len - conn->consumed_content; if (to_read < (int64_t) len) { len = (size_t) to_read; } /* Return buffered data */ body = conn->buf + conn->request_len + conn->consumed_content; buffered_len = (int64_t)(&conn->buf[conn->data_len] - body); if (buffered_len > 0) { if (len < (size_t) buffered_len) { buffered_len = (int64_t) len; } memcpy(buf, body, (size_t) buffered_len); len -= buffered_len; conn->consumed_content += buffered_len; nread += buffered_len; buf = (char *) buf + buffered_len; } /* We have returned all buffered data. Read new data from the remote socket. */ n = pull_all(NULL, conn, (char *) buf, (int64_t) len); nread = n >= 0 ? nread + n : n; } return nread; } static int mg_getc(struct mg_connection *conn) { char c; conn->content_len++; if ( mg_read_inner(conn,&c,1) <= 0 ) return EOF; return c; } int mg_read(struct mg_connection *conn, void *buf, size_t len) { if ( conn->is_chunked ) { if (conn->content_len <= 0 ) conn->content_len = 0; if (conn->consumed_content < conn->content_len) return mg_read_inner(conn,buf,len); int i = 0; char str[64]; while (1) { int c = mg_getc(conn); if (c == EOF) return EOF; if ( ! ( c == '\n' || c == '\r' ) ) { str[i++] = c; break; } } for (; i < (int)sizeof(str); i++) { int c = mg_getc(conn); if ( c == EOF ) return -1; str[i] = (char) c; if ( i > 0 && str[i] == '\n' && str[i-1] == '\r' ) break; } char *end = 0; long chunkSize = strtol(str,&end,16); if ( end != str+(i-1) ) return -1; if ( chunkSize == 0 ) return 0; conn->content_len += chunkSize; } return mg_read_inner(conn,buf,len); } int mg_write(struct mg_connection *conn, const void *buf, size_t len) { time_t now; int64_t n, total, allowed; if (conn->throttle > 0) { if ((now = time(NULL)) != conn->last_throttle_time) { conn->last_throttle_time = now; conn->last_throttle_bytes = 0; } allowed = conn->throttle - conn->last_throttle_bytes; if (allowed > (int64_t) len) { allowed = len; } if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf, (int64_t) allowed)) == allowed) { buf = (char *) buf + total; conn->last_throttle_bytes += total; while (total < (int64_t) len && conn->ctx->stop_flag == 0) { allowed = conn->throttle > (int64_t) len - total ? (int64_t) len - total : conn->throttle; if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf, (int64_t) allowed)) != allowed) { break; } sleep(1); conn->last_throttle_bytes = allowed; conn->last_throttle_time = time(NULL); buf = (char *) buf + n; total += n; } } } else { total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf, (int64_t) len); } return (int) total; } /* Alternative alloc_vprintf() for non-compliant C runtimes */ static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) { va_list ap_copy; int size = MG_BUF_LEN; int len = -1; *buf = NULL; while (len == -1) { if (*buf) mg_free(*buf); *buf = (char *)mg_malloc(size *= 4); if (!*buf) break; va_copy(ap_copy, ap); len = vsnprintf(*buf, size, fmt, ap_copy); va_end(ap_copy); } return len; } /* Print message to buffer. If buffer is large enough to hold the message, return buffer. If buffer is to small, allocate large enough buffer on heap, and return allocated buffer. */ static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) { va_list ap_copy; int len; /* Windows is not standard-compliant, and vsnprintf() returns -1 if buffer is too small. Also, older versions of msvcrt.dll do not have _vscprintf(). However, if size is 0, vsnprintf() behaves correctly. Therefore, we make two passes: on first pass, get required message length. On second pass, actually print the message. */ va_copy(ap_copy, ap); len = vsnprintf(NULL, 0, fmt, ap_copy); va_end(ap_copy); if (len < 0) { /* C runtime is not standard compliant, vsnprintf() returned -1. Switch to alternative code path that uses incremental allocations. */ va_copy(ap_copy, ap); len = alloc_vprintf2(buf, fmt, ap); va_end(ap_copy); } else if (len > (int) size && (size = len + 1) > 0 && (*buf = (char *) mg_malloc(size)) == NULL) { len = -1; /* Allocation failed, mark failure */ } else { va_copy(ap_copy, ap); IGNORE_UNUSED_RESULT(vsnprintf(*buf, size, fmt, ap_copy)); va_end(ap_copy); } return len; } int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap); int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) { char mem[MG_BUF_LEN], *buf = mem; int len; if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) { len = mg_write(conn, buf, (size_t) len); } if (buf != mem && buf != NULL) { mg_free(buf); } return len; } int mg_printf(struct mg_connection *conn, const char *fmt, ...) { va_list ap; int result; va_start(ap, fmt); result = mg_vprintf(conn, fmt, ap); va_end(ap); return result; } int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded) { int i, j, a, b; #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { if (i < src_len - 2 && src[i] == '%' && isxdigit(* (const unsigned char *) (src + i + 1)) && isxdigit(* (const unsigned char *) (src + i + 2))) { a = tolower(* (const unsigned char *) (src + i + 1)); b = tolower(* (const unsigned char *) (src + i + 2)); dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); i += 2; } else if (is_form_url_encoded && src[i] == '+') { dst[j] = ' '; } else { dst[j] = src[i]; } } dst[j] = '\0'; /* Null-terminate the destination */ return i >= src_len ? j : -1; } int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len) { return mg_get_var2(data,data_len,name,dst,dst_len,0); } int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence) { const char *p, *e, *s; size_t name_len; int len; if (dst == NULL || dst_len == 0) { len = -2; } else if (data == NULL || name == NULL || data_len == 0) { len = -1; dst[0] = '\0'; } else { name_len = strlen(name); e = data + data_len; len = -1; dst[0] = '\0'; /* data is "var1=val1&var2=val2...". Find variable first */ for (p = data; p + name_len < e; p++) { if ((p == data || p[-1] == '&') && p[name_len] == '=' && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) { /* Point p to variable value */ p += name_len + 1; /* Point s to the end of the value */ s = (const char *) memchr(p, '&', (size_t)(e - p)); if (s == NULL) { s = e; } assert(s >= p); /* Decode variable into destination buffer */ len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1); /* Redirect error code from -1 to -2 (destination buffer too small). */ if (len == -1) { len = -2; } break; } } } return len; } int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size) { const char *s, *p, *end; int name_len, len = -1; if (dst == NULL || dst_size == 0) { len = -2; } else if (var_name == NULL || (s = cookie_header) == NULL) { len = -1; dst[0] = '\0'; } else { name_len = (int) strlen(var_name); end = s + strlen(s); dst[0] = '\0'; for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) { if (s[name_len] == '=') { s += name_len + 1; if ((p = strchr(s, ' ')) == NULL) p = end; if (p[-1] == ';') p--; if (*s == '"' && p[-1] == '"' && p > s + 1) { s++; p--; } if ((size_t) (p - s) < dst_size) { len = (int)(p - s); mg_strlcpy(dst, s, (size_t) len + 1); } else { len = -3; } break; } } } return len; } #if defined(USE_WEBSOCKET) || defined(USE_LUA) static void base64_encode(const unsigned char *src, int src_len, char *dst) { static const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int i, j, a, b, c; for (i = j = 0; i < src_len; i += 3) { a = src[i]; b = i + 1 >= src_len ? 0 : src[i + 1]; c = i + 2 >= src_len ? 0 : src[i + 2]; dst[j++] = b64[a >> 2]; dst[j++] = b64[((a & 3) << 4) | (b >> 4)]; if (i + 1 < src_len) { dst[j++] = b64[(b & 15) << 2 | (c >> 6)]; } if (i + 2 < src_len) { dst[j++] = b64[c & 63]; } } while (j % 4 != 0) { dst[j++] = '='; } dst[j++] = '\0'; } static unsigned char b64reverse(char letter) { if (letter>='A' && letter<='Z') return letter-'A'; if (letter>='a' && letter<='z') return letter-'a'+26; if (letter>='0' && letter<='9') return letter-'0'+52; if (letter=='+') return 62; if (letter=='/') return 63; if (letter=='=') return 255; /* normal end */ return 254; /* error */ } static int base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len) { int i; unsigned char a, b, c, d; *dst_len = 0; for (i = 0; i < src_len; i += 4) { a = b64reverse(src[i]); if (a>=254) return i; b = b64reverse(i + 1 >= src_len ? 0 : src[i + 1]); if (b>=254) return i+1; c = b64reverse(i + 2 >= src_len ? 0 : src[i + 2]); if (c==254) return i+2; d = b64reverse(i + 3 >= src_len ? 0 : src[i + 3]); if (c==254) return i+3; dst[(*dst_len)++] = (a << 2) + (b >> 4); if (c!=255) { dst[(*dst_len)++] = (b << 4) + (c >> 2); if (d!=255) { dst[(*dst_len)++] = (c << 6) + d; } } } return -1; } #endif static void convert_uri_to_file_name(struct mg_connection *conn, char *buf, size_t buf_len, struct file *filep, int * is_script_ressource) { struct vec a, b; const char *rewrite, *uri = conn->request_info.uri, *root = conn->ctx->config[DOCUMENT_ROOT]; char *p; int match_len; char gz_path[PATH_MAX]; char const* accept_encoding; *is_script_ressource = 0; #if defined(USE_WEBSOCKET) if (is_websocket_request(conn) && conn->ctx->config[WEBSOCKET_ROOT]) { root = conn->ctx->config[WEBSOCKET_ROOT]; } #endif /* Using buf_len - 1 because memmove() for PATH_INFO may shift part of the path one byte on the right. If document_root is NULL, leave the file empty. */ mg_snprintf(conn, buf, buf_len - 1, "%s%s", root == NULL ? "" : root, root == NULL ? "" : uri); rewrite = conn->ctx->config[REWRITE]; while ((rewrite = next_option(rewrite, &a, &b)) != NULL) { if ((match_len = match_prefix(a.ptr, (int) a.len, uri)) > 0) { mg_snprintf(conn, buf, buf_len - 1, "%.*s%s", (int) b.len, b.ptr, uri + match_len); break; } } if (mg_stat(conn, buf, filep)) return; /* if we can't find the actual file, look for the file with the same name but a .gz extension. If we find it, use that and set the gzipped flag in the file struct to indicate that the response need to have the content- encoding: gzip header we can only do this if the browser declares support */ if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) { if (strstr(accept_encoding,"gzip") != NULL) { snprintf(gz_path, sizeof(gz_path), "%s.gz", buf); if (mg_stat(conn, gz_path, filep)) { filep->gzipped = 1; return; } } } /* Support PATH_INFO for CGI scripts. */ for (p = buf + strlen(buf); p > buf + 1; p--) { if (*p == '/') { *p = '\0'; if ((match_prefix(conn->ctx->config[CGI_EXTENSIONS], (int)strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 #ifdef USE_LUA || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS], (int)strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), buf) > 0 #endif ) && mg_stat(conn, buf, filep)) { /* Shift PATH_INFO block one character right, e.g. "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00" conn->path_info is pointing to the local variable "path" declared in handle_request(), so PATH_INFO is not valid after handle_request returns. */ conn->path_info = p + 1; memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for trailing \0 */ p[1] = '/'; *is_script_ressource = 1; break; } else { *p = '/'; } } } } /* Check whether full request is buffered. Return: -1 if request is malformed 0 if request is not yet fully buffered >0 actual request length, including last \r\n\r\n */ static int get_request_len(const char *buf, int buflen) { const char *s, *e; int len = 0; int in_content = 0; for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) { /* Control characters are not allowed but >=128 is. */ if (!in_content && !isprint(* (const unsigned char *) s) && *s != '\r' && *s != '\n' && * (const unsigned char *) s < 128) { len = -1; break; /* [i_a] abort scan as soon as one malformed character is found; */ /* don't let subsequent \r\n\r\n win us over anyhow */ } else if (s[0] == '\n' && s[1] == '\n') { len = (int) (s - buf) + 2; } else if (s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') { len = (int) (s - buf) + 3; in_content = 0; } if (!in_content && *s == ':') { in_content = 1; } } return len; } /* Convert month to the month number. Return -1 on error, or month number */ static int get_month_index(const char *s) { size_t i; for (i = 0; i < ARRAY_SIZE(month_names); i++) if (!strcmp(s, month_names[i])) return (int) i; return -1; } static int num_leap_years(int year) { return year / 4 - year / 100 + year / 400; } /* Parse UTC date-time string, and return the corresponding time_t value. */ static time_t parse_date_string(const char *datetime) { static const unsigned short days_before_month[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; char month_str[32]={0}; int second, minute, hour, day, month, year, leap_days, days; time_t result = (time_t) 0; if ((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour, &minute, &second) == 6) || (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour, &minute, &second) == 6) || (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year, &hour, &minute, &second) == 6) || (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour, &minute, &second) == 6)) { month = get_month_index(month_str); if ((month >= 0) && (year > 1970)) { leap_days = num_leap_years(year) - num_leap_years(1970); year -= 1970; days = year * 365 + days_before_month[month] + (day - 1) + leap_days; result = (time_t) days * 24 * 3600 + (time_t) hour * 3600 + minute * 60 + second; } } return result; } #ifndef RGW /* Protect against directory disclosure attack by removing '..', excessive '/' and '\' characters */ static void remove_double_dots_and_double_slashes(char *s) { char *p = s; while (*s != '\0') { *p++ = *s++; if (s[-1] == '/' || s[-1] == '\\') { /* Skip all following slashes, backslashes and double-dots */ while (s[0] != '\0') { if (s[0] == '/' || s[0] == '\\') { s++; } else if (s[0] == '.' && s[1] == '.') { s += 2; } else { break; } } } } *p = '\0'; } #endif static const struct { const char *extension; size_t ext_len; const char *mime_type; } builtin_mime_types[] = { /* IANA registered MIME types (http://www.iana.org/assignments/media-types) application types */ {".doc", 4, "application/msword"}, {".eps", 4, "application/postscript"}, {".exe", 4, "application/octet-stream"}, {".js", 3, "application/javascript"}, {".json", 5, "application/json"}, {".pdf", 4, "application/pdf"}, {".ps", 3, "application/postscript"}, {".rtf", 4, "application/rtf"}, {".xhtml", 6, "application/xhtml+xml"}, {".xsl", 4, "application/xml"}, {".xslt", 5, "application/xml"}, /* audio */ {".mp3", 4, "audio/mpeg"}, {".oga", 4, "audio/ogg"}, {".ogg", 4, "audio/ogg"}, /* image */ {".gif", 4, "image/gif"}, {".ief", 4, "image/ief"}, {".jpeg", 5, "image/jpeg"}, {".jpg", 4, "image/jpeg"}, {".jpm", 4, "image/jpm"}, {".jpx", 4, "image/jpx"}, {".png", 4, "image/png"}, {".svg", 4, "image/svg+xml"}, {".tif", 4, "image/tiff"}, {".tiff", 5, "image/tiff"}, /* model */ {".wrl", 4, "model/vrml"}, /* text */ {".css", 4, "text/css"}, {".csv", 4, "text/csv"}, {".htm", 4, "text/html"}, {".html", 5, "text/html"}, {".sgm", 4, "text/sgml"}, {".shtm", 5, "text/html"}, {".shtml", 6, "text/html"}, {".txt", 4, "text/plain"}, {".xml", 4, "text/xml"}, /* video */ {".mov", 4, "video/quicktime"}, {".mp4", 4, "video/mp4"}, {".mpeg", 5, "video/mpeg"}, {".mpg", 4, "video/mpeg"}, {".ogv", 4, "video/ogg"}, {".qt", 3, "video/quicktime"}, /* not registered types (http://reference.sitepoint.com/html/mime-types-full, http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */ {".arj", 4, "application/x-arj-compressed"}, {".gz", 3, "application/x-gunzip"}, {".rar", 4, "application/x-arj-compressed"}, {".swf", 4, "application/x-shockwave-flash"}, {".tar", 4, "application/x-tar"}, {".tgz", 4, "application/x-tar-gz"}, {".torrent", 8, "application/x-bittorrent"}, {".ppt", 4, "application/x-mspowerpoint"}, {".xls", 4, "application/x-msexcel"}, {".zip", 4, "application/x-zip-compressed"}, {".aac", 4, "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */ {".aif", 4, "audio/x-aif"}, {".m3u", 4, "audio/x-mpegurl"}, {".mid", 4, "audio/x-midi"}, {".ra", 3, "audio/x-pn-realaudio"}, {".ram", 4, "audio/x-pn-realaudio"}, {".wav", 4, "audio/x-wav"}, {".bmp", 4, "image/bmp"}, {".ico", 4, "image/x-icon"}, {".pct", 4, "image/x-pct"}, {".pict", 5, "image/pict"}, {".rgb", 4, "image/x-rgb"}, {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */ {".asf", 4, "video/x-ms-asf"}, {".avi", 4, "video/x-msvideo"}, {".m4v", 4, "video/x-m4v"}, {NULL, 0, NULL} }; const char *mg_get_builtin_mime_type(const char *path) { const char *ext; size_t i, path_len; path_len = strlen(path); for (i = 0; builtin_mime_types[i].extension != NULL; i++) { ext = path + (path_len - builtin_mime_types[i].ext_len); if (path_len > builtin_mime_types[i].ext_len && mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) { return builtin_mime_types[i].mime_type; } } return "text/plain"; } /* Look at the "path" extension and figure what mime type it has. Store mime type in the vector. */ static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec) { struct vec ext_vec, mime_vec; const char *list, *ext; size_t path_len; path_len = strlen(path); /* Scan user-defined mime types first, in case user wants to override default mime types. */ list = ctx->config[EXTRA_MIME_TYPES]; while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) { /* ext now points to the path suffix */ ext = path + path_len - ext_vec.len; if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { *vec = mime_vec; return; } } vec->ptr = mg_get_builtin_mime_type(path); vec->len = strlen(vec->ptr); } /* Stringify binary data. Output buffer must be twice as big as input, because each byte takes 2 bytes in string representation */ static void bin2str(char *to, const unsigned char *p, size_t len) { static const char *hex = "0123456789abcdef"; for (; len--; p++) { *to++ = hex[p[0] >> 4]; *to++ = hex[p[0] & 0x0f]; } *to = '\0'; } /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */ char *mg_md5(char buf[33], ...) { md5_byte_t hash[16]; const char *p; va_list ap; md5_state_t ctx; md5_init(&ctx); va_start(ap, buf); while ((p = va_arg(ap, const char *)) != NULL) { md5_append(&ctx, (const md5_byte_t *) p, (int) strlen(p)); } va_end(ap); md5_finish(&ctx, hash); bin2str(buf, hash, sizeof(hash)); return buf; } /* Check the user's password, return 1 if OK */ static int check_password(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response) { char ha2[32 + 1], expected_response[32 + 1]; /* Some of the parameters may be NULL */ if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL || qop == NULL || response == NULL) { return 0; } /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */ /* TODO(lsm): check for authentication timeout */ if (/* strcmp(dig->uri, c->ouri) != 0 || */ strlen(response) != 32 /* || now - strtoul(dig->nonce, NULL, 10) > 3600 */ ) { return 0; } mg_md5(ha2, method, ":", uri, NULL); mg_md5(expected_response, ha1, ":", nonce, ":", nc, ":", cnonce, ":", qop, ":", ha2, NULL); return mg_strcasecmp(response, expected_response) == 0; } /* Use the global passwords file, if specified by auth_gpass option, or search for .htpasswd in the requested directory. */ static void open_auth_file(struct mg_connection *conn, const char *path, struct file *filep) { char name[PATH_MAX]; const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE]; struct file file = STRUCT_FILE_INITIALIZER; if (gpass != NULL) { /* Use global passwords file */ if (!mg_fopen(conn, gpass, "r", filep)) { #ifdef DEBUG mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO)); #endif } /* Important: using local struct file to test path for is_directory flag. If filep is used, mg_stat() makes it appear as if auth file was opened. */ } else if (mg_stat(conn, path, &file) && file.is_directory) { mg_snprintf(conn, name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME); if (!mg_fopen(conn, name, "r", filep)) { #ifdef DEBUG mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO)); #endif } } else { /* Try to find .htpasswd in requested directory. */ for (p = path, e = p + strlen(p) - 1; e > p; e--) { if (e[0] == '/') { break; } } mg_snprintf(conn, name, sizeof(name), "%.*s%c%s", (int) (e - p), p, '/', PASSWORDS_FILE_NAME); if (!mg_fopen(conn, name, "r", filep)) { #ifdef DEBUG mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO)); #endif } } } /* Parsed Authorization header */ struct ah { char *user, *uri, *cnonce, *response, *qop, *nc, *nonce; }; /* Return 1 on success. Always initializes the ah structure. */ static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah) { char *name, *value, *s; const char *auth_header; unsigned long nonce; (void) memset(ah, 0, sizeof(*ah)); if ((auth_header = mg_get_header(conn, "Authorization")) == NULL || mg_strncasecmp(auth_header, "Digest ", 7) != 0) { return 0; } /* Make modifiable copy of the auth header */ (void) mg_strlcpy(buf, auth_header + 7, buf_size); s = buf; /* Parse authorization header */ for (;;) { /* Gobble initial spaces */ while (isspace(* (unsigned char *) s)) { s++; } name = skip_quoted(&s, "=", " ", 0); /* Value is either quote-delimited, or ends at first comma or space. */ if (s[0] == '\"') { s++; value = skip_quoted(&s, "\"", " ", '\\'); if (s[0] == ',') { s++; } } else { value = skip_quoted(&s, ", ", " ", 0); /* IE uses commas, FF uses spaces */ } if (*name == '\0') { break; } if (!strcmp(name, "username")) { ah->user = value; } else if (!strcmp(name, "cnonce")) { ah->cnonce = value; } else if (!strcmp(name, "response")) { ah->response = value; } else if (!strcmp(name, "uri")) { ah->uri = value; } else if (!strcmp(name, "qop")) { ah->qop = value; } else if (!strcmp(name, "nc")) { ah->nc = value; } else if (!strcmp(name, "nonce")) { ah->nonce = value; } } #ifndef NO_NONCE_CHECK /* Convert the nonce from the client to a number and check it. */ /* Server side nonce check is valuable in all situations but one: if the server restarts frequently, but the client should not see that, so the server should accept nonces from previous starts. */ if (ah->nonce == NULL) { return 0; } nonce = strtoul(ah->nonce, &s, 10); if ((s == NULL) || (*s != 0)) { return 0; } nonce ^= (unsigned long)(conn->ctx); if (noncectx->start_time) { /* nonce is from a previous start of the server and no longer valid (replay attack?) */ return 0; } if (nonce>=conn->ctx->start_time+conn->ctx->nonce_count) { return 0; } #endif /* CGI needs it as REMOTE_USER */ if (ah->user != NULL) { conn->request_info.remote_user = mg_strdup(ah->user); } else { return 0; } return 1; } static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p) { char *eof; size_t len; char *memend; if (filep->membuf != NULL && *p != NULL) { memend = (char *) &filep->membuf[filep->size]; eof = (char *) memchr(*p, '\n', memend - *p); /* Search for \n from p till the end of stream */ if (eof != NULL) { eof += 1; /* Include \n */ } else { eof = memend; /* Copy remaining data */ } len = (size_t) (eof - *p) > size - 1 ? size - 1 : (size_t) (eof - *p); memcpy(buf, *p, len); buf[len] = '\0'; *p += len; return len ? eof : NULL; } else if (filep->fp != NULL) { return fgets(buf, (int)size, filep->fp); } else { return NULL; } } struct read_auth_file_struct { struct mg_connection *conn; struct ah ah; char *domain; char buf[256+256+40]; char *f_user; char *f_domain; char *f_ha1; }; static int read_auth_file(struct file *filep, struct read_auth_file_struct * workdata) { char *p; int is_authorized = 0; struct file fp; int l; /* Loop over passwords file */ p = (char *) filep->membuf; while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) { l = strlen(workdata->buf); while (l>0) { if (isspace(workdata->buf[l-1]) || iscntrl(workdata->buf[l-1])) { l--; workdata->buf[l] = 0; } else break; } if (l<1) continue; workdata->f_user = workdata->buf; if (workdata->f_user[0]==':') { /* user names may not contain a ':' and may not be empty, so lines starting with ':' may be used for a special purpose */ if (workdata->f_user[1]=='#') { /* :# is a comment */ continue; } else if (!strncmp(workdata->f_user+1,"include=",8)) { if (mg_fopen(workdata->conn, workdata->f_user+9, "r", &fp)) { is_authorized = read_auth_file(&fp, workdata); mg_fclose(&fp); } else { mg_cry(workdata->conn, "%s: cannot open authorization file: %s", __func__, workdata->buf); } continue; } /* everything is invalid for the moment (might change in the future) */ mg_cry(workdata->conn, "%s: syntax error in authorization file: %s", __func__, workdata->buf); continue; } workdata->f_domain = strchr(workdata->f_user, ':'); if (workdata->f_domain == NULL) { mg_cry(workdata->conn, "%s: syntax error in authorization file: %s", __func__, workdata->buf); continue; } *(workdata->f_domain) = 0; (workdata->f_domain)++; workdata->f_ha1 = strchr(workdata->f_domain, ':'); if (workdata->f_ha1 == NULL) { mg_cry(workdata->conn, "%s: syntax error in authorization file: %s", __func__, workdata->buf); continue; } *(workdata->f_ha1) = 0; (workdata->f_ha1)++; if (!strcmp(workdata->ah.user, workdata->f_user) && !strcmp(workdata->domain, workdata->f_domain)) { return check_password(workdata->conn->request_info.request_method, workdata->f_ha1, workdata->ah.uri, workdata->ah.nonce, workdata->ah.nc, workdata->ah.cnonce, workdata->ah.qop, workdata->ah.response); } } return is_authorized; } /* Authorize against the opened passwords file. Return 1 if authorized. */ static int authorize(struct mg_connection *conn, struct file *filep) { struct read_auth_file_struct workdata; char buf[MG_BUF_LEN]; memset(&workdata,0,sizeof(workdata)); workdata.conn = conn; if (!parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) { return 0; } workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN]; return read_auth_file(filep, &workdata); } /* Return 1 if request is authorised, 0 otherwise. */ static int check_authorization(struct mg_connection *conn, const char *path) { char fname[PATH_MAX]; struct vec uri_vec, filename_vec; const char *list; struct file file = STRUCT_FILE_INITIALIZER; int authorized = 1; list = conn->ctx->config[PROTECT_URI]; while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) { if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) { mg_snprintf(conn, fname, sizeof(fname), "%.*s", (int) filename_vec.len, filename_vec.ptr); if (!mg_fopen(conn, fname, "r", &file)) { mg_cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno)); } break; } } if (!is_file_opened(&file)) { open_auth_file(conn, path, &file); } if (is_file_opened(&file)) { authorized = authorize(conn, &file); mg_fclose(&file); } return authorized; } static void send_authorization_request(struct mg_connection *conn) { char date[64]; time_t curtime = time(NULL); unsigned long nonce = (unsigned long)(conn->ctx->start_time); (void)pthread_mutex_lock(&conn->ctx->nonce_mutex); nonce += conn->ctx->nonce_count; ++conn->ctx->nonce_count; (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex); nonce ^= (unsigned long)(conn->ctx); conn->status_code = 401; conn->must_close = 1; gmt_time_string(date, sizeof(date), &curtime); mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n" "Date: %s\r\n" "Connection: %s\r\n" "Content-Length: 0\r\n" "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", nonce=\"%lu\"\r\n\r\n", date, suggest_connection_header(conn), conn->ctx->config[AUTHENTICATION_DOMAIN], nonce); } static int is_authorized_for_put(struct mg_connection *conn) { struct file file = STRUCT_FILE_INITIALIZER; const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE]; int ret = 0; if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) { ret = authorize(conn, &file); mg_fclose(&file); } return ret; } int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass) { int found, i; char line[512], u[512] = "", d[512] ="", ha1[33], tmp[PATH_MAX+8]; FILE *fp, *fp2; found = 0; fp = fp2 = NULL; /* Regard empty password as no password - remove user record. */ if (pass != NULL && pass[0] == '\0') { pass = NULL; } /* Other arguments must not be empty */ if (fname == NULL || domain == NULL || user == NULL) return 0; /* Using the given file format, user name and domain must not contain ':' */ if (strchr(user, ':') != NULL) return 0; if (strchr(domain, ':') != NULL) return 0; /* Do not allow control characters like newline in user name and domain. Do not allow excessively long names either. */ for (i=0; i<255 && user[i]!=0; i++) { if (iscntrl(user[i])) return 0; } if (user[i]) return 0; for (i=0; i<255 && domain[i]!=0; i++) { if (iscntrl(domain[i])) return 0; } if (domain[i]) return 0; /* Create a temporary file name */ (void) snprintf(tmp, sizeof(tmp) - 1, "%s.tmp", fname); tmp[sizeof(tmp) - 1] = 0; /* Create the file if does not exist */ if ((fp = fopen(fname, "a+")) != NULL) { (void) fclose(fp); } /* Open the given file and temporary file */ if ((fp = fopen(fname, "r")) == NULL) { return 0; } else if ((fp2 = fopen(tmp, "w+")) == NULL) { fclose(fp); return 0; } /* Copy the stuff to temporary file */ while (fgets(line, sizeof(line), fp) != NULL) { if (sscanf(line, "%255[^:]:%255[^:]:%*s", u, d) != 2) { continue; } u[255]=0; d[255]=0; if (!strcmp(u, user) && !strcmp(d, domain)) { found++; if (pass != NULL) { mg_md5(ha1, user, ":", domain, ":", pass, NULL); fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); } } else { fprintf(fp2, "%s", line); } } /* If new user, just add it */ if (!found && pass != NULL) { mg_md5(ha1, user, ":", domain, ":", pass, NULL); fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); } /* Close files */ fclose(fp); fclose(fp2); /* Put the temp file in place of real file */ IGNORE_UNUSED_RESULT(remove(fname)); IGNORE_UNUSED_RESULT(rename(tmp, fname)); return 1; } static SOCKET conn2(struct mg_context *ctx /* may be null */, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len) { struct sockaddr_in sain; struct hostent *he; SOCKET sock = INVALID_SOCKET; if (host == NULL) { snprintf(ebuf, ebuf_len, "%s", "NULL host"); } else if (use_ssl && SSLv23_client_method == NULL) { snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized"); /* TODO(lsm): use something threadsafe instead of gethostbyname() */ } else if ((he = gethostbyname(host)) == NULL) { snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO)); } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO)); } else { set_close_on_exec(sock, fc(ctx)); memset(&sain, '\0', sizeof(sain)); sain.sin_family = AF_INET; sain.sin_port = htons((uint16_t) port); sain.sin_addr = * (struct in_addr *) he->h_addr_list[0]; if (connect(sock, (struct sockaddr *) &sain, sizeof(sain)) != 0) { snprintf(ebuf, ebuf_len, "connect(%s:%d): %s", host, port, strerror(ERRNO)); closesocket(sock); sock = INVALID_SOCKET; } } return sock; } int mg_url_encode(const char *src, char *dst, size_t dst_len) { static const char *dont_escape = "._-$,;~()"; static const char *hex = "0123456789abcdef"; char *pos = dst; const char *end = dst + dst_len - 1; for (; *src != '\0' && pos < end; src++, pos++) { if (isalnum(*(const unsigned char *) src) || strchr(dont_escape, * (const unsigned char *) src) != NULL) { *pos = *src; } else if (pos + 2 < end) { pos[0] = '%'; pos[1] = hex[(* (const unsigned char *) src) >> 4]; pos[2] = hex[(* (const unsigned char *) src) & 0xf]; pos += 2; } else { return -1; } } *pos = '\0'; return (*src == '\0') ? (int)(pos - dst) : -1; } static void print_dir_entry(struct de *de) { char size[64], mod[64], href[PATH_MAX]; struct tm *tm; if (de->file.is_directory) { mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]"); } else { /* We use (signed) cast below because MSVC 6 compiler cannot convert unsigned __int64 to double. Sigh. */ if (de->file.size < 1024) { mg_snprintf(de->conn, size, sizeof(size), "%d", (int) de->file.size); } else if (de->file.size < 0x100000) { mg_snprintf(de->conn, size, sizeof(size), "%.1fk", (double) de->file.size / 1024.0); } else if (de->file.size < 0x40000000) { mg_snprintf(de->conn, size, sizeof(size), "%.1fM", (double) de->file.size / 1048576); } else { mg_snprintf(de->conn, size, sizeof(size), "%.1fG", (double) de->file.size / 1073741824); } } tm = localtime(&de->file.modification_time); if (tm != NULL) { strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm); } else { mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod)); mod[sizeof(mod) - 1] = '\0'; } mg_url_encode(de->file_name, href, sizeof(href)); de->conn->num_bytes_sent += mg_printf(de->conn, "
%s%s" " %s  %s\n", de->conn->request_info.uri, href, de->file.is_directory ? "/" : "", de->file_name, de->file.is_directory ? "/" : "", mod, size); } /* This function is called from send_directory() and used for sorting directory entries by size, or name, or modification time. On windows, __cdecl specification is needed in case if project is built with __stdcall convention. qsort always requires __cdels callback. */ static int WINCDECL compare_dir_entries(const void *p1, const void *p2) { const struct de *a = (const struct de *) p1, *b = (const struct de *) p2; const char *query_string = a->conn->request_info.query_string; int cmp_result = 0; if (query_string == NULL) { query_string = "na"; } if (a->file.is_directory && !b->file.is_directory) { return -1; /* Always put directories on top */ } else if (!a->file.is_directory && b->file.is_directory) { return 1; /* Always put directories on top */ } else if (*query_string == 'n') { cmp_result = strcmp(a->file_name, b->file_name); } else if (*query_string == 's') { cmp_result = a->file.size == b->file.size ? 0 : a->file.size > b->file.size ? 1 : -1; } else if (*query_string == 'd') { cmp_result = a->file.modification_time == b->file.modification_time ? 0 : a->file.modification_time > b->file.modification_time ? 1 : -1; } return query_string[1] == 'd' ? -cmp_result : cmp_result; } static int must_hide_file(struct mg_connection *conn, const char *path) { const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$"; const char *pattern = conn->ctx->config[HIDE_FILES]; return match_prefix(pw_pattern, (int)strlen(pw_pattern), path) > 0 || (pattern != NULL && match_prefix(pattern, (int)strlen(pattern), path) > 0); } static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void (*cb)(struct de *, void *)) { char path[PATH_MAX]; struct dirent *dp; DIR *dirp; struct de de; if ((dirp = opendir(dir)) == NULL) { return 0; } else { de.conn = conn; while ((dp = readdir(dirp)) != NULL) { /* Do not show current dir and hidden files */ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") || must_hide_file(conn, dp->d_name)) { continue; } mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name); /* If we don't memset stat structure to zero, mtime will have garbage and strftime() will segfault later on in print_dir_entry(). memset is required only if mg_stat() fails. For more details, see http://code.google.com/p/mongoose/issues/detail?id=79 */ memset(&de.file, 0, sizeof(de.file)); if (!mg_stat(conn, path, &de.file)) { mg_cry(conn, "%s: mg_stat(%s) failed: %s", __func__, path, strerror(ERRNO)); } de.file_name = dp->d_name; cb(&de, data); } (void) closedir(dirp); } return 1; } static int remove_directory(struct mg_connection *conn, const char *dir) { char path[PATH_MAX]; struct dirent *dp; DIR *dirp; struct de de; if ((dirp = opendir(dir)) == NULL) { return 0; } else { de.conn = conn; while ((dp = readdir(dirp)) != NULL) { /* Do not show current dir (but show hidden files as they will also be removed) */ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) { continue; } mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name); /* If we don't memset stat structure to zero, mtime will have garbage and strftime() will segfault later on in print_dir_entry(). memset is required only if mg_stat() fails. For more details, see http://code.google.com/p/mongoose/issues/detail?id=79 */ memset(&de.file, 0, sizeof(de.file)); if (!mg_stat(conn, path, &de.file)) { mg_cry(conn, "%s: mg_stat(%s) failed: %s", __func__, path, strerror(ERRNO)); } if(de.file.modification_time) { if(de.file.is_directory) { remove_directory(conn, path); } else { mg_remove(path); } } } (void) closedir(dirp); IGNORE_UNUSED_RESULT(rmdir(dir)); } return 1; } struct dir_scan_data { struct de *entries; int num_entries; int arr_size; }; /* Behaves like realloc(), but frees original pointer on failure */ static void *realloc2(void *ptr, size_t size) { void *new_ptr = mg_realloc(ptr, size); if (new_ptr == NULL) { mg_free(ptr); } return new_ptr; } static void dir_scan_callback(struct de *de, void *data) { struct dir_scan_data *dsd = (struct dir_scan_data *) data; if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) { dsd->arr_size *= 2; dsd->entries = (struct de *) realloc2(dsd->entries, dsd->arr_size * sizeof(dsd->entries[0])); } if (dsd->entries == NULL) { /* TODO(lsm): propagate an error to the caller */ dsd->num_entries = 0; } else { dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name); dsd->entries[dsd->num_entries].file = de->file; dsd->entries[dsd->num_entries].conn = de->conn; dsd->num_entries++; } } static void handle_directory_request(struct mg_connection *conn, const char *dir) { int i, sort_direction; struct dir_scan_data data = { NULL, 0, 128 }; char date[64]; time_t curtime = time(NULL); if (!scan_directory(conn, dir, &data, dir_scan_callback)) { send_http_error(conn, 500, "Cannot open directory", "Error: opendir(%s): %s", dir, strerror(ERRNO)); return; } gmt_time_string(date, sizeof(date), &curtime); sort_direction = conn->request_info.query_string != NULL && conn->request_info.query_string[1] == 'd' ? 'a' : 'd'; conn->must_close = 1; mg_printf(conn, "HTTP/1.1 200 OK\r\n" "Date: %s\r\n" "Connection: close\r\n" "Content-Type: text/html; charset=utf-8\r\n\r\n", date); conn->num_bytes_sent += mg_printf(conn, "Index of %s" "" "

Index of %s

"
                                      ""
                                      ""
                                      ""
                                      "",
                                      conn->request_info.uri, conn->request_info.uri,
                                      sort_direction, sort_direction, sort_direction);

    /* Print first entry - link to a parent directory */
    conn->num_bytes_sent += mg_printf(conn,
                                      ""
                                      "\n",
                                      conn->request_info.uri, "..", "Parent directory", "-", "-");

    /* Sort and print directory entries */
    if (data.entries != NULL) {
        qsort(data.entries, (size_t) data.num_entries,
              sizeof(data.entries[0]), compare_dir_entries);
        for (i = 0; i < data.num_entries; i++) {
            print_dir_entry(&data.entries[i]);
            mg_free(data.entries[i].file_name);
        }
        mg_free(data.entries);
    }

    conn->num_bytes_sent += mg_printf(conn, "%s", "
NameModifiedSize

%s %s  %s
"); conn->status_code = 200; } /* Send len bytes from the opened file to the client. */ static void send_file_data(struct mg_connection *conn, struct file *filep, int64_t offset, int64_t len) { char buf[MG_BUF_LEN]; int to_read, num_read, num_written; /* Sanity check the offset */ offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset; if (len > 0 && filep->membuf != NULL && filep->size > 0) { if (len > filep->size - offset) { len = filep->size - offset; } mg_write(conn, filep->membuf + offset, (size_t) len); } else if (len > 0 && filep->fp != NULL) { if (offset > 0 && fseeko(filep->fp, offset, SEEK_SET) != 0) { mg_cry(conn, "%s: fseeko() failed: %s", __func__, strerror(ERRNO)); } while (len > 0) { /* Calculate how much to read from the file in the buffer */ to_read = sizeof(buf); if ((int64_t) to_read > len) { to_read = (int) len; } /* Read from file, exit the loop on error */ if ((num_read = (int) fread(buf, 1, (size_t) to_read, filep->fp)) <= 0) { break; } /* Send read bytes to the client, exit the loop on error */ if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) { break; } /* Both read and were successful, adjust counters */ conn->num_bytes_sent += num_written; len -= num_written; } } } static int parse_range_header(const char *header, int64_t *a, int64_t *b) { return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); } static void construct_etag(char *buf, size_t buf_len, const struct file *filep) { snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) filep->modification_time, filep->size); } static void fclose_on_exec(struct file *filep, struct mg_connection *conn) { if (filep != NULL && filep->fp != NULL) { #ifdef _WIN32 (void) conn; /* Unused. */ #else if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) { mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", __func__, strerror(ERRNO)); } #endif } } static void handle_static_file_request(struct mg_connection *conn, const char *path, struct file *filep) { char date[64], lm[64], etag[64], range[64]; const char *msg = "OK", *hdr; time_t curtime = time(NULL); int64_t cl, r1, r2; struct vec mime_vec; int n; char gz_path[PATH_MAX]; const char *encoding = ""; const char *cors1, *cors2, *cors3; get_mime_type(conn->ctx, path, &mime_vec); cl = filep->size; conn->status_code = 200; range[0] = '\0'; /* if this file is in fact a pre-gzipped file, rewrite its filename it's important to rewrite the filename after resolving the mime type from it, to preserve the actual file's type */ if (filep->gzipped) { snprintf(gz_path, sizeof(gz_path), "%s.gz", path); path = gz_path; encoding = "Content-Encoding: gzip\r\n"; } if (!mg_fopen(conn, path, "rb", filep)) { send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path, strerror(ERRNO)); return; } fclose_on_exec(filep, conn); /* If Range: header specified, act accordingly */ r1 = r2 = 0; hdr = mg_get_header(conn, "Range"); if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) { /* actually, range requests don't play well with a pre-gzipped file (since the range is specified in the uncompressed space) */ if (filep->gzipped) { send_http_error(conn, 501, "Not Implemented", "range requests in gzipped files are not supported"); mg_fclose(filep); return; } conn->status_code = 206; cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1; mg_snprintf(conn, range, sizeof(range), "Content-Range: bytes " "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n", r1, r1 + cl - 1, filep->size); msg = "Partial Content"; } hdr = mg_get_header(conn, "Origin"); if (hdr) { /* Cross-origin resource sharing (CORS), see http://www.html5rocks.com/en/tutorials/cors/, http://www.html5rocks.com/static/images/cors_server_flowchart.png - preflight is not supported for files. */ cors1 = "Access-Control-Allow-Origin: "; cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN]; cors3 = "\r\n"; } else { cors1 = cors2 = cors3 = ""; } /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */ gmt_time_string(date, sizeof(date), &curtime); gmt_time_string(lm, sizeof(lm), &filep->modification_time); construct_etag(etag, sizeof(etag), filep); (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n" "%s%s%s" "Date: %s\r\n" "Last-Modified: %s\r\n" "Etag: %s\r\n" "Content-Type: %.*s\r\n" "Content-Length: %" INT64_FMT "\r\n" "Connection: %s\r\n" "Accept-Ranges: bytes\r\n" "%s%s\r\n", conn->status_code, msg, cors1, cors2, cors3, date, lm, etag, (int) mime_vec.len, mime_vec.ptr, cl, suggest_connection_header(conn), range, encoding); if (strcmp(conn->request_info.request_method, "HEAD") != 0) { send_file_data(conn, filep, r1, cl); } mg_fclose(filep); } void mg_send_file(struct mg_connection *conn, const char *path) { struct file file = STRUCT_FILE_INITIALIZER; if (mg_stat(conn, path, &file)) { handle_static_file_request(conn, path, &file); } else { send_http_error(conn, 404, "Not Found", "%s", "File not found"); } } /* Parse HTTP headers from the given buffer, advance buffer to the point where parsing stopped. */ static void parse_http_headers(char **buf, struct mg_request_info *ri) { int i; for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) { ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0); ri->http_headers[i].value = skip(buf, "\r\n"); if (ri->http_headers[i].name[0] == '\0') break; ri->num_headers = i + 1; } } static int is_valid_http_method(const char *method) { return !strcmp(method, "GET") || !strcmp(method, "POST") || !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || !strcmp(method, "PUT") || !strcmp(method, "DELETE") || !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND") || !strcmp(method, "MKCOL") ; } /* Parse HTTP request, fill in mg_request_info structure. This function modifies the buffer by NUL-terminating HTTP request components, header names and header values. */ static int parse_http_message(char *buf, int len, struct mg_request_info *ri) { int is_request, request_length = get_request_len(buf, len); if (request_length > 0) { /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port */ ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL; ri->num_headers = 0; buf[request_length - 1] = '\0'; /* RFC says that all initial whitespaces should be ingored */ while (*buf != '\0' && isspace(* (unsigned char *) buf)) { buf++; } ri->request_method = skip(&buf, " "); ri->uri = skip(&buf, " "); ri->http_version = skip(&buf, "\r\n"); /* HTTP message could be either HTTP request or HTTP response, e.g. "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */ #ifndef RGW is_request = is_valid_http_method(ri->request_method); if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { request_length = -1; } else { if (is_request) { ri->http_version += 5; } parse_http_headers(&buf, ri); } #else is_request = (memcmp(ri->http_version, "HTTP/", 5) == 0); if (is_request) { ri->http_version += 5; } if (is_request || memcmp(ri->request_method, "HTTP/", 5) == 0) { parse_http_headers(&buf, ri); } else { request_length = -1; } #endif } return request_length; } /* Keep reading the input (either opened file descriptor fd, or socket sock, or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the buffer (which marks the end of HTTP request). Buffer buf may already have some data. The length of the data is stored in nread. Upon every read operation, increase nread by the number of bytes read. */ static int read_request(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread) { int request_len, n = 0; request_len = get_request_len(buf, *nread); while (conn->ctx->stop_flag == 0 && *nread < bufsiz && request_len == 0 && (n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0) { *nread += n; assert(*nread <= bufsiz); request_len = get_request_len(buf, *nread); } return request_len <= 0 && n <= 0 ? -1 : request_len; } /* For given directory path, substitute it to valid index file. Return 1 if index file has been found, 0 if not found. If the file is found, it's stats is returned in stp. */ static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct file *filep) { const char *list = conn->ctx->config[INDEX_FILES]; struct file file = STRUCT_FILE_INITIALIZER; struct vec filename_vec; size_t n = strlen(path); int found = 0; /* The 'path' given to us points to the directory. Remove all trailing directory separator characters from the end of the path, and then append single directory separator character. */ while (n > 0 && path[n - 1] == '/') { n--; } path[n] = '/'; /* Traverse index files list. For each entry, append it to the given path and see if the file exists. If it exists, break the loop */ while ((list = next_option(list, &filename_vec, NULL)) != NULL) { /* Ignore too long entries that may overflow path buffer */ if (filename_vec.len > path_len - (n + 2)) continue; /* Prepare full path to the index file */ mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); /* Does it exist? */ if (mg_stat(conn, path, &file)) { /* Yes it does, break the loop */ *filep = file; found = 1; break; } } /* If no index file exists, restore directory path */ if (!found) { path[n] = '\0'; } return found; } /* Return True if we should reply 304 Not Modified. */ static int is_not_modified(const struct mg_connection *conn, const struct file *filep) { char etag[64]; const char *ims = mg_get_header(conn, "If-Modified-Since"); const char *inm = mg_get_header(conn, "If-None-Match"); construct_etag(etag, sizeof(etag), filep); return (inm != NULL && !mg_strcasecmp(etag, inm)) || (ims != NULL && filep->modification_time <= parse_date_string(ims)); } static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) { const char *expect, *body; char buf[MG_BUF_LEN]; int to_read, nread, buffered_len, success = 0; expect = mg_get_header(conn, "Expect"); assert(fp != NULL); if (conn->content_len == -1 && !conn->is_chunked) { send_http_error(conn, 411, "Length Required", "%s", ""); } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) { send_http_error(conn, 417, "Expectation Failed", "%s", ""); } else { if (expect != NULL) { (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n"); } body = conn->buf + conn->request_len + conn->consumed_content; buffered_len = (int)(&conn->buf[conn->data_len] - body); assert(buffered_len >= 0); assert(conn->consumed_content == 0); if (buffered_len > 0) { if ((int64_t) buffered_len > conn->content_len) { buffered_len = (int) conn->content_len; } push(fp, sock, ssl, body, (int64_t) buffered_len); conn->consumed_content += buffered_len; } nread = 0; while (conn->consumed_content < conn->content_len) { to_read = sizeof(buf); if ((int64_t) to_read > conn->content_len - conn->consumed_content) { to_read = (int) (conn->content_len - conn->consumed_content); } nread = pull(NULL, conn, buf, to_read); if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) { break; } conn->consumed_content += nread; } if (conn->consumed_content == conn->content_len) { success = nread >= 0; } /* Each error code path in this function must send an error */ if (!success) { send_http_error(conn, 577, http_500_error, "%s", ""); } } return success; } #if !defined(NO_CGI) /* This structure helps to create an environment for the spawned CGI program. Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, last element must be NULL. However, on Windows there is a requirement that all these VARIABLE=VALUE\0 strings must reside in a contiguous buffer. The end of the buffer is marked by two '\0' characters. We satisfy both worlds: we create an envp array (which is vars), all entries are actually pointers inside buf. */ struct cgi_env_block { struct mg_connection *conn; char buf[CGI_ENVIRONMENT_SIZE]; /* Environment buffer */ int len; /* Space taken */ char *vars[MAX_CGI_ENVIR_VARS]; /* char **envp */ int nvars; /* Number of variables */ }; static char *addenv(struct cgi_env_block *block, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective pointer into the vars array. */ static char *addenv(struct cgi_env_block *block, const char *fmt, ...) { int n, space; char *added; va_list ap; /* Calculate how much space is left in the buffer */ space = sizeof(block->buf) - block->len - 2; assert(space >= 0); /* Make a pointer to the free space int the buffer */ added = block->buf + block->len; /* Copy VARIABLE=VALUE\0 string into the free space */ va_start(ap, fmt); n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap); va_end(ap); /* Make sure we do not overflow buffer and the envp array */ if (n > 0 && n + 1 < space && block->nvars < (int) ARRAY_SIZE(block->vars) - 2) { /* Append a pointer to the added string into the envp array */ block->vars[block->nvars++] = added; /* Bump up used length counter. Include \0 terminator */ block->len += n + 1; } else { mg_cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt); } return added; } static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_env_block *blk) { const char *s, *slash; struct vec var_vec; char *p, src_addr[IP_ADDR_STR_LEN]; int i; blk->len = blk->nvars = 0; blk->conn = conn; sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]); addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]); addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]); addenv(blk, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version()); /* Prepare the environment block */ addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */ /* TODO(lsm): fix this for IPv6 case */ addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port)); addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method); addenv(blk, "REMOTE_ADDR=%s", src_addr); addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port); addenv(blk, "REQUEST_URI=%s", conn->request_info.uri); /* SCRIPT_NAME */ assert(conn->request_info.uri[0] == '/'); slash = strrchr(conn->request_info.uri, '/'); if ((s = strrchr(prog, '/')) == NULL) s = prog; addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri), conn->request_info.uri, s); addenv(blk, "SCRIPT_FILENAME=%s", prog); addenv(blk, "PATH_TRANSLATED=%s", prog); addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on"); if ((s = mg_get_header(conn, "Content-Type")) != NULL) addenv(blk, "CONTENT_TYPE=%s", s); if (conn->request_info.query_string != NULL) addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string); if ((s = mg_get_header(conn, "Content-Length")) != NULL) addenv(blk, "CONTENT_LENGTH=%s", s); if ((s = getenv("PATH")) != NULL) addenv(blk, "PATH=%s", s); if (conn->path_info != NULL) { addenv(blk, "PATH_INFO=%s", conn->path_info); } if (conn->status_code > 0) { /* CGI error handler should show the status code */ addenv(blk, "STATUS=%d", conn->status_code); } #if defined(_WIN32) if ((s = getenv("COMSPEC")) != NULL) { addenv(blk, "COMSPEC=%s", s); } if ((s = getenv("SYSTEMROOT")) != NULL) { addenv(blk, "SYSTEMROOT=%s", s); } if ((s = getenv("SystemDrive")) != NULL) { addenv(blk, "SystemDrive=%s", s); } if ((s = getenv("ProgramFiles")) != NULL) { addenv(blk, "ProgramFiles=%s", s); } if ((s = getenv("ProgramFiles(x86)")) != NULL) { addenv(blk, "ProgramFiles(x86)=%s", s); } #else if ((s = getenv("LD_LIBRARY_PATH")) != NULL) addenv(blk, "LD_LIBRARY_PATH=%s", s); #endif /* _WIN32 */ if ((s = getenv("PERLLIB")) != NULL) addenv(blk, "PERLLIB=%s", s); if (conn->request_info.remote_user != NULL) { addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user); addenv(blk, "%s", "AUTH_TYPE=Digest"); } /* Add all headers as HTTP_* variables */ for (i = 0; i < conn->request_info.num_headers; i++) { p = addenv(blk, "HTTP_%s=%s", conn->request_info.http_headers[i].name, conn->request_info.http_headers[i].value); /* Convert variable name into uppercase, and change - to _ */ for (; *p != '=' && *p != '\0'; p++) { if (*p == '-') *p = '_'; *p = (char) toupper(* (unsigned char *) p); } } /* Add user-specified variables */ s = conn->ctx->config[CGI_ENVIRONMENT]; while ((s = next_option(s, &var_vec, NULL)) != NULL) { addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr); } blk->vars[blk->nvars++] = NULL; blk->buf[blk->len++] = '\0'; assert(blk->nvars < (int) ARRAY_SIZE(blk->vars)); assert(blk->len > 0); assert(blk->len < (int) sizeof(blk->buf)); } static void handle_cgi_request(struct mg_connection *conn, const char *prog) { char *buf; size_t buflen; int headers_len, data_len, i, fdin[2] = { 0, 0 }, fdout[2] = { 0, 0 }; const char *status, *status_text, *connection_state; char *pbuf, dir[PATH_MAX], *p; struct mg_request_info ri; struct cgi_env_block blk; FILE *in = NULL, *out = NULL; struct file fout = STRUCT_FILE_INITIALIZER; pid_t pid = (pid_t) -1; buf = NULL; buflen = 16384; prepare_cgi_environment(conn, prog, &blk); /* CGI must be executed in its own directory. 'dir' must point to the directory containing executable program, 'p' must point to the executable program name relative to 'dir'. */ (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog); if ((p = strrchr(dir, '/')) != NULL) { *p++ = '\0'; } else { dir[0] = '.', dir[1] = '\0'; p = (char *) prog; } if (pipe(fdin) != 0 || pipe(fdout) != 0) { send_http_error(conn, 500, http_500_error, "Cannot create CGI pipe: %s", strerror(ERRNO)); goto done; } pid = spawn_process(conn, p, blk.buf, blk.vars, fdin[0], fdout[1], dir); if (pid == (pid_t) -1) { send_http_error(conn, 500, http_500_error, "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO)); goto done; } /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */ set_close_on_exec(fdin[0], conn); set_close_on_exec(fdin[1], conn); set_close_on_exec(fdout[0], conn); set_close_on_exec(fdout[1], conn); /* Parent closes only one side of the pipes. If we don't mark them as closed, close() attempt before return from this function throws an exception on Windows. Windows does not like when closed descriptor is closed again. */ (void) close(fdin[0]); (void) close(fdout[1]); fdin[0] = fdout[1] = -1; if ((in = fdopen(fdin[1], "wb")) == NULL || (out = fdopen(fdout[0], "rb")) == NULL) { send_http_error(conn, 500, http_500_error, "fopen: %s", strerror(ERRNO)); goto done; } setbuf(in, NULL); setbuf(out, NULL); fout.fp = out; /* Send POST data to the CGI process if needed */ if (!strcmp(conn->request_info.request_method, "POST") && !forward_body_data(conn, in, INVALID_SOCKET, NULL)) { goto done; } /* Close so child gets an EOF. */ fclose(in); in = NULL; fdin[1] = -1; /* Now read CGI reply into a buffer. We need to set correct status code, thus we need to see all HTTP headers first. Do not send anything back to client, until we buffer in all HTTP headers. */ data_len = 0; buf = (char *)mg_malloc(buflen); if (buf == NULL) { send_http_error(conn, 500, http_500_error, "Not enough memory for buffer (%u bytes)", (unsigned int) buflen); goto done; } headers_len = read_request(out, conn, buf, (int) buflen, &data_len); if (headers_len <= 0) { send_http_error(conn, 500, http_500_error, "CGI program sent malformed or too big (>%u bytes) " "HTTP headers: [%.*s]", (unsigned) buflen, data_len, buf); goto done; } pbuf = buf; buf[headers_len - 1] = '\0'; parse_http_headers(&pbuf, &ri); /* Make up and send the status line */ status_text = "OK"; if ((status = get_header(&ri, "Status")) != NULL) { conn->status_code = atoi(status); status_text = status; while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') { status_text++; } } else if (get_header(&ri, "Location") != NULL) { conn->status_code = 302; } else { conn->status_code = 200; } connection_state = get_header(&ri, "Connection"); if (connection_state == NULL || mg_strcasecmp(connection_state, "keep-alive")) { conn->must_close = 1; } (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text); /* Send headers */ for (i = 0; i < ri.num_headers; i++) { mg_printf(conn, "%s: %s\r\n", ri.http_headers[i].name, ri.http_headers[i].value); } mg_write(conn, "\r\n", 2); /* Send chunk of data that may have been read after the headers */ conn->num_bytes_sent += mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len)); /* Read the rest of CGI output and send to the client */ send_file_data(conn, &fout, 0, INT64_MAX); done: if (pid != (pid_t) -1) { kill(pid, SIGKILL); #if !defined(_WIN32) { int st; while (waitpid(pid, &st, 0) != -1); /* clean zombies */ } #endif } if (fdin[0] != -1) { close(fdin[0]); } if (fdout[1] != -1) { close(fdout[1]); } if (in != NULL) { fclose(in); } else if (fdin[1] != -1) { close(fdin[1]); } if (out != NULL) { fclose(out); } else if (fdout[0] != -1) { close(fdout[0]); } if (buf != NULL) { mg_free(buf); } } #endif /* !NO_CGI */ /* For a given PUT path, create all intermediate subdirectories for given path. Return 0 if the path itself is a directory, or -1 on error, 1 if OK. */ static int put_dir(struct mg_connection *conn, const char *path) { char buf[PATH_MAX]; const char *s, *p; struct file file = STRUCT_FILE_INITIALIZER; int len, res = 1; for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) { len = (int)(p - path); if (len >= (int) sizeof(buf)) { res = -1; break; } memcpy(buf, path, len); buf[len] = '\0'; /* Try to create intermediate directory */ DEBUG_TRACE("mkdir(%s)", buf); if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) { res = -1; break; } /* Is path itself a directory? */ if (p[1] == '\0') { res = 0; } } return res; } static void mkcol(struct mg_connection *conn, const char *path) { int rc, body_len; struct de de; char date[64]; time_t curtime = time(NULL); memset(&de.file, 0, sizeof(de.file)); if (!mg_stat(conn, path, &de.file)) { mg_cry(conn, "%s: mg_stat(%s) failed: %s", __func__, path, strerror(ERRNO)); } if(de.file.modification_time) { send_http_error(conn, 405, "Method Not Allowed", "mkcol(%s): %s", path, strerror(ERRNO)); return; } body_len = conn->data_len - conn->request_len; if(body_len > 0) { send_http_error(conn, 415, "Unsupported media type", "mkcol(%s): %s", path, strerror(ERRNO)); return; } rc = mg_mkdir(path, 0755); if (rc == 0) { conn->status_code = 201; gmt_time_string(date, sizeof(date), &curtime); mg_printf(conn, "HTTP/1.1 %d Created\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n", conn->status_code, date, suggest_connection_header(conn)); } else if (rc == -1) { if(errno == EEXIST) send_http_error(conn, 405, "Method Not Allowed", "mkcol(%s): %s", path, strerror(ERRNO)); else if(errno == EACCES) send_http_error(conn, 403, "Forbidden", "mkcol(%s): %s", path, strerror(ERRNO)); else if(errno == ENOENT) send_http_error(conn, 409, "Conflict", "mkcol(%s): %s", path, strerror(ERRNO)); else send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path, strerror(ERRNO)); } } static void put_file(struct mg_connection *conn, const char *path) { struct file file = STRUCT_FILE_INITIALIZER; const char *range; int64_t r1, r2; int rc; char date[64]; time_t curtime = time(NULL); conn->status_code = mg_stat(conn, path, &file) ? 200 : 201; if ((rc = put_dir(conn, path)) == 0) { gmt_time_string(date, sizeof(date), &curtime); mg_printf(conn, "HTTP/1.1 %d OK\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n", conn->status_code, date, suggest_connection_header(conn)); } else if (rc == -1) { send_http_error(conn, 500, http_500_error, "put_dir(%s): %s", path, strerror(ERRNO)); } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) { mg_fclose(&file); send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path, strerror(ERRNO)); } else { fclose_on_exec(&file, conn); range = mg_get_header(conn, "Content-Range"); r1 = r2 = 0; if (range != NULL && parse_range_header(range, &r1, &r2) > 0) { conn->status_code = 206; fseeko(file.fp, r1, SEEK_SET); } if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) { conn->status_code = 500; } gmt_time_string(date, sizeof(date), &curtime); mg_printf(conn, "HTTP/1.1 %d OK\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n", conn->status_code, date, suggest_connection_header(conn)); mg_fclose(&file); } } static void send_ssi_file(struct mg_connection *, const char *, struct file *, int); static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level) { char file_name[MG_BUF_LEN], path[512], *p; struct file file = STRUCT_FILE_INITIALIZER; size_t len; /* sscanf() is safe here, since send_ssi_file() also uses buffer of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN. */ if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) { /* File name is relative to the webserver root */ file_name[511]=0; (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s", conn->ctx->config[DOCUMENT_ROOT], '/', file_name); } else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) { /* File name is relative to the webserver working directory or it is absolute system path */ file_name[511]=0; (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name); } else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1 || sscanf(tag, " \"%511[^\"]\"", file_name) == 1) { /* File name is relative to the currect document */ file_name[511]=0; (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi); if ((p = strrchr(path, '/')) != NULL) { p[1] = '\0'; } len = strlen(path); (void) mg_snprintf(conn, path + len, sizeof(path) - len, "%s", file_name); } else { mg_cry(conn, "Bad SSI #include: [%s]", tag); return; } if (!mg_fopen(conn, path, "rb", &file)) { mg_cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", tag, path, strerror(ERRNO)); } else { fclose_on_exec(&file, conn); if (match_prefix(conn->ctx->config[SSI_EXTENSIONS], (int)strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) { send_ssi_file(conn, path, &file, include_level + 1); } else { send_file_data(conn, &file, 0, INT64_MAX); } mg_fclose(&file); } } #if !defined(NO_POPEN) static void do_ssi_exec(struct mg_connection *conn, char *tag) { char cmd[1024] = ""; struct file file = STRUCT_FILE_INITIALIZER; if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) { mg_cry(conn, "Bad SSI #exec: [%s]", tag); } else { cmd[1023]=0; if ((file.fp = popen(cmd, "r")) == NULL) { mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); } else { send_file_data(conn, &file, 0, INT64_MAX); pclose(file.fp); } } } #endif /* !NO_POPEN */ static int mg_fgetc(struct file *filep, int offset) { if (filep->membuf != NULL && offset >=0 && offset < filep->size) { return ((unsigned char *) filep->membuf)[offset]; } else if (filep->fp != NULL) { return fgetc(filep->fp); } else { return EOF; } } static void send_ssi_file(struct mg_connection *conn, const char *path, struct file *filep, int include_level) { char buf[MG_BUF_LEN]; int ch, offset, len, in_ssi_tag; if (include_level > 10) { mg_cry(conn, "SSI #include level is too deep (%s)", path); return; } in_ssi_tag = len = offset = 0; while ((ch = mg_fgetc(filep, offset)) != EOF) { if (in_ssi_tag && ch == '>') { in_ssi_tag = 0; buf[len++] = (char) ch; buf[len] = '\0'; assert(len <= (int) sizeof(buf)); if (len < 6 || memcmp(buf, " host0 --> osd.0 1.0 // | | // | +-> osd.1 1.0 // | // +-> fake --> osd.0 1.0 // | // +-> osd.1 1.0 // // Trying to adjust osd.0 weight to 2.0 in all buckets // Trying to adjust osd.1 weight to 2.0 in host=fake // // So the crush map will be: // // default --> host0 --> osd.0 2.0 // | | // | +-> osd.1 1.0 // | // +-> fake --> osd.0 2.0 // | // +-> osd.1 2.0 // float original_weight = 1.0; float modified_weight = 2.0; map loc_one, loc_two; loc_one["host"] = "host0"; loc_two["host"] = "fake"; item = 0; EXPECT_EQ(2, c->adjust_item_weightf(g_ceph_context, item, modified_weight)); EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_one)); EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_two)); item = 1; EXPECT_EQ(1, c->adjust_item_weightf_in_loc(g_ceph_context, item, modified_weight, loc_two)); EXPECT_EQ(original_weight, c->get_item_weightf_in_loc(item, loc_one)); EXPECT_EQ(modified_weight, c->get_item_weightf_in_loc(item, loc_two)); } TEST(CrushWrapper, insert_item) { CrushWrapper *c = new CrushWrapper; const int ROOT_TYPE = 2; c->set_type_name(ROOT_TYPE, "root"); const int HOST_TYPE = 1; c->set_type_name(HOST_TYPE, "host"); const int OSD_TYPE = 0; c->set_type_name(OSD_TYPE, "osd"); int rootno; c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, ROOT_TYPE, 0, NULL, NULL, &rootno); c->set_item_name(rootno, "default"); int item = 0; // invalid names anywhere in loc trigger an error { map loc; loc["host"] = "\001"; EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } // insert an item in an existing bucket { map loc; loc["root"] = "default"; item++; EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); int another_item = item + 1; EXPECT_EQ(-EEXIST, c->insert_item(g_ceph_context, another_item, 1.0, "osd." + stringify(item), loc)); } // implicit creation of a bucket { string name = "NAME"; map loc; loc["root"] = "default"; loc["host"] = name; item++; EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } // adding to an existing item name that is not associated with a bucket { string name = "ITEM_WITHOUT_BUCKET"; map loc; loc["root"] = "default"; loc["host"] = name; item++; c->set_item_name(item, name); item++; EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } // // When there is: // // default --> host0 --> item // // Trying to insert the same item higher in the hirarchy will fail // because it would create a loop. // // default --> host0 --> item // | // +-> item // { item++; { map loc; loc["root"] = "default"; loc["host"] = "host0"; EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } { map loc; loc["root"] = "default"; EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } } // // When there is: // // default --> host0 // // Trying to insert default under host0 must fail // because it would create a loop. // // default --> host0 --> default // { map loc; loc["host"] = "host0"; EXPECT_EQ(-ELOOP, c->insert_item(g_ceph_context, rootno, 1.0, "default", loc)); } // fail when mapping a bucket to the wrong type { // create an OSD bucket int osdno; int r = c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, 10, 0, NULL, NULL, &osdno); ASSERT_EQ(0, r); c->set_item_name(osdno, "myosd"); map loc; loc["root"] = "default"; // wrongfully pretend the osd is of type host loc["host"] = "myosd"; item++; EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } // fail when no location { map loc; item++; EXPECT_EQ(-EINVAL, c->insert_item(g_ceph_context, item, 1.0, "osd." + stringify(item), loc)); } delete c; } TEST(CrushWrapper, item_bucket_names) { CrushWrapper *c = new CrushWrapper; int index = 123; string name = "NAME"; EXPECT_EQ(-EINVAL, c->set_item_name(index, "\001")); EXPECT_EQ(0, c->set_item_name(index, name)); EXPECT_TRUE(c->name_exists(name)); EXPECT_TRUE(c->item_exists(index)); EXPECT_EQ(index, c->get_item_id(name)); EXPECT_EQ(name, c->get_item_name(index)); delete c; } TEST(CrushWrapper, bucket_types) { CrushWrapper *c = new CrushWrapper; int index = 123; string name = "NAME"; c->set_type_name(index, name); EXPECT_EQ(1, c->get_num_type_names()); EXPECT_EQ(index, c->get_type_id(name)); EXPECT_EQ(name, c->get_type_name(index)); delete c; } TEST(CrushWrapper, is_valid_crush_name) { EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_")); EXPECT_FALSE(CrushWrapper::is_valid_crush_name("")); EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001")); } TEST(CrushWrapper, is_valid_crush_loc) { map loc; EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); loc["good"] = "better"; EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); { map loc; loc["\005"] = "default"; EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); } { map loc; loc["host"] = "\003"; EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context, loc)); } } TEST(CrushWrapper, dump_rules) { CrushWrapper *c = new CrushWrapper; const int ROOT_TYPE = 1; c->set_type_name(ROOT_TYPE, "root"); const int OSD_TYPE = 0; c->set_type_name(OSD_TYPE, "osd"); string failure_domain_type("osd"); string root_name("default"); int rootno; c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, ROOT_TYPE, 0, NULL, NULL, &rootno); c->set_item_name(rootno, root_name); int item = 0; pair loc; int ret; loc = c->get_immediate_parent(item, &ret); EXPECT_EQ(-ENOENT, ret); { map loc; loc["root"] = root_name; EXPECT_EQ(0, c->insert_item(g_ceph_context, item, 1.0, "osd.0", loc)); } // no ruleset by default { Formatter *f = new_formatter("json-pretty"); c->dump_rules(f); stringstream ss; f->flush(ss); delete f; EXPECT_EQ("", ss.str()); } string name("NAME"); int ruleset = c->add_simple_ruleset(name, root_name, failure_domain_type, "firstn", pg_pool_t::TYPE_ERASURE); EXPECT_EQ(0, ruleset); { Formatter *f = new_formatter("xml"); c->dump_rules(f); stringstream ss; f->flush(ss); delete f; EXPECT_EQ((unsigned)0, ss.str().find("0NAME")); } { Formatter *f = new_formatter("xml"); c->dump_rule(ruleset, f); stringstream ss; f->flush(ss); delete f; EXPECT_EQ((unsigned)0, ss.str().find("0NAME")); EXPECT_NE(string::npos, ss.str().find("default")); } map wm; c->get_rule_weight_osd_map(0, &wm); ASSERT_TRUE(wm.size() == 1); ASSERT_TRUE(wm[0] == 1.0); delete c; } TEST(CrushWrapper, distance) { CrushWrapper c; c.create(); c.set_type_name(1, "host"); c.set_type_name(2, "rack"); c.set_type_name(3, "root"); int bno; int r = c.add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_DEFAULT, 3, 0, NULL, NULL, &bno); ASSERT_EQ(0, r); ASSERT_EQ(-1, bno); c.set_item_name(bno, "default"); c.set_max_devices(10); //JSONFormatter jf(true); map loc; loc["host"] = "a1"; loc["rack"] = "a"; loc["root"] = "default"; c.insert_item(g_ceph_context, 0, 1, "osd.0", loc); loc.clear(); loc["host"] = "a2"; loc["rack"] = "a"; loc["root"] = "default"; c.insert_item(g_ceph_context, 1, 1, "osd.1", loc); loc.clear(); loc["host"] = "b1"; loc["rack"] = "b"; loc["root"] = "default"; c.insert_item(g_ceph_context, 2, 1, "osd.2", loc); loc.clear(); loc["host"] = "b2"; loc["rack"] = "b"; loc["root"] = "default"; c.insert_item(g_ceph_context, 3, 1, "osd.3", loc); vector > ol; c.get_full_location_ordered(3, ol); ASSERT_EQ(3u, ol.size()); ASSERT_EQ(make_pair(string("host"),string("b2")), ol[0]); ASSERT_EQ(make_pair(string("rack"),string("b")), ol[1]); ASSERT_EQ(make_pair(string("root"),string("default")), ol[2]); //c.dump(&jf); //jf.flush(cout); multimap p; p.insert(make_pair("host","b2")); p.insert(make_pair("rack","b")); p.insert(make_pair("root","default")); ASSERT_EQ(3, c.get_common_ancestor_distance(g_ceph_context, 0, p)); ASSERT_EQ(3, c.get_common_ancestor_distance(g_ceph_context, 1, p)); ASSERT_EQ(2, c.get_common_ancestor_distance(g_ceph_context, 2, p)); ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 3, p)); ASSERT_EQ(-ENOENT, c.get_common_ancestor_distance(g_ceph_context, 123, p)); // make sure a "multipath" location will reflect a minimal // distance for both paths p.insert(make_pair("host","b1")); ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 2, p)); ASSERT_EQ(1, c.get_common_ancestor_distance(g_ceph_context, 3, p)); } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); vector def_args; def_args.push_back("--debug-crush=0"); global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } /* * Local Variables: * compile-command: "cd ../.. ; make -j4 unittest_crush_wrapper && * valgrind \ * --max-stackframe=20000000 --tool=memcheck \ * ./unittest_crush_wrapper --log-to-stderr=true --debug-crush=20 \ * # --gtest_filter=CrushWrapper.insert_item" * End: */ ceph-0.80.11/src/test/crush/indep.cc0000664000175100017510000001517612623076744021207 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * LGPL2.1 (see COPYING-LGPL2.1) or later */ #include #include #include "include/stringify.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "global/global_context.h" #include "crush/CrushWrapper.h" #include CrushWrapper *build_indep_map(CephContext *cct, int num_rack, int num_host, int num_osd) { CrushWrapper *c = new CrushWrapper; c->create(); c->set_type_name(5, "root"); c->set_type_name(4, "row"); c->set_type_name(3, "rack"); c->set_type_name(2, "chasis"); c->set_type_name(1, "host"); c->set_type_name(0, "osd"); int rootno; c->add_bucket(0, CRUSH_BUCKET_STRAW, CRUSH_HASH_RJENKINS1, 5, 0, NULL, NULL, &rootno); c->set_item_name(rootno, "default"); map loc; loc["root"] = "default"; int osd = 0; for (int r=0; rinsert_item(cct, osd, 1.0, string("osd.") + stringify(osd), loc); } } } int ret; int ruleno = 0; int ruleset = 0; ruleno = ruleset; ret = c->add_rule(4, ruleset, 123, 1, 20, ruleno); assert(ret == ruleno); ret = c->set_rule_step(ruleno, 0, CRUSH_RULE_SET_CHOOSELEAF_TRIES, 10, 0); assert(ret == 0); ret = c->set_rule_step(ruleno, 1, CRUSH_RULE_TAKE, rootno, 0); assert(ret == 0); ret = c->set_rule_step(ruleno, 2, CRUSH_RULE_CHOOSELEAF_INDEP, CRUSH_CHOOSE_N, 1); assert(ret == 0); ret = c->set_rule_step(ruleno, 3, CRUSH_RULE_EMIT, 0, 0); assert(ret == 0); c->set_rule_name(ruleno, "data"); if (false) { Formatter *f = new_formatter("json-pretty"); f->open_object_section("crush_map"); c->dump(f); f->close_section(); f->flush(cout); delete f; } return c; } int get_num_dups(const vector& v) { std::set s; int dups = 0; for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); c->dump_tree(weight, &cout, NULL); for (int x = 0; x < 100; ++x) { vector out; c->do_rule(0, x, out, 5, weight); cout << x << " -> " << out << std::endl; int num_none = 0; for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); c->dump_tree(weight, &cout, NULL); for (int x = 0; x < 100; ++x) { vector out; c->do_rule(0, x, out, 5, weight); cout << x << " -> " << out << std::endl; int num_none = 0; for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); // mark a bunch of osds out int num = 3*3*3; for (int i=0; idump_tree(weight, &cout, NULL); // need more retries to get 9/9 hosts for x in 0..99 c->set_choose_total_tries(100); for (int x = 0; x < 100; ++x) { vector out; c->do_rule(0, x, out, 9, weight); cout << x << " -> " << out << std::endl; int num_none = 0; for (unsigned i=0; i weight(c->get_max_devices(), 0x10000); // mark a bunch of osds out int num = 3*3*3; for (int i=0; idump_tree(weight, &cout, NULL); c->set_choose_total_tries(100); for (int x = 0; x < 100; ++x) { vector out; c->do_rule(0, x, out, 7, weight); cout << x << " -> " << out << std::endl; int num_none = 0; for (unsigned i=0; iset_choose_total_tries(100); vector<__u32> tweight(c->get_max_devices(), 0x10000); c->dump_tree(tweight, &cout, NULL); int tchanged = 0; for (int x = 1; x < 5; ++x) { vector<__u32> weight(c->get_max_devices(), 0x10000); std::map pos; vector prev; for (unsigned i=0; i out; c->do_rule(0, x, out, 7, weight); cout << "(" << i << "/" << weight.size() << " out) " << x << " -> " << out << std::endl; int num_none = 0; for (unsigned k=0; k args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/test_get_blkdev_size.cc0000664000175100017510000000112212623076744023145 0ustar jenkins-buildjenkins-build#include #include #include #include #include #include #include #include "common/blkdev.h" int main(int argc, char **argv) { int fd, ret; int64_t size; if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); return -1; } fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); return -1; } ret = get_block_device_size(fd, &size); if (ret < 0) { fprintf(stderr, "get_block_device_size: %s\n", strerror(-ret)); return -1; } fprintf(stdout, "%" PRId64, size); return 0; } ceph-0.80.11/src/test/heartbeat_map.cc0000664000175100017510000000203512623076744021546 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/Mutex.h" #include "common/HeartbeatMap.h" #include "common/ceph_context.h" #include "test/unit.h" #include "common/config.h" using namespace ceph; TEST(HeartbeatMap, Healthy) { HeartbeatMap hm(g_ceph_context); heartbeat_handle_d *h = hm.add_worker("one"); hm.reset_timeout(h, 9, 18); bool healthy = hm.is_healthy(); ASSERT_EQ(healthy, true); hm.remove_worker(h); } TEST(HeartbeatMap, Unhealth) { HeartbeatMap hm(g_ceph_context); heartbeat_handle_d *h = hm.add_worker("one"); hm.reset_timeout(h, 1, 3); sleep(2); bool healthy = hm.is_healthy(); ASSERT_EQ(healthy, false); hm.remove_worker(h); } ceph-0.80.11/src/test/cls_replica_log/0000775000175100017510000000000012623077035021556 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/cls_replica_log/test_cls_replica_log.cc0000664000175100017510000001122312623076744026252 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * Copyright 2013 Inktank */ #include "gtest/gtest.h" #include "test/librados/test.h" #include "cls/replica_log/cls_replica_log_client.h" #include "cls/replica_log/cls_replica_log_types.h" class cls_replica_log_Test : public ::testing::Test { public: librados::Rados rados; librados::IoCtx ioctx; string pool_name; string oid; string entity; string marker; utime_t time; list > entries; cls_replica_log_progress_marker progress; void SetUp() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); oid = "obj"; ASSERT_EQ(0, ioctx.create(oid, true)); } void add_marker() { entity = "tester_entity"; marker = "tester_marker1"; time.set_from_double(10); entries.push_back(make_pair("tester_obj1", time)); time.set_from_double(20); cls_replica_log_prepare_marker(progress, entity, marker, time, &entries); librados::ObjectWriteOperation opw; cls_replica_log_update_bound(opw, progress); ASSERT_EQ(0, ioctx.operate(oid, &opw)); } }; TEST_F(cls_replica_log_Test, test_set_get_marker) { add_marker(); string reply_position_marker; utime_t reply_time; list return_progress_list; ASSERT_EQ(0, cls_replica_log_get_bounds(ioctx, oid, reply_position_marker, reply_time, return_progress_list)); ASSERT_EQ(reply_position_marker, marker); ASSERT_EQ((double)10, (double)reply_time); string response_entity; string response_marker; utime_t response_time; list > response_item_list; cls_replica_log_extract_marker(return_progress_list.front(), response_entity, response_marker, response_time, response_item_list); ASSERT_EQ(response_entity, entity); ASSERT_EQ(response_marker, marker); ASSERT_EQ(response_time, time); ASSERT_EQ((unsigned)1, response_item_list.size()); ASSERT_EQ("tester_obj1", response_item_list.front().first); } TEST_F(cls_replica_log_Test, test_bad_update) { add_marker(); time.set_from_double(15); cls_replica_log_progress_marker bad_marker; cls_replica_log_prepare_marker(bad_marker, entity, marker, time, &entries); librados::ObjectWriteOperation badw; cls_replica_log_update_bound(badw, bad_marker); ASSERT_EQ(-EINVAL, ioctx.operate(oid, &badw)); } TEST_F(cls_replica_log_Test, test_bad_delete) { add_marker(); librados::ObjectWriteOperation badd; cls_replica_log_delete_bound(badd, entity); ASSERT_EQ(-ENOTEMPTY, ioctx.operate(oid, &badd)); } TEST_F(cls_replica_log_Test, test_good_delete) { add_marker(); librados::ObjectWriteOperation opc; progress.items.clear(); cls_replica_log_update_bound(opc, progress); ASSERT_EQ(0, ioctx.operate(oid, &opc)); librados::ObjectWriteOperation opd; cls_replica_log_delete_bound(opd, entity); ASSERT_EQ(0, ioctx.operate(oid, &opd)); string reply_position_marker; utime_t reply_time; list return_progress_list; ASSERT_EQ(0, cls_replica_log_get_bounds(ioctx, oid, reply_position_marker, reply_time, return_progress_list)); ASSERT_EQ((unsigned)0, return_progress_list.size()); } TEST_F(cls_replica_log_Test, test_bad_get) { string reply_position_marker; utime_t reply_time; list return_progress_list; ASSERT_EQ(-ENOENT, cls_replica_log_get_bounds(ioctx, oid, reply_position_marker, reply_time, return_progress_list)); } TEST_F(cls_replica_log_Test, test_double_delete) { add_marker(); librados::ObjectWriteOperation opc; progress.items.clear(); cls_replica_log_update_bound(opc, progress); ASSERT_EQ(0, ioctx.operate(oid, &opc)); librados::ObjectWriteOperation opd; cls_replica_log_delete_bound(opd, entity); ASSERT_EQ(0, ioctx.operate(oid, &opd)); librados::ObjectWriteOperation opd2; cls_replica_log_delete_bound(opd2, entity); ASSERT_EQ(0, ioctx.operate(oid, &opd2)); string reply_position_marker; utime_t reply_time; list return_progress_list; ASSERT_EQ(0, cls_replica_log_get_bounds(ioctx, oid, reply_position_marker, reply_time, return_progress_list)); ASSERT_EQ((unsigned)0, return_progress_list.size()); } ceph-0.80.11/src/test/objectstore/0000775000175100017510000000000012623077036020761 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/objectstore/test_idempotent_sequence.cc0000664000175100017510000001514112623076744026376 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/debug.h" #include "os/FileStore.h" #include "DeterministicOpSequence.h" #include "FileStoreDiff.h" #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_ #undef dout_prefix #define dout_prefix *_dout << "test_idempotent_sequence " void usage(const char *name, std::string command = "") { assert(name != NULL); std::string more = "cmd "; std::string diff = "diff "; std::string get_last_op = "get-last-op "; std::string run_seq_to = "run-sequence-to "; if (!command.empty()) { if (command == "diff") more = diff; else if (command == "get-last-op") more = get_last_op; else if (command == "run-sequence-to") more = run_seq_to; } std::cout << "usage: " << name << " " << more << " [options]" << std::endl; std::cout << "\n\ Commands:\n\ " << diff << "\n\ " << get_last_op << "\n\ " << run_seq_to << "\n\ \n\ Global Options:\n\ -c FILE Read configuration from FILE\n\ --osd-data PATH Set OSD Data path\n\ --osd-journal PATH Set OSD Journal path\n\ --osd-journal-size VAL Set Journal size\n\ --help This message\n\ \n\ Test-specific Options:\n\ --test-seed VAL Seed to run the test\n\ --test-status-file PATH Path to keep the status file\n\ --test-num-colls VAL Number of collections to create on init\n\ --test-num-objs VAL Number of objects to create on init\n\ " << std::endl; } const char *our_name = NULL; int seed = 0, num_txs = 100, num_colls = 30, num_objs = 0; bool is_seed_set = false; int verify_at = 0; std::string status_file; int run_diff(std::string& a_path, std::string& a_journal, std::string& b_path, std::string& b_journal) { FileStore *a = new FileStore(a_path, a_journal, 0, "a"); FileStore *b = new FileStore(b_path, b_journal, 0, "b"); int ret = 0; { FileStoreDiff fsd(a, b); if (fsd.diff()) { dout(0) << "diff found an difference" << dendl; ret = -1; } else { dout(0) << "no diff" << dendl; } } delete a; delete b; return ret; } int run_get_last_op(std::string& filestore_path, std::string& journal_path) { FileStore *store = new FileStore(filestore_path, journal_path); int err = store->mount(); if (err) { store->umount(); delete store; return err; } coll_t txn_coll("meta"); hobject_t txn_object(sobject_t("txn", CEPH_NOSNAP)); bufferlist bl; store->read(txn_coll, txn_object, 0, 100, bl); int32_t txn = 0; if (bl.length()) { bufferlist::iterator p = bl.begin(); ::decode(txn, p); } store->umount(); delete store; cout << txn << std::endl; return 0; } int run_sequence_to(int val, std::string& filestore_path, std::string& journal_path) { num_txs = val; if (!is_seed_set) seed = (int) time(NULL); FileStore *store = new FileStore(filestore_path, journal_path); int err; // mkfs iff directory dne err = ::mkdir(filestore_path.c_str(), 0755); if (err) { cerr << filestore_path << " already exists" << std::endl; store->umount(); delete store; return err; } err = store->mkfs(); ceph_assert(err == 0); err = store->mount(); ceph_assert(err == 0); DeterministicOpSequence op_sequence(store, status_file); op_sequence.init(num_colls, num_objs); op_sequence.generate(seed, num_txs); store->umount(); return 0; } int run_command(std::string& command, std::vector& args) { if (command.empty()) { usage(our_name); exit(0); } /* We'll have a class that will handle the options, the command * and its arguments. For the time being, and so we can move on, let's * tolerate this big, ugly code. */ if (command == "diff") { /* expect 4 arguments: (filestore path + journal path)*2 */ if (args.size() == 4) { return run_diff(args[0], args[1], args[2], args[3]); } } else if (command == "get-last-op") { /* expect 2 arguments: a filestore path + journal */ if (args.size() == 2) { return run_get_last_op(args[0], args[1]); } } else if (command == "run-sequence-to") { /* expect 3 arguments: # of operations and a filestore path + journal. */ if (args.size() == 3) { return run_sequence_to(strtoll(args[0].c_str(), NULL, 10), args[1], args[2]); } } else { std::cout << "unknown command " << command << std::endl; usage(our_name); exit(1); } usage(our_name, command); exit(1); } int main(int argc, const char *argv[]) { vector def_args; vector args; our_name = argv[0]; argv_to_vec(argc, argv, args); global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); std::string command; std::vector command_args; for (std::vector::iterator i = args.begin(); i != args.end();) { string val; if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_witharg(args, i, &val, "--test-seed", (char*) NULL)) { seed = strtoll(val.c_str(), NULL, 10); is_seed_set = true; } else if (ceph_argparse_witharg(args, i, &val, "--test-num-colls", (char*) NULL)) { num_colls = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-num-objs", (char*) NULL)) { num_objs = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-status-file", (char*) NULL)) { status_file = val; } else if (ceph_argparse_flag(args, i, "--help", (char*) NULL)) { usage(our_name); exit(0); } else { if (command.empty()) command = *i++; else command_args.push_back(string(*i++)); } } int ret = run_command(command, command_args); return ret; } ceph-0.80.11/src/test/objectstore/workload_generator.h0000664000175100017510000001164512623076744025036 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef WORKLOAD_GENERATOR_H_ #define WORKLOAD_GENERATOR_H_ #include "os/ObjectStore.h" #include #include #include #include #include #include "TestObjectStoreState.h" typedef boost::mt11213b rngen_t; class WorkloadGenerator : public TestObjectStoreState { public: static const int def_max_in_flight = 50; static const int def_destroy_coll_every_nr_runs = 100; static const int def_num_obj_per_coll = 6000; static const int def_num_colls = 30; static const size_t min_write_bytes = 1; static const size_t max_write_mb = 5; static const size_t max_write_bytes = (max_write_mb * 1024 * 1024); static const size_t min_xattr_obj_bytes = 2; static const size_t max_xattr_obj_bytes = 300; static const size_t min_xattr_coll_bytes = 4; static const size_t max_xattr_coll_bytes = 600; static const size_t log_append_bytes = 1024; struct C_StatState { utime_t start; unsigned int written_data; WorkloadGenerator *wrkldgen; C_StatState(WorkloadGenerator *state, utime_t s) : start(s), written_data(0), wrkldgen(state) { } }; protected: int m_max_in_flight; int m_num_ops; int m_destroy_coll_every_nr_runs; atomic_t m_nr_runs; int m_num_colls; rngen_t m_rng; map pg_log_size; size_t m_write_data_bytes; size_t m_write_xattr_obj_bytes; size_t m_write_xattr_coll_bytes; size_t m_write_pglog_bytes; bool m_suppress_write_data; bool m_suppress_write_xattr_obj; bool m_suppress_write_xattr_coll; bool m_suppress_write_log; bool m_do_stats; int m_stats_finished_txs; Mutex m_stats_lock; int m_stats_show_secs; size_t m_stats_total_written; utime_t m_stats_begin; private: void _suppress_ops_or_die(std::string& val); size_t _parse_size_or_die(std::string& val); void init_args(vector args); int get_uniform_random_value(int min, int max); coll_entry_t *get_rnd_coll_entry(bool erase); hobject_t *get_rnd_obj(coll_entry_t *entry); int get_random_collection_nr(); int get_random_object_nr(int coll_nr); size_t get_random_byte_amount(size_t min, size_t max); void get_filled_byte_array(bufferlist& bl, size_t size); void do_write_object(ObjectStore::Transaction *t, coll_t coll, hobject_t obj, C_StatState *stat); void do_setattr_object(ObjectStore::Transaction *t, coll_t coll, hobject_t obj, C_StatState *stat); void do_setattr_collection(ObjectStore::Transaction *t, coll_t coll, C_StatState *stat); void do_append_log(ObjectStore::Transaction *t, coll_entry_t *entry, C_StatState *stat); bool should_destroy_collection() { return ((m_destroy_coll_every_nr_runs > 0) && ((int)m_nr_runs.read() >= m_destroy_coll_every_nr_runs)); } void do_destroy_collection(ObjectStore::Transaction *t, coll_entry_t *entry, C_StatState *stat); coll_entry_t *do_create_collection(ObjectStore::Transaction *t, C_StatState *stat); void do_stats(); public: WorkloadGenerator(vector args); ~WorkloadGenerator() { m_store->umount(); } class C_OnReadable: public TestObjectStoreState::C_OnFinished { WorkloadGenerator *wrkldgen_state; public: C_OnReadable(WorkloadGenerator *state, ObjectStore::Transaction *t) :TestObjectStoreState::C_OnFinished(state, t), wrkldgen_state(state) { } void finish(int r) { TestObjectStoreState::C_OnFinished::finish(r); wrkldgen_state->m_nr_runs.inc(); } }; class C_OnDestroyed: public C_OnReadable { coll_entry_t *m_entry; public: C_OnDestroyed(WorkloadGenerator *state, ObjectStore::Transaction *t, coll_entry_t *entry) : C_OnReadable(state, t), m_entry(entry) {} void finish(int r) { C_OnReadable::finish(r); delete m_entry; } }; class C_StatWrapper : public Context { C_StatState *stat_state; Context *ctx; public: C_StatWrapper(C_StatState *state, Context *context) : stat_state(state), ctx(context) { } void finish(int r) { ctx->complete(r); stat_state->wrkldgen->m_stats_lock.Lock(); stat_state->wrkldgen->m_stats_total_written += stat_state->written_data; stat_state->wrkldgen->m_stats_finished_txs ++; stat_state->wrkldgen->m_stats_lock.Unlock(); } }; void run(void); }; bool operator<(const WorkloadGenerator::coll_entry_t& l, const WorkloadGenerator::coll_entry_t& r) { return (l.m_id < r.m_id); } #endif /* WORKLOAD_GENERATOR_H_ */ ceph-0.80.11/src/test/objectstore/chain_xattr.cc0000664000175100017510000002401312623076744023601 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "os/chain_xattr.h" #include "include/Context.h" #include "common/errno.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include #define LARGE_BLOCK_LEN CHAIN_XATTR_MAX_BLOCK_LEN + 1024 #define FILENAME "bufferlist" TEST(chain_xattr, get_and_set) { const char* file = "testfile"; ::unlink(file); int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); const string user("user."); { const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); const string x(LARGE_BLOCK_LEN, 'X'); { char y[LARGE_BLOCK_LEN]; ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ(LARGE_BLOCK_LEN, chain_getxattr(file, name.c_str(), 0, 0)); ASSERT_EQ(LARGE_BLOCK_LEN, chain_getxattr(file, name.c_str(), y, LARGE_BLOCK_LEN)); ASSERT_EQ(0, chain_removexattr(file, name.c_str())); ASSERT_EQ(0, memcmp(x.c_str(), y, LARGE_BLOCK_LEN)); } { char y[LARGE_BLOCK_LEN]; ASSERT_EQ(LARGE_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ(LARGE_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), 0, 0)); ASSERT_EQ(LARGE_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), y, LARGE_BLOCK_LEN)); ASSERT_EQ(0, chain_fremovexattr(fd, name.c_str())); ASSERT_EQ(0, memcmp(x.c_str(), y, LARGE_BLOCK_LEN)); } } // // when chain_setxattr is used to store value that is // CHAIN_XATTR_MAX_BLOCK_LEN * 2 + 10 bytes long it // // add user.foo => CHAIN_XATTR_MAX_BLOCK_LEN bytes // add user.foo@1 => CHAIN_XATTR_MAX_BLOCK_LEN bytes // add user.foo@2 => 10 bytes // // then ( no chain_removexattr in between ) when it is used to // override with a value that is exactly CHAIN_XATTR_MAX_BLOCK_LEN // bytes long it will // // replace user.foo => CHAIN_XATTR_MAX_BLOCK_LEN bytes // remove user.foo@1 => CHAIN_XATTR_MAX_BLOCK_LEN bytes // leak user.foo@2 => 10 bytes // // see http://marc.info/?l=ceph-devel&m=136027076615853&w=4 for the // discussion // { const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); const string x(LARGE_BLOCK_LEN, 'X'); { char y[CHAIN_XATTR_MAX_NAME_LEN]; ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), CHAIN_XATTR_MAX_BLOCK_LEN)); ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_getxattr(file, name.c_str(), 0, 0)); ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_getxattr(file, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); ASSERT_EQ(0, chain_removexattr(file, name.c_str())); ASSERT_EQ(0, memcmp(x.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); } { char y[CHAIN_XATTR_MAX_BLOCK_LEN]; ASSERT_EQ(LARGE_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), CHAIN_XATTR_MAX_BLOCK_LEN)); ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), 0, 0)); ASSERT_EQ(CHAIN_XATTR_MAX_BLOCK_LEN, chain_fgetxattr(fd, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); ASSERT_EQ(0, chain_fremovexattr(fd, name.c_str())); ASSERT_EQ(0, memcmp(x.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); } } { int x = 0; ASSERT_EQ(-ENOENT, chain_setxattr("UNLIKELY_TO_EXIST", "NAME", &x, sizeof(x))); ASSERT_EQ(-ENOENT, chain_getxattr("UNLIKELY_TO_EXIST", "NAME", 0, 0)); ASSERT_EQ(-ENOENT, chain_getxattr("UNLIKELY_TO_EXIST", "NAME", &x, sizeof(x))); ASSERT_EQ(-ENOENT, chain_removexattr("UNLIKELY_TO_EXIST", "NAME")); int unlikely_to_be_a_valid_fd = 400; ASSERT_EQ(-EBADF, chain_fsetxattr(unlikely_to_be_a_valid_fd, "NAME", &x, sizeof(x))); ASSERT_EQ(-EBADF, chain_fgetxattr(unlikely_to_be_a_valid_fd, "NAME", 0, 0)); ASSERT_EQ(-EBADF, chain_fgetxattr(unlikely_to_be_a_valid_fd, "NAME", &x, sizeof(x))); ASSERT_EQ(-EBADF, chain_fremovexattr(unlikely_to_be_a_valid_fd, "NAME")); } { int x; const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN * 2, '@'); ASSERT_THROW(chain_setxattr(file, name.c_str(), &x, sizeof(x)), FailedAssertion); ASSERT_THROW(chain_fsetxattr(fd, name.c_str(), &x, sizeof(x)), FailedAssertion); } { const string name = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); const string x(LARGE_BLOCK_LEN, 'X'); { char y[LARGE_BLOCK_LEN]; ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ(-ERANGE, chain_getxattr(file, name.c_str(), y, LARGE_BLOCK_LEN - 1)); ASSERT_EQ(-ERANGE, chain_getxattr(file, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); ASSERT_EQ(0, chain_removexattr(file, name.c_str())); } { char y[LARGE_BLOCK_LEN]; ASSERT_EQ(LARGE_BLOCK_LEN, chain_fsetxattr(fd, name.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ(-ERANGE, chain_fgetxattr(fd, name.c_str(), y, LARGE_BLOCK_LEN - 1)); ASSERT_EQ(-ERANGE, chain_fgetxattr(fd, name.c_str(), y, CHAIN_XATTR_MAX_BLOCK_LEN)); ASSERT_EQ(0, chain_fremovexattr(fd, name.c_str())); } } ::close(fd); ::unlink(file); } TEST(chain_xattr, chunk_aligned) { const char* file = FILENAME; ::unlink(file); int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); const string user("user."); // set N* chunk size const string name = "user.foo"; const string name2 = "user.bar"; for (int len = CHAIN_XATTR_MAX_BLOCK_LEN - 10; len < CHAIN_XATTR_MAX_BLOCK_LEN + 10; ++len) { cout << len << std::endl; const string x(len, 'x'); char buf[len*2]; ASSERT_EQ(len, chain_setxattr(file, name.c_str(), x.c_str(), len)); char attrbuf[4096]; int l = ceph_os_listxattr(file, attrbuf, sizeof(attrbuf)); for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { cout << " attr " << p << std::endl; } ASSERT_EQ(len, chain_getxattr(file, name.c_str(), buf, len*2)); ASSERT_EQ(0, chain_removexattr(file, name.c_str())); ASSERT_EQ(len, chain_fsetxattr(fd, name2.c_str(), x.c_str(), len)); l = ceph_os_flistxattr(fd, attrbuf, sizeof(attrbuf)); for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { cout << " attr " << p << std::endl; } ASSERT_EQ(len, chain_fgetxattr(fd, name2.c_str(), buf, len*2)); ASSERT_EQ(0, chain_fremovexattr(fd, name2.c_str())); } ::close(fd); ::unlink(file); } TEST(chain_xattr, listxattr) { const char* file = "testfile"; ::unlink(file); int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); const string user("user."); const string name1 = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '1'); const string name2 = user + string(CHAIN_XATTR_MAX_NAME_LEN - user.size(), '@'); const string x(LARGE_BLOCK_LEN, 'X'); const int y = 1234; ASSERT_EQ(LARGE_BLOCK_LEN, chain_setxattr(file, name1.c_str(), x.c_str(), LARGE_BLOCK_LEN)); ASSERT_EQ((int)sizeof(y), chain_setxattr(file, name2.c_str(), &y, sizeof(y))); int buffer_size = name1.size() + sizeof('\0') + name2.size() + sizeof('\0'); char* expected = (char*)malloc(buffer_size); ::strcpy(expected, name1.c_str()); ::strcpy(expected + name1.size() + 1, name2.c_str()); char* actual = (char*)calloc(1, buffer_size); ASSERT_LT(buffer_size, chain_listxattr(file, NULL, 0)); // size evaluation is conservative chain_listxattr(file, actual, buffer_size); ::memset(actual, '\0', buffer_size); chain_flistxattr(fd, actual, buffer_size); ASSERT_EQ(0, ::memcmp(expected, actual, buffer_size)); int unlikely_to_be_a_valid_fd = 400; ASSERT_GT(0, chain_listxattr("UNLIKELY_TO_EXIST", actual, 0)); ASSERT_GT(0, chain_listxattr("UNLIKELY_TO_EXIST", actual, buffer_size)); ASSERT_GT(0, chain_flistxattr(unlikely_to_be_a_valid_fd, actual, 0)); ASSERT_GT(0, chain_flistxattr(unlikely_to_be_a_valid_fd, actual, buffer_size)); ASSERT_EQ(-ERANGE, chain_listxattr(file, actual, 1)); ASSERT_EQ(-ERANGE, chain_flistxattr(fd, actual, 1)); ASSERT_EQ(0, chain_removexattr(file, name1.c_str())); ASSERT_EQ(0, chain_removexattr(file, name2.c_str())); ::unlink(file); } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_ceph_context->_conf->set_val("err_to_stderr", "false"); g_ceph_context->_conf->set_val("log_to_stderr", "false"); g_ceph_context->_conf->apply_changes(NULL); const char* file = "testfile"; int x = 1234; int y = 0; int tmpfd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); int ret = ::ceph_os_fsetxattr(tmpfd, "user.test", &x, sizeof(x)); if (ret >= 0) ret = ::ceph_os_fgetxattr(tmpfd, "user.test", &y, sizeof(y)); ::close(tmpfd); ::unlink(file); if ((ret < 0) || (x != y)) { cerr << "SKIP all tests because extended attributes don't appear to work in the file system in which the tests are run: " << cpp_strerror(ret) << std::endl; } else { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } } // Local Variables: // compile-command: "cd ../.. ; make unittest_chain_xattr ; valgrind --tool=memcheck ./unittest_chain_xattr # --gtest_filter=chain_xattr.get_and_set" // End: ceph-0.80.11/src/test/objectstore/DeterministicOpSequence.h0000664000175100017510000000565012623076744025740 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef FILESTORE_DTRMNSTC_SEQ_OPS_H_ #define FILESTORE_DTRMNSTC_SEQ_OPS_H_ #include #include #include #include "os/ObjectStore.h" #include #include #include #include "TestObjectStoreState.h" typedef boost::mt11213b rngen_t; class DeterministicOpSequence : public TestObjectStoreState { public: DeterministicOpSequence(ObjectStore *store, std::string status = std::string()); virtual ~DeterministicOpSequence(); virtual void generate(int seed, int num_txs); protected: enum { DSOP_TOUCH = 0, DSOP_WRITE = 1, DSOP_CLONE = 2, DSOP_CLONE_RANGE = 3, DSOP_OBJ_REMOVE = 4, DSOP_COLL_RENAME = 5, DSOP_COLL_ADD = 6, DSOP_SET_ATTRS = 7, DSOP_FIRST = DSOP_TOUCH, DSOP_LAST = DSOP_SET_ATTRS, }; int32_t txn; coll_t txn_coll; hobject_t txn_object; ObjectStore::Sequencer m_osr; std::ofstream m_status; bool run_one_op(int op, rngen_t& gen); void note_txn(ObjectStore::Transaction *t); bool do_touch(rngen_t& gen); bool do_remove(rngen_t& gen); bool do_write(rngen_t& gen); bool do_clone(rngen_t& gen); bool do_clone_range(rngen_t& gen); bool do_coll_rename(rngen_t& gen); bool do_coll_add(rngen_t& gen); bool do_set_attrs(rngen_t& gen); virtual void _do_touch(coll_t coll, hobject_t& obj); virtual void _do_remove(coll_t coll, hobject_t& obj); virtual void _do_write(coll_t coll, hobject_t& obj, uint64_t off, uint64_t len, const bufferlist& data); virtual void _do_set_attrs(coll_t coll, hobject_t &obj, const map &attrs); virtual void _do_clone(coll_t coll, hobject_t& orig_obj, hobject_t& new_obj); virtual void _do_clone_range(coll_t coll, hobject_t& orig_obj, hobject_t& new_obj, uint64_t srcoff, uint64_t srclen, uint64_t dstoff); virtual void _do_write_and_clone_range(coll_t coll, hobject_t& orig_obj, hobject_t& new_obj, uint64_t srcoff, uint64_t srclen, uint64_t dstoff, bufferlist& bl); virtual void _do_coll_add(coll_t orig_coll, coll_t new_coll, hobject_t& obj); virtual void _do_coll_rename(coll_t orig_coll, coll_t new_coll); int _gen_coll_id(rngen_t& gen); int _gen_obj_id(rngen_t& gen); void _print_status(int seq, int op); private: bool _prepare_clone(rngen_t& gen, coll_t& coll_ret, hobject_t& orig_obj_ret, hobject_t& new_obj_ret); bool _prepare_colls(rngen_t& gen, coll_entry_t* &orig_coll, coll_entry_t* &new_coll); }; #endif /* FILESTORE_DTRMNSTC_SEQ_OPS_H_ */ ceph-0.80.11/src/test/objectstore/TestObjectStoreState.cc0000664000175100017510000001741412623076744025370 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include "os/ObjectStore.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/debug.h" #include #include #include "TestObjectStoreState.h" #include "include/assert.h" #define dout_subsys ceph_subsys_filestore #undef dout_prefix #define dout_prefix *_dout << "ceph_test_objectstore_state " const coll_t TestObjectStoreState::META_COLL("meta"); const coll_t TestObjectStoreState::TEMP_COLL("temp"); void TestObjectStoreState::init(int colls, int objs) { dout(5) << "init " << colls << " colls " << objs << " objs" << dendl; ObjectStore::Transaction *t; t = new ObjectStore::Transaction; t->create_collection(META_COLL); t->create_collection(TEMP_COLL); m_store->apply_transaction(*t); wait_for_ready(); int baseid = 0; for (int i = 0; i < colls; i++) { int coll_id = i; coll_entry_t *entry = coll_create(coll_id); dout(5) << "init create collection " << entry->m_coll.to_str() << " meta " << entry->m_meta_obj.oid.name << dendl; t = new ObjectStore::Transaction; t->create_collection(entry->m_coll); t->touch(META_COLL, entry->m_meta_obj); for (int i = 0; i < objs; i++) { hobject_t *obj = entry->touch_obj(i + baseid); t->touch(entry->m_coll, *obj); ceph_assert(i + baseid == m_num_objects); m_num_objects++; } baseid += objs; m_store->queue_transaction(&(entry->m_osr), t, new C_OnFinished(this, t)); inc_in_flight(); m_collections.insert(make_pair(coll_id, entry)); m_collections_ids.push_back(coll_id); m_next_coll_nr++; } dout(5) << "init has " << m_in_flight.read() << "in-flight transactions" << dendl; wait_for_done(); dout(5) << "init finished" << dendl; } TestObjectStoreState::coll_entry_t *TestObjectStoreState::coll_create(int id) { char buf[100]; char meta_buf[100]; memset(buf, 0, 100); memset(meta_buf, 0, 100); snprintf(buf, 100, "0.%d_head", id); snprintf(meta_buf, 100, "pglog_0.%d_head", id); return (new coll_entry_t(id, buf, meta_buf)); } TestObjectStoreState::coll_entry_t* TestObjectStoreState::get_coll(int key, bool erase) { dout(5) << "get_coll id " << key << dendl; coll_entry_t *entry = NULL; map::iterator it = m_collections.find(key); if (it != m_collections.end()) { entry = it->second; if (erase) { m_collections.erase(it); vector::iterator cid_it = m_collections_ids.begin()+(entry->m_id); dout(20) << __func__ << " removing key " << key << " coll_id " << entry->m_id << " iterator's entry id " << (*cid_it) << dendl; m_collections_ids.erase(cid_it); } } dout(5) << "get_coll id " << key; if (!entry) *_dout << " non-existent"; else *_dout << " name " << entry->m_coll.to_str(); *_dout << dendl; return entry; } TestObjectStoreState::coll_entry_t* TestObjectStoreState::get_coll_at(int pos, bool erase) { dout(5) << "get_coll_at pos " << pos << dendl; if (m_collections.empty()) return NULL; assert((size_t) pos < m_collections_ids.size()); int coll_id = m_collections_ids[pos]; coll_entry_t *entry = m_collections[coll_id]; if (entry == NULL) { dout(5) << "get_coll_at pos " << pos << " non-existent" << dendl; return NULL; } if (erase) { m_collections.erase(coll_id); vector::iterator it = m_collections_ids.begin()+(pos); dout(20) << __func__ << " removing pos " << pos << " coll_id " << coll_id << " iterator's entry id " << (*it) << dendl; m_collections_ids.erase(it); } dout(5) << "get_coll_at pos " << pos << ": " << entry->m_coll << "(removed: " << erase << ")" << dendl; return entry; } TestObjectStoreState::coll_entry_t::~coll_entry_t() { if (m_objects.size() > 0) { map::iterator it = m_objects.begin(); for (; it != m_objects.end(); ++it) { hobject_t *obj = it->second; if (obj) { delete obj; } } m_objects.clear(); } } bool TestObjectStoreState::coll_entry_t::check_for_obj(int id) { if (m_objects.count(id)) return true; return false; } hobject_t *TestObjectStoreState::coll_entry_t::touch_obj(int id) { map::iterator it = m_objects.find(id); if (it != m_objects.end()) { dout(5) << "touch_obj coll id " << m_id << " name " << it->second->oid.name << dendl; return it->second; } char buf[100]; memset(buf, 0, 100); snprintf(buf, 100, "obj%d", id); hobject_t *obj = new hobject_t(sobject_t(object_t(buf), CEPH_NOSNAP)); m_objects.insert(make_pair(id, obj)); dout(5) << "touch_obj coll id " << m_id << " name " << buf << dendl; return obj; } hobject_t *TestObjectStoreState::coll_entry_t::get_obj(int id) { return get_obj(id, false); } /** * remove_obj - Removes object without freeing it. * @param id Object's id in the map. * @return The object or NULL in case of error. */ hobject_t *TestObjectStoreState::coll_entry_t::remove_obj(int id) { return get_obj(id, true); } hobject_t *TestObjectStoreState::coll_entry_t::get_obj(int id, bool remove) { map::iterator it = m_objects.find(id); if (it == m_objects.end()) { dout(5) << "get_obj coll " << m_coll.to_str() << " obj #" << id << " non-existent" << dendl; return NULL; } hobject_t *obj = it->second; if (remove) m_objects.erase(it); dout(5) << "get_obj coll " << m_coll.to_str() << " id " << id << ": " << obj->oid.name << "(removed: " << remove << ")" << dendl; return obj; } hobject_t *TestObjectStoreState::coll_entry_t::get_obj_at(int pos, int *key) { return get_obj_at(pos, false, key); } /** * remove_obj_at - Removes object without freeing it. * @param pos The map's position in which the object lies. * @return The object or NULL in case of error. */ hobject_t *TestObjectStoreState::coll_entry_t::remove_obj_at(int pos, int *key) { return get_obj_at(pos, true, key); } hobject_t *TestObjectStoreState::coll_entry_t::get_obj_at(int pos, bool remove, int *key) { if (m_objects.empty()) { dout(5) << "get_obj_at coll " << m_coll.to_str() << " pos " << pos << " in an empty collection" << dendl; return NULL; } hobject_t *ret = NULL; map::iterator it = m_objects.begin(); for (int i = 0; it != m_objects.end(); ++it, i++) { if (i == pos) { ret = it->second; break; } } if (ret == NULL) { dout(5) << "get_obj_at coll " << m_coll.to_str() << " pos " << pos << " non-existent" << dendl; return NULL; } if (key != NULL) *key = it->first; if (remove) m_objects.erase(it); dout(5) << "get_obj_at coll id " << m_id << " pos " << pos << ": " << ret->oid.name << "(removed: " << remove << ")" << dendl; return ret; } hobject_t* TestObjectStoreState::coll_entry_t::replace_obj(int id, hobject_t *obj) { hobject_t *old_obj = remove_obj(id); m_objects.insert(make_pair(id, obj)); return old_obj; } int TestObjectStoreState::coll_entry_t::get_random_obj_id(rngen_t& gen) { ceph_assert(!m_objects.empty()); boost::uniform_int<> orig_obj_rng(0, m_objects.size()-1); int pos = orig_obj_rng(gen); map::iterator it = m_objects.begin(); for (int i = 0; it != m_objects.end(); ++it, i++) { if (i == pos) { return it->first; } } ceph_assert(0 == "INTERNAL ERROR"); } ceph-0.80.11/src/test/objectstore/FileStoreDiff.cc0000664000175100017510000002231712623076744023767 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include "common/debug.h" #include "os/FileStore.h" #include "common/config.h" #include "FileStoreDiff.h" #define dout_subsys ceph_subsys_filestore #undef dout_prefix #define dout_prefix *_dout << "filestore_diff " FileStoreDiff::FileStoreDiff(FileStore *a, FileStore *b) : a_store(a), b_store(b) { int err; err = a_store->mount(); ceph_assert(err == 0); err = b_store->mount(); ceph_assert(err == 0); } FileStoreDiff::~FileStoreDiff() { a_store->umount(); b_store->umount(); } bool FileStoreDiff::diff_attrs(std::map& b, std::map& a) { bool ret = false; std::map::iterator b_it = b.begin(); std::map::iterator a_it = a.begin(); for (; b_it != b.end(); ++b_it, ++a_it) { if (b_it->first != a_it->first) { dout(0) << "diff_attrs name mismatch (verify: " << b_it->first << ", store: " << a_it->first << ")" << dendl; ret = true; continue; } if (!b_it->second.cmp(a_it->second)) { dout(0) << "diff_attrs contents mismatch on attr " << b_it->first << dendl; ret = true; continue; } } return ret; } static bool diff_omap(std::map& b, std::map& a) { bool ret = false; std::map::iterator b_it = b.begin(); std::map::iterator a_it = a.begin(); for (; b_it != b.end(); ++b_it, ++a_it) { if (b_it->first != a_it->first) { dout(0) << "diff_attrs name mismatch (verify: " << b_it->first << ", store: " << a_it->first << ")" << dendl; ret = true; continue; } if (!(b_it->second == a_it->second)) { dout(0) << "diff_attrs contents mismatch on attr " << b_it->first << dendl; ret = true; continue; } } return ret; } bool FileStoreDiff::diff_objects_stat(struct stat& a, struct stat& b) { bool ret = false; if (a.st_uid != b.st_uid) { dout(0) << "diff_objects_stat uid mismatch (A: " << a.st_uid << " != B: " << b.st_uid << ")" << dendl; ret = true; } if (a.st_gid != b.st_gid) { dout(0) << "diff_objects_stat gid mismatch (A: " << a.st_gid << " != B: " << b.st_gid << ")" << dendl; ret = true; } if (a.st_mode != b.st_mode) { dout(0) << "diff_objects_stat mode mismatch (A: " << a.st_mode << " != B: " << b.st_mode << ")" << dendl; ret = true; } if (a.st_nlink != b.st_nlink) { dout(0) << "diff_objects_stat nlink mismatch (A: " << a.st_nlink << " != B: " << b.st_nlink << ")" << dendl; ret = true; } if (a.st_size != b.st_size) { dout(0) << "diff_objects_stat size mismatch (A: " << a.st_size << " != B: " << b.st_size << ")" << dendl; ret = true; } return ret; } bool FileStoreDiff::diff_objects(FileStore *a_store, FileStore *b_store, coll_t coll) { dout(2) << __func__ << " coll " << coll << dendl; bool ret = false; int err; std::vector b_objects, a_objects; err = b_store->collection_list(coll, b_objects); if (err < 0) { dout(0) << "diff_objects list on verify coll " << coll.to_str() << " returns " << err << dendl; return true; } err = a_store->collection_list(coll, a_objects); if (err < 0) { dout(0) << "diff_objects list on store coll " << coll.to_str() << " returns " << err << dendl; return true; } if (b_objects.size() != a_objects.size()) { dout(0) << "diff_objects num objs mismatch (A: " << a_objects.size() << ", B: " << b_objects.size() << ")" << dendl; ret = true; } std::vector::iterator b_it = b_objects.begin(); std::vector::iterator a_it = b_objects.begin(); for (; b_it != b_objects.end(); ++b_it, ++a_it) { ghobject_t b_obj = *b_it, a_obj = *a_it; if (b_obj.hobj.oid.name != a_obj.hobj.oid.name) { dout(0) << "diff_objects name mismatch on A object " << coll << "/" << a_obj << " and B object " << coll << "/" << b_obj << dendl; ret = true; continue; } struct stat b_stat, a_stat; err = b_store->stat(coll, b_obj, &b_stat); if (err < 0) { dout(0) << "diff_objects error stating B object " << coll.to_str() << "/" << b_obj.hobj.oid.name << dendl; ret = true; } err = a_store->stat(coll, a_obj, &a_stat); if (err < 0) { dout(0) << "diff_objects error stating A object " << coll << "/" << a_obj << dendl; ret = true; } if (diff_objects_stat(a_stat, b_stat)) { dout(0) << "diff_objects stat mismatch on " << coll << "/" << b_obj << dendl; ret = true; } bufferlist a_obj_bl, b_obj_bl; b_store->read(coll, b_obj, 0, b_stat.st_size, b_obj_bl); a_store->read(coll, a_obj, 0, a_stat.st_size, a_obj_bl); if (!a_obj_bl.contents_equal(b_obj_bl)) { dout(0) << "diff_objects content mismatch on " << coll << "/" << b_obj << dendl; ret = true; } std::map a_obj_attrs_map, b_obj_attrs_map; err = a_store->getattrs(coll, a_obj, a_obj_attrs_map); if (err < 0) { dout(0) << "diff_objects getattrs on A object " << coll << "/" << a_obj << " returns " << err << dendl; ret = true; } err = b_store->getattrs(coll, b_obj, b_obj_attrs_map); if (err < 0) { dout(0) << "diff_objects getattrs on B object " << coll << "/" << b_obj << "returns " << err << dendl; ret = true; } if (diff_attrs(b_obj_attrs_map, a_obj_attrs_map)) { dout(0) << "diff_objects attrs mismatch on A object " << coll << "/" << a_obj << " and B object " << coll << "/" << b_obj << dendl; ret = true; } std::map a_obj_omap, b_obj_omap; std::set a_omap_keys, b_omap_keys; err = a_store->omap_get_keys(coll, a_obj, &a_omap_keys); if (err < 0) { dout(0) << "diff_objects getomap on A object " << coll << "/" << a_obj << " returns " << err << dendl; ret = true; } err = a_store->omap_get_values(coll, a_obj, a_omap_keys, &a_obj_omap); if (err < 0) { dout(0) << "diff_objects getomap on A object " << coll << "/" << a_obj << " returns " << err << dendl; ret = true; } err = b_store->omap_get_keys(coll, b_obj, &b_omap_keys); if (err < 0) { dout(0) << "diff_objects getomap on A object " << coll << "/" << b_obj << " returns " << err << dendl; ret = true; } err = b_store->omap_get_values(coll, b_obj, b_omap_keys, &b_obj_omap); if (err < 0) { dout(0) << "diff_objects getomap on A object " << coll << "/" << b_obj << " returns " << err << dendl; ret = true; } if (diff_omap(a_obj_omap, b_obj_omap)) { dout(0) << "diff_objects omap mismatch on A object " << coll << "/" << a_obj << " and B object " << coll << "/" << b_obj << dendl; ret = true; } } return ret; } bool FileStoreDiff::diff_coll_attrs(FileStore *a_store, FileStore *b_store, coll_t coll) { bool ret = false; int err; std::map b_coll_attrs, a_coll_attrs; err = b_store->collection_getattrs(coll, b_coll_attrs); if (err < 0) { dout(0) << "diff_attrs getattrs on verify coll " << coll.to_str() << "returns " << err << dendl; ret = true; } err = a_store->collection_getattrs(coll, a_coll_attrs); if (err < 0) { dout(0) << "diff_attrs getattrs on A coll " << coll.to_str() << "returns " << err << dendl; ret = true; } if (b_coll_attrs.size() != a_coll_attrs.size()) { dout(0) << "diff_attrs size mismatch (A: " << a_coll_attrs.size() << ", B: " << a_coll_attrs.size() << ")" << dendl; ret = true; } return diff_attrs(b_coll_attrs, a_coll_attrs) || ret; } bool FileStoreDiff::diff() { bool ret = false; std::vector a_coll_list, b_coll_list; a_store->list_collections(a_coll_list); b_store->list_collections(b_coll_list); std::vector::iterator it = b_coll_list.begin(); for (; it != b_coll_list.end(); ++it) { coll_t b_coll = *it; if (!a_store->collection_exists(b_coll)) { dout(0) << "diff B coll " << b_coll.to_str() << " DNE on A" << dendl; ret = true; continue; } for (std::vector::iterator j = a_coll_list.begin(); j != a_coll_list.end(); ++j) { if (*j == *it) { a_coll_list.erase(j); break; } } if (diff_coll_attrs(a_store, b_store, b_coll)) ret = true; if (diff_objects(a_store, b_store, b_coll)) ret = true; } for (std::vector::iterator it = a_coll_list.begin(); it != a_coll_list.end(); ++it) { dout(0) << "diff A coll " << *it << " DNE on B" << dendl; ret = true; } return ret; } ceph-0.80.11/src/test/objectstore/FileStoreTracker.cc0000664000175100017510000003124312623076744024510 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "FileStoreTracker.h" #include #include #include #include "include/Context.h" #include "common/Mutex.h" class OnApplied : public Context { FileStoreTracker *tracker; list, uint64_t> > in_flight; ObjectStore::Transaction *t; public: OnApplied(FileStoreTracker *tracker, list, uint64_t> > in_flight, ObjectStore::Transaction *t) : tracker(tracker), in_flight(in_flight), t(t) {} void finish(int r) { for (list, uint64_t> >::iterator i = in_flight.begin(); i != in_flight.end(); ++i) { tracker->applied(i->first, i->second); } delete t; } }; class OnCommitted : public Context { FileStoreTracker *tracker; list, uint64_t> > in_flight; public: OnCommitted(FileStoreTracker *tracker, list, uint64_t> > in_flight) : tracker(tracker), in_flight(in_flight) {} void finish(int r) { for (list, uint64_t> >::iterator i = in_flight.begin(); i != in_flight.end(); ++i) { tracker->committed(i->first, i->second); } } }; int FileStoreTracker::init() { set to_get; to_get.insert("STATUS"); map got; db->get("STATUS", to_get, &got); restart_seq = 0; if (!got.empty()) { bufferlist::iterator bp = got.begin()->second.begin(); ::decode(restart_seq, bp); } ++restart_seq; KeyValueDB::Transaction t = db->get_transaction(); got.clear(); ::encode(restart_seq, got["STATUS"]); t->set("STATUS", got); db->submit_transaction(t); return 0; } void FileStoreTracker::submit_transaction(Transaction &t) { list, uint64_t> > in_flight; OutTransaction out; out.t = new ObjectStore::Transaction; out.in_flight = &in_flight; for (list::iterator i = t.ops.begin(); i != t.ops.end(); ++i) { (**i)(this, &out); } store->queue_transaction( 0, out.t, new OnApplied(this, in_flight, out.t), new OnCommitted(this, in_flight)); } void FileStoreTracker::write(const pair &obj, OutTransaction *out) { Mutex::Locker l(lock); std::cerr << "Writing " << obj << std::endl; ObjectContents contents = get_current_content(obj); uint64_t offset = rand() % (SIZE/2); uint64_t len = rand() % (SIZE/2); if (!len) len = 10; contents.write(rand(), offset, len); bufferlist to_write; ObjectContents::Iterator iter = contents.get_iterator(); iter.seek_to(offset); for (uint64_t i = offset; i < offset + len; ++i, ++iter) { assert(iter.valid()); to_write.append(*iter); } out->t->write(coll_t(obj.first), hobject_t(sobject_t(obj.second, CEPH_NOSNAP)), offset, len, to_write); out->in_flight->push_back(make_pair(obj, set_content(obj, contents))); } void FileStoreTracker::remove(const pair &obj, OutTransaction *out) { std::cerr << "Deleting " << obj << std::endl; Mutex::Locker l(lock); ObjectContents old_contents = get_current_content(obj); if (!old_contents.exists()) return; out->t->remove(coll_t(obj.first), hobject_t(sobject_t(obj.second, CEPH_NOSNAP))); ObjectContents contents; out->in_flight->push_back(make_pair(obj, set_content(obj, contents))); } void FileStoreTracker::clone_range(const pair &from, const pair &to, OutTransaction *out) { Mutex::Locker l(lock); std::cerr << "CloningRange " << from << " to " << to << std::endl; assert(from.first == to.first); ObjectContents from_contents = get_current_content(from); ObjectContents to_contents = get_current_content(to); if (!from_contents.exists()) { return; } if (from.second == to.second) { return; } uint64_t new_size = from_contents.size(); interval_set interval_to_clone; uint64_t offset = rand() % (new_size/2); uint64_t len = rand() % (new_size/2); if (!len) len = 10; interval_to_clone.insert(offset, len); to_contents.clone_range(from_contents, interval_to_clone); out->t->clone_range(coll_t(from.first), hobject_t(sobject_t(from.second, CEPH_NOSNAP)), hobject_t(sobject_t(to.second, CEPH_NOSNAP)), offset, len, offset); out->in_flight->push_back(make_pair(to, set_content(to, to_contents))); } void FileStoreTracker::clone(const pair &from, const pair &to, OutTransaction *out) { Mutex::Locker l(lock); std::cerr << "Cloning " << from << " to " << to << std::endl; assert(from.first == to.first); if (from.second == to.second) { return; } ObjectContents from_contents = get_current_content(from); ObjectContents to_contents = get_current_content(to); if (!from_contents.exists()) { return; } if (to_contents.exists()) out->t->remove(coll_t(to.first), hobject_t(sobject_t(to.second, CEPH_NOSNAP))); out->t->clone(coll_t(from.first), hobject_t(sobject_t(from.second, CEPH_NOSNAP)), hobject_t(sobject_t(to.second, CEPH_NOSNAP))); out->in_flight->push_back(make_pair(to, set_content(to, from_contents))); } string obj_to_prefix(const pair &obj) { string sep; sep.push_back('^'); return obj.first + sep + obj.second + "_CONTENTS_"; } string obj_to_meta_prefix(const pair &obj) { string sep; sep.push_back('^'); return obj.first + sep + obj.second; } string seq_to_key(uint64_t seq) { char buf[50]; snprintf(buf, sizeof(buf), "%*llu", 20, (unsigned long long int)seq); return string(buf); } struct ObjStatus { uint64_t last_applied; uint64_t last_committed; uint64_t restart_seq; ObjStatus() : last_applied(0), last_committed(0), restart_seq(0) {} uint64_t get_last_applied(uint64_t seq) const { if (seq > restart_seq) return last_committed; else return last_applied; } void set_last_applied(uint64_t _last_applied, uint64_t seq) { last_applied = _last_applied; restart_seq = seq; } uint64_t trim_to() const { return last_applied < last_committed ? last_applied : last_committed; } }; void encode(const ObjStatus &obj, bufferlist &bl) { ::encode(obj.last_applied, bl); ::encode(obj.last_committed, bl); ::encode(obj.restart_seq, bl); } void decode(ObjStatus &obj, bufferlist::iterator &bl) { ::decode(obj.last_applied, bl); ::decode(obj.last_committed, bl); ::decode(obj.restart_seq, bl); } ObjStatus get_obj_status(const pair &obj, KeyValueDB *db) { set to_get; to_get.insert("META"); map got; db->get(obj_to_meta_prefix(obj), to_get, &got); ObjStatus retval; if (!got.empty()) { bufferlist::iterator bp = got.begin()->second.begin(); ::decode(retval, bp); } return retval; } void set_obj_status(const pair &obj, const ObjStatus &status, KeyValueDB::Transaction t) { map to_set; ::encode(status, to_set["META"]); t->set(obj_to_meta_prefix(obj), to_set); } void _clean_forward(const pair &obj, uint64_t last_valid, KeyValueDB *db) { KeyValueDB::Transaction t = db->get_transaction(); KeyValueDB::Iterator i = db->get_iterator(obj_to_prefix(obj)); set to_remove; i->upper_bound(seq_to_key(last_valid)); for (; i->valid(); i->next()) { to_remove.insert(i->key()); } t->rmkeys(obj_to_prefix(obj), to_remove); db->submit_transaction(t); } void FileStoreTracker::verify(const string &coll, const string &obj, bool on_start) { Mutex::Locker l(lock); std::cerr << "Verifying " << make_pair(coll, obj) << std::endl; pair valid_reads = get_valid_reads(make_pair(coll, obj)); std::cerr << "valid_reads is " << valid_reads << std::endl; bufferlist contents; int r = store->read(coll_t(coll), hobject_t(sobject_t(obj, CEPH_NOSNAP)), 0, 2*SIZE, contents); std::cerr << "exists: " << r << std::endl; for (uint64_t i = valid_reads.first; i < valid_reads.second; ++i) { ObjectContents old_contents = get_content(make_pair(coll, obj), i); std::cerr << "old_contents exists " << old_contents.exists() << std::endl; if (!old_contents.exists() && (r == -ENOENT)) return; if (old_contents.exists() && (r == -ENOENT)) continue; if (!old_contents.exists() && (r != -ENOENT)) continue; if (contents.length() != old_contents.size()) { std::cerr << "old_contents.size() is " << old_contents.size() << std::endl; continue; } bufferlist::iterator bp = contents.begin(); ObjectContents::Iterator iter = old_contents.get_iterator(); iter.seek_to_first(); bool matches = true; uint64_t pos = 0; for (; !bp.end() && iter.valid(); ++iter, ++bp, ++pos) { if (*iter != *bp) { std::cerr << "does not match at pos " << pos << std::endl; matches = false; break; } } if (matches) { if (on_start) _clean_forward(make_pair(coll, obj), i, db); return; } } std::cerr << "Verifying " << make_pair(coll, obj) << " failed " << std::endl; assert(0); } ObjectContents FileStoreTracker::get_current_content( const pair &obj) { KeyValueDB::Iterator iter = db->get_iterator( obj_to_prefix(obj)); iter->seek_to_last(); if (iter->valid()) { bufferlist bl = iter->value(); bufferlist::iterator bp = bl.begin(); pair val; ::decode(val, bp); assert(seq_to_key(val.first) == iter->key()); bp = val.second.begin(); return ObjectContents(bp); } return ObjectContents(); } ObjectContents FileStoreTracker::get_content( const pair &obj, uint64_t version) { set to_get; map got; to_get.insert(seq_to_key(version)); db->get(obj_to_prefix(obj), to_get, &got); if (got.empty()) return ObjectContents(); pair val; bufferlist::iterator bp = got.begin()->second.begin(); ::decode(val, bp); bp = val.second.begin(); assert(val.first == version); return ObjectContents(bp); } pair FileStoreTracker::get_valid_reads( const pair &obj) { pair bounds = make_pair(0,1); KeyValueDB::Iterator iter = db->get_iterator( obj_to_prefix(obj)); iter->seek_to_last(); if (iter->valid()) { pair val; bufferlist bl = iter->value(); bufferlist::iterator bp = bl.begin(); ::decode(val, bp); bounds.second = val.first + 1; } ObjStatus obj_status = get_obj_status(obj, db); bounds.first = obj_status.get_last_applied(restart_seq); return bounds; } void clear_obsolete(const pair &obj, const ObjStatus &status, KeyValueDB *db, KeyValueDB::Transaction t) { KeyValueDB::Iterator iter = db->get_iterator(obj_to_prefix(obj)); set to_remove; iter->seek_to_first(); for (; iter->valid() && iter->key() < seq_to_key(status.trim_to()); iter->next()) to_remove.insert(iter->key()); t->rmkeys(obj_to_prefix(obj), to_remove); } void FileStoreTracker::committed(const pair &obj, uint64_t seq) { Mutex::Locker l(lock); ObjStatus status = get_obj_status(obj, db); assert(status.last_committed < seq); status.last_committed = seq; KeyValueDB::Transaction t = db->get_transaction(); clear_obsolete(obj, status, db, t); set_obj_status(obj, status, t); db->submit_transaction(t); } void FileStoreTracker::applied(const pair &obj, uint64_t seq) { Mutex::Locker l(lock); std::cerr << "Applied " << obj << " version " << seq << std::endl; ObjStatus status = get_obj_status(obj, db); assert(status.last_applied < seq); status.set_last_applied(seq, restart_seq); KeyValueDB::Transaction t = db->get_transaction(); clear_obsolete(obj, status, db, t); set_obj_status(obj, status, t); db->submit_transaction(t); } uint64_t FileStoreTracker::set_content(const pair &obj, ObjectContents &content) { KeyValueDB::Transaction t = db->get_transaction(); KeyValueDB::Iterator iter = db->get_iterator( obj_to_prefix(obj)); iter->seek_to_last(); uint64_t most_recent = 0; if (iter->valid()) { pair val; bufferlist bl = iter->value(); bufferlist::iterator bp = bl.begin(); ::decode(val, bp); most_recent = val.first; } bufferlist buf_content; content.encode(buf_content); map to_set; ::encode(make_pair(most_recent + 1, buf_content), to_set[seq_to_key(most_recent + 1)]); t->set(obj_to_prefix(obj), to_set); db->submit_transaction(t); return most_recent + 1; } ceph-0.80.11/src/test/objectstore/TestObjectStoreState.h0000664000175100017510000000743112623076744025230 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef TEST_OBJECTSTORE_STATE_H_ #define TEST_OBJECTSTORE_STATE_H_ #include "os/ObjectStore.h" #include #include #include #include #include typedef boost::mt11213b rngen_t; class TestObjectStoreState { public: struct coll_entry_t { int m_id; coll_t m_coll; hobject_t m_meta_obj; ObjectStore::Sequencer m_osr; map m_objects; int m_next_object_id; coll_entry_t(int i, char *coll_buf, char *meta_obj_buf) : m_id(i), m_coll(coll_buf), m_meta_obj(sobject_t(object_t(meta_obj_buf), CEPH_NOSNAP)), m_osr(coll_buf), m_next_object_id(0) { } ~coll_entry_t(); hobject_t *touch_obj(int id); bool check_for_obj(int id); hobject_t *get_obj(int id); hobject_t *remove_obj(int id); hobject_t *get_obj_at(int pos, int *key = NULL); hobject_t *remove_obj_at(int pos, int *key = NULL); hobject_t *replace_obj(int id, hobject_t *obj); int get_random_obj_id(rngen_t& gen); private: hobject_t *get_obj(int id, bool remove); hobject_t *get_obj_at(int pos, bool remove, int *key = NULL); }; /* kept in upper case for consistency with coll_t's */ static const coll_t META_COLL; static const coll_t TEMP_COLL; protected: boost::shared_ptr m_store; map m_collections; vector m_collections_ids; int m_next_coll_nr; int m_num_objs_per_coll; int m_num_objects; int m_max_in_flight; atomic_t m_in_flight; Mutex m_finished_lock; Cond m_finished_cond; void wait_for_ready() { Mutex::Locker locker(m_finished_lock); while ((m_max_in_flight > 0) && ((int)m_in_flight.read() >= m_max_in_flight)) m_finished_cond.Wait(m_finished_lock); } void wait_for_done() { Mutex::Locker locker(m_finished_lock); while (m_in_flight.read()) m_finished_cond.Wait(m_finished_lock); } void set_max_in_flight(int max) { m_max_in_flight = max; } void set_num_objs_per_coll(int val) { m_num_objs_per_coll = val; } coll_entry_t *get_coll(int key, bool erase = false); coll_entry_t *get_coll_at(int pos, bool erase = false); private: static const int m_default_num_colls = 30; public: TestObjectStoreState(ObjectStore *store) : m_next_coll_nr(0), m_num_objs_per_coll(10), m_num_objects(0), m_max_in_flight(0), m_finished_lock("Finished Lock") { m_in_flight.set(0); m_store.reset(store); } ~TestObjectStoreState() { map::iterator it = m_collections.begin(); while (it != m_collections.end()) { if (it->second) delete it->second; m_collections.erase(it++); } } void init(int colls, int objs); void init() { init(m_default_num_colls, 0); } int inc_in_flight() { return ((int) m_in_flight.inc()); } int dec_in_flight() { return ((int) m_in_flight.dec()); } coll_entry_t *coll_create(int id); class C_OnFinished: public Context { protected: TestObjectStoreState *m_state; ObjectStore::Transaction *m_tx; public: C_OnFinished(TestObjectStoreState *state, ObjectStore::Transaction *t) : m_state(state), m_tx(t) { } void finish(int r) { Mutex::Locker locker(m_state->m_finished_lock); m_state->dec_in_flight(); m_state->m_finished_cond.Signal(); delete m_tx; } }; }; #endif /* TEST_OBJECTSTORE_STATE_H_ */ ceph-0.80.11/src/test/objectstore/store_test.cc0000664000175100017510000011036712623076744023500 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "os/ObjectStore.h" #include "os/FileStore.h" #include "os/KeyValueStore.h" #include "include/Context.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/Mutex.h" #include "common/Cond.h" #include "common/errno.h" #include #include #include #include #include #include "include/unordered_map.h" typedef boost::mt11213b gen_type; #if GTEST_HAS_PARAM_TEST class StoreTest : public ::testing::TestWithParam { public: boost::scoped_ptr store; StoreTest() : store(0) {} virtual void SetUp() { int r = ::mkdir("store_test_temp_dir", 0777); if (r < 0 && errno != EEXIST) { r = -errno; cerr << __func__ << ": unable to create store_test_temp_dir" << ": " << cpp_strerror(r) << std::endl; return; } ObjectStore *store_ = ObjectStore::create(g_ceph_context, string(GetParam()), string("store_test_temp_dir"), string("store_test_temp_journal")); store.reset(store_); EXPECT_EQ(store->mkfs(), 0); EXPECT_EQ(store->mount(), 0); } virtual void TearDown() { store->umount(); } }; bool sorted(const vector &in) { ghobject_t start; for (vector::const_iterator i = in.begin(); i != in.end(); ++i) { if (start > *i) return false; start = *i; } return true; } TEST_P(StoreTest, SimpleColTest) { coll_t cid = coll_t("initial"); int r = 0; { ObjectStore::Transaction t; t.create_collection(cid); cerr << "create collection" << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove_collection(cid); cerr << "remove collection" << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.create_collection(cid); cerr << "add collection" << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove_collection(cid); cerr << "remove collection" << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } TEST_P(StoreTest, SimpleObjectTest) { int r; coll_t cid = coll_t("coll"); { ObjectStore::Transaction t; t.create_collection(cid); cerr << "Creating collection " << cid << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP))); { ObjectStore::Transaction t; t.touch(cid, hoid); cerr << "Creating object " << hoid << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove(cid, hoid); t.remove_collection(cid); cerr << "Cleaning" << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } TEST_P(StoreTest, SimpleObjectLongnameTest) { int r; coll_t cid = coll_t("coll"); { ObjectStore::Transaction t; t.create_collection(cid); cerr << "Creating collection " << cid << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ghobject_t hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP))); { ObjectStore::Transaction t; t.touch(cid, hoid); cerr << "Creating object " << hoid << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove(cid, hoid); t.remove_collection(cid); cerr << "Cleaning" << std::endl; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } TEST_P(StoreTest, ManyObjectTest) { int NUM_OBJS = 2000; int r = 0; coll_t cid("blah"); string base = ""; for (int i = 0; i < 100; ++i) base.append("aaaaa"); set created; { ObjectStore::Transaction t; t.create_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } for (int i = 0; i < NUM_OBJS; ++i) { if (!(i % 5)) { cerr << "Object " << i << std::endl; } ObjectStore::Transaction t; char buf[100]; snprintf(buf, sizeof(buf), "%d", i); ghobject_t hoid(hobject_t(sobject_t(string(buf) + base, CEPH_NOSNAP))); t.touch(cid, hoid); created.insert(hoid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } for (set::iterator i = created.begin(); i != created.end(); ++i) { struct stat buf; ASSERT_TRUE(!store->stat(cid, *i, &buf)); } set listed; vector objects; r = store->collection_list(cid, objects); ASSERT_EQ(r, 0); cerr << "objects.size() is " << objects.size() << std::endl; for (vector ::iterator i = objects.begin(); i != objects.end(); ++i) { listed.insert(*i); ASSERT_TRUE(created.count(*i)); } ASSERT_TRUE(listed.size() == created.size()); ghobject_t start, next; objects.clear(); r = store->collection_list_partial( cid, ghobject_t::get_max(), 50, 60, 0, &objects, &next ); ASSERT_EQ(r, 0); ASSERT_TRUE(objects.empty()); objects.clear(); listed.clear(); while (1) { r = store->collection_list_partial(cid, start, 50, 60, 0, &objects, &next); ASSERT_TRUE(sorted(objects)); ASSERT_EQ(r, 0); listed.insert(objects.begin(), objects.end()); if (objects.size() < 50) { ASSERT_TRUE(next.is_max()); break; } objects.clear(); start = next; } cerr << "listed.size() is " << listed.size() << std::endl; ASSERT_TRUE(listed.size() == created.size()); for (set::iterator i = listed.begin(); i != listed.end(); ++i) { ASSERT_TRUE(created.count(*i)); } for (set::iterator i = created.begin(); i != created.end(); ++i) { ObjectStore::Transaction t; t.remove(cid, *i); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } cerr << "cleaning up" << std::endl; { ObjectStore::Transaction t; t.remove_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } class ObjectGenerator { public: virtual ghobject_t create_object(gen_type *gen) = 0; virtual ~ObjectGenerator() {} }; class MixedGenerator : public ObjectGenerator { public: unsigned seq; MixedGenerator() : seq(0) {} ghobject_t create_object(gen_type *gen) { char buf[100]; snprintf(buf, sizeof(buf), "%u", seq); boost::uniform_int<> true_false(0, 1); string name(buf); if (true_false(*gen)) { // long for (int i = 0; i < 100; ++i) name.append("aaaaa"); } else if (true_false(*gen)) { name = "DIR_" + name; } // hash //boost::binomial_distribution bin(0xFFFFFF, 0.5); ++seq; return ghobject_t(hobject_t(name, string(), rand() & 2 ? CEPH_NOSNAP : rand(), rand() & 0xFF, 0, "")); } }; class SyntheticWorkloadState { public: static const unsigned max_in_flight = 16; static const unsigned max_objects = 3000; static const unsigned max_object_len = 1024 * 20; coll_t cid; unsigned in_flight; map contents; set available_objects; set in_flight_objects; ObjectGenerator *object_gen; gen_type *rng; ObjectStore *store; ObjectStore::Sequencer *osr; Mutex lock; Cond cond; class C_SyntheticOnReadable : public Context { public: SyntheticWorkloadState *state; ObjectStore::Transaction *t; ghobject_t hoid; C_SyntheticOnReadable(SyntheticWorkloadState *state, ObjectStore::Transaction *t, ghobject_t hoid) : state(state), t(t), hoid(hoid) {} void finish(int r) { Mutex::Locker locker(state->lock); ASSERT_TRUE(state->in_flight_objects.count(hoid)); ASSERT_EQ(r, 0); state->in_flight_objects.erase(hoid); if (state->contents.count(hoid)) state->available_objects.insert(hoid); --(state->in_flight); state->cond.Signal(); } }; static void filled_byte_array(bufferlist& bl, size_t size) { static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; bufferptr bp(size); for (unsigned int i = 0; i < size - 1; i++) { bp[i] = alphanum[rand() % sizeof(alphanum)]; } bp[size - 1] = '\0'; bl.append(bp); } SyntheticWorkloadState(ObjectStore *store, ObjectGenerator *gen, gen_type *rng, ObjectStore::Sequencer *osr, coll_t cid) : cid(cid), in_flight(0), object_gen(gen), rng(rng), store(store), osr(osr), lock("State lock") {} int init() { ObjectStore::Transaction t; t.create_collection(cid); return store->apply_transaction(t); } ghobject_t get_uniform_random_object() { while (in_flight >= max_in_flight || available_objects.empty()) cond.Wait(lock); boost::uniform_int<> choose(0, available_objects.size() - 1); int index = choose(*rng); set::iterator i = available_objects.begin(); for ( ; index > 0; --index, ++i) ; ghobject_t ret = *i; return ret; } void wait_for_ready() { while (in_flight >= max_in_flight) cond.Wait(lock); } void wait_for_done() { Mutex::Locker locker(lock); while (in_flight) cond.Wait(lock); } bool can_create() { return (available_objects.size() + in_flight_objects.size()) < max_objects; } bool can_unlink() { return (available_objects.size() + in_flight_objects.size()) > 0; } int touch() { Mutex::Locker locker(lock); if (!can_create()) return -ENOSPC; wait_for_ready(); ghobject_t new_obj = object_gen->create_object(rng); available_objects.erase(new_obj); ObjectStore::Transaction *t = new ObjectStore::Transaction; t->touch(cid, new_obj); ++in_flight; in_flight_objects.insert(new_obj); if (!contents.count(new_obj)) contents[new_obj] = bufferlist(); return store->queue_transaction(osr, t, new C_SyntheticOnReadable(this, t, new_obj)); } int write() { Mutex::Locker locker(lock); if (!can_unlink()) return -ENOENT; wait_for_ready(); ghobject_t new_obj = get_uniform_random_object(); available_objects.erase(new_obj); ObjectStore::Transaction *t = new ObjectStore::Transaction; boost::uniform_int<> u1(0, max_object_len/2); boost::uniform_int<> u2(0, max_object_len); uint64_t offset = u1(*rng); uint64_t len = u2(*rng); bufferlist bl; if (offset > len) swap(offset, len); filled_byte_array(bl, len); if (contents[new_obj].length() <= offset) { contents[new_obj].append_zero(offset-contents[new_obj].length()); contents[new_obj].append(bl); } else { bufferlist value; contents[new_obj].copy(0, offset, value); value.append(bl); if (value.length() < contents[new_obj].length()) contents[new_obj].copy(value.length(), contents[new_obj].length()-value.length(), value); value.swap(contents[new_obj]); } t->write(cid, new_obj, offset, len, bl); ++in_flight; in_flight_objects.insert(new_obj); return store->queue_transaction(osr, t, new C_SyntheticOnReadable(this, t, new_obj)); } void read() { boost::uniform_int<> u1(0, max_object_len/2); boost::uniform_int<> u2(0, max_object_len); uint64_t offset = u1(*rng); uint64_t len = u2(*rng); if (offset > len) swap(offset, len); ghobject_t obj; int r; { Mutex::Locker locker(lock); if (!can_unlink()) return ; wait_for_ready(); obj = get_uniform_random_object(); } bufferlist bl, result; r = store->read(cid, obj, offset, len, result); if (offset >= contents[obj].length()) { ASSERT_EQ(r, 0); } else { size_t max_len = contents[obj].length() - offset; if (len > max_len) len = max_len; ASSERT_EQ(len, result.length()); contents[obj].copy(offset, len, bl); ASSERT_EQ(r, (int)len); ASSERT_TRUE(result.contents_equal(bl)); } } int truncate() { Mutex::Locker locker(lock); if (!can_unlink()) return -ENOENT; wait_for_ready(); ghobject_t obj = get_uniform_random_object(); available_objects.erase(obj); ObjectStore::Transaction *t = new ObjectStore::Transaction; boost::uniform_int<> choose(0, max_object_len); size_t len = choose(*rng); bufferlist bl; t->truncate(cid, obj, len); ++in_flight; in_flight_objects.insert(obj); if (contents[obj].length() <= len) contents[obj].append_zero(len - contents[obj].length()); else { contents[obj].copy(0, len, bl); bl.swap(contents[obj]); } return store->queue_transaction(osr, t, new C_SyntheticOnReadable(this, t, obj)); } void scan() { Mutex::Locker locker(lock); while (in_flight) cond.Wait(lock); vector objects; set objects_set, objects_set2; ghobject_t next, current; while (1) { cerr << "scanning..." << std::endl; int r = store->collection_list_partial(cid, current, 50, 100, 0, &objects, &next); ASSERT_EQ(r, 0); ASSERT_TRUE(sorted(objects)); objects_set.insert(objects.begin(), objects.end()); objects.clear(); if (next.is_max()) break; current = next; } ASSERT_EQ(objects_set.size(), available_objects.size()); for (set::iterator i = objects_set.begin(); i != objects_set.end(); ++i) { ASSERT_GT(available_objects.count(*i), (unsigned)0); } int r = store->collection_list(cid, objects); ASSERT_EQ(r, 0); objects_set2.insert(objects.begin(), objects.end()); ASSERT_EQ(objects_set2.size(), available_objects.size()); for (set::iterator i = objects_set2.begin(); i != objects_set2.end(); ++i) { ASSERT_GT(available_objects.count(*i), (unsigned)0); } } void stat() { ghobject_t hoid; { Mutex::Locker locker(lock); if (!can_unlink()) return ; hoid = get_uniform_random_object(); in_flight_objects.insert(hoid); available_objects.erase(hoid); ++in_flight; } struct stat buf; int r = store->stat(cid, hoid, &buf); ASSERT_EQ(0, r); ASSERT_TRUE(buf.st_size == contents[hoid].length()); { Mutex::Locker locker(lock); --in_flight; cond.Signal(); in_flight_objects.erase(hoid); available_objects.insert(hoid); } } int unlink() { Mutex::Locker locker(lock); if (!can_unlink()) return -ENOENT; ghobject_t to_remove = get_uniform_random_object(); ObjectStore::Transaction *t = new ObjectStore::Transaction; t->remove(cid, to_remove); ++in_flight; available_objects.erase(to_remove); in_flight_objects.insert(to_remove); contents.erase(to_remove); return store->queue_transaction(osr, t, new C_SyntheticOnReadable(this, t, to_remove)); } void print_internal_state() { Mutex::Locker locker(lock); cerr << "available_objects: " << available_objects.size() << " in_flight_objects: " << in_flight_objects.size() << " total objects: " << in_flight_objects.size() + available_objects.size() << " in_flight " << in_flight << std::endl; } }; TEST_P(StoreTest, Synthetic) { ObjectStore::Sequencer osr("test"); MixedGenerator gen; gen_type rng(time(NULL)); coll_t cid("synthetic_1"); SyntheticWorkloadState test_obj(store.get(), &gen, &rng, &osr, cid); test_obj.init(); for (int i = 0; i < 1000; ++i) { if (!(i % 10)) cerr << "seeding object " << i << std::endl; test_obj.touch(); } for (int i = 0; i < 10000; ++i) { if (!(i % 10)) { cerr << "Op " << i << std::endl; test_obj.print_internal_state(); } boost::uniform_int<> true_false(0, 99); int val = true_false(rng); if (val > 97) { test_obj.scan(); } else if (val > 90) { test_obj.stat(); } else if (val > 85) { test_obj.unlink(); } else if (val > 50) { test_obj.write(); } else if (val > 10) { test_obj.read(); } else { test_obj.truncate(); } } test_obj.wait_for_done(); } TEST_P(StoreTest, HashCollisionTest) { coll_t cid("blah"); int r; { ObjectStore::Transaction t; t.create_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } string base = ""; for (int i = 0; i < 100; ++i) base.append("aaaaa"); set created; for (int n = 0; n < 10; ++n) { char nbuf[100]; sprintf(nbuf, "n%d", n); for (int i = 0; i < 1000; ++i) { char buf[100]; sprintf(buf, "%d", i); if (!(i % 5)) { cerr << "Object n" << n << " "<< i << std::endl; } ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, 0, 0, string(nbuf))); { ObjectStore::Transaction t; t.touch(cid, hoid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } created.insert(hoid); } } vector objects; r = store->collection_list(cid, objects); ASSERT_EQ(r, 0); set listed(objects.begin(), objects.end()); cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl; ASSERT_TRUE(listed.size() == created.size()); objects.clear(); listed.clear(); ghobject_t current, next; while (1) { r = store->collection_list_partial(cid, current, 50, 60, 0, &objects, &next); ASSERT_EQ(r, 0); ASSERT_TRUE(sorted(objects)); for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { if (listed.count(*i)) cerr << *i << " repeated" << std::endl; listed.insert(*i); } if (objects.size() < 50) { ASSERT_TRUE(next.is_max()); break; } objects.clear(); current = next; } cerr << "listed.size() is " << listed.size() << std::endl; ASSERT_TRUE(listed.size() == created.size()); for (set::iterator i = listed.begin(); i != listed.end(); ++i) { ASSERT_TRUE(created.count(*i)); } for (set::iterator i = created.begin(); i != created.end(); ++i) { ObjectStore::Transaction t; t.collection_remove(cid, *i); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ObjectStore::Transaction t; t.remove_collection(cid); store->apply_transaction(t); } TEST_P(StoreTest, OMapTest) { coll_t cid("blah"); ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, "")); int r; { ObjectStore::Transaction t; t.create_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } map attrs; { ObjectStore::Transaction t; t.touch(cid, hoid); t.omap_clear(cid, hoid); map start_set; t.omap_setkeys(cid, hoid, start_set); store->apply_transaction(t); } for (int i = 0; i < 100; i++) { if (!(i%5)) { std::cout << "On iteration " << i << std::endl; } ObjectStore::Transaction t; bufferlist bl; map cur_attrs; r = store->omap_get(cid, hoid, &bl, &cur_attrs); ASSERT_EQ(r, 0); for (map::iterator j = attrs.begin(); j != attrs.end(); ++j) { bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str()); if (!correct) { std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl; if (cur_attrs.count(j->first) > 0) { std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl; } } ASSERT_EQ(correct, true); } ASSERT_EQ(attrs.size(), cur_attrs.size()); char buf[100]; snprintf(buf, sizeof(buf), "%d", i); bl.clear(); bufferptr bp(buf, strlen(buf) + 1); bl.append(bp); map to_add; to_add.insert(pair("key-" + string(buf), bl)); attrs.insert(pair("key-" + string(buf), bl)); t.omap_setkeys(cid, hoid, to_add); store->apply_transaction(t); } int i = 0; while (attrs.size()) { if (!(i%5)) { std::cout << "removal: On iteration " << i << std::endl; } ObjectStore::Transaction t; bufferlist bl; map cur_attrs; r = store->omap_get(cid, hoid, &bl, &cur_attrs); ASSERT_EQ(r, 0); for (map::iterator j = attrs.begin(); j != attrs.end(); ++j) { bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str()); if (!correct) { std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl; if (cur_attrs.count(j->first) > 0) { std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl; } } ASSERT_EQ(correct, true); } string to_remove = attrs.begin()->first; set keys_to_remove; keys_to_remove.insert(to_remove); t.omap_rmkeys(cid, hoid, keys_to_remove); store->apply_transaction(t); attrs.erase(to_remove); ++i; } { bufferlist bl1; bl1.append("omap_header"); ObjectStore::Transaction t; t.omap_setheader(cid, hoid, bl1); store->apply_transaction(t); bufferlist bl2; bl2.append("value"); map to_add; to_add.insert(pair("key", bl2)); t.omap_setkeys(cid, hoid, to_add); store->apply_transaction(t); bufferlist bl3; map cur_attrs; r = store->omap_get(cid, hoid, &bl3, &cur_attrs); ASSERT_EQ(r, 0); ASSERT_EQ(cur_attrs.size(), size_t(1)); ASSERT_TRUE(bl3.contents_equal(bl1)); } ObjectStore::Transaction t; t.remove(cid, hoid); t.remove_collection(cid); store->apply_transaction(t); } TEST_P(StoreTest, XattrTest) { coll_t cid("blah"); ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, "")); bufferlist big; for (unsigned i = 0; i < 10000; ++i) { big.append('\0'); } bufferlist small; for (unsigned i = 0; i < 10; ++i) { small.append('\0'); } int r; { ObjectStore::Transaction t; t.create_collection(cid); t.touch(cid, hoid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } map attrs; { ObjectStore::Transaction t; t.setattr(cid, hoid, "attr1", small); attrs["attr1"] = small; t.setattr(cid, hoid, "attr2", big); attrs["attr2"] = big; t.setattr(cid, hoid, "attr3", small); attrs["attr3"] = small; t.setattr(cid, hoid, "attr1", small); attrs["attr1"] = small; t.setattr(cid, hoid, "attr4", big); attrs["attr4"] = big; t.setattr(cid, hoid, "attr3", big); attrs["attr3"] = big; r = store->apply_transaction(t); ASSERT_EQ(r, 0); } map aset; store->getattrs(cid, hoid, aset); ASSERT_EQ(aset.size(), attrs.size()); for (map::iterator i = aset.begin(); i != aset.end(); ++i) { bufferlist bl; bl.push_back(i->second); ASSERT_TRUE(attrs[i->first] == bl); } { ObjectStore::Transaction t; t.rmattr(cid, hoid, "attr2"); attrs.erase("attr2"); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } aset.clear(); store->getattrs(cid, hoid, aset); ASSERT_EQ(aset.size(), attrs.size()); for (map::iterator i = aset.begin(); i != aset.end(); ++i) { bufferlist bl; bl.push_back(i->second); ASSERT_TRUE(attrs[i->first] == bl); } bufferptr bp; r = store->getattr(cid, hoid, "attr2", bp); ASSERT_EQ(r, -ENODATA); r = store->getattr(cid, hoid, "attr3", bp); ASSERT_GE(r, 0); bufferlist bl2; bl2.push_back(bp); ASSERT_TRUE(bl2 == attrs["attr3"]); } void colsplittest( ObjectStore *store, unsigned num_objects, unsigned common_suffix_size ) { coll_t cid("from"); coll_t tid("to"); int r = 0; { ObjectStore::Transaction t; t.create_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; for (uint32_t i = 0; i < 2*num_objects; ++i) { stringstream objname; objname << "obj" << i; t.touch(cid, ghobject_t(hobject_t( objname.str(), "", CEPH_NOSNAP, i<apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.create_collection(tid); t.split_collection(cid, common_suffix_size+1, 0, tid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ObjectStore::Transaction t; vector objects; r = store->collection_list(cid, objects); ASSERT_EQ(r, 0); ASSERT_EQ(objects.size(), num_objects); for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { ASSERT_EQ(!(i->hobj.hash & (1<collection_list(tid, objects); ASSERT_EQ(r, 0); ASSERT_EQ(objects.size(), num_objects); for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { ASSERT_EQ(i->hobj.hash & (1<apply_transaction(t); ASSERT_EQ(r, 0); } TEST_P(StoreTest, ColSplitTest1) { colsplittest(store.get(), 10000, 11); } TEST_P(StoreTest, ColSplitTest2) { colsplittest(store.get(), 100, 7); } #if 0 TEST_P(StoreTest, ColSplitTest3) { colsplittest(store.get(), 100000, 25); } #endif /** * This test tests adding two different groups * of objects, each with 1 common prefix and 1 * different prefix. We then remove half * in order to verify that the merging correctly * stops at the common prefix subdir. See bug * #5273 */ TEST_P(StoreTest, TwoHash) { coll_t cid("asdf"); int r; { ObjectStore::Transaction t; t.create_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } std::cout << "Making objects" << std::endl; for (int i = 0; i < 360; ++i) { ObjectStore::Transaction t; ghobject_t o; if (i < 8) { o.hobj.hash = (i << 16) | 0xA1; t.touch(cid, o); } o.hobj.hash = (i << 16) | 0xB1; t.touch(cid, o); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } std::cout << "Removing half" << std::endl; for (int i = 1; i < 8; ++i) { ObjectStore::Transaction t; ghobject_t o; o.hobj.hash = (i << 16) | 0xA1; t.remove(cid, o); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } std::cout << "Checking" << std::endl; for (int i = 1; i < 8; ++i) { ObjectStore::Transaction t; ghobject_t o; o.hobj.hash = (i << 16) | 0xA1; bool exists = store->exists(cid, o); ASSERT_EQ(exists, false); } { ghobject_t o; o.hobj.hash = 0xA1; bool exists = store->exists(cid, o); ASSERT_EQ(exists, true); } std::cout << "Cleanup" << std::endl; for (int i = 0; i < 360; ++i) { ObjectStore::Transaction t; ghobject_t o; o.hobj.hash = (i << 16) | 0xA1; t.remove(cid, o); o.hobj.hash = (i << 16) | 0xB1; t.remove(cid, o); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ObjectStore::Transaction t; t.remove_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } TEST_P(StoreTest, MoveRename) { coll_t temp_cid("mytemp"); hobject_t temp_oid("tmp_oid", "", CEPH_NOSNAP, 0, 0, ""); coll_t cid("dest"); hobject_t oid("dest_oid", "", CEPH_NOSNAP, 0, 0, ""); int r; { ObjectStore::Transaction t; t.create_collection(cid); t.touch(cid, oid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ASSERT_TRUE(store->exists(cid, oid)); bufferlist data, attr; map omap; data.append("data payload"); attr.append("attr value"); omap["omap_key"].append("omap value"); { ObjectStore::Transaction t; t.create_collection(temp_cid); t.touch(temp_cid, temp_oid); t.write(temp_cid, temp_oid, 0, data.length(), data); t.setattr(temp_cid, temp_oid, "attr", attr); t.omap_setkeys(temp_cid, temp_oid, omap); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ASSERT_TRUE(store->exists(temp_cid, temp_oid)); { ObjectStore::Transaction t; t.remove(cid, oid); t.collection_move_rename(temp_cid, temp_oid, cid, oid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } ASSERT_TRUE(store->exists(cid, oid)); ASSERT_FALSE(store->exists(temp_cid, temp_oid)); { bufferlist newdata; r = store->read(cid, oid, 0, 1000, newdata); ASSERT_GE(r, 0); ASSERT_TRUE(newdata.contents_equal(data)); bufferlist newattr; r = store->getattr(cid, oid, "attr", newattr); ASSERT_GE(r, 0); ASSERT_TRUE(newattr.contents_equal(attr)); set keys; keys.insert("omap_key"); map newomap; r = store->omap_get_values(cid, oid, keys, &newomap); ASSERT_GE(r, 0); ASSERT_EQ(1u, newomap.size()); ASSERT_TRUE(newomap.count("omap_key")); ASSERT_TRUE(newomap["omap_key"].contents_equal(omap["omap_key"])); } { ObjectStore::Transaction t; t.remove(cid, oid); t.remove_collection(cid); t.remove_collection(temp_cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } TEST_P(StoreTest, BigRGWObjectName) { store->set_allow_sharded_objects(); store->sync_and_flush(); coll_t temp_cid("mytemp"); hobject_t temp_oid("tmp_oid", "", CEPH_NOSNAP, 0, 0, ""); coll_t cid("dest"); ghobject_t oid( hobject_t( "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "", CEPH_NOSNAP, 0x81920472, 3, ""), 15, shard_id_t(1)); ghobject_t oid2(oid); oid2.generation = 17; ghobject_t oidhead(oid); oidhead.generation = ghobject_t::NO_GEN; int r; { ObjectStore::Transaction t; t.create_collection(cid); t.touch(cid, oidhead); t.collection_move_rename(cid, oidhead, cid, oid); t.touch(cid, oidhead); t.collection_move_rename(cid, oidhead, cid, oid2); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove(cid, oid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { vector objects; r = store->collection_list(cid, objects); ASSERT_EQ(r, 0); ASSERT_EQ(objects.size(), 1u); ASSERT_EQ(objects[0], oid2); } ASSERT_FALSE(store->exists(cid, oid)); { ObjectStore::Transaction t; t.remove(cid, oid2); t.remove_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } TEST_P(StoreTest, SetAllocHint) { coll_t cid("alloc_hint"); ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, 0, "")); int r; { ObjectStore::Transaction t; t.create_collection(cid); t.touch(cid, hoid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove(cid, hoid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } { ObjectStore::Transaction t; t.remove_collection(cid); r = store->apply_transaction(t); ASSERT_EQ(r, 0); } } INSTANTIATE_TEST_CASE_P( ObjectStore, StoreTest, ::testing::Values("filestore", "keyvaluestore-dev")); #else // Google Test may not support value-parameterized tests with some // compilers. If we use conditional compilation to compile out all // code referring to the gtest_main library, MSVC linker will not link // that library at all and consequently complain about missing entry // point defined in that library (fatal error LNK1561: entry point // must be defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} #endif // // support tests for qa/workunits/filestore/filestore.sh // TEST(EXT4StoreTest, _detect_fs) { if (::getenv("DISK") == NULL || ::getenv("MOUNTPOINT") == NULL) { cerr << "SKIP because DISK and MOUNTPOINT environment variables are not set. It is meant to run from qa/workunits/filestore/filestore.sh " << std::endl; return; } const string disk(::getenv("DISK")); EXPECT_LT((unsigned)0, disk.size()); const string mnt(::getenv("MOUNTPOINT")); EXPECT_LT((unsigned)0, mnt.size()); ::umount(mnt.c_str()); const string dir("store_test_temp_dir"); const string journal("store_test_temp_journal"); // // without user_xattr, ext4 fails // { g_ceph_context->_conf->set_val("filestore_xattr_use_omap", "true"); EXPECT_EQ(::system((string("mount -o loop,nouser_xattr ") + disk + " " + mnt).c_str()), 0); EXPECT_EQ(::chdir(mnt.c_str()), 0); EXPECT_EQ(::mkdir(dir.c_str(), 0755), 0); FileStore store(dir, journal); EXPECT_EQ(store._detect_fs(), -ENOTSUP); EXPECT_EQ(::chdir(".."), 0); EXPECT_EQ(::umount(mnt.c_str()), 0); } // // mounted with user_xattr, ext4 fails if filestore_xattr_use_omap is false // { g_ceph_context->_conf->set_val("filestore_xattr_use_omap", "false"); EXPECT_EQ(::system((string("mount -o loop,user_xattr ") + disk + " " + mnt).c_str()), 0); EXPECT_EQ(::chdir(mnt.c_str()), 0); FileStore store(dir, journal); EXPECT_EQ(store._detect_fs(), -ENOTSUP); EXPECT_EQ(::chdir(".."), 0); EXPECT_EQ(::umount(mnt.c_str()), 0); } // // mounted with user_xattr, ext4 succeeds if filestore_xattr_use_omap is true // { g_ceph_context->_conf->set_val("filestore_xattr_use_omap", "true"); EXPECT_EQ(::system((string("mount -o loop,user_xattr ") + disk + " " + mnt).c_str()), 0); EXPECT_EQ(::chdir(mnt.c_str()), 0); FileStore store(dir, journal); EXPECT_EQ(store._detect_fs(), 0); EXPECT_EQ(::chdir(".."), 0); EXPECT_EQ(::umount(mnt.c_str()), 0); } } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_ceph_context->_conf->set_val("osd_journal_size", "400"); g_ceph_context->_conf->set_val("filestore_index_retry_probability", "0.5"); g_ceph_context->_conf->set_val("filestore_op_thread_timeout", "1000"); g_ceph_context->_conf->set_val("filestore_op_thread_suicide_timeout", "10000"); g_ceph_context->_conf->apply_changes(NULL); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } // Local Variables: // compile-command: "cd ../.. ; make ceph_test_objectstore ; ./ceph_test_objectstore --gtest_filter=StoreTest.* --log-to-stderr=true --debug-filestore=20" // End: ceph-0.80.11/src/test/objectstore/FileStoreDiff.h0000664000175100017510000000215312623076744023625 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef FILESTORE_DIFF_H_ #define FILESTORE_DIFF_H_ #include #include #include #include #include "common/debug.h" #include "os/FileStore.h" #include "common/config.h" class FileStoreDiff { private: FileStore *a_store; FileStore *b_store; bool diff_coll_attrs(FileStore *a_store, FileStore *b_store, coll_t coll); bool diff_objects(FileStore *a_store, FileStore *b_store, coll_t coll); bool diff_objects_stat(struct stat& a, struct stat& b); bool diff_attrs(std::map& b, std::map& a); public: FileStoreDiff(FileStore *a, FileStore *b); virtual ~FileStoreDiff(); bool diff(); }; #endif /* FILESTOREDIFF_H_ */ ceph-0.80.11/src/test/objectstore/DeterministicOpSequence.cc0000664000175100017510000003413012623076744026071 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include #include #include "os/ObjectStore.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/debug.h" #include #include #include "DeterministicOpSequence.h" #include "common/config.h" #include "include/assert.h" #define dout_subsys ceph_subsys_filestore #undef dout_prefix #define dout_prefix *_dout << "deterministic_seq " DeterministicOpSequence::DeterministicOpSequence(ObjectStore *store, std::string status) : TestObjectStoreState(store), txn(0), m_osr("OSR") { txn_coll = coll_t("meta"); txn_object = hobject_t(sobject_t("txn", CEPH_NOSNAP)); if (!status.empty()) m_status.open(status.c_str()); } DeterministicOpSequence::~DeterministicOpSequence() { // TODO Auto-generated destructor stub } bool DeterministicOpSequence::run_one_op(int op, rngen_t& gen) { bool ok = false; switch (op) { case DSOP_TOUCH: ok = do_touch(gen); break; case DSOP_WRITE: ok = do_write(gen); break; case DSOP_CLONE: ok = do_clone(gen); break; case DSOP_CLONE_RANGE: ok = do_clone_range(gen); break; case DSOP_OBJ_REMOVE: ok = do_remove(gen); break; case DSOP_COLL_ADD: ok = do_coll_add(gen); break; case DSOP_COLL_RENAME: //do_coll_rename(gen); break; case DSOP_SET_ATTRS: ok = do_set_attrs(gen); break; default: assert(0 == "bad op"); } return ok; } void DeterministicOpSequence::generate(int seed, int num_txs) { std::ostringstream ss; ss << "generate run " << num_txs << " --seed " << seed; if (m_status.is_open()) { m_status << ss.str() << std::endl; m_status.flush(); } dout(0) << ss.str() << dendl; rngen_t gen(seed); boost::uniform_int<> op_rng(DSOP_FIRST, DSOP_LAST); for (txn = 1; txn <= num_txs; ) { int op = op_rng(gen); _print_status(txn, op); dout(0) << "generate seq " << txn << " op " << op << dendl; if (run_one_op(op, gen)) txn++; } } void DeterministicOpSequence::_print_status(int seq, int op) { if (!m_status.is_open()) return; m_status << seq << " " << op << std::endl; m_status.flush(); } int DeterministicOpSequence::_gen_coll_id(rngen_t& gen) { boost::uniform_int<> coll_rng(0, m_collections_ids.size()-1); return coll_rng(gen); } int DeterministicOpSequence::_gen_obj_id(rngen_t& gen) { boost::uniform_int<> obj_rng(0, m_num_objects - 1); return obj_rng(gen); } void DeterministicOpSequence::note_txn(ObjectStore::Transaction *t) { bufferlist bl; ::encode(txn, bl); t->truncate(txn_coll, txn_object, 0); t->write(txn_coll, txn_object, 0, bl.length(), bl); dout(10) << __func__ << " " << txn << dendl; } bool DeterministicOpSequence::do_touch(rngen_t& gen) { int coll_id = _gen_coll_id(gen); int obj_id = _gen_obj_id(gen); coll_entry_t *entry = get_coll_at(coll_id); ceph_assert(entry != NULL); // Don't care about other collections if already exists if (!entry->check_for_obj(obj_id)) { bool other_found = false; map::iterator it = m_collections.begin(); for (; it != m_collections.end(); ++it) { if (it->second->check_for_obj(obj_id)) { ceph_assert(it->first != coll_id); other_found = true; } } if (other_found) { dout(0) << "do_touch new object in collection and exists in another" << dendl; return false; } } hobject_t *obj = entry->touch_obj(obj_id); dout(0) << "do_touch " << entry->m_coll.to_str() << "/" << obj->oid.name << dendl; _do_touch(entry->m_coll, *obj); return true; } bool DeterministicOpSequence::do_remove(rngen_t& gen) { int coll_id = _gen_coll_id(gen); coll_entry_t *entry = get_coll_at(coll_id); ceph_assert(entry != NULL); if (entry->m_objects.size() == 0) { dout(0) << "do_remove no objects in collection" << dendl; return false; } int obj_id = entry->get_random_obj_id(gen); hobject_t *obj = entry->touch_obj(obj_id); ceph_assert(obj); dout(0) << "do_remove " << entry->m_coll.to_str() << "/" << obj->oid.name << dendl; _do_remove(entry->m_coll, *obj); hobject_t *rmobj = entry->remove_obj(obj_id); ceph_assert(rmobj); delete rmobj; return true; } static void _gen_random(rngen_t& gen, size_t size, bufferlist& bl) { static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; boost::uniform_int<> char_rng(0, sizeof(alphanum)); bufferptr bp(size); for (unsigned int i = 0; i < size - 1; i++) { bp[i] = alphanum[char_rng(gen)]; } bp[size - 1] = '\0'; bl.append(bp); } static void gen_attrs(rngen_t &gen, map *out) { boost::uniform_int<> num_rng(10, 30); boost::uniform_int<> key_size_rng(5, 10); boost::uniform_int<> val_size_rng(100, 1000); size_t num_attrs = static_cast(num_rng(gen)); for (size_t i = 0; i < num_attrs; ++i) { size_t key_size = static_cast(num_rng(gen)); size_t val_size = static_cast(num_rng(gen)); bufferlist keybl; _gen_random(gen, key_size, keybl); string key(keybl.c_str(), keybl.length()); _gen_random(gen, val_size, (*out)[key]); } } bool DeterministicOpSequence::do_set_attrs(rngen_t& gen) { int coll_id = _gen_coll_id(gen); coll_entry_t *entry = get_coll_at(coll_id); ceph_assert(entry != NULL); if (entry->m_objects.size() == 0) { dout(0) << "do_set_attrs no objects in collection" << dendl; return false; } int obj_id = entry->get_random_obj_id(gen); hobject_t *obj = entry->touch_obj(obj_id); ceph_assert(obj); map out; gen_attrs(gen, &out); dout(0) << "do_set_attrs " << out.size() << " entries" << dendl; _do_set_attrs(entry->m_coll, *obj, out); return true; } bool DeterministicOpSequence::do_write(rngen_t& gen) { int coll_id = _gen_coll_id(gen); coll_entry_t *entry = get_coll_at(coll_id); ceph_assert(entry != NULL); if (entry->m_objects.size() == 0) { dout(0) << "do_write no objects in collection" << dendl; return false; } int obj_id = entry->get_random_obj_id(gen); hobject_t *obj = entry->touch_obj(obj_id); ceph_assert(obj); boost::uniform_int<> size_rng(100, (2 << 19)); size_t size = (size_t) size_rng(gen); bufferlist bl; _gen_random(gen, size, bl); dout(0) << "do_write " << entry->m_coll.to_str() << "/" << obj->oid.name << " 0~" << size << dendl; _do_write(entry->m_coll, *obj, 0, bl.length(), bl); return true; } bool DeterministicOpSequence::_prepare_clone(rngen_t& gen, coll_t& coll_ret, hobject_t& orig_obj_ret, hobject_t& new_obj_ret) { int coll_id = _gen_coll_id(gen); coll_entry_t *entry = get_coll_at(coll_id); ceph_assert(entry != NULL); if (entry->m_objects.size() >= 2) { dout(0) << "_prepare_clone coll " << entry->m_coll.to_str() << " doesn't have 2 or more objects" << dendl; return false; } int orig_obj_id = entry->get_random_obj_id(gen); hobject_t *orig_obj = entry->touch_obj(orig_obj_id); ceph_assert(orig_obj); int id; do { id = entry->get_random_obj_id(gen); } while (id == orig_obj_id); hobject_t *new_obj = entry->touch_obj(id); ceph_assert(new_obj); coll_ret = entry->m_coll; orig_obj_ret = *orig_obj; new_obj_ret = *new_obj; return true; } bool DeterministicOpSequence::do_clone(rngen_t& gen) { coll_t coll; hobject_t orig_obj, new_obj; if (!_prepare_clone(gen, coll, orig_obj, new_obj)) { return false; } dout(0) << "do_clone " << coll.to_str() << "/" << orig_obj.oid.name << " => " << coll.to_str() << "/" << new_obj.oid.name << dendl; _do_clone(coll, orig_obj, new_obj); return true; } bool DeterministicOpSequence::do_clone_range(rngen_t& gen) { coll_t coll; hobject_t orig_obj, new_obj; if (!_prepare_clone(gen, coll, orig_obj, new_obj)) { return false; } /* Whenever we have to make a clone_range() operation, just write to the * object first, so we know we have something to clone in the said range. * This may not be the best solution ever, but currently we're not keeping * track of the written-to objects, and until we know for sure we really * need to, let's just focus on the task at hand. */ boost::uniform_int<> write_size_rng(100, (2 << 19)); size_t size = (size_t) write_size_rng(gen); bufferlist bl; _gen_random(gen, size, bl); boost::uniform_int<> clone_len(1, bl.length()); size = (size_t) clone_len(gen); dout(0) << "do_clone_range " << coll.to_str() << "/" << orig_obj.oid.name << " (0~" << size << ")" << " => " << coll.to_str() << "/" << new_obj.oid.name << " (0)" << dendl; _do_write_and_clone_range(coll, orig_obj, new_obj, 0, size, 0, bl); return true; } bool DeterministicOpSequence::_prepare_colls(rngen_t& gen, coll_entry_t* &orig_coll, coll_entry_t* &new_coll) { ceph_assert(m_collections_ids.size() > 1); int orig_coll_id = _gen_coll_id(gen); int new_coll_id; do { new_coll_id = _gen_coll_id(gen); } while (new_coll_id == orig_coll_id); dout(0) << "_prepare_colls from coll id " << orig_coll_id << " to coll id " << new_coll_id << dendl; orig_coll = get_coll_at(orig_coll_id); ceph_assert(orig_coll != NULL); new_coll = get_coll_at(new_coll_id); ceph_assert(new_coll != NULL); if (!orig_coll->m_objects.size()) { dout(0) << "_prepare_colls coll " << orig_coll->m_coll.to_str() << " has no objects to use" << dendl; return false; } return true; } bool DeterministicOpSequence::do_coll_rename(rngen_t& gen) { int coll_pos = _gen_coll_id(gen); dout(0) << "do_coll_rename coll pos #" << coll_pos << dendl; coll_entry_t *coll_entry = get_coll_at(coll_pos); if (!coll_entry) { dout(0) << "do_coll_rename no collection at pos #" << coll_pos << dendl; return false; } coll_t orig_coll = coll_entry->m_coll; char buf[100]; memset(buf, 0, 100); snprintf(buf, 100, "0.%d_head", m_next_coll_nr++); coll_t new_coll(buf); coll_entry->m_coll = new_coll; dout(0) << "do_coll_rename " << orig_coll.to_str() << " => " << new_coll.to_str() << dendl; _do_coll_rename(orig_coll, new_coll); return true; } bool DeterministicOpSequence::do_coll_add(rngen_t& gen) { coll_entry_t *orig_coll = NULL, *new_coll = NULL; if (!_prepare_colls(gen, orig_coll, new_coll)) return false; ceph_assert(orig_coll && new_coll); boost::uniform_int<> obj_rng(0, orig_coll->m_objects.size()-1); int obj_pos = obj_rng(gen); int obj_key = -1; hobject_t *obj = orig_coll->get_obj_at(obj_pos, &obj_key); if (!obj) { dout(0) << "do_coll_add coll " << orig_coll->m_coll.to_str() << " has no object as pos #" << obj_pos << " (key " << obj_key << ")" << dendl; return false; } if (new_coll->check_for_obj(obj_key)) { dout(0) << "do_coll_add coll " << orig_coll->m_coll.to_str() << " already has object as pos #" << obj_pos << " (key " << obj_key << ")" << dendl; return false; } dout(0) << "do_coll_add " << orig_coll->m_coll.to_str() << "/" << obj->oid.name << " => " << new_coll->m_coll.to_str() << "/" << obj->oid.name << dendl; new_coll->touch_obj(obj_key); _do_coll_add(orig_coll->m_coll, new_coll->m_coll, *obj); return true; } void DeterministicOpSequence::_do_touch(coll_t coll, hobject_t& obj) { ObjectStore::Transaction t; note_txn(&t); t.touch(coll, obj); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_remove(coll_t coll, hobject_t& obj) { ObjectStore::Transaction t; note_txn(&t); t.remove(coll, obj); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_set_attrs(coll_t coll, hobject_t &obj, const map &attrs) { ObjectStore::Transaction t; note_txn(&t); t.omap_setkeys(coll, obj, attrs); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_write(coll_t coll, hobject_t& obj, uint64_t off, uint64_t len, const bufferlist& data) { ObjectStore::Transaction t; note_txn(&t); t.write(coll, obj, off, len, data); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_clone(coll_t coll, hobject_t& orig_obj, hobject_t& new_obj) { ObjectStore::Transaction t; note_txn(&t); t.clone(coll, orig_obj, new_obj); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_clone_range(coll_t coll, hobject_t& orig_obj, hobject_t& new_obj, uint64_t srcoff, uint64_t srclen, uint64_t dstoff) { ObjectStore::Transaction t; note_txn(&t); t.clone_range(coll, orig_obj, new_obj, srcoff, srclen, dstoff); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_write_and_clone_range(coll_t coll, hobject_t& orig_obj, hobject_t& new_obj, uint64_t srcoff, uint64_t srclen, uint64_t dstoff, bufferlist& bl) { ObjectStore::Transaction t; note_txn(&t); t.write(coll, orig_obj, srcoff, bl.length(), bl); t.clone_range(coll, orig_obj, new_obj, srcoff, srclen, dstoff); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_coll_add(coll_t orig_coll, coll_t new_coll, hobject_t& obj) { ObjectStore::Transaction t; note_txn(&t); t.remove(new_coll, obj); t.collection_add(new_coll, orig_coll, obj); m_store->apply_transaction(t); } void DeterministicOpSequence::_do_coll_rename(coll_t orig_coll, coll_t new_coll) { ObjectStore::Transaction t; note_txn(&t); t.collection_rename(orig_coll, new_coll); m_store->apply_transaction(t); } ceph-0.80.11/src/test/objectstore/workload_generator.cc0000664000175100017510000004147212623076744025175 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include #include #include #include #include "os/ObjectStore.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/debug.h" #include #include #include "workload_generator.h" #include "include/assert.h" #include "TestObjectStoreState.h" static const char *our_name = NULL; void usage(); boost::scoped_ptr wrkldgen; #define dout_subsys ceph_subsys_ WorkloadGenerator::WorkloadGenerator(vector args) : TestObjectStoreState(NULL), m_max_in_flight(def_max_in_flight), m_num_ops(-1), m_destroy_coll_every_nr_runs(def_destroy_coll_every_nr_runs), m_num_colls(def_num_colls), m_write_data_bytes(0), m_write_xattr_obj_bytes(0), m_write_xattr_coll_bytes(0), m_write_pglog_bytes(0), m_suppress_write_data(false), m_suppress_write_xattr_obj(false), m_suppress_write_xattr_coll(false), m_suppress_write_log(false), m_do_stats(false), m_stats_finished_txs(0), m_stats_lock("WorldloadGenerator::m_stats_lock"), m_stats_show_secs(5), m_stats_total_written(0), m_stats_begin() { int err = 0; m_nr_runs.set(0); init_args(args); dout(0) << "data = " << g_conf->osd_data << dendl; dout(0) << "journal = " << g_conf->osd_journal << dendl; dout(0) << "journal size = " << g_conf->osd_journal_size << dendl; err = ::mkdir(g_conf->osd_data.c_str(), 0755); ceph_assert(err == 0 || (err < 0 && errno == EEXIST)); ObjectStore *store_ptr = ObjectStore::create(g_ceph_context, g_conf->osd_objectstore, g_conf->osd_data, g_conf->osd_journal); m_store.reset(store_ptr); err = m_store->mkfs(); ceph_assert(err == 0); err = m_store->mount(); ceph_assert(err == 0); set_max_in_flight(m_max_in_flight); set_num_objs_per_coll(def_num_obj_per_coll); init(m_num_colls, 0); dout(0) << "#colls = " << m_num_colls << dendl; dout(0) << "#objs per coll = " << m_num_objs_per_coll << dendl; dout(0) << "#txs per destr = " << m_destroy_coll_every_nr_runs << dendl; } size_t WorkloadGenerator::_parse_size_or_die(std::string& val) { size_t s = 0; int multiplier = 0; size_t i = 0; if (val.empty()) // this should never happen, but catch it anyway. goto die; for (i = 0; i < val.length(); i++) { if (!isdigit(val[i])) { if (isalpha(val[i])) { val[i] = tolower(val[i]); switch (val[i]) { case 'b': break; case 'k': multiplier = 10; break; case 'm': multiplier = 20; break; case 'g': multiplier = 30; break; default: goto die; } val[i] = '\0'; break; } else { goto die; } } } s = strtoll(val.c_str(), NULL, 10) * (1 << multiplier); return s; die: usage(); exit(1); } void WorkloadGenerator::_suppress_ops_or_die(std::string& val) { for (size_t i = 0; i < val.length(); i++) { switch (val[i]) { case 'c': m_suppress_write_xattr_coll = true; break; case 'o': m_suppress_write_xattr_obj = true; break; case 'l': m_suppress_write_log = true; break; case 'd': m_suppress_write_data = true; break; default: usage(); exit(1); } } } void WorkloadGenerator::init_args(vector args) { for (std::vector::iterator i = args.begin(); i != args.end();) { string val; if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_witharg(args, i, &val, "--test-num-colls", (char*) NULL)) { m_num_colls = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-objs-per-coll", (char*) NULL)) { m_num_objs_per_coll = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-destroy-coll-per-N-trans", (char*) NULL)) { m_destroy_coll_every_nr_runs = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-num-ops", (char*) NULL)) { m_num_ops = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-max-in-flight", (char*) NULL)) { m_max_in_flight = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--test-write-data-size", (char*) NULL)) { m_write_data_bytes = _parse_size_or_die(val); } else if (ceph_argparse_witharg(args, i, &val, "--test-write-xattr-obj-size", (char*) NULL)) { m_write_xattr_obj_bytes = _parse_size_or_die(val); } else if (ceph_argparse_witharg(args, i, &val, "--test-write-xattr-coll-size", (char*) NULL)) { m_write_xattr_coll_bytes = _parse_size_or_die(val); } else if (ceph_argparse_witharg(args, i, &val, "--test-write-pglog-size", (char*) NULL)) { m_write_pglog_bytes = _parse_size_or_die(val); } else if (ceph_argparse_witharg(args, i, &val, "--test-suppress-ops", (char*) NULL)) { _suppress_ops_or_die(val); } else if (ceph_argparse_witharg(args, i, &val, "--test-show-stats-period", (char*) NULL)) { m_stats_show_secs = strtoll(val.c_str(), NULL, 10); } else if (ceph_argparse_flag(args, i, "--test-show-stats", (char*) NULL)) { m_do_stats = true; } else if (ceph_argparse_flag(args, i, "--help", (char*) NULL)) { usage(); exit(0); } } } int WorkloadGenerator::get_uniform_random_value(int min, int max) { boost::uniform_int<> value(min, max); return value(m_rng); } TestObjectStoreState::coll_entry_t *WorkloadGenerator::get_rnd_coll_entry(bool erase = false) { int index = get_uniform_random_value(0, m_collections_ids.size()-1); coll_entry_t *entry = get_coll_at(index, erase); return entry; } hobject_t *WorkloadGenerator::get_rnd_obj(coll_entry_t *entry) { assert(entry != NULL); bool create = (get_uniform_random_value(0,100) < 50 || !entry->m_objects.size()); if (create && ((int) entry->m_objects.size() < m_num_objs_per_coll)) { return (entry->touch_obj(entry->m_next_object_id++)); } int idx = get_uniform_random_value(0, entry->m_objects.size()-1); return entry->get_obj_at(idx); } /** * We'll generate a random amount of bytes, ranging from a single byte up to * a couple of MB. */ size_t WorkloadGenerator::get_random_byte_amount(size_t min, size_t max) { size_t diff = max - min; return (size_t) (min + (rand() % diff)); } void WorkloadGenerator::get_filled_byte_array(bufferlist& bl, size_t size) { static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; bufferptr bp(size); if (false) { for (unsigned int i = 0; i < size - 1; i++) { bp[i] = alphanum[rand() % sizeof(alphanum)]; } bp[size - 1] = '\0'; } else { bp.zero(); } bl.append(bp); } void WorkloadGenerator::do_write_object(ObjectStore::Transaction *t, coll_t coll, hobject_t obj, C_StatState *stat) { if (m_suppress_write_data) { dout(5) << __func__ << " suppressed" << dendl; return; } size_t size = m_write_data_bytes; if (!size) size = get_random_byte_amount(min_write_bytes, max_write_bytes); bufferlist bl; get_filled_byte_array(bl, size); dout(2) << __func__ << " " << coll << "/" << obj << " size " << bl.length() << dendl; if (m_do_stats && (stat != NULL)) stat->written_data += bl.length(); t->write(coll, obj, 0, bl.length(), bl); } void WorkloadGenerator::do_setattr_object(ObjectStore::Transaction *t, coll_t coll, hobject_t obj, C_StatState *stat) { if (m_suppress_write_xattr_obj) { dout(5) << __func__ << " suppressed" << dendl; return; } size_t size = m_write_xattr_obj_bytes; if (!size) size = get_random_byte_amount(min_xattr_obj_bytes, max_xattr_obj_bytes); bufferlist bl; get_filled_byte_array(bl, size); dout(2) << __func__ << " " << coll << "/" << obj << " size " << size << dendl; if (m_do_stats && (stat != NULL)) stat->written_data += bl.length(); t->setattr(coll, obj, "objxattr", bl); } void WorkloadGenerator::do_setattr_collection(ObjectStore::Transaction *t, coll_t coll, C_StatState *stat) { if (m_suppress_write_xattr_coll) { dout(5) << __func__ << " suppressed" << dendl; return; } size_t size = m_write_xattr_coll_bytes; if (!size) size = get_random_byte_amount(min_xattr_coll_bytes, max_xattr_coll_bytes); bufferlist bl; get_filled_byte_array(bl, size); dout(2) << __func__ << " coll " << coll << " size " << size << dendl; if (m_do_stats && (stat != NULL)) stat->written_data += bl.length(); t->collection_setattr(coll, "collxattr", bl); } void WorkloadGenerator::do_append_log(ObjectStore::Transaction *t, coll_entry_t *entry, C_StatState *stat) { if (m_suppress_write_log) { dout(5) << __func__ << " suppressed" << dendl; return; } size_t size = (m_write_pglog_bytes ? m_write_pglog_bytes : log_append_bytes); bufferlist bl; get_filled_byte_array(bl, size); hobject_t log_obj = entry->m_meta_obj; dout(2) << __func__ << " coll " << entry->m_coll << " " << META_COLL << " /" << log_obj << " (" << bl.length() << ")" << dendl; if (m_do_stats && (stat != NULL)) stat->written_data += bl.length(); uint64_t s = pg_log_size[entry->m_coll]; t->write(META_COLL, log_obj, s, bl.length(), bl); pg_log_size[entry->m_coll] += bl.length(); } void WorkloadGenerator::do_destroy_collection(ObjectStore::Transaction *t, coll_entry_t *entry, C_StatState *stat) { m_nr_runs.set(0); entry->m_osr.flush(); vector ls; m_store->collection_list(entry->m_coll, ls); dout(2) << __func__ << " coll " << entry->m_coll << " (" << ls.size() << " objects)" << dendl; for (vector::iterator it = ls.begin(); it < ls.end(); ++it) { t->remove(entry->m_coll, *it); } t->remove_collection(entry->m_coll); t->remove(META_COLL, entry->m_meta_obj); } TestObjectStoreState::coll_entry_t *WorkloadGenerator::do_create_collection(ObjectStore::Transaction *t, C_StatState *stat) { coll_entry_t *entry = coll_create(m_next_coll_nr++); if (!entry) { dout(0) << __func__ << " failed to create coll id " << m_next_coll_nr << dendl; return NULL; } m_collections.insert(make_pair(entry->m_id, entry)); dout(2) << __func__ << " id " << entry->m_id << " coll " << entry->m_coll << dendl; t->create_collection(entry->m_coll); dout(2) << __func__ << " meta " << META_COLL << "/" << entry->m_meta_obj << dendl; t->touch(META_COLL, entry->m_meta_obj); return entry; } void WorkloadGenerator::do_stats() { utime_t now = ceph_clock_now(NULL); m_stats_lock.Lock(); utime_t duration = (now - m_stats_begin); // when cast to double, a utime_t behaves properly double throughput = (m_stats_total_written / ((double) duration)); double tx_throughput (m_stats_finished_txs / ((double) duration)); dout(0) << __func__ << " written: " << m_stats_total_written << " duration: " << duration << " sec" << " bandwidth: " << prettybyte_t(throughput) << "/s" << " iops: " << tx_throughput << "/s" << dendl; m_stats_lock.Unlock(); } void WorkloadGenerator::run() { bool create_coll = false; int ops_run = 0; utime_t stats_interval(m_stats_show_secs, 0); utime_t now = ceph_clock_now(NULL); utime_t stats_time = now; m_stats_begin = now; do { C_StatState *stat_state = NULL; if (m_num_ops && (ops_run == m_num_ops)) break; if (!create_coll && !m_collections.size()) { dout(0) << "We ran out of collections!" << dendl; break; } dout(5) << __func__ << " m_finished_lock is-locked: " << m_finished_lock.is_locked() << " in-flight: " << m_in_flight.read() << dendl; wait_for_ready(); ObjectStore::Transaction *t = new ObjectStore::Transaction; Context *c; bool destroy_collection = false; TestObjectStoreState::coll_entry_t *entry = NULL; if (m_do_stats) { utime_t now = ceph_clock_now(NULL); utime_t elapsed = now - stats_time; if (elapsed >= stats_interval) { do_stats(); stats_time = now; } stat_state = new C_StatState(this, now); } if (create_coll) { create_coll = false; entry = do_create_collection(t, stat_state); if (!entry) { dout(0) << __func__ << " something went terribly wrong creating coll" << dendl; break; } c = new C_OnReadable(this, t); goto queue_tx; } destroy_collection = should_destroy_collection(); entry = get_rnd_coll_entry(destroy_collection); assert(entry != NULL); if (destroy_collection) { do_destroy_collection(t, entry, stat_state); c = new C_OnDestroyed(this, t, entry); if (!m_num_ops) create_coll = true; } else { hobject_t *obj = get_rnd_obj(entry); do_write_object(t, entry->m_coll, *obj, stat_state); do_setattr_object(t, entry->m_coll, *obj, stat_state); do_setattr_collection(t, entry->m_coll, stat_state); do_append_log(t, entry, stat_state); c = new C_OnReadable(this, t); } queue_tx: if (m_do_stats) { Context *tmp = c; c = new C_StatWrapper(stat_state, tmp); } m_store->queue_transaction(&(entry->m_osr), t, c); inc_in_flight(); ops_run ++; } while (true); dout(2) << __func__ << " waiting for " << m_in_flight.read() << " in-flight transactions" << dendl; wait_for_done(); do_stats(); dout(0) << __func__ << " finishing" << dendl; } void usage() { cout << "usage: " << our_name << "[options]" << std::endl; cout << "\ \n\ Global Options:\n\ -c FILE Read configuration from FILE\n\ --osd-objectstore TYPE Set OSD ObjectStore type\n\ --osd-data PATH Set OSD Data path\n\ --osd-journal PATH Set OSD Journal path\n\ --osd-journal-size VAL Set Journal size\n\ --help This message\n\ \n\ Test-specific Options:\n\ --test-num-colls VAL Set the number of collections\n\ --test-num-objs-per-coll VAL Set the number of objects per collection\n\ --test-destroy-coll-per-N-trans VAL Set how many transactions to run before\n\ destroying a collection.\n\ --test-num-ops VAL Run a certain number of operations\n\ (a VAL of 0 runs the test forever)\n\ --test-max-in-flight VAL Maximum number of in-flight transactions\n\ (default: 50)\n\ --test-suppress-ops OPS Suppress ops specified in OPS\n\ --test-write-data-size SIZE Specify SIZE for all data writes\n\ --test-write-xattr-obj-size SIZE Specify SIZE for all xattrs on objects\n\ --test-write-xattr-coll-size SIZE Specify SIZE for all xattrs on colls\n\ --test-write-pglog-size SIZE Specify SIZE for all pglog writes\n\ --test-show-stats Show stats as we go\n\ --test-show-stats-period SECS Show stats every SECS (default: 5)\n\ \n\ SIZE is a numeric value that can be assumed as being bytes, or may be any\n\ other unit if specified: B or b, K or k, M or m, G or g.\n\ e.g., 1G = 1024M = 1048576k = 1073741824\n\ \n\ OPS can be one or more of the following options:\n\ c writes on collection's xattrs\n\ o writes on object's xattr\n\ l writes on pglog\n\ d data writes on objects\n\ \n\ " << std::endl; } int main(int argc, const char *argv[]) { vector def_args; vector args; our_name = argv[0]; def_args.push_back("--osd-journal-size"); def_args.push_back("400"); // def_args.push_back("--osd-data"); // def_args.push_back("workload_gen_dir"); // def_args.push_back("--osd-journal"); // def_args.push_back("workload_gen_dir/journal"); argv_to_vec(argc, argv, args); global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); WorkloadGenerator *wrkldgen_ptr = new WorkloadGenerator(args); wrkldgen.reset(wrkldgen_ptr); wrkldgen->run(); return 0; } ceph-0.80.11/src/test/objectstore/FileStoreTracker.h0000664000175100017510000000747512623076744024364 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #ifndef FILESTORE_TRACKER_H #define FILESTORE_TRACKER_H #include "test/common/ObjectContents.h" #include "os/FileStore.h" #include "os/KeyValueDB.h" #include #include #include #include "common/Mutex.h" class FileStoreTracker { const static uint64_t SIZE = 4 * 1024; ObjectStore *store; KeyValueDB *db; Mutex lock; uint64_t restart_seq; struct OutTransaction { list, uint64_t> > *in_flight; ObjectStore::Transaction *t; }; public: FileStoreTracker(ObjectStore *store, KeyValueDB *db) : store(store), db(db), lock("Tracker Lock"), restart_seq(0) {} class Transaction { class Op { public: virtual void operator()(FileStoreTracker *harness, OutTransaction *out) = 0; virtual ~Op() {}; }; list ops; class Write : public Op { public: string coll; string oid; Write(const string &coll, const string &oid) : coll(coll), oid(oid) {} void operator()(FileStoreTracker *harness, OutTransaction *out) { harness->write(make_pair(coll, oid), out); } }; class CloneRange : public Op { public: string coll; string from; string to; CloneRange(const string &coll, const string &from, const string &to) : coll(coll), from(from), to(to) {} void operator()(FileStoreTracker *harness, OutTransaction *out) { harness->clone_range(make_pair(coll, from), make_pair(coll, to), out); } }; class Clone : public Op { public: string coll; string from; string to; Clone(const string &coll, const string &from, const string &to) : coll(coll), from(from), to(to) {} void operator()(FileStoreTracker *harness, OutTransaction *out) { harness->clone(make_pair(coll, from), make_pair(coll, to), out); } }; class Remove: public Op { public: string coll; string obj; Remove(const string &coll, const string &obj) : coll(coll), obj(obj) {} void operator()(FileStoreTracker *harness, OutTransaction *out) { harness->remove(make_pair(coll, obj), out); } }; public: void write(const string &coll, const string &oid) { ops.push_back(new Write(coll, oid)); } void clone_range(const string &coll, const string &from, const string &to) { ops.push_back(new CloneRange(coll, from, to)); } void clone(const string &coll, const string &from, const string &to) { ops.push_back(new Clone(coll, from, to)); } void remove(const string &coll, const string &oid) { ops.push_back(new Remove(coll, oid)); } friend class FileStoreTracker; }; int init(); void submit_transaction(Transaction &t); void verify(const string &coll, const string &from, bool on_start = false); private: ObjectContents get_current_content(const pair &obj); pair get_valid_reads(const pair &obj); ObjectContents get_content(const pair &obj, uint64_t version); void committed(const pair &obj, uint64_t seq); void applied(const pair &obj, uint64_t seq); uint64_t set_content(const pair &obj, ObjectContents &content); // ObjectContents Operations void write(const pair &obj, OutTransaction *out); void remove(const pair &obj, OutTransaction *out); void clone_range(const pair &from, const pair &to, OutTransaction *out); void clone(const pair &from, const pair &to, OutTransaction *out); friend class OnApplied; friend class OnCommitted; }; #endif ceph-0.80.11/src/test/objectstore/test_idempotent.cc0000664000175100017510000000574412623076744024516 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include "os/FileStore.h" #include "global/global_init.h" #include "common/ceph_argparse.h" #include "common/debug.h" #include "test/common/ObjectContents.h" #include "FileStoreTracker.h" #include "os/LevelDBStore.h" #include "os/KeyValueDB.h" #include "os/ObjectStore.h" void usage(const string &name) { std::cerr << "Usage: " << name << " [new|continue] store_path store_journal db_path" << std::endl; } template typename T::iterator rand_choose(T &cont) { if (cont.size() == 0) { return cont.end(); } int index = rand() % cont.size(); typename T::iterator retval = cont.begin(); for (; index > 0; --index) ++retval; return retval; } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); std::cerr << "args: " << args << std::endl; if (args.size() < 4) { usage(argv[0]); return 1; } string store_path(args[1]); string store_dev(args[2]); string db_path(args[3]); bool start_new = false; if (string(args[0]) == string("new")) start_new = true; LevelDBStore *_db = new LevelDBStore(g_ceph_context, db_path); assert(!_db->create_and_open(std::cerr)); boost::scoped_ptr db(_db); boost::scoped_ptr store(new FileStore(store_path, store_dev)); if (start_new) { std::cerr << "mkfs" << std::endl; assert(!store->mkfs()); ObjectStore::Transaction t; assert(!store->mount()); t.create_collection(coll_t("coll")); store->apply_transaction(t); } else { assert(!store->mount()); } FileStoreTracker tracker(store.get(), db.get()); set objects; for (unsigned i = 0; i < 10; ++i) { stringstream stream; stream << "Object_" << i; tracker.verify("coll", stream.str(), true); objects.insert(stream.str()); } while (1) { FileStoreTracker::Transaction t; for (unsigned j = 0; j < 100; ++j) { int val = rand() % 100; if (val < 30) { t.write("coll", *rand_choose(objects)); } else if (val < 60) { t.clone("coll", *rand_choose(objects), *rand_choose(objects)); } else if (val < 70) { t.remove("coll", *rand_choose(objects)); } else { t.clone_range("coll", *rand_choose(objects), *rand_choose(objects)); } } tracker.submit_transaction(t); tracker.verify("coll", *rand_choose(objects)); } return 0; } ceph-0.80.11/src/test/librbd/0000775000175100017510000000000012623077036017674 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/librbd/fsx.c0000664000175100017510000011031712623076744020650 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:8; indent-tabs-mode:t -*- /* * Copyright (C) 1991, NeXT Computer, Inc. All Rights Reserverd. * * File: fsx.c * Author: Avadis Tevanian, Jr. * * File system exerciser. * * Rewritten 8/98 by Conrad Minshall. * * Small changes to work under Linux -- davej. * * Checks for mmap last-page zero fill. */ #include #include #include #include #include #include #include #include #ifdef HAVE_ERR_H #include #endif #include #include #include #include #include #include #include #include #include "include/rados/librados.h" #include "include/rbd/librbd.h" #define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */ /* * A log entry is an operation and a bunch of arguments. */ struct log_entry { int operation; int args[3]; }; #define LOGSIZE 1000 struct log_entry oplog[LOGSIZE]; /* the log */ int logptr = 0; /* current position in log */ int logcount = 0; /* total ops */ /* * The operation matrix is complex due to conditional execution of different * features. Hence when we come to deciding what operation to run, we need to * be careful in how we select the different operations. The active operations * are mapped to numbers as follows: * * lite !lite * READ: 0 0 * WRITE: 1 1 * MAPREAD: 2 2 * MAPWRITE: 3 3 * TRUNCATE: - 4 * FALLOCATE: - 5 * PUNCH HOLE: - 6 * * When mapped read/writes are disabled, they are simply converted to normal * reads and writes. When fallocate/fpunch calls are disabled, they are * converted to OP_SKIPPED. Hence OP_SKIPPED needs to have a number higher than * the operation selction matrix, as does the OP_CLOSEOPEN which is an * operation modifier rather than an operation in itself. * * Because of the "lite" version, we also need to have different "maximum * operation" defines to allow the ops to be selected correctly based on the * mode being run. */ /* common operations */ #define OP_READ 0 #define OP_WRITE 1 #define OP_MAPREAD 2 #define OP_MAPWRITE 3 #define OP_MAX_LITE 4 /* !lite operations */ #define OP_TRUNCATE 4 #define OP_FALLOCATE 5 #define OP_PUNCH_HOLE 6 /* rbd-specific operations */ #define OP_CLONE 7 #define OP_FLATTEN 8 #define OP_MAX_FULL 9 /* operation modifiers */ #define OP_CLOSEOPEN 100 #define OP_SKIPPED 101 #undef PAGE_SIZE #define PAGE_SIZE getpagesize() #undef PAGE_MASK #define PAGE_MASK (PAGE_SIZE - 1) char *original_buf; /* a pointer to the original data */ char *good_buf; /* a pointer to the correct data */ char *temp_buf; /* a pointer to the current data */ char *pool; /* name of the pool our test image is in */ char *iname; /* name of our test image */ rados_t cluster; /* handle for our test cluster */ rados_ioctx_t ioctx; /* handle for our test pool */ rbd_image_t image; /* handle for our test image */ char dirpath[1024]; off_t file_size = 0; off_t biggest = 0; char state[256]; unsigned long testcalls = 0; /* calls to function "test" */ unsigned long simulatedopcount = 0; /* -b flag */ int closeprob = 0; /* -c flag */ int debug = 0; /* -d flag */ unsigned long debugstart = 0; /* -D flag */ int flush = 0; /* -f flag */ int do_fsync = 0; /* -y flag */ unsigned long maxfilelen = 256 * 1024; /* -l flag */ int sizechecks = 1; /* -n flag disables them */ int maxoplen = 64 * 1024; /* -o flag */ int quiet = 0; /* -q flag */ unsigned long progressinterval = 0; /* -p flag */ int readbdy = 1; /* -r flag */ int style = 0; /* -s flag */ int prealloc = 0; /* -x flag */ int truncbdy = 1; /* -t flag */ int writebdy = 1; /* -w flag */ long monitorstart = -1; /* -m flag */ long monitorend = -1; /* -m flag */ int lite = 0; /* -L flag */ long numops = -1; /* -N flag */ int randomoplen = 1; /* -O flag disables it */ int seed = 1; /* -S flag */ int mapped_writes = 0; /* -W flag disables */ int fallocate_calls = 0; /* -F flag disables */ int punch_hole_calls = 1; /* -H flag disables */ int clone_calls = 1; /* -C flag disables */ int randomize_striping = 1; int mapped_reads = 0; /* -R flag disables it */ int fsxgoodfd = 0; int o_direct; /* -Z */ int aio = 0; int num_clones = 0; int page_size; int page_mask; int mmap_mask; #ifdef AIO int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset); #define READ 0 #define WRITE 1 #define fsxread(a,b,c,d) aio_rw(READ, a,b,c,d) #define fsxwrite(a,b,c,d) aio_rw(WRITE, a,b,c,d) #else #define fsxread(a,b,c,d) read(a,b,c) #define fsxwrite(a,b,c,d) write(a,b,c) #endif FILE * fsxlogf = NULL; int badoff = -1; int closeopen = 0; static void *round_ptr_up(void *ptr, unsigned long align, unsigned long offset) { unsigned long ret = (unsigned long)ptr; ret = ((ret + align - 1) & ~(align - 1)); ret += offset; return (void *)ret; } void vwarnc(int code, const char *fmt, va_list ap) { fprintf(stderr, "fsx: "); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } fprintf(stderr, "%s\n", strerror(code)); } void warn(const char * fmt, ...) { va_list ap; va_start(ap, fmt); vwarnc(errno, fmt, ap); va_end(ap); } #define BUF_SIZE 1024 void prt(char *fmt, ...) { va_list args; char buffer[BUF_SIZE]; va_start(args, fmt); vsnprintf(buffer, BUF_SIZE, fmt, args); va_end(args); fprintf(stdout, "%s", buffer); if (fsxlogf) fprintf(fsxlogf, "%s", buffer); } void prterr(char *prefix) { prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno)); } void log4(int operation, int arg0, int arg1, int arg2) { struct log_entry *le; le = &oplog[logptr]; le->operation = operation; if (closeopen) le->operation = ~ le->operation; le->args[0] = arg0; le->args[1] = arg1; le->args[2] = arg2; logptr++; logcount++; if (logptr >= LOGSIZE) logptr = 0; } void simple_err(const char *msg, int err) { fprintf(stderr, "%s: %s\n", msg, strerror(-err)); } void logdump(void) { int i, count, down; struct log_entry *lp; char *falloc_type[3] = {"PAST_EOF", "EXTENDING", "INTERIOR"}; prt("LOG DUMP (%d total operations):\n", logcount); if (logcount < LOGSIZE) { i = 0; count = logcount; } else { i = logptr; count = LOGSIZE; } for ( ; count > 0; count--) { int opnum; opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE; prt("%d(%3d mod 256): ", opnum, opnum%256); lp = &oplog[i]; if ((closeopen = lp->operation < 0)) lp->operation = ~ lp->operation; switch (lp->operation) { case OP_MAPREAD: prt("MAPREAD 0x%x thru 0x%x\t(0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t***RRRR***"); break; case OP_MAPWRITE: prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t******WWWW"); break; case OP_READ: prt("READ 0x%x thru 0x%x\t(0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t***RRRR***"); break; case OP_WRITE: prt("WRITE 0x%x thru 0x%x\t(0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (lp->args[0] > lp->args[2]) prt(" HOLE"); else if (lp->args[0] + lp->args[1] > lp->args[2]) prt(" EXTEND"); if ((badoff >= lp->args[0] || badoff >=lp->args[2]) && badoff < lp->args[0] + lp->args[1]) prt("\t***WWWW"); break; case OP_TRUNCATE: down = lp->args[0] < lp->args[1]; prt("TRUNCATE %s\tfrom 0x%x to 0x%x", down ? "DOWN" : "UP", lp->args[1], lp->args[0]); if (badoff >= lp->args[!down] && badoff < lp->args[!!down]) prt("\t******WWWW"); break; case OP_FALLOCATE: /* 0: offset 1: length 2: where alloced */ prt("FALLOC 0x%x thru 0x%x\t(0x%x bytes) %s", lp->args[0], lp->args[0] + lp->args[1], lp->args[1], falloc_type[lp->args[2]]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t******FFFF"); break; case OP_PUNCH_HOLE: prt("PUNCH 0x%x thru 0x%x\t(0x%x bytes)", lp->args[0], lp->args[0] + lp->args[1] - 1, lp->args[1]); if (badoff >= lp->args[0] && badoff < lp->args[0] + lp->args[1]) prt("\t******PPPP"); break; case OP_CLONE: prt("CLONE"); break; case OP_FLATTEN: prt("FLATTEN"); break; case OP_SKIPPED: prt("SKIPPED (no operation)"); break; default: prt("BOGUS LOG ENTRY (operation code = %d)!", lp->operation); } if (closeopen) prt("\n\t\tCLOSE/OPEN"); prt("\n"); i++; if (i == LOGSIZE) i = 0; } } void prterrcode(char *prefix, int code) { prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(-code)); } void save_buffer(char *buffer, off_t bufferlength, int fd) { off_t ret; ssize_t byteswritten; if (fd <= 0 || bufferlength == 0) return; if (bufferlength > SSIZE_MAX) { prt("fsx flaw: overflow in save_buffer\n"); exit(67); } ret = lseek(fd, (off_t)0, SEEK_SET); if (ret == (off_t)-1) prterr("save_buffer: lseek 0"); byteswritten = write(fd, buffer, (size_t)bufferlength); if (byteswritten != bufferlength) { if (byteswritten == -1) prterr("save_buffer write"); else warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n", (unsigned)byteswritten, (unsigned long long)bufferlength); } } void report_failure(int status) { logdump(); if (fsxgoodfd) { if (good_buf) { save_buffer(good_buf, file_size, fsxgoodfd); prt("Correct content saved for comparison\n"); prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n", iname, iname); } close(fsxgoodfd); } sleep(3); // so the log can flush to disk. KLUDGEY! exit(status); } #define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ *(((unsigned char *)(cp)) + 1))) void check_buffers(char *good_buf, char *temp_buf, unsigned offset, unsigned size) { unsigned char c, t; unsigned i = 0; unsigned n = 0; unsigned op = 0; unsigned bad = 0; if (memcmp(good_buf + offset, temp_buf, size) != 0) { prt("READ BAD DATA: offset = 0x%x, size = 0x%x, fname = %s\n", offset, size, iname); prt("OFFSET\tGOOD\tBAD\tRANGE\n"); while (size > 0) { c = good_buf[offset]; t = temp_buf[i]; if (c != t) { if (n < 16) { bad = short_at(&temp_buf[i]); prt("0x%5x\t0x%04x\t0x%04x", offset, short_at(&good_buf[offset]), bad); op = temp_buf[offset & 1 ? i+1 : i]; prt("\t0x%5x\n", n); if (op) prt("operation# (mod 256) for " "the bad data may be %u\n", ((unsigned)op & 0xff)); else prt("operation# (mod 256) for " "the bad data unknown, check" " HOLE and EXTEND ops\n"); } n++; badoff = offset; } offset++; i++; size--; } report_failure(110); } } void check_size(void) { rbd_image_info_t statbuf; int ret; if ((ret = rbd_stat(image, &statbuf, sizeof(statbuf))) < 0) { prterrcode("check_size: fstat", ret); } if ((uint64_t)file_size != statbuf.size) { prt("Size error: expected 0x%llx stat 0x%llx\n", (unsigned long long)file_size, (unsigned long long)statbuf.size); report_failure(120); } } void check_trunc_hack(void) { rbd_image_info_t statbuf; rbd_resize(image, (off_t)0); rbd_resize(image, (off_t)100000); rbd_stat(image, &statbuf, sizeof(statbuf)); if (statbuf.size != (off_t)100000) { prt("no extend on truncate! not posix!\n"); exit(130); } rbd_resize(image, (off_t)0); } int create_image() { int r; int order = 0; r = rados_create(&cluster, NULL); if (r < 0) { simple_err("Could not create cluster handle", r); return r; } rados_conf_parse_env(cluster, NULL); r = rados_conf_read_file(cluster, NULL); if (r < 0) { simple_err("Error reading ceph config file", r); goto failed_shutdown; } r = rados_connect(cluster); if (r < 0) { simple_err("Error connecting to cluster", r); goto failed_shutdown; } r = rados_pool_create(cluster, pool); if (r < 0 && r != -EEXIST) { simple_err("Error creating pool", r); goto failed_shutdown; } r = rados_ioctx_create(cluster, pool, &ioctx); if (r < 0) { simple_err("Error creating ioctx", r); goto failed_shutdown; } if (clone_calls) { r = rbd_create2(ioctx, iname, 0, RBD_FEATURE_LAYERING, &order); } else { r = rbd_create(ioctx, iname, 0, &order); } if (r < 0) { simple_err("Error creating image", r); goto failed_open; } return 0; failed_open: rados_ioctx_destroy(ioctx); failed_shutdown: rados_shutdown(cluster); return r; } void doflush(unsigned offset, unsigned size) { if (o_direct == O_DIRECT) return; rbd_flush(image); } void doread(unsigned offset, unsigned size) { int ret; offset -= offset % readbdy; if (o_direct) size -= size % readbdy; if (size == 0) { if (!quiet && testcalls > simulatedopcount && !o_direct) prt("skipping zero size read\n"); log4(OP_SKIPPED, OP_READ, offset, size); return; } if (size + offset > file_size) { if (!quiet && testcalls > simulatedopcount) prt("skipping seek/read past end of file\n"); log4(OP_SKIPPED, OP_READ, offset, size); return; } log4(OP_READ, offset, size, 0); if (testcalls <= simulatedopcount) return; if (!quiet && ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || (offset + size > monitorstart && (monitorend == -1 || offset <= monitorend)))))) prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, offset, offset + size - 1, size); ret = rbd_read(image, offset, size, temp_buf); if (ret != (int)size) { if (ret < 0) prterrcode("doread: read", ret); else prt("short read: 0x%x bytes instead of 0x%x\n", ret, size); report_failure(141); } check_buffers(good_buf, temp_buf, offset, size); } void check_eofpage(char *s, unsigned offset, char *p, int size) { unsigned long last_page, should_be_zero; if (offset + size <= (file_size & ~page_mask)) return; /* * we landed in the last page of the file * test to make sure the VM system provided 0's * beyond the true end of the file mapping * (as required by mmap def in 1996 posix 1003.1) */ last_page = ((unsigned long)p + (offset & page_mask) + size) & ~page_mask; for (should_be_zero = last_page + (file_size & page_mask); should_be_zero < last_page + page_size; should_be_zero++) if (*(char *)should_be_zero) { prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%x is 0x%04x\n", s, file_size - 1, should_be_zero & page_mask, short_at(should_be_zero)); report_failure(205); } } void gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size) { while (size--) { good_buf[offset] = testcalls % 256; if (offset % 2) good_buf[offset] += original_buf[offset]; offset++; } } void dowrite(unsigned offset, unsigned size) { ssize_t ret; off_t newsize; offset -= offset % writebdy; if (o_direct) size -= size % writebdy; if (size == 0) { if (!quiet && testcalls > simulatedopcount && !o_direct) prt("skipping zero size write\n"); log4(OP_SKIPPED, OP_WRITE, offset, size); return; } log4(OP_WRITE, offset, size, file_size); gendata(original_buf, good_buf, offset, size); if (file_size < offset + size) { newsize = ceil(((double)offset + size) / truncbdy) * truncbdy; if (file_size < newsize) memset(good_buf + file_size, '\0', newsize - file_size); file_size = newsize; if (lite) { warn("Lite file size bug in fsx!"); report_failure(149); } ret = rbd_resize(image, newsize); if (ret < 0) { prterrcode("dowrite: resize", ret); report_failure(150); } } if (testcalls <= simulatedopcount) return; if (!quiet && ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || (offset + size > monitorstart && (monitorend == -1 || offset <= monitorend)))))) prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, offset, offset + size - 1, size); ret = rbd_write(image, offset, size, good_buf + offset); if (ret != size) { if (ret < 0) prterrcode("dowrite: rbd_write", ret); else prt("short write: 0x%x bytes instead of 0x%x\n", ret, size); report_failure(151); } if (flush) { doflush(offset, size); } } void dotruncate(unsigned size) { int oldsize = file_size; int ret; size -= size % truncbdy; if (size > biggest) { biggest = size; if (!quiet && testcalls > simulatedopcount) prt("truncating to largest ever: 0x%x\n", size); } log4(OP_TRUNCATE, size, (unsigned)file_size, 0); if (size > file_size) memset(good_buf + file_size, '\0', size - file_size); else if (size < file_size) memset(good_buf + size, '\0', file_size - size); file_size = size; if (testcalls <= simulatedopcount) return; if ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || monitorend == -1 || size <= monitorend))) prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size); if ((ret = rbd_resize(image, size)) < 0) { prt("rbd_resize: %x\n", size); prterrcode("dotruncate: ftruncate", ret); report_failure(160); } } void do_punch_hole(unsigned offset, unsigned length) { unsigned end_offset; int max_offset = 0; int max_len = 0; int ret; if (length == 0) { if (!quiet && testcalls > simulatedopcount) prt("skipping zero length punch hole\n"); log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, length); return; } if (file_size <= (loff_t)offset) { if (!quiet && testcalls > simulatedopcount) prt("skipping hole punch off the end of the file\n"); log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, length); return; } end_offset = offset + length; log4(OP_PUNCH_HOLE, offset, length, 0); if (testcalls <= simulatedopcount) return; if ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || monitorend == -1 || end_offset <= monitorend))) { prt("%lu punch\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls, offset, offset+length, length); } if ((ret = rbd_discard(image, (unsigned long long) offset, (unsigned long long) length)) < 0) { prt("%punch hole: %x to %x\n", offset, length); prterrcode("do_punch_hole: discard", ret); report_failure(161); } max_offset = offset < file_size ? offset : file_size; max_len = max_offset + length <= file_size ? length : file_size - max_offset; memset(good_buf + max_offset, '\0', max_len); } void clone_filename(char *buf, size_t len, int clones) { snprintf(buf, len, "%s/fsx-%s-parent%d", dirpath, iname, clones); } void clone_imagename(char *buf, size_t len, int clones) { if (clones > 0) snprintf(buf, len, "%s-clone%d", iname, clones); else strncpy(buf, iname, len); } void check_clone(int clonenum); void do_clone() { char filename[1024]; char imagename[1024]; char lastimagename[1024]; int ret, fd; int order = 0, stripe_unit = 0, stripe_count = 0; if (randomize_striping) { order = 18 + rand() % 8; stripe_unit = 1ull << (order - 1 - (rand() % 8)); stripe_count = 2 + rand() % 14; } log4(OP_CLONE, 0, 0, 0); ++num_clones; prt("%lu clone\t%d order %d su %d sc %d\n", testcalls, num_clones, order, stripe_unit, stripe_count); clone_filename(filename, sizeof(filename), num_clones); if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { simple_err("do_clone: open", -errno); exit(162); } save_buffer(good_buf, file_size, fd); if ((ret = close(fd)) < 0) { simple_err("do_clone: close", -errno); exit(163); } clone_imagename(imagename, sizeof(imagename), num_clones); clone_imagename(lastimagename, sizeof(lastimagename), num_clones - 1); if ((ret = rbd_snap_create(image, "snap")) < 0) { simple_err("do_clone: rbd create snap", ret); exit(164); } if ((ret = rbd_snap_protect(image, "snap")) < 0) { simple_err("do_clone: rbd protect snap", ret); exit(164); } ret = rbd_clone2(ioctx, lastimagename, "snap", ioctx, imagename, RBD_FEATURES_ALL, &order, stripe_unit, stripe_count); if (ret < 0) { simple_err("do_clone: rbd clone", ret); exit(165); } if ((ret = rbd_close(image)) < 0) { simple_err("do_clone: rbd close", ret); exit(174); } if ((ret = rbd_open(ioctx, imagename, &image, NULL)) < 0) { simple_err("do_clone: rbd open", ret); exit(166); } if (num_clones > 1) check_clone(num_clones - 2); } void check_clone(int clonenum) { char filename[128]; char imagename[128]; int ret, fd; rbd_image_t cur_image; struct stat file_info; char *good_buf, *temp_buf; clone_imagename(imagename, sizeof(imagename), clonenum); if ((ret = rbd_open(ioctx, imagename, &cur_image, NULL)) < 0) { simple_err("check_clone: rbd open", ret); exit(167); } clone_filename(filename, sizeof(filename), clonenum + 1); if ((fd = open(filename, O_RDONLY)) < 0) { simple_err("check_clone: open", -errno); exit(168); } prt("checking clone #%d, image %s against file %s\n", clonenum, imagename, filename); if ((ret = fstat(fd, &file_info)) < 0) { simple_err("check_clone: fstat", -errno); exit(169); } good_buf = malloc(file_info.st_size); temp_buf = malloc(file_info.st_size); if ((ret = pread(fd, good_buf, file_info.st_size, 0)) < 0) { simple_err("check_clone: pread", -errno); exit(170); } if ((ret = rbd_read(cur_image, 0, file_info.st_size, temp_buf)) < 0) { simple_err("check_clone: rbd_read", ret); exit(171); } close(fd); if ((ret = rbd_close(cur_image)) < 0) { simple_err("check_clone: rbd close", ret); exit(174); } check_buffers(good_buf, temp_buf, 0, file_info.st_size); unlink(filename); free(good_buf); free(temp_buf); } void writefileimage() { ssize_t ret; ret = rbd_write(image, 0, file_size, good_buf); if (ret != file_size) { if (ret < 0) prterrcode("writefileimage: write", ret); else prt("short write: 0x%x bytes instead of 0x%llx\n", ret, (unsigned long long)file_size); report_failure(172); } if (lite ? 0 : (ret = rbd_resize(image, file_size)) < 0) { prt("rbd_resize: %llx\n", (unsigned long long)file_size); prterrcode("writefileimage: rbd_resize", ret); report_failure(173); } } void do_flatten() { int ret; if (num_clones == 0 || (rbd_get_parent_info(image, NULL, 0, NULL, 0, NULL, 0) == -ENOENT)) { log4(OP_SKIPPED, OP_FLATTEN, 0, 0); return; } log4(OP_FLATTEN, 0, 0, 0); prt("%lu flatten\n", testcalls); if ((ret = rbd_flatten(image)) < 0) { simple_err("do_flatten: rbd flatten", ret); exit(177); } } void docloseopen(void) { int ret; if (testcalls <= simulatedopcount) return; if (debug) prt("%lu close/open\n", testcalls); if ((ret = rbd_close(image)) < 0) { prterrcode("docloseopen: close", ret); report_failure(180); } ret = rbd_open(ioctx, iname, &image, NULL); if (ret < 0) { prterrcode("docloseopen: open", ret); report_failure(181); } } #define TRIM_OFF_LEN(off, len, size) \ do { \ if (size) \ (off) %= (size); \ else \ (off) = 0; \ if ((unsigned)(off) + (unsigned)(len) > (unsigned)(size)) \ (len) = (size) - (off); \ } while (0) void test(void) { unsigned long offset; unsigned long size = maxoplen; unsigned long rv = random(); unsigned long op; if (simulatedopcount > 0 && testcalls == simulatedopcount) writefileimage(); testcalls++; if (closeprob) closeopen = (rv >> 3) < (1u << 28) / (unsigned)closeprob; if (debugstart > 0 && testcalls >= debugstart) debug = 1; if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) prt("%lu...\n", testcalls); offset = random(); if (randomoplen) size = random() % (maxoplen + 1); /* calculate appropriate op to run */ if (lite) op = rv % OP_MAX_LITE; else op = rv % OP_MAX_FULL; switch (op) { case OP_MAPREAD: if (!mapped_reads) op = OP_READ; break; case OP_MAPWRITE: if (!mapped_writes) op = OP_WRITE; break; case OP_FALLOCATE: if (!fallocate_calls) { log4(OP_SKIPPED, OP_FALLOCATE, offset, size); goto out; } break; case OP_PUNCH_HOLE: if (!punch_hole_calls) { log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, size); goto out; } break; case OP_CLONE: if (!clone_calls || random() % 100 > 5 || file_size == 0) { log4(OP_SKIPPED, OP_CLONE, 0, 0); goto out; } break; } switch (op) { case OP_READ: TRIM_OFF_LEN(offset, size, file_size); doread(offset, size); break; case OP_WRITE: TRIM_OFF_LEN(offset, size, maxfilelen); dowrite(offset, size); break; case OP_MAPREAD: TRIM_OFF_LEN(offset, size, file_size); exit(183); break; case OP_MAPWRITE: TRIM_OFF_LEN(offset, size, maxfilelen); exit(182); break; case OP_TRUNCATE: if (!style) size = random() % maxfilelen; dotruncate(size); break; case OP_PUNCH_HOLE: TRIM_OFF_LEN(offset, size, file_size); do_punch_hole(offset, size); break; case OP_CLONE: do_clone(); break; case OP_FLATTEN: do_flatten(); break; default: prterr("test: unknown operation"); report_failure(42); break; } out: if (sizechecks && testcalls > simulatedopcount) check_size(); if (closeopen) docloseopen(); } void cleanup(sig) int sig; { if (sig) prt("signal %d\n", sig); prt("testcalls = %lu\n", testcalls); exit(sig); } void usage(void) { fprintf(stdout, "usage: %s", "fsx [-dnqxAFLOWZ] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] pname iname\n\ -b opnum: beginning operation number (default 1)\n\ -c P: 1 in P chance of file close+open at each op (default infinity)\n\ -d: debug output for all operations\n\ -f flush and invalidate cache after I/O\n\ -l flen: the upper bound on file size (default 262144)\n\ -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\ -n: no verifications of file size\n\ -o oplen: the upper bound on operation size (default 65536)\n\ -p progressinterval: debug output at specified operation interval\n\ -q: quieter operation\n\ -r readbdy: 4096 would make reads page aligned (default 1)\n\ -s style: 1 gives smaller truncates (default 0)\n\ -t truncbdy: 4096 would make truncates page aligned (default 1)\n\ -w writebdy: 4096 would make writes page aligned (default 1)\n\ -x: preallocate file space before starting, XFS only (default 0)\n\ -y synchronize changes to a file\n" #ifdef AIO " -A: Use the AIO system calls\n" #endif " -D startingop: debug output starting at specified operation\n" #ifdef FALLOCATE " -F: Do not use fallocate (preallocation) calls\n" #endif " -H: Do not use punch hole calls\n" " -C: Do not use clone calls\n" " -L: fsxLite - no file creations & no file size changes\n\ -N numops: total # operations to do (default infinity)\n\ -O: use oplen (see -o flag) for every op (default random)\n\ -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n\ -S seed: for random # generator (default 1) 0 gets timestamp\n\ -W: mapped write operations DISabled\n\ -R: read() system calls only (mapped reads disabled)\n\ -Z: O_DIRECT (use -R, -W, -r and -w too)\n\ poolname: this is REQUIRED (no default)\n\ imagename: this is REQUIRED (no default)\n"); exit(89); } int getnum(char *s, char **e) { int ret; *e = (char *) 0; ret = strtol(s, e, 0); if (*e) switch (**e) { case 'b': case 'B': ret *= 512; *e = *e + 1; break; case 'k': case 'K': ret *= 1024; *e = *e + 1; break; case 'm': case 'M': ret *= 1024*1024; *e = *e + 1; break; case 'w': case 'W': ret *= 4; *e = *e + 1; break; } return (ret); } #ifdef AIO #define QSZ 1024 io_context_t io_ctx; struct iocb iocb; int aio_setup() { int ret; ret = io_queue_init(QSZ, &io_ctx); if (ret != 0) { fprintf(stderr, "aio_setup: io_queue_init failed: %s\n", strerror(ret)); return(-1); } return(0); } int __aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset) { struct io_event event; static struct timespec ts; struct iocb *iocbs[] = { &iocb }; int ret; long res; if (rw == READ) { io_prep_pread(&iocb, fd, buf, len, offset); } else { io_prep_pwrite(&iocb, fd, buf, len, offset); } ts.tv_sec = 30; ts.tv_nsec = 0; ret = io_submit(io_ctx, 1, iocbs); if (ret != 1) { fprintf(stderr, "errcode=%d\n", ret); fprintf(stderr, "aio_rw: io_submit failed: %s\n", strerror(ret)); goto out_error; } ret = io_getevents(io_ctx, 1, 1, &event, &ts); if (ret != 1) { if (ret == 0) fprintf(stderr, "aio_rw: no events available\n"); else { fprintf(stderr, "errcode=%d\n", -ret); fprintf(stderr, "aio_rw: io_getevents failed: %s\n", strerror(-ret)); } goto out_error; } if (len != event.res) { /* * The b0rked libaio defines event.res as unsigned. * However the kernel strucuture has it signed, * and it's used to pass negated error value. * Till the library is fixed use the temp var. */ res = (long)event.res; if (res >= 0) fprintf(stderr, "bad io length: %lu instead of %u\n", res, len); else { fprintf(stderr, "errcode=%ld\n", -res); fprintf(stderr, "aio_rw: async io failed: %s\n", strerror(-res)); ret = res; goto out_error; } } return event.res; out_error: /* * The caller expects error return in traditional libc * convention, i.e. -1 and the errno set to error. */ errno = -ret; return -1; } int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset) { int ret; if (aio) { ret = __aio_rw(rw, fd, buf, len, offset); } else { if (rw == READ) ret = read(fd, buf, len); else ret = write(fd, buf, len); } return ret; } #endif void test_fallocate() { #ifdef FALLOCATE if (!lite && fallocate_calls) { if (fallocate(fd, 0, 0, 1) && errno == EOPNOTSUPP) { if(!quiet) warn("main: filesystem does not support fallocate, disabling\n"); fallocate_calls = 0; } else { ftruncate(fd, 0); } } #else /* ! FALLOCATE */ fallocate_calls = 0; #endif } int main(int argc, char **argv) { int i, style, ch, ret; char *endp; char goodfile[1024]; char logfile[1024]; goodfile[0] = 0; logfile[0] = 0; page_size = getpagesize(); page_mask = page_size - 1; mmap_mask = page_mask; setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ while ((ch = getopt(argc, argv, "b:c:dfl:m:no:p:qr:s:t:w:xyACD:FHLN:OP:RS:WZ")) != EOF) switch (ch) { case 'b': simulatedopcount = getnum(optarg, &endp); if (!quiet) fprintf(stdout, "Will begin at operation %ld\n", simulatedopcount); if (simulatedopcount == 0) usage(); simulatedopcount -= 1; break; case 'c': closeprob = getnum(optarg, &endp); if (!quiet) fprintf(stdout, "Chance of close/open is 1 in %d\n", closeprob); if (closeprob <= 0) usage(); break; case 'd': debug = 1; break; case 'f': flush = 1; break; case 'l': maxfilelen = getnum(optarg, &endp); if (maxfilelen <= 0) usage(); break; case 'm': monitorstart = getnum(optarg, &endp); if (monitorstart < 0) usage(); if (!endp || *endp++ != ':') usage(); monitorend = getnum(endp, &endp); if (monitorend < 0) usage(); if (monitorend == 0) monitorend = -1; /* aka infinity */ debug = 1; break; case 'n': sizechecks = 0; break; case 'o': maxoplen = getnum(optarg, &endp); if (maxoplen <= 0) usage(); break; case 'p': progressinterval = getnum(optarg, &endp); if (progressinterval == 0) usage(); break; case 'q': quiet = 1; break; case 'r': readbdy = getnum(optarg, &endp); if (readbdy <= 0) usage(); break; case 's': style = getnum(optarg, &endp); if (style < 0 || style > 1) usage(); break; case 't': truncbdy = getnum(optarg, &endp); if (truncbdy <= 0) usage(); break; case 'w': writebdy = getnum(optarg, &endp); if (writebdy <= 0) usage(); break; case 'x': prealloc = 1; break; case 'y': do_fsync = 1; break; case 'A': aio = 1; break; case 'C': clone_calls = 0; break; case 'D': debugstart = getnum(optarg, &endp); if (debugstart < 1) usage(); break; case 'F': fallocate_calls = 0; break; case 'H': punch_hole_calls = 0; break; case 'L': prt("lite mode not supported for rbd\n"); exit(1); break; case 'N': numops = getnum(optarg, &endp); if (numops < 0) usage(); break; case 'O': randomoplen = 0; break; case 'P': strncpy(dirpath, optarg, sizeof(dirpath)); strncpy(goodfile, dirpath, sizeof(goodfile)); strcat(goodfile, "/"); strncpy(logfile, dirpath, sizeof(logfile)); strcat(logfile, "/"); break; case 'R': mapped_reads = 0; break; case 'S': seed = getnum(optarg, &endp); if (seed == 0) seed = time(0) % 10000; if (!quiet) fprintf(stdout, "Seed set to %d\n", seed); if (seed < 0) usage(); break; case 'W': mapped_writes = 0; if (!quiet) fprintf(stdout, "mapped writes DISABLED\n"); break; case 'Z': o_direct = O_DIRECT; break; default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if (argc != 2) usage(); pool = argv[0]; iname = argv[1]; signal(SIGHUP, cleanup); signal(SIGINT, cleanup); signal(SIGPIPE, cleanup); signal(SIGALRM, cleanup); signal(SIGTERM, cleanup); signal(SIGXCPU, cleanup); signal(SIGXFSZ, cleanup); signal(SIGVTALRM, cleanup); signal(SIGUSR1, cleanup); signal(SIGUSR2, cleanup); initstate(seed, state, 256); setstate(state); ret = create_image(); if (ret < 0) { prterrcode(iname, ret); exit(90); } ret = rbd_open(ioctx, iname, &image, NULL); if (ret < 0) { simple_err("Error opening image", ret); exit(91); } if (!dirpath[0]) strcat(dirpath, "."); strncat(goodfile, iname, 256); strcat (goodfile, ".fsxgood"); fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666); if (fsxgoodfd < 0) { prterr(goodfile); exit(92); } strncat(logfile, iname, 256); strcat (logfile, ".fsxlog"); fsxlogf = fopen(logfile, "w"); if (fsxlogf == NULL) { prterr(logfile); exit(93); } #ifdef AIO if (aio) aio_setup(); #endif original_buf = (char *) malloc(maxfilelen); for (i = 0; i < (int)maxfilelen; i++) original_buf[i] = random() % 256; good_buf = (char *) malloc(maxfilelen + writebdy); good_buf = round_ptr_up(good_buf, writebdy, 0); memset(good_buf, '\0', maxfilelen); temp_buf = (char *) malloc(maxfilelen + writebdy); temp_buf = round_ptr_up(temp_buf, writebdy, 0); memset(temp_buf, '\0', maxfilelen); if (lite) { /* zero entire existing file */ ssize_t written; written = rbd_write(image, 0, (size_t)maxfilelen, good_buf); if (written != (ssize_t)maxfilelen) { if (written < 0) { prterrcode(iname, written); warn("main: error on write"); } else warn("main: short write, 0x%x bytes instead " "of 0x%lx\n", (unsigned)written, maxfilelen); exit(98); } } else check_trunc_hack(); //test_fallocate(); while (numops == -1 || numops--) test(); if ((ret = rbd_close(image)) < 0) { prterrcode("rbd_close", ret); report_failure(99); } if (num_clones > 0) check_clone(num_clones - 1); while (num_clones >= 0) { static int first = 1; char clonename[128]; char errmsg[128]; clone_imagename(clonename, 128, num_clones); if ((ret = rbd_open(ioctx, clonename, &image, NULL)) < 0) { sprintf(errmsg, "rbd_open %s", clonename); prterrcode(errmsg, ret); report_failure(101); } if (!first) { if ((ret = rbd_snap_unprotect(image, "snap")) < 0) { sprintf(errmsg, "rbd_snap_unprotect %s@snap", clonename); prterrcode(errmsg, ret); report_failure(102); } if ((ret = rbd_snap_remove(image, "snap")) < 0) { sprintf(errmsg, "rbd_snap_remove %s@snap", clonename); prterrcode(errmsg, ret); report_failure(103); } } if ((ret = rbd_close(image)) < 0) { sprintf(errmsg, "rbd_close %s", clonename); prterrcode(errmsg, ret); report_failure(104); } if ((ret = rbd_remove(ioctx, clonename)) < 0) { sprintf(errmsg, "rbd_remove %s", clonename); prterrcode(errmsg, ret); report_failure(105); } first = 0; num_clones--; } rados_ioctx_destroy(ioctx); rados_shutdown(cluster); free(original_buf); free(good_buf); free(temp_buf); prt("All operations completed A-OK!\n"); fclose(fsxlogf); exit(0); return 0; } ceph-0.80.11/src/test/librbd/test_librbd.cc0000664000175100017510000017171212623076744022516 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "include/rados/librados.h" #include "include/rbd_types.h" #include "include/rbd/librbd.h" #include "include/rbd/librbd.hpp" #include "global/global_context.h" #include "global/global_init.h" #include "common/ceph_argparse.h" #include "common/config.h" #include "gtest/gtest.h" #include #include #include #include #include #include #include #include #include #include #include "test/librados/test.h" #include "common/errno.h" #include "include/interval_set.h" #include "include/stringify.h" #include using namespace std; static int get_features(bool *old_format, uint64_t *features) { const char *c = getenv("RBD_FEATURES"); if (c) { stringstream ss; ss << c; ss >> *features; if (ss.fail()) return -EINVAL; *old_format = false; cout << "using new format!" << std::endl; } else { *old_format = true; cout << "using old format" << std::endl; } return 0; } static int create_image_full(rados_ioctx_t ioctx, const char *name, uint64_t size, int *order, int old_format, uint64_t features) { if (old_format) { return rbd_create(ioctx, name, size, order); } else if ((features & RBD_FEATURE_STRIPINGV2) != 0) { return rbd_create3(ioctx, name, size, features, order, 65536, 16); } else { return rbd_create2(ioctx, name, size, features, order); } } static int create_image(rados_ioctx_t ioctx, const char *name, uint64_t size, int *order) { bool old_format; uint64_t features; int r = get_features(&old_format, &features); if (r < 0) return r; return create_image_full(ioctx, name, size, order, old_format, features); } static int create_image_pp(librbd::RBD &rbd, librados::IoCtx &ioctx, const char *name, uint64_t size, int *order) { bool old_format; uint64_t features; int r = get_features(&old_format, &features); if (r < 0) return r; if (old_format) { return rbd.create(ioctx, name, size, order); } else { return rbd.create2(ioctx, name, size, features, order); } } TEST(LibRBD, CreateAndStat) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx)); rbd_image_info_t info; rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order); ASSERT_EQ(info.size, size); ASSERT_EQ(info.order, order); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, CreateAndStatPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::image_info_t info; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); ASSERT_EQ(0, image.stat(info, sizeof(info))); ASSERT_EQ(info.size, size); ASSERT_EQ(info.order, order); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(LibRBD, ResizeAndStat) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_info_t info; rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); ASSERT_EQ(0, rbd_resize(image, size * 4)); ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); ASSERT_EQ(info.size, size * 4); ASSERT_EQ(0, rbd_resize(image, size / 2)); ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); ASSERT_EQ(info.size, size / 2); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, ResizeAndStatPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::image_info_t info; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); ASSERT_EQ(0, image.resize(size * 4)); ASSERT_EQ(0, image.stat(info, sizeof(info))); ASSERT_EQ(info.size, size * 4); ASSERT_EQ(0, image.resize(size / 2)); ASSERT_EQ(0, image.stat(info, sizeof(info))); ASSERT_EQ(info.size, size / 2); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } int test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...) { int num_images, i, j; char *names, *cur_name; va_list ap; size_t max_size = 1024; names = (char *) malloc(sizeof(char *) * 1024); int len = rbd_list(io_ctx, names, &max_size); for (i = 0, num_images = 0, cur_name = names; cur_name < names + len; i++) { printf("image: %s\n", cur_name); cur_name += strlen(cur_name) + 1; num_images++; } va_start(ap, num_expected); for (i = num_expected; i > 0; i--) { char *expected = va_arg(ap, char *); printf("expected = %s\n", expected); int found = 0; for (j = 0, cur_name = names; j < num_images; j++) { if (cur_name[0] == '_') { cur_name += strlen(cur_name) + 1; continue; } if (strcmp(cur_name, expected) == 0) { printf("found %s\n", cur_name); cur_name[0] = '_'; found = 1; break; } } assert(found); } va_end(ap); for (i = 0, cur_name = names; cur_name < names + len; i++) { assert(cur_name[0] == '_'); cur_name += strlen(cur_name) + 1; } free(names); return num_images; } TEST(LibRBD, TestCreateLsDelete) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); int order = 0; const char *name = "testimg"; const char *name2 = "testimg2"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(1, test_ls(ioctx, 1, name)); ASSERT_EQ(0, create_image(ioctx, name2, size, &order)); ASSERT_EQ(2, test_ls(ioctx, 2, name, name2)); ASSERT_EQ(0, rbd_remove(ioctx, name)); ASSERT_EQ(1, test_ls(ioctx, 1, name2)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } int test_ls_pp(librbd::RBD& rbd, librados::IoCtx& io_ctx, size_t num_expected, ...) { int r; size_t i; va_list ap; vector names; r = rbd.list(io_ctx, names); if (r == -ENOENT) r = 0; assert(r >= 0); cout << "num images is: " << names.size() << endl << "expected: " << num_expected << endl; int num = names.size(); for (i = 0; i < names.size(); i++) { cout << "image: " << names[i] << endl; } va_start(ap, num_expected); for (i = num_expected; i > 0; i--) { char *expected = va_arg(ap, char *); cout << "expected = " << expected << endl; vector::iterator listed_name = find(names.begin(), names.end(), string(expected)); assert(listed_name != names.end()); names.erase(listed_name); } va_end(ap); assert(names.empty()); return num; } TEST(LibRBD, TestCreateLsDeletePP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; const char *name2 = "testimg2"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name)); ASSERT_EQ(0, rbd.create(ioctx, name2, size, &order)); ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name, name2)); ASSERT_EQ(0, rbd.remove(ioctx, name)); ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name2)); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } static int print_progress_percent(uint64_t offset, uint64_t src_size, void *data) { float percent = ((float)offset * 100) / src_size; printf("%3.2f%% done\n", percent); return 0; } TEST(LibRBD, TestCopy) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; const char *name2 = "testimg2"; const char *name3 = "testimg3"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); ASSERT_EQ(1, test_ls(ioctx, 1, name)); ASSERT_EQ(0, rbd_copy(image, ioctx, name2)); ASSERT_EQ(2, test_ls(ioctx, 2, name, name2)); ASSERT_EQ(0, rbd_copy_with_progress(image, ioctx, name3, print_progress_percent, NULL)); ASSERT_EQ(3, test_ls(ioctx, 3, name, name2, name3)); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } class PrintProgress : public librbd::ProgressContext { public: int update_progress(uint64_t offset, uint64_t src_size) { float percent = ((float)offset * 100) / src_size; printf("%3.2f%% done\n", percent); return 0; } }; TEST(LibRBD, TestCopyPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; const char *name2 = "testimg2"; const char *name3 = "testimg3"; uint64_t size = 2 << 20; PrintProgress pp; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); ASSERT_EQ(1, test_ls_pp(rbd, ioctx, 1, name)); ASSERT_EQ(0, image.copy(ioctx, name2)); ASSERT_EQ(2, test_ls_pp(rbd, ioctx, 2, name, name2)); ASSERT_EQ(0, image.copy_with_progress(ioctx, name3, pp)); ASSERT_EQ(3, test_ls_pp(rbd, ioctx, 3, name, name2, name3)); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } int test_ls_snaps(rbd_image_t image, int num_expected, ...) { int num_snaps, i, j, max_size = 10; va_list ap; rbd_snap_info_t snaps[max_size]; num_snaps = rbd_snap_list(image, snaps, &max_size); printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected); for (i = 0; i < num_snaps; i++) { printf("snap: %s\n", snaps[i].name); } va_start(ap, num_expected); for (i = num_expected; i > 0; i--) { char *expected = va_arg(ap, char *); uint64_t expected_size = va_arg(ap, uint64_t); int found = 0; for (j = 0; j < num_snaps; j++) { if (snaps[j].name == NULL) continue; if (strcmp(snaps[j].name, expected) == 0) { printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size); assert(snaps[j].size == expected_size); free((void *) snaps[j].name); snaps[j].name = NULL; found = 1; break; } } assert(found); } va_end(ap); for (i = 0; i < num_snaps; i++) { assert(snaps[i].name == NULL); } return num_snaps; } TEST(LibRBD, TestCreateLsDeleteSnap) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; uint64_t size2 = 4 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); ASSERT_EQ(0, rbd_snap_create(image, "snap1")); ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size)); ASSERT_EQ(0, rbd_resize(image, size2)); ASSERT_EQ(0, rbd_snap_create(image, "snap2")); ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2)); ASSERT_EQ(0, rbd_snap_remove(image, "snap1")); ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2)); ASSERT_EQ(0, rbd_snap_remove(image, "snap2")); ASSERT_EQ(0, test_ls_snaps(image, 0)); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } int test_ls_snaps(librbd::Image& image, size_t num_expected, ...) { int r; size_t i, j; va_list ap; vector snaps; r = image.snap_list(snaps); assert(r >= 0); cout << "num snaps is: " << snaps.size() << endl << "expected: " << num_expected << endl; for (i = 0; i < snaps.size(); i++) { cout << "snap: " << snaps[i].name << endl; } va_start(ap, num_expected); for (i = num_expected; i > 0; i--) { char *expected = va_arg(ap, char *); uint64_t expected_size = va_arg(ap, uint64_t); int found = 0; for (j = 0; j < snaps.size(); j++) { if (snaps[j].name == "") continue; if (strcmp(snaps[j].name.c_str(), expected) == 0) { cout << "found " << snaps[j].name << " with size " << snaps[j].size << endl; assert(snaps[j].size == expected_size); snaps[j].name = ""; found = 1; break; } } assert(found); } va_end(ap); for (i = 0; i < snaps.size(); i++) { assert(snaps[i].name == ""); } return snaps.size(); } TEST(LibRBD, TestCreateLsDeleteSnapPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; uint64_t size2 = 4 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); ASSERT_FALSE(image.snap_exists("snap1")); ASSERT_EQ(0, image.snap_create("snap1")); ASSERT_TRUE(image.snap_exists("snap1")); ASSERT_EQ(1, test_ls_snaps(image, 1, "snap1", size)); ASSERT_EQ(0, image.resize(size2)); ASSERT_FALSE(image.snap_exists("snap2")); ASSERT_EQ(0, image.snap_create("snap2")); ASSERT_TRUE(image.snap_exists("snap2")); ASSERT_EQ(2, test_ls_snaps(image, 2, "snap1", size, "snap2", size2)); ASSERT_EQ(0, image.snap_remove("snap1")); ASSERT_FALSE(image.snap_exists("snap1")); ASSERT_EQ(1, test_ls_snaps(image, 1, "snap2", size2)); ASSERT_EQ(0, image.snap_remove("snap2")); ASSERT_FALSE(image.snap_exists("snap2")); ASSERT_EQ(0, test_ls_snaps(image, 0)); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } #define TEST_IO_SIZE 512 #define TEST_IO_TO_SNAP_SIZE 80 void simple_write_cb(rbd_completion_t cb, void *arg) { printf("write completion cb called!\n"); } void simple_read_cb(rbd_completion_t cb, void *arg) { printf("read completion cb called!\n"); } void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len) { rbd_completion_t comp; rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp); printf("created completion\n"); rbd_aio_write(image, off, len, test_data, comp); printf("started write\n"); rbd_aio_wait_for_complete(comp); int r = rbd_aio_get_return_value(comp); printf("return value is: %d\n", r); assert(r == 0); printf("finished write\n"); rbd_aio_release(comp); } void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len) { ssize_t written; written = rbd_write(image, off, len, test_data); printf("wrote: %d\n", (int) written); assert(written == (ssize_t)len); } void aio_discard_test_data(rbd_image_t image, uint64_t off, uint64_t len) { rbd_completion_t comp; rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp); rbd_aio_discard(image, off, len, comp); rbd_aio_wait_for_complete(comp); int r = rbd_aio_get_return_value(comp); assert(r == 0); printf("aio discard: %d~%d = %d\n", (int)off, (int)len, (int)r); rbd_aio_release(comp); } void discard_test_data(rbd_image_t image, uint64_t off, size_t len) { ssize_t written; written = rbd_discard(image, off, len); printf("discard: %d~%d = %d\n", (int)off, (int)len, (int)written); assert(written == (ssize_t)len); } void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len) { rbd_completion_t comp; char *result = (char *)malloc(len + 1); assert(result); rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp); printf("created completion\n"); rbd_aio_read(image, off, len, result, comp); printf("started read\n"); rbd_aio_wait_for_complete(comp); int r = rbd_aio_get_return_value(comp); printf("return value is: %d\n", r); assert(r == (ssize_t)len); rbd_aio_release(comp); if (memcmp(result, expected, len)) { printf("read: %s\nexpected: %s\n", result, expected); assert(memcmp(result, expected, len) == 0); } free(result); } void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len) { ssize_t read; char *result = (char *)malloc(len + 1); assert(result); read = rbd_read(image, off, len, result); printf("read: %d\n", (int) read); assert(read == (ssize_t)len); result[len] = '\0'; if (memcmp(result, expected, len)) { printf("read: %s\nexpected: %s\n", result, expected); assert(memcmp(result, expected, len) == 0); } free(result); } TEST(LibRBD, TestIO) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); char test_data[TEST_IO_SIZE + 1]; char zero_data[TEST_IO_SIZE + 1]; int i; for (i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } test_data[TEST_IO_SIZE] = '\0'; memset(zero_data, 0, sizeof(zero_data)); for (i = 0; i < 5; ++i) write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); for (i = 5; i < 10; ++i) aio_write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); for (i = 0; i < 5; ++i) read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); for (i = 5; i < 10; ++i) aio_read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); // discard 2nd, 4th sections. discard_test_data(image, TEST_IO_SIZE, TEST_IO_SIZE); aio_discard_test_data(image, TEST_IO_SIZE*3, TEST_IO_SIZE); read_test_data(image, test_data, 0, TEST_IO_SIZE); read_test_data(image, zero_data, TEST_IO_SIZE, TEST_IO_SIZE); read_test_data(image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE); read_test_data(image, zero_data, TEST_IO_SIZE*3, TEST_IO_SIZE); read_test_data(image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE); rbd_image_info_t info; rbd_completion_t comp; ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); // can't read or write starting past end ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data)); ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data)); // reading through end returns amount up to end ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data)); // writing through end returns amount up to end ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data)); rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp); ASSERT_EQ(0, rbd_aio_write(image, info.size, 1, test_data, comp)); ASSERT_EQ(0, rbd_aio_wait_for_complete(comp)); ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp)); rbd_aio_release(comp); rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp); ASSERT_EQ(0, rbd_aio_read(image, info.size, 1, test_data, comp)); ASSERT_EQ(0, rbd_aio_wait_for_complete(comp)); ASSERT_EQ(-EINVAL, rbd_aio_get_return_value(comp)); rbd_aio_release(comp); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, TestEmptyDiscard) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 20 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); aio_discard_test_data(image, 0, 1*1024*1024); aio_discard_test_data(image, 0, 4*1024*1024); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } void simple_write_cb_pp(librbd::completion_t cb, void *arg) { cout << "write completion cb called!" << endl; } void simple_read_cb_pp(librbd::completion_t cb, void *arg) { cout << "read completion cb called!" << endl; } void aio_write_test_data(librbd::Image& image, const char *test_data, off_t off) { ceph::bufferlist bl; bl.append(test_data, strlen(test_data)); librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp); printf("created completion\n"); image.aio_write(off, strlen(test_data), bl, comp); printf("started write\n"); comp->wait_for_complete(); int r = comp->get_return_value(); printf("return value is: %d\n", r); assert(r >= 0); printf("finished write\n"); comp->release(); } void aio_discard_test_data(librbd::Image& image, off_t off, size_t len) { librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_write_cb_pp); image.aio_discard(off, len, comp); comp->wait_for_complete(); int r = comp->get_return_value(); assert(r >= 0); comp->release(); } void write_test_data(librbd::Image& image, const char *test_data, off_t off) { size_t written; size_t len = strlen(test_data); ceph::bufferlist bl; bl.append(test_data, len); written = image.write(off, len, bl); printf("wrote: %u\n", (unsigned int) written); assert(written == bl.length()); } void discard_test_data(librbd::Image& image, off_t off, size_t len) { size_t written; written = image.discard(off, len); printf("discard: %u~%u\n", (unsigned)off, (unsigned)len); assert(written == len); } void aio_read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len) { librbd::RBD::AioCompletion *comp = new librbd::RBD::AioCompletion(NULL, (librbd::callback_t) simple_read_cb_pp); ceph::bufferlist bl; printf("created completion\n"); image.aio_read(off, expected_len, bl, comp); printf("started read\n"); comp->wait_for_complete(); int r = comp->get_return_value(); printf("return value is: %d\n", r); assert(r == TEST_IO_SIZE); assert(strncmp(expected, bl.c_str(), TEST_IO_SIZE) == 0); printf("finished read\n"); comp->release(); } void read_test_data(librbd::Image& image, const char *expected, off_t off, size_t expected_len) { int read, total_read = 0; size_t len = expected_len; ceph::bufferlist bl; read = image.read(off + total_read, len, bl); assert(read >= 0); printf("read: %u\n", (unsigned int) read); printf("read: %s\nexpected: %s\n", bl.c_str(), expected); assert(strncmp(bl.c_str(), expected, expected_len) == 0); } TEST(LibRBD, TestIOPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); char test_data[TEST_IO_SIZE + 1]; char zero_data[TEST_IO_SIZE + 1]; int i; srand(time(0)); for (i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } test_data[TEST_IO_SIZE] = '\0'; memset(zero_data, 0, sizeof(zero_data)); for (i = 0; i < 5; ++i) write_test_data(image, test_data, strlen(test_data) * i); for (i = 5; i < 10; ++i) aio_write_test_data(image, test_data, strlen(test_data) * i); for (i = 0; i < 5; ++i) read_test_data(image, test_data, strlen(test_data) * i, TEST_IO_SIZE); for (i = 5; i < 10; ++i) aio_read_test_data(image, test_data, strlen(test_data) * i, TEST_IO_SIZE); // discard 2nd, 4th sections. discard_test_data(image, TEST_IO_SIZE, TEST_IO_SIZE); aio_discard_test_data(image, TEST_IO_SIZE*3, TEST_IO_SIZE); read_test_data(image, test_data, 0, TEST_IO_SIZE); read_test_data(image, zero_data, TEST_IO_SIZE, TEST_IO_SIZE); read_test_data(image, test_data, TEST_IO_SIZE*2, TEST_IO_SIZE); read_test_data(image, zero_data, TEST_IO_SIZE*3, TEST_IO_SIZE); read_test_data(image, test_data, TEST_IO_SIZE*4, TEST_IO_SIZE); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(LibRBD, TestIOToSnapshot) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t isize = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, isize, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); int i, r; rbd_image_t image_at_snap; char orig_data[TEST_IO_TO_SNAP_SIZE + 1]; char test_data[TEST_IO_TO_SNAP_SIZE + 1]; for (i = 0; i < TEST_IO_TO_SNAP_SIZE; ++i) test_data[i] = (char) (i + 48); test_data[TEST_IO_TO_SNAP_SIZE] = '\0'; orig_data[TEST_IO_TO_SNAP_SIZE] = '\0'; r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data); ASSERT_EQ(r, TEST_IO_TO_SNAP_SIZE); ASSERT_EQ(0, test_ls_snaps(image, 0)); ASSERT_EQ(0, rbd_snap_create(image, "orig")); ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize)); read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE); printf("write test data!\n"); write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE); ASSERT_EQ(0, rbd_snap_create(image, "written")); ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize)); read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE); rbd_snap_set(image, "orig"); read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE); rbd_snap_set(image, "written"); read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE); rbd_snap_set(image, "orig"); r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data); printf("write to snapshot returned %d\n", r); ASSERT_LT(r, 0); cout << cpp_strerror(-r) << std::endl; read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE); rbd_snap_set(image, "written"); read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE); r = rbd_snap_rollback(image, "orig"); ASSERT_EQ(r, -EROFS); r = rbd_snap_set(image, NULL); ASSERT_EQ(r, 0); r = rbd_snap_rollback(image, "orig"); ASSERT_EQ(r, 0); write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE); rbd_flush(image); printf("opening testimg@orig\n"); ASSERT_EQ(0, rbd_open(ioctx, name, &image_at_snap, "orig")); read_test_data(image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE); r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data); printf("write to snapshot returned %d\n", r); ASSERT_LT(r, 0); cout << cpp_strerror(-r) << std::endl; ASSERT_EQ(0, rbd_close(image_at_snap)); ASSERT_EQ(2, test_ls_snaps(image, 2, "orig", isize, "written", isize)); ASSERT_EQ(0, rbd_snap_remove(image, "written")); ASSERT_EQ(1, test_ls_snaps(image, 1, "orig", isize)); ASSERT_EQ(0, rbd_snap_remove(image, "orig")); ASSERT_EQ(0, test_ls_snaps(image, 0)); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, TestClone) { rados_t cluster; rados_ioctx_t ioctx; rbd_image_info_t pinfo, cinfo; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); int features = RBD_FEATURE_LAYERING; rbd_image_t parent, child; int order = 0; // make a parent to clone from ASSERT_EQ(0, create_image_full(ioctx, "parent", 4<<20, &order, false, features)); ASSERT_EQ(0, rbd_open(ioctx, "parent", &parent, NULL)); printf("made parent image \"parent\"\n"); char *data = (char *)"testdata"; ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data)); // can't clone a non-snapshot, expect failure EXPECT_NE(0, rbd_clone(ioctx, "parent", NULL, ioctx, "child", features, &order)); // verify that there is no parent info on "parent" char ppool[1], pname[1], psnapname[1]; ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, ppool, sizeof(ppool), pname, sizeof(pname), psnapname, sizeof(psnapname))); printf("parent has no parent info\n"); // create a snapshot, reopen as the parent we're interested in ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap")); printf("made snapshot \"parent@parent_snap\"\n"); ASSERT_EQ(0, rbd_close(parent)); ASSERT_EQ(0, rbd_open(ioctx, "parent", &parent, "parent_snap")); ASSERT_EQ(-EINVAL, rbd_clone(ioctx, "parent", "parent_snap", ioctx, "child", features, &order)); // unprotected image should fail unprotect ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap")); printf("can't unprotect an unprotected snap\n"); ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap")); // protecting again should fail ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap")); printf("can't protect a protected snap\n"); // This clone and open should work ASSERT_EQ(0, rbd_clone(ioctx, "parent", "parent_snap", ioctx, "child", features, &order)); ASSERT_EQ(0, rbd_open(ioctx, "child", &child, NULL)); printf("made and opened clone \"child\"\n"); // check read read_test_data(child, data, 0, strlen(data)); // check write ASSERT_EQ((ssize_t)strlen(data), rbd_write(child, 20, strlen(data), data)); read_test_data(child, data, 20, strlen(data)); read_test_data(child, data, 0, strlen(data)); // check attributes ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo))); ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo))); EXPECT_EQ(cinfo.size, pinfo.size); uint64_t overlap; rbd_get_overlap(child, &overlap); EXPECT_EQ(overlap, pinfo.size); EXPECT_EQ(cinfo.obj_size, pinfo.obj_size); EXPECT_EQ(cinfo.order, pinfo.order); printf("sizes and overlaps are good between parent and child\n"); // sizing down child results in changing overlap and size, not parent size ASSERT_EQ(0, rbd_resize(child, 2UL<<20)); ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo))); rbd_get_overlap(child, &overlap); ASSERT_EQ(overlap, 2UL<<20); ASSERT_EQ(cinfo.size, 2UL<<20); ASSERT_EQ(0, rbd_resize(child, 4UL<<20)); ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo))); rbd_get_overlap(child, &overlap); ASSERT_EQ(overlap, 2UL<<20); ASSERT_EQ(cinfo.size, 4UL<<20); printf("sized down clone, changed overlap\n"); // sizing back up doesn't change that ASSERT_EQ(0, rbd_resize(child, 5UL<<20)); ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo))); rbd_get_overlap(child, &overlap); ASSERT_EQ(overlap, 2UL<<20); ASSERT_EQ(cinfo.size, 5UL<<20); ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo))); printf("parent info: size %lld obj_size %lld parent_pool %lld\n", (unsigned long long)pinfo.size, (unsigned long long)pinfo.obj_size, (unsigned long long)pinfo.parent_pool); ASSERT_EQ(pinfo.size, 4UL<<20); printf("sized up clone, changed size but not overlap or parent's size\n"); ASSERT_EQ(0, rbd_close(child)); ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap")); printf("can't remove parent while child still exists\n"); ASSERT_EQ(0, rbd_remove(ioctx, "child")); ASSERT_EQ(-EBUSY, rbd_snap_remove(parent, "parent_snap")); printf("can't remove parent while still protected\n"); ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap")); ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap")); printf("removed parent snap after unprotecting\n"); ASSERT_EQ(0, rbd_close(parent)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, TestClone2) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); int features = RBD_FEATURE_LAYERING; rbd_image_t parent, child; int order = 0; // make a parent to clone from ASSERT_EQ(0, create_image_full(ioctx, "parent", 4<<20, &order, false, features)); ASSERT_EQ(0, rbd_open(ioctx, "parent", &parent, NULL)); printf("made parent image \"parent\"\n"); char *data = (char *)"testdata"; char *childata = (char *)"childata"; ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 0, strlen(data), data)); ASSERT_EQ((ssize_t)strlen(data), rbd_write(parent, 12, strlen(data), data)); // can't clone a non-snapshot, expect failure EXPECT_NE(0, rbd_clone(ioctx, "parent", NULL, ioctx, "child", features, &order)); // verify that there is no parent info on "parent" char ppool[1], pname[1], psnapname[1]; ASSERT_EQ(-ENOENT, rbd_get_parent_info(parent, ppool, sizeof(ppool), pname, sizeof(pname), psnapname, sizeof(psnapname))); printf("parent has no parent info\n"); // create a snapshot, reopen as the parent we're interested in ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap")); printf("made snapshot \"parent@parent_snap\"\n"); ASSERT_EQ(0, rbd_close(parent)); ASSERT_EQ(0, rbd_open(ioctx, "parent", &parent, "parent_snap")); ASSERT_EQ(-EINVAL, rbd_clone(ioctx, "parent", "parent_snap", ioctx, "child", features, &order)); // unprotected image should fail unprotect ASSERT_EQ(-EINVAL, rbd_snap_unprotect(parent, "parent_snap")); printf("can't unprotect an unprotected snap\n"); ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap")); // protecting again should fail ASSERT_EQ(-EBUSY, rbd_snap_protect(parent, "parent_snap")); printf("can't protect a protected snap\n"); // This clone and open should work ASSERT_EQ(0, rbd_clone(ioctx, "parent", "parent_snap", ioctx, "child", features, &order)); ASSERT_EQ(0, rbd_open(ioctx, "child", &child, NULL)); printf("made and opened clone \"child\"\n"); // write something in ASSERT_EQ((ssize_t)strlen(childata), rbd_write(child, 20, strlen(childata), childata)); char test[strlen(data) * 2]; ASSERT_EQ((ssize_t)strlen(data), rbd_read(child, 20, strlen(data), test)); ASSERT_EQ(0, memcmp(test, childata, strlen(childata))); // overlap ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 20 - strlen(data), sizeof(test), test)); ASSERT_EQ(0, memcmp(test, data, strlen(data))); ASSERT_EQ(0, memcmp(test + strlen(data), childata, strlen(childata))); // all parent ASSERT_EQ((ssize_t)sizeof(test), rbd_read(child, 0, sizeof(test), test)); ASSERT_EQ(0, memcmp(test, data, strlen(data))); ASSERT_EQ(0, rbd_close(child)); ASSERT_EQ(0, rbd_close(parent)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } static void test_list_children(rbd_image_t image, ssize_t num_expected, ...) { va_list ap; va_start(ap, num_expected); size_t pools_len = 100; size_t children_len = 100; char *pools = NULL; char *children = NULL; ssize_t num_children; do { free(pools); free(children); pools = (char *) malloc(pools_len); children = (char *) malloc(children_len); num_children = rbd_list_children(image, pools, &pools_len, children, &children_len); } while (num_children == -ERANGE); ASSERT_EQ(num_expected, num_children); for (ssize_t i = num_expected; i > 0; --i) { char *expected_pool = va_arg(ap, char *); char *expected_image = va_arg(ap, char *); char *pool = pools; char *image = children; bool found = 0; printf("\ntrying to find %s/%s\n", expected_pool, expected_image); for (ssize_t j = 0; j < num_children; ++j) { printf("checking %s/%s\n", pool, image); if (strcmp(expected_pool, pool) == 0 && strcmp(expected_image, image) == 0) { printf("found child %s/%s\n\n", pool, image); found = 1; break; } pool += strlen(pool) + 1; image += strlen(image) + 1; if (j == num_children - 1) { ASSERT_EQ(pool - pools - 1, (ssize_t) pools_len); ASSERT_EQ(image - children - 1, (ssize_t) children_len); } } ASSERT_TRUE(found); } va_end(ap); if (pools) free(pools); if (children) free(children); } TEST(LibRBD, ListChildren) { rados_t cluster; rados_ioctx_t ioctx1, ioctx2; string pool_name1 = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name1, &cluster)); string pool_name2 = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name2, &cluster)); rados_ioctx_create(cluster, pool_name1.c_str(), &ioctx1); rados_ioctx_create(cluster, pool_name2.c_str(), &ioctx2); int features = RBD_FEATURE_LAYERING; rbd_image_t parent; int order = 0; // make a parent to clone from ASSERT_EQ(0, create_image_full(ioctx1, "parent", 4<<20, &order, false, features)); ASSERT_EQ(0, rbd_open(ioctx1, "parent", &parent, NULL)); // create a snapshot, reopen as the parent we're interested in ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap")); ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap")); ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap")); ASSERT_EQ(0, rbd_close(parent)); ASSERT_EQ(0, rbd_open(ioctx1, "parent", &parent, "parent_snap")); ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx2, "child1", features, &order)); test_list_children(parent, 1, pool_name2.c_str(), "child1"); ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx1, "child2", features, &order)); test_list_children(parent, 2, pool_name2.c_str(), "child1", pool_name1.c_str(), "child2"); ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx2, "child3", features, &order)); test_list_children(parent, 3, pool_name2.c_str(), "child1", pool_name1.c_str(), "child2", pool_name2.c_str(), "child3"); ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx2, "child4", features, &order)); test_list_children(parent, 4, pool_name2.c_str(), "child1", pool_name1.c_str(), "child2", pool_name2.c_str(), "child3", pool_name2.c_str(), "child4"); ASSERT_EQ(0, rbd_remove(ioctx2, "child1")); test_list_children(parent, 3, pool_name1.c_str(), "child2", pool_name2.c_str(), "child3", pool_name2.c_str(), "child4"); ASSERT_EQ(0, rbd_remove(ioctx2, "child3")); test_list_children(parent, 2, pool_name1.c_str(), "child2", pool_name2.c_str(), "child4"); ASSERT_EQ(0, rbd_remove(ioctx2, "child4")); test_list_children(parent, 1, pool_name1.c_str(), "child2"); ASSERT_EQ(0, rbd_remove(ioctx1, "child2")); test_list_children(parent, 0); ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap")); ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap")); ASSERT_EQ(0, rbd_close(parent)); ASSERT_EQ(0, rbd_remove(ioctx1, "parent")); rados_ioctx_destroy(ioctx1); rados_ioctx_destroy(ioctx2); // destroy_one_pool also closes the cluster; do this one step at a time ASSERT_EQ(0, rados_pool_delete(cluster, pool_name1.c_str())); ASSERT_EQ(0, destroy_one_pool(pool_name2, &cluster)); } TEST(LibRBD, LockingPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; std::string cookie1 = "foo"; std::string cookie2 = "bar"; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); // no lockers initially std::list lockers; std::string tag; bool exclusive; ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag)); ASSERT_EQ(0u, lockers.size()); ASSERT_EQ("", tag); // exclusive lock is exclusive ASSERT_EQ(0, image.lock_exclusive(cookie1)); ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1)); ASSERT_EQ(-EBUSY, image.lock_exclusive("")); ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, "")); ASSERT_EQ(-EBUSY, image.lock_shared(cookie1, "test")); ASSERT_EQ(-EBUSY, image.lock_shared("", "test")); ASSERT_EQ(-EBUSY, image.lock_shared("", "")); // list exclusive ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag)); ASSERT_TRUE(exclusive); ASSERT_EQ("", tag); ASSERT_EQ(1u, lockers.size()); ASSERT_EQ(cookie1, lockers.front().cookie); // unlock ASSERT_EQ(-ENOENT, image.unlock("")); ASSERT_EQ(-ENOENT, image.unlock(cookie2)); ASSERT_EQ(0, image.unlock(cookie1)); ASSERT_EQ(-ENOENT, image.unlock(cookie1)); ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag)); ASSERT_EQ(0u, lockers.size()); ASSERT_EQ(0, image.lock_shared(cookie1, "")); ASSERT_EQ(-EEXIST, image.lock_shared(cookie1, "")); ASSERT_EQ(0, image.lock_shared(cookie2, "")); ASSERT_EQ(-EEXIST, image.lock_shared(cookie2, "")); ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie1)); ASSERT_EQ(-EEXIST, image.lock_exclusive(cookie2)); ASSERT_EQ(-EBUSY, image.lock_exclusive("")); ASSERT_EQ(-EBUSY, image.lock_exclusive("test")); // list shared ASSERT_EQ(0, image.list_lockers(&lockers, &exclusive, &tag)); ASSERT_EQ(2u, lockers.size()); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(LibRBD, FlushAio) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; size_t num_aios = 256; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); char test_data[TEST_IO_SIZE + 1]; size_t i; for (i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } rbd_completion_t write_comps[num_aios]; for (i = 0; i < num_aios; ++i) { ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &write_comps[i])); uint64_t offset = rand() % (size - TEST_IO_SIZE); ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data, write_comps[i])); } rbd_completion_t flush_comp; ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &flush_comp)); ASSERT_EQ(0, rbd_aio_flush(image, flush_comp)); ASSERT_EQ(0, rbd_aio_wait_for_complete(flush_comp)); ASSERT_EQ(1, rbd_aio_is_complete(flush_comp)); rbd_aio_release(flush_comp); for (i = 0; i < num_aios; ++i) { ASSERT_EQ(1, rbd_aio_is_complete(write_comps[i])); rbd_aio_release(write_comps[i]); } ASSERT_EQ(0, rbd_close(image)); ASSERT_EQ(0, rbd_remove(ioctx, name)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, FlushAioPP) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; size_t num_aios = 256; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); char test_data[TEST_IO_SIZE + 1]; size_t i; for (i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } librbd::RBD::AioCompletion *write_comps[num_aios]; for (i = 0; i < num_aios; ++i) { ceph::bufferlist bl; bl.append(test_data, strlen(test_data)); write_comps[i] = new librbd::RBD::AioCompletion(NULL, NULL); uint64_t offset = rand() % (size - TEST_IO_SIZE); ASSERT_EQ(0, image.aio_write(offset, TEST_IO_SIZE, bl, write_comps[i])); } librbd::RBD::AioCompletion *flush_comp = new librbd::RBD::AioCompletion(NULL, NULL); ASSERT_EQ(0, image.aio_flush(flush_comp)); ASSERT_EQ(0, flush_comp->wait_for_complete()); ASSERT_EQ(1, flush_comp->is_complete()); delete flush_comp; for (i = 0; i < num_aios; ++i) { librbd::RBD::AioCompletion *comp = write_comps[i]; ASSERT_EQ(1, comp->is_complete()); delete comp; } } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } int iterate_cb(uint64_t off, size_t len, int exists, void *arg) { //cout << "iterate_cb " << off << "~" << len << std::endl; interval_set *diff = static_cast *>(arg); diff->insert(off, len); return 0; } void scribble(librbd::Image& image, int n, int max, interval_set *exists, interval_set *what) { uint64_t size; image.size(&size); interval_set exists_at_start = *exists; for (int i=0; i w; w.insert(off, len); // the zeroed bit no longer exists... w.intersection_of(*exists); exists->subtract(w); // the bits we discarded are no long written... interval_set w2 = w; w2.intersection_of(*what); what->subtract(w2); // except for the extents that existed at the start that we overwrote. interval_set w3; w3.insert(off, len); w3.intersection_of(exists_at_start); what->union_of(w3); } else { bufferlist bl; bl.append(buffer::create(len)); bl.zero(); ASSERT_EQ((int)len, image.write(off, len, bl)); interval_set w; w.insert(off, len); what->union_of(w); exists->union_of(w); } } } TEST(LibRBD, DiffIterate) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); int seed = getpid(); cout << "seed " << seed << std::endl; srand(seed); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 20 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); interval_set exists; interval_set one, two; scribble(image, 10, 102400, &exists, &one); cout << " wrote " << one << std::endl; ASSERT_EQ(0, image.snap_create("one")); scribble(image, 10, 102400, &exists, &two); cout << " wrote " << two << std::endl; interval_set diff; ASSERT_EQ(0, image.diff_iterate("one", 0, size, iterate_cb, (void *)&diff)); cout << " diff was " << diff << std::endl; if (!two.subset_of(diff)) { interval_set i; i.intersection_of(two, diff); interval_set l = two; l.subtract(i); cout << " ... two - (two*diff) = " << l << std::endl; } ASSERT_TRUE(two.subset_of(diff)); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } struct diff_extent { diff_extent(uint64_t offset, uint64_t length, bool exists) : offset(offset), length(length), exists(exists) {} uint64_t offset; uint64_t length; bool exists; bool operator==(const diff_extent& o) const { return offset == o.offset && length == o.length && exists == o.exists; } }; ostream& operator<<(ostream & o, const diff_extent& e) { return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')'; } int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg) { cout << "iterate_cb " << off << "~" << len << std::endl; vector *diff = static_cast *>(arg); diff->push_back(diff_extent(off, len, exists)); return 0; } TEST(LibRBD, DiffIterateDiscard) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); int seed = getpid(); cout << "seed " << seed << std::endl; srand(seed); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 20 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); vector extents; ceph::bufferlist bl; ASSERT_EQ(0, image.diff_iterate(NULL, 0, size, vector_iterate_cb, (void *) &extents)); ASSERT_EQ(0u, extents.size()); char data[256]; memset(data, 1, sizeof(data)); bl.append(data, 256); ASSERT_EQ(256, image.write(0, 256, bl)); ASSERT_EQ(0, image.diff_iterate(NULL, 0, size, vector_iterate_cb, (void *) &extents)); ASSERT_EQ(1u, extents.size()); ASSERT_EQ(diff_extent(0, 256, true), extents[0]); int obj_ofs = 256; ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs)); extents.clear(); ASSERT_EQ(0, image.diff_iterate(NULL, 0, size, vector_iterate_cb, (void *) &extents)); ASSERT_EQ(0u, extents.size()); ASSERT_EQ(0, image.snap_create("snap1")); ASSERT_EQ(256, image.write(0, 256, bl)); ASSERT_EQ(0, image.diff_iterate(NULL, 0, size, vector_iterate_cb, (void *) &extents)); ASSERT_EQ(1u, extents.size()); ASSERT_EQ(diff_extent(0, 256, true), extents[0]); ASSERT_EQ(0, image.snap_create("snap2")); ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs)); extents.clear(); ASSERT_EQ(0, image.snap_set("snap2")); ASSERT_EQ(0, image.diff_iterate("snap1", 0, size, vector_iterate_cb, (void *) &extents)); ASSERT_EQ(1u, extents.size()); ASSERT_EQ(diff_extent(0, 256, true), extents[0]); ASSERT_EQ(0, image.snap_set(NULL)); ASSERT_EQ(1 << order, image.discard(0, 1 << order)); ASSERT_EQ(0, image.snap_create("snap3")); ASSERT_EQ(0, image.snap_set("snap3")); extents.clear(); ASSERT_EQ(0, image.diff_iterate("snap1", 0, size, vector_iterate_cb, (void *) &extents)); ASSERT_EQ(1u, extents.size()); ASSERT_EQ(diff_extent(0, 256, false), extents[0]); } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(LibRBD, DiffIterateStress) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); int seed = getpid(); cout << "seed " << seed << std::endl; srand(seed); { librbd::RBD rbd; librbd::Image image; int order = 0; const char *name = "testimg"; uint64_t size = 400 << 20; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name, size, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name, NULL)); interval_set curexists; vector > wrote; vector > exists; vector snap; int n = 20; for (int i=0; i w; scribble(image, 10, 8192000, &curexists, &w); cout << " i=" << i << " exists " << curexists << " wrote " << w << std::endl; string s = "snap" + stringify(i); ASSERT_EQ(0, image.snap_create(s.c_str())); wrote.push_back(w); exists.push_back(curexists); snap.push_back(s); } for (int i=0; i diff, actual, uex; for (int k=i+1; k<=j; k++) diff.union_of(wrote[k]); cout << "from " << i << " to " << j << " diff " << diff << std::endl; // limit to extents that exists both at the beginning and at the end uex.union_of(exists[i], exists[j]); diff.intersection_of(uex); cout << " limited diff " << diff << std::endl; image.snap_set(snap[j].c_str()); ASSERT_EQ(0, image.diff_iterate(snap[i].c_str(), 0, size, iterate_cb, (void *)&actual)); cout << " actual was " << actual << std::endl; if (!diff.subset_of(actual)) { interval_set i; i.intersection_of(diff, actual); interval_set l = diff; l.subtract(i); cout << " ... diff - (actual*diff) = " << l << std::endl; } ASSERT_TRUE(diff.subset_of(actual)); } } } ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(LibRBD, ZeroLengthWrite) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); char read_data[1]; ASSERT_EQ(0, rbd_write(image, 0, 0, NULL)); ASSERT_EQ(1, rbd_read(image, 0, 1, read_data)); ASSERT_EQ('\0', read_data[0]); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, ZeroLengthDiscard) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); const char *data = "blah"; char read_data[strlen(data)]; ASSERT_EQ((int)strlen(data), rbd_write(image, 0, strlen(data), data)); ASSERT_EQ(0, rbd_discard(image, 0, 0)); ASSERT_EQ((int)strlen(data), rbd_read(image, 0, strlen(data), read_data)); ASSERT_EQ(0, memcmp(data, read_data, strlen(data))); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, ZeroLengthRead) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = 2 << 20; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); char read_data[1]; ASSERT_EQ(0, rbd_read(image, 0, 0, read_data)); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, LargeCacheRead) { if (!g_conf->rbd_cache) { std::cout << "SKIPPING due to disabled cache" << std::endl; return; } rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); uint64_t orig_cache_size = g_conf->rbd_cache_size; g_conf->set_val("rbd_cache_size", "16777216"); BOOST_SCOPE_EXIT( (orig_cache_size) ) { g_conf->set_val("rbd_cache_size", stringify(orig_cache_size).c_str()); } BOOST_SCOPE_EXIT_END; ASSERT_EQ(16777216, g_conf->rbd_cache_size); rbd_image_t image; int order = 0; const char *name = "testimg"; uint64_t size = g_conf->rbd_cache_size + 1; ASSERT_EQ(0, create_image(ioctx, name, size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name, &image, NULL)); std::string buffer(1 << order, '1'); for (size_t offs = 0; offs < size; offs += buffer.size()) { size_t len = std::min(buffer.size(), size - offs); ASSERT_EQ(static_cast(len), rbd_write(image, offs, len, buffer.c_str())); } ASSERT_EQ(0, rbd_invalidate_cache(image)); buffer.resize(size); ASSERT_EQ(static_cast(size-1024), rbd_read(image, 1024, size, &buffer[0])); ASSERT_EQ(0, rbd_close(image)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, TestPendingAio) { rados_t cluster; rados_ioctx_t ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); int features = RBD_FEATURE_LAYERING; rbd_image_t image; int order = 0; std::string name = "testimg"; uint64_t size = 4 << 20; ASSERT_EQ(0, create_image_full(ioctx, name.c_str(), size, &order, false, features)); ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); char test_data[TEST_IO_SIZE]; for (size_t i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } size_t num_aios = 256; rbd_completion_t comps[num_aios]; for (size_t i = 0; i < num_aios; ++i) { ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i])); uint64_t offset = rand() % (size - TEST_IO_SIZE); ASSERT_EQ(0, rbd_aio_write(image, offset, TEST_IO_SIZE, test_data, comps[i])); } for (size_t i = 0; i < num_aios; ++i) { ASSERT_EQ(0, rbd_aio_wait_for_complete(comps[i])); rbd_aio_release(comps[i]); } ASSERT_EQ(0, rbd_invalidate_cache(image)); for (size_t i = 0; i < num_aios; ++i) { ASSERT_EQ(0, rbd_aio_create_completion(NULL, NULL, &comps[i])); uint64_t offset = rand() % (size - TEST_IO_SIZE); ASSERT_LE(0, rbd_aio_read(image, offset, TEST_IO_SIZE, test_data, comps[i])); } ASSERT_EQ(0, rbd_close(image)); for (size_t i = 0; i < num_aios; ++i) { ASSERT_EQ(1, rbd_aio_is_complete(comps[i])); rbd_aio_release(comps[i]); } rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRBD, BlockingAIO) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); librbd::RBD rbd; std::string name = "testimg"; uint64_t size = 1 << 20; int order = 18; ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); CephContext *cct = reinterpret_cast(ioctx.cct()); cct->_conf->set_val_or_die("rbd_non_blocking_aio", "0"); librbd::Image image; ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); bufferlist bl; bl.append(std::string(256, '1')); librbd::RBD::AioCompletion *write_comp = new librbd::RBD::AioCompletion(NULL, NULL); ASSERT_EQ(0, image.aio_write(0, bl.length(), bl, write_comp)); librbd::RBD::AioCompletion *flush_comp = new librbd::RBD::AioCompletion(NULL, NULL); ASSERT_EQ(0, image.aio_flush(flush_comp)); ASSERT_EQ(0, flush_comp->wait_for_complete()); ASSERT_EQ(0, flush_comp->get_return_value()); flush_comp->release(); ASSERT_EQ(1, write_comp->is_complete()); ASSERT_EQ(0, write_comp->get_return_value()); write_comp->release(); librbd::RBD::AioCompletion *discard_comp = new librbd::RBD::AioCompletion(NULL, NULL); ASSERT_EQ(0, image.aio_discard(128, 128, discard_comp)); ASSERT_EQ(0, discard_comp->wait_for_complete()); discard_comp->release(); librbd::RBD::AioCompletion *read_comp = new librbd::RBD::AioCompletion(NULL, NULL); bufferlist read_bl; image.aio_read(0, bl.length(), read_bl, read_comp); ASSERT_EQ(0, read_comp->wait_for_complete()); ASSERT_EQ(bl.length(), read_comp->get_return_value()); read_comp->release(); bufferlist expected_bl; expected_bl.append(std::string(128, '1')); expected_bl.append(std::string(128, '\0')); ASSERT_TRUE(expected_bl.contents_equal(read_bl)); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/test_str_list.cc0000664000175100017510000000155712623076744021664 0ustar jenkins-buildjenkins-build #include "include/types.h" #include "include/str_list.h" #include #include #include "gtest/gtest.h" const char *tests[][10] = { { "foo,bar", "foo", "bar", 0 }, { "foo", "foo", 0 }, { "foo;bar", "foo", "bar", 0 }, { "foo bar", "foo", "bar", 0 }, { " foo bar", "foo", "bar", 0 }, { " foo bar ", "foo", "bar", 0 }, { "a,b,c", "a", "b", "c", 0 }, { " a\tb\tc\t", "a", "b", "c", 0 }, { "a, b, c", "a", "b", "c", 0 }, { "a b c", "a", "b", "c", 0 }, { 0 }, }; TEST(StrList, All) { for (unsigned i=0; tests[i][0]; ++i) { std::string src = tests[i][0]; std::list expected; for (unsigned j=1; tests[i][j]; ++j) expected.push_back(tests[i][j]); std::list actual; get_str_list(src, actual); std::cout << "'" << src << "' -> " << actual << std::endl; ASSERT_EQ(actual, expected); } } ceph-0.80.11/src/test/cls_version/0000775000175100017510000000000012623077035020763 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/cls_version/test_cls_version.cc0000664000175100017510000001675512623076744024703 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "cls/version/cls_version_types.h" #include "cls/version/cls_version_client.h" #include "gtest/gtest.h" #include "test/librados/test.h" #include #include #include static librados::ObjectWriteOperation *new_op() { return new librados::ObjectWriteOperation(); } static librados::ObjectReadOperation *new_rop() { return new librados::ObjectReadOperation(); } TEST(cls_rgw, test_version_inc_read) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); obj_version ver; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_EQ(0, (long long)ver.ver); ASSERT_EQ(0, (int)ver.tag.size()); /* inc version */ librados::ObjectWriteOperation *op = new_op(); cls_version_inc(*op); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_GT((long long)ver.ver, 0); ASSERT_NE(0, (int)ver.tag.size()); /* inc version again! */ delete op; op = new_op(); cls_version_inc(*op); ASSERT_EQ(0, ioctx.operate(oid, op)); obj_version ver2; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver2)); ASSERT_GT((long long)ver2.ver, (long long)ver.ver); ASSERT_EQ(0, (int)ver2.tag.compare(ver.tag)); delete op; obj_version ver3; librados::ObjectReadOperation *rop = new_rop(); cls_version_read(*rop, &ver3); bufferlist outbl; ASSERT_EQ(0, ioctx.operate(oid, rop, &outbl)); ASSERT_EQ(ver2.ver, ver3.ver); ASSERT_EQ(1, (long long)ver2.compare(&ver3)); delete rop; } TEST(cls_rgw, test_version_set) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); obj_version ver; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_EQ(0, (long long)ver.ver); ASSERT_EQ(0, (int)ver.tag.size()); ver.ver = 123; ver.tag = "foo"; /* set version */ librados::ObjectWriteOperation *op = new_op(); cls_version_set(*op, ver); ASSERT_EQ(0, ioctx.operate(oid, op)); /* read version */ obj_version ver2; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver2)); ASSERT_EQ((long long)ver2.ver, (long long)ver.ver); ASSERT_EQ(0, (int)ver2.tag.compare(ver.tag)); delete op; } TEST(cls_rgw, test_version_inc_cond) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); obj_version ver; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_EQ(0, (long long)ver.ver); ASSERT_EQ(0, (int)ver.tag.size()); /* inc version */ librados::ObjectWriteOperation *op = new_op(); cls_version_inc(*op); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_GT((long long)ver.ver, 0); ASSERT_NE(0, (int)ver.tag.size()); obj_version cond_ver = ver; /* inc version again! */ delete op; op = new_op(); cls_version_inc(*op); ASSERT_EQ(0, ioctx.operate(oid, op)); obj_version ver2; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver2)); ASSERT_GT((long long)ver2.ver, (long long)ver.ver); ASSERT_EQ(0, (int)ver2.tag.compare(ver.tag)); /* now check various condition tests */ cls_version_inc(*op, cond_ver, VER_COND_NONE); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver2)); ASSERT_GT((long long)ver2.ver, (long long)ver.ver); ASSERT_EQ(0, (int)ver2.tag.compare(ver.tag)); /* a bunch of conditions that should fail */ delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_EQ); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, op)); delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_LT); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, op)); delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_LE); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, op)); delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_TAG_NE); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver2)); ASSERT_GT((long long)ver2.ver, (long long)ver.ver); ASSERT_EQ(0, (int)ver2.tag.compare(ver.tag)); /* a bunch of conditions that should succeed */ delete op; op = new_op(); cls_version_inc(*op, ver2, VER_COND_EQ); ASSERT_EQ(0, ioctx.operate(oid, op)); delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_GT); ASSERT_EQ(0, ioctx.operate(oid, op)); delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_GE); ASSERT_EQ(0, ioctx.operate(oid, op)); delete op; op = new_op(); cls_version_inc(*op, cond_ver, VER_COND_TAG_EQ); ASSERT_EQ(0, ioctx.operate(oid, op)); delete op; } TEST(cls_rgw, test_version_inc_check) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); obj_version ver; ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_EQ(0, (long long)ver.ver); ASSERT_EQ(0, (int)ver.tag.size()); /* inc version */ librados::ObjectWriteOperation *op = new_op(); cls_version_inc(*op); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver)); ASSERT_GT((long long)ver.ver, 0); ASSERT_NE(0, (int)ver.tag.size()); obj_version cond_ver = ver; /* a bunch of conditions that should succeed */ librados::ObjectReadOperation *rop = new_rop(); cls_version_check(*rop, cond_ver, VER_COND_EQ); bufferlist bl; ASSERT_EQ(0, ioctx.operate(oid, rop, &bl)); delete rop; rop = new_rop(); cls_version_check(*rop, cond_ver, VER_COND_GE); ASSERT_EQ(0, ioctx.operate(oid, rop, &bl)); delete rop; rop = new_rop(); cls_version_check(*rop, cond_ver, VER_COND_LE); ASSERT_EQ(0, ioctx.operate(oid, rop, &bl)); delete rop; rop = new_rop(); cls_version_check(*rop, cond_ver, VER_COND_TAG_EQ); ASSERT_EQ(0, ioctx.operate(oid, rop, &bl)); obj_version ver2; delete op; op = new_op(); cls_version_inc(*op); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_version_read(ioctx, oid, &ver2)); ASSERT_GT((long long)ver2.ver, (long long)ver.ver); ASSERT_EQ(0, (int)ver2.tag.compare(ver.tag)); delete op; /* a bunch of conditions that should fail */ delete rop; rop = new_rop(); cls_version_check(*rop, ver, VER_COND_LT); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, rop, &bl)); delete rop; rop = new_rop(); cls_version_check(*rop, cond_ver, VER_COND_LE); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, rop, &bl)); delete rop; rop = new_rop(); cls_version_check(*rop, cond_ver, VER_COND_TAG_NE); ASSERT_EQ(-ECANCELED, ioctx.operate(oid, rop, &bl)); delete rop; } ceph-0.80.11/src/test/test_rgw_admin_log.cc0000664000175100017510000015217112623076744022630 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include #include #include #include extern "C"{ #include } #include "common/ceph_crypto.h" #include "include/str_list.h" #include "common/ceph_json.h" #include "common/code_environment.h" #include "common/ceph_argparse.h" #include "common/Finisher.h" #include "global/global_init.h" #include "rgw/rgw_common.h" #include "rgw/rgw_bucket.h" #include "rgw/rgw_rados.h" #include "include/utime.h" #include "include/object.h" #define GTEST #ifdef GTEST #include #else #define TEST(x, y) void y() #define ASSERT_EQ(v, s) if(v != s)cout << "Error at " << __LINE__ << "(" << #v << "!= " << #s << "\n"; \ else cout << "(" << #v << "==" << #s << ") PASSED\n"; #define EXPECT_EQ(v, s) ASSERT_EQ(v, s) #define ASSERT_TRUE(c) if(c)cout << "Error at " << __LINE__ << "(" << #c << ")" << "\n"; \ else cout << "(" << #c << ") PASSED\n"; #define EXPECT_TRUE(c) ASSERT_TRUE(c) #endif using namespace std; #define CURL_VERBOSE 0 #define HTTP_RESPONSE_STR "RespCode" #define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20 #define RGW_ADMIN_RESP_PATH "/tmp/.test_rgw_admin_resp" #define TEST_BUCKET_NAME "test_bucket" #define TEST_BUCKET_OBJECT "test_object" #define TEST_BUCKET_OBJECT_1 "test_object1" #define TEST_BUCKET_OBJECT_SIZE 1024 static string uid = "ceph"; static string display_name = "CEPH"; extern "C" int ceph_armor(char *dst, const char *dst_end, const char *src, const char *end); static void print_usage(char *exec){ cout << "Usage: " << exec << " \n"; cout << "Options:\n" "-g - The ip address of the gateway\n" "-p - The port number of the gateway\n" "-c - Absolute path of ceph config file\n" "-rgw-admin - radosgw-admin absolute path\n"; } namespace admin_log { class test_helper { private: string host; string port; string creds; string rgw_admin_path; string conf_path; CURL *curl_inst; map response; list extra_hdrs; string *resp_data; unsigned resp_code; public: test_helper() : resp_data(NULL){ curl_global_init(CURL_GLOBAL_ALL); } ~test_helper(){ curl_global_cleanup(); } int send_request(string method, string uri, size_t (*function)(void *,size_t,size_t,void *) = 0, void *ud = 0, size_t length = 0); int extract_input(int argc, char *argv[]); string& get_response(string hdr){ return response[hdr]; } void set_extra_header(string hdr){ extra_hdrs.push_back(hdr); } void set_response(char *val); void set_response_data(char *data, size_t len){ if(resp_data) delete resp_data; resp_data = new string(data, len); } string& get_rgw_admin_path() { return rgw_admin_path; } string& get_ceph_conf_path() { return conf_path; } void set_creds(string& c) { creds = c; } const string *get_response_data(){return resp_data;} unsigned get_resp_code(){return resp_code;} }; int test_helper::extract_input(int argc, char *argv[]){ #define ERR_CHECK_NEXT_PARAM(o) \ if(((int)loop + 1) >= argc)return -1; \ else o = argv[loop+1]; for(unsigned loop = 1;loop < (unsigned)argc; loop += 2){ if(strcmp(argv[loop], "-g") == 0){ ERR_CHECK_NEXT_PARAM(host); }else if(strcmp(argv[loop],"-p") == 0){ ERR_CHECK_NEXT_PARAM(port); }else if(strcmp(argv[loop], "-c") == 0){ ERR_CHECK_NEXT_PARAM(conf_path); }else if(strcmp(argv[loop], "-rgw-admin") == 0){ ERR_CHECK_NEXT_PARAM(rgw_admin_path); }else return -1; } if(host.length() <= 0 || rgw_admin_path.length() <= 0) return -1; return 0; } void test_helper::set_response(char *r){ string sr(r), h, v; size_t off = sr.find(": "); if(off != string::npos){ h.assign(sr, 0, off); v.assign(sr, off + 2, sr.find("\r\n") - (off+2)); }else{ /*Could be the status code*/ if(sr.find("HTTP/") != string::npos){ h.assign(HTTP_RESPONSE_STR); off = sr.find(" "); v.assign(sr, off + 1, sr.find("\r\n") - (off + 1)); resp_code = atoi((v.substr(0, 3)).c_str()); } } response[h] = v; } size_t write_header(void *ptr, size_t size, size_t nmemb, void *ud){ test_helper *h = static_cast(ud); h->set_response((char *)ptr); return size*nmemb; } size_t write_data(void *ptr, size_t size, size_t nmemb, void *ud){ test_helper *h = static_cast(ud); h->set_response_data((char *)ptr, size*nmemb); return size*nmemb; } static inline void buf_to_hex(const unsigned char *buf, int len, char *str) { int i; str[0] = '\0'; for (i = 0; i < len; i++) { sprintf(&str[i*2], "%02x", (int)buf[i]); } } static void calc_hmac_sha1(const char *key, int key_len, const char *msg, int msg_len, char *dest) /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */ { ceph::crypto::HMACSHA1 hmac((const unsigned char *)key, key_len); hmac.Update((const unsigned char *)msg, msg_len); hmac.Final((unsigned char *)dest); char hex_str[(CEPH_CRYPTO_HMACSHA1_DIGESTSIZE * 2) + 1]; admin_log::buf_to_hex((unsigned char *)dest, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE, hex_str); } static int get_s3_auth(string method, string creds, string date, string res, string& out){ string aid, secret, auth_hdr; string tmp_res; size_t off = creds.find(":"); out = ""; if(off != string::npos){ aid.assign(creds, 0, off); secret.assign(creds, off + 1, string::npos); /*sprintf(auth_hdr, "%s\n\n\n%s\n%s", req_type, date, res);*/ char hmac_sha1[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; char b64[65]; /* 64 is really enough */ size_t off = res.find("?"); if(off == string::npos) tmp_res = res; else tmp_res.assign(res, 0, off); auth_hdr.append(method + string("\n\n\n") + date + string("\n") + tmp_res); admin_log::calc_hmac_sha1(secret.c_str(), secret.length(), auth_hdr.c_str(), auth_hdr.length(), hmac_sha1); int ret = ceph_armor(b64, b64 + 64, hmac_sha1, hmac_sha1 + CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); if (ret < 0) { cout << "ceph_armor failed\n"; return -1; } b64[ret] = 0; out.append(aid + string(":") + b64); }else return -1; return 0; } void get_date(string& d){ struct timeval tv; char date[64]; struct tm tm; char *days[] = {(char *)"Sun", (char *)"Mon", (char *)"Tue", (char *)"Wed", (char *)"Thu", (char *)"Fri", (char *)"Sat"}; char *months[] = {(char *)"Jan", (char *)"Feb", (char *)"Mar", (char *)"Apr", (char *)"May", (char *)"Jun", (char *)"Jul",(char *) "Aug", (char *)"Sep", (char *)"Oct", (char *)"Nov", (char *)"Dec"}; gettimeofday(&tv, NULL); gmtime_r(&tv.tv_sec, &tm); sprintf(date, "%s, %d %s %d %d:%d:%d GMT", days[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec); d = date; } int test_helper::send_request(string method, string res, size_t (*read_function)( void *,size_t,size_t,void *), void *ud, size_t length){ string url; string auth, date; url.append(string("http://") + host); if(port.length() > 0)url.append(string(":") + port); url.append(res); curl_inst = curl_easy_init(); if(curl_inst){ curl_easy_setopt(curl_inst, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl_inst, CURLOPT_CUSTOMREQUEST, method.c_str()); curl_easy_setopt(curl_inst, CURLOPT_VERBOSE, CURL_VERBOSE); curl_easy_setopt(curl_inst, CURLOPT_HEADERFUNCTION, admin_log::write_header); curl_easy_setopt(curl_inst, CURLOPT_WRITEHEADER, (void *)this); curl_easy_setopt(curl_inst, CURLOPT_WRITEFUNCTION, admin_log::write_data); curl_easy_setopt(curl_inst, CURLOPT_WRITEDATA, (void *)this); if(read_function){ curl_easy_setopt(curl_inst, CURLOPT_READFUNCTION, read_function); curl_easy_setopt(curl_inst, CURLOPT_READDATA, (void *)ud); curl_easy_setopt(curl_inst, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl_inst, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); } get_date(date); string http_date; http_date.append(string("Date: ") + date); string s3auth; if (admin_log::get_s3_auth(method, creds, date, res, s3auth) < 0) return -1; auth.append(string("Authorization: AWS ") + s3auth); struct curl_slist *slist = NULL; slist = curl_slist_append(slist, auth.c_str()); slist = curl_slist_append(slist, http_date.c_str()); for(list::iterator it = extra_hdrs.begin(); it != extra_hdrs.end(); ++it){ slist = curl_slist_append(slist, (*it).c_str()); } if(read_function) curl_slist_append(slist, "Expect:"); curl_easy_setopt(curl_inst, CURLOPT_HTTPHEADER, slist); response.erase(response.begin(), response.end()); extra_hdrs.erase(extra_hdrs.begin(), extra_hdrs.end()); CURLcode res = curl_easy_perform(curl_inst); if(res != CURLE_OK){ cout << "Curl perform failed for " << url << ", res: " << curl_easy_strerror(res) << "\n"; return -1; } curl_slist_free_all(slist); } curl_easy_cleanup(curl_inst); return 0; } }; admin_log::test_helper *g_test; Finisher *finisher; int run_rgw_admin(string& cmd, string& resp) { pid_t pid; pid = fork(); if (pid == 0) { /* child */ list l; get_str_list(cmd, " \t", l); char *argv[l.size()]; unsigned loop = 1; argv[0] = (char *)"radosgw-admin"; for (list::iterator it = l.begin(); it != l.end(); ++it) { argv[loop++] = (char *)(*it).c_str(); } argv[loop] = NULL; close(1); stdout = fopen(RGW_ADMIN_RESP_PATH, "w+"); if (!stdout) { cout << "Unable to open stdout file" << std::endl; } execv((g_test->get_rgw_admin_path()).c_str(), argv); } else if (pid > 0) { int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { if(WEXITSTATUS(status) != 0) { cout << "Child exited with status " << WEXITSTATUS(status) << std::endl; return -1; } } ifstream in; struct stat st; if (stat(RGW_ADMIN_RESP_PATH, &st) < 0) { cout << "Error stating the admin response file, errno " << errno << std::endl; return -1; } else { char *data = (char *)malloc(st.st_size + 1); in.open(RGW_ADMIN_RESP_PATH); in.read(data, st.st_size); in.close(); data[st.st_size] = 0; resp = data; free(data); unlink(RGW_ADMIN_RESP_PATH); /* cout << "radosgw-admin " << cmd << ": " << resp << std::endl; */ } } else return -1; return 0; } int get_creds(string& json, string& creds) { JSONParser parser; if(!parser.parse(json.c_str(), json.length())) { cout << "Error parsing create user response" << std::endl; return -1; } RGWUserInfo info; decode_json_obj(info, &parser); creds = ""; for(map::iterator it = info.access_keys.begin(); it != info.access_keys.end(); ++it) { RGWAccessKey _k = it->second; /*cout << "accesskeys [ " << it->first << " ] = " << "{ " << _k.id << ", " << _k.key << ", " << _k.subuser << "}" << std::endl;*/ creds.append(it->first + string(":") + _k.key); break; } return 0; } int user_create(string& uid, string& display_name, bool set_creds = true) { stringstream ss; string creds; ss << "-c " << g_test->get_ceph_conf_path() << " user create --uid=" << uid << " --display-name=" << display_name; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error creating user" << std::endl; return -1; } get_creds(out, creds); if(set_creds) g_test->set_creds(creds); return 0; } int user_info(string& uid, string& display_name, RGWUserInfo& uinfo) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " user info --uid=" << uid << " --display-name=" << display_name; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error reading user information" << std::endl; return -1; } JSONParser parser; if(!parser.parse(out.c_str(), out.length())) { cout << "Error parsing create user response" << std::endl; return -1; } decode_json_obj(uinfo, &parser); return 0; } int user_rm(string& uid, string& display_name) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " metadata rm --metadata-key=user:" << uid; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error removing user" << std::endl; return -1; } return 0; } int caps_add(const char * name, const char *perm) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " caps add --caps=" << name << "=" << perm << " --uid=" << uid; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error creating user" << std::endl; return -1; } return 0; } int caps_rm(const char * name, const char *perm) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " caps rm --caps=" << name << "=" << perm << " --uid=" << uid; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error creating user" << std::endl; return -1; } return 0; } static int create_bucket(void){ g_test->send_request(string("PUT"), string("/"TEST_BUCKET_NAME)); if(g_test->get_resp_code() != 200U){ cout << "Error creating bucket, http code " << g_test->get_resp_code(); return -1; } return 0; } static int delete_bucket(void){ g_test->send_request(string("DELETE"), string("/"TEST_BUCKET_NAME)); if(g_test->get_resp_code() != 204U){ cout << "Error deleting bucket, http code " << g_test->get_resp_code(); return -1; } return 0; } size_t read_dummy_post(void *ptr, size_t s, size_t n, void *ud) { int dummy = 0; memcpy(ptr, &dummy, sizeof(dummy)); return sizeof(dummy); } size_t read_bucket_object(void *ptr, size_t s, size_t n, void *ud) { memcpy(ptr, ud, TEST_BUCKET_OBJECT_SIZE); return TEST_BUCKET_OBJECT_SIZE; } static int put_bucket_obj(const char *obj_name, char *data, unsigned len) { string req = "/"TEST_BUCKET_NAME"/"; req.append(obj_name); g_test->send_request(string("PUT"), req, read_bucket_object, (void *)data, (size_t)len); if (g_test->get_resp_code() != 200U) { cout << "Errror sending object to the bucket, http_code " << g_test->get_resp_code(); return -1; } return 0; } static int read_bucket_obj(const char *obj_name) { string req = "/"TEST_BUCKET_NAME"/"; req.append(obj_name); g_test->send_request(string("GET"), req); if (g_test->get_resp_code() != 200U) { cout << "Errror sending object to the bucket, http_code " << g_test->get_resp_code(); return -1; } return 0; } static int delete_obj(const char *obj_name) { string req = "/"TEST_BUCKET_NAME"/"; req.append(obj_name); g_test->send_request(string("DELETE"), req); if (g_test->get_resp_code() != 204U) { cout << "Errror deleting object from bucket, http_code " << g_test->get_resp_code(); return -1; } return 0; } int get_formatted_time(string& ret) { struct tm *tm = NULL; char str_time[200]; const char *format = "%Y-%m-%d%%20%H:%M:%S"; time_t t; t = time(NULL); tm = gmtime(&t); if(!tm) { cerr << "Error returned by gmtime\n"; return -1; } if (strftime(str_time, sizeof(str_time), format, tm) == 0) { cerr << "Error returned by strftime\n"; return -1; } ret = str_time; return 0; } int parse_json_resp(JSONParser &parser) { string *resp; resp = (string *)g_test->get_response_data(); if(!resp) return -1; if(!parser.parse(resp->c_str(), resp->length())) { cout << "Error parsing create user response" << std::endl; return -1; } return 0; } struct RGWMetadataLogData { obj_version read_version; obj_version write_version; string status; }; struct cls_log_entry_json { string section; string name; utime_t timestamp; RGWMetadataLogData log_data; }; static int decode_json(JSONObj *obj, RGWMetadataLogData &data) { JSONObj *jo; jo = obj->find_obj("read_version"); if (!jo) return -1; data.read_version.decode_json(obj); data.write_version.decode_json(obj); jo = obj->find_obj("status"); if (!jo) return -1; JSONDecoder::decode_json("status", data.status, jo); return 0; } static int decode_json(JSONObj *obj, cls_log_entry_json& ret) { JSONDecoder::decode_json("section", ret.section, obj); JSONDecoder::decode_json("name", ret.name, obj); JSONObj *jo = obj->find_obj("data"); if(!jo) return 0; return decode_json(jo, ret.log_data); } static int get_log_list(list &entries) { JSONParser parser; if (parse_json_resp(parser) != 0) return -1; if (!parser.is_array()) return -1; vector l; l = parser.get_array_elements(); int loop = 0; for(vector::iterator it = l.begin(); it != l.end(); ++it, loop++) { JSONParser jp; cls_log_entry_json entry; if(!jp.parse((*it).c_str(), (*it).length())) { cerr << "Error parsing log json object" << std::endl; return -1; } EXPECT_EQ(decode_json((JSONObj *)&jp, entry), 0); entries.push_back(entry); } return 0; } struct cls_bilog_entry { string op_id; string op_tag; string op; string object; string status; unsigned index_ver; }; static int decode_json(JSONObj *obj, cls_bilog_entry& ret) { JSONDecoder::decode_json("op_id", ret.op_id, obj); JSONDecoder::decode_json("op_tag", ret.op_tag, obj); JSONDecoder::decode_json("op", ret.op, obj); JSONDecoder::decode_json("object", ret.object, obj); JSONDecoder::decode_json("state", ret.status, obj); JSONDecoder::decode_json("index_ver", ret.index_ver, obj); return 0; } static int get_bilog_list(list &entries) { JSONParser parser; if (parse_json_resp(parser) != 0) return -1; if (!parser.is_array()) return -1; vector l; l = parser.get_array_elements(); int loop = 0; for(vector::iterator it = l.begin(); it != l.end(); ++it, loop++) { JSONParser jp; cls_bilog_entry entry; if(!jp.parse((*it).c_str(), (*it).length())) { cerr << "Error parsing log json object" << std::endl; return -1; } EXPECT_EQ(decode_json((JSONObj *)&jp, entry), 0); entries.push_back(entry); } return 0; } static int decode_json(JSONObj *obj, rgw_data_change& ret) { string entity; JSONDecoder::decode_json("entity_type", entity, obj); if (entity.compare("bucket") == 0) ret.entity_type = ENTITY_TYPE_BUCKET; JSONDecoder::decode_json("key", ret.key, obj); return 0; } static int get_datalog_list(list &entries) { JSONParser parser; if (parse_json_resp(parser) != 0) return -1; if (!parser.is_array()) return -1; vector l; l = parser.get_array_elements(); int loop = 0; for(vector::iterator it = l.begin(); it != l.end(); ++it, loop++) { JSONParser jp; rgw_data_change entry; if(!jp.parse((*it).c_str(), (*it).length())) { cerr << "Error parsing log json object" << std::endl; return -1; } EXPECT_EQ(decode_json((JSONObj *)&jp, entry), 0); entries.push_back(entry); } return 0; } unsigned get_mdlog_shard_id(string& key, int max_shards) { string section = "user"; uint32_t val = ceph_str_hash_linux(key.c_str(), key.size()); val ^= ceph_str_hash_linux(section.c_str(), section.size()); return (unsigned)(val % max_shards); } unsigned get_datalog_shard_id(const char *bucket_name, int max_shards) { uint32_t r = ceph_str_hash_linux(bucket_name, strlen(bucket_name)) % max_shards; return (int)r; } TEST(TestRGWAdmin, datalog_list) { string start_time, end_time, start_time_2; const char *cname = "datalog", *perm = "*"; string rest_req; unsigned shard_id = get_datalog_shard_id(TEST_BUCKET_NAME, g_ceph_context->_conf->rgw_data_log_num_shards); stringstream ss; list entries; ASSERT_EQ(get_formatted_time(start_time), 0); ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=data"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); JSONParser parser; int num_objects; EXPECT_EQ (parse_json_resp(parser), 0); JSONDecoder::decode_json("num_objects", num_objects, (JSONObj *)&parser); ASSERT_EQ(num_objects,g_ceph_context->_conf->rgw_data_log_num_shards); sleep(1); ASSERT_EQ(0, create_bucket()); char *bucket_obj = (char *)malloc(TEST_BUCKET_OBJECT_SIZE); ASSERT_TRUE(bucket_obj != NULL); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); free(bucket_obj); sleep(1); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_EQ(1U, entries.size()); if (entries.size() == 1) { rgw_data_change entry = *(entries.begin()); EXPECT_EQ(entry.entity_type, ENTITY_TYPE_BUCKET); EXPECT_EQ(entry.key.compare(TEST_BUCKET_NAME), 0); } ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT)); sleep(1); ASSERT_EQ(get_formatted_time(end_time), 0); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_EQ(1U, entries.size()); if (entries.size() == 1) { list::iterator it = (entries.begin()); EXPECT_EQ((*it).entity_type, ENTITY_TYPE_BUCKET); EXPECT_EQ((*it).key.compare(TEST_BUCKET_NAME), 0); } sleep(1); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); sleep(20); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_EQ(2U, entries.size()); if (entries.size() == 2) { list::iterator it = (entries.begin()); EXPECT_EQ((*it).entity_type, ENTITY_TYPE_BUCKET); EXPECT_EQ((*it).key.compare(TEST_BUCKET_NAME), 0); it++; EXPECT_EQ((*it).entity_type, ENTITY_TYPE_BUCKET); EXPECT_EQ((*it).key.compare(TEST_BUCKET_NAME), 0); } ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&max-entries=1"; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_EQ(1U, entries.size()); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_EQ(1U, entries.size()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "read"; ASSERT_EQ(0, caps_add(cname, perm)); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT)); ASSERT_EQ(0, delete_bucket()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, datalog_lock_unlock) { const char *cname = "datalog", *perm = "*"; string rest_req; ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=data&lock&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&lock&id=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&lock&length=3&id=1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&lock&length=3&id=1&locker-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&unlock&id=1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&unlock&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&unlock&locker-id=ceph&id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&unlock&id=1&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); utime_t sleep_time(3, 0); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(500U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph1&zone-id=2"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(500U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); sleep_time.sleep(); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&unlock&id=1&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "read"; ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "write"; ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); rest_req = "/admin/log?type=data&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); rest_req = "/admin/log?type=data&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, datalog_trim) { string start_time, end_time; const char *cname = "datalog", *perm = "*"; string rest_req; unsigned shard_id = get_datalog_shard_id(TEST_BUCKET_NAME, g_ceph_context->_conf->rgw_data_log_num_shards); stringstream ss; list entries; ASSERT_EQ(get_formatted_time(start_time), 0); ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=data"; g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ ss.str(""); ss << "/admin/log?type=data&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ ASSERT_EQ(0, create_bucket()); char *bucket_obj = (char *)malloc(TEST_BUCKET_OBJECT_SIZE); ASSERT_TRUE(bucket_obj != NULL); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT)); sleep(1); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT)); sleep(20); free(bucket_obj); ASSERT_EQ(get_formatted_time(end_time), 0); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_TRUE(entries.size() > 0); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_datalog_list(entries); EXPECT_TRUE(entries.size() == 0); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "write"; ASSERT_EQ(0, caps_add(cname, perm)); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = ""; ASSERT_EQ(0, caps_add(cname, perm)); ss.str(""); ss << "/admin/log?type=data&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, delete_bucket()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, mdlog_list) { string start_time, end_time, start_time_2; const char *cname = "mdlog", *perm = "*"; string rest_req; unsigned shard_id = get_mdlog_shard_id(uid, g_ceph_context->_conf->rgw_md_log_max_shards); stringstream ss; sleep(2); ASSERT_EQ(get_formatted_time(start_time), 0); ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=metadata"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); JSONParser parser; int num_objects; EXPECT_EQ (parse_json_resp(parser), 0); JSONDecoder::decode_json("num_objects", num_objects, (JSONObj *)&parser); ASSERT_EQ(num_objects,g_ceph_context->_conf->rgw_md_log_max_shards); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); list entries; EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 4U); if(entries.size() == 4) { list::iterator it = entries.begin(); EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("write") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("complete") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("write") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("complete") == 0); } sleep(1); /*To get a modified time*/ ASSERT_EQ(get_formatted_time(start_time_2), 0); ASSERT_EQ(0, caps_rm(cname, perm)); perm="read"; ASSERT_EQ(0, caps_add(cname, perm)); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time_2; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 4U); if(entries.size() == 4) { list::iterator it = entries.begin(); EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("write") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("complete") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("write") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("complete") == 0); } sleep(1); ASSERT_EQ(get_formatted_time(start_time_2), 0); ASSERT_EQ(0, user_rm(uid, display_name)); ASSERT_EQ(0, user_create(uid, display_name)); perm = "*"; ASSERT_EQ(0, caps_add(cname, perm)); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time_2; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 6U); if(entries.size() == 6) { list::iterator it = entries.begin(); EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("remove") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("write") == 0); it++; EXPECT_TRUE(it->section.compare("user") == 0); EXPECT_TRUE(it->name.compare(uid) == 0); EXPECT_TRUE(it->log_data.status.compare("complete") == 0); } sleep(1); ASSERT_EQ(get_formatted_time(end_time), 0); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 14U); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time << "&max-entries=" << 1; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 1U); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time << "&max-entries=" << 6; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 6U); ASSERT_EQ(0, caps_rm(cname, perm)); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(403U, g_test->get_resp_code()); /*cleanup*/ ASSERT_EQ(0, caps_add(cname, perm)); sleep(1); ASSERT_EQ(get_formatted_time(end_time), 0); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, mdlog_trim) { string start_time, end_time, start_time_2; const char *cname = "mdlog", *perm = "*"; string rest_req; list entries; unsigned shard_id = get_mdlog_shard_id(uid, g_ceph_context->_conf->rgw_md_log_max_shards); ostringstream ss; sleep(1); ASSERT_EQ(get_formatted_time(start_time), 0); ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 4U); sleep(1); ASSERT_EQ(get_formatted_time(end_time), 0); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); EXPECT_EQ(get_log_list(entries), 0); EXPECT_EQ(entries.size(), 0U); ASSERT_EQ(0, caps_rm(cname, perm)); perm="write"; ASSERT_EQ(0, caps_add(cname, perm)); ASSERT_EQ(get_formatted_time(end_time), 0); ss.str(""); ss << "/admin/log?type=metadata&id=" << shard_id << "&start-time=" << start_time << "&end-time=" << end_time; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, mdlog_lock_unlock) { const char *cname = "mdlog", *perm = "*"; string rest_req; ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=metadata&lock&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&lock&id=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&lock&length=3&id=1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&lock&id=3&locker-id=ceph&length=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&unlock&id=1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&unlock&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&unlock&locker-id=ceph&id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&unlock&id=1&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); utime_t sleep_time(3, 0); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(500U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=2"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(500U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); sleep_time.sleep(); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&unlock&id=1&locker-id=ceph1&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "read"; ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "write"; ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); rest_req = "/admin/log?type=metadata&lock&id=1&length=3&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); rest_req = "/admin/log?type=metadata&unlock&id=1&locker-id=ceph&zone-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, bilog_list) { const char *cname = "bilog", *perm = "*"; string rest_req; ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); ASSERT_EQ(0, create_bucket()); char *bucket_obj = (char *)malloc(TEST_BUCKET_OBJECT_SIZE); ASSERT_TRUE(bucket_obj != NULL); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); free(bucket_obj); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); list entries; get_bilog_list(entries); EXPECT_EQ(2U, entries.size()); if (entries.size() == 2) { list::iterator it = entries.begin(); EXPECT_EQ(it->op.compare("write"), 0); EXPECT_EQ(it->object.compare(TEST_BUCKET_OBJECT), 0); EXPECT_EQ(it->status.compare("pending"), 0); EXPECT_EQ(it->index_ver, 1U); it++; EXPECT_EQ(it->op.compare("write"), 0); EXPECT_EQ(it->object.compare(TEST_BUCKET_OBJECT), 0); EXPECT_EQ(it->status.compare("complete"), 0); EXPECT_EQ(it->index_ver, 2U); } EXPECT_EQ(read_bucket_obj(TEST_BUCKET_OBJECT), 0); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_bilog_list(entries); EXPECT_EQ(2U, entries.size()); bucket_obj = (char *)malloc(TEST_BUCKET_OBJECT_SIZE); ASSERT_TRUE(bucket_obj != NULL); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT_1, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); free(bucket_obj); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_bilog_list(entries); EXPECT_EQ(4U, entries.size()); if (entries.size() == 4) { list::iterator it = entries.begin(); it++; it++; EXPECT_EQ(it->op.compare("write"), 0); EXPECT_EQ(it->object.compare(TEST_BUCKET_OBJECT_1), 0); EXPECT_EQ(it->status.compare("pending"), 0); EXPECT_EQ(it->index_ver, 3U); it++; EXPECT_EQ(it->op.compare("write"), 0); EXPECT_EQ(it->object.compare(TEST_BUCKET_OBJECT_1), 0); EXPECT_EQ(it->status.compare("complete"), 0); EXPECT_EQ(it->index_ver, 4U); } ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT)); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_bilog_list(entries); EXPECT_EQ(6U, entries.size()); string marker; if (entries.size() == 6) { list::iterator it = entries.begin(); it++; it++; it++; it++; marker = it->op_id; EXPECT_EQ(it->op.compare("del"), 0); EXPECT_EQ(it->object.compare(TEST_BUCKET_OBJECT), 0); EXPECT_EQ(it->status.compare("pending"), 0); EXPECT_EQ(it->index_ver, 5U); it++; EXPECT_EQ(it->op.compare("del"), 0); EXPECT_EQ(it->object.compare(TEST_BUCKET_OBJECT), 0); EXPECT_EQ(it->status.compare("complete"), 0); EXPECT_EQ(it->index_ver, 6U); } rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; rest_req.append("&marker="); rest_req.append(marker); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_bilog_list(entries); EXPECT_EQ(2U, entries.size()); if (entries.size() == 2U) { list::iterator it = entries.begin(); EXPECT_EQ(it->index_ver, 5U); it++; EXPECT_EQ(it->index_ver, 6U); EXPECT_EQ(it->op.compare("del"), 0); } rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; rest_req.append("&marker="); rest_req.append(marker); rest_req.append("&max-entries=1"); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_bilog_list(entries); EXPECT_EQ(1U, entries.size()); EXPECT_EQ((entries.begin())->index_ver, 5U); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "read"; ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(0, caps_rm(cname, perm)); perm = "write"; ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(403U, g_test->get_resp_code()); ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT_1)); ASSERT_EQ(0, delete_bucket()); ASSERT_EQ(0, user_rm(uid, display_name)); } TEST(TestRGWAdmin, bilog_trim) { const char *cname = "bilog", *perm = "*"; string rest_req, start_marker, end_marker; ASSERT_EQ(0, user_create(uid, display_name)); ASSERT_EQ(0, caps_add(cname, perm)); ASSERT_EQ(0, create_bucket()); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ char *bucket_obj = (char *)malloc(TEST_BUCKET_OBJECT_SIZE); ASSERT_TRUE(bucket_obj != NULL); EXPECT_EQ(put_bucket_obj(TEST_BUCKET_OBJECT, bucket_obj, TEST_BUCKET_OBJECT_SIZE), 0); free(bucket_obj); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); list entries; get_bilog_list(entries); EXPECT_EQ(2U, entries.size()); list::iterator it = entries.begin(); start_marker = it->op_id; it++; end_marker = it->op_id; rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; rest_req.append("&start-marker="); rest_req.append(start_marker); rest_req.append("&end-marker="); rest_req.append(end_marker); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/log?type=bucket-index&bucket="TEST_BUCKET_NAME; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); get_bilog_list(entries); EXPECT_EQ(0U, entries.size()); ASSERT_EQ(0, delete_obj(TEST_BUCKET_OBJECT)); ASSERT_EQ(0, delete_bucket()); ASSERT_EQ(0, user_rm(uid, display_name)); } int main(int argc, char *argv[]){ vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_test = new admin_log::test_helper(); finisher = new Finisher(g_ceph_context); #ifdef GTEST ::testing::InitGoogleTest(&argc, argv); #endif finisher->start(); if(g_test->extract_input(argc, argv) < 0){ print_usage(argv[0]); return -1; } #ifdef GTEST int r = RUN_ALL_TESTS(); if (r >= 0) { cout << "There are no failures in the test case\n"; } else { cout << "There are some failures\n"; } #endif finisher->stop(); return 0; } ceph-0.80.11/src/test/TestTimers.cc0000664000175100017510000001360412623076744021061 0ustar jenkins-buildjenkins-build#include "common/ceph_argparse.h" #include "common/Mutex.h" #include "common/Timer.h" #include "global/global_init.h" #include /* * TestTimers * * Tests the timer classes */ #define MAX_TEST_CONTEXTS 5 class TestContext; namespace { int array[MAX_TEST_CONTEXTS]; int array_idx; TestContext* test_contexts[MAX_TEST_CONTEXTS]; Mutex array_lock("test_timers_mutex"); } class TestContext : public Context { public: TestContext(int num_) : num(num_) { } virtual void finish(int r) { array_lock.Lock(); cout << "TestContext " << num << std::endl; array[array_idx++] = num; array_lock.Unlock(); } virtual ~TestContext() { } protected: int num; }; class StrictOrderTestContext : public TestContext { public: StrictOrderTestContext (int num_) : TestContext(num_) { } virtual void finish(int r) { array_lock.Lock(); cout << "StrictOrderTestContext " << num << std::endl; array[num] = num; array_lock.Unlock(); } virtual ~StrictOrderTestContext() { } }; static void print_status(const char *str, int ret) { cout << str << ": "; cout << ((ret == 0) ? "SUCCESS" : "FAILURE"); cout << std::endl; } template static int basic_timer_test(T &timer, Mutex *lock) { int ret = 0; memset(&array, 0, sizeof(array)); array_idx = 0; memset(&test_contexts, 0, sizeof(test_contexts)); cout << __PRETTY_FUNCTION__ << std::endl; for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { test_contexts[i] = new TestContext(i); } for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { if (lock) lock->Lock(); utime_t inc(2 * i, 0); utime_t t = ceph_clock_now(g_ceph_context) + inc; timer.add_event_at(t, test_contexts[i]); if (lock) lock->Unlock(); } bool done = false; do { sleep(1); array_lock.Lock(); done = (array_idx == MAX_TEST_CONTEXTS); array_lock.Unlock(); } while (!done); for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { if (array[i] != i) { ret = 1; cout << "error: expected array[" << i << "] = " << i << "; got " << array[i] << " instead." << std::endl; } } return ret; } static int test_out_of_order_insertion(SafeTimer &timer, Mutex *lock) { int ret = 0; memset(&array, 0, sizeof(array)); array_idx = 0; memset(&test_contexts, 0, sizeof(test_contexts)); cout << __PRETTY_FUNCTION__ << std::endl; test_contexts[0] = new StrictOrderTestContext(0); test_contexts[1] = new StrictOrderTestContext(1); { utime_t inc(100, 0); utime_t t = ceph_clock_now(g_ceph_context) + inc; lock->Lock(); timer.add_event_at(t, test_contexts[0]); lock->Unlock(); } { utime_t inc(2, 0); utime_t t = ceph_clock_now(g_ceph_context) + inc; lock->Lock(); timer.add_event_at(t, test_contexts[1]); lock->Unlock(); } int secs = 0; for (; secs < 100 ; ++secs) { sleep(1); array_lock.Lock(); int a = array[1]; array_lock.Unlock(); if (a == 1) break; } if (secs == 100) { ret = 1; cout << "error: expected array[" << 1 << "] = " << 1 << "; got " << array[1] << " instead." << std::endl; } return ret; } static int safe_timer_cancel_all_test(SafeTimer &safe_timer, Mutex& safe_timer_lock) { cout << __PRETTY_FUNCTION__ << std::endl; int ret = 0; memset(&array, 0, sizeof(array)); array_idx = 0; memset(&test_contexts, 0, sizeof(test_contexts)); for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { test_contexts[i] = new TestContext(i); } safe_timer_lock.Lock(); for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { utime_t inc(4 * i, 0); utime_t t = ceph_clock_now(g_ceph_context) + inc; safe_timer.add_event_at(t, test_contexts[i]); } safe_timer_lock.Unlock(); sleep(10); safe_timer_lock.Lock(); safe_timer.cancel_all_events(); safe_timer_lock.Unlock(); for (int i = 0; i < array_idx; ++i) { if (array[i] != i) { ret = 1; cout << "error: expected array[" << i << "] = " << i << "; got " << array[i] << " instead." << std::endl; } } return ret; } static int safe_timer_cancellation_test(SafeTimer &safe_timer, Mutex& safe_timer_lock) { cout << __PRETTY_FUNCTION__ << std::endl; int ret = 0; memset(&array, 0, sizeof(array)); array_idx = 0; memset(&test_contexts, 0, sizeof(test_contexts)); for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { test_contexts[i] = new StrictOrderTestContext(i); } safe_timer_lock.Lock(); for (int i = 0; i < MAX_TEST_CONTEXTS; ++i) { utime_t inc(4 * i, 0); utime_t t = ceph_clock_now(g_ceph_context) + inc; safe_timer.add_event_at(t, test_contexts[i]); } safe_timer_lock.Unlock(); // cancel the even-numbered events for (int i = 0; i < MAX_TEST_CONTEXTS; i += 2) { safe_timer_lock.Lock(); safe_timer.cancel_event(test_contexts[i]); safe_timer_lock.Unlock(); } sleep(20); safe_timer_lock.Lock(); safe_timer.cancel_all_events(); safe_timer_lock.Unlock(); for (int i = 1; i < array_idx; i += 2) { if (array[i] != i) { ret = 1; cout << "error: expected array[" << i << "] = " << i << "; got " << array[i] << " instead." << std::endl; } } return ret; } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); int ret; Mutex safe_timer_lock("safe_timer_lock"); SafeTimer safe_timer(g_ceph_context, safe_timer_lock); ret = basic_timer_test (safe_timer, &safe_timer_lock); if (ret) goto done; ret = safe_timer_cancel_all_test(safe_timer, safe_timer_lock); if (ret) goto done; ret = safe_timer_cancellation_test(safe_timer, safe_timer_lock); if (ret) goto done; ret = test_out_of_order_insertion(safe_timer, &safe_timer_lock); if (ret) goto done; done: print_status(argv[0], ret); return ret; } ceph-0.80.11/src/test/osd/0000775000175100017510000000000012623077036017223 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/osd/osdcap.cc0000664000175100017510000006362012623076744021017 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "include/stringify.h" #include "osd/OSDCap.h" #include "gtest/gtest.h" const char *parse_good[] = { "allow *", "allow r", "allow rwx", "allow r pool foo ", "allow r pool=foo", "allow wx pool taco", "allow pool foo r", "allow pool taco wx", "allow wx pool taco object_prefix obj", "allow wx pool taco object_prefix obj_with_underscores_and_no_quotes", "allow pool taco object_prefix obj wx", "allow pool taco object_prefix obj_with_underscores_and_no_quotes wx", "allow rwx pool 'weird name'", "allow rwx pool \"weird name with ''s\"", "allow rwx auid 123", "allow rwx pool foo, allow r pool bar", "allow rwx pool foo ; allow r pool bar", "allow rwx pool foo ;allow r pool bar", "allow rwx pool foo; allow r pool bar", "allow auid 123 rwx", "allow pool foo rwx, allow pool bar r", "allow pool foo.froo.foo rwx, allow pool bar r", "allow pool foo rwx ; allow pool bar r", "allow pool foo rwx ;allow pool bar r", "allow pool foo rwx; allow pool bar r", "allow pool data rw, allow pool rbd rwx, allow pool images class rbd foo", "allow class-read", "allow class-write", "allow class-read class-write", "allow r class-read pool foo", "allow rw class-read class-write pool foo", "allow r class-read pool foo", "allow pool bar rwx; allow pool baz r class-read", "allow class foo", "allow class clsname \"clsthingidon'tunderstand\"", " allow rwx pool foo; allow r pool bar ", " allow rwx pool foo; allow r pool bar ", " allow pool foo rwx; allow pool bar r ", " allow pool foo rwx; allow pool bar r ", " allow wx pool taco", "\tallow\nwx\tpool \n taco\t", "allow r pool foo object_prefix blah ; allow w auid 5", "allow class-read object_prefix rbd_children, allow pool libvirt-pool-test rwx", "allow class-read object_prefix rbd-children, allow pool libvirt_pool_test rwx", "allow pool foo namespace nfoo rwx, allow pool bar namespace=nbar r", "allow pool foo namespace=nfoo rwx ; allow pool bar namespace=nbar r", "allow pool foo namespace nfoo rwx ;allow pool bar namespace nbar r", "allow pool foo namespace=nfoo rwx; allow pool bar namespace nbar object_prefix rbd r", "allow pool foo namespace=\"\" rwx; allow pool bar namespace='' object_prefix rbd r", "allow pool foo namespace \"\" rwx; allow pool bar namespace '' object_prefix rbd r", 0 }; TEST(OSDCap, ParseGood) { for (int i=0; parse_good[i]; i++) { string str = parse_good[i]; OSDCap cap; std::cout << "Testing good input: '" << str << "'" << std::endl; ASSERT_TRUE(cap.parse(str, &cout)); } } const char *parse_bad[] = { "allow r poolfoo", "allow r w", "ALLOW r", "allow rwx,", "allow rwx x", "allow r pool foo r", "allow wwx pool taco", "allow wwx pool taco^funny&chars", "allow rwx pool 'weird name''", "allow rwx object_prefix \"beforepool\" pool weird", "allow rwx auid 123 pool asdf", "allow xrwx pool foo,, allow r pool bar", ";allow rwx pool foo rwx ; allow r pool bar", "allow rwx pool foo ;allow r pool bar gibberish", "allow rwx auid 123 pool asdf namespace=foo", "allow rwx auid 123 namespace", "allow rwx namespace", "allow namespace", "allow namespace=foo", "allow rwx auid 123 namespace asdf", "allow wwx pool ''", 0 }; TEST(OSDCap, ParseBad) { for (int i=0; parse_bad[i]; i++) { string str = parse_bad[i]; OSDCap cap; std::cout << "Testing bad input: '" << str << "'" << std::endl; ASSERT_FALSE(cap.parse(str, &cout)); } } TEST(OSDCap, AllowAll) { OSDCap cap; ASSERT_FALSE(cap.allow_all()); ASSERT_TRUE(cap.parse("allow r", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow w", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow x", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow rwx", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow rw", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow rx", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow wx", NULL)); ASSERT_FALSE(cap.allow_all()); cap.grants.clear(); ASSERT_TRUE(cap.parse("allow *", NULL)); ASSERT_TRUE(cap.allow_all()); ASSERT_TRUE(cap.is_capable("foo", "", 0, "asdf", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "anamespace", 0, "asdf", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "asdf", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "anamespace", 0, "asdf", true, true, true, true)); } TEST(OSDCap, AllowPool) { OSDCap cap; bool r = cap.parse("allow rwx pool foo", NULL); ASSERT_TRUE(r); ASSERT_TRUE(cap.is_capable("foo", "", 0, "", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "", true, true, true, true)); } TEST(OSDCap, AllowPools) { OSDCap cap; bool r = cap.parse("allow rwx pool foo, allow r pool bar", NULL); ASSERT_TRUE(r); ASSERT_TRUE(cap.is_capable("foo", "", 0, "", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "", true, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "", true, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "", true, false, false, false)); ASSERT_FALSE(cap.is_capable("baz", "ns", 0, "", true, false, false, false)); } TEST(OSDCap, AllowPools2) { OSDCap cap; bool r = cap.parse("allow r, allow rwx pool foo", NULL); ASSERT_TRUE(r); ASSERT_TRUE(cap.is_capable("foo", "", 0, "", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "", true, false, false, false)); } TEST(OSDCap, ObjectPrefix) { OSDCap cap; bool r = cap.parse("allow rwx object_prefix foo", NULL); ASSERT_TRUE(r); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "food", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo_bar", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "_foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, " foo ", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "fo", true, true, true, true)); } TEST(OSDCap, ObjectPoolAndPrefix) { OSDCap cap; bool r = cap.parse("allow rwx pool bar object_prefix foo", NULL); ASSERT_TRUE(r); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "food", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo_bar", true, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "food", true, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "fo", true, true, true, true)); } TEST(OSDCap, BasicR) { OSDCap cap; ASSERT_TRUE(cap.parse("allow r", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); } TEST(OSDCap, BasicW) { OSDCap cap; ASSERT_TRUE(cap.parse("allow w", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); } TEST(OSDCap, BasicX) { OSDCap cap; ASSERT_TRUE(cap.parse("allow x", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); } TEST(OSDCap, BasicRW) { OSDCap cap; ASSERT_TRUE(cap.parse("allow rw", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); } TEST(OSDCap, BasicRX) { OSDCap cap; ASSERT_TRUE(cap.parse("allow rx", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); } TEST(OSDCap, BasicWX) { OSDCap cap; ASSERT_TRUE(cap.parse("allow wx", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); } TEST(OSDCap, BasicRWX) { OSDCap cap; ASSERT_TRUE(cap.parse("allow rwx", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, false)); } TEST(OSDCap, BasicRWClassRClassW) { OSDCap cap; ASSERT_TRUE(cap.parse("allow rw class-read class-write", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, false)); } TEST(OSDCap, ClassR) { OSDCap cap; ASSERT_TRUE(cap.parse("allow class-read", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, false, false, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); } TEST(OSDCap, ClassW) { OSDCap cap; ASSERT_TRUE(cap.parse("allow class-write", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); } TEST(OSDCap, ClassRW) { OSDCap cap; ASSERT_TRUE(cap.parse("allow class-read class-write", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); } TEST(OSDCap, BasicRClassR) { OSDCap cap; ASSERT_TRUE(cap.parse("allow r class-read", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); ASSERT_TRUE(cap.is_capable("bar", "any", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "any", 0, "foo", true, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "any", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", true, true, false, false)); } TEST(OSDCap, PoolClassR) { OSDCap cap; ASSERT_TRUE(cap.parse("allow pool bar r class-read, allow pool foo rwx", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "foo", true, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, true, false, false)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, false)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, false)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, false, false)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, false, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, false)); } TEST(OSDCap, PoolClassRNS) { OSDCap cap; ASSERT_TRUE(cap.parse("allow pool bar namespace='' r class-read, allow pool foo namespace=ns rwx", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", false, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", true, true, false, false)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", false, false, false, false)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", false, false, true, true)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, false, false, true)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, true, false, true)); ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, true, true, false)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, false)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, false, false)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, true, true, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, false, true)); ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, false)); } TEST(OSDCap, NSClassR) { OSDCap cap; ASSERT_TRUE(cap.parse("allow namespace '' rw class-read class-write, allow namespace test r", NULL)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, false)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, true, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, true, true, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, false)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, false, true)); ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, false)); ASSERT_TRUE(cap.is_capable("bar", "test", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", true, false, true, false)); ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", true, true, false, false)); ASSERT_TRUE(cap.is_capable("foo", "test", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", true, false, true, false)); ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", true, true, true, true)); ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", false, true, false, true)); ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", true, true, false, false)); ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", true, false, false, false)); ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", false, true, false, false)); ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", false, false, true, false)); ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", false, false, false, true)); } TEST(OSDCap, OutputParsed) { struct CapsTest { const char *input; const char *output; }; CapsTest test_values[] = { {"allow *", "osdcap[grant(*)]"}, {"allow r", "osdcap[grant(r)]"}, {"allow rx", "osdcap[grant(rx)]"}, {"allow rwx", "osdcap[grant(rwx)]"}, {"allow rw class-read class-write", "osdcap[grant(rwx)]"}, {"allow rw class-read", "osdcap[grant(rw class-read)]"}, {"allow rw class-write", "osdcap[grant(rw class-write)]"}, {"allow rwx pool images", "osdcap[grant(pool images rwx)]"}, {"allow r pool images", "osdcap[grant(pool images r)]"}, {"allow pool images rwx", "osdcap[grant(pool images rwx)]"}, {"allow pool images r", "osdcap[grant(pool images r)]"}, {"allow pool images w", "osdcap[grant(pool images w)]"}, {"allow pool images x", "osdcap[grant(pool images x)]"}, {"allow r pool images namespace ''", "osdcap[grant(pool images namespace \"\" r)]"}, {"allow r pool images namespace foo", "osdcap[grant(pool images namespace foo r)]"}, {"allow r pool images namespace \"\"", "osdcap[grant(pool images namespace \"\" r)]"}, {"allow r namespace foo", "osdcap[grant(namespace foo r)]"}, {"allow pool images r; allow pool rbd rwx", "osdcap[grant(pool images r),grant(pool rbd rwx)]"}, {"allow pool images r, allow pool rbd rwx", "osdcap[grant(pool images r),grant(pool rbd rwx)]"}, {"allow class-read object_prefix rbd_children, allow pool libvirt-pool-test rwx", "osdcap[grant(object_prefix rbd_children class-read),grant(pool libvirt-pool-test rwx)]"} }; size_t num_tests = sizeof(test_values) / sizeof(*test_values); for (size_t i = 0; i < num_tests; ++i) { OSDCap cap; std::cout << "Testing input '" << test_values[i].input << "'" << std::endl; ASSERT_TRUE(cap.parse(test_values[i].input)); ASSERT_EQ(test_values[i].output, stringify(cap)); } } ceph-0.80.11/src/test/osd/RadosModel.h0000664000175100017510000014475512623076744021452 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/int_types.h" #include "common/Mutex.h" #include "common/Cond.h" #include "include/rados/librados.hpp" #include #include #include #include #include #include #include #include #include #include #include "Object.h" #include "TestOpStat.h" #include "test/librados/test.h" #include "include/memory.h" #include "common/sharedptr_registry.hpp" #include "common/errno.h" #include "osd/HitSet.h" #ifndef RADOSMODEL_H #define RADOSMODEL_H using namespace std; class RadosTestContext; class TestOpStat; template typename T::iterator rand_choose(T &cont) { if (cont.size() == 0) { return cont.end(); } int index = rand() % cont.size(); typename T::iterator retval = cont.begin(); for (; index > 0; --index) ++retval; return retval; } enum TestOpType { TEST_OP_READ, TEST_OP_WRITE, TEST_OP_DELETE, TEST_OP_SNAP_CREATE, TEST_OP_SNAP_REMOVE, TEST_OP_ROLLBACK, TEST_OP_SETATTR, TEST_OP_RMATTR, TEST_OP_WATCH, TEST_OP_COPY_FROM, TEST_OP_HIT_SET_LIST, TEST_OP_UNDIRTY, TEST_OP_IS_DIRTY, TEST_OP_CACHE_FLUSH, TEST_OP_CACHE_TRY_FLUSH, TEST_OP_CACHE_EVICT, TEST_OP_APPEND }; class TestWatchContext : public librados::WatchCtx { TestWatchContext(const TestWatchContext&); public: Cond cond; uint64_t handle; bool waiting; Mutex lock; TestWatchContext() : handle(0), waiting(false), lock("watch lock") {} void notify(uint8_t opcode, uint64_t ver, bufferlist &bl) { Mutex::Locker l(lock); waiting = false; cond.SignalAll(); } void start() { Mutex::Locker l(lock); waiting = true; } void wait() { Mutex::Locker l(lock); while (waiting) cond.Wait(lock); } uint64_t &get_handle() { return handle; } }; class TestOp { public: int num; RadosTestContext *context; TestOpStat *stat; bool done; TestOp(int n, RadosTestContext *context, TestOpStat *stat = 0) : num(n), context(context), stat(stat), done(0) {} virtual ~TestOp() {}; /** * This struct holds data to be passed by a callback * to a TestOp::finish method. */ struct CallbackInfo { uint64_t id; CallbackInfo(uint64_t id) : id(id) {} virtual ~CallbackInfo() {}; }; virtual void _begin() = 0; /** * Called when the operation completes. * This should be overridden by asynchronous operations. * * @param info information stored by a callback, or NULL - * useful for multi-operation TestOps */ virtual void _finish(CallbackInfo *info) { return; } virtual string getType() = 0; virtual bool finished() { return true; } void begin(); void finish(CallbackInfo *info); virtual bool must_quiesce_other_ops() { return false; } }; class TestOpGenerator { public: virtual ~TestOpGenerator() {}; virtual TestOp *next(RadosTestContext &context) = 0; }; class RadosTestContext { public: Mutex state_lock; Cond wait_cond; map > pool_obj_cont; set oid_in_use; set oid_not_in_use; set oid_flushing; set oid_not_flushing; SharedPtrRegistry snaps_in_use; int current_snap; string pool_name; librados::IoCtx io_ctx; librados::Rados rados; int next_oid; string prefix; int errors; int max_in_flight; int seq_num; map snaps; uint64_t seq; const char *rados_id; bool initialized; map watches; const uint64_t max_size; const uint64_t min_stride_size; const uint64_t max_stride_size; AttrGenerator attr_gen; const bool no_omap; bool pool_snaps; int snapname_num; RadosTestContext(const string &pool_name, int max_in_flight, uint64_t max_size, uint64_t min_stride_size, uint64_t max_stride_size, bool no_omap, bool pool_snaps, const char *id = 0) : state_lock("Context Lock"), pool_obj_cont(), current_snap(0), pool_name(pool_name), next_oid(0), errors(0), max_in_flight(max_in_flight), seq_num(0), seq(0), rados_id(id), initialized(false), max_size(max_size), min_stride_size(min_stride_size), max_stride_size(max_stride_size), attr_gen(2000), no_omap(no_omap), pool_snaps(pool_snaps), snapname_num(0) { } int init() { int r = rados.init(rados_id); if (r < 0) return r; r = rados.conf_read_file(NULL); if (r < 0) return r; r = rados.conf_parse_env(NULL); if (r < 0) return r; r = rados.connect(); if (r < 0) return r; r = rados.ioctx_create(pool_name.c_str(), io_ctx); if (r < 0) { rados.shutdown(); return r; } char hostname_cstr[100]; gethostname(hostname_cstr, 100); stringstream hostpid; hostpid << hostname_cstr << getpid() << "-"; prefix = hostpid.str(); assert(!initialized); initialized = true; return 0; } void shutdown() { if (initialized) { rados.shutdown(); } } void loop(TestOpGenerator *gen) { assert(initialized); list inflight; state_lock.Lock(); TestOp *next = gen->next(*this); TestOp *waiting = NULL; while (next || !inflight.empty()) { if (next && next->must_quiesce_other_ops() && !inflight.empty()) { waiting = next; next = NULL; // Force to wait for inflight to drain } if (next) { inflight.push_back(next); } state_lock.Unlock(); if (next) { (*inflight.rbegin())->begin(); } state_lock.Lock(); while (1) { for (list::iterator i = inflight.begin(); i != inflight.end();) { if ((*i)->finished()) { cout << (*i)->num << ": done (" << (inflight.size()-1) << " left)" << std::endl; delete *i; inflight.erase(i++); } else { ++i; } } if (inflight.size() >= (unsigned) max_in_flight || (!next && !inflight.empty())) { cout << " waiting on " << inflight.size() << std::endl; wait(); } else { break; } } if (waiting) { next = waiting; waiting = NULL; } else { next = gen->next(*this); } } state_lock.Unlock(); } void wait() { wait_cond.Wait(state_lock); } void kick() { wait_cond.Signal(); } TestWatchContext *get_watch_context(const string &oid) { return watches.count(oid) ? watches[oid] : 0; } TestWatchContext *watch(const string &oid) { assert(!watches.count(oid)); return (watches[oid] = new TestWatchContext); } void unwatch(const string &oid) { assert(watches.count(oid)); delete watches[oid]; watches.erase(oid); } ObjectDesc get_most_recent(const string &oid) { ObjectDesc new_obj; for (map >::reverse_iterator i = pool_obj_cont.rbegin(); i != pool_obj_cont.rend(); ++i) { map::iterator j = i->second.find(oid); if (j != i->second.end()) { new_obj = j->second; break; } } return new_obj; } void rm_object_attrs(const string &oid, const set &attrs) { ObjectDesc new_obj = get_most_recent(oid); for (set::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { new_obj.attrs.erase(*i); } new_obj.dirty = true; pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } void remove_object_header(const string &oid) { ObjectDesc new_obj = get_most_recent(oid); new_obj.header = bufferlist(); new_obj.dirty = true; pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } void update_object_header(const string &oid, const bufferlist &bl) { ObjectDesc new_obj = get_most_recent(oid); new_obj.header = bl; new_obj.exists = true; new_obj.dirty = true; pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } void update_object_attrs(const string &oid, const map &attrs) { ObjectDesc new_obj = get_most_recent(oid); for (map::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { new_obj.attrs[i->first] = i->second; } new_obj.exists = true; new_obj.dirty = true; pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } void update_object(ContentsGenerator *cont_gen, const string &oid, const ContDesc &contents) { ObjectDesc new_obj = get_most_recent(oid); new_obj.exists = true; new_obj.dirty = true; new_obj.update(cont_gen, contents); pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } void update_object_full(const string &oid, const ObjectDesc &contents) { pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, contents)); pool_obj_cont[current_snap][oid].dirty = true; } void update_object_undirty(const string &oid) { ObjectDesc new_obj = get_most_recent(oid); new_obj.dirty = false; pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } void update_object_version(const string &oid, uint64_t version, int snap = -1) { for (map >::reverse_iterator i = pool_obj_cont.rbegin(); i != pool_obj_cont.rend(); ++i) { if (snap != -1 && snap < i->first) continue; map::iterator j = i->second.find(oid); if (j != i->second.end()) { if (version) j->second.version = version; cout << __func__ << " oid " << oid << " v " << version << " " << j->second.most_recent() << " " << (j->second.dirty ? "dirty" : "clean") << " " << (j->second.exists ? "exists" : "dne") << std::endl; break; } } } void remove_object(const string &oid) { assert(!get_watch_context(oid)); ObjectDesc new_obj; pool_obj_cont[current_snap].erase(oid); pool_obj_cont[current_snap].insert(pair(oid, new_obj)); } bool find_object(const string &oid, ObjectDesc *contents, int snap = -1) const { for (map >::const_reverse_iterator i = pool_obj_cont.rbegin(); i != pool_obj_cont.rend(); ++i) { if (snap != -1 && snap < i->first) continue; if (i->second.count(oid) != 0) { *contents = i->second.find(oid)->second; return true; } } return false; } void remove_snap(int snap) { map >::iterator next_iter = pool_obj_cont.find(snap); assert(next_iter != pool_obj_cont.end()); map >::iterator current_iter = next_iter++; assert(current_iter != pool_obj_cont.end()); map ¤t = current_iter->second; map &next = next_iter->second; for (map::iterator i = current.begin(); i != current.end(); ++i) { if (next.count(i->first) == 0) { next.insert(pair(i->first, i->second)); } } pool_obj_cont.erase(current_iter); snaps.erase(snap); } void add_snap(uint64_t snap) { snaps[current_snap] = snap; current_snap++; pool_obj_cont[current_snap]; seq = snap; } void roll_back(const string &oid, int snap) { assert(!get_watch_context(oid)); ObjectDesc contents; find_object(oid, &contents, snap); contents.dirty = true; pool_obj_cont.rbegin()->second.erase(oid); pool_obj_cont.rbegin()->second.insert(pair(oid, contents)); } }; void read_callback(librados::completion_t comp, void *arg); void write_callback(librados::completion_t comp, void *arg); class RemoveAttrsOp : public TestOp { public: string oid; librados::ObjectWriteOperation op; librados::AioCompletion *comp; bool done; RemoveAttrsOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat) : TestOp(n, context, stat), oid(oid), comp(NULL), done(false) {} void _begin() { ContDesc cont; set to_remove; { Mutex::Locker l(context->state_lock); ObjectDesc obj; if (!context->find_object(oid, &obj)) { context->kick(); done = true; return; } cont = ContDesc(context->seq_num, context->current_snap, context->seq_num, ""); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); if (rand() % 30) { ContentsGenerator::iterator iter = context->attr_gen.get_iterator(cont); for (map::iterator i = obj.attrs.begin(); i != obj.attrs.end(); ++i, ++iter) { if (!(*iter % 3)) { //op.rmxattr(i->first.c_str()); to_remove.insert(i->first); op.rmxattr(i->first.c_str()); } } if (to_remove.empty()) { context->kick(); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); done = true; return; } if (!context->no_omap) { op.omap_rm_keys(to_remove); } } else { if (!context->no_omap) { op.omap_clear(); } for (map::iterator i = obj.attrs.begin(); i != obj.attrs.end(); ++i) { op.rmxattr(i->first.c_str()); to_remove.insert(i->first); } context->remove_object_header(oid); } context->rm_object_attrs(oid, to_remove); } pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); comp = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); context->io_ctx.aio_operate(context->prefix+oid, comp, &op); } void _finish(CallbackInfo *info) { Mutex::Locker l(context->state_lock); done = true; context->update_object_version(oid, comp->get_version64()); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); context->kick(); } bool finished() { return done; } string getType() { return "RemoveAttrsOp"; } }; class SetAttrsOp : public TestOp { public: string oid; librados::ObjectWriteOperation op; librados::AioCompletion *comp; bool done; SetAttrsOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat) : TestOp(n, context, stat), oid(oid), comp(NULL), done(false) {} void _begin() { ContDesc cont; { Mutex::Locker l(context->state_lock); cont = ContDesc(context->seq_num, context->current_snap, context->seq_num, ""); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); } map omap_contents; map omap; bufferlist header; ContentsGenerator::iterator keygen = context->attr_gen.get_iterator(cont); op.create(false); while (!*keygen) ++keygen; while (*keygen) { if (*keygen != '_') header.append(*keygen); ++keygen; } for (int i = 0; i < 20; ++i) { string key; while (!*keygen) ++keygen; while (*keygen && key.size() < 40) { key.push_back((*keygen % 20) + 'a'); ++keygen; } ContDesc val(cont); val.seqnum += (unsigned)(*keygen); val.prefix = ("oid: " + oid); omap[key] = val; bufferlist val_buffer = context->attr_gen.gen_bl(val); omap_contents[key] = val_buffer; op.setxattr(key.c_str(), val_buffer); } if (!context->no_omap) { op.omap_set_header(header); op.omap_set(omap_contents); } { Mutex::Locker l(context->state_lock); context->update_object_header(oid, header); context->update_object_attrs(oid, omap); } pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); comp = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); context->io_ctx.aio_operate(context->prefix+oid, comp, &op); } void _finish(CallbackInfo *info) { Mutex::Locker l(context->state_lock); int r; if ((r = comp->get_return_value())) { cerr << "err " << r << std::endl; assert(0); } done = true; context->update_object_version(oid, comp->get_version64()); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); context->kick(); } bool finished() { return done; } string getType() { return "SetAttrsOp"; } }; class WriteOp : public TestOp { public: string oid; ContDesc cont; set waiting; librados::AioCompletion *rcompletion; uint64_t waiting_on; uint64_t last_acked_tid; librados::ObjectReadOperation read_op; librados::ObjectWriteOperation write_op; bufferlist rbuffer; bool do_append; WriteOp(int n, RadosTestContext *context, const string &oid, bool do_append, TestOpStat *stat = 0) : TestOp(n, context, stat), oid(oid), waiting_on(0), last_acked_tid(0), do_append(do_append) {} void _begin() { context->state_lock.Lock(); done = 0; stringstream acc; acc << context->prefix << "OID: " << oid << " snap " << context->current_snap << std::endl; string prefix = acc.str(); cont = ContDesc(context->seq_num, context->current_snap, context->seq_num, prefix); ContentsGenerator *cont_gen; if (do_append) { ObjectDesc old_value; bool found = context->find_object(oid, &old_value); uint64_t prev_length = found && old_value.has_contents() ? old_value.most_recent_gen()->get_length(old_value.most_recent()) : 0; cont_gen = new AppendGenerator( prev_length, (context->io_ctx.pool_requires_alignment() ? context->io_ctx.pool_required_alignment() : 0), context->min_stride_size, context->max_stride_size, 3); } else { cont_gen = new VarLenGenerator( context->max_size, context->min_stride_size, context->max_stride_size); } context->update_object(cont_gen, oid, cont); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); map ranges; cont_gen->get_ranges_map(cont, ranges); std::cout << num << ": seq_num " << context->seq_num << " ranges " << ranges << std::endl; context->seq_num++; waiting_on = ranges.size(); //cout << " waiting_on = " << waiting_on << std::endl; ContentsGenerator::iterator gen_pos = cont_gen->get_iterator(cont); uint64_t tid = 1; for (map::iterator i = ranges.begin(); i != ranges.end(); ++i, ++tid) { bufferlist to_write; gen_pos.seek(i->first); for (uint64_t k = 0; k != i->second; ++k, ++gen_pos) { to_write.append(*gen_pos); } assert(to_write.length() == i->second); assert(to_write.length() > 0); std::cout << num << ": writing " << context->prefix+oid << " from " << i->first << " to " << i->first + i->second << " tid " << tid << std::endl; pair *cb_arg = new pair(this, new TestOp::CallbackInfo(tid)); librados::AioCompletion *completion = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); waiting.insert(completion); librados::ObjectWriteOperation op; if (do_append) { op.append(to_write); } else { op.write(i->first, to_write); } context->io_ctx.aio_operate( context->prefix+oid, completion, &op); } bufferlist contbl; ::encode(cont, contbl); pair *cb_arg = new pair( this, new TestOp::CallbackInfo(++tid)); librados::AioCompletion *completion = context->rados.aio_create_completion( (void*) cb_arg, NULL, &write_callback); waiting.insert(completion); waiting_on++; write_op.setxattr("_header", contbl); if (!do_append) { write_op.truncate(cont_gen->get_length(cont)); } context->io_ctx.aio_operate( context->prefix+oid, completion, &write_op); cb_arg = new pair( this, new TestOp::CallbackInfo(++tid)); rcompletion = context->rados.aio_create_completion( (void*) cb_arg, NULL, &write_callback); waiting_on++; read_op.read(0, 1, &rbuffer, 0); context->io_ctx.aio_operate( context->prefix+oid, rcompletion, &read_op, librados::OPERATION_ORDER_READS_WRITES, // order wrt previous write/update 0); context->state_lock.Unlock(); } void _finish(CallbackInfo *info) { assert(info); context->state_lock.Lock(); uint64_t tid = info->id; cout << num << ": finishing write tid " << tid << " to " << context->prefix + oid << std::endl; if (tid <= last_acked_tid) { cerr << "Error: finished tid " << tid << " when last_acked_tid was " << last_acked_tid << std::endl; assert(0); } last_acked_tid = tid; assert(!done); waiting_on--; if (waiting_on == 0) { uint64_t version = 0; for (set::iterator i = waiting.begin(); i != waiting.end(); ) { assert((*i)->is_complete()); if (int err = (*i)->get_return_value()) { cerr << "Error: oid " << oid << " write returned error code " << err << std::endl; } if ((*i)->get_version64() > version) version = (*i)->get_version64(); (*i)->release(); waiting.erase(i++); } context->update_object_version(oid, version); if (rcompletion->get_version64() != version) { cerr << "Error: racing read on " << oid << " returned version " << rcompletion->get_version64() << " rather than version " << version << std::endl; assert(0 == "racing read got wrong version"); } rcompletion->release(); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); context->kick(); done = true; } context->state_lock.Unlock(); } bool finished() { return done; } string getType() { return "WriteOp"; } }; class DeleteOp : public TestOp { public: string oid; DeleteOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat = 0) : TestOp(n, context, stat), oid(oid) {} void _begin() { context->state_lock.Lock(); if (context->get_watch_context(oid)) { context->kick(); context->state_lock.Unlock(); return; } ObjectDesc contents; context->find_object(oid, &contents); bool present = !contents.deleted(); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); context->seq_num++; context->remove_object(oid); interval_set ranges; context->state_lock.Unlock(); int r = context->io_ctx.remove(context->prefix+oid); if (r && !(r == -ENOENT && !present)) { cerr << "r is " << r << " while deleting " << oid << " and present is " << present << std::endl; assert(0); } context->state_lock.Lock(); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); context->kick(); context->state_lock.Unlock(); } string getType() { return "DeleteOp"; } }; class ReadOp : public TestOp { public: librados::AioCompletion *completion; librados::ObjectReadOperation op; string oid; ObjectDesc old_value; int snap; ceph::shared_ptr in_use; bufferlist result; int retval; map attrs; int attrretval; set omap_requested_keys; map omap_returned_values; set omap_keys; map omap; bufferlist header; map xattrs; ReadOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat = 0) : TestOp(n, context, stat), completion(NULL), oid(oid), snap(0), retval(0), attrretval(0) {} void _begin() { context->state_lock.Lock(); if (!(rand() % 4) && !context->snaps.empty()) { snap = rand_choose(context->snaps)->first; in_use = context->snaps_in_use.lookup_or_create(snap, snap); } else { snap = -1; } std::cout << num << ": read oid " << oid << " snap " << snap << std::endl; done = 0; completion = context->rados.aio_create_completion((void *) this, &read_callback, 0); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); assert(context->find_object(oid, &old_value, snap)); TestWatchContext *ctx = context->get_watch_context(oid); context->state_lock.Unlock(); if (ctx) { assert(old_value.exists); TestAlarm alarm; std::cerr << num << ": about to start" << std::endl; ctx->start(); std::cerr << num << ": started" << std::endl; bufferlist bl; context->io_ctx.set_notify_timeout(600); int r = context->io_ctx.notify(context->prefix+oid, 0, bl); if (r < 0) { std::cerr << "r is " << r << std::endl; assert(0); } std::cerr << num << ": notified, waiting" << std::endl; ctx->wait(); } if (snap >= 0) { context->io_ctx.snap_set_read(context->snaps[snap]); } op.read(0, !old_value.has_contents() ? 0 : old_value.most_recent_gen()->get_length(old_value.most_recent()), &result, &retval); for (map::iterator i = old_value.attrs.begin(); i != old_value.attrs.end(); ++i) { if (rand() % 2) { string key = i->first; if (rand() % 2) key.push_back((rand() % 26) + 'a'); omap_requested_keys.insert(key); } } if (!context->no_omap) { op.omap_get_vals_by_keys(omap_requested_keys, &omap_returned_values, 0); op.omap_get_keys("", -1, &omap_keys, 0); op.omap_get_vals("", -1, &omap, 0); op.omap_get_header(&header, 0); } op.getxattrs(&xattrs, 0); assert(!context->io_ctx.aio_operate(context->prefix+oid, completion, &op, 0)); if (snap >= 0) { context->io_ctx.snap_set_read(0); } } void _finish(CallbackInfo *info) { context->state_lock.Lock(); assert(!done); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); assert(completion->is_complete()); uint64_t version = completion->get_version64(); if (int err = completion->get_return_value()) { if (!(err == -ENOENT && old_value.deleted())) { cerr << num << ": Error: oid " << oid << " read returned error code " << err << std::endl; assert(0); } } else { map::iterator iter = xattrs.find("_header"); bufferlist headerbl; if (iter == xattrs.end()) { if (old_value.has_contents()) { cerr << num << ": Error: did not find header attr, has_contents: " << old_value.has_contents() << std::endl; assert(!old_value.has_contents()); } } else { headerbl = iter->second; xattrs.erase(iter); } cout << num << ": expect " << old_value.most_recent() << std::endl; assert(!old_value.deleted()); if (old_value.has_contents()) { ContDesc to_check; bufferlist::iterator p = headerbl.begin(); ::decode(to_check, p); if (to_check != old_value.most_recent()) { cerr << num << ": oid " << oid << " found incorrect object contents " << to_check << ", expected " << old_value.most_recent() << std::endl; context->errors++; } if (!old_value.check(result)) { cerr << num << ": oid " << oid << " contents " << to_check << " corrupt" << std::endl; context->errors++; } if (context->errors) assert(0); } // Attributes if (!context->no_omap) { if (!(old_value.header == header)) { cerr << num << ": oid " << oid << " header does not match, old size: " << old_value.header.length() << " new size " << header.length() << std::endl; assert(old_value.header == header); } if (omap.size() != old_value.attrs.size()) { cerr << num << ": oid " << oid << " omap.size() is " << omap.size() << " and old is " << old_value.attrs.size() << std::endl; assert(omap.size() == old_value.attrs.size()); } if (omap_keys.size() != old_value.attrs.size()) { cerr << num << ": oid " << oid << " omap.size() is " << omap_keys.size() << " and old is " << old_value.attrs.size() << std::endl; assert(omap_keys.size() == old_value.attrs.size()); } } if (xattrs.size() != old_value.attrs.size()) { cerr << num << ": oid " << oid << " xattrs.size() is " << xattrs.size() << " and old is " << old_value.attrs.size() << std::endl; assert(xattrs.size() == old_value.attrs.size()); } if (version != old_value.version) { cerr << num << ": oid " << oid << " version is " << version << " and expected " << old_value.version << std::endl; assert(version == old_value.version); } for (map::iterator iter = old_value.attrs.begin(); iter != old_value.attrs.end(); ++iter) { bufferlist bl = context->attr_gen.gen_bl( iter->second); if (!context->no_omap) { map::iterator omap_iter = omap.find(iter->first); assert(omap_iter != omap.end()); assert(bl.length() == omap_iter->second.length()); bufferlist::iterator k = bl.begin(); for(bufferlist::iterator l = omap_iter->second.begin(); !k.end() && !l.end(); ++k, ++l) { assert(*l == *k); } } map::iterator xattr_iter = xattrs.find(iter->first); assert(xattr_iter != xattrs.end()); assert(bl.length() == xattr_iter->second.length()); bufferlist::iterator k = bl.begin(); for (bufferlist::iterator j = xattr_iter->second.begin(); !k.end() && !j.end(); ++j, ++k) { assert(*j == *k); } } if (!context->no_omap) { for (set::iterator i = omap_requested_keys.begin(); i != omap_requested_keys.end(); ++i) { if (!omap_returned_values.count(*i)) assert(!old_value.attrs.count(*i)); if (!old_value.attrs.count(*i)) assert(!omap_returned_values.count(*i)); } for (map::iterator i = omap_returned_values.begin(); i != omap_returned_values.end(); ++i) { assert(omap_requested_keys.count(i->first)); assert(omap.count(i->first)); assert(old_value.attrs.count(i->first)); assert(i->second == omap[i->first]); } } } context->kick(); done = true; context->state_lock.Unlock(); } bool finished() { return done && completion->is_complete(); } string getType() { return "ReadOp"; } }; class SnapCreateOp : public TestOp { public: SnapCreateOp(int n, RadosTestContext *context, TestOpStat *stat = 0) : TestOp(n, context, stat) {} void _begin() { uint64_t snap; string snapname; if (context->pool_snaps) { stringstream ss; ss << context->prefix << "snap" << ++context->snapname_num; snapname = ss.str(); int ret = context->io_ctx.snap_create(snapname.c_str()); if (ret) { cerr << "snap_create returned " << ret << std::endl; assert(0); } assert(!context->io_ctx.snap_lookup(snapname.c_str(), &snap)); } else { assert(!context->io_ctx.selfmanaged_snap_create(&snap)); } context->state_lock.Lock(); context->add_snap(snap); if (context->pool_snaps) { context->state_lock.Unlock(); } else { vector snapset(context->snaps.size()); int j = 0; for (map::reverse_iterator i = context->snaps.rbegin(); i != context->snaps.rend(); ++i, ++j) { snapset[j] = i->second; } context->state_lock.Unlock(); int r = context->io_ctx.selfmanaged_snap_set_write_ctx(context->seq, snapset); if (r) { cerr << "r is " << r << " snapset is " << snapset << " seq is " << context->seq << std::endl; assert(0); } } } string getType() { return "SnapCreateOp"; } bool must_quiesce_other_ops() { return context->pool_snaps; } }; class SnapRemoveOp : public TestOp { public: int to_remove; SnapRemoveOp(int n, RadosTestContext *context, int snap, TestOpStat *stat = 0) : TestOp(n, context, stat), to_remove(snap) {} void _begin() { context->state_lock.Lock(); uint64_t snap = context->snaps[to_remove]; context->remove_snap(to_remove); context->state_lock.Unlock(); if (context->pool_snaps) { string snapname; assert(!context->io_ctx.snap_get_name(snap, &snapname)); assert(!context->io_ctx.snap_remove(snapname.c_str())); } else { assert(!context->io_ctx.selfmanaged_snap_remove(snap)); vector snapset(context->snaps.size()); int j = 0; for (map::reverse_iterator i = context->snaps.rbegin(); i != context->snaps.rend(); ++i, ++j) { snapset[j] = i->second; } int r = context->io_ctx.selfmanaged_snap_set_write_ctx(context->seq, snapset); if (r) { cerr << "r is " << r << " snapset is " << snapset << " seq is " << context->seq << std::endl; assert(0); } } } string getType() { return "SnapRemoveOp"; } }; class WatchOp : public TestOp { string oid; public: WatchOp(int n, RadosTestContext *context, const string &_oid, TestOpStat *stat = 0) : TestOp(n, context, stat), oid(_oid) {} void _begin() { context->state_lock.Lock(); ObjectDesc contents; context->find_object(oid, &contents); if (contents.deleted()) { context->kick(); context->state_lock.Unlock(); return; } context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); TestWatchContext *ctx = context->get_watch_context(oid); context->state_lock.Unlock(); int r; if (!ctx) { { Mutex::Locker l(context->state_lock); ctx = context->watch(oid); } r = context->io_ctx.watch(context->prefix+oid, 0, &ctx->get_handle(), ctx); } else { r = context->io_ctx.unwatch(context->prefix+oid, ctx->get_handle()); { Mutex::Locker l(context->state_lock); context->unwatch(oid); } } if (r) { cerr << "r is " << r << std::endl; assert(0); } { Mutex::Locker l(context->state_lock); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); } } string getType() { return "WatchOp"; } }; class RollbackOp : public TestOp { public: string oid; int roll_back_to; bool done; librados::ObjectWriteOperation op; librados::AioCompletion *comp; ceph::shared_ptr in_use; RollbackOp(int n, RadosTestContext *context, const string &_oid, TestOpStat *stat = 0) : TestOp(n, context, stat), oid(_oid), roll_back_to(-1), done(false), comp(NULL) {} void _begin() { context->state_lock.Lock(); if (context->get_watch_context(oid)) { context->kick(); context->state_lock.Unlock(); return; } if (context->snaps.empty()) { context->kick(); context->state_lock.Unlock(); done = true; return; } context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); roll_back_to = rand_choose(context->snaps)->first; in_use = context->snaps_in_use.lookup_or_create( roll_back_to, roll_back_to); cout << "rollback oid " << oid << " to " << roll_back_to << std::endl; context->roll_back(oid, roll_back_to); uint64_t snap = context->snaps[roll_back_to]; context->state_lock.Unlock(); if (context->pool_snaps) { op.snap_rollback(snap); } else { op.selfmanaged_snap_rollback(snap); } pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); comp = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); context->io_ctx.aio_operate(context->prefix+oid, comp, &op); } void _finish(CallbackInfo *info) { Mutex::Locker l(context->state_lock); int r; if ((r = comp->get_return_value())) { cerr << "err " << r << std::endl; assert(0); } done = true; context->update_object_version(oid, comp->get_version64()); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); in_use = ceph::shared_ptr(); context->kick(); } bool finished() { return done; } string getType() { return "RollBackOp"; } }; class CopyFromOp : public TestOp { public: string oid, oid_src; ObjectDesc src_value; librados::ObjectWriteOperation op; librados::ObjectReadOperation rd_op; librados::AioCompletion *comp; librados::AioCompletion *comp_racing_read; ceph::shared_ptr in_use; int snap; int done; uint64_t version; int r; CopyFromOp(int n, RadosTestContext *context, const string &oid, const string &oid_src, TestOpStat *stat) : TestOp(n, context, stat), oid(oid), oid_src(oid_src), comp(NULL), snap(-1), done(0), version(0), r(0) {} void _begin() { ContDesc cont; { Mutex::Locker l(context->state_lock); cont = ContDesc(context->seq_num, context->current_snap, context->seq_num, ""); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); context->oid_in_use.insert(oid_src); context->oid_not_in_use.erase(oid_src); // choose source snap if (0 && !(rand() % 4) && !context->snaps.empty()) { snap = rand_choose(context->snaps)->first; in_use = context->snaps_in_use.lookup_or_create(snap, snap); } else { snap = -1; } context->find_object(oid_src, &src_value, snap); if (!src_value.deleted()) context->update_object_full(oid, src_value); } string src = context->prefix+oid_src; op.copy_from(src.c_str(), context->io_ctx, src_value.version); pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); comp = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); context->io_ctx.aio_operate(context->prefix+oid, comp, &op); // queue up a racing read, too. pair *read_cb_arg = new pair(this, new TestOp::CallbackInfo(1)); comp_racing_read = context->rados.aio_create_completion((void*) read_cb_arg, NULL, &write_callback); rd_op.stat(NULL, NULL, NULL); context->io_ctx.aio_operate(context->prefix+oid, comp_racing_read, &rd_op, librados::OPERATION_ORDER_READS_WRITES, // order wrt previous write/update NULL); } void _finish(CallbackInfo *info) { Mutex::Locker l(context->state_lock); // note that the read can (and atm will) come back before the // write reply, but will reflect the update and the versions will // match. if (info->id == 0) { // copy_from assert(comp->is_complete()); cout << num << ": finishing copy_from to " << context->prefix + oid << std::endl; if ((r = comp->get_return_value())) { if (r == -ENOENT && src_value.deleted()) { cout << num << ": got expected ENOENT (src dne)" << std::endl; } else { cerr << "Error: oid " << oid << " copy_from " << oid_src << " returned error code " << r << std::endl; assert(0); } } else { assert(!version || comp->get_version64() == version); version = comp->get_version64(); context->update_object_version(oid, comp->get_version64()); } } else if (info->id == 1) { // racing read assert(comp_racing_read->is_complete()); cout << num << ": finishing copy_from racing read to " << context->prefix + oid << std::endl; if ((r = comp_racing_read->get_return_value())) { if (!(r == -ENOENT && src_value.deleted())) { cerr << "Error: oid " << oid << " copy_from " << oid_src << " returned error code " << r << std::endl; } } else { assert(comp_racing_read->get_return_value() == 0); assert(!version || comp_racing_read->get_version64() == version); version = comp_racing_read->get_version64(); } } if (++done == 2) { context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); context->oid_in_use.erase(oid_src); context->oid_not_in_use.insert(oid_src); context->kick(); } } bool finished() { return done == 2; } string getType() { return "CopyFromOp"; } }; class HitSetListOp : public TestOp { bool done; librados::AioCompletion *comp1, *comp2; uint32_t hash; std::list< std::pair > ls; bufferlist bl; public: HitSetListOp(int n, RadosTestContext *context, uint32_t hash, TestOpStat *stat = 0) : TestOp(n, context, stat), done(false), comp1(NULL), comp2(NULL), hash(hash) {} void _begin() { pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); comp1 = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); int r = context->io_ctx.hit_set_list(hash, comp1, &ls); assert(r == 0); } void _finish(CallbackInfo *info) { Mutex::Locker l(context->state_lock); if (!comp2) { if (ls.empty()) { cerr << num << ": no hitsets" << std::endl; done = true; } else { cerr << num << ": hitsets are " << ls << std::endl; int r = rand() % ls.size(); std::list >::iterator p = ls.begin(); while (r--) ++p; pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); comp2 = context->rados.aio_create_completion((void*) cb_arg, NULL, &write_callback); r = context->io_ctx.hit_set_get(hash, comp2, p->second, &bl); assert(r == 0); } } else { int r = comp2->get_return_value(); if (r == 0) { HitSet hitset; bufferlist::iterator p = bl.begin(); ::decode(hitset, p); cout << num << ": got hitset of type " << hitset.get_type_name() << " size " << bl.length() << std::endl; } else { // FIXME: we could verify that we did in fact race with a trim... assert(r == -ENOENT); } done = true; } context->kick(); } bool finished() { return done; } string getType() { return "HitSetListOp"; } }; class UndirtyOp : public TestOp { public: librados::AioCompletion *completion; librados::ObjectWriteOperation op; string oid; UndirtyOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat = 0) : TestOp(n, context, stat), completion(NULL), oid(oid) {} void _begin() { context->state_lock.Lock(); pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); completion = context->rados.aio_create_completion((void *) cb_arg, NULL, &write_callback); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); context->update_object_undirty(oid); context->state_lock.Unlock(); op.undirty(); int r = context->io_ctx.aio_operate(context->prefix+oid, completion, &op, 0); assert(!r); } void _finish(CallbackInfo *info) { context->state_lock.Lock(); assert(!done); assert(completion->is_complete()); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); context->update_object_version(oid, completion->get_version64()); context->kick(); done = true; context->state_lock.Unlock(); } bool finished() { return done; } string getType() { return "UndirtyOp"; } }; class IsDirtyOp : public TestOp { public: librados::AioCompletion *completion; librados::ObjectReadOperation op; string oid; bool dirty; ObjectDesc old_value; int snap; ceph::shared_ptr in_use; IsDirtyOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat = 0) : TestOp(n, context, stat), completion(NULL), oid(oid), dirty(false) {} void _begin() { context->state_lock.Lock(); if (!(rand() % 4) && !context->snaps.empty()) { snap = rand_choose(context->snaps)->first; in_use = context->snaps_in_use.lookup_or_create(snap, snap); } else { snap = -1; } std::cout << num << ": is_dirty oid " << oid << " snap " << snap << std::endl; pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); completion = context->rados.aio_create_completion((void *) cb_arg, NULL, &write_callback); context->oid_in_use.insert(oid); context->oid_not_in_use.erase(oid); context->state_lock.Unlock(); if (snap >= 0) { context->io_ctx.snap_set_read(context->snaps[snap]); } op.is_dirty(&dirty, NULL); int r = context->io_ctx.aio_operate(context->prefix+oid, completion, &op, 0); assert(!r); if (snap >= 0) { context->io_ctx.snap_set_read(0); } } void _finish(CallbackInfo *info) { context->state_lock.Lock(); assert(!done); assert(completion->is_complete()); context->oid_in_use.erase(oid); context->oid_not_in_use.insert(oid); assert(context->find_object(oid, &old_value, snap)); int r = completion->get_return_value(); if (r == 0) { cout << num << ": " << (dirty ? "dirty" : "clean") << std::endl; assert(!old_value.deleted()); assert(dirty == old_value.dirty); } else { cout << num << ": got " << r << std::endl; assert(r == -ENOENT); assert(old_value.deleted()); } context->kick(); done = true; context->state_lock.Unlock(); } bool finished() { return done; } string getType() { return "IsDirtyOp"; } }; class CacheFlushOp : public TestOp { public: librados::AioCompletion *completion; librados::ObjectReadOperation op; string oid; bool blocking; int snap; bool can_fail; ceph::shared_ptr in_use; CacheFlushOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat, bool b) : TestOp(n, context, stat), completion(NULL), oid(oid), blocking(b), snap(0), can_fail(false) {} void _begin() { context->state_lock.Lock(); if (!(rand() % 4) && !context->snaps.empty()) { snap = rand_choose(context->snaps)->first; in_use = context->snaps_in_use.lookup_or_create(snap, snap); } else { snap = -1; } // not being particularly specific here about knowing which // flushes are on the oldest clean snap and which ones are not. can_fail = !blocking || !context->snaps.empty(); // FIXME: we can could fail if we've ever removed a snap due to // the async snap trimming. can_fail = true; cout << num << ": " << (blocking ? "cache_flush" : "cache_try_flush") << " oid " << oid << " snap " << snap << std::endl; if (snap >= 0) { context->io_ctx.snap_set_read(context->snaps[snap]); } pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); completion = context->rados.aio_create_completion((void *) cb_arg, NULL, &write_callback); // leave object in unused list so that we race with other operations //context->oid_in_use.insert(oid); //context->oid_not_in_use.erase(oid); context->oid_flushing.insert(oid); context->oid_not_flushing.erase(oid); context->state_lock.Unlock(); unsigned flags = librados::OPERATION_IGNORE_CACHE; if (blocking) { op.cache_flush(); } else { op.cache_try_flush(); flags = librados::OPERATION_SKIPRWLOCKS; } int r = context->io_ctx.aio_operate(context->prefix+oid, completion, &op, flags, NULL); assert(!r); if (snap >= 0) { context->io_ctx.snap_set_read(0); } } void _finish(CallbackInfo *info) { context->state_lock.Lock(); assert(!done); assert(completion->is_complete()); //context->oid_in_use.erase(oid); //context->oid_not_in_use.insert(oid); context->oid_flushing.erase(oid); context->oid_not_flushing.insert(oid); int r = completion->get_return_value(); cout << num << ": got " << cpp_strerror(r) << std::endl; if (r == 0) { context->update_object_version(oid, 0, snap); } else if (r == -EBUSY) { assert(can_fail); } else if (r == -EINVAL) { // caching not enabled? } else if (r == -ENOENT) { // may have raced with a remove? } else { assert(0 == "shouldn't happen"); } context->kick(); done = true; context->state_lock.Unlock(); } bool finished() { return done; } string getType() { return "CacheFlushOp"; } }; class CacheEvictOp : public TestOp { public: librados::AioCompletion *completion; librados::ObjectReadOperation op; string oid; ceph::shared_ptr in_use; CacheEvictOp(int n, RadosTestContext *context, const string &oid, TestOpStat *stat) : TestOp(n, context, stat), completion(NULL), oid(oid) {} void _begin() { context->state_lock.Lock(); int snap; if (!(rand() % 4) && !context->snaps.empty()) { snap = rand_choose(context->snaps)->first; in_use = context->snaps_in_use.lookup_or_create(snap, snap); } else { snap = -1; } cout << num << ": cache_evict oid " << oid << " snap " << snap << std::endl; if (snap >= 0) { context->io_ctx.snap_set_read(context->snaps[snap]); } pair *cb_arg = new pair(this, new TestOp::CallbackInfo(0)); completion = context->rados.aio_create_completion((void *) cb_arg, NULL, &write_callback); // leave object in unused list so that we race with other operations //context->oid_in_use.insert(oid); //context->oid_not_in_use.erase(oid); context->state_lock.Unlock(); op.cache_evict(); int r = context->io_ctx.aio_operate(context->prefix+oid, completion, &op, librados::OPERATION_IGNORE_CACHE, NULL); assert(!r); if (snap >= 0) { context->io_ctx.snap_set_read(0); } } void _finish(CallbackInfo *info) { context->state_lock.Lock(); assert(!done); assert(completion->is_complete()); //context->oid_in_use.erase(oid); //context->oid_not_in_use.insert(oid); int r = completion->get_return_value(); cout << num << ": got " << cpp_strerror(r) << std::endl; if (r == 0) { // yay! } else if (r == -EBUSY) { // raced with something that dirtied the object } else if (r == -EINVAL) { // caching not enabled? } else if (r == -ENOENT) { // may have raced with a remove? } else { assert(0 == "shouldn't happen"); } context->kick(); done = true; context->state_lock.Unlock(); } bool finished() { return done; } string getType() { return "CacheEvictOp"; } }; #endif ceph-0.80.11/src/test/osd/RadosModel.cc0000664000175100017510000000156412623076744021576 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/interval_set.h" #include "include/buffer.h" #include #include #include #include "include/rados/librados.h" #include "RadosModel.h" #include "TestOpStat.h" void TestOp::begin() { //if (stat) stat->begin(this); _begin(); } void TestOp::finish(TestOp::CallbackInfo *info) { _finish(info); //if (stat && finished()) stat->end(this); } void read_callback(librados::completion_t comp, void *arg) { TestOp* op = static_cast(arg); op->finish(NULL); } void write_callback(librados::completion_t comp, void *arg) { std::pair *args = static_cast *>(arg); TestOp* op = args->first; TestOp::CallbackInfo *info = args->second; op->finish(info); delete args; delete info; } ceph-0.80.11/src/test/osd/types.cc0000664000175100017510000010771412623076744020715 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "osd/osd_types.h" #include "osd/OSDMap.h" #include "gtest/gtest.h" #include "common/Thread.h" #include TEST(hobject, prefixes0) { uint32_t mask = 0xE947FA20; uint32_t bits = 12; int64_t pool = 0; set prefixes_correct; prefixes_correct.insert(string("0000000000000000.02A")); set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); ASSERT_EQ(prefixes_out, prefixes_correct); } TEST(hobject, prefixes1) { uint32_t mask = 0x0000000F; uint32_t bits = 6; int64_t pool = 20; set prefixes_correct; prefixes_correct.insert(string("0000000000000014.F0")); prefixes_correct.insert(string("0000000000000014.F4")); prefixes_correct.insert(string("0000000000000014.F8")); prefixes_correct.insert(string("0000000000000014.FC")); set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); ASSERT_EQ(prefixes_out, prefixes_correct); } TEST(hobject, prefixes2) { uint32_t mask = 0xDEADBEAF; uint32_t bits = 25; int64_t pool = 0; set prefixes_correct; prefixes_correct.insert(string("0000000000000000.FAEBDA0")); prefixes_correct.insert(string("0000000000000000.FAEBDA2")); prefixes_correct.insert(string("0000000000000000.FAEBDA4")); prefixes_correct.insert(string("0000000000000000.FAEBDA6")); prefixes_correct.insert(string("0000000000000000.FAEBDA8")); prefixes_correct.insert(string("0000000000000000.FAEBDAA")); prefixes_correct.insert(string("0000000000000000.FAEBDAC")); prefixes_correct.insert(string("0000000000000000.FAEBDAE")); set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); ASSERT_EQ(prefixes_out, prefixes_correct); } TEST(hobject, prefixes3) { uint32_t mask = 0xE947FA20; uint32_t bits = 32; int64_t pool = 0x23; set prefixes_correct; prefixes_correct.insert(string("0000000000000023.02AF749E")); set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); ASSERT_EQ(prefixes_out, prefixes_correct); } TEST(hobject, prefixes4) { uint32_t mask = 0xE947FA20; uint32_t bits = 0; int64_t pool = 0x23; set prefixes_correct; prefixes_correct.insert(string("0000000000000023.")); set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); ASSERT_EQ(prefixes_out, prefixes_correct); } TEST(hobject, prefixes5) { uint32_t mask = 0xDEADBEAF; uint32_t bits = 1; int64_t pool = 0x34AC5D00; set prefixes_correct; prefixes_correct.insert(string("0000000034AC5D00.1")); prefixes_correct.insert(string("0000000034AC5D00.3")); prefixes_correct.insert(string("0000000034AC5D00.5")); prefixes_correct.insert(string("0000000034AC5D00.7")); prefixes_correct.insert(string("0000000034AC5D00.9")); prefixes_correct.insert(string("0000000034AC5D00.B")); prefixes_correct.insert(string("0000000034AC5D00.D")); prefixes_correct.insert(string("0000000034AC5D00.F")); set prefixes_out(hobject_t::get_prefixes(bits, mask, pool)); ASSERT_EQ(prefixes_out, prefixes_correct); } TEST(pg_interval_t, check_new_interval) { // // Create a situation where osdmaps are the same so that // each test case can diverge from it using minimal code. // int osd_id = 1; epoch_t epoch = 40; ceph::shared_ptr osdmap(new OSDMap()); osdmap->set_max_osd(10); osdmap->set_state(osd_id, CEPH_OSD_EXISTS); osdmap->set_epoch(epoch); ceph::shared_ptr lastmap(new OSDMap()); lastmap->set_max_osd(10); lastmap->set_state(osd_id, CEPH_OSD_EXISTS); lastmap->set_epoch(epoch); epoch_t same_interval_since = epoch; epoch_t last_epoch_clean = same_interval_since; int64_t pool_id = 200; int pg_num = 4; __u8 min_size = 2; { OSDMap::Incremental inc(epoch + 1); inc.new_pools[pool_id].min_size = min_size; inc.new_pools[pool_id].set_pg_num(pg_num); inc.new_up_thru[osd_id] = epoch + 1; osdmap->apply_incremental(inc); lastmap->apply_incremental(inc); } vector new_acting; new_acting.push_back(osd_id); new_acting.push_back(osd_id + 1); vector old_acting = new_acting; int old_primary = osd_id; int new_primary = osd_id; vector new_up; new_up.push_back(osd_id); int old_up_primary = osd_id; int new_up_primary = osd_id; vector old_up = new_up; pg_t pgid; pgid.set_pool(pool_id); // // Do nothing if there are no modifications in // acting, up or pool size and that the pool is not // being split // { map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_FALSE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); ASSERT_TRUE(past_intervals.empty()); } // // pool did not exist in the old osdmap // { ceph::shared_ptr lastmap(new OSDMap()); lastmap->set_max_osd(10); lastmap->set_state(osd_id, CEPH_OSD_EXISTS); lastmap->set_epoch(epoch); map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); } // // The acting set has changed // { vector new_acting; int _new_primary = osd_id + 1; new_acting.push_back(_new_primary); map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); old_primary = new_primary; ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); } // // The up set has changed // { vector new_up; int _new_primary = osd_id + 1; new_up.push_back(_new_primary); map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); } // // The up primary has changed // { vector new_up; int _new_up_primary = osd_id + 1; map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, _new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); } // // PG is splitting // { ceph::shared_ptr osdmap(new OSDMap()); osdmap->set_max_osd(10); osdmap->set_state(osd_id, CEPH_OSD_EXISTS); osdmap->set_epoch(epoch); int new_pg_num = pg_num ^ 2; OSDMap::Incremental inc(epoch + 1); inc.new_pools[pool_id].min_size = min_size; inc.new_pools[pool_id].set_pg_num(new_pg_num); osdmap->apply_incremental(inc); map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); } // // PG size has changed // { ceph::shared_ptr osdmap(new OSDMap()); osdmap->set_max_osd(10); osdmap->set_state(osd_id, CEPH_OSD_EXISTS); osdmap->set_epoch(epoch); OSDMap::Incremental inc(epoch + 1); __u8 new_min_size = min_size + 1; inc.new_pools[pool_id].min_size = new_min_size; inc.new_pools[pool_id].set_pg_num(pg_num); osdmap->apply_incremental(inc); map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_EQ(same_interval_since, past_intervals[same_interval_since].first); ASSERT_EQ(osdmap->get_epoch() - 1, past_intervals[same_interval_since].last); ASSERT_EQ(osd_id, past_intervals[same_interval_since].acting[0]); ASSERT_EQ(osd_id, past_intervals[same_interval_since].up[0]); } // // The old acting set was empty : the previous interval could not // have been rw // { vector old_acting; map past_intervals; ostringstream out; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals, &out)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); ASSERT_NE(string::npos, out.str().find("acting set is too small")); } // // The old acting set did not have enough osd : it could // not have been rw // { vector old_acting; old_acting.push_back(osd_id); // // see http://tracker.ceph.com/issues/5780 // the size of the old acting set should be compared // with the min_size of the old osdmap // // The new osdmap is created so that it triggers the // bug. // ceph::shared_ptr osdmap(new OSDMap()); osdmap->set_max_osd(10); osdmap->set_state(osd_id, CEPH_OSD_EXISTS); osdmap->set_epoch(epoch); OSDMap::Incremental inc(epoch + 1); __u8 new_min_size = old_acting.size(); inc.new_pools[pool_id].min_size = new_min_size; inc.new_pools[pool_id].set_pg_num(pg_num); osdmap->apply_incremental(inc); ostringstream out; map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals, &out)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); ASSERT_NE(string::npos, out.str().find("acting set is too small")); } // // The acting set changes. The old acting set primary was up during the // previous interval and may have been rw. // { vector new_acting; new_acting.push_back(osd_id + 4); new_acting.push_back(osd_id + 5); ostringstream out; map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals, &out)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_TRUE(past_intervals[same_interval_since].maybe_went_rw); ASSERT_NE(string::npos, out.str().find("includes interval")); } // // The acting set changes. The old acting set primary was not up // during the old interval but last_epoch_clean is in the // old interval and it may have been rw. // { vector new_acting; new_acting.push_back(osd_id + 4); new_acting.push_back(osd_id + 5); ceph::shared_ptr lastmap(new OSDMap()); lastmap->set_max_osd(10); lastmap->set_state(osd_id, CEPH_OSD_EXISTS); lastmap->set_epoch(epoch); OSDMap::Incremental inc(epoch + 1); inc.new_pools[pool_id].min_size = min_size; inc.new_pools[pool_id].set_pg_num(pg_num); inc.new_up_thru[osd_id] = epoch - 10; lastmap->apply_incremental(inc); ostringstream out; map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals, &out)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_TRUE(past_intervals[same_interval_since].maybe_went_rw); ASSERT_NE(string::npos, out.str().find("presumed to have been rw")); } // // The acting set changes. The old acting set primary was not up // during the old interval and last_epoch_clean is before the // old interval : the previous interval could not possibly have // been rw. // { vector new_acting; new_acting.push_back(osd_id + 4); new_acting.push_back(osd_id + 5); epoch_t last_epoch_clean = epoch - 10; ceph::shared_ptr lastmap(new OSDMap()); lastmap->set_max_osd(10); lastmap->set_state(osd_id, CEPH_OSD_EXISTS); lastmap->set_epoch(epoch); OSDMap::Incremental inc(epoch + 1); inc.new_pools[pool_id].min_size = min_size; inc.new_pools[pool_id].set_pg_num(pg_num); inc.new_up_thru[osd_id] = last_epoch_clean; lastmap->apply_incremental(inc); ostringstream out; map past_intervals; ASSERT_TRUE(past_intervals.empty()); ASSERT_TRUE(pg_interval_t::check_new_interval(old_primary, new_primary, old_acting, new_acting, old_up_primary, new_up_primary, old_up, new_up, same_interval_since, last_epoch_clean, osdmap, lastmap, pool_id, pgid, &past_intervals, &out)); ASSERT_EQ((unsigned int)1, past_intervals.size()); ASSERT_FALSE(past_intervals[same_interval_since].maybe_went_rw); ASSERT_NE(string::npos, out.str().find("does not include interval")); } } TEST(pg_t, get_ancestor) { ASSERT_EQ(pg_t(0, 0, -1), pg_t(16, 0, -1).get_ancestor(16)); ASSERT_EQ(pg_t(1, 0, -1), pg_t(17, 0, -1).get_ancestor(16)); ASSERT_EQ(pg_t(0, 0, -1), pg_t(16, 0, -1).get_ancestor(8)); ASSERT_EQ(pg_t(16, 0, -1), pg_t(16, 0, -1).get_ancestor(80)); ASSERT_EQ(pg_t(16, 0, -1), pg_t(16, 0, -1).get_ancestor(83)); ASSERT_EQ(pg_t(1, 0, -1), pg_t(1321, 0, -1).get_ancestor(123).get_ancestor(8)); ASSERT_EQ(pg_t(3, 0, -1), pg_t(1323, 0, -1).get_ancestor(123).get_ancestor(8)); ASSERT_EQ(pg_t(3, 0, -1), pg_t(1323, 0, -1).get_ancestor(8)); } TEST(pg_t, split) { pg_t pgid(0, 0, -1); set s; bool b; s.clear(); b = pgid.is_split(1, 1, &s); ASSERT_TRUE(!b); s.clear(); b = pgid.is_split(2, 4, NULL); ASSERT_TRUE(b); b = pgid.is_split(2, 4, &s); ASSERT_TRUE(b); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(s.count(pg_t(2, 0, -1))); s.clear(); b = pgid.is_split(2, 8, &s); ASSERT_TRUE(b); ASSERT_EQ(3u, s.size()); ASSERT_TRUE(s.count(pg_t(2, 0, -1))); ASSERT_TRUE(s.count(pg_t(4, 0, -1))); ASSERT_TRUE(s.count(pg_t(6, 0, -1))); s.clear(); b = pgid.is_split(3, 8, &s); ASSERT_TRUE(b); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(s.count(pg_t(4, 0, -1))); s.clear(); b = pgid.is_split(6, 8, NULL); ASSERT_TRUE(!b); b = pgid.is_split(6, 8, &s); ASSERT_TRUE(!b); ASSERT_EQ(0u, s.size()); pgid = pg_t(1, 0, -1); s.clear(); b = pgid.is_split(2, 4, &s); ASSERT_TRUE(b); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(s.count(pg_t(3, 0, -1))); s.clear(); b = pgid.is_split(2, 6, &s); ASSERT_TRUE(b); ASSERT_EQ(2u, s.size()); ASSERT_TRUE(s.count(pg_t(3, 0, -1))); ASSERT_TRUE(s.count(pg_t(5, 0, -1))); s.clear(); b = pgid.is_split(2, 8, &s); ASSERT_TRUE(b); ASSERT_EQ(3u, s.size()); ASSERT_TRUE(s.count(pg_t(3, 0, -1))); ASSERT_TRUE(s.count(pg_t(5, 0, -1))); ASSERT_TRUE(s.count(pg_t(7, 0, -1))); s.clear(); b = pgid.is_split(4, 8, &s); ASSERT_TRUE(b); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(s.count(pg_t(5, 0, -1))); s.clear(); b = pgid.is_split(3, 8, &s); ASSERT_TRUE(b); ASSERT_EQ(3u, s.size()); ASSERT_TRUE(s.count(pg_t(3, 0, -1))); ASSERT_TRUE(s.count(pg_t(5, 0, -1))); ASSERT_TRUE(s.count(pg_t(7, 0, -1))); s.clear(); b = pgid.is_split(6, 8, &s); ASSERT_TRUE(!b); ASSERT_EQ(0u, s.size()); pgid = pg_t(3, 0, -1); s.clear(); b = pgid.is_split(7, 8, &s); ASSERT_TRUE(b); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(s.count(pg_t(7, 0, -1))); s.clear(); b = pgid.is_split(7, 12, &s); ASSERT_TRUE(b); ASSERT_EQ(2u, s.size()); ASSERT_TRUE(s.count(pg_t(7, 0, -1))); ASSERT_TRUE(s.count(pg_t(11, 0, -1))); s.clear(); b = pgid.is_split(7, 11, &s); ASSERT_TRUE(b); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(s.count(pg_t(7, 0, -1))); } TEST(pg_missing_t, constructor) { pg_missing_t missing; EXPECT_EQ((unsigned int)0, missing.num_missing()); EXPECT_FALSE(missing.have_missing()); } TEST(pg_missing_t, have_missing) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.have_missing()); missing.add(oid, eversion_t(), eversion_t()); EXPECT_TRUE(missing.have_missing()); } TEST(pg_missing_t, swap) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.have_missing()); missing.add(oid, eversion_t(), eversion_t()); EXPECT_TRUE(missing.have_missing()); pg_missing_t other; EXPECT_FALSE(other.have_missing()); other.swap(missing); EXPECT_FALSE(missing.have_missing()); EXPECT_TRUE(other.have_missing()); } TEST(pg_missing_t, is_missing) { // pg_missing_t::is_missing(const hobject_t& oid) const { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.is_missing(oid)); missing.add(oid, eversion_t(), eversion_t()); EXPECT_TRUE(missing.is_missing(oid)); } // bool pg_missing_t::is_missing(const hobject_t& oid, eversion_t v) const { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; eversion_t need(10,5); EXPECT_FALSE(missing.is_missing(oid, eversion_t())); missing.add(oid, need, eversion_t()); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_FALSE(missing.is_missing(oid, eversion_t())); EXPECT_TRUE(missing.is_missing(oid, need)); } } TEST(pg_missing_t, have_old) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_EQ(eversion_t(), missing.have_old(oid)); missing.add(oid, eversion_t(), eversion_t()); EXPECT_EQ(eversion_t(), missing.have_old(oid)); eversion_t have(1,1); missing.revise_have(oid, have); EXPECT_EQ(have, missing.have_old(oid)); } TEST(pg_missing_t, add_next_event) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); hobject_t oid_other(object_t("other"), "key", 9123, 9456, 0, ""); eversion_t version(10,5); eversion_t prior_version(3,4); pg_log_entry_t sample_e(pg_log_entry_t::DELETE, oid, version, prior_version, 0, osd_reqid_t(entity_name_t::CLIENT(777), 8, 999), utime_t(8,9)); // new object (MODIFY) { pg_missing_t missing; pg_log_entry_t e = sample_e; e.op = pg_log_entry_t::MODIFY; e.prior_version = eversion_t(); EXPECT_TRUE(e.is_update()); EXPECT_FALSE(missing.is_missing(oid)); missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(eversion_t(), missing.missing[oid].have); EXPECT_EQ(oid, missing.rmissing[e.version.version]); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); // adding the same object replaces the previous one missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); } // new object (CLONE) { pg_missing_t missing; pg_log_entry_t e = sample_e; e.op = pg_log_entry_t::CLONE; e.prior_version = eversion_t(); EXPECT_TRUE(e.is_clone()); EXPECT_FALSE(missing.is_missing(oid)); missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(eversion_t(), missing.missing[oid].have); EXPECT_EQ(oid, missing.rmissing[e.version.version]); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); // adding the same object replaces the previous one missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); } // existing object (MODIFY) { pg_missing_t missing; pg_log_entry_t e = sample_e; e.op = pg_log_entry_t::MODIFY; e.prior_version = eversion_t(); EXPECT_TRUE(e.is_update()); EXPECT_FALSE(missing.is_missing(oid)); missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(eversion_t(), missing.missing[oid].have); EXPECT_EQ(oid, missing.rmissing[e.version.version]); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); // adding the same object with a different version e.prior_version = prior_version; missing.add_next_event(e); EXPECT_EQ(eversion_t(), missing.missing[oid].have); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); } // object with prior version (MODIFY) { pg_missing_t missing; pg_log_entry_t e = sample_e; e.op = pg_log_entry_t::MODIFY; EXPECT_TRUE(e.is_update()); EXPECT_FALSE(missing.is_missing(oid)); missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(prior_version, missing.missing[oid].have); EXPECT_EQ(version, missing.missing[oid].need); EXPECT_EQ(oid, missing.rmissing[e.version.version]); EXPECT_EQ(1U, missing.num_missing()); EXPECT_EQ(1U, missing.rmissing.size()); } // obsolete (BACKLOG) { pg_missing_t missing; pg_log_entry_t e = sample_e; e.op = pg_log_entry_t::BACKLOG; EXPECT_TRUE(e.is_backlog()); EXPECT_FALSE(missing.is_missing(oid)); EXPECT_THROW(missing.add_next_event(e), FailedAssertion); } // adding a DELETE matching an existing event { pg_missing_t missing; pg_log_entry_t e = sample_e; e.op = pg_log_entry_t::MODIFY; EXPECT_TRUE(e.is_update()); EXPECT_FALSE(missing.is_missing(oid)); missing.add_next_event(e); EXPECT_TRUE(missing.is_missing(oid)); e.op = pg_log_entry_t::DELETE; EXPECT_TRUE(e.is_delete()); missing.add_next_event(e); EXPECT_FALSE(missing.have_missing()); } } TEST(pg_missing_t, revise_need) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; // create a new entry EXPECT_FALSE(missing.is_missing(oid)); eversion_t need(10,10); missing.revise_need(oid, need); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(eversion_t(), missing.missing[oid].have); EXPECT_EQ(need, missing.missing[oid].need); // update an existing entry and preserve have eversion_t have(1,1); missing.revise_have(oid, have); eversion_t new_need(10,12); EXPECT_EQ(have, missing.missing[oid].have); missing.revise_need(oid, new_need); EXPECT_EQ(have, missing.missing[oid].have); EXPECT_EQ(new_need, missing.missing[oid].need); } TEST(pg_missing_t, revise_have) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; // a non existing entry means noop EXPECT_FALSE(missing.is_missing(oid)); eversion_t have(1,1); missing.revise_have(oid, have); EXPECT_FALSE(missing.is_missing(oid)); // update an existing entry eversion_t need(10,12); missing.add(oid, need, have); EXPECT_TRUE(missing.is_missing(oid)); eversion_t new_have(2,2); EXPECT_EQ(have, missing.missing[oid].have); missing.revise_have(oid, new_have); EXPECT_EQ(new_have, missing.missing[oid].have); EXPECT_EQ(need, missing.missing[oid].need); } TEST(pg_missing_t, add) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.is_missing(oid)); eversion_t have(1,1); eversion_t need(10,10); missing.add(oid, need, have); EXPECT_TRUE(missing.is_missing(oid)); EXPECT_EQ(have, missing.missing[oid].have); EXPECT_EQ(need, missing.missing[oid].need); } TEST(pg_missing_t, rm) { // void pg_missing_t::rm(const hobject_t& oid, eversion_t v) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.is_missing(oid)); epoch_t epoch = 10; eversion_t need(epoch,10); missing.add(oid, need, eversion_t()); EXPECT_TRUE(missing.is_missing(oid)); // rm of an older version is a noop missing.rm(oid, eversion_t(epoch / 2,20)); EXPECT_TRUE(missing.is_missing(oid)); // rm of a later version removes the object missing.rm(oid, eversion_t(epoch * 2,20)); EXPECT_FALSE(missing.is_missing(oid)); } // void pg_missing_t::rm(const std::map::iterator &m) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.is_missing(oid)); missing.add(oid, eversion_t(), eversion_t()); EXPECT_TRUE(missing.is_missing(oid)); const std::map::iterator m = missing.missing.find(oid); missing.rm(m); EXPECT_FALSE(missing.is_missing(oid)); } } TEST(pg_missing_t, got) { // void pg_missing_t::got(const hobject_t& oid, eversion_t v) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; // assert if the oid does not exist EXPECT_THROW(missing.got(oid, eversion_t()), FailedAssertion); EXPECT_FALSE(missing.is_missing(oid)); epoch_t epoch = 10; eversion_t need(epoch,10); missing.add(oid, need, eversion_t()); EXPECT_TRUE(missing.is_missing(oid)); // assert if that the version to be removed is lower than the version of the object EXPECT_THROW(missing.got(oid, eversion_t(epoch / 2,20)), FailedAssertion); // remove of a later version removes the object missing.got(oid, eversion_t(epoch * 2,20)); EXPECT_FALSE(missing.is_missing(oid)); } // void pg_missing_t::got(const std::map::iterator &m) { hobject_t oid(object_t("objname"), "key", 123, 456, 0, ""); pg_missing_t missing; EXPECT_FALSE(missing.is_missing(oid)); missing.add(oid, eversion_t(), eversion_t()); EXPECT_TRUE(missing.is_missing(oid)); const std::map::iterator m = missing.missing.find(oid); missing.got(m); EXPECT_FALSE(missing.is_missing(oid)); } } TEST(pg_missing_t, split_into) { uint32_t hash1 = 1; hobject_t oid1(object_t("objname"), "key1", 123, hash1, 0, ""); uint32_t hash2 = 2; hobject_t oid2(object_t("objname"), "key2", 123, hash2, 0, ""); pg_missing_t missing; missing.add(oid1, eversion_t(), eversion_t()); missing.add(oid2, eversion_t(), eversion_t()); pg_t child_pgid; child_pgid.m_seed = 1; pg_missing_t child; unsigned split_bits = 1; missing.split_into(child_pgid, split_bits, &child); EXPECT_TRUE(child.is_missing(oid1)); EXPECT_FALSE(child.is_missing(oid2)); EXPECT_FALSE(missing.is_missing(oid1)); EXPECT_TRUE(missing.is_missing(oid2)); } class ObjectContextTest : public ::testing::Test { protected: static const useconds_t DELAY_MAX = 20 * 1000 * 1000; class Thread_read_lock : public Thread { public: ObjectContext &obc; Thread_read_lock(ObjectContext& _obc) : obc(_obc) { } virtual void *entry() { obc.ondisk_read_lock(); return NULL; } }; class Thread_write_lock : public Thread { public: ObjectContext &obc; Thread_write_lock(ObjectContext& _obc) : obc(_obc) { } virtual void *entry() { obc.ondisk_write_lock(); return NULL; } }; }; TEST_F(ObjectContextTest, read_write_lock) { { ObjectContext obc; // // write_lock // write_lock // write_unlock // write_unlock // EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); obc.ondisk_write_lock(); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(1, obc.unstable_writes); obc.ondisk_write_lock(); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(2, obc.unstable_writes); obc.ondisk_write_unlock(); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(1, obc.unstable_writes); obc.ondisk_write_unlock(); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); } useconds_t delay = 0; { ObjectContext obc; // // write_lock // read_lock => wait // write_unlock => signal // read_unlock // EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); obc.ondisk_write_lock(); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(1, obc.unstable_writes); Thread_read_lock t(obc); t.create(); do { cout << "Trying (1) with delay " << delay << "us\n"; usleep(delay); } while (obc.readers_waiting == 0 && ( delay = delay * 2 + 1) < DELAY_MAX); EXPECT_EQ(1, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(1, obc.unstable_writes); obc.ondisk_write_unlock(); do { cout << "Trying (2) with delay " << delay << "us\n"; usleep(delay); } while ((obc.readers == 0 || obc.readers_waiting == 1) && ( delay = delay * 2 + 1) < DELAY_MAX); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(1, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); obc.ondisk_read_unlock(); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); t.join(); } { ObjectContext obc; // // read_lock // write_lock => wait // read_unlock => signal // write_unlock // EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); obc.ondisk_read_lock(); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(1, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); Thread_write_lock t(obc); t.create(); do { cout << "Trying (3) with delay " << delay << "us\n"; usleep(delay); } while ((obc.writers_waiting == 0) && ( delay = delay * 2 + 1) < DELAY_MAX); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(1, obc.readers); EXPECT_EQ(1, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); obc.ondisk_read_unlock(); do { cout << "Trying (4) with delay " << delay << "us\n"; usleep(delay); } while ((obc.unstable_writes == 0 || obc.writers_waiting == 1) && ( delay = delay * 2 + 1) < DELAY_MAX); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(1, obc.unstable_writes); obc.ondisk_write_unlock(); EXPECT_EQ(0, obc.readers_waiting); EXPECT_EQ(0, obc.readers); EXPECT_EQ(0, obc.writers_waiting); EXPECT_EQ(0, obc.unstable_writes); t.join(); } } TEST(pg_pool_t_test, get_pg_num_divisor) { pg_pool_t p; p.set_pg_num(16); p.set_pgp_num(16); for (int i = 0; i < 16; ++i) ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(i, 1))); p.set_pg_num(12); p.set_pgp_num(12); //cout << "num " << p.get_pg_num() // << " mask " << p.get_pg_num_mask() << std::endl; ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(0, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(1, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(2, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(3, 1))); ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(4, 1))); ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(5, 1))); ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(6, 1))); ASSERT_EQ(8u, p.get_pg_num_divisor(pg_t(7, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(8, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(9, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(10, 1))); ASSERT_EQ(16u, p.get_pg_num_divisor(pg_t(11, 1))); } TEST(pg_pool_t_test, get_random_pg_position) { srand(getpid()); for (int i = 0; i < 100; ++i) { pg_pool_t p; p.set_pg_num(1 + (rand() % 1000)); p.set_pgp_num(p.get_pg_num()); pg_t pgid(rand() % p.get_pg_num(), 1); uint32_t h = p.get_random_pg_position(pgid, rand()); uint32_t ps = p.raw_hash_to_pg(h); cout << p.get_pg_num() << " " << pgid << ": " << h << " -> " << pg_t(ps, 1) << std::endl; ASSERT_EQ(pgid.ps(), ps); } } /* * Local Variables: * compile-command: "cd .. ; * make unittest_osd_types ; * ./unittest_osd_types # --gtest_filter=pg_missing_t.constructor * " * End: */ ceph-0.80.11/src/test/osd/hitset.cc0000664000175100017510000001210512623076744021036 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * Copyright 2013 Inktank */ #include "gtest/gtest.h" #include "osd/HitSet.h" #include class HitSetTestStrap { public: HitSet *hitset; HitSetTestStrap(HitSet *h) : hitset(h) {} void fill(unsigned count) { char buf[50]; for (unsigned i = 0; i < count; ++i) { sprintf(buf, "hitsettest_%d", i); hobject_t obj(object_t(buf), "", 0, i, 0, ""); hitset->insert(obj); } EXPECT_EQ(count, hitset->insert_count()); } void verify_fill(unsigned count) { char buf[50]; for (unsigned i = 0; i < count; ++i) { sprintf(buf, "hitsettest_%d", i); hobject_t obj(object_t(buf), "", 0, i, 0, ""); EXPECT_TRUE(hitset->contains(obj)); } } }; class BloomHitSetTest : public testing::Test, public HitSetTestStrap { public: BloomHitSetTest() : HitSetTestStrap(new HitSet(new BloomHitSet)) {} void rebuild(double fp, uint64_t target, uint64_t seed) { BloomHitSet::Params *bparams = new BloomHitSet::Params(fp, target, seed); HitSet::Params param(bparams); HitSet new_set(param); *hitset = new_set; } BloomHitSet *get_hitset() { return static_cast(hitset->impl.get()); } }; TEST_F(BloomHitSetTest, Params) { BloomHitSet::Params params(0.01, 100, 5); EXPECT_EQ(.01, params.get_fpp()); EXPECT_EQ((unsigned)100, params.target_size); EXPECT_EQ((unsigned)5, params.seed); params.set_fpp(0.1); EXPECT_EQ(0.1, params.get_fpp()); bufferlist bl; params.encode(bl); BloomHitSet::Params p2; bufferlist::iterator iter = bl.begin(); p2.decode(iter); EXPECT_EQ(0.1, p2.get_fpp()); EXPECT_EQ((unsigned)100, p2.target_size); EXPECT_EQ((unsigned)5, p2.seed); } TEST_F(BloomHitSetTest, Construct) { ASSERT_EQ(hitset->impl->get_type(), HitSet::TYPE_BLOOM); // success! } TEST_F(BloomHitSetTest, Rebuild) { rebuild(0.1, 100, 1); ASSERT_EQ(hitset->impl->get_type(), HitSet::TYPE_BLOOM); } TEST_F(BloomHitSetTest, InsertsMatch) { rebuild(0.1, 100, 1); fill(50); /* * the approx unique count is atrocious on bloom filters. Empirical * evidence suggests the current test will produce a value of 62 * regardless of hitset size */ EXPECT_TRUE(hitset->approx_unique_insert_count() >= 50 && hitset->approx_unique_insert_count() <= 62); verify_fill(50); EXPECT_FALSE(hitset->is_full()); } TEST_F(BloomHitSetTest, FillsUp) { rebuild(0.1, 20, 1); fill(20); verify_fill(20); EXPECT_TRUE(hitset->is_full()); } TEST_F(BloomHitSetTest, RejectsNoMatch) { rebuild(0.001, 100, 1); fill(100); verify_fill(100); EXPECT_TRUE(hitset->is_full()); char buf[50]; int matches = 0; for (int i = 100; i < 200; ++i) { sprintf(buf, "hitsettest_%d", i); hobject_t obj(object_t(buf), "", 0, i, 0, ""); if (hitset->contains(obj)) ++matches; } // we set a 1 in 1000 false positive; allow one in our 100 EXPECT_LT(matches, 2); } class ExplicitHashHitSetTest : public testing::Test, public HitSetTestStrap { public: ExplicitHashHitSetTest() : HitSetTestStrap(new HitSet(new ExplicitHashHitSet)) {} ExplicitHashHitSet *get_hitset() { return static_cast(hitset->impl.get()); } }; TEST_F(ExplicitHashHitSetTest, Construct) { ASSERT_EQ(hitset->impl->get_type(), HitSet::TYPE_EXPLICIT_HASH); // success! } TEST_F(ExplicitHashHitSetTest, InsertsMatch) { fill(50); verify_fill(50); EXPECT_EQ((unsigned)50, hitset->approx_unique_insert_count()); EXPECT_FALSE(hitset->is_full()); } TEST_F(ExplicitHashHitSetTest, RejectsNoMatch) { fill(100); verify_fill(100); EXPECT_FALSE(hitset->is_full()); char buf[50]; int matches = 0; for (int i = 100; i < 200; ++i) { sprintf(buf, "hitsettest_%d", i); hobject_t obj(object_t(buf), "", 0, i, 0, ""); if (hitset->contains(obj)) { ++matches; } } EXPECT_EQ(matches, 0); } class ExplicitObjectHitSetTest : public testing::Test, public HitSetTestStrap { public: ExplicitObjectHitSetTest() : HitSetTestStrap(new HitSet(new ExplicitObjectHitSet)) {} ExplicitObjectHitSet *get_hitset() { return static_cast(hitset->impl.get()); } }; TEST_F(ExplicitObjectHitSetTest, Construct) { ASSERT_EQ(hitset->impl->get_type(), HitSet::TYPE_EXPLICIT_OBJECT); // success! } TEST_F(ExplicitObjectHitSetTest, InsertsMatch) { fill(50); verify_fill(50); EXPECT_EQ((unsigned)50, hitset->approx_unique_insert_count()); EXPECT_FALSE(hitset->is_full()); } TEST_F(ExplicitObjectHitSetTest, RejectsNoMatch) { fill(100); verify_fill(100); EXPECT_FALSE(hitset->is_full()); char buf[50]; int matches = 0; for (int i = 100; i < 200; ++i) { sprintf(buf, "hitsettest_%d", i); hobject_t obj(object_t(buf), "", 0, i, 0, ""); if (hitset->contains(obj)) { ++matches; } } EXPECT_EQ(matches, 0); } ceph-0.80.11/src/test/osd/TestOSDMap.cc0000664000175100017510000003104712623076744021467 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "gtest/gtest.h" #include "osd/OSDMap.h" #include "global/global_context.h" #include "global/global_init.h" #include "common/common_init.h" #include using namespace std; int main(int argc, char **argv) { std::vector preargs; std::vector args(argv, argv+argc); global_init(&preargs, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); // make sure we have 3 copies, or some tests won't work g_ceph_context->_conf->set_val("osd_pool_default_size", "3", false); // our map is flat, so just try and split across OSDs, not hosts or whatever g_ceph_context->_conf->set_val("osd_crush_chooseleaf_type", "0", false); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } class OSDMapTest : public testing::Test { const static int num_osds = 6; public: OSDMap osdmap; OSDMapTest() {} void set_up_map() { uuid_d fsid; osdmap.build_simple(g_ceph_context, 0, fsid, num_osds, 6, 6); OSDMap::Incremental pending_inc(osdmap.get_epoch() + 1); pending_inc.fsid = osdmap.get_fsid(); entity_addr_t sample_addr; uuid_d sample_uuid; for (int i = 0; i < num_osds; ++i) { sample_uuid.uuid[i] = i; sample_addr.nonce = i; pending_inc.new_state[i] = CEPH_OSD_EXISTS | CEPH_OSD_NEW; pending_inc.new_up_client[i] = sample_addr; pending_inc.new_up_cluster[i] = sample_addr; pending_inc.new_hb_back_up[i] = sample_addr; pending_inc.new_hb_front_up[i] = sample_addr; pending_inc.new_weight[i] = CEPH_OSD_IN; pending_inc.new_uuid[i] = sample_uuid; } osdmap.apply_incremental(pending_inc); // Create an EC ruleset and a pool using it int r = osdmap.crush->add_simple_ruleset("erasure", "default", "osd", "indep", pg_pool_t::TYPE_ERASURE, &cerr); OSDMap::Incremental new_pool_inc(osdmap.get_epoch() + 1); new_pool_inc.new_pool_max = osdmap.get_pool_max(); new_pool_inc.fsid = osdmap.get_fsid(); pg_pool_t empty; uint64_t pool_id = ++new_pool_inc.new_pool_max; pg_pool_t *p = new_pool_inc.get_new_pool(pool_id, &empty); p->size = 3; p->set_pg_num(64); p->set_pgp_num(64); p->type = pg_pool_t::TYPE_ERASURE; p->crush_ruleset = r; new_pool_inc.new_pool_names[pool_id] = "ec"; osdmap.apply_incremental(new_pool_inc); } unsigned int get_num_osds() { return num_osds; } void test_mappings(int pool, int num, vector *any, vector *first, vector *primary) { for (int i=0; i o; int p; pg_t pgid(i, pool); osdmap.pg_to_acting_osds(pgid, &o, &p); for (unsigned j=0; j= 0) (*primary)[p]++; } } }; TEST_F(OSDMapTest, Create) { set_up_map(); ASSERT_EQ(get_num_osds(), (unsigned)osdmap.get_max_osd()); ASSERT_EQ(get_num_osds(), osdmap.get_num_in_osds()); } TEST_F(OSDMapTest, Features) { // with EC pool set_up_map(); uint64_t features = osdmap.get_features(CEPH_ENTITY_TYPE_OSD, NULL); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES2); ASSERT_FALSE(features & CEPH_FEATURE_CRUSH_TUNABLES3); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_V2); ASSERT_TRUE(features & CEPH_FEATURE_OSD_ERASURE_CODES); ASSERT_TRUE(features & CEPH_FEATURE_OSDHASHPSPOOL); ASSERT_FALSE(features & CEPH_FEATURE_OSD_PRIMARY_AFFINITY); // clients have a slightly different view features = osdmap.get_features(CEPH_ENTITY_TYPE_CLIENT, NULL); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES2); ASSERT_FALSE(features & CEPH_FEATURE_CRUSH_TUNABLES3); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_V2); ASSERT_FALSE(features & CEPH_FEATURE_OSD_ERASURE_CODES); // dont' need this ASSERT_TRUE(features & CEPH_FEATURE_OSDHASHPSPOOL); ASSERT_FALSE(features & CEPH_FEATURE_OSD_PRIMARY_AFFINITY); // remove teh EC pool, but leave the rule. add primary affinity. { OSDMap::Incremental new_pool_inc(osdmap.get_epoch() + 1); new_pool_inc.old_pools.insert(osdmap.lookup_pg_pool_name("ec")); new_pool_inc.new_primary_affinity[0] = 0x8000; osdmap.apply_incremental(new_pool_inc); } features = osdmap.get_features(CEPH_ENTITY_TYPE_MON, NULL); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES2); ASSERT_TRUE(features & CEPH_FEATURE_CRUSH_TUNABLES3); // shared bit with primary affinity ASSERT_FALSE(features & CEPH_FEATURE_CRUSH_V2); ASSERT_FALSE(features & CEPH_FEATURE_OSD_ERASURE_CODES); ASSERT_TRUE(features & CEPH_FEATURE_OSDHASHPSPOOL); ASSERT_TRUE(features & CEPH_FEATURE_OSD_PRIMARY_AFFINITY); // FIXME: test tiering feature bits } TEST_F(OSDMapTest, MapPG) { set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); vector old_up_osds, old_acting_osds; osdmap.pg_to_up_acting_osds(pgid, old_up_osds, old_acting_osds); ASSERT_EQ(old_up_osds, up_osds); ASSERT_EQ(old_acting_osds, acting_osds); ASSERT_EQ(osdmap.get_pg_pool(0)->get_size(), up_osds.size()); } TEST_F(OSDMapTest, MapFunctionsMatch) { // TODO: make sure pg_to_up_acting_osds and pg_to_acting_osds match set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); vector up_osds_two, acting_osds_two; osdmap.pg_to_up_acting_osds(pgid, up_osds_two, acting_osds_two); ASSERT_EQ(up_osds, up_osds_two); ASSERT_EQ(acting_osds, acting_osds_two); int acting_primary_two; osdmap.pg_to_acting_osds(pgid, &acting_osds_two, &acting_primary_two); EXPECT_EQ(acting_osds, acting_osds_two); EXPECT_EQ(acting_primary, acting_primary_two); osdmap.pg_to_acting_osds(pgid, acting_osds_two); EXPECT_EQ(acting_osds, acting_osds_two); } /** This test must be removed or modified appropriately when we allow * other ways to specify a primary. */ TEST_F(OSDMapTest, PrimaryIsFirst) { set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); EXPECT_EQ(up_osds[0], up_primary); EXPECT_EQ(acting_osds[0], acting_primary); } TEST_F(OSDMapTest, PGTempRespected) { set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); // copy and swap first and last element in acting_osds vector new_acting_osds(acting_osds); int first = new_acting_osds[0]; new_acting_osds[0] = *new_acting_osds.rbegin(); *new_acting_osds.rbegin() = first; // apply pg_temp to osdmap OSDMap::Incremental pgtemp_map(osdmap.get_epoch() + 1); pgtemp_map.new_pg_temp[pgid] = new_acting_osds; osdmap.apply_incremental(pgtemp_map); osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); EXPECT_EQ(new_acting_osds, acting_osds); } TEST_F(OSDMapTest, PrimaryTempRespected) { set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); // make second OSD primary via incremental OSDMap::Incremental pgtemp_map(osdmap.get_epoch() + 1); pgtemp_map.new_primary_temp[pgid] = acting_osds[1]; osdmap.apply_incremental(pgtemp_map); osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); EXPECT_EQ(acting_primary, acting_osds[1]); } TEST_F(OSDMapTest, RemovesRedundantTemps) { set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); // stick calculated values in to temps OSDMap::Incremental pgtemp_map(osdmap.get_epoch() + 1); pgtemp_map.new_pg_temp[pgid] = up_osds; pgtemp_map.new_primary_temp[pgid] = up_primary; osdmap.apply_incremental(pgtemp_map); OSDMap::Incremental pending_inc(osdmap.get_epoch() + 1); OSDMap::remove_redundant_temporaries(g_ceph_context, osdmap, &pending_inc); EXPECT_TRUE(pending_inc.new_pg_temp.count(pgid) && pending_inc.new_pg_temp[pgid].size() == 0); EXPECT_EQ(-1, pending_inc.new_primary_temp[pgid]); } TEST_F(OSDMapTest, KeepsNecessaryTemps) { set_up_map(); pg_t rawpg(0, 0, -1); pg_t pgid = osdmap.raw_pg_to_pg(rawpg); vector up_osds, acting_osds; int up_primary, acting_primary; osdmap.pg_to_up_acting_osds(pgid, &up_osds, &up_primary, &acting_osds, &acting_primary); // find unused OSD and stick it in there OSDMap::Incremental pgtemp_map(osdmap.get_epoch() + 1); // find an unused osd and put it in place of the first one int i = 0; for(; i != (int)get_num_osds(); ++i) { bool in_use = false; for (vector::iterator osd_it = up_osds.begin(); osd_it != up_osds.end(); ++osd_it) { if (i == *osd_it) { in_use = true; break; } } if (!in_use) { up_osds[1] = i; break; } } if (i == (int)get_num_osds()) ASSERT_EQ(0, "did not find unused OSD for temp mapping"); pgtemp_map.new_pg_temp[pgid] = up_osds; pgtemp_map.new_primary_temp[pgid] = up_osds[1]; osdmap.apply_incremental(pgtemp_map); OSDMap::Incremental pending_inc(osdmap.get_epoch() + 1); OSDMap::remove_redundant_temporaries(g_ceph_context, osdmap, &pending_inc); EXPECT_FALSE(pending_inc.new_pg_temp.count(pgid)); EXPECT_FALSE(pending_inc.new_primary_temp.count(pgid)); } TEST_F(OSDMapTest, PrimaryAffinity) { set_up_map(); /* osdmap.print(cout); Formatter *f = new_formatter("json-pretty"); f->open_object_section("CRUSH"); osdmap.crush->dump(f); f->close_section(); f->flush(cout); delete f; */ int n = get_num_osds(); for (map::const_iterator p = osdmap.get_pools().begin(); p != osdmap.get_pools().end(); ++p) { int pool = p->first; cout << "pool " << pool << std::endl; { vector any(n, 0); vector first(n, 0); vector primary(n, 0); test_mappings(0, 10000, &any, &first, &primary); for (int i=0; i any(n, 0); vector first(n, 0); vector primary(n, 0); test_mappings(pool, 10000, &any, &first, &primary); for (int i=0; i= 2) { ASSERT_LT(0, first[i]); ASSERT_LT(0, primary[i]); } else { if (p->second.is_replicated()) ASSERT_EQ(0, first[i]); ASSERT_EQ(0, primary[i]); } } } osdmap.set_primary_affinity(0, 0x8000); osdmap.set_primary_affinity(1, 0); { vector any(n, 0); vector first(n, 0); vector primary(n, 0); test_mappings(pool, 10000, &any, &first, &primary); for (int i=0; i= 2) { ASSERT_LT(0, first[i]); ASSERT_LT(0, primary[i]); } else if (i == 1) { if (p->second.is_replicated()) ASSERT_EQ(0, first[i]); ASSERT_EQ(0, primary[i]); } else { ASSERT_LT(10000/6/4, primary[0]); ASSERT_GT(10000/6/4*3, primary[0]); } } } osdmap.set_primary_affinity(0, 0x10000); osdmap.set_primary_affinity(1, 0x10000); } } ceph-0.80.11/src/test/osd/TestOpStat.cc0000664000175100017510000000301112623076744021604 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/interval_set.h" #include "include/buffer.h" #include #include #include #include "RadosModel.h" #include "TestOpStat.h" void TestOpStat::begin(TestOp *in) { stat_lock.Lock(); stats[in->getType()].begin(in); stat_lock.Unlock(); } void TestOpStat::end(TestOp *in) { stat_lock.Lock(); stats[in->getType()].end(in); stat_lock.Unlock(); } void TestOpStat::TypeStatus::export_latencies(map &in) const { map::iterator i = in.begin(); multiset::iterator j = latencies.begin(); int count = 0; while (j != latencies.end() && i != in.end()) { count++; if ((((double)count)/((double)latencies.size())) * 100 >= i->first) { i->second = *j; ++i; } ++j; } } std::ostream & operator<<(std::ostream &out, TestOpStat &rhs) { rhs.stat_lock.Lock(); for (map::iterator i = rhs.stats.begin(); i != rhs.stats.end(); ++i) { map latency; latency[10] = 0; latency[50] = 0; latency[90] = 0; latency[99] = 0; i->second.export_latencies(latency); out << i->first << " latency: " << std::endl; for (map::iterator j = latency.begin(); j != latency.end(); ++j) { if (j->second == 0) break; out << "\t" << j->first << "th percentile: " << j->second / 1000 << "ms" << std::endl; } } rhs.stat_lock.Unlock(); return out; } ceph-0.80.11/src/test/osd/osd-test-helpers.sh0000664000175100017510000000317212623076744022771 0ustar jenkins-buildjenkins-build#!/bin/bash # # Copyright (C) 2014 Cloudwatt # # Author: Loic Dachary # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library Public License for more details. # function run_osd() { local dir=$1 shift local id=$1 shift local osd_data=$dir/$id local ceph_disk_args ceph_disk_args+=" --statedir=$dir" ceph_disk_args+=" --sysconfdir=$dir" ceph_disk_args+=" --prepend-to-path=" ceph_disk_args+=" --verbose" touch $dir/ceph.conf ./ceph-disk $ceph_disk_args \ prepare $osd_data || return 1 local ceph_args="$CEPH_ARGS" ceph_args+=" --osd-journal-size=100" ceph_args+=" --osd-data=$osd_data" ceph_args+=" --chdir=" ceph_args+=" --osd-pool-default-erasure-code-directory=.libs" ceph_args+=" --run-dir=$dir" ceph_args+=" --debug-osd=20" ceph_args+=" --log-file=$dir/osd-\$id.log" ceph_args+=" --pid-file=$dir/osd-\$id.pidfile" ceph_args+=" " ceph_args+="$@" CEPH_ARGS="$ceph_args" ./ceph-disk $ceph_disk_args \ activate \ --mark-init=none \ $osd_data || return 1 [ "$id" = "$(cat $osd_data/whoami)" ] || return 1 ./ceph osd crush create-or-move "$id" 1 root=default host=localhost } ceph-0.80.11/src/test/osd/TestRados.cc0000664000175100017510000002662212623076744021457 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "common/Mutex.h" #include "common/Cond.h" #include "common/errno.h" #include "common/version.h" #include #include #include #include #include #include #include #include #include "test/osd/RadosModel.h" using namespace std; class WeightedTestGenerator : public TestOpGenerator { public: WeightedTestGenerator(int ops, int objects, map op_weights, TestOpStat *stats, int max_seconds, bool ec_pool) : m_nextop(NULL), m_op(0), m_ops(ops), m_seconds(max_seconds), m_objects(objects), m_stats(stats), m_total_weight(0), m_ec_pool(ec_pool) { m_start = time(0); for (map::const_iterator it = op_weights.begin(); it != op_weights.end(); ++it) { m_total_weight += it->second; m_weight_sums.insert(pair(it->first, m_total_weight)); } } TestOp *next(RadosTestContext &context) { TestOp *retval = NULL; ++m_op; if (m_op <= m_objects) { stringstream oid; oid << m_op; cout << m_op << ": write initial oid " << oid.str() << std::endl; context.oid_not_flushing.insert(oid.str()); if (m_ec_pool) { return new WriteOp(m_op, &context, oid.str(), true); } else { return new WriteOp(m_op, &context, oid.str(), false); } } else if (m_op >= m_ops) { return NULL; } if (m_nextop) { retval = m_nextop; m_nextop = NULL; return retval; } while (retval == NULL) { unsigned int rand_val = rand() % m_total_weight; time_t now = time(0); if (m_seconds && now - m_start > m_seconds) break; for (map::const_iterator it = m_weight_sums.begin(); it != m_weight_sums.end(); ++it) { if (rand_val < it->second) { retval = gen_op(context, it->first); break; } } } return retval; } private: TestOp *gen_op(RadosTestContext &context, TestOpType type) { string oid, oid2; //cout << "oids not in use " << context.oid_not_in_use.size() << std::endl; assert(context.oid_not_in_use.size()); switch (type) { case TEST_OP_READ: oid = *(rand_choose(context.oid_not_in_use)); return new ReadOp(m_op, &context, oid, m_stats); case TEST_OP_WRITE: oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "write oid " << oid << " current snap is " << context.current_snap << std::endl; return new WriteOp(m_op, &context, oid, false, m_stats); case TEST_OP_DELETE: oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "delete oid " << oid << " current snap is " << context.current_snap << std::endl; return new DeleteOp(m_op, &context, oid, m_stats); case TEST_OP_SNAP_CREATE: cout << m_op << ": " << "snap_create" << std::endl; return new SnapCreateOp(m_op, &context, m_stats); case TEST_OP_SNAP_REMOVE: if (context.snaps.size() <= context.snaps_in_use.size()) { return NULL; } while (true) { int snap = rand_choose(context.snaps)->first; if (context.snaps_in_use.lookup(snap)) continue; // in use; try again! cout << m_op << ": " << "snap_remove snap " << snap << std::endl; return new SnapRemoveOp(m_op, &context, snap, m_stats); } case TEST_OP_ROLLBACK: { string oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "rollback oid " << oid << " current snap is " << context.current_snap << std::endl; return new RollbackOp(m_op, &context, oid); } case TEST_OP_SETATTR: oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "setattr oid " << oid << " current snap is " << context.current_snap << std::endl; return new SetAttrsOp(m_op, &context, oid, m_stats); case TEST_OP_RMATTR: oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "rmattr oid " << oid << " current snap is " << context.current_snap << std::endl; return new RemoveAttrsOp(m_op, &context, oid, m_stats); case TEST_OP_WATCH: oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "watch oid " << oid << " current snap is " << context.current_snap << std::endl; return new WatchOp(m_op, &context, oid, m_stats); case TEST_OP_COPY_FROM: oid = *(rand_choose(context.oid_not_in_use)); do { oid2 = *(rand_choose(context.oid_not_in_use)); } while (oid == oid2); cout << m_op << ": " << "copy_from oid " << oid << " from oid " << oid2 << " current snap is " << context.current_snap << std::endl; return new CopyFromOp(m_op, &context, oid, oid2, m_stats); case TEST_OP_HIT_SET_LIST: { uint32_t hash = rjhash32(rand()); cout << m_op << ": " << "hit_set_list " << hash << std::endl; return new HitSetListOp(m_op, &context, hash, m_stats); } case TEST_OP_UNDIRTY: { oid = *(rand_choose(context.oid_not_in_use)); cout << m_op << ": " << "undirty oid " << oid << std::endl; return new UndirtyOp(m_op, &context, oid, m_stats); } case TEST_OP_IS_DIRTY: { oid = *(rand_choose(context.oid_not_flushing)); return new IsDirtyOp(m_op, &context, oid, m_stats); } case TEST_OP_CACHE_FLUSH: { oid = *(rand_choose(context.oid_not_in_use)); return new CacheFlushOp(m_op, &context, oid, m_stats, true); } case TEST_OP_CACHE_TRY_FLUSH: { oid = *(rand_choose(context.oid_not_in_use)); return new CacheFlushOp(m_op, &context, oid, m_stats, false); } case TEST_OP_CACHE_EVICT: { oid = *(rand_choose(context.oid_not_in_use)); return new CacheEvictOp(m_op, &context, oid, m_stats); } case TEST_OP_APPEND: oid = *(rand_choose(context.oid_not_in_use)); cout << "append oid " << oid << " current snap is " << context.current_snap << std::endl; return new WriteOp(m_op, &context, oid, true, m_stats); default: cerr << m_op << ": Invalid op type " << type << std::endl; assert(0); } } TestOp *m_nextop; int m_op; int m_ops; int m_seconds; int m_objects; time_t m_start; TestOpStat *m_stats; map m_weight_sums; unsigned int m_total_weight; bool m_ec_pool; }; int main(int argc, char **argv) { int ops = 1000; int objects = 50; int max_in_flight = 16; int64_t size = 4000000; // 4 MB int64_t min_stride_size = -1, max_stride_size = -1; int max_seconds = 0; bool pool_snaps = false; struct { TestOpType op; const char *name; bool ec_pool_valid; } op_types[] = { { TEST_OP_READ, "read", true }, { TEST_OP_WRITE, "write", false }, { TEST_OP_DELETE, "delete", true }, { TEST_OP_SNAP_CREATE, "snap_create", true }, { TEST_OP_SNAP_REMOVE, "snap_remove", true }, { TEST_OP_ROLLBACK, "rollback", true }, { TEST_OP_SETATTR, "setattr", true }, { TEST_OP_RMATTR, "rmattr", true }, { TEST_OP_WATCH, "watch", true }, { TEST_OP_COPY_FROM, "copy_from", true }, { TEST_OP_HIT_SET_LIST, "hit_set_list", true }, { TEST_OP_IS_DIRTY, "is_dirty", true }, { TEST_OP_UNDIRTY, "undirty", true }, { TEST_OP_CACHE_FLUSH, "cache_flush", true }, { TEST_OP_CACHE_TRY_FLUSH, "cache_try_flush", true }, { TEST_OP_CACHE_EVICT, "cache_evict", true }, { TEST_OP_APPEND, "append", true }, { TEST_OP_READ /* grr */, NULL }, }; map op_weights; string pool_name = "data"; bool ec_pool = false; bool no_omap = false; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "--max-ops") == 0) ops = atoi(argv[++i]); else if (strcmp(argv[i], "--pool") == 0) pool_name = argv[++i]; else if (strcmp(argv[i], "--max-seconds") == 0) max_seconds = atoi(argv[++i]); else if (strcmp(argv[i], "--objects") == 0) objects = atoi(argv[++i]); else if (strcmp(argv[i], "--max-in-flight") == 0) max_in_flight = atoi(argv[++i]); else if (strcmp(argv[i], "--size") == 0) size = atoi(argv[++i]); else if (strcmp(argv[i], "--min-stride-size") == 0) min_stride_size = atoi(argv[++i]); else if (strcmp(argv[i], "--max-stride-size") == 0) max_stride_size = atoi(argv[++i]); else if (strcmp(argv[i], "--no-omap") == 0) no_omap = true; else if (strcmp(argv[i], "--pool-snaps") == 0) pool_snaps = true; else if (strcmp(argv[i], "--ec-pool") == 0) { if (!op_weights.empty()) { cerr << "--ec-pool must be specified prior to any ops" << std::endl; exit(1); } ec_pool = true; no_omap = true; } else if (strcmp(argv[i], "--op") == 0) { i++; if (i == argc) { cerr << "Missing op after --op" << std::endl; return 1; } int j; for (j = 0; op_types[j].name; ++j) { if (strcmp(op_types[j].name, argv[i]) == 0) { break; } } if (!op_types[j].name) { cerr << "unknown op " << argv[i] << std::endl; exit(1); } i++; if (i == argc) { cerr << "Weight unspecified." << std::endl; return 1; } int weight = atoi(argv[i]); if (weight < 0) { cerr << "Weights must be nonnegative." << std::endl; return 1; } else if (weight > 0) { if (ec_pool && !op_types[j].ec_pool_valid) { cerr << "Error: cannot use op type " << op_types[j].name << " with --ec-pool" << std::endl; exit(1); } cout << "adding op weight " << op_types[j].name << " -> " << weight << std::endl; op_weights.insert(pair(op_types[j].op, weight)); } } else { cerr << "unknown arg " << argv[i] << std::endl; //usage(); exit(1); } } if (op_weights.empty()) { cerr << "No operations specified" << std::endl; //usage(); exit(1); } if (min_stride_size < 0) min_stride_size = size / 10; if (max_stride_size < 0) max_stride_size = size / 5; cout << pretty_version_to_str() << std::endl; cout << "Configuration:" << std::endl << "\tNumber of operations: " << ops << std::endl << "\tNumber of objects: " << objects << std::endl << "\tMax in flight operations: " << max_in_flight << std::endl << "\tObject size (in bytes): " << size << std::endl << "\tWrite stride min: " << min_stride_size << std::endl << "\tWrite stride max: " << max_stride_size << std::endl; if (min_stride_size > max_stride_size) { cerr << "Error: min_stride_size cannot be more than max_stride_size" << std::endl; return 1; } if (min_stride_size > size || max_stride_size > size) { cerr << "Error: min_stride_size and max_stride_size must be " << "smaller than object size" << std::endl; return 1; } if (max_in_flight * 2 > objects) { cerr << "Error: max_in_flight must be <= than the number of objects / 2" << std::endl; return 1; } char *id = getenv("CEPH_CLIENT_ID"); RadosTestContext context( pool_name, max_in_flight, size, min_stride_size, max_stride_size, no_omap, pool_snaps, id); TestOpStat stats; WeightedTestGenerator gen = WeightedTestGenerator( ops, objects, op_weights, &stats, max_seconds, ec_pool); int r = context.init(); if (r < 0) { cerr << "Error initializing rados test context: " << cpp_strerror(r) << std::endl; exit(1); } context.loop(&gen); context.shutdown(); cerr << context.errors << " errors." << std::endl; cerr << stats << std::endl; return 0; } ceph-0.80.11/src/test/osd/TestECBackend.cc0000664000175100017510000000367712623076744022153 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "osd/ECBackend.h" #include "gtest/gtest.h" TEST(ECUtil, stripe_info_t) { const uint64_t swidth = 4096; const uint64_t ssize = 4; ECUtil::stripe_info_t s(ssize, swidth); ASSERT_EQ(s.get_stripe_width(), swidth); ASSERT_EQ(s.logical_to_next_chunk_offset(0), 0u); ASSERT_EQ(s.logical_to_next_chunk_offset(1), s.get_chunk_size()); ASSERT_EQ(s.logical_to_next_chunk_offset(swidth - 1), s.get_chunk_size()); ASSERT_EQ(s.logical_to_prev_chunk_offset(0), 0u); ASSERT_EQ(s.logical_to_prev_chunk_offset(swidth), s.get_chunk_size()); ASSERT_EQ(s.logical_to_prev_chunk_offset((swidth * 2) - 1), s.get_chunk_size()); ASSERT_EQ(s.logical_to_next_stripe_offset(0), 0u); ASSERT_EQ(s.logical_to_next_stripe_offset(swidth - 1), s.get_stripe_width()); ASSERT_EQ(s.logical_to_prev_stripe_offset(swidth), s.get_stripe_width()); ASSERT_EQ(s.logical_to_prev_stripe_offset(swidth), s.get_stripe_width()); ASSERT_EQ(s.logical_to_prev_stripe_offset((swidth * 2) - 1), s.get_stripe_width()); ASSERT_EQ(s.aligned_logical_offset_to_chunk_offset(2*swidth), 2*s.get_chunk_size()); ASSERT_EQ(s.aligned_chunk_offset_to_logical_offset(2*s.get_chunk_size()), 2*s.get_stripe_width()); ASSERT_EQ(s.aligned_offset_len_to_chunk(make_pair(swidth, 10*swidth)), make_pair(s.get_chunk_size(), 10*s.get_chunk_size())); ASSERT_EQ(s.offset_len_to_stripe_bounds(make_pair(swidth-10, (uint64_t)20)), make_pair((uint64_t)0, 2*swidth)); } ceph-0.80.11/src/test/osd/Object.cc0000664000175100017510000001103312623076744020743 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/interval_set.h" #include "include/buffer.h" #include #include #include #include "Object.h" void ContDesc::encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(objnum, bl); ::encode(cursnap, bl); ::encode(seqnum, bl); ::encode(prefix, bl); ::encode(oid, bl); ENCODE_FINISH(bl); } void ContDesc::decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(objnum, bl); ::decode(cursnap, bl); ::decode(seqnum, bl); ::decode(prefix, bl); ::decode(oid, bl); DECODE_FINISH(bl); } ostream &operator<<(ostream &out, const ContDesc &rhs) { return out << "(ObjNum " << rhs.objnum << " snap " << rhs.cursnap << " seq_num " << rhs.seqnum //<< " prefix " << rhs.prefix << ")"; } void AppendGenerator::get_ranges_map( const ContDesc &cont, map &out) { RandWrap rand(cont.seqnum); uint64_t pos = off; uint64_t limit = off + get_append_size(cont); while (pos < limit) { uint64_t segment_length = round_up( rand() % (max_append_size - min_append_size), alignment) + min_append_size; assert(segment_length >= min_append_size); if (segment_length + pos > limit) { segment_length = limit - pos; } if (alignment) assert(segment_length % alignment == 0); out.insert(make_pair(pos, segment_length)); pos += segment_length; } } void VarLenGenerator::get_ranges_map( const ContDesc &cont, map &out) { RandWrap rand(cont.seqnum); uint64_t pos = 0; uint64_t limit = get_length(cont); bool include = false; while (pos < limit) { uint64_t segment_length = (rand() % (max_stride_size - min_stride_size)) + min_stride_size; assert(segment_length < max_stride_size); assert(segment_length >= min_stride_size); if (segment_length + pos > limit) { segment_length = limit - pos; } if (include) { out.insert(make_pair(pos, segment_length)); include = false; } else { include = true; } pos += segment_length; } // make sure we write up to the limit if (limit > 0 && ( out.empty() || (out.rbegin()->first + out.rbegin()->second < limit))) out[limit-1] = 1; } ObjectDesc::iterator &ObjectDesc::iterator::advance(bool init) { assert(pos < limit); assert(!end()); if (!init) { pos++; } if (end()) { return *this; } while (pos == limit) { cur_cont = stack.begin()->first; limit = stack.begin()->second; stack.pop_front(); } if (cur_cont == obj.layers.end()) { return *this; } interval_set ranges; cur_cont->first->get_ranges(cur_cont->second, ranges); while (!ranges.contains(pos)) { stack.push_front(make_pair(cur_cont, limit)); uint64_t length = cur_cont->first->get_length(cur_cont->second); uint64_t next; if (pos >= length) { next = limit; cur_cont = obj.layers.end(); } else if (ranges.empty() || pos >= ranges.range_end()) { next = length; ++cur_cont; } else { next = ranges.start_after(pos); ++cur_cont; } if (next < limit) { limit = next; } if (cur_cont == obj.layers.end()) { break; } ranges.clear(); cur_cont->first->get_ranges(cur_cont->second, ranges); } if (cur_cont == obj.layers.end()) { return *this; } if (!cont_iters.count(cur_cont->second)) { cont_iters.insert(pair( cur_cont->second, cur_cont->first->get_iterator(cur_cont->second))); } map::iterator j = cont_iters.find( cur_cont->second); assert(j != cont_iters.end()); j->second.seek(pos); return *this; } const ContDesc &ObjectDesc::most_recent() { return layers.begin()->second; } void ObjectDesc::update(ContentsGenerator *gen, const ContDesc &next) { layers.push_front(make_pair(gen, next)); return; } bool ObjectDesc::check(bufferlist &to_check) { iterator i = begin(); uint64_t pos = 0; for (bufferlist::iterator p = to_check.begin(); !p.end(); ++p, ++i, ++pos) { if (i.end()) { std::cout << "reached end of iterator first" << std::endl; return false; } if (*i != *p) { std::cout << "incorrect buffer at pos " << pos << std::endl; return false; } } uint64_t size = layers.empty() ? 0 : most_recent_gen()->get_length(most_recent()); if (pos != size) { std::cout << "only read " << pos << " out of size " << size << std::endl; return false; } return true; } ceph-0.80.11/src/test/osd/Object.h0000664000175100017510000002136712623076744020620 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/interval_set.h" #include "include/buffer.h" #include "include/encoding.h" #include #include #include #ifndef OBJECT_H #define OBJECT_H class ContDesc { public: int objnum; int cursnap; unsigned seqnum; string prefix; string oid; ContDesc() : objnum(0), cursnap(0), seqnum(0), prefix("") {} ContDesc(int objnum, int cursnap, unsigned seqnum, const string &prefix) : objnum(objnum), cursnap(cursnap), seqnum(seqnum), prefix(prefix) {} bool operator==(const ContDesc &rhs) { return (rhs.objnum == objnum && rhs.cursnap == cursnap && rhs.seqnum == seqnum && rhs.prefix == prefix && rhs.oid == oid); } bool operator<(const ContDesc &rhs) const { return seqnum < rhs.seqnum; } bool operator!=(const ContDesc &rhs) { return !((*this) == rhs); } void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bp); }; WRITE_CLASS_ENCODER(ContDesc) ostream &operator<<(ostream &out, const ContDesc &rhs); class ContentsGenerator { public: class iterator_impl { public: virtual char operator*() = 0; virtual iterator_impl &operator++() = 0; virtual void seek(uint64_t pos) = 0; virtual bool end() = 0; virtual ContDesc get_cont() const = 0; virtual uint64_t get_pos() const = 0; virtual ~iterator_impl() {}; }; class iterator { public: ContentsGenerator *parent; iterator_impl *impl; char operator *() { return **impl; } iterator &operator++() { ++(*impl); return *this; }; void seek(uint64_t pos) { impl->seek(pos); } bool end() { return impl->end(); } ~iterator() { parent->put_iterator_impl(impl); } iterator(const iterator &rhs) : parent(rhs.parent) { impl = parent->dup_iterator_impl(rhs.impl); } iterator &operator=(const iterator &rhs) { iterator new_iter(rhs); swap(new_iter); return *this; } void swap(iterator &other) { ContentsGenerator *otherparent = other.parent; other.parent = parent; parent = otherparent; iterator_impl *otherimpl = other.impl; other.impl = impl; impl = otherimpl; } iterator(ContentsGenerator *parent, iterator_impl *impl) : parent(parent), impl(impl) {} }; virtual uint64_t get_length(const ContDesc &in) = 0; virtual void get_ranges_map( const ContDesc &cont, map &out) = 0; void get_ranges(const ContDesc &cont, interval_set &out) { map ranges; get_ranges_map(cont, ranges); for (map::iterator i = ranges.begin(); i != ranges.end(); ++i) { out.insert(i->first, i->second); } } virtual iterator_impl *get_iterator_impl(const ContDesc &in) = 0; virtual iterator_impl *dup_iterator_impl(const iterator_impl *in) = 0; virtual void put_iterator_impl(iterator_impl *in) = 0; virtual ~ContentsGenerator() {}; iterator get_iterator(const ContDesc &in) { return iterator(this, get_iterator_impl(in)); } }; class RandGenerator : public ContentsGenerator { public: class RandWrap { public: unsigned int state; RandWrap(unsigned int seed) { state = seed; } int operator()() { return rand_r(&state); } }; class iterator_impl : public ContentsGenerator::iterator_impl { public: uint64_t pos; ContDesc cont; RandWrap rand; RandGenerator *cont_gen; char current; iterator_impl(const ContDesc &cont, RandGenerator *cont_gen) : pos(0), cont(cont), rand(cont.seqnum), cont_gen(cont_gen) { current = rand(); } ContDesc get_cont() const { return cont; } uint64_t get_pos() const { return pos; } iterator_impl &operator++() { pos++; current = rand(); return *this; } char operator*() { return current; } void seek(uint64_t _pos) { if (_pos < pos) { iterator_impl begin = iterator_impl(cont, cont_gen); begin.seek(_pos); *this = begin; } while (pos < _pos) { ++(*this); } } bool end() { return pos >= cont_gen->get_length(cont); } }; ContentsGenerator::iterator_impl *get_iterator_impl(const ContDesc &in) { RandGenerator::iterator_impl *i = new iterator_impl(in, this); return i; } void put_iterator_impl(ContentsGenerator::iterator_impl *in) { delete in; } ContentsGenerator::iterator_impl *dup_iterator_impl( const ContentsGenerator::iterator_impl *in) { ContentsGenerator::iterator_impl *retval = get_iterator_impl(in->get_cont()); retval->seek(in->get_pos()); return retval; } }; class VarLenGenerator : public RandGenerator { uint64_t max_length; uint64_t min_stride_size; uint64_t max_stride_size; public: VarLenGenerator( uint64_t length, uint64_t min_stride_size, uint64_t max_stride_size) : max_length(length), min_stride_size(min_stride_size), max_stride_size(max_stride_size) {} void get_ranges_map( const ContDesc &cont, map &out); uint64_t get_length(const ContDesc &in) { RandWrap rand(in.seqnum); return (rand() % max_length); } }; class AttrGenerator : public RandGenerator { uint64_t max_len; public: AttrGenerator(uint64_t max_len) : max_len(max_len) {} void get_ranges_map( const ContDesc &cont, map &out) { out.insert(make_pair(0, get_length(cont))); } uint64_t get_length(const ContDesc &in) { RandWrap rand(in.seqnum); return (rand() % max_len); } bufferlist gen_bl(const ContDesc &in) { bufferlist bl; for (iterator i = get_iterator(in); !i.end(); ++i) { bl.append(*i); } assert(bl.length() < max_len); return bl; } }; class AppendGenerator : public RandGenerator { uint64_t off; uint64_t alignment; uint64_t min_append_size; uint64_t max_append_size; uint64_t max_append_total; uint64_t round_up(uint64_t in, uint64_t by) { if (by) in += (by - (in % by)); return in; } public: AppendGenerator( uint64_t off, uint64_t alignment, uint64_t min_append_size, uint64_t _max_append_size, uint64_t max_append_multiple) : off(off), alignment(alignment), min_append_size(round_up(min_append_size, alignment)), max_append_size(round_up(_max_append_size, alignment)) { if (_max_append_size == min_append_size) max_append_size += alignment; max_append_total = max_append_multiple * max_append_size; } uint64_t get_append_size(const ContDesc &in) { RandWrap rand(in.seqnum); return round_up(rand() % max_append_total, alignment); } uint64_t get_length(const ContDesc &in) { return off + get_append_size(in); } void get_ranges_map( const ContDesc &cont, map &out); }; class ObjectDesc { public: ObjectDesc() : exists(false), dirty(false), version(0) {} ObjectDesc(const ContDesc &init, ContentsGenerator *cont_gen) : exists(false), dirty(false), version(0) { layers.push_front(make_pair(cont_gen, init)); } class iterator { public: uint64_t pos; ObjectDesc &obj; list, ContDesc> >::iterator, uint64_t> > stack; map cont_iters; uint64_t limit; list, ContDesc> >::iterator cur_cont; iterator(ObjectDesc &obj) : pos(0), obj(obj) { limit = obj.layers.begin()->first->get_length(obj.layers.begin()->second); cur_cont = obj.layers.begin(); advance(true); } iterator &advance(bool init); iterator &operator++() { return advance(false); } char operator*() { if (cur_cont == obj.layers.end()) { return '\0'; } else { map::iterator j = cont_iters.find( cur_cont->second); assert(j != cont_iters.end()); return *(j->second); } } bool end() { return pos >= obj.layers.begin()->first->get_length( obj.layers.begin()->second); } void seek(uint64_t _pos) { if (_pos < pos) { assert(0); } while (pos < _pos) { ++(*this); } } }; iterator begin() { return iterator(*this); } bool deleted() { return !exists; } bool has_contents() { return layers.size(); } // takes ownership of gen void update(ContentsGenerator *gen, const ContDesc &next); bool check(bufferlist &to_check); const ContDesc &most_recent(); ContentsGenerator *most_recent_gen() { return layers.begin()->first.get(); } map attrs; // Both omap and xattrs bufferlist header; bool exists; bool dirty; uint64_t version; private: list, ContDesc> > layers; }; #endif ceph-0.80.11/src/test/osd/TestOpStat.h0000664000175100017510000000213512623076744021454 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "common/Mutex.h" #include "common/Cond.h" #include "include/rados/librados.hpp" #ifndef TESTOPSTAT_H #define TESTOPSTAT_H class TestOp; class TestOpStat { public: Mutex stat_lock; TestOpStat() : stat_lock("TestOpStat lock") {} static uint64_t gettime() { timeval t; gettimeofday(&t,0); return (1000000*t.tv_sec) + t.tv_usec; } class TypeStatus { public: map inflight; multiset latencies; void begin(TestOp *in) { assert(!inflight.count(in)); inflight[in] = gettime(); } void end(TestOp *in) { assert(inflight.count(in)); uint64_t curtime = gettime(); latencies.insert(curtime - inflight[in]); inflight.erase(in); } void export_latencies(map &in) const; }; map stats; void begin(TestOp *in); void end(TestOp *in); friend std::ostream & operator<<(std::ostream &, TestOpStat&); }; std::ostream & operator<<(std::ostream &out, TestOpStat &rhs); #endif ceph-0.80.11/src/test/osd/TestPGLog.cc0000664000175100017510000015323212623076744021355 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "osd/PGLog.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include class PGLogTest : public ::testing::Test, protected PGLog { public: virtual void SetUp() { } virtual void TearDown() { clear(); } static hobject_t mk_obj(unsigned id) { hobject_t hoid; stringstream ss; ss << "obj_" << id; hoid.oid = ss.str(); hoid.hash = id; return hoid; } static eversion_t mk_evt(unsigned ep, unsigned v) { return eversion_t(ep, v); } static pg_log_entry_t mk_ple_mod( const hobject_t &hoid, eversion_t v, eversion_t pv) { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.op = pg_log_entry_t::MODIFY; e.soid = hoid; e.version = v; e.prior_version = pv; return e; } static pg_log_entry_t mk_ple_dt( const hobject_t &hoid, eversion_t v, eversion_t pv) { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.op = pg_log_entry_t::DELETE; e.soid = hoid; e.version = v; e.prior_version = pv; return e; } static pg_log_entry_t mk_ple_mod_rb( const hobject_t &hoid, eversion_t v, eversion_t pv) { pg_log_entry_t e; e.op = pg_log_entry_t::MODIFY; e.soid = hoid; e.version = v; e.prior_version = pv; return e; } static pg_log_entry_t mk_ple_dt_rb( const hobject_t &hoid, eversion_t v, eversion_t pv) { pg_log_entry_t e; e.op = pg_log_entry_t::DELETE; e.soid = hoid; e.version = v; e.prior_version = pv; return e; } struct TestCase { list base; list auth; list div; pg_missing_t init; pg_missing_t final; set toremove; list torollback; private: IndexedLog fullauth; IndexedLog fulldiv; pg_info_t authinfo; pg_info_t divinfo; public: void setup() { fullauth.log.insert(fullauth.log.end(), base.begin(), base.end()); fullauth.log.insert(fullauth.log.end(), auth.begin(), auth.end()); fulldiv.log.insert(fulldiv.log.end(), base.begin(), base.end()); fulldiv.log.insert(fulldiv.log.end(), div.begin(), div.end()); fullauth.head = authinfo.last_update = fullauth.log.rbegin()->version; authinfo.last_complete = fullauth.log.rbegin()->version; authinfo.log_tail = fullauth.log.begin()->version; authinfo.log_tail.version--; fullauth.tail = authinfo.log_tail; authinfo.last_backfill = hobject_t::get_max(); fulldiv.head = divinfo.last_update = fulldiv.log.rbegin()->version; divinfo.last_complete = eversion_t(); divinfo.log_tail = fulldiv.log.begin()->version; divinfo.log_tail.version--; fulldiv.tail = divinfo.log_tail; divinfo.last_backfill = hobject_t::get_max(); if (init.missing.empty()) { divinfo.last_complete = divinfo.last_update; } else { eversion_t fmissing = init.missing[init.rmissing.begin()->second].need; for (list::const_iterator i = fulldiv.log.begin(); i != fulldiv.log.end(); ++i) { if (i->version < fmissing) divinfo.last_complete = i->version; else break; } } fullauth.index(); fulldiv.index(); } void set_div_bounds(eversion_t head, eversion_t tail) { fulldiv.tail = divinfo.log_tail = tail; fulldiv.head = divinfo.last_update = head; } void set_auth_bounds(eversion_t head, eversion_t tail) { fullauth.tail = authinfo.log_tail = tail; fullauth.head = authinfo.last_update = head; } const IndexedLog &get_fullauth() const { return fullauth; } const IndexedLog &get_fulldiv() const { return fulldiv; } const pg_info_t &get_authinfo() const { return authinfo; } const pg_info_t &get_divinfo() const { return divinfo; } }; struct LogHandler : public PGLog::LogEntryHandler { set removed; list rolledback; void rollback( const pg_log_entry_t &entry) { rolledback.push_back(entry); } void remove( const hobject_t &hoid) { removed.insert(hoid); } void trim( const pg_log_entry_t &entry) {} }; void verify_missing( const TestCase &tcase, const pg_missing_t &missing) { ASSERT_EQ(tcase.final.missing.size(), missing.missing.size()); for (map::const_iterator i = missing.missing.begin(); i != missing.missing.end(); ++i) { EXPECT_TRUE(tcase.final.missing.count(i->first)); EXPECT_EQ(tcase.final.missing.find(i->first)->second.need, i->second.need); EXPECT_EQ(tcase.final.missing.find(i->first)->second.have, i->second.have); } } void verify_sideeffects( const TestCase &tcase, const LogHandler &handler) { ASSERT_EQ(tcase.toremove.size(), handler.removed.size()); ASSERT_EQ(tcase.torollback.size(), handler.rolledback.size()); { list::const_iterator titer = tcase.torollback.begin(); list::const_iterator hiter = handler.rolledback.begin(); for (; titer != tcase.torollback.end(); ++titer, ++hiter) { EXPECT_EQ(titer->version, hiter->version); } } { set::const_iterator titer = tcase.toremove.begin(); set::const_iterator hiter = handler.removed.begin(); for (; titer != tcase.toremove.end(); ++titer, ++hiter) { EXPECT_EQ(*titer, *hiter); } } } void test_merge_log(const TestCase &tcase) { clear(); ObjectStore::Transaction t; log = tcase.get_fulldiv(); pg_info_t info = tcase.get_divinfo(); missing = tcase.init; IndexedLog olog; olog = tcase.get_fullauth(); pg_info_t oinfo = tcase.get_authinfo(); LogHandler h; bool dirty_info = false; bool dirty_big_info = false; merge_log( t, oinfo, olog, pg_shard_t(1, 0), info, &h, dirty_info, dirty_big_info); ASSERT_EQ(info.last_update, oinfo.last_update); verify_missing(tcase, missing); verify_sideeffects(tcase, h); }; void test_proc_replica_log(const TestCase &tcase) { clear(); ObjectStore::Transaction t; log = tcase.get_fullauth(); pg_info_t info = tcase.get_authinfo(); pg_missing_t omissing = tcase.init; IndexedLog olog; olog = tcase.get_fulldiv(); pg_info_t oinfo = tcase.get_divinfo(); proc_replica_log( t, oinfo, olog, omissing, pg_shard_t(1, 0)); assert(oinfo.last_update >= log.tail); if (!tcase.base.empty()) { ASSERT_EQ(tcase.base.rbegin()->version, oinfo.last_update); } for (list::const_iterator i = tcase.auth.begin(); i != tcase.auth.end(); ++i) { omissing.add_next_event(*i); } verify_missing(tcase, omissing); } void run_test_case(const TestCase &tcase) { test_merge_log(tcase); test_proc_replica_log(tcase); } }; struct TestHandler : public PGLog::LogEntryHandler { list &removed; TestHandler(list &removed) : removed(removed) {} void rollback( const pg_log_entry_t &entry) {} void remove( const hobject_t &hoid) { removed.push_back(hoid); } void cant_rollback(const pg_log_entry_t &entry) {} void trim( const pg_log_entry_t &entry) {} }; TEST_F(PGLogTest, rewind_divergent_log) { // newhead > log.tail : throw an assert { clear(); ObjectStore::Transaction t; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; log.tail = eversion_t(2, 1); TestHandler h(remove_snap); EXPECT_THROW(rewind_divergent_log(t, eversion_t(1, 1), info, &h, dirty_info, dirty_big_info), FailedAssertion); } /* +----------------+ | log | +--------+-------+ | |object | |version | hash | | | | tail > (1,1) | x5 | | | | | | | | (1,4) | x9 < newhead | MODIFY | | | | | head > (1,5) | x9 | | DELETE | | | | | +--------+-------+ */ { clear(); ObjectStore::Transaction t; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; hobject_t divergent_object; eversion_t divergent_version; eversion_t newhead; hobject_t divergent; divergent.hash = 0x9; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 1); e.soid.hash = 0x5; log.tail = e.version; log.log.push_back(e); e.version = newhead = eversion_t(1, 4); e.soid = divergent; e.op = pg_log_entry_t::MODIFY; log.log.push_back(e); e.version = divergent_version = eversion_t(1, 5); e.prior_version = eversion_t(1, 4); e.soid = divergent; divergent_object = e.soid; e.op = pg_log_entry_t::DELETE; log.log.push_back(e); log.head = e.version; log.index(); info.last_update = log.head; info.last_complete = log.head; } EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(3U, log.log.size()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_EQ(log.head, info.last_update); EXPECT_EQ(log.head, info.last_complete); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); rewind_divergent_log(t, newhead, info, &h, dirty_info, dirty_big_info); EXPECT_TRUE(log.objects.count(divergent)); EXPECT_TRUE(missing.is_missing(divergent_object)); EXPECT_EQ(1U, log.objects.count(divergent_object)); EXPECT_EQ(2U, log.log.size()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_EQ(newhead, info.last_update); EXPECT_EQ(newhead, info.last_complete); EXPECT_TRUE(is_dirty()); EXPECT_TRUE(dirty_info); EXPECT_TRUE(dirty_big_info); } /* +----------------+ | log | +--------+-------+ | |object | |version | hash | | | | tail > (1,1) | NULL | | | | | (1,4) | NULL < newhead | | | head > (1,5) | x9 | | | | +--------+-------+ */ { clear(); ObjectStore::Transaction t; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; hobject_t divergent_object; eversion_t divergent_version; eversion_t prior_version; eversion_t newhead; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); info.log_tail = log.tail = eversion_t(1, 1); newhead = eversion_t(1, 3); e.version = divergent_version = eversion_t(1, 5); e.soid.hash = 0x9; divergent_object = e.soid; e.op = pg_log_entry_t::DELETE; e.prior_version = prior_version = eversion_t(0, 2); log.log.push_back(e); log.head = e.version; } EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.log.size()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); rewind_divergent_log(t, newhead, info, &h, dirty_info, dirty_big_info); EXPECT_TRUE(missing.is_missing(divergent_object)); EXPECT_EQ(0U, log.objects.count(divergent_object)); EXPECT_TRUE(log.empty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(is_dirty()); EXPECT_TRUE(dirty_info); EXPECT_TRUE(dirty_big_info); } } TEST_F(PGLogTest, merge_old_entry) { // entries > last_backfill are silently ignored { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; info.last_backfill = hobject_t(); info.last_backfill.hash = 1; oe.soid.hash = 2; EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_TRUE(log.empty()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_TRUE(log.empty()); } // the new entry (from the logs) has a version that is higher than // the old entry (from the log entry given in argument) : do // nothing and return false { clear(); ObjectStore::Transaction t; pg_info_t info; list remove_snap; pg_log_entry_t ne; ne.mod_desc.mark_unrollbackable(); ne.version = eversion_t(2,1); log.add(ne); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.log.size()); EXPECT_EQ(ne.version, log.log.front().version); // the newer entry ( from the logs ) can be DELETE { log.log.front().op = pg_log_entry_t::DELETE; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); oe.version = eversion_t(1,1); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); } // if the newer entry is not DELETE, the object must be in missing { pg_log_entry_t &ne = log.log.front(); ne.op = pg_log_entry_t::MODIFY; missing.add_next_event(ne); pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); oe.version = eversion_t(1,1); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); missing.rm(ne.soid, ne.version); } EXPECT_FALSE(is_dirty()); EXPECT_FALSE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.log.size()); EXPECT_EQ(ne.version, log.log.front().version); } // the new entry (from the logs) has a version that is lower than // the old entry (from the log entry given in argument) and // old and new are delete : do nothing and return false { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; pg_log_entry_t ne; ne.mod_desc.mark_unrollbackable(); ne.version = eversion_t(1,1); ne.op = pg_log_entry_t::DELETE; log.add(ne); oe.version = eversion_t(2,1); oe.op = pg_log_entry_t::DELETE; EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.log.size()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.log.size()); } // the new entry (from the logs) has a version that is lower than // the old entry (from the log entry given in argument) and // old is update and new is DELETE : // if the object is in missing, it is removed { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; pg_log_entry_t ne; ne.mod_desc.mark_unrollbackable(); ne.version = eversion_t(1,1); ne.op = pg_log_entry_t::DELETE; log.add(ne); oe.version = eversion_t(2,1); oe.op = pg_log_entry_t::MODIFY; missing.add_next_event(oe); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(missing.is_missing(oe.soid)); EXPECT_EQ(1U, log.log.size()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.size() > 0); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.log.size()); } // there is no new entry (from the logs) and // the old entry (from the log entry given in argument) is not a CLONE and // the old entry prior_version is greater than the tail of the log : // do nothing and return false { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; info.log_tail = eversion_t(1,1); oe.op = pg_log_entry_t::MODIFY; oe.prior_version = eversion_t(2,1); missing_add(oe.soid, oe.prior_version, eversion_t()); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(log.empty()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(log.empty()); } // there is no new entry (from the logs) and // the old entry (from the log entry given in argument) is not a CLONE and // the old entry (from the log entry given in argument) is not a DELETE and // the old entry prior_version is lower than the tail of the log : // add the old object to the remove_snap list and // add the old object to divergent priors and // add or update the prior_version of the object to missing and // return false { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; info.log_tail = eversion_t(2,1); oe.soid.hash = 1; oe.op = pg_log_entry_t::MODIFY; oe.prior_version = eversion_t(1,1); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_TRUE(log.empty()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_TRUE(is_dirty()); EXPECT_EQ(oe.soid, remove_snap.front()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(missing.is_missing(oe.soid)); EXPECT_TRUE(log.empty()); EXPECT_EQ(oe.soid, divergent_priors[oe.prior_version]); } // there is no new entry (from the logs) and // the old entry (from the log entry given in argument) is not a CLONE and // the old entry (from the log entry given in argument) is a DELETE and // the old entry prior_version is lower than the tail of the log : // add the old object to divergent priors and // add or update the prior_version of the object to missing and // return false { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; info.log_tail = eversion_t(2,1); oe.soid.hash = 1; oe.op = pg_log_entry_t::DELETE; oe.prior_version = eversion_t(1,1); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_TRUE(log.empty()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_TRUE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(missing.is_missing(oe.soid)); EXPECT_TRUE(log.empty()); EXPECT_EQ(oe.soid, divergent_priors[oe.prior_version]); } // there is no new entry (from the logs) and // the old entry (from the log entry given in argument) is not a CLONE and // the old entry (from the log entry given in argument) is not a DELETE and // the old entry prior_version is eversion_t() : // add the old object to the remove_snap list and // remove the prior_version of the object from missing, if any and // return false { clear(); ObjectStore::Transaction t; pg_log_entry_t oe; oe.mod_desc.mark_unrollbackable(); pg_info_t info; list remove_snap; info.log_tail = eversion_t(10,1); oe.soid.hash = 1; oe.op = pg_log_entry_t::MODIFY; oe.prior_version = eversion_t(); missing.add(oe.soid, eversion_t(1,1), eversion_t()); EXPECT_FALSE(is_dirty()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(missing.is_missing(oe.soid)); EXPECT_TRUE(log.empty()); TestHandler h(remove_snap); merge_old_entry(t, oe, info, &h); EXPECT_FALSE(is_dirty()); EXPECT_EQ(oe.soid, remove_snap.front()); EXPECT_TRUE(t.empty()); EXPECT_FALSE(missing.have_missing()); EXPECT_TRUE(log.empty()); } } TEST_F(PGLogTest, merge_log) { // head and tail match, last_backfill is set: // noop { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; hobject_t last_backfill(object_t("oname"), string("key"), 1, 234, 1, ""); info.last_backfill = last_backfill; eversion_t stat_version(10, 1); info.stats.version = stat_version; log.tail = olog.tail = eversion_t(1, 1); log.head = olog.head = eversion_t(2, 1); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(0U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_EQ(last_backfill, info.last_backfill); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(0U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); } // head and tail match, last_backfill is not set: info.stats is // copied from oinfo.stats but info.stats.reported_* is guaranteed to // never be replaced by a lower version { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; eversion_t stat_version(10, 1); oinfo.stats.version = stat_version; info.stats.reported_seq = 1; info.stats.reported_epoch = 10; oinfo.stats.reported_seq = 1; oinfo.stats.reported_epoch = 1; log.tail = olog.tail = eversion_t(1, 1); log.head = olog.head = eversion_t(2, 1); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(0U, log.log.size()); EXPECT_EQ(eversion_t(), info.stats.version); EXPECT_EQ(1ull, info.stats.reported_seq); EXPECT_EQ(10u, info.stats.reported_epoch); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(info.last_backfill.is_max()); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(0U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_EQ(1ull, info.stats.reported_seq); EXPECT_EQ(10u, info.stats.reported_epoch); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); } /* Before +--------------------------+ | log olog | +--------+-------+---------+ | |object | | |version | hash | version | | | | | | | x5 | (1,1) < tail | | | | | | | | tail > (1,4) | x7 | | | | | | | | | | head > (1,5) | x9 | (1,5) < head | | | | | | | | +--------+-------+---------+ After +----------------- | log | +--------+-------+ | |object | |version | hash | | | | tail > (1,1) | x5 | | | | | | | | (1,4) | x7 | | | | | | | head > (1,5) | x9 | | | | | | | +--------+-------+ */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 4); e.soid.hash = 0x5; log.tail = e.version; log.log.push_back(e); e.version = eversion_t(1, 5); e.soid.hash = 0x9; log.log.push_back(e); log.head = e.version; log.index(); info.last_update = log.head; e.version = eversion_t(1, 1); e.soid.hash = 0x5; olog.tail = e.version; olog.log.push_back(e); e.version = eversion_t(1, 5); e.soid.hash = 0x9; olog.log.push_back(e); olog.head = e.version; } hobject_t last_backfill(object_t("oname"), string("key"), 1, 234, 1, ""); info.last_backfill = last_backfill; eversion_t stat_version(10, 1); info.stats.version = stat_version; EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(2U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_EQ(last_backfill, info.last_backfill); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(3U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_TRUE(is_dirty()); EXPECT_TRUE(dirty_info); EXPECT_TRUE(dirty_big_info); } /* +--------------------------+ | log olog | +--------+-------+---------+ | |object | | |version | hash | version | | | | | tail > (1,1) | x5 | (1,1) < tail | | | | | | | | | (1,2) | x3 | (1,2) < lower_bound | | | | | | | | head > (1,3) | x9 | | | DELETE | | | | | | | | | x9 | (2,3) | | | | MODIFY | | | | | | | x7 | (2,4) < head | | | DELETE | +--------+-------+---------+ The log entry (1,3) deletes the object x9 but the olog entry (2,3) modifies it and is authoritative : the log entry (1,3) is divergent. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; hobject_t divergent_object; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 1); e.soid.hash = 0x5; log.tail = e.version; log.log.push_back(e); e.version = eversion_t(1, 2); e.soid.hash = 0x3; log.log.push_back(e); e.version = eversion_t(1,3); e.soid.hash = 0x9; divergent_object = e.soid; e.op = pg_log_entry_t::DELETE; log.log.push_back(e); log.head = e.version; log.index(); info.last_update = log.head; e.version = eversion_t(1, 1); e.soid.hash = 0x5; olog.tail = e.version; olog.log.push_back(e); e.version = eversion_t(1, 2); e.soid.hash = 0x3; olog.log.push_back(e); e.version = eversion_t(2, 3); e.soid.hash = 0x9; e.op = pg_log_entry_t::MODIFY; olog.log.push_back(e); e.version = eversion_t(2, 4); e.soid.hash = 0x7; e.op = pg_log_entry_t::DELETE; olog.log.push_back(e); olog.head = e.version; } snapid_t purged_snap(1); { oinfo.last_update = olog.head; oinfo.purged_snaps.insert(purged_snap); } EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(1U, log.objects.count(divergent_object)); EXPECT_EQ(3U, log.log.size()); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_EQ(log.head, info.last_update); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info); /* When the divergent entry is a DELETE and the authoritative entry is a MODIFY, the object will be added to missing : it is a verifiable side effect proving the entry was identified to be divergent. */ EXPECT_TRUE(missing.is_missing(divergent_object)); EXPECT_EQ(1U, log.objects.count(divergent_object)); EXPECT_EQ(4U, log.log.size()); /* DELETE entries from olog that are appended to the hed of the log are also added to remove_snap. */ EXPECT_EQ(0x7U, remove_snap.front().hash); EXPECT_TRUE(t.empty()); EXPECT_EQ(log.head, info.last_update); EXPECT_TRUE(info.purged_snaps.contains(purged_snap)); EXPECT_TRUE(is_dirty()); EXPECT_TRUE(dirty_info); EXPECT_TRUE(dirty_big_info); } /* +--------------------------+ | log olog | +--------+-------+---------+ | |object | | |version | hash | version | | | | | tail > (1,1) | x5 | (1,1) < tail | | | | | | | | | (1,4) | x7 | (1,4) < head | | | | | | | | head > (1,5) | x9 | | | | | | | | | | +--------+-------+---------+ The head of the log entry (1,5) is divergent because it is greater than the head of olog. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 1); e.soid.hash = 0x5; log.tail = e.version; log.log.push_back(e); e.version = eversion_t(1, 4); e.soid.hash = 0x7; log.log.push_back(e); e.version = eversion_t(1, 5); e.soid.hash = 0x9; log.log.push_back(e); log.head = e.version; log.index(); info.last_update = log.head; e.version = eversion_t(1, 1); e.soid.hash = 0x5; olog.tail = e.version; olog.log.push_back(e); e.version = eversion_t(1, 4); e.soid.hash = 0x7; olog.log.push_back(e); olog.head = e.version; } hobject_t last_backfill(object_t("oname"), string("key"), 1, 234, 1, ""); info.last_backfill = last_backfill; eversion_t stat_version(10, 1); info.stats.version = stat_version; EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(3U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_TRUE(remove_snap.empty()); EXPECT_TRUE(t.empty()); EXPECT_EQ(last_backfill, info.last_backfill); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_FALSE(is_dirty()); EXPECT_FALSE(dirty_info); EXPECT_FALSE(dirty_big_info); TestHandler h(remove_snap); merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info); EXPECT_FALSE(missing.have_missing()); EXPECT_EQ(2U, log.log.size()); EXPECT_EQ(stat_version, info.stats.version); EXPECT_EQ(0x9U, remove_snap.front().hash); EXPECT_TRUE(t.empty()); EXPECT_TRUE(info.purged_snaps.empty()); EXPECT_TRUE(is_dirty()); EXPECT_TRUE(dirty_info); EXPECT_TRUE(dirty_big_info); } // If our log is empty, the incoming log needs to have not been trimmed. { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; // olog has been trimmed olog.tail = eversion_t(1, 1); TestHandler h(remove_snap); ASSERT_THROW(merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info), FailedAssertion); } /* +--------------------------+ | log olog | +--------+-------+---------+ | |object | | |version | hash | version | tail > (0,0) | | | | (1,1) | x5 | | | | | | | | | | head > (1,2) | x3 | | | | | | | | | (2,3) < tail | | x9 | (2,4) | | | | | | | x5 | (2,5) < head | | | | +--------+-------+---------+ If the logs do not overlap, throw an exception. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_shard_t fromosd; pg_info_t info; list remove_snap; bool dirty_info = false; bool dirty_big_info = false; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); log.tail = eversion_t(); e.version = eversion_t(1, 1); e.soid.hash = 0x5; log.log.push_back(e); e.version = eversion_t(1, 2); e.soid.hash = 0x3; log.log.push_back(e); log.head = e.version; log.index(); info.last_update = log.head; olog.tail = eversion_t(2, 3); e.version = eversion_t(2, 4); e.soid.hash = 0x9; olog.log.push_back(e); e.version = eversion_t(2, 5); e.soid.hash = 0x5; olog.log.push_back(e); olog.head = e.version; } TestHandler h(remove_snap); EXPECT_THROW(merge_log(t, oinfo, olog, fromosd, info, &h, dirty_info, dirty_big_info), FailedAssertion); } } TEST_F(PGLogTest, proc_replica_log) { // empty log : no side effect { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_missing_t omissing; pg_shard_t from; eversion_t last_update(1, 1); log.head = olog.head = oinfo.last_update = last_update; eversion_t last_complete(1, 1); oinfo.last_complete = last_complete; EXPECT_TRUE(t.empty()); EXPECT_FALSE(omissing.have_missing()); EXPECT_EQ(last_update, oinfo.last_update); EXPECT_EQ(last_complete, oinfo.last_complete); proc_replica_log(t, oinfo, olog, omissing, from); EXPECT_TRUE(t.empty()); EXPECT_FALSE(omissing.have_missing()); EXPECT_EQ(last_update, oinfo.last_update); EXPECT_EQ(last_update, oinfo.last_complete); } /* +--------------------------+ | log olog | +--------+-------+---------+ | |object | | |version | hash | version | | | | | | | x3 | (1,1) < tail | | | | | | | | tail > (1,2) | x5 | | | | | | | | | | head > (1,3) | x9 | | | DELETE | | | | | | | | | x9 | (2,3) < head | | | DELETE | | | | | +--------+-------+---------+ The log entry (1,3) deletes the object x9 and the olog entry (2,3) also deletes it : do nothing. The olog tail is ignored because it is before the log tail. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_missing_t omissing; pg_shard_t from; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 2); e.soid.hash = 0x5; log.tail = e.version; log.log.push_back(e); e.version = eversion_t(1, 3); e.soid.hash = 0x9; e.op = pg_log_entry_t::DELETE; log.log.push_back(e); log.head = e.version; log.index(); e.version = eversion_t(1, 1); e.soid.hash = 0x3; olog.tail = e.version; olog.log.push_back(e); e.version = eversion_t(2, 3); e.soid.hash = 0x9; e.op = pg_log_entry_t::DELETE; olog.log.push_back(e); olog.head = e.version; oinfo.last_update = olog.head; oinfo.last_complete = olog.head; } EXPECT_TRUE(t.empty()); EXPECT_FALSE(omissing.have_missing()); EXPECT_EQ(olog.head, oinfo.last_update); EXPECT_EQ(olog.head, oinfo.last_complete); proc_replica_log(t, oinfo, olog, omissing, from); EXPECT_TRUE(t.empty()); EXPECT_FALSE(omissing.have_missing()); } { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_missing_t omissing; pg_shard_t from; hobject_t divergent_object; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); { e.soid = divergent_object; e.soid.hash = 0x1; e.version = eversion_t(1, 1); log.tail = e.version; log.log.push_back(e); e.soid = divergent_object; e.prior_version = eversion_t(1, 1); e.version = eversion_t(1, 2); log.tail = e.version; log.log.push_back(e); e.soid.hash = 0x3; e.version = eversion_t(1, 4); log.log.push_back(e); e.soid.hash = 0x7; e.version = eversion_t(1, 5); log.log.push_back(e); e.soid.hash = 0x8; e.version = eversion_t(1, 6); log.log.push_back(e); e.soid.hash = 0x9; e.op = pg_log_entry_t::DELETE; e.version = eversion_t(2, 7); log.log.push_back(e); e.soid.hash = 0xa; e.version = eversion_t(2, 8); log.head = e.version; log.log.push_back(e); } log.index(); { e.soid = divergent_object; e.soid.hash = 0x1; e.version = eversion_t(1, 1); olog.tail = e.version; olog.log.push_back(e); e.soid = divergent_object; e.prior_version = eversion_t(1, 1); e.version = eversion_t(1, 2); olog.log.push_back(e); e.prior_version = eversion_t(0, 0); e.soid.hash = 0x3; e.version = eversion_t(1, 4); olog.log.push_back(e); e.soid.hash = 0x7; e.version = eversion_t(1, 5); olog.log.push_back(e); e.soid.hash = 0x8; e.version = eversion_t(1, 6); olog.log.push_back(e); e.soid.hash = 0x9; // should not be added to missing, create e.op = pg_log_entry_t::MODIFY; e.version = eversion_t(1, 7); olog.log.push_back(e); e.soid = divergent_object; // should be added to missing at 1,2 e.op = pg_log_entry_t::MODIFY; e.version = eversion_t(1, 8); e.prior_version = eversion_t(1, 2); olog.log.push_back(e); olog.head = e.version; } oinfo.last_update = olog.head; oinfo.last_complete = olog.head; } EXPECT_TRUE(t.empty()); EXPECT_FALSE(omissing.have_missing()); EXPECT_EQ(olog.head, oinfo.last_update); EXPECT_EQ(olog.head, oinfo.last_complete); proc_replica_log(t, oinfo, olog, omissing, from); EXPECT_TRUE(t.empty()); EXPECT_TRUE(omissing.have_missing()); EXPECT_TRUE(omissing.is_missing(divergent_object)); EXPECT_EQ(eversion_t(1, 2), omissing.missing[divergent_object].need); EXPECT_EQ(eversion_t(1, 6), oinfo.last_update); EXPECT_EQ(eversion_t(1, 1), oinfo.last_complete); } /* +--------------------------+ | olog log | +--------+-------+---------+ | |object | | |version | hash | version | | | | | tail > (1,1) | x9 | (1,1) < tail | | | | | | | | | (1,2) | x3 | (1,2) | | | | | | | | | head > (1,3) | x9 | | | DELETE | | | | | | | | | x9 | (2,3) < head | | | DELETE | | | | | +--------+-------+---------+ The log entry (1,3) deletes the object x9 and the olog entry (2,3) also deletes it : do nothing. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_missing_t omissing; pg_shard_t from; eversion_t last_update(1, 2); hobject_t divergent_object; divergent_object.hash = 0x9; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 1); e.soid = divergent_object; log.tail = e.version; log.log.push_back(e); e.version = last_update; e.soid.hash = 0x3; log.log.push_back(e); e.version = eversion_t(2, 3); e.prior_version = eversion_t(1, 1); e.soid = divergent_object; e.op = pg_log_entry_t::DELETE; log.log.push_back(e); log.head = e.version; log.index(); e.version = eversion_t(1, 1); e.soid = divergent_object; olog.tail = e.version; olog.log.push_back(e); e.version = last_update; e.soid.hash = 0x3; olog.log.push_back(e); e.version = eversion_t(1, 3); e.prior_version = eversion_t(1, 1); e.soid = divergent_object; e.op = pg_log_entry_t::DELETE; olog.log.push_back(e); olog.head = e.version; oinfo.last_update = olog.head; oinfo.last_complete = olog.head; } EXPECT_TRUE(t.empty()); EXPECT_FALSE(omissing.have_missing()); EXPECT_EQ(olog.head, oinfo.last_update); EXPECT_EQ(olog.head, oinfo.last_complete); proc_replica_log(t, oinfo, olog, omissing, from); EXPECT_TRUE(t.empty()); EXPECT_TRUE(omissing.have_missing()); EXPECT_TRUE(omissing.is_missing(divergent_object)); EXPECT_EQ(omissing.missing[divergent_object].have, eversion_t(0, 0)); EXPECT_EQ(omissing.missing[divergent_object].need, eversion_t(1, 1)); EXPECT_EQ(last_update, oinfo.last_update); } /* +--------------------------+ | olog log | +--------+-------+---------+ | |object | | |version | hash | version | | | | | tail > (1,1) | x9 | (1,1) < tail | | | | | | | | | (1,2) | x3 | (1,2) | | | | | | | | | head > (1,3) | x9 | | | MODIFY | | | | | | | | | x9 | (2,3) < head | | | DELETE | | | | | +--------+-------+---------+ The log entry (1,3) deletes the object x9 but the olog entry (2,3) modifies it : remove it from omissing. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_missing_t omissing; pg_shard_t from; eversion_t last_update(1, 2); hobject_t divergent_object; { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 1); e.soid = divergent_object; log.tail = e.version; log.log.push_back(e); e.version = last_update; e.soid.hash = 0x3; log.log.push_back(e); e.version = eversion_t(2, 3); e.prior_version = eversion_t(1, 1); e.soid = divergent_object; e.op = pg_log_entry_t::DELETE; log.log.push_back(e); log.head = e.version; log.index(); e.version = eversion_t(1, 1); e.soid = divergent_object; olog.tail = e.version; olog.log.push_back(e); e.version = last_update; e.soid.hash = 0x3; olog.log.push_back(e); e.version = eversion_t(1, 3); e.prior_version = eversion_t(1, 1); e.soid = divergent_object; divergent_object = e.soid; omissing.add(divergent_object, e.version, eversion_t()); e.op = pg_log_entry_t::MODIFY; olog.log.push_back(e); olog.head = e.version; oinfo.last_update = olog.head; oinfo.last_complete = olog.head; } EXPECT_TRUE(t.empty()); EXPECT_TRUE(omissing.have_missing()); EXPECT_TRUE(omissing.is_missing(divergent_object)); EXPECT_EQ(eversion_t(1, 3), omissing.missing[divergent_object].need); EXPECT_EQ(olog.head, oinfo.last_update); EXPECT_EQ(olog.head, oinfo.last_complete); proc_replica_log(t, oinfo, olog, omissing, from); EXPECT_TRUE(t.empty()); EXPECT_TRUE(omissing.have_missing()); EXPECT_TRUE(omissing.is_missing(divergent_object)); EXPECT_EQ(omissing.missing[divergent_object].have, eversion_t(0, 0)); EXPECT_EQ(omissing.missing[divergent_object].need, eversion_t(1, 1)); EXPECT_EQ(last_update, oinfo.last_update); } /* +--------------------------+ | log olog | +--------+-------+---------+ | |object | | |version | hash | version | | | | | tail > (1,1) | x9 | (1,1) < tail | | | | | | | | | (1,2) | x3 | (1,2) | | | | | | | | | | | x9 | (1,3) < head | | | MODIFY | | | | | head > (2,3) | x9 | | | DELETE | | | | | | | +--------+-------+---------+ The log entry (2,3) deletes the object x9 but the olog entry (1,3) modifies it : proc_replica_log should adjust missing to 1,1 for that object until add_next_event in PG::activate processes the delete. */ { clear(); ObjectStore::Transaction t; pg_log_t olog; pg_info_t oinfo; pg_missing_t omissing; pg_shard_t from; eversion_t last_update(1, 2); hobject_t divergent_object; eversion_t new_version(2, 3); eversion_t divergent_version(1, 3); { pg_log_entry_t e; e.mod_desc.mark_unrollbackable(); e.version = eversion_t(1, 1); e.soid.hash = 0x9; log.tail = e.version; log.log.push_back(e); e.version = last_update; e.soid.hash = 0x3; log.log.push_back(e); e.version = new_version; e.prior_version = eversion_t(1, 1); e.soid.hash = 0x9; e.op = pg_log_entry_t::DELETE; log.log.push_back(e); log.head = e.version; log.index(); e.op = pg_log_entry_t::MODIFY; e.version = eversion_t(1, 1); e.soid.hash = 0x9; olog.tail = e.version; olog.log.push_back(e); e.version = last_update; e.soid.hash = 0x3; olog.log.push_back(e); e.version = divergent_version; e.prior_version = eversion_t(1, 1); e.soid.hash = 0x9; divergent_object = e.soid; omissing.add(divergent_object, e.version, eversion_t()); e.op = pg_log_entry_t::MODIFY; olog.log.push_back(e); olog.head = e.version; oinfo.last_update = olog.head; oinfo.last_complete = olog.head; } EXPECT_TRUE(t.empty()); EXPECT_TRUE(omissing.have_missing()); EXPECT_TRUE(omissing.is_missing(divergent_object)); EXPECT_EQ(divergent_version, omissing.missing[divergent_object].need); EXPECT_EQ(olog.head, oinfo.last_update); EXPECT_EQ(olog.head, oinfo.last_complete); proc_replica_log(t, oinfo, olog, omissing, from); EXPECT_TRUE(t.empty()); EXPECT_TRUE(omissing.have_missing()); EXPECT_TRUE(omissing.missing.begin()->second.need == eversion_t(1, 1)); EXPECT_EQ(last_update, oinfo.last_update); EXPECT_EQ(eversion_t(0, 0), oinfo.last_complete); } } TEST_F(PGLogTest, merge_log_1) { TestCase t; t.base.push_back(mk_ple_mod(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.div.push_back(mk_ple_mod(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100))); t.final.add(mk_obj(1), mk_evt(10, 100), mk_evt(0, 0)); t.toremove.insert(mk_obj(1)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_2) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.div.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100))); t.div.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 102), mk_evt(10, 101))); t.torollback.insert( t.torollback.begin(), t.div.rbegin(), t.div.rend()); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_3) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.div.push_back(mk_ple_mod(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100))); t.div.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 102), mk_evt(10, 101))); t.final.add(mk_obj(1), mk_evt(10, 100), mk_evt(0, 0)); t.toremove.insert(mk_obj(1)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_4) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.div.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100))); t.div.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 102), mk_evt(10, 101))); t.init.add(mk_obj(1), mk_evt(10, 102), mk_evt(0, 0)); t.final.add(mk_obj(1), mk_evt(10, 100), mk_evt(0, 0)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_5) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.div.push_back(mk_ple_mod(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100))); t.div.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 102), mk_evt(10, 101))); t.auth.push_back(mk_ple_mod(mk_obj(1), mk_evt(11, 101), mk_evt(10, 100))); t.final.add(mk_obj(1), mk_evt(11, 101), mk_evt(0, 0)); t.toremove.insert(mk_obj(1)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_6) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.auth.push_back(mk_ple_mod(mk_obj(1), mk_evt(11, 101), mk_evt(10, 100))); t.final.add(mk_obj(1), mk_evt(11, 101), mk_evt(10, 100)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_7) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.auth.push_back(mk_ple_mod(mk_obj(1), mk_evt(11, 101), mk_evt(10, 100))); t.init.add(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80)); t.final.add(mk_obj(1), mk_evt(11, 101), mk_evt(8, 80)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_8) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.auth.push_back(mk_ple_dt(mk_obj(1), mk_evt(11, 101), mk_evt(10, 100))); t.init.add(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80)); t.toremove.insert(mk_obj(1)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_prior_version_have) { TestCase t; t.base.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 80))); t.div.push_back(mk_ple_mod(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100))); t.init.add(mk_obj(1), mk_evt(10, 101), mk_evt(10, 100)); t.setup(); run_test_case(t); } TEST_F(PGLogTest, merge_log_split_missing_entries_at_head) { TestCase t; t.auth.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(10, 100), mk_evt(8, 70))); t.auth.push_back(mk_ple_mod_rb(mk_obj(1), mk_evt(15, 150), mk_evt(10, 100))); t.div.push_back(mk_ple_mod(mk_obj(1), mk_evt(8, 70), mk_evt(8, 65))); t.setup(); t.set_div_bounds(mk_evt(9, 79), mk_evt(8, 69)); t.set_auth_bounds(mk_evt(10, 160), mk_evt(9, 77)); t.final.add(mk_obj(1), mk_evt(15, 150), mk_evt(8, 70)); run_test_case(t); } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } // Local Variables: // compile-command: "cd ../.. ; make unittest_pglog ; ./unittest_pglog --log-to-stderr=true --debug-osd=20 # --gtest_filter=*.* " // End: ceph-0.80.11/src/test/ceph_compatset.cc0000664000175100017510000001204212623076744021747 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include #include "include/types.h" #include "include/compat.h" //#undef assert //#define assert(foo) if (!(foo)) abort(); #include "include/CompatSet.h" #include "gtest/gtest.h" #include TEST(CephCompatSet, AllSet) { CompatSet::FeatureSet compat; CompatSet::FeatureSet ro; CompatSet::FeatureSet incompat; EXPECT_THROW(compat.insert(CompatSet::Feature(0, "test")), FailedAssertion); EXPECT_THROW(compat.insert(CompatSet::Feature(64, "test")), FailedAssertion); for (int i = 1; i < 64; i++) { stringstream cname; cname << string("c") << i; compat.insert(CompatSet::Feature(i,cname.str().c_str())); stringstream roname; roname << string("r") << i; ro.insert(CompatSet::Feature(i,roname.str().c_str())); stringstream iname; iname << string("i") << i; incompat.insert(CompatSet::Feature(i,iname.str().c_str())); } CompatSet tcs(compat, ro, incompat); //cout << tcs << std::endl; //Due to a workaround for a bug bit 0 is always set even though it is //not a legal feature. EXPECT_EQ(tcs.compat.mask, (uint64_t)0xffffffffffffffff); EXPECT_EQ(tcs.ro_compat.mask, (uint64_t)0xffffffffffffffff); EXPECT_EQ(tcs.incompat.mask, (uint64_t)0xffffffffffffffff); for (int i = 1; i < 64; i++) { EXPECT_TRUE(tcs.compat.contains(i)); stringstream cname; cname << string("c") << i; EXPECT_TRUE(tcs.compat.contains(CompatSet::Feature(i,cname.str().c_str()))); tcs.compat.remove(i); EXPECT_TRUE(tcs.ro_compat.contains(i)); stringstream roname; roname << string("r") << i; EXPECT_TRUE(tcs.ro_compat.contains(CompatSet::Feature(i,roname.str().c_str()))); tcs.ro_compat.remove(i); EXPECT_TRUE(tcs.incompat.contains(i)); stringstream iname; iname << string("i") << i; EXPECT_TRUE(tcs.incompat.contains(CompatSet::Feature(i,iname.str().c_str()))); tcs.incompat.remove(i); } //Due to a workaround for a bug bit 0 is always set even though it is //not a legal feature. EXPECT_EQ(tcs.compat.mask, (uint64_t)1); EXPECT_TRUE(tcs.compat.names.empty()); EXPECT_EQ(tcs.ro_compat.mask, (uint64_t)1); EXPECT_TRUE(tcs.ro_compat.names.empty()); EXPECT_EQ(tcs.incompat.mask, (uint64_t)1); EXPECT_TRUE(tcs.incompat.names.empty()); } TEST(CephCompatSet, other) { CompatSet s1, s2, s1dup; s1.compat.insert(CompatSet::Feature(1, "c1")); s1.compat.insert(CompatSet::Feature(2, "c2")); s1.compat.insert(CompatSet::Feature(32, "c32")); s1.ro_compat.insert(CompatSet::Feature(63, "r63")); s1.incompat.insert(CompatSet::Feature(1, "i1")); s2.compat.insert(CompatSet::Feature(1, "c1")); s2.compat.insert(CompatSet::Feature(32, "c32")); s2.ro_compat.insert(CompatSet::Feature(63, "r63")); s2.incompat.insert(CompatSet::Feature(1, "i1")); s1dup = s1; //Check exact match EXPECT_EQ(s1.compare(s1dup), 0); //Check superset EXPECT_EQ(s1.compare(s2), 1); //Check missing features EXPECT_EQ(s2.compare(s1), -1); CompatSet diff = s2.unsupported(s1); EXPECT_EQ(diff.compat.mask, (uint64_t)1<<2 | 1); EXPECT_EQ(diff.ro_compat.mask, (uint64_t)1); EXPECT_EQ(diff.incompat.mask, (uint64_t)1); CompatSet s3 = s1; s3.incompat.insert(CompatSet::Feature(4, "i4")); diff = s1.unsupported(s3); EXPECT_EQ(diff.compat.mask, (uint64_t)1); EXPECT_EQ(diff.ro_compat.mask, (uint64_t)1); EXPECT_EQ(diff.incompat.mask, (uint64_t)1<<4 | 1); } TEST(CephCompatSet, merge) { CompatSet s1, s2, s1dup, s2dup; s1.compat.insert(CompatSet::Feature(1, "c1")); s1.compat.insert(CompatSet::Feature(2, "c2")); s1.compat.insert(CompatSet::Feature(32, "c32")); s1.ro_compat.insert(CompatSet::Feature(63, "r63")); s1.incompat.insert(CompatSet::Feature(1, "i1")); s1dup = s1; s2.compat.insert(CompatSet::Feature(1, "c1")); s2.compat.insert(CompatSet::Feature(32, "c32")); s2.ro_compat.insert(CompatSet::Feature(1, "r1")); s2.ro_compat.insert(CompatSet::Feature(63, "r63")); s2.incompat.insert(CompatSet::Feature(1, "i1")); s2dup = s2; //Nothing to merge if they are the same EXPECT_FALSE(s1.merge(s1dup)); EXPECT_FALSE(s2.merge(s2dup)); EXPECT_TRUE(s1.merge(s2)); EXPECT_EQ(s1.compat.mask, (uint64_t)1<<1 | (uint64_t)1<<2 | (uint64_t)1<<32 | 1); EXPECT_EQ(s1.ro_compat.mask, (uint64_t)1<<1 | (uint64_t)1<<63 | 1); EXPECT_EQ(s1.incompat.mask, (uint64_t)1<<1 | 1); EXPECT_TRUE(s2.merge(s1dup)); EXPECT_EQ(s2.compat.mask, (uint64_t)1<<1 | (uint64_t)1<<2 | (uint64_t)1<<32 | 1); EXPECT_EQ(s2.ro_compat.mask, (uint64_t)1<<1 | (uint64_t)1<<63 | 1); EXPECT_EQ(s2.incompat.mask, (uint64_t)1<<1 | 1); } ceph-0.80.11/src/test/run_cmd.cc0000664000175100017510000000104712623076744020403 0ustar jenkins-buildjenkins-build#include "common/config.h" #include "common/run_cmd.h" #include "gtest/gtest.h" #include #include TEST(RunCommand, StringSimple) { char temp_file_name[] = "run_cmd_temp_file_XXXXXX"; int fd = ::mkstemp(temp_file_name); ASSERT_GE(fd, 0); ::close(fd); std::string ret = run_cmd("touch", temp_file_name, (char*)NULL); ASSERT_EQ(ret, ""); ASSERT_EQ(access(temp_file_name, R_OK), 0); ret = run_cmd("rm", "-f", temp_file_name, (char*)NULL); ASSERT_EQ(ret, ""); ASSERT_NE(access(temp_file_name, R_OK), 0); } ceph-0.80.11/src/test/test_texttable.cc0000664000175100017510000000372412623076744022013 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank Storage, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/TextTable.h" #include #include "gtest/gtest.h" TEST(TextTable, Alignment) { TextTable t; // test alignment // 3 5-character columns t.define_column("HEAD1", TextTable::LEFT, TextTable::LEFT); t.define_column("HEAD2", TextTable::LEFT, TextTable::CENTER); t.define_column("HEAD3", TextTable::LEFT, TextTable::RIGHT); t << "1" << 2 << 3 << TextTable::endrow; std::ostringstream oss; oss << t; ASSERT_STREQ("HEAD1 HEAD2 HEAD3 \n1 2 3 \n", oss.str().c_str()); } TEST(TextTable, WidenAndClearShrink) { TextTable t; t.define_column("1", TextTable::LEFT, TextTable::LEFT); // default column size is 1, widen to 5 t << "wider"; // validate wide output std::ostringstream oss; oss << t; ASSERT_STREQ("1 \nwider \n", oss.str().c_str()); oss.str(""); // reset, validate single-char width output t.clear(); t << "s"; oss << t; ASSERT_STREQ("1 \ns \n", oss.str().c_str()); } TEST(TextTable, Indent) { TextTable t; t.define_column("1", TextTable::LEFT, TextTable::LEFT); t.set_indent(10); t << "s"; std::ostringstream oss; oss << t; ASSERT_STREQ(" 1 \n s \n", oss.str().c_str()); } TEST(TextTable, TooManyItems) { TextTable t; t.define_column("1", TextTable::LEFT, TextTable::LEFT); t.define_column("2", TextTable::LEFT, TextTable::LEFT); t.define_column("3", TextTable::LEFT, TextTable::LEFT); // expect assertion failure on this, which throws FailedAssertion ASSERT_THROW((t << "1" << "2" << "3" << "4" << TextTable::endrow), FailedAssertion); } ceph-0.80.11/src/test/test_c_headers.c0000664000175100017510000000061612623076744021566 0ustar jenkins-buildjenkins-build#include "include/cephfs/libcephfs.h" #include "include/rados/librados.h" #ifdef __cplusplus #error "test invalid: only use C mode" #endif int main(int argc, char **argv) { int ret; (void)ret; // squash unused warning /* librados.h */ rados_t cluster; ret = rados_create(&cluster, NULL); /* libcephfs.h */ struct ceph_mount_info *cmount; ret = ceph_create(&cmount, NULL); return 0; } ceph-0.80.11/src/test/escape.cc0000664000175100017510000000625512623076744020222 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/escape.h" #include "gtest/gtest.h" #include static std::string escape_xml_attrs(const char *str) { int len = escape_xml_attr_len(str); char out[len]; escape_xml_attr(str, out); return out; } TEST(EscapeXml, PassThrough) { ASSERT_EQ(escape_xml_attrs("simplicity itself"), "simplicity itself"); ASSERT_EQ(escape_xml_attrs(""), ""); ASSERT_EQ(escape_xml_attrs("simple examples please!"), "simple examples please!"); } TEST(EscapeXml, EntityRefs1) { ASSERT_EQ(escape_xml_attrs("The \"scare quotes\""), "The "scare quotes""); ASSERT_EQ(escape_xml_attrs("I <3 XML"), "I <3 XML"); ASSERT_EQ(escape_xml_attrs("Some 'single' \"quotes\" here"), "Some 'single' "quotes" here"); } TEST(EscapeXml, ControlChars) { uint8_t cc1[] = { 0x01, 0x02, 0x03, 0x0 }; ASSERT_EQ(escape_xml_attrs((char*)cc1), ""); uint8_t cc2[] = { 0x61, 0x62, 0x63, 0x7f, 0x0 }; ASSERT_EQ(escape_xml_attrs((char*)cc2), "abc"); } TEST(EscapeXml, Utf8) { uint8_t cc1[] = { 0xe6, 0xb1, 0x89, 0xe5, 0xad, 0x97, 0x0a, 0x0 }; ASSERT_EQ(escape_xml_attrs((const char*)cc1), (const char*)cc1); uint8_t cc2[] = { 0x3c, 0xe6, 0xb1, 0x89, 0xe5, 0xad, 0x97, 0x3e, 0x0a, 0x0 }; uint8_t cc2_out[] = { 0x26, 0x6c, 0x74, 0x3b, 0xe6, 0xb1, 0x89, 0xe5, 0xad, 0x97, 0x26, 0x67, 0x74, 0x3b, 0x0a, 0x0 }; ASSERT_EQ(escape_xml_attrs((const char*)cc2), (const char*)cc2_out); } static std::string escape_json_attrs(const char *str) { int len = escape_json_attr_len(str); char out[len]; escape_json_attr(str, out); return out; } TEST(EscapeJson, PassThrough) { ASSERT_EQ(escape_json_attrs("simplicity itself"), "simplicity itself"); ASSERT_EQ(escape_json_attrs(""), ""); ASSERT_EQ(escape_json_attrs("simple examples please!"), "simple examples please!"); } TEST(EscapeJson, Escapes1) { ASSERT_EQ(escape_json_attrs("The \"scare quotes\""), "The \\\"scare quotes\\\""); ASSERT_EQ(escape_json_attrs("I <3 JSON"), "I <3 JSON"); ASSERT_EQ(escape_json_attrs( "JSON calls a slash / backslash a solidus / reverse solidus"), "JSON calls a slash \\/ backslash a solidus \\/ reverse solidus"); ASSERT_EQ(escape_json_attrs("Some 'single' \"quotes\" here"), "Some 'single' \\\"quotes\\\" here"); ASSERT_EQ(escape_json_attrs("tabs\tand\tnewlines\n, oh my"), "tabs\\tand\\tnewlines\\n, oh my"); } TEST(EscapeJson, ControlChars) { uint8_t cc1[] = { 0x01, 0x02, 0x03, 0x0 }; ASSERT_EQ(escape_json_attrs((char*)cc1), "\\u0001\\u0002\\u0003"); uint8_t cc2[] = { 0x61, 0x62, 0x63, 0x7f, 0x0 }; ASSERT_EQ(escape_json_attrs((char*)cc2), "abc\\u007f"); } TEST(EscapeJson, Utf8) { uint8_t cc1[] = { 0xe6, 0xb1, 0x89, 0xe5, 0xad, 0x97, 0x0a, 0x0 }; ASSERT_EQ(escape_xml_attrs((const char*)cc1), (const char*)cc1); } ceph-0.80.11/src/test/test_filejournal.cc0000664000175100017510000003023712623076744022330 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include #include #include #include "common/ceph_argparse.h" #include "common/common_init.h" #include "global/global_init.h" #include "common/config.h" #include "common/Finisher.h" #include "os/FileJournal.h" #include "include/Context.h" #include "common/Mutex.h" #include "common/safe_io.h" Finisher *finisher; Cond sync_cond; char path[200]; uuid_d fsid; bool directio = false; bool aio = false; // ---- Cond cond; Mutex wait_lock("lock"); bool done; void wait() { wait_lock.Lock(); while (!done) cond.Wait(wait_lock); wait_lock.Unlock(); } // ---- class C_Sync { public: Cond cond; Mutex lock; bool done; C_SafeCond *c; C_Sync() : lock("C_Sync::lock"), done(false) { c = new C_SafeCond(&lock, &cond, &done); } ~C_Sync() { lock.Lock(); //cout << "wait" << std::endl; while (!done) cond.Wait(lock); //cout << "waited" << std::endl; lock.Unlock(); } }; unsigned size_mb = 200; int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); char mb[10]; sprintf(mb, "%u", size_mb); g_ceph_context->_conf->set_val("osd_journal_size", mb); g_ceph_context->_conf->apply_changes(NULL); finisher = new Finisher(g_ceph_context); if (!args.empty()) { size_t copy_len = std::min(sizeof(path)-1, strlen(args[0])); strncpy(path, args[0], copy_len); path[copy_len] = '\0'; } else { srand(getpid()+time(0)); snprintf(path, sizeof(path), "/tmp/ceph_test_filejournal.tmp.%d", rand()); } cout << "path " << path << std::endl; ::testing::InitGoogleTest(&argc, argv); finisher->start(); cout << "DIRECTIO OFF AIO OFF" << std::endl; directio = false; aio = false; int r = RUN_ALL_TESTS(); if (r >= 0) { cout << "DIRECTIO ON AIO OFF" << std::endl; directio = true; r = RUN_ALL_TESTS(); if (r >= 0) { cout << "DIRECTIO ON AIO ON" << std::endl; aio = true; r = RUN_ALL_TESTS(); } } finisher->stop(); unlink(path); return r; } TEST(TestFileJournal, Create) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); } TEST(TestFileJournal, WriteSmall) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); bufferlist bl; bl.append("small"); j.submit_entry(1, bl, 0, new C_SafeCond(&wait_lock, &cond, &done)); wait(); j.close(); } TEST(TestFileJournal, WriteBig) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); bufferlist bl; while (bl.length() < size_mb*1000/2) { char foo[1024*1024]; memset(foo, 1, sizeof(foo)); bl.append(foo, sizeof(foo)); } j.submit_entry(1, bl, 0, new C_SafeCond(&wait_lock, &cond, &done)); wait(); j.close(); } TEST(TestFileJournal, WriteMany) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); C_GatherBuilder gb(g_ceph_context, new C_SafeCond(&wait_lock, &cond, &done)); bufferlist bl; bl.append("small"); uint64_t seq = 1; for (int i=0; i<100; i++) { bl.append("small"); j.submit_entry(seq++, bl, 0, gb.new_sub()); } gb.activate(); wait(); j.close(); } TEST(TestFileJournal, WriteManyVecs) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); C_GatherBuilder gb(g_ceph_context, new C_SafeCond(&wait_lock, &cond, &done)); bufferlist first; first.append("small"); j.submit_entry(1, first, 0, gb.new_sub()); bufferlist bl; for (int i=0; i= 2) { cout << "replacing at offset " << o << std::endl; memcpy(buf+o, newneedle, strlen(newneedle)); } else { cout << "leaving at offset " << o << std::endl; } n++; } } ASSERT_EQ(n, 4); close(fd); fd = open(path, O_WRONLY); ASSERT_GE(fd, 0); r = safe_write(fd, buf, sizeof(buf)); ASSERT_EQ(r, 0); close(fd); j.open(1); bufferlist inbl; string v; uint64_t seq = 0; ASSERT_EQ(true, j.read_entry(inbl, seq)); ASSERT_EQ(seq, 2ull); inbl.copy(0, inbl.length(), v); ASSERT_EQ(needle, v); inbl.clear(); v.clear(); ASSERT_TRUE(!j.read_entry(inbl, seq)); j.make_writeable(); j.close(); } TEST(TestFileJournal, WriteTrim) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); list ls; bufferlist bl; char foo[1024*1024]; memset(foo, 1, sizeof(foo)); uint64_t seq = 1, committed = 0; for (unsigned i=0; ic); while (ls.size() > size_mb/2) { delete ls.front(); ls.pop_front(); committed++; j.committed_thru(committed); } } while (ls.size()) { delete ls.front(); ls.pop_front(); j.committed_thru(committed); } j.close(); } TEST(TestFileJournal, WriteTrimSmall) { fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio); ASSERT_EQ(0, j.create()); j.make_writeable(); list ls; bufferlist bl; char foo[1024*1024]; memset(foo, 1, sizeof(foo)); uint64_t seq = 1, committed = 0; for (unsigned i=0; ic); while (ls.size() > size_mb/2) { delete ls.front(); ls.pop_front(); committed++; j.committed_thru(committed); } } while (ls.size()) { delete ls.front(); ls.pop_front(); j.committed_thru(committed); } j.close(); } TEST(TestFileJournal, ReplayDetectCorruptFooterMagic) { g_ceph_context->_conf->set_val("journal_ignore_corruption", "true"); g_ceph_context->_conf->set_val("journal_write_header_frequency", "1"); g_ceph_context->_conf->apply_changes(NULL); fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); C_GatherBuilder gb(g_ceph_context, new C_SafeCond(&wait_lock, &cond, &done)); const char *needle = "i am a needle"; for (unsigned i = 1; i <= 4; ++i) { bufferlist bl; bl.append(needle); j.submit_entry(i, bl, 0, gb.new_sub()); } gb.activate(); wait(); bufferlist bl; bl.append("needle"); j.submit_entry(5, bl, 0, new C_SafeCond(&wait_lock, &cond, &done)); wait(); j.close(); int fd = open(path, O_WRONLY); cout << "corrupting journal" << std::endl; j.open(0); j.corrupt_footer_magic(fd, 2); uint64_t seq = 0; bl.clear(); bool corrupt = false; bool result = j.read_entry(bl, seq, &corrupt); ASSERT_TRUE(result); ASSERT_EQ(seq, 1UL); ASSERT_FALSE(corrupt); result = j.read_entry(bl, seq, &corrupt); ASSERT_FALSE(result); ASSERT_TRUE(corrupt); j.make_writeable(); j.close(); ::close(fd); } TEST(TestFileJournal, ReplayDetectCorruptPayload) { g_ceph_context->_conf->set_val("journal_ignore_corruption", "true"); g_ceph_context->_conf->set_val("journal_write_header_frequency", "1"); g_ceph_context->_conf->apply_changes(NULL); fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); C_GatherBuilder gb(g_ceph_context, new C_SafeCond(&wait_lock, &cond, &done)); const char *needle = "i am a needle"; for (unsigned i = 1; i <= 4; ++i) { bufferlist bl; bl.append(needle); j.submit_entry(i, bl, 0, gb.new_sub()); } gb.activate(); wait(); bufferlist bl; bl.append("needle"); j.submit_entry(5, bl, 0, new C_SafeCond(&wait_lock, &cond, &done)); wait(); j.close(); int fd = open(path, O_WRONLY); cout << "corrupting journal" << std::endl; j.open(0); j.corrupt_payload(fd, 2); uint64_t seq = 0; bl.clear(); bool corrupt = false; bool result = j.read_entry(bl, seq, &corrupt); ASSERT_TRUE(result); ASSERT_EQ(seq, 1UL); ASSERT_FALSE(corrupt); result = j.read_entry(bl, seq, &corrupt); ASSERT_FALSE(result); ASSERT_TRUE(corrupt); j.make_writeable(); j.close(); ::close(fd); } TEST(TestFileJournal, ReplayDetectCorruptHeader) { g_ceph_context->_conf->set_val("journal_ignore_corruption", "true"); g_ceph_context->_conf->set_val("journal_write_header_frequency", "1"); g_ceph_context->_conf->apply_changes(NULL); fsid.generate_random(); FileJournal j(fsid, finisher, &sync_cond, path, directio, aio); ASSERT_EQ(0, j.create()); j.make_writeable(); C_GatherBuilder gb(g_ceph_context, new C_SafeCond(&wait_lock, &cond, &done)); const char *needle = "i am a needle"; for (unsigned i = 1; i <= 4; ++i) { bufferlist bl; bl.append(needle); j.submit_entry(i, bl, 0, gb.new_sub()); } gb.activate(); wait(); bufferlist bl; bl.append("needle"); j.submit_entry(5, bl, 0, new C_SafeCond(&wait_lock, &cond, &done)); wait(); j.close(); int fd = open(path, O_WRONLY); cout << "corrupting journal" << std::endl; j.open(0); j.corrupt_header_magic(fd, 2); uint64_t seq = 0; bl.clear(); bool corrupt = false; bool result = j.read_entry(bl, seq, &corrupt); ASSERT_TRUE(result); ASSERT_EQ(seq, 1UL); ASSERT_FALSE(corrupt); result = j.read_entry(bl, seq, &corrupt); ASSERT_FALSE(result); ASSERT_TRUE(corrupt); j.make_writeable(); j.close(); ::close(fd); } ceph-0.80.11/src/test/test_striper.cc0000664000175100017510000000322212623076744021500 0ustar jenkins-buildjenkins-build#include "gtest/gtest.h" #include "global/global_context.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/common_init.h" #include "osdc/Striper.h" TEST(Striper, Stripe1) { ceph_file_layout l; memset(&l, 0, sizeof(l)); l.fl_object_size = 262144; l.fl_stripe_unit = 4096; l.fl_stripe_count = 3; vector ex; Striper::file_to_extents(g_ceph_context, 1, &l, 5006035, 46419, 5006035, ex); cout << "result " << ex << std::endl; ASSERT_EQ(3u, ex.size()); ASSERT_EQ(98304u, ex[0].truncate_size); ASSERT_EQ(ex[1].offset, ex[1].truncate_size); ASSERT_EQ(94208u, ex[2].truncate_size); } TEST(Striper, EmptyPartialResult) { ceph_file_layout l; memset(&l, 0, sizeof(l)); l.fl_object_size = 4194304; l.fl_stripe_unit = 4194304; l.fl_stripe_count = 1; vector ex; Striper::file_to_extents(g_ceph_context, 1, &l, 725549056, 131072, 72554905600, ex); cout << "ex " << ex << std::endl; ASSERT_EQ(2u, ex.size()); Striper::StripedReadResult r; bufferlist bl; r.add_partial_result(g_ceph_context, bl, ex[1].buffer_extents); bufferptr bp(65536); bp.zero(); bl.append(bp); r.add_partial_result(g_ceph_context, bl, ex[0].buffer_extents); bufferlist outbl; r.assemble_result(g_ceph_context, outbl, false); ASSERT_EQ(65536u, outbl.length()); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); vector args; argv_to_vec(argc, (const char **)argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/kv_store_bench.cc0000664000175100017510000004016012623076744021746 0ustar jenkins-buildjenkins-build/* * KvStoreBench.cc * * Created on: Aug 23, 2012 * Author: eleanor */ #include "test/kv_store_bench.h" #include "key_value_store/key_value_structure.h" #include "key_value_store/kv_flat_btree_async.h" #include "include/rados/librados.hpp" #include "test/omap_bench.h" #include "common/ceph_argparse.h" #include #include #include #include #include KvStoreBench::KvStoreBench() : entries(30), ops(100), clients(5), key_size(5), val_size(7), max_ops_in_flight(8), clear_first(false), k(2), cache_size(10), cache_refresh(1), client_name("admin"), verbose(false), kvs(NULL), data_lock("data lock"), ops_in_flight(0), ops_in_flight_lock("KvStoreBench::ops_in_flight_lock"), rados_id("admin"), pool_name("data") { probs[25] = 'i'; probs[50] = 'u'; probs[75] = 'd'; probs[100] = 'r'; } KvStoreBench::~KvStoreBench() { librados::ObjectWriteOperation owo; owo.remove(); io_ctx.operate(client_name + ".done-setting", &owo); delete kvs; } int KvStoreBench::setup(int argc, const char** argv) { vector args; argv_to_vec(argc,argv,args); srand(time(NULL)); stringstream help; help << "Usage: KvStoreBench [options]\n" << "Generate latency and throughput statistics for the key value store\n" << "\n" << "There are two sets of options - workload options affect the kind of\n" << "test to run, while algorithm options affect how the key value\n" << "store handles the workload.\n" << "\n" << "There are about entries / k objects in the store to begin with.\n" << "Higher k values reduce the likelihood of splits and the likelihood\n" << "multiple writers simultaneously faling to write because an object \n" << "is full, but having a high k also means there will be more object\n" << "contention.\n" << "\n" << "WORKLOAD OPTIONS\n" << " --name client name (default admin)\n" << " --entries number of key/value pairs to store initially\n" << " (default " << entries << ")\n" << " --ops number of operations to run\n" << " --keysize number of characters per key (default " << key_size << ")\n" << " --valsize number of characters per value (default " << val_size << ")\n" << " -t number of operations in flight concurrently\n" << " (default " << max_ops_in_flight << ")\n" << " --clients tells this instance how many total clients are. Note that\n" << " changing this does not change the number of clients." << " -d percent (1-100) of operations that should be of each type\n" << " (default 25 25 25 25)\n" << " -r random seed to use (default time(0))\n" << "ALGORITHM OPTIONS\n" << " --kval k, where each object has a number of entries\n" << " >= k and <= 2k.\n" << " --cache-size number of index entries to keep in cache\n" << " (default " << cache_size << ")\n" << " --cache-refresh percent (1-100) of cache-size to read each \n" << " time the index is read\n" << "OTHER OPTIONS\n" << " --verbosity-on display debug output\n" << " --clear-first delete all existing objects in the pool before running tests\n"; for (unsigned i = 0; i < args.size(); i++) { if(i < args.size() - 1) { if (strcmp(args[i], "--ops") == 0) { ops = atoi(args[i+1]); } else if (strcmp(args[i], "--entries") == 0) { entries = atoi(args[i+1]); } else if (strcmp(args[i], "--kval") == 0) { k = atoi(args[i+1]); } else if (strcmp(args[i], "--keysize") == 0) { key_size = atoi(args[i+1]); } else if (strcmp(args[i], "--valsize") == 0) { val_size = atoi(args[i+1]); } else if (strcmp(args[i], "--cache-size") == 0) { cache_size = atoi(args[i+1]); } else if (strcmp(args[i], "--cache-refresh") == 0) { cache_refresh = 100 / atoi(args[i+1]); } else if (strcmp(args[i], "-t") == 0) { max_ops_in_flight = atoi(args[i+1]); } else if (strcmp(args[i], "--clients") == 0) { clients = atoi(args[i+1]); } else if (strcmp(args[i], "-d") == 0) { if (i + 4 >= args.size()) { cout << "Invalid arguments after -d: there must be 4 of them." << std::endl; continue; } else { probs.clear(); int sum = atoi(args[i + 1]); probs[sum] = 'i'; sum += atoi(args[i + 2]); probs[sum] = 'u'; sum += atoi(args[i + 3]); probs[sum] = 'd'; sum += atoi(args[i + 4]); probs[sum] = 'r'; if (sum != 100) { cout << "Invalid arguments after -d: they must add to 100." << std::endl; } } } else if (strcmp(args[i], "--name") == 0) { client_name = args[i+1]; } else if (strcmp(args[i], "-r") == 0) { srand(atoi(args[i+1])); } } else if (strcmp(args[i], "--verbosity-on") == 0) { verbose = true; } else if (strcmp(args[i], "--clear-first") == 0) { clear_first = true; } else if (strcmp(args[i], "--help") == 0) { cout << help.str() << std::endl; exit(1); } } KvFlatBtreeAsync * kvba = new KvFlatBtreeAsync(k, client_name, cache_size, cache_refresh, verbose); kvs = kvba; int r = rados.init(rados_id.c_str()); if (r < 0) { cout << "error during init" << std::endl; return r; } r = rados.conf_parse_argv(argc, argv); if (r < 0) { cout << "error during parsing args" << std::endl; return r; } r = rados.conf_parse_env(NULL); if (r < 0) { cout << "error during parsing env" << std::endl; return r; } r = rados.conf_read_file(NULL); if (r < 0) { cout << "error during read file" << std::endl; return r; } r = rados.connect(); if (r < 0) { cout << "error during connect: " << r << std::endl; return r; } r = rados.ioctx_create(pool_name.c_str(), io_ctx); if (r < 0) { cout << "error creating io ctx" << std::endl; rados.shutdown(); return r; } if (clear_first) { librados::ObjectIterator it; for (it = io_ctx.objects_begin(); it != io_ctx.objects_end(); ++it) { librados::ObjectWriteOperation rm; rm.remove(); io_ctx.operate(it->first, &rm); } } int err = kvs->setup(argc, argv); if (err < 0 && err != -17) { cout << "error during setup of kvs: " << err << std::endl; return err; } return 0; } string KvStoreBench::random_string(int len) { string ret; string alphanum = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; for (int i = 0; i < len; ++i) { ret.push_back(alphanum[rand() % (alphanum.size() - 1)]); } return ret; } pair KvStoreBench::rand_distr(bool new_elem) { pair ret; if (new_elem) { ret = make_pair(random_string(key_size), KvFlatBtreeAsync::to_bl(random_string(val_size))); key_set.insert(ret.first); } else { if (key_set.size() == 0) { return make_pair("",KvFlatBtreeAsync::to_bl("")); } string get_string = random_string(key_size); std::set::iterator it = key_set.lower_bound(get_string); if (it == key_set.end()) { ret.first = *(key_set.rbegin()); } else { ret.first = *it; } ret.second = KvFlatBtreeAsync::to_bl(random_string(val_size)); } return ret; } int KvStoreBench::test_random_insertions() { int err; if (entries == 0) { return 0; } stringstream prev_ss; prev_ss << (atoi(client_name.c_str()) - 1); string prev_rid = prev_ss.str(); stringstream last_ss; if (client_name.size() > 1) { last_ss << client_name.substr(0,client_name.size() - 2); } last_ss << clients - 1; string last_rid = client_name == "admin" ? "admin" : last_ss.str(); map big_map; for (int i = 0; i < entries; i++) { bufferlist bfr; bfr.append(random_string(7)); big_map[random_string(5)] = bfr; } uint64_t uint; time_t t; if (client_name[client_name.size() - 1] != '0' && client_name != "admin") { do { librados::ObjectReadOperation oro; oro.stat(&uint, &t, &err); err = io_ctx.operate(prev_rid + ".done-setting", &oro, NULL); if (verbose) cout << "reading " << prev_rid << ": err = " << err << std::endl; } while (err != 0); cout << "detected " << prev_rid << ".done-setting" << std::endl; } cout << "testing random insertions"; err = kvs->set_many(big_map); if (err < 0) { cout << "error setting things" << std::endl; return err; } librados::ObjectWriteOperation owo; owo.create(true); io_ctx.operate(client_name + ".done-setting", &owo); cout << "created " << client_name + ".done-setting. waiting for " << last_rid << ".done-setting" << std::endl; do { librados::ObjectReadOperation oro; oro.stat(&uint, &t, &err); err = io_ctx.operate(last_rid + ".done-setting", &oro, NULL); } while (err != 0); cout << "detected " << last_rid << ".done-setting" << std::endl; return err; } void KvStoreBench::aio_callback_timed(int * err, void *arg) { timed_args *args = reinterpret_cast(arg); Mutex * ops_in_flight_lock = &args->kvsb->ops_in_flight_lock; Mutex * data_lock = &args->kvsb->data_lock; Cond * op_avail = &args->kvsb->op_avail; int *ops_in_flight = &args->kvsb->ops_in_flight; if (*err < 0 && *err != -61) { cerr << "Error during " << args->op << " operation: " << *err << std::endl; } args->sw.stop_time(); double time = args->sw.get_time(); args->sw.clear(); data_lock->Lock(); //latency args->kvsb->data.latency_jf.open_object_section("latency"); args->kvsb->data.latency_jf.dump_float(string(1, args->op).c_str(), time); args->kvsb->data.latency_jf.close_section(); //throughput args->kvsb->data.throughput_jf.open_object_section("throughput"); args->kvsb->data.throughput_jf.dump_unsigned(string(1, args->op).c_str(), ceph_clock_now(g_ceph_context)); args->kvsb->data.throughput_jf.close_section(); data_lock->Unlock(); ops_in_flight_lock->Lock(); (*ops_in_flight)--; op_avail->Signal(); ops_in_flight_lock->Unlock(); delete args; } int KvStoreBench::test_teuthology_aio(next_gen_t distr, const map &probs) { int err = 0; cout << "inserting initial entries..." << std::endl; err = test_random_insertions(); if (err < 0) { return err; } cout << "finished inserting initial entries. Waiting 10 seconds for everyone" << " to catch up..." << std::endl; sleep(10); cout << "done waiting. Starting random operations..." << std::endl; Mutex::Locker l(ops_in_flight_lock); for (int i = 0; i < ops; i++) { assert(ops_in_flight <= max_ops_in_flight); if (ops_in_flight == max_ops_in_flight) { int err = op_avail.Wait(ops_in_flight_lock); if (err < 0) { assert(false); return err; } assert(ops_in_flight < max_ops_in_flight); } cout << "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" << i + 1 << " / " << ops << std::endl; timed_args * cb_args = new timed_args(this); pair kv; int random = (rand() % 100); cb_args->op = probs.lower_bound(random)->second; switch (cb_args->op) { case 'i': kv = (((KvStoreBench *)this)->*distr)(true); if (kv.first == "") { i--; delete cb_args; continue; } ops_in_flight++; cb_args->sw.start_time(); kvs->aio_set(kv.first, kv.second, false, aio_callback_timed, cb_args, &cb_args->err); break; case 'u': kv = (((KvStoreBench *)this)->*distr)(false); if (kv.first == "") { i--; delete cb_args; continue; } ops_in_flight++; cb_args->sw.start_time(); kvs->aio_set(kv.first, kv.second, true, aio_callback_timed, cb_args, &cb_args->err); break; case 'd': kv = (((KvStoreBench *)this)->*distr)(false); if (kv.first == "") { i--; delete cb_args; continue; } key_set.erase(kv.first); ops_in_flight++; cb_args->sw.start_time(); kvs->aio_remove(kv.first, aio_callback_timed, cb_args, &cb_args->err); break; case 'r': kv = (((KvStoreBench *)this)->*distr)(false); if (kv.first == "") { i--; delete cb_args; continue; } bufferlist val; ops_in_flight++; cb_args->sw.start_time(); kvs->aio_get(kv.first, &cb_args->val, aio_callback_timed, cb_args, &cb_args->err); break; } if (cb_args) { delete cb_args; } } while(ops_in_flight > 0) { op_avail.Wait(ops_in_flight_lock); } print_time_data(); return err; } int KvStoreBench::test_teuthology_sync(next_gen_t distr, const map &probs) { int err = 0; err = test_random_insertions(); if (err < 0) { return err; } sleep(10); for (int i = 0; i < ops; i++) { StopWatch sw; pair d; cout << "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" << i + 1 << " / " << ops << std::endl; pair kv; int random = (rand() % 100); d.first = probs.lower_bound(random)->second; switch (d.first) { case 'i': kv = (((KvStoreBench *)this)->*distr)(true); if (kv.first == "") { i--; continue; } sw.start_time(); err = kvs->set(kv.first, kv.second, true); sw.stop_time(); if (err < 0) { cout << "Error setting " << kv << ": " << err << std::endl; return err; } break; case 'u': kv = (((KvStoreBench *)this)->*distr)(false); if (kv.first == "") { i--; continue; } sw.start_time(); err = kvs->set(kv.first, kv.second, true); sw.stop_time(); if (err < 0 && err != -61) { cout << "Error updating " << kv << ": " << err << std::endl; return err; } break; case 'd': kv = (((KvStoreBench *)this)->*distr)(false); if (kv.first == "") { i--; continue; } key_set.erase(kv.first); sw.start_time(); err = kvs->remove(kv.first); sw.stop_time(); if (err < 0 && err != -61) { cout << "Error removing " << kv << ": " << err << std::endl; return err; } break; case 'r': kv = (((KvStoreBench *)this)->*distr)(false); if (kv.first == "") { i--; continue; } bufferlist val; sw.start_time(); err = kvs->get(kv.first, &kv.second); sw.stop_time(); if (err < 0 && err != -61) { cout << "Error getting " << kv << ": " << err << std::endl; return err; } break; } double time = sw.get_time(); d.second = time; sw.clear(); //latency data.latency_jf.open_object_section("latency"); data.latency_jf.dump_float(string(1, d.first).c_str(), time); data.latency_jf.close_section(); } print_time_data(); return err; } void KvStoreBench::print_time_data() { cout << "========================================================\n"; cout << "latency:" << std::endl; data.latency_jf.flush(cout); cout << std::endl; cout << "throughput:" << std::endl; data.throughput_jf.flush(cout); cout << "\n========================================================" << std::endl; } int KvStoreBench::teuthology_tests() { int err = 0; if (max_ops_in_flight > 1) { test_teuthology_aio(&KvStoreBench::rand_distr, probs); } else { err = test_teuthology_sync(&KvStoreBench::rand_distr, probs); } return err; } int main(int argc, const char** argv) { KvStoreBench kvsb; int err = kvsb.setup(argc, argv); if (err == 0) cout << "setup successful" << std::endl; else{ cout << "error " << err << std::endl; return err; } err = kvsb.teuthology_tests(); if (err < 0) return err; return 0; }; ceph-0.80.11/src/test/test_arch.cc0000664000175100017510000000063412623076744020731 0ustar jenkins-buildjenkins-build #include #include #include #include "arch/probe.h" #include "arch/intel.h" #include "arch/neon.h" int main(int argc, char **argv) { ceph_arch_probe(); assert(ceph_arch_probed); printf("ceph_arch_intel_sse42 = %d\n", ceph_arch_intel_sse42); printf("ceph_arch_intel_sse2 = %d\n", ceph_arch_intel_sse2); printf("ceph_arch_neon = %d\n", ceph_arch_neon); return 0; } ceph-0.80.11/src/test/confutils.cc0000664000175100017510000003327112623076744020766 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ConfUtils.h" #include "common/config.h" #include "common/errno.h" #include "gtest/gtest.h" #include "include/buffer.h" #include #include #include #include #include #include #include #include "include/memory.h" using ceph::bufferlist; using std::cerr; using std::ostringstream; #define MAX_FILES_TO_DELETE 1000UL static size_t config_idx = 0; static size_t unlink_idx = 0; static char *to_unlink[MAX_FILES_TO_DELETE]; static std::string get_temp_dir() { static std::string temp_dir; if (temp_dir.empty()) { const char *tmpdir = getenv("TMPDIR"); if (!tmpdir) tmpdir = "/tmp"; srand(time(NULL)); ostringstream oss; oss << tmpdir << "/confutils_test_dir." << rand() << "." << getpid(); umask(022); int res = mkdir(oss.str().c_str(), 01777); if (res) { cerr << "failed to create temp directory '" << temp_dir << "'" << std::endl; return ""; } temp_dir = oss.str(); } return temp_dir; } static void unlink_all(void) { for (size_t i = 0; i < unlink_idx; ++i) { unlink(to_unlink[i]); } for (size_t i = 0; i < unlink_idx; ++i) { free(to_unlink[i]); } rmdir(get_temp_dir().c_str()); } static int create_tempfile(const std::string &fname, const char *text) { FILE *fp = fopen(fname.c_str(), "w"); if (!fp) { int err = errno; cerr << "Failed to write file '" << fname << "' to temp directory '" << get_temp_dir() << "'. " << cpp_strerror(err) << std::endl; return err; } ceph::shared_ptr fpp(fp, fclose); if (unlink_idx >= MAX_FILES_TO_DELETE) return -ENOBUFS; if (unlink_idx == 0) { memset(to_unlink, 0, sizeof(to_unlink)); atexit(unlink_all); } to_unlink[unlink_idx++] = strdup(fname.c_str()); size_t strlen_text = strlen(text); size_t res = fwrite(text, 1, strlen_text, fp); if (res != strlen_text) { int err = errno; cerr << "fwrite error while writing to " << fname << ": " << cpp_strerror(err) << std::endl; return err; } return 0; } static std::string next_tempfile(const char *text) { ostringstream oss; std::string temp_dir(get_temp_dir()); if (temp_dir.empty()) return ""; oss << temp_dir << "/test_config." << config_idx++ << ".config"; int ret = create_tempfile(oss.str(), text); if (ret) return ""; return oss.str(); } const char * const trivial_conf_1 = ""; const char * const trivial_conf_2 = "log dir = foobar"; const char * const trivial_conf_3 = "log dir = barfoo\n"; const char * const trivial_conf_4 = "log dir = \"barbaz\"\n"; const char * const simple_conf_1 = "\ ; here's a comment\n\ [global]\n\ keyring = .my_ceph_keyring\n\ \n\ [mds]\n\ log dir = out\n\ log per instance = true\n\ log sym history = 100\n\ profiling logger = true\n\ profiling logger dir = wowsers\n\ chdir = ""\n\ pid file = out/$name.pid\n\ \n\ mds debug frag = true\n\ [osd]\n\ pid file = out/$name.pid\n\ osd scrub load threshold = 5.0\n\ \n\ lockdep = 1\n\ [osd0]\n\ osd data = dev/osd0\n\ osd journal size = 100\n\ [mds.a]\n\ [mds.b]\n\ [mds.c]\n\ "; // we can add whitespace at odd locations and it will get stripped out. const char * const simple_conf_2 = "\ [mds.a]\n\ log dir = special_mds_a\n\ [mds]\n\ log sym history = 100\n\ log dir = out # after a comment, anything # can ### happen ;;; right?\n\ log per instance = true\n\ profiling logger = true\n\ profiling logger dir = log\n\ chdir = ""\n\ pid file\t=\tfoo2\n\ [osd0]\n\ keyring = osd_keyring ; osd's keyring\n\ \n\ \n\ [global]\n\ # I like pound signs as comment markers.\n\ ; Do you like pound signs as comment markers?\n\ keyring = shenanigans ; The keyring of a leprechaun\n\ \n\ # Let's just have a line with a lot of whitespace and nothing else.\n\ \n\ lockdep = 1\n\ "; // test line-combining const char * const conf3 = "\ [global]\n\ log file = /quite/a/long/path\\\n\ /for/a/log/file\n\ pid file = \\\n\ spork\\\n\ \n\ [mon] #nothing here \n\ "; const char * const escaping_conf_1 = "\ [global]\n\ log file = the \"scare quotes\"\n\ pid file = a \\\n\ pid file\n\ [mon]\n\ keyring = \"nested \\\"quotes\\\"\"\n\ "; const char * const escaping_conf_2 = "\ [apple \\]\\[]\n\ log file = floppy disk\n\ [mon]\n\ keyring = \"backslash\\\\\"\n\ "; // illegal because it contains an invalid utf8 sequence. const char illegal_conf1[] = "\ [global]\n\ log file = foo\n\ pid file = invalid-utf-\xe2\x28\xa1\n\ [osd0]\n\ keyring = osd_keyring ; osd's keyring\n\ "; // illegal because it contains a malformed section header. const char illegal_conf2[] = "\ [global\n\ log file = foo\n\ [osd0]\n\ keyring = osd_keyring ; osd's keyring\n\ "; // illegal because it contains a line that doesn't parse const char illegal_conf3[] = "\ [global]\n\ who_what_where\n\ [osd0]\n\ keyring = osd_keyring ; osd's keyring\n\ "; // illegal because it has unterminated quotes const char illegal_conf4[] = "\ [global]\n\ keyring = \"unterminated quoted string\n\ [osd0]\n\ keyring = osd_keyring ; osd's keyring\n\ "; // illegal because it has a backslash at the very end const char illegal_conf5[] = "\ [global]\n\ keyring = something awful\\\\\n\ "; // unicode config file const char unicode_config_1[] = "\ [global]\n\ log file = \x66\xd1\x86\xd1\x9d\xd3\xad\xd3\xae \n\ pid file = foo-bar\n\ [osd0]\n\ "; const char override_config_1[] = "\ [global]\n\ log file = global_log\n\ [mds]\n\ log file = mds_log\n\ [osd]\n\ log file = osd_log\n\ [osd.0]\n\ log file = osd0_log\n\ "; const char dup_key_config_1[] = "\ [mds.a]\n\ log_file = 1\n\ log_file = 3\n\ "; TEST(ConfUtils, Whitespace) { std::string test0(""); ConfFile::trim_whitespace(test0, false); ASSERT_EQ(test0, ""); std::string test0a(""); ConfFile::trim_whitespace(test0a, true); ASSERT_EQ(test0a, ""); std::string test0b(" "); ConfFile::trim_whitespace(test0b, false); ASSERT_EQ(test0b, ""); std::string test0c(" "); ConfFile::trim_whitespace(test0c, true); ASSERT_EQ(test0c, ""); std::string test1(" abc "); ConfFile::trim_whitespace(test1, false); ASSERT_EQ(test1, "abc"); std::string test2(" abc d "); ConfFile::trim_whitespace(test2, true); ASSERT_EQ(test2, "abc d"); std::string test3(" abc d "); ConfFile::trim_whitespace(test3, false); ASSERT_EQ(test3, "abc d"); std::string test4("abcd"); ConfFile::trim_whitespace(test4, false); ASSERT_EQ(test4, "abcd"); std::string test5("abcd"); ConfFile::trim_whitespace(test5, true); ASSERT_EQ(test5, "abcd"); } TEST(ConfUtils, ParseFiles0) { std::deque err; std::string val; std::ostringstream warn; std::string trivial_conf_1_f(next_tempfile(trivial_conf_1)); ConfFile cf1; ASSERT_EQ(cf1.parse_file(trivial_conf_1_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); std::string trivial_conf_2_f(next_tempfile(trivial_conf_2)); ConfFile cf2; ASSERT_EQ(cf2.parse_file(trivial_conf_2_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 1U); bufferlist bl3; bl3.append(trivial_conf_3, strlen(trivial_conf_3)); ConfFile cf3; ASSERT_EQ(cf3.parse_bufferlist(&bl3, &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf3.read("global", "log dir", val), 0); ASSERT_EQ(val, "barfoo"); std::string trivial_conf_4_f(next_tempfile(trivial_conf_4)); ConfFile cf4; ASSERT_EQ(cf4.parse_file(trivial_conf_4_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf4.read("global", "log dir", val), 0); ASSERT_EQ(val, "barbaz"); } TEST(ConfUtils, ParseFiles1) { std::deque err; std::ostringstream warn; std::string simple_conf_1_f(next_tempfile(simple_conf_1)); ConfFile cf1; ASSERT_EQ(cf1.parse_file(simple_conf_1_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); std::string simple_conf_2_f(next_tempfile(simple_conf_1)); ConfFile cf2; ASSERT_EQ(cf2.parse_file(simple_conf_2_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); bufferlist bl3; bl3.append(simple_conf_1, strlen(simple_conf_1)); ConfFile cf3; ASSERT_EQ(cf3.parse_bufferlist(&bl3, &err, &warn), 0); ASSERT_EQ(err.size(), 0U); bufferlist bl4; bl4.append(simple_conf_2, strlen(simple_conf_2)); ConfFile cf4; ASSERT_EQ(cf4.parse_bufferlist(&bl4, &err, &warn), 0); ASSERT_EQ(err.size(), 0U); } TEST(ConfUtils, ReadFiles1) { std::deque err; std::ostringstream warn; std::string simple_conf_1_f(next_tempfile(simple_conf_1)); ConfFile cf1; ASSERT_EQ(cf1.parse_file(simple_conf_1_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); std::string val; ASSERT_EQ(cf1.read("global", "keyring", val), 0); ASSERT_EQ(val, ".my_ceph_keyring"); ASSERT_EQ(cf1.read("mds", "profiling logger dir", val), 0); ASSERT_EQ(val, "wowsers"); ASSERT_EQ(cf1.read("mds", "something that does not exist", val), -ENOENT); // exists in mds section, but not in global ASSERT_EQ(cf1.read("global", "profiling logger dir", val), -ENOENT); bufferlist bl2; bl2.append(simple_conf_2, strlen(simple_conf_2)); ConfFile cf2; ASSERT_EQ(cf2.parse_bufferlist(&bl2, &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf2.read("osd0", "keyring", val), 0); ASSERT_EQ(val, "osd_keyring"); ASSERT_EQ(cf2.read("mds", "pid file", val), 0); ASSERT_EQ(val, "foo2"); ASSERT_EQ(cf2.read("nonesuch", "keyring", val), -ENOENT); } TEST(ConfUtils, ReadFiles2) { std::deque err; std::ostringstream warn; std::string conf3_f(next_tempfile(conf3)); ConfFile cf1; std::string val; ASSERT_EQ(cf1.parse_file(conf3_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf1.read("global", "log file", val), 0); ASSERT_EQ(val, "/quite/a/long/path/for/a/log/file"); ASSERT_EQ(cf1.read("global", "pid file", val), 0); ASSERT_EQ(val, "spork"); std::string unicode_config_1f(next_tempfile(unicode_config_1)); ConfFile cf2; ASSERT_EQ(cf2.parse_file(unicode_config_1f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf2.read("global", "log file", val), 0); ASSERT_EQ(val, "\x66\xd1\x86\xd1\x9d\xd3\xad\xd3\xae"); } TEST(ConfUtils, IllegalFiles) { std::deque err; std::ostringstream warn; std::string illegal_conf1_f(next_tempfile(illegal_conf1)); ConfFile cf1; std::string val; ASSERT_EQ(cf1.parse_file(illegal_conf1_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 1U); bufferlist bl2; bl2.append(illegal_conf2, strlen(illegal_conf2)); ConfFile cf2; ASSERT_EQ(cf2.parse_bufferlist(&bl2, &err, &warn), 0); ASSERT_EQ(err.size(), 1U); std::string illegal_conf3_f(next_tempfile(illegal_conf3)); ConfFile cf3; ASSERT_EQ(cf3.parse_file(illegal_conf3_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 1U); std::string illegal_conf4_f(next_tempfile(illegal_conf4)); ConfFile cf4; ASSERT_EQ(cf4.parse_file(illegal_conf4_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 1U); std::string illegal_conf5_f(next_tempfile(illegal_conf5)); ConfFile cf5; ASSERT_EQ(cf5.parse_file(illegal_conf5_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 1U); } TEST(ConfUtils, EscapingFiles) { std::deque err; std::ostringstream warn; std::string escaping_conf_1_f(next_tempfile(escaping_conf_1)); ConfFile cf1; std::string val; ASSERT_EQ(cf1.parse_file(escaping_conf_1_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf1.read("global", "log file", val), 0); ASSERT_EQ(val, "the \"scare quotes\""); ASSERT_EQ(cf1.read("global", "pid file", val), 0); ASSERT_EQ(val, "a pid file"); ASSERT_EQ(cf1.read("mon", "keyring", val), 0); ASSERT_EQ(val, "nested \"quotes\""); std::string escaping_conf_2_f(next_tempfile(escaping_conf_2)); ConfFile cf2; ASSERT_EQ(cf2.parse_file(escaping_conf_2_f.c_str(), &err, &warn), 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(cf2.read("apple ][", "log file", val), 0); ASSERT_EQ(val, "floppy disk"); ASSERT_EQ(cf2.read("mon", "keyring", val), 0); ASSERT_EQ(val, "backslash\\"); } TEST(ConfUtils, Overrides) { md_config_t conf; std::deque err; std::ostringstream warn; std::string override_conf_1_f(next_tempfile(override_config_1)); conf.name.set(CEPH_ENTITY_TYPE_MON, "0"); conf.parse_config_files(override_conf_1_f.c_str(), &err, &warn, 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(conf.log_file, "global_log"); conf.name.set(CEPH_ENTITY_TYPE_MDS, "a"); conf.parse_config_files(override_conf_1_f.c_str(), &err, &warn, 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(conf.log_file, "mds_log"); conf.name.set(CEPH_ENTITY_TYPE_OSD, "0"); conf.parse_config_files(override_conf_1_f.c_str(), &err, &warn, 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(conf.log_file, "osd0_log"); } TEST(ConfUtils, DupKey) { md_config_t conf; std::deque err; std::ostringstream warn; std::string dup_key_config_f(next_tempfile(dup_key_config_1)); conf.name.set(CEPH_ENTITY_TYPE_MDS, "a"); conf.parse_config_files(dup_key_config_f.c_str(), &err, &warn, 0); ASSERT_EQ(err.size(), 0U); ASSERT_EQ(conf.log_file, string("3")); } ceph-0.80.11/src/test/ObjectMap/0000775000175100017510000000000012623077036020302 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/ObjectMap/KeyValueDBMemory.cc0000664000175100017510000001261712623076744023751 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/encoding.h" #include "KeyValueDBMemory.h" #include #include #include "include/memory.h" #include using namespace std; /** * Iterate over the whole key space of the in-memory store * * @note Removing keys from the store while iterating over the store key-space * may result in unspecified behavior. * If one wants to safely iterate over the store while updating the * store, one should instead use a snapshot iterator, which provides * strong read-consistency. */ class WholeSpaceMemIterator : public KeyValueDB::WholeSpaceIteratorImpl { protected: KeyValueDBMemory *db; bool ready; map, bufferlist>::iterator it; public: WholeSpaceMemIterator(KeyValueDBMemory *db) : db(db), ready(false) { } virtual ~WholeSpaceMemIterator() { } int seek_to_first() { if (db->db.empty()) { it = db->db.end(); ready = false; return 0; } it = db->db.begin(); ready = true; return 0; } int seek_to_first(const string &prefix) { it = db->db.lower_bound(make_pair(prefix, "")); if (db->db.empty() || (it == db->db.end())) { it = db->db.end(); ready = false; return 0; } ready = true; return 0; } int seek_to_last() { it = db->db.end(); if (db->db.empty()) { ready = false; return 0; } --it; assert(it != db->db.end()); ready = true; return 0; } int seek_to_last(const string &prefix) { string tmp(prefix); tmp.append(1, (char) 0); it = db->db.upper_bound(make_pair(tmp,"")); if (db->db.empty() || (it == db->db.end())) { seek_to_last(); } else { ready = true; prev(); } return 0; } int lower_bound(const string &prefix, const string &to) { it = db->db.lower_bound(make_pair(prefix,to)); if ((db->db.size() == 0) || (it == db->db.end())) { it = db->db.end(); ready = false; return 0; } assert(it != db->db.end()); ready = true; return 0; } int upper_bound(const string &prefix, const string &after) { it = db->db.upper_bound(make_pair(prefix,after)); if ((db->db.size() == 0) || (it == db->db.end())) { it = db->db.end(); ready = false; return 0; } assert(it != db->db.end()); ready = true; return 0; } bool valid() { return ready && (it != db->db.end()); } bool begin() { return ready && (it == db->db.begin()); } int prev() { if (!begin() && ready) --it; else it = db->db.end(); return 0; } int next() { if (valid()) ++it; return 0; } string key() { if (valid()) return (*it).first.second; else return ""; } pair raw_key() { if (valid()) return (*it).first; else return make_pair("", ""); } bufferlist value() { if (valid()) return (*it).second; else return bufferlist(); } int status() { return 0; } }; int KeyValueDBMemory::get(const string &prefix, const std::set &key, map *out) { if (!exists_prefix(prefix)) return 0; for (std::set::const_iterator i = key.begin(); i != key.end(); ++i) { pair k(prefix, *i); if (db.count(k)) (*out)[*i] = db[k]; } return 0; } int KeyValueDBMemory::get_keys(const string &prefix, const std::set &key, std::set *out) { if (!exists_prefix(prefix)) return 0; for (std::set::const_iterator i = key.begin(); i != key.end(); ++i) { if (db.count(make_pair(prefix, *i))) out->insert(*i); } return 0; } int KeyValueDBMemory::set(const string &prefix, const string &key, const bufferlist &bl) { db[make_pair(prefix,key)] = bl; return 0; } int KeyValueDBMemory::rmkey(const string &prefix, const string &key) { db.erase(make_pair(prefix,key)); return 0; } int KeyValueDBMemory::rmkeys_by_prefix(const string &prefix) { map,bufferlist>::iterator i; i = db.lower_bound(make_pair(prefix, "")); if (i == db.end()) return 0; while (i != db.end()) { std::pair key = (*i).first; if (key.first != prefix) break; ++i; rmkey(key.first, key.second); } return 0; } KeyValueDB::WholeSpaceIterator KeyValueDBMemory::_get_iterator() { return ceph::shared_ptr( new WholeSpaceMemIterator(this) ); } class WholeSpaceSnapshotMemIterator : public WholeSpaceMemIterator { public: /** * @note * We perform a copy of the db map, which is populated by bufferlists. * * These are designed as shallow containers, thus there is a chance that * changing the underlying memory pages will lead to the iterator seeing * erroneous states. * * Although we haven't verified this yet, there is this chance, so we should * keep it in mind. */ WholeSpaceSnapshotMemIterator(KeyValueDBMemory *db) : WholeSpaceMemIterator(db) { } ~WholeSpaceSnapshotMemIterator() { delete db; } }; KeyValueDB::WholeSpaceIterator KeyValueDBMemory::_get_snapshot_iterator() { KeyValueDBMemory *snap_db = new KeyValueDBMemory(this); return ceph::shared_ptr( new WholeSpaceSnapshotMemIterator(snap_db) ); } ceph-0.80.11/src/test/ObjectMap/test_keyvaluedb_iterators.cc0000664000175100017510000015537012623076744026117 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include "include/memory.h" #include #include #include #include #include "test/ObjectMap/KeyValueDBMemory.h" #include "os/KeyValueDB.h" #include "os/LevelDBStore.h" #include #include "global/global_init.h" #include "common/ceph_argparse.h" #include "gtest/gtest.h" using namespace std; string store_path; class IteratorTest : public ::testing::Test { public: boost::scoped_ptr db; boost::scoped_ptr mock; virtual void SetUp() { assert(!store_path.empty()); LevelDBStore *db_ptr = new LevelDBStore(g_ceph_context, store_path); assert(!db_ptr->create_and_open(std::cerr)); db.reset(db_ptr); mock.reset(new KeyValueDBMemory()); } virtual void TearDown() { } ::testing::AssertionResult validate_db_clear(KeyValueDB *store) { KeyValueDB::WholeSpaceIterator it = store->get_iterator(); it->seek_to_first(); while (it->valid()) { pair k = it->raw_key(); if (mock->db.count(k)) { return ::testing::AssertionFailure() << __func__ << " mock store count " << mock->db.count(k) << " key(" << k.first << "," << k.second << ")"; } it->next(); } return ::testing::AssertionSuccess(); } ::testing::AssertionResult validate_db_match() { KeyValueDB::WholeSpaceIterator it = db->get_iterator(); it->seek_to_first(); while (it->valid()) { pair k = it->raw_key(); if (!mock->db.count(k)) { return ::testing::AssertionFailure() << __func__ << " mock db.count() " << mock->db.count(k) << " key(" << k.first << "," << k.second << ")"; } bufferlist it_bl = it->value(); bufferlist mock_bl = mock->db[k]; string it_val = _bl_to_str(it_bl); string mock_val = _bl_to_str(mock_bl); if (it_val != mock_val) { return ::testing::AssertionFailure() << __func__ << " key(" << k.first << "," << k.second << ")" << " mismatch db value(" << it_val << ")" << " mock value(" << mock_val << ")"; } it->next(); } return ::testing::AssertionSuccess(); } ::testing::AssertionResult validate_iterator( KeyValueDB::WholeSpaceIterator it, string expected_prefix, string expected_key, string expected_value) { if (!it->valid()) { return ::testing::AssertionFailure() << __func__ << " iterator not valid"; } pair key = it->raw_key(); if (expected_prefix != key.first) { return ::testing::AssertionFailure() << __func__ << " expected prefix '" << expected_prefix << "'" << " got prefix '" << key.first << "'"; } if (expected_key != it->key()) { return ::testing::AssertionFailure() << __func__ << " expected key '" << expected_key << "'" << " got key '" << it->key() << "'"; } if (it->key() != key.second) { return ::testing::AssertionFailure() << __func__ << " key '" << it->key() << "'" << " does not match" << " pair key '" << key.second << "'"; } if (_bl_to_str(it->value()) != expected_value) { return ::testing::AssertionFailure() << __func__ << " key '(" << key.first << "," << key.second << ")''" << " expected value '" << expected_value << "'" << " got value '" << _bl_to_str(it->value()) << "'"; } return ::testing::AssertionSuccess(); } /** * Checks if each key in the queue can be forward sequentially read from * the iterator iter. All keys must be present and be prefixed with prefix, * otherwise the validation will fail. * * Assumes that each key value must be based on the key name and generated * by _gen_val(). */ void validate_prefix(KeyValueDB::WholeSpaceIterator iter, string &prefix, deque &keys) { while (!keys.empty()) { ASSERT_TRUE(iter->valid()); string expected_key = keys.front(); keys.pop_front(); string expected_value = _gen_val_str(expected_key); ASSERT_TRUE(validate_iterator(iter, prefix, expected_key, expected_value)); iter->next(); } } /** * Checks if each key in the queue can be backward sequentially read from * the iterator iter. All keys must be present and be prefixed with prefix, * otherwise the validation will fail. * * Assumes that each key value must be based on the key name and generated * by _gen_val(). */ void validate_prefix_backwards(KeyValueDB::WholeSpaceIterator iter, string &prefix, deque &keys) { while (!keys.empty()) { ASSERT_TRUE(iter->valid()); string expected_key = keys.front(); keys.pop_front(); string expected_value = _gen_val_str(expected_key); ASSERT_TRUE(validate_iterator(iter, prefix, expected_key, expected_value)); iter->prev(); } } void clear(KeyValueDB *store) { KeyValueDB::WholeSpaceIterator it = store->get_snapshot_iterator(); it->seek_to_first(); KeyValueDB::Transaction t = store->get_transaction(); while (it->valid()) { pair k = it->raw_key(); t->rmkey(k.first, k.second); it->next(); } store->submit_transaction_sync(t); } string _bl_to_str(bufferlist val) { string str(val.c_str(), val.length()); return str; } string _gen_val_str(string key) { ostringstream ss; ss << "##value##" << key << "##"; return ss.str(); } bufferlist _gen_val(string key) { bufferlist bl; bl.append(_gen_val_str(key)); return bl; } void print_iterator(KeyValueDB::WholeSpaceIterator iter) { if (!iter->valid()) { std::cerr << __func__ << " iterator is not valid; stop." << std::endl; return; } int i = 0; while (iter->valid()) { pair k = iter->raw_key(); std::cerr << __func__ << " pos " << (++i) << " key (" << k.first << "," << k.second << ")" << " value(" << _bl_to_str(iter->value()) << ")" << std::endl; iter->next(); } } void print_db(KeyValueDB *store) { KeyValueDB::WholeSpaceIterator it = store->get_iterator(); it->seek_to_first(); print_iterator(it); } }; // ------- Remove Keys / Remove Keys By Prefix ------- class RmKeysTest : public IteratorTest { public: string prefix1; string prefix2; string prefix3; void init(KeyValueDB *db) { KeyValueDB::Transaction tx = db->get_transaction(); tx->set(prefix1, "11", _gen_val("11")); tx->set(prefix1, "12", _gen_val("12")); tx->set(prefix1, "13", _gen_val("13")); tx->set(prefix2, "21", _gen_val("21")); tx->set(prefix2, "22", _gen_val("22")); tx->set(prefix2, "23", _gen_val("23")); tx->set(prefix3, "31", _gen_val("31")); tx->set(prefix3, "32", _gen_val("32")); tx->set(prefix3, "33", _gen_val("33")); db->submit_transaction_sync(tx); } virtual void SetUp() { IteratorTest::SetUp(); prefix1 = "_PREFIX_1_"; prefix2 = "_PREFIX_2_"; prefix3 = "_PREFIX_3_"; clear(db.get()); ASSERT_TRUE(validate_db_clear(db.get())); clear(mock.get()); ASSERT_TRUE(validate_db_match()); init(db.get()); init(mock.get()); ASSERT_TRUE(validate_db_match()); } virtual void TearDown() { IteratorTest::TearDown(); } /** * Test the transaction's rmkeys behavior when we remove a given prefix * from the beginning of the key space, or from the end of the key space, * or even simply in the middle. */ void RmKeysByPrefix(KeyValueDB *store) { // remove prefix2 ; check if prefix1 remains, and then prefix3 KeyValueDB::Transaction tx = store->get_transaction(); // remove the prefix in the middle of the key space tx->rmkeys_by_prefix(prefix2); store->submit_transaction_sync(tx); deque key_deque; KeyValueDB::WholeSpaceIterator iter = store->get_iterator(); iter->seek_to_first(); // check for prefix1 key_deque.push_back("11"); key_deque.push_back("12"); key_deque.push_back("13"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); // check for prefix3 ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("31"); key_deque.push_back("32"); key_deque.push_back("33"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); clear(store); ASSERT_TRUE(validate_db_clear(store)); init(store); // remove prefix1 ; check if prefix2 and then prefix3 remain tx = store->get_transaction(); // remove the prefix at the beginning of the key space tx->rmkeys_by_prefix(prefix1); store->submit_transaction_sync(tx); iter = store->get_iterator(); iter->seek_to_first(); // check for prefix2 key_deque.clear(); key_deque.push_back("21"); key_deque.push_back("22"); key_deque.push_back("23"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); // check for prefix3 ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("31"); key_deque.push_back("32"); key_deque.push_back("33"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); clear(store); ASSERT_TRUE(validate_db_clear(store)); init(store); // remove prefix3 ; check if prefix1 and then prefix2 remain tx = store->get_transaction(); // remove the prefix at the end of the key space tx->rmkeys_by_prefix(prefix3); store->submit_transaction_sync(tx); iter = store->get_iterator(); iter->seek_to_first(); // check for prefix1 key_deque.clear(); key_deque.push_back("11"); key_deque.push_back("12"); key_deque.push_back("13"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); // check for prefix2 ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("21"); key_deque.push_back("22"); key_deque.push_back("23"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); } /** * Test how the leveldb's whole-space iterator behaves when we remove * keys from the store while iterating over them. */ void RmKeysWhileIteratingSnapshot(KeyValueDB *store, KeyValueDB::WholeSpaceIterator iter) { SCOPED_TRACE("RmKeysWhileIteratingSnapshot"); iter->seek_to_first(); ASSERT_TRUE(iter->valid()); KeyValueDB::Transaction t = store->get_transaction(); t->rmkey(prefix1, "11"); t->rmkey(prefix1, "12"); t->rmkey(prefix2, "23"); t->rmkey(prefix3, "33"); store->submit_transaction_sync(t); deque key_deque; // check for prefix1 key_deque.push_back("11"); key_deque.push_back("12"); key_deque.push_back("13"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); // check for prefix2 key_deque.clear(); key_deque.push_back("21"); key_deque.push_back("22"); key_deque.push_back("23"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); // check for prefix3 key_deque.clear(); key_deque.push_back("31"); key_deque.push_back("32"); key_deque.push_back("33"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); iter->next(); ASSERT_FALSE(iter->valid()); // make sure those keys were removed from the store KeyValueDB::WholeSpaceIterator tmp_it = store->get_iterator(); tmp_it->seek_to_first(); ASSERT_TRUE(tmp_it->valid()); key_deque.clear(); key_deque.push_back("13"); validate_prefix(tmp_it, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(tmp_it->valid()); key_deque.clear(); key_deque.push_back("21"); key_deque.push_back("22"); validate_prefix(tmp_it, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(tmp_it->valid()); key_deque.clear(); key_deque.push_back("31"); key_deque.push_back("32"); validate_prefix(tmp_it, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(tmp_it->valid()); } }; TEST_F(RmKeysTest, RmKeysByPrefixLevelDB) { SCOPED_TRACE("LevelDB"); RmKeysByPrefix(db.get()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(RmKeysTest, RmKeysByPrefixMockDB) { SCOPED_TRACE("Mock DB"); RmKeysByPrefix(mock.get()); ASSERT_FALSE(HasFatalFailure()); } /** * If you refer to function RmKeysTest::RmKeysWhileIteratingSnapshot(), * you will notice that we seek the iterator to the first key, and then * we go on to remove several keys from the underlying store, including * the first couple keys. * * We would expect that during this test, as soon as we removed the keys * from the store, the iterator would get invalid, or cause some sort of * unexpected mess. * * Instead, the current version of leveldb handles it perfectly, by making * the iterator to use a snapshot instead of the store's real state. This * way, LevelDBStore's whole-space iterator will behave much like its own * whole-space snapshot iterator. * * However, this particular behavior of the iterator hasn't been documented * on leveldb, and we should assume that it can be changed at any point in * time. * * Therefore, we keep this test, being exactly the same as the one for the * whole-space snapshot iterator, as we currently assume they should behave * identically. If this test fails, at some point, and the whole-space * snapshot iterator passes, then it probably means that leveldb changed * how its iterator behaves. */ TEST_F(RmKeysTest, RmKeysWhileIteratingLevelDB) { SCOPED_TRACE("LevelDB -- WholeSpaceIterator"); RmKeysWhileIteratingSnapshot(db.get(), db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(RmKeysTest, RmKeysWhileIteratingMockDB) { std::cout << "There is no safe way to test key removal while iterating\n" << "over the mock store without using snapshots" << std::endl; } TEST_F(RmKeysTest, RmKeysWhileIteratingSnapshotLevelDB) { SCOPED_TRACE("LevelDB -- WholeSpaceSnapshotIterator"); RmKeysWhileIteratingSnapshot(db.get(), db->get_snapshot_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(RmKeysTest, RmKeysWhileIteratingSnapshotMockDB) { SCOPED_TRACE("Mock DB -- WholeSpaceSnapshotIterator"); RmKeysWhileIteratingSnapshot(mock.get(), mock->get_snapshot_iterator()); ASSERT_FALSE(HasFatalFailure()); } // ------- Set Keys / Update Values ------- class SetKeysTest : public IteratorTest { public: string prefix1; string prefix2; void init(KeyValueDB *db) { KeyValueDB::Transaction tx = db->get_transaction(); tx->set(prefix1, "aaa", _gen_val("aaa")); tx->set(prefix1, "ccc", _gen_val("ccc")); tx->set(prefix1, "eee", _gen_val("eee")); tx->set(prefix2, "vvv", _gen_val("vvv")); tx->set(prefix2, "xxx", _gen_val("xxx")); tx->set(prefix2, "zzz", _gen_val("zzz")); db->submit_transaction_sync(tx); } virtual void SetUp() { IteratorTest::SetUp(); prefix1 = "_PREFIX_1_"; prefix2 = "_PREFIX_2_"; clear(db.get()); ASSERT_TRUE(validate_db_clear(db.get())); clear(mock.get()); ASSERT_TRUE(validate_db_match()); init(db.get()); init(mock.get()); ASSERT_TRUE(validate_db_match()); } virtual void TearDown() { IteratorTest::TearDown(); } /** * Make sure that the iterator picks on new keys added if it hasn't yet * iterated away from that position. * * This should only happen for the whole-space iterator when not using * the snapshot version. * * We don't need to test the validity of all elements, but we do test * inserting while moving from the first element to the last, using next() * to move forward, and then we test the same behavior while iterating * from the last element to the first, using prev() to move backwards. */ void SetKeysWhileIterating(KeyValueDB *store, KeyValueDB::WholeSpaceIterator iter) { iter->seek_to_first(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "aaa", _gen_val_str("aaa"))); iter->next(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "ccc", _bl_to_str(_gen_val("ccc")))); // insert new key 'ddd' after 'ccc' and before 'eee' KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "ddd", _gen_val("ddd")); store->submit_transaction_sync(tx); iter->next(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "ddd", _gen_val_str("ddd"))); iter->seek_to_last(); ASSERT_TRUE(iter->valid()); tx = store->get_transaction(); tx->set(prefix2, "yyy", _gen_val("yyy")); store->submit_transaction_sync(tx); iter->prev(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix2, "yyy", _gen_val_str("yyy"))); } /** * Make sure that the whole-space snapshot iterator does not pick on new keys * added to the store since we created the iterator, thus guaranteeing * read-consistency. * * We don't need to test the validity of all elements, but we do test * inserting while moving from the first element to the last, using next() * to move forward, and then we test the same behavior while iterating * from the last element to the first, using prev() to move backwards. */ void SetKeysWhileIteratingSnapshot(KeyValueDB *store, KeyValueDB::WholeSpaceIterator iter) { iter->seek_to_first(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "aaa", _gen_val_str("aaa"))); iter->next(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "ccc", _bl_to_str(_gen_val("ccc")))); // insert new key 'ddd' after 'ccc' and before 'eee' KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "ddd", _gen_val("ddd")); store->submit_transaction_sync(tx); iter->next(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "eee", _gen_val_str("eee"))); iter->seek_to_last(); ASSERT_TRUE(iter->valid()); tx = store->get_transaction(); tx->set(prefix2, "yyy", _gen_val("yyy")); store->submit_transaction_sync(tx); iter->prev(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix2, "xxx", _gen_val_str("xxx"))); } /** * Make sure that the whole-space iterator is able to read values changed on * the store, even after we moved to the updated position. * * This should only be possible when not using the whole-space snapshot * version of the iterator. */ void UpdateValuesWhileIterating(KeyValueDB *store, KeyValueDB::WholeSpaceIterator iter) { iter->seek_to_first(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "aaa", _gen_val_str("aaa"))); KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "aaa", _gen_val("aaa_1")); store->submit_transaction_sync(tx); ASSERT_TRUE(validate_iterator(iter, prefix1, "aaa", _gen_val_str("aaa_1"))); iter->seek_to_last(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix2, "zzz", _gen_val_str("zzz"))); tx = store->get_transaction(); tx->set(prefix2, "zzz", _gen_val("zzz_1")); store->submit_transaction_sync(tx); ASSERT_TRUE(validate_iterator(iter, prefix2, "zzz", _gen_val_str("zzz_1"))); } /** * Make sure that the whole-space iterator is able to read values changed on * the store, even after we moved to the updated position. * * This should only be possible when not using the whole-space snapshot * version of the iterator. */ void UpdateValuesWhileIteratingSnapshot( KeyValueDB *store, KeyValueDB::WholeSpaceIterator iter) { iter->seek_to_first(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix1, "aaa", _gen_val_str("aaa"))); KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "aaa", _gen_val("aaa_1")); store->submit_transaction_sync(tx); ASSERT_TRUE(validate_iterator(iter, prefix1, "aaa", _gen_val_str("aaa"))); iter->seek_to_last(); ASSERT_TRUE(iter->valid()); ASSERT_TRUE(validate_iterator(iter, prefix2, "zzz", _gen_val_str("zzz"))); tx = store->get_transaction(); tx->set(prefix2, "zzz", _gen_val("zzz_1")); store->submit_transaction_sync(tx); ASSERT_TRUE(validate_iterator(iter, prefix2, "zzz", _gen_val_str("zzz"))); // check those values were really changed in the store KeyValueDB::WholeSpaceIterator tmp_iter = store->get_iterator(); tmp_iter->seek_to_first(); ASSERT_TRUE(tmp_iter->valid()); ASSERT_TRUE(validate_iterator(tmp_iter, prefix1, "aaa", _gen_val_str("aaa_1"))); tmp_iter->seek_to_last(); ASSERT_TRUE(tmp_iter->valid()); ASSERT_TRUE(validate_iterator(tmp_iter, prefix2, "zzz", _gen_val_str("zzz_1"))); } }; TEST_F(SetKeysTest, DISABLED_SetKeysWhileIteratingLevelDB) { SCOPED_TRACE("LevelDB: SetKeysWhileIteratingLevelDB"); SetKeysWhileIterating(db.get(), db->get_iterator()); ASSERT_TRUE(HasFatalFailure()); } TEST_F(SetKeysTest, SetKeysWhileIteratingMockDB) { SCOPED_TRACE("Mock DB: SetKeysWhileIteratingMockDB"); SetKeysWhileIterating(mock.get(), mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SetKeysTest, SetKeysWhileIteratingSnapshotLevelDB) { SCOPED_TRACE("LevelDB: SetKeysWhileIteratingSnapshotLevelDB"); SetKeysWhileIteratingSnapshot(db.get(), db->get_snapshot_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SetKeysTest, SetKeysWhileIteratingSnapshotMockDB) { SCOPED_TRACE("MockDB: SetKeysWhileIteratingSnapshotMockDB"); SetKeysWhileIteratingSnapshot(mock.get(), mock->get_snapshot_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SetKeysTest, DISABLED_UpdateValuesWhileIteratingLevelDB) { SCOPED_TRACE("LevelDB: UpdateValuesWhileIteratingLevelDB"); UpdateValuesWhileIterating(db.get(), db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SetKeysTest, UpdateValuesWhileIteratingMockDB) { SCOPED_TRACE("MockDB: UpdateValuesWhileIteratingMockDB"); UpdateValuesWhileIterating(mock.get(), mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SetKeysTest, UpdateValuesWhileIteratingSnapshotLevelDB) { SCOPED_TRACE("LevelDB: UpdateValuesWhileIteratingSnapshotLevelDB"); UpdateValuesWhileIteratingSnapshot(db.get(), db->get_snapshot_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SetKeysTest, UpdateValuesWhileIteratingSnapshotMockDB) { SCOPED_TRACE("MockDB: UpdateValuesWhileIteratingSnapshotMockDB"); UpdateValuesWhileIteratingSnapshot(mock.get(), mock->get_snapshot_iterator()); ASSERT_FALSE(HasFatalFailure()); } class BoundsTest : public IteratorTest { public: string prefix1; string prefix2; string prefix3; void init(KeyValueDB *store) { KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "aaa", _gen_val("aaa")); tx->set(prefix1, "ccc", _gen_val("ccc")); tx->set(prefix1, "eee", _gen_val("eee")); tx->set(prefix2, "vvv", _gen_val("vvv")); tx->set(prefix2, "xxx", _gen_val("xxx")); tx->set(prefix2, "zzz", _gen_val("zzz")); tx->set(prefix3, "aaa", _gen_val("aaa")); tx->set(prefix3, "mmm", _gen_val("mmm")); tx->set(prefix3, "yyy", _gen_val("yyy")); store->submit_transaction_sync(tx); } virtual void SetUp() { IteratorTest::SetUp(); prefix1 = "_PREFIX_1_"; prefix2 = "_PREFIX_2_"; prefix3 = "_PREFIX_4_"; clear(db.get()); ASSERT_TRUE(validate_db_clear(db.get())); clear(mock.get()); ASSERT_TRUE(validate_db_match()); init(db.get()); init(mock.get()); ASSERT_TRUE(validate_db_match()); } virtual void TearDown() { IteratorTest::TearDown(); } void LowerBoundWithEmptyKeyOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // see what happens when we have an empty key and try to get to the // first available prefix iter->lower_bound(prefix1, ""); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // if we got here without problems, then it is safe to assume the // remaining prefixes are intact. // see what happens when we have an empty key and try to get to the // middle of the key-space iter->lower_bound(prefix2, ""); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("vvv"); key_deque.push_back("xxx"); key_deque.push_back("zzz"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // if we got here without problems, then it is safe to assume the // remaining prefixes are intact. // see what happens when we have an empty key and try to get to the // last prefix on the key-space iter->lower_bound(prefix3, ""); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); key_deque.push_back("mmm"); key_deque.push_back("yyy"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); // we reached the end of the key_space, so the iterator should no longer // be valid // see what happens when we look for an inexistent prefix, that will // compare higher than the existing prefixes, with an empty key // expected: reach the store's end; iterator becomes invalid iter->lower_bound("_PREFIX_9_", ""); ASSERT_FALSE(iter->valid()); // see what happens when we look for an inexistent prefix, that will // compare lower than the existing prefixes, with an empty key // expected: find the first prefix; iterator is valid iter->lower_bound("_PREFIX_0_", ""); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // see what happens when we look for an empty prefix (that should compare // lower than any existing prefixes) // expected: find the first prefix; iterator is valid iter->lower_bound("", ""); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); } void LowerBoundWithEmptyPrefixOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // check for an empty prefix, with key 'aaa'. Since this key is shared // among two different prefixes, it is relevant to check which will be // found first. // expected: find key (prefix1, aaa); iterator is valid iter->lower_bound("", "aaa"); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // since we found prefix1, it is safe to assume that the remaining // prefixes (prefix2 and prefix3) will follow // any lower_bound operation with an empty prefix should always put the // iterator in the first key in the key-space, despite what key is // specified. This means that looking for ("","AAAAAAAAAA") should // also position the iterator on (prefix1, aaa). // expected: find key (prefix1, aaa); iterator is valid iter->lower_bound("", "AAAAAAAAAA"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // note: this test is a duplicate of the one in the function above. Why? // Well, because it also fits here (being its prefix empty), and one could // very well run solely this test (instead of the whole battery) and would // certainly expect this case to be tested. // see what happens when we look for an empty prefix (that should compare // lower than any existing prefixes) // expected: find the first prefix; iterator is valid iter->lower_bound("", ""); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); } void LowerBoundOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // check that we find the first key in the store // expected: find (prefix1, aaa); iterator is valid iter->lower_bound(prefix1, "aaa"); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that we find the last key in the store // expected: find (prefix3, yyy); iterator is valid iter->lower_bound(prefix3, "yyy"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("yyy"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); // check that looking for non-existent prefix '_PREFIX_0_' will // always result in the first value of prefix1 (prefix1,"aaa") // expected: find (prefix1, aaa); iterator is valid iter->lower_bound("_PREFIX_0_", "AAAAA"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that looking for non-existent prefix '_PREFIX_3_' will // always result in the first value of prefix3 (prefix4,"aaa") // expected: find (prefix3, aaa); iterator is valid iter->lower_bound("_PREFIX_3_", "AAAAA"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that looking for non-existent prefix '_PREFIX_9_' will // always result in an invalid iterator. // expected: iterator is invalid iter->lower_bound("_PREFIX_9_", "AAAAA"); ASSERT_FALSE(iter->valid()); } void UpperBoundWithEmptyKeyOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // check that looking for (prefix1, "") will result in finding // the first key in prefix1 (prefix1, "aaa") // expected: find (prefix1, aaa); iterator is valid iter->upper_bound(prefix1, ""); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that looking for (prefix2, "") will result in finding // the first key in prefix2 (prefix2, vvv) // expected: find (prefix2, aaa); iterator is valid iter->upper_bound(prefix2, ""); key_deque.push_back("vvv"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that looking for (prefix3, "") will result in finding // the first key in prefix3 (prefix3, aaa) // expected: find (prefix3, aaa); iterator is valid iter->upper_bound(prefix3, ""); key_deque.push_back("aaa"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // see what happens when we look for an inexistent prefix, that will // compare higher than the existing prefixes, with an empty key // expected: reach the store's end; iterator becomes invalid iter->upper_bound("_PREFIX_9_", ""); ASSERT_FALSE(iter->valid()); // see what happens when we look for an inexistent prefix, that will // compare lower than the existing prefixes, with an empty key // expected: find the first prefix; iterator is valid iter->upper_bound("_PREFIX_0_", ""); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // see what happens when we look for an empty prefix (that should compare // lower than any existing prefixes) // expected: find the first prefix; iterator is valid iter->upper_bound("", ""); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); } void UpperBoundWithEmptyPrefixOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // check for an empty prefix, with key 'aaa'. Since this key is shared // among two different prefixes, it is relevant to check which will be // found first. // expected: find key (prefix1, aaa); iterator is valid iter->upper_bound("", "aaa"); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // any upper_bound operation with an empty prefix should always put the // iterator in the first key whose prefix compares greater, despite the // key that is specified. This means that looking for ("","AAAAAAAAAA") // should position the iterator on (prefix1, aaa). // expected: find key (prefix1, aaa); iterator is valid iter->upper_bound("", "AAAAAAAAAA"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // note: this test is a duplicate of the one in the function above. Why? // Well, because it also fits here (being its prefix empty), and one could // very well run solely this test (instead of the whole battery) and would // certainly expect this case to be tested. // see what happens when we look for an empty prefix (that should compare // lower than any existing prefixes) // expected: find the first prefix; iterator is valid iter->upper_bound("", ""); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); } void UpperBoundOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // check that we find the second key in the store // expected: find (prefix1, ccc); iterator is valid iter->upper_bound(prefix1, "bbb"); ASSERT_TRUE(iter->valid()); key_deque.push_back("ccc"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that we find the last key in the store // expected: find (prefix3, yyy); iterator is valid iter->upper_bound(prefix3, "xxx"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("yyy"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); // check that looking for non-existent prefix '_PREFIX_0_' will // always result in the first value of prefix1 (prefix1,"aaa") // expected: find (prefix1, aaa); iterator is valid iter->upper_bound("_PREFIX_0_", "AAAAA"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that looking for non-existent prefix '_PREFIX_3_' will // always result in the first value of prefix3 (prefix3,"aaa") // expected: find (prefix3, aaa); iterator is valid iter->upper_bound("_PREFIX_3_", "AAAAA"); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix3, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // check that looking for non-existent prefix '_PREFIX_9_' will // always result in an invalid iterator. // expected: iterator is invalid iter->upper_bound("_PREFIX_9_", "AAAAA"); ASSERT_FALSE(iter->valid()); } }; TEST_F(BoundsTest, LowerBoundWithEmptyKeyOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Lower Bound, Empty Key, Whole-Space Iterator"); LowerBoundWithEmptyKeyOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, LowerBoundWithEmptyKeyOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Lower Bound, Empty Key, Whole-Space Iterator"); LowerBoundWithEmptyKeyOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, LowerBoundWithEmptyPrefixOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Lower Bound, Empty Prefix, Whole-Space Iterator"); LowerBoundWithEmptyPrefixOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, LowerBoundWithEmptyPrefixOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Lower Bound, Empty Prefix, Whole-Space Iterator"); LowerBoundWithEmptyPrefixOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, LowerBoundOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Lower Bound, Whole-Space Iterator"); LowerBoundOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, LowerBoundOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Lower Bound, Whole-Space Iterator"); LowerBoundOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, UpperBoundWithEmptyKeyOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Upper Bound, Empty Key, Whole-Space Iterator"); UpperBoundWithEmptyKeyOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, UpperBoundWithEmptyKeyOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Upper Bound, Empty Key, Whole-Space Iterator"); UpperBoundWithEmptyKeyOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, UpperBoundWithEmptyPrefixOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Upper Bound, Empty Prefix, Whole-Space Iterator"); UpperBoundWithEmptyPrefixOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, UpperBoundWithEmptyPrefixOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Upper Bound, Empty Prefix, Whole-Space Iterator"); UpperBoundWithEmptyPrefixOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, UpperBoundOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Upper Bound, Whole-Space Iterator"); UpperBoundOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(BoundsTest, UpperBoundOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Upper Bound, Whole-Space Iterator"); UpperBoundOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } class SeeksTest : public IteratorTest { public: string prefix0; string prefix1; string prefix2; string prefix3; string prefix4; string prefix5; void init(KeyValueDB *store) { KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "aaa", _gen_val("aaa")); tx->set(prefix1, "ccc", _gen_val("ccc")); tx->set(prefix1, "eee", _gen_val("eee")); tx->set(prefix2, "vvv", _gen_val("vvv")); tx->set(prefix2, "xxx", _gen_val("xxx")); tx->set(prefix2, "zzz", _gen_val("zzz")); tx->set(prefix4, "aaa", _gen_val("aaa")); tx->set(prefix4, "mmm", _gen_val("mmm")); tx->set(prefix4, "yyy", _gen_val("yyy")); store->submit_transaction_sync(tx); } virtual void SetUp() { IteratorTest::SetUp(); prefix0 = "_PREFIX_0_"; prefix1 = "_PREFIX_1_"; prefix2 = "_PREFIX_2_"; prefix3 = "_PREFIX_3_"; prefix4 = "_PREFIX_4_"; prefix5 = "_PREFIX_5_"; clear(db.get()); ASSERT_TRUE(validate_db_clear(db.get())); clear(mock.get()); ASSERT_TRUE(validate_db_match()); init(db.get()); init(mock.get()); ASSERT_TRUE(validate_db_match()); } virtual void TearDown() { IteratorTest::TearDown(); } void SeekToFirstOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { iter->seek_to_first(); ASSERT_TRUE(iter->valid()); deque key_deque; key_deque.push_back("aaa"); key_deque.push_back("ccc"); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); } void SeekToFirstWithPrefixOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // if the prefix is empty, we must end up seeking to the first key. // expected: seek to (prefix1, aaa); iterator is valid iter->seek_to_first(""); ASSERT_TRUE(iter->valid()); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to non-existent prefix that compares lower than the // first available prefix // expected: seek to (prefix1, aaa); iterator is valid iter->seek_to_first(prefix0); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to non-existent prefix // expected: seek to (prefix4, aaa); iterator is valid iter->seek_to_first(prefix3); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix4, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to non-existent prefix that compares greater than the // last available prefix // expected: iterator is invalid iter->seek_to_first(prefix5); ASSERT_FALSE(iter->valid()); // try seeking to the first prefix and make sure we end up in its first // position // expected: seek to (prefix1,aaa); iterator is valid iter->seek_to_first(prefix1); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to the second prefix and make sure we end up in its // first position // expected: seek to (prefix2,vvv); iterator is valid iter->seek_to_first(prefix2); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("vvv"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to the last prefix and make sure we end up in its // first position // expected: seek to (prefix4,aaa); iterator is valid iter->seek_to_first(prefix4); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("aaa"); validate_prefix(iter, prefix4, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); } void SeekToLastOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; iter->seek_to_last(); key_deque.push_back("yyy"); validate_prefix(iter, prefix4, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); } void SeekToLastWithPrefixOnWholeSpaceIterator( KeyValueDB::WholeSpaceIterator iter) { deque key_deque; // if the prefix is empty, we must end up seeking to last position // that has an empty prefix, or to the previous position to the first // position whose prefix compares higher than empty. // expected: iterator is invalid (because (prefix1,aaa) is the first // position that compared higher than an empty prefix) iter->seek_to_last(""); ASSERT_FALSE(iter->valid()); // try seeking to non-existent prefix that compares lower than the // first available prefix // expected: iterator is invalid (because (prefix1,aaa) is the first // position that compared higher than prefix0) iter->seek_to_last(prefix0); ASSERT_FALSE(iter->valid()); // try seeking to non-existent prefix // expected: seek to (prefix2, zzz); iterator is valid iter->seek_to_last(prefix3); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("zzz"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to non-existent prefix that compares greater than the // last available prefix // expected: iterator is in the last position of the store; // i.e., (prefix4,yyy) iter->seek_to_last(prefix5); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("yyy"); validate_prefix(iter, prefix4, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); // try seeking to the first prefix and make sure we end up in its last // position // expected: seek to (prefix1,eee); iterator is valid iter->seek_to_last(prefix1); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("eee"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to the second prefix and make sure we end up in its // last position // expected: seek to (prefix2,vvv); iterator is valid iter->seek_to_last(prefix2); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("zzz"); validate_prefix(iter, prefix2, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_TRUE(iter->valid()); // try seeking to the last prefix and make sure we end up in its // last position // expected: seek to (prefix4,aaa); iterator is valid iter->seek_to_last(prefix4); ASSERT_TRUE(iter->valid()); key_deque.clear(); key_deque.push_back("yyy"); validate_prefix(iter, prefix4, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); } }; TEST_F(SeeksTest, SeekToFirstOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Seek To First, Whole Space Iterator"); SeekToFirstOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToFirstOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Seek To First, Whole Space Iterator"); SeekToFirstOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToFirstWithPrefixOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Seek To First, With Prefix, Whole Space Iterator"); SeekToFirstWithPrefixOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToFirstWithPrefixOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Seek To First, With Prefix, Whole Space Iterator"); SeekToFirstWithPrefixOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToLastOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Seek To Last, Whole Space Iterator"); SeekToLastOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToLastOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Seek To Last, Whole Space Iterator"); SeekToLastOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToLastWithPrefixOnWholeSpaceIteratorLevelDB) { SCOPED_TRACE("LevelDB: Seek To Last, With Prefix, Whole Space Iterator"); SeekToLastWithPrefixOnWholeSpaceIterator(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(SeeksTest, SeekToLastWithPrefixOnWholeSpaceIteratorMockDB) { SCOPED_TRACE("MockDB: Seek To Last, With Prefix, Whole Space Iterator"); SeekToLastWithPrefixOnWholeSpaceIterator(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } class KeySpaceIteration : public IteratorTest { public: string prefix1; void init(KeyValueDB *store) { KeyValueDB::Transaction tx = store->get_transaction(); tx->set(prefix1, "aaa", _gen_val("aaa")); tx->set(prefix1, "vvv", _gen_val("vvv")); tx->set(prefix1, "zzz", _gen_val("zzz")); store->submit_transaction_sync(tx); } virtual void SetUp() { IteratorTest::SetUp(); prefix1 = "_PREFIX_1_"; clear(db.get()); ASSERT_TRUE(validate_db_clear(db.get())); clear(mock.get()); ASSERT_TRUE(validate_db_match()); init(db.get()); init(mock.get()); ASSERT_TRUE(validate_db_match()); } virtual void TearDown() { IteratorTest::TearDown(); } void ForwardIteration(KeyValueDB::WholeSpaceIterator iter) { deque key_deque; iter->seek_to_first(); key_deque.push_back("aaa"); key_deque.push_back("vvv"); key_deque.push_back("zzz"); validate_prefix(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); } void BackwardIteration(KeyValueDB::WholeSpaceIterator iter) { deque key_deque; iter->seek_to_last(); key_deque.push_back("zzz"); key_deque.push_back("vvv"); key_deque.push_back("aaa"); validate_prefix_backwards(iter, prefix1, key_deque); ASSERT_FALSE(HasFatalFailure()); ASSERT_FALSE(iter->valid()); } }; TEST_F(KeySpaceIteration, ForwardIterationLevelDB) { SCOPED_TRACE("LevelDB: Forward Iteration, Whole Space Iterator"); ForwardIteration(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(KeySpaceIteration, ForwardIterationMockDB) { SCOPED_TRACE("MockDB: Forward Iteration, Whole Space Iterator"); ForwardIteration(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(KeySpaceIteration, BackwardIterationLevelDB) { SCOPED_TRACE("LevelDB: Backward Iteration, Whole Space Iterator"); BackwardIteration(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(KeySpaceIteration, BackwardIterationMockDB) { SCOPED_TRACE("MockDB: Backward Iteration, Whole Space Iterator"); BackwardIteration(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } class EmptyStore : public IteratorTest { public: virtual void SetUp() { IteratorTest::SetUp(); clear(db.get()); ASSERT_TRUE(validate_db_clear(db.get())); clear(mock.get()); ASSERT_TRUE(validate_db_match()); } void SeekToFirst(KeyValueDB::WholeSpaceIterator iter) { // expected: iterator is invalid iter->seek_to_first(); ASSERT_FALSE(iter->valid()); } void SeekToFirstWithPrefix(KeyValueDB::WholeSpaceIterator iter) { // expected: iterator is invalid iter->seek_to_first("prefix"); ASSERT_FALSE(iter->valid()); } void SeekToLast(KeyValueDB::WholeSpaceIterator iter) { // expected: iterator is invalid iter->seek_to_last(); ASSERT_FALSE(iter->valid()); } void SeekToLastWithPrefix(KeyValueDB::WholeSpaceIterator iter) { // expected: iterator is invalid iter->seek_to_last("prefix"); ASSERT_FALSE(iter->valid()); } void LowerBound(KeyValueDB::WholeSpaceIterator iter) { // expected: iterator is invalid iter->lower_bound("prefix", ""); ASSERT_FALSE(iter->valid()); // expected: iterator is invalid iter->lower_bound("", "key"); ASSERT_FALSE(iter->valid()); // expected: iterator is invalid iter->lower_bound("prefix", "key"); ASSERT_FALSE(iter->valid()); } void UpperBound(KeyValueDB::WholeSpaceIterator iter) { // expected: iterator is invalid iter->upper_bound("prefix", ""); ASSERT_FALSE(iter->valid()); // expected: iterator is invalid iter->upper_bound("", "key"); ASSERT_FALSE(iter->valid()); // expected: iterator is invalid iter->upper_bound("prefix", "key"); ASSERT_FALSE(iter->valid()); } }; TEST_F(EmptyStore, SeekToFirstLevelDB) { SCOPED_TRACE("LevelDB: Empty Store, Seek To First"); SeekToFirst(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToFirstMockDB) { SCOPED_TRACE("MockDB: Empty Store, Seek To First"); SeekToFirst(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToFirstWithPrefixLevelDB) { SCOPED_TRACE("LevelDB: Empty Store, Seek To First With Prefix"); SeekToFirstWithPrefix(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToFirstWithPrefixMockDB) { SCOPED_TRACE("MockDB: Empty Store, Seek To First With Prefix"); SeekToFirstWithPrefix(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToLastLevelDB) { SCOPED_TRACE("LevelDB: Empty Store, Seek To Last"); SeekToLast(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToLastMockDB) { SCOPED_TRACE("MockDB: Empty Store, Seek To Last"); SeekToLast(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToLastWithPrefixLevelDB) { SCOPED_TRACE("LevelDB: Empty Store, Seek To Last With Prefix"); SeekToLastWithPrefix(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, SeekToLastWithPrefixMockDB) { SCOPED_TRACE("MockDB: Empty Store, Seek To Last With Prefix"); SeekToLastWithPrefix(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, LowerBoundLevelDB) { SCOPED_TRACE("LevelDB: Empty Store, Lower Bound"); LowerBound(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, LowerBoundMockDB) { SCOPED_TRACE("MockDB: Empty Store, Lower Bound"); LowerBound(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, UpperBoundLevelDB) { SCOPED_TRACE("LevelDB: Empty Store, Upper Bound"); UpperBound(db->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } TEST_F(EmptyStore, UpperBoundMockDB) { SCOPED_TRACE("MockDB: Empty Store, Upper Bound"); UpperBound(mock->get_iterator()); ASSERT_FALSE(HasFatalFailure()); } int main(int argc, char *argv[]) { vector args; argv_to_vec(argc, (const char **) argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); if (argc < 2) { std::cerr << "Usage: " << argv[0] << "[ceph_options] [gtest_options] " << std::endl; return 1; } store_path = string(argv[1]); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/ObjectMap/test_keyvaluedb_atomicity.cc0000664000175100017510000000545012623076744026076 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include #include "include/buffer.h" #include "os/LevelDBStore.h" #include #include #include #include #include "include/memory.h" #include #include #include "stdlib.h" const string CONTROL_PREFIX = "CONTROL"; const string PRIMARY_PREFIX = "PREFIX"; const int NUM_COPIES = 100; const int NUM_THREADS = 30; string prefix_gen(int i) { stringstream ss; ss << PRIMARY_PREFIX << "_" << i << std::endl; return ss.str(); } int verify(KeyValueDB *db) { // Verify { map iterators; for (int i = 0; i < NUM_COPIES; ++i) { iterators[i] = db->get_iterator(prefix_gen(i)); iterators[i]->seek_to_first(); } while (iterators.rbegin()->second->valid()) { for (map::iterator i = iterators.begin(); i != iterators.end(); ++i) { assert(i->second->valid()); assert(i->second->key() == iterators.rbegin()->second->key()); bufferlist r = i->second->value(); bufferlist l = iterators.rbegin()->second->value(); i->second->next(); } } for (map::iterator i = iterators.begin(); i != iterators.end(); ++i) { assert(!i->second->valid()); } } return 0; } void *write(void *_db) { KeyValueDB *db = static_cast(_db); std::cout << "Writing..." << std::endl; for (int i = 0; i < 12000; ++i) { if (!(i % 10)) { std::cout << "Iteration: " << i << std::endl; } int key_num = rand(); stringstream key; key << key_num << std::endl; map to_set; stringstream val; val << i << std::endl; bufferptr bp(val.str().c_str(), val.str().size() + 1); to_set[key.str()].push_back(bp); KeyValueDB::Transaction t = db->get_transaction(); for (int j = 0; j < NUM_COPIES; ++j) { t->set(prefix_gen(j), to_set); } assert(!db->submit_transaction(t)); } return 0; } int main() { char *path = getenv("OBJECT_MAP_PATH"); boost::scoped_ptr< KeyValueDB > db; if (!path) { std::cerr << "No path found, OBJECT_MAP_PATH undefined" << std::endl; return 0; } string strpath(path); std::cerr << "Using path: " << strpath << std::endl; LevelDBStore *store = new LevelDBStore(NULL, strpath); assert(!store->create_and_open(std::cerr)); db.reset(store); verify(db.get()); vector threads(NUM_THREADS); for (vector::iterator i = threads.begin(); i != threads.end(); ++i) { pthread_create(&*i, 0, &write, static_cast(db.get())); } for (vector::iterator i = threads.begin(); i != threads.end(); ++i) { void *tmp; pthread_join(*i, &tmp); } verify(db.get()); } ceph-0.80.11/src/test/ObjectMap/KeyValueDBMemory.h0000664000175100017510000000764512623076744023620 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include #include "include/memory.h" #include "os/KeyValueDB.h" #include "include/buffer.h" #include "include/Context.h" using std::string; class KeyValueDBMemory : public KeyValueDB { public: std::map,bufferlist> db; KeyValueDBMemory() { } KeyValueDBMemory(KeyValueDBMemory *db) : db(db->db) { } virtual ~KeyValueDBMemory() { } virtual int init() { return 0; } virtual int open(ostream &out) { return 0; } virtual int create_and_open(ostream &out) { return 0; } int get( const string &prefix, const std::set &key, std::map *out ); int get_keys( const string &prefix, const std::set &key, std::set *out ); int set( const string &prefix, const string &key, const bufferlist &bl ); int rmkey( const string &prefix, const string &key ); int rmkeys_by_prefix( const string &prefix ); class TransactionImpl_ : public TransactionImpl { public: list on_commit; KeyValueDBMemory *db; TransactionImpl_(KeyValueDBMemory *db) : db(db) {} struct SetOp : public Context { KeyValueDBMemory *db; std::pair key; bufferlist value; SetOp(KeyValueDBMemory *db, const std::pair &key, const bufferlist &value) : db(db), key(key), value(value) {} void finish(int r) { db->set(key.first, key.second, value); } }; void set(const string &prefix, const string &k, const bufferlist& bl) { on_commit.push_back(new SetOp(db, std::make_pair(prefix, k), bl)); } struct RmKeysOp : public Context { KeyValueDBMemory *db; std::pair key; RmKeysOp(KeyValueDBMemory *db, const std::pair &key) : db(db), key(key) {} void finish(int r) { db->rmkey(key.first, key.second); } }; void rmkey(const string &prefix, const string &key) { on_commit.push_back(new RmKeysOp(db, std::make_pair(prefix, key))); } struct RmKeysByPrefixOp : public Context { KeyValueDBMemory *db; string prefix; RmKeysByPrefixOp(KeyValueDBMemory *db, const string &prefix) : db(db), prefix(prefix) {} void finish(int r) { db->rmkeys_by_prefix(prefix); } }; void rmkeys_by_prefix(const string &prefix) { on_commit.push_back(new RmKeysByPrefixOp(db, prefix)); } int complete() { for (list::iterator i = on_commit.begin(); i != on_commit.end(); on_commit.erase(i++)) { (*i)->complete(0); } return 0; } ~TransactionImpl_() { for (list::iterator i = on_commit.begin(); i != on_commit.end(); on_commit.erase(i++)) { delete *i; } } }; Transaction get_transaction() { return Transaction(new TransactionImpl_(this)); } int submit_transaction(Transaction trans) { return static_cast(trans.get())->complete(); } uint64_t get_estimated_size(map &extras) { uint64_t total_size = 0; for (map,bufferlist>::iterator p = db.begin(); p != db.end(); ++p) { string prefix = p->first.first; bufferlist &bl = p->second; uint64_t sz = bl.length(); total_size += sz; if (extras.count(prefix) == 0) extras[prefix] = 0; extras[prefix] += sz; } return total_size; } private: bool exists_prefix(const string &prefix) { std::map,bufferlist>::iterator it; it = db.lower_bound(std::make_pair(prefix, "")); return ((it != db.end()) && ((*it).first.first == prefix)); } friend class WholeSpaceMemIterator; protected: WholeSpaceIterator _get_iterator(); WholeSpaceIterator _get_snapshot_iterator(); }; ceph-0.80.11/src/test/ObjectMap/test_object_map.cc0000664000175100017510000005171712623076744023773 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/memory.h" #include #include #include #include "include/buffer.h" #include "test/ObjectMap/KeyValueDBMemory.h" #include "os/KeyValueDB.h" #include "os/DBObjectMap.h" #include "os/HashIndex.h" #include "os/LevelDBStore.h" #include #include "global/global_init.h" #include "common/ceph_argparse.h" #include #include "gtest/gtest.h" #include "stdlib.h" using namespace std; template typename T::iterator rand_choose(T &cont) { if (cont.size() == 0) { return cont.end(); } int index = rand() % cont.size(); typename T::iterator retval = cont.begin(); for (; index > 0; --index) ++retval; return retval; } string num_str(unsigned i) { char buf[100]; snprintf(buf, sizeof(buf), "%.10u", i); return string(buf); } class ObjectMapTester { public: ObjectMap *db; set key_space; set object_name_space; map > omap; map hmap; map > xattrs; unsigned seq; ObjectMapTester() : db(0), seq(0) {} string val_from_key(const string &object, const string &key) { return object + "_" + key + "_" + num_str(seq++); } void set_key(const string &objname, const string &key, const string &value) { set_key(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), key, value); } void set_xattr(const string &objname, const string &key, const string &value) { set_xattr(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), key, value); } void set_key(ghobject_t hoid, string key, string value) { map to_write; bufferptr bp(value.c_str(), value.size()); bufferlist bl; bl.append(bp); to_write.insert(make_pair(key, bl)); db->set_keys(hoid, to_write); } void set_xattr(ghobject_t hoid, string key, string value) { map to_write; bufferptr bp(value.c_str(), value.size()); bufferlist bl; bl.append(bp); to_write.insert(make_pair(key, bl)); db->set_xattrs(hoid, to_write); } void set_header(const string &objname, const string &value) { set_header(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), value); } void set_header(ghobject_t hoid, const string &value) { bufferlist header; header.append(bufferptr(value.c_str(), value.size() + 1)); db->set_header(hoid, header); } int get_header(const string &objname, string *value) { return get_header(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), value); } int get_header(ghobject_t hoid, string *value) { bufferlist header; int r = db->get_header(hoid, &header); if (r < 0) return r; if (header.length()) *value = string(header.c_str()); else *value = string(""); return 0; } int get_xattr(const string &objname, const string &key, string *value) { return get_xattr(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), key, value); } int get_xattr(ghobject_t hoid, string key, string *value) { set to_get; to_get.insert(key); map got; db->get_xattrs(hoid, to_get, &got); if (!got.empty()) { *value = string(got.begin()->second.c_str(), got.begin()->second.length()); return 1; } else { return 0; } } int get_key(const string &objname, const string &key, string *value) { return get_key(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), key, value); } int get_key(ghobject_t hoid, string key, string *value) { set to_get; to_get.insert(key); map got; db->get_values(hoid, to_get, &got); if (!got.empty()) { *value = string(got.begin()->second.c_str(), got.begin()->second.length()); return 1; } else { return 0; } } void remove_key(const string &objname, const string &key) { remove_key(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), key); } void remove_key(ghobject_t hoid, string key) { set to_remove; to_remove.insert(key); db->rm_keys(hoid, to_remove); } void remove_xattr(const string &objname, const string &key) { remove_xattr(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), key); } void remove_xattr(ghobject_t hoid, string key) { set to_remove; to_remove.insert(key); db->remove_xattrs(hoid, to_remove); } void clone(const string &objname, const string &target) { clone(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP))), ghobject_t(hobject_t(sobject_t(target, CEPH_NOSNAP)))); } void clone(ghobject_t hoid, ghobject_t hoid2) { db->clone(hoid, hoid2); } void clear(const string &objname) { clear(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP)))); } void clear(ghobject_t hoid) { db->clear(hoid); } void clear_omap(const string &objname) { clear_omap(ghobject_t(hobject_t(sobject_t(objname, CEPH_NOSNAP)))); } void clear_omap(const ghobject_t &objname) { db->clear_keys_header(objname); } void def_init() { for (unsigned i = 0; i < 1000; ++i) { key_space.insert("key_" + num_str(i)); } for (unsigned i = 0; i < 1000; ++i) { object_name_space.insert("name_" + num_str(i)); } } void init_key_set(const set &keys) { key_space = keys; } void init_object_name_space(const set &onamespace) { object_name_space = onamespace; } void auto_set_xattr(ostream &out) { set::iterator key = rand_choose(key_space); set::iterator object = rand_choose(object_name_space); string value = val_from_key(*object, *key); xattrs[*object][*key] = value; set_xattr(*object, *key, value); out << "auto_set_xattr " << *object << ": " << *key << " -> " << value << std::endl; } void auto_set_key(ostream &out) { set::iterator key = rand_choose(key_space); set::iterator object = rand_choose(object_name_space); string value = val_from_key(*object, *key); omap[*object][*key] = value; set_key(*object, *key, value); out << "auto_set_key " << *object << ": " << *key << " -> " << value << std::endl; } void xattrs_on_object(const string &object, set *out) { if (!xattrs.count(object)) return; const map &xmap = xattrs.find(object)->second; for (map::const_iterator i = xmap.begin(); i != xmap.end(); ++i) { out->insert(i->first); } } void keys_on_object(const string &object, set *out) { if (!omap.count(object)) return; const map &kmap = omap.find(object)->second; for (map::const_iterator i = kmap.begin(); i != kmap.end(); ++i) { out->insert(i->first); } } void xattrs_off_object(const string &object, set *out) { *out = key_space; set xspace; xattrs_on_object(object, &xspace); for (set::iterator i = xspace.begin(); i != xspace.end(); ++i) { out->erase(*i); } } void keys_off_object(const string &object, set *out) { *out = key_space; set kspace; keys_on_object(object, &kspace); for (set::iterator i = kspace.begin(); i != kspace.end(); ++i) { out->erase(*i); } } int auto_check_present_xattr(ostream &out) { set::iterator object = rand_choose(object_name_space); set xspace; xattrs_on_object(*object, &xspace); set::iterator key = rand_choose(xspace); if (key == xspace.end()) { return 1; } string result; int r = get_xattr(*object, *key, &result); if (!r) { out << "auto_check_present_key: failed to find key " << *key << " on object " << *object << std::endl; return 0; } if (result != xattrs[*object][*key]) { out << "auto_check_present_key: for key " << *key << " on object " << *object << " found value " << result << " where we should have found " << xattrs[*object][*key] << std::endl; return 0; } out << "auto_check_present_key: for key " << *key << " on object " << *object << " found value " << result << " where we should have found " << xattrs[*object][*key] << std::endl; return 1; } int auto_check_present_key(ostream &out) { set::iterator object = rand_choose(object_name_space); set kspace; keys_on_object(*object, &kspace); set::iterator key = rand_choose(kspace); if (key == kspace.end()) { return 1; } string result; int r = get_key(*object, *key, &result); if (!r) { out << "auto_check_present_key: failed to find key " << *key << " on object " << *object << std::endl; return 0; } if (result != omap[*object][*key]) { out << "auto_check_present_key: for key " << *key << " on object " << *object << " found value " << result << " where we should have found " << omap[*object][*key] << std::endl; return 0; } out << "auto_check_present_key: for key " << *key << " on object " << *object << " found value " << result << " where we should have found " << omap[*object][*key] << std::endl; return 1; } int auto_check_absent_xattr(ostream &out) { set::iterator object = rand_choose(object_name_space); set xspace; xattrs_off_object(*object, &xspace); set::iterator key = rand_choose(xspace); if (key == xspace.end()) { return 1; } string result; int r = get_xattr(*object, *key, &result); if (!r) { out << "auto_check_absent_key: did not find key " << *key << " on object " << *object << std::endl; return 1; } out << "auto_check_basent_key: for key " << *key << " on object " << *object << " found value " << result << " where we should have found nothing" << std::endl; return 0; } int auto_check_absent_key(ostream &out) { set::iterator object = rand_choose(object_name_space); set kspace; keys_off_object(*object, &kspace); set::iterator key = rand_choose(kspace); if (key == kspace.end()) { return 1; } string result; int r = get_key(*object, *key, &result); if (!r) { out << "auto_check_absent_key: did not find key " << *key << " on object " << *object << std::endl; return 1; } out << "auto_check_basent_key: for key " << *key << " on object " << *object << " found value " << result << " where we should have found nothing" << std::endl; return 0; } void auto_clone_key(ostream &out) { set::iterator object = rand_choose(object_name_space); set::iterator target = rand_choose(object_name_space); while (target == object) { target = rand_choose(object_name_space); } out << "clone " << *object << " to " << *target; clone(*object, *target); if (!omap.count(*object)) { out << " source missing."; omap.erase(*target); } else { out << " source present."; omap[*target] = omap[*object]; } if (!hmap.count(*object)) { out << " hmap source missing." << std::endl; hmap.erase(*target); } else { out << " hmap source present." << std::endl; hmap[*target] = hmap[*object]; } if (!xattrs.count(*object)) { out << " hmap source missing." << std::endl; xattrs.erase(*target); } else { out << " hmap source present." << std::endl; xattrs[*target] = xattrs[*object]; } } void auto_remove_key(ostream &out) { set::iterator object = rand_choose(object_name_space); set kspace; keys_on_object(*object, &kspace); set::iterator key = rand_choose(kspace); if (key == kspace.end()) { return; } out << "removing " << *key << " from " << *object << std::endl; omap[*object].erase(*key); remove_key(*object, *key); } void auto_remove_xattr(ostream &out) { set::iterator object = rand_choose(object_name_space); set kspace; xattrs_on_object(*object, &kspace); set::iterator key = rand_choose(kspace); if (key == kspace.end()) { return; } out << "removing xattr " << *key << " from " << *object << std::endl; xattrs[*object].erase(*key); remove_xattr(*object, *key); } void auto_delete_object(ostream &out) { set::iterator object = rand_choose(object_name_space); out << "auto_delete_object " << *object << std::endl; clear(*object); omap.erase(*object); hmap.erase(*object); xattrs.erase(*object); } void auto_clear_omap(ostream &out) { set::iterator object = rand_choose(object_name_space); out << "auto_clear_object " << *object << std::endl; clear_omap(*object); omap.erase(*object); hmap.erase(*object); } void auto_write_header(ostream &out) { set::iterator object = rand_choose(object_name_space); string header = val_from_key(*object, "HEADER"); out << "auto_write_header: " << *object << " -> " << header << std::endl; set_header(*object, header); hmap[*object] = header; } int auto_verify_header(ostream &out) { set::iterator object = rand_choose(object_name_space); out << "verify_header: " << *object << " "; string header; int r = get_header(*object, &header); if (r < 0) { assert(0); } if (header.size() == 0) { if (hmap.count(*object)) { out << " failed to find header " << hmap[*object] << std::endl; return 0; } else { out << " found no header" << std::endl; return 1; } } if (!hmap.count(*object)) { out << " found header " << header << " should have been empty" << std::endl; return 0; } else if (header == hmap[*object]) { out << " found correct header " << header << std::endl; return 1; } else { out << " found incorrect header " << header << " where we should have found " << hmap[*object] << std::endl; return 0; } } }; class ObjectMapTest : public ::testing::Test { public: boost::scoped_ptr< ObjectMap > db; ObjectMapTester tester; virtual void SetUp() { char *path = getenv("OBJECT_MAP_PATH"); if (!path) { db.reset(new DBObjectMap(new KeyValueDBMemory())); tester.db = db.get(); return; } string strpath(path); cerr << "using path " << strpath << std::endl;; LevelDBStore *store = new LevelDBStore(g_ceph_context, strpath); assert(!store->create_and_open(cerr)); db.reset(new DBObjectMap(store)); tester.db = db.get(); } virtual void TearDown() { std::cerr << "Checking..." << std::endl; assert(db->check(std::cerr)); } }; int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } TEST_F(ObjectMapTest, CreateOneObject) { ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)), 100, 0); map to_set; string key("test"); string val("test_val"); bufferptr bp(val.c_str(), val.size()); bufferlist bl; bl.append(bp); to_set.insert(make_pair(key, bl)); ASSERT_FALSE(db->set_keys(hoid, to_set)); map got; set to_get; to_get.insert(key); to_get.insert("not there"); db->get_values(hoid, to_get, &got); ASSERT_EQ(got.size(), (unsigned)1); ASSERT_EQ(string(got[key].c_str(), got[key].length()), val); bufferlist header; got.clear(); db->get(hoid, &header, &got); ASSERT_EQ(got.size(), (unsigned)1); ASSERT_EQ(string(got[key].c_str(), got[key].length()), val); ASSERT_EQ(header.length(), (unsigned)0); db->rm_keys(hoid, to_get); got.clear(); db->get(hoid, &header, &got); ASSERT_EQ(got.size(), (unsigned)0); map attrs; attrs["attr1"] = bl; db->set_xattrs(hoid, attrs); db->set_header(hoid, bl); db->clear_keys_header(hoid); set attrs_got; db->get_all_xattrs(hoid, &attrs_got); ASSERT_EQ(attrs_got.size(), 1U); ASSERT_EQ(*(attrs_got.begin()), "attr1"); db->get(hoid, &header, &got); ASSERT_EQ(got.size(), (unsigned)0); ASSERT_EQ(header.length(), 0U); got.clear(); db->clear(hoid); db->get(hoid, &header, &got); ASSERT_EQ(got.size(), (unsigned)0); attrs_got.clear(); db->get_all_xattrs(hoid, &attrs_got); ASSERT_EQ(attrs_got.size(), 0U); } TEST_F(ObjectMapTest, CloneOneObject) { ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)), 200, 0); ghobject_t hoid2(hobject_t(sobject_t("foo2", CEPH_NOSNAP)), 201, 1); tester.set_key(hoid, "foo", "bar"); tester.set_key(hoid, "foo2", "bar2"); string result; int r = tester.get_key(hoid, "foo", &result); ASSERT_EQ(r, 1); ASSERT_EQ(result, "bar"); db->clone(hoid, hoid2); r = tester.get_key(hoid, "foo", &result); ASSERT_EQ(r, 1); ASSERT_EQ(result, "bar"); r = tester.get_key(hoid2, "foo", &result); ASSERT_EQ(r, 1); ASSERT_EQ(result, "bar"); tester.remove_key(hoid, "foo"); r = tester.get_key(hoid2, "foo", &result); ASSERT_EQ(r, 1); ASSERT_EQ(result, "bar"); r = tester.get_key(hoid, "foo", &result); ASSERT_EQ(r, 0); r = tester.get_key(hoid, "foo2", &result); ASSERT_EQ(r, 1); ASSERT_EQ(result, "bar2"); tester.set_key(hoid, "foo", "baz"); tester.remove_key(hoid, "foo"); r = tester.get_key(hoid, "foo", &result); ASSERT_EQ(r, 0); tester.set_key(hoid, "foo2", "baz"); tester.remove_key(hoid, "foo2"); r = tester.get_key(hoid, "foo2", &result); ASSERT_EQ(r, 0); map got; bufferlist header; got.clear(); db->clear(hoid); db->get(hoid, &header, &got); ASSERT_EQ(got.size(), (unsigned)0); got.clear(); r = db->clear(hoid2); ASSERT_EQ(0, r); db->get(hoid2, &header, &got); ASSERT_EQ(got.size(), (unsigned)0); tester.set_key(hoid, "baz", "bar"); got.clear(); db->get(hoid, &header, &got); ASSERT_EQ(got.size(), (unsigned)1); db->clear(hoid); db->clear(hoid2); } TEST_F(ObjectMapTest, OddEvenClone) { ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP))); ghobject_t hoid2(hobject_t(sobject_t("foo2", CEPH_NOSNAP))); for (unsigned i = 0; i < 1000; ++i) { tester.set_key(hoid, "foo" + num_str(i), "bar" + num_str(i)); } db->clone(hoid, hoid2); int r = 0; for (unsigned i = 0; i < 1000; ++i) { string result; r = tester.get_key(hoid, "foo" + num_str(i), &result); ASSERT_EQ(1, r); ASSERT_EQ("bar" + num_str(i), result); r = tester.get_key(hoid2, "foo" + num_str(i), &result); ASSERT_EQ(1, r); ASSERT_EQ("bar" + num_str(i), result); if (i % 2) { tester.remove_key(hoid, "foo" + num_str(i)); } else { tester.remove_key(hoid2, "foo" + num_str(i)); } } for (unsigned i = 0; i < 1000; ++i) { string result; string result2; r = tester.get_key(hoid, "foo" + num_str(i), &result); int r2 = tester.get_key(hoid2, "foo" + num_str(i), &result2); if (i % 2) { ASSERT_EQ(0, r); ASSERT_EQ(1, r2); ASSERT_EQ("bar" + num_str(i), result2); } else { ASSERT_EQ(0, r2); ASSERT_EQ(1, r); ASSERT_EQ("bar" + num_str(i), result); } } { ObjectMap::ObjectMapIterator iter = db->get_iterator(hoid); iter->seek_to_first(); for (unsigned i = 0; i < 1000; ++i) { if (!(i % 2)) { ASSERT_TRUE(iter->valid()); ASSERT_EQ("foo" + num_str(i), iter->key()); iter->next(); } } } { ObjectMap::ObjectMapIterator iter2 = db->get_iterator(hoid2); iter2->seek_to_first(); for (unsigned i = 0; i < 1000; ++i) { if (i % 2) { ASSERT_TRUE(iter2->valid()); ASSERT_EQ("foo" + num_str(i), iter2->key()); iter2->next(); } } } db->clear(hoid); db->clear(hoid2); } TEST_F(ObjectMapTest, RandomTest) { tester.def_init(); for (unsigned i = 0; i < 5000; ++i) { unsigned val = rand(); val <<= 8; val %= 100; if (!(i%100)) std::cout << "on op " << i << " val is " << val << std::endl; if (val < 7) { tester.auto_write_header(std::cerr); } else if (val < 14) { ASSERT_TRUE(tester.auto_verify_header(std::cerr)); } else if (val < 30) { tester.auto_set_key(std::cerr); } else if (val < 42) { tester.auto_set_xattr(std::cerr); } else if (val < 55) { ASSERT_TRUE(tester.auto_check_present_key(std::cerr)); } else if (val < 62) { ASSERT_TRUE(tester.auto_check_present_xattr(std::cerr)); } else if (val < 70) { ASSERT_TRUE(tester.auto_check_absent_key(std::cerr)); } else if (val < 72) { ASSERT_TRUE(tester.auto_check_absent_xattr(std::cerr)); } else if (val < 73) { tester.auto_clear_omap(std::cerr); } else if (val < 76) { tester.auto_delete_object(std::cerr); } else if (val < 85) { tester.auto_clone_key(std::cerr); } else if (val < 92) { tester.auto_remove_xattr(std::cerr); } else { tester.auto_remove_key(std::cerr); } } } ceph-0.80.11/src/test/crypto.cc0000664000175100017510000000767412623076744020310 0ustar jenkins-buildjenkins-build#include #include #include "include/types.h" #include "auth/Crypto.h" #include "common/ceph_crypto.h" #include "test/unit.h" class CryptoEnvironment: public ::testing::Environment { public: void SetUp() { ceph::crypto::init(g_ceph_context); } }; ::testing::Environment* const crypto_env = ::testing::AddGlobalTestEnvironment(new CryptoEnvironment); TEST(AES, ValidateSecret) { CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); int l; for (l=0; l<16; l++) { bufferptr bp(l); int err; err = h->validate_secret(bp); EXPECT_EQ(-EINVAL, err); } for (l=16; l<50; l++) { bufferptr bp(l); int err; err = h->validate_secret(bp); EXPECT_EQ(0, err); } } TEST(AES, Encrypt) { CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); char secret_s[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; bufferptr secret(secret_s, sizeof(secret_s)); unsigned char plaintext_s[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }; bufferlist plaintext; plaintext.append((char *)plaintext_s, sizeof(plaintext_s)); bufferlist cipher; std::string error; h->encrypt(secret, plaintext, cipher, error); ASSERT_EQ(error, ""); unsigned char want_cipher[] = { 0xb3, 0x8f, 0x5b, 0xc9, 0x35, 0x4c, 0xf8, 0xc6, 0x13, 0x15, 0x66, 0x6f, 0x37, 0xd7, 0x79, 0x3a, 0x11, 0x90, 0x7b, 0xe9, 0xd8, 0x3c, 0x35, 0x70, 0x58, 0x7b, 0x97, 0x9b, 0x03, 0xd2, 0xa5, 0x01, }; char cipher_s[sizeof(want_cipher)]; ASSERT_EQ(sizeof(cipher_s), cipher.length()); cipher.copy(0, sizeof(cipher_s), &cipher_s[0]); int err; err = memcmp(cipher_s, want_cipher, sizeof(want_cipher)); ASSERT_EQ(0, err); } TEST(AES, Decrypt) { CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); char secret_s[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; bufferptr secret(secret_s, sizeof(secret_s)); unsigned char cipher_s[] = { 0xb3, 0x8f, 0x5b, 0xc9, 0x35, 0x4c, 0xf8, 0xc6, 0x13, 0x15, 0x66, 0x6f, 0x37, 0xd7, 0x79, 0x3a, 0x11, 0x90, 0x7b, 0xe9, 0xd8, 0x3c, 0x35, 0x70, 0x58, 0x7b, 0x97, 0x9b, 0x03, 0xd2, 0xa5, 0x01, }; bufferlist cipher; cipher.append((char *)cipher_s, sizeof(cipher_s)); unsigned char want_plaintext[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }; char plaintext_s[sizeof(want_plaintext)]; std::string error; bufferlist plaintext; h->decrypt(secret, cipher, plaintext, error); ASSERT_EQ(error, ""); ASSERT_EQ(sizeof(plaintext_s), plaintext.length()); plaintext.copy(0, sizeof(plaintext_s), &plaintext_s[0]); int err; err = memcmp(plaintext_s, want_plaintext, sizeof(want_plaintext)); ASSERT_EQ(0, err); } TEST(AES, Loop) { int err; char secret_s[16]; err = get_random_bytes(secret_s, sizeof(secret_s)); ASSERT_EQ(0, err); bufferptr secret(secret_s, sizeof(secret_s)); char orig_plaintext_s[1024]; err = get_random_bytes(orig_plaintext_s, sizeof(orig_plaintext_s)); ASSERT_EQ(0, err); bufferlist plaintext; plaintext.append(orig_plaintext_s, sizeof(orig_plaintext_s)); for (int i=0; i<10000; i++) { bufferlist cipher; { CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); std::string error; h->encrypt(secret, plaintext, cipher, error); ASSERT_EQ(error, ""); } plaintext.clear(); { CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); std::string error; h->decrypt(secret, cipher, plaintext, error); ASSERT_EQ(error, ""); } } char plaintext_s[sizeof(orig_plaintext_s)]; plaintext.copy(0, sizeof(plaintext_s), &plaintext_s[0]); err = memcmp(plaintext_s, orig_plaintext_s, sizeof(orig_plaintext_s)); ASSERT_EQ(0, err); } ceph-0.80.11/src/test/TestSignalHandlers.cc0000664000175100017510000000463012623076744022513 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2010 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* * TestSignalHandlers * * Test the Ceph signal handlers */ #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/errno.h" #include "common/debug.h" #include "common/config.h" #include #include #include #include using std::string; // avoid compiler warning about dereferencing NULL pointer static int* get_null() { return 0; } static void simple_segv_test() { generic_dout(-1) << "triggering SIGSEGV..." << dendl; int i = *get_null(); std::cout << "i = " << i << std::endl; } static void infinite_recursion_test_impl() { infinite_recursion_test_impl(); } static void infinite_recursion_test() { generic_dout(0) << "triggering SIGSEGV with infinite recursion..." << dendl; infinite_recursion_test_impl(); } static void usage() { cerr << "usage: TestSignalHandlers [test]" << std::endl; cerr << "--simple_segv: run simple_segv test" << std::endl; cerr << "--infinite_recursion: run infinite_recursion test" << std::endl; generic_client_usage(); // Will exit() } typedef void (*test_fn_t)(void); int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); test_fn_t fn = NULL; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); } else if (ceph_argparse_flag(args, i, "--infinite_recursion", (char*)NULL)) { fn = infinite_recursion_test; } else if (ceph_argparse_flag(args, i, "-s", "--simple_segv", (char*)NULL)) { fn = simple_segv_test; } else { cerr << "Garbage at end of command line." << std::endl; usage(); } } if (!fn) { std::cerr << "Please select a test to run. Type -h for help." << std::endl; usage(); } fn(); return 0; } ceph-0.80.11/src/test/common/0000775000175100017510000000000012623077036017726 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/common/histogram.cc0000664000175100017510000000465512623076744022251 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 Inktank * * LGPL2.1 (see COPYING-LGPL2.1) or later */ #include #include #include "common/histogram.h" #include "include/stringify.h" TEST(Histogram, Basic) { pow2_hist_t h; h.add(0); h.add(0); h.add(0); ASSERT_EQ(3, h.h[0]); ASSERT_EQ(1u, h.h.size()); h.add(1); ASSERT_EQ(3, h.h[0]); ASSERT_EQ(1, h.h[1]); ASSERT_EQ(2u, h.h.size()); h.add(2); h.add(2); ASSERT_EQ(3, h.h[0]); ASSERT_EQ(1, h.h[1]); ASSERT_EQ(2, h.h[2]); ASSERT_EQ(3u, h.h.size()); } TEST(Histogram, Set) { pow2_hist_t h; h.set_bin(0, 12); h.set_bin(2, 12); ASSERT_EQ(12, h.h[0]); ASSERT_EQ(0, h.h[1]); ASSERT_EQ(12, h.h[2]); ASSERT_EQ(3u, h.h.size()); } TEST(Histogram, Position) { pow2_hist_t h; uint64_t lb, ub; h.add(0); ASSERT_EQ(-1, h.get_position_micro(-20, &lb, &ub)); } TEST(Histogram, Position1) { pow2_hist_t h; h.add(0); uint64_t lb, ub; h.get_position_micro(0, &lb, &ub); ASSERT_EQ(0u, lb); ASSERT_EQ(1000000u, ub); h.add(0); h.add(0); h.add(0); h.get_position_micro(0, &lb, &ub); ASSERT_EQ(0u, lb); ASSERT_EQ(1000000u, ub); } TEST(Histogram, Position2) { pow2_hist_t h; h.add(1); h.add(1); uint64_t lb, ub; h.get_position_micro(0, &lb, &ub); ASSERT_EQ(0u, lb); ASSERT_EQ(0u, ub); h.add(0); h.get_position_micro(0, &lb, &ub); ASSERT_EQ(0u, lb); ASSERT_EQ(333333u, ub); h.get_position_micro(1, &lb, &ub); ASSERT_EQ(333333u, lb); ASSERT_EQ(1000000u, ub); } TEST(Histogram, Position3) { pow2_hist_t h; h.h.resize(10, 0); h.h[0] = 1; h.h[5] = 1; uint64_t lb, ub; h.get_position_micro(4, &lb, &ub); ASSERT_EQ(500000u, lb); ASSERT_EQ(500000u, ub); } TEST(Histogram, Position4) { pow2_hist_t h; h.h.resize(10, 0); h.h[0] = UINT_MAX; h.h[5] = UINT_MAX; uint64_t lb, ub; h.get_position_micro(4, &lb, &ub); ASSERT_EQ(0u, lb); ASSERT_EQ(0u, ub); } TEST(Histogram, Decay) { pow2_hist_t h; h.set_bin(0, 123); h.set_bin(3, 12); h.set_bin(5, 1); h.decay(1); ASSERT_EQ(61, h.h[0]); ASSERT_EQ(6, h.h[3]); ASSERT_EQ(4u, h.h.size()); } /* * Local Variables: * compile-command: "cd ../.. ; make -j4 && * make unittest_histogram && * valgrind --tool=memcheck --leak-check=full \ * ./unittest_histogram * " * End: */ ceph-0.80.11/src/test/common/ObjectContents.cc0000664000175100017510000000602712623076744023173 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "ObjectContents.h" #include "include/buffer.h" #include #include bool test_object_contents() { ObjectContents c, d; assert(!c.exists()); c.debug(std::cerr); c.write(10, 10, 10); assert(c.exists()); assert(c.size() == 20); c.debug(std::cerr); bufferlist bl; for (ObjectContents::Iterator iter = c.get_iterator(); iter.valid(); ++iter) { bl.append(*iter); } assert(bl.length() == 20); bufferlist bl2; for (unsigned i = 0; i < 8; ++i) bl2.append(bl[i]); c.write(10, 8, 4); c.debug(std::cerr); ObjectContents::Iterator iter = c.get_iterator(); iter.seek_to(8); for (uint64_t i = 8; i < 12; ++i, ++iter) { bl2.append(*iter); } for (unsigned i = 12; i < 20; ++i) bl2.append(bl[i]); assert(bl2.length() == 20); for (ObjectContents::Iterator iter3 = c.get_iterator(); iter.valid(); ++iter) { assert(bl2[iter3.get_pos()] == *iter3); } assert(bl2[0] == '\0'); assert(bl2[7] == '\0'); interval_set to_clone; to_clone.insert(5, 10); d.clone_range(c, to_clone); assert(d.size() == 15); c.debug(std::cerr); d.debug(std::cerr); ObjectContents::Iterator iter2 = d.get_iterator(); iter2.seek_to(5); for (uint64_t i = 5; i < 15; ++i, ++iter2) { std::cerr << "i is " << i << std::endl; assert(iter2.get_pos() == i); assert(*iter2 == bl2[i]); } return true; } unsigned int ObjectContents::Iterator::get_state(uint64_t _pos) { if (parent->seeds.count(_pos)) { return parent->seeds[_pos]; } seek_to(_pos - 1); return current_state; } void ObjectContents::clone_range(ObjectContents &other, interval_set &intervals) { interval_set written_to_clone; written_to_clone.intersection_of(intervals, other.written); interval_set zeroed = intervals; zeroed.subtract(written_to_clone); written.union_of(intervals); written.subtract(zeroed); for (interval_set::iterator i = written_to_clone.begin(); i != written_to_clone.end(); ++i) { uint64_t start = i.get_start(); uint64_t len = i.get_len(); unsigned int seed = get_iterator().get_state(start+len); seeds[start+len] = seed; seeds.erase(seeds.lower_bound(start), seeds.lower_bound(start+len)); seeds[start] = other.get_iterator().get_state(start); seeds.insert(other.seeds.upper_bound(start), other.seeds.lower_bound(start+len)); } if (intervals.range_end() > _size) _size = intervals.range_end(); _exists = true; return; } void ObjectContents::write(unsigned int seed, uint64_t start, uint64_t len) { _exists = true; unsigned int _seed = get_iterator().get_state(start+len); seeds[start+len] = _seed; seeds.erase(seeds.lower_bound(start), seeds.lower_bound(start+len)); seeds[start] = seed; interval_set to_write; to_write.insert(start, len); written.union_of(to_write); if (start + len > _size) _size = start + len; return; } ceph-0.80.11/src/test/common/test_str_map.cc0000664000175100017510000000363512623076744022755 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include #include #include "include/str_map.h" using namespace std; TEST(str_map, json) { map str_map; stringstream ss; // well formatted ASSERT_EQ(0, get_str_map("{\"key\": \"value\"}", ss, &str_map)); ASSERT_EQ("value", str_map["key"]); // well formatted but not a JSON object ASSERT_EQ(-EINVAL, get_str_map("\"key\"", ss, &str_map)); ASSERT_NE(string::npos, ss.str().find("must be a JSON object")); } TEST(str_map, plaintext) { stringstream ss; { map str_map; ASSERT_EQ(0, get_str_map(" foo=bar\t\nfrob=nitz yeah right= \n\t", ss, &str_map)); ASSERT_EQ(4u, str_map.size()); ASSERT_EQ("bar", str_map["foo"]); ASSERT_EQ("nitz", str_map["frob"]); ASSERT_EQ("", str_map["yeah"]); ASSERT_EQ("", str_map["right"]); } { map str_map; ASSERT_EQ(0, get_str_map("that", ss, &str_map)); ASSERT_EQ(1u, str_map.size()); ASSERT_EQ("", str_map["that"]); } { map str_map; ASSERT_EQ(0, get_str_map(" \t \n ", ss, &str_map)); ASSERT_EQ(0u, str_map.size()); ASSERT_EQ(0, get_str_map("", ss, &str_map)); ASSERT_EQ(0u, str_map.size()); } } /* * Local Variables: * compile-command: "cd ../.. ; make -j4 && * make unittest_str_map && * valgrind --tool=memcheck --leak-check=full \ * ./unittest_str_map * " * End: */ ceph-0.80.11/src/test/common/ObjectContents.h0000664000175100017510000000533512623076744023036 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/interval_set.h" #include "include/buffer.h" #include #ifndef COMMON_OBJECT_H #define COMMON_OBJECT_H enum { RANDOMWRITEFULL, DELETED, CLONERANGE }; bool test_object_contents(); class ObjectContents { uint64_t _size; map seeds; interval_set written; bool _exists; public: class Iterator { ObjectContents *parent; map::iterator iter; unsigned int current_state; int current_val; uint64_t pos; private: unsigned int get_state(uint64_t pos); public: Iterator(ObjectContents *parent) : parent(parent), iter(parent->seeds.end()), current_state(0), current_val(0), pos(-1) { seek_to_first(); } char operator*() { return parent->written.contains(pos) ? static_cast(current_val % 256) : '\0'; } uint64_t get_pos() { return pos; } void seek_to(uint64_t _pos) { if (pos > _pos || (iter != parent->seeds.end() && _pos >= iter->first)) { iter = parent->seeds.upper_bound(_pos); --iter; current_state = iter->second; current_val = rand_r(¤t_state); pos = iter->first; ++iter; } while (pos < _pos) ++(*this); } void seek_to_first() { seek_to(0); } Iterator &operator++() { ++pos; if (iter != parent->seeds.end() && pos >= iter->first) { assert(pos == iter->first); current_state = iter->second; ++iter; } current_val = rand_r(¤t_state); return *this; } bool valid() { return pos < parent->size(); } friend class ObjectContents; }; ObjectContents() : _size(0), _exists(false) { seeds[0] = 0; } ObjectContents(bufferlist::iterator &bp) { ::decode(_size, bp); ::decode(seeds, bp); ::decode(written, bp); ::decode(_exists, bp); } void clone_range(ObjectContents &other, interval_set &intervals); void write(unsigned int seed, uint64_t from, uint64_t len); Iterator get_iterator() { return Iterator(this); } uint64_t size() const { return _size; } bool exists() { return _exists; } void debug(std::ostream &out) { out << "_size is " << _size << std::endl; out << "seeds is: ("; for (map::iterator i = seeds.begin(); i != seeds.end(); ++i) { out << "[" << i->first << "," << i->second << "], "; } out << ")" << std::endl; out << "written is " << written << std::endl; out << "_exists is " << _exists << std::endl; } void encode(bufferlist &bl) const { ::encode(_size, bl); ::encode(seeds, bl); ::encode(written, bl); ::encode(_exists, bl); } }; #endif ceph-0.80.11/src/test/common/test_sloppy_crc_map.cc0000664000175100017510000000523712623076744024322 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "common/SloppyCRCMap.h" #include "common/Formatter.h" #include void dump(const SloppyCRCMap& scm) { Formatter *f = new_formatter("json-pretty"); f->open_object_section("map"); scm.dump(f); f->close_section(); f->flush(cout); delete f; } TEST(SloppyCRCMap, basic) { SloppyCRCMap scm(4); bufferlist a, b; a.append("The quick brown fox jumped over a fence whose color I forget."); b.append("asdf"); scm.write(0, a.length(), a); if (0) dump(scm); ASSERT_EQ(0, scm.read(0, a.length(), a, &cout)); scm.write(12, b.length(), b); if (0) dump(scm); ASSERT_EQ(0, scm.read(12, b.length(), b, &cout)); ASSERT_EQ(1, scm.read(0, a.length(), a, &cout)); } TEST(SloppyCRCMap, truncate) { SloppyCRCMap scm(4); bufferlist a, b; a.append("asdf"); b.append("qwer"); scm.write(0, a.length(), a); scm.write(4, a.length(), a); ASSERT_EQ(0, scm.read(4, 4, a, &cout)); ASSERT_EQ(1, scm.read(4, 4, b, &cout)); scm.truncate(4); ASSERT_EQ(0, scm.read(4, 4, b, &cout)); } TEST(SloppyCRCMap, zero) { SloppyCRCMap scm(4); bufferlist a, b; a.append("asdf"); b.append("qwer"); scm.write(0, a.length(), a); scm.write(4, a.length(), a); ASSERT_EQ(0, scm.read(4, 4, a, &cout)); ASSERT_EQ(1, scm.read(4, 4, b, &cout)); scm.zero(4, 4); ASSERT_EQ(1, scm.read(4, 4, a, &cout)); ASSERT_EQ(1, scm.read(4, 4, b, &cout)); bufferptr bp(4); bp.zero(); bufferlist c; c.append(bp); ASSERT_EQ(0, scm.read(0, 4, a, &cout)); ASSERT_EQ(0, scm.read(4, 4, c, &cout)); scm.zero(0, 15); ASSERT_EQ(1, scm.read(0, 4, a, &cout)); ASSERT_EQ(0, scm.read(0, 4, c, &cout)); } TEST(SloppyCRCMap, clone_range) { SloppyCRCMap src(4); SloppyCRCMap dst(4); bufferlist a, b; a.append("asdfghjkl"); b.append("qwertyui"); src.write(0, a.length(), a); src.write(8, a.length(), a); src.write(16, a.length(), a); dst.write(0, b.length(), b); dst.clone_range(0, 8, 0, src); ASSERT_EQ(2, dst.read(0, 8, b, &cout)); ASSERT_EQ(0, dst.read(8, 8, b, &cout)); dst.write(16, b.length(), b); ASSERT_EQ(2, dst.read(16, 8, a, &cout)); dst.clone_range(16, 8, 16, src); ASSERT_EQ(0, dst.read(16, 8, a, &cout)); dst.write(16, b.length(), b); ASSERT_EQ(1, dst.read(16, 4, a, &cout)); dst.clone_range(16, 8, 2, src); ASSERT_EQ(0, dst.read(16, 4, a, &cout)); dst.write(0, b.length(), b); dst.write(8, b.length(), b); ASSERT_EQ(2, dst.read(0, 8, a, &cout)); ASSERT_EQ(2, dst.read(8, 8, a, &cout)); dst.clone_range(2, 8, 0, src); ASSERT_EQ(0, dst.read(0, 8, a, &cout)); ASSERT_EQ(0, dst.read(8, 4, a, &cout)); } ceph-0.80.11/src/test/common/test_io_priority.cc0000664000175100017510000000356612623076744023663 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 Red Hat * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include #include #include "common/io_priority.h" TEST(io_priority, ceph_ioprio_string_to_class) { ASSERT_EQ(IOPRIO_CLASS_IDLE, ceph_ioprio_string_to_class("idle")); ASSERT_EQ(IOPRIO_CLASS_IDLE, ceph_ioprio_string_to_class("IDLE")); ASSERT_EQ(IOPRIO_CLASS_BE, ceph_ioprio_string_to_class("be")); ASSERT_EQ(IOPRIO_CLASS_BE, ceph_ioprio_string_to_class("BE")); ASSERT_EQ(IOPRIO_CLASS_BE, ceph_ioprio_string_to_class("besteffort")); ASSERT_EQ(IOPRIO_CLASS_BE, ceph_ioprio_string_to_class("BESTEFFORT")); ASSERT_EQ(IOPRIO_CLASS_BE, ceph_ioprio_string_to_class("best effort")); ASSERT_EQ(IOPRIO_CLASS_BE, ceph_ioprio_string_to_class("BEST EFFORT")); ASSERT_EQ(IOPRIO_CLASS_RT, ceph_ioprio_string_to_class("rt")); ASSERT_EQ(IOPRIO_CLASS_RT, ceph_ioprio_string_to_class("RT")); ASSERT_EQ(IOPRIO_CLASS_RT, ceph_ioprio_string_to_class("realtime")); ASSERT_EQ(IOPRIO_CLASS_RT, ceph_ioprio_string_to_class("REALTIME")); ASSERT_EQ(IOPRIO_CLASS_RT, ceph_ioprio_string_to_class("real time")); ASSERT_EQ(IOPRIO_CLASS_RT, ceph_ioprio_string_to_class("REAL TIME")); ASSERT_EQ(-EINVAL, ceph_ioprio_string_to_class("invalid")); } /* * Local Variables: * compile-command: "cd ../.. ; * make -j4 unittest_io_priority && * libtool --mode=execute valgrind --tool=memcheck --leak-check=full \ * ./unittest_io_priority * " * End: */ ceph-0.80.11/src/test/common/test_util.cc0000664000175100017510000000177712623076744022272 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/util.h" #include "gtest/gtest.h" #include TEST(util, unit_to_bytesize) { ASSERT_EQ(1234ll, unit_to_bytesize("1234", &cerr)); ASSERT_EQ(1024ll, unit_to_bytesize("1K", &cerr)); ASSERT_EQ(1024ll, unit_to_bytesize("1k", &cerr)); ASSERT_EQ(1048576ll, unit_to_bytesize("1M", &cerr)); ASSERT_EQ(1073741824ll, unit_to_bytesize("1G", &cerr)); ASSERT_EQ(1099511627776ll, unit_to_bytesize("1T", &cerr)); ASSERT_EQ(1125899906842624ll, unit_to_bytesize("1P", &cerr)); ASSERT_EQ(1152921504606846976ll, unit_to_bytesize("1E", &cerr)); ASSERT_EQ(65536ll, unit_to_bytesize(" 64K", &cerr)); } ceph-0.80.11/src/test/common/test_bloom_filter.cc0000664000175100017510000001733112623076744023763 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * LGPL2.1 (see COPYING-LGPL2.1) or later */ #include #include #include "include/stringify.h" #include "common/bloom_filter.hpp" TEST(BloomFilter, Basic) { bloom_filter bf(10, .1, 1); bf.insert("foo"); bf.insert("bar"); ASSERT_TRUE(bf.contains("foo")); ASSERT_TRUE(bf.contains("bar")); } TEST(BloomFilter, Empty) { bloom_filter bf; for (int i=0; i<100; ++i) { ASSERT_FALSE(bf.contains(i)); ASSERT_FALSE(bf.contains(stringify(i))); } } TEST(BloomFilter, Sweep) { std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield); std::cout.precision(5); std::cout << "# max\tfpp\tactual\tsize\tB/insert" << std::endl; for (int ex = 3; ex < 12; ex += 2) { for (float fpp = .001; fpp < .5; fpp *= 4.0) { int max = 2 << ex; bloom_filter bf(max, fpp, 1); bf.insert("foo"); bf.insert("bar"); ASSERT_TRUE(bf.contains("foo")); ASSERT_TRUE(bf.contains("bar")); for (int n = 0; n < max; n++) bf.insert("ok" + stringify(n)); int test = max * 100; int hit = 0; for (int n = 0; n < test; n++) if (bf.contains("asdf" + stringify(n))) hit++; ASSERT_TRUE(bf.contains("foo")); ASSERT_TRUE(bf.contains("bar")); double actual = (double)hit / (double)test; bufferlist bl; ::encode(bf, bl); double byte_per_insert = (double)bl.length() / (double)max; std::cout << max << "\t" << fpp << "\t" << actual << "\t" << bl.length() << "\t" << byte_per_insert << std::endl; ASSERT_TRUE(actual < fpp * 10); } } } TEST(BloomFilter, SweepInt) { std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield); std::cout.precision(5); std::cout << "# max\tfpp\tactual\tsize\tB/insert\tdensity\tapprox_element_count" << std::endl; for (int ex = 3; ex < 12; ex += 2) { for (float fpp = .001; fpp < .5; fpp *= 4.0) { int max = 2 << ex; bloom_filter bf(max, fpp, 1); bf.insert("foo"); bf.insert("bar"); ASSERT_TRUE(123); ASSERT_TRUE(456); for (int n = 0; n < max; n++) bf.insert(n); int test = max * 100; int hit = 0; for (int n = 0; n < test; n++) if (bf.contains(100000 + n)) hit++; ASSERT_TRUE(123); ASSERT_TRUE(456); double actual = (double)hit / (double)test; bufferlist bl; ::encode(bf, bl); double byte_per_insert = (double)bl.length() / (double)max; std::cout << max << "\t" << fpp << "\t" << actual << "\t" << bl.length() << "\t" << byte_per_insert << "\t" << bf.density() << "\t" << bf.approx_unique_element_count() << std::endl; ASSERT_TRUE(actual < fpp * 10); ASSERT_TRUE(actual > fpp / 10); ASSERT_TRUE(bf.density() > 0.40); ASSERT_TRUE(bf.density() < 0.60); } } } TEST(BloomFilter, CompressibleSweep) { std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield); std::cout.precision(5); std::cout << "# max\tins\test ins\tafter\ttgtfpp\tactual\tsize\tb/elem\n"; float fpp = .01; int max = 1024; for (int div = 1; div < 10; div++) { compressible_bloom_filter bf(max, fpp, 1); int t = max/div; for (int n = 0; n < t; n++) bf.insert(n); unsigned est = bf.approx_unique_element_count(); if (div > 1) bf.compress(1.0 / div); for (int n = 0; n < t; n++) ASSERT_TRUE(bf.contains(n)); int test = max * 100; int hit = 0; for (int n = 0; n < test; n++) if (bf.contains(100000 + n)) hit++; double actual = (double)hit / (double)test; bufferlist bl; ::encode(bf, bl); double byte_per_insert = (double)bl.length() / (double)max; unsigned est_after = bf.approx_unique_element_count(); std::cout << max << "\t" << t << "\t" << est << "\t" << est_after << "\t" << fpp << "\t" << actual << "\t" << bl.length() << "\t" << byte_per_insert << std::endl; ASSERT_TRUE(actual < fpp * 2.0); ASSERT_TRUE(actual > fpp / 2.0); ASSERT_TRUE(est_after < est * 2); ASSERT_TRUE(est_after > est / 2); } } TEST(BloomFilter, BinSweep) { std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield); std::cout.precision(5); int total_max = 16384; float total_fpp = .01; std::cout << "total_inserts " << total_max << " target-fpp " << total_fpp << std::endl; for (int bins = 1; bins < 16; ++bins) { int max = total_max / bins; float fpp = total_fpp / bins;//pow(total_fpp, bins); std::vector ls; bufferlist bl; for (int i=0; iinsert(10000 * (i+1) + j); } ::encode(*ls.front(), bl); } int hit = 0; int test = max * 100; for (int i=0; i::iterator j = ls.begin(); j != ls.end(); ++j) { if ((*j)->contains(i * 732)) { // note: sequential i does not work here; the intenral int hash is weak!! hit++; break; } } } double actual = (double)hit / (double)test; std::cout << "bins " << bins << " bin-max " << max << " bin-fpp " << fpp << " actual-fpp " << actual << " total-size " << bl.length() << std::endl; } } // disable these tests; doing dual insertions in consecutive filters // appears to be equivalent to doing a single insertion in a bloom // filter that is twice as big. #if 0 // test the fpp over a sequence of bloom filters, each with unique // items inserted into it. // // we expect: actual_fpp = num_filters * per_filter_fpp TEST(BloomFilter, Sequence) { int max = 1024; double fpp = .01; for (int seq = 2; seq <= 128; seq *= 2) { std::vector ls; for (int i=0; iinsert("ok" + stringify(j) + "_" + stringify(i)); if (ls.size() > 1) ls[ls.size() - 2]->insert("ok" + stringify(j) + "_" + stringify(i)); } } int hit = 0; int test = max * 100; for (int i=0; i::iterator j = ls.begin(); j != ls.end(); ++j) { if ((*j)->contains("bad" + stringify(i))) { hit++; break; } } } double actual = (double)hit / (double)test; std::cout << "seq " << seq << " max " << max << " fpp " << fpp << " actual " << actual << std::endl; } } // test the ffp over a sequence of bloom filters, where actual values // are always inserted into a consecutive pair of filters. in order // to have a false positive, we need to falsely match two consecutive // filters. // // we expect: actual_fpp = num_filters * per_filter_fpp^2 TEST(BloomFilter, SequenceDouble) { int max = 1024; double fpp = .01; for (int seq = 2; seq <= 128; seq *= 2) { std::vector ls; for (int i=0; iinsert("ok" + stringify(j) + "_" + stringify(i)); if (ls.size() > 1) ls[ls.size() - 2]->insert("ok" + stringify(j) + "_" + stringify(i)); } } int hit = 0; int test = max * 100; int run = 0; for (int i=0; i::iterator j = ls.begin(); j != ls.end(); ++j) { if ((*j)->contains("bad" + stringify(i))) { run++; if (run >= 2) { hit++; break; } } else { run = 0; } } } double actual = (double)hit / (double)test; std::cout << "seq " << seq << " max " << max << " fpp " << fpp << " actual " << actual << " expected " << (fpp*fpp*(double)seq) << std::endl; } } #endif ceph-0.80.11/src/test/common/test_sharedptr_registry.cc0000664000175100017510000002261112623076744025227 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "common/Thread.h" #include "common/sharedptr_registry.hpp" #include "common/ceph_argparse.h" #include "global/global_init.h" #include using namespace std::tr1; class SharedPtrRegistryTest : public SharedPtrRegistry { public: Mutex &get_lock() { return lock; } map, int*> > &get_contents() { return contents; } }; class SharedPtrRegistry_all : public ::testing::Test { public: class Thread_wait : public Thread { public: SharedPtrRegistryTest ®istry; unsigned int key; int value; shared_ptr ptr; enum in_method_t { LOOKUP, LOOKUP_OR_CREATE } in_method; Thread_wait(SharedPtrRegistryTest& _registry, unsigned int _key, int _value, in_method_t _in_method) : registry(_registry), key(_key), value(_value), in_method(_in_method) { } virtual void *entry() { switch(in_method) { case LOOKUP_OR_CREATE: if (value) ptr = registry.lookup_or_create(key, value); else ptr = registry.lookup_or_create(key); break; case LOOKUP: ptr = shared_ptr(new int); *ptr = value; ptr = registry.lookup(key); break; } return NULL; } }; static const useconds_t DELAY_MAX = 20 * 1000 * 1000; static useconds_t delay; bool wait_for(SharedPtrRegistryTest ®istry, int waiting) { do { // // the delay variable is supposed to be initialized to zero. It would be fine // to usleep(0) but we take this opportunity to test the loop. It will try // again and therefore show that the logic ( increasing the delay ) actually // works. // if (delay > 0) usleep(delay); { Mutex::Locker l(registry.get_lock()); if (registry.waiting == waiting) break; } if (delay > 0) cout << "delay " << delay << "us, is not long enough, try again\n"; } while (( delay = delay * 2 + 1) < DELAY_MAX); return delay < DELAY_MAX; } }; useconds_t SharedPtrRegistry_all::delay = 0; TEST_F(SharedPtrRegistry_all, lookup_or_create) { SharedPtrRegistryTest registry; unsigned int key = 1; int value = 2; shared_ptr ptr = registry.lookup_or_create(key); *ptr = value; ASSERT_EQ(value, *registry.lookup_or_create(key)); } TEST_F(SharedPtrRegistry_all, wait_lookup_or_create) { SharedPtrRegistryTest registry; // // simulate the following: The last reference to a shared_ptr goes // out of scope and the shared_ptr object is about to be removed and // marked as such. The weak_ptr stored in the registry will show // that it has expired(). However, the SharedPtrRegistry::OnRemoval // object has not yet been called and did not get a chance to // acquire the lock. The lookup_or_create and lookup methods must // detect that situation and wait until the weak_ptr is removed from // the registry. // { unsigned int key = 1; { shared_ptr ptr(new int); registry.get_contents()[key] = make_pair(ptr, ptr.get()); } EXPECT_FALSE(registry.get_contents()[key].first.lock()); Thread_wait t(registry, key, 0, Thread_wait::LOOKUP_OR_CREATE); t.create(); ASSERT_TRUE(wait_for(registry, 1)); EXPECT_FALSE(t.ptr); // waiting on a key does not block lookups on other keys EXPECT_TRUE(registry.lookup_or_create(key + 12345)); registry.remove(key); ASSERT_TRUE(wait_for(registry, 0)); t.join(); EXPECT_TRUE(t.ptr); } { unsigned int key = 2; int value = 3; { shared_ptr ptr(new int); registry.get_contents()[key] = make_pair(ptr, ptr.get()); } EXPECT_FALSE(registry.get_contents()[key].first.lock()); Thread_wait t(registry, key, value, Thread_wait::LOOKUP_OR_CREATE); t.create(); ASSERT_TRUE(wait_for(registry, 1)); EXPECT_FALSE(t.ptr); // waiting on a key does not block lookups on other keys { int other_value = value + 1; unsigned int other_key = key + 1; shared_ptr ptr = registry.lookup_or_create(other_key, other_value); EXPECT_TRUE(ptr); EXPECT_EQ(other_value, *ptr); } registry.remove(key); ASSERT_TRUE(wait_for(registry, 0)); t.join(); EXPECT_TRUE(t.ptr); EXPECT_EQ(value, *t.ptr); } } TEST_F(SharedPtrRegistry_all, lookup) { SharedPtrRegistryTest registry; unsigned int key = 1; int value = 2; { shared_ptr ptr = registry.lookup_or_create(key); *ptr = value; ASSERT_EQ(value, *registry.lookup(key)); } ASSERT_FALSE(registry.lookup(key)); } TEST_F(SharedPtrRegistry_all, wait_lookup) { SharedPtrRegistryTest registry; unsigned int key = 1; int value = 2; { shared_ptr ptr(new int); registry.get_contents()[key] = make_pair(ptr, ptr.get()); } EXPECT_FALSE(registry.get_contents()[key].first.lock()); Thread_wait t(registry, key, value, Thread_wait::LOOKUP); t.create(); ASSERT_TRUE(wait_for(registry, 1)); EXPECT_EQ(value, *t.ptr); // waiting on a key does not block lookups on other keys EXPECT_FALSE(registry.lookup(key + 12345)); registry.remove(key); ASSERT_TRUE(wait_for(registry, 0)); t.join(); EXPECT_FALSE(t.ptr); } TEST_F(SharedPtrRegistry_all, get_next) { { SharedPtrRegistry registry; const unsigned int key = 0; pair i; EXPECT_FALSE(registry.get_next(key, &i)); } { SharedPtrRegistryTest registry; const unsigned int key2 = 333; shared_ptr ptr2 = registry.lookup_or_create(key2); const int value2 = *ptr2 = 400; // entries with expired pointers are silentely ignored const unsigned int key_gone = 222; registry.get_contents()[key_gone] = make_pair(shared_ptr(), (int*)0); const unsigned int key1 = 111; shared_ptr ptr1 = registry.lookup_or_create(key1); const int value1 = *ptr1 = 800; pair i; EXPECT_TRUE(registry.get_next(i.first, &i)); EXPECT_EQ(key1, i.first); EXPECT_EQ(value1, i.second); EXPECT_TRUE(registry.get_next(i.first, &i)); EXPECT_EQ(key2, i.first); EXPECT_EQ(value2, i.second); EXPECT_FALSE(registry.get_next(i.first, &i)); } { // // http://tracker.ceph.com/issues/6117 // reproduce the issue. // SharedPtrRegistryTest registry; const unsigned int key1 = 111; shared_ptr *ptr1 = new shared_ptr(registry.lookup_or_create(key1)); const unsigned int key2 = 222; shared_ptr ptr2 = registry.lookup_or_create(key2); pair > i; EXPECT_TRUE(registry.get_next(i.first, &i)); EXPECT_EQ(key1, i.first); delete ptr1; EXPECT_TRUE(registry.get_next(i.first, &i)); EXPECT_EQ(key2, i.first); } } TEST_F(SharedPtrRegistry_all, remove) { { SharedPtrRegistryTest registry; const unsigned int key1 = 1; shared_ptr ptr1 = registry.lookup_or_create(key1); *ptr1 = 400; registry.remove(key1); shared_ptr ptr2 = registry.lookup_or_create(key1); *ptr2 = 500; ptr1 = shared_ptr(); shared_ptr res = registry.lookup(key1); assert(res); assert(res == ptr2); assert(*res == 500); } { SharedPtrRegistryTest registry; const unsigned int key1 = 1; shared_ptr ptr1 = registry.lookup_or_create(key1, 400); registry.remove(key1); shared_ptr ptr2 = registry.lookup_or_create(key1, 500); ptr1 = shared_ptr(); shared_ptr res = registry.lookup(key1); assert(res); assert(res == ptr2); assert(*res == 500); } } class SharedPtrRegistry_destructor : public ::testing::Test { public: typedef enum { UNDEFINED, YES, NO } DieEnum; static DieEnum died; struct TellDie { TellDie() { died = NO; } ~TellDie() { died = YES; } int value; }; virtual void SetUp() { died = UNDEFINED; } }; SharedPtrRegistry_destructor::DieEnum SharedPtrRegistry_destructor::died = SharedPtrRegistry_destructor::UNDEFINED; TEST_F(SharedPtrRegistry_destructor, destructor) { SharedPtrRegistry registry; EXPECT_EQ(UNDEFINED, died); int key = 101; { shared_ptr a = registry.lookup_or_create(key); EXPECT_EQ(NO, died); EXPECT_TRUE(a); } EXPECT_EQ(YES, died); EXPECT_FALSE(registry.lookup(key)); } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } // Local Variables: // compile-command: "cd ../.. ; make unittest_sharedptr_registry && ./unittest_sharedptr_registry # --gtest_filter=*.* --log-to-stderr=true" // End: ceph-0.80.11/src/test/common/test_crc32c.cc0000664000175100017510000004010712623076744022362 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include "include/types.h" #include "include/crc32c.h" #include "include/utime.h" #include "common/Clock.h" #include "gtest/gtest.h" #include "common/sctp_crc32.h" #include "common/crc32c_intel_baseline.h" TEST(Crc32c, Small) { const char *a = "foo bar baz"; const char *b = "whiz bang boom"; ASSERT_EQ(4119623852u, ceph_crc32c(0, (unsigned char *)a, strlen(a))); ASSERT_EQ(881700046u, ceph_crc32c(1234, (unsigned char *)a, strlen(a))); ASSERT_EQ(2360230088u, ceph_crc32c(0, (unsigned char *)b, strlen(b))); ASSERT_EQ(3743019208u, ceph_crc32c(5678, (unsigned char *)b, strlen(b))); } TEST(Crc32c, PartialWord) { const char *a = (const char *)malloc(5); const char *b = (const char *)malloc(35); memset((void *)a, 1, 5); memset((void *)b, 1, 35); ASSERT_EQ(2715569182u, ceph_crc32c(0, (unsigned char *)a, 5)); ASSERT_EQ(440531800u, ceph_crc32c(0, (unsigned char *)b, 35)); } TEST(Crc32c, Big) { int len = 4096000; char *a = (char *)malloc(len); memset(a, 1, len); ASSERT_EQ(31583199u, ceph_crc32c(0, (unsigned char *)a, len)); ASSERT_EQ(1400919119u, ceph_crc32c(1234, (unsigned char *)a, len)); } TEST(Crc32c, Performance) { int len = 1000 * 1024 * 1024; char *a = (char *)malloc(len); std::cout << "populating large buffer" << std::endl; for (int i=0; i * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "common/Mutex.h" #include "common/Thread.h" #include "common/Throttle.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include class ThrottleTest : public ::testing::Test { protected: class Thread_get : public Thread { public: Throttle &throttle; int64_t count; bool waited; Thread_get(Throttle& _throttle, int64_t _count) : throttle(_throttle), count(_count), waited(false) { } virtual void *entry() { waited = throttle.get(count); throttle.put(count); return NULL; } }; }; TEST_F(ThrottleTest, Throttle) { ASSERT_THROW({ Throttle throttle(g_ceph_context, "throttle", -1); }, FailedAssertion); int64_t throttle_max = 10; Throttle throttle(g_ceph_context, "throttle", throttle_max); ASSERT_EQ(throttle.get_max(), throttle_max); ASSERT_EQ(throttle.get_current(), 0); } TEST_F(ThrottleTest, take) { int64_t throttle_max = 10; Throttle throttle(g_ceph_context, "throttle", throttle_max); ASSERT_THROW(throttle.take(-1), FailedAssertion); ASSERT_EQ(throttle.take(throttle_max), throttle_max); ASSERT_EQ(throttle.take(throttle_max), throttle_max * 2); } TEST_F(ThrottleTest, get) { int64_t throttle_max = 10; Throttle throttle(g_ceph_context, "throttle", throttle_max); ASSERT_THROW(throttle.get(-1), FailedAssertion); ASSERT_FALSE(throttle.get(5)); ASSERT_EQ(throttle.put(5), 0); ASSERT_FALSE(throttle.get(throttle_max)); ASSERT_FALSE(throttle.get_or_fail(1)); ASSERT_FALSE(throttle.get(1, throttle_max + 1)); ASSERT_EQ(throttle.put(throttle_max + 1), 0); ASSERT_FALSE(throttle.get(0, throttle_max)); ASSERT_FALSE(throttle.get(throttle_max)); ASSERT_FALSE(throttle.get_or_fail(1)); ASSERT_EQ(throttle.put(throttle_max), 0); useconds_t delay = 1; bool waited; do { cout << "Trying (1) with delay " << delay << "us\n"; ASSERT_FALSE(throttle.get(throttle_max)); ASSERT_FALSE(throttle.get_or_fail(throttle_max)); Thread_get t(throttle, 7); t.create(); usleep(delay); ASSERT_EQ(throttle.put(throttle_max), 0); t.join(); if (!(waited = t.waited)) delay *= 2; } while(!waited); do { cout << "Trying (2) with delay " << delay << "us\n"; ASSERT_FALSE(throttle.get(throttle_max / 2)); ASSERT_FALSE(throttle.get_or_fail(throttle_max)); Thread_get t(throttle, throttle_max); t.create(); usleep(delay); Thread_get u(throttle, 1); u.create(); usleep(delay); throttle.put(throttle_max / 2); t.join(); u.join(); if (!(waited = t.waited && u.waited)) delay *= 2; } while(!waited); } TEST_F(ThrottleTest, get_or_fail) { { Throttle throttle(g_ceph_context, "throttle"); ASSERT_TRUE(throttle.get_or_fail(5)); ASSERT_TRUE(throttle.get_or_fail(5)); } { int64_t throttle_max = 10; Throttle throttle(g_ceph_context, "throttle", throttle_max); ASSERT_TRUE(throttle.get_or_fail(throttle_max)); ASSERT_EQ(throttle.put(throttle_max), 0); ASSERT_TRUE(throttle.get_or_fail(throttle_max * 2)); ASSERT_FALSE(throttle.get_or_fail(1)); ASSERT_FALSE(throttle.get_or_fail(throttle_max * 2)); ASSERT_EQ(throttle.put(throttle_max * 2), 0); ASSERT_TRUE(throttle.get_or_fail(throttle_max)); ASSERT_FALSE(throttle.get_or_fail(1)); ASSERT_EQ(throttle.put(throttle_max), 0); } } TEST_F(ThrottleTest, wait) { int64_t throttle_max = 10; Throttle throttle(g_ceph_context, "throttle", throttle_max); useconds_t delay = 1; bool waited; do { cout << "Trying (3) with delay " << delay << "us\n"; ASSERT_FALSE(throttle.get(throttle_max / 2)); ASSERT_FALSE(throttle.get_or_fail(throttle_max)); Thread_get t(throttle, throttle_max); t.create(); usleep(delay); // // Throttle::_reset_max(int64_t m) used to contain a test // that blocked the following statement, only if // the argument was greater than throttle_max. // Although a value lower than throttle_max would cover // the same code in _reset_max, the throttle_max * 100 // value is left here to demonstrate that the problem // has been solved. // throttle.wait(throttle_max * 100); usleep(delay); t.join(); ASSERT_EQ(throttle.get_current(), throttle_max / 2); if (!(waited = t.waited)) { delay *= 2; // undo the changes we made throttle.put(throttle_max / 2); throttle.wait(throttle_max); } } while(!waited); } TEST_F(ThrottleTest, destructor) { Thread_get *t; { int64_t throttle_max = 10; Throttle *throttle = new Throttle(g_ceph_context, "throttle", throttle_max); ASSERT_FALSE(throttle->get(5)); t = new Thread_get(*throttle, 7); t->create(); bool blocked; useconds_t delay = 1; do { usleep(delay); if (throttle->get_or_fail(1)) { throttle->put(1); blocked = false; } else { blocked = true; } delay *= 2; } while(!blocked); delete throttle; } { // // The thread is left hanging, otherwise it will abort(). // Deleting the Throttle on which it is waiting creates a // inconsistency that will be detected: the Throttle object that // it references no longer exists. // pthread_t id = t->get_thread_id(); ASSERT_EQ(pthread_kill(id, 0), 0); delete t; ASSERT_EQ(pthread_kill(id, 0), 0); } } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } /* * Local Variables: * compile-command: "cd ../.. ; * make unittest_throttle ; * ./unittest_throttle # --gtest_filter=ThrottleTest.destructor \ * --log-to-stderr=true --debug-filestore=20 * " * End: */ ceph-0.80.11/src/test/common/test_config.cc0000664000175100017510000001344712623076744022557 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * * */ #include "common/config.h" #include "common/errno.h" #include "gtest/gtest.h" #define _STR(x) #x #define STRINGIFY(x) _STR(x) static struct config_option config_optionsp[] = { #define OPTION(name, type, def_val) \ { STRINGIFY(name), type, offsetof(struct md_config_t, name) }, #define SUBSYS(name, log, gather) #define DEFAULT_SUBSYS(log, gather) #include "common/config_opts.h" #undef OPTION #undef SUBSYS #undef DEFAULT_SUBSYS }; static const int NUM_CONFIG_OPTIONS = sizeof(config_optionsp) / sizeof(config_option); class test_md_config_t : public md_config_t, public ::testing::Test { public: void test_expand_meta() { Mutex::Locker l(lock); // successfull meta expansion $run_dir and ${run_dir} { ostringstream oss; std::string before = " BEFORE "; std::string after = " AFTER "; std::string val(before + "$run_dir${run_dir}" + after); EXPECT_TRUE(expand_meta(val, &oss)); EXPECT_EQ(before + "/var/run/ceph/var/run/ceph" + after, val); EXPECT_EQ("", oss.str()); } // no meta expansion if variables are unknown { ostringstream oss; std::string expected = "expect $foo and ${bar} to not expand"; std::string val = expected; EXPECT_FALSE(expand_meta(val, &oss)); EXPECT_EQ(expected, val); EXPECT_EQ("", oss.str()); } // recursive variable expansion { std::string mon_host = "$cluster_network"; EXPECT_EQ(0, set_val("mon_host", mon_host.c_str(), false)); std::string lockdep = "true"; EXPECT_EQ(0, set_val("lockdep", lockdep.c_str(), false)); std::string cluster_network = "$public_network $public_network $lockdep $host"; EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str(), false)); std::string public_network = "NETWORK"; EXPECT_EQ(0, set_val("public_network", public_network.c_str(), false)); ostringstream oss; std::string val = "$mon_host"; EXPECT_TRUE(expand_meta(val, &oss)); EXPECT_EQ(public_network + " " + public_network + " " + lockdep + " " + "localhost", val); EXPECT_EQ("", oss.str()); } // variable expansion loops are non fatal { std::string mon_host = "$cluster_network"; EXPECT_EQ(0, set_val("mon_host", mon_host.c_str(), false)); std::string cluster_network = "$public_network"; EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str(), false)); std::string public_network = "$mon_host"; EXPECT_EQ(0, set_val("public_network", public_network.c_str(), false)); ostringstream oss; std::string val = "$mon_host"; EXPECT_TRUE(expand_meta(val, &oss)); EXPECT_EQ("$cluster_network", val); const char *expected_oss = "variable expansion loop at mon_host=$cluster_network\n" "expansion stack: \n" "public_network=$mon_host\n" "cluster_network=$public_network\n" "mon_host=$cluster_network\n"; EXPECT_EQ(expected_oss, oss.str()); } } void test_expand_all_meta() { Mutex::Locker l(lock); int before_count = 0; for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) { config_option *opt = config_optionsp + i; if (opt->type == OPT_STR) { std::string *str = (std::string *)opt->conf_ptr(this); if (str->find("$") != string::npos) before_count++; } } // if there are no meta variables in the default configuration, // something must be done to check the expected side effect // of expand_all_meta ASSERT_LT(0, before_count); expand_all_meta(); int after_count = 0; for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) { config_option *opt = config_optionsp + i; if (opt->type == OPT_STR) { std::string *str = (std::string *)opt->conf_ptr(this); if (str->find("$") != string::npos) after_count++; } } ASSERT_EQ(0, after_count); } }; TEST_F(test_md_config_t, expand_meta) { test_expand_meta(); } TEST_F(test_md_config_t, expand_all_meta) { test_expand_all_meta(); } TEST(md_config_t, set_val) { int buf_size = 1024; md_config_t conf; // disable meta variable expansion { char *buf = (char*)malloc(buf_size); std::string expected = "$host"; EXPECT_EQ(0, conf.set_val("mon_host", expected.c_str(), false)); EXPECT_EQ(0, conf.get_val("mon_host", &buf, buf_size)); EXPECT_EQ(expected, buf); free(buf); } // meta variable expansion is enabled by default { char *run_dir = (char*)malloc(buf_size); EXPECT_EQ(0, conf.get_val("run_dir", &run_dir, buf_size)); EXPECT_EQ(0, conf.set_val("admin_socket", "$run_dir")); char *admin_socket = (char*)malloc(buf_size); EXPECT_EQ(0, conf.get_val("admin_socket", &admin_socket, buf_size)); EXPECT_EQ(std::string(run_dir), std::string(admin_socket)); free(run_dir); free(admin_socket); } } /* * Local Variables: * compile-command: "cd ../.. ; * make unittest_config && * valgrind \ * --max-stackframe=20000000 --tool=memcheck \ * ./unittest_config # --gtest_filter=md_config_t.set_val * " * End: */ ceph-0.80.11/src/test/common/get_command_descriptions.cc0000664000175100017510000000647512623076744025321 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "mon/Monitor.h" #include "common/ceph_argparse.h" #include "global/global_init.h" static void usage(ostream &out) { out << "usage: get_command_descriptions [options ...]" << std::endl; out << "print on stdout the result of JSON formatted options\n"; out << "found in mon/MonCommands.h as produced by the\n"; out << "Monitor.cc::get_command_descriptions function.\n"; out << "Designed as a helper for ceph_argparse.py unit tests.\n"; out << "\n"; out << " --all all of mon/MonCommands.h \n"; out << " --pull585 reproduce the bug fixed by #585\n"; out << "\n"; out << "Examples:\n"; out << " get_command_descriptions --all\n"; out << " get_command_descriptions --pull585\n"; } static void json_print(const MonCommand *mon_commands, int size) { bufferlist rdata; Formatter *f = new_formatter("json"); Monitor::format_command_descriptions(mon_commands, size, f, &rdata); delete f; string data(rdata.c_str(), rdata.length()); cout << data << std::endl; } static void all() { #undef COMMAND MonCommand mon_commands[] = { #define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ {parsesig, helptext, modulename, req_perms, avail}, #include }; json_print(mon_commands, ARRAY_SIZE(mon_commands)); } // syntax error https://github.com/ceph/ceph/pull/585 static void pull585() { MonCommand mon_commands[] = { { "osd pool create " "name=pool,type=CephPoolname " "name=pg_num,type=CephInt,range=0 " "name=pgp_num,type=CephInt,range=0,req=false" // !!! missing trailing space "name=properties,type=CephString,n=N,req=false,goodchars=[A-Za-z0-9-_.=]", "create pool", "osd", "rw", "cli,rest" } }; json_print(mon_commands, ARRAY_SIZE(mon_commands)); } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); if (args.empty()) { usage(cerr); exit(1); } for (std::vector::iterator i = args.begin(); i != args.end(); ++i) { string err; if (*i == string("help") || *i == string("-h") || *i == string("--help")) { usage(cout); exit(0); } else if (*i == string("--all")) { all(); } else if (*i == string("--pull585")) { pull585(); } } } /* * Local Variables: * compile-command: "cd ../.. ; * make get_command_descriptions && * ./get_command_descriptions --all --pull585" * End: */ ceph-0.80.11/src/test/common/test_context.cc0000664000175100017510000000334212623076744022767 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * * */ #include "gtest/gtest.h" #include "include/types.h" #include "include/msgr.h" #include "common/ceph_context.h" #include "common/config.h" TEST(CephContext, do_command) { CephContext *cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get(); string key("key"); string value("value"); cct->_conf->set_val(key.c_str(), value.c_str(), false); cmdmap_t cmdmap; cmdmap["var"] = key; { bufferlist out; cct->do_command("config get", cmdmap, "xml", &out); string s(out.c_str(), out.length()); EXPECT_EQ("" + value + "", s); } { bufferlist out; cct->do_command("config get", cmdmap, "UNSUPPORTED", &out); string s(out.c_str(), out.length()); EXPECT_EQ("{ \"key\": \"value\"}", s); } cct->put(); } /* * Local Variables: * compile-command: "cd ../.. ; * make unittest_context && * valgrind \ * --max-stackframe=20000000 --tool=memcheck \ * ./unittest_context # --gtest_filter=CephContext.* * " * End: */ ceph-0.80.11/src/test/Makefile.am0000664000175100017510000010442712623076744020507 0ustar jenkins-buildjenkins-buildinclude test/erasure-code/Makefile.am ## Unknown/other tests ceph_test_timers_SOURCES = test/TestTimers.cc ceph_test_timers_LDADD = $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_timers ceph_test_signal_handlers_SOURCES = test/TestSignalHandlers.cc ceph_test_signal_handlers_LDADD = $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_signal_handlers ceph_test_rados_SOURCES = \ test/osd/TestRados.cc \ test/osd/TestOpStat.cc \ test/osd/Object.cc \ test/osd/RadosModel.cc ceph_test_rados_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_rados ceph_test_mutate_SOURCES = test/test_mutate.cc ceph_test_mutate_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_mutate ceph_test_rewrite_latency_SOURCES = test/test_rewrite_latency.cc ceph_test_rewrite_latency_LDADD = $(LIBCOMMON) $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) bin_DEBUGPROGRAMS += ceph_test_rewrite_latency ceph_test_msgr_SOURCES = test/testmsgr.cc ceph_test_msgr_LDADD = $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_msgr ceph_streamtest_SOURCES = test/streamtest.cc ceph_streamtest_LDADD = $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_streamtest ceph_test_trans_SOURCES = test/test_trans.cc ceph_test_trans_LDADD = $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_trans ceph_test_crypto_SOURCES = test/testcrypto.cc ceph_test_crypto_LDADD = $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_crypto ceph_test_keys_SOURCES = test/testkeys.cc ceph_test_keys_LDADD = $(LIBMON) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_keys ## Dencoder test ceph_dencoder_SOURCES = \ test/encoding/ceph_dencoder.cc \ $(DENCODER_SOURCES) ceph_dencoder_LDADD = \ $(LIBOSD_TYPES) \ $(LIBOS_TYPES) \ $(LIBMDS) \ $(LIBMON_TYPES) \ $(DENCODER_DEPS) \ $(CEPH_GLOBAL) # These should always use explicit _CFLAGS/_CXXFLAGS so avoid basename conflicts ceph_dencoder_CFLAGS = ${AM_CFLAGS} ceph_dencoder_CXXFLAGS = ${AM_CXXFLAGS} if COMPILER_HAS_VTA ceph_dencoder_CFLAGS += -fno-var-tracking-assignments ceph_dencoder_CXXFLAGS += -fno-var-tracking-assignments endif bin_PROGRAMS += ceph-dencoder get_command_descriptions_SOURCES = test/common/get_command_descriptions.cc get_command_descriptions_LDADD = $(LIBMON) $(LIBCOMMON) $(CEPH_GLOBAL) noinst_PROGRAMS += get_command_descriptions ## Build tests # These should all use explicit _CXXFLAGS so avoid basename conflicts if WITH_BUILD_TESTS test_build_libcommon_SOURCES = \ test/buildtest_skeleton.cc \ $(libcommon_la_SOURCES) test_build_libcommon_LDADD = \ $(LIBCOMMON_DEPS) \ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) test_build_libcommon_LDFLAGS = -static-libtool-libs test_build_libcommon_CFLAGS = $(AM_CFLAGS) test_build_libcommon_CXXFLAGS = $(AM_CXXFLAGS) bin_DEBUGPROGRAMS += test_build_libcommon test_build_librados_SOURCES = \ test/buildtest_skeleton.cc \ $(librados_la_SOURCES) test_build_librados_LDADD = \ $(LIBRADOS_DEPS) \ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) test_build_librados_LDFLAGS = -static-libtool-libs test_build_librados_CFLAGS = $(AM_CFLAGS) test_build_librados_CXXFLAGS = $(AM_CXXFLAGS) bin_DEBUGPROGRAMS += test_build_librados test_build_librgw_SOURCES = \ test/buildtest_skeleton.cc \ $(librgw_la_SOURCES) test_build_librgw_LDADD = \ $(LIBRGW_DEPS) \ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) \ $(CEPH_GLOBAL) test_build_librgw_LDFLAGS = -static-libtool-libs test_build_librgw_CFLAGS = $(AM_CFLAGS) test_build_librgw_CXXFLAGS = $(AM_CXXFLAGS) bin_DEBUGPROGRAMS += test_build_librgw # I dont get this one... testing the osdc build but link in libcephfs? test_build_libcephfs_SOURCES = \ test/buildtest_skeleton.cc \ $(libosdc_la_SOURCES) test_build_libcephfs_LDADD = \ $(LIBCEPHFS) -lexpat \ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) test_build_libcephfs_LDFLAGS = -static-libtool-libs test_build_libcephfs_CFLAGS = $(AM_CFLAGS) test_build_libcephfs_CXXFLAGS = $(AM_CXXFLAGS) bin_DEBUGPROGRAMS += test_build_libcephfs endif # WITH_BUILD_TESTS ## Benchmarks ceph_smalliobench_SOURCES = \ test/bench/small_io_bench.cc \ test/bench/rados_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobench_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_smalliobench ceph_smalliobenchfs_SOURCES = \ test/bench/small_io_bench_fs.cc \ test/bench/testfilestore_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobenchfs_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_smalliobenchfs ceph_smalliobenchdumb_SOURCES = \ test/bench/small_io_bench_dumb.cc \ test/bench/dumb_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobenchdumb_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_smalliobenchdumb ceph_smalliobenchrbd_SOURCES = \ test/bench/small_io_bench_rbd.cc \ test/bench/rbd_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobenchrbd_LDADD = $(LIBRBD) $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_smalliobenchrbd ceph_tpbench_SOURCES = \ test/bench/tp_bench.cc \ test/bench/detailed_stat_collector.cc ceph_tpbench_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_tpbench ceph_omapbench_SOURCES = test/omap_bench.cc ceph_omapbench_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_omapbench if LINUX ceph_kvstorebench_SOURCES = \ test/kv_store_bench.cc \ key_value_store/kv_flat_btree_async.cc ceph_kvstorebench_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_kvstorebench endif ## System tests if LINUX libsystest_la_SOURCES = \ test/system/cross_process_sem.cc \ test/system/systest_runnable.cc \ test/system/systest_settings.cc libsystest_la_LIBADD = $(CEPH_GLOBAL) noinst_LTLIBRARIES += libsystest.la ceph_test_rados_list_parallel_SOURCES = \ test/system/rados_list_parallel.cc \ test/system/st_rados_create_pool.cc \ test/system/st_rados_list_objects.cc ceph_test_rados_list_parallel_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) bin_DEBUGPROGRAMS += ceph_test_rados_list_parallel ceph_test_rados_open_pools_parallel_SOURCES = \ test/system/rados_open_pools_parallel.cc \ test/system/st_rados_create_pool.cc ceph_test_rados_open_pools_parallel_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) bin_DEBUGPROGRAMS += ceph_test_rados_open_pools_parallel ceph_test_rados_delete_pools_parallel_SOURCES = \ test/system/rados_delete_pools_parallel.cc \ test/system/st_rados_create_pool.cc \ test/system/st_rados_delete_pool.cc \ test/system/st_rados_list_objects.cc ceph_test_rados_delete_pools_parallel_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) bin_DEBUGPROGRAMS += ceph_test_rados_delete_pools_parallel ceph_test_rados_watch_notify_SOURCES = \ test/system/rados_watch_notify.cc \ test/system/st_rados_create_pool.cc \ test/system/st_rados_delete_pool.cc \ test/system/st_rados_delete_objs.cc \ test/system/st_rados_watch.cc \ test/system/st_rados_notify.cc ceph_test_rados_watch_notify_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) bin_DEBUGPROGRAMS += ceph_test_rados_watch_notify endif ceph_bench_log_SOURCES = test/bench_log.cc ceph_bench_log_LDADD = $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_bench_log ## Unit tests check_SCRIPTS += \ unittest_bufferlist.sh \ test/encoding/check-generated.sh \ test/mon/osd-pool-create.sh \ test/mon/misc.sh \ test/mon/osd-crush.sh \ test/mon/osd-erasure-code-profile.sh \ test/mon/mkfs.sh \ test/ceph-disk.sh \ test/mon/mon-handle-forward.sh \ test/vstart_wrapped_tests.sh EXTRA_DIST += \ $(srcdir)/test/mon/mon-test-helpers.sh \ $(srcdir)/test/osd/osd-test-helpers.sh # target to build but not run the unit tests unittests:: $(check_PROGRAMS) UNITTEST_CXXFLAGS = \ $(AM_CXXFLAGS) \ -I$(top_srcdir)/src/gtest/include \ -I$(top_builddir)/src/gtest/include UNITTEST_LDADD = \ $(top_builddir)/src/gtest/lib/libgtest.a \ $(top_builddir)/src/gtest/lib/libgtest_main.a \ $(PTHREAD_LIBS) unittest_encoding_SOURCES = test/encoding.cc unittest_encoding_LDADD = $(LIBCEPHFS) $(LIBRADOS) -lm $(UNITTEST_LDADD) unittest_encoding_CXXFLAGS = $(UNITTEST_CXXFLAGS) -fno-strict-aliasing check_PROGRAMS += unittest_encoding unittest_addrs_SOURCES = test/test_addrs.cc unittest_addrs_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_addrs_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_addrs unittest_bloom_filter_SOURCES = test/common/test_bloom_filter.cc unittest_bloom_filter_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_bloom_filter_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_bloom_filter unittest_histogram_SOURCES = test/common/histogram.cc unittest_histogram_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_histogram_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_histogram unittest_str_map_SOURCES = test/common/test_str_map.cc unittest_str_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_str_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_str_map unittest_sharedptr_registry_SOURCES = test/common/test_sharedptr_registry.cc unittest_sharedptr_registry_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_sharedptr_registry_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_sharedptr_registry unittest_sloppy_crc_map_SOURCES = test/common/test_sloppy_crc_map.cc unittest_sloppy_crc_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_sloppy_crc_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_sloppy_crc_map unittest_util_SOURCES = test/common/test_util.cc unittest_util_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_util_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CRYPTO_LIBS) $(EXTRALIBS) check_PROGRAMS += unittest_util unittest_crush_indep_SOURCES = test/crush/indep.cc unittest_crush_indep_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_crush_indep_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CEPH_CRUSH) $(EXTRALIBS) $(CEPH_GLOBAL) check_PROGRAMS += unittest_crush_indep unittest_osdmap_SOURCES = test/osd/TestOSDMap.cc unittest_osdmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osdmap_LDADD = $(UNITTEST_LDADD) $(LIBCOMMON) $(CEPH_GLOBAL) check_PROGRAMS += unittest_osdmap unittest_workqueue_SOURCES = test/test_workqueue.cc unittest_workqueue_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_workqueue_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_workqueue unittest_striper_SOURCES = test/test_striper.cc unittest_striper_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_striper_LDADD = $(LIBOSDC) $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_striper unittest_prebufferedstreambuf_SOURCES = test/test_prebufferedstreambuf.cc unittest_prebufferedstreambuf_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_prebufferedstreambuf_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) $(EXTRALIBS) check_PROGRAMS += unittest_prebufferedstreambuf unittest_str_list_SOURCES = test/test_str_list.cc unittest_str_list_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_str_list_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_str_list unittest_log_SOURCES = log/test.cc unittest_log_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) unittest_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 check_PROGRAMS += unittest_log unittest_throttle_SOURCES = test/common/Throttle.cc unittest_throttle_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_throttle_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 check_PROGRAMS += unittest_throttle unittest_crush_wrapper_SOURCES = test/crush/TestCrushWrapper.cc unittest_crush_wrapper_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(LIBCRUSH) unittest_crush_wrapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 check_PROGRAMS += unittest_crush_wrapper unittest_base64_SOURCES = test/base64.cc unittest_base64_LDADD = $(LIBCEPHFS) -lm $(UNITTEST_LDADD) unittest_base64_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_base64 unittest_ceph_argparse_SOURCES = test/ceph_argparse.cc unittest_ceph_argparse_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_argparse_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_ceph_argparse unittest_ceph_compatset_SOURCES = test/ceph_compatset.cc unittest_ceph_compatset_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_compatset_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_ceph_compatset unittest_osd_types_SOURCES = test/osd/types.cc unittest_osd_types_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osd_types_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_osd_types unittest_pglog_SOURCES = test/osd/TestPGLog.cc unittest_pglog_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_pglog_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_pglog if LINUX unittest_pglog_LDADD += -ldl endif # LINUX unittest_ecbackend_SOURCES = test/osd/TestECBackend.cc unittest_ecbackend_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_ecbackend_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_ecbackend unittest_hitset_SOURCES = test/osd/hitset.cc unittest_hitset_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_hitset_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_hitset unittest_io_priority_SOURCES = test/common/test_io_priority.cc unittest_io_priority_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_io_priority_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) check_PROGRAMS += unittest_io_priority unittest_gather_SOURCES = test/gather.cc unittest_gather_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_gather_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_gather unittest_run_cmd_SOURCES = test/run_cmd.cc unittest_run_cmd_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) unittest_run_cmd_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_run_cmd unittest_signals_SOURCES = test/signals.cc unittest_signals_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_signals_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_signals unittest_simple_spin_SOURCES = test/simple_spin.cc unittest_simple_spin_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) unittest_simple_spin_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_simple_spin unittest_librados_SOURCES = test/librados/librados.cc unittest_librados_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) unittest_librados_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_librados unittest_bufferlist_SOURCES = test/bufferlist.cc unittest_bufferlist_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_bufferlist_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_bufferlist unittest_crc32c_SOURCES = test/common/test_crc32c.cc unittest_crc32c_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_crc32c_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_crc32c unittest_arch_SOURCES = test/test_arch.cc unittest_arch_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_arch_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_arch unittest_crypto_SOURCES = test/crypto.cc unittest_crypto_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_crypto_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_crypto unittest_crypto_init_SOURCES = test/crypto_init.cc unittest_crypto_init_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_crypto_init_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_crypto_init unittest_perf_counters_SOURCES = test/perf_counters.cc unittest_perf_counters_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_perf_counters_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_perf_counters unittest_admin_socket_SOURCES = test/admin_socket.cc unittest_admin_socket_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_admin_socket_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_admin_socket unittest_ceph_crypto_SOURCES = test/ceph_crypto.cc unittest_ceph_crypto_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_crypto_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_ceph_crypto unittest_utf8_SOURCES = test/utf8.cc unittest_utf8_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_utf8_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_utf8 unittest_mime_SOURCES = test/mime.cc unittest_mime_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_mime_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_mime unittest_escape_SOURCES = test/escape.cc unittest_escape_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_escape_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_escape unittest_chain_xattr_SOURCES = test/objectstore/chain_xattr.cc unittest_chain_xattr_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_chain_xattr_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_chain_xattr unittest_flatindex_SOURCES = test/os/TestFlatIndex.cc unittest_flatindex_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_flatindex_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_flatindex unittest_strtol_SOURCES = test/strtol.cc unittest_strtol_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_strtol_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_strtol unittest_confutils_SOURCES = test/confutils.cc unittest_confutils_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_confutils_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_confutils unittest_config_SOURCES = test/common/test_config.cc unittest_config_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_config unittest_context_SOURCES = test/common/test_context.cc unittest_context_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_context_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_context unittest_heartbeatmap_SOURCES = test/heartbeat_map.cc unittest_heartbeatmap_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_heartbeatmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_heartbeatmap # why does this include rgw/rgw_formats.cc...? unittest_formatter_SOURCES = \ test/formatter.cc \ rgw/rgw_formats.cc unittest_formatter_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_formatter_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_formatter unittest_libcephfs_config_SOURCES = test/libcephfs_config.cc unittest_libcephfs_config_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) unittest_libcephfs_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_libcephfs_config unittest_lfnindex_SOURCES = test/os/TestLFNIndex.cc unittest_lfnindex_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_lfnindex_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_lfnindex unittest_librados_config_SOURCES = test/librados/librados_config.cc unittest_librados_config_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) unittest_librados_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_librados_config #unittest_librgw_link_SOURCES = test/librgw_link.cc #unittest_librgw_link_LDFLAGS = $(PTHREAD_CFLAGS) ${AM_LDFLAGS} #unittest_librgw_link_LDADD = $(LIBRGW) ${UNITTEST_LDADD} #unittest_librgw_link_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS} #check_PROGRAMS += unittest_librgw_link unittest_daemon_config_SOURCES = test/daemon_config.cc unittest_daemon_config_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_daemon_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_daemon_config unittest_osd_osdcap_SOURCES = test/osd/osdcap.cc unittest_osd_osdcap_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_osd_osdcap_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_osd_osdcap unittest_mon_moncap_SOURCES = test/mon/moncap.cc unittest_mon_moncap_LDADD = $(LIBMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_mon_moncap_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_mon_moncap unittest_mon_pgmap_SOURCES = test/mon/PGMap.cc unittest_mon_pgmap_LDADD = $(LIBMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_mon_pgmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_mon_pgmap #if WITH_RADOSGW #unittest_librgw_SOURCES = test/librgw.cc #unittest_librgw_LDFLAGS = -lrt $(PTHREAD_CFLAGS) -lcurl ${AM_LDFLAGS} #unittest_librgw_LDADD = librgw.la $(LIBRADOS) ${UNITTEST_LDADD} -lexpat $(CEPH_GLOBAL) #unittest_librgw_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS} #check_PROGRAMS += unittest_librgw #endif # WITH_RADOSGW unittest_ipaddr_SOURCES = test/test_ipaddr.cc unittest_ipaddr_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ipaddr_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_ipaddr unittest_texttable_SOURCES = test/test_texttable.cc unittest_texttable_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) unittest_texttable_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_texttable unittest_on_exit_SOURCES = test/on_exit.cc unittest_on_exit_LDADD = $(PTHREAD_LIBS) check_PROGRAMS += unittest_on_exit check_SCRIPTS += test/pybind/test_ceph_argparse.py if WITH_RADOSGW ceph_test_cors_SOURCES = test/test_cors.cc ceph_test_cors_LDADD = \ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) \ -lcurl -luuid -lexpat ceph_test_cors_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cors ceph_test_rgw_manifest_SOURCES = test/rgw/test_rgw_manifest.cc ceph_test_rgw_manifest_LDADD = \ $(LIBRADOS) $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ -lcurl -luuid -lexpat ceph_test_rgw_manifest_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rgw_manifest ceph_test_cls_rgw_meta_SOURCES = test/test_rgw_admin_meta.cc ceph_test_cls_rgw_meta_LDADD = \ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ -lcurl -luuid -lexpat \ libcls_version_client.a libcls_log_client.a \ libcls_statelog_client.a libcls_refcount_client.la \ libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la ceph_test_cls_rgw_meta_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rgw_meta ceph_test_cls_rgw_log_SOURCES = test/test_rgw_admin_log.cc ceph_test_cls_rgw_log_LDADD = \ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ -lcurl -luuid -lexpat \ libcls_version_client.a libcls_log_client.a \ libcls_statelog_client.a libcls_refcount_client.la \ libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la ceph_test_cls_rgw_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rgw_log ceph_test_cls_rgw_opstate_SOURCES = test/test_rgw_admin_opstate.cc ceph_test_cls_rgw_opstate_LDADD = \ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ -lcurl -luuid -lexpat \ libcls_version_client.a libcls_log_client.a \ libcls_statelog_client.a libcls_refcount_client.la \ libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la ceph_test_cls_rgw_opstate_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rgw_opstate endif # WITH_RADOSGW libradostest_la_SOURCES = \ test/librados/test.cc \ test/librados/TestCase.cc noinst_LTLIBRARIES += libradostest.la libradostest_la_CXXFLAGS = $(UNITTEST_CXXFLAGS) RADOS_TEST_LDADD = libradostest.la ceph_multi_stress_watch_SOURCES = test/multi_stress_watch.cc ceph_multi_stress_watch_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) bin_DEBUGPROGRAMS += ceph_multi_stress_watch ceph_test_librbd_SOURCES = test/librbd/test_librbd.cc ceph_test_librbd_LDADD = $(LIBRBD) $(LIBRADOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_librbd_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_librbd if LINUX ceph_test_librbd_fsx_SOURCES = test/librbd/fsx.c ceph_test_librbd_fsx_LDADD = $(LIBRBD) $(LIBRADOS) -lm ceph_test_librbd_fsx_CFLAGS = ${AM_CFLAGS} bin_DEBUGPROGRAMS += ceph_test_librbd_fsx endif ceph_test_cls_rbd_SOURCES = test/cls_rbd/test_cls_rbd.cc ceph_test_cls_rbd_LDADD = $(LIBRADOS) libcls_rbd_client.la libcls_lock_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_rbd_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rbd ceph_test_cls_refcount_SOURCES = test/cls_refcount/test_cls_refcount.cc ceph_test_cls_refcount_LDADD = $(LIBRADOS) libcls_refcount_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_refcount_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_refcount ceph_test_cls_version_SOURCES = test/cls_version/test_cls_version.cc ceph_test_cls_version_LDADD = $(LIBRADOS) libcls_version_client.a $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_version_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_version ceph_test_cls_log_SOURCES = test/cls_log/test_cls_log.cc ceph_test_cls_log_LDADD = $(LIBRADOS) libcls_log_client.a $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_log ceph_test_cls_statelog_SOURCES = test/cls_statelog/test_cls_statelog.cc ceph_test_cls_statelog_LDADD = $(LIBRADOS) libcls_statelog_client.a $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_statelog_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_statelog ceph_test_cls_replica_log_SOURCES = test/cls_replica_log/test_cls_replica_log.cc ceph_test_cls_replica_log_LDADD = \ $(LIBRADOS) libcls_replica_log_client.a \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_replica_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_replica_log ceph_test_cls_lock_SOURCES = test/cls_lock/test_cls_lock.cc ceph_test_cls_lock_LDADD = $(LIBRADOS) libcls_lock_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_lock_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_lock ceph_test_cls_hello_SOURCES = test/cls_hello/test_cls_hello.cc ceph_test_cls_hello_LDADD = \ $(LIBRADOS) $(CRYPTO_LIBS) \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_hello_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_hello if WITH_RADOSGW ceph_test_cls_rgw_SOURCES = test/cls_rgw/test_cls_rgw.cc ceph_test_cls_rgw_LDADD = $(LIBRADOS) libcls_rgw_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_rgw_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rgw endif # WITH_RADOSGW ceph_test_mon_workloadgen_SOURCES = test/mon/test_mon_workloadgen.cc ceph_test_mon_workloadgen_LDADD = $(LIBOS) $(LIBOSDC) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_mon_workloadgen ceph_test_rados_api_cmd_SOURCES = test/librados/cmd.cc ceph_test_rados_api_cmd_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_cmd_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_cmd ceph_test_rados_api_io_SOURCES = test/librados/io.cc ceph_test_rados_api_io_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_io_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_io ceph_test_rados_api_c_write_operations_SOURCES = \ test/librados/c_write_operations.cc ceph_test_rados_api_c_write_operations_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_c_write_operations_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_c_write_operations ceph_test_rados_api_c_read_operations_SOURCES = \ test/librados/c_read_operations.cc ceph_test_rados_api_c_read_operations_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_c_read_operations_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_c_read_operations ceph_test_rados_api_aio_SOURCES = test/librados/aio.cc ceph_test_rados_api_aio_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_aio_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_aio ceph_test_rados_api_list_SOURCES = test/librados/list.cc ceph_test_rados_api_list_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_list_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_list ceph_test_rados_api_pool_SOURCES = test/librados/pool.cc ceph_test_rados_api_pool_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_pool_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_pool ceph_test_rados_api_stat_SOURCES = test/librados/stat.cc ceph_test_rados_api_stat_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_stat_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_stat ceph_test_rados_api_watch_notify_SOURCES = test/librados/watch_notify.cc ceph_test_rados_api_watch_notify_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_watch_notify_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_watch_notify ceph_test_rados_api_snapshots_SOURCES = test/librados/snapshots.cc ceph_test_rados_api_snapshots_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_snapshots_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_snapshots ceph_test_rados_api_cls_SOURCES = test/librados/cls.cc ceph_test_rados_api_cls_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_cls_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_cls ceph_test_rados_api_misc_SOURCES = test/librados/misc.cc ceph_test_rados_api_misc_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_rados_api_misc_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_misc ceph_test_rados_api_tier_SOURCES = \ test/librados/tier.cc \ osd/HitSet.cc ceph_test_rados_api_tier_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_rados_api_tier_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_tier ceph_test_rados_api_lock_SOURCES = test/librados/lock.cc ceph_test_rados_api_lock_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_lock_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_rados_api_lock ceph_test_libcephfs_SOURCES = \ test/libcephfs/test.cc \ test/libcephfs/readdir_r_cb.cc \ test/libcephfs/caps.cc \ test/libcephfs/multiclient.cc ceph_test_libcephfs_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) ceph_test_libcephfs_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_libcephfs if LINUX ceph_test_objectstore_SOURCES = test/objectstore/store_test.cc ceph_test_objectstore_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_objectstore_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_objectstore endif ceph_test_objectstore_workloadgen_SOURCES = \ test/objectstore/workload_generator.cc \ test/objectstore/TestObjectStoreState.cc ceph_test_objectstore_workloadgen_LDADD = $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_objectstore_workloadgen ceph_test_filestore_idempotent_SOURCES = \ test/objectstore/test_idempotent.cc \ test/objectstore/FileStoreTracker.cc \ test/common/ObjectContents.cc ceph_test_filestore_idempotent_LDADD = $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_filestore_idempotent ceph_test_filestore_idempotent_sequence_SOURCES = \ test/objectstore/test_idempotent_sequence.cc \ test/objectstore/DeterministicOpSequence.cc \ test/objectstore/TestObjectStoreState.cc \ test/objectstore/FileStoreDiff.cc ceph_test_filestore_idempotent_sequence_LDADD = $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_filestore_idempotent_sequence ceph_xattr_bench_SOURCES = test/xattr_bench.cc ceph_xattr_bench_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_xattr_bench_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_xattr_bench ceph_test_filejournal_SOURCES = test/test_filejournal.cc ceph_test_filejournal_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_filejournal_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_filejournal ceph_test_stress_watch_SOURCES = test/test_stress_watch.cc ceph_test_stress_watch_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_stress_watch_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_stress_watch ceph_test_objectcacher_stress_SOURCES = \ test/osdc/object_cacher_stress.cc \ test/osdc/FakeWriteback.cc ceph_test_objectcacher_stress_LDADD = $(LIBOSDC) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_test_objectcacher_stress ceph_test_snap_mapper_SOURCES = test/test_snap_mapper.cc ceph_test_snap_mapper_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_snap_mapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_snap_mapper ceph_test_object_map_SOURCES = \ test/ObjectMap/test_object_map.cc \ test/ObjectMap/KeyValueDBMemory.cc ceph_test_object_map_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_object_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_object_map ceph_test_keyvaluedb_atomicity_SOURCES = test/ObjectMap/test_keyvaluedb_atomicity.cc ceph_test_keyvaluedb_atomicity_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_keyvaluedb_atomicity_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_keyvaluedb_atomicity ceph_test_keyvaluedb_iterators_SOURCES = \ test/ObjectMap/test_keyvaluedb_iterators.cc \ test/ObjectMap/KeyValueDBMemory.cc ceph_test_keyvaluedb_iterators_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_keyvaluedb_iterators_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_keyvaluedb_iterators ceph_test_cfuse_cache_invalidate_SOURCES = test/test_cfuse_cache_invalidate.cc bin_DEBUGPROGRAMS += ceph_test_cfuse_cache_invalidate ceph_test_c_headers_SOURCES = test/test_c_headers.c ceph_test_c_headers_LDADD = $(LIBRADOS) $(LIBCEPHFS) bin_DEBUGPROGRAMS += ceph_test_c_headers ceph_test_get_blkdev_size_SOURCES = test/test_get_blkdev_size.cc ceph_test_get_blkdev_size_LDADD = $(LIBCOMMON) bin_DEBUGPROGRAMS += ceph_test_get_blkdev_size noinst_HEADERS += \ test/bench/backend.h \ test/bench/bencher.h \ test/bench/detailed_stat_collector.h \ test/bench/distribution.h \ test/bench/dumb_backend.h \ test/bench/rados_backend.h \ test/bench/rbd_backend.h \ test/bench/stat_collector.h \ test/bench/testfilestore_backend.h \ test/common/ObjectContents.h \ test/encoding/types.h \ test/objectstore/DeterministicOpSequence.h \ test/objectstore/FileStoreDiff.h \ test/objectstore/FileStoreTracker.h \ test/objectstore/TestObjectStoreState.h \ test/objectstore/workload_generator.h \ test/kv_store_bench.h \ test/librados/test.h \ test/librados/TestCase.h \ test/ObjectMap/KeyValueDBMemory.h \ test/omap_bench.h \ test/osdc/FakeWriteback.h \ test/osd/Object.h \ test/osd/RadosModel.h \ test/osd/TestOpStat.h \ test/system/cross_process_sem.h \ test/system/st_rados_create_pool.h \ test/system/st_rados_delete_objs.h \ test/system/st_rados_delete_pool.h \ test/system/st_rados_list_objects.h \ test/system/st_rados_notify.h \ test/system/st_rados_watch.h \ test/system/systest_runnable.h \ test/system/systest_settings.h \ test/unit.h ceph-0.80.11/src/test/libcephfs_config.cc0000664000175100017510000000316712623076744022245 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "gtest/gtest.h" #include "include/cephfs/libcephfs.h" #include #include #include using std::string; TEST(LibCephConfig, SimpleSet) { struct ceph_mount_info *cmount; int ret = ceph_create(&cmount, NULL); ASSERT_EQ(ret, 0); ret = ceph_conf_set(cmount, "max_open_files", "21"); ASSERT_EQ(ret, 0); char buf[128]; memset(buf, 0, sizeof(buf)); ret = ceph_conf_get(cmount, "max_open_files", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("21"), string(buf)); ceph_shutdown(cmount); } TEST(LibCephConfig, ArgV) { struct ceph_mount_info *cmount; int ret = ceph_create(&cmount, NULL); ASSERT_EQ(ret, 0); const char *argv[] = { "foo", "--max-open-files", "2", "--keyfile", "/tmp/my-keyfile", NULL }; size_t argc = (sizeof(argv) / sizeof(argv[0])) - 1; ceph_conf_parse_argv(cmount, argc, argv); char buf[128]; memset(buf, 0, sizeof(buf)); ret = ceph_conf_get(cmount, "keyfile", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("/tmp/my-keyfile"), string(buf)); memset(buf, 0, sizeof(buf)); ret = ceph_conf_get(cmount, "max_open_files", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("2"), string(buf)); ceph_shutdown(cmount); } ceph-0.80.11/src/test/gather.cc0000664000175100017510000000547412623076744020236 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 Greg Farnum * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/Context.h" #include "test/unit.h" class C_Checker : public Context { public: bool *finish_called; int *result; C_Checker(bool* _finish_called, int *r) : finish_called(_finish_called), result(r) {} void finish(int r) { *finish_called = true; *result = r; } }; TEST(ContextGather, Constructor) { C_GatherBuilder gather(g_ceph_context); EXPECT_FALSE(gather.has_subs()); EXPECT_TRUE(gather.get() == NULL); } TEST(ContextGather, OneSub) { C_GatherBuilder gather(g_ceph_context); Context *sub = gather.new_sub(); EXPECT_EQ(1, gather.num_subs_created()); EXPECT_EQ(1, gather.num_subs_remaining()); bool finish_called = false; int result = 0; C_Checker *checker = new C_Checker(&finish_called, &result); gather.set_finisher(checker); gather.activate(); sub->complete(0); EXPECT_TRUE(finish_called); EXPECT_EQ(0, result); } TEST(ContextGather, ManySubs) { bool finish_called = false; int result = 0; C_GatherBuilder gather(g_ceph_context, new C_Checker(&finish_called, &result)); int sub_count = 8; Context* subs[sub_count]; //create subs and test for (int i = 0; i < sub_count; ++i) { subs[i] = gather.new_sub(); EXPECT_EQ(i+1, gather.num_subs_created()); EXPECT_EQ(i+1, gather.num_subs_remaining()); } EXPECT_TRUE(gather.has_subs()); gather.activate(); //finish all except one sub for (int j = 0; j < sub_count - 1; ++j) { subs[j]->complete(0); EXPECT_FALSE(finish_called); } //finish last one and check asserts subs[sub_count-1]->complete(0); EXPECT_TRUE(finish_called); } TEST(ContextGather, AlternatingSubCreateFinish) { C_GatherBuilder gather(g_ceph_context); int sub_count = 8; bool finish_called = false; int result = 0; C_Checker *checker = new C_Checker(&finish_called, &result); gather.set_finisher(checker); Context* subs[sub_count]; //create half the subs for (int i = 0; i < sub_count / 2; ++i) { subs[i] = gather.new_sub(); EXPECT_EQ(i + 1, gather.num_subs_created()); EXPECT_EQ(i + 1, gather.num_subs_remaining()); } //alternate finishing first half of subs and creating last half of subs for (int j = 0; j < sub_count / 2; ++j) { subs[j]->complete(0); subs[sub_count / 2 + j] = gather.new_sub(); } gather.activate(); //finish last half of subs for (int k = sub_count / 2; k < sub_count; ++k) { subs[k]->complete(0); } EXPECT_TRUE(finish_called); } ceph-0.80.11/src/test/ceph_argparse.cc0000664000175100017510000002775312623076744021573 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_argparse.h" #include "gtest/gtest.h" #include /* Holds a std::vector with C-strings. * Will free() them properly in the destructor. * * Note: the ceph_argparse functions modify the vector, removing elements as * they find them. So we keep a parallel vector, orig, to make sure that we * never forget to delete a string. */ class VectorContainer { public: VectorContainer(const char** arr_) { for (const char **a = arr_; *a; ++a) { const char *str = (const char*)strdup(*a); arr.push_back(str); orig.push_back(str); } } ~VectorContainer() { for (std::vector::iterator i = orig.begin(); i != orig.end(); ++i) { free((void*)*i); } } void refresh() { arr.assign(orig.begin(), orig.end()); } std::vector < const char* > arr; private: std::vector < const char* > orig; }; TEST(CephArgParse, SimpleArgParse) { const char *BAR5[] = { "./myprog", "--bar", "5", NULL }; const char *FOO[] = { "./myprog", "--foo", "--baz", NULL }; const char *NONE[] = { "./myprog", NULL }; bool found_foo = false; std::string found_bar; VectorContainer bar5(BAR5); for (std::vector::iterator i = bar5.arr.begin(); i != bar5.arr.end(); ) { if (ceph_argparse_flag(bar5.arr, i, "--foo", (char*)NULL)) { found_foo = true; } else if (ceph_argparse_witharg(bar5.arr, i, &found_bar, "--bar", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_foo, false); ASSERT_EQ(found_bar, "5"); found_foo = false; found_bar = ""; VectorContainer foo(FOO); for (std::vector::iterator i = foo.arr.begin(); i != foo.arr.end(); ) { if (ceph_argparse_flag(foo.arr, i, "--foo", (char*)NULL)) { found_foo = true; } else if (ceph_argparse_witharg(foo.arr, i, &found_bar, "--bar", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_foo, true); ASSERT_EQ(found_bar, ""); found_foo = false; found_bar = ""; VectorContainer none(NONE); for (std::vector::iterator i = none.arr.begin(); i != none.arr.end(); ) { if (ceph_argparse_flag(none.arr, i, "--foo", (char*)NULL)) { found_foo = true; } else if (ceph_argparse_witharg(none.arr, i, &found_bar, "--bar", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_foo, false); ASSERT_EQ(found_bar, ""); } TEST(CephArgParse, DoubleDash) { const char *ARGS[] = { "./myprog", "--foo", "5", "--", "--bar", "6", NULL }; int foo = -1, bar = -1; VectorContainer args(ARGS); for (std::vector::iterator i = args.arr.begin(); i != args.arr.end(); ) { std::string myarg; if (ceph_argparse_double_dash(args.arr, i)) { break; } else if (ceph_argparse_witharg(args.arr, i, &myarg, "--foo", (char*)NULL)) { foo = atoi(myarg.c_str()); } else if (ceph_argparse_witharg(args.arr, i, &myarg, "--bar", (char*)NULL)) { bar = atoi(myarg.c_str()); } else ++i; } ASSERT_EQ(foo, 5); ASSERT_EQ(bar, -1); } TEST(CephArgParse, WithDashesAndUnderscores) { const char *BAZSTUFF1[] = { "./myprog", "--goo", "--baz-stuff", "50", "--end", NULL }; const char *BAZSTUFF2[] = { "./myprog", "--goo2", "--baz_stuff", "50", NULL }; const char *BAZSTUFF3[] = { "./myprog", "--goo2", "--baz-stuff=50", "50", NULL }; const char *BAZSTUFF4[] = { "./myprog", "--goo2", "--baz_stuff=50", "50", NULL }; const char *NONE1[] = { "./myprog", NULL }; const char *NONE2[] = { "./myprog", "--goo2", "--baz_stuff2", "50", NULL }; const char *NONE3[] = { "./myprog", "--goo2", "__baz_stuff", "50", NULL }; // as flag std::string found_baz; VectorContainer bazstuff1(BAZSTUFF1); for (std::vector::iterator i = bazstuff1.arr.begin(); i != bazstuff1.arr.end(); ) { if (ceph_argparse_flag(bazstuff1.arr, i, "--baz-stuff", (char*)NULL)) { found_baz = "true"; } else ++i; } ASSERT_EQ(found_baz, "true"); // as flag found_baz = ""; VectorContainer bazstuff2(BAZSTUFF2); for (std::vector::iterator i = bazstuff2.arr.begin(); i != bazstuff2.arr.end(); ) { if (ceph_argparse_flag(bazstuff2.arr, i, "--baz-stuff", (char*)NULL)) { found_baz = "true"; } else ++i; } ASSERT_EQ(found_baz, "true"); // with argument found_baz = ""; bazstuff1.refresh(); for (std::vector::iterator i = bazstuff1.arr.begin(); i != bazstuff1.arr.end(); ) { if (ceph_argparse_witharg(bazstuff1.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, "50"); // with argument found_baz = ""; bazstuff2.refresh(); for (std::vector::iterator i = bazstuff2.arr.begin(); i != bazstuff2.arr.end(); ) { if (ceph_argparse_witharg(bazstuff2.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, "50"); // with argument found_baz = ""; VectorContainer bazstuff3(BAZSTUFF3); for (std::vector::iterator i = bazstuff3.arr.begin(); i != bazstuff3.arr.end(); ) { if (ceph_argparse_witharg(bazstuff3.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, "50"); // with argument found_baz = ""; VectorContainer bazstuff4(BAZSTUFF4); for (std::vector::iterator i = bazstuff4.arr.begin(); i != bazstuff4.arr.end(); ) { if (ceph_argparse_witharg(bazstuff4.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, "50"); // not found found_baz = ""; VectorContainer none1(NONE1); for (std::vector::iterator i = none1.arr.begin(); i != none1.arr.end(); ) { if (ceph_argparse_flag(none1.arr, i, "--baz-stuff", (char*)NULL)) { found_baz = "true"; } else if (ceph_argparse_witharg(none1.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, ""); // not found found_baz = ""; VectorContainer none2(NONE2); for (std::vector::iterator i = none2.arr.begin(); i != none2.arr.end(); ) { if (ceph_argparse_flag(none2.arr, i, "--baz-stuff", (char*)NULL)) { found_baz = "true"; } else if (ceph_argparse_witharg(none2.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, ""); // not found found_baz = ""; VectorContainer none3(NONE3); for (std::vector::iterator i = none3.arr.begin(); i != none3.arr.end(); ) { if (ceph_argparse_flag(none3.arr, i, "--baz-stuff", (char*)NULL)) { found_baz = "true"; } else if (ceph_argparse_witharg(none3.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) { } else ++i; } ASSERT_EQ(found_baz, ""); } TEST(CephArgParse, WithInt) { const char *BAZSTUFF1[] = { "./myprog", "--foo", "50", "--bar", "52", NULL }; const char *BAZSTUFF2[] = { "./myprog", "--foo", "--bar", "52", NULL }; const char *BAZSTUFF3[] = { "./myprog", "--foo", "40", "--", "--bar", "42", NULL }; // normal test VectorContainer bazstuff1(BAZSTUFF1); ostringstream err; int foo = -1, bar = -1; for (std::vector::iterator i = bazstuff1.arr.begin(); i != bazstuff1.arr.end(); ) { if (ceph_argparse_double_dash(bazstuff1.arr, i)) { break; } else if (ceph_argparse_withint(bazstuff1.arr, i, &foo, &err, "--foo", (char*)NULL)) { ASSERT_EQ(string(""), err.str()); } else if (ceph_argparse_withint(bazstuff1.arr, i, &bar, &err, "--bar", (char*)NULL)) { ASSERT_EQ(string(""), err.str()); } else { ++i; } } ASSERT_EQ(foo, 50); ASSERT_EQ(bar, 52); // parse error test VectorContainer bazstuff2(BAZSTUFF2); ostringstream err2; for (std::vector::iterator i = bazstuff2.arr.begin(); i != bazstuff2.arr.end(); ) { if (ceph_argparse_double_dash(bazstuff2.arr, i)) { break; } else if (ceph_argparse_withint(bazstuff2.arr, i, &foo, &err2, "--foo", (char*)NULL)) { ASSERT_NE(string(""), err2.str()); } else { ++i; } } // double dash test VectorContainer bazstuff3(BAZSTUFF3); foo = -1, bar = -1; for (std::vector::iterator i = bazstuff3.arr.begin(); i != bazstuff3.arr.end(); ) { if (ceph_argparse_double_dash(bazstuff3.arr, i)) { break; } else if (ceph_argparse_withint(bazstuff3.arr, i, &foo, &err, "--foo", (char*)NULL)) { ASSERT_EQ(string(""), err.str()); } else if (ceph_argparse_withint(bazstuff3.arr, i, &bar, &err, "--bar", (char*)NULL)) { ASSERT_EQ(string(""), err.str()); } else { ++i; } } ASSERT_EQ(foo, 40); ASSERT_EQ(bar, -1); } TEST(CephArgParse, env_to_vec) { { std::vector args; unsetenv("CEPH_ARGS"); unsetenv("WHATEVER"); env_to_vec(args); EXPECT_EQ(0u, args.size()); env_to_vec(args, "WHATEVER"); EXPECT_EQ(0u, args.size()); args.push_back("a"); setenv("CEPH_ARGS", "b c", 0); env_to_vec(args); EXPECT_EQ(3u, args.size()); EXPECT_EQ(string("b"), args[1]); EXPECT_EQ(string("c"), args[2]); setenv("WHATEVER", "d e", 0); env_to_vec(args, "WHATEVER"); EXPECT_EQ(5u, args.size()); EXPECT_EQ(string("d"), args[3]); EXPECT_EQ(string("e"), args[4]); } { std::vector args; unsetenv("CEPH_ARGS"); args.push_back("a"); args.push_back("--"); args.push_back("c"); setenv("CEPH_ARGS", "b -- d", 0); env_to_vec(args); EXPECT_EQ(5u, args.size()); EXPECT_EQ(string("a"), args[0]); EXPECT_EQ(string("b"), args[1]); EXPECT_EQ(string("--"), args[2]); EXPECT_EQ(string("c"), args[3]); EXPECT_EQ(string("d"), args[4]); } { std::vector args; unsetenv("CEPH_ARGS"); args.push_back("a"); args.push_back("--"); setenv("CEPH_ARGS", "b -- c", 0); env_to_vec(args); EXPECT_EQ(4u, args.size()); EXPECT_EQ(string("a"), args[0]); EXPECT_EQ(string("b"), args[1]); EXPECT_EQ(string("--"), args[2]); EXPECT_EQ(string("c"), args[3]); } { std::vector args; unsetenv("CEPH_ARGS"); args.push_back("--"); args.push_back("c"); setenv("CEPH_ARGS", "b -- d", 0); env_to_vec(args); EXPECT_EQ(4u, args.size()); EXPECT_EQ(string("b"), args[0]); EXPECT_EQ(string("--"), args[1]); EXPECT_EQ(string("c"), args[2]); EXPECT_EQ(string("d"), args[3]); } { std::vector args; unsetenv("CEPH_ARGS"); args.push_back("b"); setenv("CEPH_ARGS", "c -- d", 0); env_to_vec(args); EXPECT_EQ(4u, args.size()); EXPECT_EQ(string("b"), args[0]); EXPECT_EQ(string("c"), args[1]); EXPECT_EQ(string("--"), args[2]); EXPECT_EQ(string("d"), args[3]); } { std::vector args; unsetenv("CEPH_ARGS"); args.push_back("a"); args.push_back("--"); args.push_back("c"); setenv("CEPH_ARGS", "-- d", 0); env_to_vec(args); EXPECT_EQ(4u, args.size()); EXPECT_EQ(string("a"), args[0]); EXPECT_EQ(string("--"), args[1]); EXPECT_EQ(string("c"), args[2]); EXPECT_EQ(string("d"), args[3]); } { std::vector args; unsetenv("CEPH_ARGS"); args.push_back("a"); args.push_back("--"); args.push_back("c"); setenv("CEPH_ARGS", "d", 0); env_to_vec(args); EXPECT_EQ(4u, args.size()); EXPECT_EQ(string("a"), args[0]); EXPECT_EQ(string("d"), args[1]); EXPECT_EQ(string("--"), args[2]); EXPECT_EQ(string("c"), args[3]); } } /* * Local Variables: * compile-command: "cd .. ; make unittest_ceph_argparse && ./unittest_ceph_argparse" * End: */ ceph-0.80.11/src/test/system/0000775000175100017510000000000012623077036017762 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/system/rados_list_parallel.cc0000664000175100017510000002252712623076744024325 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "include/stringify.h" #include "st_rados_create_pool.h" #include "st_rados_list_objects.h" #include "systest_runnable.h" #include "systest_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using std::ostringstream; using std::string; using std::vector; static int g_num_objects = 50; static CrossProcessSem *pool_setup_sem = NULL; static CrossProcessSem *modify_sem = NULL; class RadosDeleteObjectsR : public SysTestRunnable { public: RadosDeleteObjectsR(int argc, const char **argv, const std::string &pool_name) : SysTestRunnable(argc, argv), m_pool_name(pool_name) { } ~RadosDeleteObjectsR() { } int run(void) { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); RETURN1_IF_NONZERO(rados_connect(cl)); pool_setup_sem->wait(); pool_setup_sem->post(); rados_ioctx_t io_ctx; rados_pool_create(cl, m_pool_name.c_str()); RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); std::map to_delete; for (int i = 0; i < g_num_objects; ++i) { char oid[128]; snprintf(oid, sizeof(oid), "%d.obj", i); to_delete[i] = oid; } int removed = 0; while (true) { if (to_delete.empty()) break; int r = rand() % to_delete.size(); std::map ::iterator d = to_delete.begin(); for (int i = 0; i < r; ++i) ++d; if (d == to_delete.end()) { return -EDOM; } std::string oid(d->second); to_delete.erase(d); int ret = rados_remove(io_ctx, oid.c_str()); if (ret != 0) { printf("%s: rados_remove(%s) failed with error %d\n", get_id_str(), oid.c_str(), ret); return ret; } ++removed; if ((removed % 25) == 0) { printf("%s: removed %d objects...\n", get_id_str(), removed); } if (removed == g_num_objects / 2) { printf("%s: removed half of the objects\n", get_id_str()); modify_sem->post(); } } printf("%s: removed %d objects\n", get_id_str(), removed); rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return 0; } private: std::string m_pool_name; }; class RadosAddObjectsR : public SysTestRunnable { public: RadosAddObjectsR(int argc, const char **argv, const std::string &pool_name, const std::string &suffix) : SysTestRunnable(argc, argv), m_pool_name(pool_name), m_suffix(suffix) { } ~RadosAddObjectsR() { } int run(void) { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); RETURN1_IF_NONZERO(rados_connect(cl)); pool_setup_sem->wait(); pool_setup_sem->post(); rados_ioctx_t io_ctx; rados_pool_create(cl, m_pool_name.c_str()); RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); std::map to_add; for (int i = 0; i < g_num_objects; ++i) { char oid[128]; snprintf(oid, sizeof(oid), "%d%s", i, m_suffix.c_str()); to_add[i] = oid; } int added = 0; while (true) { if (to_add.empty()) break; int r = rand() % to_add.size(); std::map ::iterator d = to_add.begin(); for (int i = 0; i < r; ++i) ++d; if (d == to_add.end()) { return -EDOM; } std::string oid(d->second); to_add.erase(d); std::string buf(StRadosCreatePool::get_random_buf(256)); int ret = rados_write(io_ctx, oid.c_str(), buf.c_str(), buf.size(), 0); if (ret != 0) { printf("%s: rados_write(%s) failed with error %d\n", get_id_str(), oid.c_str(), ret); return ret; } ++added; if ((added % 25) == 0) { printf("%s: added %d objects...\n", get_id_str(), added); } if (added == g_num_objects / 2) { printf("%s: added half of the objects\n", get_id_str()); modify_sem->post(); } } printf("%s: added %d objects\n", get_id_str(), added); rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return 0; } private: std::string m_pool_name; std::string m_suffix; }; const char *get_id_str() { return "main"; } int main(int argc, const char **argv) { const char *num_objects = getenv("NUM_OBJECTS"); std::string pool = "foo." + stringify(getpid()); if (num_objects) { g_num_objects = atoi(num_objects); if (g_num_objects == 0) return 100; } RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); RETURN1_IF_NONZERO(CrossProcessSem::create(1, &modify_sem)); std::string error; // Test 1... list objects { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, g_num_objects, ".obj"); StRadosListObjects r2(argc, argv, pool, false, g_num_objects, pool_setup_sem, modify_sem, NULL); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("got error: %s\n", error.c_str()); return EXIT_FAILURE; } } // Test 2... list objects while they're being deleted RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, g_num_objects, ".obj"); StRadosListObjects r2(argc, argv, pool, false, g_num_objects / 2, pool_setup_sem, modify_sem, NULL); RadosDeleteObjectsR r3(argc, argv, pool); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("got error: %s\n", error.c_str()); return EXIT_FAILURE; } } // Test 3... list objects while others are being added RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, g_num_objects, ".obj"); StRadosListObjects r2(argc, argv, pool, false, g_num_objects / 2, pool_setup_sem, modify_sem, NULL); RadosAddObjectsR r3(argc, argv, pool, ".obj2"); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("got error: %s\n", error.c_str()); return EXIT_FAILURE; } } // Test 4... list objects while others are being added and deleted RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, g_num_objects, ".obj"); StRadosListObjects r2(argc, argv, pool, false, g_num_objects / 2, pool_setup_sem, modify_sem, NULL); RadosAddObjectsR r3(argc, argv, pool, ".obj2"); RadosAddObjectsR r4(argc, argv, pool, ".obj3"); RadosDeleteObjectsR r5(argc, argv, pool); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); vec.push_back(&r4); vec.push_back(&r5); error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("got error: %s\n", error.c_str()); return EXIT_FAILURE; } } // Test 5... list objects while they are being modified RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, g_num_objects, ".obj"); StRadosListObjects r2(argc, argv, pool, false, g_num_objects / 2, pool_setup_sem, modify_sem, NULL); // AddObjects with the same 'suffix' as used in StRadosCreatePool RadosAddObjectsR r3(argc, argv, pool, ".obj"); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("got error: %s\n", error.c_str()); return EXIT_FAILURE; } } rados_t cl; rados_create(&cl, NULL); rados_conf_parse_argv(cl, argc, argv); rados_conf_parse_argv(cl, argc, argv); rados_conf_read_file(cl, NULL); rados_conf_parse_env(cl, NULL); rados_connect(cl); rados_pool_delete(cl, pool.c_str()); printf("******* SUCCESS **********\n"); return EXIT_SUCCESS; } ceph-0.80.11/src/test/system/systest_runnable.cc0000664000175100017510000001324112623076744023703 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/errno.h" #include "include/atomic.h" #include "systest_runnable.h" #include "systest_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #endif using std::ostringstream; using std::string; static pid_t do_gettid(void) { #if defined(__linux__) return static_cast < pid_t >(syscall(SYS_gettid)); #else return static_cast < pid_t >(pthread_getthreadid_np()); #endif } ceph::atomic_t m_highest_id(0); SysTestRunnable:: SysTestRunnable(int argc, const char **argv) : m_argc(0), m_argv(NULL), m_argv_orig(NULL) { m_started = false; m_id = m_highest_id.inc(); memset(&m_pthread, 0, sizeof(m_pthread)); m_pid = 0; update_id_str(false); set_argv(argc, argv); } SysTestRunnable:: ~SysTestRunnable() { set_argv(0, NULL); } const char* SysTestRunnable:: get_id_str(void) const { return m_id_str; } int SysTestRunnable:: start() { if (m_started) { return -EDOM; } bool use_threads = SysTestSettings::inst().use_threads(); if (use_threads) { int ret = pthread_create(&m_pthread, NULL, systest_runnable_pthread_helper, static_cast(this)); if (ret) return ret; m_started = true; return 0; } else { pid_t pid = fork(); if (pid == -1) { int err = errno; return -err; } else if (pid == 0) { m_started = true; m_pid = getpid(); void *retptr = systest_runnable_pthread_helper(static_cast(this)); exit((int)(uintptr_t)retptr); } else { m_started = true; m_pid = pid; return 0; } } } std::string SysTestRunnable:: join() { if (!m_started) { return "SysTestRunnable was never started."; } bool use_threads = SysTestSettings::inst().use_threads(); if (use_threads) { void *ptrretval; int ret = pthread_join(m_pthread, &ptrretval); if (ret) { ostringstream oss; oss << "pthread_join failed with error " << ret; return oss.str(); } int retval = (int)(uintptr_t)ptrretval; if (retval != 0) { ostringstream oss; oss << "ERROR " << retval; return oss.str(); } return ""; } else { int status; printf("waitpid(%d)\n", m_pid); pid_t pid = waitpid(m_pid, &status, 0); if (pid == -1) { int err = errno; ostringstream oss; oss << get_id_str() << " waitpid error: " << cpp_strerror(err); return oss.str(); } else if (WIFSIGNALED(status)) { ostringstream oss; oss << get_id_str() << " exited with a signal"; return oss.str(); } else if (!WIFEXITED(status)) { ostringstream oss; oss << get_id_str() << " did not exit normally"; return oss.str(); } else { int exit_status = WEXITSTATUS(status); if (exit_status != 0) { ostringstream oss; oss << get_id_str() << " returned exit_status " << exit_status; return oss.str(); } return ""; } } } std::string SysTestRunnable:: run_until_finished(std::vector < SysTestRunnable * > &runnables) { int index = 0; for (std::vector < SysTestRunnable * >::const_iterator r = runnables.begin(); r != runnables.end(); ++r) { int ret = (*r)->start(); if (ret) { ostringstream oss; oss << "run_until_finished: got error " << ret << " when starting runnable " << index; return oss.str(); } ++index; } for (std::vector < SysTestRunnable * >::const_iterator r = runnables.begin(); r != runnables.end(); ++r) { std::string rstr = (*r)->join(); if (!rstr.empty()) { ostringstream oss; oss << "run_until_finished: runnable " << (*r)->get_id_str() << ": got error: " << rstr; return oss.str(); } } printf("*******************************\n"); return ""; } void *systest_runnable_pthread_helper(void *arg) { SysTestRunnable *st = static_cast < SysTestRunnable * >(arg); st->update_id_str(true); int ret = st->run(); return (void*)(uintptr_t)ret; } void SysTestRunnable:: update_id_str(bool started) { bool use_threads = SysTestSettings::inst().use_threads(); char extra[128]; extra[0] = '\0'; if (started) { if (use_threads) snprintf(extra, sizeof(extra), "_[%d]", do_gettid()); else snprintf(extra, sizeof(extra), "_[%d]", getpid()); } if (use_threads) snprintf(m_id_str, SysTestRunnable::ID_STR_SZ, "thread_%d%s", m_id, extra); else snprintf(m_id_str, SysTestRunnable::ID_STR_SZ, "process_%d%s", m_id, extra); } // Copy argv so that if some fiend decides to modify it, it's ok. void SysTestRunnable:: set_argv(int argc, const char **argv) { if (m_argv_orig != NULL) { for (int i = 0; i < m_argc; ++i) free((void*)(m_argv_orig[i])); delete[] m_argv_orig; m_argv_orig = NULL; delete[] m_argv; m_argv = NULL; m_argc = 0; } if (argv == NULL) return; m_argc = argc; m_argv_orig = new const char*[m_argc+1]; for (int i = 0; i < m_argc; ++i) m_argv_orig[i] = strdup(argv[i]); m_argv_orig[argc] = NULL; m_argv = new const char*[m_argc+1]; for (int i = 0; i <= m_argc; ++i) m_argv[i] = m_argv_orig[i]; } ceph-0.80.11/src/test/system/systest_settings.cc0000664000175100017510000000250612623076744023737 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "systest_settings.h" #include #include #include pthread_mutex_t g_system_test_settings_lock = PTHREAD_MUTEX_INITIALIZER; SysTestSettings& SysTestSettings:: inst() { pthread_mutex_lock(&g_system_test_settings_lock); if (!m_inst) m_inst = new SysTestSettings(); pthread_mutex_unlock(&g_system_test_settings_lock); return *m_inst; } bool SysTestSettings:: use_threads() const { return m_use_threads; } std::string SysTestSettings:: get_log_name(const std::string &suffix) const { if (m_log_file_base.empty()) return ""; std::ostringstream oss; oss << m_log_file_base << "." << suffix; return oss.str(); } SysTestSettings* SysTestSettings:: m_inst = NULL; SysTestSettings:: SysTestSettings() { m_use_threads = !!getenv("USE_THREADS"); const char *lfb = getenv("LOG_FILE_BASE"); if (lfb) m_log_file_base.assign(lfb); } SysTestSettings:: ~SysTestSettings() { } ceph-0.80.11/src/test/system/systest_runnable.h0000664000175100017510000000420112623076744023541 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SYSTEM_TEST_H #define CEPH_SYSTEM_TEST_H #include #include #include #include #define RETURN1_IF_NOT_VAL(expected, expr) \ do {\ int _rinv_ret = expr;\ if (_rinv_ret != expected) {\ printf("%s: file %s, line %d: expected %d, got %d\n",\ get_id_str(), __FILE__, __LINE__, expected, _rinv_ret);\ return 1; \ }\ } while(0); #define RETURN1_IF_NONZERO(expr) \ RETURN1_IF_NOT_VAL(0, expr) extern void* systest_runnable_pthread_helper(void *arg); /* Represents a single test thread / process. * * Inherit from this class and implement the test body in run(). */ class SysTestRunnable { public: static const int ID_STR_SZ = 128; SysTestRunnable(int argc, const char **argv); virtual ~SysTestRunnable(); /* Returns 0 on success; error code otherwise. */ virtual int run() = 0; /* Return a string identifying the runnable. */ const char* get_id_str(void) const; /* Start the Runnable */ int start(); /* Wait until the Runnable is finished. Returns an error string on failure. */ std::string join(); /* Starts a bunch of SystemTestRunnables and waits until they're done. * * Returns an error string on failure. */ static std::string run_until_finished(std::vector < SysTestRunnable * >& runnables); protected: int m_argc; const char **m_argv; private: SysTestRunnable(const SysTestRunnable &rhs); SysTestRunnable& operator=(const SysTestRunnable &rhs); void update_id_str(bool started); void set_argv(int argc, const char **argv); friend void* systest_runnable_pthread_helper(void *arg); const char **m_argv_orig; bool m_started; int m_id; pthread_t m_pthread; int m_pid; char m_id_str[ID_STR_SZ]; }; #endif ceph-0.80.11/src/test/system/rados_watch_notify.cc0000664000175100017510000001407712623076744024175 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_create_pool.h" #include "st_rados_delete_pool.h" #include "st_rados_delete_objs.h" #include "st_rados_watch.h" #include "st_rados_notify.h" #include "systest_runnable.h" #include "systest_settings.h" #include "include/stringify.h" #include #include #include #include #include #include #include #include #include #include #include #include using std::ostringstream; using std::string; using std::vector; /* * rados_watch_notify * * This tests watch/notify with pool and object deletion. * * EXPECT: * notifies to a deleted object or pool are not received * * notifies to existing objects are received * * DO NOT EXPECT * hangs, crashes */ const char *get_id_str() { return "main"; } int main(int argc, const char **argv) { std::string pool = "foo." + stringify(getpid()); CrossProcessSem *setup_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &setup_sem)); CrossProcessSem *watch_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &watch_sem)); CrossProcessSem *notify_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, ¬ify_sem)); // create a pool and an object, watch the object, notify. { StRadosCreatePool r1(argc, argv, NULL, setup_sem, NULL, pool, 1, ".obj"); StRadosWatch r2(argc, argv, setup_sem, watch_sem, notify_sem, 1, 0, pool, "0.obj"); StRadosNotify r3(argc, argv, setup_sem, watch_sem, notify_sem, 0, pool, "0.obj"); vector vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test1: got error: %s\n", error.c_str()); return EXIT_FAILURE; } } RETURN1_IF_NONZERO(setup_sem->reinit(0)); RETURN1_IF_NONZERO(watch_sem->reinit(0)); RETURN1_IF_NONZERO(notify_sem->reinit(0)); // create a pool and an object, watch a non-existent object, // notify non-existent object.watch pool += "."; { StRadosCreatePool r1(argc, argv, NULL, setup_sem, NULL, pool, 0, ".obj"); StRadosWatch r2(argc, argv, setup_sem, watch_sem, notify_sem, 0, -ENOENT, pool, "0.obj"); StRadosNotify r3(argc, argv, setup_sem, watch_sem, notify_sem, -ENOENT, pool, "0.obj"); vector vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test2: got error: %s\n", error.c_str()); return EXIT_FAILURE; } } RETURN1_IF_NONZERO(setup_sem->reinit(0)); RETURN1_IF_NONZERO(watch_sem->reinit(0)); RETURN1_IF_NONZERO(notify_sem->reinit(0)); CrossProcessSem *finished_notifies_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &finished_notifies_sem)); CrossProcessSem *deleted_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &deleted_sem)); CrossProcessSem *second_pool_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &second_pool_sem)); // create a pool and an object, watch the object, notify, // then delete the pool. // Create a new pool and write to it to make the osd get the updated map, // then try notifying on the deleted pool. pool += "."; { StRadosCreatePool r1(argc, argv, NULL, setup_sem, NULL, pool, 1, ".obj"); StRadosWatch r2(argc, argv, setup_sem, watch_sem, finished_notifies_sem, 1, 0, pool, "0.obj"); StRadosNotify r3(argc, argv, setup_sem, watch_sem, notify_sem, 0, pool, "0.obj"); StRadosDeletePool r4(argc, argv, notify_sem, deleted_sem, pool); StRadosCreatePool r5(argc, argv, deleted_sem, second_pool_sem, NULL, "bar", 1, ".obj"); StRadosNotify r6(argc, argv, second_pool_sem, NULL, finished_notifies_sem, 0, "bar", "0.obj"); StRadosDeletePool r7(argc, argv, finished_notifies_sem, NULL, "bar"); vector vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); vec.push_back(&r4); vec.push_back(&r5); vec.push_back(&r6); vec.push_back(&r7); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test3: got error: %s\n", error.c_str()); return EXIT_FAILURE; } } RETURN1_IF_NONZERO(setup_sem->reinit(0)); RETURN1_IF_NONZERO(watch_sem->reinit(0)); RETURN1_IF_NONZERO(notify_sem->reinit(0)); RETURN1_IF_NONZERO(finished_notifies_sem->reinit(0)); RETURN1_IF_NONZERO(deleted_sem->reinit(0)); // create a pool and an object, watch the object, notify, // then delete the object, notify if (false) { // this test is currently broken, pending the resolution of bug #2339 pool += "."; { StRadosCreatePool r1(argc, argv, NULL, setup_sem, NULL, pool, 1, ".obj"); StRadosWatch r2(argc, argv, setup_sem, watch_sem, finished_notifies_sem, 1, 0, pool, "0.obj"); StRadosNotify r3(argc, argv, setup_sem, watch_sem, notify_sem, 0, pool, "0.obj"); StRadosDeleteObjs r4(argc, argv, notify_sem, deleted_sem, 1, pool, ".obj"); StRadosNotify r5(argc, argv, setup_sem, deleted_sem, finished_notifies_sem, -ENOENT, pool, "0.obj"); vector vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); vec.push_back(&r4); vec.push_back(&r5); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test4: got error: %s\n", error.c_str()); return EXIT_FAILURE; } } } printf("******* SUCCESS **********\n"); return EXIT_SUCCESS; } ceph-0.80.11/src/test/system/cross_process_sem.cc0000664000175100017510000000454512623076744024041 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include #include #include #include /* We put our cross-process semaphore into a page of memory mapped with mmap. */ struct cross_process_sem_data_t { sem_t sem; }; /* A factory function is a good choice here because we want to be able to * return an error code. It does force heap allocation, but that is the * easiest way to use synchronization primitives anyway. Most programmers don't * care about destroying semaphores before the process finishes. It's pretty * difficult to get it right and there is usually no benefit. */ int CrossProcessSem:: create(int initial_val, CrossProcessSem** res) { struct cross_process_sem_data_t *data = static_cast < cross_process_sem_data_t*> ( mmap(NULL, sizeof(struct cross_process_sem_data_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0)); if (data == MAP_FAILED) { int err = errno; return err; } int ret = sem_init(&data->sem, 1, initial_val); if (ret) { return ret; } *res = new CrossProcessSem(data); return 0; } CrossProcessSem:: ~CrossProcessSem() { munmap(m_data, sizeof(struct cross_process_sem_data_t)); m_data = NULL; } void CrossProcessSem:: wait() { while(true) { int ret = sem_wait(&m_data->sem); if (ret == 0) return; int err = errno; if (err == -EINTR) continue; abort(); } } void CrossProcessSem:: post() { int ret = sem_post(&m_data->sem); if (ret == -1) { abort(); } } int CrossProcessSem:: reinit(int dval) { if (dval < 0) return -EINVAL; int cval; if (sem_getvalue(&m_data->sem, &cval) == -1) return errno; if (cval < dval) { int diff = dval - cval; for (int i = 0; i < diff; ++i) sem_post(&m_data->sem); } else { int diff = cval - dval; for (int i = 0; i < diff; ++i) sem_wait(&m_data->sem); } return 0; } CrossProcessSem:: CrossProcessSem(struct cross_process_sem_data_t *data) : m_data(data) { } ceph-0.80.11/src/test/system/st_rados_watch.cc0000664000175100017510000000445612623076744023313 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_watch.h" #include "systest_runnable.h" void notify_cb(uint8_t opcode, uint64_t ver, void *arg) { int *notifies = reinterpret_cast(arg); ++(*notifies); } StRadosWatch::StRadosWatch(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *watch_sem, CrossProcessSem *notify_sem, int num_notifies, int watch_retcode, const std::string &pool_name, const std::string &obj_name) : SysTestRunnable(argc, argv), m_setup_sem(setup_sem), m_watch_sem(watch_sem), m_notify_sem(notify_sem), m_num_notifies(num_notifies), m_watch_retcode(watch_retcode), m_pool_name(pool_name), m_obj_name(obj_name) { } StRadosWatch:: ~StRadosWatch() { } int StRadosWatch:: run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); if (m_setup_sem) { m_setup_sem->wait(); m_setup_sem->post(); } rados_ioctx_t io_ctx; uint64_t handle; int num_notifies = 0; RETURN1_IF_NONZERO(rados_connect(cl)); RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); printf("%s: watching object %s\n", get_id_str(), m_obj_name.c_str()); RETURN1_IF_NOT_VAL( rados_watch(io_ctx, m_obj_name.c_str(), 0, &handle, reinterpret_cast(notify_cb), reinterpret_cast(&num_notifies)), m_watch_retcode ); if (m_watch_sem) { m_watch_sem->post(); } m_notify_sem->wait(); m_notify_sem->post(); int r = 0; if (num_notifies < m_num_notifies) { printf("Received fewer notifies than expected: %d < %d\n", num_notifies, m_num_notifies); r = 1; } rados_unwatch(io_ctx, m_obj_name.c_str(), handle); rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return r; } ceph-0.80.11/src/test/system/cross_process_sem.h0000664000175100017510000000170212623076744023673 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ struct cross_process_sem_data_t; class CrossProcessSem { public: static int create(int initial_val, CrossProcessSem** ret); ~CrossProcessSem(); /* Initialize the semaphore. Must be called before any operations */ int init(); /* Semaphore wait */ void wait(); /* Semaphore post */ void post(); /* Reinitialize the semaphore to the desired value. * NOT thread-safe if it is in use at the time! */ int reinit(int dval); private: CrossProcessSem(struct cross_process_sem_data_t *data); struct cross_process_sem_data_t *m_data; }; ceph-0.80.11/src/test/system/rados_delete_pools_parallel.cc0000664000175100017510000000576512623076744026035 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_create_pool.h" #include "st_rados_delete_pool.h" #include "st_rados_list_objects.h" #include "systest_runnable.h" #include "systest_settings.h" #include #include #include #include #include #include #include #include #include #include using std::ostringstream; using std::string; using std::vector; static int g_num_objects = 50; /* * rados_delete_pools_parallel * * This tests creation and deletion races. * * EXPECT: * can delete a pool while another user is using it * * operations on pools return error codes after the pools * are deleted * * DO NOT EXPECT * hangs, crashes */ const char *get_id_str() { return "main"; } int main(int argc, const char **argv) { const char *num_objects = getenv("NUM_OBJECTS"); std::string pool = "foo"; if (num_objects) { g_num_objects = atoi(num_objects); if (g_num_objects == 0) return 100; } CrossProcessSem *pool_setup_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); CrossProcessSem *delete_pool_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &delete_pool_sem)); // first test: create a pool, then delete that pool { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, 50, ".obj"); StRadosDeletePool r2(argc, argv, pool_setup_sem, NULL, pool); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test1: got error: %s\n", error.c_str()); return EXIT_FAILURE; } } // second test: create a pool, the list objects in that pool while it's // being deleted. RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); RETURN1_IF_NONZERO(delete_pool_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, pool, g_num_objects, ".obj"); StRadosDeletePool r2(argc, argv, delete_pool_sem, NULL, pool); StRadosListObjects r3(argc, argv, pool, true, g_num_objects / 2, pool_setup_sem, NULL, delete_pool_sem); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); vec.push_back(&r3); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test2: got error: %s\n", error.c_str()); return EXIT_FAILURE; } } printf("******* SUCCESS **********\n"); return EXIT_SUCCESS; } ceph-0.80.11/src/test/system/st_rados_create_pool.h0000664000175100017510000000244112623076744024333 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef TEST_SYSTEM_ST_RADOS_CREATE_POOL_H #define TEST_SYSTEM_ST_RADOS_CREATE_POOL_H #include "systest_runnable.h" class CrossProcessSem; /* * st_rados_create_pool * * Waits, then posts to setup_sem. * Creates a pool and populates it with some objects. * Then, calls pool_setup_sem->post() */ class StRadosCreatePool : public SysTestRunnable { public: static std::string get_random_buf(int sz); StRadosCreatePool(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *pool_setup_sem, CrossProcessSem *close_create_pool_sem, const std::string &pool_name, int num_objects, const std::string &suffix); ~StRadosCreatePool(); virtual int run(); private: CrossProcessSem *m_setup_sem; CrossProcessSem *m_pool_setup_sem; CrossProcessSem *m_close_create_pool; std::string m_pool_name; int m_num_objects; std::string m_suffix; }; #endif ceph-0.80.11/src/test/system/st_rados_delete_objs.cc0000664000175100017510000000356612623076744024465 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_delete_objs.h" #include "systest_runnable.h" #include "systest_settings.h" #include StRadosDeleteObjs::StRadosDeleteObjs(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *deleted_sem, int num_objs, const std::string &pool_name, const std::string &suffix) : SysTestRunnable(argc, argv), m_setup_sem(setup_sem), m_deleted_sem(deleted_sem), m_num_objs(num_objs), m_pool_name(pool_name), m_suffix(suffix) { } StRadosDeleteObjs::~StRadosDeleteObjs() { } int StRadosDeleteObjs::run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); RETURN1_IF_NONZERO(rados_connect(cl)); m_setup_sem->wait(); m_setup_sem->post(); rados_ioctx_t io_ctx; rados_pool_create(cl, m_pool_name.c_str()); RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); for (int i = 0; i < m_num_objs; ++i) { char oid[128]; snprintf(oid, sizeof(oid), "%d%s", i, m_suffix.c_str()); RETURN1_IF_NONZERO(rados_remove(io_ctx, oid)); if (((i % 25) == 0) || (i == m_num_objs - 1)) { printf("%s: deleted object %d...\n", get_id_str(), i); } } rados_ioctx_destroy(io_ctx); if (m_deleted_sem) m_deleted_sem->post(); rados_shutdown(cl); return 0; } ceph-0.80.11/src/test/system/st_rados_delete_objs.h0000664000175100017510000000217712623076744024324 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef TEST_SYSTEM_ST_RADOS_DELETE_OBJS_H #define TEST_SYSTEM_ST_RADOS_DELETE_OBJS_H #include "systest_runnable.h" class CrossProcessSem; /* * st_rados_delete_objs * * Waits on setup_sem, posts to it, * deletes num_objs objects from the pool, * and posts to deleted_sem. */ class StRadosDeleteObjs : public SysTestRunnable { public: StRadosDeleteObjs(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *deleted_sem, int num_objs, const std::string &pool_name, const std::string &suffix); ~StRadosDeleteObjs(); virtual int run(); private: CrossProcessSem *m_setup_sem; CrossProcessSem *m_deleted_sem; int m_num_objs; std::string m_pool_name; std::string m_suffix; }; #endif ceph-0.80.11/src/test/system/st_rados_create_pool.cc0000664000175100017510000000553412623076744024477 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_create_pool.h" #include "systest_runnable.h" #include "systest_settings.h" #include #include #include #include #include #include using std::ostringstream; std::string StRadosCreatePool:: get_random_buf(int sz) { ostringstream oss; int size = rand() % sz; // yep, it's not very random for (int i = 0; i < size; ++i) { oss << "."; } return oss.str(); } StRadosCreatePool:: StRadosCreatePool(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *pool_setup_sem, CrossProcessSem *close_create_pool, const std::string &pool_name, int num_objects, const std::string &suffix) : SysTestRunnable(argc, argv), m_setup_sem(setup_sem), m_pool_setup_sem(pool_setup_sem), m_close_create_pool(close_create_pool), m_pool_name(pool_name), m_num_objects(num_objects), m_suffix(suffix) { } StRadosCreatePool:: ~StRadosCreatePool() { } int StRadosCreatePool:: run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); rados_conf_parse_env(cl, NULL); if (m_setup_sem) { m_setup_sem->wait(); m_setup_sem->post(); } RETURN1_IF_NONZERO(rados_connect(cl)); printf("%s: creating pool %s\n", get_id_str(), m_pool_name.c_str()); rados_pool_create(cl, m_pool_name.c_str()); rados_ioctx_t io_ctx; RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); for (int i = 0; i < m_num_objects; ++i) { char oid[128]; snprintf(oid, sizeof(oid), "%d%s", i, m_suffix.c_str()); std::string buf(get_random_buf(256)); int ret = rados_write(io_ctx, oid, buf.c_str(), buf.size(), 0); if (ret != 0) { printf("%s: rados_write error %d\n", get_id_str(), ret); return ret; } if (((i % 25) == 0) || (i == m_num_objects - 1)) { printf("%s: created object %d...\n", get_id_str(), i); } } printf("%s: finishing.\n", get_id_str()); if (m_pool_setup_sem) m_pool_setup_sem->post(); if (m_close_create_pool) m_close_create_pool->wait(); rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return 0; } ceph-0.80.11/src/test/system/st_rados_notify.cc0000664000175100017510000000352312623076744023507 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_notify.h" #include "systest_runnable.h" StRadosNotify::StRadosNotify(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *notify_sem, CrossProcessSem *notified_sem, int notify_retcode, const std::string &pool_name, const std::string &obj_name) : SysTestRunnable(argc, argv), m_setup_sem(setup_sem), m_notify_sem(notify_sem), m_notified_sem(notified_sem), m_notify_retcode(notify_retcode), m_pool_name(pool_name), m_obj_name(obj_name) { } StRadosNotify::~StRadosNotify() { } int StRadosNotify::run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); if (m_setup_sem) { m_setup_sem->wait(); m_setup_sem->post(); } rados_ioctx_t io_ctx; RETURN1_IF_NONZERO(rados_connect(cl)); RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); if (m_notify_sem) { m_notify_sem->wait(); m_notify_sem->post(); } printf("%s: notifying object %s\n", get_id_str(), m_obj_name.c_str()); RETURN1_IF_NOT_VAL(m_notify_retcode, rados_notify(io_ctx, m_obj_name.c_str(), 0, NULL, 0)); if (m_notified_sem) { m_notified_sem->post(); } rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return 0; } ceph-0.80.11/src/test/system/rados_open_pools_parallel.cc0000664000175100017510000000752312623076744025526 0ustar jenkins-buildjenkins-build // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_create_pool.h" #include "systest_runnable.h" #include "systest_settings.h" #include #include #include #include #include #include #include #include #include #include using std::ostringstream; using std::string; using std::vector; /* * rados_open_pools_parallel * * This tests creating a pool in one Runnable, and then opening an io context * based on that pool in another. * * EXPECT: * can't create the same pool twice * * one Runnable can use the pool after the other one creates it * * DO NOT EXPECT * hangs, crashes */ class StRadosOpenPool : public SysTestRunnable { public: StRadosOpenPool(int argc, const char **argv, CrossProcessSem *pool_setup_sem, CrossProcessSem *open_pool_sem) : SysTestRunnable(argc, argv), m_pool_setup_sem(pool_setup_sem), m_open_pool_sem(open_pool_sem) { } ~StRadosOpenPool() { } int run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); RETURN1_IF_NONZERO(rados_connect(cl)); if (m_pool_setup_sem) m_pool_setup_sem->wait(); printf("%s: rados_pool_create.\n", get_id_str()); rados_pool_create(cl, "foo"); rados_ioctx_t io_ctx; printf("%s: rados_ioctx_create.\n", get_id_str()); RETURN1_IF_NOT_VAL(0, rados_ioctx_create(cl, "foo", &io_ctx)); if (m_open_pool_sem) m_open_pool_sem->post(); rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return 0; } private: CrossProcessSem *m_pool_setup_sem; CrossProcessSem *m_open_pool_sem; }; const char *get_id_str() { return "main"; } int main(int argc, const char **argv) { // first test: create a pool, shut down the client, access that // pool in a different process. CrossProcessSem *pool_setup_sem = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); StRadosCreatePool r1(argc, argv, NULL, pool_setup_sem, NULL, "foo", 50, ".obj"); StRadosOpenPool r2(argc, argv, pool_setup_sem, NULL); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); std::string error = SysTestRunnable::run_until_finished(vec); if (!error.empty()) { printf("test1: got error: %s\n", error.c_str()); return EXIT_FAILURE; } // second test: create a pool, access that // pool in a different process, THEN shut down the first client. CrossProcessSem *pool_setup_sem2 = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem2)); CrossProcessSem *open_pool_sem2 = NULL; RETURN1_IF_NONZERO(CrossProcessSem::create(0, &open_pool_sem2)); StRadosCreatePool r3(argc, argv, NULL, pool_setup_sem2, open_pool_sem2, "foo", 50, ".obj"); StRadosOpenPool r4(argc, argv, pool_setup_sem2, open_pool_sem2); vector < SysTestRunnable* > vec2; vec2.push_back(&r3); vec2.push_back(&r4); error = SysTestRunnable::run_until_finished(vec2); if (!error.empty()) { printf("test2: got error: %s\n", error.c_str()); return EXIT_FAILURE; } printf("******* SUCCESS **********\n"); return EXIT_SUCCESS; } ceph-0.80.11/src/test/system/st_rados_list_objects.h0000664000175100017510000000250212623076744024521 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef TEST_SYSTEM_ST_RADOS_LIST_OBJECTS_H #define TEST_SYSTEM_ST_RADOS_LIST_OBJECTS_H #include "systest_runnable.h" class CrossProcessSem; /* * st_rados_list_objects * * 1. calls pool_setup_sem->wait() * 2. calls pool_setup_sem->post() * 3. list some objects * 4. modify_sem->wait() * 5. list some objects */ class StRadosListObjects : public SysTestRunnable { public: static std::string get_random_buf(int sz); StRadosListObjects(int argc, const char **argv, const std::string &pool_name, bool accept_list_errors, int midway_cnt, CrossProcessSem *pool_setup_sem, CrossProcessSem *midway_sem_wait, CrossProcessSem *midway_sem_post); ~StRadosListObjects(); virtual int run(); private: std::string m_pool_name; bool m_accept_list_errors; int m_midway_cnt; CrossProcessSem *m_pool_setup_sem; CrossProcessSem *m_midway_sem_wait; CrossProcessSem *m_midway_sem_post; }; #endif ceph-0.80.11/src/test/system/st_rados_delete_pool.cc0000664000175100017510000000324012623076744024466 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_delete_pool.h" #include "systest_runnable.h" #include "systest_settings.h" #include StRadosDeletePool::StRadosDeletePool(int argc, const char **argv, CrossProcessSem *pool_setup_sem, CrossProcessSem *delete_pool_sem, const std::string &pool_name) : SysTestRunnable(argc, argv), m_pool_setup_sem(pool_setup_sem), m_delete_pool_sem(delete_pool_sem), m_pool_name(pool_name) { } StRadosDeletePool::~StRadosDeletePool() { } int StRadosDeletePool::run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); RETURN1_IF_NONZERO(rados_connect(cl)); m_pool_setup_sem->wait(); m_pool_setup_sem->post(); rados_ioctx_t io_ctx; rados_pool_create(cl, m_pool_name.c_str()); RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); rados_ioctx_destroy(io_ctx); printf("%s: deleting pool %s\n", get_id_str(), m_pool_name.c_str()); RETURN1_IF_NONZERO(rados_pool_delete(cl, m_pool_name.c_str())); if (m_delete_pool_sem) m_delete_pool_sem->post(); rados_shutdown(cl); return 0; } ceph-0.80.11/src/test/system/systest_settings.h0000664000175100017510000000155012623076744023577 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SYSTEM_TEST_SETTINGS_H #define CEPH_SYSTEM_TEST_SETTINGS_H #include /* Singleton with settings grabbed from environment variables */ class SysTestSettings { public: static SysTestSettings& inst(); bool use_threads() const; std::string get_log_name(const std::string &suffix) const; private: static SysTestSettings* m_inst; SysTestSettings(); ~SysTestSettings(); bool m_use_threads; std::string m_log_file_base; }; #endif ceph-0.80.11/src/test/system/st_rados_watch.h0000664000175100017510000000252212623076744023145 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef TEST_SYSTEM_ST_RADOS_WATCH_H #define TEST_SYSTEM_ST_RADOS_WATCH_H #include "systest_runnable.h" class CrossProcessSem; /* * st_rados_watch * * 1. waits on setup_sem * 2. posts to setup_sem * 3. watches an object * 4. posts to watch_sem * 5. waits on notify_sem * 6. posts to notify_sem * 7. checks that the correct number of notifies were received */ class StRadosWatch : public SysTestRunnable { public: StRadosWatch(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *watch_sem, CrossProcessSem *notify_sem, int num_notifies, int watch_retcode, const std::string &pool_name, const std::string &obj_name); ~StRadosWatch(); virtual int run(); private: CrossProcessSem *m_setup_sem; CrossProcessSem *m_watch_sem; CrossProcessSem *m_notify_sem; int m_num_notifies; int m_watch_retcode; std::string m_pool_name; std::string m_obj_name; }; #endif ceph-0.80.11/src/test/system/st_rados_list_objects.cc0000664000175100017510000000507012623076744024662 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cross_process_sem.h" #include "include/rados/librados.h" #include "st_rados_list_objects.h" #include "systest_runnable.h" #include "systest_settings.h" #include #include #include #include #include #include using std::ostringstream; StRadosListObjects:: StRadosListObjects(int argc, const char **argv, const std::string &pool_name, bool accept_list_errors, int midway_cnt, CrossProcessSem *pool_setup_sem, CrossProcessSem *midway_sem_wait, CrossProcessSem *midway_sem_post) : SysTestRunnable(argc, argv), m_accept_list_errors(accept_list_errors), m_midway_cnt(midway_cnt), m_pool_setup_sem(pool_setup_sem), m_midway_sem_wait(midway_sem_wait), m_midway_sem_post(midway_sem_post) { } StRadosListObjects:: ~StRadosListObjects() { } int StRadosListObjects:: run() { rados_t cl; RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); rados_conf_parse_env(cl, NULL); RETURN1_IF_NONZERO(rados_connect(cl)); m_pool_setup_sem->wait(); m_pool_setup_sem->post(); rados_ioctx_t io_ctx; rados_pool_create(cl, "foo"); RETURN1_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); int saw = 0; const char *obj_name; rados_list_ctx_t h; printf("%s: listing objects.\n", get_id_str()); RETURN1_IF_NONZERO(rados_objects_list_open(io_ctx, &h)); while (true) { int ret = rados_objects_list_next(h, &obj_name, NULL); if (ret == -ENOENT) { break; } else if (ret != 0) { if (m_accept_list_errors && (!m_midway_sem_post || saw > m_midway_cnt)) break; printf("%s: rados_objects_list_next error: %d\n", get_id_str(), ret); return ret; } if ((saw % 25) == 0) { printf("%s: listed object %d...\n", get_id_str(), saw); } ++saw; if (saw == m_midway_cnt) { if (m_midway_sem_wait) m_midway_sem_wait->wait(); if (m_midway_sem_post) m_midway_sem_post->post(); } } rados_objects_list_close(h); printf("%s: saw %d objects\n", get_id_str(), saw); rados_ioctx_destroy(io_ctx); rados_shutdown(cl); return 0; } ceph-0.80.11/src/test/system/st_rados_delete_pool.h0000664000175100017510000000204012623076744024325 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef TEST_SYSTEM_ST_RADOS_DELETE_POOL_H #define TEST_SYSTEM_ST_RADOS_DELETE_POOL_H #include "systest_runnable.h" class CrossProcessSem; /* * st_rados_delete_pool * * Waits on pool_setup_sem, posts to it, * deletes a pool, and posts to delete_pool_sem. */ class StRadosDeletePool : public SysTestRunnable { public: StRadosDeletePool(int argc, const char **argv, CrossProcessSem *pool_setup_sem, CrossProcessSem *delete_pool_sem, const std::string &pool_name); ~StRadosDeletePool(); virtual int run(); private: CrossProcessSem *m_pool_setup_sem; CrossProcessSem *m_delete_pool_sem; std::string m_pool_name; }; #endif ceph-0.80.11/src/test/system/st_rados_notify.h0000664000175100017510000000235012623076744023346 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef TEST_SYSTEM_ST_RADOS_NOTIFY_H #define TEST_SYSTEM_ST_RADOS_NOTIFY_H #include "systest_runnable.h" class CrossProcessSem; /* * st_rados_notify * * 1. waits on and then posts to setup_sem * 2. connects and opens the pool * 3. waits on and then posts to notify_sem * 4. notifies on the object * 5. posts to notified_sem */ class StRadosNotify : public SysTestRunnable { public: StRadosNotify(int argc, const char **argv, CrossProcessSem *setup_sem, CrossProcessSem *notify_sem, CrossProcessSem *notified_sem, int notify_retcode, const std::string &pool_name, const std::string &obj_name); ~StRadosNotify(); virtual int run(); private: CrossProcessSem *m_setup_sem; CrossProcessSem *m_notify_sem; CrossProcessSem *m_notified_sem; int m_notify_retcode; std::string m_pool_name; std::string m_obj_name; }; #endif ceph-0.80.11/src/test/librados/0000775000175100017510000000000012623077036020235 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/librados/TestCase.h0000664000175100017510000000527012623076744022132 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_TEST_RADOS_TESTCASE_H #define CEPH_TEST_RADOS_TESTCASE_H #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "gtest/gtest.h" #include /** * These test cases create a temporary pool that lives as long as the * test case. Each test within a test case gets a new ioctx set to a * unique namespace within the pool. * * Since pool creation and deletion is slow, this allows many tests to * run faster. */ class RadosTest : public ::testing::Test { public: RadosTest() {} virtual ~RadosTest() {} protected: static void SetUpTestCase(); static void TearDownTestCase(); static void cleanup_default_namespace(rados_ioctx_t ioctx); static rados_t s_cluster; static std::string pool_name; static std::string nspace; virtual void SetUp(); virtual void TearDown(); rados_t cluster; rados_ioctx_t ioctx; }; class RadosTestPP : public ::testing::Test { public: RadosTestPP() : cluster(s_cluster) {} virtual ~RadosTestPP() {} protected: static void SetUpTestCase(); static void TearDownTestCase(); static void cleanup_default_namespace(librados::IoCtx ioctx); static librados::Rados s_cluster; static std::string pool_name; virtual void SetUp(); virtual void TearDown(); librados::Rados &cluster; librados::IoCtx ioctx; std::string ns; }; class RadosTestParamPP : public ::testing::TestWithParam { public: RadosTestParamPP() : cluster(s_cluster) {} virtual ~RadosTestParamPP() {} static void SetUpTestCase(); static void TearDownTestCase(); protected: static void cleanup_default_namespace(librados::IoCtx ioctx); static librados::Rados s_cluster; static std::string pool_name; static std::string cache_pool_name; virtual void SetUp(); virtual void TearDown(); librados::Rados &cluster; librados::IoCtx ioctx; std::string ns; }; class RadosTestEC : public RadosTest { public: RadosTestEC() {} virtual ~RadosTestEC() {} protected: static void SetUpTestCase(); static void TearDownTestCase(); static rados_t s_cluster; static std::string pool_name; virtual void SetUp(); virtual void TearDown(); rados_t cluster; rados_ioctx_t ioctx; uint64_t alignment; }; class RadosTestECPP : public RadosTestPP { public: RadosTestECPP() : cluster(s_cluster) {}; virtual ~RadosTestECPP() {}; protected: static void SetUpTestCase(); static void TearDownTestCase(); static librados::Rados s_cluster; static std::string pool_name; virtual void SetUp(); virtual void TearDown(); librados::Rados &cluster; librados::IoCtx ioctx; std::string ns; uint64_t alignment; }; #endif ceph-0.80.11/src/test/librados/test.cc0000664000175100017510000001624712623076744021542 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -* // vim: ts=8 sw=2 smarttab #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include #include #include #include #include using namespace librados; std::string get_temp_pool_name() { char hostname[80]; char out[80]; memset(hostname, 0, sizeof(hostname)); memset(out, 0, sizeof(out)); gethostname(hostname, sizeof(hostname)-1); static int num = 1; sprintf(out, "%s-%d-%d", hostname, getpid(), num); num++; std::string prefix("test-rados-api-"); prefix += out; return prefix; } std::string create_one_pool(const std::string &pool_name, rados_t *cluster) { std::string err = connect_cluster(cluster); if (err.length()) return err; int ret = rados_pool_create(*cluster, pool_name.c_str()); if (ret) { rados_shutdown(*cluster); std::ostringstream oss; oss << "rados_pool_create(" << pool_name << ") failed with error " << ret; return oss.str(); } return ""; } std::string create_one_ec_pool(const std::string &pool_name, rados_t *cluster) { std::string err = connect_cluster(cluster); if (err.length()) return err; char *cmd[2]; cmd[1] = NULL; cmd[0] = (char *)"{\"prefix\": \"osd erasure-code-profile set\", \"name\": \"testprofile\", \"profile\": [ \"k=2\", \"m=1\", \"ruleset-failure-domain=osd\"]}"; int ret = rados_mon_command(*cluster, (const char **)cmd, 1, "", 0, NULL, NULL, NULL, NULL); if (ret) { rados_shutdown(*cluster); std::ostringstream oss; oss << "rados_mon_command erasure-code-profile set name:testprofile failed with error " << ret; return oss.str(); } std::string cmdstr = "{\"prefix\": \"osd pool create\", \"pool\": \"" + pool_name + "\", \"pool_type\":\"erasure\", \"pg_num\":8, \"pgp_num\":8, \"erasure_code_profile\":\"testprofile\"}"; cmd[0] = (char *)cmdstr.c_str(); ret = rados_mon_command(*cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0); if (ret) { std::ostringstream oss; cmd[0] = (char *)"{\"prefix\": \"osd erasure-code-profile rm\", \"name\": \"testprofile\"}"; int ret2 = rados_mon_command(*cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0); if (ret2) oss << "rados_mon_command osd erasure-code-profile rm name:testprofile failed with error " << ret2 << std::endl; rados_shutdown(*cluster); oss << "rados_mon_command erasure-code-profile set name:testprofile failed with error " << ret; return oss.str(); } rados_wait_for_latest_osdmap(*cluster); return ""; } std::string create_one_pool_pp(const std::string &pool_name, Rados &cluster) { std::string err = connect_cluster_pp(cluster); if (err.length()) return err; int ret = cluster.pool_create(pool_name.c_str()); if (ret) { cluster.shutdown(); std::ostringstream oss; oss << "cluster.pool_create(" << pool_name << ") failed with error " << ret; return oss.str(); } return ""; } std::string create_one_ec_pool_pp(const std::string &pool_name, Rados &cluster) { std::string err = connect_cluster_pp(cluster); if (err.length()) return err; bufferlist inbl; int ret = cluster.mon_command( "{\"prefix\": \"osd erasure-code-profile set\", \"name\": \"testprofile\", \"profile\": [ \"k=2\", \"m=1\", \"ruleset-failure-domain=osd\"]}", inbl, NULL, NULL); if (ret) { cluster.shutdown(); std::ostringstream oss; oss << "mon_command erasure-code-profile set name:testprofile failed with error " << ret; return oss.str(); } ret = cluster.mon_command( "{\"prefix\": \"osd pool create\", \"pool\": \"" + pool_name + "\", \"pool_type\":\"erasure\", \"pg_num\":8, \"pgp_num\":8, \"erasure_code_profile\":\"testprofile\"}", inbl, NULL, NULL); if (ret) { std::ostringstream oss; bufferlist inbl; int ret2 = cluster.mon_command( "{\"prefix\": \"osd erasure-code-profile rm\", \"name\": \"testprofile\"}", inbl, NULL, NULL); if (ret2) oss << "mon_command osd erasure-code-profile rm name:testprofile failed with error " << ret2 << std::endl; cluster.shutdown(); oss << "mon_command osd pool create pool:" << pool_name << " pool_type:erasure failed with error " << ret; return oss.str(); } cluster.wait_for_latest_osdmap(); return ""; } std::string connect_cluster(rados_t *cluster) { char *id = getenv("CEPH_CLIENT_ID"); if (id) std::cerr << "Client id is: " << id << std::endl; int ret; ret = rados_create(cluster, NULL); if (ret) { std::ostringstream oss; oss << "rados_create failed with error " << ret; return oss.str(); } ret = rados_conf_read_file(*cluster, NULL); if (ret) { rados_shutdown(*cluster); std::ostringstream oss; oss << "rados_conf_read_file failed with error " << ret; return oss.str(); } rados_conf_parse_env(*cluster, NULL); ret = rados_connect(*cluster); if (ret) { rados_shutdown(*cluster); std::ostringstream oss; oss << "rados_connect failed with error " << ret; return oss.str(); } return ""; } std::string connect_cluster_pp(Rados &cluster) { char *id = getenv("CEPH_CLIENT_ID"); if (id) std::cerr << "Client id is: " << id << std::endl; int ret; ret = cluster.init(id); if (ret) { std::ostringstream oss; oss << "cluster.init failed with error " << ret; return oss.str(); } ret = cluster.conf_read_file(NULL); if (ret) { cluster.shutdown(); std::ostringstream oss; oss << "cluster.conf_read_file failed with error " << ret; return oss.str(); } cluster.conf_parse_env(NULL); ret = cluster.connect(); if (ret) { cluster.shutdown(); std::ostringstream oss; oss << "cluster.connect failed with error " << ret; return oss.str(); } return ""; } int destroy_one_pool(const std::string &pool_name, rados_t *cluster) { int ret = rados_pool_delete(*cluster, pool_name.c_str()); if (ret) { rados_shutdown(*cluster); return ret; } rados_shutdown(*cluster); return 0; } int destroy_one_ec_pool(const std::string &pool_name, rados_t *cluster) { int ret = rados_pool_delete(*cluster, pool_name.c_str()); if (ret == 0) { char *cmd[2]; cmd[1] = NULL; cmd[0] = (char *)"{\"prefix\": \"osd erasure-code-profile rm\", \"name\": \"testprofile\"}"; int ret2 = rados_mon_command(*cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0); if (ret2) { rados_shutdown(*cluster); return ret2; } rados_wait_for_latest_osdmap(*cluster); } rados_shutdown(*cluster); return ret; } int destroy_one_pool_pp(const std::string &pool_name, Rados &cluster) { int ret = cluster.pool_delete(pool_name.c_str()); if (ret) { cluster.shutdown(); return ret; } cluster.shutdown(); return 0; } int destroy_one_ec_pool_pp(const std::string &pool_name, Rados &cluster) { int ret = cluster.pool_delete(pool_name.c_str()); bufferlist inbl; if (ret == 0) { int ret2 = cluster.mon_command( "{\"prefix\": \"osd erasure-code-profile rm\", \"name\": \"testprofile\"}", inbl, NULL, NULL); if (ret2) { cluster.shutdown(); return ret2; } cluster.wait_for_latest_osdmap(); } cluster.shutdown(); return ret; } ceph-0.80.11/src/test/librados/list.cc0000664000175100017510000004640212623076744021532 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/stringify.h" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include "include/types.h" #include "gtest/gtest.h" #include #include using namespace librados; typedef RadosTest LibRadosList; typedef RadosTestPP LibRadosListPP; typedef RadosTestEC LibRadosListEC; typedef RadosTestECPP LibRadosListECPP; TEST_F(LibRadosList, ListObjects) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); rados_list_ctx_t ctx; ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); const char *entry; bool foundit = false; while (rados_objects_list_next(ctx, &entry, NULL) != -ENOENT) { foundit = true; ASSERT_EQ(std::string(entry), "foo"); } ASSERT_TRUE(foundit); rados_objects_list_close(ctx); } TEST_F(LibRadosListPP, ListObjectsPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ObjectIterator iter(ioctx.objects_begin()); bool foundit = false; while (iter != ioctx.objects_end()) { foundit = true; ASSERT_EQ((*iter).first, "foo"); ++iter; } ASSERT_TRUE(foundit); } TEST_F(LibRadosListPP, ListObjectsTwicePP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ObjectIterator iter(ioctx.objects_begin()); bool foundit = false; while (iter != ioctx.objects_end()) { foundit = true; ASSERT_EQ((*iter).first, "foo"); ++iter; } ASSERT_TRUE(foundit); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); foundit = false; iter.seek(0); while (iter != ioctx.objects_end()) { foundit = true; ASSERT_EQ((*iter).first, "foo"); ++iter; } ASSERT_TRUE(foundit); } TEST_F(LibRadosListPP, ListObjectsCopyIterPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); // make sure this is still valid after the original iterators are gone ObjectIterator iter3; { ObjectIterator iter(ioctx.objects_begin()); ObjectIterator iter2(iter); iter3 = iter2; ASSERT_EQ((*iter).first, "foo"); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); ASSERT_EQ(iter2->first, "foo"); ASSERT_EQ(iter3->first, "foo"); ++iter2; ASSERT_TRUE(iter2 == ioctx.objects_end()); } ASSERT_EQ(iter3->first, "foo"); iter3 = iter3; ASSERT_EQ(iter3->first, "foo"); ++iter3; ASSERT_TRUE(iter3 == ioctx.objects_end()); } TEST_F(LibRadosListPP, ListObjectsEndIter) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ObjectIterator iter(ioctx.objects_begin()); ObjectIterator iter_end(ioctx.objects_end()); ObjectIterator iter_end2 = ioctx.objects_end(); ASSERT_TRUE(iter_end == iter_end2); ASSERT_TRUE(iter_end == ioctx.objects_end()); ASSERT_TRUE(iter_end2 == ioctx.objects_end()); ASSERT_EQ(iter->first, "foo"); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); ASSERT_TRUE(iter == iter_end); ASSERT_TRUE(iter == iter_end2); ObjectIterator iter2 = iter; ASSERT_TRUE(iter2 == ioctx.objects_end()); ASSERT_TRUE(iter2 == iter_end); ASSERT_TRUE(iter2 == iter_end2); } static void check_list(std::set& myset, rados_list_ctx_t& ctx) { const char *entry; std::set orig_set(myset); /** * During splitting, we might see duplicate items. * We assert that every object returned is in myset and that * we don't hit ENOENT until we have hit every item in myset * at least once. */ while (rados_objects_list_next(ctx, &entry, NULL) != -ENOENT) { ASSERT_TRUE(orig_set.end() != orig_set.find(std::string(entry))); myset.erase(std::string(entry)); } ASSERT_TRUE(myset.empty()); } TEST_F(LibRadosList, ListObjectsNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7 rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_write(ioctx, "foo1", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "ns1"); ASSERT_EQ(0, rados_write(ioctx, "foo1", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_write(ioctx, "foo2", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo3", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "ns1"); ASSERT_EQ(0, rados_write(ioctx, "foo4", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo5", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "ns2"); ASSERT_EQ(0, rados_write(ioctx, "foo6", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo7", buf, sizeof(buf), 0)); std::set def, ns1, ns2; def.insert(std::string("foo1")); def.insert(std::string("foo2")); def.insert(std::string("foo3")); ns1.insert(std::string("foo1")); ns1.insert(std::string("foo4")); ns1.insert(std::string("foo5")); ns2.insert(std::string("foo6")); ns2.insert(std::string("foo7")); rados_list_ctx_t ctx; // Check default namespace "" rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); check_list(def, ctx); rados_objects_list_close(ctx); // Check default namespace "ns1" rados_ioctx_set_namespace(ioctx, "ns1"); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); check_list(ns1, ctx); rados_objects_list_close(ctx); // Check default namespace "ns2" rados_ioctx_set_namespace(ioctx, "ns2"); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); check_list(ns2, ctx); rados_objects_list_close(ctx); } static void check_listpp(std::set& myset, IoCtx& ioctx) { ObjectIterator iter(ioctx.objects_begin()); std::set orig_set(myset); /** * During splitting, we might see duplicate items. * We assert that every object returned is in myset and that * we don't hit ENOENT until we have hit every item in myset * at least once. */ while (iter != ioctx.objects_end()) { ASSERT_TRUE(orig_set.end() != orig_set.find(std::string((*iter).first))); myset.erase(std::string((*iter).first)); ++iter; } ASSERT_TRUE(myset.empty()); } TEST_F(LibRadosListPP, ListObjectsPPNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7 ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0)); ioctx.set_namespace("ns1"); ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0)); ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.write("foo2", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo3", bl1, sizeof(buf), 0)); ioctx.set_namespace("ns1"); ASSERT_EQ(0, ioctx.write("foo4", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo5", bl1, sizeof(buf), 0)); ioctx.set_namespace("ns2"); ASSERT_EQ(0, ioctx.write("foo6", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo7", bl1, sizeof(buf), 0)); std::set def, ns1, ns2; def.insert(std::string("foo1")); def.insert(std::string("foo2")); def.insert(std::string("foo3")); ns1.insert(std::string("foo1")); ns1.insert(std::string("foo4")); ns1.insert(std::string("foo5")); ns2.insert(std::string("foo6")); ns2.insert(std::string("foo7")); ioctx.set_namespace(""); check_listpp(def, ioctx); ioctx.set_namespace("ns1"); check_listpp(ns1, ioctx); ioctx.set_namespace("ns2"); check_listpp(ns2, ioctx); } TEST_F(LibRadosListPP, ListObjectsManyPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); for (int i=0; i<256; ++i) { ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); } librados::ObjectIterator it = ioctx.objects_begin(); std::set saw_obj; std::set saw_pg; for (; it != ioctx.objects_end(); ++it) { std::cout << it->first << " " << it.get_pg_hash_position() << std::endl; saw_obj.insert(it->first); saw_pg.insert(it.get_pg_hash_position()); } std::cout << "saw " << saw_pg.size() << " pgs " << std::endl; // make sure they are 0..n for (unsigned i = 0; i < saw_pg.size(); ++i) ASSERT_TRUE(saw_pg.count(i)); } TEST_F(LibRadosList, ListObjectsStart) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); for (int i=0; i<16; ++i) { string n = stringify(i); ASSERT_EQ(0, rados_write(ioctx, n.c_str(), buf, sizeof(buf), 0)); } rados_list_ctx_t ctx; ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); std::map > pg_to_obj; const char *entry; while (rados_objects_list_next(ctx, &entry, NULL) == 0) { uint32_t pos = rados_objects_list_get_pg_hash_position(ctx); std::cout << entry << " " << pos << std::endl; pg_to_obj[pos].insert(entry); } rados_objects_list_close(ctx); std::map >::reverse_iterator p = pg_to_obj.rbegin(); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); while (p != pg_to_obj.rend()) { ASSERT_EQ((uint32_t)p->first, rados_objects_list_seek(ctx, p->first)); ASSERT_EQ(0, rados_objects_list_next(ctx, &entry, NULL)); std::cout << "have " << entry << " expect one of " << p->second << std::endl; ASSERT_TRUE(p->second.count(entry)); ++p; } rados_objects_list_close(ctx); } TEST_F(LibRadosListPP, ListObjectsStartPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); for (int i=0; i<16; ++i) { ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); } librados::ObjectIterator it = ioctx.objects_begin(); std::map > pg_to_obj; for (; it != ioctx.objects_end(); ++it) { std::cout << it->first << " " << it.get_pg_hash_position() << std::endl; pg_to_obj[it.get_pg_hash_position()].insert(it->first); } std::map >::reverse_iterator p = pg_to_obj.rbegin(); it = ioctx.objects_begin(p->first); while (p != pg_to_obj.rend()) { ASSERT_EQ((uint32_t)p->first, it.seek(p->first)); std::cout << "have " << it->first << " expect one of " << p->second << std::endl; ASSERT_TRUE(p->second.count(it->first)); ++p; } } TEST_F(LibRadosListEC, ListObjects) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); rados_list_ctx_t ctx; ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); const char *entry; bool foundit = false; while (rados_objects_list_next(ctx, &entry, NULL) != -ENOENT) { foundit = true; ASSERT_EQ(std::string(entry), "foo"); } ASSERT_TRUE(foundit); rados_objects_list_close(ctx); } TEST_F(LibRadosListECPP, ListObjectsPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ObjectIterator iter(ioctx.objects_begin()); bool foundit = false; while (iter != ioctx.objects_end()) { foundit = true; ASSERT_EQ((*iter).first, "foo"); ++iter; } ASSERT_TRUE(foundit); } TEST_F(LibRadosListECPP, ListObjectsTwicePP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ObjectIterator iter(ioctx.objects_begin()); bool foundit = false; while (iter != ioctx.objects_end()) { foundit = true; ASSERT_EQ((*iter).first, "foo"); ++iter; } ASSERT_TRUE(foundit); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); foundit = false; iter.seek(0); while (iter != ioctx.objects_end()) { foundit = true; ASSERT_EQ((*iter).first, "foo"); ++iter; } ASSERT_TRUE(foundit); } TEST_F(LibRadosListECPP, ListObjectsCopyIterPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); // make sure this is still valid after the original iterators are gone ObjectIterator iter3; { ObjectIterator iter(ioctx.objects_begin()); ObjectIterator iter2(iter); iter3 = iter2; ASSERT_EQ((*iter).first, "foo"); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); ASSERT_EQ(iter2->first, "foo"); ASSERT_EQ(iter3->first, "foo"); ++iter2; ASSERT_TRUE(iter2 == ioctx.objects_end()); } ASSERT_EQ(iter3->first, "foo"); iter3 = iter3; ASSERT_EQ(iter3->first, "foo"); ++iter3; ASSERT_TRUE(iter3 == ioctx.objects_end()); } TEST_F(LibRadosListECPP, ListObjectsEndIter) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ObjectIterator iter(ioctx.objects_begin()); ObjectIterator iter_end(ioctx.objects_end()); ObjectIterator iter_end2 = ioctx.objects_end(); ASSERT_TRUE(iter_end == iter_end2); ASSERT_TRUE(iter_end == ioctx.objects_end()); ASSERT_TRUE(iter_end2 == ioctx.objects_end()); ASSERT_EQ(iter->first, "foo"); ++iter; ASSERT_TRUE(iter == ioctx.objects_end()); ASSERT_TRUE(iter == iter_end); ASSERT_TRUE(iter == iter_end2); ObjectIterator iter2 = iter; ASSERT_TRUE(iter2 == ioctx.objects_end()); ASSERT_TRUE(iter2 == iter_end); ASSERT_TRUE(iter2 == iter_end2); } TEST_F(LibRadosListEC, ListObjectsNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7 rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_write(ioctx, "foo1", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "ns1"); ASSERT_EQ(0, rados_write(ioctx, "foo1", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_write(ioctx, "foo2", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo3", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "ns1"); ASSERT_EQ(0, rados_write(ioctx, "foo4", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo5", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "ns2"); ASSERT_EQ(0, rados_write(ioctx, "foo6", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo7", buf, sizeof(buf), 0)); std::set def, ns1, ns2; def.insert(std::string("foo1")); def.insert(std::string("foo2")); def.insert(std::string("foo3")); ns1.insert(std::string("foo1")); ns1.insert(std::string("foo4")); ns1.insert(std::string("foo5")); ns2.insert(std::string("foo6")); ns2.insert(std::string("foo7")); rados_list_ctx_t ctx; // Check default namespace "" rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); check_list(def, ctx); rados_objects_list_close(ctx); // Check default namespace "ns1" rados_ioctx_set_namespace(ioctx, "ns1"); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); check_list(ns1, ctx); rados_objects_list_close(ctx); // Check default namespace "ns2" rados_ioctx_set_namespace(ioctx, "ns2"); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); check_list(ns2, ctx); rados_objects_list_close(ctx); } TEST_F(LibRadosListECPP, ListObjectsPPNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7 ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0)); ioctx.set_namespace("ns1"); ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0)); ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.write("foo2", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo3", bl1, sizeof(buf), 0)); ioctx.set_namespace("ns1"); ASSERT_EQ(0, ioctx.write("foo4", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo5", bl1, sizeof(buf), 0)); ioctx.set_namespace("ns2"); ASSERT_EQ(0, ioctx.write("foo6", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo7", bl1, sizeof(buf), 0)); std::set def, ns1, ns2; def.insert(std::string("foo1")); def.insert(std::string("foo2")); def.insert(std::string("foo3")); ns1.insert(std::string("foo1")); ns1.insert(std::string("foo4")); ns1.insert(std::string("foo5")); ns2.insert(std::string("foo6")); ns2.insert(std::string("foo7")); ioctx.set_namespace(""); check_listpp(def, ioctx); ioctx.set_namespace("ns1"); check_listpp(ns1, ioctx); ioctx.set_namespace("ns2"); check_listpp(ns2, ioctx); } TEST_F(LibRadosListECPP, ListObjectsManyPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); for (int i=0; i<256; ++i) { ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); } librados::ObjectIterator it = ioctx.objects_begin(); std::set saw_obj; std::set saw_pg; for (; it != ioctx.objects_end(); ++it) { std::cout << it->first << " " << it.get_pg_hash_position() << std::endl; saw_obj.insert(it->first); saw_pg.insert(it.get_pg_hash_position()); } std::cout << "saw " << saw_pg.size() << " pgs " << std::endl; // make sure they are 0..n for (unsigned i = 0; i < saw_pg.size(); ++i) ASSERT_TRUE(saw_pg.count(i)); } TEST_F(LibRadosListEC, ListObjectsStart) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); for (int i=0; i<16; ++i) { string n = stringify(i); ASSERT_EQ(0, rados_write(ioctx, n.c_str(), buf, sizeof(buf), 0)); } rados_list_ctx_t ctx; ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); std::map > pg_to_obj; const char *entry; while (rados_objects_list_next(ctx, &entry, NULL) == 0) { uint32_t pos = rados_objects_list_get_pg_hash_position(ctx); std::cout << entry << " " << pos << std::endl; pg_to_obj[pos].insert(entry); } rados_objects_list_close(ctx); std::map >::reverse_iterator p = pg_to_obj.rbegin(); ASSERT_EQ(0, rados_objects_list_open(ioctx, &ctx)); while (p != pg_to_obj.rend()) { ASSERT_EQ((uint32_t)p->first, rados_objects_list_seek(ctx, p->first)); ASSERT_EQ(0, rados_objects_list_next(ctx, &entry, NULL)); std::cout << "have " << entry << " expect one of " << p->second << std::endl; ASSERT_TRUE(p->second.count(entry)); ++p; } rados_objects_list_close(ctx); } TEST_F(LibRadosListECPP, ListObjectsStartPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); for (int i=0; i<16; ++i) { ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0)); } librados::ObjectIterator it = ioctx.objects_begin(); std::map > pg_to_obj; for (; it != ioctx.objects_end(); ++it) { std::cout << it->first << " " << it.get_pg_hash_position() << std::endl; pg_to_obj[it.get_pg_hash_position()].insert(it->first); } std::map >::reverse_iterator p = pg_to_obj.rbegin(); it = ioctx.objects_begin(p->first); while (p != pg_to_obj.rend()) { ASSERT_EQ((uint32_t)p->first, it.seek(p->first)); std::cout << "have " << it->first << " expect one of " << p->second << std::endl; ASSERT_TRUE(p->second.count(it->first)); ++p; } } ceph-0.80.11/src/test/librados/misc.cc0000664000175100017510000004101112623076744021501 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "gtest/gtest.h" #include "mds/mdstypes.h" #include "include/buffer.h" #include "include/rbd_types.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/stringify.h" #include "global/global_context.h" #include "global/global_init.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include #include #include #include using namespace librados; using ceph::buffer; using std::map; using std::ostringstream; using std::string; typedef RadosTest LibRadosMisc; typedef RadosTestPP LibRadosMiscPP; TEST(LibRadosMiscVersion, Version) { int major, minor, extra; rados_version(&major, &minor, &extra); } TEST(LibRadosMiscVersion, VersionPP) { int major, minor, extra; Rados::version(&major, &minor, &extra); } TEST(LibRadosMiscConnectFailure, ConnectFailure) { rados_t cluster; char *id = getenv("CEPH_CLIENT_ID"); if (id) std::cerr << "Client id is: " << id << std::endl; ASSERT_EQ(0, rados_create(&cluster, NULL)); ASSERT_EQ(0, rados_conf_read_file(cluster, NULL)); ASSERT_EQ(0, rados_conf_parse_env(cluster, NULL)); ASSERT_EQ(0, rados_conf_set(cluster, "client_mount_timeout", "0.000001")); ASSERT_NE(0, rados_connect(cluster)); ASSERT_NE(0, rados_connect(cluster)); rados_shutdown(cluster); } TEST_F(LibRadosMisc, ClusterFSID) { char fsid[37]; ASSERT_EQ(-ERANGE, rados_cluster_fsid(cluster, fsid, sizeof(fsid) - 1)); ASSERT_EQ(sizeof(fsid) - 1, (size_t)rados_cluster_fsid(cluster, fsid, sizeof(fsid))); } TEST_F(LibRadosMiscPP, WaitOSDMapPP) { ASSERT_EQ(0, cluster.wait_for_latest_osdmap()); } static std::string read_key_from_tmap(IoCtx& ioctx, const std::string &obj, const std::string &key) { bufferlist bl; int r = ioctx.read(obj, bl, 0, 0); if (r <= 0) { ostringstream oss; oss << "ioctx.read(" << obj << ", bl, 0, 0) returned " << r; return oss.str(); } bufferlist::iterator p = bl.begin(); bufferlist header; map m; ::decode(header, p); ::decode(m, p); map::iterator i = m.find(key); if (i == m.end()) return ""; std::string retstring; ::decode(retstring, i->second); return retstring; } static std::string add_key_to_tmap(IoCtx &ioctx, const std::string &obj, const std::string &key, const std::string &val) { __u8 c = CEPH_OSD_TMAP_SET; bufferlist tmbl; ::encode(c, tmbl); ::encode(key, tmbl); bufferlist blbl; ::encode(val, blbl); ::encode(blbl, tmbl); int ret = ioctx.tmap_update(obj, tmbl); if (ret) { ostringstream oss; oss << "ioctx.tmap_update(obj=" << obj << ", key=" << key << ", val=" << val << ") failed with error " << ret; return oss.str(); } return ""; } static int remove_key_from_tmap(IoCtx &ioctx, const std::string &obj, const std::string &key) { __u8 c = CEPH_OSD_TMAP_RM; bufferlist tmbl; ::encode(c, tmbl); ::encode(key, tmbl); int ret = ioctx.tmap_update(obj, tmbl); if (ret) { ostringstream oss; oss << "ioctx.tmap_update(obj=" << obj << ", key=" << key << ") failed with error " << ret; } return ret; } TEST_F(LibRadosMiscPP, TmapUpdatePP) { // create tmap { __u8 c = CEPH_OSD_TMAP_CREATE; std::string my_tmap("my_tmap"); bufferlist emptybl; bufferlist tmbl; ::encode(c, tmbl); ::encode(my_tmap, tmbl); ::encode(emptybl, tmbl); ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl)); } ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key1", "val1")); ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key2", "val2")); // read key1 from the tmap ASSERT_EQ(string("val1"), read_key_from_tmap(ioctx, "foo", "key1")); // remove key1 from tmap ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "key1")); ASSERT_EQ(-ENOENT, remove_key_from_tmap(ioctx, "foo", "key1")); // key should be removed ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "key1")); } TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPP) { // create tmap { __u8 c = CEPH_OSD_TMAP_CREATE; std::string my_tmap("my_tmap"); bufferlist emptybl; bufferlist tmbl; ::encode(c, tmbl); ::encode(my_tmap, tmbl); ::encode(emptybl, tmbl); ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl)); } // good update { __u8 c = CEPH_OSD_TMAP_SET; bufferlist tmbl; ::encode(c, tmbl); ::encode("a", tmbl); bufferlist blbl; ::encode("old", blbl); ::encode(blbl, tmbl); ::encode(c, tmbl); ::encode("b", tmbl); ::encode(blbl, tmbl); ::encode(c, tmbl); ::encode("c", tmbl); ::encode(blbl, tmbl); ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl)); } // bad update { __u8 c = CEPH_OSD_TMAP_SET; bufferlist tmbl; ::encode(c, tmbl); ::encode("b", tmbl); bufferlist blbl; ::encode("new", blbl); ::encode(blbl, tmbl); ::encode(c, tmbl); ::encode("a", tmbl); ::encode(blbl, tmbl); ::encode(c, tmbl); ::encode("c", tmbl); ::encode(blbl, tmbl); ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl)); } // check ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "a")); ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "b")); ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "c")); ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "a")); ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a")); ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "b")); ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a")); } TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPutPP) { // create unsorted tmap string h("header"); bufferlist bl; ::encode(h, bl); uint32_t n = 3; ::encode(n, bl); ::encode(string("b"), bl); ::encode(string("bval"), bl); ::encode(string("a"), bl); ::encode(string("aval"), bl); ::encode(string("c"), bl); ::encode(string("cval"), bl); bufferlist orig = bl; // tmap_put steals bl content ASSERT_EQ(0, ioctx.tmap_put("foo", bl)); // check bufferlist newbl; ioctx.read("foo", newbl, orig.length(), 0); ASSERT_EQ(orig.contents_equal(newbl), false); } TEST_F(LibRadosMiscPP, Tmap2OmapPP) { // create tmap bufferlist hdr; hdr.append("header"); map omap; omap["1"].append("a"); omap["2"].append("b"); omap["3"].append("c"); { bufferlist bl; ::encode(hdr, bl); ::encode(omap, bl); ASSERT_EQ(0, ioctx.tmap_put("foo", bl)); } // convert tmap to omap ASSERT_EQ(0, ioctx.tmap_to_omap("foo", false)); // if tmap was truncated ? { uint64_t size; time_t mtime; ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(0U, size); } // if 'nullok' works ASSERT_EQ(0, ioctx.tmap_to_omap("foo", true)); ASSERT_LE(ioctx.tmap_to_omap("foo", false), 0); { // read omap bufferlist got; map m; ObjectReadOperation o; o.omap_get_header(&got, NULL); o.omap_get_vals("", 1024, &m, NULL); ASSERT_EQ(0, ioctx.operate("foo", &o, NULL)); // compare header ASSERT_TRUE(hdr.contents_equal(got)); // compare values ASSERT_EQ(omap.size(), m.size()); bool same = true; for (map::iterator p = omap.begin(); p != omap.end(); ++p) { map::iterator q = m.find(p->first); if (q == m.end() || !p->second.contents_equal(q->second)) { same = false; break; } } ASSERT_TRUE(same); } } TEST_F(LibRadosMisc, Exec) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); char buf2[512]; int res = rados_exec(ioctx, "foo", "rbd", "get_all_features", NULL, 0, buf2, sizeof(buf2)); ASSERT_GT(res, 0); bufferlist bl; bl.append(buf2, res); bufferlist::iterator iter = bl.begin(); uint64_t all_features; ::decode(all_features, iter); // make sure *some* features are specified; don't care which ones ASSERT_NE(all_features, 0); } TEST_F(LibRadosMiscPP, ExecPP) { bufferlist bl; ASSERT_EQ(0, ioctx.write("foo", bl, 0, 0)); bufferlist bl2, out; int r = ioctx.exec("foo", "rbd", "get_all_features", bl2, out); ASSERT_EQ(0, r); bufferlist::iterator iter = out.begin(); uint64_t all_features; ::decode(all_features, iter); // make sure *some* features are specified; don't care which ones ASSERT_NE(all_features, 0); } TEST_F(LibRadosMiscPP, Operate1PP) { ObjectWriteOperation o; { bufferlist bl; o.write(0, bl); } std::string val1("val1"); { bufferlist bl; bl.append(val1.c_str(), val1.size() + 1); o.setxattr("key1", bl); o.omap_clear(); // shouldn't affect attrs! } ASSERT_EQ(0, ioctx.operate("foo", &o)); ObjectWriteOperation empty; ASSERT_EQ(0, ioctx.operate("foo", &empty)); { bufferlist bl; ASSERT_GT(ioctx.getxattr("foo", "key1", bl), 0); ASSERT_EQ(0, strcmp(bl.c_str(), val1.c_str())); } ObjectWriteOperation o2; { bufferlist bl; bl.append(val1); o2.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl); o2.rmxattr("key1"); } ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o2)); ObjectWriteOperation o3; { bufferlist bl; bl.append(val1); o3.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl); } ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o3)); } TEST_F(LibRadosMiscPP, Operate2PP) { ObjectWriteOperation o; { bufferlist bl; bl.append("abcdefg"); o.write(0, bl); } std::string val1("val1"); { bufferlist bl; bl.append(val1.c_str(), val1.size() + 1); o.setxattr("key1", bl); o.truncate(0); } ASSERT_EQ(0, ioctx.operate("foo", &o)); uint64_t size; time_t mtime; ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(0U, size); } TEST_F(LibRadosMiscPP, BigObjectPP) { bufferlist bl; bl.append("abcdefg"); ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0)); { ObjectWriteOperation o; o.truncate(500000000000ull); ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); } { ObjectWriteOperation o; o.zero(500000000000ull, 1); ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); } { ObjectWriteOperation o; o.zero(1, 500000000000ull); ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); } { ObjectWriteOperation o; o.zero(500000000000ull, 500000000000ull); ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); } #ifdef __LP64__ // this test only works on 64-bit platforms ASSERT_EQ(-EFBIG, ioctx.write("foo", bl, bl.length(), 500000000000ull)); #endif } void set_completion_complete(rados_completion_t cb, void *arg) { bool *my_aio_complete = (bool*)arg; *my_aio_complete = true; } TEST_F(LibRadosMiscPP, AioOperatePP) { bool my_aio_complete = false; AioCompletion *my_completion = cluster.aio_create_completion( (void*)&my_aio_complete, set_completion_complete, NULL); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); ObjectWriteOperation o; { bufferlist bl; o.write(0, bl); } std::string val1("val1"); { bufferlist bl; bl.append(val1.c_str(), val1.size() + 1); o.setxattr("key1", bl); bufferlist bl2; char buf2[1024]; memset(buf2, 0xdd, sizeof(buf2)); bl2.append(buf2, sizeof(buf2)); o.append(bl2); } ASSERT_EQ(0, ioctx.aio_operate("foo", my_completion, &o)); ASSERT_EQ(0, my_completion->wait_for_complete_and_cb()); ASSERT_EQ(my_aio_complete, true); uint64_t size; time_t mtime; ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(1024U, size); } TEST_F(LibRadosMiscPP, CloneRangePP) { char buf[64]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); ioctx.locator_set_key("foo"); ASSERT_EQ(0, ioctx.clone_range("bar", 0, "foo", 0, sizeof(buf))); bufferlist bl2; ASSERT_EQ(sizeof(buf), (size_t)ioctx.read("bar", bl2, sizeof(buf), 0)); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); } TEST_F(LibRadosMisc, CloneRange) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "src", buf, sizeof(buf), 0)); rados_ioctx_locator_set_key(ioctx, "src"); ASSERT_EQ(0, rados_clone_range(ioctx, "dst", 0, "src", 0, sizeof(buf))); char buf2[sizeof(buf)]; memset(buf2, 0, sizeof(buf2)); ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "dst", buf2, sizeof(buf2), 0)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); } TEST_F(LibRadosMiscPP, AssertExistsPP) { char buf[64]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ObjectWriteOperation op; op.assert_exists(); op.write(0, bl); ASSERT_EQ(-ENOENT, ioctx.operate("asdffoo", &op)); ASSERT_EQ(0, ioctx.create("asdffoo", true)); ASSERT_EQ(0, ioctx.operate("asdffoo", &op)); ASSERT_EQ(-EEXIST, ioctx.create("asdffoo", true)); } TEST_F(LibRadosMiscPP, BigAttrPP) { char buf[64]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.create("foo", true)); bufferlist got; cout << "osd_max_attr_size = " << g_conf->osd_max_attr_size << std::endl; if (g_conf->osd_max_attr_size) { bl.clear(); got.clear(); bl.append(buffer::create(g_conf->osd_max_attr_size)); ASSERT_EQ(0, ioctx.setxattr("foo", "one", bl)); ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", "one", got)); ASSERT_TRUE(bl.contents_equal(got)); bl.clear(); bl.append(buffer::create(g_conf->osd_max_attr_size+1)); ASSERT_EQ(-EFBIG, ioctx.setxattr("foo", "one", bl)); } else { cout << "osd_max_attr_size == 0; skipping test" << std::endl; } for (int i=0; i<1000; i++) { bl.clear(); got.clear(); bl.append(buffer::create(MIN(g_conf->osd_max_attr_size, 1024))); char n[10]; snprintf(n, sizeof(n), "a%d", i); ASSERT_EQ(0, ioctx.setxattr("foo", n, bl)); ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", n, got)); ASSERT_TRUE(bl.contents_equal(got)); } } TEST_F(LibRadosMiscPP, CopyPP) { bufferlist bl, x; bl.append("hi there"); x.append("bar"); // small object bufferlist blc = bl; bufferlist xc = x; ASSERT_EQ(0, ioctx.write_full("foo", blc)); ASSERT_EQ(0, ioctx.setxattr("foo", "myattr", xc)); version_t uv = ioctx.get_last_version(); { // pass future version ObjectWriteOperation op; op.copy_from("foo", ioctx, uv + 1); ASSERT_EQ(-EOVERFLOW, ioctx.operate("foo.copy", &op)); } { // pass old version ObjectWriteOperation op; op.copy_from("foo", ioctx, uv - 1); ASSERT_EQ(-ERANGE, ioctx.operate("foo.copy", &op)); } { ObjectWriteOperation op; op.copy_from("foo", ioctx, uv); ASSERT_EQ(0, ioctx.operate("foo.copy", &op)); bufferlist bl2, x2; ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy", bl2, 10000, 0)); ASSERT_TRUE(bl.contents_equal(bl2)); ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2)); ASSERT_TRUE(x.contents_equal(x2)); } // small object without a version { ObjectWriteOperation op; op.copy_from("foo", ioctx, 0); ASSERT_EQ(0, ioctx.operate("foo.copy2", &op)); bufferlist bl2, x2; ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy2", bl2, 10000, 0)); ASSERT_TRUE(bl.contents_equal(bl2)); ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2)); ASSERT_TRUE(x.contents_equal(x2)); } // do a big object bl.append(buffer::create(g_conf->osd_copyfrom_max_chunk * 3)); bl.zero(); bl.append("tail"); blc = bl; xc = x; ASSERT_EQ(0, ioctx.write_full("big", blc)); ASSERT_EQ(0, ioctx.setxattr("big", "myattr", xc)); { ObjectWriteOperation op; op.copy_from("big", ioctx, ioctx.get_last_version()); ASSERT_EQ(0, ioctx.operate("big.copy", &op)); bufferlist bl2, x2; ASSERT_EQ((int)bl.length(), ioctx.read("big.copy", bl2, bl.length(), 0)); ASSERT_TRUE(bl.contents_equal(bl2)); ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2)); ASSERT_TRUE(x.contents_equal(x2)); } { ObjectWriteOperation op; op.copy_from("big", ioctx, 0); ASSERT_EQ(0, ioctx.operate("big.copy2", &op)); bufferlist bl2, x2; ASSERT_EQ((int)bl.length(), ioctx.read("big.copy2", bl2, bl.length(), 0)); ASSERT_TRUE(bl.contents_equal(bl2)); ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2)); ASSERT_TRUE(x.contents_equal(x2)); } } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/librados/stat.cc0000664000175100017510000001712212623076744021527 0ustar jenkins-buildjenkins-build#include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include #include #include "gtest/gtest.h" using namespace librados; typedef RadosTest LibRadosStat; typedef RadosTestPP LibRadosStatPP; typedef RadosTestEC LibRadosStatEC; typedef RadosTestECPP LibRadosStatECPP; TEST_F(LibRadosStat, Stat) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); uint64_t size; time_t mtime; ASSERT_EQ(0, rados_stat(ioctx, "foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime)); } TEST_F(LibRadosStatPP, StatPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); uint64_t size; time_t mtime; ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime)); } TEST_F(LibRadosStat, StatNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo2", buf, sizeof(buf), 0)); char buf2[64]; memset(buf2, 0xcc, sizeof(buf2)); rados_ioctx_set_namespace(ioctx, "nspace"); ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0)); uint64_t size; time_t mtime; rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_stat(ioctx, "foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime)); rados_ioctx_set_namespace(ioctx, "nspace"); ASSERT_EQ(0, rados_stat(ioctx, "foo", &size, &mtime)); ASSERT_EQ(sizeof(buf2), size); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime)); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "foo2", &size, &mtime)); } TEST_F(LibRadosStatPP, StatPPNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo2", bl, sizeof(buf), 0)); char buf2[64]; memset(buf2, 0xbb, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); ioctx.set_namespace("nspace"); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0)); uint64_t size; time_t mtime; ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime)); ioctx.set_namespace("nspace"); ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(sizeof(buf2), size); ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime)); ASSERT_EQ(-ENOENT, ioctx.stat("foo2", &size, &mtime)); } TEST_F(LibRadosStat, ClusterStat) { struct rados_cluster_stat_t result; ASSERT_EQ(0, rados_cluster_stat(cluster, &result)); } TEST_F(LibRadosStatPP, ClusterStatPP) { cluster_stat_t cstat; ASSERT_EQ(0, cluster.cluster_stat(cstat)); } TEST_F(LibRadosStat, PoolStat) { char buf[128]; char actual_pool_name[80]; unsigned l = rados_ioctx_get_pool_name(ioctx, actual_pool_name, sizeof(actual_pool_name)); ASSERT_EQ(strlen(actual_pool_name), l); ASSERT_EQ(0, strcmp(actual_pool_name, pool_name.c_str())); memset(buf, 0xff, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); struct rados_pool_stat_t stats; memset(&stats, 0, sizeof(stats)); ASSERT_EQ(0, rados_ioctx_pool_stat(ioctx, &stats)); } TEST_F(LibRadosStatPP, PoolStatPP) { std::string n = ioctx.get_pool_name(); ASSERT_EQ(n, pool_name); char buf[128]; memset(buf, 0xff, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); std::list v; std::map stats; ASSERT_EQ(0, cluster.get_pool_stats(v, stats)); } TEST_F(LibRadosStatEC, Stat) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); uint64_t size; time_t mtime; ASSERT_EQ(0, rados_stat(ioctx, "foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime)); } TEST_F(LibRadosStatECPP, StatPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); uint64_t size; time_t mtime; ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime)); } TEST_F(LibRadosStatEC, StatNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_write(ioctx, "foo2", buf, sizeof(buf), 0)); char buf2[64]; memset(buf2, 0xcc, sizeof(buf2)); rados_ioctx_set_namespace(ioctx, "nspace"); ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0)); uint64_t size; time_t mtime; rados_ioctx_set_namespace(ioctx, ""); ASSERT_EQ(0, rados_stat(ioctx, "foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime)); rados_ioctx_set_namespace(ioctx, "nspace"); ASSERT_EQ(0, rados_stat(ioctx, "foo", &size, &mtime)); ASSERT_EQ(sizeof(buf2), size); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime)); ASSERT_EQ(-ENOENT, rados_stat(ioctx, "foo2", &size, &mtime)); } TEST_F(LibRadosStatECPP, StatPPNS) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo2", bl, sizeof(buf), 0)); char buf2[64]; memset(buf2, 0xbb, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); ioctx.set_namespace("nspace"); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0)); uint64_t size; time_t mtime; ioctx.set_namespace(""); ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(sizeof(buf), size); ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime)); ioctx.set_namespace("nspace"); ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); ASSERT_EQ(sizeof(buf2), size); ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime)); ASSERT_EQ(-ENOENT, ioctx.stat("foo2", &size, &mtime)); } TEST_F(LibRadosStatEC, ClusterStat) { struct rados_cluster_stat_t result; ASSERT_EQ(0, rados_cluster_stat(cluster, &result)); } TEST_F(LibRadosStatECPP, ClusterStatPP) { cluster_stat_t cstat; ASSERT_EQ(0, cluster.cluster_stat(cstat)); } TEST_F(LibRadosStatEC, PoolStat) { char buf[128]; char actual_pool_name[80]; unsigned l = rados_ioctx_get_pool_name(ioctx, actual_pool_name, sizeof(actual_pool_name)); ASSERT_EQ(strlen(actual_pool_name), l); ASSERT_EQ(0, strcmp(actual_pool_name, pool_name.c_str())); memset(buf, 0xff, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); struct rados_pool_stat_t stats; memset(&stats, 0, sizeof(stats)); ASSERT_EQ(0, rados_ioctx_pool_stat(ioctx, &stats)); } TEST_F(LibRadosStatECPP, PoolStatPP) { std::string n = ioctx.get_pool_name(); ASSERT_EQ(n, pool_name); char buf[128]; memset(buf, 0xff, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); std::list v; std::map stats; ASSERT_EQ(0, cluster.get_pool_stats(v, stats)); } ceph-0.80.11/src/test/librados/pool.cc0000664000175100017510000000711412623076744021525 0ustar jenkins-buildjenkins-build#include "include/rados/librados.h" #include "test/librados/test.h" #include "gtest/gtest.h" #include #include #define POOL_LIST_BUF_SZ 32768 TEST(LibRadosPools, PoolList) { char pool_list_buf[POOL_LIST_BUF_SZ]; char *buf = pool_list_buf; rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); ASSERT_LT(rados_pool_list(cluster, buf, POOL_LIST_BUF_SZ), POOL_LIST_BUF_SZ); bool found_pool = false; while (buf[0] != '\0') { if ((found_pool == false) && (strcmp(buf, pool_name.c_str()) == 0)) { found_pool = true; } buf += strlen(buf) + 1; } ASSERT_EQ(found_pool, true); // make sure we honor the buffer size limit buf = pool_list_buf; memset(buf, 0, POOL_LIST_BUF_SZ); ASSERT_LT(rados_pool_list(cluster, buf, 20), POOL_LIST_BUF_SZ); ASSERT_NE(0, buf[0]); // include at least one pool name ASSERT_EQ(0, buf[20]); // but don't touch the stopping point ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } int64_t rados_pool_lookup(rados_t cluster, const char *pool_name); TEST(LibRadosPools, PoolLookup) { rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); ASSERT_LT(0, rados_pool_lookup(cluster, pool_name.c_str())); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosPools, PoolLookup2) { rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); int64_t pool_id = rados_pool_lookup(cluster, pool_name.c_str()); ASSERT_GT(pool_id, 0); rados_ioctx_t ioctx; ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx)); int64_t pool_id2 = rados_ioctx_get_id(ioctx); ASSERT_EQ(pool_id, pool_id2); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosPools, PoolDelete) { rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); ASSERT_EQ(0, rados_pool_delete(cluster, pool_name.c_str())); ASSERT_GT(0, rados_pool_lookup(cluster, pool_name.c_str())); ASSERT_EQ(0, rados_pool_create(cluster, pool_name.c_str())); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosPools, PoolCreateDelete) { rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); std::string n = pool_name + "abc123"; ASSERT_EQ(0, rados_pool_create(cluster, n.c_str())); ASSERT_EQ(-EEXIST, rados_pool_create(cluster, n.c_str())); ASSERT_EQ(0, rados_pool_delete(cluster, n.c_str())); ASSERT_EQ(-ENOENT, rados_pool_delete(cluster, n.c_str())); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosPools, PoolCreateWithCrushRule) { rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); std::string pool2_name = get_temp_pool_name(); ASSERT_EQ(0, rados_pool_create_with_crush_rule(cluster, pool2_name.c_str(), 0)); ASSERT_EQ(0, rados_pool_delete(cluster, pool2_name.c_str())); std::string pool3_name = get_temp_pool_name(); ASSERT_EQ(0, rados_pool_create_with_all(cluster, pool3_name.c_str(), 456ull, 0)); rados_ioctx_t ioctx; ASSERT_EQ(0, rados_ioctx_create(cluster, pool3_name.c_str(), &ioctx)); uint64_t auid; ASSERT_EQ(0, rados_ioctx_pool_get_auid(ioctx, &auid)); ASSERT_EQ(456ull, auid); ASSERT_EQ(0, rados_pool_delete(cluster, pool3_name.c_str())); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } ceph-0.80.11/src/test/librados/cls.cc0000664000175100017510000000167612623076744021344 0ustar jenkins-buildjenkins-build#include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include "gtest/gtest.h" #include #include #include #include using namespace librados; using ceph::buffer; using std::map; using std::ostringstream; using std::string; TEST(LibRadosCls, DNE) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); // create an object string oid = "foo"; bufferlist bl; ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0)); // call a bogus class ASSERT_EQ(-EOPNOTSUPP, ioctx.exec(oid, "doesnotexistasdfasdf", "method", bl, bl)); // call a bogus method on existent class ASSERT_EQ(-EOPNOTSUPP, ioctx.exec(oid, "lock", "doesnotexistasdfasdfasdf", bl, bl)); ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } ceph-0.80.11/src/test/librados/c_write_operations.cc0000664000175100017510000001117712623076744024457 0ustar jenkins-buildjenkins-build// Tests for the C API coverage of atomic write operations #include "include/rados/librados.h" #include "test/librados/test.h" #include "gtest/gtest.h" TEST(LibradosCWriteOps, NewDelete) { rados_write_op_t op = rados_create_write_op(); ASSERT_TRUE(op); rados_release_write_op(op); } TEST(LibRadosCWriteOps, assertExists) { rados_t cluster; rados_ioctx_t ioctx; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rados_write_op_t op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_assert_exists(op); // -2, ENOENT ASSERT_EQ(-2, rados_write_op_operate(op, ioctx, "test", NULL, 0)); rados_release_write_op(op); rados_write_op_t op2 = rados_create_write_op(); ASSERT_TRUE(op2); rados_write_op_assert_exists(op2); rados_completion_t completion; ASSERT_EQ(0, rados_aio_create_completion(NULL, NULL, NULL, &completion)); ASSERT_EQ(0, rados_aio_write_op_operate(op2, ioctx, completion, "test", NULL, 0)); rados_aio_wait_for_complete(completion); ASSERT_EQ(-2, rados_aio_get_return_value(completion)); rados_ioctx_destroy(ioctx); rados_release_write_op(op2); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosCWriteOps, Xattrs) { rados_t cluster; rados_ioctx_t ioctx; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); // Create an object with an xattr rados_write_op_t op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_create(op, LIBRADOS_CREATE_EXCLUSIVE, NULL); rados_write_op_setxattr(op, "key", "value", 5); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "test", NULL, 0)); rados_release_write_op(op); // Check that xattr exists, if it does, delete it. op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_create(op, LIBRADOS_CREATE_IDEMPOTENT, NULL); rados_write_op_cmpxattr(op, "key", LIBRADOS_CMPXATTR_OP_EQ, "value", 5); rados_write_op_rmxattr(op, "key"); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "test", NULL, 0)); rados_release_write_op(op); // Check the xattr exits, if it does, add it again (will fail) with -125 // (ECANCELED) op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_cmpxattr(op, "key", LIBRADOS_CMPXATTR_OP_EQ, "value", 5); rados_write_op_setxattr(op, "key", "value", 5); ASSERT_EQ(-125, rados_write_op_operate(op, ioctx, "test", NULL, 0)); rados_release_write_op(op); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosCWriteOps, Write) { rados_t cluster; rados_ioctx_t ioctx; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); // Create an object, write and write full to it rados_write_op_t op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_create(op, LIBRADOS_CREATE_EXCLUSIVE, NULL); rados_write_op_write(op, "four", 4, 0); rados_write_op_write_full(op, "hi", 2); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "test", NULL, 0)); char hi[4]; ASSERT_EQ(2, rados_read(ioctx, "test", hi, 4, 0)); rados_release_write_op(op); // Truncate and append op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_truncate(op, 1); rados_write_op_append(op, "hi", 2); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "test", NULL, 0)); ASSERT_EQ(3, rados_read(ioctx, "test", hi, 4, 0)); rados_release_write_op(op); // zero and remove op = rados_create_write_op(); ASSERT_TRUE(op); rados_write_op_zero(op, 0, 3); rados_write_op_remove(op); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "test", NULL, 0)); // ENOENT ASSERT_EQ(-2, rados_read(ioctx, "test", hi, 4, 0)); rados_release_write_op(op); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } TEST(LibRadosCWriteOps, Exec) { rados_t cluster; rados_ioctx_t ioctx; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); int rval = 1; rados_write_op_t op = rados_create_write_op(); rados_write_op_exec(op, "hello", "record_hello", "test", 4, &rval); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, "test", NULL, 0)); rados_release_write_op(op); ASSERT_EQ(0, rval); char hi[100]; ASSERT_EQ(12, rados_read(ioctx, "test", hi, 100, 0)); hi[12] = '\0'; ASSERT_EQ(0, strcmp("Hello, test!", hi)); rados_ioctx_destroy(ioctx); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } ceph-0.80.11/src/test/librados/TestCase.cc0000664000175100017510000001541712623076744022274 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "test/librados/test.h" #include "test/librados/TestCase.h" using namespace librados; std::string RadosTest::pool_name; std::string RadosTest::nspace; rados_t RadosTest::s_cluster = NULL; void RadosTest::SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &s_cluster)); } void RadosTest::TearDownTestCase() { ASSERT_EQ(0, destroy_one_pool(pool_name, &s_cluster)); } void RadosTest::SetUp() { cluster = RadosTest::s_cluster; ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx)); nspace = get_temp_pool_name(); rados_ioctx_set_namespace(ioctx, nspace.c_str()); ASSERT_FALSE(rados_ioctx_pool_requires_alignment(ioctx)); } void RadosTest::TearDown() { cleanup_default_namespace(ioctx); rados_ioctx_destroy(ioctx); } void RadosTest::cleanup_default_namespace(rados_ioctx_t ioctx) { // remove all objects from the default namespace to avoid polluting // other tests rados_ioctx_set_namespace(ioctx, ""); rados_list_ctx_t list_ctx; ASSERT_EQ(0, rados_objects_list_open(ioctx, &list_ctx)); int r; const char *entry = NULL; const char *key = NULL; while ((r = rados_objects_list_next(list_ctx, &entry, &key)) != -ENOENT) { ASSERT_EQ(0, r); rados_ioctx_locator_set_key(ioctx, key); ASSERT_EQ(0, rados_remove(ioctx, entry)); } rados_objects_list_close(list_ctx); } std::string RadosTestPP::pool_name; Rados RadosTestPP::s_cluster; void RadosTestPP::SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster)); } void RadosTestPP::TearDownTestCase() { ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster)); } void RadosTestPP::SetUp() { ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx)); ns = get_temp_pool_name(); ioctx.set_namespace(ns); ASSERT_FALSE(ioctx.pool_requires_alignment()); } void RadosTestPP::TearDown() { cleanup_default_namespace(ioctx); ioctx.close(); } void RadosTestPP::cleanup_default_namespace(librados::IoCtx ioctx) { // remove all objects from the default namespace to avoid polluting // other tests ioctx.set_namespace(""); for (ObjectIterator it = ioctx.objects_begin(); it != ioctx.objects_end(); ++it) { ioctx.locator_set_key(it->second); ObjectWriteOperation op; op.remove(); librados::AioCompletion *completion = s_cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate(it->first, completion, &op, librados::OPERATION_IGNORE_CACHE)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } } std::string RadosTestParamPP::pool_name; std::string RadosTestParamPP::cache_pool_name; Rados RadosTestParamPP::s_cluster; void RadosTestParamPP::SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster)); } void RadosTestParamPP::TearDownTestCase() { if (cache_pool_name.length()) { // tear down tiers bufferlist inbl; ASSERT_EQ(0, s_cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, s_cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, s_cluster.mon_command( "{\"prefix\": \"osd pool delete\", \"pool\": \"" + cache_pool_name + "\", \"pool2\": \"" + cache_pool_name + "\", \"sure\": \"--yes-i-really-really-mean-it\"}", inbl, NULL, NULL)); cache_pool_name = ""; } ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster)); } void RadosTestParamPP::SetUp() { if (strcmp(GetParam(), "cache") == 0 && cache_pool_name.empty()) { cache_pool_name = get_temp_pool_name(); bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd pool create\", \"pool\": \"" + cache_pool_name + "\", \"pg_num\": 4}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); cluster.wait_for_latest_osdmap(); } ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx)); ns = get_temp_pool_name(); ioctx.set_namespace(ns); ASSERT_FALSE(ioctx.pool_requires_alignment()); } void RadosTestParamPP::TearDown() { cleanup_default_namespace(ioctx); ioctx.close(); } void RadosTestParamPP::cleanup_default_namespace(librados::IoCtx ioctx) { // remove all objects from the default namespace to avoid polluting // other tests ioctx.set_namespace(""); for (ObjectIterator it = ioctx.objects_begin(); it != ioctx.objects_end(); ++it) { ioctx.locator_set_key(it->second); ASSERT_EQ(0, ioctx.remove(it->first)); } } std::string RadosTestEC::pool_name; rados_t RadosTestEC::s_cluster = NULL; void RadosTestEC::SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_ec_pool(pool_name, &s_cluster)); } void RadosTestEC::TearDownTestCase() { ASSERT_EQ(0, destroy_one_ec_pool(pool_name, &s_cluster)); } void RadosTestEC::SetUp() { cluster = RadosTestEC::s_cluster; ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx)); std::string nspace = get_temp_pool_name(); rados_ioctx_set_namespace(ioctx, nspace.c_str()); ASSERT_TRUE(rados_ioctx_pool_requires_alignment(ioctx)); alignment = rados_ioctx_pool_required_alignment(ioctx); ASSERT_NE((unsigned)0, alignment); } void RadosTestEC::TearDown() { cleanup_default_namespace(ioctx); rados_ioctx_destroy(ioctx); } std::string RadosTestECPP::pool_name; Rados RadosTestECPP::s_cluster; void RadosTestECPP::SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster)); } void RadosTestECPP::TearDownTestCase() { ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster)); } void RadosTestECPP::SetUp() { ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx)); ns = get_temp_pool_name(); ioctx.set_namespace(ns); ASSERT_TRUE(ioctx.pool_requires_alignment()); alignment = ioctx.pool_required_alignment(); ASSERT_NE((unsigned)0, alignment); } void RadosTestECPP::TearDown() { cleanup_default_namespace(ioctx); ioctx.close(); } ceph-0.80.11/src/test/librados/cmd.cc0000664000175100017510000001447612623076744021330 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "mds/mdstypes.h" #include "include/buffer.h" #include "include/rbd_types.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/stringify.h" #include "test/librados/test.h" #include "common/Cond.h" #include "gtest/gtest.h" #include #include #include #include using namespace librados; using ceph::buffer; using std::map; using std::ostringstream; using std::string; TEST(LibRadosCmd, MonDescribe) { rados_t cluster; ASSERT_EQ("", connect_cluster(&cluster)); char *buf, *st; size_t buflen, stlen; char *cmd[2]; cmd[1] = NULL; cmd[0] = (char *)"{\"prefix\":\"get_command_descriptions\"}"; ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); ASSERT_LT(0u, buflen); rados_buffer_free(buf); rados_buffer_free(st); cmd[0] = (char *)"get_command_descriptions"; ASSERT_EQ(-EINVAL, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); rados_buffer_free(buf); rados_buffer_free(st); cmd[0] = (char *)"asdfqwer"; ASSERT_EQ(-EINVAL, rados_mon_command(cluster, (const char **)cmd, 1, "{}", 2, &buf, &buflen, &st, &stlen)); rados_buffer_free(buf); rados_buffer_free(st); cmd[0] = (char *)"{\"prefix\":\"mon_status\"}"; ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); ASSERT_LT(0u, buflen); //ASSERT_LT(0u, stlen); rados_buffer_free(buf); rados_buffer_free(st); rados_shutdown(cluster); } TEST(LibRadosCmd, MonDescribePP) { Rados cluster; ASSERT_EQ("", connect_cluster_pp(cluster)); bufferlist inbl, outbl; string outs; ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"get_command_descriptions\"}", inbl, &outbl, &outs)); ASSERT_LT(0u, outbl.length()); ASSERT_LE(0u, outs.length()); cluster.shutdown(); } TEST(LibRadosCmd, OSDCmd) { rados_t cluster; ASSERT_EQ("", connect_cluster(&cluster)); int r; char *buf, *st; size_t buflen, stlen; char *cmd[2]; cmd[1] = NULL; // note: tolerate NXIO here in case the cluster is thrashing out underneath us. cmd[0] = (char *)"asdfasdf"; r = rados_osd_command(cluster, 0, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen); ASSERT_TRUE(r == -22 || r == -ENXIO); cmd[0] = (char *)"version"; r = rados_osd_command(cluster, 0, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen); ASSERT_TRUE(r == -22 || r == -ENXIO); cmd[0] = (char *)"{\"prefix\":\"version\"}"; r = rados_osd_command(cluster, 0, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen); ASSERT_TRUE((r == 0 && buflen > 0) || (r == -ENXIO && buflen == 0)); rados_buffer_free(buf); rados_buffer_free(st); rados_shutdown(cluster); } TEST(LibRadosCmd, PGCmd) { rados_t cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool(pool_name, &cluster)); char *buf, *st; size_t buflen, stlen; char *cmd[2]; cmd[1] = NULL; int64_t poolid = rados_pool_lookup(cluster, pool_name.c_str()); ASSERT_LT(0, poolid); string pgid = stringify(poolid) + ".0"; cmd[0] = (char *)"asdfasdf"; // note: tolerate NXIO here in case the cluster is thrashing out underneath us. int r = rados_pg_command(cluster, pgid.c_str(), (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen); ASSERT_TRUE(r == -22 || r == -ENXIO); // make sure the pg exists on the osd before we query it rados_ioctx_t io; rados_ioctx_create(cluster, pool_name.c_str(), &io); for (int i=0; i<100; i++) { string oid = "obj" + stringify(i); ASSERT_EQ(-ENOENT, rados_stat(io, oid.c_str(), NULL, NULL)); } rados_ioctx_destroy(io); string qstr = "{\"prefix\":\"pg\", \"cmd\":\"query\", \"pgid\":\"" + pgid + "\"}"; cmd[0] = (char *)qstr.c_str(); // note: tolerate ENOENT/ENXIO here if hte osd is thrashing out underneath us r = rados_pg_command(cluster, pgid.c_str(), (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen); ASSERT_TRUE(r == 0 || r == -ENOENT || r == -ENXIO); ASSERT_LT(0u, buflen); rados_buffer_free(buf); rados_buffer_free(st); ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster)); } struct Log { list log; Cond cond; Mutex lock; Log() : lock("l::lock") {} bool contains(string str) { Mutex::Locker l(lock); for (list::iterator p = log.begin(); p != log.end(); ++p) { if (p->find(str) != std::string::npos) return true; } return false; } }; void log_cb(void *arg, const char *line, const char *who, uint64_t stampsec, uint64_t stamp_nsec, uint64_t seq, const char *level, const char *msg) { Log *l = static_cast(arg); Mutex::Locker locker(l->lock); l->log.push_back(line); l->cond.Signal(); cout << "got: " << line << std::endl; } TEST(LibRadosCmd, WatchLog) { rados_t cluster; ASSERT_EQ("", connect_cluster(&cluster)); char *buf, *st; char *cmd[2]; cmd[1] = NULL; size_t buflen, stlen; Log l; ASSERT_EQ(0, rados_monitor_log(cluster, "info", log_cb, &l)); cmd[0] = (char *)"{\"prefix\":\"log\", \"logtext\":[\"onexx\"]}"; ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); for (int i=0; !l.contains("onexx"); i++) { ASSERT_TRUE(i<100); sleep(1); } ASSERT_TRUE(l.contains("onexx")); /* changing the subscribe level is currently broken. cmd[0] = (char *)"{\"prefix\":\"log\", \"logtext\":[\"twoxx\"]}"; ASSERT_EQ(0, rados_monitor_log(cluster, "err", log_cb, &l)); ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); sleep(2); ASSERT_FALSE(l.contains("twoxx")); */ ASSERT_EQ(0, rados_monitor_log(cluster, "info", log_cb, &l)); cmd[0] = (char *)"{\"prefix\":\"log\", \"logtext\":[\"threexx\"]}"; ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); for (int i=0; !l.contains("threexx"); i++) { ASSERT_TRUE(i<100); sleep(1); } ASSERT_EQ(0, rados_monitor_log(cluster, "info", NULL, NULL)); cmd[0] = (char *)"{\"prefix\":\"log\", \"logtext\":[\"fourxx\"]}"; ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen)); sleep(2); ASSERT_FALSE(l.contains("fourxx")); rados_shutdown(cluster); } ceph-0.80.11/src/test/librados/test.h0000664000175100017510000000273512623076744021401 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_TEST_RADOS_API_TEST_H #define CEPH_TEST_RADOS_API_TEST_H #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include #include std::string get_temp_pool_name(); std::string create_one_pool(const std::string &pool_name, rados_t *cluster); std::string create_one_ec_pool(const std::string &pool_name, rados_t *cluster); std::string create_one_pool_pp(const std::string &pool_name, librados::Rados &cluster); std::string create_one_ec_pool_pp(const std::string &pool_name, librados::Rados &cluster); std::string connect_cluster(rados_t *cluster); std::string connect_cluster_pp(librados::Rados &cluster); int destroy_one_pool(const std::string &pool_name, rados_t *cluster); int destroy_one_ec_pool(const std::string &pool_name, rados_t *cluster); int destroy_one_pool_pp(const std::string &pool_name, librados::Rados &cluster); int destroy_one_ec_pool_pp(const std::string &pool_name, librados::Rados &cluster); class TestAlarm { public: TestAlarm() { alarm(360); } ~TestAlarm() { alarm(0); } }; #endif ceph-0.80.11/src/test/librados/watch_notify.cc0000664000175100017510000000737312623076744023261 0ustar jenkins-buildjenkins-build#include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/rados/rados_types.h" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include #include #include "gtest/gtest.h" using namespace librados; typedef RadosTest LibRadosWatchNotify; typedef RadosTestParamPP LibRadosWatchNotifyPP; typedef RadosTestEC LibRadosWatchNotifyEC; typedef RadosTestECPP LibRadosWatchNotifyECPP; static sem_t sem; static void watch_notify_test_cb(uint8_t opcode, uint64_t ver, void *arg) { sem_post(&sem); } class WatchNotifyTestCtx : public WatchCtx { public: void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { sem_post(&sem); } }; TEST_F(LibRadosWatchNotify, WatchNotifyTest) { ASSERT_EQ(0, sem_init(&sem, 0, 0)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); uint64_t handle; ASSERT_EQ(0, rados_watch(ioctx, "foo", 0, &handle, watch_notify_test_cb, NULL)); ASSERT_EQ(0, rados_notify(ioctx, "foo", 0, NULL, 0)); TestAlarm alarm; sem_wait(&sem); rados_unwatch(ioctx, "foo", handle); sem_destroy(&sem); } TEST_P(LibRadosWatchNotifyPP, WatchNotifyTestPP) { ASSERT_EQ(0, sem_init(&sem, 0, 0)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); uint64_t handle; WatchNotifyTestCtx ctx; ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx)); std::list watches; ASSERT_EQ(0, ioctx.list_watchers("foo", &watches)); ASSERT_EQ(watches.size(), 1u); bufferlist bl2; ASSERT_EQ(0, ioctx.notify("foo", 0, bl2)); TestAlarm alarm; sem_wait(&sem); ioctx.unwatch("foo", handle); sem_destroy(&sem); } TEST_P(LibRadosWatchNotifyPP, WatchNotifyTimeoutTestPP) { ASSERT_EQ(0, sem_init(&sem, 0, 0)); ioctx.set_notify_timeout(1); uint64_t handle; WatchNotifyTestCtx ctx; char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx)); sem_destroy(&sem); } TEST_F(LibRadosWatchNotifyEC, WatchNotifyTest) { ASSERT_EQ(0, sem_init(&sem, 0, 0)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); uint64_t handle; ASSERT_EQ(0, rados_watch(ioctx, "foo", 0, &handle, watch_notify_test_cb, NULL)); ASSERT_EQ(0, rados_notify(ioctx, "foo", 0, NULL, 0)); TestAlarm alarm; sem_wait(&sem); rados_unwatch(ioctx, "foo", handle); sem_destroy(&sem); } TEST_F(LibRadosWatchNotifyECPP, WatchNotifyTestPP) { ASSERT_EQ(0, sem_init(&sem, 0, 0)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); uint64_t handle; WatchNotifyTestCtx ctx; ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx)); std::list watches; ASSERT_EQ(0, ioctx.list_watchers("foo", &watches)); ASSERT_EQ(watches.size(), 1u); bufferlist bl2; ASSERT_EQ(0, ioctx.notify("foo", 0, bl2)); TestAlarm alarm; sem_wait(&sem); ioctx.unwatch("foo", handle); sem_destroy(&sem); } TEST_F(LibRadosWatchNotifyECPP, WatchNotifyTimeoutTestPP) { ASSERT_EQ(0, sem_init(&sem, 0, 0)); ioctx.set_notify_timeout(1); uint64_t handle; WatchNotifyTestCtx ctx; char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx)); sem_destroy(&sem); } INSTANTIATE_TEST_CASE_P(LibRadosWatchNotifyPPTests, LibRadosWatchNotifyPP, ::testing::Values("", "cache")); ceph-0.80.11/src/test/librados/lock.cc0000664000175100017510000003461212623076744021507 0ustar jenkins-buildjenkins-build#include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include "cls/lock/cls_lock_client.h" #include #include #include "gtest/gtest.h" #include using namespace librados; typedef RadosTest LibRadosLock; typedef RadosTestPP LibRadosLockPP; typedef RadosTestEC LibRadosLockEC; typedef RadosTestECPP LibRadosLockECPP; TEST_F(LibRadosLock, LockExclusive) { ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockPP, LockExclusivePP) { ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLock, LockShared) { ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(-EEXIST, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLockPP, LockSharedPP) { ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(-EEXIST, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLock, LockExclusiveDur) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", &tv, 0)); sleep(1); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockPP, LockExclusiveDurPP) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", &tv, 0)); sleep(1); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLock, LockSharedDur) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", &tv, 0)); sleep(1); ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLockPP, LockSharedDurPP) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", &tv, 0)); sleep(1); ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLock, LockRenew) { ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, LOCK_FLAG_RENEW)); } TEST_F(LibRadosLockPP, LockRenewPP) { ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, LOCK_FLAG_RENEW)); } TEST_F(LibRadosLock, Unlock) { ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, rados_unlock(ioctx, "foo", "TestLock", "Cookie")); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockPP, UnlockPP) { ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, ioctx.unlock("foo", "TestLock", "Cookie")); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLock, ListLockers) { int exclusive; char tag[1024]; char clients[1024]; char cookies[1024]; char addresses[1024]; size_t tag_len = 1024; size_t clients_len = 1024; size_t cookies_len = 1024; size_t addresses_len = 1024; std::stringstream sstm; sstm << "client." << rados_get_instance_id(cluster); std::string me = sstm.str(); ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(0, rados_unlock(ioctx, "foo", "TestLock", "Cookie")); ASSERT_EQ(0, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(-34, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); tag_len = 1024; clients_len = 1024; cookies_len = 1024; addresses_len = 1024; ASSERT_EQ(1, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); ASSERT_EQ(0, exclusive); ASSERT_EQ(0, strcmp(tag, "Tag")); ASSERT_EQ(strlen("Tag") + 1, tag_len); ASSERT_EQ(0, strcmp(me.c_str(), clients)); ASSERT_EQ(me.size() + 1, clients_len); ASSERT_EQ(0, strcmp(cookies, "Cookie")); ASSERT_EQ(strlen("Cookie") + 1, cookies_len); } TEST_F(LibRadosLockPP, ListLockersPP) { std::stringstream sstm; sstm << "client." << cluster.get_instance_id(); std::string me = sstm.str(); ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(0, ioctx.unlock("foo", "TestLock", "Cookie")); { int exclusive; std::string tag; std::list lockers; ASSERT_EQ(0, ioctx.list_lockers("foo", "TestLock", &exclusive, &tag, &lockers)); } ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); { int exclusive; std::string tag; std::list lockers; ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLock", &exclusive, &tag, &lockers)); std::list::iterator it = lockers.begin(); ASSERT_FALSE(lockers.end() == it); ASSERT_EQ(me, it->client); ASSERT_EQ("Cookie", it->cookie); } } TEST_F(LibRadosLock, BreakLock) { int exclusive; char tag[1024]; char clients[1024]; char cookies[1024]; char addresses[1024]; size_t tag_len = 1024; size_t clients_len = 1024; size_t cookies_len = 1024; size_t addresses_len = 1024; std::stringstream sstm; sstm << "client." << rados_get_instance_id(cluster); std::string me = sstm.str(); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(1, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); ASSERT_EQ(1, exclusive); ASSERT_EQ(0, strcmp(tag, "")); ASSERT_EQ(1U, tag_len); ASSERT_EQ(0, strcmp(me.c_str(), clients)); ASSERT_EQ(me.size() + 1, clients_len); ASSERT_EQ(0, strcmp(cookies, "Cookie")); ASSERT_EQ(strlen("Cookie") + 1, cookies_len); ASSERT_EQ(0, rados_break_lock(ioctx, "foo", "TestLock", clients, "Cookie")); } TEST_F(LibRadosLockPP, BreakLockPP) { int exclusive; std::string tag; std::list lockers; std::stringstream sstm; sstm << "client." << cluster.get_instance_id(); std::string me = sstm.str(); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLock", &exclusive, &tag, &lockers)); std::list::iterator it = lockers.begin(); ASSERT_FALSE(lockers.end() == it); ASSERT_EQ(me, it->client); ASSERT_EQ("Cookie", it->cookie); ASSERT_EQ(0, ioctx.break_lock("foo", "TestLock", it->client, "Cookie")); } // EC testing TEST_F(LibRadosLockEC, LockExclusive) { ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockECPP, LockExclusivePP) { ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockEC, LockShared) { ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(-EEXIST, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLockECPP, LockSharedPP) { ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(-EEXIST, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLockEC, LockExclusiveDur) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", &tv, 0)); sleep(1); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockECPP, LockExclusiveDurPP) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", &tv, 0)); sleep(1); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockEC, LockSharedDur) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", &tv, 0)); sleep(1); ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLockECPP, LockSharedDurPP) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", &tv, 0)); sleep(1); ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); } TEST_F(LibRadosLockEC, LockRenew) { ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, LOCK_FLAG_RENEW)); } TEST_F(LibRadosLockECPP, LockRenewPP) { ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, LOCK_FLAG_RENEW)); } TEST_F(LibRadosLockEC, Unlock) { ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, rados_unlock(ioctx, "foo", "TestLock", "Cookie")); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockECPP, UnlockPP) { ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(0, ioctx.unlock("foo", "TestLock", "Cookie")); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); } TEST_F(LibRadosLockEC, ListLockers) { int exclusive; char tag[1024]; char clients[1024]; char cookies[1024]; char addresses[1024]; size_t tag_len = 1024; size_t clients_len = 1024; size_t cookies_len = 1024; size_t addresses_len = 1024; std::stringstream sstm; sstm << "client." << rados_get_instance_id(cluster); std::string me = sstm.str(); ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(0, rados_unlock(ioctx, "foo", "TestLock", "Cookie")); ASSERT_EQ(0, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(-34, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); tag_len = 1024; clients_len = 1024; cookies_len = 1024; addresses_len = 1024; ASSERT_EQ(1, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); ASSERT_EQ(0, exclusive); ASSERT_EQ(0, strcmp(tag, "Tag")); ASSERT_EQ(strlen("Tag") + 1, tag_len); ASSERT_EQ(0, strcmp(me.c_str(), clients)); ASSERT_EQ(me.size() + 1, clients_len); ASSERT_EQ(0, strcmp(cookies, "Cookie")); ASSERT_EQ(strlen("Cookie") + 1, cookies_len); } TEST_F(LibRadosLockECPP, ListLockersPP) { std::stringstream sstm; sstm << "client." << cluster.get_instance_id(); std::string me = sstm.str(); ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); ASSERT_EQ(0, ioctx.unlock("foo", "TestLock", "Cookie")); { int exclusive; std::string tag; std::list lockers; ASSERT_EQ(0, ioctx.list_lockers("foo", "TestLock", &exclusive, &tag, &lockers)); } ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLock", "Cookie", "Tag", "", NULL, 0)); { int exclusive; std::string tag; std::list lockers; ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLock", &exclusive, &tag, &lockers)); std::list::iterator it = lockers.begin(); ASSERT_FALSE(lockers.end() == it); ASSERT_EQ(me, it->client); ASSERT_EQ("Cookie", it->cookie); } } TEST_F(LibRadosLockEC, BreakLock) { int exclusive; char tag[1024]; char clients[1024]; char cookies[1024]; char addresses[1024]; size_t tag_len = 1024; size_t clients_len = 1024; size_t cookies_len = 1024; size_t addresses_len = 1024; std::stringstream sstm; sstm << "client." << rados_get_instance_id(cluster); std::string me = sstm.str(); ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(1, rados_list_lockers(ioctx, "foo", "TestLock", &exclusive, tag, &tag_len, clients, &clients_len, cookies, &cookies_len, addresses, &addresses_len )); ASSERT_EQ(1, exclusive); ASSERT_EQ(0, strcmp(tag, "")); ASSERT_EQ(1U, tag_len); ASSERT_EQ(0, strcmp(me.c_str(), clients)); ASSERT_EQ(me.size() + 1, clients_len); ASSERT_EQ(0, strcmp(cookies, "Cookie")); ASSERT_EQ(strlen("Cookie") + 1, cookies_len); ASSERT_EQ(0, rados_break_lock(ioctx, "foo", "TestLock", clients, "Cookie")); } TEST_F(LibRadosLockECPP, BreakLockPP) { int exclusive; std::string tag; std::list lockers; std::stringstream sstm; sstm << "client." << cluster.get_instance_id(); std::string me = sstm.str(); ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0)); ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLock", &exclusive, &tag, &lockers)); std::list::iterator it = lockers.begin(); ASSERT_FALSE(lockers.end() == it); ASSERT_EQ(me, it->client); ASSERT_EQ("Cookie", it->cookie); ASSERT_EQ(0, ioctx.break_lock("foo", "TestLock", it->client, "Cookie")); } ceph-0.80.11/src/test/librados/librados.cc0000664000175100017510000000037012623076744022350 0ustar jenkins-buildjenkins-build//#include "common/config.h" #include "include/rados/librados.h" #include "gtest/gtest.h" TEST(Librados, CreateShutdown) { rados_t cluster; int err; err = rados_create(&cluster, "someid"); EXPECT_EQ(err, 0); rados_shutdown(cluster); } ceph-0.80.11/src/test/librados/aio.cc0000664000175100017510000030020712623076744021323 0ustar jenkins-buildjenkins-build#include "common/errno.h" #include "include/rados/librados.h" #include "test/librados/test.h" #include "include/types.h" #include "gtest/gtest.h" #include #include #include #include #include #include using std::ostringstream; using namespace librados; using std::pair; class AioTestData { public: AioTestData() : m_cluster(NULL), m_ioctx(NULL), m_init(false), m_complete(false), m_safe(false) { } ~AioTestData() { if (m_init) { rados_ioctx_destroy(m_ioctx); destroy_one_pool(m_pool_name, &m_cluster); sem_destroy(&m_sem); } } std::string init() { int ret; if (sem_init(&m_sem, 0, 0)) { int err = errno; sem_destroy(&m_sem); ostringstream oss; oss << "sem_init failed: " << cpp_strerror(err); return oss.str(); } m_pool_name = get_temp_pool_name(); std::string err = create_one_pool(m_pool_name, &m_cluster); if (!err.empty()) { sem_destroy(&m_sem); ostringstream oss; oss << "create_one_pool(" << m_pool_name << ") failed: error " << err; return oss.str(); } ret = rados_ioctx_create(m_cluster, m_pool_name.c_str(), &m_ioctx); if (ret) { sem_destroy(&m_sem); destroy_one_pool(m_pool_name, &m_cluster); ostringstream oss; oss << "rados_ioctx_create failed: error " << ret; return oss.str(); } m_init = true; return ""; } sem_t m_sem; rados_t m_cluster; rados_ioctx_t m_ioctx; std::string m_pool_name; bool m_init; bool m_complete; bool m_safe; }; class AioTestDataPP { public: AioTestDataPP() : m_init(false), m_complete(false), m_safe(false) { } ~AioTestDataPP() { if (m_init) { m_ioctx.close(); destroy_one_pool_pp(m_pool_name, m_cluster); sem_destroy(&m_sem); } } std::string init() { int ret; if (sem_init(&m_sem, 0, 0)) { int err = errno; sem_destroy(&m_sem); ostringstream oss; oss << "sem_init failed: " << cpp_strerror(err); return oss.str(); } m_pool_name = get_temp_pool_name(); std::string err = create_one_pool_pp(m_pool_name, m_cluster); if (!err.empty()) { sem_destroy(&m_sem); ostringstream oss; oss << "create_one_pool(" << m_pool_name << ") failed: error " << err; return oss.str(); } ret = m_cluster.ioctx_create(m_pool_name.c_str(), m_ioctx); if (ret) { sem_destroy(&m_sem); destroy_one_pool_pp(m_pool_name, m_cluster); ostringstream oss; oss << "rados_ioctx_create failed: error " << ret; return oss.str(); } m_init = true; return ""; } sem_t m_sem; Rados m_cluster; IoCtx m_ioctx; std::string m_pool_name; bool m_init; bool m_complete; bool m_safe; }; void set_completion_complete(rados_completion_t cb, void *arg) { AioTestData *test = static_cast(arg); test->m_complete = true; sem_post(&test->m_sem); } void set_completion_safe(rados_completion_t cb, void *arg) { AioTestData *test = static_cast(arg); test->m_safe = true; sem_post(&test->m_sem); } void set_completion_completePP(rados_completion_t cb, void *arg) { AioTestDataPP *test = static_cast(arg); test->m_complete = true; sem_post(&test->m_sem); } void set_completion_safePP(rados_completion_t cb, void *arg) { AioTestDataPP *test = static_cast(arg); test->m_safe = true; sem_post(&test->m_sem); } TEST(LibRadosAio, SimpleWrite) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_aio_release(my_completion); } TEST(LibRadosAio, SimpleWritePP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); delete my_completion; } { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); test_data.m_ioctx.set_namespace("nspace"); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); delete my_completion; } } TEST(LibRadosAio, WaitForSafe) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_safe(my_completion)); ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_aio_release(my_completion); } TEST(LibRadosAio, WaitForSafePP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_safe()); ASSERT_EQ(0, my_completion->get_return_value()); delete my_completion; } TEST(LibRadosAio, RoundTrip) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[256]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAio, RoundTrip2) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAio, RoundTripPP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAio, RoundTripPP2) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completePP, set_completion_safePP); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_safe()); ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAio, RoundTripAppend) { AioTestData test_data; rados_completion_t my_completion, my_completion2, my_completion3; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf))); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2))); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); char buf3[sizeof(buf) + sizeof(buf2)]; memset(buf3, 0, sizeof(buf3)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion3, buf3, sizeof(buf3), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ((int)sizeof(buf3), rados_aio_get_return_value(my_completion3)); ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAio, RoundTripAppendPP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion, bl1, sizeof(buf))); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(0, my_completion->get_return_value()); char buf2[128]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion2, bl2, sizeof(buf2))); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); bufferlist bl3; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3, &bl3, 2 * sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ((int)(sizeof(buf) * 2), my_completion3->get_return_value()); ASSERT_EQ(sizeof(buf) * 2, bl3.length()); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2))); delete my_completion; delete my_completion2; delete my_completion3; } TEST(LibRadosAio, IsComplete) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test rados_aio_is_complete. while (true) { int is_complete = rados_aio_is_complete(my_completion2); if (is_complete) break; } } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAio, IsCompletePP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test is_complete. while (true) { int is_complete = my_completion2->is_complete(); if (is_complete) break; } } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAio, IsSafe) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test rados_aio_is_safe. while (true) { int is_safe = rados_aio_is_safe(my_completion); if (is_safe) break; } } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAio, IsSafePP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test rados_aio_is_safe. while (true) { int is_safe = my_completion->is_safe(); if (is_safe) break; } } ASSERT_EQ(0, my_completion->get_return_value()); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); bufferlist bl2; ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAio, ReturnValue) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0, sizeof(buf)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion)); rados_aio_release(my_completion); } TEST(LibRadosAio, ReturnValuePP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); bufferlist bl1; ASSERT_EQ(0, test_data.m_ioctx.aio_read("nonexistent", my_completion, &bl1, 128, 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(-ENOENT, my_completion->get_return_value()); delete my_completion; } TEST(LibRadosAio, Flush) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xee, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_aio_flush(test_data.m_ioctx)); ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAio, FlushPP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xee, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); ASSERT_EQ(0, test_data.m_ioctx.aio_flush()); ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAio, FlushAsync) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); rados_completion_t flush_completion; ASSERT_EQ(0, rados_aio_create_completion(NULL, NULL, NULL, &flush_completion)); char buf[128]; memset(buf, 0xee, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_aio_flush_async(test_data.m_ioctx, flush_completion)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(flush_completion)); ASSERT_EQ(0, rados_aio_wait_for_safe(flush_completion)); } ASSERT_EQ(1, rados_aio_is_complete(my_completion)); ASSERT_EQ(1, rados_aio_is_safe(my_completion)); ASSERT_EQ(1, rados_aio_is_complete(flush_completion)); ASSERT_EQ(1, rados_aio_is_safe(flush_completion)); ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(flush_completion); } TEST(LibRadosAio, FlushAsyncPP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *flush_completion = test_data.m_cluster.aio_create_completion(NULL, NULL, NULL); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xee, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); ASSERT_EQ(0, test_data.m_ioctx.aio_flush_async(flush_completion)); { TestAlarm alarm; ASSERT_EQ(0, flush_completion->wait_for_complete()); ASSERT_EQ(0, flush_completion->wait_for_safe()); } ASSERT_EQ(1, my_completion->is_complete()); ASSERT_EQ(1, my_completion->is_safe()); ASSERT_EQ(1, flush_completion->is_complete()); ASSERT_EQ(1, flush_completion->is_safe()); ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; delete flush_completion; } TEST(LibRadosAio, RoundTripWriteFull) { AioTestData test_data; rados_completion_t my_completion, my_completion2, my_completion3; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_write_full(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2))); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); char buf3[sizeof(buf) + sizeof(buf2)]; memset(buf3, 0, sizeof(buf3)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion3, buf3, sizeof(buf3), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion3)); ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAio, RoundTripWriteFullPP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(0, my_completion->get_return_value()); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_write_full("foo", my_completion2, bl2)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); bufferlist bl3; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3, &bl3, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf2), my_completion3->get_return_value()); ASSERT_EQ(sizeof(buf2), bl3.length()); ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2))); delete my_completion; delete my_completion2; delete my_completion3; } TEST(LibRadosAio, SimpleStat) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); uint64_t psize; time_t pmtime; rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(sizeof(buf), psize); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAio, SimpleStatPP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); uint64_t psize; time_t pmtime; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), psize); delete my_completion; delete my_completion2; } TEST(LibRadosAio, SimpleStatNS) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); char buf2[64]; memset(buf2, 0xbb, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf2, sizeof(buf2), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); uint64_t psize; time_t pmtime; rados_completion_t my_completion2; rados_ioctx_set_namespace(test_data.m_ioctx, ""); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(sizeof(buf), psize); rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); rados_completion_t my_completion3; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion3, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); ASSERT_EQ(sizeof(buf2), psize); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAio, SimpleStatPPNS) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); uint64_t psize; time_t pmtime; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), psize); delete my_completion; delete my_completion2; } TEST(LibRadosAio, StatRemove) { AioTestData test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); uint64_t psize; time_t pmtime; rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(sizeof(buf), psize); rados_completion_t my_completion3; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3)); ASSERT_EQ(0, rados_aio_remove(test_data.m_ioctx, "foo", my_completion3)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); uint64_t psize2; time_t pmtime2; rados_completion_t my_completion4; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion4)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion4, &psize2, &pmtime2)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); } ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion4)); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); rados_aio_release(my_completion4); } TEST(LibRadosAio, StatRemovePP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); uint64_t psize; time_t pmtime; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), psize); uint64_t psize2; time_t pmtime2; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion3)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ(0, my_completion3->get_return_value()); AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion4, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion4, &psize2, &pmtime2)); { TestAlarm alarm; ASSERT_EQ(0, my_completion4->wait_for_complete()); } ASSERT_EQ(-ENOENT, my_completion4->get_return_value()); delete my_completion; delete my_completion2; delete my_completion3; delete my_completion4; } using std::string; using std::map; using std::set; TEST(LibRadosAio, OmapPP) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); string header_str = "baz"; bufferptr bp(header_str.c_str(), header_str.size() + 1); bufferlist header_to_set; header_to_set.push_back(bp); map to_set; { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectWriteOperation op; to_set["foo"] = header_to_set; to_set["foo2"] = header_to_set; to_set["qfoo3"] = header_to_set; op.omap_set(to_set); op.omap_set_header(header_to_set); ioctx.aio_operate("test_obj", my_completion.get(), &op); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(0, my_completion->get_return_value()); } { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectReadOperation op; map > assertions; bufferlist val; val.append(string("bar")); assertions["foo"] = pair(val, CEPH_OSD_CMPXATTR_OP_EQ); int r; op.omap_cmp(assertions, &r); ioctx.aio_operate("test_obj", my_completion.get(), &op, 0); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(-ECANCELED, my_completion->get_return_value()); ASSERT_EQ(-ECANCELED, r); } { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectReadOperation op; set set_got; map map_got; set to_get; map got3; map got4; bufferlist header; op.omap_get_keys("", 1, &set_got, 0); op.omap_get_vals("foo", 1, &map_got, 0); to_get.insert("foo"); to_get.insert("qfoo3"); op.omap_get_vals_by_keys(to_get, &got3, 0); op.omap_get_header(&header, 0); op.omap_get_vals("foo2", "q", 1, &got4, 0); ioctx.aio_operate("test_obj", my_completion.get(), &op, 0); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(0, my_completion->get_return_value()); ASSERT_EQ(header.length(), header_to_set.length()); ASSERT_EQ(set_got.size(), (unsigned)1); ASSERT_EQ(*set_got.begin(), "foo"); ASSERT_EQ(map_got.size(), (unsigned)1); ASSERT_EQ(map_got.begin()->first, "foo2"); ASSERT_EQ(got3.size(), (unsigned)2); ASSERT_EQ(got3.begin()->first, "foo"); ASSERT_EQ(got3.rbegin()->first, "qfoo3"); ASSERT_EQ(got4.size(), (unsigned)1); ASSERT_EQ(got4.begin()->first, "qfoo3"); } { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectWriteOperation op; set to_remove; to_remove.insert("foo2"); op.omap_rm_keys(to_remove); ioctx.aio_operate("test_obj", my_completion.get(), &op); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(0, my_completion->get_return_value()); } { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectReadOperation op; set set_got; op.omap_get_keys("", -1, &set_got, 0); ioctx.aio_operate("test_obj", my_completion.get(), &op, 0); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(0, my_completion->get_return_value()); ASSERT_EQ(set_got.size(), (unsigned)2); } { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectWriteOperation op; op.omap_clear(); ioctx.aio_operate("test_obj", my_completion.get(), &op); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(0, my_completion->get_return_value()); } { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectReadOperation op; set set_got; op.omap_get_keys("", -1, &set_got, 0); ioctx.aio_operate("test_obj", my_completion.get(), &op, 0); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(0, my_completion->get_return_value()); ASSERT_EQ(set_got.size(), (unsigned)0); } ioctx.remove("test_obj"); destroy_one_pool_pp(pool_name, cluster); } TEST(LibRadosAio, MultiWrite) { AioTestData test_data; rados_completion_t my_completion, my_completion2, my_completion3; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion2)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), sizeof(buf))); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); char buf3[(sizeof(buf) + sizeof(buf2)) * 3]; memset(buf3, 0, sizeof(buf3)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_complete, set_completion_safe, &my_completion3)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion3, buf3, sizeof(buf3), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)), rados_aio_get_return_value(my_completion3)); ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAio, MultiWritePP) { AioTestDataPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(0, my_completion->get_return_value()); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion2, bl2, sizeof(buf2), sizeof(buf))); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); bufferlist bl3; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_complete, set_completion_safe); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3, &bl3, (sizeof(buf) + sizeof(buf2) * 3), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)), my_completion3->get_return_value()); ASSERT_EQ(sizeof(buf) + sizeof(buf2), bl3.length()); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2))); delete my_completion; delete my_completion2; delete my_completion3; } // EC test cases class AioTestDataEC { public: AioTestDataEC() : m_cluster(NULL), m_ioctx(NULL), m_init(false), m_complete(false), m_safe(false) { } ~AioTestDataEC() { if (m_init) { rados_ioctx_destroy(m_ioctx); destroy_one_ec_pool(m_pool_name, &m_cluster); sem_destroy(&m_sem); } } std::string init() { int ret; if (sem_init(&m_sem, 0, 0)) { int err = errno; sem_destroy(&m_sem); ostringstream oss; oss << "sem_init failed: " << cpp_strerror(err); return oss.str(); } m_pool_name = get_temp_pool_name(); std::string err = create_one_ec_pool(m_pool_name, &m_cluster); if (!err.empty()) { sem_destroy(&m_sem); ostringstream oss; oss << "create_one_ec_pool(" << m_pool_name << ") failed: error " << err; return oss.str(); } ret = rados_ioctx_create(m_cluster, m_pool_name.c_str(), &m_ioctx); if (ret) { sem_destroy(&m_sem); destroy_one_ec_pool(m_pool_name, &m_cluster); ostringstream oss; oss << "rados_ioctx_create failed: error " << ret; return oss.str(); } m_init = true; return ""; } sem_t m_sem; rados_t m_cluster; rados_ioctx_t m_ioctx; std::string m_pool_name; bool m_init; bool m_complete; bool m_safe; }; class AioTestDataECPP { public: AioTestDataECPP() : m_init(false), m_complete(false), m_safe(false) { } ~AioTestDataECPP() { if (m_init) { m_ioctx.close(); destroy_one_ec_pool_pp(m_pool_name, m_cluster); sem_destroy(&m_sem); } } std::string init() { int ret; if (sem_init(&m_sem, 0, 0)) { int err = errno; sem_destroy(&m_sem); ostringstream oss; oss << "sem_init failed: " << cpp_strerror(err); return oss.str(); } m_pool_name = get_temp_pool_name(); std::string err = create_one_ec_pool_pp(m_pool_name, m_cluster); if (!err.empty()) { sem_destroy(&m_sem); ostringstream oss; oss << "create_one_ec_pool(" << m_pool_name << ") failed: error " << err; return oss.str(); } ret = m_cluster.ioctx_create(m_pool_name.c_str(), m_ioctx); if (ret) { sem_destroy(&m_sem); destroy_one_ec_pool_pp(m_pool_name, m_cluster); ostringstream oss; oss << "rados_ioctx_create failed: error " << ret; return oss.str(); } m_init = true; return ""; } sem_t m_sem; Rados m_cluster; IoCtx m_ioctx; std::string m_pool_name; bool m_init; bool m_complete; bool m_safe; }; void set_completion_completeEC(rados_completion_t cb, void *arg) { AioTestDataEC *test = static_cast(arg); test->m_complete = true; sem_post(&test->m_sem); } void set_completion_safeEC(rados_completion_t cb, void *arg) { AioTestDataEC *test = static_cast(arg); test->m_safe = true; sem_post(&test->m_sem); } void set_completion_completeECPP(rados_completion_t cb, void *arg) { AioTestDataECPP *test = static_cast(arg); test->m_complete = true; sem_post(&test->m_sem); } void set_completion_safeECPP(rados_completion_t cb, void *arg) { AioTestDataECPP *test = static_cast(arg); test->m_safe = true; sem_post(&test->m_sem); } TEST(LibRadosAioEC, SimpleWrite) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_aio_release(my_completion); } TEST(LibRadosAioEC, SimpleWritePP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); delete my_completion; } { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); test_data.m_ioctx.set_namespace("nspace"); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); delete my_completion; } } TEST(LibRadosAioEC, WaitForSafe) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_safe(my_completion)); ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_aio_release(my_completion); } TEST(LibRadosAioEC, WaitForSafePP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_safe()); ASSERT_EQ(0, my_completion->get_return_value()); delete my_completion; } TEST(LibRadosAioEC, RoundTrip) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[256]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAioEC, RoundTrip2) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAioEC, RoundTripPP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, RoundTripPP2) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeECPP, set_completion_safeECPP); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_safe()); ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, RoundTripAppend) { AioTestDataEC test_data; rados_completion_t my_completion, my_completion2, my_completion3, my_completion4; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); ASSERT_TRUE(rados_ioctx_pool_requires_alignment(test_data.m_ioctx)); uint64_t alignment = rados_ioctx_pool_required_alignment(test_data.m_ioctx); ASSERT_NE((unsigned)0, alignment); int bsize = alignment; char *buf = (char *)new char[bsize]; memset(buf, 0xcc, bsize); ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", my_completion, buf, bsize)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); int hbsize = bsize / 2; char *buf2 = (char *)new char[hbsize]; memset(buf2, 0xdd, hbsize); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", my_completion2, buf2, hbsize)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion3)); ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", my_completion3, buf2, hbsize)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } EXPECT_EQ(-EOPNOTSUPP, rados_aio_get_return_value(my_completion3)); int tbsize = bsize + hbsize; char *buf3 = (char *)new char[tbsize]; memset(buf3, 0, tbsize); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion4)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion4, buf3, bsize * 3, 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); } ASSERT_EQ(tbsize, rados_aio_get_return_value(my_completion4)); ASSERT_EQ(0, memcmp(buf3, buf, bsize)); ASSERT_EQ(0, memcmp(buf3 + bsize, buf2, hbsize)); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); delete[] buf; delete[] buf2; delete[] buf3; } TEST(LibRadosAioEC, RoundTripAppendPP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); ASSERT_TRUE(test_data.m_ioctx.pool_requires_alignment()); uint64_t alignment = test_data.m_ioctx.pool_required_alignment(); ASSERT_NE((unsigned)0, alignment); int bsize = alignment; char *buf = (char *)new char[bsize]; memset(buf, 0xcc, bsize); bufferlist bl1; bl1.append(buf, bsize); ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion, bl1, bsize)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(0, my_completion->get_return_value()); int hbsize = bsize / 2; char *buf2 = (char *)new char[hbsize]; memset(buf2, 0xdd, hbsize); bufferlist bl2; bl2.append(buf2, hbsize); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion2, bl2, hbsize)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion3, bl2, hbsize)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } EXPECT_EQ(-EOPNOTSUPP, my_completion3->get_return_value()); bufferlist bl3; AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion4, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion4, &bl3, bsize * 3, 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion4->wait_for_complete()); } int tbsize = bsize + hbsize; ASSERT_EQ(tbsize, my_completion4->get_return_value()); ASSERT_EQ((unsigned)tbsize, bl3.length()); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize)); ASSERT_EQ(0, memcmp(bl3.c_str() + bsize, buf2, hbsize)); delete my_completion; delete my_completion2; delete my_completion3; delete[] buf; delete[] buf2; } TEST(LibRadosAioEC, IsComplete) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test rados_aio_is_complete. while (true) { int is_complete = rados_aio_is_complete(my_completion2); if (is_complete) break; } } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAioEC, IsCompletePP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test is_complete. while (true) { int is_complete = my_completion2->is_complete(); if (is_complete) break; } } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, IsSafe) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test rados_aio_is_safe. while (true) { int is_safe = rados_aio_is_safe(my_completion); if (is_safe) break; } } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAioEC, IsSafePP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; // Busy-wait until the AIO completes. // Normally we wouldn't do this, but we want to test rados_aio_is_safe. while (true) { int is_safe = my_completion->is_safe(); if (is_safe) break; } } ASSERT_EQ(0, my_completion->get_return_value()); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); bufferlist bl2; ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, ReturnValue) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0, sizeof(buf)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion)); rados_aio_release(my_completion); } TEST(LibRadosAioEC, ReturnValuePP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); bufferlist bl1; ASSERT_EQ(0, test_data.m_ioctx.aio_read("nonexistent", my_completion, &bl1, 128, 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(-ENOENT, my_completion->get_return_value()); delete my_completion; } TEST(LibRadosAioEC, Flush) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xee, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_aio_flush(test_data.m_ioctx)); ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAioEC, FlushPP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xee, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); ASSERT_EQ(0, test_data.m_ioctx.aio_flush()); ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, FlushAsync) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); rados_completion_t flush_completion; ASSERT_EQ(0, rados_aio_create_completion(NULL, NULL, NULL, &flush_completion)); char buf[128]; memset(buf, 0xee, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_aio_flush_async(test_data.m_ioctx, flush_completion)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(flush_completion)); ASSERT_EQ(0, rados_aio_wait_for_safe(flush_completion)); } ASSERT_EQ(1, rados_aio_is_complete(my_completion)); ASSERT_EQ(1, rados_aio_is_safe(my_completion)); ASSERT_EQ(1, rados_aio_is_complete(flush_completion)); ASSERT_EQ(1, rados_aio_is_safe(flush_completion)); ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[128]; memset(buf2, 0, sizeof(buf2)); rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(flush_completion); } TEST(LibRadosAioEC, FlushAsyncPP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *flush_completion = test_data.m_cluster.aio_create_completion(NULL, NULL, NULL); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xee, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); ASSERT_EQ(0, test_data.m_ioctx.aio_flush_async(flush_completion)); { TestAlarm alarm; ASSERT_EQ(0, flush_completion->wait_for_complete()); ASSERT_EQ(0, flush_completion->wait_for_safe()); } ASSERT_EQ(1, my_completion->is_complete()); ASSERT_EQ(1, my_completion->is_safe()); ASSERT_EQ(1, flush_completion->is_complete()); ASSERT_EQ(1, flush_completion->is_safe()); ASSERT_EQ(0, my_completion->get_return_value()); bufferlist bl2; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2, &bl2, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), bl2.length()); ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf))); delete my_completion; delete my_completion2; delete flush_completion; } TEST(LibRadosAioEC, RoundTripWriteFull) { AioTestDataEC test_data; rados_completion_t my_completion, my_completion2, my_completion3; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_write_full(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2))); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); char buf3[sizeof(buf) + sizeof(buf2)]; memset(buf3, 0, sizeof(buf3)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion3)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion3, buf3, sizeof(buf3), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion3)); ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAioEC, RoundTripWriteFullPP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(0, my_completion->get_return_value()); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_write_full("foo", my_completion2, bl2)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); bufferlist bl3; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3, &bl3, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf2), my_completion3->get_return_value()); ASSERT_EQ(sizeof(buf2), bl3.length()); ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2))); delete my_completion; delete my_completion2; delete my_completion3; } TEST(LibRadosAioEC, SimpleStat) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); uint64_t psize; time_t pmtime; rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(sizeof(buf), psize); rados_aio_release(my_completion); rados_aio_release(my_completion2); } TEST(LibRadosAioEC, SimpleStatPP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); uint64_t psize; time_t pmtime; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), psize); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, SimpleStatNS) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); char buf2[64]; memset(buf2, 0xbb, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf2, sizeof(buf2), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); uint64_t psize; time_t pmtime; rados_completion_t my_completion2; rados_ioctx_set_namespace(test_data.m_ioctx, ""); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(sizeof(buf), psize); rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); rados_completion_t my_completion3; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion3)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion3, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); ASSERT_EQ(sizeof(buf2), psize); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAioEC, SimpleStatPPNS) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); uint64_t psize; time_t pmtime; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), psize); delete my_completion; delete my_completion2; } TEST(LibRadosAioEC, StatRemove) { AioTestDataEC test_data; rados_completion_t my_completion; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); uint64_t psize; time_t pmtime; rados_completion_t my_completion2; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); ASSERT_EQ(sizeof(buf), psize); rados_completion_t my_completion3; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion3)); ASSERT_EQ(0, rados_aio_remove(test_data.m_ioctx, "foo", my_completion3)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); uint64_t psize2; time_t pmtime2; rados_completion_t my_completion4; ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion4)); ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", my_completion4, &psize2, &pmtime2)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); } ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion4)); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); rados_aio_release(my_completion4); } TEST(LibRadosAioEC, StatRemovePP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; sem_wait(&test_data.m_sem); sem_wait(&test_data.m_sem); } ASSERT_EQ(0, my_completion->get_return_value()); uint64_t psize; time_t pmtime; AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2, &psize, &pmtime)); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(0, my_completion2->get_return_value()); ASSERT_EQ(sizeof(buf), psize); uint64_t psize2; time_t pmtime2; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion3)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ(0, my_completion3->get_return_value()); AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion4, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion4, &psize2, &pmtime2)); { TestAlarm alarm; ASSERT_EQ(0, my_completion4->wait_for_complete()); } ASSERT_EQ(-ENOENT, my_completion4->get_return_value()); delete my_completion; delete my_completion2; delete my_completion3; delete my_completion4; } TEST(LibRadosAioEC, OmapPP) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_ec_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); string header_str = "baz"; bufferptr bp(header_str.c_str(), header_str.size() + 1); bufferlist header_to_set; header_to_set.push_back(bp); map to_set; { boost::scoped_ptr my_completion(cluster.aio_create_completion(0, 0, 0)); ObjectWriteOperation op; to_set["foo"] = header_to_set; to_set["foo2"] = header_to_set; to_set["qfoo3"] = header_to_set; op.omap_set(to_set); op.omap_set_header(header_to_set); ioctx.aio_operate("test_obj", my_completion.get(), &op); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } EXPECT_EQ(-EOPNOTSUPP, my_completion->get_return_value()); } ioctx.remove("test_obj"); destroy_one_pool_pp(pool_name, cluster); } TEST(LibRadosAioEC, MultiWrite) { AioTestDataEC test_data; rados_completion_t my_completion, my_completion2, my_completion3; ASSERT_EQ("", test_data.init()); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion)); char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion, buf, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); } ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion2)); ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", my_completion2, buf2, sizeof(buf2), sizeof(buf))); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); } ASSERT_EQ(-EOPNOTSUPP, rados_aio_get_return_value(my_completion2)); char buf3[(sizeof(buf) + sizeof(buf2)) * 3]; memset(buf3, 0, sizeof(buf3)); ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data, set_completion_completeEC, set_completion_safeEC, &my_completion3)); ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", my_completion3, buf3, sizeof(buf3), 0)); { TestAlarm alarm; ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); } ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion3)); ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); rados_aio_release(my_completion); rados_aio_release(my_completion2); rados_aio_release(my_completion3); } TEST(LibRadosAioEC, MultiWritePP) { AioTestDataECPP test_data; ASSERT_EQ("", test_data.init()); AioCompletion *my_completion = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); AioCompletion *my_completion_null = NULL; ASSERT_NE(my_completion, my_completion_null); char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion, bl1, sizeof(buf), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion->wait_for_complete()); } ASSERT_EQ(0, my_completion->get_return_value()); char buf2[64]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion2, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion2, bl2, sizeof(buf2), sizeof(buf))); { TestAlarm alarm; ASSERT_EQ(0, my_completion2->wait_for_complete()); } ASSERT_EQ(-EOPNOTSUPP, my_completion2->get_return_value()); bufferlist bl3; AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion( (void*)&test_data, set_completion_completeEC, set_completion_safeEC); ASSERT_NE(my_completion3, my_completion_null); ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3, &bl3, (sizeof(buf) + sizeof(buf2) * 3), 0)); { TestAlarm alarm; ASSERT_EQ(0, my_completion3->wait_for_complete()); } ASSERT_EQ((int)sizeof(buf), my_completion3->get_return_value()); ASSERT_EQ(sizeof(buf), bl3.length()); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); delete my_completion; delete my_completion2; delete my_completion3; } ceph-0.80.11/src/test/librados/snapshots.cc0000664000175100017510000007520212623076744022601 0ustar jenkins-buildjenkins-build#include "include/rados/librados.hpp" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include #include #include "gtest/gtest.h" #include using namespace librados; using std::string; typedef RadosTest LibRadosSnapshots; typedef RadosTest LibRadosSnapshotsSelfManaged; typedef RadosTestPP LibRadosSnapshotsPP; typedef RadosTestPP LibRadosSnapshotsSelfManagedPP; typedef RadosTestEC LibRadosSnapshotsEC; typedef RadosTestEC LibRadosSnapshotsSelfManagedEC; typedef RadosTestECPP LibRadosSnapshotsECPP; typedef RadosTestECPP LibRadosSnapshotsSelfManagedECPP; const int bufsize = 128; TEST_F(LibRadosSnapshots, SnapList) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snap1")); rados_snap_t snaps[10]; EXPECT_EQ(1, rados_ioctx_snap_list(ioctx, snaps, sizeof(snaps) / sizeof(snaps[0]))); rados_snap_t rid; EXPECT_EQ(0, rados_ioctx_snap_lookup(ioctx, "snap1", &rid)); EXPECT_EQ(rid, snaps[0]); EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1")); } TEST_F(LibRadosSnapshotsPP, SnapListPP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snap1")); std::vector snaps; EXPECT_EQ(0, ioctx.snap_list(&snaps)); EXPECT_EQ(1U, snaps.size()); snap_t rid; EXPECT_EQ(0, ioctx.snap_lookup("snap1", &rid)); EXPECT_EQ(rid, snaps[0]); EXPECT_EQ(0, ioctx.snap_remove("snap1")); } TEST_F(LibRadosSnapshots, SnapRemove) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snap1")); rados_snap_t rid; ASSERT_EQ(0, rados_ioctx_snap_lookup(ioctx, "snap1", &rid)); ASSERT_EQ(-EEXIST, rados_ioctx_snap_create(ioctx, "snap1")); ASSERT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1")); ASSERT_EQ(-ENOENT, rados_ioctx_snap_lookup(ioctx, "snap1", &rid)); } TEST_F(LibRadosSnapshotsPP, SnapRemovePP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snap1")); rados_snap_t rid; ASSERT_EQ(0, ioctx.snap_lookup("snap1", &rid)); ASSERT_EQ(0, ioctx.snap_remove("snap1")); ASSERT_EQ(-ENOENT, ioctx.snap_lookup("snap1", &rid)); } TEST_F(LibRadosSnapshots, Rollback) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snap1")); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); EXPECT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2))); EXPECT_EQ(0, rados_ioctx_snap_rollback(ioctx, "foo", "snap1")); char buf3[sizeof(buf)]; EXPECT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0)); EXPECT_EQ(0, memcmp(buf, buf3, sizeof(buf))); EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1")); } TEST_F(LibRadosSnapshotsPP, RollbackPP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snap1")); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); EXPECT_EQ(0, ioctx.write_full("foo", bl2)); EXPECT_EQ(0, ioctx.snap_rollback("foo", "snap1")); bufferlist bl3; EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0)); EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf))); EXPECT_EQ(0, ioctx.snap_remove("snap1")); } TEST_F(LibRadosSnapshots, SnapGetName) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snapfoo")); rados_snap_t rid; EXPECT_EQ(0, rados_ioctx_snap_lookup(ioctx, "snapfoo", &rid)); EXPECT_EQ(-ENOENT, rados_ioctx_snap_lookup(ioctx, "snapbar", &rid)); char name[128]; memset(name, 0, sizeof(name)); EXPECT_EQ(0, rados_ioctx_snap_get_name(ioctx, rid, name, sizeof(name))); time_t snaptime; EXPECT_EQ(0, rados_ioctx_snap_get_stamp(ioctx, rid, &snaptime)); EXPECT_EQ(0, strcmp(name, "snapfoo")); EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snapfoo")); } TEST_F(LibRadosSnapshotsPP, SnapGetNamePP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snapfoo")); rados_snap_t rid; EXPECT_EQ(0, ioctx.snap_lookup("snapfoo", &rid)); EXPECT_EQ(-ENOENT, ioctx.snap_lookup("snapbar", &rid)); std::string name; EXPECT_EQ(0, ioctx.snap_get_name(rid, &name)); time_t snaptime; EXPECT_EQ(0, ioctx.snap_get_stamp(rid, &snaptime)); EXPECT_EQ(0, strcmp(name.c_str(), "snapfoo")); EXPECT_EQ(0, ioctx.snap_remove("snapfoo")); } TEST_F(LibRadosSnapshotsPP, SnapCreateRemovePP) { // reproduces http://tracker.ceph.com/issues/10262 bufferlist bl; bl.append("foo"); ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0)); ASSERT_EQ(0, ioctx.snap_create("snapfoo")); ASSERT_EQ(0, ioctx.remove("foo")); ASSERT_EQ(0, ioctx.snap_create("snapbar")); librados::ObjectWriteOperation *op = new librados::ObjectWriteOperation(); op->create(false); op->remove(); ASSERT_EQ(0, ioctx.operate("foo", op)); EXPECT_EQ(0, ioctx.snap_remove("snapfoo")); EXPECT_EQ(0, ioctx.snap_remove("snapbar")); } TEST_F(LibRadosSnapshotsSelfManaged, Snap) { std::vector my_snaps; my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0)); rados_ioctx_snap_set_read(ioctx, my_snaps[1]-1); char buf3[sizeof(buf)]; ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf3, sizeof(buf3), 0)); rados_ioctx_snap_set_read(ioctx, my_snaps[1]); ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0)); ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); rados_ioctx_snap_set_read(ioctx, LIBRADOS_SNAP_HEAD); ASSERT_EQ(0, rados_remove(ioctx, "foo")); } TEST_F(LibRadosSnapshotsSelfManaged, Rollback) { std::vector my_snaps; my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0)); rados_ioctx_selfmanaged_snap_rollback(ioctx, "foo", my_snaps[1]); char buf3[sizeof(buf)]; ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0)); ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, rados_remove(ioctx, "foo")); } TEST_F(LibRadosSnapshotsSelfManagedPP, SnapPP) { std::vector my_snaps; my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0)); ioctx.snap_set_read(my_snaps[1]); bufferlist bl3; ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ioctx.snap_set_read(LIBRADOS_SNAP_HEAD); ASSERT_EQ(0, ioctx.remove("foo")); } TEST_F(LibRadosSnapshotsSelfManagedPP, RollbackPP) { std::vector my_snaps; IoCtx readioctx; ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx)); readioctx.set_namespace(ns); readioctx.snap_set_read(LIBRADOS_SNAP_DIR); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); //Write 3 consecutive buffers ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*2)); snap_set_t ss; snap_t head = SNAP_HEAD; ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(1u, ss.clones.size()); ASSERT_EQ(head, ss.clones[0].cloneid); ASSERT_EQ(0u, ss.clones[0].snaps.size()); ASSERT_EQ(0u, ss.clones[0].overlap.size()); ASSERT_EQ(384u, ss.clones[0].size); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); //Change the middle buffer ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize)); //Add another after ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*3)); ASSERT_EQ(-EINVAL, ioctx.list_snaps("foo", &ss)); ObjectReadOperation o; o.list_snaps(&ss, NULL); ASSERT_EQ(-EINVAL, ioctx.operate("foo", &o, NULL)); ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(2u, ss.clones.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid); ASSERT_EQ(1u, ss.clones[0].snaps.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]); ASSERT_EQ(2u, ss.clones[0].overlap.size()); ASSERT_EQ(0u, ss.clones[0].overlap[0].first); ASSERT_EQ(128u, ss.clones[0].overlap[0].second); ASSERT_EQ(256u, ss.clones[0].overlap[1].first); ASSERT_EQ(128u, ss.clones[0].overlap[1].second); ASSERT_EQ(384u, ss.clones[0].size); ASSERT_EQ(head, ss.clones[1].cloneid); ASSERT_EQ(0u, ss.clones[1].snaps.size()); ASSERT_EQ(0u, ss.clones[1].overlap.size()); ASSERT_EQ(512u, ss.clones[1].size); ioctx.selfmanaged_snap_rollback("foo", my_snaps[1]); bufferlist bl3; ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), bufsize)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), bufsize*2)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf))); ASSERT_EQ((int)0, ioctx.read("foo", bl3, sizeof(buf), bufsize*3)); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); readioctx.close(); } TEST_F(LibRadosSnapshotsSelfManagedPP, SnapOverlapPP) { std::vector my_snaps; IoCtx readioctx; ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx)); readioctx.set_namespace(ns); readioctx.snap_set_read(LIBRADOS_SNAP_DIR); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*2)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*4)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*6)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*8)); snap_set_t ss; snap_t head = SNAP_HEAD; ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(1u, ss.clones.size()); ASSERT_EQ(head, ss.clones[0].cloneid); ASSERT_EQ(0u, ss.clones[0].snaps.size()); ASSERT_EQ(0u, ss.clones[0].overlap.size()); ASSERT_EQ(1152u, ss.clones[0].size); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*1)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*3)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*5)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*7)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*9)); ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(2u, ss.clones.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid); ASSERT_EQ(1u, ss.clones[0].snaps.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]); ASSERT_EQ(5u, ss.clones[0].overlap.size()); ASSERT_EQ(0u, ss.clones[0].overlap[0].first); ASSERT_EQ(128u, ss.clones[0].overlap[0].second); ASSERT_EQ(256u, ss.clones[0].overlap[1].first); ASSERT_EQ(128u, ss.clones[0].overlap[1].second); ASSERT_EQ(512u, ss.clones[0].overlap[2].first); ASSERT_EQ(128u, ss.clones[0].overlap[2].second); ASSERT_EQ(768u, ss.clones[0].overlap[3].first); ASSERT_EQ(128u, ss.clones[0].overlap[3].second); ASSERT_EQ(1024u, ss.clones[0].overlap[4].first); ASSERT_EQ(128u, ss.clones[0].overlap[4].second); ASSERT_EQ(1152u, ss.clones[0].size); ASSERT_EQ(head, ss.clones[1].cloneid); ASSERT_EQ(0u, ss.clones[1].snaps.size()); ASSERT_EQ(0u, ss.clones[1].overlap.size()); ASSERT_EQ(1280u, ss.clones[1].size); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char buf3[sizeof(buf)]; memset(buf3, 0xee, sizeof(buf3)); bufferlist bl4; bl4.append(buf3, sizeof(buf3)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*1)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*4)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*5)); ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*8)); ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(3u, ss.clones.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid); ASSERT_EQ(1u, ss.clones[0].snaps.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]); ASSERT_EQ(5u, ss.clones[0].overlap.size()); ASSERT_EQ(0u, ss.clones[0].overlap[0].first); ASSERT_EQ(128u, ss.clones[0].overlap[0].second); ASSERT_EQ(256u, ss.clones[0].overlap[1].first); ASSERT_EQ(128u, ss.clones[0].overlap[1].second); ASSERT_EQ(512u, ss.clones[0].overlap[2].first); ASSERT_EQ(128u, ss.clones[0].overlap[2].second); ASSERT_EQ(768u, ss.clones[0].overlap[3].first); ASSERT_EQ(128u, ss.clones[0].overlap[3].second); ASSERT_EQ(1024u, ss.clones[0].overlap[4].first); ASSERT_EQ(128u, ss.clones[0].overlap[4].second); ASSERT_EQ(1152u, ss.clones[0].size); ASSERT_EQ(my_snaps[2], ss.clones[1].cloneid); ASSERT_EQ(1u, ss.clones[1].snaps.size()); ASSERT_EQ(my_snaps[2], ss.clones[1].snaps[0]); ASSERT_EQ(4u, ss.clones[1].overlap.size()); ASSERT_EQ(0u, ss.clones[1].overlap[0].first); ASSERT_EQ(128u, ss.clones[1].overlap[0].second); ASSERT_EQ(256u, ss.clones[1].overlap[1].first); ASSERT_EQ(256u, ss.clones[1].overlap[1].second); ASSERT_EQ(768u, ss.clones[1].overlap[2].first); ASSERT_EQ(256u, ss.clones[1].overlap[2].second); ASSERT_EQ(1152u, ss.clones[1].overlap[3].first); ASSERT_EQ(128u, ss.clones[1].overlap[3].second); ASSERT_EQ(1280u, ss.clones[1].size); ASSERT_EQ(head, ss.clones[2].cloneid); ASSERT_EQ(0u, ss.clones[2].snaps.size()); ASSERT_EQ(0u, ss.clones[2].overlap.size()); ASSERT_EQ(1280u, ss.clones[2].size); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); readioctx.close(); } // EC testing TEST_F(LibRadosSnapshotsEC, SnapList) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snap1")); rados_snap_t snaps[10]; EXPECT_EQ(1, rados_ioctx_snap_list(ioctx, snaps, sizeof(snaps) / sizeof(snaps[0]))); rados_snap_t rid; EXPECT_EQ(0, rados_ioctx_snap_lookup(ioctx, "snap1", &rid)); EXPECT_EQ(rid, snaps[0]); EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1")); } TEST_F(LibRadosSnapshotsECPP, SnapListPP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snap1")); std::vector snaps; EXPECT_EQ(0, ioctx.snap_list(&snaps)); EXPECT_EQ(1U, snaps.size()); snap_t rid; EXPECT_EQ(0, ioctx.snap_lookup("snap1", &rid)); EXPECT_EQ(rid, snaps[0]); EXPECT_EQ(0, ioctx.snap_remove("snap1")); } TEST_F(LibRadosSnapshotsEC, SnapRemove) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snap1")); rados_snap_t rid; ASSERT_EQ(0, rados_ioctx_snap_lookup(ioctx, "snap1", &rid)); ASSERT_EQ(-EEXIST, rados_ioctx_snap_create(ioctx, "snap1")); ASSERT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1")); ASSERT_EQ(-ENOENT, rados_ioctx_snap_lookup(ioctx, "snap1", &rid)); } TEST_F(LibRadosSnapshotsECPP, SnapRemovePP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snap1")); rados_snap_t rid; ASSERT_EQ(0, ioctx.snap_lookup("snap1", &rid)); ASSERT_EQ(0, ioctx.snap_remove("snap1")); ASSERT_EQ(-ENOENT, ioctx.snap_lookup("snap1", &rid)); } TEST_F(LibRadosSnapshotsEC, Rollback) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snap1")); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); EXPECT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2))); EXPECT_EQ(0, rados_ioctx_snap_rollback(ioctx, "foo", "snap1")); char buf3[sizeof(buf)]; EXPECT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0)); EXPECT_EQ(0, memcmp(buf, buf3, sizeof(buf))); EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1")); } TEST_F(LibRadosSnapshotsECPP, RollbackPP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snap1")); char buf2[sizeof(buf)]; memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); EXPECT_EQ(0, ioctx.write_full("foo", bl2)); EXPECT_EQ(0, ioctx.snap_rollback("foo", "snap1")); bufferlist bl3; EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0)); EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf))); EXPECT_EQ(0, ioctx.snap_remove("snap1")); } TEST_F(LibRadosSnapshotsEC, SnapGetName) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); ASSERT_EQ(0, rados_ioctx_snap_create(ioctx, "snapfoo")); rados_snap_t rid; EXPECT_EQ(0, rados_ioctx_snap_lookup(ioctx, "snapfoo", &rid)); EXPECT_EQ(-ENOENT, rados_ioctx_snap_lookup(ioctx, "snapbar", &rid)); char name[128]; memset(name, 0, sizeof(name)); EXPECT_EQ(0, rados_ioctx_snap_get_name(ioctx, rid, name, sizeof(name))); time_t snaptime; EXPECT_EQ(0, rados_ioctx_snap_get_stamp(ioctx, rid, &snaptime)); EXPECT_EQ(0, strcmp(name, "snapfoo")); EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snapfoo")); } TEST_F(LibRadosSnapshotsECPP, SnapGetNamePP) { char buf[bufsize]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); ASSERT_EQ(0, ioctx.snap_create("snapfoo")); rados_snap_t rid; EXPECT_EQ(0, ioctx.snap_lookup("snapfoo", &rid)); EXPECT_EQ(-ENOENT, ioctx.snap_lookup("snapbar", &rid)); std::string name; EXPECT_EQ(0, ioctx.snap_get_name(rid, &name)); time_t snaptime; EXPECT_EQ(0, ioctx.snap_get_stamp(rid, &snaptime)); EXPECT_EQ(0, strcmp(name.c_str(), "snapfoo")); EXPECT_EQ(0, ioctx.snap_remove("snapfoo")); } TEST_F(LibRadosSnapshotsSelfManagedEC, Snap) { std::vector my_snaps; my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); int bsize = alignment; char *buf = (char *)new char[bsize]; memset(buf, 0xcc, bsize); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, bsize, 0)); my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); char *buf2 = (char *)new char[bsize]; memset(buf2, 0xdd, bsize); ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, bsize, bsize)); rados_ioctx_snap_set_read(ioctx, my_snaps[1]-1); char *buf3 = (char *)new char[bsize*2]; ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf3, bsize*2, 0)); rados_ioctx_snap_set_read(ioctx, my_snaps[1]); ASSERT_EQ(bsize, rados_read(ioctx, "foo", buf3, bsize*2, 0)); ASSERT_EQ(0, memcmp(buf3, buf, bsize)); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); rados_ioctx_snap_set_read(ioctx, LIBRADOS_SNAP_HEAD); ASSERT_EQ(0, rados_remove(ioctx, "foo")); delete[] buf; delete[] buf2; delete[] buf3; } TEST_F(LibRadosSnapshotsSelfManagedEC, Rollback) { std::vector my_snaps; my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); int bsize = alignment; char *buf = (char *)new char[bsize]; memset(buf, 0xcc, bsize); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, bsize, 0)); my_snaps.push_back(-2); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0], &my_snaps[0], my_snaps.size())); ::std::reverse(my_snaps.begin(), my_snaps.end()); char *buf2 = (char *)new char[bsize]; memset(buf2, 0xdd, bsize); ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, bsize, bsize)); rados_ioctx_selfmanaged_snap_rollback(ioctx, "foo", my_snaps[1]); char *buf3 = (char *)new char[bsize*2]; ASSERT_EQ(bsize, rados_read(ioctx, "foo", buf3, bsize*2, 0)); ASSERT_EQ(0, memcmp(buf3, buf, bsize)); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, rados_remove(ioctx, "foo")); delete[] buf; delete[] buf2; delete[] buf3; } TEST_F(LibRadosSnapshotsSelfManagedECPP, SnapPP) { std::vector my_snaps; my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); int bsize = alignment; char *buf = (char *)new char[bsize]; memset(buf, 0xcc, bsize); bufferlist bl1; bl1.append(buf, bsize); ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0)); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char *buf2 = (char *)new char[bsize]; memset(buf2, 0xdd, bsize); bufferlist bl2; bl2.append(buf2, bsize); // Add another aligned buffer ASSERT_EQ(0, ioctx.write("foo", bl2, bsize, bsize)); ioctx.snap_set_read(my_snaps[1]); bufferlist bl3; ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize*3, 0)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize)); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ioctx.snap_set_read(LIBRADOS_SNAP_HEAD); ASSERT_EQ(0, ioctx.remove("foo")); delete[] buf; delete[] buf2; } TEST_F(LibRadosSnapshotsSelfManagedECPP, RollbackPP) { std::vector my_snaps; IoCtx readioctx; ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx)); readioctx.set_namespace(ns); readioctx.snap_set_read(LIBRADOS_SNAP_DIR); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); int bsize = alignment; char *buf = (char *)new char[bsize]; memset(buf, 0xcc, bsize); bufferlist bl1; bl1.append(buf, bsize); //Write 3 consecutive buffers ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0)); ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, bsize)); ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, bsize*2)); snap_set_t ss; snap_t head = SNAP_HEAD; ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(1u, ss.clones.size()); ASSERT_EQ(head, ss.clones[0].cloneid); ASSERT_EQ(0u, ss.clones[0].snaps.size()); ASSERT_EQ(0u, ss.clones[0].overlap.size()); ASSERT_EQ((unsigned)(bsize*3), ss.clones[0].size); my_snaps.push_back(-2); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back())); ::std::reverse(my_snaps.begin(), my_snaps.end()); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); ::std::reverse(my_snaps.begin(), my_snaps.end()); char *buf2 = (char *)new char[bsize]; memset(buf2, 0xdd, bsize); bufferlist bl2; bl2.append(buf2, bsize); //Change the middle buffer //ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize)); //Add another after ASSERT_EQ(0, ioctx.write("foo", bl2, bsize, bsize*3)); ASSERT_EQ(-EINVAL, ioctx.list_snaps("foo", &ss)); ObjectReadOperation o; o.list_snaps(&ss, NULL); ASSERT_EQ(-EINVAL, ioctx.operate("foo", &o, NULL)); ASSERT_EQ(0, readioctx.list_snaps("foo", &ss)); ASSERT_EQ(2u, ss.clones.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid); ASSERT_EQ(1u, ss.clones[0].snaps.size()); ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]); ASSERT_EQ(1u, ss.clones[0].overlap.size()); ASSERT_EQ(0u, ss.clones[0].overlap[0].first); ASSERT_EQ((unsigned)bsize*3, ss.clones[0].overlap[0].second); ASSERT_EQ((unsigned)bsize*3, ss.clones[0].size); ASSERT_EQ(head, ss.clones[1].cloneid); ASSERT_EQ(0u, ss.clones[1].snaps.size()); ASSERT_EQ(0u, ss.clones[1].overlap.size()); ASSERT_EQ((unsigned)bsize*4, ss.clones[1].size); ioctx.selfmanaged_snap_rollback("foo", my_snaps[1]); bufferlist bl3; ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, 0)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize)); ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, bsize)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize)); ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, bsize*2)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize)); ASSERT_EQ(0, ioctx.read("foo", bl3, bsize, bsize*3)); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back())); my_snaps.pop_back(); readioctx.close(); delete[] buf; delete[] buf2; } ceph-0.80.11/src/test/librados/c_read_operations.cc0000664000175100017510000004147112623076744024240 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // Tests for the C API coverage of atomic read operations #include #include #include "include/rados/librados.h" #include "test/librados/test.h" #include "test/librados/TestCase.h" const char *data = "testdata"; const char *obj = "testobj"; const int len = strlen(data); class CReadOpsTest : public RadosTest { protected: void write_object() { // Create an object and write to it ASSERT_EQ(0, rados_write(ioctx, obj, data, len, 0)); } void remove_object() { ASSERT_EQ(0, rados_remove(ioctx, obj)); } int cmp_xattr(const char *xattr, const char *value, size_t value_len, uint8_t cmp_op) { rados_read_op_t op = rados_create_read_op(); rados_read_op_cmpxattr(op, xattr, cmp_op, value, value_len); int r = rados_read_op_operate(op, ioctx, obj, 0); rados_release_read_op(op); return r; } void fetch_and_verify_omap_vals(char const* const* keys, char const* const* vals, const size_t *lens, size_t len) { rados_omap_iter_t iter_vals, iter_keys, iter_vals_by_key; int r_vals, r_keys, r_vals_by_key; rados_read_op_t op = rados_create_read_op(); rados_read_op_omap_get_vals(op, NULL, NULL, 100, &iter_vals, &r_vals); rados_read_op_omap_get_keys(op, NULL, 100, &iter_keys, &r_keys); rados_read_op_omap_get_vals_by_keys(op, keys, len, &iter_vals_by_key, &r_vals_by_key); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); ASSERT_EQ(0, r_vals); ASSERT_EQ(0, r_keys); ASSERT_EQ(0, r_vals_by_key); const char *zeros[len]; size_t zero_lens[len]; memset(zeros, 0, len); memset(zero_lens, 0, len * sizeof(size_t)); compare_omap_vals(keys, vals, lens, len, iter_vals); compare_omap_vals(keys, zeros, zero_lens, len, iter_keys); compare_omap_vals(keys, vals, lens, len, iter_vals_by_key); } void compare_omap_vals(char const* const* keys, char const* const* vals, const size_t *lens, size_t len, rados_omap_iter_t iter) { size_t i = 0; char *key = NULL; char *val = NULL; size_t val_len = 0; while (i < len) { ASSERT_EQ(0, rados_omap_get_next(iter, &key, &val, &val_len)); if (len == 0 && key == NULL && val == NULL) break; if (key) EXPECT_EQ(std::string(keys[i]), std::string(key)); else EXPECT_EQ(keys[i], key); ASSERT_EQ(0, memcmp(vals[i], val, val_len)); ASSERT_EQ(lens[i], val_len); ++i; } ASSERT_EQ(i, len); ASSERT_EQ(0, rados_omap_get_next(iter, &key, &val, &val_len)); ASSERT_EQ((char*)NULL, key); ASSERT_EQ((char*)NULL, val); ASSERT_EQ(0u, val_len); rados_omap_get_end(iter); } void compare_xattrs(char const* const* keys, char const* const* vals, const size_t *lens, size_t len, rados_xattrs_iter_t iter) { size_t i = 0; char *key = NULL; char *val = NULL; size_t val_len = 0; while (i < len) { ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**) &key, (const char**) &val, &val_len)); if (len == 0 && key == NULL && val == NULL) break; EXPECT_EQ(std::string(keys[i]), std::string(key)); EXPECT_EQ(0, memcmp(vals[i], val, val_len)); EXPECT_EQ(lens[i], val_len); ++i; } ASSERT_EQ(i, len); ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**)&key, (const char**)&val, &val_len)); ASSERT_EQ((char*)NULL, key); ASSERT_EQ((char*)NULL, val); ASSERT_EQ(0u, val_len); rados_getxattrs_end(iter); } }; TEST_F(CReadOpsTest, NewDelete) { rados_read_op_t op = rados_create_read_op(); ASSERT_TRUE(op); rados_release_read_op(op); } TEST_F(CReadOpsTest, SetOpFlags) { write_object(); rados_read_op_t op = rados_create_read_op(); size_t bytes_read = 0; char *out = NULL; int rval = 0; rados_read_op_exec(op, "rbd", "get_id", NULL, 0, &out, &bytes_read, &rval); rados_read_op_set_flags(op, LIBRADOS_OP_FLAG_FAILOK); EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); EXPECT_EQ(-EIO, rval); EXPECT_EQ(0u, bytes_read); EXPECT_EQ((char*)NULL, out); rados_release_read_op(op); remove_object(); } TEST_F(CReadOpsTest, AssertExists) { rados_read_op_t op = rados_create_read_op(); rados_read_op_assert_exists(op); ASSERT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); op = rados_create_read_op(); rados_read_op_assert_exists(op); rados_completion_t completion; ASSERT_EQ(0, rados_aio_create_completion(NULL, NULL, NULL, &completion)); ASSERT_EQ(0, rados_aio_read_op_operate(op, ioctx, completion, obj, 0)); rados_aio_wait_for_complete(completion); ASSERT_EQ(-ENOENT, rados_aio_get_return_value(completion)); rados_release_read_op(op); write_object(); op = rados_create_read_op(); rados_read_op_assert_exists(op); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); remove_object(); } TEST_F(CReadOpsTest, CmpXattr) { write_object(); char buf[len]; memset(buf, 0xcc, sizeof(buf)); const char *xattr = "test"; rados_setxattr(ioctx, obj, xattr, buf, sizeof(buf)); // equal value EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_EQ)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_NE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GTE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LTE)); // < value EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_EQ)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_NE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_GT)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_GTE)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_LT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_LTE)); // > value memset(buf, 0xcd, sizeof(buf)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_EQ)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_NE)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GTE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LT)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LTE)); // check that null bytes are compared correctly rados_setxattr(ioctx, obj, xattr, "\0\0", 2); buf[0] = '\0'; EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_EQ)); EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_NE)); EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GTE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LT)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LTE)); buf[1] = '\0'; EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_EQ)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_NE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GTE)); EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LT)); EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LTE)); remove_object(); } TEST_F(CReadOpsTest, Read) { write_object(); char buf[len]; // check that using read_ops returns the same data with // or without bytes_read and rval out params { rados_read_op_t op = rados_create_read_op(); rados_read_op_read(op, 0, len, buf, NULL, NULL); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } { rados_read_op_t op = rados_create_read_op(); int rval; rados_read_op_read(op, 0, len, buf, NULL, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } { rados_read_op_t op = rados_create_read_op(); size_t bytes_read = 0; rados_read_op_read(op, 0, len, buf, &bytes_read, NULL); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(len, (int)bytes_read); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } { rados_read_op_t op = rados_create_read_op(); size_t bytes_read = 0; int rval; rados_read_op_read(op, 0, len, buf, &bytes_read, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(len, (int)bytes_read); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } remove_object(); } TEST_F(CReadOpsTest, ShortRead) { write_object(); char buf[len * 2]; // check that using read_ops returns the same data with // or without bytes_read and rval out params { rados_read_op_t op = rados_create_read_op(); rados_read_op_read(op, 0, len * 2, buf, NULL, NULL); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } { rados_read_op_t op = rados_create_read_op(); int rval; rados_read_op_read(op, 0, len * 2, buf, NULL, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } { rados_read_op_t op = rados_create_read_op(); size_t bytes_read = 0; rados_read_op_read(op, 0, len * 2, buf, &bytes_read, NULL); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(len, (int)bytes_read); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } { rados_read_op_t op = rados_create_read_op(); size_t bytes_read = 0; int rval; rados_read_op_read(op, 0, len * 2, buf, &bytes_read, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); ASSERT_EQ(len, (int)bytes_read); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(data, buf, len)); rados_release_read_op(op); } remove_object(); } TEST_F(CReadOpsTest, Exec) { // create object so we don't get -ENOENT write_object(); rados_read_op_t op = rados_create_read_op(); ASSERT_TRUE(op); size_t bytes_read = 0; char *out = NULL; int rval = 0; rados_read_op_exec(op, "rbd", "get_all_features", NULL, 0, &out, &bytes_read, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); EXPECT_EQ(0, rval); EXPECT_TRUE(out); uint64_t features; EXPECT_EQ(sizeof(features), bytes_read); // make sure buffer is at least as long as it claims ASSERT_TRUE(out[bytes_read-1] == out[bytes_read-1]); rados_buffer_free(out); remove_object(); } TEST_F(CReadOpsTest, ExecUserBuf) { // create object so we don't get -ENOENT write_object(); rados_read_op_t op = rados_create_read_op(); size_t bytes_read = 0; uint64_t features; char out[sizeof(features)]; int rval = 0; rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out, sizeof(out), &bytes_read, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); EXPECT_EQ(0, rval); EXPECT_EQ(sizeof(features), bytes_read); // buffer too short bytes_read = 1024; op = rados_create_read_op(); rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out, sizeof(features) - 1, &bytes_read, &rval); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); EXPECT_EQ(0u, bytes_read); EXPECT_EQ(-ERANGE, rval); // input buffer and no rval or bytes_read op = rados_create_read_op(); rados_read_op_exec_user_buf(op, "rbd", "get_all_features", out, sizeof(out), out, sizeof(out), NULL, NULL); ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); remove_object(); } TEST_F(CReadOpsTest, Stat) { rados_read_op_t op = rados_create_read_op(); uint64_t size = 1; int rval; rados_read_op_stat(op, &size, NULL, &rval); EXPECT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0)); EXPECT_EQ(-EIO, rval); EXPECT_EQ(1u, size); rados_release_read_op(op); write_object(); op = rados_create_read_op(); rados_read_op_stat(op, &size, NULL, &rval); EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); EXPECT_EQ(0, rval); EXPECT_EQ(len, (int)size); rados_release_read_op(op); op = rados_create_read_op(); rados_read_op_stat(op, NULL, NULL, NULL); EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); remove_object(); op = rados_create_read_op(); rados_read_op_stat(op, NULL, NULL, NULL); EXPECT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0)); rados_release_read_op(op); } TEST_F(CReadOpsTest, Omap) { char *keys[] = {(char*)"bar", (char*)"foo", (char*)"test1", (char*)"test2"}; char *vals[] = {(char*)"", (char*)"\0", (char*)"abc", (char*)"va\0lue"}; size_t lens[] = {0, 1, 3, 6}; // check for -ENOENT before the object exists and when it exists // with no omap entries rados_omap_iter_t iter_vals; rados_read_op_t rop = rados_create_read_op(); rados_read_op_omap_get_vals(rop, "", "", 10, &iter_vals, NULL); ASSERT_EQ(-ENOENT, rados_read_op_operate(rop, ioctx, obj, 0)); rados_release_read_op(rop); compare_omap_vals(NULL, NULL, NULL, 0, iter_vals); write_object(); fetch_and_verify_omap_vals(NULL, NULL, NULL, 0); // write and check for the k/v pairs rados_write_op_t op = rados_create_write_op(); rados_write_op_omap_set(op, keys, vals, lens, 4); ASSERT_EQ(0, rados_write_op_operate(op, ioctx, obj, NULL, 0)); rados_release_write_op(op); fetch_and_verify_omap_vals(keys, vals, lens, 4); rados_omap_iter_t iter_keys; int r_vals = -1, r_keys = -1; rop = rados_create_read_op(); rados_read_op_omap_get_vals(rop, "", "test", 1, &iter_vals, &r_vals); rados_read_op_omap_get_keys(rop, "test", 1, &iter_keys, &r_keys); ASSERT_EQ(0, rados_read_op_operate(rop, ioctx, obj, 0)); rados_release_read_op(rop); EXPECT_EQ(0, r_vals); EXPECT_EQ(0, r_keys); compare_omap_vals(&keys[2], &vals[2], &lens[2], 1, iter_vals); compare_omap_vals(&keys[2], &vals[0], &lens[0], 1, iter_keys); // check omap_cmp finds all expected values rop = rados_create_read_op(); int rvals[4]; for (int i = 0; i < 4; ++i) rados_read_op_omap_cmp(rop, keys[i], LIBRADOS_CMPXATTR_OP_EQ, vals[i], lens[i], &rvals[i]); EXPECT_EQ(0, rados_read_op_operate(rop, ioctx, obj, 0)); rados_release_read_op(rop); for (int i = 0; i < 4; ++i) EXPECT_EQ(0, rvals[i]); // try to remove keys with a guard that should fail op = rados_create_write_op(); rados_write_op_omap_cmp(op, keys[2], LIBRADOS_CMPXATTR_OP_LT, vals[2], lens[2], &r_vals); rados_write_op_omap_rm_keys(op, keys, 2); EXPECT_EQ(-ECANCELED, rados_write_op_operate(op, ioctx, obj, NULL, 0)); rados_release_write_op(op); ASSERT_EQ(-ECANCELED, r_vals); // verifying the keys are still there, and then remove them op = rados_create_write_op(); rados_write_op_omap_cmp(op, keys[0], LIBRADOS_CMPXATTR_OP_EQ, vals[0], lens[0], NULL); rados_write_op_omap_cmp(op, keys[1], LIBRADOS_CMPXATTR_OP_EQ, vals[1], lens[1], NULL); rados_write_op_omap_rm_keys(op, keys, 2); EXPECT_EQ(0, rados_write_op_operate(op, ioctx, obj, NULL, 0)); rados_release_write_op(op); fetch_and_verify_omap_vals(&keys[2], &vals[2], &lens[2], 2); // clear the rest and check there are none left op = rados_create_write_op(); rados_write_op_omap_clear(op); EXPECT_EQ(0, rados_write_op_operate(op, ioctx, obj, NULL, 0)); rados_release_write_op(op); fetch_and_verify_omap_vals(NULL, NULL, NULL, 0); remove_object(); } TEST_F(CReadOpsTest, GetXattrs) { write_object(); char *keys[] = {(char*)"bar", (char*)"foo", (char*)"test1", (char*)"test2"}; char *vals[] = {(char*)"", (char*)"\0", (char*)"abc", (char*)"va\0lue"}; size_t lens[] = {0, 1, 3, 6}; int rval = 1; rados_read_op_t op = rados_create_read_op(); rados_xattrs_iter_t it; rados_read_op_getxattrs(op, &it, &rval); EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); EXPECT_EQ(0, rval); rados_release_read_op(op); compare_xattrs(keys, vals, lens, 0, it); for (int i = 0; i < 4; ++i) rados_setxattr(ioctx, obj, keys[i], vals[i], lens[i]); rval = 1; op = rados_create_read_op(); rados_read_op_getxattrs(op, &it, &rval); EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0)); EXPECT_EQ(0, rval); rados_release_read_op(op); compare_xattrs(keys, vals, lens, 4, it); remove_object(); } ceph-0.80.11/src/test/librados/io.cc0000664000175100017510000007452212623076744021172 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -* // vim: ts=8 sw=2 smarttab #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include #include "gtest/gtest.h" using namespace librados; using std::string; typedef RadosTest LibRadosIo; typedef RadosTestEC LibRadosIoEC; typedef RadosTestPP LibRadosIoPP; typedef RadosTestECPP LibRadosIoECPP; TEST_F(LibRadosIo, SimpleWrite) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "nspace"); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); } TEST_F(LibRadosIo, ReadTimeout) { char buf[128]; memset(buf, 'a', sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); { // set up a second client rados_t cluster; rados_ioctx_t ioctx; rados_create(&cluster, "admin"); rados_conf_read_file(cluster, NULL); rados_conf_parse_env(cluster, NULL); rados_conf_set(cluster, "rados_osd_op_timeout", "0.00001"); // use any small value that will result in a timeout rados_connect(cluster); rados_ioctx_create(cluster, pool_name.c_str(), &ioctx); rados_ioctx_set_namespace(ioctx, nspace.c_str()); // then we show that the buffer is changed after rados_read returned // with a timeout for (int i=0; i<5; i++) { char buf2[sizeof(buf)]; memset(buf2, 0, sizeof(buf2)); int err = rados_read(ioctx, "foo", buf2, sizeof(buf2), 0); if (err == -110) { int startIndex = 0; // find the index until which librados already read the object before the timeout occurred for (unsigned b=0; b attrset; ASSERT_EQ(0, ioctx.getxattrs("foo", attrset)); for (std::map::iterator i = attrset.begin(); i != attrset.end(); ++i) { if (i->first == string(attr1)) { ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf))); } else if (i->first == string(attr2)) { ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf))); } else { ASSERT_EQ(0, 1); } } } TEST_F(LibRadosIoEC, SimpleWrite) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); rados_ioctx_set_namespace(ioctx, "nspace"); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); } TEST_F(LibRadosIoECPP, SimpleWritePP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); ioctx.set_namespace("nspace"); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); } TEST_F(LibRadosIoECPP, ReadOpPP) { char buf[128]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); { bufferlist op_bl; ObjectReadOperation op; op.read(0, sizeof(buf), NULL, NULL); ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl)); ASSERT_EQ(sizeof(buf), op_bl.length()); ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf))); } { bufferlist read_bl, op_bl; ObjectReadOperation op; op.read(0, sizeof(buf), &read_bl, NULL); ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl)); ASSERT_EQ(sizeof(buf), read_bl.length()); ASSERT_EQ(sizeof(buf), op_bl.length()); ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf))); } { bufferlist op_bl; int rval = 1000; ObjectReadOperation op; op.read(0, sizeof(buf), NULL, &rval); ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl)); ASSERT_EQ(sizeof(buf), op_bl.length()); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf))); } { bufferlist read_bl, op_bl; int rval = 1000; ObjectReadOperation op; op.read(0, sizeof(buf), &read_bl, &rval); ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl)); ASSERT_EQ(sizeof(buf), read_bl.length()); ASSERT_EQ(sizeof(buf), op_bl.length()); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf))); } { bufferlist read_bl1, read_bl2, op_bl; int rval1 = 1000, rval2 = 1002; ObjectReadOperation op; op.read(0, sizeof(buf), &read_bl1, &rval1); op.read(0, sizeof(buf), &read_bl2, &rval2); ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl)); ASSERT_EQ(sizeof(buf), read_bl1.length()); ASSERT_EQ(sizeof(buf), read_bl2.length()); ASSERT_EQ(sizeof(buf) * 2, op_bl.length()); ASSERT_EQ(0, rval1); ASSERT_EQ(0, rval2); ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf))); } { bufferlist op_bl; ObjectReadOperation op; op.read(0, sizeof(buf), NULL, NULL); ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl)); ASSERT_EQ(sizeof(buf), op_bl.length()); ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf))); } { bufferlist read_bl; ObjectReadOperation op; op.read(0, sizeof(buf), &read_bl, NULL); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_EQ(sizeof(buf), read_bl.length()); ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf))); } { int rval = 1000; ObjectReadOperation op; op.read(0, sizeof(buf), NULL, &rval); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_EQ(0, rval); } { bufferlist read_bl; int rval = 1000; ObjectReadOperation op; op.read(0, sizeof(buf), &read_bl, &rval); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_EQ(sizeof(buf), read_bl.length()); ASSERT_EQ(0, rval); ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf))); } { bufferlist read_bl1, read_bl2; int rval1 = 1000, rval2 = 1002; ObjectReadOperation op; op.read(0, sizeof(buf), &read_bl1, &rval1); op.read(0, sizeof(buf), &read_bl2, &rval2); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_EQ(sizeof(buf), read_bl1.length()); ASSERT_EQ(sizeof(buf), read_bl2.length()); ASSERT_EQ(0, rval1); ASSERT_EQ(0, rval2); ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf))); ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf))); } } TEST_F(LibRadosIoEC, RoundTrip) { char buf[128]; char buf2[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); memset(buf2, 0, sizeof(buf2)); ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0)); ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); } TEST_F(LibRadosIoECPP, RoundTripPP) { char buf[128]; Rados cluster; memset(buf, 0xcc, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0)); bufferlist cl; ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf) * 3, 0)); ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf))); } TEST_F(LibRadosIoEC, OverlappingWriteRoundTrip) { int bsize = alignment; int dbsize = bsize * 2; char *buf = (char *)new char[dbsize]; char *buf2 = (char *)new char[bsize]; char *buf3 = (char *)new char[dbsize]; memset(buf, 0xcc, dbsize); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, dbsize, 0)); memset(buf2, 0xdd, bsize); ASSERT_EQ(-EOPNOTSUPP, rados_write(ioctx, "foo", buf2, bsize, 0)); memset(buf3, 0xdd, dbsize); ASSERT_EQ(dbsize, rados_read(ioctx, "foo", buf3, dbsize, 0)); // Read the same as first write ASSERT_EQ(0, memcmp(buf3, buf, dbsize)); delete[] buf; delete[] buf2; delete[] buf3; } TEST_F(LibRadosIoECPP, OverlappingWriteRoundTripPP) { int bsize = alignment; int dbsize = bsize * 2; char *buf = (char *)new char[dbsize]; char *buf2 = (char *)new char[bsize]; memset(buf, 0xcc, dbsize); bufferlist bl1; bl1.append(buf, dbsize); ASSERT_EQ(0, ioctx.write("foo", bl1, dbsize, 0)); memset(buf2, 0xdd, bsize); bufferlist bl2; bl2.append(buf2, bsize); ASSERT_EQ(-EOPNOTSUPP, ioctx.write("foo", bl2, bsize, 0)); bufferlist bl3; ASSERT_EQ(dbsize, ioctx.read("foo", bl3, dbsize, 0)); // Read the same as first write ASSERT_EQ(0, memcmp(bl3.c_str(), buf, dbsize)); delete[] buf; delete[] buf2; } TEST_F(LibRadosIoEC, WriteFullRoundTrip) { char buf[128]; char buf2[64]; char buf3[128]; memset(buf, 0xcc, sizeof(buf)); ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0)); memset(buf2, 0xdd, sizeof(buf2)); ASSERT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2))); memset(buf3, 0xee, sizeof(buf3)); ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0)); ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2))); } TEST_F(LibRadosIoECPP, WriteFullRoundTripPP) { char buf[128]; char buf2[64]; memset(buf, 0xcc, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0)); memset(buf2, 0xdd, sizeof(buf2)); bufferlist bl2; bl2.append(buf2, sizeof(buf2)); ASSERT_EQ(0, ioctx.write_full("foo", bl2)); bufferlist bl3; ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0)); ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2))); } TEST_F(LibRadosIoEC, AppendRoundTrip) { char *buf = (char *)new char[alignment]; char *buf2 = (char *)new char[alignment]; char *buf3 = (char *)new char[alignment *2]; memset(buf, 0xde, alignment); ASSERT_EQ(0, rados_append(ioctx, "foo", buf, alignment)); memset(buf2, 0xad, alignment); ASSERT_EQ(0, rados_append(ioctx, "foo", buf2, alignment)); memset(buf3, 0, alignment*2); ASSERT_EQ((int)alignment*2, rados_read(ioctx, "foo", buf3, alignment*2, 0)); ASSERT_EQ(0, memcmp(buf3, buf, alignment)); ASSERT_EQ(0, memcmp(buf3 + alignment, buf2, alignment)); int uasize = alignment/2; char *unalignedbuf = (char *)new char[uasize]; ASSERT_EQ(0, rados_append(ioctx, "foo", unalignedbuf, uasize)); ASSERT_EQ(-EOPNOTSUPP, rados_append(ioctx, "foo", unalignedbuf, uasize)); delete[] buf; delete[] buf2; delete[] buf3; delete[] unalignedbuf; } TEST_F(LibRadosIoECPP, AppendRoundTripPP) { char *buf = (char *)new char[alignment]; char *buf2 = (char *)new char[alignment]; memset(buf, 0xde, alignment); bufferlist bl1; bl1.append(buf, alignment); ASSERT_EQ(0, ioctx.append("foo", bl1, alignment)); memset(buf2, 0xad, alignment); bufferlist bl2; bl2.append(buf2, alignment); ASSERT_EQ(0, ioctx.append("foo", bl2, alignment)); bufferlist bl3; ASSERT_EQ((int)(alignment * 2), ioctx.read("foo", bl3, (alignment * 4), 0)); const char *bl3_str = bl3.c_str(); ASSERT_EQ(0, memcmp(bl3_str, buf, alignment)); ASSERT_EQ(0, memcmp(bl3_str + alignment, buf2, alignment)); delete[] buf; delete[] buf2; } TEST_F(LibRadosIoEC, TruncTest) { char buf[128]; char buf2[sizeof(buf)]; memset(buf, 0xaa, sizeof(buf)); ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf))); ASSERT_EQ(-EOPNOTSUPP, rados_trunc(ioctx, "foo", sizeof(buf) / 2)); memset(buf2, 0, sizeof(buf2)); // Same size ASSERT_EQ((int)sizeof(buf), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0)); // No change ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); } TEST_F(LibRadosIoECPP, TruncTestPP) { char buf[128]; memset(buf, 0xaa, sizeof(buf)); bufferlist bl; bl.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf))); ASSERT_EQ(-EOPNOTSUPP, ioctx.trunc("foo", sizeof(buf) / 2)); bufferlist bl2; // Same size ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl2, sizeof(buf), 0)); // No change ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf))); } TEST_F(LibRadosIoEC, RemoveTest) { char buf[128]; char buf2[sizeof(buf)]; memset(buf, 0xaa, sizeof(buf)); ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf))); ASSERT_EQ(0, rados_remove(ioctx, "foo")); memset(buf2, 0, sizeof(buf2)); ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0)); } TEST_F(LibRadosIoECPP, RemoveTestPP) { char buf[128]; memset(buf, 0xaa, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf))); ASSERT_EQ(0, ioctx.remove("foo")); bufferlist bl2; ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0)); } TEST_F(LibRadosIoEC, XattrsRoundTrip) { char buf[128]; char attr1[] = "attr1"; char attr1_buf[] = "foo bar baz"; memset(buf, 0xaa, sizeof(buf)); ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf))); ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf))); ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf))); ASSERT_EQ((int)sizeof(attr1_buf), rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf))); ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf))); } TEST_F(LibRadosIoECPP, XattrsRoundTripPP) { char buf[128]; char attr1[] = "attr1"; char attr1_buf[] = "foo bar baz"; memset(buf, 0xaa, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf))); bufferlist bl2; ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2)); bufferlist bl3; bl3.append(attr1_buf, sizeof(attr1_buf)); ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3)); bufferlist bl4; ASSERT_EQ((int)sizeof(attr1_buf), ioctx.getxattr("foo", attr1, bl4)); ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf))); } TEST_F(LibRadosIoEC, RmXattr) { char buf[128]; char attr1[] = "attr1"; char attr1_buf[] = "foo bar baz"; memset(buf, 0xaa, sizeof(buf)); ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf))); ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf))); ASSERT_EQ(0, rados_rmxattr(ioctx, "foo", attr1)); ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf))); } TEST_F(LibRadosIoECPP, RmXattrPP) { char buf[128]; char attr1[] = "attr1"; char attr1_buf[] = "foo bar baz"; memset(buf, 0xaa, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf))); bufferlist bl2; bl2.append(attr1_buf, sizeof(attr1_buf)); ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2)); ASSERT_EQ(0, ioctx.rmxattr("foo", attr1)); bufferlist bl3; ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3)); } TEST_F(LibRadosIoEC, XattrIter) { char buf[128]; char attr1[] = "attr1"; char attr1_buf[] = "foo bar baz"; char attr2[] = "attr2"; char attr2_buf[256]; for (size_t j = 0; j < sizeof(attr2_buf); ++j) { attr2_buf[j] = j % 0xff; } memset(buf, 0xaa, sizeof(buf)); ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf))); ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf))); ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf))); rados_xattrs_iter_t iter; ASSERT_EQ(0, rados_getxattrs(ioctx, "foo", &iter)); int num_seen = 0; while (true) { const char *name; const char *val; size_t len; ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len)); if (name == NULL) { break; } ASSERT_LT(num_seen, 2); if ((strcmp(name, attr1) == 0) && (memcmp(val, attr1_buf, len) == 0)) { num_seen++; continue; } else if ((strcmp(name, attr2) == 0) && (memcmp(val, attr2_buf, len) == 0)) { num_seen++; continue; } else { ASSERT_EQ(0, 1); } } rados_getxattrs_end(iter); } TEST_F(LibRadosIoECPP, XattrListPP) { char buf[128]; char attr1[] = "attr1"; char attr1_buf[] = "foo bar baz"; char attr2[] = "attr2"; char attr2_buf[256]; for (size_t j = 0; j < sizeof(attr2_buf); ++j) { attr2_buf[j] = j % 0xff; } memset(buf, 0xaa, sizeof(buf)); bufferlist bl1; bl1.append(buf, sizeof(buf)); ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf))); bufferlist bl2; bl2.append(attr1_buf, sizeof(attr1_buf)); ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2)); bufferlist bl3; bl3.append(attr2_buf, sizeof(attr2_buf)); ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3)); std::map attrset; ASSERT_EQ(0, ioctx.getxattrs("foo", attrset)); for (std::map::iterator i = attrset.begin(); i != attrset.end(); ++i) { if (i->first == string(attr1)) { ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf))); } else if (i->first == string(attr2)) { ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf))); } else { ASSERT_EQ(0, 1); } } } ceph-0.80.11/src/test/librados/tier.cc0000664000175100017510000035225312623076744021526 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "gtest/gtest.h" #include "mds/mdstypes.h" #include "include/buffer.h" #include "include/rbd_types.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/stringify.h" #include "include/types.h" #include "global/global_context.h" #include "global/global_init.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/Cond.h" #include "test/librados/test.h" #include "test/librados/TestCase.h" #include "json_spirit/json_spirit.h" #include "osd/HitSet.h" #include #include #include #include using namespace librados; using ceph::buffer; using std::map; using std::ostringstream; using std::string; typedef RadosTestPP LibRadosTierPP; typedef RadosTestECPP LibRadosTierECPP; void flush_evict_all(librados::Rados& cluster, librados::IoCtx& cache_ioctx) { bufferlist inbl; cache_ioctx.set_namespace(""); for (ObjectIterator it = cache_ioctx.objects_begin(); it != cache_ioctx.objects_end(); ++it) { cache_ioctx.locator_set_key(it->second); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); cache_ioctx.aio_operate( it->first, completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL); completion->wait_for_safe(); completion->get_return_value(); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); cache_ioctx.aio_operate( it->first, completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL); completion->wait_for_safe(); completion->get_return_value(); completion->release(); } } } class LibRadosTwoPoolsPP : public RadosTestPP { public: LibRadosTwoPoolsPP() {}; virtual ~LibRadosTwoPoolsPP() {}; protected: static void SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster)); } static void TearDownTestCase() { ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster)); } static std::string cache_pool_name; virtual void SetUp() { cache_pool_name = get_temp_pool_name(); ASSERT_EQ(0, s_cluster.pool_create(cache_pool_name.c_str())); RadosTestPP::SetUp(); ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); cache_ioctx.set_namespace(ns); } virtual void TearDown() { RadosTestPP::TearDown(); // flush + evict cache flush_evict_all(cluster, cache_ioctx); bufferlist inbl; // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle before next test cluster.wait_for_latest_osdmap(); cleanup_default_namespace(cache_ioctx); cache_ioctx.close(); ASSERT_EQ(0, s_cluster.pool_delete(cache_pool_name.c_str())); } librados::IoCtx cache_ioctx; }; std::string LibRadosTwoPoolsPP::cache_pool_name; TEST_F(LibRadosTierPP, Dirty) { { ObjectWriteOperation op; op.undirty(); ASSERT_EQ(0, ioctx.operate("foo", &op)); // still get 0 if it dne } { ObjectWriteOperation op; op.create(true); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); } { ObjectWriteOperation op; op.undirty(); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { ObjectWriteOperation op; op.undirty(); ASSERT_EQ(0, ioctx.operate("foo", &op)); // still 0 if already clean } { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_FALSE(dirty); ASSERT_EQ(0, r); } { ObjectWriteOperation op; op.truncate(0); // still a write even tho it is a no-op ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); } } TEST_F(LibRadosTwoPoolsPP, Overlay) { // create objects { bufferlist bl; bl.append("base"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("cache"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, cache_ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // by default, the overlay sends us to cache pool { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } { bufferlist bl; ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // unless we say otherwise { bufferlist bl; ObjectReadOperation op; op.read(0, 1, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); ASSERT_EQ('b', bl[0]); } } TEST_F(LibRadosTwoPoolsPP, Promote) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); } // read, trigger a whiteout { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } } TEST_F(LibRadosTwoPoolsPP, PromoteSnap) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { ObjectWriteOperation op; op.remove(); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote on the head { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } { bufferlist bl; ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); // read foo snap { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // read bar snap { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // read baz snap { bufferlist bl; ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } ioctx.snap_set_read(librados::SNAP_HEAD); // read foo { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // read bar { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // read baz { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("baz", bl, 1, 0)); } } TEST_F(LibRadosTwoPoolsPP, PromoteSnapScrub) { int num = 100; // create objects for (int i=0; i my_snaps; for (int snap=0; snap<4; ++snap) { // create a snapshot, clone vector ns(1); ns.insert(ns.end(), my_snaps.begin(), my_snaps.end()); my_snaps.swap(ns); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); cout << "my_snaps " << my_snaps << std::endl; ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); for (int i=0; i num - 3) { bufferlist bl; ASSERT_EQ(1, ioctx.read(string("foo") + stringify(i), bl, 1, 0)); ASSERT_EQ('c', bl[0]); } } for (unsigned snap = 0; snap < my_snaps.size(); ++snap) { cout << "promoting from clones for snap " << my_snaps[snap] << std::endl; ioctx.snap_set_read(my_snaps[snap]); // read some snaps, semi-randomly for (int i=0; i<50; ++i) { bufferlist bl; string o = string("foo") + stringify((snap * i * 137) % 80); //cout << o << std::endl; ASSERT_EQ(1, ioctx.read(o, bl, 1, 0)); } } // ok, stop and scrub this pool (to make sure scrub can handle // missing clones in the cache tier). { IoCtx cache_ioctx; ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); for (int i=0; i<10; ++i) { ostringstream ss; ss << "{\"prefix\": \"pg scrub\", \"pgid\": \"" << cache_ioctx.get_id() << "." << i << "\"}"; cluster.mon_command(ss.str(), inbl, NULL, NULL); } // give it a few seconds to go. this is sloppy but is usually enough time cout << "waiting for scrubs..." << std::endl; sleep(30); cout << "done waiting" << std::endl; } ioctx.snap_set_read(librados::SNAP_HEAD); } TEST_F(LibRadosTwoPoolsPP, PromoteSnapTrimRace) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // delete the snap ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps[0])); ioctx.snap_set_read(my_snaps[0]); // read foo snap { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("foo", bl, 1, 0)); } } TEST_F(LibRadosTwoPoolsPP, Whiteout) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create some whiteouts, verify they behave ASSERT_EQ(0, ioctx.remove("foo")); ASSERT_EQ(-ENOENT, ioctx.remove("bar")); ASSERT_EQ(-ENOENT, ioctx.remove("bar")); // verify the whiteouts are there in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // delete a whiteout and verify it goes away ASSERT_EQ(-ENOENT, ioctx.remove("foo")); { ObjectWriteOperation op; op.remove(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op, librados::OPERATION_IGNORE_CACHE)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // recreate an object and verify we can read it { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } } TEST_F(LibRadosTwoPoolsPP, Evict) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); } // read, trigger a whiteout, and a dirty object { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ(0, ioctx.write("bar", bl, bl.length(), 0)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // evict { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "fooberdoodle", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } } TEST_F(LibRadosTwoPoolsPP, EvictSnap) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { ObjectWriteOperation op; op.remove(); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote on the head { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } { bufferlist bl; ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // evict bam { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "bam", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "bam", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } // read foo snap ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // evict foo snap { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // snap is gone... { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } // head is still there... ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // promote head + snap of bar ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // evict bar head (fail) ioctx.snap_set_read(librados::SNAP_HEAD); { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } // evict bar snap ioctx.snap_set_read(my_snaps[0]); { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // ...and then head ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } } // this test case reproduces http://tracker.ceph.com/issues/8629 TEST_F(LibRadosTwoPoolsPP, EvictSnap2) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote on the head { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // evict { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify the snapdir is not present in the cache pool { ObjectReadOperation op; librados::snap_set_t snapset; op.list_snaps(&snapset, NULL); ioctx.snap_set_read(librados::SNAP_DIR); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } } TEST_F(LibRadosTwoPoolsPP, TryFlush) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // verify the object is NOT present in the base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } // verify dirty { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); } // flush { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify clean { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_FALSE(dirty); ASSERT_EQ(0, r); } // verify in base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it != ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == ioctx.objects_end()); } // evict it { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify no longer in cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } } TEST_F(LibRadosTwoPoolsPP, Flush) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); uint64_t user_version = 0; // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // verify the object is NOT present in the base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } // verify dirty { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); user_version = cache_ioctx.get_last_version(); } // flush { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify clean { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_FALSE(dirty); ASSERT_EQ(0, r); } // verify in base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it != ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == ioctx.objects_end()); } // evict it { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify no longer in cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } // read it again and verify the version is consistent { bufferlist bl; ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0)); ASSERT_EQ(user_version, cache_ioctx.get_last_version()); } // erase it { ObjectWriteOperation op; op.remove(); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush whiteout { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // evict { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify no longer in cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } // or base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } } TEST_F(LibRadosTwoPoolsPP, FlushSnap) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create object { bufferlist bl; bl.append("a"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("b"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // and another my_snaps.resize(2); my_snaps[1] = my_snaps[0]; ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("c"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // verify the object is NOT present in the base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } // flush on head (should fail) ioctx.snap_set_read(librados::SNAP_HEAD); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } // flush on recent snap (should fail) ioctx.snap_set_read(my_snaps[0]); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } // flush on oldest snap ioctx.snap_set_read(my_snaps[1]); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // flush on next oldest snap ioctx.snap_set_read(my_snaps[0]); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // flush on head ioctx.snap_set_read(librados::SNAP_HEAD); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify i can read the snaps from the cache pool ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('b', bl[0]); } ioctx.snap_set_read(my_snaps[1]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('a', bl[0]); } // remove overlay ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); // verify i can read the snaps from the base pool ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('b', bl[0]); } ioctx.snap_set_read(my_snaps[1]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('a', bl[0]); } ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); } TEST_F(LibRadosTierPP, FlushWriteRaces) { Rados cluster; std::string pool_name = get_temp_pool_name(); std::string cache_pool_name = pool_name + "-cache"; ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str())); IoCtx cache_ioctx; ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); IoCtx ioctx; ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx)); // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create/dirty object bufferlist bl; bl.append("hi there"); { ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush + write { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); ObjectWriteOperation op2; op2.write_full(bl); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion2, &op2, 0)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } int tries = 1000; do { // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // try-flush + write { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); ObjectWriteOperation op2; op2.write_full(bl); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate("foo", completion2, &op2, 0)); completion->wait_for_safe(); completion2->wait_for_safe(); int r = completion->get_return_value(); ASSERT_TRUE(r == -EBUSY || r == 0); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); if (r == -EBUSY) break; cout << "didn't get EBUSY, trying again" << std::endl; } ASSERT_TRUE(--tries); } while (true); // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle before next test cluster.wait_for_latest_osdmap(); ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str())); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST_F(LibRadosTwoPoolsPP, FlushTryFlushRaces) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush + flush { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); ObjectReadOperation op2; op2.cache_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush + try-flush { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); ObjectReadOperation op2; op2.cache_try_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } // create/dirty object int tries = 1000; do { { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // try-flush + flush // (flush will not piggyback on try-flush) { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); ObjectReadOperation op2; op2.cache_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); int r = completion->get_return_value(); ASSERT_TRUE(r == -EBUSY || r == 0); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); if (r == -EBUSY) break; cout << "didn't get EBUSY, trying again" << std::endl; } ASSERT_TRUE(--tries); } while (true); // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // try-flush + try-flush { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); ObjectReadOperation op2; op2.cache_try_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } } IoCtx *read_ioctx = 0; Mutex test_lock("FlushReadRaces::lock"); Cond cond; int max_reads = 100; int num_reads = 0; // in progress void flush_read_race_cb(completion_t cb, void *arg); void start_flush_read() { //cout << " starting read" << std::endl; ObjectReadOperation op; op.stat(NULL, NULL, NULL); librados::AioCompletion *completion = librados::Rados::aio_create_completion(); completion->set_complete_callback(0, flush_read_race_cb); read_ioctx->aio_operate("foo", completion, &op, NULL); } void flush_read_race_cb(completion_t cb, void *arg) { //cout << " finished read" << std::endl; test_lock.Lock(); if (num_reads > max_reads) { num_reads--; cond.Signal(); } else { start_flush_read(); } // fixme: i'm leaking cb... test_lock.Unlock(); } TEST_F(LibRadosTwoPoolsPP, TryFlushReadRace) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create/dirty object { bufferlist bl; bl.append("hi there"); bufferptr bp(4000000); // make it big! bp.zero(); bl.append(bp); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // start a continuous stream of reads read_ioctx = &ioctx; test_lock.Lock(); for (int i = 0; i < max_reads; ++i) { start_flush_read(); num_reads++; } test_lock.Unlock(); // try-flush ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); // stop reads test_lock.Lock(); max_reads = 0; while (num_reads > 0) cond.Wait(test_lock); test_lock.Unlock(); } TEST_F(LibRadosTierPP, HitSetNone) { { list< pair > ls; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, ioctx.hit_set_list(123, c, &ls)); c->wait_for_complete(); ASSERT_EQ(0, c->get_return_value()); ASSERT_TRUE(ls.empty()); c->release(); } { bufferlist bl; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, ioctx.hit_set_get(123, c, 12345, &bl)); c->wait_for_complete(); ASSERT_EQ(-ENOENT, c->get_return_value()); c->release(); } } string set_pool_str(string pool, string var, string val) { return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool + string("\",\"var\": \"") + var + string("\",\"val\": \"") + val + string("\"}"); } string set_pool_str(string pool, string var, int val) { return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool + string("\",\"var\": \"") + var + string("\",\"val\": \"") + stringify(val) + string("\"}"); } TEST_F(LibRadosTwoPoolsPP, HitSetRead) { // make it a tier bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); // enable hitset tracking for this pool ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 2), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "explicit_object"), inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); cache_ioctx.set_namespace(""); // keep reading until we see our object appear in the HitSet utime_t start = ceph_clock_now(NULL); utime_t hard_stop = start + utime_t(600, 0); while (true) { utime_t now = ceph_clock_now(NULL); ASSERT_TRUE(now < hard_stop); string name = "foo"; uint32_t hash = cache_ioctx.get_object_hash_position(name); hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash, cluster.pool_lookup(cache_pool_name.c_str()), ""); bufferlist bl; ASSERT_EQ(-ENOENT, cache_ioctx.read("foo", bl, 1, 0)); bufferlist hbl; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, cache_ioctx.hit_set_get(hash, c, now.sec(), &hbl)); c->wait_for_complete(); c->release(); if (hbl.length()) { bufferlist::iterator p = hbl.begin(); HitSet hs; ::decode(hs, p); if (hs.contains(oid)) { cout << "ok, hit_set contains " << oid << std::endl; break; } cout << "hmm, not in HitSet yet" << std::endl; } else { cout << "hmm, no HitSet yet" << std::endl; } sleep(1); } } static int _get_pg_num(Rados& cluster, string pool_name) { bufferlist inbl; string cmd = string("{\"prefix\": \"osd pool get\",\"pool\":\"") + pool_name + string("\",\"var\": \"pg_num\",\"format\": \"json\"}"); bufferlist outbl; int r = cluster.mon_command(cmd, inbl, &outbl, NULL); assert(r >= 0); string outstr(outbl.c_str(), outbl.length()); json_spirit::Value v; if (!json_spirit::read(outstr, v)) { cerr <<" unable to parse json " << outstr << std::endl; return -1; } json_spirit::Object& o = v.get_obj(); for (json_spirit::Object::size_type i=0; i 0); // make it a tier bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); // enable hitset tracking for this pool ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 8), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "explicit_hash"), inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); cache_ioctx.set_namespace(""); int num = 200; // do a bunch of writes for (int i=0; i hitsets; for (int i=0; i > ls; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, cache_ioctx.hit_set_list(i, c, &ls)); c->wait_for_complete(); c->release(); std::cout << "pg " << i << " ls " << ls << std::endl; ASSERT_FALSE(ls.empty()); // get the latest c = librados::Rados::aio_create_completion(); bufferlist bl; ASSERT_EQ(0, cache_ioctx.hit_set_get(i, c, ls.back().first, &bl)); c->wait_for_complete(); c->release(); //std::cout << "bl len is " << bl.length() << "\n"; //bl.hexdump(std::cout); //std::cout << std::endl; bufferlist::iterator p = bl.begin(); ::decode(hitsets[i], p); // cope with racing splits by refreshing pg_num if (i == num_pg - 1) num_pg = _get_pg_num(cluster, cache_pool_name); } for (int i=0; i > ls; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, cache_ioctx.hit_set_list(hash, c, &ls)); c->wait_for_complete(); c->release(); ASSERT_TRUE(ls.size() <= count + 1); cout << " got ls " << ls << std::endl; if (!ls.empty()) { if (!first) { first = ls.front().first; cout << "first is " << first << std::endl; } else { if (ls.front().first != first) { cout << "first now " << ls.front().first << ", trimmed" << std::endl; break; } } } utime_t now = ceph_clock_now(NULL); ASSERT_TRUE(now < hard_stop); sleep(1); } } TEST_F(LibRadosTwoPoolsPP, PromoteOn2ndRead) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // enable hitset tracking for this pool ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "hit_set_count", 2), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "hit_set_period", 600), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "hit_set_type", "bloom"), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1), inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // 1st read, don't trigger a promote { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); } // verify the object is NOT present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } // Read until the object is present in the cache tier while (true) { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ObjectIterator it = cache_ioctx.objects_begin(); if (it != cache_ioctx.objects_end()) { ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); break; } sleep(1); } // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle before next test cluster.wait_for_latest_osdmap(); } class LibRadosTwoPoolsECPP : public RadosTestECPP { public: LibRadosTwoPoolsECPP() {}; virtual ~LibRadosTwoPoolsECPP() {}; protected: static void SetUpTestCase() { pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster)); } static void TearDownTestCase() { ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster)); } static std::string cache_pool_name; virtual void SetUp() { cache_pool_name = get_temp_pool_name(); ASSERT_EQ(0, s_cluster.pool_create(cache_pool_name.c_str())); RadosTestECPP::SetUp(); ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); cache_ioctx.set_namespace(ns); } virtual void TearDown() { RadosTestECPP::TearDown(); // flush + evict cache flush_evict_all(cluster, cache_ioctx); bufferlist inbl; // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle before next test cluster.wait_for_latest_osdmap(); cleanup_default_namespace(cache_ioctx); cache_ioctx.close(); ASSERT_EQ(0, s_cluster.pool_delete(cache_pool_name.c_str())); } librados::IoCtx cache_ioctx; }; std::string LibRadosTwoPoolsECPP::cache_pool_name; TEST_F(LibRadosTierECPP, Dirty) { { ObjectWriteOperation op; op.undirty(); ASSERT_EQ(0, ioctx.operate("foo", &op)); // still get 0 if it dne } { ObjectWriteOperation op; op.create(true); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); } { ObjectWriteOperation op; op.undirty(); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { ObjectWriteOperation op; op.undirty(); ASSERT_EQ(0, ioctx.operate("foo", &op)); // still 0 if already clean } { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); ASSERT_FALSE(dirty); ASSERT_EQ(0, r); } //{ // ObjectWriteOperation op; // op.truncate(0); // still a write even tho it is a no-op // ASSERT_EQ(0, ioctx.operate("foo", &op)); //} //{ // bool dirty = false; // int r = -1; // ObjectReadOperation op; // op.is_dirty(&dirty, &r); // ASSERT_EQ(0, ioctx.operate("foo", &op, NULL)); // ASSERT_TRUE(dirty); // ASSERT_EQ(0, r); //} } TEST_F(LibRadosTwoPoolsECPP, Overlay) { // create objects { bufferlist bl; bl.append("base"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("cache"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, cache_ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // by default, the overlay sends us to cache pool { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } { bufferlist bl; ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // unless we say otherwise { bufferlist bl; ObjectReadOperation op; op.read(0, 1, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); ASSERT_EQ('b', bl[0]); } } TEST_F(LibRadosTwoPoolsECPP, Promote) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); } // read, trigger a whiteout { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } } TEST_F(LibRadosTwoPoolsECPP, PromoteSnap) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { ObjectWriteOperation op; op.remove(); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote on the head { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } { bufferlist bl; ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); // stop and scrub this pg (to make sure scrub can handle missing // clones in the cache tier) // This test requires cache tier and base tier to have the same pg_num/pgp_num { for (int tries = 0; tries < 5; ++tries) { IoCtx cache_ioctx; ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); ostringstream ss; ss << "{\"prefix\": \"pg scrub\", \"pgid\": \"" << cache_ioctx.get_id() << "." << ioctx.get_object_pg_hash_position("foo") << "\"}"; int r = cluster.mon_command(ss.str(), inbl, NULL, NULL); if (r == -EAGAIN) continue; ASSERT_EQ(0, r); break; } // give it a few seconds to go. this is sloppy but is usually enough time cout << "waiting for scrub..." << std::endl; sleep(15); cout << "done waiting" << std::endl; } // read foo snap { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // read bar snap { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // read baz snap { bufferlist bl; ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } ioctx.snap_set_read(librados::SNAP_HEAD); // read foo { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // read bar { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // read baz { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("baz", bl, 1, 0)); } } TEST_F(LibRadosTwoPoolsECPP, PromoteSnapTrimRace) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // delete the snap ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps[0])); ioctx.snap_set_read(my_snaps[0]); // read foo snap { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("foo", bl, 1, 0)); } } TEST_F(LibRadosTwoPoolsECPP, Whiteout) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create some whiteouts, verify they behave ASSERT_EQ(0, ioctx.remove("foo")); ASSERT_EQ(-ENOENT, ioctx.remove("bar")); ASSERT_EQ(-ENOENT, ioctx.remove("bar")); // verify the whiteouts are there in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // delete a whiteout and verify it goes away ASSERT_EQ(-ENOENT, ioctx.remove("foo")); { ObjectWriteOperation op; op.remove(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op, librados::OPERATION_IGNORE_CACHE)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // recreate an object and verify we can read it { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } } TEST_F(LibRadosTwoPoolsECPP, Evict) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); } // read, trigger a whiteout, and a dirty object { bufferlist bl; ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ(0, ioctx.write("bar", bl, bl.length(), 0)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it->first == string("foo") || it->first == string("bar")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // evict { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "fooberdoodle", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } } TEST_F(LibRadosTwoPoolsECPP, EvictSnap) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bar", &op)); } { ObjectWriteOperation op; op.remove(); ASSERT_EQ(0, ioctx.operate("baz", &op)); } { bufferlist bl; bl.append("ciao!"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("bam", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // read, trigger a promote on the head { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } { bufferlist bl; ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } // evict bam { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "bam", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "bam", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } // read foo snap ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // evict foo snap { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // snap is gone... { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-ENOENT, completion->get_return_value()); completion->release(); } // head is still there... ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // promote head + snap of bar ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0)); ASSERT_EQ('h', bl[0]); } // evict bar head (fail) ioctx.snap_set_read(librados::SNAP_HEAD); { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } // evict bar snap ioctx.snap_set_read(my_snaps[0]); { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // ...and then head ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ObjectReadOperation op; op.read(1, 0, &bl, NULL); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "bar", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } } TEST_F(LibRadosTwoPoolsECPP, TryFlush) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // verify the object is NOT present in the base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } // verify dirty { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); } // flush { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify clean { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_FALSE(dirty); ASSERT_EQ(0, r); } // verify in base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it != ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == ioctx.objects_end()); } // evict it { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify no longer in cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } } TEST_F(LibRadosTwoPoolsECPP, Flush) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); uint64_t user_version = 0; // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // verify the object is NOT present in the base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } // verify dirty { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_TRUE(dirty); ASSERT_EQ(0, r); user_version = cache_ioctx.get_last_version(); } // flush { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify clean { bool dirty = false; int r = -1; ObjectReadOperation op; op.is_dirty(&dirty, &r); ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL)); ASSERT_FALSE(dirty); ASSERT_EQ(0, r); } // verify in base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it != ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == ioctx.objects_end()); } // evict it { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify no longer in cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } // read it again and verify the version is consistent { bufferlist bl; ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0)); ASSERT_EQ(user_version, cache_ioctx.get_last_version()); } // erase it { ObjectWriteOperation op; op.remove(); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush whiteout { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // evict { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify no longer in cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } // or base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } } TEST_F(LibRadosTwoPoolsECPP, FlushSnap) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create object { bufferlist bl; bl.append("a"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // create a snapshot, clone vector my_snaps(1); ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("b"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // and another my_snaps.resize(2); my_snaps[1] = my_snaps[0]; ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0])); ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps)); { bufferlist bl; bl.append("c"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // verify the object is present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it != cache_ioctx.objects_end()); ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); } // verify the object is NOT present in the base tier { ObjectIterator it = ioctx.objects_begin(); ASSERT_TRUE(it == ioctx.objects_end()); } // flush on head (should fail) ioctx.snap_set_read(librados::SNAP_HEAD); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } // flush on recent snap (should fail) ioctx.snap_set_read(my_snaps[0]); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(-EBUSY, completion->get_return_value()); completion->release(); } // flush on oldest snap ioctx.snap_set_read(my_snaps[1]); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // flush on next oldest snap ioctx.snap_set_read(my_snaps[0]); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // flush on head ioctx.snap_set_read(librados::SNAP_HEAD); { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); } // verify i can read the snaps from the cache pool ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('b', bl[0]); } ioctx.snap_set_read(my_snaps[1]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('a', bl[0]); } // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // verify i can read the snaps from the base pool ioctx.snap_set_read(librados::SNAP_HEAD); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('c', bl[0]); } ioctx.snap_set_read(my_snaps[0]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('b', bl[0]); } ioctx.snap_set_read(my_snaps[1]); { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ASSERT_EQ('a', bl[0]); } ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); } TEST_F(LibRadosTierECPP, FlushWriteRaces) { Rados cluster; std::string pool_name = get_temp_pool_name(); std::string cache_pool_name = pool_name + "-cache"; ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str())); IoCtx cache_ioctx; ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx)); IoCtx ioctx; ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx)); // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create/dirty object bufferlist bl; bl.append("hi there"); { ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush + write { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); ObjectWriteOperation op2; op2.write_full(bl); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate( "foo", completion2, &op2, 0)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } int tries = 1000; do { // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // try-flush + write { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); ObjectWriteOperation op2; op2.write_full(bl); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, ioctx.aio_operate("foo", completion2, &op2, 0)); completion->wait_for_safe(); completion2->wait_for_safe(); int r = completion->get_return_value(); ASSERT_TRUE(r == -EBUSY || r == 0); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); if (r == -EBUSY) break; cout << "didn't get EBUSY, trying again" << std::endl; } ASSERT_TRUE(--tries); } while (true); // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle before next test cluster.wait_for_latest_osdmap(); ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str())); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST_F(LibRadosTwoPoolsECPP, FlushTryFlushRaces) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush + flush { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); ObjectReadOperation op2; op2.cache_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // flush + try-flush { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY, NULL)); ObjectReadOperation op2; op2.cache_try_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } // create/dirty object int tries = 1000; do { { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // try-flush + flush // (flush will not piggyback on try-flush) { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); ObjectReadOperation op2; op2.cache_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); int r = completion->get_return_value(); ASSERT_TRUE(r == -EBUSY || r == 0); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); if (r == -EBUSY) break; cout << "didn't get EBUSY, trying again" << std::endl; } ASSERT_TRUE(--tries); } while (true); // create/dirty object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // try-flush + try-flush { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); ObjectReadOperation op2; op2.cache_try_flush(); librados::AioCompletion *completion2 = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion2, &op2, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); completion2->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); ASSERT_EQ(0, completion2->get_return_value()); completion->release(); completion2->release(); } } TEST_F(LibRadosTwoPoolsECPP, TryFlushReadRace) { // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // create/dirty object { bufferlist bl; bl.append("hi there"); bufferptr bp(4000000); // make it big! bp.zero(); bl.append(bp); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // start a continuous stream of reads read_ioctx = &ioctx; test_lock.Lock(); for (int i = 0; i < max_reads; ++i) { start_flush_read(); num_reads++; } test_lock.Unlock(); // try-flush ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = cluster.aio_create_completion(); ASSERT_EQ(0, cache_ioctx.aio_operate( "foo", completion, &op, librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL)); completion->wait_for_safe(); ASSERT_EQ(0, completion->get_return_value()); completion->release(); // stop reads test_lock.Lock(); max_reads = 0; while (num_reads > 0) cond.Wait(test_lock); test_lock.Unlock(); } TEST_F(LibRadosTierECPP, HitSetNone) { { list< pair > ls; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, ioctx.hit_set_list(123, c, &ls)); c->wait_for_complete(); ASSERT_EQ(0, c->get_return_value()); ASSERT_TRUE(ls.empty()); c->release(); } { bufferlist bl; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, ioctx.hit_set_get(123, c, 12345, &bl)); c->wait_for_complete(); ASSERT_EQ(-ENOENT, c->get_return_value()); c->release(); } } TEST_F(LibRadosTwoPoolsECPP, HitSetRead) { // make it a tier bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); // enable hitset tracking for this pool ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 2), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "explicit_object"), inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); cache_ioctx.set_namespace(""); // keep reading until we see our object appear in the HitSet utime_t start = ceph_clock_now(NULL); utime_t hard_stop = start + utime_t(600, 0); while (true) { utime_t now = ceph_clock_now(NULL); ASSERT_TRUE(now < hard_stop); string name = "foo"; uint32_t hash = cache_ioctx.get_object_hash_position(name); hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash, cluster.pool_lookup(cache_pool_name.c_str()), ""); bufferlist bl; ASSERT_EQ(-ENOENT, cache_ioctx.read("foo", bl, 1, 0)); bufferlist hbl; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, cache_ioctx.hit_set_get(hash, c, now.sec(), &hbl)); c->wait_for_complete(); c->release(); if (hbl.length()) { bufferlist::iterator p = hbl.begin(); HitSet hs; ::decode(hs, p); if (hs.contains(oid)) { cout << "ok, hit_set contains " << oid << std::endl; break; } cout << "hmm, not in HitSet yet" << std::endl; } else { cout << "hmm, no HitSet yet" << std::endl; } sleep(1); } } // disable this test until hitset-get reliably works on EC pools #if 0 TEST_F(LibRadosTierECPP, HitSetWrite) { int num_pg = _get_pg_num(cluster, pool_name); assert(num_pg > 0); // enable hitset tracking for this pool bufferlist inbl; ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_count", 8), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_period", 600), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_type", "explicit_hash"), inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); ioctx.set_namespace(""); // do a bunch of writes for (int i=0; i<1000; ++i) { bufferlist bl; bl.append("a"); ASSERT_EQ(0, ioctx.write(stringify(i), bl, 1, 0)); } // get HitSets std::map hitsets; for (int i=0; i > ls; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, ioctx.hit_set_list(i, c, &ls)); c->wait_for_complete(); c->release(); std::cout << "pg " << i << " ls " << ls << std::endl; ASSERT_FALSE(ls.empty()); // get the latest c = librados::Rados::aio_create_completion(); bufferlist bl; ASSERT_EQ(0, ioctx.hit_set_get(i, c, ls.back().first, &bl)); c->wait_for_complete(); c->release(); //std::cout << "bl len is " << bl.length() << "\n"; //bl.hexdump(std::cout); //std::cout << std::endl; bufferlist::iterator p = bl.begin(); ::decode(hitsets[i], p); // cope with racing splits by refreshing pg_num if (i == num_pg - 1) num_pg = _get_pg_num(cluster, pool_name); } for (int i=0; i<1000; ++i) { string n = stringify(i); uint32_t hash = ioctx.get_object_hash_position(n); hobject_t oid(sobject_t(n, CEPH_NOSNAP), "", hash, cluster.pool_lookup(pool_name.c_str()), ""); std::cout << "checking for " << oid << std::endl; bool found = false; for (int p=0; p > ls; AioCompletion *c = librados::Rados::aio_create_completion(); ASSERT_EQ(0, cache_ioctx.hit_set_list(hash, c, &ls)); c->wait_for_complete(); c->release(); ASSERT_TRUE(ls.size() <= count + 1); cout << " got ls " << ls << std::endl; if (!ls.empty()) { if (!first) { first = ls.front().first; cout << "first is " << first << std::endl; } else { if (ls.front().first != first) { cout << "first now " << ls.front().first << ", trimmed" << std::endl; break; } } } utime_t now = ceph_clock_now(NULL); ASSERT_TRUE(now < hard_stop); sleep(1); } delete[] buf; } TEST_F(LibRadosTwoPoolsECPP, PromoteOn2ndRead) { // create object { bufferlist bl; bl.append("hi there"); ObjectWriteOperation op; op.write_full(bl); ASSERT_EQ(0, ioctx.operate("foo", &op)); } // configure cache bufferlist inbl; ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\", \"force_nonempty\": \"--force-nonempty\" }", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name + "\", \"overlaypool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name + "\", \"mode\": \"writeback\"}", inbl, NULL, NULL)); // enable hitset tracking for this pool ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "hit_set_count", 2), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "hit_set_period", 600), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "hit_set_type", "bloom"), inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1), inbl, NULL, NULL)); // wait for maps to settle cluster.wait_for_latest_osdmap(); // 1st read, don't trigger a promote { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); } // verify the object is NOT present in the cache tier { ObjectIterator it = cache_ioctx.objects_begin(); ASSERT_TRUE(it == cache_ioctx.objects_end()); } // Read until the object is present in the cache tier while (true) { bufferlist bl; ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0)); ObjectIterator it = cache_ioctx.objects_begin(); if (it != cache_ioctx.objects_end()) { ASSERT_TRUE(it->first == string("foo")); ++it; ASSERT_TRUE(it == cache_ioctx.objects_end()); break; } sleep(1); } // tear down tiers ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name + "\"}", inbl, NULL, NULL)); ASSERT_EQ(0, cluster.mon_command( "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name + "\", \"tierpool\": \"" + cache_pool_name + "\"}", inbl, NULL, NULL)); // wait for maps to settle before next test cluster.wait_for_latest_osdmap(); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/librados/librados_config.cc0000664000175100017510000000464412623076744023705 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "gtest/gtest.h" #include "include/rados/librados.h" #include #include #include #include using std::string; TEST(LibRadosConfig, SimpleSet) { rados_t cl; int ret = rados_create(&cl, NULL); ASSERT_EQ(ret, 0); ret = rados_conf_set(cl, "max_open_files", "21"); ASSERT_EQ(ret, 0); char buf[128]; memset(buf, 0, sizeof(buf)); ret = rados_conf_get(cl, "max_open_files", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("21"), string(buf)); rados_shutdown(cl); } TEST(LibRadosConfig, ArgV) { rados_t cl; int ret = rados_create(&cl, NULL); ASSERT_EQ(ret, 0); const char *argv[] = { "foo", "--max-open-files", "2", "--keyfile", "/tmp/my-keyfile", NULL }; size_t argc = (sizeof(argv) / sizeof(argv[0])) - 1; rados_conf_parse_argv(cl, argc, argv); char buf[128]; memset(buf, 0, sizeof(buf)); ret = rados_conf_get(cl, "keyfile", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("/tmp/my-keyfile"), string(buf)); memset(buf, 0, sizeof(buf)); ret = rados_conf_get(cl, "max_open_files", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("2"), string(buf)); rados_shutdown(cl); } TEST(LibRadosConfig, DebugLevels) { rados_t cl; int ret = rados_create(&cl, NULL); ASSERT_EQ(ret, 0); ret = rados_conf_set(cl, "debug_rados", "3"); ASSERT_EQ(ret, 0); char buf[128]; memset(buf, 0, sizeof(buf)); ret = rados_conf_get(cl, "debug_rados", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(0, strncmp("3/", buf, 2)); ret = rados_conf_set(cl, "debug_rados", "7/8"); ASSERT_EQ(ret, 0); memset(buf, 0, sizeof(buf)); ret = rados_conf_get(cl, "debug_rados", buf, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(0, strcmp("7/8", buf)); ret = rados_conf_set(cl, "debug_rados", "foo"); ASSERT_EQ(ret, -EINVAL); ret = rados_conf_set(cl, "debug_asdkfasdjfajksdf", "foo"); ASSERT_EQ(ret, -ENOENT); ret = rados_conf_get(cl, "debug_radfjadfsdados", buf, sizeof(buf)); ASSERT_EQ(ret, -ENOENT); rados_shutdown(cl); } ceph-0.80.11/src/test/utf8.cc0000664000175100017510000000442612623076744017646 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/utf8.h" #include "gtest/gtest.h" #include TEST(IsValidUtf8, SimpleAscii) { ASSERT_EQ(0, check_utf8_cstr("Ascii ftw.")); ASSERT_EQ(0, check_utf8_cstr("")); ASSERT_EQ(0, check_utf8_cstr("B")); ASSERT_EQ(0, check_utf8_cstr("Badgers badgers badgers badgers " "mushroom mushroom")); ASSERT_EQ(0, check_utf8("foo", strlen("foo"))); } TEST(IsValidUtf8, ControlChars) { // Sadly, control characters are valid utf8... uint8_t control_chars[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d }; ASSERT_EQ(0, check_utf8((char*)control_chars, sizeof(control_chars))); } TEST(IsValidUtf8, SimpleUtf8) { uint8_t funkystr[] = { 0x66, 0xd1, 0x86, 0xd1, 0x9d, 0xd2, 0xa0, 0xd3, 0xad, 0xd3, 0xae, 0x0a }; ASSERT_EQ(0, check_utf8((char*)funkystr, sizeof(funkystr))); uint8_t valid2[] = { 0xc3, 0xb1 }; ASSERT_EQ(0, check_utf8((char*)valid2, sizeof(valid2))); } TEST(IsValidUtf8, InvalidUtf8) { uint8_t inval[] = { 0xe2, 0x28, 0xa1 }; ASSERT_NE(0, check_utf8((char*)inval, sizeof(inval))); uint8_t invalid2[] = { 0xc3, 0x28 }; ASSERT_NE(0, check_utf8((char*)invalid2, sizeof(invalid2))); } TEST(HasControlChars, HasControlChars1) { uint8_t has_control_chars[] = { 0x41, 0x01, 0x00 }; ASSERT_NE(0, check_for_control_characters_cstr((const char*)has_control_chars)); uint8_t has_control_chars2[] = { 0x7f, 0x41, 0x00 }; ASSERT_NE(0, check_for_control_characters_cstr((const char*)has_control_chars2)); char has_newline[] = "blah blah\n"; ASSERT_NE(0, check_for_control_characters_cstr(has_newline)); char no_control_chars[] = "blah blah"; ASSERT_EQ(0, check_for_control_characters_cstr(no_control_chars)); uint8_t validutf[] = { 0x66, 0xd1, 0x86, 0xd1, 0x9d, 0xd2, 0xa0, 0xd3, 0xad, 0xd3, 0xae, 0x0 }; ASSERT_EQ(0, check_for_control_characters_cstr((const char*)validutf)); } ceph-0.80.11/src/test/cls_statelog/0000775000175100017510000000000012623077035021120 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/cls_statelog/test_cls_statelog.cc0000664000175100017510000001321712623076744025163 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "cls/statelog/cls_statelog_types.h" #include "cls/statelog/cls_statelog_client.h" #include "include/utime.h" #include "common/Clock.h" #include "global/global_context.h" #include "gtest/gtest.h" #include "test/librados/test.h" #include #include #include static librados::ObjectWriteOperation *new_op() { return new librados::ObjectWriteOperation(); } static librados::ObjectReadOperation *new_rop() { return new librados::ObjectReadOperation(); } static void reset_op(librados::ObjectWriteOperation **pop) { delete *pop; *pop = new_op(); } static void reset_rop(librados::ObjectReadOperation **pop) { delete *pop; *pop = new_rop(); } void add_log(librados::ObjectWriteOperation *op, const string& client_id, const string& op_id, string& obj, uint32_t state) { bufferlist bl; ::encode(state, bl); utime_t ts = ceph_clock_now(g_ceph_context); cls_statelog_add(*op, client_id, op_id, obj, ts, state, bl); } void next_op_id(string& op_id, int *id) { char buf[16]; snprintf(buf, sizeof(buf), "%d", *id); op_id = buf; (*id)++; } static string get_obj_name(int num) { char buf[16]; snprintf(buf, sizeof(buf), "obj-%d", num); return string(buf); } static void get_entries_by_object(librados::IoCtx& ioctx, string& oid, list& entries, string& object, string& op_id, int expected) { /* search everything */ string empty_str, marker; librados::ObjectReadOperation *rop = new_rop(); bufferlist obl; bool truncated; cls_statelog_list(*rop, empty_str, op_id, object, marker, 0, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(expected, (int)entries.size()); delete rop; } static void get_entries_by_client_id(librados::IoCtx& ioctx, string& oid, list& entries, string& client_id, string& op_id, int expected) { /* search everything */ string empty_str, marker; librados::ObjectReadOperation *rop = new_rop(); bufferlist obl; bool truncated; cls_statelog_list(*rop, client_id, op_id, empty_str, marker, 0, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(expected, (int)entries.size()); delete rop; } static void get_all_entries(librados::IoCtx& ioctx, string& oid, list& entries, int expected) { /* search everything */ string object, op_id; get_entries_by_object(ioctx, oid, entries, object, op_id, expected); } TEST(cls_rgw, test_statelog_basic) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); int id = 0; string client_id[] = { "client-1", "client-2" }; const int num_ops = 10; string op_ids[num_ops]; librados::ObjectWriteOperation *op = new_op(); for (int i = 0; i < num_ops; i++) { next_op_id(op_ids[i], &id); string obj = get_obj_name(i / 2); string cid = client_id[i / (num_ops / 2)]; add_log(op, cid, op_ids[i], obj, i /* just for testing */); } ASSERT_EQ(0, ioctx.operate(oid, op)); librados::ObjectReadOperation *rop = new_rop(); list entries; bool truncated; /* check list by client_id */ int total_count = 0; for (int j = 0; j < 2; j++) { string marker; string obj; string cid = client_id[j]; string op_id; bufferlist obl; cls_statelog_list(*rop, cid, op_id, obj, marker, 1, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(1, (int)entries.size()); reset_rop(&rop); marker.clear(); cls_statelog_list(*rop, cid, op_id, obj, marker, 0, entries, &marker, &truncated); obl.clear(); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(5, (int)entries.size()); ASSERT_EQ(0, (int)truncated); map emap; for (list::iterator iter = entries.begin(); iter != entries.end(); ++iter) { ASSERT_EQ(cid, iter->client_id); emap[iter->op_id] = iter->object; } ASSERT_EQ(5, (int)emap.size()); /* verify correct object */ for (int i = 0; i < num_ops / 2; i++, total_count++) { string ret_obj = emap[op_ids[total_count]]; string obj = get_obj_name(total_count / 2); ASSERT_EQ(0, ret_obj.compare(obj)); } } entries.clear(); /* now search by object */ total_count = 0; for (int i = 0; i < num_ops; i++) { string marker; string obj = get_obj_name(i / 2); string cid; string op_id; bufferlist obl; reset_rop(&rop); cls_statelog_list(*rop, cid, op_id, obj, marker, 0, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(2, (int)entries.size()); } /* search everything */ get_all_entries(ioctx, oid, entries, 10); /* now remove an entry */ cls_statelog_entry e = entries.front(); entries.pop_front(); reset_op(&op); cls_statelog_remove_by_client(*op, e.client_id, e.op_id); ASSERT_EQ(0, ioctx.operate(oid, op)); get_all_entries(ioctx, oid, entries, 9); get_entries_by_object(ioctx, oid, entries, e.object, e.op_id, 0); get_entries_by_client_id(ioctx, oid, entries, e.client_id, e.op_id, 0); string empty_str; get_entries_by_client_id(ioctx, oid, entries, e.client_id, empty_str, 4); get_entries_by_object(ioctx, oid, entries, e.object, empty_str, 1); delete op; delete rop; } ceph-0.80.11/src/test/multi_stress_watch.cc0000664000175100017510000001003612623076744022675 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include #include #include #include #include #include #include #include using namespace librados; using ceph::buffer; using std::map; using std::ostringstream; using std::string; static sem_t sem; class WatchNotifyTestCtx : public WatchCtx { public: void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { sem_post(&sem); } }; void test_loop(Rados &cluster, std::string pool_name, std::string obj_name) { int ret; IoCtx ioctx; ret = cluster.ioctx_create(pool_name.c_str(), ioctx); if (ret < 0) { std::cerr << "ioctx_create " << pool_name << " failed with " << ret << std::endl; exit(1); } ret = ioctx.create(obj_name, false); if (ret < 0) { std::cerr << "create failed with " << ret << std::endl; exit(1); } for (int i = 0; i < 10000; ++i) { std::cerr << "Iteration " << i << std::endl; uint64_t handle; WatchNotifyTestCtx ctx; ret = ioctx.watch(obj_name, 0, &handle, &ctx); assert(!ret); bufferlist bl2; ret = ioctx.notify(obj_name, 0, bl2); assert(!ret); TestAlarm alarm; sem_wait(&sem); ioctx.unwatch(obj_name, handle); } ioctx.close(); } void test_replicated(Rados &cluster, std::string pool_name, std::string obj_name) { // May already exist cluster.pool_create(pool_name.c_str()); test_loop(cluster, pool_name, obj_name); } void test_erasure(Rados &cluster, std::string pool_name, std::string obj_name) { string outs; bufferlist inbl; int ret; ret = cluster.mon_command( "{\"prefix\": \"osd erasure-code-profile set\", \"name\": \"testprofile\", \"profile\": [ \"k=2\", \"m=1\", \"ruleset-failure-domain=osd\"]}", inbl, NULL, &outs); if (ret < 0) { std::cerr << "mon_command erasure-code-profile set failed with " << ret << std::endl; exit(1); } //std::cout << outs << std::endl; outs.clear(); ret = cluster.mon_command( "{\"prefix\": \"osd pool create\", \"pool\": \"" + pool_name + "\", \"pool_type\":\"erasure\", \"pg_num\":12, \"pgp_num\":12, \"erasure_code_profile\":\"testprofile\"}", inbl, NULL, &outs); if (ret < 0) { std::cerr << outs << std::endl; std::cerr << "mon_command create pool failed with " << ret << std::endl; exit(1); } //std::cout << outs << std::endl; cluster.wait_for_latest_osdmap(); test_loop(cluster, pool_name, obj_name); return; } int main(int args, char **argv) { if (args != 3 && args != 4) { std::cerr << "Error: " << argv[0] << " [ec|rep] pool_name obj_name" << std::endl; return 1; } std::string pool_name, obj_name, type; // For backward compatibility with unmodified teuthology version if (args == 3) { type = "rep"; pool_name = argv[1]; obj_name = argv[2]; } else { type = argv[1]; pool_name = argv[2]; obj_name = argv[3]; } std::cerr << "Test type " << type << std::endl; std::cerr << "pool_name, obj_name are " << pool_name << ", " << obj_name << std::endl; if (type != "ec" && type != "rep") { std::cerr << "Error: " << argv[0] << " Invalid arg must be 'ec' or 'rep' saw " << type << std::endl; return 1; } char *id = getenv("CEPH_CLIENT_ID"); if (id) std::cerr << "Client id is: " << id << std::endl; Rados cluster; int ret; ret = cluster.init(id); if (ret) { std::cerr << "Error " << ret << " in cluster.init" << std::endl; return ret; } ret = cluster.conf_read_file(NULL); if (ret) { std::cerr << "Error " << ret << " in cluster.conf_read_file" << std::endl; return ret; } ret = cluster.conf_parse_env(NULL); if (ret) { std::cerr << "Error " << ret << " in cluster.conf_read_env" << std::endl; return ret; } cluster.connect(); if (type == "rep") test_replicated(cluster, pool_name, obj_name); else if (type == "ec") test_erasure(cluster, pool_name, obj_name); sem_destroy(&sem); return 0; } ceph-0.80.11/src/test/os/0000775000175100017510000000000012623077036017057 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/os/TestFlatIndex.cc0000664000175100017510000001126612623076744022117 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "os/FlatIndex.h" #include "os/CollectionIndex.h" #include "os/chain_xattr.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include TEST(FlatIndex, FlatIndex) { coll_t collection("ABC"); const std::string base_path("PATH"); FlatIndex index(collection, base_path); EXPECT_EQ(collection, index.coll()); EXPECT_EQ((unsigned)0, index.collection_version()); // // checking placeholders // EXPECT_EQ(0, index.init()); EXPECT_EQ(0, index.cleanup()); } #ifdef GTEST_HAS_DEATH_TEST TEST(FlatIndex, collection) { coll_t collection("ABC"); const std::string base_path("PATH"); FlatIndex index(collection, base_path); const std::string key("KEY"); uint64_t hash = 111; uint64_t pool = 222; const std::string object_name(10, 'A'); ghobject_t hoid(hobject_t(object_t(object_name), key, CEPH_NOSNAP, hash, pool, "")); vector ls; ASSERT_DEATH(index.collection_list_partial(hoid, 0, 0, 0, &ls, &hoid), "0"); } #endif //GTEST_HAS_DEATH_TEST TEST(FlatIndex, created_unlink) { coll_t collection("ABC"); const std::string base_path("PATH"); EXPECT_EQ(0, ::system("rm -fr PATH")); EXPECT_EQ(0, ::mkdir("PATH", 0700)); ceph::shared_ptr index(new FlatIndex(collection, base_path)); const std::string key("KEY"); uint64_t hash = 111; uint64_t pool = 222; // // short object name // { CollectionIndex::IndexedPath indexed_path; index->set_ref(index); const std::string object_name(10, 'A'); ghobject_t hoid(hobject_t(object_t(object_name), key, CEPH_NOSNAP, hash, pool, "")); int exists; EXPECT_EQ(0, index->lookup(hoid, &indexed_path, &exists)); EXPECT_EQ(0, exists); EXPECT_EQ(0, ::close(::creat(indexed_path->path(), 0600))); EXPECT_EQ(0, index->lookup(hoid, &indexed_path, &exists)); EXPECT_EQ(1, exists); EXPECT_EQ(0, index->unlink(hoid)); EXPECT_EQ(0, index->lookup(hoid, &indexed_path, &exists)); EXPECT_EQ(0, exists); } // // long object name // { CollectionIndex::IndexedPath indexed_path; index->set_ref(index); const std::string object_name(1024, 'A'); ghobject_t hoid(hobject_t(object_t(object_name), key, CEPH_NOSNAP, hash, pool, "")); int exists; EXPECT_EQ(0, index->lookup(hoid, &indexed_path, &exists)); EXPECT_EQ(0, exists); EXPECT_EQ(0, ::close(::creat(indexed_path->path(), 0600))); EXPECT_EQ(0, index->created(hoid, indexed_path->path())); EXPECT_EQ(0, index->unlink(hoid)); EXPECT_EQ(0, index->lookup(hoid, &indexed_path, &exists)); EXPECT_EQ(0, exists); } EXPECT_EQ(0, ::system("rm -fr PATH")); } TEST(FlatIndex, collection_list) { coll_t collection("ABC"); const std::string base_path("PATH"); EXPECT_EQ(0, ::system("rm -fr PATH")); EXPECT_EQ(0, ::mkdir("PATH", 0700)); const std::string object_name("ABC"); const std::string filename("PATH/" + object_name + "_head"); EXPECT_EQ(0, ::close(::creat(filename.c_str(), 0600))); ceph::shared_ptr index(new FlatIndex(collection, base_path)); vector ls; index->collection_list(&ls); EXPECT_EQ((unsigned)1, ls.size()); EXPECT_EQ(object_name, ls[0].hobj.oid.name); EXPECT_EQ(0, ::system("rm -fr PATH")); } int main(int argc, char **argv) { int fd = ::creat("detect", 0600); int ret = chain_fsetxattr(fd, "user.test", "A", 1); ::close(fd); ::unlink("detect"); if (ret < 0) { cerr << "SKIP FlatIndex because unable to test for xattr" << std::endl; } else { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } } // Local Variables: // compile-command: "cd ../.. ; make unittest_flatindex ; ./unittest_flatindex # --gtest_filter=FlatIndexTest.FlatIndex --log-to-stderr=true --debug-filestore=20" // End: ceph-0.80.11/src/test/os/TestLFNIndex.cc0000664000175100017510000003614112623076744021647 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include #include #include "os/LFNIndex.h" #include "os/chain_xattr.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include class TestWrapLFNIndex : public LFNIndex { public: TestWrapLFNIndex(coll_t collection, const char *base_path, uint32_t index_version) : LFNIndex(collection, base_path, index_version) {} virtual uint32_t collection_version() { return index_version; } int cleanup() { return 0; } virtual int _split( uint32_t match, uint32_t bits, ceph::shared_ptr dest ) { return 0; } void test_generate_and_parse(const ghobject_t &hoid, const std::string &mangled_expected) { const std::string mangled_name = lfn_generate_object_name(hoid); EXPECT_EQ(mangled_expected, mangled_name); ghobject_t hoid_parsed; EXPECT_TRUE(lfn_parse_object_name(mangled_name, &hoid_parsed)); EXPECT_EQ(hoid, hoid_parsed); } protected: virtual int _init() { return 0; } virtual int _created( const vector &path, const ghobject_t &hoid, const string &mangled_name ) { return 0; } virtual int _remove( const vector &path, const ghobject_t &hoid, const string &mangled_name ) { return 0; } virtual int _lookup( const ghobject_t &hoid, vector *path, string *mangled_name, int *exists ) { return 0; } virtual int _collection_list( vector *ls ) { return 0; } virtual int _collection_list_partial( const ghobject_t &start, int min_count, int max_count, snapid_t seq, vector *ls, ghobject_t *next ) { return 0; } }; class TestHASH_INDEX_TAG : public TestWrapLFNIndex, public ::testing::Test { public: TestHASH_INDEX_TAG() : TestWrapLFNIndex(coll_t("ABC"), "PATH", CollectionIndex::HASH_INDEX_TAG) { } }; TEST_F(TestHASH_INDEX_TAG, generate_and_parse_name) { const vector path; const std::string key; uint64_t hash = 0xABABABAB; uint64_t pool = -1; test_generate_and_parse(ghobject_t(hobject_t(object_t(".A/B_\\C.D"), key, CEPH_NOSNAP, hash, pool, "")), "\\.A\\sB_\\\\C.D_head_ABABABAB"); test_generate_and_parse(ghobject_t(hobject_t(object_t("DIR_A"), key, CEPH_NOSNAP, hash, pool, "")), "\\dA_head_ABABABAB"); } class TestHASH_INDEX_TAG_2 : public TestWrapLFNIndex, public ::testing::Test { public: TestHASH_INDEX_TAG_2() : TestWrapLFNIndex(coll_t("ABC"), "PATH", CollectionIndex::HASH_INDEX_TAG_2) { } }; TEST_F(TestHASH_INDEX_TAG_2, generate_and_parse_name) { const vector path; std::string mangled_name; const std::string key("KEY"); uint64_t hash = 0xABABABAB; uint64_t pool = -1; { std::string name(".XA/B_\\C.D"); name[1] = '\0'; ghobject_t hoid(hobject_t(object_t(name), key, CEPH_NOSNAP, hash, pool, "")); test_generate_and_parse(hoid, "\\.\\nA\\sB\\u\\\\C.D_KEY_head_ABABABAB"); } test_generate_and_parse(ghobject_t(hobject_t(object_t("DIR_A"), key, CEPH_NOSNAP, hash, pool, "")), "\\dA_KEY_head_ABABABAB"); } class TestHOBJECT_WITH_POOL : public TestWrapLFNIndex, public ::testing::Test { public: TestHOBJECT_WITH_POOL() : TestWrapLFNIndex(coll_t("ABC"), "PATH", CollectionIndex::HOBJECT_WITH_POOL) { } }; TEST_F(TestHOBJECT_WITH_POOL, generate_and_parse_name) { const vector path; std::string mangled_name; const std::string key("KEY"); uint64_t hash = 0xABABABAB; uint64_t pool = 0xCDCDCDCD; int64_t gen = 0xefefefefef; int8_t shard_id = 0xb; { std::string name(".XA/B_\\C.D"); name[1] = '\0'; ghobject_t hoid(hobject_t(object_t(name), key, CEPH_NOSNAP, hash, pool, "")); hoid.hobj.nspace = "NSPACE"; test_generate_and_parse(hoid, "\\.\\nA\\sB\\u\\\\C.D_KEY_head_ABABABAB_NSPACE_cdcdcdcd"); } { ghobject_t hoid(hobject_t(object_t("DIR_A"), key, CEPH_NOSNAP, hash, pool, "")); hoid.hobj.nspace = "NSPACE"; test_generate_and_parse(hoid, "\\dA_KEY_head_ABABABAB_NSPACE_cdcdcdcd"); } { std::string name(".XA/B_\\C.D"); name[1] = '\0'; ghobject_t hoid(hobject_t(object_t(name), key, CEPH_NOSNAP, hash, pool, ""), gen, shard_id); hoid.hobj.nspace = "NSPACE"; test_generate_and_parse(hoid, "\\.\\nA\\sB\\u\\\\C.D_KEY_head_ABABABAB_NSPACE_cdcdcdcd_efefefefef_b"); } { ghobject_t hoid(hobject_t(object_t("DIR_A"), key, CEPH_NOSNAP, hash, pool, ""), gen, shard_id); hoid.hobj.nspace = "NSPACE"; test_generate_and_parse(hoid, "\\dA_KEY_head_ABABABAB_NSPACE_cdcdcdcd_efefefefef_b"); } } class TestLFNIndex : public TestWrapLFNIndex, public ::testing::Test { public: TestLFNIndex() : TestWrapLFNIndex(coll_t("ABC"), "PATH", CollectionIndex::HOBJECT_WITH_POOL) { } virtual void SetUp() { ::chmod("PATH", 0700); ASSERT_EQ(0, ::system("rm -fr PATH")); ASSERT_EQ(0, ::mkdir("PATH", 0700)); } virtual void TearDown() { ASSERT_EQ(0, ::system("rm -fr PATH")); } }; TEST_F(TestLFNIndex, remove_object) { const vector path; // // small object name removal // { std::string mangled_name; int exists = 666; ghobject_t hoid(hobject_t(sobject_t("ABC", CEPH_NOSNAP))); EXPECT_EQ(0, ::chmod("PATH", 0000)); EXPECT_EQ(-EACCES, remove_object(path, hoid)); EXPECT_EQ(0, ::chmod("PATH", 0700)); EXPECT_EQ(-ENOENT, remove_object(path, hoid)); EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); const std::string pathname("PATH/" + mangled_name); EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, remove_object(path, hoid)); EXPECT_EQ(-1, ::access(pathname.c_str(), 0)); EXPECT_EQ(ENOENT, errno); } // // long object name removal of a single file // { std::string mangled_name; int exists; const std::string object_name(1024, 'A'); ghobject_t hoid(hobject_t(sobject_t(object_name, CEPH_NOSNAP))); EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_EQ(0, exists); EXPECT_NE(std::string::npos, mangled_name.find("0_long")); std::string pathname("PATH/" + mangled_name); EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, created(hoid, pathname.c_str())); EXPECT_EQ(0, remove_object(path, hoid)); EXPECT_EQ(-1, ::access(pathname.c_str(), 0)); EXPECT_EQ(ENOENT, errno); } // // long object name removal of the last file // { std::string mangled_name; int exists; const std::string object_name(1024, 'A'); ghobject_t hoid(hobject_t(sobject_t(object_name, CEPH_NOSNAP))); // // PATH/AAA..._0_long => does not match long object name // EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_EQ(0, exists); EXPECT_NE(std::string::npos, mangled_name.find("0_long")); std::string pathname("PATH/" + mangled_name); EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, created(hoid, pathname.c_str())); string LFN_ATTR = "user.cephos.lfn"; if (index_version != HASH_INDEX_TAG) { char buf[100]; snprintf(buf, sizeof(buf), "%d", index_version); LFN_ATTR += string(buf); } const std::string object_name_1 = object_name + "SUFFIX"; EXPECT_EQ(object_name_1.size(), (unsigned)chain_setxattr(pathname.c_str(), LFN_ATTR.c_str(), object_name_1.c_str(), object_name_1.size())); // // PATH/AAA..._1_long => matches long object name // std::string mangled_name_1; exists = 666; EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name_1, &exists)); EXPECT_NE(std::string::npos, mangled_name_1.find("1_long")); EXPECT_EQ(0, exists); std::string pathname_1("PATH/" + mangled_name_1); EXPECT_EQ(0, ::close(::creat(pathname_1.c_str(), 0600))); EXPECT_EQ(0, created(hoid, pathname_1.c_str())); // // remove_object skips PATH/AAA..._0_long and removes PATH/AAA..._1_long // EXPECT_EQ(0, remove_object(path, hoid)); EXPECT_EQ(0, ::access(pathname.c_str(), 0)); EXPECT_EQ(-1, ::access(pathname_1.c_str(), 0)); EXPECT_EQ(ENOENT, errno); EXPECT_EQ(0, ::unlink(pathname.c_str())); } // // long object name removal of a file in the middle of the list // { std::string mangled_name; int exists; const std::string object_name(1024, 'A'); ghobject_t hoid(hobject_t(sobject_t(object_name, CEPH_NOSNAP))); // // PATH/AAA..._0_long => matches long object name // EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_EQ(0, exists); EXPECT_NE(std::string::npos, mangled_name.find("0_long")); std::string pathname("PATH/" + mangled_name); EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, created(hoid, pathname.c_str())); // // PATH/AAA..._1_long => matches long object name // std::string mangled_name_1 = mangled_name; mangled_name_1.replace(mangled_name_1.find("0_long"), 6, "1_long"); const std::string pathname_1("PATH/" + mangled_name_1); const std::string cmd("cp --preserve=xattr " + pathname + " " + pathname_1); EXPECT_EQ(0, ::system(cmd.c_str())); const string ATTR = "user.MARK"; EXPECT_EQ((unsigned)1, (unsigned)chain_setxattr(pathname_1.c_str(), ATTR.c_str(), "Y", 1)); // // remove_object replaces the file to be removed with the last from the // collision list. In this case it replaces // PATH/AAA..._0_long // with // PATH/AAA..._1_long // EXPECT_EQ(0, remove_object(path, hoid)); EXPECT_EQ(0, ::access(pathname.c_str(), 0)); char buffer[1] = { 0, }; EXPECT_EQ((unsigned)1, (unsigned)chain_getxattr(pathname.c_str(), ATTR.c_str(), buffer, 1)); EXPECT_EQ('Y', buffer[0]); EXPECT_EQ(-1, ::access(pathname_1.c_str(), 0)); EXPECT_EQ(ENOENT, errno); } } TEST_F(TestLFNIndex, get_mangled_name) { const vector path; // // small object name // { std::string mangled_name; int exists = 666; ghobject_t hoid(hobject_t(sobject_t("ABC", CEPH_NOSNAP))); EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_NE(std::string::npos, mangled_name.find("ABC__head")); EXPECT_EQ(std::string::npos, mangled_name.find("0_long")); EXPECT_EQ(0, exists); const std::string pathname("PATH/" + mangled_name); EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_NE(std::string::npos, mangled_name.find("ABC__head")); EXPECT_EQ(1, exists); EXPECT_EQ(0, ::unlink(pathname.c_str())); } // // long object name // { std::string mangled_name; int exists; const std::string object_name(1024, 'A'); ghobject_t hoid(hobject_t(sobject_t(object_name, CEPH_NOSNAP))); // // long version of the mangled name and no matching // file exists // mangled_name.clear(); exists = 666; EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_NE(std::string::npos, mangled_name.find("0_long")); EXPECT_EQ(0, exists); const std::string pathname("PATH/" + mangled_name); // // if a file by the same name exists but does not have the // expected extended attribute, it is silently removed // mangled_name.clear(); exists = 666; EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_NE(std::string::npos, mangled_name.find("0_long")); EXPECT_EQ(0, exists); EXPECT_EQ(-1, ::access(pathname.c_str(), 0)); EXPECT_EQ(ENOENT, errno); // // if a file by the same name exists but does not have the // expected extended attribute, and cannot be removed, // return on error // mangled_name.clear(); exists = 666; EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, ::chmod("PATH", 0500)); EXPECT_EQ(-EACCES, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_EQ("", mangled_name); EXPECT_EQ(666, exists); EXPECT_EQ(0, ::chmod("PATH", 0700)); EXPECT_EQ(0, ::unlink(pathname.c_str())); // // long version of the mangled name and a file // exists by that name and contains the long object name // mangled_name.clear(); exists = 666; EXPECT_EQ(0, ::close(::creat(pathname.c_str(), 0600))); EXPECT_EQ(0, created(hoid, pathname.c_str())); EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name, &exists)); EXPECT_NE(std::string::npos, mangled_name.find("0_long")); EXPECT_EQ(1, exists); EXPECT_EQ(0, ::access(pathname.c_str(), 0)); // // long version of the mangled name and a file exists by that name // and contains a long object name with the same prefix but they // are not identical and it so happens that their SHA1 is // identical : a collision number is used to differentiate them // string LFN_ATTR = "user.cephos.lfn"; if (index_version != HASH_INDEX_TAG) { char buf[100]; snprintf(buf, sizeof(buf), "%d", index_version); LFN_ATTR += string(buf); } const std::string object_name_same_prefix = object_name + "SUFFIX"; EXPECT_EQ(object_name_same_prefix.size(), (unsigned)chain_setxattr(pathname.c_str(), LFN_ATTR.c_str(), object_name_same_prefix.c_str(), object_name_same_prefix.size())); std::string mangled_name_same_prefix; exists = 666; EXPECT_EQ(0, get_mangled_name(path, hoid, &mangled_name_same_prefix, &exists)); EXPECT_NE(std::string::npos, mangled_name_same_prefix.find("1_long")); EXPECT_EQ(0, exists); EXPECT_EQ(0, ::unlink(pathname.c_str())); } } int main(int argc, char **argv) { int fd = ::creat("detect", 0600); int ret = chain_fsetxattr(fd, "user.test", "A", 1); ::close(fd); ::unlink("detect"); if (ret < 0) { cerr << "SKIP LFNIndex because unable to test for xattr" << std::endl; } else { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } } /* * Local Variables: * compile-command: "cd ../.. ; * make unittest_lfnindex && * valgrind --tool=memcheck ./unittest_lfnindex \ * # --gtest_filter=TestLFNIndex.* --log-to-stderr=true --debug-filestore=20" * End: */ ceph-0.80.11/src/test/cls_lock/0000775000175100017510000000000012623077035020226 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/cls_lock/test_cls_lock.cc0000664000175100017510000002033212623076744023373 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include "include/types.h" #include "common/Clock.h" #include "msg/msg_types.h" #include "include/rados/librados.hpp" #include "test/librados/test.h" #include "gtest/gtest.h" using namespace librados; #include "cls/lock/cls_lock_client.h" #include "cls/lock/cls_lock_ops.h" using namespace rados::cls::lock; void lock_info(IoCtx *ioctx, string& oid, string& name, map& lockers, ClsLockType *assert_type, string *assert_tag) { ClsLockType lock_type = LOCK_NONE; string tag; lockers.clear(); ASSERT_EQ(0, get_lock_info(ioctx, oid, name, &lockers, &lock_type, &tag)); cout << "lock: " << name << std::endl; cout << " lock_type: " << cls_lock_type_str(lock_type) << std::endl; cout << " tag: " << tag << std::endl; cout << " lockers:" << std::endl; if (assert_type) ASSERT_EQ(*assert_type, lock_type); if (assert_tag) ASSERT_EQ(*assert_tag, tag); map::iterator liter; for (liter = lockers.begin(); liter != lockers.end(); ++liter) { const locker_id_t& locker = liter->first; cout << " " << locker.locker << " expiration=" << liter->second.expiration << " addr=" << liter->second.addr << " cookie=" << locker.cookie << std::endl; } } void lock_info(IoCtx *ioctx, string& oid, string& name, map& lockers) { lock_info(ioctx, oid, name, lockers, NULL, NULL); } TEST(ClsLock, TestMultiLocking) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); ClsLockType lock_type_shared = LOCK_SHARED; ClsLockType lock_type_exclusive = LOCK_EXCLUSIVE; Rados cluster2; IoCtx ioctx2; ASSERT_EQ("", connect_cluster_pp(cluster2)); cluster2.ioctx_create(pool_name.c_str(), ioctx2); string oid = "foo"; bufferlist bl; string lock_name = "mylock"; ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0)); Lock l(lock_name); /* test lock object */ ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); /* test exclusive lock */ ASSERT_EQ(-EEXIST, l.lock_exclusive(&ioctx, oid)); /* test idempotency */ l.set_renew(true); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); l.set_renew(false); /* test second client */ Lock l2(lock_name); ASSERT_EQ(-EBUSY, l2.lock_exclusive(&ioctx2, oid)); ASSERT_EQ(-EBUSY, l2.lock_shared(&ioctx2, oid)); list locks; ASSERT_EQ(0, list_locks(&ioctx, oid, &locks)); ASSERT_EQ(1, (int)locks.size()); list::iterator iter = locks.begin(); map lockers; lock_info(&ioctx, oid, *iter, lockers, &lock_type_exclusive, NULL); ASSERT_EQ(1, (int)lockers.size()); /* test unlock */ ASSERT_EQ(0, l.unlock(&ioctx, oid)); locks.clear(); ASSERT_EQ(0, list_locks(&ioctx, oid, &locks)); /* test shared lock */ ASSERT_EQ(0, l2.lock_shared(&ioctx2, oid)); ASSERT_EQ(0, l.lock_shared(&ioctx, oid)); locks.clear(); ASSERT_EQ(0, list_locks(&ioctx, oid, &locks)); ASSERT_EQ(1, (int)locks.size()); iter = locks.begin(); lock_info(&ioctx, oid, *iter, lockers, &lock_type_shared, NULL); ASSERT_EQ(2, (int)lockers.size()); /* test break locks */ entity_name_t name = entity_name_t::CLIENT(cluster.get_instance_id()); entity_name_t name2 = entity_name_t::CLIENT(cluster2.get_instance_id()); l2.break_lock(&ioctx2, oid, name); lock_info(&ioctx, oid, *iter, lockers); ASSERT_EQ(1, (int)lockers.size()); map::iterator liter = lockers.begin(); const locker_id_t& id = liter->first; ASSERT_EQ(name2, id.locker); /* test lock tag */ Lock l_tag(lock_name); l_tag.set_tag("non-default tag"); ASSERT_EQ(-EBUSY, l_tag.lock_shared(&ioctx, oid)); /* test modify description */ string description = "new description"; l.set_description(description); ASSERT_EQ(0, l.lock_shared(&ioctx, oid)); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsLock, TestMeta) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); Rados cluster2; IoCtx ioctx2; ASSERT_EQ("", connect_cluster_pp(cluster2)); cluster2.ioctx_create(pool_name.c_str(), ioctx2); string oid = "foo"; bufferlist bl; string lock_name = "mylock"; ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0)); Lock l(lock_name); ASSERT_EQ(0, l.lock_shared(&ioctx, oid)); /* test lock tag */ Lock l_tag(lock_name); l_tag.set_tag("non-default tag"); ASSERT_EQ(-EBUSY, l_tag.lock_shared(&ioctx2, oid)); ASSERT_EQ(0, l.unlock(&ioctx, oid)); /* test description */ Lock l2(lock_name); string description = "new description"; l2.set_description(description); ASSERT_EQ(0, l2.lock_shared(&ioctx2, oid)); map lockers; lock_info(&ioctx, oid, lock_name, lockers, NULL, NULL); ASSERT_EQ(1, (int)lockers.size()); map::iterator iter = lockers.begin(); locker_info_t locker = iter->second; ASSERT_EQ("new description", locker.description); ASSERT_EQ(0, l2.unlock(&ioctx2, oid)); /* check new tag */ string new_tag = "new_tag"; l.set_tag(new_tag); l.set_renew(true); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); lock_info(&ioctx, oid, lock_name, lockers, NULL, &new_tag); ASSERT_EQ(1, (int)lockers.size()); l.set_tag(""); ASSERT_EQ(-EBUSY, l.lock_exclusive(&ioctx, oid)); l.set_tag(new_tag); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsLock, TestCookie) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); string oid = "foo"; string lock_name = "mylock"; Lock l(lock_name); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); /* new cookie */ string cookie = "new cookie"; l.set_cookie(cookie); ASSERT_EQ(-EBUSY, l.lock_exclusive(&ioctx, oid)); ASSERT_EQ(-ENOENT, l.unlock(&ioctx, oid)); l.set_cookie(""); ASSERT_EQ(0, l.unlock(&ioctx, oid)); map lockers; lock_info(&ioctx, oid, lock_name, lockers); ASSERT_EQ(0, (int)lockers.size()); l.set_cookie(cookie); ASSERT_EQ(0, l.lock_shared(&ioctx, oid)); l.set_cookie(""); ASSERT_EQ(0, l.lock_shared(&ioctx, oid)); lock_info(&ioctx, oid, lock_name, lockers); ASSERT_EQ(2, (int)lockers.size()); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsLock, TestMultipleLocks) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); string oid = "foo"; Lock l("lock1"); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); Lock l2("lock2"); ASSERT_EQ(0, l2.lock_exclusive(&ioctx, oid)); list locks; ASSERT_EQ(0, list_locks(&ioctx, oid, &locks)); ASSERT_EQ(2, (int)locks.size()); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsLock, TestLockDuration) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); string oid = "foo"; Lock l("lock"); utime_t dur(5, 0); l.set_duration(dur); utime_t start = ceph_clock_now(NULL); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); int r = l.lock_exclusive(&ioctx, oid); if (r == 0) { // it's possible to get success if we were just really slow... ASSERT_TRUE(ceph_clock_now(NULL) > start + dur); } else { ASSERT_EQ(-EEXIST, r); } sleep(dur.sec()); ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid)); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } ceph-0.80.11/src/test/mime.cc0000664000175100017510000001023012623076744017675 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/mime.h" #include "gtest/gtest.h" #include #include using std::string; TEST(MimeTests, SimpleEncode) { char output[256]; memset(output, 0, sizeof(output)); int len; len = mime_encode_as_qp("abc", NULL, 0); ASSERT_EQ(len, 4); len = mime_encode_as_qp("abc", output, 4); ASSERT_EQ(len, 4); ASSERT_EQ(string("abc"), string(output)); len = mime_encode_as_qp("a=b", NULL, 0); ASSERT_EQ(len, 6); len = mime_encode_as_qp("a=b", output, 6); ASSERT_EQ(len, 6); ASSERT_EQ(string("a=3Db"), string(output)); len = mime_encode_as_qp("Libert\xc3\xa9", NULL, 0); ASSERT_EQ(len, 13); len = mime_encode_as_qp("Libert\xc3\xa9", output, 13); ASSERT_EQ(len, 13); ASSERT_EQ(string("Libert=C3=A9"), string(output)); } TEST(MimeTests, EncodeOutOfSpace) { char output[256]; memset(output, 0, sizeof(output)); int len; len = mime_encode_as_qp("abcdefg", NULL, 0); ASSERT_EQ(len, 8); len = mime_encode_as_qp("abcdefg", output, 4); ASSERT_EQ(len, 8); ASSERT_EQ(string("abc"), string(output)); len = mime_encode_as_qp("abcdefg", output, 1); ASSERT_EQ(len, 8); ASSERT_EQ(string(""), string(output)); len = mime_encode_as_qp("a=b", output, 2); ASSERT_EQ(len, 6); ASSERT_EQ(string("a"), string(output)); len = mime_encode_as_qp("a=b", output, 3); ASSERT_EQ(len, 6); ASSERT_EQ(string("a"), string(output)); } TEST(MimeTests, SimpleDecode) { char output[256]; memset(output, 0, sizeof(output)); int len; len = mime_decode_from_qp("abc", NULL, 0); ASSERT_EQ(len, 4); len = mime_decode_from_qp("abc", output, 4); ASSERT_EQ(len, 4); ASSERT_EQ(string("abc"), string(output)); len = mime_decode_from_qp("a=3Db", NULL, 0); ASSERT_EQ(len, 4); len = mime_decode_from_qp("a=3Db", output, 4); ASSERT_EQ(len, 4); ASSERT_EQ(string("a=b"), string(output)); len = mime_decode_from_qp("Libert=C3=A9", NULL, 0); ASSERT_EQ(len, 9); len = mime_decode_from_qp("Libert=C3=A9", output, 9); ASSERT_EQ(len, 9); ASSERT_EQ(string("Libert\xc3\xa9"), string(output)); } TEST(MimeTests, LowercaseDecode) { char output[256]; memset(output, 0, sizeof(output)); int len; len = mime_decode_from_qp("Libert=c3=a9", NULL, 0); ASSERT_EQ(len, 9); len = mime_decode_from_qp("Libert=c3=a9", output, 9); ASSERT_EQ(len, 9); ASSERT_EQ(string("Libert\xc3\xa9"), string(output)); } TEST(MimeTests, DecodeOutOfSpace) { char output[256]; memset(output, 0, sizeof(output)); int len; len = mime_decode_from_qp("abcdefg", NULL, 0); ASSERT_EQ(len, 8); len = mime_decode_from_qp("abcdefg", output, 4); ASSERT_EQ(len, 8); ASSERT_EQ(string("abc"), string(output)); len = mime_decode_from_qp("abcdefg", output, 1); ASSERT_EQ(len, 8); ASSERT_EQ(string(""), string(output)); len = mime_decode_from_qp("a=3Db", output, 2); ASSERT_EQ(len, 4); ASSERT_EQ(string("a"), string(output)); len = mime_decode_from_qp("a=3Db", output, 3); ASSERT_EQ(len, 4); ASSERT_EQ(string("a="), string(output)); } TEST(MimeTests, DecodeErrors) { char output[128]; memset(output, 0, sizeof(output)); int len; // incomplete escape sequence len = mime_decode_from_qp("boo=", output, sizeof(output)); ASSERT_LT(len, 0); // invalid escape sequences len = mime_decode_from_qp("boo=gg", output, sizeof(output)); ASSERT_LT(len, 0); len = mime_decode_from_qp("boo=g", output, sizeof(output)); ASSERT_LT(len, 0); len = mime_decode_from_qp("boo==", output, sizeof(output)); ASSERT_LT(len, 0); len = mime_decode_from_qp("boo=44bar=z", output, sizeof(output)); ASSERT_LT(len, 0); // high bit should not be set in quoted-printable mime output unsigned char bad_input2[] = { 0x81, 0x6a, 0x0 }; len = mime_decode_from_qp(reinterpret_cast(bad_input2), output, sizeof(output)); ASSERT_LT(len, 0); } ceph-0.80.11/src/test/testcrypto.cc0000664000175100017510000000251112623076744021171 0ustar jenkins-buildjenkins-build#include "auth/Crypto.h" #include "common/Clock.h" #include "common/config.h" #include "common/debug.h" #define dout_subsys ceph_subsys_auth #define AES_KEY_LEN 16 int main(int argc, char *argv[]) { char aes_key[AES_KEY_LEN]; memset(aes_key, 0x77, sizeof(aes_key)); bufferptr keybuf(aes_key, sizeof(aes_key)); CryptoKey key(CEPH_CRYPTO_AES, ceph_clock_now(g_ceph_context), keybuf); const char *msg="hello! this is a message\n"; char pad[16]; memset(pad, 0, 16); bufferptr ptr(msg, strlen(msg)); bufferlist enc_in; enc_in.append(ptr); enc_in.append(msg, strlen(msg)); bufferlist enc_out; std::string error; key.encrypt(g_ceph_context, enc_in, enc_out, error); if (!error.empty()) { dout(0) << "couldn't encode! error " << error << dendl; exit(1); } const char *enc_buf = enc_out.c_str(); for (unsigned i=0; i #include #include #include #include #include #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/config.h" #include "common/Mutex.h" #include "common/snap_types.h" #include "global/global_init.h" #include "include/atomic.h" #include "include/buffer.h" #include "include/Context.h" #include "include/stringify.h" #include "osdc/ObjectCacher.h" #include "FakeWriteback.h" // XXX: Only tests default namespace struct op_data { op_data(std::string oid, uint64_t offset, uint64_t len, bool read) : extent(oid, 0, offset, len, 0), is_read(read) { extent.oloc.pool = 0; extent.buffer_extents.push_back(make_pair(0, len)); } ObjectExtent extent; bool is_read; ceph::bufferlist result; atomic_t done; }; class C_Count : public Context { op_data *m_op; atomic_t *m_outstanding; public: C_Count(op_data *op, atomic_t *outstanding) : m_op(op), m_outstanding(outstanding) {} void finish(int r) { m_op->done.inc(); assert(m_outstanding->read() > 0); m_outstanding->dec(); } }; int stress_test(uint64_t num_ops, uint64_t num_objs, uint64_t max_obj_size, uint64_t delay_ns, uint64_t max_op_len, float percent_reads) { Mutex lock("object_cacher_stress::object_cacher"); FakeWriteback writeback(g_ceph_context, &lock, delay_ns); ObjectCacher obc(g_ceph_context, "test", writeback, lock, NULL, NULL, g_conf->client_oc_size, g_conf->client_oc_max_objects, g_conf->client_oc_max_dirty, g_conf->client_oc_target_dirty, g_conf->client_oc_max_dirty_age, true); obc.start(); atomic_t outstanding_reads; vector > ops; ObjectCacher::ObjectSet object_set(NULL, 0, 0); SnapContext snapc; ceph::buffer::ptr bp(max_op_len); ceph::bufferlist bl; bp.zero(); bl.append(bp); // schedule ops std::cout << "Test configuration:\n\n" << setw(10) << "ops: " << num_ops << "\n" << setw(10) << "objects: " << num_objs << "\n" << setw(10) << "obj size: " << max_obj_size << "\n" << setw(10) << "delay: " << delay_ns << "\n" << setw(10) << "max op len: " << max_op_len << "\n" << setw(10) << "percent reads: " << percent_reads << "\n\n"; for (uint64_t i = 0; i < num_ops; ++i) { uint64_t offset = random() % max_obj_size; uint64_t max_len = MIN(max_obj_size - offset, max_op_len); // no zero-length operations uint64_t length = random() % (MAX(max_len - 1, 1)) + 1; std::string oid = "test" + stringify(random() % num_objs); bool is_read = random() < percent_reads * RAND_MAX; ceph::shared_ptr op(new op_data(oid, offset, length, is_read)); ops.push_back(op); std::cout << "op " << i << " " << (is_read ? "read" : "write") << " " << op->extent << "\n"; if (op->is_read) { ObjectCacher::OSDRead *rd = obc.prepare_read(CEPH_NOSNAP, &op->result, 0); rd->extents.push_back(op->extent); outstanding_reads.inc(); Context *completion = new C_Count(op.get(), &outstanding_reads); lock.Lock(); int r = obc.readx(rd, &object_set, completion); lock.Unlock(); assert(r >= 0); if ((uint64_t)r == length) completion->complete(r); else assert(r == 0); } else { ObjectCacher::OSDWrite *wr = obc.prepare_write(snapc, bl, utime_t(), 0); wr->extents.push_back(op->extent); lock.Lock(); obc.writex(wr, &object_set, lock, NULL); lock.Unlock(); } } // check that all reads completed for (uint64_t i = 0; i < num_ops; ++i) { if (!ops[i]->is_read) continue; std::cout << "waiting for read " << i << ops[i]->extent << std::endl; uint64_t done = 0; while (done == 0) { done = ops[i]->done.read(); if (!done) { usleep(500); } } if (done > 1) { std::cout << "completion called more than once!\n" << std::endl; return EXIT_FAILURE; } } lock.Lock(); obc.release_set(&object_set); lock.Unlock(); int r = 0; Mutex mylock("librbd::ImageCtx::flush_cache"); Cond cond; bool done; Context *onfinish = new C_SafeCond(&mylock, &cond, &done, &r); lock.Lock(); bool already_flushed = obc.flush_set(&object_set, onfinish); std::cout << "already flushed = " << already_flushed << std::endl; lock.Unlock(); mylock.Lock(); while (!done) { cond.Wait(mylock); } mylock.Unlock(); lock.Lock(); bool unclean = obc.release_set(&object_set); lock.Unlock(); if (unclean) { std::cout << "unclean buffers left over!" << std::endl; return EXIT_FAILURE; } obc.stop(); std::cout << "Test completed successfully." << std::endl; return EXIT_SUCCESS; } int main(int argc, const char **argv) { std::vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); long long delay_ns = 0; long long num_ops = 1000; long long obj_bytes = 4 << 20; long long max_len = 128 << 10; long long num_objs = 10; float percent_reads = 0.90; int seed = time(0) % 100000; std::ostringstream err; std::vector::iterator i; for (i = args.begin(); i != args.end();) { if (ceph_argparse_withlonglong(args, i, &delay_ns, &err, "--delay-ns", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withlonglong(args, i, &num_ops, &err, "--ops", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withlonglong(args, i, &num_objs, &err, "--objects", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withlonglong(args, i, &obj_bytes, &err, "--obj-size", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withlonglong(args, i, &max_len, &err, "--max-op-size", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withfloat(args, i, &percent_reads, &err, "--percent-read", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withint(args, i, &seed, &err, "--seed", (char*)NULL)) { if (!err.str().empty()) { cerr << argv[0] << ": " << err.str() << std::endl; return EXIT_FAILURE; } } else { cerr << "unknown option " << *i << std::endl; return EXIT_FAILURE; } } srandom(seed); return stress_test(num_ops, num_objs, obj_bytes, delay_ns, max_len, percent_reads); } ceph-0.80.11/src/test/osdc/FakeWriteback.cc0000664000175100017510000000434312623076744022410 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include "common/debug.h" #include "common/Cond.h" #include "common/Finisher.h" #include "common/Mutex.h" #include "include/assert.h" #include "include/utime.h" #include "FakeWriteback.h" #define dout_subsys ceph_subsys_objectcacher #undef dout_prefix #define dout_prefix *_dout << "FakeWriteback(" << this << ") " class C_Delay : public Context { CephContext *m_cct; Context *m_con; utime_t m_delay; Mutex *m_lock; bufferlist *m_bl; uint64_t m_off; public: C_Delay(CephContext *cct, Context *c, Mutex *lock, uint64_t off, bufferlist *pbl, uint64_t delay_ns=0) : m_cct(cct), m_con(c), m_delay(0, delay_ns), m_lock(lock), m_bl(pbl), m_off(off) {} void finish(int r) { struct timespec delay; m_delay.to_timespec(&delay); nanosleep(&delay, NULL); if (m_bl) { buffer::ptr bp(r); bp.zero(); m_bl->append(bp); ldout(m_cct, 20) << "finished read " << m_off << "~" << r << dendl; } m_lock->Lock(); m_con->complete(r); m_lock->Unlock(); } }; FakeWriteback::FakeWriteback(CephContext *cct, Mutex *lock, uint64_t delay_ns) : m_cct(cct), m_lock(lock), m_delay_ns(delay_ns) { m_finisher = new Finisher(cct); m_finisher->start(); } FakeWriteback::~FakeWriteback() { m_finisher->stop(); delete m_finisher; } void FakeWriteback::read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snapid, bufferlist *pbl, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) { C_Delay *wrapper = new C_Delay(m_cct, onfinish, m_lock, off, pbl, m_delay_ns); m_finisher->queue(wrapper, len); } ceph_tid_t FakeWriteback::write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, uint64_t trunc_size, __u32 trunc_seq, Context *oncommit) { C_Delay *wrapper = new C_Delay(m_cct, oncommit, m_lock, off, NULL, m_delay_ns);; m_finisher->queue(wrapper, 0); return m_tid.inc(); } bool FakeWriteback::may_copy_on_write(const object_t&, uint64_t, uint64_t, snapid_t) { return false; } ceph-0.80.11/src/test/osdc/FakeWriteback.h0000664000175100017510000000223512623076744022250 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_TEST_OSDC_FAKEWRITEBACK_H #define CEPH_TEST_OSDC_FAKEWRITEBACK_H #include "include/atomic.h" #include "include/Context.h" #include "include/types.h" #include "osd/osd_types.h" #include "osdc/WritebackHandler.h" class Finisher; class Mutex; class FakeWriteback : public WritebackHandler { public: FakeWriteback(CephContext *cct, Mutex *lock, uint64_t delay_ns); virtual ~FakeWriteback(); virtual void read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snapid, bufferlist *pbl, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish); virtual ceph_tid_t write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, uint64_t trunc_size, __u32 trunc_seq, Context *oncommit); virtual bool may_copy_on_write(const object_t&, uint64_t, uint64_t, snapid_t); private: CephContext *m_cct; Mutex *m_lock; uint64_t m_delay_ns; atomic_t m_tid; Finisher *m_finisher; }; #endif ceph-0.80.11/src/test/omap_bench.h0000664000175100017510000001235412623076744020714 0ustar jenkins-buildjenkins-build/* * Generate latency statistics for a configurable number of object map write * operations of configurable size. * * Created on: May 21, 2012 * Author: Eleanor Cawthon * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef OMAP_BENCH_HPP_ #define OMAP_BENCH_HPP_ #include "common/Mutex.h" #include "common/Cond.h" #include "include/rados/librados.hpp" #include #include #include using ceph::bufferlist; struct o_bench_data { double avg_latency; double min_latency; double max_latency; double total_latency; int started_ops; int completed_ops; std::map freq_map; pair mode; o_bench_data() : avg_latency(0.0), min_latency(DBL_MAX), max_latency(0.0), total_latency(0.0), started_ops(0), completed_ops(0) {} }; class OmapBench; typedef int (*omap_generator_t)(const int omap_entries, const int key_size, const int value_size, std::map *out_omap); typedef int (OmapBench::*test_t)(omap_generator_t omap_gen); class Writer{ protected: string oid; utime_t begin_time; utime_t end_time; std::map omap; OmapBench *ob; friend class OmapBench; public: Writer(OmapBench *omap_bench); virtual ~Writer(){}; virtual void start_time(); virtual void stop_time(); virtual double get_time(); virtual string get_oid(); virtual std::map & get_omap(); }; class AioWriter : public Writer{ protected: librados::AioCompletion * aioc; friend class OmapBench; public: AioWriter(OmapBench *omap_bench); ~AioWriter(); virtual librados::AioCompletion * get_aioc(); virtual void set_aioc(librados::callback_t complete, librados::callback_t safe); }; class OmapBench{ protected: librados::IoCtx io_ctx; librados::Rados rados; struct o_bench_data data; test_t test; omap_generator_t omap_generator; //aio things Cond thread_is_free; Mutex thread_is_free_lock; Mutex data_lock; int busythreads_count; librados::callback_t comp; librados::callback_t safe; string pool_name; string rados_id; string prefix; int threads; int objects; int entries_per_omap; int key_size; int value_size; double increment; friend class Writer; friend class AioWriter; public: OmapBench() : test(&OmapBench::test_write_objects_in_parallel), omap_generator(generate_uniform_omap), thread_is_free_lock("OmapBench::thread_is_free_lock"), data_lock("OmapBench::data_lock"), busythreads_count(0), comp(NULL), safe(aio_is_safe), pool_name("data"), rados_id("admin"), prefix(rados_id+".obj."), threads(3), objects(100), entries_per_omap(10), key_size(10), value_size(100), increment(10) {} /** * Parses command line args, initializes rados and ioctx */ int setup(int argc, const char** argv); /** * Callback for when an AioCompletion (called from an AioWriter) * is safe. deletes the AioWriter that called it, * Updates data, updates busythreads, and signals thread_is_free. * * @param c provided by aio_write - not used * @param arg the AioWriter that contains this AioCompletion */ static void aio_is_safe(rados_completion_t c, void *arg); /** * Generates a random string len characters long */ static string random_string(int len); /* * runs the test specified by test using the omap generator specified by * omap_generator * * @return error code */ int run(); /* * Prints all keys and values for all omap entries for all objects */ int print_written_omap(); /* * Displays relevant constants and the histogram generated through a test */ void print_results(); /** * Writes an object with the specified AioWriter. * * @param aiow the AioWriter to write with * @param omap the omap to write * @post: an asynchronous omap_set is launched */ int write_omap_asynchronously(AioWriter *aiow, const std::map &map); /** * Generates an omap with omap_entries entries, each with keys key_size * characters long and with string values value_size characters long. * * @param out_map pointer to the map to be created * @return error code */ static int generate_uniform_omap(const int omap_entries, const int key_size, const int value_size, std::map * out_omap); /** * The same as generate_uniform_omap except that string lengths are picked * randomly between 1 and the int arguments */ static int generate_non_uniform_omap(const int omap_entries, const int key_size, const int value_size, std::map * out_omap); static int generate_small_non_random_omap(const int omap_entries, const int key_size, const int value_size, std::map * out_omap); /* * Uses aio_write to write omaps generated by omap_gen to OBJECTS objects * using THREADS AioWriters at a time. * * @param omap_gen the method used to generate the omaps. */ int test_write_objects_in_parallel(omap_generator_t omap_gen); }; #endif /* OMAP_BENCH_HPP_ */ ceph-0.80.11/src/test/downloads/0000775000175100017510000000000012623076744020435 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/downloads/cram-0.5.0ceph.2011-01-14.tar.gz0000664000175100017510000005571112623076744025037 0ustar jenkins-buildjenkins-build‹}–0Mcram-0.5.0ceph.2011-01-14.tarì\{wÛ6²Ï¿å§@œœú)JÔÃvœ:ã8©ÏƱ£´ÛF9EB×ÉòaIÝÞï~3)JVœ8Þí^3‘Lá1 €y3pb{T©™-³æÈhhÖk–U©Y«Y½÷ÕžžV‹þZ;­Zùoþܳ¬–Õ´¬2îÕ¬ºµÝ¸'Z÷þ‚'KR;â^zus¹åÿMçƒãß>}~j¦“ôëŒÿv³ù¡ñ·šs=þµm |Íj4wvî‰ÚÝøógC"_ŽdŠÊ¿Dß·[b&©ð½KéOE–xÁ@$‘=®ÖÖMÃØoç’ÄÈv†^ ãé–ð X®—¤±×ËRéŠT&)jpÝgRØ=_Š4qˆt(ʼnŒ,ölŸ Š$óRÉe‰ñ&h†ŠÈÏ^ˆ~‹•â¨è#[ŽÃø2kA˜È-MMÊÜ2„©c*œñ7'€EaœrÚAÏó½tJ¸$‘t¼þTaF©Iu$SÛµS[ eÏâœÍUßÈ4‹ª©´c@ æ †W2¶µR9ˆm‚ÅYॠ1ãª-ܯfI\íyAUWÜqÊnCq ôöE2×ðÄöéP?Ä ³ˆÊrÚ–°¤ ‚#5ëÃ.ÁX»ŠÚÇ}ÔUtðÑ÷0H^’'Hƒ‹±†™ïŠžäÁ“W2^Ÿ2ÜP&ÁjJ$\a¦bÚSHÉQOº.æ œ“¬›¢=è‘7¦"–¿g^,1‹.i81¶‚Þb1…€ rû¾œx˜7Œé)Í;A˜b¸QQ Q˜$žžZåáL¨Ý³i: ¹y@§™ 0_@‘x#ÏH‡œ†²j~ùv0È0Œ /q&cKœg½ii^ýWó¦]õÿFþ7õÖüÿOÊ7Óo)ÿ<7 ù¿ƒrV³Ù¼“ÿÉÓ†~xökû§Ó×`ÝW^,¿¯lHdâ¦3–Ñ#ÆC°|ðþ@ñjpqš&F?GšÇ‚C ñP¼+k+âþ¾XaÖ³“áŠx/þü“ FP6 &8ð…í{v"]­ ¦BH—W?öWºã¡ùq3Ý.飫žþ|t~ðò•“ ÿDáäâ߉ԉÜ$ Øl^®Ë¢­RéÅv€äŠ-¶Þ´ŸŸWMS-‡hºÂp¤¿`NÎÖë{Œ»ŽF$*Wbä¶^uåU5È ÍÑkûø$4×w{♋[MA¡)(zSáʾù¤c@<R5bÛI½+É’~ËHB11\ˆM A˜)ISJÂT{)(PI†Ò÷÷‹aÄ¿M@©=5Ò¬ŸU†x÷6{Ï*­óîô¬}|úúMç½ R¼é˜ôO¬År¥©Âiø^éZ{yª¨-´‰&#Q<˜2c5Ý8}$j‡4ÀKU½Ÿ©1!­¡T/Oòè$#¥TÌ×üjB ÁÏ7$úFPH—í÷UòJ·Ñƒ¦YnƒÔ¥Šh• ý%ÓÕ<ªV !J¿@ü‘ŒÑg¥C+Ì"ÌÒ(ÓN©þÐg$c¨)”…‡TÀß3R‰ALU' :A(®×Aâò*GT%Še"ã+Y!TÓ’Rž° Ý26¡T.¥Œ*é(r½X·I)èЮc~B×sÒ0öŠ*jv´š¶$6„í!Yo-‰$]M©ˆû¯ßžäÕ‚ ŠfÌJrd;Š.9„’B©ëË8ã Ð)šo‹•ö˜’ÊI‹aÃD1\h‹ùÒ ä$¥bfº^Z?ãýÞ__·NÄZ> !lõô? £iÌJðÚẀè­UHþŠgqèzRœÛ¡ø¡ÇïO{X‰ÒŽÌ0<á)ÆJ*Ñ‚UiüïÇ,:ì§c;–Á¬U’0‹EÍNN¸:)âÔgT} X¨ ®—N“j­Ô{ªxrt~øÓÁëöÁ³ãWÇí_ÉÊxqÜ~}ôæxqz.ÄÙÁyûøðí«ƒsqööüìôÍ‘YæÖ|á]ý}‰ªSLdüÔ&ýf–‰L6C–*Þ%'ŽCõJ.Ö'ˆuž¤4Ym? ±"Ò ue°’ <žÆwo®¨cœêfÁMM‚;9Óƒùñ$O?üptú‚Yû;Jyϯ´2÷E;ΔŒ@cûÂâW5ñ³É?UÝ‚ZŸÑÕÑU ·ï 8õðüàäüp_¥|ôx”C5Žƒ+ÈWCù,²ŽF˺k!BÅö/ç½±œ=ì¡9…1ÛÜàø•ö*Z_ï£ÆúSû‘ oÔ‘BÊ̺РC_ÚÁ't¡!"Q9‡v¦U¡Ò…t¹D(&Ñ÷hÇÍ€SŠU渫+Q:Ô¥ÕÿϪè<6Œsè#Lȼúœúñ{‘\¼Tû¶ç›´”ÍļÞ€©b'ß©‹äÒ‹"Úܰ—.•zgée­lÚâo–ZØèôjýÖ£]§ÞÛéí:v«çôvwwk²ù¨Þïo÷š­z§gnä£MåwìzÃíÛ»­†³³³ÝÜío[l·Öäö[­f¹<™,E×Y_#mŽ6‹úÛÿcjý¬-©Â óZø D)RzX &øJd'‰tË9PqÒ)eñË\Npµ¼Š¿§‰YÎy m²ÊÐ_^“F‚rôˆ”³x¯\é¿o¬èf¬¦²½>7°Þ’ñ¼oXÕž® ü°GÍonn^Ïf}°(òô©¨X[Ö®Øäï§OI·ÀÑ3Ìèó ÄÙ@[H,¤z¶ #e©‘ÌZ:õ.`PWí[‹Ý³:0 ÃN`¸ÒÐëI¨èÛ)ýÌ_5¨ÍÒXyÓ/<ß§3Šôg‡NIj7›’b˜—9–4…êµ­–ØÄ÷v>…`oJ²ºmMÃʇFÆÃÒIÄÈèø%;nŽòãÈ(U†´²5羚ߋ@i ŠSX9§¨ý=8Åv0Ï¢¢ {t0otÜ1;¦qÇ4nd¤ãDvJ‡¿u^¸qm=| ¦¢‚å>’­^«¾Ó¯Yý^¿î>êYŽU·ÜZ­eÕvyÕatµt‘_ƒ]¨„Þ5&¢wËŠ Rš2KôŒœ¢˜M$]j6rµœ|Xý»c.wÌ厹0sù`ÆßSG¹Æ(îøÄŸ¸ãw|bÑ–¹:òÙvÎ/šÞ1£;ftÇŒ¾!3ú˜™tmuñÂvg>ÿáFT›ôžµêìšµÎ3ªø¡Îµ§¢÷}S3œeܦ¨¥½C]>‡®xåã]>¢ã‚¥º÷ù˜#*š¶+ªŒ¢Òаž|_W™/Õ²ÅÉݬVlNØë¨Þí ÝqÁ;.øÉûBKεæøÛ,ÿo»÷¬O©Tw—žU1kdwuÜVVø‘ß+}™JW3FŰfsm…½Q‰ùŒÞžž%ÌN[d8:y)£!>S×sdnvë¹wë1þYnï¼Ía×J°*_¸Î}Qé—¡ç„ÏaÏyc.ÒìùÞ²ìó iÛþmsù1- ¶hÿ¦ ž3‡/ç¨$•{úêíÉë7ûÍú,W%qöËó£³ íÖ1¢œQ:W8Z8ÖCØ©Ð?̼j9»c¦¤˜fMú·¬ ‘£TFwgËjˆMþ^ß•‡¯^¿|K~²*ýp!»ýÛŠâL/OÚ  (£¤Ë}°¢“.µ[Såšõ…beJ} âùÁIûäL#nnÎ\FKèk?“Ï™¿åÓfµ€•Ûí/O1™²c:¶ 6¦¢'›| “p$•ÿ"ycø>–x’IclLJ—(_DåÏ£ $¦æsΓ‹Î sŽ• Gý0ÝÆCb'±„àò½@>n¨“5](µ¤û1JûݹL€âq•V›Uivuaö²^yˆ:+b_¬>ÿ`ÎÍ©sº·ºà}½€Àb-]Œ=¢ŸÐîºÄê+ºz+FqNàƒDG®_Ù˜ñÁ‡ƒ´Ò%ER·Ø% ,`ä*ÚÒ 01³$ Ge7Ò97•Ž¡˜i¢ÇœvߛЦöHÝ㜂4zÖª™®’òwþẪd; g®Ùs ®PzѼ+ÚÌW¶Yày Ò‡(2æH‡@ÙÚ¸¦R× Àþ0 Û÷÷D/ó|×0øÏžñ 1Øu®jFÓ¼„C¬(QYR„ó°„ÑønÑ+4š¾sÜð}É3âƒCW¯^/>ïD:W”~Ç}qqMÛÊ‹ VVŠa:òðJë‹ó£ƒç'GæÈ'¯_@»[*$Ì*{7%‹¸°ï¿'ú?cÉüBª€#CÎÆqTß¶öD:ó8“žìSÀˆ’ÃQ2B€‚ Â$€d$EÀ·ƒKÖÏT^] ä˜ N:–s‘ŽŠ@§8c#’Ñ.zCH–4¶OHlQôUG:ð–¹:Ьè±aDÓ¾Vžýº´pH¹ ½@‡¸ÿ¾©(´àZ¥‘_r:ªÙ:´db"/Å•©¼| ¥R”Šõdæ†æ×=ŽCRkO1€|¥ð¢TÜÅ00 Š^hT1Nycƽ»çkÅÿÎÆíÛÊÿz³Ö¨_“ÿÛÖüÿ+žý¥Á‘l{â8]U¾"õFÒø@aƒÃÞ¼„v¸4ëÒ—ẏÀ© 4ôʬҎ"ßslس:ñf÷\ ñnðõ ÀÙ½0u›Š=øax©niHÒ½S¾)£|‚ª" µï™˜*N/ÎÐ*_‰‘#E¼Ã¤¡èÁ¡,2ôæ°ÌBd9Ö‚n«Ðe€+ËÐqU(þý’s´‡Iw©q$oœ]xÒ½Øcˉú¾FD6“ QÙʦ¹]ˆµªss˜5=KC­óŒ¯n­`éëe€?v­ªðFƒêÓmï©Ö,îYÃ(bŸé¹MÄW^eYô—DAY$ôí¢¡¿ "úkDEndôgFG•éÏŒ’þ‚Hé/–6ˆ©éÂᄨ˜r³{|ÙÑŒ SeâŽÝ®™v»ê€CNR$ù=G¯´–;ð’Š…zô€»¡O‡T ´\¾¸ˆ¯$²éÐ+æ;‡øn ØL8|*ØA ݘÎÐ0•®7ˆ‘ø˜³£ÌO½J¡Å£H¢.Š‘õ­@7·Åh:!_E§Ö UæBa#?ÓU ÈjÉá}¥ƒ.^Ê)ä¦ ŠkMmÞÑa€ƒ?uéZ¢ ‹¬”ï>º~Ê—°´Ì©ô‰Íñ†™j0oŽÂÃU-ʬ(q;Å,™p97,ß»ˆ%K«XÆÅ…[„/cßínà€ÚùsE<eË du£–º¬Ûít»[9ªít:—‰OÑŒ å½4‘~ÿfBKSo«Ú=È¢¼÷jmlOiýô=2grŠûq'r¾R¤Pò~^I¸=±ƒ°"CŸÈÍ'#í{0§M¨ÄâÚÀÕkQŽ©wj’ΕWÆTLmgj0ûf ¢Dmê­&µIbe}uNù1¼é Puv¤]\¥Ü”Fg5›ãïs”ÊÀúÁ”¯àb¯”ImI#Û4ÅE¡î‰ašF{Õê(O11ä2ð5ª\x‰ÖXTÇsz~8¨þíÃôàºKõ³¢vÏK{™s)ÉfPU×3°žQMb§šzÑÜÅI ði^æØ»ô0žÍ-Я*A¸8, \œ+G3Ž?´]£¢¢kaàÁÌ1\ˆµz]üãÙVîZ“äw£ÕÍf…vlÀÿuJô* ³¾®è¿¨Lüj E‡…‚ŸÅ½’'•Òc¿†/`‘]Ê7ØÑÊÖCÊ-rÔÍx§ñºz¹ Ϭ rÜ-ÒL¶§3@ãõ§â®ª…øÇäª/–g;î2”}mPÑ*hM#ÏT¥ú]EC_µchrqÿ˜K(]Œf:»ÚB~séoª ýÔ°=Ÿä QXS´ éRæº´Ü rHyÓñqåÕd¶ƒ¥•¯œÌÛ;â:øÐêÀ‡Aë¹ ˜(>Æú&³—¤‰ ã’â°[ëv׵Љ/sÔí&àD;:ß ûª×à /Ââ,t‹L”±º–‰²w½T­â¹‹ f†ºëË`*¢: G2_δ’y:\÷õR‡HŸTZѨåÆVÝ›øž/Í9]ðc-ÍÐÞFe£eUÕ[~Cû/–Ê5€%§$ W•¼ÁYhjÎW¨gÇôõ‡ö:èO•ïPé<“›Pg“ü xnæP¤ ¢ƒÊoïK—A ñ  ÈÆ7äÇnÛ7µ—– ‹uŠ9oÁÓY´¡Ñí.Jˆ:Ãø…¬mpUº“’uJëE-µ-fIêfËe:[–÷^>ùݧjo%äëzÆ´4†6zA[X½ª˜Ðz)T<¬…0Šs¦)G„í¥‚“ÂðøæÕPÛP×–++PŸâæxä×ròÞª‡Uj'|7*Ä„s PÓ0F’·¬™ð挃çWnÚÅd4‘°ZóëDzSpI¨áŠX ¦º¬¤Û5ÈT0Ei5ç+´¸nE”®[Ñ7êˆò5:ƱگIèøÇ¦Ó髯#]n¦úçìdœ·j[S …ºô&Sµ*{†Á‘ˆM¶ Ù£B0"êÂ@_fÿ™"§ÏÅœ\åý0#œ]Û¢,)‚ø!xÊ3E1Ô”m4²aXƒZf~* Š­T}^¡lDmX±5×í¶OΞŸÓlÂûÑÉY®tsŽ6¸Ã³iÃ6§ŒWVîÉ‹¢;ó0Xr:R@_^¼z5›»#ÍÃFÏyD¥ßˆû'³¬—'í"S{-” 9’`_¥bÄËîFóMÒ=9,±Ôí°9÷àÁÂÌ¿‚E—|‰4úœ =„íÿmïÛÛÚ8’½Ï¿gž÷CÌ’ø•D„ÌÅv¼$‘±ì°ÁÀœ¬X2HL,i´3’A»ïžÏþÖ¯ªº§ç"îÉæÙE»ÒLß»ºîU- 9k᪼VÌäE—U¨mK¹ ¾m–“—cƒ]r «ùšŠ|ö^ê çÌMUÓ[pÅ£O³^¤žp4?Ú¬h/èÙάâ#ó8zf0Yç¤8˜Ä¯Û3K[a$Öì(Í<œ’#Zz 1°z¨VJ-j°ºÃÚXÅ:kùë´Ô&ñ5¡¼ŸQßÿ!J£°¯¢¸ô#Ndv.Ü««Y‚…&M; ÍØ·1»öñð#?k ÃñSwQŸûõ?ÖÿUùå–î>4°ùù} D¢ñ9Œsoou~Þg┈pš8‘r!ÂqE$Rzs‘I²Ž k¤H‡©ÓfDºç&xoŸèI.ö|½d[£'Z­äéï†I¼¶MÞdp“q õi—utCh/3‘ؤÓf¬3ÏHô)3I˜Öq°ºãþ´i”(FӃᰶŪ*¬Ž†GDD_ Ã"Lï–%LwŸüqBl ~ejÀ1-òeú+uUtOÇС›Ùù`ÓàÄ`"Ãx2PÈêm;Æ%Z(â‚£M¹ä J3(§%¯$¡ó¬»ÂŒXáíp¯`íPÑZOR9I’ça"ùå]3 SŽ Í6¥›>áTˆ9 6Å:ø„àà#=\ÞÐaÌÈZ?$©(üôx‰Zrß" ¬´»®VMd·;Óe(â™_ß G-YpÄâU8âFHb{†J… ÈÀ’5CXV­ å´ºSei3-¤Uµ*Ôl9-^YmÇ,;¸“~Ò­«:,zllJËÔ¾²¸Ä¤k¶x îöçŸUžŽÄUÕþü×ÃÞç9Юô$ §p,R¥éžk¬ê ÜA€?õ56G 5jÔ¦èP…—2±AþIA¡Z—˜=èaÚ*7r¨šŸï8„X1»+ŸŸBwkõ°¼mêgvŒÔVâO¿~þùs˵` °Œ7à]x8Ör`ØÃÏ-ûä0xW0PÔJ‘…‚Äô´$.åÉÃÏ?›ˆ3(47,U’A±ð§~¯I8ê]QIÛѦ~o¦Q„-’ ØF¦ o6r;Šl·'¸ê>Ѫg*Ô'+àHÏd“ü.=: æß¡Æ¢x’ÇmZ·IÌÆÂÁ@kÔ²Æ>Š— P š%ì›QìXQ{ÞQ7ͬ¾÷HÔR—ÈFvg‘D#6*Núj”BfVö-èƒQN …[S—·ðl-0E°Ç¯n˜°¾™¶m |Å—dDÙsë–d†1Õ-ŒsSWËe-Y xQþkjôkÁ) QAŽ<¥S@'Ó¥³°S¸5” ”’àAB¿J$òç®0Ÿ¢|þ ~>Vˆ¯XÆ£A™I݇œÏs3NÏ™Ie…o¡±[0ûŪÜwÂ]Ø–R<êÓÑÜ;TiÅP¥Å›Q%{‹MØ)—Ïí×U&Y…³“ð\㼩1I ËZá%À‡3Ú“Ãb¬ÒydÄ!j4â{IDjboÚónró’ȧW™Z/‰ù~6Ìös$t½†„5æ|ŠÇçŽ|5‹¹éÅXq¤c§[œ¡Fκ„V!®ÑšQW•±Z =X©#Šñ BÄòN~D"n7òU£l«Í*k²Än0ޤyG—Íîüat[tñ)H4Vž9bÓ˜#…”‚ŒÀ’ò²òÒ×7ä+àŠ•†‚ín¾©¹Á,Ýr0CâQh¥“°)øFï5ŸØ»¸æL9Æú$öZ(¶÷²âìZ›F ir®2O/£ñ;gzFë}ªÑ )á´SÃt›fø ‰~Ë{Ž a*:ùJEó´5šçȼ$ézì¿2ƒ9„ºµ'’™„æ~ä™’øZù¦!!°„r †s\!Á›ó7õê»U!¯¬f¢ÇíÉøWd|¼_gþ»ßðæP¸×+XK˜"JIt3ñÿ÷)@*éŠ&E.$˜óƒ‰ÿjrº^¼ €¾îB Ÿo‰-£ƒùqÉ:QéE0„.ªÏ\›ZA‘1¥j1Oì¼8ç÷C —9FÕµ%nñƒµÞŠÅ-³yVll€qj§*}Lš üº¤7àK æX;Üôü=YTö¦8Ü;«HzÄEð#i}îd•ˆ}B\Ò±ìÅ\ƒ9gÈ…&²‰^ÃÙíOˆEÿnO<Ú¹ìSZxY\B¹Zêt]ܧü§=ø«Ôšÿü)HÂ30ƒ(¡š:žÕÚÓ¿úþÁ_?ÿæè©óàó§à†×ž~jÕaáŸGSÃïÖˆ=YKåê¡= VôUÄT’ékxß^Ñ2|¬(q²{èÕGs‡ŸûOK5µTqúØ3jŸ§kéÏš ÿɆù×â01C~°\=Ró4]Ó‡–G!…³1<¤Üèõ‹§ý/Ér™æ½óðú±¼>?ˆ†³T;½}l?÷J·XKä@ÎÂ>ÃZB!õÞš€— ô¯ëìÜ~r€"ß#´µ½Õñçþúùœ[ö’ÁkË‹‹Ž,”?ñÇ`jUpâè©•¦M¦ÀŽ]lã‡Dš9ٺגR“4qÐUÃ1€äjgCͧãx´¶Ìw#9¿Î£ÓñEÔŸÓ¹F^zBñ,úk>/Öœ÷ŸDÿw~x»°±õfû׎ÿ^Y~¾ü¢Èÿ=ÒÿßèóNï8^P%Áª¿ÔZô¶‚F±xöyx{BMȱÑÖ¬·ûú>„ #æ6f9ez†óÈ.FÓG á ˆw]º%ÍÛŒºá×'½Ýzï¿ÝÙ´ú‰…÷»›7w^}¦Ý$b àª?+XÎ|*ƒæÌËk*{n#÷¦ó­§Ým‚êªÇrÿ ;ÓÜýƒíLK3ƒîJS¸u^©…‡ Ê3Ÿ\p^eŸw ÖËê^´g>3ƒ÷ÜÄ—µéóÍêèA}YUÜ—­Á-ƒü*÷AƒþfîQ>Ð|nwý[eÓ3ƒ"Hða‚ï4øÁƒDxß`Â{>hpá=ƒ  Øð!‚Kbvb©èm‚+*?L¢ùäƒïÖݵÁ‹Öf1VôüAæ3“øÞ?ØÑ|îô8sµïi> i>™q}×GÞf£n,iY›;MÞw³fQÚ£q›`ʪÃòÁ•Ixˆ Kó¹}°eÕô®¾,¿•¹Ò­t× L· Îtþm‚4K‹i¿ØàÍŒ~ªe½b¿"¨³r_ïäYj-ôYœSõ¼n ZÉ)W‡–ÊÝ6XtFG·ͪ^DêH½k Ì *­ÜÏ™ÎJ >ÍíÞ %Á=‚R-|àTËÞ?H5Gíï¬ZZµ»¯V‚¦ fu6ëA­æsûàVó™äêψXõ‹A¯W´A°v¤7­™ë"ÿ¦,;C Ÿ9 \må¸ò-]‰F×·¶õ A·Îœà[ß ÂÕm!(ׯÎu–â³b‡ùíw$›ï^fnÌ›ñØ3‚zK==D¯‹†îì›Má!‚~3Ùô¾Á¿3)ø=‚3!¢\ ®N°ùT g“¶AÃe–傈˚‹{g;ïàb+¬ß*ȸ4Ÿ :¶§ÃWð¸÷FÎÖ®”\Ù݃”«‡>#h¹²ðUAÌÕîÔ\Uïä\=À»=W/惠+yâ Šv›|¸àèÙ¼8M»¬x¹ˆLAæÐíü\ãod]¥z¸_е;ˆëƒ¯göË`ìJ¸ºYpö›V Ö®ØÃ¢~6‘Þ¶jú â6ŸB0wÅÕ÷Ï3l· Ÿ9¢û‘[?†›±J\^Ñì}ƒÍífÞ6è¼jŠwB¿–ƒÒ¯Ç…·B†×©Û;O°z† hÝ|lðú ùíƒÙ-¼qP{¼w{Î×°Ú÷ –w}¿ y+ Þ'x¾ê_D_±.wªŸåœp· ûŒÆÝ›Ïß[5ÃÝ‚ðgÑûå[½Ò݃ógr· ÖŸÝÈ}ƒ÷ÍÇñWø0¨ßm÷úàþ+¨}9ØÿvÔþ‚ÿ-[t³$U‡û~I²cøÉ,ö{$%RJpÕé¸{òW|ƒ$W â>I\YJ.0[þ¹O²k;¹iÒ+X9 ÁíØ%%¸ rU²‚[b…bò‚+œ/œ¤¾ ³½5îšì Ò’qóäe+Cu2„Ênœä¥÷·M–0»›<¡¼Ã÷N¦àȯ³’*<œ×Ò’-¸ Ü&é‚¶†ù¥«™þ©’ƒx;ÊW­úï·~ØÚþiË[ïÃíâ4 “Uºý=v£öWWýÁo÷GçA®¬+Q!â5Ò¸æŠl€zkOhÜÃnˆ‚ÚôgnYÂA‰í½ ¿=‚•ª®j\N8 ôw&ÄNvméúÛÍF®-5 šÐd4Оõë–Û¦ˆUqoJüÇ@:æËxW‰óíßIâ3ZÄ*¸M¿F—>|æŠïÇ#%½ß‹OÇ WîÒÒó} Óñþâÿ¬Mâ_ÿá•xÌÿð;Ùñ–øõîÿ]|±ô¼˜ÿaiqù1þó·ø¨éØÚ«z5½ÅÛ8.......®.>;\|~¸øâpñKzˆôf‰ž/Ñ‹%z¼DÏ—éù2j,‹ƒ’ø$¹-.Seª±Lm-S­eªµBµV¨Ö :¢÷+ô~…Þ¯ÐûzÿŒÞ?ûRZ„K“÷SgŒ±¨þÔ ¹¼œïÖrnK‡Cv©Z’Ö_.<¶NNrYÛ›¨ßW1.Nà¨Mò‰Ã=íÏ'ÃÔ™wõå W.Û³—¹[ý>Ï?”+¿êù_¦3_<ÿ+ÏÏÿoñÙ7Á©Pø9úÁ9U©ÍÙl Ñ,£÷Õb¥Î[È”„ì3T¥ônš“2õîµø˜˜ì7>ÿìAtpÝùwø?sþW–ïÿýÝìÿðÓ½Ðÿõüßâ³Âþ?ƒ¸ð¸ÿ¿Ágý<ì~¬V»üÓÜçðDÈýzî!;J–«¿déÅþ_ðèí»}÷¡x3Î +”=§H<&œï¼p½K•Ä0ŠÇ-ËÏe½‹%oç-xûb‹ærý4_ŠXÌ$Ê=üׯN "o cù)Ì’Éc=¾ï¢Ç]â¬1-œ—3eºþŸÿÖyÔë…ç÷:ÿ·“ÿ ÿ/?Êÿ¿³ý—?w ×ÒÿçËüÿâËåøÿ7çÿÕ{Ðaùk©¯ÛþÈvÿ§ž¡d¿ÿ·ôå‹ÿ¿ôü1ÿÛoòÙ“¬mÆ‹ÖåùDeWTÜe!ˆ5ÿÿù]„èB¾Õó])ûˆ6IíÔþ?<ÉñäKRñÿŸ¦ˆÑëíÎÒ¡™‘Q) `”ï­yÕÔ½%Žª n›÷m ÿK‹ÿÅÛ¡¼ø–^ÌócÃy›â{©FûÌB.XË(Ý!±Rï/ø&À%UíYxêT¡á|ûí·þß&“KmQôšÅ§ž×êºí²ÎºŽ8X:‚”c?÷Â$)¬•ÿÍÿ]Öô¶bãe_%»Ù¾ñð÷ª¢O3U.ϧª¨ïk@ꌷ‡CS¢¢ØlÀ« ×Ñ´&¢ÿ}põá%5qIm\R#—ÔÊ%5sIí\RC—ÔÒåâW‡cúï ýëÒ¿þ^Rû—ÔþåÒ²ÏA¬ø¦†i(4ðË% þ’¹ôýûšþô´DZêÑ?Ô^†rwþïî$àöüßóg_®<âÿGþïñó;àÿD ò+êÿ¨Ïâù§¿çÿ·øpfÉ?…Çó_}þ] ç¯sþWŠþ/Ví¿¿ÝùŸÉa?ÿàó¿¾½óacëmk|9¾gWŸÿg+tì‹ö?„Ïÿoñùïÿf·oøâv¶:»íMçý«ÍuŸþu¶ö:žpó—›þŸ&ÃÐ_úúë%’¸×ãÑ4áTHõõ=üêë&¿òß$a˜9ʾ‰'ÃGq7ýaW´ŸÍ¡ ýÐßéݰéï!£¿²²Øô_Åé¥ßµ}ŸÄr‚Ë¥•Å/}ÿý^Ûó;ŸÂd Wy„†É kæ£. ‡U4½(Õ()ND]ð’“sÌ Õì«¿q/îN`ûlú'È`BÓ£±„lŽ%³.ßÏúß²;I ÓÜÄÚRÊŽ/ƒ‰)ÍÌñ¯"o¯Œp ïøà"˜òMHÞ)-ÇKÄ~zÎå‘_Ò^Dã–ï¿’àÐ$@â)8Å—§Íe,Ãïljðl$ýåÒ¥«ºÂ;ÏŒya#VÔv’hö 3(å²;y3|º%’“3Çðúh>Ù”x”à™­à°'Él¦š°x$nÛþÅ9²<|DÊúƈS~I¨¯^}/„ZmDæ&Ç>ü‚ä™ÅÞŒN8eÆÌ4ÿE«‘å¿Âd§¾ †—^GŒÀÅ8f&Žá¿‘… øˆÕàU5#iâ•$O: “Dôu›€I¨v7¤nSóÕ#KK°çîi0TxÝÌ)2èpÎŽ™Òø$Îq×g Ÿ'¤K¡®5 Ã¿ˆÒóFÓvesg¤´"ÝPâS‘ ‚ i5£±9zEc§*ʸ¹`Ì0¨ºd »2J42äe<^³î/5&T›ûˆ OÓnƒ§9Q¸õ6Ûç|Hã°;–£Ã.å]‘›Åt-“+Õ•Ü<-ÆIÔóXc¹ï¬ù¨k'Ò' N?Ê+D‹âÊ¡çù6¥ZÞ¾ÔÉõBG:í¢ï5®rTbç=8‹¡eYQ¯rGÝ•ä]þAÜCfhÌKQLT‰•Í¥“.â¿tÉ›ˆ ætgˆÈà3ÎðOÃP3è!›ÂY¤ðGÐQSˆåæ\» ¼®8F‰ß’SÆu àŒd>`M jx!¬Þ†ý§Í Z¸¦Ç<‹>“g½¹Ábާb/©BϦ5oHP%·8oÐÚ¥¡FŸ¾ò…[‘Ágî«r¦# Í·ipÙBÆ@·ea¤f&šžÀʘð» 2©A¹–6÷$»j0”Œ:}-CŠ © ÓDÓVà‹vRs½§ä’Ž9?±´úzè™ñçÜÞçÀyv€ÊõdHÿ^–sÉÓ3G´cŽJ1ë ĺ®`¬f‹Ü$5YÆØË8d‡—‚b™+›Œ97rJ­P ºœÜ+»+[zEʆÓAî“ÅC£{8_‹SÅs˜u+ˆN¹CNë8”/é83EôK€æ™žëQŠMG:$BV"F\4ÏŠ7ZÞOÂàøÈ’ Øm´•¢Cwì$q士%IØŠ#xÕðjÚL-uùl¯Ë\ƒmF2!n>êEbÄ4³gÆÿzXšQÔÄ“´/½#Áå»Èö‹ƒN&š;Ûxn)/;iŠytÝ~ $-‹¡ü/åê!äÚëŽ wçIµÔP¬S °ç0¡H~rñHʱƱdƱM{œÑ3ÏäC‡È/ßkAS1ˆMûñœœNiÚ*»K"é0óª| ¡ÚóiŠ´€ ×r˜¸&= ƒ7ÕVå5žð|–=rø/ÝK#™¦™!g9ƒåï¸E™UR 0c*fó³Q‰ ÓÅ w&*n*-8uMFíyD¨Þ¯ %{:¹%/‘©€KID;C™E:tœ}<|?hdB€˜ªÑ“å%;XcZ[^Xš#Ž·‚· ÅäLÓIr¡ù††µ[À“R-ÇIi ›’¾@›uÖ‹GO–ж‘$ » âjðÓ—ü²ÎÏR!u&q[yc¹ ®Çlw| !(ÇQ¸ÑEz ° žõN2: I϶šÅ Ò/Óï6 ën—Þú!_EÌ 3ƒ^šeiÌ¥NÑÉK2CG&4ÞMyÉ×*‡=‹…9¸l¢÷û¸W¿q­¡:¦¤G”)H õ‚ ªN›BŒZài8Œ'„]8Bˆ0ŠÆó+1ž¤ÏÒ³eŸ:xZ’_š†³ð¡§@Æa+42…k×øÄ;l}hòcœÙôÜBñÀ( û}C¿ÐœÏÂnìŠÂ‹NäV2¯Þ¹ì†zýi”Ç*r™”Ñ9š=8Ñ;8@똤[HÅ-Á0·äMAb9 dfSæ²Ü’zßH¾±Vƒ8w£7á²Q*°NN©‰…Wî3;,Œzxz/7{†ªxÑLGZE˜¡™G³ÉtI3IÑHcÜr?ÍçOÍøIáD§p†Rå÷´ÆŸBIx6ÌAÙYp<|D›Ðc±®:›gL¤ÍÿBo5ðó04Àìó]Cé<Û ^è8?¾m6Hõ°Œ)(FD¾E*ÛR¯HT$ÿ¡Ãp*Ñ’6ŒPsXÈ˯€(€3uˆÈyæV;a†S¹ðÏ0¶6Ñn “9aj!êd—„ð)ÓJ³ éõ‘Æ Í9.ž@|VŽíSŦc&ÀH%SžE˜ºNLŒÀ9ú?fTӱ窎¨˜Hw ,È\†ÁŠ"€Ê½ôi—ÎYpȺbñÆ /ÃDÄ_£8ÝTýÊÅv¨8!v®m†§ÒJV€æìdõl"saÁ³3¬’iVe™V¥ª!¯Èk1‚Ô R39‘~þ§¸?Rÿ”¤Þts’"ÁéÙü„÷ͰÐIbðŸ3:A› ÓR*©ÜÊÕ¬zq ÅÑC„bjØŸåhT|‚ÄFVN»×H&jpdô×Û3'n‰Ç°¬WñÍ`¢@e¦gʦóÏø§v—/;²™ÂîžõC¦u‰è”™äÖ @ÌmöwGiê™7§ÖQ*\Á ­ÉO‡7X7¯K­Åƒ ‰úSIŠÌ„ß* At„{IKØ´Yyf=OÌr7}¹ö‡9k’± ;Yÿ&óš†A†šL¬`‰´© ¹rPC˜³D=ƒždÉ —‘@ýÂÄðÚºp.¼6åÆ=^{OrhåWÜ¡ÑÅÍÉí3~B€o¶³×_fr‡=è΂.÷*aGfeþT 3oÐþ‚jÆ”Á£°ö,èÓX†‚Ï”Q³­¨8yX<ä{ I×VTw5ˆž¤ñÕñ¹¼Öõ‡—çkÔÀBÄrZ—D¯ Û›œêp"«O¬ 8—œì4C*¢“±°YP¶c`)§Þ 辶6/™q È–Øs89½´häìÑ—Þ=î]º4ö˜Ò¸pÓfÜ›ôåÎ #µdן¤,™iw#££#€k.{!rªÚ pLyÁÃI4‹2¶gèõ³K¨#çvA3ýlF4Ëï%Gv“y;Ï\Åf¶Yš{\ØÄª¡ú8Xóä~L£ê±L­[­±]Ô…Ú2­Ñ K ö©‘„Að s‚hæNë2CŒø#qØÖ$oè ½Øf7K%»+™€xóó‡¤D«:2ß2–{‡´+OÙö@Oh¤W;8«GDþ´Ä-8­ƒÅrN§=: Qëܵ:d0w¨)š¡a$þÌÕšZ>ØuBÍe¡ôv›™QnŒ^L˜ÏO½*¶2‡%a¤<9;wp»ÍAÊJÎÁˆ„&Ç©Äi¤ .rVß–ñ €"Q‰º†ä?V¢ ÿêr-9^ÂHôj”ÜÁ%¤Þ s‡U5 &¤Ý{Ìã\07Ïì~vïÀŸ°+ VÜ‚*a#svÏŠayöš ÍF!‹\Eg%IÕÌÎÛ a84G'híoÆs!J2÷;0>:¼Mo€‹ÍH„¡‹þ:é féG Ìî=—­3â+m$Gã‚ –FPJã4ƒŽº[0²µÓSl/Ø=ƒˆ/jÛ¼)WUz„Âgl ôAã´hûßH¼‘Ê6ÒG'‘¦‰îÖz¯‚by>ÒNÂWu5á#âä³.ƒ]PÞ×UÁ8SÉÞå Ž] 5Ò JÝÜ™…™GãftÞŒØß+,bAÄQW‡-±£Œ£A¨ ÊU¬þ53Î95T_#ÙœFƒÒ 4*³¼|‰&qÏÓ9.vd‹z¢eÕA¼ÉW _x8ÇèSRHÑW¤/6·8±'ÝPeÈ\ž^n‡±ËñØÝ(éN)cmÁp'A?Cá¡Û¼ã‰ê‰RÒØSL!Ç,Qð\UJs#Û-,¨9•Ûh’0«Ð¹ÑÎL”>ó/9õŽ÷Iš¹U@ÑO :Uí«ëŒ£žêêDq€”îb òX›-%_æ;Ç­0Â2ös#4V>õ¤Á¤ÏmѸafvn‹…éoZýª9÷œ¨Õ¶k ʈUòX0ßÇûÆpµ¶.9Þü:p¯I×\)a$E'aÂOØ ï¾Òžg Q—Ê$ì¨øIþ€ôSFœì×Òud¶€˜%®ôR•¨“‘5÷²ÕÓ^<” èõé±g)»Zá6@T3Èä=§,°c5ãË‘RÜO¬¿„¢A¥„‚ˆÏãˆyÂý©qÁTR©Ó@Ñ ´ûìàt¡Bâ -CøIÀIX¦VBUÓqYï!â«–1®õOÕëµ€±¢ÔqŸ€ùÀ8‡²`Ä7,¨t XÉ ÿdšY¶\9]ptÆŽ”|‰€YôJsã(‹ŒÑƒ^O/Å£e§í> Q|tÎôܧ¢kb‹óÛ©4Å53ç«æÂD3d&`@¢€—-„ ŽIªàê)ÜW%Ç9êêàbbòã×`„î 7ŸZ£šOâÞ´Rüu‹=afº¢c¥Œ÷nbë­l9œš?IFêéÞÏpI\,Žý¥éíann|x˜Dá# w¤ÜEIdï“â0‘NjHxFˆ´·!Wè…b}FñâpÄ]XJ1s ² $3×Ú¶ úUè±…´Çš4ð¢)!×÷dþ¡F6ÖKí˜{Η- ‚*‡:¥´s@ÞpÔJL sÍLŠc’m|4œ»p3jž¡6NbÆBh'Æk וÙàÌMààU€Ciî™A#»b»´#ÙÔú°Ä†Ï7U ›V¦*&C\—íuåÆÕ9Ì+”üOØNð¯ë…šªý.w‚ Lµ@Ûˆ/L’“Œ>xêCö=“¤•5´TÀÚ#]4wÍʺ›u^_rG<qÈRéU2¦ÖãYÃ4@ÄxÝÍuò½l,p?‹ƒ>Ÿn½}Ö€°ry`ªßw”üÈDøäâf¤¥x[™‘?âÛ€DÙJFl•3Á'¸ÕÆ„:mmû?µwwÛ[ûxÿ—Zþ«Îzûý^Çßÿ¾ãïìn¿Ým¿ó7öŒWìkÿÍn§ão¿ñ׿oï¾í4Qn·ƒn[ð‘u RÛü»óçýÎÖ¾¿ÓÙ}·±¿O­½úà·wv¨ñö«ÍŽ¿Ùþ‰V³óçõÎξÿÓ÷-oÍÿ´AãÙÛo£ÂÆ–ÿÓîÆþÆÖ[nޏ»o¿ß÷¿ßÞ|ÝÙeoݧÔ;WôwÚ»û=ÆñãÆëü¤æÚ{4ì9ÿ§ýï·ßïÛÁcrí­þ[¯›~gƒêüyg·³Gó÷¨íw4â½ÜØZß|ÿš_Q [Ûû´N43çþ6/)kZ§ÁPûÞ»Î.­ßÖ~ûÕÆæu Ïá7û[Ôû·eäëï7Û4‰÷»;Û{èo°„Ô-øîÆÞ~{ÏÓ…ýŸ÷mÛ­.µñ®½µÎUØHL×ÿ°ýTƒæ½ùÒ»»he{KpËr ›GPÒù0ð~k³ÝíüÏ{šO$ ö[‚6,¦³ïÞOÔ9v¨¸ùM®B/²Íÿ@`´í¿kÇì 4L빇 Š :Û¯¶±¯h<<,[ôºý®ý¶³×ô,p×êLÞô÷v:ëøBï ôh¯7eUèýÏ{ì"=ÐFü6m'¦8Ô-ìm¡¾‹ç²žõ]€?ÀÅæö€:ÙoûNíõõ÷»t´P5h4{ïé°mlñ¦x˜/ŸæÝ׿<ñ:ûoÚ›ïwK0F=oÓ¢I†5»!ÈöM†ã uµþ½îžŸ;µüïi+^u¨XûõÀ<ÒGgaoC×d[[ÐudÄÆÁ§4?._áÀßù^ܤÚ,ІuŸé?=ü„»EÌŽR¹¬”Q/‚’+½²ˆ¨@Ž4bE½ô”XžqüG:öH5Ù$µôGD;•¸ùâ¯`*:ésˆÂôˆŸ»^1çåiÐ@°ǤœrÓ µÆb£>4qF%;jrÊX#ëÌ»ÆRð/, ¥Á)¦†ÛÚS˜ýûØÆ„7jcá;M°¨D ˆÏ 1ŸÂ©Ú¬ˆyO•M˜مMqé9+R˜±3Ö~æáç,;0'×#‹P8ŠYbWöäã‰NÄèÀÑ ë´HêùG¬'×7ÎÔR¾ÑN›>!ÙãÔ'’ˆ3QÀPÀ^áßp[ù`ê?Âáê›Õg¦çéW¯?µ²_n¿_ÚèÆÜ. ÷›‡‰å¸ÚÝ3¼êŠ&¸}9|£õÖ›Í(eFn:ÙÌŒaÜJ=ï%Ý(óÏ­êpM±*†Ã«g¬ël˜.¹¢@®H„@cˆ;!ð/m†š Y½ËWÑZ—N½V´H§iqo@¦÷ÂÐ^ô{Å2K89GñBÎJuêP¬»p9RäüDf7¬îŽ3[Ë—g Ö¯b¹~1¦¿yçx~ÏCP"«\¨Ñ³k„Y‚[᪖ÄCšÄóOˆ/ê‹Þ3箑sOmôhïŒÁ:&Ö£Wn ƒ.›½©#§TB*rŽ®“Ž‘6pHö'aí |¿øºY8Î8;Ÿ?Ë¥ê]’%4‚´ýjo{“xÍ.ßü’aBÁÁO ÀæØÕ‹Z+;E|Ñ&aýðõyôÀ-h$•Õì¥Û]·æ¤%Ž+çÓÄ<¶re>ßf|r}µ©­ðkâns±%9)rfôÙö)VÔ’õdžã:Î)Ô°¸±=˜¤4Ö/8¡O•CÓH&ÑÓóù? ½ALM.tiY­1‡Z°p.,“³(N"±ëÚˆ!Ñɲk‚‘¹NJ<¥ju÷n‘µö L¾Dr'^ ¾ßÔ»¡ÙÕ ¦f„Ñeª¹,g.‹S1üGtê (ŸJ¼æ÷ê§À‹‚íKñ¡’«“ L%ÚâC<{ÓahÎ8hâÉÔv$ÞAÙøˆp>Á¡Û95ô³ç5˜ÇØcޣܖ uÎØ7n0iêԨ³?a4þ÷A÷#®½§¶þ(Ž$ý&(ÙŸÒQ‹‡ß4ý%âÕ’¨ÏyHÀ´È‹&òu¤‘‰ðú‘ Hõº3Юղ¨Ý(Óp~Üý• b8X›rÀÙ0Ñ&1,ÔÀ6œXªh<ãÎñ™@ûzŒ2b4Ø·ËíÑÑ«§Ö+ÅÓÆ IÂ…q5AÝ=bèLüLE® ¯:×EYµù˜Iéß-ÿ_ó=š>@Wßÿðlùùò‹,ÿÓ—ÏþkqiåÙ—ùß~“Ïgx:I“§'Ñw’ø£)q%ConnîMþ²YŽ»2÷ͪÓÜe-¢“ƒ‚¨²Ç¦´dÌê[BDæ'òj‰ˆ¥æñøDë‰5¿í›Ä>#„IØdË>™f_Ï •öÍ/haíw"¯=oœLå¦b}CXö4:ã~ãh·Á¯:I'¹²ë\v‡Ë‚4çêzÇÇDüŽý5ÿ ¯²ZÓ¯aµjGž×#Qï4öøÆ—:n^OÒ4-Ї¶ws›8ßËÎ_Ò˜#ÝØSëÈWŸC¹mKew.§-òýËjáÁ·¾]RI¢k–+júC:Ý$¾öÃ!Í«¡q)=¬Õ4~Z¦Èÿ£?̦KïÃþAt”Vÿ‹5¾†Ô‚8•¡FEøàÒØÑÚü·ô,èð iÑ_ð—V©1é(W¤Ð~Ø·=ÌW7V#¨©*þí¬âµ+Žˆ„pNþz׬”Bƒ0ÌöÈÛÏÞʯ®ùÿ¨a“j« ´3IHß¹Æ?¦8+JÉqåtÚvèG‘àí»løô›éן¤ \jñÄÿèîRØÏð m¨s›mèàã í`u‚G4Lú¹tÔ(./…±üÙéâšqO½CxraRWòÙ*+Î’IZ5¦ ¿ýønuç$&ö!³] ¦ÄqFŒÇPLŸ„㋽ xþ„èÜŠÙQ‹µÅùQ·œ¶^i>|•z8±t«ˆ*Œ¨gk\…rǬô€#Ç`ÎÚ2ïˆaÈŽ/G&5}pâ¦8@0NˆöëF¼ ­l 3ãA¶Œ°1àúXËÛÎ!Beªù™hŽNÁžÉd&$s2\Öh2!1†šÕZ”6Æh1óm1p=°ñö³Ž£ª¡‚݃Ӫ„pbkt-•¡Ö«›#ʲ[“¨í4’æÄ­ß÷ 5®%Z¥V²5$ì9<òeqJÅt‹ZÄÒÒþÖë´3„÷.Í£ª¼8õÒICVÄÚó3“[¹ÙÇž>lä„ ö6’¶ ò-7§FYË­<£›ÚáøI bš{C£©Õ¼ü†\ÛB¶gõ…7¯-,,øORü5ꦱ¦c¶Íªú¸þÝ©/]6ut³êf n‰:/ÙRÓ–›þ/ô÷—ezËë{°xt°Dˆ[~{p°lÑ«•Ü«gqÎ}÷¿ð¤×|Òó¿?ß}÷$ÃX£%0ƒè’XCôý‹>øh7Ç8åi² 98k'EÐÄ£-Q*Ì\$‹ _[­e3S+»|T-ÁéÎÐÿ¾¨FÔ•¢¦3E‚5_æÀÏè8Ò b\ •㺦ûh˜†ÉøšîO~YZýåšî¿°Ý{ˆV®Ûg\Uè$õà«úÏ׸¤jA^~yJ_NOj$чAÒ=÷¤r:9¹IýÃ| “­>FT+õz÷<©G„¹Hîº|²¸|‰3‰Ð±8ü êËÏ_Yµµ[“[ý‰V!Ñ_ˆøƒcù1®ýS¥o•7Ò/,~ðt[еnë 6…zXk]ÿo“xZiAé]”z?œô°êÛ± Z þõE°û©°û´!zËîéâÁj²ê‡Èa’È—ˆ3¾¬ÑYJÏÃ~­ÆÊ·ô¼–Í`w2”;™ˆø¢’²ë<®hHT»©Ô»©é(òEJ‚ä¬,Œ'r½_.ßa1›Ýû‘x¢ ÉšÂÒò;I¥à2YM☠¶p(Œ53Clš1†7.hܶ´"SÇ wjÍЙsàïW‹ÂÂäÆÁ&!G½±Çb< íÂdïˆåÎLÙ þjþ¼þ” ƒŸFzõ$ýÜgøuÞÆÃìí7î[¡¹ô"&Þ‘7^Pip’ò>®Y-’>qÊ@ýÊïõ2îljuûî ¦S׎œfzQÂ:mNJ˜?5JÓÖ怡­ Äu„SpšF×§ã^4\s+lìt® Tž–½TAïtŸÓx·ßï_ѱ:°—ýc½”0]ÍMxþ]QµÛÓðø´—®ÑZ°Qv§ÑeM–šåÍÅ¥àÊIÀÿ©+ÌrN¨ þ©Gÿ4Tàª0³”Ö4’ZD?éþK¨¿,,Y&+jZüIn§ WU†¶TÁ2˜Ëdá«îT,Èi<^BÛ´Ò§Á¤O¸%N1ÀFu» f°ôßü ~埵ZìøQ¯É½é‡Ã')1GþçßΉ~¤Ž•%DÖh\Q#9€NÄÎ䨑W7•¦,ÇêÚ)ó„®›õŒ±˜.Šc‘HÏüxäLß}n·˜àÙ –ŠÕhÏ@ŒtJ5]o£è)¼ŒZ‚)äµXÒÊÖ 8 ¿Oc”Ö?óÛÅAºÊˆ³ÂéÙ3Ž>La4‡$U…ü/—@µLÿÒ6cYÍ…M?Á»:Úyš`é «™FÊp~WG"×­tÔgs»µ2ó!IcqÈÊ´úIˆ”­dR²ÃF,¤´¡Ñ­´سÂ:ô‚ÅÄš s6µñF€.ˆíî¼'I|LÅQäPòŽ&²¹ó/Å«qì)s 2KYg¸ŽYš+P¦•0+¶SÔÕÅ£z£Èššb`Ê%ð'P^æ5MC ÖZ•Ç/ŒŽÞ…IõœÀ+Ãq]Îsm´SJÒP¯íœ{ð$=Ò##FŽÿq)Þ¦E”sŠU0´ ù¹tt•xÂòÚõj4å ÜBÞSSDxù†wý,2^k-¯)¯¦a:,ëÙ°z%騀(*W˜„ YËm«{NœdýÀ¶qd¸À«ª¨A±(£qýo˜”9íÕ0½aœD~„5`ªŒ –[­¤×¬cÂ~¤6,2¶UÂ.Í¿+޾”ßžRÒëÞÒ;Ml&•[~{èOFЄ7HnDÁ(uS8І‡ ©•ñ±Cƨo\H3 ÿœÁÇÎ*£ Á¥šRTò‡¡ÓäŠ9æg… 6ëÈ|7w_.Ó„õb–H#çzh}æÙa3âzºbᛉ¬$ìC­(å©«™QL_àØ2J§iK¶É>¢v8½Ì'—wÞ9ÂNÕÓþ$=¯ç8$3yÀIA¥Xì–‹ÁÈ´1«d±‚QÝslD¼k¦2Á³üë0Œ©¤¿H6–äÍyV¤2 $²Ä•†!}gh¼eMœê¬ëâ™.+”2rîúñY}ž­ +€üâÄ=—¬±â°x©˜œ=B° ^ ñX½ 8µ l‘ððâ=œõe/JÊ a¶f6 ^sjš‚ôõ @£·WÂ’ ÖÆOªX+'s3‹v ܆fX8==Â5÷ƒž¿0Z4c®°¸Ñ»¯€5S*º^æqõHyÄ^æˆó\*·]7Ï.ÐC¥ÎEu~˜ˆœ‹`ñÁˆÄÑ&!¥( ( «)ËO ¥p' *?²c3KA”,NˆÜ%Ja&ygP¡<° >±>ìVU§Fx$Ëʪc§XÉË&‘˜®³:L¦Û¥™¯ÅÚ–šÁS\–²]-’È“\ÅŒ–K‰ç'WMæD§…à(s‡˜Ir€@óËŽc|µi­ií;=Ï6‚ž/W¨ñ/ ”pÓ±æ–?ÏÝ‹žè'ˆ”Ñw¢|ù–À<ø%AÑÓÚýͺ$èªtŸº©BÅÐ - F‘G•%2Š´‚^/Ó¨dü9áP["i«L΄¿Rx)!þ((Û¦è×1BréJäÜ7LµZOät›²qªÔU™KÅ‚Ø;KÃŽNæt–œ»xhyHeáQ¦m•8w{gdœ0žÅ¡ØÚ³Fº W£å.Ï5߉ÙiS;¿,®ã“3Ñîù̉V¨„š†õfÍn‘Ã6Ê]Å\ùÖNåö§+AÇÅ7#³©4@ ]½È3á'CZ¬Šrz<ÝȵÔBKrûÖì† ^„á%ô»u#„T[5¨pâOa='¬\½óŠ9fOü®”ºv¸˜9ˆêr{ÜHŽcjT#‡ªØBFí¢V.\ ”E:®0ÛÏQ»,‘öAŸÛ€ËÜny¢ŒÔͧèûë™ÈxÕÔ«AÑÝ“êÙêê–ü"¬fT&­µ|ˆBá¾üL·j†Qi0¿5½ÊçÔ,„í:Çg^5‡´(}ò*Z”ægéúsU‚{;&ß&’4}åáà—Ÿù»$?I…Kkâ›"$þ.Ͷ\ÅÉŠÐØ‚7šYa)Ùȱ¦ìè©/„+em¸|‡E”²’Ä®ƒˆ*pÞ3¶ŸcÄ4–<¯3«ÌAm§½ÿ}ÍèðÉ¥¡ëJ]EóFMôÖðf#H¡|œ†:mIú[5Òï?oÿP-塈»˜ŒZF/GÔZÆÙ¥èð‹Ôÿ_q<•‰qBÂOA—^X>º`͆Œp“H=ÿˆH G¡>ÛÆ+ôuãïßrŸL·•eÄp«n¾ÌKsH«1R“çKb¨wÛïÖxf-„°$ÝVÎÃñø¹§Õ¯q>HÎçç?^à›³Æì¤t,þþÇ1’R[;Ÿ²ªQ¶®i=±˜Çà|í@4ÑÚŒ.¯m)s\°Õcã2@Íù ­°F¯<>†SéÞ”m©sC½v\c“b£ìßå.ݵp”5!Yj™²çÚ1nN«uR8[2žû1¦d|Ré«Q`0¸R¡r÷4ê×ÚhínT‡C狼vêÎéql²$ÔÔÙ ¸»Ž‰+„Õ­zœ¸°2®§R +‘F «ÔâpÒ¢6§’G€Y†ªÆÞ3ù U,NB»(˜ ƒa½†éÔ|ZM34àG´Ðɇ\ßËõÍ[Øa ¡^[Xå1ZT¥´¼ê?)0ø3>DGxݹV£‚_›Io3]˜zжb½d—ªé^Ê)æwì¸ìðÀÚÌ ãAçqáÊcS¬>?o¾:¢Fˆ“”w>°€0¯YgÎ3µ ”Õ/ófSé€ÿÐI88*¿%6žë)e „Y Ò–¨@Š•¸Â  Gz–m+´1 ¼Фå¨CÅH C $¶£†‰W ‚ï qŽVì­ˆF~c¦ÀÄU¯#™âÙOǹ ±óhsDu’gáæ°½ÃlŽ|¸‹ìµZÙ,ïkFÁçPÚÂŒÄ òojñ5;Wè+IÆQÍÛ¤~®B ÌÅe4®îóoÒ'Ë·ëq®[(ñæ*{ødgfô.³ÊëüXE&Š¿ê)EÒ¡“$â–æ.ÇSŽÛÞJȉBY"¨î}*½OÃô–½ª†pª7÷ûÖ¬4cžCéiß­£a|Ã~:Òf 7Ý RPŸ3 ò°ŠÝ­ ÜZº г[N•ï;EjÌÑô’:FêÑê©.°Â¨Ø ýVlí*Áá8 ‘¯‰$r‡}µ˜h{‰-D°ÃýÕãXvúßzÿ®ÒÇ~: –kMJ–œ3š%ÊŒJzdŒ1cLŒq*öàæk¡‰œb? ”˜&רº1}ÃK¶3Ï·Æ  ³¦ÚàãP‡B k¶^a¥BõúæFE`uÝ ÒÅÖsj:Ÿ@fyqiqúþ«$îE!ÉÔ±ÿÇþþÝ Ò+£Vœœ}#¬=_WïU¦ƒy =·{£‰s‹B}s—åÖ¶—%Ø©â¼(¨v—üG0oø}ÏøVžö£.³ÏŠÕxe§Üÿ‡q£b»•°p &-¨™'~U 6ßfµD¯a¦#ØŽÙµÝ"l-7eÅË•–g‚&cðŽ5ûç¡O$vu0Ç*áuÍZö)tÕ³x×”Ö¨´Q/{zg«*¹ÖDøwáÑ™qN?a*ˆ¢¤ÆOj%FµJ¯û€yìýw;ìÕkRÀú‚ïuÄ(1߯8ÛˆÙ0#S[³,<5úb—1äh•ÌHœJð8õ —bª´ß¡Aà/ýq•ÙPÓ#ö}å†rÈf¨ô1_͉½ÚÕf{ë-:Ø\?nonò7zò¾ý¶SÔ§û¬­×ªÆSÛÿ ¯Zíí»ýêë¯EY—k—Jlo¾·µ'E¾Z¬.ôv·³s¬|µi,wʦa.žX}EjSiŽ +гªŠ M1W¾³¯EŸ73t¿l~wqŸ¡I`€3ã»QgWº (ÚpÌXküHÝÇ3 Ñt¬âå1[AQ—ÞŠý;"zÎmâÃþ÷Û[,> 1× »²BnEóÜýg´cMæÍ¹™}cïÖɰɩÌS½ŽJ5i…FâS†Œà¸»Ià<”K¹›|AÂìê)rU@*µfI¯$^þØÙ…„ËRãRíÚ‚Ço66;¹_ã×Zk=µ+ãhU2J| Qï5ŒãÿðìØ99õì̽ %µ gw—½Ar·Ó~ý®Sô[[Nñ€ýįƒÅ#ê_*µÆ—ãZ£!¶t /\]Œ^œùz­–)1Uq+/Žq?o­VÖkj1Æ#ˆbIÒµ»µ×rç+ö÷Ä={uÕ_!m÷G磮u•Y§÷]m~mÃ\ò֞Рp_•Ó¨_·¨IK¶÷6pWD#;ý¾"±{ýíÎfÃmf ÙŒ©Üf0<›ŸPýÎð öÝbÛö ð=¹ÉŽ»õ7h°ˆ'cå}VZ¯¦ ¼Ûðûatéï‰É!+½h„ôÚæïw×”žï‹¾Zë5M¬<ïÈÚ?$õå*£6‹8{­ÖÆMcHGpË„¢Ú|õã w #include #include #include #include #include #include #include #include #define REGION 1048576 int main(int argc, char *argv[]) { pid_t p = fork(); char buf[REGION]; memset(buf, 0, sizeof(buf)); if (p != 0) { int done = 0; int fd = open(argv[1], O_RDWR|O_CREAT, 0644); if (fd < 0) { perror(argv[1]); return 1; } int i = 0; while(!done) { printf("writing %d\n", i++); assert(pwrite(fd, buf, REGION, 0) == REGION); int status; int ret = waitpid(p, &status, WNOHANG); assert(ret >= 0); if (ret > 0) { done = 1; } } close(fd); } else { sleep(1); int fd = open(argv[2], O_RDONLY, 0644); if (fd < 0) { perror(argv[2]); return 1; } printf("reading\n"); assert(pread(fd, buf, REGION, 0) == REGION); close(fd); } return 0; } ceph-0.80.11/src/test/cls_hello/0000775000175100017510000000000012623077035020401 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/cls_hello/test_cls_hello.cc0000664000175100017510000001072712623076744023730 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include "include/rados/librados.hpp" #include "test/librados/test.h" #include "gtest/gtest.h" using namespace librados; TEST(ClsHello, SayHello) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); bufferlist in, out; ASSERT_EQ(-ENOENT, ioctx.exec("myobject", "hello", "say_hello", in, out)); ASSERT_EQ(0, ioctx.write_full("myobject", in)); ASSERT_EQ(0, ioctx.exec("myobject", "hello", "say_hello", in, out)); ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length())); out.clear(); in.append("Tester"); ASSERT_EQ(0, ioctx.exec("myobject", "hello", "say_hello", in, out)); ASSERT_EQ(std::string("Hello, Tester!"), std::string(out.c_str(), out.length())); out.clear(); in.clear(); char buf[4096]; memset(buf, 1, sizeof(buf)); in.append(buf, sizeof(buf)); ASSERT_EQ(-EINVAL, ioctx.exec("myobject", "hello", "say_hello", in, out)); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsHello, RecordHello) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); bufferlist in, out; ASSERT_EQ(0, ioctx.exec("myobject", "hello", "record_hello", in, out)); ASSERT_EQ(-EEXIST, ioctx.exec("myobject", "hello", "record_hello", in, out)); in.append("Tester"); ASSERT_EQ(0, ioctx.exec("myobject2", "hello", "record_hello", in, out)); ASSERT_EQ(-EEXIST, ioctx.exec("myobject2", "hello", "record_hello", in, out)); ASSERT_EQ(0u, out.length()); in.clear(); out.clear(); ASSERT_EQ(0, ioctx.exec("myobject", "hello", "replay", in, out)); ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length())); out.clear(); ASSERT_EQ(0, ioctx.exec("myobject2", "hello", "replay", in, out)); ASSERT_EQ(std::string("Hello, Tester!"), std::string(out.c_str(), out.length())); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsHello, WriteReturnData) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); bufferlist in, out; ASSERT_EQ(0, ioctx.exec("myobject", "hello", "writes_dont_return_data", in, out)); ASSERT_EQ(std::string(), std::string(out.c_str(), out.length())); char buf[4096]; memset(buf, 1, sizeof(buf)); in.append(buf, sizeof(buf)); ASSERT_EQ(-EINVAL, ioctx.exec("myobject2", "hello", "writes_dont_return_data", in, out)); ASSERT_EQ(std::string("too much input data!"), std::string(out.c_str(), out.length())); ASSERT_EQ(-ENOENT, ioctx.getxattr("myobject2", "foo", out)); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsHello, Loud) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); bufferlist in, out; ASSERT_EQ(0, ioctx.exec("myobject", "hello", "record_hello", in, out)); ASSERT_EQ(0, ioctx.exec("myobject", "hello", "replay", in, out)); ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length())); ASSERT_EQ(0, ioctx.exec("myobject", "hello", "turn_it_to_11", in, out)); ASSERT_EQ(0, ioctx.exec("myobject", "hello", "replay", in, out)); ASSERT_EQ(std::string("HELLO, WORLD!"), std::string(out.c_str(), out.length())); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } TEST(ClsHello, BadMethods) { Rados cluster; std::string pool_name = get_temp_pool_name(); ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); IoCtx ioctx; cluster.ioctx_create(pool_name.c_str(), ioctx); bufferlist in, out; ASSERT_EQ(0, ioctx.write_full("myobject", in)); ASSERT_EQ(-EIO, ioctx.exec("myobject", "hello", "bad_reader", in, out)); ASSERT_EQ(-EIO, ioctx.exec("myobject", "hello", "bad_writer", in, out)); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); } ceph-0.80.11/src/test/encoding.cc0000664000175100017510000001111012623076744020532 0ustar jenkins-buildjenkins-build#include "common/config.h" #include "include/buffer.h" #include "include/encoding.h" #include "gtest/gtest.h" template < typename T > static void test_encode_and_decode(const T& src) { bufferlist bl(1000000); encode(src, bl); T dst; bufferlist::iterator i(bl.begin()); decode(dst, i); ASSERT_EQ(src, dst) << "Encoding roundtrip changed the string: orig=" << src << ", but new=" << dst; } TEST(EncodingRoundTrip, StringSimple) { string my_str("I am the very model of a modern major general"); test_encode_and_decode < std::string >(my_str); } TEST(EncodingRoundTrip, StringEmpty) { string my_str(""); test_encode_and_decode < std::string >(my_str); } TEST(EncodingRoundTrip, StringNewline) { string my_str("foo bar baz\n"); test_encode_and_decode < std::string >(my_str); } typedef std::multimap < int, std::string > multimap_t; typedef multimap_t::value_type my_val_ty; static std::ostream& operator<<(std::ostream& oss, const multimap_t &multimap) { for (multimap_t::const_iterator m = multimap.begin(); m != multimap.end(); ++m) { oss << m->first << "->" << m->second << " "; } return oss; } TEST(EncodingRoundTrip, Multimap) { multimap_t multimap; multimap.insert( my_val_ty(1, "foo") ); multimap.insert( my_val_ty(2, "bar") ); multimap.insert( my_val_ty(2, "baz") ); multimap.insert( my_val_ty(3, "lucky number 3") ); multimap.insert( my_val_ty(10000, "large number") ); test_encode_and_decode < multimap_t >(multimap); } /////////////////////////////////////////////////////// // ConstructorCounter /////////////////////////////////////////////////////// template class ConstructorCounter { public: ConstructorCounter() : data(0) { default_ctor++; } ConstructorCounter(const T& data_) : data(data_) { one_arg_ctor++; } ConstructorCounter(const ConstructorCounter &rhs) : data(rhs.data) { copy_ctor++; } ConstructorCounter &operator=(const ConstructorCounter &rhs) { data = rhs.data; assigns++; return *this; } static void init(void) { default_ctor = 0; one_arg_ctor = 0; copy_ctor = 0; assigns = 0; } static int get_default_ctor(void) { return default_ctor; } static int get_one_arg_ctor(void) { return one_arg_ctor; } static int get_copy_ctor(void) { return copy_ctor; } static int get_assigns(void) { return assigns; } bool operator<(const ConstructorCounter &rhs) const { return data < rhs.data; } bool operator==(const ConstructorCounter &rhs) const { return data == rhs.data; } friend void decode(ConstructorCounter &s, bufferlist::iterator& p) { ::decode(s.data, p); } friend void encode(const ConstructorCounter &s, bufferlist& p) { ::encode(s.data, p); } friend ostream& operator<<(ostream &oss, const ConstructorCounter &cc) { oss << cc.data; return oss; } T data; private: static int default_ctor; static int one_arg_ctor; static int copy_ctor; static int assigns; }; template class ConstructorCounter ; template class ConstructorCounter ; typedef ConstructorCounter my_key_t; typedef ConstructorCounter my_val_t; typedef std::multimap < my_key_t, my_val_t > multimap2_t; typedef multimap2_t::value_type val2_ty; template int ConstructorCounter::default_ctor = 0; template int ConstructorCounter::one_arg_ctor = 0; template int ConstructorCounter::copy_ctor = 0; template int ConstructorCounter::assigns = 0; static std::ostream& operator<<(std::ostream& oss, const multimap2_t &multimap) { for (multimap2_t::const_iterator m = multimap.begin(); m != multimap.end(); ++m) { oss << m->first << "->" << m->second << " "; } return oss; } TEST(EncodingRoundTrip, MultimapConstructorCounter) { multimap2_t multimap2; multimap2.insert( val2_ty(my_key_t(1), my_val_t(10)) ); multimap2.insert( val2_ty(my_key_t(2), my_val_t(20)) ); multimap2.insert( val2_ty(my_key_t(2), my_val_t(30)) ); multimap2.insert( val2_ty(my_key_t(3), my_val_t(40)) ); multimap2.insert( val2_ty(my_key_t(10000), my_val_t(1)) ); my_key_t::init(); my_val_t::init(); test_encode_and_decode < multimap2_t >(multimap2); EXPECT_EQ(my_key_t::get_default_ctor(), 5); EXPECT_EQ(my_key_t::get_one_arg_ctor(), 0); EXPECT_EQ(my_key_t::get_copy_ctor(), 10); EXPECT_EQ(my_key_t::get_assigns(), 0); EXPECT_EQ(my_val_t::get_default_ctor(), 5); EXPECT_EQ(my_val_t::get_one_arg_ctor(), 0); EXPECT_EQ(my_val_t::get_copy_ctor(), 10); EXPECT_EQ(my_val_t::get_assigns(), 0); } ceph-0.80.11/src/test/bufferlist.cc0000664000175100017510000016144312623076744021130 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Cloudwatt * * Author: Loic Dachary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ #include "include/memory.h" #include #include #include #include "include/buffer.h" #include "include/utime.h" #include "include/encoding.h" #include "common/environment.h" #include "common/Clock.h" #include "common/safe_io.h" #include "gtest/gtest.h" #include "stdlib.h" #include "fcntl.h" #include "sys/stat.h" #define MAX_TEST 1000000 TEST(Buffer, constructors) { bool ceph_buffer_track = get_env_bool("CEPH_BUFFER_TRACK"); unsigned len = 17; // // buffer::create // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { bufferptr ptr(buffer::create(len)); EXPECT_EQ(len, ptr.length()); if (ceph_buffer_track) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); } // // buffer::claim_char // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { char* str = new char[len]; ::memset(str, 'X', len); bufferptr ptr(buffer::claim_char(len, str)); if (ceph_buffer_track) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(str, ptr.c_str()); bufferptr clone = ptr.clone(); EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); } // // buffer::create_static // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { char* str = new char[len]; bufferptr ptr(buffer::create_static(len, str)); if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(str, ptr.c_str()); delete [] str; } // // buffer::create_malloc // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { bufferptr ptr(buffer::create_malloc(len)); if (ceph_buffer_track) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); EXPECT_EQ(len, ptr.length()); // this doesn't throw on my x86_64 wheezy box --sage //EXPECT_THROW(buffer::create_malloc((unsigned)ULLONG_MAX), buffer::bad_alloc); } // // buffer::claim_malloc // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { char* str = (char*)malloc(len); ::memset(str, 'X', len); bufferptr ptr(buffer::claim_malloc(len, str)); if (ceph_buffer_track) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(str, ptr.c_str()); bufferptr clone = ptr.clone(); EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); } // // buffer::copy // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { const std::string expected(len, 'X'); bufferptr ptr(buffer::copy(expected.c_str(), expected.size())); if (ceph_buffer_track) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); EXPECT_NE(expected.c_str(), ptr.c_str()); EXPECT_EQ(0, ::memcmp(expected.c_str(), ptr.c_str(), len)); } // // buffer::create_page_aligned // if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { bufferptr ptr(buffer::create_page_aligned(len)); ::memset(ptr.c_str(), 'X', len); if (ceph_buffer_track) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); // doesn't throw on my x86_64 wheezy box --sage //EXPECT_THROW(buffer::create_page_aligned((unsigned)ULLONG_MAX), buffer::bad_alloc); #ifndef DARWIN ASSERT_TRUE(ptr.is_page_aligned()); #endif // DARWIN bufferptr clone = ptr.clone(); EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); } #ifdef CEPH_HAVE_SPLICE if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); { // no fd EXPECT_THROW(buffer::create_zero_copy(len, -1, NULL), buffer::error_code); unsigned zc_len = 4; ::unlink("testfile"); ::system("echo ABC > testfile"); int fd = ::open("testfile", O_RDONLY); bufferptr ptr(buffer::create_zero_copy(zc_len, fd, NULL)); EXPECT_EQ(zc_len, ptr.length()); if (ceph_buffer_track) EXPECT_EQ(zc_len, (unsigned)buffer::get_total_alloc()); ::close(fd); ::unlink("testfile"); } #endif if (ceph_buffer_track) EXPECT_EQ(0, buffer::get_total_alloc()); } TEST(BufferRaw, ostream) { bufferptr ptr(1); std::ostringstream stream; stream << *ptr.get_raw(); EXPECT_GT(stream.str().size(), stream.str().find("buffer::raw(")); EXPECT_GT(stream.str().size(), stream.str().find("len 1 nref 1)")); } #ifdef CEPH_HAVE_SPLICE class TestRawPipe : public ::testing::Test { protected: virtual void SetUp() { len = 4; ::unlink("testfile"); ::system("echo ABC > testfile"); fd = ::open("testfile", O_RDONLY); assert(fd >= 0); } virtual void TearDown() { ::close(fd); ::unlink("testfile"); } int fd; unsigned len; }; TEST_F(TestRawPipe, create_zero_copy) { bufferptr ptr(buffer::create_zero_copy(len, fd, NULL)); EXPECT_EQ(len, ptr.length()); if (get_env_bool("CEPH_BUFFER_TRACK")) EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); } TEST_F(TestRawPipe, c_str_no_fd) { EXPECT_THROW(bufferptr ptr(buffer::create_zero_copy(len, -1, NULL)), buffer::error_code); } TEST_F(TestRawPipe, c_str_basic) { bufferptr ptr = bufferptr(buffer::create_zero_copy(len, fd, NULL)); EXPECT_EQ(0, memcmp(ptr.c_str(), "ABC\n", len)); EXPECT_EQ(len, ptr.length()); } TEST_F(TestRawPipe, c_str_twice) { // make sure we're creating a copy of the data and not consuming it bufferptr ptr = bufferptr(buffer::create_zero_copy(len, fd, NULL)); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "ABC\n", len)); EXPECT_EQ(0, memcmp(ptr.c_str(), "ABC\n", len)); } TEST_F(TestRawPipe, c_str_basic_offset) { loff_t offset = len - 1; ::lseek(fd, offset, SEEK_SET); bufferptr ptr = bufferptr(buffer::create_zero_copy(len - offset, fd, NULL)); EXPECT_EQ(len - offset, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "\n", len - offset)); } TEST_F(TestRawPipe, c_str_dest_short) { ::lseek(fd, 1, SEEK_SET); bufferptr ptr = bufferptr(buffer::create_zero_copy(2, fd, NULL)); EXPECT_EQ(2u, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "BC", 2)); } TEST_F(TestRawPipe, c_str_source_short) { ::lseek(fd, 1, SEEK_SET); bufferptr ptr = bufferptr(buffer::create_zero_copy(len, fd, NULL)); EXPECT_EQ(len - 1, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "BC\n", len - 1)); } TEST_F(TestRawPipe, c_str_explicit_zero_offset) { int64_t offset = 0; ::lseek(fd, 1, SEEK_SET); bufferptr ptr = bufferptr(buffer::create_zero_copy(len, fd, &offset)); EXPECT_EQ(len, offset); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "ABC\n", len)); } TEST_F(TestRawPipe, c_str_explicit_positive_offset) { int64_t offset = 1; bufferptr ptr = bufferptr(buffer::create_zero_copy(len - offset, fd, &offset)); EXPECT_EQ(len, offset); EXPECT_EQ(len - 1, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "BC\n", len - 1)); } TEST_F(TestRawPipe, c_str_explicit_positive_empty_result) { int64_t offset = len; bufferptr ptr = bufferptr(buffer::create_zero_copy(len - offset, fd, &offset)); EXPECT_EQ(len, offset); EXPECT_EQ(0u, ptr.length()); } TEST_F(TestRawPipe, c_str_source_short_explicit_offset) { int64_t offset = 1; bufferptr ptr = bufferptr(buffer::create_zero_copy(len, fd, &offset)); EXPECT_EQ(len, offset); EXPECT_EQ(len - 1, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "BC\n", len - 1)); } TEST_F(TestRawPipe, c_str_dest_short_explicit_offset) { int64_t offset = 1; bufferptr ptr = bufferptr(buffer::create_zero_copy(2, fd, &offset)); EXPECT_EQ(3, offset); EXPECT_EQ(2u, ptr.length()); EXPECT_EQ(0, memcmp(ptr.c_str(), "BC", 2)); } TEST_F(TestRawPipe, buffer_list_read_fd_zero_copy) { bufferlist bl; EXPECT_EQ(-EBADF, bl.read_fd_zero_copy(-1, len)); bl = bufferlist(); EXPECT_EQ(0, bl.read_fd_zero_copy(fd, len)); EXPECT_EQ(len, bl.length()); EXPECT_EQ(0u, bl.buffers().front().unused_tail_length()); EXPECT_EQ(1u, bl.buffers().size()); EXPECT_EQ(len, bl.buffers().front().raw_length()); EXPECT_EQ(0, memcmp(bl.c_str(), "ABC\n", len)); EXPECT_TRUE(bl.can_zero_copy()); } TEST_F(TestRawPipe, buffer_list_write_fd_zero_copy) { ::unlink("testfile_out"); bufferlist bl; EXPECT_EQ(0, bl.read_fd_zero_copy(fd, len)); EXPECT_TRUE(bl.can_zero_copy()); int out_fd = ::open("testfile_out", O_RDWR|O_CREAT|O_TRUNC, 0600); EXPECT_EQ(0, bl.write_fd_zero_copy(out_fd)); struct stat st; memset(&st, 0, sizeof(st)); EXPECT_EQ(0, ::stat("testfile_out", &st)); EXPECT_EQ(len, st.st_size); char buf[len + 1]; EXPECT_EQ((int)len, safe_read(out_fd, buf, len + 1)); EXPECT_EQ(0, memcmp(buf, "ABC\n", len)); ::close(out_fd); ::unlink("testfile_out"); } #endif // CEPH_HAVE_SPLICE // // +-----------+ +-----+ // | | | | // | offset +----------------+ | // | | | | // | length +---- | | // | | \------- | | // +-----------+ \---+ | // | ptr | +-----+ // +-----------+ | raw | // +-----+ // TEST(BufferPtr, constructors) { unsigned len = 17; // // ptr::ptr() // { buffer::ptr ptr; EXPECT_FALSE(ptr.have_raw()); EXPECT_EQ((unsigned)0, ptr.offset()); EXPECT_EQ((unsigned)0, ptr.length()); } // // ptr::ptr(raw *r) // { bufferptr ptr(buffer::create(len)); EXPECT_TRUE(ptr.have_raw()); EXPECT_EQ((unsigned)0, ptr.offset()); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(ptr.raw_length(), ptr.length()); EXPECT_EQ(1, ptr.raw_nref()); } // // ptr::ptr(unsigned l) // { bufferptr ptr(len); EXPECT_TRUE(ptr.have_raw()); EXPECT_EQ((unsigned)0, ptr.offset()); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(1, ptr.raw_nref()); } // // ptr(const char *d, unsigned l) // { const std::string str(len, 'X'); bufferptr ptr(str.c_str(), len); EXPECT_TRUE(ptr.have_raw()); EXPECT_EQ((unsigned)0, ptr.offset()); EXPECT_EQ(len, ptr.length()); EXPECT_EQ(1, ptr.raw_nref()); EXPECT_EQ(0, ::memcmp(str.c_str(), ptr.c_str(), len)); } // // ptr(const ptr& p) // { const std::string str(len, 'X'); bufferptr original(str.c_str(), len); bufferptr ptr(original); EXPECT_TRUE(ptr.have_raw()); EXPECT_EQ(original.get_raw(), ptr.get_raw()); EXPECT_EQ(2, ptr.raw_nref()); EXPECT_EQ(0, ::memcmp(original.c_str(), ptr.c_str(), len)); } // // ptr(const ptr& p, unsigned o, unsigned l) // { const std::string str(len, 'X'); bufferptr original(str.c_str(), len); bufferptr ptr(original, 0, 0); EXPECT_TRUE(ptr.have_raw()); EXPECT_EQ(original.get_raw(), ptr.get_raw()); EXPECT_EQ(2, ptr.raw_nref()); EXPECT_EQ(0, ::memcmp(original.c_str(), ptr.c_str(), len)); EXPECT_THROW(bufferptr(original, 0, original.length() + 1), FailedAssertion); EXPECT_THROW(bufferptr(bufferptr(), 0, 0), FailedAssertion); } } TEST(BufferPtr, assignment) { unsigned len = 17; // // override a bufferptr set with the same raw // { bufferptr original(len); bufferptr same_raw(original.get_raw()); unsigned offset = 5; unsigned length = len - offset; original.set_offset(offset); original.set_length(length); same_raw = original; ASSERT_EQ(2, original.raw_nref()); ASSERT_EQ(same_raw.get_raw(), original.get_raw()); ASSERT_EQ(same_raw.offset(), original.offset()); ASSERT_EQ(same_raw.length(), original.length()); } // // self assignment is a noop // { bufferptr original(len); original = original; ASSERT_EQ(1, original.raw_nref()); ASSERT_EQ((unsigned)0, original.offset()); ASSERT_EQ(len, original.length()); } // // a copy points to the same raw // { bufferptr original(len); unsigned offset = 5; unsigned length = len - offset; original.set_offset(offset); original.set_length(length); bufferptr ptr; ptr = original; ASSERT_EQ(2, original.raw_nref()); ASSERT_EQ(ptr.get_raw(), original.get_raw()); ASSERT_EQ(original.offset(), ptr.offset()); ASSERT_EQ(original.length(), ptr.length()); } } TEST(BufferPtr, clone) { unsigned len = 17; bufferptr ptr(len); ::memset(ptr.c_str(), 'X', len); bufferptr clone = ptr.clone(); EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); } TEST(BufferPtr, swap) { unsigned len = 17; bufferptr ptr1(len); ::memset(ptr1.c_str(), 'X', len); unsigned ptr1_offset = 4; ptr1.set_offset(ptr1_offset); unsigned ptr1_length = 3; ptr1.set_length(ptr1_length); bufferptr ptr2(len); ::memset(ptr2.c_str(), 'Y', len); unsigned ptr2_offset = 5; ptr2.set_offset(ptr2_offset); unsigned ptr2_length = 7; ptr2.set_length(ptr2_length); ptr1.swap(ptr2); EXPECT_EQ(ptr2_length, ptr1.length()); EXPECT_EQ(ptr2_offset, ptr1.offset()); EXPECT_EQ('Y', ptr1[0]); EXPECT_EQ(ptr1_length, ptr2.length()); EXPECT_EQ(ptr1_offset, ptr2.offset()); EXPECT_EQ('X', ptr2[0]); } TEST(BufferPtr, release) { unsigned len = 17; bufferptr ptr1(len); { bufferptr ptr2(ptr1); EXPECT_EQ(2, ptr1.raw_nref()); } EXPECT_EQ(1, ptr1.raw_nref()); } TEST(BufferPtr, have_raw) { { bufferptr ptr; EXPECT_FALSE(ptr.have_raw()); } { bufferptr ptr(1); EXPECT_TRUE(ptr.have_raw()); } } TEST(BufferPtr, at_buffer_head) { bufferptr ptr(2); EXPECT_TRUE(ptr.at_buffer_head()); ptr.set_offset(1); EXPECT_FALSE(ptr.at_buffer_head()); } TEST(BufferPtr, at_buffer_tail) { bufferptr ptr(2); EXPECT_TRUE(ptr.at_buffer_tail()); ptr.set_length(1); EXPECT_FALSE(ptr.at_buffer_tail()); } TEST(BufferPtr, is_n_page_sized) { { bufferptr ptr(CEPH_PAGE_SIZE); EXPECT_TRUE(ptr.is_n_page_sized()); } { bufferptr ptr(1); EXPECT_FALSE(ptr.is_n_page_sized()); } } TEST(BufferPtr, accessors) { unsigned len = 17; bufferptr ptr(len); ptr.c_str()[0] = 'X'; ptr[1] = 'Y'; const bufferptr const_ptr(ptr); EXPECT_NE((void*)NULL, (void*)ptr.get_raw()); EXPECT_EQ('X', ptr.c_str()[0]); { bufferptr ptr; EXPECT_THROW(ptr.c_str(), FailedAssertion); EXPECT_THROW(ptr[0], FailedAssertion); } EXPECT_EQ('X', const_ptr.c_str()[0]); { const bufferptr const_ptr; EXPECT_THROW(const_ptr.c_str(), FailedAssertion); EXPECT_THROW(const_ptr[0], FailedAssertion); } EXPECT_EQ(len, const_ptr.length()); EXPECT_EQ((unsigned)0, const_ptr.offset()); EXPECT_EQ((unsigned)0, const_ptr.start()); EXPECT_EQ(len, const_ptr.end()); EXPECT_EQ(len, const_ptr.end()); { bufferptr ptr(len); unsigned unused = 1; ptr.set_length(ptr.length() - unused); EXPECT_EQ(unused, ptr.unused_tail_length()); } { bufferptr ptr; EXPECT_EQ((unsigned)0, ptr.unused_tail_length()); } EXPECT_THROW(ptr[len], FailedAssertion); EXPECT_THROW(const_ptr[len], FailedAssertion); { const bufferptr const_ptr; EXPECT_THROW(const_ptr.raw_c_str(), FailedAssertion); EXPECT_THROW(const_ptr.raw_length(), FailedAssertion); EXPECT_THROW(const_ptr.raw_nref(), FailedAssertion); } EXPECT_NE((const char *)NULL, const_ptr.raw_c_str()); EXPECT_EQ(len, const_ptr.raw_length()); EXPECT_EQ(2, const_ptr.raw_nref()); { bufferptr ptr(len); unsigned wasted = 1; ptr.set_length(ptr.length() - wasted * 2); ptr.set_offset(wasted); EXPECT_EQ(wasted * 2, ptr.wasted()); } } TEST(BufferPtr, cmp) { bufferptr empty; bufferptr a("A", 1); bufferptr ab("AB", 2); bufferptr af("AF", 2); bufferptr acc("ACC", 3); EXPECT_GE(-1, empty.cmp(a)); EXPECT_LE(1, a.cmp(empty)); EXPECT_GE(-1, a.cmp(ab)); EXPECT_LE(1, ab.cmp(a)); EXPECT_EQ(0, ab.cmp(ab)); EXPECT_GE(-1, ab.cmp(af)); EXPECT_LE(1, af.cmp(ab)); EXPECT_GE(-1, acc.cmp(af)); EXPECT_LE(1, af.cmp(acc)); } TEST(BufferPtr, is_zero) { char str[2] = { '\0', 'X' }; { const bufferptr ptr(buffer::create_static(2, str)); EXPECT_FALSE(ptr.is_zero()); } { const bufferptr ptr(buffer::create_static(1, str)); EXPECT_TRUE(ptr.is_zero()); } } TEST(BufferPtr, copy_out) { { const bufferptr ptr; EXPECT_THROW(ptr.copy_out((unsigned)0, (unsigned)0, NULL), FailedAssertion); } { char in[] = "ABC"; const bufferptr ptr(buffer::create_static(strlen(in), in)); EXPECT_THROW(ptr.copy_out((unsigned)0, strlen(in) + 1, NULL), buffer::end_of_buffer); EXPECT_THROW(ptr.copy_out(strlen(in) + 1, (unsigned)0, NULL), buffer::end_of_buffer); char out[1] = { 'X' }; ptr.copy_out((unsigned)1, (unsigned)1, out); EXPECT_EQ('B', out[0]); } } TEST(BufferPtr, copy_in) { { bufferptr ptr; EXPECT_THROW(ptr.copy_in((unsigned)0, (unsigned)0, NULL), FailedAssertion); } { char in[] = "ABCD"; bufferptr ptr(2); EXPECT_THROW(ptr.copy_in((unsigned)0, strlen(in) + 1, NULL), FailedAssertion); EXPECT_THROW(ptr.copy_in(strlen(in) + 1, (unsigned)0, NULL), FailedAssertion); ptr.copy_in((unsigned)0, (unsigned)2, in); EXPECT_EQ(in[0], ptr[0]); EXPECT_EQ(in[1], ptr[1]); } } TEST(BufferPtr, append) { { bufferptr ptr; EXPECT_THROW(ptr.append('A'), FailedAssertion); EXPECT_THROW(ptr.append("B", (unsigned)1), FailedAssertion); } { bufferptr ptr(2); EXPECT_THROW(ptr.append('A'), FailedAssertion); EXPECT_THROW(ptr.append("B", (unsigned)1), FailedAssertion); ptr.set_length(0); ptr.append('A'); EXPECT_EQ((unsigned)1, ptr.length()); EXPECT_EQ('A', ptr[0]); ptr.append("B", (unsigned)1); EXPECT_EQ((unsigned)2, ptr.length()); EXPECT_EQ('B', ptr[1]); } } TEST(BufferPtr, zero) { char str[] = "XXXX"; bufferptr ptr(buffer::create_static(strlen(str), str)); EXPECT_THROW(ptr.zero(ptr.length() + 1, 0), FailedAssertion); ptr.zero(1, 1); EXPECT_EQ('X', ptr[0]); EXPECT_EQ('\0', ptr[1]); EXPECT_EQ('X', ptr[2]); ptr.zero(); EXPECT_EQ('\0', ptr[0]); } TEST(BufferPtr, ostream) { { bufferptr ptr; std::ostringstream stream; stream << ptr; EXPECT_GT(stream.str().size(), stream.str().find("buffer:ptr(0~0 no raw")); } { char str[] = "XXXX"; bufferptr ptr(buffer::create_static(strlen(str), str)); std::ostringstream stream; stream << ptr; EXPECT_GT(stream.str().size(), stream.str().find("len 4 nref 1)")); } } // // +---------+ // | +-----+ | // list ptr | | | | // +----------+ +-----+ | | | | // | append_ >-------> >--------------------> | | // | buffer | +-----+ | | | | // +----------+ ptr | | | | // | _len | list +-----+ | | | | // +----------+ +------+ ,--->+ >-----> | | // | _buffers >----> >----- +-----+ | +-----+ | // +----------+ +----^-+ \ ptr | raw | // | last_p | / `-->+-----+ | +-----+ | // +--------+-+ / + >-----> | | // | ,- ,--->+-----+ | | | | // | / ,--- | | | | // | / ,--- | | | | // +-v--+-^--+--^+-------+ | | | | // | bl | ls | p | p_off >--------------->| | | // +----+----+-----+-----+ | +-----+ | // | | off >------------->| raw | // +---------------+-----+ | | // iterator +---------+ // TEST(BufferListIterator, constructors) { // // iterator() // { buffer::list::iterator i; EXPECT_EQ((unsigned)0, i.get_off()); } // // iterator(list *l, unsigned o=0) // { bufferlist bl; bl.append("ABC", 3); { bufferlist::iterator i(&bl); EXPECT_EQ((unsigned)0, i.get_off()); EXPECT_EQ('A', *i); } { bufferlist::iterator i(&bl, 1); EXPECT_EQ('B', *i); EXPECT_EQ((unsigned)2, i.get_remaining()); } } // // iterator(list *l, unsigned o, std::list::iterator ip, unsigned po) // not tested because of http://tracker.ceph.com/issues/4101 // // iterator(const iterator& other) // { bufferlist bl; bl.append("ABC", 3); bufferlist::iterator i(&bl, 1); bufferlist::iterator j(i); EXPECT_EQ(*i, *j); ++j; EXPECT_NE(*i, *j); EXPECT_EQ('B', *i); EXPECT_EQ('C', *j); bl.c_str()[1] = 'X'; j.advance(-1); EXPECT_EQ('X', *j); } } TEST(BufferListIterator, operator_equal) { bufferlist bl; bl.append("ABC", 3); bufferlist::iterator i(&bl, 1); i = i; EXPECT_EQ('B', *i); bufferlist::iterator j; j = i; EXPECT_EQ('B', *j); } TEST(BufferListIterator, get_off) { bufferlist bl; bl.append("ABC", 3); bufferlist::iterator i(&bl, 1); EXPECT_EQ((unsigned)1, i.get_off()); } TEST(BufferListIterator, get_remaining) { bufferlist bl; bl.append("ABC", 3); bufferlist::iterator i(&bl, 1); EXPECT_EQ((unsigned)2, i.get_remaining()); } TEST(BufferListIterator, end) { bufferlist bl; { bufferlist::iterator i(&bl); EXPECT_TRUE(i.end()); } bl.append("ABC", 3); { bufferlist::iterator i(&bl); EXPECT_FALSE(i.end()); } } TEST(BufferListIterator, advance) { bufferlist bl; const std::string one("ABC"); bl.append(bufferptr(one.c_str(), one.size())); const std::string two("DEF"); bl.append(bufferptr(two.c_str(), two.size())); { bufferlist::iterator i(&bl); EXPECT_THROW(i.advance(200), buffer::end_of_buffer); } { bufferlist::iterator i(&bl); EXPECT_THROW(i.advance(-1), buffer::end_of_buffer); } { bufferlist::iterator i(&bl); EXPECT_EQ('A', *i); i.advance(1); EXPECT_EQ('B', *i); i.advance(3); EXPECT_EQ('E', *i); i.advance(-3); EXPECT_EQ('B', *i); i.advance(-1); EXPECT_EQ('A', *i); } } TEST(BufferListIterator, seek) { bufferlist bl; bl.append("ABC", 3); bufferlist::iterator i(&bl, 1); EXPECT_EQ('B', *i); i.seek(2); EXPECT_EQ('C', *i); } TEST(BufferListIterator, operator_star) { bufferlist bl; { bufferlist::iterator i(&bl); EXPECT_THROW(*i, buffer::end_of_buffer); } bl.append("ABC", 3); { bufferlist::iterator i(&bl); EXPECT_EQ('A', *i); EXPECT_THROW(i.advance(200), buffer::end_of_buffer); EXPECT_THROW(*i, buffer::end_of_buffer); } } TEST(BufferListIterator, operator_plus_plus) { bufferlist bl; { bufferlist::iterator i(&bl); EXPECT_THROW(++i, buffer::end_of_buffer); } bl.append("ABC", 3); { bufferlist::iterator i(&bl); ++i; EXPECT_EQ('B', *i); } } TEST(BufferListIterator, get_current_ptr) { bufferlist bl; { bufferlist::iterator i(&bl); EXPECT_THROW(++i, buffer::end_of_buffer); } bl.append("ABC", 3); { bufferlist::iterator i(&bl, 1); const buffer::ptr ptr = i.get_current_ptr(); EXPECT_EQ('B', ptr[0]); EXPECT_EQ((unsigned)1, ptr.offset()); EXPECT_EQ((unsigned)2, ptr.length()); } } TEST(BufferListIterator, copy) { bufferlist bl; const char *expected = "ABC"; bl.append(expected, 3); // // void copy(unsigned len, char *dest); // { char* copy = (char*)malloc(3); ::memset(copy, 'X', 3); bufferlist::iterator i(&bl); // // demonstrates that it seeks back to offset if p == ls->end() // EXPECT_THROW(i.advance(200), buffer::end_of_buffer); i.copy(2, copy); EXPECT_EQ(0, ::memcmp(copy, expected, 2)); EXPECT_EQ('X', copy[2]); i.seek(0); i.copy(3, copy); EXPECT_EQ(0, ::memcmp(copy, expected, 3)); } // // void buffer::list::iterator::copy(unsigned len, ptr &dest) // { bufferptr ptr; bufferlist::iterator i(&bl); i.copy(2, ptr); EXPECT_EQ((unsigned)2, ptr.length()); EXPECT_EQ('A', ptr[0]); EXPECT_EQ('B', ptr[1]); } // // void buffer::list::iterator::copy(unsigned len, list &dest) // { bufferlist copy; bufferlist::iterator i(&bl); // // demonstrates that it seeks back to offset if p == ls->end() // EXPECT_THROW(i.advance(200), buffer::end_of_buffer); i.copy(2, copy); EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2)); i.seek(0); i.copy(3, copy); EXPECT_EQ('A', copy[0]); EXPECT_EQ('B', copy[1]); EXPECT_EQ('A', copy[2]); EXPECT_EQ('B', copy[3]); EXPECT_EQ('C', copy[4]); EXPECT_EQ((unsigned)(2 + 3), copy.length()); } // // void buffer::list::iterator::copy_all(list &dest) // { bufferlist copy; bufferlist::iterator i(&bl); // // demonstrates that it seeks back to offset if p == ls->end() // EXPECT_THROW(i.advance(200), buffer::end_of_buffer); i.copy_all(copy); EXPECT_EQ('A', copy[0]); EXPECT_EQ('B', copy[1]); EXPECT_EQ('C', copy[2]); EXPECT_EQ((unsigned)3, copy.length()); } // // void copy(unsigned len, std::string &dest) // { std::string copy; bufferlist::iterator i(&bl); // // demonstrates that it seeks back to offset if p == ls->end() // EXPECT_THROW(i.advance(200), buffer::end_of_buffer); i.copy(2, copy); EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2)); i.seek(0); i.copy(3, copy); EXPECT_EQ('A', copy[0]); EXPECT_EQ('B', copy[1]); EXPECT_EQ('A', copy[2]); EXPECT_EQ('B', copy[3]); EXPECT_EQ('C', copy[4]); EXPECT_EQ((unsigned)(2 + 3), copy.length()); } } TEST(BufferListIterator, copy_in) { bufferlist bl; const char *existing = "XXX"; bl.append(existing, 3); // // void buffer::list::iterator::copy_in(unsigned len, const char *src) // { bufferlist::iterator i(&bl); // // demonstrates that it seeks back to offset if p == ls->end() // EXPECT_THROW(i.advance(200), buffer::end_of_buffer); const char *expected = "ABC"; i.copy_in(3, expected); EXPECT_EQ(0, ::memcmp(bl.c_str(), expected, 3)); EXPECT_EQ('A', bl[0]); EXPECT_EQ('B', bl[1]); EXPECT_EQ('C', bl[2]); EXPECT_EQ((unsigned)3, bl.length()); } // // void buffer::list::iterator::copy_in(unsigned len, const list& otherl) // { bufferlist::iterator i(&bl); // // demonstrates that it seeks back to offset if p == ls->end() // EXPECT_THROW(i.advance(200), buffer::end_of_buffer); bufferlist expected; expected.append("ABC", 3); i.copy_in(3, expected); EXPECT_EQ(0, ::memcmp(bl.c_str(), expected.c_str(), 3)); EXPECT_EQ('A', bl[0]); EXPECT_EQ('B', bl[1]); EXPECT_EQ('C', bl[2]); EXPECT_EQ((unsigned)3, bl.length()); } } TEST(BufferList, constructors) { // // list() // { bufferlist bl; ASSERT_EQ((unsigned)0, bl.length()); } // // list(unsigned prealloc) // { bufferlist bl(1); ASSERT_EQ((unsigned)0, bl.length()); bl.append('A'); ASSERT_EQ('A', bl[0]); } // // list(const list& other) // { bufferlist bl(1); bl.append('A'); ASSERT_EQ('A', bl[0]); bufferlist copy(bl); ASSERT_EQ('A', copy[0]); } } TEST(BufferList, operator_equal) { bufferlist bl; bl.append("ABC", 3); { std::string dest; bl.copy(1, 1, dest); ASSERT_EQ('B', dest[0]); } bufferlist copy; copy = bl; { std::string dest; copy.copy(1, 1, dest); ASSERT_EQ('B', dest[0]); } } TEST(BufferList, buffers) { bufferlist bl; ASSERT_EQ((unsigned)0, bl.buffers().size()); bl.append('A'); ASSERT_EQ((unsigned)1, bl.buffers().size()); } TEST(BufferList, swap) { bufferlist b1; b1.append('A'); bufferlist b2; b2.append('B'); b1.swap(b2); std::string s1; b1.copy(0, 1, s1); ASSERT_EQ('B', s1[0]); std::string s2; b2.copy(0, 1, s2); ASSERT_EQ('A', s2[0]); } TEST(BufferList, length) { bufferlist bl; ASSERT_EQ((unsigned)0, bl.length()); bl.append('A'); ASSERT_EQ((unsigned)1, bl.length()); } TEST(BufferList, contents_equal) { // // A BB // AB B // bufferlist bl1; bl1.append("A"); bl1.append("BB"); bufferlist bl2; ASSERT_FALSE(bl1.contents_equal(bl2)); // different length bl2.append("AB"); bl2.append("B"); ASSERT_TRUE(bl1.contents_equal(bl2)); // same length same content // // ABC // bufferlist bl3; bl3.append("ABC"); ASSERT_FALSE(bl1.contents_equal(bl3)); // same length different content } TEST(BufferList, is_page_aligned) { { bufferlist bl; EXPECT_TRUE(bl.is_page_aligned()); } { bufferlist bl; bufferptr ptr(buffer::create_page_aligned(2)); ptr.set_offset(1); ptr.set_length(1); bl.append(ptr); EXPECT_FALSE(bl.is_page_aligned()); bl.rebuild_page_aligned(); EXPECT_TRUE(bl.is_page_aligned()); } { bufferlist bl; bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1)); ptr.set_offset(1); ptr.set_length(CEPH_PAGE_SIZE); bl.append(ptr); EXPECT_FALSE(bl.is_page_aligned()); bl.rebuild_page_aligned(); EXPECT_TRUE(bl.is_page_aligned()); } } TEST(BufferList, is_n_page_sized) { { bufferlist bl; EXPECT_TRUE(bl.is_n_page_sized()); } { bufferlist bl; bl.append_zero(1); EXPECT_FALSE(bl.is_n_page_sized()); } { bufferlist bl; bl.append_zero(CEPH_PAGE_SIZE); EXPECT_TRUE(bl.is_n_page_sized()); } } TEST(BufferList, is_zero) { { bufferlist bl; EXPECT_TRUE(bl.is_zero()); } { bufferlist bl; bl.append('A'); EXPECT_FALSE(bl.is_zero()); } { bufferlist bl; bl.append_zero(1); EXPECT_TRUE(bl.is_zero()); } } TEST(BufferList, clear) { bufferlist bl; unsigned len = 17; bl.append_zero(len); bl.clear(); EXPECT_EQ((unsigned)0, bl.length()); EXPECT_EQ((unsigned)0, bl.buffers().size()); } TEST(BufferList, push_front) { // // void push_front(ptr& bp) // { bufferlist bl; bufferptr ptr; bl.push_front(ptr); EXPECT_EQ((unsigned)0, bl.length()); EXPECT_EQ((unsigned)0, bl.buffers().size()); } unsigned len = 17; { bufferlist bl; bl.append('A'); bufferptr ptr(len); ptr.c_str()[0] = 'B'; bl.push_front(ptr); EXPECT_EQ((unsigned)(1 + len), bl.length()); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ('B', bl.buffers().front()[0]); EXPECT_EQ(ptr.get_raw(), bl.buffers().front().get_raw()); } // // void push_front(raw *r) // { bufferlist bl; bl.append('A'); bufferptr ptr(len); ptr.c_str()[0] = 'B'; bl.push_front(ptr.get_raw()); EXPECT_EQ((unsigned)(1 + len), bl.length()); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ('B', bl.buffers().front()[0]); EXPECT_EQ(ptr.get_raw(), bl.buffers().front().get_raw()); } } TEST(BufferList, push_back) { // // void push_back(ptr& bp) // { bufferlist bl; bufferptr ptr; bl.push_back(ptr); EXPECT_EQ((unsigned)0, bl.length()); EXPECT_EQ((unsigned)0, bl.buffers().size()); } unsigned len = 17; { bufferlist bl; bl.append('A'); bufferptr ptr(len); ptr.c_str()[0] = 'B'; bl.push_back(ptr); EXPECT_EQ((unsigned)(1 + len), bl.length()); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ('B', bl.buffers().back()[0]); EXPECT_EQ(ptr.get_raw(), bl.buffers().back().get_raw()); } // // void push_back(raw *r) // { bufferlist bl; bl.append('A'); bufferptr ptr(len); ptr.c_str()[0] = 'B'; bl.push_back(ptr.get_raw()); EXPECT_EQ((unsigned)(1 + len), bl.length()); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ('B', bl.buffers().back()[0]); EXPECT_EQ(ptr.get_raw(), bl.buffers().back().get_raw()); } } TEST(BufferList, is_contiguous) { bufferlist bl; EXPECT_TRUE(bl.is_contiguous()); EXPECT_EQ((unsigned)0, bl.buffers().size()); bl.append('A'); EXPECT_TRUE(bl.is_contiguous()); EXPECT_EQ((unsigned)1, bl.buffers().size()); bufferptr ptr(1); bl.push_back(ptr); EXPECT_FALSE(bl.is_contiguous()); EXPECT_EQ((unsigned)2, bl.buffers().size()); } TEST(BufferList, rebuild) { { bufferlist bl; bufferptr ptr(buffer::create_page_aligned(2)); ptr.set_offset(1); ptr.set_length(1); bl.append(ptr); EXPECT_FALSE(bl.is_page_aligned()); bl.rebuild(); EXPECT_FALSE(bl.is_page_aligned()); } { bufferlist bl; const std::string str(CEPH_PAGE_SIZE, 'X'); bl.append(str.c_str(), str.size()); bl.append(str.c_str(), str.size()); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_TRUE(bl.is_page_aligned()); bl.rebuild(); EXPECT_TRUE(bl.is_page_aligned()); EXPECT_EQ((unsigned)1, bl.buffers().size()); } } TEST(BufferList, rebuild_page_aligned) { { bufferlist bl; { bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1)); ptr.set_offset(1); ptr.set_length(CEPH_PAGE_SIZE); bl.append(ptr); } EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_FALSE(bl.is_page_aligned()); bl.rebuild_page_aligned(); EXPECT_TRUE(bl.is_page_aligned()); EXPECT_EQ((unsigned)1, bl.buffers().size()); } { bufferlist bl; { bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE)); EXPECT_TRUE(ptr.is_page_aligned()); EXPECT_TRUE(ptr.is_n_page_sized()); bl.append(ptr); } { bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1)); EXPECT_TRUE(ptr.is_page_aligned()); EXPECT_FALSE(ptr.is_n_page_sized()); bl.append(ptr); } { bufferptr ptr(buffer::create_page_aligned(2)); ptr.set_offset(1); ptr.set_length(1); EXPECT_FALSE(ptr.is_page_aligned()); EXPECT_FALSE(ptr.is_n_page_sized()); bl.append(ptr); } { bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE - 2)); EXPECT_TRUE(ptr.is_page_aligned()); EXPECT_FALSE(ptr.is_n_page_sized()); bl.append(ptr); } { bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE)); EXPECT_TRUE(ptr.is_page_aligned()); EXPECT_TRUE(ptr.is_n_page_sized()); bl.append(ptr); } { bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1)); ptr.set_offset(1); ptr.set_length(CEPH_PAGE_SIZE); EXPECT_FALSE(ptr.is_page_aligned()); EXPECT_TRUE(ptr.is_n_page_sized()); bl.append(ptr); } EXPECT_EQ((unsigned)6, bl.buffers().size()); EXPECT_TRUE((bl.length() & ~CEPH_PAGE_MASK) == 0); EXPECT_FALSE(bl.is_page_aligned()); bl.rebuild_page_aligned(); EXPECT_TRUE(bl.is_page_aligned()); EXPECT_EQ((unsigned)4, bl.buffers().size()); } } TEST(BufferList, claim) { bufferlist from; { bufferptr ptr(2); from.append(ptr); } bufferlist to; { bufferptr ptr(4); to.append(ptr); } EXPECT_EQ((unsigned)4, to.length()); EXPECT_EQ((unsigned)1, to.buffers().size()); to.claim(from); EXPECT_EQ((unsigned)2, to.length()); EXPECT_EQ((unsigned)1, to.buffers().size()); EXPECT_EQ((unsigned)0, from.buffers().size()); EXPECT_EQ((unsigned)0, from.length()); } TEST(BufferList, claim_append) { bufferlist from; { bufferptr ptr(2); from.append(ptr); } bufferlist to; { bufferptr ptr(4); to.append(ptr); } EXPECT_EQ((unsigned)4, to.length()); EXPECT_EQ((unsigned)1, to.buffers().size()); to.claim_append(from); EXPECT_EQ((unsigned)(4 + 2), to.length()); EXPECT_EQ((unsigned)4, to.buffers().front().length()); EXPECT_EQ((unsigned)2, to.buffers().back().length()); EXPECT_EQ((unsigned)2, to.buffers().size()); EXPECT_EQ((unsigned)0, from.buffers().size()); EXPECT_EQ((unsigned)0, from.length()); } TEST(BufferList, claim_prepend) { bufferlist from; { bufferptr ptr(2); from.append(ptr); } bufferlist to; { bufferptr ptr(4); to.append(ptr); } EXPECT_EQ((unsigned)4, to.length()); EXPECT_EQ((unsigned)1, to.buffers().size()); to.claim_prepend(from); EXPECT_EQ((unsigned)(2 + 4), to.length()); EXPECT_EQ((unsigned)2, to.buffers().front().length()); EXPECT_EQ((unsigned)4, to.buffers().back().length()); EXPECT_EQ((unsigned)2, to.buffers().size()); EXPECT_EQ((unsigned)0, from.buffers().size()); EXPECT_EQ((unsigned)0, from.length()); } TEST(BufferList, begin) { bufferlist bl; bl.append("ABC"); bufferlist::iterator i = bl.begin(); EXPECT_EQ('A', *i); } TEST(BufferList, end) { bufferlist bl; bl.append("ABC"); bufferlist::iterator i = bl.end(); i.advance(-1); EXPECT_EQ('C', *i); } TEST(BufferList, copy) { // // void copy(unsigned off, unsigned len, char *dest) const; // { bufferlist bl; EXPECT_THROW(bl.copy((unsigned)100, (unsigned)100, (char*)0), buffer::end_of_buffer); const char *expected = "ABC"; bl.append(expected); char *dest = new char[2]; bl.copy(1, 2, dest); EXPECT_EQ(0, ::memcmp(expected + 1, dest, 2)); delete [] dest; } // // void copy(unsigned off, unsigned len, list &dest) const; // { bufferlist bl; bufferlist dest; EXPECT_THROW(bl.copy((unsigned)100, (unsigned)100, dest), buffer::end_of_buffer); const char *expected = "ABC"; bl.append(expected); bl.copy(1, 2, dest); EXPECT_EQ(0, ::memcmp(expected + 1, dest.c_str(), 2)); } // // void copy(unsigned off, unsigned len, std::string &dest) const; // { bufferlist bl; std::string dest; EXPECT_THROW(bl.copy((unsigned)100, (unsigned)100, dest), buffer::end_of_buffer); const char *expected = "ABC"; bl.append(expected); bl.copy(1, 2, dest); EXPECT_EQ(0, ::memcmp(expected + 1, dest.c_str(), 2)); } } TEST(BufferList, copy_in) { // // void copy_in(unsigned off, unsigned len, const char *src); // { bufferlist bl; bl.append("XXX"); EXPECT_THROW(bl.copy_in((unsigned)100, (unsigned)100, (char*)0), buffer::end_of_buffer); bl.copy_in(1, 2, "AB"); EXPECT_EQ(0, ::memcmp("XAB", bl.c_str(), 3)); } // // void copy_in(unsigned off, unsigned len, const list& src); // { bufferlist bl; bl.append("XXX"); bufferlist src; src.append("ABC"); EXPECT_THROW(bl.copy_in((unsigned)100, (unsigned)100, src), buffer::end_of_buffer); bl.copy_in(1, 2, src); EXPECT_EQ(0, ::memcmp("XAB", bl.c_str(), 3)); } } TEST(BufferList, append) { // // void append(char c); // { bufferlist bl; EXPECT_EQ((unsigned)0, bl.buffers().size()); bl.append('A'); EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_TRUE(bl.is_page_aligned()); } // // void append(const char *data, unsigned len); // { bufferlist bl(CEPH_PAGE_SIZE); std::string str(CEPH_PAGE_SIZE * 2, 'X'); bl.append(str.c_str(), str.size()); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().front().length()); EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().back().length()); } // // void append(const std::string& s); // { bufferlist bl(CEPH_PAGE_SIZE); std::string str(CEPH_PAGE_SIZE * 2, 'X'); bl.append(str); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().front().length()); EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().back().length()); } // // void append(const ptr& bp); // { bufferlist bl; EXPECT_EQ((unsigned)0, bl.buffers().size()); EXPECT_EQ((unsigned)0, bl.length()); { bufferptr ptr; bl.append(ptr); EXPECT_EQ((unsigned)0, bl.buffers().size()); EXPECT_EQ((unsigned)0, bl.length()); } { bufferptr ptr(3); bl.append(ptr); EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_EQ((unsigned)3, bl.length()); } } // // void append(const ptr& bp, unsigned off, unsigned len); // { bufferlist bl; bl.append('A'); bufferptr back(bl.buffers().back()); bufferptr in(back); EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_EQ((unsigned)1, bl.length()); EXPECT_THROW(bl.append(in, (unsigned)100, (unsigned)100), FailedAssertion); EXPECT_LT((unsigned)0, in.unused_tail_length()); in.append('B'); bl.append(in, back.end(), 1); EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_EQ((unsigned)2, bl.length()); EXPECT_EQ('B', bl[1]); } { bufferlist bl; EXPECT_EQ((unsigned)0, bl.buffers().size()); EXPECT_EQ((unsigned)0, bl.length()); bufferptr ptr(2); ptr.set_length(0); ptr.append("AB", 2); bl.append(ptr, 1, 1); EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_EQ((unsigned)1, bl.length()); } // // void append(const list& bl); // { bufferlist bl; bl.append('A'); bufferlist other; other.append('B'); bl.append(other); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ('B', bl[1]); } // // void append(std::istream& in); // { bufferlist bl; std::string expected("ABC\nDEF\n"); std::istringstream is("ABC\n\nDEF"); bl.append(is); EXPECT_EQ(0, ::memcmp(expected.c_str(), bl.c_str(), expected.size())); EXPECT_EQ(expected.size(), bl.length()); } } TEST(BufferList, append_zero) { bufferlist bl; bl.append('A'); EXPECT_EQ((unsigned)1, bl.buffers().size()); EXPECT_EQ((unsigned)1, bl.length()); bl.append_zero(1); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ((unsigned)2, bl.length()); EXPECT_EQ('\0', bl[1]); } TEST(BufferList, operator_brackets) { bufferlist bl; EXPECT_THROW(bl[1], buffer::end_of_buffer); bl.append('A'); bufferlist other; other.append('B'); bl.append(other); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ('B', bl[1]); } TEST(BufferList, c_str) { bufferlist bl; EXPECT_EQ((const char*)NULL, bl.c_str()); bl.append('A'); bufferlist other; other.append('B'); bl.append(other); EXPECT_EQ((unsigned)2, bl.buffers().size()); EXPECT_EQ(0, ::memcmp("AB", bl.c_str(), 2)); } TEST(BufferList, substr_of) { bufferlist bl; EXPECT_THROW(bl.substr_of(bl, 1, 1), buffer::end_of_buffer); const char *s[] = { "ABC", "DEF", "GHI", "JKL" }; for (unsigned i = 0; i < 4; i++) { bufferptr ptr(s[i], strlen(s[i])); bl.push_back(ptr); } EXPECT_EQ((unsigned)4, bl.buffers().size()); bufferlist other; other.append("TO BE CLEARED"); other.substr_of(bl, 4, 4); EXPECT_EQ((unsigned)2, other.buffers().size()); EXPECT_EQ((unsigned)4, other.length()); EXPECT_EQ(0, ::memcmp("EFGH", other.c_str(), 4)); } TEST(BufferList, splice) { bufferlist bl; EXPECT_THROW(bl.splice(1, 1), buffer::end_of_buffer); const char *s[] = { "ABC", "DEF", "GHI", "JKL" }; for (unsigned i = 0; i < 4; i++) { bufferptr ptr(s[i], strlen(s[i])); bl.push_back(ptr); } EXPECT_EQ((unsigned)4, bl.buffers().size()); bl.splice(0, 0); bufferlist other; other.append('X'); bl.splice(4, 4, &other); EXPECT_EQ((unsigned)3, other.buffers().size()); EXPECT_EQ((unsigned)5, other.length()); EXPECT_EQ(0, ::memcmp("XEFGH", other.c_str(), other.length())); EXPECT_EQ((unsigned)8, bl.length()); { bufferlist tmp(bl); EXPECT_EQ(0, ::memcmp("ABCDIJKL", tmp.c_str(), tmp.length())); } bl.splice(4, 4); EXPECT_EQ((unsigned)4, bl.length()); EXPECT_EQ(0, ::memcmp("ABCD", bl.c_str(), bl.length())); } TEST(BufferList, write) { std::ostringstream stream; bufferlist bl; bl.append("ABC"); bl.write(1, 2, stream); EXPECT_EQ("BC", stream.str()); } TEST(BufferList, encode_base64) { bufferlist bl; bl.append("ABCD"); bufferlist other; bl.encode_base64(other); const char *expected = "QUJDRA=="; EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected))); } TEST(BufferList, decode_base64) { bufferlist bl; bl.append("QUJDRA=="); bufferlist other; other.decode_base64(bl); const char *expected = "ABCD"; EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected))); bufferlist malformed; malformed.append("QUJDRA"); EXPECT_THROW(other.decode_base64(malformed), buffer::malformed_input); } TEST(BufferList, hexdump) { bufferlist bl; std::ostringstream stream; bl.append("013245678901234\0006789012345678901234", 32); bl.hexdump(stream); EXPECT_EQ("0000 : 30 31 33 32 34 35 36 37 38 39 30 31 32 33 34 00 : 013245678901234.\n" "0010 : 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 : 6789012345678901\n", stream.str()); } TEST(BufferList, read_file) { std::string error; bufferlist bl; ::unlink("testfile"); EXPECT_EQ(-ENOENT, bl.read_file("UNLIKELY", &error)); ::system("echo ABC > testfile ; chmod 0 testfile"); EXPECT_EQ(-EACCES, bl.read_file("testfile", &error)); ::system("chmod +r testfile"); EXPECT_EQ(0, bl.read_file("testfile", &error)); ::unlink("testfile"); EXPECT_EQ((unsigned)4, bl.length()); std::string actual(bl.c_str(), bl.length()); EXPECT_EQ("ABC\n", actual); } TEST(BufferList, read_fd) { unsigned len = 4; ::unlink("testfile"); ::system("echo ABC > testfile"); int fd = -1; bufferlist bl; EXPECT_EQ(-EBADF, bl.read_fd(fd, len)); fd = ::open("testfile", O_RDONLY); EXPECT_EQ(len, (unsigned)bl.read_fd(fd, len)); EXPECT_EQ(CEPH_PAGE_SIZE - len, bl.buffers().front().unused_tail_length()); EXPECT_EQ(len, bl.length()); ::close(fd); ::unlink("testfile"); } TEST(BufferList, write_file) { ::unlink("testfile"); int mode = 0600; bufferlist bl; EXPECT_EQ(-ENOENT, bl.write_file("un/like/ly", mode)); bl.append("ABC"); EXPECT_EQ(0, bl.write_file("testfile", mode)); struct stat st; memset(&st, 0, sizeof(st)); ::stat("testfile", &st); EXPECT_EQ((unsigned)(mode | S_IFREG), st.st_mode); ::unlink("testfile"); } TEST(BufferList, write_fd) { ::unlink("testfile"); int fd = ::open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0600); bufferlist bl; for (unsigned i = 0; i < IOV_MAX * 2; i++) { bufferptr ptr("A", 1); bl.push_back(ptr); } EXPECT_EQ(0, bl.write_fd(fd)); ::close(fd); struct stat st; memset(&st, 0, sizeof(st)); ::stat("testfile", &st); EXPECT_EQ(IOV_MAX * 2, st.st_size); ::unlink("testfile"); } TEST(BufferList, crc32c) { bufferlist bl; __u32 crc = 0; bl.append("A"); crc = bl.crc32c(crc); EXPECT_EQ((unsigned)0xB3109EBF, crc); crc = bl.crc32c(crc); EXPECT_EQ((unsigned)0x5FA5C0CC, crc); } TEST(BufferList, crc32c_append) { bufferlist bl1; bufferlist bl2; for (int j = 0; j < 200; ++j) { bufferlist bl; for (int i = 0; i < 200; ++i) { char x = rand(); bl.append(x); bl1.append(x); } bl.crc32c(rand()); // mess with the cached bufferptr crc values bl2.append(bl); } ASSERT_EQ(bl1.crc32c(0), bl2.crc32c(0)); } TEST(BufferList, crc32c_append_perf) { int len = 256 * 1024 * 1024; bufferptr a(len); bufferptr b(len); bufferptr c(len); bufferptr d(len); std::cout << "populating large buffers (a, b=c=d)" << std::endl; char *pa = a.c_str(); char *pb = b.c_str(); char *pc = c.c_str(); char *pd = c.c_str(); for (int i=0; i(bufferlist& l, bufferlist& r) // ASSERT_FALSE(a > ab); ASSERT_TRUE(ab > a); ASSERT_TRUE(ac > ab); ASSERT_FALSE(ab > ac); ASSERT_FALSE(ab > ab); // // bool operator>=(bufferlist& l, bufferlist& r) // ASSERT_FALSE(a >= ab); ASSERT_TRUE(ab >= a); ASSERT_TRUE(ac >= ab); ASSERT_FALSE(ab >= ac); ASSERT_TRUE(ab >= ab); // // bool operator<(bufferlist& l, bufferlist& r) // ASSERT_TRUE(a < ab); ASSERT_FALSE(ab < a); ASSERT_FALSE(ac < ab); ASSERT_TRUE(ab < ac); ASSERT_FALSE(ab < ab); // // bool operator<=(bufferlist& l, bufferlist& r) // ASSERT_TRUE(a <= ab); ASSERT_FALSE(ab <= a); ASSERT_FALSE(ac <= ab); ASSERT_TRUE(ab <= ac); ASSERT_TRUE(ab <= ab); // // bool operator==(bufferlist &l, bufferlist &r) // ASSERT_FALSE(a == ab); ASSERT_FALSE(ac == ab); ASSERT_TRUE(ab == ab); } TEST(BufferList, ostream) { std::ostringstream stream; bufferlist bl; const char *s[] = { "ABC", "DEF" }; for (unsigned i = 0; i < 2; i++) { bufferptr ptr(s[i], strlen(s[i])); bl.push_back(ptr); } stream << bl; std::cerr << stream.str() << std::endl; EXPECT_GT(stream.str().size(), stream.str().find("list(len=6,")); EXPECT_GT(stream.str().size(), stream.str().find("len 3 nref 1),\n")); EXPECT_GT(stream.str().size(), stream.str().find("len 3 nref 1)\n")); } TEST(BufferList, zero) { // // void zero() // { bufferlist bl; bl.append('A'); EXPECT_EQ('A', bl[0]); bl.zero(); EXPECT_EQ('\0', bl[0]); } // // void zero(unsigned o, unsigned l) // const char *s[] = { "ABC", "DEF", "GHI", "KLM" }; { bufferlist bl; bufferptr ptr(s[0], strlen(s[0])); bl.push_back(ptr); bl.zero((unsigned)0, (unsigned)1); EXPECT_EQ(0, ::memcmp("\0BC", bl.c_str(), 3)); } { bufferlist bl; for (unsigned i = 0; i < 4; i++) { bufferptr ptr(s[i], strlen(s[i])); bl.push_back(ptr); } EXPECT_THROW(bl.zero((unsigned)0, (unsigned)2000), FailedAssertion); bl.zero((unsigned)2, (unsigned)5); EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl.c_str(), 9)); } { bufferlist bl; for (unsigned i = 0; i < 4; i++) { bufferptr ptr(s[i], strlen(s[i])); bl.push_back(ptr); } bl.zero((unsigned)3, (unsigned)3); EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl.c_str(), 9)); } { bufferlist bl; bufferptr ptr1(4); bufferptr ptr2(4); memset(ptr1.c_str(), 'a', 4); memset(ptr2.c_str(), 'b', 4); bl.append(ptr1); bl.append(ptr2); bl.zero((unsigned)2, (unsigned)4); EXPECT_EQ(0, ::memcmp("aa\0\0\0\0bb", bl.c_str(), 8)); } } TEST(BufferList, EmptyAppend) { bufferlist bl; bufferptr ptr; bl.push_back(ptr); ASSERT_EQ(bl.begin().end(), 1); } TEST(BufferList, TestPtrAppend) { bufferlist bl; char correct[MAX_TEST]; int curpos = 0; int length = random() % 5 > 0 ? random() % 1000 : 0; while (curpos + length < MAX_TEST) { if (!length) { bufferptr ptr; bl.push_back(ptr); } else { char *current = correct + curpos; for (int i = 0; i < length; ++i) { char next = random() % 255; correct[curpos++] = next; } bufferptr ptr(current, length); bl.append(ptr); } length = random() % 5 > 0 ? random() % 1000 : 0; } ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0); } TEST(BufferList, TestDirectAppend) { bufferlist bl; char correct[MAX_TEST]; int curpos = 0; int length = random() % 5 > 0 ? random() % 1000 : 0; while (curpos + length < MAX_TEST) { char *current = correct + curpos; for (int i = 0; i < length; ++i) { char next = random() % 255; correct[curpos++] = next; } bl.append(current, length); length = random() % 5 > 0 ? random() % 1000 : 0; } ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0); } TEST(BufferList, TestCopyAll) { const static size_t BIG_SZ = 10737414; ceph::shared_ptr big( (unsigned char*)malloc(BIG_SZ), free); unsigned char c = 0; for (size_t i = 0; i < BIG_SZ; ++i) { big.get()[i] = c++; } bufferlist bl; bl.append((const char*)big.get(), BIG_SZ); bufferlist::iterator i = bl.begin(); bufferlist bl2; i.copy_all(bl2); ASSERT_EQ(bl2.length(), BIG_SZ); ceph::shared_ptr big2( (unsigned char*)malloc(BIG_SZ), free); bl2.copy(0, BIG_SZ, (char*)big2.get()); ASSERT_EQ(memcmp(big.get(), big2.get(), BIG_SZ), 0); } TEST(BufferHash, all) { { bufferlist bl; bl.append("A"); bufferhash hash; EXPECT_EQ((unsigned)0, hash.digest()); hash.update(bl); EXPECT_EQ((unsigned)0xB3109EBF, hash.digest()); hash.update(bl); EXPECT_EQ((unsigned)0x5FA5C0CC, hash.digest()); } { bufferlist bl; bl.append("A"); bufferhash hash; EXPECT_EQ((unsigned)0, hash.digest()); bufferhash& returned_hash = hash << bl; EXPECT_EQ(&returned_hash, &hash); EXPECT_EQ((unsigned)0xB3109EBF, hash.digest()); } } /* * Local Variables: * compile-command: "cd .. ; make unittest_bufferlist && * ulimit -s unlimited ; CEPH_BUFFER_TRACK=true valgrind \ * --max-stackframe=20000000 --tool=memcheck \ * ./unittest_bufferlist # --gtest_filter=BufferList.constructors" * End: */ ceph-0.80.11/src/test/unit.h0000664000175100017510000000244712623076744017602 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_UNIT_TEST_H #define CEPH_UNIT_TEST_H #include "include/types.h" // FIXME: ordering shouldn't be important, but right // now, this include has to come before the others. #include "common/code_environment.h" #include "global/global_context.h" #include "global/global_init.h" #include "include/msgr.h" // for CEPH_ENTITY_TYPE_CLIENT #include "gtest/gtest.h" #include /* * You only need to include this file if you are testing Ceph internal code. If * you are testing library code, the library init() interfaces will handle * initialization for you. */ int main(int argc, char **argv) { std::vector args; global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } #endif ceph-0.80.11/src/test/cls_log/0000775000175100017510000000000012623077035020057 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/test/cls_log/test_cls_log.cc0000664000175100017510000001637712623076744023073 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "cls/log/cls_log_types.h" #include "cls/log/cls_log_client.h" #include "include/utime.h" #include "common/Clock.h" #include "global/global_context.h" #include "gtest/gtest.h" #include "test/librados/test.h" #include #include #include static librados::ObjectWriteOperation *new_op() { return new librados::ObjectWriteOperation(); } static librados::ObjectReadOperation *new_rop() { return new librados::ObjectReadOperation(); } static void reset_rop(librados::ObjectReadOperation **pop) { delete *pop; *pop = new_rop(); } static int read_bl(bufferlist& bl, int *i) { bufferlist::iterator iter = bl.begin(); try { ::decode(*i, iter); } catch (buffer::error& err) { std::cout << "failed to decode buffer" << std::endl; return -EIO; } return 0; } void add_log(librados::ObjectWriteOperation *op, utime_t& timestamp, string& section, string&name, int i) { bufferlist bl; ::encode(i, bl); cls_log_add(*op, timestamp, section, name, bl); } string get_name(int i) { string name_prefix = "data-source"; char buf[16]; snprintf(buf, sizeof(buf), "%d", i); return name_prefix + buf; } void generate_log(librados::IoCtx& ioctx, string& oid, int max, utime_t& start_time, bool modify_time) { string section = "global"; librados::ObjectWriteOperation *op = new_op(); int i; for (i = 0; i < max; i++) { uint32_t secs = start_time.sec(); if (modify_time) secs += i; utime_t ts(secs, start_time.nsec()); string name = get_name(i); add_log(op, ts, section, name, i); } ASSERT_EQ(0, ioctx.operate(oid, op)); delete op; } utime_t get_time(utime_t& start_time, int i, bool modify_time) { uint32_t secs = start_time.sec(); if (modify_time) secs += i; return utime_t(secs, start_time.nsec()); } void check_entry(cls_log_entry& entry, utime_t& start_time, int i, bool modified_time) { string section = "global"; string name = get_name(i); utime_t ts = get_time(start_time, i, modified_time); ASSERT_EQ(section, entry.section); ASSERT_EQ(name, entry.name); ASSERT_EQ(ts, entry.timestamp); } TEST(cls_rgw, test_log_add_same_time) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* generate log */ utime_t start_time = ceph_clock_now(g_ceph_context); generate_log(ioctx, oid, 10, start_time, false); librados::ObjectReadOperation *rop = new_rop(); list entries; bool truncated; /* check list */ utime_t to_time = get_time(start_time, 1, true); string marker; cls_log_list(*rop, start_time, to_time, marker, 0, entries, &marker, &truncated); bufferlist obl; ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(10, (int)entries.size()); ASSERT_EQ(0, (int)truncated); list::iterator iter; /* need to sort returned entries, all were using the same time as key */ map check_ents; for (iter = entries.begin(); iter != entries.end(); ++iter) { cls_log_entry& entry = *iter; int num; ASSERT_EQ(0, read_bl(entry.data, &num)); check_ents[num] = entry; } ASSERT_EQ(10, (int)check_ents.size()); map::iterator ei; /* verify entries are as expected */ int i; for (i = 0, ei = check_ents.begin(); i < 10; i++, ++ei) { cls_log_entry& entry = ei->second; ASSERT_EQ(i, ei->first); check_entry(entry, start_time, i, false); } reset_rop(&rop); /* check list again, now want to be truncated*/ marker.clear(); cls_log_list(*rop, start_time, to_time, marker, 1, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(1, (int)entries.size()); ASSERT_EQ(1, (int)truncated); delete rop; } TEST(cls_rgw, test_log_add_different_time) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* generate log */ utime_t start_time = ceph_clock_now(g_ceph_context); generate_log(ioctx, oid, 10, start_time, true); librados::ObjectReadOperation *rop = new_rop(); list entries; bool truncated; utime_t to_time = utime_t(start_time.sec() + 10, start_time.nsec()); string marker; /* check list */ cls_log_list(*rop, start_time, to_time, marker, 0, entries, &marker, &truncated); bufferlist obl; ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(10, (int)entries.size()); ASSERT_EQ(0, (int)truncated); list::iterator iter; /* returned entries should be sorted by time */ map check_ents; int i; for (i = 0, iter = entries.begin(); iter != entries.end(); ++iter, ++i) { cls_log_entry& entry = *iter; int num; ASSERT_EQ(0, read_bl(entry.data, &num)); ASSERT_EQ(i, num); check_entry(entry, start_time, i, true); } reset_rop(&rop); /* check list again with shifted time */ utime_t next_time = get_time(start_time, 1, true); marker.clear(); cls_log_list(*rop, next_time, to_time, marker, 0, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(9, (int)entries.size()); ASSERT_EQ(0, (int)truncated); reset_rop(&rop); marker.clear(); i = 0; do { bufferlist obl; string old_marker = marker; cls_log_list(*rop, start_time, to_time, old_marker, 1, entries, &marker, &truncated); ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_NE(old_marker, marker); ASSERT_EQ(1, (int)entries.size()); ++i; ASSERT_GE(10, i); } while (truncated); ASSERT_EQ(10, i); delete rop; } TEST(cls_rgw, test_log_trim) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* generate log */ utime_t start_time = ceph_clock_now(g_ceph_context); generate_log(ioctx, oid, 10, start_time, true); librados::ObjectReadOperation *rop = new_rop(); list entries; bool truncated; /* check list */ /* trim */ utime_t to_time = get_time(start_time, 10, true); for (int i = 0; i < 10; i++) { utime_t trim_time = get_time(start_time, i, true); utime_t zero_time; string start_marker, end_marker; ASSERT_EQ(0, cls_log_trim(ioctx, oid, zero_time, trim_time, start_marker, end_marker)); string marker; cls_log_list(*rop, start_time, to_time, marker, 0, entries, &marker, &truncated); bufferlist obl; ASSERT_EQ(0, ioctx.operate(oid, rop, &obl)); ASSERT_EQ(9 - i, (int)entries.size()); ASSERT_EQ(0, (int)truncated); } delete rop; } ceph-0.80.11/src/test/testkeys.cc0000664000175100017510000000301212623076744020621 0ustar jenkins-buildjenkins-build#include "auth/cephx/CephxKeyServer.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/config.h" #define AES_KEY_LEN 16 int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); KeyRing extra; KeyServer server(g_ceph_context, &extra); generic_dout(0) << "server created" << dendl; getchar(); #if 0 char aes_key[AES_KEY_LEN]; memset(aes_key, 0x77, sizeof(aes_key)); bufferptr keybuf(aes_key, sizeof(aes_key)); CryptoKey key(CEPH_CRYPTO_AES, ceph_clock_now(g_ceph_context), keybuf); const char *msg="hello! this is a message\n"; char pad[16]; memset(pad, 0, 16); bufferptr ptr(msg, strlen(msg)); bufferlist enc_in; enc_in.append(ptr); enc_in.append(msg, strlen(msg)); bufferlist enc_out; if (key.encrypt(enc_in, enc_out) < 0) { derr(0) << "couldn't encode!" << dendl; exit(1); } const char *enc_buf = enc_out.c_str(); for (unsigned i=0; i * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include using namespace std; #include "common/config.h" #include "mon/MonMap.h" #include "mon/MonClient.h" #include "msg/Messenger.h" #include "messages/MPing.h" #include "common/Timer.h" #include "global/global_init.h" #include "common/ceph_argparse.h" #ifndef DARWIN #include #endif // DARWIN #include #include #define dout_subsys ceph_subsys_ms Messenger *messenger = 0; Mutex test_lock("mylock"); Cond cond; uint64_t received = 0; class Admin : public Dispatcher { public: Admin() : Dispatcher(g_ceph_context) { } private: bool ms_dispatch(Message *m) { //cerr << "got ping from " << m->get_source() << std::endl; dout(0) << "got ping from " << m->get_source() << dendl; test_lock.Lock(); ++received; cond.Signal(); test_lock.Unlock(); m->put(); return true; } bool ms_handle_reset(Connection *con) { return false; } void ms_handle_remote_reset(Connection *con) {} } dispatcher; int main(int argc, const char **argv, const char *envp[]) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); dout(0) << "i am mon " << args[0] << dendl; // get monmap MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) return -1; // start up network int whoami = mc.monmap.get_rank(args[0]); assert(whoami >= 0); ostringstream ss; ss << mc.monmap.get_addr(whoami); std::string sss(ss.str()); g_ceph_context->_conf->set_val("public_addr", sss.c_str()); g_ceph_context->_conf->apply_changes(NULL); Messenger *rank = Messenger::create(g_ceph_context, entity_name_t::MON(whoami), "tester", getpid()); int err = rank->bind(g_ceph_context->_conf->public_addr); if (err < 0) return 1; // start monitor messenger = rank; messenger->set_default_send_priority(CEPH_MSG_PRIO_HIGH); messenger->add_dispatcher_head(&dispatcher); rank->start(); int isend = 0; if (whoami == 0) isend = 100; test_lock.Lock(); uint64_t sent = 0; while (1) { while (received + isend <= sent) { //cerr << "wait r " << received << " s " << sent << " is " << isend << std::endl; dout(0) << "wait r " << received << " s " << sent << " is " << isend << dendl; cond.Wait(test_lock); } int t = rand() % mc.get_num_mon(); if (t == whoami) continue; if (rand() % 10 == 0) { //cerr << "mark_down " << t << std::endl; dout(0) << "mark_down " << t << dendl; messenger->mark_down(mc.get_mon_addr(t)); } //cerr << "pinging " << t << std::endl; dout(0) << "pinging " << t << dendl; messenger->send_message(new MPing, mc.get_mon_inst(t)); cerr << isend << "\t" << ++sent << "\t" << received << "\r"; } test_lock.Unlock(); // wait for messenger to finish rank->wait(); return 0; } ceph-0.80.11/src/test/daemon_config.cc0000664000175100017510000002533312623076744021550 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_argparse.h" #include "common/config.h" #include "include/cephfs/libcephfs.h" #include "include/rados/librados.h" #include "test/unit.h" #include #include #include #include using std::string; TEST(DaemonConfig, SimpleSet) { int ret; ret = g_ceph_context->_conf->set_val("num_client", "21"); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); char buf[128]; memset(buf, 0, sizeof(buf)); char *tmp = buf; ret = g_ceph_context->_conf->get_val("num_client", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("21"), string(buf)); } TEST(DaemonConfig, Substitution) { int ret; ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false"); ret = g_ceph_context->_conf->set_val("host", "foo"); ASSERT_EQ(ret, 0); ret = g_ceph_context->_conf->set_val("public_network", "bar$host.baz", false); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); char buf[128]; memset(buf, 0, sizeof(buf)); char *tmp = buf; ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("barfoo.baz"), string(buf)); } TEST(DaemonConfig, SubstitutionTrailing) { int ret; ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false"); ret = g_ceph_context->_conf->set_val("host", "foo"); ASSERT_EQ(ret, 0); ret = g_ceph_context->_conf->set_val("public_network", "bar$host", false); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); char buf[128]; memset(buf, 0, sizeof(buf)); char *tmp = buf; ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("barfoo"), string(buf)); } TEST(DaemonConfig, SubstitutionBraces) { int ret; ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false"); ret = g_ceph_context->_conf->set_val("host", "foo"); ASSERT_EQ(ret, 0); ret = g_ceph_context->_conf->set_val("public_network", "bar${host}baz", false); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); char buf[128]; memset(buf, 0, sizeof(buf)); char *tmp = buf; ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("barfoobaz"), string(buf)); } TEST(DaemonConfig, SubstitutionBracesTrailing) { int ret; ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false"); ret = g_ceph_context->_conf->set_val("host", "foo"); ASSERT_EQ(ret, 0); ret = g_ceph_context->_conf->set_val("public_network", "bar${host}", false); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); char buf[128]; memset(buf, 0, sizeof(buf)); char *tmp = buf; ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("barfoo"), string(buf)); } // config: variable substitution happen only once http://tracker.ceph.com/issues/7103 TEST(DaemonConfig, SubstitutionMultiple) { int ret; ret = g_ceph_context->_conf->set_val("mon_host", "localhost", false); ASSERT_EQ(ret, 0); ret = g_ceph_context->_conf->set_val("keyring", "$mon_host/$cluster.keyring,$mon_host/$cluster.mon.keyring", false); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); char buf[512]; memset(buf, 0, sizeof(buf)); char *tmp = buf; ret = g_ceph_context->_conf->get_val("keyring", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("localhost/ceph.keyring,localhost/ceph.mon.keyring"), tmp); ASSERT_TRUE(strchr(buf, '$') == NULL); } TEST(DaemonConfig, ArgV) { ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false")); int ret; const char *argv[] = { "foo", "--num-client", "22", "--keyfile", "/tmp/my-keyfile", NULL }; size_t argc = (sizeof(argv) / sizeof(argv[0])) - 1; vector args; argv_to_vec(argc, argv, args); g_ceph_context->_conf->parse_argv(args); g_ceph_context->_conf->apply_changes(NULL); char buf[128]; char *tmp = buf; memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("keyfile", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("/tmp/my-keyfile"), string(buf)); memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("num_client", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("22"), string(buf)); ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "true")); } TEST(DaemonConfig, InjectArgs) { int ret; std::string injection("--num-client 56 --max-open-files 42"); ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, 0); char buf[128]; char *tmp = buf; memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("max_open_files", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("42"), string(buf)); memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("num_client", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("56"), string(buf)); injection = "--num-client 57"; ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, 0); ret = g_ceph_context->_conf->get_val("num_client", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("57"), string(buf)); } TEST(DaemonConfig, InjectArgsReject) { int ret; char buf[128]; char *tmp = buf; char buf2[128]; char *tmp2 = buf2; // We should complain about the garbage in the input std::string injection("--random-garbage-in-injectargs 26 --num-client 28"); ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, -EINVAL); // But, debug should still be set... memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("num_client", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("28"), string(buf)); // What's the current value of osd_data? memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("osd_data", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); // Injectargs shouldn't let us change this, since it is a string-valued // variable and there isn't an observer for it. std::string injection2("--osd_data /tmp/some-other-directory --num-client 4"); ret = g_ceph_context->_conf->injectargs(injection2, &cout); ASSERT_EQ(ret, -ENOSYS); // It should be unchanged. memset(buf2, 0, sizeof(buf2)); ret = g_ceph_context->_conf->get_val("osd_data", &tmp2, sizeof(buf2)); ASSERT_EQ(ret, 0); ASSERT_EQ(string(buf), string(buf2)); } TEST(DaemonConfig, InjectArgsBooleans) { int ret; char buf[128]; char *tmp = buf; // Change log_to_syslog std::string injection("--log_to_syslog --num-client 28"); ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, 0); // log_to_syslog should be set... memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("true"), string(buf)); // Turn off log_to_syslog injection = "--log_to_syslog=false --num-client 28"; ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, 0); // log_to_syslog should be cleared... memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("false"), string(buf)); // Turn on log_to_syslog injection = "--num-client 1 --log_to_syslog=true --max-open-files 40"; ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, 0); // log_to_syslog should be set... memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("true"), string(buf)); // parse error injection = "--num-client 1 --log_to_syslog=falsey --max-open-files 42"; ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, -EINVAL); // log_to_syslog should still be set... memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("log_to_syslog", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("true"), string(buf)); // debug-ms should still become 42... memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("max_open_files", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("42"), string(buf)); } TEST(DaemonConfig, InjectArgsLogfile) { int ret; char tmpfile[PATH_MAX]; const char *tmpdir = getenv("TMPDIR"); if (!tmpdir) tmpdir = "/tmp"; snprintf(tmpfile, sizeof(tmpfile), "%s/daemon_config_test.%d", tmpdir, getpid()); std::string injection("--log_file "); injection += tmpfile; // We're allowed to change log_file because there is an observer. ret = g_ceph_context->_conf->injectargs(injection, &cout); ASSERT_EQ(ret, 0); // It should have taken effect. char buf[128]; char *tmp = buf; memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("log_file", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string(buf), string(tmpfile)); // The logfile should exist. ASSERT_EQ(access(tmpfile, R_OK), 0); // Let's turn off the logfile. ret = g_ceph_context->_conf->set_val("log_file", ""); ASSERT_EQ(ret, 0); g_ceph_context->_conf->apply_changes(NULL); ret = g_ceph_context->_conf->get_val("log_file", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string(""), string(buf)); // Clean up the garbage unlink(tmpfile); } TEST(DaemonConfig, ThreadSafety1) { int ret; // Verify that we can't change this, since internal_safe_to_start_threads has // been set. ret = g_ceph_context->_conf->set_val("osd_data", ""); ASSERT_EQ(ret, -ENOSYS); ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false")); // Ok, now we can change this. Since this is just a test, and there are no // OSD threads running, we know changing osd_data won't actually blow up the // world. ret = g_ceph_context->_conf->set_val("osd_data", "/tmp/crazydata"); ASSERT_EQ(ret, 0); char buf[128]; char *tmp = buf; memset(buf, 0, sizeof(buf)); ret = g_ceph_context->_conf->get_val("osd_data", &tmp, sizeof(buf)); ASSERT_EQ(ret, 0); ASSERT_EQ(string("/tmp/crazydata"), string(buf)); ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false")); ASSERT_EQ(ret, 0); } /* * Local Variables: * compile-command: "cd .. ; make unittest_daemon_config && ./unittest_daemon_config" * End: */ ceph-0.80.11/src/test/test_rgw_admin_opstate.cc0000664000175100017510000006443712623076744023535 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 eNovance SAS * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include #include #include #include #include extern "C"{ #include } #include "common/ceph_crypto.h" #include "include/str_list.h" #include "common/ceph_json.h" #include "common/code_environment.h" #include "common/ceph_argparse.h" #include "common/Finisher.h" #include "global/global_init.h" #include "rgw/rgw_common.h" #include "rgw/rgw_bucket.h" #include "rgw/rgw_rados.h" #include "include/utime.h" #include "include/object.h" #include "cls/statelog/cls_statelog_types.h" #define GTEST #ifdef GTEST #include #else #define TEST(x, y) void y() #define ASSERT_EQ(v, s) if(v != s)cout << "Error at " << __LINE__ << "(" << #v << "!= " << #s << "\n"; \ else cout << "(" << #v << "==" << #s << ") PASSED\n"; #define EXPECT_EQ(v, s) ASSERT_EQ(v, s) #define ASSERT_TRUE(c) if(c)cout << "Error at " << __LINE__ << "(" << #c << ")" << "\n"; \ else cout << "(" << #c << ") PASSED\n"; #define EXPECT_TRUE(c) ASSERT_TRUE(c) #endif using namespace std; #define CURL_VERBOSE 0 #define HTTP_RESPONSE_STR "RespCode" #define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20 #define RGW_ADMIN_RESP_PATH "/tmp/.test_rgw_admin_resp" static string uid = "ceph"; static string display_name = "CEPH"; extern "C" int ceph_armor(char *dst, const char *dst_end, const char *src, const char *end); static void print_usage(char *exec){ cout << "Usage: " << exec << " \n"; cout << "Options:\n" "-g - The ip address of the gateway\n" "-p - The port number of the gateway\n" "-c - Absolute path of ceph config file\n" "-rgw-admin - radosgw-admin absolute path\n"; } namespace admin_log { class test_helper { private: string host; string port; string creds; string rgw_admin_path; string conf_path; CURL *curl_inst; map response; list extra_hdrs; string *resp_data; unsigned resp_code; public: test_helper() : resp_data(NULL){ curl_global_init(CURL_GLOBAL_ALL); } ~test_helper(){ curl_global_cleanup(); } int send_request(string method, string uri, size_t (*function)(void *,size_t,size_t,void *) = 0, void *ud = 0, size_t length = 0); int extract_input(int argc, char *argv[]); string& get_response(string hdr){ return response[hdr]; } void set_extra_header(string hdr){ extra_hdrs.push_back(hdr); } void set_response(char *val); void set_response_data(char *data, size_t len){ if(resp_data) delete resp_data; resp_data = new string(data, len); } string& get_rgw_admin_path() { return rgw_admin_path; } string& get_ceph_conf_path() { return conf_path; } void set_creds(string& c) { creds = c; } const string *get_response_data(){return resp_data;} unsigned get_resp_code(){return resp_code;} }; int test_helper::extract_input(int argc, char *argv[]){ #define ERR_CHECK_NEXT_PARAM(o) \ if(((int)loop + 1) >= argc)return -1; \ else o = argv[loop+1]; for(unsigned loop = 1;loop < (unsigned)argc; loop += 2){ if(strcmp(argv[loop], "-g") == 0){ ERR_CHECK_NEXT_PARAM(host); }else if(strcmp(argv[loop],"-p") == 0){ ERR_CHECK_NEXT_PARAM(port); }else if(strcmp(argv[loop], "-c") == 0){ ERR_CHECK_NEXT_PARAM(conf_path); }else if(strcmp(argv[loop], "-rgw-admin") == 0){ ERR_CHECK_NEXT_PARAM(rgw_admin_path); }else return -1; } if(host.length() <= 0 || rgw_admin_path.length() <= 0) return -1; return 0; } void test_helper::set_response(char *r){ string sr(r), h, v; size_t off = sr.find(": "); if(off != string::npos){ h.assign(sr, 0, off); v.assign(sr, off + 2, sr.find("\r\n") - (off+2)); }else{ /*Could be the status code*/ if(sr.find("HTTP/") != string::npos){ h.assign(HTTP_RESPONSE_STR); off = sr.find(" "); v.assign(sr, off + 1, sr.find("\r\n") - (off + 1)); resp_code = atoi((v.substr(0, 3)).c_str()); } } response[h] = v; } size_t write_header(void *ptr, size_t size, size_t nmemb, void *ud){ test_helper *h = static_cast(ud); h->set_response((char *)ptr); return size*nmemb; } size_t write_data(void *ptr, size_t size, size_t nmemb, void *ud){ test_helper *h = static_cast(ud); h->set_response_data((char *)ptr, size*nmemb); return size*nmemb; } static inline void buf_to_hex(const unsigned char *buf, int len, char *str) { int i; str[0] = '\0'; for (i = 0; i < len; i++) { sprintf(&str[i*2], "%02x", (int)buf[i]); } } static void calc_hmac_sha1(const char *key, int key_len, const char *msg, int msg_len, char *dest) /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */ { ceph::crypto::HMACSHA1 hmac((const unsigned char *)key, key_len); hmac.Update((const unsigned char *)msg, msg_len); hmac.Final((unsigned char *)dest); char hex_str[(CEPH_CRYPTO_HMACSHA1_DIGESTSIZE * 2) + 1]; admin_log::buf_to_hex((unsigned char *)dest, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE, hex_str); } static int get_s3_auth(string method, string creds, string date, string res, string& out){ string aid, secret, auth_hdr; string tmp_res; size_t off = creds.find(":"); out = ""; if(off != string::npos){ aid.assign(creds, 0, off); secret.assign(creds, off + 1, string::npos); /*sprintf(auth_hdr, "%s\n\n\n%s\n%s", req_type, date, res);*/ char hmac_sha1[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; char b64[65]; /* 64 is really enough */ size_t off = res.find("?"); if(off == string::npos) tmp_res = res; else tmp_res.assign(res, 0, off); auth_hdr.append(method + string("\n\n\n") + date + string("\n") + tmp_res); admin_log::calc_hmac_sha1(secret.c_str(), secret.length(), auth_hdr.c_str(), auth_hdr.length(), hmac_sha1); int ret = ceph_armor(b64, b64 + 64, hmac_sha1, hmac_sha1 + CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); if (ret < 0) { cout << "ceph_armor failed\n"; return -1; } b64[ret] = 0; out.append(aid + string(":") + b64); }else return -1; return 0; } void get_date(string& d){ struct timeval tv; char date[64]; struct tm tm; char *days[] = {(char *)"Sun", (char *)"Mon", (char *)"Tue", (char *)"Wed", (char *)"Thu", (char *)"Fri", (char *)"Sat"}; char *months[] = {(char *)"Jan", (char *)"Feb", (char *)"Mar", (char *)"Apr", (char *)"May", (char *)"Jun", (char *)"Jul",(char *) "Aug", (char *)"Sep", (char *)"Oct", (char *)"Nov", (char *)"Dec"}; gettimeofday(&tv, NULL); gmtime_r(&tv.tv_sec, &tm); sprintf(date, "%s, %d %s %d %d:%d:%d GMT", days[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec); d = date; } int test_helper::send_request(string method, string res, size_t (*read_function)( void *,size_t,size_t,void *), void *ud, size_t length){ string url; string auth, date; url.append(string("http://") + host); if(port.length() > 0)url.append(string(":") + port); url.append(res); curl_inst = curl_easy_init(); if(curl_inst){ curl_easy_setopt(curl_inst, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl_inst, CURLOPT_CUSTOMREQUEST, method.c_str()); curl_easy_setopt(curl_inst, CURLOPT_VERBOSE, CURL_VERBOSE); curl_easy_setopt(curl_inst, CURLOPT_HEADERFUNCTION, admin_log::write_header); curl_easy_setopt(curl_inst, CURLOPT_WRITEHEADER, (void *)this); curl_easy_setopt(curl_inst, CURLOPT_WRITEFUNCTION, admin_log::write_data); curl_easy_setopt(curl_inst, CURLOPT_WRITEDATA, (void *)this); if(read_function){ curl_easy_setopt(curl_inst, CURLOPT_READFUNCTION, read_function); curl_easy_setopt(curl_inst, CURLOPT_READDATA, (void *)ud); curl_easy_setopt(curl_inst, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl_inst, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); } get_date(date); string http_date; http_date.append(string("Date: ") + date); string s3auth; if (admin_log::get_s3_auth(method, creds, date, res, s3auth) < 0) return -1; auth.append(string("Authorization: AWS ") + s3auth); struct curl_slist *slist = NULL; slist = curl_slist_append(slist, auth.c_str()); slist = curl_slist_append(slist, http_date.c_str()); for(list::iterator it = extra_hdrs.begin(); it != extra_hdrs.end(); ++it){ slist = curl_slist_append(slist, (*it).c_str()); } if(read_function) curl_slist_append(slist, "Expect:"); curl_easy_setopt(curl_inst, CURLOPT_HTTPHEADER, slist); response.erase(response.begin(), response.end()); extra_hdrs.erase(extra_hdrs.begin(), extra_hdrs.end()); CURLcode res = curl_easy_perform(curl_inst); if(res != CURLE_OK){ cout << "Curl perform failed for " << url << ", res: " << curl_easy_strerror(res) << "\n"; return -1; } curl_slist_free_all(slist); } curl_easy_cleanup(curl_inst); return 0; } }; admin_log::test_helper *g_test; Finisher *finisher; RGWRados *store; int run_rgw_admin(string& cmd, string& resp) { pid_t pid; pid = fork(); if (pid == 0) { /* child */ list l; get_str_list(cmd, " \t", l); char *argv[l.size()]; unsigned loop = 1; argv[0] = (char *)"radosgw-admin"; for (list::iterator it = l.begin(); it != l.end(); ++it) { argv[loop++] = (char *)(*it).c_str(); } argv[loop] = NULL; close(1); stdout = fopen(RGW_ADMIN_RESP_PATH, "w+"); if (!stdout) { cout << "Unable to open stdout file" << std::endl; } execv((g_test->get_rgw_admin_path()).c_str(), argv); } else if (pid > 0) { int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { if(WEXITSTATUS(status) != 0) { cout << "Child exited with status " << WEXITSTATUS(status) << std::endl; return -1; } } ifstream in; struct stat st; if (stat(RGW_ADMIN_RESP_PATH, &st) < 0) { cout << "Error stating the admin response file, errno " << errno << std::endl; return -1; } else { char *data = (char *)malloc(st.st_size + 1); in.open(RGW_ADMIN_RESP_PATH); in.read(data, st.st_size); in.close(); data[st.st_size] = 0; resp = data; free(data); unlink(RGW_ADMIN_RESP_PATH); /* cout << "radosgw-admin " << cmd << ": " << resp << std::endl; */ } } else return -1; return 0; } int get_creds(string& json, string& creds) { JSONParser parser; if(!parser.parse(json.c_str(), json.length())) { cout << "Error parsing create user response" << std::endl; return -1; } RGWUserInfo info; decode_json_obj(info, &parser); creds = ""; for(map::iterator it = info.access_keys.begin(); it != info.access_keys.end(); ++it) { RGWAccessKey _k = it->second; /*cout << "accesskeys [ " << it->first << " ] = " << "{ " << _k.id << ", " << _k.key << ", " << _k.subuser << "}" << std::endl;*/ creds.append(it->first + string(":") + _k.key); break; } return 0; } int user_create(string& uid, string& display_name, bool set_creds = true) { stringstream ss; string creds; ss << "-c " << g_test->get_ceph_conf_path() << " user create --uid=" << uid << " --display-name=" << display_name; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error creating user" << std::endl; return -1; } get_creds(out, creds); if(set_creds) g_test->set_creds(creds); return 0; } int user_info(string& uid, string& display_name, RGWUserInfo& uinfo) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " user info --uid=" << uid << " --display-name=" << display_name; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error reading user information" << std::endl; return -1; } JSONParser parser; if(!parser.parse(out.c_str(), out.length())) { cout << "Error parsing create user response" << std::endl; return -1; } decode_json_obj(uinfo, &parser); return 0; } int user_rm(string& uid, string& display_name) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " metadata rm --metadata-key=user:" << uid; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error removing user" << std::endl; return -1; } return 0; } int caps_add(const char * name, const char *perm) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " caps add --caps=" << name << "=" << perm << " --uid=" << uid; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error creating user" << std::endl; return -1; } return 0; } int caps_rm(const char * name, const char *perm) { stringstream ss; ss << "-c " << g_test->get_ceph_conf_path() << " caps rm --caps=" << name << "=" << perm << " --uid=" << uid; string out; string cmd = ss.str(); if(run_rgw_admin(cmd, out) != 0) { cout << "Error creating user" << std::endl; return -1; } return 0; } size_t read_dummy_post(void *ptr, size_t s, size_t n, void *ud) { int dummy = 0; memcpy(ptr, &dummy, sizeof(dummy)); return sizeof(dummy); } int parse_json_resp(JSONParser &parser) { string *resp; resp = (string *)g_test->get_response_data(); if(!resp) return -1; if(!parser.parse(resp->c_str(), resp->length())) { cout << "Error parsing create user response" << std::endl; return -1; } return 0; } static int decode_json(JSONObj *obj, cls_statelog_entry& ret) { JSONDecoder::decode_json("op_id", ret.op_id, obj); JSONDecoder::decode_json("client_id", ret.client_id, obj); JSONDecoder::decode_json("object", ret.object, obj); string state; JSONDecoder::decode_json("state", state, obj); RGWOpState oc(store); return oc.state_from_str(state, (RGWOpState::OpState *)&ret.state); } static int get_opstate_list(list &entries) { JSONParser parser; if (parse_json_resp(parser) != 0) return -1; if (!parser.is_array()) return -1; vector l; l = parser.get_array_elements(); int loop = 0; for(vector::iterator it = l.begin(); it != l.end(); ++it, loop++) { JSONParser jp; cls_statelog_entry entry; if(!jp.parse((*it).c_str(), (*it).length())) { cerr << "Error parsing log json object" << std::endl; return -1; } EXPECT_EQ(decode_json((JSONObj *)&jp, entry), 0); entries.push_back(entry); } return 0; } TEST(TestRGWAdmin, opstate_set_list_delete) { const char *cname = "opstate", *perm = "*"; string rest_req; stringstream ss; list entries; string cid_1 = "cid_1", cid_2 = "cid_2"; string oid_1 = "operation", oid_2 = "operation"; string obj_1 = "obj1", obj_2 = "obj2"; string state; ASSERT_EQ(user_create(uid, display_name), 0); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/opstate?client-id=1&op-id=1&object=o"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing state*/ rest_req = "/admin/opstate?client-id=1&op-id=1&state=in-progress"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing object*/ rest_req = "/admin/opstate?client-id=1&state=in-progress&object=o"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing op-id*/ rest_req = "/admin/opstate?state=in-progress&op-id=1&object=o"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing client-id*/ rest_req = "/admin/opstate?state=invalid&op-id=1&object=o&client-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Invalid state*/ state = "in-progress"; entries.clear(); ss << "/admin/opstate?client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1 << "&state=" << state; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); entries.clear(); rest_req = "/admin/opstate"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 1U); if (entries.size() == 1U) { list::iterator it = entries.begin(); EXPECT_TRUE((*it).client_id.compare(cid_1) == 0); EXPECT_TRUE((*it).op_id.compare(oid_1) == 0); EXPECT_TRUE((*it).object.compare(obj_1) == 0); EXPECT_EQ((*it).state, (uint32_t)RGWOpState::OPSTATE_IN_PROGRESS); } state = "complete"; ss.str(""); entries.clear(); ss << "/admin/opstate?client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1 << "&state=" << state; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); rest_req = "/admin/opstate"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 1U); if (entries.size() == 1U) { list::iterator it = entries.begin(); EXPECT_TRUE((*it).client_id.compare(cid_1) == 0); EXPECT_TRUE((*it).op_id.compare(oid_1) == 0); EXPECT_TRUE((*it).object.compare(obj_1) == 0); EXPECT_EQ((*it).state, (uint32_t)RGWOpState::OPSTATE_COMPLETE); } ss.str(""); entries.clear(); ss << "/admin/opstate?client-id=" << cid_2 << "&op-id=" << oid_2 << "&object=" << obj_2 << "&state=" << state; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); entries.clear(); rest_req = "/admin/opstate"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 2U); if (entries.size() == 1U) { list::iterator it = entries.begin(); EXPECT_TRUE((*it).client_id.compare(cid_1) == 0); EXPECT_TRUE((*it).op_id.compare(oid_1) == 0); EXPECT_TRUE((*it).object.compare(obj_1) == 0); EXPECT_EQ((*it).state, (uint32_t)RGWOpState::OPSTATE_COMPLETE); it++; EXPECT_TRUE((*it).client_id.compare(cid_2) == 0); EXPECT_TRUE((*it).op_id.compare(oid_2) == 0); EXPECT_TRUE((*it).object.compare(obj_2) == 0); EXPECT_EQ((*it).state, (uint32_t)RGWOpState::OPSTATE_COMPLETE); } entries.clear(); rest_req = "/admin/opstate?max-entries=1"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 1U); ss.str(""); entries.clear(); ss << "/admin/opstate?client-id=" << cid_2 << "&op-id=" << oid_2 << "&object=" << obj_2; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 1U); ss.str(""); entries.clear(); ss << "/admin/opstate?client-id=" << cid_2; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 1U); ss.str(""); entries.clear(); ss << "/admin/opstate?op-id=" << oid_2; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 2U); ss.str(""); entries.clear(); ss << "/admin/opstate?op-id=" << oid_2 << "&object=" << obj_1 << "&client-id=" << cid_2 ; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 0U); rest_req = "/admin/opstate?client-id=1&op-id=1"; g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing object*/ rest_req = "/admin/opstate?client-id=1&object=1"; g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing op-id*/ rest_req = "/admin/opstate?object=1&op-id=1"; g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing client-id*/ rest_req = "/admin/opstate?object=1&op-id=1&client-id=1"; g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(404U, g_test->get_resp_code()); ss.str(""); ss << "/admin/opstate?client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); entries.clear(); ss << "/admin/opstate"; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 1U); ss.str(""); ss << "/admin/opstate?client-id=" << cid_2 << "&op-id=" << oid_2 << "&object=" << obj_2; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); entries.clear(); ss << "/admin/opstate"; rest_req = ss.str(); g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); EXPECT_EQ(get_opstate_list(entries), 0); EXPECT_EQ(entries.size(), 0U); ASSERT_EQ(caps_rm(cname, perm), 0); ASSERT_EQ(user_rm(uid, display_name), 0); } TEST(TestRGWAdmin, opstate_renew) { const char *cname = "opstate", *perm = "*"; string rest_req; stringstream ss; string cid_1 = "cid_1"; string oid_1 = "operation"; string obj_1 = "obj1"; string state; ASSERT_EQ(user_create(uid, display_name), 0); ASSERT_EQ(0, caps_add(cname, perm)); rest_req = "/admin/opstate?renew&client-id=1&op-id=1&object=o"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing state*/ rest_req = "/admin/opstate?renew&client-id=1&op-id=1&state=in-progress"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing object*/ rest_req = "/admin/opstate?renew&client-id=1&state=in-progress&object=o"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing op-id*/ rest_req = "/admin/opstate?renew&state=in-progress&op-id=1&object=o"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Missing client-id*/ rest_req = "/admin/opstate?&renew&state=invalid&op-id=1&object=o&client-id=1"; g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(400U, g_test->get_resp_code()); /*Invalid state*/ state = "complete"; ss.str(""); ss << "/admin/opstate?client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1 << "&state=" << state; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); rest_req = "/admin/opstate"; g_test->send_request(string("GET"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); ss << "/admin/opstate?renew&client-id=" << cid_1 << "&op-id=1" << "&object=" << obj_1 << "&state=" << state; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(404U, g_test->get_resp_code()); ss.str(""); ss << "/admin/opstate?renew&client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1 << "&state=" << state; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(200U, g_test->get_resp_code()); ss.str(""); ss << "/admin/opstate?renew&client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1 << "&state=in-progress"; rest_req = ss.str(); g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); EXPECT_EQ(500U, g_test->get_resp_code()); ss.str(""); ss << "/admin/opstate?client-id=" << cid_1 << "&op-id=" << oid_1 << "&object=" << obj_1; rest_req = ss.str(); g_test->send_request(string("DELETE"), rest_req); EXPECT_EQ(200U, g_test->get_resp_code()); ASSERT_EQ(caps_rm(cname, perm), 0); ASSERT_EQ(user_rm(uid, display_name), 0); } int main(int argc, char *argv[]){ vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); store = RGWStoreManager::get_storage(g_ceph_context, false, false); g_test = new admin_log::test_helper(); finisher = new Finisher(g_ceph_context); #ifdef GTEST ::testing::InitGoogleTest(&argc, argv); #endif finisher->start(); if(g_test->extract_input(argc, argv) < 0){ print_usage(argv[0]); return -1; } #ifdef GTEST int r = RUN_ALL_TESTS(); if (r >= 0) { cout << "There are no failures in the test case\n"; } else { cout << "There are some failures\n"; } #endif finisher->stop(); return 0; } ceph-0.80.11/src/test/signals.cc0000664000175100017510000000525412623076744020420 0ustar jenkins-buildjenkins-build#include "common/config.h" #include "common/signal.h" #include "global/signal_handler.h" #include "test/unit.h" #include #include #include #include static volatile sig_atomic_t got_sigusr1 = 0; static void handle_sigusr1(int signo) { got_sigusr1 = 1; } TEST(SignalApi, SimpleInstall) { install_sighandler(SIGPIPE, handle_sigusr1, 0); } TEST(SignalApi, SimpleInstallAndTest) { install_sighandler(SIGPIPE, handle_sigusr1, 0); // SIGPIPE starts out blocked int ret = kill(getpid(), SIGPIPE); ASSERT_EQ(ret, 0); ASSERT_EQ(got_sigusr1, 0); // handle SIGPIPE sigset_t mask; sigemptyset(&mask); ret = sigsuspend(&mask); if (ret == -1) ret = errno; // we should have gotten it ASSERT_EQ(ret, EINTR); ASSERT_EQ(got_sigusr1, 1); } TEST(SignalEffects, ErrnoTest1) { } bool usr1 = false; bool usr2 = false; void reset() { usr1 = false; usr2 = false; } void testhandler(int signal) { switch (signal) { case SIGUSR1: usr1 = true; break; case SIGUSR2: usr2 = true; break; default: assert(0 == "unexpected signal"); } } TEST(SignalHandler, Single) { reset(); init_async_signal_handler(); register_async_signal_handler(SIGUSR1, testhandler); ASSERT_TRUE(usr1 == false); int ret = kill(getpid(), SIGUSR1); ASSERT_EQ(ret, 0); sleep(1); ASSERT_TRUE(usr1 == true); unregister_async_signal_handler(SIGUSR1, testhandler); shutdown_async_signal_handler(); } TEST(SignalHandler, Multiple) { int ret; reset(); init_async_signal_handler(); register_async_signal_handler(SIGUSR1, testhandler); register_async_signal_handler(SIGUSR2, testhandler); ASSERT_TRUE(usr1 == false); ASSERT_TRUE(usr2 == false); ret = kill(getpid(), SIGUSR1); ASSERT_EQ(ret, 0); ret = kill(getpid(), SIGUSR2); ASSERT_EQ(ret, 0); sleep(1); ASSERT_TRUE(usr1 == true); ASSERT_TRUE(usr2 == true); unregister_async_signal_handler(SIGUSR1, testhandler); unregister_async_signal_handler(SIGUSR2, testhandler); shutdown_async_signal_handler(); } /* TEST(SignalHandler, MultipleBigFd) { int ret; for (int i = 0; i < 1500; i++) ::open(".", O_RDONLY); reset(); init_async_signal_handler(); register_async_signal_handler(SIGUSR1, testhandler); register_async_signal_handler(SIGUSR2, testhandler); ASSERT_TRUE(usr1 == false); ASSERT_TRUE(usr2 == false); ret = kill(getpid(), SIGUSR1); ASSERT_EQ(ret, 0); ret = kill(getpid(), SIGUSR2); ASSERT_EQ(ret, 0); sleep(1); ASSERT_TRUE(usr1 == true); ASSERT_TRUE(usr2 == true); unregister_async_signal_handler(SIGUSR1, testhandler); unregister_async_signal_handler(SIGUSR2, testhandler); shutdown_async_signal_handler(); } */ ceph-0.80.11/src/test/run-cli-tests-maybe-unset-ccache0000775000175100017510000000050612623076744024536 0ustar jenkins-buildjenkins-build#!/bin/sh set -e # ccache breaks if it sees CCACHE_DIR="", yet due to clumsiness of # /usr/bin/env, it's hard to avoid setting env vars for the parent; # unset them if they're empty if [ -z "$CCACHE_DIR" ]; then unset CCACHE_DIR fi if [ -z "$CC" ]; then unset CC fi if [ -z "$CXX" ]; then unset CXX fi exec "$@" ceph-0.80.11/src/test/test_workqueue.cc0000664000175100017510000000272712623076744022050 0ustar jenkins-buildjenkins-build#include "gtest/gtest.h" #include "common/WorkQueue.h" #include "global/global_context.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/common_init.h" TEST(WorkQueue, StartStop) { ThreadPool tp(g_ceph_context, "foo", 10, ""); tp.start(); tp.pause(); tp.pause_new(); tp.unpause(); tp.unpause(); tp.drain(); tp.stop(); } TEST(WorkQueue, Resize) { ThreadPool tp(g_ceph_context, "bar", 2, "osd_op_threads"); tp.start(); sleep(1); ASSERT_EQ(2, tp.get_num_threads()); g_conf->set_val("osd op threads", "5"); g_conf->apply_changes(&cout); sleep(1); ASSERT_EQ(5, tp.get_num_threads()); g_conf->set_val("osd op threads", "3"); g_conf->apply_changes(&cout); sleep(1); ASSERT_EQ(3, tp.get_num_threads()); g_conf->set_val("osd op threads", "15"); g_conf->apply_changes(&cout); sleep(1); ASSERT_EQ(15, tp.get_num_threads()); g_conf->set_val("osd op threads", "0"); g_conf->apply_changes(&cout); sleep(1); ASSERT_EQ(15, tp.get_num_threads()); g_conf->set_val("osd op threads", "-1"); g_conf->apply_changes(&cout); sleep(1); ASSERT_EQ(15, tp.get_num_threads()); sleep(1); tp.stop(); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); return RUN_ALL_TESTS(); } ceph-0.80.11/src/test/test_snap_mapper.cc0000664000175100017510000003552012623076744022323 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- #include "include/memory.h" #include #include #include #include #include "include/buffer.h" #include "common/map_cacher.hpp" #include "osd/SnapMapper.h" #include "global/global_init.h" #include "common/ceph_argparse.h" #include "gtest/gtest.h" #include "stdlib.h" using namespace std; template typename T::iterator rand_choose(T &cont) { if (cont.size() == 0) { return cont.end(); } int index = rand() % cont.size(); typename T::iterator retval = cont.begin(); for (; index > 0; --index) ++retval; return retval; } string random_string(size_t size) { string name; for (size_t j = 0; j < size; ++j) { name.push_back('a' + (rand() % 26)); } return name; } class PausyAsyncMap : public MapCacher::StoreDriver { struct _Op { virtual void operate(map *store) = 0; virtual ~_Op() {} }; typedef ceph::shared_ptr<_Op> Op; struct Remove : public _Op { set to_remove; Remove(const set &to_remove) : to_remove(to_remove) {} void operate(map *store) { for (set::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { store->erase(*i); } } }; struct Insert : public _Op { map to_insert; Insert(const map &to_insert) : to_insert(to_insert) {} void operate(map *store) { for (map::iterator i = to_insert.begin(); i != to_insert.end(); ++i) { store->erase(i->first); store->insert(*i); } } }; struct Callback : public _Op { Context *context; Callback(Context *c) : context(c) {} void operate(map *store) { context->complete(0); } }; public: class Transaction : public MapCacher::Transaction { friend class PausyAsyncMap; list ops; list callbacks; public: void set_keys(const map &i) { ops.push_back(Op(new Insert(i))); } void remove_keys(const set &r) { ops.push_back(Op(new Remove(r))); } void add_callback(Context *c) { callbacks.push_back(Op(new Callback(c))); } }; private: Mutex lock; map store; class Doer : public Thread { static const size_t MAX_SIZE = 100; PausyAsyncMap *parent; Mutex lock; Cond cond; int stopping; bool paused; list queue; public: Doer(PausyAsyncMap *parent) : parent(parent), lock("Doer lock"), stopping(0), paused(false) {} virtual void *entry() { while (1) { list ops; { Mutex::Locker l(lock); while (!stopping && (queue.empty() || paused)) cond.Wait(lock); if (stopping && queue.empty()) { stopping = 2; cond.Signal(); return 0; } assert(!queue.empty()); assert(!paused); ops.swap(queue); cond.Signal(); } assert(!ops.empty()); for (list::iterator i = ops.begin(); i != ops.end(); ops.erase(i++)) { if (!(rand()%3)) usleep(1+(rand() % 5000)); Mutex::Locker l(parent->lock); (*i)->operate(&(parent->store)); } } } void pause() { Mutex::Locker l(lock); paused = true; cond.Signal(); } void resume() { Mutex::Locker l(lock); paused = false; cond.Signal(); } void submit(list &in) { Mutex::Locker l(lock); while (queue.size() >= MAX_SIZE) cond.Wait(lock); queue.splice(queue.end(), in, in.begin(), in.end()); cond.Signal(); } void stop() { Mutex::Locker l(lock); stopping = 1; cond.Signal(); while (stopping != 2) cond.Wait(lock); cond.Signal(); } } doer; public: PausyAsyncMap() : lock("PausyAsyncMap"), doer(this) { doer.create(); } ~PausyAsyncMap() { doer.join(); } int get_keys( const set &keys, map *out) { Mutex::Locker l(lock); for (set::const_iterator i = keys.begin(); i != keys.end(); ++i) { map::iterator j = store.find(*i); if (j != store.end()) out->insert(*j); } return 0; } int get_next( const string &key, pair *next) { Mutex::Locker l(lock); map::iterator j = store.upper_bound(key); if (j != store.end()) { if (next) *next = *j; return 0; } else { return -ENOENT; } } void submit(Transaction *t) { doer.submit(t->ops); doer.submit(t->callbacks); } void flush() { Mutex lock("flush lock"); Cond cond; bool done = false; class OnFinish : public Context { Mutex *lock; Cond *cond; bool *done; public: OnFinish(Mutex *lock, Cond *cond, bool *done) : lock(lock), cond(cond), done(done) {} void finish(int) { Mutex::Locker l(*lock); *done = true; cond->Signal(); } }; Transaction t; t.add_callback(new OnFinish(&lock, &cond, &done)); submit(&t); { Mutex::Locker l(lock); while (!done) cond.Wait(lock); } } void pause() { doer.pause(); } void resume() { doer.resume(); } void stop() { doer.stop(); } }; class MapCacherTest : public ::testing::Test { protected: boost::scoped_ptr< PausyAsyncMap > driver; boost::scoped_ptr > cache; map truth; set names; public: void assert_bl_eq(bufferlist &bl1, bufferlist &bl2) { ASSERT_EQ(bl1.length(), bl2.length()); bufferlist::iterator j = bl2.begin(); for (bufferlist::iterator i = bl1.begin(); !i.end(); ++i, ++j) { ASSERT_TRUE(!j.end()); ASSERT_EQ(*i, *j); } } void assert_bl_map_eq(map &m1, map &m2) { ASSERT_EQ(m1.size(), m2.size()); map::iterator j = m2.begin(); for (map::iterator i = m1.begin(); i != m1.end(); ++i, ++j) { ASSERT_TRUE(j != m2.end()); ASSERT_EQ(i->first, j->first); assert_bl_eq(i->second, j->second); } } size_t random_num() { return random() % 10; } size_t random_size() { return random() % 1000; } void random_bl(size_t size, bufferlist *bl) { for (size_t i = 0; i < size; ++i) { bl->append(rand()); } } void do_set() { size_t set_size = random_num(); map to_set; for (size_t i = 0; i < set_size; ++i) { bufferlist bl; random_bl(random_size(), &bl); string key = *rand_choose(names); to_set.insert( make_pair(key, bl)); } for (map::iterator i = to_set.begin(); i != to_set.end(); ++i) { truth.erase(i->first); truth.insert(*i); } { PausyAsyncMap::Transaction t; cache->set_keys(to_set, &t); driver->submit(&t); } } void remove() { size_t remove_size = random_num(); set to_remove; for (size_t i = 0; i < remove_size ; ++i) { to_remove.insert(*rand_choose(names)); } for (set::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { truth.erase(*i); } { PausyAsyncMap::Transaction t; cache->remove_keys(to_remove, &t); driver->submit(&t); } } void get() { set to_get; size_t get_size = random_num(); for (size_t i = 0; i < get_size; ++i) { to_get.insert(*rand_choose(names)); } map got_truth; for (set::iterator i = to_get.begin(); i != to_get.end(); ++i) { map::iterator j = truth.find(*i); if (j != truth.end()) got_truth.insert(*j); } map got; cache->get_keys(to_get, &got); assert_bl_map_eq(got, got_truth); } void get_next() { string cur; while (true) { pair next; int r = cache->get_next(cur, &next); pair next_truth; map::iterator i = truth.upper_bound(cur); int r_truth = (i == truth.end()) ? -ENOENT : 0; if (i != truth.end()) next_truth = *i; ASSERT_EQ(r, r_truth); if (r == -ENOENT) break; ASSERT_EQ(next.first, next_truth.first); assert_bl_eq(next.second, next_truth.second); cur = next.first; } } virtual void SetUp() { driver.reset(new PausyAsyncMap()); cache.reset(new MapCacher::MapCacher(driver.get())); names.clear(); truth.clear(); size_t names_size(random_num() + 10); for (size_t i = 0; i < names_size; ++i) { names.insert(random_string(1 + (random_size() % 10))); } } virtual void TearDown() { driver->stop(); cache.reset(); driver.reset(); } }; TEST_F(MapCacherTest, Simple) { driver->pause(); map truth; set truth_keys; string blah("asdf"); bufferlist bl; ::encode(blah, bl); truth[string("asdf")] = bl; truth_keys.insert(truth.begin()->first); { PausyAsyncMap::Transaction t; cache->set_keys(truth, &t); driver->submit(&t); cache->set_keys(truth, &t); driver->submit(&t); } map got; cache->get_keys(truth_keys, &got); assert_bl_map_eq(got, truth); driver->resume(); sleep(1); got.clear(); cache->get_keys(truth_keys, &got); assert_bl_map_eq(got, truth); } TEST_F(MapCacherTest, Random) { for (size_t i = 0; i < 5000; ++i) { if (!(i % 50)) { std::cout << "On iteration " << i << std::endl; } switch (rand() % 4) { case 0: get(); break; case 1: do_set(); break; case 2: get_next(); break; case 3: remove(); break; } } } class MapperVerifier { PausyAsyncMap *driver; boost::scoped_ptr< SnapMapper > mapper; map > snap_to_hobject; map > hobject_to_snap; snapid_t next; uint32_t mask; uint32_t bits; Mutex lock; public: MapperVerifier( PausyAsyncMap *driver, uint32_t mask, uint32_t bits) : driver(driver), mapper(new SnapMapper(driver, mask, bits, 0, 1)), mask(mask), bits(bits), lock("lock") {} hobject_t random_hobject() { return hobject_t( random_string(1+(rand() % 16)), random_string(1+(rand() % 16)), snapid_t(rand() % 1000), (rand() & ((~0)< *snaps) { assert(snaps); assert(!snap_to_hobject.empty()); for (int i = 0; i < num || snaps->empty(); ++i) { snaps->insert(rand_choose(snap_to_hobject)->first); } } void create_snap() { snap_to_hobject[next]; ++next; } void create_object() { Mutex::Locker l(lock); if (snap_to_hobject.empty()) return; hobject_t obj; do { obj = random_hobject(); } while (hobject_to_snap.count(obj)); set &snaps = hobject_to_snap[obj]; choose_random_snaps(1 + (rand() % 20), &snaps); for (set::iterator i = snaps.begin(); i != snaps.end(); ++i) { map >::iterator j = snap_to_hobject.find(*i); assert(j != snap_to_hobject.end()); j->second.insert(obj); } { PausyAsyncMap::Transaction t; mapper->add_oid(obj, snaps, &t); driver->submit(&t); } } void trim_snap() { Mutex::Locker l(lock); if (snap_to_hobject.empty()) return; map >::iterator snap = rand_choose(snap_to_hobject); set hobjects = snap->second; hobject_t hoid; while (mapper->get_next_object_to_trim(snap->first, &hoid) == 0) { assert(!hoid.is_max()); assert(hobjects.count(hoid)); hobjects.erase(hoid); map >::iterator j = hobject_to_snap.find(hoid); assert(j->second.count(snap->first)); set old_snaps(j->second); j->second.erase(snap->first); { PausyAsyncMap::Transaction t; mapper->update_snaps( hoid, j->second, &old_snaps, &t); driver->submit(&t); } if (j->second.empty()) { hobject_to_snap.erase(j); } hoid = hobject_t::get_max(); } assert(hobjects.empty()); snap_to_hobject.erase(snap); } void remove_oid() { Mutex::Locker l(lock); if (hobject_to_snap.empty()) return; map >::iterator obj = rand_choose(hobject_to_snap); for (set::iterator i = obj->second.begin(); i != obj->second.end(); ++i) { map >::iterator j = snap_to_hobject.find(*i); assert(j->second.count(obj->first)); j->second.erase(obj->first); } { PausyAsyncMap::Transaction t; mapper->remove_oid( obj->first, &t); driver->submit(&t); } hobject_to_snap.erase(obj); } void check_oid() { Mutex::Locker l(lock); if (hobject_to_snap.empty()) return; map >::iterator obj = rand_choose(hobject_to_snap); set snaps; int r = mapper->get_snaps(obj->first, &snaps); assert(r == 0); ASSERT_EQ(snaps, obj->second); } }; class SnapMapperTest : public ::testing::Test { protected: boost::scoped_ptr< PausyAsyncMap > driver; map > mappers; uint32_t pgnum; virtual void SetUp() { driver.reset(new PausyAsyncMap()); pgnum = 0; } virtual void TearDown() { driver->stop(); mappers.clear(); driver.reset(); } MapperVerifier &get_tester() { //return *(mappers.begin()->second); return *(rand_choose(mappers)->second); } void init(uint32_t to_set) { pgnum = to_set; for (uint32_t i = 0; i < pgnum; ++i) { pg_t pgid(i, 0, -1); mappers[pgid].reset( new MapperVerifier( driver.get(), i, pgid.get_split_bits(pgnum) ) ); } } void run() { for (int i = 0; i < 5000; ++i) { if (!(i % 50)) std::cout << i << std::endl; switch (rand() % 5) { case 0: get_tester().create_snap(); break; case 1: get_tester().create_object(); break; case 2: get_tester().trim_snap(); break; case 3: get_tester().check_oid(); break; case 4: get_tester().remove_oid(); break; } } } }; TEST_F(SnapMapperTest, Simple) { init(1); get_tester().create_snap(); get_tester().create_object(); get_tester().trim_snap(); } TEST_F(SnapMapperTest, More) { init(1); run(); } TEST_F(SnapMapperTest, MultiPG) { init(50); run(); } int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ceph-0.80.11/src/ceph-disk0000775000175100017510000023532512623076744017273 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # # Copyright (C) 2014 Inktank # Copyright (C) 2014 Cloudwatt # # Author: Loic Dachary # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library Public License for more details. # import argparse import errno import fcntl import logging import os import os.path import platform import re import subprocess import stat import sys import tempfile import uuid """ Prepare: - create GPT partition - mark the partition with the ceph type uuid - create a file system - mark the fs as ready for ceph consumption - entire data disk is used (one big partition) - a new partition is added to the journal disk (so it can be easily shared) - triggered by administrator or ceph-deploy, e.g. 'ceph-disk [journal disk] Activate: - mount the volume in a temp location - allocate an osd id (if needed) - remount in the correct location /var/lib/ceph/osd/$cluster-$id - start ceph-osd - triggered by udev when it sees the OSD gpt partition type - triggered by admin 'ceph-disk activate ' - triggered on ceph service startup with 'ceph-disk activate-all' We rely on /dev/disk/by-partuuid to find partitions by their UUID; this is what the journal symlink inside the osd data volume normally points to. activate-all relies on /dev/disk/by-parttype-uuid/$typeuuid.$uuid to find all partitions. We install special udev rules to create these links. udev triggers 'ceph-disk activate ' or 'ceph-disk activate-journal ' based on the partition type. On old distros (e.g., RHEL6), the blkid installed does not recognized GPT partition metadata and the /dev/disk/by-partuuid etc. links aren't present. We have a horrible hack in the form of ceph-disk-udev that parses gparted output to create the symlinks above and triggers the 'ceph-disk activate' etc commands that udev normally would do if it knew the GPT partition type. """ CEPH_OSD_ONDISK_MAGIC = 'ceph osd volume v026' JOURNAL_UUID = '45b0969e-9b03-4f30-b4c6-b4b80ceff106' DMCRYPT_JOURNAL_UUID = '45b0969e-9b03-4f30-b4c6-5ec00ceff106' OSD_UUID = '4fbd7e29-9d25-41b8-afd0-062c0ceff05d' DMCRYPT_OSD_UUID = '4fbd7e29-9d25-41b8-afd0-5ec00ceff05d' TOBE_UUID = '89c57f98-2fe5-4dc0-89c1-f3ad0ceff2be' DMCRYPT_TOBE_UUID = '89c57f98-2fe5-4dc0-89c1-5ec00ceff2be' DEFAULT_FS_TYPE = 'xfs' MOUNT_OPTIONS = dict( btrfs='noatime,user_subvol_rm_allowed', # user_xattr is default ever since linux 2.6.39 / 3.0, but we'll # delay a moment before removing it fully because we did have some # issues with ext4 before the xatts-in-leveldb work, and it seemed # that user_xattr helped ext4='noatime,user_xattr', xfs='noatime,inode64', ) MKFS_ARGS = dict( btrfs=[ '-m', 'single', '-l', '32768', '-n', '32768', ], xfs=[ # xfs insists on not overwriting previous fs; even if we wipe # partition table, we often recreate it exactly the same way, # so we'll see ghosts of filesystems past '-f', '-i', 'size=2048', ], ) INIT_SYSTEMS = [ 'upstart', 'sysvinit', 'systemd', 'auto', 'none', ] STATEDIR = '/var/lib/ceph' SYSCONFDIR = '/etc/ceph' # only warn once about some things warned_about = {} # Nuke the TERM variable to avoid confusing any subprocesses we call. # For example, libreadline will print weird control sequences for some # TERM values. if 'TERM' in os.environ: del os.environ['TERM'] LOG_NAME = __name__ if LOG_NAME == '__main__': LOG_NAME = os.path.basename(sys.argv[0]) LOG = logging.getLogger(LOG_NAME) ###### lock ######## class filelock(object): def __init__(self, fn): self.fn = fn self.fd = None def acquire(self): assert not self.fd self.fd = file(self.fn, 'w') fcntl.lockf(self.fd, fcntl.LOCK_EX) def release(self): assert self.fd fcntl.lockf(self.fd, fcntl.LOCK_UN) self.fd = None ###### exceptions ######## class Error(Exception): """ Error """ def __str__(self): doc = self.__doc__.strip() return ': '.join([doc] + [str(a) for a in self.args]) class MountError(Error): """ Mounting filesystem failed """ class UnmountError(Error): """ Unmounting filesystem failed """ class BadMagicError(Error): """ Does not look like a Ceph OSD, or incompatible version """ class TruncatedLineError(Error): """ Line is truncated """ class TooManyLinesError(Error): """ Too many lines """ class FilesystemTypeError(Error): """ Cannot discover filesystem type """ class CephDiskException(Exception): """ A base exception for ceph-disk to provide custom (ad-hoc) messages that will be caught and dealt with when main() is executed """ pass class ExecutableNotFound(CephDiskException): """ Exception to report on executables not available in PATH """ pass ####### utils def maybe_mkdir(*a, **kw): """ Creates a new directory if it doesn't exist, removes existing symlink before creating the directory. """ # remove any symlink, if it is there.. if os.path.exists(*a) and stat.S_ISLNK(os.lstat(*a).st_mode): LOG.debug('Removing old symlink at %s', *a) os.unlink(*a) try: os.mkdir(*a, **kw) except OSError, e: if e.errno == errno.EEXIST: pass else: raise def which(executable): """find the location of an executable""" if 'PATH' in os.environ: envpath = os.environ['PATH'] else: envpath = os.defpath PATH = envpath.split(os.pathsep) locations = PATH + [ '/usr/local/bin', '/bin', '/usr/bin', '/usr/local/sbin', '/usr/sbin', '/sbin', ] for location in locations: executable_path = os.path.join(location, executable) if os.path.exists(executable_path): return executable_path def _get_command_executable(arguments): """ Return the full path for an executable, raise if the executable is not found. If the executable has already a full path do not perform any checks. """ if arguments[0].startswith('/'): # an absolute path return arguments executable = which(arguments[0]) if not executable: command_msg = 'Could not run command: %s' % ' '.join(arguments) executable_msg = '%s not in path.' % arguments[0] raise ExecutableNotFound('%s %s' % (executable_msg, command_msg)) # swap the old executable for the new one arguments[0] = executable return arguments def command(arguments, **kwargs): """ Safely execute a ``subprocess.Popen`` call making sure that the executable exists and raising a helpful error message if it does not. .. note:: This should be the prefered way of calling ``subprocess.Popen`` since it provides the caller with the safety net of making sure that executables *will* be found and will error nicely otherwise. This returns the output of the command and the return code of the process in a tuple: (output, returncode). """ arguments = _get_command_executable(arguments) LOG.info('Running command: %s' % ' '.join(arguments)) process = subprocess.Popen( arguments, stdout=subprocess.PIPE, **kwargs) out, _ = process.communicate() return out, process.returncode def command_check_call(arguments): """ Safely execute a ``subprocess.check_call`` call making sure that the executable exists and raising a helpful error message if it does not. .. note:: This should be the prefered way of calling ``subprocess.check_call`` since it provides the caller with the safety net of making sure that executables *will* be found and will error nicely otherwise. """ arguments = _get_command_executable(arguments) LOG.info('Running command: %s', ' '.join(arguments)) return subprocess.check_call(arguments) def platform_distro(): """ Returns a normalized, lower case string without any leading nor trailing whitespace that represents the distribution name of the current machine. """ distro = platform_information()[0] or '' return distro.strip().lower() def platform_information(): distro, release, codename = platform.linux_distribution() if not codename and 'debian' in distro.lower(): # this could be an empty string in Debian debian_codenames = { '8': 'jessie', '7': 'wheezy', '6': 'squeeze', } major_version = release.split('.')[0] codename = debian_codenames.get(major_version, '') # In order to support newer jessie/sid or wheezy/sid strings we test this # if sid is buried in the minor, we should use sid anyway. if not codename and '/' in release: major, minor = release.split('/') if minor == 'sid': codename = minor else: codename = major return ( str(distro).strip(), str(release).strip(), str(codename).strip() ) def get_dev_name(path): """ get device name from path. e.g.:: /dev/sda -> sdas, /dev/cciss/c0d1 -> cciss!c0d1 a device "name" is something like:: sdb cciss!c0d1 """ assert path.startswith('/dev/') base = path[5:] return base.replace('/', '!') def get_dev_path(name): """ get a path (/dev/...) from a name (cciss!c0d1) a device "path" is something like:: /dev/sdb /dev/cciss/c0d1 """ return '/dev/' + name.replace('!', '/') def get_dev_relpath(name): """ get a relative path to /dev from a name (cciss!c0d1) """ return name.replace('!', '/') def get_dev_size(dev, size='megabytes'): """ Attempt to get the size of a device so that we can prevent errors from actions to devices that are smaller, and improve error reporting. Because we want to avoid breakage in case this approach is not robust, we will issue a warning if we failed to get the size. :param size: bytes or megabytes :param dev: the device to calculate the size """ fd = os.open(dev, os.O_RDONLY) dividers = {'bytes': 1, 'megabytes': 1024*1024} try: device_size = os.lseek(fd, 0, os.SEEK_END) divider = dividers.get(size, 1024*1024) # default to megabytes return device_size/divider except Exception as error: LOG.warning('failed to get size of %s: %s' % (dev, str(error))) finally: os.close(fd) def get_partition_dev(dev, pnum): """ get the device name for a partition assume that partitions are named like the base dev, with a number, and optionally some intervening characters (like 'p'). e.g., sda 1 -> sda1 cciss/c0d1 1 -> cciss!c0d1p1 """ name = get_dev_name(os.path.realpath(dev)) partname = None for f in os.listdir(os.path.join('/sys/block', name)): if f.startswith(name) and f.endswith(str(pnum)): # we want the shortest name that starts with the base name and ends with the partition number if not partname or len(f) < len(partname): partname = f if partname: return get_dev_path(partname) else: raise Error('partition %d for %s does not appear to exist' % (pnum, dev)) def list_all_partitions(): """ Return a list of devices and partitions """ dev_part_list = {} for name in os.listdir('/sys/block'): # /dev/fd0 may hang http://tracker.ceph.com/issues/6827 if re.match(r'^fd\d$', name): continue if not os.path.exists(os.path.join('/sys/block', name, 'device')): continue dev_part_list[name] = list_partitions(name) return dev_part_list def list_partitions(basename): """ Return a list of partitions on the given device name """ partitions = [] for name in os.listdir(os.path.join('/sys/block', basename)): if name.startswith(basename): partitions.append(name) return partitions def get_partition_base(dev): """ Get the base device for a partition """ dev = os.path.realpath(dev) if not stat.S_ISBLK(os.lstat(dev).st_mode): raise Error('not a block device', dev) name = get_dev_name(dev) if os.path.exists(os.path.join('/sys/block', name)): raise Error('not a partition', dev) # find the base for basename in os.listdir('/sys/block'): if os.path.exists(os.path.join('/sys/block', basename, name)): return '/dev/' + basename raise Error('no parent device for partition', dev) def is_partition(dev): """ Check whether a given device path is a partition or a full disk. """ dev = os.path.realpath(dev) if not stat.S_ISBLK(os.lstat(dev).st_mode): raise Error('not a block device', dev) name = get_dev_name(dev) if os.path.exists(os.path.join('/sys/block', name)): return False # make sure it is a partition of something else for basename in os.listdir('/sys/block'): if os.path.exists(os.path.join('/sys/block', basename, name)): return True raise Error('not a disk or partition', dev) def is_mounted(dev): """ Check if the given device is mounted. """ dev = os.path.realpath(dev) with file('/proc/mounts', 'rb') as proc_mounts: for line in proc_mounts: fields = line.split() if len(fields) < 3: continue mounts_dev = fields[0] path = fields[1] if mounts_dev.startswith('/') and os.path.exists(mounts_dev): mounts_dev = os.path.realpath(mounts_dev) if mounts_dev == dev: return path return None def is_held(dev): """ Check if a device is held by another device (e.g., a dm-crypt mapping) """ assert os.path.exists(dev) dev = os.path.realpath(dev) base = get_dev_name(dev) # full disk? directory = '/sys/block/{base}/holders'.format(base=base) if os.path.exists(directory): return os.listdir(directory) # partition? part = base while len(base): directory = '/sys/block/{base}/{part}/holders'.format(part=part, base=base) if os.path.exists(directory): return os.listdir(directory) base = base[:-1] return [] def verify_not_in_use(dev, check_partitions=False): """ Verify if a given device (path) is in use (e.g. mounted or in use by device-mapper). :raises: Error if device is in use. """ assert os.path.exists(dev) if is_mounted(dev): raise Error('Device is mounted', dev) holders = is_held(dev) if holders: raise Error('Device is in use by a device-mapper mapping (dm-crypt?)' % dev, ','.join(holders)) if check_partitions and not is_partition(dev): basename = get_dev_name(os.path.realpath(dev)) for partname in list_partitions(basename): partition = get_dev_path(partname) if is_mounted(partition): raise Error('Device is mounted', partition) holders = is_held(partition) if holders: raise Error('Device %s is in use by a device-mapper mapping (dm-crypt?)' % partition, ','.join(holders)) def must_be_one_line(line): """ Checks if given line is really one single line. :raises: TruncatedLineError or TooManyLinesError :return: Content of the line, or None if line isn't valid. """ if line[-1:] != '\n': raise TruncatedLineError(line) line = line[:-1] if '\n' in line: raise TooManyLinesError(line) return line def read_one_line(parent, name): """ Read a file whose sole contents are a single line. Strips the newline. :return: Contents of the line, or None if file did not exist. """ path = os.path.join(parent, name) try: line = file(path, 'rb').read() except IOError as e: if e.errno == errno.ENOENT: return None else: raise try: line = must_be_one_line(line) except (TruncatedLineError, TooManyLinesError) as e: raise Error( 'File is corrupt: {path}: {msg}'.format( path=path, msg=e, ) ) return line def write_one_line(parent, name, text): """ Write a file whose sole contents are a single line. Adds a newline. """ path = os.path.join(parent, name) tmp = '{path}.{pid}.tmp'.format(path=path, pid=os.getpid()) with file(tmp, 'wb') as tmp_file: tmp_file.write(text + '\n') os.fsync(tmp_file.fileno()) os.rename(tmp, path) def check_osd_magic(path): """ Check that this path has the Ceph OSD magic. :raises: BadMagicError if this does not look like a Ceph OSD data dir. """ magic = read_one_line(path, 'magic') if magic is None: # probably not mkfs'ed yet raise BadMagicError(path) if magic != CEPH_OSD_ONDISK_MAGIC: raise BadMagicError(path) def check_osd_id(osd_id): """ Ensures osd id is numeric. """ if not re.match(r'^[0-9]+$', osd_id): raise Error('osd id is not numeric', osd_id) def allocate_osd_id( cluster, fsid, keyring, ): """ Accocates an OSD id on the given cluster. :raises: Error if the call to allocate the OSD id fails. :return: The allocated OSD id. """ LOG.debug('Allocating OSD id...') try: osd_id = _check_output( args=[ 'ceph', '--cluster', cluster, '--name', 'client.bootstrap-osd', '--keyring', keyring, 'osd', 'create', '--concise', fsid, ], ) except subprocess.CalledProcessError as e: raise Error('ceph osd create failed', e, e.output) osd_id = must_be_one_line(osd_id) check_osd_id(osd_id) return osd_id def get_osd_id(path): """ Gets the OSD id of the OSD at the given path. """ osd_id = read_one_line(path, 'whoami') if osd_id is not None: check_osd_id(osd_id) return osd_id def _check_output(args=None, **kwargs): out, ret = command(args, **kwargs) if ret: cmd = args[0] error = subprocess.CalledProcessError(ret, cmd) error.output = out raise error return out def get_conf(cluster, variable): """ Get the value of the given configuration variable from the cluster. :raises: Error if call to ceph-conf fails. :return: The variable value or None. """ try: out, ret = command( [ 'ceph-conf', '--cluster={cluster}'.format( cluster=cluster, ), '--name=osd.', '--lookup', variable, ], close_fds=True, ) except OSError as e: raise Error('error executing ceph-conf', e) if ret == 1: # config entry not found return None elif ret != 0: raise Error('getting variable from configuration failed') value = out.split('\n', 1)[0] # don't differentiate between "var=" and no var set if not value: return None return value def get_conf_with_default(cluster, variable): """ Get a config value that is known to the C++ code. This will fail if called on variables that are not defined in common config options. """ try: out = _check_output( args=[ 'ceph-osd', '--cluster={cluster}'.format( cluster=cluster, ), '--show-config-value={variable}'.format( variable=variable, ), ], close_fds=True, ) except subprocess.CalledProcessError as e: raise Error( 'getting variable from configuration failed', e, ) value = str(out).split('\n', 1)[0] return value def get_fsid(cluster): """ Get the fsid of the cluster. :return: The fsid or raises Error. """ fsid = get_conf_with_default(cluster=cluster, variable='fsid') if fsid is None: raise Error('getting cluster uuid from configuration failed') return fsid.lower() def get_or_create_dmcrypt_key( _uuid, key_dir, ): """ Get path to dmcrypt key or create a new key file. :return: Path to the dmcrypt key file. """ path = os.path.join(key_dir, _uuid) # already have it? if os.path.exists(path): return path # make a new key try: if not os.path.exists(key_dir): os.makedirs(key_dir, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR) with file('/dev/urandom', 'rb') as i: key = i.read(256) fd = os.open(path, os.O_WRONLY|os.O_CREAT, stat.S_IRUSR|stat.S_IWUSR) assert os.write(fd, key) == len(key) os.close(fd) return path except: raise Error('unable to read or create dm-crypt key', path) def dmcrypt_map( rawdev, keypath, _uuid, ): """ Maps a device to a dmcrypt device. :return: Path to the dmcrypt device. """ dev = '/dev/mapper/' + _uuid args = [ 'cryptsetup', '--key-file', keypath, '--key-size', '256', 'create', _uuid, rawdev, ] try: command_check_call(args) return dev except subprocess.CalledProcessError as e: raise Error('unable to map device', rawdev, e) def dmcrypt_unmap( _uuid ): """ Removes the dmcrypt device with the given UUID. """ args = [ 'cryptsetup', 'remove', _uuid ] try: command_check_call(args) except subprocess.CalledProcessError as e: raise Error('unable to unmap device', _uuid, e) def mount( dev, fstype, options, ): """ Mounts a device with given filessystem type and mount options to a tempfile path under /var/lib/ceph/tmp. """ # sanity check: none of the arguments are None if dev is None: raise ValueError('dev may not be None') if fstype is None: raise ValueError('fstype may not be None') # pick best-of-breed mount options based on fs type if options is None: options = MOUNT_OPTIONS.get(fstype, '') # mount path = tempfile.mkdtemp( prefix='mnt.', dir=STATEDIR + '/tmp', ) try: LOG.debug('Mounting %s on %s with options %s', dev, path, options) command_check_call( [ 'mount', '-t', fstype, '-o', options, '--', dev, path, ], ) except subprocess.CalledProcessError as e: try: os.rmdir(path) except (OSError, IOError): pass raise MountError(e) return path def unmount( path, ): """ Unmount and removes the given mount point. """ try: LOG.debug('Unmounting %s', path) command_check_call( [ '/bin/umount', '--', path, ], ) except subprocess.CalledProcessError as e: raise UnmountError(e) os.rmdir(path) ########################################### def extract_parted_partition_numbers(partitions): numbers_as_strings = re.findall('^\d+', partitions, re.MULTILINE) return map(int, numbers_as_strings) def get_free_partition_index(dev): """ Get the next free partition index on a given device. :return: Index number (> 1 if there is already a partition on the device) or 1 if there is no partition table. """ try: lines = _check_output( args=[ 'parted', '--machine', '--', dev, 'print', ], ) except subprocess.CalledProcessError as e: print 'cannot read partition index; assume it isn\'t present\n (Error: %s)' % e return 1 if not lines: raise Error('parted failed to output anything') if ('CHS;' not in lines and 'CYL;' not in lines and 'BYT;' not in lines): raise Error('parted output expected to contain one of ' + 'CHH; CYL; or BYT; : ' + lines) if dev not in lines: raise Error('parted output expected to contain ' + dev + ': ' + lines) _, partitions = lines.split(dev) partition_numbers = extract_parted_partition_numbers(partitions) if partition_numbers: return max(partition_numbers) + 1 else: return 1 def update_partition(action, dev, description): # try to make sure the kernel refreshes the table. note # that if this gets ebusy, we are probably racing with # udev because it already updated it.. ignore failure here. # On RHEL and CentOS distros, calling partprobe forces a reboot of the # server. Since we are not resizing partitons so we rely on calling # partx if platform_distro().startswith(('centos', 'red', 'scientific')): LOG.info('calling partx on %s device %s', description, dev) LOG.info('re-reading known partitions will display errors') command( [ 'partx', action, dev, ], ) else: LOG.debug('Calling partprobe on %s device %s', description, dev) command( [ 'partprobe', dev, ], ) def zap(dev): """ Destroy the partition table and content of a given disk. """ try: LOG.debug('Zapping partition table on %s', dev) # try to wipe out any GPT partition table backups. sgdisk # isn't too thorough. lba_size = 4096 size = 33 * lba_size with file(dev, 'wb') as dev_file: dev_file.seek(-size, os.SEEK_END) dev_file.write(size*'\0') command_check_call( [ 'sgdisk', '--zap-all', '--', dev, ], ) command_check_call( [ 'sgdisk', '--clear', '--mbrtogpt', '--', dev, ], ) update_partition('-d', dev, 'zapped') except subprocess.CalledProcessError as e: raise Error(e) def prepare_journal_dev( data, journal, journal_size, journal_uuid, journal_dm_keypath, ): reusing_partition = False if is_partition(journal): LOG.debug('Journal %s is a partition', journal) LOG.warning('OSD will not be hot-swappable if journal is not the same device as the osd data') if get_partition_type(journal) == JOURNAL_UUID: LOG.debug('Journal %s was previously prepared with ceph-disk. Reusing it.', journal) reusing_partition = True # Read and reuse the partition uuid from this journal's previous life. # We reuse the uuid instead of changing it because udev does not reliably # notice changes to an existing partition's GUID. # See http://tracker.ceph.com/issues/10146 journal_uuid = get_partition_uuid(journal) LOG.debug('Reusing journal with uuid %s', journal_uuid) else: LOG.warning('Journal %s was not prepared with ceph-disk. Symlinking directly.', journal) return (journal, None, None) journal_symlink = '/dev/disk/by-partuuid/{journal_uuid}'.format( journal_uuid=journal_uuid, ) journal_dmcrypt = None if journal_dm_keypath: journal_dmcrypt = journal_symlink journal_symlink = '/dev/mapper/{uuid}'.format(uuid=journal_uuid) if reusing_partition: # confirm that the journal_symlink exists. It should since this was an active journal # in the past. Continuing otherwise would be futile. assert os.path.exists(journal_symlink) return (journal_symlink, journal_dmcrypt, journal_uuid) # From here on we are creating a new journal device, not reusing. ptype = JOURNAL_UUID if journal_dm_keypath: ptype = DMCRYPT_JOURNAL_UUID # it is a whole disk. create a partition! num = None if journal == data: # we're sharing the disk between osd data and journal; # make journal be partition number 2, so it's pretty num = 2 journal_part = '{num}:0:{size}M'.format( num=num, size=journal_size, ) else: # sgdisk has no way for me to say "whatever is the next # free index number" when setting type guids etc, so we # need to awkwardly look up the next free number, and then # fix that in the call -- and hope nobody races with us; # then again nothing guards the partition table from races # anyway num = get_free_partition_index(dev=journal) journal_part = '{num}:0:+{size}M'.format( num=num, size=journal_size, ) LOG.warning('OSD will not be hot-swappable if journal is not the same device as the osd data') dev_size = get_dev_size(journal) if journal_size > dev_size: LOG.error('refusing to create journal on %s' % journal) LOG.error('journal size (%sM) is bigger than device (%sM)' % (journal_size, dev_size)) raise Error( '%s device size (%sM) is not big enough for journal' % (journal, dev_size) ) try: LOG.debug('Creating journal partition num %d size %d on %s', num, journal_size, journal) command_check_call( [ 'sgdisk', '--new={part}'.format(part=journal_part), '--change-name={num}:ceph journal'.format(num=num), '--partition-guid={num}:{journal_uuid}'.format( num=num, journal_uuid=journal_uuid, ), '--typecode={num}:{uuid}'.format( num=num, uuid=ptype, ), '--mbrtogpt', '--', journal, ] ) update_partition('-a', journal, 'prepared') # wait for udev event queue to clear command( [ 'udevadm', 'settle', ], ) LOG.debug('Journal is GPT partition %s', journal_symlink) # udev should have created the symlink by now. If not, abort. assert os.path.exists(journal_symlink) return (journal_symlink, journal_dmcrypt, journal_uuid) except subprocess.CalledProcessError as e: raise Error(e) def prepare_journal_file( journal): if not os.path.exists(journal): LOG.debug('Creating journal file %s with size 0 (ceph-osd will resize and allocate)', journal) with file(journal, 'wb') as journal_file: # noqa pass LOG.debug('Journal is file %s', journal) LOG.warning('OSD will not be hot-swappable if journal is not the same device as the osd data') return (journal, None, None) def prepare_journal( data, journal, journal_size, journal_uuid, force_file, force_dev, journal_dm_keypath, ): if journal is None: if force_dev: raise Error('Journal is unspecified; not a block device') return (None, None, None) if not os.path.exists(journal): if force_dev: raise Error('Journal does not exist; not a block device', journal) return prepare_journal_file(journal) jmode = os.stat(journal).st_mode if stat.S_ISREG(jmode): if force_dev: raise Error('Journal is not a block device', journal) return prepare_journal_file(journal) if stat.S_ISBLK(jmode): if force_file: raise Error('Journal is not a regular file', journal) return prepare_journal_dev(data, journal, journal_size, journal_uuid, journal_dm_keypath) raise Error('Journal %s is neither a block device nor regular file' % journal) def adjust_symlink(target, path): create = True if os.path.lexists(path): try: mode = os.lstat(path).st_mode if stat.S_ISREG(mode): LOG.debug('Removing old file %s', path) os.unlink(path) elif stat.S_ISLNK(mode): old = os.readlink(path) if old != target: LOG.debug('Removing old symlink %s -> %s', path, old) os.unlink(path) else: create = False except: raise Error('unable to remove (or adjust) old file (symlink)', path) if create: LOG.debug('Creating symlink %s -> %s', path, target) try: os.symlink(target, path) except: raise Error('unable to create symlink %s -> %s' % (path, target)) def prepare_dir( path, journal, cluster_uuid, osd_uuid, journal_uuid, journal_dmcrypt=None, ): if os.path.exists(os.path.join(path, 'magic')): LOG.debug('Data dir %s already exists', path) return else: LOG.debug('Preparing osd data dir %s', path) if osd_uuid is None: osd_uuid = str(uuid.uuid4()) if journal is not None: # we're using an external journal; point to it here adjust_symlink(journal, os.path.join(path, 'journal')) if journal_dmcrypt is not None: adjust_symlink(journal_dmcrypt, os.path.join(path, 'journal_dmcrypt')) else: try: os.unlink(os.path.join(path, 'journal_dmcrypt')) except OSError: pass write_one_line(path, 'ceph_fsid', cluster_uuid) write_one_line(path, 'fsid', osd_uuid) if journal_uuid is not None: # i.e., journal is a tagged partition write_one_line(path, 'journal_uuid', journal_uuid) write_one_line(path, 'magic', CEPH_OSD_ONDISK_MAGIC) def prepare_dev( data, journal, fstype, mkfs_args, mount_options, cluster_uuid, osd_uuid, journal_uuid, journal_dmcrypt, osd_dm_keypath, ): """ Prepare a data/journal combination to be used for an OSD. The ``magic`` file is written last, so it's presence is a reliable indicator of the whole sequence having completed. WARNING: This will unconditionally overwrite anything given to it. """ ptype_tobe = TOBE_UUID ptype_osd = OSD_UUID if osd_dm_keypath: ptype_tobe = DMCRYPT_TOBE_UUID ptype_osd = DMCRYPT_OSD_UUID rawdev = None if is_partition(data): LOG.debug('OSD data device %s is a partition', data) rawdev = data else: LOG.debug('Creating osd partition on %s', data) try: command_check_call( [ 'sgdisk', '--largest-new=1', '--change-name=1:ceph data', '--partition-guid=1:{osd_uuid}'.format( osd_uuid=osd_uuid, ), '--typecode=1:%s' % ptype_tobe, '--', data, ], ) update_partition('-a', data, 'created') command( [ # wait for udev event queue to clear 'udevadm', 'settle', ], ) except subprocess.CalledProcessError as e: raise Error(e) rawdev = get_partition_dev(data, 1) dev = None if osd_dm_keypath: dev = dmcrypt_map(rawdev, osd_dm_keypath, osd_uuid) else: dev = rawdev try: args = [ 'mkfs', '-t', fstype, ] if mkfs_args is not None: args.extend(mkfs_args.split()) if fstype == 'xfs': args.extend(['-f']) # always force else: args.extend(MKFS_ARGS.get(fstype, [])) args.extend([ '--', dev, ]) try: LOG.debug('Creating %s fs on %s', fstype, dev) command_check_call(args) except subprocess.CalledProcessError as e: raise Error(e) #remove whitespaces from mount_options if mount_options is not None: mount_options = "".join(mount_options.split()) path = mount(dev=dev, fstype=fstype, options=mount_options) try: prepare_dir( path=path, journal=journal, cluster_uuid=cluster_uuid, osd_uuid=osd_uuid, journal_uuid=journal_uuid, journal_dmcrypt=journal_dmcrypt, ) finally: unmount(path) finally: if rawdev != dev: dmcrypt_unmap(osd_uuid) if not is_partition(data): try: command_check_call( [ 'sgdisk', '--typecode=1:%s' % ptype_osd, '--', data, ], ) except subprocess.CalledProcessError as e: raise Error(e) def main_prepare(args): journal_dm_keypath = None osd_dm_keypath = None try: prepare_lock.acquire() # noqa if not os.path.exists(args.data): if args.data_dev: raise Error('data path does not exist', args.data) else: os.mkdir(args.data) # in use? dmode = os.stat(args.data).st_mode if stat.S_ISBLK(dmode): verify_not_in_use(args.data, True) if args.journal and os.path.exists(args.journal): jmode = os.stat(args.journal).st_mode if stat.S_ISBLK(jmode): verify_not_in_use(args.journal, False) if args.zap_disk is not None: if stat.S_ISBLK(dmode) and not is_partition(args.data): zap(args.data) else: raise Error('not full block device; cannot zap', args.data) if args.cluster_uuid is None: args.cluster_uuid = get_fsid(cluster=args.cluster) if args.cluster_uuid is None: raise Error( 'must have fsid in config or pass --cluster-uuid=', ) if args.fs_type is None: args.fs_type = get_conf( cluster=args.cluster, variable='osd_mkfs_type', ) if args.fs_type is None: args.fs_type = get_conf( cluster=args.cluster, variable='osd_fs_type', ) if args.fs_type is None: args.fs_type = DEFAULT_FS_TYPE mkfs_args = get_conf( cluster=args.cluster, variable='osd_mkfs_options_{fstype}'.format( fstype=args.fs_type, ), ) if mkfs_args is None: mkfs_args = get_conf( cluster=args.cluster, variable='osd_fs_mkfs_options_{fstype}'.format( fstype=args.fs_type, ), ) mount_options = get_conf( cluster=args.cluster, variable='osd_mount_options_{fstype}'.format( fstype=args.fs_type, ), ) if mount_options is None: mount_options = get_conf( cluster=args.cluster, variable='osd_fs_mount_options_{fstype}'.format( fstype=args.fs_type, ), ) journal_size = get_conf_with_default( cluster=args.cluster, variable='osd_journal_size', ) journal_size = int(journal_size) # colocate journal with data? if stat.S_ISBLK(dmode) and not is_partition(args.data) and args.journal is None and args.journal_file is None: LOG.info('Will colocate journal with data on %s', args.data) args.journal = args.data if args.journal_uuid is None: args.journal_uuid = str(uuid.uuid4()) if args.osd_uuid is None: args.osd_uuid = str(uuid.uuid4()) # dm-crypt keys? if args.dmcrypt: journal_dm_keypath = get_or_create_dmcrypt_key(args.journal_uuid, args.dmcrypt_key_dir) osd_dm_keypath = get_or_create_dmcrypt_key(args.osd_uuid, args.dmcrypt_key_dir) # prepare journal (journal_symlink, journal_dmcrypt, journal_uuid) = prepare_journal( data=args.data, journal=args.journal, journal_size=journal_size, journal_uuid=args.journal_uuid, force_file=args.journal_file, force_dev=args.journal_dev, journal_dm_keypath=journal_dm_keypath, ) # prepare data if stat.S_ISDIR(dmode): if args.data_dev: raise Error('data path is not a block device', args.data) prepare_dir( path=args.data, journal=journal_symlink, cluster_uuid=args.cluster_uuid, osd_uuid=args.osd_uuid, journal_uuid=journal_uuid, journal_dmcrypt=journal_dmcrypt, ) elif stat.S_ISBLK(dmode): if args.data_dir: raise Error('data path is not a directory', args.data) prepare_dev( data=args.data, journal=journal_symlink, fstype=args.fs_type, mkfs_args=mkfs_args, mount_options=mount_options, cluster_uuid=args.cluster_uuid, osd_uuid=args.osd_uuid, journal_uuid=journal_uuid, journal_dmcrypt=journal_dmcrypt, osd_dm_keypath=osd_dm_keypath, ) else: raise Error('not a dir or block device', args.data) prepare_lock.release() # noqa if stat.S_ISBLK(dmode): update_partition('-a', args.data, 'prepared') except Error as e: if journal_dm_keypath: os.unlink(journal_dm_keypath) if osd_dm_keypath: os.unlink(osd_dm_keypath) prepare_lock.release() # noqa raise e ########################### def mkfs( path, cluster, osd_id, fsid, keyring, ): monmap = os.path.join(path, 'activate.monmap') command_check_call( [ 'ceph', '--cluster', cluster, '--name', 'client.bootstrap-osd', '--keyring', keyring, 'mon', 'getmap', '-o', monmap, ], ) command_check_call( [ 'ceph-osd', '--cluster', cluster, '--mkfs', '--mkkey', '-i', osd_id, '--monmap', monmap, '--osd-data', path, '--osd-journal', os.path.join(path, 'journal'), '--osd-uuid', fsid, '--keyring', os.path.join(path, 'keyring'), ], ) # TODO ceph-osd --mkfs removes the monmap file? # os.unlink(monmap) def auth_key( path, cluster, osd_id, keyring, ): try: # try dumpling+ cap scheme command_check_call( [ 'ceph', '--cluster', cluster, '--name', 'client.bootstrap-osd', '--keyring', keyring, 'auth', 'add', 'osd.{osd_id}'.format(osd_id=osd_id), '-i', os.path.join(path, 'keyring'), 'osd', 'allow *', 'mon', 'allow profile osd', ], ) except subprocess.CalledProcessError as err: if err.returncode == errno.EACCES: # try old cap scheme command_check_call( [ 'ceph', '--cluster', cluster, '--name', 'client.bootstrap-osd', '--keyring', keyring, 'auth', 'add', 'osd.{osd_id}'.format(osd_id=osd_id), '-i', os.path.join(path, 'keyring'), 'osd', 'allow *', 'mon', 'allow rwx', ], ) else: raise def move_mount( dev, path, cluster, osd_id, fstype, mount_options, ): LOG.debug('Moving mount to final location...') parent = STATEDIR + '/osd' osd_data = os.path.join( parent, '{cluster}-{osd_id}'.format(cluster=cluster, osd_id=osd_id), ) maybe_mkdir(osd_data) # pick best-of-breed mount options based on fs type if mount_options is None: mount_options = MOUNT_OPTIONS.get(fstype, '') # we really want to mount --move, but that is not supported when # the parent mount is shared, as it is by default on RH, Fedora, # and probably others. Also, --bind doesn't properly manipulate # /etc/mtab, which *still* isn't a symlink to /proc/mounts despite # this being 2013. Instead, mount the original device at the final # location. command_check_call( [ '/bin/mount', '-o', mount_options, '--', dev, osd_data, ], ) command_check_call( [ '/bin/umount', '-l', # lazy, in case someone else is peeking at the # wrong moment '--', path, ], ) def start_daemon( cluster, osd_id, ): LOG.debug('Starting %s osd.%s...', cluster, osd_id) path = (STATEDIR + '/osd/{cluster}-{osd_id}').format( cluster=cluster, osd_id=osd_id) # upstart? try: if os.path.exists(os.path.join(path,'upstart')): command_check_call( [ '/sbin/initctl', # use emit, not start, because start would fail if the # instance was already running 'emit', # since the daemon starting doesn't guarantee much about # the service being operational anyway, don't bother # waiting for it '--no-wait', '--', 'ceph-osd', 'cluster={cluster}'.format(cluster=cluster), 'id={osd_id}'.format(osd_id=osd_id), ], ) elif os.path.exists(os.path.join(path, 'sysvinit')): if os.path.exists('/usr/sbin/service'): svc = '/usr/sbin/service' else: svc = '/sbin/service' command_check_call( [ svc, 'ceph', '--cluster', '{cluster}'.format(cluster=cluster), 'start', 'osd.{osd_id}'.format(osd_id=osd_id), ], ) else: raise Error('{cluster} osd.{osd_id} is not tagged with an init system'.format( cluster=cluster, osd_id=osd_id, )) except subprocess.CalledProcessError as e: raise Error('ceph osd start failed', e) def detect_fstype( dev, ): fstype = _check_output( args=[ '/sbin/blkid', # we don't want stale cached results '-p', '-s', 'TYPE', '-o' 'value', '--', dev, ], ) fstype = must_be_one_line(fstype) return fstype def mount_activate( dev, activate_key_template, init, ): try: fstype = detect_fstype(dev=dev) except (subprocess.CalledProcessError, TruncatedLineError, TooManyLinesError) as e: raise FilesystemTypeError( 'device {dev}'.format(dev=dev), e, ) # TODO always using mount options from cluster=ceph for # now; see http://tracker.newdream.net/issues/3253 mount_options = get_conf( cluster='ceph', variable='osd_mount_options_{fstype}'.format( fstype=fstype, ), ) if mount_options is None: mount_options = get_conf( cluster='ceph', variable='osd_fs_mount_options_{fstype}'.format( fstype=fstype, ), ) #remove whitespaces from mount_options if mount_options is not None: mount_options = "".join(mount_options.split()) path = mount(dev=dev, fstype=fstype, options=mount_options) osd_id = None cluster = None try: (osd_id, cluster) = activate(path, activate_key_template, init) # check if the disk is already active, or if something else is already # mounted there active = False other = False src_dev = os.stat(path).st_dev try: dst_dev = os.stat((STATEDIR + '/osd/{cluster}-{osd_id}').format( cluster=cluster, osd_id=osd_id)).st_dev if src_dev == dst_dev: active = True else: parent_dev = os.stat(STATEDIR + '/osd').st_dev if dst_dev != parent_dev: other = True elif os.listdir((STATEDIR + '/osd/{cluster}-{osd_id}').format( cluster=cluster, osd_id=osd_id, )): other = True except OSError: pass if active: LOG.info('%s osd.%s already mounted in position; unmounting ours.' % (cluster, osd_id)) unmount(path) elif other: raise Error('another %s osd.%s already mounted in position (old/different cluster instance?); unmounting ours.' % (cluster, osd_id)) else: move_mount( dev=dev, path=path, cluster=cluster, osd_id=osd_id, fstype=fstype, mount_options=mount_options, ) return (cluster, osd_id) except: LOG.error('Failed to activate') unmount(path) raise finally: # remove our temp dir if os.path.exists(path): os.rmdir(path) def activate_dir( path, activate_key_template, init, ): if not os.path.exists(path): raise Error( 'directory %s does not exist' % path ) (osd_id, cluster) = activate(path, activate_key_template, init) if init not in (None, 'none' ): canonical = (STATEDIR + '/osd/{cluster}-{osd_id}').format( cluster=cluster, osd_id=osd_id) if path != canonical: # symlink it from the proper location create = True if os.path.lexists(canonical): old = os.readlink(canonical) if old != path: LOG.debug('Removing old symlink %s -> %s', canonical, old) try: os.unlink(canonical) except: raise Error('unable to remove old symlink', canonical) else: create = False if create: LOG.debug('Creating symlink %s -> %s', canonical, path) try: os.symlink(path, canonical) except: raise Error('unable to create symlink %s -> %s' % (canonical, path)) return (cluster, osd_id) def find_cluster_by_uuid(_uuid): """ Find a cluster name by searching /etc/ceph/*.conf for a conf file with the right uuid. """ _uuid = _uuid.lower() no_fsid = [] if not os.path.exists(SYSCONFDIR): return None for conf_file in os.listdir(SYSCONFDIR): if not conf_file.endswith('.conf'): continue cluster = conf_file[:-5] try: fsid = get_fsid(cluster) except Error as e: if e.message != 'getting cluster uuid from configuration failed': raise e no_fsid.append(cluster) else: if fsid == _uuid: return cluster # be tolerant of /etc/ceph/ceph.conf without an fsid defined. if len(no_fsid) == 1 and no_fsid[0] == 'ceph': LOG.warning('No fsid defined in ' + SYSCONFDIR + '/ceph.conf; using anyway') return 'ceph' return None def activate( path, activate_key_template, init, ): check_osd_magic(path) ceph_fsid = read_one_line(path, 'ceph_fsid') if ceph_fsid is None: raise Error('No cluster uuid assigned.') LOG.debug('Cluster uuid is %s', ceph_fsid) cluster = find_cluster_by_uuid(ceph_fsid) if cluster is None: raise Error('No cluster conf found in ' + SYSCONFDIR + ' with fsid %s' % ceph_fsid) LOG.debug('Cluster name is %s', cluster) fsid = read_one_line(path, 'fsid') if fsid is None: raise Error('No OSD uuid assigned.') LOG.debug('OSD uuid is %s', fsid) keyring = activate_key_template.format(cluster=cluster, statedir=STATEDIR) osd_id = get_osd_id(path) if osd_id is None: osd_id = allocate_osd_id( cluster=cluster, fsid=fsid, keyring=keyring, ) write_one_line(path, 'whoami', osd_id) LOG.debug('OSD id is %s', osd_id) if not os.path.exists(os.path.join(path, 'ready')): LOG.debug('Initializing OSD...') # re-running mkfs is safe, so just run until it completes mkfs( path=path, cluster=cluster, osd_id=osd_id, fsid=fsid, keyring=keyring, ) if init not in (None, 'none' ): if init == 'auto': conf_val = get_conf( cluster=cluster, variable='init' ) if conf_val is not None: init = conf_val else: (distro, release, codename) = platform.dist() if distro == 'Ubuntu': init = 'upstart' else: init = 'sysvinit' LOG.debug('Marking with init system %s', init) with file(os.path.join(path, init), 'w'): pass # remove markers for others, just in case. for other in INIT_SYSTEMS: if other != init: try: os.unlink(os.path.join(path, other)) except OSError: pass if not os.path.exists(os.path.join(path, 'active')): LOG.debug('Authorizing OSD key...') auth_key( path=path, cluster=cluster, osd_id=osd_id, keyring=keyring, ) write_one_line(path, 'active', 'ok') LOG.debug('%s osd.%s data dir is ready at %s', cluster, osd_id, path) return (osd_id, cluster) def main_activate(args): cluster = None osd_id = None if not os.path.exists(args.path): raise Error('%s does not exist' % args.path) if is_suppressed(args.path): LOG.info('suppressed activate request on %s', args.path) return activate_lock.acquire() # noqa try: mode = os.stat(args.path).st_mode if stat.S_ISBLK(mode): (cluster, osd_id) = mount_activate( dev=args.path, activate_key_template=args.activate_key_template, init=args.mark_init, ) elif stat.S_ISDIR(mode): (cluster, osd_id) = activate_dir( path=args.path, activate_key_template=args.activate_key_template, init=args.mark_init, ) if args.mark_init == 'none': command_check_call( [ 'ceph-osd', '--cluster={cluster}'.format(cluster=cluster), '--id={osd_id}'.format(osd_id=osd_id), '--osd-data={path}'.format(path=args.path), '--osd-journal={path}/journal'.format(path=args.path), ], ) else: raise Error('%s is not a directory or block device' % args.path) if args.mark_init not in (None, 'none' ): start_daemon( cluster=cluster, osd_id=osd_id, ) finally: activate_lock.release() # noqa ########################### def get_journal_osd_uuid(path): if not os.path.exists(path): raise Error('%s does not exist' % path) mode = os.stat(path).st_mode if not stat.S_ISBLK(mode): raise Error('%s is not a block device' % path) try: out = _check_output( args=[ 'ceph-osd', '-i', '0', # this is ignored '--get-journal-uuid', '--osd-journal', path, ], close_fds=True, ) except subprocess.CalledProcessError as e: raise Error( 'failed to get osd uuid/fsid from journal', e, ) value = str(out).split('\n', 1)[0] LOG.debug('Journal %s has OSD UUID %s', path, value) return value def main_activate_journal(args): if not os.path.exists(args.dev): raise Error('%s does not exist' % args.dev) cluster = None osd_id = None osd_uuid = None activate_lock.acquire() # noqa try: osd_uuid = get_journal_osd_uuid(args.dev) path = os.path.join('/dev/disk/by-partuuid/', osd_uuid.lower()) (cluster, osd_id) = mount_activate( dev=path, activate_key_template=args.activate_key_template, init=args.mark_init, ) start_daemon( cluster=cluster, osd_id=osd_id, ) finally: activate_lock.release() # noqa ########################### def main_activate_all(args): dir = '/dev/disk/by-parttypeuuid' LOG.debug('Scanning %s', dir) if not os.path.exists(dir): return err = False for name in os.listdir(dir): if name.find('.') < 0: continue (tag, uuid) = name.split('.') if tag == OSD_UUID or tag == DMCRYPT_OSD_UUID: if tag == DMCRYPT_OSD_UUID: path = os.path.join('/dev/mapper', uuid) else: path = os.path.join(dir, name) LOG.info('Activating %s', path) activate_lock.acquire() # noqa try: (cluster, osd_id) = mount_activate( dev=path, activate_key_template=args.activate_key_template, init=args.mark_init, ) start_daemon( cluster=cluster, osd_id=osd_id, ) except Exception as e: print >> sys.stderr, '{prog}: {msg}'.format( prog=args.prog, msg=e, ) err = True finally: activate_lock.release() # noqa if err: raise Error('One or more partitions failed to activate') ########################### def is_swap(dev): dev = os.path.realpath(dev) with file('/proc/swaps', 'rb') as proc_swaps: for line in proc_swaps.readlines()[1:]: fields = line.split() if len(fields) < 3: continue swaps_dev = fields[0] if swaps_dev.startswith('/') and os.path.exists(swaps_dev): swaps_dev = os.path.realpath(swaps_dev) if swaps_dev == dev: return True return False def get_oneliner(base, name): path = os.path.join(base, name) if os.path.isfile(path): with open(path, 'r') as _file: return _file.readline().rstrip() return None def get_dev_fs(dev): fscheck, _ = command( [ 'blkid', '-s', 'TYPE', dev, ], ) if 'TYPE' in fscheck: fstype = fscheck.split()[1].split('"')[1] return fstype else: return None def split_dev_base_partnum(dev): if 'loop' in dev or 'cciss' in dev or 'nvme' in dev: return re.match('(.*\d+)p(\d+)', dev).group(1, 2) else: return re.match('(\D+)(\d+)', dev).group(1, 2) def get_partition_type(part): """ Get the GPT partition type UUID. If we have an old blkid and can't get it that way, use sgdisk and use the description instead (and hope dmcrypt isn't being used). """ blkid, _ = command( [ 'blkid', '-p', '-o', 'udev', part, ] ) saw_part_entry = False for line in blkid.splitlines(): (key, value) = line.split('=') if key == 'ID_PART_ENTRY_TYPE': return value if key == 'ID_PART_ENTRY_SCHEME': table_type = value if key.startswith('ID_PART_ENTRY_'): saw_part_entry = True # hmm, is it in fact GPT? table_type = None base = get_partition_base(part) blkid, _ = command( [ 'blkid', '-p', '-o', 'udev', base ] ) for line in blkid.splitlines(): (key, value) = line.split('=') if key == 'ID_PART_TABLE_TYPE': table_type = value if table_type != 'gpt': return None # not even GPT if saw_part_entry: return None # GPT, and blkid appears to be new, so we're done. # bah, fall back to sgdisk. if 'blkid' not in warned_about: LOG.warning('Old blkid does not support ID_PART_ENTRY_* fields, trying sgdisk; may not correctly identify ceph volumes with dmcrypt') warned_about['blkid'] = True (base, partnum) = split_dev_base_partnum(part) sgdisk, _ = command( [ 'sgdisk', '-p', base, ] ) for line in sgdisk.splitlines(): m = re.search('\s+(\d+)\s+\d+\s+\d+\s+\S+ \S+B\s+\S+\s+(.*)', line) if m is not None: num = m.group(1) if num != partnum: continue desc = m.group(2) # assume unencrypted ... blkid has failed us :( if desc == 'ceph data': return OSD_UUID if desc == 'ceph journal': return JOURNAL_UUID return None def get_partition_uuid(dev): (base, partnum) = split_dev_base_partnum(dev) out, _ = command(['sgdisk', '-i', partnum, base]) for line in out.splitlines(): m = re.match('Partition unique GUID: (\S+)', line) if m: return m.group(1).lower() return None def more_osd_info(path, uuid_map): desc = [] ceph_fsid = get_oneliner(path, 'ceph_fsid') if ceph_fsid: cluster = find_cluster_by_uuid(ceph_fsid) if cluster: desc.append('cluster ' + cluster) else: desc.append('unknown cluster ' + ceph_fsid) who = get_oneliner(path, 'whoami') if who: desc.append('osd.%s' % who) journal_uuid = get_oneliner(path, 'journal_uuid') if journal_uuid: journal_uuid = journal_uuid.lower() if journal_uuid in uuid_map: desc.append('journal %s' % uuid_map[journal_uuid]) return desc def list_dev_osd(dev, uuid_map): path = is_mounted(dev) fs_type = get_dev_fs(dev) desc = [] if path: desc.append('active') desc.extend(more_osd_info(path, uuid_map)) elif fs_type: try: tpath = mount(dev=dev, fstype=fs_type, options='') if tpath: try: magic = get_oneliner(tpath, 'magic') if magic is not None: desc.append('prepared') desc.extend(more_osd_info(tpath, uuid_map)) finally: unmount(tpath) except MountError: pass return desc def list_dev(dev, uuid_map, journal_map): ptype = 'unknown' prefix = '' if is_partition(dev): ptype = get_partition_type(dev) prefix = ' ' desc = [] if ptype == OSD_UUID: desc = list_dev_osd(dev, uuid_map) if desc: desc = ['ceph data'] + desc else: desc = ['ceph data', 'unprepared'] elif ptype == DMCRYPT_OSD_UUID: holders = is_held(dev) if not holders: desc = ['ceph data (dmcrypt)', 'not currently mapped'] elif len(holders) == 1: holder = '/dev/' + holders[0] fs_desc = list_dev_osd(holder, uuid_map) desc = ['ceph data (dmcrypt %s)' % holder] + fs_desc else: desc = ['ceph data (dmcrypt)', 'holders: ' + ','.join(holders)] elif ptype == JOURNAL_UUID: desc.append('ceph journal') part_uuid = get_partition_uuid(dev) if part_uuid and part_uuid in journal_map: desc.append('for %s' % journal_map[part_uuid]) elif ptype == DMCRYPT_JOURNAL_UUID: holders = is_held(dev) if len(holders) == 1: desc = ['ceph journal (dmcrypt /dev/%s)' % holders[0]] else: desc = ['ceph journal (dmcrypt)'] part_uuid = get_partition_uuid(dev) if part_uuid and part_uuid in journal_map: desc.append('for %s' % journal_map[part_uuid]) else: path = is_mounted(dev) fs_type = get_dev_fs(dev) if is_swap(dev): desc.append('swap') else: desc.append('other') if fs_type: desc.append(fs_type) elif ptype: desc.append(ptype) if path: desc.append('mounted on %s' % path) print '%s%s %s' % (prefix, dev, ', '.join(desc)) def main_list(args): partmap = list_all_partitions() uuid_map = {} journal_map = {} for base, parts in sorted(partmap.iteritems()): for p in parts: dev = get_dev_path(p) part_uuid = get_partition_uuid(dev) if part_uuid: uuid_map[part_uuid] = dev ptype = get_partition_type(dev) if ptype == OSD_UUID: fs_type = get_dev_fs(dev) if fs_type is not None: try: tpath = mount(dev=dev, fstype=fs_type, options='') try: journal_uuid = get_oneliner(tpath, 'journal_uuid') if journal_uuid: journal_map[journal_uuid.lower()] = dev finally: unmount(tpath) except MountError: pass if ptype == DMCRYPT_OSD_UUID: holders = is_held(dev) if len(holders) == 1: holder = '/dev/' + holders[0] fs_type = get_dev_fs(holder) if fs_type is not None: try: tpath = mount(dev=holder, fstype=fs_type, options='') try: journal_uuid = get_oneliner(tpath, 'journal_uuid') if journal_uuid: journal_map[journal_uuid.lower()] = dev finally: unmount(tpath) except MountError: pass for base, parts in sorted(partmap.iteritems()): if parts: print '%s :' % get_dev_path(base) for p in sorted(parts): list_dev(get_dev_path(p), uuid_map, journal_map) else: list_dev(get_dev_path(base), uuid_map, journal_map) ########################### # # Mark devices that we want to suppress activates on with a # file like # # /var/lib/ceph/tmp/suppress-activate.sdb # # where the last bit is the sanitized device name (/dev/X without the # /dev/ prefix) and the is_suppress() check matches a prefix. That # means suppressing sdb will stop activate on sdb1, sdb2, etc. # def is_suppressed(path): disk = os.path.realpath(path) try: if not disk.startswith('/dev/') or not stat.S_ISBLK(os.lstat(path).st_mode): return False base = get_dev_name(disk) while len(base): if os.path.exists(SUPPRESS_PREFIX + base): # noqa return True base = base[:-1] except: return False def set_suppress(path): disk = os.path.realpath(path) if not os.path.exists(disk): raise Error('does not exist', path) if not stat.S_ISBLK(os.lstat(path).st_mode): raise Error('not a block device', path) base = get_dev_name(disk) with file(SUPPRESS_PREFIX + base, 'w') as f: # noqa pass LOG.info('set suppress flag on %s', base) def unset_suppress(path): disk = os.path.realpath(path) if not os.path.exists(disk): raise Error('does not exist', path) if not stat.S_ISBLK(os.lstat(path).st_mode): raise Error('not a block device', path) assert disk.startswith('/dev/') base = get_dev_name(disk) fn = SUPPRESS_PREFIX + base # noqa if not os.path.exists(fn): raise Error('not marked as suppressed', path) try: os.unlink(fn) LOG.info('unset suppress flag on %s', base) except OSError as e: raise Error('failed to unsuppress', e) def main_suppress(args): set_suppress(args.path) def main_unsuppress(args): unset_suppress(args.path) def main_zap(args): for dev in args.dev: zap(dev) ########################### def setup_statedir(dir): # XXX The following use of globals makes linting # really hard. Global state in Python is iffy and # should be avoided. global STATEDIR STATEDIR = dir if not os.path.exists(STATEDIR): os.mkdir(STATEDIR) if not os.path.exists(STATEDIR + "/tmp"): os.mkdir(STATEDIR + "/tmp") global prepare_lock prepare_lock = filelock(STATEDIR + '/tmp/ceph-disk.prepare.lock') global activate_lock activate_lock = filelock(STATEDIR + '/tmp/ceph-disk.activate.lock') global SUPPRESS_PREFIX SUPPRESS_PREFIX = STATEDIR + '/tmp/suppress-activate.' def setup_sysconfdir(dir): global SYSCONFDIR SYSCONFDIR = dir def parse_args(): parser = argparse.ArgumentParser( 'ceph-disk', ) parser.add_argument( '-v', '--verbose', action='store_true', default=None, help='be more verbose', ) parser.add_argument( '--prepend-to-path', metavar='PATH', default='/usr/bin', help='prepend PATH to $PATH for backward compatibility (default /usr/bin)', ) parser.add_argument( '--statedir', metavar='PATH', default='/var/lib/ceph', help='directory in which ceph state is preserved (default /var/lib/ceph)', ) parser.add_argument( '--sysconfdir', metavar='PATH', default='/etc/ceph', help='directory in which ceph configuration files are found (default /etc/ceph)', ) parser.set_defaults( # we want to hold on to this, for later prog=parser.prog, cluster='ceph', ) subparsers = parser.add_subparsers( title='subcommands', description='valid subcommands', help='sub-command help', ) prepare_parser = subparsers.add_parser('prepare', help='Prepare a directory or disk for a Ceph OSD') prepare_parser.add_argument( '--cluster', metavar='NAME', help='cluster name to assign this disk to', ) prepare_parser.add_argument( '--cluster-uuid', metavar='UUID', help='cluster uuid to assign this disk to', ) prepare_parser.add_argument( '--osd-uuid', metavar='UUID', help='unique OSD uuid to assign this disk to', ) prepare_parser.add_argument( '--journal-uuid', metavar='UUID', help='unique uuid to assign to the journal', ) prepare_parser.add_argument( '--fs-type', help='file system type to use (e.g. "ext4")', ) prepare_parser.add_argument( '--zap-disk', action='store_true', default=None, help='destroy the partition table (and content) of a disk', ) prepare_parser.add_argument( '--data-dir', action='store_true', default=None, help='verify that DATA is a dir', ) prepare_parser.add_argument( '--data-dev', action='store_true', default=None, help='verify that DATA is a block device', ) prepare_parser.add_argument( '--journal-file', action='store_true', default=None, help='verify that JOURNAL is a file', ) prepare_parser.add_argument( '--journal-dev', action='store_true', default=None, help='verify that JOURNAL is a block device', ) prepare_parser.add_argument( '--dmcrypt', action='store_true', default=None, help='encrypt DATA and/or JOURNAL devices with dm-crypt', ) prepare_parser.add_argument( '--dmcrypt-key-dir', metavar='KEYDIR', default='/etc/ceph/dmcrypt-keys', help='directory where dm-crypt keys are stored', ) prepare_parser.add_argument( 'data', metavar='DATA', help='path to OSD data (a disk block device or directory)', ) prepare_parser.add_argument( 'journal', metavar='JOURNAL', nargs='?', help=('path to OSD journal disk block device;' + ' leave out to store journal in file'), ) prepare_parser.set_defaults( func=main_prepare, ) activate_parser = subparsers.add_parser('activate', help='Activate a Ceph OSD') activate_parser.add_argument( '--mount', action='store_true', default=None, help='mount a block device [deprecated, ignored]', ) activate_parser.add_argument( '--activate-key', metavar='PATH', help='bootstrap-osd keyring path template (%(default)s)', dest='activate_key_template', ) activate_parser.add_argument( '--mark-init', metavar='INITSYSTEM', help='init system to manage this dir', default='auto', choices=INIT_SYSTEMS, ) activate_parser.add_argument( 'path', metavar='PATH', nargs='?', help='path to block device or directory', ) activate_parser.set_defaults( activate_key_template='{statedir}/bootstrap-osd/{cluster}.keyring', func=main_activate, ) activate_journal_parser = subparsers.add_parser('activate-journal', help='Activate an OSD via its journal device') activate_journal_parser.add_argument( 'dev', metavar='DEV', help='path to journal block device', ) activate_journal_parser.add_argument( '--activate-key', metavar='PATH', help='bootstrap-osd keyring path template (%(default)s)', dest='activate_key_template', ) activate_journal_parser.add_argument( '--mark-init', metavar='INITSYSTEM', help='init system to manage this dir', default='auto', choices=INIT_SYSTEMS, ) activate_journal_parser.set_defaults( activate_key_template='{statedir}/bootstrap-osd/{cluster}.keyring', func=main_activate_journal, ) activate_all_parser = subparsers.add_parser('activate-all', help='Activate all tagged OSD partitions') activate_all_parser.add_argument( '--activate-key', metavar='PATH', help='bootstrap-osd keyring path template (%(default)s)', dest='activate_key_template', ) activate_all_parser.add_argument( '--mark-init', metavar='INITSYSTEM', help='init system to manage this dir', default='auto', choices=INIT_SYSTEMS, ) activate_all_parser.set_defaults( activate_key_template='{statedir}/bootstrap-osd/{cluster}.keyring', func=main_activate_all, ) list_parser = subparsers.add_parser('list', help='List disks, partitions, and Ceph OSDs') list_parser.set_defaults( func=main_list, ) suppress_parser = subparsers.add_parser('suppress-activate', help='Suppress activate on a device (prefix)') suppress_parser.add_argument( 'path', metavar='PATH', nargs='?', help='path to block device or directory', ) suppress_parser.set_defaults( func=main_suppress, ) unsuppress_parser = subparsers.add_parser('unsuppress-activate', help='Stop suppressing activate on a device (prefix)') unsuppress_parser.add_argument( 'path', metavar='PATH', nargs='?', help='path to block device or directory', ) unsuppress_parser.set_defaults( func=main_unsuppress, ) zap_parser = subparsers.add_parser('zap', help='Zap/erase/destroy a device\'s partition table (and contents)') zap_parser.add_argument( 'dev', metavar='DEV', nargs='+', help='path to block device', ) zap_parser.set_defaults( func=main_zap, ) args = parser.parse_args() return args def main(): args = parse_args() loglevel = logging.WARNING if args.verbose: loglevel = logging.DEBUG logging.basicConfig( level=loglevel, ) if args.prepend_to_path != '': path = os.environ.get('PATH', os.defpath) os.environ['PATH'] = args.prepend_to_path + ":" + path setup_statedir(args.statedir) setup_sysconfdir(args.sysconfdir) try: args.func(args) except Error as e: raise SystemExit( '{prog}: {msg}'.format( prog=args.prog, msg=e, ) ) except CephDiskException as error: exc_name = error.__class__.__name__ raise SystemExit( '{prog} {exc_name}: {msg}'.format( prog=args.prog, exc_name=exc_name, msg=error, ) ) if __name__ == '__main__': main() warned_about = {} ceph-0.80.11/src/ceph-clsinfo0000775000175100017510000000270612623076744017771 0ustar jenkins-buildjenkins-build#!/bin/sh show_name=0 show_ver=0 show_arch=0 show_default=1 fname="" usage="usage: $0 [option]... \n" usage=$usage"options:\n" usage=$usage"\t-n, --name\n" usage=$usage"\t-v, --ver\n" usage=$usage"\t-a, --arch\n" usage_exit() { printf "$usage" exit 1 } err_exit() { echo "Error: $*" exit 1 } while [ $# -ge 1 ]; do case $1 in -n | --name ) show_name=1 show_default=0 ;; -v | --ver ) show_ver=1 show_default=0 ;; -a | --arch ) show_arch=1 show_default=0 ;; * ) [ -n "$fname" ] && usage_exit fname=$1 ;; esac shift done [ -z "$fname" ] && usage_exit if [ $show_default -eq 1 ]; then show_name=1 show_ver=1 show_arch=1 fi [ -e "$fname" ] || err_exit "File not found: ${fname}" if [ $show_name -eq 1 ]; then raw_name=`nm $fname | grep __cls_name__` name=`echo $raw_name | sed 's/.*cls_name__//g'` [ -z "$name" ] && err_exit "Could not detect class name" s=$name c=" " fi if [ $show_ver -eq 1 ]; then raw_ver=`nm $fname | grep __cls_ver__` ver=`echo $raw_ver | sed 's/.*cls_ver__//g; s/_/./g'` [ -z "$ver" ] && err_exit "Could not detect class version" s=$s$c$ver c=" " fi if [ $show_arch -eq 1 ]; then raw_arch=`readelf -h $fname | grep Machine` arch="" [ `echo $raw_arch | grep -c 386` -gt 0 ] && arch="i386" [ `echo $raw_arch | grep -c 86-64` -gt 0 ] && arch="x86-64" [ -z "$arch" ] && err_exit "unknown file architecture" s=$s$c$arch c=" " fi echo $s ceph-0.80.11/src/global/0000775000175100017510000000000012623077035016716 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/global/global_context.cc0000664000175100017510000000112712623076744022240 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_context.h" #include "global/global_context.h" /* * Global variables for use from process context. */ CephContext *g_ceph_context = NULL; md_config_t *g_conf = NULL; ceph-0.80.11/src/global/pidfile.cc0000664000175100017510000000432212623076744020650 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/debug.h" #include "common/errno.h" #include "common/safe_io.h" #include "global/pidfile.h" #include #include #include #include #include #if defined(__FreeBSD__) #include #endif #include "include/compat.h" #define dout_prefix *_dout static char pid_file[PATH_MAX] = ""; int pidfile_write(const md_config_t *conf) { int ret, fd; if (conf->pid_file.empty()) { return pidfile_remove(); } snprintf(pid_file, PATH_MAX, "%s", conf->pid_file.c_str()); fd = TEMP_FAILURE_RETRY(::open(pid_file, O_CREAT|O_TRUNC|O_WRONLY, 0644)); if (fd < 0) { int err = errno; derr << "write_pid_file: failed to open pid file '" << pid_file << "': " << cpp_strerror(err) << dendl; return err; } char buf[20]; int len = snprintf(buf, sizeof(buf), "%d\n", getpid()); ret = safe_write(fd, buf, len); if (ret < 0) { derr << "write_pid_file: failed to write to pid file '" << pid_file << "': " << cpp_strerror(ret) << dendl; VOID_TEMP_FAILURE_RETRY(::close(fd)); return ret; } if (TEMP_FAILURE_RETRY(::close(fd))) { ret = errno; derr << "SimpleMessenger::write_pid_file: failed to close to pid file '" << pid_file << "': " << cpp_strerror(ret) << dendl; return -ret; } return 0; } int pidfile_remove(void) { if (!pid_file[0]) return 0; // only remove it if it has OUR pid in it! int fd = TEMP_FAILURE_RETRY(::open(pid_file, O_RDONLY)); if (fd < 0) return -errno; char buf[32]; memset(buf, 0, sizeof(buf)); ssize_t res = safe_read(fd, buf, sizeof(buf)); VOID_TEMP_FAILURE_RETRY(::close(fd)); if (res < 0) return res; int a = atoi(buf); if (a != getpid()) return -EDOM; res = ::unlink(pid_file); if (res) return res; pid_file[0] = '\0'; return 0; } ceph-0.80.11/src/global/global_init.h0000664000175100017510000000521012623076744021356 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_GLOBAL_INIT_H #define CEPH_COMMON_GLOBAL_INIT_H #include #include #include #include #include "common/code_environment.h" #include "common/common_init.h" class CephContext; /* * global_init is the first initialization function that * daemons and utility programs need to call. It takes care of a lot of * initialization, including setting up g_ceph_context. */ void global_init(std::vector < const char * > *alt_def_args, std::vector < const char* >& args, uint32_t module_type, code_environment_t code_env, int flags); // just the first half; enough to get config parsed but doesn't start up the // cct or log. void global_pre_init(std::vector < const char * > *alt_def_args, std::vector < const char* >& args, uint32_t module_type, code_environment_t code_env, int flags); /* * perform all of the steps that global_init_daemonize performs just prior * to actually forking (via daemon(3)). return 0 if we are going to proceed * with the fork, or -1 otherwise. */ int global_init_prefork(CephContext *cct, int flags); /* * perform all the steps that global_init_daemonize performs just after * the fork, except closing stderr, which we'll do later on. */ void global_init_postfork_start(CephContext *cct); /* * close stderr, thus completing the postfork. */ void global_init_postfork_finish(CephContext *cct, int flags); /* * global_init_daemonize handles daemonizing a process. * * If this is called, it *must* be called before common_init_finish. * Note that this is equivalent to calling _prefork(), daemon(), and * _postfork. */ void global_init_daemonize(CephContext *cct, int flags); /* * global_init_chdir changes the process directory. * * If this is called, it *must* be called before common_init_finish */ void global_init_chdir(const CephContext *cct); /* * Explicitly shut down stderr. Usually, you don't need to do * this, because global_init_daemonize will do it for you. However, in some * rare cases you need to call this explicitly. * * If this is called, it *must* be called before common_init_finish */ int global_init_shutdown_stderr(CephContext *cct); /** * print daemon startup banner/warning */ void global_print_banner(void); #endif ceph-0.80.11/src/global/global_init.cc0000664000175100017510000001726312623076744021527 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/Thread.h" #include "common/ceph_argparse.h" #include "common/code_environment.h" #include "common/common_init.h" #include "common/config.h" #include "common/debug.h" #include "common/errno.h" #include "common/safe_io.h" #include "common/signal.h" #include "common/version.h" #include "global/global_context.h" #include "global/global_init.h" #include "global/pidfile.h" #include "global/signal_handler.h" #include "include/compat.h" #include "include/color.h" #include #include #define dout_subsys ceph_subsys_ static void global_init_set_globals(CephContext *cct) { g_ceph_context = cct; g_conf = cct->_conf; } static void output_ceph_version() { char buf[1024]; snprintf(buf, sizeof(buf), "%s, process %s, pid %d", pretty_version_to_str().c_str(), get_process_name_cpp().c_str(), getpid()); generic_dout(0) << buf << dendl; } static const char* c_str_or_null(const std::string &str) { if (str.empty()) return NULL; return str.c_str(); } void global_pre_init(std::vector < const char * > *alt_def_args, std::vector < const char* >& args, uint32_t module_type, code_environment_t code_env, int flags) { // You can only call global_init once. assert(!g_ceph_context); std::string conf_file_list; std::string cluster = "ceph"; CephInitParameters iparams = ceph_argparse_early_args(args, module_type, flags, &cluster, &conf_file_list); CephContext *cct = common_preinit(iparams, code_env, flags); cct->_conf->cluster = cluster; global_init_set_globals(cct); md_config_t *conf = cct->_conf; if (alt_def_args) conf->parse_argv(*alt_def_args); // alternative default args std::deque parse_errors; int ret = conf->parse_config_files(c_str_or_null(conf_file_list), &parse_errors, &cerr, flags); if (ret == -EDOM) { dout_emergency("global_init: error parsing config file.\n"); _exit(1); } else if (ret == -EINVAL) { if (!(flags & CINIT_FLAG_NO_DEFAULT_CONFIG_FILE)) { if (conf_file_list.length()) { ostringstream oss; oss << "global_init: unable to open config file from search list " << conf_file_list << "\n"; dout_emergency(oss.str()); _exit(1); } else { derr <<"did not load config file, using default settings." << dendl; } } } else if (ret) { dout_emergency("global_init: error reading config file.\n"); _exit(1); } conf->parse_env(); // environment variables override conf->parse_argv(args); // argv override // Expand metavariables. Invoke configuration observers. conf->apply_changes(NULL); // Now we're ready to complain about config file parse errors complain_about_parse_errors(cct, &parse_errors); } void global_init(std::vector < const char * > *alt_def_args, std::vector < const char* >& args, uint32_t module_type, code_environment_t code_env, int flags) { global_pre_init(alt_def_args, args, module_type, code_env, flags); g_lockdep = g_ceph_context->_conf->lockdep; // signal stuff int siglist[] = { SIGPIPE, 0 }; block_signals(siglist, NULL); if (g_conf->fatal_signal_handlers) install_standard_sighandlers(); if (g_conf->log_flush_on_exit) g_ceph_context->_log->set_flush_on_exit(); if (g_conf->run_dir.length() && code_env == CODE_ENVIRONMENT_DAEMON && !(flags & CINIT_FLAG_NO_DAEMON_ACTIONS)) { int r = ::mkdir(g_conf->run_dir.c_str(), 0755); if (r < 0 && errno != EEXIST) { r = -errno; derr << "warning: unable to create " << g_conf->run_dir << ": " << cpp_strerror(r) << dendl; } } if (g_lockdep) { lockdep_register_ceph_context(g_ceph_context); } register_assert_context(g_ceph_context); // call all observers now. this has the side-effect of configuring // and opening the log file immediately. g_conf->call_all_observers(); if (code_env == CODE_ENVIRONMENT_DAEMON && !(flags & CINIT_FLAG_NO_DAEMON_ACTIONS)) output_ceph_version(); } void global_print_banner(void) { output_ceph_version(); } static void pidfile_remove_void(void) { pidfile_remove(); } int global_init_prefork(CephContext *cct, int flags) { if (g_code_env != CODE_ENVIRONMENT_DAEMON) return -1; const md_config_t *conf = cct->_conf; if (!conf->daemonize) { if (atexit(pidfile_remove_void)) { derr << "global_init_daemonize: failed to set pidfile_remove function " << "to run at exit." << dendl; } pidfile_write(g_conf); return -1; } // stop log thread g_ceph_context->_log->flush(); g_ceph_context->_log->stop(); return 0; } void global_init_daemonize(CephContext *cct, int flags) { if (global_init_prefork(cct, flags) < 0) return; int ret = daemon(1, 1); if (ret) { ret = errno; derr << "global_init_daemonize: BUG: daemon error: " << cpp_strerror(ret) << dendl; exit(1); } global_init_postfork_start(cct); global_init_postfork_finish(cct, flags); } void global_init_postfork_start(CephContext *cct) { // restart log thread g_ceph_context->_log->start(); if (atexit(pidfile_remove_void)) { derr << "global_init_daemonize: failed to set pidfile_remove function " << "to run at exit." << dendl; } /* This is the old trick where we make file descriptors 0, 1, and possibly 2 * point to /dev/null. * * We have to do this because otherwise some arbitrary call to open() later * in the program might get back one of these file descriptors. It's hard to * guarantee that nobody ever writes to stdout, even though they're not * supposed to. */ VOID_TEMP_FAILURE_RETRY(close(STDIN_FILENO)); if (open("/dev/null", O_RDONLY) < 0) { int err = errno; derr << "global_init_daemonize: open(/dev/null) failed: error " << err << dendl; exit(1); } VOID_TEMP_FAILURE_RETRY(close(STDOUT_FILENO)); if (open("/dev/null", O_RDONLY) < 0) { int err = errno; derr << "global_init_daemonize: open(/dev/null) failed: error " << err << dendl; exit(1); } pidfile_write(g_conf); } void global_init_postfork_finish(CephContext *cct, int flags) { /* We only close stderr once the caller decides the daemonization * process is finished. This way we can allow error messages to be * propagated in a manner that the user is able to see. */ if (!(flags & CINIT_FLAG_NO_CLOSE_STDERR)) { int ret = global_init_shutdown_stderr(cct); if (ret) { derr << "global_init_daemonize: global_init_shutdown_stderr failed with " << "error code " << ret << dendl; exit(1); } } ldout(cct, 1) << "finished global_init_daemonize" << dendl; } void global_init_chdir(const CephContext *cct) { const md_config_t *conf = cct->_conf; if (conf->chdir.empty()) return; if (::chdir(conf->chdir.c_str())) { int err = errno; derr << "global_init_chdir: failed to chdir to directory: '" << conf->chdir << "': " << cpp_strerror(err) << dendl; } } /* Map stderr to /dev/null. This isn't really re-entrant; we rely on the old unix * behavior that the file descriptor that gets assigned is the lowest * available one. */ int global_init_shutdown_stderr(CephContext *cct) { VOID_TEMP_FAILURE_RETRY(close(STDERR_FILENO)); if (open("/dev/null", O_RDONLY) < 0) { int err = errno; derr << "global_init_shutdown_stderr: open(/dev/null) failed: error " << err << dendl; return 1; } cct->_log->set_stderr_level(-1, -1); return 0; } ceph-0.80.11/src/global/signal_handler.h0000664000175100017510000000250312623076744022047 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_GLOBAL_SIGNAL_HANDLER_H #define CEPH_GLOBAL_SIGNAL_HANDLER_H #include #include typedef void (*signal_handler_t)(int); void install_sighandler(int signum, signal_handler_t handler, int flags); // handles SIGHUP void sighup_handler(int signum); // Install the standard Ceph signal handlers void install_standard_sighandlers(void); /// initialize async signal handler framework void init_async_signal_handler(); /// shutdown async signal handler framework void shutdown_async_signal_handler(); /// queue an async signal void queue_async_signal(int signum); /// install a safe, async, callback for the given signal void register_async_signal_handler(int signum, signal_handler_t handler); void register_async_signal_handler_oneshot(int signum, signal_handler_t handler); /// uninstall a safe async signal callback void unregister_async_signal_handler(int signum, signal_handler_t handler); #endif ceph-0.80.11/src/global/pidfile.h0000664000175100017510000000143012623076744020507 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMMON_PIDFILE_H #define CEPH_COMMON_PIDFILE_H struct md_config_t; // Write a pidfile with the current pid, using the configuration in the // provided conf structure. int pidfile_write(const md_config_t *conf); // Remove the pid file that was previously written by pidfile_write. // This is safe to call in a signal handler context. int pidfile_remove(void); #endif ceph-0.80.11/src/global/Makefile.am0000664000175100017510000000047112623076744020762 0ustar jenkins-buildjenkins-buildlibglobal_la_SOURCES = \ global/global_context.cc \ global/global_init.cc \ global/pidfile.cc \ global/signal_handler.cc libglobal_la_LIBADD = $(LIBCOMMON) noinst_LTLIBRARIES += libglobal.la noinst_HEADERS += \ global/pidfile.h \ global/global_init.h \ global/global_context.h \ global/signal_handler.h ceph-0.80.11/src/global/global_context.h0000664000175100017510000000117612623076744022106 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_GLOBAL_CONTEXT_H #define CEPH_GLOBAL_CONTEXT_H #include "common/ceph_context.h" #include #include struct md_config_t; extern CephContext *g_ceph_context; extern md_config_t *g_conf; #endif ceph-0.80.11/src/global/signal_handler.cc0000664000175100017510000002121012623076744022201 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/BackTrace.h" #include "common/perf_counters.h" #include "common/config.h" #include "common/debug.h" #include "global/pidfile.h" #include "global/signal_handler.h" #include #include #include #include #include #include void install_sighandler(int signum, signal_handler_t handler, int flags) { int ret; struct sigaction oldact; struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = flags; ret = sigaction(signum, &act, &oldact); if (ret != 0) { char buf[1024]; snprintf(buf, sizeof(buf), "install_sighandler: sigaction returned " "%d when trying to install a signal handler for %s\n", ret, sys_siglist[signum]); dout_emergency(buf); exit(1); } } void sighup_handler(int signum) { g_ceph_context->reopen_logs(); } static void reraise_fatal(int signum) { // Use default handler to dump core int ret = raise(signum); // Normally, we won't get here. If we do, something is very weird. char buf[1024]; if (ret) { snprintf(buf, sizeof(buf), "reraise_fatal: failed to re-raise " "signal %d\n", signum); dout_emergency(buf); } else { snprintf(buf, sizeof(buf), "reraise_fatal: default handler for " "signal %d didn't terminate the process?\n", signum); dout_emergency(buf); } exit(1); } static void handle_fatal_signal(int signum) { // This code may itself trigger a SIGSEGV if the heap is corrupt. In that // case, SA_RESETHAND specifies that the default signal handler-- // presumably dump core-- will handle it. char buf[1024]; snprintf(buf, sizeof(buf), "*** Caught signal (%s) **\n " "in thread %llx\n", sys_siglist[signum], (unsigned long long)pthread_self()); dout_emergency(buf); pidfile_remove(); // TODO: don't use an ostringstream here. It could call malloc(), which we // don't want inside a signal handler. // Also fix the backtrace code not to allocate memory. BackTrace bt(0); ostringstream oss; bt.print(oss); dout_emergency(oss.str()); // dump to log. this uses the heap extensively, but we're better // off trying than not. derr << buf << std::endl; bt.print(*_dout); *_dout << " NOTE: a copy of the executable, or `objdump -rdS ` " << "is needed to interpret this.\n" << dendl; g_ceph_context->_log->dump_recent(); reraise_fatal(signum); } void install_standard_sighandlers(void) { install_sighandler(SIGSEGV, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGABRT, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGBUS, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGILL, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGFPE, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGXCPU, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGXFSZ, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); install_sighandler(SIGSYS, handle_fatal_signal, SA_RESETHAND | SA_NODEFER); } /// --- safe handler --- #include "common/Thread.h" #include /** * safe async signal handler / dispatcher * * This is an async unix signal handler based on the design from * * http://evbergen.home.xs4all.nl/unix-signals.html * * Features: * - no unsafe work is done in the signal handler itself * - callbacks are called from a regular thread * - signals are not lost, unless multiple instances of the same signal * are sent twice in quick succession. */ struct SignalHandler : public Thread { /// to kick the thread, for shutdown, new handlers, etc. int pipefd[2]; // write to [1], read from [0] /// to signal shutdown bool stop; /// for an individual signal struct safe_handler { int pipefd[2]; // write to [1], read from [0] signal_handler_t handler; }; /// all handlers safe_handler *handlers[32]; /// to protect the handlers array Mutex lock; SignalHandler() : stop(false), lock("SignalHandler::lock") { for (unsigned i = 0; i < 32; i++) handlers[i] = NULL; // create signal pipe int r = pipe(pipefd); assert(r == 0); r = fcntl(pipefd[0], F_SETFL, O_NONBLOCK); assert(r == 0); // create thread create(); } ~SignalHandler() { shutdown(); } void signal_thread() { int r = write(pipefd[1], "\0", 1); assert(r == 1); } void shutdown() { stop = true; signal_thread(); join(); } // thread entry point void *entry() { while (!stop) { // build fd list struct pollfd fds[33]; lock.Lock(); int num_fds = 0; fds[num_fds].fd = pipefd[0]; fds[num_fds].events = POLLIN | POLLERR; fds[num_fds].revents = 0; ++num_fds; for (unsigned i=0; i<32; i++) { if (handlers[i]) { fds[num_fds].fd = handlers[i]->pipefd[0]; fds[num_fds].events = POLLIN | POLLERR; fds[num_fds].revents = 0; ++num_fds; } } lock.Unlock(); // wait for data on any of those pipes int r = poll(fds, num_fds, -1); if (stop) break; if (r > 0) { char v; // consume byte from signal socket, if any. r = read(pipefd[0], &v, 1); lock.Lock(); for (unsigned signum=0; signum<32; signum++) { if (handlers[signum]) { r = read(handlers[signum]->pipefd[0], &v, 1); if (r == 1) { handlers[signum]->handler(signum); } } } lock.Unlock(); } else { //cout << "no data, got r=" << r << " errno=" << errno << std::endl; } } return NULL; } void queue_signal(int signum) { // If this signal handler is registered, the callback must be // defined. We can do this without the lock because we will never // have the signal handler defined without the handlers entry also // being filled in. assert(handlers[signum]); int r = write(handlers[signum]->pipefd[1], " ", 1); assert(r == 1); } void register_handler(int signum, signal_handler_t handler, bool oneshot); void unregister_handler(int signum, signal_handler_t handler); }; static SignalHandler *g_signal_handler = NULL; static void handler_hook(int signum) { g_signal_handler->queue_signal(signum); } void SignalHandler::register_handler(int signum, signal_handler_t handler, bool oneshot) { int r; assert(signum >= 0 && signum < 32); safe_handler *h = new safe_handler; r = pipe(h->pipefd); assert(r == 0); r = fcntl(h->pipefd[0], F_SETFL, O_NONBLOCK); assert(r == 0); h->handler = handler; lock.Lock(); handlers[signum] = h; lock.Unlock(); // signal thread so that it sees our new handler signal_thread(); // install our handler struct sigaction oldact; struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = handler_hook; sigfillset(&act.sa_mask); // mask all signals in the handler act.sa_flags = oneshot ? SA_RESETHAND : 0; int ret = sigaction(signum, &act, &oldact); assert(ret == 0); } void SignalHandler::unregister_handler(int signum, signal_handler_t handler) { assert(signum >= 0 && signum < 32); safe_handler *h = handlers[signum]; assert(h); assert(h->handler == handler); // restore to default signal(signum, SIG_DFL); // _then_ remove our handlers entry lock.Lock(); handlers[signum] = NULL; lock.Unlock(); // this will wake up select() so that worker thread sees our handler is gone close(h->pipefd[0]); close(h->pipefd[1]); delete h; } // ------- void init_async_signal_handler() { assert(!g_signal_handler); g_signal_handler = new SignalHandler; } void shutdown_async_signal_handler() { assert(g_signal_handler); delete g_signal_handler; g_signal_handler = NULL; } void queue_async_signal(int signum) { assert(g_signal_handler); g_signal_handler->queue_signal(signum); } void register_async_signal_handler(int signum, signal_handler_t handler) { assert(g_signal_handler); g_signal_handler->register_handler(signum, handler, false); } void register_async_signal_handler_oneshot(int signum, signal_handler_t handler) { assert(g_signal_handler); g_signal_handler->register_handler(signum, handler, true); } void unregister_async_signal_handler(int signum, signal_handler_t handler) { assert(g_signal_handler); g_signal_handler->unregister_handler(signum, handler); } ceph-0.80.11/src/ceph-debugpack.in0000664000175100017510000000403612623076744020661 0ustar jenkins-buildjenkins-build#!/bin/sh # if we start up as ./init-ceph, assume everything else is in the # current directory too. if [ `dirname $0` = "." ] && [ $PWD != "/etc/init.d" ]; then BINDIR=. LIBDIR=. ETCDIR=. else BINDIR=@bindir@ LIBDIR=@libdir@/ceph ETCDIR=@sysconfdir@/ceph fi BINDBGDIR="/usr/lib/debug/usr/bin" usage_exit() { echo "usage: $0 [-c ceph.conf] " exit } wait_pid_exit() { pid=$1 for i in {1..10}; do [ -e /proc/$pid ] || return sleep 1 done if [ -e /proc/$pid ]; then echo Killing pid $pid kill $pid fi } . $LIBDIR/ceph_common.sh dest_tar='' while [ $# -ge 1 ]; do case $1 in --conf | -c) [ -z "$2" ] && usage_exit shift conf=$1 ;; *) if [ -n "$dest_tar" ]; then echo unrecognized option \'$1\' usage_exit fi dest_tar=$1 ;; esac shift done [ "$dest_tar" = "" ] && usage_exit echo "$0: generating debugpack tarball..." if [ -e $dest_tar ]; then echo "$0: dest $dest_tar already exists, aborting" exit 1 fi # get absolute path for dest_tar bins="ceph-mon ceph-mds ceph-osd radosgw" core_paths="/ $BINDIR $BINDBGDIR" [ "$conf" = "" ] && conf=$ETCDIR/ceph.conf log_path=`$CCONF -c $conf "log dir"` [ -z "$conf" ] && usage_exit # all configs files='/etc/ceph' # binaries for bin in bins; do if [ -e "/usr/bin/$bin" ]; then files="$files /usr/bin/$bin" fi if [ -e "/usr/lib/debug/usr/bin/$bin" ]; then files="$files /usr/lib/debug/usr/bin/$bin" fi done # logs (the non-rotated ones) for f in `find $path -maxdepth 1 -name 'core*'`; do files="$files $f" done # copy cores (if exist) for path in $core_paths; do if [ -d $path ]; then for f in `find $path -maxdepth 1 -name 'core*'`; do files="$files $f" done fi done # cluster state tmp_path=`mktemp -d /tmp/ceph-debugpack.XXXXXXXXXX` $BINDIR/ceph report > $tmp_path/ceph-report & wait_pid_exit $! files="$files $tmp_path" # now create a tarball tar cvfz $dest_tar $files rm -rf $tmp_path echo "$0: created debugpack tarball at $dest_tar" ceph-0.80.11/src/cls/0000775000175100017510000000000012623077033016235 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/user/0000775000175100017510000000000012623077035017215 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/user/cls_user_client.cc0000664000175100017510000000764012623076744022716 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "include/types.h" #include "cls/user/cls_user_ops.h" #include "cls/user/cls_user_client.h" #include "include/rados/librados.hpp" using namespace librados; void cls_user_set_buckets(librados::ObjectWriteOperation& op, list& entries, bool add) { bufferlist in; cls_user_set_buckets_op call; call.entries = entries; call.add = add; call.time = ceph_clock_now(NULL); ::encode(call, in); op.exec("user", "set_buckets_info", in); } void cls_user_complete_stats_sync(librados::ObjectWriteOperation& op) { bufferlist in; cls_user_complete_stats_sync_op call; call.time = ceph_clock_now(NULL); ::encode(call, in); op.exec("user", "complete_stats_sync", in); } void cls_user_remove_bucket(librados::ObjectWriteOperation& op, const cls_user_bucket& bucket) { bufferlist in; cls_user_remove_bucket_op call; call.bucket = bucket; ::encode(call, in); op.exec("user", "remove_bucket", in); } class ClsUserListCtx : public ObjectOperationCompletion { list *entries; string *marker; bool *truncated; int *pret; public: ClsUserListCtx(list *_entries, string *_marker, bool *_truncated, int *_pret) : entries(_entries), marker(_marker), truncated(_truncated), pret(_pret) {} void handle_completion(int r, bufferlist& outbl) { if (r >= 0) { cls_user_list_buckets_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); if (entries) *entries = ret.entries; if (truncated) *truncated = ret.truncated; if (marker) *marker = ret.marker; } catch (buffer::error& err) { r = -EIO; } } if (pret) { *pret = r; } } }; void cls_user_bucket_list(librados::ObjectReadOperation& op, const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated, int *pret) { bufferlist inbl; cls_user_list_buckets_op call; call.marker = in_marker; call.max_entries = max_entries; ::encode(call, inbl); op.exec("user", "list_buckets", inbl, new ClsUserListCtx(&entries, out_marker, truncated, pret)); } class ClsUserGetHeaderCtx : public ObjectOperationCompletion { cls_user_header *header; RGWGetUserHeader_CB *ret_ctx; int *pret; public: ClsUserGetHeaderCtx(cls_user_header *_h, RGWGetUserHeader_CB *_ctx, int *_pret) : header(_h), ret_ctx(_ctx), pret(_pret) {} ~ClsUserGetHeaderCtx() { if (ret_ctx) { ret_ctx->put(); } } void handle_completion(int r, bufferlist& outbl) { if (r >= 0) { cls_user_get_header_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); if (header) *header = ret.header; } catch (buffer::error& err) { r = -EIO; } if (ret_ctx) { ret_ctx->handle_response(r, ret.header); } } if (pret) { *pret = r; } } }; void cls_user_get_header(librados::ObjectReadOperation& op, cls_user_header *header, int *pret) { bufferlist inbl; cls_user_get_header_op call; ::encode(call, inbl); op.exec("user", "get_header", inbl, new ClsUserGetHeaderCtx(header, NULL, pret)); } int cls_user_get_header_async(IoCtx& io_ctx, string& oid, RGWGetUserHeader_CB *ctx) { bufferlist in, out; cls_user_get_header_op call; ::encode(call, in); ObjectReadOperation op; op.exec("user", "get_header", in, new ClsUserGetHeaderCtx(NULL, ctx, NULL)); /* no need to pass pret, as we'll call ctx->handle_response() with correct error */ AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); int r = io_ctx.aio_operate(oid, c, &op, NULL); c->release(); if (r < 0) return r; return 0; } ceph-0.80.11/src/cls/user/cls_user_ops.cc0000664000175100017510000000611512623076744022235 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "cls/user/cls_user_types.h" #include "cls/user/cls_user_ops.h" #include "common/Formatter.h" #include "common/ceph_json.h" void cls_user_set_buckets_op::dump(Formatter *f) const { encode_json("entries", entries, f); encode_json("add", add, f); encode_json("time", time, f); } void cls_user_set_buckets_op::generate_test_instances(list& ls) { ls.push_back(new cls_user_set_buckets_op); cls_user_set_buckets_op *op = new cls_user_set_buckets_op; for (int i = 0; i < 3; i++) { cls_user_bucket_entry e; cls_user_gen_test_bucket_entry(&e, i); op->entries.push_back(e); } op->add = true; op->time = utime_t(1, 0); ls.push_back(op); } void cls_user_remove_bucket_op::dump(Formatter *f) const { encode_json("bucket", bucket, f); } void cls_user_remove_bucket_op::generate_test_instances(list& ls) { ls.push_back(new cls_user_remove_bucket_op); cls_user_remove_bucket_op *op = new cls_user_remove_bucket_op; cls_user_gen_test_bucket(&op->bucket, 0); ls.push_back(op); } void cls_user_list_buckets_op::dump(Formatter *f) const { encode_json("marker", marker, f); encode_json("max_entries", max_entries, f); } void cls_user_list_buckets_op::generate_test_instances(list& ls) { ls.push_back(new cls_user_list_buckets_op); cls_user_list_buckets_op *op = new cls_user_list_buckets_op; op->marker = "marker"; op->max_entries = 1000; ls.push_back(op); } void cls_user_list_buckets_ret::dump(Formatter *f) const { encode_json("entries", entries, f); encode_json("marker", marker, f); encode_json("truncated", truncated, f); } void cls_user_list_buckets_ret::generate_test_instances(list& ls) { ls.push_back(new cls_user_list_buckets_ret); cls_user_list_buckets_ret *ret = new cls_user_list_buckets_ret; for (int i = 0; i < 3; i++) { cls_user_bucket_entry e; cls_user_gen_test_bucket_entry(&e, i); ret->entries.push_back(e); } ret->marker = "123"; ret->truncated = true; ls.push_back(ret); } void cls_user_get_header_op::dump(Formatter *f) const { // empty! } void cls_user_get_header_op::generate_test_instances(list& ls) { ls.push_back(new cls_user_get_header_op); } void cls_user_get_header_ret::dump(Formatter *f) const { encode_json("header", header, f); } void cls_user_get_header_ret::generate_test_instances(list& ls) { ls.push_back(new cls_user_get_header_ret); cls_user_get_header_ret *ret = new cls_user_get_header_ret; cls_user_gen_test_header(&ret->header); ls.push_back(ret); } void cls_user_complete_stats_sync_op::dump(Formatter *f) const { encode_json("time", time, f); } void cls_user_complete_stats_sync_op::generate_test_instances(list& ls) { ls.push_back(new cls_user_complete_stats_sync_op); cls_user_complete_stats_sync_op *op = new cls_user_complete_stats_sync_op; op->time = utime_t(12345, 0); ls.push_back(op); } ceph-0.80.11/src/cls/user/cls_user_client.h0000664000175100017510000000233412623076744022553 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_USER_CLIENT_H #define CEPH_CLS_USER_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" #include "cls_user_types.h" #include "common/RefCountedObj.h" class RGWGetUserHeader_CB : public RefCountedObject { public: virtual ~RGWGetUserHeader_CB() {} virtual void handle_response(int r, cls_user_header& header) = 0; }; /* * user objclass */ void cls_user_set_buckets(librados::ObjectWriteOperation& op, list& entries, bool add); void cls_user_complete_stats_sync(librados::ObjectWriteOperation& op); void cls_user_remove_bucket(librados::ObjectWriteOperation& op, const cls_user_bucket& bucket); void cls_user_bucket_list(librados::ObjectReadOperation& op, const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated, int *pret); void cls_user_get_header(librados::ObjectReadOperation& op, cls_user_header *header, int *pret); int cls_user_get_header_async(librados::IoCtx& io_ctx, string& oid, RGWGetUserHeader_CB *ctx); #endif ceph-0.80.11/src/cls/user/cls_user_types.h0000664000175100017510000001140712623076744022442 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_USER_TYPES_H #define CEPH_CLS_USER_TYPES_H #include "include/encoding.h" #include "include/types.h" #include "include/utime.h" /* * this needs to be compatible with with rgw_bucket, as it replaces it */ struct cls_user_bucket { std::string name; std::string data_pool; std::string index_pool; std::string marker; std::string bucket_id; std::string data_extra_pool; void encode(bufferlist& bl) const { ENCODE_START(7, 3, bl); ::encode(name, bl); ::encode(data_pool, bl); ::encode(marker, bl); ::encode(bucket_id, bl); ::encode(index_pool, bl); ::encode(data_extra_pool, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(7, 3, 3, bl); ::decode(name, bl); ::decode(data_pool, bl); if (struct_v >= 2) { ::decode(marker, bl); if (struct_v <= 3) { uint64_t id; ::decode(id, bl); char buf[16]; snprintf(buf, sizeof(buf), "%llu", (long long)id); bucket_id = buf; } else { ::decode(bucket_id, bl); } } if (struct_v >= 5) { ::decode(index_pool, bl); } else { index_pool = data_pool; } if (struct_v >= 7) { ::decode(data_extra_pool, bl); } DECODE_FINISH(bl); } bool operator<(const cls_user_bucket& b) const { return name.compare(b.name) < 0; } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_bucket) /* * this structure overrides RGWBucketEnt */ struct cls_user_bucket_entry { cls_user_bucket bucket; size_t size; size_t size_rounded; time_t creation_time; uint64_t count; bool user_stats_sync; cls_user_bucket_entry() : size(0), size_rounded(0), creation_time(0), count(0), user_stats_sync(false) {} void encode(bufferlist& bl) const { ENCODE_START(6, 5, bl); uint64_t s = size; __u32 mt = creation_time; string empty_str; // originally had the bucket name here, but we encode bucket later ::encode(empty_str, bl); ::encode(s, bl); ::encode(mt, bl); ::encode(count, bl); ::encode(bucket, bl); s = size_rounded; ::encode(s, bl); ::encode(user_stats_sync, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 5, 5, bl); __u32 mt; uint64_t s; string empty_str; // backward compatibility ::decode(empty_str, bl); ::decode(s, bl); ::decode(mt, bl); size = s; creation_time = mt; if (struct_v >= 2) ::decode(count, bl); if (struct_v >= 3) ::decode(bucket, bl); if (struct_v >= 4) ::decode(s, bl); size_rounded = s; if (struct_v >= 6) ::decode(user_stats_sync, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_bucket_entry) struct cls_user_stats { uint64_t total_entries; uint64_t total_bytes; uint64_t total_bytes_rounded; cls_user_stats() : total_entries(0), total_bytes(0), total_bytes_rounded(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(total_entries, bl); ::encode(total_bytes, bl); ::encode(total_bytes_rounded, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(total_entries, bl); ::decode(total_bytes, bl); ::decode(total_bytes_rounded, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_stats) /* * this needs to be compatible with with rgw_bucket, as it replaces it */ struct cls_user_header { cls_user_stats stats; utime_t last_stats_sync; /* last time a full stats sync completed */ utime_t last_stats_update; /* last time a stats update was done */ void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(stats, bl); ::encode(last_stats_sync, bl); ::encode(last_stats_update, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(stats, bl); ::decode(last_stats_sync, bl); ::decode(last_stats_update, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_header) void cls_user_gen_test_bucket(cls_user_bucket *bucket, int i); void cls_user_gen_test_bucket_entry(cls_user_bucket_entry *entry, int i); void cls_user_gen_test_stats(cls_user_stats *stats); void cls_user_gen_test_header(cls_user_header *h); #endif ceph-0.80.11/src/cls/user/cls_user_ops.h0000664000175100017510000001007712623076744022101 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_USER_OPS_H #define CEPH_CLS_USER_OPS_H #include "include/types.h" #include "cls_user_types.h" struct cls_user_set_buckets_op { list entries; bool add; utime_t time; /* op time */ cls_user_set_buckets_op() : add(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ::encode(add, bl); ::encode(time, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); ::decode(add, bl); ::decode(time, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_set_buckets_op) struct cls_user_remove_bucket_op { cls_user_bucket bucket; cls_user_remove_bucket_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(bucket, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(bucket, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_remove_bucket_op) struct cls_user_list_buckets_op { string marker; int max_entries; /* upperbound to returned num of entries might return less than that and still be truncated */ cls_user_list_buckets_op() : max_entries(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(marker, bl); ::encode(max_entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(marker, bl); ::decode(max_entries, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_list_buckets_op) struct cls_user_list_buckets_ret { list entries; string marker; bool truncated; cls_user_list_buckets_ret() : truncated(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ::encode(marker, bl); ::encode(truncated, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); ::decode(marker, bl); ::decode(truncated, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_list_buckets_ret) struct cls_user_get_header_op { cls_user_get_header_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_get_header_op) struct cls_user_get_header_ret { cls_user_header header; cls_user_get_header_ret() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(header, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(header, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_get_header_ret) struct cls_user_complete_stats_sync_op { utime_t time; cls_user_complete_stats_sync_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(time, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(time, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_user_complete_stats_sync_op) #endif ceph-0.80.11/src/cls/user/cls_user_types.cc0000664000175100017510000000570612623076744022605 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "cls/user/cls_user_types.h" #include "common/Formatter.h" #include "common/ceph_json.h" void cls_user_gen_test_bucket(cls_user_bucket *bucket, int i) { char buf[16]; snprintf(buf, sizeof(buf), ".%d", i); bucket->name = string("buck") + buf; bucket->data_pool = string(".data.pool") + buf; bucket->index_pool = string(".index.pool") + buf; bucket->marker = string("mark") + buf; bucket->bucket_id = string("bucket.id") + buf; } void cls_user_bucket::dump(Formatter *f) const { encode_json("name", name, f); encode_json("data_pool", data_pool,f); encode_json("data_extra_pool", data_extra_pool,f); encode_json("index_pool", index_pool,f); encode_json("marker", marker,f); encode_json("bucket_id", bucket_id,f); } void cls_user_bucket::generate_test_instances(list& ls) { ls.push_back(new cls_user_bucket); cls_user_bucket *b = new cls_user_bucket; cls_user_gen_test_bucket(b, 0); ls.push_back(b); } void cls_user_bucket_entry::dump(Formatter *f) const { encode_json("bucket", bucket, f); encode_json("size", size, f); encode_json("size_rounded", size_rounded, f); encode_json("creation_time", creation_time, f); encode_json("count", count, f); encode_json("user_stats_sync", user_stats_sync, f); } void cls_user_gen_test_bucket_entry(cls_user_bucket_entry *entry, int i) { cls_user_gen_test_bucket(&entry->bucket, i); entry->size = i + 1; entry->size_rounded = i + 2; entry->creation_time = i + 3; entry->count = i + 4; entry->user_stats_sync = true; } void cls_user_bucket_entry::generate_test_instances(list& ls) { ls.push_back(new cls_user_bucket_entry); cls_user_bucket_entry *entry = new cls_user_bucket_entry; cls_user_gen_test_bucket_entry(entry, 0); ls.push_back(entry); } void cls_user_gen_test_stats(cls_user_stats *s) { s->total_entries = 1; s->total_bytes = 2; s->total_bytes_rounded = 3; } void cls_user_stats::dump(Formatter *f) const { f->dump_int("total_entries", total_entries); f->dump_int("total_bytes", total_bytes); f->dump_int("total_bytes_rounded", total_bytes_rounded); } void cls_user_stats::generate_test_instances(list& ls) { ls.push_back(new cls_user_stats); cls_user_stats *s = new cls_user_stats; cls_user_gen_test_stats(s); ls.push_back(s); } void cls_user_gen_test_header(cls_user_header *h) { cls_user_gen_test_stats(&h->stats); h->last_stats_sync = utime_t(1, 0); h->last_stats_update = utime_t(2, 0); } void cls_user_header::dump(Formatter *f) const { encode_json("stats", stats, f); encode_json("last_stats_sync", last_stats_sync, f); encode_json("last_stats_update", last_stats_update, f); } void cls_user_header::generate_test_instances(list& ls) { ls.push_back(new cls_user_header); cls_user_header *h = new cls_user_header; cls_user_gen_test_header(h); ls.push_back(h); } ceph-0.80.11/src/cls/user/cls_user.cc0000664000175100017510000002226712623076744021362 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "objclass/objclass.h" #include "cls_user_types.h" #include "cls_user_ops.h" CLS_VER(1,0) CLS_NAME(user) cls_handle_t h_class; cls_method_handle_t h_user_set_buckets_info; cls_method_handle_t h_user_complete_stats_sync; cls_method_handle_t h_user_remove_bucket; cls_method_handle_t h_user_list_buckets; cls_method_handle_t h_user_get_header; static int write_entry(cls_method_context_t hctx, const string& key, const cls_user_bucket_entry& entry) { bufferlist bl; ::encode(entry, bl); int ret = cls_cxx_map_set_val(hctx, key, &bl); if (ret < 0) return ret; return 0; } static int remove_entry(cls_method_context_t hctx, const string& key) { int ret = cls_cxx_map_remove_key(hctx, key); if (ret < 0) return ret; return 0; } static void get_key_by_bucket_name(const string& bucket_name, string *key) { *key = bucket_name; } static int get_existing_bucket_entry(cls_method_context_t hctx, const string& bucket_name, cls_user_bucket_entry& entry) { if (bucket_name.empty()) { return -EINVAL; } string key; get_key_by_bucket_name(bucket_name, &key); bufferlist bl; int rc = cls_cxx_map_get_val(hctx, key, &bl); if (rc < 0) { CLS_LOG(10, "could not read entry %s", key.c_str()); return rc; } try { bufferlist::iterator iter = bl.begin(); ::decode(entry, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: failed to decode entry %s", key.c_str()); return -EIO; } return 0; } static int read_header(cls_method_context_t hctx, cls_user_header *header) { bufferlist bl; int ret = cls_cxx_map_read_header(hctx, &bl); if (ret < 0) return ret; if (bl.length() == 0) { *header = cls_user_header(); return 0; } try { ::decode(*header, bl); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: failed to decode user header"); return -EIO; } return 0; } static void add_header_stats(cls_user_stats *stats, cls_user_bucket_entry& entry) { stats->total_entries += entry.count; stats->total_bytes += entry.size; stats->total_bytes_rounded += entry.size_rounded; } static void dec_header_stats(cls_user_stats *stats, cls_user_bucket_entry& entry) { stats->total_bytes -= entry.size; stats->total_bytes_rounded -= entry.size_rounded; stats->total_entries -= entry.count; } static void apply_entry_stats(const cls_user_bucket_entry& src_entry, cls_user_bucket_entry *target_entry) { target_entry->size = src_entry.size; target_entry->size_rounded = src_entry.size_rounded; target_entry->count = src_entry.count; } static int cls_user_set_buckets_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_user_set_buckets_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_user_add_op(): failed to decode op"); return -EINVAL; } cls_user_header header; int ret = read_header(hctx, &header); if (ret < 0) { CLS_LOG(0, "ERROR: failed to read user info header ret=%d", ret); return ret; } for (list::iterator iter = op.entries.begin(); iter != op.entries.end(); ++iter) { cls_user_bucket_entry& update_entry = *iter; string key; get_key_by_bucket_name(update_entry.bucket.name, &key); cls_user_bucket_entry entry; ret = get_existing_bucket_entry(hctx, key, entry); if (ret == -ENOENT) { if (!op.add) continue; /* racing bucket removal */ entry = update_entry; ret = 0; } if (ret < 0) { CLS_LOG(0, "ERROR: get_existing_bucket_entry() key=%s returned %d", key.c_str(), ret); return ret; } else if (ret >= 0 && entry.user_stats_sync) { dec_header_stats(&header.stats, entry); } CLS_LOG(20, "storing entry for key=%s size=%lld count=%lld", key.c_str(), (long long)update_entry.size, (long long)update_entry.count); apply_entry_stats(update_entry, &entry); entry.user_stats_sync = true; ret = write_entry(hctx, key, entry); if (ret < 0) return ret; add_header_stats(&header.stats, entry); } bufferlist bl; CLS_LOG(20, "header: total bytes=%lld entries=%lld", (long long)header.stats.total_bytes, (long long)header.stats.total_entries); if (header.last_stats_update < op.time) header.last_stats_update = op.time; ::encode(header, bl); ret = cls_cxx_map_write_header(hctx, &bl); if (ret < 0) return ret; return 0; } static int cls_user_complete_stats_sync(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_user_complete_stats_sync_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_user_add_op(): failed to decode op"); return -EINVAL; } cls_user_header header; int ret = read_header(hctx, &header); if (ret < 0) { CLS_LOG(0, "ERROR: failed to read user info header ret=%d", ret); return ret; } if (header.last_stats_sync < op.time) header.last_stats_sync = op.time; bufferlist bl; ::encode(header, bl); ret = cls_cxx_map_write_header(hctx, &bl); if (ret < 0) return ret; return 0; } static int cls_user_remove_bucket(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_user_remove_bucket_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_user_add_op(): failed to decode op"); return -EINVAL; } cls_user_header header; int ret = read_header(hctx, &header); if (ret < 0) { CLS_LOG(0, "ERROR: failed to read user info header ret=%d", ret); return ret; } string key; get_key_by_bucket_name(op.bucket.name, &key); cls_user_bucket_entry entry; ret = get_existing_bucket_entry(hctx, key, entry); if (ret == -ENOENT) { return 0; /* idempotent removal */ } if (ret < 0) { CLS_LOG(0, "ERROR: get existing bucket entry, key=%s ret=%d", key.c_str(), ret); return ret; } if (entry.user_stats_sync) { dec_header_stats(&header.stats, entry); } CLS_LOG(20, "removing entry at %s", key.c_str()); ret = remove_entry(hctx, key); if (ret < 0) return ret; return 0; } static int cls_user_list_buckets(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_user_list_buckets_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_user_list_op(): failed to decode op"); return -EINVAL; } map keys; string from_index = op.marker; #define MAX_ENTRIES 1000 size_t max_entries = op.max_entries; if (!max_entries || max_entries > MAX_ENTRIES) max_entries = MAX_ENTRIES; string match_prefix; int rc = cls_cxx_map_get_vals(hctx, from_index, match_prefix, max_entries + 1, &keys); if (rc < 0) return rc; CLS_LOG(20, "from_index=%s match_prefix=%s", from_index.c_str(), match_prefix.c_str()); cls_user_list_buckets_ret ret; list& entries = ret.entries; map::iterator iter = keys.begin(); bool done = false; string marker; size_t i; for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) { const string& index = iter->first; marker = index; bufferlist& bl = iter->second; bufferlist::iterator biter = bl.begin(); try { cls_user_bucket_entry e; ::decode(e, biter); entries.push_back(e); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_user_list: could not decode entry, index=%s", index.c_str()); } } if (iter == keys.end()) done = true; else ret.marker = marker; ret.truncated = !done; ::encode(ret, *out); return 0; } static int cls_user_get_header(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_user_get_header_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_user_get_header_op(): failed to decode op"); return -EINVAL; } cls_user_get_header_ret op_ret; int ret = read_header(hctx, &op_ret.header); if (ret < 0) return ret; ::encode(op_ret, *out); return 0; } void __cls_init() { CLS_LOG(1, "Loaded user class!"); cls_register("user", &h_class); /* log */ cls_register_cxx_method(h_class, "set_buckets_info", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_set_buckets_info, &h_user_set_buckets_info); cls_register_cxx_method(h_class, "complete_stats_sync", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_complete_stats_sync, &h_user_set_buckets_info); cls_register_cxx_method(h_class, "remove_bucket", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_remove_bucket, &h_user_remove_bucket); cls_register_cxx_method(h_class, "list_buckets", CLS_METHOD_RD, cls_user_list_buckets, &h_user_list_buckets); cls_register_cxx_method(h_class, "get_header", CLS_METHOD_RD, cls_user_get_header, &h_user_get_header); return; } ceph-0.80.11/src/cls/rgw/0000775000175100017510000000000012623077035017036 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/rgw/cls_rgw_client.cc0000664000175100017510000002120412623076744022350 0ustar jenkins-buildjenkins-build#include #include "include/types.h" #include "cls/rgw/cls_rgw_ops.h" #include "cls/rgw/cls_rgw_client.h" #include "include/rados/librados.hpp" #include "common/debug.h" using namespace librados; void cls_rgw_bucket_init(ObjectWriteOperation& o) { bufferlist in; o.exec("rgw", "bucket_init_index", in); } void cls_rgw_bucket_set_tag_timeout(ObjectWriteOperation& o, uint64_t tag_timeout) { bufferlist in; struct rgw_cls_tag_timeout_op call; call.tag_timeout = tag_timeout; ::encode(call, in); o.exec("rgw", "bucket_set_tag_timeout", in); } void cls_rgw_bucket_prepare_op(ObjectWriteOperation& o, RGWModifyOp op, string& tag, string& name, string& locator, bool log_op) { struct rgw_cls_obj_prepare_op call; call.op = op; call.tag = tag; call.name = name; call.locator = locator; call.log_op = log_op; bufferlist in; ::encode(call, in); o.exec("rgw", "bucket_prepare_op", in); } void cls_rgw_bucket_complete_op(ObjectWriteOperation& o, RGWModifyOp op, string& tag, rgw_bucket_entry_ver& ver, string& name, rgw_bucket_dir_entry_meta& dir_meta, list *remove_objs, bool log_op) { bufferlist in; struct rgw_cls_obj_complete_op call; call.op = op; call.tag = tag; call.name = name; call.ver = ver; call.meta = dir_meta; call.log_op = log_op; if (remove_objs) call.remove_objs = *remove_objs; ::encode(call, in); o.exec("rgw", "bucket_complete_op", in); } int cls_rgw_list_op(IoCtx& io_ctx, string& oid, string& start_obj, string& filter_prefix, uint32_t num_entries, rgw_bucket_dir *dir, bool *is_truncated) { bufferlist in, out; struct rgw_cls_list_op call; call.start_obj = start_obj; call.filter_prefix = filter_prefix; call.num_entries = num_entries; ::encode(call, in); int r = io_ctx.exec(oid, "rgw", "bucket_list", in, out); if (r < 0) return r; struct rgw_cls_list_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } if (dir) *dir = ret.dir; if (is_truncated) *is_truncated = ret.is_truncated; return r; } int cls_rgw_bucket_check_index_op(IoCtx& io_ctx, string& oid, rgw_bucket_dir_header *existing_header, rgw_bucket_dir_header *calculated_header) { bufferlist in, out; int r = io_ctx.exec(oid, "rgw", "bucket_check_index", in, out); if (r < 0) return r; struct rgw_cls_check_index_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } if (existing_header) *existing_header = ret.existing_header; if (calculated_header) *calculated_header = ret.calculated_header; return 0; } int cls_rgw_bucket_rebuild_index_op(IoCtx& io_ctx, string& oid) { bufferlist in, out; int r = io_ctx.exec(oid, "rgw", "bucket_rebuild_index", in, out); if (r < 0) return r; return 0; } void cls_rgw_encode_suggestion(char op, rgw_bucket_dir_entry& dirent, bufferlist& updates) { updates.append(op); ::encode(dirent, updates); } void cls_rgw_suggest_changes(ObjectWriteOperation& o, bufferlist& updates) { o.exec("rgw", "dir_suggest_changes", updates); } int cls_rgw_get_dir_header(IoCtx& io_ctx, string& oid, rgw_bucket_dir_header *header) { bufferlist in, out; struct rgw_cls_list_op call; call.num_entries = 0; ::encode(call, in); int r = io_ctx.exec(oid, "rgw", "bucket_list", in, out); if (r < 0) return r; struct rgw_cls_list_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } if (header) *header = ret.dir.header; return r; } class GetDirHeaderCompletion : public ObjectOperationCompletion { RGWGetDirHeader_CB *ret_ctx; public: GetDirHeaderCompletion(RGWGetDirHeader_CB *_ctx) : ret_ctx(_ctx) {} ~GetDirHeaderCompletion() { ret_ctx->put(); } void handle_completion(int r, bufferlist& outbl) { struct rgw_cls_list_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); } catch (buffer::error& err) { r = -EIO; } ret_ctx->handle_response(r, ret.dir.header); }; }; int cls_rgw_get_dir_header_async(IoCtx& io_ctx, string& oid, RGWGetDirHeader_CB *ctx) { bufferlist in, out; struct rgw_cls_list_op call; call.num_entries = 0; ::encode(call, in); ObjectReadOperation op; GetDirHeaderCompletion *cb = new GetDirHeaderCompletion(ctx); op.exec("rgw", "bucket_list", in, cb); AioCompletion *c = librados::Rados::aio_create_completion(NULL, NULL, NULL); int r = io_ctx.aio_operate(oid, c, &op, NULL); c->release(); if (r < 0) return r; return 0; } int cls_rgw_bi_log_list(IoCtx& io_ctx, string& oid, string& marker, uint32_t max, list& entries, bool *truncated) { bufferlist in, out; cls_rgw_bi_log_list_op call; call.marker = marker; call.max = max; ::encode(call, in); int r = io_ctx.exec(oid, "rgw", "bi_log_list", in, out); if (r < 0) return r; cls_rgw_bi_log_list_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } entries = ret.entries; if (truncated) *truncated = ret.truncated; return r; } int cls_rgw_bi_log_trim(IoCtx& io_ctx, string& oid, string& start_marker, string& end_marker) { do { int r; bufferlist in, out; cls_rgw_bi_log_trim_op call; call.start_marker = start_marker; call.end_marker = end_marker; ::encode(call, in); r = io_ctx.exec(oid, "rgw", "bi_log_trim", in, out); if (r == -ENODATA) break; if (r < 0) return r; } while (1); return 0; } int cls_rgw_usage_log_read(IoCtx& io_ctx, string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, string& read_iter, map& usage, bool *is_truncated) { *is_truncated = false; bufferlist in, out; rgw_cls_usage_log_read_op call; call.start_epoch = start_epoch; call.end_epoch = end_epoch; call.owner = user; call.max_entries = max_entries; call.iter = read_iter; ::encode(call, in); int r = io_ctx.exec(oid, "rgw", "user_usage_log_read", in, out); if (r < 0) return r; try { rgw_cls_usage_log_read_ret result; bufferlist::iterator iter = out.begin(); ::decode(result, iter); read_iter = result.next_iter; if (is_truncated) *is_truncated = result.truncated; usage = result.usage; } catch (buffer::error& e) { return -EINVAL; } return 0; } void cls_rgw_usage_log_trim(ObjectWriteOperation& op, string& user, uint64_t start_epoch, uint64_t end_epoch) { bufferlist in; rgw_cls_usage_log_trim_op call; call.start_epoch = start_epoch; call.end_epoch = end_epoch; call.user = user; ::encode(call, in); op.exec("rgw", "user_usage_log_trim", in); } void cls_rgw_usage_log_add(ObjectWriteOperation& op, rgw_usage_log_info& info) { bufferlist in; rgw_cls_usage_log_add_op call; call.info = info; ::encode(call, in); op.exec("rgw", "user_usage_log_add", in); } /* garbage collection */ void cls_rgw_gc_set_entry(ObjectWriteOperation& op, uint32_t expiration_secs, cls_rgw_gc_obj_info& info) { bufferlist in; cls_rgw_gc_set_entry_op call; call.expiration_secs = expiration_secs; call.info = info; ::encode(call, in); op.exec("rgw", "gc_set_entry", in); } void cls_rgw_gc_defer_entry(ObjectWriteOperation& op, uint32_t expiration_secs, const string& tag) { bufferlist in; cls_rgw_gc_defer_entry_op call; call.expiration_secs = expiration_secs; call.tag = tag; ::encode(call, in); op.exec("rgw", "gc_defer_entry", in); } int cls_rgw_gc_list(IoCtx& io_ctx, string& oid, string& marker, uint32_t max, bool expired_only, list& entries, bool *truncated) { bufferlist in, out; cls_rgw_gc_list_op call; call.marker = marker; call.max = max; call.expired_only = expired_only; ::encode(call, in); int r = io_ctx.exec(oid, "rgw", "gc_list", in, out); if (r < 0) return r; cls_rgw_gc_list_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } entries = ret.entries; if (truncated) *truncated = ret.truncated; return r; } void cls_rgw_gc_remove(librados::ObjectWriteOperation& op, const list& tags) { bufferlist in; cls_rgw_gc_remove_op call; call.tags = tags; ::encode(call, in); op.exec("rgw", "gc_remove", in); } ceph-0.80.11/src/cls/rgw/cls_rgw_types.cc0000664000175100017510000001535612623076744022251 0ustar jenkins-buildjenkins-build #include "cls/rgw/cls_rgw_types.h" #include "common/Formatter.h" void rgw_bucket_pending_info::generate_test_instances(list& o) { rgw_bucket_pending_info *i = new rgw_bucket_pending_info; i->state = CLS_RGW_STATE_COMPLETE; i->op = CLS_RGW_OP_DEL; o.push_back(i); o.push_back(new rgw_bucket_pending_info); } void rgw_bucket_pending_info::dump(Formatter *f) const { f->dump_int("state", (int)state); f->dump_stream("timestamp") << timestamp; f->dump_int("op", (int)op); } void rgw_bucket_dir_entry_meta::generate_test_instances(list& o) { rgw_bucket_dir_entry_meta *m = new rgw_bucket_dir_entry_meta; m->category = 1; m->size = 100; m->etag = "etag"; m->owner = "owner"; m->owner_display_name = "display name"; m->content_type = "content/type"; o.push_back(m); o.push_back(new rgw_bucket_dir_entry_meta); } void rgw_bucket_dir_entry_meta::dump(Formatter *f) const { f->dump_int("category", category); f->dump_unsigned("size", size); f->dump_stream("mtime") << mtime; f->dump_string("etag", etag); f->dump_string("owner", owner); f->dump_string("owner_display_name", owner_display_name); f->dump_string("content_type", content_type); } void rgw_bucket_dir_entry::generate_test_instances(list& o) { list l; rgw_bucket_dir_entry_meta::generate_test_instances(l); list::iterator iter; for (iter = l.begin(); iter != l.end(); ++iter) { rgw_bucket_dir_entry_meta *m = *iter; rgw_bucket_dir_entry *e = new rgw_bucket_dir_entry; e->name = "name"; e->ver.pool = 1; e->ver.epoch = 1234; e->locator = "locator"; e->exists = true; e->meta = *m; e->tag = "tag"; o.push_back(e); delete m; } o.push_back(new rgw_bucket_dir_entry); } void rgw_bucket_entry_ver::dump(Formatter *f) const { f->dump_int("pool", pool); f->dump_unsigned("epoch", epoch); } void rgw_bucket_entry_ver::generate_test_instances(list& ls) { ls.push_back(new rgw_bucket_entry_ver); ls.push_back(new rgw_bucket_entry_ver); ls.back()->pool = 123; ls.back()->epoch = 12322; } void rgw_bucket_dir_entry::dump(Formatter *f) const { f->dump_string("name", name); f->open_object_section("ver"); ver.dump(f); f->close_section(); f->dump_string("locator", locator); f->dump_int("exists", (int)exists); f->open_object_section("meta"); meta.dump(f); f->close_section(); f->dump_string("tag", tag); map::const_iterator iter = pending_map.begin(); f->open_array_section("pending_map"); for (; iter != pending_map.end(); ++iter) { f->dump_string("tag", iter->first); f->open_object_section("info"); iter->second.dump(f); f->close_section(); } f->close_section(); } void rgw_bi_log_entry::dump(Formatter *f) const { f->dump_string("op_id", id); f->dump_string("op_tag", tag); switch (op) { case CLS_RGW_OP_ADD: f->dump_string("op", "write"); break; case CLS_RGW_OP_DEL: f->dump_string("op", "del"); break; case CLS_RGW_OP_CANCEL: f->dump_string("op", "cancel"); break; case CLS_RGW_OP_UNKNOWN: f->dump_string("op", "unknown"); break; default: f->dump_string("op", "invalid"); break; } f->dump_string("object", object); switch (state) { case CLS_RGW_STATE_PENDING_MODIFY: f->dump_string("state", "pending"); break; case CLS_RGW_STATE_COMPLETE: f->dump_string("state", "complete"); break; default: f->dump_string("state", "invalid"); break; } f->dump_int("index_ver", index_ver); timestamp.gmtime(f->dump_stream("timestamp")); f->open_object_section("ver"); ver.dump(f); f->close_section(); } void rgw_bi_log_entry::generate_test_instances(list& ls) { ls.push_back(new rgw_bi_log_entry); ls.push_back(new rgw_bi_log_entry); ls.back()->id = "midf"; ls.back()->object = "obj"; ls.back()->timestamp = utime_t(2, 3); ls.back()->index_ver = 4323; ls.back()->tag = "tagasdfds"; ls.back()->op = CLS_RGW_OP_DEL; ls.back()->state = CLS_RGW_STATE_PENDING_MODIFY; } void rgw_bucket_category_stats::generate_test_instances(list& o) { rgw_bucket_category_stats *s = new rgw_bucket_category_stats; s->total_size = 1024; s->total_size_rounded = 4096; s->num_entries = 2; o.push_back(s); o.push_back(new rgw_bucket_category_stats); } void rgw_bucket_category_stats::dump(Formatter *f) const { f->dump_unsigned("total_size", total_size); f->dump_unsigned("total_size_rounded", total_size_rounded); f->dump_unsigned("num_entries", num_entries); } void rgw_bucket_dir_header::generate_test_instances(list& o) { list l; list::iterator iter; rgw_bucket_category_stats::generate_test_instances(l); uint8_t i; for (i = 0, iter = l.begin(); iter != l.end(); ++iter, ++i) { rgw_bucket_dir_header *h = new rgw_bucket_dir_header; rgw_bucket_category_stats *s = *iter; h->stats[i] = *s; o.push_back(h); delete s; } o.push_back(new rgw_bucket_dir_header); } void rgw_bucket_dir_header::dump(Formatter *f) const { f->dump_int("ver", ver); f->dump_int("master_ver", master_ver); map::const_iterator iter = stats.begin(); f->open_array_section("stats"); for (; iter != stats.end(); ++iter) { f->dump_int("category", (int)iter->first); f->open_object_section("category_stats"); iter->second.dump(f); f->close_section(); } f->close_section(); } void rgw_bucket_dir::generate_test_instances(list& o) { list l; list::iterator iter; rgw_bucket_dir_header::generate_test_instances(l); uint8_t i; for (i = 0, iter = l.begin(); iter != l.end(); ++iter, ++i) { rgw_bucket_dir *d = new rgw_bucket_dir; rgw_bucket_dir_header *h = *iter; d->header = *h; list el; list::iterator eiter; for (eiter = el.begin(); eiter != el.end(); ++eiter) { rgw_bucket_dir_entry *e = *eiter; d->m[e->name] = *e; delete e; } o.push_back(d); delete h; } o.push_back(new rgw_bucket_dir); } void rgw_bucket_dir::dump(Formatter *f) const { f->open_object_section("header"); header.dump(f); f->close_section(); map::const_iterator iter = m.begin(); f->open_array_section("map"); for (; iter != m.end(); ++iter) { f->dump_string("obj", iter->first); f->open_object_section("dir_entry"); iter->second.dump(f); f->close_section(); } f->close_section(); } ceph-0.80.11/src/cls/rgw/cls_rgw_ops.cc0000664000175100017510000001346412623076744021704 0ustar jenkins-buildjenkins-build #include "cls/rgw/cls_rgw_ops.h" #include "common/Formatter.h" #include "common/ceph_json.h" void rgw_cls_tag_timeout_op::dump(Formatter *f) const { f->dump_int("tag_timeout", tag_timeout); } void rgw_cls_tag_timeout_op::generate_test_instances(list& ls) { ls.push_back(new rgw_cls_tag_timeout_op); ls.push_back(new rgw_cls_tag_timeout_op); ls.back()->tag_timeout = 23323; } void cls_rgw_gc_set_entry_op::dump(Formatter *f) const { f->dump_unsigned("expiration_secs", expiration_secs); f->open_object_section("obj_info"); info.dump(f); f->close_section(); } void cls_rgw_gc_set_entry_op::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_gc_set_entry_op); ls.push_back(new cls_rgw_gc_set_entry_op); ls.back()->expiration_secs = 123; } void cls_rgw_gc_defer_entry_op::dump(Formatter *f) const { f->dump_unsigned("expiration_secs", expiration_secs); f->dump_string("tag", tag); } void cls_rgw_gc_defer_entry_op::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_gc_defer_entry_op); ls.push_back(new cls_rgw_gc_defer_entry_op); ls.back()->expiration_secs = 123; ls.back()->tag = "footag"; } void cls_rgw_gc_list_op::dump(Formatter *f) const { f->dump_string("marker", marker); f->dump_unsigned("max", max); f->dump_bool("expired_only", expired_only); } void cls_rgw_gc_list_op::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_gc_list_op); ls.push_back(new cls_rgw_gc_list_op); ls.back()->marker = "mymarker"; ls.back()->max = 2312; } void cls_rgw_gc_list_ret::dump(Formatter *f) const { encode_json("entries", entries, f); f->dump_int("truncated", (int)truncated); } void cls_rgw_gc_list_ret::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_gc_list_ret); ls.push_back(new cls_rgw_gc_list_ret); ls.back()->entries.push_back(cls_rgw_gc_obj_info()); ls.back()->truncated = true; } void cls_rgw_gc_remove_op::dump(Formatter *f) const { encode_json("tags", tags, f); } void cls_rgw_gc_remove_op::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_gc_remove_op); ls.push_back(new cls_rgw_gc_remove_op); ls.back()->tags.push_back("tag1"); ls.back()->tags.push_back("tag2"); } void rgw_cls_obj_prepare_op::generate_test_instances(list& o) { rgw_cls_obj_prepare_op *op = new rgw_cls_obj_prepare_op; op->op = CLS_RGW_OP_ADD; op->name = "name"; op->tag = "tag"; op->locator = "locator"; o.push_back(op); o.push_back(new rgw_cls_obj_prepare_op); } void rgw_cls_obj_prepare_op::dump(Formatter *f) const { f->dump_int("op", op); f->dump_string("name", name); f->dump_string("tag", tag); f->dump_string("locator", locator); } void rgw_cls_obj_complete_op::generate_test_instances(list& o) { rgw_cls_obj_complete_op *op = new rgw_cls_obj_complete_op; op->op = CLS_RGW_OP_DEL; op->name = "name"; op->locator = "locator"; op->ver.pool = 2; op->ver.epoch = 100; op->tag = "tag"; list l; rgw_bucket_dir_entry_meta::generate_test_instances(l); list::iterator iter = l.begin(); op->meta = *(*iter); o.push_back(op); o.push_back(new rgw_cls_obj_complete_op); } void rgw_cls_obj_complete_op::dump(Formatter *f) const { f->dump_int("op", (int)op); f->dump_string("name", name); f->dump_string("locator", locator); f->open_object_section("ver"); ver.dump(f); f->close_section(); f->open_object_section("meta"); meta.dump(f); f->close_section(); f->dump_string("tag", tag); } void rgw_cls_list_op::generate_test_instances(list& o) { rgw_cls_list_op *op = new rgw_cls_list_op; op->start_obj = "start_obj"; op->num_entries = 100; op->filter_prefix = "filter_prefix"; o.push_back(op); o.push_back(new rgw_cls_list_op); } void rgw_cls_list_op::dump(Formatter *f) const { f->dump_string("start_obj", start_obj); f->dump_unsigned("num_entries", num_entries); } void rgw_cls_list_ret::generate_test_instances(list& o) { list l; rgw_bucket_dir::generate_test_instances(l); list::iterator iter; for (iter = l.begin(); iter != l.end(); ++iter) { rgw_bucket_dir *d = *iter; rgw_cls_list_ret *ret = new rgw_cls_list_ret; ret->dir = *d; ret->is_truncated = true; o.push_back(ret); delete d; } o.push_back(new rgw_cls_list_ret); } void rgw_cls_list_ret::dump(Formatter *f) const { f->open_object_section("dir"); dir.dump(f); f->close_section(); f->dump_int("is_truncated", (int)is_truncated); } void cls_rgw_bi_log_list_op::dump(Formatter *f) const { f->dump_string("marker", marker); f->dump_unsigned("max", max); } void cls_rgw_bi_log_list_op::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_bi_log_list_op); ls.push_back(new cls_rgw_bi_log_list_op); ls.back()->marker = "mark"; ls.back()->max = 123; } void cls_rgw_bi_log_trim_op::dump(Formatter *f) const { f->dump_string("start_marker", start_marker); f->dump_string("end_marker", end_marker); } void cls_rgw_bi_log_trim_op::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_bi_log_trim_op); ls.push_back(new cls_rgw_bi_log_trim_op); ls.back()->start_marker = "foo"; ls.back()->end_marker = "bar"; } void cls_rgw_bi_log_list_ret::dump(Formatter *f) const { encode_json("entries", entries, f); f->dump_unsigned("truncated", (int)truncated); } void cls_rgw_bi_log_list_ret::generate_test_instances(list& ls) { ls.push_back(new cls_rgw_bi_log_list_ret); ls.push_back(new cls_rgw_bi_log_list_ret); ls.back()->entries.push_back(rgw_bi_log_entry()); ls.back()->truncated = true; } ceph-0.80.11/src/cls/rgw/cls_rgw.cc0000664000175100017510000013377512623076744021033 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/int_types.h" #include "include/types.h" #include #include #include #include #include "include/utime.h" #include "objclass/objclass.h" #include "cls/rgw/cls_rgw_ops.h" #include "common/Clock.h" #include "global/global_context.h" CLS_VER(1,0) CLS_NAME(rgw) cls_handle_t h_class; cls_method_handle_t h_rgw_bucket_init_index; cls_method_handle_t h_rgw_bucket_set_tag_timeout; cls_method_handle_t h_rgw_bucket_list; cls_method_handle_t h_rgw_bucket_check_index; cls_method_handle_t h_rgw_bucket_rebuild_index; cls_method_handle_t h_rgw_bucket_prepare_op; cls_method_handle_t h_rgw_bucket_complete_op; cls_method_handle_t h_rgw_bi_log_list_op; cls_method_handle_t h_rgw_dir_suggest_changes; cls_method_handle_t h_rgw_user_usage_log_add; cls_method_handle_t h_rgw_user_usage_log_read; cls_method_handle_t h_rgw_user_usage_log_trim; cls_method_handle_t h_rgw_gc_set_entry; cls_method_handle_t h_rgw_gc_list; cls_method_handle_t h_rgw_gc_remove; #define ROUND_BLOCK_SIZE 4096 #define BI_PREFIX_CHAR 0x80 #define BI_BUCKET_OBJS_INDEX 0 #define BI_BUCKET_LOG_INDEX 1 #define BI_BUCKET_LAST_INDEX 2 static string bucket_index_prefixes[] = { "", /* special handling for the objs index */ "0_", /* this must be the last index */ "9999_",}; static uint64_t get_rounded_size(uint64_t size) { return (size + ROUND_BLOCK_SIZE - 1) & ~(ROUND_BLOCK_SIZE - 1); } static bool bi_is_objs_index(const string& s) { return ((unsigned char)s[0] != BI_PREFIX_CHAR); } int bi_entry_type(const string& s) { if (bi_is_objs_index(s)) { return BI_BUCKET_OBJS_INDEX; } for (size_t i = 1; i < sizeof(bucket_index_prefixes) / sizeof(bucket_index_prefixes[0]); ++i) { const string& t = bucket_index_prefixes[i]; if (s.compare(0, t.size(), t) == 0) { return i; } } return -EINVAL; } static void get_time_key(utime_t& ut, string *key) { char buf[32]; snprintf(buf, 32, "%011llu.%09u", (unsigned long long)ut.sec(), ut.nsec()); *key = buf; } static void get_index_ver_key(cls_method_context_t hctx, uint64_t index_ver, string *key) { char buf[48]; snprintf(buf, sizeof(buf), "%011llu.%llu.%d", (unsigned long long)index_ver, (unsigned long long)cls_current_version(hctx), cls_current_subop_num(hctx)); *key = buf; } static void bi_log_index_key(cls_method_context_t hctx, string& key, string& id, uint64_t index_ver) { key = BI_PREFIX_CHAR; key.append(bucket_index_prefixes[BI_BUCKET_LOG_INDEX]); get_index_ver_key(hctx, index_ver, &id); key.append(id); } static int log_index_operation(cls_method_context_t hctx, string& obj, RGWModifyOp op, string& tag, utime_t& timestamp, rgw_bucket_entry_ver& ver, RGWPendingState state, uint64_t index_ver, string& max_marker) { bufferlist bl; struct rgw_bi_log_entry entry; entry.object = obj; entry.timestamp = timestamp; entry.op = op; entry.ver = ver; entry.state = state; entry.index_ver = index_ver; entry.tag = tag; string key; bi_log_index_key(hctx, key, entry.id, index_ver); ::encode(entry, bl); if (entry.id > max_marker) max_marker = entry.id; return cls_cxx_map_set_val(hctx, key, &bl); } /* * read list of objects, skips objects in the ugly namespace */ static int get_obj_vals(cls_method_context_t hctx, const string& start, const string& filter_prefix, int num_entries, map *pkeys) { int ret = cls_cxx_map_get_vals(hctx, start, filter_prefix, num_entries, pkeys); if (ret < 0) return ret; if (pkeys->empty()) return 0; map::reverse_iterator last_element = pkeys->rbegin(); if ((unsigned char)last_element->first[0] < BI_PREFIX_CHAR) { /* nothing to see here, move along */ return 0; } map::iterator first_element = pkeys->begin(); if ((unsigned char)first_element->first[0] > BI_PREFIX_CHAR) { return 0; } /* let's rebuild the list, only keep entries we're interested in */ map old_keys; old_keys.swap(*pkeys); for (map::iterator iter = old_keys.begin(); iter != old_keys.end(); ++iter) { if ((unsigned char)iter->first[0] != BI_PREFIX_CHAR) { (*pkeys)[iter->first] = iter->second; } } if (num_entries == (int)pkeys->size()) return 0; map new_keys; char c[] = { (char)(BI_PREFIX_CHAR + 1), 0 }; string new_start = c; /* now get some more keys */ ret = cls_cxx_map_get_vals(hctx, new_start, filter_prefix, num_entries - pkeys->size(), &new_keys); if (ret < 0) return ret; for (map::iterator iter = new_keys.begin(); iter != new_keys.end(); ++iter) { (*pkeys)[iter->first] = iter->second; } return 0; } int rgw_bucket_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator iter = in->begin(); struct rgw_cls_list_op op; try { ::decode(op, iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode request\n"); return -EINVAL; } struct rgw_cls_list_ret ret; struct rgw_bucket_dir& new_dir = ret.dir; bufferlist header_bl; int rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) return rc; bufferlist::iterator header_iter = header_bl.begin(); try { ::decode(new_dir.header, header_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode header\n"); return -EINVAL; } bufferlist bl; map keys; rc = get_obj_vals(hctx, op.start_obj, op.filter_prefix, op.num_entries + 1, &keys); if (rc < 0) return rc; std::map& m = new_dir.m; std::map::iterator kiter = keys.begin(); uint32_t i; bool done = false; for (i = 0; i < op.num_entries && kiter != keys.end(); ++i, ++kiter) { struct rgw_bucket_dir_entry entry; if (!bi_is_objs_index(kiter->first)) { done = true; break; } bufferlist& entrybl = kiter->second; bufferlist::iterator eiter = entrybl.begin(); try { ::decode(entry, eiter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode entry, key=%s\n", kiter->first.c_str()); return -EINVAL; } m[kiter->first] = entry; } ret.is_truncated = (kiter != keys.end() && !done); ::encode(ret, *out); return 0; } static int check_index(cls_method_context_t hctx, struct rgw_bucket_dir_header *existing_header, struct rgw_bucket_dir_header *calc_header) { bufferlist header_bl; int rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) return rc; bufferlist::iterator header_iter = header_bl.begin(); try { ::decode(*existing_header, header_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode header\n"); return -EINVAL; } calc_header->tag_timeout = existing_header->tag_timeout; calc_header->ver = existing_header->ver; bufferlist bl; map keys; string start_obj; string filter_prefix; #define CHECK_CHUNK_SIZE 1000 bool done = false; do { rc = get_obj_vals(hctx, start_obj, filter_prefix, CHECK_CHUNK_SIZE, &keys); if (rc < 0) return rc; std::map::iterator kiter = keys.begin(); for (; kiter != keys.end(); ++kiter) { if (!bi_is_objs_index(kiter->first)) { done = true; break; } struct rgw_bucket_dir_entry entry; bufferlist::iterator eiter = kiter->second.begin(); try { ::decode(entry, eiter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode entry, key=%s\n", kiter->first.c_str()); return -EIO; } struct rgw_bucket_category_stats& stats = calc_header->stats[entry.meta.category]; stats.num_entries++; stats.total_size += entry.meta.size; stats.total_size_rounded += get_rounded_size(entry.meta.size); start_obj = kiter->first; } } while (keys.size() == CHECK_CHUNK_SIZE && !done); return 0; } int rgw_bucket_check_index(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { struct rgw_cls_check_index_ret ret; int rc = check_index(hctx, &ret.existing_header, &ret.calculated_header); if (rc < 0) return rc; ::encode(ret, *out); return 0; } static int write_bucket_header(cls_method_context_t hctx, struct rgw_bucket_dir_header *header) { header->ver++; bufferlist header_bl; ::encode(*header, header_bl); return cls_cxx_map_write_header(hctx, &header_bl); } int rgw_bucket_rebuild_index(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { struct rgw_bucket_dir_header existing_header; struct rgw_bucket_dir_header calc_header; int rc = check_index(hctx, &existing_header, &calc_header); if (rc < 0) return rc; return write_bucket_header(hctx, &calc_header); } int rgw_bucket_init_index(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist bl; bufferlist::iterator iter; bufferlist header_bl; int rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) { switch (rc) { case -ENODATA: case -ENOENT: break; default: return rc; } } if (header_bl.length() != 0) { CLS_LOG(1, "ERROR: index already initialized\n"); return -EINVAL; } rgw_bucket_dir dir; return write_bucket_header(hctx, &dir.header); } int rgw_bucket_set_tag_timeout(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // decode request rgw_cls_tag_timeout_op op; bufferlist::iterator iter = in->begin(); try { ::decode(op, iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_set_tag_timeout(): failed to decode request\n"); return -EINVAL; } bufferlist header_bl; struct rgw_bucket_dir_header header; int rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) return rc; bufferlist::iterator header_iter = header_bl.begin(); try { ::decode(header, header_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode header\n"); return -EINVAL; } header.tag_timeout = op.tag_timeout; return write_bucket_header(hctx, &header); } int rgw_bucket_prepare_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // decode request rgw_cls_obj_prepare_op op; bufferlist::iterator iter = in->begin(); try { ::decode(op, iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_prepare_op(): failed to decode request\n"); return -EINVAL; } if (op.tag.empty()) { CLS_LOG(1, "ERROR: tag is empty\n"); return -EINVAL; } CLS_LOG(1, "rgw_bucket_prepare_op(): request: op=%d name=%s tag=%s\n", op.op, op.name.c_str(), op.tag.c_str()); // get on-disk state bufferlist cur_value; int rc = cls_cxx_map_get_val(hctx, op.name, &cur_value); if (rc < 0 && rc != -ENOENT) return rc; struct rgw_bucket_dir_entry entry; bool noent = (rc == -ENOENT); rc = 0; if (!noent) { try { bufferlist::iterator biter = cur_value.begin(); ::decode(entry, biter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_prepare_op(): failed to decode entry\n"); /* ignoring error */ noent = true; } } if (noent) { // no entry, initialize fields entry.name = op.name; entry.ver = rgw_bucket_entry_ver(); entry.exists = false; entry.locator = op.locator; } // fill in proper state struct rgw_bucket_pending_info info; info.timestamp = ceph_clock_now(g_ceph_context); info.state = CLS_RGW_STATE_PENDING_MODIFY; info.op = op.op; entry.pending_map.insert(pair(op.tag, info)); bufferlist header_bl; struct rgw_bucket_dir_header header; rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) return rc; bufferlist::iterator header_iter = header_bl.begin(); try { ::decode(header, header_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode header\n"); return -EINVAL; } if (op.log_op) { rc = log_index_operation(hctx, op.name, op.op, op.tag, entry.meta.mtime, entry.ver, info.state, header.ver, header.max_marker); if (rc < 0) return rc; } // write out new key to disk bufferlist info_bl; ::encode(entry, info_bl); rc = cls_cxx_map_set_val(hctx, op.name, &info_bl); if (rc < 0) return rc; return write_bucket_header(hctx, &header); } static void unaccount_entry(struct rgw_bucket_dir_header& header, struct rgw_bucket_dir_entry& entry) { struct rgw_bucket_category_stats& stats = header.stats[entry.meta.category]; stats.num_entries--; stats.total_size -= entry.meta.size; stats.total_size_rounded -= get_rounded_size(entry.meta.size); } static int read_index_entry(cls_method_context_t hctx, string& name, struct rgw_bucket_dir_entry *entry) { bufferlist current_entry; int rc = cls_cxx_map_get_val(hctx, name, ¤t_entry); if (rc < 0) { return rc; } bufferlist::iterator cur_iter = current_entry.begin(); try { ::decode(*entry, cur_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: read_index_entry(): failed to decode entry\n"); return -EIO; } CLS_LOG(1, "read_index_entry(): existing entry: ver=%ld:%llu name=%s locator=%s\n", (long)entry->ver.pool, (unsigned long long)entry->ver.epoch, entry->name.c_str(), entry->locator.c_str()); return 0; } int rgw_bucket_complete_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // decode request rgw_cls_obj_complete_op op; bufferlist::iterator iter = in->begin(); try { ::decode(op, iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode request\n"); return -EINVAL; } CLS_LOG(1, "rgw_bucket_complete_op(): request: op=%d name=%s ver=%lu:%llu tag=%s\n", op.op, op.name.c_str(), (unsigned long)op.ver.pool, (unsigned long long)op.ver.epoch, op.tag.c_str()); bufferlist header_bl; struct rgw_bucket_dir_header header; int rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) return rc; bufferlist::iterator header_iter = header_bl.begin(); try { ::decode(header, header_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode header\n"); return -EINVAL; } struct rgw_bucket_dir_entry entry; bool ondisk = true; rc = read_index_entry(hctx, op.name, &entry); if (rc == -ENOENT) { entry.name = op.name; entry.ver = op.ver; entry.meta = op.meta; entry.locator = op.locator; ondisk = false; } else if (rc < 0) { return rc; } entry.index_ver = header.ver; if (op.tag.size()) { map::iterator pinter = entry.pending_map.find(op.tag); if (pinter == entry.pending_map.end()) { CLS_LOG(1, "ERROR: couldn't find tag for pending operation\n"); return -EINVAL; } entry.pending_map.erase(pinter); } bool cancel = false; bufferlist update_bl; if (op.tag.size() && op.op == CLS_RGW_OP_CANCEL) { CLS_LOG(1, "rgw_bucket_complete_op(): cancel requested\n"); cancel = true; } else if (op.ver.pool == entry.ver.pool && op.ver.epoch && op.ver.epoch <= entry.ver.epoch) { CLS_LOG(1, "rgw_bucket_complete_op(): skipping request, old epoch\n"); cancel = true; } bufferlist op_bl; if (cancel) { if (op.log_op) { rc = log_index_operation(hctx, op.name, op.op, op.tag, entry.meta.mtime, entry.ver, CLS_RGW_STATE_COMPLETE, header.ver, header.max_marker); if (rc < 0) return rc; } if (op.tag.size()) { bufferlist new_key_bl; ::encode(entry, new_key_bl); return cls_cxx_map_set_val(hctx, op.name, &new_key_bl); } else { return 0; } } if (entry.exists) { unaccount_entry(header, entry); } entry.ver = op.ver; switch ((int)op.op) { case CLS_RGW_OP_DEL: if (ondisk) { if (!entry.pending_map.size()) { int ret = cls_cxx_map_remove_key(hctx, op.name); if (ret < 0) return ret; } else { entry.exists = false; bufferlist new_key_bl; ::encode(entry, new_key_bl); int ret = cls_cxx_map_set_val(hctx, op.name, &new_key_bl); if (ret < 0) return ret; } } else { return -ENOENT; } break; case CLS_RGW_OP_ADD: { struct rgw_bucket_dir_entry_meta& meta = op.meta; struct rgw_bucket_category_stats& stats = header.stats[meta.category]; entry.meta = meta; entry.name = op.name; entry.exists = true; entry.tag = op.tag; stats.num_entries++; stats.total_size += meta.size; stats.total_size_rounded += get_rounded_size(meta.size); bufferlist new_key_bl; ::encode(entry, new_key_bl); int ret = cls_cxx_map_set_val(hctx, op.name, &new_key_bl); if (ret < 0) return ret; } break; } if (op.log_op) { rc = log_index_operation(hctx, op.name, op.op, op.tag, entry.meta.mtime, entry.ver, CLS_RGW_STATE_COMPLETE, header.ver, header.max_marker); if (rc < 0) return rc; } list::iterator remove_iter; CLS_LOG(20, "rgw_bucket_complete_op(): remove_objs.size()=%d\n", (int)op.remove_objs.size()); for (remove_iter = op.remove_objs.begin(); remove_iter != op.remove_objs.end(); ++remove_iter) { string& remove_oid_name = *remove_iter; CLS_LOG(1, "rgw_bucket_complete_op(): removing entries, read_index_entry name=%s\n", remove_oid_name.c_str()); struct rgw_bucket_dir_entry remove_entry; int ret = read_index_entry(hctx, remove_oid_name, &remove_entry); if (ret < 0) { CLS_LOG(1, "rgw_bucket_complete_op(): removing entries, read_index_entry name=%s ret=%d\n", remove_oid_name.c_str(), ret); continue; } CLS_LOG(0, "rgw_bucket_complete_op(): entry.name=%s entry.meta.category=%d\n", remove_entry.name.c_str(), remove_entry.meta.category); unaccount_entry(header, remove_entry); if (op.log_op) { rc = log_index_operation(hctx, remove_oid_name, CLS_RGW_OP_DEL, op.tag, remove_entry.meta.mtime, remove_entry.ver, CLS_RGW_STATE_COMPLETE, header.ver, header.max_marker); if (rc < 0) continue; } ret = cls_cxx_map_remove_key(hctx, remove_oid_name); if (ret < 0) { CLS_LOG(1, "rgw_bucket_complete_op(): cls_cxx_map_remove_key, failed to remove entry, name=%s read_index_entry ret=%d\n", remove_oid_name.c_str(), rc); continue; } } return write_bucket_header(hctx, &header); } int rgw_dir_suggest_changes(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(1, "rgw_dir_suggest_changes()"); bufferlist header_bl; struct rgw_bucket_dir_header header; bool header_changed = false; int rc = cls_cxx_map_read_header(hctx, &header_bl); if (rc < 0) return rc; uint64_t tag_timeout; try { bufferlist::iterator header_iter = header_bl.begin(); ::decode(header, header_iter); } catch (buffer::error& error) { CLS_LOG(1, "ERROR: rgw_dir_suggest_changes(): failed to decode header\n"); return -EINVAL; } tag_timeout = (header.tag_timeout ? header.tag_timeout : CEPH_RGW_TAG_TIMEOUT); bufferlist::iterator in_iter = in->begin(); while (!in_iter.end()) { __u8 op; rgw_bucket_dir_entry cur_change; rgw_bucket_dir_entry cur_disk; try { ::decode(op, in_iter); ::decode(cur_change, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_dir_suggest_changes(): failed to decode request\n"); return -EINVAL; } bufferlist cur_disk_bl; int ret = cls_cxx_map_get_val(hctx, cur_change.name, &cur_disk_bl); if (ret < 0 && ret != -ENOENT) return -EINVAL; if (cur_disk_bl.length()) { bufferlist::iterator cur_disk_iter = cur_disk_bl.begin(); try { ::decode(cur_disk, cur_disk_iter); } catch (buffer::error& error) { CLS_LOG(1, "ERROR: rgw_dir_suggest_changes(): failed to decode cur_disk\n"); return -EINVAL; } utime_t cur_time = ceph_clock_now(g_ceph_context); map::iterator iter = cur_disk.pending_map.begin(); while(iter != cur_disk.pending_map.end()) { map::iterator cur_iter=iter++; if (cur_time > (cur_iter->second.timestamp + tag_timeout)) { cur_disk.pending_map.erase(cur_iter); } } } CLS_LOG(20, "cur_disk.pending_map.empty()=%d op=%d cur_disk.exists=%d cur_change.pending_map.size()=%d cur_change.exists=%d\n", cur_disk.pending_map.empty(), (int)op, cur_disk.exists, (int)cur_change.pending_map.size(), cur_change.exists); if (cur_disk.pending_map.empty()) { if (cur_disk.exists) { struct rgw_bucket_category_stats& old_stats = header.stats[cur_disk.meta.category]; CLS_LOG(10, "total_entries: %"PRId64" -> %"PRId64"\n", old_stats.num_entries, old_stats.num_entries - 1); old_stats.num_entries--; old_stats.total_size -= cur_disk.meta.size; old_stats.total_size_rounded -= get_rounded_size(cur_disk.meta.size); header_changed = true; } struct rgw_bucket_category_stats& stats = header.stats[cur_change.meta.category]; switch(op) { case CEPH_RGW_REMOVE: CLS_LOG(10, "CEPH_RGW_REMOVE name=%s\n", cur_change.name.c_str()); ret = cls_cxx_map_remove_key(hctx, cur_change.name); if (ret < 0) return ret; break; case CEPH_RGW_UPDATE: CLS_LOG(10, "CEPH_RGW_UPDATE name=%s total_entries: %"PRId64" -> %"PRId64"\n", cur_change.name.c_str(), stats.num_entries, stats.num_entries + 1); stats.num_entries++; stats.total_size += cur_change.meta.size; stats.total_size_rounded += get_rounded_size(cur_change.meta.size); header_changed = true; cur_change.index_ver = header.ver; bufferlist cur_state_bl; ::encode(cur_change, cur_state_bl); ret = cls_cxx_map_set_val(hctx, cur_change.name, &cur_state_bl); if (ret < 0) return ret; break; } } } if (header_changed) { return write_bucket_header(hctx, &header); } return 0; } int bi_log_record_decode(bufferlist& bl, rgw_bi_log_entry& e) { bufferlist::iterator iter = bl.begin(); try { ::decode(e, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: failed to decode rgw_bi_log_entry"); return -EIO; } return 0; } static int bi_log_iterate_entries(cls_method_context_t hctx, const string& marker, const string& end_marker, string& key_iter, uint32_t max_entries, bool *truncated, int (*cb)(cls_method_context_t, const string&, rgw_bi_log_entry&, void *), void *param) { CLS_LOG(10, "bi_log_iterate_range"); map keys; string filter_prefix, end_key; bufferlist start_bl; bool start_key_added = false; uint32_t i = 0; string key; if (truncated) *truncated = false; string start_key; if (key_iter.empty()) { key = BI_PREFIX_CHAR; key.append(bucket_index_prefixes[BI_BUCKET_LOG_INDEX]); key.append(marker); start_key = key; int ret = cls_cxx_map_get_val(hctx, start_key, &start_bl); if ((ret < 0) && (ret != -ENOENT)) { return ret; } } else { start_key = key_iter; } if (end_marker.empty()) { end_key = BI_PREFIX_CHAR; end_key.append(bucket_index_prefixes[BI_BUCKET_LAST_INDEX]); } else { end_key = BI_PREFIX_CHAR; end_key.append(bucket_index_prefixes[BI_BUCKET_LOG_INDEX]); end_key.append(end_marker); } CLS_LOG(0, "bi_log_iterate_entries start_key=%s end_key=%s\n", start_key.c_str(), end_key.c_str()); string filter; do { #define BI_NUM_KEYS 128 int ret = cls_cxx_map_get_vals(hctx, start_key, filter, BI_NUM_KEYS, &keys); if (ret < 0) return ret; if ((start_bl.length() > 0) && (!start_key_added)) { keys[start_key] = start_bl; start_key_added = true; } map::iterator iter = keys.begin(); if (iter == keys.end()) break; for (; iter != keys.end(); ++iter) { const string& key = iter->first; rgw_bi_log_entry e; CLS_LOG(0, "bi_log_iterate_entries key=%s bl.length=%d\n", key.c_str(), (int)iter->second.length()); if (key.compare(end_key) > 0) return 0; ret = bi_log_record_decode(iter->second, e); if (ret < 0) return ret; if (max_entries && (i >= max_entries)) { if (truncated) *truncated = true; key_iter = key; return 0; } ret = cb(hctx, key, e, param); if (ret < 0) return ret; i++; } --iter; start_key = iter->first; } while (true); return 0; } static int bi_log_list_cb(cls_method_context_t hctx, const string& key, rgw_bi_log_entry& info, void *param) { list *l = (list *)param; l->push_back(info); return 0; } static int bi_log_list_entries(cls_method_context_t hctx, const string& marker, uint32_t max, list& entries, bool *truncated) { string key_iter; string end_marker; int ret = bi_log_iterate_entries(hctx, marker, end_marker, key_iter, max, truncated, bi_log_list_cb, &entries); return ret; } static int rgw_bi_log_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_rgw_bi_log_list_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bi_log_list(): failed to decode entry\n"); return -EINVAL; } cls_rgw_bi_log_list_ret op_ret; int ret = bi_log_list_entries(hctx, op.marker, op.max, op_ret.entries, &op_ret.truncated); if (ret < 0) return ret; ::encode(op_ret, *out); return 0; } static int bi_log_list_trim_cb(cls_method_context_t hctx, const string& key, rgw_bi_log_entry& info, void *param) { list *entries = (list *)param; entries->push_back(info); return 0; } static int bi_log_remove_entry(cls_method_context_t hctx, rgw_bi_log_entry& entry) { string key; key = BI_PREFIX_CHAR; key.append(bucket_index_prefixes[BI_BUCKET_LOG_INDEX]); key.append(entry.id); return cls_cxx_map_remove_key(hctx, key); } static int bi_log_list_trim_entries(cls_method_context_t hctx, const string& start_marker, const string& end_marker, list& entries, bool *truncated) { string key_iter; #define MAX_TRIM_ENTRIES 1000 /* max entries to trim in a single operation */ int ret = bi_log_iterate_entries(hctx, start_marker, end_marker, key_iter, MAX_TRIM_ENTRIES, truncated, bi_log_list_trim_cb, &entries); return ret; } static int rgw_bi_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_rgw_bi_log_trim_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_bi_log_list(): failed to decode entry\n"); return -EINVAL; } cls_rgw_bi_log_list_ret op_ret; list entries; #define MAX_TRIM_ENTRIES 1000 /* don't do more than that in a single operation */ bool truncated; int ret = bi_log_list_trim_entries(hctx, op.start_marker, op.end_marker, entries, &truncated); if (ret < 0) return ret; if (entries.empty()) return -ENODATA; list::iterator iter; for (iter = entries.begin(); iter != entries.end(); ++iter) { rgw_bi_log_entry& entry = *iter; ret = bi_log_remove_entry(hctx, entry); if (ret < 0) return ret; } return 0; } static void usage_record_prefix_by_time(uint64_t epoch, string& key) { char buf[32]; snprintf(buf, sizeof(buf), "%011llu", (long long unsigned)epoch); key = buf; } static void usage_record_prefix_by_user(string& user, uint64_t epoch, string& key) { char buf[user.size() + 32]; snprintf(buf, sizeof(buf), "%s_%011llu_", user.c_str(), (long long unsigned)epoch); key = buf; } static void usage_record_name_by_time(uint64_t epoch, string& user, string& bucket, string& key) { char buf[32 + user.size() + bucket.size()]; snprintf(buf, sizeof(buf), "%011llu_%s_%s", (long long unsigned)epoch, user.c_str(), bucket.c_str()); key = buf; } static void usage_record_name_by_user(string& user, uint64_t epoch, string& bucket, string& key) { char buf[32 + user.size() + bucket.size()]; snprintf(buf, sizeof(buf), "%s_%011llu_%s", user.c_str(), (long long unsigned)epoch, bucket.c_str()); key = buf; } static int usage_record_decode(bufferlist& record_bl, rgw_usage_log_entry& e) { bufferlist::iterator kiter = record_bl.begin(); try { ::decode(e, kiter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: usage_record_decode(): failed to decode record_bl\n"); return -EINVAL; } return 0; } int rgw_user_usage_log_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(10, "rgw_user_usage_log_add()"); bufferlist::iterator in_iter = in->begin(); rgw_cls_usage_log_add_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_user_usage_log_add(): failed to decode request\n"); return -EINVAL; } rgw_usage_log_info& info = op.info; vector::iterator iter; for (iter = info.entries.begin(); iter != info.entries.end(); ++iter) { rgw_usage_log_entry& entry = *iter; string key_by_time; usage_record_name_by_time(entry.epoch, entry.owner, entry.bucket, key_by_time); CLS_LOG(10, "rgw_user_usage_log_add user=%s bucket=%s\n", entry.owner.c_str(), entry.bucket.c_str()); bufferlist record_bl; int ret = cls_cxx_map_get_val(hctx, key_by_time, &record_bl); if (ret < 0 && ret != -ENOENT) { CLS_LOG(1, "ERROR: rgw_user_usage_log_add(): cls_cxx_map_read_key returned %d\n", ret); return -EINVAL; } if (ret >= 0) { rgw_usage_log_entry e; ret = usage_record_decode(record_bl, e); if (ret < 0) return ret; CLS_LOG(10, "rgw_user_usage_log_add aggregating existing bucket\n"); entry.aggregate(e); } bufferlist new_record_bl; ::encode(entry, new_record_bl); ret = cls_cxx_map_set_val(hctx, key_by_time, &new_record_bl); if (ret < 0) return ret; string key_by_user; usage_record_name_by_user(entry.owner, entry.epoch, entry.bucket, key_by_user); ret = cls_cxx_map_set_val(hctx, key_by_user, &new_record_bl); if (ret < 0) return ret; } return 0; } static int usage_iterate_range(cls_method_context_t hctx, uint64_t start, uint64_t end, string& user, string& key_iter, uint32_t max_entries, bool *truncated, int (*cb)(cls_method_context_t, const string&, rgw_usage_log_entry&, void *), void *param) { CLS_LOG(10, "usage_iterate_range"); map keys; #define NUM_KEYS 32 string filter_prefix; string start_key, end_key; bool by_user = !user.empty(); uint32_t i = 0; string user_key; if (truncated) *truncated = false; if (!by_user) { usage_record_prefix_by_time(end, end_key); } else { user_key = user; user_key.append("_"); } if (key_iter.empty()) { if (by_user) { usage_record_prefix_by_user(user, start, start_key); } else { usage_record_prefix_by_time(start, start_key); } } else { start_key = key_iter; } do { CLS_LOG(20, "usage_iterate_range start_key=%s", start_key.c_str()); int ret = cls_cxx_map_get_vals(hctx, start_key, filter_prefix, NUM_KEYS, &keys); if (ret < 0) return ret; map::iterator iter = keys.begin(); if (iter == keys.end()) break; for (; iter != keys.end(); ++iter) { const string& key = iter->first; rgw_usage_log_entry e; if (!by_user && key.compare(end_key) >= 0) { CLS_LOG(20, "usage_iterate_range reached key=%s, done", key.c_str()); return 0; } if (by_user && key.compare(0, user_key.size(), user_key) != 0) { CLS_LOG(20, "usage_iterate_range reached key=%s, done", key.c_str()); return 0; } ret = usage_record_decode(iter->second, e); if (ret < 0) return ret; if (e.epoch < start) continue; /* keys are sorted by epoch, so once we're past end we're done */ if (e.epoch >= end) return 0; ret = cb(hctx, key, e, param); if (ret < 0) return ret; i++; if (max_entries && (i > max_entries)) { CLS_LOG(20, "usage_iterate_range reached max_entries (%d), done", max_entries); *truncated = true; key_iter = key; return 0; } } --iter; start_key = iter->first; } while (true); return 0; } static int usage_log_read_cb(cls_method_context_t hctx, const string& key, rgw_usage_log_entry& entry, void *param) { map *usage = (map *)param; rgw_user_bucket ub(entry.owner, entry.bucket); rgw_usage_log_entry& le = (*usage)[ub]; le.aggregate(entry); return 0; } int rgw_user_usage_log_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(10, "rgw_user_usage_log_read()"); bufferlist::iterator in_iter = in->begin(); rgw_cls_usage_log_read_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_user_usage_log_read(): failed to decode request\n"); return -EINVAL; } rgw_cls_usage_log_read_ret ret_info; map *usage = &ret_info.usage; string iter = op.iter; #define MAX_ENTRIES 1000 uint32_t max_entries = (op.max_entries ? op.max_entries : MAX_ENTRIES); int ret = usage_iterate_range(hctx, op.start_epoch, op.end_epoch, op.owner, iter, max_entries, &ret_info.truncated, usage_log_read_cb, (void *)usage); if (ret < 0) return ret; if (ret_info.truncated) ret_info.next_iter = iter; ::encode(ret_info, *out); return 0; } static int usage_log_trim_cb(cls_method_context_t hctx, const string& key, rgw_usage_log_entry& entry, void *param) { string key_by_time; string key_by_user; usage_record_name_by_time(entry.epoch, entry.owner, entry.bucket, key_by_time); usage_record_name_by_user(entry.owner, entry.epoch, entry.bucket, key_by_user); int ret = cls_cxx_map_remove_key(hctx, key_by_time); if (ret < 0) return ret; return cls_cxx_map_remove_key(hctx, key_by_user); } int rgw_user_usage_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(10, "rgw_user_usage_log_trim()"); /* only continue if object exists! */ int ret = cls_cxx_stat(hctx, NULL, NULL); if (ret < 0) return ret; bufferlist::iterator in_iter = in->begin(); rgw_cls_usage_log_trim_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_user_log_usage_log_trim(): failed to decode request\n"); return -EINVAL; } string iter; ret = usage_iterate_range(hctx, op.start_epoch, op.end_epoch, op.user, iter, 0, NULL, usage_log_trim_cb, NULL); if (ret < 0) return ret; return 0; } /* * We hold the garbage collection chain data under two different indexes: the first 'name' index * keeps them under a unique tag that represents the chains, and a second 'time' index keeps * them by their expiration timestamp */ #define GC_OBJ_NAME_INDEX 0 #define GC_OBJ_TIME_INDEX 1 static string gc_index_prefixes[] = { "0_", "1_" }; static void prepend_index_prefix(const string& src, int index, string *dest) { *dest = gc_index_prefixes[index]; dest->append(src); } static int gc_omap_get(cls_method_context_t hctx, int type, const string& key, cls_rgw_gc_obj_info *info) { string index; prepend_index_prefix(key, type, &index); bufferlist bl; int ret = cls_cxx_map_get_val(hctx, index, &bl); if (ret < 0) return ret; try { bufferlist::iterator iter = bl.begin(); ::decode(*info, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: rgw_cls_gc_omap_get(): failed to decode index=%s\n", index.c_str()); } return 0; } static int gc_omap_set(cls_method_context_t hctx, int type, const string& key, const cls_rgw_gc_obj_info *info) { bufferlist bl; ::encode(*info, bl); string index = gc_index_prefixes[type]; index.append(key); int ret = cls_cxx_map_set_val(hctx, index, &bl); if (ret < 0) return ret; return 0; } static int gc_omap_remove(cls_method_context_t hctx, int type, const string& key) { string index = gc_index_prefixes[type]; index.append(key); bufferlist bl; int ret = cls_cxx_map_remove_key(hctx, index); if (ret < 0) return ret; return 0; } static bool key_in_index(const string& key, int index_type) { const string& prefix = gc_index_prefixes[index_type]; return (key.compare(0, prefix.size(), prefix) == 0); } static int gc_update_entry(cls_method_context_t hctx, uint32_t expiration_secs, cls_rgw_gc_obj_info& info) { cls_rgw_gc_obj_info old_info; int ret = gc_omap_get(hctx, GC_OBJ_NAME_INDEX, info.tag, &old_info); if (ret == 0) { string key; get_time_key(old_info.time, &key); ret = gc_omap_remove(hctx, GC_OBJ_TIME_INDEX, key); if (ret < 0 && ret != -ENOENT) { CLS_LOG(0, "ERROR: failed to remove key=%s\n", key.c_str()); return ret; } } info.time = ceph_clock_now(g_ceph_context); info.time += expiration_secs; ret = gc_omap_set(hctx, GC_OBJ_NAME_INDEX, info.tag, &info); if (ret < 0) return ret; string key; get_time_key(info.time, &key); ret = gc_omap_set(hctx, GC_OBJ_TIME_INDEX, key, &info); if (ret < 0) goto done_err; return 0; done_err: CLS_LOG(0, "ERROR: gc_set_entry error info.tag=%s, ret=%d\n", info.tag.c_str(), ret); gc_omap_remove(hctx, GC_OBJ_NAME_INDEX, info.tag); return ret; } static int gc_defer_entry(cls_method_context_t hctx, const string& tag, uint32_t expiration_secs) { cls_rgw_gc_obj_info info; int ret = gc_omap_get(hctx, GC_OBJ_NAME_INDEX, tag, &info); if (ret == -ENOENT) return 0; if (ret < 0) return ret; return gc_update_entry(hctx, expiration_secs, info); } int gc_record_decode(bufferlist& bl, cls_rgw_gc_obj_info& e) { bufferlist::iterator iter = bl.begin(); try { ::decode(e, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: failed to decode cls_rgw_gc_obj_info"); return -EIO; } return 0; } static int rgw_cls_gc_set_entry(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_rgw_gc_set_entry_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_cls_gc_set_entry(): failed to decode entry\n"); return -EINVAL; } return gc_update_entry(hctx, op.expiration_secs, op.info); } static int rgw_cls_gc_defer_entry(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_rgw_gc_defer_entry_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_cls_gc_defer_entry(): failed to decode entry\n"); return -EINVAL; } return gc_defer_entry(hctx, op.tag, op.expiration_secs); } static int gc_iterate_entries(cls_method_context_t hctx, const string& marker, bool expired_only, string& key_iter, uint32_t max_entries, bool *truncated, int (*cb)(cls_method_context_t, const string&, cls_rgw_gc_obj_info&, void *), void *param) { CLS_LOG(10, "gc_iterate_range"); map keys; string filter_prefix, end_key; uint32_t i = 0; string key; if (truncated) *truncated = false; string start_key; if (key_iter.empty()) { prepend_index_prefix(marker, GC_OBJ_TIME_INDEX, &start_key); } else { start_key = key_iter; } if (expired_only) { utime_t now = ceph_clock_now(g_ceph_context); string now_str; get_time_key(now, &now_str); prepend_index_prefix(now_str, GC_OBJ_TIME_INDEX, &end_key); CLS_LOG(0, "gc_iterate_entries end_key=%s\n", end_key.c_str()); } string filter; do { #define GC_NUM_KEYS 32 int ret = cls_cxx_map_get_vals(hctx, start_key, filter, GC_NUM_KEYS, &keys); if (ret < 0) return ret; map::iterator iter = keys.begin(); if (iter == keys.end()) break; for (; iter != keys.end(); ++iter) { const string& key = iter->first; cls_rgw_gc_obj_info e; CLS_LOG(10, "gc_iterate_entries key=%s\n", key.c_str()); if (!end_key.empty() && key.compare(end_key) >= 0) return 0; if (!key_in_index(key, GC_OBJ_TIME_INDEX)) return 0; ret = gc_record_decode(iter->second, e); if (ret < 0) return ret; if (max_entries && (i >= max_entries)) { if (truncated) *truncated = true; key_iter = key; return 0; } ret = cb(hctx, key, e, param); if (ret < 0) return ret; i++; } --iter; start_key = iter->first; } while (true); return 0; } static int gc_list_cb(cls_method_context_t hctx, const string& key, cls_rgw_gc_obj_info& info, void *param) { list *l = (list *)param; l->push_back(info); return 0; } static int gc_list_entries(cls_method_context_t hctx, const string& marker, uint32_t max, bool expired_only, list& entries, bool *truncated) { string key_iter; int ret = gc_iterate_entries(hctx, marker, expired_only, key_iter, max, truncated, gc_list_cb, &entries); return ret; } static int rgw_cls_gc_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_rgw_gc_list_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_cls_gc_list(): failed to decode entry\n"); return -EINVAL; } cls_rgw_gc_list_ret op_ret; int ret = gc_list_entries(hctx, op.marker, op.max, op.expired_only, op_ret.entries, &op_ret.truncated); if (ret < 0) return ret; ::encode(op_ret, *out); return 0; } static int gc_remove(cls_method_context_t hctx, list& tags) { list::iterator iter; for (iter = tags.begin(); iter != tags.end(); ++iter) { string& tag = *iter; cls_rgw_gc_obj_info info; int ret = gc_omap_get(hctx, GC_OBJ_NAME_INDEX, tag, &info); if (ret == -ENOENT) { CLS_LOG(0, "couldn't find tag in name index tag=%s\n", tag.c_str()); continue; } if (ret < 0) return ret; string time_key; get_time_key(info.time, &time_key); ret = gc_omap_remove(hctx, GC_OBJ_TIME_INDEX, time_key); if (ret < 0 && ret != -ENOENT) return ret; if (ret == -ENOENT) { CLS_LOG(0, "couldn't find key in time index key=%s\n", time_key.c_str()); } ret = gc_omap_remove(hctx, GC_OBJ_NAME_INDEX, tag); if (ret < 0 && ret != -ENOENT) return ret; } return 0; } static int rgw_cls_gc_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_rgw_gc_remove_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: rgw_cls_gc_remove(): failed to decode entry\n"); return -EINVAL; } return gc_remove(hctx, op.tags); } void __cls_init() { CLS_LOG(1, "Loaded rgw class!"); cls_register("rgw", &h_class); /* bucket index */ cls_register_cxx_method(h_class, "bucket_init_index", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_init_index, &h_rgw_bucket_init_index); cls_register_cxx_method(h_class, "bucket_set_tag_timeout", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_set_tag_timeout, &h_rgw_bucket_set_tag_timeout); cls_register_cxx_method(h_class, "bucket_list", CLS_METHOD_RD, rgw_bucket_list, &h_rgw_bucket_list); cls_register_cxx_method(h_class, "bucket_check_index", CLS_METHOD_RD, rgw_bucket_check_index, &h_rgw_bucket_check_index); cls_register_cxx_method(h_class, "bucket_rebuild_index", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_rebuild_index, &h_rgw_bucket_rebuild_index); cls_register_cxx_method(h_class, "bucket_prepare_op", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_prepare_op, &h_rgw_bucket_prepare_op); cls_register_cxx_method(h_class, "bucket_complete_op", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bucket_complete_op, &h_rgw_bucket_complete_op); cls_register_cxx_method(h_class, "bi_log_list", CLS_METHOD_RD, rgw_bi_log_list, &h_rgw_bi_log_list_op); cls_register_cxx_method(h_class, "bi_log_trim", CLS_METHOD_RD | CLS_METHOD_WR, rgw_bi_log_trim, &h_rgw_bi_log_list_op); cls_register_cxx_method(h_class, "dir_suggest_changes", CLS_METHOD_RD | CLS_METHOD_WR, rgw_dir_suggest_changes, &h_rgw_dir_suggest_changes); /* usage logging */ cls_register_cxx_method(h_class, "user_usage_log_add", CLS_METHOD_RD | CLS_METHOD_WR, rgw_user_usage_log_add, &h_rgw_user_usage_log_add); cls_register_cxx_method(h_class, "user_usage_log_read", CLS_METHOD_RD, rgw_user_usage_log_read, &h_rgw_user_usage_log_read); cls_register_cxx_method(h_class, "user_usage_log_trim", CLS_METHOD_RD | CLS_METHOD_WR, rgw_user_usage_log_trim, &h_rgw_user_usage_log_trim); /* garbage collection */ cls_register_cxx_method(h_class, "gc_set_entry", CLS_METHOD_RD | CLS_METHOD_WR, rgw_cls_gc_set_entry, &h_rgw_gc_set_entry); cls_register_cxx_method(h_class, "gc_defer_entry", CLS_METHOD_RD | CLS_METHOD_WR, rgw_cls_gc_defer_entry, &h_rgw_gc_set_entry); cls_register_cxx_method(h_class, "gc_list", CLS_METHOD_RD, rgw_cls_gc_list, &h_rgw_gc_list); cls_register_cxx_method(h_class, "gc_remove", CLS_METHOD_RD | CLS_METHOD_WR, rgw_cls_gc_remove, &h_rgw_gc_remove); return; } ceph-0.80.11/src/cls/rgw/cls_rgw_types.h0000664000175100017510000003716212623076744022112 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_RGW_TYPES_H #define CEPH_CLS_RGW_TYPES_H #include #include "include/types.h" #include "include/utime.h" #include "common/Formatter.h" #define CEPH_RGW_REMOVE 'r' #define CEPH_RGW_UPDATE 'u' #define CEPH_RGW_TAG_TIMEOUT 60*60*24 namespace ceph { class Formatter; } enum RGWPendingState { CLS_RGW_STATE_PENDING_MODIFY = 0, CLS_RGW_STATE_COMPLETE = 1, }; enum RGWModifyOp { CLS_RGW_OP_ADD = 0, CLS_RGW_OP_DEL = 1, CLS_RGW_OP_CANCEL = 2, CLS_RGW_OP_UNKNOWN = 3, }; struct rgw_bucket_pending_info { RGWPendingState state; utime_t timestamp; uint8_t op; rgw_bucket_pending_info() : state(CLS_RGW_STATE_PENDING_MODIFY), op(0) {} void encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); uint8_t s = (uint8_t)state; ::encode(s, bl); ::encode(timestamp, bl); ::encode(op, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); uint8_t s; ::decode(s, bl); state = (RGWPendingState)s; ::decode(timestamp, bl); ::decode(op, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_pending_info) struct rgw_bucket_dir_entry_meta { uint8_t category; uint64_t size; utime_t mtime; string etag; string owner; string owner_display_name; string content_type; rgw_bucket_dir_entry_meta() : category(0), size(0) { mtime.set_from_double(0); } void encode(bufferlist &bl) const { ENCODE_START(3, 3, bl); ::encode(category, bl); ::encode(size, bl); ::encode(mtime, bl); ::encode(etag, bl); ::encode(owner, bl); ::encode(owner_display_name, bl); ::encode(content_type, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl); ::decode(category, bl); ::decode(size, bl); ::decode(mtime, bl); ::decode(etag, bl); ::decode(owner, bl); ::decode(owner_display_name, bl); if (struct_v >= 2) ::decode(content_type, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_dir_entry_meta) template void encode_packed_val(T val, bufferlist& bl) { if ((uint64_t)val < 0x80) { ::encode((uint8_t)val, bl); } else { unsigned char c = 0x80; if ((uint64_t)val < 0x100) { c |= 1; ::encode(c, bl); ::encode((uint8_t)val, bl); } else if ((uint64_t)val <= 0x10000) { c |= 2; ::encode(c, bl); ::encode((uint16_t)val, bl); } else if ((uint64_t)val <= 0x1000000) { c |= 4; ::encode(c, bl); ::encode((uint32_t)val, bl); } else { c |= 8; ::encode(c, bl); ::encode((uint64_t)val, bl); } } } template void decode_packed_val(T& val, bufferlist::iterator& bl) { unsigned char c; ::decode(c, bl); if (c < 0x80) { val = c; return; } c &= ~0x80; switch (c) { case 1: { uint8_t v; ::decode(v, bl); val = v; } break; case 2: { uint16_t v; ::decode(v, bl); val = v; } break; case 4: { uint32_t v; ::decode(v, bl); val = v; } break; case 8: { uint64_t v; ::decode(v, bl); val = v; } break; default: throw buffer::error(); } } struct rgw_bucket_entry_ver { int64_t pool; uint64_t epoch; rgw_bucket_entry_ver() : pool(-1), epoch(0) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode_packed_val(pool, bl); ::encode_packed_val(epoch, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode_packed_val(pool, bl); ::decode_packed_val(epoch, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_entry_ver) struct rgw_bucket_dir_entry { std::string name; rgw_bucket_entry_ver ver; std::string locator; bool exists; struct rgw_bucket_dir_entry_meta meta; multimap pending_map; uint64_t index_ver; string tag; rgw_bucket_dir_entry() : exists(false), index_ver(0) {} void encode(bufferlist &bl) const { ENCODE_START(5, 3, bl); ::encode(name, bl); ::encode(ver.epoch, bl); ::encode(exists, bl); ::encode(meta, bl); ::encode(pending_map, bl); ::encode(locator, bl); ::encode(ver, bl); ::encode_packed_val(index_ver, bl); ::encode(tag, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl); ::decode(name, bl); ::decode(ver.epoch, bl); ::decode(exists, bl); ::decode(meta, bl); ::decode(pending_map, bl); if (struct_v >= 2) { ::decode(locator, bl); } if (struct_v >= 4) { ::decode(ver, bl); } else { ver.pool = -1; } if (struct_v >= 5) { ::decode_packed_val(index_ver, bl); ::decode(tag, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_dir_entry) struct rgw_bi_log_entry { string id; string object; utime_t timestamp; rgw_bucket_entry_ver ver; RGWModifyOp op; RGWPendingState state; uint64_t index_ver; string tag; rgw_bi_log_entry() : op(CLS_RGW_OP_UNKNOWN), state(CLS_RGW_STATE_PENDING_MODIFY), index_ver(0) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(id, bl); ::encode(object, bl); ::encode(timestamp, bl); ::encode(ver, bl); ::encode(tag, bl); uint8_t c = (uint8_t)op; ::encode(c, bl); c = (uint8_t)state; ::encode(c, bl); encode_packed_val(index_ver, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(id, bl); ::decode(object, bl); ::decode(timestamp, bl); ::decode(ver, bl); ::decode(tag, bl); uint8_t c; ::decode(c, bl); op = (RGWModifyOp)c; ::decode(c, bl); state = (RGWPendingState)c; decode_packed_val(index_ver, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bi_log_entry) struct rgw_bucket_category_stats { uint64_t total_size; uint64_t total_size_rounded; uint64_t num_entries; rgw_bucket_category_stats() : total_size(0), total_size_rounded(0), num_entries(0) {} void encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(total_size, bl); ::encode(total_size_rounded, bl); ::encode(num_entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(total_size, bl); ::decode(total_size_rounded, bl); ::decode(num_entries, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_category_stats) struct rgw_bucket_dir_header { map stats; uint64_t tag_timeout; uint64_t ver; uint64_t master_ver; string max_marker; rgw_bucket_dir_header() : tag_timeout(0), ver(0), master_ver(0) {} void encode(bufferlist &bl) const { ENCODE_START(5, 2, bl); ::encode(stats, bl); ::encode(tag_timeout, bl); ::encode(ver, bl); ::encode(master_ver, bl); ::encode(max_marker, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl); ::decode(stats, bl); if (struct_v > 2) { ::decode(tag_timeout, bl); } else { tag_timeout = 0; } if (struct_v >= 4) { ::decode(ver, bl); ::decode(master_ver, bl); } else { ver = 0; } if (struct_v >= 5) { ::decode(max_marker, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_dir_header) struct rgw_bucket_dir { struct rgw_bucket_dir_header header; std::map m; void encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(header, bl); ::encode(m, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(header, bl); ::decode(m, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_bucket_dir) struct rgw_usage_data { uint64_t bytes_sent; uint64_t bytes_received; uint64_t ops; uint64_t successful_ops; rgw_usage_data() : bytes_sent(0), bytes_received(0), ops(0), successful_ops(0) {} rgw_usage_data(uint64_t sent, uint64_t received) : bytes_sent(sent), bytes_received(received), ops(0), successful_ops(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(bytes_sent, bl); ::encode(bytes_received, bl); ::encode(ops, bl); ::encode(successful_ops, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(bytes_sent, bl); ::decode(bytes_received, bl); ::decode(ops, bl); ::decode(successful_ops, bl); DECODE_FINISH(bl); } void aggregate(const rgw_usage_data& usage) { bytes_sent += usage.bytes_sent; bytes_received += usage.bytes_received; ops += usage.ops; successful_ops += usage.successful_ops; } }; WRITE_CLASS_ENCODER(rgw_usage_data) struct rgw_usage_log_entry { string owner; string bucket; uint64_t epoch; rgw_usage_data total_usage; /* this one is kept for backwards compatibility */ map usage_map; rgw_usage_log_entry() : epoch(0) {} rgw_usage_log_entry(string& o, string& b) : owner(o), bucket(b), epoch(0) {} void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(owner, bl); ::encode(bucket, bl); ::encode(epoch, bl); ::encode(total_usage.bytes_sent, bl); ::encode(total_usage.bytes_received, bl); ::encode(total_usage.ops, bl); ::encode(total_usage.successful_ops, bl); ::encode(usage_map, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(owner, bl); ::decode(bucket, bl); ::decode(epoch, bl); ::decode(total_usage.bytes_sent, bl); ::decode(total_usage.bytes_received, bl); ::decode(total_usage.ops, bl); ::decode(total_usage.successful_ops, bl); if (struct_v < 2) { usage_map[""] = total_usage; } else { ::decode(usage_map, bl); } DECODE_FINISH(bl); } void aggregate(const rgw_usage_log_entry& e, map *categories = NULL) { if (owner.empty()) { owner = e.owner; bucket = e.bucket; epoch = e.epoch; } map::const_iterator iter; for (iter = e.usage_map.begin(); iter != e.usage_map.end(); ++iter) { if (!categories || !categories->size() || categories->count(iter->first)) { add(iter->first, iter->second); } } } void sum(rgw_usage_data& usage, map& categories) const { usage = rgw_usage_data(); for (map::const_iterator iter = usage_map.begin(); iter != usage_map.end(); ++iter) { if (!categories.size() || categories.count(iter->first)) { usage.aggregate(iter->second); } } } void add(const string& category, const rgw_usage_data& data) { usage_map[category].aggregate(data); total_usage.aggregate(data); } }; WRITE_CLASS_ENCODER(rgw_usage_log_entry) struct rgw_usage_log_info { vector entries; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); DECODE_FINISH(bl); } rgw_usage_log_info() {} }; WRITE_CLASS_ENCODER(rgw_usage_log_info) struct rgw_user_bucket { string user; string bucket; rgw_user_bucket() {} rgw_user_bucket(string &u, string& b) : user(u), bucket(b) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(user, bl); ::encode(bucket, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(user, bl); ::decode(bucket, bl); DECODE_FINISH(bl); } bool operator<(const rgw_user_bucket& ub2) const { int comp = user.compare(ub2.user); if (comp < 0) return true; else if (!comp) return bucket.compare(ub2.bucket) < 0; return false; } }; WRITE_CLASS_ENCODER(rgw_user_bucket) enum cls_rgw_gc_op { CLS_RGW_GC_DEL_OBJ, CLS_RGW_GC_DEL_BUCKET, }; struct cls_rgw_obj { string pool; string oid; string key; cls_rgw_obj() {} cls_rgw_obj(string& _p, string& _o) : pool(_p), oid(_o) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(pool, bl); ::encode(oid, bl); ::encode(key, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(pool, bl); ::decode(oid, bl); ::decode(key, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_string("pool", pool); f->dump_string("oid", oid); f->dump_string("key", key); } static void generate_test_instances(list& ls) { ls.push_back(new cls_rgw_obj); ls.push_back(new cls_rgw_obj); ls.back()->pool = "mypool"; ls.back()->oid = "myoid"; ls.back()->key = "mykey"; } }; WRITE_CLASS_ENCODER(cls_rgw_obj) struct cls_rgw_obj_chain { list objs; cls_rgw_obj_chain() {} void push_obj(string& pool, string& oid, string& key) { cls_rgw_obj obj; obj.pool = pool; obj.oid = oid; obj.key = key; objs.push_back(obj); } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(objs, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(objs, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->open_array_section("objs"); for (list::const_iterator p = objs.begin(); p != objs.end(); ++p) { f->open_object_section("obj"); p->dump(f); f->close_section(); } f->close_section(); } static void generate_test_instances(list& ls) { ls.push_back(new cls_rgw_obj_chain); } }; WRITE_CLASS_ENCODER(cls_rgw_obj_chain) struct cls_rgw_gc_obj_info { string tag; cls_rgw_obj_chain chain; utime_t time; cls_rgw_gc_obj_info() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(tag, bl); ::encode(chain, bl); ::encode(time, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(tag, bl); ::decode(chain, bl); ::decode(time, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_string("tag", tag); f->open_object_section("chain"); chain.dump(f); f->close_section(); f->dump_stream("time") << time; } static void generate_test_instances(list& ls) { ls.push_back(new cls_rgw_gc_obj_info); ls.push_back(new cls_rgw_gc_obj_info); ls.back()->tag = "footag"; ls.back()->time = utime_t(21, 32); } }; WRITE_CLASS_ENCODER(cls_rgw_gc_obj_info) #endif ceph-0.80.11/src/cls/rgw/cls_rgw_ops.h0000664000175100017510000002647112623076744021550 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_RGW_OPS_H #define CEPH_CLS_RGW_OPS_H #include #include "include/types.h" #include "cls/rgw/cls_rgw_types.h" struct rgw_cls_tag_timeout_op { uint64_t tag_timeout; rgw_cls_tag_timeout_op() : tag_timeout(0) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(tag_timeout, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(tag_timeout, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(rgw_cls_tag_timeout_op) struct rgw_cls_obj_prepare_op { RGWModifyOp op; string name; string tag; string locator; bool log_op; rgw_cls_obj_prepare_op() : op(CLS_RGW_OP_UNKNOWN), log_op(false) {} void encode(bufferlist &bl) const { ENCODE_START(4, 3, bl); uint8_t c = (uint8_t)op; ::encode(c, bl); ::encode(name, bl); ::encode(tag, bl); ::encode(locator, bl); ::encode(log_op, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl); uint8_t c; ::decode(c, bl); op = (RGWModifyOp)c; ::decode(name, bl); ::decode(tag, bl); if (struct_v >= 2) { ::decode(locator, bl); } if (struct_v >= 4) { ::decode(log_op, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_cls_obj_prepare_op) struct rgw_cls_obj_complete_op { RGWModifyOp op; string name; string locator; rgw_bucket_entry_ver ver; struct rgw_bucket_dir_entry_meta meta; string tag; bool log_op; list remove_objs; rgw_cls_obj_complete_op() : op(CLS_RGW_OP_ADD), log_op(false) {} void encode(bufferlist &bl) const { ENCODE_START(6, 3, bl); uint8_t c = (uint8_t)op; ::encode(c, bl); ::encode(name, bl); ::encode(ver.epoch, bl); ::encode(meta, bl); ::encode(tag, bl); ::encode(locator, bl); ::encode(remove_objs, bl); ::encode(ver, bl); ::encode(log_op, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl); uint8_t c; ::decode(c, bl); op = (RGWModifyOp)c; ::decode(name, bl); ::decode(ver.epoch, bl); ::decode(meta, bl); ::decode(tag, bl); if (struct_v >= 2) { ::decode(locator, bl); } if (struct_v >= 4) { ::decode(remove_objs, bl); } if (struct_v >= 5) { ::decode(ver, bl); } else { ver.pool = -1; } if (struct_v >= 6) { ::decode(log_op, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_cls_obj_complete_op) struct rgw_cls_list_op { string start_obj; uint32_t num_entries; string filter_prefix; rgw_cls_list_op() : num_entries(0) {} void encode(bufferlist &bl) const { ENCODE_START(3, 2, bl); ::encode(start_obj, bl); ::encode(num_entries, bl); ::encode(filter_prefix, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl); ::decode(start_obj, bl); ::decode(num_entries, bl); if (struct_v >= 3) ::decode(filter_prefix, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_cls_list_op) struct rgw_cls_list_ret { rgw_bucket_dir dir; bool is_truncated; rgw_cls_list_ret() : is_truncated(false) {} void encode(bufferlist &bl) const { ENCODE_START(2, 2, bl); ::encode(dir, bl); ::encode(is_truncated, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); ::decode(dir, bl); ::decode(is_truncated, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_cls_list_ret) struct rgw_cls_check_index_ret { rgw_bucket_dir_header existing_header; rgw_bucket_dir_header calculated_header; rgw_cls_check_index_ret() {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(existing_header, bl); ::encode(calculated_header, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START(1, bl); ::decode(existing_header, bl); ::decode(calculated_header, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rgw_cls_check_index_ret) struct rgw_cls_usage_log_add_op { rgw_usage_log_info info; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(info, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(info, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(rgw_cls_usage_log_add_op) struct rgw_cls_usage_log_read_op { uint64_t start_epoch; uint64_t end_epoch; string owner; string iter; // should be empty for the first call, non empty for subsequent calls uint32_t max_entries; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(start_epoch, bl); ::encode(end_epoch, bl); ::encode(owner, bl); ::encode(iter, bl); ::encode(max_entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(start_epoch, bl); ::decode(end_epoch, bl); ::decode(owner, bl); ::decode(iter, bl); ::decode(max_entries, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(rgw_cls_usage_log_read_op) struct rgw_cls_usage_log_read_ret { map usage; bool truncated; string next_iter; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(usage, bl); ::encode(truncated, bl); ::encode(next_iter, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(usage, bl); ::decode(truncated, bl); ::decode(next_iter, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(rgw_cls_usage_log_read_ret) struct rgw_cls_usage_log_trim_op { uint64_t start_epoch; uint64_t end_epoch; string user; void encode(bufferlist& bl) const { ENCODE_START(2, 2, bl); ::encode(start_epoch, bl); ::encode(end_epoch, bl); ::encode(user, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(start_epoch, bl); ::decode(end_epoch, bl); ::decode(user, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(rgw_cls_usage_log_trim_op) struct cls_rgw_gc_set_entry_op { uint32_t expiration_secs; cls_rgw_gc_obj_info info; cls_rgw_gc_set_entry_op() : expiration_secs(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(expiration_secs, bl); ::encode(info, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(expiration_secs, bl); ::decode(info, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_gc_set_entry_op) struct cls_rgw_gc_defer_entry_op { uint32_t expiration_secs; string tag; cls_rgw_gc_defer_entry_op() : expiration_secs(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(expiration_secs, bl); ::encode(tag, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(expiration_secs, bl); ::decode(tag, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_gc_defer_entry_op) struct cls_rgw_gc_list_op { string marker; uint32_t max; bool expired_only; cls_rgw_gc_list_op() : max(0), expired_only(true) {} void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(marker, bl); ::encode(max, bl); ::encode(expired_only, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(marker, bl); ::decode(max, bl); if (struct_v >= 2) { ::decode(expired_only, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_gc_list_op) struct cls_rgw_gc_list_ret { list entries; bool truncated; cls_rgw_gc_list_ret() : truncated(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ::encode(truncated, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); ::decode(truncated, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_gc_list_ret) struct cls_rgw_gc_remove_op { list tags; cls_rgw_gc_remove_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(tags, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(tags, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_gc_remove_op) struct cls_rgw_bi_log_list_op { string marker; uint32_t max; cls_rgw_bi_log_list_op() : max(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(marker, bl); ::encode(max, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(marker, bl); ::decode(max, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_bi_log_list_op) struct cls_rgw_bi_log_trim_op { string start_marker; string end_marker; cls_rgw_bi_log_trim_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(start_marker, bl); ::encode(end_marker, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(start_marker, bl); ::decode(end_marker, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_bi_log_trim_op) struct cls_rgw_bi_log_list_ret { list entries; bool truncated; cls_rgw_bi_log_list_ret() : truncated(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ::encode(truncated, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); ::decode(truncated, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_rgw_bi_log_list_ret) #endif ceph-0.80.11/src/cls/rgw/cls_rgw_client.h0000664000175100017510000000615712623076744022224 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_RGW_CLIENT_H #define CEPH_CLS_RGW_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" #include "cls_rgw_types.h" #include "common/RefCountedObj.h" class RGWGetDirHeader_CB : public RefCountedObject { public: virtual ~RGWGetDirHeader_CB() {} virtual void handle_response(int r, rgw_bucket_dir_header& header) = 0; }; /* bucket index */ void cls_rgw_bucket_init(librados::ObjectWriteOperation& o); void cls_rgw_bucket_set_tag_timeout(librados::ObjectWriteOperation& o, uint64_t tag_timeout); void cls_rgw_bucket_prepare_op(librados::ObjectWriteOperation& o, RGWModifyOp op, string& tag, string& name, string& locator, bool log_op); void cls_rgw_bucket_complete_op(librados::ObjectWriteOperation& o, RGWModifyOp op, string& tag, rgw_bucket_entry_ver& ver, string& name, rgw_bucket_dir_entry_meta& dir_meta, list *remove_objs, bool log_op); int cls_rgw_list_op(librados::IoCtx& io_ctx, string& oid, string& start_obj, string& filter_prefix, uint32_t num_entries, rgw_bucket_dir *dir, bool *is_truncated); int cls_rgw_bucket_check_index_op(librados::IoCtx& io_ctx, string& oid, rgw_bucket_dir_header *existing_header, rgw_bucket_dir_header *calculated_header); int cls_rgw_bucket_rebuild_index_op(librados::IoCtx& io_ctx, string& oid); int cls_rgw_get_dir_header(librados::IoCtx& io_ctx, string& oid, rgw_bucket_dir_header *header); int cls_rgw_get_dir_header_async(librados::IoCtx& io_ctx, string& oid, RGWGetDirHeader_CB *ctx); void cls_rgw_encode_suggestion(char op, rgw_bucket_dir_entry& dirent, bufferlist& updates); void cls_rgw_suggest_changes(librados::ObjectWriteOperation& o, bufferlist& updates); /* bucket index log */ int cls_rgw_bi_log_list(librados::IoCtx& io_ctx, string& oid, string& marker, uint32_t max, list& entries, bool *truncated); int cls_rgw_bi_log_trim(librados::IoCtx& io_ctx, string& oid, string& start_marker, string& end_marker); /* usage logging */ int cls_rgw_usage_log_read(librados::IoCtx& io_ctx, string& oid, string& user, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, string& read_iter, map& usage, bool *is_truncated); void cls_rgw_usage_log_trim(librados::ObjectWriteOperation& op, string& user, uint64_t start_epoch, uint64_t end_epoch); void cls_rgw_usage_log_add(librados::ObjectWriteOperation& op, rgw_usage_log_info& info); /* garbage collection */ void cls_rgw_gc_set_entry(librados::ObjectWriteOperation& op, uint32_t expiration_secs, cls_rgw_gc_obj_info& info); void cls_rgw_gc_defer_entry(librados::ObjectWriteOperation& op, uint32_t expiration_secs, const string& tag); int cls_rgw_gc_list(librados::IoCtx& io_ctx, string& oid, string& marker, uint32_t max, bool expired_only, list& entries, bool *truncated); void cls_rgw_gc_remove(librados::ObjectWriteOperation& op, const list& tags); #endif ceph-0.80.11/src/cls/hello/0000775000175100017510000000000012623077035017342 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/hello/cls_hello.cc0000664000175100017510000002253412623076744021631 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * This is a simple example RADOS class, designed to be usable as a * template from implementing new methods. * * Our goal here is to illustrate the interface between the OSD and * the class and demonstrate what kinds of things a class can do. * * Note that any *real* class will probably have a much more * sophisticated protocol dealing with the in and out data buffers. * For an example of the model that we've settled on for handling that * in a clean way, please refer to cls_lock or cls_version for * relatively simple examples of how the parameter encoding can be * encoded in a way that allows for forward and backward compatibility * between client vs class revisions. */ /* * A quick note about bufferlists: * * The bufferlist class allows memory buffers to be concatenated, * truncated, spliced, "copied," encoded/embedded, and decoded. For * most operations no actual data is ever copied, making bufferlists * very convenient for efficiently passing data around. * * bufferlist is actually a typedef of buffer::list, and is defined in * include/buffer.h (and implemented in common/buffer.cc). */ #include #include #include #include #include "objclass/objclass.h" CLS_VER(1,0) CLS_NAME(hello) cls_handle_t h_class; cls_method_handle_t h_say_hello; cls_method_handle_t h_record_hello; cls_method_handle_t h_replay; cls_method_handle_t h_writes_dont_return_data; cls_method_handle_t h_turn_it_to_11; cls_method_handle_t h_bad_reader; cls_method_handle_t h_bad_writer; /** * say hello - a "read" method that does not depend on the object * * This is an example of a method that does some computation and * returns data to the caller, without depending on the local object * content. */ static int say_hello(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // see if the input data from the client matches what this method // expects to receive. your class can fill this buffer with what it // wants. if (in->length() > 100) return -EINVAL; // we generate our reply out->append("Hello, "); if (in->length() == 0) out->append("world"); else out->append(*in); out->append("!"); // this return value will be returned back to the librados caller return 0; } /** * record hello - a "write" method that creates an object * * This method modifies a local object (in this case, by creating it * if it doesn't exist). We make multiple write calls (write, * setxattr) which are accumulated and applied as an atomic * transaction. */ static int record_hello(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // we can write arbitrary stuff to the ceph-osd debug log. each log // message is accompanied by an integer log level. smaller is // "louder". how much of this makes it into the log is controlled // by the debug_cls option on the ceph-osd, similar to how other log // levels are controlled. this message, at level 20, will generally // not be seen by anyone unless debug_cls is set at 20 or higher. CLS_LOG(20, "in record_hello"); // see if the input data from the client matches what this method // expects to receive. your class can fill this buffer with what it // wants. if (in->length() > 100) return -EINVAL; // only say hello to non-existent objects if (cls_cxx_stat(hctx, NULL, NULL) == 0) return -EEXIST; bufferlist content; content.append("Hello, "); if (in->length() == 0) content.append("world"); else content.append(*in); content.append("!"); // create/write the object int r = cls_cxx_write_full(hctx, &content); if (r < 0) return r; // also make note of who said it entity_inst_t origin; cls_get_request_origin(hctx, &origin); ostringstream ss; ss << origin; bufferlist attrbl; attrbl.append(ss.str()); r = cls_cxx_setxattr(hctx, "said_by", &attrbl); if (r < 0) return r; // For write operations, there are two possible outcomes: // // * For a failure, we return a negative error code. The out // buffer can contain any data that we want, and that data will // be returned to the caller. No change is made to the object. // // * For a success, we must return 0 and *no* data in the out // buffer. This is becaues the OSD does not log write result // codes or output buffers and we need a replayed/resent // operation (e.g., after a TCP disconnect) to be idempotent. // // If a class returns a positive value or puts data in the out // buffer, the OSD code will ignore it and return 0 to the // client. return 0; } static int writes_dont_return_data(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // make some change to the object bufferlist attrbl; attrbl.append("bar"); int r = cls_cxx_setxattr(hctx, "foo", &attrbl); if (r < 0) return r; if (in->length() > 0) { // note that if we return anything < 0 (an error), this // operation/transaction will abort, and the setattr above will // never happen. however, we *can* return data on error. out->append("too much input data!"); return -EINVAL; } // try to return some data. note that this *won't* reach the // client! see the matching test case in test_cls_hello.cc. out->append("you will never see this"); // if we try to return anything > 0 here the client will see 0. return 42; } /** * replay - a "read" method to get a previously recorded hello * * This is a read method that will retrieve a previously recorded * hello statement. */ static int replay(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // read contents out of the on-disk object. our behavior can be a // function of either the request alone, or the request and the // on-disk state, depending on whether the RD flag is specified when // registering the method (see the __cls__init function below). int r = cls_cxx_read(hctx, 0, 1100, out); if (r < 0) return r; // note that our return value need not be the length of the returned // data; it can be whatever value we want: positive, zero or // negative (this is a read). return 0; } /** * turn_it_to_11 - a "write" method that mutates existing object data * * A write method can depend on previous object content (i.e., perform * a read/modify/write operation). This atomically transitions the * object state from the old content to the new content. */ static int turn_it_to_11(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // see if the input data from the client matches what this method // expects to receive. your class can fill this buffer with what it // wants. if (in->length() != 0) return -EINVAL; bufferlist previous; int r = cls_cxx_read(hctx, 0, 1100, &previous); if (r < 0) return r; std::string str(previous.c_str(), previous.length()); std::transform(str.begin(), str.end(), str.begin(), ::toupper); previous.clear(); previous.append(str); // replace previous byte data content (write_full == truncate(0) + write) r = cls_cxx_write_full(hctx, &previous); if (r < 0) return r; // record who did it entity_inst_t origin; cls_get_request_origin(hctx, &origin); ostringstream ss; ss << origin; bufferlist attrbl; attrbl.append(ss.str()); r = cls_cxx_setxattr(hctx, "amplified_by", &attrbl); if (r < 0) return r; // return value is 0 for success; out buffer is empty. return 0; } /** * example method that does not behave * * This method is registered as WR but tries to read */ static int bad_reader(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { return cls_cxx_read(hctx, 0, 100, out); } /** * example method that does not behave * * This method is registered as RD but tries to write */ static int bad_writer(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { return cls_cxx_write_full(hctx, in); } /** * initialize class * * We do two things here: we register the new class, and then register * all of the class's methods. */ void __cls_init() { // this log message, at level 0, will always appear in the ceph-osd // log file. CLS_LOG(0, "loading cls_hello"); cls_register("hello", &h_class); // There are two flags we specify for methods: // // RD : whether this method (may) read prior object state // WR : whether this method (may) write or update the object // // A method can be RD, WR, neither, or both. If a method does // neither, the data it returns to the caller is a function of the // request and not the object contents. cls_register_cxx_method(h_class, "say_hello", CLS_METHOD_RD, say_hello, &h_say_hello); cls_register_cxx_method(h_class, "record_hello", CLS_METHOD_WR, record_hello, &h_record_hello); cls_register_cxx_method(h_class, "writes_dont_return_data", CLS_METHOD_WR, writes_dont_return_data, &h_writes_dont_return_data); cls_register_cxx_method(h_class, "replay", CLS_METHOD_RD, replay, &h_replay); // RD | WR is a read-modify-write method. cls_register_cxx_method(h_class, "turn_it_to_11", CLS_METHOD_RD | CLS_METHOD_WR, turn_it_to_11, &h_turn_it_to_11); // counter-examples cls_register_cxx_method(h_class, "bad_reader", CLS_METHOD_WR, bad_reader, &h_bad_reader); cls_register_cxx_method(h_class, "bad_writer", CLS_METHOD_RD, bad_writer, &h_bad_writer); } ceph-0.80.11/src/cls/refcount/0000775000175100017510000000000012623077035020064 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/refcount/cls_refcount.cc0000664000175100017510000001253512623076744023075 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "objclass/objclass.h" #include "cls/refcount/cls_refcount_ops.h" #include "common/Clock.h" #include "global/global_context.h" CLS_VER(1,0) CLS_NAME(refcount) cls_handle_t h_class; cls_method_handle_t h_refcount_get; cls_method_handle_t h_refcount_put; cls_method_handle_t h_refcount_set; cls_method_handle_t h_refcount_read; #define REFCOUNT_ATTR "refcount" struct obj_refcount { map refs; obj_refcount() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(refs, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(refs, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(obj_refcount) static string wildcard_tag; static int read_refcount(cls_method_context_t hctx, bool implicit_ref, obj_refcount *objr) { bufferlist bl; objr->refs.clear(); int ret = cls_cxx_getxattr(hctx, REFCOUNT_ATTR, &bl); if (ret == -ENOENT || ret == -ENODATA) { if (implicit_ref) { objr->refs[wildcard_tag] = true; } return 0; } if (ret < 0) return ret; try { bufferlist::iterator iter = bl.begin(); ::decode(*objr, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: read_refcount(): failed to decode refcount entry\n"); return -EIO; } return 0; } static int set_refcount(cls_method_context_t hctx, map& refs) { bufferlist bl; struct obj_refcount objr; objr.refs = refs; ::encode(objr, bl); int ret = cls_cxx_setxattr(hctx, REFCOUNT_ATTR, &bl); if (ret < 0) return ret; return 0; } static int cls_rc_refcount_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_refcount_get_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_rc_refcount_get(): failed to decode entry\n"); return -EINVAL; } obj_refcount objr; int ret = read_refcount(hctx, op.implicit_ref, &objr); if (ret < 0) return ret; CLS_LOG(10, "cls_rc_refcount_get() tag=%s\n", op.tag.c_str()); objr.refs[op.tag] = true; ret = set_refcount(hctx, objr.refs); if (ret < 0) return ret; return 0; } static int cls_rc_refcount_put(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_refcount_put_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_rc_refcount_put(): failed to decode entry\n"); return -EINVAL; } obj_refcount objr; int ret = read_refcount(hctx, op.implicit_ref, &objr); if (ret < 0) return ret; if (objr.refs.empty()) {// shouldn't happen! CLS_LOG(0, "ERROR: cls_rc_refcount_put() was called without any references!\n"); return -EINVAL; } CLS_LOG(10, "cls_rc_refcount_put() tag=%s\n", op.tag.c_str()); bool found = false; map::iterator iter = objr.refs.find(op.tag); if (iter != objr.refs.end()) { found = true; } else if (op.implicit_ref) { iter = objr.refs.find(wildcard_tag); if (iter != objr.refs.end()) { found = true; } } if (!found) return 0; objr.refs.erase(iter); if (objr.refs.empty()) { return cls_cxx_remove(hctx); } ret = set_refcount(hctx, objr.refs); if (ret < 0) return ret; return 0; } static int cls_rc_refcount_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_refcount_set_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_refcount_set(): failed to decode entry\n"); return -EINVAL; } if (!op.refs.size()) { return cls_cxx_remove(hctx); } obj_refcount objr; list::iterator iter; for (iter = op.refs.begin(); iter != op.refs.end(); ++iter) { objr.refs[*iter] = true; } int ret = set_refcount(hctx, objr.refs); if (ret < 0) return ret; return 0; } static int cls_rc_refcount_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_refcount_read_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_rc_refcount_read(): failed to decode entry\n"); return -EINVAL; } obj_refcount objr; cls_refcount_read_ret read_ret; int ret = read_refcount(hctx, op.implicit_ref, &objr); if (ret < 0) return ret; map::iterator iter; for (iter = objr.refs.begin(); iter != objr.refs.end(); ++iter) { read_ret.refs.push_back(iter->first); } ::encode(read_ret, *out); return 0; } void __cls_init() { CLS_LOG(1, "Loaded refcount class!"); cls_register("refcount", &h_class); /* refcount */ cls_register_cxx_method(h_class, "get", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_refcount_get, &h_refcount_get); cls_register_cxx_method(h_class, "put", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_refcount_put, &h_refcount_put); cls_register_cxx_method(h_class, "set", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_refcount_set, &h_refcount_set); cls_register_cxx_method(h_class, "read", CLS_METHOD_RD, cls_rc_refcount_read, &h_refcount_read); return; } ceph-0.80.11/src/cls/refcount/cls_refcount_ops.cc0000664000175100017510000000402212623076744023746 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "cls_refcount_ops.h" #include "common/Formatter.h" #include "common/ceph_json.h" void cls_refcount_get_op::dump(ceph::Formatter *f) const { f->dump_string("tag", tag); f->dump_int("implicit_ref", (int)implicit_ref); } void cls_refcount_get_op::generate_test_instances(list& ls) { ls.push_back(new cls_refcount_get_op); ls.push_back(new cls_refcount_get_op); ls.back()->tag = "foo"; ls.back()->implicit_ref = true; } void cls_refcount_put_op::dump(ceph::Formatter *f) const { f->dump_string("tag", tag); f->dump_int("implicit_ref", (int)implicit_ref); } void cls_refcount_put_op::generate_test_instances(list& ls) { ls.push_back(new cls_refcount_put_op); ls.push_back(new cls_refcount_put_op); ls.back()->tag = "foo"; ls.back()->implicit_ref = true; } void cls_refcount_set_op::dump(ceph::Formatter *f) const { encode_json("refs", refs, f); } void cls_refcount_set_op::generate_test_instances(list& ls) { ls.push_back(new cls_refcount_set_op); ls.push_back(new cls_refcount_set_op); ls.back()->refs.push_back("foo"); ls.back()->refs.push_back("bar"); } void cls_refcount_read_op::dump(ceph::Formatter *f) const { f->dump_int("implicit_ref", (int)implicit_ref); } void cls_refcount_read_op::generate_test_instances(list& ls) { ls.push_back(new cls_refcount_read_op); ls.push_back(new cls_refcount_read_op); ls.back()->implicit_ref = true; } void cls_refcount_read_ret::dump(ceph::Formatter *f) const { f->open_array_section("refs"); for (list::const_iterator p = refs.begin(); p != refs.end(); ++p) f->dump_string("ref", *p); f->close_section(); } void cls_refcount_read_ret::generate_test_instances(list& ls) { ls.push_back(new cls_refcount_read_ret); ls.push_back(new cls_refcount_read_ret); ls.back()->refs.push_back("foo"); ls.back()->refs.push_back("bar"); } ceph-0.80.11/src/cls/refcount/cls_refcount_client.cc0000664000175100017510000000252512623076744024431 0ustar jenkins-buildjenkins-build#include #include "include/types.h" #include "cls/refcount/cls_refcount_ops.h" #include "include/rados/librados.hpp" using namespace librados; void cls_refcount_get(librados::ObjectWriteOperation& op, const string& tag, bool implicit_ref) { bufferlist in; cls_refcount_get_op call; call.tag = tag; call.implicit_ref = implicit_ref; ::encode(call, in); op.exec("refcount", "get", in); } void cls_refcount_put(librados::ObjectWriteOperation& op, const string& tag, bool implicit_ref) { bufferlist in; cls_refcount_put_op call; call.tag = tag; call.implicit_ref = implicit_ref; ::encode(call, in); op.exec("refcount", "put", in); } void cls_refcount_set(librados::ObjectWriteOperation& op, list& refs) { bufferlist in; cls_refcount_set_op call; call.refs = refs; ::encode(call, in); op.exec("refcount", "set", in); } int cls_refcount_read(librados::IoCtx& io_ctx, string& oid, list *refs, bool implicit_ref) { bufferlist in, out; cls_refcount_read_op call; call.implicit_ref = implicit_ref; ::encode(call, in); int r = io_ctx.exec(oid, "refcount", "read", in, out); if (r < 0) return r; cls_refcount_read_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } *refs = ret.refs; return r; } ceph-0.80.11/src/cls/refcount/cls_refcount_ops.h0000664000175100017510000000570212623076744023616 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_REFCOUNT_OPS_H #define CEPH_CLS_REFCOUNT_OPS_H #include #include "include/types.h" class Formatter; struct cls_refcount_get_op { string tag; bool implicit_ref; cls_refcount_get_op() : implicit_ref(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(tag, bl); ::encode(implicit_ref, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(tag, bl); ::decode(implicit_ref, bl); DECODE_FINISH(bl); } void dump(ceph::Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_refcount_get_op) struct cls_refcount_put_op { string tag; bool implicit_ref; // assume wildcard reference for // objects without a set ref cls_refcount_put_op() : implicit_ref(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(tag, bl); ::encode(implicit_ref, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(tag, bl); ::decode(implicit_ref, bl); DECODE_FINISH(bl); } void dump(ceph::Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_refcount_put_op) struct cls_refcount_set_op { list refs; cls_refcount_set_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(refs, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(refs, bl); DECODE_FINISH(bl); } void dump(ceph::Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_refcount_set_op) struct cls_refcount_read_op { bool implicit_ref; // assume wildcard reference for // objects without a set ref cls_refcount_read_op() : implicit_ref(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(implicit_ref, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(implicit_ref, bl); DECODE_FINISH(bl); } void dump(ceph::Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_refcount_read_op) struct cls_refcount_read_ret { list refs; cls_refcount_read_ret() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(refs, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(refs, bl); DECODE_FINISH(bl); } void dump(ceph::Formatter *f) const; static void generate_test_instances(list& ls); }; WRITE_CLASS_ENCODER(cls_refcount_read_ret) #endif ceph-0.80.11/src/cls/refcount/cls_refcount_client.h0000664000175100017510000000361212623076744024271 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_REFCOUNT_CLIENT_H #define CEPH_CLS_REFCOUNT_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" /* * refcount objclass * * The refcount objclass implements a refcounting scheme that allows having multiple references * to a single rados object. The canonical way to use it is to add a reference and to remove a * reference using a specific tag. This way we ensure that refcounting operations are idempotent, * that is, a single client can only increase/decrease the refcount once using a single tag, so * any replay of operations (implicit or explicit) is possible. * * So, the regular usage would be to create an object, to increase the refcount. Then, when * wanting to have another reference to it, increase the refcount using a different tag. When * removing a reference it is required to drop the refcount (using the same tag that was used * for that reference). When the refcount drops to zero, the object is removed automaticfally. * * In order to maintain backwards compatibility with objects that were created without having * their refcount increased, the implicit_ref was added. Any object that was created without * having it's refcount increased (explicitly) is having an implicit refcount of 1. Since * we don't have a tag for this refcount, we consider this tag as a wildcard. So if the refcount * is being decreased by an unknown tag and we still have one wildcard tag, we'll accept it * as the relevant tag, and the refcount will be decreased. */ void cls_refcount_get(librados::ObjectWriteOperation& op, const string& tag, bool implicit_ref = false); void cls_refcount_put(librados::ObjectWriteOperation& op, const string& tag, bool implicit_ref = false); void cls_refcount_set(librados::ObjectWriteOperation& op, list& refs); int cls_refcount_read(librados::IoCtx& io_ctx, string& oid, list *refs, bool implicit_ref = false); #endif ceph-0.80.11/src/cls/log/0000775000175100017510000000000012623077035017020 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/log/cls_log.cc0000664000175100017510000001614212623076744020763 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "objclass/objclass.h" #include "cls_log_types.h" #include "cls_log_ops.h" #include "global/global_context.h" CLS_VER(1,0) CLS_NAME(log) cls_handle_t h_class; cls_method_handle_t h_log_add; cls_method_handle_t h_log_list; cls_method_handle_t h_log_trim; cls_method_handle_t h_log_info; static string log_index_prefix = "1_"; static int write_log_entry(cls_method_context_t hctx, string& index, cls_log_entry& entry) { bufferlist bl; ::encode(entry, bl); int ret = cls_cxx_map_set_val(hctx, index, &bl); if (ret < 0) return ret; return 0; } static void get_index_time_prefix(utime_t& ts, string& index) { char buf[32]; snprintf(buf, sizeof(buf), "%010ld.%06ld_", (long)ts.sec(), (long)ts.usec()); index = log_index_prefix + buf; } static int read_header(cls_method_context_t hctx, cls_log_header& header) { bufferlist header_bl; int ret = cls_cxx_map_read_header(hctx, &header_bl); if (ret < 0) return ret; if (header_bl.length() == 0) { header = cls_log_header(); return 0; } bufferlist::iterator iter = header_bl.begin(); try { ::decode(header, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: read_header(): failed to decode header"); } return 0; } static int write_header(cls_method_context_t hctx, cls_log_header& header) { bufferlist header_bl; ::encode(header, header_bl); int ret = cls_cxx_map_write_header(hctx, &header_bl); if (ret < 0) return ret; return 0; } static void get_index(cls_method_context_t hctx, utime_t& ts, string& index) { get_index_time_prefix(ts, index); string unique_id; cls_cxx_subop_version(hctx, &unique_id); index.append(unique_id); } static int cls_log_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_log_add_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op"); return -EINVAL; } cls_log_header header; int ret = read_header(hctx, header); if (ret < 0) return ret; for (list::iterator iter = op.entries.begin(); iter != op.entries.end(); ++iter) { cls_log_entry& entry = *iter; string index; utime_t timestamp = entry.timestamp; if (timestamp < header.max_time) timestamp = header.max_time; else if (timestamp > header.max_time) header.max_time = timestamp; get_index(hctx, timestamp, index); CLS_LOG(0, "storing entry at %s", index.c_str()); entry.id = index; if (index > header.max_marker) header.max_marker = index; ret = write_log_entry(hctx, index, entry); if (ret < 0) return ret; } ret = write_header(hctx, header); if (ret < 0) return ret; return 0; } static int cls_log_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_log_list_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_log_list_op(): failed to decode op"); return -EINVAL; } map keys; string from_index; string to_index; if (op.marker.empty()) { get_index_time_prefix(op.from_time, from_index); } else { from_index = op.marker; } bool use_time_boundary = (!op.from_time.is_zero() && (op.to_time >= op.from_time)); if (use_time_boundary) get_index_time_prefix(op.to_time, to_index); #define MAX_ENTRIES 1000 size_t max_entries = op.max_entries; if (!max_entries || max_entries > MAX_ENTRIES) max_entries = MAX_ENTRIES; int rc = cls_cxx_map_get_vals(hctx, from_index, log_index_prefix, max_entries + 1, &keys); if (rc < 0) return rc; cls_log_list_ret ret; list& entries = ret.entries; map::iterator iter = keys.begin(); bool done = false; string marker; size_t i; for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) { const string& index = iter->first; marker = index; if (use_time_boundary && index.compare(0, to_index.size(), to_index) >= 0) { done = true; break; } bufferlist& bl = iter->second; bufferlist::iterator biter = bl.begin(); try { cls_log_entry e; ::decode(e, biter); entries.push_back(e); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_log_list: could not decode entry, index=%s", index.c_str()); } } if (iter == keys.end()) done = true; ret.marker = marker; ret.truncated = !done; ::encode(ret, *out); return 0; } static int cls_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_log_trim_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_log_list_op(): failed to decode entry"); return -EINVAL; } map keys; string from_index; string to_index; if (op.from_marker.empty()) { get_index_time_prefix(op.from_time, from_index); } else { from_index = op.from_marker; } if (op.to_marker.empty()) { get_index_time_prefix(op.to_time, to_index); } else { to_index = op.to_marker; } #define MAX_TRIM_ENTRIES 1000 size_t max_entries = MAX_TRIM_ENTRIES; int rc = cls_cxx_map_get_vals(hctx, from_index, log_index_prefix, max_entries, &keys); if (rc < 0) return rc; map::iterator iter = keys.begin(); size_t i; bool removed = false; for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) { const string& index = iter->first; CLS_LOG(20, "index=%s to_index=%s", index.c_str(), to_index.c_str()); if (index.compare(0, to_index.size(), to_index) > 0) break; CLS_LOG(20, "removing key: index=%s", index.c_str()); int rc = cls_cxx_map_remove_key(hctx, index); if (rc < 0) { CLS_LOG(1, "ERROR: cls_cxx_map_remove_key failed rc=%d", rc); return -EINVAL; } removed = true; } if (!removed) return -ENODATA; return 0; } static int cls_log_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_log_info_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op"); return -EINVAL; } cls_log_info_ret ret; int rc = read_header(hctx, ret.header); if (rc < 0) return rc; ::encode(ret, *out); return 0; } void __cls_init() { CLS_LOG(1, "Loaded log class!"); cls_register("log", &h_class); /* log */ cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_add, &h_log_add); cls_register_cxx_method(h_class, "list", CLS_METHOD_RD, cls_log_list, &h_log_list); cls_register_cxx_method(h_class, "trim", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_trim, &h_log_trim); cls_register_cxx_method(h_class, "info", CLS_METHOD_RD, cls_log_info, &h_log_info); return; } ceph-0.80.11/src/cls/log/cls_log_ops.h0000664000175100017510000000642012623076744021504 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_LOG_OPS_H #define CEPH_CLS_LOG_OPS_H #include "include/types.h" #include "cls_log_types.h" struct cls_log_add_op { list entries; cls_log_add_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_add_op) struct cls_log_list_op { utime_t from_time; string marker; /* if not empty, overrides from_time */ utime_t to_time; /* not inclusive */ int max_entries; /* upperbound to returned num of entries might return less than that and still be truncated */ cls_log_list_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(from_time, bl); ::encode(marker, bl); ::encode(to_time, bl); ::encode(max_entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(from_time, bl); ::decode(marker, bl); ::decode(to_time, bl); ::decode(max_entries, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_list_op) struct cls_log_list_ret { list entries; string marker; bool truncated; cls_log_list_ret() : truncated(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ::encode(marker, bl); ::encode(truncated, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); ::decode(marker, bl); ::decode(truncated, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_list_ret) /* * operation will return 0 when successfully removed but not done. Will return * -ENODATA when done, so caller needs to repeat sending request until that. */ struct cls_log_trim_op { utime_t from_time; utime_t to_time; /* inclusive */ string from_marker; string to_marker; cls_log_trim_op() {} void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(from_time, bl); ::encode(to_time, bl); ::encode(from_marker, bl); ::encode(to_marker, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(from_time, bl); ::decode(to_time, bl); if (struct_v >= 2) { ::decode(from_marker, bl); ::decode(to_marker, bl); } DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_trim_op) struct cls_log_info_op { cls_log_info_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); // currently empty request ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); // currently empty request DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_info_op) struct cls_log_info_ret { cls_log_header header; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(header, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(header, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_info_ret) #endif ceph-0.80.11/src/cls/log/cls_log_client.h0000664000175100017510000000245512623076744022165 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_LOG_CLIENT_H #define CEPH_CLS_LOG_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" #include "cls_log_types.h" /* * log objclass */ void cls_log_add_prepare_entry(cls_log_entry& entry, const utime_t& timestamp, const string& section, const string& name, bufferlist& bl); void cls_log_add(librados::ObjectWriteOperation& op, list& entry); void cls_log_add(librados::ObjectWriteOperation& op, cls_log_entry& entry); void cls_log_add(librados::ObjectWriteOperation& op, const utime_t& timestamp, const string& section, const string& name, bufferlist& bl); void cls_log_list(librados::ObjectReadOperation& op, utime_t& from, utime_t& to, const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated); void cls_log_trim(librados::ObjectWriteOperation& op, const utime_t& from_time, const utime_t& to_time, const string& from_marker, const string& to_marker); int cls_log_trim(librados::IoCtx& io_ctx, const string& oid, const utime_t& from_time, const utime_t& to_time, const string& from_marker, const string& to_marker); void cls_log_info(librados::ObjectReadOperation& op, cls_log_header *header); #endif ceph-0.80.11/src/cls/log/cls_log_client.cc0000664000175100017510000000746412623076744022330 0ustar jenkins-buildjenkins-build#include #include "include/types.h" #include "cls/log/cls_log_ops.h" #include "include/rados/librados.hpp" using namespace librados; void cls_log_add(librados::ObjectWriteOperation& op, list& entries) { bufferlist in; cls_log_add_op call; call.entries = entries; ::encode(call, in); op.exec("log", "add", in); } void cls_log_add(librados::ObjectWriteOperation& op, cls_log_entry& entry) { bufferlist in; cls_log_add_op call; call.entries.push_back(entry); ::encode(call, in); op.exec("log", "add", in); } void cls_log_add_prepare_entry(cls_log_entry& entry, const utime_t& timestamp, const string& section, const string& name, bufferlist& bl) { entry.timestamp = timestamp; entry.section = section; entry.name = name; entry.data = bl; } void cls_log_add(librados::ObjectWriteOperation& op, const utime_t& timestamp, const string& section, const string& name, bufferlist& bl) { cls_log_entry entry; cls_log_add_prepare_entry(entry, timestamp, section, name, bl); cls_log_add(op, entry); } void cls_log_trim(librados::ObjectWriteOperation& op, const utime_t& from_time, const utime_t& to_time, const string& from_marker, const string& to_marker) { bufferlist in; cls_log_trim_op call; call.from_time = from_time; call.to_time = to_time; call.from_marker = from_marker; call.to_marker = to_marker; ::encode(call, in); op.exec("log", "trim", in); } int cls_log_trim(librados::IoCtx& io_ctx, const string& oid, const utime_t& from_time, const utime_t& to_time, const string& from_marker, const string& to_marker) { bool done = false; do { ObjectWriteOperation op; cls_log_trim(op, from_time, to_time, from_marker, to_marker); int r = io_ctx.operate(oid, &op); if (r == -ENODATA) done = true; else if (r < 0) return r; } while (!done); return 0; } class LogListCtx : public ObjectOperationCompletion { list *entries; string *marker; bool *truncated; public: LogListCtx(list *_entries, string *_marker, bool *_truncated) : entries(_entries), marker(_marker), truncated(_truncated) {} void handle_completion(int r, bufferlist& outbl) { if (r >= 0) { cls_log_list_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); if (entries) *entries = ret.entries; if (truncated) *truncated = ret.truncated; if (marker) *marker = ret.marker; } catch (buffer::error& err) { // nothing we can do about it atm } } } }; void cls_log_list(librados::ObjectReadOperation& op, utime_t& from, utime_t& to, const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated) { bufferlist inbl; cls_log_list_op call; call.from_time = from; call.to_time = to; call.marker = in_marker; call.max_entries = max_entries; ::encode(call, inbl); op.exec("log", "list", inbl, new LogListCtx(&entries, out_marker, truncated)); } class LogInfoCtx : public ObjectOperationCompletion { cls_log_header *header; public: LogInfoCtx(cls_log_header *_header) : header(_header) {} void handle_completion(int r, bufferlist& outbl) { if (r >= 0) { cls_log_info_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); if (header) *header = ret.header; } catch (buffer::error& err) { // nothing we can do about it atm } } } }; void cls_log_info(librados::ObjectReadOperation& op, cls_log_header *header) { bufferlist inbl; cls_log_info_op call; ::encode(call, inbl); op.exec("log", "info", inbl, new LogInfoCtx(header)); } ceph-0.80.11/src/cls/log/cls_log_types.h0000664000175100017510000000230212623076744022042 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_LOG_TYPES_H #define CEPH_CLS_LOG_TYPES_H #include "include/encoding.h" #include "include/types.h" #include "include/utime.h" class JSONObj; struct cls_log_entry { string id; string section; string name; utime_t timestamp; bufferlist data; cls_log_entry() {} void encode(bufferlist& bl) const { ENCODE_START(2, 1, bl); ::encode(section, bl); ::encode(name, bl); ::encode(timestamp, bl); ::encode(data, bl); ::encode(id, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(2, bl); ::decode(section, bl); ::decode(name, bl); ::decode(timestamp, bl); ::decode(data, bl); if (struct_v >= 2) ::decode(id, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_entry) struct cls_log_header { string max_marker; utime_t max_time; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(max_marker, bl); ::encode(max_time, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(max_marker, bl); ::decode(max_time, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_log_header) #endif ceph-0.80.11/src/cls/replica_log/0000775000175100017510000000000012623077035020517 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/replica_log/cls_replica_log_client.h0000664000175100017510000000651012623076744025357 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Copyright 2013 Inktank */ #ifndef CLS_REPLICA_LOG_CLIENT_H_ #define CLS_REPLICA_LOG_CLIENT_H_ #include "include/rados/librados.hpp" #include "cls_replica_log_types.h" /** * Prepare a progress marker object to send out. * * @param progress The marker object to prepare * @param entity The ID of the entity setting the progress * @param marker The marker key the entity has gotten to * @param time The timestamp associated with the marker * param entries A list of in-progress entries prior to the marker */ void cls_replica_log_prepare_marker(cls_replica_log_progress_marker& progress, const string& entity, const string& marker, const utime_t& time, const list > *entries); /** * Extract a progress marker object into its components. * * @param progress The marker object to extract data from * @param entity [out] The ID of the entity the progress is associated with * @param marker [out] The marker key the entity has gotten to * @param time [out] The timestamp associated with the marker * @param entries [out] List of in-progress entries prior to the marker */ void cls_replica_log_extract_marker(const cls_replica_log_progress_marker& progress, string& entity, string& marker, utime_t& time, list >& entries); /** * Add a progress marker update to a write op. The op will return 0 on * success, -EEXIST if the marker conflicts with an existing one, or * -EINVAL if the marker is in conflict (ie, before) the daemon's existing * marker. * * @param op The op to add the update to * @param progress The progress marker to send */ void cls_replica_log_update_bound(librados::ObjectWriteOperation& op, const cls_replica_log_progress_marker& progress); /** * Remove an entity's progress marker from the replica log. The op will return * 0 on success, -ENOENT if the entity does not exist on the replica log, or * -ENOTEMPTY if the items list on the marker is not empty. * * @param op The op to add the delete to * @param entity The entity whose progress should be removed */ void cls_replica_log_delete_bound(librados::ObjectWriteOperation& op, const string& entity); /** * Read the bounds on a replica log. * * @param io_ctx The IoCtx to use for the read * @param oid The oid to direct the read to * @param position_marker [out] The lowest marker key that has been reached * @param oldest_time [out] Timestamp corresponding to the position marker or * oldest in-progress item. * @param markers [out] List of progress markers for individual daemons */ int cls_replica_log_get_bounds(librados::IoCtx& io_ctx, const string& oid, string& position_marker, utime_t& oldest_time, list& markers); #endif /* CLS_REPLICA_LOG_CLIENT_H_ */ ceph-0.80.11/src/cls/replica_log/cls_replica_log_types.h0000664000175100017510000001353612623076744025253 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Copyright 2013 Inktank */ #ifndef CLS_REPLICA_LOG_TYPES_H_ #define CLS_REPLICA_LOG_TYPES_H_ #include "include/utime.h" #include "include/encoding.h" #include "include/types.h" #include class JSONObj; struct cls_replica_log_item_marker { string item_name; // the name of the item we're marking utime_t item_timestamp; // the time stamp at which the item was outdated cls_replica_log_item_marker() {} cls_replica_log_item_marker(const string& name, const utime_t& time) : item_name(name), item_timestamp(time) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(item_name, bl); ::encode(item_timestamp, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(item_name, bl); ::decode(item_timestamp, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_item_marker) struct cls_replica_log_progress_marker { string entity_id; // the name of the entity setting the progress marker string position_marker; // represents a log listing position on the master utime_t position_time; // the timestamp associated with the position marker std::list items; /* any items not caught up to the position marker*/ cls_replica_log_progress_marker() {} cls_replica_log_progress_marker(const string& entity, const string& marker, const utime_t& time ) : entity_id(entity), position_marker(marker), position_time(time) {} cls_replica_log_progress_marker(const string& entity, const string& marker, const utime_t& time, const std::list& b) : entity_id(entity), position_marker(marker), position_time(time), items(b) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entity_id, bl); ::encode(position_marker, bl); ::encode(position_time, bl); ::encode(items, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entity_id, bl); ::decode(position_marker, bl); ::decode(position_time, bl); ::decode(items, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_progress_marker) class cls_replica_log_bound { /** * Right now, we are lazy and only support a single marker at a time. In the * future, we might support more than one, so the interface is designed to * let that work. */ string position_marker; // represents a log listing position on the master utime_t position_time; // the timestamp associated with the position marker bool marker_exists; // has the marker been set? cls_replica_log_progress_marker marker; // the status of the current locker public: cls_replica_log_bound() : marker_exists(false) {} int update_marker(const cls_replica_log_progress_marker& new_mark) { // only one marker at a time right now if (marker_exists && (marker.entity_id != new_mark.entity_id)) { return -EEXIST; } // can't go backwards with our one marker! if (marker_exists && (marker.position_time > new_mark.position_time)) { return -EINVAL; } marker = new_mark; position_marker = new_mark.position_marker; position_time = new_mark.position_time; marker_exists = true; // hey look, updating is idempotent; did you notice that? return 0; } int delete_marker(const string& entity_id) { if (marker_exists) { // ENOENT if our marker doesn't match the passed ID if (marker.entity_id != entity_id) { return -ENOENT; } // you can't delete it if there are unclean entries if (!marker.items.empty()) { return -ENOTEMPTY; } } marker_exists = false; marker = cls_replica_log_progress_marker(); // hey look, deletion is idempotent! Hurray. return 0; } std::string get_lowest_marker_bound() { return position_marker; } utime_t get_lowest_time_bound() { return position_time; } utime_t get_oldest_time() { utime_t oldest = position_time; list::const_iterator i; for ( i = marker.items.begin(); i != marker.items.end(); ++i) { if (i->item_timestamp < oldest) oldest = i->item_timestamp; } return oldest; } void get_markers(list& ls) { if (marker_exists) { ls.push_back(marker); } } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(position_marker, bl); ::encode(position_time, bl); ::encode(marker_exists, bl); if (marker_exists) { ::encode(marker, bl); } ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(position_marker, bl); ::decode(position_time, bl); ::decode(marker_exists, bl); if (marker_exists) { ::decode(marker, bl); } DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_bound); #endif /* CLS_REPLICA_LOG_TYPES_H_ */ ceph-0.80.11/src/cls/replica_log/cls_replica_log_ops.cc0000664000175100017510000000516012623076744025040 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cls_replica_log_ops.h" #include "common/Formatter.h" #include "common/ceph_json.h" void cls_replica_log_delete_marker_op::dump(Formatter *f) const { f->dump_string("entity_id", entity_id); } void cls_replica_log_delete_marker_op:: generate_test_instances(std::list& ls) { ls.push_back(new cls_replica_log_delete_marker_op); ls.push_back(new cls_replica_log_delete_marker_op); ls.back()->entity_id = "test_entity_1"; } void cls_replica_log_set_marker_op::dump(Formatter *f) const { encode_json("marker", marker, f); } void cls_replica_log_set_marker_op:: generate_test_instances(std::list& ls) { std::list samples; cls_replica_log_progress_marker::generate_test_instances(samples); std::list::iterator i; for (i = samples.begin(); i != samples.end(); ++i) { ls.push_back(new cls_replica_log_set_marker_op(*(*i))); } } void cls_replica_log_get_bounds_op::dump(Formatter *f) const { f->dump_string("contents", "empty"); } void cls_replica_log_get_bounds_op:: generate_test_instances(std::list& ls) { ls.push_back(new cls_replica_log_get_bounds_op); } void cls_replica_log_get_bounds_ret::dump(Formatter *f) const { f->dump_string("position_marker", position_marker); oldest_time.gmtime(f->dump_stream("oldest_time")); encode_json("entity_markers", markers, f); } void cls_replica_log_get_bounds_ret:: generate_test_instances(std::list& ls) { std::list samples; cls_replica_log_progress_marker::generate_test_instances(samples); std::list samples_whole; std::list::iterator i; int count = 0; for (i = samples.begin(); i != samples.end(); ++i) { ls.push_back(new cls_replica_log_get_bounds_ret()); ls.back()->markers.push_back(*(*i)); ls.back()->oldest_time.set_from_double(1000*count); ls.back()->position_marker = ls.back()->markers.front().position_marker; samples_whole.push_back(*(*i)); } ls.push_back(new cls_replica_log_get_bounds_ret()); ls.back()->markers = samples_whole; ls.back()->oldest_time = samples_whole.back().position_time; ls.back()->position_marker = samples_whole.back().position_marker; } ceph-0.80.11/src/cls/replica_log/cls_replica_log.cc0000664000175100017510000000747212623076744024167 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * * Copyright Inktank 2013 */ #include "objclass/objclass.h" #include "global/global_context.h" #include "cls_replica_log_types.h" #include "cls_replica_log_ops.h" CLS_VER(1, 0) CLS_NAME(replica_log) cls_handle_t h_class; cls_method_handle_t h_replica_log_set; cls_method_handle_t h_replica_log_delete; cls_method_handle_t h_replica_log_get; static const string replica_log_prefix = "rl_"; static const string replica_log_bounds = replica_log_prefix + "bounds"; static int get_bounds(cls_method_context_t hctx, cls_replica_log_bound& bound) { bufferlist bounds_bl; int rc = cls_cxx_map_get_val(hctx, replica_log_bounds, &bounds_bl); if (rc < 0) { return rc; } try { bufferlist::iterator bounds_bl_i = bounds_bl.begin(); ::decode(bound, bounds_bl_i); } catch (buffer::error& err) { bound = cls_replica_log_bound(); CLS_LOG(0, "ERROR: get_bounds(): failed to decode on-disk bounds object"); return -EIO; } return 0; } static int write_bounds(cls_method_context_t hctx, const cls_replica_log_bound& bound) { bufferlist bounds_bl; ::encode(bound, bounds_bl); return cls_cxx_map_set_val(hctx, replica_log_bounds, &bounds_bl); } static int cls_replica_log_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_replica_log_set_marker_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_replica_log_set(): failed to decode op"); return -EINVAL; } cls_replica_log_bound bound; int rc = get_bounds(hctx, bound); if (rc < 0 && rc != -ENOENT) { return rc; } rc = bound.update_marker(op.marker); if (rc < 0) { return rc; } return write_bounds(hctx, bound); } static int cls_replica_log_delete(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_replica_log_delete_marker_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_replica_log_delete(): failed to decode op"); return -EINVAL; } cls_replica_log_bound bound; int rc = get_bounds(hctx, bound); if (rc < 0 && rc != -ENOENT) { return rc; } rc = bound.delete_marker(op.entity_id); if (rc < 0) { return rc; } return write_bounds(hctx, bound); } static int cls_replica_log_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_replica_log_get_bounds_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_replica_log_get(): failed to decode op"); return -EINVAL; } cls_replica_log_bound bound; int rc = get_bounds(hctx, bound); if (rc < 0) { return rc; } cls_replica_log_get_bounds_ret ret; ret.oldest_time = bound.get_oldest_time(); ret.position_marker = bound.get_lowest_marker_bound(); bound.get_markers(ret.markers); ::encode(ret, *out); return 0; } void __cls_init() { CLS_LOG(1, "Loaded replica log class!"); cls_register("replica_log", &h_class); cls_register_cxx_method(h_class, "set", CLS_METHOD_RD | CLS_METHOD_WR, cls_replica_log_set, &h_replica_log_set); cls_register_cxx_method(h_class, "get", CLS_METHOD_RD, cls_replica_log_get, &h_replica_log_get); cls_register_cxx_method(h_class, "delete", CLS_METHOD_RD | CLS_METHOD_WR, cls_replica_log_delete, &h_replica_log_delete); } ceph-0.80.11/src/cls/replica_log/cls_replica_log_client.cc0000664000175100017510000000547212623076744025523 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include "cls/replica_log/cls_replica_log_ops.h" #include "include/rados/librados.hpp" using namespace librados; void cls_replica_log_prepare_marker(cls_replica_log_progress_marker& progress, const string& entity, const string& marker, const utime_t& time, const list > *entries) { progress.entity_id = entity; progress.position_marker = marker; progress.position_time = time; if (entries) { list >::const_iterator i; for (i = entries->begin(); i != entries->end(); ++i) { cls_replica_log_item_marker item(i->first, i->second); progress.items.push_back(item); } } } void cls_replica_log_extract_marker(const cls_replica_log_progress_marker& progress, string& entity, string& marker, utime_t& time, list >& entries) { entity = progress.entity_id; marker = progress.position_marker; time = progress.position_time; list::const_iterator i; for (i = progress.items.begin(); i != progress.items.end(); ++i) { entries.push_back(make_pair(i->item_name, i->item_timestamp)); } } void cls_replica_log_update_bound(librados::ObjectWriteOperation& o, const cls_replica_log_progress_marker& progress) { cls_replica_log_set_marker_op op(progress); bufferlist in; ::encode(op, in); o.exec("replica_log", "set", in); } void cls_replica_log_delete_bound(librados::ObjectWriteOperation& o, const string& entity) { cls_replica_log_delete_marker_op op(entity); bufferlist in; ::encode(op, in); o.exec("replica_log", "delete", in); } int cls_replica_log_get_bounds(librados::IoCtx& io_ctx, const string& oid, string& position_marker, utime_t& oldest_time, list& markers) { bufferlist in; bufferlist out; cls_replica_log_get_bounds_op op; ::encode(op, in); int r = io_ctx.exec(oid, "replica_log", "get", in, out); if (r < 0) return r; cls_replica_log_get_bounds_ret ret; try { bufferlist::iterator i = out.begin(); ::decode(ret, i); } catch (buffer::error& err) { return -EIO; } position_marker = ret.position_marker; oldest_time = ret.oldest_time; markers = ret.markers; return 0; } ceph-0.80.11/src/cls/replica_log/cls_replica_log_ops.h0000664000175100017510000000610612623076744024703 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef CLS_REPLICA_LOG_OPS_H_ #define CLS_REPLICA_LOG_OPS_H_ #include "include/types.h" #include "cls_replica_log_types.h" struct cls_replica_log_delete_marker_op { string entity_id; cls_replica_log_delete_marker_op() {} cls_replica_log_delete_marker_op(const string& id) : entity_id(id) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entity_id, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entity_id, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_delete_marker_op) struct cls_replica_log_set_marker_op { cls_replica_log_progress_marker marker; cls_replica_log_set_marker_op() {} cls_replica_log_set_marker_op(const cls_replica_log_progress_marker& m) : marker(m) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(marker, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(marker, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_set_marker_op) struct cls_replica_log_get_bounds_op { cls_replica_log_get_bounds_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_get_bounds_op) struct cls_replica_log_get_bounds_ret { string position_marker; // oldest log listing position on the master utime_t oldest_time; // oldest timestamp associated with position or an item std::list markers; cls_replica_log_get_bounds_ret() {} cls_replica_log_get_bounds_ret(const string& pos_marker, const utime_t& time, const std::list& m) : position_marker(pos_marker), oldest_time(time), markers(m) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(position_marker, bl); ::encode(oldest_time, bl); ::encode(markers, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(position_marker, bl); ::decode(oldest_time, bl); ::decode(markers, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(std::list& ls); }; WRITE_CLASS_ENCODER(cls_replica_log_get_bounds_ret) #endif /* CLS_REPLICA_LOG_OPS_H_ */ ceph-0.80.11/src/cls/replica_log/cls_replica_log_types.cc0000664000175100017510000000653012623076744025405 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "cls_replica_log_types.h" #include "common/Formatter.h" #include "common/ceph_json.h" void cls_replica_log_item_marker::dump(Formatter *f) const { f->dump_string("name", item_name); f->dump_stream("timestamp") << item_timestamp; } void cls_replica_log_item_marker::decode_json(JSONObj *obj) { JSONDecoder::decode_json("name", item_name, obj); JSONDecoder::decode_json("timestamp", item_timestamp, obj); } void cls_replica_log_item_marker:: generate_test_instances(std::list& ls) { ls.push_back(new cls_replica_log_item_marker); ls.back()->item_name = "test_item_1"; ls.back()->item_timestamp.set_from_double(0); ls.push_back(new cls_replica_log_item_marker); ls.back()->item_name = "test_item_2"; ls.back()->item_timestamp.set_from_double(20); } void cls_replica_log_progress_marker::dump(Formatter *f) const { encode_json("entity", entity_id, f); encode_json("position_marker", position_marker, f); encode_json("position_time", position_time, f); encode_json("items_in_progress", items, f); } void cls_replica_log_progress_marker::decode_json(JSONObj *obj) { JSONDecoder::decode_json("entity", entity_id, obj); JSONDecoder::decode_json("position_marker", position_marker, obj); JSONDecoder::decode_json("position_time", position_time, obj); JSONDecoder::decode_json("items_in_progress", items, obj); } void cls_replica_log_progress_marker:: generate_test_instances(std::list& ls) { ls.push_back(new cls_replica_log_progress_marker); ls.push_back(new cls_replica_log_progress_marker); ls.back()->entity_id = "entity1"; ls.back()->position_marker = "pos1"; ls.back()->position_time.set_from_double(20); std::list test_items; cls_replica_log_item_marker::generate_test_instances(test_items); std::list::iterator i = test_items.begin(); for ( ; i != test_items.end(); ++i) { ls.back()->items.push_back(*(*i)); } } void cls_replica_log_bound::dump(Formatter *f) const { encode_json("position_marker", position_marker, f); encode_json("position_time", position_time, f); encode_json("marker_exists", marker_exists, f); if (marker_exists) { encode_json("marker", marker, f); //progress marker } } void cls_replica_log_bound::decode_json(JSONObj *obj) { JSONDecoder::decode_json("position_marker", position_marker, obj); JSONDecoder::decode_json("position_time", position_time, obj); JSONDecoder::decode_json("marker_exists", marker_exists, obj); if (marker_exists) { JSONDecoder::decode_json("marker", marker, obj); //progress marker } } void cls_replica_log_bound:: generate_test_instances(std::list& ls) { ls.push_back(new cls_replica_log_bound); std::list marker_objects; cls_replica_log_progress_marker::generate_test_instances(marker_objects); std::list::iterator i = marker_objects.begin(); ls.back()->update_marker(*(*i)); ls.push_back(new cls_replica_log_bound); ++i; ls.back()->update_marker(*(*i)); } ceph-0.80.11/src/cls/statelog/0000775000175100017510000000000012623077035020061 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/statelog/cls_statelog_client.h0000664000175100017510000000277712623076744024276 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_STATELOG_CLIENT_H #define CEPH_CLS_STATELOG_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" #include "cls_statelog_types.h" /* * log objclass */ void cls_statelog_add_prepare_entry(cls_statelog_entry& entry, const string& client_id, const string& op_id, const string& object, const utime_t& timestamp, uint32_t state, bufferlist& bl); void cls_statelog_add(librados::ObjectWriteOperation& op, list& entry); void cls_statelog_add(librados::ObjectWriteOperation& op, cls_statelog_entry& entry); void cls_statelog_add(librados::ObjectWriteOperation& op, const string& client_id, const string& op_id, const string& object, const utime_t& timestamp, uint32_t state, bufferlist& bl); void cls_statelog_list(librados::ObjectReadOperation& op, const string& client_id, const string& op_id, const string& object, /* op_id may be empty, also one of client_id, object*/ const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated); void cls_statelog_remove_by_client(librados::ObjectWriteOperation& op, const string& client_id, const string& op_id); void cls_statelog_remove_by_object(librados::ObjectWriteOperation& op, const string& object, const string& op_id); void cls_statelog_check_state(librados::ObjectOperation& op, const string& client_id, const string& op_id, const string& object, uint32_t state); #endif ceph-0.80.11/src/cls/statelog/cls_statelog.cc0000664000175100017510000002006012623076744023057 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "objclass/objclass.h" #include "cls_statelog_types.h" #include "cls_statelog_ops.h" #include "global/global_context.h" CLS_VER(1,0) CLS_NAME(statelog) cls_handle_t h_class; cls_method_handle_t h_statelog_add; cls_method_handle_t h_statelog_list; cls_method_handle_t h_statelog_remove; cls_method_handle_t h_statelog_check_state; static string statelog_index_by_client_prefix = "1_"; static string statelog_index_by_object_prefix = "2_"; static int write_statelog_entry(cls_method_context_t hctx, const string& index, const cls_statelog_entry& entry) { bufferlist bl; ::encode(entry, bl); int ret = cls_cxx_map_set_val(hctx, index, &bl); if (ret < 0) return ret; return 0; } static void get_index_by_client(const string& client_id, const string& op_id, string& index) { index = statelog_index_by_client_prefix; index.append(client_id + "_" + op_id); } static void get_index_by_client(cls_statelog_entry& entry, string& index) { get_index_by_client(entry.client_id, entry.op_id, index); } static void get_index_by_object(const string& object, const string& op_id, string& index) { char buf[16]; snprintf(buf, sizeof(buf), "%d_", (int)object.size()); index = statelog_index_by_object_prefix + buf; /* append object length to ensure uniqueness */ index.append(object + "_" + op_id); } static void get_index_by_object(cls_statelog_entry& entry, string& index) { get_index_by_object(entry.object, entry.op_id, index); } static int get_existing_entry(cls_method_context_t hctx, const string& client_id, const string& op_id, const string& object, cls_statelog_entry& entry) { if ((object.empty() && client_id.empty()) || op_id.empty()) { return -EINVAL; } string obj_index; if (!object.empty()) { get_index_by_object(object, op_id, obj_index); } else { get_index_by_client(client_id, op_id, obj_index); } bufferlist bl; int rc = cls_cxx_map_get_val(hctx, obj_index, &bl); if (rc < 0) { CLS_LOG(0, "could not find entry %s", obj_index.c_str()); return rc; } try { bufferlist::iterator iter = bl.begin(); ::decode(entry, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: failed to decode entry %s", obj_index.c_str()); return -EIO; } if ((!object.empty() && entry.object != object) || (!client_id.empty() && entry.client_id != client_id)){ /* ouch, we were passed inconsistent client_id / object */ CLS_LOG(0, "data mismatch: object=%s client_id=%s entry: object=%s client_id=%s", object.c_str(), client_id.c_str(), entry.object.c_str(), entry.client_id.c_str()); return -EINVAL; } return 0; } static int cls_statelog_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_statelog_add_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_statelog_add_op(): failed to decode op"); return -EINVAL; } for (list::iterator iter = op.entries.begin(); iter != op.entries.end(); ++iter) { cls_statelog_entry& entry = *iter; string index_by_client; get_index_by_client(entry, index_by_client); CLS_LOG(0, "storing entry by client/op at %s", index_by_client.c_str()); int ret = write_statelog_entry(hctx, index_by_client, entry); if (ret < 0) return ret; string index_by_obj; get_index_by_object(entry, index_by_obj); CLS_LOG(0, "storing entry by object at %s", index_by_obj.c_str()); ret = write_statelog_entry(hctx, index_by_obj, entry); if (ret < 0) return ret; } return 0; } static int cls_statelog_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_statelog_list_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_statelog_list_op(): failed to decode op"); return -EINVAL; } map keys; string from_index; string match_prefix; if (!op.client_id.empty()) { get_index_by_client(op.client_id, op.op_id, match_prefix); } else if (!op.object.empty()) { get_index_by_object(op.object, op.op_id, match_prefix); } else { match_prefix = statelog_index_by_object_prefix; } if (op.marker.empty()) { from_index = match_prefix; } else { from_index = op.marker; } #define MAX_ENTRIES 1000 size_t max_entries = op.max_entries; if (!max_entries || max_entries > MAX_ENTRIES) max_entries = MAX_ENTRIES; int rc = cls_cxx_map_get_vals(hctx, from_index, match_prefix, max_entries + 1, &keys); if (rc < 0) return rc; CLS_LOG(20, "from_index=%s match_prefix=%s", from_index.c_str(), match_prefix.c_str()); cls_statelog_list_ret ret; list& entries = ret.entries; map::iterator iter = keys.begin(); bool done = false; string marker; size_t i; for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) { const string& index = iter->first; marker = index; bufferlist& bl = iter->second; bufferlist::iterator biter = bl.begin(); try { cls_statelog_entry e; ::decode(e, biter); entries.push_back(e); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: cls_statelog_list: could not decode entry, index=%s", index.c_str()); } } if (iter == keys.end()) done = true; else ret.marker = marker; ret.truncated = !done; ::encode(ret, *out); return 0; } static int cls_statelog_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_statelog_remove_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_statelog_remove_op(): failed to decode op"); return -EINVAL; } cls_statelog_entry entry; int rc = get_existing_entry(hctx, op.client_id, op.op_id, op.object, entry); if (rc < 0) return rc; string obj_index; get_index_by_object(entry.object, entry.op_id, obj_index); rc = cls_cxx_map_remove_key(hctx, obj_index); if (rc < 0) { CLS_LOG(0, "ERROR: failed to remove key"); return rc; } string client_index; get_index_by_client(entry.client_id, entry.op_id, client_index); rc = cls_cxx_map_remove_key(hctx, client_index); if (rc < 0) { CLS_LOG(0, "ERROR: failed to remove key"); return rc; } return 0; } static int cls_statelog_check_state(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_statelog_check_state_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_statelog_check_state_op(): failed to decode op"); return -EINVAL; } if (op.object.empty() || op.op_id.empty()) { CLS_LOG(0, "object name or op id not specified"); return -EINVAL; } string obj_index; get_index_by_object(op.object, op.op_id, obj_index); bufferlist bl; int rc = cls_cxx_map_get_val(hctx, obj_index, &bl); if (rc < 0) { CLS_LOG(0, "could not find entry %s", obj_index.c_str()); return rc; } cls_statelog_entry entry; rc = get_existing_entry(hctx, op.client_id, op.op_id, op.object, entry); if (rc < 0) return rc; if (entry.state != op.state) return -ECANCELED; return 0; } void __cls_init() { CLS_LOG(1, "Loaded log class!"); cls_register("statelog", &h_class); /* log */ cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR, cls_statelog_add, &h_statelog_add); cls_register_cxx_method(h_class, "list", CLS_METHOD_RD, cls_statelog_list, &h_statelog_list); cls_register_cxx_method(h_class, "remove", CLS_METHOD_RD | CLS_METHOD_WR, cls_statelog_remove, &h_statelog_remove); cls_register_cxx_method(h_class, "check_state", CLS_METHOD_RD, cls_statelog_check_state, &h_statelog_check_state); return; } ceph-0.80.11/src/cls/statelog/cls_statelog_client.cc0000664000175100017510000000723212623076744024423 0ustar jenkins-buildjenkins-build#include #include "include/types.h" #include "cls/statelog/cls_statelog_ops.h" #include "include/rados/librados.hpp" using namespace librados; void cls_statelog_add(librados::ObjectWriteOperation& op, list& entries) { bufferlist in; cls_statelog_add_op call; call.entries = entries; ::encode(call, in); op.exec("statelog", "add", in); } void cls_statelog_add(librados::ObjectWriteOperation& op, cls_statelog_entry& entry) { bufferlist in; cls_statelog_add_op call; call.entries.push_back(entry); ::encode(call, in); op.exec("statelog", "add", in); } void cls_statelog_add_prepare_entry(cls_statelog_entry& entry, const string& client_id, const string& op_id, const string& object, const utime_t& timestamp, uint32_t state, bufferlist& bl) { entry.client_id = client_id; entry.op_id = op_id; entry.object = object; entry.timestamp = timestamp; entry.state = state; entry.data = bl; } void cls_statelog_add(librados::ObjectWriteOperation& op, const string& client_id, const string& op_id, const string& object, const utime_t& timestamp, uint32_t state, bufferlist& bl) { cls_statelog_entry entry; cls_statelog_add_prepare_entry(entry, client_id, op_id, object, timestamp, state, bl); cls_statelog_add(op, entry); } void cls_statelog_remove_by_client(librados::ObjectWriteOperation& op, const string& client_id, const string& op_id) { bufferlist in; cls_statelog_remove_op call; call.client_id = client_id; call.op_id = op_id; ::encode(call, in); op.exec("statelog", "remove", in); } void cls_statelog_remove_by_object(librados::ObjectWriteOperation& op, const string& object, const string& op_id) { bufferlist in; cls_statelog_remove_op call; call.object = object; call.op_id = op_id; ::encode(call, in); op.exec("statelog", "remove", in); } class StateLogListCtx : public ObjectOperationCompletion { list *entries; string *marker; bool *truncated; public: StateLogListCtx(list *_entries, string *_marker, bool *_truncated) : entries(_entries), marker(_marker), truncated(_truncated) {} void handle_completion(int r, bufferlist& outbl) { if (r >= 0) { cls_statelog_list_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); if (entries) *entries = ret.entries; if (truncated) *truncated = ret.truncated; if (marker) *marker = ret.marker; } catch (buffer::error& err) { // nothing we can do about it atm } } } }; void cls_statelog_list(librados::ObjectReadOperation& op, const string& client_id, const string& op_id, const string& object, /* op_id may be empty, also one of client_id, object*/ const string& in_marker, int max_entries, list& entries, string *out_marker, bool *truncated) { bufferlist inbl; cls_statelog_list_op call; call.client_id = client_id; call.op_id = op_id; call.object = object; call.marker = in_marker; call.max_entries = max_entries; ::encode(call, inbl); op.exec("statelog", "list", inbl, new StateLogListCtx(&entries, out_marker, truncated)); } void cls_statelog_check_state(librados::ObjectOperation& op, const string& client_id, const string& op_id, const string& object, uint32_t state) { bufferlist inbl; bufferlist outbl; cls_statelog_check_state_op call; call.client_id = client_id; call.op_id = op_id; call.object = object; call.state = state; ::encode(call, inbl); op.exec("statelog", "check_state", inbl, NULL); } ceph-0.80.11/src/cls/statelog/cls_statelog_ops.h0000664000175100017510000000626212623076744023612 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_STATELOG_OPS_H #define CEPH_CLS_STATELOG_OPS_H #include "include/types.h" #include "cls_statelog_types.h" struct cls_statelog_add_op { list entries; cls_statelog_add_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_statelog_add_op) struct cls_statelog_list_op { string object; string client_id; string op_id; string marker; /* if not empty, overrides from_time */ int max_entries; /* upperbound to returned num of entries might return less than that and still be truncated */ cls_statelog_list_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(object, bl); ::encode(client_id, bl); ::encode(op_id, bl); ::encode(marker, bl); ::encode(max_entries, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(object, bl); ::decode(client_id, bl); ::decode(op_id, bl); ::decode(marker, bl); ::decode(max_entries, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_statelog_list_op) struct cls_statelog_list_ret { list entries; string marker; bool truncated; cls_statelog_list_ret() : truncated(false) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(entries, bl); ::encode(marker, bl); ::encode(truncated, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(entries, bl); ::decode(marker, bl); ::decode(truncated, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_statelog_list_ret) /* * operation will return 0 when successfully removed but not done. Will return * -ENODATA when done, so caller needs to repeat sending request until that. */ struct cls_statelog_remove_op { string client_id; string op_id; string object; cls_statelog_remove_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(client_id, bl); ::encode(op_id, bl); ::encode(object, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(client_id, bl); ::decode(op_id, bl); ::decode(object, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_statelog_remove_op) struct cls_statelog_check_state_op { string client_id; string op_id; string object; uint32_t state; cls_statelog_check_state_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(client_id, bl); ::encode(op_id, bl); ::encode(object, bl); ::encode(state, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(client_id, bl); ::decode(op_id, bl); ::decode(object, bl); ::decode(state, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_statelog_check_state_op) #endif ceph-0.80.11/src/cls/statelog/cls_statelog_types.h0000664000175100017510000000173512623076744024155 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_STATELOG_TYPES_H #define CEPH_CLS_STATELOG_TYPES_H #include "include/encoding.h" #include "include/types.h" #include "include/utime.h" class JSONObj; struct cls_statelog_entry { string client_id; string op_id; string object; utime_t timestamp; bufferlist data; uint32_t state; /* user defined state */ cls_statelog_entry() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(client_id, bl); ::encode(op_id, bl); ::encode(object, bl); ::encode(timestamp, bl); ::encode(data, bl); ::encode(state, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(client_id, bl); ::decode(op_id, bl); ::decode(object, bl); ::decode(timestamp, bl); ::decode(data, bl); ::decode(state, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(cls_statelog_entry) #endif ceph-0.80.11/src/cls/Makefile.am0000664000175100017510000001176512623076744020313 0ustar jenkins-buildjenkins-build## Rados object classes libcls_hello_la_SOURCES = cls/hello/cls_hello.cc libcls_hello_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_hello_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_hello.la libcls_rbd_la_SOURCES = cls/rbd/cls_rbd.cc libcls_rbd_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_rbd_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_rbd.la libcls_lock_la_SOURCES = cls/lock/cls_lock.cc libcls_lock_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_lock_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_lock.la libcls_refcount_la_SOURCES = \ cls/refcount/cls_refcount.cc \ cls/refcount/cls_refcount_ops.cc \ common/ceph_json.cc libcls_refcount_la_LIBADD = libjson_spirit.la $(PTHREAD_LIBS) $(EXTRALIBS) libcls_refcount_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_refcount.la libcls_version_la_SOURCES = cls/version/cls_version.cc libcls_version_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_version_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_version.la libcls_log_la_SOURCES = cls/log/cls_log.cc libcls_log_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_log_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_log.la libcls_statelog_la_SOURCES = cls/statelog/cls_statelog.cc libcls_statelog_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_statelog_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_statelog.la libcls_replica_log_la_SOURCES = cls/replica_log/cls_replica_log.cc libcls_replica_log_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_replica_log_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_replica_log.la libcls_user_la_SOURCES = cls/user/cls_user.cc libcls_user_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_user_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_user.la libcls_rgw_la_SOURCES = \ cls/rgw/cls_rgw.cc \ cls/rgw/cls_rgw_ops.cc \ cls/rgw/cls_rgw_types.cc \ common/ceph_json.cc libcls_rgw_la_LIBADD = libjson_spirit.la $(PTHREAD_LIBS) $(EXTRALIBS) libcls_rgw_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' radoslib_LTLIBRARIES += libcls_rgw.la ## Rados object client classes libcls_lock_client_la_SOURCES = \ cls/lock/cls_lock_client.cc \ cls/lock/cls_lock_types.cc \ cls/lock/cls_lock_ops.cc noinst_LTLIBRARIES += libcls_lock_client.la DENCODER_DEPS += libcls_lock_client.la libcls_refcount_client_la_SOURCES = \ cls/refcount/cls_refcount_client.cc \ cls/refcount/cls_refcount_ops.cc noinst_LTLIBRARIES += libcls_refcount_client.la DENCODER_DEPS += libcls_refcount_client.la libcls_version_client_a_SOURCES = \ cls/version/cls_version_client.cc \ cls/version/cls_version_types.cc noinst_LIBRARIES += libcls_version_client.a libcls_log_client_a_SOURCES = cls/log/cls_log_client.cc noinst_LIBRARIES += libcls_log_client.a libcls_statelog_client_a_SOURCES = cls/statelog/cls_statelog_client.cc noinst_LIBRARIES += libcls_statelog_client.a libcls_replica_log_client_a_SOURCES = \ cls/replica_log/cls_replica_log_types.cc \ cls/replica_log/cls_replica_log_ops.cc \ cls/replica_log/cls_replica_log_client.cc noinst_LIBRARIES += libcls_replica_log_client.a DENCODER_DEPS += libcls_replica_log_client.a libcls_rgw_client_la_SOURCES = \ cls/rgw/cls_rgw_client.cc \ cls/rgw/cls_rgw_types.cc \ cls/rgw/cls_rgw_ops.cc noinst_LTLIBRARIES += libcls_rgw_client.la DENCODER_DEPS += libcls_rgw_client.la libcls_rbd_client_la_SOURCES = cls/rbd/cls_rbd_client.cc noinst_LTLIBRARIES += libcls_rbd_client.la libcls_user_client_a_SOURCES = cls/user/cls_user_client.cc \ cls/user/cls_user_types.cc \ cls/user/cls_user_ops.cc DENCODER_DEPS += libcls_user_client.a noinst_LIBRARIES += libcls_user_client.a noinst_HEADERS += \ cls/lock/cls_lock_types.h \ cls/lock/cls_lock_ops.h \ cls/lock/cls_lock_client.h \ cls/rbd/cls_rbd.h \ cls/rbd/cls_rbd_client.h \ cls/refcount/cls_refcount_ops.h \ cls/refcount/cls_refcount_client.h \ cls/version/cls_version_types.h \ cls/version/cls_version_ops.h \ cls/version/cls_version_client.h \ cls/log/cls_log_types.h \ cls/log/cls_log_ops.h \ cls/log/cls_log_client.h \ cls/statelog/cls_statelog_types.h \ cls/statelog/cls_statelog_ops.h \ cls/statelog/cls_statelog_client.h \ cls/replica_log/cls_replica_log_types.h \ cls/replica_log/cls_replica_log_ops.h \ cls/replica_log/cls_replica_log_client.h \ cls/rgw/cls_rgw_client.h \ cls/rgw/cls_rgw_ops.h \ cls/rgw/cls_rgw_types.h \ cls/user/cls_user_client.h \ cls/user/cls_user_ops.h \ cls/user/cls_user_types.h ceph-0.80.11/src/cls/version/0000775000175100017510000000000012623077035017724 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/version/cls_version_types.h0000664000175100017510000000277512623076744023670 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_VERSION_TYPES_H #define CEPH_CLS_VERSION_TYPES_H #include "include/encoding.h" #include "include/types.h" class JSONObj; struct obj_version { uint64_t ver; string tag; obj_version() : ver(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(ver, bl); ::encode(tag, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(ver, bl); ::decode(tag, bl); DECODE_FINISH(bl); } void inc() { ver++; } bool empty() { return tag.empty(); } bool compare(struct obj_version *v) { return (ver == v->ver && tag.compare(v->tag) == 0); } void dump(Formatter *f) const; void decode_json(JSONObj *obj); }; WRITE_CLASS_ENCODER(obj_version) enum VersionCond { VER_COND_NONE = 0, VER_COND_EQ, /* equal */ VER_COND_GT, /* greater than */ VER_COND_GE, /* greater or equal */ VER_COND_LT, /* less than */ VER_COND_LE, /* less or equal */ VER_COND_TAG_EQ, VER_COND_TAG_NE, }; struct obj_version_cond { struct obj_version ver; VersionCond cond; void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(ver, bl); uint32_t c = (uint32_t)cond; ::encode(c, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(ver, bl); uint32_t c; ::decode(c, bl); cond = (VersionCond)c; DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(obj_version_cond) #endif ceph-0.80.11/src/cls/version/cls_version_client.cc0000664000175100017510000000412612623076744024130 0ustar jenkins-buildjenkins-build#include #include "include/types.h" #include "cls/version/cls_version_ops.h" #include "include/rados/librados.hpp" using namespace librados; void cls_version_set(librados::ObjectWriteOperation& op, obj_version& objv) { bufferlist in; cls_version_set_op call; call.objv = objv; ::encode(call, in); op.exec("version", "set", in); } void cls_version_inc(librados::ObjectWriteOperation& op) { bufferlist in; cls_version_inc_op call; ::encode(call, in); op.exec("version", "inc", in); } void cls_version_inc(librados::ObjectWriteOperation& op, obj_version& objv, VersionCond cond) { bufferlist in; cls_version_inc_op call; call.objv = objv; obj_version_cond c; c.cond = cond; c.ver = objv; call.conds.push_back(c); ::encode(call, in); op.exec("version", "inc_conds", in); } void cls_version_check(librados::ObjectOperation& op, obj_version& objv, VersionCond cond) { bufferlist in; cls_version_inc_op call; call.objv = objv; obj_version_cond c; c.cond = cond; c.ver = objv; call.conds.push_back(c); ::encode(call, in); op.exec("version", "check_conds", in); } class VersionReadCtx : public ObjectOperationCompletion { obj_version *objv; public: VersionReadCtx(obj_version *_objv) : objv(_objv) {} void handle_completion(int r, bufferlist& outbl) { if (r >= 0) { cls_version_read_ret ret; try { bufferlist::iterator iter = outbl.begin(); ::decode(ret, iter); *objv = ret.objv; } catch (buffer::error& err) { // nothing we can do about it atm } } } }; void cls_version_read(librados::ObjectReadOperation& op, obj_version *objv) { bufferlist inbl; op.exec("version", "read", inbl, new VersionReadCtx(objv)); } int cls_version_read(librados::IoCtx& io_ctx, string& oid, obj_version *ver) { bufferlist in, out; int r = io_ctx.exec(oid, "version", "read", in, out); if (r < 0) return r; cls_version_read_ret ret; try { bufferlist::iterator iter = out.begin(); ::decode(ret, iter); } catch (buffer::error& err) { return -EIO; } *ver = ret.objv; return r; } ceph-0.80.11/src/cls/version/cls_version_types.cc0000664000175100017510000000053612623076744024017 0ustar jenkins-buildjenkins-build #include "cls/version/cls_version_types.h" #include "common/Formatter.h" #include "common/ceph_json.h" void obj_version::dump(Formatter *f) const { f->dump_int("ver", ver); f->dump_string("tag", tag); } void obj_version::decode_json(JSONObj *obj) { JSONDecoder::decode_json("ver", ver, obj); JSONDecoder::decode_json("tag", tag, obj); } ceph-0.80.11/src/cls/version/cls_version_ops.h0000664000175100017510000000346512623076744023322 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_VERSION_OPS_H #define CEPH_CLS_VERSION_OPS_H #include #include "include/types.h" #include "cls_version_types.h" struct cls_version_set_op { obj_version objv; cls_version_set_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(objv, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(objv, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_version_set_op) struct cls_version_inc_op { obj_version objv; list conds; cls_version_inc_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(objv, bl); ::encode(conds, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(objv, bl); ::decode(conds, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_version_inc_op) struct cls_version_check_op { obj_version objv; list conds; cls_version_check_op() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(objv, bl); ::encode(conds, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(objv, bl); ::decode(conds, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_version_check_op) struct cls_version_read_ret { obj_version objv; cls_version_read_ret() {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(objv, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(objv, bl); DECODE_FINISH(bl); } }; WRITE_CLASS_ENCODER(cls_version_read_ret) #endif ceph-0.80.11/src/cls/version/cls_version.cc0000664000175100017510000001271212623076744022572 0ustar jenkins-buildjenkins-build// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "objclass/objclass.h" #include "cls/version/cls_version_types.h" #include "cls/version/cls_version_ops.h" #include "common/Clock.h" #include "global/global_context.h" CLS_VER(1,0) CLS_NAME(version) cls_handle_t h_class; cls_method_handle_t h_version_set; cls_method_handle_t h_version_inc; cls_method_handle_t h_version_inc_conds; cls_method_handle_t h_version_read; cls_method_handle_t h_version_check_conds; #define VERSION_ATTR "ceph.objclass.version" static int set_version(cls_method_context_t hctx, struct obj_version *objv) { bufferlist bl; ::encode(*objv, bl); CLS_LOG(20, "cls_version: set_version %s:%d", objv->tag.c_str(), (int)objv->ver); int ret = cls_cxx_setxattr(hctx, VERSION_ATTR, &bl); if (ret < 0) return ret; return 0; } static int init_version(cls_method_context_t hctx, struct obj_version *objv) { #define TAG_LEN 24 char buf[TAG_LEN + 1]; int ret = cls_gen_rand_base64(buf, sizeof(buf)); if (ret < 0) return ret; objv->ver = 1; objv->tag = buf; CLS_LOG(20, "cls_version: init_version %s:%d", objv->tag.c_str(), (int)objv->ver); return set_version(hctx, objv); } /* implicit create should be true only if called from a write operation (set, inc), never from a read operation (read, check) */ static int read_version(cls_method_context_t hctx, obj_version *objv, bool implicit_create) { bufferlist bl; int ret = cls_cxx_getxattr(hctx, VERSION_ATTR, &bl); if (ret == -ENOENT || ret == -ENODATA) { objv->ver = 0; if (implicit_create) { return init_version(hctx, objv); } return 0; } if (ret < 0) return ret; try { bufferlist::iterator iter = bl.begin(); ::decode(*objv, iter); } catch (buffer::error& err) { CLS_LOG(0, "ERROR: read_version(): failed to decode version entry\n"); return -EIO; } return 0; } static int cls_version_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_version_set_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n"); return -EINVAL; } int ret = set_version(hctx, &op.objv); if (ret < 0) return ret; return 0; } static bool check_conds(list& conds, obj_version& objv) { if (conds.empty()) return true; for (list::iterator iter = conds.begin(); iter != conds.end(); ++iter) { obj_version_cond& cond = *iter; obj_version& v = cond.ver; switch (cond.cond) { case VER_COND_NONE: break; case VER_COND_EQ: if (!objv.compare(&v)) return false; break; case VER_COND_GT: if (!(objv.ver > v.ver)) return false; break; case VER_COND_GE: if (!(objv.ver >= v.ver)) return false; break; case VER_COND_LT: if (!(objv.ver < v.ver)) return false; break; case VER_COND_LE: if (!(objv.ver <= v.ver)) return false; break; case VER_COND_TAG_EQ: if (objv.tag.compare(v.tag) != 0) return false; break; case VER_COND_TAG_NE: if (objv.tag.compare(v.tag) == 0) return false; break; } } return true; } static int cls_version_inc(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_version_inc_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n"); return -EINVAL; } obj_version objv; int ret = read_version(hctx, &objv, true); if (ret < 0) return ret; if (!check_conds(op.conds, objv)) { return -ECANCELED; } objv.inc(); ret = set_version(hctx, &objv); if (ret < 0) return ret; return 0; } static int cls_version_check(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist::iterator in_iter = in->begin(); cls_version_check_op op; try { ::decode(op, in_iter); } catch (buffer::error& err) { CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n"); return -EINVAL; } obj_version objv; int ret = read_version(hctx, &objv, false); if (ret < 0) return ret; CLS_LOG(20, "cls_version: read_version %s:%d", objv.tag.c_str(), (int)objv.ver); if (!check_conds(op.conds, objv)) { CLS_LOG(20, "cls_version: failed condition check"); return -ECANCELED; } return 0; } static int cls_version_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { obj_version objv; cls_version_read_ret read_ret; int ret = read_version(hctx, &read_ret.objv, false); if (ret < 0) return ret; ::encode(read_ret, *out); return 0; } void __cls_init() { CLS_LOG(1, "Loaded version class!"); cls_register("version", &h_class); /* version */ cls_register_cxx_method(h_class, "set", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_set, &h_version_set); cls_register_cxx_method(h_class, "inc", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_inc, &h_version_inc); cls_register_cxx_method(h_class, "inc_conds", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_inc, &h_version_inc_conds); cls_register_cxx_method(h_class, "read", CLS_METHOD_RD, cls_version_read, &h_version_read); cls_register_cxx_method(h_class, "check_conds", CLS_METHOD_RD, cls_version_check, &h_version_check_conds); return; } ceph-0.80.11/src/cls/version/cls_version_client.h0000664000175100017510000000133612623076744023772 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_VERSION_CLIENT_H #define CEPH_CLS_VERSION_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" /* * version objclass */ void cls_version_set(librados::ObjectWriteOperation& op, obj_version& ver); /* increase anyway */ void cls_version_inc(librados::ObjectWriteOperation& op); /* conditional increase, return -EAGAIN if condition fails */ void cls_version_inc(librados::ObjectWriteOperation& op, obj_version& ver, VersionCond cond); void cls_version_read(librados::ObjectReadOperation& op, obj_version *objv); int cls_version_read(librados::IoCtx& io_ctx, string& oid, obj_version *ver); void cls_version_check(librados::ObjectOperation& op, obj_version& ver, VersionCond cond); #endif ceph-0.80.11/src/cls/lock/0000775000175100017510000000000012623077035017167 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/lock/cls_lock_client.cc0000664000175100017510000001405212623076744022635 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "msg/msg_types.h" #include "include/rados/librados.hpp" using namespace librados; #include #include #include #include #include "cls/lock/cls_lock_types.h" #include "cls/lock/cls_lock_ops.h" #include "cls/lock/cls_lock_client.h" namespace rados { namespace cls { namespace lock { void lock(ObjectWriteOperation *rados_op, const string& name, ClsLockType type, const string& cookie, const string& tag, const string& description, const utime_t& duration, uint8_t flags) { cls_lock_lock_op op; op.name = name; op.type = type; op.cookie = cookie; op.tag = tag; op.description = description; op.duration = duration; op.flags = flags; bufferlist in; ::encode(op, in); rados_op->exec("lock", "lock", in); } int lock(IoCtx *ioctx, const string& oid, const string& name, ClsLockType type, const string& cookie, const string& tag, const string& description, const utime_t& duration, uint8_t flags) { ObjectWriteOperation op; lock(&op, name, type, cookie, tag, description, duration, flags); return ioctx->operate(oid, &op); } void unlock(ObjectWriteOperation *rados_op, const string& name, const string& cookie) { cls_lock_unlock_op op; op.name = name; op.cookie = cookie; bufferlist in; ::encode(op, in); rados_op->exec("lock", "unlock", in); } int unlock(IoCtx *ioctx, const string& oid, const string& name, const string& cookie) { ObjectWriteOperation op; unlock(&op, name, cookie); return ioctx->operate(oid, &op); } void break_lock(ObjectWriteOperation *rados_op, const string& name, const string& cookie, const entity_name_t& locker) { cls_lock_break_op op; op.name = name; op.cookie = cookie; op.locker = locker; bufferlist in; ::encode(op, in); rados_op->exec("lock", "break_lock", in); } int break_lock(IoCtx *ioctx, const string& oid, const string& name, const string& cookie, const entity_name_t& locker) { ObjectWriteOperation op; break_lock(&op, name, cookie, locker); return ioctx->operate(oid, &op); } int list_locks(IoCtx *ioctx, const string& oid, list *locks) { bufferlist in, out; int r = ioctx->exec(oid, "lock", "list_locks", in, out); if (r < 0) return r; cls_lock_list_locks_reply ret; bufferlist::iterator iter = out.begin(); try { ::decode(ret, iter); } catch (buffer::error& err) { return -EBADMSG; } *locks = ret.locks; return 0; } void get_lock_info_start(ObjectReadOperation *rados_op, const string& name) { bufferlist in; cls_lock_get_info_op op; op.name = name; ::encode(op, in); rados_op->exec("lock", "get_info", in); } int get_lock_info_finish(bufferlist::iterator *iter, map *lockers, ClsLockType *type, string *tag) { cls_lock_get_info_reply ret; try { ::decode(ret, *iter); } catch (buffer::error& err) { return -EBADMSG; } if (lockers) { *lockers = ret.lockers; } if (type) { *type = ret.lock_type; } if (tag) { *tag = ret.tag; } return 0; } int get_lock_info(IoCtx *ioctx, const string& oid, const string& name, map *lockers, ClsLockType *type, string *tag) { ObjectReadOperation op; get_lock_info_start(&op, name); bufferlist out; int r = ioctx->operate(oid, &op, &out); if (r < 0) return r; bufferlist::iterator it = out.begin(); return get_lock_info_finish(&it, lockers, type, tag); } void Lock::lock_shared(ObjectWriteOperation *op) { lock(op, name, LOCK_SHARED, cookie, tag, description, duration, flags); } int Lock::lock_shared(IoCtx *ioctx, const string& oid) { return lock(ioctx, oid, name, LOCK_SHARED, cookie, tag, description, duration, flags); } void Lock::lock_exclusive(ObjectWriteOperation *op) { lock(op, name, LOCK_EXCLUSIVE, cookie, tag, description, duration, flags); } int Lock::lock_exclusive(IoCtx *ioctx, const string& oid) { return lock(ioctx, oid, name, LOCK_EXCLUSIVE, cookie, tag, description, duration, flags); } void Lock::unlock(ObjectWriteOperation *op) { rados::cls::lock::unlock(op, name, cookie); } int Lock::unlock(IoCtx *ioctx, const string& oid) { return rados::cls::lock::unlock(ioctx, oid, name, cookie); } void Lock::break_lock(ObjectWriteOperation *op, const entity_name_t& locker) { rados::cls::lock::break_lock(op, name, cookie, locker); } int Lock::break_lock(IoCtx *ioctx, const string& oid, const entity_name_t& locker) { return rados::cls::lock::break_lock(ioctx, oid, name, cookie, locker); } } // namespace lock } // namespace cls } // namespace rados ceph-0.80.11/src/cls/lock/cls_lock_ops.cc0000664000175100017510000001126312623076744022161 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "msg/msg_types.h" #include "common/Formatter.h" #include "cls/lock/cls_lock_types.h" #include "cls/lock/cls_lock_ops.h" using namespace rados::cls::lock; static void generate_lock_id(locker_id_t& i, int n, const string& cookie) { i.locker = entity_name_t(entity_name_t::CLIENT(n)); i.cookie = cookie; } void cls_lock_lock_op::dump(Formatter *f) const { f->dump_string("name", name); f->dump_string("type", cls_lock_type_str(type)); f->dump_string("cookie", cookie); f->dump_string("tag", tag); f->dump_string("description", description); f->dump_stream("duration") << duration; f->dump_int("flags", (int)flags); } void cls_lock_lock_op::generate_test_instances(list& o) { cls_lock_lock_op *i = new cls_lock_lock_op; i->name = "name"; i->type = LOCK_SHARED; i->cookie = "cookie"; i->tag = "tag"; i->description = "description"; i->duration = utime_t(5, 0); i->flags = LOCK_FLAG_RENEW; o.push_back(i); o.push_back(new cls_lock_lock_op); } void cls_lock_unlock_op::dump(Formatter *f) const { f->dump_string("name", name); f->dump_string("cookie", cookie); } void cls_lock_unlock_op::generate_test_instances(list& o) { cls_lock_unlock_op *i = new cls_lock_unlock_op; i->name = "name"; i->cookie = "cookie"; o.push_back(i); o.push_back(new cls_lock_unlock_op); } void cls_lock_break_op::dump(Formatter *f) const { f->dump_string("name", name); f->dump_string("cookie", cookie); f->dump_stream("locker") << locker; } void cls_lock_break_op::generate_test_instances(list& o) { cls_lock_break_op *i = new cls_lock_break_op; i->name = "name"; i->cookie = "cookie"; i->locker = entity_name_t(entity_name_t::CLIENT(1)); o.push_back(i); o.push_back(new cls_lock_break_op); } void cls_lock_get_info_op::dump(Formatter *f) const { f->dump_string("name", name); } void cls_lock_get_info_op::generate_test_instances(list& o) { cls_lock_get_info_op *i = new cls_lock_get_info_op; i->name = "name"; o.push_back(i); o.push_back(new cls_lock_get_info_op); } static void generate_test_addr(entity_addr_t& a, int nonce, int port) { a.set_nonce(nonce); a.set_family(AF_INET); a.set_in4_quad(0, 127); a.set_in4_quad(1, 0); a.set_in4_quad(2, 1); a.set_in4_quad(3, 2); a.set_port(port); } void cls_lock_get_info_reply::dump(Formatter *f) const { f->dump_string("lock_type", cls_lock_type_str(lock_type)); f->dump_string("tag", tag); f->open_array_section("lockers"); map::const_iterator iter; for (iter = lockers.begin(); iter != lockers.end(); ++iter) { const locker_id_t& id = iter->first; const locker_info_t& info = iter->second; f->open_object_section("object"); f->dump_stream("locker") << id.locker; f->dump_string("description", info.description); f->dump_string("cookie", id.cookie); f->dump_stream("expiration") << info.expiration; f->dump_stream("addr") << info.addr; f->close_section(); } f->close_section(); } void cls_lock_get_info_reply::generate_test_instances(list& o) { cls_lock_get_info_reply *i = new cls_lock_get_info_reply; i->lock_type = LOCK_SHARED; i->tag = "tag"; locker_id_t id1, id2; entity_addr_t addr1, addr2; generate_lock_id(id1, 1, "cookie1"); generate_test_addr(addr1, 10, 20); i->lockers[id1] = locker_info_t(utime_t(10, 0), addr1, "description1"); generate_lock_id(id2, 2, "cookie2"); generate_test_addr(addr2, 30, 40); i->lockers[id2] = locker_info_t(utime_t(20, 0), addr2, "description2"); o.push_back(i); o.push_back(new cls_lock_get_info_reply); } void cls_lock_list_locks_reply::dump(Formatter *f) const { list::const_iterator iter; f->open_array_section("locks"); for (iter = locks.begin(); iter != locks.end(); ++iter) { f->open_array_section("object"); f->dump_string("lock", *iter); f->close_section(); } f->close_section(); } void cls_lock_list_locks_reply::generate_test_instances(list& o) { cls_lock_list_locks_reply *i = new cls_lock_list_locks_reply; i->locks.push_back("lock1"); i->locks.push_back("lock2"); i->locks.push_back("lock3"); o.push_back(i); o.push_back(new cls_lock_list_locks_reply); } ceph-0.80.11/src/cls/lock/cls_lock.cc0000664000175100017510000002744112623076744021305 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /** \file * * This is an OSD class that implements methods for object * advisory locking. * */ #include #include #include #include #include #include #include #include #include "include/types.h" #include "include/utime.h" #include "objclass/objclass.h" #include "common/errno.h" #include "common/Clock.h" #include "cls/lock/cls_lock_types.h" #include "cls/lock/cls_lock_ops.h" #include "global/global_context.h" using namespace rados::cls::lock; CLS_VER(1,0) CLS_NAME(lock) cls_handle_t h_class; cls_method_handle_t h_lock_op; cls_method_handle_t h_unlock_op; cls_method_handle_t h_break_lock; cls_method_handle_t h_get_info; cls_method_handle_t h_list_locks; #define LOCK_PREFIX "lock." typedef struct lock_info_s { map lockers; // map of lockers ClsLockType lock_type; // lock type (exclusive / shared) string tag; // tag: operations on lock can only succeed with this tag // as long as set of non expired lockers // is bigger than 0. void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(lockers, bl); uint8_t t = (uint8_t)lock_type; ::encode(t, bl); ::encode(tag, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(lockers, bl); uint8_t t; ::decode(t, bl); lock_type = (ClsLockType)t; ::decode(tag, bl); DECODE_FINISH(bl); } lock_info_s() : lock_type(LOCK_NONE) {} } lock_info_t; WRITE_CLASS_ENCODER(lock_info_t) static int read_lock(cls_method_context_t hctx, const string& name, lock_info_t *lock) { bufferlist bl; string key = LOCK_PREFIX; key.append(name); int r = cls_cxx_getxattr(hctx, key.c_str(), &bl); if (r < 0) { if (r == -ENODATA) { *lock = lock_info_t(); return 0; } if (r != -ENOENT) { CLS_ERR("error reading xattr %s: %d", key.c_str(), r); } return r; } try { bufferlist::iterator it = bl.begin(); ::decode(*lock, it); } catch (const buffer::error &err) { CLS_ERR("error decoding %s", key.c_str()); return -EIO; } /* now trim expired locks */ utime_t now = ceph_clock_now(g_ceph_context); map::iterator iter = lock->lockers.begin(); while (iter != lock->lockers.end()) { map::iterator next = iter; ++next; struct locker_info_t& info = iter->second; if (!info.expiration.is_zero() && info.expiration < now) { CLS_LOG(20, "expiring locker"); lock->lockers.erase(iter); } iter = next; } return 0; } static int write_lock(cls_method_context_t hctx, const string& name, const lock_info_t& lock) { string key = LOCK_PREFIX; key.append(name); bufferlist lock_bl; ::encode(lock, lock_bl); int r = cls_cxx_setxattr(hctx, key.c_str(), &lock_bl); if (r < 0) return r; return 0; } /** * helper function to add a lock and update disk state. * * Input: * @param name Lock name * @param lock_type Type of lock (exclusive / shared) * @param duration Duration of lock (in seconds). Zero means it doesn't expire. * @param flags lock flags * @param cookie The cookie to set in the lock * @param tag The tag to match with the lock (can only lock with matching tags) * @param lock_description The lock description to set (if not empty) * @param locker_description The locker description * * @return 0 on success, or -errno on failure */ static int lock_obj(cls_method_context_t hctx, const string& name, ClsLockType lock_type, utime_t duration, const string& description, uint8_t flags, const string& cookie, const string& tag) { bool exclusive = lock_type == LOCK_EXCLUSIVE; lock_info_t linfo; bool fail_if_exists = (flags & LOCK_FLAG_RENEW) == 0; CLS_LOG(20, "requested lock_type=%s fail_if_exists=%d", cls_lock_type_str(lock_type), fail_if_exists); if (lock_type != LOCK_EXCLUSIVE && lock_type != LOCK_SHARED) return -EINVAL; if (name.empty()) return -EINVAL; // see if there's already a locker int r = read_lock(hctx, name, &linfo); if (r < 0 && r != -ENOENT) { CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); return r; } map& lockers = linfo.lockers; map::iterator iter; locker_id_t id; id.cookie = cookie; entity_inst_t inst; r = cls_get_request_origin(hctx, &inst); id.locker = inst.name; assert(r == 0); /* check this early, before we check fail_if_exists, otherwise we might * remove the locker entry and not check it later */ if (lockers.size() && tag != linfo.tag) { CLS_LOG(20, "cannot take lock on object, conflicting tag"); return -EBUSY; } ClsLockType existing_lock_type = linfo.lock_type; CLS_LOG(20, "existing_lock_type=%s", cls_lock_type_str(existing_lock_type)); iter = lockers.find(id); if (iter != lockers.end()) { if (fail_if_exists) { return -EEXIST; } else { lockers.erase(iter); // remove old entry } } if (!lockers.empty()) { if (exclusive) { CLS_LOG(20, "could not exclusive-lock object, already locked"); return -EBUSY; } if (existing_lock_type != lock_type) { CLS_LOG(20, "cannot take lock on object, conflicting lock type"); return -EBUSY; } } linfo.lock_type = lock_type; linfo.tag = tag; utime_t expiration; if (!duration.is_zero()) { expiration = ceph_clock_now(g_ceph_context); expiration += duration; } struct locker_info_t info(expiration, inst.addr, description); linfo.lockers[id] = info; r = write_lock(hctx, name, linfo); if (r < 0) return r; return 0; } /** * Set an exclusive lock on an object for the activating client, if possible. * * Input: * @param cls_lock_lock_op request input * * @returns 0 on success, -EINVAL if it can't decode the lock_cookie, * -EBUSY if the object is already locked, or -errno on (unexpected) failure. */ static int lock_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "lock_op"); cls_lock_lock_op op; try { bufferlist::iterator iter = in->begin(); ::decode(op, iter); } catch (const buffer::error &err) { return -EINVAL; } return lock_obj(hctx, op.name, op.type, op.duration, op.description, op.flags, op.cookie, op.tag); } /** * helper function to remove a lock from on disk and clean up state. * * @param name The lock name * @param locker The locker entity name * @param cookie The user-defined cookie associated with the lock. * * @return 0 on success, -ENOENT if there is no such lock (either * entity or cookie is wrong), or -errno on other error. */ static int remove_lock(cls_method_context_t hctx, const string& name, entity_name_t& locker, const string& cookie) { // get current lockers lock_info_t linfo; int r = read_lock(hctx, name, &linfo); if (r < 0) { CLS_ERR("Could not read list of current lockers off disk: %s", cpp_strerror(r).c_str()); return r; } map& lockers = linfo.lockers; struct locker_id_t id(locker, cookie); // remove named locker from set map::iterator iter = lockers.find(id); if (iter == lockers.end()) { // no such key return -ENOENT; } lockers.erase(iter); r = write_lock(hctx, name, linfo); return r; } /** * Unlock an object which the activating client currently has locked. * * Input: * @param cls_lock_unlock_op request input * * @return 0 on success, -EINVAL if it can't decode the cookie, -ENOENT * if there is no such lock (either entity or cookie is wrong), or * -errno on other (unexpected) error. */ static int unlock_op(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "unlock_op"); cls_lock_unlock_op op; try { bufferlist::iterator iter = in->begin(); ::decode(op, iter); } catch (const buffer::error& err) { return -EINVAL; } entity_inst_t inst; int r = cls_get_request_origin(hctx, &inst); assert(r == 0); return remove_lock(hctx, op.name, inst.name, op.cookie); } /** * Break the lock on an object held by any client. * * Input: * @param cls_lock_break_op request input * * @return 0 on success, -EINVAL if it can't decode the locker and * cookie, -ENOENT if there is no such lock (either entity or cookie * is wrong), or -errno on other (unexpected) error. */ static int break_lock(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "break_lock"); cls_lock_break_op op; try { bufferlist::iterator iter = in->begin(); ::decode(op, iter); } catch (const buffer::error& err) { return -EINVAL; } return remove_lock(hctx, op.name, op.locker, op.cookie); } /** * Retrieve lock info: lockers, tag, exclusive * * Input: * @param cls_lock_list_lockers_op request input * * Output: * @param cls_lock_list_lockers_reply result * * @return 0 on success, -errno on failure. */ static int get_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "get_info"); cls_lock_get_info_op op; try { bufferlist::iterator iter = in->begin(); ::decode(op, iter); } catch (const buffer::error& err) { return -EINVAL; } // get current lockers lock_info_t linfo; int r = read_lock(hctx, op.name, &linfo); if (r < 0) { CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); return r; } struct cls_lock_get_info_reply ret; map::iterator iter; for (iter = linfo.lockers.begin(); iter != linfo.lockers.end(); ++iter) { ret.lockers[iter->first] = iter->second; } ret.lock_type = linfo.lock_type; ret.tag = linfo.tag; ::encode(ret, *out); return 0; } /** * Retrieve a list of locks for this object * * Input: * @param in is ignored. * * Output: * @param out contains encoded cls_list_locks_reply * * @return 0 on success, -errno on failure. */ static int list_locks(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "list_locks"); map attrs; int r = cls_cxx_getxattrs(hctx, &attrs); if (r < 0) return r; cls_lock_list_locks_reply ret; map::iterator iter; size_t pos = sizeof(LOCK_PREFIX) - 1; for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const string& attr = iter->first; if (attr.substr(0, pos).compare(LOCK_PREFIX) == 0) { ret.locks.push_back(attr.substr(pos)); } } ::encode(ret, *out); return 0; } void __cls_init() { CLS_LOG(20, "Loaded lock class!"); cls_register("lock", &h_class); cls_register_cxx_method(h_class, "lock", CLS_METHOD_RD | CLS_METHOD_WR, lock_op, &h_lock_op); cls_register_cxx_method(h_class, "unlock", CLS_METHOD_RD | CLS_METHOD_WR, unlock_op, &h_unlock_op); cls_register_cxx_method(h_class, "break_lock", CLS_METHOD_RD | CLS_METHOD_WR, break_lock, &h_break_lock); cls_register_cxx_method(h_class, "get_info", CLS_METHOD_RD, get_info, &h_get_info); cls_register_cxx_method(h_class, "list_locks", CLS_METHOD_RD, list_locks, &h_list_locks); return; } ceph-0.80.11/src/cls/lock/cls_lock_types.h0000664000175100017510000000551712623076744022373 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_LOCK_TYPES_H #define CEPH_CLS_LOCK_TYPES_H #include "include/encoding.h" #include "include/types.h" #include "include/utime.h" #include "msg/msg_types.h" /* lock flags */ #define LOCK_FLAG_RENEW 0x1 /* idempotent lock acquire */ enum ClsLockType { LOCK_NONE = 0, LOCK_EXCLUSIVE = 1, LOCK_SHARED = 2, }; static inline const char *cls_lock_type_str(ClsLockType type) { switch (type) { case LOCK_NONE: return "none"; case LOCK_EXCLUSIVE: return "exclusive"; case LOCK_SHARED: return "shared"; default: return ""; } } namespace rados { namespace cls { namespace lock { /* * locker_id_t: the locker id, needs to be unique in a single lock */ struct locker_id_t { entity_name_t locker; // locker's client name string cookie; // locker's cookie. locker_id_t() {} locker_id_t(entity_name_t& _n, const string& _c) : locker(_n), cookie(_c) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(locker, bl); ::encode(cookie, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(locker, bl); ::decode(cookie, bl); DECODE_FINISH(bl); } bool operator<(const locker_id_t& rhs) const { if (locker == rhs.locker) return cookie.compare(rhs.cookie) < 0; if (locker < rhs.locker) return true; return false; } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rados::cls::lock::locker_id_t) struct locker_info_t { utime_t expiration; // expiration: non-zero means epoch of locker expiration entity_addr_t addr; // addr: locker address string description; // description: locker description, may be empty locker_info_t() {} locker_info_t(const utime_t& _e, const entity_addr_t& _a, const string& _d) : expiration(_e), addr(_a), description(_d) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(expiration, bl); ::encode(addr, bl); ::encode(description, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(expiration, bl); ::decode(addr, bl); ::decode(description, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(rados::cls::lock::locker_info_t) } } } #endif ceph-0.80.11/src/cls/lock/cls_lock_ops.h0000664000175100017510000001000612623076744022015 0ustar jenkins-buildjenkins-build#ifndef CEPH_CLS_LOCK_OPS_H #define CEPH_CLS_LOCK_OPS_H #include "include/types.h" #include "include/utime.h" #include "cls/lock/cls_lock_types.h" struct cls_lock_lock_op { string name; ClsLockType type; string cookie; string tag; string description; utime_t duration; uint8_t flags; cls_lock_lock_op() : type(LOCK_NONE), flags(0) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(name, bl); uint8_t t = (uint8_t)type; ::encode(t, bl); ::encode(cookie, bl); ::encode(tag, bl); ::encode(description, bl); ::encode(duration, bl); ::encode(flags, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(name, bl); uint8_t t; ::decode(t, bl); type = (ClsLockType)t; ::decode(cookie, bl); ::decode(tag, bl); ::decode(description, bl); ::decode(duration, bl); ::decode(flags, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(cls_lock_lock_op) struct cls_lock_unlock_op { string name; string cookie; cls_lock_unlock_op() {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(name, bl); ::encode(cookie, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(name, bl); ::decode(cookie, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(cls_lock_unlock_op) struct cls_lock_break_op { string name; entity_name_t locker; string cookie; cls_lock_break_op() {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(name, bl); ::encode(locker, bl); ::encode(cookie, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(name, bl); ::decode(locker, bl); ::decode(cookie, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(cls_lock_break_op) struct cls_lock_get_info_op { string name; cls_lock_get_info_op() {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(name, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(name, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(cls_lock_get_info_op) struct cls_lock_get_info_reply { map lockers; ClsLockType lock_type; string tag; cls_lock_get_info_reply() : lock_type(LOCK_NONE) {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(lockers, bl); uint8_t t = (uint8_t)lock_type; ::encode(t, bl); ::encode(tag, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(lockers, bl); uint8_t t; ::decode(t, bl); lock_type = (ClsLockType)t; ::decode(tag, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(cls_lock_get_info_reply) struct cls_lock_list_locks_reply { list locks; cls_lock_list_locks_reply() {} void encode(bufferlist &bl) const { ENCODE_START(1, 1, bl); ::encode(locks, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator &bl) { DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl); ::decode(locks, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(cls_lock_list_locks_reply) #endif ceph-0.80.11/src/cls/lock/cls_lock_client.h0000664000175100017510000000640012623076744022475 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLS_LOCK_CLIENT_H #define CEPH_CLS_LOCK_CLIENT_H #include "include/types.h" #include "include/rados/librados.hpp" #include "cls/lock/cls_lock_types.h" namespace rados { namespace cls { namespace lock { extern void lock(librados::ObjectWriteOperation *rados_op, const std::string& name, ClsLockType type, const std::string& cookie, const std::string& tag, const std::string& description, const utime_t& duration, uint8_t flags); extern int lock(librados::IoCtx *ioctx, const std::string& oid, const std::string& name, ClsLockType type, const std::string& cookie, const std::string& tag, const std::string& description, const utime_t& duration, uint8_t flags); extern void unlock(librados::ObjectWriteOperation *rados_op, const std::string& name, const std::string& cookie); extern int unlock(librados::IoCtx *ioctx, const std::string& oid, const std::string& name, const std::string& cookie); extern void break_lock(librados::ObjectWriteOperation *op, const std::string& name, const std::string& cookie, const entity_name_t& locker); extern int break_lock(librados::IoCtx *ioctx, const std::string& oid, const std::string& name, const std::string& cookie, const entity_name_t& locker); extern int list_locks(librados::IoCtx *ioctx, const std::string& oid, list *locks); extern void get_lock_info_start(librados::ObjectReadOperation *rados_op, const std::string& name); extern int get_lock_info_finish(ceph::bufferlist::iterator *out, map *lockers, ClsLockType *type, std::string *tag); extern int get_lock_info(librados::IoCtx *ioctx, const std::string& oid, const std::string& name, map *lockers, ClsLockType *type, std::string *tag); class Lock { std::string name; std::string cookie; std::string tag; std::string description; utime_t duration; uint8_t flags; public: Lock(const std::string& _n) : name(_n), flags(0) {} void set_cookie(const std::string& c) { cookie = c; } void set_tag(const std::string& t) { tag = t; } void set_description(const std::string& desc) { description = desc; } void set_duration(const utime_t& e) { duration = e; } void set_renew(bool renew) { if (renew) { flags |= LOCK_FLAG_RENEW; } else { flags &= ~LOCK_FLAG_RENEW; } } /* ObjectWriteOperation */ void lock_exclusive(librados::ObjectWriteOperation *ioctx); void lock_shared(librados::ObjectWriteOperation *ioctx); void unlock(librados::ObjectWriteOperation *ioctx); void break_lock(librados::ObjectWriteOperation *ioctx, const entity_name_t& locker); /* IoCtx */ int lock_exclusive(librados::IoCtx *ioctx, const std::string& oid); int lock_shared(librados::IoCtx *ioctx, const std::string& oid); int unlock(librados::IoCtx *ioctx, const std::string& oid); int break_lock(librados::IoCtx *ioctx, const std::string& oid, const entity_name_t& locker); }; } // namespace lock } // namespace cls } // namespace rados #endif ceph-0.80.11/src/cls/lock/cls_lock_types.cc0000664000175100017510000000331612623076744022524 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "msg/msg_types.h" #include "common/Formatter.h" #include "cls/lock/cls_lock_types.h" using namespace rados::cls::lock; static void generate_lock_id(locker_id_t& i, int n, const string& cookie) { i.locker = entity_name_t(entity_name_t::CLIENT(n)); i.cookie = cookie; } void locker_id_t::dump(Formatter *f) const { f->dump_stream("locker") << locker; f->dump_string("cookie", cookie); } void locker_id_t::generate_test_instances(list& o) { locker_id_t *i = new locker_id_t; generate_lock_id(*i, 1, "cookie"); o.push_back(i); o.push_back(new locker_id_t); } void locker_info_t::dump(Formatter *f) const { f->dump_stream("expiration") << expiration; f->dump_stream("addr") << addr; f->dump_string("description", description); } static void generate_test_addr(entity_addr_t& a, int nonce, int port) { a.set_nonce(nonce); a.set_family(AF_INET); a.set_in4_quad(0, 127); a.set_in4_quad(1, 0); a.set_in4_quad(2, 1); a.set_in4_quad(3, 2); a.set_port(port); } void locker_info_t::generate_test_instances(list& o) { locker_info_t *i = new locker_info_t; i->expiration = utime_t(5, 0); generate_test_addr(i->addr, 1, 2); i->description = "description"; o.push_back(i); o.push_back(new locker_info_t); } ceph-0.80.11/src/cls/rbd/0000775000175100017510000000000012623077035017006 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/cls/rbd/cls_rbd.h0000664000175100017510000000752712623076744020610 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef __CEPH_CLS_RBD_H #define __CEPH_CLS_RBD_H #include "include/types.h" #include "include/buffer.h" #include "common/Formatter.h" #include "librbd/parent_types.h" /// information about our parent image, if any struct cls_rbd_parent { int64_t pool; ///< parent pool id string id; ///< parent image id snapid_t snapid; ///< parent snapid we refer to uint64_t overlap; ///< portion of this image mapped onto parent (bytes) /// true if our parent pointer information is defined bool exists() const { return snapid != CEPH_NOSNAP && pool >= 0 && id.length() > 0 && overlap > 0; } cls_rbd_parent() : pool(-1), snapid(CEPH_NOSNAP), overlap(0) {} void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(pool, bl); ::encode(id, bl); ::encode(snapid, bl); ::encode(overlap, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(pool, bl); ::decode(id, bl); ::decode(snapid, bl); ::decode(overlap, bl); DECODE_FINISH(bl); } void dump(Formatter *f) const { f->dump_int("pool", pool); f->dump_string("id", id); f->dump_unsigned("snapid", snapid); f->dump_unsigned("overlap", overlap); } static void generate_test_instances(list& o) { o.push_back(new cls_rbd_parent); cls_rbd_parent *t = new cls_rbd_parent; t->pool = 1; t->id = "foo"; t->snapid = 3; t->overlap = 500; o.push_back(t); } }; WRITE_CLASS_ENCODER(cls_rbd_parent) struct cls_rbd_snap { snapid_t id; string name; uint64_t image_size; uint64_t features; uint8_t protection_status; cls_rbd_parent parent; /// true if we have a parent bool has_parent() const { return parent.exists(); } cls_rbd_snap() : id(CEPH_NOSNAP), image_size(0), features(0), protection_status(RBD_PROTECTION_STATUS_UNPROTECTED) {} void encode(bufferlist& bl) const { ENCODE_START(3, 1, bl); ::encode(id, bl); ::encode(name, bl); ::encode(image_size, bl); ::encode(features, bl); ::encode(parent, bl); ::encode(protection_status, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& p) { DECODE_START(3, p); ::decode(id, p); ::decode(name, p); ::decode(image_size, p); ::decode(features, p); if (struct_v >= 2) { ::decode(parent, p); } if (struct_v >= 3) { ::decode(protection_status, p); } DECODE_FINISH(p); } void dump(Formatter *f) const { f->dump_unsigned("id", id); f->dump_string("name", name); f->dump_unsigned("image_size", image_size); f->dump_unsigned("features", features); if (has_parent()) { f->open_object_section("parent"); parent.dump(f); f->close_section(); } switch (protection_status) { case RBD_PROTECTION_STATUS_UNPROTECTED: f->dump_string("protection_status", "unprotected"); break; case RBD_PROTECTION_STATUS_UNPROTECTING: f->dump_string("protection_status", "unprotecting"); break; case RBD_PROTECTION_STATUS_PROTECTED: f->dump_string("protection_status", "protected"); break; default: assert(0); } } static void generate_test_instances(list& o) { o.push_back(new cls_rbd_snap); cls_rbd_snap *t = new cls_rbd_snap; t->id = 1; t->name = "snap"; t->image_size = 123456; t->features = 123; o.push_back(t); t = new cls_rbd_snap; t->id = 2; t->name = "snap2"; t->image_size = 12345678; t->features = 1234; t->parent.pool = 1; t->parent.id = "parent"; t->parent.snapid = 456; t->parent.overlap = 12345; t->protection_status = RBD_PROTECTION_STATUS_PROTECTED; o.push_back(t); } }; WRITE_CLASS_ENCODER(cls_rbd_snap) #endif ceph-0.80.11/src/cls/rbd/cls_rbd_client.h0000664000175100017510000001226412623076744022140 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_CLS_RBD_CLIENT_H #define CEPH_LIBRBD_CLS_RBD_CLIENT_H #include "cls/lock/cls_lock_types.h" #include "common/snap_types.h" #include "include/rados/librados.hpp" #include "include/types.h" #include "librbd/parent_types.h" #include #include namespace librbd { namespace cls_client { // high-level interface to the header int get_immutable_metadata(librados::IoCtx *ioctx, const std::string &oid, std::string *object_prefix, uint8_t *order); int get_mutable_metadata(librados::IoCtx *ioctx, const std::string &oid, uint64_t *size, uint64_t *features, uint64_t *incompatible_features, map *lockers, bool *exclusive_lock, std::string *lock_tag, ::SnapContext *snapc, parent_info *parent); // low-level interface (mainly for testing) int create_image(librados::IoCtx *ioctx, const std::string &oid, uint64_t size, uint8_t order, uint64_t features, const std::string &object_prefix); int get_features(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint64_t *features); int get_object_prefix(librados::IoCtx *ioctx, const std::string &oid, std::string *object_prefix); int get_size(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint64_t *size, uint8_t *order); int set_size(librados::IoCtx *ioctx, const std::string &oid, uint64_t size); int set_size(librados::IoCtx *ioctx, const std::string &oid, uint64_t size); int get_parent(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, parent_spec *pspec, uint64_t *parent_overlap); int set_parent(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, uint64_t parent_overlap); int remove_parent(librados::IoCtx *ioctx, const std::string &oid); int add_child(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, const std::string &c_imageid); int remove_child(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, const std::string &c_imageid); int get_children(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, set& children); int snapshot_add(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, const std::string &snap_name); int snapshot_remove(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id); int get_snapcontext(librados::IoCtx *ioctx, const std::string &oid, ::SnapContext *snapc); int snapshot_list(librados::IoCtx *ioctx, const std::string &oid, const std::vector &ids, std::vector *names, std::vector *sizes, std::vector *features, std::vector *parents, std::vector *protection_statuses); int copyup(librados::IoCtx *ioctx, const std::string &oid, bufferlist data); int get_protection_status(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint8_t *protection_status); int set_protection_status(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint8_t protection_status); int get_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, uint64_t *stripe_unit, uint64_t *stripe_count); int set_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, uint64_t stripe_unit, uint64_t stripe_count); // operations on rbd_id objects int get_id(librados::IoCtx *ioctx, const std::string &oid, std::string *id); int set_id(librados::IoCtx *ioctx, const std::string &oid, std::string id); // operations on rbd_directory objects int dir_get_id(librados::IoCtx *ioctx, const std::string &oid, const std::string &name, std::string *id); int dir_get_name(librados::IoCtx *ioctx, const std::string &oid, const std::string &id, std::string *name); int dir_list(librados::IoCtx *ioctx, const std::string &oid, const std::string &start, uint64_t max_return, map *images); int dir_add_image(librados::IoCtx *ioctx, const std::string &oid, const std::string &name, const std::string &id); int dir_remove_image(librados::IoCtx *ioctx, const std::string &oid, const std::string &name, const std::string &id); // atomic remove and add int dir_rename_image(librados::IoCtx *ioctx, const std::string &oid, const std::string &src, const std::string &dest, const std::string &id); // class operations on the old format, kept for // backwards compatability int old_snapshot_add(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, const std::string &snap_name); int old_snapshot_remove(librados::IoCtx *ioctx, const std::string &oid, const std::string &snap_name); int old_snapshot_list(librados::IoCtx *ioctx, const std::string &oid, std::vector *names, std::vector *sizes, ::SnapContext *snapc); } // namespace cls_client } // namespace librbd #endif // CEPH_LIBRBD_CLS_RBD_CLIENT_H ceph-0.80.11/src/cls/rbd/cls_rbd_client.cc0000664000175100017510000004052512623076744022277 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "cls/lock/cls_lock_client.h" #include "include/buffer.h" #include "include/encoding.h" #include "include/rbd_types.h" #include "cls_rbd_client.h" #include namespace librbd { namespace cls_client { int get_immutable_metadata(librados::IoCtx *ioctx, const std::string &oid, std::string *object_prefix, uint8_t *order) { assert(object_prefix); assert(order); librados::ObjectReadOperation op; bufferlist bl, empty; snapid_t snap = CEPH_NOSNAP; ::encode(snap, bl); op.exec("rbd", "get_size", bl); op.exec("rbd", "get_object_prefix", empty); bufferlist outbl; int r = ioctx->operate(oid, &op, &outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); uint64_t size; // get_size ::decode(*order, iter); ::decode(size, iter); // get_object_prefix ::decode(*object_prefix, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int get_mutable_metadata(librados::IoCtx *ioctx, const std::string &oid, uint64_t *size, uint64_t *features, uint64_t *incompatible_features, map *lockers, bool *exclusive_lock, string *lock_tag, ::SnapContext *snapc, parent_info *parent) { assert(size); assert(features); assert(incompatible_features); assert(lockers); assert(exclusive_lock); assert(snapc); assert(parent); librados::ObjectReadOperation op; bufferlist sizebl, featuresbl, parentbl, empty; snapid_t snap = CEPH_NOSNAP; ::encode(snap, sizebl); ::encode(snap, featuresbl); ::encode(snap, parentbl); op.exec("rbd", "get_size", sizebl); op.exec("rbd", "get_features", featuresbl); op.exec("rbd", "get_snapcontext", empty); op.exec("rbd", "get_parent", parentbl); rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME); bufferlist outbl; int r = ioctx->operate(oid, &op, &outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); uint8_t order; // get_size ::decode(order, iter); ::decode(*size, iter); // get_features ::decode(*features, iter); ::decode(*incompatible_features, iter); // get_snapcontext ::decode(*snapc, iter); // get_parent ::decode(parent->spec.pool_id, iter); ::decode(parent->spec.image_id, iter); ::decode(parent->spec.snap_id, iter); ::decode(parent->overlap, iter); // get_lock_info ClsLockType lock_type = LOCK_NONE; r = rados::cls::lock::get_lock_info_finish(&iter, lockers, &lock_type, lock_tag); // see comment in ictx_refresh(). Ugly conflation of // EOPNOTSUPP and EIO. if (r < 0 && ((r != -EOPNOTSUPP) && (r != -EIO))) return r; *exclusive_lock = (lock_type == LOCK_EXCLUSIVE); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int create_image(librados::IoCtx *ioctx, const std::string &oid, uint64_t size, uint8_t order, uint64_t features, const std::string &object_prefix) { bufferlist bl, bl2; ::encode(size, bl); ::encode(order, bl); ::encode(features, bl); ::encode(object_prefix, (bl)); return ioctx->exec(oid, "rbd", "create", bl, bl2); } int get_features(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint64_t *features) { bufferlist inbl, outbl; ::encode(snap_id, inbl); int r = ioctx->exec(oid, "rbd", "get_features", inbl, outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); ::decode(*features, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int get_object_prefix(librados::IoCtx *ioctx, const std::string &oid, std::string *object_prefix) { bufferlist inbl, outbl; int r = ioctx->exec(oid, "rbd", "get_object_prefix", inbl, outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); ::decode(*object_prefix, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int get_size(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint64_t *size, uint8_t *order) { bufferlist inbl, outbl; ::encode(snap_id, inbl); int r = ioctx->exec(oid, "rbd", "get_size", inbl, outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); ::decode(*order, iter); ::decode(*size, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int set_size(librados::IoCtx *ioctx, const std::string &oid, uint64_t size) { bufferlist bl, bl2; ::encode(size, bl); return ioctx->exec(oid, "rbd", "set_size", bl, bl2); } int get_parent(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, parent_spec *pspec, uint64_t *parent_overlap) { bufferlist inbl, outbl; ::encode(snap_id, inbl); int r = ioctx->exec(oid, "rbd", "get_parent", inbl, outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); ::decode(pspec->pool_id, iter); ::decode(pspec->image_id, iter); ::decode(pspec->snap_id, iter); ::decode(*parent_overlap, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int set_parent(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, uint64_t parent_overlap) { bufferlist inbl, outbl; ::encode(pspec.pool_id, inbl); ::encode(pspec.image_id, inbl); ::encode(pspec.snap_id, inbl); ::encode(parent_overlap, inbl); return ioctx->exec(oid, "rbd", "set_parent", inbl, outbl); } int remove_parent(librados::IoCtx *ioctx, const std::string &oid) { bufferlist inbl, outbl; return ioctx->exec(oid, "rbd", "remove_parent", inbl, outbl); } int add_child(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, const std::string &c_imageid) { bufferlist in, out; ::encode(pspec.pool_id, in); ::encode(pspec.image_id, in); ::encode(pspec.snap_id, in); ::encode(c_imageid, in); return ioctx->exec(oid, "rbd", "add_child", in, out); } int remove_child(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, const std::string &c_imageid) { bufferlist in, out; ::encode(pspec.pool_id, in); ::encode(pspec.image_id, in); ::encode(pspec.snap_id, in); ::encode(c_imageid, in); return ioctx->exec(oid, "rbd", "remove_child", in, out); } int get_children(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, set& children) { bufferlist in, out; ::encode(pspec.pool_id, in); ::encode(pspec.image_id, in); ::encode(pspec.snap_id, in); int r = ioctx->exec(oid, "rbd", "get_children", in, out); if (r < 0) return r; bufferlist::iterator it = out.begin(); try { ::decode(children, it); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int snapshot_add(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, const std::string &snap_name) { bufferlist bl, bl2; ::encode(snap_name, bl); ::encode(snap_id, bl); return ioctx->exec(oid, "rbd", "snapshot_add", bl, bl2); } int snapshot_remove(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id) { bufferlist bl, bl2; ::encode(snap_id, bl); return ioctx->exec(oid, "rbd", "snapshot_remove", bl, bl2); } int get_snapcontext(librados::IoCtx *ioctx, const std::string &oid, ::SnapContext *snapc) { bufferlist inbl, outbl; int r = ioctx->exec(oid, "rbd", "get_snapcontext", inbl, outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); ::decode(*snapc, iter); } catch (const buffer::error &err) { return -EBADMSG; } if (!snapc->is_valid()) return -EBADMSG; return 0; } int snapshot_list(librados::IoCtx *ioctx, const std::string &oid, const std::vector &ids, std::vector *names, std::vector *sizes, std::vector *features, std::vector *parents, std::vector *protection_statuses) { names->clear(); names->resize(ids.size()); sizes->clear(); sizes->resize(ids.size()); features->clear(); features->resize(ids.size()); parents->clear(); parents->resize(ids.size()); protection_statuses->clear(); protection_statuses->resize(ids.size()); librados::ObjectReadOperation op; for (vector::const_iterator it = ids.begin(); it != ids.end(); ++it) { snapid_t snap_id = it->val; bufferlist bl1, bl2, bl3, bl4, bl5; ::encode(snap_id, bl1); op.exec("rbd", "get_snapshot_name", bl1); ::encode(snap_id, bl2); op.exec("rbd", "get_size", bl2); ::encode(snap_id, bl3); op.exec("rbd", "get_features", bl3); ::encode(snap_id, bl4); op.exec("rbd", "get_parent", bl4); ::encode(snap_id, bl5); op.exec("rbd", "get_protection_status", bl5); } bufferlist outbl; int r = ioctx->operate(oid, &op, &outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); for (size_t i = 0; i < ids.size(); ++i) { uint8_t order; uint64_t incompat_features; // get_snapshot_name ::decode((*names)[i], iter); // get_size ::decode(order, iter); ::decode((*sizes)[i], iter); // get_features ::decode((*features)[i], iter); ::decode(incompat_features, iter); // get_parent ::decode((*parents)[i].spec.pool_id, iter); ::decode((*parents)[i].spec.image_id, iter); ::decode((*parents)[i].spec.snap_id, iter); ::decode((*parents)[i].overlap, iter); // get_protection_status ::decode((*protection_statuses)[i], iter); } } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int old_snapshot_add(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, const std::string &snap_name) { bufferlist bl, bl2; ::encode(snap_name, bl); ::encode(snap_id, bl); return ioctx->exec(oid, "rbd", "snap_add", bl, bl2); } int old_snapshot_remove(librados::IoCtx *ioctx, const std::string &oid, const std::string &snap_name) { bufferlist bl, bl2; ::encode(snap_name, bl); return ioctx->exec(oid, "rbd", "snap_remove", bl, bl2); } int old_snapshot_list(librados::IoCtx *ioctx, const std::string &oid, std::vector *names, std::vector *sizes, ::SnapContext *snapc) { bufferlist bl, outbl; int r = ioctx->exec(oid, "rbd", "snap_list", bl, outbl); if (r < 0) return r; bufferlist::iterator iter = outbl.begin(); uint32_t num_snaps; try { ::decode(snapc->seq, iter); ::decode(num_snaps, iter); names->resize(num_snaps); sizes->resize(num_snaps); snapc->snaps.resize(num_snaps); for (uint32_t i = 0; i < num_snaps; ++i) { ::decode(snapc->snaps[i], iter); ::decode((*sizes)[i], iter); ::decode((*names)[i], iter); } } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int copyup(librados::IoCtx *ioctx, const std::string &oid, bufferlist data) { bufferlist out; return ioctx->exec(oid, "rbd", "copyup", data, out); } int get_protection_status(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint8_t *protection_status) { bufferlist in, out; ::encode(snap_id.val, in); int r = ioctx->exec(oid, "rbd", "get_protection_status", in, out); if (r < 0) return r; try { bufferlist::iterator iter = out.begin(); ::decode(*protection_status, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int set_protection_status(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint8_t protection_status) { bufferlist in, out; ::encode(snap_id, in); ::encode(protection_status, in); return ioctx->exec(oid, "rbd", "set_protection_status", in, out); } int get_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, uint64_t *stripe_unit, uint64_t *stripe_count) { assert(stripe_unit); assert(stripe_count); librados::ObjectReadOperation op; bufferlist empty; op.exec("rbd", "get_stripe_unit_count", empty); bufferlist outbl; int r = ioctx->operate(oid, &op, &outbl); if (r < 0) return r; try { bufferlist::iterator iter = outbl.begin(); ::decode(*stripe_unit, iter); ::decode(*stripe_count, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int set_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, uint64_t stripe_unit, uint64_t stripe_count) { bufferlist in, out; ::encode(stripe_unit, in); ::encode(stripe_count, in); return ioctx->exec(oid, "rbd", "set_stripe_unit_count", in, out); } /************************ rbd_id object methods ************************/ int get_id(librados::IoCtx *ioctx, const std::string &oid, std::string *id) { bufferlist in, out; int r = ioctx->exec(oid, "rbd", "get_id", in, out); if (r < 0) return r; bufferlist::iterator iter = out.begin(); try { ::decode(*id, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int set_id(librados::IoCtx *ioctx, const std::string &oid, std::string id) { bufferlist in, out; ::encode(id, in); return ioctx->exec(oid, "rbd", "set_id", in, out); } /******************** rbd_directory object methods ********************/ int dir_get_id(librados::IoCtx *ioctx, const std::string &oid, const std::string &name, std::string *id) { bufferlist in, out; ::encode(name, in); int r = ioctx->exec(oid, "rbd", "dir_get_id", in, out); if (r < 0) return r; bufferlist::iterator iter = out.begin(); try { ::decode(*id, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int dir_get_name(librados::IoCtx *ioctx, const std::string &oid, const std::string &id, std::string *name) { bufferlist in, out; ::encode(id, in); int r = ioctx->exec(oid, "rbd", "dir_get_name", in, out); if (r < 0) return r; bufferlist::iterator iter = out.begin(); try { ::decode(*name, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int dir_list(librados::IoCtx *ioctx, const std::string &oid, const std::string &start, uint64_t max_return, map *images) { bufferlist in, out; ::encode(start, in); ::encode(max_return, in); int r = ioctx->exec(oid, "rbd", "dir_list", in, out); if (r < 0) return r; bufferlist::iterator iter = out.begin(); try { ::decode(*images, iter); } catch (const buffer::error &err) { return -EBADMSG; } return 0; } int dir_add_image(librados::IoCtx *ioctx, const std::string &oid, const std::string &name, const std::string &id) { bufferlist in, out; ::encode(name, in); ::encode(id, in); return ioctx->exec(oid, "rbd", "dir_add_image", in, out); } int dir_remove_image(librados::IoCtx *ioctx, const std::string &oid, const std::string &name, const std::string &id) { bufferlist in, out; ::encode(name, in); ::encode(id, in); return ioctx->exec(oid, "rbd", "dir_remove_image", in, out); } int dir_rename_image(librados::IoCtx *ioctx, const std::string &oid, const std::string &src, const std::string &dest, const std::string &id) { bufferlist in, out; ::encode(src, in); ::encode(dest, in); ::encode(id, in); return ioctx->exec(oid, "rbd", "dir_rename_image", in, out); } } // namespace cls_client } // namespace librbd ceph-0.80.11/src/cls/rbd/cls_rbd.cc0000664000175100017510000015434312623076744020745 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /** \file * * This is an OSD class that implements methods for * use with rbd. * * Most of these deal with the rbd header object. Methods prefixed * with old_ deal with the original rbd design, in which clients read * and interpreted the header object directly. * * The new format is meant to be opaque to clients - all their * interactions with non-data objects should go through this * class. The OSD class interface leaves the class to implement its * own argument and payload serialization/deserialization, so for ease * of implementation we use the existing ceph encoding/decoding * methods. Something like json might be preferable, but the rbd * kernel module has to be able understand format as well. The * datatypes exposed to the clients are strings, unsigned integers, * and vectors of those types. The on-wire format can be found in * src/include/encoding.h. * * The methods for interacting with the new format document their * parameters as the client sees them - it would be silly to mention * in each one that they take an input and an output bufferlist. */ #include "include/int_types.h" #include "include/types.h" #include #include #include #include #include #include #include #include #include "common/errno.h" #include "objclass/objclass.h" #include "include/rbd_types.h" #include "cls/rbd/cls_rbd.h" /* * Object keys: * * * * stripe_unit: size in bytes of the stripe unit. if not present, * the stripe unit is assumed to match the object size (1 << order). * * stripe_count: number of objects to stripe over before looping back. * if not present or 1, striping is disabled. this is the default. * */ CLS_VER(2,0) CLS_NAME(rbd) cls_handle_t h_class; cls_method_handle_t h_create; cls_method_handle_t h_get_features; cls_method_handle_t h_get_size; cls_method_handle_t h_set_size; cls_method_handle_t h_get_parent; cls_method_handle_t h_set_parent; cls_method_handle_t h_get_protection_status; cls_method_handle_t h_set_protection_status; cls_method_handle_t h_get_stripe_unit_count; cls_method_handle_t h_set_stripe_unit_count; cls_method_handle_t h_remove_parent; cls_method_handle_t h_add_child; cls_method_handle_t h_remove_child; cls_method_handle_t h_get_children; cls_method_handle_t h_get_snapcontext; cls_method_handle_t h_get_object_prefix; cls_method_handle_t h_get_snapshot_name; cls_method_handle_t h_snapshot_add; cls_method_handle_t h_snapshot_remove; cls_method_handle_t h_get_all_features; cls_method_handle_t h_copyup; cls_method_handle_t h_get_id; cls_method_handle_t h_set_id; cls_method_handle_t h_dir_get_id; cls_method_handle_t h_dir_get_name; cls_method_handle_t h_dir_list; cls_method_handle_t h_dir_add_image; cls_method_handle_t h_dir_remove_image; cls_method_handle_t h_dir_rename_image; cls_method_handle_t h_old_snapshots_list; cls_method_handle_t h_old_snapshot_add; cls_method_handle_t h_old_snapshot_remove; #define RBD_MAX_KEYS_READ 64 #define RBD_SNAP_KEY_PREFIX "snapshot_" #define RBD_DIR_ID_KEY_PREFIX "id_" #define RBD_DIR_NAME_KEY_PREFIX "name_" static int snap_read_header(cls_method_context_t hctx, bufferlist& bl) { unsigned snap_count = 0; uint64_t snap_names_len = 0; struct rbd_obj_header_ondisk *header; CLS_LOG(20, "snapshots_list"); while (1) { int len = sizeof(*header) + snap_count * sizeof(struct rbd_obj_snap_ondisk) + snap_names_len; int rc = cls_cxx_read(hctx, 0, len, &bl); if (rc < 0) return rc; if (bl.length() < sizeof(*header)) return -EINVAL; header = (struct rbd_obj_header_ondisk *)bl.c_str(); assert(header); if ((snap_count != header->snap_count) || (snap_names_len != header->snap_names_len)) { snap_count = header->snap_count; snap_names_len = header->snap_names_len; bl.clear(); continue; } break; } return 0; } static void key_from_snap_id(snapid_t snap_id, string *out) { ostringstream oss; oss << RBD_SNAP_KEY_PREFIX << std::setw(16) << std::setfill('0') << std::hex << snap_id; *out = oss.str(); } static snapid_t snap_id_from_key(const string &key) { istringstream iss(key); uint64_t id; iss.ignore(strlen(RBD_SNAP_KEY_PREFIX)) >> std::hex >> id; return id; } template static int read_key(cls_method_context_t hctx, const string &key, T *out) { bufferlist bl; int r = cls_cxx_map_get_val(hctx, key, &bl); if (r < 0) { if (r != -ENOENT) { CLS_ERR("error reading omap key %s: %d", key.c_str(), r); } return r; } try { bufferlist::iterator it = bl.begin(); ::decode(*out, it); } catch (const buffer::error &err) { CLS_ERR("error decoding %s", key.c_str()); return -EIO; } return 0; } static bool is_valid_id(const string &id) { if (!id.size()) return false; for (size_t i = 0; i < id.size(); ++i) { if (!isalnum(id[i])) { return false; } } return true; } /** * Initialize the header with basic metadata. * Extra features may initialize more fields in the future. * Everything is stored as key/value pairs as omaps in the header object. * * If features the OSD does not understand are requested, -ENOSYS is * returned. * * Input: * @param size number of bytes in the image (uint64_t) * @param order bits to shift to determine the size of data objects (uint8_t) * @param features what optional things this image will use (uint64_t) * @param object_prefix a prefix for all the data objects * * Output: * @return 0 on success, negative error code on failure */ int create(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { string object_prefix; uint64_t features, size; uint8_t order; try { bufferlist::iterator iter = in->begin(); ::decode(size, iter); ::decode(order, iter); ::decode(features, iter); ::decode(object_prefix, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "create object_prefix=%s size=%llu order=%u features=%llu", object_prefix.c_str(), (unsigned long long)size, order, (unsigned long long)features); if (features & ~RBD_FEATURES_ALL) { return -ENOSYS; } if (!object_prefix.size()) { return -EINVAL; } bufferlist stored_prefixbl; int r = cls_cxx_map_get_val(hctx, "object_prefix", &stored_prefixbl); if (r != -ENOENT) { CLS_ERR("reading object_prefix returned %d", r); return -EEXIST; } bufferlist sizebl; ::encode(size, sizebl); r = cls_cxx_map_set_val(hctx, "size", &sizebl); if (r < 0) return r; bufferlist orderbl; ::encode(order, orderbl); r = cls_cxx_map_set_val(hctx, "order", &orderbl); if (r < 0) return r; bufferlist featuresbl; ::encode(features, featuresbl); r = cls_cxx_map_set_val(hctx, "features", &featuresbl); if (r < 0) return r; bufferlist object_prefixbl; ::encode(object_prefix, object_prefixbl); r = cls_cxx_map_set_val(hctx, "object_prefix", &object_prefixbl); if (r < 0) return r; bufferlist snap_seqbl; uint64_t snap_seq = 0; ::encode(snap_seq, snap_seqbl); r = cls_cxx_map_set_val(hctx, "snap_seq", &snap_seqbl); if (r < 0) return r; return 0; } /** * Input: * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) * * Output: * @param features list of enabled features for the given snapshot (uint64_t) * @returns 0 on success, negative error code on failure */ int get_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t features, snap_id; bufferlist::iterator iter = in->begin(); try { ::decode(snap_id, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "get_features snap_id=%llu", (unsigned long long)snap_id); if (snap_id == CEPH_NOSNAP) { int r = read_key(hctx, "features", &features); if (r < 0) { CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str()); return r; } } else { cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id, &snapshot_key); int r = read_key(hctx, snapshot_key, &snap); if (r < 0) return r; features = snap.features; } uint64_t incompatible = features & RBD_FEATURES_INCOMPATIBLE; ::encode(features, *out); ::encode(incompatible, *out); return 0; } /** * check that given feature(s) are set * * @param hctx context * @param need features needed * @return 0 if features are set, negative error (like ENOEXEC) otherwise */ int require_feature(cls_method_context_t hctx, uint64_t need) { uint64_t features; int r = read_key(hctx, "features", &features); if (r == -ENOENT) // this implies it's an old-style image with no features return -ENOEXEC; if (r < 0) return r; if ((features & need) != need) { CLS_LOG(10, "require_feature missing feature %llx, have %llx", (unsigned long long)need, (unsigned long long)features); return -ENOEXEC; } return 0; } /** * Input: * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) * * Output: * @param order bits to shift to get the size of data objects (uint8_t) * @param size size of the image in bytes for the given snapshot (uint64_t) * @returns 0 on success, negative error code on failure */ int get_size(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t snap_id, size; uint8_t order; bufferlist::iterator iter = in->begin(); try { ::decode(snap_id, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "get_size snap_id=%llu", (unsigned long long)snap_id); int r = read_key(hctx, "order", &order); if (r < 0) { CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r).c_str()); return r; } if (snap_id == CEPH_NOSNAP) { r = read_key(hctx, "size", &size); if (r < 0) { CLS_ERR("failed to read the image's size off of disk: %s", cpp_strerror(r).c_str()); return r; } } else { cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id, &snapshot_key); int r = read_key(hctx, snapshot_key, &snap); if (r < 0) return r; size = snap.image_size; } ::encode(order, *out); ::encode(size, *out); return 0; } /** * Input: * @param size new capacity of the image in bytes (uint64_t) * * Output: * @returns 0 on success, negative error code on failure */ int set_size(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t size; bufferlist::iterator iter = in->begin(); try { ::decode(size, iter); } catch (const buffer::error &err) { return -EINVAL; } // check that size exists to make sure this is a header object // that was created correctly uint64_t orig_size; int r = read_key(hctx, "size", &orig_size); if (r < 0) { CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r).c_str()); return r; } CLS_LOG(20, "set_size size=%llu orig_size=%llu", (unsigned long long)size, (unsigned long long)orig_size); bufferlist sizebl; ::encode(size, sizebl); r = cls_cxx_map_set_val(hctx, "size", &sizebl); if (r < 0) { CLS_ERR("error writing snapshot metadata: %d", r); return r; } // if we are shrinking, and have a parent, shrink our overlap with // the parent, too. if (size < orig_size) { cls_rbd_parent parent; r = read_key(hctx, "parent", &parent); if (r == -ENOENT) r = 0; if (r < 0) return r; if (parent.exists() && parent.overlap > size) { bufferlist parentbl; parent.overlap = size; ::encode(parent, parentbl); r = cls_cxx_map_set_val(hctx, "parent", &parentbl); if (r < 0) { CLS_ERR("error writing parent: %d", r); return r; } } } return 0; } /** * verify that the header object exists * * @return 0 if the object exists, -ENOENT if it does not, or other error */ int check_exists(cls_method_context_t hctx) { uint64_t size; time_t mtime; return cls_cxx_stat(hctx, &size, &mtime); } /** * get the current protection status of the specified snapshot * * Input: * @param snap_id (uint64_t) which snapshot to get the status of * * Output: * @param status (uint8_t) one of: * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING} * * @returns 0 on success, negative error code on failure * @returns -EINVAL if snapid is CEPH_NOSNAP */ int get_protection_status(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { snapid_t snap_id; bufferlist::iterator iter = in->begin(); try { ::decode(snap_id, iter); } catch (const buffer::error &err) { CLS_LOG(20, "get_protection_status: invalid decode"); return -EINVAL; } int r = check_exists(hctx); if (r < 0) return r; CLS_LOG(20, "get_protection_status snap_id=%llu", (unsigned long long)snap_id.val); if (snap_id == CEPH_NOSNAP) return -EINVAL; cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id.val, &snapshot_key); r = read_key(hctx, snapshot_key, &snap); if (r < 0) { CLS_ERR("could not read key for snapshot id %"PRIu64, snap_id.val); return r; } if (snap.protection_status >= RBD_PROTECTION_STATUS_LAST) { CLS_ERR("invalid protection status for snap id %llu: %u", (unsigned long long)snap_id.val, snap.protection_status); return -EIO; } ::encode(snap.protection_status, *out); return 0; } /** * set the proctection status of a snapshot * * Input: * @param snapid (uint64_t) which snapshot to set the status of * @param status (uint8_t) one of: * RBD_PROTECTION_STATUS_{PROTECTED, UNPROTECTED, UNPROTECTING} * * @returns 0 on success, negative error code on failure * @returns -EINVAL if snapid is CEPH_NOSNAP */ int set_protection_status(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { snapid_t snap_id; uint8_t status; bufferlist::iterator iter = in->begin(); try { ::decode(snap_id, iter); ::decode(status, iter); } catch (const buffer::error &err) { CLS_LOG(20, "set_protection_status: invalid decode"); return -EINVAL; } int r = check_exists(hctx); if (r < 0) return r; r = require_feature(hctx, RBD_FEATURE_LAYERING); if (r < 0) { CLS_LOG(20, "image does not support layering"); return r; } CLS_LOG(20, "set_protection_status snapid=%llu status=%u", (unsigned long long)snap_id.val, status); if (snap_id == CEPH_NOSNAP) return -EINVAL; if (status >= RBD_PROTECTION_STATUS_LAST) { CLS_LOG(10, "invalid protection status for snap id %llu: %u", (unsigned long long)snap_id.val, status); return -EINVAL; } cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id.val, &snapshot_key); r = read_key(hctx, snapshot_key, &snap); if (r < 0) { CLS_ERR("could not read key for snapshot id %"PRIu64, snap_id.val); return r; } snap.protection_status = status; bufferlist snapshot_bl; ::encode(snap, snapshot_bl); r = cls_cxx_map_set_val(hctx, snapshot_key, &snapshot_bl); if (r < 0) { CLS_ERR("error writing snapshot metadata: %d", r); return r; } return 0; } /** * get striping parameters * * Input: * none * * Output: * @param stripe unit (bytes) * @param stripe count (num objects) * * @returns 0 on success */ int get_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r = check_exists(hctx); if (r < 0) return r; CLS_LOG(20, "get_stripe_unit_count"); r = require_feature(hctx, RBD_FEATURE_STRIPINGV2); if (r < 0) return r; uint64_t stripe_unit = 0, stripe_count = 0; r = read_key(hctx, "stripe_unit", &stripe_unit); if (r == -ENOENT) { // default to object size uint8_t order; r = read_key(hctx, "order", &order); if (r < 0) { CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r).c_str()); return -EIO; } stripe_unit = 1ull << order; } if (r < 0) return r; r = read_key(hctx, "stripe_count", &stripe_count); if (r == -ENOENT) { // default to 1 stripe_count = 1; r = 0; } if (r < 0) return r; ::encode(stripe_unit, *out); ::encode(stripe_count, *out); return 0; } /** * set striping parameters * * Input: * @param stripe unit (bytes) * @param stripe count (num objects) * * @returns 0 on success */ int set_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t stripe_unit, stripe_count; bufferlist::iterator iter = in->begin(); try { ::decode(stripe_unit, iter); ::decode(stripe_count, iter); } catch (const buffer::error &err) { CLS_LOG(20, "set_stripe_unit_count: invalid decode"); return -EINVAL; } if (!stripe_count || !stripe_unit) return -EINVAL; int r = check_exists(hctx); if (r < 0) return r; CLS_LOG(20, "set_stripe_unit_count"); r = require_feature(hctx, RBD_FEATURE_STRIPINGV2); if (r < 0) return r; uint8_t order; r = read_key(hctx, "order", &order); if (r < 0) { CLS_ERR("failed to read the order off of disk: %s", cpp_strerror(r).c_str()); return r; } if ((1ull << order) % stripe_unit || stripe_unit > (1ull << order)) { CLS_ERR("stripe unit %llu is not a factor of the object size %llu", (unsigned long long)stripe_unit, 1ull << order); return -EINVAL; } bufferlist bl, bl2; ::encode(stripe_unit, bl); r = cls_cxx_map_set_val(hctx, "stripe_unit", &bl); if (r < 0) { CLS_ERR("error writing stripe_unit metadata: %d", r); return r; } ::encode(stripe_count, bl2); r = cls_cxx_map_set_val(hctx, "stripe_count", &bl2); if (r < 0) { CLS_ERR("error writing stripe_count metadata: %d", r); return r; } return 0; } /** * get the current parent, if any * * Input: * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) * * Output: * @param pool parent pool id (-1 if parent does not exist) * @param image parent image id * @param snapid parent snapid * @param size portion of parent mapped under the child * * @returns 0 on success or parent does not exist, negative error code on failure */ int get_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t snap_id; bufferlist::iterator iter = in->begin(); try { ::decode(snap_id, iter); } catch (const buffer::error &err) { return -EINVAL; } int r = check_exists(hctx); if (r < 0) return r; CLS_LOG(20, "get_parent snap_id=%llu", (unsigned long long)snap_id); cls_rbd_parent parent; r = require_feature(hctx, RBD_FEATURE_LAYERING); if (r == 0) { if (snap_id == CEPH_NOSNAP) { r = read_key(hctx, "parent", &parent); if (r < 0 && r != -ENOENT) return r; } else { cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id, &snapshot_key); r = read_key(hctx, snapshot_key, &snap); if (r < 0 && r != -ENOENT) return r; parent = snap.parent; } } ::encode(parent.pool, *out); ::encode(parent.id, *out); ::encode(parent.snapid, *out); ::encode(parent.overlap, *out); return 0; } /** * set the image parent * * Input: * @param pool parent pool * @param id parent image id * @param snapid parent snapid * @param size parent size * * @returns 0 on success, or negative error code */ int set_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int64_t pool; string id; snapid_t snapid; uint64_t size; bufferlist::iterator iter = in->begin(); try { ::decode(pool, iter); ::decode(id, iter); ::decode(snapid, iter); ::decode(size, iter); } catch (const buffer::error &err) { CLS_LOG(20, "cls_rbd::set_parent: invalid decode"); return -EINVAL; } int r = check_exists(hctx); if (r < 0) { CLS_LOG(20, "cls_rbd::set_parent: child already exists"); return r; } r = require_feature(hctx, RBD_FEATURE_LAYERING); if (r < 0) { CLS_LOG(20, "cls_rbd::set_parent: child does not support layering"); return r; } CLS_LOG(20, "set_parent pool=%llu id=%s snapid=%llu size=%llu", (unsigned long long)pool, id.c_str(), (unsigned long long)snapid.val, (unsigned long long)size); if (pool < 0 || id.length() == 0 || snapid == CEPH_NOSNAP || size == 0) { return -EINVAL; } // make sure there isn't already a parent cls_rbd_parent parent; r = read_key(hctx, "parent", &parent); if (r == 0) { CLS_LOG(20, "set_parent existing parent pool=%llu id=%s snapid=%llu" "overlap=%llu", (unsigned long long)parent.pool, parent.id.c_str(), (unsigned long long)parent.snapid.val, (unsigned long long)parent.overlap); return -EEXIST; } // our overlap is the min of our size and the parent's size. uint64_t our_size; r = read_key(hctx, "size", &our_size); if (r < 0) return r; bufferlist parentbl; parent.pool = pool; parent.id = id; parent.snapid = snapid; parent.overlap = MIN(our_size, size); ::encode(parent, parentbl); r = cls_cxx_map_set_val(hctx, "parent", &parentbl); if (r < 0) { CLS_ERR("error writing parent: %d", r); return r; } return 0; } /** * remove the parent pointer * * This can only happen on the head, not on a snapshot. No arguments. * * @returns 0 on success, negative error code on failure. */ int remove_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r = check_exists(hctx); if (r < 0) return r; r = require_feature(hctx, RBD_FEATURE_LAYERING); if (r < 0) return r; cls_rbd_parent parent; r = read_key(hctx, "parent", &parent); if (r < 0) return r; r = cls_cxx_map_remove_key(hctx, "parent"); if (r < 0) { CLS_ERR("error removing parent: %d", r); return r; } return 0; } /** * methods for dealing with rbd_children object */ static int decode_parent_common(bufferlist::iterator& it, uint64_t *pool_id, string *image_id, snapid_t *snap_id) { try { ::decode(*pool_id, it); ::decode(*image_id, it); ::decode(*snap_id, it); } catch (const buffer::error &err) { CLS_ERR("error decoding parent spec"); return -EINVAL; } return 0; } static int decode_parent(bufferlist *in, uint64_t *pool_id, string *image_id, snapid_t *snap_id) { bufferlist::iterator it = in->begin(); return decode_parent_common(it, pool_id, image_id, snap_id); } static int decode_parent_and_child(bufferlist *in, uint64_t *pool_id, string *image_id, snapid_t *snap_id, string *c_image_id) { bufferlist::iterator it = in->begin(); int r = decode_parent_common(it, pool_id, image_id, snap_id); if (r < 0) return r; try { ::decode(*c_image_id, it); } catch (const buffer::error &err) { CLS_ERR("error decoding child image id"); return -EINVAL; } return 0; } static string parent_key(uint64_t pool_id, string image_id, snapid_t snap_id) { bufferlist key_bl; ::encode(pool_id, key_bl); ::encode(image_id, key_bl); ::encode(snap_id, key_bl); return string(key_bl.c_str(), key_bl.length()); } /** * add child to rbd_children directory object * * rbd_children is a map of (p_pool_id, p_image_id, p_snap_id) to * [c_image_id, [c_image_id ... ]] * * Input: * @param p_pool_id parent pool id * @param p_image_id parent image oid * @param p_snap_id parent snapshot id * @param c_image_id new child image oid to add * * @returns 0 on success, negative error on failure */ int add_child(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r; uint64_t p_pool_id; snapid_t p_snap_id; string p_image_id, c_image_id; // Use set for ease of erase() for remove_child() std::set children; r = decode_parent_and_child(in, &p_pool_id, &p_image_id, &p_snap_id, &c_image_id); if (r < 0) return r; CLS_LOG(20, "add_child %s to (%"PRIu64", %s, %"PRIu64")", c_image_id.c_str(), p_pool_id, p_image_id.c_str(), p_snap_id.val); string key = parent_key(p_pool_id, p_image_id, p_snap_id); // get current child list for parent, if any r = read_key(hctx, key, &children); if ((r < 0) && (r != -ENOENT)) { CLS_LOG(20, "add_child: omap read failed: %d", r); return r; } if (children.find(c_image_id) != children.end()) { CLS_LOG(20, "add_child: child already exists: %s", c_image_id.c_str()); return -EEXIST; } // add new child children.insert(c_image_id); // write back bufferlist childbl; ::encode(children, childbl); r = cls_cxx_map_set_val(hctx, key, &childbl); if (r < 0) CLS_LOG(20, "add_child: omap write failed: %d", r); return r; } /** * remove child from rbd_children directory object * * Input: * @param p_pool_id parent pool id * @param p_image_id parent image oid * @param p_snap_id parent snapshot id * @param c_image_id new child image oid to add * * @returns 0 on success, negative error on failure */ int remove_child(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r; uint64_t p_pool_id; snapid_t p_snap_id; string p_image_id, c_image_id; std::set children; r = decode_parent_and_child(in, &p_pool_id, &p_image_id, &p_snap_id, &c_image_id); if (r < 0) return r; CLS_LOG(20, "remove_child %s from (%"PRIu64", %s, %"PRIu64")", c_image_id.c_str(), p_pool_id, p_image_id.c_str(), p_snap_id.val); string key = parent_key(p_pool_id, p_image_id, p_snap_id); // get current child list for parent. Unlike add_child(), an empty list // is an error (how can we remove something that doesn't exist?) r = read_key(hctx, key, &children); if (r < 0) { CLS_LOG(20, "remove_child: read omap failed: %d", r); return r; } if (children.find(c_image_id) == children.end()) { CLS_LOG(20, "remove_child: child not found: %s", c_image_id.c_str()); return -ENOENT; } // find and remove child children.erase(c_image_id); // now empty? remove key altogether if (children.empty()) { r = cls_cxx_map_remove_key(hctx, key); if (r < 0) CLS_LOG(20, "remove_child: remove key failed: %d", r); } else { // write back shortened children list bufferlist childbl; ::encode(children, childbl); r = cls_cxx_map_set_val(hctx, key, &childbl); if (r < 0) CLS_LOG(20, "remove_child: write omap failed: %d ", r); } return r; } /** * Input: * @param p_pool_id parent pool id * @param p_image_id parent image oid * @param p_snap_id parent snapshot id * @param c_image_id new child image oid to add * * Output: * @param children set of children * * @returns 0 on success, negative error on failure */ int get_children(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r; uint64_t p_pool_id; snapid_t p_snap_id; string p_image_id; std::set children; r = decode_parent(in, &p_pool_id, &p_image_id, &p_snap_id); if (r < 0) return r; CLS_LOG(20, "get_children of (%"PRIu64", %s, %"PRIu64")", p_pool_id, p_image_id.c_str(), p_snap_id.val); string key = parent_key(p_pool_id, p_image_id, p_snap_id); r = read_key(hctx, key, &children); if (r < 0) { if (r != -ENOENT) CLS_LOG(20, "get_children: read omap failed: %d", r); return r; } ::encode(children, *out); return 0; } /** * Get the information needed to create a rados snap context for doing * I/O to the data objects. This must include all snapshots. * * Output: * @param snap_seq the highest snapshot id ever associated with the image (uint64_t) * @param snap_ids existing snapshot ids in descending order (vector) * @returns 0 on success, negative error code on failure */ int get_snapcontext(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "get_snapcontext"); int r; int max_read = RBD_MAX_KEYS_READ; vector snap_ids; string last_read = RBD_SNAP_KEY_PREFIX; do { set keys; r = cls_cxx_map_get_keys(hctx, last_read, max_read, &keys); if (r < 0) return r; for (set::const_iterator it = keys.begin(); it != keys.end(); ++it) { if ((*it).find(RBD_SNAP_KEY_PREFIX) != 0) break; snapid_t snap_id = snap_id_from_key(*it); snap_ids.push_back(snap_id); } if (!keys.empty()) last_read = *(keys.rbegin()); } while (r == max_read); uint64_t snap_seq; r = read_key(hctx, "snap_seq", &snap_seq); if (r < 0) { CLS_ERR("could not read the image's snap_seq off disk: %s", cpp_strerror(r).c_str()); return r; } // snap_ids must be descending in a snap context std::reverse(snap_ids.begin(), snap_ids.end()); ::encode(snap_seq, *out); ::encode(snap_ids, *out); return 0; } /** * Output: * @param object_prefix prefix for data object names (string) * @returns 0 on success, negative error code on failure */ int get_object_prefix(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { CLS_LOG(20, "get_object_prefix"); string object_prefix; int r = read_key(hctx, "object_prefix", &object_prefix); if (r < 0) { CLS_ERR("failed to read the image's object prefix off of disk: %s", cpp_strerror(r).c_str()); return r; } ::encode(object_prefix, *out); return 0; } int get_snapshot_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t snap_id; bufferlist::iterator iter = in->begin(); try { ::decode(snap_id, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "get_snapshot_name snap_id=%llu", (unsigned long long)snap_id); if (snap_id == CEPH_NOSNAP) return -EINVAL; cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id, &snapshot_key); int r = read_key(hctx, snapshot_key, &snap); if (r < 0) return r; ::encode(snap.name, *out); return 0; } /** * Adds a snapshot to an rbd header. Ensures the id and name are unique. * * Input: * @param snap_name name of the snapshot (string) * @param snap_id id of the snapshot (uint64_t) * * Output: * @returns 0 on success, negative error code on failure. * @returns -ESTALE if the input snap_id is less than the image's snap_seq * @returns -EEXIST if the id or name are already used by another snapshot */ int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist snap_namebl, snap_idbl; cls_rbd_snap snap_meta; try { bufferlist::iterator iter = in->begin(); ::decode(snap_meta.name, iter); ::decode(snap_meta.id, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "snapshot_add name=%s id=%llu", snap_meta.name.c_str(), (unsigned long long)snap_meta.id.val); if (snap_meta.id > CEPH_MAXSNAP) return -EINVAL; uint64_t cur_snap_seq; int r = read_key(hctx, "snap_seq", &cur_snap_seq); if (r < 0) { CLS_ERR("Could not read image's snap_seq off disk: %s", cpp_strerror(r).c_str()); return r; } // client lost a race with another snapshot creation. // snap_seq must be monotonically increasing. if (snap_meta.id < cur_snap_seq) return -ESTALE; r = read_key(hctx, "size", &snap_meta.image_size); if (r < 0) { CLS_ERR("Could not read image's size off disk: %s", cpp_strerror(r).c_str()); return r; } r = read_key(hctx, "features", &snap_meta.features); if (r < 0) { CLS_ERR("Could not read image's features off disk: %s", cpp_strerror(r).c_str()); return r; } int max_read = RBD_MAX_KEYS_READ; string last_read = RBD_SNAP_KEY_PREFIX; do { map vals; r = cls_cxx_map_get_vals(hctx, last_read, RBD_SNAP_KEY_PREFIX, max_read, &vals); if (r < 0) return r; for (map::iterator it = vals.begin(); it != vals.end(); ++it) { cls_rbd_snap old_meta; bufferlist::iterator iter = it->second.begin(); try { ::decode(old_meta, iter); } catch (const buffer::error &err) { snapid_t snap_id = snap_id_from_key(it->first); CLS_ERR("error decoding snapshot metadata for snap_id: %llu", (unsigned long long)snap_id.val); return -EIO; } if (snap_meta.name == old_meta.name || snap_meta.id == old_meta.id) { CLS_LOG(20, "snap_name %s or snap_id %llu matches existing snap %s %llu", snap_meta.name.c_str(), (unsigned long long)snap_meta.id.val, old_meta.name.c_str(), (unsigned long long)old_meta.id.val); return -EEXIST; } } if (!vals.empty()) last_read = vals.rbegin()->first; } while (r == RBD_MAX_KEYS_READ); // snapshot inherits parent, if any cls_rbd_parent parent; r = read_key(hctx, "parent", &parent); if (r < 0 && r != -ENOENT) return r; if (r == 0) { snap_meta.parent = parent; } bufferlist snap_metabl, snap_seqbl; ::encode(snap_meta, snap_metabl); ::encode(snap_meta.id, snap_seqbl); string snapshot_key; key_from_snap_id(snap_meta.id, &snapshot_key); map vals; vals["snap_seq"] = snap_seqbl; vals[snapshot_key] = snap_metabl; r = cls_cxx_map_set_vals(hctx, &vals); if (r < 0) { CLS_ERR("error writing snapshot metadata: %d", r); return r; } return 0; } /** * Removes a snapshot from an rbd header. * * Input: * @param snap_id the id of the snapshot to remove (uint64_t) * * Output: * @returns 0 on success, negative error code on failure */ int snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { snapid_t snap_id; try { bufferlist::iterator iter = in->begin(); ::decode(snap_id, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "snapshot_remove id=%llu", (unsigned long long)snap_id.val); // check if the key exists. we can't rely on remove_key doing this for // us, since OMAPRMKEYS returns success if the key is not there. // bug or feature? sounds like a bug, since tmap did not have this // behavior, but cls_rgw may rely on it... cls_rbd_snap snap; string snapshot_key; key_from_snap_id(snap_id, &snapshot_key); int r = read_key(hctx, snapshot_key, &snap); if (r == -ENOENT) return -ENOENT; if (snap.protection_status != RBD_PROTECTION_STATUS_UNPROTECTED) return -EBUSY; r = cls_cxx_map_remove_key(hctx, snapshot_key); if (r < 0) { CLS_ERR("error writing snapshot metadata: %d", r); return r; } return 0; } /** * Returns a uint64_t of all the features supported by this class. */ int get_all_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t all_features = RBD_FEATURES_ALL; ::encode(all_features, *out); return 0; } /** * "Copy up" data from the parent of a clone to the clone's object(s). * Used for implementing copy-on-write for a clone image. Client * will pass down a chunk of data that fits completely within one * clone block (one object), and is aligned (starts at beginning of block), * but may be shorter (for non-full parent blocks). The class method * can't know the object size to validate the requested length, * so it just writes the data as given if the child object doesn't * already exist, and returns success if it does. * * Input: * @param in bufferlist of data to write * * Output: * @returns 0 on success, or if block already exists in child * negative error code on other error */ int copyup(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { // check for existence; if child object exists, just return success if (cls_cxx_stat(hctx, NULL, NULL) == 0) return 0; CLS_LOG(20, "copyup: writing length %d\n", in->length()); return cls_cxx_write(hctx, 0, in->length(), in); } /************************ rbd_id object methods **************************/ /** * Input: * @param in ignored * * Output: * @param id the id stored in the object * @returns 0 on success, negative error code on failure */ int get_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { uint64_t size; int r = cls_cxx_stat(hctx, &size, NULL); if (r < 0) return r; if (size == 0) return -ENOENT; bufferlist read_bl; r = cls_cxx_read(hctx, 0, size, &read_bl); if (r < 0) { CLS_ERR("get_id: could not read id: %d", r); return r; } string id; try { bufferlist::iterator iter = read_bl.begin(); ::decode(id, iter); } catch (const buffer::error &err) { return -EIO; } ::encode(id, *out); return 0; }; /** * Set the id of an image. The object must already exist. * * Input: * @param id the id of the image, as an alpha-numeric string * * Output: * @returns 0 on success, -EEXIST if the atomic create fails, * negative error code on other error */ int set_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r = check_exists(hctx); if (r < 0) return r; string id; try { bufferlist::iterator iter = in->begin(); ::decode(id, iter); } catch (const buffer::error &err) { return -EINVAL; } if (!is_valid_id(id)) { CLS_ERR("set_id: invalid id '%s'", id.c_str()); return -EINVAL; } uint64_t size; r = cls_cxx_stat(hctx, &size, NULL); if (r < 0) return r; if (size != 0) return -EEXIST; CLS_LOG(20, "set_id: id=%s", id.c_str()); bufferlist write_bl; ::encode(id, write_bl); return cls_cxx_write(hctx, 0, write_bl.length(), &write_bl); } /*********************** methods for rbd_directory ***********************/ static const string dir_key_for_id(const string &id) { return RBD_DIR_ID_KEY_PREFIX + id; } static const string dir_key_for_name(const string &name) { return RBD_DIR_NAME_KEY_PREFIX + name; } static const string dir_name_from_key(const string &key) { return key.substr(strlen(RBD_DIR_NAME_KEY_PREFIX)); } static int dir_add_image_helper(cls_method_context_t hctx, const string &name, const string &id, bool check_for_unique_id) { if (!name.size() || !is_valid_id(id)) { CLS_ERR("dir_add_image_helper: invalid name '%s' or id '%s'", name.c_str(), id.c_str()); return -EINVAL; } CLS_LOG(20, "dir_add_image_helper name=%s id=%s", name.c_str(), id.c_str()); string tmp; string name_key = dir_key_for_name(name); string id_key = dir_key_for_id(id); int r = read_key(hctx, name_key, &tmp); if (r != -ENOENT) { CLS_LOG(10, "name already exists"); return -EEXIST; } r = read_key(hctx, id_key, &tmp); if (r != -ENOENT && check_for_unique_id) { CLS_LOG(10, "id already exists"); return -EBADF; } bufferlist id_bl, name_bl; ::encode(id, id_bl); ::encode(name, name_bl); map omap_vals; omap_vals[name_key] = id_bl; omap_vals[id_key] = name_bl; return cls_cxx_map_set_vals(hctx, &omap_vals); } static int dir_remove_image_helper(cls_method_context_t hctx, const string &name, const string &id) { CLS_LOG(20, "dir_remove_image_helper name=%s id=%s", name.c_str(), id.c_str()); string stored_name, stored_id; string name_key = dir_key_for_name(name); string id_key = dir_key_for_id(id); int r = read_key(hctx, name_key, &stored_id); if (r < 0) { if (r != -ENOENT) CLS_ERR("error reading name to id mapping: %d", r); return r; } r = read_key(hctx, id_key, &stored_name); if (r < 0) { CLS_ERR("error reading id to name mapping: %d", r); return r; } // check if this op raced with a rename if (stored_name != name || stored_id != id) { CLS_ERR("stored name '%s' and id '%s' do not match args '%s' and '%s'", stored_name.c_str(), stored_id.c_str(), name.c_str(), id.c_str()); return -ESTALE; } r = cls_cxx_map_remove_key(hctx, name_key); if (r < 0) { CLS_ERR("error removing name: %d", r); return r; } r = cls_cxx_map_remove_key(hctx, id_key); if (r < 0) { CLS_ERR("error removing id: %d", r); return r; } return 0; } /** * Rename an image in the directory, updating both indexes * atomically. This can't be done from the client calling * dir_add_image and dir_remove_image in one transaction because the * results of the first method are not visibale to later steps. * * Input: * @param src original name of the image * @param dest new name of the image * @param id the id of the image * * Output: * @returns -ESTALE if src and id do not map to each other * @returns -ENOENT if src or id are not in the directory * @returns -EEXIST if dest already exists * @returns 0 on success, negative error code on failure */ int dir_rename_image(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { string src, dest, id; try { bufferlist::iterator iter = in->begin(); ::decode(src, iter); ::decode(dest, iter); ::decode(id, iter); } catch (const buffer::error &err) { return -EINVAL; } int r = dir_remove_image_helper(hctx, src, id); if (r < 0) return r; // ignore duplicate id because the result of // remove_image_helper is not visible yet return dir_add_image_helper(hctx, dest, id, false); } /** * Get the id of an image given its name. * * Input: * @param name the name of the image * * Output: * @param id the id of the image * @returns 0 on success, negative error code on failure */ int dir_get_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { string name; try { bufferlist::iterator iter = in->begin(); ::decode(name, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "dir_get_id: name=%s", name.c_str()); string id; int r = read_key(hctx, dir_key_for_name(name), &id); if (r < 0) { if (r != -ENOENT) CLS_ERR("error reading id for name '%s': %d", name.c_str(), r); return r; } ::encode(id, *out); return 0; } /** * Get the name of an image given its id. * * Input: * @param id the id of the image * * Output: * @param name the name of the image * @returns 0 on success, negative error code on failure */ int dir_get_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { string id; try { bufferlist::iterator iter = in->begin(); ::decode(id, iter); } catch (const buffer::error &err) { return -EINVAL; } CLS_LOG(20, "dir_get_name: id=%s", id.c_str()); string name; int r = read_key(hctx, dir_key_for_id(id), &name); if (r < 0) { CLS_ERR("error reading name for id '%s': %d", id.c_str(), r); return r; } ::encode(name, *out); return 0; } /** * List the names and ids of the images in the directory, sorted by * name. * * Input: * @param start_after which name to begin listing after * (use the empty string to start at the beginning) * @param max_return the maximum number of names to list * * Output: * @param images map from name to id of up to max_return images * @returns 0 on success, negative error code on failure */ int dir_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { string start_after; uint64_t max_return; try { bufferlist::iterator iter = in->begin(); ::decode(start_after, iter); ::decode(max_return, iter); } catch (const buffer::error &err) { return -EINVAL; } int max_read = RBD_MAX_KEYS_READ; int r = max_read; map images; string last_read = dir_key_for_name(start_after); while (r == max_read && images.size() < max_return) { map vals; CLS_LOG(20, "last_read = '%s'", last_read.c_str()); r = cls_cxx_map_get_vals(hctx, last_read, RBD_DIR_NAME_KEY_PREFIX, max_read, &vals); if (r < 0) { CLS_ERR("error reading directory by name: %d", r); return r; } for (map::iterator it = vals.begin(); it != vals.end(); ++it) { string id; bufferlist::iterator iter = it->second.begin(); try { ::decode(id, iter); } catch (const buffer::error &err) { CLS_ERR("could not decode id of image '%s'", it->first.c_str()); return -EIO; } CLS_LOG(20, "adding '%s' -> '%s'", dir_name_from_key(it->first).c_str(), id.c_str()); images[dir_name_from_key(it->first)] = id; if (images.size() >= max_return) break; } if (!vals.empty()) { last_read = dir_key_for_name(images.rbegin()->first); } } ::encode(images, *out); return 0; } /** * Add an image to the rbd directory. Creates the directory object if * needed, and updates the index from id to name and name to id. * * Input: * @param name the name of the image * @param id the id of the image * * Output: * @returns -EEXIST if the image name is already in the directory * @returns -EBADF if the image id is already in the directory * @returns 0 on success, negative error code on failure */ int dir_add_image(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { int r = cls_cxx_create(hctx, false); if (r < 0) { CLS_ERR("could not create directory: error %d", r); return r; } string name, id; try { bufferlist::iterator iter = in->begin(); ::decode(name, iter); ::decode(id, iter); } catch (const buffer::error &err) { return -EINVAL; } return dir_add_image_helper(hctx, name, id, true); } /** * Remove an image from the rbd directory. * * Input: * @param name the name of the image * @param id the id of the image * * Output: * @returns -ESTALE if the name and id do not map to each other * @returns 0 on success, negative error code on failure */ int dir_remove_image(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { string name, id; try { bufferlist::iterator iter = in->begin(); ::decode(name, iter); ::decode(id, iter); } catch (const buffer::error &err) { return -EINVAL; } return dir_remove_image_helper(hctx, name, id); } /****************************** Old format *******************************/ int old_snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist bl; struct rbd_obj_header_ondisk *header; int rc = snap_read_header(hctx, bl); if (rc < 0) return rc; header = (struct rbd_obj_header_ondisk *)bl.c_str(); bufferptr p(header->snap_names_len); char *buf = (char *)header; char *name = buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk); char *end = name + header->snap_names_len; memcpy(p.c_str(), buf + sizeof(*header) + header->snap_count * sizeof(struct rbd_obj_snap_ondisk), header->snap_names_len); ::encode(header->snap_seq, *out); ::encode(header->snap_count, *out); for (unsigned i = 0; i < header->snap_count; i++) { string s = name; ::encode(header->snaps[i].id, *out); ::encode(header->snaps[i].image_size, *out); ::encode(s, *out); name += strlen(name) + 1; if (name > end) return -EIO; } return 0; } int old_snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist bl; struct rbd_obj_header_ondisk *header; bufferlist newbl; bufferptr header_bp(sizeof(*header)); struct rbd_obj_snap_ondisk *new_snaps; int rc = snap_read_header(hctx, bl); if (rc < 0) return rc; header = (struct rbd_obj_header_ondisk *)bl.c_str(); int snaps_id_ofs = sizeof(*header); int names_ofs = snaps_id_ofs + sizeof(*new_snaps) * header->snap_count; const char *snap_name; const char *snap_names = ((char *)header) + names_ofs; const char *end = snap_names + header->snap_names_len; bufferlist::iterator iter = in->begin(); string s; uint64_t snap_id; try { ::decode(s, iter); ::decode(snap_id, iter); } catch (const buffer::error &err) { return -EINVAL; } snap_name = s.c_str(); if (header->snap_seq > snap_id) return -ESTALE; const char *cur_snap_name; for (cur_snap_name = snap_names; cur_snap_name < end; cur_snap_name += strlen(cur_snap_name) + 1) { if (strncmp(cur_snap_name, snap_name, end - cur_snap_name) == 0) return -EEXIST; } if (cur_snap_name > end) return -EIO; int snap_name_len = strlen(snap_name); bufferptr new_names_bp(header->snap_names_len + snap_name_len + 1); bufferptr new_snaps_bp(sizeof(*new_snaps) * (header->snap_count + 1)); /* copy snap names and append to new snap name */ char *new_snap_names = new_names_bp.c_str(); strcpy(new_snap_names, snap_name); memcpy(new_snap_names + snap_name_len + 1, snap_names, header->snap_names_len); /* append new snap id */ new_snaps = (struct rbd_obj_snap_ondisk *)new_snaps_bp.c_str(); memcpy(new_snaps + 1, header->snaps, sizeof(*new_snaps) * header->snap_count); header->snap_count = header->snap_count + 1; header->snap_names_len = header->snap_names_len + snap_name_len + 1; header->snap_seq = snap_id; new_snaps[0].id = snap_id; new_snaps[0].image_size = header->image_size; memcpy(header_bp.c_str(), header, sizeof(*header)); newbl.push_back(header_bp); newbl.push_back(new_snaps_bp); newbl.push_back(new_names_bp); rc = cls_cxx_write_full(hctx, &newbl); if (rc < 0) return rc; return 0; } int old_snapshot_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { bufferlist bl; struct rbd_obj_header_ondisk *header; bufferlist newbl; bufferptr header_bp(sizeof(*header)); int rc = snap_read_header(hctx, bl); if (rc < 0) return rc; header = (struct rbd_obj_header_ondisk *)bl.c_str(); int snaps_id_ofs = sizeof(*header); int names_ofs = snaps_id_ofs + sizeof(struct rbd_obj_snap_ondisk) * header->snap_count; const char *snap_name; const char *snap_names = ((char *)header) + names_ofs; const char *orig_names = snap_names; const char *end = snap_names + header->snap_names_len; bufferlist::iterator iter = in->begin(); string s; unsigned i; bool found = false; struct rbd_obj_snap_ondisk snap; try { ::decode(s, iter); } catch (const buffer::error &err) { return -EINVAL; } snap_name = s.c_str(); for (i = 0; snap_names < end; i++) { if (strcmp(snap_names, snap_name) == 0) { snap = header->snaps[i]; found = true; break; } snap_names += strlen(snap_names) + 1; } if (!found) { CLS_ERR("couldn't find snap %s\n", snap_name); return -ENOENT; } header->snap_names_len = header->snap_names_len - (s.length() + 1); header->snap_count = header->snap_count - 1; bufferptr new_names_bp(header->snap_names_len); bufferptr new_snaps_bp(sizeof(header->snaps[0]) * header->snap_count); memcpy(header_bp.c_str(), header, sizeof(*header)); newbl.push_back(header_bp); if (header->snap_count) { int snaps_len = 0; int names_len = 0; CLS_LOG(20, "i=%d\n", i); if (i > 0) { snaps_len = sizeof(header->snaps[0]) * i; names_len = snap_names - orig_names; memcpy(new_snaps_bp.c_str(), header->snaps, snaps_len); memcpy(new_names_bp.c_str(), orig_names, names_len); } snap_names += s.length() + 1; if (i < header->snap_count) { memcpy(new_snaps_bp.c_str() + snaps_len, header->snaps + i + 1, sizeof(header->snaps[0]) * (header->snap_count - i)); memcpy(new_names_bp.c_str() + names_len, snap_names , end - snap_names); } newbl.push_back(new_snaps_bp); newbl.push_back(new_names_bp); } rc = cls_cxx_write_full(hctx, &newbl); if (rc < 0) return rc; return 0; } void __cls_init() { CLS_LOG(20, "Loaded rbd class!"); cls_register("rbd", &h_class); cls_register_cxx_method(h_class, "create", CLS_METHOD_RD | CLS_METHOD_WR, create, &h_create); cls_register_cxx_method(h_class, "get_features", CLS_METHOD_RD, get_features, &h_get_features); cls_register_cxx_method(h_class, "get_size", CLS_METHOD_RD, get_size, &h_get_size); cls_register_cxx_method(h_class, "set_size", CLS_METHOD_RD | CLS_METHOD_WR, set_size, &h_set_size); cls_register_cxx_method(h_class, "get_snapcontext", CLS_METHOD_RD, get_snapcontext, &h_get_snapcontext); cls_register_cxx_method(h_class, "get_object_prefix", CLS_METHOD_RD, get_object_prefix, &h_get_object_prefix); cls_register_cxx_method(h_class, "get_snapshot_name", CLS_METHOD_RD, get_snapshot_name, &h_get_snapshot_name); cls_register_cxx_method(h_class, "snapshot_add", CLS_METHOD_RD | CLS_METHOD_WR, snapshot_add, &h_snapshot_add); cls_register_cxx_method(h_class, "snapshot_remove", CLS_METHOD_RD | CLS_METHOD_WR, snapshot_remove, &h_snapshot_remove); cls_register_cxx_method(h_class, "get_all_features", CLS_METHOD_RD, get_all_features, &h_get_all_features); cls_register_cxx_method(h_class, "copyup", CLS_METHOD_RD | CLS_METHOD_WR, copyup, &h_copyup); cls_register_cxx_method(h_class, "get_parent", CLS_METHOD_RD, get_parent, &h_get_parent); cls_register_cxx_method(h_class, "set_parent", CLS_METHOD_RD | CLS_METHOD_WR, set_parent, &h_set_parent); cls_register_cxx_method(h_class, "remove_parent", CLS_METHOD_RD | CLS_METHOD_WR, remove_parent, &h_remove_parent); cls_register_cxx_method(h_class, "set_protection_status", CLS_METHOD_RD | CLS_METHOD_WR, set_protection_status, &h_set_protection_status); cls_register_cxx_method(h_class, "get_protection_status", CLS_METHOD_RD, get_protection_status, &h_get_protection_status); cls_register_cxx_method(h_class, "get_stripe_unit_count", CLS_METHOD_RD, get_stripe_unit_count, &h_get_stripe_unit_count); cls_register_cxx_method(h_class, "set_stripe_unit_count", CLS_METHOD_RD | CLS_METHOD_WR, set_stripe_unit_count, &h_set_stripe_unit_count); /* methods for the rbd_children object */ cls_register_cxx_method(h_class, "add_child", CLS_METHOD_RD | CLS_METHOD_WR, add_child, &h_add_child); cls_register_cxx_method(h_class, "remove_child", CLS_METHOD_RD | CLS_METHOD_WR, remove_child, &h_remove_child); cls_register_cxx_method(h_class, "get_children", CLS_METHOD_RD, get_children, &h_get_children); /* methods for the rbd_id.$image_name objects */ cls_register_cxx_method(h_class, "get_id", CLS_METHOD_RD, get_id, &h_get_id); cls_register_cxx_method(h_class, "set_id", CLS_METHOD_RD | CLS_METHOD_WR, set_id, &h_set_id); /* methods for the rbd_directory object */ cls_register_cxx_method(h_class, "dir_get_id", CLS_METHOD_RD, dir_get_id, &h_dir_get_id); cls_register_cxx_method(h_class, "dir_get_name", CLS_METHOD_RD, dir_get_name, &h_dir_get_name); cls_register_cxx_method(h_class, "dir_list", CLS_METHOD_RD, dir_list, &h_dir_list); cls_register_cxx_method(h_class, "dir_add_image", CLS_METHOD_RD | CLS_METHOD_WR, dir_add_image, &h_dir_add_image); cls_register_cxx_method(h_class, "dir_remove_image", CLS_METHOD_RD | CLS_METHOD_WR, dir_remove_image, &h_dir_remove_image); cls_register_cxx_method(h_class, "dir_rename_image", CLS_METHOD_RD | CLS_METHOD_WR, dir_rename_image, &h_dir_rename_image); /* methods for the old format */ cls_register_cxx_method(h_class, "snap_list", CLS_METHOD_RD, old_snapshots_list, &h_old_snapshots_list); cls_register_cxx_method(h_class, "snap_add", CLS_METHOD_RD | CLS_METHOD_WR, old_snapshot_add, &h_old_snapshot_add); cls_register_cxx_method(h_class, "snap_remove", CLS_METHOD_RD | CLS_METHOD_WR, old_snapshot_remove, &h_old_snapshot_remove); return; } ceph-0.80.11/src/osdc/0000775000175100017510000000000012623077035016406 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/osdc/Striper.cc0000664000175100017510000002601612623076744020360 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Striper.h" #include "include/types.h" #include "include/buffer.h" #include "osd/OSDMap.h" #include "common/config.h" #include "common/debug.h" #define dout_subsys ceph_subsys_striper #undef dout_prefix #define dout_prefix *_dout << "striper " void Striper::file_to_extents(CephContext *cct, const char *object_format, ceph_file_layout *layout, uint64_t offset, uint64_t len, uint64_t trunc_size, vector& extents, uint64_t buffer_offset) { map > object_extents; file_to_extents(cct, object_format, layout, offset, len, trunc_size, object_extents, buffer_offset); assimilate_extents(object_extents, extents); } void Striper::file_to_extents(CephContext *cct, const char *object_format, ceph_file_layout *layout, uint64_t offset, uint64_t len, uint64_t trunc_size, map >& object_extents, uint64_t buffer_offset) { ldout(cct, 10) << "file_to_extents " << offset << "~" << len << " format " << object_format << dendl; assert(len > 0); /* * we want only one extent per object! * this means that each extent we read may map into different bits of the * final read buffer.. hence OSDExtent.buffer_extents */ __u32 object_size = layout->fl_object_size; __u32 su = layout->fl_stripe_unit; __u32 stripe_count = layout->fl_stripe_count; assert(object_size >= su); uint64_t stripes_per_object = object_size / su; ldout(cct, 20) << " su " << su << " sc " << stripe_count << " os " << object_size << " stripes_per_object " << stripes_per_object << dendl; uint64_t cur = offset; uint64_t left = len; while (left > 0) { // layout into objects uint64_t blockno = cur / su; // which block uint64_t stripeno = blockno / stripe_count; // which horizontal stripe (Y) uint64_t stripepos = blockno % stripe_count; // which object in the object set (X) uint64_t objectsetno = stripeno / stripes_per_object; // which object set uint64_t objectno = objectsetno * stripe_count + stripepos; // object id // find oid, extent char buf[strlen(object_format) + 32]; snprintf(buf, sizeof(buf), object_format, (long long unsigned)objectno); object_t oid = buf; // map range into object uint64_t block_start = (stripeno % stripes_per_object) * su; uint64_t block_off = cur % su; uint64_t max = su - block_off; uint64_t x_offset = block_start + block_off; uint64_t x_len; if (left > max) x_len = max; else x_len = left; ldout(cct, 20) << " off " << cur << " blockno " << blockno << " stripeno " << stripeno << " stripepos " << stripepos << " objectsetno " << objectsetno << " objectno " << objectno << " block_start " << block_start << " block_off " << block_off << " " << x_offset << "~" << x_len << dendl; ObjectExtent *ex = 0; vector& exv = object_extents[oid]; if (exv.empty() || exv.back().offset + exv.back().length != x_offset) { exv.resize(exv.size() + 1); ex = &exv.back(); ex->oid = oid; ex->objectno = objectno; ex->oloc = OSDMap::file_to_object_locator(*layout); ex->offset = x_offset; ex->length = x_len; ex->truncate_size = object_truncate_size(cct, layout, objectno, trunc_size); ldout(cct, 20) << " added new " << *ex << dendl; } else { // add to extent ex = &exv.back(); ldout(cct, 20) << " adding in to " << *ex << dendl; ex->length += x_len; } ex->buffer_extents.push_back(make_pair(cur - offset + buffer_offset, x_len)); ldout(cct, 15) << "file_to_extents " << *ex << " in " << ex->oloc << dendl; //ldout(cct, 0) << "map: ino " << ino << " oid " << ex.oid << " osd " << ex.osd << " offset " << ex.offset << " len " << ex.len << " ... left " << left << dendl; left -= x_len; cur += x_len; } } void Striper::assimilate_extents(map >& object_extents, vector& extents) { // make final list for (map >::iterator it = object_extents.begin(); it != object_extents.end(); ++it) { for (vector::iterator p = it->second.begin(); p != it->second.end(); ++p) { extents.push_back(*p); } } } void Striper::extent_to_file(CephContext *cct, ceph_file_layout *layout, uint64_t objectno, uint64_t off, uint64_t len, vector >& extents) { ldout(cct, 10) << "extent_to_file " << objectno << " " << off << "~" << len << dendl; __u32 object_size = layout->fl_object_size; __u32 su = layout->fl_stripe_unit; __u32 stripe_count = layout->fl_stripe_count; assert(object_size >= su); uint64_t stripes_per_object = object_size / su; ldout(cct, 20) << " stripes_per_object " << stripes_per_object << dendl; uint64_t off_in_block = off % su; extents.reserve(len / su + 1); while (len > 0) { uint64_t stripepos = objectno % stripe_count; uint64_t objectsetno = objectno / stripe_count; uint64_t stripeno = off / su + objectsetno * stripes_per_object; uint64_t blockno = stripeno * stripe_count + stripepos; uint64_t extent_off = blockno * su + off_in_block; uint64_t extent_len = MIN(len, su - off_in_block); extents.push_back(make_pair(extent_off, extent_len)); ldout(cct, 20) << " object " << off << "~" << extent_len << " -> file " << extent_off << "~" << extent_len << dendl; off_in_block = 0; off += extent_len; len -= extent_len; } } uint64_t Striper::object_truncate_size(CephContext *cct, ceph_file_layout *layout, uint64_t objectno, uint64_t trunc_size) { uint64_t obj_trunc_size; if (trunc_size == 0 || trunc_size == (uint64_t)-1) { obj_trunc_size = trunc_size; } else { __u32 object_size = layout->fl_object_size; __u32 su = layout->fl_stripe_unit; __u32 stripe_count = layout->fl_stripe_count; assert(object_size >= su); uint64_t stripes_per_object = object_size / su; uint64_t objectsetno = objectno / stripe_count; uint64_t trunc_objectsetno = trunc_size / object_size / stripe_count; if (objectsetno > trunc_objectsetno) obj_trunc_size = 0; else if (objectsetno < trunc_objectsetno) obj_trunc_size = object_size; else { uint64_t trunc_blockno = trunc_size / su; uint64_t trunc_stripeno = trunc_blockno / stripe_count; uint64_t trunc_stripepos = trunc_blockno % stripe_count; uint64_t trunc_objectno = trunc_objectsetno * stripe_count + trunc_stripepos; if (objectno < trunc_objectno) obj_trunc_size = ((trunc_stripeno % stripes_per_object) + 1) * su; else if (objectno > trunc_objectno) obj_trunc_size = (trunc_stripeno % stripes_per_object) * su; else obj_trunc_size = (trunc_stripeno % stripes_per_object) * su + (trunc_size % su); } } ldout(cct, 20) << "object_truncate_size " << objectno << " " << trunc_size << "->" << obj_trunc_size << dendl; return obj_trunc_size; } // StripedReadResult void Striper::StripedReadResult::add_partial_result(CephContext *cct, bufferlist& bl, const vector >& buffer_extents) { ldout(cct, 10) << "add_partial_result(" << this << ") " << bl.length() << " to " << buffer_extents << dendl; for (vector >::const_iterator p = buffer_extents.begin(); p != buffer_extents.end(); ++p) { pair& r = partial[p->first]; size_t actual = MIN(bl.length(), p->second); bl.splice(0, actual, &r.first); r.second = p->second; } } void Striper::StripedReadResult::add_partial_sparse_result(CephContext *cct, bufferlist& bl, const map& bl_map, uint64_t bl_off, const vector >& buffer_extents) { ldout(cct, 10) << "add_partial_sparse_result(" << this << ") " << bl.length() << " covering " << bl_map << " (offset " << bl_off << ")" << " to " << buffer_extents << dendl; map::const_iterator s = bl_map.begin(); for (vector >::const_iterator p = buffer_extents.begin(); p != buffer_extents.end(); ++p) { uint64_t tofs = p->first; uint64_t tlen = p->second; ldout(cct, 30) << " be " << tofs << "~" << tlen << dendl; while (tlen > 0) { ldout(cct, 20) << " t " << tofs << "~" << tlen << " bl has " << bl.length() << " off " << bl_off << dendl; if (s == bl_map.end()) { ldout(cct, 20) << " s at end" << dendl; pair& r = partial[tofs]; r.second = tlen; break; } ldout(cct, 30) << " s " << s->first << "~" << s->second << dendl; // skip zero-length extent if (s->second == 0) { ldout(cct, 30) << " s len 0, skipping" << dendl; ++s; continue; } if (s->first > bl_off) { // gap in sparse read result pair& r = partial[tofs]; size_t gap = MIN(s->first - bl_off, tlen); ldout(cct, 20) << " s gap " << gap << ", skipping" << dendl; r.second = gap; bl_off += gap; tofs += gap; tlen -= gap; if (tlen == 0) { continue; } } assert(s->first <= bl_off); size_t left = (s->first + s->second) - bl_off; size_t actual = MIN(left, tlen); if (actual > 0) { ldout(cct, 20) << " s has " << actual << ", copying" << dendl; pair& r = partial[tofs]; bl.splice(0, actual, &r.first); r.second = actual; bl_off += actual; tofs += actual; tlen -= actual; } if (actual == left) { ldout(cct, 30) << " s advancing" << dendl; ++s; } } } } void Striper::StripedReadResult::assemble_result(CephContext *cct, bufferlist& bl, bool zero_tail) { ldout(cct, 10) << "assemble_result(" << this << ") zero_tail=" << zero_tail << dendl; // go backwards, so that we can efficiently discard zeros map >::reverse_iterator p = partial.rbegin(); if (p == partial.rend()) return; uint64_t end = p->first + p->second.second; while (p != partial.rend()) { // sanity check ldout(cct, 20) << "assemble_result(" << this << ") " << p->first << "~" << p->second.second << " " << p->second.first.length() << " bytes" << dendl; assert(p->first == end - p->second.second); end = p->first; size_t len = p->second.first.length(); if (len < p->second.second) { if (zero_tail || bl.length()) { bufferptr bp(p->second.second - len); bp.zero(); bl.push_front(bp); bl.claim_prepend(p->second.first); } else { bl.claim_prepend(p->second.first); } } else { bl.claim_prepend(p->second.first); } ++p; } partial.clear(); } ceph-0.80.11/src/osdc/Filer.cc0000664000175100017510000001773412623076744020000 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Filer.h" #include "osd/OSDMap.h" #include "Striper.h" #include "messages/MOSDOp.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDMap.h" #include "msg/Messenger.h" #include "include/Context.h" #include "common/config.h" #define dout_subsys ceph_subsys_filer #undef dout_prefix #define dout_prefix *_dout << objecter->messenger->get_myname() << ".filer " class Filer::C_Probe : public Context { public: Filer *filer; Probe *probe; object_t oid; uint64_t size; utime_t mtime; C_Probe(Filer *f, Probe *p, object_t o) : filer(f), probe(p), oid(o), size(0) {} void finish(int r) { if (r == -ENOENT) { r = 0; assert(size == 0); } // TODO: handle this error. if (r != 0) probe->err = r; filer->_probed(probe, oid, size, mtime); } }; int Filer::probe(inodeno_t ino, ceph_file_layout *layout, snapid_t snapid, uint64_t start_from, uint64_t *end, // LB, when !fwd utime_t *pmtime, bool fwd, int flags, Context *onfinish) { ldout(cct, 10) << "probe " << (fwd ? "fwd ":"bwd ") << hex << ino << dec << " starting from " << start_from << dendl; assert(snapid); // (until there is a non-NOSNAP write) Probe *probe = new Probe(ino, *layout, snapid, start_from, end, pmtime, flags, fwd, onfinish); // period (bytes before we jump unto a new set of object(s)) uint64_t period = (uint64_t)layout->fl_stripe_count * (uint64_t)layout->fl_object_size; // start with 1+ periods. probe->probing_len = period; if (probe->fwd) { if (start_from % period) probe->probing_len += period - (start_from % period); } else { assert(start_from > *end); if (start_from % period) probe->probing_len -= period - (start_from % period); probe->probing_off -= probe->probing_len; } _probe(probe); return 0; } void Filer::_probe(Probe *probe) { ldout(cct, 10) << "_probe " << hex << probe->ino << dec << " " << probe->probing_off << "~" << probe->probing_len << dendl; // map range onto objects probe->known_size.clear(); probe->probing.clear(); Striper::file_to_extents(cct, probe->ino, &probe->layout, probe->probing_off, probe->probing_len, 0, probe->probing); for (vector::iterator p = probe->probing.begin(); p != probe->probing.end(); ++p) { ldout(cct, 10) << "_probe probing " << p->oid << dendl; C_Probe *c = new C_Probe(this, probe, p->oid); objecter->stat(p->oid, p->oloc, probe->snapid, &c->size, &c->mtime, probe->flags | CEPH_OSD_FLAG_RWORDERED, c); probe->ops.insert(p->oid); } } void Filer::_probed(Probe *probe, const object_t& oid, uint64_t size, utime_t mtime) { ldout(cct, 10) << "_probed " << probe->ino << " object " << oid << " has size " << size << " mtime " << mtime << dendl; probe->known_size[oid] = size; if (mtime > probe->max_mtime) probe->max_mtime = mtime; assert(probe->ops.count(oid)); probe->ops.erase(oid); if (!probe->ops.empty()) return; // waiting for more! if (probe->err) { // we hit an error, propagate back up probe->onfinish->complete(probe->err); delete probe; return; } // analyze! uint64_t end = 0; if (!probe->fwd) { // reverse vector r; for (vector::reverse_iterator p = probe->probing.rbegin(); p != probe->probing.rend(); ++p) r.push_back(*p); probe->probing.swap(r); } for (vector::iterator p = probe->probing.begin(); p != probe->probing.end(); ++p) { uint64_t shouldbe = p->length + p->offset; ldout(cct, 10) << "_probed " << probe->ino << " object " << hex << p->oid << dec << " should be " << shouldbe << ", actual is " << probe->known_size[p->oid] << dendl; if (!probe->found_size) { assert(probe->known_size[p->oid] <= shouldbe); if ((probe->fwd && probe->known_size[p->oid] == shouldbe) || (!probe->fwd && probe->known_size[p->oid] == 0 && probe->probing_off > 0)) continue; // keep going // aha, we found the end! // calc offset into buffer_extent to get distance from probe->from. uint64_t oleft = probe->known_size[p->oid] - p->offset; for (vector >::iterator i = p->buffer_extents.begin(); i != p->buffer_extents.end(); ++i) { if (oleft <= (uint64_t)i->second) { end = probe->probing_off + i->first + oleft; ldout(cct, 10) << "_probed end is in buffer_extent " << i->first << "~" << i->second << " off " << oleft << ", from was " << probe->probing_off << ", end is " << end << dendl; probe->found_size = true; ldout(cct, 10) << "_probed found size at " << end << dendl; *probe->psize = end; if (!probe->pmtime) // stop if we don't need mtime too break; } oleft -= i->second; } } break; } if (!probe->found_size || (probe->probing_off && probe->pmtime)) { // keep probing! ldout(cct, 10) << "_probed probing further" << dendl; uint64_t period = (uint64_t)probe->layout.fl_stripe_count * (uint64_t)probe->layout.fl_object_size; if (probe->fwd) { probe->probing_off += probe->probing_len; assert(probe->probing_off % period == 0); probe->probing_len = period; } else { // previous period. assert(probe->probing_off % period == 0); probe->probing_len = period; probe->probing_off -= period; } _probe(probe); return; } if (probe->pmtime) { ldout(cct, 10) << "_probed found mtime " << probe->max_mtime << dendl; *probe->pmtime = probe->max_mtime; } // done! finish and clean up. probe->onfinish->complete(probe->err); delete probe; } // ----------------------- struct PurgeRange { inodeno_t ino; ceph_file_layout layout; SnapContext snapc; uint64_t first, num; utime_t mtime; int flags; Context *oncommit; int uncommitted; }; int Filer::purge_range(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t first_obj, uint64_t num_obj, utime_t mtime, int flags, Context *oncommit) { assert(num_obj > 0); // single object? easy! if (num_obj == 1) { object_t oid = file_object_t(ino, first_obj); object_locator_t oloc = objecter->osdmap->file_to_object_locator(*layout); objecter->remove(oid, oloc, snapc, mtime, flags, NULL, oncommit); return 0; } // lots! let's do this in pieces. PurgeRange *pr = new PurgeRange; pr->ino = ino; pr->layout = *layout; pr->snapc = snapc; pr->first = first_obj; pr->num = num_obj; pr->mtime = mtime; pr->flags = flags; pr->oncommit = oncommit; pr->uncommitted = 0; _do_purge_range(pr, 0); return 0; } struct C_PurgeRange : public Context { Filer *filer; PurgeRange *pr; C_PurgeRange(Filer *f, PurgeRange *p) : filer(f), pr(p) {} void finish(int r) { filer->_do_purge_range(pr, 1); } }; void Filer::_do_purge_range(PurgeRange *pr, int fin) { pr->uncommitted -= fin; ldout(cct, 10) << "_do_purge_range " << pr->ino << " objects " << pr->first << "~" << pr->num << " uncommitted " << pr->uncommitted << dendl; if (pr->num == 0 && pr->uncommitted == 0) { pr->oncommit->complete(0); delete pr; return; } int max = 10 - pr->uncommitted; while (pr->num > 0 && max > 0) { object_t oid = file_object_t(pr->ino, pr->first); object_locator_t oloc = objecter->osdmap->file_to_object_locator(pr->layout); objecter->remove(oid, oloc, pr->snapc, pr->mtime, pr->flags, NULL, new C_PurgeRange(this, pr)); pr->uncommitted++; pr->first++; pr->num--; max--; } } ceph-0.80.11/src/osdc/ObjectCacher.h0000664000175100017510000004753512623076744021117 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_OBJECTCACHER_H #define CEPH_OBJECTCACHER_H #include "include/types.h" #include "include/lru.h" #include "include/Context.h" #include "include/xlist.h" #include "common/Cond.h" #include "common/Finisher.h" #include "common/Thread.h" #include "Objecter.h" #include "Striper.h" class CephContext; class WritebackHandler; class PerfCounters; enum { l_objectcacher_first = 25000, l_objectcacher_cache_ops_hit, // ops we satisfy completely from cache l_objectcacher_cache_ops_miss, // ops we don't satisfy completely from cache l_objectcacher_cache_bytes_hit, // bytes read directly from cache l_objectcacher_cache_bytes_miss, // bytes we couldn't read directly from cache l_objectcacher_data_read, // total bytes read out l_objectcacher_data_written, // bytes written to cache l_objectcacher_data_flushed, // bytes flushed to WritebackHandler l_objectcacher_overwritten_in_flush, // bytes overwritten while flushing is in progress l_objectcacher_write_ops_blocked, // total write ops we delayed due to dirty limits l_objectcacher_write_bytes_blocked, // total number of write bytes we delayed due to dirty limits l_objectcacher_write_time_blocked, // total time in seconds spent blocking a write due to dirty limits l_objectcacher_last, }; class ObjectCacher { PerfCounters *perfcounter; public: CephContext *cct; class Object; struct ObjectSet; class C_ReadFinish; typedef void (*flush_set_callback_t) (void *p, ObjectSet *oset); // read scatter/gather struct OSDRead { vector extents; snapid_t snap; map read_data; // bits of data as they come back bufferlist *bl; int flags; OSDRead(snapid_t s, bufferlist *b, int f) : snap(s), bl(b), flags(f) {} }; OSDRead *prepare_read(snapid_t snap, bufferlist *b, int f) { return new OSDRead(snap, b, f); } // write scatter/gather struct OSDWrite { vector extents; SnapContext snapc; bufferlist bl; utime_t mtime; int flags; OSDWrite(const SnapContext& sc, bufferlist& b, utime_t mt, int f) : snapc(sc), bl(b), mtime(mt), flags(f) {} }; OSDWrite *prepare_write(const SnapContext& sc, bufferlist &b, utime_t mt, int f) { return new OSDWrite(sc, b, mt, f); } // ******* BufferHead ********* class BufferHead : public LRUObject { public: // states static const int STATE_MISSING = 0; static const int STATE_CLEAN = 1; static const int STATE_ZERO = 2; // NOTE: these are *clean* zeros static const int STATE_DIRTY = 3; static const int STATE_RX = 4; static const int STATE_TX = 5; static const int STATE_ERROR = 6; // a read error occurred private: // my fields int state; int ref; struct { loff_t start, length; // bh extent in object } ex; public: Object *ob; bufferlist bl; ceph_tid_t last_write_tid; // version of bh (if non-zero) ceph_tid_t last_read_tid; // tid of last read op (if any) utime_t last_write; SnapContext snapc; int error; // holds return value for failed reads map< loff_t, list > waitfor_read; // cons BufferHead(Object *o) : state(STATE_MISSING), ref(0), ob(o), last_write_tid(0), last_read_tid(0), error(0) { ex.start = ex.length = 0; } // extent loff_t start() const { return ex.start; } void set_start(loff_t s) { ex.start = s; } loff_t length() const { return ex.length; } void set_length(loff_t l) { ex.length = l; } loff_t end() const { return ex.start + ex.length; } loff_t last() const { return end() - 1; } // states void set_state(int s) { if (s == STATE_RX || s == STATE_TX) get(); if (state == STATE_RX || state == STATE_TX) put(); state = s; } int get_state() const { return state; } bool is_missing() { return state == STATE_MISSING; } bool is_dirty() { return state == STATE_DIRTY; } bool is_clean() { return state == STATE_CLEAN; } bool is_zero() { return state == STATE_ZERO; } bool is_tx() { return state == STATE_TX; } bool is_rx() { return state == STATE_RX; } bool is_error() { return state == STATE_ERROR; } // reference counting int get() { assert(ref >= 0); if (ref == 0) lru_pin(); return ++ref; } int put() { assert(ref > 0); if (ref == 1) lru_unpin(); --ref; return ref; } }; // ******* Object ********* class Object : public LRUObject { private: // ObjectCacher::Object fields int ref; ObjectCacher *oc; sobject_t oid; friend struct ObjectSet; public: ObjectSet *oset; xlist::item set_item; object_locator_t oloc; uint64_t truncate_size, truncate_seq; bool complete; bool exists; public: map data; ceph_tid_t last_write_tid; // version of bh (if non-zero) ceph_tid_t last_commit_tid; // last update commited. int dirty_or_tx; map< ceph_tid_t, list > waitfor_commit; xlist reads; public: Object(const Object& other); const Object& operator=(const Object& other); Object(ObjectCacher *_oc, sobject_t o, ObjectSet *os, object_locator_t& l, uint64_t ts, uint64_t tq) : ref(0), oc(_oc), oid(o), oset(os), set_item(this), oloc(l), truncate_size(ts), truncate_seq(tq), complete(false), exists(true), last_write_tid(0), last_commit_tid(0), dirty_or_tx(0) { // add to set os->objects.push_back(&set_item); } ~Object() { reads.clear(); assert(ref == 0); assert(data.empty()); assert(dirty_or_tx == 0); set_item.remove_myself(); } sobject_t get_soid() { return oid; } object_t get_oid() { return oid.oid; } snapid_t get_snap() { return oid.snap; } ObjectSet *get_object_set() { return oset; } string get_namespace() { return oloc.nspace; } object_locator_t& get_oloc() { return oloc; } void set_object_locator(object_locator_t& l) { oloc = l; } bool can_close() { if (lru_is_expireable()) { assert(data.empty()); assert(waitfor_commit.empty()); return true; } return false; } /** * Check buffers and waiters for consistency * - no overlapping buffers * - index in map matches BH * - waiters fall within BH */ void audit_buffers(); /** * find first buffer that includes or follows an offset * * @param offset object byte offset * @return iterator pointing to buffer, or data.end() */ map::iterator data_lower_bound(loff_t offset) { map::iterator p = data.lower_bound(offset); if (p != data.begin() && (p == data.end() || p->first > offset)) { --p; // might overlap! if (p->first + p->second->length() <= offset) ++p; // doesn't overlap. } return p; } // bh // add to my map void add_bh(BufferHead *bh) { if (data.empty()) get(); assert(data.count(bh->start()) == 0); data[bh->start()] = bh; } void remove_bh(BufferHead *bh) { assert(data.count(bh->start())); data.erase(bh->start()); if (data.empty()) put(); } bool is_empty() { return data.empty(); } // mid-level BufferHead *split(BufferHead *bh, loff_t off); void merge_left(BufferHead *left, BufferHead *right); void try_merge_bh(BufferHead *bh); bool is_cached(loff_t off, loff_t len); int map_read(OSDRead *rd, map& hits, map& missing, map& rx, map& errors); BufferHead *map_write(OSDWrite *wr); void truncate(loff_t s); void discard(loff_t off, loff_t len); // reference counting int get() { assert(ref >= 0); if (ref == 0) lru_pin(); return ++ref; } int put() { assert(ref > 0); if (ref == 1) lru_unpin(); --ref; return ref; } }; struct ObjectSet { void *parent; inodeno_t ino; uint64_t truncate_seq, truncate_size; int64_t poolid; xlist objects; int dirty_or_tx; bool return_enoent; ObjectSet(void *p, int64_t _poolid, inodeno_t i) : parent(p), ino(i), truncate_seq(0), truncate_size(0), poolid(_poolid), dirty_or_tx(0), return_enoent(false) {} }; // ******* ObjectCacher ********* // ObjectCacher fields private: WritebackHandler& writeback_handler; string name; Mutex& lock; uint64_t max_dirty, target_dirty, max_size, max_objects; utime_t max_dirty_age; bool block_writes_upfront; flush_set_callback_t flush_set_callback; void *flush_set_callback_arg; vector > objects; // indexed by pool_id list waitfor_read; ceph_tid_t last_read_tid; set dirty_bh; LRU bh_lru_dirty, bh_lru_rest; LRU ob_lru; Cond flusher_cond; bool flusher_stop; void flusher_entry(); class FlusherThread : public Thread { ObjectCacher *oc; public: FlusherThread(ObjectCacher *o) : oc(o) {} void *entry() { oc->flusher_entry(); return 0; } } flusher_thread; Finisher finisher; // objects Object *get_object_maybe(sobject_t oid, object_locator_t &l) { // have it? if (((uint32_t)l.pool < objects.size()) && (objects[l.pool].count(oid))) return objects[l.pool][oid]; return NULL; } Object *get_object(sobject_t oid, ObjectSet *oset, object_locator_t &l, uint64_t truncate_size, uint64_t truncate_seq); void close_object(Object *ob); // bh stats Cond stat_cond; loff_t stat_clean; loff_t stat_zero; loff_t stat_dirty; loff_t stat_rx; loff_t stat_tx; loff_t stat_missing; loff_t stat_error; loff_t stat_dirty_waiting; // bytes that writers are waiting on to write void verify_stats() const; void bh_stat_add(BufferHead *bh); void bh_stat_sub(BufferHead *bh); loff_t get_stat_tx() { return stat_tx; } loff_t get_stat_rx() { return stat_rx; } loff_t get_stat_dirty() { return stat_dirty; } loff_t get_stat_dirty_waiting() { return stat_dirty_waiting; } loff_t get_stat_clean() { return stat_clean; } loff_t get_stat_zero() { return stat_zero; } void touch_bh(BufferHead *bh) { if (bh->is_dirty()) bh_lru_dirty.lru_touch(bh); else bh_lru_rest.lru_touch(bh); touch_ob(bh->ob); } void touch_ob(Object *ob) { ob_lru.lru_touch(ob); } // bh states void bh_set_state(BufferHead *bh, int s); void copy_bh_state(BufferHead *bh1, BufferHead *bh2) { bh_set_state(bh2, bh1->get_state()); } void mark_missing(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_MISSING); }; void mark_clean(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_CLEAN); }; void mark_zero(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_ZERO); }; void mark_rx(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_RX); }; void mark_tx(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_TX); }; void mark_error(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_ERROR); }; void mark_dirty(BufferHead *bh) { bh_set_state(bh, BufferHead::STATE_DIRTY); bh_lru_dirty.lru_touch(bh); //bh->set_dirty_stamp(ceph_clock_now(g_ceph_context)); }; void bh_add(Object *ob, BufferHead *bh); void bh_remove(Object *ob, BufferHead *bh); // io void bh_read(BufferHead *bh); void bh_write(BufferHead *bh); void trim(); void flush(loff_t amount=0); /** * flush a range of buffers * * Flush any buffers that intersect the specified extent. If len==0, * flush *all* buffers for the object. * * @param o object * @param off start offset * @param len extent length, or 0 for entire object * @return true if object was already clean/flushed. */ bool flush(Object *o, loff_t off, loff_t len); loff_t release(Object *o); void purge(Object *o); int64_t reads_outstanding; Cond read_cond; int _readx(OSDRead *rd, ObjectSet *oset, Context *onfinish, bool external_call); void retry_waiting_reads(); public: void bh_read_finish(int64_t poolid, sobject_t oid, ceph_tid_t tid, loff_t offset, uint64_t length, bufferlist &bl, int r, bool trust_enoent); void bh_write_commit(int64_t poolid, sobject_t oid, loff_t offset, uint64_t length, ceph_tid_t t, int r); class C_ReadFinish : public Context { ObjectCacher *oc; int64_t poolid; sobject_t oid; loff_t start; uint64_t length; xlist::item set_item; bool trust_enoent; ceph_tid_t tid; public: bufferlist bl; C_ReadFinish(ObjectCacher *c, Object *ob, ceph_tid_t t, loff_t s, uint64_t l) : oc(c), poolid(ob->oloc.pool), oid(ob->get_soid()), start(s), length(l), set_item(this), trust_enoent(true), tid(t) { ob->reads.push_back(&set_item); } void finish(int r) { oc->bh_read_finish(poolid, oid, tid, start, length, bl, r, trust_enoent); // object destructor clears the list if (set_item.is_on_list()) set_item.remove_myself(); } void distrust_enoent() { trust_enoent = false; } }; class C_WriteCommit : public Context { ObjectCacher *oc; int64_t poolid; sobject_t oid; loff_t start; uint64_t length; public: ceph_tid_t tid; C_WriteCommit(ObjectCacher *c, int64_t _poolid, sobject_t o, loff_t s, uint64_t l) : oc(c), poolid(_poolid), oid(o), start(s), length(l), tid(0) {} void finish(int r) { oc->bh_write_commit(poolid, oid, start, length, tid, r); } }; class C_WaitForWrite : public Context { public: C_WaitForWrite(ObjectCacher *oc, uint64_t len, Context *onfinish) : m_oc(oc), m_len(len), m_onfinish(onfinish) {} void finish(int r); private: ObjectCacher *m_oc; uint64_t m_len; Context *m_onfinish; }; void perf_start(); void perf_stop(); ObjectCacher(CephContext *cct_, string name, WritebackHandler& wb, Mutex& l, flush_set_callback_t flush_callback, void *flush_callback_arg, uint64_t max_bytes, uint64_t max_objects, uint64_t max_dirty, uint64_t target_dirty, double max_age, bool block_writes_upfront); ~ObjectCacher(); void start() { flusher_thread.create(); } void stop() { assert(flusher_thread.is_started()); lock.Lock(); // hmm.. watch out for deadlock! flusher_stop = true; flusher_cond.Signal(); lock.Unlock(); flusher_thread.join(); } class C_RetryRead : public Context { ObjectCacher *oc; OSDRead *rd; ObjectSet *oset; Context *onfinish; public: C_RetryRead(ObjectCacher *_oc, OSDRead *r, ObjectSet *os, Context *c) : oc(_oc), rd(r), oset(os), onfinish(c) {} void finish(int r) { if (r < 0) { if (onfinish) onfinish->complete(r); return; } int ret = oc->_readx(rd, oset, onfinish, false); if (ret != 0 && onfinish) { onfinish->complete(ret); } } }; // non-blocking. async. /** * @note total read size must be <= INT_MAX, since * the return value is total bytes read */ int readx(OSDRead *rd, ObjectSet *oset, Context *onfinish); int writex(OSDWrite *wr, ObjectSet *oset, Mutex& wait_on_lock, Context *onfreespace); bool is_cached(ObjectSet *oset, vector& extents, snapid_t snapid); private: // write blocking int _wait_for_write(OSDWrite *wr, uint64_t len, ObjectSet *oset, Mutex& lock, Context *onfreespace); void maybe_wait_for_writeback(uint64_t len); bool _flush_set_finish(C_GatherBuilder *gather, Context *onfinish); public: bool set_is_empty(ObjectSet *oset); bool set_is_cached(ObjectSet *oset); bool set_is_dirty_or_committing(ObjectSet *oset); bool flush_set(ObjectSet *oset, Context *onfinish=0); bool flush_set(ObjectSet *oset, vector& ex, Context *onfinish=0); void flush_all(Context *onfinish=0); void purge_set(ObjectSet *oset); loff_t release_set(ObjectSet *oset); // returns # of bytes not released (ie non-clean) uint64_t release_all(); void discard_set(ObjectSet *oset, vector& ex); /** * Retry any in-flight reads that get -ENOENT instead of marking * them zero, and get rid of any cached -ENOENTs. * After this is called and the cache's lock is unlocked, * any new requests will treat -ENOENT normally. */ void clear_nonexistence(ObjectSet *oset); // cache sizes void set_max_dirty(uint64_t v) { max_dirty = v; } void set_target_dirty(int64_t v) { target_dirty = v; } void set_max_size(int64_t v) { max_size = v; } void set_max_dirty_age(double a) { max_dirty_age.set_from_double(a); } void set_max_objects(int64_t v) { max_objects = v; } // file functions /*** async+caching (non-blocking) file interface ***/ int file_is_cached(ObjectSet *oset, ceph_file_layout *layout, snapid_t snapid, loff_t offset, uint64_t len) { vector extents; Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, extents); return is_cached(oset, extents, snapid); } int file_read(ObjectSet *oset, ceph_file_layout *layout, snapid_t snapid, loff_t offset, uint64_t len, bufferlist *bl, int flags, Context *onfinish) { OSDRead *rd = prepare_read(snapid, bl, flags); Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, rd->extents); return readx(rd, oset, onfinish); } int file_write(ObjectSet *oset, ceph_file_layout *layout, const SnapContext& snapc, loff_t offset, uint64_t len, bufferlist& bl, utime_t mtime, int flags, Mutex& wait_on_lock) { OSDWrite *wr = prepare_write(snapc, bl, mtime, flags); Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, wr->extents); return writex(wr, oset, wait_on_lock, NULL); } bool file_flush(ObjectSet *oset, ceph_file_layout *layout, const SnapContext& snapc, loff_t offset, uint64_t len, Context *onfinish) { vector extents; Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, extents); return flush_set(oset, extents, onfinish); } }; inline ostream& operator<<(ostream& out, ObjectCacher::BufferHead &bh) { out << "bh[ " << &bh << " " << bh.start() << "~" << bh.length() << " " << bh.ob << " (" << bh.bl.length() << ")" << " v " << bh.last_write_tid; if (bh.is_tx()) out << " tx"; if (bh.is_rx()) out << " rx"; if (bh.is_dirty()) out << " dirty"; if (bh.is_clean()) out << " clean"; if (bh.is_zero()) out << " zero"; if (bh.is_missing()) out << " missing"; if (bh.bl.length() > 0) out << " firstbyte=" << (int)bh.bl[0]; if (bh.error) out << " error=" << bh.error; out << "]"; out << " waiters = {"; for (map >::const_iterator it = bh.waitfor_read.begin(); it != bh.waitfor_read.end(); ++it) { out << " " << it->first << "->["; for (list::const_iterator lit = it->second.begin(); lit != it->second.end(); ++lit) { out << *lit << ", "; } out << "]"; } out << "}"; return out; } inline ostream& operator<<(ostream& out, ObjectCacher::ObjectSet &os) { return out << "objectset[" << os.ino << " ts " << os.truncate_seq << "/" << os.truncate_size << " objects " << os.objects.size() << " dirty_or_tx " << os.dirty_or_tx << "]"; } inline ostream& operator<<(ostream& out, ObjectCacher::Object &ob) { out << "object[" << ob.get_soid() << " oset " << ob.oset << dec << " wr " << ob.last_write_tid << "/" << ob.last_commit_tid; if (ob.complete) out << " COMPLETE"; if (!ob.exists) out << " !EXISTS"; out << "]"; return out; } #endif ceph-0.80.11/src/osdc/Filer.h0000664000175100017510000001716112623076744017634 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_FILER_H #define CEPH_FILER_H /*** Filer * * stripe file ranges onto objects. * build list for the objecter or objectcacher. * * also, provide convenience methods that call objecter for you. * * "files" are identified by ino. */ #include "include/types.h" #include "osd/OSDMap.h" #include "Objecter.h" #include "Striper.h" class Context; class Messenger; class OSDMap; /**** Filer interface ***/ class Filer { CephContext *cct; Objecter *objecter; // probes struct Probe { inodeno_t ino; ceph_file_layout layout; snapid_t snapid; uint64_t *psize; utime_t *pmtime; int flags; bool fwd; Context *onfinish; vector probing; uint64_t probing_off, probing_len; map known_size; utime_t max_mtime; set ops; int err; bool found_size; Probe(inodeno_t i, ceph_file_layout &l, snapid_t sn, uint64_t f, uint64_t *e, utime_t *m, int fl, bool fw, Context *c) : ino(i), layout(l), snapid(sn), psize(e), pmtime(m), flags(fl), fwd(fw), onfinish(c), probing_off(f), probing_len(0), err(0), found_size(false) {} }; class C_Probe; void _probe(Probe *p); void _probed(Probe *p, const object_t& oid, uint64_t size, utime_t mtime); public: Filer(const Filer& other); const Filer operator=(const Filer& other); Filer(Objecter *o) : cct(o->cct), objecter(o) {} ~Filer() {} bool is_active() { return objecter->is_active(); // || (oc && oc->is_active()); } /*** async file interface. scatter/gather as needed. ***/ int read(inodeno_t ino, ceph_file_layout *layout, snapid_t snap, uint64_t offset, uint64_t len, bufferlist *bl, // ptr to data int flags, Context *onfinish) { assert(snap); // (until there is a non-NOSNAP write) vector extents; Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents); objecter->sg_read(extents, snap, bl, flags, onfinish); return 0; } int read_trunc(inodeno_t ino, ceph_file_layout *layout, snapid_t snap, uint64_t offset, uint64_t len, bufferlist *bl, // ptr to data int flags, uint64_t truncate_size, __u32 truncate_seq, Context *onfinish) { assert(snap); // (until there is a non-NOSNAP write) vector extents; Striper::file_to_extents(cct, ino, layout, offset, len, truncate_size, extents); objecter->sg_read_trunc(extents, snap, bl, flags, truncate_size, truncate_seq, onfinish); return 0; } int write(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t offset, uint64_t len, bufferlist& bl, utime_t mtime, int flags, Context *onack, Context *oncommit) { vector extents; Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents); objecter->sg_write(extents, snapc, bl, mtime, flags, onack, oncommit); return 0; } int write_trunc(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t offset, uint64_t len, bufferlist& bl, utime_t mtime, int flags, uint64_t truncate_size, __u32 truncate_seq, Context *onack, Context *oncommit) { vector extents; Striper::file_to_extents(cct, ino, layout, offset, len, truncate_size, extents); objecter->sg_write_trunc(extents, snapc, bl, mtime, flags, truncate_size, truncate_seq, onack, oncommit); return 0; } int truncate(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t offset, uint64_t len, __u32 truncate_seq, utime_t mtime, int flags, Context *onack, Context *oncommit) { vector extents; Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents); if (extents.size() == 1) { vector ops(1); ops[0].op.op = CEPH_OSD_OP_TRIMTRUNC; ops[0].op.extent.truncate_seq = truncate_seq; ops[0].op.extent.truncate_size = extents[0].offset; objecter->_modify(extents[0].oid, extents[0].oloc, ops, mtime, snapc, flags, onack, oncommit); } else { C_GatherBuilder gack(cct, onack); C_GatherBuilder gcom(cct, oncommit); for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { vector ops(1); ops[0].op.op = CEPH_OSD_OP_TRIMTRUNC; ops[0].op.extent.truncate_size = p->offset; ops[0].op.extent.truncate_seq = truncate_seq; objecter->_modify(p->oid, p->oloc, ops, mtime, snapc, flags, onack ? gack.new_sub():0, oncommit ? gcom.new_sub():0); } gack.activate(); gcom.activate(); } return 0; } int zero(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t offset, uint64_t len, utime_t mtime, int flags, bool keep_first, Context *onack, Context *oncommit) { vector extents; Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents); if (extents.size() == 1) { if (extents[0].offset == 0 && extents[0].length == layout->fl_object_size && (!keep_first || extents[0].objectno != 0)) objecter->remove(extents[0].oid, extents[0].oloc, snapc, mtime, flags, onack, oncommit); else objecter->zero(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length, snapc, mtime, flags, onack, oncommit); } else { C_GatherBuilder gack(cct, onack); C_GatherBuilder gcom(cct, oncommit); for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { if (p->offset == 0 && p->length == layout->fl_object_size && (!keep_first || p->objectno != 0)) objecter->remove(p->oid, p->oloc, snapc, mtime, flags, onack ? gack.new_sub():0, oncommit ? gcom.new_sub():0); else objecter->zero(p->oid, p->oloc, p->offset, p->length, snapc, mtime, flags, onack ? gack.new_sub():0, oncommit ? gcom.new_sub():0); } gack.activate(); gcom.activate(); } return 0; } int zero(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t offset, uint64_t len, utime_t mtime, int flags, Context *onack, Context *oncommit) { return zero(ino, layout, snapc, offset, len, mtime, flags, false, onack, oncommit); } // purge range of ino.### objects int purge_range(inodeno_t ino, ceph_file_layout *layout, const SnapContext& snapc, uint64_t first_obj, uint64_t num_obj, utime_t mtime, int flags, Context *oncommit); void _do_purge_range(struct PurgeRange *pr, int fin); /* * probe * specify direction, * and whether we stop when we find data, or hole. */ int probe(inodeno_t ino, ceph_file_layout *layout, snapid_t snapid, uint64_t start_from, uint64_t *end, utime_t *mtime, bool fwd, int flags, Context *onfinish); }; #endif ceph-0.80.11/src/osdc/Blinker.h0000664000175100017510000000434712623076744020163 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_BLINKER_H #define CEPH_BLINKER_H class Blinker { public: class Op { int op; static const int LOOKUP = 1; static const int INSERT = 2; static const int REMOVE = 3; static const int CLEAR = 4; Op(int o) : op(o) {} }; class OpLookup : public Op { public: bufferptr key; OpLookup(bufferptr& k) : Op(Op::LOOKUP), key(k) {} }; class OpInsert : public Op { bufferptr key; bufferlist val; OpInsert(bufferptr& k, bufferlist& v) : Op(Op::INSERT), key(k), val(v) {} }; class OpRemove : public Op { public: bufferptr key; OpRemove(bufferptr& k) : Op(Op::REMOVE), key(k) {} }; class OpClear : public Op { public: OpClear() : Op(Op::CLEAR) {} }; private: Objecter *objecter; // in-flight operations. // cache information about tree structure. public: // public interface // simple accessors void lookup(inode_t& inode, bufferptr& key, bufferlist *pval, Context *onfinish); // simple modifiers void insert(inode_t& inode, bufferptr& key, bufferlist& val, Context *onack, Context *onsafe); void remove(inode_t& inode, bufferptr& key, Context *onack, Context *onsafe); void clear(inode_t& inode, Context *onack, Context *onsafe); // these are dangerous: the table may be large. void listkeys(inode_t& inode, list* pkeys, Context *onfinish); void listvals(inode_t& inode, list* pkeys, list* pvals, Context *onfinish); // fetch *at least* key, but also anything else that is convenient. // include lexical bounds for which this is a complete result. // (if *start and *end are empty, it's the entire table) void prefetch(inode_t& inode, bufferptr& key, list* pkeys, list* pvals, bufferptr *start, bufferptr *end, Context *onfinish); }; #endif ceph-0.80.11/src/osdc/Objecter.cc0000664000175100017510000024511312623076744020466 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "Objecter.h" #include "osd/OSDMap.h" #include "Filer.h" #include "mon/MonClient.h" #include "msg/Messenger.h" #include "msg/Message.h" #include "messages/MPing.h" #include "messages/MOSDOp.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDMap.h" #include "messages/MPoolOp.h" #include "messages/MPoolOpReply.h" #include "messages/MGetPoolStats.h" #include "messages/MGetPoolStatsReply.h" #include "messages/MStatfs.h" #include "messages/MStatfsReply.h" #include "messages/MOSDFailure.h" #include "messages/MMonCommand.h" #include "messages/MCommand.h" #include "messages/MCommandReply.h" #include #include "common/config.h" #include "common/perf_counters.h" #include "include/str_list.h" #include "common/errno.h" #define dout_subsys ceph_subsys_objecter #undef dout_prefix #define dout_prefix *_dout << messenger->get_myname() << ".objecter " enum { l_osdc_first = 123200, l_osdc_op_active, l_osdc_op_laggy, l_osdc_op_send, l_osdc_op_send_bytes, l_osdc_op_resend, l_osdc_op_ack, l_osdc_op_commit, l_osdc_op, l_osdc_op_r, l_osdc_op_w, l_osdc_op_rmw, l_osdc_op_pg, l_osdc_osdop_stat, l_osdc_osdop_create, l_osdc_osdop_read, l_osdc_osdop_write, l_osdc_osdop_writefull, l_osdc_osdop_append, l_osdc_osdop_zero, l_osdc_osdop_truncate, l_osdc_osdop_delete, l_osdc_osdop_mapext, l_osdc_osdop_sparse_read, l_osdc_osdop_clonerange, l_osdc_osdop_getxattr, l_osdc_osdop_setxattr, l_osdc_osdop_cmpxattr, l_osdc_osdop_rmxattr, l_osdc_osdop_resetxattrs, l_osdc_osdop_tmap_up, l_osdc_osdop_tmap_put, l_osdc_osdop_tmap_get, l_osdc_osdop_call, l_osdc_osdop_watch, l_osdc_osdop_notify, l_osdc_osdop_src_cmpxattr, l_osdc_osdop_pgls, l_osdc_osdop_pgls_filter, l_osdc_osdop_other, l_osdc_linger_active, l_osdc_linger_send, l_osdc_linger_resend, l_osdc_poolop_active, l_osdc_poolop_send, l_osdc_poolop_resend, l_osdc_poolstat_active, l_osdc_poolstat_send, l_osdc_poolstat_resend, l_osdc_statfs_active, l_osdc_statfs_send, l_osdc_statfs_resend, l_osdc_command_active, l_osdc_command_send, l_osdc_command_resend, l_osdc_map_epoch, l_osdc_map_full, l_osdc_map_inc, l_osdc_osd_sessions, l_osdc_osd_session_open, l_osdc_osd_session_close, l_osdc_osd_laggy, l_osdc_last, }; // config obs ---------------------------- static const char *config_keys[] = { "crush_location", NULL }; const char** Objecter::get_tracked_conf_keys() const { return config_keys; } void Objecter::handle_conf_change(const struct md_config_t *conf, const std::set &changed) { if (changed.count("crush_location")) { crush_location.clear(); vector lvec; get_str_vec(cct->_conf->crush_location, ";, \t", lvec); int r = CrushWrapper::parse_loc_multimap(lvec, &crush_location); if (r < 0) { lderr(cct) << "warning: crush_location '" << cct->_conf->crush_location << "' does not parse" << dendl; } } } // messages ------------------------------ void Objecter::init_unlocked() { assert(!initialized); if (!logger) { PerfCountersBuilder pcb(cct, "objecter", l_osdc_first, l_osdc_last); pcb.add_u64(l_osdc_op_active, "op_active"); pcb.add_u64(l_osdc_op_laggy, "op_laggy"); pcb.add_u64_counter(l_osdc_op_send, "op_send"); pcb.add_u64_counter(l_osdc_op_send_bytes, "op_send_bytes"); pcb.add_u64_counter(l_osdc_op_resend, "op_resend"); pcb.add_u64_counter(l_osdc_op_ack, "op_ack"); pcb.add_u64_counter(l_osdc_op_commit, "op_commit"); pcb.add_u64_counter(l_osdc_op, "op"); pcb.add_u64_counter(l_osdc_op_r, "op_r"); pcb.add_u64_counter(l_osdc_op_w, "op_w"); pcb.add_u64_counter(l_osdc_op_rmw, "op_rmw"); pcb.add_u64_counter(l_osdc_op_pg, "op_pg"); pcb.add_u64_counter(l_osdc_osdop_stat, "osdop_stat"); pcb.add_u64_counter(l_osdc_osdop_create, "osdop_create"); pcb.add_u64_counter(l_osdc_osdop_read, "osdop_read"); pcb.add_u64_counter(l_osdc_osdop_write, "osdop_write"); pcb.add_u64_counter(l_osdc_osdop_writefull, "osdop_writefull"); pcb.add_u64_counter(l_osdc_osdop_append, "osdop_append"); pcb.add_u64_counter(l_osdc_osdop_zero, "osdop_zero"); pcb.add_u64_counter(l_osdc_osdop_truncate, "osdop_truncate"); pcb.add_u64_counter(l_osdc_osdop_delete, "osdop_delete"); pcb.add_u64_counter(l_osdc_osdop_mapext, "osdop_mapext"); pcb.add_u64_counter(l_osdc_osdop_sparse_read, "osdop_sparse_read"); pcb.add_u64_counter(l_osdc_osdop_clonerange, "osdop_clonerange"); pcb.add_u64_counter(l_osdc_osdop_getxattr, "osdop_getxattr"); pcb.add_u64_counter(l_osdc_osdop_setxattr, "osdop_setxattr"); pcb.add_u64_counter(l_osdc_osdop_cmpxattr, "osdop_cmpxattr"); pcb.add_u64_counter(l_osdc_osdop_rmxattr, "osdop_rmxattr"); pcb.add_u64_counter(l_osdc_osdop_resetxattrs, "osdop_resetxattrs"); pcb.add_u64_counter(l_osdc_osdop_tmap_up, "osdop_tmap_up"); pcb.add_u64_counter(l_osdc_osdop_tmap_put, "osdop_tmap_put"); pcb.add_u64_counter(l_osdc_osdop_tmap_get, "osdop_tmap_get"); pcb.add_u64_counter(l_osdc_osdop_call, "osdop_call"); pcb.add_u64_counter(l_osdc_osdop_watch, "osdop_watch"); pcb.add_u64_counter(l_osdc_osdop_notify, "osdop_notify"); pcb.add_u64_counter(l_osdc_osdop_src_cmpxattr, "osdop_src_cmpxattr"); pcb.add_u64_counter(l_osdc_osdop_pgls, "osdop_pgls"); pcb.add_u64_counter(l_osdc_osdop_pgls_filter, "osdop_pgls_filter"); pcb.add_u64_counter(l_osdc_osdop_other, "osdop_other"); pcb.add_u64(l_osdc_linger_active, "linger_active"); pcb.add_u64_counter(l_osdc_linger_send, "linger_send"); pcb.add_u64_counter(l_osdc_linger_resend, "linger_resend"); pcb.add_u64(l_osdc_poolop_active, "poolop_active"); pcb.add_u64_counter(l_osdc_poolop_send, "poolop_send"); pcb.add_u64_counter(l_osdc_poolop_resend, "poolop_resend"); pcb.add_u64(l_osdc_poolstat_active, "poolstat_active"); pcb.add_u64_counter(l_osdc_poolstat_send, "poolstat_send"); pcb.add_u64_counter(l_osdc_poolstat_resend, "poolstat_resend"); pcb.add_u64(l_osdc_statfs_active, "statfs_active"); pcb.add_u64_counter(l_osdc_statfs_send, "statfs_send"); pcb.add_u64_counter(l_osdc_statfs_resend, "statfs_resend"); pcb.add_u64(l_osdc_command_active, "command_active"); pcb.add_u64_counter(l_osdc_command_send, "command_send"); pcb.add_u64_counter(l_osdc_command_resend, "command_resend"); pcb.add_u64(l_osdc_map_epoch, "map_epoch"); pcb.add_u64_counter(l_osdc_map_full, "map_full"); pcb.add_u64_counter(l_osdc_map_inc, "map_inc"); pcb.add_u64(l_osdc_osd_sessions, "osd_sessions"); // open sessions pcb.add_u64_counter(l_osdc_osd_session_open, "osd_session_open"); pcb.add_u64_counter(l_osdc_osd_session_close, "osd_session_close"); pcb.add_u64(l_osdc_osd_laggy, "osd_laggy"); logger = pcb.create_perf_counters(); cct->get_perfcounters_collection()->add(logger); } m_request_state_hook = new RequestStateHook(this); AdminSocket* admin_socket = cct->get_admin_socket(); int ret = admin_socket->register_command("objecter_requests", "objecter_requests", m_request_state_hook, "show in-progress osd requests"); if (ret < 0) { lderr(cct) << "error registering admin socket command: " << cpp_strerror(ret) << dendl; } } void Objecter::init_locked() { assert(client_lock.is_locked()); assert(!initialized); schedule_tick(); if (osdmap->get_epoch() == 0) maybe_request_map(); initialized = true; } void Objecter::shutdown_locked() { assert(client_lock.is_locked()); assert(initialized); initialized = false; map::iterator p; while (!osd_sessions.empty()) { p = osd_sessions.begin(); close_session(p->second); } if (tick_event) { timer.cancel_event(tick_event); tick_event = NULL; } } void Objecter::shutdown_unlocked() { if (m_request_state_hook) { AdminSocket* admin_socket = cct->get_admin_socket(); admin_socket->unregister_command("objecter_requests"); delete m_request_state_hook; m_request_state_hook = NULL; } if (logger) { cct->get_perfcounters_collection()->remove(logger); delete logger; logger = NULL; } } void Objecter::send_linger(LingerOp *info) { ldout(cct, 15) << "send_linger " << info->linger_id << dendl; vector opv = info->ops; // need to pass a copy to ops Context *onack = (!info->registered && info->on_reg_ack) ? new C_Linger_Ack(this, info) : NULL; Context *oncommit = new C_Linger_Commit(this, info); Op *o = new Op(info->target.base_oid, info->target.base_oloc, opv, info->target.flags | CEPH_OSD_FLAG_READ, onack, oncommit, info->pobjver); o->snapid = info->snap; o->snapc = info->snapc; o->mtime = info->mtime; // do not resend this; we will send a new op to reregister o->should_resend = false; if (info->session) { int r = recalc_op_target(o); if (r == RECALC_OP_TARGET_POOL_DNE) { _send_linger_map_check(info); } } if (info->register_tid) { // repeat send. cancel old registeration op, if any. if (ops.count(info->register_tid)) { Op *o = ops[info->register_tid]; op_cancel_map_check(o); cancel_linger_op(o); } info->register_tid = _op_submit(o); } else { // first send // populate info->pgid and info->acting so we // don't resend the linger op on the next osdmap update recalc_linger_op_target(info); info->register_tid = op_submit(o); } OSDSession *s = o->session; if (info->session != s) { info->session_item.remove_myself(); info->session = s; if (info->session) s->linger_ops.push_back(&info->session_item); } logger->inc(l_osdc_linger_send); } void Objecter::_linger_ack(LingerOp *info, int r) { ldout(cct, 10) << "_linger_ack " << info->linger_id << dendl; if (info->on_reg_ack) { info->on_reg_ack->complete(r); info->on_reg_ack = NULL; } } void Objecter::_linger_commit(LingerOp *info, int r) { ldout(cct, 10) << "_linger_commit " << info->linger_id << dendl; if (info->on_reg_commit) { info->on_reg_commit->complete(r); info->on_reg_commit = NULL; } // only tell the user the first time we do this info->registered = true; info->pobjver = NULL; } void Objecter::unregister_linger(uint64_t linger_id) { map::iterator iter = linger_ops.find(linger_id); if (iter != linger_ops.end()) { LingerOp *info = iter->second; info->session_item.remove_myself(); linger_ops.erase(iter); info->put(); logger->set(l_osdc_linger_active, linger_ops.size()); } } ceph_tid_t Objecter::linger_mutate(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, const SnapContext& snapc, utime_t mtime, bufferlist& inbl, int flags, Context *onack, Context *oncommit, version_t *objver) { LingerOp *info = new LingerOp; info->target.base_oid = oid; info->target.base_oloc = oloc; if (info->target.base_oloc.key == oid) info->target.base_oloc.key.clear(); info->snapc = snapc; info->mtime = mtime; info->target.flags = flags | CEPH_OSD_FLAG_WRITE; info->ops = op.ops; info->inbl = inbl; info->poutbl = NULL; info->pobjver = objver; info->on_reg_ack = onack; info->on_reg_commit = oncommit; info->linger_id = ++max_linger_id; linger_ops[info->linger_id] = info; logger->set(l_osdc_linger_active, linger_ops.size()); send_linger(info); return info->linger_id; } ceph_tid_t Objecter::linger_read(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, snapid_t snap, bufferlist& inbl, bufferlist *poutbl, int flags, Context *onfinish, version_t *objver) { LingerOp *info = new LingerOp; info->target.base_oid = oid; info->target.base_oloc = oloc; if (info->target.base_oloc.key == oid) info->target.base_oloc.key.clear(); info->snap = snap; info->target.flags = flags; info->ops = op.ops; info->inbl = inbl; info->poutbl = poutbl; info->pobjver = objver; info->on_reg_commit = onfinish; info->linger_id = ++max_linger_id; linger_ops[info->linger_id] = info; logger->set(l_osdc_linger_active, linger_ops.size()); send_linger(info); return info->linger_id; } void Objecter::dispatch(Message *m) { switch (m->get_type()) { case CEPH_MSG_OSD_OPREPLY: handle_osd_op_reply(static_cast(m)); break; case CEPH_MSG_OSD_MAP: handle_osd_map(static_cast(m)); break; case MSG_GETPOOLSTATSREPLY: handle_get_pool_stats_reply(static_cast(m)); break; case CEPH_MSG_STATFS_REPLY: handle_fs_stats_reply(static_cast(m)); break; case CEPH_MSG_POOLOP_REPLY: handle_pool_op_reply(static_cast(m)); break; case MSG_COMMAND_REPLY: handle_command_reply(static_cast(m)); break; default: ldout(cct, 0) << "don't know message type " << m->get_type() << dendl; assert(0); } } void Objecter::scan_requests(bool force_resend, bool force_resend_writes, map& need_resend, list& need_resend_linger, map& need_resend_command) { // check for changed linger mappings (_before_ regular ops) map::iterator lp = linger_ops.begin(); while (lp != linger_ops.end()) { LingerOp *op = lp->second; ++lp; // check_linger_pool_dne() may touch linger_ops; prevent iterator invalidation ldout(cct, 10) << " checking linger op " << op->linger_id << dendl; int r = recalc_linger_op_target(op); switch (r) { case RECALC_OP_TARGET_NO_ACTION: if (!force_resend && !force_resend_writes) break; // -- fall-thru -- case RECALC_OP_TARGET_NEED_RESEND: need_resend_linger.push_back(op); linger_cancel_map_check(op); break; case RECALC_OP_TARGET_POOL_DNE: check_linger_pool_dne(op); break; } } // check for changed request mappings map::iterator p = ops.begin(); while (p != ops.end()) { Op *op = p->second; ++p; // check_op_pool_dne() may touch ops; prevent iterator invalidation ldout(cct, 10) << " checking op " << op->tid << dendl; int r = recalc_op_target(op); switch (r) { case RECALC_OP_TARGET_NO_ACTION: if (!force_resend && (!force_resend_writes || !(op->target.flags & CEPH_OSD_FLAG_WRITE))) break; // -- fall-thru -- case RECALC_OP_TARGET_NEED_RESEND: need_resend[op->tid] = op; op_cancel_map_check(op); break; case RECALC_OP_TARGET_POOL_DNE: check_op_pool_dne(op); break; } } // commands map::iterator cp = command_ops.begin(); while (cp != command_ops.end()) { CommandOp *c = cp->second; ++cp; ldout(cct, 10) << " checking command " << c->tid << dendl; int r = recalc_command_target(c); switch (r) { case RECALC_OP_TARGET_NO_ACTION: // resend if skipped map; otherwise do nothing. if (!force_resend && !force_resend_writes) break; // -- fall-thru -- case RECALC_OP_TARGET_NEED_RESEND: need_resend_command[c->tid] = c; command_cancel_map_check(c); break; case RECALC_OP_TARGET_POOL_DNE: case RECALC_OP_TARGET_OSD_DNE: case RECALC_OP_TARGET_OSD_DOWN: check_command_map_dne(c); break; } } } void Objecter::handle_osd_map(MOSDMap *m) { assert(client_lock.is_locked()); assert(initialized); assert(osdmap); if (m->fsid != monc->get_fsid()) { ldout(cct, 0) << "handle_osd_map fsid " << m->fsid << " != " << monc->get_fsid() << dendl; m->put(); return; } bool was_pauserd = osdmap->test_flag(CEPH_OSDMAP_PAUSERD); bool was_full = osdmap_full_flag(); bool was_pausewr = osdmap->test_flag(CEPH_OSDMAP_PAUSEWR) || was_full; list need_resend_linger; map need_resend; map need_resend_command; if (m->get_last() <= osdmap->get_epoch()) { ldout(cct, 3) << "handle_osd_map ignoring epochs [" << m->get_first() << "," << m->get_last() << "] <= " << osdmap->get_epoch() << dendl; } else { ldout(cct, 3) << "handle_osd_map got epochs [" << m->get_first() << "," << m->get_last() << "] > " << osdmap->get_epoch() << dendl; if (osdmap->get_epoch()) { bool skipped_map = false; // we want incrementals for (epoch_t e = osdmap->get_epoch() + 1; e <= m->get_last(); e++) { if (osdmap->get_epoch() == e-1 && m->incremental_maps.count(e)) { ldout(cct, 3) << "handle_osd_map decoding incremental epoch " << e << dendl; OSDMap::Incremental inc(m->incremental_maps[e]); osdmap->apply_incremental(inc); logger->inc(l_osdc_map_inc); } else if (m->maps.count(e)) { ldout(cct, 3) << "handle_osd_map decoding full epoch " << e << dendl; osdmap->decode(m->maps[e]); logger->inc(l_osdc_map_full); } else { if (e >= m->get_oldest()) { ldout(cct, 3) << "handle_osd_map requesting missing epoch " << osdmap->get_epoch()+1 << dendl; maybe_request_map(); break; } ldout(cct, 3) << "handle_osd_map missing epoch " << osdmap->get_epoch()+1 << ", jumping to " << m->get_oldest() << dendl; e = m->get_oldest() - 1; skipped_map = true; continue; } logger->set(l_osdc_map_epoch, osdmap->get_epoch()); was_full = was_full || osdmap_full_flag(); scan_requests(skipped_map, was_full, need_resend, need_resend_linger, need_resend_command); // osd addr changes? for (map::iterator p = osd_sessions.begin(); p != osd_sessions.end(); ) { OSDSession *s = p->second; ++p; if (osdmap->is_up(s->osd)) { if (s->con && s->con->get_peer_addr() != osdmap->get_inst(s->osd).addr) close_session(s); } else { close_session(s); } } assert(e == osdmap->get_epoch()); } } else { // first map. we want the full thing. if (m->maps.count(m->get_last())) { ldout(cct, 3) << "handle_osd_map decoding full epoch " << m->get_last() << dendl; osdmap->decode(m->maps[m->get_last()]); scan_requests(false, false, need_resend, need_resend_linger, need_resend_command); } else { ldout(cct, 3) << "handle_osd_map hmm, i want a full map, requesting" << dendl; monc->sub_want("osdmap", 0, CEPH_SUBSCRIBE_ONETIME); monc->renew_subs(); } } } bool pauserd = osdmap->test_flag(CEPH_OSDMAP_PAUSERD); bool pausewr = osdmap->test_flag(CEPH_OSDMAP_PAUSEWR) || osdmap_full_flag(); // was/is paused? if (was_pauserd || was_pausewr || pauserd || pausewr) maybe_request_map(); // resend requests for (map::iterator p = need_resend.begin(); p != need_resend.end(); ++p) { Op *op = p->second; if (op->should_resend) { if (op->session && !op->target.paused) { logger->inc(l_osdc_op_resend); send_op(op); } } else { cancel_linger_op(op); } } for (list::iterator p = need_resend_linger.begin(); p != need_resend_linger.end(); ++p) { LingerOp *op = *p; if (op->session) { logger->inc(l_osdc_linger_resend); send_linger(op); } } for (map::iterator p = need_resend_command.begin(); p != need_resend_command.end(); ++p) { CommandOp *c = p->second; if (c->session) { _send_command(c); } } dump_active(); // finish any Contexts that were waiting on a map update map > >::iterator p = waiting_for_map.begin(); while (p != waiting_for_map.end() && p->first <= osdmap->get_epoch()) { //go through the list and call the onfinish methods for (list >::iterator i = p->second.begin(); i != p->second.end(); ++i) { i->first->complete(i->second); } waiting_for_map.erase(p++); } m->put(); monc->sub_got("osdmap", osdmap->get_epoch()); if (!waiting_for_map.empty()) maybe_request_map(); } // op pool check void Objecter::C_Op_Map_Latest::finish(int r) { if (r == -EAGAIN || r == -ECANCELED) return; lgeneric_subdout(objecter->cct, objecter, 10) << "op_map_latest r=" << r << " tid=" << tid << " latest " << latest << dendl; Mutex::Locker l(objecter->client_lock); map::iterator iter = objecter->check_latest_map_ops.find(tid); if (iter == objecter->check_latest_map_ops.end()) { lgeneric_subdout(objecter->cct, objecter, 10) << "op_map_latest op " << tid << " not found" << dendl; return; } Op *op = iter->second; objecter->check_latest_map_ops.erase(iter); lgeneric_subdout(objecter->cct, objecter, 20) << "op_map_latest op " << op << dendl; if (op->map_dne_bound == 0) op->map_dne_bound = latest; objecter->check_op_pool_dne(op); } void Objecter::check_op_pool_dne(Op *op) { ldout(cct, 10) << "check_op_pool_dne tid " << op->tid << " current " << osdmap->get_epoch() << " map_dne_bound " << op->map_dne_bound << dendl; if (op->map_dne_bound > 0) { if (osdmap->get_epoch() >= op->map_dne_bound) { // we had a new enough map ldout(cct, 10) << "check_op_pool_dne tid " << op->tid << " concluding pool " << op->target.base_pgid.pool() << " dne" << dendl; if (op->onack) { op->onack->complete(-ENOENT); } if (op->oncommit) { op->oncommit->complete(-ENOENT); } op->session_item.remove_myself(); ops.erase(op->tid); delete op; } } else { _send_op_map_check(op); } } void Objecter::_send_op_map_check(Op *op) { assert(client_lock.is_locked()); // ask the monitor if (check_latest_map_ops.count(op->tid) == 0) { check_latest_map_ops[op->tid] = op; C_Op_Map_Latest *c = new C_Op_Map_Latest(this, op->tid); monc->get_version("osdmap", &c->latest, NULL, c); } } void Objecter::op_cancel_map_check(Op *op) { assert(client_lock.is_locked()); map::iterator iter = check_latest_map_ops.find(op->tid); if (iter != check_latest_map_ops.end()) { check_latest_map_ops.erase(iter); } } // linger pool check void Objecter::C_Linger_Map_Latest::finish(int r) { if (r == -EAGAIN || r == -ECANCELED) { // ignore callback; we will retry in resend_mon_ops() return; } Mutex::Locker l(objecter->client_lock); map::iterator iter = objecter->check_latest_map_lingers.find(linger_id); if (iter == objecter->check_latest_map_lingers.end()) { return; } LingerOp *op = iter->second; objecter->check_latest_map_lingers.erase(iter); op->put(); if (op->map_dne_bound == 0) op->map_dne_bound = latest; objecter->check_linger_pool_dne(op); } void Objecter::check_linger_pool_dne(LingerOp *op) { ldout(cct, 10) << "check_linger_pool_dne linger_id " << op->linger_id << " current " << osdmap->get_epoch() << " map_dne_bound " << op->map_dne_bound << dendl; if (op->map_dne_bound > 0) { if (osdmap->get_epoch() >= op->map_dne_bound) { if (op->on_reg_ack) { op->on_reg_ack->complete(-ENOENT); } if (op->on_reg_commit) { op->on_reg_commit->complete(-ENOENT); } unregister_linger(op->linger_id); } } else { _send_linger_map_check(op); } } void Objecter::_send_linger_map_check(LingerOp *op) { // ask the monitor if (check_latest_map_lingers.count(op->linger_id) == 0) { op->get(); check_latest_map_lingers[op->linger_id] = op; C_Linger_Map_Latest *c = new C_Linger_Map_Latest(this, op->linger_id); monc->get_version("osdmap", &c->latest, NULL, c); } } void Objecter::linger_cancel_map_check(LingerOp *op) { map::iterator iter = check_latest_map_lingers.find(op->linger_id); if (iter != check_latest_map_lingers.end()) { LingerOp *op = iter->second; op->put(); check_latest_map_lingers.erase(iter); } } // command pool check void Objecter::C_Command_Map_Latest::finish(int r) { if (r == -EAGAIN || r == -ECANCELED) { // ignore callback; we will retry in resend_mon_ops() return; } Mutex::Locker l(objecter->client_lock); map::iterator iter = objecter->check_latest_map_commands.find(tid); if (iter == objecter->check_latest_map_commands.end()) { return; } CommandOp *c = iter->second; objecter->check_latest_map_commands.erase(iter); c->put(); if (c->map_dne_bound == 0) c->map_dne_bound = latest; objecter->check_command_map_dne(c); } void Objecter::check_command_map_dne(CommandOp *c) { ldout(cct, 10) << "check_command_map_dne tid " << c->tid << " current " << osdmap->get_epoch() << " map_dne_bound " << c->map_dne_bound << dendl; if (c->map_dne_bound > 0) { if (osdmap->get_epoch() >= c->map_dne_bound) { _finish_command(c, c->map_check_error, c->map_check_error_str); } } else { _send_command_map_check(c); } } void Objecter::_send_command_map_check(CommandOp *c) { // ask the monitor if (check_latest_map_commands.count(c->tid) == 0) { c->get(); check_latest_map_commands[c->tid] = c; C_Command_Map_Latest *f = new C_Command_Map_Latest(this, c->tid); monc->get_version("osdmap", &f->latest, NULL, f); } } void Objecter::command_cancel_map_check(CommandOp *c) { map::iterator iter = check_latest_map_commands.find(c->tid); if (iter != check_latest_map_commands.end()) { CommandOp *c = iter->second; c->put(); check_latest_map_commands.erase(iter); } } Objecter::OSDSession *Objecter::get_session(int osd) { map::iterator p = osd_sessions.find(osd); if (p != osd_sessions.end()) return p->second; OSDSession *s = new OSDSession(osd); osd_sessions[osd] = s; s->con = messenger->get_connection(osdmap->get_inst(osd)); logger->inc(l_osdc_osd_session_open); logger->inc(l_osdc_osd_sessions, osd_sessions.size()); return s; } void Objecter::reopen_session(OSDSession *s) { entity_inst_t inst = osdmap->get_inst(s->osd); ldout(cct, 10) << "reopen_session osd." << s->osd << " session, addr now " << inst << dendl; if (s->con) { messenger->mark_down(s->con); logger->inc(l_osdc_osd_session_close); } s->con = messenger->get_connection(inst); s->incarnation++; logger->inc(l_osdc_osd_session_open); } void Objecter::close_session(OSDSession *s) { ldout(cct, 10) << "close_session for osd." << s->osd << dendl; if (s->con) { messenger->mark_down(s->con); logger->inc(l_osdc_osd_session_close); } s->ops.clear(); s->linger_ops.clear(); s->command_ops.clear(); osd_sessions.erase(s->osd); delete s; logger->set(l_osdc_osd_sessions, osd_sessions.size()); } void Objecter::wait_for_osd_map() { if (osdmap->get_epoch()) return; Mutex lock(""); Cond cond; bool done; lock.Lock(); C_SafeCond *context = new C_SafeCond(&lock, &cond, &done, NULL); waiting_for_map[0].push_back(pair(context, 0)); while (!done) cond.Wait(lock); lock.Unlock(); } struct C_Objecter_GetVersion : public Context { Objecter *objecter; uint64_t oldest, newest; Context *fin; C_Objecter_GetVersion(Objecter *o, Context *c) : objecter(o), oldest(0), newest(0), fin(c) {} void finish(int r) { if (r >= 0) objecter->_get_latest_version(oldest, newest, fin); else if (r == -EAGAIN) { // try again as instructed objecter->wait_for_latest_osdmap(fin); } else { // it doesn't return any other error codes! assert(0); } } }; void Objecter::wait_for_latest_osdmap(Context *fin) { ldout(cct, 10) << __func__ << dendl; C_Objecter_GetVersion *c = new C_Objecter_GetVersion(this, fin); monc->get_version("osdmap", &c->newest, &c->oldest, c); } void Objecter::_get_latest_version(epoch_t oldest, epoch_t newest, Context *fin) { if (osdmap->get_epoch() >= newest) { ldout(cct, 10) << __func__ << " latest " << newest << ", have it" << dendl; if (fin) fin->complete(0); return; } ldout(cct, 10) << __func__ << " latest " << newest << ", waiting" << dendl; wait_for_new_map(fin, newest, 0); } void Objecter::maybe_request_map() { int flag = 0; if (osdmap_full_flag()) { ldout(cct, 10) << "maybe_request_map subscribing (continuous) to next osd map (FULL flag is set)" << dendl; } else { ldout(cct, 10) << "maybe_request_map subscribing (onetime) to next osd map" << dendl; flag = CEPH_SUBSCRIBE_ONETIME; } epoch_t epoch = osdmap->get_epoch() ? osdmap->get_epoch()+1 : 0; if (monc->sub_want("osdmap", epoch, flag)) monc->renew_subs(); } void Objecter::wait_for_new_map(Context *c, epoch_t epoch, int err) { waiting_for_map[epoch].push_back(pair(c, err)); maybe_request_map(); } void Objecter::kick_requests(OSDSession *session) { ldout(cct, 10) << "kick_requests for osd." << session->osd << dendl; // resend ops map resend; // resend in tid order for (xlist::iterator p = session->ops.begin(); !p.end();) { Op *op = *p; ++p; logger->inc(l_osdc_op_resend); if (op->should_resend) { if (!op->target.paused) resend[op->tid] = op; } else { cancel_linger_op(op); } } while (!resend.empty()) { send_op(resend.begin()->second); resend.erase(resend.begin()); } // resend lingers map lresend; // resend in order for (xlist::iterator j = session->linger_ops.begin(); !j.end(); ++j) { logger->inc(l_osdc_linger_resend); lresend[(*j)->linger_id] = *j; } while (!lresend.empty()) { send_linger(lresend.begin()->second); lresend.erase(lresend.begin()); } // resend commands map cresend; // resend in order for (xlist::iterator k = session->command_ops.begin(); !k.end(); ++k) { logger->inc(l_osdc_command_resend); cresend[(*k)->tid] = *k; } while (!cresend.empty()) { _send_command(cresend.begin()->second); cresend.erase(cresend.begin()); } } void Objecter::schedule_tick() { assert(tick_event == NULL); tick_event = new C_Tick(this); timer.add_event_after(cct->_conf->objecter_tick_interval, tick_event); } void Objecter::tick() { ldout(cct, 10) << "tick" << dendl; assert(client_lock.is_locked()); assert(initialized); // we are only called by C_Tick assert(tick_event); tick_event = NULL; set toping; // look for laggy requests utime_t cutoff = ceph_clock_now(cct); cutoff -= cct->_conf->objecter_timeout; // timeout unsigned laggy_ops = 0; for (map::iterator p = ops.begin(); p != ops.end(); ++p) { Op *op = p->second; if (op->session && op->stamp < cutoff) { ldout(cct, 2) << " tid " << p->first << " on osd." << op->session->osd << " is laggy" << dendl; toping.insert(op->session); ++laggy_ops; } } for (map::iterator p = linger_ops.begin(); p != linger_ops.end(); ++p) { LingerOp *op = p->second; if (op->session) { ldout(cct, 10) << " pinging osd that serves lingering tid " << p->first << " (osd." << op->session->osd << ")" << dendl; toping.insert(op->session); } else { ldout(cct, 10) << " lingering tid " << p->first << " does not have session" << dendl; } } for (map::iterator p = command_ops.begin(); p != command_ops.end(); ++p) { CommandOp *op = p->second; if (op->session) { ldout(cct, 10) << " pinging osd that serves command tid " << p->first << " (osd." << op->session->osd << ")" << dendl; toping.insert(op->session); } else { ldout(cct, 10) << " command tid " << p->first << " does not have session" << dendl; } } logger->set(l_osdc_op_laggy, laggy_ops); logger->set(l_osdc_osd_laggy, toping.size()); if (num_homeless_ops || !toping.empty()) maybe_request_map(); if (!toping.empty()) { // send a ping to these osds, to ensure we detect any session resets // (osd reply message policy is lossy) for (set::iterator i = toping.begin(); i != toping.end(); ++i) { messenger->send_message(new MPing, (*i)->con); } } // reschedule schedule_tick(); } void Objecter::resend_mon_ops() { assert(client_lock.is_locked()); ldout(cct, 10) << "resend_mon_ops" << dendl; for (map::iterator p = poolstat_ops.begin(); p!=poolstat_ops.end(); ++p) { poolstat_submit(p->second); logger->inc(l_osdc_poolstat_resend); } for (map::iterator p = statfs_ops.begin(); p!=statfs_ops.end(); ++p) { fs_stats_submit(p->second); logger->inc(l_osdc_statfs_resend); } for (map::iterator p = pool_ops.begin(); p!=pool_ops.end(); ++p) { _pool_op_submit(p->second); logger->inc(l_osdc_poolop_resend); } for (map::iterator p = check_latest_map_ops.begin(); p != check_latest_map_ops.end(); ++p) { C_Op_Map_Latest *c = new C_Op_Map_Latest(this, p->second->tid); monc->get_version("osdmap", &c->latest, NULL, c); } for (map::iterator p = check_latest_map_lingers.begin(); p != check_latest_map_lingers.end(); ++p) { C_Linger_Map_Latest *c = new C_Linger_Map_Latest(this, p->second->linger_id); monc->get_version("osdmap", &c->latest, NULL, c); } for (map::iterator p = check_latest_map_commands.begin(); p != check_latest_map_commands.end(); ++p) { C_Command_Map_Latest *c = new C_Command_Map_Latest(this, p->second->tid); monc->get_version("osdmap", &c->latest, NULL, c); } } // read | write --------------------------- class C_CancelOp : public Context { Objecter::Op *op; Objecter *objecter; public: C_CancelOp(Objecter::Op *op, Objecter *objecter) : op(op), objecter(objecter) {} void finish(int r) { // note that objecter lock == timer lock, and is already held objecter->op_cancel(op->tid, -ETIMEDOUT); } }; ceph_tid_t Objecter::op_submit(Op *op, int *ctx_budget) { assert(client_lock.is_locked()); assert(initialized); assert(op->ops.size() == op->out_bl.size()); assert(op->ops.size() == op->out_rval.size()); assert(op->ops.size() == op->out_handler.size()); if (osd_timeout > 0) { op->ontimeout = new C_CancelOp(op, this); timer.add_event_after(osd_timeout, op->ontimeout); } // throttle. before we look at any state, because // take_op_budget() may drop our lock while it blocks. if (!op->ctx_budgeted || (ctx_budget && (*ctx_budget == -1))) { int op_budget = take_op_budget(op); // take and pass out the budget for the first OP // in the context session if (ctx_budget && (*ctx_budget == -1)) { *ctx_budget = op_budget; } } return _op_submit(op); } ceph_tid_t Objecter::_op_submit(Op *op) { // pick tid if we haven't got one yet if (op->tid == ceph_tid_t(0)) { ceph_tid_t mytid = ++last_tid; op->tid = mytid; } assert(client_inc >= 0); // pick target num_homeless_ops++; // initially; recalc_op_target() will decrement if it finds a target int r = recalc_op_target(op); bool check_for_latest_map = (r == RECALC_OP_TARGET_POOL_DNE); // add to gather set(s) if (op->onack) { ++num_unacked; } else { ldout(cct, 20) << " note: not requesting ack" << dendl; } if (op->oncommit) { ++num_uncommitted; } else { ldout(cct, 20) << " note: not requesting commit" << dendl; } ops[op->tid] = op; logger->set(l_osdc_op_active, ops.size()); logger->inc(l_osdc_op); if ((op->target.flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) == (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) logger->inc(l_osdc_op_rmw); else if (op->target.flags & CEPH_OSD_FLAG_WRITE) logger->inc(l_osdc_op_w); else if (op->target.flags & CEPH_OSD_FLAG_READ) logger->inc(l_osdc_op_r); if (op->target.flags & CEPH_OSD_FLAG_PGOP) logger->inc(l_osdc_op_pg); for (vector::iterator p = op->ops.begin(); p != op->ops.end(); ++p) { int code = l_osdc_osdop_other; switch (p->op.op) { case CEPH_OSD_OP_STAT: code = l_osdc_osdop_stat; break; case CEPH_OSD_OP_CREATE: code = l_osdc_osdop_create; break; case CEPH_OSD_OP_READ: code = l_osdc_osdop_read; break; case CEPH_OSD_OP_WRITE: code = l_osdc_osdop_write; break; case CEPH_OSD_OP_WRITEFULL: code = l_osdc_osdop_writefull; break; case CEPH_OSD_OP_APPEND: code = l_osdc_osdop_append; break; case CEPH_OSD_OP_ZERO: code = l_osdc_osdop_zero; break; case CEPH_OSD_OP_TRUNCATE: code = l_osdc_osdop_truncate; break; case CEPH_OSD_OP_DELETE: code = l_osdc_osdop_delete; break; case CEPH_OSD_OP_MAPEXT: code = l_osdc_osdop_mapext; break; case CEPH_OSD_OP_SPARSE_READ: code = l_osdc_osdop_sparse_read; break; case CEPH_OSD_OP_CLONERANGE: code = l_osdc_osdop_clonerange; break; case CEPH_OSD_OP_GETXATTR: code = l_osdc_osdop_getxattr; break; case CEPH_OSD_OP_SETXATTR: code = l_osdc_osdop_setxattr; break; case CEPH_OSD_OP_CMPXATTR: code = l_osdc_osdop_cmpxattr; break; case CEPH_OSD_OP_RMXATTR: code = l_osdc_osdop_rmxattr; break; case CEPH_OSD_OP_RESETXATTRS: code = l_osdc_osdop_resetxattrs; break; case CEPH_OSD_OP_TMAPUP: code = l_osdc_osdop_tmap_up; break; case CEPH_OSD_OP_TMAPPUT: code = l_osdc_osdop_tmap_put; break; case CEPH_OSD_OP_TMAPGET: code = l_osdc_osdop_tmap_get; break; case CEPH_OSD_OP_CALL: code = l_osdc_osdop_call; break; case CEPH_OSD_OP_WATCH: code = l_osdc_osdop_watch; break; case CEPH_OSD_OP_NOTIFY: code = l_osdc_osdop_notify; break; case CEPH_OSD_OP_SRC_CMPXATTR: code = l_osdc_osdop_src_cmpxattr; break; } if (code) logger->inc(code); } // send? ldout(cct, 10) << "op_submit oid " << op->target.base_oid << " " << op->target.base_oloc << " " << op->target.target_oloc << " " << op->ops << " tid " << op->tid << " osd." << (op->session ? op->session->osd : -1) << dendl; assert(op->target.flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)); if ((op->target.flags & CEPH_OSD_FLAG_WRITE) && osdmap->test_flag(CEPH_OSDMAP_PAUSEWR)) { ldout(cct, 10) << " paused modify " << op << " tid " << last_tid << dendl; op->target.paused = true; maybe_request_map(); } else if ((op->target.flags & CEPH_OSD_FLAG_READ) && osdmap->test_flag(CEPH_OSDMAP_PAUSERD)) { ldout(cct, 10) << " paused read " << op << " tid " << last_tid << dendl; op->target.paused = true; maybe_request_map(); } else if ((op->target.flags & CEPH_OSD_FLAG_WRITE) && osdmap_full_flag()) { ldout(cct, 0) << " FULL, paused modify " << op << " tid " << last_tid << dendl; op->target.paused = true; maybe_request_map(); } else if (op->session) { send_op(op); } else { maybe_request_map(); } if (check_for_latest_map) { _send_op_map_check(op); } ldout(cct, 5) << num_unacked << " unacked, " << num_uncommitted << " uncommitted" << dendl; return op->tid; } int Objecter::op_cancel(ceph_tid_t tid, int r) { assert(client_lock.is_locked()); assert(initialized); map::iterator p = ops.find(tid); if (p == ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; } ldout(cct, 10) << __func__ << " tid " << tid << dendl; Op *op = p->second; if (op->con) { ldout(cct, 20) << " revoking rx buffer for " << tid << " on " << op->con << dendl; op->con->revoke_rx_buffer(tid); } if (op->onack) { op->onack->complete(r); op->onack = NULL; } if (op->oncommit) { op->oncommit->complete(r); op->oncommit = NULL; } op_cancel_map_check(op); finish_op(op); return 0; } bool Objecter::is_pg_changed( int oldprimary, const vector& oldacting, int newprimary, const vector& newacting, bool any_change) { if (OSDMap::primary_changed( oldprimary, oldacting, newprimary, newacting)) return true; if (any_change && oldacting != newacting) return true; return false; // same primary (tho replicas may have changed) } bool Objecter::target_should_be_paused(op_target_t *t) { bool pauserd = osdmap->test_flag(CEPH_OSDMAP_PAUSERD); bool pausewr = osdmap->test_flag(CEPH_OSDMAP_PAUSEWR) || osdmap_full_flag(); return (t->flags & CEPH_OSD_FLAG_READ && pauserd) || (t->flags & CEPH_OSD_FLAG_WRITE && pausewr); } /** * Wrapper around osdmap->test_flag for special handling of the FULL flag. */ bool Objecter::osdmap_full_flag() const { // Ignore the FULL flag if we are working on behalf of an MDS, in order to permit // MDS journal writes for file deletions. return osdmap->test_flag(CEPH_OSDMAP_FULL) && (messenger->get_myname().type() != entity_name_t::TYPE_MDS); } int64_t Objecter::get_object_hash_position(int64_t pool, const string& key, const string& ns) { const pg_pool_t *p = osdmap->get_pg_pool(pool); if (!p) return -ENOENT; return p->hash_key(key, ns); } int64_t Objecter::get_object_pg_hash_position(int64_t pool, const string& key, const string& ns) { const pg_pool_t *p = osdmap->get_pg_pool(pool); if (!p) return -ENOENT; return p->raw_hash_to_pg(p->hash_key(key, ns)); } int Objecter::calc_target(op_target_t *t, epoch_t *last_force_resend, bool any_change) { bool is_read = t->flags & CEPH_OSD_FLAG_READ; bool is_write = t->flags & CEPH_OSD_FLAG_WRITE; const pg_pool_t *pi = osdmap->get_pg_pool(t->base_oloc.pool); bool force_resend = false; bool need_check_tiering = false; if (pi && osdmap->get_epoch() == pi->last_force_op_resend) { if (last_force_resend && *last_force_resend < pi->last_force_op_resend) { *last_force_resend = pi->last_force_op_resend; force_resend = true; } else if (last_force_resend == 0) force_resend = true; } if (t->target_oid.name.empty() || force_resend) { t->target_oid = t->base_oid; need_check_tiering = true; } if (t->target_oloc.empty() || force_resend) { t->target_oloc = t->base_oloc; need_check_tiering = true; } if (need_check_tiering && (t->flags & CEPH_OSD_FLAG_IGNORE_OVERLAY) == 0) { if (pi) { if (is_read && pi->has_read_tier()) t->target_oloc.pool = pi->read_tier; if (is_write && pi->has_write_tier()) t->target_oloc.pool = pi->write_tier; } } pg_t pgid; if (t->precalc_pgid) { assert(t->base_oid.name.empty()); // make sure this is a listing op ldout(cct, 10) << __func__ << " have " << t->base_pgid << " pool " << osdmap->have_pg_pool(t->base_pgid.pool()) << dendl; if (!osdmap->have_pg_pool(t->base_pgid.pool())) return RECALC_OP_TARGET_POOL_DNE; pgid = osdmap->raw_pg_to_pg(t->base_pgid); } else { int ret = osdmap->object_locator_to_pg(t->target_oid, t->target_oloc, pgid); if (ret == -ENOENT) return RECALC_OP_TARGET_POOL_DNE; } int size = pi->size; int min_size = pi->min_size; unsigned pg_num = pi->get_pg_num(); int up_primary, acting_primary; vector up, acting; osdmap->pg_to_up_acting_osds(pgid, &up, &up_primary, &acting, &acting_primary); unsigned prev_seed = ceph_stable_mod(pgid.ps(), t->pg_num, t->pg_num_mask); if (any_change && pg_interval_t::is_new_interval( t->acting_primary, acting_primary, t->acting, acting, t->up_primary, up_primary, t->up, up, t->size, size, t->min_size, min_size, t->pg_num, pg_num, pg_t(prev_seed, pgid.pool(), pgid.preferred()))) { force_resend = true; } bool need_resend = false; bool paused = target_should_be_paused(t); if (!paused && paused != t->paused) { t->paused = false; need_resend = true; } if (t->pgid != pgid || is_pg_changed( t->acting_primary, t->acting, acting_primary, acting, t->used_replica || any_change) || force_resend) { t->pgid = pgid; t->acting = acting; t->acting_primary = acting_primary; t->up_primary = up_primary; t->up = up; t->size = size; t->min_size = min_size; t->pg_num = pg_num; t->pg_num_mask = pi->get_pg_num_mask(); ldout(cct, 10) << __func__ << " " << " pgid " << pgid << " acting " << acting << dendl; t->used_replica = false; if (acting_primary == -1) { t->osd = -1; } else { int osd; bool read = is_read && !is_write; if (read && (t->flags & CEPH_OSD_FLAG_BALANCE_READS)) { int p = rand() % acting.size(); if (p) t->used_replica = true; osd = acting[p]; ldout(cct, 10) << " chose random osd." << osd << " of " << acting << dendl; } else if (read && (t->flags & CEPH_OSD_FLAG_LOCALIZE_READS) && acting.size() > 1) { // look for a local replica. prefer the primary if the // distance is the same. int best = -1; int best_locality; for (unsigned i = 0; i < acting.size(); ++i) { int locality = osdmap->crush->get_common_ancestor_distance( cct, acting[i], crush_location); ldout(cct, 20) << __func__ << " localize: rank " << i << " osd." << acting[i] << " locality " << locality << dendl; if (i == 0 || (locality >= 0 && best_locality >= 0 && locality < best_locality) || (best_locality < 0 && locality >= 0)) { best = i; best_locality = locality; if (i) t->used_replica = true; } } assert(best >= 0); osd = acting[best]; } else { osd = acting_primary; } t->osd = osd; } need_resend = true; } if (need_resend) { return RECALC_OP_TARGET_NEED_RESEND; } return RECALC_OP_TARGET_NO_ACTION; } int Objecter::recalc_op_target(Op *op) { int r = calc_target(&op->target, &op->last_force_resend); if (r == RECALC_OP_TARGET_NEED_RESEND) { OSDSession *s = NULL; if (op->target.osd >= 0) s = get_session(op->target.osd); if (op->session != s) { if (!op->session) num_homeless_ops--; op->session_item.remove_myself(); op->session = s; if (s) s->ops.push_back(&op->session_item); else num_homeless_ops++; } } return r; } bool Objecter::recalc_linger_op_target(LingerOp *linger_op) { int r = calc_target(&linger_op->target, &linger_op->last_force_resend, true); if (r == RECALC_OP_TARGET_NEED_RESEND) { ldout(cct, 10) << "recalc_linger_op_target tid " << linger_op->linger_id << " pgid " << linger_op->target.pgid << " acting " << linger_op->target.acting << dendl; OSDSession *s = linger_op->target.osd != -1 ? get_session(linger_op->target.osd) : NULL; if (linger_op->session != s) { linger_op->session_item.remove_myself(); linger_op->session = s; if (s) s->linger_ops.push_back(&linger_op->session_item); } } return r; } void Objecter::cancel_linger_op(Op *op) { ldout(cct, 15) << "cancel_op " << op->tid << dendl; assert(!op->should_resend); delete op->onack; delete op->oncommit; finish_op(op); } void Objecter::finish_op(Op *op) { ldout(cct, 15) << "finish_op " << op->tid << dendl; op->session_item.remove_myself(); if (!op->ctx_budgeted && op->budgeted) put_op_budget(op); ops.erase(op->tid); logger->set(l_osdc_op_active, ops.size()); // our reply may have raced with pool deletion resulting in a map // check in flight. op_cancel_map_check(op); if (op->ontimeout) timer.cancel_event(op->ontimeout); delete op; } void Objecter::send_op(Op *op) { ldout(cct, 15) << "send_op " << op->tid << " to osd." << op->session->osd << dendl; int flags = op->target.flags; if (op->oncommit) flags |= CEPH_OSD_FLAG_ONDISK; if (op->onack) flags |= CEPH_OSD_FLAG_ACK; assert(op->session->con); // preallocated rx buffer? if (op->con) { ldout(cct, 20) << " revoking rx buffer for " << op->tid << " on " << op->con << dendl; op->con->revoke_rx_buffer(op->tid); } if (op->outbl && op->ontimeout == NULL && // only post rx_buffer if no timeout; see #9582 op->outbl->length()) { ldout(cct, 20) << " posting rx buffer for " << op->tid << " on " << op->session->con << dendl; op->con = op->session->con; op->con->post_rx_buffer(op->tid, *op->outbl); } op->target.paused = false; op->incarnation = op->session->incarnation; op->stamp = ceph_clock_now(cct); MOSDOp *m = new MOSDOp(client_inc, op->tid, op->target.target_oid, op->target.target_oloc, op->target.pgid, osdmap->get_epoch(), flags); m->set_snapid(op->snapid); m->set_snap_seq(op->snapc.seq); m->set_snaps(op->snapc.snaps); m->ops = op->ops; m->set_mtime(op->mtime); m->set_retry_attempt(op->attempts++); if (op->replay_version != eversion_t()) m->set_version(op->replay_version); // we're replaying this op! if (op->priority) m->set_priority(op->priority); else m->set_priority(cct->_conf->osd_client_op_priority); logger->inc(l_osdc_op_send); logger->inc(l_osdc_op_send_bytes, m->get_data().length()); messenger->send_message(m, op->session->con); } int Objecter::calc_op_budget(Op *op) { int op_budget = 0; for (vector::iterator i = op->ops.begin(); i != op->ops.end(); ++i) { if (i->op.op & CEPH_OSD_OP_MODE_WR) { op_budget += i->indata.length(); } else if (ceph_osd_op_mode_read(i->op.op)) { if (ceph_osd_op_type_data(i->op.op)) { if ((int64_t)i->op.extent.length > 0) op_budget += (int64_t)i->op.extent.length; } else if (ceph_osd_op_type_attr(i->op.op)) { op_budget += i->op.xattr.name_len + i->op.xattr.value_len; } } } return op_budget; } void Objecter::throttle_op(Op *op, int op_budget) { if (!op_budget) op_budget = calc_op_budget(op); if (!op_throttle_bytes.get_or_fail(op_budget)) { //couldn't take right now client_lock.Unlock(); op_throttle_bytes.get(op_budget); client_lock.Lock(); } if (!op_throttle_ops.get_or_fail(1)) { //couldn't take right now client_lock.Unlock(); op_throttle_ops.get(1); client_lock.Lock(); } } void Objecter::unregister_op(Op *op) { if (op->onack) num_unacked--; if (op->oncommit) num_uncommitted--; ops.erase(op->tid); } /* This function DOES put the passed message before returning */ void Objecter::handle_osd_op_reply(MOSDOpReply *m) { assert(client_lock.is_locked()); assert(initialized); ldout(cct, 10) << "in handle_osd_op_reply" << dendl; // get pio ceph_tid_t tid = m->get_tid(); if (ops.count(tid) == 0) { ldout(cct, 7) << "handle_osd_op_reply " << tid << (m->is_ondisk() ? " ondisk":(m->is_onnvram() ? " onnvram":" ack")) << " ... stray" << dendl; m->put(); return; } ldout(cct, 7) << "handle_osd_op_reply " << tid << (m->is_ondisk() ? " ondisk":(m->is_onnvram() ? " onnvram":" ack")) << " v " << m->get_replay_version() << " uv " << m->get_user_version() << " in " << m->get_pg() << " attempt " << m->get_retry_attempt() << dendl; Op *op = ops[tid]; if (m->get_retry_attempt() >= 0) { if (m->get_retry_attempt() != (op->attempts - 1)) { ldout(cct, 7) << " ignoring reply from attempt " << m->get_retry_attempt() << " from " << m->get_source_inst() << "; last attempt " << (op->attempts - 1) << " sent to " << op->session->con->get_peer_addr() << dendl; m->put(); return; } } else { // we don't know the request attempt because the server is old, so // just accept this one. we may do ACK callbacks we shouldn't // have, but that is better than doing callbacks out of order. } Context *onack = 0; Context *oncommit = 0; int rc = m->get_result(); if (m->is_redirect_reply()) { ldout(cct, 5) << " got redirect reply; redirecting" << dendl; unregister_op(op); m->get_redirect().combine_with_locator(op->target.target_oloc, op->target.target_oid.name); _op_submit(op); m->put(); return; } if (rc == -EAGAIN) { ldout(cct, 7) << " got -EAGAIN, resubmitting" << dendl; unregister_op(op); _op_submit(op); m->put(); return; } if (op->objver) *op->objver = m->get_user_version(); if (op->reply_epoch) *op->reply_epoch = m->get_map_epoch(); // per-op result demuxing vector out_ops; m->claim_ops(out_ops); if (out_ops.size() != op->ops.size()) ldout(cct, 0) << "WARNING: tid " << op->tid << " reply ops " << out_ops << " != request ops " << op->ops << " from " << m->get_source_inst() << dendl; vector::iterator pb = op->out_bl.begin(); vector::iterator pr = op->out_rval.begin(); vector::iterator ph = op->out_handler.begin(); assert(op->out_bl.size() == op->out_rval.size()); assert(op->out_bl.size() == op->out_handler.size()); vector::iterator p = out_ops.begin(); for (unsigned i = 0; p != out_ops.end() && pb != op->out_bl.end(); ++i, ++p, ++pb, ++pr, ++ph) { ldout(cct, 10) << " op " << i << " rval " << p->rval << " len " << p->outdata.length() << dendl; if (*pb) **pb = p->outdata; // set rval before running handlers so that handlers // can change it if e.g. decoding fails if (*pr) **pr = p->rval; if (*ph) { ldout(cct, 10) << " op " << i << " handler " << *ph << dendl; (*ph)->complete(p->rval); *ph = NULL; } } // ack|commit -> ack if (op->onack) { ldout(cct, 15) << "handle_osd_op_reply ack" << dendl; op->replay_version = m->get_replay_version(); onack = op->onack; op->onack = 0; // only do callback once num_unacked--; logger->inc(l_osdc_op_ack); } if (op->oncommit && (m->is_ondisk() || rc)) { ldout(cct, 15) << "handle_osd_op_reply safe" << dendl; oncommit = op->oncommit; op->oncommit = 0; num_uncommitted--; logger->inc(l_osdc_op_commit); } // got data? if (op->outbl) { if (op->con) op->con->revoke_rx_buffer(op->tid); m->claim_data(*op->outbl); op->outbl = 0; } // done with this tid? if (!op->onack && !op->oncommit) { ldout(cct, 15) << "handle_osd_op_reply completed tid " << tid << dendl; finish_op(op); } ldout(cct, 5) << num_unacked << " unacked, " << num_uncommitted << " uncommitted" << dendl; // do callbacks if (onack) { onack->complete(rc); } if (oncommit) { oncommit->complete(rc); } m->put(); } uint32_t Objecter::list_objects_seek(ListContext *list_context, uint32_t pos) { assert(client_lock.is_locked()); pg_t actual = osdmap->raw_pg_to_pg(pg_t(pos, list_context->pool_id)); ldout(cct, 10) << "list_objects_seek " << list_context << " pos " << pos << " -> " << actual << dendl; list_context->current_pg = actual.ps(); list_context->cookie = collection_list_handle_t(); list_context->at_end_of_pg = false; list_context->at_end_of_pool = false; list_context->current_pg_epoch = 0; return list_context->current_pg; } void Objecter::list_objects(ListContext *list_context, Context *onfinish) { assert(client_lock.is_locked()); ldout(cct, 10) << "list_objects" << dendl; ldout(cct, 20) << " pool_id " << list_context->pool_id << " pool_snap_seq " << list_context->pool_snap_seq << " max_entries " << list_context->max_entries << " list_context " << list_context << " onfinish " << onfinish << " list_context->current_pg " << list_context->current_pg << " list_context->cookie " << list_context->cookie << dendl; if (list_context->at_end_of_pg) { list_context->at_end_of_pg = false; ++list_context->current_pg; list_context->current_pg_epoch = 0; list_context->cookie = collection_list_handle_t(); if (list_context->current_pg >= list_context->starting_pg_num) { list_context->at_end_of_pool = true; ldout(cct, 20) << " no more pgs; reached end of pool" << dendl; } else { ldout(cct, 20) << " move to next pg " << list_context->current_pg << dendl; } } if (list_context->at_end_of_pool) { // release the listing context's budget once all // OPs (in the session) are finished put_list_context_budget(list_context); onfinish->complete(0); return; } const pg_pool_t *pool = osdmap->get_pg_pool(list_context->pool_id); int pg_num = pool->get_pg_num(); if (list_context->starting_pg_num == 0) { // there can't be zero pgs! list_context->starting_pg_num = pg_num; ldout(cct, 20) << pg_num << " placement groups" << dendl; } if (list_context->starting_pg_num != pg_num) { // start reading from the beginning; the pgs have changed ldout(cct, 10) << " pg_num changed; restarting with " << pg_num << dendl; list_context->current_pg = 0; list_context->cookie = collection_list_handle_t(); list_context->current_pg_epoch = 0; list_context->starting_pg_num = pg_num; } assert(list_context->current_pg <= pg_num); ObjectOperation op; op.pg_ls(list_context->max_entries, list_context->filter, list_context->cookie, list_context->current_pg_epoch); list_context->bl.clear(); C_List *onack = new C_List(list_context, onfinish, this); object_locator_t oloc(list_context->pool_id, list_context->nspace); pg_read(list_context->current_pg, oloc, op, &list_context->bl, 0, onack, &onack->epoch, &list_context->ctx_budget); } void Objecter::_list_reply(ListContext *list_context, int r, Context *final_finish, epoch_t reply_epoch) { ldout(cct, 10) << "_list_reply" << dendl; bufferlist::iterator iter = list_context->bl.begin(); pg_ls_response_t response; bufferlist extra_info; ::decode(response, iter); if (!iter.end()) { ::decode(extra_info, iter); } list_context->cookie = response.handle; if (!list_context->current_pg_epoch) { // first pgls result, set epoch marker ldout(cct, 20) << " first pgls piece, reply_epoch is " << reply_epoch << dendl; list_context->current_pg_epoch = reply_epoch; } int response_size = response.entries.size(); ldout(cct, 20) << " response.entries.size " << response_size << ", response.entries " << response.entries << dendl; list_context->extra_info.append(extra_info); if (response_size) { list_context->list.merge(response.entries); } // if the osd returns 1 (newer code), or no entries, it means we // hit the end of the pg. if (response_size == 0 || r == 1) { ldout(cct, 20) << " at end of pg" << dendl; list_context->at_end_of_pg = true; } else { // there is more for this pg; get it? if (response_size < list_context->max_entries) { list_context->max_entries -= response_size; list_objects(list_context, final_finish); return; } } if (!list_context->list.empty()) { ldout(cct, 20) << " returning results so far" << dendl; // release the listing context's budget once all // OPs (in the session) are finished put_list_context_budget(list_context); final_finish->complete(0); return; } // continue! list_objects(list_context, final_finish); } void Objecter::put_list_context_budget(ListContext *list_context) { if (list_context->ctx_budget >= 0) { ldout(cct, 10) << " release listing context's budget " << list_context->ctx_budget << dendl; put_op_budget_bytes(list_context->ctx_budget); list_context->ctx_budget = -1; } } //snapshots int Objecter::create_pool_snap(int64_t pool, string& snap_name, Context *onfinish) { ldout(cct, 10) << "create_pool_snap; pool: " << pool << "; snap: " << snap_name << dendl; const pg_pool_t *p = osdmap->get_pg_pool(pool); if (!p) return -EINVAL; if (p->snap_exists(snap_name.c_str())) return -EEXIST; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->name = snap_name; op->onfinish = onfinish; op->pool_op = POOL_OP_CREATE_SNAP; pool_ops[op->tid] = op; pool_op_submit(op); return 0; } struct C_SelfmanagedSnap : public Context { bufferlist bl; snapid_t *psnapid; Context *fin; C_SelfmanagedSnap(snapid_t *ps, Context *f) : psnapid(ps), fin(f) {} void finish(int r) { if (r == 0) { bufferlist::iterator p = bl.begin(); ::decode(*psnapid, p); } fin->complete(r); } }; int Objecter::allocate_selfmanaged_snap(int64_t pool, snapid_t *psnapid, Context *onfinish) { ldout(cct, 10) << "allocate_selfmanaged_snap; pool: " << pool << dendl; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; C_SelfmanagedSnap *fin = new C_SelfmanagedSnap(psnapid, onfinish); op->onfinish = fin; op->blp = &fin->bl; op->pool_op = POOL_OP_CREATE_UNMANAGED_SNAP; pool_ops[op->tid] = op; pool_op_submit(op); return 0; } int Objecter::delete_pool_snap(int64_t pool, string& snap_name, Context *onfinish) { ldout(cct, 10) << "delete_pool_snap; pool: " << pool << "; snap: " << snap_name << dendl; const pg_pool_t *p = osdmap->get_pg_pool(pool); if (!p) return -EINVAL; if (!p->snap_exists(snap_name.c_str())) return -ENOENT; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->name = snap_name; op->onfinish = onfinish; op->pool_op = POOL_OP_DELETE_SNAP; pool_ops[op->tid] = op; pool_op_submit(op); return 0; } int Objecter::delete_selfmanaged_snap(int64_t pool, snapid_t snap, Context *onfinish) { ldout(cct, 10) << "delete_selfmanaged_snap; pool: " << pool << "; snap: " << snap << dendl; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->onfinish = onfinish; op->pool_op = POOL_OP_DELETE_UNMANAGED_SNAP; op->snapid = snap; pool_ops[op->tid] = op; pool_op_submit(op); return 0; } int Objecter::create_pool(string& name, Context *onfinish, uint64_t auid, int crush_rule) { ldout(cct, 10) << "create_pool name=" << name << dendl; if (osdmap->lookup_pg_pool_name(name.c_str()) >= 0) return -EEXIST; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = 0; op->name = name; op->onfinish = onfinish; op->pool_op = POOL_OP_CREATE; pool_ops[op->tid] = op; op->auid = auid; op->crush_rule = crush_rule; pool_op_submit(op); return 0; } int Objecter::delete_pool(int64_t pool, Context *onfinish) { ldout(cct, 10) << "delete_pool " << pool << dendl; if (!osdmap->have_pg_pool(pool)) return -ENOENT; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->name = "delete"; op->onfinish = onfinish; op->pool_op = POOL_OP_DELETE; pool_ops[op->tid] = op; pool_op_submit(op); return 0; } /** * change the auid owner of a pool by contacting the monitor. * This requires the current connection to have write permissions * on both the pool's current auid and the new (parameter) auid. * Uses the standard Context callback when done. */ int Objecter::change_pool_auid(int64_t pool, Context *onfinish, uint64_t auid) { ldout(cct, 10) << "change_pool_auid " << pool << " to " << auid << dendl; PoolOp *op = new PoolOp; if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->name = "change_pool_auid"; op->onfinish = onfinish; op->pool_op = POOL_OP_AUID_CHANGE; op->auid = auid; pool_ops[op->tid] = op; logger->set(l_osdc_poolop_active, pool_ops.size()); pool_op_submit(op); return 0; } class C_CancelPoolOp : public Context { ceph_tid_t tid; Objecter *objecter; public: C_CancelPoolOp(ceph_tid_t tid, Objecter *objecter) : tid(tid), objecter(objecter) {} void finish(int r) { // note that objecter lock == timer lock, and is already held objecter->pool_op_cancel(tid, -ETIMEDOUT); } }; void Objecter::pool_op_submit(PoolOp *op) { if (mon_timeout > 0) { op->ontimeout = new C_CancelPoolOp(op->tid, this); timer.add_event_after(mon_timeout, op->ontimeout); } _pool_op_submit(op); } void Objecter::_pool_op_submit(PoolOp *op) { ldout(cct, 10) << "pool_op_submit " << op->tid << dendl; MPoolOp *m = new MPoolOp(monc->get_fsid(), op->tid, op->pool, op->name, op->pool_op, op->auid, last_seen_osdmap_version); if (op->snapid) m->snapid = op->snapid; if (op->crush_rule) m->crush_rule = op->crush_rule; monc->send_mon_message(m); op->last_submit = ceph_clock_now(cct); logger->inc(l_osdc_poolop_send); } /** * Handle a reply to a PoolOp message. Check that we sent the message * and give the caller responsibility for the returned bufferlist. * Then either call the finisher or stash the PoolOp, depending on if we * have a new enough map. * Lastly, clean up the message and PoolOp. */ void Objecter::handle_pool_op_reply(MPoolOpReply *m) { assert(client_lock.is_locked()); assert(initialized); ldout(cct, 10) << "handle_pool_op_reply " << *m << dendl; ceph_tid_t tid = m->get_tid(); if (pool_ops.count(tid)) { PoolOp *op = pool_ops[tid]; ldout(cct, 10) << "have request " << tid << " at " << op << " Op: " << ceph_pool_op_name(op->pool_op) << dendl; if (op->blp) op->blp->claim(m->response_data); if (m->version > last_seen_osdmap_version) last_seen_osdmap_version = m->version; if (osdmap->get_epoch() < m->epoch) { ldout(cct, 20) << "waiting for client to reach epoch " << m->epoch << " before calling back" << dendl; wait_for_new_map(op->onfinish, m->epoch, m->replyCode); } else { op->onfinish->complete(m->replyCode); } op->onfinish = NULL; finish_pool_op(op); } else { ldout(cct, 10) << "unknown request " << tid << dendl; } ldout(cct, 10) << "done" << dendl; m->put(); } int Objecter::pool_op_cancel(ceph_tid_t tid, int r) { assert(client_lock.is_locked()); assert(initialized); map::iterator it = pool_ops.find(tid); if (it == pool_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; } ldout(cct, 10) << __func__ << " tid " << tid << dendl; PoolOp *op = it->second; if (op->onfinish) op->onfinish->complete(r); finish_pool_op(op); return 0; } void Objecter::finish_pool_op(PoolOp *op) { pool_ops.erase(op->tid); logger->set(l_osdc_poolop_active, pool_ops.size()); if (op->ontimeout) timer.cancel_event(op->ontimeout); delete op; } // pool stats class C_CancelPoolStatOp : public Context { ceph_tid_t tid; Objecter *objecter; public: C_CancelPoolStatOp(ceph_tid_t tid, Objecter *objecter) : tid(tid), objecter(objecter) {} void finish(int r) { // note that objecter lock == timer lock, and is already held objecter->pool_stat_op_cancel(tid, -ETIMEDOUT); } }; void Objecter::get_pool_stats(list& pools, map *result, Context *onfinish) { ldout(cct, 10) << "get_pool_stats " << pools << dendl; PoolStatOp *op = new PoolStatOp; op->tid = ++last_tid; op->pools = pools; op->pool_stats = result; op->onfinish = onfinish; op->ontimeout = NULL; if (mon_timeout > 0) { op->ontimeout = new C_CancelPoolStatOp(op->tid, this); timer.add_event_after(mon_timeout, op->ontimeout); } poolstat_ops[op->tid] = op; logger->set(l_osdc_poolstat_active, poolstat_ops.size()); poolstat_submit(op); } void Objecter::poolstat_submit(PoolStatOp *op) { ldout(cct, 10) << "poolstat_submit " << op->tid << dendl; monc->send_mon_message(new MGetPoolStats(monc->get_fsid(), op->tid, op->pools, last_seen_pgmap_version)); op->last_submit = ceph_clock_now(cct); logger->inc(l_osdc_poolstat_send); } void Objecter::handle_get_pool_stats_reply(MGetPoolStatsReply *m) { assert(client_lock.is_locked()); assert(initialized); ldout(cct, 10) << "handle_get_pool_stats_reply " << *m << dendl; ceph_tid_t tid = m->get_tid(); if (poolstat_ops.count(tid)) { PoolStatOp *op = poolstat_ops[tid]; ldout(cct, 10) << "have request " << tid << " at " << op << dendl; *op->pool_stats = m->pool_stats; if (m->version > last_seen_pgmap_version) last_seen_pgmap_version = m->version; op->onfinish->complete(0); finish_pool_stat_op(op); } else { ldout(cct, 10) << "unknown request " << tid << dendl; } ldout(cct, 10) << "done" << dendl; m->put(); } int Objecter::pool_stat_op_cancel(ceph_tid_t tid, int r) { assert(client_lock.is_locked()); assert(initialized); map::iterator it = poolstat_ops.find(tid); if (it == poolstat_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; } ldout(cct, 10) << __func__ << " tid " << tid << dendl; PoolStatOp *op = it->second; if (op->onfinish) op->onfinish->complete(r); finish_pool_stat_op(op); return 0; } void Objecter::finish_pool_stat_op(PoolStatOp *op) { poolstat_ops.erase(op->tid); logger->set(l_osdc_poolstat_active, poolstat_ops.size()); if (op->ontimeout) timer.cancel_event(op->ontimeout); delete op; } class C_CancelStatfsOp : public Context { ceph_tid_t tid; Objecter *objecter; public: C_CancelStatfsOp(ceph_tid_t tid, Objecter *objecter) : tid(tid), objecter(objecter) {} void finish(int r) { // note that objecter lock == timer lock, and is already held objecter->statfs_op_cancel(tid, -ETIMEDOUT); } }; void Objecter::get_fs_stats(ceph_statfs& result, Context *onfinish) { ldout(cct, 10) << "get_fs_stats" << dendl; StatfsOp *op = new StatfsOp; op->tid = ++last_tid; op->stats = &result; op->onfinish = onfinish; op->ontimeout = NULL; if (mon_timeout > 0) { op->ontimeout = new C_CancelStatfsOp(op->tid, this); timer.add_event_after(mon_timeout, op->ontimeout); } statfs_ops[op->tid] = op; logger->set(l_osdc_statfs_active, statfs_ops.size()); fs_stats_submit(op); } void Objecter::fs_stats_submit(StatfsOp *op) { ldout(cct, 10) << "fs_stats_submit" << op->tid << dendl; monc->send_mon_message(new MStatfs(monc->get_fsid(), op->tid, last_seen_pgmap_version)); op->last_submit = ceph_clock_now(cct); logger->inc(l_osdc_statfs_send); } void Objecter::handle_fs_stats_reply(MStatfsReply *m) { assert(client_lock.is_locked()); assert(initialized); ldout(cct, 10) << "handle_fs_stats_reply " << *m << dendl; ceph_tid_t tid = m->get_tid(); if (statfs_ops.count(tid)) { StatfsOp *op = statfs_ops[tid]; ldout(cct, 10) << "have request " << tid << " at " << op << dendl; *(op->stats) = m->h.st; if (m->h.version > last_seen_pgmap_version) last_seen_pgmap_version = m->h.version; op->onfinish->complete(0); finish_statfs_op(op); } else { ldout(cct, 10) << "unknown request " << tid << dendl; } ldout(cct, 10) << "done" << dendl; m->put(); } int Objecter::statfs_op_cancel(ceph_tid_t tid, int r) { assert(client_lock.is_locked()); assert(initialized); map::iterator it = statfs_ops.find(tid); if (it == statfs_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; } ldout(cct, 10) << __func__ << " tid " << tid << dendl; StatfsOp *op = it->second; if (op->onfinish) op->onfinish->complete(r); finish_statfs_op(op); return 0; } void Objecter::finish_statfs_op(StatfsOp *op) { statfs_ops.erase(op->tid); logger->set(l_osdc_statfs_active, statfs_ops.size()); if (op->ontimeout) timer.cancel_event(op->ontimeout); delete op; } // scatter/gather void Objecter::_sg_read_finish(vector& extents, vector& resultbl, bufferlist *bl, Context *onfinish) { // all done ldout(cct, 15) << "_sg_read_finish" << dendl; if (extents.size() > 1) { Striper::StripedReadResult r; vector::iterator bit = resultbl.begin(); for (vector::iterator eit = extents.begin(); eit != extents.end(); ++eit, ++bit) { r.add_partial_result(cct, *bit, eit->buffer_extents); } bl->clear(); r.assemble_result(cct, *bl, false); } else { ldout(cct, 15) << " only one frag" << dendl; bl->claim(resultbl[0]); } // done uint64_t bytes_read = bl->length(); ldout(cct, 7) << "_sg_read_finish " << bytes_read << " bytes" << dendl; if (onfinish) { onfinish->complete(bytes_read);// > 0 ? bytes_read:m->get_result()); } } void Objecter::ms_handle_connect(Connection *con) { ldout(cct, 10) << "ms_handle_connect " << con << dendl; if (con->get_peer_type() == CEPH_ENTITY_TYPE_MON) resend_mon_ops(); } void Objecter::ms_handle_reset(Connection *con) { if (con->get_peer_type() == CEPH_ENTITY_TYPE_OSD) { // int osd = osdmap->identify_osd(con->get_peer_addr()); if (osd >= 0) { ldout(cct, 1) << "ms_handle_reset on osd." << osd << dendl; map::iterator p = osd_sessions.find(osd); if (p != osd_sessions.end()) { OSDSession *session = p->second; reopen_session(session); kick_requests(session); maybe_request_map(); } } else { ldout(cct, 10) << "ms_handle_reset on unknown osd addr " << con->get_peer_addr() << dendl; } } } void Objecter::ms_handle_remote_reset(Connection *con) { /* * treat these the same. */ ms_handle_reset(con); } void Objecter::op_target_t::dump(Formatter *f) const { f->dump_stream("pg") << pgid; f->dump_int("osd", osd); f->dump_stream("object_id") << base_oid; f->dump_stream("object_locator") << base_oloc; f->dump_stream("target_object_id") << target_oid; f->dump_stream("target_object_locator") << target_oloc; f->dump_int("paused", (int)paused); f->dump_int("used_replica", (int)used_replica); f->dump_int("precalc_pgid", (int)precalc_pgid); } void Objecter::dump_active() { ldout(cct, 20) << "dump_active .. " << num_homeless_ops << " homeless" << dendl; for (map::iterator p = ops.begin(); p != ops.end(); ++p) { Op *op = p->second; ldout(cct, 20) << op->tid << "\t" << op->target.pgid << "\tosd." << (op->session ? op->session->osd : -1) << "\t" << op->target.base_oid << "\t" << op->ops << dendl; } } void Objecter::dump_requests(Formatter *fmt) const { assert(client_lock.is_locked()); fmt->open_object_section("requests"); dump_ops(fmt); dump_linger_ops(fmt); dump_pool_ops(fmt); dump_pool_stat_ops(fmt); dump_statfs_ops(fmt); dump_command_ops(fmt); fmt->close_section(); // requests object } void Objecter::dump_ops(Formatter *fmt) const { fmt->open_array_section("ops"); for (map::const_iterator p = ops.begin(); p != ops.end(); ++p) { Op *op = p->second; fmt->open_object_section("op"); fmt->dump_unsigned("tid", op->tid); op->target.dump(fmt); fmt->dump_stream("last_sent") << op->stamp; fmt->dump_int("attempts", op->attempts); fmt->dump_stream("snapid") << op->snapid; fmt->dump_stream("snap_context") << op->snapc; fmt->dump_stream("mtime") << op->mtime; fmt->open_array_section("osd_ops"); for (vector::const_iterator it = op->ops.begin(); it != op->ops.end(); ++it) { fmt->dump_stream("osd_op") << *it; } fmt->close_section(); // osd_ops array fmt->close_section(); // op object } fmt->close_section(); // ops array } void Objecter::dump_linger_ops(Formatter *fmt) const { fmt->open_array_section("linger_ops"); for (map::const_iterator p = linger_ops.begin(); p != linger_ops.end(); ++p) { LingerOp *op = p->second; fmt->open_object_section("linger_op"); fmt->dump_unsigned("linger_id", op->linger_id); op->target.dump(fmt); fmt->dump_stream("snapid") << op->snap; fmt->dump_stream("registered") << op->registered; fmt->close_section(); // linger_op object } fmt->close_section(); // linger_ops array } void Objecter::dump_command_ops(Formatter *fmt) const { fmt->open_array_section("command_ops"); for (map::const_iterator p = command_ops.begin(); p != command_ops.end(); ++p) { CommandOp *op = p->second; fmt->open_object_section("command_op"); fmt->dump_unsigned("command_id", op->tid); fmt->dump_int("osd", op->session ? op->session->osd : -1); fmt->open_array_section("command"); for (vector::const_iterator q = op->cmd.begin(); q != op->cmd.end(); ++q) fmt->dump_string("word", *q); fmt->close_section(); if (op->target_osd >= 0) fmt->dump_int("target_osd", op->target_osd); else fmt->dump_stream("target_pg") << op->target_pg; fmt->close_section(); // command_op object } fmt->close_section(); // command_ops array } void Objecter::dump_pool_ops(Formatter *fmt) const { fmt->open_array_section("pool_ops"); for (map::const_iterator p = pool_ops.begin(); p != pool_ops.end(); ++p) { PoolOp *op = p->second; fmt->open_object_section("pool_op"); fmt->dump_unsigned("tid", op->tid); fmt->dump_int("pool", op->pool); fmt->dump_string("name", op->name); fmt->dump_int("operation_type", op->pool_op); fmt->dump_unsigned("auid", op->auid); fmt->dump_unsigned("crush_rule", op->crush_rule); fmt->dump_stream("snapid") << op->snapid; fmt->dump_stream("last_sent") << op->last_submit; fmt->close_section(); // pool_op object } fmt->close_section(); // pool_ops array } void Objecter::dump_pool_stat_ops(Formatter *fmt) const { fmt->open_array_section("pool_stat_ops"); for (map::const_iterator p = poolstat_ops.begin(); p != poolstat_ops.end(); ++p) { PoolStatOp *op = p->second; fmt->open_object_section("pool_stat_op"); fmt->dump_unsigned("tid", op->tid); fmt->dump_stream("last_sent") << op->last_submit; fmt->open_array_section("pools"); for (list::const_iterator it = op->pools.begin(); it != op->pools.end(); ++it) { fmt->dump_string("pool", *it); } fmt->close_section(); // pool_op object fmt->close_section(); // pool_stat_op object } fmt->close_section(); // pool_stat_ops array } void Objecter::dump_statfs_ops(Formatter *fmt) const { fmt->open_array_section("statfs_ops"); for (map::const_iterator p = statfs_ops.begin(); p != statfs_ops.end(); ++p) { StatfsOp *op = p->second; fmt->open_object_section("statfs_op"); fmt->dump_unsigned("tid", op->tid); fmt->dump_stream("last_sent") << op->last_submit; fmt->close_section(); // pool_stat_op object } fmt->close_section(); // pool_stat_ops array } Objecter::RequestStateHook::RequestStateHook(Objecter *objecter) : m_objecter(objecter) { } bool Objecter::RequestStateHook::call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out) { Formatter *f = new_formatter(format); if (!f) f = new_formatter("json-pretty"); m_objecter->client_lock.Lock(); m_objecter->dump_requests(f); m_objecter->client_lock.Unlock(); f->flush(out); delete f; return true; } void Objecter::blacklist_self(bool set) { ldout(cct, 10) << "blacklist_self " << (set ? "add" : "rm") << dendl; vector cmd; cmd.push_back("{\"prefix\":\"osd blacklist\", "); if (set) cmd.push_back("\"blacklistop\":\"add\","); else cmd.push_back("\"blacklistop\":\"rm\","); stringstream ss; ss << messenger->get_myaddr(); cmd.push_back("\"addr\":\"" + ss.str() + "\""); MMonCommand *m = new MMonCommand(monc->get_fsid()); m->cmd = cmd; monc->send_mon_message(m); } // commands void Objecter::handle_command_reply(MCommandReply *m) { map::iterator p = command_ops.find(m->get_tid()); if (p == command_ops.end()) { ldout(cct, 10) << "handle_command_reply tid " << m->get_tid() << " not found" << dendl; m->put(); return; } CommandOp *c = p->second; if (!c->session || m->get_connection() != c->session->con) { ldout(cct, 10) << "handle_command_reply tid " << m->get_tid() << " got reply from wrong connection " << m->get_connection() << " " << m->get_source_inst() << dendl; m->put(); return; } if (c->poutbl) c->poutbl->claim(m->get_data()); _finish_command(c, m->r, m->rs); m->put(); } class C_CancelCommandOp : public Context { ceph_tid_t tid; Objecter *objecter; public: C_CancelCommandOp(ceph_tid_t tid, Objecter *objecter) : tid(tid), objecter(objecter) {} void finish(int r) { // note that objecter lock == timer lock, and is already held objecter->command_op_cancel(tid, -ETIMEDOUT); } }; int Objecter::_submit_command(CommandOp *c, ceph_tid_t *ptid) { ceph_tid_t tid = ++last_tid; ldout(cct, 10) << "_submit_command " << tid << " " << c->cmd << dendl; c->tid = tid; if (osd_timeout > 0) { c->ontimeout = new C_CancelCommandOp(tid, this); timer.add_event_after(osd_timeout, c->ontimeout); } command_ops[tid] = c; num_homeless_ops++; (void)recalc_command_target(c); if (c->session) _send_command(c); else maybe_request_map(); if (c->map_check_error) _send_command_map_check(c); *ptid = tid; logger->set(l_osdc_command_active, command_ops.size()); return 0; } int Objecter::recalc_command_target(CommandOp *c) { OSDSession *s = NULL; c->map_check_error = 0; if (c->target_osd >= 0) { if (!osdmap->exists(c->target_osd)) { c->map_check_error = -ENOENT; c->map_check_error_str = "osd dne"; return RECALC_OP_TARGET_OSD_DNE; } if (osdmap->is_down(c->target_osd)) { c->map_check_error = -ENXIO; c->map_check_error_str = "osd down"; return RECALC_OP_TARGET_OSD_DOWN; } s = get_session(c->target_osd); } else { if (!osdmap->have_pg_pool(c->target_pg.pool())) { c->map_check_error = -ENOENT; c->map_check_error_str = "pool dne"; return RECALC_OP_TARGET_POOL_DNE; } int primary; vector acting; osdmap->pg_to_acting_osds(c->target_pg, &acting, &primary); if (primary != -1) s = get_session(primary); } if (c->session != s) { ldout(cct, 10) << "recalc_command_target " << c->tid << " now " << c->session << dendl; if (s) { if (!c->session) num_homeless_ops--; c->session = s; s->command_ops.push_back(&c->session_item); } else { c->session = NULL; num_homeless_ops++; } return RECALC_OP_TARGET_NEED_RESEND; } ldout(cct, 20) << "recalc_command_target " << c->tid << " no change, " << c->session << dendl; return RECALC_OP_TARGET_NO_ACTION; } void Objecter::_send_command(CommandOp *c) { ldout(cct, 10) << "_send_command " << c->tid << dendl; assert(c->session); assert(c->session->con); MCommand *m = new MCommand(monc->monmap.fsid); m->cmd = c->cmd; m->set_data(c->inbl); m->set_tid(c->tid); messenger->send_message(m, c->session->con); logger->inc(l_osdc_command_send); } int Objecter::command_op_cancel(ceph_tid_t tid, int r) { assert(client_lock.is_locked()); assert(initialized); map::iterator it = command_ops.find(tid); if (it == command_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; } ldout(cct, 10) << __func__ << " tid " << tid << dendl; CommandOp *op = it->second; command_cancel_map_check(op); _finish_command(op, -ETIMEDOUT, ""); return 0; } void Objecter::_finish_command(CommandOp *c, int r, string rs) { ldout(cct, 10) << "_finish_command " << c->tid << " = " << r << " " << rs << dendl; c->session_item.remove_myself(); if (c->prs) *c->prs = rs; if (c->onfinish) c->onfinish->complete(r); command_ops.erase(c->tid); if (c->ontimeout) timer.cancel_event(c->ontimeout); c->put(); logger->set(l_osdc_command_active, command_ops.size()); } ceph-0.80.11/src/osdc/Makefile.am0000664000175100017510000000047412623076744020455 0ustar jenkins-buildjenkins-buildlibosdc_la_SOURCES = \ osdc/Objecter.cc \ osdc/ObjectCacher.cc \ osdc/Filer.cc \ osdc/Striper.cc \ osdc/Journaler.cc noinst_LTLIBRARIES += libosdc.la noinst_HEADERS += \ osdc/Blinker.h \ osdc/Filer.h \ osdc/Journaler.h \ osdc/ObjectCacher.h \ osdc/Objecter.h \ osdc/Striper.h \ osdc/WritebackHandler.h ceph-0.80.11/src/osdc/Striper.h0000664000175100017510000000604012623076744020215 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_STRIPER_H #define CEPH_STRIPER_H #include "include/types.h" #include "osd/osd_types.h" class CephContext; //namespace ceph { class Striper { public: /* * map (ino, layout, offset, len) to a (list of) OSDExtents (byte * ranges in objects on (primary) osds) */ static void file_to_extents(CephContext *cct, const char *object_format, ceph_file_layout *layout, uint64_t offset, uint64_t len, uint64_t trunc_size, map >& extents, uint64_t buffer_offset=0); static void file_to_extents(CephContext *cct, const char *object_format, ceph_file_layout *layout, uint64_t offset, uint64_t len, uint64_t trunc_size, vector& extents, uint64_t buffer_offset=0); static void file_to_extents(CephContext *cct, inodeno_t ino, ceph_file_layout *layout, uint64_t offset, uint64_t len, uint64_t trunc_size, vector& extents) { // generate prefix/format char buf[32]; snprintf(buf, sizeof(buf), "%llx.%%08llx", (long long unsigned)ino); file_to_extents(cct, buf, layout, offset, len, trunc_size, extents); } static void assimilate_extents(map >& object_extents, vector& extents); /** * reverse map an object extent to file extents */ static void extent_to_file(CephContext *cct, ceph_file_layout *layout, uint64_t objectno, uint64_t off, uint64_t len, vector >& extents); static uint64_t object_truncate_size(CephContext *cct, ceph_file_layout *layout, uint64_t objectno, uint64_t trunc_size); /* * helper to assemble a striped result */ class StripedReadResult { map > partial; // offset -> (data, intended length) public: void add_partial_result(CephContext *cct, bufferlist& bl, const vector >& buffer_extents); /** * add sparse read into results * * @param bl buffer * @param bl_map map of which logical source extents this covers * @param bl_off logical buffer offset (e.g., first bl_map key if the buffer is not sparse) * @param buffer_extents output buffer extents the data maps to */ void add_partial_sparse_result(CephContext *cct, bufferlist& bl, const map& bl_map, uint64_t bl_off, const vector >& buffer_extents); void assemble_result(CephContext *cct, bufferlist& bl, bool zero_tail); }; }; //}; #endif ceph-0.80.11/src/osdc/WritebackHandler.h0000664000175100017510000000270512623076744022002 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_OSDC_WRITEBACKHANDLER_H #define CEPH_OSDC_WRITEBACKHANDLER_H #include "include/Context.h" #include "include/types.h" #include "osd/osd_types.h" class WritebackHandler { public: WritebackHandler() {} virtual ~WritebackHandler() {} virtual void read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snapid, bufferlist *pbl, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) = 0; /** * check if a given extent read result may change due to a write * * Check if the content we see at the given read offset may change due to a write to * this object. * * @param oid object * @param read_off read offset * @param read_len read length * @param snapid read snapid */ virtual bool may_copy_on_write(const object_t& oid, uint64_t read_off, uint64_t read_len, snapid_t snapid) = 0; virtual ceph_tid_t write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, uint64_t trunc_size, __u32 trunc_seq, Context *oncommit) = 0; virtual ceph_tid_t lock(const object_t& oid, const object_locator_t& oloc, int op, int flags, Context *onack, Context *oncommit) { assert(0 == "this WritebackHandler does not support the lock operation"); } }; #endif ceph-0.80.11/src/osdc/ObjectCacher.cc0000664000175100017510000016477312623076744021261 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include #include "msg/Messenger.h" #include "ObjectCacher.h" #include "WritebackHandler.h" #include "common/errno.h" #include "common/perf_counters.h" #include "include/assert.h" #define MAX_FLUSH_UNDER_LOCK 20 ///< max bh's we start writeback on while holding the lock /*** ObjectCacher::BufferHead ***/ /*** ObjectCacher::Object ***/ #define dout_subsys ceph_subsys_objectcacher #undef dout_prefix #define dout_prefix *_dout << "objectcacher.object(" << oid << ") " ObjectCacher::BufferHead *ObjectCacher::Object::split(BufferHead *left, loff_t off) { assert(oc->lock.is_locked()); ldout(oc->cct, 20) << "split " << *left << " at " << off << dendl; // split off right ObjectCacher::BufferHead *right = new BufferHead(this); right->last_write_tid = left->last_write_tid; right->last_read_tid = left->last_read_tid; right->set_state(left->get_state()); right->snapc = left->snapc; loff_t newleftlen = off - left->start(); right->set_start(off); right->set_length(left->length() - newleftlen); // shorten left oc->bh_stat_sub(left); left->set_length(newleftlen); oc->bh_stat_add(left); // add right oc->bh_add(this, right); // split buffers too bufferlist bl; bl.claim(left->bl); if (bl.length()) { assert(bl.length() == (left->length() + right->length())); right->bl.substr_of(bl, left->length(), right->length()); left->bl.substr_of(bl, 0, left->length()); } // move read waiters if (!left->waitfor_read.empty()) { map >::iterator start_remove = left->waitfor_read.begin(); while (start_remove != left->waitfor_read.end() && start_remove->first < right->start()) ++start_remove; for (map >::iterator p = start_remove; p != left->waitfor_read.end(); ++p) { ldout(oc->cct, 20) << "split moving waiters at byte " << p->first << " to right bh" << dendl; right->waitfor_read[p->first].swap( p->second ); assert(p->second.empty()); } left->waitfor_read.erase(start_remove, left->waitfor_read.end()); } ldout(oc->cct, 20) << "split left is " << *left << dendl; ldout(oc->cct, 20) << "split right is " << *right << dendl; return right; } void ObjectCacher::Object::merge_left(BufferHead *left, BufferHead *right) { assert(oc->lock.is_locked()); assert(left->end() == right->start()); assert(left->get_state() == right->get_state()); ldout(oc->cct, 10) << "merge_left " << *left << " + " << *right << dendl; oc->bh_remove(this, right); oc->bh_stat_sub(left); left->set_length(left->length() + right->length()); oc->bh_stat_add(left); // data left->bl.claim_append(right->bl); // version // note: this is sorta busted, but should only be used for dirty buffers left->last_write_tid = MAX( left->last_write_tid, right->last_write_tid ); left->last_write = MAX( left->last_write, right->last_write ); // waiters for (map >::iterator p = right->waitfor_read.begin(); p != right->waitfor_read.end(); ++p) left->waitfor_read[p->first].splice( left->waitfor_read[p->first].begin(), p->second ); // hose right delete right; ldout(oc->cct, 10) << "merge_left result " << *left << dendl; } void ObjectCacher::Object::try_merge_bh(BufferHead *bh) { assert(oc->lock.is_locked()); ldout(oc->cct, 10) << "try_merge_bh " << *bh << dendl; // do not merge rx buffers; last_read_tid may not match if (bh->is_rx()) return; // to the left? map::iterator p = data.find(bh->start()); assert(p->second == bh); if (p != data.begin()) { --p; if (p->second->end() == bh->start() && p->second->get_state() == bh->get_state()) { merge_left(p->second, bh); bh = p->second; } else { ++p; } } // to the right? assert(p->second == bh); ++p; if (p != data.end() && p->second->start() == bh->end() && p->second->get_state() == bh->get_state()) merge_left(bh, p->second); } /* * count bytes we have cached in given range */ bool ObjectCacher::Object::is_cached(loff_t cur, loff_t left) { assert(oc->lock.is_locked()); map::iterator p = data_lower_bound(cur); while (left > 0) { if (p == data.end()) return false; if (p->first <= cur) { // have part of it loff_t lenfromcur = MIN(p->second->end() - cur, left); cur += lenfromcur; left -= lenfromcur; ++p; continue; } else if (p->first > cur) { // gap return false; } else assert(0); } return true; } /* * map a range of bytes into buffer_heads. * - create missing buffer_heads as necessary. */ int ObjectCacher::Object::map_read(OSDRead *rd, map& hits, map& missing, map& rx, map& errors) { assert(oc->lock.is_locked()); for (vector::iterator ex_it = rd->extents.begin(); ex_it != rd->extents.end(); ++ex_it) { if (ex_it->oid != oid.oid) continue; ldout(oc->cct, 10) << "map_read " << ex_it->oid << " " << ex_it->offset << "~" << ex_it->length << dendl; loff_t cur = ex_it->offset; loff_t left = ex_it->length; map::iterator p = data_lower_bound(ex_it->offset); while (left > 0) { // at end? if (p == data.end()) { // rest is a miss. BufferHead *n = new BufferHead(this); n->set_start(cur); n->set_length(left); oc->bh_add(this, n); if (complete) { oc->mark_zero(n); hits[cur] = n; ldout(oc->cct, 20) << "map_read miss+complete+zero " << left << " left, " << *n << dendl; } else { missing[cur] = n; ldout(oc->cct, 20) << "map_read miss " << left << " left, " << *n << dendl; } cur += left; left = 0; assert(cur == (loff_t)ex_it->offset + (loff_t)ex_it->length); break; // no more. } if (p->first <= cur) { // have it (or part of it) BufferHead *e = p->second; if (e->is_clean() || e->is_dirty() || e->is_tx() || e->is_zero()) { hits[cur] = e; // readable! ldout(oc->cct, 20) << "map_read hit " << *e << dendl; } else if (e->is_rx()) { rx[cur] = e; // missing, not readable. ldout(oc->cct, 20) << "map_read rx " << *e << dendl; } else if (e->is_error()) { errors[cur] = e; ldout(oc->cct, 20) << "map_read error " << *e << dendl; } else { assert(0); } loff_t lenfromcur = MIN(e->end() - cur, left); cur += lenfromcur; left -= lenfromcur; ++p; continue; // more? } else if (p->first > cur) { // gap.. miss loff_t next = p->first; BufferHead *n = new BufferHead(this); loff_t len = MIN(next - cur, left); n->set_start(cur); n->set_length(len); oc->bh_add(this,n); if (complete) { oc->mark_zero(n); hits[cur] = n; ldout(oc->cct, 20) << "map_read gap+complete+zero " << *n << dendl; } else { missing[cur] = n; ldout(oc->cct, 20) << "map_read gap " << *n << dendl; } cur += MIN(left, n->length()); left -= MIN(left, n->length()); continue; // more? } else { assert(0); } } } return 0; } void ObjectCacher::Object::audit_buffers() { loff_t offset = 0; for (map::const_iterator it = data.begin(); it != data.end(); ++it) { if (it->first != it->second->start()) { lderr(oc->cct) << "AUDIT FAILURE: map position " << it->first << " does not match bh start position: " << *it->second << dendl; assert(it->first == it->second->start()); } if (it->first < offset) { lderr(oc->cct) << "AUDIT FAILURE: " << it->first << " " << *it->second << " overlaps with previous bh " << *((--it)->second) << dendl; assert(it->first >= offset); } BufferHead *bh = it->second; map >::const_iterator w_it; for (w_it = bh->waitfor_read.begin(); w_it != bh->waitfor_read.end(); ++w_it) { if (w_it->first < bh->start() || w_it->first >= bh->start() + bh->length()) { lderr(oc->cct) << "AUDIT FAILURE: waiter at " << w_it->first << " is not within bh " << *bh << dendl; assert(w_it->first >= bh->start()); assert(w_it->first < bh->start() + bh->length()); } } offset = it->first + it->second->length(); } } /* * map a range of extents on an object's buffer cache. * - combine any bh's we're writing into one * - break up bufferheads that don't fall completely within the range * //no! - return a bh that includes the write. may also include other dirty data to left and/or right. */ ObjectCacher::BufferHead *ObjectCacher::Object::map_write(OSDWrite *wr) { assert(oc->lock.is_locked()); BufferHead *final = 0; for (vector::iterator ex_it = wr->extents.begin(); ex_it != wr->extents.end(); ++ex_it) { if (ex_it->oid != oid.oid) continue; ldout(oc->cct, 10) << "map_write oex " << ex_it->oid << " " << ex_it->offset << "~" << ex_it->length << dendl; loff_t cur = ex_it->offset; loff_t left = ex_it->length; map::iterator p = data_lower_bound(ex_it->offset); while (left > 0) { loff_t max = left; // at end ? if (p == data.end()) { if (final == NULL) { final = new BufferHead(this); final->set_start( cur ); final->set_length( max ); oc->bh_add(this, final); ldout(oc->cct, 10) << "map_write adding trailing bh " << *final << dendl; } else { oc->bh_stat_sub(final); final->set_length(final->length() + max); oc->bh_stat_add(final); } left -= max; cur += max; continue; } ldout(oc->cct, 10) << "cur is " << cur << ", p is " << *p->second << dendl; //oc->verify_stats(); if (p->first <= cur) { BufferHead *bh = p->second; ldout(oc->cct, 10) << "map_write bh " << *bh << " intersected" << dendl; if (p->first < cur) { assert(final == 0); if (cur + max >= p->first + p->second->length()) { // we want right bit (one splice) final = split(bh, cur); // just split it, take right half. ++p; assert(p->second == final); } else { // we want middle bit (two splices) final = split(bh, cur); ++p; assert(p->second == final); split(final, cur+max); } } else { assert(p->first == cur); if (p->second->length() <= max) { // whole bufferhead, piece of cake. } else { // we want left bit (one splice) split(bh, cur + max); // just split } if (final) { oc->mark_dirty(bh); oc->mark_dirty(final); --p; // move iterator back to final assert(p->second == final); merge_left(final, bh); } else { final = bh; } } // keep going. loff_t lenfromcur = final->end() - cur; cur += lenfromcur; left -= lenfromcur; ++p; continue; } else { // gap! loff_t next = p->first; loff_t glen = MIN(next - cur, max); ldout(oc->cct, 10) << "map_write gap " << cur << "~" << glen << dendl; if (final) { oc->bh_stat_sub(final); final->set_length(final->length() + glen); oc->bh_stat_add(final); } else { final = new BufferHead(this); final->set_start( cur ); final->set_length( glen ); oc->bh_add(this, final); } cur += glen; left -= glen; continue; // more? } } } // set versoin assert(final); ldout(oc->cct, 10) << "map_write final is " << *final << dendl; return final; } void ObjectCacher::Object::truncate(loff_t s) { assert(oc->lock.is_locked()); ldout(oc->cct, 10) << "truncate " << *this << " to " << s << dendl; while (!data.empty()) { BufferHead *bh = data.rbegin()->second; if (bh->end() <= s) break; // split bh at truncation point? if (bh->start() < s) { split(bh, s); continue; } // remove bh entirely assert(bh->start() >= s); assert(bh->waitfor_read.empty()); oc->bh_remove(this, bh); delete bh; } } void ObjectCacher::Object::discard(loff_t off, loff_t len) { assert(oc->lock.is_locked()); ldout(oc->cct, 10) << "discard " << *this << " " << off << "~" << len << dendl; if (!exists) { ldout(oc->cct, 10) << " setting exists on " << *this << dendl; exists = true; } if (complete) { ldout(oc->cct, 10) << " clearing complete on " << *this << dendl; complete = false; } map::iterator p = data_lower_bound(off); while (p != data.end()) { BufferHead *bh = p->second; if (bh->start() >= off + len) break; // split bh at truncation point? if (bh->start() < off) { split(bh, off); ++p; continue; } assert(bh->start() >= off); if (bh->end() > off + len) { split(bh, off + len); } ++p; ldout(oc->cct, 10) << "discard " << *this << " bh " << *bh << dendl; assert(bh->waitfor_read.empty()); oc->bh_remove(this, bh); delete bh; } } /*** ObjectCacher ***/ #undef dout_prefix #define dout_prefix *_dout << "objectcacher " ObjectCacher::ObjectCacher(CephContext *cct_, string name, WritebackHandler& wb, Mutex& l, flush_set_callback_t flush_callback, void *flush_callback_arg, uint64_t max_bytes, uint64_t max_objects, uint64_t max_dirty, uint64_t target_dirty, double max_dirty_age, bool block_writes_upfront) : perfcounter(NULL), cct(cct_), writeback_handler(wb), name(name), lock(l), max_dirty(max_dirty), target_dirty(target_dirty), max_size(max_bytes), max_objects(max_objects), block_writes_upfront(block_writes_upfront), flush_set_callback(flush_callback), flush_set_callback_arg(flush_callback_arg), last_read_tid(0), flusher_stop(false), flusher_thread(this), finisher(cct), stat_clean(0), stat_zero(0), stat_dirty(0), stat_rx(0), stat_tx(0), stat_missing(0), stat_error(0), stat_dirty_waiting(0), reads_outstanding(0) { this->max_dirty_age.set_from_double(max_dirty_age); perf_start(); finisher.start(); } ObjectCacher::~ObjectCacher() { finisher.stop(); perf_stop(); // we should be empty. for (vector >::iterator i = objects.begin(); i != objects.end(); ++i) assert(i->empty()); assert(bh_lru_rest.lru_get_size() == 0); assert(bh_lru_dirty.lru_get_size() == 0); assert(ob_lru.lru_get_size() == 0); assert(dirty_bh.empty()); } void ObjectCacher::perf_start() { string n = "objectcacher-" + name; PerfCountersBuilder plb(cct, n, l_objectcacher_first, l_objectcacher_last); plb.add_u64_counter(l_objectcacher_cache_ops_hit, "cache_ops_hit"); plb.add_u64_counter(l_objectcacher_cache_ops_miss, "cache_ops_miss"); plb.add_u64_counter(l_objectcacher_cache_bytes_hit, "cache_bytes_hit"); plb.add_u64_counter(l_objectcacher_cache_bytes_miss, "cache_bytes_miss"); plb.add_u64_counter(l_objectcacher_data_read, "data_read"); plb.add_u64_counter(l_objectcacher_data_written, "data_written"); plb.add_u64_counter(l_objectcacher_data_flushed, "data_flushed"); plb.add_u64_counter(l_objectcacher_overwritten_in_flush, "data_overwritten_while_flushing"); plb.add_u64_counter(l_objectcacher_write_ops_blocked, "write_ops_blocked"); plb.add_u64_counter(l_objectcacher_write_bytes_blocked, "write_bytes_blocked"); plb.add_time(l_objectcacher_write_time_blocked, "write_time_blocked"); perfcounter = plb.create_perf_counters(); cct->get_perfcounters_collection()->add(perfcounter); } void ObjectCacher::perf_stop() { assert(perfcounter); cct->get_perfcounters_collection()->remove(perfcounter); delete perfcounter; } /* private */ ObjectCacher::Object *ObjectCacher::get_object(sobject_t oid, ObjectSet *oset, object_locator_t &l, uint64_t truncate_size, uint64_t truncate_seq) { // XXX: Add handling of nspace in object_locator_t in cache assert(lock.is_locked()); // have it? if ((uint32_t)l.pool < objects.size()) { if (objects[l.pool].count(oid)) { Object *o = objects[l.pool][oid]; o->truncate_size = truncate_size; o->truncate_seq = truncate_seq; return o; } } else { objects.resize(l.pool+1); } // create it. Object *o = new Object(this, oid, oset, l, truncate_size, truncate_seq); objects[l.pool][oid] = o; ob_lru.lru_insert_top(o); return o; } void ObjectCacher::close_object(Object *ob) { assert(lock.is_locked()); ldout(cct, 10) << "close_object " << *ob << dendl; assert(ob->can_close()); // ok! ob_lru.lru_remove(ob); objects[ob->oloc.pool].erase(ob->get_soid()); ob->set_item.remove_myself(); delete ob; } void ObjectCacher::bh_read(BufferHead *bh) { assert(lock.is_locked()); ldout(cct, 7) << "bh_read on " << *bh << " outstanding reads " << reads_outstanding << dendl; mark_rx(bh); bh->last_read_tid = ++last_read_tid; // finisher C_ReadFinish *onfinish = new C_ReadFinish(this, bh->ob, bh->last_read_tid, bh->start(), bh->length()); // go writeback_handler.read(bh->ob->get_oid(), bh->ob->get_oloc(), bh->start(), bh->length(), bh->ob->get_snap(), &onfinish->bl, bh->ob->truncate_size, bh->ob->truncate_seq, onfinish); ++reads_outstanding; } void ObjectCacher::bh_read_finish(int64_t poolid, sobject_t oid, ceph_tid_t tid, loff_t start, uint64_t length, bufferlist &bl, int r, bool trust_enoent) { assert(lock.is_locked()); ldout(cct, 7) << "bh_read_finish " << oid << " tid " << tid << " " << start << "~" << length << " (bl is " << bl.length() << ")" << " returned " << r << " outstanding reads " << reads_outstanding << dendl; if (bl.length() < length) { bufferptr bp(length - bl.length()); bp.zero(); ldout(cct, 7) << "bh_read_finish " << oid << " padding " << start << "~" << length << " with " << bp.length() << " bytes of zeroes" << dendl; bl.push_back(bp); } list ls; int err = 0; if (objects[poolid].count(oid) == 0) { ldout(cct, 7) << "bh_read_finish no object cache" << dendl; } else { Object *ob = objects[poolid][oid]; if (r == -ENOENT && !ob->complete) { // wake up *all* rx waiters, or else we risk reordering identical reads. e.g. // read 1~1 // reply to unrelated 3~1 -> !exists // read 1~1 -> immediate ENOENT // reply to first 1~1 -> ooo ENOENT bool allzero = true; for (map::iterator p = ob->data.begin(); p != ob->data.end(); ++p) { BufferHead *bh = p->second; for (map >::iterator p = bh->waitfor_read.begin(); p != bh->waitfor_read.end(); ++p) ls.splice(ls.end(), p->second); bh->waitfor_read.clear(); if (!bh->is_zero() && !bh->is_rx()) allzero = false; } // just pass through and retry all waiters if we don't trust // -ENOENT for this read if (trust_enoent) { ldout(cct, 7) << "bh_read_finish ENOENT, marking complete and !exists on " << *ob << dendl; ob->complete = true; ob->exists = false; /* If all the bhs are effectively zero, get rid of them. All * the waiters will be retried and get -ENOENT immediately, so * it's safe to clean up the unneeded bh's now. Since we know * it's safe to remove them now, do so, so they aren't hanging *around waiting for more -ENOENTs from rados while the cache * is being shut down. * * Only do this when all the bhs are rx or clean, to match the * condition in _readx(). If there are any non-rx or non-clean * bhs, _readx() will wait for the final result instead of * returning -ENOENT immediately. */ if (allzero) { ldout(cct, 10) << "bh_read_finish ENOENT and allzero, getting rid of " << "bhs for " << *ob << dendl; map::iterator p = ob->data.begin(); while (p != ob->data.end()) { BufferHead *bh = p->second; // current iterator will be invalidated by bh_remove() ++p; bh_remove(ob, bh); delete bh; } } } } // apply to bh's! loff_t opos = start; while (true) { map::iterator p = ob->data_lower_bound(opos); if (p == ob->data.end()) break; if (opos >= start+(loff_t)length) { ldout(cct, 20) << "break due to opos " << opos << " >= start+length " << start << "+" << length << "=" << start+(loff_t)length << dendl; break; } BufferHead *bh = p->second; ldout(cct, 20) << "checking bh " << *bh << dendl; // finishers? for (map >::iterator it = bh->waitfor_read.begin(); it != bh->waitfor_read.end(); ++it) ls.splice(ls.end(), it->second); bh->waitfor_read.clear(); if (bh->start() > opos) { ldout(cct, 1) << "bh_read_finish skipping gap " << opos << "~" << bh->start() - opos << dendl; opos = bh->start(); continue; } if (!bh->is_rx()) { ldout(cct, 10) << "bh_read_finish skipping non-rx " << *bh << dendl; opos = bh->end(); continue; } if (bh->last_read_tid != tid) { ldout(cct, 10) << "bh_read_finish bh->last_read_tid " << bh->last_read_tid << " != tid " << tid << ", skipping" << dendl; opos = bh->end(); continue; } assert(opos >= bh->start()); assert(bh->start() == opos); // we don't merge rx bh's... yet! assert(bh->length() <= start+(loff_t)length-opos); if (bh->error < 0) err = bh->error; loff_t oldpos = opos; opos = bh->end(); if (r == -ENOENT) { if (trust_enoent) { ldout(cct, 10) << "bh_read_finish removing " << *bh << dendl; bh_remove(ob, bh); delete bh; } else { ldout(cct, 10) << "skipping unstrusted -ENOENT and will retry for " << *bh << dendl; } continue; } if (r < 0) { bh->error = r; mark_error(bh); } else { bh->bl.substr_of(bl, oldpos-bh->start(), bh->length()); mark_clean(bh); } ldout(cct, 10) << "bh_read_finish read " << *bh << dendl; ob->try_merge_bh(bh); } } // called with lock held. ldout(cct, 20) << "finishing waiters " << ls << dendl; finish_contexts(cct, ls, err); retry_waiting_reads(); --reads_outstanding; read_cond.Signal(); } void ObjectCacher::bh_write(BufferHead *bh) { assert(lock.is_locked()); ldout(cct, 7) << "bh_write " << *bh << dendl; bh->ob->get(); // finishers C_WriteCommit *oncommit = new C_WriteCommit(this, bh->ob->oloc.pool, bh->ob->get_soid(), bh->start(), bh->length()); // go ceph_tid_t tid = writeback_handler.write(bh->ob->get_oid(), bh->ob->get_oloc(), bh->start(), bh->length(), bh->snapc, bh->bl, bh->last_write, bh->ob->truncate_size, bh->ob->truncate_seq, oncommit); ldout(cct, 20) << " tid " << tid << " on " << bh->ob->get_oid() << dendl; // set bh last_write_tid oncommit->tid = tid; bh->ob->last_write_tid = tid; bh->last_write_tid = tid; if (perfcounter) { perfcounter->inc(l_objectcacher_data_flushed, bh->length()); } mark_tx(bh); } void ObjectCacher::bh_write_commit(int64_t poolid, sobject_t oid, loff_t start, uint64_t length, ceph_tid_t tid, int r) { assert(lock.is_locked()); ldout(cct, 7) << "bh_write_commit " << oid << " tid " << tid << " " << start << "~" << length << " returned " << r << dendl; if (objects[poolid].count(oid) == 0) { ldout(cct, 7) << "bh_write_commit no object cache" << dendl; } else { Object *ob = objects[poolid][oid]; int was_dirty_or_tx = ob->oset->dirty_or_tx; if (!ob->exists) { ldout(cct, 10) << "bh_write_commit marking exists on " << *ob << dendl; ob->exists = true; if (writeback_handler.may_copy_on_write(ob->get_oid(), start, length, ob->get_snap())) { ldout(cct, 10) << "bh_write_commit may copy on write, clearing complete on " << *ob << dendl; ob->complete = false; } } // apply to bh's! for (map::iterator p = ob->data_lower_bound(start); p != ob->data.end(); ++p) { BufferHead *bh = p->second; if (bh->start() > start+(loff_t)length) break; if (bh->start() < start && bh->end() > start+(loff_t)length) { ldout(cct, 20) << "bh_write_commit skipping " << *bh << dendl; continue; } // make sure bh is tx if (!bh->is_tx()) { ldout(cct, 10) << "bh_write_commit skipping non-tx " << *bh << dendl; continue; } // make sure bh tid matches if (bh->last_write_tid != tid) { assert(bh->last_write_tid > tid); ldout(cct, 10) << "bh_write_commit newer tid on " << *bh << dendl; continue; } if (r >= 0) { // ok! mark bh clean and error-free mark_clean(bh); ldout(cct, 10) << "bh_write_commit clean " << *bh << dendl; } else { mark_dirty(bh); ldout(cct, 10) << "bh_write_commit marking dirty again due to error " << *bh << " r = " << r << " " << cpp_strerror(-r) << dendl; } } // update last_commit. assert(ob->last_commit_tid < tid); ob->last_commit_tid = tid; // waiters? list ls; if (ob->waitfor_commit.count(tid)) { ls.splice(ls.begin(), ob->waitfor_commit[tid]); ob->waitfor_commit.erase(tid); } // is the entire object set now clean and fully committed? ObjectSet *oset = ob->oset; ob->put(); if (flush_set_callback && was_dirty_or_tx > 0 && oset->dirty_or_tx == 0) { // nothing dirty/tx flush_set_callback(flush_set_callback_arg, oset); } if (!ls.empty()) finish_contexts(cct, ls, r); } } void ObjectCacher::flush(loff_t amount) { assert(lock.is_locked()); utime_t cutoff = ceph_clock_now(cct); ldout(cct, 10) << "flush " << amount << dendl; /* * NOTE: we aren't actually pulling things off the LRU here, just looking at the * tail item. Then we call bh_write, which moves it to the other LRU, so that we * can call lru_dirty.lru_get_next_expire() again. */ loff_t did = 0; while (amount == 0 || did < amount) { BufferHead *bh = static_cast(bh_lru_dirty.lru_get_next_expire()); if (!bh) break; if (bh->last_write > cutoff) break; did += bh->length(); bh_write(bh); } } void ObjectCacher::trim() { assert(lock.is_locked()); ldout(cct, 10) << "trim start: bytes: max " << max_size << " clean " << get_stat_clean() << ", objects: max " << max_objects << " current " << ob_lru.lru_get_size() << dendl; while (get_stat_clean() > 0 && (uint64_t) get_stat_clean() > max_size) { BufferHead *bh = static_cast(bh_lru_rest.lru_expire()); if (!bh) break; ldout(cct, 10) << "trim trimming " << *bh << dendl; assert(bh->is_clean() || bh->is_zero()); Object *ob = bh->ob; bh_remove(ob, bh); delete bh; if (ob->complete) { ldout(cct, 10) << "trim clearing complete on " << *ob << dendl; ob->complete = false; } } while (ob_lru.lru_get_size() > max_objects) { Object *ob = static_cast(ob_lru.lru_expire()); if (!ob) break; ldout(cct, 10) << "trim trimming " << *ob << dendl; close_object(ob); } ldout(cct, 10) << "trim finish: max " << max_size << " clean " << get_stat_clean() << ", objects: max " << max_objects << " current " << ob_lru.lru_get_size() << dendl; } /* public */ bool ObjectCacher::is_cached(ObjectSet *oset, vector& extents, snapid_t snapid) { assert(lock.is_locked()); for (vector::iterator ex_it = extents.begin(); ex_it != extents.end(); ++ex_it) { ldout(cct, 10) << "is_cached " << *ex_it << dendl; // get Object cache sobject_t soid(ex_it->oid, snapid); Object *o = get_object_maybe(soid, ex_it->oloc); if (!o) return false; if (!o->is_cached(ex_it->offset, ex_it->length)) return false; } return true; } /* * returns # bytes read (if in cache). onfinish is untouched (caller must delete it) * returns 0 if doing async read */ int ObjectCacher::readx(OSDRead *rd, ObjectSet *oset, Context *onfinish) { return _readx(rd, oset, onfinish, true); } int ObjectCacher::_readx(OSDRead *rd, ObjectSet *oset, Context *onfinish, bool external_call) { assert(lock.is_locked()); bool success = true; int error = 0; list hit_ls; uint64_t bytes_in_cache = 0; uint64_t bytes_not_in_cache = 0; uint64_t total_bytes_read = 0; map stripe_map; // final buffer offset -> substring for (vector::iterator ex_it = rd->extents.begin(); ex_it != rd->extents.end(); ++ex_it) { ldout(cct, 10) << "readx " << *ex_it << dendl; total_bytes_read += ex_it->length; // get Object cache sobject_t soid(ex_it->oid, rd->snap); Object *o = get_object(soid, oset, ex_it->oloc, ex_it->truncate_size, oset->truncate_seq); touch_ob(o); // does not exist and no hits? if (oset->return_enoent && !o->exists) { // WARNING: we can only meaningfully return ENOENT if the read request // passed in a single ObjectExtent. Any caller who wants ENOENT instead of // zeroed buffers needs to feed single extents into readx(). assert(rd->extents.size() == 1); ldout(cct, 10) << "readx object !exists, 1 extent..." << dendl; // should we worry about COW underneaeth us? if (writeback_handler.may_copy_on_write(soid.oid, ex_it->offset, ex_it->length, soid.snap)) { ldout(cct, 20) << "readx may copy on write" << dendl; bool wait = false; for (map::iterator bh_it = o->data.begin(); bh_it != o->data.end(); ++bh_it) { BufferHead *bh = bh_it->second; if (bh->is_dirty() || bh->is_tx()) { ldout(cct, 10) << "readx flushing " << *bh << dendl; wait = true; if (bh->is_dirty()) bh_write(bh); } } if (wait) { ldout(cct, 10) << "readx waiting on tid " << o->last_write_tid << " on " << *o << dendl; o->waitfor_commit[o->last_write_tid].push_back(new C_RetryRead(this, rd, oset, onfinish)); // FIXME: perfcounter! return 0; } } // can we return ENOENT? bool allzero = true; for (map::iterator bh_it = o->data.begin(); bh_it != o->data.end(); ++bh_it) { ldout(cct, 20) << "readx ob has bh " << *bh_it->second << dendl; if (!bh_it->second->is_zero() && !bh_it->second->is_rx()) { allzero = false; break; } } if (allzero) { ldout(cct, 10) << "readx ob has all zero|rx, returning ENOENT" << dendl; delete rd; return -ENOENT; } } // map extent into bufferheads map hits, missing, rx, errors; o->map_read(rd, hits, missing, rx, errors); if (external_call) { // retry reading error buffers missing.insert(errors.begin(), errors.end()); } else { // some reads had errors, fail later so completions // are cleaned up up properly // TODO: make read path not call _readx for every completion hits.insert(errors.begin(), errors.end()); } if (!missing.empty() || !rx.empty()) { // read missing for (map::iterator bh_it = missing.begin(); bh_it != missing.end(); ++bh_it) { uint64_t rx_bytes = static_cast( stat_rx + bh_it->second->length()); if (!waitfor_read.empty() || rx_bytes > max_size) { // cache is full with concurrent reads -- wait for rx's to complete // to constrain memory growth (especially during copy-ups) if (success) { ldout(cct, 10) << "readx missed, waiting on cache to complete " << waitfor_read.size() << " blocked reads, " << (MAX(rx_bytes, max_size) - max_size) << " read bytes" << dendl; waitfor_read.push_back(new C_RetryRead(this, rd, oset, onfinish)); } bh_remove(o, bh_it->second); delete bh_it->second; } else { bh_read(bh_it->second); if (success && onfinish) { ldout(cct, 10) << "readx missed, waiting on " << *bh_it->second << " off " << bh_it->first << dendl; bh_it->second->waitfor_read[bh_it->first].push_back( new C_RetryRead(this, rd, oset, onfinish) ); } } bytes_not_in_cache += bh_it->second->length(); success = false; } // bump rx for (map::iterator bh_it = rx.begin(); bh_it != rx.end(); ++bh_it) { touch_bh(bh_it->second); // bump in lru, so we don't lose it. if (success && onfinish) { ldout(cct, 10) << "readx missed, waiting on " << *bh_it->second << " off " << bh_it->first << dendl; bh_it->second->waitfor_read[bh_it->first].push_back( new C_RetryRead(this, rd, oset, onfinish) ); } bytes_not_in_cache += bh_it->second->length(); success = false; } } else { assert(!hits.empty()); // make a plain list for (map::iterator bh_it = hits.begin(); bh_it != hits.end(); ++bh_it) { ldout(cct, 10) << "readx hit bh " << *bh_it->second << dendl; if (bh_it->second->is_error() && bh_it->second->error) error = bh_it->second->error; hit_ls.push_back(bh_it->second); bytes_in_cache += bh_it->second->length(); } // create reverse map of buffer offset -> object for the eventual result. // this is over a single ObjectExtent, so we know that // - the bh's are contiguous // - the buffer frags need not be (and almost certainly aren't) loff_t opos = ex_it->offset; map::iterator bh_it = hits.begin(); assert(bh_it->second->start() <= opos); uint64_t bhoff = opos - bh_it->second->start(); vector >::iterator f_it = ex_it->buffer_extents.begin(); uint64_t foff = 0; while (1) { BufferHead *bh = bh_it->second; assert(opos == (loff_t)(bh->start() + bhoff)); uint64_t len = MIN(f_it->second - foff, bh->length() - bhoff); ldout(cct, 10) << "readx rmap opos " << opos << ": " << *bh << " +" << bhoff << " frag " << f_it->first << "~" << f_it->second << " +" << foff << "~" << len << dendl; bufferlist bit; // put substr here first, since substr_of clobbers, and // we may get multiple bh's at this stripe_map position if (bh->is_zero()) { bufferptr bp(len); bp.zero(); stripe_map[f_it->first].push_back(bp); } else { bit.substr_of(bh->bl, opos - bh->start(), len); stripe_map[f_it->first].claim_append(bit); } opos += len; bhoff += len; foff += len; if (opos == bh->end()) { ++bh_it; bhoff = 0; } if (foff == f_it->second) { ++f_it; foff = 0; } if (bh_it == hits.end()) break; if (f_it == ex_it->buffer_extents.end()) break; } assert(f_it == ex_it->buffer_extents.end()); assert(opos == (loff_t)ex_it->offset + (loff_t)ex_it->length); } } // bump hits in lru for (list::iterator bhit = hit_ls.begin(); bhit != hit_ls.end(); ++bhit) touch_bh(*bhit); if (!success) { if (perfcounter && external_call) { perfcounter->inc(l_objectcacher_data_read, total_bytes_read); perfcounter->inc(l_objectcacher_cache_bytes_miss, bytes_not_in_cache); perfcounter->inc(l_objectcacher_cache_ops_miss); } if (onfinish) { ldout(cct, 20) << "readx defer " << rd << dendl; } else { ldout(cct, 20) << "readx drop " << rd << " (no complete, but no waiter)" << dendl; delete rd; } return 0; // wait! } if (perfcounter && external_call) { perfcounter->inc(l_objectcacher_data_read, total_bytes_read); perfcounter->inc(l_objectcacher_cache_bytes_hit, bytes_in_cache); perfcounter->inc(l_objectcacher_cache_ops_hit); } // no misses... success! do the read. assert(!hit_ls.empty()); ldout(cct, 10) << "readx has all buffers" << dendl; // ok, assemble into result buffer. uint64_t pos = 0; if (rd->bl && !error) { rd->bl->clear(); for (map::iterator i = stripe_map.begin(); i != stripe_map.end(); ++i) { assert(pos == i->first); ldout(cct, 10) << "readx adding buffer len " << i->second.length() << " at " << pos << dendl; pos += i->second.length(); rd->bl->claim_append(i->second); assert(rd->bl->length() == pos); } ldout(cct, 10) << "readx result is " << rd->bl->length() << dendl; } else { ldout(cct, 10) << "readx no bufferlist ptr (readahead?), done." << dendl; map::reverse_iterator i = stripe_map.rbegin(); pos = i->first + i->second.length(); } // done with read. int ret = error ? error : pos; ldout(cct, 20) << "readx done " << rd << " " << ret << dendl; assert(pos <= (uint64_t) INT_MAX); delete rd; trim(); return ret; } void ObjectCacher::retry_waiting_reads() { list ls; ls.swap(waitfor_read); while (!ls.empty() && waitfor_read.empty()) { Context *ctx = ls.front(); ls.pop_front(); ctx->complete(0); } waitfor_read.splice(waitfor_read.end(), ls); } int ObjectCacher::writex(OSDWrite *wr, ObjectSet *oset, Mutex& wait_on_lock, Context *onfreespace) { assert(lock.is_locked()); utime_t now = ceph_clock_now(cct); uint64_t bytes_written = 0; uint64_t bytes_written_in_flush = 0; for (vector::iterator ex_it = wr->extents.begin(); ex_it != wr->extents.end(); ++ex_it) { // get object cache sobject_t soid(ex_it->oid, CEPH_NOSNAP); Object *o = get_object(soid, oset, ex_it->oloc, ex_it->truncate_size, oset->truncate_seq); // map it all into a single bufferhead. BufferHead *bh = o->map_write(wr); bh->snapc = wr->snapc; bytes_written += bh->length(); if (bh->is_tx()) { bytes_written_in_flush += bh->length(); } // adjust buffer pointers (ie "copy" data into my cache) // this is over a single ObjectExtent, so we know that // - there is one contiguous bh // - the buffer frags need not be (and almost certainly aren't) // note: i assume striping is monotonic... no jumps backwards, ever! loff_t opos = ex_it->offset; for (vector >::iterator f_it = ex_it->buffer_extents.begin(); f_it != ex_it->buffer_extents.end(); ++f_it) { ldout(cct, 10) << "writex writing " << f_it->first << "~" << f_it->second << " into " << *bh << " at " << opos << dendl; uint64_t bhoff = bh->start() - opos; assert(f_it->second <= bh->length() - bhoff); // get the frag we're mapping in bufferlist frag; frag.substr_of(wr->bl, f_it->first, f_it->second); // keep anything left of bhoff bufferlist newbl; if (bhoff) newbl.substr_of(bh->bl, 0, bhoff); newbl.claim_append(frag); bh->bl.swap(newbl); opos += f_it->second; } // ok, now bh is dirty. mark_dirty(bh); touch_bh(bh); bh->last_write = now; o->try_merge_bh(bh); } if (perfcounter) { perfcounter->inc(l_objectcacher_data_written, bytes_written); if (bytes_written_in_flush) { perfcounter->inc(l_objectcacher_overwritten_in_flush, bytes_written_in_flush); } } int r = _wait_for_write(wr, bytes_written, oset, wait_on_lock, onfreespace); delete wr; //verify_stats(); trim(); return r; } void ObjectCacher::C_WaitForWrite::finish(int r) { Mutex::Locker l(m_oc->lock); m_oc->maybe_wait_for_writeback(m_len); m_onfinish->complete(r); } void ObjectCacher::maybe_wait_for_writeback(uint64_t len) { assert(lock.is_locked()); utime_t start = ceph_clock_now(cct); int blocked = 0; // wait for writeback? // - wait for dirty and tx bytes (relative to the max_dirty threshold) // - do not wait for bytes other waiters are waiting on. this means that // threads do not wait for each other. this effectively allows the cache // size to balloon proportional to the data that is in flight. while (get_stat_dirty() + get_stat_tx() > 0 && (uint64_t) (get_stat_dirty() + get_stat_tx()) >= max_dirty + get_stat_dirty_waiting()) { ldout(cct, 10) << __func__ << " waiting for dirty|tx " << (get_stat_dirty() + get_stat_tx()) << " >= max " << max_dirty << " + dirty_waiting " << get_stat_dirty_waiting() << dendl; flusher_cond.Signal(); stat_dirty_waiting += len; stat_cond.Wait(lock); stat_dirty_waiting -= len; ++blocked; ldout(cct, 10) << __func__ << " woke up" << dendl; } if (blocked && perfcounter) { perfcounter->inc(l_objectcacher_write_ops_blocked); perfcounter->inc(l_objectcacher_write_bytes_blocked, len); utime_t blocked = ceph_clock_now(cct) - start; perfcounter->tinc(l_objectcacher_write_time_blocked, blocked); } } // blocking wait for write. int ObjectCacher::_wait_for_write(OSDWrite *wr, uint64_t len, ObjectSet *oset, Mutex& lock, Context *onfreespace) { assert(lock.is_locked()); int ret = 0; if (max_dirty > 0) { if (block_writes_upfront) { maybe_wait_for_writeback(len); if (onfreespace) onfreespace->complete(0); } else { assert(onfreespace); finisher.queue(new C_WaitForWrite(this, len, onfreespace)); } } else { // write-thru! flush what we just wrote. Cond cond; bool done; Context *fin = block_writes_upfront ? new C_Cond(&cond, &done, &ret) : onfreespace; assert(fin); bool flushed = flush_set(oset, wr->extents, fin); assert(!flushed); // we just dirtied it, and didn't drop our lock! ldout(cct, 10) << "wait_for_write waiting on write-thru of " << len << " bytes" << dendl; if (block_writes_upfront) { while (!done) cond.Wait(lock); ldout(cct, 10) << "wait_for_write woke up, ret " << ret << dendl; if (onfreespace) onfreespace->complete(ret); } } // start writeback anyway? if (get_stat_dirty() > 0 && (uint64_t) get_stat_dirty() > target_dirty) { ldout(cct, 10) << "wait_for_write " << get_stat_dirty() << " > target " << target_dirty << ", nudging flusher" << dendl; flusher_cond.Signal(); } return ret; } void ObjectCacher::flusher_entry() { ldout(cct, 10) << "flusher start" << dendl; lock.Lock(); while (!flusher_stop) { loff_t all = get_stat_tx() + get_stat_rx() + get_stat_clean() + get_stat_dirty(); ldout(cct, 11) << "flusher " << all << " / " << max_size << ": " << get_stat_tx() << " tx, " << get_stat_rx() << " rx, " << get_stat_clean() << " clean, " << get_stat_dirty() << " dirty (" << target_dirty << " target, " << max_dirty << " max)" << dendl; loff_t actual = get_stat_dirty() + get_stat_dirty_waiting(); if (actual > 0 && (uint64_t) actual > target_dirty) { // flush some dirty pages ldout(cct, 10) << "flusher " << get_stat_dirty() << " dirty + " << get_stat_dirty_waiting() << " dirty_waiting > target " << target_dirty << ", flushing some dirty bhs" << dendl; flush(actual - target_dirty); } else { // check tail of lru for old dirty items utime_t cutoff = ceph_clock_now(cct); cutoff -= max_dirty_age; BufferHead *bh = 0; int max = MAX_FLUSH_UNDER_LOCK; while ((bh = static_cast(bh_lru_dirty.lru_get_next_expire())) != 0 && bh->last_write < cutoff && --max > 0) { ldout(cct, 10) << "flusher flushing aged dirty bh " << *bh << dendl; bh_write(bh); } if (!max) { // back off the lock to avoid starving other threads lock.Unlock(); lock.Lock(); continue; } } if (flusher_stop) break; flusher_cond.WaitInterval(cct, lock, utime_t(1,0)); } /* Wait for reads to finish. This is only possible if handling * -ENOENT made some read completions finish before their rados read * came back. If we don't wait for them, and destroy the cache, when * the rados reads do come back their callback will try to access the * no-longer-valid ObjectCacher. */ while (reads_outstanding > 0) { ldout(cct, 10) << "Waiting for all reads to complete. Number left: " << reads_outstanding << dendl; read_cond.Wait(lock); } lock.Unlock(); ldout(cct, 10) << "flusher finish" << dendl; } // ------------------------------------------------- bool ObjectCacher::set_is_empty(ObjectSet *oset) { assert(lock.is_locked()); if (oset->objects.empty()) return true; for (xlist::iterator p = oset->objects.begin(); !p.end(); ++p) if (!(*p)->is_empty()) return false; return true; } bool ObjectCacher::set_is_cached(ObjectSet *oset) { assert(lock.is_locked()); if (oset->objects.empty()) return false; for (xlist::iterator p = oset->objects.begin(); !p.end(); ++p) { Object *ob = *p; for (map::iterator q = ob->data.begin(); q != ob->data.end(); ++q) { BufferHead *bh = q->second; if (!bh->is_dirty() && !bh->is_tx()) return true; } } return false; } bool ObjectCacher::set_is_dirty_or_committing(ObjectSet *oset) { assert(lock.is_locked()); if (oset->objects.empty()) return false; for (xlist::iterator i = oset->objects.begin(); !i.end(); ++i) { Object *ob = *i; for (map::iterator p = ob->data.begin(); p != ob->data.end(); ++p) { BufferHead *bh = p->second; if (bh->is_dirty() || bh->is_tx()) return true; } } return false; } // purge. non-blocking. violently removes dirty buffers from cache. void ObjectCacher::purge(Object *ob) { assert(lock.is_locked()); ldout(cct, 10) << "purge " << *ob << dendl; ob->truncate(0); } // flush. non-blocking. no callback. // true if clean, already flushed. // false if we wrote something. // be sloppy about the ranges and flush any buffer it touches bool ObjectCacher::flush(Object *ob, loff_t offset, loff_t length) { assert(lock.is_locked()); bool clean = true; ldout(cct, 10) << "flush " << *ob << " " << offset << "~" << length << dendl; for (map::iterator p = ob->data_lower_bound(offset); p != ob->data.end(); ++p) { BufferHead *bh = p->second; ldout(cct, 20) << "flush " << *bh << dendl; if (length && bh->start() > offset+length) { break; } if (bh->is_tx()) { clean = false; continue; } if (!bh->is_dirty()) { continue; } bh_write(bh); clean = false; } return clean; } bool ObjectCacher::_flush_set_finish(C_GatherBuilder *gather, Context *onfinish) { assert(lock.is_locked()); if (gather->has_subs()) { gather->set_finisher(onfinish); gather->activate(); return false; } ldout(cct, 10) << "flush_set has no dirty|tx bhs" << dendl; onfinish->complete(0); return true; } // flush. non-blocking, takes callback. // returns true if already flushed bool ObjectCacher::flush_set(ObjectSet *oset, Context *onfinish) { assert(lock.is_locked()); assert(onfinish != NULL); if (oset->objects.empty()) { ldout(cct, 10) << "flush_set on " << oset << " dne" << dendl; onfinish->complete(0); return true; } ldout(cct, 10) << "flush_set " << oset << dendl; // we'll need to wait for all objects to flush! C_GatherBuilder gather(cct); for (xlist::iterator i = oset->objects.begin(); !i.end(); ++i) { Object *ob = *i; if (ob->dirty_or_tx == 0) continue; if (!flush(ob, 0, 0)) { // we'll need to gather... ldout(cct, 10) << "flush_set " << oset << " will wait for ack tid " << ob->last_write_tid << " on " << *ob << dendl; ob->waitfor_commit[ob->last_write_tid].push_back(gather.new_sub()); } } return _flush_set_finish(&gather, onfinish); } // flush. non-blocking, takes callback. // returns true if already flushed bool ObjectCacher::flush_set(ObjectSet *oset, vector& exv, Context *onfinish) { assert(lock.is_locked()); assert(onfinish != NULL); if (oset->objects.empty()) { ldout(cct, 10) << "flush_set on " << oset << " dne" << dendl; onfinish->complete(0); return true; } ldout(cct, 10) << "flush_set " << oset << " on " << exv.size() << " ObjectExtents" << dendl; // we'll need to wait for all objects to flush! C_GatherBuilder gather(cct); for (vector::iterator p = exv.begin(); p != exv.end(); ++p) { ObjectExtent &ex = *p; sobject_t soid(ex.oid, CEPH_NOSNAP); if (objects[oset->poolid].count(soid) == 0) continue; Object *ob = objects[oset->poolid][soid]; ldout(cct, 20) << "flush_set " << oset << " ex " << ex << " ob " << soid << " " << ob << dendl; if (!flush(ob, ex.offset, ex.length)) { // we'll need to gather... ldout(cct, 10) << "flush_set " << oset << " will wait for ack tid " << ob->last_write_tid << " on " << *ob << dendl; ob->waitfor_commit[ob->last_write_tid].push_back(gather.new_sub()); } } return _flush_set_finish(&gather, onfinish); } void ObjectCacher::purge_set(ObjectSet *oset) { assert(lock.is_locked()); if (oset->objects.empty()) { ldout(cct, 10) << "purge_set on " << oset << " dne" << dendl; return; } ldout(cct, 10) << "purge_set " << oset << dendl; for (xlist::iterator i = oset->objects.begin(); !i.end(); ++i) { Object *ob = *i; purge(ob); } } loff_t ObjectCacher::release(Object *ob) { assert(lock.is_locked()); list clean; loff_t o_unclean = 0; for (map::iterator p = ob->data.begin(); p != ob->data.end(); ++p) { BufferHead *bh = p->second; if (bh->is_clean() || bh->is_zero()) clean.push_back(bh); else o_unclean += bh->length(); } for (list::iterator p = clean.begin(); p != clean.end(); ++p) { bh_remove(ob, *p); delete *p; } if (ob->can_close()) { ldout(cct, 10) << "release trimming " << *ob << dendl; close_object(ob); assert(o_unclean == 0); return 0; } if (ob->complete) { ldout(cct, 10) << "release clearing complete on " << *ob << dendl; ob->complete = false; } if (!ob->exists) { ldout(cct, 10) << "release setting exists on " << *ob << dendl; ob->exists = true; } return o_unclean; } loff_t ObjectCacher::release_set(ObjectSet *oset) { assert(lock.is_locked()); // return # bytes not clean (and thus not released). loff_t unclean = 0; if (oset->objects.empty()) { ldout(cct, 10) << "release_set on " << oset << " dne" << dendl; return 0; } ldout(cct, 10) << "release_set " << oset << dendl; xlist::iterator q; for (xlist::iterator p = oset->objects.begin(); !p.end(); ) { q = p; ++q; Object *ob = *p; loff_t o_unclean = release(ob); unclean += o_unclean; if (o_unclean) ldout(cct, 10) << "release_set " << oset << " " << *ob << " has " << o_unclean << " bytes left" << dendl; p = q; } if (unclean) { ldout(cct, 10) << "release_set " << oset << ", " << unclean << " bytes left" << dendl; } return unclean; } uint64_t ObjectCacher::release_all() { assert(lock.is_locked()); ldout(cct, 10) << "release_all" << dendl; uint64_t unclean = 0; vector >::iterator i = objects.begin(); while (i != objects.end()) { ceph::unordered_map::iterator p = i->begin(); while (p != i->end()) { ceph::unordered_map::iterator n = p; ++n; Object *ob = p->second; loff_t o_unclean = release(ob); unclean += o_unclean; if (o_unclean) ldout(cct, 10) << "release_all " << *ob << " has " << o_unclean << " bytes left" << dendl; p = n; } ++i; } if (unclean) { ldout(cct, 10) << "release_all unclean " << unclean << " bytes left" << dendl; } return unclean; } void ObjectCacher::clear_nonexistence(ObjectSet *oset) { assert(lock.is_locked()); ldout(cct, 10) << "clear_nonexistence() " << oset << dendl; for (xlist::iterator p = oset->objects.begin(); !p.end(); ++p) { Object *ob = *p; if (!ob->exists) { ldout(cct, 10) << " setting exists and complete on " << *ob << dendl; ob->exists = true; ob->complete = false; } for (xlist::iterator q = ob->reads.begin(); !q.end(); ++q) { C_ReadFinish *comp = *q; comp->distrust_enoent(); } } } /** * discard object extents from an ObjectSet by removing the objects in exls from the in-memory oset. */ void ObjectCacher::discard_set(ObjectSet *oset, vector& exls) { assert(lock.is_locked()); if (oset->objects.empty()) { ldout(cct, 10) << "discard_set on " << oset << " dne" << dendl; return; } ldout(cct, 10) << "discard_set " << oset << dendl; bool were_dirty = oset->dirty_or_tx > 0; for (vector::iterator p = exls.begin(); p != exls.end(); ++p) { ldout(cct, 10) << "discard_set " << oset << " ex " << *p << dendl; ObjectExtent &ex = *p; sobject_t soid(ex.oid, CEPH_NOSNAP); if (objects[oset->poolid].count(soid) == 0) continue; Object *ob = objects[oset->poolid][soid]; ob->discard(ex.offset, ex.length); } // did we truncate off dirty data? if (flush_set_callback && were_dirty && oset->dirty_or_tx == 0) flush_set_callback(flush_set_callback_arg, oset); } void ObjectCacher::verify_stats() const { assert(lock.is_locked()); ldout(cct, 10) << "verify_stats" << dendl; loff_t clean = 0, zero = 0, dirty = 0, rx = 0, tx = 0, missing = 0, error = 0; for (vector >::const_iterator i = objects.begin(); i != objects.end(); ++i) { for (ceph::unordered_map::const_iterator p = i->begin(); p != i->end(); ++p) { Object *ob = p->second; for (map::const_iterator q = ob->data.begin(); q != ob->data.end(); ++q) { BufferHead *bh = q->second; switch (bh->get_state()) { case BufferHead::STATE_MISSING: missing += bh->length(); break; case BufferHead::STATE_CLEAN: clean += bh->length(); break; case BufferHead::STATE_ZERO: zero += bh->length(); break; case BufferHead::STATE_DIRTY: dirty += bh->length(); break; case BufferHead::STATE_TX: tx += bh->length(); break; case BufferHead::STATE_RX: rx += bh->length(); break; case BufferHead::STATE_ERROR: error += bh->length(); break; default: assert(0); } } } } ldout(cct, 10) << " clean " << clean << " rx " << rx << " tx " << tx << " dirty " << dirty << " missing " << missing << " error " << error << dendl; assert(clean == stat_clean); assert(rx == stat_rx); assert(tx == stat_tx); assert(dirty == stat_dirty); assert(missing == stat_missing); assert(zero == stat_zero); assert(error == stat_error); } void ObjectCacher::bh_stat_add(BufferHead *bh) { assert(lock.is_locked()); switch (bh->get_state()) { case BufferHead::STATE_MISSING: stat_missing += bh->length(); break; case BufferHead::STATE_CLEAN: stat_clean += bh->length(); break; case BufferHead::STATE_ZERO: stat_zero += bh->length(); break; case BufferHead::STATE_DIRTY: stat_dirty += bh->length(); bh->ob->dirty_or_tx += bh->length(); bh->ob->oset->dirty_or_tx += bh->length(); break; case BufferHead::STATE_TX: stat_tx += bh->length(); bh->ob->dirty_or_tx += bh->length(); bh->ob->oset->dirty_or_tx += bh->length(); break; case BufferHead::STATE_RX: stat_rx += bh->length(); break; case BufferHead::STATE_ERROR: stat_error += bh->length(); break; default: assert(0 == "bh_stat_add: invalid bufferhead state"); } if (get_stat_dirty_waiting() > 0) stat_cond.Signal(); } void ObjectCacher::bh_stat_sub(BufferHead *bh) { assert(lock.is_locked()); switch (bh->get_state()) { case BufferHead::STATE_MISSING: stat_missing -= bh->length(); break; case BufferHead::STATE_CLEAN: stat_clean -= bh->length(); break; case BufferHead::STATE_ZERO: stat_zero -= bh->length(); break; case BufferHead::STATE_DIRTY: stat_dirty -= bh->length(); bh->ob->dirty_or_tx -= bh->length(); bh->ob->oset->dirty_or_tx -= bh->length(); break; case BufferHead::STATE_TX: stat_tx -= bh->length(); bh->ob->dirty_or_tx -= bh->length(); bh->ob->oset->dirty_or_tx -= bh->length(); break; case BufferHead::STATE_RX: stat_rx -= bh->length(); break; case BufferHead::STATE_ERROR: stat_error -= bh->length(); break; default: assert(0 == "bh_stat_sub: invalid bufferhead state"); } } void ObjectCacher::bh_set_state(BufferHead *bh, int s) { assert(lock.is_locked()); // move between lru lists? if (s == BufferHead::STATE_DIRTY && bh->get_state() != BufferHead::STATE_DIRTY) { bh_lru_rest.lru_remove(bh); bh_lru_dirty.lru_insert_top(bh); dirty_bh.insert(bh); } if (s != BufferHead::STATE_DIRTY && bh->get_state() == BufferHead::STATE_DIRTY) { bh_lru_dirty.lru_remove(bh); bh_lru_rest.lru_insert_top(bh); dirty_bh.erase(bh); } if (s != BufferHead::STATE_ERROR && bh->get_state() == BufferHead::STATE_ERROR) { bh->error = 0; } // set state bh_stat_sub(bh); bh->set_state(s); bh_stat_add(bh); } void ObjectCacher::bh_add(Object *ob, BufferHead *bh) { assert(lock.is_locked()); ldout(cct, 30) << "bh_add " << *ob << " " << *bh << dendl; ob->add_bh(bh); if (bh->is_dirty()) { bh_lru_dirty.lru_insert_top(bh); dirty_bh.insert(bh); } else { bh_lru_rest.lru_insert_top(bh); } bh_stat_add(bh); } void ObjectCacher::bh_remove(Object *ob, BufferHead *bh) { assert(lock.is_locked()); ldout(cct, 30) << "bh_remove " << *ob << " " << *bh << dendl; ob->remove_bh(bh); if (bh->is_dirty()) { bh_lru_dirty.lru_remove(bh); dirty_bh.erase(bh); } else { bh_lru_rest.lru_remove(bh); } bh_stat_sub(bh); } ceph-0.80.11/src/osdc/Journaler.h0000664000175100017510000002741312623076744020535 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ /* Journaler * * This class stripes a serial log over objects on the store. Four logical pointers: * * write_pos - where we're writing new entries * unused_field - where we're reading old entires * expire_pos - what is deemed "old" by user * trimmed_pos - where we're expiring old items * * trimmed_pos <= expire_pos <= unused_field <= write_pos. * * Often, unused_field <= write_pos (as with MDS log). During recovery, write_pos is undefined * until the end of the log is discovered. * * A "head" struct at the beginning of the log is used to store metadata at * regular intervals. The basic invariants include: * * head.unused_field <= unused_field -- the head may "lag", since it's updated lazily. * head.write_pos <= write_pos * head.expire_pos <= expire_pos * head.trimmed_pos <= trimmed_pos * * More significantly, * * head.expire_pos >= trimmed_pos -- this ensures we can find the "beginning" of the log * as last recorded, before it is trimmed. trimming will * block until a sufficiently current expire_pos is committed. * * To recover log state, we simply start at the last write_pos in the head, and probe the * object sequence sizes until we read the end. * * Head struct is stored in the first object. Actual journal starts after layout.period() bytes. * */ #ifndef CEPH_JOURNALER_H #define CEPH_JOURNALER_H #include "Objecter.h" #include "Filer.h" #include #include class CephContext; class Context; class PerfCounters; class Journaler { public: CephContext *cct; // this goes at the head of the log "file". struct Header { uint64_t trimmed_pos; uint64_t expire_pos; uint64_t unused_field; uint64_t write_pos; string magic; ceph_file_layout layout; Header(const char *m="") : trimmed_pos(0), expire_pos(0), unused_field(0), write_pos(0), magic(m) { memset(&layout, 0, sizeof(layout)); } void encode(bufferlist &bl) const { __u8 struct_v = 1; ::encode(struct_v, bl); ::encode(magic, bl); ::encode(trimmed_pos, bl); ::encode(expire_pos, bl); ::encode(unused_field, bl); ::encode(write_pos, bl); ::encode(layout, bl); } void decode(bufferlist::iterator &bl) { __u8 struct_v; ::decode(struct_v, bl); ::decode(magic, bl); ::decode(trimmed_pos, bl); ::decode(expire_pos, bl); ::decode(unused_field, bl); ::decode(write_pos, bl); ::decode(layout, bl); } void dump(Formatter *f) const { f->open_object_section("journal_header"); { f->dump_string("magic", magic); f->dump_unsigned("write_pos", write_pos); f->dump_unsigned("expire_pos", expire_pos); f->dump_unsigned("trimmed_pos", trimmed_pos); f->open_object_section("layout"); { f->dump_unsigned("stripe_unit", layout.fl_stripe_unit); f->dump_unsigned("stripe_count", layout.fl_stripe_unit); f->dump_unsigned("object_size", layout.fl_stripe_unit); f->dump_unsigned("cas_hash", layout.fl_stripe_unit); f->dump_unsigned("object_stripe_unit", layout.fl_stripe_unit); f->dump_unsigned("pg_pool", layout.fl_stripe_unit); } f->close_section(); // layout } f->close_section(); // journal_header } static void generate_test_instances(list &ls) { ls.push_back(new Header()); ls.push_back(new Header()); ls.back()->trimmed_pos = 1; ls.back()->expire_pos = 2; ls.back()->unused_field = 3; ls.back()->write_pos = 4; ls.back()->magic = "magique"; } } last_written, last_committed; WRITE_CLASS_ENCODER(Header) private: // me inodeno_t ino; int64_t pg_pool; bool readonly; ceph_file_layout layout; const char *magic; Objecter *objecter; Filer filer; PerfCounters *logger; int logger_key_lat; SafeTimer *timer; class C_DelayFlush : public Context { Journaler *journaler; public: C_DelayFlush(Journaler *j) : journaler(j) {} void finish(int r) { journaler->delay_flush_event = 0; journaler->_do_flush(); } } *delay_flush_event; // my state static const int STATE_UNDEF = 0; static const int STATE_READHEAD = 1; static const int STATE_PROBING = 2; static const int STATE_ACTIVE = 3; static const int STATE_REREADHEAD = 4; static const int STATE_REPROBING = 5; int state; int error; // header utime_t last_wrote_head; void _finish_write_head(int r, Header &wrote, Context *oncommit); class C_WriteHead; friend class C_WriteHead; list waitfor_recover; void read_head(Context *on_finish, bufferlist *bl); void _finish_read_head(int r, bufferlist& bl); void _finish_reread_head(int r, bufferlist& bl, Context *finish); void probe(Context *finish, uint64_t *end); void _finish_probe_end(int r, uint64_t end); void _finish_reprobe(int r, uint64_t end, Context *onfinish); void _finish_reread_head_and_probe(int r, Context *onfinish); class C_ReadHead; friend class C_ReadHead; class C_ProbeEnd; friend class C_ProbeEnd; class C_RereadHead; friend class C_RereadHead; class C_ReProbe; friend class C_ReProbe; class C_RereadHeadProbe; friend class C_RereadHeadProbe; // writer uint64_t prezeroing_pos; uint64_t prezero_pos; // we zero journal space ahead of write_pos to avoid problems with tail probing uint64_t write_pos; // logical write position, where next entry will go uint64_t flush_pos; // where we will flush. if write_pos>flush_pos, we're buffering writes. uint64_t safe_pos; // what has been committed safely to disk. bufferlist write_buf; // write buffer. flush_pos + write_buf.length() == write_pos. bool waiting_for_zero; interval_set pending_zero; // non-contig bits we've zeroed std::set pending_safe; std::map > waitfor_safe; // when safe through given offset void _do_flush(unsigned amount=0); void _finish_flush(int r, uint64_t start, utime_t stamp); class C_Flush; friend class C_Flush; // reader uint64_t read_pos; // logical read position, where next entry starts. uint64_t requested_pos; // what we've requested from OSD. uint64_t received_pos; // what we've received from OSD. bufferlist read_buf; // read buffer. unused_field + read_buf.length() == prefetch_pos. map prefetch_buf; uint64_t fetch_len; // how much to read at a time uint64_t temp_fetch_len; // for wait_for_readable() Context *on_readable; Context *on_write_error; void _finish_read(int r, uint64_t offset, bufferlist &bl); // read completion callback void _assimilate_prefetch(); void _issue_read(uint64_t len); // read some more void _prefetch(); // maybe read ahead class C_Read; friend class C_Read; class C_RetryRead; friend class C_RetryRead; // trimmer uint64_t expire_pos; // what we're allowed to trim to uint64_t trimming_pos; // what we've requested to trim through uint64_t trimmed_pos; // what has been trimmed map > waitfor_trim; void _trim_finish(int r, uint64_t to); class C_Trim; friend class C_Trim; void _issue_prezero(); void _prezeroed(int r, uint64_t from, uint64_t len); friend struct C_Journaler_Prezero; // only init_headers when following or first reading off-disk void init_headers(Header& h) { assert(readonly || state == STATE_READHEAD || state == STATE_REREADHEAD); last_written = last_committed = h; } /** * handle a write error * * called when we get an objecter error on a write. * * @param r error code */ void handle_write_error(int r); public: Journaler(inodeno_t ino_, int64_t pool, const char *mag, Objecter *obj, PerfCounters *l, int lkey, SafeTimer *tim) : cct(obj->cct), last_written(mag), last_committed(mag), ino(ino_), pg_pool(pool), readonly(true), magic(mag), objecter(obj), filer(objecter), logger(l), logger_key_lat(lkey), timer(tim), delay_flush_event(0), state(STATE_UNDEF), error(0), prezeroing_pos(0), prezero_pos(0), write_pos(0), flush_pos(0), safe_pos(0), waiting_for_zero(false), read_pos(0), requested_pos(0), received_pos(0), fetch_len(0), temp_fetch_len(0), on_readable(0), on_write_error(NULL), expire_pos(0), trimming_pos(0), trimmed_pos(0) { memset(&layout, 0, sizeof(layout)); } void reset() { assert(state == STATE_ACTIVE); readonly = true; delay_flush_event = 0; state = STATE_UNDEF; error = 0; prezeroing_pos = 0; prezero_pos = 0; write_pos = 0; flush_pos = 0; safe_pos = 0; read_pos = 0; requested_pos = 0; received_pos = 0; fetch_len = 0; assert(!on_readable); expire_pos = 0; trimming_pos = 0; trimmed_pos = 0; waiting_for_zero = false; } // me //void open(Context *onopen); //void claim(Context *onclaim, msg_addr_t from); /* reset * NOTE: we assume the caller knows/has ensured that any objects * in our sequence do not exist.. e.g. after a MKFS. this is _not_ * an "erase" method. */ void create(ceph_file_layout *layout); void recover(Context *onfinish); void reread_head(Context *onfinish); void reprobe(Context *onfinish); void reread_head_and_probe(Context *onfinish); void write_head(Context *onsave=0); void set_layout(ceph_file_layout *l); void set_readonly(); void set_writeable(); bool is_readonly() { return readonly; } bool is_active() { return state == STATE_ACTIVE; } int get_error() { return error; } uint64_t get_write_pos() const { return write_pos; } uint64_t get_write_safe_pos() const { return safe_pos; } uint64_t get_read_pos() const { return read_pos; } uint64_t get_expire_pos() const { return expire_pos; } uint64_t get_trimmed_pos() const { return trimmed_pos; } uint64_t get_layout_period() const { return (uint64_t)layout.fl_stripe_count * (uint64_t)layout.fl_object_size; } ceph_file_layout& get_layout() { return layout; } // write uint64_t append_entry(bufferlist& bl); void wait_for_flush(Context *onsafe = 0); void flush(Context *onsafe = 0); // read void set_read_pos(int64_t p) { assert(requested_pos == received_pos); // we can't cope w/ in-progress read right now. read_pos = requested_pos = received_pos = p; read_buf.clear(); } bool _is_readable(); bool is_readable(); bool try_read_entry(bufferlist& bl); void wait_for_readable(Context *onfinish); void set_write_pos(int64_t p) { prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = p; } /** * set write error callback * * Set a callback/context to trigger if we get a write error from * the objecter. This may be from an explicit request (e.g., flush) * or something async the journaler did on its own (e.g., journal * header update). * * It is only used once; if the caller continues to use the * Journaler and wants to hear about errors, it needs to reset the * error_handler. * * @param c callback/context to trigger on error */ void set_write_error_handler(Context *c) { assert(!on_write_error); on_write_error = c; } // trim void set_expire_pos(int64_t ep) { expire_pos = ep; } void set_trimmed_pos(int64_t p) { trimming_pos = trimmed_pos = p; } void trim(); void trim_tail() { assert(!readonly); _issue_prezero(); } }; WRITE_CLASS_ENCODER(Journaler::Header) #endif ceph-0.80.11/src/osdc/Journaler.cc0000664000175100017510000007032212623076744020670 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/perf_counters.h" #include "common/dout.h" #include "include/Context.h" #include "msg/Messenger.h" #include "osdc/Journaler.h" #include "common/errno.h" #include "include/assert.h" #define dout_subsys ceph_subsys_journaler #undef dout_prefix #define dout_prefix *_dout << objecter->messenger->get_myname() << ".journaler" << (readonly ? "(ro) ":"(rw) ") void Journaler::set_readonly() { ldout(cct, 1) << "set_readonly" << dendl; readonly = true; } void Journaler::set_writeable() { ldout(cct, 1) << "set_writeable" << dendl; readonly = false; } void Journaler::create(ceph_file_layout *l) { assert(!readonly); ldout(cct, 1) << "create blank journal" << dendl; state = STATE_ACTIVE; set_layout(l); prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = read_pos = requested_pos = received_pos = expire_pos = trimming_pos = trimmed_pos = layout.fl_stripe_count * layout.fl_object_size; } void Journaler::set_layout(ceph_file_layout *l) { layout = *l; assert(layout.fl_pg_pool == pg_pool); last_written.layout = layout; last_committed.layout = layout; // prefetch intelligently. // (watch out, this is big if you use big objects or weird striping) uint64_t periods = cct->_conf->journaler_prefetch_periods; if (periods < 2) periods = 2; // we need at least 2 periods to make progress. fetch_len = layout.fl_stripe_count * layout.fl_object_size * periods; } /***************** HEADER *******************/ ostream& operator<<(ostream& out, Journaler::Header &h) { return out << "loghead(trim " << h.trimmed_pos << ", expire " << h.expire_pos << ", write " << h.write_pos << ")"; } class Journaler::C_ReadHead : public Context { Journaler *ls; public: bufferlist bl; C_ReadHead(Journaler *l) : ls(l) {} void finish(int r) { ls->_finish_read_head(r, bl); } }; class Journaler::C_RereadHead : public Context { Journaler *ls; Context *onfinish; public: bufferlist bl; C_RereadHead(Journaler *l, Context *onfinish_) : ls (l), onfinish(onfinish_){} void finish(int r) { ls->_finish_reread_head(r, bl, onfinish); } }; class Journaler::C_ProbeEnd : public Context { Journaler *ls; public: uint64_t end; C_ProbeEnd(Journaler *l) : ls(l), end(-1) {} void finish(int r) { ls->_finish_probe_end(r, end); } }; class Journaler::C_ReProbe : public Context { Journaler *ls; Context *onfinish; public: uint64_t end; C_ReProbe(Journaler *l, Context *onfinish_) : ls(l), onfinish(onfinish_), end(0) {} void finish(int r) { ls->_finish_reprobe(r, end, onfinish); } }; void Journaler::recover(Context *onread) { ldout(cct, 1) << "recover start" << dendl; assert(state != STATE_ACTIVE); assert(readonly); if (onread) waitfor_recover.push_back(onread); if (state != STATE_UNDEF) { ldout(cct, 1) << "recover - already recoverying" << dendl; return; } ldout(cct, 1) << "read_head" << dendl; state = STATE_READHEAD; C_ReadHead *fin = new C_ReadHead(this); read_head(fin, &fin->bl); } void Journaler::read_head(Context *on_finish, bufferlist *bl) { assert(state == STATE_READHEAD || state == STATE_REREADHEAD); object_t oid = file_object_t(ino, 0); object_locator_t oloc(pg_pool); objecter->read_full(oid, oloc, CEPH_NOSNAP, bl, 0, on_finish); } /** * Re-read the head from disk, and set the write_pos, expire_pos, trimmed_pos * from the on-disk header. This switches the state to STATE_REREADHEAD for * the duration, and you shouldn't start a re-read while other operations are * in-flight, nor start other operations while a re-read is in progress. * Also, don't call this until the Journaler has finished its recovery and has * gone STATE_ACTIVE! */ void Journaler::reread_head(Context *onfinish) { ldout(cct, 10) << "reread_head" << dendl; assert(state == STATE_ACTIVE); state = STATE_REREADHEAD; C_RereadHead *fin = new C_RereadHead(this, onfinish); read_head(fin, &fin->bl); } void Journaler::_finish_reread_head(int r, bufferlist& bl, Context *finish) { //read on-disk header into assert(bl.length() || r < 0 ); // unpack header Header h; bufferlist::iterator p = bl.begin(); ::decode(h, p); prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = h.write_pos; expire_pos = h.expire_pos; trimmed_pos = trimming_pos = h.trimmed_pos; init_headers(h); state = STATE_ACTIVE; finish->complete(r); } void Journaler::_finish_read_head(int r, bufferlist& bl) { assert(state == STATE_READHEAD); if (r!=0) { ldout(cct, 0) << "error getting journal off disk" << dendl; list ls; ls.swap(waitfor_recover); finish_contexts(cct, ls, r); return; } if (bl.length() == 0) { ldout(cct, 1) << "_finish_read_head r=" << r << " read 0 bytes, assuming empty log" << dendl; state = STATE_ACTIVE; list ls; ls.swap(waitfor_recover); finish_contexts(cct, ls, 0); return; } // unpack header Header h; bufferlist::iterator p = bl.begin(); ::decode(h, p); if (h.magic != magic) { ldout(cct, 0) << "on disk magic '" << h.magic << "' != my magic '" << magic << "'" << dendl; list ls; ls.swap(waitfor_recover); finish_contexts(cct, ls, -EINVAL); return; } prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = h.write_pos; read_pos = requested_pos = received_pos = expire_pos = h.expire_pos; trimmed_pos = trimming_pos = h.trimmed_pos; init_headers(h); set_layout(&h.layout); ldout(cct, 1) << "_finish_read_head " << h << ". probing for end of log (from " << write_pos << ")..." << dendl; C_ProbeEnd *fin = new C_ProbeEnd(this); state = STATE_PROBING; probe(fin, &fin->end); } void Journaler::probe(Context *finish, uint64_t *end) { ldout(cct, 1) << "probing for end of the log" << dendl; assert(state == STATE_PROBING || state == STATE_REPROBING); // probe the log filer.probe(ino, &layout, CEPH_NOSNAP, write_pos, end, 0, true, 0, finish); } void Journaler::reprobe(Context *finish) { ldout(cct, 10) << "reprobe" << dendl; assert(state == STATE_ACTIVE); state = STATE_REPROBING; C_ReProbe *fin = new C_ReProbe(this, finish); probe(fin, &fin->end); } void Journaler::_finish_reprobe(int r, uint64_t new_end, Context *onfinish) { assert(new_end >= write_pos || r < 0); ldout(cct, 1) << "_finish_reprobe new_end = " << new_end << " (header had " << write_pos << ")." << dendl; prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = new_end; state = STATE_ACTIVE; onfinish->complete(r); } void Journaler::_finish_probe_end(int r, uint64_t end) { assert(state == STATE_PROBING); if (r < 0) { // error in probing goto out; } if (((int64_t)end) == -1) { end = write_pos; ldout(cct, 1) << "_finish_probe_end write_pos = " << end << " (header had " << write_pos << "). log was empty. recovered." << dendl; assert(0); // hrm. } else { assert(end >= write_pos); ldout(cct, 1) << "_finish_probe_end write_pos = " << end << " (header had " << write_pos << "). recovered." << dendl; } state = STATE_ACTIVE; prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = end; out: // done. list ls; ls.swap(waitfor_recover); finish_contexts(cct, ls, r); } class Journaler::C_RereadHeadProbe : public Context { Journaler *ls; Context *final_finish; public: C_RereadHeadProbe(Journaler *l, Context *finish) : ls(l), final_finish(finish) {} void finish(int r) { ls->_finish_reread_head_and_probe(r, final_finish); } }; void Journaler::reread_head_and_probe(Context *onfinish) { assert(state == STATE_ACTIVE); reread_head(new C_RereadHeadProbe(this, onfinish)); } void Journaler::_finish_reread_head_and_probe(int r, Context *onfinish) { assert(!r); //if we get an error, we're boned reprobe(onfinish); } // WRITING class Journaler::C_WriteHead : public Context { public: Journaler *ls; Header h; Context *oncommit; C_WriteHead(Journaler *l, Header& h_, Context *c) : ls(l), h(h_), oncommit(c) {} void finish(int r) { ls->_finish_write_head(r, h, oncommit); } }; void Journaler::write_head(Context *oncommit) { assert(!readonly); assert(state == STATE_ACTIVE); last_written.trimmed_pos = trimmed_pos; last_written.expire_pos = expire_pos; last_written.unused_field = expire_pos; last_written.write_pos = safe_pos; ldout(cct, 10) << "write_head " << last_written << dendl; last_wrote_head = ceph_clock_now(cct); bufferlist bl; ::encode(last_written, bl); SnapContext snapc; object_t oid = file_object_t(ino, 0); object_locator_t oloc(pg_pool); objecter->write_full(oid, oloc, snapc, bl, ceph_clock_now(cct), 0, NULL, new C_WriteHead(this, last_written, oncommit)); } void Journaler::_finish_write_head(int r, Header &wrote, Context *oncommit) { if (r < 0) { lderr(cct) << "_finish_write_head got " << cpp_strerror(r) << dendl; handle_write_error(r); return; } assert(!readonly); ldout(cct, 10) << "_finish_write_head " << wrote << dendl; last_committed = wrote; if (oncommit) { oncommit->complete(r); } trim(); // trim? } /***************** WRITING *******************/ class Journaler::C_Flush : public Context { Journaler *ls; uint64_t start; utime_t stamp; public: C_Flush(Journaler *l, int64_t s, utime_t st) : ls(l), start(s), stamp(st) {} void finish(int r) { ls->_finish_flush(r, start, stamp); } }; void Journaler::_finish_flush(int r, uint64_t start, utime_t stamp) { assert(!readonly); if (r < 0) { lderr(cct) << "_finish_flush got " << cpp_strerror(r) << dendl; handle_write_error(r); return; } assert(start >= safe_pos); assert(start < flush_pos); // calc latency? if (logger) { utime_t lat = ceph_clock_now(cct); lat -= stamp; logger->tinc(logger_key_lat, lat); } // adjust safe_pos assert(pending_safe.count(start)); pending_safe.erase(start); if (pending_safe.empty()) safe_pos = flush_pos; else safe_pos = *pending_safe.begin(); ldout(cct, 10) << "_finish_flush safe from " << start << ", pending_safe " << pending_safe << ", (prezeroing/prezero)/write/flush/safe positions now " << "(" << prezeroing_pos << "/" << prezero_pos << ")/" << write_pos << "/" << flush_pos << "/" << safe_pos << dendl; // kick waiters <= safe_pos while (!waitfor_safe.empty()) { if (waitfor_safe.begin()->first > safe_pos) break; finish_contexts(cct, waitfor_safe.begin()->second); waitfor_safe.erase(waitfor_safe.begin()); } } uint64_t Journaler::append_entry(bufferlist& bl) { assert(!readonly); uint32_t s = bl.length(); if (!cct->_conf->journaler_allow_split_entries) { // will we span a stripe boundary? int p = layout.fl_stripe_unit; if (write_pos / p != (write_pos + (int64_t)(bl.length() + sizeof(s))) / p) { // yes. // move write_pos forward. int64_t owp = write_pos; write_pos += p; write_pos -= (write_pos % p); // pad with zeros. bufferptr bp(write_pos - owp); bp.zero(); assert(bp.length() >= 4); write_buf.push_back(bp); // now flush. flush(); ldout(cct, 12) << "append_entry skipped " << (write_pos-owp) << " bytes to " << write_pos << " to avoid spanning stripe boundary" << dendl; } } ldout(cct, 10) << "append_entry len " << bl.length() << " to " << write_pos << "~" << (bl.length() + sizeof(uint32_t)) << dendl; // append ::encode(s, write_buf); write_buf.claim_append(bl); write_pos += sizeof(s) + s; // flush previous object? uint64_t su = get_layout_period(); assert(su > 0); uint64_t write_off = write_pos % su; uint64_t write_obj = write_pos / su; uint64_t flush_obj = flush_pos / su; if (write_obj != flush_obj) { ldout(cct, 10) << " flushing completed object(s) (su " << su << " wro " << write_obj << " flo " << flush_obj << ")" << dendl; _do_flush(write_buf.length() - write_off); } return write_pos; } void Journaler::_do_flush(unsigned amount) { if (write_pos == flush_pos) return; assert(write_pos > flush_pos); assert(!readonly); // flush unsigned len = write_pos - flush_pos; assert(len == write_buf.length()); if (amount && amount < len) len = amount; // zero at least two full periods ahead. this ensures // that the next object will not exist. uint64_t period = get_layout_period(); if (flush_pos + len + 2*period > prezero_pos) { _issue_prezero(); int64_t newlen = prezero_pos - flush_pos - period; if (newlen <= 0) { ldout(cct, 10) << "_do_flush wanted to do " << flush_pos << "~" << len << " already too close to prezero_pos " << prezero_pos << ", zeroing first" << dendl; waiting_for_zero = true; return; } if (newlen < len) { ldout(cct, 10) << "_do_flush wanted to do " << flush_pos << "~" << len << " but hit prezero_pos " << prezero_pos << ", will do " << flush_pos << "~" << newlen << dendl; len = newlen; } else { waiting_for_zero = false; } } else { waiting_for_zero = false; } ldout(cct, 10) << "_do_flush flushing " << flush_pos << "~" << len << dendl; // submit write for anything pending // flush _start_ pos to _finish_flush utime_t now = ceph_clock_now(cct); SnapContext snapc; Context *onsafe = new C_Flush(this, flush_pos, now); // on COMMIT pending_safe.insert(flush_pos); bufferlist write_bl; // adjust pointers if (len == write_buf.length()) { write_bl.swap(write_buf); } else { write_buf.splice(0, len, &write_bl); } filer.write(ino, &layout, snapc, flush_pos, len, write_bl, ceph_clock_now(cct), 0, NULL, onsafe); flush_pos += len; assert(write_buf.length() == write_pos - flush_pos); ldout(cct, 10) << "_do_flush (prezeroing/prezero)/write/flush/safe pointers now at " << "(" << prezeroing_pos << "/" << prezero_pos << ")/" << write_pos << "/" << flush_pos << "/" << safe_pos << dendl; _issue_prezero(); } void Journaler::wait_for_flush(Context *onsafe) { assert(!readonly); // all flushed and safe? if (write_pos == safe_pos) { assert(write_buf.length() == 0); ldout(cct, 10) << "flush nothing to flush, (prezeroing/prezero)/write/flush/safe pointers at " << "(" << prezeroing_pos << "/" << prezero_pos << ")/" << write_pos << "/" << flush_pos << "/" << safe_pos << dendl; if (onsafe) { onsafe->complete(0); onsafe = 0; } return; } // queue waiter if (onsafe) waitfor_safe[write_pos].push_back(onsafe); } void Journaler::flush(Context *onsafe) { assert(!readonly); if (write_pos == flush_pos) { assert(write_buf.length() == 0); ldout(cct, 10) << "flush nothing to flush, (prezeroing/prezero)/write/flush/safe pointers at " << "(" << prezeroing_pos << "/" << prezero_pos << ")/" << write_pos << "/" << flush_pos << "/" << safe_pos << dendl; if (onsafe) { onsafe->complete(0); } } else { if (1) { // maybe buffer if (write_buf.length() < cct->_conf->journaler_batch_max) { // delay! schedule an event. ldout(cct, 20) << "flush delaying flush" << dendl; if (delay_flush_event) timer->cancel_event(delay_flush_event); delay_flush_event = new C_DelayFlush(this); timer->add_event_after(cct->_conf->journaler_batch_interval, delay_flush_event); } else { ldout(cct, 20) << "flush not delaying flush" << dendl; _do_flush(); } } else { // always flush _do_flush(); } wait_for_flush(onsafe); } // write head? if (last_wrote_head.sec() + cct->_conf->journaler_write_head_interval < ceph_clock_now(cct).sec()) { write_head(); } } /*************** prezeroing ******************/ struct C_Journaler_Prezero : public Context { Journaler *journaler; uint64_t from, len; C_Journaler_Prezero(Journaler *j, uint64_t f, uint64_t l) : journaler(j), from(f), len(l) {} void finish(int r) { journaler->_prezeroed(r, from, len); } }; void Journaler::_issue_prezero() { assert(prezeroing_pos >= flush_pos); // we need to zero at least two periods, minimum, to ensure that we have a full // empty object/period in front of us. uint64_t num_periods = MAX(2, cct->_conf->journaler_prezero_periods); /* * issue zero requests based on write_pos, even though the invariant * is that we zero ahead of flush_pos. */ uint64_t period = get_layout_period(); uint64_t to = write_pos + period * num_periods + period - 1; to -= to % period; if (prezeroing_pos >= to) { ldout(cct, 20) << "_issue_prezero target " << to << " <= prezeroing_pos " << prezeroing_pos << dendl; return; } while (prezeroing_pos < to) { uint64_t len; if (prezeroing_pos % period == 0) { len = period; ldout(cct, 10) << "_issue_prezero removing " << prezeroing_pos << "~" << period << " (full period)" << dendl; } else { len = period - (prezeroing_pos % period); ldout(cct, 10) << "_issue_prezero zeroing " << prezeroing_pos << "~" << len << " (partial period)" << dendl; } SnapContext snapc; Context *c = new C_Journaler_Prezero(this, prezeroing_pos, len); filer.zero(ino, &layout, snapc, prezeroing_pos, len, ceph_clock_now(cct), 0, NULL, c); prezeroing_pos += len; } } void Journaler::_prezeroed(int r, uint64_t start, uint64_t len) { ldout(cct, 10) << "_prezeroed to " << start << "~" << len << ", prezeroing/prezero was " << prezeroing_pos << "/" << prezero_pos << ", pending " << pending_zero << dendl; if (r < 0 && r != -ENOENT) { lderr(cct) << "_prezeroed got " << cpp_strerror(r) << dendl; handle_write_error(r); return; } assert(r == 0 || r == -ENOENT); if (start == prezero_pos) { prezero_pos += len; while (!pending_zero.empty() && pending_zero.begin().get_start() == prezero_pos) { interval_set::iterator b(pending_zero.begin()); prezero_pos += b.get_len(); pending_zero.erase(b); } if (waiting_for_zero) { _do_flush(); } } else { pending_zero.insert(start, len); } ldout(cct, 10) << "_prezeroed prezeroing/prezero now " << prezeroing_pos << "/" << prezero_pos << ", pending " << pending_zero << dendl; } /***************** READING *******************/ class Journaler::C_Read : public Context { Journaler *ls; uint64_t offset; public: bufferlist bl; C_Read(Journaler *l, uint64_t o) : ls(l), offset(o) {} void finish(int r) { ls->_finish_read(r, offset, bl); } }; class Journaler::C_RetryRead : public Context { Journaler *ls; public: C_RetryRead(Journaler *l) : ls(l) {} void finish(int r) { // kickstart. ls->_prefetch(); } }; void Journaler::_finish_read(int r, uint64_t offset, bufferlist& bl) { if (r < 0) { ldout(cct, 0) << "_finish_read got error " << r << dendl; error = r; if (on_readable) { Context *f = on_readable; on_readable = 0; f->complete(r); } return; } assert(r>=0); ldout(cct, 10) << "_finish_read got " << offset << "~" << bl.length() << dendl; prefetch_buf[offset].swap(bl); _assimilate_prefetch(); _prefetch(); } void Journaler::_assimilate_prefetch() { bool was_readable = _is_readable(); bool got_any = false; while (!prefetch_buf.empty()) { map::iterator p = prefetch_buf.begin(); if (p->first != received_pos) { uint64_t gap = p->first - received_pos; ldout(cct, 10) << "_assimilate_prefetch gap of " << gap << " from received_pos " << received_pos << " to first prefetched buffer " << p->first << dendl; break; } ldout(cct, 10) << "_assimilate_prefetch " << p->first << "~" << p->second.length() << dendl; received_pos += p->second.length(); read_buf.claim_append(p->second); assert(received_pos <= requested_pos); prefetch_buf.erase(p); got_any = true; } if (got_any) ldout(cct, 10) << "_assimilate_prefetch read_buf now " << read_pos << "~" << read_buf.length() << ", read pointers " << read_pos << "/" << received_pos << "/" << requested_pos << dendl; if ((got_any && !was_readable && _is_readable()) || read_pos == write_pos) { // readable! ldout(cct, 10) << "_finish_read now readable (or at journal end)" << dendl; if (on_readable) { Context *f = on_readable; on_readable = 0; f->complete(0); } } } void Journaler::_issue_read(uint64_t len) { // make sure we're fully flushed _do_flush(); // stuck at safe_pos? // (this is needed if we are reading the tail of a journal we are also writing to) assert(requested_pos <= safe_pos); if (requested_pos == safe_pos) { ldout(cct, 10) << "_issue_read requested_pos = safe_pos = " << safe_pos << ", waiting" << dendl; assert(write_pos > requested_pos); if (flush_pos == safe_pos) flush(); assert(flush_pos > safe_pos); waitfor_safe[flush_pos].push_back(new C_RetryRead(this)); return; } // don't read too much if (requested_pos + len > safe_pos) { len = safe_pos - requested_pos; ldout(cct, 10) << "_issue_read reading only up to safe_pos " << safe_pos << dendl; } // go. ldout(cct, 10) << "_issue_read reading " << requested_pos << "~" << len << ", read pointers " << read_pos << "/" << received_pos << "/" << (requested_pos+len) << dendl; // step by period (object). _don't_ do a single big filer.read() // here because it will wait for all object reads to complete before // giving us back any data. this way we can process whatever bits // come in that are contiguous. uint64_t period = get_layout_period(); while (len > 0) { uint64_t e = requested_pos + period; e -= e % period; uint64_t l = e - requested_pos; if (l > len) l = len; C_Read *c = new C_Read(this, requested_pos); filer.read(ino, &layout, CEPH_NOSNAP, requested_pos, l, &c->bl, 0, c); requested_pos += l; len -= l; } } void Journaler::_prefetch() { ldout(cct, 10) << "_prefetch" << dendl; // prefetch uint64_t pf; if (temp_fetch_len) { ldout(cct, 10) << "_prefetch temp_fetch_len " << temp_fetch_len << dendl; pf = temp_fetch_len; temp_fetch_len = 0; } else { pf = fetch_len; } uint64_t raw_target = read_pos + pf; // read full log segments, so increase if necessary uint64_t period = get_layout_period(); uint64_t remainder = raw_target % period; uint64_t adjustment = remainder ? period - remainder : 0; uint64_t target = raw_target + adjustment; // don't read past the log tail if (target > write_pos) target = write_pos; if (requested_pos < target) { uint64_t len = target - requested_pos; ldout(cct, 10) << "_prefetch " << pf << " requested_pos " << requested_pos << " < target " << target << " (" << raw_target << "), prefetching " << len << dendl; _issue_read(len); } } /* * _is_readable() - return true if next entry is ready. */ bool Journaler::_is_readable() { // anything to read? if (read_pos == write_pos) return false; // have enough for entry size? uint32_t s = 0; bufferlist::iterator p = read_buf.begin(); if (read_buf.length() >= sizeof(s)) ::decode(s, p); // entry and payload? if (read_buf.length() >= sizeof(s) && read_buf.length() >= sizeof(s) + s) return true; // yep, next entry is ready. ldout (cct, 10) << "_is_readable read_buf.length() == " << read_buf.length() << ", but need " << s + sizeof(s) << " for next entry; fetch_len is " << fetch_len << dendl; // partial fragment at the end? if (received_pos == write_pos) { ldout(cct, 10) << "is_readable() detected partial entry at tail, adjusting write_pos to " << read_pos << dendl; // adjust write_pos prezeroing_pos = prezero_pos = write_pos = flush_pos = safe_pos = read_pos; assert(write_buf.length() == 0); // reset read state requested_pos = received_pos = read_pos; read_buf.clear(); // FIXME: truncate on disk? return false; } uint64_t need = sizeof(s) + s; if (need > fetch_len) { temp_fetch_len = sizeof(s) + s; ldout(cct, 10) << "_is_readable noting temp_fetch_len " << temp_fetch_len << " for len " << s << " entry" << dendl; } ldout(cct, 10) << "_is_readable: not readable, returning false" << dendl; return false; } /* * is_readable() - kickstart prefetch, too */ bool Journaler::is_readable() { bool r = _is_readable(); _prefetch(); return r; } /* try_read_entry(bl) * read entry into bl if it's ready. * otherwise, do nothing. (well, we'll start fetching it for good measure.) */ bool Journaler::try_read_entry(bufferlist& bl) { if (!is_readable()) { // this may start a read. ldout(cct, 10) << "try_read_entry at " << read_pos << " not readable" << dendl; return false; } uint32_t s; { bufferlist::iterator p = read_buf.begin(); ::decode(s, p); } assert(read_buf.length() >= sizeof(s) + s); ldout(cct, 10) << "try_read_entry at " << read_pos << " reading " << read_pos << "~" << (sizeof(s)+s) << " (have " << read_buf.length() << ")" << dendl; if (s == 0) { ldout(cct, 0) << "try_read_entry got 0 len entry at offset " << read_pos << dendl; error = -EINVAL; return false; } // do it assert(bl.length() == 0); read_buf.splice(0, sizeof(s)); read_buf.splice(0, s, &bl); read_pos += sizeof(s) + s; // prefetch? _prefetch(); return true; } void Journaler::wait_for_readable(Context *onreadable) { ldout(cct, 10) << "wait_for_readable at " << read_pos << " onreadable " << onreadable << dendl; assert(!_is_readable()); assert(on_readable == 0); on_readable = onreadable; } /***************** TRIMMING *******************/ class Journaler::C_Trim : public Context { Journaler *ls; uint64_t to; public: C_Trim(Journaler *l, int64_t t) : ls(l), to(t) {} void finish(int r) { ls->_trim_finish(r, to); } }; void Journaler::trim() { assert(!readonly); uint64_t period = get_layout_period(); uint64_t trim_to = last_committed.expire_pos; trim_to -= trim_to % period; ldout(cct, 10) << "trim last_commited head was " << last_committed << ", can trim to " << trim_to << dendl; if (trim_to == 0 || trim_to == trimming_pos) { ldout(cct, 10) << "trim already trimmed/trimming to " << trimmed_pos << "/" << trimming_pos << dendl; return; } if (trimming_pos > trimmed_pos) { ldout(cct, 10) << "trim already trimming atm, try again later. trimmed/trimming is " << trimmed_pos << "/" << trimming_pos << dendl; return; } // trim assert(trim_to <= write_pos); assert(trim_to <= expire_pos); assert(trim_to > trimming_pos); ldout(cct, 10) << "trim trimming to " << trim_to << ", trimmed/trimming/expire are " << trimmed_pos << "/" << trimming_pos << "/" << expire_pos << dendl; // delete range of objects uint64_t first = trimming_pos / period; uint64_t num = (trim_to - trimming_pos) / period; SnapContext snapc; filer.purge_range(ino, &layout, snapc, first, num, ceph_clock_now(cct), 0, new C_Trim(this, trim_to)); trimming_pos = trim_to; } void Journaler::_trim_finish(int r, uint64_t to) { assert(!readonly); ldout(cct, 10) << "_trim_finish trimmed_pos was " << trimmed_pos << ", trimmed/trimming/expire now " << to << "/" << trimming_pos << "/" << expire_pos << dendl; if (r < 0 && r != -ENOENT) { lderr(cct) << "_trim_finish got " << cpp_strerror(r) << dendl; handle_write_error(r); return; } assert(r >= 0 || r == -ENOENT); assert(to <= trimming_pos); assert(to > trimmed_pos); trimmed_pos = to; // finishers? while (!waitfor_trim.empty() && waitfor_trim.begin()->first <= trimmed_pos) { finish_contexts(cct, waitfor_trim.begin()->second, 0); waitfor_trim.erase(waitfor_trim.begin()); } } void Journaler::handle_write_error(int r) { lderr(cct) << "handle_write_error " << cpp_strerror(r) << dendl; if (on_write_error) { on_write_error->complete(r); on_write_error = NULL; } else { assert(0 == "unhandled write error"); } } // eof. ceph-0.80.11/src/osdc/Objecter.h0000664000175100017510000020637612623076744020340 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_OBJECTER_H #define CEPH_OBJECTER_H #include "include/types.h" #include "include/buffer.h" #include "include/xlist.h" #include "osd/OSDMap.h" #include "messages/MOSDOp.h" #include "common/admin_socket.h" #include "common/Timer.h" #include "include/rados/rados_types.h" #include "include/rados/rados_types.hpp" #include #include #include #include using namespace std; class Context; class Messenger; class OSDMap; class MonClient; class Message; class MPoolOpReply; class MGetPoolStatsReply; class MStatfsReply; class MCommandReply; class PerfCounters; // ----------------------------------------- struct ObjectOperation { vector ops; int flags; int priority; vector out_bl; vector out_handler; vector out_rval; ObjectOperation() : flags(0), priority(0) {} ~ObjectOperation() { while (!out_handler.empty()) { delete out_handler.back(); out_handler.pop_back(); } } size_t size() { return ops.size(); } void set_last_op_flags(int flags) { assert(!ops.empty()); ops.rbegin()->op.flags = flags; } /** * This is a more limited form of C_Contexts, but that requires * a ceph_context which we don't have here. */ class C_TwoContexts : public Context { Context *first; Context *second; public: C_TwoContexts(Context *first, Context *second) : first(first), second(second) {} void finish(int r) { first->complete(r); second->complete(r); } }; /** * Add a callback to run when this operation completes, * after any other callbacks for it. */ void add_handler(Context *extra) { size_t last = out_handler.size() - 1; Context *orig = out_handler[last]; if (orig) { Context *wrapper = new C_TwoContexts(orig, extra); out_handler[last] = wrapper; } else { out_handler[last] = extra; } } OSDOp& add_op(int op) { int s = ops.size(); ops.resize(s+1); ops[s].op.op = op; out_bl.resize(s+1); out_bl[s] = NULL; out_handler.resize(s+1); out_handler[s] = NULL; out_rval.resize(s+1); out_rval[s] = NULL; return ops[s]; } void add_data(int op, uint64_t off, uint64_t len, bufferlist& bl) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.extent.offset = off; osd_op.op.extent.length = len; osd_op.indata.claim_append(bl); } void add_clone_range(int op, uint64_t off, uint64_t len, const object_t& srcoid, uint64_t srcoff, snapid_t srcsnapid) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.clonerange.offset = off; osd_op.op.clonerange.length = len; osd_op.op.clonerange.src_offset = srcoff; osd_op.soid = sobject_t(srcoid, srcsnapid); } void add_xattr(int op, const char *name, const bufferlist& data) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.xattr.name_len = (name ? strlen(name) : 0); osd_op.op.xattr.value_len = data.length(); if (name) osd_op.indata.append(name); osd_op.indata.append(data); } void add_xattr_cmp(int op, const char *name, uint8_t cmp_op, uint8_t cmp_mode, const bufferlist& data) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.xattr.name_len = (name ? strlen(name) : 0); osd_op.op.xattr.value_len = data.length(); osd_op.op.xattr.cmp_op = cmp_op; osd_op.op.xattr.cmp_mode = cmp_mode; if (name) osd_op.indata.append(name); osd_op.indata.append(data); } void add_call(int op, const char *cname, const char *method, bufferlist &indata, bufferlist *outbl, Context *ctx, int *prval) { OSDOp& osd_op = add_op(op); unsigned p = ops.size() - 1; out_handler[p] = ctx; out_bl[p] = outbl; out_rval[p] = prval; osd_op.op.op = op; osd_op.op.cls.class_len = strlen(cname); osd_op.op.cls.method_len = strlen(method); osd_op.op.cls.indata_len = indata.length(); osd_op.indata.append(cname, osd_op.op.cls.class_len); osd_op.indata.append(method, osd_op.op.cls.method_len); osd_op.indata.append(indata); } void add_watch(int op, uint64_t cookie, uint64_t ver, uint8_t flag, bufferlist& inbl) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.watch.cookie = cookie; osd_op.op.watch.ver = ver; osd_op.op.watch.flag = flag; osd_op.indata.append(inbl); } void add_pgls(int op, uint64_t count, collection_list_handle_t cookie, epoch_t start_epoch) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.pgls.count = count; osd_op.op.pgls.start_epoch = start_epoch; ::encode(cookie, osd_op.indata); } void add_pgls_filter(int op, uint64_t count, bufferlist& filter, collection_list_handle_t cookie, epoch_t start_epoch) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.pgls.count = count; osd_op.op.pgls.start_epoch = start_epoch; string cname = "pg"; string mname = "filter"; ::encode(cname, osd_op.indata); ::encode(mname, osd_op.indata); ::encode(cookie, osd_op.indata); osd_op.indata.append(filter); } void add_alloc_hint(int op, uint64_t expected_object_size, uint64_t expected_write_size) { OSDOp& osd_op = add_op(op); osd_op.op.op = op; osd_op.op.alloc_hint.expected_object_size = expected_object_size; osd_op.op.alloc_hint.expected_write_size = expected_write_size; } // ------ // pg void pg_ls(uint64_t count, bufferlist& filter, collection_list_handle_t cookie, epoch_t start_epoch) { if (filter.length() == 0) add_pgls(CEPH_OSD_OP_PGLS, count, cookie, start_epoch); else add_pgls_filter(CEPH_OSD_OP_PGLS_FILTER, count, filter, cookie, start_epoch); flags |= CEPH_OSD_FLAG_PGOP; } void create(bool excl) { OSDOp& o = add_op(CEPH_OSD_OP_CREATE); o.op.flags = (excl ? CEPH_OSD_OP_FLAG_EXCL : 0); } void create(bool excl, const string& category) { OSDOp& o = add_op(CEPH_OSD_OP_CREATE); o.op.flags = (excl ? CEPH_OSD_OP_FLAG_EXCL : 0); ::encode(category, o.indata); } struct C_ObjectOperation_stat : public Context { bufferlist bl; uint64_t *psize; utime_t *pmtime; time_t *ptime; int *prval; C_ObjectOperation_stat(uint64_t *ps, utime_t *pm, time_t *pt, int *prval) : psize(ps), pmtime(pm), ptime(pt), prval(prval) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); try { uint64_t size; utime_t mtime; ::decode(size, p); ::decode(mtime, p); if (psize) *psize = size; if (pmtime) *pmtime = mtime; if (ptime) *ptime = mtime.sec(); } catch (buffer::error& e) { if (prval) *prval = -EIO; } } } }; void stat(uint64_t *psize, utime_t *pmtime, int *prval) { add_op(CEPH_OSD_OP_STAT); unsigned p = ops.size() - 1; C_ObjectOperation_stat *h = new C_ObjectOperation_stat(psize, pmtime, NULL, prval); out_bl[p] = &h->bl; out_handler[p] = h; out_rval[p] = prval; } void stat(uint64_t *psize, time_t *ptime, int *prval) { add_op(CEPH_OSD_OP_STAT); unsigned p = ops.size() - 1; C_ObjectOperation_stat *h = new C_ObjectOperation_stat(psize, NULL, ptime, prval); out_bl[p] = &h->bl; out_handler[p] = h; out_rval[p] = prval; } // object data void read(uint64_t off, uint64_t len, bufferlist *pbl, int *prval, Context* ctx) { bufferlist bl; add_data(CEPH_OSD_OP_READ, off, len, bl); unsigned p = ops.size() - 1; out_bl[p] = pbl; out_rval[p] = prval; out_handler[p] = ctx; } struct C_ObjectOperation_sparse_read : public Context { bufferlist bl; bufferlist *data_bl; std::map *extents; int *prval; C_ObjectOperation_sparse_read(bufferlist *data_bl, std::map *extents, int *prval) : data_bl(data_bl), extents(extents), prval(prval) {} void finish(int r) { bufferlist::iterator iter = bl.begin(); if (r >= 0) { try { ::decode(*extents, iter); ::decode(*data_bl, iter); } catch (buffer::error& e) { if (prval) *prval = -EIO; } } } }; void sparse_read(uint64_t off, uint64_t len, std::map *m, bufferlist *data_bl, int *prval) { bufferlist bl; add_data(CEPH_OSD_OP_SPARSE_READ, off, len, bl); unsigned p = ops.size() - 1; C_ObjectOperation_sparse_read *h = new C_ObjectOperation_sparse_read(data_bl, m, prval); out_bl[p] = &h->bl; out_handler[p] = h; out_rval[p] = prval; } void write(uint64_t off, bufferlist& bl, uint64_t truncate_size, uint32_t truncate_seq) { add_data(CEPH_OSD_OP_WRITE, off, bl.length(), bl); OSDOp& o = *ops.rbegin(); o.op.extent.truncate_size = truncate_size; o.op.extent.truncate_seq = truncate_seq; } void write(uint64_t off, bufferlist& bl) { write(off, bl, 0, 0); } void write_full(bufferlist& bl) { add_data(CEPH_OSD_OP_WRITEFULL, 0, bl.length(), bl); } void append(bufferlist& bl) { add_data(CEPH_OSD_OP_APPEND, 0, bl.length(), bl); } void zero(uint64_t off, uint64_t len) { bufferlist bl; add_data(CEPH_OSD_OP_ZERO, off, len, bl); } void truncate(uint64_t off) { bufferlist bl; add_data(CEPH_OSD_OP_TRUNCATE, off, 0, bl); } void remove() { bufferlist bl; add_data(CEPH_OSD_OP_DELETE, 0, 0, bl); } void mapext(uint64_t off, uint64_t len) { bufferlist bl; add_data(CEPH_OSD_OP_MAPEXT, off, len, bl); } void sparse_read(uint64_t off, uint64_t len) { bufferlist bl; add_data(CEPH_OSD_OP_SPARSE_READ, off, len, bl); } void clone_range(const object_t& src_oid, uint64_t src_offset, uint64_t len, uint64_t dst_offset) { add_clone_range(CEPH_OSD_OP_CLONERANGE, dst_offset, len, src_oid, src_offset, CEPH_NOSNAP); } // object attrs void getxattr(const char *name, bufferlist *pbl, int *prval) { bufferlist bl; add_xattr(CEPH_OSD_OP_GETXATTR, name, bl); unsigned p = ops.size() - 1; out_bl[p] = pbl; out_rval[p] = prval; } struct C_ObjectOperation_decodevals : public Context { bufferlist bl; std::map *pattrs; int *prval; C_ObjectOperation_decodevals(std::map *pa, int *pr) : pattrs(pa), prval(pr) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); try { if (pattrs) ::decode(*pattrs, p); } catch (buffer::error& e) { if (prval) *prval = -EIO; } } } }; struct C_ObjectOperation_decodekeys : public Context { bufferlist bl; std::set *pattrs; int *prval; C_ObjectOperation_decodekeys(std::set *pa, int *pr) : pattrs(pa), prval(pr) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); try { if (pattrs) ::decode(*pattrs, p); } catch (buffer::error& e) { if (prval) *prval = -EIO; } } } }; struct C_ObjectOperation_decodewatchers : public Context { bufferlist bl; list *pwatchers; int *prval; C_ObjectOperation_decodewatchers(list *pw, int *pr) : pwatchers(pw), prval(pr) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); try { obj_list_watch_response_t resp; ::decode(resp, p); if (pwatchers) { for (list::iterator i = resp.entries.begin() ; i != resp.entries.end() ; ++i) { obj_watch_t ow; ostringstream sa; sa << i->addr; strncpy(ow.addr, sa.str().c_str(), 256); ow.watcher_id = i->name.num(); ow.cookie = i->cookie; ow.timeout_seconds = i->timeout_seconds; pwatchers->push_back(ow); } } } catch (buffer::error& e) { if (prval) *prval = -EIO; } } } }; struct C_ObjectOperation_decodesnaps : public Context { bufferlist bl; librados::snap_set_t *psnaps; int *prval; C_ObjectOperation_decodesnaps(librados::snap_set_t *ps, int *pr) : psnaps(ps), prval(pr) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); try { obj_list_snap_response_t resp; ::decode(resp, p); if (psnaps) { psnaps->clones.clear(); for (vector::iterator ci = resp.clones.begin(); ci != resp.clones.end(); ++ci) { librados::clone_info_t clone; clone.cloneid = ci->cloneid; clone.snaps.reserve(ci->snaps.size()); clone.snaps.insert(clone.snaps.end(), ci->snaps.begin(), ci->snaps.end()); clone.overlap = ci->overlap; clone.size = ci->size; psnaps->clones.push_back(clone); } psnaps->seq = resp.seq; } } catch (buffer::error& e) { if (prval) *prval = -EIO; } } } }; void getxattrs(std::map *pattrs, int *prval) { add_op(CEPH_OSD_OP_GETXATTRS); if (pattrs || prval) { unsigned p = ops.size() - 1; C_ObjectOperation_decodevals *h = new C_ObjectOperation_decodevals(pattrs, prval); out_handler[p] = h; out_bl[p] = &h->bl; out_rval[p] = prval; } } void setxattr(const char *name, const bufferlist& bl) { add_xattr(CEPH_OSD_OP_SETXATTR, name, bl); } void setxattr(const char *name, const string& s) { bufferlist bl; bl.append(s); add_xattr(CEPH_OSD_OP_SETXATTR, name, bl); } void cmpxattr(const char *name, uint8_t cmp_op, uint8_t cmp_mode, const bufferlist& bl) { add_xattr_cmp(CEPH_OSD_OP_CMPXATTR, name, cmp_op, cmp_mode, bl); } void rmxattr(const char *name) { bufferlist bl; add_xattr(CEPH_OSD_OP_RMXATTR, name, bl); } void setxattrs(map& attrs) { bufferlist bl; ::encode(attrs, bl); add_xattr(CEPH_OSD_OP_RESETXATTRS, 0, bl.length()); } void resetxattrs(const char *prefix, map& attrs) { bufferlist bl; ::encode(attrs, bl); add_xattr(CEPH_OSD_OP_RESETXATTRS, prefix, bl); } // trivialmap void tmap_update(bufferlist& bl) { add_data(CEPH_OSD_OP_TMAPUP, 0, 0, bl); } void tmap_put(bufferlist& bl) { add_data(CEPH_OSD_OP_TMAPPUT, 0, bl.length(), bl); } void tmap_get(bufferlist *pbl, int *prval) { add_op(CEPH_OSD_OP_TMAPGET); unsigned p = ops.size() - 1; out_bl[p] = pbl; out_rval[p] = prval; } void tmap_get() { add_op(CEPH_OSD_OP_TMAPGET); } void tmap_to_omap(bool nullok=false) { OSDOp& osd_op = add_op(CEPH_OSD_OP_TMAP2OMAP); osd_op.op.op = CEPH_OSD_OP_TMAP2OMAP; if (nullok) osd_op.op.tmap2omap.flags = CEPH_OSD_TMAP2OMAP_NULLOK; } // objectmap void omap_get_keys(const string &start_after, uint64_t max_to_get, std::set *out_set, int *prval) { OSDOp &op = add_op(CEPH_OSD_OP_OMAPGETKEYS); bufferlist bl; ::encode(start_after, bl); ::encode(max_to_get, bl); op.op.extent.offset = 0; op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval || out_set) { unsigned p = ops.size() - 1; C_ObjectOperation_decodekeys *h = new C_ObjectOperation_decodekeys(out_set, prval); out_handler[p] = h; out_bl[p] = &h->bl; out_rval[p] = prval; } } void omap_get_vals(const string &start_after, const string &filter_prefix, uint64_t max_to_get, std::map *out_set, int *prval) { OSDOp &op = add_op(CEPH_OSD_OP_OMAPGETVALS); bufferlist bl; ::encode(start_after, bl); ::encode(max_to_get, bl); ::encode(filter_prefix, bl); op.op.extent.offset = 0; op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval || out_set) { unsigned p = ops.size() - 1; C_ObjectOperation_decodevals *h = new C_ObjectOperation_decodevals(out_set, prval); out_handler[p] = h; out_bl[p] = &h->bl; out_rval[p] = prval; } } void omap_get_vals_by_keys(const std::set &to_get, std::map *out_set, int *prval) { OSDOp &op = add_op(CEPH_OSD_OP_OMAPGETVALSBYKEYS); bufferlist bl; ::encode(to_get, bl); op.op.extent.offset = 0; op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval || out_set) { unsigned p = ops.size() - 1; C_ObjectOperation_decodevals *h = new C_ObjectOperation_decodevals(out_set, prval); out_handler[p] = h; out_bl[p] = &h->bl; out_rval[p] = prval; } } void omap_cmp(const std::map > &assertions, int *prval) { OSDOp &op = add_op(CEPH_OSD_OP_OMAP_CMP); bufferlist bl; ::encode(assertions, bl); op.op.extent.offset = 0; op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval) { unsigned p = ops.size() - 1; out_rval[p] = prval; out_bl[p] = NULL; out_handler[p] = NULL; } } struct C_ObjectOperation_copyget : public Context { bufferlist bl; object_copy_cursor_t *cursor; uint64_t *out_size; utime_t *out_mtime; string *out_category; std::map *out_attrs; bufferlist *out_data, *out_omap_header; std::map *out_omap; vector *out_snaps; snapid_t *out_snap_seq; int *prval; C_ObjectOperation_copyget(object_copy_cursor_t *c, uint64_t *s, utime_t *m, string *cat, std::map *a, bufferlist *d, bufferlist *oh, std::map *o, std::vector *osnaps, snapid_t *osnap_seq, int *r) : cursor(c), out_size(s), out_mtime(m), out_category(cat), out_attrs(a), out_data(d), out_omap_header(oh), out_omap(o), out_snaps(osnaps), out_snap_seq(osnap_seq), prval(r) {} void finish(int r) { if (r < 0) return; try { bufferlist::iterator p = bl.begin(); object_copy_data_t copy_reply; ::decode(copy_reply, p); if (out_size) *out_size = copy_reply.size; if (out_mtime) *out_mtime = copy_reply.mtime; if (out_category) *out_category = copy_reply.category; if (out_attrs) *out_attrs = copy_reply.attrs; if (out_data) out_data->claim_append(copy_reply.data); if (out_omap_header) out_omap_header->claim_append(copy_reply.omap_header); if (out_omap) *out_omap = copy_reply.omap; if (out_snaps) *out_snaps = copy_reply.snaps; if (out_snap_seq) *out_snap_seq = copy_reply.snap_seq; *cursor = copy_reply.cursor; } catch (buffer::error& e) { if (prval) *prval = -EIO; } } }; void copy_get(object_copy_cursor_t *cursor, uint64_t max, uint64_t *out_size, utime_t *out_mtime, string *out_category, std::map *out_attrs, bufferlist *out_data, bufferlist *out_omap_header, std::map *out_omap, vector *out_snaps, snapid_t *out_snap_seq, int *prval) { OSDOp& osd_op = add_op(CEPH_OSD_OP_COPY_GET); osd_op.op.copy_get.max = max; ::encode(*cursor, osd_op.indata); ::encode(max, osd_op.indata); unsigned p = ops.size() - 1; out_rval[p] = prval; C_ObjectOperation_copyget *h = new C_ObjectOperation_copyget(cursor, out_size, out_mtime, out_category, out_attrs, out_data, out_omap_header, out_omap, out_snaps, out_snap_seq, prval); out_bl[p] = &h->bl; out_handler[p] = h; } void undirty() { add_op(CEPH_OSD_OP_UNDIRTY); } struct C_ObjectOperation_isdirty : public Context { bufferlist bl; bool *pisdirty; int *prval; C_ObjectOperation_isdirty(bool *p, int *r) : pisdirty(p), prval(r) {} void finish(int r) { if (r < 0) return; try { bufferlist::iterator p = bl.begin(); bool isdirty; ::decode(isdirty, p); if (pisdirty) *pisdirty = isdirty; } catch (buffer::error& e) { if (prval) *prval = -EIO; } } }; void is_dirty(bool *pisdirty, int *prval) { add_op(CEPH_OSD_OP_ISDIRTY); unsigned p = ops.size() - 1; out_rval[p] = prval; C_ObjectOperation_isdirty *h = new C_ObjectOperation_isdirty(pisdirty, prval); out_bl[p] = &h->bl; out_handler[p] = h; } struct C_ObjectOperation_hit_set_ls : public Context { bufferlist bl; std::list< std::pair > *ptls; std::list< std::pair > *putls; int *prval; C_ObjectOperation_hit_set_ls(std::list< std::pair > *t, std::list< std::pair > *ut, int *r) : ptls(t), putls(ut), prval(r) {} void finish(int r) { if (r < 0) return; try { bufferlist::iterator p = bl.begin(); std::list< std::pair > ls; ::decode(ls, p); if (ptls) { ptls->clear(); for (list< pair >::iterator p = ls.begin(); p != ls.end(); ++p) // round initial timestamp up to the next full second to keep this a valid interval. ptls->push_back(make_pair(p->first.usec() ? p->first.sec() + 1 : p->first.sec(), p->second.sec())); } if (putls) putls->swap(ls); } catch (buffer::error& e) { r = -EIO; } if (prval) *prval = r; } }; /** * list available HitSets. * * We will get back a list of time intervals. Note that the most recent range may have * an empty end timestamp if it is still accumulating. * * @param pls [out] list of time intervals * @param prval [out] return value */ void hit_set_ls(std::list< std::pair > *pls, int *prval) { add_op(CEPH_OSD_OP_PG_HITSET_LS); unsigned p = ops.size() - 1; out_rval[p] = prval; C_ObjectOperation_hit_set_ls *h = new C_ObjectOperation_hit_set_ls(pls, NULL, prval); out_bl[p] = &h->bl; out_handler[p] = h; } void hit_set_ls(std::list< std::pair > *pls, int *prval) { add_op(CEPH_OSD_OP_PG_HITSET_LS); unsigned p = ops.size() - 1; out_rval[p] = prval; C_ObjectOperation_hit_set_ls *h = new C_ObjectOperation_hit_set_ls(NULL, pls, prval); out_bl[p] = &h->bl; out_handler[p] = h; } /** * get HitSet * * Return an encoded HitSet that includes the provided time * interval. * * @param stamp [in] timestamp * @param pbl [out] target buffer for encoded HitSet * @param prval [out] return value */ void hit_set_get(utime_t stamp, bufferlist *pbl, int *prval) { OSDOp& op = add_op(CEPH_OSD_OP_PG_HITSET_GET); op.op.hit_set_get.stamp.tv_sec = stamp.sec(); op.op.hit_set_get.stamp.tv_nsec = stamp.nsec(); unsigned p = ops.size() - 1; out_rval[p] = prval; out_bl[p] = pbl; } void omap_get_header(bufferlist *bl, int *prval) { add_op(CEPH_OSD_OP_OMAPGETHEADER); unsigned p = ops.size() - 1; out_bl[p] = bl; out_rval[p] = prval; } void omap_set(const map &map) { bufferlist bl; ::encode(map, bl); add_data(CEPH_OSD_OP_OMAPSETVALS, 0, bl.length(), bl); } void omap_set_header(bufferlist &bl) { add_data(CEPH_OSD_OP_OMAPSETHEADER, 0, bl.length(), bl); } void omap_clear() { add_op(CEPH_OSD_OP_OMAPCLEAR); } void omap_rm_keys(const std::set &to_remove) { bufferlist bl; ::encode(to_remove, bl); add_data(CEPH_OSD_OP_OMAPRMKEYS, 0, bl.length(), bl); } // object classes void call(const char *cname, const char *method, bufferlist &indata) { add_call(CEPH_OSD_OP_CALL, cname, method, indata, NULL, NULL, NULL); } void call(const char *cname, const char *method, bufferlist &indata, bufferlist *outdata, Context *ctx, int *prval) { add_call(CEPH_OSD_OP_CALL, cname, method, indata, outdata, ctx, prval); } // watch/notify void watch(uint64_t cookie, uint64_t ver, bool set) { bufferlist inbl; add_watch(CEPH_OSD_OP_WATCH, cookie, ver, (set ? 1 : 0), inbl); } void notify(uint64_t cookie, uint64_t ver, bufferlist& inbl) { add_watch(CEPH_OSD_OP_NOTIFY, cookie, ver, 1, inbl); } void notify_ack(uint64_t notify_id, uint64_t ver, uint64_t cookie) { bufferlist bl; ::encode(notify_id, bl); ::encode(cookie, bl); add_watch(CEPH_OSD_OP_NOTIFY_ACK, notify_id, ver, 0, bl); } void list_watchers(list *out, int *prval) { (void)add_op(CEPH_OSD_OP_LIST_WATCHERS); if (prval || out) { unsigned p = ops.size() - 1; C_ObjectOperation_decodewatchers *h = new C_ObjectOperation_decodewatchers(out, prval); out_handler[p] = h; out_bl[p] = &h->bl; out_rval[p] = prval; } } void list_snaps(librados::snap_set_t *out, int *prval) { (void)add_op(CEPH_OSD_OP_LIST_SNAPS); if (prval || out) { unsigned p = ops.size() - 1; C_ObjectOperation_decodesnaps *h = new C_ObjectOperation_decodesnaps(out, prval); out_handler[p] = h; out_bl[p] = &h->bl; out_rval[p] = prval; } } void assert_version(uint64_t ver) { OSDOp& osd_op = add_op(CEPH_OSD_OP_ASSERT_VER); osd_op.op.assert_ver.ver = ver; } void assert_src_version(const object_t& srcoid, snapid_t srcsnapid, uint64_t ver) { bufferlist bl; add_watch(CEPH_OSD_OP_ASSERT_SRC_VERSION, 0, ver, 0, bl); ops.rbegin()->soid = sobject_t(srcoid, srcsnapid); } void cmpxattr(const char *name, const bufferlist& val, int op, int mode) { add_xattr(CEPH_OSD_OP_CMPXATTR, name, val); OSDOp& o = *ops.rbegin(); o.op.xattr.cmp_op = op; o.op.xattr.cmp_mode = mode; } void src_cmpxattr(const object_t& srcoid, snapid_t srcsnapid, const char *name, const bufferlist& val, int op, int mode) { add_xattr(CEPH_OSD_OP_SRC_CMPXATTR, name, val); OSDOp& o = *ops.rbegin(); o.soid = sobject_t(srcoid, srcsnapid); o.op.xattr.cmp_op = op; o.op.xattr.cmp_mode = mode; } void rollback(uint64_t snapid) { OSDOp& osd_op = add_op(CEPH_OSD_OP_ROLLBACK); osd_op.op.snap.snapid = snapid; } void copy_from(object_t src, snapid_t snapid, object_locator_t src_oloc, version_t src_version, unsigned flags) { OSDOp& osd_op = add_op(CEPH_OSD_OP_COPY_FROM); osd_op.op.copy_from.snapid = snapid; osd_op.op.copy_from.src_version = src_version; osd_op.op.copy_from.flags = flags; ::encode(src, osd_op.indata); ::encode(src_oloc, osd_op.indata); } /** * writeback content to backing tier * * If object is marked dirty in the cache tier, write back content * to backing tier. If the object is clean this is a no-op. * * If writeback races with an update, the update will block. * * use with IGNORE_CACHE to avoid triggering promote. */ void cache_flush() { add_op(CEPH_OSD_OP_CACHE_FLUSH); } /** * writeback content to backing tier * * If object is marked dirty in the cache tier, write back content * to backing tier. If the object is clean this is a no-op. * * If writeback races with an update, return EAGAIN. Requires that * the SKIPRWLOCKS flag be set. * * use with IGNORE_CACHE to avoid triggering promote. */ void cache_try_flush() { add_op(CEPH_OSD_OP_CACHE_TRY_FLUSH); } /** * evict object from cache tier * * If object is marked clean, remove the object from the cache tier. * Otherwise, return EBUSY. * * use with IGNORE_CACHE to avoid triggering promote. */ void cache_evict() { add_op(CEPH_OSD_OP_CACHE_EVICT); } void set_alloc_hint(uint64_t expected_object_size, uint64_t expected_write_size ) { add_alloc_hint(CEPH_OSD_OP_SETALLOCHINT, expected_object_size, expected_write_size); // CEPH_OSD_OP_SETALLOCHINT op is advisory and therefore deemed // not worth a feature bit. Set FAILOK per-op flag to make // sure older osds don't trip over an unsupported opcode. set_last_op_flags(CEPH_OSD_OP_FLAG_FAILOK); } }; // ---------------- class Objecter : public md_config_obs_t { public: // config observer bits virtual const char** get_tracked_conf_keys() const; virtual void handle_conf_change(const struct md_config_t *conf, const std::set &changed); public: Messenger *messenger; MonClient *monc; OSDMap *osdmap; CephContext *cct; std::multimap crush_location; bool initialized; private: ceph_tid_t last_tid; int client_inc; uint64_t max_linger_id; int num_unacked; int num_uncommitted; int global_op_flags; // flags which are applied to each IO op bool keep_balanced_budget; bool honor_osdmap_full; public: void maybe_request_map(); private: version_t last_seen_osdmap_version; version_t last_seen_pgmap_version; Mutex &client_lock; SafeTimer &timer; PerfCounters *logger; class C_Tick : public Context { Objecter *ob; public: C_Tick(Objecter *o) : ob(o) {} void finish(int r) { ob->tick(); } } *tick_event; void schedule_tick(); void tick(); class RequestStateHook : public AdminSocketHook { Objecter *m_objecter; public: RequestStateHook(Objecter *objecter); bool call(std::string command, cmdmap_t& cmdmap, std::string format, bufferlist& out); }; RequestStateHook *m_request_state_hook; public: /*** track pending operations ***/ // read public: struct OSDSession; struct op_target_t { int flags; object_t base_oid; object_locator_t base_oloc; object_t target_oid; object_locator_t target_oloc; bool precalc_pgid; ///< true if we are directed at base_pgid, not base_oid pg_t base_pgid; ///< explciti pg target, if any pg_t pgid; ///< last pg we mapped to unsigned pg_num; ///< last pg_num we mapped to unsigned pg_num_mask; ///< last pg_num_mask we mapped to vector up; ///< set of up osds for last pg we mapped to vector acting; ///< set of acting osds for last pg we mapped to int up_primary; ///< primary for last pg we mapped to based on the up set int acting_primary; ///< primary for last pg we mapped to based on the acting set int size; ///< the size of the pool when were were last mapped int min_size; ///< the min size of the pool when were were last mapped bool used_replica; bool paused; int osd; ///< the final target osd, or -1 op_target_t(object_t oid, object_locator_t oloc, int flags) : flags(flags), base_oid(oid), base_oloc(oloc), precalc_pgid(false), pg_num(0), pg_num_mask(0), up_primary(-1), acting_primary(-1), size(-1), min_size(-1), used_replica(false), paused(false), osd(-1) {} void dump(Formatter *f) const; }; struct Op { OSDSession *session; xlist::item session_item; int incarnation; op_target_t target; ConnectionRef con; // for rx buffer only vector ops; snapid_t snapid; SnapContext snapc; utime_t mtime; bufferlist *outbl; vector out_bl; vector out_handler; vector out_rval; int priority; Context *onack, *oncommit, *ontimeout; ceph_tid_t tid; eversion_t replay_version; // for op replay int attempts; version_t *objver; epoch_t *reply_epoch; utime_t stamp; epoch_t map_dne_bound; bool budgeted; /// true if we should resend this message on failure bool should_resend; epoch_t last_force_resend; /// true if the throttle budget is get/put on a series of OPs, instead of /// per OP basis, when this flag is set, the budget is acquired before sending /// the very first OP of the series and released upon receiving the last OP reply. bool ctx_budgeted; Op(const object_t& o, const object_locator_t& ol, vector& op, int f, Context *ac, Context *co, version_t *ov) : session(NULL), session_item(this), incarnation(0), target(o, ol, f), con(NULL), snapid(CEPH_NOSNAP), outbl(NULL), priority(0), onack(ac), oncommit(co), ontimeout(NULL), tid(0), attempts(0), objver(ov), reply_epoch(NULL), map_dne_bound(0), budgeted(false), should_resend(true), last_force_resend(0), ctx_budgeted(false) { ops.swap(op); /* initialize out_* to match op vector */ out_bl.resize(ops.size()); out_rval.resize(ops.size()); out_handler.resize(ops.size()); for (unsigned i = 0; i < ops.size(); i++) { out_bl[i] = NULL; out_handler[i] = NULL; out_rval[i] = NULL; } if (target.base_oloc.key == o) target.base_oloc.key.clear(); } ~Op() { while (!out_handler.empty()) { delete out_handler.back(); out_handler.pop_back(); } } bool operator<(const Op& other) const { return tid < other.tid; } }; struct C_Op_Map_Latest : public Context { Objecter *objecter; ceph_tid_t tid; version_t latest; C_Op_Map_Latest(Objecter *o, ceph_tid_t t) : objecter(o), tid(t), latest(0) {} void finish(int r); }; struct C_Command_Map_Latest : public Context { Objecter *objecter; uint64_t tid; version_t latest; C_Command_Map_Latest(Objecter *o, ceph_tid_t t) : objecter(o), tid(t), latest(0) {} void finish(int r); }; struct C_Stat : public Context { bufferlist bl; uint64_t *psize; utime_t *pmtime; Context *fin; C_Stat(uint64_t *ps, utime_t *pm, Context *c) : psize(ps), pmtime(pm), fin(c) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); uint64_t s; utime_t m; ::decode(s, p); ::decode(m, p); if (psize) *psize = s; if (pmtime) *pmtime = m; } fin->complete(r); } }; struct C_GetAttrs : public Context { bufferlist bl; map& attrset; Context *fin; C_GetAttrs(map& set, Context *c) : attrset(set), fin(c) {} void finish(int r) { if (r >= 0) { bufferlist::iterator p = bl.begin(); ::decode(attrset, p); } fin->complete(r); } }; // Pools and statistics struct ListContext { int current_pg; collection_list_handle_t cookie; epoch_t current_pg_epoch; int starting_pg_num; bool at_end_of_pool; bool at_end_of_pg; int64_t pool_id; int pool_snap_seq; int max_entries; string nspace; bufferlist bl; // raw data read to here std::list > list; bufferlist filter; bufferlist extra_info; // The budget associated with this context, once it is set (>= 0), // the budget is not get/released on OP basis, instead the budget // is acquired before sending the first OP and released upon receiving // the last op reply. int ctx_budget; ListContext() : current_pg(0), current_pg_epoch(0), starting_pg_num(0), at_end_of_pool(false), at_end_of_pg(false), pool_id(0), pool_snap_seq(0), max_entries(0), nspace(), bl(), list(), filter(), extra_info(), ctx_budget(-1) {} bool at_end() const { return at_end_of_pool; } uint32_t get_pg_hash_position() const { return current_pg; } }; struct C_List : public Context { ListContext *list_context; Context *final_finish; Objecter *objecter; epoch_t epoch; C_List(ListContext *lc, Context * finish, Objecter *ob) : list_context(lc), final_finish(finish), objecter(ob), epoch(0) {} void finish(int r) { if (r >= 0) { objecter->_list_reply(list_context, r, final_finish, epoch); } else { final_finish->complete(r); } } }; struct PoolStatOp { ceph_tid_t tid; list pools; map *pool_stats; Context *onfinish, *ontimeout; utime_t last_submit; }; struct StatfsOp { ceph_tid_t tid; struct ceph_statfs *stats; Context *onfinish, *ontimeout; utime_t last_submit; }; struct PoolOp { ceph_tid_t tid; int64_t pool; string name; Context *onfinish, *ontimeout; int pool_op; uint64_t auid; __u8 crush_rule; snapid_t snapid; bufferlist *blp; utime_t last_submit; PoolOp() : tid(0), pool(0), onfinish(NULL), ontimeout(NULL), pool_op(0), auid(0), crush_rule(0), snapid(0), blp(NULL) {} }; // -- osd commands -- struct CommandOp : public RefCountedObject { xlist::item session_item; OSDSession *session; ceph_tid_t tid; vector cmd; bufferlist inbl; bufferlist *poutbl; string *prs; int target_osd; pg_t target_pg; epoch_t map_dne_bound; int map_check_error; // error to return if map check fails const char *map_check_error_str; Context *onfinish, *ontimeout; utime_t last_submit; CommandOp() : session_item(this), session(NULL), tid(0), poutbl(NULL), prs(NULL), target_osd(-1), map_dne_bound(0), map_check_error(0), map_check_error_str(NULL), onfinish(NULL), ontimeout(NULL) {} }; int _submit_command(CommandOp *c, ceph_tid_t *ptid); int recalc_command_target(CommandOp *c); void _send_command(CommandOp *c); int command_op_cancel(ceph_tid_t tid, int r); void _finish_command(CommandOp *c, int r, string rs); void handle_command_reply(MCommandReply *m); // -- lingering ops -- struct LingerOp : public RefCountedObject { uint64_t linger_id; op_target_t target; snapid_t snap; SnapContext snapc; utime_t mtime; vector ops; bufferlist inbl; bufferlist *poutbl; version_t *pobjver; bool registered; Context *on_reg_ack, *on_reg_commit; OSDSession *session; xlist::item session_item; ceph_tid_t register_tid; epoch_t map_dne_bound; epoch_t last_force_resend; LingerOp() : linger_id(0), target(object_t(), object_locator_t(), 0), snap(CEPH_NOSNAP), poutbl(NULL), pobjver(NULL), registered(false), on_reg_ack(NULL), on_reg_commit(NULL), session(NULL), session_item(this), register_tid(0), map_dne_bound(0), last_force_resend(0) {} // no copy! const LingerOp &operator=(const LingerOp& r); LingerOp(const LingerOp& o); private: ~LingerOp() {} }; struct C_Linger_Ack : public Context { Objecter *objecter; LingerOp *info; C_Linger_Ack(Objecter *o, LingerOp *l) : objecter(o), info(l) { info->get(); } ~C_Linger_Ack() { info->put(); } void finish(int r) { objecter->_linger_ack(info, r); } }; struct C_Linger_Commit : public Context { Objecter *objecter; LingerOp *info; C_Linger_Commit(Objecter *o, LingerOp *l) : objecter(o), info(l) { info->get(); } ~C_Linger_Commit() { info->put(); } void finish(int r) { objecter->_linger_commit(info, r); } }; struct C_Linger_Map_Latest : public Context { Objecter *objecter; uint64_t linger_id; version_t latest; C_Linger_Map_Latest(Objecter *o, uint64_t id) : objecter(o), linger_id(id), latest(0) {} void finish(int r); }; // -- osd sessions -- struct OSDSession { xlist ops; xlist linger_ops; xlist command_ops; int osd; int incarnation; ConnectionRef con; OSDSession(int o) : osd(o), incarnation(0), con(NULL) {} }; map osd_sessions; private: // pending ops map ops; int num_homeless_ops; map linger_ops; map poolstat_ops; map statfs_ops; map pool_ops; map command_ops; // ops waiting for an osdmap with a new pool or confirmation that // the pool does not exist (may be expanded to other uses later) map check_latest_map_lingers; map check_latest_map_ops; map check_latest_map_commands; map > > waiting_for_map; double mon_timeout, osd_timeout; void send_op(Op *op); void cancel_linger_op(Op *op); void finish_op(Op *op); static bool is_pg_changed( int oldprimary, const vector& oldacting, int newprimary, const vector& newacting, bool any_change=false); enum recalc_op_target_result { RECALC_OP_TARGET_NO_ACTION = 0, RECALC_OP_TARGET_NEED_RESEND, RECALC_OP_TARGET_POOL_DNE, RECALC_OP_TARGET_OSD_DNE, RECALC_OP_TARGET_OSD_DOWN, }; bool osdmap_full_flag() const; bool target_should_be_paused(op_target_t *op); int calc_target(op_target_t *t, epoch_t *last_force_resend=0, bool any_change=false); int recalc_op_target(Op *op); bool recalc_linger_op_target(LingerOp *op); void send_linger(LingerOp *info); void _linger_ack(LingerOp *info, int r); void _linger_commit(LingerOp *info, int r); void check_op_pool_dne(Op *op); void _send_op_map_check(Op *op); void op_cancel_map_check(Op *op); void check_linger_pool_dne(LingerOp *op); void _send_linger_map_check(LingerOp *op); void linger_cancel_map_check(LingerOp *op); void check_command_map_dne(CommandOp *op); void _send_command_map_check(CommandOp *op); void command_cancel_map_check(CommandOp *op); void kick_requests(OSDSession *session); OSDSession *get_session(int osd); void reopen_session(OSDSession *session); void close_session(OSDSession *session); void _list_reply(ListContext *list_context, int r, Context *final_finish, epoch_t reply_epoch); void resend_mon_ops(); /** * handle a budget for in-flight ops * budget is taken whenever an op goes into the ops map * and returned whenever an op is removed from the map * If throttle_op needs to throttle it will unlock client_lock. */ int calc_op_budget(Op *op); void throttle_op(Op *op, int op_size=0); int take_op_budget(Op *op) { int op_budget = calc_op_budget(op); if (keep_balanced_budget) { throttle_op(op, op_budget); } else { op_throttle_bytes.take(op_budget); op_throttle_ops.take(1); } op->budgeted = true; return op_budget; } void put_op_budget_bytes(int op_budget) { assert(op_budget >= 0); op_throttle_bytes.put(op_budget); op_throttle_ops.put(1); } void put_op_budget(Op *op) { assert(op->budgeted); int op_budget = calc_op_budget(op); put_op_budget_bytes(op_budget); } void put_list_context_budget(ListContext *list_context); Throttle op_throttle_bytes, op_throttle_ops; public: Objecter(CephContext *cct_, Messenger *m, MonClient *mc, OSDMap *om, Mutex& l, SafeTimer& t, double mon_timeout, double osd_timeout) : messenger(m), monc(mc), osdmap(om), cct(cct_), initialized(false), last_tid(0), client_inc(-1), max_linger_id(0), num_unacked(0), num_uncommitted(0), global_op_flags(0), keep_balanced_budget(false), honor_osdmap_full(true), last_seen_osdmap_version(0), last_seen_pgmap_version(0), client_lock(l), timer(t), logger(NULL), tick_event(NULL), m_request_state_hook(NULL), num_homeless_ops(0), mon_timeout(mon_timeout), osd_timeout(osd_timeout), op_throttle_bytes(cct, "objecter_bytes", cct->_conf->objecter_inflight_op_bytes), op_throttle_ops(cct, "objecter_ops", cct->_conf->objecter_inflight_ops) { } ~Objecter() { assert(!tick_event); assert(!m_request_state_hook); assert(!logger); } void init_unlocked(); void init_locked(); void shutdown_locked(); void shutdown_unlocked(); /** * Tell the objecter to throttle outgoing ops according to its * budget (in _conf). If you do this, ops can block, in * which case it will unlock client_lock and sleep until * incoming messages reduce the used budget low enough for * the ops to continue going; then it will lock client_lock again. */ void set_balanced_budget() { keep_balanced_budget = true; } void unset_balanced_budget() { keep_balanced_budget = false; } void set_honor_osdmap_full() { honor_osdmap_full = true; } void unset_honor_osdmap_full() { honor_osdmap_full = false; } void scan_requests(bool force_resend, bool force_resend_writes, map& need_resend, list& need_resend_linger, map& need_resend_command); int64_t get_object_hash_position(int64_t pool, const string& key, const string& ns); int64_t get_object_pg_hash_position(int64_t pool, const string& key, const string& ns); // messages public: void dispatch(Message *m); void handle_osd_op_reply(class MOSDOpReply *m); void handle_osd_map(class MOSDMap *m); void wait_for_osd_map(); private: // low-level ceph_tid_t _op_submit(Op *op); inline void unregister_op(Op *op); // public interface public: ceph_tid_t op_submit(Op *op, int *ctx_budget = NULL); bool is_active() { return !(ops.empty() && linger_ops.empty() && poolstat_ops.empty() && statfs_ops.empty()); } /** * Output in-flight requests */ void dump_active(); void dump_requests(Formatter *fmt) const; void dump_ops(Formatter *fmt) const; void dump_linger_ops(Formatter *fmt) const; void dump_command_ops(Formatter *fmt) const; void dump_pool_ops(Formatter *fmt) const; void dump_pool_stat_ops(Formatter *fmt) const; void dump_statfs_ops(Formatter *fmt) const; int get_client_incarnation() const { return client_inc; } void set_client_incarnation(int inc) { client_inc = inc; } void wait_for_new_map(Context *c, epoch_t epoch, int err=0); void wait_for_latest_osdmap(Context *fin); void _get_latest_version(epoch_t oldest, epoch_t neweset, Context *fin); /** Get the current set of global op flags */ int get_global_op_flags() { return global_op_flags; } /** Add a flag to the global op flags */ void add_global_op_flags(int flag) { global_op_flags |= flag; } /** Clear the passed flags from the global op flag set */ void clear_global_op_flag(int flags) { global_op_flags &= ~flags; } /// cancel an in-progress request with the given return code int op_cancel(ceph_tid_t tid, int r); // commands int osd_command(int osd, vector& cmd, const bufferlist& inbl, ceph_tid_t *ptid, bufferlist *poutbl, string *prs, Context *onfinish) { assert(osd >= 0); CommandOp *c = new CommandOp; c->cmd = cmd; c->inbl = inbl; c->poutbl = poutbl; c->prs = prs; c->onfinish = onfinish; c->target_osd = osd; return _submit_command(c, ptid); } int pg_command(pg_t pgid, vector& cmd, const bufferlist& inbl, ceph_tid_t *ptid, bufferlist *poutbl, string *prs, Context *onfinish) { CommandOp *c = new CommandOp; c->cmd = cmd; c->inbl = inbl; c->poutbl = poutbl; c->prs = prs; c->onfinish = onfinish; c->target_pg = pgid; return _submit_command(c, ptid); } // mid-level helpers Op *prepare_mutate_op(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, const SnapContext& snapc, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL) { Op *o = new Op(oid, oloc, op.ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->priority = op.priority; o->mtime = mtime; o->snapc = snapc; o->out_rval.swap(op.out_rval); return o; } ceph_tid_t mutate(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, const SnapContext& snapc, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL) { Op *o = prepare_mutate_op(oid, oloc, op, snapc, mtime, flags, onack, oncommit, objver); return op_submit(o); } Op *prepare_read_op(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, snapid_t snapid, bufferlist *pbl, int flags, Context *onack, version_t *objver = NULL) { Op *o = new Op(oid, oloc, op.ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onack, NULL, objver); o->priority = op.priority; o->snapid = snapid; o->outbl = pbl; o->out_bl.swap(op.out_bl); o->out_handler.swap(op.out_handler); o->out_rval.swap(op.out_rval); return o; } ceph_tid_t read(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, snapid_t snapid, bufferlist *pbl, int flags, Context *onack, version_t *objver = NULL) { Op *o = prepare_read_op(oid, oloc, op, snapid, pbl, flags, onack, objver); return op_submit(o); } ceph_tid_t pg_read(uint32_t hash, object_locator_t oloc, ObjectOperation& op, bufferlist *pbl, int flags, Context *onack, epoch_t *reply_epoch, int *ctx_budget) { Op *o = new Op(object_t(), oloc, op.ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onack, NULL, NULL); o->target.precalc_pgid = true; o->target.base_pgid = pg_t(hash, oloc.pool); o->priority = op.priority; o->snapid = CEPH_NOSNAP; o->outbl = pbl; o->out_bl.swap(op.out_bl); o->out_handler.swap(op.out_handler); o->out_rval.swap(op.out_rval); o->reply_epoch = reply_epoch; if (ctx_budget) { // budget is tracked by listing context o->ctx_budgeted = true; } return op_submit(o, ctx_budget); } ceph_tid_t linger_mutate(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, const SnapContext& snapc, utime_t mtime, bufferlist& inbl, int flags, Context *onack, Context *onfinish, version_t *objver); ceph_tid_t linger_read(const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, snapid_t snap, bufferlist& inbl, bufferlist *poutbl, int flags, Context *onack, version_t *objver); void unregister_linger(uint64_t linger_id); /** * set up initial ops in the op vector, and allocate a final op slot. * * The caller is responsible for filling in the final ops_count ops. * * @param ops op vector * @param ops_count number of final ops the caller will fill in * @param extra_ops pointer to [array of] initial op[s] * @return index of final op (for caller to fill in) */ int init_ops(vector& ops, int ops_count, ObjectOperation *extra_ops) { int i; int extra = 0; if (extra_ops) extra = extra_ops->ops.size(); ops.resize(ops_count + extra); for (i=0; iops[i]; } return i; } // high-level helpers ceph_tid_t stat(const object_t& oid, const object_locator_t& oloc, snapid_t snap, uint64_t *psize, utime_t *pmtime, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_STAT; C_Stat *fin = new C_Stat(psize, pmtime, onfinish); Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, fin, 0, objver); o->snapid = snap; o->outbl = &fin->bl; return op_submit(o); } ceph_tid_t read(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snap, bufferlist *pbl, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_READ; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, 0, objver); o->snapid = snap; o->outbl = pbl; return op_submit(o); } ceph_tid_t read_trunc(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snap, bufferlist *pbl, int flags, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_READ; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = trunc_size; ops[i].op.extent.truncate_seq = trunc_seq; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, 0, objver); o->snapid = snap; o->outbl = pbl; return op_submit(o); } ceph_tid_t mapext(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, snapid_t snap, bufferlist *pbl, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_MAPEXT; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, 0, objver); o->snapid = snap; o->outbl = pbl; return op_submit(o); } ceph_tid_t getxattr(const object_t& oid, const object_locator_t& oloc, const char *name, snapid_t snap, bufferlist *pbl, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_GETXATTR; ops[i].op.xattr.name_len = (name ? strlen(name) : 0); ops[i].op.xattr.value_len = 0; if (name) ops[i].indata.append(name); Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, 0, objver); o->snapid = snap; o->outbl = pbl; return op_submit(o); } ceph_tid_t getxattrs(const object_t& oid, const object_locator_t& oloc, snapid_t snap, map& attrset, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_GETXATTRS; C_GetAttrs *fin = new C_GetAttrs(attrset, onfinish); Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, fin, 0, objver); o->snapid = snap; o->outbl = &fin->bl; return op_submit(o); } ceph_tid_t read_full(const object_t& oid, const object_locator_t& oloc, snapid_t snap, bufferlist *pbl, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { return read(oid, oloc, 0, 0, snap, pbl, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, objver); } // writes ceph_tid_t _modify(const object_t& oid, const object_locator_t& oloc, vector& ops, utime_t mtime, const SnapContext& snapc, int flags, Context *onack, Context *oncommit, version_t *objver = NULL) { Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t write(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITE; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; ops[i].indata = bl; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t append(const object_t& oid, const object_locator_t& oloc, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_APPEND; ops[i].op.extent.offset = 0; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; ops[i].indata = bl; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t write_trunc(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, int flags, uint64_t trunc_size, __u32 trunc_seq, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITE; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = trunc_size; ops[i].op.extent.truncate_seq = trunc_seq; ops[i].indata = bl; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t write_full(const object_t& oid, const object_locator_t& oloc, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITEFULL; ops[i].op.extent.offset = 0; ops[i].op.extent.length = bl.length(); ops[i].indata = bl; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t trunc(const object_t& oid, const object_locator_t& oloc, const SnapContext& snapc, utime_t mtime, int flags, uint64_t trunc_size, __u32 trunc_seq, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_TRUNCATE; ops[i].op.extent.offset = trunc_size; ops[i].op.extent.truncate_size = trunc_size; ops[i].op.extent.truncate_seq = trunc_seq; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t zero(const object_t& oid, const object_locator_t& oloc, uint64_t off, uint64_t len, const SnapContext& snapc, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_ZERO; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t rollback_object(const object_t& oid, const object_locator_t& oloc, const SnapContext& snapc, snapid_t snapid, utime_t mtime, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_ROLLBACK; ops[i].op.snap.snapid = snapid; Op *o = new Op(oid, oloc, ops, CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t create(const object_t& oid, const object_locator_t& oloc, const SnapContext& snapc, utime_t mtime, int global_flags, int create_flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_CREATE; ops[i].op.flags = create_flags; Op *o = new Op(oid, oloc, ops, global_flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t remove(const object_t& oid, const object_locator_t& oloc, const SnapContext& snapc, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_DELETE; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t lock(const object_t& oid, const object_locator_t& oloc, int op, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { SnapContext snapc; // no snapc for lock ops vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = op; Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->snapc = snapc; return op_submit(o); } ceph_tid_t setxattr(const object_t& oid, const object_locator_t& oloc, const char *name, const SnapContext& snapc, const bufferlist &bl, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_SETXATTR; ops[i].op.xattr.name_len = (name ? strlen(name) : 0); ops[i].op.xattr.value_len = bl.length(); if (name) ops[i].indata.append(name); ops[i].indata.append(bl); Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } ceph_tid_t removexattr(const object_t& oid, const object_locator_t& oloc, const char *name, const SnapContext& snapc, utime_t mtime, int flags, Context *onack, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { vector ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_RMXATTR; ops[i].op.xattr.name_len = (name ? strlen(name) : 0); ops[i].op.xattr.value_len = 0; if (name) ops[i].indata.append(name); Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, onack, oncommit, objver); o->mtime = mtime; o->snapc = snapc; return op_submit(o); } void list_objects(ListContext *p, Context *onfinish); uint32_t list_objects_seek(ListContext *p, uint32_t pos); // ------------------------- // pool ops private: void pool_op_submit(PoolOp *op); void _pool_op_submit(PoolOp *op); public: int create_pool_snap(int64_t pool, string& snapName, Context *onfinish); int allocate_selfmanaged_snap(int64_t pool, snapid_t *psnapid, Context *onfinish); int delete_pool_snap(int64_t pool, string& snapName, Context *onfinish); int delete_selfmanaged_snap(int64_t pool, snapid_t snap, Context *onfinish); int create_pool(string& name, Context *onfinish, uint64_t auid=0, int crush_rule=-1); int delete_pool(int64_t pool, Context *onfinish); int change_pool_auid(int64_t pool, Context *onfinish, uint64_t auid); void handle_pool_op_reply(MPoolOpReply *m); int pool_op_cancel(ceph_tid_t tid, int r); void finish_pool_op(PoolOp *op); // -------------------------- // pool stats private: void poolstat_submit(PoolStatOp *op); public: void handle_get_pool_stats_reply(MGetPoolStatsReply *m); void get_pool_stats(list& pools, map *result, Context *onfinish); int pool_stat_op_cancel(ceph_tid_t tid, int r); void finish_pool_stat_op(PoolStatOp *op); // --------------------------- // df stats private: void fs_stats_submit(StatfsOp *op); public: void handle_fs_stats_reply(MStatfsReply *m); void get_fs_stats(struct ceph_statfs& result, Context *onfinish); int statfs_op_cancel(ceph_tid_t tid, int r); void finish_statfs_op(StatfsOp *op); // --------------------------- // some scatter/gather hackery void _sg_read_finish(vector& extents, vector& resultbl, bufferlist *bl, Context *onfinish); struct C_SGRead : public Context { Objecter *objecter; vector extents; vector resultbl; bufferlist *bl; Context *onfinish; C_SGRead(Objecter *ob, vector& e, vector& r, bufferlist *b, Context *c) : objecter(ob), bl(b), onfinish(c) { extents.swap(e); resultbl.swap(r); } void finish(int r) { objecter->_sg_read_finish(extents, resultbl, bl, onfinish); } }; void sg_read_trunc(vector& extents, snapid_t snap, bufferlist *bl, int flags, uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) { if (extents.size() == 1) { read_trunc(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length, snap, bl, flags, extents[0].truncate_size, trunc_seq, onfinish); } else { C_GatherBuilder gather(cct); vector resultbl(extents.size()); int i=0; for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { read_trunc(p->oid, p->oloc, p->offset, p->length, snap, &resultbl[i++], flags, p->truncate_size, trunc_seq, gather.new_sub()); } gather.set_finisher(new C_SGRead(this, extents, resultbl, bl, onfinish)); gather.activate(); } } void sg_read(vector& extents, snapid_t snap, bufferlist *bl, int flags, Context *onfinish) { sg_read_trunc(extents, snap, bl, flags, 0, 0, onfinish); } void sg_write_trunc(vector& extents, const SnapContext& snapc, const bufferlist& bl, utime_t mtime, int flags, uint64_t trunc_size, __u32 trunc_seq, Context *onack, Context *oncommit) { if (extents.size() == 1) { write_trunc(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length, snapc, bl, mtime, flags, extents[0].truncate_size, trunc_seq, onack, oncommit); } else { C_GatherBuilder gack(cct, onack); C_GatherBuilder gcom(cct, oncommit); for (vector::iterator p = extents.begin(); p != extents.end(); ++p) { bufferlist cur; for (vector >::iterator bit = p->buffer_extents.begin(); bit != p->buffer_extents.end(); ++bit) bl.copy(bit->first, bit->second, cur); assert(cur.length() == p->length); write_trunc(p->oid, p->oloc, p->offset, p->length, snapc, cur, mtime, flags, p->truncate_size, trunc_seq, onack ? gack.new_sub():0, oncommit ? gcom.new_sub():0); } gack.activate(); gcom.activate(); } } void sg_write(vector& extents, const SnapContext& snapc, const bufferlist& bl, utime_t mtime, int flags, Context *onack, Context *oncommit) { sg_write_trunc(extents, snapc, bl, mtime, flags, 0, 0, onack, oncommit); } void ms_handle_connect(Connection *con); void ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con); void blacklist_self(bool set); }; #endif ceph-0.80.11/src/mkcephfs.in0000664000175100017510000003304312623076744017617 0ustar jenkins-buildjenkins-build#!/bin/sh # # mkcephfs # # This tool is designed to be flexible. There are two ways to go: # # The easy way does everything for you using ssh keys. This does not # scale well for large clusters. # # master$ mkcephfs -a -c /etc/ceph/ceph.conf # # Alternatively, you can use whatever file distribution and/or job # launching you want. # # master$ mkdir /tmp/foo # master$ mkcephfs -d /tmp/foo -c /etc/ceph/ceph.conf --prepare-monmap # # ...copy/share /tmp/foo with all osd and mds nodes at /tmp/bar... # # osd$ mkcephfs -d /tmp/bar --init-local-daemons osd # mds$ mkcephfs -d /tmp/bar --init-local-daemons mds # # ...gather contents of /tmp/bar's back into /tmp/foo... # # master$ mkcephfs -d /tmp/foo --prepare-mon # # ...distribute /tmp/foo to each monitor node... # # mon$ mkcephfs -d /tmp/foo --init-local-daemons mon # # master$ cp /tmp/foo/keyring.admin /etc/ceph/keyring # don't forget! # # In the degenerate case (one node), this is just # # mkdir /tmp/foo # mkcephfs -c ceph.conf -d /tmp/foo --prepare-monmap # mkcephfs -d /tmp/foo --init-local-daemons mds # mkcephfs -d /tmp/foo --init-local-daemons osd # mkcephfs -d /tmp/foo --prepare-mon # mkcephfs -d /tmp/foo --init-local-daemons mon # cp /tmp/foo/keyring.admin /etc/ceph/keyring # # or simply # # mkcephfs -a -c ceph.conf # set -e trap 'echo "\nWARNING: mkcephfs is now deprecated in favour of ceph-deploy. Please see: \n http://github.com/ceph/ceph-deploy"' EXIT # if we start up as ./mkcephfs, assume everything else is in the # current directory too. if [ `dirname $0` = "." ] && [ $PWD != "/etc/init.d" ]; then BINDIR=. LIBDIR=. ETCDIR=. else BINDIR=@bindir@ LIBDIR=@libdir@/ceph ETCDIR=@sysconfdir@/ceph fi usage_exit() { echo "usage: $0 -a -c ceph.conf [-k adminkeyring] [--mkfs]" echo " to generate a new ceph cluster on all nodes; for advanced usage see man page" echo " ** be careful, this WILL clobber old data; check your ceph.conf carefully **" exit } . $LIBDIR/ceph_common.sh allhosts=0 mkfs=0 preparemonmap=0 prepareosdfs="" initdaemon="" initdaemons="" preparemon=0 numosd= useosdmap= usecrushmapsrc= usecrushmap= verbose=0 adminkeyring="" conf="" dir="" moreargs="" auto_action=0 manual_action=0 nocopyconf=0 while [ $# -ge 1 ]; do case $1 in -v ) verbose=1; ;; --dir | -d) [ -z "$2" ] && usage_exit shift dir=$1 ;; --allhosts | -a) allhosts=1 auto_action=1 ;; --prepare-monmap) preparemonmap=1 manual_action=1 ;; --prepare-osdfs) [ -z "$2" ] && usage_exit shift prepareosdfs=$1 manual_action=1 ;; --init-daemon) [ -z "$2" ] && usage_exit shift initdaemon=$1 manual_action=1 ;; --init-local-daemons) [ -z "$2" ] && usage_exit shift initlocaldaemons=$1 manual_action=1 ;; --prepare-mon) preparemon=1 manual_action=1 ;; --mkbtrfs | --mkfs) mkfs=1 ;; --no-copy-conf) nocopyconf=1 ;; --conf | -c) [ -z "$2" ] && usage_exit shift conf=$1 ;; --numosd) [ -z "$2" ] && usage_exit shift numosd=$1 moreargs="$moreargs --numosd $1" ;; --osdmap) [ -z "$2" ] && usage_exit shift useosdmap=$1 moreargs="$moreargs --osdmap $1" ;; --crushmapsrc) [ -z "$2" ] && usage_exit shift usecrushmapsrc=$1 moreargs="$moreargs --crushmapsrc $1" ;; --crushmap) [ -z "$2" ] && usage_exit shift usecrushmap=$1 moreargs="$moreargs --crushmap $1" ;; -k) [ -z "$2" ] && usage_exit shift adminkeyring=$1 ;; *) echo unrecognized option \'$1\' usage_exit ;; esac shift done [ -z "$conf" ] && [ -n "$dir" ] && conf="$dir/conf" if [ $manual_action -eq 0 ]; then if [ $auto_action -eq 0 ]; then echo "You must specify an action. See man page." usage_exit fi elif [ $auto_action -eq 1 ]; then echo "The -a option cannot be combined with other subcommands; see man page." usage_exit fi ### prepare-monmap ### if [ $preparemonmap -eq 1 ]; then echo "preparing monmap in $dir/monmap" # first, make a list of monitors mons=`$CCONF -c $conf -l mon | egrep -v '^mon$' | sort` args="" type="mon" for name in $mons; do id=`echo $name | cut -c 4- | sed 's/^\\.//'` get_conf addr "" "mon addr" if [ -z "$addr" ]; then echo "$0: monitor $name has no address defined." 1>&2 exit 1 fi args=$args" --add $id $addr" done if [ -z "$args" ]; then echo "$0: no monitors found in config, aborting." 1>&2 exit 1 fi # build monmap monmap="$dir/monmap" echo $BINDIR/monmaptool --create --clobber $args --print $monmap || exit 1 $BINDIR/monmaptool --create --clobber $args --print $monmap || exit 1 # copy conf cp $conf $dir/conf exit 0 fi ### init-daemon ### if [ -n "$initdaemon" ]; then name=$initdaemon type=`echo $name | cut -c 1-3` # e.g. 'mon', if $name is 'mon1' id=`echo $name | cut -c 4- | sed 's/^\\.//'` name="$type.$id" # create /var/run/ceph (or wherever pid file and/or admin socket live) get_conf pid_file "/var/run/ceph/$name.pid" "pid file" rundir=`dirname $pid_file` if [ "$rundir" != "." ] && [ ! -d "$rundir" ]; then mkdir -p $rundir fi get_conf asok_file "/var/run/ceph/$name.asok" "admin socket" rundir=`dirname $asok_file` if [ "$rundir" != "." ] && [ ! -d "$rundir" ]; then mkdir -p $rundir fi if [ $type = "osd" ]; then $BINDIR/ceph-osd -c $conf --monmap $dir/monmap -i $id --mkfs --mkkey get_conf osd_data "/var/lib/ceph/osd/ceph-$id" "osd data" get_conf osd_keyring "$osd_data/keyring" "keyring" $BINDIR/ceph-authtool -p -n $name $osd_keyring > $dir/key.$name fi if [ $type = "mds" ]; then get_conf mds_data "/var/lib/ceph/mds/ceph-$id" "mds data" get_conf mds_keyring "$mds_data/keyring" "keyring" test -d $mds_data || mkdir -p $mds_data echo "creating private key for $name keyring $mds_keyring" $BINDIR/ceph-authtool --create-keyring --gen-key -n $name $mds_keyring $BINDIR/ceph-authtool -p -n $name $mds_keyring > $dir/key.$name fi if [ $type = "mon" ]; then get_conf mon_data "/var/lib/ceph/mon/ceph-$id" "mon data" mkdir -p "$mon_data" if ! find "$mon_data" -maxdepth 0 -empty | read foo; then echo "ERROR: $name mon_data directory $mon_data is not empty." echo " Please make sure that it is empty before running mkcephfs." exit 1 fi $BINDIR/ceph-mon -c $conf --mkfs -i $id --monmap $dir/monmap --osdmap $dir/osdmap -k $dir/keyring.mon fi exit 0 fi ## init-local-daemons ## if [ -n "$initlocaldaemons" ]; then get_name_list "$initlocaldaemons" for name in $what; do type=`echo $name | cut -c 1-3` # e.g. 'mon', if $name is 'mon1' id=`echo $name | cut -c 4- | sed 's/^\\.//'` num=$id name="$type.$id" check_host || continue $0 -d $dir --init-daemon $name done exit 0 fi ### prepare-osdfs ### if [ -n "$prepareosdfs" ]; then name=$prepareosdfs type=`echo $name | cut -c 1-3` # e.g. 'mon', if $name is 'mon1' id=`echo $name | cut -c 4- | sed 's/^\\.//'` name="$type.$id" get_conf osd_data "/var/lib/ceph/osd/ceph-$id" "osd data" get_conf osd_journal "$osd_data/journal" "osd journal" get_conf fs_path "$osd_data" "fs path" # mount point defaults so osd data get_conf fs_devs "" "devs" get_conf fs_type "" "osd mkfs type" if [ -z "$fs_devs" ]; then # try to fallback to old keys get_conf tmp_btrfs_devs "" "btrfs devs" if [ -n "$tmp_btrfs_devs" ]; then fs_devs="$tmp_btrfs_devs" else echo "no devs defined for $name" exit 1 fi fi if [ -z "$fs_type" ]; then # try to fallback to to old keys get_conf tmp_devs "" "btrfs devs" if [ -n "$tmp_devs" ]; then fs_type="btrfs" else echo No filesystem type defined! exit 1 fi fi first_dev=`echo $fs_devs | cut '-d ' -f 1` get_conf fs_opt "" "osd mount options $fs_type" if [ -z "$fs_opt" ]; then if [ "$fs_type" = "btrfs" ]; then #try to fallback to old keys get_conf fs_opt "" "btrfs options" fi if [ -z "$fs_opt" ]; then if [ "$fs_type" = "xfs" ]; then fs_opt="rw,noatime,inode64" else #fallback to use at least rw,noatime fs_opt="rw,noatime" fi fi fi [ -n "$fs_opt" ] && fs_opt="-o $fs_opt" get_conf osd_user "root" "user" if [ -n "$osd_journal" ] && echo "fs_devs" | grep -q -w "$osd_journal" ; then echo "ERROR: osd journal device ($osd_journal) also used by devs ($fs_devs)" exit 1 fi test -d $osd_data || mkdir -p $osd_data if [ -n "$osd_journal" ]; then test -d $osd_journal || mkdir -p `dirname $osd_journal` fi umount $fs_path || true for f in $fs_devs ; do umount $f || true done get_conf mkfs_opt "" "osd mkfs options $fs_type" if [ "$fs_type" = "xfs" ] && [ -z "$mkfs_opt" ]; then echo Xfs filesystem found add missing -f mkfs option! mkfs_opt="-f" fi modprobe $fs_type || true mkfs.$fs_type $mkfs_opt $fs_devs mount -t $fs_type $fs_opt $first_dev $fs_path chown $osd_user $fs_path chmod +w $fs_path exit 0 fi ### prepare-mon ### if [ $preparemon -eq 1 ]; then if [ -n "$useosdmap" ]; then echo "Using osdmap $useosdmap" cp $useosdmap $dir/osdmap else echo "Building generic osdmap from $conf" $BINDIR/osdmaptool --create-from-conf $dir/osdmap -c $conf fi # import crush map? get_conf crushmapsrc "" "crush map src" mon global if [ -n "$crushmapsrc" ]; then echo Compiling crush map from $crushmapsrc to $dir/crushmap $BINDIR/crushtool -c $crushmapsrc -o $dir/crushmap fi get_conf crushmap "$usecrushmap" "crush map" mon global if [ -n "$crushmap" ]; then echo Importing crush map from $crushmap $BINDIR/osdmaptool --import-crush $crushmap $dir/osdmap fi # admin keyring echo Generating admin key at $dir/keyring.admin $BINDIR/ceph-authtool --create-keyring --gen-key -n client.admin $dir/keyring.admin # mon keyring echo Building initial monitor keyring cp $dir/keyring.admin $dir/keyring.mon $BINDIR/ceph-authtool -n client.admin --set-uid=0 \ --cap mon 'allow *' \ --cap osd 'allow *' \ --cap mds 'allow' \ $dir/keyring.mon $BINDIR/ceph-authtool --gen-key -n mon. $dir/keyring.mon --cap mon 'allow *' for k in $dir/key.* do kname=`echo $k | sed 's/.*key\.//'` ktype=`echo $kname | cut -c 1-3` kid=`echo $kname | cut -c 4- | sed 's/^\\.//'` kname="$ktype.$kid" secret=`cat $k` if [ "$ktype" = "osd" ]; then $BINDIR/ceph-authtool -n $kname --add-key $secret $dir/keyring.mon \ --cap mon 'allow rwx' \ --cap osd 'allow *' fi if [ "$ktype" = "mds" ]; then $BINDIR/ceph-authtool -n $kname --add-key $secret $dir/keyring.mon \ --cap mon "allow rwx" \ --cap osd 'allow *' \ --cap mds 'allow' fi done exit 0 fi ### do everything via ssh ### if [ $allhosts -eq 1 ]; then verify_conf # do it all if [ -z "$dir" ]; then dir=`mktemp -d -t mkcephfs.XXXXXXXXXX` || exit 1 echo "temp dir is $dir" trap "rm -rf $dir ; exit" INT TERM EXIT fi $0 --prepare-monmap -d $dir -c $conf # osd, mds get_name_list "osd mds" for name in $what; do type=`echo $name | cut -c 1-3` # e.g. 'mon', if $name is 'mon1' id=`echo $name | cut -c 4- | sed 's/^\\.//'` num=$id name="$type.$id" check_host || continue if [ -n "$ssh" ]; then rdir=`mktemp -u /tmp/mkfs.ceph.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` || exit 1 echo pushing conf and monmap to $host:$rdir do_cmd "mkdir -p $rdir" scp -q $dir/conf $host:$rdir scp -q $dir/monmap $host:$rdir if [ $nocopyconf -eq 0 ]; then # also put conf at /etc/ceph/ceph.conf scp -q $dir/conf $host:/etc/ceph/ceph.conf fi else rdir=$dir if [ $nocopyconf -eq 0 ]; then # also put conf at /etc/ceph/ceph.conf cp $dir/conf /etc/ceph/ceph.conf fi fi if [ $mkfs -eq 1 ] && [ "$type" = "osd" ]; then do_root_cmd "$0 -d $rdir --prepare-osdfs $name" fi do_root_cmd "$0 -d $rdir --init-daemon $name" # collect the key if [ -n "$ssh" ]; then echo collecting $name key scp -q $host:$rdir/key.$name $dir #cleanup no longer need rdir do_cmd "rm -r $rdir" fi done # prepare monitors $0 -d $dir --prepare-mon $moreargs # mons get_name_list "mon" for name in $what; do type=`echo $name | cut -c 1-3` # e.g. 'mon', if $name is 'mon1' id=`echo $name | cut -c 4- | sed 's/^\\.//'` num=$id name="$type.$id" check_host || continue if [ -n "$ssh" ]; then rdir=`mktemp -u /tmp/mkfs.ceph.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` || exit 1 echo pushing everything to $host ssh $host mkdir -p $rdir scp -q $dir/* $host:$rdir if [ $nocopyconf -eq 0 ]; then # also put conf at /etc/ceph/ceph.conf scp -q $dir/conf $host:/etc/ceph/ceph.conf fi else rdir=$dir if [ $nocopyconf -eq 0 ]; then # also put conf at /etc/ceph/ceph.conf cp $dir/conf /etc/ceph/ceph.conf fi fi do_root_cmd "$0 -d $rdir --init-daemon $name" if [ -n "$ssh" ]; then #cleanup no longer need rdir do_cmd "rm -r $rdir" fi done # admin keyring if [ -z "$adminkeyring" ]; then get_conf adminkeyring "/etc/ceph/keyring" "keyring" global fi echo "placing client.admin keyring in $adminkeyring" cp $dir/keyring.admin $adminkeyring exit 0 fi ceph-0.80.11/src/Makefile.in0000664000175100017510000545157212623076765017557 0ustar jenkins-buildjenkins-build# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ DIST_COMMON = $(srcdir)/Makefile-env.am $(srcdir)/arch/Makefile.am \ $(srcdir)/auth/Makefile.am $(srcdir)/brag/Makefile.am \ $(srcdir)/crush/Makefile.am $(srcdir)/mon/Makefile.am \ $(srcdir)/mds/Makefile.am $(srcdir)/os/Makefile.am \ $(srcdir)/osd/Makefile.am $(srcdir)/erasure-code/Makefile.am \ $(srcdir)/erasure-code/jerasure/Makefile.am \ $(srcdir)/osdc/Makefile.am $(srcdir)/client/Makefile.am \ $(srcdir)/global/Makefile.am $(srcdir)/json_spirit/Makefile.am \ $(srcdir)/log/Makefile.am $(srcdir)/perfglue/Makefile.am \ $(srcdir)/common/Makefile.am $(srcdir)/msg/Makefile.am \ $(srcdir)/messages/Makefile.am $(srcdir)/include/Makefile.am \ $(srcdir)/librados/Makefile.am $(srcdir)/librbd/Makefile.am \ $(srcdir)/rgw/Makefile.am $(srcdir)/cls/Makefile.am \ $(srcdir)/key_value_store/Makefile.am \ $(srcdir)/test/Makefile.am \ $(srcdir)/test/erasure-code/Makefile.am \ $(srcdir)/tools/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(srcdir)/acconfig.h.in \ $(dist_bin_SCRIPTS) $(top_srcdir)/depcomp $(python_PYTHON) \ $(top_srcdir)/py-compile $(am__noinst_HEADERS_DIST) \ $(top_srcdir)/test-driver README TODO bin_PROGRAMS = $(am__EXEEXT_9) $(am__EXEEXT_10) ceph-dencoder$(EXEEXT) \ ceph-objectstore-tool$(EXEEXT) monmaptool$(EXEEXT) \ crushtool$(EXEEXT) osdmaptool$(EXEEXT) rados$(EXEEXT) \ $(am__EXEEXT_11) ceph-conf$(EXEEXT) ceph-authtool$(EXEEXT) \ ceph_mon_store_converter$(EXEEXT) ceph-mon$(EXEEXT) \ ceph-osd$(EXEEXT) ceph-mds$(EXEEXT) cephfs$(EXEEXT) \ librados-config$(EXEEXT) ceph-syn$(EXEEXT) $(am__EXEEXT_12) \ $(am__EXEEXT_13) noinst_PROGRAMS = ceph_erasure_code_non_regression$(EXEEXT) \ get_command_descriptions$(EXEEXT) sbin_PROGRAMS = su_sbin_PROGRAMS = $(am__EXEEXT_14) check_PROGRAMS = unittest_erasure_code_plugin$(EXEEXT) \ unittest_erasure_code_jerasure$(EXEEXT) \ unittest_erasure_code_plugin_jerasure$(EXEEXT) \ unittest_erasure_code_example$(EXEEXT) \ unittest_encoding$(EXEEXT) unittest_addrs$(EXEEXT) \ unittest_bloom_filter$(EXEEXT) unittest_histogram$(EXEEXT) \ unittest_str_map$(EXEEXT) unittest_sharedptr_registry$(EXEEXT) \ unittest_sloppy_crc_map$(EXEEXT) unittest_util$(EXEEXT) \ unittest_crush_indep$(EXEEXT) unittest_osdmap$(EXEEXT) \ unittest_workqueue$(EXEEXT) unittest_striper$(EXEEXT) \ unittest_prebufferedstreambuf$(EXEEXT) \ unittest_str_list$(EXEEXT) unittest_log$(EXEEXT) \ unittest_throttle$(EXEEXT) unittest_crush_wrapper$(EXEEXT) \ unittest_base64$(EXEEXT) unittest_ceph_argparse$(EXEEXT) \ unittest_ceph_compatset$(EXEEXT) unittest_osd_types$(EXEEXT) \ unittest_pglog$(EXEEXT) unittest_ecbackend$(EXEEXT) \ unittest_hitset$(EXEEXT) unittest_io_priority$(EXEEXT) \ unittest_gather$(EXEEXT) unittest_run_cmd$(EXEEXT) \ unittest_signals$(EXEEXT) unittest_simple_spin$(EXEEXT) \ unittest_librados$(EXEEXT) unittest_bufferlist$(EXEEXT) \ unittest_crc32c$(EXEEXT) unittest_arch$(EXEEXT) \ unittest_crypto$(EXEEXT) unittest_crypto_init$(EXEEXT) \ unittest_perf_counters$(EXEEXT) unittest_admin_socket$(EXEEXT) \ unittest_ceph_crypto$(EXEEXT) unittest_utf8$(EXEEXT) \ unittest_mime$(EXEEXT) unittest_escape$(EXEEXT) \ unittest_chain_xattr$(EXEEXT) unittest_flatindex$(EXEEXT) \ unittest_strtol$(EXEEXT) unittest_confutils$(EXEEXT) \ unittest_config$(EXEEXT) unittest_context$(EXEEXT) \ unittest_heartbeatmap$(EXEEXT) unittest_formatter$(EXEEXT) \ unittest_libcephfs_config$(EXEEXT) unittest_lfnindex$(EXEEXT) \ unittest_librados_config$(EXEEXT) \ unittest_daemon_config$(EXEEXT) unittest_osd_osdcap$(EXEEXT) \ unittest_mon_moncap$(EXEEXT) unittest_mon_pgmap$(EXEEXT) \ unittest_ipaddr$(EXEEXT) unittest_texttable$(EXEEXT) \ unittest_on_exit$(EXEEXT) # when doing a debug build, make sure to make the targets @WITH_DEBUG_TRUE@am__append_1 = $(bin_DEBUGPROGRAMS) @LINUX_TRUE@am__append_2 = -Wl,--as-needed @USE_BOOST_SPIRIT_OLD_HDR_TRUE@am__append_3 = -DUSE_BOOST_SPIRIT_OLD_HDR @WITH_LIBATOMIC_TRUE@am__append_4 = -latomic_ops @ENABLE_COVERAGE_TRUE@am__append_5 = -fprofile-arcs -ftest-coverage @ENABLE_COVERAGE_TRUE@am__append_6 = -fprofile-arcs -ftest-coverage -O0 @FREEBSD_TRUE@am__append_7 = -lexecinfo @LINUX_TRUE@am__append_8 = -lrt @WITH_PROFILER_TRUE@am__append_9 = -lprofiler @WITH_LIBAIO_TRUE@am__append_10 = -laio @WITH_LIBZFS_TRUE@am__append_11 = libos_zfs.a -lzfs @WITH_TCMALLOC_TRUE@am__append_12 = -ltcmalloc @ENABLE_COVERAGE_TRUE@am__append_13 = -lgcov @LINUX_TRUE@am__append_14 = os/BtrfsFileStoreBackend.cc @WITH_LIBXFS_TRUE@am__append_15 = os/XfsFileStoreBackend.cc @WITH_LIBZFS_TRUE@am__append_16 = os/ZFSFileStoreBackend.cc @WITH_LIBZFS_TRUE@am__append_17 = libos_zfs.a @WITH_LIBZFS_TRUE@am__append_18 = os/ZFS.h @LINUX_TRUE@am__append_19 = -export-symbols-regex '.*__erasure_code_.*' @LINUX_TRUE@am__append_20 = -export-symbols-regex '.*__erasure_code_.*' @LINUX_TRUE@am__append_21 = -export-symbols-regex '.*__erasure_code_.*' @LINUX_TRUE@am__append_22 = -export-symbols-regex '.*__erasure_code_.*' @WITH_FUSE_TRUE@am__append_23 = libclient_fuse.la @WITH_FUSE_TRUE@am__append_24 = client/fuse_ll.h @WITH_TCMALLOC_TRUE@am__append_25 = perfglue/heap_profiler.cc @WITH_TCMALLOC_TRUE@am__append_26 = -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free @WITH_TCMALLOC_TRUE@am__append_27 = -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free @WITH_TCMALLOC_FALSE@am__append_28 = perfglue/disabled_heap_profiler.cc @WITH_PROFILER_TRUE@am__append_29 = perfglue/cpu_profiler.cc @WITH_PROFILER_FALSE@am__append_30 = perfglue/disabled_stubs.cc @WITH_GOOD_YASM_ELF64_TRUE@am__append_31 = common/crc32c_intel_fast_asm.S common/crc32c_intel_fast_zero_asm.S @LINUX_TRUE@am__append_32 = -lrt @LINUX_TRUE@am__append_33 = -export-symbols-regex '^rados_.*' @LINUX_TRUE@am__append_34 = -export-symbols-regex '^rbd_.*' @WITH_RADOSGW_TRUE@am__append_35 = librgw.la libcivetweb.la @WITH_RADOSGW_TRUE@am__append_36 = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la \ @WITH_RADOSGW_TRUE@ libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a \ @WITH_RADOSGW_TRUE@ libcls_user_client.a \ @WITH_RADOSGW_TRUE@ libcls_replica_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_lock_client.la \ @WITH_RADOSGW_TRUE@ libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_version_client.a \ @WITH_RADOSGW_TRUE@ -lcurl \ @WITH_RADOSGW_TRUE@ -lexpat \ @WITH_RADOSGW_TRUE@ -lm \ @WITH_RADOSGW_TRUE@ -lfcgi \ @WITH_RADOSGW_TRUE@ -ldl @WITH_RADOSGW_TRUE@am__append_37 = radosgw radosgw-admin @WITH_RADOSGW_TRUE@am__append_38 = ceph_rgw_multiparser \ @WITH_RADOSGW_TRUE@ ceph_rgw_jsonparser # inject rgw stuff in the decoder testcase @WITH_RADOSGW_TRUE@am__append_39 = \ @WITH_RADOSGW_TRUE@ rgw/rgw_dencoder.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_acl.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_common.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_env.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_json_enc.cc @LINUX_TRUE@am__append_40 = libcls_kvs.la @LINUX_TRUE@am__append_41 = -ldl @LINUX_TRUE@am__append_42 = -ldl @LINUX_TRUE@am__append_43 = -ldl @LINUX_TRUE@am__append_44 = -ldl @LINUX_TRUE@am__append_45 = -ldl @LINUX_TRUE@am__append_46 = -ldl @COMPILER_HAS_VTA_TRUE@am__append_47 = -fno-var-tracking-assignments @COMPILER_HAS_VTA_TRUE@am__append_48 = -fno-var-tracking-assignments @WITH_BUILD_TESTS_TRUE@am__append_49 = test_build_libcommon \ @WITH_BUILD_TESTS_TRUE@ test_build_librados test_build_librgw \ @WITH_BUILD_TESTS_TRUE@ test_build_libcephfs @LINUX_TRUE@am__append_50 = ceph_kvstorebench \ @LINUX_TRUE@ ceph_test_rados_list_parallel \ @LINUX_TRUE@ ceph_test_rados_open_pools_parallel \ @LINUX_TRUE@ ceph_test_rados_delete_pools_parallel \ @LINUX_TRUE@ ceph_test_rados_watch_notify @LINUX_TRUE@am__append_51 = libsystest.la @LINUX_TRUE@am__append_52 = -ldl @WITH_RADOSGW_TRUE@am__append_53 = ceph_test_cors \ @WITH_RADOSGW_TRUE@ ceph_test_rgw_manifest \ @WITH_RADOSGW_TRUE@ ceph_test_cls_rgw_meta \ @WITH_RADOSGW_TRUE@ ceph_test_cls_rgw_log \ @WITH_RADOSGW_TRUE@ ceph_test_cls_rgw_opstate @LINUX_TRUE@am__append_54 = ceph_test_librbd_fsx @WITH_RADOSGW_TRUE@am__append_55 = ceph_test_cls_rgw @LINUX_TRUE@am__append_56 = ceph_test_objectstore @LINUX_TRUE@am__append_57 = -ldl @WITH_REST_BENCH_TRUE@am__append_58 = rest-bench @WITH_REST_BENCH_TRUE@@WITH_SYSTEM_LIBS3_TRUE@am__append_59 = -ls3 @WITH_REST_BENCH_TRUE@@WITH_SYSTEM_LIBS3_FALSE@am__append_60 = libs3/build/lib/libs3.a -lcurl -lxml2 @WITH_REST_BENCH_TRUE@@WITH_SYSTEM_LIBS3_FALSE@am__append_61 = libs3 @LINUX_TRUE@am__append_62 = mount.ceph @LINUX_TRUE@am__append_63 = rbd @WITH_FUSE_TRUE@am__append_64 = ceph-fuse rbd-fuse @ENABLE_CEPHFS_JAVA_TRUE@am__append_65 = libcephfs_jni.la subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_check_classpath.m4 \ $(top_srcdir)/m4/ac_prog_jar.m4 \ $(top_srcdir)/m4/ac_prog_javac.m4 \ $(top_srcdir)/m4/ac_prog_javac_works.m4 \ $(top_srcdir)/m4/ac_prog_javah.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/ax_c_pretty_func.m4 \ $(top_srcdir)/m4/ax_c_var_func.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_cxx_static_cast.m4 \ $(top_srcdir)/m4/ax_intel.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = acconfig.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libcls_log_client_a_AR = $(AR) $(ARFLAGS) libcls_log_client_a_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_libcls_log_client_a_OBJECTS = cls/log/cls_log_client.$(OBJEXT) libcls_log_client_a_OBJECTS = $(am_libcls_log_client_a_OBJECTS) libcls_replica_log_client_a_AR = $(AR) $(ARFLAGS) libcls_replica_log_client_a_LIBADD = am_libcls_replica_log_client_a_OBJECTS = \ cls/replica_log/cls_replica_log_types.$(OBJEXT) \ cls/replica_log/cls_replica_log_ops.$(OBJEXT) \ cls/replica_log/cls_replica_log_client.$(OBJEXT) libcls_replica_log_client_a_OBJECTS = \ $(am_libcls_replica_log_client_a_OBJECTS) libcls_statelog_client_a_AR = $(AR) $(ARFLAGS) libcls_statelog_client_a_LIBADD = am_libcls_statelog_client_a_OBJECTS = \ cls/statelog/cls_statelog_client.$(OBJEXT) libcls_statelog_client_a_OBJECTS = \ $(am_libcls_statelog_client_a_OBJECTS) libcls_user_client_a_AR = $(AR) $(ARFLAGS) libcls_user_client_a_LIBADD = am_libcls_user_client_a_OBJECTS = cls/user/cls_user_client.$(OBJEXT) \ cls/user/cls_user_types.$(OBJEXT) \ cls/user/cls_user_ops.$(OBJEXT) libcls_user_client_a_OBJECTS = $(am_libcls_user_client_a_OBJECTS) libcls_version_client_a_AR = $(AR) $(ARFLAGS) libcls_version_client_a_LIBADD = am_libcls_version_client_a_OBJECTS = \ cls/version/cls_version_client.$(OBJEXT) \ cls/version/cls_version_types.$(OBJEXT) libcls_version_client_a_OBJECTS = \ $(am_libcls_version_client_a_OBJECTS) libos_zfs_a_AR = $(AR) $(ARFLAGS) libos_zfs_a_LIBADD = am__libos_zfs_a_SOURCES_DIST = os/ZFS.cc @WITH_LIBZFS_TRUE@am_libos_zfs_a_OBJECTS = \ @WITH_LIBZFS_TRUE@ os/libos_zfs_a-ZFS.$(OBJEXT) libos_zfs_a_OBJECTS = $(am_libos_zfs_a_OBJECTS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(erasure_codelibdir)" \ "$(DESTDIR)$(libdir)" "$(DESTDIR)$(radoslibdir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(su_sbindir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(ceph_sbindir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(shell_commondir)" \ "$(DESTDIR)$(su_sbindir)" "$(DESTDIR)$(pythondir)" \ "$(DESTDIR)$(bash_completiondir)" "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(libcephfs_includedir)" \ "$(DESTDIR)$(librbd_includedir)" \ "$(DESTDIR)$(rados_includedir)" LTLIBRARIES = $(erasure_codelib_LTLIBRARIES) $(lib_LTLIBRARIES) \ $(noinst_LTLIBRARIES) $(radoslib_LTLIBRARIES) libarch_la_LIBADD = am_libarch_la_OBJECTS = arch/intel.lo arch/neon.lo arch/probe.lo libarch_la_OBJECTS = $(am_libarch_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libauth_la_LIBADD = am_libauth_la_OBJECTS = auth/AuthAuthorizeHandler.lo \ auth/AuthClientHandler.lo auth/AuthSessionHandler.lo \ auth/AuthServiceHandler.lo auth/AuthMethodList.lo \ auth/cephx/CephxAuthorizeHandler.lo \ auth/cephx/CephxClientHandler.lo auth/cephx/CephxProtocol.lo \ auth/cephx/CephxServiceHandler.lo \ auth/cephx/CephxSessionHandler.lo auth/cephx/CephxKeyServer.lo \ auth/none/AuthNoneAuthorizeHandler.lo \ auth/unknown/AuthUnknownAuthorizeHandler.lo auth/Crypto.lo \ auth/KeyRing.lo auth/RotatingKeyRing.lo libauth_la_OBJECTS = $(am_libauth_la_OBJECTS) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) libcephfs_la_DEPENDENCIES = $(LIBCLIENT) $(LIBCOMMON) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcephfs_la_OBJECTS = libcephfs.lo libcephfs_la_OBJECTS = $(am_libcephfs_la_OBJECTS) libcephfs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(libcephfs_la_LDFLAGS) $(LDFLAGS) -o $@ @ENABLE_CEPHFS_JAVA_TRUE@libcephfs_jni_la_DEPENDENCIES = $(LIBCEPHFS) \ @ENABLE_CEPHFS_JAVA_TRUE@ $(am__DEPENDENCIES_2) am__libcephfs_jni_la_SOURCES_DIST = java/native/libcephfs_jni.cc \ java/native/ScopedLocalRef.h java/native/JniConstants.cpp \ java/native/JniConstants.h @ENABLE_CEPHFS_JAVA_TRUE@am_libcephfs_jni_la_OBJECTS = java/native/libcephfs_jni_la-libcephfs_jni.lo \ @ENABLE_CEPHFS_JAVA_TRUE@ java/native/libcephfs_jni_la-JniConstants.lo libcephfs_jni_la_OBJECTS = $(am_libcephfs_jni_la_OBJECTS) libcephfs_jni_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcephfs_jni_la_LDFLAGS) \ $(LDFLAGS) -o $@ @ENABLE_CEPHFS_JAVA_TRUE@am_libcephfs_jni_la_rpath = -rpath $(libdir) libcivetweb_la_LIBADD = am__libcivetweb_la_SOURCES_DIST = rgw/rgw_civetweb.cc \ rgw/rgw_civetweb_log.cc civetweb/src/civetweb.c @WITH_RADOSGW_TRUE@am_libcivetweb_la_OBJECTS = \ @WITH_RADOSGW_TRUE@ rgw/libcivetweb_la-rgw_civetweb.lo \ @WITH_RADOSGW_TRUE@ rgw/libcivetweb_la-rgw_civetweb_log.lo \ @WITH_RADOSGW_TRUE@ civetweb/src/libcivetweb_la-civetweb.lo libcivetweb_la_OBJECTS = $(am_libcivetweb_la_OBJECTS) libcivetweb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libcivetweb_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ @WITH_RADOSGW_TRUE@am_libcivetweb_la_rpath = libclient_la_DEPENDENCIES = $(LIBOSDC) $(am__DEPENDENCIES_1) am_libclient_la_OBJECTS = client/Client.lo client/Inode.lo \ client/Dentry.lo client/MetaRequest.lo \ client/ClientSnapRealm.lo client/MetaSession.lo \ client/Trace.lo libclient_la_OBJECTS = $(am_libclient_la_OBJECTS) @WITH_FUSE_TRUE@libclient_fuse_la_DEPENDENCIES = libclient.la am__libclient_fuse_la_SOURCES_DIST = client/fuse_ll.cc @WITH_FUSE_TRUE@am_libclient_fuse_la_OBJECTS = client/fuse_ll.lo libclient_fuse_la_OBJECTS = $(am_libclient_fuse_la_OBJECTS) @WITH_FUSE_TRUE@am_libclient_fuse_la_rpath = libcls_hello_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_hello_la_OBJECTS = cls/hello/cls_hello.lo libcls_hello_la_OBJECTS = $(am_libcls_hello_la_OBJECTS) libcls_hello_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_hello_la_LDFLAGS) \ $(LDFLAGS) -o $@ @LINUX_TRUE@libcls_kvs_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ @LINUX_TRUE@ $(am__DEPENDENCIES_2) am__libcls_kvs_la_SOURCES_DIST = key_value_store/cls_kvs.cc @LINUX_TRUE@am_libcls_kvs_la_OBJECTS = key_value_store/cls_kvs.lo libcls_kvs_la_OBJECTS = $(am_libcls_kvs_la_OBJECTS) libcls_kvs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_kvs_la_LDFLAGS) $(LDFLAGS) \ -o $@ @LINUX_TRUE@am_libcls_kvs_la_rpath = -rpath $(radoslibdir) libcls_lock_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_lock_la_OBJECTS = cls/lock/cls_lock.lo libcls_lock_la_OBJECTS = $(am_libcls_lock_la_OBJECTS) libcls_lock_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_lock_la_LDFLAGS) \ $(LDFLAGS) -o $@ libcls_lock_client_la_LIBADD = am_libcls_lock_client_la_OBJECTS = cls/lock/cls_lock_client.lo \ cls/lock/cls_lock_types.lo cls/lock/cls_lock_ops.lo libcls_lock_client_la_OBJECTS = $(am_libcls_lock_client_la_OBJECTS) libcls_log_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_log_la_OBJECTS = cls/log/cls_log.lo libcls_log_la_OBJECTS = $(am_libcls_log_la_OBJECTS) libcls_log_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_log_la_LDFLAGS) $(LDFLAGS) \ -o $@ libcls_rbd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_rbd_la_OBJECTS = cls/rbd/cls_rbd.lo libcls_rbd_la_OBJECTS = $(am_libcls_rbd_la_OBJECTS) libcls_rbd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_rbd_la_LDFLAGS) $(LDFLAGS) \ -o $@ libcls_rbd_client_la_LIBADD = am_libcls_rbd_client_la_OBJECTS = cls/rbd/cls_rbd_client.lo libcls_rbd_client_la_OBJECTS = $(am_libcls_rbd_client_la_OBJECTS) libcls_refcount_la_DEPENDENCIES = libjson_spirit.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am_libcls_refcount_la_OBJECTS = cls/refcount/cls_refcount.lo \ cls/refcount/cls_refcount_ops.lo common/ceph_json.lo libcls_refcount_la_OBJECTS = $(am_libcls_refcount_la_OBJECTS) libcls_refcount_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_refcount_la_LDFLAGS) \ $(LDFLAGS) -o $@ libcls_refcount_client_la_LIBADD = am_libcls_refcount_client_la_OBJECTS = \ cls/refcount/cls_refcount_client.lo \ cls/refcount/cls_refcount_ops.lo libcls_refcount_client_la_OBJECTS = \ $(am_libcls_refcount_client_la_OBJECTS) libcls_replica_log_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_replica_log_la_OBJECTS = cls/replica_log/cls_replica_log.lo libcls_replica_log_la_OBJECTS = $(am_libcls_replica_log_la_OBJECTS) libcls_replica_log_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_replica_log_la_LDFLAGS) \ $(LDFLAGS) -o $@ libcls_rgw_la_DEPENDENCIES = libjson_spirit.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_rgw_la_OBJECTS = cls/rgw/cls_rgw.lo cls/rgw/cls_rgw_ops.lo \ cls/rgw/cls_rgw_types.lo common/ceph_json.lo libcls_rgw_la_OBJECTS = $(am_libcls_rgw_la_OBJECTS) libcls_rgw_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_rgw_la_LDFLAGS) $(LDFLAGS) \ -o $@ libcls_rgw_client_la_LIBADD = am_libcls_rgw_client_la_OBJECTS = cls/rgw/cls_rgw_client.lo \ cls/rgw/cls_rgw_types.lo cls/rgw/cls_rgw_ops.lo libcls_rgw_client_la_OBJECTS = $(am_libcls_rgw_client_la_OBJECTS) libcls_statelog_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_statelog_la_OBJECTS = cls/statelog/cls_statelog.lo libcls_statelog_la_OBJECTS = $(am_libcls_statelog_la_OBJECTS) libcls_statelog_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_statelog_la_LDFLAGS) \ $(LDFLAGS) -o $@ libcls_user_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_user_la_OBJECTS = cls/user/cls_user.lo libcls_user_la_OBJECTS = $(am_libcls_user_la_OBJECTS) libcls_user_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_user_la_LDFLAGS) \ $(LDFLAGS) -o $@ libcls_version_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libcls_version_la_OBJECTS = cls/version/cls_version.lo libcls_version_la_OBJECTS = $(am_libcls_version_la_OBJECTS) libcls_version_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libcls_version_la_LDFLAGS) \ $(LDFLAGS) -o $@ am__DEPENDENCIES_3 = libcommon_crc.la $(LIBERASURE_CODE) $(LIBMSG) \ $(LIBAUTH) $(LIBCRUSH) $(LIBJSON_SPIRIT) $(LIBLOG) $(LIBARCH) \ $(am__DEPENDENCIES_1) libcommon_la_DEPENDENCIES = $(am__DEPENDENCIES_3) am_libcommon_la_OBJECTS = ceph_ver.lo common/DecayCounter.lo \ common/LogClient.lo common/LogEntry.lo \ common/PrebufferedStreambuf.lo common/SloppyCRCMap.lo \ common/BackTrace.lo common/perf_counters.lo common/Mutex.lo \ common/OutputDataSocket.lo common/admin_socket.lo \ common/admin_socket_client.lo common/cmdparse.lo \ common/escape.lo common/io_priority.lo common/Clock.lo \ common/Throttle.lo common/Timer.lo common/Finisher.lo \ common/environment.lo common/assert.lo common/run_cmd.lo \ common/WorkQueue.lo common/ConfUtils.lo common/MemoryModel.lo \ common/armor.lo common/fd.lo common/xattr.lo common/safe_io.lo \ common/snap_types.lo common/str_list.lo common/str_map.lo \ common/errno.lo common/RefCountedObj.lo common/blkdev.lo \ common/common_init.lo common/pipe.lo common/ceph_argparse.lo \ common/ceph_context.lo common/buffer.lo \ common/code_environment.lo common/dout.lo common/histogram.lo \ common/signal.lo common/simple_spin.lo common/Thread.lo \ common/Formatter.lo common/HeartbeatMap.lo common/config.lo \ common/utf8.lo common/mime.lo common/strtol.lo common/page.lo \ common/lockdep.lo common/version.lo common/hex.lo \ common/entity_name.lo common/ceph_crypto.lo \ common/ceph_crypto_cms.lo common/ceph_json.lo common/ipaddr.lo \ common/pick_address.lo common/util.lo common/TextTable.lo \ common/ceph_fs.lo common/ceph_hash.lo common/ceph_strings.lo \ common/ceph_frag.lo common/addr_parsing.lo common/hobject.lo \ common/bloom_filter.lo common/linux_version.lo mon/MonCap.lo \ mon/MonClient.lo mon/MonMap.lo osd/OSDMap.lo osd/osd_types.lo \ osd/ECMsgTypes.lo osd/HitSet.lo mds/MDSMap.lo \ mds/inode_backtrace.lo mds/mdstypes.lo mds/flock.lo libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS) libcommon_crc_la_LIBADD = am__libcommon_crc_la_SOURCES_DIST = common/sctp_crc32.c \ common/crc32c.cc common/crc32c_intel_baseline.c \ common/crc32c_intel_fast.c common/crc32c_intel_fast_asm.S \ common/crc32c_intel_fast_zero_asm.S @WITH_GOOD_YASM_ELF64_TRUE@am__objects_1 = common/libcommon_crc_la-crc32c_intel_fast_asm.lo \ @WITH_GOOD_YASM_ELF64_TRUE@ common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo am_libcommon_crc_la_OBJECTS = common/libcommon_crc_la-sctp_crc32.lo \ common/libcommon_crc_la-crc32c.lo \ common/libcommon_crc_la-crc32c_intel_baseline.lo \ common/libcommon_crc_la-crc32c_intel_fast.lo $(am__objects_1) libcommon_crc_la_OBJECTS = $(am_libcommon_crc_la_OBJECTS) libcommon_crc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ libcrush_la_LIBADD = am_libcrush_la_OBJECTS = crush/builder.lo crush/mapper.lo \ crush/crush.lo crush/hash.lo crush/CrushWrapper.lo \ crush/CrushCompiler.lo crush/CrushTester.lo libcrush_la_OBJECTS = $(am_libcrush_la_OBJECTS) libec_example_la_DEPENDENCIES = $(LIBCRUSH) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_example_la_OBJECTS = test/erasure-code/libec_example_la-ErasureCodePluginExample.lo libec_example_la_OBJECTS = $(am_libec_example_la_OBJECTS) libec_example_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_example_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_example_la_LDFLAGS) $(LDFLAGS) -o $@ libec_fail_to_initialize_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_fail_to_initialize_la_OBJECTS = test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo libec_fail_to_initialize_la_OBJECTS = \ $(am_libec_fail_to_initialize_la_OBJECTS) libec_fail_to_initialize_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_fail_to_initialize_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_fail_to_initialize_la_LDFLAGS) $(LDFLAGS) -o $@ libec_fail_to_register_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_fail_to_register_la_OBJECTS = test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo libec_fail_to_register_la_OBJECTS = \ $(am_libec_fail_to_register_la_OBJECTS) libec_fail_to_register_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_fail_to_register_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_fail_to_register_la_LDFLAGS) $(LDFLAGS) -o $@ libec_hangs_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_hangs_la_OBJECTS = \ test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo libec_hangs_la_OBJECTS = $(am_libec_hangs_la_OBJECTS) libec_hangs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_hangs_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_hangs_la_LDFLAGS) $(LDFLAGS) -o $@ libec_jerasure_la_DEPENDENCIES = $(LIBCRUSH) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_jerasure_la_OBJECTS = erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo libec_jerasure_la_OBJECTS = $(am_libec_jerasure_la_OBJECTS) libec_jerasure_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_jerasure_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_jerasure_la_LDFLAGS) $(LDFLAGS) -o $@ libec_jerasure_generic_la_DEPENDENCIES = $(LIBCRUSH) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am__objects_2 = erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo \ erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo \ erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo am_libec_jerasure_generic_la_OBJECTS = $(am__objects_2) libec_jerasure_generic_la_OBJECTS = \ $(am_libec_jerasure_generic_la_OBJECTS) libec_jerasure_generic_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_jerasure_generic_la_LDFLAGS) $(LDFLAGS) -o $@ libec_jerasure_sse3_la_DEPENDENCIES = $(LIBCRUSH) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am__objects_3 = erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo \ erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo \ erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo am_libec_jerasure_sse3_la_OBJECTS = $(am__objects_3) libec_jerasure_sse3_la_OBJECTS = $(am_libec_jerasure_sse3_la_OBJECTS) libec_jerasure_sse3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_jerasure_sse3_la_LDFLAGS) $(LDFLAGS) -o $@ libec_jerasure_sse4_la_DEPENDENCIES = $(LIBCRUSH) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am__objects_4 = erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo \ erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo \ erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo \ erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo \ erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo am_libec_jerasure_sse4_la_OBJECTS = $(am__objects_4) libec_jerasure_sse4_la_OBJECTS = $(am_libec_jerasure_sse4_la_OBJECTS) libec_jerasure_sse4_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_jerasure_sse4_la_LDFLAGS) $(LDFLAGS) -o $@ libec_missing_entry_point_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_missing_entry_point_la_OBJECTS = test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo libec_missing_entry_point_la_OBJECTS = \ $(am_libec_missing_entry_point_la_OBJECTS) libec_missing_entry_point_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_missing_entry_point_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_missing_entry_point_la_LDFLAGS) $(LDFLAGS) -o $@ libec_test_jerasure_generic_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_test_jerasure_generic_la_OBJECTS = test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo libec_test_jerasure_generic_la_OBJECTS = \ $(am_libec_test_jerasure_generic_la_OBJECTS) libec_test_jerasure_generic_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_test_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_test_jerasure_generic_la_LDFLAGS) $(LDFLAGS) -o $@ libec_test_jerasure_sse3_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_test_jerasure_sse3_la_OBJECTS = test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo libec_test_jerasure_sse3_la_OBJECTS = \ $(am_libec_test_jerasure_sse3_la_OBJECTS) libec_test_jerasure_sse3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_test_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_test_jerasure_sse3_la_LDFLAGS) $(LDFLAGS) -o $@ libec_test_jerasure_sse4_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_libec_test_jerasure_sse4_la_OBJECTS = test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo libec_test_jerasure_sse4_la_OBJECTS = \ $(am_libec_test_jerasure_sse4_la_OBJECTS) libec_test_jerasure_sse4_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libec_test_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) \ $(libec_test_jerasure_sse4_la_LDFLAGS) $(LDFLAGS) -o $@ liberasure_code_la_DEPENDENCIES = am_liberasure_code_la_OBJECTS = erasure-code/ErasureCodePlugin.lo liberasure_code_la_OBJECTS = $(am_liberasure_code_la_OBJECTS) libglobal_la_DEPENDENCIES = $(LIBCOMMON) am_libglobal_la_OBJECTS = global/global_context.lo \ global/global_init.lo global/pidfile.lo \ global/signal_handler.lo libglobal_la_OBJECTS = $(am_libglobal_la_OBJECTS) libjson_spirit_la_LIBADD = am_libjson_spirit_la_OBJECTS = json_spirit/json_spirit_reader.lo \ json_spirit/json_spirit_writer.lo libjson_spirit_la_OBJECTS = $(am_libjson_spirit_la_OBJECTS) liblog_la_LIBADD = am_liblog_la_OBJECTS = log/Log.lo log/SubsystemMap.lo liblog_la_OBJECTS = $(am_liblog_la_OBJECTS) libmds_la_DEPENDENCIES = $(LIBOSDC) am_libmds_la_OBJECTS = mds/Anchor.lo mds/Capability.lo mds/Dumper.lo \ mds/Resetter.lo mds/MDS.lo mds/locks.lo mds/journal.lo \ mds/Server.lo mds/Mutation.lo mds/MDCache.lo mds/Locker.lo \ mds/Migrator.lo mds/MDBalancer.lo mds/CDentry.lo mds/CDir.lo \ mds/CInode.lo mds/LogEvent.lo mds/MDSTable.lo mds/InoTable.lo \ mds/MDSTableClient.lo mds/MDSTableServer.lo \ mds/AnchorServer.lo mds/AnchorClient.lo mds/SnapRealm.lo \ mds/SnapServer.lo mds/snap.lo mds/SessionMap.lo mds/MDLog.lo \ mds/MDSUtility.lo libmds_la_OBJECTS = $(am_libmds_la_OBJECTS) @WITH_LIBZFS_TRUE@am__DEPENDENCIES_4 = libos_zfs.a am__DEPENDENCIES_5 = libos.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_4) libmon_la_DEPENDENCIES = $(LIBAUTH) $(LIBCOMMON) $(am__DEPENDENCIES_5) \ $(LIBMON_TYPES) am_libmon_la_OBJECTS = mon/Monitor.lo mon/Paxos.lo mon/PaxosService.lo \ mon/OSDMonitor.lo mon/MDSMonitor.lo mon/MonmapMonitor.lo \ mon/PGMonitor.lo mon/LogMonitor.lo mon/AuthMonitor.lo \ mon/Elector.lo mon/MonitorStore.lo mon/HealthMonitor.lo \ mon/DataHealthService.lo mon/ConfigKeyService.lo libmon_la_OBJECTS = $(am_libmon_la_OBJECTS) libmon_types_la_LIBADD = am_libmon_types_la_OBJECTS = mon/PGMap.lo libmon_types_la_OBJECTS = $(am_libmon_types_la_OBJECTS) libmsg_la_LIBADD = am_libmsg_la_OBJECTS = msg/Accepter.lo msg/DispatchQueue.lo \ msg/Message.lo msg/Messenger.lo msg/Pipe.lo \ msg/SimpleMessenger.lo msg/msg_types.lo libmsg_la_OBJECTS = $(am_libmsg_la_OBJECTS) libos_la_DEPENDENCIES = $(LIBOS_TYPES) am__libos_la_SOURCES_DIST = os/chain_xattr.cc os/DBObjectMap.cc \ os/GenericObjectMap.cc os/FileJournal.cc os/FileStore.cc \ os/FlatIndex.cc os/GenericFileStoreBackend.cc os/HashIndex.cc \ os/IndexManager.cc os/JournalingObjectStore.cc \ os/LevelDBStore.cc os/LFNIndex.cc os/MemStore.cc \ os/KeyValueStore.cc os/ObjectStore.cc os/WBThrottle.cc \ common/TrackedOp.cc os/BtrfsFileStoreBackend.cc \ os/XfsFileStoreBackend.cc os/ZFSFileStoreBackend.cc @LINUX_TRUE@am__objects_5 = os/libos_la-BtrfsFileStoreBackend.lo @WITH_LIBXFS_TRUE@am__objects_6 = os/libos_la-XfsFileStoreBackend.lo @WITH_LIBZFS_TRUE@am__objects_7 = os/libos_la-ZFSFileStoreBackend.lo am_libos_la_OBJECTS = os/libos_la-chain_xattr.lo \ os/libos_la-DBObjectMap.lo os/libos_la-GenericObjectMap.lo \ os/libos_la-FileJournal.lo os/libos_la-FileStore.lo \ os/libos_la-FlatIndex.lo \ os/libos_la-GenericFileStoreBackend.lo \ os/libos_la-HashIndex.lo os/libos_la-IndexManager.lo \ os/libos_la-JournalingObjectStore.lo \ os/libos_la-LevelDBStore.lo os/libos_la-LFNIndex.lo \ os/libos_la-MemStore.lo os/libos_la-KeyValueStore.lo \ os/libos_la-ObjectStore.lo os/libos_la-WBThrottle.lo \ common/libos_la-TrackedOp.lo $(am__objects_5) $(am__objects_6) \ $(am__objects_7) libos_la_OBJECTS = $(am_libos_la_OBJECTS) libos_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libos_la_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ libos_types_la_LIBADD = am_libos_types_la_OBJECTS = os/libos_types_la-Transaction.lo libos_types_la_OBJECTS = $(am_libos_types_la_OBJECTS) libos_types_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libos_types_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ libosd_la_DEPENDENCIES = $(LIBOSDC) $(am__DEPENDENCIES_5) \ $(LIBOSD_TYPES) $(LIBOS_TYPES) am_libosd_la_OBJECTS = osd/libosd_la-PG.lo \ osd/libosd_la-ReplicatedPG.lo \ osd/libosd_la-ReplicatedBackend.lo osd/libosd_la-ECBackend.lo \ osd/libosd_la-ECMsgTypes.lo osd/libosd_la-ECTransaction.lo \ osd/libosd_la-PGBackend.lo osd/libosd_la-Ager.lo \ osd/libosd_la-HitSet.lo osd/libosd_la-OSD.lo \ osd/libosd_la-OSDCap.lo osd/libosd_la-Watch.lo \ osd/libosd_la-ClassHandler.lo osd/libosd_la-OpRequest.lo \ common/libosd_la-TrackedOp.lo osd/libosd_la-SnapMapper.lo \ objclass/libosd_la-class_api.lo libosd_la_OBJECTS = $(am_libosd_la_OBJECTS) libosd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libosd_la_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ libosd_types_la_LIBADD = am_libosd_types_la_OBJECTS = osd/libosd_types_la-PGLog.lo \ osd/libosd_types_la-osd_types.lo osd/libosd_types_la-ECUtil.lo libosd_types_la_OBJECTS = $(am_libosd_types_la_OBJECTS) libosd_types_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ libosdc_la_LIBADD = am_libosdc_la_OBJECTS = osdc/Objecter.lo osdc/ObjectCacher.lo \ osdc/Filer.lo osdc/Striper.lo osdc/Journaler.lo libosdc_la_OBJECTS = $(am_libosdc_la_OBJECTS) libperfglue_la_DEPENDENCIES = am__libperfglue_la_SOURCES_DIST = perfglue/heap_profiler.cc \ perfglue/disabled_heap_profiler.cc perfglue/cpu_profiler.cc \ perfglue/disabled_stubs.cc @WITH_TCMALLOC_TRUE@am__objects_8 = perfglue/heap_profiler.lo @WITH_TCMALLOC_FALSE@am__objects_9 = \ @WITH_TCMALLOC_FALSE@ perfglue/disabled_heap_profiler.lo @WITH_PROFILER_TRUE@am__objects_10 = perfglue/cpu_profiler.lo @WITH_PROFILER_FALSE@am__objects_11 = perfglue/disabled_stubs.lo am_libperfglue_la_OBJECTS = $(am__objects_8) $(am__objects_9) \ $(am__objects_10) $(am__objects_11) libperfglue_la_OBJECTS = $(am_libperfglue_la_OBJECTS) librados_la_DEPENDENCIES = $(LIBRADOS_DEPS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am_librados_la_OBJECTS = librados/librados_la-librados.lo \ librados/librados_la-RadosClient.lo \ librados/librados_la-IoCtxImpl.lo \ librados/librados_la-snap_set_diff.lo librados_la_OBJECTS = $(am_librados_la_OBJECTS) librados_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(librados_la_CXXFLAGS) \ $(CXXFLAGS) $(librados_la_LDFLAGS) $(LDFLAGS) -o $@ libradostest_la_LIBADD = am_libradostest_la_OBJECTS = test/librados/libradostest_la-test.lo \ test/librados/libradostest_la-TestCase.lo libradostest_la_OBJECTS = $(am_libradostest_la_OBJECTS) libradostest_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libradostest_la_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ librbd_la_DEPENDENCIES = $(LIBRADOS) $(LIBOSDC) libcls_rbd_client.la \ libcls_lock_client.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_librbd_la_OBJECTS = librbd/librbd.lo librbd/AioCompletion.lo \ librbd/AioRequest.lo librbd/ImageCtx.lo librbd/internal.lo \ librbd/LibrbdWriteback.lo librbd/WatchCtx.lo librbd_la_OBJECTS = $(am_librbd_la_OBJECTS) librbd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(librbd_la_LDFLAGS) $(LDFLAGS) -o $@ librgw_la_LIBADD = am__librgw_la_SOURCES_DIST = rgw/librgw.cc rgw/rgw_acl.cc \ rgw/rgw_acl_s3.cc rgw/rgw_acl_swift.cc rgw/rgw_client_io.cc \ rgw/rgw_fcgi.cc rgw/rgw_xml.cc rgw/rgw_usage.cc \ rgw/rgw_json_enc.cc rgw/rgw_user.cc rgw/rgw_bucket.cc \ rgw/rgw_tools.cc rgw/rgw_rados.cc rgw/rgw_http_client.cc \ rgw/rgw_rest_client.cc rgw/rgw_rest_conn.cc rgw/rgw_op.cc \ rgw/rgw_common.cc rgw/rgw_cache.cc rgw/rgw_formats.cc \ rgw/rgw_log.cc rgw/rgw_multi.cc rgw/rgw_policy_s3.cc \ rgw/rgw_gc.cc rgw/rgw_multi_del.cc rgw/rgw_env.cc \ rgw/rgw_cors.cc rgw/rgw_cors_s3.cc rgw/rgw_auth_s3.cc \ rgw/rgw_metadata.cc rgw/rgw_replica_log.cc rgw/rgw_keystone.cc \ rgw/rgw_quota.cc rgw/rgw_dencoder.cc @WITH_RADOSGW_TRUE@am_librgw_la_OBJECTS = rgw/librgw_la-librgw.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_acl.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_acl_s3.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_acl_swift.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_client_io.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_fcgi.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_xml.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_usage.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_json_enc.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_user.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_bucket.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_tools.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_rados.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_http_client.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_rest_client.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_rest_conn.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_op.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_common.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_cache.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_formats.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_log.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_multi.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_policy_s3.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_gc.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_multi_del.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_env.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_cors.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_cors_s3.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_auth_s3.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_metadata.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_replica_log.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_keystone.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_quota.lo \ @WITH_RADOSGW_TRUE@ rgw/librgw_la-rgw_dencoder.lo librgw_la_OBJECTS = $(am_librgw_la_OBJECTS) librgw_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(librgw_la_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ @WITH_RADOSGW_TRUE@am_librgw_la_rpath = am__DEPENDENCIES_6 = $(LIBGLOBAL) $(LIBCOMMON) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) @LINUX_TRUE@libsystest_la_DEPENDENCIES = $(am__DEPENDENCIES_6) am__libsystest_la_SOURCES_DIST = test/system/cross_process_sem.cc \ test/system/systest_runnable.cc \ test/system/systest_settings.cc @LINUX_TRUE@am_libsystest_la_OBJECTS = \ @LINUX_TRUE@ test/system/cross_process_sem.lo \ @LINUX_TRUE@ test/system/systest_runnable.lo \ @LINUX_TRUE@ test/system/systest_settings.lo libsystest_la_OBJECTS = $(am_libsystest_la_OBJECTS) @LINUX_TRUE@am_libsystest_la_rpath = @WITH_RADOSGW_TRUE@am__EXEEXT_1 = ceph_rgw_multiparser$(EXEEXT) \ @WITH_RADOSGW_TRUE@ ceph_rgw_jsonparser$(EXEEXT) @WITH_BUILD_TESTS_TRUE@am__EXEEXT_2 = test_build_libcommon$(EXEEXT) \ @WITH_BUILD_TESTS_TRUE@ test_build_librados$(EXEEXT) \ @WITH_BUILD_TESTS_TRUE@ test_build_librgw$(EXEEXT) \ @WITH_BUILD_TESTS_TRUE@ test_build_libcephfs$(EXEEXT) @LINUX_TRUE@am__EXEEXT_3 = ceph_kvstorebench$(EXEEXT) \ @LINUX_TRUE@ ceph_test_rados_list_parallel$(EXEEXT) \ @LINUX_TRUE@ ceph_test_rados_open_pools_parallel$(EXEEXT) \ @LINUX_TRUE@ ceph_test_rados_delete_pools_parallel$(EXEEXT) \ @LINUX_TRUE@ ceph_test_rados_watch_notify$(EXEEXT) @WITH_RADOSGW_TRUE@am__EXEEXT_4 = ceph_test_cors$(EXEEXT) \ @WITH_RADOSGW_TRUE@ ceph_test_rgw_manifest$(EXEEXT) \ @WITH_RADOSGW_TRUE@ ceph_test_cls_rgw_meta$(EXEEXT) \ @WITH_RADOSGW_TRUE@ ceph_test_cls_rgw_log$(EXEEXT) \ @WITH_RADOSGW_TRUE@ ceph_test_cls_rgw_opstate$(EXEEXT) @LINUX_TRUE@am__EXEEXT_5 = ceph_test_librbd_fsx$(EXEEXT) @WITH_RADOSGW_TRUE@am__EXEEXT_6 = ceph_test_cls_rgw$(EXEEXT) @LINUX_TRUE@am__EXEEXT_7 = ceph_test_objectstore$(EXEEXT) am__EXEEXT_8 = ceph_test_ioctls$(EXEEXT) $(am__EXEEXT_1) \ ceph_erasure_code_benchmark$(EXEEXT) \ ceph_erasure_code$(EXEEXT) ceph_test_timers$(EXEEXT) \ ceph_test_signal_handlers$(EXEEXT) ceph_test_rados$(EXEEXT) \ ceph_test_mutate$(EXEEXT) ceph_test_rewrite_latency$(EXEEXT) \ ceph_test_msgr$(EXEEXT) ceph_streamtest$(EXEEXT) \ ceph_test_trans$(EXEEXT) ceph_test_crypto$(EXEEXT) \ ceph_test_keys$(EXEEXT) $(am__EXEEXT_2) \ ceph_smalliobench$(EXEEXT) ceph_smalliobenchfs$(EXEEXT) \ ceph_smalliobenchdumb$(EXEEXT) ceph_smalliobenchrbd$(EXEEXT) \ ceph_tpbench$(EXEEXT) ceph_omapbench$(EXEEXT) $(am__EXEEXT_3) \ ceph_bench_log$(EXEEXT) $(am__EXEEXT_4) \ ceph_multi_stress_watch$(EXEEXT) ceph_test_librbd$(EXEEXT) \ $(am__EXEEXT_5) ceph_test_cls_rbd$(EXEEXT) \ ceph_test_cls_refcount$(EXEEXT) ceph_test_cls_version$(EXEEXT) \ ceph_test_cls_log$(EXEEXT) ceph_test_cls_statelog$(EXEEXT) \ ceph_test_cls_replica_log$(EXEEXT) ceph_test_cls_lock$(EXEEXT) \ ceph_test_cls_hello$(EXEEXT) $(am__EXEEXT_6) \ ceph_test_mon_workloadgen$(EXEEXT) \ ceph_test_rados_api_cmd$(EXEEXT) \ ceph_test_rados_api_io$(EXEEXT) \ ceph_test_rados_api_c_write_operations$(EXEEXT) \ ceph_test_rados_api_c_read_operations$(EXEEXT) \ ceph_test_rados_api_aio$(EXEEXT) \ ceph_test_rados_api_list$(EXEEXT) \ ceph_test_rados_api_pool$(EXEEXT) \ ceph_test_rados_api_stat$(EXEEXT) \ ceph_test_rados_api_watch_notify$(EXEEXT) \ ceph_test_rados_api_snapshots$(EXEEXT) \ ceph_test_rados_api_cls$(EXEEXT) \ ceph_test_rados_api_misc$(EXEEXT) \ ceph_test_rados_api_tier$(EXEEXT) \ ceph_test_rados_api_lock$(EXEEXT) ceph_test_libcephfs$(EXEEXT) \ $(am__EXEEXT_7) ceph_test_objectstore_workloadgen$(EXEEXT) \ ceph_test_filestore_idempotent$(EXEEXT) \ ceph_test_filestore_idempotent_sequence$(EXEEXT) \ ceph_xattr_bench$(EXEEXT) ceph_test_filejournal$(EXEEXT) \ ceph_test_stress_watch$(EXEEXT) \ ceph_test_objectcacher_stress$(EXEEXT) \ ceph_test_snap_mapper$(EXEEXT) ceph_test_object_map$(EXEEXT) \ ceph_test_keyvaluedb_atomicity$(EXEEXT) \ ceph_test_keyvaluedb_iterators$(EXEEXT) \ ceph_test_cfuse_cache_invalidate$(EXEEXT) \ ceph_test_c_headers$(EXEEXT) \ ceph_test_get_blkdev_size$(EXEEXT) ceph-osdomap-tool$(EXEEXT) \ ceph-monstore-tool$(EXEEXT) ceph-kvstore-tool$(EXEEXT) \ ceph_scratchtool$(EXEEXT) ceph_scratchtoolpp$(EXEEXT) \ ceph_psim$(EXEEXT) ceph_dupstore$(EXEEXT) \ ceph_radosacl$(EXEEXT) ceph-client-debug$(EXEEXT) @WITH_DEBUG_TRUE@am__EXEEXT_9 = $(am__EXEEXT_8) @WITH_RADOSGW_TRUE@am__EXEEXT_10 = radosgw$(EXEEXT) \ @WITH_RADOSGW_TRUE@ radosgw-admin$(EXEEXT) @WITH_REST_BENCH_TRUE@am__EXEEXT_11 = rest-bench$(EXEEXT) @LINUX_TRUE@am__EXEEXT_12 = rbd$(EXEEXT) @WITH_FUSE_TRUE@am__EXEEXT_13 = ceph-fuse$(EXEEXT) rbd-fuse$(EXEEXT) @LINUX_TRUE@am__EXEEXT_14 = mount.ceph$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(sbin_PROGRAMS) \ $(su_sbin_PROGRAMS) am_ceph_authtool_OBJECTS = tools/ceph_authtool.$(OBJEXT) ceph_authtool_OBJECTS = $(am_ceph_authtool_OBJECTS) ceph_authtool_DEPENDENCIES = $(am__DEPENDENCIES_6) $(LIBCOMMON) am_ceph_client_debug_OBJECTS = tools/ceph-client-debug.$(OBJEXT) ceph_client_debug_OBJECTS = $(am_ceph_client_debug_OBJECTS) ceph_client_debug_DEPENDENCIES = $(LIBCEPHFS) $(am__DEPENDENCIES_6) \ $(LIBCOMMON) am_ceph_conf_OBJECTS = tools/ceph_conf.$(OBJEXT) ceph_conf_OBJECTS = $(am_ceph_conf_OBJECTS) ceph_conf_DEPENDENCIES = $(am__DEPENDENCIES_6) $(LIBCOMMON) am__ceph_dencoder_SOURCES_DIST = test/encoding/ceph_dencoder.cc \ rgw/rgw_dencoder.cc rgw/rgw_acl.cc rgw/rgw_common.cc \ rgw/rgw_env.cc rgw/rgw_json_enc.cc @WITH_RADOSGW_TRUE@am__objects_12 = \ @WITH_RADOSGW_TRUE@ rgw/ceph_dencoder-rgw_dencoder.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/ceph_dencoder-rgw_acl.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/ceph_dencoder-rgw_common.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/ceph_dencoder-rgw_env.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/ceph_dencoder-rgw_json_enc.$(OBJEXT) am__objects_13 = $(am__objects_12) am_ceph_dencoder_OBJECTS = \ test/encoding/ceph_dencoder-ceph_dencoder.$(OBJEXT) \ $(am__objects_13) ceph_dencoder_OBJECTS = $(am_ceph_dencoder_OBJECTS) am__DEPENDENCIES_7 = libperfglue.la $(am__DEPENDENCIES_1) am__DEPENDENCIES_8 = libmds.la $(am__DEPENDENCIES_7) ceph_dencoder_DEPENDENCIES = $(LIBOSD_TYPES) $(LIBOS_TYPES) \ $(am__DEPENDENCIES_8) $(LIBMON_TYPES) $(DENCODER_DEPS) \ $(am__DEPENDENCIES_6) ceph_dencoder_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ am__ceph_fuse_SOURCES_DIST = ceph_fuse.cc @WITH_FUSE_TRUE@am_ceph_fuse_OBJECTS = ceph_fuse.$(OBJEXT) ceph_fuse_OBJECTS = $(am_ceph_fuse_OBJECTS) @WITH_FUSE_TRUE@ceph_fuse_DEPENDENCIES = $(LIBCLIENT_FUSE) \ @WITH_FUSE_TRUE@ $(am__DEPENDENCIES_6) am_ceph_kvstore_tool_OBJECTS = \ tools/ceph_kvstore_tool-ceph_kvstore_tool.$(OBJEXT) ceph_kvstore_tool_OBJECTS = $(am_ceph_kvstore_tool_OBJECTS) ceph_kvstore_tool_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) ceph_kvstore_tool_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_kvstore_tool_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_mds_OBJECTS = ceph_mds.$(OBJEXT) ceph_mds_OBJECTS = $(am_ceph_mds_OBJECTS) ceph_mds_DEPENDENCIES = $(am__DEPENDENCIES_8) $(LIBOSDC) \ $(am__DEPENDENCIES_6) $(LIBCOMMON) am_ceph_mon_OBJECTS = ceph_mon.$(OBJEXT) ceph_mon_OBJECTS = $(am_ceph_mon_OBJECTS) am__DEPENDENCIES_9 = libmon.la $(am__DEPENDENCIES_7) ceph_mon_DEPENDENCIES = $(am__DEPENDENCIES_9) $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) $(LIBCOMMON) am_ceph_monstore_tool_OBJECTS = tools/ceph_monstore_tool.$(OBJEXT) ceph_monstore_tool_OBJECTS = $(am_ceph_monstore_tool_OBJECTS) ceph_monstore_tool_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_1) am_ceph_objectstore_tool_OBJECTS = \ tools/ceph_objectstore_tool.$(OBJEXT) ceph_objectstore_tool_OBJECTS = $(am_ceph_objectstore_tool_OBJECTS) am__DEPENDENCIES_10 = libosd.la $(LIBOSDC) $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_7) ceph_objectstore_tool_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) $(LIBRADOS) $(am__DEPENDENCIES_1) am_ceph_osd_OBJECTS = ceph_osd.$(OBJEXT) ceph_osd_OBJECTS = $(am_ceph_osd_OBJECTS) ceph_osd_DEPENDENCIES = $(am__DEPENDENCIES_10) $(am__DEPENDENCIES_6) \ $(LIBCOMMON) am_ceph_osdomap_tool_OBJECTS = tools/ceph_osdomap_tool.$(OBJEXT) ceph_osdomap_tool_OBJECTS = $(am_ceph_osdomap_tool_OBJECTS) ceph_osdomap_tool_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_1) am_ceph_syn_OBJECTS = ceph_syn.$(OBJEXT) \ client/SyntheticClient.$(OBJEXT) ceph_syn_OBJECTS = $(am_ceph_syn_OBJECTS) ceph_syn_DEPENDENCIES = $(LIBCLIENT) $(am__DEPENDENCIES_6) am_ceph_bench_log_OBJECTS = test/bench_log.$(OBJEXT) ceph_bench_log_OBJECTS = $(am_ceph_bench_log_OBJECTS) ceph_bench_log_DEPENDENCIES = $(am__DEPENDENCIES_6) am_ceph_dupstore_OBJECTS = tools/dupstore.$(OBJEXT) ceph_dupstore_OBJECTS = $(am_ceph_dupstore_OBJECTS) ceph_dupstore_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) am_ceph_erasure_code_OBJECTS = \ test/erasure-code/ceph_erasure_code.$(OBJEXT) ceph_erasure_code_OBJECTS = $(am_ceph_erasure_code_OBJECTS) ceph_erasure_code_DEPENDENCIES = $(am__DEPENDENCIES_10) $(LIBCOMMON) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) am_ceph_erasure_code_benchmark_OBJECTS = \ test/erasure-code/ceph_erasure_code_benchmark.$(OBJEXT) ceph_erasure_code_benchmark_OBJECTS = \ $(am_ceph_erasure_code_benchmark_OBJECTS) ceph_erasure_code_benchmark_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(LIBCOMMON) $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) am_ceph_erasure_code_non_regression_OBJECTS = \ test/erasure-code/ceph_erasure_code_non_regression.$(OBJEXT) ceph_erasure_code_non_regression_OBJECTS = \ $(am_ceph_erasure_code_non_regression_OBJECTS) ceph_erasure_code_non_regression_DEPENDENCIES = \ $(am__DEPENDENCIES_10) $(LIBCOMMON) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_1) am__ceph_kvstorebench_SOURCES_DIST = test/kv_store_bench.cc \ key_value_store/kv_flat_btree_async.cc @LINUX_TRUE@am_ceph_kvstorebench_OBJECTS = \ @LINUX_TRUE@ test/kv_store_bench.$(OBJEXT) \ @LINUX_TRUE@ key_value_store/kv_flat_btree_async.$(OBJEXT) ceph_kvstorebench_OBJECTS = $(am_ceph_kvstorebench_OBJECTS) @LINUX_TRUE@ceph_kvstorebench_DEPENDENCIES = $(LIBRADOS) \ @LINUX_TRUE@ $(am__DEPENDENCIES_6) am_ceph_mon_store_converter_OBJECTS = \ tools/mon_store_converter.$(OBJEXT) ceph_mon_store_converter_OBJECTS = \ $(am_ceph_mon_store_converter_OBJECTS) ceph_mon_store_converter_DEPENDENCIES = $(am__DEPENDENCIES_9) \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) am_ceph_multi_stress_watch_OBJECTS = \ test/multi_stress_watch.$(OBJEXT) ceph_multi_stress_watch_OBJECTS = \ $(am_ceph_multi_stress_watch_OBJECTS) ceph_multi_stress_watch_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_6) $(RADOS_TEST_LDADD) am_ceph_omapbench_OBJECTS = test/omap_bench.$(OBJEXT) ceph_omapbench_OBJECTS = $(am_ceph_omapbench_OBJECTS) ceph_omapbench_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am_ceph_psim_OBJECTS = tools/psim.$(OBJEXT) ceph_psim_OBJECTS = $(am_ceph_psim_OBJECTS) ceph_psim_DEPENDENCIES = $(am__DEPENDENCIES_6) am_ceph_radosacl_OBJECTS = tools/radosacl.$(OBJEXT) ceph_radosacl_OBJECTS = $(am_ceph_radosacl_OBJECTS) ceph_radosacl_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am__ceph_rgw_jsonparser_SOURCES_DIST = rgw/rgw_jsonparser.cc \ rgw/rgw_common.cc rgw/rgw_env.cc rgw/rgw_json_enc.cc @WITH_RADOSGW_TRUE@am_ceph_rgw_jsonparser_OBJECTS = \ @WITH_RADOSGW_TRUE@ rgw/rgw_jsonparser.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_common.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_env.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_json_enc.$(OBJEXT) ceph_rgw_jsonparser_OBJECTS = $(am_ceph_rgw_jsonparser_OBJECTS) @WITH_RADOSGW_TRUE@am__DEPENDENCIES_11 = $(LIBRADOS) \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a \ @WITH_RADOSGW_TRUE@ libcls_user_client.a \ @WITH_RADOSGW_TRUE@ libcls_replica_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_lock_client.la \ @WITH_RADOSGW_TRUE@ libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_version_client.a am__DEPENDENCIES_12 = $(am__DEPENDENCIES_11) @WITH_RADOSGW_TRUE@ceph_rgw_jsonparser_DEPENDENCIES = $(LIBRGW) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_12) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_6) am__ceph_rgw_multiparser_SOURCES_DIST = rgw/rgw_multiparser.cc @WITH_RADOSGW_TRUE@am_ceph_rgw_multiparser_OBJECTS = \ @WITH_RADOSGW_TRUE@ rgw/rgw_multiparser.$(OBJEXT) ceph_rgw_multiparser_OBJECTS = $(am_ceph_rgw_multiparser_OBJECTS) @WITH_RADOSGW_TRUE@ceph_rgw_multiparser_DEPENDENCIES = $(LIBRGW) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_12) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_6) am_ceph_scratchtool_OBJECTS = tools/scratchtool.$(OBJEXT) ceph_scratchtool_OBJECTS = $(am_ceph_scratchtool_OBJECTS) ceph_scratchtool_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am_ceph_scratchtoolpp_OBJECTS = tools/scratchtoolpp.$(OBJEXT) ceph_scratchtoolpp_OBJECTS = $(am_ceph_scratchtoolpp_OBJECTS) ceph_scratchtoolpp_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am_ceph_smalliobench_OBJECTS = test/bench/small_io_bench.$(OBJEXT) \ test/bench/rados_backend.$(OBJEXT) \ test/bench/detailed_stat_collector.$(OBJEXT) \ test/bench/bencher.$(OBJEXT) ceph_smalliobench_OBJECTS = $(am_ceph_smalliobench_OBJECTS) ceph_smalliobench_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_6) am_ceph_smalliobenchdumb_OBJECTS = \ test/bench/small_io_bench_dumb.$(OBJEXT) \ test/bench/dumb_backend.$(OBJEXT) \ test/bench/detailed_stat_collector.$(OBJEXT) \ test/bench/bencher.$(OBJEXT) ceph_smalliobenchdumb_OBJECTS = $(am_ceph_smalliobenchdumb_OBJECTS) ceph_smalliobenchdumb_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) am_ceph_smalliobenchfs_OBJECTS = \ test/bench/small_io_bench_fs.$(OBJEXT) \ test/bench/testfilestore_backend.$(OBJEXT) \ test/bench/detailed_stat_collector.$(OBJEXT) \ test/bench/bencher.$(OBJEXT) ceph_smalliobenchfs_OBJECTS = $(am_ceph_smalliobenchfs_OBJECTS) ceph_smalliobenchfs_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) am_ceph_smalliobenchrbd_OBJECTS = \ test/bench/small_io_bench_rbd.$(OBJEXT) \ test/bench/rbd_backend.$(OBJEXT) \ test/bench/detailed_stat_collector.$(OBJEXT) \ test/bench/bencher.$(OBJEXT) ceph_smalliobenchrbd_OBJECTS = $(am_ceph_smalliobenchrbd_OBJECTS) ceph_smalliobenchrbd_DEPENDENCIES = $(LIBRBD) $(LIBRADOS) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_6) am_ceph_streamtest_OBJECTS = test/streamtest.$(OBJEXT) ceph_streamtest_OBJECTS = $(am_ceph_streamtest_OBJECTS) ceph_streamtest_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) am_ceph_test_c_headers_OBJECTS = test/test_c_headers.$(OBJEXT) ceph_test_c_headers_OBJECTS = $(am_ceph_test_c_headers_OBJECTS) ceph_test_c_headers_DEPENDENCIES = $(LIBRADOS) $(LIBCEPHFS) am_ceph_test_cfuse_cache_invalidate_OBJECTS = \ test/test_cfuse_cache_invalidate.$(OBJEXT) ceph_test_cfuse_cache_invalidate_OBJECTS = \ $(am_ceph_test_cfuse_cache_invalidate_OBJECTS) ceph_test_cfuse_cache_invalidate_LDADD = $(LDADD) am_ceph_test_cls_hello_OBJECTS = \ test/cls_hello/ceph_test_cls_hello-test_cls_hello.$(OBJEXT) ceph_test_cls_hello_OBJECTS = $(am_ceph_test_cls_hello_OBJECTS) am__DEPENDENCIES_13 = $(top_builddir)/src/gtest/lib/libgtest.a \ $(top_builddir)/src/gtest/lib/libgtest_main.a \ $(am__DEPENDENCIES_1) ceph_test_cls_hello_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(RADOS_TEST_LDADD) ceph_test_cls_hello_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_hello_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_cls_lock_OBJECTS = \ test/cls_lock/ceph_test_cls_lock-test_cls_lock.$(OBJEXT) ceph_test_cls_lock_OBJECTS = $(am_ceph_test_cls_lock_OBJECTS) ceph_test_cls_lock_DEPENDENCIES = $(LIBRADOS) libcls_lock_client.la \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_cls_lock_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_lock_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_cls_log_OBJECTS = \ test/cls_log/ceph_test_cls_log-test_cls_log.$(OBJEXT) ceph_test_cls_log_OBJECTS = $(am_ceph_test_cls_log_OBJECTS) ceph_test_cls_log_DEPENDENCIES = $(LIBRADOS) libcls_log_client.a \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(RADOS_TEST_LDADD) ceph_test_cls_log_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_log_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_cls_rbd_OBJECTS = \ test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.$(OBJEXT) ceph_test_cls_rbd_OBJECTS = $(am_ceph_test_cls_rbd_OBJECTS) ceph_test_cls_rbd_DEPENDENCIES = $(LIBRADOS) libcls_rbd_client.la \ libcls_lock_client.la $(am__DEPENDENCIES_13) \ $(RADOS_TEST_LDADD) ceph_test_cls_rbd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_rbd_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_cls_refcount_OBJECTS = test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.$(OBJEXT) ceph_test_cls_refcount_OBJECTS = $(am_ceph_test_cls_refcount_OBJECTS) ceph_test_cls_refcount_DEPENDENCIES = $(LIBRADOS) \ libcls_refcount_client.la $(am__DEPENDENCIES_13) \ $(RADOS_TEST_LDADD) ceph_test_cls_refcount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_refcount_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_cls_replica_log_OBJECTS = test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.$(OBJEXT) ceph_test_cls_replica_log_OBJECTS = \ $(am_ceph_test_cls_replica_log_OBJECTS) ceph_test_cls_replica_log_DEPENDENCIES = $(LIBRADOS) \ libcls_replica_log_client.a $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) $(RADOS_TEST_LDADD) ceph_test_cls_replica_log_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_replica_log_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__ceph_test_cls_rgw_SOURCES_DIST = test/cls_rgw/test_cls_rgw.cc @WITH_RADOSGW_TRUE@am_ceph_test_cls_rgw_OBJECTS = test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.$(OBJEXT) ceph_test_cls_rgw_OBJECTS = $(am_ceph_test_cls_rgw_OBJECTS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_DEPENDENCIES = $(LIBRADOS) \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la $(am__DEPENDENCIES_13) \ @WITH_RADOSGW_TRUE@ $(RADOS_TEST_LDADD) ceph_test_cls_rgw_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_rgw_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__ceph_test_cls_rgw_log_SOURCES_DIST = test/test_rgw_admin_log.cc @WITH_RADOSGW_TRUE@am_ceph_test_cls_rgw_log_OBJECTS = test/ceph_test_cls_rgw_log-test_rgw_admin_log.$(OBJEXT) ceph_test_cls_rgw_log_OBJECTS = $(am_ceph_test_cls_rgw_log_OBJECTS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_log_DEPENDENCIES = $(LIBRADOS) \ @WITH_RADOSGW_TRUE@ $(LIBRGW) $(am__DEPENDENCIES_6) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_13) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_RADOSGW_TRUE@ libcls_version_client.a libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a \ @WITH_RADOSGW_TRUE@ libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_user_client.a \ @WITH_RADOSGW_TRUE@ libcls_lock_client.la ceph_test_cls_rgw_log_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_rgw_log_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__ceph_test_cls_rgw_meta_SOURCES_DIST = test/test_rgw_admin_meta.cc @WITH_RADOSGW_TRUE@am_ceph_test_cls_rgw_meta_OBJECTS = test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.$(OBJEXT) ceph_test_cls_rgw_meta_OBJECTS = $(am_ceph_test_cls_rgw_meta_OBJECTS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_meta_DEPENDENCIES = $(LIBRADOS) \ @WITH_RADOSGW_TRUE@ $(LIBRGW) $(am__DEPENDENCIES_6) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_13) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_RADOSGW_TRUE@ libcls_version_client.a libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a \ @WITH_RADOSGW_TRUE@ libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_user_client.a \ @WITH_RADOSGW_TRUE@ libcls_lock_client.la ceph_test_cls_rgw_meta_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_rgw_meta_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__ceph_test_cls_rgw_opstate_SOURCES_DIST = \ test/test_rgw_admin_opstate.cc @WITH_RADOSGW_TRUE@am_ceph_test_cls_rgw_opstate_OBJECTS = test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.$(OBJEXT) ceph_test_cls_rgw_opstate_OBJECTS = \ $(am_ceph_test_cls_rgw_opstate_OBJECTS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_opstate_DEPENDENCIES = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) $(LIBRGW) $(am__DEPENDENCIES_6) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_13) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_RADOSGW_TRUE@ libcls_version_client.a libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a \ @WITH_RADOSGW_TRUE@ libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_user_client.a \ @WITH_RADOSGW_TRUE@ libcls_lock_client.la ceph_test_cls_rgw_opstate_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_rgw_opstate_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ceph_test_cls_statelog_OBJECTS = test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.$(OBJEXT) ceph_test_cls_statelog_OBJECTS = $(am_ceph_test_cls_statelog_OBJECTS) ceph_test_cls_statelog_DEPENDENCIES = $(LIBRADOS) \ libcls_statelog_client.a $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) $(RADOS_TEST_LDADD) ceph_test_cls_statelog_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_statelog_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_cls_version_OBJECTS = test/cls_version/ceph_test_cls_version-test_cls_version.$(OBJEXT) ceph_test_cls_version_OBJECTS = $(am_ceph_test_cls_version_OBJECTS) ceph_test_cls_version_DEPENDENCIES = $(LIBRADOS) \ libcls_version_client.a $(am__DEPENDENCIES_13) \ $(RADOS_TEST_LDADD) ceph_test_cls_version_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cls_version_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__ceph_test_cors_SOURCES_DIST = test/test_cors.cc @WITH_RADOSGW_TRUE@am_ceph_test_cors_OBJECTS = \ @WITH_RADOSGW_TRUE@ test/ceph_test_cors-test_cors.$(OBJEXT) ceph_test_cors_OBJECTS = $(am_ceph_test_cors_OBJECTS) @WITH_RADOSGW_TRUE@ceph_test_cors_DEPENDENCIES = $(LIBRADOS) $(LIBRGW) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_13) ceph_test_cors_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_cors_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_crypto_OBJECTS = test/testcrypto.$(OBJEXT) ceph_test_crypto_OBJECTS = $(am_ceph_test_crypto_OBJECTS) ceph_test_crypto_DEPENDENCIES = $(am__DEPENDENCIES_6) am_ceph_test_filejournal_OBJECTS = \ test/ceph_test_filejournal-test_filejournal.$(OBJEXT) ceph_test_filejournal_OBJECTS = $(am_ceph_test_filejournal_OBJECTS) ceph_test_filejournal_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) ceph_test_filejournal_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_filejournal_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_filestore_idempotent_OBJECTS = \ test/objectstore/test_idempotent.$(OBJEXT) \ test/objectstore/FileStoreTracker.$(OBJEXT) \ test/common/ObjectContents.$(OBJEXT) ceph_test_filestore_idempotent_OBJECTS = \ $(am_ceph_test_filestore_idempotent_OBJECTS) ceph_test_filestore_idempotent_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) am_ceph_test_filestore_idempotent_sequence_OBJECTS = \ test/objectstore/test_idempotent_sequence.$(OBJEXT) \ test/objectstore/DeterministicOpSequence.$(OBJEXT) \ test/objectstore/TestObjectStoreState.$(OBJEXT) \ test/objectstore/FileStoreDiff.$(OBJEXT) ceph_test_filestore_idempotent_sequence_OBJECTS = \ $(am_ceph_test_filestore_idempotent_sequence_OBJECTS) ceph_test_filestore_idempotent_sequence_DEPENDENCIES = \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) am_ceph_test_get_blkdev_size_OBJECTS = \ test/test_get_blkdev_size.$(OBJEXT) ceph_test_get_blkdev_size_OBJECTS = \ $(am_ceph_test_get_blkdev_size_OBJECTS) ceph_test_get_blkdev_size_DEPENDENCIES = $(LIBCOMMON) am_ceph_test_ioctls_OBJECTS = client/test_ioctls.$(OBJEXT) ceph_test_ioctls_OBJECTS = $(am_ceph_test_ioctls_OBJECTS) ceph_test_ioctls_LDADD = $(LDADD) am_ceph_test_keys_OBJECTS = test/testkeys.$(OBJEXT) ceph_test_keys_OBJECTS = $(am_ceph_test_keys_OBJECTS) ceph_test_keys_DEPENDENCIES = $(am__DEPENDENCIES_9) \ $(am__DEPENDENCIES_6) am_ceph_test_keyvaluedb_atomicity_OBJECTS = test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.$(OBJEXT) ceph_test_keyvaluedb_atomicity_OBJECTS = \ $(am_ceph_test_keyvaluedb_atomicity_OBJECTS) ceph_test_keyvaluedb_atomicity_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) ceph_test_keyvaluedb_atomicity_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_keyvaluedb_atomicity_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ceph_test_keyvaluedb_iterators_OBJECTS = test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.$(OBJEXT) \ test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.$(OBJEXT) ceph_test_keyvaluedb_iterators_OBJECTS = \ $(am_ceph_test_keyvaluedb_iterators_OBJECTS) ceph_test_keyvaluedb_iterators_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) ceph_test_keyvaluedb_iterators_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ceph_test_libcephfs_OBJECTS = \ test/libcephfs/ceph_test_libcephfs-test.$(OBJEXT) \ test/libcephfs/ceph_test_libcephfs-readdir_r_cb.$(OBJEXT) \ test/libcephfs/ceph_test_libcephfs-caps.$(OBJEXT) \ test/libcephfs/ceph_test_libcephfs-multiclient.$(OBJEXT) ceph_test_libcephfs_OBJECTS = $(am_ceph_test_libcephfs_OBJECTS) ceph_test_libcephfs_DEPENDENCIES = $(LIBCEPHFS) $(am__DEPENDENCIES_13) ceph_test_libcephfs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_librbd_OBJECTS = \ test/librbd/ceph_test_librbd-test_librbd.$(OBJEXT) ceph_test_librbd_OBJECTS = $(am_ceph_test_librbd_OBJECTS) ceph_test_librbd_DEPENDENCIES = $(LIBRBD) $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(RADOS_TEST_LDADD) ceph_test_librbd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_librbd_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__ceph_test_librbd_fsx_SOURCES_DIST = test/librbd/fsx.c @LINUX_TRUE@am_ceph_test_librbd_fsx_OBJECTS = \ @LINUX_TRUE@ test/librbd/ceph_test_librbd_fsx-fsx.$(OBJEXT) ceph_test_librbd_fsx_OBJECTS = $(am_ceph_test_librbd_fsx_OBJECTS) @LINUX_TRUE@ceph_test_librbd_fsx_DEPENDENCIES = $(LIBRBD) $(LIBRADOS) ceph_test_librbd_fsx_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(ceph_test_librbd_fsx_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_mon_workloadgen_OBJECTS = \ test/mon/test_mon_workloadgen.$(OBJEXT) ceph_test_mon_workloadgen_OBJECTS = \ $(am_ceph_test_mon_workloadgen_OBJECTS) ceph_test_mon_workloadgen_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(LIBOSDC) $(am__DEPENDENCIES_6) am_ceph_test_msgr_OBJECTS = test/testmsgr.$(OBJEXT) ceph_test_msgr_OBJECTS = $(am_ceph_test_msgr_OBJECTS) ceph_test_msgr_DEPENDENCIES = $(am__DEPENDENCIES_6) am_ceph_test_mutate_OBJECTS = test/test_mutate.$(OBJEXT) ceph_test_mutate_OBJECTS = $(am_ceph_test_mutate_OBJECTS) ceph_test_mutate_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am_ceph_test_object_map_OBJECTS = \ test/ObjectMap/ceph_test_object_map-test_object_map.$(OBJEXT) \ test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.$(OBJEXT) ceph_test_object_map_OBJECTS = $(am_ceph_test_object_map_OBJECTS) ceph_test_object_map_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) ceph_test_object_map_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_objectcacher_stress_OBJECTS = \ test/osdc/object_cacher_stress.$(OBJEXT) \ test/osdc/FakeWriteback.$(OBJEXT) ceph_test_objectcacher_stress_OBJECTS = \ $(am_ceph_test_objectcacher_stress_OBJECTS) ceph_test_objectcacher_stress_DEPENDENCIES = $(LIBOSDC) \ $(am__DEPENDENCIES_6) am__ceph_test_objectstore_SOURCES_DIST = \ test/objectstore/store_test.cc @LINUX_TRUE@am_ceph_test_objectstore_OBJECTS = test/objectstore/ceph_test_objectstore-store_test.$(OBJEXT) ceph_test_objectstore_OBJECTS = $(am_ceph_test_objectstore_OBJECTS) @LINUX_TRUE@ceph_test_objectstore_DEPENDENCIES = \ @LINUX_TRUE@ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_13) \ @LINUX_TRUE@ $(am__DEPENDENCIES_6) ceph_test_objectstore_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_objectstore_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_objectstore_workloadgen_OBJECTS = \ test/objectstore/workload_generator.$(OBJEXT) \ test/objectstore/TestObjectStoreState.$(OBJEXT) ceph_test_objectstore_workloadgen_OBJECTS = \ $(am_ceph_test_objectstore_workloadgen_OBJECTS) ceph_test_objectstore_workloadgen_DEPENDENCIES = \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) am_ceph_test_rados_OBJECTS = test/osd/TestRados.$(OBJEXT) \ test/osd/TestOpStat.$(OBJEXT) test/osd/Object.$(OBJEXT) \ test/osd/RadosModel.$(OBJEXT) ceph_test_rados_OBJECTS = $(am_ceph_test_rados_OBJECTS) ceph_test_rados_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am_ceph_test_rados_api_aio_OBJECTS = \ test/librados/ceph_test_rados_api_aio-aio.$(OBJEXT) ceph_test_rados_api_aio_OBJECTS = \ $(am_ceph_test_rados_api_aio_OBJECTS) ceph_test_rados_api_aio_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_aio_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_aio_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_c_read_operations_OBJECTS = test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.$(OBJEXT) ceph_test_rados_api_c_read_operations_OBJECTS = \ $(am_ceph_test_rados_api_c_read_operations_OBJECTS) ceph_test_rados_api_c_read_operations_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_c_read_operations_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CXXLD) $(ceph_test_rados_api_c_read_operations_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ceph_test_rados_api_c_write_operations_OBJECTS = test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.$(OBJEXT) ceph_test_rados_api_c_write_operations_OBJECTS = \ $(am_ceph_test_rados_api_c_write_operations_OBJECTS) ceph_test_rados_api_c_write_operations_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_c_write_operations_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CXXLD) $(ceph_test_rados_api_c_write_operations_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ceph_test_rados_api_cls_OBJECTS = \ test/librados/ceph_test_rados_api_cls-cls.$(OBJEXT) ceph_test_rados_api_cls_OBJECTS = \ $(am_ceph_test_rados_api_cls_OBJECTS) ceph_test_rados_api_cls_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_cls_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_cls_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_cmd_OBJECTS = \ test/librados/ceph_test_rados_api_cmd-cmd.$(OBJEXT) ceph_test_rados_api_cmd_OBJECTS = \ $(am_ceph_test_rados_api_cmd_OBJECTS) ceph_test_rados_api_cmd_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_cmd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_cmd_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_io_OBJECTS = \ test/librados/ceph_test_rados_api_io-io.$(OBJEXT) ceph_test_rados_api_io_OBJECTS = $(am_ceph_test_rados_api_io_OBJECTS) ceph_test_rados_api_io_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_io_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_io_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_list_OBJECTS = \ test/librados/ceph_test_rados_api_list-list.$(OBJEXT) ceph_test_rados_api_list_OBJECTS = \ $(am_ceph_test_rados_api_list_OBJECTS) ceph_test_rados_api_list_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_list_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_list_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_lock_OBJECTS = \ test/librados/ceph_test_rados_api_lock-lock.$(OBJEXT) ceph_test_rados_api_lock_OBJECTS = \ $(am_ceph_test_rados_api_lock_OBJECTS) ceph_test_rados_api_lock_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_lock_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_lock_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_misc_OBJECTS = \ test/librados/ceph_test_rados_api_misc-misc.$(OBJEXT) ceph_test_rados_api_misc_OBJECTS = \ $(am_ceph_test_rados_api_misc_OBJECTS) ceph_test_rados_api_misc_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(RADOS_TEST_LDADD) ceph_test_rados_api_misc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_misc_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_pool_OBJECTS = \ test/librados/ceph_test_rados_api_pool-pool.$(OBJEXT) ceph_test_rados_api_pool_OBJECTS = \ $(am_ceph_test_rados_api_pool_OBJECTS) ceph_test_rados_api_pool_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_pool_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_pool_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_snapshots_OBJECTS = test/librados/ceph_test_rados_api_snapshots-snapshots.$(OBJEXT) ceph_test_rados_api_snapshots_OBJECTS = \ $(am_ceph_test_rados_api_snapshots_OBJECTS) ceph_test_rados_api_snapshots_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_snapshots_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_snapshots_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ceph_test_rados_api_stat_OBJECTS = \ test/librados/ceph_test_rados_api_stat-stat.$(OBJEXT) ceph_test_rados_api_stat_OBJECTS = \ $(am_ceph_test_rados_api_stat_OBJECTS) ceph_test_rados_api_stat_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_stat_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_stat_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_tier_OBJECTS = \ test/librados/ceph_test_rados_api_tier-tier.$(OBJEXT) \ osd/ceph_test_rados_api_tier-HitSet.$(OBJEXT) ceph_test_rados_api_tier_OBJECTS = \ $(am_ceph_test_rados_api_tier_OBJECTS) ceph_test_rados_api_tier_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(RADOS_TEST_LDADD) ceph_test_rados_api_tier_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_rados_api_watch_notify_OBJECTS = test/librados/ceph_test_rados_api_watch_notify-watch_notify.$(OBJEXT) ceph_test_rados_api_watch_notify_OBJECTS = \ $(am_ceph_test_rados_api_watch_notify_OBJECTS) ceph_test_rados_api_watch_notify_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_rados_api_watch_notify_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CXXLD) $(ceph_test_rados_api_watch_notify_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__ceph_test_rados_delete_pools_parallel_SOURCES_DIST = \ test/system/rados_delete_pools_parallel.cc \ test/system/st_rados_create_pool.cc \ test/system/st_rados_delete_pool.cc \ test/system/st_rados_list_objects.cc @LINUX_TRUE@am_ceph_test_rados_delete_pools_parallel_OBJECTS = \ @LINUX_TRUE@ test/system/rados_delete_pools_parallel.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_create_pool.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_delete_pool.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_list_objects.$(OBJEXT) ceph_test_rados_delete_pools_parallel_OBJECTS = \ $(am_ceph_test_rados_delete_pools_parallel_OBJECTS) @LINUX_TRUE@ceph_test_rados_delete_pools_parallel_DEPENDENCIES = \ @LINUX_TRUE@ $(LIBRADOS) libsystest.la $(am__DEPENDENCIES_1) am__ceph_test_rados_list_parallel_SOURCES_DIST = \ test/system/rados_list_parallel.cc \ test/system/st_rados_create_pool.cc \ test/system/st_rados_list_objects.cc @LINUX_TRUE@am_ceph_test_rados_list_parallel_OBJECTS = \ @LINUX_TRUE@ test/system/rados_list_parallel.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_create_pool.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_list_objects.$(OBJEXT) ceph_test_rados_list_parallel_OBJECTS = \ $(am_ceph_test_rados_list_parallel_OBJECTS) @LINUX_TRUE@ceph_test_rados_list_parallel_DEPENDENCIES = $(LIBRADOS) \ @LINUX_TRUE@ libsystest.la $(am__DEPENDENCIES_1) am__ceph_test_rados_open_pools_parallel_SOURCES_DIST = \ test/system/rados_open_pools_parallel.cc \ test/system/st_rados_create_pool.cc @LINUX_TRUE@am_ceph_test_rados_open_pools_parallel_OBJECTS = \ @LINUX_TRUE@ test/system/rados_open_pools_parallel.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_create_pool.$(OBJEXT) ceph_test_rados_open_pools_parallel_OBJECTS = \ $(am_ceph_test_rados_open_pools_parallel_OBJECTS) @LINUX_TRUE@ceph_test_rados_open_pools_parallel_DEPENDENCIES = \ @LINUX_TRUE@ $(LIBRADOS) libsystest.la $(am__DEPENDENCIES_1) am__ceph_test_rados_watch_notify_SOURCES_DIST = \ test/system/rados_watch_notify.cc \ test/system/st_rados_create_pool.cc \ test/system/st_rados_delete_pool.cc \ test/system/st_rados_delete_objs.cc \ test/system/st_rados_watch.cc test/system/st_rados_notify.cc @LINUX_TRUE@am_ceph_test_rados_watch_notify_OBJECTS = \ @LINUX_TRUE@ test/system/rados_watch_notify.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_create_pool.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_delete_pool.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_delete_objs.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_watch.$(OBJEXT) \ @LINUX_TRUE@ test/system/st_rados_notify.$(OBJEXT) ceph_test_rados_watch_notify_OBJECTS = \ $(am_ceph_test_rados_watch_notify_OBJECTS) @LINUX_TRUE@ceph_test_rados_watch_notify_DEPENDENCIES = $(LIBRADOS) \ @LINUX_TRUE@ libsystest.la $(am__DEPENDENCIES_1) am_ceph_test_rewrite_latency_OBJECTS = \ test/test_rewrite_latency.$(OBJEXT) ceph_test_rewrite_latency_OBJECTS = \ $(am_ceph_test_rewrite_latency_OBJECTS) ceph_test_rewrite_latency_DEPENDENCIES = $(LIBCOMMON) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am__ceph_test_rgw_manifest_SOURCES_DIST = \ test/rgw/test_rgw_manifest.cc @WITH_RADOSGW_TRUE@am_ceph_test_rgw_manifest_OBJECTS = test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.$(OBJEXT) ceph_test_rgw_manifest_OBJECTS = $(am_ceph_test_rgw_manifest_OBJECTS) @WITH_RADOSGW_TRUE@ceph_test_rgw_manifest_DEPENDENCIES = $(LIBRADOS) \ @WITH_RADOSGW_TRUE@ $(LIBRGW) $(am__DEPENDENCIES_12) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_6) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_13) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_1) ceph_test_rgw_manifest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_rgw_manifest_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_signal_handlers_OBJECTS = \ test/TestSignalHandlers.$(OBJEXT) ceph_test_signal_handlers_OBJECTS = \ $(am_ceph_test_signal_handlers_OBJECTS) ceph_test_signal_handlers_DEPENDENCIES = $(am__DEPENDENCIES_6) am_ceph_test_snap_mapper_OBJECTS = \ test/ceph_test_snap_mapper-test_snap_mapper.$(OBJEXT) ceph_test_snap_mapper_OBJECTS = $(am_ceph_test_snap_mapper_OBJECTS) ceph_test_snap_mapper_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) ceph_test_snap_mapper_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_snap_mapper_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_stress_watch_OBJECTS = \ test/ceph_test_stress_watch-test_stress_watch.$(OBJEXT) ceph_test_stress_watch_OBJECTS = $(am_ceph_test_stress_watch_OBJECTS) ceph_test_stress_watch_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) $(RADOS_TEST_LDADD) ceph_test_stress_watch_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_test_stress_watch_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_ceph_test_timers_OBJECTS = test/TestTimers.$(OBJEXT) ceph_test_timers_OBJECTS = $(am_ceph_test_timers_OBJECTS) ceph_test_timers_DEPENDENCIES = $(am__DEPENDENCIES_6) am_ceph_test_trans_OBJECTS = test/test_trans.$(OBJEXT) ceph_test_trans_OBJECTS = $(am_ceph_test_trans_OBJECTS) ceph_test_trans_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) am_ceph_tpbench_OBJECTS = test/bench/tp_bench.$(OBJEXT) \ test/bench/detailed_stat_collector.$(OBJEXT) ceph_tpbench_OBJECTS = $(am_ceph_tpbench_OBJECTS) ceph_tpbench_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) am_ceph_xattr_bench_OBJECTS = \ test/ceph_xattr_bench-xattr_bench.$(OBJEXT) ceph_xattr_bench_OBJECTS = $(am_ceph_xattr_bench_OBJECTS) ceph_xattr_bench_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) ceph_xattr_bench_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(ceph_xattr_bench_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_cephfs_OBJECTS = cephfs.$(OBJEXT) cephfs_OBJECTS = $(am_cephfs_OBJECTS) cephfs_DEPENDENCIES = $(LIBCOMMON) am_crushtool_OBJECTS = tools/crushtool.$(OBJEXT) crushtool_OBJECTS = $(am_crushtool_OBJECTS) crushtool_DEPENDENCIES = $(am__DEPENDENCIES_6) am_get_command_descriptions_OBJECTS = \ test/common/get_command_descriptions.$(OBJEXT) get_command_descriptions_OBJECTS = \ $(am_get_command_descriptions_OBJECTS) get_command_descriptions_DEPENDENCIES = $(am__DEPENDENCIES_9) \ $(LIBCOMMON) $(am__DEPENDENCIES_6) am_librados_config_OBJECTS = librados-config.$(OBJEXT) librados_config_OBJECTS = $(am_librados_config_OBJECTS) librados_config_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_6) am_monmaptool_OBJECTS = tools/monmaptool.$(OBJEXT) monmaptool_OBJECTS = $(am_monmaptool_OBJECTS) monmaptool_DEPENDENCIES = $(am__DEPENDENCIES_6) $(LIBCOMMON) am_mount_ceph_OBJECTS = mount/mount.ceph.$(OBJEXT) \ common/secret.$(OBJEXT) mount_ceph_OBJECTS = $(am_mount_ceph_OBJECTS) mount_ceph_DEPENDENCIES = $(LIBCOMMON) $(am__DEPENDENCIES_1) am_osdmaptool_OBJECTS = tools/osdmaptool.$(OBJEXT) osdmaptool_OBJECTS = $(am_osdmaptool_OBJECTS) osdmaptool_DEPENDENCIES = $(am__DEPENDENCIES_6) am_rados_OBJECTS = tools/rados/rados.$(OBJEXT) \ tools/rados/rados_import.$(OBJEXT) \ tools/rados/rados_export.$(OBJEXT) \ tools/rados/rados_sync.$(OBJEXT) common/obj_bencher.$(OBJEXT) rados_OBJECTS = $(am_rados_OBJECTS) rados_DEPENDENCIES = libcls_lock_client.la $(LIBRADOS) \ $(am__DEPENDENCIES_6) am__radosgw_SOURCES_DIST = rgw/rgw_resolve.cc rgw/rgw_rest.cc \ rgw/rgw_rest_swift.cc rgw/rgw_rest_s3.cc rgw/rgw_rest_usage.cc \ rgw/rgw_rest_user.cc rgw/rgw_rest_bucket.cc \ rgw/rgw_rest_metadata.cc rgw/rgw_replica_log.cc \ rgw/rgw_rest_log.cc rgw/rgw_rest_opstate.cc \ rgw/rgw_rest_replica_log.cc rgw/rgw_rest_config.cc \ rgw/rgw_http_client.cc rgw/rgw_swift.cc rgw/rgw_swift_auth.cc \ rgw/rgw_loadgen.cc rgw/rgw_main.cc @WITH_RADOSGW_TRUE@am_radosgw_OBJECTS = rgw/rgw_resolve.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_swift.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_s3.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_usage.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_user.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_bucket.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_metadata.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_replica_log.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_log.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_opstate.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_replica_log.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_config.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_http_client.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_swift.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_swift_auth.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_loadgen.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/rgw_main.$(OBJEXT) radosgw_OBJECTS = $(am_radosgw_OBJECTS) @WITH_RADOSGW_TRUE@radosgw_DEPENDENCIES = $(LIBRGW) $(LIBCIVETWEB) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_12) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_6) am__radosgw_admin_SOURCES_DIST = rgw/rgw_admin.cc @WITH_RADOSGW_TRUE@am_radosgw_admin_OBJECTS = rgw/rgw_admin.$(OBJEXT) radosgw_admin_OBJECTS = $(am_radosgw_admin_OBJECTS) @WITH_RADOSGW_TRUE@radosgw_admin_DEPENDENCIES = $(LIBRGW) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_12) \ @WITH_RADOSGW_TRUE@ $(am__DEPENDENCIES_6) am_rbd_OBJECTS = rbd.$(OBJEXT) common/secret.$(OBJEXT) rbd_OBJECTS = $(am_rbd_OBJECTS) rbd_DEPENDENCIES = $(LIBRBD) $(LIBRADOS) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) am__rbd_fuse_SOURCES_DIST = rbd_fuse/rbd-fuse.c @WITH_FUSE_TRUE@am_rbd_fuse_OBJECTS = rbd_fuse/rbd-fuse.$(OBJEXT) rbd_fuse_OBJECTS = $(am_rbd_fuse_OBJECTS) @WITH_FUSE_TRUE@rbd_fuse_DEPENDENCIES = $(LIBRBD) $(LIBRADOS) \ @WITH_FUSE_TRUE@ $(am__DEPENDENCIES_6) am__rest_bench_SOURCES_DIST = tools/rest_bench.cc \ common/obj_bencher.cc @WITH_REST_BENCH_TRUE@am_rest_bench_OBJECTS = \ @WITH_REST_BENCH_TRUE@ tools/rest_bench-rest_bench.$(OBJEXT) \ @WITH_REST_BENCH_TRUE@ common/rest_bench-obj_bencher.$(OBJEXT) rest_bench_OBJECTS = $(am_rest_bench_OBJECTS) @WITH_REST_BENCH_TRUE@@WITH_SYSTEM_LIBS3_FALSE@am__DEPENDENCIES_14 = libs3/build/lib/libs3.a @WITH_REST_BENCH_TRUE@rest_bench_DEPENDENCIES = $(am__DEPENDENCIES_6) \ @WITH_REST_BENCH_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_REST_BENCH_TRUE@ $(am__DEPENDENCIES_14) rest_bench_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(rest_bench_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__test_build_libcephfs_SOURCES_DIST = test/buildtest_skeleton.cc \ osdc/Objecter.cc osdc/ObjectCacher.cc osdc/Filer.cc \ osdc/Striper.cc osdc/Journaler.cc am__objects_14 = osdc/test_build_libcephfs-Objecter.$(OBJEXT) \ osdc/test_build_libcephfs-ObjectCacher.$(OBJEXT) \ osdc/test_build_libcephfs-Filer.$(OBJEXT) \ osdc/test_build_libcephfs-Striper.$(OBJEXT) \ osdc/test_build_libcephfs-Journaler.$(OBJEXT) @WITH_BUILD_TESTS_TRUE@am_test_build_libcephfs_OBJECTS = test/test_build_libcephfs-buildtest_skeleton.$(OBJEXT) \ @WITH_BUILD_TESTS_TRUE@ $(am__objects_14) test_build_libcephfs_OBJECTS = $(am_test_build_libcephfs_OBJECTS) @WITH_BUILD_TESTS_TRUE@test_build_libcephfs_DEPENDENCIES = \ @WITH_BUILD_TESTS_TRUE@ $(LIBCEPHFS) $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_2) test_build_libcephfs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) \ $(test_build_libcephfs_LDFLAGS) $(LDFLAGS) -o $@ am__test_build_libcommon_SOURCES_DIST = test/buildtest_skeleton.cc \ ceph_ver.c common/DecayCounter.cc common/LogClient.cc \ common/LogEntry.cc common/PrebufferedStreambuf.cc \ common/SloppyCRCMap.cc common/BackTrace.cc \ common/perf_counters.cc common/Mutex.cc \ common/OutputDataSocket.cc common/admin_socket.cc \ common/admin_socket_client.cc common/cmdparse.cc \ common/escape.c common/io_priority.cc common/Clock.cc \ common/Throttle.cc common/Timer.cc common/Finisher.cc \ common/environment.cc common/assert.cc common/run_cmd.cc \ common/WorkQueue.cc common/ConfUtils.cc common/MemoryModel.cc \ common/armor.c common/fd.cc common/xattr.c common/safe_io.c \ common/snap_types.cc common/str_list.cc common/str_map.cc \ common/errno.cc common/RefCountedObj.cc common/blkdev.cc \ common/common_init.cc common/pipe.c common/ceph_argparse.cc \ common/ceph_context.cc common/buffer.cc \ common/code_environment.cc common/dout.cc common/histogram.cc \ common/signal.cc common/simple_spin.cc common/Thread.cc \ common/Formatter.cc common/HeartbeatMap.cc common/config.cc \ common/utf8.c common/mime.c common/strtol.cc common/page.cc \ common/lockdep.cc common/version.cc common/hex.cc \ common/entity_name.cc common/ceph_crypto.cc \ common/ceph_crypto_cms.cc common/ceph_json.cc common/ipaddr.cc \ common/pick_address.cc common/util.cc common/TextTable.cc \ common/ceph_fs.cc common/ceph_hash.cc common/ceph_strings.cc \ common/ceph_frag.cc common/addr_parsing.c common/hobject.cc \ common/bloom_filter.cc common/linux_version.c mon/MonCap.cc \ mon/MonClient.cc mon/MonMap.cc osd/OSDMap.cc osd/osd_types.cc \ osd/ECMsgTypes.cc osd/HitSet.cc mds/MDSMap.cc \ mds/inode_backtrace.cc mds/mdstypes.cc mds/flock.cc am__objects_15 = test_build_libcommon-ceph_ver.$(OBJEXT) \ common/test_build_libcommon-DecayCounter.$(OBJEXT) \ common/test_build_libcommon-LogClient.$(OBJEXT) \ common/test_build_libcommon-LogEntry.$(OBJEXT) \ common/test_build_libcommon-PrebufferedStreambuf.$(OBJEXT) \ common/test_build_libcommon-SloppyCRCMap.$(OBJEXT) \ common/test_build_libcommon-BackTrace.$(OBJEXT) \ common/test_build_libcommon-perf_counters.$(OBJEXT) \ common/test_build_libcommon-Mutex.$(OBJEXT) \ common/test_build_libcommon-OutputDataSocket.$(OBJEXT) \ common/test_build_libcommon-admin_socket.$(OBJEXT) \ common/test_build_libcommon-admin_socket_client.$(OBJEXT) \ common/test_build_libcommon-cmdparse.$(OBJEXT) \ common/test_build_libcommon-escape.$(OBJEXT) \ common/test_build_libcommon-io_priority.$(OBJEXT) \ common/test_build_libcommon-Clock.$(OBJEXT) \ common/test_build_libcommon-Throttle.$(OBJEXT) \ common/test_build_libcommon-Timer.$(OBJEXT) \ common/test_build_libcommon-Finisher.$(OBJEXT) \ common/test_build_libcommon-environment.$(OBJEXT) \ common/test_build_libcommon-assert.$(OBJEXT) \ common/test_build_libcommon-run_cmd.$(OBJEXT) \ common/test_build_libcommon-WorkQueue.$(OBJEXT) \ common/test_build_libcommon-ConfUtils.$(OBJEXT) \ common/test_build_libcommon-MemoryModel.$(OBJEXT) \ common/test_build_libcommon-armor.$(OBJEXT) \ common/test_build_libcommon-fd.$(OBJEXT) \ common/test_build_libcommon-xattr.$(OBJEXT) \ common/test_build_libcommon-safe_io.$(OBJEXT) \ common/test_build_libcommon-snap_types.$(OBJEXT) \ common/test_build_libcommon-str_list.$(OBJEXT) \ common/test_build_libcommon-str_map.$(OBJEXT) \ common/test_build_libcommon-errno.$(OBJEXT) \ common/test_build_libcommon-RefCountedObj.$(OBJEXT) \ common/test_build_libcommon-blkdev.$(OBJEXT) \ common/test_build_libcommon-common_init.$(OBJEXT) \ common/test_build_libcommon-pipe.$(OBJEXT) \ common/test_build_libcommon-ceph_argparse.$(OBJEXT) \ common/test_build_libcommon-ceph_context.$(OBJEXT) \ common/test_build_libcommon-buffer.$(OBJEXT) \ common/test_build_libcommon-code_environment.$(OBJEXT) \ common/test_build_libcommon-dout.$(OBJEXT) \ common/test_build_libcommon-histogram.$(OBJEXT) \ common/test_build_libcommon-signal.$(OBJEXT) \ common/test_build_libcommon-simple_spin.$(OBJEXT) \ common/test_build_libcommon-Thread.$(OBJEXT) \ common/test_build_libcommon-Formatter.$(OBJEXT) \ common/test_build_libcommon-HeartbeatMap.$(OBJEXT) \ common/test_build_libcommon-config.$(OBJEXT) \ common/test_build_libcommon-utf8.$(OBJEXT) \ common/test_build_libcommon-mime.$(OBJEXT) \ common/test_build_libcommon-strtol.$(OBJEXT) \ common/test_build_libcommon-page.$(OBJEXT) \ common/test_build_libcommon-lockdep.$(OBJEXT) \ common/test_build_libcommon-version.$(OBJEXT) \ common/test_build_libcommon-hex.$(OBJEXT) \ common/test_build_libcommon-entity_name.$(OBJEXT) \ common/test_build_libcommon-ceph_crypto.$(OBJEXT) \ common/test_build_libcommon-ceph_crypto_cms.$(OBJEXT) \ common/test_build_libcommon-ceph_json.$(OBJEXT) \ common/test_build_libcommon-ipaddr.$(OBJEXT) \ common/test_build_libcommon-pick_address.$(OBJEXT) \ common/test_build_libcommon-util.$(OBJEXT) \ common/test_build_libcommon-TextTable.$(OBJEXT) \ common/test_build_libcommon-ceph_fs.$(OBJEXT) \ common/test_build_libcommon-ceph_hash.$(OBJEXT) \ common/test_build_libcommon-ceph_strings.$(OBJEXT) \ common/test_build_libcommon-ceph_frag.$(OBJEXT) \ common/test_build_libcommon-addr_parsing.$(OBJEXT) \ common/test_build_libcommon-hobject.$(OBJEXT) \ common/test_build_libcommon-bloom_filter.$(OBJEXT) \ common/test_build_libcommon-linux_version.$(OBJEXT) \ mon/test_build_libcommon-MonCap.$(OBJEXT) \ mon/test_build_libcommon-MonClient.$(OBJEXT) \ mon/test_build_libcommon-MonMap.$(OBJEXT) \ osd/test_build_libcommon-OSDMap.$(OBJEXT) \ osd/test_build_libcommon-osd_types.$(OBJEXT) \ osd/test_build_libcommon-ECMsgTypes.$(OBJEXT) \ osd/test_build_libcommon-HitSet.$(OBJEXT) \ mds/test_build_libcommon-MDSMap.$(OBJEXT) \ mds/test_build_libcommon-inode_backtrace.$(OBJEXT) \ mds/test_build_libcommon-mdstypes.$(OBJEXT) \ mds/test_build_libcommon-flock.$(OBJEXT) @WITH_BUILD_TESTS_TRUE@am_test_build_libcommon_OBJECTS = test/test_build_libcommon-buildtest_skeleton.$(OBJEXT) \ @WITH_BUILD_TESTS_TRUE@ $(am__objects_15) test_build_libcommon_OBJECTS = $(am_test_build_libcommon_OBJECTS) @WITH_BUILD_TESTS_TRUE@test_build_libcommon_DEPENDENCIES = \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_3) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_2) test_build_libcommon_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) \ $(test_build_libcommon_LDFLAGS) $(LDFLAGS) -o $@ am__test_build_librados_SOURCES_DIST = test/buildtest_skeleton.cc \ librados/librados.cc librados/RadosClient.cc \ librados/IoCtxImpl.cc librados/snap_set_diff.cc am__objects_16 = librados/test_build_librados-librados.$(OBJEXT) \ librados/test_build_librados-RadosClient.$(OBJEXT) \ librados/test_build_librados-IoCtxImpl.$(OBJEXT) \ librados/test_build_librados-snap_set_diff.$(OBJEXT) @WITH_BUILD_TESTS_TRUE@am_test_build_librados_OBJECTS = test/test_build_librados-buildtest_skeleton.$(OBJEXT) \ @WITH_BUILD_TESTS_TRUE@ $(am__objects_16) test_build_librados_OBJECTS = $(am_test_build_librados_OBJECTS) @WITH_BUILD_TESTS_TRUE@test_build_librados_DEPENDENCIES = \ @WITH_BUILD_TESTS_TRUE@ $(LIBRADOS_DEPS) $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_2) test_build_librados_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(test_build_librados_CXXFLAGS) $(CXXFLAGS) \ $(test_build_librados_LDFLAGS) $(LDFLAGS) -o $@ am__test_build_librgw_SOURCES_DIST = test/buildtest_skeleton.cc \ rgw/librgw.cc rgw/rgw_acl.cc rgw/rgw_acl_s3.cc \ rgw/rgw_acl_swift.cc rgw/rgw_client_io.cc rgw/rgw_fcgi.cc \ rgw/rgw_xml.cc rgw/rgw_usage.cc rgw/rgw_json_enc.cc \ rgw/rgw_user.cc rgw/rgw_bucket.cc rgw/rgw_tools.cc \ rgw/rgw_rados.cc rgw/rgw_http_client.cc rgw/rgw_rest_client.cc \ rgw/rgw_rest_conn.cc rgw/rgw_op.cc rgw/rgw_common.cc \ rgw/rgw_cache.cc rgw/rgw_formats.cc rgw/rgw_log.cc \ rgw/rgw_multi.cc rgw/rgw_policy_s3.cc rgw/rgw_gc.cc \ rgw/rgw_multi_del.cc rgw/rgw_env.cc rgw/rgw_cors.cc \ rgw/rgw_cors_s3.cc rgw/rgw_auth_s3.cc rgw/rgw_metadata.cc \ rgw/rgw_replica_log.cc rgw/rgw_keystone.cc rgw/rgw_quota.cc \ rgw/rgw_dencoder.cc @WITH_RADOSGW_TRUE@am__objects_17 = \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-librgw.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_acl.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_acl_s3.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_acl_swift.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_client_io.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_fcgi.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_xml.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_usage.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_json_enc.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_user.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_bucket.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_tools.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_rados.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_http_client.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_rest_client.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_rest_conn.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_op.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_common.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_cache.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_formats.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_log.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_multi.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_policy_s3.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_gc.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_multi_del.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_env.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_cors.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_cors_s3.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_auth_s3.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_metadata.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_replica_log.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_keystone.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_quota.$(OBJEXT) \ @WITH_RADOSGW_TRUE@ rgw/test_build_librgw-rgw_dencoder.$(OBJEXT) @WITH_BUILD_TESTS_TRUE@am_test_build_librgw_OBJECTS = test/test_build_librgw-buildtest_skeleton.$(OBJEXT) \ @WITH_BUILD_TESTS_TRUE@ $(am__objects_17) test_build_librgw_OBJECTS = $(am_test_build_librgw_OBJECTS) @WITH_BUILD_TESTS_TRUE@test_build_librgw_DEPENDENCIES = \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_12) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_2) \ @WITH_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_6) test_build_librgw_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) \ $(test_build_librgw_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_addrs_OBJECTS = test/unittest_addrs-test_addrs.$(OBJEXT) unittest_addrs_OBJECTS = $(am_unittest_addrs_OBJECTS) unittest_addrs_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_addrs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_addrs_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_admin_socket_OBJECTS = \ test/unittest_admin_socket-admin_socket.$(OBJEXT) unittest_admin_socket_OBJECTS = $(am_unittest_admin_socket_OBJECTS) unittest_admin_socket_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_admin_socket_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_admin_socket_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_arch_OBJECTS = test/unittest_arch-test_arch.$(OBJEXT) unittest_arch_OBJECTS = $(am_unittest_arch_OBJECTS) unittest_arch_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_arch_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_arch_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ am_unittest_base64_OBJECTS = test/unittest_base64-base64.$(OBJEXT) unittest_base64_OBJECTS = $(am_unittest_base64_OBJECTS) unittest_base64_DEPENDENCIES = $(LIBCEPHFS) $(am__DEPENDENCIES_13) unittest_base64_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_base64_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_bloom_filter_OBJECTS = \ test/common/unittest_bloom_filter-test_bloom_filter.$(OBJEXT) unittest_bloom_filter_OBJECTS = $(am_unittest_bloom_filter_OBJECTS) unittest_bloom_filter_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_bloom_filter_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_bloom_filter_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_bufferlist_OBJECTS = \ test/unittest_bufferlist-bufferlist.$(OBJEXT) unittest_bufferlist_OBJECTS = $(am_unittest_bufferlist_OBJECTS) unittest_bufferlist_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_bufferlist_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_bufferlist_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_ceph_argparse_OBJECTS = \ test/unittest_ceph_argparse-ceph_argparse.$(OBJEXT) unittest_ceph_argparse_OBJECTS = $(am_unittest_ceph_argparse_OBJECTS) unittest_ceph_argparse_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_ceph_argparse_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_ceph_argparse_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_ceph_compatset_OBJECTS = \ test/unittest_ceph_compatset-ceph_compatset.$(OBJEXT) unittest_ceph_compatset_OBJECTS = \ $(am_unittest_ceph_compatset_OBJECTS) unittest_ceph_compatset_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_ceph_compatset_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_ceph_compatset_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_ceph_crypto_OBJECTS = \ test/unittest_ceph_crypto-ceph_crypto.$(OBJEXT) unittest_ceph_crypto_OBJECTS = $(am_unittest_ceph_crypto_OBJECTS) unittest_ceph_crypto_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_ceph_crypto_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_ceph_crypto_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_chain_xattr_OBJECTS = \ test/objectstore/unittest_chain_xattr-chain_xattr.$(OBJEXT) unittest_chain_xattr_OBJECTS = $(am_unittest_chain_xattr_OBJECTS) unittest_chain_xattr_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_chain_xattr_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_chain_xattr_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_config_OBJECTS = \ test/common/unittest_config-test_config.$(OBJEXT) unittest_config_OBJECTS = $(am_unittest_config_OBJECTS) unittest_config_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_config_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_config_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_confutils_OBJECTS = \ test/unittest_confutils-confutils.$(OBJEXT) unittest_confutils_OBJECTS = $(am_unittest_confutils_OBJECTS) unittest_confutils_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_confutils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_confutils_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_context_OBJECTS = \ test/common/unittest_context-test_context.$(OBJEXT) unittest_context_OBJECTS = $(am_unittest_context_OBJECTS) unittest_context_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_context_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_context_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_crc32c_OBJECTS = \ test/common/unittest_crc32c-test_crc32c.$(OBJEXT) unittest_crc32c_OBJECTS = $(am_unittest_crc32c_OBJECTS) unittest_crc32c_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_crc32c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_crc32c_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_crush_indep_OBJECTS = \ test/crush/unittest_crush_indep-indep.$(OBJEXT) unittest_crush_indep_OBJECTS = $(am_unittest_crush_indep_OBJECTS) unittest_crush_indep_DEPENDENCIES = $(LIBCOMMON) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_6) unittest_crush_indep_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_crush_indep_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_crush_wrapper_OBJECTS = \ test/crush/unittest_crush_wrapper-TestCrushWrapper.$(OBJEXT) unittest_crush_wrapper_OBJECTS = $(am_unittest_crush_wrapper_OBJECTS) unittest_crush_wrapper_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) $(LIBCRUSH) unittest_crush_wrapper_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_crush_wrapper_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_crypto_OBJECTS = test/unittest_crypto-crypto.$(OBJEXT) unittest_crypto_OBJECTS = $(am_unittest_crypto_OBJECTS) unittest_crypto_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_crypto_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_crypto_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_crypto_init_OBJECTS = \ test/unittest_crypto_init-crypto_init.$(OBJEXT) unittest_crypto_init_OBJECTS = $(am_unittest_crypto_init_OBJECTS) unittest_crypto_init_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_crypto_init_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_crypto_init_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_daemon_config_OBJECTS = \ test/unittest_daemon_config-daemon_config.$(OBJEXT) unittest_daemon_config_OBJECTS = $(am_unittest_daemon_config_OBJECTS) unittest_daemon_config_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_daemon_config_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_daemon_config_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_ecbackend_OBJECTS = \ test/osd/unittest_ecbackend-TestECBackend.$(OBJEXT) unittest_ecbackend_OBJECTS = $(am_unittest_ecbackend_OBJECTS) unittest_ecbackend_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_ecbackend_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_ecbackend_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_encoding_OBJECTS = \ test/unittest_encoding-encoding.$(OBJEXT) unittest_encoding_OBJECTS = $(am_unittest_encoding_OBJECTS) unittest_encoding_DEPENDENCIES = $(LIBCEPHFS) $(LIBRADOS) \ $(am__DEPENDENCIES_13) unittest_encoding_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_encoding_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_erasure_code_example_OBJECTS = test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.$(OBJEXT) unittest_erasure_code_example_OBJECTS = \ $(am_unittest_erasure_code_example_OBJECTS) unittest_erasure_code_example_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(LIBCOMMON) $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_erasure_code_example_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_erasure_code_example_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__objects_18 = erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.$(OBJEXT) \ erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.$(OBJEXT) \ erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.$(OBJEXT) \ erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.$(OBJEXT) \ erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.$(OBJEXT) \ erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.$(OBJEXT) \ erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.$(OBJEXT) \ erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.$(OBJEXT) am_unittest_erasure_code_jerasure_OBJECTS = test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.$(OBJEXT) \ $(am__objects_18) unittest_erasure_code_jerasure_OBJECTS = \ $(am_unittest_erasure_code_jerasure_OBJECTS) unittest_erasure_code_jerasure_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(LIBCOMMON) $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) unittest_erasure_code_jerasure_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_erasure_code_plugin_OBJECTS = test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.$(OBJEXT) unittest_erasure_code_plugin_OBJECTS = \ $(am_unittest_erasure_code_plugin_OBJECTS) unittest_erasure_code_plugin_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(LIBCOMMON) $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) unittest_erasure_code_plugin_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_erasure_code_plugin_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_erasure_code_plugin_jerasure_OBJECTS = test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.$(OBJEXT) unittest_erasure_code_plugin_jerasure_OBJECTS = \ $(am_unittest_erasure_code_plugin_jerasure_OBJECTS) unittest_erasure_code_plugin_jerasure_DEPENDENCIES = \ $(am__DEPENDENCIES_10) $(LIBCOMMON) $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_1) unittest_erasure_code_plugin_jerasure_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CXXLD) $(unittest_erasure_code_plugin_jerasure_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_escape_OBJECTS = test/unittest_escape-escape.$(OBJEXT) unittest_escape_OBJECTS = $(am_unittest_escape_OBJECTS) unittest_escape_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_escape_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_escape_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_flatindex_OBJECTS = \ test/os/unittest_flatindex-TestFlatIndex.$(OBJEXT) unittest_flatindex_OBJECTS = $(am_unittest_flatindex_OBJECTS) unittest_flatindex_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_flatindex_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_flatindex_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_formatter_OBJECTS = \ test/unittest_formatter-formatter.$(OBJEXT) \ rgw/unittest_formatter-rgw_formats.$(OBJEXT) unittest_formatter_OBJECTS = $(am_unittest_formatter_OBJECTS) unittest_formatter_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_formatter_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_gather_OBJECTS = test/unittest_gather-gather.$(OBJEXT) unittest_gather_OBJECTS = $(am_unittest_gather_OBJECTS) unittest_gather_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_gather_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_gather_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_heartbeatmap_OBJECTS = \ test/unittest_heartbeatmap-heartbeat_map.$(OBJEXT) unittest_heartbeatmap_OBJECTS = $(am_unittest_heartbeatmap_OBJECTS) unittest_heartbeatmap_DEPENDENCIES = $(LIBCOMMON) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_heartbeatmap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_heartbeatmap_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_histogram_OBJECTS = \ test/common/unittest_histogram-histogram.$(OBJEXT) unittest_histogram_OBJECTS = $(am_unittest_histogram_OBJECTS) unittest_histogram_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_histogram_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_histogram_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_hitset_OBJECTS = \ test/osd/unittest_hitset-hitset.$(OBJEXT) unittest_hitset_OBJECTS = $(am_unittest_hitset_OBJECTS) unittest_hitset_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_hitset_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_hitset_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_io_priority_OBJECTS = \ test/common/unittest_io_priority-test_io_priority.$(OBJEXT) unittest_io_priority_OBJECTS = $(am_unittest_io_priority_OBJECTS) unittest_io_priority_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_io_priority_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_io_priority_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_ipaddr_OBJECTS = \ test/unittest_ipaddr-test_ipaddr.$(OBJEXT) unittest_ipaddr_OBJECTS = $(am_unittest_ipaddr_OBJECTS) unittest_ipaddr_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_ipaddr_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_ipaddr_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_lfnindex_OBJECTS = \ test/os/unittest_lfnindex-TestLFNIndex.$(OBJEXT) unittest_lfnindex_OBJECTS = $(am_unittest_lfnindex_OBJECTS) unittest_lfnindex_DEPENDENCIES = $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_lfnindex_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_lfnindex_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_libcephfs_config_OBJECTS = \ test/unittest_libcephfs_config-libcephfs_config.$(OBJEXT) unittest_libcephfs_config_OBJECTS = \ $(am_unittest_libcephfs_config_OBJECTS) unittest_libcephfs_config_DEPENDENCIES = $(LIBCEPHFS) \ $(am__DEPENDENCIES_13) unittest_libcephfs_config_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_libcephfs_config_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_librados_OBJECTS = \ test/librados/unittest_librados-librados.$(OBJEXT) unittest_librados_OBJECTS = $(am_unittest_librados_OBJECTS) unittest_librados_DEPENDENCIES = $(LIBRADOS) $(am__DEPENDENCIES_13) unittest_librados_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_librados_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_librados_config_OBJECTS = test/librados/unittest_librados_config-librados_config.$(OBJEXT) unittest_librados_config_OBJECTS = \ $(am_unittest_librados_config_OBJECTS) unittest_librados_config_DEPENDENCIES = $(LIBRADOS) \ $(am__DEPENDENCIES_13) unittest_librados_config_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_librados_config_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_log_OBJECTS = log/unittest_log-test.$(OBJEXT) unittest_log_OBJECTS = $(am_unittest_log_OBJECTS) unittest_log_DEPENDENCIES = $(LIBCOMMON) $(am__DEPENDENCIES_13) unittest_log_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(unittest_log_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_mime_OBJECTS = test/unittest_mime-mime.$(OBJEXT) unittest_mime_OBJECTS = $(am_unittest_mime_OBJECTS) unittest_mime_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_mime_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_mime_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ am_unittest_mon_moncap_OBJECTS = \ test/mon/unittest_mon_moncap-moncap.$(OBJEXT) unittest_mon_moncap_OBJECTS = $(am_unittest_mon_moncap_OBJECTS) unittest_mon_moncap_DEPENDENCIES = $(am__DEPENDENCIES_9) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_mon_moncap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_mon_moncap_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_mon_pgmap_OBJECTS = \ test/mon/unittest_mon_pgmap-PGMap.$(OBJEXT) unittest_mon_pgmap_OBJECTS = $(am_unittest_mon_pgmap_OBJECTS) unittest_mon_pgmap_DEPENDENCIES = $(am__DEPENDENCIES_9) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_mon_pgmap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_mon_pgmap_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_on_exit_OBJECTS = test/on_exit.$(OBJEXT) unittest_on_exit_OBJECTS = $(am_unittest_on_exit_OBJECTS) unittest_on_exit_DEPENDENCIES = $(am__DEPENDENCIES_1) am_unittest_osd_osdcap_OBJECTS = \ test/osd/unittest_osd_osdcap-osdcap.$(OBJEXT) unittest_osd_osdcap_OBJECTS = $(am_unittest_osd_osdcap_OBJECTS) unittest_osd_osdcap_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) unittest_osd_osdcap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_osd_osdcap_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_osd_types_OBJECTS = \ test/osd/unittest_osd_types-types.$(OBJEXT) unittest_osd_types_OBJECTS = $(am_unittest_osd_types_OBJECTS) unittest_osd_types_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_osd_types_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_osd_types_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_osdmap_OBJECTS = \ test/osd/unittest_osdmap-TestOSDMap.$(OBJEXT) unittest_osdmap_OBJECTS = $(am_unittest_osdmap_OBJECTS) unittest_osdmap_DEPENDENCIES = $(am__DEPENDENCIES_13) $(LIBCOMMON) \ $(am__DEPENDENCIES_6) unittest_osdmap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_osdmap_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_perf_counters_OBJECTS = \ test/unittest_perf_counters-perf_counters.$(OBJEXT) unittest_perf_counters_OBJECTS = $(am_unittest_perf_counters_OBJECTS) unittest_perf_counters_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_perf_counters_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_perf_counters_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_pglog_OBJECTS = \ test/osd/unittest_pglog-TestPGLog.$(OBJEXT) unittest_pglog_OBJECTS = $(am_unittest_pglog_OBJECTS) unittest_pglog_DEPENDENCIES = $(am__DEPENDENCIES_10) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_6) \ $(am__DEPENDENCIES_1) unittest_pglog_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_pglog_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_prebufferedstreambuf_OBJECTS = test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.$(OBJEXT) unittest_prebufferedstreambuf_OBJECTS = \ $(am_unittest_prebufferedstreambuf_OBJECTS) unittest_prebufferedstreambuf_DEPENDENCIES = $(LIBCOMMON) \ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_2) unittest_prebufferedstreambuf_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_prebufferedstreambuf_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_run_cmd_OBJECTS = test/unittest_run_cmd-run_cmd.$(OBJEXT) unittest_run_cmd_OBJECTS = $(am_unittest_run_cmd_OBJECTS) unittest_run_cmd_DEPENDENCIES = $(LIBCEPHFS) $(am__DEPENDENCIES_13) unittest_run_cmd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_run_cmd_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_sharedptr_registry_OBJECTS = test/common/unittest_sharedptr_registry-test_sharedptr_registry.$(OBJEXT) unittest_sharedptr_registry_OBJECTS = \ $(am_unittest_sharedptr_registry_OBJECTS) unittest_sharedptr_registry_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_sharedptr_registry_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_sharedptr_registry_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_unittest_signals_OBJECTS = test/unittest_signals-signals.$(OBJEXT) unittest_signals_OBJECTS = $(am_unittest_signals_OBJECTS) unittest_signals_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_signals_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_signals_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_simple_spin_OBJECTS = \ test/unittest_simple_spin-simple_spin.$(OBJEXT) unittest_simple_spin_OBJECTS = $(am_unittest_simple_spin_OBJECTS) unittest_simple_spin_DEPENDENCIES = $(LIBCEPHFS) \ $(am__DEPENDENCIES_13) unittest_simple_spin_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_simple_spin_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_sloppy_crc_map_OBJECTS = test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.$(OBJEXT) unittest_sloppy_crc_map_OBJECTS = \ $(am_unittest_sloppy_crc_map_OBJECTS) unittest_sloppy_crc_map_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_sloppy_crc_map_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_sloppy_crc_map_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_str_list_OBJECTS = \ test/unittest_str_list-test_str_list.$(OBJEXT) unittest_str_list_OBJECTS = $(am_unittest_str_list_OBJECTS) unittest_str_list_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_str_list_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_str_list_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_str_map_OBJECTS = \ test/common/unittest_str_map-test_str_map.$(OBJEXT) unittest_str_map_OBJECTS = $(am_unittest_str_map_OBJECTS) unittest_str_map_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_str_map_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_str_map_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_striper_OBJECTS = \ test/unittest_striper-test_striper.$(OBJEXT) unittest_striper_OBJECTS = $(am_unittest_striper_OBJECTS) unittest_striper_DEPENDENCIES = $(LIBOSDC) $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_striper_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_striper_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_strtol_OBJECTS = test/unittest_strtol-strtol.$(OBJEXT) unittest_strtol_OBJECTS = $(am_unittest_strtol_OBJECTS) unittest_strtol_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_strtol_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_strtol_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_texttable_OBJECTS = \ test/unittest_texttable-test_texttable.$(OBJEXT) unittest_texttable_OBJECTS = $(am_unittest_texttable_OBJECTS) unittest_texttable_DEPENDENCIES = $(LIBCOMMON) $(am__DEPENDENCIES_13) unittest_texttable_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_texttable_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_throttle_OBJECTS = \ test/common/unittest_throttle-Throttle.$(OBJEXT) unittest_throttle_OBJECTS = $(am_unittest_throttle_OBJECTS) unittest_throttle_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_throttle_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_throttle_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_unittest_utf8_OBJECTS = test/unittest_utf8-utf8.$(OBJEXT) unittest_utf8_OBJECTS = $(am_unittest_utf8_OBJECTS) unittest_utf8_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_utf8_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_utf8_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ am_unittest_util_OBJECTS = \ test/common/unittest_util-test_util.$(OBJEXT) unittest_util_OBJECTS = $(am_unittest_util_OBJECTS) unittest_util_DEPENDENCIES = $(LIBCOMMON) $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) unittest_util_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_util_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ am_unittest_workqueue_OBJECTS = \ test/unittest_workqueue-test_workqueue.$(OBJEXT) unittest_workqueue_OBJECTS = $(am_unittest_workqueue_OBJECTS) unittest_workqueue_DEPENDENCIES = $(am__DEPENDENCIES_13) \ $(am__DEPENDENCIES_6) unittest_workqueue_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(unittest_workqueue_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SCRIPTS = $(bin_SCRIPTS) $(ceph_sbin_SCRIPTS) $(dist_bin_SCRIPTS) \ $(sbin_SCRIPTS) $(shell_common_SCRIPTS) $(su_sbin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) LTCPPASCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CCASFLAGS) $(CCASFLAGS) AM_V_CPPAS = $(am__v_CPPAS_@AM_V@) am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@) am__v_CPPAS_0 = @echo " CPPAS " $@; am__v_CPPAS_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libcls_log_client_a_SOURCES) \ $(libcls_replica_log_client_a_SOURCES) \ $(libcls_statelog_client_a_SOURCES) \ $(libcls_user_client_a_SOURCES) \ $(libcls_version_client_a_SOURCES) $(libos_zfs_a_SOURCES) \ $(libarch_la_SOURCES) $(libauth_la_SOURCES) \ $(libcephfs_la_SOURCES) $(libcephfs_jni_la_SOURCES) \ $(libcivetweb_la_SOURCES) $(libclient_la_SOURCES) \ $(libclient_fuse_la_SOURCES) $(libcls_hello_la_SOURCES) \ $(libcls_kvs_la_SOURCES) $(libcls_lock_la_SOURCES) \ $(libcls_lock_client_la_SOURCES) $(libcls_log_la_SOURCES) \ $(libcls_rbd_la_SOURCES) $(libcls_rbd_client_la_SOURCES) \ $(libcls_refcount_la_SOURCES) \ $(libcls_refcount_client_la_SOURCES) \ $(libcls_replica_log_la_SOURCES) $(libcls_rgw_la_SOURCES) \ $(libcls_rgw_client_la_SOURCES) $(libcls_statelog_la_SOURCES) \ $(libcls_user_la_SOURCES) $(libcls_version_la_SOURCES) \ $(libcommon_la_SOURCES) $(libcommon_crc_la_SOURCES) \ $(libcrush_la_SOURCES) $(libec_example_la_SOURCES) \ $(libec_fail_to_initialize_la_SOURCES) \ $(libec_fail_to_register_la_SOURCES) $(libec_hangs_la_SOURCES) \ $(libec_jerasure_la_SOURCES) \ $(libec_jerasure_generic_la_SOURCES) \ $(libec_jerasure_sse3_la_SOURCES) \ $(libec_jerasure_sse4_la_SOURCES) \ $(libec_missing_entry_point_la_SOURCES) \ $(libec_test_jerasure_generic_la_SOURCES) \ $(libec_test_jerasure_sse3_la_SOURCES) \ $(libec_test_jerasure_sse4_la_SOURCES) \ $(liberasure_code_la_SOURCES) $(libglobal_la_SOURCES) \ $(libjson_spirit_la_SOURCES) $(liblog_la_SOURCES) \ $(libmds_la_SOURCES) $(libmon_la_SOURCES) \ $(libmon_types_la_SOURCES) $(libmsg_la_SOURCES) \ $(libos_la_SOURCES) $(libos_types_la_SOURCES) \ $(libosd_la_SOURCES) $(libosd_types_la_SOURCES) \ $(libosdc_la_SOURCES) $(libperfglue_la_SOURCES) \ $(librados_la_SOURCES) $(libradostest_la_SOURCES) \ $(librbd_la_SOURCES) $(librgw_la_SOURCES) \ $(libsystest_la_SOURCES) $(ceph_authtool_SOURCES) \ $(ceph_client_debug_SOURCES) $(ceph_conf_SOURCES) \ $(ceph_dencoder_SOURCES) $(ceph_fuse_SOURCES) \ $(ceph_kvstore_tool_SOURCES) $(ceph_mds_SOURCES) \ $(ceph_mon_SOURCES) $(ceph_monstore_tool_SOURCES) \ $(ceph_objectstore_tool_SOURCES) $(ceph_osd_SOURCES) \ $(ceph_osdomap_tool_SOURCES) $(ceph_syn_SOURCES) \ $(ceph_bench_log_SOURCES) $(ceph_dupstore_SOURCES) \ $(ceph_erasure_code_SOURCES) \ $(ceph_erasure_code_benchmark_SOURCES) \ $(ceph_erasure_code_non_regression_SOURCES) \ $(ceph_kvstorebench_SOURCES) \ $(ceph_mon_store_converter_SOURCES) \ $(ceph_multi_stress_watch_SOURCES) $(ceph_omapbench_SOURCES) \ $(ceph_psim_SOURCES) $(ceph_radosacl_SOURCES) \ $(ceph_rgw_jsonparser_SOURCES) $(ceph_rgw_multiparser_SOURCES) \ $(ceph_scratchtool_SOURCES) $(ceph_scratchtoolpp_SOURCES) \ $(ceph_smalliobench_SOURCES) $(ceph_smalliobenchdumb_SOURCES) \ $(ceph_smalliobenchfs_SOURCES) $(ceph_smalliobenchrbd_SOURCES) \ $(ceph_streamtest_SOURCES) $(ceph_test_c_headers_SOURCES) \ $(ceph_test_cfuse_cache_invalidate_SOURCES) \ $(ceph_test_cls_hello_SOURCES) $(ceph_test_cls_lock_SOURCES) \ $(ceph_test_cls_log_SOURCES) $(ceph_test_cls_rbd_SOURCES) \ $(ceph_test_cls_refcount_SOURCES) \ $(ceph_test_cls_replica_log_SOURCES) \ $(ceph_test_cls_rgw_SOURCES) $(ceph_test_cls_rgw_log_SOURCES) \ $(ceph_test_cls_rgw_meta_SOURCES) \ $(ceph_test_cls_rgw_opstate_SOURCES) \ $(ceph_test_cls_statelog_SOURCES) \ $(ceph_test_cls_version_SOURCES) $(ceph_test_cors_SOURCES) \ $(ceph_test_crypto_SOURCES) $(ceph_test_filejournal_SOURCES) \ $(ceph_test_filestore_idempotent_SOURCES) \ $(ceph_test_filestore_idempotent_sequence_SOURCES) \ $(ceph_test_get_blkdev_size_SOURCES) \ $(ceph_test_ioctls_SOURCES) $(ceph_test_keys_SOURCES) \ $(ceph_test_keyvaluedb_atomicity_SOURCES) \ $(ceph_test_keyvaluedb_iterators_SOURCES) \ $(ceph_test_libcephfs_SOURCES) $(ceph_test_librbd_SOURCES) \ $(ceph_test_librbd_fsx_SOURCES) \ $(ceph_test_mon_workloadgen_SOURCES) $(ceph_test_msgr_SOURCES) \ $(ceph_test_mutate_SOURCES) $(ceph_test_object_map_SOURCES) \ $(ceph_test_objectcacher_stress_SOURCES) \ $(ceph_test_objectstore_SOURCES) \ $(ceph_test_objectstore_workloadgen_SOURCES) \ $(ceph_test_rados_SOURCES) $(ceph_test_rados_api_aio_SOURCES) \ $(ceph_test_rados_api_c_read_operations_SOURCES) \ $(ceph_test_rados_api_c_write_operations_SOURCES) \ $(ceph_test_rados_api_cls_SOURCES) \ $(ceph_test_rados_api_cmd_SOURCES) \ $(ceph_test_rados_api_io_SOURCES) \ $(ceph_test_rados_api_list_SOURCES) \ $(ceph_test_rados_api_lock_SOURCES) \ $(ceph_test_rados_api_misc_SOURCES) \ $(ceph_test_rados_api_pool_SOURCES) \ $(ceph_test_rados_api_snapshots_SOURCES) \ $(ceph_test_rados_api_stat_SOURCES) \ $(ceph_test_rados_api_tier_SOURCES) \ $(ceph_test_rados_api_watch_notify_SOURCES) \ $(ceph_test_rados_delete_pools_parallel_SOURCES) \ $(ceph_test_rados_list_parallel_SOURCES) \ $(ceph_test_rados_open_pools_parallel_SOURCES) \ $(ceph_test_rados_watch_notify_SOURCES) \ $(ceph_test_rewrite_latency_SOURCES) \ $(ceph_test_rgw_manifest_SOURCES) \ $(ceph_test_signal_handlers_SOURCES) \ $(ceph_test_snap_mapper_SOURCES) \ $(ceph_test_stress_watch_SOURCES) $(ceph_test_timers_SOURCES) \ $(ceph_test_trans_SOURCES) $(ceph_tpbench_SOURCES) \ $(ceph_xattr_bench_SOURCES) $(cephfs_SOURCES) \ $(crushtool_SOURCES) $(get_command_descriptions_SOURCES) \ $(librados_config_SOURCES) $(monmaptool_SOURCES) \ $(mount_ceph_SOURCES) $(osdmaptool_SOURCES) $(rados_SOURCES) \ $(radosgw_SOURCES) $(radosgw_admin_SOURCES) $(rbd_SOURCES) \ $(rbd_fuse_SOURCES) $(rest_bench_SOURCES) \ $(test_build_libcephfs_SOURCES) \ $(test_build_libcommon_SOURCES) $(test_build_librados_SOURCES) \ $(test_build_librgw_SOURCES) $(unittest_addrs_SOURCES) \ $(unittest_admin_socket_SOURCES) $(unittest_arch_SOURCES) \ $(unittest_base64_SOURCES) $(unittest_bloom_filter_SOURCES) \ $(unittest_bufferlist_SOURCES) \ $(unittest_ceph_argparse_SOURCES) \ $(unittest_ceph_compatset_SOURCES) \ $(unittest_ceph_crypto_SOURCES) \ $(unittest_chain_xattr_SOURCES) $(unittest_config_SOURCES) \ $(unittest_confutils_SOURCES) $(unittest_context_SOURCES) \ $(unittest_crc32c_SOURCES) $(unittest_crush_indep_SOURCES) \ $(unittest_crush_wrapper_SOURCES) $(unittest_crypto_SOURCES) \ $(unittest_crypto_init_SOURCES) \ $(unittest_daemon_config_SOURCES) \ $(unittest_ecbackend_SOURCES) $(unittest_encoding_SOURCES) \ $(unittest_erasure_code_example_SOURCES) \ $(unittest_erasure_code_jerasure_SOURCES) \ $(unittest_erasure_code_plugin_SOURCES) \ $(unittest_erasure_code_plugin_jerasure_SOURCES) \ $(unittest_escape_SOURCES) $(unittest_flatindex_SOURCES) \ $(unittest_formatter_SOURCES) $(unittest_gather_SOURCES) \ $(unittest_heartbeatmap_SOURCES) $(unittest_histogram_SOURCES) \ $(unittest_hitset_SOURCES) $(unittest_io_priority_SOURCES) \ $(unittest_ipaddr_SOURCES) $(unittest_lfnindex_SOURCES) \ $(unittest_libcephfs_config_SOURCES) \ $(unittest_librados_SOURCES) \ $(unittest_librados_config_SOURCES) $(unittest_log_SOURCES) \ $(unittest_mime_SOURCES) $(unittest_mon_moncap_SOURCES) \ $(unittest_mon_pgmap_SOURCES) $(unittest_on_exit_SOURCES) \ $(unittest_osd_osdcap_SOURCES) $(unittest_osd_types_SOURCES) \ $(unittest_osdmap_SOURCES) $(unittest_perf_counters_SOURCES) \ $(unittest_pglog_SOURCES) \ $(unittest_prebufferedstreambuf_SOURCES) \ $(unittest_run_cmd_SOURCES) \ $(unittest_sharedptr_registry_SOURCES) \ $(unittest_signals_SOURCES) $(unittest_simple_spin_SOURCES) \ $(unittest_sloppy_crc_map_SOURCES) \ $(unittest_str_list_SOURCES) $(unittest_str_map_SOURCES) \ $(unittest_striper_SOURCES) $(unittest_strtol_SOURCES) \ $(unittest_texttable_SOURCES) $(unittest_throttle_SOURCES) \ $(unittest_utf8_SOURCES) $(unittest_util_SOURCES) \ $(unittest_workqueue_SOURCES) DIST_SOURCES = $(libcls_log_client_a_SOURCES) \ $(libcls_replica_log_client_a_SOURCES) \ $(libcls_statelog_client_a_SOURCES) \ $(libcls_user_client_a_SOURCES) \ $(libcls_version_client_a_SOURCES) \ $(am__libos_zfs_a_SOURCES_DIST) $(libarch_la_SOURCES) \ $(libauth_la_SOURCES) $(libcephfs_la_SOURCES) \ $(am__libcephfs_jni_la_SOURCES_DIST) \ $(am__libcivetweb_la_SOURCES_DIST) $(libclient_la_SOURCES) \ $(am__libclient_fuse_la_SOURCES_DIST) \ $(libcls_hello_la_SOURCES) $(am__libcls_kvs_la_SOURCES_DIST) \ $(libcls_lock_la_SOURCES) $(libcls_lock_client_la_SOURCES) \ $(libcls_log_la_SOURCES) $(libcls_rbd_la_SOURCES) \ $(libcls_rbd_client_la_SOURCES) $(libcls_refcount_la_SOURCES) \ $(libcls_refcount_client_la_SOURCES) \ $(libcls_replica_log_la_SOURCES) $(libcls_rgw_la_SOURCES) \ $(libcls_rgw_client_la_SOURCES) $(libcls_statelog_la_SOURCES) \ $(libcls_user_la_SOURCES) $(libcls_version_la_SOURCES) \ $(libcommon_la_SOURCES) $(am__libcommon_crc_la_SOURCES_DIST) \ $(libcrush_la_SOURCES) $(libec_example_la_SOURCES) \ $(libec_fail_to_initialize_la_SOURCES) \ $(libec_fail_to_register_la_SOURCES) $(libec_hangs_la_SOURCES) \ $(libec_jerasure_la_SOURCES) \ $(libec_jerasure_generic_la_SOURCES) \ $(libec_jerasure_sse3_la_SOURCES) \ $(libec_jerasure_sse4_la_SOURCES) \ $(libec_missing_entry_point_la_SOURCES) \ $(libec_test_jerasure_generic_la_SOURCES) \ $(libec_test_jerasure_sse3_la_SOURCES) \ $(libec_test_jerasure_sse4_la_SOURCES) \ $(liberasure_code_la_SOURCES) $(libglobal_la_SOURCES) \ $(libjson_spirit_la_SOURCES) $(liblog_la_SOURCES) \ $(libmds_la_SOURCES) $(libmon_la_SOURCES) \ $(libmon_types_la_SOURCES) $(libmsg_la_SOURCES) \ $(am__libos_la_SOURCES_DIST) $(libos_types_la_SOURCES) \ $(libosd_la_SOURCES) $(libosd_types_la_SOURCES) \ $(libosdc_la_SOURCES) $(am__libperfglue_la_SOURCES_DIST) \ $(librados_la_SOURCES) $(libradostest_la_SOURCES) \ $(librbd_la_SOURCES) $(am__librgw_la_SOURCES_DIST) \ $(am__libsystest_la_SOURCES_DIST) $(ceph_authtool_SOURCES) \ $(ceph_client_debug_SOURCES) $(ceph_conf_SOURCES) \ $(am__ceph_dencoder_SOURCES_DIST) \ $(am__ceph_fuse_SOURCES_DIST) $(ceph_kvstore_tool_SOURCES) \ $(ceph_mds_SOURCES) $(ceph_mon_SOURCES) \ $(ceph_monstore_tool_SOURCES) $(ceph_objectstore_tool_SOURCES) \ $(ceph_osd_SOURCES) $(ceph_osdomap_tool_SOURCES) \ $(ceph_syn_SOURCES) $(ceph_bench_log_SOURCES) \ $(ceph_dupstore_SOURCES) $(ceph_erasure_code_SOURCES) \ $(ceph_erasure_code_benchmark_SOURCES) \ $(ceph_erasure_code_non_regression_SOURCES) \ $(am__ceph_kvstorebench_SOURCES_DIST) \ $(ceph_mon_store_converter_SOURCES) \ $(ceph_multi_stress_watch_SOURCES) $(ceph_omapbench_SOURCES) \ $(ceph_psim_SOURCES) $(ceph_radosacl_SOURCES) \ $(am__ceph_rgw_jsonparser_SOURCES_DIST) \ $(am__ceph_rgw_multiparser_SOURCES_DIST) \ $(ceph_scratchtool_SOURCES) $(ceph_scratchtoolpp_SOURCES) \ $(ceph_smalliobench_SOURCES) $(ceph_smalliobenchdumb_SOURCES) \ $(ceph_smalliobenchfs_SOURCES) $(ceph_smalliobenchrbd_SOURCES) \ $(ceph_streamtest_SOURCES) $(ceph_test_c_headers_SOURCES) \ $(ceph_test_cfuse_cache_invalidate_SOURCES) \ $(ceph_test_cls_hello_SOURCES) $(ceph_test_cls_lock_SOURCES) \ $(ceph_test_cls_log_SOURCES) $(ceph_test_cls_rbd_SOURCES) \ $(ceph_test_cls_refcount_SOURCES) \ $(ceph_test_cls_replica_log_SOURCES) \ $(am__ceph_test_cls_rgw_SOURCES_DIST) \ $(am__ceph_test_cls_rgw_log_SOURCES_DIST) \ $(am__ceph_test_cls_rgw_meta_SOURCES_DIST) \ $(am__ceph_test_cls_rgw_opstate_SOURCES_DIST) \ $(ceph_test_cls_statelog_SOURCES) \ $(ceph_test_cls_version_SOURCES) \ $(am__ceph_test_cors_SOURCES_DIST) $(ceph_test_crypto_SOURCES) \ $(ceph_test_filejournal_SOURCES) \ $(ceph_test_filestore_idempotent_SOURCES) \ $(ceph_test_filestore_idempotent_sequence_SOURCES) \ $(ceph_test_get_blkdev_size_SOURCES) \ $(ceph_test_ioctls_SOURCES) $(ceph_test_keys_SOURCES) \ $(ceph_test_keyvaluedb_atomicity_SOURCES) \ $(ceph_test_keyvaluedb_iterators_SOURCES) \ $(ceph_test_libcephfs_SOURCES) $(ceph_test_librbd_SOURCES) \ $(am__ceph_test_librbd_fsx_SOURCES_DIST) \ $(ceph_test_mon_workloadgen_SOURCES) $(ceph_test_msgr_SOURCES) \ $(ceph_test_mutate_SOURCES) $(ceph_test_object_map_SOURCES) \ $(ceph_test_objectcacher_stress_SOURCES) \ $(am__ceph_test_objectstore_SOURCES_DIST) \ $(ceph_test_objectstore_workloadgen_SOURCES) \ $(ceph_test_rados_SOURCES) $(ceph_test_rados_api_aio_SOURCES) \ $(ceph_test_rados_api_c_read_operations_SOURCES) \ $(ceph_test_rados_api_c_write_operations_SOURCES) \ $(ceph_test_rados_api_cls_SOURCES) \ $(ceph_test_rados_api_cmd_SOURCES) \ $(ceph_test_rados_api_io_SOURCES) \ $(ceph_test_rados_api_list_SOURCES) \ $(ceph_test_rados_api_lock_SOURCES) \ $(ceph_test_rados_api_misc_SOURCES) \ $(ceph_test_rados_api_pool_SOURCES) \ $(ceph_test_rados_api_snapshots_SOURCES) \ $(ceph_test_rados_api_stat_SOURCES) \ $(ceph_test_rados_api_tier_SOURCES) \ $(ceph_test_rados_api_watch_notify_SOURCES) \ $(am__ceph_test_rados_delete_pools_parallel_SOURCES_DIST) \ $(am__ceph_test_rados_list_parallel_SOURCES_DIST) \ $(am__ceph_test_rados_open_pools_parallel_SOURCES_DIST) \ $(am__ceph_test_rados_watch_notify_SOURCES_DIST) \ $(ceph_test_rewrite_latency_SOURCES) \ $(am__ceph_test_rgw_manifest_SOURCES_DIST) \ $(ceph_test_signal_handlers_SOURCES) \ $(ceph_test_snap_mapper_SOURCES) \ $(ceph_test_stress_watch_SOURCES) $(ceph_test_timers_SOURCES) \ $(ceph_test_trans_SOURCES) $(ceph_tpbench_SOURCES) \ $(ceph_xattr_bench_SOURCES) $(cephfs_SOURCES) \ $(crushtool_SOURCES) $(get_command_descriptions_SOURCES) \ $(librados_config_SOURCES) $(monmaptool_SOURCES) \ $(mount_ceph_SOURCES) $(osdmaptool_SOURCES) $(rados_SOURCES) \ $(am__radosgw_SOURCES_DIST) $(am__radosgw_admin_SOURCES_DIST) \ $(rbd_SOURCES) $(am__rbd_fuse_SOURCES_DIST) \ $(am__rest_bench_SOURCES_DIST) \ $(am__test_build_libcephfs_SOURCES_DIST) \ $(am__test_build_libcommon_SOURCES_DIST) \ $(am__test_build_librados_SOURCES_DIST) \ $(am__test_build_librgw_SOURCES_DIST) \ $(unittest_addrs_SOURCES) $(unittest_admin_socket_SOURCES) \ $(unittest_arch_SOURCES) $(unittest_base64_SOURCES) \ $(unittest_bloom_filter_SOURCES) \ $(unittest_bufferlist_SOURCES) \ $(unittest_ceph_argparse_SOURCES) \ $(unittest_ceph_compatset_SOURCES) \ $(unittest_ceph_crypto_SOURCES) \ $(unittest_chain_xattr_SOURCES) $(unittest_config_SOURCES) \ $(unittest_confutils_SOURCES) $(unittest_context_SOURCES) \ $(unittest_crc32c_SOURCES) $(unittest_crush_indep_SOURCES) \ $(unittest_crush_wrapper_SOURCES) $(unittest_crypto_SOURCES) \ $(unittest_crypto_init_SOURCES) \ $(unittest_daemon_config_SOURCES) \ $(unittest_ecbackend_SOURCES) $(unittest_encoding_SOURCES) \ $(unittest_erasure_code_example_SOURCES) \ $(unittest_erasure_code_jerasure_SOURCES) \ $(unittest_erasure_code_plugin_SOURCES) \ $(unittest_erasure_code_plugin_jerasure_SOURCES) \ $(unittest_escape_SOURCES) $(unittest_flatindex_SOURCES) \ $(unittest_formatter_SOURCES) $(unittest_gather_SOURCES) \ $(unittest_heartbeatmap_SOURCES) $(unittest_histogram_SOURCES) \ $(unittest_hitset_SOURCES) $(unittest_io_priority_SOURCES) \ $(unittest_ipaddr_SOURCES) $(unittest_lfnindex_SOURCES) \ $(unittest_libcephfs_config_SOURCES) \ $(unittest_librados_SOURCES) \ $(unittest_librados_config_SOURCES) $(unittest_log_SOURCES) \ $(unittest_mime_SOURCES) $(unittest_mon_moncap_SOURCES) \ $(unittest_mon_pgmap_SOURCES) $(unittest_on_exit_SOURCES) \ $(unittest_osd_osdcap_SOURCES) $(unittest_osd_types_SOURCES) \ $(unittest_osdmap_SOURCES) $(unittest_perf_counters_SOURCES) \ $(unittest_pglog_SOURCES) \ $(unittest_prebufferedstreambuf_SOURCES) \ $(unittest_run_cmd_SOURCES) \ $(unittest_sharedptr_registry_SOURCES) \ $(unittest_signals_SOURCES) $(unittest_simple_spin_SOURCES) \ $(unittest_sloppy_crc_map_SOURCES) \ $(unittest_str_list_SOURCES) $(unittest_str_map_SOURCES) \ $(unittest_striper_SOURCES) $(unittest_strtol_SOURCES) \ $(unittest_texttable_SOURCES) $(unittest_throttle_SOURCES) \ $(unittest_utf8_SOURCES) $(unittest_util_SOURCES) \ $(unittest_workqueue_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile) am__pep3147_tweak = \ sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|' py_compile = $(top_srcdir)/py-compile DATA = $(bash_completion_DATA) $(doc_DATA) $(libcephfs_include_DATA) \ $(librbd_include_DATA) $(rados_include_DATA) am__noinst_HEADERS_DIST = arch/intel.h arch/neon.h arch/probe.h \ auth/cephx/CephxAuthorizeHandler.h auth/cephx/CephxKeyServer.h \ auth/cephx/CephxProtocol.h auth/cephx/CephxClientHandler.h \ auth/cephx/CephxServiceHandler.h \ auth/cephx/CephxSessionHandler.h \ auth/none/AuthNoneAuthorizeHandler.h \ auth/none/AuthNoneClientHandler.h \ auth/none/AuthNoneServiceHandler.h \ auth/none/AuthNoneSessionHandler.h \ auth/none/AuthNoneProtocol.h \ auth/unknown/AuthUnknownAuthorizeHandler.h \ auth/unknown/AuthUnknownClientHandler.h \ auth/unknown/AuthUnknownServiceHandler.h \ auth/unknown/AuthUnknownSessionHandler.h \ auth/unknown/AuthUnknownProtocol.h auth/Auth.h \ auth/AuthMethodList.h auth/AuthClientHandler.h \ auth/AuthServiceHandler.h auth/AuthSessionHandler.h \ auth/AuthAuthorizeHandler.h auth/KeyRing.h \ auth/RotatingKeyRing.h auth/Crypto.h crush/CrushCompiler.h \ crush/CrushTester.h crush/CrushWrapper.h crush/CrushWrapper.i \ crush/builder.h crush/crush.h crush/grammar.h crush/hash.h \ crush/mapper.h crush/sample.txt crush/types.h \ mon/AuthMonitor.h mon/DataHealthService.h mon/Elector.h \ mon/LogMonitor.h mon/ConfigKeyService.h mon/HealthMonitor.h \ mon/HealthService.h mon/MDSMonitor.h mon/MonmapMonitor.h \ mon/MonCap.h mon/MonClient.h mon/MonCommands.h \ mon/DumplingMonCommands.h mon/MonMap.h mon/Monitor.h \ mon/MonitorStore.h mon/MonitorDBStore.h mon/OSDMonitor.h \ mon/PGMap.h mon/PGMonitor.h mon/Paxos.h mon/PaxosService.h \ mon/QuorumService.h mon/Session.h mon/mon_types.h \ mds/inode_backtrace.h mds/flock.h mds/locks.c mds/locks.h \ mds/Anchor.h mds/AnchorClient.h mds/AnchorServer.h \ mds/CDentry.h mds/CDir.h mds/CInode.h mds/Capability.h \ mds/Dumper.h mds/InoTable.h mds/LocalLock.h mds/Locker.h \ mds/LogEvent.h mds/LogSegment.h mds/MDBalancer.h mds/MDCache.h \ mds/MDLog.h mds/MDS.h mds/MDSMap.h mds/MDSTable.h \ mds/MDSTableServer.h mds/MDSTableClient.h mds/MDSUtility.h \ mds/Mutation.h mds/Migrator.h mds/Resetter.h mds/ScatterLock.h \ mds/Server.h mds/SessionMap.h mds/SimpleLock.h \ mds/SnapClient.h mds/SnapRealm.h mds/SnapServer.h \ mds/mds_table_types.h mds/mdstypes.h mds/snap.h \ mds/events/ECommitted.h mds/events/EExport.h \ mds/events/EFragment.h mds/events/EImportFinish.h \ mds/events/EImportStart.h mds/events/EMetaBlob.h \ mds/events/EOpen.h mds/events/EResetJournal.h \ mds/events/ESession.h mds/events/ESessions.h \ mds/events/ESlaveUpdate.h mds/events/ESubtreeMap.h \ mds/events/ETableClient.h mds/events/ETableServer.h \ mds/events/EUpdate.h os/btrfs_ioctl.h os/chain_xattr.h \ os/BtrfsFileStoreBackend.h os/CollectionIndex.h \ os/DBObjectMap.h os/GenericObjectMap.h os/FileJournal.h \ os/FileStore.h os/FlatIndex.h os/FDCache.h \ os/GenericFileStoreBackend.h os/HashIndex.h os/IndexManager.h \ os/Journal.h os/JournalingObjectStore.h os/KeyValueDB.h \ os/LevelDBStore.h os/LFNIndex.h os/MemStore.h \ os/KeyValueStore.h os/ObjectMap.h os/ObjectStore.h \ os/SequencerPosition.h os/WBThrottle.h \ os/XfsFileStoreBackend.h os/ZFSFileStoreBackend.h os/ZFS.h \ osd/Ager.h osd/ClassHandler.h osd/HitSet.h osd/OSD.h \ osd/OSDCap.h osd/OSDMap.h osd/ObjectVersioner.h \ osd/OpRequest.h osd/SnapMapper.h osd/PG.h osd/PGLog.h \ osd/ReplicatedPG.h osd/PGBackend.h osd/ReplicatedBackend.h \ osd/TierAgentState.h osd/ECBackend.h osd/ECUtil.h \ osd/ECMsgTypes.h osd/ECTransaction.h osd/Watch.h \ osd/osd_types.h \ erasure-code/jerasure/jerasure/include/cauchy.h \ erasure-code/jerasure/jerasure/include/galois.h \ erasure-code/jerasure/jerasure/include/jerasure.h \ erasure-code/jerasure/jerasure/include/liberation.h \ erasure-code/jerasure/jerasure/include/reed_sol.h \ erasure-code/jerasure/gf-complete/include/gf_int.h \ erasure-code/jerasure/gf-complete/include/gf_complete.h \ erasure-code/jerasure/gf-complete/include/gf_rand.h \ erasure-code/jerasure/gf-complete/include/gf_method.h \ erasure-code/jerasure/gf-complete/include/gf_general.h \ erasure-code/jerasure/ErasureCodeJerasure.h \ erasure-code/ErasureCodeInterface.h \ erasure-code/ErasureCodePlugin.h osdc/Blinker.h osdc/Filer.h \ osdc/Journaler.h osdc/ObjectCacher.h osdc/Objecter.h \ osdc/Striper.h osdc/WritebackHandler.h client/Client.h \ client/Dentry.h client/Dir.h client/Fh.h client/Inode.h \ client/MetaRequest.h client/MetaSession.h \ client/ClientSnapRealm.h client/SyntheticClient.h \ client/Trace.h client/ioctl.h client/ObjecterWriteback.h \ client/fuse_ll.h global/pidfile.h global/global_init.h \ global/global_context.h global/signal_handler.h \ json_spirit/json_spirit.h \ json_spirit/json_spirit_error_position.h \ json_spirit/json_spirit_reader.h \ json_spirit/json_spirit_reader_template.h \ json_spirit/json_spirit_stream_reader.h \ json_spirit/json_spirit_utils.h \ json_spirit/json_spirit_value.h \ json_spirit/json_spirit_writer.h \ json_spirit/json_spirit_writer_options.h \ json_spirit/json_spirit_writer_template.h log/Entry.h \ log/EntryQueue.h log/Log.h log/SubsystemMap.h \ perfglue/cpu_profiler.h perfglue/heap_profiler.h \ common/bloom_filter.hpp common/sctp_crc32.h \ common/crc32c_intel_baseline.h common/crc32c_intel_fast.h \ common/BackTrace.h common/RefCountedObj.h \ common/HeartbeatMap.h common/LogClient.h common/LogEntry.h \ common/Preforker.h common/SloppyCRCMap.h common/WorkQueue.h \ common/PrioritizedQueue.h common/ceph_argparse.h \ common/ceph_context.h common/xattr.h common/blkdev.h \ common/compiler_extensions.h common/debug.h common/dout.h \ common/escape.h common/fd.h common/version.h common/hex.h \ common/histogram.h common/entity_name.h common/errno.h \ common/environment.h common/likely.h common/lockdep.h \ common/obj_bencher.h common/snap_types.h common/Clock.h \ common/Cond.h common/ConfUtils.h common/DecayCounter.h \ common/Finisher.h common/Formatter.h common/perf_counters.h \ common/OutputDataSocket.h common/admin_socket.h \ common/admin_socket_client.h common/random_cache.hpp \ common/shared_cache.hpp common/tracked_int_ptr.hpp \ common/simple_cache.hpp common/sharedptr_registry.hpp \ common/map_cacher.hpp common/MemoryModel.h common/Mutex.h \ common/PrebufferedStreambuf.h common/RWLock.h \ common/Semaphore.h common/SimpleRNG.h common/TextTable.h \ common/Thread.h common/Throttle.h common/Timer.h \ common/TrackedOp.h common/arch.h common/armor.h \ common/common_init.h common/io_priority.h common/pipe.h \ common/code_environment.h common/signal.h common/simple_spin.h \ common/run_cmd.h common/safe_io.h common/config.h \ common/config_obs.h common/config_opts.h common/ceph_crypto.h \ common/ceph_crypto_cms.h common/ceph_json.h common/lru_map.h \ common/utf8.h common/mime.h common/pick_address.h \ common/secret.h common/strtol.h common/static_assert.h \ common/AsyncReserver.h common/sync_filesystem.h \ common/cmdparse.h common/hobject.h common/linux_version.h \ msg/Accepter.h msg/DispatchQueue.h msg/Dispatcher.h \ msg/Message.h msg/Messenger.h msg/Pipe.h msg/SimpleMessenger.h \ msg/msg_types.h messages/MAuth.h messages/MAuthReply.h \ messages/MCacheExpire.h messages/MClientCaps.h \ messages/MClientCapRelease.h messages/MClientLease.h \ messages/MClientReconnect.h messages/MClientReply.h \ messages/MClientRequest.h messages/MClientRequestForward.h \ messages/MClientSession.h messages/MClientSnap.h \ messages/MCommand.h messages/MCommandReply.h \ messages/MDentryLink.h messages/MDentryUnlink.h \ messages/MDirUpdate.h messages/MDiscover.h \ messages/MDiscoverReply.h messages/MExportCaps.h \ messages/MExportCapsAck.h messages/MExportDir.h \ messages/MExportDirAck.h messages/MExportDirCancel.h \ messages/MExportDirDiscover.h messages/MExportDirDiscoverAck.h \ messages/MExportDirFinish.h messages/MExportDirNotify.h \ messages/MExportDirNotifyAck.h messages/MExportDirPrep.h \ messages/MExportDirPrepAck.h messages/MGenericMessage.h \ messages/MGetPoolStats.h messages/MGetPoolStatsReply.h \ messages/MHeartbeat.h messages/MInodeFileCaps.h \ messages/MLock.h messages/MLog.h messages/MLogAck.h \ messages/MMDSBeacon.h messages/MMDSCacheRejoin.h \ messages/MMDSLoadTargets.h messages/MMDSFindIno.h \ messages/MMDSFindInoReply.h messages/MMDSFragmentNotify.h \ messages/MMDSMap.h messages/MMDSOpenIno.h \ messages/MMDSOpenInoReply.h messages/MMDSResolve.h \ messages/MMDSResolveAck.h messages/MMDSSlaveRequest.h \ messages/MMDSTableRequest.h messages/MMonCommand.h \ messages/MMonCommandAck.h messages/MMonElection.h \ messages/MMonGetMap.h messages/MMonGetVersion.h \ messages/MMonGetVersionReply.h messages/MMonGlobalID.h \ messages/MMonHealth.h messages/MMonJoin.h messages/MMonMap.h \ messages/MMonPaxos.h messages/MMonProbe.h messages/MMonScrub.h \ messages/MMonSubscribe.h messages/MMonSubscribeAck.h \ messages/MMonSync.h messages/MOSDAlive.h messages/MOSDBoot.h \ messages/MOSDFailure.h messages/MOSDMarkMeDown.h \ messages/MOSDMap.h messages/MOSDOp.h messages/MOSDOpReply.h \ messages/MOSDPGBackfill.h messages/MOSDPGCreate.h \ messages/MOSDPGPush.h messages/MOSDPGPull.h \ messages/MOSDPGPushReply.h messages/MOSDPGInfo.h \ messages/MOSDPGLog.h messages/MOSDPGMissing.h \ messages/MOSDPGNotify.h messages/MOSDPGQuery.h \ messages/MOSDPGRemove.h messages/MOSDPGScan.h \ messages/MOSDECSubOpWrite.h messages/MOSDECSubOpWriteReply.h \ messages/MOSDECSubOpRead.h messages/MOSDECSubOpReadReply.h \ messages/MBackfillReserve.h messages/MRecoveryReserve.h \ messages/MMonQuorumService.h messages/MOSDPGTemp.h \ messages/MOSDPGTrim.h messages/MOSDPing.h \ messages/MOSDRepScrub.h messages/MOSDScrub.h \ messages/MOSDSubOp.h messages/MOSDSubOpReply.h \ messages/MPGStats.h messages/MPGStatsAck.h messages/MPing.h \ messages/MPoolOp.h messages/MPoolOpReply.h \ messages/MRemoveSnaps.h messages/MRoute.h messages/MForward.h \ messages/MStatfs.h messages/MStatfsReply.h \ messages/MTimeCheck.h messages/MWatchNotify.h \ messages/PaxosServiceMessage.h include/Context.h \ include/CompatSet.h include/Distribution.h include/Spinlock.h \ include/addr_parsing.h include/assert.h include/atomic.h \ include/bitmapper.h include/blobhash.h include/buffer.h \ include/byteorder.h include/cephfs/libcephfs.h \ include/ceph_features.h include/ceph_frag.h include/ceph_fs.h \ include/ceph_hash.h include/cmp.h include/color.h \ include/compat.h include/crc32c.h include/encoding.h \ include/err.h include/error.h include/filepath.h \ include/frag.h include/hash.h include/intarith.h \ include/interval_set.h include/int_types.h include/ipaddr.h \ include/linux_fiemap.h include/lru.h include/msgr.h \ include/object.h include/page.h include/rangeset.h \ include/rados.h include/rbd_types.h include/statlite.h \ include/str_list.h include/str_map.h include/stringify.h \ include/triple.h include/types.h include/utime.h \ include/dlist.h include/elist.h include/uuid.h include/xlist.h \ include/rados/librados.h include/rados/rados_types.h \ include/rados/rados_types.hpp include/rados/librados.hpp \ include/rados/librgw.h include/rados/page.h \ include/rados/crc32c.h include/rados/buffer.h \ include/rbd/features.h include/rbd/librbd.h \ include/rbd/librbd.hpp include/util.h include/stat.h \ include/on_exit.h include/memory.h include/rados/memory.h \ include/hash_namespace.h include/unordered_set.h \ include/unordered_map.h librados/snap_set_diff.h \ librados/AioCompletionImpl.h librados/IoCtxImpl.h \ librados/PoolAsyncCompletionImpl.h librados/RadosClient.h \ librbd/AioCompletion.h librbd/AioRequest.h librbd/ImageCtx.h \ librbd/internal.h librbd/LibrbdWriteback.h \ librbd/parent_types.h librbd/SnapInfo.h librbd/WatchCtx.h \ rgw/logrotate.conf rgw/rgw_acl.h rgw/rgw_acl_s3.h \ rgw/rgw_acl_swift.h rgw/rgw_client_io.h rgw/rgw_fcgi.h \ rgw/rgw_xml.h rgw/rgw_cache.h rgw/rgw_common.h rgw/rgw_cors.h \ rgw/rgw_cors_s3.h rgw/rgw_cors_swift.h rgw/rgw_string.h \ rgw/rgw_formats.h rgw/rgw_http_errors.h rgw/rgw_log.h \ rgw/rgw_loadgen.h rgw/rgw_multi.h rgw/rgw_policy_s3.h \ rgw/rgw_gc.h rgw/rgw_metadata.h rgw/rgw_multi_del.h \ rgw/rgw_op.h rgw/rgw_http_client.h rgw/rgw_swift.h \ rgw/rgw_swift_auth.h rgw/rgw_quota.h rgw/rgw_rados.h \ rgw/rgw_replica_log.h rgw/rgw_resolve.h rgw/rgw_rest.h \ rgw/rgw_rest_swift.h rgw/rgw_rest_s3.h rgw/rgw_auth_s3.h \ rgw/rgw_rest_admin.h rgw/rgw_rest_usage.h rgw/rgw_rest_user.h \ rgw/rgw_rest_bucket.h rgw/rgw_rest_client.h \ rgw/rgw_rest_conn.h rgw/rgw_tools.h rgw/rgw_rest_metadata.h \ rgw/rgw_rest_log.h rgw/rgw_rest_opstate.h \ rgw/rgw_rest_replica_log.h rgw/rgw_rest_config.h \ rgw/rgw_usage.h rgw/rgw_user.h rgw/rgw_bucket.h \ rgw/rgw_keystone.h rgw/rgw_civetweb.h rgw/rgw_civetweb_log.h \ civetweb/civetweb.h civetweb/include/civetweb.h \ civetweb/include/civetweb_conf.h civetweb/src/md5.h \ cls/lock/cls_lock_types.h cls/lock/cls_lock_ops.h \ cls/lock/cls_lock_client.h cls/rbd/cls_rbd.h \ cls/rbd/cls_rbd_client.h cls/refcount/cls_refcount_ops.h \ cls/refcount/cls_refcount_client.h \ cls/version/cls_version_types.h cls/version/cls_version_ops.h \ cls/version/cls_version_client.h cls/log/cls_log_types.h \ cls/log/cls_log_ops.h cls/log/cls_log_client.h \ cls/statelog/cls_statelog_types.h \ cls/statelog/cls_statelog_ops.h \ cls/statelog/cls_statelog_client.h \ cls/replica_log/cls_replica_log_types.h \ cls/replica_log/cls_replica_log_ops.h \ cls/replica_log/cls_replica_log_client.h \ cls/rgw/cls_rgw_client.h cls/rgw/cls_rgw_ops.h \ cls/rgw/cls_rgw_types.h cls/user/cls_user_client.h \ cls/user/cls_user_ops.h cls/user/cls_user_types.h \ key_value_store/key_value_structure.h \ key_value_store/kv_flat_btree_async.h \ key_value_store/kvs_arg_types.h \ test/erasure-code/ErasureCodeExample.h \ test/erasure-code/ceph_erasure_code_benchmark.h \ test/bench/backend.h test/bench/bencher.h \ test/bench/detailed_stat_collector.h test/bench/distribution.h \ test/bench/dumb_backend.h test/bench/rados_backend.h \ test/bench/rbd_backend.h test/bench/stat_collector.h \ test/bench/testfilestore_backend.h \ test/common/ObjectContents.h test/encoding/types.h \ test/objectstore/DeterministicOpSequence.h \ test/objectstore/FileStoreDiff.h \ test/objectstore/FileStoreTracker.h \ test/objectstore/TestObjectStoreState.h \ test/objectstore/workload_generator.h test/kv_store_bench.h \ test/librados/test.h test/librados/TestCase.h \ test/ObjectMap/KeyValueDBMemory.h test/omap_bench.h \ test/osdc/FakeWriteback.h test/osd/Object.h \ test/osd/RadosModel.h test/osd/TestOpStat.h \ test/system/cross_process_sem.h \ test/system/st_rados_create_pool.h \ test/system/st_rados_delete_objs.h \ test/system/st_rados_delete_pool.h \ test/system/st_rados_list_objects.h \ test/system/st_rados_notify.h test/system/st_rados_watch.h \ test/system/systest_runnable.h test/system/systest_settings.h \ test/unit.h tools/rados/rados_sync.h tools/common.h cls_acl.cc \ cls_crypto.cc fetch_config logrotate.conf sample.ceph.conf \ bash_completion/ceph bash_completion/rados bash_completion/rbd \ bash_completion/radosgw-admin mount/canonicalize.c \ mount/mtab.c objclass/objclass.h HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ check recheck distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)acconfig.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CXXFLAGS = @AM_CXXFLAGS@ $(AM_COMMON_CFLAGS) -ftemplate-depth-1024 \ -Wnon-virtual-dtor -Wno-invalid-offsetof $(am__append_3) \ $(am__append_6) $(am__append_27) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@ CC = @CC@ CCAS = ${srcdir}/yasm-wrapper CCASDEPMODE = @CCASDEPMODE@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOPP_CFLAGS = @CRYPTOPP_CFLAGS@ CRYPTOPP_LIBS = @CRYPTOPP_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CLASSPATH_JAR = @EXTRA_CLASSPATH_JAR@ FGREP = @FGREP@ GCOV_PREFIX_STRIP = @GCOV_PREFIX_STRIP@ GIT_CHECK = @GIT_CHECK@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTEL_FLAGS = @INTEL_FLAGS@ INTEL_PCLMUL_FLAGS = @INTEL_PCLMUL_FLAGS@ INTEL_SSE2_FLAGS = @INTEL_SSE2_FLAGS@ INTEL_SSE3_FLAGS = @INTEL_SSE3_FLAGS@ INTEL_SSE4_1_FLAGS = @INTEL_SSE4_1_FLAGS@ INTEL_SSE4_2_FLAGS = @INTEL_SSE4_2_FLAGS@ INTEL_SSE_FLAGS = @INTEL_SSE_FLAGS@ INTEL_SSSE3_FLAGS = @INTEL_SSSE3_FLAGS@ JAR = @JAR@ JAVAC = @JAVAC@ JAVAH = @JAVAH@ JDK_CPPFLAGS = @JDK_CPPFLAGS@ KEYUTILS_LIB = @KEYUTILS_LIB@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEDIT_CFLAGS = @LIBEDIT_CFLAGS@ LIBEDIT_LIBS = @LIBEDIT_LIBS@ LIBFUSE = @LIBFUSE@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTCMALLOC = @LIBTCMALLOC@ LIBTOOL = @LIBTOOL@ LIBZFS_CFLAGS = @LIBZFS_CFLAGS@ LIBZFS_LIBS = @LIBZFS_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NSS_CFLAGS = @NSS_CFLAGS@ NSS_LIBS = @NSS_LIBS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RESOLV_LIBS = @RESOLV_LIBS@ RPM_RELEASE = @RPM_RELEASE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WARN_IGNORED_QUALIFIERS = @WARN_IGNORED_QUALIFIERS@ WARN_TYPE_LIMITS = @WARN_TYPE_LIMITS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = gnu subdir-objects SUBDIRS = ocf java $(am__append_61) DIST_SUBDIRS = gtest ocf libs3 java BUILT_SOURCES = init-ceph # extra bits EXTRA_DIST = brag/server brag/README.md brag/client \ $(srcdir)/test/mon/mon-test-helpers.sh \ $(srcdir)/test/osd/osd-test-helpers.sh \ $(srcdir)/$(shell_scripts:%=%.in) \ $(srcdir)/verify-mds-journal.sh $(srcdir)/vstart.sh \ $(srcdir)/stop.sh ceph-run $(srcdir)/ceph_common.sh \ $(srcdir)/init-radosgw $(srcdir)/init-radosgw.sysv \ $(srcdir)/init-rbdmap $(srcdir)/ceph-clsinfo \ $(srcdir)/make_version $(srcdir)/check_version \ $(srcdir)/.git_version $(srcdir)/ceph-rbdnamer \ $(srcdir)/test/encoding/readable.sh \ $(srcdir)/test/encoding/check-generated.sh \ $(srcdir)/upstart/ceph-all.conf \ $(srcdir)/upstart/ceph-mon.conf \ $(srcdir)/upstart/ceph-mon-all.conf \ $(srcdir)/upstart/ceph-mon-all-starter.conf \ $(srcdir)/upstart/ceph-create-keys.conf \ $(srcdir)/upstart/ceph-osd.conf \ $(srcdir)/upstart/ceph-osd-all.conf \ $(srcdir)/upstart/ceph-osd-all-starter.conf \ $(srcdir)/upstart/ceph-mds.conf \ $(srcdir)/upstart/ceph-mds-all.conf \ $(srcdir)/upstart/ceph-mds-all-starter.conf \ $(srcdir)/upstart/radosgw.conf \ $(srcdir)/upstart/radosgw-all.conf \ $(srcdir)/upstart/radosgw-all-starter.conf \ $(srcdir)/upstart/rbdmap.conf ceph.in ceph-disk \ ceph-disk-prepare ceph-disk-activate ceph-disk-udev \ ceph-create-keys ceph-rest-api ceph-crush-location \ mount.fuse.ceph rbdmap unittest_bufferlist.sh yasm-wrapper \ libs3/COPYING libs3/ChangeLog libs3/GNUmakefile \ libs3/GNUmakefile.mingw libs3/GNUmakefile.osx libs3/INSTALL \ libs3/LICENSE libs3/README libs3/TODO libs3/archlinux \ libs3/debian libs3/doxyfile libs3/inc libs3/libs3.spec \ libs3/mswin libs3/src libs3/test unittest_bufferlist.sh CLEANFILES = $(shell_scripts) ceph_ver.h sample.fetch_config # jerasure plugin # everything else we want to include in a 'make dist' noinst_HEADERS = arch/intel.h arch/neon.h arch/probe.h \ auth/cephx/CephxAuthorizeHandler.h auth/cephx/CephxKeyServer.h \ auth/cephx/CephxProtocol.h auth/cephx/CephxClientHandler.h \ auth/cephx/CephxServiceHandler.h \ auth/cephx/CephxSessionHandler.h \ auth/none/AuthNoneAuthorizeHandler.h \ auth/none/AuthNoneClientHandler.h \ auth/none/AuthNoneServiceHandler.h \ auth/none/AuthNoneSessionHandler.h \ auth/none/AuthNoneProtocol.h \ auth/unknown/AuthUnknownAuthorizeHandler.h \ auth/unknown/AuthUnknownClientHandler.h \ auth/unknown/AuthUnknownServiceHandler.h \ auth/unknown/AuthUnknownSessionHandler.h \ auth/unknown/AuthUnknownProtocol.h auth/Auth.h \ auth/AuthMethodList.h auth/AuthClientHandler.h \ auth/AuthServiceHandler.h auth/AuthSessionHandler.h \ auth/AuthAuthorizeHandler.h auth/KeyRing.h \ auth/RotatingKeyRing.h auth/Crypto.h crush/CrushCompiler.h \ crush/CrushTester.h crush/CrushWrapper.h crush/CrushWrapper.i \ crush/builder.h crush/crush.h crush/grammar.h crush/hash.h \ crush/mapper.h crush/sample.txt crush/types.h \ mon/AuthMonitor.h mon/DataHealthService.h mon/Elector.h \ mon/LogMonitor.h mon/ConfigKeyService.h mon/HealthMonitor.h \ mon/HealthService.h mon/MDSMonitor.h mon/MonmapMonitor.h \ mon/MonCap.h mon/MonClient.h mon/MonCommands.h \ mon/DumplingMonCommands.h mon/MonMap.h mon/Monitor.h \ mon/MonitorStore.h mon/MonitorDBStore.h mon/OSDMonitor.h \ mon/PGMap.h mon/PGMonitor.h mon/Paxos.h mon/PaxosService.h \ mon/QuorumService.h mon/Session.h mon/mon_types.h \ mds/inode_backtrace.h mds/flock.h mds/locks.c mds/locks.h \ mds/Anchor.h mds/AnchorClient.h mds/AnchorServer.h \ mds/CDentry.h mds/CDir.h mds/CInode.h mds/Capability.h \ mds/Dumper.h mds/InoTable.h mds/LocalLock.h mds/Locker.h \ mds/LogEvent.h mds/LogSegment.h mds/MDBalancer.h mds/MDCache.h \ mds/MDLog.h mds/MDS.h mds/MDSMap.h mds/MDSTable.h \ mds/MDSTableServer.h mds/MDSTableClient.h mds/MDSUtility.h \ mds/Mutation.h mds/Migrator.h mds/Resetter.h mds/ScatterLock.h \ mds/Server.h mds/SessionMap.h mds/SimpleLock.h \ mds/SnapClient.h mds/SnapRealm.h mds/SnapServer.h \ mds/inode_backtrace.h mds/mds_table_types.h mds/mdstypes.h \ mds/snap.h mds/events/ECommitted.h mds/events/EExport.h \ mds/events/EFragment.h mds/events/EImportFinish.h \ mds/events/EImportStart.h mds/events/EMetaBlob.h \ mds/events/EOpen.h mds/events/EResetJournal.h \ mds/events/ESession.h mds/events/ESessions.h \ mds/events/ESlaveUpdate.h mds/events/ESubtreeMap.h \ mds/events/ETableClient.h mds/events/ETableServer.h \ mds/events/EUpdate.h os/btrfs_ioctl.h os/chain_xattr.h \ os/BtrfsFileStoreBackend.h os/CollectionIndex.h \ os/DBObjectMap.h os/GenericObjectMap.h os/FileJournal.h \ os/FileStore.h os/FlatIndex.h os/FDCache.h \ os/GenericFileStoreBackend.h os/HashIndex.h os/IndexManager.h \ os/Journal.h os/JournalingObjectStore.h os/KeyValueDB.h \ os/LevelDBStore.h os/LFNIndex.h os/MemStore.h \ os/KeyValueStore.h os/ObjectMap.h os/ObjectStore.h \ os/SequencerPosition.h os/WBThrottle.h \ os/XfsFileStoreBackend.h os/ZFSFileStoreBackend.h \ $(am__append_18) osd/Ager.h osd/ClassHandler.h osd/HitSet.h \ osd/OSD.h osd/OSDCap.h osd/OSDMap.h osd/ObjectVersioner.h \ osd/OpRequest.h osd/SnapMapper.h osd/PG.h osd/PGLog.h \ osd/ReplicatedPG.h osd/PGBackend.h osd/ReplicatedBackend.h \ osd/TierAgentState.h osd/ECBackend.h osd/ECUtil.h \ osd/ECMsgTypes.h osd/ECTransaction.h osd/Watch.h \ osd/osd_types.h \ erasure-code/jerasure/jerasure/include/cauchy.h \ erasure-code/jerasure/jerasure/include/galois.h \ erasure-code/jerasure/jerasure/include/jerasure.h \ erasure-code/jerasure/jerasure/include/liberation.h \ erasure-code/jerasure/jerasure/include/reed_sol.h \ erasure-code/jerasure/gf-complete/include/gf_int.h \ erasure-code/jerasure/gf-complete/include/gf_complete.h \ erasure-code/jerasure/gf-complete/include/gf_rand.h \ erasure-code/jerasure/gf-complete/include/gf_method.h \ erasure-code/jerasure/gf-complete/include/gf_general.h \ erasure-code/jerasure/ErasureCodeJerasure.h \ erasure-code/ErasureCodeInterface.h \ erasure-code/ErasureCodePlugin.h osdc/Blinker.h osdc/Filer.h \ osdc/Journaler.h osdc/ObjectCacher.h osdc/Objecter.h \ osdc/Striper.h osdc/WritebackHandler.h client/Client.h \ client/Dentry.h client/Dir.h client/Fh.h client/Inode.h \ client/MetaRequest.h client/MetaSession.h \ client/ClientSnapRealm.h client/SyntheticClient.h \ client/Trace.h client/ioctl.h client/ObjecterWriteback.h \ $(am__append_24) global/pidfile.h global/global_init.h \ global/global_context.h global/signal_handler.h \ json_spirit/json_spirit.h \ json_spirit/json_spirit_error_position.h \ json_spirit/json_spirit_reader.h \ json_spirit/json_spirit_reader_template.h \ json_spirit/json_spirit_stream_reader.h \ json_spirit/json_spirit_utils.h \ json_spirit/json_spirit_value.h \ json_spirit/json_spirit_writer.h \ json_spirit/json_spirit_writer_options.h \ json_spirit/json_spirit_writer_template.h log/Entry.h \ log/EntryQueue.h log/Log.h log/SubsystemMap.h \ perfglue/cpu_profiler.h perfglue/heap_profiler.h \ common/bloom_filter.hpp common/sctp_crc32.h \ common/crc32c_intel_baseline.h common/crc32c_intel_fast.h \ common/BackTrace.h common/RefCountedObj.h \ common/HeartbeatMap.h common/LogClient.h common/LogEntry.h \ common/Preforker.h common/SloppyCRCMap.h common/WorkQueue.h \ common/PrioritizedQueue.h common/ceph_argparse.h \ common/ceph_context.h common/xattr.h common/blkdev.h \ common/compiler_extensions.h common/debug.h common/dout.h \ common/escape.h common/fd.h common/version.h common/hex.h \ common/histogram.h common/entity_name.h common/errno.h \ common/environment.h common/likely.h common/lockdep.h \ common/obj_bencher.h common/snap_types.h common/Clock.h \ common/Cond.h common/ConfUtils.h common/DecayCounter.h \ common/Finisher.h common/Formatter.h common/perf_counters.h \ common/OutputDataSocket.h common/admin_socket.h \ common/admin_socket_client.h common/random_cache.hpp \ common/shared_cache.hpp common/tracked_int_ptr.hpp \ common/simple_cache.hpp common/sharedptr_registry.hpp \ common/map_cacher.hpp common/MemoryModel.h common/Mutex.h \ common/PrebufferedStreambuf.h common/RWLock.h \ common/Semaphore.h common/SimpleRNG.h common/TextTable.h \ common/Thread.h common/Throttle.h common/Timer.h \ common/TrackedOp.h common/arch.h common/armor.h \ common/common_init.h common/io_priority.h common/pipe.h \ common/code_environment.h common/signal.h common/simple_spin.h \ common/run_cmd.h common/safe_io.h common/config.h \ common/config_obs.h common/config_opts.h common/ceph_crypto.h \ common/ceph_crypto_cms.h common/ceph_json.h common/lru_map.h \ common/utf8.h common/mime.h common/pick_address.h \ common/secret.h common/strtol.h common/static_assert.h \ common/AsyncReserver.h common/sync_filesystem.h \ common/cmdparse.h common/hobject.h common/linux_version.h \ msg/Accepter.h msg/DispatchQueue.h msg/Dispatcher.h \ msg/Message.h msg/Messenger.h msg/Pipe.h msg/SimpleMessenger.h \ msg/msg_types.h messages/MAuth.h messages/MAuthReply.h \ messages/MCacheExpire.h messages/MClientCaps.h \ messages/MClientCapRelease.h messages/MClientLease.h \ messages/MClientReconnect.h messages/MClientReply.h \ messages/MClientRequest.h messages/MClientRequestForward.h \ messages/MClientSession.h messages/MClientSnap.h \ messages/MCommand.h messages/MCommandReply.h \ messages/MDentryLink.h messages/MDentryUnlink.h \ messages/MDirUpdate.h messages/MDiscover.h \ messages/MDiscoverReply.h messages/MExportCaps.h \ messages/MExportCapsAck.h messages/MExportDir.h \ messages/MExportDirAck.h messages/MExportDirCancel.h \ messages/MExportDirDiscover.h messages/MExportDirDiscoverAck.h \ messages/MExportDirFinish.h messages/MExportDirNotify.h \ messages/MExportDirNotifyAck.h messages/MExportDirPrep.h \ messages/MExportDirPrepAck.h messages/MGenericMessage.h \ messages/MGetPoolStats.h messages/MGetPoolStatsReply.h \ messages/MHeartbeat.h messages/MInodeFileCaps.h \ messages/MLock.h messages/MLog.h messages/MLogAck.h \ messages/MMDSBeacon.h messages/MMDSCacheRejoin.h \ messages/MMDSLoadTargets.h messages/MMDSFindIno.h \ messages/MMDSFindInoReply.h messages/MMDSFragmentNotify.h \ messages/MMDSMap.h messages/MMDSOpenIno.h \ messages/MMDSOpenInoReply.h messages/MMDSResolve.h \ messages/MMDSResolveAck.h messages/MMDSSlaveRequest.h \ messages/MMDSTableRequest.h messages/MMonCommand.h \ messages/MMonCommandAck.h messages/MMonElection.h \ messages/MMonGetMap.h messages/MMonGetVersion.h \ messages/MMonGetVersionReply.h messages/MMonGlobalID.h \ messages/MMonHealth.h messages/MMonJoin.h messages/MMonMap.h \ messages/MMonPaxos.h messages/MMonProbe.h messages/MMonScrub.h \ messages/MMonSubscribe.h messages/MMonSubscribeAck.h \ messages/MMonSync.h messages/MOSDAlive.h messages/MOSDBoot.h \ messages/MOSDFailure.h messages/MOSDMarkMeDown.h \ messages/MOSDMap.h messages/MOSDOp.h messages/MOSDOpReply.h \ messages/MOSDPGBackfill.h messages/MOSDPGCreate.h \ messages/MOSDPGPush.h messages/MOSDPGPull.h \ messages/MOSDPGPushReply.h messages/MOSDPGInfo.h \ messages/MOSDPGLog.h messages/MOSDPGMissing.h \ messages/MOSDPGNotify.h messages/MOSDPGQuery.h \ messages/MOSDPGRemove.h messages/MOSDPGScan.h \ messages/MOSDECSubOpWrite.h messages/MOSDECSubOpWriteReply.h \ messages/MOSDECSubOpRead.h messages/MOSDECSubOpReadReply.h \ messages/MBackfillReserve.h messages/MRecoveryReserve.h \ messages/MMonQuorumService.h messages/MOSDPGTemp.h \ messages/MOSDPGTrim.h messages/MOSDPing.h \ messages/MOSDRepScrub.h messages/MOSDScrub.h \ messages/MOSDSubOp.h messages/MOSDSubOpReply.h \ messages/MPGStats.h messages/MPGStatsAck.h messages/MPing.h \ messages/MPoolOp.h messages/MPoolOpReply.h \ messages/MRemoveSnaps.h messages/MRoute.h messages/MForward.h \ messages/MStatfs.h messages/MStatfsReply.h \ messages/MTimeCheck.h messages/MWatchNotify.h \ messages/PaxosServiceMessage.h include/Context.h \ include/CompatSet.h include/Distribution.h include/Spinlock.h \ include/addr_parsing.h include/assert.h include/atomic.h \ include/bitmapper.h include/blobhash.h include/buffer.h \ include/byteorder.h include/cephfs/libcephfs.h \ include/ceph_features.h include/ceph_frag.h include/ceph_fs.h \ include/ceph_hash.h include/cmp.h include/color.h \ include/compat.h include/crc32c.h include/encoding.h \ include/err.h include/error.h include/filepath.h \ include/frag.h include/hash.h include/intarith.h \ include/interval_set.h include/int_types.h include/ipaddr.h \ include/linux_fiemap.h include/lru.h include/msgr.h \ include/object.h include/page.h include/rangeset.h \ include/rados.h include/rbd_types.h include/statlite.h \ include/str_list.h include/str_map.h include/stringify.h \ include/triple.h include/types.h include/utime.h \ include/dlist.h include/elist.h include/uuid.h include/xlist.h \ include/rados/librados.h include/rados/rados_types.h \ include/rados/rados_types.hpp include/rados/librados.hpp \ include/rados/librgw.h include/rados/page.h \ include/rados/crc32c.h include/rados/buffer.h \ include/rbd/features.h include/rbd/librbd.h \ include/rbd/librbd.hpp include/util.h include/stat.h \ include/on_exit.h include/memory.h include/rados/memory.h \ include/hash_namespace.h include/unordered_set.h \ include/unordered_map.h librados/snap_set_diff.h \ librados/AioCompletionImpl.h librados/IoCtxImpl.h \ librados/PoolAsyncCompletionImpl.h librados/RadosClient.h \ librbd/AioCompletion.h librbd/AioRequest.h librbd/ImageCtx.h \ librbd/internal.h librbd/LibrbdWriteback.h \ librbd/parent_types.h librbd/SnapInfo.h librbd/WatchCtx.h \ rgw/logrotate.conf rgw/rgw_acl.h rgw/rgw_acl_s3.h \ rgw/rgw_acl_swift.h rgw/rgw_client_io.h rgw/rgw_fcgi.h \ rgw/rgw_xml.h rgw/rgw_cache.h rgw/rgw_common.h rgw/rgw_cors.h \ rgw/rgw_cors_s3.h rgw/rgw_cors_swift.h rgw/rgw_string.h \ rgw/rgw_formats.h rgw/rgw_http_errors.h rgw/rgw_log.h \ rgw/rgw_loadgen.h rgw/rgw_multi.h rgw/rgw_policy_s3.h \ rgw/rgw_gc.h rgw/rgw_metadata.h rgw/rgw_multi_del.h \ rgw/rgw_op.h rgw/rgw_http_client.h rgw/rgw_swift.h \ rgw/rgw_swift_auth.h rgw/rgw_quota.h rgw/rgw_rados.h \ rgw/rgw_replica_log.h rgw/rgw_resolve.h rgw/rgw_rest.h \ rgw/rgw_rest_swift.h rgw/rgw_rest_s3.h rgw/rgw_auth_s3.h \ rgw/rgw_rest_admin.h rgw/rgw_rest_usage.h rgw/rgw_rest_user.h \ rgw/rgw_rest_bucket.h rgw/rgw_rest_client.h \ rgw/rgw_rest_conn.h rgw/rgw_tools.h rgw/rgw_rest_metadata.h \ rgw/rgw_rest_log.h rgw/rgw_rest_opstate.h \ rgw/rgw_rest_replica_log.h rgw/rgw_rest_config.h \ rgw/rgw_usage.h rgw/rgw_user.h rgw/rgw_bucket.h \ rgw/rgw_keystone.h rgw/rgw_civetweb.h rgw/rgw_civetweb_log.h \ civetweb/civetweb.h civetweb/include/civetweb.h \ civetweb/include/civetweb_conf.h civetweb/src/md5.h \ cls/lock/cls_lock_types.h cls/lock/cls_lock_ops.h \ cls/lock/cls_lock_client.h cls/rbd/cls_rbd.h \ cls/rbd/cls_rbd_client.h cls/refcount/cls_refcount_ops.h \ cls/refcount/cls_refcount_client.h \ cls/version/cls_version_types.h cls/version/cls_version_ops.h \ cls/version/cls_version_client.h cls/log/cls_log_types.h \ cls/log/cls_log_ops.h cls/log/cls_log_client.h \ cls/statelog/cls_statelog_types.h \ cls/statelog/cls_statelog_ops.h \ cls/statelog/cls_statelog_client.h \ cls/replica_log/cls_replica_log_types.h \ cls/replica_log/cls_replica_log_ops.h \ cls/replica_log/cls_replica_log_client.h \ cls/rgw/cls_rgw_client.h cls/rgw/cls_rgw_ops.h \ cls/rgw/cls_rgw_types.h cls/user/cls_user_client.h \ cls/user/cls_user_ops.h cls/user/cls_user_types.h \ key_value_store/key_value_structure.h \ key_value_store/kv_flat_btree_async.h \ key_value_store/kvs_arg_types.h \ test/erasure-code/ErasureCodeExample.h \ test/erasure-code/ceph_erasure_code_benchmark.h \ test/bench/backend.h test/bench/bencher.h \ test/bench/detailed_stat_collector.h test/bench/distribution.h \ test/bench/dumb_backend.h test/bench/rados_backend.h \ test/bench/rbd_backend.h test/bench/stat_collector.h \ test/bench/testfilestore_backend.h \ test/common/ObjectContents.h test/encoding/types.h \ test/objectstore/DeterministicOpSequence.h \ test/objectstore/FileStoreDiff.h \ test/objectstore/FileStoreTracker.h \ test/objectstore/TestObjectStoreState.h \ test/objectstore/workload_generator.h test/kv_store_bench.h \ test/librados/test.h test/librados/TestCase.h \ test/ObjectMap/KeyValueDBMemory.h test/omap_bench.h \ test/osdc/FakeWriteback.h test/osd/Object.h \ test/osd/RadosModel.h test/osd/TestOpStat.h \ test/system/cross_process_sem.h \ test/system/st_rados_create_pool.h \ test/system/st_rados_delete_objs.h \ test/system/st_rados_delete_pool.h \ test/system/st_rados_list_objects.h \ test/system/st_rados_notify.h test/system/st_rados_watch.h \ test/system/systest_runnable.h test/system/systest_settings.h \ test/unit.h tools/rados/rados_sync.h tools/common.h cls_acl.cc \ cls_crypto.cc fetch_config logrotate.conf sample.ceph.conf \ bash_completion/ceph bash_completion/rados bash_completion/rbd \ bash_completion/radosgw-admin mount/canonicalize.c \ mount/mtab.c objclass/objclass.h bin_SCRIPTS = brag/client/ceph-brag ceph ceph-run ceph-rest-api \ ceph-clsinfo ceph-debugpack ceph-rbdnamer ceph-post-file \ ceph-crush-location ceph-coverage sbin_SCRIPTS = su_sbin_SCRIPTS = mount.fuse.ceph mkcephfs dist_bin_SCRIPTS = lib_LTLIBRARIES = librados.la librbd.la libcephfs.la $(am__append_65) noinst_LTLIBRARIES = libarch.la libauth.la libcrush.la libmon_types.la \ libmon.la libmds.la libos_types.la libos.la libosd_types.la \ libosd.la liberasure_code.la libosdc.la libclient.la \ $(am__append_23) libglobal.la libjson_spirit.la liblog.la \ libperfglue.la libcommon_crc.la libcommon.la libmsg.la \ $(am__append_35) libcls_lock_client.la \ libcls_refcount_client.la libcls_rgw_client.la \ libcls_rbd_client.la $(am__append_51) libradostest.la noinst_LIBRARIES = $(am__append_17) libcls_version_client.a \ libcls_log_client.a libcls_statelog_client.a \ libcls_replica_log_client.a libcls_user_client.a radoslib_LTLIBRARIES = libcls_hello.la libcls_rbd.la libcls_lock.la \ libcls_refcount.la libcls_version.la libcls_log.la \ libcls_statelog.la libcls_replica_log.la libcls_user.la \ libcls_rgw.la $(am__append_40) # like bin_PROGRAMS, but these targets are only built for debug builds bin_DEBUGPROGRAMS = ceph_test_ioctls $(am__append_38) \ ceph_erasure_code_benchmark ceph_erasure_code ceph_test_timers \ ceph_test_signal_handlers ceph_test_rados ceph_test_mutate \ ceph_test_rewrite_latency ceph_test_msgr ceph_streamtest \ ceph_test_trans ceph_test_crypto ceph_test_keys \ $(am__append_49) ceph_smalliobench ceph_smalliobenchfs \ ceph_smalliobenchdumb ceph_smalliobenchrbd ceph_tpbench \ ceph_omapbench $(am__append_50) ceph_bench_log \ $(am__append_53) ceph_multi_stress_watch ceph_test_librbd \ $(am__append_54) ceph_test_cls_rbd ceph_test_cls_refcount \ ceph_test_cls_version ceph_test_cls_log ceph_test_cls_statelog \ ceph_test_cls_replica_log ceph_test_cls_lock \ ceph_test_cls_hello $(am__append_55) ceph_test_mon_workloadgen \ ceph_test_rados_api_cmd ceph_test_rados_api_io \ ceph_test_rados_api_c_write_operations \ ceph_test_rados_api_c_read_operations ceph_test_rados_api_aio \ ceph_test_rados_api_list ceph_test_rados_api_pool \ ceph_test_rados_api_stat ceph_test_rados_api_watch_notify \ ceph_test_rados_api_snapshots ceph_test_rados_api_cls \ ceph_test_rados_api_misc ceph_test_rados_api_tier \ ceph_test_rados_api_lock ceph_test_libcephfs $(am__append_56) \ ceph_test_objectstore_workloadgen \ ceph_test_filestore_idempotent \ ceph_test_filestore_idempotent_sequence ceph_xattr_bench \ ceph_test_filejournal ceph_test_stress_watch \ ceph_test_objectcacher_stress ceph_test_snap_mapper \ ceph_test_object_map ceph_test_keyvaluedb_atomicity \ ceph_test_keyvaluedb_iterators \ ceph_test_cfuse_cache_invalidate ceph_test_c_headers \ ceph_test_get_blkdev_size ceph-osdomap-tool ceph-monstore-tool \ ceph-kvstore-tool ceph_scratchtool ceph_scratchtoolpp \ ceph_psim ceph_dupstore ceph_radosacl ceph-client-debug # like sbin_SCRIPTS but can be used to install to e.g. /usr/sbin ceph_sbindir = $(sbindir) # certain things go straight into /sbin, though! su_sbindir = /sbin # tests scripts will be appended to this check_SCRIPTS = test/erasure-code/test-erasure-code.sh \ unittest_bufferlist.sh test/encoding/check-generated.sh \ test/mon/osd-pool-create.sh test/mon/misc.sh \ test/mon/osd-crush.sh test/mon/osd-erasure-code-profile.sh \ test/mon/mkfs.sh test/ceph-disk.sh \ test/mon/mon-handle-forward.sh test/vstart_wrapped_tests.sh \ test/pybind/test_ceph_argparse.py ################################## AM_COMMON_CPPFLAGS = \ -D__CEPH__ \ -D_FILE_OFFSET_BITS=64 \ -D_REENTRANT \ -D_THREAD_SAFE \ -D__STDC_FORMAT_MACROS \ -D_GNU_SOURCE \ -DCEPH_LIBDIR=\"${libdir}\" \ -DCEPH_PKGLIBDIR=\"${pkglibdir}\" \ -DGTEST_HAS_TR1_TUPLE=0 AM_COMMON_CFLAGS = \ -Wall \ ${WARN_TYPE_LIMITS} \ ${WARN_IGNORED_QUALIFIERS} \ -Winit-self \ -Wpointer-arith \ -Werror=format-security \ -fno-strict-aliasing \ -fsigned-char AM_CFLAGS = $(AM_COMMON_CFLAGS) $(am__append_5) $(am__append_26) AM_CPPFLAGS = $(AM_COMMON_CPPFLAGS) # note: this is position dependant, it affects the -l options that # come after it on the command line. when you use ${AM_LDFLAGS} in # later rules, take care where you place it. for more information, see # http://blog.flameeyes.eu/2008/11/19/relationship-between-as-needed-and-no-undefined-part-1-what-do-they-do # http://blog.flameeyes.eu/2008/11/20/misguided-link-and-as-needed # http://www.gentoo.org/proj/en/qa/asneeded.xml # http://gcc.gnu.org/ml/gcc-help/2010-12/msg00338.html # http://sigquit.wordpress.com/2011/02/16/why-asneeded-doesnt-work-as-expected-for-your-libraries-on-your-autotools-project/ AM_LDFLAGS = $(am__append_2) $(am__append_4) AM_CCASFLAGS = -f elf64 ##################### EXTRALIBS = -luuid -lm $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_13) LIBGLOBAL = libglobal.la LIBCOMMON = libcommon.la LIBARCH = libarch.la LIBPERFGLUE = libperfglue.la $(am__append_12) LIBAUTH = libauth.la LIBMSG = libmsg.la LIBCRUSH = libcrush.la LIBJSON_SPIRIT = libjson_spirit.la LIBLOG = liblog.la # Always use system leveldb LIBOS = libos.la $(am__append_10) $(am__append_11) -lleveldb -lsnappy LIBOS_TYPES = libos_types.la # Libosd always needs osdc and os LIBOSD = libosd.la $(LIBOSDC) $(LIBOS) $(LIBPERFGLUE) LIBOSD_TYPES = libosd_types.la LIBOSDC = libosdc.la # These have references to syms like ceph_using_tcmalloc(), glue libperfglue to them LIBMON = libmon.la $(LIBPERFGLUE) LIBMON_TYPES = libmon_types.la LIBMDS = libmds.la $(LIBPERFGLUE) LIBCLIENT = libclient.la LIBCLIENT_FUSE = libclient_fuse.la LIBRADOS = librados.la LIBRGW = librgw.la LIBCIVETWEB = libcivetweb.la LIBRBD = librbd.la LIBCEPHFS = libcephfs.la LIBERASURE_CODE = liberasure_code.la # Use this for binaries requiring libglobal CEPH_GLOBAL = $(LIBGLOBAL) $(LIBCOMMON) $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) # This is set by [lib]/Makefile.am and used for build tests # important; libmsg before libauth! LIBCOMMON_DEPS = libcommon_crc.la $(LIBERASURE_CODE) $(LIBMSG) \ $(LIBAUTH) $(LIBCRUSH) $(LIBJSON_SPIRIT) $(LIBLOG) $(LIBARCH) \ $(am__append_32) LIBRADOS_DEPS = libcls_lock_client.la $(LIBOSDC) $(LIBCOMMON) LIBRGW_DEPS = $(am__append_36) # This is used by the dencoder test DENCODER_SOURCES = $(am__append_39) DENCODER_DEPS = libcls_lock_client.la libcls_refcount_client.la \ libcls_replica_log_client.a libcls_rgw_client.la \ libcls_user_client.a radoslibdir = $(libdir)/rados-classes libarch_la_SOURCES = \ arch/intel.c \ arch/neon.c \ arch/probe.cc libauth_la_SOURCES = \ auth/AuthAuthorizeHandler.cc \ auth/AuthClientHandler.cc \ auth/AuthSessionHandler.cc \ auth/AuthServiceHandler.cc \ auth/AuthMethodList.cc \ auth/cephx/CephxAuthorizeHandler.cc \ auth/cephx/CephxClientHandler.cc \ auth/cephx/CephxProtocol.cc \ auth/cephx/CephxServiceHandler.cc \ auth/cephx/CephxSessionHandler.cc \ auth/cephx/CephxKeyServer.cc \ auth/none/AuthNoneAuthorizeHandler.cc \ auth/unknown/AuthUnknownAuthorizeHandler.cc \ auth/Crypto.cc \ auth/KeyRing.cc \ auth/RotatingKeyRing.cc libcrush_la_SOURCES = \ crush/builder.c \ crush/mapper.c \ crush/crush.c \ crush/hash.c \ crush/CrushWrapper.cc \ crush/CrushCompiler.cc \ crush/CrushTester.cc libmon_types_la_SOURCES = \ mon/PGMap.cc libmon_la_SOURCES = \ mon/Monitor.cc \ mon/Paxos.cc \ mon/PaxosService.cc \ mon/OSDMonitor.cc \ mon/MDSMonitor.cc \ mon/MonmapMonitor.cc \ mon/PGMonitor.cc \ mon/LogMonitor.cc \ mon/AuthMonitor.cc \ mon/Elector.cc \ mon/MonitorStore.cc \ mon/HealthMonitor.cc \ mon/DataHealthService.cc \ mon/ConfigKeyService.cc libmon_la_LIBADD = $(LIBAUTH) $(LIBCOMMON) $(LIBOS) $(LIBMON_TYPES) libmds_la_SOURCES = \ mds/Anchor.cc \ mds/Capability.cc \ mds/Dumper.cc \ mds/Resetter.cc \ mds/MDS.cc \ mds/locks.c \ mds/journal.cc \ mds/Server.cc \ mds/Mutation.cc \ mds/MDCache.cc \ mds/Locker.cc \ mds/Migrator.cc \ mds/MDBalancer.cc \ mds/CDentry.cc \ mds/CDir.cc \ mds/CInode.cc \ mds/LogEvent.cc \ mds/MDSTable.cc \ mds/InoTable.cc \ mds/MDSTableClient.cc \ mds/MDSTableServer.cc \ mds/AnchorServer.cc \ mds/AnchorClient.cc \ mds/SnapRealm.cc \ mds/SnapServer.cc \ mds/snap.cc \ mds/SessionMap.cc \ mds/MDLog.cc \ mds/MDSUtility.cc libmds_la_LIBADD = $(LIBOSDC) libos_types_la_SOURCES = \ os/Transaction.cc libos_types_la_CXXFLAGS = ${AM_CXXFLAGS} libos_la_SOURCES = os/chain_xattr.cc os/DBObjectMap.cc \ os/GenericObjectMap.cc os/FileJournal.cc os/FileStore.cc \ os/FlatIndex.cc os/GenericFileStoreBackend.cc os/HashIndex.cc \ os/IndexManager.cc os/JournalingObjectStore.cc \ os/LevelDBStore.cc os/LFNIndex.cc os/MemStore.cc \ os/KeyValueStore.cc os/ObjectStore.cc os/WBThrottle.cc \ common/TrackedOp.cc $(am__append_14) $(am__append_15) \ $(am__append_16) libos_la_CXXFLAGS = ${AM_CXXFLAGS} libos_la_LIBADD = $(LIBOS_TYPES) @WITH_LIBZFS_TRUE@libos_zfs_a_SOURCES = os/ZFS.cc @WITH_LIBZFS_TRUE@libos_zfs_a_CXXFLAGS = ${AM_CXXFLAGS} ${LIBZFS_CFLAGS} libosd_types_la_SOURCES = \ osd/PGLog.cc \ osd/osd_types.cc \ osd/ECUtil.cc libosd_types_la_CXXFLAGS = ${AM_CXXFLAGS} libosd_la_SOURCES = \ osd/PG.cc \ osd/ReplicatedPG.cc \ osd/ReplicatedBackend.cc \ osd/ECBackend.cc \ osd/ECMsgTypes.cc \ osd/ECTransaction.cc \ osd/PGBackend.cc \ osd/Ager.cc \ osd/HitSet.cc \ osd/OSD.cc \ osd/OSDCap.cc \ osd/Watch.cc \ osd/ClassHandler.cc \ osd/OpRequest.cc \ common/TrackedOp.cc \ osd/SnapMapper.cc \ objclass/class_api.cc libosd_la_CXXFLAGS = ${AM_CXXFLAGS} libosd_la_LIBADD = $(LIBOSDC) $(LIBOS) $(LIBOSD_TYPES) $(LIBOS_TYPES) erasure_codelibdir = $(pkglibdir)/erasure-code erasure_codelib_LTLIBRARIES = libec_jerasure_generic.la \ libec_jerasure_sse3.la libec_jerasure_sse4.la \ libec_jerasure.la libec_example.la \ libec_missing_entry_point.la libec_hangs.la \ libec_fail_to_initialize.la libec_fail_to_register.la \ libec_test_jerasure_sse4.la libec_test_jerasure_sse3.la \ libec_test_jerasure_generic.la jerasure_sources = \ erasure-code/jerasure/jerasure/src/cauchy.c \ erasure-code/jerasure/jerasure/src/galois.c \ erasure-code/jerasure/jerasure/src/jerasure.c \ erasure-code/jerasure/jerasure/src/liberation.c \ erasure-code/jerasure/jerasure/src/reed_sol.c \ erasure-code/jerasure/gf-complete/src/gf_wgen.c \ erasure-code/jerasure/gf-complete/src/gf_method.c \ erasure-code/jerasure/gf-complete/src/gf_w16.c \ erasure-code/jerasure/gf-complete/src/gf.c \ erasure-code/jerasure/gf-complete/src/gf_w32.c \ erasure-code/jerasure/gf-complete/src/gf_w64.c \ erasure-code/jerasure/gf-complete/src/gf_w128.c \ erasure-code/jerasure/gf-complete/src/gf_general.c \ erasure-code/jerasure/gf-complete/src/gf_w4.c \ erasure-code/jerasure/gf-complete/src/gf_rand.c \ erasure-code/jerasure/gf-complete/src/gf_w8.c \ erasure-code/jerasure/ErasureCodePluginJerasure.cc \ erasure-code/jerasure/ErasureCodeJerasure.cc libec_jerasure_generic_la_SOURCES = ${jerasure_sources} libec_jerasure_generic_la_CFLAGS = ${AM_CFLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_generic_la_CXXFLAGS = ${AM_CXXFLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_generic_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_generic_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 \ $(am__append_19) libec_jerasure_sse3_la_SOURCES = ${jerasure_sources} libec_jerasure_sse3_la_CFLAGS = ${AM_CFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse3_la_CXXFLAGS = ${AM_CXXFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse3_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_sse3_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 \ $(am__append_20) libec_jerasure_sse4_la_SOURCES = ${jerasure_sources} libec_jerasure_sse4_la_CFLAGS = ${AM_CFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ ${INTEL_SSE4_1_FLAGS} \ ${INTEL_SSE4_2_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse4_la_CXXFLAGS = ${AM_CXXFLAGS} \ ${INTEL_SSE_FLAGS} \ ${INTEL_SSE2_FLAGS} \ ${INTEL_SSE3_FLAGS} \ ${INTEL_SSSE3_FLAGS} \ ${INTEL_SSE4_1_FLAGS} \ ${INTEL_SSE4_2_FLAGS} \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include libec_jerasure_sse4_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_sse4_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 \ $(am__append_21) libec_jerasure_la_SOURCES = \ erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc libec_jerasure_la_CFLAGS = ${AM_CFLAGS} libec_jerasure_la_CXXFLAGS = ${AM_CXXFLAGS} libec_jerasure_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_jerasure_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 \ $(am__append_22) liberasure_code_la_SOURCES = \ erasure-code/ErasureCodePlugin.cc @LINUX_TRUE@liberasure_code_la_LIBADD = -ldl libosdc_la_SOURCES = \ osdc/Objecter.cc \ osdc/ObjectCacher.cc \ osdc/Filer.cc \ osdc/Striper.cc \ osdc/Journaler.cc libclient_la_SOURCES = \ client/Client.cc \ client/Inode.cc \ client/Dentry.cc \ client/MetaRequest.cc \ client/ClientSnapRealm.cc \ client/MetaSession.cc \ client/Trace.cc libclient_la_LIBADD = $(LIBOSDC) $(LIBEDIT_LIBS) @WITH_FUSE_TRUE@libclient_fuse_la_SOURCES = client/fuse_ll.cc @WITH_FUSE_TRUE@libclient_fuse_la_LIBADD = libclient.la -lfuse ceph_test_ioctls_SOURCES = client/test_ioctls.c libglobal_la_SOURCES = \ global/global_context.cc \ global/global_init.cc \ global/pidfile.cc \ global/signal_handler.cc libglobal_la_LIBADD = $(LIBCOMMON) libjson_spirit_la_SOURCES = \ json_spirit/json_spirit_reader.cpp \ json_spirit/json_spirit_writer.cpp liblog_la_SOURCES = \ log/Log.cc \ log/SubsystemMap.cc libperfglue_la_SOURCES = $(am__append_25) $(am__append_28) \ $(am__append_29) $(am__append_30) @WITH_TCMALLOC_TRUE@libperfglue_la_LIBADD = -ltcmalloc # these should go out of libcommon libcommon_la_SOURCES = ceph_ver.c common/DecayCounter.cc \ common/LogClient.cc common/LogEntry.cc \ common/PrebufferedStreambuf.cc common/SloppyCRCMap.cc \ common/BackTrace.cc common/perf_counters.cc common/Mutex.cc \ common/OutputDataSocket.cc common/admin_socket.cc \ common/admin_socket_client.cc common/cmdparse.cc \ common/escape.c common/io_priority.cc common/Clock.cc \ common/Throttle.cc common/Timer.cc common/Finisher.cc \ common/environment.cc common/assert.cc common/run_cmd.cc \ common/WorkQueue.cc common/ConfUtils.cc common/MemoryModel.cc \ common/armor.c common/fd.cc common/xattr.c common/safe_io.c \ common/snap_types.cc common/str_list.cc common/str_map.cc \ common/errno.cc common/RefCountedObj.cc common/blkdev.cc \ common/common_init.cc common/pipe.c common/ceph_argparse.cc \ common/ceph_context.cc common/buffer.cc \ common/code_environment.cc common/dout.cc common/histogram.cc \ common/signal.cc common/simple_spin.cc common/Thread.cc \ common/Formatter.cc common/HeartbeatMap.cc common/config.cc \ common/utf8.c common/mime.c common/strtol.cc common/page.cc \ common/lockdep.cc common/version.cc common/hex.cc \ common/entity_name.cc common/ceph_crypto.cc \ common/ceph_crypto_cms.cc common/ceph_json.cc common/ipaddr.cc \ common/pick_address.cc common/util.cc common/TextTable.cc \ common/ceph_fs.cc common/ceph_hash.cc common/ceph_strings.cc \ common/ceph_frag.cc common/addr_parsing.c common/hobject.cc \ common/bloom_filter.cc common/linux_version.c mon/MonCap.cc \ mon/MonClient.cc mon/MonMap.cc osd/OSDMap.cc osd/osd_types.cc \ osd/ECMsgTypes.cc osd/HitSet.cc mds/MDSMap.cc \ mds/inode_backtrace.cc mds/mdstypes.cc mds/flock.cc # inject crc in common libcommon_crc_la_SOURCES = common/sctp_crc32.c common/crc32c.cc \ common/crc32c_intel_baseline.c common/crc32c_intel_fast.c \ $(am__append_31) @WITH_GOOD_YASM_ELF64_TRUE@libcommon_crc_la_LIBTOOLFLAGS = --tag=CC libcommon_la_LIBADD = $(LIBCOMMON_DEPS) libmsg_la_SOURCES = \ msg/Accepter.cc \ msg/DispatchQueue.cc \ msg/Message.cc \ msg/Messenger.cc \ msg/Pipe.cc \ msg/SimpleMessenger.cc \ msg/msg_types.cc libcephfs_includedir = $(includedir)/cephfs libcephfs_include_DATA = $(srcdir)/include/cephfs/libcephfs.h librbd_includedir = $(includedir)/rbd librbd_include_DATA = \ $(srcdir)/include/rbd/features.h \ $(srcdir)/include/rbd/librbd.h \ $(srcdir)/include/rbd/librbd.hpp rados_includedir = $(includedir)/rados rados_include_DATA = \ $(srcdir)/include/rados/librados.h \ $(srcdir)/include/rados/rados_types.h \ $(srcdir)/include/rados/rados_types.hpp \ $(srcdir)/include/rados/librados.hpp \ $(srcdir)/include/buffer.h \ $(srcdir)/include/page.h \ $(srcdir)/include/crc32c.h \ $(srcdir)/include/memory.h librados_la_SOURCES = \ librados/librados.cc \ librados/RadosClient.cc \ librados/IoCtxImpl.cc \ librados/snap_set_diff.cc # We need this to avoid basename conflicts with the librados build tests in test/Makefile.am librados_la_CXXFLAGS = ${AM_CXXFLAGS} librados_la_LIBADD = $(LIBRADOS_DEPS) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) librados_la_LDFLAGS = ${AM_LDFLAGS} -version-info 2:0:0 \ $(am__append_33) librbd_la_SOURCES = \ librbd/librbd.cc \ librbd/AioCompletion.cc \ librbd/AioRequest.cc \ librbd/ImageCtx.cc \ librbd/internal.cc \ librbd/LibrbdWriteback.cc \ librbd/WatchCtx.cc librbd_la_LIBADD = \ $(LIBRADOS) $(LIBOSDC) \ libcls_rbd_client.la libcls_lock_client.la \ $(PTHREAD_LIBS) $(EXTRALIBS) librbd_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 $(am__append_34) @WITH_RADOSGW_TRUE@librgw_la_SOURCES = \ @WITH_RADOSGW_TRUE@ rgw/librgw.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_acl.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_acl_s3.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_acl_swift.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_client_io.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_fcgi.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_xml.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_usage.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_json_enc.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_user.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_bucket.cc\ @WITH_RADOSGW_TRUE@ rgw/rgw_tools.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rados.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_http_client.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_client.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_conn.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_op.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_common.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_cache.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_formats.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_log.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_multi.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_policy_s3.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_gc.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_multi_del.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_env.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_cors.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_cors_s3.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_auth_s3.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_metadata.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_replica_log.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_keystone.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_quota.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_dencoder.cc @WITH_RADOSGW_TRUE@librgw_la_CXXFLAGS = -Woverloaded-virtual ${AM_CXXFLAGS} @WITH_RADOSGW_TRUE@CIVETWEB_INCLUDE = --include civetweb/include/civetweb_conf.h @WITH_RADOSGW_TRUE@libcivetweb_la_SOURCES = \ @WITH_RADOSGW_TRUE@ rgw/rgw_civetweb.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_civetweb_log.cc \ @WITH_RADOSGW_TRUE@ civetweb/src/civetweb.c @WITH_RADOSGW_TRUE@libcivetweb_la_CXXFLAGS = ${CIVETWEB_INCLUDE} -Woverloaded-virtual ${AM_CXXFLAGS} @WITH_RADOSGW_TRUE@libcivetweb_la_CFLAGS = -Icivetweb/include ${CIVETWEB_INCLUDE} @WITH_RADOSGW_TRUE@radosgw_SOURCES = \ @WITH_RADOSGW_TRUE@ rgw/rgw_resolve.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_swift.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_s3.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_usage.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_user.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_bucket.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_metadata.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_replica_log.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_log.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_opstate.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_replica_log.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_rest_config.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_http_client.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_swift.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_swift_auth.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_loadgen.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_main.cc @WITH_RADOSGW_TRUE@radosgw_CFLAGS = -I$(srcdir)/civetweb/include @WITH_RADOSGW_TRUE@radosgw_LDADD = $(LIBRGW) $(LIBCIVETWEB) $(LIBRGW_DEPS) $(RESOLV_LIBS) $(CEPH_GLOBAL) @WITH_RADOSGW_TRUE@radosgw_admin_SOURCES = rgw/rgw_admin.cc @WITH_RADOSGW_TRUE@radosgw_admin_LDADD = $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) @WITH_RADOSGW_TRUE@ceph_rgw_multiparser_SOURCES = rgw/rgw_multiparser.cc @WITH_RADOSGW_TRUE@ceph_rgw_multiparser_LDADD = $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) @WITH_RADOSGW_TRUE@ceph_rgw_jsonparser_SOURCES = \ @WITH_RADOSGW_TRUE@ rgw/rgw_jsonparser.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_common.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_env.cc \ @WITH_RADOSGW_TRUE@ rgw/rgw_json_enc.cc @WITH_RADOSGW_TRUE@ceph_rgw_jsonparser_LDADD = $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) libcls_hello_la_SOURCES = cls/hello/cls_hello.cc libcls_hello_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_hello_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_rbd_la_SOURCES = cls/rbd/cls_rbd.cc libcls_rbd_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_rbd_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_lock_la_SOURCES = cls/lock/cls_lock.cc libcls_lock_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_lock_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_refcount_la_SOURCES = \ cls/refcount/cls_refcount.cc \ cls/refcount/cls_refcount_ops.cc \ common/ceph_json.cc libcls_refcount_la_LIBADD = libjson_spirit.la $(PTHREAD_LIBS) $(EXTRALIBS) libcls_refcount_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_version_la_SOURCES = cls/version/cls_version.cc libcls_version_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_version_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_log_la_SOURCES = cls/log/cls_log.cc libcls_log_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_log_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_statelog_la_SOURCES = cls/statelog/cls_statelog.cc libcls_statelog_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_statelog_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_replica_log_la_SOURCES = cls/replica_log/cls_replica_log.cc libcls_replica_log_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_replica_log_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_user_la_SOURCES = cls/user/cls_user.cc libcls_user_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libcls_user_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '.*__cls_.*' libcls_rgw_la_SOURCES = \ cls/rgw/cls_rgw.cc \ cls/rgw/cls_rgw_ops.cc \ cls/rgw/cls_rgw_types.cc \ common/ceph_json.cc libcls_rgw_la_LIBADD = libjson_spirit.la $(PTHREAD_LIBS) $(EXTRALIBS) libcls_rgw_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' libcls_lock_client_la_SOURCES = \ cls/lock/cls_lock_client.cc \ cls/lock/cls_lock_types.cc \ cls/lock/cls_lock_ops.cc libcls_refcount_client_la_SOURCES = \ cls/refcount/cls_refcount_client.cc \ cls/refcount/cls_refcount_ops.cc libcls_version_client_a_SOURCES = \ cls/version/cls_version_client.cc \ cls/version/cls_version_types.cc libcls_log_client_a_SOURCES = cls/log/cls_log_client.cc libcls_statelog_client_a_SOURCES = cls/statelog/cls_statelog_client.cc libcls_replica_log_client_a_SOURCES = \ cls/replica_log/cls_replica_log_types.cc \ cls/replica_log/cls_replica_log_ops.cc \ cls/replica_log/cls_replica_log_client.cc libcls_rgw_client_la_SOURCES = \ cls/rgw/cls_rgw_client.cc \ cls/rgw/cls_rgw_types.cc \ cls/rgw/cls_rgw_ops.cc libcls_rbd_client_la_SOURCES = cls/rbd/cls_rbd_client.cc libcls_user_client_a_SOURCES = cls/user/cls_user_client.cc \ cls/user/cls_user_types.cc \ cls/user/cls_user_ops.cc @LINUX_TRUE@libcls_kvs_la_SOURCES = key_value_store/cls_kvs.cc @LINUX_TRUE@libcls_kvs_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) @LINUX_TRUE@libcls_kvs_la_LDFLAGS = ${AM_LDFLAGS} -module -avoid-version -shared -export-symbols-regex '.*__cls_.*' ceph_erasure_code_benchmark_SOURCES = \ test/erasure-code/ceph_erasure_code_benchmark.cc ceph_erasure_code_benchmark_LDADD = $(LIBOSD) $(LIBCOMMON) \ $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) $(am__append_41) ceph_erasure_code_non_regression_SOURCES = \ test/erasure-code/ceph_erasure_code_non_regression.cc ceph_erasure_code_non_regression_LDADD = $(LIBOSD) $(LIBCOMMON) \ $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) $(am__append_42) ceph_erasure_code_SOURCES = \ test/erasure-code/ceph_erasure_code.cc ceph_erasure_code_LDADD = $(LIBOSD) $(LIBCOMMON) \ $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) $(am__append_43) libec_example_la_SOURCES = test/erasure-code/ErasureCodePluginExample.cc libec_example_la_CFLAGS = ${AM_CFLAGS} libec_example_la_CXXFLAGS = ${AM_CXXFLAGS} libec_example_la_LIBADD = $(LIBCRUSH) $(PTHREAD_LIBS) $(EXTRALIBS) libec_example_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_missing_entry_point_la_SOURCES = test/erasure-code/ErasureCodePluginMissingEntryPoint.cc libec_missing_entry_point_la_CFLAGS = ${AM_CFLAGS} libec_missing_entry_point_la_CXXFLAGS = ${AM_CXXFLAGS} libec_missing_entry_point_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_missing_entry_point_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_hangs_la_SOURCES = test/erasure-code/ErasureCodePluginHangs.cc libec_hangs_la_CFLAGS = ${AM_CFLAGS} libec_hangs_la_CXXFLAGS = ${AM_CXXFLAGS} libec_hangs_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_hangs_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_fail_to_initialize_la_SOURCES = test/erasure-code/ErasureCodePluginFailToInitialize.cc libec_fail_to_initialize_la_CFLAGS = ${AM_CFLAGS} libec_fail_to_initialize_la_CXXFLAGS = ${AM_CXXFLAGS} libec_fail_to_initialize_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_fail_to_initialize_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_fail_to_register_la_SOURCES = test/erasure-code/ErasureCodePluginFailToRegister.cc libec_fail_to_register_la_CFLAGS = ${AM_CFLAGS} libec_fail_to_register_la_CXXFLAGS = ${AM_CXXFLAGS} libec_fail_to_register_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_fail_to_register_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_test_jerasure_sse4_la_SOURCES = test/erasure-code/TestJerasurePluginSSE4.cc libec_test_jerasure_sse4_la_CFLAGS = ${AM_CFLAGS} libec_test_jerasure_sse4_la_CXXFLAGS = ${AM_CXXFLAGS} libec_test_jerasure_sse4_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_test_jerasure_sse4_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_test_jerasure_sse3_la_SOURCES = test/erasure-code/TestJerasurePluginSSE3.cc libec_test_jerasure_sse3_la_CFLAGS = ${AM_CFLAGS} libec_test_jerasure_sse3_la_CXXFLAGS = ${AM_CXXFLAGS} libec_test_jerasure_sse3_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_test_jerasure_sse3_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' libec_test_jerasure_generic_la_SOURCES = test/erasure-code/TestJerasurePluginGeneric.cc libec_test_jerasure_generic_la_CFLAGS = ${AM_CFLAGS} libec_test_jerasure_generic_la_CXXFLAGS = ${AM_CXXFLAGS} libec_test_jerasure_generic_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS) libec_test_jerasure_generic_la_LDFLAGS = ${AM_LDFLAGS} -export-symbols-regex '.*__erasure_code_.*' unittest_erasure_code_plugin_SOURCES = test/erasure-code/TestErasureCodePlugin.cc unittest_erasure_code_plugin_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_erasure_code_plugin_LDADD = $(LIBOSD) $(LIBCOMMON) \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(am__append_44) unittest_erasure_code_jerasure_SOURCES = \ test/erasure-code/TestErasureCodeJerasure.cc \ ${jerasure_sources} unittest_erasure_code_jerasure_CFLAGS = $(AM_CFLAGS) \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include unittest_erasure_code_jerasure_CXXFLAGS = $(UNITTEST_CXXFLAGS) \ -Ierasure-code/jerasure/gf-complete/include \ -Ierasure-code/jerasure/jerasure/include unittest_erasure_code_jerasure_LDADD = $(LIBOSD) $(LIBCOMMON) \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(am__append_45) unittest_erasure_code_plugin_jerasure_SOURCES = \ test/erasure-code/TestErasureCodePluginJerasure.cc unittest_erasure_code_plugin_jerasure_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS} unittest_erasure_code_plugin_jerasure_LDADD = $(LIBOSD) $(LIBCOMMON) \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(am__append_46) unittest_erasure_code_example_SOURCES = test/erasure-code/TestErasureCodeExample.cc unittest_erasure_code_example_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_erasure_code_example_LDADD = $(LIBOSD) $(LIBCOMMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_timers_SOURCES = test/TestTimers.cc ceph_test_timers_LDADD = $(CEPH_GLOBAL) ceph_test_signal_handlers_SOURCES = test/TestSignalHandlers.cc ceph_test_signal_handlers_LDADD = $(CEPH_GLOBAL) ceph_test_rados_SOURCES = \ test/osd/TestRados.cc \ test/osd/TestOpStat.cc \ test/osd/Object.cc \ test/osd/RadosModel.cc ceph_test_rados_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) ceph_test_mutate_SOURCES = test/test_mutate.cc ceph_test_mutate_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) ceph_test_rewrite_latency_SOURCES = test/test_rewrite_latency.cc ceph_test_rewrite_latency_LDADD = $(LIBCOMMON) $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) ceph_test_msgr_SOURCES = test/testmsgr.cc ceph_test_msgr_LDADD = $(CEPH_GLOBAL) ceph_streamtest_SOURCES = test/streamtest.cc ceph_streamtest_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_test_trans_SOURCES = test/test_trans.cc ceph_test_trans_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_test_crypto_SOURCES = test/testcrypto.cc ceph_test_crypto_LDADD = $(CEPH_GLOBAL) ceph_test_keys_SOURCES = test/testkeys.cc ceph_test_keys_LDADD = $(LIBMON) $(CEPH_GLOBAL) ceph_dencoder_SOURCES = \ test/encoding/ceph_dencoder.cc \ $(DENCODER_SOURCES) ceph_dencoder_LDADD = \ $(LIBOSD_TYPES) \ $(LIBOS_TYPES) \ $(LIBMDS) \ $(LIBMON_TYPES) \ $(DENCODER_DEPS) \ $(CEPH_GLOBAL) # These should always use explicit _CFLAGS/_CXXFLAGS so avoid basename conflicts ceph_dencoder_CFLAGS = ${AM_CFLAGS} $(am__append_47) ceph_dencoder_CXXFLAGS = ${AM_CXXFLAGS} $(am__append_48) get_command_descriptions_SOURCES = test/common/get_command_descriptions.cc get_command_descriptions_LDADD = $(LIBMON) $(LIBCOMMON) $(CEPH_GLOBAL) # These should all use explicit _CXXFLAGS so avoid basename conflicts @WITH_BUILD_TESTS_TRUE@test_build_libcommon_SOURCES = \ @WITH_BUILD_TESTS_TRUE@ test/buildtest_skeleton.cc \ @WITH_BUILD_TESTS_TRUE@ $(libcommon_la_SOURCES) @WITH_BUILD_TESTS_TRUE@test_build_libcommon_LDADD = \ @WITH_BUILD_TESTS_TRUE@ $(LIBCOMMON_DEPS) \ @WITH_BUILD_TESTS_TRUE@ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) @WITH_BUILD_TESTS_TRUE@test_build_libcommon_LDFLAGS = -static-libtool-libs @WITH_BUILD_TESTS_TRUE@test_build_libcommon_CFLAGS = $(AM_CFLAGS) @WITH_BUILD_TESTS_TRUE@test_build_libcommon_CXXFLAGS = $(AM_CXXFLAGS) @WITH_BUILD_TESTS_TRUE@test_build_librados_SOURCES = \ @WITH_BUILD_TESTS_TRUE@ test/buildtest_skeleton.cc \ @WITH_BUILD_TESTS_TRUE@ $(librados_la_SOURCES) @WITH_BUILD_TESTS_TRUE@test_build_librados_LDADD = \ @WITH_BUILD_TESTS_TRUE@ $(LIBRADOS_DEPS) \ @WITH_BUILD_TESTS_TRUE@ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) @WITH_BUILD_TESTS_TRUE@test_build_librados_LDFLAGS = -static-libtool-libs @WITH_BUILD_TESTS_TRUE@test_build_librados_CFLAGS = $(AM_CFLAGS) @WITH_BUILD_TESTS_TRUE@test_build_librados_CXXFLAGS = $(AM_CXXFLAGS) @WITH_BUILD_TESTS_TRUE@test_build_librgw_SOURCES = \ @WITH_BUILD_TESTS_TRUE@ test/buildtest_skeleton.cc \ @WITH_BUILD_TESTS_TRUE@ $(librgw_la_SOURCES) @WITH_BUILD_TESTS_TRUE@test_build_librgw_LDADD = \ @WITH_BUILD_TESTS_TRUE@ $(LIBRGW_DEPS) \ @WITH_BUILD_TESTS_TRUE@ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) \ @WITH_BUILD_TESTS_TRUE@ $(CEPH_GLOBAL) @WITH_BUILD_TESTS_TRUE@test_build_librgw_LDFLAGS = -static-libtool-libs @WITH_BUILD_TESTS_TRUE@test_build_librgw_CFLAGS = $(AM_CFLAGS) @WITH_BUILD_TESTS_TRUE@test_build_librgw_CXXFLAGS = $(AM_CXXFLAGS) # I dont get this one... testing the osdc build but link in libcephfs? @WITH_BUILD_TESTS_TRUE@test_build_libcephfs_SOURCES = \ @WITH_BUILD_TESTS_TRUE@ test/buildtest_skeleton.cc \ @WITH_BUILD_TESTS_TRUE@ $(libosdc_la_SOURCES) @WITH_BUILD_TESTS_TRUE@test_build_libcephfs_LDADD = \ @WITH_BUILD_TESTS_TRUE@ $(LIBCEPHFS) -lexpat \ @WITH_BUILD_TESTS_TRUE@ $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) @WITH_BUILD_TESTS_TRUE@test_build_libcephfs_LDFLAGS = -static-libtool-libs @WITH_BUILD_TESTS_TRUE@test_build_libcephfs_CFLAGS = $(AM_CFLAGS) @WITH_BUILD_TESTS_TRUE@test_build_libcephfs_CXXFLAGS = $(AM_CXXFLAGS) ceph_smalliobench_SOURCES = \ test/bench/small_io_bench.cc \ test/bench/rados_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobench_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) ceph_smalliobenchfs_SOURCES = \ test/bench/small_io_bench_fs.cc \ test/bench/testfilestore_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobenchfs_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBOS) $(CEPH_GLOBAL) ceph_smalliobenchdumb_SOURCES = \ test/bench/small_io_bench_dumb.cc \ test/bench/dumb_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobenchdumb_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBOS) $(CEPH_GLOBAL) ceph_smalliobenchrbd_SOURCES = \ test/bench/small_io_bench_rbd.cc \ test/bench/rbd_backend.cc \ test/bench/detailed_stat_collector.cc \ test/bench/bencher.cc ceph_smalliobenchrbd_LDADD = $(LIBRBD) $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(CEPH_GLOBAL) ceph_tpbench_SOURCES = \ test/bench/tp_bench.cc \ test/bench/detailed_stat_collector.cc ceph_tpbench_LDADD = $(LIBRADOS) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBOS) $(CEPH_GLOBAL) ceph_omapbench_SOURCES = test/omap_bench.cc ceph_omapbench_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) @LINUX_TRUE@ceph_kvstorebench_SOURCES = \ @LINUX_TRUE@ test/kv_store_bench.cc \ @LINUX_TRUE@ key_value_store/kv_flat_btree_async.cc @LINUX_TRUE@ceph_kvstorebench_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) @LINUX_TRUE@libsystest_la_SOURCES = \ @LINUX_TRUE@ test/system/cross_process_sem.cc \ @LINUX_TRUE@ test/system/systest_runnable.cc \ @LINUX_TRUE@ test/system/systest_settings.cc @LINUX_TRUE@libsystest_la_LIBADD = $(CEPH_GLOBAL) @LINUX_TRUE@ceph_test_rados_list_parallel_SOURCES = \ @LINUX_TRUE@ test/system/rados_list_parallel.cc \ @LINUX_TRUE@ test/system/st_rados_create_pool.cc \ @LINUX_TRUE@ test/system/st_rados_list_objects.cc @LINUX_TRUE@ceph_test_rados_list_parallel_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) @LINUX_TRUE@ceph_test_rados_open_pools_parallel_SOURCES = \ @LINUX_TRUE@ test/system/rados_open_pools_parallel.cc \ @LINUX_TRUE@ test/system/st_rados_create_pool.cc @LINUX_TRUE@ceph_test_rados_open_pools_parallel_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) @LINUX_TRUE@ceph_test_rados_delete_pools_parallel_SOURCES = \ @LINUX_TRUE@ test/system/rados_delete_pools_parallel.cc \ @LINUX_TRUE@ test/system/st_rados_create_pool.cc \ @LINUX_TRUE@ test/system/st_rados_delete_pool.cc \ @LINUX_TRUE@ test/system/st_rados_list_objects.cc @LINUX_TRUE@ceph_test_rados_delete_pools_parallel_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) @LINUX_TRUE@ceph_test_rados_watch_notify_SOURCES = \ @LINUX_TRUE@ test/system/rados_watch_notify.cc \ @LINUX_TRUE@ test/system/st_rados_create_pool.cc \ @LINUX_TRUE@ test/system/st_rados_delete_pool.cc \ @LINUX_TRUE@ test/system/st_rados_delete_objs.cc \ @LINUX_TRUE@ test/system/st_rados_watch.cc \ @LINUX_TRUE@ test/system/st_rados_notify.cc @LINUX_TRUE@ceph_test_rados_watch_notify_LDADD = $(LIBRADOS) libsystest.la $(PTHREAD_LIBS) ceph_bench_log_SOURCES = test/bench_log.cc ceph_bench_log_LDADD = $(CEPH_GLOBAL) UNITTEST_CXXFLAGS = \ $(AM_CXXFLAGS) \ -I$(top_srcdir)/src/gtest/include \ -I$(top_builddir)/src/gtest/include UNITTEST_LDADD = \ $(top_builddir)/src/gtest/lib/libgtest.a \ $(top_builddir)/src/gtest/lib/libgtest_main.a \ $(PTHREAD_LIBS) unittest_encoding_SOURCES = test/encoding.cc unittest_encoding_LDADD = $(LIBCEPHFS) $(LIBRADOS) -lm $(UNITTEST_LDADD) unittest_encoding_CXXFLAGS = $(UNITTEST_CXXFLAGS) -fno-strict-aliasing unittest_addrs_SOURCES = test/test_addrs.cc unittest_addrs_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_addrs_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_bloom_filter_SOURCES = test/common/test_bloom_filter.cc unittest_bloom_filter_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_bloom_filter_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_histogram_SOURCES = test/common/histogram.cc unittest_histogram_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_histogram_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_str_map_SOURCES = test/common/test_str_map.cc unittest_str_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_str_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_sharedptr_registry_SOURCES = test/common/test_sharedptr_registry.cc unittest_sharedptr_registry_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_sharedptr_registry_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_sloppy_crc_map_SOURCES = test/common/test_sloppy_crc_map.cc unittest_sloppy_crc_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_sloppy_crc_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_util_SOURCES = test/common/test_util.cc unittest_util_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_util_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CRYPTO_LIBS) $(EXTRALIBS) unittest_crush_indep_SOURCES = test/crush/indep.cc unittest_crush_indep_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_crush_indep_LDADD = $(LIBCOMMON) -lm $(UNITTEST_LDADD) $(CEPH_CRUSH) $(EXTRALIBS) $(CEPH_GLOBAL) unittest_osdmap_SOURCES = test/osd/TestOSDMap.cc unittest_osdmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osdmap_LDADD = $(UNITTEST_LDADD) $(LIBCOMMON) $(CEPH_GLOBAL) unittest_workqueue_SOURCES = test/test_workqueue.cc unittest_workqueue_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_workqueue_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_striper_SOURCES = test/test_striper.cc unittest_striper_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_striper_LDADD = $(LIBOSDC) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_prebufferedstreambuf_SOURCES = test/test_prebufferedstreambuf.cc unittest_prebufferedstreambuf_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_prebufferedstreambuf_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) $(EXTRALIBS) unittest_str_list_SOURCES = test/test_str_list.cc unittest_str_list_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_str_list_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_log_SOURCES = log/test.cc unittest_log_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) unittest_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 unittest_throttle_SOURCES = test/common/Throttle.cc unittest_throttle_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_throttle_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 unittest_crush_wrapper_SOURCES = test/crush/TestCrushWrapper.cc unittest_crush_wrapper_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(LIBCRUSH) unittest_crush_wrapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) -O2 unittest_base64_SOURCES = test/base64.cc unittest_base64_LDADD = $(LIBCEPHFS) -lm $(UNITTEST_LDADD) unittest_base64_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_ceph_argparse_SOURCES = test/ceph_argparse.cc unittest_ceph_argparse_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_argparse_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_ceph_compatset_SOURCES = test/ceph_compatset.cc unittest_ceph_compatset_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_compatset_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osd_types_SOURCES = test/osd/types.cc unittest_osd_types_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osd_types_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_pglog_SOURCES = test/osd/TestPGLog.cc unittest_pglog_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_pglog_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) \ $(am__append_52) unittest_ecbackend_SOURCES = test/osd/TestECBackend.cc unittest_ecbackend_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_ecbackend_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_hitset_SOURCES = test/osd/hitset.cc unittest_hitset_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_hitset_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_io_priority_SOURCES = test/common/test_io_priority.cc unittest_io_priority_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_io_priority_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_gather_SOURCES = test/gather.cc unittest_gather_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_gather_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_run_cmd_SOURCES = test/run_cmd.cc unittest_run_cmd_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) unittest_run_cmd_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_signals_SOURCES = test/signals.cc unittest_signals_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_signals_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_simple_spin_SOURCES = test/simple_spin.cc unittest_simple_spin_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) unittest_simple_spin_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_librados_SOURCES = test/librados/librados.cc unittest_librados_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) unittest_librados_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_bufferlist_SOURCES = test/bufferlist.cc unittest_bufferlist_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_bufferlist_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_crc32c_SOURCES = test/common/test_crc32c.cc unittest_crc32c_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_crc32c_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_arch_SOURCES = test/test_arch.cc unittest_arch_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_arch_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_crypto_SOURCES = test/crypto.cc unittest_crypto_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_crypto_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_crypto_init_SOURCES = test/crypto_init.cc unittest_crypto_init_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_crypto_init_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_perf_counters_SOURCES = test/perf_counters.cc unittest_perf_counters_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_perf_counters_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_admin_socket_SOURCES = test/admin_socket.cc unittest_admin_socket_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_admin_socket_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_ceph_crypto_SOURCES = test/ceph_crypto.cc unittest_ceph_crypto_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ceph_crypto_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_utf8_SOURCES = test/utf8.cc unittest_utf8_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_utf8_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_mime_SOURCES = test/mime.cc unittest_mime_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_mime_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_escape_SOURCES = test/escape.cc unittest_escape_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_escape_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_chain_xattr_SOURCES = test/objectstore/chain_xattr.cc unittest_chain_xattr_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_chain_xattr_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_flatindex_SOURCES = test/os/TestFlatIndex.cc unittest_flatindex_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_flatindex_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_strtol_SOURCES = test/strtol.cc unittest_strtol_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_strtol_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_confutils_SOURCES = test/confutils.cc unittest_confutils_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_confutils_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_config_SOURCES = test/common/test_config.cc unittest_config_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_context_SOURCES = test/common/test_context.cc unittest_context_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_context_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_heartbeatmap_SOURCES = test/heartbeat_map.cc unittest_heartbeatmap_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_heartbeatmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) # why does this include rgw/rgw_formats.cc...? unittest_formatter_SOURCES = \ test/formatter.cc \ rgw/rgw_formats.cc unittest_formatter_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_formatter_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_libcephfs_config_SOURCES = test/libcephfs_config.cc unittest_libcephfs_config_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) unittest_libcephfs_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_lfnindex_SOURCES = test/os/TestLFNIndex.cc unittest_lfnindex_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_lfnindex_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_librados_config_SOURCES = test/librados/librados_config.cc unittest_librados_config_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) unittest_librados_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) #unittest_librgw_link_SOURCES = test/librgw_link.cc #unittest_librgw_link_LDFLAGS = $(PTHREAD_CFLAGS) ${AM_LDFLAGS} #unittest_librgw_link_LDADD = $(LIBRGW) ${UNITTEST_LDADD} #unittest_librgw_link_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS} #check_PROGRAMS += unittest_librgw_link unittest_daemon_config_SOURCES = test/daemon_config.cc unittest_daemon_config_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_daemon_config_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_osd_osdcap_SOURCES = test/osd/osdcap.cc unittest_osd_osdcap_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_osd_osdcap_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_mon_moncap_SOURCES = test/mon/moncap.cc unittest_mon_moncap_LDADD = $(LIBMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_mon_moncap_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_mon_pgmap_SOURCES = test/mon/PGMap.cc unittest_mon_pgmap_LDADD = $(LIBMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_mon_pgmap_CXXFLAGS = $(UNITTEST_CXXFLAGS) #if WITH_RADOSGW #unittest_librgw_SOURCES = test/librgw.cc #unittest_librgw_LDFLAGS = -lrt $(PTHREAD_CFLAGS) -lcurl ${AM_LDFLAGS} #unittest_librgw_LDADD = librgw.la $(LIBRADOS) ${UNITTEST_LDADD} -lexpat $(CEPH_GLOBAL) #unittest_librgw_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS} #check_PROGRAMS += unittest_librgw #endif # WITH_RADOSGW unittest_ipaddr_SOURCES = test/test_ipaddr.cc unittest_ipaddr_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL) unittest_ipaddr_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_texttable_SOURCES = test/test_texttable.cc unittest_texttable_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) unittest_texttable_CXXFLAGS = $(UNITTEST_CXXFLAGS) unittest_on_exit_SOURCES = test/on_exit.cc unittest_on_exit_LDADD = $(PTHREAD_LIBS) @WITH_RADOSGW_TRUE@ceph_test_cors_SOURCES = test/test_cors.cc @WITH_RADOSGW_TRUE@ceph_test_cors_LDADD = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ @WITH_RADOSGW_TRUE@ $(UNITTEST_LDADD) \ @WITH_RADOSGW_TRUE@ -lcurl -luuid -lexpat @WITH_RADOSGW_TRUE@ceph_test_cors_CXXFLAGS = $(UNITTEST_CXXFLAGS) @WITH_RADOSGW_TRUE@ceph_test_rgw_manifest_SOURCES = test/rgw/test_rgw_manifest.cc @WITH_RADOSGW_TRUE@ceph_test_rgw_manifest_LDADD = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) \ @WITH_RADOSGW_TRUE@ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ @WITH_RADOSGW_TRUE@ -lcurl -luuid -lexpat @WITH_RADOSGW_TRUE@ceph_test_rgw_manifest_CXXFLAGS = $(UNITTEST_CXXFLAGS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_meta_SOURCES = test/test_rgw_admin_meta.cc @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_meta_LDADD = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ @WITH_RADOSGW_TRUE@ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ @WITH_RADOSGW_TRUE@ -lcurl -luuid -lexpat \ @WITH_RADOSGW_TRUE@ libcls_version_client.a libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_meta_CXXFLAGS = $(UNITTEST_CXXFLAGS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_log_SOURCES = test/test_rgw_admin_log.cc @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_log_LDADD = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ @WITH_RADOSGW_TRUE@ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ @WITH_RADOSGW_TRUE@ -lcurl -luuid -lexpat \ @WITH_RADOSGW_TRUE@ libcls_version_client.a libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_opstate_SOURCES = test/test_rgw_admin_opstate.cc @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_opstate_LDADD = \ @WITH_RADOSGW_TRUE@ $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ @WITH_RADOSGW_TRUE@ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ @WITH_RADOSGW_TRUE@ -lcurl -luuid -lexpat \ @WITH_RADOSGW_TRUE@ libcls_version_client.a libcls_log_client.a \ @WITH_RADOSGW_TRUE@ libcls_statelog_client.a libcls_refcount_client.la \ @WITH_RADOSGW_TRUE@ libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_opstate_CXXFLAGS = $(UNITTEST_CXXFLAGS) libradostest_la_SOURCES = \ test/librados/test.cc \ test/librados/TestCase.cc libradostest_la_CXXFLAGS = $(UNITTEST_CXXFLAGS) RADOS_TEST_LDADD = libradostest.la ceph_multi_stress_watch_SOURCES = test/multi_stress_watch.cc ceph_multi_stress_watch_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_librbd_SOURCES = test/librbd/test_librbd.cc ceph_test_librbd_LDADD = $(LIBRBD) $(LIBRADOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_librbd_CXXFLAGS = $(UNITTEST_CXXFLAGS) @LINUX_TRUE@ceph_test_librbd_fsx_SOURCES = test/librbd/fsx.c @LINUX_TRUE@ceph_test_librbd_fsx_LDADD = $(LIBRBD) $(LIBRADOS) -lm @LINUX_TRUE@ceph_test_librbd_fsx_CFLAGS = ${AM_CFLAGS} ceph_test_cls_rbd_SOURCES = test/cls_rbd/test_cls_rbd.cc ceph_test_cls_rbd_LDADD = $(LIBRADOS) libcls_rbd_client.la libcls_lock_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_rbd_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_refcount_SOURCES = test/cls_refcount/test_cls_refcount.cc ceph_test_cls_refcount_LDADD = $(LIBRADOS) libcls_refcount_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_refcount_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_version_SOURCES = test/cls_version/test_cls_version.cc ceph_test_cls_version_LDADD = $(LIBRADOS) libcls_version_client.a $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_version_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_log_SOURCES = test/cls_log/test_cls_log.cc ceph_test_cls_log_LDADD = $(LIBRADOS) libcls_log_client.a $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_statelog_SOURCES = test/cls_statelog/test_cls_statelog.cc ceph_test_cls_statelog_LDADD = $(LIBRADOS) libcls_statelog_client.a $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_statelog_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_replica_log_SOURCES = test/cls_replica_log/test_cls_replica_log.cc ceph_test_cls_replica_log_LDADD = \ $(LIBRADOS) libcls_replica_log_client.a \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_replica_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_lock_SOURCES = test/cls_lock/test_cls_lock.cc ceph_test_cls_lock_LDADD = $(LIBRADOS) libcls_lock_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_cls_lock_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cls_hello_SOURCES = test/cls_hello/test_cls_hello.cc ceph_test_cls_hello_LDADD = \ $(LIBRADOS) $(CRYPTO_LIBS) \ $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_cls_hello_CXXFLAGS = $(UNITTEST_CXXFLAGS) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_SOURCES = test/cls_rgw/test_cls_rgw.cc @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_LDADD = $(LIBRADOS) libcls_rgw_client.la $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) @WITH_RADOSGW_TRUE@ceph_test_cls_rgw_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_mon_workloadgen_SOURCES = test/mon/test_mon_workloadgen.cc ceph_test_mon_workloadgen_LDADD = $(LIBOS) $(LIBOSDC) $(CEPH_GLOBAL) ceph_test_rados_api_cmd_SOURCES = test/librados/cmd.cc ceph_test_rados_api_cmd_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_cmd_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_io_SOURCES = test/librados/io.cc ceph_test_rados_api_io_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_io_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_c_write_operations_SOURCES = \ test/librados/c_write_operations.cc ceph_test_rados_api_c_write_operations_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_c_write_operations_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_c_read_operations_SOURCES = \ test/librados/c_read_operations.cc ceph_test_rados_api_c_read_operations_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_c_read_operations_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_aio_SOURCES = test/librados/aio.cc ceph_test_rados_api_aio_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_aio_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_list_SOURCES = test/librados/list.cc ceph_test_rados_api_list_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_list_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_pool_SOURCES = test/librados/pool.cc ceph_test_rados_api_pool_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_pool_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_stat_SOURCES = test/librados/stat.cc ceph_test_rados_api_stat_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_stat_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_watch_notify_SOURCES = test/librados/watch_notify.cc ceph_test_rados_api_watch_notify_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_watch_notify_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_snapshots_SOURCES = test/librados/snapshots.cc ceph_test_rados_api_snapshots_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_snapshots_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_cls_SOURCES = test/librados/cls.cc ceph_test_rados_api_cls_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_cls_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_misc_SOURCES = test/librados/misc.cc ceph_test_rados_api_misc_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_rados_api_misc_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_tier_SOURCES = \ test/librados/tier.cc \ osd/HitSet.cc ceph_test_rados_api_tier_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) $(RADOS_TEST_LDADD) ceph_test_rados_api_tier_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_rados_api_lock_SOURCES = test/librados/lock.cc ceph_test_rados_api_lock_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_rados_api_lock_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_libcephfs_SOURCES = \ test/libcephfs/test.cc \ test/libcephfs/readdir_r_cb.cc \ test/libcephfs/caps.cc \ test/libcephfs/multiclient.cc ceph_test_libcephfs_LDADD = $(LIBCEPHFS) $(UNITTEST_LDADD) ceph_test_libcephfs_CXXFLAGS = $(UNITTEST_CXXFLAGS) @LINUX_TRUE@ceph_test_objectstore_SOURCES = test/objectstore/store_test.cc @LINUX_TRUE@ceph_test_objectstore_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) @LINUX_TRUE@ceph_test_objectstore_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_objectstore_workloadgen_SOURCES = \ test/objectstore/workload_generator.cc \ test/objectstore/TestObjectStoreState.cc ceph_test_objectstore_workloadgen_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_test_filestore_idempotent_SOURCES = \ test/objectstore/test_idempotent.cc \ test/objectstore/FileStoreTracker.cc \ test/common/ObjectContents.cc ceph_test_filestore_idempotent_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_test_filestore_idempotent_sequence_SOURCES = \ test/objectstore/test_idempotent_sequence.cc \ test/objectstore/DeterministicOpSequence.cc \ test/objectstore/TestObjectStoreState.cc \ test/objectstore/FileStoreDiff.cc ceph_test_filestore_idempotent_sequence_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_xattr_bench_SOURCES = test/xattr_bench.cc ceph_xattr_bench_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_xattr_bench_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_filejournal_SOURCES = test/test_filejournal.cc ceph_test_filejournal_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_filejournal_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_stress_watch_SOURCES = test/test_stress_watch.cc ceph_test_stress_watch_LDADD = $(LIBRADOS) $(UNITTEST_LDADD) $(RADOS_TEST_LDADD) ceph_test_stress_watch_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_objectcacher_stress_SOURCES = \ test/osdc/object_cacher_stress.cc \ test/osdc/FakeWriteback.cc ceph_test_objectcacher_stress_LDADD = $(LIBOSDC) $(CEPH_GLOBAL) ceph_test_snap_mapper_SOURCES = test/test_snap_mapper.cc ceph_test_snap_mapper_LDADD = $(LIBOSD) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_snap_mapper_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_object_map_SOURCES = \ test/ObjectMap/test_object_map.cc \ test/ObjectMap/KeyValueDBMemory.cc ceph_test_object_map_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_object_map_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_keyvaluedb_atomicity_SOURCES = test/ObjectMap/test_keyvaluedb_atomicity.cc ceph_test_keyvaluedb_atomicity_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_keyvaluedb_atomicity_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_keyvaluedb_iterators_SOURCES = \ test/ObjectMap/test_keyvaluedb_iterators.cc \ test/ObjectMap/KeyValueDBMemory.cc ceph_test_keyvaluedb_iterators_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL) ceph_test_keyvaluedb_iterators_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_test_cfuse_cache_invalidate_SOURCES = test/test_cfuse_cache_invalidate.cc ceph_test_c_headers_SOURCES = test/test_c_headers.c ceph_test_c_headers_LDADD = $(LIBRADOS) $(LIBCEPHFS) ceph_test_get_blkdev_size_SOURCES = test/test_get_blkdev_size.cc ceph_test_get_blkdev_size_LDADD = $(LIBCOMMON) ceph_osdomap_tool_SOURCES = tools/ceph_osdomap_tool.cc ceph_osdomap_tool_LDADD = $(LIBOS) $(CEPH_GLOBAL) $(BOOST_PROGRAM_OPTIONS_LIBS) ceph_monstore_tool_SOURCES = tools/ceph_monstore_tool.cc ceph_monstore_tool_LDADD = $(LIBOS) $(CEPH_GLOBAL) $(BOOST_PROGRAM_OPTIONS_LIBS) ceph_kvstore_tool_SOURCES = tools/ceph_kvstore_tool.cc ceph_kvstore_tool_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_kvstore_tool_CXXFLAGS = $(UNITTEST_CXXFLAGS) ceph_objectstore_tool_SOURCES = tools/ceph_objectstore_tool.cc ceph_objectstore_tool_LDADD = $(LIBOSD) $(LIBOS) $(CEPH_GLOBAL) \ $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBRADOS) $(am__append_57) monmaptool_SOURCES = tools/monmaptool.cc monmaptool_LDADD = $(CEPH_GLOBAL) $(LIBCOMMON) crushtool_SOURCES = tools/crushtool.cc crushtool_LDADD = $(CEPH_GLOBAL) osdmaptool_SOURCES = tools/osdmaptool.cc osdmaptool_LDADD = $(CEPH_GLOBAL) ceph_scratchtool_SOURCES = tools/scratchtool.c ceph_scratchtool_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) ceph_scratchtoolpp_SOURCES = tools/scratchtoolpp.cc ceph_scratchtoolpp_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) ceph_psim_SOURCES = tools/psim.cc ceph_psim_LDADD = $(CEPH_GLOBAL) ceph_dupstore_SOURCES = tools/dupstore.cc ceph_dupstore_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_radosacl_SOURCES = tools/radosacl.cc ceph_radosacl_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) ceph_client_debug_SOURCES = tools/ceph-client-debug.cc ceph_client_debug_LDADD = $(LIBCEPHFS) $(CEPH_GLOBAL) $(LIBCOMMON) rados_SOURCES = tools/rados/rados.cc tools/rados/rados_import.cc \ tools/rados/rados_export.cc tools/rados/rados_sync.cc \ common/obj_bencher.cc # needs cleanup so it can go in \ libcommon.la rados_LDADD = libcls_lock_client.la $(LIBRADOS) $(CEPH_GLOBAL) @WITH_REST_BENCH_TRUE@rest_bench_SOURCES = tools/rest_bench.cc \ @WITH_REST_BENCH_TRUE@ common/obj_bencher.cc # needs cleanup so \ @WITH_REST_BENCH_TRUE@ it can go in libcommon.la @WITH_REST_BENCH_TRUE@rest_bench_LDADD = $(CEPH_GLOBAL) \ @WITH_REST_BENCH_TRUE@ $(am__append_59) $(am__append_60) @WITH_REST_BENCH_TRUE@@WITH_SYSTEM_LIBS3_FALSE@rest_bench_CXXFLAGS = ${AM_CXXFLAGS} -I$(top_srcdir)/src/libs3/inc ceph_conf_SOURCES = tools/ceph_conf.cc ceph_conf_LDADD = $(CEPH_GLOBAL) $(LIBCOMMON) ceph_authtool_SOURCES = tools/ceph_authtool.cc ceph_authtool_LDADD = $(CEPH_GLOBAL) $(LIBCOMMON) ceph_mon_store_converter_SOURCES = tools/mon_store_converter.cc ceph_mon_store_converter_LDADD = $(LIBMON) $(LIBOS) $(CEPH_GLOBAL) # subdirs # core daemons ceph_mon_SOURCES = ceph_mon.cc ceph_mon_LDADD = $(LIBMON) $(LIBOS) $(CEPH_GLOBAL) $(LIBCOMMON) ceph_osd_SOURCES = ceph_osd.cc ceph_osd_LDADD = $(LIBOSD) $(CEPH_GLOBAL) $(LIBCOMMON) ceph_mds_SOURCES = ceph_mds.cc ceph_mds_LDADD = $(LIBMDS) $(LIBOSDC) $(CEPH_GLOBAL) $(LIBCOMMON) # admin tools # user tools mount_ceph_SOURCES = mount/mount.ceph.c common/secret.c mount_ceph_LDADD = $(LIBCOMMON) $(KEYUTILS_LIB) cephfs_SOURCES = cephfs.cc cephfs_LDADD = $(LIBCOMMON) librados_config_SOURCES = librados-config.cc librados_config_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) ceph_syn_SOURCES = ceph_syn.cc client/SyntheticClient.cc # uses \ g_conf.. needs cleanup ceph_syn_LDADD = $(LIBCLIENT) $(CEPH_GLOBAL) rbd_SOURCES = rbd.cc common/secret.c rbd_LDADD = $(LIBRBD) $(LIBRADOS) $(CEPH_GLOBAL) -lblkid $(KEYUTILS_LIB) # Fuse targets @WITH_FUSE_TRUE@ceph_fuse_SOURCES = ceph_fuse.cc @WITH_FUSE_TRUE@ceph_fuse_LDADD = $(LIBCLIENT_FUSE) $(CEPH_GLOBAL) @WITH_FUSE_TRUE@rbd_fuse_SOURCES = rbd_fuse/rbd-fuse.c @WITH_FUSE_TRUE@rbd_fuse_LDADD = -lfuse $(LIBRBD) $(LIBRADOS) $(CEPH_GLOBAL) # libcephfs (this should go somewhere else in the future) libcephfs_la_SOURCES = libcephfs.cc libcephfs_la_LIBADD = $(LIBCLIENT) $(LIBCOMMON) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(EXTRALIBS) libcephfs_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '^ceph_.*' # jni library (java source is in src/java) @ENABLE_CEPHFS_JAVA_TRUE@libcephfs_jni_la_SOURCES = \ @ENABLE_CEPHFS_JAVA_TRUE@ java/native/libcephfs_jni.cc \ @ENABLE_CEPHFS_JAVA_TRUE@ java/native/ScopedLocalRef.h \ @ENABLE_CEPHFS_JAVA_TRUE@ java/native/JniConstants.cpp \ @ENABLE_CEPHFS_JAVA_TRUE@ java/native/JniConstants.h @ENABLE_CEPHFS_JAVA_TRUE@libcephfs_jni_la_LIBADD = $(LIBCEPHFS) $(EXTRALIBS) @ENABLE_CEPHFS_JAVA_TRUE@libcephfs_jni_la_CPPFLAGS = $(JDK_CPPFLAGS) $(AM_CPPFLAGS) @ENABLE_CEPHFS_JAVA_TRUE@libcephfs_jni_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 # shell scripts editpaths = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@sbindir[@]|$(sbindir)|g' \ -e 's|@libdir[@]|$(libdir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@datadir[@]|$(pkgdatadir)|g' \ -e 's|@prefix[@]|$(prefix)|g' \ -e 's|@@GCOV_PREFIX_STRIP[@][@]|$(GCOV_PREFIX_STRIP)|g' # coverage shell_scripts = ceph-debugpack ceph-post-file ceph-crush-location \ init-ceph mkcephfs ceph-coverage doc_DATA = $(srcdir)/sample.ceph.conf sample.fetch_config # various scripts shell_commondir = $(libdir)/ceph shell_common_SCRIPTS = ceph_common.sh bash_completiondir = $(sysconfdir)/bash_completion.d bash_completion_DATA = $(srcdir)/bash_completion/ceph \ $(srcdir)/bash_completion/rados \ $(srcdir)/bash_completion/rbd \ $(srcdir)/bash_completion/radosgw-admin ceph_sbin_SCRIPTS = \ ceph-disk \ ceph-disk-prepare \ ceph-disk-activate \ ceph-disk-udev \ ceph-create-keys # tests to actually run on "make check"; if you need extra, non-test, # executables built, you need to replace this with manual assignments # target by target TESTS = \ $(check_PROGRAMS) \ $(check_SCRIPTS) # pybind python_PYTHON = pybind/rados.py \ pybind/rbd.py \ pybind/cephfs.py \ pybind/ceph_argparse.py \ pybind/ceph_rest_api.py @ENABLE_COVERAGE_TRUE@COV_DIR = $(DESTDIR)$(libdir)/ceph/coverage @ENABLE_COVERAGE_TRUE@COV_FILES = $(srcdir)/*.gcno @ENABLE_COVERAGE_TRUE@COV_LIB_FILES = $(srcdir)/.libs/*.gcno all: $(BUILT_SOURCES) acconfig.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .S .c .cc .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/Makefile-env.am $(srcdir)/arch/Makefile.am $(srcdir)/auth/Makefile.am $(srcdir)/brag/Makefile.am $(srcdir)/crush/Makefile.am $(srcdir)/mon/Makefile.am $(srcdir)/mds/Makefile.am $(srcdir)/os/Makefile.am $(srcdir)/osd/Makefile.am $(srcdir)/erasure-code/Makefile.am $(srcdir)/erasure-code/jerasure/Makefile.am $(srcdir)/osdc/Makefile.am $(srcdir)/client/Makefile.am $(srcdir)/global/Makefile.am $(srcdir)/json_spirit/Makefile.am $(srcdir)/log/Makefile.am $(srcdir)/perfglue/Makefile.am $(srcdir)/common/Makefile.am $(srcdir)/msg/Makefile.am $(srcdir)/messages/Makefile.am $(srcdir)/include/Makefile.am $(srcdir)/librados/Makefile.am $(srcdir)/librbd/Makefile.am $(srcdir)/rgw/Makefile.am $(srcdir)/cls/Makefile.am $(srcdir)/key_value_store/Makefile.am $(srcdir)/test/Makefile.am $(srcdir)/test/erasure-code/Makefile.am $(srcdir)/tools/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(srcdir)/Makefile-env.am $(srcdir)/arch/Makefile.am $(srcdir)/auth/Makefile.am $(srcdir)/brag/Makefile.am $(srcdir)/crush/Makefile.am $(srcdir)/mon/Makefile.am $(srcdir)/mds/Makefile.am $(srcdir)/os/Makefile.am $(srcdir)/osd/Makefile.am $(srcdir)/erasure-code/Makefile.am $(srcdir)/erasure-code/jerasure/Makefile.am $(srcdir)/osdc/Makefile.am $(srcdir)/client/Makefile.am $(srcdir)/global/Makefile.am $(srcdir)/json_spirit/Makefile.am $(srcdir)/log/Makefile.am $(srcdir)/perfglue/Makefile.am $(srcdir)/common/Makefile.am $(srcdir)/msg/Makefile.am $(srcdir)/messages/Makefile.am $(srcdir)/include/Makefile.am $(srcdir)/librados/Makefile.am $(srcdir)/librbd/Makefile.am $(srcdir)/rgw/Makefile.am $(srcdir)/cls/Makefile.am $(srcdir)/key_value_store/Makefile.am $(srcdir)/test/Makefile.am $(srcdir)/test/erasure-code/Makefile.am $(srcdir)/tools/Makefile.am: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): acconfig.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/acconfig.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status src/acconfig.h $(srcdir)/acconfig.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f acconfig.h stamp-h1 clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) cls/log/$(am__dirstamp): @$(MKDIR_P) cls/log @: > cls/log/$(am__dirstamp) cls/log/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/log/$(DEPDIR) @: > cls/log/$(DEPDIR)/$(am__dirstamp) cls/log/cls_log_client.$(OBJEXT): cls/log/$(am__dirstamp) \ cls/log/$(DEPDIR)/$(am__dirstamp) libcls_log_client.a: $(libcls_log_client_a_OBJECTS) $(libcls_log_client_a_DEPENDENCIES) $(EXTRA_libcls_log_client_a_DEPENDENCIES) $(AM_V_at)-rm -f libcls_log_client.a $(AM_V_AR)$(libcls_log_client_a_AR) libcls_log_client.a $(libcls_log_client_a_OBJECTS) $(libcls_log_client_a_LIBADD) $(AM_V_at)$(RANLIB) libcls_log_client.a cls/replica_log/$(am__dirstamp): @$(MKDIR_P) cls/replica_log @: > cls/replica_log/$(am__dirstamp) cls/replica_log/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/replica_log/$(DEPDIR) @: > cls/replica_log/$(DEPDIR)/$(am__dirstamp) cls/replica_log/cls_replica_log_types.$(OBJEXT): \ cls/replica_log/$(am__dirstamp) \ cls/replica_log/$(DEPDIR)/$(am__dirstamp) cls/replica_log/cls_replica_log_ops.$(OBJEXT): \ cls/replica_log/$(am__dirstamp) \ cls/replica_log/$(DEPDIR)/$(am__dirstamp) cls/replica_log/cls_replica_log_client.$(OBJEXT): \ cls/replica_log/$(am__dirstamp) \ cls/replica_log/$(DEPDIR)/$(am__dirstamp) libcls_replica_log_client.a: $(libcls_replica_log_client_a_OBJECTS) $(libcls_replica_log_client_a_DEPENDENCIES) $(EXTRA_libcls_replica_log_client_a_DEPENDENCIES) $(AM_V_at)-rm -f libcls_replica_log_client.a $(AM_V_AR)$(libcls_replica_log_client_a_AR) libcls_replica_log_client.a $(libcls_replica_log_client_a_OBJECTS) $(libcls_replica_log_client_a_LIBADD) $(AM_V_at)$(RANLIB) libcls_replica_log_client.a cls/statelog/$(am__dirstamp): @$(MKDIR_P) cls/statelog @: > cls/statelog/$(am__dirstamp) cls/statelog/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/statelog/$(DEPDIR) @: > cls/statelog/$(DEPDIR)/$(am__dirstamp) cls/statelog/cls_statelog_client.$(OBJEXT): \ cls/statelog/$(am__dirstamp) \ cls/statelog/$(DEPDIR)/$(am__dirstamp) libcls_statelog_client.a: $(libcls_statelog_client_a_OBJECTS) $(libcls_statelog_client_a_DEPENDENCIES) $(EXTRA_libcls_statelog_client_a_DEPENDENCIES) $(AM_V_at)-rm -f libcls_statelog_client.a $(AM_V_AR)$(libcls_statelog_client_a_AR) libcls_statelog_client.a $(libcls_statelog_client_a_OBJECTS) $(libcls_statelog_client_a_LIBADD) $(AM_V_at)$(RANLIB) libcls_statelog_client.a cls/user/$(am__dirstamp): @$(MKDIR_P) cls/user @: > cls/user/$(am__dirstamp) cls/user/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/user/$(DEPDIR) @: > cls/user/$(DEPDIR)/$(am__dirstamp) cls/user/cls_user_client.$(OBJEXT): cls/user/$(am__dirstamp) \ cls/user/$(DEPDIR)/$(am__dirstamp) cls/user/cls_user_types.$(OBJEXT): cls/user/$(am__dirstamp) \ cls/user/$(DEPDIR)/$(am__dirstamp) cls/user/cls_user_ops.$(OBJEXT): cls/user/$(am__dirstamp) \ cls/user/$(DEPDIR)/$(am__dirstamp) libcls_user_client.a: $(libcls_user_client_a_OBJECTS) $(libcls_user_client_a_DEPENDENCIES) $(EXTRA_libcls_user_client_a_DEPENDENCIES) $(AM_V_at)-rm -f libcls_user_client.a $(AM_V_AR)$(libcls_user_client_a_AR) libcls_user_client.a $(libcls_user_client_a_OBJECTS) $(libcls_user_client_a_LIBADD) $(AM_V_at)$(RANLIB) libcls_user_client.a cls/version/$(am__dirstamp): @$(MKDIR_P) cls/version @: > cls/version/$(am__dirstamp) cls/version/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/version/$(DEPDIR) @: > cls/version/$(DEPDIR)/$(am__dirstamp) cls/version/cls_version_client.$(OBJEXT): cls/version/$(am__dirstamp) \ cls/version/$(DEPDIR)/$(am__dirstamp) cls/version/cls_version_types.$(OBJEXT): cls/version/$(am__dirstamp) \ cls/version/$(DEPDIR)/$(am__dirstamp) libcls_version_client.a: $(libcls_version_client_a_OBJECTS) $(libcls_version_client_a_DEPENDENCIES) $(EXTRA_libcls_version_client_a_DEPENDENCIES) $(AM_V_at)-rm -f libcls_version_client.a $(AM_V_AR)$(libcls_version_client_a_AR) libcls_version_client.a $(libcls_version_client_a_OBJECTS) $(libcls_version_client_a_LIBADD) $(AM_V_at)$(RANLIB) libcls_version_client.a os/$(am__dirstamp): @$(MKDIR_P) os @: > os/$(am__dirstamp) os/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) os/$(DEPDIR) @: > os/$(DEPDIR)/$(am__dirstamp) os/libos_zfs_a-ZFS.$(OBJEXT): os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) libos_zfs.a: $(libos_zfs_a_OBJECTS) $(libos_zfs_a_DEPENDENCIES) $(EXTRA_libos_zfs_a_DEPENDENCIES) $(AM_V_at)-rm -f libos_zfs.a $(AM_V_AR)$(libos_zfs_a_AR) libos_zfs.a $(libos_zfs_a_OBJECTS) $(libos_zfs_a_LIBADD) $(AM_V_at)$(RANLIB) libos_zfs.a install-erasure_codelibLTLIBRARIES: $(erasure_codelib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(erasure_codelib_LTLIBRARIES)'; test -n "$(erasure_codelibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(erasure_codelibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(erasure_codelibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(erasure_codelibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(erasure_codelibdir)"; \ } uninstall-erasure_codelibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(erasure_codelib_LTLIBRARIES)'; test -n "$(erasure_codelibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(erasure_codelibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(erasure_codelibdir)/$$f"; \ done clean-erasure_codelibLTLIBRARIES: -test -z "$(erasure_codelib_LTLIBRARIES)" || rm -f $(erasure_codelib_LTLIBRARIES) @list='$(erasure_codelib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } install-radoslibLTLIBRARIES: $(radoslib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(radoslib_LTLIBRARIES)'; test -n "$(radoslibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(radoslibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(radoslibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(radoslibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(radoslibdir)"; \ } uninstall-radoslibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(radoslib_LTLIBRARIES)'; test -n "$(radoslibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(radoslibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(radoslibdir)/$$f"; \ done clean-radoslibLTLIBRARIES: -test -z "$(radoslib_LTLIBRARIES)" || rm -f $(radoslib_LTLIBRARIES) @list='$(radoslib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } arch/$(am__dirstamp): @$(MKDIR_P) arch @: > arch/$(am__dirstamp) arch/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) arch/$(DEPDIR) @: > arch/$(DEPDIR)/$(am__dirstamp) arch/intel.lo: arch/$(am__dirstamp) arch/$(DEPDIR)/$(am__dirstamp) arch/neon.lo: arch/$(am__dirstamp) arch/$(DEPDIR)/$(am__dirstamp) arch/probe.lo: arch/$(am__dirstamp) arch/$(DEPDIR)/$(am__dirstamp) libarch.la: $(libarch_la_OBJECTS) $(libarch_la_DEPENDENCIES) $(EXTRA_libarch_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libarch_la_OBJECTS) $(libarch_la_LIBADD) $(LIBS) auth/$(am__dirstamp): @$(MKDIR_P) auth @: > auth/$(am__dirstamp) auth/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) auth/$(DEPDIR) @: > auth/$(DEPDIR)/$(am__dirstamp) auth/AuthAuthorizeHandler.lo: auth/$(am__dirstamp) \ auth/$(DEPDIR)/$(am__dirstamp) auth/AuthClientHandler.lo: auth/$(am__dirstamp) \ auth/$(DEPDIR)/$(am__dirstamp) auth/AuthSessionHandler.lo: auth/$(am__dirstamp) \ auth/$(DEPDIR)/$(am__dirstamp) auth/AuthServiceHandler.lo: auth/$(am__dirstamp) \ auth/$(DEPDIR)/$(am__dirstamp) auth/AuthMethodList.lo: auth/$(am__dirstamp) \ auth/$(DEPDIR)/$(am__dirstamp) auth/cephx/$(am__dirstamp): @$(MKDIR_P) auth/cephx @: > auth/cephx/$(am__dirstamp) auth/cephx/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) auth/cephx/$(DEPDIR) @: > auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/cephx/CephxAuthorizeHandler.lo: auth/cephx/$(am__dirstamp) \ auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/cephx/CephxClientHandler.lo: auth/cephx/$(am__dirstamp) \ auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/cephx/CephxProtocol.lo: auth/cephx/$(am__dirstamp) \ auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/cephx/CephxServiceHandler.lo: auth/cephx/$(am__dirstamp) \ auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/cephx/CephxSessionHandler.lo: auth/cephx/$(am__dirstamp) \ auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/cephx/CephxKeyServer.lo: auth/cephx/$(am__dirstamp) \ auth/cephx/$(DEPDIR)/$(am__dirstamp) auth/none/$(am__dirstamp): @$(MKDIR_P) auth/none @: > auth/none/$(am__dirstamp) auth/none/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) auth/none/$(DEPDIR) @: > auth/none/$(DEPDIR)/$(am__dirstamp) auth/none/AuthNoneAuthorizeHandler.lo: auth/none/$(am__dirstamp) \ auth/none/$(DEPDIR)/$(am__dirstamp) auth/unknown/$(am__dirstamp): @$(MKDIR_P) auth/unknown @: > auth/unknown/$(am__dirstamp) auth/unknown/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) auth/unknown/$(DEPDIR) @: > auth/unknown/$(DEPDIR)/$(am__dirstamp) auth/unknown/AuthUnknownAuthorizeHandler.lo: \ auth/unknown/$(am__dirstamp) \ auth/unknown/$(DEPDIR)/$(am__dirstamp) auth/Crypto.lo: auth/$(am__dirstamp) auth/$(DEPDIR)/$(am__dirstamp) auth/KeyRing.lo: auth/$(am__dirstamp) auth/$(DEPDIR)/$(am__dirstamp) auth/RotatingKeyRing.lo: auth/$(am__dirstamp) \ auth/$(DEPDIR)/$(am__dirstamp) libauth.la: $(libauth_la_OBJECTS) $(libauth_la_DEPENDENCIES) $(EXTRA_libauth_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libauth_la_OBJECTS) $(libauth_la_LIBADD) $(LIBS) libcephfs.la: $(libcephfs_la_OBJECTS) $(libcephfs_la_DEPENDENCIES) $(EXTRA_libcephfs_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcephfs_la_LINK) -rpath $(libdir) $(libcephfs_la_OBJECTS) $(libcephfs_la_LIBADD) $(LIBS) java/native/$(am__dirstamp): @$(MKDIR_P) java/native @: > java/native/$(am__dirstamp) java/native/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) java/native/$(DEPDIR) @: > java/native/$(DEPDIR)/$(am__dirstamp) java/native/libcephfs_jni_la-libcephfs_jni.lo: \ java/native/$(am__dirstamp) \ java/native/$(DEPDIR)/$(am__dirstamp) java/native/libcephfs_jni_la-JniConstants.lo: \ java/native/$(am__dirstamp) \ java/native/$(DEPDIR)/$(am__dirstamp) libcephfs_jni.la: $(libcephfs_jni_la_OBJECTS) $(libcephfs_jni_la_DEPENDENCIES) $(EXTRA_libcephfs_jni_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcephfs_jni_la_LINK) $(am_libcephfs_jni_la_rpath) $(libcephfs_jni_la_OBJECTS) $(libcephfs_jni_la_LIBADD) $(LIBS) rgw/$(am__dirstamp): @$(MKDIR_P) rgw @: > rgw/$(am__dirstamp) rgw/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) rgw/$(DEPDIR) @: > rgw/$(DEPDIR)/$(am__dirstamp) rgw/libcivetweb_la-rgw_civetweb.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/libcivetweb_la-rgw_civetweb_log.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) civetweb/src/$(am__dirstamp): @$(MKDIR_P) civetweb/src @: > civetweb/src/$(am__dirstamp) civetweb/src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) civetweb/src/$(DEPDIR) @: > civetweb/src/$(DEPDIR)/$(am__dirstamp) civetweb/src/libcivetweb_la-civetweb.lo: civetweb/src/$(am__dirstamp) \ civetweb/src/$(DEPDIR)/$(am__dirstamp) libcivetweb.la: $(libcivetweb_la_OBJECTS) $(libcivetweb_la_DEPENDENCIES) $(EXTRA_libcivetweb_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcivetweb_la_LINK) $(am_libcivetweb_la_rpath) $(libcivetweb_la_OBJECTS) $(libcivetweb_la_LIBADD) $(LIBS) client/$(am__dirstamp): @$(MKDIR_P) client @: > client/$(am__dirstamp) client/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) client/$(DEPDIR) @: > client/$(DEPDIR)/$(am__dirstamp) client/Client.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) client/Inode.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) client/Dentry.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) client/MetaRequest.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) client/ClientSnapRealm.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) client/MetaSession.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) client/Trace.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) libclient.la: $(libclient_la_OBJECTS) $(libclient_la_DEPENDENCIES) $(EXTRA_libclient_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libclient_la_OBJECTS) $(libclient_la_LIBADD) $(LIBS) client/fuse_ll.lo: client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) libclient_fuse.la: $(libclient_fuse_la_OBJECTS) $(libclient_fuse_la_DEPENDENCIES) $(EXTRA_libclient_fuse_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(am_libclient_fuse_la_rpath) $(libclient_fuse_la_OBJECTS) $(libclient_fuse_la_LIBADD) $(LIBS) cls/hello/$(am__dirstamp): @$(MKDIR_P) cls/hello @: > cls/hello/$(am__dirstamp) cls/hello/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/hello/$(DEPDIR) @: > cls/hello/$(DEPDIR)/$(am__dirstamp) cls/hello/cls_hello.lo: cls/hello/$(am__dirstamp) \ cls/hello/$(DEPDIR)/$(am__dirstamp) libcls_hello.la: $(libcls_hello_la_OBJECTS) $(libcls_hello_la_DEPENDENCIES) $(EXTRA_libcls_hello_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_hello_la_LINK) -rpath $(radoslibdir) $(libcls_hello_la_OBJECTS) $(libcls_hello_la_LIBADD) $(LIBS) key_value_store/$(am__dirstamp): @$(MKDIR_P) key_value_store @: > key_value_store/$(am__dirstamp) key_value_store/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) key_value_store/$(DEPDIR) @: > key_value_store/$(DEPDIR)/$(am__dirstamp) key_value_store/cls_kvs.lo: key_value_store/$(am__dirstamp) \ key_value_store/$(DEPDIR)/$(am__dirstamp) libcls_kvs.la: $(libcls_kvs_la_OBJECTS) $(libcls_kvs_la_DEPENDENCIES) $(EXTRA_libcls_kvs_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_kvs_la_LINK) $(am_libcls_kvs_la_rpath) $(libcls_kvs_la_OBJECTS) $(libcls_kvs_la_LIBADD) $(LIBS) cls/lock/$(am__dirstamp): @$(MKDIR_P) cls/lock @: > cls/lock/$(am__dirstamp) cls/lock/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/lock/$(DEPDIR) @: > cls/lock/$(DEPDIR)/$(am__dirstamp) cls/lock/cls_lock.lo: cls/lock/$(am__dirstamp) \ cls/lock/$(DEPDIR)/$(am__dirstamp) libcls_lock.la: $(libcls_lock_la_OBJECTS) $(libcls_lock_la_DEPENDENCIES) $(EXTRA_libcls_lock_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_lock_la_LINK) -rpath $(radoslibdir) $(libcls_lock_la_OBJECTS) $(libcls_lock_la_LIBADD) $(LIBS) cls/lock/cls_lock_client.lo: cls/lock/$(am__dirstamp) \ cls/lock/$(DEPDIR)/$(am__dirstamp) cls/lock/cls_lock_types.lo: cls/lock/$(am__dirstamp) \ cls/lock/$(DEPDIR)/$(am__dirstamp) cls/lock/cls_lock_ops.lo: cls/lock/$(am__dirstamp) \ cls/lock/$(DEPDIR)/$(am__dirstamp) libcls_lock_client.la: $(libcls_lock_client_la_OBJECTS) $(libcls_lock_client_la_DEPENDENCIES) $(EXTRA_libcls_lock_client_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libcls_lock_client_la_OBJECTS) $(libcls_lock_client_la_LIBADD) $(LIBS) cls/log/cls_log.lo: cls/log/$(am__dirstamp) \ cls/log/$(DEPDIR)/$(am__dirstamp) libcls_log.la: $(libcls_log_la_OBJECTS) $(libcls_log_la_DEPENDENCIES) $(EXTRA_libcls_log_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_log_la_LINK) -rpath $(radoslibdir) $(libcls_log_la_OBJECTS) $(libcls_log_la_LIBADD) $(LIBS) cls/rbd/$(am__dirstamp): @$(MKDIR_P) cls/rbd @: > cls/rbd/$(am__dirstamp) cls/rbd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/rbd/$(DEPDIR) @: > cls/rbd/$(DEPDIR)/$(am__dirstamp) cls/rbd/cls_rbd.lo: cls/rbd/$(am__dirstamp) \ cls/rbd/$(DEPDIR)/$(am__dirstamp) libcls_rbd.la: $(libcls_rbd_la_OBJECTS) $(libcls_rbd_la_DEPENDENCIES) $(EXTRA_libcls_rbd_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_rbd_la_LINK) -rpath $(radoslibdir) $(libcls_rbd_la_OBJECTS) $(libcls_rbd_la_LIBADD) $(LIBS) cls/rbd/cls_rbd_client.lo: cls/rbd/$(am__dirstamp) \ cls/rbd/$(DEPDIR)/$(am__dirstamp) libcls_rbd_client.la: $(libcls_rbd_client_la_OBJECTS) $(libcls_rbd_client_la_DEPENDENCIES) $(EXTRA_libcls_rbd_client_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libcls_rbd_client_la_OBJECTS) $(libcls_rbd_client_la_LIBADD) $(LIBS) cls/refcount/$(am__dirstamp): @$(MKDIR_P) cls/refcount @: > cls/refcount/$(am__dirstamp) cls/refcount/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/refcount/$(DEPDIR) @: > cls/refcount/$(DEPDIR)/$(am__dirstamp) cls/refcount/cls_refcount.lo: cls/refcount/$(am__dirstamp) \ cls/refcount/$(DEPDIR)/$(am__dirstamp) cls/refcount/cls_refcount_ops.lo: cls/refcount/$(am__dirstamp) \ cls/refcount/$(DEPDIR)/$(am__dirstamp) common/$(am__dirstamp): @$(MKDIR_P) common @: > common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) common/$(DEPDIR) @: > common/$(DEPDIR)/$(am__dirstamp) common/ceph_json.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) libcls_refcount.la: $(libcls_refcount_la_OBJECTS) $(libcls_refcount_la_DEPENDENCIES) $(EXTRA_libcls_refcount_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_refcount_la_LINK) -rpath $(radoslibdir) $(libcls_refcount_la_OBJECTS) $(libcls_refcount_la_LIBADD) $(LIBS) cls/refcount/cls_refcount_client.lo: cls/refcount/$(am__dirstamp) \ cls/refcount/$(DEPDIR)/$(am__dirstamp) libcls_refcount_client.la: $(libcls_refcount_client_la_OBJECTS) $(libcls_refcount_client_la_DEPENDENCIES) $(EXTRA_libcls_refcount_client_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libcls_refcount_client_la_OBJECTS) $(libcls_refcount_client_la_LIBADD) $(LIBS) cls/replica_log/cls_replica_log.lo: cls/replica_log/$(am__dirstamp) \ cls/replica_log/$(DEPDIR)/$(am__dirstamp) libcls_replica_log.la: $(libcls_replica_log_la_OBJECTS) $(libcls_replica_log_la_DEPENDENCIES) $(EXTRA_libcls_replica_log_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_replica_log_la_LINK) -rpath $(radoslibdir) $(libcls_replica_log_la_OBJECTS) $(libcls_replica_log_la_LIBADD) $(LIBS) cls/rgw/$(am__dirstamp): @$(MKDIR_P) cls/rgw @: > cls/rgw/$(am__dirstamp) cls/rgw/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cls/rgw/$(DEPDIR) @: > cls/rgw/$(DEPDIR)/$(am__dirstamp) cls/rgw/cls_rgw.lo: cls/rgw/$(am__dirstamp) \ cls/rgw/$(DEPDIR)/$(am__dirstamp) cls/rgw/cls_rgw_ops.lo: cls/rgw/$(am__dirstamp) \ cls/rgw/$(DEPDIR)/$(am__dirstamp) cls/rgw/cls_rgw_types.lo: cls/rgw/$(am__dirstamp) \ cls/rgw/$(DEPDIR)/$(am__dirstamp) libcls_rgw.la: $(libcls_rgw_la_OBJECTS) $(libcls_rgw_la_DEPENDENCIES) $(EXTRA_libcls_rgw_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_rgw_la_LINK) -rpath $(radoslibdir) $(libcls_rgw_la_OBJECTS) $(libcls_rgw_la_LIBADD) $(LIBS) cls/rgw/cls_rgw_client.lo: cls/rgw/$(am__dirstamp) \ cls/rgw/$(DEPDIR)/$(am__dirstamp) libcls_rgw_client.la: $(libcls_rgw_client_la_OBJECTS) $(libcls_rgw_client_la_DEPENDENCIES) $(EXTRA_libcls_rgw_client_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libcls_rgw_client_la_OBJECTS) $(libcls_rgw_client_la_LIBADD) $(LIBS) cls/statelog/cls_statelog.lo: cls/statelog/$(am__dirstamp) \ cls/statelog/$(DEPDIR)/$(am__dirstamp) libcls_statelog.la: $(libcls_statelog_la_OBJECTS) $(libcls_statelog_la_DEPENDENCIES) $(EXTRA_libcls_statelog_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_statelog_la_LINK) -rpath $(radoslibdir) $(libcls_statelog_la_OBJECTS) $(libcls_statelog_la_LIBADD) $(LIBS) cls/user/cls_user.lo: cls/user/$(am__dirstamp) \ cls/user/$(DEPDIR)/$(am__dirstamp) libcls_user.la: $(libcls_user_la_OBJECTS) $(libcls_user_la_DEPENDENCIES) $(EXTRA_libcls_user_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_user_la_LINK) -rpath $(radoslibdir) $(libcls_user_la_OBJECTS) $(libcls_user_la_LIBADD) $(LIBS) cls/version/cls_version.lo: cls/version/$(am__dirstamp) \ cls/version/$(DEPDIR)/$(am__dirstamp) libcls_version.la: $(libcls_version_la_OBJECTS) $(libcls_version_la_DEPENDENCIES) $(EXTRA_libcls_version_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcls_version_la_LINK) -rpath $(radoslibdir) $(libcls_version_la_OBJECTS) $(libcls_version_la_LIBADD) $(LIBS) common/DecayCounter.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/LogClient.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/LogEntry.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/PrebufferedStreambuf.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/SloppyCRCMap.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/BackTrace.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/perf_counters.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Mutex.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/OutputDataSocket.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/admin_socket.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/admin_socket_client.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/cmdparse.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/escape.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/io_priority.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Clock.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Throttle.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Timer.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Finisher.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/environment.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/assert.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/run_cmd.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/WorkQueue.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ConfUtils.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/MemoryModel.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/armor.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/fd.lo: common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/xattr.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/safe_io.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/snap_types.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/str_list.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/str_map.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/errno.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/RefCountedObj.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/blkdev.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/common_init.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/pipe.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_argparse.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_context.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/buffer.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/code_environment.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/dout.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/histogram.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/signal.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/simple_spin.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Thread.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/Formatter.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/HeartbeatMap.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/config.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/utf8.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/mime.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/strtol.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/page.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/lockdep.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/version.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/hex.lo: common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/entity_name.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_crypto.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_crypto_cms.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ipaddr.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/pick_address.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/util.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/TextTable.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_fs.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_hash.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_strings.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/ceph_frag.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/addr_parsing.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/hobject.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/bloom_filter.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/linux_version.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) mon/$(am__dirstamp): @$(MKDIR_P) mon @: > mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) mon/$(DEPDIR) @: > mon/$(DEPDIR)/$(am__dirstamp) mon/MonCap.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/MonClient.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/MonMap.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) osd/$(am__dirstamp): @$(MKDIR_P) osd @: > osd/$(am__dirstamp) osd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) osd/$(DEPDIR) @: > osd/$(DEPDIR)/$(am__dirstamp) osd/OSDMap.lo: osd/$(am__dirstamp) osd/$(DEPDIR)/$(am__dirstamp) osd/osd_types.lo: osd/$(am__dirstamp) osd/$(DEPDIR)/$(am__dirstamp) osd/ECMsgTypes.lo: osd/$(am__dirstamp) osd/$(DEPDIR)/$(am__dirstamp) osd/HitSet.lo: osd/$(am__dirstamp) osd/$(DEPDIR)/$(am__dirstamp) mds/$(am__dirstamp): @$(MKDIR_P) mds @: > mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) mds/$(DEPDIR) @: > mds/$(DEPDIR)/$(am__dirstamp) mds/MDSMap.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/inode_backtrace.lo: mds/$(am__dirstamp) \ mds/$(DEPDIR)/$(am__dirstamp) mds/mdstypes.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/flock.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) common/libcommon_crc_la-sctp_crc32.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libcommon_crc_la-crc32c.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libcommon_crc_la-crc32c_intel_baseline.lo: \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/libcommon_crc_la-crc32c_intel_fast.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libcommon_crc_la-crc32c_intel_fast_asm.lo: \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo: \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) libcommon_crc.la: $(libcommon_crc_la_OBJECTS) $(libcommon_crc_la_DEPENDENCIES) $(EXTRA_libcommon_crc_la_DEPENDENCIES) $(AM_V_CXXLD)$(libcommon_crc_la_LINK) $(libcommon_crc_la_OBJECTS) $(libcommon_crc_la_LIBADD) $(LIBS) crush/$(am__dirstamp): @$(MKDIR_P) crush @: > crush/$(am__dirstamp) crush/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) crush/$(DEPDIR) @: > crush/$(DEPDIR)/$(am__dirstamp) crush/builder.lo: crush/$(am__dirstamp) \ crush/$(DEPDIR)/$(am__dirstamp) crush/mapper.lo: crush/$(am__dirstamp) crush/$(DEPDIR)/$(am__dirstamp) crush/crush.lo: crush/$(am__dirstamp) crush/$(DEPDIR)/$(am__dirstamp) crush/hash.lo: crush/$(am__dirstamp) crush/$(DEPDIR)/$(am__dirstamp) crush/CrushWrapper.lo: crush/$(am__dirstamp) \ crush/$(DEPDIR)/$(am__dirstamp) crush/CrushCompiler.lo: crush/$(am__dirstamp) \ crush/$(DEPDIR)/$(am__dirstamp) crush/CrushTester.lo: crush/$(am__dirstamp) \ crush/$(DEPDIR)/$(am__dirstamp) libcrush.la: $(libcrush_la_OBJECTS) $(libcrush_la_DEPENDENCIES) $(EXTRA_libcrush_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libcrush_la_OBJECTS) $(libcrush_la_LIBADD) $(LIBS) test/erasure-code/$(am__dirstamp): @$(MKDIR_P) test/erasure-code @: > test/erasure-code/$(am__dirstamp) test/erasure-code/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/erasure-code/$(DEPDIR) @: > test/erasure-code/$(DEPDIR)/$(am__dirstamp) test/erasure-code/libec_example_la-ErasureCodePluginExample.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_example.la: $(libec_example_la_OBJECTS) $(libec_example_la_DEPENDENCIES) $(EXTRA_libec_example_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_example_la_LINK) -rpath $(erasure_codelibdir) $(libec_example_la_OBJECTS) $(libec_example_la_LIBADD) $(LIBS) test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_fail_to_initialize.la: $(libec_fail_to_initialize_la_OBJECTS) $(libec_fail_to_initialize_la_DEPENDENCIES) $(EXTRA_libec_fail_to_initialize_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_fail_to_initialize_la_LINK) -rpath $(erasure_codelibdir) $(libec_fail_to_initialize_la_OBJECTS) $(libec_fail_to_initialize_la_LIBADD) $(LIBS) test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_fail_to_register.la: $(libec_fail_to_register_la_OBJECTS) $(libec_fail_to_register_la_DEPENDENCIES) $(EXTRA_libec_fail_to_register_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_fail_to_register_la_LINK) -rpath $(erasure_codelibdir) $(libec_fail_to_register_la_OBJECTS) $(libec_fail_to_register_la_LIBADD) $(LIBS) test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_hangs.la: $(libec_hangs_la_OBJECTS) $(libec_hangs_la_DEPENDENCIES) $(EXTRA_libec_hangs_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_hangs_la_LINK) -rpath $(erasure_codelibdir) $(libec_hangs_la_OBJECTS) $(libec_hangs_la_LIBADD) $(LIBS) erasure-code/jerasure/$(am__dirstamp): @$(MKDIR_P) erasure-code/jerasure @: > erasure-code/jerasure/$(am__dirstamp) erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) erasure-code/jerasure/$(DEPDIR) @: > erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) libec_jerasure.la: $(libec_jerasure_la_OBJECTS) $(libec_jerasure_la_DEPENDENCIES) $(EXTRA_libec_jerasure_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_jerasure_la_LINK) -rpath $(erasure_codelibdir) $(libec_jerasure_la_OBJECTS) $(libec_jerasure_la_LIBADD) $(LIBS) erasure-code/jerasure/jerasure/src/$(am__dirstamp): @$(MKDIR_P) erasure-code/jerasure/jerasure/src @: > erasure-code/jerasure/jerasure/src/$(am__dirstamp) erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) erasure-code/jerasure/jerasure/src/$(DEPDIR) @: > erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/$(am__dirstamp): @$(MKDIR_P) erasure-code/jerasure/gf-complete/src @: > erasure-code/jerasure/gf-complete/src/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) erasure-code/jerasure/gf-complete/src/$(DEPDIR) @: > erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) libec_jerasure_generic.la: $(libec_jerasure_generic_la_OBJECTS) $(libec_jerasure_generic_la_DEPENDENCIES) $(EXTRA_libec_jerasure_generic_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_jerasure_generic_la_LINK) -rpath $(erasure_codelibdir) $(libec_jerasure_generic_la_OBJECTS) $(libec_jerasure_generic_la_LIBADD) $(LIBS) erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) libec_jerasure_sse3.la: $(libec_jerasure_sse3_la_OBJECTS) $(libec_jerasure_sse3_la_DEPENDENCIES) $(EXTRA_libec_jerasure_sse3_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_jerasure_sse3_la_LINK) -rpath $(erasure_codelibdir) $(libec_jerasure_sse3_la_OBJECTS) $(libec_jerasure_sse3_la_LIBADD) $(LIBS) erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo: \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo: \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo: \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) libec_jerasure_sse4.la: $(libec_jerasure_sse4_la_OBJECTS) $(libec_jerasure_sse4_la_DEPENDENCIES) $(EXTRA_libec_jerasure_sse4_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_jerasure_sse4_la_LINK) -rpath $(erasure_codelibdir) $(libec_jerasure_sse4_la_OBJECTS) $(libec_jerasure_sse4_la_LIBADD) $(LIBS) test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_missing_entry_point.la: $(libec_missing_entry_point_la_OBJECTS) $(libec_missing_entry_point_la_DEPENDENCIES) $(EXTRA_libec_missing_entry_point_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_missing_entry_point_la_LINK) -rpath $(erasure_codelibdir) $(libec_missing_entry_point_la_OBJECTS) $(libec_missing_entry_point_la_LIBADD) $(LIBS) test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_test_jerasure_generic.la: $(libec_test_jerasure_generic_la_OBJECTS) $(libec_test_jerasure_generic_la_DEPENDENCIES) $(EXTRA_libec_test_jerasure_generic_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_test_jerasure_generic_la_LINK) -rpath $(erasure_codelibdir) $(libec_test_jerasure_generic_la_OBJECTS) $(libec_test_jerasure_generic_la_LIBADD) $(LIBS) test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_test_jerasure_sse3.la: $(libec_test_jerasure_sse3_la_OBJECTS) $(libec_test_jerasure_sse3_la_DEPENDENCIES) $(EXTRA_libec_test_jerasure_sse3_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_test_jerasure_sse3_la_LINK) -rpath $(erasure_codelibdir) $(libec_test_jerasure_sse3_la_OBJECTS) $(libec_test_jerasure_sse3_la_LIBADD) $(LIBS) test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo: \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) libec_test_jerasure_sse4.la: $(libec_test_jerasure_sse4_la_OBJECTS) $(libec_test_jerasure_sse4_la_DEPENDENCIES) $(EXTRA_libec_test_jerasure_sse4_la_DEPENDENCIES) $(AM_V_CXXLD)$(libec_test_jerasure_sse4_la_LINK) -rpath $(erasure_codelibdir) $(libec_test_jerasure_sse4_la_OBJECTS) $(libec_test_jerasure_sse4_la_LIBADD) $(LIBS) erasure-code/$(am__dirstamp): @$(MKDIR_P) erasure-code @: > erasure-code/$(am__dirstamp) erasure-code/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) erasure-code/$(DEPDIR) @: > erasure-code/$(DEPDIR)/$(am__dirstamp) erasure-code/ErasureCodePlugin.lo: erasure-code/$(am__dirstamp) \ erasure-code/$(DEPDIR)/$(am__dirstamp) liberasure_code.la: $(liberasure_code_la_OBJECTS) $(liberasure_code_la_DEPENDENCIES) $(EXTRA_liberasure_code_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(liberasure_code_la_OBJECTS) $(liberasure_code_la_LIBADD) $(LIBS) global/$(am__dirstamp): @$(MKDIR_P) global @: > global/$(am__dirstamp) global/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) global/$(DEPDIR) @: > global/$(DEPDIR)/$(am__dirstamp) global/global_context.lo: global/$(am__dirstamp) \ global/$(DEPDIR)/$(am__dirstamp) global/global_init.lo: global/$(am__dirstamp) \ global/$(DEPDIR)/$(am__dirstamp) global/pidfile.lo: global/$(am__dirstamp) \ global/$(DEPDIR)/$(am__dirstamp) global/signal_handler.lo: global/$(am__dirstamp) \ global/$(DEPDIR)/$(am__dirstamp) libglobal.la: $(libglobal_la_OBJECTS) $(libglobal_la_DEPENDENCIES) $(EXTRA_libglobal_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libglobal_la_OBJECTS) $(libglobal_la_LIBADD) $(LIBS) json_spirit/$(am__dirstamp): @$(MKDIR_P) json_spirit @: > json_spirit/$(am__dirstamp) json_spirit/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) json_spirit/$(DEPDIR) @: > json_spirit/$(DEPDIR)/$(am__dirstamp) json_spirit/json_spirit_reader.lo: json_spirit/$(am__dirstamp) \ json_spirit/$(DEPDIR)/$(am__dirstamp) json_spirit/json_spirit_writer.lo: json_spirit/$(am__dirstamp) \ json_spirit/$(DEPDIR)/$(am__dirstamp) libjson_spirit.la: $(libjson_spirit_la_OBJECTS) $(libjson_spirit_la_DEPENDENCIES) $(EXTRA_libjson_spirit_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libjson_spirit_la_OBJECTS) $(libjson_spirit_la_LIBADD) $(LIBS) log/$(am__dirstamp): @$(MKDIR_P) log @: > log/$(am__dirstamp) log/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) log/$(DEPDIR) @: > log/$(DEPDIR)/$(am__dirstamp) log/Log.lo: log/$(am__dirstamp) log/$(DEPDIR)/$(am__dirstamp) log/SubsystemMap.lo: log/$(am__dirstamp) log/$(DEPDIR)/$(am__dirstamp) liblog.la: $(liblog_la_OBJECTS) $(liblog_la_DEPENDENCIES) $(EXTRA_liblog_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(liblog_la_OBJECTS) $(liblog_la_LIBADD) $(LIBS) mds/Anchor.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Capability.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Dumper.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Resetter.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDS.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/locks.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/journal.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Server.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Mutation.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDCache.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Locker.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/Migrator.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDBalancer.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/CDentry.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/CDir.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/CInode.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/LogEvent.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDSTable.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/InoTable.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDSTableClient.lo: mds/$(am__dirstamp) \ mds/$(DEPDIR)/$(am__dirstamp) mds/MDSTableServer.lo: mds/$(am__dirstamp) \ mds/$(DEPDIR)/$(am__dirstamp) mds/AnchorServer.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/AnchorClient.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/SnapRealm.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/SnapServer.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/snap.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/SessionMap.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDLog.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/MDSUtility.lo: mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) libmds.la: $(libmds_la_OBJECTS) $(libmds_la_DEPENDENCIES) $(EXTRA_libmds_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libmds_la_OBJECTS) $(libmds_la_LIBADD) $(LIBS) mon/Monitor.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/Paxos.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/PaxosService.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/OSDMonitor.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/MDSMonitor.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/MonmapMonitor.lo: mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) mon/PGMonitor.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/LogMonitor.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/AuthMonitor.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/Elector.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/MonitorStore.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) mon/HealthMonitor.lo: mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) mon/DataHealthService.lo: mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) mon/ConfigKeyService.lo: mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) libmon.la: $(libmon_la_OBJECTS) $(libmon_la_DEPENDENCIES) $(EXTRA_libmon_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libmon_la_OBJECTS) $(libmon_la_LIBADD) $(LIBS) mon/PGMap.lo: mon/$(am__dirstamp) mon/$(DEPDIR)/$(am__dirstamp) libmon_types.la: $(libmon_types_la_OBJECTS) $(libmon_types_la_DEPENDENCIES) $(EXTRA_libmon_types_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libmon_types_la_OBJECTS) $(libmon_types_la_LIBADD) $(LIBS) msg/$(am__dirstamp): @$(MKDIR_P) msg @: > msg/$(am__dirstamp) msg/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) msg/$(DEPDIR) @: > msg/$(DEPDIR)/$(am__dirstamp) msg/Accepter.lo: msg/$(am__dirstamp) msg/$(DEPDIR)/$(am__dirstamp) msg/DispatchQueue.lo: msg/$(am__dirstamp) \ msg/$(DEPDIR)/$(am__dirstamp) msg/Message.lo: msg/$(am__dirstamp) msg/$(DEPDIR)/$(am__dirstamp) msg/Messenger.lo: msg/$(am__dirstamp) msg/$(DEPDIR)/$(am__dirstamp) msg/Pipe.lo: msg/$(am__dirstamp) msg/$(DEPDIR)/$(am__dirstamp) msg/SimpleMessenger.lo: msg/$(am__dirstamp) \ msg/$(DEPDIR)/$(am__dirstamp) msg/msg_types.lo: msg/$(am__dirstamp) msg/$(DEPDIR)/$(am__dirstamp) libmsg.la: $(libmsg_la_OBJECTS) $(libmsg_la_DEPENDENCIES) $(EXTRA_libmsg_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libmsg_la_OBJECTS) $(libmsg_la_LIBADD) $(LIBS) os/libos_la-chain_xattr.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-DBObjectMap.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-GenericObjectMap.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-FileJournal.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-FileStore.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-FlatIndex.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-GenericFileStoreBackend.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-HashIndex.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-IndexManager.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-JournalingObjectStore.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-LevelDBStore.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-LFNIndex.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-MemStore.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-KeyValueStore.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-ObjectStore.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-WBThrottle.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) common/libos_la-TrackedOp.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) os/libos_la-BtrfsFileStoreBackend.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-XfsFileStoreBackend.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libos_la-ZFSFileStoreBackend.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) libos.la: $(libos_la_OBJECTS) $(libos_la_DEPENDENCIES) $(EXTRA_libos_la_DEPENDENCIES) $(AM_V_CXXLD)$(libos_la_LINK) $(libos_la_OBJECTS) $(libos_la_LIBADD) $(LIBS) os/libos_types_la-Transaction.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) libos_types.la: $(libos_types_la_OBJECTS) $(libos_types_la_DEPENDENCIES) $(EXTRA_libos_types_la_DEPENDENCIES) $(AM_V_CXXLD)$(libos_types_la_LINK) $(libos_types_la_OBJECTS) $(libos_types_la_LIBADD) $(LIBS) osd/libosd_la-PG.lo: osd/$(am__dirstamp) osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-ReplicatedPG.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-ReplicatedBackend.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-ECBackend.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-ECMsgTypes.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-ECTransaction.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-PGBackend.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-Ager.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-HitSet.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-OSD.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-OSDCap.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-Watch.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-ClassHandler.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-OpRequest.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) common/libosd_la-TrackedOp.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) osd/libosd_la-SnapMapper.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) objclass/$(am__dirstamp): @$(MKDIR_P) objclass @: > objclass/$(am__dirstamp) objclass/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) objclass/$(DEPDIR) @: > objclass/$(DEPDIR)/$(am__dirstamp) objclass/libosd_la-class_api.lo: objclass/$(am__dirstamp) \ objclass/$(DEPDIR)/$(am__dirstamp) libosd.la: $(libosd_la_OBJECTS) $(libosd_la_DEPENDENCIES) $(EXTRA_libosd_la_DEPENDENCIES) $(AM_V_CXXLD)$(libosd_la_LINK) $(libosd_la_OBJECTS) $(libosd_la_LIBADD) $(LIBS) osd/libosd_types_la-PGLog.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_types_la-osd_types.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/libosd_types_la-ECUtil.lo: osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) libosd_types.la: $(libosd_types_la_OBJECTS) $(libosd_types_la_DEPENDENCIES) $(EXTRA_libosd_types_la_DEPENDENCIES) $(AM_V_CXXLD)$(libosd_types_la_LINK) $(libosd_types_la_OBJECTS) $(libosd_types_la_LIBADD) $(LIBS) osdc/$(am__dirstamp): @$(MKDIR_P) osdc @: > osdc/$(am__dirstamp) osdc/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) osdc/$(DEPDIR) @: > osdc/$(DEPDIR)/$(am__dirstamp) osdc/Objecter.lo: osdc/$(am__dirstamp) osdc/$(DEPDIR)/$(am__dirstamp) osdc/ObjectCacher.lo: osdc/$(am__dirstamp) \ osdc/$(DEPDIR)/$(am__dirstamp) osdc/Filer.lo: osdc/$(am__dirstamp) osdc/$(DEPDIR)/$(am__dirstamp) osdc/Striper.lo: osdc/$(am__dirstamp) osdc/$(DEPDIR)/$(am__dirstamp) osdc/Journaler.lo: osdc/$(am__dirstamp) osdc/$(DEPDIR)/$(am__dirstamp) libosdc.la: $(libosdc_la_OBJECTS) $(libosdc_la_DEPENDENCIES) $(EXTRA_libosdc_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libosdc_la_OBJECTS) $(libosdc_la_LIBADD) $(LIBS) perfglue/$(am__dirstamp): @$(MKDIR_P) perfglue @: > perfglue/$(am__dirstamp) perfglue/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) perfglue/$(DEPDIR) @: > perfglue/$(DEPDIR)/$(am__dirstamp) perfglue/heap_profiler.lo: perfglue/$(am__dirstamp) \ perfglue/$(DEPDIR)/$(am__dirstamp) perfglue/disabled_heap_profiler.lo: perfglue/$(am__dirstamp) \ perfglue/$(DEPDIR)/$(am__dirstamp) perfglue/cpu_profiler.lo: perfglue/$(am__dirstamp) \ perfglue/$(DEPDIR)/$(am__dirstamp) perfglue/disabled_stubs.lo: perfglue/$(am__dirstamp) \ perfglue/$(DEPDIR)/$(am__dirstamp) libperfglue.la: $(libperfglue_la_OBJECTS) $(libperfglue_la_DEPENDENCIES) $(EXTRA_libperfglue_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libperfglue_la_OBJECTS) $(libperfglue_la_LIBADD) $(LIBS) librados/$(am__dirstamp): @$(MKDIR_P) librados @: > librados/$(am__dirstamp) librados/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) librados/$(DEPDIR) @: > librados/$(DEPDIR)/$(am__dirstamp) librados/librados_la-librados.lo: librados/$(am__dirstamp) \ librados/$(DEPDIR)/$(am__dirstamp) librados/librados_la-RadosClient.lo: librados/$(am__dirstamp) \ librados/$(DEPDIR)/$(am__dirstamp) librados/librados_la-IoCtxImpl.lo: librados/$(am__dirstamp) \ librados/$(DEPDIR)/$(am__dirstamp) librados/librados_la-snap_set_diff.lo: librados/$(am__dirstamp) \ librados/$(DEPDIR)/$(am__dirstamp) librados.la: $(librados_la_OBJECTS) $(librados_la_DEPENDENCIES) $(EXTRA_librados_la_DEPENDENCIES) $(AM_V_CXXLD)$(librados_la_LINK) -rpath $(libdir) $(librados_la_OBJECTS) $(librados_la_LIBADD) $(LIBS) test/librados/$(am__dirstamp): @$(MKDIR_P) test/librados @: > test/librados/$(am__dirstamp) test/librados/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/librados/$(DEPDIR) @: > test/librados/$(DEPDIR)/$(am__dirstamp) test/librados/libradostest_la-test.lo: test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) test/librados/libradostest_la-TestCase.lo: \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) libradostest.la: $(libradostest_la_OBJECTS) $(libradostest_la_DEPENDENCIES) $(EXTRA_libradostest_la_DEPENDENCIES) $(AM_V_CXXLD)$(libradostest_la_LINK) $(libradostest_la_OBJECTS) $(libradostest_la_LIBADD) $(LIBS) librbd/$(am__dirstamp): @$(MKDIR_P) librbd @: > librbd/$(am__dirstamp) librbd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) librbd/$(DEPDIR) @: > librbd/$(DEPDIR)/$(am__dirstamp) librbd/librbd.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd/AioCompletion.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd/AioRequest.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd/ImageCtx.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd/internal.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd/LibrbdWriteback.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd/WatchCtx.lo: librbd/$(am__dirstamp) \ librbd/$(DEPDIR)/$(am__dirstamp) librbd.la: $(librbd_la_OBJECTS) $(librbd_la_DEPENDENCIES) $(EXTRA_librbd_la_DEPENDENCIES) $(AM_V_CXXLD)$(librbd_la_LINK) -rpath $(libdir) $(librbd_la_OBJECTS) $(librbd_la_LIBADD) $(LIBS) rgw/librgw_la-librgw.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_acl.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_acl_s3.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_acl_swift.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_client_io.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_fcgi.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_xml.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_usage.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_json_enc.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_user.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_bucket.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_tools.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_rados.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_http_client.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_rest_client.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_rest_conn.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_op.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_common.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_cache.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_formats.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_log.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_multi.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_policy_s3.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_gc.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_multi_del.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_env.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_cors.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_cors_s3.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_auth_s3.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_metadata.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_replica_log.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_keystone.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_quota.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/librgw_la-rgw_dencoder.lo: rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) librgw.la: $(librgw_la_OBJECTS) $(librgw_la_DEPENDENCIES) $(EXTRA_librgw_la_DEPENDENCIES) $(AM_V_CXXLD)$(librgw_la_LINK) $(am_librgw_la_rpath) $(librgw_la_OBJECTS) $(librgw_la_LIBADD) $(LIBS) test/system/$(am__dirstamp): @$(MKDIR_P) test/system @: > test/system/$(am__dirstamp) test/system/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/system/$(DEPDIR) @: > test/system/$(DEPDIR)/$(am__dirstamp) test/system/cross_process_sem.lo: test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/systest_runnable.lo: test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/systest_settings.lo: test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) libsystest.la: $(libsystest_la_OBJECTS) $(libsystest_la_DEPENDENCIES) $(EXTRA_libsystest_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(am_libsystest_la_rpath) $(libsystest_la_OBJECTS) $(libsystest_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-su_sbinPROGRAMS: $(su_sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(su_sbin_PROGRAMS)'; test -n "$(su_sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(su_sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(su_sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(su_sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(su_sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-su_sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(su_sbin_PROGRAMS)'; test -n "$(su_sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(su_sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(su_sbindir)" && rm -f $$files clean-su_sbinPROGRAMS: @list='$(su_sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list tools/$(am__dirstamp): @$(MKDIR_P) tools @: > tools/$(am__dirstamp) tools/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) tools/$(DEPDIR) @: > tools/$(DEPDIR)/$(am__dirstamp) tools/ceph_authtool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph-authtool$(EXEEXT): $(ceph_authtool_OBJECTS) $(ceph_authtool_DEPENDENCIES) $(EXTRA_ceph_authtool_DEPENDENCIES) @rm -f ceph-authtool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_authtool_OBJECTS) $(ceph_authtool_LDADD) $(LIBS) tools/ceph-client-debug.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph-client-debug$(EXEEXT): $(ceph_client_debug_OBJECTS) $(ceph_client_debug_DEPENDENCIES) $(EXTRA_ceph_client_debug_DEPENDENCIES) @rm -f ceph-client-debug$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_client_debug_OBJECTS) $(ceph_client_debug_LDADD) $(LIBS) tools/ceph_conf.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph-conf$(EXEEXT): $(ceph_conf_OBJECTS) $(ceph_conf_DEPENDENCIES) $(EXTRA_ceph_conf_DEPENDENCIES) @rm -f ceph-conf$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_conf_OBJECTS) $(ceph_conf_LDADD) $(LIBS) test/encoding/$(am__dirstamp): @$(MKDIR_P) test/encoding @: > test/encoding/$(am__dirstamp) test/encoding/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/encoding/$(DEPDIR) @: > test/encoding/$(DEPDIR)/$(am__dirstamp) test/encoding/ceph_dencoder-ceph_dencoder.$(OBJEXT): \ test/encoding/$(am__dirstamp) \ test/encoding/$(DEPDIR)/$(am__dirstamp) rgw/ceph_dencoder-rgw_dencoder.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/ceph_dencoder-rgw_acl.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/ceph_dencoder-rgw_common.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/ceph_dencoder-rgw_env.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/ceph_dencoder-rgw_json_enc.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) ceph-dencoder$(EXEEXT): $(ceph_dencoder_OBJECTS) $(ceph_dencoder_DEPENDENCIES) $(EXTRA_ceph_dencoder_DEPENDENCIES) @rm -f ceph-dencoder$(EXEEXT) $(AM_V_CXXLD)$(ceph_dencoder_LINK) $(ceph_dencoder_OBJECTS) $(ceph_dencoder_LDADD) $(LIBS) ceph-fuse$(EXEEXT): $(ceph_fuse_OBJECTS) $(ceph_fuse_DEPENDENCIES) $(EXTRA_ceph_fuse_DEPENDENCIES) @rm -f ceph-fuse$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_fuse_OBJECTS) $(ceph_fuse_LDADD) $(LIBS) tools/ceph_kvstore_tool-ceph_kvstore_tool.$(OBJEXT): \ tools/$(am__dirstamp) tools/$(DEPDIR)/$(am__dirstamp) ceph-kvstore-tool$(EXEEXT): $(ceph_kvstore_tool_OBJECTS) $(ceph_kvstore_tool_DEPENDENCIES) $(EXTRA_ceph_kvstore_tool_DEPENDENCIES) @rm -f ceph-kvstore-tool$(EXEEXT) $(AM_V_CXXLD)$(ceph_kvstore_tool_LINK) $(ceph_kvstore_tool_OBJECTS) $(ceph_kvstore_tool_LDADD) $(LIBS) ceph-mds$(EXEEXT): $(ceph_mds_OBJECTS) $(ceph_mds_DEPENDENCIES) $(EXTRA_ceph_mds_DEPENDENCIES) @rm -f ceph-mds$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_mds_OBJECTS) $(ceph_mds_LDADD) $(LIBS) ceph-mon$(EXEEXT): $(ceph_mon_OBJECTS) $(ceph_mon_DEPENDENCIES) $(EXTRA_ceph_mon_DEPENDENCIES) @rm -f ceph-mon$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_mon_OBJECTS) $(ceph_mon_LDADD) $(LIBS) tools/ceph_monstore_tool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph-monstore-tool$(EXEEXT): $(ceph_monstore_tool_OBJECTS) $(ceph_monstore_tool_DEPENDENCIES) $(EXTRA_ceph_monstore_tool_DEPENDENCIES) @rm -f ceph-monstore-tool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_monstore_tool_OBJECTS) $(ceph_monstore_tool_LDADD) $(LIBS) tools/ceph_objectstore_tool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph-objectstore-tool$(EXEEXT): $(ceph_objectstore_tool_OBJECTS) $(ceph_objectstore_tool_DEPENDENCIES) $(EXTRA_ceph_objectstore_tool_DEPENDENCIES) @rm -f ceph-objectstore-tool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_objectstore_tool_OBJECTS) $(ceph_objectstore_tool_LDADD) $(LIBS) ceph-osd$(EXEEXT): $(ceph_osd_OBJECTS) $(ceph_osd_DEPENDENCIES) $(EXTRA_ceph_osd_DEPENDENCIES) @rm -f ceph-osd$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_osd_OBJECTS) $(ceph_osd_LDADD) $(LIBS) tools/ceph_osdomap_tool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph-osdomap-tool$(EXEEXT): $(ceph_osdomap_tool_OBJECTS) $(ceph_osdomap_tool_DEPENDENCIES) $(EXTRA_ceph_osdomap_tool_DEPENDENCIES) @rm -f ceph-osdomap-tool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_osdomap_tool_OBJECTS) $(ceph_osdomap_tool_LDADD) $(LIBS) client/SyntheticClient.$(OBJEXT): client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) ceph-syn$(EXEEXT): $(ceph_syn_OBJECTS) $(ceph_syn_DEPENDENCIES) $(EXTRA_ceph_syn_DEPENDENCIES) @rm -f ceph-syn$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_syn_OBJECTS) $(ceph_syn_LDADD) $(LIBS) test/$(am__dirstamp): @$(MKDIR_P) test @: > test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/$(DEPDIR) @: > test/$(DEPDIR)/$(am__dirstamp) test/bench_log.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_bench_log$(EXEEXT): $(ceph_bench_log_OBJECTS) $(ceph_bench_log_DEPENDENCIES) $(EXTRA_ceph_bench_log_DEPENDENCIES) @rm -f ceph_bench_log$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_bench_log_OBJECTS) $(ceph_bench_log_LDADD) $(LIBS) tools/dupstore.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph_dupstore$(EXEEXT): $(ceph_dupstore_OBJECTS) $(ceph_dupstore_DEPENDENCIES) $(EXTRA_ceph_dupstore_DEPENDENCIES) @rm -f ceph_dupstore$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_dupstore_OBJECTS) $(ceph_dupstore_LDADD) $(LIBS) test/erasure-code/ceph_erasure_code.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) ceph_erasure_code$(EXEEXT): $(ceph_erasure_code_OBJECTS) $(ceph_erasure_code_DEPENDENCIES) $(EXTRA_ceph_erasure_code_DEPENDENCIES) @rm -f ceph_erasure_code$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_erasure_code_OBJECTS) $(ceph_erasure_code_LDADD) $(LIBS) test/erasure-code/ceph_erasure_code_benchmark.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) ceph_erasure_code_benchmark$(EXEEXT): $(ceph_erasure_code_benchmark_OBJECTS) $(ceph_erasure_code_benchmark_DEPENDENCIES) $(EXTRA_ceph_erasure_code_benchmark_DEPENDENCIES) @rm -f ceph_erasure_code_benchmark$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_erasure_code_benchmark_OBJECTS) $(ceph_erasure_code_benchmark_LDADD) $(LIBS) test/erasure-code/ceph_erasure_code_non_regression.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) ceph_erasure_code_non_regression$(EXEEXT): $(ceph_erasure_code_non_regression_OBJECTS) $(ceph_erasure_code_non_regression_DEPENDENCIES) $(EXTRA_ceph_erasure_code_non_regression_DEPENDENCIES) @rm -f ceph_erasure_code_non_regression$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_erasure_code_non_regression_OBJECTS) $(ceph_erasure_code_non_regression_LDADD) $(LIBS) test/kv_store_bench.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) key_value_store/kv_flat_btree_async.$(OBJEXT): \ key_value_store/$(am__dirstamp) \ key_value_store/$(DEPDIR)/$(am__dirstamp) ceph_kvstorebench$(EXEEXT): $(ceph_kvstorebench_OBJECTS) $(ceph_kvstorebench_DEPENDENCIES) $(EXTRA_ceph_kvstorebench_DEPENDENCIES) @rm -f ceph_kvstorebench$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_kvstorebench_OBJECTS) $(ceph_kvstorebench_LDADD) $(LIBS) tools/mon_store_converter.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph_mon_store_converter$(EXEEXT): $(ceph_mon_store_converter_OBJECTS) $(ceph_mon_store_converter_DEPENDENCIES) $(EXTRA_ceph_mon_store_converter_DEPENDENCIES) @rm -f ceph_mon_store_converter$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_mon_store_converter_OBJECTS) $(ceph_mon_store_converter_LDADD) $(LIBS) test/multi_stress_watch.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_multi_stress_watch$(EXEEXT): $(ceph_multi_stress_watch_OBJECTS) $(ceph_multi_stress_watch_DEPENDENCIES) $(EXTRA_ceph_multi_stress_watch_DEPENDENCIES) @rm -f ceph_multi_stress_watch$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_multi_stress_watch_OBJECTS) $(ceph_multi_stress_watch_LDADD) $(LIBS) test/omap_bench.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_omapbench$(EXEEXT): $(ceph_omapbench_OBJECTS) $(ceph_omapbench_DEPENDENCIES) $(EXTRA_ceph_omapbench_DEPENDENCIES) @rm -f ceph_omapbench$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_omapbench_OBJECTS) $(ceph_omapbench_LDADD) $(LIBS) tools/psim.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph_psim$(EXEEXT): $(ceph_psim_OBJECTS) $(ceph_psim_DEPENDENCIES) $(EXTRA_ceph_psim_DEPENDENCIES) @rm -f ceph_psim$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_psim_OBJECTS) $(ceph_psim_LDADD) $(LIBS) tools/radosacl.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph_radosacl$(EXEEXT): $(ceph_radosacl_OBJECTS) $(ceph_radosacl_DEPENDENCIES) $(EXTRA_ceph_radosacl_DEPENDENCIES) @rm -f ceph_radosacl$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_radosacl_OBJECTS) $(ceph_radosacl_LDADD) $(LIBS) rgw/rgw_jsonparser.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_common.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_env.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_json_enc.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) ceph_rgw_jsonparser$(EXEEXT): $(ceph_rgw_jsonparser_OBJECTS) $(ceph_rgw_jsonparser_DEPENDENCIES) $(EXTRA_ceph_rgw_jsonparser_DEPENDENCIES) @rm -f ceph_rgw_jsonparser$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_rgw_jsonparser_OBJECTS) $(ceph_rgw_jsonparser_LDADD) $(LIBS) rgw/rgw_multiparser.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) ceph_rgw_multiparser$(EXEEXT): $(ceph_rgw_multiparser_OBJECTS) $(ceph_rgw_multiparser_DEPENDENCIES) $(EXTRA_ceph_rgw_multiparser_DEPENDENCIES) @rm -f ceph_rgw_multiparser$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_rgw_multiparser_OBJECTS) $(ceph_rgw_multiparser_LDADD) $(LIBS) tools/scratchtool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph_scratchtool$(EXEEXT): $(ceph_scratchtool_OBJECTS) $(ceph_scratchtool_DEPENDENCIES) $(EXTRA_ceph_scratchtool_DEPENDENCIES) @rm -f ceph_scratchtool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ceph_scratchtool_OBJECTS) $(ceph_scratchtool_LDADD) $(LIBS) tools/scratchtoolpp.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) ceph_scratchtoolpp$(EXEEXT): $(ceph_scratchtoolpp_OBJECTS) $(ceph_scratchtoolpp_DEPENDENCIES) $(EXTRA_ceph_scratchtoolpp_DEPENDENCIES) @rm -f ceph_scratchtoolpp$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_scratchtoolpp_OBJECTS) $(ceph_scratchtoolpp_LDADD) $(LIBS) test/bench/$(am__dirstamp): @$(MKDIR_P) test/bench @: > test/bench/$(am__dirstamp) test/bench/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/bench/$(DEPDIR) @: > test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/small_io_bench.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/rados_backend.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/detailed_stat_collector.$(OBJEXT): \ test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/bencher.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) ceph_smalliobench$(EXEEXT): $(ceph_smalliobench_OBJECTS) $(ceph_smalliobench_DEPENDENCIES) $(EXTRA_ceph_smalliobench_DEPENDENCIES) @rm -f ceph_smalliobench$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_smalliobench_OBJECTS) $(ceph_smalliobench_LDADD) $(LIBS) test/bench/small_io_bench_dumb.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/dumb_backend.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) ceph_smalliobenchdumb$(EXEEXT): $(ceph_smalliobenchdumb_OBJECTS) $(ceph_smalliobenchdumb_DEPENDENCIES) $(EXTRA_ceph_smalliobenchdumb_DEPENDENCIES) @rm -f ceph_smalliobenchdumb$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_smalliobenchdumb_OBJECTS) $(ceph_smalliobenchdumb_LDADD) $(LIBS) test/bench/small_io_bench_fs.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/testfilestore_backend.$(OBJEXT): \ test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) ceph_smalliobenchfs$(EXEEXT): $(ceph_smalliobenchfs_OBJECTS) $(ceph_smalliobenchfs_DEPENDENCIES) $(EXTRA_ceph_smalliobenchfs_DEPENDENCIES) @rm -f ceph_smalliobenchfs$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_smalliobenchfs_OBJECTS) $(ceph_smalliobenchfs_LDADD) $(LIBS) test/bench/small_io_bench_rbd.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) test/bench/rbd_backend.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) ceph_smalliobenchrbd$(EXEEXT): $(ceph_smalliobenchrbd_OBJECTS) $(ceph_smalliobenchrbd_DEPENDENCIES) $(EXTRA_ceph_smalliobenchrbd_DEPENDENCIES) @rm -f ceph_smalliobenchrbd$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_smalliobenchrbd_OBJECTS) $(ceph_smalliobenchrbd_LDADD) $(LIBS) test/streamtest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_streamtest$(EXEEXT): $(ceph_streamtest_OBJECTS) $(ceph_streamtest_DEPENDENCIES) $(EXTRA_ceph_streamtest_DEPENDENCIES) @rm -f ceph_streamtest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_streamtest_OBJECTS) $(ceph_streamtest_LDADD) $(LIBS) test/test_c_headers.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_c_headers$(EXEEXT): $(ceph_test_c_headers_OBJECTS) $(ceph_test_c_headers_DEPENDENCIES) $(EXTRA_ceph_test_c_headers_DEPENDENCIES) @rm -f ceph_test_c_headers$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ceph_test_c_headers_OBJECTS) $(ceph_test_c_headers_LDADD) $(LIBS) test/test_cfuse_cache_invalidate.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_cfuse_cache_invalidate$(EXEEXT): $(ceph_test_cfuse_cache_invalidate_OBJECTS) $(ceph_test_cfuse_cache_invalidate_DEPENDENCIES) $(EXTRA_ceph_test_cfuse_cache_invalidate_DEPENDENCIES) @rm -f ceph_test_cfuse_cache_invalidate$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_cfuse_cache_invalidate_OBJECTS) $(ceph_test_cfuse_cache_invalidate_LDADD) $(LIBS) test/cls_hello/$(am__dirstamp): @$(MKDIR_P) test/cls_hello @: > test/cls_hello/$(am__dirstamp) test/cls_hello/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_hello/$(DEPDIR) @: > test/cls_hello/$(DEPDIR)/$(am__dirstamp) test/cls_hello/ceph_test_cls_hello-test_cls_hello.$(OBJEXT): \ test/cls_hello/$(am__dirstamp) \ test/cls_hello/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_hello$(EXEEXT): $(ceph_test_cls_hello_OBJECTS) $(ceph_test_cls_hello_DEPENDENCIES) $(EXTRA_ceph_test_cls_hello_DEPENDENCIES) @rm -f ceph_test_cls_hello$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_hello_LINK) $(ceph_test_cls_hello_OBJECTS) $(ceph_test_cls_hello_LDADD) $(LIBS) test/cls_lock/$(am__dirstamp): @$(MKDIR_P) test/cls_lock @: > test/cls_lock/$(am__dirstamp) test/cls_lock/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_lock/$(DEPDIR) @: > test/cls_lock/$(DEPDIR)/$(am__dirstamp) test/cls_lock/ceph_test_cls_lock-test_cls_lock.$(OBJEXT): \ test/cls_lock/$(am__dirstamp) \ test/cls_lock/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_lock$(EXEEXT): $(ceph_test_cls_lock_OBJECTS) $(ceph_test_cls_lock_DEPENDENCIES) $(EXTRA_ceph_test_cls_lock_DEPENDENCIES) @rm -f ceph_test_cls_lock$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_lock_LINK) $(ceph_test_cls_lock_OBJECTS) $(ceph_test_cls_lock_LDADD) $(LIBS) test/cls_log/$(am__dirstamp): @$(MKDIR_P) test/cls_log @: > test/cls_log/$(am__dirstamp) test/cls_log/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_log/$(DEPDIR) @: > test/cls_log/$(DEPDIR)/$(am__dirstamp) test/cls_log/ceph_test_cls_log-test_cls_log.$(OBJEXT): \ test/cls_log/$(am__dirstamp) \ test/cls_log/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_log$(EXEEXT): $(ceph_test_cls_log_OBJECTS) $(ceph_test_cls_log_DEPENDENCIES) $(EXTRA_ceph_test_cls_log_DEPENDENCIES) @rm -f ceph_test_cls_log$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_log_LINK) $(ceph_test_cls_log_OBJECTS) $(ceph_test_cls_log_LDADD) $(LIBS) test/cls_rbd/$(am__dirstamp): @$(MKDIR_P) test/cls_rbd @: > test/cls_rbd/$(am__dirstamp) test/cls_rbd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_rbd/$(DEPDIR) @: > test/cls_rbd/$(DEPDIR)/$(am__dirstamp) test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.$(OBJEXT): \ test/cls_rbd/$(am__dirstamp) \ test/cls_rbd/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_rbd$(EXEEXT): $(ceph_test_cls_rbd_OBJECTS) $(ceph_test_cls_rbd_DEPENDENCIES) $(EXTRA_ceph_test_cls_rbd_DEPENDENCIES) @rm -f ceph_test_cls_rbd$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_rbd_LINK) $(ceph_test_cls_rbd_OBJECTS) $(ceph_test_cls_rbd_LDADD) $(LIBS) test/cls_refcount/$(am__dirstamp): @$(MKDIR_P) test/cls_refcount @: > test/cls_refcount/$(am__dirstamp) test/cls_refcount/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_refcount/$(DEPDIR) @: > test/cls_refcount/$(DEPDIR)/$(am__dirstamp) test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.$(OBJEXT): \ test/cls_refcount/$(am__dirstamp) \ test/cls_refcount/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_refcount$(EXEEXT): $(ceph_test_cls_refcount_OBJECTS) $(ceph_test_cls_refcount_DEPENDENCIES) $(EXTRA_ceph_test_cls_refcount_DEPENDENCIES) @rm -f ceph_test_cls_refcount$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_refcount_LINK) $(ceph_test_cls_refcount_OBJECTS) $(ceph_test_cls_refcount_LDADD) $(LIBS) test/cls_replica_log/$(am__dirstamp): @$(MKDIR_P) test/cls_replica_log @: > test/cls_replica_log/$(am__dirstamp) test/cls_replica_log/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_replica_log/$(DEPDIR) @: > test/cls_replica_log/$(DEPDIR)/$(am__dirstamp) test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.$(OBJEXT): \ test/cls_replica_log/$(am__dirstamp) \ test/cls_replica_log/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_replica_log$(EXEEXT): $(ceph_test_cls_replica_log_OBJECTS) $(ceph_test_cls_replica_log_DEPENDENCIES) $(EXTRA_ceph_test_cls_replica_log_DEPENDENCIES) @rm -f ceph_test_cls_replica_log$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_replica_log_LINK) $(ceph_test_cls_replica_log_OBJECTS) $(ceph_test_cls_replica_log_LDADD) $(LIBS) test/cls_rgw/$(am__dirstamp): @$(MKDIR_P) test/cls_rgw @: > test/cls_rgw/$(am__dirstamp) test/cls_rgw/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_rgw/$(DEPDIR) @: > test/cls_rgw/$(DEPDIR)/$(am__dirstamp) test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.$(OBJEXT): \ test/cls_rgw/$(am__dirstamp) \ test/cls_rgw/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_rgw$(EXEEXT): $(ceph_test_cls_rgw_OBJECTS) $(ceph_test_cls_rgw_DEPENDENCIES) $(EXTRA_ceph_test_cls_rgw_DEPENDENCIES) @rm -f ceph_test_cls_rgw$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_rgw_LINK) $(ceph_test_cls_rgw_OBJECTS) $(ceph_test_cls_rgw_LDADD) $(LIBS) test/ceph_test_cls_rgw_log-test_rgw_admin_log.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_rgw_log$(EXEEXT): $(ceph_test_cls_rgw_log_OBJECTS) $(ceph_test_cls_rgw_log_DEPENDENCIES) $(EXTRA_ceph_test_cls_rgw_log_DEPENDENCIES) @rm -f ceph_test_cls_rgw_log$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_rgw_log_LINK) $(ceph_test_cls_rgw_log_OBJECTS) $(ceph_test_cls_rgw_log_LDADD) $(LIBS) test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_rgw_meta$(EXEEXT): $(ceph_test_cls_rgw_meta_OBJECTS) $(ceph_test_cls_rgw_meta_DEPENDENCIES) $(EXTRA_ceph_test_cls_rgw_meta_DEPENDENCIES) @rm -f ceph_test_cls_rgw_meta$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_rgw_meta_LINK) $(ceph_test_cls_rgw_meta_OBJECTS) $(ceph_test_cls_rgw_meta_LDADD) $(LIBS) test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_rgw_opstate$(EXEEXT): $(ceph_test_cls_rgw_opstate_OBJECTS) $(ceph_test_cls_rgw_opstate_DEPENDENCIES) $(EXTRA_ceph_test_cls_rgw_opstate_DEPENDENCIES) @rm -f ceph_test_cls_rgw_opstate$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_rgw_opstate_LINK) $(ceph_test_cls_rgw_opstate_OBJECTS) $(ceph_test_cls_rgw_opstate_LDADD) $(LIBS) test/cls_statelog/$(am__dirstamp): @$(MKDIR_P) test/cls_statelog @: > test/cls_statelog/$(am__dirstamp) test/cls_statelog/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_statelog/$(DEPDIR) @: > test/cls_statelog/$(DEPDIR)/$(am__dirstamp) test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.$(OBJEXT): \ test/cls_statelog/$(am__dirstamp) \ test/cls_statelog/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_statelog$(EXEEXT): $(ceph_test_cls_statelog_OBJECTS) $(ceph_test_cls_statelog_DEPENDENCIES) $(EXTRA_ceph_test_cls_statelog_DEPENDENCIES) @rm -f ceph_test_cls_statelog$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_statelog_LINK) $(ceph_test_cls_statelog_OBJECTS) $(ceph_test_cls_statelog_LDADD) $(LIBS) test/cls_version/$(am__dirstamp): @$(MKDIR_P) test/cls_version @: > test/cls_version/$(am__dirstamp) test/cls_version/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/cls_version/$(DEPDIR) @: > test/cls_version/$(DEPDIR)/$(am__dirstamp) test/cls_version/ceph_test_cls_version-test_cls_version.$(OBJEXT): \ test/cls_version/$(am__dirstamp) \ test/cls_version/$(DEPDIR)/$(am__dirstamp) ceph_test_cls_version$(EXEEXT): $(ceph_test_cls_version_OBJECTS) $(ceph_test_cls_version_DEPENDENCIES) $(EXTRA_ceph_test_cls_version_DEPENDENCIES) @rm -f ceph_test_cls_version$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cls_version_LINK) $(ceph_test_cls_version_OBJECTS) $(ceph_test_cls_version_LDADD) $(LIBS) test/ceph_test_cors-test_cors.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_cors$(EXEEXT): $(ceph_test_cors_OBJECTS) $(ceph_test_cors_DEPENDENCIES) $(EXTRA_ceph_test_cors_DEPENDENCIES) @rm -f ceph_test_cors$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_cors_LINK) $(ceph_test_cors_OBJECTS) $(ceph_test_cors_LDADD) $(LIBS) test/testcrypto.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_crypto$(EXEEXT): $(ceph_test_crypto_OBJECTS) $(ceph_test_crypto_DEPENDENCIES) $(EXTRA_ceph_test_crypto_DEPENDENCIES) @rm -f ceph_test_crypto$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_crypto_OBJECTS) $(ceph_test_crypto_LDADD) $(LIBS) test/ceph_test_filejournal-test_filejournal.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) ceph_test_filejournal$(EXEEXT): $(ceph_test_filejournal_OBJECTS) $(ceph_test_filejournal_DEPENDENCIES) $(EXTRA_ceph_test_filejournal_DEPENDENCIES) @rm -f ceph_test_filejournal$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_filejournal_LINK) $(ceph_test_filejournal_OBJECTS) $(ceph_test_filejournal_LDADD) $(LIBS) test/objectstore/$(am__dirstamp): @$(MKDIR_P) test/objectstore @: > test/objectstore/$(am__dirstamp) test/objectstore/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/objectstore/$(DEPDIR) @: > test/objectstore/$(DEPDIR)/$(am__dirstamp) test/objectstore/test_idempotent.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) test/objectstore/FileStoreTracker.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) test/common/$(am__dirstamp): @$(MKDIR_P) test/common @: > test/common/$(am__dirstamp) test/common/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/common/$(DEPDIR) @: > test/common/$(DEPDIR)/$(am__dirstamp) test/common/ObjectContents.$(OBJEXT): test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) ceph_test_filestore_idempotent$(EXEEXT): $(ceph_test_filestore_idempotent_OBJECTS) $(ceph_test_filestore_idempotent_DEPENDENCIES) $(EXTRA_ceph_test_filestore_idempotent_DEPENDENCIES) @rm -f ceph_test_filestore_idempotent$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_filestore_idempotent_OBJECTS) $(ceph_test_filestore_idempotent_LDADD) $(LIBS) test/objectstore/test_idempotent_sequence.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) test/objectstore/DeterministicOpSequence.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) test/objectstore/TestObjectStoreState.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) test/objectstore/FileStoreDiff.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) ceph_test_filestore_idempotent_sequence$(EXEEXT): $(ceph_test_filestore_idempotent_sequence_OBJECTS) $(ceph_test_filestore_idempotent_sequence_DEPENDENCIES) $(EXTRA_ceph_test_filestore_idempotent_sequence_DEPENDENCIES) @rm -f ceph_test_filestore_idempotent_sequence$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_filestore_idempotent_sequence_OBJECTS) $(ceph_test_filestore_idempotent_sequence_LDADD) $(LIBS) test/test_get_blkdev_size.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_get_blkdev_size$(EXEEXT): $(ceph_test_get_blkdev_size_OBJECTS) $(ceph_test_get_blkdev_size_DEPENDENCIES) $(EXTRA_ceph_test_get_blkdev_size_DEPENDENCIES) @rm -f ceph_test_get_blkdev_size$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_get_blkdev_size_OBJECTS) $(ceph_test_get_blkdev_size_LDADD) $(LIBS) client/test_ioctls.$(OBJEXT): client/$(am__dirstamp) \ client/$(DEPDIR)/$(am__dirstamp) ceph_test_ioctls$(EXEEXT): $(ceph_test_ioctls_OBJECTS) $(ceph_test_ioctls_DEPENDENCIES) $(EXTRA_ceph_test_ioctls_DEPENDENCIES) @rm -f ceph_test_ioctls$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ceph_test_ioctls_OBJECTS) $(ceph_test_ioctls_LDADD) $(LIBS) test/testkeys.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_keys$(EXEEXT): $(ceph_test_keys_OBJECTS) $(ceph_test_keys_DEPENDENCIES) $(EXTRA_ceph_test_keys_DEPENDENCIES) @rm -f ceph_test_keys$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_keys_OBJECTS) $(ceph_test_keys_LDADD) $(LIBS) test/ObjectMap/$(am__dirstamp): @$(MKDIR_P) test/ObjectMap @: > test/ObjectMap/$(am__dirstamp) test/ObjectMap/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/ObjectMap/$(DEPDIR) @: > test/ObjectMap/$(DEPDIR)/$(am__dirstamp) test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.$(OBJEXT): \ test/ObjectMap/$(am__dirstamp) \ test/ObjectMap/$(DEPDIR)/$(am__dirstamp) ceph_test_keyvaluedb_atomicity$(EXEEXT): $(ceph_test_keyvaluedb_atomicity_OBJECTS) $(ceph_test_keyvaluedb_atomicity_DEPENDENCIES) $(EXTRA_ceph_test_keyvaluedb_atomicity_DEPENDENCIES) @rm -f ceph_test_keyvaluedb_atomicity$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_keyvaluedb_atomicity_LINK) $(ceph_test_keyvaluedb_atomicity_OBJECTS) $(ceph_test_keyvaluedb_atomicity_LDADD) $(LIBS) test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.$(OBJEXT): \ test/ObjectMap/$(am__dirstamp) \ test/ObjectMap/$(DEPDIR)/$(am__dirstamp) test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.$(OBJEXT): \ test/ObjectMap/$(am__dirstamp) \ test/ObjectMap/$(DEPDIR)/$(am__dirstamp) ceph_test_keyvaluedb_iterators$(EXEEXT): $(ceph_test_keyvaluedb_iterators_OBJECTS) $(ceph_test_keyvaluedb_iterators_DEPENDENCIES) $(EXTRA_ceph_test_keyvaluedb_iterators_DEPENDENCIES) @rm -f ceph_test_keyvaluedb_iterators$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_keyvaluedb_iterators_LINK) $(ceph_test_keyvaluedb_iterators_OBJECTS) $(ceph_test_keyvaluedb_iterators_LDADD) $(LIBS) test/libcephfs/$(am__dirstamp): @$(MKDIR_P) test/libcephfs @: > test/libcephfs/$(am__dirstamp) test/libcephfs/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/libcephfs/$(DEPDIR) @: > test/libcephfs/$(DEPDIR)/$(am__dirstamp) test/libcephfs/ceph_test_libcephfs-test.$(OBJEXT): \ test/libcephfs/$(am__dirstamp) \ test/libcephfs/$(DEPDIR)/$(am__dirstamp) test/libcephfs/ceph_test_libcephfs-readdir_r_cb.$(OBJEXT): \ test/libcephfs/$(am__dirstamp) \ test/libcephfs/$(DEPDIR)/$(am__dirstamp) test/libcephfs/ceph_test_libcephfs-caps.$(OBJEXT): \ test/libcephfs/$(am__dirstamp) \ test/libcephfs/$(DEPDIR)/$(am__dirstamp) test/libcephfs/ceph_test_libcephfs-multiclient.$(OBJEXT): \ test/libcephfs/$(am__dirstamp) \ test/libcephfs/$(DEPDIR)/$(am__dirstamp) ceph_test_libcephfs$(EXEEXT): $(ceph_test_libcephfs_OBJECTS) $(ceph_test_libcephfs_DEPENDENCIES) $(EXTRA_ceph_test_libcephfs_DEPENDENCIES) @rm -f ceph_test_libcephfs$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_libcephfs_LINK) $(ceph_test_libcephfs_OBJECTS) $(ceph_test_libcephfs_LDADD) $(LIBS) test/librbd/$(am__dirstamp): @$(MKDIR_P) test/librbd @: > test/librbd/$(am__dirstamp) test/librbd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/librbd/$(DEPDIR) @: > test/librbd/$(DEPDIR)/$(am__dirstamp) test/librbd/ceph_test_librbd-test_librbd.$(OBJEXT): \ test/librbd/$(am__dirstamp) \ test/librbd/$(DEPDIR)/$(am__dirstamp) ceph_test_librbd$(EXEEXT): $(ceph_test_librbd_OBJECTS) $(ceph_test_librbd_DEPENDENCIES) $(EXTRA_ceph_test_librbd_DEPENDENCIES) @rm -f ceph_test_librbd$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_librbd_LINK) $(ceph_test_librbd_OBJECTS) $(ceph_test_librbd_LDADD) $(LIBS) test/librbd/ceph_test_librbd_fsx-fsx.$(OBJEXT): \ test/librbd/$(am__dirstamp) \ test/librbd/$(DEPDIR)/$(am__dirstamp) ceph_test_librbd_fsx$(EXEEXT): $(ceph_test_librbd_fsx_OBJECTS) $(ceph_test_librbd_fsx_DEPENDENCIES) $(EXTRA_ceph_test_librbd_fsx_DEPENDENCIES) @rm -f ceph_test_librbd_fsx$(EXEEXT) $(AM_V_CCLD)$(ceph_test_librbd_fsx_LINK) $(ceph_test_librbd_fsx_OBJECTS) $(ceph_test_librbd_fsx_LDADD) $(LIBS) test/mon/$(am__dirstamp): @$(MKDIR_P) test/mon @: > test/mon/$(am__dirstamp) test/mon/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/mon/$(DEPDIR) @: > test/mon/$(DEPDIR)/$(am__dirstamp) test/mon/test_mon_workloadgen.$(OBJEXT): test/mon/$(am__dirstamp) \ test/mon/$(DEPDIR)/$(am__dirstamp) ceph_test_mon_workloadgen$(EXEEXT): $(ceph_test_mon_workloadgen_OBJECTS) $(ceph_test_mon_workloadgen_DEPENDENCIES) $(EXTRA_ceph_test_mon_workloadgen_DEPENDENCIES) @rm -f ceph_test_mon_workloadgen$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_mon_workloadgen_OBJECTS) $(ceph_test_mon_workloadgen_LDADD) $(LIBS) test/testmsgr.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_msgr$(EXEEXT): $(ceph_test_msgr_OBJECTS) $(ceph_test_msgr_DEPENDENCIES) $(EXTRA_ceph_test_msgr_DEPENDENCIES) @rm -f ceph_test_msgr$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_msgr_OBJECTS) $(ceph_test_msgr_LDADD) $(LIBS) test/test_mutate.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_mutate$(EXEEXT): $(ceph_test_mutate_OBJECTS) $(ceph_test_mutate_DEPENDENCIES) $(EXTRA_ceph_test_mutate_DEPENDENCIES) @rm -f ceph_test_mutate$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_mutate_OBJECTS) $(ceph_test_mutate_LDADD) $(LIBS) test/ObjectMap/ceph_test_object_map-test_object_map.$(OBJEXT): \ test/ObjectMap/$(am__dirstamp) \ test/ObjectMap/$(DEPDIR)/$(am__dirstamp) test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.$(OBJEXT): \ test/ObjectMap/$(am__dirstamp) \ test/ObjectMap/$(DEPDIR)/$(am__dirstamp) ceph_test_object_map$(EXEEXT): $(ceph_test_object_map_OBJECTS) $(ceph_test_object_map_DEPENDENCIES) $(EXTRA_ceph_test_object_map_DEPENDENCIES) @rm -f ceph_test_object_map$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_object_map_LINK) $(ceph_test_object_map_OBJECTS) $(ceph_test_object_map_LDADD) $(LIBS) test/osdc/$(am__dirstamp): @$(MKDIR_P) test/osdc @: > test/osdc/$(am__dirstamp) test/osdc/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/osdc/$(DEPDIR) @: > test/osdc/$(DEPDIR)/$(am__dirstamp) test/osdc/object_cacher_stress.$(OBJEXT): test/osdc/$(am__dirstamp) \ test/osdc/$(DEPDIR)/$(am__dirstamp) test/osdc/FakeWriteback.$(OBJEXT): test/osdc/$(am__dirstamp) \ test/osdc/$(DEPDIR)/$(am__dirstamp) ceph_test_objectcacher_stress$(EXEEXT): $(ceph_test_objectcacher_stress_OBJECTS) $(ceph_test_objectcacher_stress_DEPENDENCIES) $(EXTRA_ceph_test_objectcacher_stress_DEPENDENCIES) @rm -f ceph_test_objectcacher_stress$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_objectcacher_stress_OBJECTS) $(ceph_test_objectcacher_stress_LDADD) $(LIBS) test/objectstore/ceph_test_objectstore-store_test.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) ceph_test_objectstore$(EXEEXT): $(ceph_test_objectstore_OBJECTS) $(ceph_test_objectstore_DEPENDENCIES) $(EXTRA_ceph_test_objectstore_DEPENDENCIES) @rm -f ceph_test_objectstore$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_objectstore_LINK) $(ceph_test_objectstore_OBJECTS) $(ceph_test_objectstore_LDADD) $(LIBS) test/objectstore/workload_generator.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) ceph_test_objectstore_workloadgen$(EXEEXT): $(ceph_test_objectstore_workloadgen_OBJECTS) $(ceph_test_objectstore_workloadgen_DEPENDENCIES) $(EXTRA_ceph_test_objectstore_workloadgen_DEPENDENCIES) @rm -f ceph_test_objectstore_workloadgen$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_objectstore_workloadgen_OBJECTS) $(ceph_test_objectstore_workloadgen_LDADD) $(LIBS) test/osd/$(am__dirstamp): @$(MKDIR_P) test/osd @: > test/osd/$(am__dirstamp) test/osd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/osd/$(DEPDIR) @: > test/osd/$(DEPDIR)/$(am__dirstamp) test/osd/TestRados.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) test/osd/TestOpStat.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) test/osd/Object.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) test/osd/RadosModel.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) ceph_test_rados$(EXEEXT): $(ceph_test_rados_OBJECTS) $(ceph_test_rados_DEPENDENCIES) $(EXTRA_ceph_test_rados_DEPENDENCIES) @rm -f ceph_test_rados$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_rados_OBJECTS) $(ceph_test_rados_LDADD) $(LIBS) test/librados/ceph_test_rados_api_aio-aio.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_aio$(EXEEXT): $(ceph_test_rados_api_aio_OBJECTS) $(ceph_test_rados_api_aio_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_aio_DEPENDENCIES) @rm -f ceph_test_rados_api_aio$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_aio_LINK) $(ceph_test_rados_api_aio_OBJECTS) $(ceph_test_rados_api_aio_LDADD) $(LIBS) test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_c_read_operations$(EXEEXT): $(ceph_test_rados_api_c_read_operations_OBJECTS) $(ceph_test_rados_api_c_read_operations_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_c_read_operations_DEPENDENCIES) @rm -f ceph_test_rados_api_c_read_operations$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_c_read_operations_LINK) $(ceph_test_rados_api_c_read_operations_OBJECTS) $(ceph_test_rados_api_c_read_operations_LDADD) $(LIBS) test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_c_write_operations$(EXEEXT): $(ceph_test_rados_api_c_write_operations_OBJECTS) $(ceph_test_rados_api_c_write_operations_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_c_write_operations_DEPENDENCIES) @rm -f ceph_test_rados_api_c_write_operations$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_c_write_operations_LINK) $(ceph_test_rados_api_c_write_operations_OBJECTS) $(ceph_test_rados_api_c_write_operations_LDADD) $(LIBS) test/librados/ceph_test_rados_api_cls-cls.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_cls$(EXEEXT): $(ceph_test_rados_api_cls_OBJECTS) $(ceph_test_rados_api_cls_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_cls_DEPENDENCIES) @rm -f ceph_test_rados_api_cls$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_cls_LINK) $(ceph_test_rados_api_cls_OBJECTS) $(ceph_test_rados_api_cls_LDADD) $(LIBS) test/librados/ceph_test_rados_api_cmd-cmd.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_cmd$(EXEEXT): $(ceph_test_rados_api_cmd_OBJECTS) $(ceph_test_rados_api_cmd_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_cmd_DEPENDENCIES) @rm -f ceph_test_rados_api_cmd$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_cmd_LINK) $(ceph_test_rados_api_cmd_OBJECTS) $(ceph_test_rados_api_cmd_LDADD) $(LIBS) test/librados/ceph_test_rados_api_io-io.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_io$(EXEEXT): $(ceph_test_rados_api_io_OBJECTS) $(ceph_test_rados_api_io_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_io_DEPENDENCIES) @rm -f ceph_test_rados_api_io$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_io_LINK) $(ceph_test_rados_api_io_OBJECTS) $(ceph_test_rados_api_io_LDADD) $(LIBS) test/librados/ceph_test_rados_api_list-list.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_list$(EXEEXT): $(ceph_test_rados_api_list_OBJECTS) $(ceph_test_rados_api_list_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_list_DEPENDENCIES) @rm -f ceph_test_rados_api_list$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_list_LINK) $(ceph_test_rados_api_list_OBJECTS) $(ceph_test_rados_api_list_LDADD) $(LIBS) test/librados/ceph_test_rados_api_lock-lock.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_lock$(EXEEXT): $(ceph_test_rados_api_lock_OBJECTS) $(ceph_test_rados_api_lock_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_lock_DEPENDENCIES) @rm -f ceph_test_rados_api_lock$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_lock_LINK) $(ceph_test_rados_api_lock_OBJECTS) $(ceph_test_rados_api_lock_LDADD) $(LIBS) test/librados/ceph_test_rados_api_misc-misc.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_misc$(EXEEXT): $(ceph_test_rados_api_misc_OBJECTS) $(ceph_test_rados_api_misc_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_misc_DEPENDENCIES) @rm -f ceph_test_rados_api_misc$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_misc_LINK) $(ceph_test_rados_api_misc_OBJECTS) $(ceph_test_rados_api_misc_LDADD) $(LIBS) test/librados/ceph_test_rados_api_pool-pool.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_pool$(EXEEXT): $(ceph_test_rados_api_pool_OBJECTS) $(ceph_test_rados_api_pool_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_pool_DEPENDENCIES) @rm -f ceph_test_rados_api_pool$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_pool_LINK) $(ceph_test_rados_api_pool_OBJECTS) $(ceph_test_rados_api_pool_LDADD) $(LIBS) test/librados/ceph_test_rados_api_snapshots-snapshots.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_snapshots$(EXEEXT): $(ceph_test_rados_api_snapshots_OBJECTS) $(ceph_test_rados_api_snapshots_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_snapshots_DEPENDENCIES) @rm -f ceph_test_rados_api_snapshots$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_snapshots_LINK) $(ceph_test_rados_api_snapshots_OBJECTS) $(ceph_test_rados_api_snapshots_LDADD) $(LIBS) test/librados/ceph_test_rados_api_stat-stat.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_stat$(EXEEXT): $(ceph_test_rados_api_stat_OBJECTS) $(ceph_test_rados_api_stat_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_stat_DEPENDENCIES) @rm -f ceph_test_rados_api_stat$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_stat_LINK) $(ceph_test_rados_api_stat_OBJECTS) $(ceph_test_rados_api_stat_LDADD) $(LIBS) test/librados/ceph_test_rados_api_tier-tier.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) osd/ceph_test_rados_api_tier-HitSet.$(OBJEXT): osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_tier$(EXEEXT): $(ceph_test_rados_api_tier_OBJECTS) $(ceph_test_rados_api_tier_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_tier_DEPENDENCIES) @rm -f ceph_test_rados_api_tier$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_tier_LINK) $(ceph_test_rados_api_tier_OBJECTS) $(ceph_test_rados_api_tier_LDADD) $(LIBS) test/librados/ceph_test_rados_api_watch_notify-watch_notify.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_api_watch_notify$(EXEEXT): $(ceph_test_rados_api_watch_notify_OBJECTS) $(ceph_test_rados_api_watch_notify_DEPENDENCIES) $(EXTRA_ceph_test_rados_api_watch_notify_DEPENDENCIES) @rm -f ceph_test_rados_api_watch_notify$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rados_api_watch_notify_LINK) $(ceph_test_rados_api_watch_notify_OBJECTS) $(ceph_test_rados_api_watch_notify_LDADD) $(LIBS) test/system/rados_delete_pools_parallel.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/st_rados_create_pool.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/st_rados_delete_pool.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/st_rados_list_objects.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_delete_pools_parallel$(EXEEXT): $(ceph_test_rados_delete_pools_parallel_OBJECTS) $(ceph_test_rados_delete_pools_parallel_DEPENDENCIES) $(EXTRA_ceph_test_rados_delete_pools_parallel_DEPENDENCIES) @rm -f ceph_test_rados_delete_pools_parallel$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_rados_delete_pools_parallel_OBJECTS) $(ceph_test_rados_delete_pools_parallel_LDADD) $(LIBS) test/system/rados_list_parallel.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_list_parallel$(EXEEXT): $(ceph_test_rados_list_parallel_OBJECTS) $(ceph_test_rados_list_parallel_DEPENDENCIES) $(EXTRA_ceph_test_rados_list_parallel_DEPENDENCIES) @rm -f ceph_test_rados_list_parallel$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_rados_list_parallel_OBJECTS) $(ceph_test_rados_list_parallel_LDADD) $(LIBS) test/system/rados_open_pools_parallel.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_open_pools_parallel$(EXEEXT): $(ceph_test_rados_open_pools_parallel_OBJECTS) $(ceph_test_rados_open_pools_parallel_DEPENDENCIES) $(EXTRA_ceph_test_rados_open_pools_parallel_DEPENDENCIES) @rm -f ceph_test_rados_open_pools_parallel$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_rados_open_pools_parallel_OBJECTS) $(ceph_test_rados_open_pools_parallel_LDADD) $(LIBS) test/system/rados_watch_notify.$(OBJEXT): test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/st_rados_delete_objs.$(OBJEXT): \ test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/st_rados_watch.$(OBJEXT): test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) test/system/st_rados_notify.$(OBJEXT): test/system/$(am__dirstamp) \ test/system/$(DEPDIR)/$(am__dirstamp) ceph_test_rados_watch_notify$(EXEEXT): $(ceph_test_rados_watch_notify_OBJECTS) $(ceph_test_rados_watch_notify_DEPENDENCIES) $(EXTRA_ceph_test_rados_watch_notify_DEPENDENCIES) @rm -f ceph_test_rados_watch_notify$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_rados_watch_notify_OBJECTS) $(ceph_test_rados_watch_notify_LDADD) $(LIBS) test/test_rewrite_latency.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_rewrite_latency$(EXEEXT): $(ceph_test_rewrite_latency_OBJECTS) $(ceph_test_rewrite_latency_DEPENDENCIES) $(EXTRA_ceph_test_rewrite_latency_DEPENDENCIES) @rm -f ceph_test_rewrite_latency$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_rewrite_latency_OBJECTS) $(ceph_test_rewrite_latency_LDADD) $(LIBS) test/rgw/$(am__dirstamp): @$(MKDIR_P) test/rgw @: > test/rgw/$(am__dirstamp) test/rgw/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/rgw/$(DEPDIR) @: > test/rgw/$(DEPDIR)/$(am__dirstamp) test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.$(OBJEXT): \ test/rgw/$(am__dirstamp) test/rgw/$(DEPDIR)/$(am__dirstamp) ceph_test_rgw_manifest$(EXEEXT): $(ceph_test_rgw_manifest_OBJECTS) $(ceph_test_rgw_manifest_DEPENDENCIES) $(EXTRA_ceph_test_rgw_manifest_DEPENDENCIES) @rm -f ceph_test_rgw_manifest$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_rgw_manifest_LINK) $(ceph_test_rgw_manifest_OBJECTS) $(ceph_test_rgw_manifest_LDADD) $(LIBS) test/TestSignalHandlers.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_signal_handlers$(EXEEXT): $(ceph_test_signal_handlers_OBJECTS) $(ceph_test_signal_handlers_DEPENDENCIES) $(EXTRA_ceph_test_signal_handlers_DEPENDENCIES) @rm -f ceph_test_signal_handlers$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_signal_handlers_OBJECTS) $(ceph_test_signal_handlers_LDADD) $(LIBS) test/ceph_test_snap_mapper-test_snap_mapper.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) ceph_test_snap_mapper$(EXEEXT): $(ceph_test_snap_mapper_OBJECTS) $(ceph_test_snap_mapper_DEPENDENCIES) $(EXTRA_ceph_test_snap_mapper_DEPENDENCIES) @rm -f ceph_test_snap_mapper$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_snap_mapper_LINK) $(ceph_test_snap_mapper_OBJECTS) $(ceph_test_snap_mapper_LDADD) $(LIBS) test/ceph_test_stress_watch-test_stress_watch.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) ceph_test_stress_watch$(EXEEXT): $(ceph_test_stress_watch_OBJECTS) $(ceph_test_stress_watch_DEPENDENCIES) $(EXTRA_ceph_test_stress_watch_DEPENDENCIES) @rm -f ceph_test_stress_watch$(EXEEXT) $(AM_V_CXXLD)$(ceph_test_stress_watch_LINK) $(ceph_test_stress_watch_OBJECTS) $(ceph_test_stress_watch_LDADD) $(LIBS) test/TestTimers.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_timers$(EXEEXT): $(ceph_test_timers_OBJECTS) $(ceph_test_timers_DEPENDENCIES) $(EXTRA_ceph_test_timers_DEPENDENCIES) @rm -f ceph_test_timers$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_timers_OBJECTS) $(ceph_test_timers_LDADD) $(LIBS) test/test_trans.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_test_trans$(EXEEXT): $(ceph_test_trans_OBJECTS) $(ceph_test_trans_DEPENDENCIES) $(EXTRA_ceph_test_trans_DEPENDENCIES) @rm -f ceph_test_trans$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_test_trans_OBJECTS) $(ceph_test_trans_LDADD) $(LIBS) test/bench/tp_bench.$(OBJEXT): test/bench/$(am__dirstamp) \ test/bench/$(DEPDIR)/$(am__dirstamp) ceph_tpbench$(EXEEXT): $(ceph_tpbench_OBJECTS) $(ceph_tpbench_DEPENDENCIES) $(EXTRA_ceph_tpbench_DEPENDENCIES) @rm -f ceph_tpbench$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(ceph_tpbench_OBJECTS) $(ceph_tpbench_LDADD) $(LIBS) test/ceph_xattr_bench-xattr_bench.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) ceph_xattr_bench$(EXEEXT): $(ceph_xattr_bench_OBJECTS) $(ceph_xattr_bench_DEPENDENCIES) $(EXTRA_ceph_xattr_bench_DEPENDENCIES) @rm -f ceph_xattr_bench$(EXEEXT) $(AM_V_CXXLD)$(ceph_xattr_bench_LINK) $(ceph_xattr_bench_OBJECTS) $(ceph_xattr_bench_LDADD) $(LIBS) cephfs$(EXEEXT): $(cephfs_OBJECTS) $(cephfs_DEPENDENCIES) $(EXTRA_cephfs_DEPENDENCIES) @rm -f cephfs$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(cephfs_OBJECTS) $(cephfs_LDADD) $(LIBS) tools/crushtool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) crushtool$(EXEEXT): $(crushtool_OBJECTS) $(crushtool_DEPENDENCIES) $(EXTRA_crushtool_DEPENDENCIES) @rm -f crushtool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(crushtool_OBJECTS) $(crushtool_LDADD) $(LIBS) test/common/get_command_descriptions.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) get_command_descriptions$(EXEEXT): $(get_command_descriptions_OBJECTS) $(get_command_descriptions_DEPENDENCIES) $(EXTRA_get_command_descriptions_DEPENDENCIES) @rm -f get_command_descriptions$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(get_command_descriptions_OBJECTS) $(get_command_descriptions_LDADD) $(LIBS) librados-config$(EXEEXT): $(librados_config_OBJECTS) $(librados_config_DEPENDENCIES) $(EXTRA_librados_config_DEPENDENCIES) @rm -f librados-config$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(librados_config_OBJECTS) $(librados_config_LDADD) $(LIBS) tools/monmaptool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) monmaptool$(EXEEXT): $(monmaptool_OBJECTS) $(monmaptool_DEPENDENCIES) $(EXTRA_monmaptool_DEPENDENCIES) @rm -f monmaptool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(monmaptool_OBJECTS) $(monmaptool_LDADD) $(LIBS) mount/$(am__dirstamp): @$(MKDIR_P) mount @: > mount/$(am__dirstamp) mount/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) mount/$(DEPDIR) @: > mount/$(DEPDIR)/$(am__dirstamp) mount/mount.ceph.$(OBJEXT): mount/$(am__dirstamp) \ mount/$(DEPDIR)/$(am__dirstamp) common/secret.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) mount.ceph$(EXEEXT): $(mount_ceph_OBJECTS) $(mount_ceph_DEPENDENCIES) $(EXTRA_mount_ceph_DEPENDENCIES) @rm -f mount.ceph$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mount_ceph_OBJECTS) $(mount_ceph_LDADD) $(LIBS) tools/osdmaptool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) osdmaptool$(EXEEXT): $(osdmaptool_OBJECTS) $(osdmaptool_DEPENDENCIES) $(EXTRA_osdmaptool_DEPENDENCIES) @rm -f osdmaptool$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(osdmaptool_OBJECTS) $(osdmaptool_LDADD) $(LIBS) tools/rados/$(am__dirstamp): @$(MKDIR_P) tools/rados @: > tools/rados/$(am__dirstamp) tools/rados/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) tools/rados/$(DEPDIR) @: > tools/rados/$(DEPDIR)/$(am__dirstamp) tools/rados/rados.$(OBJEXT): tools/rados/$(am__dirstamp) \ tools/rados/$(DEPDIR)/$(am__dirstamp) tools/rados/rados_import.$(OBJEXT): tools/rados/$(am__dirstamp) \ tools/rados/$(DEPDIR)/$(am__dirstamp) tools/rados/rados_export.$(OBJEXT): tools/rados/$(am__dirstamp) \ tools/rados/$(DEPDIR)/$(am__dirstamp) tools/rados/rados_sync.$(OBJEXT): tools/rados/$(am__dirstamp) \ tools/rados/$(DEPDIR)/$(am__dirstamp) common/obj_bencher.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) rados$(EXEEXT): $(rados_OBJECTS) $(rados_DEPENDENCIES) $(EXTRA_rados_DEPENDENCIES) @rm -f rados$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(rados_OBJECTS) $(rados_LDADD) $(LIBS) rgw/rgw_resolve.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_swift.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_s3.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_usage.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_user.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_bucket.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_metadata.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_replica_log.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_log.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_opstate.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_replica_log.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_rest_config.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_http_client.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_swift.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_swift_auth.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_loadgen.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/rgw_main.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) radosgw$(EXEEXT): $(radosgw_OBJECTS) $(radosgw_DEPENDENCIES) $(EXTRA_radosgw_DEPENDENCIES) @rm -f radosgw$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(radosgw_OBJECTS) $(radosgw_LDADD) $(LIBS) rgw/rgw_admin.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) radosgw-admin$(EXEEXT): $(radosgw_admin_OBJECTS) $(radosgw_admin_DEPENDENCIES) $(EXTRA_radosgw_admin_DEPENDENCIES) @rm -f radosgw-admin$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(radosgw_admin_OBJECTS) $(radosgw_admin_LDADD) $(LIBS) rbd$(EXEEXT): $(rbd_OBJECTS) $(rbd_DEPENDENCIES) $(EXTRA_rbd_DEPENDENCIES) @rm -f rbd$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(rbd_OBJECTS) $(rbd_LDADD) $(LIBS) rbd_fuse/$(am__dirstamp): @$(MKDIR_P) rbd_fuse @: > rbd_fuse/$(am__dirstamp) rbd_fuse/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) rbd_fuse/$(DEPDIR) @: > rbd_fuse/$(DEPDIR)/$(am__dirstamp) rbd_fuse/rbd-fuse.$(OBJEXT): rbd_fuse/$(am__dirstamp) \ rbd_fuse/$(DEPDIR)/$(am__dirstamp) rbd-fuse$(EXEEXT): $(rbd_fuse_OBJECTS) $(rbd_fuse_DEPENDENCIES) $(EXTRA_rbd_fuse_DEPENDENCIES) @rm -f rbd-fuse$(EXEEXT) $(AM_V_CCLD)$(LINK) $(rbd_fuse_OBJECTS) $(rbd_fuse_LDADD) $(LIBS) tools/rest_bench-rest_bench.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) common/rest_bench-obj_bencher.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) rest-bench$(EXEEXT): $(rest_bench_OBJECTS) $(rest_bench_DEPENDENCIES) $(EXTRA_rest_bench_DEPENDENCIES) @rm -f rest-bench$(EXEEXT) $(AM_V_CXXLD)$(rest_bench_LINK) $(rest_bench_OBJECTS) $(rest_bench_LDADD) $(LIBS) test/test_build_libcephfs-buildtest_skeleton.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) osdc/test_build_libcephfs-Objecter.$(OBJEXT): osdc/$(am__dirstamp) \ osdc/$(DEPDIR)/$(am__dirstamp) osdc/test_build_libcephfs-ObjectCacher.$(OBJEXT): \ osdc/$(am__dirstamp) osdc/$(DEPDIR)/$(am__dirstamp) osdc/test_build_libcephfs-Filer.$(OBJEXT): osdc/$(am__dirstamp) \ osdc/$(DEPDIR)/$(am__dirstamp) osdc/test_build_libcephfs-Striper.$(OBJEXT): osdc/$(am__dirstamp) \ osdc/$(DEPDIR)/$(am__dirstamp) osdc/test_build_libcephfs-Journaler.$(OBJEXT): osdc/$(am__dirstamp) \ osdc/$(DEPDIR)/$(am__dirstamp) test_build_libcephfs$(EXEEXT): $(test_build_libcephfs_OBJECTS) $(test_build_libcephfs_DEPENDENCIES) $(EXTRA_test_build_libcephfs_DEPENDENCIES) @rm -f test_build_libcephfs$(EXEEXT) $(AM_V_CXXLD)$(test_build_libcephfs_LINK) $(test_build_libcephfs_OBJECTS) $(test_build_libcephfs_LDADD) $(LIBS) test/test_build_libcommon-buildtest_skeleton.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-DecayCounter.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-LogClient.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-LogEntry.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-PrebufferedStreambuf.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-SloppyCRCMap.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-BackTrace.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-perf_counters.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Mutex.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-OutputDataSocket.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-admin_socket.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-admin_socket_client.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-cmdparse.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-escape.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-io_priority.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Clock.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Throttle.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Timer.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Finisher.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-environment.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-assert.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-run_cmd.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-WorkQueue.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ConfUtils.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-MemoryModel.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-armor.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-fd.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-xattr.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-safe_io.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-snap_types.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-str_list.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-str_map.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-errno.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-RefCountedObj.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-blkdev.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-common_init.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-pipe.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_argparse.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_context.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-buffer.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-code_environment.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-dout.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-histogram.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-signal.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-simple_spin.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Thread.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-Formatter.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-HeartbeatMap.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-config.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-utf8.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-mime.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-strtol.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-page.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-lockdep.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-version.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-hex.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-entity_name.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_crypto.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_crypto_cms.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_json.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ipaddr.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-pick_address.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-util.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-TextTable.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_fs.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_hash.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_strings.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-ceph_frag.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-addr_parsing.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-hobject.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-bloom_filter.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/test_build_libcommon-linux_version.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) mon/test_build_libcommon-MonCap.$(OBJEXT): mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) mon/test_build_libcommon-MonClient.$(OBJEXT): mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) mon/test_build_libcommon-MonMap.$(OBJEXT): mon/$(am__dirstamp) \ mon/$(DEPDIR)/$(am__dirstamp) osd/test_build_libcommon-OSDMap.$(OBJEXT): osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/test_build_libcommon-osd_types.$(OBJEXT): osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/test_build_libcommon-ECMsgTypes.$(OBJEXT): osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) osd/test_build_libcommon-HitSet.$(OBJEXT): osd/$(am__dirstamp) \ osd/$(DEPDIR)/$(am__dirstamp) mds/test_build_libcommon-MDSMap.$(OBJEXT): mds/$(am__dirstamp) \ mds/$(DEPDIR)/$(am__dirstamp) mds/test_build_libcommon-inode_backtrace.$(OBJEXT): \ mds/$(am__dirstamp) mds/$(DEPDIR)/$(am__dirstamp) mds/test_build_libcommon-mdstypes.$(OBJEXT): mds/$(am__dirstamp) \ mds/$(DEPDIR)/$(am__dirstamp) mds/test_build_libcommon-flock.$(OBJEXT): mds/$(am__dirstamp) \ mds/$(DEPDIR)/$(am__dirstamp) test_build_libcommon$(EXEEXT): $(test_build_libcommon_OBJECTS) $(test_build_libcommon_DEPENDENCIES) $(EXTRA_test_build_libcommon_DEPENDENCIES) @rm -f test_build_libcommon$(EXEEXT) $(AM_V_CXXLD)$(test_build_libcommon_LINK) $(test_build_libcommon_OBJECTS) $(test_build_libcommon_LDADD) $(LIBS) test/test_build_librados-buildtest_skeleton.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) librados/test_build_librados-librados.$(OBJEXT): \ librados/$(am__dirstamp) librados/$(DEPDIR)/$(am__dirstamp) librados/test_build_librados-RadosClient.$(OBJEXT): \ librados/$(am__dirstamp) librados/$(DEPDIR)/$(am__dirstamp) librados/test_build_librados-IoCtxImpl.$(OBJEXT): \ librados/$(am__dirstamp) librados/$(DEPDIR)/$(am__dirstamp) librados/test_build_librados-snap_set_diff.$(OBJEXT): \ librados/$(am__dirstamp) librados/$(DEPDIR)/$(am__dirstamp) test_build_librados$(EXEEXT): $(test_build_librados_OBJECTS) $(test_build_librados_DEPENDENCIES) $(EXTRA_test_build_librados_DEPENDENCIES) @rm -f test_build_librados$(EXEEXT) $(AM_V_CXXLD)$(test_build_librados_LINK) $(test_build_librados_OBJECTS) $(test_build_librados_LDADD) $(LIBS) test/test_build_librgw-buildtest_skeleton.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-librgw.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_acl.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_acl_s3.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_acl_swift.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_client_io.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_fcgi.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_xml.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_usage.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_json_enc.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_user.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_bucket.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_tools.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_rados.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_http_client.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_rest_client.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_rest_conn.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_op.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_common.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_cache.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_formats.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_log.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_multi.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_policy_s3.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_gc.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_multi_del.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_env.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_cors.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_cors_s3.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_auth_s3.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_metadata.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_replica_log.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_keystone.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_quota.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) rgw/test_build_librgw-rgw_dencoder.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) test_build_librgw$(EXEEXT): $(test_build_librgw_OBJECTS) $(test_build_librgw_DEPENDENCIES) $(EXTRA_test_build_librgw_DEPENDENCIES) @rm -f test_build_librgw$(EXEEXT) $(AM_V_CXXLD)$(test_build_librgw_LINK) $(test_build_librgw_OBJECTS) $(test_build_librgw_LDADD) $(LIBS) test/unittest_addrs-test_addrs.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_addrs$(EXEEXT): $(unittest_addrs_OBJECTS) $(unittest_addrs_DEPENDENCIES) $(EXTRA_unittest_addrs_DEPENDENCIES) @rm -f unittest_addrs$(EXEEXT) $(AM_V_CXXLD)$(unittest_addrs_LINK) $(unittest_addrs_OBJECTS) $(unittest_addrs_LDADD) $(LIBS) test/unittest_admin_socket-admin_socket.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_admin_socket$(EXEEXT): $(unittest_admin_socket_OBJECTS) $(unittest_admin_socket_DEPENDENCIES) $(EXTRA_unittest_admin_socket_DEPENDENCIES) @rm -f unittest_admin_socket$(EXEEXT) $(AM_V_CXXLD)$(unittest_admin_socket_LINK) $(unittest_admin_socket_OBJECTS) $(unittest_admin_socket_LDADD) $(LIBS) test/unittest_arch-test_arch.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_arch$(EXEEXT): $(unittest_arch_OBJECTS) $(unittest_arch_DEPENDENCIES) $(EXTRA_unittest_arch_DEPENDENCIES) @rm -f unittest_arch$(EXEEXT) $(AM_V_CXXLD)$(unittest_arch_LINK) $(unittest_arch_OBJECTS) $(unittest_arch_LDADD) $(LIBS) test/unittest_base64-base64.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_base64$(EXEEXT): $(unittest_base64_OBJECTS) $(unittest_base64_DEPENDENCIES) $(EXTRA_unittest_base64_DEPENDENCIES) @rm -f unittest_base64$(EXEEXT) $(AM_V_CXXLD)$(unittest_base64_LINK) $(unittest_base64_OBJECTS) $(unittest_base64_LDADD) $(LIBS) test/common/unittest_bloom_filter-test_bloom_filter.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_bloom_filter$(EXEEXT): $(unittest_bloom_filter_OBJECTS) $(unittest_bloom_filter_DEPENDENCIES) $(EXTRA_unittest_bloom_filter_DEPENDENCIES) @rm -f unittest_bloom_filter$(EXEEXT) $(AM_V_CXXLD)$(unittest_bloom_filter_LINK) $(unittest_bloom_filter_OBJECTS) $(unittest_bloom_filter_LDADD) $(LIBS) test/unittest_bufferlist-bufferlist.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_bufferlist$(EXEEXT): $(unittest_bufferlist_OBJECTS) $(unittest_bufferlist_DEPENDENCIES) $(EXTRA_unittest_bufferlist_DEPENDENCIES) @rm -f unittest_bufferlist$(EXEEXT) $(AM_V_CXXLD)$(unittest_bufferlist_LINK) $(unittest_bufferlist_OBJECTS) $(unittest_bufferlist_LDADD) $(LIBS) test/unittest_ceph_argparse-ceph_argparse.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_ceph_argparse$(EXEEXT): $(unittest_ceph_argparse_OBJECTS) $(unittest_ceph_argparse_DEPENDENCIES) $(EXTRA_unittest_ceph_argparse_DEPENDENCIES) @rm -f unittest_ceph_argparse$(EXEEXT) $(AM_V_CXXLD)$(unittest_ceph_argparse_LINK) $(unittest_ceph_argparse_OBJECTS) $(unittest_ceph_argparse_LDADD) $(LIBS) test/unittest_ceph_compatset-ceph_compatset.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_ceph_compatset$(EXEEXT): $(unittest_ceph_compatset_OBJECTS) $(unittest_ceph_compatset_DEPENDENCIES) $(EXTRA_unittest_ceph_compatset_DEPENDENCIES) @rm -f unittest_ceph_compatset$(EXEEXT) $(AM_V_CXXLD)$(unittest_ceph_compatset_LINK) $(unittest_ceph_compatset_OBJECTS) $(unittest_ceph_compatset_LDADD) $(LIBS) test/unittest_ceph_crypto-ceph_crypto.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_ceph_crypto$(EXEEXT): $(unittest_ceph_crypto_OBJECTS) $(unittest_ceph_crypto_DEPENDENCIES) $(EXTRA_unittest_ceph_crypto_DEPENDENCIES) @rm -f unittest_ceph_crypto$(EXEEXT) $(AM_V_CXXLD)$(unittest_ceph_crypto_LINK) $(unittest_ceph_crypto_OBJECTS) $(unittest_ceph_crypto_LDADD) $(LIBS) test/objectstore/unittest_chain_xattr-chain_xattr.$(OBJEXT): \ test/objectstore/$(am__dirstamp) \ test/objectstore/$(DEPDIR)/$(am__dirstamp) unittest_chain_xattr$(EXEEXT): $(unittest_chain_xattr_OBJECTS) $(unittest_chain_xattr_DEPENDENCIES) $(EXTRA_unittest_chain_xattr_DEPENDENCIES) @rm -f unittest_chain_xattr$(EXEEXT) $(AM_V_CXXLD)$(unittest_chain_xattr_LINK) $(unittest_chain_xattr_OBJECTS) $(unittest_chain_xattr_LDADD) $(LIBS) test/common/unittest_config-test_config.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_config$(EXEEXT): $(unittest_config_OBJECTS) $(unittest_config_DEPENDENCIES) $(EXTRA_unittest_config_DEPENDENCIES) @rm -f unittest_config$(EXEEXT) $(AM_V_CXXLD)$(unittest_config_LINK) $(unittest_config_OBJECTS) $(unittest_config_LDADD) $(LIBS) test/unittest_confutils-confutils.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_confutils$(EXEEXT): $(unittest_confutils_OBJECTS) $(unittest_confutils_DEPENDENCIES) $(EXTRA_unittest_confutils_DEPENDENCIES) @rm -f unittest_confutils$(EXEEXT) $(AM_V_CXXLD)$(unittest_confutils_LINK) $(unittest_confutils_OBJECTS) $(unittest_confutils_LDADD) $(LIBS) test/common/unittest_context-test_context.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_context$(EXEEXT): $(unittest_context_OBJECTS) $(unittest_context_DEPENDENCIES) $(EXTRA_unittest_context_DEPENDENCIES) @rm -f unittest_context$(EXEEXT) $(AM_V_CXXLD)$(unittest_context_LINK) $(unittest_context_OBJECTS) $(unittest_context_LDADD) $(LIBS) test/common/unittest_crc32c-test_crc32c.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_crc32c$(EXEEXT): $(unittest_crc32c_OBJECTS) $(unittest_crc32c_DEPENDENCIES) $(EXTRA_unittest_crc32c_DEPENDENCIES) @rm -f unittest_crc32c$(EXEEXT) $(AM_V_CXXLD)$(unittest_crc32c_LINK) $(unittest_crc32c_OBJECTS) $(unittest_crc32c_LDADD) $(LIBS) test/crush/$(am__dirstamp): @$(MKDIR_P) test/crush @: > test/crush/$(am__dirstamp) test/crush/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/crush/$(DEPDIR) @: > test/crush/$(DEPDIR)/$(am__dirstamp) test/crush/unittest_crush_indep-indep.$(OBJEXT): \ test/crush/$(am__dirstamp) \ test/crush/$(DEPDIR)/$(am__dirstamp) unittest_crush_indep$(EXEEXT): $(unittest_crush_indep_OBJECTS) $(unittest_crush_indep_DEPENDENCIES) $(EXTRA_unittest_crush_indep_DEPENDENCIES) @rm -f unittest_crush_indep$(EXEEXT) $(AM_V_CXXLD)$(unittest_crush_indep_LINK) $(unittest_crush_indep_OBJECTS) $(unittest_crush_indep_LDADD) $(LIBS) test/crush/unittest_crush_wrapper-TestCrushWrapper.$(OBJEXT): \ test/crush/$(am__dirstamp) \ test/crush/$(DEPDIR)/$(am__dirstamp) unittest_crush_wrapper$(EXEEXT): $(unittest_crush_wrapper_OBJECTS) $(unittest_crush_wrapper_DEPENDENCIES) $(EXTRA_unittest_crush_wrapper_DEPENDENCIES) @rm -f unittest_crush_wrapper$(EXEEXT) $(AM_V_CXXLD)$(unittest_crush_wrapper_LINK) $(unittest_crush_wrapper_OBJECTS) $(unittest_crush_wrapper_LDADD) $(LIBS) test/unittest_crypto-crypto.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_crypto$(EXEEXT): $(unittest_crypto_OBJECTS) $(unittest_crypto_DEPENDENCIES) $(EXTRA_unittest_crypto_DEPENDENCIES) @rm -f unittest_crypto$(EXEEXT) $(AM_V_CXXLD)$(unittest_crypto_LINK) $(unittest_crypto_OBJECTS) $(unittest_crypto_LDADD) $(LIBS) test/unittest_crypto_init-crypto_init.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_crypto_init$(EXEEXT): $(unittest_crypto_init_OBJECTS) $(unittest_crypto_init_DEPENDENCIES) $(EXTRA_unittest_crypto_init_DEPENDENCIES) @rm -f unittest_crypto_init$(EXEEXT) $(AM_V_CXXLD)$(unittest_crypto_init_LINK) $(unittest_crypto_init_OBJECTS) $(unittest_crypto_init_LDADD) $(LIBS) test/unittest_daemon_config-daemon_config.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_daemon_config$(EXEEXT): $(unittest_daemon_config_OBJECTS) $(unittest_daemon_config_DEPENDENCIES) $(EXTRA_unittest_daemon_config_DEPENDENCIES) @rm -f unittest_daemon_config$(EXEEXT) $(AM_V_CXXLD)$(unittest_daemon_config_LINK) $(unittest_daemon_config_OBJECTS) $(unittest_daemon_config_LDADD) $(LIBS) test/osd/unittest_ecbackend-TestECBackend.$(OBJEXT): \ test/osd/$(am__dirstamp) test/osd/$(DEPDIR)/$(am__dirstamp) unittest_ecbackend$(EXEEXT): $(unittest_ecbackend_OBJECTS) $(unittest_ecbackend_DEPENDENCIES) $(EXTRA_unittest_ecbackend_DEPENDENCIES) @rm -f unittest_ecbackend$(EXEEXT) $(AM_V_CXXLD)$(unittest_ecbackend_LINK) $(unittest_ecbackend_OBJECTS) $(unittest_ecbackend_LDADD) $(LIBS) test/unittest_encoding-encoding.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_encoding$(EXEEXT): $(unittest_encoding_OBJECTS) $(unittest_encoding_DEPENDENCIES) $(EXTRA_unittest_encoding_DEPENDENCIES) @rm -f unittest_encoding$(EXEEXT) $(AM_V_CXXLD)$(unittest_encoding_LINK) $(unittest_encoding_OBJECTS) $(unittest_encoding_LDADD) $(LIBS) test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) unittest_erasure_code_example$(EXEEXT): $(unittest_erasure_code_example_OBJECTS) $(unittest_erasure_code_example_DEPENDENCIES) $(EXTRA_unittest_erasure_code_example_DEPENDENCIES) @rm -f unittest_erasure_code_example$(EXEEXT) $(AM_V_CXXLD)$(unittest_erasure_code_example_LINK) $(unittest_erasure_code_example_OBJECTS) $(unittest_erasure_code_example_LDADD) $(LIBS) test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.$(OBJEXT): \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.$(OBJEXT): \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.$(OBJEXT): \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.$(OBJEXT): \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.$(OBJEXT): \ erasure-code/jerasure/jerasure/src/$(am__dirstamp) \ erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.$(OBJEXT): \ erasure-code/jerasure/gf-complete/src/$(am__dirstamp) \ erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.$(OBJEXT): \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.$(OBJEXT): \ erasure-code/jerasure/$(am__dirstamp) \ erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) unittest_erasure_code_jerasure$(EXEEXT): $(unittest_erasure_code_jerasure_OBJECTS) $(unittest_erasure_code_jerasure_DEPENDENCIES) $(EXTRA_unittest_erasure_code_jerasure_DEPENDENCIES) @rm -f unittest_erasure_code_jerasure$(EXEEXT) $(AM_V_CXXLD)$(unittest_erasure_code_jerasure_LINK) $(unittest_erasure_code_jerasure_OBJECTS) $(unittest_erasure_code_jerasure_LDADD) $(LIBS) test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) unittest_erasure_code_plugin$(EXEEXT): $(unittest_erasure_code_plugin_OBJECTS) $(unittest_erasure_code_plugin_DEPENDENCIES) $(EXTRA_unittest_erasure_code_plugin_DEPENDENCIES) @rm -f unittest_erasure_code_plugin$(EXEEXT) $(AM_V_CXXLD)$(unittest_erasure_code_plugin_LINK) $(unittest_erasure_code_plugin_OBJECTS) $(unittest_erasure_code_plugin_LDADD) $(LIBS) test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.$(OBJEXT): \ test/erasure-code/$(am__dirstamp) \ test/erasure-code/$(DEPDIR)/$(am__dirstamp) unittest_erasure_code_plugin_jerasure$(EXEEXT): $(unittest_erasure_code_plugin_jerasure_OBJECTS) $(unittest_erasure_code_plugin_jerasure_DEPENDENCIES) $(EXTRA_unittest_erasure_code_plugin_jerasure_DEPENDENCIES) @rm -f unittest_erasure_code_plugin_jerasure$(EXEEXT) $(AM_V_CXXLD)$(unittest_erasure_code_plugin_jerasure_LINK) $(unittest_erasure_code_plugin_jerasure_OBJECTS) $(unittest_erasure_code_plugin_jerasure_LDADD) $(LIBS) test/unittest_escape-escape.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_escape$(EXEEXT): $(unittest_escape_OBJECTS) $(unittest_escape_DEPENDENCIES) $(EXTRA_unittest_escape_DEPENDENCIES) @rm -f unittest_escape$(EXEEXT) $(AM_V_CXXLD)$(unittest_escape_LINK) $(unittest_escape_OBJECTS) $(unittest_escape_LDADD) $(LIBS) test/os/$(am__dirstamp): @$(MKDIR_P) test/os @: > test/os/$(am__dirstamp) test/os/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/os/$(DEPDIR) @: > test/os/$(DEPDIR)/$(am__dirstamp) test/os/unittest_flatindex-TestFlatIndex.$(OBJEXT): \ test/os/$(am__dirstamp) test/os/$(DEPDIR)/$(am__dirstamp) unittest_flatindex$(EXEEXT): $(unittest_flatindex_OBJECTS) $(unittest_flatindex_DEPENDENCIES) $(EXTRA_unittest_flatindex_DEPENDENCIES) @rm -f unittest_flatindex$(EXEEXT) $(AM_V_CXXLD)$(unittest_flatindex_LINK) $(unittest_flatindex_OBJECTS) $(unittest_flatindex_LDADD) $(LIBS) test/unittest_formatter-formatter.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) rgw/unittest_formatter-rgw_formats.$(OBJEXT): rgw/$(am__dirstamp) \ rgw/$(DEPDIR)/$(am__dirstamp) unittest_formatter$(EXEEXT): $(unittest_formatter_OBJECTS) $(unittest_formatter_DEPENDENCIES) $(EXTRA_unittest_formatter_DEPENDENCIES) @rm -f unittest_formatter$(EXEEXT) $(AM_V_CXXLD)$(unittest_formatter_LINK) $(unittest_formatter_OBJECTS) $(unittest_formatter_LDADD) $(LIBS) test/unittest_gather-gather.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_gather$(EXEEXT): $(unittest_gather_OBJECTS) $(unittest_gather_DEPENDENCIES) $(EXTRA_unittest_gather_DEPENDENCIES) @rm -f unittest_gather$(EXEEXT) $(AM_V_CXXLD)$(unittest_gather_LINK) $(unittest_gather_OBJECTS) $(unittest_gather_LDADD) $(LIBS) test/unittest_heartbeatmap-heartbeat_map.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_heartbeatmap$(EXEEXT): $(unittest_heartbeatmap_OBJECTS) $(unittest_heartbeatmap_DEPENDENCIES) $(EXTRA_unittest_heartbeatmap_DEPENDENCIES) @rm -f unittest_heartbeatmap$(EXEEXT) $(AM_V_CXXLD)$(unittest_heartbeatmap_LINK) $(unittest_heartbeatmap_OBJECTS) $(unittest_heartbeatmap_LDADD) $(LIBS) test/common/unittest_histogram-histogram.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_histogram$(EXEEXT): $(unittest_histogram_OBJECTS) $(unittest_histogram_DEPENDENCIES) $(EXTRA_unittest_histogram_DEPENDENCIES) @rm -f unittest_histogram$(EXEEXT) $(AM_V_CXXLD)$(unittest_histogram_LINK) $(unittest_histogram_OBJECTS) $(unittest_histogram_LDADD) $(LIBS) test/osd/unittest_hitset-hitset.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) unittest_hitset$(EXEEXT): $(unittest_hitset_OBJECTS) $(unittest_hitset_DEPENDENCIES) $(EXTRA_unittest_hitset_DEPENDENCIES) @rm -f unittest_hitset$(EXEEXT) $(AM_V_CXXLD)$(unittest_hitset_LINK) $(unittest_hitset_OBJECTS) $(unittest_hitset_LDADD) $(LIBS) test/common/unittest_io_priority-test_io_priority.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_io_priority$(EXEEXT): $(unittest_io_priority_OBJECTS) $(unittest_io_priority_DEPENDENCIES) $(EXTRA_unittest_io_priority_DEPENDENCIES) @rm -f unittest_io_priority$(EXEEXT) $(AM_V_CXXLD)$(unittest_io_priority_LINK) $(unittest_io_priority_OBJECTS) $(unittest_io_priority_LDADD) $(LIBS) test/unittest_ipaddr-test_ipaddr.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_ipaddr$(EXEEXT): $(unittest_ipaddr_OBJECTS) $(unittest_ipaddr_DEPENDENCIES) $(EXTRA_unittest_ipaddr_DEPENDENCIES) @rm -f unittest_ipaddr$(EXEEXT) $(AM_V_CXXLD)$(unittest_ipaddr_LINK) $(unittest_ipaddr_OBJECTS) $(unittest_ipaddr_LDADD) $(LIBS) test/os/unittest_lfnindex-TestLFNIndex.$(OBJEXT): \ test/os/$(am__dirstamp) test/os/$(DEPDIR)/$(am__dirstamp) unittest_lfnindex$(EXEEXT): $(unittest_lfnindex_OBJECTS) $(unittest_lfnindex_DEPENDENCIES) $(EXTRA_unittest_lfnindex_DEPENDENCIES) @rm -f unittest_lfnindex$(EXEEXT) $(AM_V_CXXLD)$(unittest_lfnindex_LINK) $(unittest_lfnindex_OBJECTS) $(unittest_lfnindex_LDADD) $(LIBS) test/unittest_libcephfs_config-libcephfs_config.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_libcephfs_config$(EXEEXT): $(unittest_libcephfs_config_OBJECTS) $(unittest_libcephfs_config_DEPENDENCIES) $(EXTRA_unittest_libcephfs_config_DEPENDENCIES) @rm -f unittest_libcephfs_config$(EXEEXT) $(AM_V_CXXLD)$(unittest_libcephfs_config_LINK) $(unittest_libcephfs_config_OBJECTS) $(unittest_libcephfs_config_LDADD) $(LIBS) test/librados/unittest_librados-librados.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) unittest_librados$(EXEEXT): $(unittest_librados_OBJECTS) $(unittest_librados_DEPENDENCIES) $(EXTRA_unittest_librados_DEPENDENCIES) @rm -f unittest_librados$(EXEEXT) $(AM_V_CXXLD)$(unittest_librados_LINK) $(unittest_librados_OBJECTS) $(unittest_librados_LDADD) $(LIBS) test/librados/unittest_librados_config-librados_config.$(OBJEXT): \ test/librados/$(am__dirstamp) \ test/librados/$(DEPDIR)/$(am__dirstamp) unittest_librados_config$(EXEEXT): $(unittest_librados_config_OBJECTS) $(unittest_librados_config_DEPENDENCIES) $(EXTRA_unittest_librados_config_DEPENDENCIES) @rm -f unittest_librados_config$(EXEEXT) $(AM_V_CXXLD)$(unittest_librados_config_LINK) $(unittest_librados_config_OBJECTS) $(unittest_librados_config_LDADD) $(LIBS) log/unittest_log-test.$(OBJEXT): log/$(am__dirstamp) \ log/$(DEPDIR)/$(am__dirstamp) unittest_log$(EXEEXT): $(unittest_log_OBJECTS) $(unittest_log_DEPENDENCIES) $(EXTRA_unittest_log_DEPENDENCIES) @rm -f unittest_log$(EXEEXT) $(AM_V_CXXLD)$(unittest_log_LINK) $(unittest_log_OBJECTS) $(unittest_log_LDADD) $(LIBS) test/unittest_mime-mime.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_mime$(EXEEXT): $(unittest_mime_OBJECTS) $(unittest_mime_DEPENDENCIES) $(EXTRA_unittest_mime_DEPENDENCIES) @rm -f unittest_mime$(EXEEXT) $(AM_V_CXXLD)$(unittest_mime_LINK) $(unittest_mime_OBJECTS) $(unittest_mime_LDADD) $(LIBS) test/mon/unittest_mon_moncap-moncap.$(OBJEXT): \ test/mon/$(am__dirstamp) test/mon/$(DEPDIR)/$(am__dirstamp) unittest_mon_moncap$(EXEEXT): $(unittest_mon_moncap_OBJECTS) $(unittest_mon_moncap_DEPENDENCIES) $(EXTRA_unittest_mon_moncap_DEPENDENCIES) @rm -f unittest_mon_moncap$(EXEEXT) $(AM_V_CXXLD)$(unittest_mon_moncap_LINK) $(unittest_mon_moncap_OBJECTS) $(unittest_mon_moncap_LDADD) $(LIBS) test/mon/unittest_mon_pgmap-PGMap.$(OBJEXT): test/mon/$(am__dirstamp) \ test/mon/$(DEPDIR)/$(am__dirstamp) unittest_mon_pgmap$(EXEEXT): $(unittest_mon_pgmap_OBJECTS) $(unittest_mon_pgmap_DEPENDENCIES) $(EXTRA_unittest_mon_pgmap_DEPENDENCIES) @rm -f unittest_mon_pgmap$(EXEEXT) $(AM_V_CXXLD)$(unittest_mon_pgmap_LINK) $(unittest_mon_pgmap_OBJECTS) $(unittest_mon_pgmap_LDADD) $(LIBS) test/on_exit.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_on_exit$(EXEEXT): $(unittest_on_exit_OBJECTS) $(unittest_on_exit_DEPENDENCIES) $(EXTRA_unittest_on_exit_DEPENDENCIES) @rm -f unittest_on_exit$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(unittest_on_exit_OBJECTS) $(unittest_on_exit_LDADD) $(LIBS) test/osd/unittest_osd_osdcap-osdcap.$(OBJEXT): \ test/osd/$(am__dirstamp) test/osd/$(DEPDIR)/$(am__dirstamp) unittest_osd_osdcap$(EXEEXT): $(unittest_osd_osdcap_OBJECTS) $(unittest_osd_osdcap_DEPENDENCIES) $(EXTRA_unittest_osd_osdcap_DEPENDENCIES) @rm -f unittest_osd_osdcap$(EXEEXT) $(AM_V_CXXLD)$(unittest_osd_osdcap_LINK) $(unittest_osd_osdcap_OBJECTS) $(unittest_osd_osdcap_LDADD) $(LIBS) test/osd/unittest_osd_types-types.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) unittest_osd_types$(EXEEXT): $(unittest_osd_types_OBJECTS) $(unittest_osd_types_DEPENDENCIES) $(EXTRA_unittest_osd_types_DEPENDENCIES) @rm -f unittest_osd_types$(EXEEXT) $(AM_V_CXXLD)$(unittest_osd_types_LINK) $(unittest_osd_types_OBJECTS) $(unittest_osd_types_LDADD) $(LIBS) test/osd/unittest_osdmap-TestOSDMap.$(OBJEXT): \ test/osd/$(am__dirstamp) test/osd/$(DEPDIR)/$(am__dirstamp) unittest_osdmap$(EXEEXT): $(unittest_osdmap_OBJECTS) $(unittest_osdmap_DEPENDENCIES) $(EXTRA_unittest_osdmap_DEPENDENCIES) @rm -f unittest_osdmap$(EXEEXT) $(AM_V_CXXLD)$(unittest_osdmap_LINK) $(unittest_osdmap_OBJECTS) $(unittest_osdmap_LDADD) $(LIBS) test/unittest_perf_counters-perf_counters.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_perf_counters$(EXEEXT): $(unittest_perf_counters_OBJECTS) $(unittest_perf_counters_DEPENDENCIES) $(EXTRA_unittest_perf_counters_DEPENDENCIES) @rm -f unittest_perf_counters$(EXEEXT) $(AM_V_CXXLD)$(unittest_perf_counters_LINK) $(unittest_perf_counters_OBJECTS) $(unittest_perf_counters_LDADD) $(LIBS) test/osd/unittest_pglog-TestPGLog.$(OBJEXT): test/osd/$(am__dirstamp) \ test/osd/$(DEPDIR)/$(am__dirstamp) unittest_pglog$(EXEEXT): $(unittest_pglog_OBJECTS) $(unittest_pglog_DEPENDENCIES) $(EXTRA_unittest_pglog_DEPENDENCIES) @rm -f unittest_pglog$(EXEEXT) $(AM_V_CXXLD)$(unittest_pglog_LINK) $(unittest_pglog_OBJECTS) $(unittest_pglog_LDADD) $(LIBS) test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_prebufferedstreambuf$(EXEEXT): $(unittest_prebufferedstreambuf_OBJECTS) $(unittest_prebufferedstreambuf_DEPENDENCIES) $(EXTRA_unittest_prebufferedstreambuf_DEPENDENCIES) @rm -f unittest_prebufferedstreambuf$(EXEEXT) $(AM_V_CXXLD)$(unittest_prebufferedstreambuf_LINK) $(unittest_prebufferedstreambuf_OBJECTS) $(unittest_prebufferedstreambuf_LDADD) $(LIBS) test/unittest_run_cmd-run_cmd.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_run_cmd$(EXEEXT): $(unittest_run_cmd_OBJECTS) $(unittest_run_cmd_DEPENDENCIES) $(EXTRA_unittest_run_cmd_DEPENDENCIES) @rm -f unittest_run_cmd$(EXEEXT) $(AM_V_CXXLD)$(unittest_run_cmd_LINK) $(unittest_run_cmd_OBJECTS) $(unittest_run_cmd_LDADD) $(LIBS) test/common/unittest_sharedptr_registry-test_sharedptr_registry.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_sharedptr_registry$(EXEEXT): $(unittest_sharedptr_registry_OBJECTS) $(unittest_sharedptr_registry_DEPENDENCIES) $(EXTRA_unittest_sharedptr_registry_DEPENDENCIES) @rm -f unittest_sharedptr_registry$(EXEEXT) $(AM_V_CXXLD)$(unittest_sharedptr_registry_LINK) $(unittest_sharedptr_registry_OBJECTS) $(unittest_sharedptr_registry_LDADD) $(LIBS) test/unittest_signals-signals.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_signals$(EXEEXT): $(unittest_signals_OBJECTS) $(unittest_signals_DEPENDENCIES) $(EXTRA_unittest_signals_DEPENDENCIES) @rm -f unittest_signals$(EXEEXT) $(AM_V_CXXLD)$(unittest_signals_LINK) $(unittest_signals_OBJECTS) $(unittest_signals_LDADD) $(LIBS) test/unittest_simple_spin-simple_spin.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_simple_spin$(EXEEXT): $(unittest_simple_spin_OBJECTS) $(unittest_simple_spin_DEPENDENCIES) $(EXTRA_unittest_simple_spin_DEPENDENCIES) @rm -f unittest_simple_spin$(EXEEXT) $(AM_V_CXXLD)$(unittest_simple_spin_LINK) $(unittest_simple_spin_OBJECTS) $(unittest_simple_spin_LDADD) $(LIBS) test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_sloppy_crc_map$(EXEEXT): $(unittest_sloppy_crc_map_OBJECTS) $(unittest_sloppy_crc_map_DEPENDENCIES) $(EXTRA_unittest_sloppy_crc_map_DEPENDENCIES) @rm -f unittest_sloppy_crc_map$(EXEEXT) $(AM_V_CXXLD)$(unittest_sloppy_crc_map_LINK) $(unittest_sloppy_crc_map_OBJECTS) $(unittest_sloppy_crc_map_LDADD) $(LIBS) test/unittest_str_list-test_str_list.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_str_list$(EXEEXT): $(unittest_str_list_OBJECTS) $(unittest_str_list_DEPENDENCIES) $(EXTRA_unittest_str_list_DEPENDENCIES) @rm -f unittest_str_list$(EXEEXT) $(AM_V_CXXLD)$(unittest_str_list_LINK) $(unittest_str_list_OBJECTS) $(unittest_str_list_LDADD) $(LIBS) test/common/unittest_str_map-test_str_map.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_str_map$(EXEEXT): $(unittest_str_map_OBJECTS) $(unittest_str_map_DEPENDENCIES) $(EXTRA_unittest_str_map_DEPENDENCIES) @rm -f unittest_str_map$(EXEEXT) $(AM_V_CXXLD)$(unittest_str_map_LINK) $(unittest_str_map_OBJECTS) $(unittest_str_map_LDADD) $(LIBS) test/unittest_striper-test_striper.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_striper$(EXEEXT): $(unittest_striper_OBJECTS) $(unittest_striper_DEPENDENCIES) $(EXTRA_unittest_striper_DEPENDENCIES) @rm -f unittest_striper$(EXEEXT) $(AM_V_CXXLD)$(unittest_striper_LINK) $(unittest_striper_OBJECTS) $(unittest_striper_LDADD) $(LIBS) test/unittest_strtol-strtol.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_strtol$(EXEEXT): $(unittest_strtol_OBJECTS) $(unittest_strtol_DEPENDENCIES) $(EXTRA_unittest_strtol_DEPENDENCIES) @rm -f unittest_strtol$(EXEEXT) $(AM_V_CXXLD)$(unittest_strtol_LINK) $(unittest_strtol_OBJECTS) $(unittest_strtol_LDADD) $(LIBS) test/unittest_texttable-test_texttable.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_texttable$(EXEEXT): $(unittest_texttable_OBJECTS) $(unittest_texttable_DEPENDENCIES) $(EXTRA_unittest_texttable_DEPENDENCIES) @rm -f unittest_texttable$(EXEEXT) $(AM_V_CXXLD)$(unittest_texttable_LINK) $(unittest_texttable_OBJECTS) $(unittest_texttable_LDADD) $(LIBS) test/common/unittest_throttle-Throttle.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_throttle$(EXEEXT): $(unittest_throttle_OBJECTS) $(unittest_throttle_DEPENDENCIES) $(EXTRA_unittest_throttle_DEPENDENCIES) @rm -f unittest_throttle$(EXEEXT) $(AM_V_CXXLD)$(unittest_throttle_LINK) $(unittest_throttle_OBJECTS) $(unittest_throttle_LDADD) $(LIBS) test/unittest_utf8-utf8.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) unittest_utf8$(EXEEXT): $(unittest_utf8_OBJECTS) $(unittest_utf8_DEPENDENCIES) $(EXTRA_unittest_utf8_DEPENDENCIES) @rm -f unittest_utf8$(EXEEXT) $(AM_V_CXXLD)$(unittest_utf8_LINK) $(unittest_utf8_OBJECTS) $(unittest_utf8_LDADD) $(LIBS) test/common/unittest_util-test_util.$(OBJEXT): \ test/common/$(am__dirstamp) \ test/common/$(DEPDIR)/$(am__dirstamp) unittest_util$(EXEEXT): $(unittest_util_OBJECTS) $(unittest_util_DEPENDENCIES) $(EXTRA_unittest_util_DEPENDENCIES) @rm -f unittest_util$(EXEEXT) $(AM_V_CXXLD)$(unittest_util_LINK) $(unittest_util_OBJECTS) $(unittest_util_LDADD) $(LIBS) test/unittest_workqueue-test_workqueue.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) unittest_workqueue$(EXEEXT): $(unittest_workqueue_OBJECTS) $(unittest_workqueue_DEPENDENCIES) $(EXTRA_unittest_workqueue_DEPENDENCIES) @rm -f unittest_workqueue$(EXEEXT) $(AM_V_CXXLD)$(unittest_workqueue_LINK) $(unittest_workqueue_OBJECTS) $(unittest_workqueue_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) install-ceph_sbinSCRIPTS: $(ceph_sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(ceph_sbin_SCRIPTS)'; test -n "$(ceph_sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ceph_sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ceph_sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(ceph_sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(ceph_sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-ceph_sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(ceph_sbin_SCRIPTS)'; test -n "$(ceph_sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(ceph_sbindir)'; $(am__uninstall_files_from_dir) install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) install-shell_commonSCRIPTS: $(shell_common_SCRIPTS) @$(NORMAL_INSTALL) @list='$(shell_common_SCRIPTS)'; test -n "$(shell_commondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(shell_commondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(shell_commondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(shell_commondir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(shell_commondir)$$dir" || exit $$?; \ } \ ; done uninstall-shell_commonSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(shell_common_SCRIPTS)'; test -n "$(shell_commondir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(shell_commondir)'; $(am__uninstall_files_from_dir) install-su_sbinSCRIPTS: $(su_sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(su_sbin_SCRIPTS)'; test -n "$(su_sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(su_sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(su_sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(su_sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(su_sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-su_sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(su_sbin_SCRIPTS)'; test -n "$(su_sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(su_sbindir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f arch/*.$(OBJEXT) -rm -f arch/*.lo -rm -f auth/*.$(OBJEXT) -rm -f auth/*.lo -rm -f auth/cephx/*.$(OBJEXT) -rm -f auth/cephx/*.lo -rm -f auth/none/*.$(OBJEXT) -rm -f auth/none/*.lo -rm -f auth/unknown/*.$(OBJEXT) -rm -f auth/unknown/*.lo -rm -f civetweb/src/*.$(OBJEXT) -rm -f civetweb/src/*.lo -rm -f client/*.$(OBJEXT) -rm -f client/*.lo -rm -f cls/hello/*.$(OBJEXT) -rm -f cls/hello/*.lo -rm -f cls/lock/*.$(OBJEXT) -rm -f cls/lock/*.lo -rm -f cls/log/*.$(OBJEXT) -rm -f cls/log/*.lo -rm -f cls/rbd/*.$(OBJEXT) -rm -f cls/rbd/*.lo -rm -f cls/refcount/*.$(OBJEXT) -rm -f cls/refcount/*.lo -rm -f cls/replica_log/*.$(OBJEXT) -rm -f cls/replica_log/*.lo -rm -f cls/rgw/*.$(OBJEXT) -rm -f cls/rgw/*.lo -rm -f cls/statelog/*.$(OBJEXT) -rm -f cls/statelog/*.lo -rm -f cls/user/*.$(OBJEXT) -rm -f cls/user/*.lo -rm -f cls/version/*.$(OBJEXT) -rm -f cls/version/*.lo -rm -f common/*.$(OBJEXT) -rm -f common/*.lo -rm -f crush/*.$(OBJEXT) -rm -f crush/*.lo -rm -f erasure-code/*.$(OBJEXT) -rm -f erasure-code/*.lo -rm -f erasure-code/jerasure/*.$(OBJEXT) -rm -f erasure-code/jerasure/*.lo -rm -f erasure-code/jerasure/gf-complete/src/*.$(OBJEXT) -rm -f erasure-code/jerasure/gf-complete/src/*.lo -rm -f erasure-code/jerasure/jerasure/src/*.$(OBJEXT) -rm -f erasure-code/jerasure/jerasure/src/*.lo -rm -f global/*.$(OBJEXT) -rm -f global/*.lo -rm -f java/native/*.$(OBJEXT) -rm -f java/native/*.lo -rm -f json_spirit/*.$(OBJEXT) -rm -f json_spirit/*.lo -rm -f key_value_store/*.$(OBJEXT) -rm -f key_value_store/*.lo -rm -f librados/*.$(OBJEXT) -rm -f librados/*.lo -rm -f librbd/*.$(OBJEXT) -rm -f librbd/*.lo -rm -f log/*.$(OBJEXT) -rm -f log/*.lo -rm -f mds/*.$(OBJEXT) -rm -f mds/*.lo -rm -f mon/*.$(OBJEXT) -rm -f mon/*.lo -rm -f mount/*.$(OBJEXT) -rm -f msg/*.$(OBJEXT) -rm -f msg/*.lo -rm -f objclass/*.$(OBJEXT) -rm -f objclass/*.lo -rm -f os/*.$(OBJEXT) -rm -f os/*.lo -rm -f osd/*.$(OBJEXT) -rm -f osd/*.lo -rm -f osdc/*.$(OBJEXT) -rm -f osdc/*.lo -rm -f perfglue/*.$(OBJEXT) -rm -f perfglue/*.lo -rm -f rbd_fuse/*.$(OBJEXT) -rm -f rgw/*.$(OBJEXT) -rm -f rgw/*.lo -rm -f test/*.$(OBJEXT) -rm -f test/ObjectMap/*.$(OBJEXT) -rm -f test/bench/*.$(OBJEXT) -rm -f test/cls_hello/*.$(OBJEXT) -rm -f test/cls_lock/*.$(OBJEXT) -rm -f test/cls_log/*.$(OBJEXT) -rm -f test/cls_rbd/*.$(OBJEXT) -rm -f test/cls_refcount/*.$(OBJEXT) -rm -f test/cls_replica_log/*.$(OBJEXT) -rm -f test/cls_rgw/*.$(OBJEXT) -rm -f test/cls_statelog/*.$(OBJEXT) -rm -f test/cls_version/*.$(OBJEXT) -rm -f test/common/*.$(OBJEXT) -rm -f test/crush/*.$(OBJEXT) -rm -f test/encoding/*.$(OBJEXT) -rm -f test/erasure-code/*.$(OBJEXT) -rm -f test/erasure-code/*.lo -rm -f test/libcephfs/*.$(OBJEXT) -rm -f test/librados/*.$(OBJEXT) -rm -f test/librados/*.lo -rm -f test/librbd/*.$(OBJEXT) -rm -f test/mon/*.$(OBJEXT) -rm -f test/objectstore/*.$(OBJEXT) -rm -f test/os/*.$(OBJEXT) -rm -f test/osd/*.$(OBJEXT) -rm -f test/osdc/*.$(OBJEXT) -rm -f test/rgw/*.$(OBJEXT) -rm -f test/system/*.$(OBJEXT) -rm -f test/system/*.lo -rm -f tools/*.$(OBJEXT) -rm -f tools/rados/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ceph_fuse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ceph_mds.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ceph_mon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ceph_osd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ceph_syn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ceph_ver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cephfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcephfs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librados-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_build_libcommon-ceph_ver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arch/$(DEPDIR)/intel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arch/$(DEPDIR)/neon.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@arch/$(DEPDIR)/probe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/AuthAuthorizeHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/AuthClientHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/AuthMethodList.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/AuthServiceHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/AuthSessionHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/Crypto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/KeyRing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/$(DEPDIR)/RotatingKeyRing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/cephx/$(DEPDIR)/CephxAuthorizeHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/cephx/$(DEPDIR)/CephxClientHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/cephx/$(DEPDIR)/CephxKeyServer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/cephx/$(DEPDIR)/CephxProtocol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/cephx/$(DEPDIR)/CephxServiceHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/cephx/$(DEPDIR)/CephxSessionHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/none/$(DEPDIR)/AuthNoneAuthorizeHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@auth/unknown/$(DEPDIR)/AuthUnknownAuthorizeHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@civetweb/src/$(DEPDIR)/libcivetweb_la-civetweb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/Client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/ClientSnapRealm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/Dentry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/Inode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/MetaRequest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/MetaSession.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/SyntheticClient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/Trace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/fuse_ll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/test_ioctls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/hello/$(DEPDIR)/cls_hello.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/lock/$(DEPDIR)/cls_lock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/lock/$(DEPDIR)/cls_lock_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/lock/$(DEPDIR)/cls_lock_ops.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/lock/$(DEPDIR)/cls_lock_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/log/$(DEPDIR)/cls_log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/log/$(DEPDIR)/cls_log_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/rbd/$(DEPDIR)/cls_rbd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/rbd/$(DEPDIR)/cls_rbd_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/refcount/$(DEPDIR)/cls_refcount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/refcount/$(DEPDIR)/cls_refcount_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/refcount/$(DEPDIR)/cls_refcount_ops.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/replica_log/$(DEPDIR)/cls_replica_log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/replica_log/$(DEPDIR)/cls_replica_log_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/replica_log/$(DEPDIR)/cls_replica_log_ops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/replica_log/$(DEPDIR)/cls_replica_log_types.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/rgw/$(DEPDIR)/cls_rgw.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/rgw/$(DEPDIR)/cls_rgw_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/rgw/$(DEPDIR)/cls_rgw_ops.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/rgw/$(DEPDIR)/cls_rgw_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/statelog/$(DEPDIR)/cls_statelog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/statelog/$(DEPDIR)/cls_statelog_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/user/$(DEPDIR)/cls_user.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/user/$(DEPDIR)/cls_user_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/user/$(DEPDIR)/cls_user_ops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/user/$(DEPDIR)/cls_user_types.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/version/$(DEPDIR)/cls_version.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/version/$(DEPDIR)/cls_version_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cls/version/$(DEPDIR)/cls_version_types.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/BackTrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Clock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ConfUtils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/DecayCounter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Finisher.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Formatter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/HeartbeatMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/LogClient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/LogEntry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/MemoryModel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Mutex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/OutputDataSocket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/PrebufferedStreambuf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/RefCountedObj.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/SloppyCRCMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/TextTable.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Throttle.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/Timer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/WorkQueue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/addr_parsing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/admin_socket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/admin_socket_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/armor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/assert.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/blkdev.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/bloom_filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/buffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_argparse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_context.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_crypto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_crypto_cms.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_frag.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_fs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_json.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ceph_strings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/cmdparse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/code_environment.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/common_init.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/dout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/entity_name.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/environment.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/errno.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/escape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/fd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/hex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/histogram.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/hobject.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/io_priority.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/ipaddr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libcommon_crc_la-crc32c.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_baseline.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_asm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_zero_asm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libcommon_crc_la-sctp_crc32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libos_la-TrackedOp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libosd_la-TrackedOp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/linux_version.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/lockdep.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/mime.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/obj_bencher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/page.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/perf_counters.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/pick_address.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/pipe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/rest_bench-obj_bencher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/run_cmd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/safe_io.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/secret.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/simple_spin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/snap_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/str_list.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/str_map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/strtol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-BackTrace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Clock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ConfUtils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-DecayCounter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Finisher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Formatter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-LogClient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-LogEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-MemoryModel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Mutex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-TextTable.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Thread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Throttle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-Timer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-WorkQueue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-addr_parsing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-admin_socket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-armor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-assert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-blkdev.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-bloom_filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_context.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_frag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_fs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_json.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ceph_strings.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-cmdparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-code_environment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-common_init.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-dout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-entity_name.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-environment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-errno.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-escape.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-fd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-hex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-histogram.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-hobject.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-io_priority.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-ipaddr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-linux_version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-lockdep.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-mime.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-page.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-perf_counters.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-pick_address.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-pipe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-run_cmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-safe_io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-signal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-simple_spin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-snap_types.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-str_list.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-str_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-strtol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-utf8.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/test_build_libcommon-xattr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/utf8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/version.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/xattr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/CrushCompiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/CrushTester.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/CrushWrapper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/builder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/crush.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@crush/$(DEPDIR)/mapper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/$(DEPDIR)/ErasureCodePlugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodeJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodePluginJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_la-ErasureCodePluginSelectJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodeJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodePluginJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodeJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodePluginJerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_general.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_method.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_rand.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w128.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w16.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_wgen.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_general.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_method.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_rand.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w128.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w16.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_wgen.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_general.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_method.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_rand.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w128.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w16.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_wgen.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-cauchy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-galois.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-jerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-liberation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-reed_sol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-cauchy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-galois.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-jerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-liberation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-reed_sol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-cauchy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-galois.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-jerasure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-liberation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-reed_sol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@global/$(DEPDIR)/global_context.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@global/$(DEPDIR)/global_init.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@global/$(DEPDIR)/pidfile.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@global/$(DEPDIR)/signal_handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/native/$(DEPDIR)/libcephfs_jni_la-JniConstants.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/native/$(DEPDIR)/libcephfs_jni_la-libcephfs_jni.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@json_spirit/$(DEPDIR)/json_spirit_reader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@json_spirit/$(DEPDIR)/json_spirit_writer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@key_value_store/$(DEPDIR)/cls_kvs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@key_value_store/$(DEPDIR)/kv_flat_btree_async.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/librados_la-IoCtxImpl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/librados_la-RadosClient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/librados_la-librados.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/librados_la-snap_set_diff.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/test_build_librados-RadosClient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/test_build_librados-librados.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librados/$(DEPDIR)/test_build_librados-snap_set_diff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/AioCompletion.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/AioRequest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/ImageCtx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/LibrbdWriteback.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/WatchCtx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/internal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@librbd/$(DEPDIR)/librbd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@log/$(DEPDIR)/Log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@log/$(DEPDIR)/SubsystemMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@log/$(DEPDIR)/unittest_log-test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Anchor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/AnchorClient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/AnchorServer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/CDentry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/CDir.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/CInode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Capability.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Dumper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/InoTable.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Locker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/LogEvent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDBalancer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDCache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDLog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDS.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDSMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDSTable.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDSTableClient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDSTableServer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/MDSUtility.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Migrator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Mutation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Resetter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/Server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/SessionMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/SnapRealm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/SnapServer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/flock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/inode_backtrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/journal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/locks.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/mdstypes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/snap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/test_build_libcommon-MDSMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/test_build_libcommon-flock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mds/$(DEPDIR)/test_build_libcommon-mdstypes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/AuthMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/ConfigKeyService.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/DataHealthService.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/Elector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/HealthMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/LogMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/MDSMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/MonCap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/MonClient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/MonMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/Monitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/MonitorStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/MonmapMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/OSDMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/PGMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/PGMonitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/Paxos.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/PaxosService.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/test_build_libcommon-MonCap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/test_build_libcommon-MonClient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mon/$(DEPDIR)/test_build_libcommon-MonMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mount/$(DEPDIR)/mount.ceph.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/Accepter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/DispatchQueue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/Message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/Messenger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/Pipe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/SimpleMessenger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@msg/$(DEPDIR)/msg_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@objclass/$(DEPDIR)/libosd_la-class_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-BtrfsFileStoreBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-DBObjectMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-FileJournal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-FileStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-FlatIndex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-GenericFileStoreBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-GenericObjectMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-HashIndex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-IndexManager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-JournalingObjectStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-KeyValueStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-LFNIndex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-LevelDBStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-MemStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-ObjectStore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-WBThrottle.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-XfsFileStoreBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-ZFSFileStoreBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_la-chain_xattr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_types_la-Transaction.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libos_zfs_a-ZFS.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/ECMsgTypes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/HitSet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/OSDMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-Ager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-ClassHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-ECBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-ECMsgTypes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-ECTransaction.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-HitSet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-OSD.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-OSDCap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-OpRequest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-PG.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-PGBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-ReplicatedBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-ReplicatedPG.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-SnapMapper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_la-Watch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_types_la-ECUtil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_types_la-PGLog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/libosd_types_la-osd_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/osd_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/test_build_libcommon-HitSet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/test_build_libcommon-OSDMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osd/$(DEPDIR)/test_build_libcommon-osd_types.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/Filer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/Journaler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/ObjectCacher.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/Objecter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/Striper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/test_build_libcephfs-Filer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@osdc/$(DEPDIR)/test_build_libcephfs-Striper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@perfglue/$(DEPDIR)/cpu_profiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@perfglue/$(DEPDIR)/disabled_heap_profiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@perfglue/$(DEPDIR)/disabled_stubs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@perfglue/$(DEPDIR)/heap_profiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rbd_fuse/$(DEPDIR)/rbd-fuse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb_log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-librgw.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_acl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_acl_s3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_acl_swift.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_auth_s3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_bucket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_client_io.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_cors.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_cors_s3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_dencoder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_env.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_fcgi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_formats.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_gc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_http_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_json_enc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_keystone.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_metadata.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_multi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_multi_del.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_op.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_policy_s3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_quota.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_rados.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_replica_log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_rest_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_rest_conn.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_tools.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_usage.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_user.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/librgw_la-rgw_xml.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_admin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_env.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_http_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_json_enc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_jsonparser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_loadgen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_multiparser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_replica_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_resolve.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_bucket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_metadata.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_opstate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_replica_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_s3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_swift.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_usage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_rest_user.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_swift.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/rgw_swift_auth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-librgw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_env.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_op.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_user.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/TestSignalHandlers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/TestTimers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bench_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_cors-test_cors.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/kv_store_bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/multi_stress_watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/omap_bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/on_exit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/streamtest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_c_headers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_cfuse_cache_invalidate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_get_blkdev_size.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_mutate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_rewrite_latency.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test_trans.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/testcrypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/testkeys.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/testmsgr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_addrs-test_addrs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_admin_socket-admin_socket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_arch-test_arch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_base64-base64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_bufferlist-bufferlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_confutils-confutils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_crypto-crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_crypto_init-crypto_init.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_daemon_config-daemon_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_encoding-encoding.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_escape-escape.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_formatter-formatter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_gather-gather.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_mime-mime.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_perf_counters-perf_counters.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_run_cmd-run_cmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_signals-signals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_simple_spin-simple_spin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_str_list-test_str_list.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_striper-test_striper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_strtol-strtol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_texttable-test_texttable.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_utf8-utf8.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/unittest_workqueue-test_workqueue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/bencher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/detailed_stat_collector.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/dumb_backend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/rados_backend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/rbd_backend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/small_io_bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/small_io_bench_dumb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/small_io_bench_fs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/small_io_bench_rbd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/testfilestore_backend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/bench/$(DEPDIR)/tp_bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/ObjectContents.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/get_command_descriptions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_config-test_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_context-test_context.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_histogram-histogram.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_str_map-test_str_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_throttle-Throttle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/common/$(DEPDIR)/unittest_util-test_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/crush/$(DEPDIR)/unittest_crush_indep-indep.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/ceph_erasure_code.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/ceph_erasure_code_benchmark.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/ceph_erasure_code_non_regression.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_example_la-ErasureCodePluginExample.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_fail_to_register_la-ErasureCodePluginFailToRegister.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_hangs_la-ErasureCodePluginHangs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/libradostest_la-TestCase.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/libradostest_la-test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/unittest_librados-librados.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/mon/$(DEPDIR)/test_mon_workloadgen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/DeterministicOpSequence.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/FileStoreDiff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/FileStoreTracker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/TestObjectStoreState.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/test_idempotent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/test_idempotent_sequence.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/objectstore/$(DEPDIR)/workload_generator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/Object.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/RadosModel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/TestOpStat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/TestRados.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/unittest_hitset-hitset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/unittest_osd_types-types.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osdc/$(DEPDIR)/FakeWriteback.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/osdc/$(DEPDIR)/object_cacher_stress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/cross_process_sem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/rados_delete_pools_parallel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/rados_list_parallel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/rados_open_pools_parallel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/rados_watch_notify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/st_rados_create_pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/st_rados_delete_objs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/st_rados_delete_pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/st_rados_list_objects.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/st_rados_notify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/st_rados_watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/systest_runnable.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/system/$(DEPDIR)/systest_settings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph-client-debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph_authtool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph_conf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph_monstore_tool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph_objectstore_tool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ceph_osdomap_tool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/crushtool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dupstore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mon_store_converter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/monmaptool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/osdmaptool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/psim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/radosacl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rest_bench-rest_bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/scratchtool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/scratchtoolpp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/rados/$(DEPDIR)/rados.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/rados/$(DEPDIR)/rados_export.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/rados/$(DEPDIR)/rados_import.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/rados/$(DEPDIR)/rados_sync.Po@am__quote@ .S.o: @am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ $< .S.obj: @am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .S.lo: @am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCCAS_TRUE@ $(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(LTCPPASCOMPILE) -c -o $@ $< common/libcommon_crc_la-crc32c_intel_fast_asm.lo: common/crc32c_intel_fast_asm.S @am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(LIBTOOL) $(AM_V_lt) $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -MT common/libcommon_crc_la-crc32c_intel_fast_asm.lo -MD -MP -MF common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_asm.Tpo -c -o common/libcommon_crc_la-crc32c_intel_fast_asm.lo `test -f 'common/crc32c_intel_fast_asm.S' || echo '$(srcdir)/'`common/crc32c_intel_fast_asm.S @am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_asm.Tpo common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_asm.Plo @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='common/crc32c_intel_fast_asm.S' object='common/libcommon_crc_la-crc32c_intel_fast_asm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -c -o common/libcommon_crc_la-crc32c_intel_fast_asm.lo `test -f 'common/crc32c_intel_fast_asm.S' || echo '$(srcdir)/'`common/crc32c_intel_fast_asm.S common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo: common/crc32c_intel_fast_zero_asm.S @am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(LIBTOOL) $(AM_V_lt) $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -MT common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo -MD -MP -MF common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_zero_asm.Tpo -c -o common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo `test -f 'common/crc32c_intel_fast_zero_asm.S' || echo '$(srcdir)/'`common/crc32c_intel_fast_zero_asm.S @am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_zero_asm.Tpo common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast_zero_asm.Plo @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='common/crc32c_intel_fast_zero_asm.S' object='common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -c -o common/libcommon_crc_la-crc32c_intel_fast_zero_asm.lo `test -f 'common/crc32c_intel_fast_zero_asm.S' || echo '$(srcdir)/'`common/crc32c_intel_fast_zero_asm.S .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< civetweb/src/libcivetweb_la-civetweb.lo: civetweb/src/civetweb.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcivetweb_la_CFLAGS) $(CFLAGS) -MT civetweb/src/libcivetweb_la-civetweb.lo -MD -MP -MF civetweb/src/$(DEPDIR)/libcivetweb_la-civetweb.Tpo -c -o civetweb/src/libcivetweb_la-civetweb.lo `test -f 'civetweb/src/civetweb.c' || echo '$(srcdir)/'`civetweb/src/civetweb.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) civetweb/src/$(DEPDIR)/libcivetweb_la-civetweb.Tpo civetweb/src/$(DEPDIR)/libcivetweb_la-civetweb.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='civetweb/src/civetweb.c' object='civetweb/src/libcivetweb_la-civetweb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcivetweb_la_CFLAGS) $(CFLAGS) -c -o civetweb/src/libcivetweb_la-civetweb.lo `test -f 'civetweb/src/civetweb.c' || echo '$(srcdir)/'`civetweb/src/civetweb.c common/libcommon_crc_la-sctp_crc32.lo: common/sctp_crc32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT common/libcommon_crc_la-sctp_crc32.lo -MD -MP -MF common/$(DEPDIR)/libcommon_crc_la-sctp_crc32.Tpo -c -o common/libcommon_crc_la-sctp_crc32.lo `test -f 'common/sctp_crc32.c' || echo '$(srcdir)/'`common/sctp_crc32.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libcommon_crc_la-sctp_crc32.Tpo common/$(DEPDIR)/libcommon_crc_la-sctp_crc32.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/sctp_crc32.c' object='common/libcommon_crc_la-sctp_crc32.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o common/libcommon_crc_la-sctp_crc32.lo `test -f 'common/sctp_crc32.c' || echo '$(srcdir)/'`common/sctp_crc32.c common/libcommon_crc_la-crc32c_intel_baseline.lo: common/crc32c_intel_baseline.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT common/libcommon_crc_la-crc32c_intel_baseline.lo -MD -MP -MF common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_baseline.Tpo -c -o common/libcommon_crc_la-crc32c_intel_baseline.lo `test -f 'common/crc32c_intel_baseline.c' || echo '$(srcdir)/'`common/crc32c_intel_baseline.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_baseline.Tpo common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_baseline.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/crc32c_intel_baseline.c' object='common/libcommon_crc_la-crc32c_intel_baseline.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o common/libcommon_crc_la-crc32c_intel_baseline.lo `test -f 'common/crc32c_intel_baseline.c' || echo '$(srcdir)/'`common/crc32c_intel_baseline.c common/libcommon_crc_la-crc32c_intel_fast.lo: common/crc32c_intel_fast.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT common/libcommon_crc_la-crc32c_intel_fast.lo -MD -MP -MF common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast.Tpo -c -o common/libcommon_crc_la-crc32c_intel_fast.lo `test -f 'common/crc32c_intel_fast.c' || echo '$(srcdir)/'`common/crc32c_intel_fast.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast.Tpo common/$(DEPDIR)/libcommon_crc_la-crc32c_intel_fast.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/crc32c_intel_fast.c' object='common/libcommon_crc_la-crc32c_intel_fast.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o common/libcommon_crc_la-crc32c_intel_fast.lo `test -f 'common/crc32c_intel_fast.c' || echo '$(srcdir)/'`common/crc32c_intel_fast.c erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo: erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-cauchy.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-cauchy.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-cauchy.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/cauchy.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-cauchy.lo `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo: erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-galois.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-galois.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-galois.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/galois.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-galois.lo `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo: erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-jerasure.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-jerasure.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-jerasure.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/jerasure.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-jerasure.lo `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo: erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-liberation.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-liberation.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-liberation.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/liberation.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-liberation.lo `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo: erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-reed_sol.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-reed_sol.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_generic_la-reed_sol.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/reed_sol.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_generic_la-reed_sol.lo `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo: erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_wgen.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_wgen.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_wgen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_wgen.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_wgen.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo: erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_method.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_method.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_method.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_method.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_method.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo: erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w16.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w16.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w16.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w16.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w16.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo: erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo: erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w32.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w32.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w32.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w32.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w32.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo: erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w64.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w64.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w64.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w64.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w64.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo: erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w128.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w128.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w128.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w128.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w128.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo: erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_general.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_general.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_general.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_general.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_general.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo: erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w4.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w4.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w4.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w4.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w4.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo: erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_rand.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_rand.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_rand.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_rand.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_rand.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo: erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w8.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w8.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_generic_la-gf_w8.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w8.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_generic_la-gf_w8.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo: erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-cauchy.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-cauchy.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-cauchy.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/cauchy.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-cauchy.lo `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo: erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-galois.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-galois.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-galois.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/galois.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-galois.lo `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo: erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-jerasure.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-jerasure.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-jerasure.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/jerasure.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-jerasure.lo `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo: erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-liberation.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-liberation.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-liberation.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/liberation.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-liberation.lo `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo: erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-reed_sol.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-reed_sol.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse3_la-reed_sol.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/reed_sol.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse3_la-reed_sol.lo `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo: erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_wgen.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_wgen.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_wgen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_wgen.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_wgen.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo: erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_method.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_method.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_method.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_method.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_method.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo: erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w16.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w16.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w16.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w16.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w16.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo: erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo: erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w32.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w32.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w32.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w32.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w32.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo: erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w64.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w64.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w64.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w64.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w64.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo: erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w128.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w128.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w128.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w128.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w128.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo: erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_general.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_general.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_general.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_general.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_general.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo: erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w4.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w4.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w4.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w4.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w4.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo: erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_rand.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_rand.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_rand.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_rand.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_rand.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo: erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w8.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w8.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse3_la-gf_w8.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w8.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse3_la-gf_w8.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo: erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-cauchy.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-cauchy.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-cauchy.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/cauchy.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-cauchy.lo `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo: erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-galois.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-galois.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-galois.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/galois.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-galois.lo `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo: erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-jerasure.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-jerasure.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-jerasure.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/jerasure.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-jerasure.lo `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo: erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-liberation.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-liberation.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-liberation.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/liberation.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-liberation.lo `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo: erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-reed_sol.Tpo -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-reed_sol.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/libec_jerasure_sse4_la-reed_sol.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/reed_sol.c' object='erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/libec_jerasure_sse4_la-reed_sol.lo `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo: erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_wgen.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_wgen.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_wgen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_wgen.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_wgen.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo: erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_method.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_method.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_method.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_method.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_method.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo: erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w16.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w16.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w16.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w16.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w16.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo: erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo: erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w32.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w32.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w32.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w32.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w32.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo: erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w64.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w64.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w64.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w64.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w64.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo: erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w128.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w128.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w128.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w128.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w128.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo: erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_general.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_general.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_general.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_general.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_general.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo: erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w4.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w4.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w4.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w4.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w4.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo: erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_rand.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_rand.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_rand.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_rand.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_rand.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo: erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w8.Tpo -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w8.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/libec_jerasure_sse4_la-gf_w8.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w8.c' object='erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/libec_jerasure_sse4_la-gf_w8.lo `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c test/librbd/ceph_test_librbd_fsx-fsx.o: test/librbd/fsx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_fsx_CFLAGS) $(CFLAGS) -MT test/librbd/ceph_test_librbd_fsx-fsx.o -MD -MP -MF test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Tpo -c -o test/librbd/ceph_test_librbd_fsx-fsx.o `test -f 'test/librbd/fsx.c' || echo '$(srcdir)/'`test/librbd/fsx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Tpo test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/librbd/fsx.c' object='test/librbd/ceph_test_librbd_fsx-fsx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_fsx_CFLAGS) $(CFLAGS) -c -o test/librbd/ceph_test_librbd_fsx-fsx.o `test -f 'test/librbd/fsx.c' || echo '$(srcdir)/'`test/librbd/fsx.c test/librbd/ceph_test_librbd_fsx-fsx.obj: test/librbd/fsx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_fsx_CFLAGS) $(CFLAGS) -MT test/librbd/ceph_test_librbd_fsx-fsx.obj -MD -MP -MF test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Tpo -c -o test/librbd/ceph_test_librbd_fsx-fsx.obj `if test -f 'test/librbd/fsx.c'; then $(CYGPATH_W) 'test/librbd/fsx.c'; else $(CYGPATH_W) '$(srcdir)/test/librbd/fsx.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Tpo test/librbd/$(DEPDIR)/ceph_test_librbd_fsx-fsx.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/librbd/fsx.c' object='test/librbd/ceph_test_librbd_fsx-fsx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_fsx_CFLAGS) $(CFLAGS) -c -o test/librbd/ceph_test_librbd_fsx-fsx.obj `if test -f 'test/librbd/fsx.c'; then $(CYGPATH_W) 'test/librbd/fsx.c'; else $(CYGPATH_W) '$(srcdir)/test/librbd/fsx.c'; fi` test_build_libcommon-ceph_ver.o: ceph_ver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT test_build_libcommon-ceph_ver.o -MD -MP -MF $(DEPDIR)/test_build_libcommon-ceph_ver.Tpo -c -o test_build_libcommon-ceph_ver.o `test -f 'ceph_ver.c' || echo '$(srcdir)/'`ceph_ver.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_build_libcommon-ceph_ver.Tpo $(DEPDIR)/test_build_libcommon-ceph_ver.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ceph_ver.c' object='test_build_libcommon-ceph_ver.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o test_build_libcommon-ceph_ver.o `test -f 'ceph_ver.c' || echo '$(srcdir)/'`ceph_ver.c test_build_libcommon-ceph_ver.obj: ceph_ver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT test_build_libcommon-ceph_ver.obj -MD -MP -MF $(DEPDIR)/test_build_libcommon-ceph_ver.Tpo -c -o test_build_libcommon-ceph_ver.obj `if test -f 'ceph_ver.c'; then $(CYGPATH_W) 'ceph_ver.c'; else $(CYGPATH_W) '$(srcdir)/ceph_ver.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_build_libcommon-ceph_ver.Tpo $(DEPDIR)/test_build_libcommon-ceph_ver.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ceph_ver.c' object='test_build_libcommon-ceph_ver.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o test_build_libcommon-ceph_ver.obj `if test -f 'ceph_ver.c'; then $(CYGPATH_W) 'ceph_ver.c'; else $(CYGPATH_W) '$(srcdir)/ceph_ver.c'; fi` common/test_build_libcommon-escape.o: common/escape.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-escape.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-escape.Tpo -c -o common/test_build_libcommon-escape.o `test -f 'common/escape.c' || echo '$(srcdir)/'`common/escape.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-escape.Tpo common/$(DEPDIR)/test_build_libcommon-escape.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/escape.c' object='common/test_build_libcommon-escape.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-escape.o `test -f 'common/escape.c' || echo '$(srcdir)/'`common/escape.c common/test_build_libcommon-escape.obj: common/escape.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-escape.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-escape.Tpo -c -o common/test_build_libcommon-escape.obj `if test -f 'common/escape.c'; then $(CYGPATH_W) 'common/escape.c'; else $(CYGPATH_W) '$(srcdir)/common/escape.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-escape.Tpo common/$(DEPDIR)/test_build_libcommon-escape.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/escape.c' object='common/test_build_libcommon-escape.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-escape.obj `if test -f 'common/escape.c'; then $(CYGPATH_W) 'common/escape.c'; else $(CYGPATH_W) '$(srcdir)/common/escape.c'; fi` common/test_build_libcommon-armor.o: common/armor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-armor.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-armor.Tpo -c -o common/test_build_libcommon-armor.o `test -f 'common/armor.c' || echo '$(srcdir)/'`common/armor.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-armor.Tpo common/$(DEPDIR)/test_build_libcommon-armor.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/armor.c' object='common/test_build_libcommon-armor.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-armor.o `test -f 'common/armor.c' || echo '$(srcdir)/'`common/armor.c common/test_build_libcommon-armor.obj: common/armor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-armor.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-armor.Tpo -c -o common/test_build_libcommon-armor.obj `if test -f 'common/armor.c'; then $(CYGPATH_W) 'common/armor.c'; else $(CYGPATH_W) '$(srcdir)/common/armor.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-armor.Tpo common/$(DEPDIR)/test_build_libcommon-armor.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/armor.c' object='common/test_build_libcommon-armor.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-armor.obj `if test -f 'common/armor.c'; then $(CYGPATH_W) 'common/armor.c'; else $(CYGPATH_W) '$(srcdir)/common/armor.c'; fi` common/test_build_libcommon-xattr.o: common/xattr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-xattr.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-xattr.Tpo -c -o common/test_build_libcommon-xattr.o `test -f 'common/xattr.c' || echo '$(srcdir)/'`common/xattr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-xattr.Tpo common/$(DEPDIR)/test_build_libcommon-xattr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/xattr.c' object='common/test_build_libcommon-xattr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-xattr.o `test -f 'common/xattr.c' || echo '$(srcdir)/'`common/xattr.c common/test_build_libcommon-xattr.obj: common/xattr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-xattr.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-xattr.Tpo -c -o common/test_build_libcommon-xattr.obj `if test -f 'common/xattr.c'; then $(CYGPATH_W) 'common/xattr.c'; else $(CYGPATH_W) '$(srcdir)/common/xattr.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-xattr.Tpo common/$(DEPDIR)/test_build_libcommon-xattr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/xattr.c' object='common/test_build_libcommon-xattr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-xattr.obj `if test -f 'common/xattr.c'; then $(CYGPATH_W) 'common/xattr.c'; else $(CYGPATH_W) '$(srcdir)/common/xattr.c'; fi` common/test_build_libcommon-safe_io.o: common/safe_io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-safe_io.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-safe_io.Tpo -c -o common/test_build_libcommon-safe_io.o `test -f 'common/safe_io.c' || echo '$(srcdir)/'`common/safe_io.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-safe_io.Tpo common/$(DEPDIR)/test_build_libcommon-safe_io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/safe_io.c' object='common/test_build_libcommon-safe_io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-safe_io.o `test -f 'common/safe_io.c' || echo '$(srcdir)/'`common/safe_io.c common/test_build_libcommon-safe_io.obj: common/safe_io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-safe_io.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-safe_io.Tpo -c -o common/test_build_libcommon-safe_io.obj `if test -f 'common/safe_io.c'; then $(CYGPATH_W) 'common/safe_io.c'; else $(CYGPATH_W) '$(srcdir)/common/safe_io.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-safe_io.Tpo common/$(DEPDIR)/test_build_libcommon-safe_io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/safe_io.c' object='common/test_build_libcommon-safe_io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-safe_io.obj `if test -f 'common/safe_io.c'; then $(CYGPATH_W) 'common/safe_io.c'; else $(CYGPATH_W) '$(srcdir)/common/safe_io.c'; fi` common/test_build_libcommon-pipe.o: common/pipe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-pipe.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-pipe.Tpo -c -o common/test_build_libcommon-pipe.o `test -f 'common/pipe.c' || echo '$(srcdir)/'`common/pipe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-pipe.Tpo common/$(DEPDIR)/test_build_libcommon-pipe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/pipe.c' object='common/test_build_libcommon-pipe.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-pipe.o `test -f 'common/pipe.c' || echo '$(srcdir)/'`common/pipe.c common/test_build_libcommon-pipe.obj: common/pipe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-pipe.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-pipe.Tpo -c -o common/test_build_libcommon-pipe.obj `if test -f 'common/pipe.c'; then $(CYGPATH_W) 'common/pipe.c'; else $(CYGPATH_W) '$(srcdir)/common/pipe.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-pipe.Tpo common/$(DEPDIR)/test_build_libcommon-pipe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/pipe.c' object='common/test_build_libcommon-pipe.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-pipe.obj `if test -f 'common/pipe.c'; then $(CYGPATH_W) 'common/pipe.c'; else $(CYGPATH_W) '$(srcdir)/common/pipe.c'; fi` common/test_build_libcommon-utf8.o: common/utf8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-utf8.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-utf8.Tpo -c -o common/test_build_libcommon-utf8.o `test -f 'common/utf8.c' || echo '$(srcdir)/'`common/utf8.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-utf8.Tpo common/$(DEPDIR)/test_build_libcommon-utf8.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/utf8.c' object='common/test_build_libcommon-utf8.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-utf8.o `test -f 'common/utf8.c' || echo '$(srcdir)/'`common/utf8.c common/test_build_libcommon-utf8.obj: common/utf8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-utf8.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-utf8.Tpo -c -o common/test_build_libcommon-utf8.obj `if test -f 'common/utf8.c'; then $(CYGPATH_W) 'common/utf8.c'; else $(CYGPATH_W) '$(srcdir)/common/utf8.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-utf8.Tpo common/$(DEPDIR)/test_build_libcommon-utf8.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/utf8.c' object='common/test_build_libcommon-utf8.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-utf8.obj `if test -f 'common/utf8.c'; then $(CYGPATH_W) 'common/utf8.c'; else $(CYGPATH_W) '$(srcdir)/common/utf8.c'; fi` common/test_build_libcommon-mime.o: common/mime.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-mime.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-mime.Tpo -c -o common/test_build_libcommon-mime.o `test -f 'common/mime.c' || echo '$(srcdir)/'`common/mime.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-mime.Tpo common/$(DEPDIR)/test_build_libcommon-mime.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/mime.c' object='common/test_build_libcommon-mime.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-mime.o `test -f 'common/mime.c' || echo '$(srcdir)/'`common/mime.c common/test_build_libcommon-mime.obj: common/mime.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-mime.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-mime.Tpo -c -o common/test_build_libcommon-mime.obj `if test -f 'common/mime.c'; then $(CYGPATH_W) 'common/mime.c'; else $(CYGPATH_W) '$(srcdir)/common/mime.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-mime.Tpo common/$(DEPDIR)/test_build_libcommon-mime.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/mime.c' object='common/test_build_libcommon-mime.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-mime.obj `if test -f 'common/mime.c'; then $(CYGPATH_W) 'common/mime.c'; else $(CYGPATH_W) '$(srcdir)/common/mime.c'; fi` common/test_build_libcommon-addr_parsing.o: common/addr_parsing.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-addr_parsing.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-addr_parsing.Tpo -c -o common/test_build_libcommon-addr_parsing.o `test -f 'common/addr_parsing.c' || echo '$(srcdir)/'`common/addr_parsing.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-addr_parsing.Tpo common/$(DEPDIR)/test_build_libcommon-addr_parsing.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/addr_parsing.c' object='common/test_build_libcommon-addr_parsing.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-addr_parsing.o `test -f 'common/addr_parsing.c' || echo '$(srcdir)/'`common/addr_parsing.c common/test_build_libcommon-addr_parsing.obj: common/addr_parsing.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-addr_parsing.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-addr_parsing.Tpo -c -o common/test_build_libcommon-addr_parsing.obj `if test -f 'common/addr_parsing.c'; then $(CYGPATH_W) 'common/addr_parsing.c'; else $(CYGPATH_W) '$(srcdir)/common/addr_parsing.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-addr_parsing.Tpo common/$(DEPDIR)/test_build_libcommon-addr_parsing.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/addr_parsing.c' object='common/test_build_libcommon-addr_parsing.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-addr_parsing.obj `if test -f 'common/addr_parsing.c'; then $(CYGPATH_W) 'common/addr_parsing.c'; else $(CYGPATH_W) '$(srcdir)/common/addr_parsing.c'; fi` common/test_build_libcommon-linux_version.o: common/linux_version.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-linux_version.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-linux_version.Tpo -c -o common/test_build_libcommon-linux_version.o `test -f 'common/linux_version.c' || echo '$(srcdir)/'`common/linux_version.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-linux_version.Tpo common/$(DEPDIR)/test_build_libcommon-linux_version.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/linux_version.c' object='common/test_build_libcommon-linux_version.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-linux_version.o `test -f 'common/linux_version.c' || echo '$(srcdir)/'`common/linux_version.c common/test_build_libcommon-linux_version.obj: common/linux_version.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -MT common/test_build_libcommon-linux_version.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-linux_version.Tpo -c -o common/test_build_libcommon-linux_version.obj `if test -f 'common/linux_version.c'; then $(CYGPATH_W) 'common/linux_version.c'; else $(CYGPATH_W) '$(srcdir)/common/linux_version.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-linux_version.Tpo common/$(DEPDIR)/test_build_libcommon-linux_version.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common/linux_version.c' object='common/test_build_libcommon-linux_version.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CFLAGS) $(CFLAGS) -c -o common/test_build_libcommon-linux_version.obj `if test -f 'common/linux_version.c'; then $(CYGPATH_W) 'common/linux_version.c'; else $(CYGPATH_W) '$(srcdir)/common/linux_version.c'; fi` erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.o: erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.o -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.o `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/cauchy.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.o `test -f 'erasure-code/jerasure/jerasure/src/cauchy.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/cauchy.c erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.obj: erasure-code/jerasure/jerasure/src/cauchy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.obj -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.obj `if test -f 'erasure-code/jerasure/jerasure/src/cauchy.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/cauchy.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/cauchy.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-cauchy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/cauchy.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-cauchy.obj `if test -f 'erasure-code/jerasure/jerasure/src/cauchy.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/cauchy.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/cauchy.c'; fi` erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.o: erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.o -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.o `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/galois.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.o `test -f 'erasure-code/jerasure/jerasure/src/galois.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/galois.c erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.obj: erasure-code/jerasure/jerasure/src/galois.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.obj -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.obj `if test -f 'erasure-code/jerasure/jerasure/src/galois.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/galois.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/galois.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-galois.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/galois.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-galois.obj `if test -f 'erasure-code/jerasure/jerasure/src/galois.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/galois.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/galois.c'; fi` erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.o: erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.o -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.o `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/jerasure.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.o `test -f 'erasure-code/jerasure/jerasure/src/jerasure.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/jerasure.c erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.obj: erasure-code/jerasure/jerasure/src/jerasure.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.obj -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.obj `if test -f 'erasure-code/jerasure/jerasure/src/jerasure.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/jerasure.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/jerasure.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-jerasure.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/jerasure.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-jerasure.obj `if test -f 'erasure-code/jerasure/jerasure/src/jerasure.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/jerasure.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/jerasure.c'; fi` erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.o: erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.o -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.o `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/liberation.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.o `test -f 'erasure-code/jerasure/jerasure/src/liberation.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/liberation.c erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.obj: erasure-code/jerasure/jerasure/src/liberation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.obj -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.obj `if test -f 'erasure-code/jerasure/jerasure/src/liberation.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/liberation.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/liberation.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-liberation.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/liberation.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-liberation.obj `if test -f 'erasure-code/jerasure/jerasure/src/liberation.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/liberation.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/liberation.c'; fi` erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.o: erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.o -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.o `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/reed_sol.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.o `test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c' || echo '$(srcdir)/'`erasure-code/jerasure/jerasure/src/reed_sol.c erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.obj: erasure-code/jerasure/jerasure/src/reed_sol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.obj -MD -MP -MF erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Tpo -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.obj `if test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/reed_sol.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/reed_sol.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Tpo erasure-code/jerasure/jerasure/src/$(DEPDIR)/unittest_erasure_code_jerasure-reed_sol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/jerasure/src/reed_sol.c' object='erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/jerasure/src/unittest_erasure_code_jerasure-reed_sol.obj `if test -f 'erasure-code/jerasure/jerasure/src/reed_sol.c'; then $(CYGPATH_W) 'erasure-code/jerasure/jerasure/src/reed_sol.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/jerasure/src/reed_sol.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.o: erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_wgen.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_wgen.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.obj: erasure-code/jerasure/gf-complete/src/gf_wgen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_wgen.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_wgen.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_wgen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_wgen.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_wgen.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_wgen.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_wgen.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_wgen.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.o: erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_method.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_method.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.obj: erasure-code/jerasure/gf-complete/src/gf_method.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_method.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_method.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_method.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_method.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_method.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_method.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_method.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_method.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.o: erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w16.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w16.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.obj: erasure-code/jerasure/gf-complete/src/gf_w16.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w16.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w16.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w16.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w16.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w16.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w16.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w16.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w16.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.o: erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.o `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.o `test -f 'erasure-code/jerasure/gf-complete/src/gf.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.obj: erasure-code/jerasure/gf-complete/src/gf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.o: erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w32.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w32.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.obj: erasure-code/jerasure/gf-complete/src/gf_w32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w32.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w32.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w32.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w32.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w32.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w32.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w32.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w32.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.o: erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w64.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w64.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.obj: erasure-code/jerasure/gf-complete/src/gf_w64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w64.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w64.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w64.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w64.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w64.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w64.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w64.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w64.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.o: erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w128.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w128.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.obj: erasure-code/jerasure/gf-complete/src/gf_w128.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w128.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w128.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w128.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w128.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w128.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w128.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w128.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w128.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.o: erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_general.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_general.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.obj: erasure-code/jerasure/gf-complete/src/gf_general.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_general.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_general.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_general.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_general.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_general.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_general.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_general.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_general.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.o: erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w4.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w4.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.obj: erasure-code/jerasure/gf-complete/src/gf_w4.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w4.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w4.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w4.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w4.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w4.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w4.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w4.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w4.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.o: erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_rand.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_rand.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.obj: erasure-code/jerasure/gf-complete/src/gf_rand.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_rand.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_rand.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_rand.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_rand.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_rand.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_rand.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_rand.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_rand.c'; fi` erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.o: erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.o -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w8.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.o `test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c' || echo '$(srcdir)/'`erasure-code/jerasure/gf-complete/src/gf_w8.c erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.obj: erasure-code/jerasure/gf-complete/src/gf_w8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -MT erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.obj -MD -MP -MF erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Tpo -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w8.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w8.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Tpo erasure-code/jerasure/gf-complete/src/$(DEPDIR)/unittest_erasure_code_jerasure-gf_w8.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='erasure-code/jerasure/gf-complete/src/gf_w8.c' object='erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CFLAGS) $(CFLAGS) -c -o erasure-code/jerasure/gf-complete/src/unittest_erasure_code_jerasure-gf_w8.obj `if test -f 'erasure-code/jerasure/gf-complete/src/gf_w8.c'; then $(CYGPATH_W) 'erasure-code/jerasure/gf-complete/src/gf_w8.c'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/gf-complete/src/gf_w8.c'; fi` .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< os/libos_zfs_a-ZFS.o: os/ZFS.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_zfs_a_CXXFLAGS) $(CXXFLAGS) -MT os/libos_zfs_a-ZFS.o -MD -MP -MF os/$(DEPDIR)/libos_zfs_a-ZFS.Tpo -c -o os/libos_zfs_a-ZFS.o `test -f 'os/ZFS.cc' || echo '$(srcdir)/'`os/ZFS.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_zfs_a-ZFS.Tpo os/$(DEPDIR)/libos_zfs_a-ZFS.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/ZFS.cc' object='os/libos_zfs_a-ZFS.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_zfs_a_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_zfs_a-ZFS.o `test -f 'os/ZFS.cc' || echo '$(srcdir)/'`os/ZFS.cc os/libos_zfs_a-ZFS.obj: os/ZFS.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_zfs_a_CXXFLAGS) $(CXXFLAGS) -MT os/libos_zfs_a-ZFS.obj -MD -MP -MF os/$(DEPDIR)/libos_zfs_a-ZFS.Tpo -c -o os/libos_zfs_a-ZFS.obj `if test -f 'os/ZFS.cc'; then $(CYGPATH_W) 'os/ZFS.cc'; else $(CYGPATH_W) '$(srcdir)/os/ZFS.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_zfs_a-ZFS.Tpo os/$(DEPDIR)/libos_zfs_a-ZFS.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/ZFS.cc' object='os/libos_zfs_a-ZFS.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_zfs_a_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_zfs_a-ZFS.obj `if test -f 'os/ZFS.cc'; then $(CYGPATH_W) 'os/ZFS.cc'; else $(CYGPATH_W) '$(srcdir)/os/ZFS.cc'; fi` java/native/libcephfs_jni_la-libcephfs_jni.lo: java/native/libcephfs_jni.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcephfs_jni_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT java/native/libcephfs_jni_la-libcephfs_jni.lo -MD -MP -MF java/native/$(DEPDIR)/libcephfs_jni_la-libcephfs_jni.Tpo -c -o java/native/libcephfs_jni_la-libcephfs_jni.lo `test -f 'java/native/libcephfs_jni.cc' || echo '$(srcdir)/'`java/native/libcephfs_jni.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) java/native/$(DEPDIR)/libcephfs_jni_la-libcephfs_jni.Tpo java/native/$(DEPDIR)/libcephfs_jni_la-libcephfs_jni.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='java/native/libcephfs_jni.cc' object='java/native/libcephfs_jni_la-libcephfs_jni.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcephfs_jni_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o java/native/libcephfs_jni_la-libcephfs_jni.lo `test -f 'java/native/libcephfs_jni.cc' || echo '$(srcdir)/'`java/native/libcephfs_jni.cc java/native/libcephfs_jni_la-JniConstants.lo: java/native/JniConstants.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcephfs_jni_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT java/native/libcephfs_jni_la-JniConstants.lo -MD -MP -MF java/native/$(DEPDIR)/libcephfs_jni_la-JniConstants.Tpo -c -o java/native/libcephfs_jni_la-JniConstants.lo `test -f 'java/native/JniConstants.cpp' || echo '$(srcdir)/'`java/native/JniConstants.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) java/native/$(DEPDIR)/libcephfs_jni_la-JniConstants.Tpo java/native/$(DEPDIR)/libcephfs_jni_la-JniConstants.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='java/native/JniConstants.cpp' object='java/native/libcephfs_jni_la-JniConstants.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcephfs_jni_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o java/native/libcephfs_jni_la-JniConstants.lo `test -f 'java/native/JniConstants.cpp' || echo '$(srcdir)/'`java/native/JniConstants.cpp rgw/libcivetweb_la-rgw_civetweb.lo: rgw/rgw_civetweb.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcivetweb_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/libcivetweb_la-rgw_civetweb.lo -MD -MP -MF rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb.Tpo -c -o rgw/libcivetweb_la-rgw_civetweb.lo `test -f 'rgw/rgw_civetweb.cc' || echo '$(srcdir)/'`rgw/rgw_civetweb.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb.Tpo rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_civetweb.cc' object='rgw/libcivetweb_la-rgw_civetweb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcivetweb_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/libcivetweb_la-rgw_civetweb.lo `test -f 'rgw/rgw_civetweb.cc' || echo '$(srcdir)/'`rgw/rgw_civetweb.cc rgw/libcivetweb_la-rgw_civetweb_log.lo: rgw/rgw_civetweb_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcivetweb_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/libcivetweb_la-rgw_civetweb_log.lo -MD -MP -MF rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb_log.Tpo -c -o rgw/libcivetweb_la-rgw_civetweb_log.lo `test -f 'rgw/rgw_civetweb_log.cc' || echo '$(srcdir)/'`rgw/rgw_civetweb_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb_log.Tpo rgw/$(DEPDIR)/libcivetweb_la-rgw_civetweb_log.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_civetweb_log.cc' object='rgw/libcivetweb_la-rgw_civetweb_log.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcivetweb_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/libcivetweb_la-rgw_civetweb_log.lo `test -f 'rgw/rgw_civetweb_log.cc' || echo '$(srcdir)/'`rgw/rgw_civetweb_log.cc common/libcommon_crc_la-crc32c.lo: common/crc32c.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT common/libcommon_crc_la-crc32c.lo -MD -MP -MF common/$(DEPDIR)/libcommon_crc_la-crc32c.Tpo -c -o common/libcommon_crc_la-crc32c.lo `test -f 'common/crc32c.cc' || echo '$(srcdir)/'`common/crc32c.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libcommon_crc_la-crc32c.Tpo common/$(DEPDIR)/libcommon_crc_la-crc32c.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/crc32c.cc' object='common/libcommon_crc_la-crc32c.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(libcommon_crc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o common/libcommon_crc_la-crc32c.lo `test -f 'common/crc32c.cc' || echo '$(srcdir)/'`common/crc32c.cc test/erasure-code/libec_example_la-ErasureCodePluginExample.lo: test/erasure-code/ErasureCodePluginExample.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_example_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_example_la-ErasureCodePluginExample.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_example_la-ErasureCodePluginExample.Tpo -c -o test/erasure-code/libec_example_la-ErasureCodePluginExample.lo `test -f 'test/erasure-code/ErasureCodePluginExample.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginExample.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_example_la-ErasureCodePluginExample.Tpo test/erasure-code/$(DEPDIR)/libec_example_la-ErasureCodePluginExample.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/ErasureCodePluginExample.cc' object='test/erasure-code/libec_example_la-ErasureCodePluginExample.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_example_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_example_la-ErasureCodePluginExample.lo `test -f 'test/erasure-code/ErasureCodePluginExample.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginExample.cc test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo: test/erasure-code/ErasureCodePluginFailToInitialize.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_fail_to_initialize_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.Tpo -c -o test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo `test -f 'test/erasure-code/ErasureCodePluginFailToInitialize.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginFailToInitialize.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.Tpo test/erasure-code/$(DEPDIR)/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/ErasureCodePluginFailToInitialize.cc' object='test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_fail_to_initialize_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_fail_to_initialize_la-ErasureCodePluginFailToInitialize.lo `test -f 'test/erasure-code/ErasureCodePluginFailToInitialize.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginFailToInitialize.cc test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo: test/erasure-code/ErasureCodePluginFailToRegister.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_fail_to_register_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_fail_to_register_la-ErasureCodePluginFailToRegister.Tpo -c -o test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo `test -f 'test/erasure-code/ErasureCodePluginFailToRegister.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginFailToRegister.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_fail_to_register_la-ErasureCodePluginFailToRegister.Tpo test/erasure-code/$(DEPDIR)/libec_fail_to_register_la-ErasureCodePluginFailToRegister.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/ErasureCodePluginFailToRegister.cc' object='test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_fail_to_register_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_fail_to_register_la-ErasureCodePluginFailToRegister.lo `test -f 'test/erasure-code/ErasureCodePluginFailToRegister.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginFailToRegister.cc test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo: test/erasure-code/ErasureCodePluginHangs.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_hangs_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_hangs_la-ErasureCodePluginHangs.Tpo -c -o test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo `test -f 'test/erasure-code/ErasureCodePluginHangs.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginHangs.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_hangs_la-ErasureCodePluginHangs.Tpo test/erasure-code/$(DEPDIR)/libec_hangs_la-ErasureCodePluginHangs.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/ErasureCodePluginHangs.cc' object='test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_hangs_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_hangs_la-ErasureCodePluginHangs.lo `test -f 'test/erasure-code/ErasureCodePluginHangs.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginHangs.cc erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo: erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_la-ErasureCodePluginSelectJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_la-ErasureCodePluginSelectJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_la-ErasureCodePluginSelectJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc' object='erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_la-ErasureCodePluginSelectJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginSelectJerasure.cc erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo: erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodePluginJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodePluginJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodePluginJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodePluginJerasure.cc' object='erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodePluginJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo: erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodeJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodeJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_generic_la-ErasureCodeJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodeJerasure.cc' object='erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_generic_la-ErasureCodeJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo: erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodePluginJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodePluginJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodePluginJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodePluginJerasure.cc' object='erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodePluginJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo: erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodeJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodeJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse3_la-ErasureCodeJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodeJerasure.cc' object='erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_sse3_la-ErasureCodeJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo: erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodePluginJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodePluginJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodePluginJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodePluginJerasure.cc' object='erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodePluginJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo: erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodeJerasure.Tpo -c -o erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodeJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/libec_jerasure_sse4_la-ErasureCodeJerasure.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodeJerasure.cc' object='erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/libec_jerasure_sse4_la-ErasureCodeJerasure.lo `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo: test/erasure-code/ErasureCodePluginMissingEntryPoint.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_missing_entry_point_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.Tpo -c -o test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo `test -f 'test/erasure-code/ErasureCodePluginMissingEntryPoint.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginMissingEntryPoint.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.Tpo test/erasure-code/$(DEPDIR)/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/ErasureCodePluginMissingEntryPoint.cc' object='test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_missing_entry_point_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_missing_entry_point_la-ErasureCodePluginMissingEntryPoint.lo `test -f 'test/erasure-code/ErasureCodePluginMissingEntryPoint.cc' || echo '$(srcdir)/'`test/erasure-code/ErasureCodePluginMissingEntryPoint.cc test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo: test/erasure-code/TestJerasurePluginGeneric.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_test_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.Tpo -c -o test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo `test -f 'test/erasure-code/TestJerasurePluginGeneric.cc' || echo '$(srcdir)/'`test/erasure-code/TestJerasurePluginGeneric.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.Tpo test/erasure-code/$(DEPDIR)/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestJerasurePluginGeneric.cc' object='test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_test_jerasure_generic_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_test_jerasure_generic_la-TestJerasurePluginGeneric.lo `test -f 'test/erasure-code/TestJerasurePluginGeneric.cc' || echo '$(srcdir)/'`test/erasure-code/TestJerasurePluginGeneric.cc test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo: test/erasure-code/TestJerasurePluginSSE3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_test_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.Tpo -c -o test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo `test -f 'test/erasure-code/TestJerasurePluginSSE3.cc' || echo '$(srcdir)/'`test/erasure-code/TestJerasurePluginSSE3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.Tpo test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestJerasurePluginSSE3.cc' object='test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_test_jerasure_sse3_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_test_jerasure_sse3_la-TestJerasurePluginSSE3.lo `test -f 'test/erasure-code/TestJerasurePluginSSE3.cc' || echo '$(srcdir)/'`test/erasure-code/TestJerasurePluginSSE3.cc test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo: test/erasure-code/TestJerasurePluginSSE4.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_test_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo -MD -MP -MF test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.Tpo -c -o test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo `test -f 'test/erasure-code/TestJerasurePluginSSE4.cc' || echo '$(srcdir)/'`test/erasure-code/TestJerasurePluginSSE4.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.Tpo test/erasure-code/$(DEPDIR)/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestJerasurePluginSSE4.cc' object='test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libec_test_jerasure_sse4_la_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/libec_test_jerasure_sse4_la-TestJerasurePluginSSE4.lo `test -f 'test/erasure-code/TestJerasurePluginSSE4.cc' || echo '$(srcdir)/'`test/erasure-code/TestJerasurePluginSSE4.cc os/libos_la-chain_xattr.lo: os/chain_xattr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-chain_xattr.lo -MD -MP -MF os/$(DEPDIR)/libos_la-chain_xattr.Tpo -c -o os/libos_la-chain_xattr.lo `test -f 'os/chain_xattr.cc' || echo '$(srcdir)/'`os/chain_xattr.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-chain_xattr.Tpo os/$(DEPDIR)/libos_la-chain_xattr.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/chain_xattr.cc' object='os/libos_la-chain_xattr.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-chain_xattr.lo `test -f 'os/chain_xattr.cc' || echo '$(srcdir)/'`os/chain_xattr.cc os/libos_la-DBObjectMap.lo: os/DBObjectMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-DBObjectMap.lo -MD -MP -MF os/$(DEPDIR)/libos_la-DBObjectMap.Tpo -c -o os/libos_la-DBObjectMap.lo `test -f 'os/DBObjectMap.cc' || echo '$(srcdir)/'`os/DBObjectMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-DBObjectMap.Tpo os/$(DEPDIR)/libos_la-DBObjectMap.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/DBObjectMap.cc' object='os/libos_la-DBObjectMap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-DBObjectMap.lo `test -f 'os/DBObjectMap.cc' || echo '$(srcdir)/'`os/DBObjectMap.cc os/libos_la-GenericObjectMap.lo: os/GenericObjectMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-GenericObjectMap.lo -MD -MP -MF os/$(DEPDIR)/libos_la-GenericObjectMap.Tpo -c -o os/libos_la-GenericObjectMap.lo `test -f 'os/GenericObjectMap.cc' || echo '$(srcdir)/'`os/GenericObjectMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-GenericObjectMap.Tpo os/$(DEPDIR)/libos_la-GenericObjectMap.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/GenericObjectMap.cc' object='os/libos_la-GenericObjectMap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-GenericObjectMap.lo `test -f 'os/GenericObjectMap.cc' || echo '$(srcdir)/'`os/GenericObjectMap.cc os/libos_la-FileJournal.lo: os/FileJournal.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-FileJournal.lo -MD -MP -MF os/$(DEPDIR)/libos_la-FileJournal.Tpo -c -o os/libos_la-FileJournal.lo `test -f 'os/FileJournal.cc' || echo '$(srcdir)/'`os/FileJournal.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-FileJournal.Tpo os/$(DEPDIR)/libos_la-FileJournal.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/FileJournal.cc' object='os/libos_la-FileJournal.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-FileJournal.lo `test -f 'os/FileJournal.cc' || echo '$(srcdir)/'`os/FileJournal.cc os/libos_la-FileStore.lo: os/FileStore.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-FileStore.lo -MD -MP -MF os/$(DEPDIR)/libos_la-FileStore.Tpo -c -o os/libos_la-FileStore.lo `test -f 'os/FileStore.cc' || echo '$(srcdir)/'`os/FileStore.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-FileStore.Tpo os/$(DEPDIR)/libos_la-FileStore.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/FileStore.cc' object='os/libos_la-FileStore.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-FileStore.lo `test -f 'os/FileStore.cc' || echo '$(srcdir)/'`os/FileStore.cc os/libos_la-FlatIndex.lo: os/FlatIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-FlatIndex.lo -MD -MP -MF os/$(DEPDIR)/libos_la-FlatIndex.Tpo -c -o os/libos_la-FlatIndex.lo `test -f 'os/FlatIndex.cc' || echo '$(srcdir)/'`os/FlatIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-FlatIndex.Tpo os/$(DEPDIR)/libos_la-FlatIndex.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/FlatIndex.cc' object='os/libos_la-FlatIndex.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-FlatIndex.lo `test -f 'os/FlatIndex.cc' || echo '$(srcdir)/'`os/FlatIndex.cc os/libos_la-GenericFileStoreBackend.lo: os/GenericFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-GenericFileStoreBackend.lo -MD -MP -MF os/$(DEPDIR)/libos_la-GenericFileStoreBackend.Tpo -c -o os/libos_la-GenericFileStoreBackend.lo `test -f 'os/GenericFileStoreBackend.cc' || echo '$(srcdir)/'`os/GenericFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-GenericFileStoreBackend.Tpo os/$(DEPDIR)/libos_la-GenericFileStoreBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/GenericFileStoreBackend.cc' object='os/libos_la-GenericFileStoreBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-GenericFileStoreBackend.lo `test -f 'os/GenericFileStoreBackend.cc' || echo '$(srcdir)/'`os/GenericFileStoreBackend.cc os/libos_la-HashIndex.lo: os/HashIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-HashIndex.lo -MD -MP -MF os/$(DEPDIR)/libos_la-HashIndex.Tpo -c -o os/libos_la-HashIndex.lo `test -f 'os/HashIndex.cc' || echo '$(srcdir)/'`os/HashIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-HashIndex.Tpo os/$(DEPDIR)/libos_la-HashIndex.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/HashIndex.cc' object='os/libos_la-HashIndex.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-HashIndex.lo `test -f 'os/HashIndex.cc' || echo '$(srcdir)/'`os/HashIndex.cc os/libos_la-IndexManager.lo: os/IndexManager.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-IndexManager.lo -MD -MP -MF os/$(DEPDIR)/libos_la-IndexManager.Tpo -c -o os/libos_la-IndexManager.lo `test -f 'os/IndexManager.cc' || echo '$(srcdir)/'`os/IndexManager.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-IndexManager.Tpo os/$(DEPDIR)/libos_la-IndexManager.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/IndexManager.cc' object='os/libos_la-IndexManager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-IndexManager.lo `test -f 'os/IndexManager.cc' || echo '$(srcdir)/'`os/IndexManager.cc os/libos_la-JournalingObjectStore.lo: os/JournalingObjectStore.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-JournalingObjectStore.lo -MD -MP -MF os/$(DEPDIR)/libos_la-JournalingObjectStore.Tpo -c -o os/libos_la-JournalingObjectStore.lo `test -f 'os/JournalingObjectStore.cc' || echo '$(srcdir)/'`os/JournalingObjectStore.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-JournalingObjectStore.Tpo os/$(DEPDIR)/libos_la-JournalingObjectStore.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/JournalingObjectStore.cc' object='os/libos_la-JournalingObjectStore.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-JournalingObjectStore.lo `test -f 'os/JournalingObjectStore.cc' || echo '$(srcdir)/'`os/JournalingObjectStore.cc os/libos_la-LevelDBStore.lo: os/LevelDBStore.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-LevelDBStore.lo -MD -MP -MF os/$(DEPDIR)/libos_la-LevelDBStore.Tpo -c -o os/libos_la-LevelDBStore.lo `test -f 'os/LevelDBStore.cc' || echo '$(srcdir)/'`os/LevelDBStore.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-LevelDBStore.Tpo os/$(DEPDIR)/libos_la-LevelDBStore.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/LevelDBStore.cc' object='os/libos_la-LevelDBStore.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-LevelDBStore.lo `test -f 'os/LevelDBStore.cc' || echo '$(srcdir)/'`os/LevelDBStore.cc os/libos_la-LFNIndex.lo: os/LFNIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-LFNIndex.lo -MD -MP -MF os/$(DEPDIR)/libos_la-LFNIndex.Tpo -c -o os/libos_la-LFNIndex.lo `test -f 'os/LFNIndex.cc' || echo '$(srcdir)/'`os/LFNIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-LFNIndex.Tpo os/$(DEPDIR)/libos_la-LFNIndex.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/LFNIndex.cc' object='os/libos_la-LFNIndex.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-LFNIndex.lo `test -f 'os/LFNIndex.cc' || echo '$(srcdir)/'`os/LFNIndex.cc os/libos_la-MemStore.lo: os/MemStore.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-MemStore.lo -MD -MP -MF os/$(DEPDIR)/libos_la-MemStore.Tpo -c -o os/libos_la-MemStore.lo `test -f 'os/MemStore.cc' || echo '$(srcdir)/'`os/MemStore.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-MemStore.Tpo os/$(DEPDIR)/libos_la-MemStore.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/MemStore.cc' object='os/libos_la-MemStore.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-MemStore.lo `test -f 'os/MemStore.cc' || echo '$(srcdir)/'`os/MemStore.cc os/libos_la-KeyValueStore.lo: os/KeyValueStore.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-KeyValueStore.lo -MD -MP -MF os/$(DEPDIR)/libos_la-KeyValueStore.Tpo -c -o os/libos_la-KeyValueStore.lo `test -f 'os/KeyValueStore.cc' || echo '$(srcdir)/'`os/KeyValueStore.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-KeyValueStore.Tpo os/$(DEPDIR)/libos_la-KeyValueStore.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/KeyValueStore.cc' object='os/libos_la-KeyValueStore.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-KeyValueStore.lo `test -f 'os/KeyValueStore.cc' || echo '$(srcdir)/'`os/KeyValueStore.cc os/libos_la-ObjectStore.lo: os/ObjectStore.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-ObjectStore.lo -MD -MP -MF os/$(DEPDIR)/libos_la-ObjectStore.Tpo -c -o os/libos_la-ObjectStore.lo `test -f 'os/ObjectStore.cc' || echo '$(srcdir)/'`os/ObjectStore.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-ObjectStore.Tpo os/$(DEPDIR)/libos_la-ObjectStore.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/ObjectStore.cc' object='os/libos_la-ObjectStore.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-ObjectStore.lo `test -f 'os/ObjectStore.cc' || echo '$(srcdir)/'`os/ObjectStore.cc os/libos_la-WBThrottle.lo: os/WBThrottle.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-WBThrottle.lo -MD -MP -MF os/$(DEPDIR)/libos_la-WBThrottle.Tpo -c -o os/libos_la-WBThrottle.lo `test -f 'os/WBThrottle.cc' || echo '$(srcdir)/'`os/WBThrottle.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-WBThrottle.Tpo os/$(DEPDIR)/libos_la-WBThrottle.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/WBThrottle.cc' object='os/libos_la-WBThrottle.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-WBThrottle.lo `test -f 'os/WBThrottle.cc' || echo '$(srcdir)/'`os/WBThrottle.cc common/libos_la-TrackedOp.lo: common/TrackedOp.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT common/libos_la-TrackedOp.lo -MD -MP -MF common/$(DEPDIR)/libos_la-TrackedOp.Tpo -c -o common/libos_la-TrackedOp.lo `test -f 'common/TrackedOp.cc' || echo '$(srcdir)/'`common/TrackedOp.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libos_la-TrackedOp.Tpo common/$(DEPDIR)/libos_la-TrackedOp.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/TrackedOp.cc' object='common/libos_la-TrackedOp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libos_la-TrackedOp.lo `test -f 'common/TrackedOp.cc' || echo '$(srcdir)/'`common/TrackedOp.cc os/libos_la-BtrfsFileStoreBackend.lo: os/BtrfsFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-BtrfsFileStoreBackend.lo -MD -MP -MF os/$(DEPDIR)/libos_la-BtrfsFileStoreBackend.Tpo -c -o os/libos_la-BtrfsFileStoreBackend.lo `test -f 'os/BtrfsFileStoreBackend.cc' || echo '$(srcdir)/'`os/BtrfsFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-BtrfsFileStoreBackend.Tpo os/$(DEPDIR)/libos_la-BtrfsFileStoreBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/BtrfsFileStoreBackend.cc' object='os/libos_la-BtrfsFileStoreBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-BtrfsFileStoreBackend.lo `test -f 'os/BtrfsFileStoreBackend.cc' || echo '$(srcdir)/'`os/BtrfsFileStoreBackend.cc os/libos_la-XfsFileStoreBackend.lo: os/XfsFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-XfsFileStoreBackend.lo -MD -MP -MF os/$(DEPDIR)/libos_la-XfsFileStoreBackend.Tpo -c -o os/libos_la-XfsFileStoreBackend.lo `test -f 'os/XfsFileStoreBackend.cc' || echo '$(srcdir)/'`os/XfsFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-XfsFileStoreBackend.Tpo os/$(DEPDIR)/libos_la-XfsFileStoreBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/XfsFileStoreBackend.cc' object='os/libos_la-XfsFileStoreBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-XfsFileStoreBackend.lo `test -f 'os/XfsFileStoreBackend.cc' || echo '$(srcdir)/'`os/XfsFileStoreBackend.cc os/libos_la-ZFSFileStoreBackend.lo: os/ZFSFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_la-ZFSFileStoreBackend.lo -MD -MP -MF os/$(DEPDIR)/libos_la-ZFSFileStoreBackend.Tpo -c -o os/libos_la-ZFSFileStoreBackend.lo `test -f 'os/ZFSFileStoreBackend.cc' || echo '$(srcdir)/'`os/ZFSFileStoreBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_la-ZFSFileStoreBackend.Tpo os/$(DEPDIR)/libos_la-ZFSFileStoreBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/ZFSFileStoreBackend.cc' object='os/libos_la-ZFSFileStoreBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_la-ZFSFileStoreBackend.lo `test -f 'os/ZFSFileStoreBackend.cc' || echo '$(srcdir)/'`os/ZFSFileStoreBackend.cc os/libos_types_la-Transaction.lo: os/Transaction.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_types_la_CXXFLAGS) $(CXXFLAGS) -MT os/libos_types_la-Transaction.lo -MD -MP -MF os/$(DEPDIR)/libos_types_la-Transaction.Tpo -c -o os/libos_types_la-Transaction.lo `test -f 'os/Transaction.cc' || echo '$(srcdir)/'`os/Transaction.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libos_types_la-Transaction.Tpo os/$(DEPDIR)/libos_types_la-Transaction.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='os/Transaction.cc' object='os/libos_types_la-Transaction.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libos_types_la_CXXFLAGS) $(CXXFLAGS) -c -o os/libos_types_la-Transaction.lo `test -f 'os/Transaction.cc' || echo '$(srcdir)/'`os/Transaction.cc osd/libosd_la-PG.lo: osd/PG.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-PG.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-PG.Tpo -c -o osd/libosd_la-PG.lo `test -f 'osd/PG.cc' || echo '$(srcdir)/'`osd/PG.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-PG.Tpo osd/$(DEPDIR)/libosd_la-PG.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/PG.cc' object='osd/libosd_la-PG.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-PG.lo `test -f 'osd/PG.cc' || echo '$(srcdir)/'`osd/PG.cc osd/libosd_la-ReplicatedPG.lo: osd/ReplicatedPG.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-ReplicatedPG.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-ReplicatedPG.Tpo -c -o osd/libosd_la-ReplicatedPG.lo `test -f 'osd/ReplicatedPG.cc' || echo '$(srcdir)/'`osd/ReplicatedPG.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-ReplicatedPG.Tpo osd/$(DEPDIR)/libosd_la-ReplicatedPG.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ReplicatedPG.cc' object='osd/libosd_la-ReplicatedPG.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-ReplicatedPG.lo `test -f 'osd/ReplicatedPG.cc' || echo '$(srcdir)/'`osd/ReplicatedPG.cc osd/libosd_la-ReplicatedBackend.lo: osd/ReplicatedBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-ReplicatedBackend.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-ReplicatedBackend.Tpo -c -o osd/libosd_la-ReplicatedBackend.lo `test -f 'osd/ReplicatedBackend.cc' || echo '$(srcdir)/'`osd/ReplicatedBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-ReplicatedBackend.Tpo osd/$(DEPDIR)/libosd_la-ReplicatedBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ReplicatedBackend.cc' object='osd/libosd_la-ReplicatedBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-ReplicatedBackend.lo `test -f 'osd/ReplicatedBackend.cc' || echo '$(srcdir)/'`osd/ReplicatedBackend.cc osd/libosd_la-ECBackend.lo: osd/ECBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-ECBackend.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-ECBackend.Tpo -c -o osd/libosd_la-ECBackend.lo `test -f 'osd/ECBackend.cc' || echo '$(srcdir)/'`osd/ECBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-ECBackend.Tpo osd/$(DEPDIR)/libosd_la-ECBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ECBackend.cc' object='osd/libosd_la-ECBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-ECBackend.lo `test -f 'osd/ECBackend.cc' || echo '$(srcdir)/'`osd/ECBackend.cc osd/libosd_la-ECMsgTypes.lo: osd/ECMsgTypes.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-ECMsgTypes.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-ECMsgTypes.Tpo -c -o osd/libosd_la-ECMsgTypes.lo `test -f 'osd/ECMsgTypes.cc' || echo '$(srcdir)/'`osd/ECMsgTypes.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-ECMsgTypes.Tpo osd/$(DEPDIR)/libosd_la-ECMsgTypes.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ECMsgTypes.cc' object='osd/libosd_la-ECMsgTypes.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-ECMsgTypes.lo `test -f 'osd/ECMsgTypes.cc' || echo '$(srcdir)/'`osd/ECMsgTypes.cc osd/libosd_la-ECTransaction.lo: osd/ECTransaction.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-ECTransaction.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-ECTransaction.Tpo -c -o osd/libosd_la-ECTransaction.lo `test -f 'osd/ECTransaction.cc' || echo '$(srcdir)/'`osd/ECTransaction.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-ECTransaction.Tpo osd/$(DEPDIR)/libosd_la-ECTransaction.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ECTransaction.cc' object='osd/libosd_la-ECTransaction.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-ECTransaction.lo `test -f 'osd/ECTransaction.cc' || echo '$(srcdir)/'`osd/ECTransaction.cc osd/libosd_la-PGBackend.lo: osd/PGBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-PGBackend.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-PGBackend.Tpo -c -o osd/libosd_la-PGBackend.lo `test -f 'osd/PGBackend.cc' || echo '$(srcdir)/'`osd/PGBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-PGBackend.Tpo osd/$(DEPDIR)/libosd_la-PGBackend.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/PGBackend.cc' object='osd/libosd_la-PGBackend.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-PGBackend.lo `test -f 'osd/PGBackend.cc' || echo '$(srcdir)/'`osd/PGBackend.cc osd/libosd_la-Ager.lo: osd/Ager.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-Ager.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-Ager.Tpo -c -o osd/libosd_la-Ager.lo `test -f 'osd/Ager.cc' || echo '$(srcdir)/'`osd/Ager.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-Ager.Tpo osd/$(DEPDIR)/libosd_la-Ager.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/Ager.cc' object='osd/libosd_la-Ager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-Ager.lo `test -f 'osd/Ager.cc' || echo '$(srcdir)/'`osd/Ager.cc osd/libosd_la-HitSet.lo: osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-HitSet.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-HitSet.Tpo -c -o osd/libosd_la-HitSet.lo `test -f 'osd/HitSet.cc' || echo '$(srcdir)/'`osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-HitSet.Tpo osd/$(DEPDIR)/libosd_la-HitSet.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/HitSet.cc' object='osd/libosd_la-HitSet.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-HitSet.lo `test -f 'osd/HitSet.cc' || echo '$(srcdir)/'`osd/HitSet.cc osd/libosd_la-OSD.lo: osd/OSD.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-OSD.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-OSD.Tpo -c -o osd/libosd_la-OSD.lo `test -f 'osd/OSD.cc' || echo '$(srcdir)/'`osd/OSD.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-OSD.Tpo osd/$(DEPDIR)/libosd_la-OSD.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/OSD.cc' object='osd/libosd_la-OSD.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-OSD.lo `test -f 'osd/OSD.cc' || echo '$(srcdir)/'`osd/OSD.cc osd/libosd_la-OSDCap.lo: osd/OSDCap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-OSDCap.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-OSDCap.Tpo -c -o osd/libosd_la-OSDCap.lo `test -f 'osd/OSDCap.cc' || echo '$(srcdir)/'`osd/OSDCap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-OSDCap.Tpo osd/$(DEPDIR)/libosd_la-OSDCap.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/OSDCap.cc' object='osd/libosd_la-OSDCap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-OSDCap.lo `test -f 'osd/OSDCap.cc' || echo '$(srcdir)/'`osd/OSDCap.cc osd/libosd_la-Watch.lo: osd/Watch.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-Watch.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-Watch.Tpo -c -o osd/libosd_la-Watch.lo `test -f 'osd/Watch.cc' || echo '$(srcdir)/'`osd/Watch.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-Watch.Tpo osd/$(DEPDIR)/libosd_la-Watch.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/Watch.cc' object='osd/libosd_la-Watch.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-Watch.lo `test -f 'osd/Watch.cc' || echo '$(srcdir)/'`osd/Watch.cc osd/libosd_la-ClassHandler.lo: osd/ClassHandler.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-ClassHandler.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-ClassHandler.Tpo -c -o osd/libosd_la-ClassHandler.lo `test -f 'osd/ClassHandler.cc' || echo '$(srcdir)/'`osd/ClassHandler.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-ClassHandler.Tpo osd/$(DEPDIR)/libosd_la-ClassHandler.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ClassHandler.cc' object='osd/libosd_la-ClassHandler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-ClassHandler.lo `test -f 'osd/ClassHandler.cc' || echo '$(srcdir)/'`osd/ClassHandler.cc osd/libosd_la-OpRequest.lo: osd/OpRequest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-OpRequest.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-OpRequest.Tpo -c -o osd/libosd_la-OpRequest.lo `test -f 'osd/OpRequest.cc' || echo '$(srcdir)/'`osd/OpRequest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-OpRequest.Tpo osd/$(DEPDIR)/libosd_la-OpRequest.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/OpRequest.cc' object='osd/libosd_la-OpRequest.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-OpRequest.lo `test -f 'osd/OpRequest.cc' || echo '$(srcdir)/'`osd/OpRequest.cc common/libosd_la-TrackedOp.lo: common/TrackedOp.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT common/libosd_la-TrackedOp.lo -MD -MP -MF common/$(DEPDIR)/libosd_la-TrackedOp.Tpo -c -o common/libosd_la-TrackedOp.lo `test -f 'common/TrackedOp.cc' || echo '$(srcdir)/'`common/TrackedOp.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libosd_la-TrackedOp.Tpo common/$(DEPDIR)/libosd_la-TrackedOp.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/TrackedOp.cc' object='common/libosd_la-TrackedOp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libosd_la-TrackedOp.lo `test -f 'common/TrackedOp.cc' || echo '$(srcdir)/'`common/TrackedOp.cc osd/libosd_la-SnapMapper.lo: osd/SnapMapper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_la-SnapMapper.lo -MD -MP -MF osd/$(DEPDIR)/libosd_la-SnapMapper.Tpo -c -o osd/libosd_la-SnapMapper.lo `test -f 'osd/SnapMapper.cc' || echo '$(srcdir)/'`osd/SnapMapper.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_la-SnapMapper.Tpo osd/$(DEPDIR)/libosd_la-SnapMapper.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/SnapMapper.cc' object='osd/libosd_la-SnapMapper.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_la-SnapMapper.lo `test -f 'osd/SnapMapper.cc' || echo '$(srcdir)/'`osd/SnapMapper.cc objclass/libosd_la-class_api.lo: objclass/class_api.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -MT objclass/libosd_la-class_api.lo -MD -MP -MF objclass/$(DEPDIR)/libosd_la-class_api.Tpo -c -o objclass/libosd_la-class_api.lo `test -f 'objclass/class_api.cc' || echo '$(srcdir)/'`objclass/class_api.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) objclass/$(DEPDIR)/libosd_la-class_api.Tpo objclass/$(DEPDIR)/libosd_la-class_api.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='objclass/class_api.cc' object='objclass/libosd_la-class_api.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_la_CXXFLAGS) $(CXXFLAGS) -c -o objclass/libosd_la-class_api.lo `test -f 'objclass/class_api.cc' || echo '$(srcdir)/'`objclass/class_api.cc osd/libosd_types_la-PGLog.lo: osd/PGLog.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_types_la-PGLog.lo -MD -MP -MF osd/$(DEPDIR)/libosd_types_la-PGLog.Tpo -c -o osd/libosd_types_la-PGLog.lo `test -f 'osd/PGLog.cc' || echo '$(srcdir)/'`osd/PGLog.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_types_la-PGLog.Tpo osd/$(DEPDIR)/libosd_types_la-PGLog.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/PGLog.cc' object='osd/libosd_types_la-PGLog.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_types_la-PGLog.lo `test -f 'osd/PGLog.cc' || echo '$(srcdir)/'`osd/PGLog.cc osd/libosd_types_la-osd_types.lo: osd/osd_types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_types_la-osd_types.lo -MD -MP -MF osd/$(DEPDIR)/libosd_types_la-osd_types.Tpo -c -o osd/libosd_types_la-osd_types.lo `test -f 'osd/osd_types.cc' || echo '$(srcdir)/'`osd/osd_types.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_types_la-osd_types.Tpo osd/$(DEPDIR)/libosd_types_la-osd_types.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/osd_types.cc' object='osd/libosd_types_la-osd_types.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_types_la-osd_types.lo `test -f 'osd/osd_types.cc' || echo '$(srcdir)/'`osd/osd_types.cc osd/libosd_types_la-ECUtil.lo: osd/ECUtil.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) -MT osd/libosd_types_la-ECUtil.lo -MD -MP -MF osd/$(DEPDIR)/libosd_types_la-ECUtil.Tpo -c -o osd/libosd_types_la-ECUtil.lo `test -f 'osd/ECUtil.cc' || echo '$(srcdir)/'`osd/ECUtil.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/libosd_types_la-ECUtil.Tpo osd/$(DEPDIR)/libosd_types_la-ECUtil.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ECUtil.cc' object='osd/libosd_types_la-ECUtil.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libosd_types_la_CXXFLAGS) $(CXXFLAGS) -c -o osd/libosd_types_la-ECUtil.lo `test -f 'osd/ECUtil.cc' || echo '$(srcdir)/'`osd/ECUtil.cc librados/librados_la-librados.lo: librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -MT librados/librados_la-librados.lo -MD -MP -MF librados/$(DEPDIR)/librados_la-librados.Tpo -c -o librados/librados_la-librados.lo `test -f 'librados/librados.cc' || echo '$(srcdir)/'`librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/librados_la-librados.Tpo librados/$(DEPDIR)/librados_la-librados.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/librados.cc' object='librados/librados_la-librados.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -c -o librados/librados_la-librados.lo `test -f 'librados/librados.cc' || echo '$(srcdir)/'`librados/librados.cc librados/librados_la-RadosClient.lo: librados/RadosClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -MT librados/librados_la-RadosClient.lo -MD -MP -MF librados/$(DEPDIR)/librados_la-RadosClient.Tpo -c -o librados/librados_la-RadosClient.lo `test -f 'librados/RadosClient.cc' || echo '$(srcdir)/'`librados/RadosClient.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/librados_la-RadosClient.Tpo librados/$(DEPDIR)/librados_la-RadosClient.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/RadosClient.cc' object='librados/librados_la-RadosClient.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -c -o librados/librados_la-RadosClient.lo `test -f 'librados/RadosClient.cc' || echo '$(srcdir)/'`librados/RadosClient.cc librados/librados_la-IoCtxImpl.lo: librados/IoCtxImpl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -MT librados/librados_la-IoCtxImpl.lo -MD -MP -MF librados/$(DEPDIR)/librados_la-IoCtxImpl.Tpo -c -o librados/librados_la-IoCtxImpl.lo `test -f 'librados/IoCtxImpl.cc' || echo '$(srcdir)/'`librados/IoCtxImpl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/librados_la-IoCtxImpl.Tpo librados/$(DEPDIR)/librados_la-IoCtxImpl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/IoCtxImpl.cc' object='librados/librados_la-IoCtxImpl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -c -o librados/librados_la-IoCtxImpl.lo `test -f 'librados/IoCtxImpl.cc' || echo '$(srcdir)/'`librados/IoCtxImpl.cc librados/librados_la-snap_set_diff.lo: librados/snap_set_diff.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -MT librados/librados_la-snap_set_diff.lo -MD -MP -MF librados/$(DEPDIR)/librados_la-snap_set_diff.Tpo -c -o librados/librados_la-snap_set_diff.lo `test -f 'librados/snap_set_diff.cc' || echo '$(srcdir)/'`librados/snap_set_diff.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/librados_la-snap_set_diff.Tpo librados/$(DEPDIR)/librados_la-snap_set_diff.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/snap_set_diff.cc' object='librados/librados_la-snap_set_diff.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librados_la_CXXFLAGS) $(CXXFLAGS) -c -o librados/librados_la-snap_set_diff.lo `test -f 'librados/snap_set_diff.cc' || echo '$(srcdir)/'`librados/snap_set_diff.cc test/librados/libradostest_la-test.lo: test/librados/test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradostest_la_CXXFLAGS) $(CXXFLAGS) -MT test/librados/libradostest_la-test.lo -MD -MP -MF test/librados/$(DEPDIR)/libradostest_la-test.Tpo -c -o test/librados/libradostest_la-test.lo `test -f 'test/librados/test.cc' || echo '$(srcdir)/'`test/librados/test.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/libradostest_la-test.Tpo test/librados/$(DEPDIR)/libradostest_la-test.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/test.cc' object='test/librados/libradostest_la-test.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradostest_la_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/libradostest_la-test.lo `test -f 'test/librados/test.cc' || echo '$(srcdir)/'`test/librados/test.cc test/librados/libradostest_la-TestCase.lo: test/librados/TestCase.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradostest_la_CXXFLAGS) $(CXXFLAGS) -MT test/librados/libradostest_la-TestCase.lo -MD -MP -MF test/librados/$(DEPDIR)/libradostest_la-TestCase.Tpo -c -o test/librados/libradostest_la-TestCase.lo `test -f 'test/librados/TestCase.cc' || echo '$(srcdir)/'`test/librados/TestCase.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/libradostest_la-TestCase.Tpo test/librados/$(DEPDIR)/libradostest_la-TestCase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/TestCase.cc' object='test/librados/libradostest_la-TestCase.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libradostest_la_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/libradostest_la-TestCase.lo `test -f 'test/librados/TestCase.cc' || echo '$(srcdir)/'`test/librados/TestCase.cc rgw/librgw_la-librgw.lo: rgw/librgw.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-librgw.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-librgw.Tpo -c -o rgw/librgw_la-librgw.lo `test -f 'rgw/librgw.cc' || echo '$(srcdir)/'`rgw/librgw.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-librgw.Tpo rgw/$(DEPDIR)/librgw_la-librgw.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/librgw.cc' object='rgw/librgw_la-librgw.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-librgw.lo `test -f 'rgw/librgw.cc' || echo '$(srcdir)/'`rgw/librgw.cc rgw/librgw_la-rgw_acl.lo: rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_acl.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_acl.Tpo -c -o rgw/librgw_la-rgw_acl.lo `test -f 'rgw/rgw_acl.cc' || echo '$(srcdir)/'`rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_acl.Tpo rgw/$(DEPDIR)/librgw_la-rgw_acl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl.cc' object='rgw/librgw_la-rgw_acl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_acl.lo `test -f 'rgw/rgw_acl.cc' || echo '$(srcdir)/'`rgw/rgw_acl.cc rgw/librgw_la-rgw_acl_s3.lo: rgw/rgw_acl_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_acl_s3.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_acl_s3.Tpo -c -o rgw/librgw_la-rgw_acl_s3.lo `test -f 'rgw/rgw_acl_s3.cc' || echo '$(srcdir)/'`rgw/rgw_acl_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_acl_s3.Tpo rgw/$(DEPDIR)/librgw_la-rgw_acl_s3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl_s3.cc' object='rgw/librgw_la-rgw_acl_s3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_acl_s3.lo `test -f 'rgw/rgw_acl_s3.cc' || echo '$(srcdir)/'`rgw/rgw_acl_s3.cc rgw/librgw_la-rgw_acl_swift.lo: rgw/rgw_acl_swift.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_acl_swift.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_acl_swift.Tpo -c -o rgw/librgw_la-rgw_acl_swift.lo `test -f 'rgw/rgw_acl_swift.cc' || echo '$(srcdir)/'`rgw/rgw_acl_swift.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_acl_swift.Tpo rgw/$(DEPDIR)/librgw_la-rgw_acl_swift.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl_swift.cc' object='rgw/librgw_la-rgw_acl_swift.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_acl_swift.lo `test -f 'rgw/rgw_acl_swift.cc' || echo '$(srcdir)/'`rgw/rgw_acl_swift.cc rgw/librgw_la-rgw_client_io.lo: rgw/rgw_client_io.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_client_io.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_client_io.Tpo -c -o rgw/librgw_la-rgw_client_io.lo `test -f 'rgw/rgw_client_io.cc' || echo '$(srcdir)/'`rgw/rgw_client_io.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_client_io.Tpo rgw/$(DEPDIR)/librgw_la-rgw_client_io.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_client_io.cc' object='rgw/librgw_la-rgw_client_io.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_client_io.lo `test -f 'rgw/rgw_client_io.cc' || echo '$(srcdir)/'`rgw/rgw_client_io.cc rgw/librgw_la-rgw_fcgi.lo: rgw/rgw_fcgi.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_fcgi.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_fcgi.Tpo -c -o rgw/librgw_la-rgw_fcgi.lo `test -f 'rgw/rgw_fcgi.cc' || echo '$(srcdir)/'`rgw/rgw_fcgi.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_fcgi.Tpo rgw/$(DEPDIR)/librgw_la-rgw_fcgi.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_fcgi.cc' object='rgw/librgw_la-rgw_fcgi.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_fcgi.lo `test -f 'rgw/rgw_fcgi.cc' || echo '$(srcdir)/'`rgw/rgw_fcgi.cc rgw/librgw_la-rgw_xml.lo: rgw/rgw_xml.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_xml.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_xml.Tpo -c -o rgw/librgw_la-rgw_xml.lo `test -f 'rgw/rgw_xml.cc' || echo '$(srcdir)/'`rgw/rgw_xml.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_xml.Tpo rgw/$(DEPDIR)/librgw_la-rgw_xml.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_xml.cc' object='rgw/librgw_la-rgw_xml.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_xml.lo `test -f 'rgw/rgw_xml.cc' || echo '$(srcdir)/'`rgw/rgw_xml.cc rgw/librgw_la-rgw_usage.lo: rgw/rgw_usage.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_usage.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_usage.Tpo -c -o rgw/librgw_la-rgw_usage.lo `test -f 'rgw/rgw_usage.cc' || echo '$(srcdir)/'`rgw/rgw_usage.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_usage.Tpo rgw/$(DEPDIR)/librgw_la-rgw_usage.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_usage.cc' object='rgw/librgw_la-rgw_usage.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_usage.lo `test -f 'rgw/rgw_usage.cc' || echo '$(srcdir)/'`rgw/rgw_usage.cc rgw/librgw_la-rgw_json_enc.lo: rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_json_enc.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_json_enc.Tpo -c -o rgw/librgw_la-rgw_json_enc.lo `test -f 'rgw/rgw_json_enc.cc' || echo '$(srcdir)/'`rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_json_enc.Tpo rgw/$(DEPDIR)/librgw_la-rgw_json_enc.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_json_enc.cc' object='rgw/librgw_la-rgw_json_enc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_json_enc.lo `test -f 'rgw/rgw_json_enc.cc' || echo '$(srcdir)/'`rgw/rgw_json_enc.cc rgw/librgw_la-rgw_user.lo: rgw/rgw_user.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_user.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_user.Tpo -c -o rgw/librgw_la-rgw_user.lo `test -f 'rgw/rgw_user.cc' || echo '$(srcdir)/'`rgw/rgw_user.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_user.Tpo rgw/$(DEPDIR)/librgw_la-rgw_user.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_user.cc' object='rgw/librgw_la-rgw_user.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_user.lo `test -f 'rgw/rgw_user.cc' || echo '$(srcdir)/'`rgw/rgw_user.cc rgw/librgw_la-rgw_bucket.lo: rgw/rgw_bucket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_bucket.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_bucket.Tpo -c -o rgw/librgw_la-rgw_bucket.lo `test -f 'rgw/rgw_bucket.cc' || echo '$(srcdir)/'`rgw/rgw_bucket.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_bucket.Tpo rgw/$(DEPDIR)/librgw_la-rgw_bucket.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_bucket.cc' object='rgw/librgw_la-rgw_bucket.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_bucket.lo `test -f 'rgw/rgw_bucket.cc' || echo '$(srcdir)/'`rgw/rgw_bucket.cc rgw/librgw_la-rgw_tools.lo: rgw/rgw_tools.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_tools.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_tools.Tpo -c -o rgw/librgw_la-rgw_tools.lo `test -f 'rgw/rgw_tools.cc' || echo '$(srcdir)/'`rgw/rgw_tools.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_tools.Tpo rgw/$(DEPDIR)/librgw_la-rgw_tools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_tools.cc' object='rgw/librgw_la-rgw_tools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_tools.lo `test -f 'rgw/rgw_tools.cc' || echo '$(srcdir)/'`rgw/rgw_tools.cc rgw/librgw_la-rgw_rados.lo: rgw/rgw_rados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_rados.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_rados.Tpo -c -o rgw/librgw_la-rgw_rados.lo `test -f 'rgw/rgw_rados.cc' || echo '$(srcdir)/'`rgw/rgw_rados.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_rados.Tpo rgw/$(DEPDIR)/librgw_la-rgw_rados.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rados.cc' object='rgw/librgw_la-rgw_rados.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_rados.lo `test -f 'rgw/rgw_rados.cc' || echo '$(srcdir)/'`rgw/rgw_rados.cc rgw/librgw_la-rgw_http_client.lo: rgw/rgw_http_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_http_client.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_http_client.Tpo -c -o rgw/librgw_la-rgw_http_client.lo `test -f 'rgw/rgw_http_client.cc' || echo '$(srcdir)/'`rgw/rgw_http_client.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_http_client.Tpo rgw/$(DEPDIR)/librgw_la-rgw_http_client.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_http_client.cc' object='rgw/librgw_la-rgw_http_client.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_http_client.lo `test -f 'rgw/rgw_http_client.cc' || echo '$(srcdir)/'`rgw/rgw_http_client.cc rgw/librgw_la-rgw_rest_client.lo: rgw/rgw_rest_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_rest_client.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_rest_client.Tpo -c -o rgw/librgw_la-rgw_rest_client.lo `test -f 'rgw/rgw_rest_client.cc' || echo '$(srcdir)/'`rgw/rgw_rest_client.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_rest_client.Tpo rgw/$(DEPDIR)/librgw_la-rgw_rest_client.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rest_client.cc' object='rgw/librgw_la-rgw_rest_client.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_rest_client.lo `test -f 'rgw/rgw_rest_client.cc' || echo '$(srcdir)/'`rgw/rgw_rest_client.cc rgw/librgw_la-rgw_rest_conn.lo: rgw/rgw_rest_conn.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_rest_conn.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_rest_conn.Tpo -c -o rgw/librgw_la-rgw_rest_conn.lo `test -f 'rgw/rgw_rest_conn.cc' || echo '$(srcdir)/'`rgw/rgw_rest_conn.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_rest_conn.Tpo rgw/$(DEPDIR)/librgw_la-rgw_rest_conn.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rest_conn.cc' object='rgw/librgw_la-rgw_rest_conn.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_rest_conn.lo `test -f 'rgw/rgw_rest_conn.cc' || echo '$(srcdir)/'`rgw/rgw_rest_conn.cc rgw/librgw_la-rgw_op.lo: rgw/rgw_op.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_op.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_op.Tpo -c -o rgw/librgw_la-rgw_op.lo `test -f 'rgw/rgw_op.cc' || echo '$(srcdir)/'`rgw/rgw_op.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_op.Tpo rgw/$(DEPDIR)/librgw_la-rgw_op.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_op.cc' object='rgw/librgw_la-rgw_op.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_op.lo `test -f 'rgw/rgw_op.cc' || echo '$(srcdir)/'`rgw/rgw_op.cc rgw/librgw_la-rgw_common.lo: rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_common.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_common.Tpo -c -o rgw/librgw_la-rgw_common.lo `test -f 'rgw/rgw_common.cc' || echo '$(srcdir)/'`rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_common.Tpo rgw/$(DEPDIR)/librgw_la-rgw_common.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_common.cc' object='rgw/librgw_la-rgw_common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_common.lo `test -f 'rgw/rgw_common.cc' || echo '$(srcdir)/'`rgw/rgw_common.cc rgw/librgw_la-rgw_cache.lo: rgw/rgw_cache.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_cache.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_cache.Tpo -c -o rgw/librgw_la-rgw_cache.lo `test -f 'rgw/rgw_cache.cc' || echo '$(srcdir)/'`rgw/rgw_cache.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_cache.Tpo rgw/$(DEPDIR)/librgw_la-rgw_cache.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cache.cc' object='rgw/librgw_la-rgw_cache.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_cache.lo `test -f 'rgw/rgw_cache.cc' || echo '$(srcdir)/'`rgw/rgw_cache.cc rgw/librgw_la-rgw_formats.lo: rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_formats.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_formats.Tpo -c -o rgw/librgw_la-rgw_formats.lo `test -f 'rgw/rgw_formats.cc' || echo '$(srcdir)/'`rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_formats.Tpo rgw/$(DEPDIR)/librgw_la-rgw_formats.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_formats.cc' object='rgw/librgw_la-rgw_formats.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_formats.lo `test -f 'rgw/rgw_formats.cc' || echo '$(srcdir)/'`rgw/rgw_formats.cc rgw/librgw_la-rgw_log.lo: rgw/rgw_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_log.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_log.Tpo -c -o rgw/librgw_la-rgw_log.lo `test -f 'rgw/rgw_log.cc' || echo '$(srcdir)/'`rgw/rgw_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_log.Tpo rgw/$(DEPDIR)/librgw_la-rgw_log.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_log.cc' object='rgw/librgw_la-rgw_log.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_log.lo `test -f 'rgw/rgw_log.cc' || echo '$(srcdir)/'`rgw/rgw_log.cc rgw/librgw_la-rgw_multi.lo: rgw/rgw_multi.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_multi.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_multi.Tpo -c -o rgw/librgw_la-rgw_multi.lo `test -f 'rgw/rgw_multi.cc' || echo '$(srcdir)/'`rgw/rgw_multi.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_multi.Tpo rgw/$(DEPDIR)/librgw_la-rgw_multi.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_multi.cc' object='rgw/librgw_la-rgw_multi.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_multi.lo `test -f 'rgw/rgw_multi.cc' || echo '$(srcdir)/'`rgw/rgw_multi.cc rgw/librgw_la-rgw_policy_s3.lo: rgw/rgw_policy_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_policy_s3.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_policy_s3.Tpo -c -o rgw/librgw_la-rgw_policy_s3.lo `test -f 'rgw/rgw_policy_s3.cc' || echo '$(srcdir)/'`rgw/rgw_policy_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_policy_s3.Tpo rgw/$(DEPDIR)/librgw_la-rgw_policy_s3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_policy_s3.cc' object='rgw/librgw_la-rgw_policy_s3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_policy_s3.lo `test -f 'rgw/rgw_policy_s3.cc' || echo '$(srcdir)/'`rgw/rgw_policy_s3.cc rgw/librgw_la-rgw_gc.lo: rgw/rgw_gc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_gc.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_gc.Tpo -c -o rgw/librgw_la-rgw_gc.lo `test -f 'rgw/rgw_gc.cc' || echo '$(srcdir)/'`rgw/rgw_gc.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_gc.Tpo rgw/$(DEPDIR)/librgw_la-rgw_gc.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_gc.cc' object='rgw/librgw_la-rgw_gc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_gc.lo `test -f 'rgw/rgw_gc.cc' || echo '$(srcdir)/'`rgw/rgw_gc.cc rgw/librgw_la-rgw_multi_del.lo: rgw/rgw_multi_del.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_multi_del.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_multi_del.Tpo -c -o rgw/librgw_la-rgw_multi_del.lo `test -f 'rgw/rgw_multi_del.cc' || echo '$(srcdir)/'`rgw/rgw_multi_del.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_multi_del.Tpo rgw/$(DEPDIR)/librgw_la-rgw_multi_del.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_multi_del.cc' object='rgw/librgw_la-rgw_multi_del.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_multi_del.lo `test -f 'rgw/rgw_multi_del.cc' || echo '$(srcdir)/'`rgw/rgw_multi_del.cc rgw/librgw_la-rgw_env.lo: rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_env.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_env.Tpo -c -o rgw/librgw_la-rgw_env.lo `test -f 'rgw/rgw_env.cc' || echo '$(srcdir)/'`rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_env.Tpo rgw/$(DEPDIR)/librgw_la-rgw_env.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_env.cc' object='rgw/librgw_la-rgw_env.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_env.lo `test -f 'rgw/rgw_env.cc' || echo '$(srcdir)/'`rgw/rgw_env.cc rgw/librgw_la-rgw_cors.lo: rgw/rgw_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_cors.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_cors.Tpo -c -o rgw/librgw_la-rgw_cors.lo `test -f 'rgw/rgw_cors.cc' || echo '$(srcdir)/'`rgw/rgw_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_cors.Tpo rgw/$(DEPDIR)/librgw_la-rgw_cors.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cors.cc' object='rgw/librgw_la-rgw_cors.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_cors.lo `test -f 'rgw/rgw_cors.cc' || echo '$(srcdir)/'`rgw/rgw_cors.cc rgw/librgw_la-rgw_cors_s3.lo: rgw/rgw_cors_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_cors_s3.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_cors_s3.Tpo -c -o rgw/librgw_la-rgw_cors_s3.lo `test -f 'rgw/rgw_cors_s3.cc' || echo '$(srcdir)/'`rgw/rgw_cors_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_cors_s3.Tpo rgw/$(DEPDIR)/librgw_la-rgw_cors_s3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cors_s3.cc' object='rgw/librgw_la-rgw_cors_s3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_cors_s3.lo `test -f 'rgw/rgw_cors_s3.cc' || echo '$(srcdir)/'`rgw/rgw_cors_s3.cc rgw/librgw_la-rgw_auth_s3.lo: rgw/rgw_auth_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_auth_s3.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_auth_s3.Tpo -c -o rgw/librgw_la-rgw_auth_s3.lo `test -f 'rgw/rgw_auth_s3.cc' || echo '$(srcdir)/'`rgw/rgw_auth_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_auth_s3.Tpo rgw/$(DEPDIR)/librgw_la-rgw_auth_s3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_auth_s3.cc' object='rgw/librgw_la-rgw_auth_s3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_auth_s3.lo `test -f 'rgw/rgw_auth_s3.cc' || echo '$(srcdir)/'`rgw/rgw_auth_s3.cc rgw/librgw_la-rgw_metadata.lo: rgw/rgw_metadata.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_metadata.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_metadata.Tpo -c -o rgw/librgw_la-rgw_metadata.lo `test -f 'rgw/rgw_metadata.cc' || echo '$(srcdir)/'`rgw/rgw_metadata.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_metadata.Tpo rgw/$(DEPDIR)/librgw_la-rgw_metadata.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_metadata.cc' object='rgw/librgw_la-rgw_metadata.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_metadata.lo `test -f 'rgw/rgw_metadata.cc' || echo '$(srcdir)/'`rgw/rgw_metadata.cc rgw/librgw_la-rgw_replica_log.lo: rgw/rgw_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_replica_log.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_replica_log.Tpo -c -o rgw/librgw_la-rgw_replica_log.lo `test -f 'rgw/rgw_replica_log.cc' || echo '$(srcdir)/'`rgw/rgw_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_replica_log.Tpo rgw/$(DEPDIR)/librgw_la-rgw_replica_log.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_replica_log.cc' object='rgw/librgw_la-rgw_replica_log.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_replica_log.lo `test -f 'rgw/rgw_replica_log.cc' || echo '$(srcdir)/'`rgw/rgw_replica_log.cc rgw/librgw_la-rgw_keystone.lo: rgw/rgw_keystone.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_keystone.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_keystone.Tpo -c -o rgw/librgw_la-rgw_keystone.lo `test -f 'rgw/rgw_keystone.cc' || echo '$(srcdir)/'`rgw/rgw_keystone.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_keystone.Tpo rgw/$(DEPDIR)/librgw_la-rgw_keystone.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_keystone.cc' object='rgw/librgw_la-rgw_keystone.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_keystone.lo `test -f 'rgw/rgw_keystone.cc' || echo '$(srcdir)/'`rgw/rgw_keystone.cc rgw/librgw_la-rgw_quota.lo: rgw/rgw_quota.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_quota.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_quota.Tpo -c -o rgw/librgw_la-rgw_quota.lo `test -f 'rgw/rgw_quota.cc' || echo '$(srcdir)/'`rgw/rgw_quota.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_quota.Tpo rgw/$(DEPDIR)/librgw_la-rgw_quota.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_quota.cc' object='rgw/librgw_la-rgw_quota.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_quota.lo `test -f 'rgw/rgw_quota.cc' || echo '$(srcdir)/'`rgw/rgw_quota.cc rgw/librgw_la-rgw_dencoder.lo: rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -MT rgw/librgw_la-rgw_dencoder.lo -MD -MP -MF rgw/$(DEPDIR)/librgw_la-rgw_dencoder.Tpo -c -o rgw/librgw_la-rgw_dencoder.lo `test -f 'rgw/rgw_dencoder.cc' || echo '$(srcdir)/'`rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/librgw_la-rgw_dencoder.Tpo rgw/$(DEPDIR)/librgw_la-rgw_dencoder.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_dencoder.cc' object='rgw/librgw_la-rgw_dencoder.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librgw_la_CXXFLAGS) $(CXXFLAGS) -c -o rgw/librgw_la-rgw_dencoder.lo `test -f 'rgw/rgw_dencoder.cc' || echo '$(srcdir)/'`rgw/rgw_dencoder.cc test/encoding/ceph_dencoder-ceph_dencoder.o: test/encoding/ceph_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT test/encoding/ceph_dencoder-ceph_dencoder.o -MD -MP -MF test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Tpo -c -o test/encoding/ceph_dencoder-ceph_dencoder.o `test -f 'test/encoding/ceph_dencoder.cc' || echo '$(srcdir)/'`test/encoding/ceph_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Tpo test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/encoding/ceph_dencoder.cc' object='test/encoding/ceph_dencoder-ceph_dencoder.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o test/encoding/ceph_dencoder-ceph_dencoder.o `test -f 'test/encoding/ceph_dencoder.cc' || echo '$(srcdir)/'`test/encoding/ceph_dencoder.cc test/encoding/ceph_dencoder-ceph_dencoder.obj: test/encoding/ceph_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT test/encoding/ceph_dencoder-ceph_dencoder.obj -MD -MP -MF test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Tpo -c -o test/encoding/ceph_dencoder-ceph_dencoder.obj `if test -f 'test/encoding/ceph_dencoder.cc'; then $(CYGPATH_W) 'test/encoding/ceph_dencoder.cc'; else $(CYGPATH_W) '$(srcdir)/test/encoding/ceph_dencoder.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Tpo test/encoding/$(DEPDIR)/ceph_dencoder-ceph_dencoder.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/encoding/ceph_dencoder.cc' object='test/encoding/ceph_dencoder-ceph_dencoder.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o test/encoding/ceph_dencoder-ceph_dencoder.obj `if test -f 'test/encoding/ceph_dencoder.cc'; then $(CYGPATH_W) 'test/encoding/ceph_dencoder.cc'; else $(CYGPATH_W) '$(srcdir)/test/encoding/ceph_dencoder.cc'; fi` rgw/ceph_dencoder-rgw_dencoder.o: rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_dencoder.o -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Tpo -c -o rgw/ceph_dencoder-rgw_dencoder.o `test -f 'rgw/rgw_dencoder.cc' || echo '$(srcdir)/'`rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_dencoder.cc' object='rgw/ceph_dencoder-rgw_dencoder.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_dencoder.o `test -f 'rgw/rgw_dencoder.cc' || echo '$(srcdir)/'`rgw/rgw_dencoder.cc rgw/ceph_dencoder-rgw_dencoder.obj: rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_dencoder.obj -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Tpo -c -o rgw/ceph_dencoder-rgw_dencoder.obj `if test -f 'rgw/rgw_dencoder.cc'; then $(CYGPATH_W) 'rgw/rgw_dencoder.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_dencoder.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_dencoder.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_dencoder.cc' object='rgw/ceph_dencoder-rgw_dencoder.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_dencoder.obj `if test -f 'rgw/rgw_dencoder.cc'; then $(CYGPATH_W) 'rgw/rgw_dencoder.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_dencoder.cc'; fi` rgw/ceph_dencoder-rgw_acl.o: rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_acl.o -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Tpo -c -o rgw/ceph_dencoder-rgw_acl.o `test -f 'rgw/rgw_acl.cc' || echo '$(srcdir)/'`rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl.cc' object='rgw/ceph_dencoder-rgw_acl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_acl.o `test -f 'rgw/rgw_acl.cc' || echo '$(srcdir)/'`rgw/rgw_acl.cc rgw/ceph_dencoder-rgw_acl.obj: rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_acl.obj -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Tpo -c -o rgw/ceph_dencoder-rgw_acl.obj `if test -f 'rgw/rgw_acl.cc'; then $(CYGPATH_W) 'rgw/rgw_acl.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_acl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl.cc' object='rgw/ceph_dencoder-rgw_acl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_acl.obj `if test -f 'rgw/rgw_acl.cc'; then $(CYGPATH_W) 'rgw/rgw_acl.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl.cc'; fi` rgw/ceph_dencoder-rgw_common.o: rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_common.o -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Tpo -c -o rgw/ceph_dencoder-rgw_common.o `test -f 'rgw/rgw_common.cc' || echo '$(srcdir)/'`rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_common.cc' object='rgw/ceph_dencoder-rgw_common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_common.o `test -f 'rgw/rgw_common.cc' || echo '$(srcdir)/'`rgw/rgw_common.cc rgw/ceph_dencoder-rgw_common.obj: rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_common.obj -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Tpo -c -o rgw/ceph_dencoder-rgw_common.obj `if test -f 'rgw/rgw_common.cc'; then $(CYGPATH_W) 'rgw/rgw_common.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_common.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_common.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_common.cc' object='rgw/ceph_dencoder-rgw_common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_common.obj `if test -f 'rgw/rgw_common.cc'; then $(CYGPATH_W) 'rgw/rgw_common.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_common.cc'; fi` rgw/ceph_dencoder-rgw_env.o: rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_env.o -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Tpo -c -o rgw/ceph_dencoder-rgw_env.o `test -f 'rgw/rgw_env.cc' || echo '$(srcdir)/'`rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_env.cc' object='rgw/ceph_dencoder-rgw_env.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_env.o `test -f 'rgw/rgw_env.cc' || echo '$(srcdir)/'`rgw/rgw_env.cc rgw/ceph_dencoder-rgw_env.obj: rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_env.obj -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Tpo -c -o rgw/ceph_dencoder-rgw_env.obj `if test -f 'rgw/rgw_env.cc'; then $(CYGPATH_W) 'rgw/rgw_env.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_env.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_env.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_env.cc' object='rgw/ceph_dencoder-rgw_env.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_env.obj `if test -f 'rgw/rgw_env.cc'; then $(CYGPATH_W) 'rgw/rgw_env.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_env.cc'; fi` rgw/ceph_dencoder-rgw_json_enc.o: rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_json_enc.o -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Tpo -c -o rgw/ceph_dencoder-rgw_json_enc.o `test -f 'rgw/rgw_json_enc.cc' || echo '$(srcdir)/'`rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_json_enc.cc' object='rgw/ceph_dencoder-rgw_json_enc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_json_enc.o `test -f 'rgw/rgw_json_enc.cc' || echo '$(srcdir)/'`rgw/rgw_json_enc.cc rgw/ceph_dencoder-rgw_json_enc.obj: rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -MT rgw/ceph_dencoder-rgw_json_enc.obj -MD -MP -MF rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Tpo -c -o rgw/ceph_dencoder-rgw_json_enc.obj `if test -f 'rgw/rgw_json_enc.cc'; then $(CYGPATH_W) 'rgw/rgw_json_enc.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_json_enc.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Tpo rgw/$(DEPDIR)/ceph_dencoder-rgw_json_enc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_json_enc.cc' object='rgw/ceph_dencoder-rgw_json_enc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_dencoder_CXXFLAGS) $(CXXFLAGS) -c -o rgw/ceph_dencoder-rgw_json_enc.obj `if test -f 'rgw/rgw_json_enc.cc'; then $(CYGPATH_W) 'rgw/rgw_json_enc.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_json_enc.cc'; fi` tools/ceph_kvstore_tool-ceph_kvstore_tool.o: tools/ceph_kvstore_tool.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_kvstore_tool_CXXFLAGS) $(CXXFLAGS) -MT tools/ceph_kvstore_tool-ceph_kvstore_tool.o -MD -MP -MF tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Tpo -c -o tools/ceph_kvstore_tool-ceph_kvstore_tool.o `test -f 'tools/ceph_kvstore_tool.cc' || echo '$(srcdir)/'`tools/ceph_kvstore_tool.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Tpo tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tools/ceph_kvstore_tool.cc' object='tools/ceph_kvstore_tool-ceph_kvstore_tool.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_kvstore_tool_CXXFLAGS) $(CXXFLAGS) -c -o tools/ceph_kvstore_tool-ceph_kvstore_tool.o `test -f 'tools/ceph_kvstore_tool.cc' || echo '$(srcdir)/'`tools/ceph_kvstore_tool.cc tools/ceph_kvstore_tool-ceph_kvstore_tool.obj: tools/ceph_kvstore_tool.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_kvstore_tool_CXXFLAGS) $(CXXFLAGS) -MT tools/ceph_kvstore_tool-ceph_kvstore_tool.obj -MD -MP -MF tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Tpo -c -o tools/ceph_kvstore_tool-ceph_kvstore_tool.obj `if test -f 'tools/ceph_kvstore_tool.cc'; then $(CYGPATH_W) 'tools/ceph_kvstore_tool.cc'; else $(CYGPATH_W) '$(srcdir)/tools/ceph_kvstore_tool.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Tpo tools/$(DEPDIR)/ceph_kvstore_tool-ceph_kvstore_tool.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tools/ceph_kvstore_tool.cc' object='tools/ceph_kvstore_tool-ceph_kvstore_tool.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_kvstore_tool_CXXFLAGS) $(CXXFLAGS) -c -o tools/ceph_kvstore_tool-ceph_kvstore_tool.obj `if test -f 'tools/ceph_kvstore_tool.cc'; then $(CYGPATH_W) 'tools/ceph_kvstore_tool.cc'; else $(CYGPATH_W) '$(srcdir)/tools/ceph_kvstore_tool.cc'; fi` test/cls_hello/ceph_test_cls_hello-test_cls_hello.o: test/cls_hello/test_cls_hello.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_hello_CXXFLAGS) $(CXXFLAGS) -MT test/cls_hello/ceph_test_cls_hello-test_cls_hello.o -MD -MP -MF test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Tpo -c -o test/cls_hello/ceph_test_cls_hello-test_cls_hello.o `test -f 'test/cls_hello/test_cls_hello.cc' || echo '$(srcdir)/'`test/cls_hello/test_cls_hello.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Tpo test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_hello/test_cls_hello.cc' object='test/cls_hello/ceph_test_cls_hello-test_cls_hello.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_hello_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_hello/ceph_test_cls_hello-test_cls_hello.o `test -f 'test/cls_hello/test_cls_hello.cc' || echo '$(srcdir)/'`test/cls_hello/test_cls_hello.cc test/cls_hello/ceph_test_cls_hello-test_cls_hello.obj: test/cls_hello/test_cls_hello.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_hello_CXXFLAGS) $(CXXFLAGS) -MT test/cls_hello/ceph_test_cls_hello-test_cls_hello.obj -MD -MP -MF test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Tpo -c -o test/cls_hello/ceph_test_cls_hello-test_cls_hello.obj `if test -f 'test/cls_hello/test_cls_hello.cc'; then $(CYGPATH_W) 'test/cls_hello/test_cls_hello.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_hello/test_cls_hello.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Tpo test/cls_hello/$(DEPDIR)/ceph_test_cls_hello-test_cls_hello.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_hello/test_cls_hello.cc' object='test/cls_hello/ceph_test_cls_hello-test_cls_hello.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_hello_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_hello/ceph_test_cls_hello-test_cls_hello.obj `if test -f 'test/cls_hello/test_cls_hello.cc'; then $(CYGPATH_W) 'test/cls_hello/test_cls_hello.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_hello/test_cls_hello.cc'; fi` test/cls_lock/ceph_test_cls_lock-test_cls_lock.o: test/cls_lock/test_cls_lock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_lock_CXXFLAGS) $(CXXFLAGS) -MT test/cls_lock/ceph_test_cls_lock-test_cls_lock.o -MD -MP -MF test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Tpo -c -o test/cls_lock/ceph_test_cls_lock-test_cls_lock.o `test -f 'test/cls_lock/test_cls_lock.cc' || echo '$(srcdir)/'`test/cls_lock/test_cls_lock.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Tpo test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_lock/test_cls_lock.cc' object='test/cls_lock/ceph_test_cls_lock-test_cls_lock.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_lock_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_lock/ceph_test_cls_lock-test_cls_lock.o `test -f 'test/cls_lock/test_cls_lock.cc' || echo '$(srcdir)/'`test/cls_lock/test_cls_lock.cc test/cls_lock/ceph_test_cls_lock-test_cls_lock.obj: test/cls_lock/test_cls_lock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_lock_CXXFLAGS) $(CXXFLAGS) -MT test/cls_lock/ceph_test_cls_lock-test_cls_lock.obj -MD -MP -MF test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Tpo -c -o test/cls_lock/ceph_test_cls_lock-test_cls_lock.obj `if test -f 'test/cls_lock/test_cls_lock.cc'; then $(CYGPATH_W) 'test/cls_lock/test_cls_lock.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_lock/test_cls_lock.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Tpo test/cls_lock/$(DEPDIR)/ceph_test_cls_lock-test_cls_lock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_lock/test_cls_lock.cc' object='test/cls_lock/ceph_test_cls_lock-test_cls_lock.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_lock_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_lock/ceph_test_cls_lock-test_cls_lock.obj `if test -f 'test/cls_lock/test_cls_lock.cc'; then $(CYGPATH_W) 'test/cls_lock/test_cls_lock.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_lock/test_cls_lock.cc'; fi` test/cls_log/ceph_test_cls_log-test_cls_log.o: test/cls_log/test_cls_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_log_CXXFLAGS) $(CXXFLAGS) -MT test/cls_log/ceph_test_cls_log-test_cls_log.o -MD -MP -MF test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Tpo -c -o test/cls_log/ceph_test_cls_log-test_cls_log.o `test -f 'test/cls_log/test_cls_log.cc' || echo '$(srcdir)/'`test/cls_log/test_cls_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Tpo test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_log/test_cls_log.cc' object='test/cls_log/ceph_test_cls_log-test_cls_log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_log_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_log/ceph_test_cls_log-test_cls_log.o `test -f 'test/cls_log/test_cls_log.cc' || echo '$(srcdir)/'`test/cls_log/test_cls_log.cc test/cls_log/ceph_test_cls_log-test_cls_log.obj: test/cls_log/test_cls_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_log_CXXFLAGS) $(CXXFLAGS) -MT test/cls_log/ceph_test_cls_log-test_cls_log.obj -MD -MP -MF test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Tpo -c -o test/cls_log/ceph_test_cls_log-test_cls_log.obj `if test -f 'test/cls_log/test_cls_log.cc'; then $(CYGPATH_W) 'test/cls_log/test_cls_log.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_log/test_cls_log.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Tpo test/cls_log/$(DEPDIR)/ceph_test_cls_log-test_cls_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_log/test_cls_log.cc' object='test/cls_log/ceph_test_cls_log-test_cls_log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_log_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_log/ceph_test_cls_log-test_cls_log.obj `if test -f 'test/cls_log/test_cls_log.cc'; then $(CYGPATH_W) 'test/cls_log/test_cls_log.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_log/test_cls_log.cc'; fi` test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.o: test/cls_rbd/test_cls_rbd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rbd_CXXFLAGS) $(CXXFLAGS) -MT test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.o -MD -MP -MF test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Tpo -c -o test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.o `test -f 'test/cls_rbd/test_cls_rbd.cc' || echo '$(srcdir)/'`test/cls_rbd/test_cls_rbd.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Tpo test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_rbd/test_cls_rbd.cc' object='test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rbd_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.o `test -f 'test/cls_rbd/test_cls_rbd.cc' || echo '$(srcdir)/'`test/cls_rbd/test_cls_rbd.cc test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.obj: test/cls_rbd/test_cls_rbd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rbd_CXXFLAGS) $(CXXFLAGS) -MT test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.obj -MD -MP -MF test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Tpo -c -o test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.obj `if test -f 'test/cls_rbd/test_cls_rbd.cc'; then $(CYGPATH_W) 'test/cls_rbd/test_cls_rbd.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_rbd/test_cls_rbd.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Tpo test/cls_rbd/$(DEPDIR)/ceph_test_cls_rbd-test_cls_rbd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_rbd/test_cls_rbd.cc' object='test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rbd_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_rbd/ceph_test_cls_rbd-test_cls_rbd.obj `if test -f 'test/cls_rbd/test_cls_rbd.cc'; then $(CYGPATH_W) 'test/cls_rbd/test_cls_rbd.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_rbd/test_cls_rbd.cc'; fi` test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.o: test/cls_refcount/test_cls_refcount.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_refcount_CXXFLAGS) $(CXXFLAGS) -MT test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.o -MD -MP -MF test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Tpo -c -o test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.o `test -f 'test/cls_refcount/test_cls_refcount.cc' || echo '$(srcdir)/'`test/cls_refcount/test_cls_refcount.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Tpo test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_refcount/test_cls_refcount.cc' object='test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_refcount_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.o `test -f 'test/cls_refcount/test_cls_refcount.cc' || echo '$(srcdir)/'`test/cls_refcount/test_cls_refcount.cc test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.obj: test/cls_refcount/test_cls_refcount.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_refcount_CXXFLAGS) $(CXXFLAGS) -MT test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.obj -MD -MP -MF test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Tpo -c -o test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.obj `if test -f 'test/cls_refcount/test_cls_refcount.cc'; then $(CYGPATH_W) 'test/cls_refcount/test_cls_refcount.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_refcount/test_cls_refcount.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Tpo test/cls_refcount/$(DEPDIR)/ceph_test_cls_refcount-test_cls_refcount.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_refcount/test_cls_refcount.cc' object='test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_refcount_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_refcount/ceph_test_cls_refcount-test_cls_refcount.obj `if test -f 'test/cls_refcount/test_cls_refcount.cc'; then $(CYGPATH_W) 'test/cls_refcount/test_cls_refcount.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_refcount/test_cls_refcount.cc'; fi` test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.o: test/cls_replica_log/test_cls_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_replica_log_CXXFLAGS) $(CXXFLAGS) -MT test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.o -MD -MP -MF test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Tpo -c -o test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.o `test -f 'test/cls_replica_log/test_cls_replica_log.cc' || echo '$(srcdir)/'`test/cls_replica_log/test_cls_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Tpo test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_replica_log/test_cls_replica_log.cc' object='test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_replica_log_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.o `test -f 'test/cls_replica_log/test_cls_replica_log.cc' || echo '$(srcdir)/'`test/cls_replica_log/test_cls_replica_log.cc test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.obj: test/cls_replica_log/test_cls_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_replica_log_CXXFLAGS) $(CXXFLAGS) -MT test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.obj -MD -MP -MF test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Tpo -c -o test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.obj `if test -f 'test/cls_replica_log/test_cls_replica_log.cc'; then $(CYGPATH_W) 'test/cls_replica_log/test_cls_replica_log.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_replica_log/test_cls_replica_log.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Tpo test/cls_replica_log/$(DEPDIR)/ceph_test_cls_replica_log-test_cls_replica_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_replica_log/test_cls_replica_log.cc' object='test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_replica_log_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_replica_log/ceph_test_cls_replica_log-test_cls_replica_log.obj `if test -f 'test/cls_replica_log/test_cls_replica_log.cc'; then $(CYGPATH_W) 'test/cls_replica_log/test_cls_replica_log.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_replica_log/test_cls_replica_log.cc'; fi` test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.o: test/cls_rgw/test_cls_rgw.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_CXXFLAGS) $(CXXFLAGS) -MT test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.o -MD -MP -MF test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Tpo -c -o test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.o `test -f 'test/cls_rgw/test_cls_rgw.cc' || echo '$(srcdir)/'`test/cls_rgw/test_cls_rgw.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Tpo test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_rgw/test_cls_rgw.cc' object='test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.o `test -f 'test/cls_rgw/test_cls_rgw.cc' || echo '$(srcdir)/'`test/cls_rgw/test_cls_rgw.cc test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.obj: test/cls_rgw/test_cls_rgw.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_CXXFLAGS) $(CXXFLAGS) -MT test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.obj -MD -MP -MF test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Tpo -c -o test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.obj `if test -f 'test/cls_rgw/test_cls_rgw.cc'; then $(CYGPATH_W) 'test/cls_rgw/test_cls_rgw.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_rgw/test_cls_rgw.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Tpo test/cls_rgw/$(DEPDIR)/ceph_test_cls_rgw-test_cls_rgw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_rgw/test_cls_rgw.cc' object='test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_rgw/ceph_test_cls_rgw-test_cls_rgw.obj `if test -f 'test/cls_rgw/test_cls_rgw.cc'; then $(CYGPATH_W) 'test/cls_rgw/test_cls_rgw.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_rgw/test_cls_rgw.cc'; fi` test/ceph_test_cls_rgw_log-test_rgw_admin_log.o: test/test_rgw_admin_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_log_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cls_rgw_log-test_rgw_admin_log.o -MD -MP -MF test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Tpo -c -o test/ceph_test_cls_rgw_log-test_rgw_admin_log.o `test -f 'test/test_rgw_admin_log.cc' || echo '$(srcdir)/'`test/test_rgw_admin_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Tpo test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_rgw_admin_log.cc' object='test/ceph_test_cls_rgw_log-test_rgw_admin_log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_log_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cls_rgw_log-test_rgw_admin_log.o `test -f 'test/test_rgw_admin_log.cc' || echo '$(srcdir)/'`test/test_rgw_admin_log.cc test/ceph_test_cls_rgw_log-test_rgw_admin_log.obj: test/test_rgw_admin_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_log_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cls_rgw_log-test_rgw_admin_log.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Tpo -c -o test/ceph_test_cls_rgw_log-test_rgw_admin_log.obj `if test -f 'test/test_rgw_admin_log.cc'; then $(CYGPATH_W) 'test/test_rgw_admin_log.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_rgw_admin_log.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Tpo test/$(DEPDIR)/ceph_test_cls_rgw_log-test_rgw_admin_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_rgw_admin_log.cc' object='test/ceph_test_cls_rgw_log-test_rgw_admin_log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_log_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cls_rgw_log-test_rgw_admin_log.obj `if test -f 'test/test_rgw_admin_log.cc'; then $(CYGPATH_W) 'test/test_rgw_admin_log.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_rgw_admin_log.cc'; fi` test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.o: test/test_rgw_admin_meta.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_meta_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.o -MD -MP -MF test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Tpo -c -o test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.o `test -f 'test/test_rgw_admin_meta.cc' || echo '$(srcdir)/'`test/test_rgw_admin_meta.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Tpo test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_rgw_admin_meta.cc' object='test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_meta_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.o `test -f 'test/test_rgw_admin_meta.cc' || echo '$(srcdir)/'`test/test_rgw_admin_meta.cc test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.obj: test/test_rgw_admin_meta.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_meta_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Tpo -c -o test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.obj `if test -f 'test/test_rgw_admin_meta.cc'; then $(CYGPATH_W) 'test/test_rgw_admin_meta.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_rgw_admin_meta.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Tpo test/$(DEPDIR)/ceph_test_cls_rgw_meta-test_rgw_admin_meta.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_rgw_admin_meta.cc' object='test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_meta_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cls_rgw_meta-test_rgw_admin_meta.obj `if test -f 'test/test_rgw_admin_meta.cc'; then $(CYGPATH_W) 'test/test_rgw_admin_meta.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_rgw_admin_meta.cc'; fi` test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.o: test/test_rgw_admin_opstate.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_opstate_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.o -MD -MP -MF test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Tpo -c -o test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.o `test -f 'test/test_rgw_admin_opstate.cc' || echo '$(srcdir)/'`test/test_rgw_admin_opstate.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Tpo test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_rgw_admin_opstate.cc' object='test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_opstate_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.o `test -f 'test/test_rgw_admin_opstate.cc' || echo '$(srcdir)/'`test/test_rgw_admin_opstate.cc test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.obj: test/test_rgw_admin_opstate.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_opstate_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Tpo -c -o test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.obj `if test -f 'test/test_rgw_admin_opstate.cc'; then $(CYGPATH_W) 'test/test_rgw_admin_opstate.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_rgw_admin_opstate.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Tpo test/$(DEPDIR)/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_rgw_admin_opstate.cc' object='test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_rgw_opstate_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cls_rgw_opstate-test_rgw_admin_opstate.obj `if test -f 'test/test_rgw_admin_opstate.cc'; then $(CYGPATH_W) 'test/test_rgw_admin_opstate.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_rgw_admin_opstate.cc'; fi` test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.o: test/cls_statelog/test_cls_statelog.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_statelog_CXXFLAGS) $(CXXFLAGS) -MT test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.o -MD -MP -MF test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Tpo -c -o test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.o `test -f 'test/cls_statelog/test_cls_statelog.cc' || echo '$(srcdir)/'`test/cls_statelog/test_cls_statelog.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Tpo test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_statelog/test_cls_statelog.cc' object='test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_statelog_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.o `test -f 'test/cls_statelog/test_cls_statelog.cc' || echo '$(srcdir)/'`test/cls_statelog/test_cls_statelog.cc test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.obj: test/cls_statelog/test_cls_statelog.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_statelog_CXXFLAGS) $(CXXFLAGS) -MT test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.obj -MD -MP -MF test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Tpo -c -o test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.obj `if test -f 'test/cls_statelog/test_cls_statelog.cc'; then $(CYGPATH_W) 'test/cls_statelog/test_cls_statelog.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_statelog/test_cls_statelog.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Tpo test/cls_statelog/$(DEPDIR)/ceph_test_cls_statelog-test_cls_statelog.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_statelog/test_cls_statelog.cc' object='test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_statelog_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_statelog/ceph_test_cls_statelog-test_cls_statelog.obj `if test -f 'test/cls_statelog/test_cls_statelog.cc'; then $(CYGPATH_W) 'test/cls_statelog/test_cls_statelog.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_statelog/test_cls_statelog.cc'; fi` test/cls_version/ceph_test_cls_version-test_cls_version.o: test/cls_version/test_cls_version.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_version_CXXFLAGS) $(CXXFLAGS) -MT test/cls_version/ceph_test_cls_version-test_cls_version.o -MD -MP -MF test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Tpo -c -o test/cls_version/ceph_test_cls_version-test_cls_version.o `test -f 'test/cls_version/test_cls_version.cc' || echo '$(srcdir)/'`test/cls_version/test_cls_version.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Tpo test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_version/test_cls_version.cc' object='test/cls_version/ceph_test_cls_version-test_cls_version.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_version_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_version/ceph_test_cls_version-test_cls_version.o `test -f 'test/cls_version/test_cls_version.cc' || echo '$(srcdir)/'`test/cls_version/test_cls_version.cc test/cls_version/ceph_test_cls_version-test_cls_version.obj: test/cls_version/test_cls_version.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_version_CXXFLAGS) $(CXXFLAGS) -MT test/cls_version/ceph_test_cls_version-test_cls_version.obj -MD -MP -MF test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Tpo -c -o test/cls_version/ceph_test_cls_version-test_cls_version.obj `if test -f 'test/cls_version/test_cls_version.cc'; then $(CYGPATH_W) 'test/cls_version/test_cls_version.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_version/test_cls_version.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Tpo test/cls_version/$(DEPDIR)/ceph_test_cls_version-test_cls_version.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/cls_version/test_cls_version.cc' object='test/cls_version/ceph_test_cls_version-test_cls_version.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cls_version_CXXFLAGS) $(CXXFLAGS) -c -o test/cls_version/ceph_test_cls_version-test_cls_version.obj `if test -f 'test/cls_version/test_cls_version.cc'; then $(CYGPATH_W) 'test/cls_version/test_cls_version.cc'; else $(CYGPATH_W) '$(srcdir)/test/cls_version/test_cls_version.cc'; fi` test/ceph_test_cors-test_cors.o: test/test_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cors_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cors-test_cors.o -MD -MP -MF test/$(DEPDIR)/ceph_test_cors-test_cors.Tpo -c -o test/ceph_test_cors-test_cors.o `test -f 'test/test_cors.cc' || echo '$(srcdir)/'`test/test_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cors-test_cors.Tpo test/$(DEPDIR)/ceph_test_cors-test_cors.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_cors.cc' object='test/ceph_test_cors-test_cors.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cors_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cors-test_cors.o `test -f 'test/test_cors.cc' || echo '$(srcdir)/'`test/test_cors.cc test/ceph_test_cors-test_cors.obj: test/test_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cors_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_cors-test_cors.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_cors-test_cors.Tpo -c -o test/ceph_test_cors-test_cors.obj `if test -f 'test/test_cors.cc'; then $(CYGPATH_W) 'test/test_cors.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_cors.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_cors-test_cors.Tpo test/$(DEPDIR)/ceph_test_cors-test_cors.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_cors.cc' object='test/ceph_test_cors-test_cors.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_cors_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_cors-test_cors.obj `if test -f 'test/test_cors.cc'; then $(CYGPATH_W) 'test/test_cors.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_cors.cc'; fi` test/ceph_test_filejournal-test_filejournal.o: test/test_filejournal.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_filejournal_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_filejournal-test_filejournal.o -MD -MP -MF test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Tpo -c -o test/ceph_test_filejournal-test_filejournal.o `test -f 'test/test_filejournal.cc' || echo '$(srcdir)/'`test/test_filejournal.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Tpo test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_filejournal.cc' object='test/ceph_test_filejournal-test_filejournal.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_filejournal_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_filejournal-test_filejournal.o `test -f 'test/test_filejournal.cc' || echo '$(srcdir)/'`test/test_filejournal.cc test/ceph_test_filejournal-test_filejournal.obj: test/test_filejournal.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_filejournal_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_filejournal-test_filejournal.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Tpo -c -o test/ceph_test_filejournal-test_filejournal.obj `if test -f 'test/test_filejournal.cc'; then $(CYGPATH_W) 'test/test_filejournal.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_filejournal.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Tpo test/$(DEPDIR)/ceph_test_filejournal-test_filejournal.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_filejournal.cc' object='test/ceph_test_filejournal-test_filejournal.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_filejournal_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_filejournal-test_filejournal.obj `if test -f 'test/test_filejournal.cc'; then $(CYGPATH_W) 'test/test_filejournal.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_filejournal.cc'; fi` test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.o: test/ObjectMap/test_keyvaluedb_atomicity.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_atomicity_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.o -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Tpo -c -o test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.o `test -f 'test/ObjectMap/test_keyvaluedb_atomicity.cc' || echo '$(srcdir)/'`test/ObjectMap/test_keyvaluedb_atomicity.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/test_keyvaluedb_atomicity.cc' object='test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_atomicity_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.o `test -f 'test/ObjectMap/test_keyvaluedb_atomicity.cc' || echo '$(srcdir)/'`test/ObjectMap/test_keyvaluedb_atomicity.cc test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.obj: test/ObjectMap/test_keyvaluedb_atomicity.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_atomicity_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.obj -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Tpo -c -o test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.obj `if test -f 'test/ObjectMap/test_keyvaluedb_atomicity.cc'; then $(CYGPATH_W) 'test/ObjectMap/test_keyvaluedb_atomicity.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/test_keyvaluedb_atomicity.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/test_keyvaluedb_atomicity.cc' object='test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_atomicity_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_keyvaluedb_atomicity-test_keyvaluedb_atomicity.obj `if test -f 'test/ObjectMap/test_keyvaluedb_atomicity.cc'; then $(CYGPATH_W) 'test/ObjectMap/test_keyvaluedb_atomicity.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/test_keyvaluedb_atomicity.cc'; fi` test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.o: test/ObjectMap/test_keyvaluedb_iterators.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.o -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Tpo -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.o `test -f 'test/ObjectMap/test_keyvaluedb_iterators.cc' || echo '$(srcdir)/'`test/ObjectMap/test_keyvaluedb_iterators.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/test_keyvaluedb_iterators.cc' object='test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.o `test -f 'test/ObjectMap/test_keyvaluedb_iterators.cc' || echo '$(srcdir)/'`test/ObjectMap/test_keyvaluedb_iterators.cc test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.obj: test/ObjectMap/test_keyvaluedb_iterators.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.obj -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Tpo -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.obj `if test -f 'test/ObjectMap/test_keyvaluedb_iterators.cc'; then $(CYGPATH_W) 'test/ObjectMap/test_keyvaluedb_iterators.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/test_keyvaluedb_iterators.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/test_keyvaluedb_iterators.cc' object='test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-test_keyvaluedb_iterators.obj `if test -f 'test/ObjectMap/test_keyvaluedb_iterators.cc'; then $(CYGPATH_W) 'test/ObjectMap/test_keyvaluedb_iterators.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/test_keyvaluedb_iterators.cc'; fi` test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.o: test/ObjectMap/KeyValueDBMemory.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.o -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Tpo -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.o `test -f 'test/ObjectMap/KeyValueDBMemory.cc' || echo '$(srcdir)/'`test/ObjectMap/KeyValueDBMemory.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/KeyValueDBMemory.cc' object='test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.o `test -f 'test/ObjectMap/KeyValueDBMemory.cc' || echo '$(srcdir)/'`test/ObjectMap/KeyValueDBMemory.cc test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.obj: test/ObjectMap/KeyValueDBMemory.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.obj -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Tpo -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.obj `if test -f 'test/ObjectMap/KeyValueDBMemory.cc'; then $(CYGPATH_W) 'test/ObjectMap/KeyValueDBMemory.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/KeyValueDBMemory.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/KeyValueDBMemory.cc' object='test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_keyvaluedb_iterators_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_keyvaluedb_iterators-KeyValueDBMemory.obj `if test -f 'test/ObjectMap/KeyValueDBMemory.cc'; then $(CYGPATH_W) 'test/ObjectMap/KeyValueDBMemory.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/KeyValueDBMemory.cc'; fi` test/libcephfs/ceph_test_libcephfs-test.o: test/libcephfs/test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-test.o -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Tpo -c -o test/libcephfs/ceph_test_libcephfs-test.o `test -f 'test/libcephfs/test.cc' || echo '$(srcdir)/'`test/libcephfs/test.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/test.cc' object='test/libcephfs/ceph_test_libcephfs-test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-test.o `test -f 'test/libcephfs/test.cc' || echo '$(srcdir)/'`test/libcephfs/test.cc test/libcephfs/ceph_test_libcephfs-test.obj: test/libcephfs/test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-test.obj -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Tpo -c -o test/libcephfs/ceph_test_libcephfs-test.obj `if test -f 'test/libcephfs/test.cc'; then $(CYGPATH_W) 'test/libcephfs/test.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/test.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/test.cc' object='test/libcephfs/ceph_test_libcephfs-test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-test.obj `if test -f 'test/libcephfs/test.cc'; then $(CYGPATH_W) 'test/libcephfs/test.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/test.cc'; fi` test/libcephfs/ceph_test_libcephfs-readdir_r_cb.o: test/libcephfs/readdir_r_cb.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-readdir_r_cb.o -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Tpo -c -o test/libcephfs/ceph_test_libcephfs-readdir_r_cb.o `test -f 'test/libcephfs/readdir_r_cb.cc' || echo '$(srcdir)/'`test/libcephfs/readdir_r_cb.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/readdir_r_cb.cc' object='test/libcephfs/ceph_test_libcephfs-readdir_r_cb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-readdir_r_cb.o `test -f 'test/libcephfs/readdir_r_cb.cc' || echo '$(srcdir)/'`test/libcephfs/readdir_r_cb.cc test/libcephfs/ceph_test_libcephfs-readdir_r_cb.obj: test/libcephfs/readdir_r_cb.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-readdir_r_cb.obj -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Tpo -c -o test/libcephfs/ceph_test_libcephfs-readdir_r_cb.obj `if test -f 'test/libcephfs/readdir_r_cb.cc'; then $(CYGPATH_W) 'test/libcephfs/readdir_r_cb.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/readdir_r_cb.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-readdir_r_cb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/readdir_r_cb.cc' object='test/libcephfs/ceph_test_libcephfs-readdir_r_cb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-readdir_r_cb.obj `if test -f 'test/libcephfs/readdir_r_cb.cc'; then $(CYGPATH_W) 'test/libcephfs/readdir_r_cb.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/readdir_r_cb.cc'; fi` test/libcephfs/ceph_test_libcephfs-caps.o: test/libcephfs/caps.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-caps.o -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Tpo -c -o test/libcephfs/ceph_test_libcephfs-caps.o `test -f 'test/libcephfs/caps.cc' || echo '$(srcdir)/'`test/libcephfs/caps.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/caps.cc' object='test/libcephfs/ceph_test_libcephfs-caps.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-caps.o `test -f 'test/libcephfs/caps.cc' || echo '$(srcdir)/'`test/libcephfs/caps.cc test/libcephfs/ceph_test_libcephfs-caps.obj: test/libcephfs/caps.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-caps.obj -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Tpo -c -o test/libcephfs/ceph_test_libcephfs-caps.obj `if test -f 'test/libcephfs/caps.cc'; then $(CYGPATH_W) 'test/libcephfs/caps.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/caps.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-caps.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/caps.cc' object='test/libcephfs/ceph_test_libcephfs-caps.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-caps.obj `if test -f 'test/libcephfs/caps.cc'; then $(CYGPATH_W) 'test/libcephfs/caps.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/caps.cc'; fi` test/libcephfs/ceph_test_libcephfs-multiclient.o: test/libcephfs/multiclient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-multiclient.o -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Tpo -c -o test/libcephfs/ceph_test_libcephfs-multiclient.o `test -f 'test/libcephfs/multiclient.cc' || echo '$(srcdir)/'`test/libcephfs/multiclient.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/multiclient.cc' object='test/libcephfs/ceph_test_libcephfs-multiclient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-multiclient.o `test -f 'test/libcephfs/multiclient.cc' || echo '$(srcdir)/'`test/libcephfs/multiclient.cc test/libcephfs/ceph_test_libcephfs-multiclient.obj: test/libcephfs/multiclient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/libcephfs/ceph_test_libcephfs-multiclient.obj -MD -MP -MF test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Tpo -c -o test/libcephfs/ceph_test_libcephfs-multiclient.obj `if test -f 'test/libcephfs/multiclient.cc'; then $(CYGPATH_W) 'test/libcephfs/multiclient.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/multiclient.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Tpo test/libcephfs/$(DEPDIR)/ceph_test_libcephfs-multiclient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs/multiclient.cc' object='test/libcephfs/ceph_test_libcephfs-multiclient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/libcephfs/ceph_test_libcephfs-multiclient.obj `if test -f 'test/libcephfs/multiclient.cc'; then $(CYGPATH_W) 'test/libcephfs/multiclient.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs/multiclient.cc'; fi` test/librbd/ceph_test_librbd-test_librbd.o: test/librbd/test_librbd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_CXXFLAGS) $(CXXFLAGS) -MT test/librbd/ceph_test_librbd-test_librbd.o -MD -MP -MF test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Tpo -c -o test/librbd/ceph_test_librbd-test_librbd.o `test -f 'test/librbd/test_librbd.cc' || echo '$(srcdir)/'`test/librbd/test_librbd.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Tpo test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librbd/test_librbd.cc' object='test/librbd/ceph_test_librbd-test_librbd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_CXXFLAGS) $(CXXFLAGS) -c -o test/librbd/ceph_test_librbd-test_librbd.o `test -f 'test/librbd/test_librbd.cc' || echo '$(srcdir)/'`test/librbd/test_librbd.cc test/librbd/ceph_test_librbd-test_librbd.obj: test/librbd/test_librbd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_CXXFLAGS) $(CXXFLAGS) -MT test/librbd/ceph_test_librbd-test_librbd.obj -MD -MP -MF test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Tpo -c -o test/librbd/ceph_test_librbd-test_librbd.obj `if test -f 'test/librbd/test_librbd.cc'; then $(CYGPATH_W) 'test/librbd/test_librbd.cc'; else $(CYGPATH_W) '$(srcdir)/test/librbd/test_librbd.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Tpo test/librbd/$(DEPDIR)/ceph_test_librbd-test_librbd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librbd/test_librbd.cc' object='test/librbd/ceph_test_librbd-test_librbd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_librbd_CXXFLAGS) $(CXXFLAGS) -c -o test/librbd/ceph_test_librbd-test_librbd.obj `if test -f 'test/librbd/test_librbd.cc'; then $(CYGPATH_W) 'test/librbd/test_librbd.cc'; else $(CYGPATH_W) '$(srcdir)/test/librbd/test_librbd.cc'; fi` test/ObjectMap/ceph_test_object_map-test_object_map.o: test/ObjectMap/test_object_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_object_map-test_object_map.o -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Tpo -c -o test/ObjectMap/ceph_test_object_map-test_object_map.o `test -f 'test/ObjectMap/test_object_map.cc' || echo '$(srcdir)/'`test/ObjectMap/test_object_map.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/test_object_map.cc' object='test/ObjectMap/ceph_test_object_map-test_object_map.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_object_map-test_object_map.o `test -f 'test/ObjectMap/test_object_map.cc' || echo '$(srcdir)/'`test/ObjectMap/test_object_map.cc test/ObjectMap/ceph_test_object_map-test_object_map.obj: test/ObjectMap/test_object_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_object_map-test_object_map.obj -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Tpo -c -o test/ObjectMap/ceph_test_object_map-test_object_map.obj `if test -f 'test/ObjectMap/test_object_map.cc'; then $(CYGPATH_W) 'test/ObjectMap/test_object_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/test_object_map.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_object_map-test_object_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/test_object_map.cc' object='test/ObjectMap/ceph_test_object_map-test_object_map.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_object_map-test_object_map.obj `if test -f 'test/ObjectMap/test_object_map.cc'; then $(CYGPATH_W) 'test/ObjectMap/test_object_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/test_object_map.cc'; fi` test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.o: test/ObjectMap/KeyValueDBMemory.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.o -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Tpo -c -o test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.o `test -f 'test/ObjectMap/KeyValueDBMemory.cc' || echo '$(srcdir)/'`test/ObjectMap/KeyValueDBMemory.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/KeyValueDBMemory.cc' object='test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.o `test -f 'test/ObjectMap/KeyValueDBMemory.cc' || echo '$(srcdir)/'`test/ObjectMap/KeyValueDBMemory.cc test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.obj: test/ObjectMap/KeyValueDBMemory.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -MT test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.obj -MD -MP -MF test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Tpo -c -o test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.obj `if test -f 'test/ObjectMap/KeyValueDBMemory.cc'; then $(CYGPATH_W) 'test/ObjectMap/KeyValueDBMemory.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/KeyValueDBMemory.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Tpo test/ObjectMap/$(DEPDIR)/ceph_test_object_map-KeyValueDBMemory.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ObjectMap/KeyValueDBMemory.cc' object='test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_object_map_CXXFLAGS) $(CXXFLAGS) -c -o test/ObjectMap/ceph_test_object_map-KeyValueDBMemory.obj `if test -f 'test/ObjectMap/KeyValueDBMemory.cc'; then $(CYGPATH_W) 'test/ObjectMap/KeyValueDBMemory.cc'; else $(CYGPATH_W) '$(srcdir)/test/ObjectMap/KeyValueDBMemory.cc'; fi` test/objectstore/ceph_test_objectstore-store_test.o: test/objectstore/store_test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_objectstore_CXXFLAGS) $(CXXFLAGS) -MT test/objectstore/ceph_test_objectstore-store_test.o -MD -MP -MF test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Tpo -c -o test/objectstore/ceph_test_objectstore-store_test.o `test -f 'test/objectstore/store_test.cc' || echo '$(srcdir)/'`test/objectstore/store_test.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Tpo test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/objectstore/store_test.cc' object='test/objectstore/ceph_test_objectstore-store_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_objectstore_CXXFLAGS) $(CXXFLAGS) -c -o test/objectstore/ceph_test_objectstore-store_test.o `test -f 'test/objectstore/store_test.cc' || echo '$(srcdir)/'`test/objectstore/store_test.cc test/objectstore/ceph_test_objectstore-store_test.obj: test/objectstore/store_test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_objectstore_CXXFLAGS) $(CXXFLAGS) -MT test/objectstore/ceph_test_objectstore-store_test.obj -MD -MP -MF test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Tpo -c -o test/objectstore/ceph_test_objectstore-store_test.obj `if test -f 'test/objectstore/store_test.cc'; then $(CYGPATH_W) 'test/objectstore/store_test.cc'; else $(CYGPATH_W) '$(srcdir)/test/objectstore/store_test.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Tpo test/objectstore/$(DEPDIR)/ceph_test_objectstore-store_test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/objectstore/store_test.cc' object='test/objectstore/ceph_test_objectstore-store_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_objectstore_CXXFLAGS) $(CXXFLAGS) -c -o test/objectstore/ceph_test_objectstore-store_test.obj `if test -f 'test/objectstore/store_test.cc'; then $(CYGPATH_W) 'test/objectstore/store_test.cc'; else $(CYGPATH_W) '$(srcdir)/test/objectstore/store_test.cc'; fi` test/librados/ceph_test_rados_api_aio-aio.o: test/librados/aio.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_aio_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_aio-aio.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Tpo -c -o test/librados/ceph_test_rados_api_aio-aio.o `test -f 'test/librados/aio.cc' || echo '$(srcdir)/'`test/librados/aio.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/aio.cc' object='test/librados/ceph_test_rados_api_aio-aio.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_aio_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_aio-aio.o `test -f 'test/librados/aio.cc' || echo '$(srcdir)/'`test/librados/aio.cc test/librados/ceph_test_rados_api_aio-aio.obj: test/librados/aio.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_aio_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_aio-aio.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Tpo -c -o test/librados/ceph_test_rados_api_aio-aio.obj `if test -f 'test/librados/aio.cc'; then $(CYGPATH_W) 'test/librados/aio.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/aio.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_aio-aio.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/aio.cc' object='test/librados/ceph_test_rados_api_aio-aio.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_aio_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_aio-aio.obj `if test -f 'test/librados/aio.cc'; then $(CYGPATH_W) 'test/librados/aio.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/aio.cc'; fi` test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.o: test/librados/c_read_operations.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_read_operations_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Tpo -c -o test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.o `test -f 'test/librados/c_read_operations.cc' || echo '$(srcdir)/'`test/librados/c_read_operations.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/c_read_operations.cc' object='test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_read_operations_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.o `test -f 'test/librados/c_read_operations.cc' || echo '$(srcdir)/'`test/librados/c_read_operations.cc test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.obj: test/librados/c_read_operations.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_read_operations_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Tpo -c -o test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.obj `if test -f 'test/librados/c_read_operations.cc'; then $(CYGPATH_W) 'test/librados/c_read_operations.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/c_read_operations.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_c_read_operations-c_read_operations.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/c_read_operations.cc' object='test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_read_operations_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_c_read_operations-c_read_operations.obj `if test -f 'test/librados/c_read_operations.cc'; then $(CYGPATH_W) 'test/librados/c_read_operations.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/c_read_operations.cc'; fi` test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.o: test/librados/c_write_operations.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_write_operations_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Tpo -c -o test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.o `test -f 'test/librados/c_write_operations.cc' || echo '$(srcdir)/'`test/librados/c_write_operations.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/c_write_operations.cc' object='test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_write_operations_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.o `test -f 'test/librados/c_write_operations.cc' || echo '$(srcdir)/'`test/librados/c_write_operations.cc test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.obj: test/librados/c_write_operations.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_write_operations_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Tpo -c -o test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.obj `if test -f 'test/librados/c_write_operations.cc'; then $(CYGPATH_W) 'test/librados/c_write_operations.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/c_write_operations.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_c_write_operations-c_write_operations.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/c_write_operations.cc' object='test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_c_write_operations_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_c_write_operations-c_write_operations.obj `if test -f 'test/librados/c_write_operations.cc'; then $(CYGPATH_W) 'test/librados/c_write_operations.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/c_write_operations.cc'; fi` test/librados/ceph_test_rados_api_cls-cls.o: test/librados/cls.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cls_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_cls-cls.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Tpo -c -o test/librados/ceph_test_rados_api_cls-cls.o `test -f 'test/librados/cls.cc' || echo '$(srcdir)/'`test/librados/cls.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/cls.cc' object='test/librados/ceph_test_rados_api_cls-cls.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cls_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_cls-cls.o `test -f 'test/librados/cls.cc' || echo '$(srcdir)/'`test/librados/cls.cc test/librados/ceph_test_rados_api_cls-cls.obj: test/librados/cls.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cls_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_cls-cls.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Tpo -c -o test/librados/ceph_test_rados_api_cls-cls.obj `if test -f 'test/librados/cls.cc'; then $(CYGPATH_W) 'test/librados/cls.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/cls.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_cls-cls.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/cls.cc' object='test/librados/ceph_test_rados_api_cls-cls.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cls_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_cls-cls.obj `if test -f 'test/librados/cls.cc'; then $(CYGPATH_W) 'test/librados/cls.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/cls.cc'; fi` test/librados/ceph_test_rados_api_cmd-cmd.o: test/librados/cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cmd_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_cmd-cmd.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Tpo -c -o test/librados/ceph_test_rados_api_cmd-cmd.o `test -f 'test/librados/cmd.cc' || echo '$(srcdir)/'`test/librados/cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/cmd.cc' object='test/librados/ceph_test_rados_api_cmd-cmd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cmd_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_cmd-cmd.o `test -f 'test/librados/cmd.cc' || echo '$(srcdir)/'`test/librados/cmd.cc test/librados/ceph_test_rados_api_cmd-cmd.obj: test/librados/cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cmd_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_cmd-cmd.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Tpo -c -o test/librados/ceph_test_rados_api_cmd-cmd.obj `if test -f 'test/librados/cmd.cc'; then $(CYGPATH_W) 'test/librados/cmd.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/cmd.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_cmd-cmd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/cmd.cc' object='test/librados/ceph_test_rados_api_cmd-cmd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_cmd_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_cmd-cmd.obj `if test -f 'test/librados/cmd.cc'; then $(CYGPATH_W) 'test/librados/cmd.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/cmd.cc'; fi` test/librados/ceph_test_rados_api_io-io.o: test/librados/io.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_io_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_io-io.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Tpo -c -o test/librados/ceph_test_rados_api_io-io.o `test -f 'test/librados/io.cc' || echo '$(srcdir)/'`test/librados/io.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/io.cc' object='test/librados/ceph_test_rados_api_io-io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_io_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_io-io.o `test -f 'test/librados/io.cc' || echo '$(srcdir)/'`test/librados/io.cc test/librados/ceph_test_rados_api_io-io.obj: test/librados/io.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_io_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_io-io.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Tpo -c -o test/librados/ceph_test_rados_api_io-io.obj `if test -f 'test/librados/io.cc'; then $(CYGPATH_W) 'test/librados/io.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/io.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_io-io.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/io.cc' object='test/librados/ceph_test_rados_api_io-io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_io_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_io-io.obj `if test -f 'test/librados/io.cc'; then $(CYGPATH_W) 'test/librados/io.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/io.cc'; fi` test/librados/ceph_test_rados_api_list-list.o: test/librados/list.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_list_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_list-list.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Tpo -c -o test/librados/ceph_test_rados_api_list-list.o `test -f 'test/librados/list.cc' || echo '$(srcdir)/'`test/librados/list.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/list.cc' object='test/librados/ceph_test_rados_api_list-list.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_list_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_list-list.o `test -f 'test/librados/list.cc' || echo '$(srcdir)/'`test/librados/list.cc test/librados/ceph_test_rados_api_list-list.obj: test/librados/list.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_list_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_list-list.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Tpo -c -o test/librados/ceph_test_rados_api_list-list.obj `if test -f 'test/librados/list.cc'; then $(CYGPATH_W) 'test/librados/list.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/list.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_list-list.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/list.cc' object='test/librados/ceph_test_rados_api_list-list.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_list_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_list-list.obj `if test -f 'test/librados/list.cc'; then $(CYGPATH_W) 'test/librados/list.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/list.cc'; fi` test/librados/ceph_test_rados_api_lock-lock.o: test/librados/lock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_lock_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_lock-lock.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Tpo -c -o test/librados/ceph_test_rados_api_lock-lock.o `test -f 'test/librados/lock.cc' || echo '$(srcdir)/'`test/librados/lock.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/lock.cc' object='test/librados/ceph_test_rados_api_lock-lock.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_lock_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_lock-lock.o `test -f 'test/librados/lock.cc' || echo '$(srcdir)/'`test/librados/lock.cc test/librados/ceph_test_rados_api_lock-lock.obj: test/librados/lock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_lock_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_lock-lock.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Tpo -c -o test/librados/ceph_test_rados_api_lock-lock.obj `if test -f 'test/librados/lock.cc'; then $(CYGPATH_W) 'test/librados/lock.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/lock.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_lock-lock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/lock.cc' object='test/librados/ceph_test_rados_api_lock-lock.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_lock_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_lock-lock.obj `if test -f 'test/librados/lock.cc'; then $(CYGPATH_W) 'test/librados/lock.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/lock.cc'; fi` test/librados/ceph_test_rados_api_misc-misc.o: test/librados/misc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_misc_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_misc-misc.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Tpo -c -o test/librados/ceph_test_rados_api_misc-misc.o `test -f 'test/librados/misc.cc' || echo '$(srcdir)/'`test/librados/misc.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/misc.cc' object='test/librados/ceph_test_rados_api_misc-misc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_misc_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_misc-misc.o `test -f 'test/librados/misc.cc' || echo '$(srcdir)/'`test/librados/misc.cc test/librados/ceph_test_rados_api_misc-misc.obj: test/librados/misc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_misc_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_misc-misc.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Tpo -c -o test/librados/ceph_test_rados_api_misc-misc.obj `if test -f 'test/librados/misc.cc'; then $(CYGPATH_W) 'test/librados/misc.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/misc.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_misc-misc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/misc.cc' object='test/librados/ceph_test_rados_api_misc-misc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_misc_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_misc-misc.obj `if test -f 'test/librados/misc.cc'; then $(CYGPATH_W) 'test/librados/misc.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/misc.cc'; fi` test/librados/ceph_test_rados_api_pool-pool.o: test/librados/pool.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_pool_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_pool-pool.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Tpo -c -o test/librados/ceph_test_rados_api_pool-pool.o `test -f 'test/librados/pool.cc' || echo '$(srcdir)/'`test/librados/pool.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/pool.cc' object='test/librados/ceph_test_rados_api_pool-pool.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_pool_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_pool-pool.o `test -f 'test/librados/pool.cc' || echo '$(srcdir)/'`test/librados/pool.cc test/librados/ceph_test_rados_api_pool-pool.obj: test/librados/pool.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_pool_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_pool-pool.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Tpo -c -o test/librados/ceph_test_rados_api_pool-pool.obj `if test -f 'test/librados/pool.cc'; then $(CYGPATH_W) 'test/librados/pool.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/pool.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_pool-pool.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/pool.cc' object='test/librados/ceph_test_rados_api_pool-pool.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_pool_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_pool-pool.obj `if test -f 'test/librados/pool.cc'; then $(CYGPATH_W) 'test/librados/pool.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/pool.cc'; fi` test/librados/ceph_test_rados_api_snapshots-snapshots.o: test/librados/snapshots.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_snapshots_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_snapshots-snapshots.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Tpo -c -o test/librados/ceph_test_rados_api_snapshots-snapshots.o `test -f 'test/librados/snapshots.cc' || echo '$(srcdir)/'`test/librados/snapshots.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/snapshots.cc' object='test/librados/ceph_test_rados_api_snapshots-snapshots.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_snapshots_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_snapshots-snapshots.o `test -f 'test/librados/snapshots.cc' || echo '$(srcdir)/'`test/librados/snapshots.cc test/librados/ceph_test_rados_api_snapshots-snapshots.obj: test/librados/snapshots.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_snapshots_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_snapshots-snapshots.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Tpo -c -o test/librados/ceph_test_rados_api_snapshots-snapshots.obj `if test -f 'test/librados/snapshots.cc'; then $(CYGPATH_W) 'test/librados/snapshots.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/snapshots.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_snapshots-snapshots.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/snapshots.cc' object='test/librados/ceph_test_rados_api_snapshots-snapshots.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_snapshots_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_snapshots-snapshots.obj `if test -f 'test/librados/snapshots.cc'; then $(CYGPATH_W) 'test/librados/snapshots.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/snapshots.cc'; fi` test/librados/ceph_test_rados_api_stat-stat.o: test/librados/stat.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_stat_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_stat-stat.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Tpo -c -o test/librados/ceph_test_rados_api_stat-stat.o `test -f 'test/librados/stat.cc' || echo '$(srcdir)/'`test/librados/stat.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/stat.cc' object='test/librados/ceph_test_rados_api_stat-stat.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_stat_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_stat-stat.o `test -f 'test/librados/stat.cc' || echo '$(srcdir)/'`test/librados/stat.cc test/librados/ceph_test_rados_api_stat-stat.obj: test/librados/stat.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_stat_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_stat-stat.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Tpo -c -o test/librados/ceph_test_rados_api_stat-stat.obj `if test -f 'test/librados/stat.cc'; then $(CYGPATH_W) 'test/librados/stat.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/stat.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_stat-stat.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/stat.cc' object='test/librados/ceph_test_rados_api_stat-stat.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_stat_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_stat-stat.obj `if test -f 'test/librados/stat.cc'; then $(CYGPATH_W) 'test/librados/stat.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/stat.cc'; fi` test/librados/ceph_test_rados_api_tier-tier.o: test/librados/tier.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_tier-tier.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Tpo -c -o test/librados/ceph_test_rados_api_tier-tier.o `test -f 'test/librados/tier.cc' || echo '$(srcdir)/'`test/librados/tier.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/tier.cc' object='test/librados/ceph_test_rados_api_tier-tier.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_tier-tier.o `test -f 'test/librados/tier.cc' || echo '$(srcdir)/'`test/librados/tier.cc test/librados/ceph_test_rados_api_tier-tier.obj: test/librados/tier.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_tier-tier.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Tpo -c -o test/librados/ceph_test_rados_api_tier-tier.obj `if test -f 'test/librados/tier.cc'; then $(CYGPATH_W) 'test/librados/tier.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/tier.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_tier-tier.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/tier.cc' object='test/librados/ceph_test_rados_api_tier-tier.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_tier-tier.obj `if test -f 'test/librados/tier.cc'; then $(CYGPATH_W) 'test/librados/tier.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/tier.cc'; fi` osd/ceph_test_rados_api_tier-HitSet.o: osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -MT osd/ceph_test_rados_api_tier-HitSet.o -MD -MP -MF osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Tpo -c -o osd/ceph_test_rados_api_tier-HitSet.o `test -f 'osd/HitSet.cc' || echo '$(srcdir)/'`osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Tpo osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/HitSet.cc' object='osd/ceph_test_rados_api_tier-HitSet.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -c -o osd/ceph_test_rados_api_tier-HitSet.o `test -f 'osd/HitSet.cc' || echo '$(srcdir)/'`osd/HitSet.cc osd/ceph_test_rados_api_tier-HitSet.obj: osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -MT osd/ceph_test_rados_api_tier-HitSet.obj -MD -MP -MF osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Tpo -c -o osd/ceph_test_rados_api_tier-HitSet.obj `if test -f 'osd/HitSet.cc'; then $(CYGPATH_W) 'osd/HitSet.cc'; else $(CYGPATH_W) '$(srcdir)/osd/HitSet.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Tpo osd/$(DEPDIR)/ceph_test_rados_api_tier-HitSet.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/HitSet.cc' object='osd/ceph_test_rados_api_tier-HitSet.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_tier_CXXFLAGS) $(CXXFLAGS) -c -o osd/ceph_test_rados_api_tier-HitSet.obj `if test -f 'osd/HitSet.cc'; then $(CYGPATH_W) 'osd/HitSet.cc'; else $(CYGPATH_W) '$(srcdir)/osd/HitSet.cc'; fi` test/librados/ceph_test_rados_api_watch_notify-watch_notify.o: test/librados/watch_notify.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_watch_notify_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_watch_notify-watch_notify.o -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Tpo -c -o test/librados/ceph_test_rados_api_watch_notify-watch_notify.o `test -f 'test/librados/watch_notify.cc' || echo '$(srcdir)/'`test/librados/watch_notify.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/watch_notify.cc' object='test/librados/ceph_test_rados_api_watch_notify-watch_notify.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_watch_notify_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_watch_notify-watch_notify.o `test -f 'test/librados/watch_notify.cc' || echo '$(srcdir)/'`test/librados/watch_notify.cc test/librados/ceph_test_rados_api_watch_notify-watch_notify.obj: test/librados/watch_notify.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_watch_notify_CXXFLAGS) $(CXXFLAGS) -MT test/librados/ceph_test_rados_api_watch_notify-watch_notify.obj -MD -MP -MF test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Tpo -c -o test/librados/ceph_test_rados_api_watch_notify-watch_notify.obj `if test -f 'test/librados/watch_notify.cc'; then $(CYGPATH_W) 'test/librados/watch_notify.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/watch_notify.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Tpo test/librados/$(DEPDIR)/ceph_test_rados_api_watch_notify-watch_notify.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/watch_notify.cc' object='test/librados/ceph_test_rados_api_watch_notify-watch_notify.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rados_api_watch_notify_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/ceph_test_rados_api_watch_notify-watch_notify.obj `if test -f 'test/librados/watch_notify.cc'; then $(CYGPATH_W) 'test/librados/watch_notify.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/watch_notify.cc'; fi` test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.o: test/rgw/test_rgw_manifest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rgw_manifest_CXXFLAGS) $(CXXFLAGS) -MT test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.o -MD -MP -MF test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Tpo -c -o test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.o `test -f 'test/rgw/test_rgw_manifest.cc' || echo '$(srcdir)/'`test/rgw/test_rgw_manifest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Tpo test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/rgw/test_rgw_manifest.cc' object='test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rgw_manifest_CXXFLAGS) $(CXXFLAGS) -c -o test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.o `test -f 'test/rgw/test_rgw_manifest.cc' || echo '$(srcdir)/'`test/rgw/test_rgw_manifest.cc test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.obj: test/rgw/test_rgw_manifest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rgw_manifest_CXXFLAGS) $(CXXFLAGS) -MT test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.obj -MD -MP -MF test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Tpo -c -o test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.obj `if test -f 'test/rgw/test_rgw_manifest.cc'; then $(CYGPATH_W) 'test/rgw/test_rgw_manifest.cc'; else $(CYGPATH_W) '$(srcdir)/test/rgw/test_rgw_manifest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Tpo test/rgw/$(DEPDIR)/ceph_test_rgw_manifest-test_rgw_manifest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/rgw/test_rgw_manifest.cc' object='test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_rgw_manifest_CXXFLAGS) $(CXXFLAGS) -c -o test/rgw/ceph_test_rgw_manifest-test_rgw_manifest.obj `if test -f 'test/rgw/test_rgw_manifest.cc'; then $(CYGPATH_W) 'test/rgw/test_rgw_manifest.cc'; else $(CYGPATH_W) '$(srcdir)/test/rgw/test_rgw_manifest.cc'; fi` test/ceph_test_snap_mapper-test_snap_mapper.o: test/test_snap_mapper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_snap_mapper_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_snap_mapper-test_snap_mapper.o -MD -MP -MF test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Tpo -c -o test/ceph_test_snap_mapper-test_snap_mapper.o `test -f 'test/test_snap_mapper.cc' || echo '$(srcdir)/'`test/test_snap_mapper.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Tpo test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_snap_mapper.cc' object='test/ceph_test_snap_mapper-test_snap_mapper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_snap_mapper_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_snap_mapper-test_snap_mapper.o `test -f 'test/test_snap_mapper.cc' || echo '$(srcdir)/'`test/test_snap_mapper.cc test/ceph_test_snap_mapper-test_snap_mapper.obj: test/test_snap_mapper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_snap_mapper_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_snap_mapper-test_snap_mapper.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Tpo -c -o test/ceph_test_snap_mapper-test_snap_mapper.obj `if test -f 'test/test_snap_mapper.cc'; then $(CYGPATH_W) 'test/test_snap_mapper.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_snap_mapper.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Tpo test/$(DEPDIR)/ceph_test_snap_mapper-test_snap_mapper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_snap_mapper.cc' object='test/ceph_test_snap_mapper-test_snap_mapper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_snap_mapper_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_snap_mapper-test_snap_mapper.obj `if test -f 'test/test_snap_mapper.cc'; then $(CYGPATH_W) 'test/test_snap_mapper.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_snap_mapper.cc'; fi` test/ceph_test_stress_watch-test_stress_watch.o: test/test_stress_watch.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_stress_watch_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_stress_watch-test_stress_watch.o -MD -MP -MF test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Tpo -c -o test/ceph_test_stress_watch-test_stress_watch.o `test -f 'test/test_stress_watch.cc' || echo '$(srcdir)/'`test/test_stress_watch.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Tpo test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_stress_watch.cc' object='test/ceph_test_stress_watch-test_stress_watch.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_stress_watch_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_stress_watch-test_stress_watch.o `test -f 'test/test_stress_watch.cc' || echo '$(srcdir)/'`test/test_stress_watch.cc test/ceph_test_stress_watch-test_stress_watch.obj: test/test_stress_watch.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_stress_watch_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_test_stress_watch-test_stress_watch.obj -MD -MP -MF test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Tpo -c -o test/ceph_test_stress_watch-test_stress_watch.obj `if test -f 'test/test_stress_watch.cc'; then $(CYGPATH_W) 'test/test_stress_watch.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_stress_watch.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Tpo test/$(DEPDIR)/ceph_test_stress_watch-test_stress_watch.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_stress_watch.cc' object='test/ceph_test_stress_watch-test_stress_watch.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_test_stress_watch_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_test_stress_watch-test_stress_watch.obj `if test -f 'test/test_stress_watch.cc'; then $(CYGPATH_W) 'test/test_stress_watch.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_stress_watch.cc'; fi` test/ceph_xattr_bench-xattr_bench.o: test/xattr_bench.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_xattr_bench_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_xattr_bench-xattr_bench.o -MD -MP -MF test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Tpo -c -o test/ceph_xattr_bench-xattr_bench.o `test -f 'test/xattr_bench.cc' || echo '$(srcdir)/'`test/xattr_bench.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Tpo test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/xattr_bench.cc' object='test/ceph_xattr_bench-xattr_bench.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_xattr_bench_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_xattr_bench-xattr_bench.o `test -f 'test/xattr_bench.cc' || echo '$(srcdir)/'`test/xattr_bench.cc test/ceph_xattr_bench-xattr_bench.obj: test/xattr_bench.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_xattr_bench_CXXFLAGS) $(CXXFLAGS) -MT test/ceph_xattr_bench-xattr_bench.obj -MD -MP -MF test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Tpo -c -o test/ceph_xattr_bench-xattr_bench.obj `if test -f 'test/xattr_bench.cc'; then $(CYGPATH_W) 'test/xattr_bench.cc'; else $(CYGPATH_W) '$(srcdir)/test/xattr_bench.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Tpo test/$(DEPDIR)/ceph_xattr_bench-xattr_bench.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/xattr_bench.cc' object='test/ceph_xattr_bench-xattr_bench.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ceph_xattr_bench_CXXFLAGS) $(CXXFLAGS) -c -o test/ceph_xattr_bench-xattr_bench.obj `if test -f 'test/xattr_bench.cc'; then $(CYGPATH_W) 'test/xattr_bench.cc'; else $(CYGPATH_W) '$(srcdir)/test/xattr_bench.cc'; fi` tools/rest_bench-rest_bench.o: tools/rest_bench.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -MT tools/rest_bench-rest_bench.o -MD -MP -MF tools/$(DEPDIR)/rest_bench-rest_bench.Tpo -c -o tools/rest_bench-rest_bench.o `test -f 'tools/rest_bench.cc' || echo '$(srcdir)/'`tools/rest_bench.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) tools/$(DEPDIR)/rest_bench-rest_bench.Tpo tools/$(DEPDIR)/rest_bench-rest_bench.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tools/rest_bench.cc' object='tools/rest_bench-rest_bench.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -c -o tools/rest_bench-rest_bench.o `test -f 'tools/rest_bench.cc' || echo '$(srcdir)/'`tools/rest_bench.cc tools/rest_bench-rest_bench.obj: tools/rest_bench.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -MT tools/rest_bench-rest_bench.obj -MD -MP -MF tools/$(DEPDIR)/rest_bench-rest_bench.Tpo -c -o tools/rest_bench-rest_bench.obj `if test -f 'tools/rest_bench.cc'; then $(CYGPATH_W) 'tools/rest_bench.cc'; else $(CYGPATH_W) '$(srcdir)/tools/rest_bench.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) tools/$(DEPDIR)/rest_bench-rest_bench.Tpo tools/$(DEPDIR)/rest_bench-rest_bench.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tools/rest_bench.cc' object='tools/rest_bench-rest_bench.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -c -o tools/rest_bench-rest_bench.obj `if test -f 'tools/rest_bench.cc'; then $(CYGPATH_W) 'tools/rest_bench.cc'; else $(CYGPATH_W) '$(srcdir)/tools/rest_bench.cc'; fi` common/rest_bench-obj_bencher.o: common/obj_bencher.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -MT common/rest_bench-obj_bencher.o -MD -MP -MF common/$(DEPDIR)/rest_bench-obj_bencher.Tpo -c -o common/rest_bench-obj_bencher.o `test -f 'common/obj_bencher.cc' || echo '$(srcdir)/'`common/obj_bencher.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/rest_bench-obj_bencher.Tpo common/$(DEPDIR)/rest_bench-obj_bencher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/obj_bencher.cc' object='common/rest_bench-obj_bencher.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -c -o common/rest_bench-obj_bencher.o `test -f 'common/obj_bencher.cc' || echo '$(srcdir)/'`common/obj_bencher.cc common/rest_bench-obj_bencher.obj: common/obj_bencher.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -MT common/rest_bench-obj_bencher.obj -MD -MP -MF common/$(DEPDIR)/rest_bench-obj_bencher.Tpo -c -o common/rest_bench-obj_bencher.obj `if test -f 'common/obj_bencher.cc'; then $(CYGPATH_W) 'common/obj_bencher.cc'; else $(CYGPATH_W) '$(srcdir)/common/obj_bencher.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/rest_bench-obj_bencher.Tpo common/$(DEPDIR)/rest_bench-obj_bencher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/obj_bencher.cc' object='common/rest_bench-obj_bencher.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rest_bench_CXXFLAGS) $(CXXFLAGS) -c -o common/rest_bench-obj_bencher.obj `if test -f 'common/obj_bencher.cc'; then $(CYGPATH_W) 'common/obj_bencher.cc'; else $(CYGPATH_W) '$(srcdir)/common/obj_bencher.cc'; fi` test/test_build_libcephfs-buildtest_skeleton.o: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_libcephfs-buildtest_skeleton.o -MD -MP -MF test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Tpo -c -o test/test_build_libcephfs-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_libcephfs-buildtest_skeleton.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_libcephfs-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc test/test_build_libcephfs-buildtest_skeleton.obj: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_libcephfs-buildtest_skeleton.obj -MD -MP -MF test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Tpo -c -o test/test_build_libcephfs-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_libcephfs-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_libcephfs-buildtest_skeleton.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_libcephfs-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` osdc/test_build_libcephfs-Objecter.o: osdc/Objecter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Objecter.o -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Tpo -c -o osdc/test_build_libcephfs-Objecter.o `test -f 'osdc/Objecter.cc' || echo '$(srcdir)/'`osdc/Objecter.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Objecter.cc' object='osdc/test_build_libcephfs-Objecter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Objecter.o `test -f 'osdc/Objecter.cc' || echo '$(srcdir)/'`osdc/Objecter.cc osdc/test_build_libcephfs-Objecter.obj: osdc/Objecter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Objecter.obj -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Tpo -c -o osdc/test_build_libcephfs-Objecter.obj `if test -f 'osdc/Objecter.cc'; then $(CYGPATH_W) 'osdc/Objecter.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Objecter.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Objecter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Objecter.cc' object='osdc/test_build_libcephfs-Objecter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Objecter.obj `if test -f 'osdc/Objecter.cc'; then $(CYGPATH_W) 'osdc/Objecter.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Objecter.cc'; fi` osdc/test_build_libcephfs-ObjectCacher.o: osdc/ObjectCacher.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-ObjectCacher.o -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Tpo -c -o osdc/test_build_libcephfs-ObjectCacher.o `test -f 'osdc/ObjectCacher.cc' || echo '$(srcdir)/'`osdc/ObjectCacher.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Tpo osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/ObjectCacher.cc' object='osdc/test_build_libcephfs-ObjectCacher.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-ObjectCacher.o `test -f 'osdc/ObjectCacher.cc' || echo '$(srcdir)/'`osdc/ObjectCacher.cc osdc/test_build_libcephfs-ObjectCacher.obj: osdc/ObjectCacher.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-ObjectCacher.obj -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Tpo -c -o osdc/test_build_libcephfs-ObjectCacher.obj `if test -f 'osdc/ObjectCacher.cc'; then $(CYGPATH_W) 'osdc/ObjectCacher.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/ObjectCacher.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Tpo osdc/$(DEPDIR)/test_build_libcephfs-ObjectCacher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/ObjectCacher.cc' object='osdc/test_build_libcephfs-ObjectCacher.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-ObjectCacher.obj `if test -f 'osdc/ObjectCacher.cc'; then $(CYGPATH_W) 'osdc/ObjectCacher.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/ObjectCacher.cc'; fi` osdc/test_build_libcephfs-Filer.o: osdc/Filer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Filer.o -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Filer.Tpo -c -o osdc/test_build_libcephfs-Filer.o `test -f 'osdc/Filer.cc' || echo '$(srcdir)/'`osdc/Filer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Filer.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Filer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Filer.cc' object='osdc/test_build_libcephfs-Filer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Filer.o `test -f 'osdc/Filer.cc' || echo '$(srcdir)/'`osdc/Filer.cc osdc/test_build_libcephfs-Filer.obj: osdc/Filer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Filer.obj -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Filer.Tpo -c -o osdc/test_build_libcephfs-Filer.obj `if test -f 'osdc/Filer.cc'; then $(CYGPATH_W) 'osdc/Filer.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Filer.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Filer.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Filer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Filer.cc' object='osdc/test_build_libcephfs-Filer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Filer.obj `if test -f 'osdc/Filer.cc'; then $(CYGPATH_W) 'osdc/Filer.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Filer.cc'; fi` osdc/test_build_libcephfs-Striper.o: osdc/Striper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Striper.o -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Striper.Tpo -c -o osdc/test_build_libcephfs-Striper.o `test -f 'osdc/Striper.cc' || echo '$(srcdir)/'`osdc/Striper.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Striper.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Striper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Striper.cc' object='osdc/test_build_libcephfs-Striper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Striper.o `test -f 'osdc/Striper.cc' || echo '$(srcdir)/'`osdc/Striper.cc osdc/test_build_libcephfs-Striper.obj: osdc/Striper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Striper.obj -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Striper.Tpo -c -o osdc/test_build_libcephfs-Striper.obj `if test -f 'osdc/Striper.cc'; then $(CYGPATH_W) 'osdc/Striper.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Striper.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Striper.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Striper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Striper.cc' object='osdc/test_build_libcephfs-Striper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Striper.obj `if test -f 'osdc/Striper.cc'; then $(CYGPATH_W) 'osdc/Striper.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Striper.cc'; fi` osdc/test_build_libcephfs-Journaler.o: osdc/Journaler.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Journaler.o -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Tpo -c -o osdc/test_build_libcephfs-Journaler.o `test -f 'osdc/Journaler.cc' || echo '$(srcdir)/'`osdc/Journaler.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Journaler.cc' object='osdc/test_build_libcephfs-Journaler.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Journaler.o `test -f 'osdc/Journaler.cc' || echo '$(srcdir)/'`osdc/Journaler.cc osdc/test_build_libcephfs-Journaler.obj: osdc/Journaler.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -MT osdc/test_build_libcephfs-Journaler.obj -MD -MP -MF osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Tpo -c -o osdc/test_build_libcephfs-Journaler.obj `if test -f 'osdc/Journaler.cc'; then $(CYGPATH_W) 'osdc/Journaler.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Journaler.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Tpo osdc/$(DEPDIR)/test_build_libcephfs-Journaler.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osdc/Journaler.cc' object='osdc/test_build_libcephfs-Journaler.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcephfs_CXXFLAGS) $(CXXFLAGS) -c -o osdc/test_build_libcephfs-Journaler.obj `if test -f 'osdc/Journaler.cc'; then $(CYGPATH_W) 'osdc/Journaler.cc'; else $(CYGPATH_W) '$(srcdir)/osdc/Journaler.cc'; fi` test/test_build_libcommon-buildtest_skeleton.o: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_libcommon-buildtest_skeleton.o -MD -MP -MF test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Tpo -c -o test/test_build_libcommon-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_libcommon-buildtest_skeleton.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_libcommon-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc test/test_build_libcommon-buildtest_skeleton.obj: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_libcommon-buildtest_skeleton.obj -MD -MP -MF test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Tpo -c -o test/test_build_libcommon-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_libcommon-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_libcommon-buildtest_skeleton.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_libcommon-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` common/test_build_libcommon-DecayCounter.o: common/DecayCounter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-DecayCounter.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-DecayCounter.Tpo -c -o common/test_build_libcommon-DecayCounter.o `test -f 'common/DecayCounter.cc' || echo '$(srcdir)/'`common/DecayCounter.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-DecayCounter.Tpo common/$(DEPDIR)/test_build_libcommon-DecayCounter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/DecayCounter.cc' object='common/test_build_libcommon-DecayCounter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-DecayCounter.o `test -f 'common/DecayCounter.cc' || echo '$(srcdir)/'`common/DecayCounter.cc common/test_build_libcommon-DecayCounter.obj: common/DecayCounter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-DecayCounter.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-DecayCounter.Tpo -c -o common/test_build_libcommon-DecayCounter.obj `if test -f 'common/DecayCounter.cc'; then $(CYGPATH_W) 'common/DecayCounter.cc'; else $(CYGPATH_W) '$(srcdir)/common/DecayCounter.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-DecayCounter.Tpo common/$(DEPDIR)/test_build_libcommon-DecayCounter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/DecayCounter.cc' object='common/test_build_libcommon-DecayCounter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-DecayCounter.obj `if test -f 'common/DecayCounter.cc'; then $(CYGPATH_W) 'common/DecayCounter.cc'; else $(CYGPATH_W) '$(srcdir)/common/DecayCounter.cc'; fi` common/test_build_libcommon-LogClient.o: common/LogClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-LogClient.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-LogClient.Tpo -c -o common/test_build_libcommon-LogClient.o `test -f 'common/LogClient.cc' || echo '$(srcdir)/'`common/LogClient.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-LogClient.Tpo common/$(DEPDIR)/test_build_libcommon-LogClient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/LogClient.cc' object='common/test_build_libcommon-LogClient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-LogClient.o `test -f 'common/LogClient.cc' || echo '$(srcdir)/'`common/LogClient.cc common/test_build_libcommon-LogClient.obj: common/LogClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-LogClient.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-LogClient.Tpo -c -o common/test_build_libcommon-LogClient.obj `if test -f 'common/LogClient.cc'; then $(CYGPATH_W) 'common/LogClient.cc'; else $(CYGPATH_W) '$(srcdir)/common/LogClient.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-LogClient.Tpo common/$(DEPDIR)/test_build_libcommon-LogClient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/LogClient.cc' object='common/test_build_libcommon-LogClient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-LogClient.obj `if test -f 'common/LogClient.cc'; then $(CYGPATH_W) 'common/LogClient.cc'; else $(CYGPATH_W) '$(srcdir)/common/LogClient.cc'; fi` common/test_build_libcommon-LogEntry.o: common/LogEntry.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-LogEntry.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-LogEntry.Tpo -c -o common/test_build_libcommon-LogEntry.o `test -f 'common/LogEntry.cc' || echo '$(srcdir)/'`common/LogEntry.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-LogEntry.Tpo common/$(DEPDIR)/test_build_libcommon-LogEntry.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/LogEntry.cc' object='common/test_build_libcommon-LogEntry.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-LogEntry.o `test -f 'common/LogEntry.cc' || echo '$(srcdir)/'`common/LogEntry.cc common/test_build_libcommon-LogEntry.obj: common/LogEntry.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-LogEntry.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-LogEntry.Tpo -c -o common/test_build_libcommon-LogEntry.obj `if test -f 'common/LogEntry.cc'; then $(CYGPATH_W) 'common/LogEntry.cc'; else $(CYGPATH_W) '$(srcdir)/common/LogEntry.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-LogEntry.Tpo common/$(DEPDIR)/test_build_libcommon-LogEntry.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/LogEntry.cc' object='common/test_build_libcommon-LogEntry.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-LogEntry.obj `if test -f 'common/LogEntry.cc'; then $(CYGPATH_W) 'common/LogEntry.cc'; else $(CYGPATH_W) '$(srcdir)/common/LogEntry.cc'; fi` common/test_build_libcommon-PrebufferedStreambuf.o: common/PrebufferedStreambuf.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-PrebufferedStreambuf.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Tpo -c -o common/test_build_libcommon-PrebufferedStreambuf.o `test -f 'common/PrebufferedStreambuf.cc' || echo '$(srcdir)/'`common/PrebufferedStreambuf.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Tpo common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/PrebufferedStreambuf.cc' object='common/test_build_libcommon-PrebufferedStreambuf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-PrebufferedStreambuf.o `test -f 'common/PrebufferedStreambuf.cc' || echo '$(srcdir)/'`common/PrebufferedStreambuf.cc common/test_build_libcommon-PrebufferedStreambuf.obj: common/PrebufferedStreambuf.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-PrebufferedStreambuf.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Tpo -c -o common/test_build_libcommon-PrebufferedStreambuf.obj `if test -f 'common/PrebufferedStreambuf.cc'; then $(CYGPATH_W) 'common/PrebufferedStreambuf.cc'; else $(CYGPATH_W) '$(srcdir)/common/PrebufferedStreambuf.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Tpo common/$(DEPDIR)/test_build_libcommon-PrebufferedStreambuf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/PrebufferedStreambuf.cc' object='common/test_build_libcommon-PrebufferedStreambuf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-PrebufferedStreambuf.obj `if test -f 'common/PrebufferedStreambuf.cc'; then $(CYGPATH_W) 'common/PrebufferedStreambuf.cc'; else $(CYGPATH_W) '$(srcdir)/common/PrebufferedStreambuf.cc'; fi` common/test_build_libcommon-SloppyCRCMap.o: common/SloppyCRCMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-SloppyCRCMap.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Tpo -c -o common/test_build_libcommon-SloppyCRCMap.o `test -f 'common/SloppyCRCMap.cc' || echo '$(srcdir)/'`common/SloppyCRCMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Tpo common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/SloppyCRCMap.cc' object='common/test_build_libcommon-SloppyCRCMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-SloppyCRCMap.o `test -f 'common/SloppyCRCMap.cc' || echo '$(srcdir)/'`common/SloppyCRCMap.cc common/test_build_libcommon-SloppyCRCMap.obj: common/SloppyCRCMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-SloppyCRCMap.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Tpo -c -o common/test_build_libcommon-SloppyCRCMap.obj `if test -f 'common/SloppyCRCMap.cc'; then $(CYGPATH_W) 'common/SloppyCRCMap.cc'; else $(CYGPATH_W) '$(srcdir)/common/SloppyCRCMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Tpo common/$(DEPDIR)/test_build_libcommon-SloppyCRCMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/SloppyCRCMap.cc' object='common/test_build_libcommon-SloppyCRCMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-SloppyCRCMap.obj `if test -f 'common/SloppyCRCMap.cc'; then $(CYGPATH_W) 'common/SloppyCRCMap.cc'; else $(CYGPATH_W) '$(srcdir)/common/SloppyCRCMap.cc'; fi` common/test_build_libcommon-BackTrace.o: common/BackTrace.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-BackTrace.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-BackTrace.Tpo -c -o common/test_build_libcommon-BackTrace.o `test -f 'common/BackTrace.cc' || echo '$(srcdir)/'`common/BackTrace.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-BackTrace.Tpo common/$(DEPDIR)/test_build_libcommon-BackTrace.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/BackTrace.cc' object='common/test_build_libcommon-BackTrace.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-BackTrace.o `test -f 'common/BackTrace.cc' || echo '$(srcdir)/'`common/BackTrace.cc common/test_build_libcommon-BackTrace.obj: common/BackTrace.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-BackTrace.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-BackTrace.Tpo -c -o common/test_build_libcommon-BackTrace.obj `if test -f 'common/BackTrace.cc'; then $(CYGPATH_W) 'common/BackTrace.cc'; else $(CYGPATH_W) '$(srcdir)/common/BackTrace.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-BackTrace.Tpo common/$(DEPDIR)/test_build_libcommon-BackTrace.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/BackTrace.cc' object='common/test_build_libcommon-BackTrace.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-BackTrace.obj `if test -f 'common/BackTrace.cc'; then $(CYGPATH_W) 'common/BackTrace.cc'; else $(CYGPATH_W) '$(srcdir)/common/BackTrace.cc'; fi` common/test_build_libcommon-perf_counters.o: common/perf_counters.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-perf_counters.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-perf_counters.Tpo -c -o common/test_build_libcommon-perf_counters.o `test -f 'common/perf_counters.cc' || echo '$(srcdir)/'`common/perf_counters.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-perf_counters.Tpo common/$(DEPDIR)/test_build_libcommon-perf_counters.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/perf_counters.cc' object='common/test_build_libcommon-perf_counters.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-perf_counters.o `test -f 'common/perf_counters.cc' || echo '$(srcdir)/'`common/perf_counters.cc common/test_build_libcommon-perf_counters.obj: common/perf_counters.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-perf_counters.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-perf_counters.Tpo -c -o common/test_build_libcommon-perf_counters.obj `if test -f 'common/perf_counters.cc'; then $(CYGPATH_W) 'common/perf_counters.cc'; else $(CYGPATH_W) '$(srcdir)/common/perf_counters.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-perf_counters.Tpo common/$(DEPDIR)/test_build_libcommon-perf_counters.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/perf_counters.cc' object='common/test_build_libcommon-perf_counters.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-perf_counters.obj `if test -f 'common/perf_counters.cc'; then $(CYGPATH_W) 'common/perf_counters.cc'; else $(CYGPATH_W) '$(srcdir)/common/perf_counters.cc'; fi` common/test_build_libcommon-Mutex.o: common/Mutex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Mutex.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Mutex.Tpo -c -o common/test_build_libcommon-Mutex.o `test -f 'common/Mutex.cc' || echo '$(srcdir)/'`common/Mutex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Mutex.Tpo common/$(DEPDIR)/test_build_libcommon-Mutex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Mutex.cc' object='common/test_build_libcommon-Mutex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Mutex.o `test -f 'common/Mutex.cc' || echo '$(srcdir)/'`common/Mutex.cc common/test_build_libcommon-Mutex.obj: common/Mutex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Mutex.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Mutex.Tpo -c -o common/test_build_libcommon-Mutex.obj `if test -f 'common/Mutex.cc'; then $(CYGPATH_W) 'common/Mutex.cc'; else $(CYGPATH_W) '$(srcdir)/common/Mutex.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Mutex.Tpo common/$(DEPDIR)/test_build_libcommon-Mutex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Mutex.cc' object='common/test_build_libcommon-Mutex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Mutex.obj `if test -f 'common/Mutex.cc'; then $(CYGPATH_W) 'common/Mutex.cc'; else $(CYGPATH_W) '$(srcdir)/common/Mutex.cc'; fi` common/test_build_libcommon-OutputDataSocket.o: common/OutputDataSocket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-OutputDataSocket.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Tpo -c -o common/test_build_libcommon-OutputDataSocket.o `test -f 'common/OutputDataSocket.cc' || echo '$(srcdir)/'`common/OutputDataSocket.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Tpo common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/OutputDataSocket.cc' object='common/test_build_libcommon-OutputDataSocket.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-OutputDataSocket.o `test -f 'common/OutputDataSocket.cc' || echo '$(srcdir)/'`common/OutputDataSocket.cc common/test_build_libcommon-OutputDataSocket.obj: common/OutputDataSocket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-OutputDataSocket.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Tpo -c -o common/test_build_libcommon-OutputDataSocket.obj `if test -f 'common/OutputDataSocket.cc'; then $(CYGPATH_W) 'common/OutputDataSocket.cc'; else $(CYGPATH_W) '$(srcdir)/common/OutputDataSocket.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Tpo common/$(DEPDIR)/test_build_libcommon-OutputDataSocket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/OutputDataSocket.cc' object='common/test_build_libcommon-OutputDataSocket.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-OutputDataSocket.obj `if test -f 'common/OutputDataSocket.cc'; then $(CYGPATH_W) 'common/OutputDataSocket.cc'; else $(CYGPATH_W) '$(srcdir)/common/OutputDataSocket.cc'; fi` common/test_build_libcommon-admin_socket.o: common/admin_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-admin_socket.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-admin_socket.Tpo -c -o common/test_build_libcommon-admin_socket.o `test -f 'common/admin_socket.cc' || echo '$(srcdir)/'`common/admin_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-admin_socket.Tpo common/$(DEPDIR)/test_build_libcommon-admin_socket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/admin_socket.cc' object='common/test_build_libcommon-admin_socket.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-admin_socket.o `test -f 'common/admin_socket.cc' || echo '$(srcdir)/'`common/admin_socket.cc common/test_build_libcommon-admin_socket.obj: common/admin_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-admin_socket.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-admin_socket.Tpo -c -o common/test_build_libcommon-admin_socket.obj `if test -f 'common/admin_socket.cc'; then $(CYGPATH_W) 'common/admin_socket.cc'; else $(CYGPATH_W) '$(srcdir)/common/admin_socket.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-admin_socket.Tpo common/$(DEPDIR)/test_build_libcommon-admin_socket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/admin_socket.cc' object='common/test_build_libcommon-admin_socket.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-admin_socket.obj `if test -f 'common/admin_socket.cc'; then $(CYGPATH_W) 'common/admin_socket.cc'; else $(CYGPATH_W) '$(srcdir)/common/admin_socket.cc'; fi` common/test_build_libcommon-admin_socket_client.o: common/admin_socket_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-admin_socket_client.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Tpo -c -o common/test_build_libcommon-admin_socket_client.o `test -f 'common/admin_socket_client.cc' || echo '$(srcdir)/'`common/admin_socket_client.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Tpo common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/admin_socket_client.cc' object='common/test_build_libcommon-admin_socket_client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-admin_socket_client.o `test -f 'common/admin_socket_client.cc' || echo '$(srcdir)/'`common/admin_socket_client.cc common/test_build_libcommon-admin_socket_client.obj: common/admin_socket_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-admin_socket_client.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Tpo -c -o common/test_build_libcommon-admin_socket_client.obj `if test -f 'common/admin_socket_client.cc'; then $(CYGPATH_W) 'common/admin_socket_client.cc'; else $(CYGPATH_W) '$(srcdir)/common/admin_socket_client.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Tpo common/$(DEPDIR)/test_build_libcommon-admin_socket_client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/admin_socket_client.cc' object='common/test_build_libcommon-admin_socket_client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-admin_socket_client.obj `if test -f 'common/admin_socket_client.cc'; then $(CYGPATH_W) 'common/admin_socket_client.cc'; else $(CYGPATH_W) '$(srcdir)/common/admin_socket_client.cc'; fi` common/test_build_libcommon-cmdparse.o: common/cmdparse.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-cmdparse.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-cmdparse.Tpo -c -o common/test_build_libcommon-cmdparse.o `test -f 'common/cmdparse.cc' || echo '$(srcdir)/'`common/cmdparse.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-cmdparse.Tpo common/$(DEPDIR)/test_build_libcommon-cmdparse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/cmdparse.cc' object='common/test_build_libcommon-cmdparse.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-cmdparse.o `test -f 'common/cmdparse.cc' || echo '$(srcdir)/'`common/cmdparse.cc common/test_build_libcommon-cmdparse.obj: common/cmdparse.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-cmdparse.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-cmdparse.Tpo -c -o common/test_build_libcommon-cmdparse.obj `if test -f 'common/cmdparse.cc'; then $(CYGPATH_W) 'common/cmdparse.cc'; else $(CYGPATH_W) '$(srcdir)/common/cmdparse.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-cmdparse.Tpo common/$(DEPDIR)/test_build_libcommon-cmdparse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/cmdparse.cc' object='common/test_build_libcommon-cmdparse.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-cmdparse.obj `if test -f 'common/cmdparse.cc'; then $(CYGPATH_W) 'common/cmdparse.cc'; else $(CYGPATH_W) '$(srcdir)/common/cmdparse.cc'; fi` common/test_build_libcommon-io_priority.o: common/io_priority.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-io_priority.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-io_priority.Tpo -c -o common/test_build_libcommon-io_priority.o `test -f 'common/io_priority.cc' || echo '$(srcdir)/'`common/io_priority.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-io_priority.Tpo common/$(DEPDIR)/test_build_libcommon-io_priority.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/io_priority.cc' object='common/test_build_libcommon-io_priority.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-io_priority.o `test -f 'common/io_priority.cc' || echo '$(srcdir)/'`common/io_priority.cc common/test_build_libcommon-io_priority.obj: common/io_priority.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-io_priority.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-io_priority.Tpo -c -o common/test_build_libcommon-io_priority.obj `if test -f 'common/io_priority.cc'; then $(CYGPATH_W) 'common/io_priority.cc'; else $(CYGPATH_W) '$(srcdir)/common/io_priority.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-io_priority.Tpo common/$(DEPDIR)/test_build_libcommon-io_priority.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/io_priority.cc' object='common/test_build_libcommon-io_priority.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-io_priority.obj `if test -f 'common/io_priority.cc'; then $(CYGPATH_W) 'common/io_priority.cc'; else $(CYGPATH_W) '$(srcdir)/common/io_priority.cc'; fi` common/test_build_libcommon-Clock.o: common/Clock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Clock.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Clock.Tpo -c -o common/test_build_libcommon-Clock.o `test -f 'common/Clock.cc' || echo '$(srcdir)/'`common/Clock.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Clock.Tpo common/$(DEPDIR)/test_build_libcommon-Clock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Clock.cc' object='common/test_build_libcommon-Clock.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Clock.o `test -f 'common/Clock.cc' || echo '$(srcdir)/'`common/Clock.cc common/test_build_libcommon-Clock.obj: common/Clock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Clock.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Clock.Tpo -c -o common/test_build_libcommon-Clock.obj `if test -f 'common/Clock.cc'; then $(CYGPATH_W) 'common/Clock.cc'; else $(CYGPATH_W) '$(srcdir)/common/Clock.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Clock.Tpo common/$(DEPDIR)/test_build_libcommon-Clock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Clock.cc' object='common/test_build_libcommon-Clock.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Clock.obj `if test -f 'common/Clock.cc'; then $(CYGPATH_W) 'common/Clock.cc'; else $(CYGPATH_W) '$(srcdir)/common/Clock.cc'; fi` common/test_build_libcommon-Throttle.o: common/Throttle.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Throttle.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Throttle.Tpo -c -o common/test_build_libcommon-Throttle.o `test -f 'common/Throttle.cc' || echo '$(srcdir)/'`common/Throttle.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Throttle.Tpo common/$(DEPDIR)/test_build_libcommon-Throttle.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Throttle.cc' object='common/test_build_libcommon-Throttle.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Throttle.o `test -f 'common/Throttle.cc' || echo '$(srcdir)/'`common/Throttle.cc common/test_build_libcommon-Throttle.obj: common/Throttle.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Throttle.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Throttle.Tpo -c -o common/test_build_libcommon-Throttle.obj `if test -f 'common/Throttle.cc'; then $(CYGPATH_W) 'common/Throttle.cc'; else $(CYGPATH_W) '$(srcdir)/common/Throttle.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Throttle.Tpo common/$(DEPDIR)/test_build_libcommon-Throttle.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Throttle.cc' object='common/test_build_libcommon-Throttle.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Throttle.obj `if test -f 'common/Throttle.cc'; then $(CYGPATH_W) 'common/Throttle.cc'; else $(CYGPATH_W) '$(srcdir)/common/Throttle.cc'; fi` common/test_build_libcommon-Timer.o: common/Timer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Timer.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Timer.Tpo -c -o common/test_build_libcommon-Timer.o `test -f 'common/Timer.cc' || echo '$(srcdir)/'`common/Timer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Timer.Tpo common/$(DEPDIR)/test_build_libcommon-Timer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Timer.cc' object='common/test_build_libcommon-Timer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Timer.o `test -f 'common/Timer.cc' || echo '$(srcdir)/'`common/Timer.cc common/test_build_libcommon-Timer.obj: common/Timer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Timer.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Timer.Tpo -c -o common/test_build_libcommon-Timer.obj `if test -f 'common/Timer.cc'; then $(CYGPATH_W) 'common/Timer.cc'; else $(CYGPATH_W) '$(srcdir)/common/Timer.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Timer.Tpo common/$(DEPDIR)/test_build_libcommon-Timer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Timer.cc' object='common/test_build_libcommon-Timer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Timer.obj `if test -f 'common/Timer.cc'; then $(CYGPATH_W) 'common/Timer.cc'; else $(CYGPATH_W) '$(srcdir)/common/Timer.cc'; fi` common/test_build_libcommon-Finisher.o: common/Finisher.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Finisher.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Finisher.Tpo -c -o common/test_build_libcommon-Finisher.o `test -f 'common/Finisher.cc' || echo '$(srcdir)/'`common/Finisher.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Finisher.Tpo common/$(DEPDIR)/test_build_libcommon-Finisher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Finisher.cc' object='common/test_build_libcommon-Finisher.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Finisher.o `test -f 'common/Finisher.cc' || echo '$(srcdir)/'`common/Finisher.cc common/test_build_libcommon-Finisher.obj: common/Finisher.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Finisher.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Finisher.Tpo -c -o common/test_build_libcommon-Finisher.obj `if test -f 'common/Finisher.cc'; then $(CYGPATH_W) 'common/Finisher.cc'; else $(CYGPATH_W) '$(srcdir)/common/Finisher.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Finisher.Tpo common/$(DEPDIR)/test_build_libcommon-Finisher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Finisher.cc' object='common/test_build_libcommon-Finisher.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Finisher.obj `if test -f 'common/Finisher.cc'; then $(CYGPATH_W) 'common/Finisher.cc'; else $(CYGPATH_W) '$(srcdir)/common/Finisher.cc'; fi` common/test_build_libcommon-environment.o: common/environment.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-environment.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-environment.Tpo -c -o common/test_build_libcommon-environment.o `test -f 'common/environment.cc' || echo '$(srcdir)/'`common/environment.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-environment.Tpo common/$(DEPDIR)/test_build_libcommon-environment.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/environment.cc' object='common/test_build_libcommon-environment.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-environment.o `test -f 'common/environment.cc' || echo '$(srcdir)/'`common/environment.cc common/test_build_libcommon-environment.obj: common/environment.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-environment.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-environment.Tpo -c -o common/test_build_libcommon-environment.obj `if test -f 'common/environment.cc'; then $(CYGPATH_W) 'common/environment.cc'; else $(CYGPATH_W) '$(srcdir)/common/environment.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-environment.Tpo common/$(DEPDIR)/test_build_libcommon-environment.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/environment.cc' object='common/test_build_libcommon-environment.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-environment.obj `if test -f 'common/environment.cc'; then $(CYGPATH_W) 'common/environment.cc'; else $(CYGPATH_W) '$(srcdir)/common/environment.cc'; fi` common/test_build_libcommon-assert.o: common/assert.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-assert.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-assert.Tpo -c -o common/test_build_libcommon-assert.o `test -f 'common/assert.cc' || echo '$(srcdir)/'`common/assert.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-assert.Tpo common/$(DEPDIR)/test_build_libcommon-assert.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/assert.cc' object='common/test_build_libcommon-assert.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-assert.o `test -f 'common/assert.cc' || echo '$(srcdir)/'`common/assert.cc common/test_build_libcommon-assert.obj: common/assert.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-assert.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-assert.Tpo -c -o common/test_build_libcommon-assert.obj `if test -f 'common/assert.cc'; then $(CYGPATH_W) 'common/assert.cc'; else $(CYGPATH_W) '$(srcdir)/common/assert.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-assert.Tpo common/$(DEPDIR)/test_build_libcommon-assert.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/assert.cc' object='common/test_build_libcommon-assert.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-assert.obj `if test -f 'common/assert.cc'; then $(CYGPATH_W) 'common/assert.cc'; else $(CYGPATH_W) '$(srcdir)/common/assert.cc'; fi` common/test_build_libcommon-run_cmd.o: common/run_cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-run_cmd.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-run_cmd.Tpo -c -o common/test_build_libcommon-run_cmd.o `test -f 'common/run_cmd.cc' || echo '$(srcdir)/'`common/run_cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-run_cmd.Tpo common/$(DEPDIR)/test_build_libcommon-run_cmd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/run_cmd.cc' object='common/test_build_libcommon-run_cmd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-run_cmd.o `test -f 'common/run_cmd.cc' || echo '$(srcdir)/'`common/run_cmd.cc common/test_build_libcommon-run_cmd.obj: common/run_cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-run_cmd.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-run_cmd.Tpo -c -o common/test_build_libcommon-run_cmd.obj `if test -f 'common/run_cmd.cc'; then $(CYGPATH_W) 'common/run_cmd.cc'; else $(CYGPATH_W) '$(srcdir)/common/run_cmd.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-run_cmd.Tpo common/$(DEPDIR)/test_build_libcommon-run_cmd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/run_cmd.cc' object='common/test_build_libcommon-run_cmd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-run_cmd.obj `if test -f 'common/run_cmd.cc'; then $(CYGPATH_W) 'common/run_cmd.cc'; else $(CYGPATH_W) '$(srcdir)/common/run_cmd.cc'; fi` common/test_build_libcommon-WorkQueue.o: common/WorkQueue.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-WorkQueue.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-WorkQueue.Tpo -c -o common/test_build_libcommon-WorkQueue.o `test -f 'common/WorkQueue.cc' || echo '$(srcdir)/'`common/WorkQueue.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-WorkQueue.Tpo common/$(DEPDIR)/test_build_libcommon-WorkQueue.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/WorkQueue.cc' object='common/test_build_libcommon-WorkQueue.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-WorkQueue.o `test -f 'common/WorkQueue.cc' || echo '$(srcdir)/'`common/WorkQueue.cc common/test_build_libcommon-WorkQueue.obj: common/WorkQueue.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-WorkQueue.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-WorkQueue.Tpo -c -o common/test_build_libcommon-WorkQueue.obj `if test -f 'common/WorkQueue.cc'; then $(CYGPATH_W) 'common/WorkQueue.cc'; else $(CYGPATH_W) '$(srcdir)/common/WorkQueue.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-WorkQueue.Tpo common/$(DEPDIR)/test_build_libcommon-WorkQueue.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/WorkQueue.cc' object='common/test_build_libcommon-WorkQueue.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-WorkQueue.obj `if test -f 'common/WorkQueue.cc'; then $(CYGPATH_W) 'common/WorkQueue.cc'; else $(CYGPATH_W) '$(srcdir)/common/WorkQueue.cc'; fi` common/test_build_libcommon-ConfUtils.o: common/ConfUtils.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ConfUtils.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ConfUtils.Tpo -c -o common/test_build_libcommon-ConfUtils.o `test -f 'common/ConfUtils.cc' || echo '$(srcdir)/'`common/ConfUtils.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ConfUtils.Tpo common/$(DEPDIR)/test_build_libcommon-ConfUtils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ConfUtils.cc' object='common/test_build_libcommon-ConfUtils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ConfUtils.o `test -f 'common/ConfUtils.cc' || echo '$(srcdir)/'`common/ConfUtils.cc common/test_build_libcommon-ConfUtils.obj: common/ConfUtils.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ConfUtils.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ConfUtils.Tpo -c -o common/test_build_libcommon-ConfUtils.obj `if test -f 'common/ConfUtils.cc'; then $(CYGPATH_W) 'common/ConfUtils.cc'; else $(CYGPATH_W) '$(srcdir)/common/ConfUtils.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ConfUtils.Tpo common/$(DEPDIR)/test_build_libcommon-ConfUtils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ConfUtils.cc' object='common/test_build_libcommon-ConfUtils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ConfUtils.obj `if test -f 'common/ConfUtils.cc'; then $(CYGPATH_W) 'common/ConfUtils.cc'; else $(CYGPATH_W) '$(srcdir)/common/ConfUtils.cc'; fi` common/test_build_libcommon-MemoryModel.o: common/MemoryModel.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-MemoryModel.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-MemoryModel.Tpo -c -o common/test_build_libcommon-MemoryModel.o `test -f 'common/MemoryModel.cc' || echo '$(srcdir)/'`common/MemoryModel.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-MemoryModel.Tpo common/$(DEPDIR)/test_build_libcommon-MemoryModel.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/MemoryModel.cc' object='common/test_build_libcommon-MemoryModel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-MemoryModel.o `test -f 'common/MemoryModel.cc' || echo '$(srcdir)/'`common/MemoryModel.cc common/test_build_libcommon-MemoryModel.obj: common/MemoryModel.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-MemoryModel.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-MemoryModel.Tpo -c -o common/test_build_libcommon-MemoryModel.obj `if test -f 'common/MemoryModel.cc'; then $(CYGPATH_W) 'common/MemoryModel.cc'; else $(CYGPATH_W) '$(srcdir)/common/MemoryModel.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-MemoryModel.Tpo common/$(DEPDIR)/test_build_libcommon-MemoryModel.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/MemoryModel.cc' object='common/test_build_libcommon-MemoryModel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-MemoryModel.obj `if test -f 'common/MemoryModel.cc'; then $(CYGPATH_W) 'common/MemoryModel.cc'; else $(CYGPATH_W) '$(srcdir)/common/MemoryModel.cc'; fi` common/test_build_libcommon-fd.o: common/fd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-fd.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-fd.Tpo -c -o common/test_build_libcommon-fd.o `test -f 'common/fd.cc' || echo '$(srcdir)/'`common/fd.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-fd.Tpo common/$(DEPDIR)/test_build_libcommon-fd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/fd.cc' object='common/test_build_libcommon-fd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-fd.o `test -f 'common/fd.cc' || echo '$(srcdir)/'`common/fd.cc common/test_build_libcommon-fd.obj: common/fd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-fd.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-fd.Tpo -c -o common/test_build_libcommon-fd.obj `if test -f 'common/fd.cc'; then $(CYGPATH_W) 'common/fd.cc'; else $(CYGPATH_W) '$(srcdir)/common/fd.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-fd.Tpo common/$(DEPDIR)/test_build_libcommon-fd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/fd.cc' object='common/test_build_libcommon-fd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-fd.obj `if test -f 'common/fd.cc'; then $(CYGPATH_W) 'common/fd.cc'; else $(CYGPATH_W) '$(srcdir)/common/fd.cc'; fi` common/test_build_libcommon-snap_types.o: common/snap_types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-snap_types.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-snap_types.Tpo -c -o common/test_build_libcommon-snap_types.o `test -f 'common/snap_types.cc' || echo '$(srcdir)/'`common/snap_types.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-snap_types.Tpo common/$(DEPDIR)/test_build_libcommon-snap_types.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/snap_types.cc' object='common/test_build_libcommon-snap_types.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-snap_types.o `test -f 'common/snap_types.cc' || echo '$(srcdir)/'`common/snap_types.cc common/test_build_libcommon-snap_types.obj: common/snap_types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-snap_types.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-snap_types.Tpo -c -o common/test_build_libcommon-snap_types.obj `if test -f 'common/snap_types.cc'; then $(CYGPATH_W) 'common/snap_types.cc'; else $(CYGPATH_W) '$(srcdir)/common/snap_types.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-snap_types.Tpo common/$(DEPDIR)/test_build_libcommon-snap_types.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/snap_types.cc' object='common/test_build_libcommon-snap_types.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-snap_types.obj `if test -f 'common/snap_types.cc'; then $(CYGPATH_W) 'common/snap_types.cc'; else $(CYGPATH_W) '$(srcdir)/common/snap_types.cc'; fi` common/test_build_libcommon-str_list.o: common/str_list.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-str_list.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-str_list.Tpo -c -o common/test_build_libcommon-str_list.o `test -f 'common/str_list.cc' || echo '$(srcdir)/'`common/str_list.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-str_list.Tpo common/$(DEPDIR)/test_build_libcommon-str_list.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/str_list.cc' object='common/test_build_libcommon-str_list.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-str_list.o `test -f 'common/str_list.cc' || echo '$(srcdir)/'`common/str_list.cc common/test_build_libcommon-str_list.obj: common/str_list.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-str_list.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-str_list.Tpo -c -o common/test_build_libcommon-str_list.obj `if test -f 'common/str_list.cc'; then $(CYGPATH_W) 'common/str_list.cc'; else $(CYGPATH_W) '$(srcdir)/common/str_list.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-str_list.Tpo common/$(DEPDIR)/test_build_libcommon-str_list.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/str_list.cc' object='common/test_build_libcommon-str_list.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-str_list.obj `if test -f 'common/str_list.cc'; then $(CYGPATH_W) 'common/str_list.cc'; else $(CYGPATH_W) '$(srcdir)/common/str_list.cc'; fi` common/test_build_libcommon-str_map.o: common/str_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-str_map.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-str_map.Tpo -c -o common/test_build_libcommon-str_map.o `test -f 'common/str_map.cc' || echo '$(srcdir)/'`common/str_map.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-str_map.Tpo common/$(DEPDIR)/test_build_libcommon-str_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/str_map.cc' object='common/test_build_libcommon-str_map.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-str_map.o `test -f 'common/str_map.cc' || echo '$(srcdir)/'`common/str_map.cc common/test_build_libcommon-str_map.obj: common/str_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-str_map.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-str_map.Tpo -c -o common/test_build_libcommon-str_map.obj `if test -f 'common/str_map.cc'; then $(CYGPATH_W) 'common/str_map.cc'; else $(CYGPATH_W) '$(srcdir)/common/str_map.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-str_map.Tpo common/$(DEPDIR)/test_build_libcommon-str_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/str_map.cc' object='common/test_build_libcommon-str_map.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-str_map.obj `if test -f 'common/str_map.cc'; then $(CYGPATH_W) 'common/str_map.cc'; else $(CYGPATH_W) '$(srcdir)/common/str_map.cc'; fi` common/test_build_libcommon-errno.o: common/errno.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-errno.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-errno.Tpo -c -o common/test_build_libcommon-errno.o `test -f 'common/errno.cc' || echo '$(srcdir)/'`common/errno.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-errno.Tpo common/$(DEPDIR)/test_build_libcommon-errno.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/errno.cc' object='common/test_build_libcommon-errno.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-errno.o `test -f 'common/errno.cc' || echo '$(srcdir)/'`common/errno.cc common/test_build_libcommon-errno.obj: common/errno.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-errno.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-errno.Tpo -c -o common/test_build_libcommon-errno.obj `if test -f 'common/errno.cc'; then $(CYGPATH_W) 'common/errno.cc'; else $(CYGPATH_W) '$(srcdir)/common/errno.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-errno.Tpo common/$(DEPDIR)/test_build_libcommon-errno.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/errno.cc' object='common/test_build_libcommon-errno.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-errno.obj `if test -f 'common/errno.cc'; then $(CYGPATH_W) 'common/errno.cc'; else $(CYGPATH_W) '$(srcdir)/common/errno.cc'; fi` common/test_build_libcommon-RefCountedObj.o: common/RefCountedObj.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-RefCountedObj.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Tpo -c -o common/test_build_libcommon-RefCountedObj.o `test -f 'common/RefCountedObj.cc' || echo '$(srcdir)/'`common/RefCountedObj.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Tpo common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/RefCountedObj.cc' object='common/test_build_libcommon-RefCountedObj.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-RefCountedObj.o `test -f 'common/RefCountedObj.cc' || echo '$(srcdir)/'`common/RefCountedObj.cc common/test_build_libcommon-RefCountedObj.obj: common/RefCountedObj.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-RefCountedObj.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Tpo -c -o common/test_build_libcommon-RefCountedObj.obj `if test -f 'common/RefCountedObj.cc'; then $(CYGPATH_W) 'common/RefCountedObj.cc'; else $(CYGPATH_W) '$(srcdir)/common/RefCountedObj.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Tpo common/$(DEPDIR)/test_build_libcommon-RefCountedObj.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/RefCountedObj.cc' object='common/test_build_libcommon-RefCountedObj.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-RefCountedObj.obj `if test -f 'common/RefCountedObj.cc'; then $(CYGPATH_W) 'common/RefCountedObj.cc'; else $(CYGPATH_W) '$(srcdir)/common/RefCountedObj.cc'; fi` common/test_build_libcommon-blkdev.o: common/blkdev.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-blkdev.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-blkdev.Tpo -c -o common/test_build_libcommon-blkdev.o `test -f 'common/blkdev.cc' || echo '$(srcdir)/'`common/blkdev.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-blkdev.Tpo common/$(DEPDIR)/test_build_libcommon-blkdev.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/blkdev.cc' object='common/test_build_libcommon-blkdev.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-blkdev.o `test -f 'common/blkdev.cc' || echo '$(srcdir)/'`common/blkdev.cc common/test_build_libcommon-blkdev.obj: common/blkdev.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-blkdev.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-blkdev.Tpo -c -o common/test_build_libcommon-blkdev.obj `if test -f 'common/blkdev.cc'; then $(CYGPATH_W) 'common/blkdev.cc'; else $(CYGPATH_W) '$(srcdir)/common/blkdev.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-blkdev.Tpo common/$(DEPDIR)/test_build_libcommon-blkdev.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/blkdev.cc' object='common/test_build_libcommon-blkdev.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-blkdev.obj `if test -f 'common/blkdev.cc'; then $(CYGPATH_W) 'common/blkdev.cc'; else $(CYGPATH_W) '$(srcdir)/common/blkdev.cc'; fi` common/test_build_libcommon-common_init.o: common/common_init.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-common_init.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-common_init.Tpo -c -o common/test_build_libcommon-common_init.o `test -f 'common/common_init.cc' || echo '$(srcdir)/'`common/common_init.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-common_init.Tpo common/$(DEPDIR)/test_build_libcommon-common_init.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/common_init.cc' object='common/test_build_libcommon-common_init.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-common_init.o `test -f 'common/common_init.cc' || echo '$(srcdir)/'`common/common_init.cc common/test_build_libcommon-common_init.obj: common/common_init.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-common_init.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-common_init.Tpo -c -o common/test_build_libcommon-common_init.obj `if test -f 'common/common_init.cc'; then $(CYGPATH_W) 'common/common_init.cc'; else $(CYGPATH_W) '$(srcdir)/common/common_init.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-common_init.Tpo common/$(DEPDIR)/test_build_libcommon-common_init.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/common_init.cc' object='common/test_build_libcommon-common_init.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-common_init.obj `if test -f 'common/common_init.cc'; then $(CYGPATH_W) 'common/common_init.cc'; else $(CYGPATH_W) '$(srcdir)/common/common_init.cc'; fi` common/test_build_libcommon-ceph_argparse.o: common/ceph_argparse.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_argparse.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Tpo -c -o common/test_build_libcommon-ceph_argparse.o `test -f 'common/ceph_argparse.cc' || echo '$(srcdir)/'`common/ceph_argparse.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_argparse.cc' object='common/test_build_libcommon-ceph_argparse.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_argparse.o `test -f 'common/ceph_argparse.cc' || echo '$(srcdir)/'`common/ceph_argparse.cc common/test_build_libcommon-ceph_argparse.obj: common/ceph_argparse.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_argparse.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Tpo -c -o common/test_build_libcommon-ceph_argparse.obj `if test -f 'common/ceph_argparse.cc'; then $(CYGPATH_W) 'common/ceph_argparse.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_argparse.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_argparse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_argparse.cc' object='common/test_build_libcommon-ceph_argparse.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_argparse.obj `if test -f 'common/ceph_argparse.cc'; then $(CYGPATH_W) 'common/ceph_argparse.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_argparse.cc'; fi` common/test_build_libcommon-ceph_context.o: common/ceph_context.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_context.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_context.Tpo -c -o common/test_build_libcommon-ceph_context.o `test -f 'common/ceph_context.cc' || echo '$(srcdir)/'`common/ceph_context.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_context.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_context.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_context.cc' object='common/test_build_libcommon-ceph_context.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_context.o `test -f 'common/ceph_context.cc' || echo '$(srcdir)/'`common/ceph_context.cc common/test_build_libcommon-ceph_context.obj: common/ceph_context.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_context.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_context.Tpo -c -o common/test_build_libcommon-ceph_context.obj `if test -f 'common/ceph_context.cc'; then $(CYGPATH_W) 'common/ceph_context.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_context.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_context.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_context.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_context.cc' object='common/test_build_libcommon-ceph_context.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_context.obj `if test -f 'common/ceph_context.cc'; then $(CYGPATH_W) 'common/ceph_context.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_context.cc'; fi` common/test_build_libcommon-buffer.o: common/buffer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-buffer.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-buffer.Tpo -c -o common/test_build_libcommon-buffer.o `test -f 'common/buffer.cc' || echo '$(srcdir)/'`common/buffer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-buffer.Tpo common/$(DEPDIR)/test_build_libcommon-buffer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/buffer.cc' object='common/test_build_libcommon-buffer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-buffer.o `test -f 'common/buffer.cc' || echo '$(srcdir)/'`common/buffer.cc common/test_build_libcommon-buffer.obj: common/buffer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-buffer.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-buffer.Tpo -c -o common/test_build_libcommon-buffer.obj `if test -f 'common/buffer.cc'; then $(CYGPATH_W) 'common/buffer.cc'; else $(CYGPATH_W) '$(srcdir)/common/buffer.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-buffer.Tpo common/$(DEPDIR)/test_build_libcommon-buffer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/buffer.cc' object='common/test_build_libcommon-buffer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-buffer.obj `if test -f 'common/buffer.cc'; then $(CYGPATH_W) 'common/buffer.cc'; else $(CYGPATH_W) '$(srcdir)/common/buffer.cc'; fi` common/test_build_libcommon-code_environment.o: common/code_environment.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-code_environment.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-code_environment.Tpo -c -o common/test_build_libcommon-code_environment.o `test -f 'common/code_environment.cc' || echo '$(srcdir)/'`common/code_environment.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-code_environment.Tpo common/$(DEPDIR)/test_build_libcommon-code_environment.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/code_environment.cc' object='common/test_build_libcommon-code_environment.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-code_environment.o `test -f 'common/code_environment.cc' || echo '$(srcdir)/'`common/code_environment.cc common/test_build_libcommon-code_environment.obj: common/code_environment.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-code_environment.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-code_environment.Tpo -c -o common/test_build_libcommon-code_environment.obj `if test -f 'common/code_environment.cc'; then $(CYGPATH_W) 'common/code_environment.cc'; else $(CYGPATH_W) '$(srcdir)/common/code_environment.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-code_environment.Tpo common/$(DEPDIR)/test_build_libcommon-code_environment.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/code_environment.cc' object='common/test_build_libcommon-code_environment.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-code_environment.obj `if test -f 'common/code_environment.cc'; then $(CYGPATH_W) 'common/code_environment.cc'; else $(CYGPATH_W) '$(srcdir)/common/code_environment.cc'; fi` common/test_build_libcommon-dout.o: common/dout.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-dout.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-dout.Tpo -c -o common/test_build_libcommon-dout.o `test -f 'common/dout.cc' || echo '$(srcdir)/'`common/dout.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-dout.Tpo common/$(DEPDIR)/test_build_libcommon-dout.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/dout.cc' object='common/test_build_libcommon-dout.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-dout.o `test -f 'common/dout.cc' || echo '$(srcdir)/'`common/dout.cc common/test_build_libcommon-dout.obj: common/dout.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-dout.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-dout.Tpo -c -o common/test_build_libcommon-dout.obj `if test -f 'common/dout.cc'; then $(CYGPATH_W) 'common/dout.cc'; else $(CYGPATH_W) '$(srcdir)/common/dout.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-dout.Tpo common/$(DEPDIR)/test_build_libcommon-dout.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/dout.cc' object='common/test_build_libcommon-dout.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-dout.obj `if test -f 'common/dout.cc'; then $(CYGPATH_W) 'common/dout.cc'; else $(CYGPATH_W) '$(srcdir)/common/dout.cc'; fi` common/test_build_libcommon-histogram.o: common/histogram.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-histogram.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-histogram.Tpo -c -o common/test_build_libcommon-histogram.o `test -f 'common/histogram.cc' || echo '$(srcdir)/'`common/histogram.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-histogram.Tpo common/$(DEPDIR)/test_build_libcommon-histogram.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/histogram.cc' object='common/test_build_libcommon-histogram.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-histogram.o `test -f 'common/histogram.cc' || echo '$(srcdir)/'`common/histogram.cc common/test_build_libcommon-histogram.obj: common/histogram.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-histogram.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-histogram.Tpo -c -o common/test_build_libcommon-histogram.obj `if test -f 'common/histogram.cc'; then $(CYGPATH_W) 'common/histogram.cc'; else $(CYGPATH_W) '$(srcdir)/common/histogram.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-histogram.Tpo common/$(DEPDIR)/test_build_libcommon-histogram.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/histogram.cc' object='common/test_build_libcommon-histogram.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-histogram.obj `if test -f 'common/histogram.cc'; then $(CYGPATH_W) 'common/histogram.cc'; else $(CYGPATH_W) '$(srcdir)/common/histogram.cc'; fi` common/test_build_libcommon-signal.o: common/signal.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-signal.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-signal.Tpo -c -o common/test_build_libcommon-signal.o `test -f 'common/signal.cc' || echo '$(srcdir)/'`common/signal.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-signal.Tpo common/$(DEPDIR)/test_build_libcommon-signal.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/signal.cc' object='common/test_build_libcommon-signal.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-signal.o `test -f 'common/signal.cc' || echo '$(srcdir)/'`common/signal.cc common/test_build_libcommon-signal.obj: common/signal.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-signal.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-signal.Tpo -c -o common/test_build_libcommon-signal.obj `if test -f 'common/signal.cc'; then $(CYGPATH_W) 'common/signal.cc'; else $(CYGPATH_W) '$(srcdir)/common/signal.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-signal.Tpo common/$(DEPDIR)/test_build_libcommon-signal.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/signal.cc' object='common/test_build_libcommon-signal.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-signal.obj `if test -f 'common/signal.cc'; then $(CYGPATH_W) 'common/signal.cc'; else $(CYGPATH_W) '$(srcdir)/common/signal.cc'; fi` common/test_build_libcommon-simple_spin.o: common/simple_spin.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-simple_spin.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-simple_spin.Tpo -c -o common/test_build_libcommon-simple_spin.o `test -f 'common/simple_spin.cc' || echo '$(srcdir)/'`common/simple_spin.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-simple_spin.Tpo common/$(DEPDIR)/test_build_libcommon-simple_spin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/simple_spin.cc' object='common/test_build_libcommon-simple_spin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-simple_spin.o `test -f 'common/simple_spin.cc' || echo '$(srcdir)/'`common/simple_spin.cc common/test_build_libcommon-simple_spin.obj: common/simple_spin.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-simple_spin.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-simple_spin.Tpo -c -o common/test_build_libcommon-simple_spin.obj `if test -f 'common/simple_spin.cc'; then $(CYGPATH_W) 'common/simple_spin.cc'; else $(CYGPATH_W) '$(srcdir)/common/simple_spin.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-simple_spin.Tpo common/$(DEPDIR)/test_build_libcommon-simple_spin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/simple_spin.cc' object='common/test_build_libcommon-simple_spin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-simple_spin.obj `if test -f 'common/simple_spin.cc'; then $(CYGPATH_W) 'common/simple_spin.cc'; else $(CYGPATH_W) '$(srcdir)/common/simple_spin.cc'; fi` common/test_build_libcommon-Thread.o: common/Thread.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Thread.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Thread.Tpo -c -o common/test_build_libcommon-Thread.o `test -f 'common/Thread.cc' || echo '$(srcdir)/'`common/Thread.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Thread.Tpo common/$(DEPDIR)/test_build_libcommon-Thread.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Thread.cc' object='common/test_build_libcommon-Thread.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Thread.o `test -f 'common/Thread.cc' || echo '$(srcdir)/'`common/Thread.cc common/test_build_libcommon-Thread.obj: common/Thread.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Thread.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Thread.Tpo -c -o common/test_build_libcommon-Thread.obj `if test -f 'common/Thread.cc'; then $(CYGPATH_W) 'common/Thread.cc'; else $(CYGPATH_W) '$(srcdir)/common/Thread.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Thread.Tpo common/$(DEPDIR)/test_build_libcommon-Thread.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Thread.cc' object='common/test_build_libcommon-Thread.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Thread.obj `if test -f 'common/Thread.cc'; then $(CYGPATH_W) 'common/Thread.cc'; else $(CYGPATH_W) '$(srcdir)/common/Thread.cc'; fi` common/test_build_libcommon-Formatter.o: common/Formatter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Formatter.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Formatter.Tpo -c -o common/test_build_libcommon-Formatter.o `test -f 'common/Formatter.cc' || echo '$(srcdir)/'`common/Formatter.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Formatter.Tpo common/$(DEPDIR)/test_build_libcommon-Formatter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Formatter.cc' object='common/test_build_libcommon-Formatter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Formatter.o `test -f 'common/Formatter.cc' || echo '$(srcdir)/'`common/Formatter.cc common/test_build_libcommon-Formatter.obj: common/Formatter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-Formatter.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-Formatter.Tpo -c -o common/test_build_libcommon-Formatter.obj `if test -f 'common/Formatter.cc'; then $(CYGPATH_W) 'common/Formatter.cc'; else $(CYGPATH_W) '$(srcdir)/common/Formatter.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-Formatter.Tpo common/$(DEPDIR)/test_build_libcommon-Formatter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Formatter.cc' object='common/test_build_libcommon-Formatter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-Formatter.obj `if test -f 'common/Formatter.cc'; then $(CYGPATH_W) 'common/Formatter.cc'; else $(CYGPATH_W) '$(srcdir)/common/Formatter.cc'; fi` common/test_build_libcommon-HeartbeatMap.o: common/HeartbeatMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-HeartbeatMap.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Tpo -c -o common/test_build_libcommon-HeartbeatMap.o `test -f 'common/HeartbeatMap.cc' || echo '$(srcdir)/'`common/HeartbeatMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Tpo common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/HeartbeatMap.cc' object='common/test_build_libcommon-HeartbeatMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-HeartbeatMap.o `test -f 'common/HeartbeatMap.cc' || echo '$(srcdir)/'`common/HeartbeatMap.cc common/test_build_libcommon-HeartbeatMap.obj: common/HeartbeatMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-HeartbeatMap.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Tpo -c -o common/test_build_libcommon-HeartbeatMap.obj `if test -f 'common/HeartbeatMap.cc'; then $(CYGPATH_W) 'common/HeartbeatMap.cc'; else $(CYGPATH_W) '$(srcdir)/common/HeartbeatMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Tpo common/$(DEPDIR)/test_build_libcommon-HeartbeatMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/HeartbeatMap.cc' object='common/test_build_libcommon-HeartbeatMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-HeartbeatMap.obj `if test -f 'common/HeartbeatMap.cc'; then $(CYGPATH_W) 'common/HeartbeatMap.cc'; else $(CYGPATH_W) '$(srcdir)/common/HeartbeatMap.cc'; fi` common/test_build_libcommon-config.o: common/config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-config.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-config.Tpo -c -o common/test_build_libcommon-config.o `test -f 'common/config.cc' || echo '$(srcdir)/'`common/config.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-config.Tpo common/$(DEPDIR)/test_build_libcommon-config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/config.cc' object='common/test_build_libcommon-config.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-config.o `test -f 'common/config.cc' || echo '$(srcdir)/'`common/config.cc common/test_build_libcommon-config.obj: common/config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-config.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-config.Tpo -c -o common/test_build_libcommon-config.obj `if test -f 'common/config.cc'; then $(CYGPATH_W) 'common/config.cc'; else $(CYGPATH_W) '$(srcdir)/common/config.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-config.Tpo common/$(DEPDIR)/test_build_libcommon-config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/config.cc' object='common/test_build_libcommon-config.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-config.obj `if test -f 'common/config.cc'; then $(CYGPATH_W) 'common/config.cc'; else $(CYGPATH_W) '$(srcdir)/common/config.cc'; fi` common/test_build_libcommon-strtol.o: common/strtol.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-strtol.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-strtol.Tpo -c -o common/test_build_libcommon-strtol.o `test -f 'common/strtol.cc' || echo '$(srcdir)/'`common/strtol.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-strtol.Tpo common/$(DEPDIR)/test_build_libcommon-strtol.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/strtol.cc' object='common/test_build_libcommon-strtol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-strtol.o `test -f 'common/strtol.cc' || echo '$(srcdir)/'`common/strtol.cc common/test_build_libcommon-strtol.obj: common/strtol.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-strtol.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-strtol.Tpo -c -o common/test_build_libcommon-strtol.obj `if test -f 'common/strtol.cc'; then $(CYGPATH_W) 'common/strtol.cc'; else $(CYGPATH_W) '$(srcdir)/common/strtol.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-strtol.Tpo common/$(DEPDIR)/test_build_libcommon-strtol.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/strtol.cc' object='common/test_build_libcommon-strtol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-strtol.obj `if test -f 'common/strtol.cc'; then $(CYGPATH_W) 'common/strtol.cc'; else $(CYGPATH_W) '$(srcdir)/common/strtol.cc'; fi` common/test_build_libcommon-page.o: common/page.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-page.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-page.Tpo -c -o common/test_build_libcommon-page.o `test -f 'common/page.cc' || echo '$(srcdir)/'`common/page.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-page.Tpo common/$(DEPDIR)/test_build_libcommon-page.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/page.cc' object='common/test_build_libcommon-page.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-page.o `test -f 'common/page.cc' || echo '$(srcdir)/'`common/page.cc common/test_build_libcommon-page.obj: common/page.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-page.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-page.Tpo -c -o common/test_build_libcommon-page.obj `if test -f 'common/page.cc'; then $(CYGPATH_W) 'common/page.cc'; else $(CYGPATH_W) '$(srcdir)/common/page.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-page.Tpo common/$(DEPDIR)/test_build_libcommon-page.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/page.cc' object='common/test_build_libcommon-page.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-page.obj `if test -f 'common/page.cc'; then $(CYGPATH_W) 'common/page.cc'; else $(CYGPATH_W) '$(srcdir)/common/page.cc'; fi` common/test_build_libcommon-lockdep.o: common/lockdep.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-lockdep.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-lockdep.Tpo -c -o common/test_build_libcommon-lockdep.o `test -f 'common/lockdep.cc' || echo '$(srcdir)/'`common/lockdep.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-lockdep.Tpo common/$(DEPDIR)/test_build_libcommon-lockdep.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/lockdep.cc' object='common/test_build_libcommon-lockdep.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-lockdep.o `test -f 'common/lockdep.cc' || echo '$(srcdir)/'`common/lockdep.cc common/test_build_libcommon-lockdep.obj: common/lockdep.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-lockdep.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-lockdep.Tpo -c -o common/test_build_libcommon-lockdep.obj `if test -f 'common/lockdep.cc'; then $(CYGPATH_W) 'common/lockdep.cc'; else $(CYGPATH_W) '$(srcdir)/common/lockdep.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-lockdep.Tpo common/$(DEPDIR)/test_build_libcommon-lockdep.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/lockdep.cc' object='common/test_build_libcommon-lockdep.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-lockdep.obj `if test -f 'common/lockdep.cc'; then $(CYGPATH_W) 'common/lockdep.cc'; else $(CYGPATH_W) '$(srcdir)/common/lockdep.cc'; fi` common/test_build_libcommon-version.o: common/version.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-version.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-version.Tpo -c -o common/test_build_libcommon-version.o `test -f 'common/version.cc' || echo '$(srcdir)/'`common/version.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-version.Tpo common/$(DEPDIR)/test_build_libcommon-version.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/version.cc' object='common/test_build_libcommon-version.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-version.o `test -f 'common/version.cc' || echo '$(srcdir)/'`common/version.cc common/test_build_libcommon-version.obj: common/version.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-version.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-version.Tpo -c -o common/test_build_libcommon-version.obj `if test -f 'common/version.cc'; then $(CYGPATH_W) 'common/version.cc'; else $(CYGPATH_W) '$(srcdir)/common/version.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-version.Tpo common/$(DEPDIR)/test_build_libcommon-version.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/version.cc' object='common/test_build_libcommon-version.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-version.obj `if test -f 'common/version.cc'; then $(CYGPATH_W) 'common/version.cc'; else $(CYGPATH_W) '$(srcdir)/common/version.cc'; fi` common/test_build_libcommon-hex.o: common/hex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-hex.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-hex.Tpo -c -o common/test_build_libcommon-hex.o `test -f 'common/hex.cc' || echo '$(srcdir)/'`common/hex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-hex.Tpo common/$(DEPDIR)/test_build_libcommon-hex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/hex.cc' object='common/test_build_libcommon-hex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-hex.o `test -f 'common/hex.cc' || echo '$(srcdir)/'`common/hex.cc common/test_build_libcommon-hex.obj: common/hex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-hex.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-hex.Tpo -c -o common/test_build_libcommon-hex.obj `if test -f 'common/hex.cc'; then $(CYGPATH_W) 'common/hex.cc'; else $(CYGPATH_W) '$(srcdir)/common/hex.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-hex.Tpo common/$(DEPDIR)/test_build_libcommon-hex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/hex.cc' object='common/test_build_libcommon-hex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-hex.obj `if test -f 'common/hex.cc'; then $(CYGPATH_W) 'common/hex.cc'; else $(CYGPATH_W) '$(srcdir)/common/hex.cc'; fi` common/test_build_libcommon-entity_name.o: common/entity_name.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-entity_name.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-entity_name.Tpo -c -o common/test_build_libcommon-entity_name.o `test -f 'common/entity_name.cc' || echo '$(srcdir)/'`common/entity_name.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-entity_name.Tpo common/$(DEPDIR)/test_build_libcommon-entity_name.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/entity_name.cc' object='common/test_build_libcommon-entity_name.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-entity_name.o `test -f 'common/entity_name.cc' || echo '$(srcdir)/'`common/entity_name.cc common/test_build_libcommon-entity_name.obj: common/entity_name.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-entity_name.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-entity_name.Tpo -c -o common/test_build_libcommon-entity_name.obj `if test -f 'common/entity_name.cc'; then $(CYGPATH_W) 'common/entity_name.cc'; else $(CYGPATH_W) '$(srcdir)/common/entity_name.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-entity_name.Tpo common/$(DEPDIR)/test_build_libcommon-entity_name.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/entity_name.cc' object='common/test_build_libcommon-entity_name.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-entity_name.obj `if test -f 'common/entity_name.cc'; then $(CYGPATH_W) 'common/entity_name.cc'; else $(CYGPATH_W) '$(srcdir)/common/entity_name.cc'; fi` common/test_build_libcommon-ceph_crypto.o: common/ceph_crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_crypto.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Tpo -c -o common/test_build_libcommon-ceph_crypto.o `test -f 'common/ceph_crypto.cc' || echo '$(srcdir)/'`common/ceph_crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_crypto.cc' object='common/test_build_libcommon-ceph_crypto.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_crypto.o `test -f 'common/ceph_crypto.cc' || echo '$(srcdir)/'`common/ceph_crypto.cc common/test_build_libcommon-ceph_crypto.obj: common/ceph_crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_crypto.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Tpo -c -o common/test_build_libcommon-ceph_crypto.obj `if test -f 'common/ceph_crypto.cc'; then $(CYGPATH_W) 'common/ceph_crypto.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_crypto.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_crypto.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_crypto.cc' object='common/test_build_libcommon-ceph_crypto.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_crypto.obj `if test -f 'common/ceph_crypto.cc'; then $(CYGPATH_W) 'common/ceph_crypto.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_crypto.cc'; fi` common/test_build_libcommon-ceph_crypto_cms.o: common/ceph_crypto_cms.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_crypto_cms.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Tpo -c -o common/test_build_libcommon-ceph_crypto_cms.o `test -f 'common/ceph_crypto_cms.cc' || echo '$(srcdir)/'`common/ceph_crypto_cms.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_crypto_cms.cc' object='common/test_build_libcommon-ceph_crypto_cms.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_crypto_cms.o `test -f 'common/ceph_crypto_cms.cc' || echo '$(srcdir)/'`common/ceph_crypto_cms.cc common/test_build_libcommon-ceph_crypto_cms.obj: common/ceph_crypto_cms.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_crypto_cms.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Tpo -c -o common/test_build_libcommon-ceph_crypto_cms.obj `if test -f 'common/ceph_crypto_cms.cc'; then $(CYGPATH_W) 'common/ceph_crypto_cms.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_crypto_cms.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_crypto_cms.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_crypto_cms.cc' object='common/test_build_libcommon-ceph_crypto_cms.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_crypto_cms.obj `if test -f 'common/ceph_crypto_cms.cc'; then $(CYGPATH_W) 'common/ceph_crypto_cms.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_crypto_cms.cc'; fi` common/test_build_libcommon-ceph_json.o: common/ceph_json.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_json.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_json.Tpo -c -o common/test_build_libcommon-ceph_json.o `test -f 'common/ceph_json.cc' || echo '$(srcdir)/'`common/ceph_json.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_json.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_json.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_json.cc' object='common/test_build_libcommon-ceph_json.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_json.o `test -f 'common/ceph_json.cc' || echo '$(srcdir)/'`common/ceph_json.cc common/test_build_libcommon-ceph_json.obj: common/ceph_json.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_json.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_json.Tpo -c -o common/test_build_libcommon-ceph_json.obj `if test -f 'common/ceph_json.cc'; then $(CYGPATH_W) 'common/ceph_json.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_json.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_json.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_json.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_json.cc' object='common/test_build_libcommon-ceph_json.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_json.obj `if test -f 'common/ceph_json.cc'; then $(CYGPATH_W) 'common/ceph_json.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_json.cc'; fi` common/test_build_libcommon-ipaddr.o: common/ipaddr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ipaddr.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ipaddr.Tpo -c -o common/test_build_libcommon-ipaddr.o `test -f 'common/ipaddr.cc' || echo '$(srcdir)/'`common/ipaddr.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ipaddr.Tpo common/$(DEPDIR)/test_build_libcommon-ipaddr.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ipaddr.cc' object='common/test_build_libcommon-ipaddr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ipaddr.o `test -f 'common/ipaddr.cc' || echo '$(srcdir)/'`common/ipaddr.cc common/test_build_libcommon-ipaddr.obj: common/ipaddr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ipaddr.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ipaddr.Tpo -c -o common/test_build_libcommon-ipaddr.obj `if test -f 'common/ipaddr.cc'; then $(CYGPATH_W) 'common/ipaddr.cc'; else $(CYGPATH_W) '$(srcdir)/common/ipaddr.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ipaddr.Tpo common/$(DEPDIR)/test_build_libcommon-ipaddr.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ipaddr.cc' object='common/test_build_libcommon-ipaddr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ipaddr.obj `if test -f 'common/ipaddr.cc'; then $(CYGPATH_W) 'common/ipaddr.cc'; else $(CYGPATH_W) '$(srcdir)/common/ipaddr.cc'; fi` common/test_build_libcommon-pick_address.o: common/pick_address.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-pick_address.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-pick_address.Tpo -c -o common/test_build_libcommon-pick_address.o `test -f 'common/pick_address.cc' || echo '$(srcdir)/'`common/pick_address.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-pick_address.Tpo common/$(DEPDIR)/test_build_libcommon-pick_address.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/pick_address.cc' object='common/test_build_libcommon-pick_address.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-pick_address.o `test -f 'common/pick_address.cc' || echo '$(srcdir)/'`common/pick_address.cc common/test_build_libcommon-pick_address.obj: common/pick_address.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-pick_address.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-pick_address.Tpo -c -o common/test_build_libcommon-pick_address.obj `if test -f 'common/pick_address.cc'; then $(CYGPATH_W) 'common/pick_address.cc'; else $(CYGPATH_W) '$(srcdir)/common/pick_address.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-pick_address.Tpo common/$(DEPDIR)/test_build_libcommon-pick_address.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/pick_address.cc' object='common/test_build_libcommon-pick_address.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-pick_address.obj `if test -f 'common/pick_address.cc'; then $(CYGPATH_W) 'common/pick_address.cc'; else $(CYGPATH_W) '$(srcdir)/common/pick_address.cc'; fi` common/test_build_libcommon-util.o: common/util.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-util.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-util.Tpo -c -o common/test_build_libcommon-util.o `test -f 'common/util.cc' || echo '$(srcdir)/'`common/util.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-util.Tpo common/$(DEPDIR)/test_build_libcommon-util.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/util.cc' object='common/test_build_libcommon-util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-util.o `test -f 'common/util.cc' || echo '$(srcdir)/'`common/util.cc common/test_build_libcommon-util.obj: common/util.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-util.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-util.Tpo -c -o common/test_build_libcommon-util.obj `if test -f 'common/util.cc'; then $(CYGPATH_W) 'common/util.cc'; else $(CYGPATH_W) '$(srcdir)/common/util.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-util.Tpo common/$(DEPDIR)/test_build_libcommon-util.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/util.cc' object='common/test_build_libcommon-util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-util.obj `if test -f 'common/util.cc'; then $(CYGPATH_W) 'common/util.cc'; else $(CYGPATH_W) '$(srcdir)/common/util.cc'; fi` common/test_build_libcommon-TextTable.o: common/TextTable.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-TextTable.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-TextTable.Tpo -c -o common/test_build_libcommon-TextTable.o `test -f 'common/TextTable.cc' || echo '$(srcdir)/'`common/TextTable.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-TextTable.Tpo common/$(DEPDIR)/test_build_libcommon-TextTable.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/TextTable.cc' object='common/test_build_libcommon-TextTable.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-TextTable.o `test -f 'common/TextTable.cc' || echo '$(srcdir)/'`common/TextTable.cc common/test_build_libcommon-TextTable.obj: common/TextTable.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-TextTable.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-TextTable.Tpo -c -o common/test_build_libcommon-TextTable.obj `if test -f 'common/TextTable.cc'; then $(CYGPATH_W) 'common/TextTable.cc'; else $(CYGPATH_W) '$(srcdir)/common/TextTable.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-TextTable.Tpo common/$(DEPDIR)/test_build_libcommon-TextTable.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/TextTable.cc' object='common/test_build_libcommon-TextTable.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-TextTable.obj `if test -f 'common/TextTable.cc'; then $(CYGPATH_W) 'common/TextTable.cc'; else $(CYGPATH_W) '$(srcdir)/common/TextTable.cc'; fi` common/test_build_libcommon-ceph_fs.o: common/ceph_fs.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_fs.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_fs.Tpo -c -o common/test_build_libcommon-ceph_fs.o `test -f 'common/ceph_fs.cc' || echo '$(srcdir)/'`common/ceph_fs.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_fs.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_fs.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_fs.cc' object='common/test_build_libcommon-ceph_fs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_fs.o `test -f 'common/ceph_fs.cc' || echo '$(srcdir)/'`common/ceph_fs.cc common/test_build_libcommon-ceph_fs.obj: common/ceph_fs.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_fs.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_fs.Tpo -c -o common/test_build_libcommon-ceph_fs.obj `if test -f 'common/ceph_fs.cc'; then $(CYGPATH_W) 'common/ceph_fs.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_fs.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_fs.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_fs.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_fs.cc' object='common/test_build_libcommon-ceph_fs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_fs.obj `if test -f 'common/ceph_fs.cc'; then $(CYGPATH_W) 'common/ceph_fs.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_fs.cc'; fi` common/test_build_libcommon-ceph_hash.o: common/ceph_hash.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_hash.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_hash.Tpo -c -o common/test_build_libcommon-ceph_hash.o `test -f 'common/ceph_hash.cc' || echo '$(srcdir)/'`common/ceph_hash.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_hash.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_hash.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_hash.cc' object='common/test_build_libcommon-ceph_hash.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_hash.o `test -f 'common/ceph_hash.cc' || echo '$(srcdir)/'`common/ceph_hash.cc common/test_build_libcommon-ceph_hash.obj: common/ceph_hash.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_hash.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_hash.Tpo -c -o common/test_build_libcommon-ceph_hash.obj `if test -f 'common/ceph_hash.cc'; then $(CYGPATH_W) 'common/ceph_hash.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_hash.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_hash.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_hash.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_hash.cc' object='common/test_build_libcommon-ceph_hash.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_hash.obj `if test -f 'common/ceph_hash.cc'; then $(CYGPATH_W) 'common/ceph_hash.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_hash.cc'; fi` common/test_build_libcommon-ceph_strings.o: common/ceph_strings.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_strings.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_strings.Tpo -c -o common/test_build_libcommon-ceph_strings.o `test -f 'common/ceph_strings.cc' || echo '$(srcdir)/'`common/ceph_strings.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_strings.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_strings.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_strings.cc' object='common/test_build_libcommon-ceph_strings.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_strings.o `test -f 'common/ceph_strings.cc' || echo '$(srcdir)/'`common/ceph_strings.cc common/test_build_libcommon-ceph_strings.obj: common/ceph_strings.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_strings.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_strings.Tpo -c -o common/test_build_libcommon-ceph_strings.obj `if test -f 'common/ceph_strings.cc'; then $(CYGPATH_W) 'common/ceph_strings.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_strings.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_strings.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_strings.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_strings.cc' object='common/test_build_libcommon-ceph_strings.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_strings.obj `if test -f 'common/ceph_strings.cc'; then $(CYGPATH_W) 'common/ceph_strings.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_strings.cc'; fi` common/test_build_libcommon-ceph_frag.o: common/ceph_frag.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_frag.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_frag.Tpo -c -o common/test_build_libcommon-ceph_frag.o `test -f 'common/ceph_frag.cc' || echo '$(srcdir)/'`common/ceph_frag.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_frag.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_frag.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_frag.cc' object='common/test_build_libcommon-ceph_frag.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_frag.o `test -f 'common/ceph_frag.cc' || echo '$(srcdir)/'`common/ceph_frag.cc common/test_build_libcommon-ceph_frag.obj: common/ceph_frag.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-ceph_frag.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-ceph_frag.Tpo -c -o common/test_build_libcommon-ceph_frag.obj `if test -f 'common/ceph_frag.cc'; then $(CYGPATH_W) 'common/ceph_frag.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_frag.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-ceph_frag.Tpo common/$(DEPDIR)/test_build_libcommon-ceph_frag.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ceph_frag.cc' object='common/test_build_libcommon-ceph_frag.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-ceph_frag.obj `if test -f 'common/ceph_frag.cc'; then $(CYGPATH_W) 'common/ceph_frag.cc'; else $(CYGPATH_W) '$(srcdir)/common/ceph_frag.cc'; fi` common/test_build_libcommon-hobject.o: common/hobject.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-hobject.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-hobject.Tpo -c -o common/test_build_libcommon-hobject.o `test -f 'common/hobject.cc' || echo '$(srcdir)/'`common/hobject.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-hobject.Tpo common/$(DEPDIR)/test_build_libcommon-hobject.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/hobject.cc' object='common/test_build_libcommon-hobject.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-hobject.o `test -f 'common/hobject.cc' || echo '$(srcdir)/'`common/hobject.cc common/test_build_libcommon-hobject.obj: common/hobject.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-hobject.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-hobject.Tpo -c -o common/test_build_libcommon-hobject.obj `if test -f 'common/hobject.cc'; then $(CYGPATH_W) 'common/hobject.cc'; else $(CYGPATH_W) '$(srcdir)/common/hobject.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-hobject.Tpo common/$(DEPDIR)/test_build_libcommon-hobject.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/hobject.cc' object='common/test_build_libcommon-hobject.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-hobject.obj `if test -f 'common/hobject.cc'; then $(CYGPATH_W) 'common/hobject.cc'; else $(CYGPATH_W) '$(srcdir)/common/hobject.cc'; fi` common/test_build_libcommon-bloom_filter.o: common/bloom_filter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-bloom_filter.o -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-bloom_filter.Tpo -c -o common/test_build_libcommon-bloom_filter.o `test -f 'common/bloom_filter.cc' || echo '$(srcdir)/'`common/bloom_filter.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-bloom_filter.Tpo common/$(DEPDIR)/test_build_libcommon-bloom_filter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/bloom_filter.cc' object='common/test_build_libcommon-bloom_filter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-bloom_filter.o `test -f 'common/bloom_filter.cc' || echo '$(srcdir)/'`common/bloom_filter.cc common/test_build_libcommon-bloom_filter.obj: common/bloom_filter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT common/test_build_libcommon-bloom_filter.obj -MD -MP -MF common/$(DEPDIR)/test_build_libcommon-bloom_filter.Tpo -c -o common/test_build_libcommon-bloom_filter.obj `if test -f 'common/bloom_filter.cc'; then $(CYGPATH_W) 'common/bloom_filter.cc'; else $(CYGPATH_W) '$(srcdir)/common/bloom_filter.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/test_build_libcommon-bloom_filter.Tpo common/$(DEPDIR)/test_build_libcommon-bloom_filter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/bloom_filter.cc' object='common/test_build_libcommon-bloom_filter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o common/test_build_libcommon-bloom_filter.obj `if test -f 'common/bloom_filter.cc'; then $(CYGPATH_W) 'common/bloom_filter.cc'; else $(CYGPATH_W) '$(srcdir)/common/bloom_filter.cc'; fi` mon/test_build_libcommon-MonCap.o: mon/MonCap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mon/test_build_libcommon-MonCap.o -MD -MP -MF mon/$(DEPDIR)/test_build_libcommon-MonCap.Tpo -c -o mon/test_build_libcommon-MonCap.o `test -f 'mon/MonCap.cc' || echo '$(srcdir)/'`mon/MonCap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mon/$(DEPDIR)/test_build_libcommon-MonCap.Tpo mon/$(DEPDIR)/test_build_libcommon-MonCap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mon/MonCap.cc' object='mon/test_build_libcommon-MonCap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mon/test_build_libcommon-MonCap.o `test -f 'mon/MonCap.cc' || echo '$(srcdir)/'`mon/MonCap.cc mon/test_build_libcommon-MonCap.obj: mon/MonCap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mon/test_build_libcommon-MonCap.obj -MD -MP -MF mon/$(DEPDIR)/test_build_libcommon-MonCap.Tpo -c -o mon/test_build_libcommon-MonCap.obj `if test -f 'mon/MonCap.cc'; then $(CYGPATH_W) 'mon/MonCap.cc'; else $(CYGPATH_W) '$(srcdir)/mon/MonCap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mon/$(DEPDIR)/test_build_libcommon-MonCap.Tpo mon/$(DEPDIR)/test_build_libcommon-MonCap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mon/MonCap.cc' object='mon/test_build_libcommon-MonCap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mon/test_build_libcommon-MonCap.obj `if test -f 'mon/MonCap.cc'; then $(CYGPATH_W) 'mon/MonCap.cc'; else $(CYGPATH_W) '$(srcdir)/mon/MonCap.cc'; fi` mon/test_build_libcommon-MonClient.o: mon/MonClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mon/test_build_libcommon-MonClient.o -MD -MP -MF mon/$(DEPDIR)/test_build_libcommon-MonClient.Tpo -c -o mon/test_build_libcommon-MonClient.o `test -f 'mon/MonClient.cc' || echo '$(srcdir)/'`mon/MonClient.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mon/$(DEPDIR)/test_build_libcommon-MonClient.Tpo mon/$(DEPDIR)/test_build_libcommon-MonClient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mon/MonClient.cc' object='mon/test_build_libcommon-MonClient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mon/test_build_libcommon-MonClient.o `test -f 'mon/MonClient.cc' || echo '$(srcdir)/'`mon/MonClient.cc mon/test_build_libcommon-MonClient.obj: mon/MonClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mon/test_build_libcommon-MonClient.obj -MD -MP -MF mon/$(DEPDIR)/test_build_libcommon-MonClient.Tpo -c -o mon/test_build_libcommon-MonClient.obj `if test -f 'mon/MonClient.cc'; then $(CYGPATH_W) 'mon/MonClient.cc'; else $(CYGPATH_W) '$(srcdir)/mon/MonClient.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mon/$(DEPDIR)/test_build_libcommon-MonClient.Tpo mon/$(DEPDIR)/test_build_libcommon-MonClient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mon/MonClient.cc' object='mon/test_build_libcommon-MonClient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mon/test_build_libcommon-MonClient.obj `if test -f 'mon/MonClient.cc'; then $(CYGPATH_W) 'mon/MonClient.cc'; else $(CYGPATH_W) '$(srcdir)/mon/MonClient.cc'; fi` mon/test_build_libcommon-MonMap.o: mon/MonMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mon/test_build_libcommon-MonMap.o -MD -MP -MF mon/$(DEPDIR)/test_build_libcommon-MonMap.Tpo -c -o mon/test_build_libcommon-MonMap.o `test -f 'mon/MonMap.cc' || echo '$(srcdir)/'`mon/MonMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mon/$(DEPDIR)/test_build_libcommon-MonMap.Tpo mon/$(DEPDIR)/test_build_libcommon-MonMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mon/MonMap.cc' object='mon/test_build_libcommon-MonMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mon/test_build_libcommon-MonMap.o `test -f 'mon/MonMap.cc' || echo '$(srcdir)/'`mon/MonMap.cc mon/test_build_libcommon-MonMap.obj: mon/MonMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mon/test_build_libcommon-MonMap.obj -MD -MP -MF mon/$(DEPDIR)/test_build_libcommon-MonMap.Tpo -c -o mon/test_build_libcommon-MonMap.obj `if test -f 'mon/MonMap.cc'; then $(CYGPATH_W) 'mon/MonMap.cc'; else $(CYGPATH_W) '$(srcdir)/mon/MonMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mon/$(DEPDIR)/test_build_libcommon-MonMap.Tpo mon/$(DEPDIR)/test_build_libcommon-MonMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mon/MonMap.cc' object='mon/test_build_libcommon-MonMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mon/test_build_libcommon-MonMap.obj `if test -f 'mon/MonMap.cc'; then $(CYGPATH_W) 'mon/MonMap.cc'; else $(CYGPATH_W) '$(srcdir)/mon/MonMap.cc'; fi` osd/test_build_libcommon-OSDMap.o: osd/OSDMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-OSDMap.o -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-OSDMap.Tpo -c -o osd/test_build_libcommon-OSDMap.o `test -f 'osd/OSDMap.cc' || echo '$(srcdir)/'`osd/OSDMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-OSDMap.Tpo osd/$(DEPDIR)/test_build_libcommon-OSDMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/OSDMap.cc' object='osd/test_build_libcommon-OSDMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-OSDMap.o `test -f 'osd/OSDMap.cc' || echo '$(srcdir)/'`osd/OSDMap.cc osd/test_build_libcommon-OSDMap.obj: osd/OSDMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-OSDMap.obj -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-OSDMap.Tpo -c -o osd/test_build_libcommon-OSDMap.obj `if test -f 'osd/OSDMap.cc'; then $(CYGPATH_W) 'osd/OSDMap.cc'; else $(CYGPATH_W) '$(srcdir)/osd/OSDMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-OSDMap.Tpo osd/$(DEPDIR)/test_build_libcommon-OSDMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/OSDMap.cc' object='osd/test_build_libcommon-OSDMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-OSDMap.obj `if test -f 'osd/OSDMap.cc'; then $(CYGPATH_W) 'osd/OSDMap.cc'; else $(CYGPATH_W) '$(srcdir)/osd/OSDMap.cc'; fi` osd/test_build_libcommon-osd_types.o: osd/osd_types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-osd_types.o -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-osd_types.Tpo -c -o osd/test_build_libcommon-osd_types.o `test -f 'osd/osd_types.cc' || echo '$(srcdir)/'`osd/osd_types.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-osd_types.Tpo osd/$(DEPDIR)/test_build_libcommon-osd_types.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/osd_types.cc' object='osd/test_build_libcommon-osd_types.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-osd_types.o `test -f 'osd/osd_types.cc' || echo '$(srcdir)/'`osd/osd_types.cc osd/test_build_libcommon-osd_types.obj: osd/osd_types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-osd_types.obj -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-osd_types.Tpo -c -o osd/test_build_libcommon-osd_types.obj `if test -f 'osd/osd_types.cc'; then $(CYGPATH_W) 'osd/osd_types.cc'; else $(CYGPATH_W) '$(srcdir)/osd/osd_types.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-osd_types.Tpo osd/$(DEPDIR)/test_build_libcommon-osd_types.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/osd_types.cc' object='osd/test_build_libcommon-osd_types.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-osd_types.obj `if test -f 'osd/osd_types.cc'; then $(CYGPATH_W) 'osd/osd_types.cc'; else $(CYGPATH_W) '$(srcdir)/osd/osd_types.cc'; fi` osd/test_build_libcommon-ECMsgTypes.o: osd/ECMsgTypes.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-ECMsgTypes.o -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Tpo -c -o osd/test_build_libcommon-ECMsgTypes.o `test -f 'osd/ECMsgTypes.cc' || echo '$(srcdir)/'`osd/ECMsgTypes.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Tpo osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ECMsgTypes.cc' object='osd/test_build_libcommon-ECMsgTypes.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-ECMsgTypes.o `test -f 'osd/ECMsgTypes.cc' || echo '$(srcdir)/'`osd/ECMsgTypes.cc osd/test_build_libcommon-ECMsgTypes.obj: osd/ECMsgTypes.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-ECMsgTypes.obj -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Tpo -c -o osd/test_build_libcommon-ECMsgTypes.obj `if test -f 'osd/ECMsgTypes.cc'; then $(CYGPATH_W) 'osd/ECMsgTypes.cc'; else $(CYGPATH_W) '$(srcdir)/osd/ECMsgTypes.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Tpo osd/$(DEPDIR)/test_build_libcommon-ECMsgTypes.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/ECMsgTypes.cc' object='osd/test_build_libcommon-ECMsgTypes.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-ECMsgTypes.obj `if test -f 'osd/ECMsgTypes.cc'; then $(CYGPATH_W) 'osd/ECMsgTypes.cc'; else $(CYGPATH_W) '$(srcdir)/osd/ECMsgTypes.cc'; fi` osd/test_build_libcommon-HitSet.o: osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-HitSet.o -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-HitSet.Tpo -c -o osd/test_build_libcommon-HitSet.o `test -f 'osd/HitSet.cc' || echo '$(srcdir)/'`osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-HitSet.Tpo osd/$(DEPDIR)/test_build_libcommon-HitSet.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/HitSet.cc' object='osd/test_build_libcommon-HitSet.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-HitSet.o `test -f 'osd/HitSet.cc' || echo '$(srcdir)/'`osd/HitSet.cc osd/test_build_libcommon-HitSet.obj: osd/HitSet.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT osd/test_build_libcommon-HitSet.obj -MD -MP -MF osd/$(DEPDIR)/test_build_libcommon-HitSet.Tpo -c -o osd/test_build_libcommon-HitSet.obj `if test -f 'osd/HitSet.cc'; then $(CYGPATH_W) 'osd/HitSet.cc'; else $(CYGPATH_W) '$(srcdir)/osd/HitSet.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) osd/$(DEPDIR)/test_build_libcommon-HitSet.Tpo osd/$(DEPDIR)/test_build_libcommon-HitSet.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='osd/HitSet.cc' object='osd/test_build_libcommon-HitSet.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o osd/test_build_libcommon-HitSet.obj `if test -f 'osd/HitSet.cc'; then $(CYGPATH_W) 'osd/HitSet.cc'; else $(CYGPATH_W) '$(srcdir)/osd/HitSet.cc'; fi` mds/test_build_libcommon-MDSMap.o: mds/MDSMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-MDSMap.o -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-MDSMap.Tpo -c -o mds/test_build_libcommon-MDSMap.o `test -f 'mds/MDSMap.cc' || echo '$(srcdir)/'`mds/MDSMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-MDSMap.Tpo mds/$(DEPDIR)/test_build_libcommon-MDSMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/MDSMap.cc' object='mds/test_build_libcommon-MDSMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-MDSMap.o `test -f 'mds/MDSMap.cc' || echo '$(srcdir)/'`mds/MDSMap.cc mds/test_build_libcommon-MDSMap.obj: mds/MDSMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-MDSMap.obj -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-MDSMap.Tpo -c -o mds/test_build_libcommon-MDSMap.obj `if test -f 'mds/MDSMap.cc'; then $(CYGPATH_W) 'mds/MDSMap.cc'; else $(CYGPATH_W) '$(srcdir)/mds/MDSMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-MDSMap.Tpo mds/$(DEPDIR)/test_build_libcommon-MDSMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/MDSMap.cc' object='mds/test_build_libcommon-MDSMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-MDSMap.obj `if test -f 'mds/MDSMap.cc'; then $(CYGPATH_W) 'mds/MDSMap.cc'; else $(CYGPATH_W) '$(srcdir)/mds/MDSMap.cc'; fi` mds/test_build_libcommon-inode_backtrace.o: mds/inode_backtrace.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-inode_backtrace.o -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Tpo -c -o mds/test_build_libcommon-inode_backtrace.o `test -f 'mds/inode_backtrace.cc' || echo '$(srcdir)/'`mds/inode_backtrace.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Tpo mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/inode_backtrace.cc' object='mds/test_build_libcommon-inode_backtrace.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-inode_backtrace.o `test -f 'mds/inode_backtrace.cc' || echo '$(srcdir)/'`mds/inode_backtrace.cc mds/test_build_libcommon-inode_backtrace.obj: mds/inode_backtrace.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-inode_backtrace.obj -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Tpo -c -o mds/test_build_libcommon-inode_backtrace.obj `if test -f 'mds/inode_backtrace.cc'; then $(CYGPATH_W) 'mds/inode_backtrace.cc'; else $(CYGPATH_W) '$(srcdir)/mds/inode_backtrace.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Tpo mds/$(DEPDIR)/test_build_libcommon-inode_backtrace.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/inode_backtrace.cc' object='mds/test_build_libcommon-inode_backtrace.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-inode_backtrace.obj `if test -f 'mds/inode_backtrace.cc'; then $(CYGPATH_W) 'mds/inode_backtrace.cc'; else $(CYGPATH_W) '$(srcdir)/mds/inode_backtrace.cc'; fi` mds/test_build_libcommon-mdstypes.o: mds/mdstypes.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-mdstypes.o -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-mdstypes.Tpo -c -o mds/test_build_libcommon-mdstypes.o `test -f 'mds/mdstypes.cc' || echo '$(srcdir)/'`mds/mdstypes.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-mdstypes.Tpo mds/$(DEPDIR)/test_build_libcommon-mdstypes.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/mdstypes.cc' object='mds/test_build_libcommon-mdstypes.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-mdstypes.o `test -f 'mds/mdstypes.cc' || echo '$(srcdir)/'`mds/mdstypes.cc mds/test_build_libcommon-mdstypes.obj: mds/mdstypes.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-mdstypes.obj -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-mdstypes.Tpo -c -o mds/test_build_libcommon-mdstypes.obj `if test -f 'mds/mdstypes.cc'; then $(CYGPATH_W) 'mds/mdstypes.cc'; else $(CYGPATH_W) '$(srcdir)/mds/mdstypes.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-mdstypes.Tpo mds/$(DEPDIR)/test_build_libcommon-mdstypes.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/mdstypes.cc' object='mds/test_build_libcommon-mdstypes.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-mdstypes.obj `if test -f 'mds/mdstypes.cc'; then $(CYGPATH_W) 'mds/mdstypes.cc'; else $(CYGPATH_W) '$(srcdir)/mds/mdstypes.cc'; fi` mds/test_build_libcommon-flock.o: mds/flock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-flock.o -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-flock.Tpo -c -o mds/test_build_libcommon-flock.o `test -f 'mds/flock.cc' || echo '$(srcdir)/'`mds/flock.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-flock.Tpo mds/$(DEPDIR)/test_build_libcommon-flock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/flock.cc' object='mds/test_build_libcommon-flock.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-flock.o `test -f 'mds/flock.cc' || echo '$(srcdir)/'`mds/flock.cc mds/test_build_libcommon-flock.obj: mds/flock.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -MT mds/test_build_libcommon-flock.obj -MD -MP -MF mds/$(DEPDIR)/test_build_libcommon-flock.Tpo -c -o mds/test_build_libcommon-flock.obj `if test -f 'mds/flock.cc'; then $(CYGPATH_W) 'mds/flock.cc'; else $(CYGPATH_W) '$(srcdir)/mds/flock.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mds/$(DEPDIR)/test_build_libcommon-flock.Tpo mds/$(DEPDIR)/test_build_libcommon-flock.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mds/flock.cc' object='mds/test_build_libcommon-flock.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_libcommon_CXXFLAGS) $(CXXFLAGS) -c -o mds/test_build_libcommon-flock.obj `if test -f 'mds/flock.cc'; then $(CYGPATH_W) 'mds/flock.cc'; else $(CYGPATH_W) '$(srcdir)/mds/flock.cc'; fi` test/test_build_librados-buildtest_skeleton.o: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_librados-buildtest_skeleton.o -MD -MP -MF test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Tpo -c -o test/test_build_librados-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_librados-buildtest_skeleton.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_librados-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc test/test_build_librados-buildtest_skeleton.obj: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_librados-buildtest_skeleton.obj -MD -MP -MF test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Tpo -c -o test/test_build_librados-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_librados-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_librados-buildtest_skeleton.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_librados-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` librados/test_build_librados-librados.o: librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-librados.o -MD -MP -MF librados/$(DEPDIR)/test_build_librados-librados.Tpo -c -o librados/test_build_librados-librados.o `test -f 'librados/librados.cc' || echo '$(srcdir)/'`librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-librados.Tpo librados/$(DEPDIR)/test_build_librados-librados.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/librados.cc' object='librados/test_build_librados-librados.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-librados.o `test -f 'librados/librados.cc' || echo '$(srcdir)/'`librados/librados.cc librados/test_build_librados-librados.obj: librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-librados.obj -MD -MP -MF librados/$(DEPDIR)/test_build_librados-librados.Tpo -c -o librados/test_build_librados-librados.obj `if test -f 'librados/librados.cc'; then $(CYGPATH_W) 'librados/librados.cc'; else $(CYGPATH_W) '$(srcdir)/librados/librados.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-librados.Tpo librados/$(DEPDIR)/test_build_librados-librados.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/librados.cc' object='librados/test_build_librados-librados.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-librados.obj `if test -f 'librados/librados.cc'; then $(CYGPATH_W) 'librados/librados.cc'; else $(CYGPATH_W) '$(srcdir)/librados/librados.cc'; fi` librados/test_build_librados-RadosClient.o: librados/RadosClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-RadosClient.o -MD -MP -MF librados/$(DEPDIR)/test_build_librados-RadosClient.Tpo -c -o librados/test_build_librados-RadosClient.o `test -f 'librados/RadosClient.cc' || echo '$(srcdir)/'`librados/RadosClient.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-RadosClient.Tpo librados/$(DEPDIR)/test_build_librados-RadosClient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/RadosClient.cc' object='librados/test_build_librados-RadosClient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-RadosClient.o `test -f 'librados/RadosClient.cc' || echo '$(srcdir)/'`librados/RadosClient.cc librados/test_build_librados-RadosClient.obj: librados/RadosClient.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-RadosClient.obj -MD -MP -MF librados/$(DEPDIR)/test_build_librados-RadosClient.Tpo -c -o librados/test_build_librados-RadosClient.obj `if test -f 'librados/RadosClient.cc'; then $(CYGPATH_W) 'librados/RadosClient.cc'; else $(CYGPATH_W) '$(srcdir)/librados/RadosClient.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-RadosClient.Tpo librados/$(DEPDIR)/test_build_librados-RadosClient.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/RadosClient.cc' object='librados/test_build_librados-RadosClient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-RadosClient.obj `if test -f 'librados/RadosClient.cc'; then $(CYGPATH_W) 'librados/RadosClient.cc'; else $(CYGPATH_W) '$(srcdir)/librados/RadosClient.cc'; fi` librados/test_build_librados-IoCtxImpl.o: librados/IoCtxImpl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-IoCtxImpl.o -MD -MP -MF librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Tpo -c -o librados/test_build_librados-IoCtxImpl.o `test -f 'librados/IoCtxImpl.cc' || echo '$(srcdir)/'`librados/IoCtxImpl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Tpo librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/IoCtxImpl.cc' object='librados/test_build_librados-IoCtxImpl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-IoCtxImpl.o `test -f 'librados/IoCtxImpl.cc' || echo '$(srcdir)/'`librados/IoCtxImpl.cc librados/test_build_librados-IoCtxImpl.obj: librados/IoCtxImpl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-IoCtxImpl.obj -MD -MP -MF librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Tpo -c -o librados/test_build_librados-IoCtxImpl.obj `if test -f 'librados/IoCtxImpl.cc'; then $(CYGPATH_W) 'librados/IoCtxImpl.cc'; else $(CYGPATH_W) '$(srcdir)/librados/IoCtxImpl.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Tpo librados/$(DEPDIR)/test_build_librados-IoCtxImpl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/IoCtxImpl.cc' object='librados/test_build_librados-IoCtxImpl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-IoCtxImpl.obj `if test -f 'librados/IoCtxImpl.cc'; then $(CYGPATH_W) 'librados/IoCtxImpl.cc'; else $(CYGPATH_W) '$(srcdir)/librados/IoCtxImpl.cc'; fi` librados/test_build_librados-snap_set_diff.o: librados/snap_set_diff.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-snap_set_diff.o -MD -MP -MF librados/$(DEPDIR)/test_build_librados-snap_set_diff.Tpo -c -o librados/test_build_librados-snap_set_diff.o `test -f 'librados/snap_set_diff.cc' || echo '$(srcdir)/'`librados/snap_set_diff.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-snap_set_diff.Tpo librados/$(DEPDIR)/test_build_librados-snap_set_diff.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/snap_set_diff.cc' object='librados/test_build_librados-snap_set_diff.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-snap_set_diff.o `test -f 'librados/snap_set_diff.cc' || echo '$(srcdir)/'`librados/snap_set_diff.cc librados/test_build_librados-snap_set_diff.obj: librados/snap_set_diff.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -MT librados/test_build_librados-snap_set_diff.obj -MD -MP -MF librados/$(DEPDIR)/test_build_librados-snap_set_diff.Tpo -c -o librados/test_build_librados-snap_set_diff.obj `if test -f 'librados/snap_set_diff.cc'; then $(CYGPATH_W) 'librados/snap_set_diff.cc'; else $(CYGPATH_W) '$(srcdir)/librados/snap_set_diff.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) librados/$(DEPDIR)/test_build_librados-snap_set_diff.Tpo librados/$(DEPDIR)/test_build_librados-snap_set_diff.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='librados/snap_set_diff.cc' object='librados/test_build_librados-snap_set_diff.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librados_CXXFLAGS) $(CXXFLAGS) -c -o librados/test_build_librados-snap_set_diff.obj `if test -f 'librados/snap_set_diff.cc'; then $(CYGPATH_W) 'librados/snap_set_diff.cc'; else $(CYGPATH_W) '$(srcdir)/librados/snap_set_diff.cc'; fi` test/test_build_librgw-buildtest_skeleton.o: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_librgw-buildtest_skeleton.o -MD -MP -MF test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Tpo -c -o test/test_build_librgw-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_librgw-buildtest_skeleton.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_librgw-buildtest_skeleton.o `test -f 'test/buildtest_skeleton.cc' || echo '$(srcdir)/'`test/buildtest_skeleton.cc test/test_build_librgw-buildtest_skeleton.obj: test/buildtest_skeleton.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT test/test_build_librgw-buildtest_skeleton.obj -MD -MP -MF test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Tpo -c -o test/test_build_librgw-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Tpo test/$(DEPDIR)/test_build_librgw-buildtest_skeleton.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/buildtest_skeleton.cc' object='test/test_build_librgw-buildtest_skeleton.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o test/test_build_librgw-buildtest_skeleton.obj `if test -f 'test/buildtest_skeleton.cc'; then $(CYGPATH_W) 'test/buildtest_skeleton.cc'; else $(CYGPATH_W) '$(srcdir)/test/buildtest_skeleton.cc'; fi` rgw/test_build_librgw-librgw.o: rgw/librgw.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-librgw.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-librgw.Tpo -c -o rgw/test_build_librgw-librgw.o `test -f 'rgw/librgw.cc' || echo '$(srcdir)/'`rgw/librgw.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-librgw.Tpo rgw/$(DEPDIR)/test_build_librgw-librgw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/librgw.cc' object='rgw/test_build_librgw-librgw.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-librgw.o `test -f 'rgw/librgw.cc' || echo '$(srcdir)/'`rgw/librgw.cc rgw/test_build_librgw-librgw.obj: rgw/librgw.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-librgw.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-librgw.Tpo -c -o rgw/test_build_librgw-librgw.obj `if test -f 'rgw/librgw.cc'; then $(CYGPATH_W) 'rgw/librgw.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/librgw.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-librgw.Tpo rgw/$(DEPDIR)/test_build_librgw-librgw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/librgw.cc' object='rgw/test_build_librgw-librgw.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-librgw.obj `if test -f 'rgw/librgw.cc'; then $(CYGPATH_W) 'rgw/librgw.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/librgw.cc'; fi` rgw/test_build_librgw-rgw_acl.o: rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_acl.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Tpo -c -o rgw/test_build_librgw-rgw_acl.o `test -f 'rgw/rgw_acl.cc' || echo '$(srcdir)/'`rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl.cc' object='rgw/test_build_librgw-rgw_acl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_acl.o `test -f 'rgw/rgw_acl.cc' || echo '$(srcdir)/'`rgw/rgw_acl.cc rgw/test_build_librgw-rgw_acl.obj: rgw/rgw_acl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_acl.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Tpo -c -o rgw/test_build_librgw-rgw_acl.obj `if test -f 'rgw/rgw_acl.cc'; then $(CYGPATH_W) 'rgw/rgw_acl.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_acl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl.cc' object='rgw/test_build_librgw-rgw_acl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_acl.obj `if test -f 'rgw/rgw_acl.cc'; then $(CYGPATH_W) 'rgw/rgw_acl.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl.cc'; fi` rgw/test_build_librgw-rgw_acl_s3.o: rgw/rgw_acl_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_acl_s3.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Tpo -c -o rgw/test_build_librgw-rgw_acl_s3.o `test -f 'rgw/rgw_acl_s3.cc' || echo '$(srcdir)/'`rgw/rgw_acl_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl_s3.cc' object='rgw/test_build_librgw-rgw_acl_s3.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_acl_s3.o `test -f 'rgw/rgw_acl_s3.cc' || echo '$(srcdir)/'`rgw/rgw_acl_s3.cc rgw/test_build_librgw-rgw_acl_s3.obj: rgw/rgw_acl_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_acl_s3.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Tpo -c -o rgw/test_build_librgw-rgw_acl_s3.obj `if test -f 'rgw/rgw_acl_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_acl_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl_s3.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_acl_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl_s3.cc' object='rgw/test_build_librgw-rgw_acl_s3.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_acl_s3.obj `if test -f 'rgw/rgw_acl_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_acl_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl_s3.cc'; fi` rgw/test_build_librgw-rgw_acl_swift.o: rgw/rgw_acl_swift.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_acl_swift.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Tpo -c -o rgw/test_build_librgw-rgw_acl_swift.o `test -f 'rgw/rgw_acl_swift.cc' || echo '$(srcdir)/'`rgw/rgw_acl_swift.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl_swift.cc' object='rgw/test_build_librgw-rgw_acl_swift.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_acl_swift.o `test -f 'rgw/rgw_acl_swift.cc' || echo '$(srcdir)/'`rgw/rgw_acl_swift.cc rgw/test_build_librgw-rgw_acl_swift.obj: rgw/rgw_acl_swift.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_acl_swift.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Tpo -c -o rgw/test_build_librgw-rgw_acl_swift.obj `if test -f 'rgw/rgw_acl_swift.cc'; then $(CYGPATH_W) 'rgw/rgw_acl_swift.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl_swift.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_acl_swift.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_acl_swift.cc' object='rgw/test_build_librgw-rgw_acl_swift.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_acl_swift.obj `if test -f 'rgw/rgw_acl_swift.cc'; then $(CYGPATH_W) 'rgw/rgw_acl_swift.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_acl_swift.cc'; fi` rgw/test_build_librgw-rgw_client_io.o: rgw/rgw_client_io.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_client_io.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Tpo -c -o rgw/test_build_librgw-rgw_client_io.o `test -f 'rgw/rgw_client_io.cc' || echo '$(srcdir)/'`rgw/rgw_client_io.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_client_io.cc' object='rgw/test_build_librgw-rgw_client_io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_client_io.o `test -f 'rgw/rgw_client_io.cc' || echo '$(srcdir)/'`rgw/rgw_client_io.cc rgw/test_build_librgw-rgw_client_io.obj: rgw/rgw_client_io.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_client_io.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Tpo -c -o rgw/test_build_librgw-rgw_client_io.obj `if test -f 'rgw/rgw_client_io.cc'; then $(CYGPATH_W) 'rgw/rgw_client_io.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_client_io.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_client_io.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_client_io.cc' object='rgw/test_build_librgw-rgw_client_io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_client_io.obj `if test -f 'rgw/rgw_client_io.cc'; then $(CYGPATH_W) 'rgw/rgw_client_io.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_client_io.cc'; fi` rgw/test_build_librgw-rgw_fcgi.o: rgw/rgw_fcgi.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_fcgi.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Tpo -c -o rgw/test_build_librgw-rgw_fcgi.o `test -f 'rgw/rgw_fcgi.cc' || echo '$(srcdir)/'`rgw/rgw_fcgi.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_fcgi.cc' object='rgw/test_build_librgw-rgw_fcgi.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_fcgi.o `test -f 'rgw/rgw_fcgi.cc' || echo '$(srcdir)/'`rgw/rgw_fcgi.cc rgw/test_build_librgw-rgw_fcgi.obj: rgw/rgw_fcgi.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_fcgi.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Tpo -c -o rgw/test_build_librgw-rgw_fcgi.obj `if test -f 'rgw/rgw_fcgi.cc'; then $(CYGPATH_W) 'rgw/rgw_fcgi.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_fcgi.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_fcgi.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_fcgi.cc' object='rgw/test_build_librgw-rgw_fcgi.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_fcgi.obj `if test -f 'rgw/rgw_fcgi.cc'; then $(CYGPATH_W) 'rgw/rgw_fcgi.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_fcgi.cc'; fi` rgw/test_build_librgw-rgw_xml.o: rgw/rgw_xml.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_xml.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Tpo -c -o rgw/test_build_librgw-rgw_xml.o `test -f 'rgw/rgw_xml.cc' || echo '$(srcdir)/'`rgw/rgw_xml.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_xml.cc' object='rgw/test_build_librgw-rgw_xml.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_xml.o `test -f 'rgw/rgw_xml.cc' || echo '$(srcdir)/'`rgw/rgw_xml.cc rgw/test_build_librgw-rgw_xml.obj: rgw/rgw_xml.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_xml.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Tpo -c -o rgw/test_build_librgw-rgw_xml.obj `if test -f 'rgw/rgw_xml.cc'; then $(CYGPATH_W) 'rgw/rgw_xml.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_xml.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_xml.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_xml.cc' object='rgw/test_build_librgw-rgw_xml.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_xml.obj `if test -f 'rgw/rgw_xml.cc'; then $(CYGPATH_W) 'rgw/rgw_xml.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_xml.cc'; fi` rgw/test_build_librgw-rgw_usage.o: rgw/rgw_usage.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_usage.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Tpo -c -o rgw/test_build_librgw-rgw_usage.o `test -f 'rgw/rgw_usage.cc' || echo '$(srcdir)/'`rgw/rgw_usage.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_usage.cc' object='rgw/test_build_librgw-rgw_usage.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_usage.o `test -f 'rgw/rgw_usage.cc' || echo '$(srcdir)/'`rgw/rgw_usage.cc rgw/test_build_librgw-rgw_usage.obj: rgw/rgw_usage.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_usage.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Tpo -c -o rgw/test_build_librgw-rgw_usage.obj `if test -f 'rgw/rgw_usage.cc'; then $(CYGPATH_W) 'rgw/rgw_usage.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_usage.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_usage.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_usage.cc' object='rgw/test_build_librgw-rgw_usage.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_usage.obj `if test -f 'rgw/rgw_usage.cc'; then $(CYGPATH_W) 'rgw/rgw_usage.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_usage.cc'; fi` rgw/test_build_librgw-rgw_json_enc.o: rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_json_enc.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Tpo -c -o rgw/test_build_librgw-rgw_json_enc.o `test -f 'rgw/rgw_json_enc.cc' || echo '$(srcdir)/'`rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_json_enc.cc' object='rgw/test_build_librgw-rgw_json_enc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_json_enc.o `test -f 'rgw/rgw_json_enc.cc' || echo '$(srcdir)/'`rgw/rgw_json_enc.cc rgw/test_build_librgw-rgw_json_enc.obj: rgw/rgw_json_enc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_json_enc.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Tpo -c -o rgw/test_build_librgw-rgw_json_enc.obj `if test -f 'rgw/rgw_json_enc.cc'; then $(CYGPATH_W) 'rgw/rgw_json_enc.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_json_enc.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_json_enc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_json_enc.cc' object='rgw/test_build_librgw-rgw_json_enc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_json_enc.obj `if test -f 'rgw/rgw_json_enc.cc'; then $(CYGPATH_W) 'rgw/rgw_json_enc.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_json_enc.cc'; fi` rgw/test_build_librgw-rgw_user.o: rgw/rgw_user.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_user.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_user.Tpo -c -o rgw/test_build_librgw-rgw_user.o `test -f 'rgw/rgw_user.cc' || echo '$(srcdir)/'`rgw/rgw_user.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_user.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_user.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_user.cc' object='rgw/test_build_librgw-rgw_user.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_user.o `test -f 'rgw/rgw_user.cc' || echo '$(srcdir)/'`rgw/rgw_user.cc rgw/test_build_librgw-rgw_user.obj: rgw/rgw_user.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_user.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_user.Tpo -c -o rgw/test_build_librgw-rgw_user.obj `if test -f 'rgw/rgw_user.cc'; then $(CYGPATH_W) 'rgw/rgw_user.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_user.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_user.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_user.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_user.cc' object='rgw/test_build_librgw-rgw_user.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_user.obj `if test -f 'rgw/rgw_user.cc'; then $(CYGPATH_W) 'rgw/rgw_user.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_user.cc'; fi` rgw/test_build_librgw-rgw_bucket.o: rgw/rgw_bucket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_bucket.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Tpo -c -o rgw/test_build_librgw-rgw_bucket.o `test -f 'rgw/rgw_bucket.cc' || echo '$(srcdir)/'`rgw/rgw_bucket.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_bucket.cc' object='rgw/test_build_librgw-rgw_bucket.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_bucket.o `test -f 'rgw/rgw_bucket.cc' || echo '$(srcdir)/'`rgw/rgw_bucket.cc rgw/test_build_librgw-rgw_bucket.obj: rgw/rgw_bucket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_bucket.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Tpo -c -o rgw/test_build_librgw-rgw_bucket.obj `if test -f 'rgw/rgw_bucket.cc'; then $(CYGPATH_W) 'rgw/rgw_bucket.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_bucket.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_bucket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_bucket.cc' object='rgw/test_build_librgw-rgw_bucket.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_bucket.obj `if test -f 'rgw/rgw_bucket.cc'; then $(CYGPATH_W) 'rgw/rgw_bucket.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_bucket.cc'; fi` rgw/test_build_librgw-rgw_tools.o: rgw/rgw_tools.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_tools.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Tpo -c -o rgw/test_build_librgw-rgw_tools.o `test -f 'rgw/rgw_tools.cc' || echo '$(srcdir)/'`rgw/rgw_tools.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_tools.cc' object='rgw/test_build_librgw-rgw_tools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_tools.o `test -f 'rgw/rgw_tools.cc' || echo '$(srcdir)/'`rgw/rgw_tools.cc rgw/test_build_librgw-rgw_tools.obj: rgw/rgw_tools.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_tools.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Tpo -c -o rgw/test_build_librgw-rgw_tools.obj `if test -f 'rgw/rgw_tools.cc'; then $(CYGPATH_W) 'rgw/rgw_tools.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_tools.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_tools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_tools.cc' object='rgw/test_build_librgw-rgw_tools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_tools.obj `if test -f 'rgw/rgw_tools.cc'; then $(CYGPATH_W) 'rgw/rgw_tools.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_tools.cc'; fi` rgw/test_build_librgw-rgw_rados.o: rgw/rgw_rados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_rados.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Tpo -c -o rgw/test_build_librgw-rgw_rados.o `test -f 'rgw/rgw_rados.cc' || echo '$(srcdir)/'`rgw/rgw_rados.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rados.cc' object='rgw/test_build_librgw-rgw_rados.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_rados.o `test -f 'rgw/rgw_rados.cc' || echo '$(srcdir)/'`rgw/rgw_rados.cc rgw/test_build_librgw-rgw_rados.obj: rgw/rgw_rados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_rados.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Tpo -c -o rgw/test_build_librgw-rgw_rados.obj `if test -f 'rgw/rgw_rados.cc'; then $(CYGPATH_W) 'rgw/rgw_rados.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_rados.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_rados.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rados.cc' object='rgw/test_build_librgw-rgw_rados.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_rados.obj `if test -f 'rgw/rgw_rados.cc'; then $(CYGPATH_W) 'rgw/rgw_rados.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_rados.cc'; fi` rgw/test_build_librgw-rgw_http_client.o: rgw/rgw_http_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_http_client.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Tpo -c -o rgw/test_build_librgw-rgw_http_client.o `test -f 'rgw/rgw_http_client.cc' || echo '$(srcdir)/'`rgw/rgw_http_client.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_http_client.cc' object='rgw/test_build_librgw-rgw_http_client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_http_client.o `test -f 'rgw/rgw_http_client.cc' || echo '$(srcdir)/'`rgw/rgw_http_client.cc rgw/test_build_librgw-rgw_http_client.obj: rgw/rgw_http_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_http_client.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Tpo -c -o rgw/test_build_librgw-rgw_http_client.obj `if test -f 'rgw/rgw_http_client.cc'; then $(CYGPATH_W) 'rgw/rgw_http_client.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_http_client.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_http_client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_http_client.cc' object='rgw/test_build_librgw-rgw_http_client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_http_client.obj `if test -f 'rgw/rgw_http_client.cc'; then $(CYGPATH_W) 'rgw/rgw_http_client.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_http_client.cc'; fi` rgw/test_build_librgw-rgw_rest_client.o: rgw/rgw_rest_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_rest_client.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Tpo -c -o rgw/test_build_librgw-rgw_rest_client.o `test -f 'rgw/rgw_rest_client.cc' || echo '$(srcdir)/'`rgw/rgw_rest_client.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rest_client.cc' object='rgw/test_build_librgw-rgw_rest_client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_rest_client.o `test -f 'rgw/rgw_rest_client.cc' || echo '$(srcdir)/'`rgw/rgw_rest_client.cc rgw/test_build_librgw-rgw_rest_client.obj: rgw/rgw_rest_client.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_rest_client.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Tpo -c -o rgw/test_build_librgw-rgw_rest_client.obj `if test -f 'rgw/rgw_rest_client.cc'; then $(CYGPATH_W) 'rgw/rgw_rest_client.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_rest_client.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_rest_client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rest_client.cc' object='rgw/test_build_librgw-rgw_rest_client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_rest_client.obj `if test -f 'rgw/rgw_rest_client.cc'; then $(CYGPATH_W) 'rgw/rgw_rest_client.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_rest_client.cc'; fi` rgw/test_build_librgw-rgw_rest_conn.o: rgw/rgw_rest_conn.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_rest_conn.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Tpo -c -o rgw/test_build_librgw-rgw_rest_conn.o `test -f 'rgw/rgw_rest_conn.cc' || echo '$(srcdir)/'`rgw/rgw_rest_conn.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rest_conn.cc' object='rgw/test_build_librgw-rgw_rest_conn.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_rest_conn.o `test -f 'rgw/rgw_rest_conn.cc' || echo '$(srcdir)/'`rgw/rgw_rest_conn.cc rgw/test_build_librgw-rgw_rest_conn.obj: rgw/rgw_rest_conn.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_rest_conn.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Tpo -c -o rgw/test_build_librgw-rgw_rest_conn.obj `if test -f 'rgw/rgw_rest_conn.cc'; then $(CYGPATH_W) 'rgw/rgw_rest_conn.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_rest_conn.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_rest_conn.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_rest_conn.cc' object='rgw/test_build_librgw-rgw_rest_conn.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_rest_conn.obj `if test -f 'rgw/rgw_rest_conn.cc'; then $(CYGPATH_W) 'rgw/rgw_rest_conn.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_rest_conn.cc'; fi` rgw/test_build_librgw-rgw_op.o: rgw/rgw_op.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_op.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_op.Tpo -c -o rgw/test_build_librgw-rgw_op.o `test -f 'rgw/rgw_op.cc' || echo '$(srcdir)/'`rgw/rgw_op.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_op.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_op.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_op.cc' object='rgw/test_build_librgw-rgw_op.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_op.o `test -f 'rgw/rgw_op.cc' || echo '$(srcdir)/'`rgw/rgw_op.cc rgw/test_build_librgw-rgw_op.obj: rgw/rgw_op.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_op.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_op.Tpo -c -o rgw/test_build_librgw-rgw_op.obj `if test -f 'rgw/rgw_op.cc'; then $(CYGPATH_W) 'rgw/rgw_op.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_op.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_op.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_op.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_op.cc' object='rgw/test_build_librgw-rgw_op.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_op.obj `if test -f 'rgw/rgw_op.cc'; then $(CYGPATH_W) 'rgw/rgw_op.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_op.cc'; fi` rgw/test_build_librgw-rgw_common.o: rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_common.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_common.Tpo -c -o rgw/test_build_librgw-rgw_common.o `test -f 'rgw/rgw_common.cc' || echo '$(srcdir)/'`rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_common.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_common.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_common.cc' object='rgw/test_build_librgw-rgw_common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_common.o `test -f 'rgw/rgw_common.cc' || echo '$(srcdir)/'`rgw/rgw_common.cc rgw/test_build_librgw-rgw_common.obj: rgw/rgw_common.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_common.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_common.Tpo -c -o rgw/test_build_librgw-rgw_common.obj `if test -f 'rgw/rgw_common.cc'; then $(CYGPATH_W) 'rgw/rgw_common.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_common.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_common.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_common.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_common.cc' object='rgw/test_build_librgw-rgw_common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_common.obj `if test -f 'rgw/rgw_common.cc'; then $(CYGPATH_W) 'rgw/rgw_common.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_common.cc'; fi` rgw/test_build_librgw-rgw_cache.o: rgw/rgw_cache.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_cache.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Tpo -c -o rgw/test_build_librgw-rgw_cache.o `test -f 'rgw/rgw_cache.cc' || echo '$(srcdir)/'`rgw/rgw_cache.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cache.cc' object='rgw/test_build_librgw-rgw_cache.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_cache.o `test -f 'rgw/rgw_cache.cc' || echo '$(srcdir)/'`rgw/rgw_cache.cc rgw/test_build_librgw-rgw_cache.obj: rgw/rgw_cache.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_cache.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Tpo -c -o rgw/test_build_librgw-rgw_cache.obj `if test -f 'rgw/rgw_cache.cc'; then $(CYGPATH_W) 'rgw/rgw_cache.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_cache.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_cache.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cache.cc' object='rgw/test_build_librgw-rgw_cache.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_cache.obj `if test -f 'rgw/rgw_cache.cc'; then $(CYGPATH_W) 'rgw/rgw_cache.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_cache.cc'; fi` rgw/test_build_librgw-rgw_formats.o: rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_formats.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Tpo -c -o rgw/test_build_librgw-rgw_formats.o `test -f 'rgw/rgw_formats.cc' || echo '$(srcdir)/'`rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_formats.cc' object='rgw/test_build_librgw-rgw_formats.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_formats.o `test -f 'rgw/rgw_formats.cc' || echo '$(srcdir)/'`rgw/rgw_formats.cc rgw/test_build_librgw-rgw_formats.obj: rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_formats.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Tpo -c -o rgw/test_build_librgw-rgw_formats.obj `if test -f 'rgw/rgw_formats.cc'; then $(CYGPATH_W) 'rgw/rgw_formats.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_formats.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_formats.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_formats.cc' object='rgw/test_build_librgw-rgw_formats.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_formats.obj `if test -f 'rgw/rgw_formats.cc'; then $(CYGPATH_W) 'rgw/rgw_formats.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_formats.cc'; fi` rgw/test_build_librgw-rgw_log.o: rgw/rgw_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_log.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_log.Tpo -c -o rgw/test_build_librgw-rgw_log.o `test -f 'rgw/rgw_log.cc' || echo '$(srcdir)/'`rgw/rgw_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_log.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_log.cc' object='rgw/test_build_librgw-rgw_log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_log.o `test -f 'rgw/rgw_log.cc' || echo '$(srcdir)/'`rgw/rgw_log.cc rgw/test_build_librgw-rgw_log.obj: rgw/rgw_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_log.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_log.Tpo -c -o rgw/test_build_librgw-rgw_log.obj `if test -f 'rgw/rgw_log.cc'; then $(CYGPATH_W) 'rgw/rgw_log.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_log.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_log.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_log.cc' object='rgw/test_build_librgw-rgw_log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_log.obj `if test -f 'rgw/rgw_log.cc'; then $(CYGPATH_W) 'rgw/rgw_log.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_log.cc'; fi` rgw/test_build_librgw-rgw_multi.o: rgw/rgw_multi.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_multi.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Tpo -c -o rgw/test_build_librgw-rgw_multi.o `test -f 'rgw/rgw_multi.cc' || echo '$(srcdir)/'`rgw/rgw_multi.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_multi.cc' object='rgw/test_build_librgw-rgw_multi.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_multi.o `test -f 'rgw/rgw_multi.cc' || echo '$(srcdir)/'`rgw/rgw_multi.cc rgw/test_build_librgw-rgw_multi.obj: rgw/rgw_multi.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_multi.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Tpo -c -o rgw/test_build_librgw-rgw_multi.obj `if test -f 'rgw/rgw_multi.cc'; then $(CYGPATH_W) 'rgw/rgw_multi.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_multi.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_multi.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_multi.cc' object='rgw/test_build_librgw-rgw_multi.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_multi.obj `if test -f 'rgw/rgw_multi.cc'; then $(CYGPATH_W) 'rgw/rgw_multi.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_multi.cc'; fi` rgw/test_build_librgw-rgw_policy_s3.o: rgw/rgw_policy_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_policy_s3.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Tpo -c -o rgw/test_build_librgw-rgw_policy_s3.o `test -f 'rgw/rgw_policy_s3.cc' || echo '$(srcdir)/'`rgw/rgw_policy_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_policy_s3.cc' object='rgw/test_build_librgw-rgw_policy_s3.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_policy_s3.o `test -f 'rgw/rgw_policy_s3.cc' || echo '$(srcdir)/'`rgw/rgw_policy_s3.cc rgw/test_build_librgw-rgw_policy_s3.obj: rgw/rgw_policy_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_policy_s3.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Tpo -c -o rgw/test_build_librgw-rgw_policy_s3.obj `if test -f 'rgw/rgw_policy_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_policy_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_policy_s3.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_policy_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_policy_s3.cc' object='rgw/test_build_librgw-rgw_policy_s3.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_policy_s3.obj `if test -f 'rgw/rgw_policy_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_policy_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_policy_s3.cc'; fi` rgw/test_build_librgw-rgw_gc.o: rgw/rgw_gc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_gc.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Tpo -c -o rgw/test_build_librgw-rgw_gc.o `test -f 'rgw/rgw_gc.cc' || echo '$(srcdir)/'`rgw/rgw_gc.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_gc.cc' object='rgw/test_build_librgw-rgw_gc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_gc.o `test -f 'rgw/rgw_gc.cc' || echo '$(srcdir)/'`rgw/rgw_gc.cc rgw/test_build_librgw-rgw_gc.obj: rgw/rgw_gc.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_gc.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Tpo -c -o rgw/test_build_librgw-rgw_gc.obj `if test -f 'rgw/rgw_gc.cc'; then $(CYGPATH_W) 'rgw/rgw_gc.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_gc.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_gc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_gc.cc' object='rgw/test_build_librgw-rgw_gc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_gc.obj `if test -f 'rgw/rgw_gc.cc'; then $(CYGPATH_W) 'rgw/rgw_gc.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_gc.cc'; fi` rgw/test_build_librgw-rgw_multi_del.o: rgw/rgw_multi_del.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_multi_del.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Tpo -c -o rgw/test_build_librgw-rgw_multi_del.o `test -f 'rgw/rgw_multi_del.cc' || echo '$(srcdir)/'`rgw/rgw_multi_del.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_multi_del.cc' object='rgw/test_build_librgw-rgw_multi_del.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_multi_del.o `test -f 'rgw/rgw_multi_del.cc' || echo '$(srcdir)/'`rgw/rgw_multi_del.cc rgw/test_build_librgw-rgw_multi_del.obj: rgw/rgw_multi_del.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_multi_del.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Tpo -c -o rgw/test_build_librgw-rgw_multi_del.obj `if test -f 'rgw/rgw_multi_del.cc'; then $(CYGPATH_W) 'rgw/rgw_multi_del.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_multi_del.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_multi_del.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_multi_del.cc' object='rgw/test_build_librgw-rgw_multi_del.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_multi_del.obj `if test -f 'rgw/rgw_multi_del.cc'; then $(CYGPATH_W) 'rgw/rgw_multi_del.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_multi_del.cc'; fi` rgw/test_build_librgw-rgw_env.o: rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_env.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_env.Tpo -c -o rgw/test_build_librgw-rgw_env.o `test -f 'rgw/rgw_env.cc' || echo '$(srcdir)/'`rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_env.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_env.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_env.cc' object='rgw/test_build_librgw-rgw_env.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_env.o `test -f 'rgw/rgw_env.cc' || echo '$(srcdir)/'`rgw/rgw_env.cc rgw/test_build_librgw-rgw_env.obj: rgw/rgw_env.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_env.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_env.Tpo -c -o rgw/test_build_librgw-rgw_env.obj `if test -f 'rgw/rgw_env.cc'; then $(CYGPATH_W) 'rgw/rgw_env.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_env.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_env.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_env.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_env.cc' object='rgw/test_build_librgw-rgw_env.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_env.obj `if test -f 'rgw/rgw_env.cc'; then $(CYGPATH_W) 'rgw/rgw_env.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_env.cc'; fi` rgw/test_build_librgw-rgw_cors.o: rgw/rgw_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_cors.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Tpo -c -o rgw/test_build_librgw-rgw_cors.o `test -f 'rgw/rgw_cors.cc' || echo '$(srcdir)/'`rgw/rgw_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cors.cc' object='rgw/test_build_librgw-rgw_cors.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_cors.o `test -f 'rgw/rgw_cors.cc' || echo '$(srcdir)/'`rgw/rgw_cors.cc rgw/test_build_librgw-rgw_cors.obj: rgw/rgw_cors.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_cors.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Tpo -c -o rgw/test_build_librgw-rgw_cors.obj `if test -f 'rgw/rgw_cors.cc'; then $(CYGPATH_W) 'rgw/rgw_cors.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_cors.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_cors.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cors.cc' object='rgw/test_build_librgw-rgw_cors.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_cors.obj `if test -f 'rgw/rgw_cors.cc'; then $(CYGPATH_W) 'rgw/rgw_cors.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_cors.cc'; fi` rgw/test_build_librgw-rgw_cors_s3.o: rgw/rgw_cors_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_cors_s3.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Tpo -c -o rgw/test_build_librgw-rgw_cors_s3.o `test -f 'rgw/rgw_cors_s3.cc' || echo '$(srcdir)/'`rgw/rgw_cors_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cors_s3.cc' object='rgw/test_build_librgw-rgw_cors_s3.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_cors_s3.o `test -f 'rgw/rgw_cors_s3.cc' || echo '$(srcdir)/'`rgw/rgw_cors_s3.cc rgw/test_build_librgw-rgw_cors_s3.obj: rgw/rgw_cors_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_cors_s3.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Tpo -c -o rgw/test_build_librgw-rgw_cors_s3.obj `if test -f 'rgw/rgw_cors_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_cors_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_cors_s3.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_cors_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_cors_s3.cc' object='rgw/test_build_librgw-rgw_cors_s3.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_cors_s3.obj `if test -f 'rgw/rgw_cors_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_cors_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_cors_s3.cc'; fi` rgw/test_build_librgw-rgw_auth_s3.o: rgw/rgw_auth_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_auth_s3.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Tpo -c -o rgw/test_build_librgw-rgw_auth_s3.o `test -f 'rgw/rgw_auth_s3.cc' || echo '$(srcdir)/'`rgw/rgw_auth_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_auth_s3.cc' object='rgw/test_build_librgw-rgw_auth_s3.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_auth_s3.o `test -f 'rgw/rgw_auth_s3.cc' || echo '$(srcdir)/'`rgw/rgw_auth_s3.cc rgw/test_build_librgw-rgw_auth_s3.obj: rgw/rgw_auth_s3.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_auth_s3.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Tpo -c -o rgw/test_build_librgw-rgw_auth_s3.obj `if test -f 'rgw/rgw_auth_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_auth_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_auth_s3.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_auth_s3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_auth_s3.cc' object='rgw/test_build_librgw-rgw_auth_s3.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_auth_s3.obj `if test -f 'rgw/rgw_auth_s3.cc'; then $(CYGPATH_W) 'rgw/rgw_auth_s3.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_auth_s3.cc'; fi` rgw/test_build_librgw-rgw_metadata.o: rgw/rgw_metadata.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_metadata.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Tpo -c -o rgw/test_build_librgw-rgw_metadata.o `test -f 'rgw/rgw_metadata.cc' || echo '$(srcdir)/'`rgw/rgw_metadata.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_metadata.cc' object='rgw/test_build_librgw-rgw_metadata.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_metadata.o `test -f 'rgw/rgw_metadata.cc' || echo '$(srcdir)/'`rgw/rgw_metadata.cc rgw/test_build_librgw-rgw_metadata.obj: rgw/rgw_metadata.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_metadata.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Tpo -c -o rgw/test_build_librgw-rgw_metadata.obj `if test -f 'rgw/rgw_metadata.cc'; then $(CYGPATH_W) 'rgw/rgw_metadata.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_metadata.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_metadata.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_metadata.cc' object='rgw/test_build_librgw-rgw_metadata.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_metadata.obj `if test -f 'rgw/rgw_metadata.cc'; then $(CYGPATH_W) 'rgw/rgw_metadata.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_metadata.cc'; fi` rgw/test_build_librgw-rgw_replica_log.o: rgw/rgw_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_replica_log.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Tpo -c -o rgw/test_build_librgw-rgw_replica_log.o `test -f 'rgw/rgw_replica_log.cc' || echo '$(srcdir)/'`rgw/rgw_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_replica_log.cc' object='rgw/test_build_librgw-rgw_replica_log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_replica_log.o `test -f 'rgw/rgw_replica_log.cc' || echo '$(srcdir)/'`rgw/rgw_replica_log.cc rgw/test_build_librgw-rgw_replica_log.obj: rgw/rgw_replica_log.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_replica_log.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Tpo -c -o rgw/test_build_librgw-rgw_replica_log.obj `if test -f 'rgw/rgw_replica_log.cc'; then $(CYGPATH_W) 'rgw/rgw_replica_log.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_replica_log.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_replica_log.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_replica_log.cc' object='rgw/test_build_librgw-rgw_replica_log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_replica_log.obj `if test -f 'rgw/rgw_replica_log.cc'; then $(CYGPATH_W) 'rgw/rgw_replica_log.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_replica_log.cc'; fi` rgw/test_build_librgw-rgw_keystone.o: rgw/rgw_keystone.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_keystone.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Tpo -c -o rgw/test_build_librgw-rgw_keystone.o `test -f 'rgw/rgw_keystone.cc' || echo '$(srcdir)/'`rgw/rgw_keystone.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_keystone.cc' object='rgw/test_build_librgw-rgw_keystone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_keystone.o `test -f 'rgw/rgw_keystone.cc' || echo '$(srcdir)/'`rgw/rgw_keystone.cc rgw/test_build_librgw-rgw_keystone.obj: rgw/rgw_keystone.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_keystone.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Tpo -c -o rgw/test_build_librgw-rgw_keystone.obj `if test -f 'rgw/rgw_keystone.cc'; then $(CYGPATH_W) 'rgw/rgw_keystone.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_keystone.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_keystone.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_keystone.cc' object='rgw/test_build_librgw-rgw_keystone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_keystone.obj `if test -f 'rgw/rgw_keystone.cc'; then $(CYGPATH_W) 'rgw/rgw_keystone.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_keystone.cc'; fi` rgw/test_build_librgw-rgw_quota.o: rgw/rgw_quota.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_quota.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Tpo -c -o rgw/test_build_librgw-rgw_quota.o `test -f 'rgw/rgw_quota.cc' || echo '$(srcdir)/'`rgw/rgw_quota.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_quota.cc' object='rgw/test_build_librgw-rgw_quota.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_quota.o `test -f 'rgw/rgw_quota.cc' || echo '$(srcdir)/'`rgw/rgw_quota.cc rgw/test_build_librgw-rgw_quota.obj: rgw/rgw_quota.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_quota.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Tpo -c -o rgw/test_build_librgw-rgw_quota.obj `if test -f 'rgw/rgw_quota.cc'; then $(CYGPATH_W) 'rgw/rgw_quota.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_quota.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_quota.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_quota.cc' object='rgw/test_build_librgw-rgw_quota.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_quota.obj `if test -f 'rgw/rgw_quota.cc'; then $(CYGPATH_W) 'rgw/rgw_quota.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_quota.cc'; fi` rgw/test_build_librgw-rgw_dencoder.o: rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_dencoder.o -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Tpo -c -o rgw/test_build_librgw-rgw_dencoder.o `test -f 'rgw/rgw_dencoder.cc' || echo '$(srcdir)/'`rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_dencoder.cc' object='rgw/test_build_librgw-rgw_dencoder.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_dencoder.o `test -f 'rgw/rgw_dencoder.cc' || echo '$(srcdir)/'`rgw/rgw_dencoder.cc rgw/test_build_librgw-rgw_dencoder.obj: rgw/rgw_dencoder.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -MT rgw/test_build_librgw-rgw_dencoder.obj -MD -MP -MF rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Tpo -c -o rgw/test_build_librgw-rgw_dencoder.obj `if test -f 'rgw/rgw_dencoder.cc'; then $(CYGPATH_W) 'rgw/rgw_dencoder.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_dencoder.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Tpo rgw/$(DEPDIR)/test_build_librgw-rgw_dencoder.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_dencoder.cc' object='rgw/test_build_librgw-rgw_dencoder.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_build_librgw_CXXFLAGS) $(CXXFLAGS) -c -o rgw/test_build_librgw-rgw_dencoder.obj `if test -f 'rgw/rgw_dencoder.cc'; then $(CYGPATH_W) 'rgw/rgw_dencoder.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_dencoder.cc'; fi` test/unittest_addrs-test_addrs.o: test/test_addrs.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_addrs_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_addrs-test_addrs.o -MD -MP -MF test/$(DEPDIR)/unittest_addrs-test_addrs.Tpo -c -o test/unittest_addrs-test_addrs.o `test -f 'test/test_addrs.cc' || echo '$(srcdir)/'`test/test_addrs.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_addrs-test_addrs.Tpo test/$(DEPDIR)/unittest_addrs-test_addrs.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_addrs.cc' object='test/unittest_addrs-test_addrs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_addrs_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_addrs-test_addrs.o `test -f 'test/test_addrs.cc' || echo '$(srcdir)/'`test/test_addrs.cc test/unittest_addrs-test_addrs.obj: test/test_addrs.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_addrs_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_addrs-test_addrs.obj -MD -MP -MF test/$(DEPDIR)/unittest_addrs-test_addrs.Tpo -c -o test/unittest_addrs-test_addrs.obj `if test -f 'test/test_addrs.cc'; then $(CYGPATH_W) 'test/test_addrs.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_addrs.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_addrs-test_addrs.Tpo test/$(DEPDIR)/unittest_addrs-test_addrs.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_addrs.cc' object='test/unittest_addrs-test_addrs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_addrs_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_addrs-test_addrs.obj `if test -f 'test/test_addrs.cc'; then $(CYGPATH_W) 'test/test_addrs.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_addrs.cc'; fi` test/unittest_admin_socket-admin_socket.o: test/admin_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_admin_socket_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_admin_socket-admin_socket.o -MD -MP -MF test/$(DEPDIR)/unittest_admin_socket-admin_socket.Tpo -c -o test/unittest_admin_socket-admin_socket.o `test -f 'test/admin_socket.cc' || echo '$(srcdir)/'`test/admin_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_admin_socket-admin_socket.Tpo test/$(DEPDIR)/unittest_admin_socket-admin_socket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/admin_socket.cc' object='test/unittest_admin_socket-admin_socket.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_admin_socket_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_admin_socket-admin_socket.o `test -f 'test/admin_socket.cc' || echo '$(srcdir)/'`test/admin_socket.cc test/unittest_admin_socket-admin_socket.obj: test/admin_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_admin_socket_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_admin_socket-admin_socket.obj -MD -MP -MF test/$(DEPDIR)/unittest_admin_socket-admin_socket.Tpo -c -o test/unittest_admin_socket-admin_socket.obj `if test -f 'test/admin_socket.cc'; then $(CYGPATH_W) 'test/admin_socket.cc'; else $(CYGPATH_W) '$(srcdir)/test/admin_socket.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_admin_socket-admin_socket.Tpo test/$(DEPDIR)/unittest_admin_socket-admin_socket.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/admin_socket.cc' object='test/unittest_admin_socket-admin_socket.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_admin_socket_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_admin_socket-admin_socket.obj `if test -f 'test/admin_socket.cc'; then $(CYGPATH_W) 'test/admin_socket.cc'; else $(CYGPATH_W) '$(srcdir)/test/admin_socket.cc'; fi` test/unittest_arch-test_arch.o: test/test_arch.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_arch_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_arch-test_arch.o -MD -MP -MF test/$(DEPDIR)/unittest_arch-test_arch.Tpo -c -o test/unittest_arch-test_arch.o `test -f 'test/test_arch.cc' || echo '$(srcdir)/'`test/test_arch.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_arch-test_arch.Tpo test/$(DEPDIR)/unittest_arch-test_arch.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_arch.cc' object='test/unittest_arch-test_arch.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_arch_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_arch-test_arch.o `test -f 'test/test_arch.cc' || echo '$(srcdir)/'`test/test_arch.cc test/unittest_arch-test_arch.obj: test/test_arch.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_arch_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_arch-test_arch.obj -MD -MP -MF test/$(DEPDIR)/unittest_arch-test_arch.Tpo -c -o test/unittest_arch-test_arch.obj `if test -f 'test/test_arch.cc'; then $(CYGPATH_W) 'test/test_arch.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_arch.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_arch-test_arch.Tpo test/$(DEPDIR)/unittest_arch-test_arch.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_arch.cc' object='test/unittest_arch-test_arch.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_arch_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_arch-test_arch.obj `if test -f 'test/test_arch.cc'; then $(CYGPATH_W) 'test/test_arch.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_arch.cc'; fi` test/unittest_base64-base64.o: test/base64.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_base64_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_base64-base64.o -MD -MP -MF test/$(DEPDIR)/unittest_base64-base64.Tpo -c -o test/unittest_base64-base64.o `test -f 'test/base64.cc' || echo '$(srcdir)/'`test/base64.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_base64-base64.Tpo test/$(DEPDIR)/unittest_base64-base64.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/base64.cc' object='test/unittest_base64-base64.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_base64_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_base64-base64.o `test -f 'test/base64.cc' || echo '$(srcdir)/'`test/base64.cc test/unittest_base64-base64.obj: test/base64.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_base64_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_base64-base64.obj -MD -MP -MF test/$(DEPDIR)/unittest_base64-base64.Tpo -c -o test/unittest_base64-base64.obj `if test -f 'test/base64.cc'; then $(CYGPATH_W) 'test/base64.cc'; else $(CYGPATH_W) '$(srcdir)/test/base64.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_base64-base64.Tpo test/$(DEPDIR)/unittest_base64-base64.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/base64.cc' object='test/unittest_base64-base64.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_base64_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_base64-base64.obj `if test -f 'test/base64.cc'; then $(CYGPATH_W) 'test/base64.cc'; else $(CYGPATH_W) '$(srcdir)/test/base64.cc'; fi` test/common/unittest_bloom_filter-test_bloom_filter.o: test/common/test_bloom_filter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bloom_filter_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_bloom_filter-test_bloom_filter.o -MD -MP -MF test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Tpo -c -o test/common/unittest_bloom_filter-test_bloom_filter.o `test -f 'test/common/test_bloom_filter.cc' || echo '$(srcdir)/'`test/common/test_bloom_filter.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Tpo test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_bloom_filter.cc' object='test/common/unittest_bloom_filter-test_bloom_filter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bloom_filter_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_bloom_filter-test_bloom_filter.o `test -f 'test/common/test_bloom_filter.cc' || echo '$(srcdir)/'`test/common/test_bloom_filter.cc test/common/unittest_bloom_filter-test_bloom_filter.obj: test/common/test_bloom_filter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bloom_filter_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_bloom_filter-test_bloom_filter.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Tpo -c -o test/common/unittest_bloom_filter-test_bloom_filter.obj `if test -f 'test/common/test_bloom_filter.cc'; then $(CYGPATH_W) 'test/common/test_bloom_filter.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_bloom_filter.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Tpo test/common/$(DEPDIR)/unittest_bloom_filter-test_bloom_filter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_bloom_filter.cc' object='test/common/unittest_bloom_filter-test_bloom_filter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bloom_filter_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_bloom_filter-test_bloom_filter.obj `if test -f 'test/common/test_bloom_filter.cc'; then $(CYGPATH_W) 'test/common/test_bloom_filter.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_bloom_filter.cc'; fi` test/unittest_bufferlist-bufferlist.o: test/bufferlist.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bufferlist_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_bufferlist-bufferlist.o -MD -MP -MF test/$(DEPDIR)/unittest_bufferlist-bufferlist.Tpo -c -o test/unittest_bufferlist-bufferlist.o `test -f 'test/bufferlist.cc' || echo '$(srcdir)/'`test/bufferlist.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_bufferlist-bufferlist.Tpo test/$(DEPDIR)/unittest_bufferlist-bufferlist.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/bufferlist.cc' object='test/unittest_bufferlist-bufferlist.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bufferlist_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_bufferlist-bufferlist.o `test -f 'test/bufferlist.cc' || echo '$(srcdir)/'`test/bufferlist.cc test/unittest_bufferlist-bufferlist.obj: test/bufferlist.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bufferlist_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_bufferlist-bufferlist.obj -MD -MP -MF test/$(DEPDIR)/unittest_bufferlist-bufferlist.Tpo -c -o test/unittest_bufferlist-bufferlist.obj `if test -f 'test/bufferlist.cc'; then $(CYGPATH_W) 'test/bufferlist.cc'; else $(CYGPATH_W) '$(srcdir)/test/bufferlist.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_bufferlist-bufferlist.Tpo test/$(DEPDIR)/unittest_bufferlist-bufferlist.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/bufferlist.cc' object='test/unittest_bufferlist-bufferlist.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_bufferlist_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_bufferlist-bufferlist.obj `if test -f 'test/bufferlist.cc'; then $(CYGPATH_W) 'test/bufferlist.cc'; else $(CYGPATH_W) '$(srcdir)/test/bufferlist.cc'; fi` test/unittest_ceph_argparse-ceph_argparse.o: test/ceph_argparse.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_argparse_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ceph_argparse-ceph_argparse.o -MD -MP -MF test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Tpo -c -o test/unittest_ceph_argparse-ceph_argparse.o `test -f 'test/ceph_argparse.cc' || echo '$(srcdir)/'`test/ceph_argparse.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Tpo test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ceph_argparse.cc' object='test/unittest_ceph_argparse-ceph_argparse.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_argparse_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ceph_argparse-ceph_argparse.o `test -f 'test/ceph_argparse.cc' || echo '$(srcdir)/'`test/ceph_argparse.cc test/unittest_ceph_argparse-ceph_argparse.obj: test/ceph_argparse.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_argparse_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ceph_argparse-ceph_argparse.obj -MD -MP -MF test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Tpo -c -o test/unittest_ceph_argparse-ceph_argparse.obj `if test -f 'test/ceph_argparse.cc'; then $(CYGPATH_W) 'test/ceph_argparse.cc'; else $(CYGPATH_W) '$(srcdir)/test/ceph_argparse.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Tpo test/$(DEPDIR)/unittest_ceph_argparse-ceph_argparse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ceph_argparse.cc' object='test/unittest_ceph_argparse-ceph_argparse.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_argparse_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ceph_argparse-ceph_argparse.obj `if test -f 'test/ceph_argparse.cc'; then $(CYGPATH_W) 'test/ceph_argparse.cc'; else $(CYGPATH_W) '$(srcdir)/test/ceph_argparse.cc'; fi` test/unittest_ceph_compatset-ceph_compatset.o: test/ceph_compatset.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_compatset_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ceph_compatset-ceph_compatset.o -MD -MP -MF test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Tpo -c -o test/unittest_ceph_compatset-ceph_compatset.o `test -f 'test/ceph_compatset.cc' || echo '$(srcdir)/'`test/ceph_compatset.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Tpo test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ceph_compatset.cc' object='test/unittest_ceph_compatset-ceph_compatset.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_compatset_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ceph_compatset-ceph_compatset.o `test -f 'test/ceph_compatset.cc' || echo '$(srcdir)/'`test/ceph_compatset.cc test/unittest_ceph_compatset-ceph_compatset.obj: test/ceph_compatset.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_compatset_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ceph_compatset-ceph_compatset.obj -MD -MP -MF test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Tpo -c -o test/unittest_ceph_compatset-ceph_compatset.obj `if test -f 'test/ceph_compatset.cc'; then $(CYGPATH_W) 'test/ceph_compatset.cc'; else $(CYGPATH_W) '$(srcdir)/test/ceph_compatset.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Tpo test/$(DEPDIR)/unittest_ceph_compatset-ceph_compatset.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ceph_compatset.cc' object='test/unittest_ceph_compatset-ceph_compatset.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_compatset_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ceph_compatset-ceph_compatset.obj `if test -f 'test/ceph_compatset.cc'; then $(CYGPATH_W) 'test/ceph_compatset.cc'; else $(CYGPATH_W) '$(srcdir)/test/ceph_compatset.cc'; fi` test/unittest_ceph_crypto-ceph_crypto.o: test/ceph_crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_crypto_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ceph_crypto-ceph_crypto.o -MD -MP -MF test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Tpo -c -o test/unittest_ceph_crypto-ceph_crypto.o `test -f 'test/ceph_crypto.cc' || echo '$(srcdir)/'`test/ceph_crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Tpo test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ceph_crypto.cc' object='test/unittest_ceph_crypto-ceph_crypto.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_crypto_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ceph_crypto-ceph_crypto.o `test -f 'test/ceph_crypto.cc' || echo '$(srcdir)/'`test/ceph_crypto.cc test/unittest_ceph_crypto-ceph_crypto.obj: test/ceph_crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_crypto_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ceph_crypto-ceph_crypto.obj -MD -MP -MF test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Tpo -c -o test/unittest_ceph_crypto-ceph_crypto.obj `if test -f 'test/ceph_crypto.cc'; then $(CYGPATH_W) 'test/ceph_crypto.cc'; else $(CYGPATH_W) '$(srcdir)/test/ceph_crypto.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Tpo test/$(DEPDIR)/unittest_ceph_crypto-ceph_crypto.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/ceph_crypto.cc' object='test/unittest_ceph_crypto-ceph_crypto.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ceph_crypto_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ceph_crypto-ceph_crypto.obj `if test -f 'test/ceph_crypto.cc'; then $(CYGPATH_W) 'test/ceph_crypto.cc'; else $(CYGPATH_W) '$(srcdir)/test/ceph_crypto.cc'; fi` test/objectstore/unittest_chain_xattr-chain_xattr.o: test/objectstore/chain_xattr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_chain_xattr_CXXFLAGS) $(CXXFLAGS) -MT test/objectstore/unittest_chain_xattr-chain_xattr.o -MD -MP -MF test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Tpo -c -o test/objectstore/unittest_chain_xattr-chain_xattr.o `test -f 'test/objectstore/chain_xattr.cc' || echo '$(srcdir)/'`test/objectstore/chain_xattr.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Tpo test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/objectstore/chain_xattr.cc' object='test/objectstore/unittest_chain_xattr-chain_xattr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_chain_xattr_CXXFLAGS) $(CXXFLAGS) -c -o test/objectstore/unittest_chain_xattr-chain_xattr.o `test -f 'test/objectstore/chain_xattr.cc' || echo '$(srcdir)/'`test/objectstore/chain_xattr.cc test/objectstore/unittest_chain_xattr-chain_xattr.obj: test/objectstore/chain_xattr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_chain_xattr_CXXFLAGS) $(CXXFLAGS) -MT test/objectstore/unittest_chain_xattr-chain_xattr.obj -MD -MP -MF test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Tpo -c -o test/objectstore/unittest_chain_xattr-chain_xattr.obj `if test -f 'test/objectstore/chain_xattr.cc'; then $(CYGPATH_W) 'test/objectstore/chain_xattr.cc'; else $(CYGPATH_W) '$(srcdir)/test/objectstore/chain_xattr.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Tpo test/objectstore/$(DEPDIR)/unittest_chain_xattr-chain_xattr.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/objectstore/chain_xattr.cc' object='test/objectstore/unittest_chain_xattr-chain_xattr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_chain_xattr_CXXFLAGS) $(CXXFLAGS) -c -o test/objectstore/unittest_chain_xattr-chain_xattr.obj `if test -f 'test/objectstore/chain_xattr.cc'; then $(CYGPATH_W) 'test/objectstore/chain_xattr.cc'; else $(CYGPATH_W) '$(srcdir)/test/objectstore/chain_xattr.cc'; fi` test/common/unittest_config-test_config.o: test/common/test_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_config_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_config-test_config.o -MD -MP -MF test/common/$(DEPDIR)/unittest_config-test_config.Tpo -c -o test/common/unittest_config-test_config.o `test -f 'test/common/test_config.cc' || echo '$(srcdir)/'`test/common/test_config.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_config-test_config.Tpo test/common/$(DEPDIR)/unittest_config-test_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_config.cc' object='test/common/unittest_config-test_config.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_config_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_config-test_config.o `test -f 'test/common/test_config.cc' || echo '$(srcdir)/'`test/common/test_config.cc test/common/unittest_config-test_config.obj: test/common/test_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_config_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_config-test_config.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_config-test_config.Tpo -c -o test/common/unittest_config-test_config.obj `if test -f 'test/common/test_config.cc'; then $(CYGPATH_W) 'test/common/test_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_config.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_config-test_config.Tpo test/common/$(DEPDIR)/unittest_config-test_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_config.cc' object='test/common/unittest_config-test_config.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_config_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_config-test_config.obj `if test -f 'test/common/test_config.cc'; then $(CYGPATH_W) 'test/common/test_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_config.cc'; fi` test/unittest_confutils-confutils.o: test/confutils.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_confutils_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_confutils-confutils.o -MD -MP -MF test/$(DEPDIR)/unittest_confutils-confutils.Tpo -c -o test/unittest_confutils-confutils.o `test -f 'test/confutils.cc' || echo '$(srcdir)/'`test/confutils.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_confutils-confutils.Tpo test/$(DEPDIR)/unittest_confutils-confutils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/confutils.cc' object='test/unittest_confutils-confutils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_confutils_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_confutils-confutils.o `test -f 'test/confutils.cc' || echo '$(srcdir)/'`test/confutils.cc test/unittest_confutils-confutils.obj: test/confutils.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_confutils_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_confutils-confutils.obj -MD -MP -MF test/$(DEPDIR)/unittest_confutils-confutils.Tpo -c -o test/unittest_confutils-confutils.obj `if test -f 'test/confutils.cc'; then $(CYGPATH_W) 'test/confutils.cc'; else $(CYGPATH_W) '$(srcdir)/test/confutils.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_confutils-confutils.Tpo test/$(DEPDIR)/unittest_confutils-confutils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/confutils.cc' object='test/unittest_confutils-confutils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_confutils_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_confutils-confutils.obj `if test -f 'test/confutils.cc'; then $(CYGPATH_W) 'test/confutils.cc'; else $(CYGPATH_W) '$(srcdir)/test/confutils.cc'; fi` test/common/unittest_context-test_context.o: test/common/test_context.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_context_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_context-test_context.o -MD -MP -MF test/common/$(DEPDIR)/unittest_context-test_context.Tpo -c -o test/common/unittest_context-test_context.o `test -f 'test/common/test_context.cc' || echo '$(srcdir)/'`test/common/test_context.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_context-test_context.Tpo test/common/$(DEPDIR)/unittest_context-test_context.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_context.cc' object='test/common/unittest_context-test_context.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_context_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_context-test_context.o `test -f 'test/common/test_context.cc' || echo '$(srcdir)/'`test/common/test_context.cc test/common/unittest_context-test_context.obj: test/common/test_context.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_context_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_context-test_context.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_context-test_context.Tpo -c -o test/common/unittest_context-test_context.obj `if test -f 'test/common/test_context.cc'; then $(CYGPATH_W) 'test/common/test_context.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_context.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_context-test_context.Tpo test/common/$(DEPDIR)/unittest_context-test_context.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_context.cc' object='test/common/unittest_context-test_context.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_context_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_context-test_context.obj `if test -f 'test/common/test_context.cc'; then $(CYGPATH_W) 'test/common/test_context.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_context.cc'; fi` test/common/unittest_crc32c-test_crc32c.o: test/common/test_crc32c.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crc32c_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_crc32c-test_crc32c.o -MD -MP -MF test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Tpo -c -o test/common/unittest_crc32c-test_crc32c.o `test -f 'test/common/test_crc32c.cc' || echo '$(srcdir)/'`test/common/test_crc32c.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Tpo test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_crc32c.cc' object='test/common/unittest_crc32c-test_crc32c.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crc32c_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_crc32c-test_crc32c.o `test -f 'test/common/test_crc32c.cc' || echo '$(srcdir)/'`test/common/test_crc32c.cc test/common/unittest_crc32c-test_crc32c.obj: test/common/test_crc32c.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crc32c_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_crc32c-test_crc32c.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Tpo -c -o test/common/unittest_crc32c-test_crc32c.obj `if test -f 'test/common/test_crc32c.cc'; then $(CYGPATH_W) 'test/common/test_crc32c.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_crc32c.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Tpo test/common/$(DEPDIR)/unittest_crc32c-test_crc32c.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_crc32c.cc' object='test/common/unittest_crc32c-test_crc32c.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crc32c_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_crc32c-test_crc32c.obj `if test -f 'test/common/test_crc32c.cc'; then $(CYGPATH_W) 'test/common/test_crc32c.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_crc32c.cc'; fi` test/crush/unittest_crush_indep-indep.o: test/crush/indep.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_indep_CXXFLAGS) $(CXXFLAGS) -MT test/crush/unittest_crush_indep-indep.o -MD -MP -MF test/crush/$(DEPDIR)/unittest_crush_indep-indep.Tpo -c -o test/crush/unittest_crush_indep-indep.o `test -f 'test/crush/indep.cc' || echo '$(srcdir)/'`test/crush/indep.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/crush/$(DEPDIR)/unittest_crush_indep-indep.Tpo test/crush/$(DEPDIR)/unittest_crush_indep-indep.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crush/indep.cc' object='test/crush/unittest_crush_indep-indep.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_indep_CXXFLAGS) $(CXXFLAGS) -c -o test/crush/unittest_crush_indep-indep.o `test -f 'test/crush/indep.cc' || echo '$(srcdir)/'`test/crush/indep.cc test/crush/unittest_crush_indep-indep.obj: test/crush/indep.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_indep_CXXFLAGS) $(CXXFLAGS) -MT test/crush/unittest_crush_indep-indep.obj -MD -MP -MF test/crush/$(DEPDIR)/unittest_crush_indep-indep.Tpo -c -o test/crush/unittest_crush_indep-indep.obj `if test -f 'test/crush/indep.cc'; then $(CYGPATH_W) 'test/crush/indep.cc'; else $(CYGPATH_W) '$(srcdir)/test/crush/indep.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/crush/$(DEPDIR)/unittest_crush_indep-indep.Tpo test/crush/$(DEPDIR)/unittest_crush_indep-indep.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crush/indep.cc' object='test/crush/unittest_crush_indep-indep.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_indep_CXXFLAGS) $(CXXFLAGS) -c -o test/crush/unittest_crush_indep-indep.obj `if test -f 'test/crush/indep.cc'; then $(CYGPATH_W) 'test/crush/indep.cc'; else $(CYGPATH_W) '$(srcdir)/test/crush/indep.cc'; fi` test/crush/unittest_crush_wrapper-TestCrushWrapper.o: test/crush/TestCrushWrapper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_wrapper_CXXFLAGS) $(CXXFLAGS) -MT test/crush/unittest_crush_wrapper-TestCrushWrapper.o -MD -MP -MF test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Tpo -c -o test/crush/unittest_crush_wrapper-TestCrushWrapper.o `test -f 'test/crush/TestCrushWrapper.cc' || echo '$(srcdir)/'`test/crush/TestCrushWrapper.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Tpo test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crush/TestCrushWrapper.cc' object='test/crush/unittest_crush_wrapper-TestCrushWrapper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_wrapper_CXXFLAGS) $(CXXFLAGS) -c -o test/crush/unittest_crush_wrapper-TestCrushWrapper.o `test -f 'test/crush/TestCrushWrapper.cc' || echo '$(srcdir)/'`test/crush/TestCrushWrapper.cc test/crush/unittest_crush_wrapper-TestCrushWrapper.obj: test/crush/TestCrushWrapper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_wrapper_CXXFLAGS) $(CXXFLAGS) -MT test/crush/unittest_crush_wrapper-TestCrushWrapper.obj -MD -MP -MF test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Tpo -c -o test/crush/unittest_crush_wrapper-TestCrushWrapper.obj `if test -f 'test/crush/TestCrushWrapper.cc'; then $(CYGPATH_W) 'test/crush/TestCrushWrapper.cc'; else $(CYGPATH_W) '$(srcdir)/test/crush/TestCrushWrapper.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Tpo test/crush/$(DEPDIR)/unittest_crush_wrapper-TestCrushWrapper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crush/TestCrushWrapper.cc' object='test/crush/unittest_crush_wrapper-TestCrushWrapper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crush_wrapper_CXXFLAGS) $(CXXFLAGS) -c -o test/crush/unittest_crush_wrapper-TestCrushWrapper.obj `if test -f 'test/crush/TestCrushWrapper.cc'; then $(CYGPATH_W) 'test/crush/TestCrushWrapper.cc'; else $(CYGPATH_W) '$(srcdir)/test/crush/TestCrushWrapper.cc'; fi` test/unittest_crypto-crypto.o: test/crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_crypto-crypto.o -MD -MP -MF test/$(DEPDIR)/unittest_crypto-crypto.Tpo -c -o test/unittest_crypto-crypto.o `test -f 'test/crypto.cc' || echo '$(srcdir)/'`test/crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_crypto-crypto.Tpo test/$(DEPDIR)/unittest_crypto-crypto.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crypto.cc' object='test/unittest_crypto-crypto.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_crypto-crypto.o `test -f 'test/crypto.cc' || echo '$(srcdir)/'`test/crypto.cc test/unittest_crypto-crypto.obj: test/crypto.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_crypto-crypto.obj -MD -MP -MF test/$(DEPDIR)/unittest_crypto-crypto.Tpo -c -o test/unittest_crypto-crypto.obj `if test -f 'test/crypto.cc'; then $(CYGPATH_W) 'test/crypto.cc'; else $(CYGPATH_W) '$(srcdir)/test/crypto.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_crypto-crypto.Tpo test/$(DEPDIR)/unittest_crypto-crypto.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crypto.cc' object='test/unittest_crypto-crypto.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_crypto-crypto.obj `if test -f 'test/crypto.cc'; then $(CYGPATH_W) 'test/crypto.cc'; else $(CYGPATH_W) '$(srcdir)/test/crypto.cc'; fi` test/unittest_crypto_init-crypto_init.o: test/crypto_init.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_init_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_crypto_init-crypto_init.o -MD -MP -MF test/$(DEPDIR)/unittest_crypto_init-crypto_init.Tpo -c -o test/unittest_crypto_init-crypto_init.o `test -f 'test/crypto_init.cc' || echo '$(srcdir)/'`test/crypto_init.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_crypto_init-crypto_init.Tpo test/$(DEPDIR)/unittest_crypto_init-crypto_init.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crypto_init.cc' object='test/unittest_crypto_init-crypto_init.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_init_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_crypto_init-crypto_init.o `test -f 'test/crypto_init.cc' || echo '$(srcdir)/'`test/crypto_init.cc test/unittest_crypto_init-crypto_init.obj: test/crypto_init.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_init_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_crypto_init-crypto_init.obj -MD -MP -MF test/$(DEPDIR)/unittest_crypto_init-crypto_init.Tpo -c -o test/unittest_crypto_init-crypto_init.obj `if test -f 'test/crypto_init.cc'; then $(CYGPATH_W) 'test/crypto_init.cc'; else $(CYGPATH_W) '$(srcdir)/test/crypto_init.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_crypto_init-crypto_init.Tpo test/$(DEPDIR)/unittest_crypto_init-crypto_init.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/crypto_init.cc' object='test/unittest_crypto_init-crypto_init.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_crypto_init_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_crypto_init-crypto_init.obj `if test -f 'test/crypto_init.cc'; then $(CYGPATH_W) 'test/crypto_init.cc'; else $(CYGPATH_W) '$(srcdir)/test/crypto_init.cc'; fi` test/unittest_daemon_config-daemon_config.o: test/daemon_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_daemon_config_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_daemon_config-daemon_config.o -MD -MP -MF test/$(DEPDIR)/unittest_daemon_config-daemon_config.Tpo -c -o test/unittest_daemon_config-daemon_config.o `test -f 'test/daemon_config.cc' || echo '$(srcdir)/'`test/daemon_config.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_daemon_config-daemon_config.Tpo test/$(DEPDIR)/unittest_daemon_config-daemon_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/daemon_config.cc' object='test/unittest_daemon_config-daemon_config.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_daemon_config_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_daemon_config-daemon_config.o `test -f 'test/daemon_config.cc' || echo '$(srcdir)/'`test/daemon_config.cc test/unittest_daemon_config-daemon_config.obj: test/daemon_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_daemon_config_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_daemon_config-daemon_config.obj -MD -MP -MF test/$(DEPDIR)/unittest_daemon_config-daemon_config.Tpo -c -o test/unittest_daemon_config-daemon_config.obj `if test -f 'test/daemon_config.cc'; then $(CYGPATH_W) 'test/daemon_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/daemon_config.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_daemon_config-daemon_config.Tpo test/$(DEPDIR)/unittest_daemon_config-daemon_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/daemon_config.cc' object='test/unittest_daemon_config-daemon_config.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_daemon_config_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_daemon_config-daemon_config.obj `if test -f 'test/daemon_config.cc'; then $(CYGPATH_W) 'test/daemon_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/daemon_config.cc'; fi` test/osd/unittest_ecbackend-TestECBackend.o: test/osd/TestECBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ecbackend_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_ecbackend-TestECBackend.o -MD -MP -MF test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Tpo -c -o test/osd/unittest_ecbackend-TestECBackend.o `test -f 'test/osd/TestECBackend.cc' || echo '$(srcdir)/'`test/osd/TestECBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Tpo test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/TestECBackend.cc' object='test/osd/unittest_ecbackend-TestECBackend.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ecbackend_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_ecbackend-TestECBackend.o `test -f 'test/osd/TestECBackend.cc' || echo '$(srcdir)/'`test/osd/TestECBackend.cc test/osd/unittest_ecbackend-TestECBackend.obj: test/osd/TestECBackend.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ecbackend_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_ecbackend-TestECBackend.obj -MD -MP -MF test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Tpo -c -o test/osd/unittest_ecbackend-TestECBackend.obj `if test -f 'test/osd/TestECBackend.cc'; then $(CYGPATH_W) 'test/osd/TestECBackend.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/TestECBackend.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Tpo test/osd/$(DEPDIR)/unittest_ecbackend-TestECBackend.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/TestECBackend.cc' object='test/osd/unittest_ecbackend-TestECBackend.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ecbackend_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_ecbackend-TestECBackend.obj `if test -f 'test/osd/TestECBackend.cc'; then $(CYGPATH_W) 'test/osd/TestECBackend.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/TestECBackend.cc'; fi` test/unittest_encoding-encoding.o: test/encoding.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_encoding_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_encoding-encoding.o -MD -MP -MF test/$(DEPDIR)/unittest_encoding-encoding.Tpo -c -o test/unittest_encoding-encoding.o `test -f 'test/encoding.cc' || echo '$(srcdir)/'`test/encoding.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_encoding-encoding.Tpo test/$(DEPDIR)/unittest_encoding-encoding.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/encoding.cc' object='test/unittest_encoding-encoding.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_encoding_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_encoding-encoding.o `test -f 'test/encoding.cc' || echo '$(srcdir)/'`test/encoding.cc test/unittest_encoding-encoding.obj: test/encoding.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_encoding_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_encoding-encoding.obj -MD -MP -MF test/$(DEPDIR)/unittest_encoding-encoding.Tpo -c -o test/unittest_encoding-encoding.obj `if test -f 'test/encoding.cc'; then $(CYGPATH_W) 'test/encoding.cc'; else $(CYGPATH_W) '$(srcdir)/test/encoding.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_encoding-encoding.Tpo test/$(DEPDIR)/unittest_encoding-encoding.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/encoding.cc' object='test/unittest_encoding-encoding.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_encoding_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_encoding-encoding.obj `if test -f 'test/encoding.cc'; then $(CYGPATH_W) 'test/encoding.cc'; else $(CYGPATH_W) '$(srcdir)/test/encoding.cc'; fi` test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.o: test/erasure-code/TestErasureCodeExample.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_example_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.o -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Tpo -c -o test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.o `test -f 'test/erasure-code/TestErasureCodeExample.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodeExample.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodeExample.cc' object='test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_example_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.o `test -f 'test/erasure-code/TestErasureCodeExample.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodeExample.cc test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.obj: test/erasure-code/TestErasureCodeExample.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_example_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.obj -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Tpo -c -o test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.obj `if test -f 'test/erasure-code/TestErasureCodeExample.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodeExample.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodeExample.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_example-TestErasureCodeExample.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodeExample.cc' object='test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_example_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_example-TestErasureCodeExample.obj `if test -f 'test/erasure-code/TestErasureCodeExample.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodeExample.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodeExample.cc'; fi` test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.o: test/erasure-code/TestErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.o -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Tpo -c -o test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.o `test -f 'test/erasure-code/TestErasureCodeJerasure.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodeJerasure.cc' object='test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.o `test -f 'test/erasure-code/TestErasureCodeJerasure.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodeJerasure.cc test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.obj: test/erasure-code/TestErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.obj -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Tpo -c -o test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.obj `if test -f 'test/erasure-code/TestErasureCodeJerasure.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodeJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodeJerasure.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_jerasure-TestErasureCodeJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodeJerasure.cc' object='test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_jerasure-TestErasureCodeJerasure.obj `if test -f 'test/erasure-code/TestErasureCodeJerasure.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodeJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodeJerasure.cc'; fi` erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.o: erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.o -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Tpo -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.o `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodePluginJerasure.cc' object='erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.o `test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodePluginJerasure.cc erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.obj: erasure-code/jerasure/ErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.obj -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Tpo -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.obj `if test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc'; then $(CYGPATH_W) 'erasure-code/jerasure/ErasureCodePluginJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/ErasureCodePluginJerasure.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodePluginJerasure.cc' object='erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodePluginJerasure.obj `if test -f 'erasure-code/jerasure/ErasureCodePluginJerasure.cc'; then $(CYGPATH_W) 'erasure-code/jerasure/ErasureCodePluginJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/ErasureCodePluginJerasure.cc'; fi` erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.o: erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.o -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Tpo -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.o `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodeJerasure.cc' object='erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.o `test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc' || echo '$(srcdir)/'`erasure-code/jerasure/ErasureCodeJerasure.cc erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.obj: erasure-code/jerasure/ErasureCodeJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -MT erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.obj -MD -MP -MF erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Tpo -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.obj `if test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc'; then $(CYGPATH_W) 'erasure-code/jerasure/ErasureCodeJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/ErasureCodeJerasure.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Tpo erasure-code/jerasure/$(DEPDIR)/unittest_erasure_code_jerasure-ErasureCodeJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='erasure-code/jerasure/ErasureCodeJerasure.cc' object='erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o erasure-code/jerasure/unittest_erasure_code_jerasure-ErasureCodeJerasure.obj `if test -f 'erasure-code/jerasure/ErasureCodeJerasure.cc'; then $(CYGPATH_W) 'erasure-code/jerasure/ErasureCodeJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/erasure-code/jerasure/ErasureCodeJerasure.cc'; fi` test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.o: test/erasure-code/TestErasureCodePlugin.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.o -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Tpo -c -o test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.o `test -f 'test/erasure-code/TestErasureCodePlugin.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodePlugin.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodePlugin.cc' object='test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.o `test -f 'test/erasure-code/TestErasureCodePlugin.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodePlugin.cc test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.obj: test/erasure-code/TestErasureCodePlugin.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.obj -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Tpo -c -o test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.obj `if test -f 'test/erasure-code/TestErasureCodePlugin.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodePlugin.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodePlugin.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin-TestErasureCodePlugin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodePlugin.cc' object='test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_plugin-TestErasureCodePlugin.obj `if test -f 'test/erasure-code/TestErasureCodePlugin.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodePlugin.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodePlugin.cc'; fi` test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.o: test/erasure-code/TestErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_jerasure_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.o -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Tpo -c -o test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.o `test -f 'test/erasure-code/TestErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodePluginJerasure.cc' object='test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.o `test -f 'test/erasure-code/TestErasureCodePluginJerasure.cc' || echo '$(srcdir)/'`test/erasure-code/TestErasureCodePluginJerasure.cc test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.obj: test/erasure-code/TestErasureCodePluginJerasure.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_jerasure_CXXFLAGS) $(CXXFLAGS) -MT test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.obj -MD -MP -MF test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Tpo -c -o test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.obj `if test -f 'test/erasure-code/TestErasureCodePluginJerasure.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodePluginJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodePluginJerasure.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Tpo test/erasure-code/$(DEPDIR)/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/erasure-code/TestErasureCodePluginJerasure.cc' object='test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_erasure_code_plugin_jerasure_CXXFLAGS) $(CXXFLAGS) -c -o test/erasure-code/unittest_erasure_code_plugin_jerasure-TestErasureCodePluginJerasure.obj `if test -f 'test/erasure-code/TestErasureCodePluginJerasure.cc'; then $(CYGPATH_W) 'test/erasure-code/TestErasureCodePluginJerasure.cc'; else $(CYGPATH_W) '$(srcdir)/test/erasure-code/TestErasureCodePluginJerasure.cc'; fi` test/unittest_escape-escape.o: test/escape.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_escape_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_escape-escape.o -MD -MP -MF test/$(DEPDIR)/unittest_escape-escape.Tpo -c -o test/unittest_escape-escape.o `test -f 'test/escape.cc' || echo '$(srcdir)/'`test/escape.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_escape-escape.Tpo test/$(DEPDIR)/unittest_escape-escape.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/escape.cc' object='test/unittest_escape-escape.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_escape_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_escape-escape.o `test -f 'test/escape.cc' || echo '$(srcdir)/'`test/escape.cc test/unittest_escape-escape.obj: test/escape.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_escape_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_escape-escape.obj -MD -MP -MF test/$(DEPDIR)/unittest_escape-escape.Tpo -c -o test/unittest_escape-escape.obj `if test -f 'test/escape.cc'; then $(CYGPATH_W) 'test/escape.cc'; else $(CYGPATH_W) '$(srcdir)/test/escape.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_escape-escape.Tpo test/$(DEPDIR)/unittest_escape-escape.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/escape.cc' object='test/unittest_escape-escape.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_escape_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_escape-escape.obj `if test -f 'test/escape.cc'; then $(CYGPATH_W) 'test/escape.cc'; else $(CYGPATH_W) '$(srcdir)/test/escape.cc'; fi` test/os/unittest_flatindex-TestFlatIndex.o: test/os/TestFlatIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_flatindex_CXXFLAGS) $(CXXFLAGS) -MT test/os/unittest_flatindex-TestFlatIndex.o -MD -MP -MF test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Tpo -c -o test/os/unittest_flatindex-TestFlatIndex.o `test -f 'test/os/TestFlatIndex.cc' || echo '$(srcdir)/'`test/os/TestFlatIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Tpo test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/os/TestFlatIndex.cc' object='test/os/unittest_flatindex-TestFlatIndex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_flatindex_CXXFLAGS) $(CXXFLAGS) -c -o test/os/unittest_flatindex-TestFlatIndex.o `test -f 'test/os/TestFlatIndex.cc' || echo '$(srcdir)/'`test/os/TestFlatIndex.cc test/os/unittest_flatindex-TestFlatIndex.obj: test/os/TestFlatIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_flatindex_CXXFLAGS) $(CXXFLAGS) -MT test/os/unittest_flatindex-TestFlatIndex.obj -MD -MP -MF test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Tpo -c -o test/os/unittest_flatindex-TestFlatIndex.obj `if test -f 'test/os/TestFlatIndex.cc'; then $(CYGPATH_W) 'test/os/TestFlatIndex.cc'; else $(CYGPATH_W) '$(srcdir)/test/os/TestFlatIndex.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Tpo test/os/$(DEPDIR)/unittest_flatindex-TestFlatIndex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/os/TestFlatIndex.cc' object='test/os/unittest_flatindex-TestFlatIndex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_flatindex_CXXFLAGS) $(CXXFLAGS) -c -o test/os/unittest_flatindex-TestFlatIndex.obj `if test -f 'test/os/TestFlatIndex.cc'; then $(CYGPATH_W) 'test/os/TestFlatIndex.cc'; else $(CYGPATH_W) '$(srcdir)/test/os/TestFlatIndex.cc'; fi` test/unittest_formatter-formatter.o: test/formatter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_formatter-formatter.o -MD -MP -MF test/$(DEPDIR)/unittest_formatter-formatter.Tpo -c -o test/unittest_formatter-formatter.o `test -f 'test/formatter.cc' || echo '$(srcdir)/'`test/formatter.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_formatter-formatter.Tpo test/$(DEPDIR)/unittest_formatter-formatter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/formatter.cc' object='test/unittest_formatter-formatter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_formatter-formatter.o `test -f 'test/formatter.cc' || echo '$(srcdir)/'`test/formatter.cc test/unittest_formatter-formatter.obj: test/formatter.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_formatter-formatter.obj -MD -MP -MF test/$(DEPDIR)/unittest_formatter-formatter.Tpo -c -o test/unittest_formatter-formatter.obj `if test -f 'test/formatter.cc'; then $(CYGPATH_W) 'test/formatter.cc'; else $(CYGPATH_W) '$(srcdir)/test/formatter.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_formatter-formatter.Tpo test/$(DEPDIR)/unittest_formatter-formatter.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/formatter.cc' object='test/unittest_formatter-formatter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_formatter-formatter.obj `if test -f 'test/formatter.cc'; then $(CYGPATH_W) 'test/formatter.cc'; else $(CYGPATH_W) '$(srcdir)/test/formatter.cc'; fi` rgw/unittest_formatter-rgw_formats.o: rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -MT rgw/unittest_formatter-rgw_formats.o -MD -MP -MF rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Tpo -c -o rgw/unittest_formatter-rgw_formats.o `test -f 'rgw/rgw_formats.cc' || echo '$(srcdir)/'`rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Tpo rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_formats.cc' object='rgw/unittest_formatter-rgw_formats.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -c -o rgw/unittest_formatter-rgw_formats.o `test -f 'rgw/rgw_formats.cc' || echo '$(srcdir)/'`rgw/rgw_formats.cc rgw/unittest_formatter-rgw_formats.obj: rgw/rgw_formats.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -MT rgw/unittest_formatter-rgw_formats.obj -MD -MP -MF rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Tpo -c -o rgw/unittest_formatter-rgw_formats.obj `if test -f 'rgw/rgw_formats.cc'; then $(CYGPATH_W) 'rgw/rgw_formats.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_formats.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Tpo rgw/$(DEPDIR)/unittest_formatter-rgw_formats.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rgw/rgw_formats.cc' object='rgw/unittest_formatter-rgw_formats.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_formatter_CXXFLAGS) $(CXXFLAGS) -c -o rgw/unittest_formatter-rgw_formats.obj `if test -f 'rgw/rgw_formats.cc'; then $(CYGPATH_W) 'rgw/rgw_formats.cc'; else $(CYGPATH_W) '$(srcdir)/rgw/rgw_formats.cc'; fi` test/unittest_gather-gather.o: test/gather.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_gather_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_gather-gather.o -MD -MP -MF test/$(DEPDIR)/unittest_gather-gather.Tpo -c -o test/unittest_gather-gather.o `test -f 'test/gather.cc' || echo '$(srcdir)/'`test/gather.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_gather-gather.Tpo test/$(DEPDIR)/unittest_gather-gather.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/gather.cc' object='test/unittest_gather-gather.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_gather_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_gather-gather.o `test -f 'test/gather.cc' || echo '$(srcdir)/'`test/gather.cc test/unittest_gather-gather.obj: test/gather.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_gather_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_gather-gather.obj -MD -MP -MF test/$(DEPDIR)/unittest_gather-gather.Tpo -c -o test/unittest_gather-gather.obj `if test -f 'test/gather.cc'; then $(CYGPATH_W) 'test/gather.cc'; else $(CYGPATH_W) '$(srcdir)/test/gather.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_gather-gather.Tpo test/$(DEPDIR)/unittest_gather-gather.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/gather.cc' object='test/unittest_gather-gather.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_gather_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_gather-gather.obj `if test -f 'test/gather.cc'; then $(CYGPATH_W) 'test/gather.cc'; else $(CYGPATH_W) '$(srcdir)/test/gather.cc'; fi` test/unittest_heartbeatmap-heartbeat_map.o: test/heartbeat_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_heartbeatmap_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_heartbeatmap-heartbeat_map.o -MD -MP -MF test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Tpo -c -o test/unittest_heartbeatmap-heartbeat_map.o `test -f 'test/heartbeat_map.cc' || echo '$(srcdir)/'`test/heartbeat_map.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Tpo test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/heartbeat_map.cc' object='test/unittest_heartbeatmap-heartbeat_map.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_heartbeatmap_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_heartbeatmap-heartbeat_map.o `test -f 'test/heartbeat_map.cc' || echo '$(srcdir)/'`test/heartbeat_map.cc test/unittest_heartbeatmap-heartbeat_map.obj: test/heartbeat_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_heartbeatmap_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_heartbeatmap-heartbeat_map.obj -MD -MP -MF test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Tpo -c -o test/unittest_heartbeatmap-heartbeat_map.obj `if test -f 'test/heartbeat_map.cc'; then $(CYGPATH_W) 'test/heartbeat_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/heartbeat_map.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Tpo test/$(DEPDIR)/unittest_heartbeatmap-heartbeat_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/heartbeat_map.cc' object='test/unittest_heartbeatmap-heartbeat_map.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_heartbeatmap_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_heartbeatmap-heartbeat_map.obj `if test -f 'test/heartbeat_map.cc'; then $(CYGPATH_W) 'test/heartbeat_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/heartbeat_map.cc'; fi` test/common/unittest_histogram-histogram.o: test/common/histogram.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_histogram_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_histogram-histogram.o -MD -MP -MF test/common/$(DEPDIR)/unittest_histogram-histogram.Tpo -c -o test/common/unittest_histogram-histogram.o `test -f 'test/common/histogram.cc' || echo '$(srcdir)/'`test/common/histogram.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_histogram-histogram.Tpo test/common/$(DEPDIR)/unittest_histogram-histogram.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/histogram.cc' object='test/common/unittest_histogram-histogram.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_histogram_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_histogram-histogram.o `test -f 'test/common/histogram.cc' || echo '$(srcdir)/'`test/common/histogram.cc test/common/unittest_histogram-histogram.obj: test/common/histogram.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_histogram_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_histogram-histogram.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_histogram-histogram.Tpo -c -o test/common/unittest_histogram-histogram.obj `if test -f 'test/common/histogram.cc'; then $(CYGPATH_W) 'test/common/histogram.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/histogram.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_histogram-histogram.Tpo test/common/$(DEPDIR)/unittest_histogram-histogram.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/histogram.cc' object='test/common/unittest_histogram-histogram.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_histogram_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_histogram-histogram.obj `if test -f 'test/common/histogram.cc'; then $(CYGPATH_W) 'test/common/histogram.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/histogram.cc'; fi` test/osd/unittest_hitset-hitset.o: test/osd/hitset.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_hitset_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_hitset-hitset.o -MD -MP -MF test/osd/$(DEPDIR)/unittest_hitset-hitset.Tpo -c -o test/osd/unittest_hitset-hitset.o `test -f 'test/osd/hitset.cc' || echo '$(srcdir)/'`test/osd/hitset.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_hitset-hitset.Tpo test/osd/$(DEPDIR)/unittest_hitset-hitset.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/hitset.cc' object='test/osd/unittest_hitset-hitset.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_hitset_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_hitset-hitset.o `test -f 'test/osd/hitset.cc' || echo '$(srcdir)/'`test/osd/hitset.cc test/osd/unittest_hitset-hitset.obj: test/osd/hitset.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_hitset_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_hitset-hitset.obj -MD -MP -MF test/osd/$(DEPDIR)/unittest_hitset-hitset.Tpo -c -o test/osd/unittest_hitset-hitset.obj `if test -f 'test/osd/hitset.cc'; then $(CYGPATH_W) 'test/osd/hitset.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/hitset.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_hitset-hitset.Tpo test/osd/$(DEPDIR)/unittest_hitset-hitset.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/hitset.cc' object='test/osd/unittest_hitset-hitset.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_hitset_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_hitset-hitset.obj `if test -f 'test/osd/hitset.cc'; then $(CYGPATH_W) 'test/osd/hitset.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/hitset.cc'; fi` test/common/unittest_io_priority-test_io_priority.o: test/common/test_io_priority.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_io_priority_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_io_priority-test_io_priority.o -MD -MP -MF test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Tpo -c -o test/common/unittest_io_priority-test_io_priority.o `test -f 'test/common/test_io_priority.cc' || echo '$(srcdir)/'`test/common/test_io_priority.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Tpo test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_io_priority.cc' object='test/common/unittest_io_priority-test_io_priority.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_io_priority_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_io_priority-test_io_priority.o `test -f 'test/common/test_io_priority.cc' || echo '$(srcdir)/'`test/common/test_io_priority.cc test/common/unittest_io_priority-test_io_priority.obj: test/common/test_io_priority.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_io_priority_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_io_priority-test_io_priority.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Tpo -c -o test/common/unittest_io_priority-test_io_priority.obj `if test -f 'test/common/test_io_priority.cc'; then $(CYGPATH_W) 'test/common/test_io_priority.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_io_priority.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Tpo test/common/$(DEPDIR)/unittest_io_priority-test_io_priority.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_io_priority.cc' object='test/common/unittest_io_priority-test_io_priority.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_io_priority_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_io_priority-test_io_priority.obj `if test -f 'test/common/test_io_priority.cc'; then $(CYGPATH_W) 'test/common/test_io_priority.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_io_priority.cc'; fi` test/unittest_ipaddr-test_ipaddr.o: test/test_ipaddr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ipaddr_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ipaddr-test_ipaddr.o -MD -MP -MF test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Tpo -c -o test/unittest_ipaddr-test_ipaddr.o `test -f 'test/test_ipaddr.cc' || echo '$(srcdir)/'`test/test_ipaddr.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Tpo test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_ipaddr.cc' object='test/unittest_ipaddr-test_ipaddr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ipaddr_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ipaddr-test_ipaddr.o `test -f 'test/test_ipaddr.cc' || echo '$(srcdir)/'`test/test_ipaddr.cc test/unittest_ipaddr-test_ipaddr.obj: test/test_ipaddr.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ipaddr_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_ipaddr-test_ipaddr.obj -MD -MP -MF test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Tpo -c -o test/unittest_ipaddr-test_ipaddr.obj `if test -f 'test/test_ipaddr.cc'; then $(CYGPATH_W) 'test/test_ipaddr.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_ipaddr.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Tpo test/$(DEPDIR)/unittest_ipaddr-test_ipaddr.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_ipaddr.cc' object='test/unittest_ipaddr-test_ipaddr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_ipaddr_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_ipaddr-test_ipaddr.obj `if test -f 'test/test_ipaddr.cc'; then $(CYGPATH_W) 'test/test_ipaddr.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_ipaddr.cc'; fi` test/os/unittest_lfnindex-TestLFNIndex.o: test/os/TestLFNIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_lfnindex_CXXFLAGS) $(CXXFLAGS) -MT test/os/unittest_lfnindex-TestLFNIndex.o -MD -MP -MF test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Tpo -c -o test/os/unittest_lfnindex-TestLFNIndex.o `test -f 'test/os/TestLFNIndex.cc' || echo '$(srcdir)/'`test/os/TestLFNIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Tpo test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/os/TestLFNIndex.cc' object='test/os/unittest_lfnindex-TestLFNIndex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_lfnindex_CXXFLAGS) $(CXXFLAGS) -c -o test/os/unittest_lfnindex-TestLFNIndex.o `test -f 'test/os/TestLFNIndex.cc' || echo '$(srcdir)/'`test/os/TestLFNIndex.cc test/os/unittest_lfnindex-TestLFNIndex.obj: test/os/TestLFNIndex.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_lfnindex_CXXFLAGS) $(CXXFLAGS) -MT test/os/unittest_lfnindex-TestLFNIndex.obj -MD -MP -MF test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Tpo -c -o test/os/unittest_lfnindex-TestLFNIndex.obj `if test -f 'test/os/TestLFNIndex.cc'; then $(CYGPATH_W) 'test/os/TestLFNIndex.cc'; else $(CYGPATH_W) '$(srcdir)/test/os/TestLFNIndex.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Tpo test/os/$(DEPDIR)/unittest_lfnindex-TestLFNIndex.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/os/TestLFNIndex.cc' object='test/os/unittest_lfnindex-TestLFNIndex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_lfnindex_CXXFLAGS) $(CXXFLAGS) -c -o test/os/unittest_lfnindex-TestLFNIndex.obj `if test -f 'test/os/TestLFNIndex.cc'; then $(CYGPATH_W) 'test/os/TestLFNIndex.cc'; else $(CYGPATH_W) '$(srcdir)/test/os/TestLFNIndex.cc'; fi` test/unittest_libcephfs_config-libcephfs_config.o: test/libcephfs_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_libcephfs_config_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_libcephfs_config-libcephfs_config.o -MD -MP -MF test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Tpo -c -o test/unittest_libcephfs_config-libcephfs_config.o `test -f 'test/libcephfs_config.cc' || echo '$(srcdir)/'`test/libcephfs_config.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Tpo test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs_config.cc' object='test/unittest_libcephfs_config-libcephfs_config.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_libcephfs_config_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_libcephfs_config-libcephfs_config.o `test -f 'test/libcephfs_config.cc' || echo '$(srcdir)/'`test/libcephfs_config.cc test/unittest_libcephfs_config-libcephfs_config.obj: test/libcephfs_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_libcephfs_config_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_libcephfs_config-libcephfs_config.obj -MD -MP -MF test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Tpo -c -o test/unittest_libcephfs_config-libcephfs_config.obj `if test -f 'test/libcephfs_config.cc'; then $(CYGPATH_W) 'test/libcephfs_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs_config.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Tpo test/$(DEPDIR)/unittest_libcephfs_config-libcephfs_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/libcephfs_config.cc' object='test/unittest_libcephfs_config-libcephfs_config.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_libcephfs_config_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_libcephfs_config-libcephfs_config.obj `if test -f 'test/libcephfs_config.cc'; then $(CYGPATH_W) 'test/libcephfs_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/libcephfs_config.cc'; fi` test/librados/unittest_librados-librados.o: test/librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_CXXFLAGS) $(CXXFLAGS) -MT test/librados/unittest_librados-librados.o -MD -MP -MF test/librados/$(DEPDIR)/unittest_librados-librados.Tpo -c -o test/librados/unittest_librados-librados.o `test -f 'test/librados/librados.cc' || echo '$(srcdir)/'`test/librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/unittest_librados-librados.Tpo test/librados/$(DEPDIR)/unittest_librados-librados.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/librados.cc' object='test/librados/unittest_librados-librados.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/unittest_librados-librados.o `test -f 'test/librados/librados.cc' || echo '$(srcdir)/'`test/librados/librados.cc test/librados/unittest_librados-librados.obj: test/librados/librados.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_CXXFLAGS) $(CXXFLAGS) -MT test/librados/unittest_librados-librados.obj -MD -MP -MF test/librados/$(DEPDIR)/unittest_librados-librados.Tpo -c -o test/librados/unittest_librados-librados.obj `if test -f 'test/librados/librados.cc'; then $(CYGPATH_W) 'test/librados/librados.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/librados.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/unittest_librados-librados.Tpo test/librados/$(DEPDIR)/unittest_librados-librados.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/librados.cc' object='test/librados/unittest_librados-librados.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/unittest_librados-librados.obj `if test -f 'test/librados/librados.cc'; then $(CYGPATH_W) 'test/librados/librados.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/librados.cc'; fi` test/librados/unittest_librados_config-librados_config.o: test/librados/librados_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_config_CXXFLAGS) $(CXXFLAGS) -MT test/librados/unittest_librados_config-librados_config.o -MD -MP -MF test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Tpo -c -o test/librados/unittest_librados_config-librados_config.o `test -f 'test/librados/librados_config.cc' || echo '$(srcdir)/'`test/librados/librados_config.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Tpo test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/librados_config.cc' object='test/librados/unittest_librados_config-librados_config.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_config_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/unittest_librados_config-librados_config.o `test -f 'test/librados/librados_config.cc' || echo '$(srcdir)/'`test/librados/librados_config.cc test/librados/unittest_librados_config-librados_config.obj: test/librados/librados_config.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_config_CXXFLAGS) $(CXXFLAGS) -MT test/librados/unittest_librados_config-librados_config.obj -MD -MP -MF test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Tpo -c -o test/librados/unittest_librados_config-librados_config.obj `if test -f 'test/librados/librados_config.cc'; then $(CYGPATH_W) 'test/librados/librados_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/librados_config.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Tpo test/librados/$(DEPDIR)/unittest_librados_config-librados_config.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/librados/librados_config.cc' object='test/librados/unittest_librados_config-librados_config.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_librados_config_CXXFLAGS) $(CXXFLAGS) -c -o test/librados/unittest_librados_config-librados_config.obj `if test -f 'test/librados/librados_config.cc'; then $(CYGPATH_W) 'test/librados/librados_config.cc'; else $(CYGPATH_W) '$(srcdir)/test/librados/librados_config.cc'; fi` log/unittest_log-test.o: log/test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_log_CXXFLAGS) $(CXXFLAGS) -MT log/unittest_log-test.o -MD -MP -MF log/$(DEPDIR)/unittest_log-test.Tpo -c -o log/unittest_log-test.o `test -f 'log/test.cc' || echo '$(srcdir)/'`log/test.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) log/$(DEPDIR)/unittest_log-test.Tpo log/$(DEPDIR)/unittest_log-test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='log/test.cc' object='log/unittest_log-test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_log_CXXFLAGS) $(CXXFLAGS) -c -o log/unittest_log-test.o `test -f 'log/test.cc' || echo '$(srcdir)/'`log/test.cc log/unittest_log-test.obj: log/test.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_log_CXXFLAGS) $(CXXFLAGS) -MT log/unittest_log-test.obj -MD -MP -MF log/$(DEPDIR)/unittest_log-test.Tpo -c -o log/unittest_log-test.obj `if test -f 'log/test.cc'; then $(CYGPATH_W) 'log/test.cc'; else $(CYGPATH_W) '$(srcdir)/log/test.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) log/$(DEPDIR)/unittest_log-test.Tpo log/$(DEPDIR)/unittest_log-test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='log/test.cc' object='log/unittest_log-test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_log_CXXFLAGS) $(CXXFLAGS) -c -o log/unittest_log-test.obj `if test -f 'log/test.cc'; then $(CYGPATH_W) 'log/test.cc'; else $(CYGPATH_W) '$(srcdir)/log/test.cc'; fi` test/unittest_mime-mime.o: test/mime.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mime_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_mime-mime.o -MD -MP -MF test/$(DEPDIR)/unittest_mime-mime.Tpo -c -o test/unittest_mime-mime.o `test -f 'test/mime.cc' || echo '$(srcdir)/'`test/mime.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_mime-mime.Tpo test/$(DEPDIR)/unittest_mime-mime.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mime.cc' object='test/unittest_mime-mime.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mime_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_mime-mime.o `test -f 'test/mime.cc' || echo '$(srcdir)/'`test/mime.cc test/unittest_mime-mime.obj: test/mime.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mime_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_mime-mime.obj -MD -MP -MF test/$(DEPDIR)/unittest_mime-mime.Tpo -c -o test/unittest_mime-mime.obj `if test -f 'test/mime.cc'; then $(CYGPATH_W) 'test/mime.cc'; else $(CYGPATH_W) '$(srcdir)/test/mime.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_mime-mime.Tpo test/$(DEPDIR)/unittest_mime-mime.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mime.cc' object='test/unittest_mime-mime.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mime_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_mime-mime.obj `if test -f 'test/mime.cc'; then $(CYGPATH_W) 'test/mime.cc'; else $(CYGPATH_W) '$(srcdir)/test/mime.cc'; fi` test/mon/unittest_mon_moncap-moncap.o: test/mon/moncap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_moncap_CXXFLAGS) $(CXXFLAGS) -MT test/mon/unittest_mon_moncap-moncap.o -MD -MP -MF test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Tpo -c -o test/mon/unittest_mon_moncap-moncap.o `test -f 'test/mon/moncap.cc' || echo '$(srcdir)/'`test/mon/moncap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Tpo test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mon/moncap.cc' object='test/mon/unittest_mon_moncap-moncap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_moncap_CXXFLAGS) $(CXXFLAGS) -c -o test/mon/unittest_mon_moncap-moncap.o `test -f 'test/mon/moncap.cc' || echo '$(srcdir)/'`test/mon/moncap.cc test/mon/unittest_mon_moncap-moncap.obj: test/mon/moncap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_moncap_CXXFLAGS) $(CXXFLAGS) -MT test/mon/unittest_mon_moncap-moncap.obj -MD -MP -MF test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Tpo -c -o test/mon/unittest_mon_moncap-moncap.obj `if test -f 'test/mon/moncap.cc'; then $(CYGPATH_W) 'test/mon/moncap.cc'; else $(CYGPATH_W) '$(srcdir)/test/mon/moncap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Tpo test/mon/$(DEPDIR)/unittest_mon_moncap-moncap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mon/moncap.cc' object='test/mon/unittest_mon_moncap-moncap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_moncap_CXXFLAGS) $(CXXFLAGS) -c -o test/mon/unittest_mon_moncap-moncap.obj `if test -f 'test/mon/moncap.cc'; then $(CYGPATH_W) 'test/mon/moncap.cc'; else $(CYGPATH_W) '$(srcdir)/test/mon/moncap.cc'; fi` test/mon/unittest_mon_pgmap-PGMap.o: test/mon/PGMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_pgmap_CXXFLAGS) $(CXXFLAGS) -MT test/mon/unittest_mon_pgmap-PGMap.o -MD -MP -MF test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Tpo -c -o test/mon/unittest_mon_pgmap-PGMap.o `test -f 'test/mon/PGMap.cc' || echo '$(srcdir)/'`test/mon/PGMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Tpo test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mon/PGMap.cc' object='test/mon/unittest_mon_pgmap-PGMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_pgmap_CXXFLAGS) $(CXXFLAGS) -c -o test/mon/unittest_mon_pgmap-PGMap.o `test -f 'test/mon/PGMap.cc' || echo '$(srcdir)/'`test/mon/PGMap.cc test/mon/unittest_mon_pgmap-PGMap.obj: test/mon/PGMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_pgmap_CXXFLAGS) $(CXXFLAGS) -MT test/mon/unittest_mon_pgmap-PGMap.obj -MD -MP -MF test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Tpo -c -o test/mon/unittest_mon_pgmap-PGMap.obj `if test -f 'test/mon/PGMap.cc'; then $(CYGPATH_W) 'test/mon/PGMap.cc'; else $(CYGPATH_W) '$(srcdir)/test/mon/PGMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Tpo test/mon/$(DEPDIR)/unittest_mon_pgmap-PGMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mon/PGMap.cc' object='test/mon/unittest_mon_pgmap-PGMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_mon_pgmap_CXXFLAGS) $(CXXFLAGS) -c -o test/mon/unittest_mon_pgmap-PGMap.obj `if test -f 'test/mon/PGMap.cc'; then $(CYGPATH_W) 'test/mon/PGMap.cc'; else $(CYGPATH_W) '$(srcdir)/test/mon/PGMap.cc'; fi` test/osd/unittest_osd_osdcap-osdcap.o: test/osd/osdcap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_osdcap_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_osd_osdcap-osdcap.o -MD -MP -MF test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Tpo -c -o test/osd/unittest_osd_osdcap-osdcap.o `test -f 'test/osd/osdcap.cc' || echo '$(srcdir)/'`test/osd/osdcap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Tpo test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/osdcap.cc' object='test/osd/unittest_osd_osdcap-osdcap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_osdcap_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_osd_osdcap-osdcap.o `test -f 'test/osd/osdcap.cc' || echo '$(srcdir)/'`test/osd/osdcap.cc test/osd/unittest_osd_osdcap-osdcap.obj: test/osd/osdcap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_osdcap_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_osd_osdcap-osdcap.obj -MD -MP -MF test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Tpo -c -o test/osd/unittest_osd_osdcap-osdcap.obj `if test -f 'test/osd/osdcap.cc'; then $(CYGPATH_W) 'test/osd/osdcap.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/osdcap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Tpo test/osd/$(DEPDIR)/unittest_osd_osdcap-osdcap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/osdcap.cc' object='test/osd/unittest_osd_osdcap-osdcap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_osdcap_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_osd_osdcap-osdcap.obj `if test -f 'test/osd/osdcap.cc'; then $(CYGPATH_W) 'test/osd/osdcap.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/osdcap.cc'; fi` test/osd/unittest_osd_types-types.o: test/osd/types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_types_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_osd_types-types.o -MD -MP -MF test/osd/$(DEPDIR)/unittest_osd_types-types.Tpo -c -o test/osd/unittest_osd_types-types.o `test -f 'test/osd/types.cc' || echo '$(srcdir)/'`test/osd/types.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_osd_types-types.Tpo test/osd/$(DEPDIR)/unittest_osd_types-types.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/types.cc' object='test/osd/unittest_osd_types-types.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_types_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_osd_types-types.o `test -f 'test/osd/types.cc' || echo '$(srcdir)/'`test/osd/types.cc test/osd/unittest_osd_types-types.obj: test/osd/types.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_types_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_osd_types-types.obj -MD -MP -MF test/osd/$(DEPDIR)/unittest_osd_types-types.Tpo -c -o test/osd/unittest_osd_types-types.obj `if test -f 'test/osd/types.cc'; then $(CYGPATH_W) 'test/osd/types.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/types.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_osd_types-types.Tpo test/osd/$(DEPDIR)/unittest_osd_types-types.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/types.cc' object='test/osd/unittest_osd_types-types.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osd_types_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_osd_types-types.obj `if test -f 'test/osd/types.cc'; then $(CYGPATH_W) 'test/osd/types.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/types.cc'; fi` test/osd/unittest_osdmap-TestOSDMap.o: test/osd/TestOSDMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osdmap_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_osdmap-TestOSDMap.o -MD -MP -MF test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Tpo -c -o test/osd/unittest_osdmap-TestOSDMap.o `test -f 'test/osd/TestOSDMap.cc' || echo '$(srcdir)/'`test/osd/TestOSDMap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Tpo test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/TestOSDMap.cc' object='test/osd/unittest_osdmap-TestOSDMap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osdmap_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_osdmap-TestOSDMap.o `test -f 'test/osd/TestOSDMap.cc' || echo '$(srcdir)/'`test/osd/TestOSDMap.cc test/osd/unittest_osdmap-TestOSDMap.obj: test/osd/TestOSDMap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osdmap_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_osdmap-TestOSDMap.obj -MD -MP -MF test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Tpo -c -o test/osd/unittest_osdmap-TestOSDMap.obj `if test -f 'test/osd/TestOSDMap.cc'; then $(CYGPATH_W) 'test/osd/TestOSDMap.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/TestOSDMap.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Tpo test/osd/$(DEPDIR)/unittest_osdmap-TestOSDMap.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/TestOSDMap.cc' object='test/osd/unittest_osdmap-TestOSDMap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_osdmap_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_osdmap-TestOSDMap.obj `if test -f 'test/osd/TestOSDMap.cc'; then $(CYGPATH_W) 'test/osd/TestOSDMap.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/TestOSDMap.cc'; fi` test/unittest_perf_counters-perf_counters.o: test/perf_counters.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_perf_counters_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_perf_counters-perf_counters.o -MD -MP -MF test/$(DEPDIR)/unittest_perf_counters-perf_counters.Tpo -c -o test/unittest_perf_counters-perf_counters.o `test -f 'test/perf_counters.cc' || echo '$(srcdir)/'`test/perf_counters.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_perf_counters-perf_counters.Tpo test/$(DEPDIR)/unittest_perf_counters-perf_counters.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/perf_counters.cc' object='test/unittest_perf_counters-perf_counters.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_perf_counters_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_perf_counters-perf_counters.o `test -f 'test/perf_counters.cc' || echo '$(srcdir)/'`test/perf_counters.cc test/unittest_perf_counters-perf_counters.obj: test/perf_counters.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_perf_counters_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_perf_counters-perf_counters.obj -MD -MP -MF test/$(DEPDIR)/unittest_perf_counters-perf_counters.Tpo -c -o test/unittest_perf_counters-perf_counters.obj `if test -f 'test/perf_counters.cc'; then $(CYGPATH_W) 'test/perf_counters.cc'; else $(CYGPATH_W) '$(srcdir)/test/perf_counters.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_perf_counters-perf_counters.Tpo test/$(DEPDIR)/unittest_perf_counters-perf_counters.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/perf_counters.cc' object='test/unittest_perf_counters-perf_counters.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_perf_counters_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_perf_counters-perf_counters.obj `if test -f 'test/perf_counters.cc'; then $(CYGPATH_W) 'test/perf_counters.cc'; else $(CYGPATH_W) '$(srcdir)/test/perf_counters.cc'; fi` test/osd/unittest_pglog-TestPGLog.o: test/osd/TestPGLog.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_pglog_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_pglog-TestPGLog.o -MD -MP -MF test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Tpo -c -o test/osd/unittest_pglog-TestPGLog.o `test -f 'test/osd/TestPGLog.cc' || echo '$(srcdir)/'`test/osd/TestPGLog.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Tpo test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/TestPGLog.cc' object='test/osd/unittest_pglog-TestPGLog.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_pglog_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_pglog-TestPGLog.o `test -f 'test/osd/TestPGLog.cc' || echo '$(srcdir)/'`test/osd/TestPGLog.cc test/osd/unittest_pglog-TestPGLog.obj: test/osd/TestPGLog.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_pglog_CXXFLAGS) $(CXXFLAGS) -MT test/osd/unittest_pglog-TestPGLog.obj -MD -MP -MF test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Tpo -c -o test/osd/unittest_pglog-TestPGLog.obj `if test -f 'test/osd/TestPGLog.cc'; then $(CYGPATH_W) 'test/osd/TestPGLog.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/TestPGLog.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Tpo test/osd/$(DEPDIR)/unittest_pglog-TestPGLog.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/osd/TestPGLog.cc' object='test/osd/unittest_pglog-TestPGLog.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_pglog_CXXFLAGS) $(CXXFLAGS) -c -o test/osd/unittest_pglog-TestPGLog.obj `if test -f 'test/osd/TestPGLog.cc'; then $(CYGPATH_W) 'test/osd/TestPGLog.cc'; else $(CYGPATH_W) '$(srcdir)/test/osd/TestPGLog.cc'; fi` test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.o: test/test_prebufferedstreambuf.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_prebufferedstreambuf_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.o -MD -MP -MF test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Tpo -c -o test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.o `test -f 'test/test_prebufferedstreambuf.cc' || echo '$(srcdir)/'`test/test_prebufferedstreambuf.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Tpo test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_prebufferedstreambuf.cc' object='test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_prebufferedstreambuf_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.o `test -f 'test/test_prebufferedstreambuf.cc' || echo '$(srcdir)/'`test/test_prebufferedstreambuf.cc test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.obj: test/test_prebufferedstreambuf.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_prebufferedstreambuf_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.obj -MD -MP -MF test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Tpo -c -o test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.obj `if test -f 'test/test_prebufferedstreambuf.cc'; then $(CYGPATH_W) 'test/test_prebufferedstreambuf.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_prebufferedstreambuf.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Tpo test/$(DEPDIR)/unittest_prebufferedstreambuf-test_prebufferedstreambuf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_prebufferedstreambuf.cc' object='test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_prebufferedstreambuf_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_prebufferedstreambuf-test_prebufferedstreambuf.obj `if test -f 'test/test_prebufferedstreambuf.cc'; then $(CYGPATH_W) 'test/test_prebufferedstreambuf.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_prebufferedstreambuf.cc'; fi` test/unittest_run_cmd-run_cmd.o: test/run_cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_run_cmd_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_run_cmd-run_cmd.o -MD -MP -MF test/$(DEPDIR)/unittest_run_cmd-run_cmd.Tpo -c -o test/unittest_run_cmd-run_cmd.o `test -f 'test/run_cmd.cc' || echo '$(srcdir)/'`test/run_cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_run_cmd-run_cmd.Tpo test/$(DEPDIR)/unittest_run_cmd-run_cmd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/run_cmd.cc' object='test/unittest_run_cmd-run_cmd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_run_cmd_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_run_cmd-run_cmd.o `test -f 'test/run_cmd.cc' || echo '$(srcdir)/'`test/run_cmd.cc test/unittest_run_cmd-run_cmd.obj: test/run_cmd.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_run_cmd_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_run_cmd-run_cmd.obj -MD -MP -MF test/$(DEPDIR)/unittest_run_cmd-run_cmd.Tpo -c -o test/unittest_run_cmd-run_cmd.obj `if test -f 'test/run_cmd.cc'; then $(CYGPATH_W) 'test/run_cmd.cc'; else $(CYGPATH_W) '$(srcdir)/test/run_cmd.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_run_cmd-run_cmd.Tpo test/$(DEPDIR)/unittest_run_cmd-run_cmd.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/run_cmd.cc' object='test/unittest_run_cmd-run_cmd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_run_cmd_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_run_cmd-run_cmd.obj `if test -f 'test/run_cmd.cc'; then $(CYGPATH_W) 'test/run_cmd.cc'; else $(CYGPATH_W) '$(srcdir)/test/run_cmd.cc'; fi` test/common/unittest_sharedptr_registry-test_sharedptr_registry.o: test/common/test_sharedptr_registry.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sharedptr_registry_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_sharedptr_registry-test_sharedptr_registry.o -MD -MP -MF test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Tpo -c -o test/common/unittest_sharedptr_registry-test_sharedptr_registry.o `test -f 'test/common/test_sharedptr_registry.cc' || echo '$(srcdir)/'`test/common/test_sharedptr_registry.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Tpo test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_sharedptr_registry.cc' object='test/common/unittest_sharedptr_registry-test_sharedptr_registry.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sharedptr_registry_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_sharedptr_registry-test_sharedptr_registry.o `test -f 'test/common/test_sharedptr_registry.cc' || echo '$(srcdir)/'`test/common/test_sharedptr_registry.cc test/common/unittest_sharedptr_registry-test_sharedptr_registry.obj: test/common/test_sharedptr_registry.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sharedptr_registry_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_sharedptr_registry-test_sharedptr_registry.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Tpo -c -o test/common/unittest_sharedptr_registry-test_sharedptr_registry.obj `if test -f 'test/common/test_sharedptr_registry.cc'; then $(CYGPATH_W) 'test/common/test_sharedptr_registry.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_sharedptr_registry.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Tpo test/common/$(DEPDIR)/unittest_sharedptr_registry-test_sharedptr_registry.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_sharedptr_registry.cc' object='test/common/unittest_sharedptr_registry-test_sharedptr_registry.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sharedptr_registry_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_sharedptr_registry-test_sharedptr_registry.obj `if test -f 'test/common/test_sharedptr_registry.cc'; then $(CYGPATH_W) 'test/common/test_sharedptr_registry.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_sharedptr_registry.cc'; fi` test/unittest_signals-signals.o: test/signals.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_signals_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_signals-signals.o -MD -MP -MF test/$(DEPDIR)/unittest_signals-signals.Tpo -c -o test/unittest_signals-signals.o `test -f 'test/signals.cc' || echo '$(srcdir)/'`test/signals.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_signals-signals.Tpo test/$(DEPDIR)/unittest_signals-signals.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/signals.cc' object='test/unittest_signals-signals.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_signals_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_signals-signals.o `test -f 'test/signals.cc' || echo '$(srcdir)/'`test/signals.cc test/unittest_signals-signals.obj: test/signals.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_signals_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_signals-signals.obj -MD -MP -MF test/$(DEPDIR)/unittest_signals-signals.Tpo -c -o test/unittest_signals-signals.obj `if test -f 'test/signals.cc'; then $(CYGPATH_W) 'test/signals.cc'; else $(CYGPATH_W) '$(srcdir)/test/signals.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_signals-signals.Tpo test/$(DEPDIR)/unittest_signals-signals.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/signals.cc' object='test/unittest_signals-signals.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_signals_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_signals-signals.obj `if test -f 'test/signals.cc'; then $(CYGPATH_W) 'test/signals.cc'; else $(CYGPATH_W) '$(srcdir)/test/signals.cc'; fi` test/unittest_simple_spin-simple_spin.o: test/simple_spin.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_simple_spin_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_simple_spin-simple_spin.o -MD -MP -MF test/$(DEPDIR)/unittest_simple_spin-simple_spin.Tpo -c -o test/unittest_simple_spin-simple_spin.o `test -f 'test/simple_spin.cc' || echo '$(srcdir)/'`test/simple_spin.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_simple_spin-simple_spin.Tpo test/$(DEPDIR)/unittest_simple_spin-simple_spin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/simple_spin.cc' object='test/unittest_simple_spin-simple_spin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_simple_spin_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_simple_spin-simple_spin.o `test -f 'test/simple_spin.cc' || echo '$(srcdir)/'`test/simple_spin.cc test/unittest_simple_spin-simple_spin.obj: test/simple_spin.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_simple_spin_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_simple_spin-simple_spin.obj -MD -MP -MF test/$(DEPDIR)/unittest_simple_spin-simple_spin.Tpo -c -o test/unittest_simple_spin-simple_spin.obj `if test -f 'test/simple_spin.cc'; then $(CYGPATH_W) 'test/simple_spin.cc'; else $(CYGPATH_W) '$(srcdir)/test/simple_spin.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_simple_spin-simple_spin.Tpo test/$(DEPDIR)/unittest_simple_spin-simple_spin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/simple_spin.cc' object='test/unittest_simple_spin-simple_spin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_simple_spin_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_simple_spin-simple_spin.obj `if test -f 'test/simple_spin.cc'; then $(CYGPATH_W) 'test/simple_spin.cc'; else $(CYGPATH_W) '$(srcdir)/test/simple_spin.cc'; fi` test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.o: test/common/test_sloppy_crc_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sloppy_crc_map_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.o -MD -MP -MF test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Tpo -c -o test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.o `test -f 'test/common/test_sloppy_crc_map.cc' || echo '$(srcdir)/'`test/common/test_sloppy_crc_map.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Tpo test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_sloppy_crc_map.cc' object='test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sloppy_crc_map_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.o `test -f 'test/common/test_sloppy_crc_map.cc' || echo '$(srcdir)/'`test/common/test_sloppy_crc_map.cc test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.obj: test/common/test_sloppy_crc_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sloppy_crc_map_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Tpo -c -o test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.obj `if test -f 'test/common/test_sloppy_crc_map.cc'; then $(CYGPATH_W) 'test/common/test_sloppy_crc_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_sloppy_crc_map.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Tpo test/common/$(DEPDIR)/unittest_sloppy_crc_map-test_sloppy_crc_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_sloppy_crc_map.cc' object='test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_sloppy_crc_map_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_sloppy_crc_map-test_sloppy_crc_map.obj `if test -f 'test/common/test_sloppy_crc_map.cc'; then $(CYGPATH_W) 'test/common/test_sloppy_crc_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_sloppy_crc_map.cc'; fi` test/unittest_str_list-test_str_list.o: test/test_str_list.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_list_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_str_list-test_str_list.o -MD -MP -MF test/$(DEPDIR)/unittest_str_list-test_str_list.Tpo -c -o test/unittest_str_list-test_str_list.o `test -f 'test/test_str_list.cc' || echo '$(srcdir)/'`test/test_str_list.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_str_list-test_str_list.Tpo test/$(DEPDIR)/unittest_str_list-test_str_list.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_str_list.cc' object='test/unittest_str_list-test_str_list.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_list_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_str_list-test_str_list.o `test -f 'test/test_str_list.cc' || echo '$(srcdir)/'`test/test_str_list.cc test/unittest_str_list-test_str_list.obj: test/test_str_list.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_list_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_str_list-test_str_list.obj -MD -MP -MF test/$(DEPDIR)/unittest_str_list-test_str_list.Tpo -c -o test/unittest_str_list-test_str_list.obj `if test -f 'test/test_str_list.cc'; then $(CYGPATH_W) 'test/test_str_list.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_str_list.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_str_list-test_str_list.Tpo test/$(DEPDIR)/unittest_str_list-test_str_list.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_str_list.cc' object='test/unittest_str_list-test_str_list.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_list_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_str_list-test_str_list.obj `if test -f 'test/test_str_list.cc'; then $(CYGPATH_W) 'test/test_str_list.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_str_list.cc'; fi` test/common/unittest_str_map-test_str_map.o: test/common/test_str_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_map_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_str_map-test_str_map.o -MD -MP -MF test/common/$(DEPDIR)/unittest_str_map-test_str_map.Tpo -c -o test/common/unittest_str_map-test_str_map.o `test -f 'test/common/test_str_map.cc' || echo '$(srcdir)/'`test/common/test_str_map.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_str_map-test_str_map.Tpo test/common/$(DEPDIR)/unittest_str_map-test_str_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_str_map.cc' object='test/common/unittest_str_map-test_str_map.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_map_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_str_map-test_str_map.o `test -f 'test/common/test_str_map.cc' || echo '$(srcdir)/'`test/common/test_str_map.cc test/common/unittest_str_map-test_str_map.obj: test/common/test_str_map.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_map_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_str_map-test_str_map.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_str_map-test_str_map.Tpo -c -o test/common/unittest_str_map-test_str_map.obj `if test -f 'test/common/test_str_map.cc'; then $(CYGPATH_W) 'test/common/test_str_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_str_map.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_str_map-test_str_map.Tpo test/common/$(DEPDIR)/unittest_str_map-test_str_map.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_str_map.cc' object='test/common/unittest_str_map-test_str_map.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_str_map_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_str_map-test_str_map.obj `if test -f 'test/common/test_str_map.cc'; then $(CYGPATH_W) 'test/common/test_str_map.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_str_map.cc'; fi` test/unittest_striper-test_striper.o: test/test_striper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_striper_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_striper-test_striper.o -MD -MP -MF test/$(DEPDIR)/unittest_striper-test_striper.Tpo -c -o test/unittest_striper-test_striper.o `test -f 'test/test_striper.cc' || echo '$(srcdir)/'`test/test_striper.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_striper-test_striper.Tpo test/$(DEPDIR)/unittest_striper-test_striper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_striper.cc' object='test/unittest_striper-test_striper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_striper_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_striper-test_striper.o `test -f 'test/test_striper.cc' || echo '$(srcdir)/'`test/test_striper.cc test/unittest_striper-test_striper.obj: test/test_striper.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_striper_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_striper-test_striper.obj -MD -MP -MF test/$(DEPDIR)/unittest_striper-test_striper.Tpo -c -o test/unittest_striper-test_striper.obj `if test -f 'test/test_striper.cc'; then $(CYGPATH_W) 'test/test_striper.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_striper.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_striper-test_striper.Tpo test/$(DEPDIR)/unittest_striper-test_striper.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_striper.cc' object='test/unittest_striper-test_striper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_striper_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_striper-test_striper.obj `if test -f 'test/test_striper.cc'; then $(CYGPATH_W) 'test/test_striper.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_striper.cc'; fi` test/unittest_strtol-strtol.o: test/strtol.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_strtol_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_strtol-strtol.o -MD -MP -MF test/$(DEPDIR)/unittest_strtol-strtol.Tpo -c -o test/unittest_strtol-strtol.o `test -f 'test/strtol.cc' || echo '$(srcdir)/'`test/strtol.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_strtol-strtol.Tpo test/$(DEPDIR)/unittest_strtol-strtol.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/strtol.cc' object='test/unittest_strtol-strtol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_strtol_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_strtol-strtol.o `test -f 'test/strtol.cc' || echo '$(srcdir)/'`test/strtol.cc test/unittest_strtol-strtol.obj: test/strtol.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_strtol_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_strtol-strtol.obj -MD -MP -MF test/$(DEPDIR)/unittest_strtol-strtol.Tpo -c -o test/unittest_strtol-strtol.obj `if test -f 'test/strtol.cc'; then $(CYGPATH_W) 'test/strtol.cc'; else $(CYGPATH_W) '$(srcdir)/test/strtol.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_strtol-strtol.Tpo test/$(DEPDIR)/unittest_strtol-strtol.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/strtol.cc' object='test/unittest_strtol-strtol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_strtol_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_strtol-strtol.obj `if test -f 'test/strtol.cc'; then $(CYGPATH_W) 'test/strtol.cc'; else $(CYGPATH_W) '$(srcdir)/test/strtol.cc'; fi` test/unittest_texttable-test_texttable.o: test/test_texttable.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_texttable_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_texttable-test_texttable.o -MD -MP -MF test/$(DEPDIR)/unittest_texttable-test_texttable.Tpo -c -o test/unittest_texttable-test_texttable.o `test -f 'test/test_texttable.cc' || echo '$(srcdir)/'`test/test_texttable.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_texttable-test_texttable.Tpo test/$(DEPDIR)/unittest_texttable-test_texttable.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_texttable.cc' object='test/unittest_texttable-test_texttable.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_texttable_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_texttable-test_texttable.o `test -f 'test/test_texttable.cc' || echo '$(srcdir)/'`test/test_texttable.cc test/unittest_texttable-test_texttable.obj: test/test_texttable.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_texttable_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_texttable-test_texttable.obj -MD -MP -MF test/$(DEPDIR)/unittest_texttable-test_texttable.Tpo -c -o test/unittest_texttable-test_texttable.obj `if test -f 'test/test_texttable.cc'; then $(CYGPATH_W) 'test/test_texttable.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_texttable.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_texttable-test_texttable.Tpo test/$(DEPDIR)/unittest_texttable-test_texttable.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_texttable.cc' object='test/unittest_texttable-test_texttable.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_texttable_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_texttable-test_texttable.obj `if test -f 'test/test_texttable.cc'; then $(CYGPATH_W) 'test/test_texttable.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_texttable.cc'; fi` test/common/unittest_throttle-Throttle.o: test/common/Throttle.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_throttle_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_throttle-Throttle.o -MD -MP -MF test/common/$(DEPDIR)/unittest_throttle-Throttle.Tpo -c -o test/common/unittest_throttle-Throttle.o `test -f 'test/common/Throttle.cc' || echo '$(srcdir)/'`test/common/Throttle.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_throttle-Throttle.Tpo test/common/$(DEPDIR)/unittest_throttle-Throttle.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/Throttle.cc' object='test/common/unittest_throttle-Throttle.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_throttle_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_throttle-Throttle.o `test -f 'test/common/Throttle.cc' || echo '$(srcdir)/'`test/common/Throttle.cc test/common/unittest_throttle-Throttle.obj: test/common/Throttle.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_throttle_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_throttle-Throttle.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_throttle-Throttle.Tpo -c -o test/common/unittest_throttle-Throttle.obj `if test -f 'test/common/Throttle.cc'; then $(CYGPATH_W) 'test/common/Throttle.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/Throttle.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_throttle-Throttle.Tpo test/common/$(DEPDIR)/unittest_throttle-Throttle.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/Throttle.cc' object='test/common/unittest_throttle-Throttle.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_throttle_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_throttle-Throttle.obj `if test -f 'test/common/Throttle.cc'; then $(CYGPATH_W) 'test/common/Throttle.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/Throttle.cc'; fi` test/unittest_utf8-utf8.o: test/utf8.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_utf8_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_utf8-utf8.o -MD -MP -MF test/$(DEPDIR)/unittest_utf8-utf8.Tpo -c -o test/unittest_utf8-utf8.o `test -f 'test/utf8.cc' || echo '$(srcdir)/'`test/utf8.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_utf8-utf8.Tpo test/$(DEPDIR)/unittest_utf8-utf8.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/utf8.cc' object='test/unittest_utf8-utf8.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_utf8_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_utf8-utf8.o `test -f 'test/utf8.cc' || echo '$(srcdir)/'`test/utf8.cc test/unittest_utf8-utf8.obj: test/utf8.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_utf8_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_utf8-utf8.obj -MD -MP -MF test/$(DEPDIR)/unittest_utf8-utf8.Tpo -c -o test/unittest_utf8-utf8.obj `if test -f 'test/utf8.cc'; then $(CYGPATH_W) 'test/utf8.cc'; else $(CYGPATH_W) '$(srcdir)/test/utf8.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_utf8-utf8.Tpo test/$(DEPDIR)/unittest_utf8-utf8.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/utf8.cc' object='test/unittest_utf8-utf8.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_utf8_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_utf8-utf8.obj `if test -f 'test/utf8.cc'; then $(CYGPATH_W) 'test/utf8.cc'; else $(CYGPATH_W) '$(srcdir)/test/utf8.cc'; fi` test/common/unittest_util-test_util.o: test/common/test_util.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_util_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_util-test_util.o -MD -MP -MF test/common/$(DEPDIR)/unittest_util-test_util.Tpo -c -o test/common/unittest_util-test_util.o `test -f 'test/common/test_util.cc' || echo '$(srcdir)/'`test/common/test_util.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_util-test_util.Tpo test/common/$(DEPDIR)/unittest_util-test_util.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_util.cc' object='test/common/unittest_util-test_util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_util_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_util-test_util.o `test -f 'test/common/test_util.cc' || echo '$(srcdir)/'`test/common/test_util.cc test/common/unittest_util-test_util.obj: test/common/test_util.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_util_CXXFLAGS) $(CXXFLAGS) -MT test/common/unittest_util-test_util.obj -MD -MP -MF test/common/$(DEPDIR)/unittest_util-test_util.Tpo -c -o test/common/unittest_util-test_util.obj `if test -f 'test/common/test_util.cc'; then $(CYGPATH_W) 'test/common/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_util.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/common/$(DEPDIR)/unittest_util-test_util.Tpo test/common/$(DEPDIR)/unittest_util-test_util.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/common/test_util.cc' object='test/common/unittest_util-test_util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_util_CXXFLAGS) $(CXXFLAGS) -c -o test/common/unittest_util-test_util.obj `if test -f 'test/common/test_util.cc'; then $(CYGPATH_W) 'test/common/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/test/common/test_util.cc'; fi` test/unittest_workqueue-test_workqueue.o: test/test_workqueue.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_workqueue_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_workqueue-test_workqueue.o -MD -MP -MF test/$(DEPDIR)/unittest_workqueue-test_workqueue.Tpo -c -o test/unittest_workqueue-test_workqueue.o `test -f 'test/test_workqueue.cc' || echo '$(srcdir)/'`test/test_workqueue.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_workqueue-test_workqueue.Tpo test/$(DEPDIR)/unittest_workqueue-test_workqueue.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_workqueue.cc' object='test/unittest_workqueue-test_workqueue.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_workqueue_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_workqueue-test_workqueue.o `test -f 'test/test_workqueue.cc' || echo '$(srcdir)/'`test/test_workqueue.cc test/unittest_workqueue-test_workqueue.obj: test/test_workqueue.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_workqueue_CXXFLAGS) $(CXXFLAGS) -MT test/unittest_workqueue-test_workqueue.obj -MD -MP -MF test/$(DEPDIR)/unittest_workqueue-test_workqueue.Tpo -c -o test/unittest_workqueue-test_workqueue.obj `if test -f 'test/test_workqueue.cc'; then $(CYGPATH_W) 'test/test_workqueue.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_workqueue.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/unittest_workqueue-test_workqueue.Tpo test/$(DEPDIR)/unittest_workqueue-test_workqueue.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test_workqueue.cc' object='test/unittest_workqueue-test_workqueue.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_workqueue_CXXFLAGS) $(CXXFLAGS) -c -o test/unittest_workqueue-test_workqueue.obj `if test -f 'test/test_workqueue.cc'; then $(CYGPATH_W) 'test/test_workqueue.cc'; else $(CYGPATH_W) '$(srcdir)/test/test_workqueue.cc'; fi` .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf arch/.libs arch/_libs -rm -rf auth/.libs auth/_libs -rm -rf auth/cephx/.libs auth/cephx/_libs -rm -rf auth/none/.libs auth/none/_libs -rm -rf auth/unknown/.libs auth/unknown/_libs -rm -rf civetweb/src/.libs civetweb/src/_libs -rm -rf client/.libs client/_libs -rm -rf cls/hello/.libs cls/hello/_libs -rm -rf cls/lock/.libs cls/lock/_libs -rm -rf cls/log/.libs cls/log/_libs -rm -rf cls/rbd/.libs cls/rbd/_libs -rm -rf cls/refcount/.libs cls/refcount/_libs -rm -rf cls/replica_log/.libs cls/replica_log/_libs -rm -rf cls/rgw/.libs cls/rgw/_libs -rm -rf cls/statelog/.libs cls/statelog/_libs -rm -rf cls/user/.libs cls/user/_libs -rm -rf cls/version/.libs cls/version/_libs -rm -rf common/.libs common/_libs -rm -rf crush/.libs crush/_libs -rm -rf erasure-code/.libs erasure-code/_libs -rm -rf erasure-code/jerasure/.libs erasure-code/jerasure/_libs -rm -rf erasure-code/jerasure/gf-complete/src/.libs erasure-code/jerasure/gf-complete/src/_libs -rm -rf erasure-code/jerasure/jerasure/src/.libs erasure-code/jerasure/jerasure/src/_libs -rm -rf global/.libs global/_libs -rm -rf java/native/.libs java/native/_libs -rm -rf json_spirit/.libs json_spirit/_libs -rm -rf key_value_store/.libs key_value_store/_libs -rm -rf librados/.libs librados/_libs -rm -rf librbd/.libs librbd/_libs -rm -rf log/.libs log/_libs -rm -rf mds/.libs mds/_libs -rm -rf mon/.libs mon/_libs -rm -rf msg/.libs msg/_libs -rm -rf objclass/.libs objclass/_libs -rm -rf os/.libs os/_libs -rm -rf osd/.libs osd/_libs -rm -rf osdc/.libs osdc/_libs -rm -rf perfglue/.libs perfglue/_libs -rm -rf rgw/.libs rgw/_libs -rm -rf test/erasure-code/.libs test/erasure-code/_libs -rm -rf test/librados/.libs test/librados/_libs -rm -rf test/system/.libs test/system/_libs install-pythonPYTHON: $(python_PYTHON) @$(NORMAL_INSTALL) @list='$(python_PYTHON)'; dlist=; list2=; test -n "$(pythondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pythondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pythondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ if test -f $$b$$p; then \ $(am__strip_dir) \ dlist="$$dlist $$f"; \ list2="$$list2 $$b$$p"; \ else :; fi; \ done; \ for file in $$list2; do echo $$file; done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pythondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pythondir)" || exit $$?; \ done || exit $$?; \ if test -n "$$dlist"; then \ $(am__py_compile) --destdir "$(DESTDIR)" \ --basedir "$(pythondir)" $$dlist; \ else :; fi uninstall-pythonPYTHON: @$(NORMAL_UNINSTALL) @list='$(python_PYTHON)'; test -n "$(pythondir)" || list=; \ py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$py_files" || exit 0; \ dir='$(DESTDIR)$(pythondir)'; \ pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \ echo "$$py_files_pep3147";\ pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \ pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \ st=0; \ for files in \ "$$py_files" \ "$$pyc_files" \ "$$pyo_files" \ "$$pyc_files_pep3147" \ "$$pyo_files_pep3147" \ ; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done; \ exit $$st install-bash_completionDATA: $(bash_completion_DATA) @$(NORMAL_INSTALL) @list='$(bash_completion_DATA)'; test -n "$(bash_completiondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bash_completiondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bash_completiondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(bash_completiondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(bash_completiondir)" || exit $$?; \ done uninstall-bash_completionDATA: @$(NORMAL_UNINSTALL) @list='$(bash_completion_DATA)'; test -n "$(bash_completiondir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(bash_completiondir)'; $(am__uninstall_files_from_dir) install-docDATA: $(doc_DATA) @$(NORMAL_INSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-docDATA: @$(NORMAL_UNINSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-libcephfs_includeDATA: $(libcephfs_include_DATA) @$(NORMAL_INSTALL) @list='$(libcephfs_include_DATA)'; test -n "$(libcephfs_includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libcephfs_includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libcephfs_includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(libcephfs_includedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(libcephfs_includedir)" || exit $$?; \ done uninstall-libcephfs_includeDATA: @$(NORMAL_UNINSTALL) @list='$(libcephfs_include_DATA)'; test -n "$(libcephfs_includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(libcephfs_includedir)'; $(am__uninstall_files_from_dir) install-librbd_includeDATA: $(librbd_include_DATA) @$(NORMAL_INSTALL) @list='$(librbd_include_DATA)'; test -n "$(librbd_includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(librbd_includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(librbd_includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(librbd_includedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(librbd_includedir)" || exit $$?; \ done uninstall-librbd_includeDATA: @$(NORMAL_UNINSTALL) @list='$(librbd_include_DATA)'; test -n "$(librbd_includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(librbd_includedir)'; $(am__uninstall_files_from_dir) install-rados_includeDATA: $(rados_include_DATA) @$(NORMAL_INSTALL) @list='$(rados_include_DATA)'; test -n "$(rados_includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(rados_includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(rados_includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(rados_includedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(rados_includedir)" || exit $$?; \ done uninstall-rados_includeDATA: @$(NORMAL_UNINSTALL) @list='$(rados_include_DATA)'; test -n "$(rados_includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(rados_includedir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ else \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all $(check_PROGRAMS) $(check_SCRIPTS) @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? unittest_erasure_code_plugin.log: unittest_erasure_code_plugin$(EXEEXT) @p='unittest_erasure_code_plugin$(EXEEXT)'; \ b='unittest_erasure_code_plugin'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_erasure_code_jerasure.log: unittest_erasure_code_jerasure$(EXEEXT) @p='unittest_erasure_code_jerasure$(EXEEXT)'; \ b='unittest_erasure_code_jerasure'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_erasure_code_plugin_jerasure.log: unittest_erasure_code_plugin_jerasure$(EXEEXT) @p='unittest_erasure_code_plugin_jerasure$(EXEEXT)'; \ b='unittest_erasure_code_plugin_jerasure'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_erasure_code_example.log: unittest_erasure_code_example$(EXEEXT) @p='unittest_erasure_code_example$(EXEEXT)'; \ b='unittest_erasure_code_example'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_encoding.log: unittest_encoding$(EXEEXT) @p='unittest_encoding$(EXEEXT)'; \ b='unittest_encoding'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_addrs.log: unittest_addrs$(EXEEXT) @p='unittest_addrs$(EXEEXT)'; \ b='unittest_addrs'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_bloom_filter.log: unittest_bloom_filter$(EXEEXT) @p='unittest_bloom_filter$(EXEEXT)'; \ b='unittest_bloom_filter'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_histogram.log: unittest_histogram$(EXEEXT) @p='unittest_histogram$(EXEEXT)'; \ b='unittest_histogram'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_str_map.log: unittest_str_map$(EXEEXT) @p='unittest_str_map$(EXEEXT)'; \ b='unittest_str_map'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_sharedptr_registry.log: unittest_sharedptr_registry$(EXEEXT) @p='unittest_sharedptr_registry$(EXEEXT)'; \ b='unittest_sharedptr_registry'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_sloppy_crc_map.log: unittest_sloppy_crc_map$(EXEEXT) @p='unittest_sloppy_crc_map$(EXEEXT)'; \ b='unittest_sloppy_crc_map'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_util.log: unittest_util$(EXEEXT) @p='unittest_util$(EXEEXT)'; \ b='unittest_util'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_crush_indep.log: unittest_crush_indep$(EXEEXT) @p='unittest_crush_indep$(EXEEXT)'; \ b='unittest_crush_indep'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_osdmap.log: unittest_osdmap$(EXEEXT) @p='unittest_osdmap$(EXEEXT)'; \ b='unittest_osdmap'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_workqueue.log: unittest_workqueue$(EXEEXT) @p='unittest_workqueue$(EXEEXT)'; \ b='unittest_workqueue'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_striper.log: unittest_striper$(EXEEXT) @p='unittest_striper$(EXEEXT)'; \ b='unittest_striper'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_prebufferedstreambuf.log: unittest_prebufferedstreambuf$(EXEEXT) @p='unittest_prebufferedstreambuf$(EXEEXT)'; \ b='unittest_prebufferedstreambuf'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_str_list.log: unittest_str_list$(EXEEXT) @p='unittest_str_list$(EXEEXT)'; \ b='unittest_str_list'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_log.log: unittest_log$(EXEEXT) @p='unittest_log$(EXEEXT)'; \ b='unittest_log'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_throttle.log: unittest_throttle$(EXEEXT) @p='unittest_throttle$(EXEEXT)'; \ b='unittest_throttle'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_crush_wrapper.log: unittest_crush_wrapper$(EXEEXT) @p='unittest_crush_wrapper$(EXEEXT)'; \ b='unittest_crush_wrapper'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_base64.log: unittest_base64$(EXEEXT) @p='unittest_base64$(EXEEXT)'; \ b='unittest_base64'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_ceph_argparse.log: unittest_ceph_argparse$(EXEEXT) @p='unittest_ceph_argparse$(EXEEXT)'; \ b='unittest_ceph_argparse'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_ceph_compatset.log: unittest_ceph_compatset$(EXEEXT) @p='unittest_ceph_compatset$(EXEEXT)'; \ b='unittest_ceph_compatset'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_osd_types.log: unittest_osd_types$(EXEEXT) @p='unittest_osd_types$(EXEEXT)'; \ b='unittest_osd_types'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_pglog.log: unittest_pglog$(EXEEXT) @p='unittest_pglog$(EXEEXT)'; \ b='unittest_pglog'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_ecbackend.log: unittest_ecbackend$(EXEEXT) @p='unittest_ecbackend$(EXEEXT)'; \ b='unittest_ecbackend'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_hitset.log: unittest_hitset$(EXEEXT) @p='unittest_hitset$(EXEEXT)'; \ b='unittest_hitset'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_io_priority.log: unittest_io_priority$(EXEEXT) @p='unittest_io_priority$(EXEEXT)'; \ b='unittest_io_priority'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_gather.log: unittest_gather$(EXEEXT) @p='unittest_gather$(EXEEXT)'; \ b='unittest_gather'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_run_cmd.log: unittest_run_cmd$(EXEEXT) @p='unittest_run_cmd$(EXEEXT)'; \ b='unittest_run_cmd'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_signals.log: unittest_signals$(EXEEXT) @p='unittest_signals$(EXEEXT)'; \ b='unittest_signals'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_simple_spin.log: unittest_simple_spin$(EXEEXT) @p='unittest_simple_spin$(EXEEXT)'; \ b='unittest_simple_spin'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_librados.log: unittest_librados$(EXEEXT) @p='unittest_librados$(EXEEXT)'; \ b='unittest_librados'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_bufferlist.log: unittest_bufferlist$(EXEEXT) @p='unittest_bufferlist$(EXEEXT)'; \ b='unittest_bufferlist'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_crc32c.log: unittest_crc32c$(EXEEXT) @p='unittest_crc32c$(EXEEXT)'; \ b='unittest_crc32c'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_arch.log: unittest_arch$(EXEEXT) @p='unittest_arch$(EXEEXT)'; \ b='unittest_arch'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_crypto.log: unittest_crypto$(EXEEXT) @p='unittest_crypto$(EXEEXT)'; \ b='unittest_crypto'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_crypto_init.log: unittest_crypto_init$(EXEEXT) @p='unittest_crypto_init$(EXEEXT)'; \ b='unittest_crypto_init'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_perf_counters.log: unittest_perf_counters$(EXEEXT) @p='unittest_perf_counters$(EXEEXT)'; \ b='unittest_perf_counters'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_admin_socket.log: unittest_admin_socket$(EXEEXT) @p='unittest_admin_socket$(EXEEXT)'; \ b='unittest_admin_socket'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_ceph_crypto.log: unittest_ceph_crypto$(EXEEXT) @p='unittest_ceph_crypto$(EXEEXT)'; \ b='unittest_ceph_crypto'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_utf8.log: unittest_utf8$(EXEEXT) @p='unittest_utf8$(EXEEXT)'; \ b='unittest_utf8'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_mime.log: unittest_mime$(EXEEXT) @p='unittest_mime$(EXEEXT)'; \ b='unittest_mime'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_escape.log: unittest_escape$(EXEEXT) @p='unittest_escape$(EXEEXT)'; \ b='unittest_escape'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_chain_xattr.log: unittest_chain_xattr$(EXEEXT) @p='unittest_chain_xattr$(EXEEXT)'; \ b='unittest_chain_xattr'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_flatindex.log: unittest_flatindex$(EXEEXT) @p='unittest_flatindex$(EXEEXT)'; \ b='unittest_flatindex'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_strtol.log: unittest_strtol$(EXEEXT) @p='unittest_strtol$(EXEEXT)'; \ b='unittest_strtol'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_confutils.log: unittest_confutils$(EXEEXT) @p='unittest_confutils$(EXEEXT)'; \ b='unittest_confutils'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_config.log: unittest_config$(EXEEXT) @p='unittest_config$(EXEEXT)'; \ b='unittest_config'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_context.log: unittest_context$(EXEEXT) @p='unittest_context$(EXEEXT)'; \ b='unittest_context'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_heartbeatmap.log: unittest_heartbeatmap$(EXEEXT) @p='unittest_heartbeatmap$(EXEEXT)'; \ b='unittest_heartbeatmap'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_formatter.log: unittest_formatter$(EXEEXT) @p='unittest_formatter$(EXEEXT)'; \ b='unittest_formatter'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_libcephfs_config.log: unittest_libcephfs_config$(EXEEXT) @p='unittest_libcephfs_config$(EXEEXT)'; \ b='unittest_libcephfs_config'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_lfnindex.log: unittest_lfnindex$(EXEEXT) @p='unittest_lfnindex$(EXEEXT)'; \ b='unittest_lfnindex'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_librados_config.log: unittest_librados_config$(EXEEXT) @p='unittest_librados_config$(EXEEXT)'; \ b='unittest_librados_config'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_daemon_config.log: unittest_daemon_config$(EXEEXT) @p='unittest_daemon_config$(EXEEXT)'; \ b='unittest_daemon_config'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_osd_osdcap.log: unittest_osd_osdcap$(EXEEXT) @p='unittest_osd_osdcap$(EXEEXT)'; \ b='unittest_osd_osdcap'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_mon_moncap.log: unittest_mon_moncap$(EXEEXT) @p='unittest_mon_moncap$(EXEEXT)'; \ b='unittest_mon_moncap'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_mon_pgmap.log: unittest_mon_pgmap$(EXEEXT) @p='unittest_mon_pgmap$(EXEEXT)'; \ b='unittest_mon_pgmap'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_ipaddr.log: unittest_ipaddr$(EXEEXT) @p='unittest_ipaddr$(EXEEXT)'; \ b='unittest_ipaddr'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_texttable.log: unittest_texttable$(EXEEXT) @p='unittest_texttable$(EXEEXT)'; \ b='unittest_texttable'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_on_exit.log: unittest_on_exit$(EXEEXT) @p='unittest_on_exit$(EXEEXT)'; \ b='unittest_on_exit'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/erasure-code/test-erasure-code.sh.log: test/erasure-code/test-erasure-code.sh @p='test/erasure-code/test-erasure-code.sh'; \ b='test/erasure-code/test-erasure-code.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) unittest_bufferlist.sh.log: unittest_bufferlist.sh @p='unittest_bufferlist.sh'; \ b='unittest_bufferlist.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/encoding/check-generated.sh.log: test/encoding/check-generated.sh @p='test/encoding/check-generated.sh'; \ b='test/encoding/check-generated.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/mon/osd-pool-create.sh.log: test/mon/osd-pool-create.sh @p='test/mon/osd-pool-create.sh'; \ b='test/mon/osd-pool-create.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/mon/misc.sh.log: test/mon/misc.sh @p='test/mon/misc.sh'; \ b='test/mon/misc.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/mon/osd-crush.sh.log: test/mon/osd-crush.sh @p='test/mon/osd-crush.sh'; \ b='test/mon/osd-crush.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/mon/osd-erasure-code-profile.sh.log: test/mon/osd-erasure-code-profile.sh @p='test/mon/osd-erasure-code-profile.sh'; \ b='test/mon/osd-erasure-code-profile.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/mon/mkfs.sh.log: test/mon/mkfs.sh @p='test/mon/mkfs.sh'; \ b='test/mon/mkfs.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/ceph-disk.sh.log: test/ceph-disk.sh @p='test/ceph-disk.sh'; \ b='test/ceph-disk.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/mon/mon-handle-forward.sh.log: test/mon/mon-handle-forward.sh @p='test/mon/mon-handle-forward.sh'; \ b='test/mon/mon-handle-forward.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/vstart_wrapped_tests.sh.log: test/vstart_wrapped_tests.sh @p='test/vstart_wrapped_tests.sh'; \ b='test/vstart_wrapped_tests.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test/pybind/test_ceph_argparse.py.log: test/pybind/test_ceph_argparse.py @p='test/pybind/test_ceph_argparse.py'; \ b='test/pybind/test_ceph_argparse.py'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) \ $(DATA) $(HEADERS) acconfig.h install-binPROGRAMS: install-libLTLIBRARIES installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(erasure_codelibdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(radoslibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(su_sbindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(ceph_sbindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(shell_commondir)" "$(DESTDIR)$(su_sbindir)" "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(bash_completiondir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(libcephfs_includedir)" "$(DESTDIR)$(librbd_includedir)" "$(DESTDIR)$(rados_includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f arch/$(DEPDIR)/$(am__dirstamp) -rm -f arch/$(am__dirstamp) -rm -f auth/$(DEPDIR)/$(am__dirstamp) -rm -f auth/$(am__dirstamp) -rm -f auth/cephx/$(DEPDIR)/$(am__dirstamp) -rm -f auth/cephx/$(am__dirstamp) -rm -f auth/none/$(DEPDIR)/$(am__dirstamp) -rm -f auth/none/$(am__dirstamp) -rm -f auth/unknown/$(DEPDIR)/$(am__dirstamp) -rm -f auth/unknown/$(am__dirstamp) -rm -f civetweb/src/$(DEPDIR)/$(am__dirstamp) -rm -f civetweb/src/$(am__dirstamp) -rm -f client/$(DEPDIR)/$(am__dirstamp) -rm -f client/$(am__dirstamp) -rm -f cls/hello/$(DEPDIR)/$(am__dirstamp) -rm -f cls/hello/$(am__dirstamp) -rm -f cls/lock/$(DEPDIR)/$(am__dirstamp) -rm -f cls/lock/$(am__dirstamp) -rm -f cls/log/$(DEPDIR)/$(am__dirstamp) -rm -f cls/log/$(am__dirstamp) -rm -f cls/rbd/$(DEPDIR)/$(am__dirstamp) -rm -f cls/rbd/$(am__dirstamp) -rm -f cls/refcount/$(DEPDIR)/$(am__dirstamp) -rm -f cls/refcount/$(am__dirstamp) -rm -f cls/replica_log/$(DEPDIR)/$(am__dirstamp) -rm -f cls/replica_log/$(am__dirstamp) -rm -f cls/rgw/$(DEPDIR)/$(am__dirstamp) -rm -f cls/rgw/$(am__dirstamp) -rm -f cls/statelog/$(DEPDIR)/$(am__dirstamp) -rm -f cls/statelog/$(am__dirstamp) -rm -f cls/user/$(DEPDIR)/$(am__dirstamp) -rm -f cls/user/$(am__dirstamp) -rm -f cls/version/$(DEPDIR)/$(am__dirstamp) -rm -f cls/version/$(am__dirstamp) -rm -f common/$(DEPDIR)/$(am__dirstamp) -rm -f common/$(am__dirstamp) -rm -f crush/$(DEPDIR)/$(am__dirstamp) -rm -f crush/$(am__dirstamp) -rm -f erasure-code/$(DEPDIR)/$(am__dirstamp) -rm -f erasure-code/$(am__dirstamp) -rm -f erasure-code/jerasure/$(DEPDIR)/$(am__dirstamp) -rm -f erasure-code/jerasure/$(am__dirstamp) -rm -f erasure-code/jerasure/gf-complete/src/$(DEPDIR)/$(am__dirstamp) -rm -f erasure-code/jerasure/gf-complete/src/$(am__dirstamp) -rm -f erasure-code/jerasure/jerasure/src/$(DEPDIR)/$(am__dirstamp) -rm -f erasure-code/jerasure/jerasure/src/$(am__dirstamp) -rm -f global/$(DEPDIR)/$(am__dirstamp) -rm -f global/$(am__dirstamp) -rm -f java/native/$(DEPDIR)/$(am__dirstamp) -rm -f java/native/$(am__dirstamp) -rm -f json_spirit/$(DEPDIR)/$(am__dirstamp) -rm -f json_spirit/$(am__dirstamp) -rm -f key_value_store/$(DEPDIR)/$(am__dirstamp) -rm -f key_value_store/$(am__dirstamp) -rm -f librados/$(DEPDIR)/$(am__dirstamp) -rm -f librados/$(am__dirstamp) -rm -f librbd/$(DEPDIR)/$(am__dirstamp) -rm -f librbd/$(am__dirstamp) -rm -f log/$(DEPDIR)/$(am__dirstamp) -rm -f log/$(am__dirstamp) -rm -f mds/$(DEPDIR)/$(am__dirstamp) -rm -f mds/$(am__dirstamp) -rm -f mon/$(DEPDIR)/$(am__dirstamp) -rm -f mon/$(am__dirstamp) -rm -f mount/$(DEPDIR)/$(am__dirstamp) -rm -f mount/$(am__dirstamp) -rm -f msg/$(DEPDIR)/$(am__dirstamp) -rm -f msg/$(am__dirstamp) -rm -f objclass/$(DEPDIR)/$(am__dirstamp) -rm -f objclass/$(am__dirstamp) -rm -f os/$(DEPDIR)/$(am__dirstamp) -rm -f os/$(am__dirstamp) -rm -f osd/$(DEPDIR)/$(am__dirstamp) -rm -f osd/$(am__dirstamp) -rm -f osdc/$(DEPDIR)/$(am__dirstamp) -rm -f osdc/$(am__dirstamp) -rm -f perfglue/$(DEPDIR)/$(am__dirstamp) -rm -f perfglue/$(am__dirstamp) -rm -f rbd_fuse/$(DEPDIR)/$(am__dirstamp) -rm -f rbd_fuse/$(am__dirstamp) -rm -f rgw/$(DEPDIR)/$(am__dirstamp) -rm -f rgw/$(am__dirstamp) -rm -f test/$(DEPDIR)/$(am__dirstamp) -rm -f test/$(am__dirstamp) -rm -f test/ObjectMap/$(DEPDIR)/$(am__dirstamp) -rm -f test/ObjectMap/$(am__dirstamp) -rm -f test/bench/$(DEPDIR)/$(am__dirstamp) -rm -f test/bench/$(am__dirstamp) -rm -f test/cls_hello/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_hello/$(am__dirstamp) -rm -f test/cls_lock/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_lock/$(am__dirstamp) -rm -f test/cls_log/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_log/$(am__dirstamp) -rm -f test/cls_rbd/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_rbd/$(am__dirstamp) -rm -f test/cls_refcount/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_refcount/$(am__dirstamp) -rm -f test/cls_replica_log/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_replica_log/$(am__dirstamp) -rm -f test/cls_rgw/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_rgw/$(am__dirstamp) -rm -f test/cls_statelog/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_statelog/$(am__dirstamp) -rm -f test/cls_version/$(DEPDIR)/$(am__dirstamp) -rm -f test/cls_version/$(am__dirstamp) -rm -f test/common/$(DEPDIR)/$(am__dirstamp) -rm -f test/common/$(am__dirstamp) -rm -f test/crush/$(DEPDIR)/$(am__dirstamp) -rm -f test/crush/$(am__dirstamp) -rm -f test/encoding/$(DEPDIR)/$(am__dirstamp) -rm -f test/encoding/$(am__dirstamp) -rm -f test/erasure-code/$(DEPDIR)/$(am__dirstamp) -rm -f test/erasure-code/$(am__dirstamp) -rm -f test/libcephfs/$(DEPDIR)/$(am__dirstamp) -rm -f test/libcephfs/$(am__dirstamp) -rm -f test/librados/$(DEPDIR)/$(am__dirstamp) -rm -f test/librados/$(am__dirstamp) -rm -f test/librbd/$(DEPDIR)/$(am__dirstamp) -rm -f test/librbd/$(am__dirstamp) -rm -f test/mon/$(DEPDIR)/$(am__dirstamp) -rm -f test/mon/$(am__dirstamp) -rm -f test/objectstore/$(DEPDIR)/$(am__dirstamp) -rm -f test/objectstore/$(am__dirstamp) -rm -f test/os/$(DEPDIR)/$(am__dirstamp) -rm -f test/os/$(am__dirstamp) -rm -f test/osd/$(DEPDIR)/$(am__dirstamp) -rm -f test/osd/$(am__dirstamp) -rm -f test/osdc/$(DEPDIR)/$(am__dirstamp) -rm -f test/osdc/$(am__dirstamp) -rm -f test/rgw/$(DEPDIR)/$(am__dirstamp) -rm -f test/rgw/$(am__dirstamp) -rm -f test/system/$(DEPDIR)/$(am__dirstamp) -rm -f test/system/$(am__dirstamp) -rm -f tools/$(DEPDIR)/$(am__dirstamp) -rm -f tools/$(am__dirstamp) -rm -f tools/rados/$(DEPDIR)/$(am__dirstamp) -rm -f tools/rados/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-binPROGRAMS clean-checkPROGRAMS \ clean-erasure_codelibLTLIBRARIES clean-generic \ clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLIBRARIES clean-noinstLTLIBRARIES \ clean-noinstPROGRAMS clean-radoslibLTLIBRARIES \ clean-sbinPROGRAMS clean-su_sbinPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) arch/$(DEPDIR) auth/$(DEPDIR) auth/cephx/$(DEPDIR) auth/none/$(DEPDIR) auth/unknown/$(DEPDIR) civetweb/src/$(DEPDIR) client/$(DEPDIR) cls/hello/$(DEPDIR) cls/lock/$(DEPDIR) cls/log/$(DEPDIR) cls/rbd/$(DEPDIR) cls/refcount/$(DEPDIR) cls/replica_log/$(DEPDIR) cls/rgw/$(DEPDIR) cls/statelog/$(DEPDIR) cls/user/$(DEPDIR) cls/version/$(DEPDIR) common/$(DEPDIR) crush/$(DEPDIR) erasure-code/$(DEPDIR) erasure-code/jerasure/$(DEPDIR) erasure-code/jerasure/gf-complete/src/$(DEPDIR) erasure-code/jerasure/jerasure/src/$(DEPDIR) global/$(DEPDIR) java/native/$(DEPDIR) json_spirit/$(DEPDIR) key_value_store/$(DEPDIR) librados/$(DEPDIR) librbd/$(DEPDIR) log/$(DEPDIR) mds/$(DEPDIR) mon/$(DEPDIR) mount/$(DEPDIR) msg/$(DEPDIR) objclass/$(DEPDIR) os/$(DEPDIR) osd/$(DEPDIR) osdc/$(DEPDIR) perfglue/$(DEPDIR) rbd_fuse/$(DEPDIR) rgw/$(DEPDIR) test/$(DEPDIR) test/ObjectMap/$(DEPDIR) test/bench/$(DEPDIR) test/cls_hello/$(DEPDIR) test/cls_lock/$(DEPDIR) test/cls_log/$(DEPDIR) test/cls_rbd/$(DEPDIR) test/cls_refcount/$(DEPDIR) test/cls_replica_log/$(DEPDIR) test/cls_rgw/$(DEPDIR) test/cls_statelog/$(DEPDIR) test/cls_version/$(DEPDIR) test/common/$(DEPDIR) test/crush/$(DEPDIR) test/encoding/$(DEPDIR) test/erasure-code/$(DEPDIR) test/libcephfs/$(DEPDIR) test/librados/$(DEPDIR) test/librbd/$(DEPDIR) test/mon/$(DEPDIR) test/objectstore/$(DEPDIR) test/os/$(DEPDIR) test/osd/$(DEPDIR) test/osdc/$(DEPDIR) test/rgw/$(DEPDIR) test/system/$(DEPDIR) tools/$(DEPDIR) tools/rados/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-bash_completionDATA install-ceph_sbinSCRIPTS \ install-data-local install-docDATA \ install-erasure_codelibLTLIBRARIES \ install-libcephfs_includeDATA install-librbd_includeDATA \ install-pythonPYTHON install-rados_includeDATA \ install-radoslibLTLIBRARIES install-shell_commonSCRIPTS \ install-su_sbinPROGRAMS install-su_sbinSCRIPTS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-binSCRIPTS \ install-dist_binSCRIPTS install-libLTLIBRARIES \ install-sbinPROGRAMS install-sbinSCRIPTS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) arch/$(DEPDIR) auth/$(DEPDIR) auth/cephx/$(DEPDIR) auth/none/$(DEPDIR) auth/unknown/$(DEPDIR) civetweb/src/$(DEPDIR) client/$(DEPDIR) cls/hello/$(DEPDIR) cls/lock/$(DEPDIR) cls/log/$(DEPDIR) cls/rbd/$(DEPDIR) cls/refcount/$(DEPDIR) cls/replica_log/$(DEPDIR) cls/rgw/$(DEPDIR) cls/statelog/$(DEPDIR) cls/user/$(DEPDIR) cls/version/$(DEPDIR) common/$(DEPDIR) crush/$(DEPDIR) erasure-code/$(DEPDIR) erasure-code/jerasure/$(DEPDIR) erasure-code/jerasure/gf-complete/src/$(DEPDIR) erasure-code/jerasure/jerasure/src/$(DEPDIR) global/$(DEPDIR) java/native/$(DEPDIR) json_spirit/$(DEPDIR) key_value_store/$(DEPDIR) librados/$(DEPDIR) librbd/$(DEPDIR) log/$(DEPDIR) mds/$(DEPDIR) mon/$(DEPDIR) mount/$(DEPDIR) msg/$(DEPDIR) objclass/$(DEPDIR) os/$(DEPDIR) osd/$(DEPDIR) osdc/$(DEPDIR) perfglue/$(DEPDIR) rbd_fuse/$(DEPDIR) rgw/$(DEPDIR) test/$(DEPDIR) test/ObjectMap/$(DEPDIR) test/bench/$(DEPDIR) test/cls_hello/$(DEPDIR) test/cls_lock/$(DEPDIR) test/cls_log/$(DEPDIR) test/cls_rbd/$(DEPDIR) test/cls_refcount/$(DEPDIR) test/cls_replica_log/$(DEPDIR) test/cls_rgw/$(DEPDIR) test/cls_statelog/$(DEPDIR) test/cls_version/$(DEPDIR) test/common/$(DEPDIR) test/crush/$(DEPDIR) test/encoding/$(DEPDIR) test/erasure-code/$(DEPDIR) test/libcephfs/$(DEPDIR) test/librados/$(DEPDIR) test/librbd/$(DEPDIR) test/mon/$(DEPDIR) test/objectstore/$(DEPDIR) test/os/$(DEPDIR) test/osd/$(DEPDIR) test/osdc/$(DEPDIR) test/rgw/$(DEPDIR) test/system/$(DEPDIR) tools/$(DEPDIR) tools/rados/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-bash_completionDATA uninstall-binPROGRAMS \ uninstall-binSCRIPTS uninstall-ceph_sbinSCRIPTS \ uninstall-dist_binSCRIPTS uninstall-docDATA \ uninstall-erasure_codelibLTLIBRARIES uninstall-libLTLIBRARIES \ uninstall-libcephfs_includeDATA uninstall-librbd_includeDATA \ uninstall-local uninstall-pythonPYTHON \ uninstall-rados_includeDATA uninstall-radoslibLTLIBRARIES \ uninstall-sbinPROGRAMS uninstall-sbinSCRIPTS \ uninstall-shell_commonSCRIPTS uninstall-su_sbinPROGRAMS \ uninstall-su_sbinSCRIPTS .MAKE: $(am__recursive_targets) all check check-am install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-TESTS check-am check-local clean clean-binPROGRAMS \ clean-checkPROGRAMS clean-erasure_codelibLTLIBRARIES \ clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLIBRARIES clean-noinstLTLIBRARIES \ clean-noinstPROGRAMS clean-radoslibLTLIBRARIES \ clean-sbinPROGRAMS clean-su_sbinPROGRAMS cscopelist-am ctags \ ctags-am dist-hook distclean distclean-compile \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-bash_completionDATA \ install-binPROGRAMS install-binSCRIPTS \ install-ceph_sbinSCRIPTS install-data install-data-am \ install-data-local install-dist_binSCRIPTS install-docDATA \ install-dvi install-dvi-am install-erasure_codelibLTLIBRARIES \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-libcephfs_includeDATA install-librbd_includeDATA \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-pythonPYTHON install-rados_includeDATA \ install-radoslibLTLIBRARIES install-sbinPROGRAMS \ install-sbinSCRIPTS install-shell_commonSCRIPTS install-strip \ install-su_sbinPROGRAMS install-su_sbinSCRIPTS installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ recheck tags tags-am uninstall uninstall-am \ uninstall-bash_completionDATA uninstall-binPROGRAMS \ uninstall-binSCRIPTS uninstall-ceph_sbinSCRIPTS \ uninstall-dist_binSCRIPTS uninstall-docDATA \ uninstall-erasure_codelibLTLIBRARIES uninstall-libLTLIBRARIES \ uninstall-libcephfs_includeDATA uninstall-librbd_includeDATA \ uninstall-local uninstall-pythonPYTHON \ uninstall-rados_includeDATA uninstall-radoslibLTLIBRARIES \ uninstall-sbinPROGRAMS uninstall-sbinSCRIPTS \ uninstall-shell_commonSCRIPTS uninstall-su_sbinPROGRAMS \ uninstall-su_sbinSCRIPTS # python unit tests need to know where the scripts are located export PYTHONPATH=$(top_srcdir)/src/pybind @CLANG_FALSE@ AM_COMMON_CFLAGS += -rdynamic @CLANG_FALSE@ AM_CXXFLAGS += -Wstrict-null-sentinel #crush_includedir = $(includedir)/crush #crush_include_DATA = \ # $(srcdir)/crush/hash.h \ # $(srcdir)/crush/crush.h \ # $(srcdir)/crush/mapper.h \ # $(srcdir)/crush/types.h # target to build but not run the unit tests unittests:: $(check_PROGRAMS) $(shell_scripts): Makefile $(shell_scripts): %: %.in rm -f $@ $@.tmp $(editpaths) '$(srcdir)/$@.in' >$@.tmp chmod +x $@.tmp chmod a-w $@.tmp mv $@.tmp $@ # work around old versions of automake that don't define $docdir # NOTE: this won't work on suse, where docdir is /usr/share/doc/packages/$package. docdir ?= ${datadir}/doc/ceph check-local: $(top_srcdir)/qa/workunits/erasure-code/encode-decode-non-regression.sh $(srcdir)/test/encoding/readable.sh ../ceph-object-corpus # base targets core-daemons: ceph-mon ceph-osd ceph-mds radosgw admin-tools: monmaptool osdmaptool crushtool ceph-authtool base: core-daemons admin-tools \ cephfs ceph-syn ceph-conf \ rados librados-config \ init-ceph mkcephfs ceph_mon_store_converter ceph-post-file # version stuff FORCE: .git_version: FORCE $(srcdir)/check_version $(srcdir)/.git_version # if NO_VERSION is set, only generate a new ceph_ver.h if there currently # is none, and call "make_version -n" to fill it with a fixed string. # Otherwise, set it from the contents of .git_version. ceph_ver.h: .git_version if [ -n "$$NO_VERSION" ] ; then \ if [ ! -f ./ceph_ver.h ] ; then \ $(srcdir)/make_version -n ./ceph_ver.h ; \ fi; \ else \ $(srcdir)/make_version $(srcdir)/.git_version ./ceph_ver.h ; \ fi ceph_ver.c: ./ceph_ver.h common/version.cc: ./ceph_ver.h test/encoding/ceph_dencoder.cc: ./ceph_ver.h sample.fetch_config: fetch_config cp -f $(srcdir)/fetch_config ./sample.fetch_config dist-hook: $(srcdir)/check_version $(srcdir)/.git_version # assemble Python script with global version variables # NB: depends on format of ceph_ver.h ceph: ceph.in ./ceph_ver.h Makefile rm -f $@ $@.tmp echo "#!/usr/bin/env python" >$@.tmp grep "#define CEPH_GIT_NICE_VER" ./ceph_ver.h | \ sed -e 's/#define \(.*VER\) /\1=/' >>$@.tmp grep "#define CEPH_GIT_VER" ./ceph_ver.h | \ sed -e 's/#define \(.*VER\) /\1=/' -e 's/=\(.*\)$$/="\1"/' >>$@.tmp cat $(srcdir)/$@.in >>$@.tmp chmod a+x $@.tmp chmod a-w $@.tmp mv $@.tmp $@ # cleaning clean-local: rm -f *.so find . -name '*.gcno' -o -name '*.gcda' -o -name '*.lcov' | xargs rm -f rm -f ceph java/java/com/ceph/crush/Bucket.class install-coverage: @ENABLE_COVERAGE_TRUE@ -mkdir -p $(COV_DIR)/.libs @ENABLE_COVERAGE_TRUE@ -$(INSTALL_DATA) $(COV_FILES) $(COV_DIR) @ENABLE_COVERAGE_TRUE@ -$(INSTALL_DATA) $(COV_LIB_FILES) $(COV_DIR)/.libs uninstall-coverage: @ENABLE_COVERAGE_TRUE@ -rm $(COV_DIR)/*.gcno @ENABLE_COVERAGE_TRUE@ -rm $(COV_DIR)/.libs/*.gcno @ENABLE_COVERAGE_TRUE@ -rmdir -p $(COV_DIR)/.libs @ENABLE_COVERAGE_TRUE@ -rmdir -p $(COV_DIR) check-coverage: @ENABLE_COVERAGE_TRUE@ -test/coverage.sh -d $(srcdir) -o check-coverage make check install-data-local: install-coverage -mkdir -p $(DESTDIR)$(sysconfdir)/ceph -mkdir -p $(DESTDIR)$(localstatedir)/log/ceph -mkdir -p $(DESTDIR)$(localstatedir)/lib/ceph/tmp uninstall-local: uninstall-coverage -rmdir -p $(DESTDIR)$(sysconfdir)/ceph/ -rmdir -p $(DESTDIR)$(localstatedir)/log/ceph -rmdir -p $(DESTDIR)$(localstatedir)/lib/ceph/tmp # # coverity rules expect: # - cov-build to be in the path # - password in ~/coverity.build.pass.txt # - ability to scp into the ceph.com directory # project.tgz: clean rm -rf cov-int cov-build --dir cov-int make echo Sage Weil sage@newdream.net ceph >> README tar czvf project.tgz README cov-int rm -f README coverity-submit: scp project.tgz ceph.com:/home/ceph_site/ceph.com/coverity/`git describe`.tgz curl --data "project=ceph&password=`cat ~/coverity.build.pass.txt`&email=sage@newdream.net&url=http://ceph.com/coverity/`git describe`.tgz" http://scan5.coverity.com/cgi-bin/submit_build.py # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ceph-0.80.11/src/mount/0000775000175100017510000000000012623077036016621 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/mount/canonicalize.c0000664000175100017510000001063112623076744021432 0ustar jenkins-buildjenkins-build/* * canonicalize.c -- canonicalize pathname by removing symlinks * Copyright (C) 1993 Rick Sladkey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library Public License for more details. * */ /* * This routine is part of libc. We include it nevertheless, * since the libc version has some security flaws. * * TODO: use canonicalize_file_name() when exist in glibc */ #include #include #include #include #include #include #include #ifndef MAXSYMLINKS # define MAXSYMLINKS 256 #endif static char * myrealpath(const char *path, char *resolved_path, int maxreslth) { int readlinks = 0; char *npath; char *link_path; int n; char *buf = NULL; npath = resolved_path; /* If it's a relative pathname use getcwd for starters. */ if (*path != '/') { if (!getcwd(npath, maxreslth-2)) return NULL; npath += strlen(npath); if (npath[-1] != '/') *npath++ = '/'; } else { *npath++ = '/'; path++; } /* Expand each slash-separated pathname component. */ link_path = malloc(PATH_MAX+1); if (!link_path) return NULL; while (*path != '\0') { /* Ignore stray "/" */ if (*path == '/') { path++; continue; } if (*path == '.' && (path[1] == '\0' || path[1] == '/')) { /* Ignore "." */ path++; continue; } if (*path == '.' && path[1] == '.' && (path[2] == '\0' || path[2] == '/')) { /* Backup for ".." */ path += 2; while (npath > resolved_path+1 && (--npath)[-1] != '/') ; continue; } /* Safely copy the next pathname component. */ while (*path != '\0' && *path != '/') { if (npath-resolved_path > maxreslth-2) { errno = ENAMETOOLONG; goto err; } *npath++ = *path++; } /* Protect against infinite loops. */ if (readlinks++ > MAXSYMLINKS) { errno = ELOOP; goto err; } /* See if last pathname component is a symlink. */ *npath = '\0'; n = readlink(resolved_path, link_path, PATH_MAX); if (n < 0) { /* EINVAL means the file exists but isn't a symlink. */ if (errno != EINVAL) goto err; } else { int m; char *newbuf; /* Note: readlink doesn't add the null byte. */ link_path[n] = '\0'; if (*link_path == '/') /* Start over for an absolute symlink. */ npath = resolved_path; else /* Otherwise back up over this component. */ while (*(--npath) != '/') ; /* Insert symlink contents into path. */ m = strlen(path); newbuf = malloc(m + n + 1); if (!newbuf) goto err; memcpy(newbuf, link_path, n); memcpy(newbuf + n, path, m + 1); free(buf); path = buf = newbuf; } *npath++ = '/'; } /* Delete trailing slash but don't whomp a lone slash. */ if (npath != resolved_path+1 && npath[-1] == '/') npath--; /* Make sure it's null terminated. */ *npath = '\0'; free(link_path); free(buf); return resolved_path; err: free(link_path); free(buf); return NULL; } /* * Converts private "dm-N" names to "/dev/mapper/" * * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs * provides the real DM device names in /sys/block//dm/name */ char * canonicalize_dm_name(const char *ptname) { FILE *f; size_t sz; char path[256], name[256], *res = NULL; snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); if (!(f = fopen(path, "r"))) return NULL; /* read "\n" from sysfs */ if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { name[sz - 1] = '\0'; snprintf(path, sizeof(path), "/dev/mapper/%s", name); res = strdup(path); } fclose(f); return res; } char * canonicalize_path(const char *path) { char *canonical; char *p; if (path == NULL) return NULL; canonical = malloc(PATH_MAX+2); if (!canonical) return NULL; if (!myrealpath(path, canonical, PATH_MAX+1)) { free(canonical); return strdup(path); } p = strrchr(canonical, '/'); if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { p = canonicalize_dm_name(p+1); if (p) { free(canonical); return p; } } return canonical; } ceph-0.80.11/src/mount/mtab.c0000664000175100017510000002004212623076744017713 0ustar jenkins-buildjenkins-build /* * this code lifted from util-linux-ng, licensed GPLv2+, * * git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git * * whoever decided that each special mount program is responsible * for updating /etc/mtab should be spanked. * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mount/canonicalize.c" /* Updating mtab ----------------------------------------------*/ /* Flag for already existing lock file. */ static int we_created_lockfile = 0; static int lockfile_fd = -1; /* Flag to indicate that signals have been set up. */ static int signals_have_been_setup = 0; /* Ensure that the lock is released if we are interrupted. */ extern char *strsignal(int sig); /* not always in */ static void setlkw_timeout (int sig) { /* nothing, fcntl will fail anyway */ } #define _PATH_MOUNTED "/etc/mtab" #define _PATH_MOUNTED_LOCK "/etc/mtab~" #define PROC_SUPER_MAGIC 0x9fa0 /* exit status - bits below are ORed */ #define EX_USAGE 1 /* incorrect invocation or permission */ #define EX_SYSERR 2 /* out of memory, cannot fork, ... */ #define EX_SOFTWARE 4 /* internal mount bug or wrong version */ #define EX_USER 8 /* user interrupt */ #define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */ #define EX_FAIL 32 /* mount failure */ #define EX_SOMEOK 64 /* some mount succeeded */ int die(int err, const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); exit(err); } static void handler (int sig) { die(EX_USER, "%s", strsignal(sig)); } /* Remove lock file. */ void unlock_mtab (void) { if (we_created_lockfile) { close(lockfile_fd); lockfile_fd = -1; unlink (_PATH_MOUNTED_LOCK); we_created_lockfile = 0; } } /* Create the lock file. The lock file will be removed if we catch a signal or when we exit. */ /* The old code here used flock on a lock file /etc/mtab~ and deleted this lock file afterwards. However, as rgooch remarks, that has a race: a second mount may be waiting on the lock and proceed as soon as the lock file is deleted by the first mount, and immediately afterwards a third mount comes, creates a new /etc/mtab~, applies flock to that, and also proceeds, so that the second and third mount now both are scribbling in /etc/mtab. The new code uses a link() instead of a creat(), where we proceed only if it was us that created the lock, and hence we always have to delete the lock afterwards. Now the use of flock() is in principle superfluous, but avoids an arbitrary sleep(). */ /* Where does the link point to? Obvious choices are mtab and mtab~~. HJLu points out that the latter leads to races. Right now we use mtab~. instead. Use 20 as upper bound for the length of %d. */ #define MOUNTLOCK_LINKTARGET _PATH_MOUNTED_LOCK "%d" #define MOUNTLOCK_LINKTARGET_LTH (sizeof(_PATH_MOUNTED_LOCK)+20) /* * The original mount locking code has used sleep(1) between attempts and * maximal number of attemps has been 5. * * There was very small number of attempts and extremely long waiting (1s) * that is useless on machines with large number of concurret mount processes. * * Now we wait few thousand microseconds between attempts and we have global * time limit (30s) rather than limit for number of attempts. The advantage * is that this method also counts time which we spend in fcntl(F_SETLKW) and * number of attempts is not so much restricted. * * -- kzak@redhat.com [2007-Mar-2007] */ /* maximum seconds between first and last attempt */ #define MOUNTLOCK_MAXTIME 30 /* sleep time (in microseconds, max=999999) between attempts */ #define MOUNTLOCK_WAITTIME 5000 void lock_mtab (void) { int i; struct timespec waittime; struct timeval maxtime; char linktargetfile[MOUNTLOCK_LINKTARGET_LTH]; if (!signals_have_been_setup) { int sig = 0; struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; sigfillset (&sa.sa_mask); while (sigismember (&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD) { if (sig == SIGALRM) sa.sa_handler = setlkw_timeout; else sa.sa_handler = handler; sigaction (sig, &sa, (struct sigaction *) 0); } signals_have_been_setup = 1; } snprintf(linktargetfile, sizeof(linktargetfile), MOUNTLOCK_LINKTARGET, getpid ()); i = open (linktargetfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); if (i < 0) { int errsv = errno; /* linktargetfile does not exist (as a file) and we cannot create it. Read-only filesystem? Too many files open in the system? Filesystem full? */ die (EX_FILEIO, "can't create lock file %s: %s " "(use -n flag to override)", linktargetfile, strerror (errsv)); } close(i); gettimeofday(&maxtime, NULL); maxtime.tv_sec += MOUNTLOCK_MAXTIME; waittime.tv_sec = 0; waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME); /* Repeat until it was us who made the link */ while (!we_created_lockfile) { struct timeval now; struct flock flock; int errsv, j; j = link(linktargetfile, _PATH_MOUNTED_LOCK); errsv = errno; if (j == 0) we_created_lockfile = 1; if (j < 0 && errsv != EEXIST) { (void) unlink(linktargetfile); die (EX_FILEIO, "can't link lock file %s: %s " "(use -n flag to override)", _PATH_MOUNTED_LOCK, strerror (errsv)); } lockfile_fd = open (_PATH_MOUNTED_LOCK, O_WRONLY); if (lockfile_fd < 0) { /* Strange... Maybe the file was just deleted? */ int errsv = errno; gettimeofday(&now, NULL); if (errno == ENOENT && now.tv_sec < maxtime.tv_sec) { we_created_lockfile = 0; continue; } (void) unlink(linktargetfile); die (EX_FILEIO, "can't open lock file %s: %s " "(use -n flag to override)", _PATH_MOUNTED_LOCK, strerror (errsv)); } flock.l_type = F_WRLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; if (j == 0) { /* We made the link. Now claim the lock. */ if (fcntl (lockfile_fd, F_SETLK, &flock) == -1) { /* proceed, since it was us who created the lockfile anyway */ } (void) unlink(linktargetfile); } else { /* Someone else made the link. Wait. */ gettimeofday(&now, NULL); if (now.tv_sec < maxtime.tv_sec) { alarm(maxtime.tv_sec - now.tv_sec); if (fcntl (lockfile_fd, F_SETLKW, &flock) == -1) { int errsv = errno; (void) unlink(linktargetfile); die (EX_FILEIO, "can't lock lock file %s: %s", _PATH_MOUNTED_LOCK, (errno == EINTR) ? "timed out" : strerror (errsv)); } alarm(0); nanosleep(&waittime, NULL); } else { (void) unlink(linktargetfile); die (EX_FILEIO, "Cannot create link %s\n" "Perhaps there is a stale lock file?\n", _PATH_MOUNTED_LOCK); } close(lockfile_fd); } } } static void update_mtab_entry(const char *spec, const char *node, const char *type, const char *opts, int flags, int freq, int pass) { struct statfs buf; int err = statfs(_PATH_MOUNTED, &buf); if (err) { printf("mount: can't statfs %s: %s", _PATH_MOUNTED, strerror (err)); return; } /* /etc/mtab is symbol link to /proc/self/mounts? */ if (buf.f_type == PROC_SUPER_MAGIC) return; if (!opts) opts = "rw"; struct mntent mnt; mnt.mnt_fsname = strdup(spec); mnt.mnt_dir = canonicalize_path(node); mnt.mnt_type = strdup(type); mnt.mnt_opts = strdup(opts); mnt.mnt_freq = freq; mnt.mnt_passno = pass; FILE *fp; lock_mtab(); fp = setmntent(_PATH_MOUNTED, "a+"); if (fp == NULL) { int errsv = errno; printf("mount: can't open %s: %s", _PATH_MOUNTED, strerror (errsv)); } else { if ((addmntent (fp, &mnt)) == 1) { int errsv = errno; printf("mount: error writing %s: %s", _PATH_MOUNTED, strerror (errsv)); } } endmntent(fp); unlock_mtab(); free(mnt.mnt_fsname); free(mnt.mnt_dir); } ceph-0.80.11/src/mount/mount.ceph.c0000664000175100017510000002163312623076744021057 0ustar jenkins-buildjenkins-build#include #include #include #include #include #include #include #include "common/secret.h" #include "include/addr_parsing.h" #ifndef MS_RELATIME # define MS_RELATIME (1<<21) #endif #define MAX_SECRET_LEN 1000 #define MAX_SECRET_OPTION_LEN (MAX_SECRET_LEN + 7) int verboseflag = 0; int skip_mtab_flag = 0; static const char * const EMPTY_STRING = ""; /* TODO duplicates logic from kernel */ #define CEPH_AUTH_NAME_DEFAULT "guest" #include "mtab.c" static void block_signals (int how) { sigset_t sigs; sigfillset (&sigs); sigdelset(&sigs, SIGTRAP); sigdelset(&sigs, SIGSEGV); sigprocmask (how, &sigs, (sigset_t *) 0); } static char *mount_resolve_src(const char *orig_str) { int len, pos; char *mount_path; char *src; char *buf = strdup(orig_str); mount_path = strstr(buf, ":/"); if (!mount_path) { printf("source mount path was not specified\n"); free(buf); return NULL; } if (mount_path == buf) { printf("server address expected\n"); free(buf); return NULL; } *mount_path = '\0'; mount_path++; if (!*mount_path) { printf("incorrect source mount path\n"); free(buf); return NULL; } src = resolve_addrs(buf); if (!src) return NULL; len = strlen(src); pos = safe_cat(&src, &len, len, ":"); safe_cat(&src, &len, pos, mount_path); free(buf); return src; } /* * this one is partialy based on parse_options() from cifs.mount.c */ static char *parse_options(const char *data, int *filesys_flags) { char * next_keyword = NULL; char * out = NULL; int out_len = 0; int pos = 0; char *name = NULL; int name_len = 0; int name_pos = 0; char secret[MAX_SECRET_LEN]; char *saw_name = NULL; char *saw_secret = NULL; if(verboseflag) printf("parsing options: %s\n", data); do { char * value = NULL; /* check if ends with trailing comma */ if(*data == 0) break; next_keyword = strchr(data,','); /* temporarily null terminate end of keyword=value pair */ if(next_keyword) *next_keyword++ = 0; /* temporarily null terminate keyword to make keyword and value distinct */ if ((value = strchr(data, '=')) != NULL) { *value = '\0'; value++; } int skip = 1; if (strncmp(data, "ro", 2) == 0) { *filesys_flags |= MS_RDONLY; } else if (strncmp(data, "rw", 2) == 0) { *filesys_flags &= ~MS_RDONLY; } else if (strncmp(data, "nosuid", 6) == 0) { *filesys_flags |= MS_NOSUID; } else if (strncmp(data, "suid", 4) == 0) { *filesys_flags &= ~MS_NOSUID; } else if (strncmp(data, "dev", 3) == 0) { *filesys_flags &= ~MS_NODEV; } else if (strncmp(data, "nodev", 5) == 0) { *filesys_flags |= MS_NODEV; } else if (strncmp(data, "noexec", 6) == 0) { *filesys_flags |= MS_NOEXEC; } else if (strncmp(data, "exec", 4) == 0) { *filesys_flags &= ~MS_NOEXEC; } else if (strncmp(data, "sync", 4) == 0) { *filesys_flags |= MS_SYNCHRONOUS; } else if (strncmp(data, "remount", 7) == 0) { *filesys_flags |= MS_REMOUNT; } else if (strncmp(data, "mandlock", 8) == 0) { *filesys_flags |= MS_MANDLOCK; } else if ((strncmp(data, "nobrl", 5) == 0) || (strncmp(data, "nolock", 6) == 0)) { *filesys_flags &= ~MS_MANDLOCK; } else if (strncmp(data, "noatime", 7) == 0) { *filesys_flags |= MS_NOATIME; } else if (strncmp(data, "nodiratime", 10) == 0) { *filesys_flags |= MS_NODIRATIME; } else if (strncmp(data, "relatime", 8) == 0) { *filesys_flags |= MS_RELATIME; } else if (strncmp(data, "noauto", 6) == 0) { skip = 1; /* ignore */ } else if (strncmp(data, "_netdev", 7) == 0) { skip = 1; /* ignore */ } else if (strncmp(data, "secretfile", 10) == 0) { if (!value || !*value) { printf("keyword secretfile found, but no secret file specified\n"); return NULL; } if (read_secret_from_file(value, secret, sizeof(secret)) < 0) { printf("error reading secret file\n"); return NULL; } /* see comment for "secret" */ saw_secret = secret; skip = 1; } else if (strncmp(data, "secret", 6) == 0) { if (!value || !*value) { printf("mount option secret requires a value.\n"); return NULL; } /* secret is only added to kernel options as backwards compatilbity, if add_key doesn't recognize our keytype; hence, it is skipped here and appended to options on add_key failure */ strncpy(secret, value, sizeof(secret)); saw_secret = secret; skip = 1; } else if (strncmp(data, "name", 4) == 0) { if (!value || !*value) { printf("mount option name requires a value.\n"); return NULL; } /* take a copy of the name, to be used for naming the keys that we add to kernel; ignore memleak as mount.ceph is short-lived */ saw_name = strdup(value); if (!saw_name) { printf("out of memory.\n"); return NULL; } skip = 0; } else { skip = 0; if (verboseflag) printf("ceph: Unknown mount option %s\n",data); } /* Copy (possibly modified) option to out */ if (!skip) { if (pos) pos = safe_cat(&out, &out_len, pos, ","); if (value) { pos = safe_cat(&out, &out_len, pos, data); pos = safe_cat(&out, &out_len, pos, "="); pos = safe_cat(&out, &out_len, pos, value); } else { pos = safe_cat(&out, &out_len, pos, data); } } data = next_keyword; } while (data); name_pos = safe_cat(&name, &name_len, name_pos, "client."); if (!saw_name) { name_pos = safe_cat(&name, &name_len, name_pos, CEPH_AUTH_NAME_DEFAULT); } else { name_pos = safe_cat(&name, &name_len, name_pos, saw_name); } if (saw_secret || is_kernel_secret(name)) { int ret; char secret_option[MAX_SECRET_OPTION_LEN]; ret = get_secret_option(saw_secret, name, secret_option, sizeof(secret_option)); if (ret < 0) { return NULL; } else { if (pos) { pos = safe_cat(&out, &out_len, pos, ","); } pos = safe_cat(&out, &out_len, pos, secret_option); } } if (!out) return strdup(EMPTY_STRING); return out; } static int parse_arguments(int argc, char *const *const argv, const char **src, const char **node, const char **opts) { int i; if (argc < 2) { // There were no arguments. Just show the usage. return 1; } if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) { // The user asked for help. return 1; } // The first two arguments are positional if (argc < 3) return -EINVAL; *src = argv[1]; *node = argv[2]; // Parse the remaining options *opts = EMPTY_STRING; for (i = 3; i < argc; ++i) { if (!strcmp("-h", argv[i])) return 1; else if (!strcmp("-n", argv[i])) skip_mtab_flag = 1; else if (!strcmp("-v", argv[i])) verboseflag = 1; else if (!strcmp("-o", argv[i])) { ++i; if (i >= argc) { printf("Option -o requires an argument.\n\n"); return -EINVAL; } *opts = argv[i]; } else { printf("Can't understand option: '%s'\n\n", argv[i]); return -EINVAL; } } return 0; } /* modprobe failing doesn't necessarily prevent from working, so this returns void */ static void modprobe(void) { int status; status = system("/sbin/modprobe ceph"); if (status < 0) { char error_buf[80]; fprintf(stderr, "mount.ceph: cannot run modprobe: %s\n", strerror_r(errno, error_buf, sizeof(error_buf))); } else if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status != 0) { fprintf(stderr, "mount.ceph: modprobe failed, exit status %d\n", status); } } else if (WIFSIGNALED(status)) { fprintf(stderr, "mount.ceph: modprobe failed with signal %d\n", WTERMSIG(status)); } else { fprintf(stderr, "mount.ceph: weird status from modprobe: %d\n", status); } } static void usage(const char *prog_name) { printf("usage: %s [src] [mount-point] [-n] [-v] [-o ceph-options]\n", prog_name); printf("options:\n"); printf("\t-h: Print this help\n"); printf("\t-n: Do not update /etc/mtab\n"); printf("\t-v: Verbose\n"); printf("\tceph-options: refer to mount.ceph(8)\n"); printf("\n"); } int main(int argc, char *argv[]) { const char *src, *node, *opts; char *rsrc = NULL; char *popts = NULL; int flags = 0; int retval = 0; retval = parse_arguments(argc, argv, &src, &node, &opts); if (retval) { usage(argv[0]); exit((retval > 0) ? EXIT_SUCCESS : EXIT_FAILURE); } rsrc = mount_resolve_src(src); if (!rsrc) { printf("failed to resolve source\n"); exit(1); } modprobe(); popts = parse_options(opts, &flags); if (!popts) { printf("failed to parse ceph_options\n"); exit(1); } block_signals(SIG_BLOCK); if (mount(rsrc, node, "ceph", flags, popts)) { retval = errno; switch (errno) { case ENODEV: printf("mount error: ceph filesystem not supported by the system\n"); break; default: printf("mount error %d = %s\n",errno,strerror(errno)); } } else { if (!skip_mtab_flag) { update_mtab_entry(rsrc, node, "ceph", popts, flags, 0, 0); } } block_signals(SIG_UNBLOCK); free(popts); free(rsrc); exit(retval); } ceph-0.80.11/src/ceph-rest-api0000775000175100017510000000373012623076744020056 0ustar jenkins-buildjenkins-build#!/usr/bin/env python # vim: ts=4 sw=4 smarttab expandtab import argparse import inspect import os import sys # Make life easier on developers MYPATH = os.path.abspath(__file__) MYDIR = os.path.dirname(MYPATH) DEVMODEMSG = '*** DEVELOPER MODE: setting PYTHONPATH and LD_LIBRARY_PATH' if MYDIR.endswith('src') and \ os.path.exists(os.path.join(MYDIR, '.libs')) and \ os.path.exists(os.path.join(MYDIR, 'pybind')): MYLIBPATH = os.path.join(MYDIR, '.libs') if 'LD_LIBRARY_PATH' in os.environ: if MYLIBPATH not in os.environ['LD_LIBRARY_PATH']: os.environ['LD_LIBRARY_PATH'] += ':' + MYLIBPATH print >> sys.stderr, DEVMODEMSG os.execvp('python', ['python'] + sys.argv) else: os.environ['LD_LIBRARY_PATH'] = MYLIBPATH print >> sys.stderr, DEVMODEMSG os.execvp('python', ['python'] + sys.argv) sys.path.insert(0, os.path.join(MYDIR, 'pybind')) def parse_args(): parser = argparse.ArgumentParser(description="Ceph REST API webapp") parser.add_argument('-c', '--conf', help='Ceph configuration file') parser.add_argument('--cluster', help='Ceph cluster name') parser.add_argument('-n', '--name', help='Ceph client name') parser.add_argument('-i', '--id', help='Ceph client id') return parser.parse_known_args() # main parsed_args, rest = parse_args() # import now that env vars are available to imported module try: import ceph_rest_api except EnvironmentError as e: print >> sys.stderr, "Error importing ceph_rest_api: ", str(e) sys.exit(1) # let other exceptions generate traceback app = ceph_rest_api.generate_app( parsed_args.conf, parsed_args.cluster, parsed_args.name, parsed_args.id, rest, ) files = [os.path.split(fr[1])[-1] for fr in inspect.stack()] if 'pdb.py' in files: app.run(host=app.ceph_addr, port=app.ceph_port, debug=True, use_reloader=False, use_debugger=False) else: app.run(host=app.ceph_addr, port=app.ceph_port) ceph-0.80.11/src/tools/0000775000175100017510000000000012623077036016617 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/tools/radosacl.cc0000664000175100017510000001006712623076744020727 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "include/rados/librados.hpp" using namespace librados; #include #include #include #include void buf_to_hex(const unsigned char *buf, int len, char *str) { str[0] = '\0'; for (int i = 0; i < len; i++) { sprintf(&str[i*2], "%02x", (int)buf[i]); } } #define ID_SIZE 8 #define ACL_RD 0x1 #define ACL_WR 0x2 struct ACLID { char id[ID_SIZE + 1]; void encode(bufferlist& bl) const { bl.append((const char *)id, ID_SIZE); } void decode(bufferlist::iterator& iter) { iter.copy(ID_SIZE, (char *)id); } }; WRITE_CLASS_ENCODER(ACLID) typedef __u32 ACLFlags; inline bool operator<(const ACLID& l, const ACLID& r) { return (memcmp(&l, &r, ID_SIZE) > 0); } struct ACLPair { ACLID id; ACLFlags flags; }; class ObjectACLs { map acls_map; public: void encode(bufferlist& bl) const { ::encode(acls_map, bl); } void decode(bufferlist::iterator& bl) { ::decode(acls_map, bl); } int read_acl(ACLID& id, ACLFlags *flags); void set_acl(ACLID& id, ACLFlags flags); }; WRITE_CLASS_ENCODER(ObjectACLs) int ObjectACLs::read_acl(ACLID& id, ACLFlags *flags) { if (!flags) return -EINVAL; map::iterator iter = acls_map.find(id); if (iter == acls_map.end()) return -ENOENT; *flags = iter->second; return 0; } void ObjectACLs::set_acl(ACLID& id, ACLFlags flags) { acls_map[id] = flags; } class ACLEntity { string name; map groups; }; typedef map tACLIDEntityMap; static map users; static map groups; void get_user(ACLID& aclid, ACLEntity *entity) { //users.find(aclid); } int main(int argc, const char **argv) { Rados rados; if (rados.init(NULL) < 0) { cerr << "couldn't initialize rados!" << std::endl; exit(1); } if (rados.conf_read_file(NULL)) { cerr << "couldn't read Ceph configuration file!" << std::endl; exit(1); } if (rados.connect() < 0) { cerr << "couldn't connect to cluster!" << std::endl; exit(1); } time_t tm; bufferlist bl, bl2; char buf[128]; time(&tm); snprintf(buf, 128, "%s", ctime(&tm)); bl.append(buf, strlen(buf)); const char *oid = "bar"; IoCtx io_ctx; int r = rados.ioctx_create("data", io_ctx); cout << "open io_ctx result = " << r << " pool = " << io_ctx.get_pool_name() << std::endl; ACLID id; snprintf(id.id, ID_SIZE + 1, "%.16x", 0x1234); cout << "id=" << id.id << std::endl; r = io_ctx.exec(oid, "acl", "get", bl, bl2); cout << "exec returned " << r << " len=" << bl2.length() << std::endl; ObjectACLs oa; if (r >= 0) { bufferlist::iterator iter = bl2.begin(); oa.decode(iter); } oa.set_acl(id, ACL_RD); bl.clear(); oa.encode(bl); r = io_ctx.exec(oid, "acl", "set", bl, bl2); const unsigned char *md5 = (const unsigned char *)bl2.c_str(); char md5_str[bl2.length()*2 + 1]; buf_to_hex(md5, bl2.length(), md5_str); cout << "md5 result=" << md5_str << std::endl; int size = io_ctx.read(oid, bl2, 128, 0); cout << "read result=" << bl2.c_str() << std::endl; cout << "size=" << size << std::endl; #if 0 Rados::ListCtx ctx; int entries; do { list vec; r = rados.list(io_ctx, 2, vec, ctx); entries = vec.size(); cout << "list result=" << r << " entries=" << entries << std::endl; list::iterator iter; for (iter = vec.begin(); iter != vec.end(); ++iter) { cout << *iter << std::endl; } } while (entries); #endif #if 0 r = rados.remove(io_ctx, oid); cout << "remove result=" << r << std::endl; rados.close_io_ctx(io_ctx); #endif return 0; } ceph-0.80.11/src/tools/scratchtool.c0000664000175100017510000002064612623076744021325 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/rados/librados.h" #include #include #include #include #include #include static int do_rados_setxattr(rados_ioctx_t io_ctx, const char *oid, const char *key, const char *val) { int ret = rados_setxattr(io_ctx, oid, key, val, strlen(val) + 1); if (ret < 0) { printf("rados_setxattr failed with error %d\n", ret); return 1; } printf("rados_setxattr %s=%s\n", key, val); return 0; } static int do_rados_getxattr(rados_ioctx_t io_ctx, const char *oid, const char *key, const char *expected) { size_t blen = strlen(expected) + 1; char buf[blen]; memset(buf, 0, sizeof(buf)); int r = rados_getxattr(io_ctx, oid, key, buf, blen); if (r < 0) { printf("rados_getxattr(%s) failed with error %d\n", key, r); return 1; } if (strcmp(buf, expected) != 0) { printf("rados_getxattr(%s) got wrong result! " "expected: '%s'. got '%s'\n", key, expected, buf); return 1; } printf("rados_getxattr %s=%s\n", key, buf); return 0; } static int do_rados_getxattrs(rados_ioctx_t io_ctx, const char *oid, const char **exkeys, const char **exvals) { rados_xattrs_iter_t iter; int nval = 0, i, nfound = 0, ret = 0; for (i = 0; exvals[i]; ++i) { ++nval; } ret = rados_getxattrs(io_ctx, oid, &iter); if (ret) { printf("rados_getxattrs(%s) failed with error %d\n", oid, ret); return 1; } while (1) { size_t len; const char *key, *val; ret = rados_getxattrs_next(iter, &key, &val, &len); if (ret) { printf("rados_getxattrs(%s): rados_getxattrs_next " "returned error %d\n", oid, ret); return 1; } if (!key) break; for (i = 0; i < nval; ++i) { if (strcmp(exkeys[i], key)) continue; if ((len == strlen(exvals[i]) + 1) && (!strcmp(exvals[i], val))) { nfound++; break; } printf("rados_getxattrs(%s): got key %s, but the " "value was %s rather than %s.\n", oid, key, val, exvals[i]); return 1; } } if (nfound != nval) { printf("rados_getxattrs(%s): only found %d extended attributes. " "Expected %d\n", oid, nfound, nval); return 1; } rados_getxattrs_end(iter); printf("rados_getxattrs(%s)\n", oid); return 0; } static int testrados(void) { char tmp[32]; int i, r; int ret = 1; //set 1 as error case rados_t cl; if (rados_create(&cl, NULL) < 0) { printf("error initializing\n"); return 1; } if (rados_conf_read_file(cl, NULL)) { printf("error reading configuration file\n"); goto out_err; } // Try to set a configuration option that doesn't exist. // This should fail. if (!rados_conf_set(cl, "config option that doesn't exist", "some random value")) { printf("error: succeeded in setting nonexistent config option\n"); goto out_err; } if (rados_conf_get(cl, "log to stderr", tmp, sizeof(tmp))) { printf("error: failed to read log_to_stderr from config\n"); goto out_err; } // Can we change it? if (rados_conf_set(cl, "log to stderr", "true")) { printf("error: error setting log_to_stderr\n"); goto out_err; } if (rados_conf_get(cl, "log to stderr", tmp, sizeof(tmp))) { printf("error: failed to read log_to_stderr from config\n"); goto out_err; } if (strcmp(tmp, "true")) { printf("error: new setting for log_to_stderr failed to take effect.\n"); goto out_err; } if (rados_connect(cl)) { printf("error connecting\n"); goto out_err; } if (rados_connect(cl) == 0) { printf("second connect attempt didn't return an error\n"); goto out_err; } /* create an io_ctx */ r = rados_pool_create(cl, "foo"); printf("rados_pool_create = %d\n", r); rados_ioctx_t io_ctx; r = rados_ioctx_create(cl, "foo", &io_ctx); printf("rados_ioctx_create = %d, io_ctx = %p\n", r, io_ctx); /* list all pools */ { int buf_sz = rados_pool_list(cl, NULL, 0); printf("need buffer size of %d\n", buf_sz); char buf[buf_sz]; int r = rados_pool_list(cl, buf, buf_sz); if (r != buf_sz) { printf("buffer size mismatch: got %d the first time, but %d " "the second.\n", buf_sz, r); goto out_err; } const char *b = buf; printf("begin pools.\n"); while (1) { if (b[0] == '\0') break; printf(" pool: '%s'\n", b); b += strlen(b) + 1; }; printf("end pools.\n"); } /* stat */ struct rados_pool_stat_t st; r = rados_ioctx_pool_stat(io_ctx, &st); printf("rados_ioctx_pool_stat = %d, %lld KB, %lld objects\n", r, (long long)st.num_kb, (long long)st.num_objects); /* snapshots */ r = rados_ioctx_snap_create(io_ctx, "snap1"); printf("rados_ioctx_snap_create snap1 = %d\n", r); rados_snap_t snaps[10]; r = rados_ioctx_snap_list(io_ctx, snaps, 10); for (i=0; i #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global/global_init.h" #include "os/LevelDBStore.h" #include "mon/MonitorDBStore.h" #include "mon/Paxos.h" #include "common/Formatter.h" #include "include/stringify.h" #include "common/errno.h" namespace po = boost::program_options; using namespace std; class TraceIter { int fd; unsigned idx; MonitorDBStore::Transaction t; public: TraceIter(string fname) : fd(-1), idx(-1) { fd = ::open(fname.c_str(), O_RDONLY); } bool valid() { return fd != -1; } const MonitorDBStore::Transaction &cur() { assert(valid()); return t; } unsigned num() { return idx; } void next() { ++idx; bufferlist bl; int r = bl.read_fd(fd, 6); if (r < 0) { std::cerr << "Got error: " << cpp_strerror(r) << " on read_fd" << std::endl; ::close(fd); fd = -1; return; } else if ((unsigned)r < 6) { std::cerr << "short read" << std::endl; ::close(fd); fd = -1; return; } bufferlist::iterator bliter = bl.begin(); uint8_t ver, ver2; ::decode(ver, bliter); ::decode(ver2, bliter); uint32_t len; ::decode(len, bliter); r = bl.read_fd(fd, len); if (r < 0) { std::cerr << "Got error: " << cpp_strerror(r) << " on read_fd" << std::endl; ::close(fd); fd = -1; return; } else if ((unsigned)r < len) { std::cerr << "short read" << std::endl; ::close(fd); fd = -1; return; } bliter = bl.begin(); t.decode(bliter); } void init() { next(); } ~TraceIter() { if (fd != -1) { ::close(fd); fd = -1; } } }; int main(int argc, char **argv) { po::options_description desc("Allowed options"); int version = -1; string store_path, cmd, out_path, tfile; unsigned dstart = 0; unsigned dstop = ~0; unsigned num_replays = 1; unsigned tsize = 200; unsigned tvalsize = 1024; unsigned ntrans = 100; desc.add_options() ("help", "produce help message") ("mon-store-path", po::value(&store_path), "path to mon directory, mandatory") ("out", po::value(&out_path), "out path") ("version", po::value(&version), "version requested") ("trace-file", po::value(&tfile), "trace file") ("dump-start", po::value(&dstart), "transaction num to start dumping at") ("dump-end", po::value(&dstop), "transaction num to stop dumping at") ("num-replays", po::value(&num_replays), "number of times to replay") ("trans-size", po::value(&tsize), "keys to write in each transaction") ("trans-val-size", po::value(&tvalsize), "val to write in each key") ("num-trans", po::value(&ntrans), "number of transactions to run") ("command", po::value(&cmd), "command") ; po::positional_options_description p; p.add("command", 1); p.add("version", 1); po::variables_map vm; po::parsed_options parsed = po::command_line_parser(argc, argv).options(desc).positional(p).run(); po::store( parsed, vm); try { po::notify(vm); } catch (...) { cout << desc << std::endl; return 1; } vector ceph_options, def_args; vector ceph_option_strings = po::collect_unrecognized( parsed.options, po::include_positional); ceph_options.reserve(ceph_option_strings.size()); for (vector::iterator i = ceph_option_strings.begin(); i != ceph_option_strings.end(); ++i) { ceph_options.push_back(i->c_str()); } global_init( &def_args, ceph_options, CEPH_ENTITY_TYPE_MON, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); g_conf = g_ceph_context->_conf; if (vm.count("help")) { std::cerr << desc << std::endl; return 1; } int fd; if (vm.count("out")) { if ((fd = open(out_path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { int _err = errno; if (_err != EISDIR) { std::cerr << "Couldn't open " << out_path << ": " << cpp_strerror(_err) << std::endl; return 1; } } } else { fd = STDOUT_FILENO; } if (fd < 0 && cmd != "store-copy") { std::cerr << "error: '" << out_path << "' is a directory!" << std::endl; return 1; } MonitorDBStore st(store_path); if (store_path.size()) { stringstream ss; int r = st.open(ss); if (r < 0) { std::cerr << ss.str() << std::endl; goto done; } } if (cmd == "dump-keys") { KeyValueDB::WholeSpaceIterator iter = st.get_iterator(); while (iter->valid()) { pair key(iter->raw_key()); cout << key.first << " / " << key.second << std::endl; iter->next(); } } else if (cmd == "compact") { st.compact(); } else if (cmd == "getmonmap") { assert(fd >= 0); if (!store_path.size()) { std::cerr << "need mon store path" << std::endl; std::cerr << desc << std::endl; goto done; } version_t v; if (version <= 0) { v = st.get("monmap", "last_committed"); } else { v = version; } bufferlist bl; /// XXX: this is not ok, osdmap and full should be abstracted somewhere int r = st.get("monmap", v, bl); if (r < 0) { std::cerr << "Error getting map: " << cpp_strerror(r) << std::endl; goto done; } bl.write_fd(fd); } else if (cmd == "getosdmap") { if (!store_path.size()) { std::cerr << "need mon store path" << std::endl; std::cerr << desc << std::endl; goto done; } version_t v; if (version == -1) { v = st.get("osdmap", "last_committed"); } else { v = version; } bufferlist bl; /// XXX: this is not ok, osdmap and full should be abstracted somewhere int r = st.get("osdmap", st.combine_strings("full", v), bl); if (r < 0) { std::cerr << "Error getting map: " << cpp_strerror(r) << std::endl; goto done; } bl.write_fd(fd); } else if (cmd == "dump-paxos") { for (version_t v = dstart; v <= dstop; ++v) { bufferlist bl; st.get("paxos", v, bl); if (bl.length() == 0) break; cout << "\n--- " << v << " ---" << std::endl; MonitorDBStore::Transaction tx; Paxos::decode_append_transaction(tx, bl); JSONFormatter f(true); tx.dump(&f); f.flush(cout); } } else if (cmd == "dump-trace") { if (tfile.empty()) { std::cerr << "Need trace_file" << std::endl; std::cerr << desc << std::endl; goto done; } TraceIter iter(tfile.c_str()); iter.init(); while (true) { if (!iter.valid()) break; if (iter.num() >= dstop) { break; } if (iter.num() >= dstart) { JSONFormatter f(true); iter.cur().dump(&f, false); f.flush(std::cout); std::cout << std::endl; } iter.next(); } std::cerr << "Read up to transaction " << iter.num() << std::endl; } else if (cmd == "replay-trace") { if (!store_path.size()) { std::cerr << "need mon store path" << std::endl; std::cerr << desc << std::endl; goto done; } if (tfile.empty()) { std::cerr << "Need trace_file" << std::endl; std::cerr << desc << std::endl; goto done; } unsigned num = 0; for (unsigned i = 0; i < num_replays; ++i) { TraceIter iter(tfile.c_str()); iter.init(); while (true) { if (!iter.valid()) break; std::cerr << "Replaying trans num " << num << std::endl; st.apply_transaction(iter.cur()); iter.next(); ++num; } std::cerr << "Read up to transaction " << iter.num() << std::endl; } } else if (cmd == "random-gen") { if (!store_path.size()) { std::cerr << "need mon store path" << std::endl; std::cerr << desc << std::endl; goto done; } unsigned num = 0; for (unsigned i = 0; i < ntrans; ++i) { std::cerr << "Applying trans " << i << std::endl; MonitorDBStore::Transaction t; string prefix; prefix.push_back((i%26)+'a'); for (unsigned j = 0; j < tsize; ++j) { stringstream os; os << num; bufferlist bl; for (unsigned k = 0; k < tvalsize; ++k) bl.append(rand()); t.put(prefix, os.str(), bl); ++num; } t.compact_prefix(prefix); st.apply_transaction(t); } } else if (cmd == "store-copy") { if (!store_path.size()) { std::cerr << "need mon store path to copy from" << std::endl; std::cerr << desc << std::endl; goto done; } if (!out_path.size()) { std::cerr << "need mon store path to copy to (--out )" << std::endl; std::cerr << desc << std::endl; goto done; } if (fd > 0) { std::cerr << "supplied out path '" << out_path << "' is not a directory" << std::endl; goto done; } MonitorDBStore out_store(out_path); { stringstream ss; int r = out_store.create_and_open(ss); if (r < 0) { std::cerr << ss.str() << std::endl; goto done; } } KeyValueDB::WholeSpaceIterator it = st.get_iterator(); uint64_t total_keys = 0; uint64_t total_size = 0; uint64_t total_tx = 0; do { uint64_t num_keys = 0; MonitorDBStore::Transaction tx; while (it->valid() && num_keys < 128) { pair k = it->raw_key(); bufferlist v = it->value(); tx.put(k.first, k.second, v); num_keys ++; total_tx ++; total_size += v.length(); it->next(); } total_keys += num_keys; if (!tx.empty()) out_store.apply_transaction(tx); std::cout << "copied " << total_keys << " keys so far (" << stringify(si_t(total_size)) << ")" << std::endl; } while (it->valid()); std::cout << "summary: copied " << total_keys << " keys, using " << total_tx << " transactions, totalling " << stringify(si_t(total_size)) << std::endl; std::cout << "from '" << store_path << "' to '" << out_path << "'" << std::endl; } else { std::cerr << "Unrecognized command: " << cmd << std::endl; goto done; } done: if (vm.count("out") && fd > 0) { ::close(fd); } return 0; } ceph-0.80.11/src/tools/crushtool.cc0000664000175100017510000006221412623076744021162 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * Copyright (C) 2014 Cloudwatt * * Author: Loic Dachary * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "common/debug.h" #include "common/errno.h" #include "common/config.h" #include "common/ceph_argparse.h" #include "global/global_context.h" #include "global/global_init.h" #include "osd/OSDMap.h" #include "crush/CrushWrapper.h" #include "crush/CrushCompiler.h" #include "crush/CrushTester.h" #include "include/assert.h" #define dout_subsys ceph_subsys_crush using namespace std; const char *infn = "stdin"; //////////////////////////////////////////////////////////////////////////// void data_analysis_usage() { cout << "data output from testing routine ...\n"; cout << " absolute_weights\n"; cout << " the decimal weight of each OSD\n"; cout << " data layout: ROW MAJOR\n"; cout << " OSD id (int), weight (int)\n"; cout << " batch_device_expected_utilization_all\n"; cout << " the expected number of objects each OSD should receive per placement batch\n"; cout << " which may be a decimal value\n"; cout << " data layout: COLUMN MAJOR\n"; cout << " round (int), objects expected on OSD 0...OSD n (float)\n"; cout << " batch_device_utilization_all\n"; cout << " the number of objects stored on each OSD during each placement round\n"; cout << " data layout: COLUMN MAJOR\n"; cout << " round (int), objects stored on OSD 0...OSD n (int)\n"; cout << " device_utilization_all\n"; cout << " the number of objects stored on each OSD at the end of placements\n"; cout << " data_layout: ROW MAJOR\n"; cout << " OSD id (int), objects stored (int), objects expected (float)\n"; cout << " device_utilization\n"; cout << " the number of objects stored on each OSD marked 'up' at the end of placements\n"; cout << " data_layout: ROW MAJOR\n"; cout << " OSD id (int), objects stored (int), objects expected (float)\n"; cout << " placement_information\n"; cout << " the map of input -> OSD\n"; cout << " data_layout: ROW MAJOR\n"; cout << " input (int), OSD's mapped (int)\n"; cout << " proportional_weights_all\n"; cout << " the proportional weight of each OSD specified in the CRUSH map\n"; cout << " data_layout: ROW MAJOR\n"; cout << " OSD id (int), proportional weight (float)\n"; cout << " proportional_weights\n"; cout << " the proportional weight of each 'up' OSD specified in the CRUSH map\n"; cout << " data_layout: ROW MAJOR\n"; cout << " OSD id (int), proportional weight (float)\n"; } void usage() { cout << "usage: crushtool ...\n"; cout << " --decompile|-d map decompile a crush map to source\n"; cout << " --compile|-c map.txt compile a map from source\n"; cout << " [-o outfile [--clobber]]\n"; cout << " specify output for for (de)compilation\n"; cout << " --build --num_osds N layer1 ...\n"; cout << " build a new map, where each 'layer' is\n"; cout << " 'name (uniform|straw|list|tree) size'\n"; cout << " -i mapfn --test test a range of inputs on the map\n"; cout << " [--min-x x] [--max-x x] [--x x]\n"; cout << " [--min-rule r] [--max-rule r] [--rule r]\n"; cout << " [--num-rep n]\n"; cout << " [--batches b] split the CRUSH mapping into b > 1 rounds\n"; cout << " [--weight|-w devno weight]\n"; cout << " where weight is 0 to 1.0\n"; cout << " [--simulate] simulate placements using a random\n"; cout << " number generator in place of the CRUSH\n"; cout << " algorithm\n"; cout << " -i mapfn --add-item id weight name [--loc type name ...]\n"; cout << " insert an item into the hierarchy at the\n"; cout << " given location\n"; cout << " -i mapfn --update-item id weight name [--loc type name ...]\n"; cout << " insert or move an item into the hierarchy at the\n"; cout << " given location\n"; cout << " -i mapfn --remove-item name\n" << " remove the given item\n"; cout << " -i mapfn --reweight-item name weight\n"; cout << " reweight a given item (and adjust ancestor\n" << " weights as needed)\n"; cout << " -i mapfn --reweight recalculate all bucket weights\n"; cout << " --show-utilization show OSD usage\n"; cout << " --show utilization-all\n"; cout << " include zero weight items\n"; cout << " --show-statistics show chi squared statistics\n"; cout << " --show-mappings show mappings\n"; cout << " --show-bad-mappings show bad mappings\n"; cout << " --show-choose-tries show choose tries histogram\n"; cout << " --set-choose-local-tries N\n"; cout << " set choose local retries before re-descent\n"; cout << " --set-choose-local-fallback-tries N\n"; cout << " set choose local retries using fallback\n"; cout << " permutation before re-descent\n"; cout << " --set-choose-total-tries N\n"; cout << " set choose total descent attempts\n"; cout << " --set-chooseleaf-descend-once <0|1>\n"; cout << " set chooseleaf to (not) retry the recursive descent\n"; cout << " --set-chooseleaf-vary-r <0|1>\n"; cout << " set chooseleaf to (not) vary r based on parent\n"; cout << " --output-name name\n"; cout << " prepend the data file(s) generated during the\n"; cout << " testing routine with name\n"; cout << " --output-csv\n"; cout << " export select data generated during testing routine\n"; cout << " to CSV files for off-line post-processing\n"; cout << " use --help-output for more information\n"; } struct bucket_types_t { const char *name; int type; } bucket_types[] = { { "uniform", CRUSH_BUCKET_UNIFORM }, { "list", CRUSH_BUCKET_LIST }, { "straw", CRUSH_BUCKET_STRAW }, { "tree", CRUSH_BUCKET_TREE }, { 0, 0 }, }; struct layer_t { const char *name; const char *buckettype; int size; }; int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); const char *me = argv[0]; std::string infn, srcfn, outfn, add_name, remove_name, reweight_name; bool compile = false; bool decompile = false; bool test = false; bool display = false; bool write_to_file = false; int verbose = 0; bool unsafe_tunables = false; bool reweight = false; int add_item = -1; bool update_item = false; float add_weight = 0; map add_loc; float reweight_weight = 0; bool adjust = false; int build = 0; int num_osds =0; vector layers; int choose_local_tries = -1; int choose_local_fallback_tries = -1; int choose_total_tries = -1; int chooseleaf_descend_once = -1; int chooseleaf_vary_r = -1; int straw_calc_version = -1; CrushWrapper crush; CrushTester tester(crush, cerr); // we use -c, don't confuse the generic arg parsing // only parse arguments from CEPH_ARGS, if in the environment vector env_args; env_to_vec(env_args); global_init(NULL, env_args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); int x; float y; std::string val; std::ostringstream err; int tmp; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); exit(0); } else if (ceph_argparse_witharg(args, i, &val, "-d", "--decompile", (char*)NULL)) { infn = val; decompile = true; } else if (ceph_argparse_witharg(args, i, &val, "-i", "--infn", (char*)NULL)) { infn = val; } else if (ceph_argparse_witharg(args, i, &val, "-o", "--outfn", (char*)NULL)) { outfn = val; } else if (ceph_argparse_flag(args, i, "-v", "--verbose", (char*)NULL)) { verbose += 1; } else if (ceph_argparse_flag(args, i, "--show_utilization", (char*)NULL)) { display = true; tester.set_output_utilization(true); } else if (ceph_argparse_flag(args, i, "--show_utilization_all", (char*)NULL)) { display = true; tester.set_output_utilization_all(true); } else if (ceph_argparse_flag(args, i, "--show_statistics", (char*)NULL)) { display = true; tester.set_output_statistics(true); } else if (ceph_argparse_flag(args, i, "--show_mappings", (char*)NULL)) { display = true; tester.set_output_mappings(true); } else if (ceph_argparse_flag(args, i, "--show_bad_mappings", (char*)NULL)) { display = true; tester.set_output_bad_mappings(true); } else if (ceph_argparse_flag(args, i, "--show_choose_tries", (char*)NULL)) { display = true; tester.set_output_choose_tries(true); } else if (ceph_argparse_witharg(args, i, &val, "-c", "--compile", (char*)NULL)) { srcfn = val; compile = true; } else if (ceph_argparse_flag(args, i, "-t", "--test", (char*)NULL)) { test = true; } else if (ceph_argparse_flag(args, i, "-s", "--simulate", (char*)NULL)) { tester.set_random_placement(); } else if (ceph_argparse_flag(args, i, "--enable-unsafe-tunables", (char*)NULL)) { unsafe_tunables = true; } else if (ceph_argparse_withint(args, i, &choose_local_tries, &err, "--set_choose_local_tries", (char*)NULL)) { adjust = true; } else if (ceph_argparse_withint(args, i, &choose_local_fallback_tries, &err, "--set_choose_local_fallback_tries", (char*)NULL)) { adjust = true; } else if (ceph_argparse_withint(args, i, &choose_total_tries, &err, "--set_choose_total_tries", (char*)NULL)) { adjust = true; } else if (ceph_argparse_withint(args, i, &chooseleaf_descend_once, &err, "--set_chooseleaf_descend_once", (char*)NULL)) { adjust = true; } else if (ceph_argparse_withint(args, i, &chooseleaf_vary_r, &err, "--set_chooseleaf_vary_r", (char*)NULL)) { adjust = true; } else if (ceph_argparse_withint(args, i, &straw_calc_version, &err, "--set_straw_calc_version", (char*)NULL)) { adjust = true; } else if (ceph_argparse_flag(args, i, "--reweight", (char*)NULL)) { reweight = true; } else if (ceph_argparse_withint(args, i, &add_item, &err, "--add_item", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } if (i == args.end()) { cerr << "expecting additional argument to --add-item" << std::endl; exit(EXIT_FAILURE); } add_weight = atof(*i); i = args.erase(i); if (i == args.end()) { cerr << "expecting additional argument to --add-item" << std::endl; exit(EXIT_FAILURE); } add_name.assign(*i); i = args.erase(i); } else if (ceph_argparse_withint(args, i, &add_item, &err, "--update_item", (char*)NULL)) { update_item = true; if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } if (i == args.end()) { cerr << "expecting additional argument to --update-item" << std::endl; exit(EXIT_FAILURE); } add_weight = atof(*i); i = args.erase(i); if (i == args.end()) { cerr << "expecting additional argument to --update-item" << std::endl; exit(EXIT_FAILURE); } add_name.assign(*i); i = args.erase(i); } else if (ceph_argparse_witharg(args, i, &val, "--loc", (char*)NULL)) { std::string type(val); if (i == args.end()) { cerr << "expecting additional argument to --loc" << std::endl; exit(EXIT_FAILURE); } std::string name(*i); i = args.erase(i); add_loc[type] = name; } else if (ceph_argparse_flag(args, i, "--output-csv", (char*)NULL)) { write_to_file = true; tester.set_output_data_file(true); tester.set_output_csv(true); } else if (ceph_argparse_flag(args, i, "--help-output", (char*)NULL)) { data_analysis_usage(); exit(0); } else if (ceph_argparse_witharg(args, i, &val, "--output-name", (char*)NULL)) { std::string name(val); if (i == args.end()) { cerr << "expecting additional argument to --output-name" << std::endl; exit(EXIT_FAILURE); } else { tester.set_output_data_file_name(name + "-"); } } else if (ceph_argparse_witharg(args, i, &val, "--remove_item", (char*)NULL)) { remove_name = val; } else if (ceph_argparse_witharg(args, i, &val, "--reweight_item", (char*)NULL)) { reweight_name = val; if (i == args.end()) { cerr << "expecting additional argument to --reweight-item" << std::endl; exit(EXIT_FAILURE); } reweight_weight = atof(*i); i = args.erase(i); } else if (ceph_argparse_flag(args, i, "--build", (char*)NULL)) { build = true; } else if (ceph_argparse_withint(args, i, &num_osds, &err, "--num_osds", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } } else if (ceph_argparse_withint(args, i, &x, &err, "--num_rep", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_num_rep(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--max_x", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_max_x(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--min_x", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_min_x(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--x", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_x(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--max_rule", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_max_rule(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--min_rule", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_min_rule(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--rule", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_rule(x); } else if (ceph_argparse_withint(args, i, &x, &err, "--batches", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_batches(x); } else if (ceph_argparse_withfloat(args, i, &y, &err, "--mark-down-ratio", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_device_down_ratio(y); } else if (ceph_argparse_withfloat(args, i, &y, &err, "--mark-down-bucket-ratio", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } tester.set_bucket_down_ratio(y); } else if (ceph_argparse_withint(args, i, &tmp, &err, "--weight", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } int dev = tmp; if (i == args.end()) { cerr << "expecting additional argument to --weight" << std::endl; exit(EXIT_FAILURE); } float f = atof(*i); i = args.erase(i); tester.set_device_weight(dev, f); } else { ++i; } } if (test && !display && !write_to_file) { cerr << "WARNING: no output selected; use --output-csv or --show-X" << std::endl; exit(EXIT_FAILURE); } if (decompile + compile + build > 1) { cout << "cannot specify more than one of compile, decompile, and build" << std::endl; exit(EXIT_FAILURE); } if (!compile && !decompile && !build && !test && !reweight && !adjust && add_item < 0 && remove_name.empty() && reweight_name.empty()) { cout << "no action specified; -h for help" << std::endl; exit(EXIT_FAILURE); } if ((!build) && (!args.empty())) { cerr << "unrecognized arguments: " << args << std::endl; exit(EXIT_FAILURE); } else { if ((args.size() % 3) != 0U) { cerr << "remaining args: " << args << std::endl; cerr << "layers must be specified with 3-tuples of (name, buckettype, size)" << std::endl; exit(EXIT_FAILURE); } for (size_t j = 0; j < args.size(); j += 3) { layer_t l; l.name = args[j]; l.buckettype = args[j+1]; l.size = atoi(args[j+2]); layers.push_back(l); } } /* if (outfn) cout << "outfn " << outfn << std::endl; if (cinfn) cout << "cinfn " << cinfn << std::endl; if (dinfn) cout << "dinfn " << dinfn << std::endl; */ bool modified = false; if (!infn.empty()) { bufferlist bl; std::string error; int r = bl.read_file(infn.c_str(), &error); if (r < 0) { cerr << me << ": error reading '" << infn << "': " << error << std::endl; exit(1); } bufferlist::iterator p = bl.begin(); crush.decode(p); } if (decompile) { CrushCompiler cc(crush, cerr, verbose); if (!outfn.empty()) { ofstream o; o.open(outfn.c_str(), ios::out | ios::binary | ios::trunc); if (!o.is_open()) { cerr << me << ": error writing '" << outfn << "'" << std::endl; exit(1); } cc.decompile(o); o.close(); } else { cc.decompile(cout); } } if (compile) { crush.create(); // read the file ifstream in(srcfn.c_str()); if (!in.is_open()) { cerr << "input file " << srcfn << " not found" << std::endl; return -ENOENT; } CrushCompiler cc(crush, cerr, verbose); if (unsafe_tunables) cc.enable_unsafe_tunables(); int r = cc.compile(in, srcfn.c_str()); if (r < 0) exit(1); modified = true; } if (build) { if (layers.empty()) { cerr << me << ": must specify at least one layer" << std::endl; exit(1); } crush.create(); vector lower_items; vector lower_weights; for (int i=0; i::iterator p = layers.begin(); p != layers.end(); ++p, type++) { layer_t &l = *p; dout(2) << "layer " << type << " " << l.name << " bucket type " << l.buckettype << " " << l.size << dendl; crush.set_type_name(type, l.name); int buckettype = -1; for (int i = 0; bucket_types[i].name; i++) if (l.buckettype && strcmp(l.buckettype, bucket_types[i].name) == 0) { buckettype = bucket_types[i].type; break; } if (buckettype < 0) { cerr << "unknown bucket type '" << l.buckettype << "'" << std::endl << std::endl; exit(EXIT_FAILURE); } // build items vector cur_items; vector cur_weights; unsigned lower_pos = 0; // lower pos dout(2) << "lower_items " << lower_items << dendl; dout(2) << "lower_weights " << lower_weights << dendl; int i = 0; while (1) { if (lower_pos == lower_items.size()) break; int items[num_osds]; int weights[num_osds]; int weight = 0; int j; for (j=0; j weights(crush.get_max_devices(), 0x10000); crush.dump_tree(weights, &oss, NULL); dout(1) << "\n" << oss.str() << dendl; } string root = layers.back().size == 0 ? layers.back().name : string(layers.back().name) + "0"; { set roots; crush.find_roots(roots); if (roots.size() > 1) dout(1) << "The crush rulesets will use the root " << root << "\n" << "and ignore the others.\n" << "There are " << roots.size() << " roots, they can be\n" << "grouped into a single root by appending something like:\n" << " root straw 0\n" << dendl; } if (OSDMap::build_simple_crush_rulesets(g_ceph_context, crush, root, &cerr)) exit(EXIT_FAILURE); modified = true; } if (!reweight_name.empty()) { cout << me << " reweighting item " << reweight_name << " to " << reweight_weight << std::endl; int r; if (!crush.name_exists(reweight_name)) { cerr << " name " << reweight_name << " dne" << std::endl; r = -ENOENT; } else { int item = crush.get_item_id(reweight_name); r = crush.adjust_item_weightf(g_ceph_context, item, reweight_weight); } if (r >= 0) modified = true; else { cerr << me << " " << cpp_strerror(r) << std::endl; return r; } } if (!remove_name.empty()) { cout << me << " removing item " << remove_name << std::endl; int r; if (!crush.name_exists(remove_name)) { cerr << " name " << remove_name << " dne" << std::endl; r = -ENOENT; } else { int remove_item = crush.get_item_id(remove_name); r = crush.remove_item(g_ceph_context, remove_item, false); } if (r == 0) modified = true; else { cerr << me << " " << cpp_strerror(r) << std::endl; return r; } } if (add_item >= 0) { int r; if (update_item) { r = crush.update_item(g_ceph_context, add_item, add_weight, add_name.c_str(), add_loc); } else { r = crush.insert_item(g_ceph_context, add_item, add_weight, add_name.c_str(), add_loc); } if (r >= 0) { modified = true; } else { cerr << me << " " << cpp_strerror(r) << std::endl; return r; } } if (reweight) { crush.reweight(g_ceph_context); modified = true; } if (choose_local_tries >= 0) { crush.set_choose_local_tries(choose_local_tries); modified = true; } if (choose_local_fallback_tries >= 0) { crush.set_choose_local_fallback_tries(choose_local_fallback_tries); modified = true; } if (choose_total_tries >= 0) { crush.set_choose_total_tries(choose_total_tries); modified = true; } if (chooseleaf_descend_once >= 0) { crush.set_chooseleaf_descend_once(chooseleaf_descend_once); modified = true; } if (chooseleaf_vary_r >= 0) { crush.set_chooseleaf_vary_r(chooseleaf_vary_r); modified = true; } if (straw_calc_version >= 0) { crush.set_straw_calc_version(straw_calc_version); modified = true; } if (modified) { crush.finalize(); if (outfn.empty()) { cout << me << " successfully built or modified map. Use '-o ' to write it out." << std::endl; } else { bufferlist bl; crush.encode(bl); int r = bl.write_file(outfn.c_str()); if (r < 0) { cerr << me << ": error writing '" << outfn << "': " << cpp_strerror(r) << std::endl; exit(1); } if (verbose) cout << "wrote crush map to " << outfn << std::endl; } } if (test) { if (tester.get_output_utilization_all() || tester.get_output_utilization()) tester.set_output_statistics(true); int r = tester.test(); if (r < 0) exit(1); } return 0; } /* * Local Variables: * compile-command: "cd .. ; make crushtool && test/run-cli-tests" * End: */ ceph-0.80.11/src/tools/ceph_conf.cc0000664000175100017510000001606612623076744021070 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2010 Dreamhost * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "mon/AuthMonitor.h" #include "common/ConfUtils.h" #include "global/global_init.h" #include "common/entity_name.h" #include "common/ceph_argparse.h" #include "common/config.h" #include "include/str_list.h" using std::deque; using std::string; static void usage() { // TODO: add generic_usage once cerr/derr issues are resolved cerr << "Ceph configuration query tool\n\ \n\ USAGE\n\ ceph-conf \n\ \n\ ACTIONS\n\ -L|--list-all-sections List all sections\n\ -l|--list-sections List sections with the given prefix\n\ --filter-key Filter section list to only include sections\n\ with given key defined.\n\ --filter-key-value = Filter section list to only include sections\n\ with given key/value pair.\n\ --lookup Print a configuration setting to stdout.\n\ Returns 0 (success) if the configuration setting is\n\ found; 1 otherwise.\n\ -r|--resolve-search search for the first file that exists and\n\ can be opened in the resulted comma\n\ delimited search list.\n\ \n\ FLAGS\n\ --name name Set type.id\n\ [-s
] Add to list of sections to search\n\ \n\ If there is no action given, the action will default to --lookup.\n\ \n\ EXAMPLES\n\ $ ceph-conf --name mon.0 -c /etc/ceph/ceph.conf 'mon addr'\n\ Find out what the value of 'mon add' is for monitor 0.\n\ \n\ $ ceph-conf -l mon\n\ List sections beginning with 'mon'.\n\ \n\ RETURN CODE\n\ Return code will be 0 on success; error code otherwise.\n\ "; exit(1); } static int list_sections(const std::string &prefix, const std::list& filter_key, const std::map& filter_key_value) { std::vector sections; int ret = g_conf->get_all_sections(sections); if (ret) return 2; for (std::vector::const_iterator p = sections.begin(); p != sections.end(); ++p) { if (strncmp(prefix.c_str(), p->c_str(), prefix.size())) continue; std::vector sec; sec.push_back(*p); int r = 0; for (std::list::const_iterator q = filter_key.begin(); q != filter_key.end(); ++q) { string v; r = g_conf->get_val_from_conf_file(sec, q->c_str(), v, false); if (r < 0) break; } if (r < 0) continue; for (std::map::const_iterator q = filter_key_value.begin(); q != filter_key_value.end(); ++q) { string v; r = g_conf->get_val_from_conf_file(sec, q->first.c_str(), v, false); if (r < 0 || v != q->second) { r = -1; break; } } if (r < 0) continue; cout << *p << std::endl; } return 0; } static int lookup(const std::deque §ions, const std::string &key, bool resolve_search) { std::vector my_sections; for (deque::const_iterator s = sections.begin(); s != sections.end(); ++s) { my_sections.push_back(*s); } g_conf->get_my_sections(my_sections); std::string val; int ret = g_conf->get_val_from_conf_file(my_sections, key.c_str(), val, true); if (ret == -ENOENT) return 1; else if (ret == 0) { if (resolve_search) { string result; if (ceph_resolve_file_search(val, result)) puts(result.c_str()); } else { puts(val.c_str()); } return 0; } else { cerr << "error looking up '" << key << "': error " << ret << std::endl; return 2; } } int main(int argc, const char **argv) { vector args; deque sections; bool resolve_search = false; std::string action; std::string lookup_key; std::string section_list_prefix; std::list filter_key; std::map filter_key_value; argv_to_vec(argc, argv, args); env_to_vec(args); vector orig_args = args; global_pre_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_DAEMON, CINIT_FLAG_NO_DAEMON_ACTIONS); // do not common_init_finish(); do not start threads; do not do any of thing // wonky things the daemon whose conf we are examining would do (like initialize // the admin socket). //common_init_finish(g_ceph_context); std::string val; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_witharg(args, i, &val, "-s", "--section", (char*)NULL)) { sections.push_back(val); } else if (ceph_argparse_flag(args, i, "-r", "--resolve_search", (char*)NULL)) { resolve_search = true; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { action = "help"; } else if (ceph_argparse_witharg(args, i, &val, "--lookup", (char*)NULL)) { action = "lookup"; lookup_key = val; } else if (ceph_argparse_flag(args, i, "-L", "--list_all_sections", (char*)NULL)) { action = "list-sections"; section_list_prefix = ""; } else if (ceph_argparse_witharg(args, i, &val, "-l", "--list_sections", (char*)NULL)) { action = "list-sections"; section_list_prefix = val; } else if (ceph_argparse_witharg(args, i, &val, "--filter_key", (char*)NULL)) { filter_key.push_back(val); } else if (ceph_argparse_witharg(args, i, &val, "--filter_key_value", (char*)NULL)) { size_t pos = val.find_first_of('='); if (pos == string::npos) { cerr << "expecting argument like 'key=value' for --filter-key-value (not '" << val << "')" << std::endl; usage(); exit(1); } string key(val, 0, pos); string value(val, pos+1); filter_key_value[key] = value; } else { if (((action == "lookup") || (action == "")) && (lookup_key.empty())) { action = "lookup"; lookup_key = *i++; } else { cerr << "unable to parse option: '" << *i << "'" << std::endl; cerr << "args:"; for (std::vector::iterator ci = orig_args.begin(); ci != orig_args.end(); ++ci) { cerr << " '" << *ci << "'"; } cerr << std::endl; usage(); exit(1); } } } if (action == "help") { usage(); exit(0); } else if (action == "list-sections") { return list_sections(section_list_prefix, filter_key, filter_key_value); } else if (action == "lookup") { return lookup(sections, lookup_key, resolve_search); } else { cerr << "You must give an action, such as --lookup or --list-all-sections." << std::endl; cerr << "Pass --help for more help." << std::endl; exit(1); } } ceph-0.80.11/src/tools/ceph-client-debug.cc0000664000175100017510000001042312623076744022412 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/Formatter.h" #include "common/debug.h" #include "common/errno.h" #include "client/Inode.h" #include "client/Dentry.h" #include "client/Dir.h" #include "include/cephfs/libcephfs.h" #define dout_subsys ceph_subsys_client void usage() { std::cout << "Usage: ceph-client-debug [options] " << std::endl; generic_client_usage(); } /** * Given an inode, look up the path from the Client cache: assumes * client cache is fully populated. */ void traverse_dentries(Inode *ino, std::vector &parts) { if (ino->dn_set.empty()) { return; } Dentry* dn = *(ino->dn_set.begin()); parts.push_back(dn); traverse_dentries(dn->dir->parent_inode, parts); } /** * Given an inode, send lookup requests to the MDS for * all its ancestors, such that the full trace will be * populated in client cache. */ int lookup_trace(ceph_mount_info *client, inodeno_t const ino) { Inode *inode; int r = ceph_ll_lookup_inode(client, ino, &inode); if (r != 0) { return r; } else { if (!inode->dn_set.empty()) { Dentry *dn = *(inode->dn_set.begin()); assert(dn->dir); assert(dn->dir->parent_inode); r = lookup_trace(client, dn->dir->parent_inode->ino); if (r) { return r; } } else { // We reached the root of the tree assert(inode->ino == CEPH_INO_ROOT); } } return r; } int main(int argc, const char **argv) { // Argument handling vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS); common_init_finish(g_ceph_context); // Expect exactly one positional argument (inode number) if (args.size() != 1) { usage(); } char const *inode_str = args[0]; inodeno_t inode = strtoll(inode_str, NULL, 0); if (inode <= 0) { derr << "Invalid inode: " << inode_str << dendl; return -1; } // Initialize filesystem client struct ceph_mount_info *client; int r = ceph_create_with_context(&client, g_ceph_context); if (r) { derr << "Error initializing libcephfs: " << cpp_strerror(r) << dendl; return r; } r = ceph_mount(client, "/"); if (r) { derr << "Error mounting: " << cpp_strerror(r) << dendl; ceph_shutdown(client); return r; } // Populate client cache with inode of interest & ancestors r = lookup_trace(client, inode); if (r) { derr << "Error looking up inode " << std::hex << inode << std::dec << ": " << cpp_strerror(r) << dendl; return -1; } // Retrieve inode of interest struct vinodeno_t vinode; vinode.ino = inode; vinode.snapid = CEPH_NOSNAP; Inode *ino = ceph_ll_get_inode(client, vinode); // Retrieve dentry trace std::vector path; traverse_dentries(ino, path); // Print inode and path as a JSON object JSONFormatter jf(true); jf.open_object_section("client_debug"); { jf.open_object_section("inode"); { ino->dump(&jf); } jf.close_section(); // inode jf.open_array_section("path"); { for (std::vector::reverse_iterator p = path.rbegin(); p != path.rend(); ++p) { jf.open_object_section("dentry"); { (*p)->dump(&jf); } jf.close_section(); // dentry } } jf.close_section(); // path } jf.close_section(); // client_debug jf.flush(std::cout); std::cout << std::endl; // Release Inode references ceph_ll_forget(client, ino, 1); for (std::vector::reverse_iterator p = path.rbegin(); p != path.rend(); ++p) { ceph_ll_forget(client, (*p)->inode, 1); } ino = NULL; path.clear(); // Shut down r = ceph_unmount(client); if (r) { derr << "Error mounting: " << cpp_strerror(r) << dendl; } ceph_shutdown(client); return r; } ceph-0.80.11/src/tools/ceph_kvstore_tool.cc0000664000175100017510000002503412623076744022670 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include "os/LevelDBStore.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/errno.h" #include "common/safe_io.h" #include "common/config.h" #include "common/strtol.h" #include "include/stringify.h" using namespace std; class StoreTool { boost::scoped_ptr db; string store_path; public: StoreTool(const string &path) : store_path(path) { LevelDBStore *db_ptr = new LevelDBStore(g_ceph_context, store_path); assert(!db_ptr->open(std::cerr)); db.reset(db_ptr); } uint32_t traverse(const string &prefix, const bool do_crc, ostream *out) { KeyValueDB::WholeSpaceIterator iter = db->get_iterator(); if (prefix.empty()) iter->seek_to_first(); else iter->seek_to_first(prefix); uint32_t crc = -1; while (iter->valid()) { pair rk = iter->raw_key(); if (!prefix.empty() && (rk.first != prefix)) break; if (out) *out << rk.first << ":" << rk.second; if (do_crc) { bufferlist bl; bl.append(rk.first); bl.append(rk.second); bl.append(iter->value()); crc = bl.crc32c(crc); if (out) { *out << " (" << bl.crc32c(0) << ")"; } } if (out) *out << std::endl; iter->next(); } return crc; } void list(const string &prefix, const bool do_crc) { traverse(prefix, do_crc, &std::cout); } bool exists(const string &prefix) { assert(!prefix.empty()); KeyValueDB::WholeSpaceIterator iter = db->get_iterator(); iter->seek_to_first(prefix); return (iter->valid() && (iter->raw_key().first == prefix)); } bool exists(const string &prefix, const string &key) { assert(!prefix.empty()); if (key.empty()) { return exists(prefix); } bool exists = false; get(prefix, key, exists); return exists; } bufferlist get(const string &prefix, const string &key, bool &exists) { assert(!prefix.empty() && !key.empty()); map result; std::set keys; keys.insert(key); db->get(prefix, keys, &result); if (result.count(key) > 0) { exists = true; return result[key]; } exists = false; return bufferlist(); } uint64_t get_size() { map extras; uint64_t s = db->get_estimated_size(extras); for (map::iterator p = extras.begin(); p != extras.end(); ++p) { std::cout << p->first << " - " << p->second << std::endl; } std::cout << "total: " << s << std::endl; return s; } bool set(const string &prefix, const string &key, bufferlist &val) { assert(!prefix.empty()); assert(!key.empty()); assert(val.length() > 0); KeyValueDB::Transaction tx = db->get_transaction(); tx->set(prefix, key, val); int ret = db->submit_transaction_sync(tx); return (ret == 0); } int copy_store_to(const string &other_path, const int num_keys_per_tx) { if (num_keys_per_tx <= 0) { std::cerr << "must specify a number of keys/tx > 0" << std::endl; return -EINVAL; } // open or create a leveldb store at @p other_path LevelDBStore other(g_ceph_context, other_path); int err = other.create_and_open(std::cerr); if (err < 0) return err; KeyValueDB::WholeSpaceIterator it = db->get_iterator(); it->seek_to_first(); uint64_t total_keys = 0; uint64_t total_size = 0; uint64_t total_txs = 0; utime_t started_at = ceph_clock_now(g_ceph_context); do { int num_keys = 0; KeyValueDB::Transaction tx = other.get_transaction(); while (it->valid() && num_keys < num_keys_per_tx) { pair k = it->raw_key(); bufferlist v = it->value(); tx->set(k.first, k.second, v); num_keys ++; total_size += v.length(); it->next(); } total_txs ++; total_keys += num_keys; if (num_keys > 0) other.submit_transaction_sync(tx); utime_t cur_duration = ceph_clock_now(g_ceph_context) - started_at; std::cout << "ts = " << cur_duration << "s, copied " << total_keys << " keys so far (" << stringify(si_t(total_size)) << ")" << std::endl; } while (it->valid()); utime_t time_taken = ceph_clock_now(g_ceph_context) - started_at; std::cout << "summary:" << std::endl; std::cout << " copied " << total_keys << " keys" << std::endl; std::cout << " used " << total_txs << " transactions" << std::endl; std::cout << " total size " << stringify(si_t(total_size)) << std::endl; std::cout << " from '" << store_path << "' to '" << other_path << "'" << std::endl; std::cout << " duration " << time_taken << " seconds" << std::endl; return 0; } }; void usage(const char *pname) { std::cerr << "Usage: " << pname << " command [args...]\n" << "\n" << "Commands:\n" << " list [prefix]\n" << " list-crc [prefix]\n" << " exists [key]\n" << " get [out ]\n" << " crc \n" << " get-size [ ]\n" << " set [ver |in ]\n" << " store-copy [num-keys-per-tx]\n" << " store-crc \n" << std::endl; } int main(int argc, const char *argv[]) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init( NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); if (args.size() < 2) { usage(argv[0]); return 1; } string path(args[0]); string cmd(args[1]); StoreTool st(path); if (cmd == "list" || cmd == "list-crc") { string prefix; if (argc > 3) prefix = argv[3]; bool do_crc = (cmd == "list-crc"); st.list(prefix, do_crc); } else if (cmd == "exists") { string key; if (argc < 4) { usage(argv[0]); return 1; } string prefix(argv[3]); if (argc > 4) key = argv[4]; bool ret = st.exists(prefix, key); std::cout << "(" << prefix << ", " << key << ") " << (ret ? "exists" : "does not exist") << std::endl; return (ret ? 0 : 1); } else if (cmd == "get") { if (argc < 5) { usage(argv[0]); return 1; } string prefix(argv[3]); string key(argv[4]); bool exists = false; bufferlist bl = st.get(prefix, key, exists); std::cout << "(" << prefix << ", " << key << ")"; if (!exists) { std::cout << " does not exist" << std::endl; return 1; } std::cout << std::endl; if (argc >= 6) { string subcmd(argv[5]); string out(argv[6]); if (subcmd != "out") { std::cerr << "unrecognized subcmd '" << subcmd << "'" << std::endl; return 1; } if (out.empty()) { std::cerr << "unspecified out file" << std::endl; return 1; } int err = bl.write_file(argv[6], 0644); if (err < 0) { std::cerr << "error writing value to '" << out << "': " << cpp_strerror(err) << std::endl; return 1; } } else { ostringstream os; bl.hexdump(os); std::cout << os.str() << std::endl; } } else if (cmd == "crc") { if (argc < 5) { usage(argv[0]); return 1; } string prefix(argv[3]); string key(argv[4]); bool exists = false; bufferlist bl = st.get(prefix, key, exists); std::cout << "(" << prefix << ", " << key << ") "; if (!exists) { std::cout << " does not exist" << std::endl; return 1; } std::cout << " crc " << bl.crc32c(0) << std::endl; } else if (cmd == "get-size") { std::cout << "estimated store size: " << st.get_size() << std::endl; if (argc < 4) return 0; if (argc < 5) { usage(argv[0]); return 1; } string prefix(argv[3]); string key(argv[4]); bool exists = false; bufferlist bl = st.get(prefix, key, exists); if (!exists) { std::cerr << "(" << prefix << "," << key << ") does not exist" << std::endl; return 1; } std::cout << "(" << prefix << "," << key << ") size " << si_t(bl.length()) << std::endl; } else if (cmd == "set") { if (argc < 7) { usage(argv[0]); return 1; } string prefix(argv[3]); string key(argv[4]); string subcmd(argv[5]); bufferlist val; string errstr; if (subcmd == "ver") { version_t v = (version_t) strict_strtoll(argv[6], 10, &errstr); if (!errstr.empty()) { std::cerr << "error reading version: " << errstr << std::endl; return 1; } ::encode(v, val); } else if (subcmd == "in") { int ret = val.read_file(argv[6], &errstr); if (ret < 0 || !errstr.empty()) { std::cerr << "error reading file: " << errstr << std::endl; return 1; } } else { std::cerr << "unrecognized subcommand '" << subcmd << "'" << std::endl; usage(argv[0]); return 1; } bool ret = st.set(prefix, key, val); if (!ret) { std::cerr << "error setting (" << prefix << "," << key << ")" << std::endl; return 1; } } else if (cmd == "store-copy") { int num_keys_per_tx = 128; // magic number that just feels right. if (argc < 4) { usage(argv[0]); return 1; } else if (argc > 4) { string err; num_keys_per_tx = strict_strtol(argv[4], 10, &err); if (!err.empty()) { std::cerr << "invalid num_keys_per_tx: " << err << std::endl; return 1; } } int ret = st.copy_store_to(argv[3], num_keys_per_tx); if (ret < 0) { std::cerr << "error copying store to path '" << argv[3] << "': " << cpp_strerror(ret) << std::endl; return 1; } } else if (cmd == "store-crc") { uint32_t crc = st.traverse(string(), true, NULL); std::cout << "store at '" << path << "' crc " << crc << std::endl; } else { std::cerr << "Unrecognized command: " << cmd << std::endl; return 1; } return 0; } ceph-0.80.11/src/tools/monmaptool.cc0000664000175100017510000001315012623076744021320 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include using namespace std; #include "common/config.h" #include "common/ceph_argparse.h" #include "common/errno.h" #include "global/global_init.h" #include "mon/MonMap.h" #include "include/str_list.h" void usage() { cout << " usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] " << std::endl; exit(1); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); const char *me = argv[0]; std::string fn; bool print = false; bool create = false; bool clobber = false; bool modified = false; bool generate = false; bool filter = false; map add; list rm; global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); std::string val; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); } else if (ceph_argparse_flag(args, i, "-p", "--print", (char*)NULL)) { print = true; } else if (ceph_argparse_flag(args, i, "--create", (char*)NULL)) { create = true; } else if (ceph_argparse_flag(args, i, "--clobber", (char*)NULL)) { clobber = true; } else if (ceph_argparse_flag(args, i, "--generate", (char*)NULL)) { generate = true; } else if (ceph_argparse_flag(args, i, "--set-initial-members", (char*)NULL)) { filter = true; } else if (ceph_argparse_flag(args, i, "--add", (char*)NULL)) { string name = *i; i = args.erase(i); if (i == args.end()) usage(); entity_addr_t addr; if (!addr.parse(*i)) { cerr << me << ": invalid ip:port '" << *i << "'" << std::endl; return -1; } if (addr.get_port() == 0) addr.set_port(CEPH_MON_PORT); add[name] = addr; modified = true; i = args.erase(i); } else if (ceph_argparse_witharg(args, i, &val, "--rm", (char*)NULL)) { rm.push_back(val); modified = true; } else { ++i; } } if (args.empty()) { cerr << me << ": must specify monmap filename" << std::endl; usage(); } else if (args.size() > 1) { cerr << me << ": too many arguments" << std::endl; usage(); } fn = args[0]; MonMap monmap; cout << me << ": monmap file " << fn << std::endl; int r = 0; if (!(create && clobber)) { try { r = monmap.read(fn.c_str()); } catch (...) { cerr << me << ": unable to read monmap file" << std::endl; return -1; } } if (!create && r < 0) { cerr << me << ": couldn't open " << fn << ": " << cpp_strerror(r) << std::endl; return -1; } else if (create && !clobber && r == 0) { cerr << me << ": " << fn << " exists, --clobber to overwrite" << std::endl; return -1; } if (create) { monmap.epoch = 0; monmap.created = ceph_clock_now(g_ceph_context); monmap.last_changed = monmap.created; srand(getpid() + time(0)); if (g_conf->fsid.is_zero()) { monmap.generate_fsid(); cout << me << ": generated fsid " << monmap.fsid << std::endl; } modified = true; } if (generate) { int r = monmap.build_initial(g_ceph_context, cerr); if (r < 0) return r; } if (filter) { // apply initial members list initial_members; get_str_list(g_conf->mon_initial_members, initial_members); if (!initial_members.empty()) { cout << "initial_members " << initial_members << ", filtering seed monmap" << std::endl; set removed; monmap.set_initial_members(g_ceph_context, initial_members, string(), entity_addr_t(), &removed); cout << "removed " << removed << std::endl; } modified = true; } if (!g_conf->fsid.is_zero()) { monmap.fsid = g_conf->fsid; cout << me << ": set fsid to " << monmap.fsid << std::endl; modified = true; } for (map::iterator p = add.begin(); p != add.end(); ++p) { if (monmap.contains(p->first)) { cerr << me << ": map already contains mon." << p->first << std::endl; usage(); } if (monmap.contains(p->second)) { cerr << me << ": map already contains " << p->second << std::endl; usage(); } monmap.add(p->first, p->second); } for (list::iterator p = rm.begin(); p != rm.end(); ++p) { cout << me << ": removing " << *p << std::endl; if (!monmap.contains(*p)) { cerr << me << ": map does not contain " << *p << std::endl; usage(); } monmap.remove(*p); } if (!print && !modified) usage(); if (print) monmap.print(cout); if (modified) { // write it out cout << me << ": writing epoch " << monmap.epoch << " to " << fn << " (" << monmap.size() << " monitors)" << std::endl; int r = monmap.write(fn.c_str()); if (r < 0) { cerr << "monmaptool: error writing to '" << fn << "': " << cpp_strerror(r) << std::endl; return 1; } } return 0; } ceph-0.80.11/src/tools/scratchtoolpp.cc0000664000175100017510000002146512623076744022030 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "include/rados/librados.hpp" using namespace librados; #include #include #include #include void buf_to_hex(const unsigned char *buf, int len, char *str) { str[0] = '\0'; for (int i = 0; i < len; i++) { sprintf(&str[i*2], "%02x", (int)buf[i]); } } class C_Watch : public WatchCtx { public: C_Watch() {} void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { cout << "C_Watch::notify() opcode=" << (int)opcode << " ver=" << ver << std::endl; } }; void testradospp_milestone(void) { int c; cout << "*** press enter to continue ***" << std::endl; while ((c = getchar()) != EOF) { if (c == '\n') break; } } int main(int argc, const char **argv) { Rados rados; if (rados.init(NULL) < 0) { cerr << "couldn't initialize rados!" << std::endl; exit(1); } if (rados.conf_read_file(NULL)) { cerr << "couldn't read configuration file." << std::endl; exit(1); } rados.conf_parse_argv(argc, argv); if (!rados.conf_set("config option that doesn't exist", "some random value")) { printf("error: succeeded in setting nonexistent config option\n"); exit(1); } if (rados.conf_set("log to stderr", "true")) { printf("error: error setting log_to_stderr\n"); exit(1); } std::string tmp; if (rados.conf_get("log to stderr", tmp)) { printf("error: failed to read log_to_stderr from config\n"); exit(1); } if (tmp != "true") { printf("error: new setting for log_to_stderr failed to take effect.\n"); exit(1); } if (rados.connect()) { printf("error connecting\n"); exit(1); } cout << "rados_initialize completed" << std::endl; testradospp_milestone(); time_t tm; bufferlist bl, bl2, blf; char buf[128]; time(&tm); snprintf(buf, 128, "%s", ctime(&tm)); bl.append(buf, strlen(buf)); blf.append(buf, 16); const char *oid = "bar"; IoCtx io_ctx; int r = rados.ioctx_create("data", io_ctx); cout << "ioctx_create result = " << r << std::endl; r = io_ctx.write(oid, bl, bl.length(), 0); uint64_t objver = io_ctx.get_last_version(); assert(objver > 0); cout << "io_ctx.write returned " << r << " last_ver=" << objver << std::endl; uint64_t stat_size; time_t stat_mtime; r = io_ctx.stat(oid, &stat_size, &stat_mtime); cout << "io_ctx.stat returned " << r << " size = " << stat_size << " mtime = " << stat_mtime << std::endl; r = io_ctx.stat(oid, NULL, NULL); cout << "io_ctx.stat(does_not_exist) = " << r << std::endl; uint64_t handle; C_Watch wc; r = io_ctx.watch(oid, objver, &handle, &wc); cout << "io_ctx.watch returned " << r << std::endl; testradospp_milestone(); io_ctx.set_notify_timeout(7); bufferlist notify_bl; r = io_ctx.notify(oid, objver, notify_bl); cout << "io_ctx.notify returned " << r << std::endl; testradospp_milestone(); r = io_ctx.notify(oid, objver, notify_bl); cout << "io_ctx.notify returned " << r << std::endl; testradospp_milestone(); r = io_ctx.unwatch(oid, handle); cout << "io_ctx.unwatch returned " << r << std::endl; testradospp_milestone(); r = io_ctx.notify(oid, objver, notify_bl); cout << "io_ctx.notify returned " << r << std::endl; testradospp_milestone(); io_ctx.set_assert_version(objver); r = io_ctx.write(oid, bl, bl.length() - 1, 0); cout << "io_ctx.write returned " << r << std::endl; r = io_ctx.write(oid, bl, bl.length() - 2, 0); cout << "io_ctx.write returned " << r << std::endl; r = io_ctx.write(oid, bl, bl.length() - 3, 0); cout << "rados.write returned " << r << std::endl; r = io_ctx.append(oid, bl, bl.length()); cout << "rados.write returned " << r << std::endl; r = io_ctx.write_full(oid, blf); cout << "rados.write_full returned " << r << std::endl; r = io_ctx.read(oid, bl, bl.length(), 0); cout << "rados.read returned " << r << std::endl; r = io_ctx.trunc(oid, 8); cout << "rados.trunc returned " << r << std::endl; r = io_ctx.read(oid, bl, bl.length(), 0); cout << "rados.read returned " << r << std::endl; r = io_ctx.exec(oid, "crypto", "md5", bl, bl2); cout << "exec returned " << r << " buf size=" << bl2.length() << std::endl; const unsigned char *md5 = (const unsigned char *)bl2.c_str(); char md5_str[bl2.length()*2 + 1]; buf_to_hex(md5, bl2.length(), md5_str); cout << "md5 result=" << md5_str << std::endl; // test assert_version r = io_ctx.read(oid, bl, 0, 1); assert(r >= 0); uint64_t v = io_ctx.get_last_version(); cout << oid << " version is " << v << std::endl; assert(v > 0); io_ctx.set_assert_version(v); r = io_ctx.read(oid, bl, 0, 1); assert(r >= 0); io_ctx.set_assert_version(v - 1); r = io_ctx.read(oid, bl, 0, 1); assert(r == -ERANGE); io_ctx.set_assert_version(v + 1); r = io_ctx.read(oid, bl, 0, 1); assert(r == -EOVERFLOW); // test assert_src_version r = io_ctx.read(oid, bl, 0, 1); assert(r >= 0); v = io_ctx.get_last_version(); cout << oid << " version is " << v << std::endl; io_ctx.set_assert_src_version(oid, v); r = io_ctx.exec(oid, "crypto", "sha1", bl, bl2); cout << "exec returned " << r << std::endl; const unsigned char *sha1 = (const unsigned char *)bl2.c_str(); char sha1_str[bl2.length()*2 + 1]; buf_to_hex(sha1, bl2.length(), sha1_str); cout << "sha1 result=" << sha1_str << std::endl; r = io_ctx.exec(oid, "acl", "set", bl, bl2); cout << "exec (set) returned " << r << std::endl; r = io_ctx.exec(oid, "acl", "get", bl, bl2); cout << "exec (get) returned " << r << std::endl; if (bl2.length() > 0) { cout << "attr=" << bl2.c_str() << std::endl; } int size = io_ctx.read(oid, bl2, 128, 0); if (size <= 0) { cout << "failed to read oid " << oid << "." << std::endl; exit(1); } if (size > 4096) { cout << "read too many bytes from oid " << oid << "." << std::endl; exit(1); } char rbuf[size + 1]; memcpy(rbuf, bl2.c_str(), size); rbuf[size] = '\0'; cout << "read result='" << rbuf << "'" << std::endl; cout << "size=" << size << std::endl; const char *oid2 = "jjj10.rbd"; r = io_ctx.exec(oid2, "rbd", "snap_list", bl, bl2); cout << "snap_list result=" << r << std::endl; r = io_ctx.exec(oid2, "rbd", "snap_add", bl, bl2); cout << "snap_add result=" << r << std::endl; if (r > 0) { char *s = bl2.c_str(); for (int i=0; i= 0); { ObjectReadOperation o; o.cmpxattr("foo", CEPH_OSD_CMPXATTR_OP_EQ, val); r = io_ctx.operate(oid, &o, &bl2); cout << " got " << r << " wanted >= 0" << std::endl; assert(r >= 0); } val.append("..."); { ObjectReadOperation o; o.cmpxattr("foo", CEPH_OSD_CMPXATTR_OP_EQ, val); r = io_ctx.operate(oid, &o, &bl2); cout << " got " << r << " wanted " << -ECANCELED << " (-ECANCELED)" << std::endl; assert(r == -ECANCELED); } cout << "src_cmpxattr" << std::endl; const char *oidb = "bar-clone"; { ObjectWriteOperation o; o.src_cmpxattr(oid, "foo", CEPH_OSD_CMPXATTR_OP_EQ, val); io_ctx.locator_set_key(oid); o.write_full(val); r = io_ctx.operate(oidb, &o); cout << " got " << r << " wanted " << -ECANCELED << " (-ECANCELED)" << std::endl; assert(r == -ECANCELED); } { ObjectWriteOperation o; o.src_cmpxattr(oid, "foo", CEPH_OSD_CMPXATTR_OP_NE, val); io_ctx.locator_set_key(oid); o.write_full(val); r = io_ctx.operate(oidb, &o); cout << " got " << r << " wanted >= 0" << std::endl; assert(r >= 0); } io_ctx.locator_set_key(string()); cout << "iterating over objects..." << std::endl; int num_objs = 0; for (ObjectIterator iter = io_ctx.objects_begin(); iter != io_ctx.objects_end(); ++iter) { num_objs++; cout << "'" << *iter << "'" << std::endl; } cout << "iterated over " << num_objs << " objects." << std::endl; map attrset; io_ctx.getxattrs(oid, attrset); map::iterator it; for (it = attrset.begin(); it != attrset.end(); ++it) { cout << "xattr: " << it->first << std::endl; } r = io_ctx.remove(oid); cout << "remove result=" << r << std::endl; rados.shutdown(); return 0; } ceph-0.80.11/src/tools/rados/0000775000175100017510000000000012623077036017727 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/tools/rados/rados.cc0000664000175100017510000023140212623076744021355 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "include/rados/librados.hpp" #include "include/rados/rados_types.hpp" #include "rados_sync.h" using namespace librados; #include "common/config.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/Cond.h" #include "common/debug.h" #include "common/errno.h" #include "common/Formatter.h" #include "common/obj_bencher.h" #include "mds/inode_backtrace.h" #include "auth/Crypto.h" #include #include #include #include #include #include #include #include #include #include #include "cls/lock/cls_lock_client.h" #include "include/compat.h" int rados_tool_sync(const std::map < std::string, std::string > &opts, std::vector &args); // two steps seem to be necessary to do this right #define STR(x) _STR(x) #define _STR(x) #x void usage(ostream& out) { out << \ "usage: rados [options] [commands]\n" "POOL COMMANDS\n" " lspools list pools\n" " mkpool [123[ 4]] create pool '\n" " [with auid 123[and using crush rule 4]]\n" " cppool copy content of a pool\n" " rmpool [ --yes-i-really-really-mean-it]\n" " remove pool '\n" " df show per-pool and total usage\n" " ls list objects in pool\n\n" " chown 123 change the pool owner to auid 123\n" "\n" "OBJECT COMMANDS\n" " get [outfile] fetch object\n" " put [infile] write object\n" " truncate length truncate object\n" " create [category] create object\n" " rm ... remove object(s)\n" " cp [target-obj] copy object\n" " clonedata clone object data\n" " listxattr \n" " getxattr attr\n" " setxattr attr val\n" " rmxattr attr\n" " stat objname stat the named object\n" " mapext \n" " lssnap list snaps\n" " mksnap create snap \n" " rmsnap remove snap \n" " rollback roll back object to snap \n" "\n" " listsnaps list the snapshots of this object\n" " bench write|seq|rand [-t concurrent_operations] [--no-cleanup] [--run-name run_name]\n" " default is 16 concurrent IOs and 4 MB ops\n" " default is to clean up after write benchmark\n" " default run-name is 'benchmark_last_metadata'\n" " cleanup [--run-name run_name] [--prefix prefix]\n" " clean up a previous benchmark operation\n" " default run-name is 'benchmark_last_metadata'\n" " load-gen [options] generate load on the cluster\n" " listomapkeys list the keys in the object map\n" " listomapvals list the keys and vals in the object map \n" " getomapval [file] show the value for the specified key\n" " in the object's object map\n" " setomapval \n" " rmomapkey \n" " getomapheader [file]\n" " setomapheader \n" " tmap-to-omap convert tmap keys/values to omap\n" " listwatchers list the watchers of this object\n" " set-alloc-hint \n" " set allocation hint for an object\n" "\n" "IMPORT AND EXPORT\n" " import [options] \n" " Upload to \n" " export [options] rados-pool> \n" " Download to \n" " options:\n" " -f / --force Copy everything, even if it hasn't changed.\n" " -d / --delete-after After synchronizing, delete unreferenced\n" " files or objects from the target bucket\n" " or directory.\n" " --workers Number of worker threads to spawn \n" " (default " STR(DEFAULT_NUM_RADOS_WORKER_THREADS) ")\n" "\n" "ADVISORY LOCKS\n" " lock list \n" " List all advisory locks on an object\n" " lock get \n" " Try to acquire a lock\n" " lock break \n" " Try to break a lock acquired by another client\n" " lock info \n" " Show lock information\n" " options:\n" " --lock-tag Lock tag, all locks operation should use\n" " the same tag\n" " --lock-cookie Locker cookie\n" " --lock-description Description of lock\n" " --lock-duration Lock duration (in seconds)\n" " --lock-type Lock type (shared, exclusive)\n" "\n" "CACHE POOLS: (for testing/development only)\n" " cache-flush flush cache pool object (blocking)\n" " cache-try-flush flush cache pool object (non-blocking)\n" " cache-evict evict cache pool object\n" " cache-flush-evict-all flush+evict all objects\n" " cache-try-flush-evict-all try-flush+evict all objects\n" "\n" "GLOBAL OPTIONS:\n" " --object_locator object_locator\n" " set object_locator for operation\n" " -p pool\n" " --pool=pool\n" " select given pool by name\n" " --target-pool=pool\n" " select target pool by name\n" " -b op_size\n" " set the size of write ops for put or benchmarking\n" " -s name\n" " --snap name\n" " select given snap name for (read) IO\n" " -i infile\n" " --create\n" " create the pool or directory that was specified\n" " -N namespace\n" " --namespace=namespace\n" " specify the namespace to use for the object\n" "\n" "BENCH OPTIONS:\n" " -t N\n" " --concurrent-ios=N\n" " Set number of concurrent I/O operations\n" " --show-time\n" " prefix output with date/time\n" "\n" "LOAD GEN OPTIONS:\n" " --num-objects total number of objects\n" " --min-object-size min object size\n" " --max-object-size max object size\n" " --min-ops min number of operations\n" " --max-ops max number of operations\n" " --max-backlog max backlog (in MB)\n" " --percent percent of operations that are read\n" " --target-throughput target throughput (in MB)\n" " --run-length total time (in seconds)\n" ; } static void usage_exit() { usage(cerr); exit(1); } static int dump_data(std::string const &filename, bufferlist const &data) { int fd; if (filename == "-") { fd = 1; } else { fd = TEMP_FAILURE_RETRY(::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644)); if (fd < 0) { int err = errno; cerr << "failed to open file: " << cpp_strerror(err) << std::endl; return -err; } } int r = data.write_fd(fd); if (fd != 1) { VOID_TEMP_FAILURE_RETRY(::close(fd)); } return r; } static int do_get(IoCtx& io_ctx, const char *objname, const char *outfile, unsigned op_size) { string oid(objname); int fd; if (strcmp(outfile, "-") == 0) { fd = 1; } else { fd = TEMP_FAILURE_RETRY(::open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0644)); if (fd < 0) { int err = errno; cerr << "failed to open file: " << cpp_strerror(err) << std::endl; return -err; } } uint64_t offset = 0; int ret; while (true) { bufferlist outdata; ret = io_ctx.read(oid, outdata, op_size, offset); if (ret <= 0) { goto out; } ret = outdata.write_fd(fd); if (ret < 0) { cerr << "error writing to file: " << cpp_strerror(ret) << std::endl; goto out; } if (outdata.length() < op_size) break; offset += outdata.length(); } ret = 0; out: if (fd != 1) VOID_TEMP_FAILURE_RETRY(::close(fd)); return ret; } static int do_copy(IoCtx& io_ctx, const char *objname, IoCtx& target_ctx, const char *target_obj) { string oid(objname); bufferlist outdata; librados::ObjectReadOperation read_op; string start_after; #define COPY_CHUNK_SIZE (4 * 1024 * 1024) read_op.read(0, COPY_CHUNK_SIZE, &outdata, NULL); map attrset; read_op.getxattrs(&attrset, NULL); bufferlist omap_header; read_op.omap_get_header(&omap_header, NULL); #define OMAP_CHUNK 1000 map omap; read_op.omap_get_vals(start_after, OMAP_CHUNK, &omap, NULL); bufferlist opbl; int ret = io_ctx.operate(oid, &read_op, &opbl); if (ret < 0) { return ret; } librados::ObjectWriteOperation write_op; string target_oid(target_obj); /* reset dest if exists */ write_op.create(false); write_op.remove(); write_op.write_full(outdata); write_op.omap_set_header(omap_header); map::iterator iter; for (iter = attrset.begin(); iter != attrset.end(); ++iter) { write_op.setxattr(iter->first.c_str(), iter->second); } if (!omap.empty()) { write_op.omap_set(omap); } ret = target_ctx.operate(target_oid, &write_op); if (ret < 0) { return ret; } uint64_t off = 0; while (outdata.length() == COPY_CHUNK_SIZE) { off += outdata.length(); outdata.clear(); ret = io_ctx.read(oid, outdata, COPY_CHUNK_SIZE, off); if (ret < 0) goto err; ret = target_ctx.write(target_oid, outdata, outdata.length(), off); if (ret < 0) goto err; } /* iterate through source omap and update target. This is not atomic */ while (omap.size() == OMAP_CHUNK) { /* now start_after should point at the last entry */ map::iterator iter = omap.end(); --iter; start_after = iter->first; omap.clear(); ret = io_ctx.omap_get_vals(oid, start_after, OMAP_CHUNK, &omap); if (ret < 0) goto err; if (omap.empty()) break; ret = target_ctx.omap_set(target_oid, omap); if (ret < 0) goto err; } return 0; err: target_ctx.remove(target_oid); return ret; } static int do_clone_data(IoCtx& io_ctx, const char *objname, IoCtx& target_ctx, const char *target_obj) { string oid(objname); // get size uint64_t size; int r = target_ctx.stat(oid, &size, NULL); if (r < 0) return r; librados::ObjectWriteOperation write_op; string target_oid(target_obj); /* reset data stream only */ write_op.create(false); write_op.truncate(0); write_op.clone_range(0, oid, 0, size); return target_ctx.operate(target_oid, &write_op); } static int do_copy_pool(Rados& rados, const char *src_pool, const char *target_pool) { IoCtx src_ctx, target_ctx; int ret = rados.ioctx_create(src_pool, src_ctx); if (ret < 0) { cerr << "cannot open source pool: " << src_pool << std::endl; return ret; } ret = rados.ioctx_create(target_pool, target_ctx); if (ret < 0) { cerr << "cannot open target pool: " << target_pool << std::endl; return ret; } librados::ObjectIterator i = src_ctx.objects_begin(); librados::ObjectIterator i_end = src_ctx.objects_end(); for (; i != i_end; ++i) { string oid = i->first; string locator = i->second; if (i->second.size()) cout << src_pool << ":" << oid << "(@" << locator << ")" << " => " << target_pool << ":" << oid << "(@" << locator << ")" << std::endl; else cout << src_pool << ":" << oid << " => " << target_pool << ":" << oid << std::endl; target_ctx.locator_set_key(locator); ret = do_copy(src_ctx, oid.c_str(), target_ctx, oid.c_str()); if (ret < 0) { cerr << "error copying object: " << cpp_strerror(errno) << std::endl; return ret; } } return 0; } static int do_put(IoCtx& io_ctx, const char *objname, const char *infile, int op_size) { string oid(objname); bufferlist indata; bool stdio = false; if (strcmp(infile, "-") == 0) stdio = true; int ret; int fd = 0; if (!stdio) fd = open(infile, O_RDONLY); if (fd < 0) { cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl; return 1; } char *buf = new char[op_size]; int count = op_size; uint64_t offset = 0; while (count != 0) { count = read(fd, buf, op_size); if (count < 0) { ret = -errno; cerr << "error reading input file " << infile << ": " << cpp_strerror(ret) << std::endl; goto out; } if (count == 0) { if (!offset) { ret = io_ctx.create(oid, true); if (ret < 0) { cerr << "WARNING: could not create object: " << oid << std::endl; goto out; } } continue; } indata.append(buf, count); if (offset == 0) ret = io_ctx.write_full(oid, indata); else ret = io_ctx.write(oid, indata, count, offset); indata.clear(); if (ret < 0) { goto out; } offset += count; } ret = 0; out: VOID_TEMP_FAILURE_RETRY(close(fd)); delete[] buf; return ret; } class RadosWatchCtx : public librados::WatchCtx { string name; public: RadosWatchCtx(const char *imgname) : name(imgname) {} virtual ~RadosWatchCtx() {} virtual void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { string s; try { bufferlist::iterator iter = bl.begin(); ::decode(s, iter); } catch (buffer::error *err) { cout << "could not decode bufferlist, buffer length=" << bl.length() << std::endl; } cout << name << " got notification opcode=" << (int)opcode << " ver=" << ver << " msg='" << s << "'" << std::endl; } }; static const char alphanum_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; int gen_rand_alphanumeric(char *dest, int size) /* size should be the required string size + 1 */ { int ret = get_random_bytes(dest, size); if (ret < 0) { cerr << "cannot get random bytes: " << cpp_strerror(ret) << std::endl; return -1; } int i; for (i=0; i objs; utime_t start_time; bool going_down; public: int read_percent; int num_objs; size_t min_obj_len; uint64_t max_obj_len; size_t min_op_len; size_t max_op_len; size_t max_ops; size_t max_backlog; size_t target_throughput; int run_length; enum { OP_READ, OP_WRITE, }; struct LoadGenOp { int id; int type; string oid; size_t off; size_t len; bufferlist bl; LoadGen *lg; librados::AioCompletion *completion; LoadGenOp() {} LoadGenOp(LoadGen *_lg) : lg(_lg), completion(NULL) {} }; int max_op; map pending_ops; void gen_op(LoadGenOp *op); uint64_t gen_next_op(); void run_op(LoadGenOp *op); uint64_t cur_sent_rate() { return total_sent / time_passed(); } uint64_t cur_completed_rate() { return total_completed / time_passed(); } uint64_t total_expected() { return target_throughput * time_passed(); } float time_passed() { utime_t now = ceph_clock_now(g_ceph_context); now -= start_time; uint64_t ns = now.nsec(); float total = ns / 1000000000; total += now.sec(); return total; } Mutex lock; Cond cond; LoadGen(Rados *_rados) : rados(_rados), going_down(false), lock("LoadGen") { read_percent = 80; min_obj_len = 1024; max_obj_len = 5ull * 1024ull * 1024ull * 1024ull; min_op_len = 1024; target_throughput = 5 * 1024 * 1024; // B/sec max_op_len = 2 * 1024 * 1024; max_backlog = target_throughput * 2; run_length = 60; total_sent = 0; total_completed = 0; num_objs = 200; max_op = 16; } int bootstrap(const char *pool); int run(); void cleanup(); void io_cb(completion_t c, LoadGenOp *op) { total_completed += op->len; Mutex::Locker l(lock); double rate = (double)cur_completed_rate() / (1024 * 1024); cout.precision(3); cout << "op " << op->id << " completed, throughput=" << rate << "MB/sec" << std::endl; map::iterator iter = pending_ops.find(op->id); if (iter != pending_ops.end()) pending_ops.erase(iter); if (!going_down) op->completion->release(); delete op; cond.Signal(); } }; static void _load_gen_cb(completion_t c, void *param) { LoadGen::LoadGenOp *op = (LoadGen::LoadGenOp *)param; op->lg->io_cb(c, op); } int LoadGen::bootstrap(const char *pool) { char buf[128]; int i; if (!pool) { cerr << "ERROR: pool name was not specified" << std::endl; return -EINVAL; } int ret = rados->ioctx_create(pool, io_ctx); if (ret < 0) { cerr << "error opening pool " << pool << ": " << cpp_strerror(ret) << std::endl; return ret; } int buf_len = 1; bufferptr p = buffer::create(buf_len); bufferlist bl; memset(p.c_str(), 0, buf_len); bl.push_back(p); list completions; for (i = 0; i < num_objs; i++) { obj_info info; gen_rand_alphanumeric(buf, 16); info.name = "obj-"; info.name.append(buf); info.len = get_random(min_obj_len, max_obj_len); // throttle... while (completions.size() > max_ops) { AioCompletion *c = completions.front(); c->wait_for_complete(); ret = c->get_return_value(); c->release(); completions.pop_front(); if (ret < 0) { cerr << "aio_write failed" << std::endl; return ret; } } librados::AioCompletion *c = rados->aio_create_completion(NULL, NULL, NULL); completions.push_back(c); // generate object ret = io_ctx.aio_write(info.name, c, bl, buf_len, info.len - buf_len); if (ret < 0) { cerr << "couldn't write obj: " << info.name << " ret=" << ret << std::endl; return ret; } objs[i] = info; } list::iterator iter; for (iter = completions.begin(); iter != completions.end(); ++iter) { AioCompletion *c = *iter; c->wait_for_complete(); ret = c->get_return_value(); c->release(); if (ret < 0) { // yes, we leak. cerr << "aio_write failed" << std::endl; return ret; } } return 0; } void LoadGen::run_op(LoadGenOp *op) { op->completion = rados->aio_create_completion(op, _load_gen_cb, NULL); switch (op->type) { case OP_READ: io_ctx.aio_read(op->oid, op->completion, &op->bl, op->len, op->off); break; case OP_WRITE: bufferptr p = buffer::create(op->len); memset(p.c_str(), 0, op->len); op->bl.push_back(p); io_ctx.aio_write(op->oid, op->completion, op->bl, op->len, op->off); break; } total_sent += op->len; } void LoadGen::gen_op(LoadGenOp *op) { int i = get_random(0, objs.size() - 1); obj_info& info = objs[i]; op->oid = info.name; size_t len = get_random(min_op_len, max_op_len); if (len > info.len) len = info.len; size_t off = get_random(0, info.len); if (off + len > info.len) off = info.len - len; op->off = off; op->len = len; i = get_random(1, 100); if (i > read_percent) op->type = OP_WRITE; else op->type = OP_READ; cout << (op->type == OP_READ ? "READ" : "WRITE") << " : oid=" << op->oid << " off=" << op->off << " len=" << op->len << std::endl; } uint64_t LoadGen::gen_next_op() { lock.Lock(); LoadGenOp *op = new LoadGenOp(this); gen_op(op); op->id = max_op++; pending_ops[op->id] = op; lock.Unlock(); run_op(op); return op->len; } int LoadGen::run() { start_time = ceph_clock_now(g_ceph_context); utime_t end_time = start_time; end_time += run_length; utime_t stamp_time = start_time; uint32_t total_sec = 0; while (1) { lock.Lock(); utime_t one_second(1, 0); cond.WaitInterval(g_ceph_context, lock, one_second); lock.Unlock(); utime_t now = ceph_clock_now(g_ceph_context); if (now > end_time) break; uint64_t expected = total_expected(); lock.Lock(); uint64_t sent = total_sent; uint64_t completed = total_completed; lock.Unlock(); if (now - stamp_time >= utime_t(1, 0)) { double rate = (double)cur_completed_rate() / (1024 * 1024); ++total_sec; cout.precision(3); cout << setw(5) << total_sec << ": throughput=" << rate << "MB/sec" << " pending data=" << sent - completed << std::endl; stamp_time = now; } while (sent < expected && sent - completed < max_backlog && pending_ops.size() < max_ops) { sent += gen_next_op(); } } // get a reference to all pending requests vector completions; lock.Lock(); going_down = true; map::iterator iter; for (iter = pending_ops.begin(); iter != pending_ops.end(); ++iter) { LoadGenOp *op = iter->second; completions.push_back(op->completion); } lock.Unlock(); cout << "waiting for all operations to complete" << std::endl; // now wait on all the pending requests for (vector::iterator citer = completions.begin(); citer != completions.end(); ++citer) { librados::AioCompletion *c = *citer; c->wait_for_complete(); c->release(); } return 0; } void LoadGen::cleanup() { cout << "cleaning up objects" << std::endl; map::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { obj_info& info = iter->second; int ret = io_ctx.remove(info.name); if (ret < 0) cerr << "couldn't remove obj: " << info.name << " ret=" << ret << std::endl; } } class RadosBencher : public ObjBencher { librados::AioCompletion **completions; librados::Rados& rados; librados::IoCtx& io_ctx; librados::ObjectIterator oi; bool iterator_valid; protected: int completions_init(int concurrentios) { completions = new librados::AioCompletion *[concurrentios]; return 0; } void completions_done() { delete[] completions; completions = NULL; } int create_completion(int slot, void (*cb)(void *, void*), void *arg) { completions[slot] = rados.aio_create_completion((void *) arg, 0, cb); if (!completions[slot]) return -EINVAL; return 0; } void release_completion(int slot) { completions[slot]->release(); completions[slot] = 0; } int aio_read(const std::string& oid, int slot, bufferlist *pbl, size_t len) { return io_ctx.aio_read(oid, completions[slot], pbl, len, 0); } int aio_write(const std::string& oid, int slot, bufferlist& bl, size_t len) { return io_ctx.aio_write(oid, completions[slot], bl, len, 0); } int aio_remove(const std::string& oid, int slot) { return io_ctx.aio_remove(oid, completions[slot]); } int sync_read(const std::string& oid, bufferlist& bl, size_t len) { return io_ctx.read(oid, bl, len, 0); } int sync_write(const std::string& oid, bufferlist& bl, size_t len) { return io_ctx.write_full(oid, bl); } int sync_remove(const std::string& oid) { return io_ctx.remove(oid); } bool completion_is_done(int slot) { return completions[slot]->is_safe(); } int completion_wait(int slot) { return completions[slot]->wait_for_safe_and_cb(); } int completion_ret(int slot) { return completions[slot]->get_return_value(); } bool get_objects(std::list* objects, int num) { int count = 0; if (!iterator_valid) { oi = io_ctx.objects_begin(); iterator_valid = true; } librados::ObjectIterator ei = io_ctx.objects_end(); if (oi == ei) { iterator_valid = false; return false; } objects->clear(); for ( ; oi != ei && count < num; ++oi) { objects->push_back(oi->first); ++count; } return true; } public: RadosBencher(CephContext *cct_, librados::Rados& _r, librados::IoCtx& _i) : ObjBencher(cct_), completions(NULL), rados(_r), io_ctx(_i), iterator_valid(false) {} ~RadosBencher() { } }; static int do_lock_cmd(std::vector &nargs, const std::map < std::string, std::string > &opts, IoCtx *ioctx, Formatter *formatter) { if (nargs.size() < 3) usage_exit(); string cmd(nargs[1]); string oid(nargs[2]); string lock_tag; string lock_cookie; string lock_description; int lock_duration = 0; ClsLockType lock_type = LOCK_EXCLUSIVE; map::const_iterator i; i = opts.find("lock-tag"); if (i != opts.end()) { lock_tag = i->second; } i = opts.find("lock-cookie"); if (i != opts.end()) { lock_cookie = i->second; } i = opts.find("lock-description"); if (i != opts.end()) { lock_description = i->second; } i = opts.find("lock-duration"); if (i != opts.end()) { lock_duration = strtol(i->second.c_str(), NULL, 10); } i = opts.find("lock-type"); if (i != opts.end()) { const string& type_str = i->second; if (type_str.compare("exclusive") == 0) { lock_type = LOCK_EXCLUSIVE; } else if (type_str.compare("shared") == 0) { lock_type = LOCK_SHARED; } else { cerr << "unknown lock type was specified, aborting" << std::endl; return -EINVAL; } } if (cmd.compare("list") == 0) { list locks; int ret = rados::cls::lock::list_locks(ioctx, oid, &locks); if (ret < 0) { cerr << "ERROR: rados_list_locks(): " << cpp_strerror(ret) << std::endl; return ret; } formatter->open_object_section("object"); formatter->dump_string("objname", oid); formatter->open_array_section("locks"); list::iterator iter; for (iter = locks.begin(); iter != locks.end(); ++iter) { formatter->open_object_section("lock"); formatter->dump_string("name", *iter); formatter->close_section(); } formatter->close_section(); formatter->close_section(); formatter->flush(cout); return 0; } if (nargs.size() < 4) usage_exit(); string lock_name(nargs[3]); if (cmd.compare("info") == 0) { map lockers; ClsLockType type = LOCK_NONE; string tag; int ret = rados::cls::lock::get_lock_info(ioctx, oid, lock_name, &lockers, &type, &tag); if (ret < 0) { cerr << "ERROR: rados_lock_get_lock_info(): " << cpp_strerror(ret) << std::endl; return ret; } formatter->open_object_section("lock"); formatter->dump_string("name", lock_name); formatter->dump_string("type", cls_lock_type_str(type)); formatter->dump_string("tag", tag); formatter->open_array_section("lockers"); map::iterator iter; for (iter = lockers.begin(); iter != lockers.end(); ++iter) { const rados::cls::lock::locker_id_t& id = iter->first; const rados::cls::lock::locker_info_t& info = iter->second; formatter->open_object_section("locker"); formatter->dump_stream("name") << id.locker; formatter->dump_string("cookie", id.cookie); formatter->dump_string("description", info.description); formatter->dump_stream("expiration") << info.expiration; formatter->dump_stream("addr") << info.addr; formatter->close_section(); } formatter->close_section(); formatter->close_section(); formatter->flush(cout); return ret; } else if (cmd.compare("get") == 0) { rados::cls::lock::Lock l(lock_name); l.set_cookie(lock_cookie); l.set_tag(lock_tag); l.set_duration(utime_t(lock_duration, 0)); l.set_description(lock_description); int ret; switch (lock_type) { case LOCK_SHARED: ret = l.lock_shared(ioctx, oid); break; default: ret = l.lock_exclusive(ioctx, oid); } if (ret < 0) { cerr << "ERROR: failed locking: " << cpp_strerror(ret) << std::endl; return ret; } return ret; } if (nargs.size() < 5) usage_exit(); if (cmd.compare("break") == 0) { string locker(nargs[4]); rados::cls::lock::Lock l(lock_name); l.set_cookie(lock_cookie); l.set_tag(lock_tag); entity_name_t name; if (!name.parse(locker)) { cerr << "ERROR: failed to parse locker name (" << locker << ")" << std::endl; return -EINVAL; } int ret = l.break_lock(ioctx, oid, name); if (ret < 0) { cerr << "ERROR: failed breaking lock: " << cpp_strerror(ret) << std::endl; return ret; } } else { usage_exit(); } return 0; } static int do_cache_flush(IoCtx& io_ctx, string oid) { ObjectReadOperation op; op.cache_flush(); librados::AioCompletion *completion = librados::Rados::aio_create_completion(); io_ctx.aio_operate(oid.c_str(), completion, &op, librados::OPERATION_IGNORE_CACHE | librados::OPERATION_IGNORE_OVERLAY, NULL); completion->wait_for_safe(); int r = completion->get_return_value(); completion->release(); return r; } static int do_cache_try_flush(IoCtx& io_ctx, string oid) { ObjectReadOperation op; op.cache_try_flush(); librados::AioCompletion *completion = librados::Rados::aio_create_completion(); io_ctx.aio_operate(oid.c_str(), completion, &op, librados::OPERATION_IGNORE_CACHE | librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL); completion->wait_for_safe(); int r = completion->get_return_value(); completion->release(); return r; } static int do_cache_evict(IoCtx& io_ctx, string oid) { ObjectReadOperation op; op.cache_evict(); librados::AioCompletion *completion = librados::Rados::aio_create_completion(); io_ctx.aio_operate(oid.c_str(), completion, &op, librados::OPERATION_IGNORE_CACHE | librados::OPERATION_IGNORE_OVERLAY | librados::OPERATION_SKIPRWLOCKS, NULL); completion->wait_for_safe(); int r = completion->get_return_value(); completion->release(); return r; } static int do_cache_flush_evict_all(IoCtx& io_ctx, bool blocking) { int r; int errors = 0; try { librados::ObjectIterator i = io_ctx.objects_begin(); librados::ObjectIterator i_end = io_ctx.objects_end(); for (; i != i_end; ++i) { cout << i->first << "\t" << i->second << std::endl; if (i->second.size()) { io_ctx.locator_set_key(i->second); } else { io_ctx.locator_set_key(string()); } if (blocking) r = do_cache_flush(io_ctx, i->first); else r = do_cache_try_flush(io_ctx, i->first); if (r < 0) { cerr << "failed to flush " << i->first << ": " << cpp_strerror(r) << std::endl; ++errors; continue; } r = do_cache_evict(io_ctx, i->first); if (r < 0) { cerr << "failed to evict " << i->first << ": " << cpp_strerror(r) << std::endl; ++errors; continue; } } } catch (const std::runtime_error& e) { cerr << e.what() << std::endl; return -1; } return errors ? -1 : 0; } /********************************************** **********************************************/ static int rados_tool_common(const std::map < std::string, std::string > &opts, std::vector &nargs) { int ret; bool create_pool = false; const char *pool_name = NULL; const char *target_pool_name = NULL; string oloc, target_oloc, nspace; int concurrent_ios = 16; int op_size = 1 << 22; bool cleanup = true; const char *snapname = NULL; snap_t snapid = CEPH_NOSNAP; std::map::const_iterator i; std::string category; uint64_t min_obj_len = 0; uint64_t max_obj_len = 0; uint64_t min_op_len = 0; uint64_t max_op_len = 0; uint64_t max_ops = 0; uint64_t max_backlog = 0; uint64_t target_throughput = 0; int64_t read_percent = -1; uint64_t num_objs = 0; int run_length = 0; bool show_time = false; const char* run_name = NULL; const char* prefix = NULL; Formatter *formatter = NULL; bool pretty_format = false; Rados rados; IoCtx io_ctx; i = opts.find("create"); if (i != opts.end()) { create_pool = true; } i = opts.find("pool"); if (i != opts.end()) { pool_name = i->second.c_str(); } i = opts.find("target_pool"); if (i != opts.end()) { target_pool_name = i->second.c_str(); } i = opts.find("object_locator"); if (i != opts.end()) { oloc = i->second; } i = opts.find("target_locator"); if (i != opts.end()) { target_oloc = i->second; } i = opts.find("category"); if (i != opts.end()) { category = i->second; } i = opts.find("concurrent-ios"); if (i != opts.end()) { concurrent_ios = strtol(i->second.c_str(), NULL, 10); } i = opts.find("run-name"); if (i != opts.end()) { run_name = i->second.c_str(); } i = opts.find("prefix"); if (i != opts.end()) { prefix = i->second.c_str(); } i = opts.find("block-size"); if (i != opts.end()) { op_size = strtol(i->second.c_str(), NULL, 10); } i = opts.find("snap"); if (i != opts.end()) { snapname = i->second.c_str(); } i = opts.find("snapid"); if (i != opts.end()) { snapid = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("min-object-size"); if (i != opts.end()) { min_obj_len = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("max-object-size"); if (i != opts.end()) { max_obj_len = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("min-op-len"); if (i != opts.end()) { min_op_len = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("max-op-len"); if (i != opts.end()) { max_op_len = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("max-ops"); if (i != opts.end()) { max_ops = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("max-backlog"); if (i != opts.end()) { max_backlog = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("target-throughput"); if (i != opts.end()) { target_throughput = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("read-percent"); if (i != opts.end()) { read_percent = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("num-objects"); if (i != opts.end()) { num_objs = strtoll(i->second.c_str(), NULL, 10); } i = opts.find("run-length"); if (i != opts.end()) { run_length = strtol(i->second.c_str(), NULL, 10); } i = opts.find("show-time"); if (i != opts.end()) { show_time = true; } i = opts.find("no-cleanup"); if (i != opts.end()) { cleanup = false; } i = opts.find("pretty-format"); if (i != opts.end()) { pretty_format = true; } i = opts.find("format"); if (i != opts.end()) { const char *format = i->second.c_str(); if (strcmp(format, "xml") == 0) formatter = new XMLFormatter(pretty_format); else if (strcmp(format, "json") == 0) formatter = new JSONFormatter(pretty_format); else { cerr << "unrecognized format: " << format << std::endl; return -EINVAL; } } i = opts.find("namespace"); if (i != opts.end()) { nspace = i->second; } // open rados ret = rados.init_with_context(g_ceph_context); if (ret) { cerr << "couldn't initialize rados! error " << ret << std::endl; ret = -1; goto out; } ret = rados.connect(); if (ret) { cerr << "couldn't connect to cluster! error " << ret << std::endl; ret = -1; goto out; } if (create_pool && !pool_name) { cerr << "--create-pool requested but pool_name was not specified!" << std::endl; usage_exit(); } if (create_pool) { ret = rados.pool_create(pool_name, 0, 0); if (ret < 0) { cerr << "error creating pool " << pool_name << ": " << cpp_strerror(ret) << std::endl; goto out; } } // open io context. if (pool_name) { ret = rados.ioctx_create(pool_name, io_ctx); if (ret < 0) { cerr << "error opening pool " << pool_name << ": " << cpp_strerror(ret) << std::endl; goto out; } // align op_size if (io_ctx.pool_requires_alignment()) { const uint64_t align = io_ctx.pool_required_alignment(); const bool wrn = (op_size != (1<<22)); op_size = uint64_t((op_size + align - 1) / align) * align; if (wrn) cerr << "INFO: op_size has been rounded to " << op_size << std::endl; } } // snapname? if (snapname) { ret = io_ctx.snap_lookup(snapname, &snapid); if (ret < 0) { cerr << "error looking up snap '" << snapname << "': " << cpp_strerror(ret) << std::endl; goto out; } } if (oloc.size()) { io_ctx.locator_set_key(oloc); } if (!nspace.empty()) { io_ctx.set_namespace(nspace); } if (snapid != CEPH_NOSNAP) { string name; ret = io_ctx.snap_get_name(snapid, &name); if (ret < 0) { cerr << "snapid " << snapid << " doesn't exist in pool " << io_ctx.get_pool_name() << std::endl; goto out; } io_ctx.snap_set_read(snapid); cout << "selected snap " << snapid << " '" << snapname << "'" << std::endl; } assert(!nargs.empty()); // list pools? if (strcmp(nargs[0], "lspools") == 0) { list vec; ret = rados.pool_list(vec); if (ret < 0) { cerr << "error listing pools: " << cpp_strerror(ret) << std::endl; goto out; } for (list::iterator i = vec.begin(); i != vec.end(); ++i) cout << *i << std::endl; } else if (strcmp(nargs[0], "df") == 0) { // pools list vec; if (!pool_name) { ret = rados.pool_list(vec); if (ret < 0) { cerr << "error listing pools: " << cpp_strerror(ret) << std::endl; goto out; } } else { vec.push_back(pool_name); } map > stats; ret = rados.get_pool_stats(vec, category, stats); if (ret < 0) { cerr << "error fetching pool stats: " << cpp_strerror(ret) << std::endl; goto out; } if (!formatter) { printf("%-15s %-15s" "%12s %12s %12s %12s " "%12s %12s %12s %12s %12s\n", "pool name", "category", "KB", "objects", "clones", "degraded", "unfound", "rd", "rd KB", "wr", "wr KB"); } else { formatter->open_object_section("stats"); formatter->open_array_section("pools"); } for (map::iterator c = stats.begin(); c != stats.end(); ++c) { const char *pool_name = c->first.c_str(); stats_map& m = c->second; if (formatter) { formatter->open_object_section("pool"); int64_t pool_id = rados.pool_lookup(pool_name); formatter->dump_string("name", pool_name); if (pool_id >= 0) formatter->dump_format("id", "%lld", pool_id); else cerr << "ERROR: lookup_pg_pool_name for name=" << pool_name << " returned " << pool_id << std::endl; formatter->open_array_section("categories"); } for (stats_map::iterator i = m.begin(); i != m.end(); ++i) { const char *category = (i->first.size() ? i->first.c_str() : ""); pool_stat_t& s = i->second; if (!formatter) { if (!*category) category = "-"; printf("%-15s " "%-15s " "%12lld %12lld %12lld %12lld" "%12lld %12lld %12lld %12lld %12lld\n", pool_name, category, (long long)s.num_kb, (long long)s.num_objects, (long long)s.num_object_clones, (long long)s.num_objects_degraded, (long long)s.num_objects_unfound, (long long)s.num_rd, (long long)s.num_rd_kb, (long long)s.num_wr, (long long)s.num_wr_kb); } else { formatter->open_object_section("category"); if (category) formatter->dump_string("name", category); formatter->dump_format("size_bytes", "%lld", s.num_bytes); formatter->dump_format("size_kb", "%lld", s.num_kb); formatter->dump_format("num_objects", "%lld", s.num_objects); formatter->dump_format("num_object_clones", "%lld", s.num_object_clones); formatter->dump_format("num_object_copies", "%lld", s.num_object_copies); formatter->dump_format("num_objects_missing_on_primary", "%lld", s.num_objects_missing_on_primary); formatter->dump_format("num_objects_unfound", "%lld", s.num_objects_unfound); formatter->dump_format("num_objects_degraded", "%lld", s.num_objects_degraded); formatter->dump_format("read_bytes", "%lld", s.num_rd); formatter->dump_format("read_kb", "%lld", s.num_rd_kb); formatter->dump_format("write_bytes", "%lld", s.num_wr); formatter->dump_format("write_kb", "%lld", s.num_wr_kb); formatter->flush(cout); } if (formatter) { formatter->close_section(); } } if (formatter) { formatter->close_section(); formatter->close_section(); formatter->flush(cout); } } // total cluster_stat_t tstats; ret = rados.cluster_stat(tstats); if (ret < 0) { cerr << "error getting total cluster usage: " << cpp_strerror(ret) << std::endl; goto out; } if (!formatter) { printf(" total used %12lld %12lld\n", (long long unsigned)tstats.kb_used, (long long unsigned)tstats.num_objects); printf(" total avail %12lld\n", (long long unsigned)tstats.kb_avail); printf(" total space %12lld\n", (long long unsigned)tstats.kb); } else { formatter->close_section(); formatter->dump_format("total_objects", "%lld", (long long unsigned)tstats.num_objects); formatter->dump_format("total_used", "%lld", (long long unsigned)tstats.kb_used); formatter->dump_format("total_avail", "%lld", (long long unsigned)tstats.kb_avail); formatter->dump_format("total_space", "%lld", (long long unsigned)tstats.kb); formatter->close_section(); formatter->flush(cout); } } else if (strcmp(nargs[0], "ls") == 0) { if (!pool_name) { cerr << "pool name was not specified" << std::endl; ret = -1; goto out; } bool stdout = (nargs.size() < 2) || (strcmp(nargs[1], "-") == 0); ostream *outstream; if(stdout) outstream = &cout; else outstream = new ofstream(nargs[1]); { try { librados::ObjectIterator i = io_ctx.objects_begin(); librados::ObjectIterator i_end = io_ctx.objects_end(); for (; i != i_end; ++i) { if (i->second.size()) *outstream << i->first << "\t" << i->second << std::endl; else *outstream << i->first << std::endl; } } catch (const std::runtime_error& e) { cerr << e.what() << std::endl; ret = -1; goto out; } } if (!stdout) delete outstream; } else if (strcmp(nargs[0], "chown") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); uint64_t new_auid = strtol(nargs[1], 0, 10); ret = io_ctx.set_auid(new_auid); if (ret < 0) { cerr << "error changing auid on pool " << io_ctx.get_pool_name() << ':' << cpp_strerror(ret) << std::endl; } else cerr << "changed auid on pool " << io_ctx.get_pool_name() << " to " << new_auid << std::endl; } else if (strcmp(nargs[0], "mapext") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); std::map m; ret = io_ctx.mapext(oid, 0, -1, m); if (ret < 0) { cerr << "mapext error on " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } std::map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { cout << hex << iter->first << "\t" << iter->second << dec << std::endl; } } else if (strcmp(nargs[0], "stat") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); uint64_t size; time_t mtime; ret = io_ctx.stat(oid, &size, &mtime); if (ret < 0) { cerr << " error stat-ing " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } else { cout << pool_name << "/" << oid << " mtime " << mtime << ", size " << size << std::endl; } } else if (strcmp(nargs[0], "get") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); ret = do_get(io_ctx, nargs[1], nargs[2], op_size); if (ret < 0) { cerr << "error getting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "put") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); ret = do_put(io_ctx, nargs[1], nargs[2], op_size); if (ret < 0) { cerr << "error putting " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "truncate") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); long size = atol(nargs[2]); if (size < 0) { cerr << "error, cannot truncate to negative value" << std::endl; usage_exit(); } ret = io_ctx.trunc(oid, size); if (ret < 0) { cerr << "error truncating oid " << oid << " to " << size << ": " << cpp_strerror(ret) << std::endl; } else { ret = 0; } } else if (strcmp(nargs[0], "setxattr") == 0) { if (!pool_name || nargs.size() < 4) usage_exit(); string oid(nargs[1]); string attr_name(nargs[2]); string attr_val(nargs[3]); bufferlist bl; bl.append(attr_val.c_str(), attr_val.length()); ret = io_ctx.setxattr(oid, attr_name.c_str(), bl); if (ret < 0) { cerr << "error setting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl; goto out; } else ret = 0; } else if (strcmp(nargs[0], "getxattr") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); string attr_name(nargs[2]); bufferlist bl; ret = io_ctx.getxattr(oid, attr_name.c_str(), bl); if (ret < 0) { cerr << "error getting xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl; goto out; } else ret = 0; string s(bl.c_str(), bl.length()); cout << s << std::endl; } else if (strcmp(nargs[0], "rmxattr") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); string attr_name(nargs[2]); ret = io_ctx.rmxattr(oid, attr_name.c_str()); if (ret < 0) { cerr << "error removing xattr " << pool_name << "/" << oid << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "listxattr") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); map attrset; bufferlist bl; ret = io_ctx.getxattrs(oid, attrset); if (ret < 0) { cerr << "error getting xattr set " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } for (map::iterator iter = attrset.begin(); iter != attrset.end(); ++iter) { cout << iter->first << std::endl; } } else if (strcmp(nargs[0], "getomapheader") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); string outfile; if (nargs.size() >= 3) { outfile = nargs[2]; } bufferlist header; ret = io_ctx.omap_get_header(oid, &header); if (ret < 0) { cerr << "error getting omap header " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } else { if (!outfile.empty()) { cerr << "Writing to " << outfile << std::endl; dump_data(outfile, header); } else { cout << "header (" << header.length() << " bytes) :\n"; header.hexdump(cout); cout << std::endl; } ret = 0; } } else if (strcmp(nargs[0], "setomapheader") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); string val(nargs[2]); bufferlist bl; bl.append(val); ret = io_ctx.omap_set_header(oid, bl); if (ret < 0) { cerr << "error setting omap value " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } else { ret = 0; } } else if (strcmp(nargs[0], "setomapval") == 0) { if (!pool_name || nargs.size() < 4) usage_exit(); string oid(nargs[1]); string key(nargs[2]); string val(nargs[3]); map values; bufferlist bl; bl.append(val); values[key] = bl; ret = io_ctx.omap_set(oid, values); if (ret < 0) { cerr << "error setting omap value " << pool_name << "/" << oid << "/" << key << ": " << cpp_strerror(ret) << std::endl; goto out; } else { ret = 0; } } else if (strcmp(nargs[0], "getomapval") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); string key(nargs[2]); set keys; keys.insert(key); std::string outfile; if (nargs.size() >= 4) { outfile = nargs[3]; } map values; ret = io_ctx.omap_get_vals_by_keys(oid, keys, &values); if (ret < 0) { cerr << "error getting omap value " << pool_name << "/" << oid << "/" << key << ": " << cpp_strerror(ret) << std::endl; goto out; } else { ret = 0; } if (values.size() && values.begin()->first == key) { cout << " (length " << values.begin()->second.length() << ") : "; if (!outfile.empty()) { cerr << "Writing to " << outfile << std::endl; dump_data(outfile, values.begin()->second); } else { values.begin()->second.hexdump(cout); cout << std::endl; } ret = 0; } else { cout << "No such key: " << pool_name << "/" << oid << "/" << key << std::endl; ret = -1; goto out; } } else if (strcmp(nargs[0], "rmomapkey") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); string key(nargs[2]); set keys; keys.insert(key); ret = io_ctx.omap_rm_keys(oid, keys); if (ret < 0) { cerr << "error removing omap key " << pool_name << "/" << oid << "/" << key << ": " << cpp_strerror(ret) << std::endl; goto out; } else { ret = 0; } } else if (strcmp(nargs[0], "listomapvals") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); string last_read = ""; int MAX_READ = 512; do { map values; ret = io_ctx.omap_get_vals(oid, last_read, MAX_READ, &values); if (ret < 0) { cerr << "error getting omap keys " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; return 1; } ret = values.size(); for (map::const_iterator it = values.begin(); it != values.end(); ++it) { last_read = it->first; // dump key in hex if it contains nonprintable characters if (std::count_if(it->first.begin(), it->first.end(), (int (*)(int))isprint) < (int)it->first.length()) { cout << "key: (" << it->first.length() << " bytes):\n"; bufferlist keybl; keybl.append(it->first); keybl.hexdump(cout); } else { cout << it->first; } cout << std::endl; cout << "value: (" << it->second.length() << " bytes) :\n"; it->second.hexdump(cout); cout << std::endl; } } while (ret == MAX_READ); ret = 0; } else if (strcmp(nargs[0], "cp") == 0) { if (!pool_name) usage_exit(); if (nargs.size() < 2 || nargs.size() > 3) usage_exit(); const char *target = target_pool_name; if (!target) target = pool_name; const char *target_obj; if (nargs.size() < 3) { if (strcmp(target, pool_name) == 0) { cerr << "cannot copy object into itself" << std::endl; ret = -1; goto out; } target_obj = nargs[1]; } else { target_obj = nargs[2]; } // open io context. IoCtx target_ctx; ret = rados.ioctx_create(target, target_ctx); if (ret < 0) { cerr << "error opening target pool " << target << ": " << cpp_strerror(ret) << std::endl; goto out; } if (target_oloc.size()) { target_ctx.locator_set_key(target_oloc); } ret = do_copy(io_ctx, nargs[1], target_ctx, target_obj); if (ret < 0) { cerr << "error copying " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "clonedata") == 0) { if (!pool_name) usage_exit(); if (nargs.size() < 2 || nargs.size() > 3) usage_exit(); const char *target = target_pool_name; if (!target) target = pool_name; const char *target_obj; if (nargs.size() < 3) { if (strcmp(target, pool_name) == 0) { cerr << "cannot copy object into itself" << std::endl; ret = -1; goto out; } target_obj = nargs[1]; } else { target_obj = nargs[2]; } // open io context. IoCtx target_ctx; ret = rados.ioctx_create(target, target_ctx); if (ret < 0) { cerr << "error opening target pool " << target << ": " << cpp_strerror(ret) << std::endl; goto out; } if (oloc.size()) { target_ctx.locator_set_key(oloc); } else { cerr << "must specify locator for clone" << std::endl; ret = -1; goto out; } ret = do_clone_data(io_ctx, nargs[1], target_ctx, target_obj); if (ret < 0) { cerr << "error cloning " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "rm") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); vector::iterator iter = nargs.begin(); ++iter; for (; iter != nargs.end(); ++iter) { const string & oid = *iter; ret = io_ctx.remove(oid); if (ret < 0) { cerr << "error removing " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } } } else if (strcmp(nargs[0], "create") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); if (nargs.size() > 2) { string category(nargs[2]); ret = io_ctx.create(oid, true, category); } else { ret = io_ctx.create(oid, true); } if (ret < 0) { cerr << "error creating " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "tmap") == 0) { if (nargs.size() < 3) usage_exit(); if (strcmp(nargs[1], "dump") == 0) { bufferlist outdata; string oid(nargs[2]); ret = io_ctx.read(oid, outdata, 0, 0); if (ret < 0) { cerr << "error reading " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } bufferlist::iterator p = outdata.begin(); bufferlist header; map kv; try { ::decode(header, p); ::decode(kv, p); } catch (buffer::error& e) { cerr << "error decoding tmap " << pool_name << "/" << oid << std::endl; ret = -EINVAL; goto out; } cout << "header (" << header.length() << " bytes):\n"; header.hexdump(cout); cout << "\n"; cout << kv.size() << " keys\n"; for (map::iterator q = kv.begin(); q != kv.end(); ++q) { cout << "key '" << q->first << "' (" << q->second.length() << " bytes):\n"; q->second.hexdump(cout); cout << "\n"; } } else if (strcmp(nargs[1], "set") == 0 || strcmp(nargs[1], "create") == 0) { if (nargs.size() < 5) usage_exit(); string oid(nargs[2]); string k(nargs[3]); string v(nargs[4]); bufferlist bl; char c = (strcmp(nargs[1], "set") == 0) ? CEPH_OSD_TMAP_SET : CEPH_OSD_TMAP_CREATE; ::encode(c, bl); ::encode(k, bl); ::encode(v, bl); ret = io_ctx.tmap_update(oid, bl); } } else if (strcmp(nargs[0], "tmap-to-omap") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); bufferlist bl; int r = io_ctx.tmap_get(oid, bl); if (r < 0) { ret = r; cerr << "error reading tmap " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } bufferlist hdr; map kv; bufferlist::iterator p = bl.begin(); try { ::decode(hdr, p); ::decode(kv, p); } catch (buffer::error& e) { cerr << "error decoding tmap " << pool_name << "/" << oid << std::endl; ret = -EINVAL; goto out; } if (!p.end()) { cerr << "error decoding tmap (stray trailing data) in " << pool_name << "/" << oid << std::endl; ret = -EINVAL; goto out; } librados::ObjectWriteOperation wr; wr.omap_set_header(hdr); wr.omap_set(kv); wr.truncate(0); // delete the old tmap data r = io_ctx.operate(oid, &wr); if (r < 0) { ret = r; cerr << "error writing tmap data as omap on " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } ret = 0; } else if (strcmp(nargs[0], "mkpool") == 0) { int auid = 0; __u8 crush_rule = 0; if (nargs.size() < 2) usage_exit(); if (nargs.size() > 2) { auid = strtol(nargs[2], 0, 10); cerr << "setting auid:" << auid << std::endl; if (nargs.size() > 3) { crush_rule = (__u8)strtol(nargs[3], 0, 10); cerr << "using crush rule " << (int)crush_rule << std::endl; } } ret = rados.pool_create(nargs[1], auid, crush_rule); if (ret < 0) { cerr << "error creating pool " << nargs[1] << ": " << cpp_strerror(ret) << std::endl; goto out; } cout << "successfully created pool " << nargs[1] << std::endl; } else if (strcmp(nargs[0], "cppool") == 0) { if (nargs.size() != 3) usage_exit(); const char *src_pool = nargs[1]; const char *target_pool = nargs[2]; if (strcmp(src_pool, target_pool) == 0) { cerr << "cannot copy pool into itself" << std::endl; ret = -1; goto out; } ret = do_copy_pool(rados, src_pool, target_pool); if (ret < 0) { cerr << "error copying pool " << src_pool << " => " << target_pool << ": " << cpp_strerror(ret) << std::endl; goto out; } cout << "successfully copied pool " << nargs[1] << std::endl; } else if (strcmp(nargs[0], "rmpool") == 0) { if (nargs.size() < 2) usage_exit(); if (nargs.size() < 4 || strcmp(nargs[1], nargs[2]) != 0 || strcmp(nargs[3], "--yes-i-really-really-mean-it") != 0) { cerr << "WARNING:\n" << " This will PERMANENTLY DESTROY an entire pool of objects with no way back.\n" << " To confirm, pass the pool to remove twice, followed by\n" << " --yes-i-really-really-mean-it" << std::endl; ret = -1; goto out; } ret = rados.pool_delete(nargs[1]); if (ret >= 0) { cout << "successfully deleted pool " << nargs[1] << std::endl; } else { //error cerr << "pool " << nargs[1] << " does not exist" << std::endl; } } else if (strcmp(nargs[0], "lssnap") == 0) { if (!pool_name || nargs.size() != 1) usage_exit(); vector snaps; io_ctx.snap_list(&snaps); for (vector::iterator i = snaps.begin(); i != snaps.end(); ++i) { string s; time_t t; if (io_ctx.snap_get_name(*i, &s) < 0) continue; if (io_ctx.snap_get_stamp(*i, &t) < 0) continue; struct tm bdt; localtime_r(&t, &bdt); cout << *i << "\t" << s << "\t"; cout.setf(std::ios::right); cout.fill('0'); cout << std::setw(4) << (bdt.tm_year+1900) << '.' << std::setw(2) << (bdt.tm_mon+1) << '.' << std::setw(2) << bdt.tm_mday << ' ' << std::setw(2) << bdt.tm_hour << ':' << std::setw(2) << bdt.tm_min << ':' << std::setw(2) << bdt.tm_sec << std::endl; cout.unsetf(std::ios::right); } cout << snaps.size() << " snaps" << std::endl; } else if (strcmp(nargs[0], "mksnap") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); ret = io_ctx.snap_create(nargs[1]); if (ret < 0) { cerr << "error creating pool " << pool_name << " snapshot " << nargs[1] << ": " << cpp_strerror(ret) << std::endl; goto out; } cout << "created pool " << pool_name << " snap " << nargs[1] << std::endl; } else if (strcmp(nargs[0], "rmsnap") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); ret = io_ctx.snap_remove(nargs[1]); if (ret < 0) { cerr << "error removing pool " << pool_name << " snapshot " << nargs[1] << ": " << cpp_strerror(ret) << std::endl; goto out; } cout << "removed pool " << pool_name << " snap " << nargs[1] << std::endl; } else if (strcmp(nargs[0], "rollback") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); ret = io_ctx.rollback(nargs[1], nargs[2]); if (ret < 0) { cerr << "error rolling back pool " << pool_name << " to snapshot " << nargs[1] << cpp_strerror(ret) << std::endl; goto out; } cout << "rolled back pool " << pool_name << " to snapshot " << nargs[2] << std::endl; } else if (strcmp(nargs[0], "bench") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); int seconds = atoi(nargs[1]); int operation = 0; if (strcmp(nargs[2], "write") == 0) operation = OP_WRITE; else if (strcmp(nargs[2], "seq") == 0) operation = OP_SEQ_READ; else if (strcmp(nargs[2], "rand") == 0) operation = OP_RAND_READ; else usage_exit(); RadosBencher bencher(g_ceph_context, rados, io_ctx); bencher.set_show_time(show_time); ret = bencher.aio_bench(operation, seconds, num_objs, concurrent_ios, op_size, cleanup, run_name); if (ret != 0) cerr << "error during benchmark: " << ret << std::endl; } else if (strcmp(nargs[0], "cleanup") == 0) { if (!pool_name) usage_exit(); RadosBencher bencher(g_ceph_context, rados, io_ctx); ret = bencher.clean_up(prefix, concurrent_ios, run_name); if (ret != 0) cerr << "error during cleanup: " << ret << std::endl; } else if (strcmp(nargs[0], "watch") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); RadosWatchCtx ctx(oid.c_str()); uint64_t cookie; ret = io_ctx.watch(oid, 0, &cookie, &ctx); if (ret != 0) cerr << "error calling watch: " << ret << std::endl; else { cout << "press enter to exit..." << std::endl; getchar(); } } else if (strcmp(nargs[0], "notify") == 0) { if (!pool_name || nargs.size() < 3) usage_exit(); string oid(nargs[1]); string msg(nargs[2]); bufferlist bl; ::encode(msg, bl); ret = io_ctx.notify(oid, 0, bl); if (ret != 0) cerr << "error calling notify: " << ret << std::endl; } else if (strcmp(nargs[0], "set-alloc-hint") == 0) { if (!pool_name || nargs.size() < 4) usage_exit(); string err; string oid(nargs[1]); uint64_t expected_object_size = strict_strtoll(nargs[2], 10, &err); if (!err.empty()) { cerr << "couldn't parse expected_object_size: " << err << std::endl; usage_exit(); } uint64_t expected_write_size = strict_strtoll(nargs[3], 10, &err); if (!err.empty()) { cerr << "couldn't parse expected_write_size: " << err << std::endl; usage_exit(); } ret = io_ctx.set_alloc_hint(oid, expected_object_size, expected_write_size); if (ret < 0) { cerr << "error setting alloc-hint " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "load-gen") == 0) { if (!pool_name) { cerr << "error: must specify pool" << std::endl; usage_exit(); } LoadGen lg(&rados); if (min_obj_len) lg.min_obj_len = min_obj_len; if (max_obj_len) lg.max_obj_len = max_obj_len; if (min_op_len) lg.min_op_len = min_op_len; if (max_op_len) lg.max_op_len = max_op_len; if (max_ops) lg.max_ops = max_ops; if (max_backlog) lg.max_backlog = max_backlog; if (target_throughput) lg.target_throughput = target_throughput << 20; if (read_percent >= 0) lg.read_percent = read_percent; if (num_objs) lg.num_objs = num_objs; if (run_length) lg.run_length = run_length; cout << "run length " << run_length << " seconds" << std::endl; cout << "preparing " << lg.num_objs << " objects" << std::endl; ret = lg.bootstrap(pool_name); if (ret < 0) { cerr << "load-gen bootstrap failed" << std::endl; exit(1); } cout << "load-gen will run " << lg.run_length << " seconds" << std::endl; lg.run(); lg.cleanup(); } else if (strcmp(nargs[0], "listomapkeys") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); librados::ObjectReadOperation read; set out_keys; read.omap_get_keys("", LONG_MAX, &out_keys, &ret); io_ctx.operate(nargs[1], &read, NULL); if (ret < 0) { cerr << "error getting omap key set " << pool_name << "/" << nargs[1] << ": " << cpp_strerror(ret) << std::endl; goto out; } for (set::iterator iter = out_keys.begin(); iter != out_keys.end(); ++iter) { cout << *iter << std::endl; } } else if (strcmp(nargs[0], "lock") == 0) { if (!pool_name) usage_exit(); if (!formatter) { formatter = new JSONFormatter(pretty_format); } ret = do_lock_cmd(nargs, opts, &io_ctx, formatter); } else if (strcmp(nargs[0], "listwatchers") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); std::list lw; ret = io_ctx.list_watchers(oid, &lw); if (ret < 0) { cerr << "error listing watchers " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } else ret = 0; for (std::list::iterator i = lw.begin(); i != lw.end(); ++i) { cout << "watcher=" << i->addr << " client." << i->watcher_id << " cookie=" << i->cookie << std::endl; } } else if (strcmp(nargs[0], "listsnaps") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); snap_set_t ls; io_ctx.snap_set_read(LIBRADOS_SNAP_DIR); ret = io_ctx.list_snaps(oid, &ls); if (ret < 0) { cerr << "error listing snap shots " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } else ret = 0; map snamemap; if (formatter || pretty_format) { vector snaps; io_ctx.snap_list(&snaps); for (vector::iterator i = snaps.begin(); i != snaps.end(); ++i) { string s; if (io_ctx.snap_get_name(*i, &s) < 0) continue; snamemap.insert(pair(*i, s)); } } if (formatter) { formatter->open_object_section("object"); formatter->dump_string("name", oid); formatter->open_array_section("clones"); } else { cout << oid << ":" << std::endl; cout << "cloneid snaps size overlap" << std::endl; } for (std::vector::iterator ci = ls.clones.begin(); ci != ls.clones.end(); ++ci) { if (formatter) formatter->open_object_section("clone"); if (ci->cloneid == librados::SNAP_HEAD) { if (formatter) formatter->dump_string("id", "head"); else cout << "head"; } else { if (formatter) formatter->dump_unsigned("id", ci->cloneid); else cout << ci->cloneid; } if (formatter) formatter->open_array_section("snapshots"); else cout << "\t"; if (!formatter && ci->snaps.empty()) { cout << "-"; } for (std::vector::const_iterator snapindex = ci->snaps.begin(); snapindex != ci->snaps.end(); ++snapindex) { map::iterator si; if (formatter || pretty_format) si = snamemap.find(*snapindex); if (formatter) { formatter->open_object_section("snapshot"); formatter->dump_unsigned("id", *snapindex); if (si != snamemap.end()) formatter->dump_string("name", si->second); formatter->close_section(); //snapshot } else { if (snapindex != ci->snaps.begin()) cout << ","; if (!pretty_format || (si == snamemap.end())) cout << *snapindex; else cout << si->second << "(" << *snapindex << ")"; } } if (formatter) { formatter->close_section(); //Snapshots formatter->dump_unsigned("size", ci->size); } else { cout << "\t" << ci->size; } if (ci->cloneid != librados::SNAP_HEAD) { if (formatter) formatter->open_array_section("overlaps"); else cout << "\t["; for (std::vector< std::pair >::iterator ovi = ci->overlap.begin(); ovi != ci->overlap.end(); ++ovi) { if (formatter) { formatter->open_object_section("section"); formatter->dump_unsigned("start", ovi->first); formatter->dump_unsigned("length", ovi->second); formatter->close_section(); //section } else { if (ovi != ci->overlap.begin()) cout << ","; cout << ovi->first << "~" << ovi->second; } } if (formatter) formatter->close_section(); //overlaps else cout << "]" << std::endl; } if (formatter) formatter->close_section(); //clone } if (formatter) { formatter->close_section(); //clones formatter->close_section(); //object formatter->flush(cout); } else { cout << std::endl; } } else if (strcmp(nargs[0], "cache-flush") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); ret = do_cache_flush(io_ctx, oid); if (ret < 0) { cerr << "error from cache-flush " << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "cache-try-flush") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); ret = do_cache_try_flush(io_ctx, oid); if (ret < 0) { cerr << "error from cache-try-flush " << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "cache-evict") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); string oid(nargs[1]); ret = do_cache_evict(io_ctx, oid); if (ret < 0) { cerr << "error from cache-evict " << oid << ": " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "cache-flush-evict-all") == 0) { if (!pool_name) usage_exit(); ret = do_cache_flush_evict_all(io_ctx, true); if (ret < 0) { cerr << "error from cache-flush-evict-all: " << cpp_strerror(ret) << std::endl; goto out; } } else if (strcmp(nargs[0], "cache-try-flush-evict-all") == 0) { if (!pool_name) usage_exit(); ret = do_cache_flush_evict_all(io_ctx, false); if (ret < 0) { cerr << "error from cache-try-flush-evict-all: " << cpp_strerror(ret) << std::endl; goto out; } } else { cerr << "unrecognized command " << nargs[0] << "; -h or --help for usage" << std::endl; ret = -EINVAL; goto out; } if (ret < 0) cerr << "error " << (-ret) << ": " << cpp_strerror(ret) << std::endl; out: delete formatter; return (ret < 0) ? 1 : 0; } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); std::map < std::string, std::string > opts; std::vector::iterator i; std::string val; for (i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(cout); exit(0); } else if (ceph_argparse_flag(args, i, "-f", "--force", (char*)NULL)) { opts["force"] = "true"; } else if (ceph_argparse_flag(args, i, "-d", "--delete-after", (char*)NULL)) { opts["delete-after"] = "true"; } else if (ceph_argparse_flag(args, i, "-C", "--create", "--create-pool", (char*)NULL)) { opts["create"] = "true"; } else if (ceph_argparse_flag(args, i, "--pretty-format", (char*)NULL)) { opts["pretty-format"] = "true"; } else if (ceph_argparse_flag(args, i, "--show-time", (char*)NULL)) { opts["show-time"] = "true"; } else if (ceph_argparse_flag(args, i, "--no-cleanup", (char*)NULL)) { opts["no-cleanup"] = "true"; } else if (ceph_argparse_witharg(args, i, &val, "--run-name", (char*)NULL)) { opts["run-name"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--prefix", (char*)NULL)) { opts["prefix"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { opts["pool"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--target-pool", (char*)NULL)) { opts["target_pool"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--object-locator" , (char *)NULL)) { opts["object_locator"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--target-locator" , (char *)NULL)) { opts["target_locator"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--category", (char*)NULL)) { opts["category"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-t", "--concurrent-ios", (char*)NULL)) { opts["concurrent-ios"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--block-size", (char*)NULL)) { opts["block-size"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-b", (char*)NULL)) { opts["block-size"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-s", "--snap", (char*)NULL)) { opts["snap"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-S", "--snapid", (char*)NULL)) { opts["snapid"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--min-object-size", (char*)NULL)) { opts["min-object-size"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--max-object-size", (char*)NULL)) { opts["max-object-size"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--min-op-len", (char*)NULL)) { opts["min-op-len"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--max-op-len", (char*)NULL)) { opts["max-op-len"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--max-ops", (char*)NULL)) { opts["max-ops"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--max-backlog", (char*)NULL)) { opts["max-backlog"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--target-throughput", (char*)NULL)) { opts["target-throughput"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--read-percent", (char*)NULL)) { opts["read-percent"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--num-objects", (char*)NULL)) { opts["num-objects"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--run-length", (char*)NULL)) { opts["run-length"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--workers", (char*)NULL)) { opts["workers"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--format", (char*)NULL)) { opts["format"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--lock-tag", (char*)NULL)) { opts["lock-tag"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--lock-cookie", (char*)NULL)) { opts["lock-cookie"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--lock-description", (char*)NULL)) { opts["lock-description"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--lock-duration", (char*)NULL)) { opts["lock-duration"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--lock-type", (char*)NULL)) { opts["lock-type"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-N", "--namespace", (char*)NULL)) { opts["namespace"] = val; } else { if (val[0] == '-') usage_exit(); ++i; } } if (args.empty()) { cerr << "rados: you must give an action. Try --help" << std::endl; return 1; } if ((strcmp(args[0], "import") == 0) || (strcmp(args[0], "export") == 0)) return rados_tool_sync(opts, args); else return rados_tool_common(opts, args); } ceph-0.80.11/src/tools/rados/rados_import.cc0000664000175100017510000001613212623076744022750 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include #include #include #include #include #include #include #include #include #include #include "rados_sync.h" #include "common/errno.h" #include "common/strtol.h" #include "include/rados/librados.hpp" using namespace librados; using std::auto_ptr; class ImportLocalFileWQ : public RadosSyncWQ { public: ImportLocalFileWQ(const char *dir_name, bool force, IoCtxDistributor *io_ctx_dist, time_t ti, ThreadPool *tp) : RadosSyncWQ(io_ctx_dist, ti, 0, tp), m_dir_name(dir_name), m_force(force) { } private: void _process(std::string *s) { IoCtx &io_ctx(m_io_ctx_dist->get_ioctx()); const std::string &local_name(*s); auto_ptr sobj; auto_ptr dobj; std::list < std::string > only_in_a; std::list < std::string > only_in_b; std::list < std::string > diff; int flags = 0; int ret = BackedUpObject::from_file(local_name.c_str(), m_dir_name.c_str(), sobj); if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_file: got error " << ret << std::endl; _exit(ret); } const char *rados_name(sobj->get_rados_name()); if (m_force) { flags |= (CHANGED_CONTENTS | CHANGED_XATTRS); } else { ret = BackedUpObject::from_rados(io_ctx, rados_name, dobj); if (ret == -ENOENT) { flags |= CHANGED_CONTENTS; sobj->get_xattrs(only_in_a); } else if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_rados returned " << ret << std::endl; _exit(ret); } else { sobj->xattr_diff(dobj.get(), only_in_a, only_in_b, diff); if ((sobj->get_rados_size() == dobj->get_rados_size()) && (sobj->get_mtime() == dobj->get_mtime())) { flags |= CHANGED_CONTENTS; } } } if (flags & CHANGED_CONTENTS) { ret = sobj->upload(io_ctx, local_name.c_str(), m_dir_name.c_str()); if (ret) { cerr << ERR_PREFIX << "upload error: " << ret << std::endl; _exit(ret); } } for (std::list < std::string >::const_iterator x = only_in_a.begin(); x != only_in_a.end(); ++x) { flags |= CHANGED_XATTRS; const Xattr *xattr = sobj->get_xattr(*x); if (xattr == NULL) { cerr << ERR_PREFIX << "internal error on line: " << __LINE__ << std::endl; _exit(ret); } bufferlist bl; bl.append(xattr->data, xattr->len); ret = io_ctx.setxattr(rados_name, x->c_str(), bl); if (ret < 0) { ret = errno; cerr << ERR_PREFIX << "io_ctx.setxattr(rados_name='" << rados_name << "', xattr_name='" << x->c_str() << "'): " << cpp_strerror(ret) << std::endl; _exit(ret); } } for (std::list < std::string >::const_iterator x = diff.begin(); x != diff.end(); ++x) { flags |= CHANGED_XATTRS; const Xattr *xattr = sobj->get_xattr(*x); if (xattr == NULL) { cerr << ERR_PREFIX << "internal error on line: " << __LINE__ << std::endl; _exit(ret); } bufferlist bl; bl.append(xattr->data, xattr->len); ret = io_ctx.rmxattr(rados_name, x->c_str()); if (ret < 0) { cerr << ERR_PREFIX << "io_ctx.rmxattr error2: " << cpp_strerror(ret) << std::endl; _exit(ret); } ret = io_ctx.setxattr(rados_name, x->c_str(), bl); if (ret < 0) { ret = errno; cerr << ERR_PREFIX << "io_ctx.setxattr(rados_name='" << rados_name << "', xattr='" << x->c_str() << "'): " << cpp_strerror(ret) << std::endl; _exit(ret); } } for (std::list < std::string >::const_iterator x = only_in_b.begin(); x != only_in_b.end(); ++x) { flags |= CHANGED_XATTRS; ret = io_ctx.rmxattr(rados_name, x->c_str()); if (ret < 0) { ret = errno; cerr << ERR_PREFIX << "rmxattr error3: " << cpp_strerror(ret) << std::endl; _exit(ret); } } if (m_force) { cout << "[force] " << rados_name << std::endl; } else if (flags & CHANGED_CONTENTS) { cout << "[imported] " << rados_name << std::endl; } else if (flags & CHANGED_XATTRS) { cout << "[xattr] " << rados_name << std::endl; } } std::string m_dir_name; bool m_force; }; class ImportValidateExistingWQ : public RadosSyncWQ { public: ImportValidateExistingWQ(ExportDir *export_dir, IoCtxDistributor *io_ctx_dist, time_t ti, ThreadPool *tp) : RadosSyncWQ(io_ctx_dist, ti, 0, tp), m_export_dir(export_dir) { } private: void _process(std::string *s) { IoCtx &io_ctx(m_io_ctx_dist->get_ioctx()); const std::string &rados_name(*s); auto_ptr robj; int ret = BackedUpObject::from_rados(io_ctx, rados_name.c_str(), robj); if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_rados in delete loop " << "returned " << ret << std::endl; _exit(ret); } std::string obj_path(robj->get_fs_path(m_export_dir)); auto_ptr lobj; ret = BackedUpObject::from_path(obj_path.c_str(), lobj); if (ret == ENOENT) { ret = io_ctx.remove(rados_name); if (ret && ret != -ENOENT) { cerr << ERR_PREFIX << "io_ctx.remove(" << obj_path << ") failed " << "with error " << ret << std::endl; _exit(ret); } cout << "[deleted] " << "removed '" << rados_name << "'" << std::endl; } else if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_path in delete loop " << "returned " << ret << std::endl; _exit(ret); } } ExportDir *m_export_dir; }; int do_rados_import(ThreadPool *tp, IoCtx &io_ctx, IoCtxDistributor* io_ctx_dist, const char *dir_name, bool force, bool delete_after) { auto_ptr export_dir; export_dir.reset(ExportDir::from_file_system(dir_name)); if (!export_dir.get()) return -EIO; DirHolder dh; int ret = dh.opendir(dir_name); if (ret) { cerr << ERR_PREFIX << "opendir(" << dir_name << ") error: " << cpp_strerror(ret) << std::endl; return ret; } ImportLocalFileWQ import_file_wq(dir_name, force, io_ctx_dist, time(NULL), tp); while (true) { struct dirent *de = readdir(dh.dp); if (!de) break; if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) continue; if (is_suffix(de->d_name, RADOS_SYNC_TMP_SUFFIX)) continue; import_file_wq.queue(new std::string(de->d_name)); } import_file_wq.drain(); if (delete_after) { ImportValidateExistingWQ import_val_wq(export_dir.get(), io_ctx_dist, time(NULL), tp); librados::ObjectIterator oi = io_ctx.objects_begin(); librados::ObjectIterator oi_end = io_ctx.objects_end(); for (; oi != oi_end; ++oi) { import_val_wq.queue(new std::string((*oi).first)); } import_val_wq.drain(); } cout << "[done]" << std::endl; return 0; } ceph-0.80.11/src/tools/rados/rados_sync.h0000664000175100017510000001414112623076744022252 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RADOS_SYNC_H #define CEPH_RADOS_SYNC_H #include #include "include/atomic.h" #include "common/WorkQueue.h" #include #include namespace librados { class IoCtx; class Rados; } extern const char USER_XATTR_PREFIX[]; extern const char RADOS_SYNC_TMP_SUFFIX[]; #define ERR_PREFIX "[ERROR] " #define DEFAULT_NUM_RADOS_WORKER_THREADS 5 /* Linux seems to use ENODATA instead of ENOATTR when an extended attribute * is missing */ #ifndef ENOATTR #define ENOATTR ENODATA #endif enum { CHANGED_XATTRS = 0x1, CHANGED_CONTENTS = 0x2, }; /** Given the name of an extended attribute from a file in the filesystem, * returns an empty string if the extended attribute does not represent a rados * user extended attribute. Otherwise, returns the name of the rados extended * attribute. * * Rados user xattrs are prefixed with USER_XATTR_PREFIX. */ std::string get_user_xattr_name(const char *fs_xattr_name); /* Returns true if 'suffix' is a suffix of str */ bool is_suffix(const char *str, const char *suffix); /** Represents a directory in the filesystem that we export rados objects to (or * import them from.) */ class ExportDir { public: static ExportDir* create_for_writing(const std::string &path, int version, bool create); static ExportDir* from_file_system(const std::string &path); /* Given a rados object name, return something which looks kind of like the * first part of the name. * * The actual file name that the backed-up object is stored in is irrelevant * to rados_sync. The only reason to make it human-readable at all is to make * things easier on sysadmins. The XATTR_FULLNAME extended attribute has the * real, full object name. * * This function turns unicode into a bunch of 'at' signs. This could be * fixed. If you try, be sure to handle all the multibyte characters * correctly. * I guess a better hash would be nice too. */ std::string get_fs_path(const std::string &rados_name) const; private: explicit ExportDir(const std::string &path_); std::string path; }; /** Smart pointer wrapper for a DIR* */ class DirHolder { public: DirHolder(); ~DirHolder(); int opendir(const char *dir_name); DIR *dp; }; /** IoCtxDistributor is a singleton that distributes out IoCtx instances to * different threads. */ class IoCtxDistributor { public: static IoCtxDistributor* instance(); int init(librados::Rados &cluster, const char *pool_name, int num_ioctxes); void clear(); librados::IoCtx& get_ioctx(); private: static IoCtxDistributor *s_instance; IoCtxDistributor(); ~IoCtxDistributor(); ceph::atomic_t m_highest_iod_idx; /* NB: there might be some false sharing here that we could optimize * away in the future */ std::vector m_io_ctxes; }; class RadosSyncWQ : public ThreadPool::WorkQueue { public: RadosSyncWQ(IoCtxDistributor *io_ctx_dist, time_t timeout, time_t suicide_timeout, ThreadPool *tp); protected: IoCtxDistributor *m_io_ctx_dist; private: bool _enqueue(std::string *s); void _dequeue(std::string *o); bool _empty(); std::string *_dequeue(); void _process_finish(std::string *s); void _clear(); std::deque m_items; }; /* Stores a length and a chunk of malloc()ed data */ class Xattr { public: Xattr(char *data_, ssize_t len_); ~Xattr(); bool operator==(const class Xattr &rhs) const; bool operator!=(const class Xattr &rhs) const; char *data; ssize_t len; }; /* Represents an object that we are backing up */ class BackedUpObject { public: static int from_file(const char *file_name, const char *dir_name, std::auto_ptr &obj); static int from_path(const char *path, std::auto_ptr &obj); static int from_rados(librados::IoCtx& io_ctx, const char *rados_name_, auto_ptr &obj); ~BackedUpObject(); /* Get the mangled name for this rados object. */ std::string get_fs_path(const ExportDir *export_dir) const; /* Convert the xattrs on this BackedUpObject to a kind of JSON-like string. * This is only used for debugging. * Note that we're assuming we can just treat the xattr data as a * null-terminated string, which isn't true. Again, this is just for debugging, * so it doesn't matter. */ std::string xattrs_to_str() const; /* Diff the extended attributes on this BackedUpObject with those found on a * different BackedUpObject */ void xattr_diff(const BackedUpObject *rhs, std::list < std::string > &only_in_a, std::list < std::string > &only_in_b, std::list < std::string > &diff) const; void get_xattrs(std::list < std::string > &xattrs_) const; const Xattr* get_xattr(const std::string &name) const; const char *get_rados_name() const; uint64_t get_rados_size() const; time_t get_mtime() const; int download(librados::IoCtx &io_ctx, const char *path); int upload(librados::IoCtx &io_ctx, const char *file_name, const char *dir_name); private: BackedUpObject(const char *rados_name_, uint64_t rados_size_, time_t rados_time_); int read_xattrs_from_file(int fd); int read_xattrs_from_rados(librados::IoCtx &io_ctx); // don't allow copying BackedUpObject &operator=(const BackedUpObject &rhs); BackedUpObject(const BackedUpObject &rhs); char *rados_name; uint64_t rados_size; uint64_t rados_time; std::map < std::string, Xattr* > xattrs; }; extern int do_rados_import(ThreadPool *tp, librados::IoCtx &io_ctx, IoCtxDistributor* io_ctx_dist, const char *dir_name, bool force, bool delete_after); extern int do_rados_export(ThreadPool *tp, librados::IoCtx& io_ctx, IoCtxDistributor *io_ctx_dist, const char *dir_name, bool create, bool force, bool delete_after); #endif ceph-0.80.11/src/tools/rados/rados_sync.cc0000664000175100017510000005755012623076744022423 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "common/ceph_argparse.h" #include "common/config.h" #include "common/errno.h" #include "common/strtol.h" #include "global/global_context.h" #include "global/global_init.h" #include "include/rados/librados.hpp" #include "rados_sync.h" #include "include/compat.h" #include "common/xattr.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace librados; using std::auto_ptr; static const char * const XATTR_RADOS_SYNC_VER = "user.rados_sync_ver"; static const char * const XATTR_FULLNAME = "user.rados_full_name"; const char USER_XATTR_PREFIX[] = "user.rados."; static const size_t USER_XATTR_PREFIX_LEN = sizeof(USER_XATTR_PREFIX) / sizeof(USER_XATTR_PREFIX[0]) - 1; /* It's important that RADOS_SYNC_TMP_SUFFIX contain at least one character * that we wouldn't normally alllow in a file name-- in this case, $ */ const char RADOS_SYNC_TMP_SUFFIX[] = "$tmp"; static const size_t RADOS_SYNC_TMP_SUFFIX_LEN = sizeof(RADOS_SYNC_TMP_SUFFIX) / sizeof(RADOS_SYNC_TMP_SUFFIX[0]) - 1; std::string get_user_xattr_name(const char *fs_xattr_name) { if (strncmp(fs_xattr_name, USER_XATTR_PREFIX, USER_XATTR_PREFIX_LEN)) return ""; return fs_xattr_name + USER_XATTR_PREFIX_LEN; } bool is_suffix(const char *str, const char *suffix) { size_t strlen_str = strlen(str); size_t strlen_suffix = strlen(suffix); if (strlen_str < strlen_suffix) return false; return (strcmp(str + (strlen_str - strlen_suffix), suffix) == 0); } ExportDir* ExportDir::create_for_writing(const std::string &path, int version, bool create) { if (access(path.c_str(), R_OK | W_OK) == 0) { return ExportDir::from_file_system(path); } if (!create) { cerr << ERR_PREFIX << "ExportDir: directory '" << path << "' does not exist. Use --create to create it." << std::endl; return NULL; } int ret = mkdir(path.c_str(), 0700); if (ret < 0) { int err = errno; if (err != EEXIST) { cerr << ERR_PREFIX << "ExportDir: mkdir error: " << cpp_strerror(err) << std::endl; return NULL; } } char buf[32]; snprintf(buf, sizeof(buf), "%d", version); ret = ceph_os_setxattr(path.c_str(), XATTR_RADOS_SYNC_VER, buf, strlen(buf) + 1); if (ret < 0) { int err = errno; cerr << ERR_PREFIX << "ExportDir: setxattr error :" << cpp_strerror(err) << std::endl; return NULL; } return new ExportDir(path); } ExportDir* ExportDir::from_file_system(const std::string &path) { if (access(path.c_str(), R_OK)) { cerr << "ExportDir: source directory '" << path << "' appears to be inaccessible." << std::endl; return NULL; } int ret; char buf[32]; memset(buf, 0, sizeof(buf)); ret = ceph_os_getxattr(path.c_str(), XATTR_RADOS_SYNC_VER, buf, sizeof(buf) - 1); if (ret < 0) { ret = errno; if (ret == ENODATA) { cerr << ERR_PREFIX << "ExportDir: directory '" << path << "' does not appear to have been created by a rados " << "export operation." << std::endl; return NULL; } cerr << ERR_PREFIX << "ExportDir: getxattr error :" << cpp_strerror(ret) << std::endl; return NULL; } std::string err; ret = strict_strtol(buf, 10, &err); if (!err.empty()) { cerr << ERR_PREFIX << "ExportDir: invalid value for " << XATTR_RADOS_SYNC_VER << ": " << buf << ". parse error: " << err << std::endl; return NULL; } if (ret != 1) { cerr << ERR_PREFIX << "ExportDir: can't handle any naming " << "convention besides version 1. You must upgrade this program to " << "handle the data in the new format." << std::endl; return NULL; } return new ExportDir(path); } std::string ExportDir::get_fs_path(const std::string &rados_name) const { static int HASH_LENGTH = 17; size_t i; size_t strlen_rados_name = strlen(rados_name.c_str()); size_t sz; bool need_hash = false; if (strlen_rados_name > 200) { sz = 200; need_hash = true; } else { sz = strlen_rados_name; } char fs_path[sz + HASH_LENGTH + 1]; for (i = 0; i < sz; ++i) { // Just replace anything that looks funny with an 'at' sign. // Unicode also gets turned into 'at' signs. signed char c = rados_name[i]; if (c < 0x20) { // Since c is signed, this also eliminates bytes with the high bit set c = '@'; need_hash = true; } else if (c == 0x7f) { c = '@'; need_hash = true; } else if (c == '/') { c = '@'; need_hash = true; } else if (c == '\\') { c = '@'; need_hash = true; } else if (c == '$') { c = '@'; need_hash = true; } else if (c == ' ') { c = '_'; need_hash = true; } fs_path[i] = c; } if (need_hash) { uint64_t hash = 17; for (i = 0; i < strlen_rados_name; ++i) { hash += (rados_name[i] * 33); } // The extra byte of length is because snprintf always NULL-terminates. snprintf(fs_path + i, HASH_LENGTH + 1, "_%016" PRIx64, hash); } else { // NULL-terminate. fs_path[i] = '\0'; } ostringstream oss; oss << path << "/" << fs_path; return oss.str(); } ExportDir::ExportDir(const std::string &path_) : path(path_) { } DirHolder::DirHolder() : dp(NULL) { } DirHolder::~DirHolder() { if (!dp) return; if (closedir(dp)) { int err = errno; cerr << ERR_PREFIX << "closedir failed: " << cpp_strerror(err) << std::endl; } dp = NULL; } int DirHolder::opendir(const char *dir_name) { dp = ::opendir(dir_name); if (!dp) { int err = errno; return err; } return 0; } static __thread int t_iod_idx = -1; static pthread_mutex_t io_ctx_distributor_lock = PTHREAD_MUTEX_INITIALIZER; IoCtxDistributor* IoCtxDistributor::instance() { IoCtxDistributor *ret; pthread_mutex_lock(&io_ctx_distributor_lock); if (s_instance == NULL) { s_instance = new IoCtxDistributor(); } ret = s_instance; pthread_mutex_unlock(&io_ctx_distributor_lock); return ret; } int IoCtxDistributor::init(Rados &cluster, const char *pool_name, int num_ioctxes) { m_io_ctxes.resize(num_ioctxes); for (std::vector::iterator i = m_io_ctxes.begin(); i != m_io_ctxes.end(); ++i) { IoCtx &io_ctx(*i); int ret = cluster.ioctx_create(pool_name, io_ctx); if (ret) { return ret; } } m_highest_iod_idx.set(0); return 0; } void IoCtxDistributor::clear() { for (std::vector::iterator i = m_io_ctxes.begin(); i != m_io_ctxes.end(); ++i) { IoCtx &io_ctx(*i); io_ctx.close(); } m_io_ctxes.clear(); m_highest_iod_idx.set(0); } IoCtx& IoCtxDistributor::get_ioctx() { if (t_iod_idx == -1) { t_iod_idx = m_highest_iod_idx.inc() - 1; } if (m_io_ctxes.size() <= (unsigned int)t_iod_idx) { cerr << ERR_PREFIX << "IoCtxDistributor: logic error on line " << __LINE__ << std::endl; _exit(1); } return m_io_ctxes[t_iod_idx]; } IoCtxDistributor *IoCtxDistributor::s_instance = NULL; IoCtxDistributor::IoCtxDistributor() { clear(); } IoCtxDistributor::~IoCtxDistributor() { clear(); } RadosSyncWQ::RadosSyncWQ(IoCtxDistributor *io_ctx_dist, time_t timeout, time_t suicide_timeout, ThreadPool *tp) : ThreadPool::WorkQueue("FileStore::OpWQ", timeout, suicide_timeout, tp), m_io_ctx_dist(io_ctx_dist) { } bool RadosSyncWQ::_enqueue(std::string *s) { m_items.push_back(s); return true; } void RadosSyncWQ::_dequeue(std::string *o) { assert(0); } bool RadosSyncWQ::_empty() { return m_items.empty(); } std::string *RadosSyncWQ::_dequeue() { if (m_items.empty()) return NULL; std::string *ret = m_items.front(); m_items.pop_front(); return ret; } void RadosSyncWQ::_process_finish(std::string *s) { delete s; } void RadosSyncWQ::_clear() { for (std::deque::iterator i = m_items.begin(); i != m_items.end(); ++i) { delete *i; } m_items.clear(); } Xattr::Xattr(char *data_, ssize_t len_) : data(data_), len(len_) { } Xattr::~Xattr() { free(data); } bool Xattr::operator==(const class Xattr &rhs) const { if (len != rhs.len) return false; return (memcmp(data, rhs.data, len) == 0); } bool Xattr::operator!=(const class Xattr &rhs) const { return !((*this) == rhs); } int BackedUpObject::from_file(const char *file_name, const char *dir_name, std::auto_ptr &obj) { char obj_path[strlen(dir_name) + strlen(file_name) + 2]; snprintf(obj_path, sizeof(obj_path), "%s/%s", dir_name, file_name); return BackedUpObject::from_path(obj_path, obj); } int BackedUpObject::from_path(const char *path, std::auto_ptr &obj) { int ret; FILE *fp = fopen(path, "r"); if (!fp) { ret = errno; if (ret != ENOENT) { cerr << ERR_PREFIX << "BackedUpObject::from_path: error while trying to " << "open '" << path << "': " << cpp_strerror(ret) << std::endl; } return ret; } int fd = fileno(fp); struct stat st_buf; memset(&st_buf, 0, sizeof(st_buf)); ret = fstat(fd, &st_buf); if (ret) { ret = errno; fclose(fp); cerr << ERR_PREFIX << "BackedUpObject::from_path: error while trying " << "to stat '" << path << "': " << cpp_strerror(ret) << std::endl; return ret; } // get fullname ssize_t res = ceph_os_fgetxattr(fd, XATTR_FULLNAME, NULL, 0); if (res <= 0) { fclose(fp); ret = errno; if (res == 0) { cerr << ERR_PREFIX << "BackedUpObject::from_path: found empty " << XATTR_FULLNAME << " attribute on '" << path << "'" << std::endl; ret = ENODATA; } else if (ret == ENODATA) { cerr << ERR_PREFIX << "BackedUpObject::from_path: there was no " << XATTR_FULLNAME << " attribute found on '" << path << "'" << std::endl; } else { cerr << ERR_PREFIX << "getxattr error: " << cpp_strerror(ret) << std::endl; } return ret; } char rados_name_[res + 1]; memset(rados_name_, 0, sizeof(rados_name_)); res = ceph_os_fgetxattr(fd, XATTR_FULLNAME, rados_name_, res); if (res < 0) { ret = errno; fclose(fp); cerr << ERR_PREFIX << "BackedUpObject::getxattr(" << XATTR_FULLNAME << ") error: " << cpp_strerror(ret) << std::endl; return ret; } BackedUpObject *o = new BackedUpObject(rados_name_, st_buf.st_size, st_buf.st_mtime); if (!o) { fclose(fp); return ENOBUFS; } ret = o->read_xattrs_from_file(fileno(fp)); if (ret) { fclose(fp); cerr << ERR_PREFIX << "BackedUpObject::from_path(path = '" << path << "): read_xattrs_from_file returned " << ret << std::endl; delete o; return ret; } fclose(fp); obj.reset(o); return 0; } int BackedUpObject::from_rados(IoCtx& io_ctx, const char *rados_name_, auto_ptr &obj) { uint64_t rados_size_ = 0; time_t rados_time_ = 0; int ret = io_ctx.stat(rados_name_, &rados_size_, &rados_time_); if (ret == -ENOENT) { // don't complain here about ENOENT return ret; } else if (ret < 0) { cerr << ERR_PREFIX << "BackedUpObject::from_rados(rados_name_ = '" << rados_name_ << "'): stat failed with error " << ret << std::endl; return ret; } BackedUpObject *o = new BackedUpObject(rados_name_, rados_size_, rados_time_); ret = o->read_xattrs_from_rados(io_ctx); if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_rados(rados_name_ = '" << rados_name_ << "'): read_xattrs_from_rados returned " << ret << std::endl; delete o; return ret; } obj.reset(o); return 0; } BackedUpObject::~BackedUpObject() { for (std::map < std::string, Xattr* >::iterator x = xattrs.begin(); x != xattrs.end(); ++x) { delete x->second; x->second = NULL; } free(rados_name); } std::string BackedUpObject::get_fs_path(const ExportDir *export_dir) const { return export_dir->get_fs_path(rados_name); } std::string BackedUpObject::xattrs_to_str() const { ostringstream oss; std::string prefix; for (std::map < std::string, Xattr* >::const_iterator x = xattrs.begin(); x != xattrs.end(); ++x) { char buf[x->second->len + 1]; memcpy(buf, x->second->data, x->second->len); buf[x->second->len] = '\0'; oss << prefix << "{" << x->first << ":" << buf << "}"; prefix = ", "; } return oss.str(); } void BackedUpObject::xattr_diff(const BackedUpObject *rhs, std::list < std::string > &only_in_a, std::list < std::string > &only_in_b, std::list < std::string > &diff) const { only_in_a.clear(); only_in_b.clear(); diff.clear(); for (std::map < std::string, Xattr* >::const_iterator x = xattrs.begin(); x != xattrs.end(); ++x) { std::map < std::string, Xattr* >::const_iterator r = rhs->xattrs.find(x->first); if (r == rhs->xattrs.end()) { only_in_a.push_back(x->first); } else { const Xattr &r_obj(*r->second); const Xattr &x_obj(*x->second); if (r_obj != x_obj) diff.push_back(x->first); } } for (std::map < std::string, Xattr* >::const_iterator r = rhs->xattrs.begin(); r != rhs->xattrs.end(); ++r) { std::map < std::string, Xattr* >::const_iterator x = rhs->xattrs.find(r->first); if (x == xattrs.end()) { only_in_b.push_back(r->first); } } } void BackedUpObject::get_xattrs(std::list < std::string > &xattrs_) const { for (std::map < std::string, Xattr* >::const_iterator r = xattrs.begin(); r != xattrs.end(); ++r) { xattrs_.push_back(r->first); } } const Xattr* BackedUpObject::get_xattr(const std::string &name) const { std::map < std::string, Xattr* >::const_iterator x = xattrs.find(name); if (x == xattrs.end()) return NULL; else return x->second; } const char *BackedUpObject::get_rados_name() const { return rados_name; } uint64_t BackedUpObject::get_rados_size() const { return rados_size; } time_t BackedUpObject::get_mtime() const { return rados_time; } int BackedUpObject::download(IoCtx &io_ctx, const char *path) { char tmp_path[strlen(path) + RADOS_SYNC_TMP_SUFFIX_LEN + 1]; snprintf(tmp_path, sizeof(tmp_path), "%s%s", path, RADOS_SYNC_TMP_SUFFIX); FILE *fp = fopen(tmp_path, "w"); if (!fp) { int err = errno; cerr << ERR_PREFIX << "download: error opening '" << tmp_path << "':" << cpp_strerror(err) << std::endl; return err; } int fd = fileno(fp); uint64_t off = 0; static const int CHUNK_SZ = 32765; while (true) { bufferlist bl; int rlen = io_ctx.read(rados_name, bl, CHUNK_SZ, off); if (rlen < 0) { cerr << ERR_PREFIX << "download: io_ctx.read(" << rados_name << ") returned " << rlen << std::endl; fclose(fp); return rlen; } if (rlen < CHUNK_SZ) off = 0; else off += rlen; size_t flen = fwrite(bl.c_str(), 1, rlen, fp); if (flen != (size_t)rlen) { int err = errno; cerr << ERR_PREFIX << "download: fwrite(" << tmp_path << ") error: " << cpp_strerror(err) << std::endl; fclose(fp); return err; } if (off == 0) break; } size_t attr_sz = strlen(rados_name) + 1; int res = ceph_os_fsetxattr(fd, XATTR_FULLNAME, rados_name, attr_sz); if (res) { int err = errno; cerr << ERR_PREFIX << "download: fsetxattr(" << tmp_path << ") error: " << cpp_strerror(err) << std::endl; fclose(fp); return err; } if (fclose(fp)) { int err = errno; cerr << ERR_PREFIX << "download: fclose(" << tmp_path << ") error: " << cpp_strerror(err) << std::endl; return err; } if (rename(tmp_path, path)) { int err = errno; cerr << ERR_PREFIX << "download: rename(" << tmp_path << ", " << path << ") error: " << cpp_strerror(err) << std::endl; return err; } return 0; } int BackedUpObject::upload(IoCtx &io_ctx, const char *file_name, const char *dir_name) { char path[strlen(file_name) + strlen(dir_name) + 2]; snprintf(path, sizeof(path), "%s/%s", dir_name, file_name); FILE *fp = fopen(path, "r"); if (!fp) { int err = errno; cerr << ERR_PREFIX << "upload: error opening '" << path << "': " << cpp_strerror(err) << std::endl; return err; } // Need to truncate RADOS object to size 0, in case there is // already something there. int ret = io_ctx.trunc(rados_name, 0); if (ret) { cerr << ERR_PREFIX << "upload: trunc failed with error " << ret << std::endl; fclose(fp); return ret; } uint64_t off = 0; static const int CHUNK_SZ = 32765; while (true) { char buf[CHUNK_SZ]; int flen = fread(buf, 1, CHUNK_SZ, fp); if (flen < 0) { int err = errno; cerr << ERR_PREFIX << "upload: fread(" << file_name << ") error: " << cpp_strerror(err) << std::endl; fclose(fp); return err; } if ((flen == 0) && (off != 0)) { fclose(fp); break; } // There must be a zero-copy way to do this? bufferlist bl; bl.append(buf, flen); int rlen = io_ctx.write(rados_name, bl, flen, off); if (rlen < 0) { fclose(fp); cerr << ERR_PREFIX << "upload: rados_write error: " << rlen << std::endl; return rlen; } if (rlen != flen) { fclose(fp); cerr << ERR_PREFIX << "upload: rados_write error: short write" << std::endl; return -EIO; } off += rlen; if (flen < CHUNK_SZ) { fclose(fp); return 0; } } return 0; } BackedUpObject::BackedUpObject(const char *rados_name_, uint64_t rados_size_, time_t rados_time_) : rados_name(strdup(rados_name_)), rados_size(rados_size_), rados_time(rados_time_) { } int BackedUpObject::read_xattrs_from_file(int fd) { ssize_t blen = ceph_os_flistxattr(fd, NULL, 0); if (blen > 0x1000000) { cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_file: unwilling " << "to allocate a buffer of size " << blen << " on the stack for " << "flistxattr." << std::endl; return ENOBUFS; } char buf[blen + 1]; memset(buf, 0, sizeof(buf)); ssize_t blen2 = ceph_os_flistxattr(fd, buf, blen); if (blen != blen2) { cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_file: xattrs changed while " << "we were trying to " << "list them? First length was " << blen << ", but now it's " << blen2 << std::endl; return EDOM; } const char *b = buf; while (*b) { size_t bs = strlen(b); std::string xattr_name = get_user_xattr_name(b); if (!xattr_name.empty()) { ssize_t attr_len = ceph_os_fgetxattr(fd, b, NULL, 0); if (attr_len < 0) { int err = errno; cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_file: " << "fgetxattr(rados_name = '" << rados_name << "', xattr_name='" << xattr_name << "') failed: " << cpp_strerror(err) << std::endl; return EDOM; } char *attr = (char*)malloc(attr_len); if (!attr) { cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_file: " << "malloc(" << attr_len << ") failed for xattr_name='" << xattr_name << "'" << std::endl; return ENOBUFS; } ssize_t attr_len2 = ceph_os_fgetxattr(fd, b, attr, attr_len); if (attr_len2 < 0) { int err = errno; cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_file: " << "fgetxattr(rados_name = '" << rados_name << "', " << "xattr_name='" << xattr_name << "') failed: " << cpp_strerror(err) << std::endl; free(attr); return EDOM; } if (attr_len2 != attr_len) { cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_file: xattr " << "changed while we were trying to get it? " << "fgetxattr(rados_name = '"<< rados_name << "', xattr_name='" << xattr_name << "') returned a different length " << "than when we first called it! old_len = " << attr_len << "new_len = " << attr_len2 << std::endl; free(attr); return EDOM; } xattrs[xattr_name] = new Xattr(attr, attr_len); } b += (bs + 1); } return 0; } int BackedUpObject::read_xattrs_from_rados(IoCtx &io_ctx) { map attrset; int ret = io_ctx.getxattrs(rados_name, attrset); if (ret) { cerr << ERR_PREFIX << "BackedUpObject::read_xattrs_from_rados: " << "getxattrs failed with error code " << ret << std::endl; return ret; } for (map::iterator i = attrset.begin(); i != attrset.end(); ) { bufferlist& bl(i->second); char *data = (char*)malloc(bl.length()); if (!data) return ENOBUFS; memcpy(data, bl.c_str(), bl.length()); Xattr *xattr = new Xattr(data, bl.length()); if (!xattr) { free(data); return ENOBUFS; } xattrs[i->first] = xattr; attrset.erase(i++); } return 0; } int rados_tool_sync(const std::map < std::string, std::string > &opts, std::vector &args) { int ret; bool force = opts.count("force"); bool delete_after = opts.count("delete-after"); bool create = opts.count("create"); std::map < std::string, std::string >::const_iterator n = opts.find("workers"); int num_threads; if (n == opts.end()) { num_threads = DEFAULT_NUM_RADOS_WORKER_THREADS; } else { std::string err; num_threads = strict_strtol(n->second.c_str(), 10, &err); if (!err.empty()) { cerr << "rados: can't parse number of worker threads given: " << err << std::endl; return 1; } if ((num_threads < 1) || (num_threads > 9000)) { cerr << "rados: unreasonable value given for num_threads: " << num_threads << std::endl; return 1; } } std::string action, src, dst; std::vector::iterator i = args.begin(); if ((i != args.end()) && ((strcmp(*i, "import") == 0) || (strcmp(*i, "export") == 0))) { action = *i; ++i; } else { cerr << "rados" << ": You must specify either 'import' or 'export'.\n"; cerr << "Use --help to show help.\n"; exit(1); } if (i != args.end()) { src = *i; ++i; } else { cerr << "rados" << ": You must give a source.\n"; cerr << "Use --help to show help.\n"; exit(1); } if (i != args.end()) { dst = *i; ++i; } else { cerr << "rados" << ": You must give a destination.\n"; cerr << "Use --help to show help.\n"; exit(1); } // open rados Rados rados; if (rados.init_with_context(g_ceph_context) < 0) { cerr << "rados" << ": failed to initialize Rados!" << std::endl; exit(1); } if (rados.connect() < 0) { cerr << "rados" << ": failed to connect to Rados cluster!" << std::endl; exit(1); } IoCtx io_ctx; std::string pool_name = (action == "import") ? dst : src; ret = rados.ioctx_create(pool_name.c_str(), io_ctx); if ((ret == -ENOENT) && (action == "import")) { if (create) { ret = rados.pool_create(pool_name.c_str()); if (ret) { cerr << "rados" << ": pool_create failed with error " << ret << std::endl; exit(ret); } ret = rados.ioctx_create(pool_name.c_str(), io_ctx); } else { cerr << "rados" << ": pool '" << pool_name << "' does not exist. Use " << "--create to try to create it." << std::endl; exit(ENOENT); } } if (ret < 0) { cerr << "rados" << ": error opening pool " << pool_name << ": " << cpp_strerror(ret) << std::endl; exit(ret); } IoCtxDistributor *io_ctx_dist = IoCtxDistributor::instance(); ret = io_ctx_dist->init(rados, pool_name.c_str(), num_threads); if (ret) { cerr << ERR_PREFIX << "failed to initialize Rados io contexts." << std::endl; _exit(ret); } ThreadPool thread_pool(g_ceph_context, "rados_sync_threadpool", num_threads); thread_pool.start(); if (action == "import") { ret = do_rados_import(&thread_pool, io_ctx, io_ctx_dist, src.c_str(), force, delete_after); thread_pool.stop(); return ret; } else { ret = do_rados_export(&thread_pool, io_ctx, io_ctx_dist, dst.c_str(), create, force, delete_after); thread_pool.stop(); return ret; } } ceph-0.80.11/src/tools/rados/rados_export.cc0000664000175100017510000001565012623076744022763 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2011 New Dream Network * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/int_types.h" #include "rados_sync.h" #include "common/errno.h" #include "common/strtol.h" #include "include/rados/librados.hpp" #include #include #include #include #include #include #include #include #include #include #include #include "include/compat.h" #include "common/xattr.h" using namespace librados; class ExportLocalFileWQ : public RadosSyncWQ { public: ExportLocalFileWQ(IoCtxDistributor *io_ctx_dist, time_t ti, ThreadPool *tp, ExportDir *export_dir, bool force) : RadosSyncWQ(io_ctx_dist, ti, 0, tp), m_export_dir(export_dir), m_force(force) { } private: void _process(std::string *s) { IoCtx &io_ctx(m_io_ctx_dist->get_ioctx()); int flags = 0; auto_ptr sobj; auto_ptr dobj; const std::string &rados_name(*s); std::list < std::string > only_in_a; std::list < std::string > only_in_b; std::list < std::string > diff; int ret = BackedUpObject::from_rados(io_ctx, rados_name.c_str(), sobj); if (ret) { cerr << ERR_PREFIX << "couldn't get '" << rados_name << "' from rados: error " << ret << std::endl; _exit(ret); } std::string obj_path(sobj->get_fs_path(m_export_dir)); if (m_force) { flags |= (CHANGED_CONTENTS | CHANGED_XATTRS); } else { ret = BackedUpObject::from_path(obj_path.c_str(), dobj); if (ret == ENOENT) { sobj->get_xattrs(only_in_a); flags |= CHANGED_CONTENTS; } else if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_path returned " << ret << std::endl; _exit(ret); } else { sobj->xattr_diff(dobj.get(), only_in_a, only_in_b, diff); if ((sobj->get_rados_size() == dobj->get_rados_size()) && (sobj->get_mtime() == dobj->get_mtime())) { flags |= CHANGED_CONTENTS; } } } if (flags & CHANGED_CONTENTS) { ret = sobj->download(io_ctx, obj_path.c_str()); if (ret) { cerr << ERR_PREFIX << "download error: " << ret << std::endl; _exit(ret); } } diff.splice(diff.begin(), only_in_a); for (std::list < std::string >::const_iterator x = diff.begin(); x != diff.end(); ++x) { flags |= CHANGED_XATTRS; const Xattr *xattr = sobj->get_xattr(*x); if (xattr == NULL) { cerr << ERR_PREFIX << "internal error on line: " << __LINE__ << std::endl; _exit(ret); } std::string xattr_fs_name(USER_XATTR_PREFIX); xattr_fs_name += x->c_str(); ret = ceph_os_setxattr(obj_path.c_str(), xattr_fs_name.c_str(), xattr->data, xattr->len); if (ret) { ret = errno; cerr << ERR_PREFIX << "setxattr error: " << cpp_strerror(ret) << std::endl; _exit(ret); } } for (std::list < std::string >::const_iterator x = only_in_b.begin(); x != only_in_b.end(); ++x) { flags |= CHANGED_XATTRS; ret = ceph_os_removexattr(obj_path.c_str(), x->c_str()); if (ret) { ret = errno; cerr << ERR_PREFIX << "removexattr error: " << cpp_strerror(ret) << std::endl; _exit(ret); } } if (m_force) { cout << "[force] " << rados_name << std::endl; } else if (flags & CHANGED_CONTENTS) { cout << "[exported] " << rados_name << std::endl; } else if (flags & CHANGED_XATTRS) { cout << "[xattr] " << rados_name << std::endl; } } ExportDir *m_export_dir; bool m_force; }; class ExportValidateExistingWQ : public RadosSyncWQ { public: ExportValidateExistingWQ(IoCtxDistributor *io_ctx_dist, time_t ti, ThreadPool *tp, const char *dir_name) : RadosSyncWQ(io_ctx_dist, ti, 0, tp), m_dir_name(dir_name) { } private: void _process(std::string *s) { IoCtx &io_ctx(m_io_ctx_dist->get_ioctx()); auto_ptr lobj; const std::string &local_name(*s); int ret = BackedUpObject::from_file(local_name.c_str(), m_dir_name, lobj); if (ret) { cout << ERR_PREFIX << "BackedUpObject::from_file: delete loop: " << "got error " << ret << std::endl; _exit(ret); } auto_ptr robj; ret = BackedUpObject::from_rados(io_ctx, lobj->get_rados_name(), robj); if (ret == -ENOENT) { // The entry doesn't exist on the remote server; delete it locally char path[strlen(m_dir_name) + local_name.size() + 2]; snprintf(path, sizeof(path), "%s/%s", m_dir_name, local_name.c_str()); if (unlink(path)) { ret = errno; cerr << ERR_PREFIX << "error unlinking '" << path << "': " << cpp_strerror(ret) << std::endl; _exit(ret); } cout << "[deleted] " << "removed '" << local_name << "'" << std::endl; } else if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_rados: delete loop: " << "got error " << ret << std::endl; _exit(ret); } } const char *m_dir_name; }; int do_rados_export(ThreadPool *tp, IoCtx& io_ctx, IoCtxDistributor *io_ctx_dist, const char *dir_name, bool create, bool force, bool delete_after) { librados::ObjectIterator oi = io_ctx.objects_begin(); librados::ObjectIterator oi_end = io_ctx.objects_end(); auto_ptr export_dir; export_dir.reset(ExportDir::create_for_writing(dir_name, 1, create)); if (!export_dir.get()) return -EIO; ExportLocalFileWQ export_object_wq(io_ctx_dist, time(NULL), tp, export_dir.get(), force); for (; oi != oi_end; ++oi) { export_object_wq.queue(new std::string((*oi).first)); } export_object_wq.drain(); if (delete_after) { ExportValidateExistingWQ export_val_wq(io_ctx_dist, time(NULL), tp, dir_name); DirHolder dh; int err = dh.opendir(dir_name); if (err) { cerr << ERR_PREFIX << "opendir(" << dir_name << ") error: " << cpp_strerror(err) << std::endl; return err; } while (true) { struct dirent *de = readdir(dh.dp); if (!de) break; if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) continue; if (is_suffix(de->d_name, RADOS_SYNC_TMP_SUFFIX)) { char path[strlen(dir_name) + strlen(de->d_name) + 2]; snprintf(path, sizeof(path), "%s/%s", dir_name, de->d_name); if (unlink(path)) { int ret = errno; cerr << ERR_PREFIX << "error unlinking temporary file '" << path << "': " << cpp_strerror(ret) << std::endl; return ret; } cout << "[deleted] " << "removed temporary file '" << de->d_name << "'" << std::endl; continue; } export_val_wq.queue(new std::string(de->d_name)); } export_val_wq.drain(); } cout << "[done]" << std::endl; return 0; } ceph-0.80.11/src/tools/ceph_osdomap_tool.cc0000664000175100017510000001115412623076744022633 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License kkjversion 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global/global_init.h" #include "os/LevelDBStore.h" #include "mon/MonitorDBStore.h" #include "os/DBObjectMap.h" #include "common/errno.h" namespace po = boost::program_options; using namespace std; int main(int argc, char **argv) { po::options_description desc("Allowed options"); string store_path, cmd, out_path; bool paranoid = false; desc.add_options() ("help", "produce help message") ("omap-path", po::value(&store_path), "path to mon directory, mandatory (current/omap usually)") ("paranoid", po::value(¶noid), "use paranoid checking") ("command", po::value(&cmd), "command") ; po::positional_options_description p; p.add("command", 1); po::variables_map vm; po::parsed_options parsed = po::command_line_parser(argc, argv).options(desc).positional(p).run(); po::store( parsed, vm); try { po::notify(vm); } catch (...) { cout << desc << std::endl; return 1; } vector ceph_options, def_args; vector ceph_option_strings = po::collect_unrecognized( parsed.options, po::include_positional); ceph_options.reserve(ceph_option_strings.size()); for (vector::iterator i = ceph_option_strings.begin(); i != ceph_option_strings.end(); ++i) { ceph_options.push_back(i->c_str()); } global_init( &def_args, ceph_options, CEPH_ENTITY_TYPE_OSD, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); g_conf = g_ceph_context->_conf; if (vm.count("help")) { std::cerr << desc << std::endl; return 1; } LevelDBStore* store(new LevelDBStore(g_ceph_context, store_path)); if (paranoid) { std::cerr << "Enabling paranoid checks" << std::endl; store->options.paranoid_checks = paranoid; } DBObjectMap omap(store); stringstream out; int r = store->open(out); if (r < 0) { std::cerr << "Store open got: " << cpp_strerror(r) << std::endl; std::cerr << "Output: " << out.str() << std::endl; goto done; } r = 0; if (cmd == "dump-raw-keys") { KeyValueDB::WholeSpaceIterator i = store->get_iterator(); for (i->seek_to_first(); i->valid(); i->next()) { std::cout << i->raw_key() << std::endl; } } else if (cmd == "dump-raw-key-vals") { KeyValueDB::WholeSpaceIterator i = store->get_iterator(); for (i->seek_to_first(); i->valid(); i->next()) { std::cout << i->raw_key() << std::endl; i->value().hexdump(std::cout); } } else if (cmd == "dump-objects") { vector objects; r = omap.list_objects(&objects); if (r < 0) { std::cerr << "list_objects got: " << cpp_strerror(r) << std::endl; goto done; } for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { std::cout << *i << std::endl; } r = 0; } else if (cmd == "dump-objects-with-keys") { vector objects; r = omap.list_objects(&objects); if (r < 0) { std::cerr << "list_objects got: " << cpp_strerror(r) << std::endl; goto done; } for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { std::cout << "Object: " << *i << std::endl; ObjectMap::ObjectMapIterator j = omap.get_iterator(i->hobj); for (j->seek_to_first(); j->valid(); j->next()) { std::cout << j->key() << std::endl; j->value().hexdump(std::cout); } } } else if (cmd == "check") { r = omap.check(std::cout); if (!r) { std::cerr << "check got: " << cpp_strerror(r) << std::endl; goto done; } std::cout << "check succeeded" << std::endl; } else { std::cerr << "Did not recognize command " << cmd << std::endl; goto done; } done: return r; } ceph-0.80.11/src/tools/Makefile.am0000664000175100017510000000613512623076744020665 0ustar jenkins-buildjenkins-buildceph_osdomap_tool_SOURCES = tools/ceph_osdomap_tool.cc ceph_osdomap_tool_LDADD = $(LIBOS) $(CEPH_GLOBAL) $(BOOST_PROGRAM_OPTIONS_LIBS) bin_DEBUGPROGRAMS += ceph-osdomap-tool ceph_monstore_tool_SOURCES = tools/ceph_monstore_tool.cc ceph_monstore_tool_LDADD = $(LIBOS) $(CEPH_GLOBAL) $(BOOST_PROGRAM_OPTIONS_LIBS) bin_DEBUGPROGRAMS += ceph-monstore-tool ceph_kvstore_tool_SOURCES = tools/ceph_kvstore_tool.cc ceph_kvstore_tool_LDADD = $(LIBOS) $(CEPH_GLOBAL) ceph_kvstore_tool_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph-kvstore-tool ceph_objectstore_tool_SOURCES = tools/ceph_objectstore_tool.cc ceph_objectstore_tool_LDADD = $(LIBOSD) $(LIBOS) $(CEPH_GLOBAL) $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBRADOS) if LINUX ceph_objectstore_tool_LDADD += -ldl endif # LINUX bin_PROGRAMS += ceph-objectstore-tool monmaptool_SOURCES = tools/monmaptool.cc monmaptool_LDADD = $(CEPH_GLOBAL) $(LIBCOMMON) bin_PROGRAMS += monmaptool crushtool_SOURCES = tools/crushtool.cc crushtool_LDADD = $(CEPH_GLOBAL) bin_PROGRAMS += crushtool osdmaptool_SOURCES = tools/osdmaptool.cc osdmaptool_LDADD = $(CEPH_GLOBAL) bin_PROGRAMS += osdmaptool ceph_scratchtool_SOURCES = tools/scratchtool.c ceph_scratchtool_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_scratchtool ceph_scratchtoolpp_SOURCES = tools/scratchtoolpp.cc ceph_scratchtoolpp_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_scratchtoolpp ceph_psim_SOURCES = tools/psim.cc ceph_psim_LDADD = $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_psim ceph_dupstore_SOURCES = tools/dupstore.cc ceph_dupstore_LDADD = $(LIBOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_dupstore ceph_radosacl_SOURCES = tools/radosacl.cc ceph_radosacl_LDADD = $(LIBRADOS) $(CEPH_GLOBAL) bin_DEBUGPROGRAMS += ceph_radosacl ceph_client_debug_SOURCES = tools/ceph-client-debug.cc ceph_client_debug_LDADD = $(LIBCEPHFS) $(CEPH_GLOBAL) $(LIBCOMMON) bin_DEBUGPROGRAMS += ceph-client-debug rados_SOURCES = \ tools/rados/rados.cc \ tools/rados/rados_import.cc \ tools/rados/rados_export.cc \ tools/rados/rados_sync.cc rados_SOURCES += common/obj_bencher.cc # needs cleanup so it can go in libcommon.la rados_LDADD = libcls_lock_client.la $(LIBRADOS) $(CEPH_GLOBAL) bin_PROGRAMS += rados if WITH_REST_BENCH rest_bench_SOURCES = tools/rest_bench.cc rest_bench_SOURCES += common/obj_bencher.cc # needs cleanup so it can go in libcommon.la rest_bench_LDADD = $(CEPH_GLOBAL) bin_PROGRAMS += rest-bench if WITH_SYSTEM_LIBS3 rest_bench_LDADD += -ls3 else rest_bench_LDADD += libs3/build/lib/libs3.a -lcurl -lxml2 rest_bench_CXXFLAGS = ${AM_CXXFLAGS} -I$(top_srcdir)/src/libs3/inc SUBDIRS += libs3 endif # WITH_SYSTEM_LIBS3 endif # WITH_REST_BENCH ceph_conf_SOURCES = tools/ceph_conf.cc ceph_conf_LDADD = $(CEPH_GLOBAL) $(LIBCOMMON) bin_PROGRAMS += ceph-conf ceph_authtool_SOURCES = tools/ceph_authtool.cc ceph_authtool_LDADD = $(CEPH_GLOBAL) $(LIBCOMMON) bin_PROGRAMS += ceph-authtool ceph_mon_store_converter_SOURCES = tools/mon_store_converter.cc ceph_mon_store_converter_LDADD = $(LIBMON) $(LIBOS) $(CEPH_GLOBAL) bin_PROGRAMS += ceph_mon_store_converter noinst_HEADERS += \ tools/rados/rados_sync.h \ tools/common.h ceph-0.80.11/src/tools/mon_store_converter.cc0000664000175100017510000002120312623076744023225 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2012 Inktank, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #include #include #include #include #include #include #include #include "include/types.h" #include "include/buffer.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "common/debug.h" #include "common/config.h" #include "mon/MonitorDBStore.h" #include "mon/MonitorStore.h" using namespace std; class MonitorStoreConverter { boost::scoped_ptr db; boost::scoped_ptr store; set gvs; version_t highest_last_pn; version_t highest_accepted_pn; static const int PAXOS_MAX_VERSIONS = 50; string MONITOR_NAME; public: MonitorStoreConverter(string &store_path, string &db_store_path) : db(0), store(0), highest_last_pn(0), highest_accepted_pn(0), MONITOR_NAME("monitor") { MonitorStore *store_ptr = new MonitorStore(store_path); assert(!store_ptr->mount()); store.reset(store_ptr); MonitorDBStore *db_ptr = new MonitorDBStore(db_store_path); db.reset(db_ptr); } int convert() { if (db->open(std::cerr) >= 0) { std::cerr << "store already exists" << std::endl; return EEXIST; } assert(!db->create_and_open(std::cerr)); if (db->exists("mon_convert", "on_going")) { std::cout << __func__ << " found a mon store in mid-convertion; abort!" << std::endl; return EEXIST; } _mark_convert_start(); _convert_monitor(); _convert_machines(); _mark_convert_finish(); std::cout << __func__ << " finished conversion" << std::endl; return 0; } bool match() { return true; } private: set _get_machines_names() { set names; names.insert("auth"); names.insert("logm"); names.insert("mdsmap"); names.insert("monmap"); names.insert("osdmap"); names.insert("pgmap"); return names; } void _mark_convert_start() { MonitorDBStore::Transaction tx; tx.put("mon_convert", "on_going", 1); db->apply_transaction(tx); } void _mark_convert_finish() { MonitorDBStore::Transaction tx; tx.erase("mon_convert", "on_going"); db->apply_transaction(tx); } void _convert_monitor() { assert(store->exists_bl_ss("magic")); assert(store->exists_bl_ss("keyring")); assert(store->exists_bl_ss("feature_set")); assert(store->exists_bl_ss("election_epoch")); MonitorDBStore::Transaction tx; if (store->exists_bl_ss("joined")) { version_t joined = store->get_int("joined"); tx.put(MONITOR_NAME, "joined", joined); } vector keys; keys.push_back("magic"); keys.push_back("feature_set"); keys.push_back("election_epoch"); keys.push_back("cluster_uuid"); vector::iterator it; for (it = keys.begin(); it != keys.end(); ++it) { if (!store->exists_bl_ss((*it).c_str())) continue; bufferlist bl; int r = store->get_bl_ss(bl, (*it).c_str(), 0); assert(r > 0); tx.put(MONITOR_NAME, *it, bl); } assert(!tx.empty()); db->apply_transaction(tx); } void _convert_machines(string machine) { std::cout << __func__ << " " << machine << std::endl; version_t first_committed = store->get_int(machine.c_str(), "first_committed"); version_t last_committed = store->get_int(machine.c_str(), "last_committed"); version_t accepted_pn = store->get_int(machine.c_str(), "accepted_pn"); version_t last_pn = store->get_int(machine.c_str(), "last_pn"); if (accepted_pn > highest_accepted_pn) highest_accepted_pn = accepted_pn; if (last_pn > highest_last_pn) highest_last_pn = last_pn; string machine_gv(machine); machine_gv.append("_gv"); bool has_gv = true; if (!store->exists_bl_ss(machine_gv.c_str())) { std::cerr << __func__ << " " << machine << " no gv dir '" << machine_gv << "'" << std::endl; has_gv = false; } for (version_t ver = first_committed; ver <= last_committed; ver++) { if (!store->exists_bl_sn(machine.c_str(), ver)) { std::cerr << __func__ << " " << machine << " ver " << ver << " dne" << std::endl; continue; } bufferlist bl; int r = store->get_bl_sn(bl, machine.c_str(), ver); assert(r >= 0); std::cout << __func__ << " " << machine << " ver " << ver << " bl " << bl.length() << std::endl; MonitorDBStore::Transaction tx; tx.put(machine, ver, bl); tx.put(machine, "last_committed", ver); if (has_gv && store->exists_bl_sn(machine_gv.c_str(), ver)) { stringstream s; s << ver; string ver_str = s.str(); version_t gv = store->get_int(machine_gv.c_str(), ver_str.c_str()); std::cerr << __func__ << " " << machine << " ver " << ver << " -> " << gv << std::endl; if (gvs.count(gv) == 0) { gvs.insert(gv); } else { std::cerr << __func__ << " " << machine << " gv " << gv << " already exists" << std::endl; } bufferlist tx_bl; tx.encode(tx_bl); tx.put("paxos", gv, tx_bl); } db->apply_transaction(tx); } version_t lc = db->get(machine, "last_committed"); assert(lc == last_committed); MonitorDBStore::Transaction tx; tx.put(machine, "first_committed", first_committed); tx.put(machine, "last_committed", last_committed); if (store->exists_bl_ss(machine.c_str(), "latest")) { bufferlist latest_bl_raw; int r = store->get_bl_ss(latest_bl_raw, machine.c_str(), "latest"); assert(r >= 0); if (!latest_bl_raw.length()) { std::cerr << __func__ << " machine " << machine << " skip latest with size 0" << std::endl; goto out; } tx.put(machine, "latest", latest_bl_raw); bufferlist::iterator lbl_it = latest_bl_raw.begin(); bufferlist latest_bl; version_t latest_ver; ::decode(latest_ver, lbl_it); ::decode(latest_bl, lbl_it); std::cout << __func__ << " machine " << machine << " latest ver " << latest_ver << std::endl; tx.put(machine, "full_latest", latest_ver); stringstream os; os << "full_" << latest_ver; tx.put(machine, os.str(), latest_bl); } out: db->apply_transaction(tx); } void _convert_paxos() { assert(!gvs.empty()); set::reverse_iterator rit = gvs.rbegin(); version_t highest_gv = *rit; version_t last_gv = highest_gv; int n = 0; for (; (rit != gvs.rend()) && (n < PAXOS_MAX_VERSIONS); ++rit, ++n) { version_t gv = *rit; if (last_gv == gv) continue; if ((last_gv - gv) > 1) { // we are done; we found a gap and we are only interested in keeping // contiguous paxos versions. break; } last_gv = gv; } // erase all paxos versions between [first, last_gv[, with first being the // first gv in the map. MonitorDBStore::Transaction tx; set::iterator it = gvs.begin(); std::cout << __func__ << " first gv " << (*it) << " last gv " << last_gv << std::endl; for (; it != gvs.end() && (*it < last_gv); ++it) { tx.erase("paxos", *it); } tx.put("paxos", "first_committed", last_gv); tx.put("paxos", "last_committed", highest_gv); tx.put("paxos", "accepted_pn", highest_accepted_pn); tx.put("paxos", "last_pn", highest_last_pn); db->apply_transaction(tx); } void _convert_machines() { set machine_names = _get_machines_names(); set::iterator it = machine_names.begin(); std::cout << __func__ << std::endl; for (; it != machine_names.end(); ++it) { _convert_machines(*it); } _convert_paxos(); } }; void usage(const char *pname) { std::cerr << "Usage: " << pname << " \n" << std::endl; } int main(int argc, const char *argv[]) { vector def_args; vector args; const char *our_name = argv[0]; argv_to_vec(argc, argv, args); global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); g_ceph_context->_conf->apply_changes(NULL); if (args.empty()) { usage(our_name); return 1; } string store(args[0]); string new_store(store); MonitorStoreConverter converter(store, new_store); assert(!converter.convert()); assert(converter.match()); std::cout << "store successfully converted to new format" << std::endl; return 0; } ceph-0.80.11/src/tools/ceph_objectstore_tool.cc0000664000175100017510000024154712623076744023527 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2013 Inktank * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include "common/Formatter.h" #include "common/errno.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "os/ObjectStore.h" #include "os/FileStore.h" #include "osd/PGLog.h" #include "osd/OSD.h" #include "json_spirit/json_spirit_value.h" #include "json_spirit/json_spirit_reader.h" #include "include/rados/librados.hpp" namespace po = boost::program_options; using namespace std; enum { TYPE_NONE = 0, TYPE_PG_BEGIN, TYPE_PG_END, TYPE_OBJECT_BEGIN, TYPE_OBJECT_END, TYPE_DATA, TYPE_ATTRS, TYPE_OMAP_HDR, TYPE_OMAP, TYPE_PG_METADATA, END_OF_TYPES, //Keep at the end }; //#define INTERNAL_TEST //#define INTERNAL_TEST2 //#define INTERNAL_TEST3 #ifdef INTERNAL_TEST CompatSet get_test_compat_set() { CompatSet::FeatureSet ceph_osd_feature_compat; CompatSet::FeatureSet ceph_osd_feature_ro_compat; CompatSet::FeatureSet ceph_osd_feature_incompat; ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BASE); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_PGINFO); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_OLOC); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEC); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_CATEGORIES); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_HOBJECTPOOL); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_BIGINFO); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEVELDBINFO); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_LEVELDBLOG); #ifdef INTERNAL_TEST2 ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SNAPMAPPER); ceph_osd_feature_incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); #endif return CompatSet(ceph_osd_feature_compat, ceph_osd_feature_ro_compat, ceph_osd_feature_incompat); } #endif typedef uint8_t sectiontype_t; typedef uint32_t mymagic_t; typedef int64_t mysize_t; const ssize_t max_read = 1024 * 1024; const uint16_t shortmagic = 0xffce; //goes into stream as "ceff" //endmagic goes into stream as "ceff ffec" const mymagic_t endmagic = (0xecff << 16) | shortmagic; const int fd_none = INT_MIN; bool outistty; //The first FIXED_LENGTH bytes are a fixed //portion of the export output. This includes the overall //version number, and size of header and footer. //THIS STRUCTURE CAN ONLY BE APPENDED TO. If it needs to expand, //the version can be bumped and then anything //can be added to the export format. struct super_header { static const uint32_t super_magic = (shortmagic << 16) | shortmagic; // ver = 1, Initial version // ver = 2, Add OSDSuperblock to pg_begin static const uint32_t super_ver = 2; static const uint32_t FIXED_LENGTH = 16; uint32_t magic; uint32_t version; uint32_t header_size; uint32_t footer_size; super_header() : magic(0), version(0), header_size(0), footer_size(0) { } int read_super(); void encode(bufferlist& bl) const { ::encode(magic, bl); ::encode(version, bl); ::encode(header_size, bl); ::encode(footer_size, bl); } void decode(bufferlist::iterator& bl) { ::decode(magic, bl); ::decode(version, bl); ::decode(header_size, bl); ::decode(footer_size, bl); } }; struct header { sectiontype_t type; mysize_t size; header(sectiontype_t type, mysize_t size) : type(type), size(size) { } header(): type(0), size(0) { } int get_header(); void encode(bufferlist& bl) const { uint32_t debug_type = (type << 24) | (type << 16) | shortmagic; ENCODE_START(1, 1, bl); ::encode(debug_type, bl); ::encode(size, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { uint32_t debug_type; DECODE_START(1, bl); ::decode(debug_type, bl); type = debug_type >> 24; ::decode(size, bl); DECODE_FINISH(bl); } }; struct footer { mymagic_t magic; footer() : magic(endmagic) { } int get_footer(); void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(magic, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(magic, bl); DECODE_FINISH(bl); } }; struct pg_begin { spg_t pgid; OSDSuperblock superblock; pg_begin(spg_t pg, const OSDSuperblock& sb): pgid(pg), superblock(sb) { } pg_begin() { } void encode(bufferlist& bl) const { // If superblock doesn't include CEPH_FS_FEATURE_INCOMPAT_SHARDS then // shard will be NO_SHARD for a replicated pool. This means // that we allow the decode by struct_v 2. ENCODE_START(3, 2, bl); ::encode(pgid.pgid, bl); ::encode(superblock, bl); ::encode(pgid.shard, bl); ENCODE_FINISH(bl); } // NOTE: New super_ver prevents decode from ver 1 void decode(bufferlist::iterator& bl) { DECODE_START(3, bl); ::decode(pgid.pgid, bl); if (struct_v > 1) { ::decode(superblock, bl); } if (struct_v > 2) { ::decode(pgid.shard, bl); } else { pgid.shard = ghobject_t::NO_SHARD; } DECODE_FINISH(bl); } }; struct object_begin { ghobject_t hoid; // Duplicate what is in the OI_ATTR so we have it at the start // of object processing. object_info_t oi; object_begin(const ghobject_t &hoid): hoid(hoid) { } object_begin() { } // If superblock doesn't include CEPH_FS_FEATURE_INCOMPAT_SHARDS then // generation will be NO_GEN, shard_id will be NO_SHARD for a replicated // pool. This means we will allow the decode by struct_v 1. void encode(bufferlist& bl) const { ENCODE_START(3, 1, bl); ::encode(hoid.hobj, bl); ::encode(hoid.generation, bl); ::encode(hoid.shard_id, bl); ::encode(oi, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(3, bl); ::decode(hoid.hobj, bl); if (struct_v > 1) { ::decode(hoid.generation, bl); ::decode(hoid.shard_id, bl); } else { hoid.generation = ghobject_t::NO_GEN; hoid.shard_id = ghobject_t::NO_SHARD; } if (struct_v > 2) { ::decode(oi, bl); } DECODE_FINISH(bl); } }; struct data_section { uint64_t offset; uint64_t len; bufferlist databl; data_section(uint64_t offset, uint64_t len, bufferlist bl): offset(offset), len(len), databl(bl) { } data_section(): offset(0), len(0) { } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(offset, bl); ::encode(len, bl); ::encode(databl, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(offset, bl); ::decode(len, bl); ::decode(databl, bl); DECODE_FINISH(bl); } }; struct attr_section { map data; attr_section(const map &data) : data(data) { } attr_section() { } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(data, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(data, bl); DECODE_FINISH(bl); } }; struct omap_hdr_section { bufferlist hdr; omap_hdr_section(bufferlist hdr) : hdr(hdr) { } omap_hdr_section() { } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(hdr, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(hdr, bl); DECODE_FINISH(bl); } }; struct omap_section { map omap; omap_section(const map &omap) : omap(omap) { } omap_section() { } void encode(bufferlist& bl) const { ENCODE_START(1, 1, bl); ::encode(omap, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(1, bl); ::decode(omap, bl); DECODE_FINISH(bl); } }; struct metadata_section { __u8 struct_ver; epoch_t map_epoch; pg_info_t info; pg_log_t log; map past_intervals; OSDMap osdmap; metadata_section(__u8 struct_ver, epoch_t map_epoch, const pg_info_t &info, const pg_log_t &log, map &past_intervals) : struct_ver(struct_ver), map_epoch(map_epoch), info(info), log(log), past_intervals(past_intervals) { } metadata_section() : struct_ver(0), map_epoch(0) { } void encode(bufferlist& bl) const { ENCODE_START(3, 1, bl); ::encode(struct_ver, bl); ::encode(map_epoch, bl); ::encode(info, bl); ::encode(log, bl); ::encode(past_intervals, bl); osdmap.encode(bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { DECODE_START(3, bl); ::decode(struct_ver, bl); ::decode(map_epoch, bl); ::decode(info, bl); ::decode(log, bl); if (struct_v > 1) { ::decode(past_intervals, bl); } else { cout << "NOTICE: Older export without past_intervals" << std::endl; } if (struct_v > 2) { osdmap.decode(bl); } else { cout << "WARNING: Older export without OSDMap information" << std::endl; } DECODE_FINISH(bl); } }; struct action_on_object_t { virtual ~action_on_object_t() {} virtual int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) = 0; }; int _action_on_all_objects_in_pg(ObjectStore *store, coll_t coll, action_on_object_t &action, bool debug) { unsigned LIST_AT_A_TIME = 100; ghobject_t next; while (!next.is_max()) { vector list; int r = store->collection_list_partial( coll, next, LIST_AT_A_TIME, LIST_AT_A_TIME, 0, &list, &next); if (r < 0) { cerr << "Error listing collection: " << coll << ", " << cpp_strerror(r) << std::endl; return r; } for (vector::iterator obj = list.begin(); obj != list.end(); ++obj) { bufferlist attr; r = store->getattr(coll, *obj, OI_ATTR, attr); if (r < 0) { cerr << "Error getting attr on : " << make_pair(coll, *obj) << ", " << cpp_strerror(r) << std::endl; return r; } object_info_t oi; bufferlist::iterator bp = attr.begin(); try { ::decode(oi, bp); } catch (...) { r = -EINVAL; cerr << "Error getting attr on : " << make_pair(coll, *obj) << ", " << cpp_strerror(r) << std::endl; return r; } r = action.call(store, coll, *obj, oi); if (r < 0) return r; } } return 0; } int action_on_all_objects_in_pg(ObjectStore *store, coll_t coll, action_on_object_t &action, bool debug) { int r = _action_on_all_objects_in_pg(store, coll, action, debug); store->sync_and_flush(); return r; } int _action_on_all_objects(ObjectStore *store, action_on_object_t &action, bool debug) { unsigned scanned = 0; int r = 0; vector colls_to_check; vector candidates; r = store->list_collections(candidates); if (r < 0) { cerr << "Error listing collections: " << cpp_strerror(r) << std::endl; return r; } for (vector::iterator i = candidates.begin(); i != candidates.end(); ++i) { spg_t pgid; snapid_t snap; if (i->is_pg(pgid, snap)) { colls_to_check.push_back(*i); } } if (debug) cerr << colls_to_check.size() << " pgs to scan" << std::endl; for (vector::iterator i = colls_to_check.begin(); i != colls_to_check.end(); ++i, ++scanned) { if (debug) cerr << "Scanning " << *i << ", " << scanned << "/" << colls_to_check.size() << " completed" << std::endl; r = _action_on_all_objects_in_pg(store, *i, action, debug); if (r < 0) return r; } return 0; } int action_on_all_objects(ObjectStore *store, action_on_object_t &action, bool debug) { int r = _action_on_all_objects(store, action, debug); store->sync_and_flush(); return r; } struct pgid_object_list { list > _objects; void insert(coll_t coll, ghobject_t &ghobj) { _objects.push_back(make_pair(coll, ghobj)); } void dump(Formatter *f, bool human_readable) const { if (!human_readable) f->open_array_section("pgid_objects"); for (list >::const_iterator i = _objects.begin(); i != _objects.end(); ++i) { if (i != _objects.begin() && human_readable) { f->flush(cout); cout << std::endl; } f->open_array_section("pgid_object"); string pgid = i->first.c_str(); std::size_t pos = pgid.find("_"); if (pos == string::npos) f->dump_string("pgid", pgid); else f->dump_string("pgid", pgid.substr(0, pos)); f->open_object_section("ghobject"); i->second.dump(f); f->close_section(); f->close_section(); } if (!human_readable) f->close_section(); } }; struct lookup_ghobject : public action_on_object_t { pgid_object_list _objects; const string _name; lookup_ghobject(const string& name) : _name(name) { } virtual int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) { if (_name.length() == 0 || ghobj.hobj.oid.name == _name) _objects.insert(coll, ghobj); return 0; } int size() const { return _objects._objects.size(); } pair pop() { pair front = _objects._objects.front(); _objects._objects.pop_front(); return front; } void dump(Formatter *f, bool human_readable) const { _objects.dump(f, human_readable); } }; hobject_t infos_oid = OSD::make_infos_oid(); hobject_t biginfo_oid, log_oid; int file_fd = fd_none; bool debug = false; super_header sh; uint64_t testalign; template int write_section(sectiontype_t type, const T& obj, int fd) { bufferlist blhdr, bl, blftr; obj.encode(bl); header hdr(type, bl.length()); hdr.encode(blhdr); footer ft; ft.encode(blftr); int ret = blhdr.write_fd(fd); if (ret) return ret; ret = bl.write_fd(fd); if (ret) return ret; ret = blftr.write_fd(fd); return ret; } // Convert non-printable characters to '\###' static void cleanbin(string &str) { bool cleaned = false; string clean; for (string::iterator it = str.begin(); it != str.end(); ++it) { if (!isprint(*it)) { clean.push_back('\\'); clean.push_back('0' + ((*it >> 6) & 7)); clean.push_back('0' + ((*it >> 3) & 7)); clean.push_back('0' + (*it & 7)); cleaned = true; } else { clean.push_back(*it); } } if (cleaned) str = clean; return; } int write_simple(sectiontype_t type, int fd) { bufferlist hbl; header hdr(type, 0); hdr.encode(hbl); return hbl.write_fd(fd); } static int get_fd_data(int fd, bufferlist &bl) { uint64_t total = 0; do { ssize_t bytes = bl.read_fd(fd, max_read); if (bytes < 0) { cerr << "read_fd error " << cpp_strerror(-bytes) << std::endl; return 1; } if (bytes == 0) break; total += bytes; } while(true); assert(bl.length() == total); return 0; } static void invalid_filestore_path(string &path) { cerr << "Invalid filestore path specified: " << path << "\n"; exit(1); } int get_log(ObjectStore *fs, coll_t coll, spg_t pgid, const pg_info_t &info, PGLog::IndexedLog &log, pg_missing_t &missing) { map divergent_priors; try { ostringstream oss; PGLog::read_log(fs, coll, log_oid, info, divergent_priors, log, missing, oss); if (debug && oss.str().size()) cerr << oss.str() << std::endl; } catch (const buffer::error &e) { cerr << "read_log threw exception error " << e.what() << std::endl; return 1; } return 0; } //Based on RemoveWQ::_process() void remove_coll(ObjectStore *store, const coll_t &coll) { spg_t pg; coll.is_pg_prefix(pg); OSDriver driver( store, coll_t(), OSD::make_snapmapper_oid()); SnapMapper mapper(&driver, 0, 0, 0, pg.shard); ghobject_t next; int r = 0; int64_t num = 0; ObjectStore::Transaction *t = new ObjectStore::Transaction; cout << "remove_coll " << coll << std::endl; while (!next.is_max()) { vector objects; r = store->collection_list_partial(coll, next, 200, 300, 0, &objects, &next); if (r < 0) goto out; for (vector::iterator i = objects.begin(); i != objects.end(); ++i, ++num) { OSDriver::OSTransaction _t(driver.get_transaction(t)); cout << "remove " << *i << std::endl; int r = mapper.remove_oid(i->hobj, &_t); if (r != 0 && r != -ENOENT) { assert(0); } t->remove(coll, *i); if (num >= 30) { store->apply_transaction(*t); delete t; t = new ObjectStore::Transaction; num = 0; } } } t->remove_collection(coll); store->apply_transaction(*t); out: delete t; } //Based on part of OSD::load_pgs() int finish_remove_pgs(ObjectStore *store, uint64_t *next_removal_seq) { vector ls; int r = store->list_collections(ls); if (r < 0) { cerr << "finish_remove_pgs: failed to list pgs: " << cpp_strerror(-r) << std::endl; return r; } for (vector::iterator it = ls.begin(); it != ls.end(); ++it) { spg_t pgid; if (it->is_temp(pgid)) { cout << "finish_remove_pgs " << *it << " clearing temp" << std::endl; OSD::recursive_remove_collection(store, *it); continue; } uint64_t seq; if (it->is_removal(&seq, &pgid)) { if (seq >= *next_removal_seq) *next_removal_seq = seq + 1; cout << "finish_remove_pgs removing " << *it << ", seq is " << seq << " pgid is " << pgid << std::endl; remove_coll(store, *it); continue; } //cout << "finish_remove_pgs ignoring unrecognized " << *it << std::endl; } return 0; } int initiate_new_remove_pg(ObjectStore *store, spg_t r_pgid, uint64_t *next_removal_seq) { ObjectStore::Transaction *rmt = new ObjectStore::Transaction; if (store->collection_exists(coll_t(r_pgid))) { coll_t to_remove = coll_t::make_removal_coll((*next_removal_seq)++, r_pgid); cout << "collection rename " << coll_t(r_pgid) << " to " << to_remove << std::endl; rmt->collection_rename(coll_t(r_pgid), to_remove); } else { delete rmt; return ENOENT; } cout << "remove " << coll_t::META_COLL << " " << log_oid.oid << std::endl; rmt->remove(coll_t::META_COLL, log_oid); cout << "remove " << coll_t::META_COLL << " " << biginfo_oid.oid << std::endl; rmt->remove(coll_t::META_COLL, biginfo_oid); store->apply_transaction(*rmt); return 0; } int header::get_header() { bufferlist ebl; bufferlist::iterator ebliter = ebl.begin(); ssize_t bytes; bytes = ebl.read_fd(file_fd, sh.header_size); if ((size_t)bytes != sh.header_size) { cerr << "Unexpected EOF" << std::endl; return EFAULT; } decode(ebliter); return 0; } int footer::get_footer() { bufferlist ebl; bufferlist::iterator ebliter = ebl.begin(); ssize_t bytes; bytes = ebl.read_fd(file_fd, sh.footer_size); if ((size_t)bytes != sh.footer_size) { cerr << "Unexpected EOF" << std::endl; return EFAULT; } decode(ebliter); if (magic != endmagic) { cerr << "Bad footer magic" << std::endl; return EFAULT; } return 0; } int write_info(ObjectStore::Transaction &t, epoch_t epoch, pg_info_t &info, __u8 struct_ver, map &past_intervals) { //Empty for this interval_set snap_collections; // obsolete coll_t coll(info.pgid); int ret = PG::_write_info(t, epoch, info, coll, past_intervals, snap_collections, infos_oid, struct_ver, true, true); if (ret < 0) ret = -ret; if (ret) cerr << "Failed to write info" << std::endl; return ret; } void write_log(ObjectStore::Transaction &t, pg_log_t &log) { map divergent_priors; PGLog::write_log(t, log, log_oid, divergent_priors); } int write_pg(ObjectStore::Transaction &t, epoch_t epoch, pg_info_t &info, pg_log_t &log, __u8 struct_ver, map &past_intervals) { int ret = write_info(t, epoch, info, struct_ver, past_intervals); if (ret) return ret; write_log(t, log); return 0; } const int OMAP_BATCH_SIZE = 25; void get_omap_batch(ObjectMap::ObjectMapIterator &iter, map &oset) { oset.clear(); for (int count = OMAP_BATCH_SIZE; count && iter->valid(); --count, iter->next()) { oset.insert(pair(iter->key(), iter->value())); } } int export_file(ObjectStore *store, coll_t cid, ghobject_t &obj) { struct stat st; mysize_t total; footer ft; int ret = store->stat(cid, obj, &st); if (ret < 0) return ret; cerr << "Read " << obj << std::endl; total = st.st_size; if (debug) cerr << "size=" << total << std::endl; object_begin objb(obj); { bufferptr bp; bufferlist bl; ret = store->getattr(cid, obj, OI_ATTR, bp); if (ret < 0) { cerr << "getattr failure object_info " << ret << std::endl; return ret; } bl.push_back(bp); decode(objb.oi, bl); if (debug) cerr << "object_info: " << objb.oi << std::endl; } // XXX: Should we be checking for WHITEOUT or LOST in objb.oi.flags and skip? ret = write_section(TYPE_OBJECT_BEGIN, objb, file_fd); if (ret < 0) return ret; uint64_t offset = 0; bufferlist rawdatabl; while(total > 0) { rawdatabl.clear(); mysize_t len = max_read; if (len > total) len = total; ret = store->read(cid, obj, offset, len, rawdatabl); if (ret < 0) return ret; if (ret == 0) return -EINVAL; data_section dblock(offset, len, rawdatabl); if (debug) cerr << "data section offset=" << offset << " len=" << len << std::endl; total -= ret; offset += ret; ret = write_section(TYPE_DATA, dblock, file_fd); if (ret) return ret; } //Handle attrs for this object map aset; ret = store->getattrs(cid, obj, aset, false); if (ret) return ret; attr_section as(aset); ret = write_section(TYPE_ATTRS, as, file_fd); if (ret) return ret; if (debug) { cerr << "attrs size " << aset.size() << std::endl; } //Handle omap information bufferlist hdrbuf; ret = store->omap_get_header(cid, obj, &hdrbuf, true); if (ret < 0) { cerr << "omap_get_header: " << cpp_strerror(-ret) << std::endl; return ret; } omap_hdr_section ohs(hdrbuf); ret = write_section(TYPE_OMAP_HDR, ohs, file_fd); if (ret) return ret; ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(cid, obj); if (!iter) { ret = -ENOENT; cerr << "omap_get_iterator: " << cpp_strerror(-ret) << std::endl; return ret; } iter->seek_to_first(); int mapcount = 0; map out; while(iter->valid()) { get_omap_batch(iter, out); if (out.empty()) break; mapcount += out.size(); omap_section oms(out); ret = write_section(TYPE_OMAP, oms, file_fd); if (ret) return ret; } if (debug) cerr << "omap map size " << mapcount << std::endl; ret = write_simple(TYPE_OBJECT_END, file_fd); if (ret) return ret; return 0; } int export_files(ObjectStore *store, coll_t coll) { ghobject_t next; while (!next.is_max()) { vector objects; int r = store->collection_list_partial(coll, next, 200, 300, 0, &objects, &next); if (r < 0) return r; for (vector::iterator i = objects.begin(); i != objects.end(); ++i) { r = export_file(store, coll, *i); if (r < 0) return r; } } return 0; } int get_osdmap(ObjectStore *store, epoch_t e, OSDMap &osdmap) { bufferlist bl; bool found = store->read( coll_t::META_COLL, OSD::get_osdmap_pobject_name(e), 0, 0, bl) >= 0; if (!found) { cerr << "Can't find OSDMap for pg epoch " << e << std::endl; return ENOENT; } osdmap.decode(bl); if (debug) cerr << osdmap << std::endl; return 0; } int add_osdmap(ObjectStore *store, metadata_section &ms) { return get_osdmap(store, ms.map_epoch, ms.osdmap); } //Write super_header with its fixed 16 byte length void write_super() { bufferlist superbl; super_header sh; footer ft; header hdr(TYPE_NONE, 0); hdr.encode(superbl); sh.magic = super_header::super_magic; sh.version = super_header::super_ver; sh.header_size = superbl.length(); superbl.clear(); ft.encode(superbl); sh.footer_size = superbl.length(); superbl.clear(); sh.encode(superbl); assert(super_header::FIXED_LENGTH == superbl.length()); superbl.write_fd(file_fd); } int do_export(ObjectStore *fs, coll_t coll, spg_t pgid, pg_info_t &info, epoch_t map_epoch, __u8 struct_ver, const OSDSuperblock& superblock, map &past_intervals) { PGLog::IndexedLog log; pg_missing_t missing; cerr << "Exporting " << pgid << std::endl; int ret = get_log(fs, coll, pgid, info, log, missing); if (ret > 0) return ret; write_super(); pg_begin pgb(pgid, superblock); // Special case: If replicated pg don't require the importing OSD to have shard feature if (pgid.is_no_shard()) { pgb.superblock.compat_features.incompat.remove(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); } ret = write_section(TYPE_PG_BEGIN, pgb, file_fd); if (ret) return ret; // The metadata_section is now before files, so import can detect // errors and abort without wasting time. metadata_section ms(struct_ver, map_epoch, info, log, past_intervals); ret = add_osdmap(fs, ms); if (ret) return ret; ret = write_section(TYPE_PG_METADATA, ms, file_fd); if (ret) return ret; ret = export_files(fs, coll); if (ret) { cerr << "export_files error " << ret << std::endl; return ret; } ret = write_simple(TYPE_PG_END, file_fd); if (ret) return ret; return 0; } int super_header::read_super() { bufferlist ebl; bufferlist::iterator ebliter = ebl.begin(); ssize_t bytes; bytes = ebl.read_fd(file_fd, super_header::FIXED_LENGTH); if ((size_t)bytes != super_header::FIXED_LENGTH) { cerr << "Unexpected EOF" << std::endl; return EFAULT; } decode(ebliter); return 0; } int read_section(int fd, sectiontype_t *type, bufferlist *bl) { header hdr; ssize_t bytes; int ret = hdr.get_header(); if (ret) return ret; *type = hdr.type; bl->clear(); bytes = bl->read_fd(fd, hdr.size); if (bytes != hdr.size) { cerr << "Unexpected EOF" << std::endl; return EFAULT; } if (hdr.size > 0) { footer ft; ret = ft.get_footer(); if (ret) return ret; } return 0; } int get_data(ObjectStore *store, coll_t coll, ghobject_t hoid, ObjectStore::Transaction *t, bufferlist &bl) { bufferlist::iterator ebliter = bl.begin(); data_section ds; ds.decode(ebliter); if (debug) cerr << "\tdata: offset " << ds.offset << " len " << ds.len << std::endl; t->write(coll, hoid, ds.offset, ds.len, ds.databl); return 0; } int get_attrs(ObjectStore *store, coll_t coll, ghobject_t hoid, ObjectStore::Transaction *t, bufferlist &bl, OSDriver &driver, SnapMapper &snap_mapper) { bufferlist::iterator ebliter = bl.begin(); attr_section as; as.decode(ebliter); if (debug) cerr << "\tattrs: len " << as.data.size() << std::endl; t->setattrs(coll, hoid, as.data); // This could have been handled in the caller if we didn't need to // support exports that didn't include object_info_t in object_begin. if (hoid.hobj.snap < CEPH_MAXSNAP && hoid.generation == ghobject_t::NO_GEN) { map::iterator mi = as.data.find(OI_ATTR); if (mi != as.data.end()) { bufferlist attr_bl; attr_bl.push_back(mi->second); object_info_t oi(attr_bl); if (debug) cerr << "object_info " << oi << std::endl; OSDriver::OSTransaction _t(driver.get_transaction(t)); set oi_snaps(oi.snaps.begin(), oi.snaps.end()); snap_mapper.add_oid(hoid.hobj, oi_snaps, &_t); } } return 0; } int get_omap_hdr(ObjectStore *store, coll_t coll, ghobject_t hoid, ObjectStore::Transaction *t, bufferlist &bl) { bufferlist::iterator ebliter = bl.begin(); omap_hdr_section oh; oh.decode(ebliter); if (debug) cerr << "\tomap header: " << string(oh.hdr.c_str(), oh.hdr.length()) << std::endl; t->omap_setheader(coll, hoid, oh.hdr); return 0; } int get_omap(ObjectStore *store, coll_t coll, ghobject_t hoid, ObjectStore::Transaction *t, bufferlist &bl) { bufferlist::iterator ebliter = bl.begin(); omap_section os; os.decode(ebliter); if (debug) cerr << "\tomap: size " << os.omap.size() << std::endl; t->omap_setkeys(coll, hoid, os.omap); return 0; } int skip_object(bufferlist &bl) { bufferlist::iterator ebliter = bl.begin(); bufferlist ebl; bool done = false; while(!done) { sectiontype_t type; int ret = read_section(file_fd, &type, &ebl); if (ret) return ret; ebliter = ebl.begin(); if (type >= END_OF_TYPES) { cout << "Skipping unknown object section type" << std::endl; continue; } switch(type) { case TYPE_DATA: case TYPE_ATTRS: case TYPE_OMAP_HDR: case TYPE_OMAP: if (debug) cerr << "Skip type " << (int)type << std::endl; break; case TYPE_OBJECT_END: done = true; break; default: return EFAULT; } } return 0; } int get_object_rados(librados::IoCtx &ioctx, bufferlist &bl) { bufferlist::iterator ebliter = bl.begin(); object_begin ob; ob.decode(ebliter); map::iterator i; bufferlist abl; data_section ds; attr_section as; omap_hdr_section oh; omap_section os; assert(g_ceph_context); if (ob.hoid.hobj.nspace == g_ceph_context->_conf->osd_hit_set_namespace) { cout << "Skipping internal object " << ob.hoid << std::endl; skip_object(bl); return 0; } if (!ob.hoid.hobj.is_head()) { cout << "Skipping non-head for " << ob.hoid << std::endl; skip_object(bl); return 0; } ioctx.set_namespace(ob.hoid.hobj.get_namespace()); string msg("Write"); int ret = ioctx.create(ob.hoid.hobj.oid.name, true); if (ret && ret != -EEXIST) { cerr << "create failed: " << cpp_strerror(ret) << std::endl; return ret; } if (ret == -EEXIST) { msg = "***Overwrite***"; ret = ioctx.remove(ob.hoid.hobj.oid.name); if (ret < 0) { cerr << "remove failed: " << cpp_strerror(ret) << std::endl; return ret; } ret = ioctx.create(ob.hoid.hobj.oid.name, true); if (ret < 0) { cerr << "create failed: " << cpp_strerror(ret) << std::endl; return ret; } } cout << msg << " " << ob.hoid << std::endl; bool need_align = false; uint64_t alignment = 0; if (testalign) { need_align = true; alignment = testalign; } else { if ((need_align = ioctx.pool_requires_alignment())) alignment = ioctx.pool_required_alignment(); } if (debug && need_align) cerr << "alignment = " << alignment << std::endl; bufferlist ebl, databl; uint64_t in_offset = 0, out_offset = 0; bool done = false; while(!done) { sectiontype_t type; int ret = read_section(file_fd, &type, &ebl); if (ret) return ret; ebliter = ebl.begin(); //cout << "\tdo_object: Section type " << hex << type << dec << std::endl; //cout << "\t\tsection size " << ebl.length() << std::endl; if (type >= END_OF_TYPES) { cout << "Skipping unknown object section type" << std::endl; continue; } switch(type) { case TYPE_DATA: ds.decode(ebliter); if (debug) cerr << "\tdata: offset " << ds.offset << " len " << ds.len << std::endl; if (need_align) { if (ds.offset != in_offset) { cerr << "Discontiguous object data in export" << std::endl; return EFAULT; } assert(ds.databl.length() == ds.len); databl.claim_append(ds.databl); in_offset += ds.len; if (databl.length() >= alignment) { uint64_t rndlen = uint64_t(databl.length() / alignment) * alignment; if (debug) cerr << "write offset=" << out_offset << " len=" << rndlen << std::endl; ret = ioctx.write(ob.hoid.hobj.oid.name, databl, rndlen, out_offset); if (ret) { cerr << "write failed: " << cpp_strerror(ret) << std::endl; return ret; } out_offset += rndlen; bufferlist n; if (databl.length() > rndlen) { assert(databl.length() - rndlen < alignment); n.substr_of(databl, rndlen, databl.length() - rndlen); } databl = n; } break; } ret = ioctx.write(ob.hoid.hobj.oid.name, ds.databl, ds.len, ds.offset); if (ret) { cerr << "write failed: " << cpp_strerror(ret) << std::endl; return ret; } break; case TYPE_ATTRS: as.decode(ebliter); if (debug) cerr << "\tattrs: len " << as.data.size() << std::endl; for (i = as.data.begin(); i != as.data.end(); ++i) { if (i->first == "_" || i->first == "snapset") continue; abl.clear(); abl.push_front(i->second); ret = ioctx.setxattr(ob.hoid.hobj.oid.name, i->first.substr(1).c_str(), abl); if (ret) { cerr << "setxattr failed: " << cpp_strerror(ret) << std::endl; if (ret != -EOPNOTSUPP) return ret; } } break; case TYPE_OMAP_HDR: oh.decode(ebliter); if (debug) cerr << "\tomap header: " << string(oh.hdr.c_str(), oh.hdr.length()) << std::endl; ret = ioctx.omap_set_header(ob.hoid.hobj.oid.name, oh.hdr); if (ret) { cerr << "omap_set_header failed: " << cpp_strerror(ret) << std::endl; if (ret != -EOPNOTSUPP) return ret; } break; case TYPE_OMAP: os.decode(ebliter); if (debug) cerr << "\tomap: size " << os.omap.size() << std::endl; ret = ioctx.omap_set(ob.hoid.hobj.oid.name, os.omap); if (ret) { cerr << "omap_set failed: " << cpp_strerror(ret) << std::endl; if (ret != -EOPNOTSUPP) return ret; } break; case TYPE_OBJECT_END: if (need_align && databl.length() > 0) { assert(databl.length() < alignment); if (debug) cerr << "END write offset=" << out_offset << " len=" << databl.length() << std::endl; ret = ioctx.write(ob.hoid.hobj.oid.name, databl, databl.length(), out_offset); if (ret) { cerr << "write failed: " << cpp_strerror(ret) << std::endl; return ret; } } done = true; break; default: return EFAULT; } } return 0; } int get_object(ObjectStore *store, coll_t coll, bufferlist &bl, OSDMap &curmap, coll_t final_coll) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; bufferlist::iterator ebliter = bl.begin(); object_begin ob; ob.decode(ebliter); OSDriver driver( store, coll_t(), OSD::make_snapmapper_oid()); spg_t pg; coll.is_pg_prefix(pg); SnapMapper mapper(&driver, 0, 0, 0, pg.shard); assert(g_ceph_context); if (ob.hoid.hobj.nspace != g_ceph_context->_conf->osd_hit_set_namespace) { object_t oid = ob.hoid.hobj.oid; object_locator_t loc(ob.hoid.hobj); // XXX: Do we need to set the hash? // loc.hash = ob.hoid.hash; pg_t raw_pgid = curmap.object_locator_to_pg(oid, loc); pg_t pgid = curmap.raw_pg_to_pg(raw_pgid); spg_t coll_pgid; snapid_t coll_snap; if (final_coll.is_pg(coll_pgid, coll_snap) == false) { cerr << "INTERNAL ERROR: Bad collection during import" << std::endl; return 1; } if (coll_pgid.shard != ob.hoid.shard_id) { cerr << "INTERNAL ERROR: Importing shard " << coll_pgid.shard << " but object shard is " << ob.hoid.shard_id << std::endl; return 1; } if (coll_pgid.pgid != pgid) { cerr << "Skipping object '" << ob.hoid << "' which no longer belongs in exported pg" << std::endl; skip_object(bl); return 0; } } t->touch(coll, ob.hoid); cout << "Write " << ob.hoid << std::endl; bufferlist ebl; bool done = false; while(!done) { sectiontype_t type; int ret = read_section(file_fd, &type, &ebl); if (ret) return ret; //cout << "\tdo_object: Section type " << hex << type << dec << std::endl; //cout << "\t\tsection size " << ebl.length() << std::endl; if (type >= END_OF_TYPES) { cout << "Skipping unknown object section type" << std::endl; continue; } switch(type) { case TYPE_DATA: ret = get_data(store, coll, ob.hoid, t, ebl); if (ret) return ret; break; case TYPE_ATTRS: ret = get_attrs(store, coll, ob.hoid, t, ebl, driver, mapper); if (ret) return ret; break; case TYPE_OMAP_HDR: ret = get_omap_hdr(store, coll, ob.hoid, t, ebl); if (ret) return ret; break; case TYPE_OMAP: ret = get_omap(store, coll, ob.hoid, t, ebl); if (ret) return ret; break; case TYPE_OBJECT_END: done = true; break; default: return EFAULT; } } store->apply_transaction(*t); return 0; } int get_pg_metadata(ObjectStore *store, bufferlist &bl, metadata_section &ms, const OSDSuperblock& sb, OSDMap& curmap) { bufferlist::iterator ebliter = bl.begin(); ms.decode(ebliter); #if DIAGNOSTIC Formatter *formatter = new JSONFormatter(true); cout << "struct_v " << (int)ms.struct_ver << std::endl; cout << "map epoch " << ms.map_epoch << std::endl; formatter->open_object_section("importing OSDMap"); ms.osdmap.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; cout << "osd current epoch " << sb.current_epoch << std::endl; formatter->open_object_section("current OSDMap"); curmap.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; formatter->open_object_section("info"); ms.info.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; formatter->open_object_section("log"); ms.log.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; #endif if (ms.map_epoch > sb.current_epoch) { cerr << "ERROR: Export map_epoch " << ms.map_epoch << " > osd epoch " << sb.current_epoch << std::endl; return 1; } // If the osdmap was present in the metadata we can check for splits. // Pool verified to exist for call to get_pg_num(). if (ms.map_epoch < sb.current_epoch) { bool found_map = false; OSDMap findmap; int ret = get_osdmap(store, ms.map_epoch, findmap); if (ret == 0) found_map = true; // Old export didn't include OSDMap if (ms.osdmap.get_epoch() == 0) { // If we found the map locally and an older export didn't have it, // then we'll use the local one. if (found_map) { ms.osdmap = findmap; } else { cerr << "WARNING: No OSDMap in old export," " some objects may be ignored due to a split" << std::endl; } } // If OSDMap is available check for splits if (ms.osdmap.get_epoch()) { spg_t parent(ms.info.pgid); if (parent.is_split(ms.osdmap.get_pg_num(ms.info.pgid.pgid.m_pool), curmap.get_pg_num(ms.info.pgid.pgid.m_pool), NULL)) { cerr << "WARNING: Split occurred, some objects may be ignored" << std::endl; } } } ms.past_intervals.clear(); ms.info.history.same_interval_since = ms.map_epoch = sb.current_epoch; return 0; } int do_import_rados(string pool) { bufferlist ebl; pg_info_t info; PGLog::IndexedLog log; int ret = sh.read_super(); if (ret) return ret; if (sh.magic != super_header::super_magic) { cerr << "Invalid magic number" << std::endl; return EFAULT; } if (sh.version > super_header::super_ver) { cerr << "Can't handle export format version=" << sh.version << std::endl; return EINVAL; } //First section must be TYPE_PG_BEGIN sectiontype_t type; ret = read_section(file_fd, &type, &ebl); if (ret) return ret; if (type != TYPE_PG_BEGIN) { return EFAULT; } bufferlist::iterator ebliter = ebl.begin(); pg_begin pgb; pgb.decode(ebliter); spg_t pgid = pgb.pgid; if (!pgid.is_no_shard()) { cerr << "Importing Erasure Coded shard is not supported" << std::endl; exit(1); } if (debug) { cerr << "Exported features: " << pgb.superblock.compat_features << std::endl; } // XXX: How to check export features? #if 0 if (sb.compat_features.compare(pgb.superblock.compat_features) == -1) { cerr << "Export has incompatible features set " << pgb.superblock.compat_features << std::endl; return 1; } #endif librados::IoCtx ioctx; librados::Rados cluster; char *id = getenv("CEPH_CLIENT_ID"); if (id) cerr << "Client id is: " << id << std::endl; ret = cluster.init(id); if (ret) { cerr << "Error " << ret << " in cluster.init" << std::endl; return ret; } ret = cluster.conf_read_file(NULL); if (ret) { cerr << "Error " << ret << " in cluster.conf_read_file" << std::endl; return ret; } ret = cluster.conf_parse_env(NULL); if (ret) { cerr << "Error " << ret << " in cluster.conf_read_env" << std::endl; return ret; } cluster.connect(); ret = cluster.ioctx_create(pool.c_str(), ioctx); if (ret < 0) { cerr << "ioctx_create " << pool << " failed with " << ret << std::endl; return ret; } cout << "Importing from pgid " << pgid << std::endl; bool done = false; bool found_metadata = false; metadata_section ms; while(!done) { ret = read_section(file_fd, &type, &ebl); if (ret) return ret; //cout << "do_import: Section type " << hex << type << dec << std::endl; if (type >= END_OF_TYPES) { cout << "Skipping unknown section type" << std::endl; continue; } switch(type) { case TYPE_OBJECT_BEGIN: ret = get_object_rados(ioctx, ebl); if (ret) return ret; break; case TYPE_PG_METADATA: if (debug) cout << "Don't care about the old metadata" << std::endl; found_metadata = true; break; case TYPE_PG_END: done = true; break; default: return EFAULT; } } if (!found_metadata) { cerr << "Missing metadata section, ignored" << std::endl; } return 0; } int do_import(ObjectStore *store, OSDSuperblock& sb) { bufferlist ebl; pg_info_t info; PGLog::IndexedLog log; uint64_t next_removal_seq = 0; //My local seq finish_remove_pgs(store, &next_removal_seq); int ret = sh.read_super(); if (ret) return ret; if (sh.magic != super_header::super_magic) { cerr << "Invalid magic number" << std::endl; return EFAULT; } if (sh.version > super_header::super_ver) { cerr << "Can't handle export format version=" << sh.version << std::endl; return EINVAL; } //First section must be TYPE_PG_BEGIN sectiontype_t type; ret = read_section(file_fd, &type, &ebl); if (ret) return ret; if (type != TYPE_PG_BEGIN) { return EFAULT; } bufferlist::iterator ebliter = ebl.begin(); pg_begin pgb; pgb.decode(ebliter); spg_t pgid = pgb.pgid; if (!pgb.superblock.cluster_fsid.is_zero() && pgb.superblock.cluster_fsid != sb.cluster_fsid) { cerr << "Export came from different cluster with fsid " << pgb.superblock.cluster_fsid << std::endl; return 1; } if (debug) { cerr << "Exported features: " << pgb.superblock.compat_features << std::endl; } // Special case: Old export has SHARDS incompat feature on replicated pg, remove it if (pgid.is_no_shard()) pgb.superblock.compat_features.incompat.remove(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); if (sb.compat_features.compare(pgb.superblock.compat_features) == -1) { CompatSet unsupported = sb.compat_features.unsupported(pgb.superblock.compat_features); cerr << "Export has incompatible features set " << unsupported << std::endl; // If shards setting the issue, then inform user what they can do about it. if (unsupported.incompat.contains(CEPH_OSD_FEATURE_INCOMPAT_SHARDS)) { cerr << std::endl; cerr << "OSD requires sharding to be enabled" << std::endl; cerr << std::endl; cerr << "If you wish to import, first do 'ceph-objectstore-tool...--op set-allow-sharded-objects'" << std::endl; } return 11; // Assume no +EAGAIN gets to end of main() until we clean up error code handling } // Don't import if pool no longer exists OSDMap curmap; ret = get_osdmap(store, sb.current_epoch, curmap); if (ret) { cerr << "Can't find local OSDMap" << std::endl; return ret; } if (!curmap.have_pg_pool(pgid.pgid.m_pool)) { cerr << "Pool " << pgid.pgid.m_pool << " no longer exists" << std::endl; // Special exit code for this error, used by test code return 10; // Assume no +ECHILD gets to end of main() until we clean up error code handling } log_oid = OSD::make_pg_log_oid(pgid); biginfo_oid = OSD::make_pg_biginfo_oid(pgid); //Check for PG already present. coll_t coll(pgid); if (store->collection_exists(coll)) { cerr << "pgid " << pgid << " already exists" << std::endl; return 1; } //Switch to collection which will be removed automatically if //this program is interupted. coll_t rmcoll = coll_t::make_removal_coll(next_removal_seq, pgid); ObjectStore::Transaction *t = new ObjectStore::Transaction; t->create_collection(rmcoll); store->apply_transaction(*t); delete t; cout << "Importing pgid " << pgid << std::endl; bool done = false; bool found_metadata = false; metadata_section ms; while(!done) { ret = read_section(file_fd, &type, &ebl); if (ret) return ret; //cout << "do_import: Section type " << hex << type << dec << std::endl; if (type >= END_OF_TYPES) { cout << "Skipping unknown section type" << std::endl; continue; } switch(type) { case TYPE_OBJECT_BEGIN: ret = get_object(store, rmcoll, ebl, curmap, coll); if (ret) return ret; break; case TYPE_PG_METADATA: ret = get_pg_metadata(store, ebl, ms, sb, curmap); if (ret) return ret; found_metadata = true; break; case TYPE_PG_END: done = true; break; default: return EFAULT; } } if (!found_metadata) { cerr << "Missing metadata section" << std::endl; return EFAULT; } t = new ObjectStore::Transaction; assert(ms.info.pgid == pgid); coll_t newcoll(ms.info.pgid); t->collection_rename(rmcoll, newcoll); ret = write_pg(*t, ms.map_epoch, ms.info, ms.log, ms.struct_ver, ms.past_intervals); if (ret) return ret; store->apply_transaction(*t); delete t; return 0; } int do_list(ObjectStore *store, string pgidstr, string object, Formatter *formatter, bool debug, bool human_readable) { int r; lookup_ghobject lookup(object); if (pgidstr.length() > 0) { spg_t pgid; pgid.parse(pgidstr.c_str()); r = action_on_all_objects_in_pg(store, coll_t(pgid), lookup, debug); } else { r = action_on_all_objects(store, lookup, debug); } if (r) return r; lookup.dump(formatter, human_readable); formatter->flush(cout); cout << std::endl; return 0; } int do_remove_object(ObjectStore *store, coll_t coll, ghobject_t &ghobj) { spg_t pg; coll.is_pg_prefix(pg); OSDriver driver( store, coll_t(), OSD::make_snapmapper_oid()); SnapMapper mapper(&driver, 0, 0, 0, pg.shard); struct stat st; int r = store->stat(coll, ghobj, &st); if (r < 0) { cerr << "remove: " << cpp_strerror(-r) << std::endl; return r; } ObjectStore::Transaction *t = new ObjectStore::Transaction; OSDriver::OSTransaction _t(driver.get_transaction(t)); cout << "remove " << ghobj << std::endl; r = mapper.remove_oid(ghobj.hobj, &_t); if (r != 0 && r != -ENOENT) { cerr << "remove_oid returned " << cpp_strerror(-r) << std::endl; return r; } t->remove(coll, ghobj); store->apply_transaction(*t); delete t; return 0; } int do_list_attrs(ObjectStore *store, coll_t coll, ghobject_t &ghobj) { map aset; int r = store->getattrs(coll, ghobj, aset); if (r < 0) { cerr << "getattrs: " << cpp_strerror(-r) << std::endl; return r; } for (map::iterator i = aset.begin();i != aset.end(); ++i) { string key(i->first); if (outistty) cleanbin(key); cout << key << std::endl; } return 0; } int do_list_omap(ObjectStore *store, coll_t coll, ghobject_t &ghobj) { ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(coll, ghobj); if (!iter) { cerr << "omap_get_iterator: " << cpp_strerror(ENOENT) << std::endl; return -ENOENT; } iter->seek_to_first(); map oset; while(iter->valid()) { get_omap_batch(iter, oset); for (map::iterator i = oset.begin();i != oset.end(); ++i) { string key(i->first); if (outistty) cleanbin(key); cout << key << std::endl; } } return 0; } int do_get_bytes(ObjectStore *store, coll_t coll, ghobject_t &ghobj, int fd) { struct stat st; mysize_t total; int ret = store->stat(coll, ghobj, &st); if (ret < 0) { cerr << "get-bytes: " << cpp_strerror(-ret) << std::endl; return 1; } total = st.st_size; if (debug) cerr << "size=" << total << std::endl; uint64_t offset = 0; bufferlist rawdatabl; while(total > 0) { rawdatabl.clear(); mysize_t len = max_read; if (len > total) len = total; ret = store->read(coll, ghobj, offset, len, rawdatabl); if (ret < 0) return ret; if (ret == 0) return -EINVAL; if (debug) cerr << "data section offset=" << offset << " len=" << len << std::endl; total -= ret; offset += ret; ret = write(fd, rawdatabl.c_str(), ret); if (ret == -1) { perror("write"); return 1; } } return 0; } int do_set_bytes(ObjectStore *store, coll_t coll, ghobject_t &ghobj, int fd) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; if (debug) cerr << "Write " << ghobj << std::endl; t->touch(coll, ghobj); t->truncate(coll, ghobj, 0); uint64_t offset = 0; bufferlist rawdatabl; do { rawdatabl.clear(); ssize_t bytes = rawdatabl.read_fd(fd, max_read); if (bytes < 0) { cerr << "read_fd error " << cpp_strerror(-bytes) << std::endl; return 1; } if (bytes == 0) break; if (debug) cerr << "\tdata: offset " << offset << " bytes " << bytes << std::endl; t->write(coll, ghobj, offset, bytes, rawdatabl); offset += bytes; // XXX: Should we apply_transaction() every once in a while for very large files } while(true); store->apply_transaction(*t); return 0; } int do_get_attr(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key) { bufferptr bp; int r = store->getattr(coll, ghobj, key.c_str(), bp); if (r < 0) { cerr << "getattr: " << cpp_strerror(-r) << std::endl; return r; } string value(bp.c_str(), bp.length()); if (outistty) { cleanbin(value); value.push_back('\n'); } cout << value; return 0; } int do_set_attr(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key, int fd) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; bufferlist bl; if (debug) cerr << "Setattr " << ghobj << std::endl; if (get_fd_data(fd, bl)) return 1; t->touch(coll, ghobj); t->setattr(coll, ghobj, key, bl); store->apply_transaction(*t); return 0; } int do_rm_attr(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; if (debug) cerr << "Rmattr " << ghobj << std::endl; t->rmattr(coll, ghobj, key); store->apply_transaction(*t); return 0; } int do_get_omap(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key) { set keys; map out; keys.insert(key); int r = store->omap_get_values(coll, ghobj, keys, &out); if (r < 0) { cerr << "omap_get_values: " << cpp_strerror(-r) << std::endl; return r; } if (out.empty()) { cerr << "Key not found" << std::endl; return -ENOENT; } assert(out.size() == 1); bufferlist bl = out.begin()->second; string value(bl.c_str(), bl.length()); if (outistty) { cleanbin(value); value.push_back('\n'); } cout << value; return 0; } int do_set_omap(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key, int fd) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; map attrset; bufferlist valbl; if (debug) cerr << "Set_omap " << ghobj << std::endl; if (get_fd_data(fd, valbl)) return 1; attrset.insert(pair(key, valbl)); t->touch(coll, ghobj); t->omap_setkeys(coll, ghobj, attrset); store->apply_transaction(*t); return 0; } int do_rm_omap(ObjectStore *store, coll_t coll, ghobject_t &ghobj, string key) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; set keys; keys.insert(key); if (debug) cerr << "Rm_omap " << ghobj << std::endl; t->omap_rmkeys(coll, ghobj, keys); store->apply_transaction(*t); return 0; } int do_get_omaphdr(ObjectStore *store, coll_t coll, ghobject_t &ghobj) { bufferlist hdrbl; int r = store->omap_get_header(coll, ghobj, &hdrbl, true); if (r < 0) { cerr << "omap_get_header: " << cpp_strerror(-r) << std::endl; return r; } string header(hdrbl.c_str(), hdrbl.length()); if (outistty) { cleanbin(header); header.push_back('\n'); } cout << header; return 0; } int do_set_omaphdr(ObjectStore *store, coll_t coll, ghobject_t &ghobj, int fd) { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; bufferlist hdrbl; if (debug) cerr << "Omap_setheader " << ghobj << std::endl; if (get_fd_data(fd, hdrbl)) return 1; t->touch(coll, ghobj); t->omap_setheader(coll, ghobj, hdrbl); store->apply_transaction(*t); return 0; } struct do_list_lost : public action_on_object_t { virtual int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) { if (oi.is_lost()) cout << coll << "/" << ghobj << " is lost" << std::endl; return 0; } }; struct do_fix_lost : public action_on_object_t { virtual int call(ObjectStore *store, coll_t coll, ghobject_t &ghobj, object_info_t &oi) { if (oi.is_lost()) { cout << coll << "/" << ghobj << " is lost, fixing" << std::endl; oi.clear_flag(object_info_t::FLAG_LOST); bufferlist bl; ::encode(oi, bl); ObjectStore::Transaction t; t.setattr(coll, ghobj, OI_ATTR, bl); int r = store->apply_transaction(t); if (r < 0) { cerr << "Error getting fixing attr on : " << make_pair(coll, ghobj) << ", " << cpp_strerror(r) << std::endl; return r; } } return 0; } }; void usage(po::options_description &desc) { cerr << std::endl; cerr << desc << std::endl; cerr << std::endl; cerr << "Positional syntax:" << std::endl; cerr << std::endl; cerr << "ceph-objectstore-tool ... (get|set)-bytes [file]" << std::endl; cerr << "ceph-objectstore-tool ... set-(attr|omap) [file]" << std::endl; cerr << "ceph-objectstore-tool ... (get|rm)-(attr|omap) " << std::endl; cerr << "ceph-objectstore-tool ... get-omaphdr" << std::endl; cerr << "ceph-objectstore-tool ... set-omaphdr [file]" << std::endl; cerr << "ceph-objectstore-tool ... list-attrs" << std::endl; cerr << "ceph-objectstore-tool ... list-omap" << std::endl; cerr << "ceph-objectstore-tool ... remove" << std::endl; cerr << std::endl; cerr << "ceph-objectstore-tool import-rados [file]" << std::endl; cerr << std::endl; cerr << " can be a JSON object description as displayed" << std::endl; cerr << "by --op list." << std::endl; cerr << " can be an object name which will be looked up in all" << std::endl; cerr << "the OSD's PGs." << std::endl; cerr << std::endl; cerr << "The optional [file] argument will read stdin or write stdout" << std::endl; cerr << "if not specified or if '-' specified." << std::endl; exit(1); } bool ends_with(const string& check, const string& ending) { return check.size() >= ending.size() && check.rfind(ending) == (check.size() - ending.size()); } int main(int argc, char **argv) { string dpath, jpath, pgidstr, op, file, object, objcmd, arg1, arg2, type, format; spg_t pgid; ghobject_t ghobj; bool human_readable; Formatter *formatter; po::options_description desc("Allowed options"); desc.add_options() ("help", "produce help message") ("type", po::value(&type), "Arg is one of [filestore (default), memstore, keyvaluestore-dev]") ("data-path", po::value(&dpath), "path to object store, mandatory") ("journal-path", po::value(&jpath), "path to journal, mandatory for filestore type") ("pgid", po::value(&pgidstr), "PG id, mandatory except for import, list-lost, fix-lost, list-pgs, set-allow-sharded-objects") ("op", po::value(&op), "Arg is one of [info, log, remove, export, import, list, list-lost, fix-lost, list-pgs, rm-past-intervals, set-allow-sharded-objects]") ("file", po::value(&file), "path of file to export or import") ("format", po::value(&format)->default_value("json-pretty"), "Output format which may be json, json-pretty, xml, xml-pretty") ("debug", "Enable diagnostic output to stderr") ("skip-journal-replay", "Disable journal replay") ("skip-mount-omap", "Disable mounting of omap") ; po::options_description positional("Positional options"); positional.add_options() ("object", po::value(&object), "object name or ghobject in json") ("objcmd", po::value(&objcmd), "command [(get|set)-bytes, (get|set|rm)-(attr|omap), (get|set)-omaphdr, list-attrs, list-omap, remove]") ("arg1", po::value(&arg1), "arg1 based on cmd") ("arg2", po::value(&arg2), "arg2 based on cmd") ("test-align", po::value(&testalign)->default_value(0), "hidden align option for testing") ; po::options_description all("All options"); all.add(desc).add(positional); po::positional_options_description pd; pd.add("object", 1).add("objcmd", 1).add("arg1", 1).add("arg2", 1); po::variables_map vm; po::parsed_options parsed = po::command_line_parser(argc, argv).options(all).allow_unregistered().positional(pd).run(); po::store( parsed, vm); try { po::notify(vm); } catch(...) { usage(desc); } if (vm.count("help")) { usage(desc); } if (!vm.count("debug")) { debug = false; } else { debug = true; } vector ceph_options; env_to_vec(ceph_options); vector ceph_option_strings = po::collect_unrecognized( parsed.options, po::include_positional); ceph_options.reserve(ceph_options.size() + ceph_option_strings.size()); for (vector::iterator i = ceph_option_strings.begin(); i != ceph_option_strings.end(); ++i) { ceph_options.push_back(i->c_str()); } // Handle completely different operation "import-rados" if (object == "import-rados") { if (vm.count("objcmd") == 0) { cerr << "ceph-objectstore-tool import-rados [file]" << std::endl; exit(1); } string pool = objcmd; // positional argument takes precendence, but accept // --file option too if (!vm.count("arg1")) { if (!vm.count("file")) arg1 = "-"; else arg1 = file; } if (arg1 == "-") { if (isatty(STDIN_FILENO)) { cerr << "stdin is a tty and no file specified" << std::endl; exit(1); } file_fd = STDIN_FILENO; } else { file_fd = open(arg1.c_str(), O_RDONLY); if (file_fd < 0) { perror("open"); return 1; } } global_init(NULL, ceph_options, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); int ret = do_import_rados(pool); if (ret == 0) cout << "Import successful" << std::endl; return ret != 0; } if (!vm.count("data-path")) { cerr << "Must provide --data-path" << std::endl; usage(desc); } if (!vm.count("type")) { type = "filestore"; } if (type == "filestore" && !vm.count("journal-path")) { cerr << "Must provide --journal-path" << std::endl; usage(desc); } if (op != "list" && vm.count("object") && !vm.count("objcmd")) { cerr << "Invalid syntax, missing command" << std::endl; usage(desc); } if (!vm.count("op") && !(vm.count("object") && vm.count("objcmd"))) { cerr << "Must provide --op or object command..." << std::endl; usage(desc); } if (op != "list" && vm.count("op") && vm.count("object")) { cerr << "Can't specify both --op and object command syntax" << std::endl; usage(desc); } outistty = isatty(STDOUT_FILENO); file_fd = fd_none; if (op == "export") { if (!vm.count("file") || file == "-") { if (outistty) { cerr << "stdout is a tty and no --file filename specified" << std::endl; exit(1); } file_fd = STDOUT_FILENO; } else { file_fd = open(file.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); } } else if (op == "import") { if (!vm.count("file") || file == "-") { if (isatty(STDIN_FILENO)) { cerr << "stdin is a tty and no --file filename specified" << std::endl; exit(1); } file_fd = STDIN_FILENO; } else { file_fd = open(file.c_str(), O_RDONLY); } } if (vm.count("file") && file_fd == fd_none) { cerr << "--file option only applies to import or export" << std::endl; return 1; } if (file_fd != fd_none && file_fd < 0) { perror("open"); return 1; } if (dpath.length() == 0) { cerr << "Invalid params" << std::endl; return 1; } osflagbits_t flags = 0; if (vm.count("skip-journal-replay")) flags |= SKIP_JOURNAL_REPLAY; if (vm.count("skip-mount-omap")) flags |= SKIP_MOUNT_OMAP; global_init( NULL, ceph_options, CEPH_ENTITY_TYPE_OSD, CODE_ENVIRONMENT_UTILITY_NODOUT, 0); //CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); g_conf = g_ceph_context->_conf; if (debug) { g_conf->set_val_or_die("log_to_stderr", "true"); g_conf->set_val_or_die("err_to_stderr", "true"); } g_conf->apply_changes(NULL); //Verify that data-path really exists struct stat st; if (::stat(dpath.c_str(), &st) == -1) { perror("data-path"); exit(1); } //Verify data data-path really is a filestore if (type == "filestore") { if (!S_ISDIR(st.st_mode)) { invalid_filestore_path(dpath); } string check = dpath + "/whoami"; if (::stat(check.c_str(), &st) == -1) { perror("whoami"); invalid_filestore_path(dpath); } if (!S_ISREG(st.st_mode)) { invalid_filestore_path(dpath); } check = dpath + "/current"; if (::stat(check.c_str(), &st) == -1) { perror("current"); invalid_filestore_path(dpath); } if (!S_ISDIR(st.st_mode)) { invalid_filestore_path(dpath); } } if (op == "import" && pgidstr.length()) { cerr << "--pgid option invalid with import" << std::endl; return 1; } ObjectStore *fs = ObjectStore::create(g_ceph_context, type, dpath, jpath, flags); if (fs == NULL) { cerr << "Must provide --type (filestore, memstore, keyvaluestore-dev)" << std::endl; exit(1); } int r = fs->mount(); if (r < 0) { if (r == -EBUSY) { cerr << "OSD has the store locked" << std::endl; } else { cerr << "Mount failed with '" << cpp_strerror(-r) << "'" << std::endl; } return 1; } bool fs_sharded_objects = fs->get_allow_sharded_objects(); int ret = 0; vector ls; vector::iterator it; CompatSet supported; #ifdef INTERNAL_TEST supported = get_test_compat_set(); #else supported = OSD::get_osd_compat_set(); #endif bufferlist bl; OSDSuperblock superblock; bufferlist::iterator p; r = fs->read(coll_t::META_COLL, OSD_SUPERBLOCK_POBJECT, 0, 0, bl); if (r < 0) { cerr << "Failure to read OSD superblock error= " << r << std::endl; goto out; } p = bl.begin(); ::decode(superblock, p); if (debug) { cerr << "Cluster fsid=" << superblock.cluster_fsid << std::endl; } #ifdef INTERNAL_TEST2 fs->set_allow_sharded_objects(); assert(fs->get_allow_sharded_objects()); fs_sharded_objects = true; superblock.compat_features.incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); #endif if (debug) { cerr << "Supported features: " << supported << std::endl; cerr << "On-disk features: " << superblock.compat_features << std::endl; } if (supported.compare(superblock.compat_features) == -1) { CompatSet unsupported = supported.unsupported(superblock.compat_features); cerr << "On-disk OSD incompatible features set " << unsupported << std::endl; ret = EINVAL; goto out; } if (pgidstr.length() && !pgid.parse(pgidstr.c_str())) { cerr << "Invalid pgid '" << pgidstr << "' specified" << std::endl; return 1; } if (op != "list" && vm.count("object")) { json_spirit::Value v; try { if (!json_spirit::read(object, v)) { lookup_ghobject lookup(object); if (action_on_all_objects(fs, lookup, debug)) { throw std::runtime_error("Internal error"); } else { if (lookup.size() != 1) { stringstream ss; if (lookup.size() == 0) ss << objcmd << ": " << cpp_strerror(ENOENT); else ss << "expected a single object named '" << object << "' but got " << lookup.size() << " instead"; throw std::runtime_error(ss.str()); } pair found = lookup.pop(); pgidstr = found.first.to_str(); pgid.parse(pgidstr.c_str()); ghobj = found.second; } } else { stringstream ss; if (pgidstr.length() == 0 && v.type() != json_spirit::array_type) { ss << "object '" << object << "' must be a JSON array but is of type " << v.type() << " instead"; throw std::runtime_error(ss.str()); } if (v.type() == json_spirit::array_type) { json_spirit::Array array = v.get_array(); vector::iterator i = array.begin(); if (i->type() != json_spirit::str_type) { ss << "object '" << object << "' must be a JSON array with the first element a string but " << "found type " << v.type() << " instead"; throw std::runtime_error(ss.str()); } string object_pgidstr = i->get_str(); spg_t object_pgid; object_pgid.parse(object_pgidstr.c_str()); if (pgidstr.length() > 0) { if (object_pgid != pgid) { ss << "object '" << object << "' has a pgid different from the --pgid=" << pgidstr << " option"; throw std::runtime_error(ss.str()); } } else { pgidstr = object_pgidstr; pgid = object_pgid; } ++i; v = *i; } try { ghobj.decode(v); } catch (std::runtime_error& e) { ss << "Decode object json error: " << e.what(); throw std::runtime_error(ss.str()); } if ((uint64_t)pgid.pgid.m_pool != (uint64_t)ghobj.hobj.pool) { cerr << "Object pool and pgid pool don't match" << std::endl; ret = 1; goto out; } } } catch (std::runtime_error& e) { cerr << e.what() << std::endl; ret = 1; goto out; } } if (op != "list" && op != "import" && op != "list-lost" && op != "fix-lost" && op != "list-pgs" && op != "set-allow-sharded-objects" && (pgidstr.length() == 0)) { cerr << "Must provide pgid" << std::endl; usage(desc); } if (op == "set-allow-sharded-objects") { // This could only happen if we backport changes to an older release if (!supported.incompat.contains(CEPH_OSD_FEATURE_INCOMPAT_SHARDS)) { cerr << "Can't enable sharded objects in this release" << std::endl; ret = 1; goto out; } if (superblock.compat_features.incompat.contains(CEPH_OSD_FEATURE_INCOMPAT_SHARDS) && fs_sharded_objects) { cerr << "Sharded objects already fully enabled" << std::endl; ret = 0; goto out; } OSDMap curmap; ret = get_osdmap(fs, superblock.current_epoch, curmap); if (ret) { cerr << "Can't find local OSDMap" << std::endl; goto out; } // Based on OSDMonitor::check_cluster_features() // XXX: The up state of osds in the last map isn't // as important from a non-running osd. I'm using // get_all_osds() instead. An osd which was never // upgraded and never removed would be flagged here. stringstream unsupported_ss; int unsupported_count = 0; uint64_t features = CEPH_FEATURE_OSD_ERASURE_CODES; set all_osds; curmap.get_all_osds(all_osds); for (set::iterator it = all_osds.begin(); it != all_osds.end(); ++it) { const osd_xinfo_t &xi = curmap.get_xinfo(*it); #ifdef INTERNAL_TEST3 // Force one of the OSDs to not have support for erasure codes if (unsupported_count == 0) ((osd_xinfo_t &)xi).features &= ~features; #endif if ((xi.features & features) != features) { if (unsupported_count > 0) unsupported_ss << ", "; unsupported_ss << "osd." << *it; unsupported_count ++; } } if (unsupported_count > 0) { cerr << "ERASURE_CODES feature unsupported by: " << unsupported_ss.str() << std::endl; ret = 1; goto out; } superblock.compat_features.incompat.insert(CEPH_OSD_FEATURE_INCOMPAT_SHARDS); ObjectStore::Transaction t; bufferlist bl; ::encode(superblock, bl); t.write(coll_t::META_COLL, OSD_SUPERBLOCK_POBJECT, 0, bl.length(), bl); r = fs->apply_transaction(t); if (r < 0) { cerr << "Error writing OSD superblock: " << cpp_strerror(r) << std::endl; ret = 1; goto out; } fs->set_allow_sharded_objects(); cout << "Enabled on-disk sharded objects" << std::endl; ret = 0; goto out; } // If there was a crash as an OSD was transitioning to sharded objects // and hadn't completed a set_allow_sharded_objects(). // This utility does not want to attempt to finish that transition. if (superblock.compat_features.incompat.contains(CEPH_OSD_FEATURE_INCOMPAT_SHARDS) != fs_sharded_objects) { // An OSD should never have call set_allow_sharded_objects() before // updating its own OSD features. if (fs_sharded_objects) cerr << "FileStore sharded but OSD not set, Corruption?" << std::endl; else cerr << "Found incomplete transition to sharded objects" << std::endl; cerr << std::endl; cerr << "Use --op set-allow-sharded-objects to repair" << std::endl; ret = EINVAL; goto out; } if (op == "import") { try { ret = do_import(fs, superblock); } catch (const buffer::error &e) { cerr << "do_import threw exception error " << e.what() << std::endl; ret = EFAULT; } if (ret == EFAULT) { cerr << "Corrupt input for import" << std::endl; } if (ret == 0) cout << "Import successful" << std::endl; goto out; } log_oid = OSD::make_pg_log_oid(pgid); biginfo_oid = OSD::make_pg_biginfo_oid(pgid); if (op == "remove") { uint64_t next_removal_seq = 0; //My local seq finish_remove_pgs(fs, &next_removal_seq); int r = initiate_new_remove_pg(fs, pgid, &next_removal_seq); if (r) { cerr << "PG '" << pgid << "' not found" << std::endl; ret = 1; goto out; } finish_remove_pgs(fs, &next_removal_seq); cout << "Remove successful" << std::endl; goto out; } if (op == "list-lost" || op == "fix-lost") { boost::scoped_ptr action; if (op == "list-lost") action.reset(new do_list_lost()); if (op == "fix-lost") action.reset(new do_fix_lost()); if (pgidstr.length()) ret = action_on_all_objects_in_pg(fs, coll_t(pgid), *action, debug); else ret = action_on_all_objects(fs, *action, debug); goto out; } // Special list handling. Treating pretty_format as human readable, // with one object per line and not an enclosing array. human_readable = ends_with(format, "-pretty"); if (op == "list" && human_readable) { // Remove -pretty from end of format which we know is there format = format.substr(0, format.size() - strlen("-pretty")); } formatter = new_formatter(format); if (formatter == NULL) { cerr << "unrecognized format: " << format << std::endl; ret = 1; goto out; } if (op == "list") { r = do_list(fs, pgidstr, object, formatter, debug, human_readable); if (r) { cerr << "do_list failed with " << r << std::endl; ret = 1; } goto out; } r = fs->list_collections(ls); if (r < 0) { cerr << "failed to list pgs: " << cpp_strerror(-r) << std::endl; ret = 1; goto out; } if (debug && op == "list-pgs") cout << "Performing list-pgs operation" << std::endl; // Find pg for (it = ls.begin(); it != ls.end(); ++it) { snapid_t snap; spg_t tmppgid; if (!it->is_pg(tmppgid, snap)) { continue; } if (it->is_temp(tmppgid)) { continue; } if (op != "list-pgs" && tmppgid != pgid) { continue; } if (snap != CEPH_NOSNAP && debug) { cout << "skipping snapped dir " << *it << " (pg " << pgid << " snap " << snap << ")" << std::endl; continue; } if (op != "list-pgs") { //Found! break; } cout << tmppgid << std::endl; } if (op == "list-pgs") { ret = 0; goto out; } epoch_t map_epoch; // The following code for export, info, log require omap or !skip-mount-omap if (it != ls.end()) { coll_t coll = *it; if (vm.count("objcmd")) { ret = 0; if (objcmd == "remove") { int r = do_remove_object(fs, coll, ghobj); if (r) { ret = 1; } goto out; } else if (objcmd == "list-attrs") { int r = do_list_attrs(fs, coll, ghobj); if (r) { ret = 1; } goto out; } else if (objcmd == "list-omap") { int r = do_list_omap(fs, coll, ghobj); if (r) { ret = 1; } goto out; } else if (objcmd == "get-bytes" || objcmd == "set-bytes") { int r; if (objcmd == "get-bytes") { int fd; if (vm.count("arg1") == 0 || arg1 == "-") { fd = STDOUT_FILENO; } else { fd = open(arg1.c_str(), O_WRONLY|O_TRUNC|O_CREAT|O_EXCL|O_LARGEFILE, 0666); if (fd == -1) { cerr << "open " << arg1 << " " << cpp_strerror(errno) << std::endl; ret = 1; goto out; } } r = do_get_bytes(fs, coll, ghobj, fd); if (fd != STDOUT_FILENO) close(fd); } else { int fd; if (vm.count("arg1") == 0 || arg1 == "-") { // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it. if (isatty(STDIN_FILENO)) { cerr << "stdin is a tty and no file specified" << std::endl; ret = 1; goto out; } fd = STDIN_FILENO; } else { fd = open(arg1.c_str(), O_RDONLY|O_LARGEFILE, 0666); if (fd == -1) { cerr << "open " << arg1 << " " << cpp_strerror(errno) << std::endl; ret = 1; goto out; } } r = do_set_bytes(fs, coll, ghobj, fd); if (fd != STDIN_FILENO) close(fd); } if (r) ret = 1; goto out; } else if (objcmd == "get-attr") { if (vm.count("arg1") == 0) usage(desc); r = do_get_attr(fs, coll, ghobj, arg1); if (r) ret = 1; goto out; } else if (objcmd == "set-attr") { if (vm.count("arg1") == 0) usage(desc); int fd; if (vm.count("arg2") == 0 || arg2 == "-") { // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it. if (isatty(STDIN_FILENO)) { cerr << "stdin is a tty and no file specified" << std::endl; ret = 1; goto out; } fd = STDIN_FILENO; } else { fd = open(arg2.c_str(), O_RDONLY|O_LARGEFILE, 0666); if (fd == -1) { cerr << "open " << arg2 << " " << cpp_strerror(errno) << std::endl; ret = 1; goto out; } } r = do_set_attr(fs, coll, ghobj, arg1, fd); if (fd != STDIN_FILENO) close(fd); if (r) ret = 1; goto out; } else if (objcmd == "rm-attr") { if (vm.count("arg1") == 0) usage(desc); r = do_rm_attr(fs, coll, ghobj, arg1); if (r) ret = 1; goto out; } else if (objcmd == "get-omap") { if (vm.count("arg1") == 0) usage(desc); r = do_get_omap(fs, coll, ghobj, arg1); if (r) ret = 1; goto out; } else if (objcmd == "set-omap") { if (vm.count("arg1") == 0) usage(desc); int fd; if (vm.count("arg2") == 0 || arg2 == "-") { // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it. if (isatty(STDIN_FILENO)) { cerr << "stdin is a tty and no file specified" << std::endl; ret = 1; goto out; } fd = STDIN_FILENO; } else { fd = open(arg2.c_str(), O_RDONLY|O_LARGEFILE, 0666); if (fd == -1) { cerr << "open " << arg2 << " " << cpp_strerror(errno) << std::endl; ret = 1; goto out; } } r = do_set_omap(fs, coll, ghobj, arg1, fd); if (fd != STDIN_FILENO) close(fd); if (r) ret = 1; goto out; } else if (objcmd == "rm-omap") { if (vm.count("arg1") == 0) usage(desc); r = do_rm_omap(fs, coll, ghobj, arg1); if (r) ret = 1; goto out; } else if (objcmd == "get-omaphdr") { if (vm.count("arg1")) usage(desc); r = do_get_omaphdr(fs, coll, ghobj); if (r) ret = 1; goto out; } else if (objcmd == "set-omaphdr") { // Extra arg if (vm.count("arg2")) usage(desc); int fd; if (vm.count("arg1") == 0 || arg1 == "-") { // Since read_fd() doesn't handle ^D from a tty stdin, don't allow it. if (isatty(STDIN_FILENO)) { cerr << "stdin is a tty and no file specified" << std::endl; ret = 1; goto out; } fd = STDIN_FILENO; } else { fd = open(arg1.c_str(), O_RDONLY|O_LARGEFILE, 0666); if (fd == -1) { cerr << "open " << arg1 << " " << cpp_strerror(errno) << std::endl; ret = 1; goto out; } } r = do_set_omaphdr(fs, coll, ghobj, fd); if (fd != STDIN_FILENO) close(fd); if (r) ret = 1; goto out; } cerr << "Unknown object command '" << objcmd << "'" << std::endl; usage(desc); } bufferlist bl; map_epoch = PG::peek_map_epoch(fs, coll, infos_oid, &bl); if (debug) cerr << "map_epoch " << map_epoch << std::endl; pg_info_t info(pgid); map past_intervals; hobject_t biginfo_oid = OSD::make_pg_biginfo_oid(pgid); interval_set snap_collections; __u8 struct_ver; r = PG::read_info(fs, coll, bl, info, past_intervals, biginfo_oid, infos_oid, snap_collections, struct_ver); if (r < 0) { cerr << "read_info error " << cpp_strerror(-r) << std::endl; ret = 1; goto out; } if (debug) cerr << "struct_v " << (int)struct_ver << std::endl; if (op == "export") { ret = do_export(fs, coll, pgid, info, map_epoch, struct_ver, superblock, past_intervals); if (ret == 0) cerr << "Export successful" << std::endl; } else if (op == "info") { formatter->open_object_section("info"); info.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; } else if (op == "log") { PGLog::IndexedLog log; pg_missing_t missing; ret = get_log(fs, coll, pgid, info, log, missing); if (ret > 0) goto out; formatter->open_object_section("log"); log.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; formatter->open_object_section("missing"); missing.dump(formatter); formatter->close_section(); formatter->flush(cout); cout << std::endl; } else if (op == "rm-past-intervals") { ObjectStore::Transaction tran; ObjectStore::Transaction *t = &tran; if (struct_ver != PG::cur_struct_v) { cerr << "Can't remove past-intervals, version mismatch " << (int)struct_ver << " (pg) != " << (int)PG::cur_struct_v << " (tool)" << std::endl; ret = 1; goto out; } cout << "Remove past-intervals " << past_intervals << std::endl; past_intervals.clear(); ret = write_info(*t, map_epoch, info, struct_ver, past_intervals); if (ret == 0) { fs->apply_transaction(*t); cout << "Removal succeeded" << std::endl; } } else { cerr << "Must provide --op (info, log, remove, export, import, list, list-lost, fix-lost, list-pgs, rm-past-intervals)" << std::endl; usage(desc); } } else { cerr << "PG '" << pgid << "' not found" << std::endl; ret = 1; } out: if (fs->umount() < 0) { cerr << "umount failed" << std::endl; return 1; } // Check for -errno accidentally getting here if (ret < 0) ret = 1; return ret; } ceph-0.80.11/src/tools/psim.cc0000664000175100017510000000572312623076744020112 0ustar jenkins-buildjenkins-build #include #include "crush/CrushWrapper.h" #include "osd/OSDMap.h" #include "common/config.h" #include "include/buffer.h" int main(int argc, char **argv) { /* * you need to create a suitable osdmap first. e.g., for 40 osds, * $ ./osdmaptool --createsimple 40 --clobber .ceph_osdmap */ bufferlist bl; std::string error; if (bl.read_file(".ceph_osdmap", &error)) { cout << argv[0] << ": error reading .ceph_osdmap: " << error << std::endl; return 1; } OSDMap osdmap; osdmap.decode(bl); //osdmap.set_primary_affinity(0, 0x8000); //osdmap.set_primary_affinity(3, 0); int n = osdmap.get_max_osd(); int count[n]; int first_count[n]; int primary_count[n]; for (int i=0; itype = pg_pool_t::TYPE_ERASURE; int size[4]; for (int i=0; i<4; i++) size[i] = 0; for (int n = 0; n < 10; n++) { // namespaces char nspace[20]; snprintf(nspace, sizeof(nspace), "n%d", n); for (int f = 0; f < 5000; f++) { // files for (int b = 0; b < 4; b++) { // blocks char foo[20]; snprintf(foo, sizeof(foo), "%d.%d", f, b); object_t oid(foo); ceph_object_layout l = osdmap.make_object_layout(oid, 0, nspace); //osdmap.file_to_object_layout(oid, g_default_file_layout); vector osds; pg_t pgid = pg_t(l.ol_pgid); //pgid.u.ps = f * 4 + b; int primary; osdmap.pg_to_acting_osds(pgid, &osds, &primary); size[osds.size()]++; #if 0 if (0) { hash H; int x = H(oid); x = ceph_stable_mod(x, 1023, 1023); int s = crush_hash32(x) % 15; //cout << "ceph_psim: x = " << x << " s = " << s << std::endl; //osds[0] = s; } #endif //osds[0] = crush_hash32(f) % n; //cout << "oid " << oid << " pgid " << pgid << " on " << osds << std::endl; for (unsigned i=0; i= 0) primary_count[primary]++; } } } uint64_t avg = 0; for (int i=0; iget_pg_num() / (double)n; double edev = sqrt(pgavg) * (double)avg / pgavg; cout << " avg " << avg << " stddev " << dev << " (expected " << edev << ")" << " (indep object placement would be " << sqrt(avg) << ")" << std::endl; for (int i=0; i<4; i++) { cout << "size" << i << "\t" << size[i] << std::endl; } return 0; } ceph-0.80.11/src/tools/dupstore.cc0000664000175100017510000000547612623076744021014 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include "os/FileStore.h" #include "common/ceph_argparse.h" #include "global/global_init.h" #include "include/unordered_map.h" int dupstore(ObjectStore* src, ObjectStore* dst) { if (src->mount() < 0) return 1; if (dst->mkfs() < 0) return 1; if (dst->mount() < 0) return 1; // objects ceph::unordered_map did_object; // collections vector collections; int ret = src->list_collections(collections); if (ret < 0) { cerr << "Error " << ret << " while listing collections" << std::endl; return 1; } int num = collections.size(); cout << num << " collections" << std::endl; int i = 1; for (vector::iterator p = collections.begin(); p != collections.end(); ++p) { cout << "collection " << i++ << "/" << num << " " << hex << *p << dec << std::endl; { ObjectStore::Transaction t; t.create_collection(*p); map attrs; src->collection_getattrs(*p, attrs); t.collection_setattrs(*p, attrs); dst->apply_transaction(t); } vector o; src->collection_list(*p, o); int numo = o.size(); int j = 1; for (vector::iterator q = o.begin(); q != o.end(); ++q) { ObjectStore::Transaction t; if (did_object.count(*q)) t.collection_add(*p, did_object[*q], *q); else { bufferlist bl; src->read(*p, *q, 0, 0, bl); cout << "object " << j++ << "/" << numo << " " << *q << " = " << bl.length() << " bytes" << std::endl; t.write(*p, *q, 0, bl.length(), bl); map attrs; src->getattrs(*p, *q, attrs); t.setattrs(*p, *q, attrs); did_object[*q] = *p; } dst->apply_transaction(t); } } src->umount(); dst->umount(); return 0; } void usage() { cerr << "usage: ceph_dupstore filestore SRC filestore DST" << std::endl; exit(0); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); // args if (args.size() != 4) usage(); ObjectStore *src = 0, *dst = 0; if (strcmp(args[0], "filestore") == 0) src = new FileStore(args[1], NULL); else usage(); if (strcmp(args[2], "filestore") == 0) dst = new FileStore(args[3], NULL); else usage(); return dupstore(src, dst); } ceph-0.80.11/src/tools/ceph_authtool.cc0000664000175100017510000002063212623076744021774 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2009 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "common/config.h" #include "common/strtol.h" #include "common/ConfUtils.h" #include "common/ceph_argparse.h" #include "global/global_context.h" #include "global/global_init.h" #include "auth/Crypto.h" #include "auth/Auth.h" #include "auth/KeyRing.h" #include void usage() { cout << "usage: ceph-authtool keyringfile [OPTIONS]...\n" << "where the options are:\n" << " -l, --list will list all keys and capabilities present in\n" << " the keyring\n" << " -p, --print-key will print an encoded key for the specified\n" << " entityname. This is suitable for the\n" << " 'mount -o secret=..' argument\n" << " -C, --create-keyring will create a new keyring, overwriting any\n" << " existing keyringfile\n" << " -g, --gen-key will generate a new secret key for the\n" << " specified entityname\n" << " --gen-print-key will generate a new secret key without set it\n" << " to the keyringfile, prints the secret to stdout\n" << " --import-keyring will import the content of a given keyring\n" << " into the keyringfile\n" << " -u, --set-uid sets the auid (authenticated user id) for the\n" << " specified entityname\n" << " -a, --add-key will add an encoded key to the keyring\n" << " --cap subsystem capability will set the capability for given subsystem\n" << " --caps capsfile will set all of capabilities associated with a\n" << " given key, for all subsystems" << std::endl; exit(1); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); bool gen_key = false; bool gen_print_key = false; std::string add_key; bool list = false; bool print_key = false; bool create_keyring = false; std::string caps_fn; std::string import_keyring; bool set_auid = false; uint64_t auid = CEPH_AUTH_UID_DEFAULT; map caps; std::string fn; global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); std::vector::iterator i; for (i = args.begin(); i != args.end(); ) { std::string val; if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-g", "--gen-key", (char*)NULL)) { gen_key = true; } else if (ceph_argparse_flag(args, i, "--gen-print-key", (char*)NULL)) { gen_print_key = true; } else if (ceph_argparse_witharg(args, i, &val, "-a", "--add-key", (char*)NULL)) { add_key = val; } else if (ceph_argparse_flag(args, i, "-l", "--list", (char*)NULL)) { list = true; } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) { caps_fn = val; } else if (ceph_argparse_witharg(args, i, &val, "--cap", (char*)NULL)) { std::string my_key = val; if (i == args.end()) { cerr << "must give two arguments to --cap: key and val." << std::endl; exit(1); } std::string my_val = *i; ++i; ::encode(my_val, caps[my_key]); } else if (ceph_argparse_flag(args, i, "-p", "--print-key", (char*)NULL)) { print_key = true; } else if (ceph_argparse_flag(args, i, "-C", "--create-keyring", (char*)NULL)) { create_keyring = true; } else if (ceph_argparse_witharg(args, i, &val, "--import-keyring", (char*)NULL)) { import_keyring = val; } else if (ceph_argparse_witharg(args, i, &val, "-u", "--set-uid", (char*)NULL)) { std::string err; auid = strict_strtoll(val.c_str(), 10, &err); if (!err.empty()) { cerr << "error parsing UID: " << err << std::endl; exit(1); } set_auid = true; } else if (fn.empty()) { fn = *i++; } else { cerr << argv[0] << ": unexpected '" << *i << "'" << std::endl; usage(); } } if (fn.empty() && !gen_print_key) { cerr << argv[0] << ": must specify filename" << std::endl; usage(); } if (!(gen_key || gen_print_key || !add_key.empty() || list || !caps_fn.empty() || !caps.empty() || set_auid || print_key || create_keyring || !import_keyring.empty())) { cerr << "no command specified" << std::endl; usage(); } if (gen_key && (!add_key.empty())) { cerr << "can't both gen_key and add_key" << std::endl; usage(); } common_init_finish(g_ceph_context); EntityName ename(g_conf->name); if (gen_print_key) { CryptoKey key; key.create(g_ceph_context, CEPH_CRYPTO_AES); cout << key << std::endl; return 0; } // keyring -------- bool modified = false; KeyRing keyring; bufferlist bl; int r = 0; if (create_keyring) { cout << "creating " << fn << std::endl; modified = true; } else { std::string err; r = bl.read_file(fn.c_str(), &err); if (r >= 0) { try { bufferlist::iterator iter = bl.begin(); ::decode(keyring, iter); } catch (const buffer::error &err) { cerr << "error reading file " << fn << std::endl; exit(1); } } else { cerr << "can't open " << fn << ": " << err << std::endl; exit(1); } } // write commands if (!import_keyring.empty()) { KeyRing other; bufferlist obl; std::string err; int r = obl.read_file(import_keyring.c_str(), &err); if (r >= 0) { try { bufferlist::iterator iter = obl.begin(); ::decode(other, iter); } catch (const buffer::error &err) { cerr << "error reading file " << import_keyring << std::endl; exit(1); } cout << "importing contents of " << import_keyring << " into " << fn << std::endl; //other.print(cout); keyring.import(g_ceph_context, other); modified = true; } else { cerr << "can't open " << import_keyring << ": " << err << std::endl; exit(1); } } if (gen_key) { EntityAuth eauth; eauth.key.create(g_ceph_context, CEPH_CRYPTO_AES); keyring.add(ename, eauth); modified = true; } if (!add_key.empty()) { EntityAuth eauth; try { eauth.key.decode_base64(add_key); } catch (const buffer::error &err) { cerr << "can't decode key '" << add_key << "'" << std::endl; exit(1); } keyring.add(ename, eauth); modified = true; cout << "added entity " << ename << " auth " << eauth << std::endl; } if (!caps_fn.empty()) { ConfFile cf; std::deque parse_errors; if (cf.parse_file(caps_fn, &parse_errors, &cerr) != 0) { cerr << "could not parse caps file " << caps_fn << std::endl; exit(1); } complain_about_parse_errors(g_ceph_context, &parse_errors); map caps; const char *key_names[] = { "mon", "osd", "mds", NULL }; for (int i=0; key_names[i]; i++) { std::string val; if (cf.read("global", key_names[i], val) == 0) { bufferlist bl; ::encode(val, bl); string s(key_names[i]); caps[s] = bl; } } keyring.set_caps(ename, caps); modified = true; } if (!caps.empty()) { keyring.set_caps(ename, caps); modified = true; } if (set_auid) { keyring.set_uid(ename, auid); modified = true; } // read commands if (list) { keyring.print(cout); } if (print_key) { CryptoKey key; if (keyring.get_secret(ename, key)) { cout << key << std::endl; } else { cerr << "entity " << ename << " not found" << std::endl; } } // write result? if (modified) { bufferlist bl; keyring.encode_plaintext(bl); r = bl.write_file(fn.c_str(), 0600); if (r < 0) { cerr << "could not write " << fn << std::endl; } //cout << "wrote " << bl.length() << " bytes to " << fn << std::endl; } return 0; } ceph-0.80.11/src/tools/rest_bench.cc0000664000175100017510000005035412623076744021256 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "include/types.h" #include "include/atomic.h" #include "common/obj_bencher.h" #include "common/config.h" #include "common/debug.h" #include "common/ceph_argparse.h" #include "common/WorkQueue.h" #include "msg/Message.h" #include "global/global_init.h" #include "libs3.h" #include #include #define DEFAULT_USER_AGENT "rest-bench" #define DEFAULT_BUCKET "rest-bench-bucket" void usage(ostream& out) { out << \ "usage: rest-bench [options] \n" " rest-bench [options] cleanup [--run-name run_name] [--prefix prefix]\n" "BENCHMARK OPTIONS\n" " --seconds\n" " benchmak length (default: 60)\n" " -t concurrent_operations\n" " --concurrent-ios=concurrent_operations\n" " select bucket by name\n" " -b op-size\n" " --block-size=op-size\n" " set the size of write ops for put or benchmarking\n" " --show-time\n" " prefix output lines with date and time\n" " --no-cleanup\n" " do not clean up data after write bench\n" "REST CONFIG OPTIONS\n" " --api-host=bhost\n" " host name\n" " --bucket=bucket\n" " select bucket by name\n" " --access-key=access_key\n" " access key to RESTful storage provider\n" " --secret=secret_key\n" " secret key for the specified access key\n" " --protocol=\n" " protocol to be used (default: http)\n" " --uri_style=\n" " uri style in requests (default: path)\n"; } static void usage_exit() { usage(cerr); exit(1); } enum OpType { OP_NONE = 0, OP_GET_OBJ = 1, OP_PUT_OBJ = 2, OP_DELETE_OBJ = 3, OP_LIST_BUCKET = 4, OP_CLEANUP = 5, }; struct req_context : public RefCountedObject { bool complete; S3Status status; S3RequestContext *ctx; void (*cb)(void *, void *); void *arg; bufferlist *in_bl; bufferlist out_bl; uint64_t off; uint64_t len; const char *list_start; std::list* list_objects; int list_count; string oid; Mutex lock; Cond cond; S3BucketContext *bucket_ctx; bool should_destroy_ctx; OpType op; bool used; req_context() : complete(false), status(S3StatusOK), ctx(NULL), cb(NULL), arg(NULL), in_bl(NULL), off(0), len(0), lock("req_context"), bucket_ctx(NULL), should_destroy_ctx(false), op(OP_NONE), used(false) {} ~req_context() { if (should_destroy_ctx) { S3_destroy_request_context(ctx); } } int init_ctx() { S3Status status = S3_create_request_context(&ctx); if (status != S3StatusOK) { cerr << "failed to create context: " << S3_get_status_name(status) << std::endl; return -EINVAL; } should_destroy_ctx = true; return 0; } int ret() { if (status != S3StatusOK) { return -EINVAL; } return 0; } }; static S3Status properties_callback(const S3ResponseProperties *properties, void *cb_data) { return S3StatusOK; } static void complete_callback(S3Status status, const S3ErrorDetails *details, void *cb_data) { if (!cb_data) return; struct req_context *ctx = (struct req_context *)cb_data; ctx->lock.Lock(); ctx->status = status; ctx->lock.Unlock(); if (ctx->cb) { ctx->cb((void *)ctx->cb, ctx->arg); } ctx->put(); } static S3Status get_obj_callback(int size, const char *buf, void *cb_data) { if (!cb_data) return S3StatusOK; struct req_context *ctx = (struct req_context *)cb_data; ctx->in_bl->append(buf, size); return S3StatusOK; } static int put_obj_callback(int size, char *buf, void *cb_data) { if (!cb_data) return 0; struct req_context *ctx = (struct req_context *)cb_data; int chunk = ctx->out_bl.length() - ctx->off; if (!chunk) return 0; if (chunk > size) chunk = size; memcpy(buf, ctx->out_bl.c_str() + ctx->off, chunk); ctx->off += chunk; return chunk; } static S3Status list_bucket_callback(int is_truncated, const char *next_marker, int count, const S3ListBucketContent *objects, int prefix_count, const char **prefixes, void *cb_data) { if (!cb_data) return S3StatusOK; struct req_context *ctx = (struct req_context *)cb_data; ctx->list_start = next_marker; for (int i = 0; i < count; ++i) { ctx->list_objects->push_back(objects[i].key); } return S3StatusOK; } class RESTDispatcher { deque m_req_queue; ThreadPool m_tp; S3ResponseHandler response_handler; S3GetObjectHandler get_obj_handler; S3PutObjectHandler put_obj_handler; S3ListBucketHandler list_bucket_handler; struct DispatcherWQ : public ThreadPool::WorkQueue { RESTDispatcher *dispatcher; DispatcherWQ(RESTDispatcher *p, time_t timeout, time_t suicide_timeout, ThreadPool *tp) : ThreadPool::WorkQueue("REST", timeout, suicide_timeout, tp), dispatcher(p) {} bool _enqueue(req_context *req) { dispatcher->m_req_queue.push_back(req); _dump_queue(); return true; } void _dequeue(req_context *req) { assert(0); } bool _empty() { return dispatcher->m_req_queue.empty(); } req_context *_dequeue() { if (dispatcher->m_req_queue.empty()) return NULL; req_context *req = dispatcher->m_req_queue.front(); dispatcher->m_req_queue.pop_front(); _dump_queue(); return req; } void _process(req_context *req) { dispatcher->process_context(req); } void _dump_queue() { deque::iterator iter; if (dispatcher->m_req_queue.empty()) { generic_dout(20) << "DispatcherWQ: empty" << dendl; return; } generic_dout(20) << "DispatcherWQ:" << dendl; for (iter = dispatcher->m_req_queue.begin(); iter != dispatcher->m_req_queue.end(); ++iter) { generic_dout(20) << "req: " << hex << *iter << dec << dendl; } } void _clear() { assert(dispatcher->m_req_queue.empty()); } } req_wq; public: CephContext *cct; RESTDispatcher(CephContext *cct_, int num_threads) : m_tp(cct_, "RESTDispatcher::m_tp", num_threads), req_wq(this, cct_->_conf->rgw_op_thread_timeout, cct_->_conf->rgw_op_thread_suicide_timeout, &m_tp), cct(cct_) { response_handler.propertiesCallback = properties_callback; response_handler.completeCallback = complete_callback; get_obj_handler.responseHandler = response_handler; get_obj_handler.getObjectDataCallback = get_obj_callback; put_obj_handler.responseHandler = response_handler; put_obj_handler.putObjectDataCallback = put_obj_callback; list_bucket_handler.responseHandler = response_handler; list_bucket_handler.listBucketCallback = list_bucket_callback; } void process_context(req_context *ctx); void get_obj(req_context *ctx); void put_obj(req_context *ctx); void delete_obj(req_context *ctx); void list_bucket(req_context *ctx); void queue(req_context *ctx) { req_wq.queue(ctx); } void start() { m_tp.start(); } }; void RESTDispatcher::process_context(req_context *ctx) { ctx->get(); switch (ctx->op) { case OP_GET_OBJ: get_obj(ctx); break; case OP_PUT_OBJ: put_obj(ctx); break; case OP_DELETE_OBJ: delete_obj(ctx); break; case OP_LIST_BUCKET: list_bucket(ctx); break; default: assert(0); } S3Status status = S3_runall_request_context(ctx->ctx); if (status != S3StatusOK) { cerr << "ERROR: S3_runall_request_context() returned " << S3_get_status_name(status) << std::endl; ctx->status = status; } else if (ctx->status != S3StatusOK) { cerr << "ERROR: " << ctx->oid << ": " << S3_get_status_name(ctx->status) << std::endl; } ctx->lock.Lock(); ctx->complete = true; ctx->cond.SignalAll(); ctx->lock.Unlock(); ctx->put(); } void RESTDispatcher::put_obj(req_context *ctx) { S3_put_object(ctx->bucket_ctx, ctx->oid.c_str(), ctx->out_bl.length(), NULL, ctx->ctx, &put_obj_handler, ctx); } void RESTDispatcher::get_obj(req_context *ctx) { S3_get_object(ctx->bucket_ctx, ctx->oid.c_str(), NULL, 0, ctx->len, ctx->ctx, &get_obj_handler, ctx); } void RESTDispatcher::delete_obj(req_context *ctx) { S3_delete_object(ctx->bucket_ctx, ctx->oid.c_str(), ctx->ctx, &response_handler, ctx); } void RESTDispatcher::list_bucket(req_context *ctx) { S3_list_bucket(ctx->bucket_ctx, NULL, ctx->list_start, NULL, ctx->list_count, ctx->ctx, &list_bucket_handler, ctx); } class RESTBencher : public ObjBencher { RESTDispatcher *dispatcher; struct req_context **completions; struct S3RequestContext **handles; S3BucketContext bucket_ctx; const char *list_start; bool bucket_list_done; string user_agent; string host; string bucket; S3Protocol protocol; string access_key; string secret; int concurrentios; protected: int rest_init() { S3Status status = S3_initialize(user_agent.c_str(), S3_INIT_ALL, host.c_str()); if (status != S3StatusOK) { cerr << "failed to init: " << S3_get_status_name(status) << std::endl; return -EINVAL; } return 0; } int completions_init(int _concurrentios) { concurrentios = _concurrentios; completions = new req_context *[concurrentios]; handles = new S3RequestContext *[concurrentios]; for (int i = 0; i < concurrentios; i++) { completions[i] = NULL; S3Status status = S3_create_request_context(&handles[i]); if (status != S3StatusOK) { cerr << "failed to create context: " << S3_get_status_name(status) << std::endl; return -EINVAL; } } return 0; } void completions_done() { delete[] completions; completions = NULL; for (int i = 0; i < concurrentios; i++) { S3_destroy_request_context(handles[i]); } delete[] handles; handles = NULL; } int create_completion(int slot, void (*cb)(void *, void*), void *arg) { assert (!completions[slot]); struct req_context *ctx = new req_context; ctx->ctx = handles[slot]; assert (!ctx->used); ctx->used = true; ctx->cb = cb; ctx->arg = arg; completions[slot] = ctx; return 0; } void release_completion(int slot) { struct req_context *ctx = completions[slot]; ctx->used = false; ctx->put(); completions[slot] = 0; } int aio_read(const std::string& oid, int slot, bufferlist *pbl, size_t len) { struct req_context *ctx = completions[slot]; ctx->get(); ctx->in_bl = pbl; ctx->oid = oid; ctx->len = len; ctx->bucket_ctx = &bucket_ctx; ctx->op = OP_GET_OBJ; dispatcher->queue(ctx); return 0; } int aio_write(const std::string& oid, int slot, bufferlist& bl, size_t len) { struct req_context *ctx = completions[slot]; ctx->get(); ctx->bucket_ctx = &bucket_ctx; ctx->out_bl = bl; ctx->oid = oid; ctx->len = len; ctx->op = OP_PUT_OBJ; dispatcher->queue(ctx); return 0; } int aio_remove(const std::string& oid, int slot) { struct req_context *ctx = completions[slot]; ctx->get(); ctx->bucket_ctx = &bucket_ctx; ctx->oid = oid; ctx->op = OP_DELETE_OBJ; dispatcher->queue(ctx); return 0; } int sync_read(const std::string& oid, bufferlist& bl, size_t len) { struct req_context *ctx = new req_context; int ret = ctx->init_ctx(); if (ret < 0) { return ret; } ctx->in_bl = &bl; ctx->get(); ctx->bucket_ctx = &bucket_ctx; ctx->oid = oid; ctx->len = len; ctx->op = OP_GET_OBJ; dispatcher->process_context(ctx); ret = ctx->ret(); ctx->put(); return bl.length(); } int sync_write(const std::string& oid, bufferlist& bl, size_t len) { struct req_context *ctx = new req_context; int ret = ctx->init_ctx(); if (ret < 0) { return ret; } ctx->get(); ctx->out_bl = bl; ctx->bucket_ctx = &bucket_ctx; ctx->oid = oid; ctx->op = OP_PUT_OBJ; dispatcher->process_context(ctx); ret = ctx->ret(); ctx->put(); return ret; } int sync_remove(const std::string& oid) { struct req_context *ctx = new req_context; int ret = ctx->init_ctx(); if (ret < 0) { return ret; } ctx->get(); ctx->bucket_ctx = &bucket_ctx; ctx->oid = oid; ctx->op = OP_DELETE_OBJ; dispatcher->process_context(ctx); ret = ctx->ret(); ctx->put(); return ret; } bool get_objects(std::list* objects, int num) { if (bucket_list_done) { bucket_list_done = false; return false; } struct req_context *ctx = new req_context; int ret = ctx->init_ctx(); if (ret < 0) { return ret; } ctx->get(); ctx->bucket_ctx = &bucket_ctx; ctx->list_start = list_start; ctx->list_objects = objects; ctx->list_count = num; ctx->op = OP_LIST_BUCKET; dispatcher->process_context(ctx); ret = ctx->ret(); list_start = ctx->list_start; if (list_start == NULL || strcmp(list_start, "") == 0) { bucket_list_done = true; list_start = NULL; } ctx->put(); return ret == 0; } bool completion_is_done(int slot) { return completions[slot]->complete; } int completion_wait(int slot) { req_context *ctx = completions[slot]; Mutex::Locker l(ctx->lock); while (!ctx->complete) { ctx->cond.Wait(ctx->lock); } return 0; } int completion_ret(int slot) { S3Status status = completions[slot]->status; if (status != S3StatusOK) return -EIO; return 0; } public: RESTBencher(RESTDispatcher *_dispatcher) : ObjBencher(_dispatcher->cct), dispatcher(_dispatcher), completions(NULL), list_start(NULL), bucket_list_done(false) { dispatcher->start(); } ~RESTBencher() { } int init(string& _agent, string& _host, string& _bucket, S3Protocol _protocol, S3UriStyle uri_style, string& _access_key, string& _secret) { user_agent = _agent; host = _host; bucket = _bucket; protocol = _protocol; access_key = _access_key; secret = _secret; bucket_ctx.hostName = NULL; // host.c_str(); bucket_ctx.bucketName = bucket.c_str(); bucket_ctx.protocol = protocol; bucket_ctx.accessKeyId = access_key.c_str(); bucket_ctx.secretAccessKey = secret.c_str(); bucket_ctx.uriStyle = uri_style; struct req_context *ctx = new req_context; int ret = rest_init(); if (ret < 0) { return ret; } ret = ctx->init_ctx(); if (ret < 0) { return ret; } ctx->get(); S3ResponseHandler response_handler; response_handler.propertiesCallback = properties_callback; response_handler.completeCallback = complete_callback; S3_create_bucket(protocol, access_key.c_str(), secret.c_str(), NULL, bucket.c_str(), S3CannedAclPrivate, NULL, /* locationConstraint */ NULL, /* requestContext */ &response_handler, /* handler */ (void *)ctx /* callbackData */); ret = ctx->ret(); if (ret < 0) { cerr << "ERROR: failed to create bucket: " << S3_get_status_name(ctx->status) << std::endl; return ret; } ctx->put(); return 0; } }; int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); std::vector::iterator i; std::string host; std::string val; std::string user_agent; std::string access_key; std::string secret; std::string bucket = DEFAULT_BUCKET; S3Protocol protocol = S3ProtocolHTTP; S3UriStyle uri_style = S3UriStylePath; std::string proto_str; int concurrent_ios = 16; int op_size = 1 << 22; int seconds = 60; bool show_time = false; bool cleanup = true; std::string run_name; std::string prefix; for (i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(cout); exit(0); } else if (ceph_argparse_flag(args, i, "--show-time", (char*)NULL)) { show_time = true; } else if (ceph_argparse_flag(args, i, "--no-cleanup", (char*)NULL)) { cleanup = false; } else if (ceph_argparse_witharg(args, i, &user_agent, "--agent", (char*)NULL)) { /* nothing */ } else if (ceph_argparse_witharg(args, i, &access_key, "--access-key", (char*)NULL)) { /* nothing */ } else if (ceph_argparse_witharg(args, i, &secret, "--secret", (char*)NULL)) { /* nothing */ } else if (ceph_argparse_witharg(args, i, &bucket, "--bucket", (char*)NULL)) { /* nothing */ } else if (ceph_argparse_witharg(args, i, &host, "--api-host", (char*)NULL)) { cerr << "host=" << host << std::endl; /* nothing */ } else if (ceph_argparse_witharg(args, i, &proto_str, "--protocol", (char*)NULL)) { if (strcasecmp(proto_str.c_str(), "http") == 0) { protocol = S3ProtocolHTTP; } else if (strcasecmp(proto_str.c_str(), "http") == 0) { protocol = S3ProtocolHTTPS; } else { cerr << "bad protocol" << std::endl; usage_exit(); } /* nothing */ } else if (ceph_argparse_witharg(args, i, &proto_str, "--uri-style", (char*)NULL)) { if (strcasecmp(proto_str.c_str(), "vhost") == 0) { uri_style = S3UriStyleVirtualHost; } else if (strcasecmp(proto_str.c_str(), "path") == 0) { uri_style = S3UriStylePath; } else { cerr << "bad protocol" << std::endl; usage_exit(); } } else if (ceph_argparse_witharg(args, i, &val, "-t", "--concurrent-ios", (char*)NULL)) { concurrent_ios = strtol(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "--run-name", (char*)NULL)) { run_name = val; } else if (ceph_argparse_witharg(args, i, &val, "--prefix", (char*)NULL)) { prefix = val; } else if (ceph_argparse_witharg(args, i, &val, "--seconds", (char*)NULL)) { seconds = strtol(val.c_str(), NULL, 10); } else if (ceph_argparse_witharg(args, i, &val, "-b", "--block-size", (char*)NULL)) { op_size = strtol(val.c_str(), NULL, 10); } else { if (val[0] == '-') usage_exit(); ++i; } } if (bucket.empty()) { cerr << "rest-bench: bucket not specified" << std::endl; usage_exit(); } if (args.empty()) usage_exit(); int operation = 0; if (strcmp(args[0], "write") == 0) operation = OP_WRITE; else if (strcmp(args[0], "seq") == 0) operation = OP_SEQ_READ; else if (strcmp(args[0], "rand") == 0) operation = OP_RAND_READ; else if (strcmp(args[0], "cleanup") == 0) { operation = OP_CLEANUP; } else usage_exit(); if (host.empty()) { cerr << "rest-bench: api host not provided." << std::endl; usage_exit(); } if (access_key.empty() || secret.empty()) { cerr << "rest-bench: access key or secret was not provided" << std::endl; usage_exit(); } if (bucket.empty()) { bucket = DEFAULT_BUCKET; } if (user_agent.empty()) user_agent = DEFAULT_USER_AGENT; RESTDispatcher dispatcher(g_ceph_context, concurrent_ios); RESTBencher bencher(&dispatcher); bencher.set_show_time(show_time); int ret = bencher.init(user_agent, host, bucket, protocol, uri_style, access_key, secret); if (ret < 0) { cerr << "failed initializing benchmark" << std::endl; exit(1); } if (operation == OP_CLEANUP) { ret = bencher.clean_up(prefix.c_str(), concurrent_ios, run_name.c_str()); if (ret != 0) cerr << "error during cleanup: " << ret << std::endl; } else { ret = bencher.aio_bench(operation, seconds, 0, concurrent_ios, op_size, cleanup, run_name.c_str()); if (ret != 0) { cerr << "error during benchmark: " << ret << std::endl; } } return 0; } ceph-0.80.11/src/tools/osdmaptool.cc0000664000175100017510000003522412623076744021322 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include using namespace std; #include "common/config.h" #include "common/errno.h" #include "osd/OSDMap.h" #include "mon/MonMap.h" #include "common/ceph_argparse.h" #include "global/global_init.h" void usage() { cout << " usage: [--print] [--createsimple [--clobber] [--pg_bits ]] " << std::endl; cout << " --export-crush write osdmap's crush map to " << std::endl; cout << " --import-crush replace osdmap's crush map with " << std::endl; cout << " --test-map-pgs [--pool ] map all pgs" << std::endl; cout << " --test-map-pgs-dump [--pool ] map all pgs" << std::endl; cout << " --mark-up-in mark osds up and in (but do not persist)" << std::endl; cout << " --clear-temp clear pg_temp and primary_temp" << std::endl; cout << " --test-random do random placements" << std::endl; cout << " --test-map-pg map a pgid to osds" << std::endl; cout << " --test-map-object [--pool ] map an object to osds" << std::endl; exit(1); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); common_init_finish(g_ceph_context); const char *me = argv[0]; std::string fn; bool print = false; bool print_json = false; bool tree = false; bool createsimple = false; bool create_from_conf = false; int num_osd = 0; int pg_bits = g_conf->osd_pg_bits; int pgp_bits = g_conf->osd_pgp_bits; bool clobber = false; bool modified = false; std::string export_crush, import_crush, test_map_pg, test_map_object; bool test_crush = false; int range_first = -1; int range_last = -1; int pool = -1; bool mark_up_in = false; bool clear_temp = false; bool test_map_pgs = false; bool test_map_pgs_dump = false; bool test_random = false; std::string val; std::ostringstream err; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); } else if (ceph_argparse_flag(args, i, "-p", "--print", (char*)NULL)) { print = true; } else if (ceph_argparse_flag(args, i, "--dump-json", (char*)NULL)) { print_json = true; } else if (ceph_argparse_flag(args, i, "--tree", (char*)NULL)) { tree = true; } else if (ceph_argparse_withint(args, i, &num_osd, &err, "--createsimple", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } createsimple = true; } else if (ceph_argparse_flag(args, i, "--create-from-conf", (char*)NULL)) { create_from_conf = true; } else if (ceph_argparse_flag(args, i, "--mark-up-in", (char*)NULL)) { mark_up_in = true; } else if (ceph_argparse_flag(args, i, "--clear-temp", (char*)NULL)) { clear_temp = true; } else if (ceph_argparse_flag(args, i, "--test-map-pgs", (char*)NULL)) { test_map_pgs = true; } else if (ceph_argparse_flag(args, i, "--test-map-pgs-dump", (char*)NULL)) { test_map_pgs_dump = true; } else if (ceph_argparse_flag(args, i, "--test-random", (char*)NULL)) { test_random = true; } else if (ceph_argparse_flag(args, i, "--clobber", (char*)NULL)) { clobber = true; } else if (ceph_argparse_withint(args, i, &pg_bits, &err, "--pg_bits", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } } else if (ceph_argparse_withint(args, i, &pgp_bits, &err, "--pgp_bits", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } } else if (ceph_argparse_witharg(args, i, &val, "--export_crush", (char*)NULL)) { export_crush = val; } else if (ceph_argparse_witharg(args, i, &val, "--import_crush", (char*)NULL)) { import_crush = val; } else if (ceph_argparse_witharg(args, i, &val, "--test_map_pg", (char*)NULL)) { test_map_pg = val; } else if (ceph_argparse_witharg(args, i, &val, "--test_map_object", (char*)NULL)) { test_map_object = val; } else if (ceph_argparse_flag(args, i, "--test_crush", (char*)NULL)) { test_crush = true; } else if (ceph_argparse_withint(args, i, &range_first, &err, "--range_first", (char*)NULL)) { } else if (ceph_argparse_withint(args, i, &range_last, &err, "--range_last", (char*)NULL)) { } else if (ceph_argparse_withint(args, i, &pool, &err, "--pool", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; exit(EXIT_FAILURE); } } else { ++i; } } if (args.empty()) { cerr << me << ": must specify osdmap filename" << std::endl; usage(); } else if (args.size() > 1) { cerr << me << ": too many arguments" << std::endl; usage(); } fn = args[0]; if (range_first >= 0 && range_last >= 0) { set maps; OSDMap *prev = NULL; for (int i=range_first; i <= range_last; i++) { ostringstream f; f << fn << "/" << i; bufferlist bl; string error, s = f.str(); int r = bl.read_file(s.c_str(), &error); if (r < 0) { cerr << "unable to read " << s << ": " << cpp_strerror(r) << std::endl; exit(1); } cout << s << " got " << bl.length() << " bytes" << std::endl; OSDMap *o = new OSDMap; o->decode(bl); maps.insert(o); if (prev) OSDMap::dedup(prev, o); prev = o; } exit(0); } OSDMap osdmap; bufferlist bl; cerr << me << ": osdmap file '" << fn << "'" << std::endl; int r = 0; struct stat st; if (!createsimple && !create_from_conf && !clobber) { std::string error; r = bl.read_file(fn.c_str(), &error); if (r == 0) { try { osdmap.decode(bl); } catch (const buffer::error &e) { cerr << me << ": error decoding osdmap '" << fn << "'" << std::endl; return -1; } } else { cerr << me << ": couldn't open " << fn << ": " << error << std::endl; return -1; } } else if ((createsimple || create_from_conf) && !clobber && ::stat(fn.c_str(), &st) == 0) { cerr << me << ": " << fn << " exists, --clobber to overwrite" << std::endl; return -1; } if (createsimple || create_from_conf) { if (createsimple) { if (num_osd < 1) { cerr << me << ": osd count must be > 0" << std::endl; exit(1); } } else { num_osd = -1; } uuid_d fsid; memset(&fsid, 0, sizeof(uuid_d)); osdmap.build_simple(g_ceph_context, 0, fsid, num_osd, pg_bits, pgp_bits); modified = true; } if (mark_up_in) { cout << "marking all OSDs up and in" << std::endl; int n = osdmap.get_max_osd(); for (int i=0; iadjust_item_weightf(g_ceph_context, i, 1.0); } } if (clear_temp) { cout << "clearing pg/primary temp" << std::endl; osdmap.clear_temp(); } if (!import_crush.empty()) { bufferlist cbl; std::string error; r = cbl.read_file(import_crush.c_str(), &error); if (r) { cerr << me << ": error reading crush map from " << import_crush << ": " << error << std::endl; exit(1); } // validate CrushWrapper cw; bufferlist::iterator p = cbl.begin(); cw.decode(p); if (cw.get_max_devices() > osdmap.get_max_osd()) { cerr << me << ": crushmap max_devices " << cw.get_max_devices() << " > osdmap max_osd " << osdmap.get_max_osd() << std::endl; exit(1); } // apply OSDMap::Incremental inc; inc.fsid = osdmap.get_fsid(); inc.epoch = osdmap.get_epoch()+1; inc.crush = cbl; osdmap.apply_incremental(inc); cout << me << ": imported " << cbl.length() << " byte crush map from " << import_crush << std::endl; modified = true; } if (!export_crush.empty()) { bufferlist cbl; osdmap.crush->encode(cbl); r = cbl.write_file(export_crush.c_str()); if (r < 0) { cerr << me << ": error writing crush map to " << import_crush << std::endl; exit(1); } cout << me << ": exported crush map to " << export_crush << std::endl; } if (!test_map_object.empty()) { object_t oid(test_map_object); if (pool == -1) { cout << me << ": assuming pool 0 (use --pool to override)" << std::endl; pool = 0; } if (!osdmap.have_pg_pool(pool)) { cerr << "There is no pool " << pool << std::endl; exit(1); } object_locator_t loc(pool); pg_t raw_pgid = osdmap.object_locator_to_pg(oid, loc); pg_t pgid = osdmap.raw_pg_to_pg(raw_pgid); vector acting; osdmap.pg_to_acting_osds(pgid, acting); cout << " object '" << oid << "' -> " << pgid << " -> " << acting << std::endl; } if (!test_map_pg.empty()) { pg_t pgid; if (!pgid.parse(test_map_pg.c_str())) { cerr << me << ": failed to parse pg '" << test_map_pg << "', r = " << r << std::endl; usage(); } cout << " parsed '" << test_map_pg << "' -> " << pgid << std::endl; vector raw, up, acting; int calced_primary, up_primary, acting_primary; osdmap.pg_to_osds(pgid, &raw, &calced_primary); osdmap.pg_to_up_acting_osds(pgid, &up, &up_primary, &acting, &acting_primary); cout << pgid << " raw (" << raw << ", p" << calced_primary << ") up (" << up << ", p" << up_primary << ") acting (" << acting << ", p" << acting_primary << ")" << std::endl; } if (test_map_pgs || test_map_pgs_dump) { if (pool != -1 && !osdmap.have_pg_pool(pool)) { cerr << "There is no pool " << pool << std::endl; exit(1); } int n = osdmap.get_max_osd(); vector count(n, 0); vector first_count(n, 0); vector primary_count(n, 0); vector size(30, 0); if (test_random) srand(getpid()); const map& pools = osdmap.get_pools(); for (map::const_iterator p = pools.begin(); p != pools.end(); ++p) { if (pool != -1 && p->first != pool) continue; cout << "pool " << p->first << " pg_num " << p->second.get_pg_num() << std::endl; for (unsigned i = 0; i < p->second.get_pg_num(); ++i) { pg_t pgid = pg_t(i, p->first); vector osds; int primary; if (test_random) { osds.resize(p->second.size); for (unsigned i=0; i= 0) primary_count[primary]++; } } uint64_t total = 0; int in = 0; int min_osd = -1; int max_osd = -1; cout << "#osd\tcount\tfirst\tprimary\tc wt\twt\n"; for (int i=0; iget_item_weight(i) <= 0) continue; in++; cout << "osd." << i << "\t" << count[i] << "\t" << first_count[i] << "\t" << primary_count[i] << "\t" << osdmap.crush->get_item_weightf(i) << "\t" << osdmap.get_weightf(i) << std::endl; total += count[i]; if (count[i] && (min_osd < 0 || count[i] < count[min_osd])) min_osd = i; if (count[i] && (max_osd < 0 || count[i] > count[max_osd])) max_osd = i; } uint64_t avg = total / in; double dev = 0; for (int i=0; iget_item_weight(i) <= 0) continue; dev += (avg - count[i]) * (avg - count[i]); } dev /= in; dev = sqrt(dev); //double edev = sqrt(pgavg) * (double)avg / pgavg; double edev = sqrt((double)total / (double)in * (1.0 - (1.0 / (double)in))); cout << " in " << in << std::endl; cout << " avg " << avg << " stddev " << dev << " (" << (dev/avg) << "x)" << " (expected " << edev << " " << (edev/avg) << "x))" << std::endl; if (min_osd >= 0) cout << " min osd." << min_osd << " " << count[min_osd] << std::endl; if (max_osd >= 0) cout << " max osd." << max_osd << " " << count[max_osd] << std::endl; for (int i=0; i<4; i++) { cout << "size " << i << "\t" << size[i] << std::endl; } } if (test_crush) { int pass = 0; while (1) { cout << "pass " << ++pass << std::endl; ceph::unordered_map > m; for (map::const_iterator p = osdmap.get_pools().begin(); p != osdmap.get_pools().end(); ++p) { const pg_pool_t *pool = osdmap.get_pg_pool(p->first); for (ps_t ps = 0; ps < pool->get_pg_num(); ps++) { pg_t pgid(ps, p->first, -1); for (int i=0; i<100; i++) { cout << pgid << " attempt " << i << std::endl; vector r; osdmap.pg_to_acting_osds(pgid, r); //cout << pgid << " " << r << std::endl; if (m.count(pgid)) { if (m[pgid] != r) { cout << pgid << " had " << m[pgid] << " now " << r << std::endl; assert(0); } } else m[pgid] = r; } } } } } if (!print && !print_json && !tree && !modified && export_crush.empty() && import_crush.empty() && test_map_pg.empty() && test_map_object.empty() && !test_map_pgs && !test_map_pgs_dump) { cerr << me << ": no action specified?" << std::endl; usage(); } if (modified) osdmap.inc_epoch(); if (print) osdmap.print(cout); if (print_json) osdmap.dump_json(cout); if (tree) osdmap.print_tree(&cout, NULL); if (modified) { bl.clear(); osdmap.encode(bl); // write it out cout << me << ": writing epoch " << osdmap.get_epoch() << " to " << fn << std::endl; int r = bl.write_file(fn.c_str()); if (r) { cerr << "osdmaptool: error writing to '" << fn << "': " << cpp_strerror(r) << std::endl; return 1; } } return 0; } ceph-0.80.11/src/tools/common.h0000664000175100017510000000542612623076744020274 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_TOOLS_COMMON_DOT_H #define CEPH_TOOLS_COMMON_DOT_H #include #include #include #include "common/Cond.h" #include "common/Mutex.h" #include "mon/MonClient.h" #include "mon/PGMap.h" #include "mds/MDSMap.h" #include "osd/OSDMap.h" #include "common/Timer.h" #include "common/LogEntry.h" #include "mon/mon_types.h" #include "messages/MOSDMap.h" #include "messages/MLog.h" #include "messages/MCommand.h" #include "messages/MCommandReply.h" #include "messages/MMonCommandAck.h" #define OSD_MON_UPDATE (1<<0) #define MDS_MON_UPDATE (1<<1) #define PG_MON_UPDATE (1<<2) #define MON_MON_UPDATE (1<<3) #define EVERYTHING_UPDATE 0xffffffff class CephContext; class CephToolCtx; enum ceph_tool_mode_t { CEPH_TOOL_MODE_CLI_INPUT = 0, CEPH_TOOL_MODE_WATCH = 1, CEPH_TOOL_MODE_STATUS = 2, CEPH_TOOL_MODE_GUI = 3 }; struct Subscriptions { CephToolCtx *ctx; version_t last_known_version; string name; Subscriptions(CephToolCtx *c) : ctx(c), last_known_version(0) { } void handle_log(MLog *m); }; class Admin : public Dispatcher { private: CephToolCtx *ctx; public: Subscriptions subs; Admin(CephToolCtx *ctx_) : Dispatcher(g_ceph_context), ctx(ctx_), subs(ctx_) { } bool ms_dispatch(Message *m); void ms_handle_connect(Connection *con); bool ms_handle_reset(Connection *con); void ms_handle_remote_reset(Connection *con) {} bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new); }; // tool/ceph.cc class CephToolCtx { public: CephContext *cct; PGMap pgmap; MDSMap mdsmap; OSDMap osdmap; MonClient mc; // Which aspects of the cluster have been updated recently? uint32_t updates; // The main log for ceph-tool std::ostream *log; // Used by the GUI to read from the log. // NULL if there is no GUI active. std::ostringstream *slog; // The ceph-tool lock Mutex lock; SafeTimer timer; // A condition variable used to wake up the GUI thread Cond gui_cond; bool concise; Admin *dispatcher; CephToolCtx(CephContext *cct_, bool concise_) : cct(cct_), mc(g_ceph_context), updates(EVERYTHING_UPDATE), log(&std::cout), slog(NULL), lock("ceph.cc lock"), timer(cct_, lock), concise(concise_), dispatcher(NULL) { } ~CephToolCtx() { delete dispatcher; } }; // tool/ceph.cc int ceph_tool_do_cli(CephToolCtx *data); int run_command(CephToolCtx *data, const char *line); CephToolCtx* ceph_tool_common_init(ceph_tool_mode_t mode, bool concise); int do_command(CephToolCtx *ctx, vector& cmd, bufferlist& bl, bufferlist& rbl); int ceph_tool_messenger_shutdown(); int ceph_tool_common_shutdown(CephToolCtx *ctx); #endif ceph-0.80.11/src/arch/0000775000175100017510000000000012623077035016373 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/arch/neon.h0000664000175100017510000000035512623076744017514 0ustar jenkins-buildjenkins-build#ifndef CEPH_ARCH_NEON_H #define CEPH_ARCH_NEON_H #ifdef __cplusplus extern "C" { #endif extern int ceph_arch_neon; /* true if we have ARM NEON abilities */ extern int ceph_arch_neon_probe(void); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/arch/neon.c0000664000175100017510000000146112623076744017506 0ustar jenkins-buildjenkins-build#include "arch/probe.h" /* flags we export */ int ceph_arch_neon = 0; #include #if __linux__ #include #include // ElfW macro #if __arm__ #include #endif // __arm__ static unsigned long get_auxval(unsigned long type) { unsigned long result = 0; FILE *f = fopen("/proc/self/auxv", "r"); if (f) { ElfW(auxv_t) entry; while (fread(&entry, sizeof(entry), 1, f)) { if (entry.a_type == type) { result = entry.a_un.a_val; break; } } fclose(f); } return result; } static unsigned long get_hwcap(void) { return get_auxval(AT_HWCAP); } #endif // __linux__ int ceph_arch_neon_probe(void) { #if __arm__ && __linux__ ceph_arch_neon = (get_hwcap() & HWCAP_NEON) == HWCAP_NEON; #else if (0) get_hwcap(); // make compiler shut up #endif return 0; } ceph-0.80.11/src/arch/intel.h0000664000175100017510000000114012623076744017661 0ustar jenkins-buildjenkins-build#ifndef CEPH_ARCH_INTEL_H #define CEPH_ARCH_INTEL_H #ifdef __cplusplus extern "C" { #endif extern int ceph_arch_intel_pclmul; /* true if we have PCLMUL features */ extern int ceph_arch_intel_sse42; /* true if we have sse 4.2 features */ extern int ceph_arch_intel_sse41; /* true if we have sse 4.1 features */ extern int ceph_arch_intel_ssse3; /* true if we have ssse 3 features */ extern int ceph_arch_intel_sse3; /* true if we have sse 3 features */ extern int ceph_arch_intel_sse2; /* true if we have sse 2 features */ extern int ceph_arch_intel_probe(void); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/arch/intel.c0000664000175100017510000000431712623076744017665 0ustar jenkins-buildjenkins-build/* * Ceph - scalable distributed file system * * Copyright (C) 2013,2014 Inktank Storage, Inc. * Copyright (C) 2014 Cloudwatt * * Author: Loic Dachary * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #include #include "arch/probe.h" /* flags we export */ int ceph_arch_intel_pclmul = 0; int ceph_arch_intel_sse42 = 0; int ceph_arch_intel_sse41 = 0; int ceph_arch_intel_ssse3 = 0; int ceph_arch_intel_sse3 = 0; int ceph_arch_intel_sse2 = 0; #ifdef __x86_64__ /* Note: valgrind redefines cpuid : it is different from the native processor. */ /* intel cpu? */ static void do_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { int id = *eax; asm("movl %4, %%eax;" "cpuid;" "movl %%eax, %0;" "movl %%ebx, %1;" "movl %%ecx, %2;" "movl %%edx, %3;" : "=r" (*eax), "=r" (*ebx), "=r" (*ecx), "=r" (*edx) : "r" (id) : "eax", "ebx", "ecx", "edx"); } /* http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits */ #define CPUID_PCLMUL (1 << 1) #define CPUID_SSE42 (1 << 20) #define CPUID_SSE41 (1 << 19) #define CPUID_SSSE3 (1 << 9) #define CPUID_SSE3 (1) #define CPUID_SSE2 (1 << 26) int ceph_arch_intel_probe(void) { /* i know how to check this on x86_64... */ unsigned int eax = 1, ebx, ecx, edx; do_cpuid(&eax, &ebx, &ecx, &edx); if ((ecx & CPUID_PCLMUL) != 0) { ceph_arch_intel_pclmul = 1; } if ((ecx & CPUID_SSE42) != 0) { ceph_arch_intel_sse42 = 1; } if ((ecx & CPUID_SSE41) != 0) { ceph_arch_intel_sse41 = 1; } if ((ecx & CPUID_SSSE3) != 0) { ceph_arch_intel_ssse3 = 1; } if ((ecx & CPUID_SSE3) != 0) { ceph_arch_intel_sse3 = 1; } if ((edx & CPUID_SSE2) != 0) { ceph_arch_intel_sse2 = 1; } return 0; } #else // __x86_64__ int ceph_arch_intel_probe(void) { /* no features */ return 0; } #endif // __x86_64__ ceph-0.80.11/src/arch/probe.h0000664000175100017510000000035312623076744017662 0ustar jenkins-buildjenkins-build#ifndef CEPH_ARCH_PROBE_H #define CEPH_ARCH_PROBE_H #ifdef __cplusplus extern "C" { #endif extern int ceph_arch_probed; /* non-zero if we've probed features */ extern int ceph_arch_probe(void); #ifdef __cplusplus } #endif #endif ceph-0.80.11/src/arch/Makefile.am0000664000175100017510000000025112623076744020433 0ustar jenkins-buildjenkins-buildlibarch_la_SOURCES = \ arch/intel.c \ arch/neon.c \ arch/probe.cc noinst_LTLIBRARIES += libarch.la noinst_HEADERS += \ arch/intel.h \ arch/neon.h \ arch/probe.h ceph-0.80.11/src/arch/probe.cc0000664000175100017510000000063612623076744020024 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "arch/probe.h" #include "arch/intel.h" #include "arch/neon.h" int ceph_arch_probe(void) { if (ceph_arch_probed) return 1; ceph_arch_intel_probe(); ceph_arch_neon_probe(); ceph_arch_probed = 1; return 1; } // do this once using the magic of c++. int ceph_arch_probed = ceph_arch_probe(); ceph-0.80.11/src/msg/0000775000175100017510000000000012623077035016244 5ustar jenkins-buildjenkins-buildceph-0.80.11/src/msg/Messenger.cc0000664000175100017510000000075112623076744020514 0ustar jenkins-buildjenkins-build #include "include/types.h" #include "Messenger.h" #include "SimpleMessenger.h" Messenger *Messenger::create_client_messenger(CephContext *cct, string lname) { uint64_t nonce = 0; get_random_bytes((char*)&nonce, sizeof(nonce)); return Messenger::create(cct, entity_name_t::CLIENT(), lname, nonce); } Messenger *Messenger::create(CephContext *cct, entity_name_t name, string lname, uint64_t nonce) { return new SimpleMessenger(cct, name, lname, nonce); } ceph-0.80.11/src/msg/Messenger.h0000664000175100017510000005523712623076744020367 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MESSENGER_H #define CEPH_MESSENGER_H #include using namespace std; #include "Message.h" #include "Dispatcher.h" #include "common/Mutex.h" #include "common/Cond.h" #include "include/Context.h" #include "include/types.h" #include "include/ceph_features.h" #include "auth/Crypto.h" #include #include class MDS; class Timer; class Messenger { private: list dispatchers; protected: /// the "name" of the local daemon. eg client.99 entity_inst_t my_inst; int default_send_priority; /// set to true once the Messenger has started, and set to false on shutdown bool started; public: /** * The CephContext this Messenger uses. Many other components initialize themselves * from this value. */ CephContext *cct; /** * A Policy describes the rules of a Connection. Is there a limit on how * much data this Connection can have locally? When the underlying connection * experiences an error, does the Connection disappear? Can this Messenger * re-establish the underlying connection? */ struct Policy { /// If true, the Connection is tossed out on errors. bool lossy; /// If true, the underlying connection can't be re-established from this end. bool server; /// If true, we will standby when idle bool standby; /// If true, we will try to detect session resets bool resetcheck; /** * The throttler is used to limit how much data is held by Messages from * the associated Connection(s). When reading in a new Message, the Messenger * will call throttler->throttle() for the size of the new Message. */ Throttle *throttler_bytes; Throttle *throttler_messages; /// Specify features supported locally by the endpoint. uint64_t features_supported; /// Specify features any remotes must have to talk to this endpoint. uint64_t features_required; Policy() : lossy(false), server(false), standby(false), resetcheck(true), throttler_bytes(NULL), throttler_messages(NULL), features_supported(CEPH_FEATURES_SUPPORTED_DEFAULT), features_required(0) {} private: Policy(bool l, bool s, bool st, bool r, uint64_t sup, uint64_t req) : lossy(l), server(s), standby(st), resetcheck(r), throttler_bytes(NULL), throttler_messages(NULL), features_supported(sup | CEPH_FEATURES_SUPPORTED_DEFAULT), features_required(req) {} public: static Policy stateful_server(uint64_t sup, uint64_t req) { return Policy(false, true, true, true, sup, req); } static Policy stateless_server(uint64_t sup, uint64_t req) { return Policy(true, true, false, false, sup, req); } static Policy lossless_peer(uint64_t sup, uint64_t req) { return Policy(false, false, true, false, sup, req); } static Policy lossless_peer_reuse(uint64_t sup, uint64_t req) { return Policy(false, false, true, true, sup, req); } static Policy lossy_client(uint64_t sup, uint64_t req) { return Policy(true, false, false, false, sup, req); } static Policy lossless_client(uint64_t sup, uint64_t req) { return Policy(false, false, false, true, sup, req); } }; /** * Messenger constructor. Call this from your implementation. * Messenger users should construct full implementations directly, * or use the create() function. */ Messenger(CephContext *cct_, entity_name_t w) : my_inst(), default_send_priority(CEPH_MSG_PRIO_DEFAULT), started(false), cct(cct_) { my_inst.name = w; } virtual ~Messenger() {} /** * create a new messenger * * Create a new messenger instance, with whatever implementation is * available or specified via the configuration in cct. * * @param cct context * @param name entity name to register * @param lname logical name of the messenger in this process (e.g., "client") * @param nonce nonce value to uniquely identify this instance on the current host */ static Messenger *create(CephContext *cct, entity_name_t name, string lname, uint64_t nonce); /** * create a new messenger * * Create a new messenger instance. * Same as the above, but a slightly simpler interface for clients: * - Generate a random nonce * - use the default feature bits * - get the messenger type from cct * - use the client entity_type * * @param cct context * @param lname logical name of the messenger in this process (e.g., "client") */ static Messenger *create_client_messenger(CephContext *cct, string lname); /** * @defgroup Accessors * @{ */ /** * Retrieve the Messenger's instance. * * @return A const reference to the instance this Messenger * currently believes to be its own. */ const entity_inst_t& get_myinst() { return my_inst; } /** * set messenger's instance */ void set_myinst(entity_inst_t i) { my_inst = i; } /** * Retrieve the Messenger's address. * * @return A const reference to the address this Messenger * currently believes to be its own. */ const entity_addr_t& get_myaddr() { return my_inst.addr; } protected: /** * set messenger's address */ void set_myaddr(const entity_addr_t& a) { my_inst.addr = a; } public: /** * Retrieve the Messenger's name. * * @return A const reference to the name this Messenger * currently believes to be its own. */ const entity_name_t& get_myname() { return my_inst.name; } /** * Set the name of the local entity. The name is reported to others and * can be changed while the system is running, but doing so at incorrect * times may have bad results. * * @param m The name to set. */ void set_myname(const entity_name_t& m) { my_inst.name = m; } /** * Set the unknown address components for this Messenger. * This is useful if the Messenger doesn't know its full address just by * binding, but another Messenger on the same interface has already learned * its full address. This function does not fill in known address elements, * cause a rebind, or do anything of that sort. * * @param addr The address to use as a template. */ virtual void set_addr_unknowns(entity_addr_t &addr) = 0; /// Get the default send priority. int get_default_send_priority() { return default_send_priority; } /** * Get the number of Messages which the Messenger has received * but not yet dispatched. */ virtual int get_dispatch_queue_len() = 0; /** * Get age of oldest undelivered message * (0 if the queue is empty) */ virtual double get_dispatch_queue_max_age(utime_t now) = 0; /** * @} // Accessors */ /** * @defgroup Configuration * @{ */ /** * Set the cluster protocol in use by this daemon. * This is an init-time function and cannot be called after calling * start() or bind(). * * @param p The cluster protocol to use. Defined externally. */ virtual void set_cluster_protocol(int p) = 0; /** * Set a policy which is applied to all peers who do not have a type-specific * Policy. * This is an init-time function and cannot be called after calling * start() or bind(). * * @param p The Policy to apply. */ virtual void set_default_policy(Policy p) = 0; /** * Set a policy which is applied to all peers of the given type. * This is an init-time function and cannot be called after calling * start() or bind(). * * @param type The peer type this policy applies to. * @param p The policy to apply. */ virtual void set_policy(int type, Policy p) = 0; /** * Set the Policy associated with a type of peer. * * This can be called either on initial setup, or after connections * are already established. However, the policies for existing * connections will not be affected; the new policy will only apply * to future connections. * * @param t The peer type to get the default policy for. * @return A const Policy reference. */ virtual Policy get_policy(int t) = 0; /** * Get the default Policy * * @return A const Policy reference. */ virtual Policy get_default_policy() = 0; /** * Set a Throttler which is applied to all Messages from the given * type of peer. * * This is an init-time function and cannot be called after calling * start() or bind(). * * @param type The peer type this Throttler will apply to. * @param t The Throttler to apply. The Messenger does not take * ownership of this pointer, but you must not destroy it before * you destroy the Messenger. */ virtual void set_policy_throttlers(int type, Throttle *bytes, Throttle *msgs=NULL) = 0; /** * Set the default send priority * * This is an init-time function and must be called *before* calling * start(). * * @param p The cluster protocol to use. Defined externally. */ void set_default_send_priority(int p) { assert(!started); default_send_priority = p; } /** * Add a new Dispatcher to the front of the list. If you add * a Dispatcher which is already included, it will get a duplicate * entry. This will reduce efficiency but not break anything. * * @param d The Dispatcher to insert into the list. */ void add_dispatcher_head(Dispatcher *d) { bool first = dispatchers.empty(); dispatchers.push_front(d); if (first) ready(); } /** * Add a new Dispatcher to the end of the list. If you add * a Dispatcher which is already included, it will get a duplicate * entry. This will reduce efficiency but not break anything. * * @param d The Dispatcher to insert into the list. */ void add_dispatcher_tail(Dispatcher *d) { bool first = dispatchers.empty(); dispatchers.push_back(d); if (first) ready(); } /** * Bind the Messenger to a specific address. If bind_addr * is not completely filled in the system will use the * valid portions and cycle through the unset ones (eg, the port) * in an unspecified order. * * @param bind_addr The address to bind to. * @return 0 on success, or -1 on error, or -errno if * we can be more specific about the failure. */ virtual int bind(const entity_addr_t& bind_addr) = 0; /** * This function performs a full restart of the Messenger component, * whatever that means. Other entities who connect to this * Messenger post-rebind() should perceive it as a new entity which * they have not previously contacted, and it MUST bind to a * different address than it did previously. * * @param avoid_ports Additional port to avoid binding to. */ virtual int rebind(const set& avoid_ports) { return -EOPNOTSUPP; } /** * @} // Configuration */ /** * @defgroup Startup/Shutdown * @{ */ /** * Perform any resource allocation, thread startup, etc * that is required before attempting to connect to other * Messengers or transmit messages. * Once this function completes, started shall be set to true. * * @return 0 on success; -errno on failure. */ virtual int start() { started = true; return 0; } // shutdown /** * Block until the Messenger has finished shutting down (according * to the shutdown() function). * It is valid to call this after calling shutdown(), but it must * be called before deleting the Messenger. */ virtual void wait() = 0; /** * Initiate a shutdown of the Messenger. * * @return 0 on success, -errno otherwise. */ virtual int shutdown() { started = false; return 0; } /** * @} // Startup/Shutdown */ /** * @defgroup Messaging * @{ */ /** * Queue the given Message for the given entity. * Success in this function does not guarantee Message delivery, only * success in queueing the Message. Other guarantees may be provided based * on the Connection policy associated with the dest. * * @param m The Message to send. The Messenger consumes a single reference * when you pass it in. * @param dest The entity to send the Message to. * * DEPRECATED: please do not use this interface for any new code; * use the Connection* variant. * * @return 0 on success, or -errno on failure. */ virtual int send_message(Message *m, const entity_inst_t& dest) = 0; /** * Queue the given Message to send out on the given Connection. * Success in this function does not guarantee Message delivery, only * success in queueing the Message. Other guarantees may be provided based * on the Connection policy. * * @param m The Message to send. The Messenger consumes a single reference * when you pass it in. * @param con The Connection to send the Message out on. * * @return 0 on success, or -errno on failure. */ virtual int send_message(Message *m, Connection *con) = 0; int send_message(Message *m, const ConnectionRef& con) { return send_message(m, con.get()); } /** * Lazily queue the given Message for the given entity. Unlike with * send_message(), lazy_send_message() will not establish a * Connection if none exists, re-establish the connection if it * has broken, or queue the Message if the connection is broken. * * @param m The Message to send. The Messenger consumes a single reference * when you pass it in. * @param dest The entity to send the Message to. * * DEPRECATED: please do not use this interface for any new code; * use the Connection* variant. * * @return 0. */ virtual int lazy_send_message(Message *m, const entity_inst_t& dest) = 0; /** * Lazily queue the given Message for the given Connection. Unlike with * send_message(), lazy_send_message() does not necessarily re-establish * the connection if it has broken, or even queue the Message if the * connection is broken. * * @param m The Message to send. The Messenger consumes a single reference * when you pass it in. * @param dest The entity to send the Message to. * * @return 0. */ virtual int lazy_send_message(Message *m, Connection *con) = 0; /** * @} // Messaging */ /** * @defgroup Connection Management * @{ */ /** * Get the Connection object associated with a given entity. If a * Connection does not exist, create one and establish a logical connection. * The caller owns a reference when this returns. Call ->put() when you're * done! * * @param dest The entity to get a connection for. */ virtual ConnectionRef get_connection(const entity_inst_t& dest) = 0; /** * Get the Connection object associated with ourselves. */ virtual ConnectionRef get_loopback_connection() = 0; /** * Send a "keepalive" ping to the given dest, if it has a working Connection. * If the Messenger doesn't already have a Connection, or if the underlying * connection has broken, this function does nothing. * * @param dest The entity to send the keepalive to. * @return 0, or implementation-defined error numbers. */ virtual int send_keepalive(const entity_inst_t& dest) = 0; /** * Send a "keepalive" ping along the given Connection, if it's working. * If the underlying connection has broken, this function does nothing. * * @param dest The entity to send the keepalive to. * @return 0, or implementation-defined error numbers. */ virtual int send_keepalive(Connection *con) = 0; /** * Mark down a Connection to a remote. * * This will cause us to discard our outgoing queue for them, and if * reset detection is enabled in the policy and the endpoint tries * to reconnect they will discard their queue when we inform them of * the session reset. * * If there is no Connection to the given dest, it is a no-op. * * This generates a RESET notification to the Dispatcher. * * DEPRECATED: please do not use this interface for any new code; * use the Connection* variant. * * @param a The address to mark down. */ virtual void mark_down(const entity_addr_t& a) = 0; /** * Mark down the given Connection. * * This will cause us to discard its outgoing queue, and if reset * detection is enabled in the policy and the endpoint tries to * reconnect they will discard their queue when we inform them of * the session reset. * * If the Connection* is NULL, this is a no-op. * * It does not generate any notifications to the Dispatcher. * * @param con The Connection to mark down. */ virtual void mark_down(Connection *con) = 0; void mark_down(const ConnectionRef& con) { mark_down(con.get()); } /** * Mark all the existing Connections down. This is equivalent * to iterating over all Connections and calling mark_down() * on each. * * This will generate a RESET event for each closed connections. */ virtual void mark_down_all() = 0; /** * Unlike mark_down, this function will try and deliver * all messages before ending the connection, and it will use * the Pipe's existing semantics to do so. Once the Messages * all been sent out the Connection will be closed and * generate an ms_handle_reset notification to the * Dispatcher. * This function means that you will get standard delivery to endpoints, * and then the Connection will be cleaned up. * * @param con The Connection to mark down. */ virtual void mark_down_on_empty(Connection *con) = 0; /** * Mark a Connection as "disposable", setting it to lossy * (regardless of initial Policy). Unlike mark_down_on_empty() * this does not immediately close the Connection once * Messages have been delivered, so as long as there are no errors you can * continue to receive responses; but it will not attempt * to reconnect for message delivery or preserve your old * delivery semantics, either. * * TODO: There's some odd stuff going on in our SimpleMessenger * implementation during connect that looks unused; is there * more of a contract that that's enforcing? * * @param con The Connection to mark as disposable. */ virtual void mark_disposable(Connection *con) = 0; /** * @} // Connection Management */ protected: /** * @defgroup Subclass Interfacing * @{ */ /** * A courtesy function for Messenger implementations which * will be called when we receive our first Dispatcher. */ virtual void ready() { } /** * @} // Subclass Interfacing */ /** * @defgroup Dispatcher Interfacing * @{ */ public: /** * Deliver a single Message. Send it to each Dispatcher * in sequence until one of them handles it. * If none of our Dispatchers can handle it, assert(0). * * @param m The Message to deliver. We take ownership of * one reference to it. */ void ms_deliver_dispatch(Message *m) { m->set_dispatch_stamp(ceph_clock_now(cct)); for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) { if ((*p)->ms_dispatch(m)) return; } lsubdout(cct, ms, 0) << "ms_deliver_dispatch: unhandled message " << m << " " << *m << " from " << m->get_source_inst() << dendl; assert(!cct->_conf->ms_die_on_unhandled_msg); m->put(); } /** * Notify each Dispatcher of a new Connection. Call * this function whenever a new Connection is initiated. * * @param con Pointer to the new Connection. */ void ms_deliver_handle_connect(Connection *con) { for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) (*p)->ms_handle_connect(con); } /** * Notify each Dispatcher of a new incomming Connection. Call * this function whenever a new Connection is accepted. * * @param con Pointer to the new Connection. */ void ms_deliver_handle_accept(Connection *con) { for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) (*p)->ms_handle_accept(con); } /** * Notify each Dispatcher of a Connection which may have lost * Messages. Call this function whenever you detect that a lossy Connection * has been disconnected. * * @param con Pointer to the broken Connection. */ void ms_deliver_handle_reset(Connection *con) { for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) { if ((*p)->ms_handle_reset(con)) return; } } /** * Notify each Dispatcher of a Connection which has been "forgotten" about * by the remote end, implying that messages have probably been lost. * Call this function whenever you detect a reset. * * @param con Pointer to the broken Connection. */ void ms_deliver_handle_remote_reset(Connection *con) { for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) (*p)->ms_handle_remote_reset(con); } /** * Get the AuthAuthorizer for a new outgoing Connection. * * @param peer_type The peer type for the new Connection * @param force_new True if we want to wait for new keys, false otherwise. * @return A pointer to the AuthAuthorizer, if we have one; NULL otherwise */ AuthAuthorizer *ms_deliver_get_authorizer(int peer_type, bool force_new) { AuthAuthorizer *a = 0; for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) { if ((*p)->ms_get_authorizer(peer_type, &a, force_new)) return a; } return NULL; } /** * Verify that the authorizer on a new incoming Connection is correct. * * @param con The new incoming Connection * @param peer_type The type of the endpoint on the new Connection * @param protocol The ID of the protocol in use (at time of writing, cephx or none) * @param authorizer The authorization string supplied by the remote * @param authorizer_reply Output param: The string we should send back to * the remote to authorize ourselves. Only filled in if isvalid * @param isvalid Output param: True if authorizer is valid, false otherwise * * @return True if we were able to prove or disprove correctness of * authorizer, false otherwise. */ bool ms_deliver_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key) { for (list::iterator p = dispatchers.begin(); p != dispatchers.end(); ++p) { if ((*p)->ms_verify_authorizer(con, peer_type, protocol, authorizer, authorizer_reply, isvalid, session_key)) return true; } return false; } /** * @} // Dispatcher Interfacing */ }; #endif ceph-0.80.11/src/msg/Accepter.h0000664000175100017510000000206312623076744020152 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MSG_ACCEPTER_H #define CEPH_MSG_ACCEPTER_H #include "msg/msg_types.h" #include "common/Thread.h" class SimpleMessenger; /** * If the SimpleMessenger binds to a specific address, the Accepter runs * and listens for incoming connections. */ class Accepter : public Thread { SimpleMessenger *msgr; bool done; int listen_sd; uint64_t nonce; public: Accepter(SimpleMessenger *r, uint64_t n) : msgr(r), done(false), listen_sd(-1), nonce(n) {} void *entry(); void stop(); int bind(const entity_addr_t &bind_addr, const set& avoid_ports); int rebind(const set& avoid_port); int start(); }; #endif ceph-0.80.11/src/msg/SimpleMessenger.h0000664000175100017510000003211112623076744021523 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_SIMPLEMESSENGER_H #define CEPH_SIMPLEMESSENGER_H #include "include/types.h" #include "include/xlist.h" #include #include using namespace std; #include "include/unordered_map.h" #include "include/unordered_set.h" #include "common/Mutex.h" #include "include/atomic.h" #include "common/Cond.h" #include "common/Thread.h" #include "common/Throttle.h" #include "Messenger.h" #include "Message.h" #include "include/assert.h" #include "DispatchQueue.h" #include "Pipe.h" #include "Accepter.h" #include "include/Spinlock.h" /* * This class handles transmission and reception of messages. Generally * speaking, there are several major components: * * - Connection * Each logical session is associated with a Connection. * - Pipe * Each network connection is handled through a pipe, which handles * the input and output of each message. There is normally a 1:1 * relationship between Pipe and Connection, but logical sessions may * get handed off between Pipes when sockets reconnect or during * connection races. * - IncomingQueue * Incoming messages are associated with an IncomingQueue, and there * is one such queue associated with each Pipe. * - DispatchQueue * IncomingQueues get queued in the DIspatchQueue, which is responsible * for doing a round-robin sweep and processing them via a worker thread. * - SimpleMessenger * It's the exterior class passed to the external message handler and * most of the API details. * * Lock ordering: * * SimpleMessenger::lock * Pipe::pipe_lock * DispatchQueue::lock * IncomingQueue::lock */ class SimpleMessenger : public Messenger { // First we have the public Messenger interface implementation... public: /** * Initialize the SimpleMessenger! * * @param cct The CephContext to use * @param name The name to assign ourselves * _nonce A unique ID to use for this SimpleMessenger. It should not * be a value that will be repeated if the daemon restarts. */ SimpleMessenger(CephContext *cct, entity_name_t name, string mname, uint64_t _nonce); /** * Destroy the SimpleMessenger. Pretty simple since all the work is done * elsewhere. */ virtual ~SimpleMessenger(); /** @defgroup Accessors * @{ */ void set_addr_unknowns(entity_addr_t& addr); int get_dispatch_queue_len() { return dispatch_queue.get_queue_len(); } double get_dispatch_queue_max_age(utime_t now) { return dispatch_queue.get_max_age(now); } /** @} Accessors */ /** * @defgroup Configuration functions * @{ */ void set_cluster_protocol(int p) { assert(!started && !did_bind); cluster_protocol = p; } void set_default_policy(Policy p) { Mutex::Locker l(policy_lock); default_policy = p; } void set_policy(int type, Policy p) { Mutex::Locker l(policy_lock); policy_map[type] = p; } void set_policy_throttlers(int type, Throttle *byte_throttle, Throttle *msg_throttle) { Mutex::Locker l(policy_lock); if (policy_map.count(type)) { policy_map[type].throttler_bytes = byte_throttle; policy_map[type].throttler_messages = msg_throttle; } else { default_policy.throttler_bytes = byte_throttle; default_policy.throttler_messages = msg_throttle; } } int bind(const entity_addr_t& bind_addr); int rebind(const set& avoid_ports); /** @} Configuration functions */ /** * @defgroup Startup/Shutdown * @{ */ virtual int start(); virtual void wait(); virtual int shutdown(); /** @} // Startup/Shutdown */ /** * @defgroup Messaging * @{ */ virtual int send_message(Message *m, const entity_inst_t& dest) { return _send_message(m, dest, false); } virtual int send_message(Message *m, Connection *con) { return _send_message(m, con, false); } virtual int lazy_send_message(Message *m, const entity_inst_t& dest) { return _send_message(m, dest, true); } virtual int lazy_send_message(Message *m, Connection *con) { return _send_message(m, con, true); } /** @} // Messaging */ /** * @defgroup Connection Management * @{ */ virtual ConnectionRef get_connection(const entity_inst_t& dest); virtual ConnectionRef get_loopback_connection(); virtual int send_keepalive(const entity_inst_t& addr); virtual int send_keepalive(Connection *con); virtual void mark_down(const entity_addr_t& addr); virtual void mark_down(Connection *con); virtual void mark_down_on_empty(Connection *con); virtual void mark_disposable(Connection *con); virtual void mark_down_all(); /** @} // Connection Management */ protected: /** * @defgroup Messenger Interfaces * @{ */ /** * Start up the DispatchQueue thread once we have somebody to dispatch to. */ virtual void ready(); /** @} // Messenger Interfaces */ private: /** * @defgroup Inner classes * @{ */ public: Accepter accepter; DispatchQueue dispatch_queue; friend class Accepter; /** * Register a new pipe for accept * * @param sd socket */ Pipe *add_accept_pipe(int sd); private: /** * A thread used to tear down Pipes when they're complete. */ class ReaperThread : public Thread { SimpleMessenger *msgr; public: ReaperThread(SimpleMessenger *m) : msgr(m) {} void *entry() { msgr->reaper_entry(); return 0; } } reaper_thread; /** * @} // Inner classes */ /** * @defgroup Utility functions * @{ */ /** * Create a Pipe associated with the given entity (of the given type). * Initiate the connection. (This function returning does not guarantee * connection success.) * * @param addr The address of the entity to connect to. * @param type The peer type of the entity at the address. * @param con An existing Connection to associate with the new Pipe. If * NULL, it creates a new Connection. * @param msg an initial message to queue on the new pipe * * @return a pointer to the newly-created Pipe. Caller does not own a * reference; take one if you need it. */ Pipe *connect_rank(const entity_addr_t& addr, int type, Connection *con, Message *first); /** * Send a message, lazily or not. * This just glues [lazy_]send_message together and passes * the input on to submit_message. */ int _send_message(Message *m, const entity_inst_t& dest, bool lazy); /** * Same as above, but for the Connection-based variants. */ int _send_message(Message *m, Connection *con, bool lazy); /** * Queue up a Message for delivery to the entity specified * by addr and dest_type. * submit_message() is responsible for creating * new Pipes (and closing old ones) as necessary. * * @param m The Message to queue up. This function eats a reference. * @param con The existing Connection to use, or NULL if you don't know of one. * @param addr The address to send the Message to. * @param dest_type The peer type of the address we're sending to * @param lazy If true, do not establish or fix a Connection to send the Message; * just drop silently under failure. */ void submit_message(Message *m, Connection *con, const entity_addr_t& addr, int dest_type, bool lazy); /** * Look through the pipes in the pipe_reap_queue and tear them down. */ void reaper(); /** * @} // Utility functions */ // SimpleMessenger stuff /// the peer type of our endpoint int my_type; /// approximately unique ID set by the Constructor for use in entity_addr_t uint64_t nonce; /// overall lock used for SimpleMessenger data structures Mutex lock; /// true, specifying we haven't learned our addr; set false when we find it. // maybe this should be protected by the lock? bool need_addr; public: bool get_need_addr() const { return need_addr; } private: /** * false; set to true if the SimpleMessenger bound to a specific address; * and set false again by Accepter::stop(). This isn't lock-protected * since you shouldn't be able to race the only writers. */ bool did_bind; /// counter for the global seq our connection protocol uses __u32 global_seq; /// lock to protect the global_seq ceph_spinlock_t global_seq_lock; /** * hash map of addresses to Pipes * * NOTE: a Pipe* with state CLOSED may still be in the map but is considered * invalid and can be replaced by anyone holding the msgr lock */ ceph::unordered_map rank_pipe; /** * list of pipes are in teh process of accepting * * These are not yet in the rank_pipe map. */ set accepting_pipes; /// a set of all the Pipes we have which are somehow active set pipes; /// a list of Pipes we want to tear down list pipe_reap_queue; /// internal cluster protocol version, if any, for talking to entities of the same type. int cluster_protocol; /// lock protecting policy Mutex policy_lock; /// the default Policy we use for Pipes Policy default_policy; /// map specifying different Policies for specific peer types map policy_map; // entity_name_t::type -> Policy /// Throttle preventing us from building up a big backlog waiting for dispatch Throttle dispatch_throttler; bool reaper_started, reaper_stop; Cond reaper_cond; /// This Cond is slept on by wait() and signaled by dispatch_entry() Cond wait_cond; friend class Pipe; Pipe *_lookup_pipe(const entity_addr_t& k) { ceph::unordered_map::iterator p = rank_pipe.find(k); if (p == rank_pipe.end()) return NULL; // see lock cribbing in Pipe::fault() if (p->second->state_closed.read()) return NULL; return p->second; } public: int timeout; /// con used for sending messages to ourselves ConnectionRef local_connection; /** * @defgroup SimpleMessenger internals * @{ */ /** * This wraps ms_deliver_get_authorizer. We use it for Pipe. */ AuthAuthorizer *get_authorizer(int peer_type, bool force_new); /** * This wraps ms_deliver_verify_authorizer; we use it for Pipe. */ bool verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& auth, bufferlist& auth_reply, bool& isvalid,CryptoKey& session_key); /** * Increment the global sequence for this SimpleMessenger and return it. * This is for the connect protocol, although it doesn't hurt if somebody * else calls it. * * @return a global sequence ID that nobody else has seen. */ __u32 get_global_seq(__u32 old=0) { ceph_spin_lock(&global_seq_lock); if (old > global_seq) global_seq = old; __u32 ret = ++global_seq; ceph_spin_unlock(&global_seq_lock); return ret; } /** * Get the protocol version we support for the given peer type: either * a peer protocol (if it matches our own), the protocol version for the * peer (if we're connecting), or our protocol version (if we're accepting). */ int get_proto_version(int peer_type, bool connect); /** * Fill in the address and peer type for the local connection, which * is used for delivering messages back to ourself. */ void init_local_connection(); /** * Tell the SimpleMessenger its full IP address. * * This is used by Pipes when connecting to other endpoints, and * probably shouldn't be called by anybody else. */ void learned_addr(const entity_addr_t& peer_addr_for_me); /** * Tell the SimpleMessenger its address is no longer known * * This happens when we rebind to a new port. */ void unlearn_addr(); /** * Get the Policy associated with a type of peer. * @param t The peer type to get the default policy for. * * @return A const Policy reference. */ Policy get_policy(int t) { Mutex::Locker l(policy_lock); if (policy_map.count(t)) return policy_map[t]; else return default_policy; } Policy get_default_policy() { Mutex::Locker l(policy_lock); return default_policy; } /** * Release memory accounting back to the dispatch throttler. * * @param msize The amount of memory to release. */ void dispatch_throttle_release(uint64_t msize); /** * This function is used by the reaper thread. As long as nobody * has set reaper_stop, it calls the reaper function, then * waits to be signaled when it needs to reap again (or when it needs * to stop). */ void reaper_entry(); /** * Add a pipe to the pipe_reap_queue, to be torn down on * the next call to reaper(). * It should really only be the Pipe calling this, in our current * implementation. * * @param pipe A Pipe which has stopped its threads and is * ready to be torn down. */ void queue_reap(Pipe *pipe); /** * @} // SimpleMessenger Internals */ } ; #endif ceph-0.80.11/src/msg/Message.h0000664000175100017510000003621712623076744020020 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MESSAGE_H #define CEPH_MESSAGE_H #include #include #include // Because intusive_ptr clobbers our assert... #include "include/assert.h" #include "include/types.h" #include "include/buffer.h" #include "common/Throttle.h" #include "msg_types.h" #include "common/RefCountedObj.h" #include "common/debug.h" #include "common/config.h" // monitor internal #define MSG_MON_SCRUB 64 #define MSG_MON_ELECTION 65 #define MSG_MON_PAXOS 66 #define MSG_MON_PROBE 67 #define MSG_MON_JOIN 68 #define MSG_MON_SYNC 69 /* monitor <-> mon admin tool */ #define MSG_MON_COMMAND 50 #define MSG_MON_COMMAND_ACK 51 #define MSG_LOG 52 #define MSG_LOGACK 53 //#define MSG_MON_OBSERVE 54 //#define MSG_MON_OBSERVE_NOTIFY 55 #define MSG_CLASS 56 #define MSG_CLASS_ACK 57 #define MSG_GETPOOLSTATS 58 #define MSG_GETPOOLSTATSREPLY 59 #define MSG_MON_GLOBAL_ID 60 // #define MSG_POOLOP 49 // #define MSG_POOLOPREPLY 48 #define MSG_ROUTE 47 #define MSG_FORWARD 46 #define MSG_PAXOS 40 // osd internal #define MSG_OSD_PING 70 #define MSG_OSD_BOOT 71 #define MSG_OSD_FAILURE 72 #define MSG_OSD_ALIVE 73 #define MSG_OSD_MARK_ME_DOWN 74 #define MSG_OSD_SUBOP 76 #define MSG_OSD_SUBOPREPLY 77 #define MSG_OSD_PGTEMP 78 #define MSG_OSD_PG_NOTIFY 80 #define MSG_OSD_PG_QUERY 81 #define MSG_OSD_PG_SUMMARY 82 #define MSG_OSD_PG_LOG 83 #define MSG_OSD_PG_REMOVE 84 #define MSG_OSD_PG_INFO 85 #define MSG_OSD_PG_TRIM 86 #define MSG_PGSTATS 87 #define MSG_PGSTATSACK 88 #define MSG_OSD_PG_CREATE 89 #define MSG_REMOVE_SNAPS 90 #define MSG_OSD_SCRUB 91 #define MSG_OSD_PG_MISSING 92 #define MSG_OSD_REP_SCRUB 93 #define MSG_OSD_PG_SCAN 94 #define MSG_OSD_PG_BACKFILL 95 #define MSG_COMMAND 97 #define MSG_COMMAND_REPLY 98 #define MSG_OSD_BACKFILL_RESERVE 99 #define MSG_OSD_RECOVERY_RESERVE 150 #define MSG_OSD_PG_PUSH 105 #define MSG_OSD_PG_PULL 106 #define MSG_OSD_PG_PUSH_REPLY 107 #define MSG_OSD_EC_WRITE 108 #define MSG_OSD_EC_WRITE_REPLY 109 #define MSG_OSD_EC_READ 110 #define MSG_OSD_EC_READ_REPLY 111 // *** MDS *** #define MSG_MDS_BEACON 100 // to monitor #define MSG_MDS_SLAVE_REQUEST 101 #define MSG_MDS_TABLE_REQUEST 102 // 150 already in use (MSG_OSD_RECOVERY_RESERVE) #define MSG_MDS_RESOLVE 0x200 #define MSG_MDS_RESOLVEACK 0x201 #define MSG_MDS_CACHEREJOIN 0x202 #define MSG_MDS_DISCOVER 0x203 #define MSG_MDS_DISCOVERREPLY 0x204 #define MSG_MDS_INODEUPDATE 0x205 #define MSG_MDS_DIRUPDATE 0x206 #define MSG_MDS_CACHEEXPIRE 0x207 #define MSG_MDS_DENTRYUNLINK 0x208 #define MSG_MDS_FRAGMENTNOTIFY 0x209 #define MSG_MDS_OFFLOAD_TARGETS 0x20a #define MSG_MDS_DENTRYLINK 0x20c #define MSG_MDS_FINDINO 0x20d #define MSG_MDS_FINDINOREPLY 0x20e #define MSG_MDS_OPENINO 0x20f #define MSG_MDS_OPENINOREPLY 0x210 #define MSG_MDS_LOCK 0x300 #define MSG_MDS_INODEFILECAPS 0x301 #define MSG_MDS_EXPORTDIRDISCOVER 0x449 #define MSG_MDS_EXPORTDIRDISCOVERACK 0x450 #define MSG_MDS_EXPORTDIRCANCEL 0x451 #define MSG_MDS_EXPORTDIRPREP 0x452 #define MSG_MDS_EXPORTDIRPREPACK 0x453 #define MSG_MDS_EXPORTDIRWARNING 0x454 #define MSG_MDS_EXPORTDIRWARNINGACK 0x455 #define MSG_MDS_EXPORTDIR 0x456 #define MSG_MDS_EXPORTDIRACK 0x457 #define MSG_MDS_EXPORTDIRNOTIFY 0x458 #define MSG_MDS_EXPORTDIRNOTIFYACK 0x459 #define MSG_MDS_EXPORTDIRFINISH 0x460 #define MSG_MDS_EXPORTCAPS 0x470 #define MSG_MDS_EXPORTCAPSACK 0x471 #define MSG_MDS_HEARTBEAT 0x500 // for mds load balancer // *** generic *** #define MSG_TIMECHECK 0x600 #define MSG_MON_HEALTH 0x601 // ====================================================== // abstract Connection, for keeping per-connection state class Messenger; struct Connection : private RefCountedObject { Mutex lock; Messenger *msgr; RefCountedObject *priv; int peer_type; entity_addr_t peer_addr; utime_t last_keepalive_ack; private: uint64_t features; public: RefCountedObject *pipe; bool failed; /// true if we are a lossy connection that has failed. int rx_buffers_version; map > rx_buffers; friend class boost::intrusive_ptr; public: Connection(Messenger *m) : lock("Connection::lock"), msgr(m), priv(NULL), peer_type(-1), features(0), pipe(NULL), failed(false), rx_buffers_version(0) { // we are managed exlusively by ConnectionRef; make it so you can // ConnectionRef foo = new Connection; nref.set(0); } ~Connection() { //generic_dout(0) << "~Connection " << this << dendl; if (priv) { //generic_dout(0) << "~Connection " << this << " dropping priv " << priv << dendl; priv->put(); } if (pipe) pipe->put(); } void set_priv(RefCountedObject *o) { Mutex::Locker l(lock); if (priv) priv->put(); priv = o; } RefCountedObject *get_priv() { Mutex::Locker l(lock); if (priv) return priv->get(); return NULL; } RefCountedObject *get_pipe() { Mutex::Locker l(lock); if (pipe) return pipe->get(); return NULL; } bool try_get_pipe(RefCountedObject **p) { Mutex::Locker l(lock); if (failed) { *p = NULL; } else { if (pipe) *p = pipe->get(); else *p = NULL; } return !failed; } bool clear_pipe(RefCountedObject *old_p) { if (old_p == pipe) { Mutex::Locker l(lock); pipe->put(); pipe = NULL; failed = true; return true; } return false; } void reset_pipe(RefCountedObject *p) { Mutex::Locker l(lock); if (pipe) pipe->put(); pipe = p->get(); } bool is_connected() { Mutex::Locker l(lock); return pipe != NULL; } Messenger *get_messenger() { return msgr; } int get_peer_type() { return peer_type; } void set_peer_type(int t) { peer_type = t; } bool peer_is_mon() { return peer_type == CEPH_ENTITY_TYPE_MON; } bool peer_is_mds() { return peer_type == CEPH_ENTITY_TYPE_MDS; } bool peer_is_osd() { return peer_type == CEPH_ENTITY_TYPE_OSD; } bool peer_is_client() { return peer_type == CEPH_ENTITY_TYPE_CLIENT; } const entity_addr_t& get_peer_addr() { return peer_addr; } void set_peer_addr(const entity_addr_t& a) { peer_addr = a; } uint64_t get_features() const { return features; } bool has_feature(uint64_t f) const { return features & f; } void set_features(uint64_t f) { features = f; } void set_feature(uint64_t f) { features |= f; } void post_rx_buffer(ceph_tid_t tid, bufferlist& bl) { Mutex::Locker l(lock); ++rx_buffers_version; rx_buffers[tid] = pair(bl, rx_buffers_version); } void revoke_rx_buffer(ceph_tid_t tid) { Mutex::Locker l(lock); rx_buffers.erase(tid); } utime_t get_last_keepalive_ack() const { return last_keepalive_ack; } }; typedef boost::intrusive_ptr ConnectionRef; // abstract Message class class Message : public RefCountedObject { protected: ceph_msg_header header; // headerelope ceph_msg_footer footer; bufferlist payload; // "front" unaligned blob bufferlist middle; // "middle" unaligned blob bufferlist data; // data payload (page-alignment will be preserved where possible) /* recv_stamp is set when the Messenger starts reading the * Message off the wire */ utime_t recv_stamp; /* dispatch_stamp is set when the Messenger starts calling dispatch() on * its endpoints */ utime_t dispatch_stamp; /* throttle_stamp is the point at which we got throttle */ utime_t throttle_stamp; /* time at which message was fully read */ utime_t recv_complete_stamp; ConnectionRef connection; // release our size in bytes back to this throttler when our payload // is adjusted or when we are destroyed. Throttle *byte_throttler; // release a count back to this throttler when we are destroyed Throttle *msg_throttler; // keep track of how big this message was when we reserved space in // the msgr dispatch_throttler, so that we can properly release it // later. this is necessary because messages can enter the dispatch // queue locally (not via read_message()), and those are not // currently throttled. uint64_t dispatch_throttle_size; friend class Messenger; public: Message() : connection(NULL), byte_throttler(NULL), msg_throttler(NULL), dispatch_throttle_size(0) { memset(&header, 0, sizeof(header)); memset(&footer, 0, sizeof(footer)); }; Message(int t, int version=1, int compat_version=0) : connection(NULL), byte_throttler(NULL), msg_throttler(NULL), dispatch_throttle_size(0) { memset(&header, 0, sizeof(header)); header.type = t; header.version = version; header.compat_version = compat_version; header.priority = 0; // undef header.data_off = 0; memset(&footer, 0, sizeof(footer)); } Message *get() { return static_cast(RefCountedObject::get()); } protected: virtual ~Message() { assert(nref.read() == 0); if (byte_throttler) byte_throttler->put(payload.length() + middle.length() + data.length()); if (msg_throttler) msg_throttler->put(); } public: const ConnectionRef& get_connection() { return connection; } void set_connection(const ConnectionRef& c) { connection = c; } void set_byte_throttler(Throttle *t) { byte_throttler = t; } Throttle *get_byte_throttler() { return byte_throttler; } void set_message_throttler(Throttle *t) { msg_throttler = t; } Throttle *get_message_throttler() { return msg_throttler; } void set_dispatch_throttle_size(uint64_t s) { dispatch_throttle_size = s; } uint64_t get_dispatch_throttle_size() { return dispatch_throttle_size; } ceph_msg_header &get_header() { return header; } void set_header(const ceph_msg_header &e) { header = e; } void set_footer(const ceph_msg_footer &e) { footer = e; } ceph_msg_footer &get_footer() { return footer; } /* * If you use get_[data, middle, payload] you shouldn't * use it to change those bufferlists unless you KNOW * there is no throttle being used. The other * functions are throttling-aware as appropriate. */ void clear_payload() { if (byte_throttler) byte_throttler->put(payload.length() + middle.length()); payload.clear(); middle.clear(); } virtual void clear_buffers() {} void clear_data() { if (byte_throttler) byte_throttler->put(data.length()); data.clear(); clear_buffers(); // let subclass drop buffers as well } bool empty_payload() { return payload.length() == 0; } bufferlist& get_payload() { return payload; } void set_payload(bufferlist& bl) { if (byte_throttler) byte_throttler->put(payload.length()); payload.claim(bl); if (byte_throttler) byte_throttler->take(payload.length()); } void set_middle(bufferlist& bl) { if (byte_throttler) byte_throttler->put(payload.length()); middle.claim(bl); if (byte_throttler) byte_throttler->take(payload.length()); } bufferlist& get_middle() { return middle; } void set_data(const bufferlist &d) { if (byte_throttler) byte_throttler->put(data.length()); data = d; if (byte_throttler) byte_throttler->take(data.length()); } bufferlist& get_data() { return data; } void claim_data(bufferlist& bl) { if (byte_throttler) byte_throttler->put(data.length()); bl.claim(data); } off_t get_data_len() { return data.length(); } void set_recv_stamp(utime_t t) { recv_stamp = t; } const utime_t& get_recv_stamp() const { return recv_stamp; } void set_dispatch_stamp(utime_t t) { dispatch_stamp = t; } const utime_t& get_dispatch_stamp() const { return dispatch_stamp; } void set_throttle_stamp(utime_t t) { throttle_stamp = t; } const utime_t& get_throttle_stamp() const { return throttle_stamp; } void set_recv_complete_stamp(utime_t t) { recv_complete_stamp = t; } const utime_t& get_recv_complete_stamp() const { return recv_complete_stamp; } void calc_header_crc() { header.crc = ceph_crc32c(0, (unsigned char*)&header, sizeof(header) - sizeof(header.crc)); } void calc_front_crc() { footer.front_crc = payload.crc32c(0); footer.middle_crc = middle.crc32c(0); } void calc_data_crc() { footer.data_crc = data.crc32c(0); } virtual int get_cost() const { return data.length(); } // type int get_type() const { return header.type; } void set_type(int t) { header.type = t; } uint64_t get_tid() const { return header.tid; } void set_tid(uint64_t t) { header.tid = t; } unsigned get_seq() const { return header.seq; } void set_seq(unsigned s) { header.seq = s; } unsigned get_priority() const { return header.priority; } void set_priority(__s16 p) { header.priority = p; } // source/dest entity_inst_t get_source_inst() const { return entity_inst_t(get_source(), get_source_addr()); } entity_name_t get_source() const { return entity_name_t(header.src); } entity_addr_t get_source_addr() const { if (connection) return connection->get_peer_addr(); return entity_addr_t(); } // forwarded? entity_inst_t get_orig_source_inst() const { return get_source_inst(); } entity_name_t get_orig_source() const { return get_orig_source_inst().name; } entity_addr_t get_orig_source_addr() const { return get_orig_source_inst().addr; } // virtual bits virtual void decode_payload() = 0; virtual void encode_payload(uint64_t features) = 0; virtual const char *get_type_name() const = 0; virtual void print(ostream& out) const { out << get_type_name(); } virtual void dump(Formatter *f) const; void encode(uint64_t features, bool datacrc); }; typedef boost::intrusive_ptr MessageRef; extern Message *decode_message(CephContext *cct, ceph_msg_header &header, ceph_msg_footer& footer, bufferlist& front, bufferlist& middle, bufferlist& data); inline ostream& operator<<(ostream& out, Message& m) { m.print(out); if (m.get_header().version) out << " v" << m.get_header().version; return out; } extern void encode_message(Message *m, uint64_t features, bufferlist& bl); extern Message *decode_message(CephContext *cct, bufferlist::iterator& bl); #endif ceph-0.80.11/src/msg/msg_types.cc0000664000175100017510000000667512623076744020611 0ustar jenkins-buildjenkins-build #include "msg_types.h" #include #include #include #include #include "common/Formatter.h" void entity_name_t::dump(Formatter *f) const { f->dump_string("type", type_str()); f->dump_unsigned("num", num()); } void entity_addr_t::dump(Formatter *f) const { f->dump_unsigned("nonce", nonce); f->dump_stream("addr") << addr; } void entity_name_t::generate_test_instances(list& o) { o.push_back(new entity_name_t(entity_name_t::MON())); o.push_back(new entity_name_t(entity_name_t::MON(1))); o.push_back(new entity_name_t(entity_name_t::OSD(1))); o.push_back(new entity_name_t(entity_name_t::CLIENT(1))); } void entity_addr_t::generate_test_instances(list& o) { o.push_back(new entity_addr_t()); entity_addr_t *a = new entity_addr_t(); a->set_nonce(1); o.push_back(a); entity_addr_t *b = new entity_addr_t(); b->set_nonce(5); b->set_family(AF_INET); b->set_in4_quad(0, 127); b->set_in4_quad(1, 0); b->set_in4_quad(2, 1); b->set_in4_quad(3, 2); b->set_port(2); o.push_back(b); } bool entity_addr_t::parse(const char *s, const char **end) { memset(this, 0, sizeof(*this)); const char *start = s; bool brackets = false; if (*start == '[') { start++; brackets = true; } // inet_pton() requires a null terminated input, so let's fill two // buffers, one with ipv4 allowed characters, and one with ipv6, and // then see which parses. char buf4[39]; char *o = buf4; const char *p = start; while (o < buf4 + sizeof(buf4) && *p && ((*p == '.') || (*p >= '0' && *p <= '9'))) { *o++ = *p++; } *o = 0; char buf6[64]; // actually 39 + null is sufficient. o = buf6; p = start; while (o < buf6 + sizeof(buf6) && *p && ((*p == ':') || (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) { *o++ = *p++; } *o = 0; //cout << "buf4 is '" << buf4 << "', buf6 is '" << buf6 << "'" << std::endl; // ipv4? struct in_addr a4; struct in6_addr a6; if (inet_pton(AF_INET, buf4, &a4)) { addr4.sin_addr.s_addr = a4.s_addr; addr.ss_family = AF_INET; p = start + strlen(buf4); } else if (inet_pton(AF_INET6, buf6, &a6)) { addr.ss_family = AF_INET6; memcpy(&addr6.sin6_addr, &a6, sizeof(a6)); p = start + strlen(buf6); } else { return false; } if (brackets) { if (*p != ']') return false; p++; } //cout << "p is " << *p << std::endl; if (*p == ':') { // parse a port, too! p++; int port = atoi(p); set_port(port); while (*p && *p >= '0' && *p <= '9') p++; } if (*p == '/') { // parse nonce, too p++; int non = atoi(p); set_nonce(non); while (*p && *p >= '0' && *p <= '9') p++; } if (end) *end = p; //cout << *this << std::endl; return true; } ostream& operator<<(ostream& out, const sockaddr_storage &ss) { char buf[NI_MAXHOST] = { 0 }; char serv[NI_MAXSERV] = { 0 }; size_t hostlen; if (ss.ss_family == AF_INET) hostlen = sizeof(struct sockaddr_in); else if (ss.ss_family == AF_INET6) hostlen = sizeof(struct sockaddr_in6); else hostlen = sizeof(struct sockaddr_storage); getnameinfo((struct sockaddr *)&ss, hostlen, buf, sizeof(buf), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); if (ss.ss_family == AF_INET6) return out << '[' << buf << "]:" << serv; return out //<< ss.ss_family << ":" << buf << ':' << serv; } ceph-0.80.11/src/msg/DispatchQueue.cc0000664000175100017510000001102712623076744021326 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include "msg/Message.h" #include "DispatchQueue.h" #include "SimpleMessenger.h" #include "common/ceph_context.h" #define dout_subsys ceph_subsys_ms #include "common/debug.h" /******************* * DispatchQueue */ #undef dout_prefix #define dout_prefix *_dout << "-- " << msgr->get_myaddr() << " " double DispatchQueue::get_max_age(utime_t now) { Mutex::Locker l(lock); if (marrival.empty()) return 0; else return (now - marrival.begin()->first); } void DispatchQueue::enqueue(Message *m, int priority, uint64_t id) { Mutex::Locker l(lock); ldout(cct,20) << "queue " << m << " prio " << priority << dendl; add_arrival(m); if (priority >= CEPH_MSG_PRIO_LOW) { mqueue.enqueue_strict( id, priority, QueueItem(m)); } else { mqueue.enqueue( id, priority, m->get_cost(), QueueItem(m)); } cond.Signal(); } void DispatchQueue::local_delivery(Message *m, int priority) { Mutex::Locker l(lock); m->set_connection(msgr->local_connection.get()); m->set_recv_stamp(ceph_clock_now(msgr->cct)); add_arrival(m); if (priority >= CEPH_MSG_PRIO_LOW) { mqueue.enqueue_strict( 0, priority, QueueItem(m)); } else { mqueue.enqueue( 0, priority, m->get_cost(), QueueItem(m)); } cond.Signal(); } /* * This function delivers incoming messages to the Messenger. * Pipes with messages are kept in queues; when beginning a message * delivery the highest-priority queue is selected, the pipe from the * front of the queue is removed, and its message read. If the pipe * has remaining messages at that priority level, it is re-placed on to the * end of the queue. If the queue is empty; it's removed. * The message is then delivered and the process starts again. */ void DispatchQueue::entry() { lock.Lock(); while (true) { while (!mqueue.empty()) { QueueItem qitem = mqueue.dequeue(); if (!qitem.is_code()) remove_arrival(qitem.get_message()); lock.Unlock(); if (qitem.is_code()) { switch (qitem.get_code()) { case D_BAD_REMOTE_RESET: msgr->ms_deliver_handle_remote_reset(qitem.get_connection()); break; case D_CONNECT: msgr->ms_deliver_handle_connect(qitem.get_connection()); break; case D_ACCEPT: msgr->ms_deliver_handle_accept(qitem.get_connection()); break; case D_BAD_RESET: msgr->ms_deliver_handle_reset(qitem.get_connection()); break; default: assert(0); } } else { Message *m = qitem.get_message(); if (stop) { ldout(cct,10) << " stop flag set, discarding " << m << " " << *m << dendl; m->put(); } else { uint64_t msize = m->get_dispatch_throttle_size(); m->set_dispatch_throttle_size(0); // clear it out, in case we requeue this message. ldout(cct,1) << "<== " << m->get_source_inst() << " " << m->get_seq() << " ==== " << *m << " ==== " << m->get_payload().length() << "+" << m->get_middle().length() << "+" << m->get_data().length() << " (" << m->get_footer().front_crc << " " << m->get_footer().middle_crc << " " << m->get_footer().data_crc << ")" << " " << m << " con " << m->get_connection() << dendl; msgr->ms_deliver_dispatch(m); msgr->dispatch_throttle_release(msize); ldout(cct,20) << "done calling dispatch on " << m << dendl; } } lock.Lock(); } if (stop) break; // wait for something to be put on queue cond.Wait(lock); } lock.Unlock(); } void DispatchQueue::discard_queue(uint64_t id) { Mutex::Locker l(lock); list removed; mqueue.remove_by_class(id, &removed); for (list::iterator i = removed.begin(); i != removed.end(); ++i) { assert(!(i->is_code())); // We don't discard id 0, ever! Message *m = i->get_message(); remove_arrival(m); msgr->dispatch_throttle_release(m->get_dispatch_throttle_size()); m->put(); } } void DispatchQueue::start() { assert(!stop); assert(!dispatch_thread.is_started()); dispatch_thread.create(); } void DispatchQueue::wait() { dispatch_thread.join(); } void DispatchQueue::shutdown() { // stop my dispatch thread lock.Lock(); stop = true; cond.Signal(); lock.Unlock(); } ceph-0.80.11/src/msg/Accepter.cc0000664000175100017510000001510312623076744020307 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "Accepter.h" #include "SimpleMessenger.h" #include "Message.h" #include "Pipe.h" #include "common/debug.h" #include "common/errno.h" #define dout_subsys ceph_subsys_ms #undef dout_prefix #define dout_prefix *_dout << "accepter." /******************************************** * Accepter */ int Accepter::bind(const entity_addr_t &bind_addr, const set& avoid_ports) { const md_config_t *conf = msgr->cct->_conf; // bind to a socket ldout(msgr->cct,10) << "accepter.bind" << dendl; int family; switch (bind_addr.get_family()) { case AF_INET: case AF_INET6: family = bind_addr.get_family(); break; default: // bind_addr is empty family = conf->ms_bind_ipv6 ? AF_INET6 : AF_INET; } /* socket creation */ listen_sd = ::socket(family, SOCK_STREAM, 0); if (listen_sd < 0) { lderr(msgr->cct) << "accepter.bind unable to create socket: " << cpp_strerror(errno) << dendl; return -errno; } // use whatever user specified (if anything) entity_addr_t listen_addr = bind_addr; listen_addr.set_family(family); /* bind to port */ int rc = -1; if (listen_addr.get_port()) { // specific port // reuse addr+port when possible int on = 1; rc = ::setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (rc < 0) { lderr(msgr->cct) << "accepter.bind unable to setsockopt: " << cpp_strerror(errno) << dendl; return -errno; } rc = ::bind(listen_sd, (struct sockaddr *) &listen_addr.ss_addr(), listen_addr.addr_size()); if (rc < 0) { lderr(msgr->cct) << "accepter.bind unable to bind to " << listen_addr.ss_addr() << ": " << cpp_strerror(errno) << dendl; return -errno; } } else { // try a range of ports for (int port = msgr->cct->_conf->ms_bind_port_min; port <= msgr->cct->_conf->ms_bind_port_max; port++) { if (avoid_ports.count(port)) continue; listen_addr.set_port(port); rc = ::bind(listen_sd, (struct sockaddr *) &listen_addr.ss_addr(), listen_addr.addr_size()); if (rc == 0) break; } if (rc < 0) { lderr(msgr->cct) << "accepter.bind unable to bind to " << listen_addr.ss_addr() << " on any port in range " << msgr->cct->_conf->ms_bind_port_min << "-" << msgr->cct->_conf->ms_bind_port_max << ": " << cpp_strerror(errno) << dendl; return -errno; } ldout(msgr->cct,10) << "accepter.bind bound on random port " << listen_addr << dendl; } // what port did we get? socklen_t llen = sizeof(listen_addr.ss_addr()); rc = getsockname(listen_sd, (sockaddr*)&listen_addr.ss_addr(), &llen); if (rc < 0) { rc = -errno; lderr(msgr->cct) << "accepter.bind failed getsockname: " << cpp_strerror(rc) << dendl; return rc; } ldout(msgr->cct,10) << "accepter.bind bound to " << listen_addr << dendl; // listen! rc = ::listen(listen_sd, 128); if (rc < 0) { rc = -errno; lderr(msgr->cct) << "accepter.bind unable to listen on " << listen_addr << ": " << cpp_strerror(rc) << dendl; return rc; } msgr->set_myaddr(bind_addr); if (bind_addr != entity_addr_t()) msgr->learned_addr(bind_addr); else assert(msgr->get_need_addr()); // should still be true. if (msgr->get_myaddr().get_port() == 0) { msgr->set_myaddr(listen_addr); } entity_addr_t addr = msgr->get_myaddr(); addr.nonce = nonce; msgr->set_myaddr(addr); msgr->init_local_connection(); ldout(msgr->cct,1) << "accepter.bind my_inst.addr is " << msgr->get_myaddr() << " need_addr=" << msgr->get_need_addr() << dendl; return 0; } int Accepter::rebind(const set& avoid_ports) { ldout(msgr->cct,1) << "accepter.rebind avoid " << avoid_ports << dendl; // invalidate our previously learned address. msgr->unlearn_addr(); entity_addr_t addr = msgr->get_myaddr(); set new_avoid = avoid_ports; new_avoid.insert(addr.get_port()); addr.set_port(0); // adjust the nonce; we want our entity_addr_t to be truly unique. nonce += 1000000; msgr->my_inst.addr.nonce = nonce; ldout(msgr->cct,10) << " new nonce " << nonce << " and inst " << msgr->my_inst << dendl; ldout(msgr->cct,10) << " will try " << addr << " and avoid ports " << new_avoid << dendl; int r = bind(addr, new_avoid); if (r == 0) start(); return r; } int Accepter::start() { ldout(msgr->cct,1) << "accepter.start" << dendl; // start thread create(); return 0; } void *Accepter::entry() { ldout(msgr->cct,10) << "accepter starting" << dendl; int errors = 0; struct pollfd pfd; pfd.fd = listen_sd; pfd.events = POLLIN | POLLERR | POLLNVAL | POLLHUP; while (!done) { ldout(msgr->cct,20) << "accepter calling poll" << dendl; int r = poll(&pfd, 1, -1); if (r < 0) break; ldout(msgr->cct,20) << "accepter poll got " << r << dendl; if (pfd.revents & (POLLERR | POLLNVAL | POLLHUP)) break; ldout(msgr->cct,10) << "pfd.revents=" << pfd.revents << dendl; if (done) break; // accept entity_addr_t addr; socklen_t slen = sizeof(addr.ss_addr()); int sd = ::accept(listen_sd, (sockaddr*)&addr.ss_addr(), &slen); if (sd >= 0) { errors = 0; ldout(msgr->cct,10) << "accepted incoming on sd " << sd << dendl; msgr->add_accept_pipe(sd); } else { ldout(msgr->cct,0) << "accepter no incoming connection? sd = " << sd << " errno " << errno << " " << cpp_strerror(errno) << dendl; if (++errors > 4) break; } } ldout(msgr->cct,20) << "accepter closing" << dendl; // don't close socket, in case we start up again? blech. if (listen_sd >= 0) { ::close(listen_sd); listen_sd = -1; } ldout(msgr->cct,10) << "accepter stopping" << dendl; return 0; } void Accepter::stop() { done = true; ldout(msgr->cct,10) << "stop accepter" << dendl; if (listen_sd >= 0) { ::shutdown(listen_sd, SHUT_RDWR); } // wait for thread to stop before closing the socket, to avoid // racing against fd re-use. if (is_started()) { join(); } if (listen_sd >= 0) { ::close(listen_sd); listen_sd = -1; } done = false; } ceph-0.80.11/src/msg/Pipe.h0000664000175100017510000002213712623076744017325 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MSGR_PIPE_H #define CEPH_MSGR_PIPE_H #include "include/memory.h" #include "msg_types.h" #include "Messenger.h" #include "auth/AuthSessionHandler.h" class SimpleMessenger; class IncomingQueue; class DispatchQueue; /** * The Pipe is the most complex SimpleMessenger component. It gets * two threads, one each for reading and writing on a socket it's handed * at creation time, and is responsible for everything that happens on * that socket. Besides message transmission, it's responsible for * propagating socket errors to the SimpleMessenger and then sticking * around in a state where it can provide enough data for the SimpleMessenger * to provide reliable Message delivery when it manages to reconnect. */ class Pipe : public RefCountedObject { /** * The Reader thread handles all reads off the socket -- not just * Messages, but also acks and other protocol bits (excepting startup, * when the Writer does a couple of reads). * All the work is implemented in Pipe itself, of course. */ class Reader : public Thread { Pipe *pipe; public: Reader(Pipe *p) : pipe(p) {} void *entry() { pipe->reader(); return 0; } } reader_thread; friend class Reader; /** * The Writer thread handles all writes to the socket (after startup). * All the work is implemented in Pipe itself, of course. */ class Writer : public Thread { Pipe *pipe; public: Writer(Pipe *p) : pipe(p) {} void *entry() { pipe->writer(); return 0; } } writer_thread; friend class Writer; /** * The DelayedDelivery is for injecting delays into Message delivery off * the socket. It is only enabled if delays are requested, and if they * are then it pulls Messages off the DelayQueue and puts them into the * in_q (SimpleMessenger::dispatch_queue). * Please note that this probably has issues with Pipe shutdown and * replacement semantics. I've tried, but no guarantees. */ class DelayedDelivery: public Thread { Pipe *pipe; std::deque< pair > delay_queue; Mutex delay_lock; Cond delay_cond; bool stop_delayed_delivery; public: DelayedDelivery(Pipe *p) : pipe(p), delay_lock("Pipe::DelayedDelivery::delay_lock"), stop_delayed_delivery(false) { } ~DelayedDelivery() { discard(); } void *entry(); void queue(utime_t release, Message *m) { Mutex::Locker l(delay_lock); delay_queue.push_back(make_pair(release, m)); delay_cond.Signal(); } void discard(); void flush(); void stop() { delay_lock.Lock(); stop_delayed_delivery = true; delay_cond.Signal(); delay_lock.Unlock(); } } *delay_thread; friend class DelayedDelivery; public: Pipe(SimpleMessenger *r, int st, Connection *con); ~Pipe(); SimpleMessenger *msgr; uint64_t conn_id; ostream& _pipe_prefix(std::ostream *_dout); enum { STATE_ACCEPTING, STATE_CONNECTING, STATE_OPEN, STATE_STANDBY, STATE_CLOSED, STATE_CLOSING, STATE_WAIT // just wait for racing connection }; static const char *get_state_name(int s) { switch (s) { case STATE_ACCEPTING: return "accepting"; case STATE_CONNECTING: return "connecting"; case STATE_OPEN: return "open"; case STATE_STANDBY: return "standby"; case STATE_CLOSED: return "closed"; case STATE_CLOSING: return "closing"; case STATE_WAIT: return "wait"; default: return "UNKNOWN"; } } const char *get_state_name() { return get_state_name(state); } int sd; int port; int peer_type; entity_addr_t peer_addr; Messenger::Policy policy; Mutex pipe_lock; int state; atomic_t state_closed; // non-zero iff state = STATE_CLOSED // session_security handles any signatures or encryptions required for this pipe's msgs. PLR ceph::shared_ptr session_security; protected: friend class SimpleMessenger; ConnectionRef connection_state; utime_t backoff; // backoff time bool reader_running, reader_needs_join; bool writer_running; map > out_q; // priority queue for outbound msgs DispatchQueue *in_q; list sent; Cond cond; bool send_keepalive; bool send_keepalive_ack; utime_t keepalive_ack_stamp; bool halt_delivery; //if a pipe's queue is destroyed, stop adding to it bool close_on_empty; __u32 connect_seq, peer_global_seq; uint64_t out_seq; uint64_t in_seq, in_seq_acked; void set_socket_options(); int accept(); // server handshake int connect(); // client handshake void reader(); void writer(); void unlock_maybe_reap(); int randomize_out_seq(); int read_message(Message **pm, AuthSessionHandler *session_security_copy); int write_message(ceph_msg_header& h, ceph_msg_footer& f, bufferlist& body); /** * Write the given data (of length len) to the Pipe's socket. This function * will loop until all passed data has been written out. * If more is set, the function will optimize socket writes * for additional data (by passing the MSG_MORE flag, aka TCP_CORK). * * @param msg The msghdr to write out * @param len The length of the data in msg * @param more Should be set true if this is one part of a larger message * @return 0, or -1 on failure (unrecoverable -- close the socket). */ int do_sendmsg(struct msghdr *msg, int len, bool more=false); int write_ack(uint64_t s); int write_keepalive(); int write_keepalive2(char tag, const utime_t &t); void fault(bool reader=false); void was_session_reset(); /* Clean up sent list */ void handle_ack(uint64_t seq); public: Pipe(const Pipe& other); const Pipe& operator=(const Pipe& other); void start_reader(); void start_writer(); void maybe_start_delay_thread(); void join_reader(); // public constructors static const Pipe& Server(int s); static const Pipe& Client(const entity_addr_t& pi); __u32 get_out_seq() { return out_seq; } bool is_queued() { return !out_q.empty() || send_keepalive || send_keepalive_ack; } entity_addr_t& get_peer_addr() { return peer_addr; } void set_peer_addr(const entity_addr_t& a) { if (&peer_addr != &a) // shut up valgrind peer_addr = a; connection_state->set_peer_addr(a); } void set_peer_type(int t) { peer_type = t; connection_state->set_peer_type(t); } void register_pipe(); void unregister_pipe(); void join(); void stop(); void _send(Message *m) { assert(pipe_lock.is_locked()); out_q[m->get_priority()].push_back(m); cond.Signal(); } void _send_keepalive() { assert(pipe_lock.is_locked()); send_keepalive = true; cond.Signal(); } Message *_get_next_outgoing() { assert(pipe_lock.is_locked()); Message *m = 0; while (!m && !out_q.empty()) { map >::reverse_iterator p = out_q.rbegin(); if (!p->second.empty()) { m = p->second.front(); p->second.pop_front(); } if (p->second.empty()) out_q.erase(p->first); } return m; } /// move all messages in the sent list back into the queue at the highest priority. void requeue_sent(); /// discard messages requeued by requeued_sent() up to a given seq void discard_requeued_up_to(uint64_t seq); void discard_out_queue(); void shutdown_socket() { if (sd >= 0) ::shutdown(sd, SHUT_RDWR); } /** * do a blocking read of len bytes from socket * * @param buf buffer to read into * @param len exact number of bytes to read * @return 0 for success, or -1 on error */ int tcp_read(char *buf, int len); /** * wait for bytes to become available on the socket * * @return 0 for success, or -1 on error */ int tcp_read_wait(); /** * non-blocking read of available bytes on socket * * This is expected to be used after tcp_read_wait(), and will return * an error if there is no data on the socket to consume. * * @param buf buffer to read into * @param len maximum number of bytes to read * @return bytes read, or -1 on error or when there is no data */ int tcp_read_nonblocking(char *buf, int len); /** * blocking write of bytes to socket * * @param buf buffer * @param len number of bytes to write * @return 0 for success, or -1 on error */ int tcp_write(const char *buf, int len); }; #endif ceph-0.80.11/src/msg/Makefile.am0000664000175100017510000000056112623076744020310 0ustar jenkins-buildjenkins-buildlibmsg_la_SOURCES = \ msg/Accepter.cc \ msg/DispatchQueue.cc \ msg/Message.cc \ msg/Messenger.cc \ msg/Pipe.cc \ msg/SimpleMessenger.cc \ msg/msg_types.cc noinst_HEADERS += \ msg/Accepter.h \ msg/DispatchQueue.h \ msg/Dispatcher.h \ msg/Message.h \ msg/Messenger.h \ msg/Pipe.h \ msg/SimpleMessenger.h \ msg/msg_types.h noinst_LTLIBRARIES += libmsg.la ceph-0.80.11/src/msg/SimpleMessenger.cc0000664000175100017510000004512612623076744021673 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include "SimpleMessenger.h" #include "common/config.h" #include "common/Timer.h" #include "common/errno.h" #include "auth/Crypto.h" #include "include/Spinlock.h" #define dout_subsys ceph_subsys_ms #undef dout_prefix #define dout_prefix _prefix(_dout, this) static ostream& _prefix(std::ostream *_dout, SimpleMessenger *msgr) { return *_dout << "-- " << msgr->get_myaddr() << " "; } /******************* * SimpleMessenger */ SimpleMessenger::SimpleMessenger(CephContext *cct, entity_name_t name, string mname, uint64_t _nonce) : Messenger(cct, name), accepter(this, _nonce), dispatch_queue(cct, this), reaper_thread(this), my_type(name.type()), nonce(_nonce), lock("SimpleMessenger::lock"), need_addr(true), did_bind(false), global_seq(0), cluster_protocol(0), policy_lock("SimpleMessenger::policy_lock"), dispatch_throttler(cct, string("msgr_dispatch_throttler-") + mname, cct->_conf->ms_dispatch_throttle_bytes), reaper_started(false), reaper_stop(false), timeout(0), local_connection(new Connection(this)) { ceph_spin_init(&global_seq_lock); init_local_connection(); } /** * Destroy the SimpleMessenger. Pretty simple since all the work is done * elsewhere. */ SimpleMessenger::~SimpleMessenger() { assert(!did_bind); // either we didn't bind or we shut down the Accepter assert(rank_pipe.empty()); // we don't have any running Pipes. assert(reaper_stop && !reaper_started); // the reaper thread is stopped } void SimpleMessenger::ready() { ldout(cct,10) << "ready " << get_myaddr() << dendl; dispatch_queue.start(); lock.Lock(); if (did_bind) accepter.start(); lock.Unlock(); } int SimpleMessenger::shutdown() { ldout(cct,10) << "shutdown " << get_myaddr() << dendl; mark_down_all(); dispatch_queue.shutdown(); // break ref cycles on the loopback connection local_connection->set_priv(NULL); return 0; } int SimpleMessenger::_send_message(Message *m, const entity_inst_t& dest, bool lazy) { // set envelope m->get_header().src = get_myname(); if (!m->get_priority()) m->set_priority(get_default_send_priority()); ldout(cct,1) << (lazy ? "lazy " : "") <<"--> " << dest.name << " " << dest.addr << " -- " << *m << " -- ?+" << m->get_data().length() << " " << m << dendl; if (dest.addr == entity_addr_t()) { ldout(cct,0) << (lazy ? "lazy_" : "") << "send_message message " << *m << " with empty dest " << dest.addr << dendl; m->put(); return -EINVAL; } lock.Lock(); Pipe *pipe = _lookup_pipe(dest.addr); submit_message(m, (pipe ? pipe->connection_state.get() : NULL), dest.addr, dest.name.type(), lazy); lock.Unlock(); return 0; } int SimpleMessenger::_send_message(Message *m, Connection *con, bool lazy) { //set envelope m->get_header().src = get_myname(); if (!m->get_priority()) m->set_priority(get_default_send_priority()); ldout(cct,1) << (lazy ? "lazy " : "") << "--> " << con->get_peer_addr() << " -- " << *m << " -- ?+" << m->get_data().length() << " " << m << " con " << con << dendl; lock.Lock(); submit_message(m, con, con->get_peer_addr(), con->get_peer_type(), lazy); lock.Unlock(); return 0; } /** * If my_inst.addr doesn't have an IP set, this function * will fill it in from the passed addr. Otherwise it does nothing and returns. */ void SimpleMessenger::set_addr_unknowns(entity_addr_t &addr) { if (my_inst.addr.is_blank_ip()) { int port = my_inst.addr.get_port(); my_inst.addr.addr = addr.addr; my_inst.addr.set_port(port); init_local_connection(); } } int SimpleMessenger::get_proto_version(int peer_type, bool connect) { // set reply protocol version if (peer_type == my_type) { // internal return cluster_protocol; } else { // public if (connect) { switch (peer_type) { case CEPH_ENTITY_TYPE_OSD: return CEPH_OSDC_PROTOCOL; case CEPH_ENTITY_TYPE_MDS: return CEPH_MDSC_PROTOCOL; case CEPH_ENTITY_TYPE_MON: return CEPH_MONC_PROTOCOL; } } else { switch (my_type) { case CEPH_ENTITY_TYPE_OSD: return CEPH_OSDC_PROTOCOL; case CEPH_ENTITY_TYPE_MDS: return CEPH_MDSC_PROTOCOL; case CEPH_ENTITY_TYPE_MON: return CEPH_MONC_PROTOCOL; } } } return 0; } /******************************************** * SimpleMessenger */ #undef dout_prefix #define dout_prefix _prefix(_dout, this) void SimpleMessenger::dispatch_throttle_release(uint64_t msize) { if (msize) { ldout(cct,10) << "dispatch_throttle_release " << msize << " to dispatch throttler " << dispatch_throttler.get_current() << "/" << dispatch_throttler.get_max() << dendl; dispatch_throttler.put(msize); } } void SimpleMessenger::reaper_entry() { ldout(cct,10) << "reaper_entry start" << dendl; lock.Lock(); while (!reaper_stop) { reaper(); reaper_cond.Wait(lock); } lock.Unlock(); ldout(cct,10) << "reaper_entry done" << dendl; } /* * note: assumes lock is held */ void SimpleMessenger::reaper() { ldout(cct,10) << "reaper" << dendl; assert(lock.is_locked()); while (!pipe_reap_queue.empty()) { Pipe *p = pipe_reap_queue.front(); pipe_reap_queue.pop_front(); ldout(cct,10) << "reaper reaping pipe " << p << " " << p->get_peer_addr() << dendl; p->pipe_lock.Lock(); p->discard_out_queue(); if (p->connection_state) { // mark_down, mark_down_all, or fault() should have done this, // or accept() may have switch the Connection to a different // Pipe... but make sure! bool cleared = p->connection_state->clear_pipe(p); assert(!cleared); } p->pipe_lock.Unlock(); p->unregister_pipe(); assert(pipes.count(p)); pipes.erase(p); p->join(); if (p->sd >= 0) ::close(p->sd); ldout(cct,10) << "reaper reaped pipe " << p << " " << p->get_peer_addr() << dendl; p->put(); ldout(cct,10) << "reaper deleted pipe " << p << dendl; } ldout(cct,10) << "reaper done" << dendl; } void SimpleMessenger::queue_reap(Pipe *pipe) { ldout(cct,10) << "queue_reap " << pipe << dendl; lock.Lock(); pipe_reap_queue.push_back(pipe); reaper_cond.Signal(); lock.Unlock(); } int SimpleMessenger::bind(const entity_addr_t &bind_addr) { lock.Lock(); if (started) { ldout(cct,10) << "rank.bind already started" << dendl; lock.Unlock(); return -1; } ldout(cct,10) << "rank.bind " << bind_addr << dendl; lock.Unlock(); // bind to a socket set avoid_ports; int r = accepter.bind(bind_addr, avoid_ports); if (r >= 0) did_bind = true; return r; } int SimpleMessenger::rebind(const set& avoid_ports) { ldout(cct,1) << "rebind avoid " << avoid_ports << dendl; assert(did_bind); accepter.stop(); mark_down_all(); return accepter.rebind(avoid_ports); } int SimpleMessenger::start() { lock.Lock(); ldout(cct,1) << "messenger.start" << dendl; // register at least one entity, first! assert(my_type >= 0); assert(!started); started = true; if (!did_bind) { my_inst.addr.nonce = nonce; init_local_connection(); } lock.Unlock(); reaper_started = true; reaper_thread.create(); return 0; } Pipe *SimpleMessenger::add_accept_pipe(int sd) { lock.Lock(); Pipe *p = new Pipe(this, Pipe::STATE_ACCEPTING, NULL); p->sd = sd; p->pipe_lock.Lock(); p->start_reader(); p->pipe_lock.Unlock(); pipes.insert(p); accepting_pipes.insert(p); lock.Unlock(); return p; } /* connect_rank * NOTE: assumes messenger.lock held. */ Pipe *SimpleMessenger::connect_rank(const entity_addr_t& addr, int type, Connection *con, Message *first) { assert(lock.is_locked()); assert(addr != my_inst.addr); ldout(cct,10) << "connect_rank to " << addr << ", creating pipe and registering" << dendl; // create pipe Pipe *pipe = new Pipe(this, Pipe::STATE_CONNECTING, con); pipe->pipe_lock.Lock(); pipe->set_peer_type(type); pipe->set_peer_addr(addr); pipe->policy = get_policy(type); pipe->start_writer(); if (first) pipe->_send(first); pipe->pipe_lock.Unlock(); pipe->register_pipe(); pipes.insert(pipe); return pipe; } AuthAuthorizer *SimpleMessenger::get_authorizer(int peer_type, bool force_new) { return ms_deliver_get_authorizer(peer_type, force_new); } bool SimpleMessenger::verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer, bufferlist& authorizer_reply, bool& isvalid,CryptoKey& session_key) { return ms_deliver_verify_authorizer(con, peer_type, protocol, authorizer, authorizer_reply, isvalid,session_key); } ConnectionRef SimpleMessenger::get_connection(const entity_inst_t& dest) { Mutex::Locker l(lock); if (my_inst.addr == dest.addr) { // local return local_connection; } // remote while (true) { Pipe *pipe = _lookup_pipe(dest.addr); if (pipe) { ldout(cct, 10) << "get_connection " << dest << " existing " << pipe << dendl; } else { pipe = connect_rank(dest.addr, dest.name.type(), NULL, NULL); ldout(cct, 10) << "get_connection " << dest << " new " << pipe << dendl; } Mutex::Locker l(pipe->pipe_lock); if (pipe->connection_state) return pipe->connection_state; // we failed too quickly! retry. FIXME. } } ConnectionRef SimpleMessenger::get_loopback_connection() { return local_connection; } void SimpleMessenger::submit_message(Message *m, Connection *con, const entity_addr_t& dest_addr, int dest_type, bool lazy) { if (cct->_conf->ms_dump_on_send) { m->encode(-1, true); ldout(cct, 0) << "submit_message " << *m << "\n"; m->get_payload().hexdump(*_dout); if (m->get_data().length() > 0) { *_dout << " data:\n"; m->get_data().hexdump(*_dout); } *_dout << dendl; m->clear_payload(); } // existing connection? if (con) { Pipe *pipe = NULL; bool ok = con->try_get_pipe((RefCountedObject**)&pipe); if (!ok) { ldout(cct,0) << "submit_message " << *m << " remote, " << dest_addr << ", failed lossy con, dropping message " << m << dendl; m->put(); return; } if (pipe) { pipe->pipe_lock.Lock(); if (pipe->state != Pipe::STATE_CLOSED) { ldout(cct,20) << "submit_message " << *m << " remote, " << dest_addr << ", have pipe." << dendl; pipe->_send(m); pipe->pipe_lock.Unlock(); pipe->put(); return; } pipe->pipe_lock.Unlock(); pipe->put(); ldout(cct,20) << "submit_message " << *m << " remote, " << dest_addr << ", had pipe " << pipe << ", but it closed." << dendl; m->put(); return; } } // local? if (my_inst.addr == dest_addr) { // local ldout(cct,20) << "submit_message " << *m << " local" << dendl; dispatch_queue.local_delivery(m, m->get_priority()); return; } // remote, no existing pipe. const Policy& policy = get_policy(dest_type); if (policy.server) { ldout(cct,20) << "submit_message " << *m << " remote, " << dest_addr << ", lossy server for target type " << ceph_entity_type_name(dest_type) << ", no session, dropping." << dendl; m->put(); } else if (lazy) { ldout(cct,20) << "submit_message " << *m << " remote, " << dest_addr << ", lazy, dropping." << dendl; m->put(); } else { ldout(cct,20) << "submit_message " << *m << " remote, " << dest_addr << ", new pipe." << dendl; connect_rank(dest_addr, dest_type, con, m); } } int SimpleMessenger::send_keepalive(const entity_inst_t& dest) { const entity_addr_t dest_addr = dest.addr; entity_addr_t dest_proc_addr = dest_addr; int ret = 0; lock.Lock(); { // local? if (my_inst.addr != dest_addr) { // remote. Pipe *pipe = _lookup_pipe(dest_proc_addr); if (pipe) { // connected? pipe->pipe_lock.Lock(); ldout(cct,20) << "send_keepalive remote, " << dest_addr << ", have pipe." << dendl; pipe->_send_keepalive(); pipe->pipe_lock.Unlock(); } else { ret = -EINVAL; } if (!pipe) { ldout(cct,20) << "send_keepalive no pipe for " << dest_addr << ", doing nothing." << dendl; } } } lock.Unlock(); return ret; } int SimpleMessenger::send_keepalive(Connection *con) { int ret = 0; Pipe *pipe = static_cast(con->get_pipe()); if (pipe) { ldout(cct,20) << "send_keepalive con " << con << ", have pipe." << dendl; assert(pipe->msgr == this); pipe->pipe_lock.Lock(); pipe->_send_keepalive(); pipe->pipe_lock.Unlock(); pipe->put(); } else { ldout(cct,0) << "send_keepalive con " << con << ", no pipe." << dendl; ret = -EPIPE; } return ret; } void SimpleMessenger::wait() { lock.Lock(); if (!started) { lock.Unlock(); return; } lock.Unlock(); if(dispatch_queue.is_started()) { ldout(cct,10) << "wait: waiting for dispatch queue" << dendl; dispatch_queue.wait(); ldout(cct,10) << "wait: dispatch queue is stopped" << dendl; } // done! clean up. if (did_bind) { ldout(cct,20) << "wait: stopping accepter thread" << dendl; accepter.stop(); did_bind = false; ldout(cct,20) << "wait: stopped accepter thread" << dendl; } if (reaper_started) { ldout(cct,20) << "wait: stopping reaper thread" << dendl; lock.Lock(); reaper_cond.Signal(); reaper_stop = true; lock.Unlock(); reaper_thread.join(); reaper_started = false; ldout(cct,20) << "wait: stopped reaper thread" << dendl; } // close+reap all pipes lock.Lock(); { ldout(cct,10) << "wait: closing pipes" << dendl; while (!rank_pipe.empty()) { Pipe *p = rank_pipe.begin()->second; p->unregister_pipe(); p->pipe_lock.Lock(); p->stop(); p->pipe_lock.Unlock(); } reaper(); ldout(cct,10) << "wait: waiting for pipes " << pipes << " to close" << dendl; while (!pipes.empty()) { reaper_cond.Wait(lock); reaper(); } } lock.Unlock(); ldout(cct,10) << "wait: done." << dendl; ldout(cct,1) << "shutdown complete." << dendl; started = false; my_type = -1; } void SimpleMessenger::mark_down_all() { ldout(cct,1) << "mark_down_all" << dendl; lock.Lock(); for (set::iterator q = accepting_pipes.begin(); q != accepting_pipes.end(); ++q) { Pipe *p = *q; ldout(cct,5) << "mark_down_all accepting_pipe " << p << dendl; p->pipe_lock.Lock(); p->stop(); ConnectionRef con = p->connection_state; if (con && con->clear_pipe(p)) dispatch_queue.queue_reset(con.get()); p->pipe_lock.Unlock(); } accepting_pipes.clear(); while (!rank_pipe.empty()) { ceph::unordered_map::iterator it = rank_pipe.begin(); Pipe *p = it->second; ldout(cct,5) << "mark_down_all " << it->first << " " << p << dendl; rank_pipe.erase(it); p->unregister_pipe(); p->pipe_lock.Lock(); p->stop(); ConnectionRef con = p->connection_state; if (con && con->clear_pipe(p)) dispatch_queue.queue_reset(con.get()); p->pipe_lock.Unlock(); } lock.Unlock(); } void SimpleMessenger::mark_down(const entity_addr_t& addr) { lock.Lock(); Pipe *p = _lookup_pipe(addr); if (p) { ldout(cct,1) << "mark_down " << addr << " -- " << p << dendl; p->unregister_pipe(); p->pipe_lock.Lock(); p->stop(); if (p->connection_state) { // generate a reset event for the caller in this case, even // though they asked for it, since this is the addr-based (and // not Connection* based) interface ConnectionRef con = p->connection_state; if (con && con->clear_pipe(p)) dispatch_queue.queue_reset(con.get()); } p->pipe_lock.Unlock(); } else { ldout(cct,1) << "mark_down " << addr << " -- pipe dne" << dendl; } lock.Unlock(); } void SimpleMessenger::mark_down(Connection *con) { if (con == NULL) return; lock.Lock(); Pipe *p = static_cast(con->get_pipe()); if (p) { ldout(cct,1) << "mark_down " << con << " -- " << p << dendl; assert(p->msgr == this); p->unregister_pipe(); p->pipe_lock.Lock(); p->stop(); if (p->connection_state) { // do not generate a reset event for the caller in this case, // since they asked for it. p->connection_state->clear_pipe(p); } p->pipe_lock.Unlock(); p->put(); } else { ldout(cct,1) << "mark_down " << con << " -- pipe dne" << dendl; } lock.Unlock(); } void SimpleMessenger::mark_down_on_empty(Connection *con) { lock.Lock(); Pipe *p = static_cast(con->get_pipe()); if (p) { assert(p->msgr == this); p->pipe_lock.Lock(); p->unregister_pipe(); if (p->out_q.empty()) { ldout(cct,1) << "mark_down_on_empty " << con << " -- " << p << " closing (queue is empty)" << dendl; p->stop(); } else { ldout(cct,1) << "mark_down_on_empty " << con << " -- " << p << " marking (queue is not empty)" << dendl; p->close_on_empty = true; } p->pipe_lock.Unlock(); p->put(); } else { ldout(cct,1) << "mark_down_on_empty " << con << " -- pipe dne" << dendl; } lock.Unlock(); } void SimpleMessenger::mark_disposable(Connection *con) { lock.Lock(); Pipe *p = static_cast(con->get_pipe()); if (p) { ldout(cct,1) << "mark_disposable " << con << " -- " << p << dendl; assert(p->msgr == this); p->pipe_lock.Lock(); p->policy.lossy = true; p->pipe_lock.Unlock(); p->put(); } else { ldout(cct,1) << "mark_disposable " << con << " -- pipe dne" << dendl; } lock.Unlock(); } void SimpleMessenger::learned_addr(const entity_addr_t &peer_addr_for_me) { // be careful here: multiple threads may block here, and readers of // my_inst.addr do NOT hold any lock. // this always goes from true -> false under the protection of the // mutex. if it is already false, we need not retake the mutex at // all. if (!need_addr) return; lock.Lock(); if (need_addr) { entity_addr_t t = peer_addr_for_me; t.set_port(my_inst.addr.get_port()); my_inst.addr.addr = t.addr; ldout(cct,1) << "learned my addr " << my_inst.addr << dendl; need_addr = false; init_local_connection(); } lock.Unlock(); } void SimpleMessenger::unlearn_addr() { lock.Lock(); need_addr = true; lock.Unlock(); } void SimpleMessenger::init_local_connection() { local_connection->peer_addr = my_inst.addr; local_connection->peer_type = my_type; } ceph-0.80.11/src/msg/msg_types.h0000664000175100017510000002675712623076744020456 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_MSG_TYPES_H #define CEPH_MSG_TYPES_H #include #include "include/types.h" #include "include/blobhash.h" #include "include/encoding.h" #include "include/hash_namespace.h" namespace ceph { class Formatter; } inline bool operator==(const sockaddr_in& a, const sockaddr_in& b) { return strncmp((const char*)&a, (const char*)&b, sizeof(a)) == 0; } inline bool operator!=(const sockaddr_in& a, const sockaddr_in& b) { return strncmp((const char*)&a, (const char*)&b, sizeof(a)) != 0; } extern ostream& operator<<(ostream& out, const sockaddr_storage &ss); class entity_name_t { public: __u8 _type; int64_t _num; public: static const int TYPE_MON = CEPH_ENTITY_TYPE_MON; static const int TYPE_MDS = CEPH_ENTITY_TYPE_MDS; static const int TYPE_OSD = CEPH_ENTITY_TYPE_OSD; static const int TYPE_CLIENT = CEPH_ENTITY_TYPE_CLIENT; static const int NEW = -1; // cons entity_name_t() : _type(0), _num(0) { } entity_name_t(int t, int64_t n) : _type(t), _num(n) { } entity_name_t(const ceph_entity_name &n) : _type(n.type), _num(n.num) { } // static cons static entity_name_t MON(int i=NEW) { return entity_name_t(TYPE_MON, i); } static entity_name_t MDS(int i=NEW) { return entity_name_t(TYPE_MDS, i); } static entity_name_t OSD(int i=NEW) { return entity_name_t(TYPE_OSD, i); } static entity_name_t CLIENT(int i=NEW) { return entity_name_t(TYPE_CLIENT, i); } int64_t num() const { return _num; } int type() const { return _type; } const char *type_str() const { return ceph_entity_type_name(type()); } bool is_new() const { return num() < 0; } bool is_client() const { return type() == TYPE_CLIENT; } bool is_mds() const { return type() == TYPE_MDS; } bool is_osd() const { return type() == TYPE_OSD; } bool is_mon() const { return type() == TYPE_MON; } operator ceph_entity_name() const { ceph_entity_name n = { _type, init_le64(_num) }; return n; } bool parse(const string& s) { const char *start = s.c_str(); char *end; bool got = parse(start, &end); return got && end == start + s.length(); } bool parse(const char *start, char **end) { if (strstr(start, "mon.") == start) { _type = TYPE_MON; start += 4; } else if (strstr(start, "osd.") == start) { _type = TYPE_OSD; start += 4; } else if (strstr(start, "mds.") == start) { _type = TYPE_MDS; start += 4; } else if (strstr(start, "client.") == start) { _type = TYPE_CLIENT; start += 7; } else { return false; } if (isspace(*start)) return false; _num = strtoll(start, end, 10); if (*end == NULL || *end == start) return false; return true; } void encode(bufferlist& bl) const { ::encode(_type, bl); ::encode(_num, bl); } void decode(bufferlist::iterator& bl) { ::decode(_type, bl); ::decode(_num, bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(entity_name_t) inline bool operator== (const entity_name_t& l, const entity_name_t& r) { return (l.type() == r.type()) && (l.num() == r.num()); } inline bool operator!= (const entity_name_t& l, const entity_name_t& r) { return (l.type() != r.type()) || (l.num() != r.num()); } inline bool operator< (const entity_name_t& l, const entity_name_t& r) { return (l.type() < r.type()) || (l.type() == r.type() && l.num() < r.num()); } inline std::ostream& operator<<(std::ostream& out, const entity_name_t& addr) { //if (addr.is_namer()) return out << "namer"; if (addr.is_new() || addr.num() < 0) return out << addr.type_str() << ".?"; else return out << addr.type_str() << '.' << addr.num(); } inline std::ostream& operator<<(std::ostream& out, const ceph_entity_name& addr) { return out << *(const entity_name_t*)&addr; } CEPH_HASH_NAMESPACE_START template<> struct hash< entity_name_t > { size_t operator()( const entity_name_t &m ) const { return rjhash32(m.type() ^ m.num()); } }; CEPH_HASH_NAMESPACE_END /* * an entity's network address. * includes a random value that prevents it from being reused. * thus identifies a particular process instance. * ipv4 for now. */ /* * encode sockaddr.ss_family in big endian */ static inline void encode(const sockaddr_storage& a, bufferlist& bl) { struct sockaddr_storage ss = a; #if !defined(__FreeBSD__) ss.ss_family = htons(ss.ss_family); #endif ::encode_raw(ss, bl); } static inline void decode(sockaddr_storage& a, bufferlist::iterator& bl) { ::decode_raw(a, bl); #if !defined(__FreeBSD__) a.ss_family = ntohs(a.ss_family); #endif } struct entity_addr_t { __u32 type; __u32 nonce; union { sockaddr_storage addr; sockaddr_in addr4; sockaddr_in6 addr6; }; unsigned int addr_size() const { switch (addr.ss_family) { case AF_INET: return sizeof(addr4); break; case AF_INET6: return sizeof(addr6); break; } return sizeof(addr); } entity_addr_t() : type(0), nonce(0) { memset(&addr, 0, sizeof(addr)); } entity_addr_t(const ceph_entity_addr &o) { type = o.type; nonce = o.nonce; addr = o.in_addr; #if !defined(__FreeBSD__) addr.ss_family = ntohs(addr.ss_family); #endif } __u32 get_nonce() const { return nonce; } void set_nonce(__u32 n) { nonce = n; } int get_family() const { return addr.ss_family; } void set_family(int f) { addr.ss_family = f; } sockaddr_storage &ss_addr() { return addr; } sockaddr_in &in4_addr() { return addr4; } sockaddr_in6 &in6_addr() { return addr6; } bool set_sockaddr(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: memcpy(&addr4, sa, sizeof(sockaddr_in)); break; case AF_INET6: memcpy(&addr6, sa, sizeof(sockaddr_in6)); break; default: return false; } return true; } void set_in4_quad(int pos, int val) { addr4.sin_family = AF_INET; unsigned char *ipq = (unsigned char*)&addr4.sin_addr.s_addr; ipq[pos] = val; } void set_port(int port) { switch (addr.ss_family) { case AF_INET: addr4.sin_port = htons(port); break; case AF_INET6: addr6.sin6_port = htons(port); break; default: assert(0); } } int get_port() const { switch (addr.ss_family) { case AF_INET: return ntohs(addr4.sin_port); break; case AF_INET6: return ntohs(addr6.sin6_port); break; } return 0; } operator ceph_entity_addr() const { ceph_entity_addr a; a.type = 0; a.nonce = nonce; a.in_addr = addr; #if !defined(__FreeBSD__) a.in_addr.ss_family = htons(addr.ss_family); #endif return a; } bool probably_equals(const entity_addr_t &o) const { if (get_port() != o.get_port()) return false; if (get_nonce() != o.get_nonce()) return false; if (is_blank_ip() || o.is_blank_ip()) return true; if (memcmp(&addr, &o.addr, sizeof(addr)) == 0) return true; return false; } bool is_same_host(const entity_addr_t &o) const { if (addr.ss_family != o.addr.ss_family) return false; if (addr.ss_family == AF_INET) return addr4.sin_addr.s_addr == o.addr4.sin_addr.s_addr; if (addr.ss_family == AF_INET6) return memcmp(addr6.sin6_addr.s6_addr, o.addr6.sin6_addr.s6_addr, sizeof(addr6.sin6_addr.s6_addr)) == 0; return false; } bool is_blank_ip() const { switch (addr.ss_family) { case AF_INET: return addr4.sin_addr.s_addr == INADDR_ANY; case AF_INET6: return memcmp(&addr6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0; default: return true; } } bool is_ip() const { switch (addr.ss_family) { case AF_INET: case AF_INET6: return true; default: return false; } } bool parse(const char *s, const char **end = 0); void encode(bufferlist& bl) const { ::encode(type, bl); ::encode(nonce, bl); ::encode(addr, bl); } void decode(bufferlist::iterator& bl) { ::decode(type, bl); ::decode(nonce, bl); ::decode(addr, bl); } void dump(Formatter *f) const; static void generate_test_instances(list& o); }; WRITE_CLASS_ENCODER(entity_addr_t) inline ostream& operator<<(ostream& out, const entity_addr_t &addr) { return out << addr.addr << '/' << addr.nonce; } inline bool operator==(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) == 0; } inline bool operator!=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) != 0; } inline bool operator<(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) < 0; } inline bool operator<=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) <= 0; } inline bool operator>(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) > 0; } inline bool operator>=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) >= 0; } CEPH_HASH_NAMESPACE_START template<> struct hash< entity_addr_t > { size_t operator()( const entity_addr_t& x ) const { static blobhash H; return H((const char*)&x, sizeof(x)); } }; CEPH_HASH_NAMESPACE_END /* * a particular entity instance */ struct entity_inst_t { entity_name_t name; entity_addr_t addr; entity_inst_t() {} entity_inst_t(entity_name_t n, const entity_addr_t& a) : name(n), addr(a) {} entity_inst_t(const ceph_entity_inst& i) : name(i.name), addr(i.addr) { } entity_inst_t(const ceph_entity_name& n, const ceph_entity_addr &a) : name(n), addr(a) {} operator ceph_entity_inst() { ceph_entity_inst i = {name, addr}; return i; } void encode(bufferlist& bl) const { ::encode(name, bl); ::encode(addr, bl); } void decode(bufferlist::iterator& bl) { ::decode(name, bl); ::decode(addr, bl); } }; WRITE_CLASS_ENCODER(entity_inst_t) inline bool operator==(const entity_inst_t& a, const entity_inst_t& b) { return a.name == b.name && a.addr == b.addr; } inline bool operator!=(const entity_inst_t& a, const entity_inst_t& b) { return a.name != b.name || a.addr != b.addr; } inline bool operator<(const entity_inst_t& a, const entity_inst_t& b) { return a.name < b.name || (a.name == b.name && a.addr < b.addr); } inline bool operator<=(const entity_inst_t& a, const entity_inst_t& b) { return a.name < b.name || (a.name == b.name && a.addr <= b.addr); } inline bool operator>(const entity_inst_t& a, const entity_inst_t& b) { return b < a; } inline bool operator>=(const entity_inst_t& a, const entity_inst_t& b) { return b <= a; } CEPH_HASH_NAMESPACE_START template<> struct hash< entity_inst_t > { size_t operator()( const entity_inst_t& x ) const { static hash< entity_name_t > H; static hash< entity_addr_t > I; return H(x.name) ^ I(x.addr); } }; CEPH_HASH_NAMESPACE_END inline ostream& operator<<(ostream& out, const entity_inst_t &i) { return out << i.name << " " << i.addr; } inline ostream& operator<<(ostream& out, const ceph_entity_inst &i) { entity_inst_t n = i; return out << n; } #endif ceph-0.80.11/src/msg/Dispatcher.h0000664000175100017510000000754012623076744020517 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DISPATCHER_H #define CEPH_DISPATCHER_H #include "Message.h" #include "common/config.h" #include "auth/Auth.h" class Messenger; class Dispatcher { public: Dispatcher(CephContext *cct_) : cct(cct_) { } virtual ~Dispatcher() { } // how i receive messages virtual bool ms_dispatch(Message *m) = 0; /** * This function will be called whenever a new Connection is made to the * Messenger. * * @param con The new Connection which has been established. You are not * granted a reference to it -- take one if you need one! */ virtual void ms_handle_connect(Connection *con) { }; /** * Callback indicating we have accepted an incoming connection. * * @param con The (new or existing) Connection associated with the session */ virtual void ms_handle_accept(Connection *con) { }; /* * this indicates that the ordered+reliable delivery semantics have * been violated. Messages may have been lost due to a fault * in the network connection. * Only called on lossy Connections or those you've * designated mark_down_on_empty(). * * @param con The Connection which broke. You are not granted * a reference to it. */ virtual bool ms_handle_reset(Connection *con) = 0; /** * This indicates that the ordered+reliable delivery semantics * have been violated because the remote somehow reset. * It implies that incoming messages were dropped, and * probably some of our previous outgoing messages were too. * * @param con The Connection which broke. You are not granted * a reference to it. */ virtual void ms_handle_remote_reset(Connection *con) = 0; /** * @defgroup Authentication * @{ */ /** * Retrieve the AuthAuthorizer for the given peer type. It might not * provide one if it knows there is no AuthAuthorizer for that type. * * @param dest_type The peer type we want the authorizer for. * @param a Double pointer to an AuthAuthorizer. The Dispatcher will fill * in *a with the correct AuthAuthorizer, if it can. Make sure that you have * set *a to NULL before calling in. * @param force_new Force the Dispatcher to wait for a new set of keys before * returning the authorizer. * * @return True if this function call properly filled in *a, false otherwise. */ virtual bool ms_get_authorizer(int dest_type, AuthAuthorizer **a, bool force_new) { return false; }; /** * Verify the authorizer for a new incoming Connection. * * @param con The new incoming Connection * @param peer_type The type of the endpoint which initiated this Connection * @param protocol The ID of the protocol in use (at time of writing, cephx or none) * @param authorizer The authorization string supplied by the remote * @param authorizer_reply Output param: The string we should send back to * the remote to authorize ourselves. Only filled in if isvalid * @param isvalid Output param: True if authorizer is valid, false otherwise * * @return True if we were able to prove or disprove correctness of * authorizer, false otherwise. */ virtual bool ms_verify_authorizer(Connection *con, int peer_type, int protocol, bufferlist& authorizer, bufferlist& authorizer_reply, bool& isvalid, CryptoKey& session_key) { return false; }; /** * @} //Authentication */ protected: CephContext *cct; private: Dispatcher(const Dispatcher &rhs); Dispatcher& operator=(const Dispatcher &rhs); }; #endif ceph-0.80.11/src/msg/DispatchQueue.h0000664000175100017510000001046112623076744021171 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_DISPATCHQUEUE_H #define CEPH_DISPATCHQUEUE_H #include #include #include "include/assert.h" #include "include/xlist.h" #include "include/atomic.h" #include "common/Mutex.h" #include "common/Cond.h" #include "common/Thread.h" #include "common/RefCountedObj.h" #include "common/PrioritizedQueue.h" class CephContext; class DispatchQueue; class Pipe; class SimpleMessenger; class Message; struct Connection; /** * The DispatchQueue contains all the Pipes which have Messages * they want to be dispatched, carefully organized by Message priority * and permitted to deliver in a round-robin fashion. * See SimpleMessenger::dispatch_entry for details. */ class DispatchQueue { class QueueItem { int type; ConnectionRef con; MessageRef m; public: QueueItem(Message *m) : type(-1), con(0), m(m) {} QueueItem(int type, Connection *con) : type(type), con(con), m(0) {} bool is_code() const { return type != -1; } int get_code () { assert(is_code()); return type; } Message *get_message() { assert(!is_code()); return m.get(); } Connection *get_connection() { assert(is_code()); return con.get(); } }; CephContext *cct; SimpleMessenger *msgr; Mutex lock; Cond cond; PrioritizedQueue mqueue; set > marrival; map >::iterator> marrival_map; void add_arrival(Message *m) { marrival_map.insert( make_pair( m, marrival.insert(make_pair(m->get_recv_stamp(), m)).first ) ); } void remove_arrival(Message *m) { map >::iterator>::iterator i = marrival_map.find(m); assert(i != marrival_map.end()); marrival.erase(i->second); marrival_map.erase(i); } uint64_t next_pipe_id; enum { D_CONNECT = 1, D_ACCEPT, D_BAD_REMOTE_RESET, D_BAD_RESET, D_NUM_CODES }; /** * The DispatchThread runs dispatch_entry to empty out the dispatch_queue. */ class DispatchThread : public Thread { DispatchQueue *dq; public: DispatchThread(DispatchQueue *dq) : dq(dq) {} void *entry() { dq->entry(); return 0; } } dispatch_thread; public: bool stop; void local_delivery(Message *m, int priority); double get_max_age(utime_t now); int get_queue_len() { Mutex::Locker l(lock); return mqueue.length(); } void queue_connect(Connection *con) { Mutex::Locker l(lock); if (stop) return; mqueue.enqueue_strict( 0, CEPH_MSG_PRIO_HIGHEST, QueueItem(D_CONNECT, con)); cond.Signal(); } void queue_accept(Connection *con) { Mutex::Locker l(lock); if (stop) return; mqueue.enqueue_strict( 0, CEPH_MSG_PRIO_HIGHEST, QueueItem(D_ACCEPT, con)); cond.Signal(); } void queue_remote_reset(Connection *con) { Mutex::Locker l(lock); if (stop) return; mqueue.enqueue_strict( 0, CEPH_MSG_PRIO_HIGHEST, QueueItem(D_BAD_REMOTE_RESET, con)); cond.Signal(); } void queue_reset(Connection *con) { Mutex::Locker l(lock); if (stop) return; mqueue.enqueue_strict( 0, CEPH_MSG_PRIO_HIGHEST, QueueItem(D_BAD_RESET, con)); cond.Signal(); } void enqueue(Message *m, int priority, uint64_t id); void discard_queue(uint64_t id); uint64_t get_id() { Mutex::Locker l(lock); return next_pipe_id++; } void start(); void entry(); void wait(); void shutdown(); bool is_started() {return dispatch_thread.is_started();} DispatchQueue(CephContext *cct, SimpleMessenger *msgr) : cct(cct), msgr(msgr), lock("SimpleMessenger::DispatchQeueu::lock"), mqueue(cct->_conf->ms_pq_max_tokens_per_priority, cct->_conf->ms_pq_min_cost), next_pipe_id(1), dispatch_thread(this), stop(false) {} }; #endif ceph-0.80.11/src/msg/Message.cc0000664000175100017510000004356312623076744020160 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifdef ENCODE_DUMP # include # include #endif #include using namespace std; #include "include/types.h" #include "global/global_context.h" #include "Message.h" #include "Pipe.h" #include "messages/MPGStats.h" #include "messages/MGenericMessage.h" #include "messages/MPGStatsAck.h" #include "messages/MStatfs.h" #include "messages/MStatfsReply.h" #include "messages/MGetPoolStats.h" #include "messages/MGetPoolStatsReply.h" #include "messages/MPoolOp.h" #include "messages/MPoolOpReply.h" #include "messages/PaxosServiceMessage.h" #include "messages/MMonCommand.h" #include "messages/MMonCommandAck.h" #include "messages/MMonPaxos.h" #include "messages/MMonProbe.h" #include "messages/MMonJoin.h" #include "messages/MMonElection.h" #include "messages/MMonSync.h" #include "messages/MMonScrub.h" #include "messages/MLog.h" #include "messages/MLogAck.h" #include "messages/MPing.h" #include "messages/MCommand.h" #include "messages/MCommandReply.h" #include "messages/MBackfillReserve.h" #include "messages/MRecoveryReserve.h" #include "messages/MRoute.h" #include "messages/MForward.h" #include "messages/MOSDBoot.h" #include "messages/MOSDAlive.h" #include "messages/MOSDPGTemp.h" #include "messages/MOSDFailure.h" #include "messages/MOSDMarkMeDown.h" #include "messages/MOSDPing.h" #include "messages/MOSDOp.h" #include "messages/MOSDOpReply.h" #include "messages/MOSDSubOp.h" #include "messages/MOSDSubOpReply.h" #include "messages/MOSDMap.h" #include "messages/MOSDPGNotify.h" #include "messages/MOSDPGQuery.h" #include "messages/MOSDPGLog.h" #include "messages/MOSDPGRemove.h" #include "messages/MOSDPGInfo.h" #include "messages/MOSDPGCreate.h" #include "messages/MOSDPGTrim.h" #include "messages/MOSDPGMissing.h" #include "messages/MOSDScrub.h" #include "messages/MOSDRepScrub.h" #include "messages/MOSDPGScan.h" #include "messages/MOSDPGBackfill.h" #include "messages/MRemoveSnaps.h" #include "messages/MMonMap.h" #include "messages/MMonGetMap.h" #include "messages/MMonGetVersion.h" #include "messages/MMonGetVersionReply.h" #include "messages/MMonHealth.h" #include "messages/MAuth.h" #include "messages/MAuthReply.h" #include "messages/MMonSubscribe.h" #include "messages/MMonSubscribeAck.h" #include "messages/MMonGlobalID.h" #include "messages/MClientSession.h" #include "messages/MClientReconnect.h" #include "messages/MClientRequest.h" #include "messages/MClientRequestForward.h" #include "messages/MClientReply.h" #include "messages/MClientCaps.h" #include "messages/MClientCapRelease.h" #include "messages/MClientLease.h" #include "messages/MClientSnap.h" #include "messages/MMDSSlaveRequest.h" #include "messages/MMDSMap.h" #include "messages/MMDSBeacon.h" #include "messages/MMDSLoadTargets.h" #include "messages/MMDSResolve.h" #include "messages/MMDSResolveAck.h" #include "messages/MMDSCacheRejoin.h" #include "messages/MMDSFindIno.h" #include "messages/MMDSFindInoReply.h" #include "messages/MMDSOpenIno.h" #include "messages/MMDSOpenInoReply.h" #include "messages/MDirUpdate.h" #include "messages/MDiscover.h" #include "messages/MDiscoverReply.h" #include "messages/MMDSFragmentNotify.h" #include "messages/MExportDirDiscover.h" #include "messages/MExportDirDiscoverAck.h" #include "messages/MExportDirCancel.h" #include "messages/MExportDirPrep.h" #include "messages/MExportDirPrepAck.h" #include "messages/MExportDir.h" #include "messages/MExportDirAck.h" #include "messages/MExportDirNotify.h" #include "messages/MExportDirNotifyAck.h" #include "messages/MExportDirFinish.h" #include "messages/MExportCaps.h" #include "messages/MExportCapsAck.h" #include "messages/MDentryUnlink.h" #include "messages/MDentryLink.h" #include "messages/MHeartbeat.h" #include "messages/MMDSTableRequest.h" //#include "messages/MInodeUpdate.h" #include "messages/MCacheExpire.h" #include "messages/MInodeFileCaps.h" #include "messages/MLock.h" #include "messages/MWatchNotify.h" #include "messages/MTimeCheck.h" #include "common/config.h" #include "messages/MOSDPGPush.h" #include "messages/MOSDPGPushReply.h" #include "messages/MOSDPGPull.h" #include "messages/MOSDECSubOpWrite.h" #include "messages/MOSDECSubOpWriteReply.h" #include "messages/MOSDECSubOpRead.h" #include "messages/MOSDECSubOpReadReply.h" #define DEBUGLVL 10 // debug level of output #define dout_subsys ceph_subsys_ms void Message::encode(uint64_t features, bool datacrc) { // encode and copy out of *m if (empty_payload()) { encode_payload(features); // if the encoder didn't specify past compatibility, we assume it // is incompatible. if (header.compat_version == 0) header.compat_version = header.version; } calc_front_crc(); // update envelope header.front_len = get_payload().length(); header.middle_len = get_middle().length(); header.data_len = get_data().length(); calc_header_crc(); footer.flags = CEPH_MSG_FOOTER_COMPLETE; if (datacrc) { calc_data_crc(); #ifdef ENCODE_DUMP bufferlist bl; ::encode(get_header(), bl); // dump the old footer format ceph_msg_footer_old old_footer; old_footer.front_crc = footer.front_crc; old_footer.middle_crc = footer.middle_crc; old_footer.data_crc = footer.data_crc; old_footer.flags = footer.flags; ::encode(old_footer, bl); ::encode(get_payload(), bl); ::encode(get_middle(), bl); ::encode(get_data(), bl); // this is almost an exponential backoff, except because we count // bits we tend to sample things we encode later, which should be // more representative. static int i = 0; i++; int bits = 0; for (unsigned t = i; t; bits++) t &= t - 1; if (bits <= 2) { char fn[200]; int status; snprintf(fn, sizeof(fn), ENCODE_STRINGIFY(ENCODE_DUMP) "/%s__%d.%x", abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status), getpid(), i++); int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); if (fd >= 0) { bl.write_fd(fd); ::close(fd); } } #endif } else { footer.flags = (unsigned)footer.flags | CEPH_MSG_FOOTER_NOCRC; } } void Message::dump(Formatter *f) const { stringstream ss; print(ss); f->dump_string("summary", ss.str()); } Message *decode_message(CephContext *cct, ceph_msg_header& header, ceph_msg_footer& footer, bufferlist& front, bufferlist& middle, bufferlist& data) { // verify crc if (!cct || !cct->_conf->ms_nocrc) { __u32 front_crc = front.crc32c(0); __u32 middle_crc = middle.crc32c(0); if (front_crc != footer.front_crc) { if (cct) { ldout(cct, 0) << "bad crc in front " << front_crc << " != exp " << footer.front_crc << dendl; ldout(cct, 20) << " "; front.hexdump(*_dout); *_dout << dendl; } return 0; } if (middle_crc != footer.middle_crc) { if (cct) { ldout(cct, 0) << "bad crc in middle " << middle_crc << " != exp " << footer.middle_crc << dendl; ldout(cct, 20) << " "; middle.hexdump(*_dout); *_dout << dendl; } return 0; } if ((footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0) { __u32 data_crc = data.crc32c(0); if (data_crc != footer.data_crc) { if (cct) { ldout(cct, 0) << "bad crc in data " << data_crc << " != exp " << footer.data_crc << dendl; ldout(cct, 20) << " "; data.hexdump(*_dout); *_dout << dendl; } return 0; } } } // make message Message *m = 0; int type = header.type; switch (type) { // -- with payload -- case MSG_PGSTATS: m = new MPGStats; break; case MSG_PGSTATSACK: m = new MPGStatsAck; break; case CEPH_MSG_STATFS: m = new MStatfs; break; case CEPH_MSG_STATFS_REPLY: m = new MStatfsReply; break; case MSG_GETPOOLSTATS: m = new MGetPoolStats; break; case MSG_GETPOOLSTATSREPLY: m = new MGetPoolStatsReply; break; case CEPH_MSG_POOLOP: m = new MPoolOp; break; case CEPH_MSG_POOLOP_REPLY: m = new MPoolOpReply; break; case MSG_MON_COMMAND: m = new MMonCommand; break; case MSG_MON_COMMAND_ACK: m = new MMonCommandAck; break; case MSG_MON_PAXOS: m = new MMonPaxos; break; case MSG_MON_PROBE: m = new MMonProbe; break; case MSG_MON_JOIN: m = new MMonJoin; break; case MSG_MON_ELECTION: m = new MMonElection; break; case MSG_MON_SYNC: m = new MMonSync; break; case MSG_MON_SCRUB: m = new MMonScrub; break; case MSG_LOG: m = new MLog; break; case MSG_LOGACK: m = new MLogAck; break; case CEPH_MSG_PING: m = new MPing(); break; case MSG_COMMAND: m = new MCommand; break; case MSG_COMMAND_REPLY: m = new MCommandReply; break; case MSG_OSD_BACKFILL_RESERVE: m = new MBackfillReserve; break; case MSG_OSD_RECOVERY_RESERVE: m = new MRecoveryReserve; break; case MSG_ROUTE: m = new MRoute; break; case MSG_FORWARD: m = new MForward; break; case CEPH_MSG_MON_MAP: m = new MMonMap; break; case CEPH_MSG_MON_GET_MAP: m = new MMonGetMap; break; case CEPH_MSG_MON_GET_VERSION: m = new MMonGetVersion(); break; case CEPH_MSG_MON_GET_VERSION_REPLY: m = new MMonGetVersionReply(); break; case MSG_OSD_BOOT: m = new MOSDBoot(); break; case MSG_OSD_ALIVE: m = new MOSDAlive(); break; case MSG_OSD_PGTEMP: m = new MOSDPGTemp; break; case MSG_OSD_FAILURE: m = new MOSDFailure(); break; case MSG_OSD_MARK_ME_DOWN: m = new MOSDMarkMeDown(); break; case MSG_OSD_PING: m = new MOSDPing(); break; case CEPH_MSG_OSD_OP: m = new MOSDOp(); break; case CEPH_MSG_OSD_OPREPLY: m = new MOSDOpReply(); break; case MSG_OSD_SUBOP: m = new MOSDSubOp(); break; case MSG_OSD_SUBOPREPLY: m = new MOSDSubOpReply(); break; case CEPH_MSG_OSD_MAP: m = new MOSDMap; break; case CEPH_MSG_WATCH_NOTIFY: m = new MWatchNotify; break; case MSG_OSD_PG_NOTIFY: m = new MOSDPGNotify; break; case MSG_OSD_PG_QUERY: m = new MOSDPGQuery; break; case MSG_OSD_PG_LOG: m = new MOSDPGLog; break; case MSG_OSD_PG_REMOVE: m = new MOSDPGRemove; break; case MSG_OSD_PG_INFO: m = new MOSDPGInfo; break; case MSG_OSD_PG_CREATE: m = new MOSDPGCreate; break; case MSG_OSD_PG_TRIM: m = new MOSDPGTrim; break; case MSG_OSD_SCRUB: m = new MOSDScrub; break; case MSG_REMOVE_SNAPS: m = new MRemoveSnaps; break; case MSG_OSD_PG_MISSING: m = new MOSDPGMissing; break; case MSG_OSD_REP_SCRUB: m = new MOSDRepScrub; break; case MSG_OSD_PG_SCAN: m = new MOSDPGScan; break; case MSG_OSD_PG_BACKFILL: m = new MOSDPGBackfill; break; case MSG_OSD_PG_PUSH: m = new MOSDPGPush; break; case MSG_OSD_PG_PULL: m = new MOSDPGPull; break; case MSG_OSD_PG_PUSH_REPLY: m = new MOSDPGPushReply; break; case MSG_OSD_EC_WRITE: m = new MOSDECSubOpWrite; break; case MSG_OSD_EC_WRITE_REPLY: m = new MOSDECSubOpWriteReply; break; case MSG_OSD_EC_READ: m = new MOSDECSubOpRead; break; case MSG_OSD_EC_READ_REPLY: m = new MOSDECSubOpReadReply; break; // auth case CEPH_MSG_AUTH: m = new MAuth; break; case CEPH_MSG_AUTH_REPLY: m = new MAuthReply; break; case MSG_MON_GLOBAL_ID: m = new MMonGlobalID; break; // clients case CEPH_MSG_MON_SUBSCRIBE: m = new MMonSubscribe; break; case CEPH_MSG_MON_SUBSCRIBE_ACK: m = new MMonSubscribeAck; break; case CEPH_MSG_CLIENT_SESSION: m = new MClientSession; break; case CEPH_MSG_CLIENT_RECONNECT: m = new MClientReconnect; break; case CEPH_MSG_CLIENT_REQUEST: m = new MClientRequest; break; case CEPH_MSG_CLIENT_REQUEST_FORWARD: m = new MClientRequestForward; break; case CEPH_MSG_CLIENT_REPLY: m = new MClientReply; break; case CEPH_MSG_CLIENT_CAPS: m = new MClientCaps; break; case CEPH_MSG_CLIENT_CAPRELEASE: m = new MClientCapRelease; break; case CEPH_MSG_CLIENT_LEASE: m = new MClientLease; break; case CEPH_MSG_CLIENT_SNAP: m = new MClientSnap; break; // mds case MSG_MDS_SLAVE_REQUEST: m = new MMDSSlaveRequest; break; case CEPH_MSG_MDS_MAP: m = new MMDSMap; break; case MSG_MDS_BEACON: m = new MMDSBeacon; break; case MSG_MDS_OFFLOAD_TARGETS: m = new MMDSLoadTargets; break; case MSG_MDS_RESOLVE: m = new MMDSResolve; break; case MSG_MDS_RESOLVEACK: m = new MMDSResolveAck; break; case MSG_MDS_CACHEREJOIN: m = new MMDSCacheRejoin; break; /* case MSG_MDS_CACHEREJOINACK: m = new MMDSCacheRejoinAck; break; */ case MSG_MDS_DIRUPDATE: m = new MDirUpdate(); break; case MSG_MDS_DISCOVER: m = new MDiscover(); break; case MSG_MDS_DISCOVERREPLY: m = new MDiscoverReply(); break; case MSG_MDS_FINDINO: m = new MMDSFindIno; break; case MSG_MDS_FINDINOREPLY: m = new MMDSFindInoReply; break; case MSG_MDS_OPENINO: m = new MMDSOpenIno; break; case MSG_MDS_OPENINOREPLY: m = new MMDSOpenInoReply; break; case MSG_MDS_FRAGMENTNOTIFY: m = new MMDSFragmentNotify; break; case MSG_MDS_EXPORTDIRDISCOVER: m = new MExportDirDiscover(); break; case MSG_MDS_EXPORTDIRDISCOVERACK: m = new MExportDirDiscoverAck(); break; case MSG_MDS_EXPORTDIRCANCEL: m = new MExportDirCancel(); break; case MSG_MDS_EXPORTDIR: m = new MExportDir; break; case MSG_MDS_EXPORTDIRACK: m = new MExportDirAck; break; case MSG_MDS_EXPORTDIRFINISH: m = new MExportDirFinish; break; case MSG_MDS_EXPORTDIRNOTIFY: m = new MExportDirNotify(); break; case MSG_MDS_EXPORTDIRNOTIFYACK: m = new MExportDirNotifyAck(); break; case MSG_MDS_EXPORTDIRPREP: m = new MExportDirPrep(); break; case MSG_MDS_EXPORTDIRPREPACK: m = new MExportDirPrepAck(); break; case MSG_MDS_EXPORTCAPS: m = new MExportCaps; break; case MSG_MDS_EXPORTCAPSACK: m = new MExportCapsAck; break; case MSG_MDS_DENTRYUNLINK: m = new MDentryUnlink; break; case MSG_MDS_DENTRYLINK: m = new MDentryLink; break; case MSG_MDS_HEARTBEAT: m = new MHeartbeat(); break; case MSG_MDS_CACHEEXPIRE: m = new MCacheExpire(); break; case MSG_MDS_TABLE_REQUEST: m = new MMDSTableRequest; break; /* case MSG_MDS_INODEUPDATE: m = new MInodeUpdate(); break; */ case MSG_MDS_INODEFILECAPS: m = new MInodeFileCaps(); break; case MSG_MDS_LOCK: m = new MLock(); break; case MSG_TIMECHECK: m = new MTimeCheck(); break; case MSG_MON_HEALTH: m = new MMonHealth(); break; // -- simple messages without payload -- case CEPH_MSG_SHUTDOWN: m = new MGenericMessage(type); break; default: if (cct) { ldout(cct, 0) << "can't decode unknown message type " << type << " MSG_AUTH=" << CEPH_MSG_AUTH << dendl; if (cct->_conf->ms_die_on_bad_msg) assert(0); } return 0; } // m->header.version, if non-zero, should be populated with the // newest version of the encoding the code supports. If set, check // it against compat_version. if (m->get_header().version && m->get_header().version < header.compat_version) { if (cct) { ldout(cct, 0) << "will not decode message of type " << type << " version " << header.version << " because compat_version " << header.compat_version << " > supported version " << m->get_header().version << dendl; if (cct->_conf->ms_die_on_bad_msg) assert(0); } m->put(); return 0; } m->set_header(header); m->set_footer(footer); m->set_payload(front); m->set_middle(middle); m->set_data(data); try { m->decode_payload(); } catch (const buffer::error &e) { if (cct) { lderr(cct) << "failed to decode message of type " << type << " v" << header.version << ": " << e.what() << dendl; ldout(cct, 30) << "dump: \n"; m->get_payload().hexdump(*_dout); *_dout << dendl; if (cct->_conf->ms_die_on_bad_msg) assert(0); } m->put(); return 0; } // done! return m; } // This routine is not used for ordinary messages, but only when encapsulating a message // for forwarding and routing. It's also used in a backward compatibility test, which only // effectively tests backward compability for those functions. To avoid backward compatibility // problems, we currently always encode and decode using the old footer format that doesn't // allow for message authentication. Eventually we should fix that. PLR void encode_message(Message *msg, uint64_t features, bufferlist& payload) { bufferlist front, middle, data; ceph_msg_footer_old old_footer; ceph_msg_footer footer; msg->encode(features, true); ::encode(msg->get_header(), payload); // Here's where we switch to the old footer format. PLR footer = msg->get_footer(); old_footer.front_crc = footer.front_crc; old_footer.middle_crc = footer.middle_crc; old_footer.data_crc = footer.data_crc; old_footer.flags = footer.flags; ::encode(old_footer, payload); ::encode(msg->get_payload(), payload); ::encode(msg->get_middle(), payload); ::encode(msg->get_data(), payload); } // See above for somewhat bogus use of the old message footer. We switch to the current footer // after decoding the old one so the other form of decode_message() doesn't have to change. // We've slipped in a 0 signature at this point, so any signature checking after this will // fail. PLR Message *decode_message(CephContext *cct, bufferlist::iterator& p) { ceph_msg_header h; ceph_msg_footer_old fo; ceph_msg_footer f; bufferlist fr, mi, da; ::decode(h, p); ::decode(fo, p); f.front_crc = fo.front_crc; f.middle_crc = fo.middle_crc; f.data_crc = fo.data_crc; f.flags = fo.flags; f.sig = 0; ::decode(fr, p); ::decode(mi, p); ::decode(da, p); return decode_message(cct, h, f, fr, mi, da); } ceph-0.80.11/src/msg/Pipe.cc0000664000175100017510000021475312623076744017472 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include "Message.h" #include "Pipe.h" #include "SimpleMessenger.h" #include "common/debug.h" #include "common/errno.h" // Below included to get encode_encrypt(); That probably should be in Crypto.h, instead #include "auth/Crypto.h" #include "auth/cephx/CephxProtocol.h" #include "auth/AuthSessionHandler.h" // Constant to limit starting sequence number to 2^31. Nothing special about it, just a big number. PLR #define SEQ_MASK 0x7fffffff #define dout_subsys ceph_subsys_ms #undef dout_prefix #define dout_prefix _pipe_prefix(_dout) ostream& Pipe::_pipe_prefix(std::ostream *_dout) { return *_dout << "-- " << msgr->get_myinst().addr << " >> " << peer_addr << " pipe(" << this << " sd=" << sd << " :" << port << " s=" << state << " pgs=" << peer_global_seq << " cs=" << connect_seq << " l=" << policy.lossy << " c=" << connection_state << ")."; } /* * This optimization may not be available on all platforms (e.g. OSX). * Apparently a similar approach based on TCP_CORK can be used. */ #ifndef MSG_MORE # define MSG_MORE 0 #endif /* * On BSD SO_NOSIGPIPE can be set via setsockopt to block SIGPIPE. */ #ifndef MSG_NOSIGNAL # define MSG_NOSIGNAL 0 # ifdef SO_NOSIGPIPE # define CEPH_USE_SO_NOSIGPIPE # else # error "Cannot block SIGPIPE!" # endif #endif /************************************** * Pipe */ Pipe::Pipe(SimpleMessenger *r, int st, Connection *con) : reader_thread(this), writer_thread(this), delay_thread(NULL), msgr(r), conn_id(r->dispatch_queue.get_id()), sd(-1), port(0), peer_type(-1), pipe_lock("SimpleMessenger::Pipe::pipe_lock"), state(st), connection_state(NULL), reader_running(false), reader_needs_join(false), writer_running(false), in_q(&(r->dispatch_queue)), send_keepalive(false), send_keepalive_ack(false), close_on_empty(false), connect_seq(0), peer_global_seq(0), out_seq(0), in_seq(0), in_seq_acked(0) { if (con) { connection_state = con; connection_state->reset_pipe(this); } else { connection_state = new Connection(msgr); connection_state->pipe = get(); } if (randomize_out_seq()) { lsubdout(msgr->cct,ms,15) << "Pipe(): Could not get random bytes to set seq number for session reset; set seq number to " << out_seq << dendl; } msgr->timeout = msgr->cct->_conf->ms_tcp_read_timeout * 1000; //convert to ms if (msgr->timeout == 0) msgr->timeout = -1; } Pipe::~Pipe() { assert(out_q.empty()); assert(sent.empty()); delete delay_thread; } void Pipe::handle_ack(uint64_t seq) { lsubdout(msgr->cct, ms, 15) << "reader got ack seq " << seq << dendl; // trim sent list while (!sent.empty() && sent.front()->get_seq() <= seq) { Message *m = sent.front(); sent.pop_front(); lsubdout(msgr->cct, ms, 10) << "reader got ack seq " << seq << " >= " << m->get_seq() << " on " << m << " " << *m << dendl; m->put(); } if (sent.empty() && close_on_empty) { lsubdout(msgr->cct, ms, 10) << "reader got last ack, queue empty, closing" << dendl; stop(); } } void Pipe::start_reader() { assert(pipe_lock.is_locked()); assert(!reader_running); if (reader_needs_join) { reader_thread.join(); reader_needs_join = false; } reader_running = true; reader_thread.create(msgr->cct->_conf->ms_rwthread_stack_bytes); } void Pipe::maybe_start_delay_thread() { if (!delay_thread && msgr->cct->_conf->ms_inject_delay_type.find(ceph_entity_type_name(connection_state->peer_type)) != string::npos) { lsubdout(msgr->cct, ms, 1) << "setting up a delay queue on Pipe " << this << dendl; delay_thread = new DelayedDelivery(this); delay_thread->create(); } } void Pipe::start_writer() { assert(pipe_lock.is_locked()); assert(!writer_running); writer_running = true; writer_thread.create(msgr->cct->_conf->ms_rwthread_stack_bytes); } void Pipe::join_reader() { if (!reader_running) return; cond.Signal(); pipe_lock.Unlock(); reader_thread.join(); pipe_lock.Lock(); reader_needs_join = false; } void Pipe::DelayedDelivery::discard() { lgeneric_subdout(pipe->msgr->cct, ms, 20) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::discard" << dendl; Mutex::Locker l(delay_lock); while (!delay_queue.empty()) { Message *m = delay_queue.front().second; pipe->msgr->dispatch_throttle_release(m->get_dispatch_throttle_size()); m->put(); delay_queue.pop_front(); } } void Pipe::DelayedDelivery::flush() { lgeneric_subdout(pipe->msgr->cct, ms, 20) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::flush" << dendl; Mutex::Locker l(delay_lock); while (!delay_queue.empty()) { Message *m = delay_queue.front().second; delay_queue.pop_front(); pipe->in_q->enqueue(m, m->get_priority(), pipe->conn_id); } } void *Pipe::DelayedDelivery::entry() { Mutex::Locker locker(delay_lock); lgeneric_subdout(pipe->msgr->cct, ms, 20) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::entry start" << dendl; while (!stop_delayed_delivery) { if (delay_queue.empty()) { lgeneric_subdout(pipe->msgr->cct, ms, 30) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::entry sleeping on delay_cond because delay queue is empty" << dendl; delay_cond.Wait(delay_lock); continue; } utime_t release = delay_queue.front().first; Message *m = delay_queue.front().second; string delay_msg_type = pipe->msgr->cct->_conf->ms_inject_delay_msg_type; if (release > ceph_clock_now(pipe->msgr->cct) && (delay_msg_type.empty() || m->get_type_name() == delay_msg_type)) { lgeneric_subdout(pipe->msgr->cct, ms, 10) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::entry sleeping on delay_cond until " << release << dendl; delay_cond.WaitUntil(delay_lock, release); continue; } lgeneric_subdout(pipe->msgr->cct, ms, 10) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::entry dequeuing message " << m << " for delivery, past " << release << dendl; delay_queue.pop_front(); pipe->in_q->enqueue(m, m->get_priority(), pipe->conn_id); } lgeneric_subdout(pipe->msgr->cct, ms, 20) << pipe->_pipe_prefix(_dout) << "DelayedDelivery::entry stop" << dendl; return NULL; } int Pipe::accept() { ldout(msgr->cct,10) << "accept" << dendl; assert(pipe_lock.is_locked()); assert(state == STATE_ACCEPTING); pipe_lock.Unlock(); // vars bufferlist addrs; entity_addr_t socket_addr; socklen_t len; int r; char banner[strlen(CEPH_BANNER)+1]; bufferlist addrbl; ceph_msg_connect connect; ceph_msg_connect_reply reply; Pipe *existing = 0; bufferptr bp; bufferlist authorizer, authorizer_reply; bool authorizer_valid; uint64_t feat_missing; bool replaced = false; // this variable denotes if the connection attempt from peer is a hard // reset or not, it is true if there is an existing connection and the // connection sequence from peer is equal to zero bool is_reset_from_peer = false; CryptoKey session_key; int removed; // single-use down below // this should roughly mirror pseudocode at // http://ceph.newdream.net/wiki/Messaging_protocol int reply_tag = 0; uint64_t existing_seq = -1; // used for reading in the remote acked seq on connect uint64_t newly_acked_seq = 0; set_socket_options(); // announce myself. r = tcp_write(CEPH_BANNER, strlen(CEPH_BANNER)); if (r < 0) { ldout(msgr->cct,10) << "accept couldn't write banner" << dendl; goto fail_unlocked; } // and my addr ::encode(msgr->my_inst.addr, addrs); port = msgr->my_inst.addr.get_port(); // and peer's socket addr (they might not know their ip) len = sizeof(socket_addr.ss_addr()); r = ::getpeername(sd, (sockaddr*)&socket_addr.ss_addr(), &len); if (r < 0) { ldout(msgr->cct,0) << "accept failed to getpeername " << cpp_strerror(errno) << dendl; goto fail_unlocked; } ::encode(socket_addr, addrs); r = tcp_write(addrs.c_str(), addrs.length()); if (r < 0) { ldout(msgr->cct,10) << "accept couldn't write my+peer addr" << dendl; goto fail_unlocked; } ldout(msgr->cct,1) << "accept sd=" << sd << " " << socket_addr << dendl; // identify peer if (tcp_read(banner, strlen(CEPH_BANNER)) < 0) { ldout(msgr->cct,10) << "accept couldn't read banner" << dendl; goto fail_unlocked; } if (memcmp(banner, CEPH_BANNER, strlen(CEPH_BANNER))) { banner[strlen(CEPH_BANNER)] = 0; ldout(msgr->cct,1) << "accept peer sent bad banner '" << banner << "' (should be '" << CEPH_BANNER << "')" << dendl; goto fail_unlocked; } { bufferptr tp(sizeof(peer_addr)); addrbl.push_back(tp); } if (tcp_read(addrbl.c_str(), addrbl.length()) < 0) { ldout(msgr->cct,10) << "accept couldn't read peer_addr" << dendl; goto fail_unlocked; } { bufferlist::iterator ti = addrbl.begin(); ::decode(peer_addr, ti); } ldout(msgr->cct,10) << "accept peer addr is " << peer_addr << dendl; if (peer_addr.is_blank_ip()) { // peer apparently doesn't know what ip they have; figure it out for them. int port = peer_addr.get_port(); peer_addr.addr = socket_addr.addr; peer_addr.set_port(port); ldout(msgr->cct,0) << "accept peer addr is really " << peer_addr << " (socket is " << socket_addr << ")" << dendl; } set_peer_addr(peer_addr); // so that connection_state gets set up while (1) { if (tcp_read((char*)&connect, sizeof(connect)) < 0) { ldout(msgr->cct,10) << "accept couldn't read connect" << dendl; goto fail_unlocked; } // sanitize features connect.features = ceph_sanitize_features(connect.features); authorizer.clear(); if (connect.authorizer_len) { bp = buffer::create(connect.authorizer_len); if (tcp_read(bp.c_str(), connect.authorizer_len) < 0) { ldout(msgr->cct,10) << "accept couldn't read connect authorizer" << dendl; goto fail_unlocked; } authorizer.push_back(bp); authorizer_reply.clear(); } ldout(msgr->cct,20) << "accept got peer connect_seq " << connect.connect_seq << " global_seq " << connect.global_seq << dendl; msgr->lock.Lock(); // FIXME pipe_lock.Lock(); if (msgr->dispatch_queue.stop) goto shutting_down; if (state != STATE_ACCEPTING) { goto shutting_down; } // note peer's type, flags set_peer_type(connect.host_type); policy = msgr->get_policy(connect.host_type); ldout(msgr->cct,10) << "accept of host_type " << connect.host_type << ", policy.lossy=" << policy.lossy << " policy.server=" << policy.server << " policy.standby=" << policy.standby << " policy.resetcheck=" << policy.resetcheck << dendl; memset(&reply, 0, sizeof(reply)); reply.protocol_version = msgr->get_proto_version(peer_type, false); msgr->lock.Unlock(); // mismatch? ldout(msgr->cct,10) << "accept my proto " << reply.protocol_version << ", their proto " << connect.protocol_version << dendl; if (connect.protocol_version != reply.protocol_version) { reply.tag = CEPH_MSGR_TAG_BADPROTOVER; goto reply; } // require signatures for cephx? if (connect.authorizer_protocol == CEPH_AUTH_CEPHX) { if (peer_type == CEPH_ENTITY_TYPE_OSD || peer_type == CEPH_ENTITY_TYPE_MDS) { if (msgr->cct->_conf->cephx_require_signatures || msgr->cct->_conf->cephx_cluster_require_signatures) { ldout(msgr->cct,10) << "using cephx, requiring MSG_AUTH feature bit for cluster" << dendl; policy.features_required |= CEPH_FEATURE_MSG_AUTH; } } else { if (msgr->cct->_conf->cephx_require_signatures || msgr->cct->_conf->cephx_service_require_signatures) { ldout(msgr->cct,10) << "using cephx, requiring MSG_AUTH feature bit for service" << dendl; policy.features_required |= CEPH_FEATURE_MSG_AUTH; } } } feat_missing = policy.features_required & ~(uint64_t)connect.features; if (feat_missing) { ldout(msgr->cct,1) << "peer missing required features " << std::hex << feat_missing << std::dec << dendl; reply.tag = CEPH_MSGR_TAG_FEATURES; goto reply; } // Check the authorizer. If not good, bail out. pipe_lock.Unlock(); if (!msgr->verify_authorizer(connection_state.get(), peer_type, connect.authorizer_protocol, authorizer, authorizer_reply, authorizer_valid, session_key) || !authorizer_valid) { ldout(msgr->cct,0) << "accept: got bad authorizer" << dendl; pipe_lock.Lock(); if (state != STATE_ACCEPTING) goto shutting_down_msgr_unlocked; reply.tag = CEPH_MSGR_TAG_BADAUTHORIZER; session_security.reset(); goto reply; } // We've verified the authorizer for this pipe, so set up the session security structure. PLR ldout(msgr->cct,10) << "accept: setting up session_security." << dendl; msgr->lock.Lock(); pipe_lock.Lock(); if (msgr->dispatch_queue.stop) goto shutting_down; if (state != STATE_ACCEPTING) goto shutting_down; // existing? existing = msgr->_lookup_pipe(peer_addr); if (existing) { existing->pipe_lock.Lock(true); // skip lockdep check (we are locking a second Pipe here) if (connect.global_seq < existing->peer_global_seq) { ldout(msgr->cct,10) << "accept existing " << existing << ".gseq " << existing->peer_global_seq << " > " << connect.global_seq << ", RETRY_GLOBAL" << dendl; reply.tag = CEPH_MSGR_TAG_RETRY_GLOBAL; reply.global_seq = existing->peer_global_seq; // so we can send it below.. existing->pipe_lock.Unlock(); msgr->lock.Unlock(); goto reply; } else { ldout(msgr->cct,10) << "accept existing " << existing << ".gseq " << existing->peer_global_seq << " <= " << connect.global_seq << ", looks ok" << dendl; } if (existing->policy.lossy) { ldout(msgr->cct,0) << "accept replacing existing (lossy) channel (new one lossy=" << policy.lossy << ")" << dendl; existing->was_session_reset(); goto replace; } ldout(msgr->cct,0) << "accept connect_seq " << connect.connect_seq << " vs existing " << existing->connect_seq << " state " << existing->get_state_name() << dendl; if (connect.connect_seq == 0 && existing->connect_seq > 0) { ldout(msgr->cct,0) << "accept peer reset, then tried to connect to us, replacing" << dendl; // this is a hard reset from peer is_reset_from_peer = true; if (policy.resetcheck) existing->was_session_reset(); // this resets out_queue, msg_ and connect_seq #'s goto replace; } if (connect.connect_seq < existing->connect_seq) { // old attempt, or we sent READY but they didn't get it. ldout(msgr->cct,10) << "accept existing " << existing << ".cseq " << existing->connect_seq << " > " << connect.connect_seq << ", RETRY_SESSION" << dendl; goto retry_session; } if (connect.connect_seq == existing->connect_seq) { // if the existing connection successfully opened, and/or // subsequently went to standby, then the peer should bump // their connect_seq and retry: this is not a connection race // we need to resolve here. if (existing->state == STATE_OPEN || existing->state == STATE_STANDBY) { ldout(msgr->cct,10) << "accept connection race, existing " << existing << ".cseq " << existing->connect_seq << " == " << connect.connect_seq << ", OPEN|STANDBY, RETRY_SESSION" << dendl; goto retry_session; } // connection race? if (peer_addr < msgr->my_inst.addr || existing->policy.server) { // incoming wins ldout(msgr->cct,10) << "accept connection race, existing " << existing << ".cseq " << existing->connect_seq << " == " << connect.connect_seq << ", or we are server, replacing my attempt" << dendl; if (!(existing->state == STATE_CONNECTING || existing->state == STATE_WAIT)) lderr(msgr->cct) << "accept race bad state, would replace, existing=" << existing->get_state_name() << " " << existing << ".cseq=" << existing->connect_seq << " == " << connect.connect_seq << dendl; assert(existing->state == STATE_CONNECTING || existing->state == STATE_WAIT); goto replace; } else { // our existing outgoing wins ldout(msgr->cct,10) << "accept connection race, existing " << existing << ".cseq " << existing->connect_seq << " == " << connect.connect_seq << ", sending WAIT" << dendl; assert(peer_addr > msgr->my_inst.addr); if (!(existing->state == STATE_CONNECTING)) lderr(msgr->cct) << "accept race bad state, would send wait, existing=" << existing->get_state_name() << " " << existing << ".cseq=" << existing->connect_seq << " == " << connect.connect_seq << dendl; assert(existing->state == STATE_CONNECTING); // make sure our outgoing connection will follow through existing->_send_keepalive(); reply.tag = CEPH_MSGR_TAG_WAIT; existing->pipe_lock.Unlock(); msgr->lock.Unlock(); goto reply; } } assert(connect.connect_seq > existing->connect_seq); assert(connect.global_seq >= existing->peer_global_seq); if (policy.resetcheck && // RESETSESSION only used by servers; peers do not reset each other existing->connect_seq == 0) { ldout(msgr->cct,0) << "accept we reset (peer sent cseq " << connect.connect_seq << ", " << existing << ".cseq = " << existing->connect_seq << "), sending RESETSESSION" << dendl; reply.tag = CEPH_MSGR_TAG_RESETSESSION; msgr->lock.Unlock(); existing->pipe_lock.Unlock(); goto reply; } // reconnect ldout(msgr->cct,10) << "accept peer sent cseq " << connect.connect_seq << " > " << existing->connect_seq << dendl; goto replace; } // existing else if (connect.connect_seq > 0) { // we reset, and they are opening a new session ldout(msgr->cct,0) << "accept we reset (peer sent cseq " << connect.connect_seq << "), sending RESETSESSION" << dendl; msgr->lock.Unlock(); reply.tag = CEPH_MSGR_TAG_RESETSESSION; goto reply; } else { // new session ldout(msgr->cct,10) << "accept new session" << dendl; existing = NULL; goto open; } assert(0); retry_session: assert(existing->pipe_lock.is_locked()); assert(pipe_lock.is_locked()); reply.tag = CEPH_MSGR_TAG_RETRY_SESSION; reply.connect_seq = existing->connect_seq + 1; existing->pipe_lock.Unlock(); msgr->lock.Unlock(); goto reply; reply: assert(pipe_lock.is_locked()); reply.features = ((uint64_t)connect.features & policy.features_supported) | policy.features_required; reply.authorizer_len = authorizer_reply.length(); pipe_lock.Unlock(); r = tcp_write((char*)&reply, sizeof(reply)); if (r < 0) goto fail_unlocked; if (reply.authorizer_len) { r = tcp_write(authorizer_reply.c_str(), authorizer_reply.length()); if (r < 0) goto fail_unlocked; } } replace: assert(existing->pipe_lock.is_locked()); assert(pipe_lock.is_locked()); // if it is a hard reset from peer, we don't need a round-trip to negotiate in/out sequence if ((connect.features & CEPH_FEATURE_RECONNECT_SEQ) && !is_reset_from_peer) { reply_tag = CEPH_MSGR_TAG_SEQ; existing_seq = existing->in_seq; } ldout(msgr->cct,10) << "accept replacing " << existing << dendl; existing->stop(); existing->unregister_pipe(); replaced = true; if (existing->policy.lossy) { // disconnect from the Connection assert(existing->connection_state); if (existing->connection_state->clear_pipe(existing)) msgr->dispatch_queue.queue_reset(existing->connection_state.get()); } else { // queue a reset on the old connection msgr->dispatch_queue.queue_reset(connection_state.get()); // drop my Connection, and take a ref to the existing one. do not // clear existing->connection_state, since read_message and // write_message both dereference it without pipe_lock. connection_state = existing->connection_state; // make existing Connection reference us connection_state->reset_pipe(this); // flush/queue any existing delayed messages if (existing->delay_thread) existing->delay_thread->flush(); // steal incoming queue uint64_t replaced_conn_id = conn_id; conn_id = existing->conn_id; existing->conn_id = replaced_conn_id; // reset the in_seq if this is a hard reset from peer, // otherwise we respect our original connection's value in_seq = is_reset_from_peer ? 0 : existing->in_seq; in_seq_acked = in_seq; // steal outgoing queue and out_seq existing->requeue_sent(); out_seq = existing->out_seq; ldout(msgr->cct,10) << "accept re-queuing on out_seq " << out_seq << " in_seq " << in_seq << dendl; for (map >::iterator p = existing->out_q.begin(); p != existing->out_q.end(); ++p) out_q[p->first].splice(out_q[p->first].begin(), p->second); } existing->pipe_lock.Unlock(); open: // open assert(pipe_lock.is_locked()); connect_seq = connect.connect_seq + 1; peer_global_seq = connect.global_seq; assert(state == STATE_ACCEPTING); state = STATE_OPEN; ldout(msgr->cct,10) << "accept success, connect_seq = " << connect_seq << ", sending READY" << dendl; // send READY reply reply.tag = (reply_tag ? reply_tag : CEPH_MSGR_TAG_READY); reply.features = policy.features_supported; reply.global_seq = msgr->get_global_seq(); reply.connect_seq = connect_seq; reply.flags = 0; reply.authorizer_len = authorizer_reply.length(); if (policy.lossy) reply.flags = reply.flags | CEPH_MSG_CONNECT_LOSSY; connection_state->set_features((uint64_t)reply.features & (uint64_t)connect.features); ldout(msgr->cct,10) << "accept features " << connection_state->get_features() << dendl; session_security.reset( get_auth_session_handler(msgr->cct, connect.authorizer_protocol, session_key, connection_state->get_features())); // notify msgr->dispatch_queue.queue_accept(connection_state.get()); // ok! if (msgr->dispatch_queue.stop) goto shutting_down; removed = msgr->accepting_pipes.erase(this); assert(removed == 1); register_pipe(); msgr->lock.Unlock(); pipe_lock.Unlock(); r = tcp_write((char*)&reply, sizeof(reply)); if (r < 0) { goto fail_registered; } if (reply.authorizer_len) { r = tcp_write(authorizer_reply.c_str(), authorizer_reply.length()); if (r < 0) { goto fail_registered; } } if (reply_tag == CEPH_MSGR_TAG_SEQ) { if (tcp_write((char*)&existing_seq, sizeof(existing_seq)) < 0) { ldout(msgr->cct,2) << "accept write error on in_seq" << dendl; goto fail_registered; } if (tcp_read((char*)&newly_acked_seq, sizeof(newly_acked_seq)) < 0) { ldout(msgr->cct,2) << "accept read error on newly_acked_seq" << dendl; goto fail_registered; } } pipe_lock.Lock(); discard_requeued_up_to(newly_acked_seq); if (state != STATE_CLOSED) { ldout(msgr->cct,10) << "accept starting writer, state " << get_state_name() << dendl; start_writer(); } ldout(msgr->cct,20) << "accept done" << dendl; maybe_start_delay_thread(); return 0; // success. fail_registered: ldout(msgr->cct, 10) << "accept fault after register" << dendl; if (msgr->cct->_conf->ms_inject_internal_delays) { ldout(msgr->cct, 10) << " sleep for " << msgr->cct->_conf->ms_inject_internal_delays << dendl; utime_t t; t.set_from_double(msgr->cct->_conf->ms_inject_internal_delays); t.sleep(); } fail_unlocked: pipe_lock.Lock(); if (state != STATE_CLOSED) { bool queued = is_queued(); ldout(msgr->cct, 10) << " queued = " << (int)queued << dendl; if (queued) { state = policy.server ? STATE_STANDBY : STATE_CONNECTING; } else if (replaced) { state = STATE_STANDBY; } else { state = STATE_CLOSED; state_closed.set(1); } fault(); if (queued || replaced) start_writer(); } return -1; shutting_down: msgr->lock.Unlock(); shutting_down_msgr_unlocked: assert(pipe_lock.is_locked()); if (msgr->cct->_conf->ms_inject_internal_delays) { ldout(msgr->cct, 10) << " sleep for " << msgr->cct->_conf->ms_inject_internal_delays << dendl; utime_t t; t.set_from_double(msgr->cct->_conf->ms_inject_internal_delays); t.sleep(); } state = STATE_CLOSED; state_closed.set(1); fault(); return -1; } void Pipe::set_socket_options() { // disable Nagle algorithm? if (msgr->cct->_conf->ms_tcp_nodelay) { int flag = 1; int r = ::setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)); if (r < 0) { r = -errno; ldout(msgr->cct,0) << "couldn't set TCP_NODELAY: " << cpp_strerror(r) << dendl; } } if (msgr->cct->_conf->ms_tcp_rcvbuf) { int size = msgr->cct->_conf->ms_tcp_rcvbuf; int r = ::setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void*)&size, sizeof(size)); if (r < 0) { r = -errno; ldout(msgr->cct,0) << "couldn't set SO_RCVBUF to " << size << ": " << cpp_strerror(r) << dendl; } } // block ESIGPIPE #ifdef CEPH_USE_SO_NOSIGPIPE int val = 1; int r = ::setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)); if (r) { r = -errno; ldout(msgr->cct,0) << "couldn't set SO_NOSIGPIPE: " << cpp_strerror(r) << dendl; } #endif } int Pipe::connect() { bool got_bad_auth = false; ldout(msgr->cct,10) << "connect " << connect_seq << dendl; assert(pipe_lock.is_locked()); __u32 cseq = connect_seq; __u32 gseq = msgr->get_global_seq(); // stop reader thrad join_reader(); pipe_lock.Unlock(); char tag = -1; int rc; struct msghdr msg; struct iovec msgvec[2]; int msglen; char banner[strlen(CEPH_BANNER) + 1]; // extra byte makes coverity happy entity_addr_t paddr; entity_addr_t peer_addr_for_me, socket_addr; AuthAuthorizer *authorizer = NULL; bufferlist addrbl, myaddrbl; const md_config_t *conf = msgr->cct->_conf; // close old socket. this is safe because we stopped the reader thread above. if (sd >= 0) ::close(sd); // create socket? sd = ::socket(peer_addr.get_family(), SOCK_STREAM, 0); if (sd < 0) { lderr(msgr->cct) << "connect couldn't created socket " << cpp_strerror(errno) << dendl; goto fail; } // connect! ldout(msgr->cct,10) << "connecting to " << peer_addr << dendl; rc = ::connect(sd, (sockaddr*)&peer_addr.addr, peer_addr.addr_size()); if (rc < 0) { ldout(msgr->cct,2) << "connect error " << peer_addr << ", " << cpp_strerror(errno) << dendl; goto fail; } set_socket_options(); // verify banner // FIXME: this should be non-blocking, or in some other way verify the banner as we get it. if (tcp_read((char*)&banner, strlen(CEPH_BANNER)) < 0) { ldout(msgr->cct,2) << "connect couldn't read banner, " << cpp_strerror(errno) << dendl; goto fail; } if (memcmp(banner, CEPH_BANNER, strlen(CEPH_BANNER))) { ldout(msgr->cct,0) << "connect protocol error (bad banner) on peer " << paddr << dendl; goto fail; } memset(&msg, 0, sizeof(msg)); msgvec[0].iov_base = banner; msgvec[0].iov_len = strlen(CEPH_BANNER); msg.msg_iov = msgvec; msg.msg_iovlen = 1; msglen = msgvec[0].iov_len; if (do_sendmsg(&msg, msglen)) { ldout(msgr->cct,2) << "connect couldn't write my banner, " << cpp_strerror(errno) << dendl; goto fail; } // identify peer { bufferptr p(sizeof(paddr) * 2); addrbl.push_back(p); } if (tcp_read(addrbl.c_str(), addrbl.length()) < 0) { ldout(msgr->cct,2) << "connect couldn't read peer addrs, " << cpp_strerror(errno) << dendl; goto fail; } { bufferlist::iterator p = addrbl.begin(); ::decode(paddr, p); ::decode(peer_addr_for_me, p); port = peer_addr_for_me.get_port(); } ldout(msgr->cct,20) << "connect read peer addr " << paddr << " on socket " << sd << dendl; if (peer_addr != paddr) { if (paddr.is_blank_ip() && peer_addr.get_port() == paddr.get_port() && peer_addr.get_nonce() == paddr.get_nonce()) { ldout(msgr->cct,0) << "connect claims to be " << paddr << " not " << peer_addr << " - presumably this is the same node!" << dendl; } else { ldout(msgr->cct,0) << "connect claims to be " << paddr << " not " << peer_addr << " - wrong node!" << dendl; goto fail; } } ldout(msgr->cct,20) << "connect peer addr for me is " << peer_addr_for_me << dendl; msgr->learned_addr(peer_addr_for_me); ::encode(msgr->my_inst.addr, myaddrbl); memset(&msg, 0, sizeof(msg)); msgvec[0].iov_base = myaddrbl.c_str(); msgvec[0].iov_len = myaddrbl.length(); msg.msg_iov = msgvec; msg.msg_iovlen = 1; msglen = msgvec[0].iov_len; if (do_sendmsg(&msg, msglen)) { ldout(msgr->cct,2) << "connect couldn't write my addr, " << cpp_strerror(errno) << dendl; goto fail; } ldout(msgr->cct,10) << "connect sent my addr " << msgr->my_inst.addr << dendl; while (1) { delete authorizer; authorizer = msgr->get_authorizer(peer_type, false); bufferlist authorizer_reply; ceph_msg_connect connect; connect.features = policy.features_supported; connect.host_type = msgr->my_type; connect.global_seq = gseq; connect.connect_seq = cseq; connect.protocol_version = msgr->get_proto_version(peer_type, true); connect.authorizer_protocol = authorizer ? authorizer->protocol : 0; connect.authorizer_len = authorizer ? authorizer->bl.length() : 0; if (authorizer) ldout(msgr->cct,10) << "connect.authorizer_len=" << connect.authorizer_len << " protocol=" << connect.authorizer_protocol << dendl; connect.flags = 0; if (policy.lossy) connect.flags |= CEPH_MSG_CONNECT_LOSSY; // this is fyi, actually, server decides! memset(&msg, 0, sizeof(msg)); msgvec[0].iov_base = (char*)&connect; msgvec[0].iov_len = sizeof(connect); msg.msg_iov = msgvec; msg.msg_iovlen = 1; msglen = msgvec[0].iov_len; if (authorizer) { msgvec[1].iov_base = authorizer->bl.c_str(); msgvec[1].iov_len = authorizer->bl.length(); msg.msg_iovlen++; msglen += msgvec[1].iov_len; } ldout(msgr->cct,10) << "connect sending gseq=" << gseq << " cseq=" << cseq << " proto=" << connect.protocol_version << dendl; if (do_sendmsg(&msg, msglen)) { ldout(msgr->cct,2) << "connect couldn't write gseq, cseq, " << cpp_strerror(errno) << dendl; goto fail; } ldout(msgr->cct,20) << "connect wrote (self +) cseq, waiting for reply" << dendl; ceph_msg_connect_reply reply; if (tcp_read((char*)&reply, sizeof(reply)) < 0) { ldout(msgr->cct,2) << "connect read reply " << cpp_strerror(errno) << dendl; goto fail; } // sanitize features reply.features = ceph_sanitize_features(reply.features); ldout(msgr->cct,20) << "connect got reply tag " << (int)reply.tag << " connect_seq " << reply.connect_seq << " global_seq " << reply.global_seq << " proto " << reply.protocol_version << " flags " << (int)reply.flags << " features " << reply.features << dendl; authorizer_reply.clear(); if (reply.authorizer_len) { ldout(msgr->cct,10) << "reply.authorizer_len=" << reply.authorizer_len << dendl; bufferptr bp = buffer::create(reply.authorizer_len); if (tcp_read(bp.c_str(), reply.authorizer_len) < 0) { ldout(msgr->cct,10) << "connect couldn't read connect authorizer_reply" << dendl; goto fail; } authorizer_reply.push_back(bp); } if (authorizer) { bufferlist::iterator iter = authorizer_reply.begin(); if (!authorizer->verify_reply(iter)) { ldout(msgr->cct,0) << "failed verifying authorize reply" << dendl; goto fail; } } if (conf->ms_inject_internal_delays) { ldout(msgr->cct, 10) << " sleep for " << msgr->cct->_conf->ms_inject_internal_delays << dendl; utime_t t; t.set_from_double(msgr->cct->_conf->ms_inject_internal_delays); t.sleep(); } pipe_lock.Lock(); if (state != STATE_CONNECTING) { ldout(msgr->cct,0) << "connect got RESETSESSION but no longer connecting" << dendl; goto stop_locked; } if (reply.tag == CEPH_MSGR_TAG_FEATURES) { ldout(msgr->cct,0) << "connect protocol feature mismatch, my " << std::hex << connect.features << " < peer " << reply.features << " missing " << (reply.features & ~policy.features_supported) << std::dec << dendl; goto fail_locked; } if (reply.tag == CEPH_MSGR_TAG_BADPROTOVER) { ldout(msgr->cct,0) << "connect protocol version mismatch, my " << connect.protocol_version << " != " << reply.protocol_version << dendl; goto fail_locked; } if (reply.tag == CEPH_MSGR_TAG_BADAUTHORIZER) { ldout(msgr->cct,0) << "connect got BADAUTHORIZER" << dendl; if (got_bad_auth) goto stop_locked; got_bad_auth = true; pipe_lock.Unlock(); delete authorizer; authorizer = msgr->get_authorizer(peer_type, true); // try harder continue; } if (reply.tag == CEPH_MSGR_TAG_RESETSESSION) { ldout(msgr->cct,0) << "connect got RESETSESSION" << dendl; was_session_reset(); cseq = 0; pipe_lock.Unlock(); continue; } if (reply.tag == CEPH_MSGR_TAG_RETRY_GLOBAL) { gseq = msgr->get_global_seq(reply.global_seq); ldout(msgr->cct,10) << "connect got RETRY_GLOBAL " << reply.global_seq << " chose new " << gseq << dendl; pipe_lock.Unlock(); continue; } if (reply.tag == CEPH_MSGR_TAG_RETRY_SESSION) { assert(reply.connect_seq > connect_seq); ldout(msgr->cct,10) << "connect got RETRY_SESSION " << connect_seq << " -> " << reply.connect_seq << dendl; cseq = connect_seq = reply.connect_seq; pipe_lock.Unlock(); continue; } if (reply.tag == CEPH_MSGR_TAG_WAIT) { ldout(msgr->cct,3) << "connect got WAIT (connection race)" << dendl; state = STATE_WAIT; goto stop_locked; } if (reply.tag == CEPH_MSGR_TAG_READY || reply.tag == CEPH_MSGR_TAG_SEQ) { uint64_t feat_missing = policy.features_required & ~(uint64_t)reply.features; if (feat_missing) { ldout(msgr->cct,1) << "missing required features " << std::hex << feat_missing << std::dec << dendl; goto fail_locked; } if (reply.tag == CEPH_MSGR_TAG_SEQ) { ldout(msgr->cct,10) << "got CEPH_MSGR_TAG_SEQ, reading acked_seq and writing in_seq" << dendl; uint64_t newly_acked_seq = 0; if (tcp_read((char*)&newly_acked_seq, sizeof(newly_acked_seq)) < 0) { ldout(msgr->cct,2) << "connect read error on newly_acked_seq" << dendl; goto fail_locked; } ldout(msgr->cct,2) << " got newly_acked_seq " << newly_acked_seq << " vs out_seq " << out_seq << dendl; while (newly_acked_seq > out_seq) { Message *m = _get_next_outgoing(); assert(m); ldout(msgr->cct,2) << " discarding previously sent " << m->get_seq() << " " << *m << dendl; assert(m->get_seq() <= newly_acked_seq); m->put(); ++out_seq; } if (tcp_write((char*)&in_seq, sizeof(in_seq)) < 0) { ldout(msgr->cct,2) << "connect write error on in_seq" << dendl; goto fail_locked; } } // hooray! peer_global_seq = reply.global_seq; policy.lossy = reply.flags & CEPH_MSG_CONNECT_LOSSY; state = STATE_OPEN; connect_seq = cseq + 1; assert(connect_seq == reply.connect_seq); backoff = utime_t(); connection_state->set_features((uint64_t)reply.features & (uint64_t)connect.features); ldout(msgr->cct,10) << "connect success " << connect_seq << ", lossy = " << policy.lossy << ", features " << connection_state->get_features() << dendl; // If we have an authorizer, get a new AuthSessionHandler to deal with ongoing security of the // connection. PLR if (authorizer != NULL) { session_security.reset( get_auth_session_handler(msgr->cct, authorizer->protocol, authorizer->session_key, connection_state->get_features())); } else { // We have no authorizer, so we shouldn't be applying security to messages in this pipe. PLR session_security.reset(); } msgr->dispatch_queue.queue_connect(connection_state.get()); if (!reader_running) { ldout(msgr->cct,20) << "connect starting reader" << dendl; start_reader(); } maybe_start_delay_thread(); delete authorizer; return 0; } // protocol error ldout(msgr->cct,0) << "connect got bad tag " << (int)tag << dendl; goto fail_locked; } fail: if (conf->ms_inject_internal_delays) { ldout(msgr->cct, 10) << " sleep for " << msgr->cct->_conf->ms_inject_internal_delays << dendl; utime_t t; t.set_from_double(msgr->cct->_conf->ms_inject_internal_delays); t.sleep(); } pipe_lock.Lock(); fail_locked: if (state == STATE_CONNECTING) fault(); else ldout(msgr->cct,3) << "connect fault, but state = " << get_state_name() << " != connecting, stopping" << dendl; stop_locked: delete authorizer; return -1; } void Pipe::register_pipe() { ldout(msgr->cct,10) << "register_pipe" << dendl; assert(msgr->lock.is_locked()); Pipe *existing = msgr->_lookup_pipe(peer_addr); assert(existing == NULL); msgr->rank_pipe[peer_addr] = this; } void Pipe::unregister_pipe() { assert(msgr->lock.is_locked()); ceph::unordered_map::iterator p = msgr->rank_pipe.find(peer_addr); if (p != msgr->rank_pipe.end() && p->second == this) { ldout(msgr->cct,10) << "unregister_pipe" << dendl; msgr->rank_pipe.erase(p); } else { ldout(msgr->cct,10) << "unregister_pipe - not registered" << dendl; msgr->accepting_pipes.erase(this); // somewhat overkill, but safe. } } void Pipe::join() { ldout(msgr->cct, 20) << "join" << dendl; if (writer_thread.is_started()) writer_thread.join(); if (reader_thread.is_started()) reader_thread.join(); if (delay_thread) { ldout(msgr->cct, 20) << "joining delay_thread" << dendl; delay_thread->stop(); delay_thread->join(); } } void Pipe::requeue_sent() { if (sent.empty()) return; list& rq = out_q[CEPH_MSG_PRIO_HIGHEST]; while (!sent.empty()) { Message *m = sent.back(); sent.pop_back(); ldout(msgr->cct,10) << "requeue_sent " << *m << " for resend seq " << out_seq << " (" << m->get_seq() << ")" << dendl; rq.push_front(m); out_seq--; } } void Pipe::discard_requeued_up_to(uint64_t seq) { ldout(msgr->cct, 10) << "discard_requeued_up_to " << seq << dendl; if (out_q.count(CEPH_MSG_PRIO_HIGHEST) == 0) return; list& rq = out_q[CEPH_MSG_PRIO_HIGHEST]; while (!rq.empty()) { Message *m = rq.front(); if (m->get_seq() == 0 || m->get_seq() > seq) break; ldout(msgr->cct,10) << "discard_requeued_up_to " << *m << " for resend seq " << out_seq << " <= " << seq << ", discarding" << dendl; m->put(); rq.pop_front(); out_seq++; } if (rq.empty()) out_q.erase(CEPH_MSG_PRIO_HIGHEST); } /* * Tears down the Pipe's message queues, and removes them from the DispatchQueue * Must hold pipe_lock prior to calling. */ void Pipe::discard_out_queue() { ldout(msgr->cct,10) << "discard_queue" << dendl; for (list::iterator p = sent.begin(); p != sent.end(); ++p) { ldout(msgr->cct,20) << " discard " << *p << dendl; (*p)->put(); } sent.clear(); for (map >::iterator p = out_q.begin(); p != out_q.end(); ++p) for (list::iterator r = p->second.begin(); r != p->second.end(); ++r) { ldout(msgr->cct,20) << " discard " << *r << dendl; (*r)->put(); } out_q.clear(); } void Pipe::fault(bool onread) { const md_config_t *conf = msgr->cct->_conf; assert(pipe_lock.is_locked()); cond.Signal(); if (onread && state == STATE_CONNECTING) { ldout(msgr->cct,10) << "fault already connecting, reader shutting down" << dendl; return; } ldout(msgr->cct,2) << "fault " << cpp_strerror(errno) << dendl; if (state == STATE_CLOSED || state == STATE_CLOSING) { ldout(msgr->cct,10) << "fault already closed|closing" << dendl; if (connection_state->clear_pipe(this)) msgr->dispatch_queue.queue_reset(connection_state.get()); return; } shutdown_socket(); // lossy channel? if (policy.lossy && state != STATE_CONNECTING) { ldout(msgr->cct,10) << "fault on lossy channel, failing" << dendl; stop(); // crib locks, blech. note that Pipe is now STATE_CLOSED and the // rank_pipe entry is ignored by others. pipe_lock.Unlock(); if (conf->ms_inject_internal_delays) { ldout(msgr->cct, 10) << " sleep for " << msgr->cct->_conf->ms_inject_internal_delays << dendl; utime_t t; t.set_from_double(msgr->cct->_conf->ms_inject_internal_delays); t.sleep(); } msgr->lock.Lock(); pipe_lock.Lock(); unregister_pipe(); msgr->lock.Unlock(); in_q->discard_queue(conn_id); if (delay_thread) delay_thread->discard(); discard_out_queue(); // disconnect from Connection, and mark it failed. future messages // will be dropped. assert(connection_state); if (connection_state->clear_pipe(this)) msgr->dispatch_queue.queue_reset(connection_state.get()); return; } // queue delayed items immediately if (delay_thread) delay_thread->flush(); // requeue sent items requeue_sent(); if (policy.standby && !is_queued()) { ldout(msgr->cct,0) << "fault with nothing to send, going to standby" << dendl; state = STATE_STANDBY; return; } if (state != STATE_CONNECTING) { if (policy.server) { ldout(msgr->cct,0) << "fault, server, going to standby" << dendl; state = STATE_STANDBY; } else { ldout(msgr->cct,0) << "fault, initiating reconnect" << dendl; connect_seq++; state = STATE_CONNECTING; } backoff = utime_t(); } else if (backoff == utime_t()) { ldout(msgr->cct,0) << "fault" << dendl; backoff.set_from_double(conf->ms_initial_backoff); } else { ldout(msgr->cct,10) << "fault waiting " << backoff << dendl; cond.WaitInterval(msgr->cct, pipe_lock, backoff); backoff += backoff; if (backoff > conf->ms_max_backoff) backoff.set_from_double(conf->ms_max_backoff); ldout(msgr->cct,10) << "fault done waiting or woke up" << dendl; } } int Pipe::randomize_out_seq() { if (connection_state->get_features() & CEPH_FEATURE_MSG_AUTH) { // Set out_seq to a random value, so CRC won't be predictable. Don't bother checking seq_error // here. We'll check it on the call. PLR int seq_error = get_random_bytes((char *)&out_seq, sizeof(out_seq)); out_seq &= SEQ_MASK; lsubdout(msgr->cct, ms, 10) << "randomize_out_seq " << out_seq << dendl; return seq_error; } else { // previously, seq #'s always started at 0. out_seq = 0; return 0; } } void Pipe::was_session_reset() { assert(pipe_lock.is_locked()); ldout(msgr->cct,10) << "was_session_reset" << dendl; in_q->discard_queue(conn_id); if (delay_thread) delay_thread->discard(); discard_out_queue(); msgr->dispatch_queue.queue_remote_reset(connection_state.get()); if (randomize_out_seq()) { lsubdout(msgr->cct,ms,15) << "was_session_reset(): Could not get random bytes to set seq number for session reset; set seq number to " << out_seq << dendl; } in_seq = 0; connect_seq = 0; } void Pipe::stop() { ldout(msgr->cct,10) << "stop" << dendl; assert(pipe_lock.is_locked()); state = STATE_CLOSED; state_closed.set(1); cond.Signal(); shutdown_socket(); } /* read msgs from socket. * also, server. */ void Pipe::reader() { pipe_lock.Lock(); if (state == STATE_ACCEPTING) { accept(); assert(pipe_lock.is_locked()); } // loop. while (state != STATE_CLOSED && state != STATE_CONNECTING) { assert(pipe_lock.is_locked()); // sleep if (re)connecting if (state == STATE_STANDBY) { ldout(msgr->cct,20) << "reader sleeping during reconnect|standby" << dendl; cond.Wait(pipe_lock); continue; } // get a reference to the AuthSessionHandler while we have the pipe_lock ceph::shared_ptr auth_handler = session_security; pipe_lock.Unlock(); char tag = -1; ldout(msgr->cct,20) << "reader reading tag..." << dendl; if (tcp_read((char*)&tag, 1) < 0) { pipe_lock.Lock(); ldout(msgr->cct,2) << "reader couldn't read tag, " << cpp_strerror(errno) << dendl; fault(true); continue; } if (tag == CEPH_MSGR_TAG_KEEPALIVE) { ldout(msgr->cct,20) << "reader got KEEPALIVE" << dendl; pipe_lock.Lock(); continue; } if (tag == CEPH_MSGR_TAG_KEEPALIVE2) { ldout(msgr->cct,30) << "reader got KEEPALIVE2 tag ..." << dendl; ceph_timespec t; int rc = tcp_read((char*)&t, sizeof(t)); pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,2) << "reader couldn't read KEEPALIVE2 stamp " << cpp_strerror(errno) << dendl; fault(true); } else { send_keepalive_ack = true; keepalive_ack_stamp = utime_t(t); ldout(msgr->cct,20) << "reader got KEEPALIVE2 " << keepalive_ack_stamp << dendl; cond.Signal(); } continue; } if (tag == CEPH_MSGR_TAG_KEEPALIVE2_ACK) { ldout(msgr->cct,20) << "reader got KEEPALIVE_ACK" << dendl; struct ceph_timespec t; int rc = tcp_read((char*)&t, sizeof(t)); pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,2) << "reader couldn't read KEEPALIVE2 stamp " << cpp_strerror(errno) << dendl; fault(true); } else { connection_state->last_keepalive_ack = utime_t(t); } continue; } // open ... if (tag == CEPH_MSGR_TAG_ACK) { ldout(msgr->cct,20) << "reader got ACK" << dendl; ceph_le64 seq; int rc = tcp_read((char*)&seq, sizeof(seq)); pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,2) << "reader couldn't read ack seq, " << cpp_strerror(errno) << dendl; fault(true); } else if (state != STATE_CLOSED) { handle_ack(seq); } continue; } else if (tag == CEPH_MSGR_TAG_MSG) { ldout(msgr->cct,20) << "reader got MSG" << dendl; Message *m = 0; int r = read_message(&m, auth_handler.get()); pipe_lock.Lock(); if (!m) { if (r < 0) fault(true); continue; } if (state == STATE_CLOSED || state == STATE_CONNECTING) { msgr->dispatch_throttle_release(m->get_dispatch_throttle_size()); m->put(); continue; } // check received seq#. if it is old, drop the message. // note that incoming messages may skip ahead. this is convenient for the client // side queueing because messages can't be renumbered, but the (kernel) client will // occasionally pull a message out of the sent queue to send elsewhere. in that case // it doesn't matter if we "got" it or not. if (m->get_seq() <= in_seq) { ldout(msgr->cct,0) << "reader got old message " << m->get_seq() << " <= " << in_seq << " " << m << " " << *m << ", discarding" << dendl; msgr->dispatch_throttle_release(m->get_dispatch_throttle_size()); m->put(); if (connection_state->has_feature(CEPH_FEATURE_RECONNECT_SEQ) && msgr->cct->_conf->ms_die_on_old_message) assert(0 == "old msgs despite reconnect_seq feature"); continue; } m->set_connection(connection_state.get()); // note last received message. in_seq = m->get_seq(); cond.Signal(); // wake up writer, to ack this ldout(msgr->cct,10) << "reader got message " << m->get_seq() << " " << m << " " << *m << dendl; if (delay_thread) { utime_t release; if (rand() % 10000 < msgr->cct->_conf->ms_inject_delay_probability * 10000.0) { release = m->get_recv_stamp(); release += msgr->cct->_conf->ms_inject_delay_max * (double)(rand() % 10000) / 10000.0; lsubdout(msgr->cct, ms, 1) << "queue_received will delay until " << release << " on " << m << " " << *m << dendl; } delay_thread->queue(release, m); } else { in_q->enqueue(m, m->get_priority(), conn_id); } } else if (tag == CEPH_MSGR_TAG_CLOSE) { ldout(msgr->cct,20) << "reader got CLOSE" << dendl; pipe_lock.Lock(); if (state == STATE_CLOSING) { state = STATE_CLOSED; state_closed.set(1); } else { state = STATE_CLOSING; } cond.Signal(); break; } else { ldout(msgr->cct,0) << "reader bad tag " << (int)tag << dendl; pipe_lock.Lock(); fault(true); } } // reap? reader_running = false; reader_needs_join = true; unlock_maybe_reap(); ldout(msgr->cct,10) << "reader done" << dendl; } /* write msgs to socket. * also, client. */ void Pipe::writer() { pipe_lock.Lock(); while (state != STATE_CLOSED) {// && state != STATE_WAIT) { ldout(msgr->cct,10) << "writer: state = " << get_state_name() << " policy.server=" << policy.server << dendl; // standby? if (is_queued() && state == STATE_STANDBY && !policy.server) { connect_seq++; state = STATE_CONNECTING; } // connect? if (state == STATE_CONNECTING) { assert(!policy.server); connect(); continue; } if (state == STATE_CLOSING) { // write close tag ldout(msgr->cct,20) << "writer writing CLOSE tag" << dendl; char tag = CEPH_MSGR_TAG_CLOSE; state = STATE_CLOSED; state_closed.set(1); pipe_lock.Unlock(); if (sd) { int r = ::write(sd, &tag, 1); // we can ignore r, actually; we don't care if this succeeds. r++; r = 0; // placate gcc } pipe_lock.Lock(); continue; } if (state != STATE_CONNECTING && state != STATE_WAIT && state != STATE_STANDBY && (is_queued() || in_seq > in_seq_acked)) { // keepalive? if (send_keepalive) { int rc; if (connection_state->has_feature(CEPH_FEATURE_MSGR_KEEPALIVE2)) { pipe_lock.Unlock(); rc = write_keepalive2(CEPH_MSGR_TAG_KEEPALIVE2, ceph_clock_now(msgr->cct)); } else { pipe_lock.Unlock(); rc = write_keepalive(); } pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,2) << "writer couldn't write keepalive[2], " << cpp_strerror(errno) << dendl; fault(); continue; } send_keepalive = false; } if (send_keepalive_ack) { utime_t t = keepalive_ack_stamp; pipe_lock.Unlock(); int rc = write_keepalive2(CEPH_MSGR_TAG_KEEPALIVE2_ACK, t); pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,2) << "writer couldn't write keepalive_ack, " << cpp_strerror(errno) << dendl; fault(); continue; } send_keepalive_ack = false; } // send ack? if (in_seq > in_seq_acked) { uint64_t send_seq = in_seq; pipe_lock.Unlock(); int rc = write_ack(send_seq); pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,2) << "writer couldn't write ack, " << cpp_strerror(errno) << dendl; fault(); continue; } in_seq_acked = send_seq; } // grab outgoing message Message *m = _get_next_outgoing(); if (m) { m->set_seq(++out_seq); if (!policy.lossy || close_on_empty) { // put on sent list sent.push_back(m); m->get(); } // associate message with Connection (for benefit of encode_payload) m->set_connection(connection_state.get()); uint64_t features = connection_state->get_features(); if (m->empty_payload()) ldout(msgr->cct,20) << "writer encoding " << m->get_seq() << " features " << features << " " << m << " " << *m << dendl; else ldout(msgr->cct,20) << "writer half-reencoding " << m->get_seq() << " features " << features << " " << m << " " << *m << dendl; // encode and copy out of *m m->encode(features, !msgr->cct->_conf->ms_nocrc); // prepare everything ceph_msg_header& header = m->get_header(); ceph_msg_footer& footer = m->get_footer(); // Now that we have all the crcs calculated, handle the // digital signature for the message, if the pipe has session // security set up. Some session security options do not // actually calculate and check the signature, but they should // handle the calls to sign_message and check_signature. PLR if (session_security.get() == NULL) { ldout(msgr->cct, 20) << "writer no session security" << dendl; } else { if (session_security->sign_message(m)) { ldout(msgr->cct, 20) << "writer failed to sign seq # " << header.seq << "): sig = " << footer.sig << dendl; } else { ldout(msgr->cct, 20) << "writer signed seq # " << header.seq << "): sig = " << footer.sig << dendl; } } bufferlist blist = m->get_payload(); blist.append(m->get_middle()); blist.append(m->get_data()); pipe_lock.Unlock(); ldout(msgr->cct,20) << "writer sending " << m->get_seq() << " " << m << dendl; int rc = write_message(header, footer, blist); pipe_lock.Lock(); if (rc < 0) { ldout(msgr->cct,1) << "writer error sending " << m << ", " << cpp_strerror(errno) << dendl; fault(); } m->put(); } continue; } if (sent.empty() && close_on_empty) { ldout(msgr->cct,10) << "writer out and sent queues empty, closing" << dendl; stop(); continue; } // wait ldout(msgr->cct,20) << "writer sleeping" << dendl; cond.Wait(pipe_lock); } ldout(msgr->cct,20) << "writer finishing" << dendl; // reap? writer_running = false; unlock_maybe_reap(); ldout(msgr->cct,10) << "writer done" << dendl; } void Pipe::unlock_maybe_reap() { if (!reader_running && !writer_running) { shutdown_socket(); pipe_lock.Unlock(); msgr->queue_reap(this); } else { pipe_lock.Unlock(); } } static void alloc_aligned_buffer(bufferlist& data, unsigned len, unsigned off) { // create a buffer to read into that matches the data alignment unsigned left = len; if (off & ~CEPH_PAGE_MASK) { // head unsigned head = 0; head = MIN(CEPH_PAGE_SIZE - (off & ~CEPH_PAGE_MASK), left); bufferptr bp = buffer::create(head); data.push_back(bp); left -= head; } unsigned middle = left & CEPH_PAGE_MASK; if (middle > 0) { bufferptr bp = buffer::create_page_aligned(middle); data.push_back(bp); left -= middle; } if (left) { bufferptr bp = buffer::create(left); data.push_back(bp); } } int Pipe::read_message(Message **pm, AuthSessionHandler* auth_handler) { int ret = -1; // envelope //ldout(msgr->cct,10) << "receiver.read_message from sd " << sd << dendl; ceph_msg_header header; ceph_msg_footer footer; __u32 header_crc; if (connection_state->has_feature(CEPH_FEATURE_NOSRCADDR)) { if (tcp_read((char*)&header, sizeof(header)) < 0) return -1; header_crc = ceph_crc32c(0, (unsigned char *)&header, sizeof(header) - sizeof(header.crc)); } else { ceph_msg_header_old oldheader; if (tcp_read((char*)&oldheader, sizeof(oldheader)) < 0) return -1; // this is fugly memcpy(&header, &oldheader, sizeof(header)); header.src = oldheader.src.name; header.reserved = oldheader.reserved; header.crc = oldheader.crc; header_crc = ceph_crc32c(0, (unsigned char *)&oldheader, sizeof(oldheader) - sizeof(oldheader.crc)); } ldout(msgr->cct,20) << "reader got envelope type=" << header.type << " src " << entity_name_t(header.src) << " front=" << header.front_len << " data=" << header.data_len << " off " << header.data_off << dendl; // verify header crc if (header_crc != header.crc) { ldout(msgr->cct,0) << "reader got bad header crc " << header_crc << " != " << header.crc << dendl; return -1; } bufferlist front, middle, data; int front_len, middle_len; unsigned data_len, data_off; int aborted; Message *message; utime_t recv_stamp = ceph_clock_now(msgr->cct); if (policy.throttler_messages) { ldout(msgr->cct,10) << "reader wants " << 1 << " message from policy throttler " << policy.throttler_messages->get_current() << "/" << policy.throttler_messages->get_max() << dendl; policy.throttler_messages->get(); } uint64_t message_size = header.front_len + header.middle_len + header.data_len; if (message_size) { if (policy.throttler_bytes) { ldout(msgr->cct,10) << "reader wants " << message_size << " bytes from policy throttler " << policy.throttler_bytes->get_current() << "/" << policy.throttler_bytes->get_max() << dendl; policy.throttler_bytes->get(message_size); } // throttle total bytes waiting for dispatch. do this _after_ the // policy throttle, as this one does not deadlock (unless dispatch // blocks indefinitely, which it shouldn't). in contrast, the // policy throttle carries for the lifetime of the message. ldout(msgr->cct,10) << "reader wants " << message_size << " from dispatch throttler " << msgr->dispatch_throttler.get_current() << "/" << msgr->dispatch_throttler.get_max() << dendl; msgr->dispatch_throttler.get(message_size); } utime_t throttle_stamp = ceph_clock_now(msgr->cct); // read front front_len = header.front_len; if (front_len) { bufferptr bp = buffer::create(front_len); if (tcp_read(bp.c_str(), front_len) < 0) goto out_dethrottle; front.push_back(bp); ldout(msgr->cct,20) << "reader got front " << front.length() << dendl; } // read middle middle_len = header.middle_len; if (middle_len) { bufferptr bp = buffer::create(middle_len); if (tcp_read(bp.c_str(), middle_len) < 0) goto out_dethrottle; middle.push_back(bp); ldout(msgr->cct,20) << "reader got middle " << middle.length() << dendl; } // read data data_len = le32_to_cpu(header.data_len); data_off = le32_to_cpu(header.data_off); if (data_len) { unsigned offset = 0; unsigned left = data_len; bufferlist newbuf, rxbuf; bufferlist::iterator blp; int rxbuf_version = 0; while (left > 0) { // wait for data if (tcp_read_wait() < 0) goto out_dethrottle; // get a buffer connection_state->lock.Lock(); map >::iterator p = connection_state->rx_buffers.find(header.tid); if (p != connection_state->rx_buffers.end()) { if (rxbuf.length() == 0 || p->second.second != rxbuf_version) { ldout(msgr->cct,10) << "reader seleting rx buffer v " << p->second.second << " at offset " << offset << " len " << p->second.first.length() << dendl; rxbuf = p->second.first; rxbuf_version = p->second.second; // make sure it's big enough if (rxbuf.length() < data_len) rxbuf.push_back(buffer::create(data_len - rxbuf.length())); blp = p->second.first.begin(); blp.advance(offset); } } else { if (!newbuf.length()) { ldout(msgr->cct,20) << "reader allocating new rx buffer at offset " << offset << dendl; alloc_aligned_buffer(newbuf, data_len, data_off); blp = newbuf.begin(); blp.advance(offset); } } bufferptr bp = blp.get_current_ptr(); int read = MIN(bp.length(), left); ldout(msgr->cct,20) << "reader reading nonblocking into " << (void*)bp.c_str() << " len " << bp.length() << dendl; int got = tcp_read_nonblocking(bp.c_str(), read); ldout(msgr->cct,30) << "reader read " << got << " of " << read << dendl; connection_state->lock.Unlock(); if (got < 0) goto out_dethrottle; if (got > 0) { blp.advance(got); data.append(bp, 0, got); offset += got; left -= got; } // else we got a signal or something; just loop. } } // footer if (connection_state->has_feature(CEPH_FEATURE_MSG_AUTH)) { if (tcp_read((char*)&footer, sizeof(footer)) < 0) goto out_dethrottle; } else { ceph_msg_footer_old old_footer; if (tcp_read((char*)&old_footer, sizeof(old_footer)) < 0) goto out_dethrottle; footer.front_crc = old_footer.front_crc; footer.middle_crc = old_footer.middle_crc; footer.data_crc = old_footer.data_crc; footer.sig = 0; footer.flags = old_footer.flags; } aborted = (footer.flags & CEPH_MSG_FOOTER_COMPLETE) == 0; ldout(msgr->cct,10) << "aborted = " << aborted << dendl; if (aborted) { ldout(msgr->cct,0) << "reader got " << front.length() << " + " << middle.length() << " + " << data.length() << " byte message.. ABORTED" << dendl; ret = 0; goto out_dethrottle; } ldout(msgr->cct,20) << "reader got " << front.length() << " + " << middle.length() << " + " << data.length() << " byte message" << dendl; message = decode_message(msgr->cct, header, footer, front, middle, data); if (!message) { ret = -EINVAL; goto out_dethrottle; } // // Check the signature if one should be present. A zero return indicates success. PLR // if (auth_handler == NULL) { ldout(msgr->cct, 10) << "No session security set" << dendl; } else { if (auth_handler->check_message_signature(message)) { ldout(msgr->cct, 0) << "Signature check failed" << dendl; ret = -EINVAL; goto out_dethrottle; } } message->set_byte_throttler(policy.throttler_bytes); message->set_message_throttler(policy.throttler_messages); // store reservation size in message, so we don't get confused // by messages entering the dispatch queue through other paths. message->set_dispatch_throttle_size(message_size); message->set_recv_stamp(recv_stamp); message->set_throttle_stamp(throttle_stamp); message->set_recv_complete_stamp(ceph_clock_now(msgr->cct)); *pm = message; return 0; out_dethrottle: // release bytes reserved from the throttlers on failure if (policy.throttler_messages) { ldout(msgr->cct,10) << "reader releasing " << 1 << " message to policy throttler " << policy.throttler_messages->get_current() << "/" << policy.throttler_messages->get_max() << dendl; policy.throttler_messages->put(); } if (message_size) { if (policy.throttler_bytes) { ldout(msgr->cct,10) << "reader releasing " << message_size << " bytes to policy throttler " << policy.throttler_bytes->get_current() << "/" << policy.throttler_bytes->get_max() << dendl; policy.throttler_bytes->put(message_size); } msgr->dispatch_throttle_release(message_size); } return ret; } int Pipe::do_sendmsg(struct msghdr *msg, int len, bool more) { while (len > 0) { if (0) { // sanity int l = 0; for (unsigned i=0; imsg_iovlen; i++) l += msg->msg_iov[i].iov_len; assert(l == len); } int r = ::sendmsg(sd, msg, MSG_NOSIGNAL | (more ? MSG_MORE : 0)); if (r == 0) ldout(msgr->cct,10) << "do_sendmsg hmm do_sendmsg got r==0!" << dendl; if (r < 0) { ldout(msgr->cct,1) << "do_sendmsg error " << cpp_strerror(errno) << dendl; return -1; } if (state == STATE_CLOSED) { ldout(msgr->cct,10) << "do_sendmsg oh look, state == CLOSED, giving up" << dendl; errno = EINTR; return -1; // close enough } len -= r; if (len == 0) break; // hrmph. trim r bytes off the front of our message. ldout(msgr->cct,20) << "do_sendmsg short write did " << r << ", still have " << len << dendl; while (r > 0) { if (msg->msg_iov[0].iov_len <= (size_t)r) { // lose this whole item //ldout(msgr->cct,30) << "skipping " << msg->msg_iov[0].iov_len << ", " << (msg->msg_iovlen-1) << " v, " << r << " left" << dendl; r -= msg->msg_iov[0].iov_len; msg->msg_iov++; msg->msg_iovlen--; } else { // partial! //ldout(msgr->cct,30) << "adjusting " << msg->msg_iov[0].iov_len << ", " << msg->msg_iovlen << " v, " << r << " left" << dendl; msg->msg_iov[0].iov_base = (char *)msg->msg_iov[0].iov_base + r; msg->msg_iov[0].iov_len -= r; break; } } } return 0; } int Pipe::write_ack(uint64_t seq) { ldout(msgr->cct,10) << "write_ack " << seq << dendl; char c = CEPH_MSGR_TAG_ACK; ceph_le64 s; s = seq; struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct iovec msgvec[2]; msgvec[0].iov_base = &c; msgvec[0].iov_len = 1; msgvec[1].iov_base = &s; msgvec[1].iov_len = sizeof(s); msg.msg_iov = msgvec; msg.msg_iovlen = 2; if (do_sendmsg(&msg, 1 + sizeof(s), true) < 0) return -1; return 0; } int Pipe::write_keepalive() { ldout(msgr->cct,10) << "write_keepalive" << dendl; char c = CEPH_MSGR_TAG_KEEPALIVE; struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct iovec msgvec[2]; msgvec[0].iov_base = &c; msgvec[0].iov_len = 1; msg.msg_iov = msgvec; msg.msg_iovlen = 1; if (do_sendmsg(&msg, 1) < 0) return -1; return 0; } int Pipe::write_keepalive2(char tag, const utime_t& t) { ldout(msgr->cct,10) << "write_keepalive2 " << (int)tag << " " << t << dendl; struct ceph_timespec ts; t.encode_timeval(&ts); struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct iovec msgvec[2]; msgvec[0].iov_base = &tag; msgvec[0].iov_len = 1; msgvec[1].iov_base = &ts; msgvec[1].iov_len = sizeof(ts); msg.msg_iov = msgvec; msg.msg_iovlen = 2; if (do_sendmsg(&msg, 1 + sizeof(ts)) < 0) return -1; return 0; } int Pipe::write_message(ceph_msg_header& header, ceph_msg_footer& footer, bufferlist& blist) { int ret; // set up msghdr and iovecs struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct iovec *msgvec = new iovec[3 + blist.buffers().size()]; // conservative upper bound msg.msg_iov = msgvec; int msglen = 0; // send tag char tag = CEPH_MSGR_TAG_MSG; msgvec[msg.msg_iovlen].iov_base = &tag; msgvec[msg.msg_iovlen].iov_len = 1; msglen++; msg.msg_iovlen++; // send envelope ceph_msg_header_old oldheader; if (connection_state->has_feature(CEPH_FEATURE_NOSRCADDR)) { msgvec[msg.msg_iovlen].iov_base = (char*)&header; msgvec[msg.msg_iovlen].iov_len = sizeof(header); msglen += sizeof(header); msg.msg_iovlen++; } else { memcpy(&oldheader, &header, sizeof(header)); oldheader.src.name = header.src; oldheader.src.addr = connection_state->get_peer_addr(); oldheader.orig_src = oldheader.src; oldheader.reserved = header.reserved; oldheader.crc = ceph_crc32c(0, (unsigned char*)&oldheader, sizeof(oldheader) - sizeof(oldheader.crc)); msgvec[msg.msg_iovlen].iov_base = (char*)&oldheader; msgvec[msg.msg_iovlen].iov_len = sizeof(oldheader); msglen += sizeof(oldheader); msg.msg_iovlen++; } // payload (front+data) list::const_iterator pb = blist.buffers().begin(); int b_off = 0; // carry-over buffer offset, if any int bl_pos = 0; // blist pos int left = blist.length(); while (left > 0) { int donow = MIN(left, (int)pb->length()-b_off); if (donow == 0) { ldout(msgr->cct,0) << "donow = " << donow << " left " << left << " pb->length " << pb->length() << " b_off " << b_off << dendl; } assert(donow > 0); ldout(msgr->cct,30) << " bl_pos " << bl_pos << " b_off " << b_off << " leftinchunk " << left << " buffer len " << pb->length() << " writing " << donow << dendl; if (msg.msg_iovlen >= IOV_MAX-2) { if (do_sendmsg(&msg, msglen, true)) goto fail; // and restart the iov msg.msg_iov = msgvec; msg.msg_iovlen = 0; msglen = 0; } msgvec[msg.msg_iovlen].iov_base = (void*)(pb->c_str()+b_off); msgvec[msg.msg_iovlen].iov_len = donow; msglen += donow; msg.msg_iovlen++; left -= donow; assert(left >= 0); b_off += donow; bl_pos += donow; if (left == 0) break; while (b_off == (int)pb->length()) { ++pb; b_off = 0; } } assert(left == 0); // send footer; if receiver doesn't support signatures, use the old footer format ceph_msg_footer_old old_footer; if (connection_state->has_feature(CEPH_FEATURE_MSG_AUTH)) { msgvec[msg.msg_iovlen].iov_base = (void*)&footer; msgvec[msg.msg_iovlen].iov_len = sizeof(footer); msglen += sizeof(footer); msg.msg_iovlen++; } else { old_footer.front_crc = footer.front_crc; old_footer.middle_crc = footer.middle_crc; old_footer.data_crc = footer.data_crc; old_footer.flags = footer.flags; msgvec[msg.msg_iovlen].iov_base = (char*)&old_footer; msgvec[msg.msg_iovlen].iov_len = sizeof(old_footer); msglen += sizeof(old_footer); msg.msg_iovlen++; } // send if (do_sendmsg(&msg, msglen)) goto fail; ret = 0; out: delete[] msgvec; return ret; fail: ret = -1; goto out; } int Pipe::tcp_read(char *buf, int len) { if (sd < 0) return -1; while (len > 0) { if (msgr->cct->_conf->ms_inject_socket_failures && sd >= 0) { if (rand() % msgr->cct->_conf->ms_inject_socket_failures == 0) { ldout(msgr->cct, 0) << "injecting socket failure" << dendl; ::shutdown(sd, SHUT_RDWR); } } if (tcp_read_wait() < 0) return -1; int got = tcp_read_nonblocking(buf, len); if (got < 0) return -1; len -= got; buf += got; //lgeneric_dout(cct, DBL) << "tcp_read got " << got << ", " << len << " left" << dendl; } return len; } int Pipe::tcp_read_wait() { if (sd < 0) return -1; struct pollfd pfd; short evmask; pfd.fd = sd; pfd.events = POLLIN; #if defined(__linux__) pfd.events |= POLLRDHUP; #endif if (poll(&pfd, 1, msgr->timeout) <= 0) return -1; evmask = POLLERR | POLLHUP | POLLNVAL; #if defined(__linux__) evmask |= POLLRDHUP; #endif if (pfd.revents & evmask) return -1; if (!(pfd.revents & POLLIN)) return -1; return 0; } int Pipe::tcp_read_nonblocking(char *buf, int len) { again: int got = ::recv( sd, buf, len, MSG_DONTWAIT ); if (got < 0) { if (errno == EAGAIN || errno == EINTR) { goto again; } else { ldout(msgr->cct, 10) << "tcp_read_nonblocking socket " << sd << " returned " << got << " " << cpp_strerror(errno) << dendl; return -1; } } else if (got == 0) { /* poll() said there was data, but we didn't read any - peer * sent a FIN. Maybe POLLRDHUP signals this, but this is * standard socket behavior as documented by Stevens. */ return -1; } return got; } int Pipe::tcp_write(const char *buf, int len) { if (sd < 0) return -1; struct pollfd pfd; pfd.fd = sd; pfd.events = POLLOUT | POLLHUP | POLLNVAL | POLLERR; #if defined(__linux__) pfd.events |= POLLRDHUP; #endif if (msgr->cct->_conf->ms_inject_socket_failures && sd >= 0) { if (rand() % msgr->cct->_conf->ms_inject_socket_failures == 0) { ldout(msgr->cct, 0) << "injecting socket failure" << dendl; ::shutdown(sd, SHUT_RDWR); } } if (poll(&pfd, 1, -1) < 0) return -1; if (!(pfd.revents & POLLOUT)) return -1; //lgeneric_dout(cct, DBL) << "tcp_write writing " << len << dendl; assert(len > 0); while (len > 0) { int did = ::send( sd, buf, len, MSG_NOSIGNAL ); if (did < 0) { //lgeneric_dout(cct, 1) << "tcp_write error did = " << did << " " << cpp_strerror(errno) << dendl; //lgeneric_derr(cct, 1) << "tcp_write error did = " << did << " " << cpp_strerror(errno) << dendl; return did; } len -= did; buf += did; //lgeneric_dout(cct, DBL) << "tcp_write did " << did << ", " << len << " left" << dendl; } return 0; } ceph-0.80.11/src/check_version0000775000175100017510000000055112623076744020235 0ustar jenkins-buildjenkins-build#!/bin/sh dname=`dirname $0` if [ ! -d $dname/../.git ]; then echo "not updating .git_version (no $dname/../.git)" exit 0 fi cur=`cd $dname && git rev-parse HEAD 2>/dev/null; git describe 2>/dev/null` [ -e $1 ] && old=`cat $1` if [ "$cur" != "$old" ]; then echo regenerating $1 with $cur echo "$cur" > $1 else echo $1 is up to date. fi ceph-0.80.11/src/init-radosgw0000664000175100017510000000557512623076744020032 0ustar jenkins-buildjenkins-build#! /bin/sh ### BEGIN INIT INFO # Provides: radosgw # Required-Start: $remote_fs $named $network $time # Required-Stop: $remote_fs $named $network $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: radosgw RESTful rados gateway # Description: radosgw RESTful rados gateway ### END INIT INFO PATH=/sbin:/bin:/usr/bin . /lib/lsb/init-functions daemon_is_running() { daemon=$1 if pidof $daemon >/dev/null; then echo "$daemon is running." exit 0 else echo "$daemon is not running." exit 1 fi } VERBOSE=0 for opt in $*; do if [ "$opt" = "-v" ] || [ "$opt" = "--verbose" ]; then VERBOSE=1 fi done # prefix for radosgw instances in ceph.conf PREFIX='client.radosgw.' # user to run radosgw as (it not specified in ceph.conf) DEFAULT_USER='root' RADOSGW=`which radosgw` if [ ! -x "$RADOSGW" ]; then [ $VERBOSE -eq 1 ] && echo "$RADOSGW could not start, it is not executable." exit 1 fi case "$1" in start) for name in `ceph-conf --list-sections $PREFIX`; do auto_start=`ceph-conf -n $name 'auto start'` if [ "$auto_start" = "no" ] || [ "$auto_start" = "false" ] || [ "$auto_start" = "0" ]; then continue fi # mapped to this host? host=`ceph-conf -n $name host` hostname=`hostname -s` if [ "$host" != "$hostname" ]; then [ $VERBOSE -eq 1 ] && echo "hostname $hostname could not be found in ceph.conf:[$name], not starting." continue fi user=`ceph-conf -n $name user` if [ -z "$user" ]; then user="$DEFAULT_USER" fi log_file=`$RADOSGW -n $name --show-config-value log_file` if [ -n "$log_file" ]; then if [ ! -e "$log_file" ]; then touch "$log_file" fi chown $user $log_file fi echo "Starting $name..." start-stop-daemon --start -u $user -x $RADOSGW -- -n $name done daemon_is_running $RADOSGW ;; reload) echo "Reloading $name..." start-stop-daemon --stop --signal HUP -x $RADOSGW --oknodo ;; restart|force-reload) $0 stop $0 start ;; stop) timeout=0 for name in `ceph-conf --list-sections $PREFIX`; do t=`$RADOSGW -n $name --show-config-value rgw_exit_timeout_secs` if [ $t -gt $timeout ]; then timeout=$t; fi done if [ $timeout -gt 0 ]; then TIMEOUT="-R $timeout"; fi start-stop-daemon --stop -x $RADOSGW --oknodo $TIMEOUT ;; status) daemon_is_running $RADOSGW ;; *) echo "Usage: $0 {start|stop|restart|force-reload|reload|status} [-v|--verbose]" >&2 exit 3 ;; esac ceph-0.80.11/src/ceph-coverage.in0000664000175100017510000000061212623076744020523 0ustar jenkins-buildjenkins-build#!/bin/sh set -e export GCOV_PREFIX_STRIP=@@GCOV_PREFIX_STRIP@@ usage () { printf '%s: usage: %s OUTPUTDIR COMMAND [ARGS..]\n' "$(basename "$0")" "$(basename "$0")" 1>&2 exit 1 } export GCOV_PREFIX="$1" [ -n "$GCOV_PREFIX" ] || usage shift case "$GCOV_PREFIX" in /*) # absolute path -> ok ;; *) # make it absolute GCOV_PREFIX="$PWD/$GCOV_PREFIX" ;; esac exec "$@" ceph-0.80.11/src/rbd.cc0000664000175100017510000024703712623076744016557 0ustar jenkins-buildjenkins-build// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2012 Sage Weil and others * * LGPL2. See file COPYING. * */ #include "include/int_types.h" #include "mon/MonClient.h" #include "mon/MonMap.h" #include "common/config.h" #include "auth/KeyRing.h" #include "common/errno.h" #include "common/ceph_argparse.h" #include "common/strtol.h" #include "global/global_init.h" #include "common/safe_io.h" #include "common/secret.h" #include "include/stringify.h" #include "include/rados/librados.hpp" #include "include/rbd/librbd.hpp" #include "include/byteorder.h" #include "include/intarith.h" #include "include/compat.h" #include "common/blkdev.h" #include #include #include #include #include #include #include #include #include #include "include/memory.h" #include #include "include/rbd_types.h" #include "common/TextTable.h" #include "include/util.h" #include "common/Formatter.h" #if defined(__linux__) #include #endif #if defined(__FreeBSD__) #include #endif #include #define MAX_SECRET_LEN 1000 #define MAX_POOL_NAME_SIZE 128 #define RBD_DIFF_BANNER "rbd diff v1\n" static string dir_oid = RBD_DIRECTORY; static string dir_info_oid = RBD_INFO; bool udevadm_settle = true; bool progress = true; bool resize_allow_shrink = false; map map_options; // -o / --options map #define dout_subsys ceph_subsys_rbd void usage() { cout << "usage: rbd [-n ] [OPTIONS] ...\n" "where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of:\n" " (ls | list) [-l | --long ] [pool-name] list rbd images\n" " (-l includes snapshots/clones)\n" " info show information about image size,\n" " striping, etc.\n" " create [--order ] --size create an empty image\n" " clone [--order ] \n" " clone a snapshot into a COW\n" " child image\n" " children display children of snapshot\n" " flatten fill clone with parent data\n" " (make it independent)\n" " resize --size resize (expand or contract) image\n" " rm delete an image\n" " export export image to file\n" " \"-\" for stdout\n" " import import image from file\n" " (dest defaults\n" " as the filename part of file)\n" " \"-\" for stdin\n" " diff [--from-snap ] print extents that differ since\n" " a previous snap, or image creation\n" " export-diff [--from-snap ] \n" " export an incremental diff to\n" " path, or \"-\" for stdout\n" " import-diff import an incremental diff from\n" " path or \"-\" for stdin\n" " (cp | copy) copy src image to dest\n" " (mv | rename) rename src image to dest\n" " snap ls dump list of image snapshots\n" " snap create create a snapshot\n" " snap rollback rollback image to snapshot\n" " snap rm deletes a snapshot\n" " snap purge deletes all snapshots\n" " snap protect prevent a snapshot from being deleted\n" " snap unprotect allow a snapshot to be deleted\n" " watch watch events on image\n" " map map image to a block device\n" " using the kernel\n" " unmap unmap a rbd device that was\n" " mapped by the kernel\n" " showmapped show the rbd images mapped\n" " by the kernel\n" " lock list show locks held on an image\n" " lock add [--shared ] take a lock called id on an image\n" " lock remove release a lock on an image\n" " bench-write simple write benchmark\n" " --io-size write size\n" " --io-threads ios in flight\n" " --io-total total bytes to write\n" " --io-pattern write pattern\n" "\n" ", are [pool/]name[@snap], or you may specify\n" "individual pieces of names with -p/--pool, --image, and/or --snap.\n" "\n" "Other input options:\n" " -p, --pool source pool name\n" " --image image name\n" " --dest destination [pool and] image name\n" " --snap snapshot name\n" " --dest-pool destination pool name\n" " --path path name for import/export\n" " --size size of image for create and resize\n" " --order the object size in bits; object size will be\n" " (1 << order) bytes. Default is 22 (4 MB).\n" " --image-format format to use when creating an image\n" " format 1 is the original format (default)\n" " format 2 supports cloning\n" " --id rados user (without 'client.'prefix) to\n" " authenticate as\n" " --keyfile file containing secret key for use with cephx\n" " --shared take a shared (rather than exclusive) lock\n" " --format output format (default: plain, json, xml)\n" " --pretty-format make json or xml output more readable\n" " --no-settle do not wait for udevadm to settle on map/unmap\n" " --no-progress do not show progress for long-running commands\n" " -o, --options options to use when mapping an image\n" " --read-only set device readonly when mapping image\n" " --allow-shrink allow shrinking of an image when resizing\n"; } static string feature_str(uint64_t feature) { switch (feature) { case RBD_FEATURE_LAYERING: return "layering"; case RBD_FEATURE_STRIPINGV2: return "striping"; default: return ""; } } static string features_str(uint64_t features) { string s = ""; for (uint64_t feature = 1; feature <= RBD_FEATURE_STRIPINGV2; feature <<= 1) { if (feature & features) { if (s.size()) s += ", "; s += feature_str(feature); } } return s; } static void format_features(Formatter *f, uint64_t features) { f->open_array_section("features"); for (uint64_t feature = 1; feature <= RBD_FEATURE_STRIPINGV2; feature <<= 1) { f->dump_string("feature", feature_str(feature)); } f->close_section(); } struct MyProgressContext : public librbd::ProgressContext { const char *operation; int last_pc; MyProgressContext(const char *o) : operation(o), last_pc(0) { } int update_progress(uint64_t offset, uint64_t total) { if (progress) { int pc = total ? (offset * 100ull / total) : 0; if (pc != last_pc) { cerr << "\r" << operation << ": " // << offset << " / " << total << " " << pc << "% complete..."; cerr.flush(); last_pc = pc; } } return 0; } void finish() { if (progress) { cerr << "\r" << operation << ": 100% complete...done." << std::endl; } } void fail() { if (progress) { cerr << "\r" << operation << ": " << last_pc << "% complete...failed." << std::endl; } } }; static int get_outfmt(const char *output_format, bool pretty, boost::scoped_ptr *f) { if (!strcmp(output_format, "json")) { f->reset(new JSONFormatter(pretty)); } else if (!strcmp(output_format, "xml")) { f->reset(new XMLFormatter(pretty)); } else if (strcmp(output_format, "plain")) { cerr << "rbd: unknown format '" << output_format << "'" << std::endl; return -EINVAL; } return 0; } static int do_list(librbd::RBD &rbd, librados::IoCtx& io_ctx, bool lflag, Formatter *f) { std::vector names; int r = rbd.list(io_ctx, names); if (r == -ENOENT) r = 0; if (r < 0) return r; if (!lflag) { if (f) f->open_array_section("images"); for (std::vector::const_iterator i = names.begin(); i != names.end(); ++i) { if (f) f->dump_string("name", *i); else cout << *i << std::endl; } if (f) { f->close_section(); f->flush(cout); } return 0; } TextTable tbl; if (f) { f->open_array_section("images"); } else { tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT); tbl.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT); tbl.define_column("PARENT", TextTable::LEFT, TextTable::LEFT); tbl.define_column("FMT", TextTable::RIGHT, TextTable::RIGHT); tbl.define_column("PROT", TextTable::LEFT, TextTable::LEFT); tbl.define_column("LOCK", TextTable::LEFT, TextTable::LEFT); } string pool, image, snap, parent; for (std::vector::const_iterator i = names.begin(); i != names.end(); ++i) { librbd::image_info_t info; librbd::Image im; r = rbd.open_read_only(io_ctx, im, i->c_str(), NULL); // image might disappear between rbd.list() and rbd.open(); ignore // that, warn about other possible errors (EPERM, say, for opening // an old-format image, because you need execute permission for the // class method) if (r < 0) { if (r != -ENOENT) { cerr << "rbd: error opening " << *i << ": " << cpp_strerror(r) << std::endl; } // in any event, continue to next image continue; } // handle second-nth trips through loop parent.clear(); r = im.parent_info(&pool, &image, &snap); if (r < 0 && r != -ENOENT) return r; bool has_parent = false; if (r != -ENOENT) { parent = pool + "/" + image + "@" + snap; has_parent = true; } if (im.stat(info, sizeof(info)) < 0) return -EINVAL; uint8_t old_format; im.old_format(&old_format); list lockers; bool exclusive; r = im.list_lockers(&lockers, &exclusive, NULL); if (r < 0) return r; string lockstr; if (!lockers.empty()) { lockstr = (exclusive) ? "excl" : "shr"; } if (f) { f->open_object_section("image"); f->dump_string("image", *i); f->dump_unsigned("size", info.size); if (has_parent) { f->open_object_section("parent"); f->dump_string("pool", pool); f->dump_string("image", image); f->dump_string("snapshot", snap); f->close_section(); } f->dump_int("format", old_format ? 1 : 2); if (!lockers.empty()) f->dump_string("lock_type", exclusive ? "exclusive" : "shared"); f->close_section(); } else { tbl << *i << stringify(si_t(info.size)) << parent << ((old_format) ? '1' : '2') << "" // protect doesn't apply to images << lockstr << TextTable::endrow; } vector snaplist; if (im.snap_list(snaplist) >= 0 && !snaplist.empty()) { for (std::vector::iterator s = snaplist.begin(); s != snaplist.end(); ++s) { bool is_protected; bool has_parent = false; parent.clear(); im.snap_set(s->name.c_str()); r = im.snap_is_protected(s->name.c_str(), &is_protected); if (r < 0) return r; if (im.parent_info(&pool, &image, &snap) >= 0) { parent = pool + "/" + image + "@" + snap; has_parent = true; } if (f) { f->open_object_section("snapshot"); f->dump_string("image", *i); f->dump_string("snapshot", s->name); f->dump_unsigned("size", s->size); if (has_parent) { f->open_object_section("parent"); f->dump_string("pool", pool); f->dump_string("image", image); f->dump_string("snapshot", snap); f->close_section(); } f->dump_int("format", old_format ? 1 : 2); f->dump_string("protected", is_protected ? "true" : "false"); f->close_section(); } else { tbl << *i + "@" + s->name << stringify(si_t(s->size)) << parent << ((old_format) ? '1' : '2') << (is_protected ? "yes" : "") << "" // locks don't apply to snaps << TextTable::endrow; } } } } if (f) { f->close_section(); f->flush(cout); } else if (!names.empty()) { cout << tbl; } return 0; } static int do_create(librbd::RBD &rbd, librados::IoCtx& io_ctx, const char *imgname, uint64_t size, int *order, int format, uint64_t features, uint64_t stripe_unit, uint64_t stripe_count) { int r; if (format == 1) { // weird striping not allowed with format 1! if ((stripe_unit || stripe_count) && (stripe_unit != (1ull << *order) && stripe_count != 1)) { cerr << "non-default striping not allowed with format 1; use --format 2" << std::endl; return -EINVAL; } r = rbd.create(io_ctx, imgname, size, order); } else { if (features == 0) { features = RBD_FEATURE_LAYERING; } if ((stripe_unit || stripe_count) && (stripe_unit != (1ull << *order) && stripe_count != 1)) { features |= RBD_FEATURE_STRIPINGV2; } r = rbd.create3(io_ctx, imgname, size, features, order, stripe_unit, stripe_count); } if (r < 0) return r; return 0; } static int do_clone(librbd::RBD &rbd, librados::IoCtx &p_ioctx, const char *p_name, const char *p_snapname, librados::IoCtx &c_ioctx, const char *c_name, uint64_t features, int *c_order) { if (features == 0) features = RBD_FEATURES_ALL; else if ((features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) return -EINVAL; return rbd.clone(p_ioctx, p_name, p_snapname, c_ioctx, c_name, features, c_order); } static int do_flatten(librbd::Image& image) { MyProgressContext pc("Image flatten"); int r = image.flatten_with_progress(pc); if (r < 0) { pc.fail(); return r; } pc.finish(); return 0; } static int do_rename(librbd::RBD &rbd, librados::IoCtx& io_ctx, const char *imgname, const char *destname) { int r = rbd.rename(io_ctx, imgname, destname); if (r < 0) return r; return 0; } static int do_show_info(const char *imgname, librbd::Image& image, const char *snapname, Formatter *f) { librbd::image_info_t info; string parent_pool, parent_name, parent_snapname; uint8_t old_format; uint64_t overlap, features; bool snap_protected; int r; r = image.stat(info, sizeof(info)); if (r < 0) return r; r = image.old_format(&old_format); if (r < 0) return r; r = image.overlap(&overlap); if (r < 0) return r; r = image.features(&features); if (r < 0) return r; if (snapname) { r = image.snap_is_protected(snapname, &snap_protected); if (r < 0) return r; } char prefix[RBD_MAX_BLOCK_NAME_SIZE + 1]; strncpy(prefix, info.block_name_prefix, RBD_MAX_BLOCK_NAME_SIZE); prefix[RBD_MAX_BLOCK_NAME_SIZE] = '\0'; if (f) { f->open_object_section("image"); f->dump_string("name", imgname); f->dump_unsigned("size", info.size); f->dump_unsigned("objects", info.num_objs); f->dump_int("order", info.order); f->dump_unsigned("object_size", info.obj_size); f->dump_string("block_name_prefix", prefix); f->dump_int("format", (old_format ? 1 : 2)); } else { cout << "rbd image '" << imgname << "':\n" << "\tsize " << prettybyte_t(info.size) << " in " << info.num_objs << " objects" << std::endl << "\torder " << info.order << " (" << prettybyte_t(info.obj_size) << " objects)" << std::endl << "\tblock_name_prefix: " << prefix << std::endl << "\tformat: " << (old_format ? "1" : "2") << std::endl; } if (!old_format) { if (f) format_features(f, features); else cout << "\tfeatures: " << features_str(features) << std::endl; } // snapshot info, if present if (snapname) { if (f) { f->dump_string("protected", snap_protected ? "true" : "false"); } else { cout << "\tprotected: " << (snap_protected ? "True" : "False") << std::endl; } } // parent info, if present if ((image.parent_info(&parent_pool, &parent_name, &parent_snapname) == 0) && parent_name.length() > 0) { if (f) { f->open_object_section("parent"); f->dump_string("pool", parent_pool); f->dump_string("image", parent_name); f->dump_string("snapshot", parent_snapname); f->dump_unsigned("overlap", overlap); f->close_section(); } else { cout << "\tparent: " << parent_pool << "/" << parent_name << "@" << parent_snapname << std::endl; cout << "\toverlap: " << prettybyte_t(overlap) << std::endl; } } // striping info, if feature is set if (features & RBD_FEATURE_STRIPINGV2) { if (f) { f->dump_unsigned("stripe_unit", image.get_stripe_unit()); f->dump_unsigned("stripe_count", image.get_stripe_count()); } else { cout << "\tstripe unit: " << prettybyte_t(image.get_stripe_unit()) << std::endl << "\tstripe count: " << image.get_stripe_count() << std::endl; } } if (f) { f->close_section(); f->flush(cout); } return 0; } static int do_delete(librbd::RBD &rbd, librados::IoCtx& io_ctx, const char *imgname) { MyProgressContext pc("Removing image"); int r = rbd.remove_with_progress(io_ctx, imgname, pc); if (r < 0) { pc.fail(); return r; } pc.finish(); return 0; } static int do_resize(librbd::Image& image, uint64_t size) { MyProgressContext pc("Resizing image"); int r = image.resize_with_progress(size, pc); if (r < 0) { pc.fail(); return r; } pc.finish(); return 0; } static int do_list_snaps(librbd::Image& image, Formatter *f) { std::vector snaps; TextTable t; int r; r = image.snap_list(snaps); if (r < 0) return r; if (f) { f->open_array_section("snapshots"); } else { t.define_column("SNAPID", TextTable::RIGHT, TextTable::RIGHT); t.define_column("NAME", TextTable::LEFT, TextTable::LEFT); t.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT); } for (std::vector::iterator s = snaps.begin(); s != snaps.end(); ++s) { if (f) { f->open_object_section("snapshot"); f->dump_unsigned("id", s->id); f->dump_string("name", s->name); f->dump_unsigned("size", s->size); f->close_section(); } else { t << s->id << s->name << stringify(prettybyte_t(s->size)) << TextTable::endrow; } } if (f) { f->close_section(); f->flush(cout); } else if (snaps.size()) { cout << t; } return 0; } static int do_add_snap(librbd::Image& image, const char *snapname) { int r = image.snap_create(snapname); if (r < 0) return r; return 0; } static int do_remove_snap(librbd::Image& image, const char *snapname) { int r = image.snap_remove(snapname); if (r < 0) return r; return 0; } static int do_rollback_snap(librbd::Image& image, const char *snapname) { MyProgressContext pc("Rolling back to snapshot"); int r = image.snap_rollback_with_progress(snapname, pc); if (r < 0) { pc.fail(); return r; } pc.finish(); return 0; } static int do_purge_snaps(librbd::Image& image) { MyProgressContext pc("Removing all snapshots"); std::vector snaps; int r = image.snap_list(snaps); if (r < 0) { pc.fail(); return r; } for (size_t i = 0; i < snaps.size(); ++i) { r = image.snap_remove(snaps[i].name.c_str()); if (r < 0) { pc.fail(); return r; } pc.update_progress(i + 1, snaps.size()); } pc.finish(); return 0; } static int do_protect_snap(librbd::Image& image, const char *snapname) { int r = image.snap_protect(snapname); if (r < 0) return r; return 0; } static int do_unprotect_snap(librbd::Image& image, const char *snapname) { int r = image.snap_unprotect(snapname); if (r < 0) return r; return 0; } static int do_list_children(librbd::Image &image, Formatter *f) { set > children; int r; r = image.list_children(&children); if (r < 0) return r; if (f) f->open_array_section("children"); for (set >::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) { if (f) { f->open_object_section("child"); f->dump_string("pool", child_it->first); f->dump_string("image", child_it->second); f->close_section(); } else { cout << child_it->first << "/" << child_it->second << std::endl; } } if (f) { f->close_section(); f->flush(cout); } return 0; } static int do_lock_list(librbd::Image& image, Formatter *f) { list lockers; bool exclusive; string tag; TextTable tbl; int r; r = image.list_lockers(&lockers, &exclusive, &tag); if (r < 0) return r; if (f) { f->open_object_section("locks"); } else { tbl.define_column("Locker", TextTable::LEFT, TextTable::LEFT); tbl.define_column("ID", TextTable::LEFT, TextTable::LEFT); tbl.define_column("Address", TextTable::LEFT, TextTable::LEFT); } if (lockers.size()) { bool one = (lockers.size() == 1); if (!f) { cout << "There " << (one ? "is " : "are ") << lockers.size() << (exclusive ? " exclusive" : " shared") << " lock" << (one ? "" : "s") << " on this image.\n"; if (!exclusive) cout << "Lock tag: " << tag << "\n"; } for (list::const_iterator it = lockers.begin(); it != lockers.end(); ++it) { if (f) { f->open_object_section(it->cookie.c_str()); f->dump_string("locker", it->client); f->dump_string("address", it->address); f->close_section(); } else { tbl << it->client << it->cookie << it->address << TextTable::endrow; } } if (!f) cout << tbl; } if (f) { f->close_section(); f->flush(cout); } return 0; } static int do_lock_add(librbd::Image& image, const char *cookie, const char *tag) { if (tag) return image.lock_shared(cookie, tag); else return image.lock_exclusive(cookie); } static int do_lock_remove(librbd::Image& image, const char *client, const char *cookie) { return image.break_lock(client, cookie); } static void rbd_bencher_completion(void *c, void *pc); struct rbd_bencher; struct rbd_bencher { librbd::Image *image; Mutex lock; Cond cond; int in_flight; rbd_bencher(librbd::Image *i) : image(i), lock("rbd_bencher::lock"), in_flight(0) { } bool start_write(int max, uint64_t off, uint64_t len, bufferlist& bl) { { Mutex::Locker l(lock); if (in_flight >= max) return false; in_flight++; } librbd::RBD::AioCompletion *c = new librbd::RBD::AioCompletion((void *)this, rbd_bencher_completion); image->aio_write(off, len, bl, c); //cout << "start " << c << " at " << off << "~" << len << std::endl; return true; } void wait_for(int max) { Mutex::Locker l(lock); while (in_flight > max) { utime_t dur; dur.set_from_double(.2); cond.WaitInterval(g_ceph_context, lock, dur); } } }; void rbd_bencher_completion(void *vc, void *pc) { librbd::RBD::AioCompletion *c = (librbd::RBD::AioCompletion *)vc; rbd_bencher *b = static_cast(pc); //cout << "complete " << c << std::endl; int ret = c->get_return_value(); if (ret != 0) { cout << "write error: " << cpp_strerror(ret) << std::endl; assert(0 == ret); } b->lock.Lock(); b->in_flight--; b->cond.Signal(); b->lock.Unlock(); c->release(); } static int do_bench_write(librbd::Image& image, uint64_t io_size, uint64_t io_threads, uint64_t io_bytes, string pattern) { rbd_bencher b(&image); cout << "bench-write " << " io_size " << io_size << " io_threads " << io_threads << " bytes " << io_bytes << " pattern " << pattern << std::endl; if (pattern != "rand" && pattern != "seq") return -EINVAL; srand(time(NULL) % (unsigned long) -1); bufferptr bp(io_size); memset(bp.c_str(), rand() & 0xff, io_size); bufferlist bl; bl.push_back(bp); utime_t start = ceph_clock_now(NULL); utime_t last; unsigned ios = 0; uint64_t size = 0; image.size(&size); vector thread_offset; uint64_t i; uint64_t start_pos; // disturb all thread's offset, used by seq write for (i = 0; i < io_threads; i++) { start_pos = (rand() % (size / io_size)) * io_size; thread_offset.push_back(start_pos); } printf(" SEC OPS OPS/SEC BYTES/SEC\n"); uint64_t off; for (off = 0; off < io_bytes; off += io_size) { b.wait_for(io_threads - 1); i = 0; while (i < io_threads && off < io_bytes && b.start_write(io_threads, thread_offset[i], io_size, bl)) { ++i; ++ios; off += io_size; if (pattern == "rand") { thread_offset[i] = (rand() % (size / io_size)) * io_size; } else { thread_offset[i] += io_size; if (thread_offset[i] + io_size > size) thread_offset[i] = 0; } } utime_t now = ceph_clock_now(NULL); utime_t elapsed = now - start; if (elapsed.sec() != last.sec()) { printf("%5d %8d %8.2lf %8.2lf\n", (int)elapsed, (int)(ios - io_threads), (double)(ios - io_threads) / elapsed, (double)(off - io_threads * io_size) / elapsed); last = elapsed; } } b.wait_for(0); int r = image.flush(); if (r < 0) { cerr << "Error flushing data at the end: " << cpp_strerror(r) << std::endl; } utime_t now = ceph_clock_now(NULL); double elapsed = now - start; printf("elapsed: %5d ops: %8d ops/sec: %8.2lf bytes/sec: %8.2lf\n", (int)elapsed, ios, (double)ios / elapsed, (double)off / elapsed); return 0; } struct ExportContext { librbd::Image *image; int fd; uint64_t totalsize; MyProgressContext pc; ExportContext(librbd::Image *i, int f, uint64_t t) : image(i), fd(f), totalsize(t), pc("Exporting image") {} }; static int export_read_cb(uint64_t ofs, size_t len, const char *buf, void *arg) { ssize_t ret; ExportContext *ec = static_cast(arg); int fd = ec->fd; static char *localbuf = NULL; static size_t maplen = 0; if (fd == 1) { if (!buf) { // can't seek stdout; need actual data to write if (maplen < len) { // never mapped, or need to map larger int r; if (localbuf != NULL){ if ((r = munmap(localbuf, len)) < 0) { cerr << "rbd: error " << r << "munmap'ing buffer" << std::endl; return errno; } } maplen = len; localbuf = (char *)mmap(NULL, maplen, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (localbuf == MAP_FAILED) { cerr << "rbd: MAP_FAILED mmap'ing buffer for zero writes" << std::endl; return -ENOMEM; } } ret = write(fd, localbuf, len); } else { ret = write(fd, buf, len); } } else { // not stdout if (!buf || buf_is_zero(buf, len)) { /* a hole */ return 0; } ret = lseek64(fd, ofs, SEEK_SET); if (ret < 0) return -errno; ret = write(fd, buf, len); ec->pc.update_progress(ofs, ec->totalsize); } if (ret < 0) return -errno; return 0; } static int do_export(librbd::Image& image, const char *path) { int64_t r; librbd::image_info_t info; int fd; r = image.stat(info, sizeof(info)); if (r < 0) return r; if (strcmp(path, "-") == 0) fd = 1; else fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd < 0) return -errno; ExportContext ec(&image, fd, info.size); r = image.read_iterate2(0, info.size, export_read_cb, (void *)&ec); if (r < 0) goto out; if (fd != 1) r = ftruncate(fd, info.size); if (r < 0) goto out; out: close(fd); if (r < 0) ec.pc.fail(); else ec.pc.finish(); return r; } static int export_diff_cb(uint64_t ofs, size_t _len, int exists, void *arg) { ExportContext *ec = static_cast(arg); int r; // extent bufferlist bl; __u8 tag = exists ? 'w' : 'z'; ::encode(tag, bl); ::encode(ofs, bl); uint64_t len = _len; ::encode(len, bl); r = bl.write_fd(ec->fd); if (r < 0) return r; if (exists) { // read block bl.clear(); r = ec->image->read(ofs, len, bl); if (r < 0) return r; r = bl.write_fd(ec->fd); if (r < 0) return r; } ec->pc.update_progress(ofs, ec->totalsize); return 0; } static int do_export_diff(librbd::Image& image, const char *fromsnapname, const char *endsnapname, const char *path) { int r; librbd::image_info_t info; int fd; r = image.stat(info, sizeof(info)); if (r < 0) return r; if (strcmp(path, "-") == 0) fd = 1; else fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd < 0) return -errno; { // header bufferlist bl; bl.append(RBD_DIFF_BANNER, strlen(RBD_DIFF_BANNER)); __u8 tag; if (fromsnapname) { tag = 'f'; ::encode(tag, bl); string from(fromsnapname); ::encode(from, bl); } if (endsnapname) { tag = 't'; ::encode(tag, bl); string to(endsnapname); ::encode(to, bl); } tag = 's'; ::encode(tag, bl); uint64_t endsize = info.size; ::encode(endsize, bl); r = bl.write_fd(fd); if (r < 0) { close(fd); return r; } } ExportContext ec(&image, fd, info.size); r = image.diff_iterate(fromsnapname, 0, info.size, export_diff_cb, (void *)&ec); if (r < 0) goto out; { __u8 tag = 'e'; bufferlist bl; ::encode(tag, bl); r = bl.write_fd(fd); } out: close(fd); if (r < 0) ec.pc.fail(); else ec.pc.finish(); return r; } struct output_method { output_method() : f(NULL), t(NULL), empty(true) {} Formatter *f; TextTable *t; bool empty; }; static int diff_cb(uint64_t ofs, size_t len, int exists, void *arg) { output_method *om = static_cast(arg); om->empty = false; if (om->f) { om->f->open_object_section("extent"); om->f->dump_unsigned("offset", ofs); om->f->dump_unsigned("length", len); om->f->dump_string("exists", exists ? "true" : "false"); om->f->close_section(); } else { assert(om->t); *(om->t) << ofs << len << (exists ? "data" : "zero") << TextTable::endrow; } return 0; } static int do_diff(librbd::Image& image, const char *fromsnapname, Formatter *f) { int r; librbd::image_info_t info; r = image.stat(info, sizeof(info)); if (r < 0) return r; output_method om; if (f) { om.f = f; f->open_array_section("extents"); } else { om.t = new TextTable(); om.t->define_column("Offset", TextTable::LEFT, TextTable::LEFT); om.t->define_column("Length", TextTable::LEFT, TextTable::LEFT); om.t->define_column("Type", TextTable::LEFT, TextTable::LEFT); } r = image.diff_iterate(fromsnapname, 0, info.size, diff_cb, &om); if (f) { f->close_section(); f->flush(cout); } else { if (!om.empty) cout << *om.t; delete om.t; } return r; } static const char *imgname_from_path(const char *path) { const char *imgname; imgname = strrchr(path, '/'); if (imgname) imgname++; else imgname = path; return imgname; } static void update_snap_name(char *imgname, char **snap) { char *s; s = strrchr(imgname, '@'); if (!s) return; *s = '\0'; if (!snap) return; s++; if (*s) *snap = s; } static void set_pool_image_name(const char *orig_pool, const char *orig_img, char **new_pool, char **new_img, char **snap) { const char *sep; if (!orig_img) return; sep = strchr(orig_img, '/'); if (!sep) { *new_img = strdup(orig_img); goto done_img; } *new_pool = strdup(orig_img); sep = strchr(*new_pool, '/'); assert (sep); *(char *)sep = '\0'; *new_img = strdup(sep + 1); done_img: update_snap_name(*new_img, snap); } static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx, const char *imgname, int *order, const char *path, int format, uint64_t features, uint64_t size) { int fd, r; struct stat stat_buf; MyProgressContext pc("Importing image"); assert(imgname); // default order as usual if (*order == 0) *order = 22; // try to fill whole imgblklen blocks for sparsification uint64_t image_pos = 0; size_t imgblklen = 1 << *order; char *p = new char[imgblklen]; size_t reqlen = imgblklen; // amount requested from read ssize_t readlen; // amount received from one read size_t blklen = 0; // amount accumulated from reads to fill blk librbd::Image image; bool from_stdin = !strcmp(path, "-"); if (from_stdin) { fd = 0; size = 1ULL << *order; } else { if ((fd = open(path, O_RDONLY)) < 0) { r = -errno; cerr << "rbd: error opening " << path << std::endl; goto done2; } if ((fstat(fd, &stat_buf)) < 0) { r = -errno; cerr << "rbd: stat error " << path << std::endl; goto done; } if (S_ISDIR(stat_buf.st_mode)) { r = -EISDIR; cerr << "rbd: cannot import a directory" << std::endl; goto done; } if (stat_buf.st_size) size = (uint64_t)stat_buf.st_size; if (!size) { int64_t bdev_size = 0; r = get_block_device_size(fd, &bdev_size); if (r < 0) { cerr << "rbd: unable to get size of file/block device" << std::endl; goto done; } assert(bdev_size >= 0); size = (uint64_t) bdev_size; } } r = do_create(rbd, io_ctx, imgname, size, order, format, features, 0, 0); if (r < 0) { cerr << "rbd: image creation failed" << std::endl; goto done; } r = rbd.open(io_ctx, image, imgname); if (r < 0) { cerr << "rbd: failed to open image" << std::endl; goto done; } // loop body handles 0 return, as we may have a block to flush while ((readlen = ::read(fd, p + blklen, reqlen)) >= 0) { blklen += readlen; // if read was short, try again to fill the block before writing if (readlen && ((size_t)readlen < reqlen)) { reqlen -= readlen; continue; } if (!from_stdin) pc.update_progress(image_pos, size); bufferlist bl(blklen); bl.append(p, blklen); // resize output image by binary expansion as we go for stdin if (from_stdin && (image_pos + (size_t)blklen) > size) { size *= 2; r = image.resize(size); if (r < 0) { cerr << "rbd: can't resize image during import" << std::endl; goto done; } } // write as much as we got; perhaps less than imgblklen // but skip writing zeros to create sparse images if (!bl.is_zero()) { r = image.write(image_pos, blklen, bl); if (r < 0) { cerr << "rbd: error writing to image position " << image_pos << std::endl; goto done; } } // done with whole block, whether written or not image_pos += blklen; // if read had returned 0, we're at EOF and should quit if (readlen == 0) break; blklen = 0; reqlen = imgblklen; } if (from_stdin) { r = image.resize(image_pos); if (r < 0) { cerr << "rbd: final image resize failed" << std::endl; goto done; } } r = 0; done: if (!from_stdin) { if (r < 0) pc.fail(); else pc.finish(); close(fd); } done2: delete[] p; return r; } static int read_string(int fd, unsigned max, string *out) { char buf[4]; int r = safe_read_exact(fd, buf, 4); if (r < 0) return r; bufferlist bl; bl.append(buf, 4); bufferlist::iterator p = bl.begin(); uint32_t len; ::decode(len, p); if (len > max) return -EINVAL; char sbuf[len]; r = safe_read_exact(fd, sbuf, len); if (r < 0) return r; out->assign(sbuf, len); return len; } static int do_import_diff(librbd::Image &image, const char *path) { int fd, r; struct stat stat_buf; MyProgressContext pc("Importing image diff"); uint64_t size = 0; uint64_t off = 0; string from, to; bool from_stdin = !strcmp(path, "-"); if (from_stdin) { fd = 0; } else { fd = open(path, O_RDONLY); if (fd < 0) { r = -errno; cerr << "rbd: error opening " << path << std::endl; return r; } r = ::fstat(fd, &stat_buf); if (r < 0) goto done; size = (uint64_t)stat_buf.st_size; } char buf[strlen(RBD_DIFF_BANNER) + 1]; r = safe_read_exact(fd, buf, strlen(RBD_DIFF_BANNER)); if (r < 0) goto done; buf[strlen(RBD_DIFF_BANNER)] = '\0'; if (strcmp(buf, RBD_DIFF_BANNER)) { cerr << "invalid banner '" << buf << "', expected '" << RBD_DIFF_BANNER << "'" << std::endl; r = -EINVAL; goto done; } while (true) { __u8 tag; r = safe_read_exact(fd, &tag, 1); if (r < 0) { goto done; } if (tag == 'e') { dout(2) << " end diff" << dendl; break; } else if (tag == 'f') { r = read_string(fd, 4096, &from); // 4k limit to make sure we don't get a garbage string if (r < 0) goto done; dout(2) << " from snap " << from << dendl; if (!image.snap_exists(from.c_str())) { cerr << "start snapshot '" << from << "' does not exist in the image, aborting" << std::endl; r = -EINVAL; goto done; } } else if (tag == 't') { r = read_string(fd, 4096, &to); // 4k limit to make sure we don't get a garbage string if (r < 0) goto done; dout(2) << " to snap " << to << dendl; // verify this snap isn't already present if (image.snap_exists(to.c_str())) { cerr << "end snapshot '" << to << "' already exists, aborting" << std::endl; r = -EEXIST; goto done; } } else if (tag == 's') { uint64_t end_size; char buf[8]; r = safe_read_exact(fd, buf, 8); if (r < 0) goto done; bufferlist bl; bl.append(buf, 8); bufferlist::iterator p = bl.begin(); ::decode(end_size, p); uint64_t cur_size; image.size(&cur_size); if (cur_size != end_size) { dout(2) << "resize " << cur_size << " -> " << end_size << dendl; image.resize(end_size); } else { dout(2) << "size " << end_size << " (no change)" << dendl; } if (from_stdin) size = end_size; } else if (tag == 'w' || tag == 'z') { uint64_t len; char buf[16]; r = safe_read_exact(fd, buf, 16); if (r < 0) goto done; bufferlist bl; bl.append(buf, 16); bufferlist::iterator p = bl.begin(); ::decode(off, p); ::decode(len, p); if (tag == 'w') { bufferptr bp = buffer::create(len); r = safe_read_exact(fd, bp.c_str(), len); if (r < 0) goto done; bufferlist data; data.append(bp); dout(2) << " write " << off << "~" << len << dendl; image.write(off, len, data); } else { dout(2) << " zero " << off << "~" << len << dendl; image.discard(off, len); } } else { cerr << "unrecognized tag byte " << (int)tag << " in stream; aborting" << std::endl; r = -EINVAL; goto done; } if (!from_stdin) { // progress through input uint64_t off = lseek64(fd, 0, SEEK_CUR); pc.update_progress(off, size); } else if (size) { // progress through image offsets. this may jitter if blocks // aren't in order, but it is better than nothing. pc.update_progress(off, size); } } // take final snap if (to.length()) { dout(2) << " create end snap " << to << dendl; r = image.snap_create(to.c_str()); } done: if (r < 0) pc.fail(); else pc.finish(); if (!from_stdin) close(fd); return r; } static int do_copy(librbd::Image &src, librados::IoCtx& dest_pp, const char *destname) { MyProgressContext pc("Image copy"); int r = src.copy_with_progress(dest_pp, destname, pc); if (r < 0){ pc.fail(); return r; } pc.finish(); return 0; } class RbdWatchCtx : public librados::WatchCtx { string name; public: RbdWatchCtx(const char *imgname) : name(imgname) {} virtual ~RbdWatchCtx() {} virtual void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) { cout << name << " got notification opcode=" << (int)opcode << " ver=" << ver << " bl.length=" << bl.length() << std::endl; } }; static int do_watch(librados::IoCtx& pp, const char *imgname) { string md_oid, dest_md_oid; uint64_t cookie; RbdWatchCtx ctx(imgname); string old_header_oid = imgname; old_header_oid += RBD_SUFFIX; string new_header_oid = RBD_HEADER_PREFIX; new_header_oid += imgname; bool old_format = true; int r = pp.stat(old_header_oid, NULL, NULL); if (r < 0) { r = pp.stat(new_header_oid, NULL, NULL); if (r < 0) return r; old_format = false; } r = pp.watch(old_format ? old_header_oid : new_header_oid, 0, &cookie, &ctx); if (r < 0) { cerr << "rbd: watch failed" << std::endl; return r; } cout << "press enter to exit..." << std::endl; getchar(); return 0; } static int do_kernel_add(const char *poolname, const char *imgname, const char *snapname) { MonMap monmap; int r = monmap.build_initial(g_ceph_context, cerr); if (r < 0) return r; map::const_iterator it = monmap.mon_addr.begin(); ostringstream oss; for (size_t i = 0; i < monmap.mon_addr.size(); ++i, ++it) { oss << it->second.addr; if (i + 1 < monmap.mon_addr.size()) oss << ","; } const char *user = g_conf->name.get_id().c_str(); oss << " name=" << user; char key_name[strlen(user) + strlen("client.") + 1]; snprintf(key_name, sizeof(key_name), "client.%s", user); KeyRing keyring; r = keyring.from_ceph_context(g_ceph_context); if (r == -ENOENT && !(g_conf->keyfile.length() || g_conf->key.length())) r = 0; if (r < 0) { cerr << "rbd: failed to get secret: " << cpp_strerror(r) << std::endl; return r; } CryptoKey secret; if (keyring.get_secret(g_conf->name, secret)) { string secret_str; secret.encode_base64(secret_str); r = set_kernel_secret(secret_str.c_str(), key_name); if (r >= 0) { if (r == 0) cerr << "rbd: warning: secret has length 0" << std::endl; oss << ",key=" << key_name; } else if (r == -ENODEV || r == -ENOSYS) { /* running against older kernel; fall back to secret= in options */ oss << ",secret=" << secret_str; } else { cerr << "rbd: failed to add ceph secret key '" << key_name << "' to kernel: " << cpp_strerror(r) << std::endl; return r; } } else if (is_kernel_secret(key_name)) { oss << ",key=" << key_name; } for (map::const_iterator it = map_options.begin(); it != map_options.end(); ++it) { // for compatibility with < 3.7 kernels, assume that rw is on by // default and omit it even if it was specified by the user // (see ceph.git commit fb0f1986449b) if (it->first == "rw" && it->second == "rw") continue; oss << "," << it->second; } oss << " " << poolname << " " << imgname; if (snapname) { oss << " " << snapname; } // modprobe the rbd module if /sys/bus/rbd doesn't exist struct stat sb; if ((stat("/sys/bus/rbd", &sb) < 0) || (!S_ISDIR(sb.st_mode))) { // turn on single-major device number allocation scheme if the // kernel supports it const char *cmd = "/sbin/modprobe rbd"; r = system("/sbin/modinfo -F parm rbd | /bin/grep -q ^single_major:"); if (r == 0) { cmd = "/sbin/modprobe rbd single_major=Y"; } else if (r < 0) { cerr << "rbd: error executing modinfo as shell command!" << std::endl; } r = system(cmd); if (r) { if (r < 0) cerr << "rbd: error executing modprobe as shell command!" << std::endl; else cerr << "rbd: modprobe rbd failed! (" << r << ")" < device_dir(opendir(devices_path), do_closedir); if (!device_dir.get()) { r = -errno; cerr << "rbd: could not open " << devices_path << ": " << cpp_strerror(-r) << std::endl; return r; } struct dirent *dent; dent = readdir(device_dir.get()); if (!dent) { r = -errno; cerr << "rbd: error reading " << devices_path << ": " << cpp_strerror(-r) << std::endl; return r; } if (f) { f->open_object_section("devices"); } else { tbl.define_column("id", TextTable::LEFT, TextTable::LEFT); tbl.define_column("pool", TextTable::LEFT, TextTable::LEFT); tbl.define_column("image", TextTable::LEFT, TextTable::LEFT); tbl.define_column("snap", TextTable::LEFT, TextTable::LEFT); tbl.define_column("device", TextTable::LEFT, TextTable::LEFT); } do { if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; char fn[PATH_MAX]; char dev[PATH_MAX]; snprintf(dev, sizeof(dev), "/dev/rbd%s", dent->d_name); char name[RBD_MAX_IMAGE_NAME_SIZE]; snprintf(fn, sizeof(fn), "%s/%s/name", devices_path, dent->d_name); r = read_file(fn, name, sizeof(name)); if (r < 0) { cerr << "rbd: could not read name from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } char pool[4096]; snprintf(fn, sizeof(fn), "%s/%s/pool", devices_path, dent->d_name); r = read_file(fn, pool, sizeof(pool)); if (r < 0) { cerr << "rbd: could not read name from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } char snap[4096]; snprintf(fn, sizeof(fn), "%s/%s/current_snap", devices_path, dent->d_name); r = read_file(fn, snap, sizeof(snap)); if (r < 0) { cerr << "rbd: could not read name from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } if (f) { f->open_object_section(dent->d_name); f->dump_string("pool", pool); f->dump_string("name", name); f->dump_string("snap", snap); f->dump_string("device", dev); f->close_section(); } else { tbl << dent->d_name << pool << name << snap << dev << TextTable::endrow; } have_output = true; } while ((dent = readdir(device_dir.get()))); if (f) { f->close_section(); f->flush(cout); } else { if (have_output) cout << tbl; } return 0; } static int get_rbd_seq(dev_t devno, string &seq) { // convert devno, which might be a partition major:minor pair, into // a whole disk major:minor pair dev_t wholediskno; int r = blkid_devno_to_wholedisk(devno, NULL, 0, &wholediskno); if (r) { cerr << "rbd: could not compute wholediskno: " << r << std::endl; // ignore the error: devno == wholediskno most of the time, and if // it turns out it's not we will fail with -ENOENT later anyway wholediskno = devno; } const char *devices_path = "/sys/bus/rbd/devices"; DIR *device_dir = opendir(devices_path); if (!device_dir) { r = -errno; cerr << "rbd: could not open " << devices_path << ": " << cpp_strerror(-r) << std::endl; return r; } struct dirent *dent; dent = readdir(device_dir); if (!dent) { r = -errno; cerr << "Error reading " << devices_path << ": " << cpp_strerror(-r) << std::endl; closedir(device_dir); return r; } int match_minor = -1; do { char fn[strlen(devices_path) + strlen(dent->d_name) + strlen("//major") + 1]; char buf[32]; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; snprintf(fn, sizeof(fn), "%s/%s/major", devices_path, dent->d_name); r = read_file(fn, buf, sizeof(buf)); if (r < 0) { cerr << "rbd: could not read major number from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } string err; int cur_major = strict_strtol(buf, 10, &err); if (!err.empty()) { cerr << err << std::endl; cerr << "rbd: could not parse major number read from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } if (cur_major != (int)major(wholediskno)) continue; if (match_minor == -1) { // matching minors in addition to majors is not necessary unless // single-major scheme is turned on, but, if the kernel supports // it, do it anyway (blkid stuff above ensures that we always have // the correct minor to match with) struct stat sbuf; snprintf(fn, sizeof(fn), "%s/%s/minor", devices_path, dent->d_name); match_minor = (stat(fn, &sbuf) == 0); } if (match_minor == 1) { snprintf(fn, sizeof(fn), "%s/%s/minor", devices_path, dent->d_name); r = read_file(fn, buf, sizeof(buf)); if (r < 0) { cerr << "rbd: could not read minor number from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } int cur_minor = strict_strtol(buf, 10, &err); if (!err.empty()) { cerr << err << std::endl; cerr << "rbd: could not parse minor number read from " << fn << ": " << cpp_strerror(-r) << std::endl; continue; } if (cur_minor != (int)minor(wholediskno)) continue; } else { assert(match_minor == 0); } seq = string(dent->d_name); closedir(device_dir); return 0; } while ((dent = readdir(device_dir))); closedir(device_dir); return -ENOENT; } static int do_kernel_rm(const char *dev) { struct stat sbuf; if (stat(dev, &sbuf) || !S_ISBLK(sbuf.st_mode)) { cerr << "rbd: " << dev << " is not a block device" << std::endl; return -EINVAL; } string seq_num; int r = get_rbd_seq(sbuf.st_rdev, seq_num); if (r == -ENOENT) { cerr << "rbd: " << dev << " is not an rbd device" << std::endl; return -EINVAL; } if (r < 0) return r; // let udevadm do its job *before* we try to unmap if (udevadm_settle) { int r = system("/sbin/udevadm settle"); if (r) { if (r < 0) cerr << "rbd: error executing udevadm as shell command!" << std::endl; else cerr << "rbd: '/sbin/udevadm settle' failed! (" << r << ")" <::const_iterator it = map_options.find(key); if (it != map_options.end()) { cerr << "rbd: warning: redefining map option " << key << ": '" << it->second << "' -> '" << val << "'" << std::endl; } map_options[key] = val; } static int put_map_option_value(const string opt, const char *value_char, string (*parse_cb)(const char *)) { if (!value_char || *value_char == '\0') { cerr << "rbd: " << opt << " option requires a value" << std::endl; return 1; } string value = parse_cb(value_char); if (value.empty()) { cerr << "rbd: invalid " << opt << " value '" << value_char << "'" << std::endl; return 1; } put_map_option(opt, opt + "=" + value); return 0; } static int parse_map_options(char *options) { for (char *this_char = strtok(options, ", "); this_char != NULL; this_char = strtok(NULL, ",")) { char *value_char; if ((value_char = strchr(this_char, '=')) != NULL) *value_char++ = '\0'; if (!strcmp(this_char, "fsid")) { if (put_map_option_value("fsid", value_char, map_option_uuid_cb)) return 1; } else if (!strcmp(this_char, "ip")) { if (put_map_option_value("ip", value_char, map_option_ip_cb)) return 1; } else if (!strcmp(this_char, "share") || !strcmp(this_char, "noshare")) { put_map_option("share", this_char); } else if (!strcmp(this_char, "crc") || !strcmp(this_char, "nocrc")) { put_map_option("crc", this_char); } else if (!strcmp(this_char, "mount_timeout")) { if (put_map_option_value("mount_timeout", value_char, map_option_int_cb)) return 1; } else if (!strcmp(this_char, "osdkeepalive")) { if (put_map_option_value("osdkeepalive", value_char, map_option_int_cb)) return 1; } else if (!strcmp(this_char, "osd_idle_ttl")) { if (put_map_option_value("osd_idle_ttl", value_char, map_option_int_cb)) return 1; } else if (!strcmp(this_char, "rw") || !strcmp(this_char, "ro")) { put_map_option("rw", this_char); } else { cerr << "rbd: unknown map option '" << this_char << "'" << std::endl; return 1; } } return 0; } enum { OPT_NO_CMD = 0, OPT_LIST, OPT_INFO, OPT_CREATE, OPT_CLONE, OPT_FLATTEN, OPT_CHILDREN, OPT_RESIZE, OPT_RM, OPT_EXPORT, OPT_EXPORT_DIFF, OPT_DIFF, OPT_IMPORT, OPT_IMPORT_DIFF, OPT_COPY, OPT_RENAME, OPT_SNAP_CREATE, OPT_SNAP_ROLLBACK, OPT_SNAP_REMOVE, OPT_SNAP_LIST, OPT_SNAP_PURGE, OPT_SNAP_PROTECT, OPT_SNAP_UNPROTECT, OPT_WATCH, OPT_MAP, OPT_UNMAP, OPT_SHOWMAPPED, OPT_LOCK_LIST, OPT_LOCK_ADD, OPT_LOCK_REMOVE, OPT_BENCH_WRITE, }; static int get_cmd(const char *cmd, bool snapcmd, bool lockcmd) { if (!snapcmd && !lockcmd) { if (strcmp(cmd, "ls") == 0 || strcmp(cmd, "list") == 0) return OPT_LIST; if (strcmp(cmd, "info") == 0) return OPT_INFO; if (strcmp(cmd, "create") == 0) return OPT_CREATE; if (strcmp(cmd, "clone") == 0) return OPT_CLONE; if (strcmp(cmd, "flatten") == 0) return OPT_FLATTEN; if (strcmp(cmd, "children") == 0) return OPT_CHILDREN; if (strcmp(cmd, "resize") == 0) return OPT_RESIZE; if (strcmp(cmd, "rm") == 0) return OPT_RM; if (strcmp(cmd, "export") == 0) return OPT_EXPORT; if (strcmp(cmd, "export-diff") == 0) return OPT_EXPORT_DIFF; if (strcmp(cmd, "diff") == 0) return OPT_DIFF; if (strcmp(cmd, "import") == 0) return OPT_IMPORT; if (strcmp(cmd, "import-diff") == 0) return OPT_IMPORT_DIFF; if (strcmp(cmd, "copy") == 0 || strcmp(cmd, "cp") == 0) return OPT_COPY; if (strcmp(cmd, "rename") == 0 || strcmp(cmd, "mv") == 0) return OPT_RENAME; if (strcmp(cmd, "watch") == 0) return OPT_WATCH; if (strcmp(cmd, "map") == 0) return OPT_MAP; if (strcmp(cmd, "showmapped") == 0) return OPT_SHOWMAPPED; if (strcmp(cmd, "unmap") == 0) return OPT_UNMAP; if (strcmp(cmd, "bench-write") == 0) return OPT_BENCH_WRITE; } else if (snapcmd) { if (strcmp(cmd, "create") == 0 || strcmp(cmd, "add") == 0) return OPT_SNAP_CREATE; if (strcmp(cmd, "rollback") == 0 || strcmp(cmd, "revert") == 0) return OPT_SNAP_ROLLBACK; if (strcmp(cmd, "remove") == 0 || strcmp(cmd, "rm") == 0) return OPT_SNAP_REMOVE; if (strcmp(cmd, "ls") == 0 || strcmp(cmd, "list") == 0) return OPT_SNAP_LIST; if (strcmp(cmd, "purge") == 0) return OPT_SNAP_PURGE; if (strcmp(cmd, "protect") == 0) return OPT_SNAP_PROTECT; if (strcmp(cmd, "unprotect") == 0) return OPT_SNAP_UNPROTECT; } else { if (strcmp(cmd, "ls") == 0 || strcmp(cmd, "list") == 0) return OPT_LOCK_LIST; if (strcmp(cmd, "add") == 0) return OPT_LOCK_ADD; if (strcmp(cmd, "remove") == 0 || strcmp(cmd, "rm") == 0) return OPT_LOCK_REMOVE; } return OPT_NO_CMD; } /* * Called 1-N times depending on how many args the command needs. If * the positional varN is already set, set the next one; this handles * both --args above and unadorned args below. Calling with all args * filled is an error. */ static bool set_conf_param(const char *param, const char **var1, const char **var2, const char **var3) { if (!*var1) *var1 = param; else if (var2 && !*var2) *var2 = param; else if (var3 && !*var3) *var3 = param; else return false; return true; } bool size_set; int main(int argc, const char **argv) { librados::Rados rados; librbd::RBD rbd; librados::IoCtx io_ctx, dest_io_ctx; librbd::Image image; vector args; argv_to_vec(argc, argv, args); env_to_vec(args); int opt_cmd = OPT_NO_CMD; global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); const char *poolname = NULL; uint64_t size = 0; // in bytes int order = 0; bool format_specified = false, output_format_specified = false; int format = 1; uint64_t features = RBD_FEATURE_LAYERING; const char *imgname = NULL, *snapname = NULL, *destname = NULL, *dest_poolname = NULL, *dest_snapname = NULL, *path = NULL, *devpath = NULL, *lock_cookie = NULL, *lock_client = NULL, *lock_tag = NULL, *output_format = "plain", *fromsnapname = NULL; bool lflag = false; int pretty_format = 0; long long stripe_unit = 0, stripe_count = 0; long long bench_io_size = 4096, bench_io_threads = 16, bench_bytes = 1 << 30; string bench_pattern = "seq"; std::string val; std::ostringstream err; long long sizell = 0; std::vector::iterator i; for (i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_witharg(args, i, &val, "--secret", (char*)NULL)) { int r = g_conf->set_val("keyfile", val.c_str()); assert(r == 0); } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); return 0; } else if (ceph_argparse_flag(args, i, "--new-format", (char*)NULL)) { format = 2; format_specified = true; } else if (ceph_argparse_withint(args, i, &format, &err, "--image-format", (char*)NULL)) { if (!err.str().empty()) { cerr << "rbd: " << err.str() << std::endl; return EXIT_FAILURE; } format_specified = true; } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { poolname = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--dest-pool", (char*)NULL)) { dest_poolname = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--snap", (char*)NULL)) { snapname = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--from-snap", (char*)NULL)) { fromsnapname = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "-i", "--image", (char*)NULL)) { imgname = strdup(val.c_str()); } else if (ceph_argparse_withlonglong(args, i, &sizell, &err, "-s", "--size", (char*)NULL)) { if (!err.str().empty()) { cerr << "rbd: " << err.str() << std::endl; return EXIT_FAILURE; } if (sizell < 0) { cerr << "rbd: size must be >= 0" << std::endl; return EXIT_FAILURE; } size = sizell << 20; // bytes to MB size_set = true; } else if (ceph_argparse_flag(args, i, "-l", "--long", (char*)NULL)) { lflag = true; } else if (ceph_argparse_withlonglong(args, i, &stripe_unit, &err, "--stripe-unit", (char*)NULL)) { } else if (ceph_argparse_withlonglong(args, i, &stripe_count, &err, "--stripe-count", (char*)NULL)) { } else if (ceph_argparse_withint(args, i, &order, &err, "--order", (char*)NULL)) { if (!err.str().empty()) { cerr << "rbd: " << err.str() << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_withlonglong(args, i, &bench_io_size, &err, "--io-size", (char*)NULL)) { } else if (ceph_argparse_withlonglong(args, i, &bench_io_threads, &err, "--io-threads", (char*)NULL)) { } else if (ceph_argparse_withlonglong(args, i, &bench_bytes, &err, "--io-total", (char*)NULL)) { } else if (ceph_argparse_witharg(args, i, &bench_pattern, &err, "--io-pattern", (char*)NULL)) { } else if (ceph_argparse_withlonglong(args, i, &stripe_count, &err, "--stripe-count", (char*)NULL)) { } else if (ceph_argparse_witharg(args, i, &val, "--path", (char*)NULL)) { path = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--dest", (char*)NULL)) { destname = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--parent", (char *)NULL)) { imgname = strdup(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--shared", (char *)NULL)) { lock_tag = strdup(val.c_str()); } else if (ceph_argparse_flag(args, i, "--no-settle", (char *)NULL)) { udevadm_settle = false; } else if (ceph_argparse_witharg(args, i, &val, "-o", "--options", (char*)NULL)) { char *map_options = strdup(val.c_str()); if (parse_map_options(map_options)) { cerr << "rbd: couldn't parse map options" << std::endl; return EXIT_FAILURE; } } else if (ceph_argparse_flag(args, i, "--read-only", (char *)NULL)) { // --read-only is equivalent to -o ro put_map_option("rw", "ro"); } else if (ceph_argparse_flag(args, i, "--no-progress", (char *)NULL)) { progress = false; } else if (ceph_argparse_flag(args, i , "--allow-shrink", (char *)NULL)) { resize_allow_shrink = true; } else if (ceph_argparse_witharg(args, i, &val, "--format", (char *) NULL)) { std::string err; long long ret = strict_strtoll(val.c_str(), 10, &err); if (err.empty()) { format = ret; format_specified = true; cerr << "rbd: using --format for specifying the rbd image format is" << " deprecated, use --image-format instead" << std::endl; } else { output_format = strdup(val.c_str()); output_format_specified = true; } } else if (ceph_argparse_binary_flag(args, i, &pretty_format, NULL, "--pretty-format", (char*)NULL)) { } else { ++i; } } common_init_finish(g_ceph_context); i = args.begin(); if (i == args.end()) { cerr << "rbd: you must specify a command." << std::endl; return EXIT_FAILURE; } else if (strcmp(*i, "snap") == 0) { i = args.erase(i); if (i == args.end()) { cerr << "rbd: which snap command do you want?" << std::endl; return EXIT_FAILURE; } opt_cmd = get_cmd(*i, true, false); } else if (strcmp(*i, "lock") == 0) { i = args.erase(i); if (i == args.end()) { cerr << "rbd: which lock command do you want?" << std::endl; return EXIT_FAILURE; } opt_cmd = get_cmd(*i, false, true); } else { opt_cmd = get_cmd(*i, false, false); } if (opt_cmd == OPT_NO_CMD) { cerr << "rbd: error parsing command '" << *i << "'; -h or --help for usage" << std::endl; return EXIT_FAILURE; } // loop across all remaining arguments; by command, accumulate any // that are still missing into the appropriate variables, one at a // time (i.e. SET_CONF_PARAM will be called N times for N remaining // arguments). #define SET_CONF_PARAM(v, p1, p2, p3) \ if (!set_conf_param(v, p1, p2, p3)) { \ cerr << "rbd: extraneous parameter " << v << std::endl; \ return EXIT_FAILURE; \ } for (i = args.erase(i); i != args.end(); ++i) { const char *v = *i; switch (opt_cmd) { case OPT_LIST: SET_CONF_PARAM(v, &poolname, NULL, NULL); break; case OPT_INFO: case OPT_CREATE: case OPT_FLATTEN: case OPT_RESIZE: case OPT_RM: case OPT_SNAP_CREATE: case OPT_SNAP_ROLLBACK: case OPT_SNAP_REMOVE: case OPT_SNAP_LIST: case OPT_SNAP_PURGE: case OPT_SNAP_PROTECT: case OPT_SNAP_UNPROTECT: case OPT_WATCH: case OPT_MAP: case OPT_BENCH_WRITE: case OPT_LOCK_LIST: case OPT_DIFF: SET_CONF_PARAM(v, &imgname, NULL, NULL); break; case OPT_UNMAP: SET_CONF_PARAM(v, &devpath, NULL, NULL); break; case OPT_EXPORT: case OPT_EXPORT_DIFF: SET_CONF_PARAM(v, &imgname, &path, NULL); break; case OPT_IMPORT: case OPT_IMPORT_DIFF: SET_CONF_PARAM(v, &path, &imgname, NULL); break; case OPT_COPY: case OPT_RENAME: case OPT_CLONE: SET_CONF_PARAM(v, &imgname, &destname, NULL); break; case OPT_SHOWMAPPED: cerr << "rbd: showmapped takes no parameters" << std::endl; return EXIT_FAILURE; case OPT_CHILDREN: SET_CONF_PARAM(v, &imgname, NULL, NULL); break; case OPT_LOCK_ADD: SET_CONF_PARAM(v, &imgname, &lock_cookie, NULL); break; case OPT_LOCK_REMOVE: SET_CONF_PARAM(v, &imgname, &lock_client, &lock_cookie); break; default: assert(0); break; } } if (format_specified && opt_cmd != OPT_IMPORT && opt_cmd != OPT_CREATE) { cerr << "rbd: image format can only be set when " << "creating or importing an image" << std::endl; return EXIT_FAILURE; } if (pretty_format && !strcmp(output_format, "plain")) { cerr << "rbd: --pretty-format only works when --format is json or xml" << std::endl; return EXIT_FAILURE; } boost::scoped_ptr formatter; if (output_format_specified && opt_cmd != OPT_SHOWMAPPED && opt_cmd != OPT_INFO && opt_cmd != OPT_LIST && opt_cmd != OPT_SNAP_LIST && opt_cmd != OPT_LOCK_LIST && opt_cmd != OPT_CHILDREN && opt_cmd != OPT_DIFF) { cerr << "rbd: command doesn't use output formatting" << std::endl; return EXIT_FAILURE; } else if (get_outfmt(output_format, pretty_format, &formatter) < 0) { return EXIT_FAILURE; } if (format_specified) { if (format < 1 || format > 2) { cerr << "rbd: image format must be 1 or 2" << std::endl; return EXIT_FAILURE; } } if (opt_cmd == OPT_EXPORT && !imgname) { cerr << "rbd: image name was not specified" << std::endl; return EXIT_FAILURE; } if ((opt_cmd == OPT_IMPORT || opt_cmd == OPT_IMPORT_DIFF) && !path) { cerr << "rbd: path was not specified" << std::endl; return EXIT_FAILURE; } if (opt_cmd == OPT_IMPORT && !destname) { destname = imgname; if (!destname) destname = imgname_from_path(path); imgname = NULL; } if (opt_cmd != OPT_LOCK_ADD && lock_tag) { cerr << "rbd: only the lock add command uses the --shared option" << std::endl; return EXIT_FAILURE; } if ((opt_cmd == OPT_LOCK_ADD || opt_cmd == OPT_LOCK_REMOVE) && !lock_cookie) { cerr << "rbd: lock id was not specified" << std::endl; return EXIT_FAILURE; } if (opt_cmd != OPT_LIST && opt_cmd != OPT_IMPORT && opt_cmd != OPT_IMPORT_DIFF && opt_cmd != OPT_UNMAP && opt_cmd != OPT_SHOWMAPPED && !imgname) { cerr << "rbd: image name was not specified" << std::endl; return EXIT_FAILURE; } if (opt_cmd == OPT_UNMAP && !devpath) { cerr << "rbd: device path was not specified" << std::endl; return EXIT_FAILURE; } // do this unconditionally so we can parse pool/image@snapshot into // the relevant parts set_pool_image_name(poolname, imgname, (char **)&poolname, (char **)&imgname, (char **)&snapname); if (snapname && opt_cmd != OPT_SNAP_CREATE && opt_cmd != OPT_SNAP_ROLLBACK && opt_cmd != OPT_SNAP_REMOVE && opt_cmd != OPT_INFO && opt_cmd != OPT_EXPORT && opt_cmd != OPT_EXPORT_DIFF && opt_cmd != OPT_DIFF && opt_cmd != OPT_COPY && opt_cmd != OPT_MAP && opt_cmd != OPT_CLONE && opt_cmd != OPT_SNAP_PROTECT && opt_cmd != OPT_SNAP_UNPROTECT && opt_cmd != OPT_CHILDREN) { cerr << "rbd: snapname specified for a command that doesn't use it" << std::endl; return EXIT_FAILURE; } if ((opt_cmd == OPT_SNAP_CREATE || opt_cmd == OPT_SNAP_ROLLBACK || opt_cmd == OPT_SNAP_REMOVE || opt_cmd == OPT_CLONE || opt_cmd == OPT_SNAP_PROTECT || opt_cmd == OPT_SNAP_UNPROTECT || opt_cmd == OPT_CHILDREN) && !snapname) { cerr << "rbd: snap name was not specified" << std::endl; return EXIT_FAILURE; } set_pool_image_name(dest_poolname, destname, (char **)&dest_poolname, (char **)&destname, (char **)&dest_snapname); if (opt_cmd == OPT_IMPORT) { if (poolname && dest_poolname) { cerr << "rbd: source and destination pool both specified" << std::endl; return EXIT_FAILURE; } if (imgname && destname) { cerr << "rbd: source and destination image both specified" << std::endl; return EXIT_FAILURE; } if (poolname) dest_poolname = poolname; } if (!poolname) poolname = "rbd"; if (!dest_poolname) dest_poolname = "rbd"; if (opt_cmd == OPT_EXPORT && !path) path = imgname; if ((opt_cmd == OPT_COPY || opt_cmd == OPT_CLONE || opt_cmd == OPT_RENAME) && !destname ) { cerr << "rbd: destination image name was not specified" << std::endl; return EXIT_FAILURE; } if ((opt_cmd == OPT_CLONE) && dest_snapname) { cerr << "rbd: cannot clone to a snapshot" << std::endl; return EXIT_FAILURE; } if ((opt_cmd == OPT_CLONE) && size) { cerr << "rbd: clone must begin at size of parent" << std::endl; return EXIT_FAILURE; } if ((opt_cmd == OPT_RENAME) && (strcmp(poolname, dest_poolname) != 0)) { cerr << "rbd: mv/rename across pools not supported" << std::endl; cerr << "source pool: " << poolname << " dest pool: " << dest_poolname << std::endl; return EXIT_FAILURE; } bool talk_to_cluster = (opt_cmd != OPT_MAP && opt_cmd != OPT_UNMAP && opt_cmd != OPT_SHOWMAPPED); if (talk_to_cluster && rados.init_with_context(g_ceph_context) < 0) { cerr << "rbd: couldn't initialize rados!" << std::endl; return EXIT_FAILURE; } if (talk_to_cluster && rados.connect() < 0) { cerr << "rbd: couldn't connect to the cluster!" << std::endl; return EXIT_FAILURE; } int r; if (talk_to_cluster && opt_cmd != OPT_IMPORT) { r = rados.ioctx_create(poolname, io_ctx); if (r < 0) { cerr << "rbd: error opening pool " << poolname << ": " << cpp_strerror(-r) << std::endl; return -r; } } if (imgname && talk_to_cluster && (opt_cmd == OPT_RESIZE || opt_cmd == OPT_SNAP_CREATE || opt_cmd == OPT_SNAP_ROLLBACK || opt_cmd == OPT_SNAP_REMOVE || opt_cmd == OPT_SNAP_PURGE || opt_cmd == OPT_SNAP_PROTECT || opt_cmd == OPT_SNAP_UNPROTECT || opt_cmd == OPT_WATCH || opt_cmd == OPT_FLATTEN || opt_cmd == OPT_LOCK_ADD || opt_cmd == OPT_LOCK_REMOVE || opt_cmd == OPT_BENCH_WRITE || opt_cmd == OPT_INFO || opt_cmd == OPT_SNAP_LIST || opt_cmd == OPT_IMPORT_DIFF || opt_cmd == OPT_EXPORT || opt_cmd == OPT_EXPORT_DIFF || opt_cmd == OPT_COPY || opt_cmd == OPT_DIFF || opt_cmd == OPT_CHILDREN || opt_cmd == OPT_LOCK_LIST)) { if (opt_cmd == OPT_INFO || opt_cmd == OPT_SNAP_LIST || opt_cmd == OPT_EXPORT || opt_cmd == OPT_EXPORT || opt_cmd == OPT_COPY || opt_cmd == OPT_CHILDREN || opt_cmd == OPT_LOCK_LIST) { r = rbd.open_read_only(io_ctx, image, imgname, NULL); } else { r = rbd.open(io_ctx, image, imgname); } if (r < 0) { cerr << "rbd: error opening image " << imgname << ": " << cpp_strerror(-r) << std::endl; return -r; } } if (snapname && talk_to_cluster && (opt_cmd == OPT_INFO || opt_cmd == OPT_EXPORT || opt_cmd == OPT_EXPORT_DIFF || opt_cmd == OPT_DIFF || opt_cmd == OPT_COPY || opt_cmd == OPT_CHILDREN)) { r = image.snap_set(snapname); if (r < 0) { cerr << "rbd: error setting snapshot context: " << cpp_strerror(-r) << std::endl; return -r; } } if (opt_cmd == OPT_COPY || opt_cmd == OPT_IMPORT || opt_cmd == OPT_CLONE) { r = rados.ioctx_create(dest_poolname, dest_io_ctx); if (r < 0) { cerr << "rbd: error opening pool " << dest_poolname << ": " << cpp_strerror(-r) << std::endl; return -r; } } if (opt_cmd == OPT_CREATE || opt_cmd == OPT_RESIZE) { if (!size_set) { cerr << "rbd: must specify --size " << std::endl; return EINVAL; } } switch (opt_cmd) { case OPT_LIST: r = do_list(rbd, io_ctx, lflag, formatter.get()); if (r < 0) { cerr << "rbd: list: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_CREATE: if (order && (order < 12 || order > 25)) { cerr << "rbd: order must be between 12 (4 KB) and 25 (32 MB)" << std::endl; return EINVAL; } if ((stripe_unit && !stripe_count) || (!stripe_unit && stripe_count)) { cerr << "must specify both (or neither) of stripe-unit and stripe-count" << std::endl; usage(); return EINVAL; } r = do_create(rbd, io_ctx, imgname, size, &order, format, features, stripe_unit, stripe_count); if (r < 0) { cerr << "rbd: create error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_CLONE: if (order && (order < 12 || order > 25)) { cerr << "rbd: order must be between 12 (4 KB) and 25 (32 MB)" << std::endl; return EINVAL; } r = do_clone(rbd, io_ctx, imgname, snapname, dest_io_ctx, destname, features, &order); if (r < 0) { cerr << "rbd: clone error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_FLATTEN: r = do_flatten(image); if (r < 0) { cerr << "rbd: flatten error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_RENAME: r = do_rename(rbd, io_ctx, imgname, destname); if (r < 0) { cerr << "rbd: rename error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_INFO: r = do_show_info(imgname, image, snapname, formatter.get()); if (r < 0) { cerr << "rbd: info: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_RM: r = do_delete(rbd, io_ctx, imgname); if (r < 0) { if (r == -ENOTEMPTY) { cerr << "rbd: image has snapshots - these must be deleted" << " with 'rbd snap purge' before the image can be removed." << std::endl; } else if (r == -EBUSY) { cerr << "rbd: error: image still has watchers" << std::endl << "This means the image is still open or the client using " << "it crashed. Try again after closing/unmapping it or " << "waiting 30s for the crashed client to timeout." << std::endl; } else { cerr << "rbd: delete error: " << cpp_strerror(-r) << std::endl; } return -r ; } break; case OPT_RESIZE: librbd::image_info_t info; r = image.stat(info, sizeof(info)); if (r < 0) { cerr << "rbd: resize error: " << cpp_strerror(-r) << std::endl; return -r; } if (info.size > size && !resize_allow_shrink) { cerr << "rbd: shrinking an image is only allowed with the --allow-shrink flag" << std::endl; return EINVAL; } r = do_resize(image, size); if (r < 0) { cerr << "rbd: resize error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SNAP_LIST: if (!imgname) { cerr << "rbd: snap list requires an image parameter" << std::endl; return EXIT_FAILURE; } r = do_list_snaps(image, formatter.get()); if (r < 0) { cerr << "rbd: failed to list snapshots: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SNAP_CREATE: if (!imgname || !snapname) { cerr << "rbd: snap create requires image and snapname" << std::endl; return EINVAL; } r = do_add_snap(image, snapname); if (r < 0) { cerr << "rbd: failed to create snapshot: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SNAP_ROLLBACK: if (!imgname) { cerr << "rbd: snap rollback requires image name" << std::endl; return EINVAL; } r = do_rollback_snap(image, snapname); if (r < 0) { cerr << "rbd: rollback failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SNAP_REMOVE: if (!imgname) { cerr << "rbd: snap remove requires image name" << std::endl; return EINVAL; } r = do_remove_snap(image, snapname); if (r < 0) { if (r == -EBUSY) { cerr << "rbd: snapshot '" << snapname << "' is protected from removal." << std::endl; } else { cerr << "rbd: failed to remove snapshot: " << cpp_strerror(-r) << std::endl; } return -r; } break; case OPT_SNAP_PURGE: if (!imgname) { cerr << "rbd: snap purge requires image name" << std::endl; return EINVAL; } r = do_purge_snaps(image); if (r < 0) { cerr << "rbd: removing snaps failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SNAP_PROTECT: if (!imgname) { cerr << "rbd: snap protect requires image name" << std::endl; return EINVAL; } r = do_protect_snap(image, snapname); if (r < 0) { cerr << "rbd: protecting snap failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SNAP_UNPROTECT: if (!imgname) { cerr << "rbd: snap unprotect requires image name" << std::endl; return EINVAL; } r = do_unprotect_snap(image, snapname); if (r < 0) { cerr << "rbd: unprotecting snap failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_CHILDREN: r = do_list_children(image, formatter.get()); if (r < 0) { cerr << "rbd: listing children failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_EXPORT: if (!path) { cerr << "rbd: export requires pathname" << std::endl; return EINVAL; } r = do_export(image, path); if (r < 0) { cerr << "rbd: export error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_DIFF: r = do_diff(image, fromsnapname, formatter.get()); if (r < 0) { cerr << "rbd: diff error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_EXPORT_DIFF: if (!path) { cerr << "rbd: export-diff requires pathname" << std::endl; return EINVAL; } r = do_export_diff(image, fromsnapname, snapname, path); if (r < 0) { cerr << "rbd: export-diff error: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_IMPORT: if (!path) { cerr << "rbd: import requires pathname" << std::endl; return EINVAL; } r = do_import(rbd, dest_io_ctx, destname, &order, path, format, features, size); if (r < 0) { cerr << "rbd: import failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_IMPORT_DIFF: assert(path); r = do_import_diff(image, path); if (r < 0) { cerr << "rbd: import-diff failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_COPY: r = do_copy(image, dest_io_ctx, destname); if (r < 0) { cerr << "rbd: copy failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_WATCH: r = do_watch(io_ctx, imgname); if (r < 0) { cerr << "rbd: watch failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_MAP: r = do_kernel_add(poolname, imgname, snapname); if (r < 0) { cerr << "rbd: add failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_UNMAP: r = do_kernel_rm(devpath); if (r < 0) { cerr << "rbd: remove failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_SHOWMAPPED: r = do_kernel_showmapped(formatter.get()); if (r < 0) { cerr << "rbd: showmapped failed: " << cpp_strerror(-r) << std::endl; return -r; } break; case OPT_LOCK_LIST: r = do_lock_list(image, formatter.get()); if (r < 0) { cerr << "rbd: listing locks failed: " << cpp_strerror(r) << std::endl; return -r; } break; case OPT_LOCK_ADD: r = do_lock_add(image, lock_cookie, lock_tag); if (r < 0) { if (r == -EBUSY || r == -EEXIST) { if (lock_tag) { cerr << "rbd: lock is alrady held by someone else" << " with a different tag" << std::endl; } else { cerr << "rbd: lock is already held by someone else" << std::endl; } } else { cerr << "rbd: taking lock failed: " << cpp_strerror(r) << std::endl; } return -r; } break; case OPT_LOCK_REMOVE: r = do_lock_remove(image, lock_cookie, lock_client); if (r < 0) { cerr << "rbd: releasing lock failed: " << cpp_strerror(r) << std::endl; return -r; } break; case OPT_BENCH_WRITE: r = do_bench_write(image, bench_io_size, bench_io_threads, bench_bytes, bench_pattern); if (r < 0) { cerr << "bench-write failed: " << cpp_strerror(-r) << std::endl; return -r; } break; } return 0; } ceph-0.80.11/src/README0000664000175100017510000000011112623076744016335 0ustar jenkins-buildjenkins-buildSage Weil Ceph - scalable distributed storage system ceph-0.80.11/install-sh0000755000175100017510000003325512261335263016677 0ustar jenkins-buildjenkins-build#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/share/0000775000175100017510000000000012623077033015767 5ustar jenkins-buildjenkins-buildceph-0.80.11/share/id_dsa_drop.ceph.com0000664000175100017510000000123412623076744021664 0ustar jenkins-buildjenkins-build-----BEGIN DSA PRIVATE KEY----- MIIBugIBAAKBgQDv8F/WToUDOc2HRWUOqtq5ilORE+5P53yZUo7ugr8XD3wM0H7Q IIl9F9fizwUtL2gh3n1BnBxmPhkVU6VYsiDpn1P3dWvRmf+jyqPuk+b185L0Erb8 QsExADv6v33Yyd+9i5oTI988Rm1VWY6QhP7neW6yMPt2noi1TwleLm6z2wIVAKHL ciT2S0w/dbTFQDFHSEOCAif3AoGAHwOYd8YEInrcBrXPFJuPFbQKr8ceO3/ItY0r /W/L92nXUJbdl1JEt2KfkdwaxkBhlYT7E1JR5MRoTNBTEMCFjHxemZCdH+03+Jzq +RAQ28p77przbqOFaMuZuQoGlqMy3gYrhnPRGEJGjh+pkhMePqUPCCKFtRntNzlH lDh4uOACgYBLGpqu3Pthhd4fnawv8Md16gc/p1Vg/5vyAzi9Gshhgf1hXvFHdeJv AN/5mgE/Ekg7fqeNUhui9LYkuuOMgP267naGkAAgxV3bbiy439Vj8SzXdOQk4agA YgebWkmJrdMtUSzeBYBkqBZTZODvQwCmYdR6INuNuZtA+rHgKwiAHQIUZak7aJD8 y4kap9GmduDYmp6/JxU= -----END DSA PRIVATE KEY----- ceph-0.80.11/share/id_dsa_drop.ceph.com.pub0000664000175100017510000000115512623076744022453 0ustar jenkins-buildjenkins-buildssh-dss AAAAB3NzaC1kc3MAAACBAO/wX9ZOhQM5zYdFZQ6q2rmKU5ET7k/nfJlSju6CvxcPfAzQftAgiX0X1+LPBS0vaCHefUGcHGY+GRVTpViyIOmfU/d1a9GZ/6PKo+6T5vXzkvQStvxCwTEAO/q/fdjJ372LmhMj3zxGbVVZjpCE/ud5brIw+3aeiLVPCV4ubrPbAAAAFQChy3Ik9ktMP3W0xUAxR0hDggIn9wAAAIAfA5h3xgQietwGtc8Um48VtAqvxx47f8i1jSv9b8v3addQlt2XUkS3Yp+R3BrGQGGVhPsTUlHkxGhM0FMQwIWMfF6ZkJ0f7Tf4nOr5EBDbynvumvNuo4Voy5m5CgaWozLeBiuGc9EYQkaOH6mSEx4+pQ8IIoW1Ge03OUeUOHi44AAAAIBLGpqu3Pthhd4fnawv8Md16gc/p1Vg/5vyAzi9Gshhgf1hXvFHdeJvAN/5mgE/Ekg7fqeNUhui9LYkuuOMgP267naGkAAgxV3bbiy439Vj8SzXdOQk4agAYgebWkmJrdMtUSzeBYBkqBZTZODvQwCmYdR6INuNuZtA+rHgKwiAHQ== public_ceph_post_key_2013-08-16 ceph-0.80.11/share/known_hosts_drop.ceph.com0000664000175100017510000000061312623076744023015 0ustar jenkins-buildjenkins-builddrop.ceph.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjl2XzIpS92snr4SymcBVQx7y6d/ZjzCKJAlGZYkgknWWf+JBEpXp+cOoMk2Td5pIPkOdn72pGAuuPzL9HSJpN/o75tzbv0mAd//3t9D5/Kpnd+tWIDDgj+RIz8ZKRxSR8lnVjsUHlTrwQwaUkZ3KDiVgtQXDp0+1rU1+02cEkeBStoMLQt/6xw1hmPGSIAMH2HRkyge+/I8RwK7jbTwwcxh61Vxe0qMGkDO6vUVXw+K6hoXV4uGaqZ9/B2GirXJPz6ulvLC/mtEdgtfKS3eiMTaJS5Cpne6rJw2Wm7kHfQPstJaUq06BJiRe6R+JHC897NVZd0yc1bZe+BI0PmQJL ceph-0.80.11/man/0000775000175100017510000000000012623077037015444 5ustar jenkins-buildjenkins-buildceph-0.80.11/man/ceph-authtool.80000664000175100017510000001620212623076744020316 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-AUTHTOOL" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-authtool \- ceph keyring manipulation tool . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-authtool\fP \fIkeyringfile\fP [ \-l | \-\-list ] [ \-C | \-\-create\-keyring ] [ \-p | \-\-print ] [ \-n | \-\-name \fIentityname\fP ] [ \-\-gen\-key ] [ \-a | \-\-add\-key \fIbase64_key\fP ] [ \-\-caps \fIcapfile\fP ] .fi .sp .SH DESCRIPTION .sp \fBceph\-authtool\fP is a utility to create, view, and modify a Ceph keyring file. A keyring file stores one or more Ceph authentication keys and possibly an associated capability specification. Each key is associated with an entity name, of the form \fB{client,mon,mds,osd}.name\fP\&. .sp \fBWARNING\fP Ceph provides authentication and protection against man\-in\-the\-middle attacks once secret keys are in place. However, data over the wire is not encrypted, which may include the messages used to configure said keys. The system is primarily intended to be used in trusted environments. .SH OPTIONS .INDENT 0.0 .TP .B \-l, \-\-list will list all keys and capabilities present in the keyring .UNINDENT .INDENT 0.0 .TP .B \-p, \-\-print will print an encoded key for the specified entityname. This is suitable for the \fBmount \-o secret=\fP argument .UNINDENT .INDENT 0.0 .TP .B \-C, \-\-create\-keyring will create a new keyring, overwriting any existing keyringfile .UNINDENT .INDENT 0.0 .TP .B \-\-gen\-key will generate a new secret key for the specified entityname .UNINDENT .INDENT 0.0 .TP .B \-\-add\-key will add an encoded key to the keyring .UNINDENT .INDENT 0.0 .TP .B \-\-cap subsystem capability will set the capability for given subsystem .UNINDENT .INDENT 0.0 .TP .B \-\-caps capsfile will set all of capabilities associated with a given key, for all subsystems .UNINDENT .SH CAPABILITIES .sp The subsystem is the name of a Ceph subsystem: \fBmon\fP, \fBmds\fP, or \fBosd\fP\&. .sp The capability is a string describing what the given user is allowed to do. This takes the form of a comma separated list of allow clauses with a permission specifier containing one or more of rwx for read, write, and execute permission. The \fBallow *\fP grants full superuser permissions for the given subsystem. .sp For example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C # can read, write, and execute objects osd = "allow rwx" # can access mds server mds = "allow" # can modify cluster state (i.e., is a server daemon) mon = "allow rwx" .ft P .fi .UNINDENT .UNINDENT .sp A librados user restricted to a single pool might look like: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mon = "allow r" osd = "allow rw pool foo" .ft P .fi .UNINDENT .UNINDENT .sp A client using rbd with read access to one pool and read/write access to another: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mon = "allow r" osd = "allow class\-read object_prefix rbd_children, allow pool templates r class\-read, allow pool vms rwx" .ft P .fi .UNINDENT .UNINDENT .sp A client mounting the file system with minimal permissions would need caps like: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mds = "allow" osd = "allow rw pool data" mon = "allow r" .ft P .fi .UNINDENT .UNINDENT .SH OSD CAPABILITIES .sp In general, an osd capability follows the grammar: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C osdcap := grant[,grant...] grant := allow (match capspec | capspec match) match := [pool[=] | object_prefix ] capspec := * | [r][w][x] [class\-read] [class\-write] .ft P .fi .UNINDENT .UNINDENT .sp The capspec determines what kind of operations the entity can perform: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C r = read access to objects w = write access to objects x = can call any class method (same as class\-read class\-write) class\-read = can call class methods that are reads class\-write = can call class methods that are writes * = equivalent to rwx, plus the ability to run osd admin commands, i.e. ceph osd tell ... .ft P .fi .UNINDENT .UNINDENT .sp The match criteria restrict a grant based on the pool being accessed. Grants are additive if the client fulfills the match condition. For example, if a client has the osd capabilities: "allow r object_prefix prefix, allow w pool foo, allow x pool bar", then it has rw access to pool foo, rx access to pool bar, and r access to objects whose names begin with \(aqprefix\(aq in any pool. .SH CAPS FILE FORMAT .sp The caps file format consists of zero or more key/value pairs, one per line. The key and value are separated by an \fB=\fP, and the value must be quoted (with \fB\(aq\fP or \fB"\fP) if it contains any whitespace. The key is the name of the Ceph subsystem (\fBosd\fP, \fBmds\fP, \fBmon\fP), and the value is the capability string (see above). .SH EXAMPLE .sp To create a new keyring containing a key for client.foo: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-authtool \-C \-n client.foo \-\-gen\-key keyring .ft P .fi .UNINDENT .UNINDENT .sp To associate some capabilities with the key (namely, the ability to mount a Ceph filesystem): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-authtool \-n client.foo \-\-cap mds \(aqallow\(aq \-\-cap osd \(aqallow rw pool=data\(aq \-\-cap mon \(aqallow r\(aq keyring .ft P .fi .UNINDENT .UNINDENT .sp To display the contents of the keyring: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-authtool \-l keyring .ft P .fi .UNINDENT .UNINDENT .sp When mount a Ceph file system, you can grab the appropriately encoded secret key with: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount \-t ceph serverhost:/ mountpoint \-o name=foo,secret=\(gaceph\-authtool \-p \-n client.foo keyring\(ga .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBceph\-authtool\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/radosgw.80000664000175100017510000001344212623076744017213 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "RADOSGW" "8" "January 12, 2014" "dev" "Ceph" .SH NAME radosgw \- rados REST gateway . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBradosgw\fP .fi .sp .SH DESCRIPTION .sp \fBradosgw\fP is an HTTP REST gateway for the RADOS object store, a part of the Ceph distributed storage system. It is implemented as a FastCGI module using libfcgi, and can be used in conjunction with any FastCGI capable web server. .SH OPTIONS .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through \fBceph.conf\fP). .UNINDENT .INDENT 0.0 .TP .B \-\-rgw\-socket\-path=path Specify a unix domain socket path. .UNINDENT .SH CONFIGURATION .sp Currently it\(aqs the easiest to use the RADOS Gateway with Apache and mod_fastcgi: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C FastCgiExternalServer /var/www/s3gw.fcgi \-socket /tmp/radosgw.sock ServerName rgw.example1.com ServerAlias rgw ServerAdmin webmaster@example1.com DocumentRoot /var/www RewriteEngine On RewriteRule ^/([a\-zA\-Z0\-9\-_.]*)([/]?.*) /s3gw.fcgi?page=$1¶ms=$2&%{QUERY_STRING} [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] Options +ExecCGI AllowOverride All SetHandler fastcgi\-script Order allow,deny Allow from all AuthBasicAuthoritative Off AllowEncodedSlashes On ServerSignature Off .ft P .fi .UNINDENT .UNINDENT .sp And the corresponding radosgw script (/var/www/s3gw.fcgi): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C #!/bin/sh exec /usr/bin/radosgw \-c /etc/ceph/ceph.conf \-n client.radosgw.gateway .ft P .fi .UNINDENT .UNINDENT .sp The radosgw daemon is a standalone process which needs a configuration section in the ceph.conf The section name should start with \(aqclient.radosgw.\(aq as specified in /etc/init.d/radosgw: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [client.radosgw.gateway] host = gateway keyring = /etc/ceph/keyring.radosgw.gateway rgw socket path = /tmp/radosgw.sock .ft P .fi .UNINDENT .UNINDENT .sp You will also have to generate a key for the radosgw to use for authentication with the cluster: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-authtool \-C \-n client.radosgw.gateway \-\-gen\-key /etc/ceph/keyring.radosgw.gateway ceph\-authtool \-n client.radosgw.gateway \-\-cap mon \(aqallow rw\(aq \-\-cap osd \(aqallow rwx\(aq /etc/ceph/keyring.radosgw.gateway .ft P .fi .UNINDENT .UNINDENT .sp And add the key to the auth entries: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth add client.radosgw.gateway \-\-in\-file=keyring.radosgw.gateway .ft P .fi .UNINDENT .UNINDENT .sp Now you can start Apache and the radosgw daemon: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C /etc/init.d/apache2 start /etc/init.d/radosgw start .ft P .fi .UNINDENT .UNINDENT .SH USAGE LOGGING .sp The \fBradosgw\fP maintains an asynchronous usage log. It accumulates statistics about user operations and flushes it periodically. The logs can be accessed and managed through \fBradosgw\-admin\fP\&. .sp The information that is being logged contains total data transfer, total operations, and total successful operations. The data is being accounted in an hourly resolution under the bucket owner, unless the operation was done on the service (e.g., when listing a bucket) in which case it is accounted under the operating user. .sp Following is an example configuration: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [client.radosgw.gateway] rgw enable usage log = true rgw usage log tick interval = 30 rgw usage log flush threshold = 1024 rgw usage max shards = 32 rgw usage max user shards = 1 .ft P .fi .UNINDENT .UNINDENT .sp The total number of shards determines how many total objects hold the usage log information. The per\-user number of shards specify how many objects hold usage information for a single user. The tick interval configures the number of seconds between log flushes, and the flush threshold specify how many entries can be kept before resorting to synchronous flush. .SH AVAILABILITY .sp \fBradosgw\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) \fBradosgw\-admin\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/crushtool.80000664000175100017510000002462212623076744017571 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CRUSHTOOL" "8" "January 12, 2014" "dev" "Ceph" .SH NAME crushtool \- CRUSH map manipulation tool . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBcrushtool\fP ( \-d \fImap\fP | \-c \fImap.txt\fP | \-\-build \-\-num_osds \fInumosds\fP \fIlayer1\fP \fI\&...\fP | \-\-test ) [ \-o \fIoutfile\fP ] .fi .sp .SH DESCRIPTION .INDENT 0.0 .TP .B \fBcrushtool\fP is a utility that lets you create, compile, decompile and test CRUSH map files. .UNINDENT .sp CRUSH is a pseudo\-random data distribution algorithm that efficiently maps input values (typically data objects) across a heterogeneous, hierarchically structured device map. The algorithm was originally described in detail in the following paper (although it has evolved some since then): .INDENT 0.0 .INDENT 3.5 \fI\%http://www.ssrc.ucsc.edu/Papers/weil-sc06.pdf\fP .UNINDENT .UNINDENT .sp The tool has four modes of operation. .INDENT 0.0 .TP .B \-\-compile|\-c map.txt will compile a plaintext map.txt into a binary map file. .UNINDENT .INDENT 0.0 .TP .B \-\-decompile|\-d map will take the compiled map and decompile it into a plaintext source file, suitable for editing. .UNINDENT .INDENT 0.0 .TP .B \-\-build \-\-num_osds {num\-osds} layer1 ... will create map with the given layer structure. See below for a detailed explanation. .UNINDENT .INDENT 0.0 .TP .B \-\-test will perform a dry run of a CRUSH mapping for a range of input object names. See below for a detailed explanation. .UNINDENT .sp Unlike other Ceph tools, \fBcrushtool\fP does not accept generic options such as \fB\-\-debug\-crush\fP from the command line. They can however be provided via the CEPH_ARGS environment variable. For instance, to silence all output from the CRUSH subsystem: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C CEPH_ARGS="\-\-debug\-crush 0" crushtool ... .ft P .fi .UNINDENT .UNINDENT .SH RUNNING TESTS WITH --TEST .sp The test mode will use the input crush map ( as specified with \fB\-i map\fP ) and perform a dry run of CRUSH mapping or random placement ( if \fB\-\-simulate\fP is set ). On completion, two kinds of reports can be created. The \fB\-\-show\-...\fP options output human readable information on stderr. The \fB\-\-output\-csv\fP option creates CSV files that are documented by the \fB\-\-help\-output\fP option. .INDENT 0.0 .TP .B \-\-show\-statistics for each rule display the mapping of each object. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C CRUSH rule 1 x 24 [11,6] .ft P .fi .UNINDENT .UNINDENT .sp shows that object \fB24\fP is mapped to devices \fB[11,6]\fP by rule \fB1\fP\&. At the end of the mapping details, a summary of the distribution is displayed. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C rule 1 (metadata) num_rep 5 result size == 5: 1024/1024 .ft P .fi .UNINDENT .UNINDENT .sp shows that rule \fB1\fP which is named \fBmetadata\fP successfully mapped \fB1024\fP objects to \fBresult size == 5\fP devices when trying to map them to \fBnum_rep 5\fP replicas. When it fails to provide the required mapping, presumably because the number of \fBtries\fP must be increased, a breakdown of the failures is displays. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C rule 1 (metadata) num_rep 10 result size == 8: 4/1024 rule 1 (metadata) num_rep 10 result size == 9: 93/1024 rule 1 (metadata) num_rep 10 result size == 10: 927/1024 .ft P .fi .UNINDENT .UNINDENT .sp shows that although \fBnum_rep 10\fP replicas were required, \fB4\fP out of \fB1024\fP objects ( \fB4/1024\fP ) were mapped to \fBresult size == 8\fP devices only. .UNINDENT .INDENT 0.0 .TP .B \-\-show\-bad\-mappings display which object failed to be mapped to the required number of devices. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C bad mapping rule 1 x 781 num_rep 7 result [8,10,2,11,6,9] .ft P .fi .UNINDENT .UNINDENT .sp shows that when rule \fB1\fP was required to map \fB7\fP devices, it could only map six : \fB[8,10,2,11,6,9]\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-show\-utilization display the expected and actual utilisation for each device, for each number of replicas. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C device 0: stored : 951 expected : 853.333 device 1: stored : 963 expected : 853.333 \&... .ft P .fi .UNINDENT .UNINDENT .sp shows that device \fB0\fP stored \fB951\fP objects and was expected to store \fB853\fP\&. Implies \fB\-\-show\-statistics\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-show\-utilization\-all displays the same as \fB\-\-show\-utilization\fP but does not suppress output when the weight of a device is zero. Implies \fB\-\-show\-statistics\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-show\-choose\-tries display how many attempts were needed to find a device mapping. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C 0: 95224 1: 3745 2: 2225 \&.. .ft P .fi .UNINDENT .UNINDENT .sp shows that \fB95224\fP mappings succeeded without retries, \fB3745\fP mappings succeeded with one attempts, etc. There are as many rows as the value of the \fB\-\-set\-choose\-total\-tries\fP option. .UNINDENT .INDENT 0.0 .TP .B \-\-output\-csv create CSV files (in the current directory) containing information documented by \fB\-\-help\-output\fP\&. The files are named after the rule used when collecting the statistics. For instance, if the rule metadata is used, the CSV files will be: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C metadata\-absolute_weights.csv metadata\-device_utilization.csv \&... .ft P .fi .UNINDENT .UNINDENT .sp The first line of the file shortly explains the column layout. For instance: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C metadata\-absolute_weights.csv Device ID, Absolute Weight 0,1 \&... .ft P .fi .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B \-\-output\-name NAME prepend \fBNAME\fP to the file names generated when \fB\-\-output\-csv\fP is specified. For instance \fB\-\-output\-name FOO\fP will create files: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C FOO\-metadata\-absolute_weights.csv FOO\-metadata\-device_utilization.csv \&... .ft P .fi .UNINDENT .UNINDENT .UNINDENT .sp The \fB\-\-set\-...\fP options can be used to modify the tunables of the input crush map. The input crush map is modified in memory. For example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ crushtool \-i mymap \-\-test \-\-show\-bad\-mappings bad mapping rule 1 x 781 num_rep 7 result [8,10,2,11,6,9] .ft P .fi .UNINDENT .UNINDENT .sp could be fixed by increasing the \fBchoose\-total\-tries\fP as follows: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .TP .B $ crushtool \-i mymap \-\-test \-\-show\-bad\-mappings \-\-set\-choose\-total\-tries 500 .UNINDENT .UNINDENT .UNINDENT .SH BUILDING A MAP WITH --BUILD .sp The build mode will generate hierarchical maps. The first argument specifies the number of devices (leaves) in the CRUSH hierarchy. Each layer describes how the layer (or devices) preceding it should be grouped. .sp Each layer consists of: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bucket ( uniform | list | tree | straw ) size .ft P .fi .UNINDENT .UNINDENT .sp The \fBbucket\fP is the type of the buckets in the layer (e.g. "rack"). Each bucket name will be built by appending a unique number to the \fBbucket\fP string (e.g. "rack0", "rack1"...). .sp The second component is the type of bucket: \fBstraw\fP should be used most of the time. .sp The third component is the maximum size of the bucket. A size of zero means a bucket of infinite capacity. .SH EXAMPLE .sp Suppose we have two rows with two racks each and 20 nodes per rack. Suppose each node contains 4 storage devices for Ceph OSD Daemons. This configuration allows us to deploy 320 Ceph OSD Daemons. Lets assume a 42U rack with 2U nodes, leaving an extra 2U for a rack switch. .sp To reflect our hierarchy of devices, nodes, racks and rows, we would execute the following: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ crushtool \-o crushmap \-\-build \-\-num_osds 320 \e node straw 4 \e rack straw 20 \e row straw 2 \e root straw 0 # id weight type name reweight \-87 320 root root \-85 160 row row0 \-81 80 rack rack0 \-1 4 node node0 0 1 osd.0 1 1 1 osd.1 1 2 1 osd.2 1 3 1 osd.3 1 \-2 4 node node1 4 1 osd.4 1 5 1 osd.5 1 \&... .ft P .fi .UNINDENT .UNINDENT .sp CRUSH rulesets are created so the generated crushmap can be tested. They are the same rulesets as the one created by default when creating a new Ceph cluster. They can be further edited with: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C # decompile crushtool \-d crushmap \-o map.txt # edit emacs map.txt # recompile crushtool \-c map.txt \-o crushmap .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBcrushtool\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBosdmaptool\fP(8), .SH AUTHORS .sp John Wilkins, Sage Weil, Loic Dachary .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-run.80000664000175100017510000000424312623076744017265 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-RUN" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-run \- restart daemon on core dump . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-run\fP \fIcommand\fP ... .fi .sp .SH DESCRIPTION .sp \fBceph\-run\fP is a simple wrapper that will restart a daemon if it exits with a signal indicating it crashed and possibly core dumped (that is, signals 3, 4, 5, 6, 8, or 11). .sp The command should run the daemon in the foreground. For Ceph daemons, that means the \fB\-f\fP option. .SH OPTIONS .sp None .SH AVAILABILITY .sp \fBceph\-run\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBceph\-mon\fP(8), \fBceph\-mds\fP(8), \fBceph\-osd\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/osdmaptool.80000664000175100017510000000635212623076744017730 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "OSDMAPTOOL" "8" "January 12, 2014" "dev" "Ceph" .SH NAME osdmaptool \- ceph osd cluster map manipulation tool . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBosdmaptool\fP \fImapfilename\fP [\-\-print] [\-\-createsimple \fInumosd\fP [\-\-pgbits \fIbitsperosd\fP ] ] [\-\-clobber] .fi .sp .SH DESCRIPTION .sp \fBosdmaptool\fP is a utility that lets you create, view, and manipulate OSD cluster maps from the Ceph distributed storage system. Notably, it lets you extract the embedded CRUSH map or import a new CRUSH map. .SH OPTIONS .INDENT 0.0 .TP .B \-\-print will simply make the tool print a plaintext dump of the map, after any modifications are made. .UNINDENT .INDENT 0.0 .TP .B \-\-clobber will allow osdmaptool to overwrite mapfilename if changes are made. .UNINDENT .INDENT 0.0 .TP .B \-\-import\-crush mapfile will load the CRUSH map from mapfile and embed it in the OSD map. .UNINDENT .INDENT 0.0 .TP .B \-\-export\-crush mapfile will extract the CRUSH map from the OSD map and write it to mapfile. .UNINDENT .INDENT 0.0 .TP .B \-\-createsimple numosd [\-\-pgbits bitsperosd] will create a relatively generic OSD map with the numosd devices. If \-\-pgbits is specified, the initial placement group counts will be set with bitsperosd bits per OSD. That is, the pg_num map attribute will be set to numosd shifted by bitsperosd. .UNINDENT .SH EXAMPLE .sp To create a simple map with 16 devices: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C osdmaptool \-\-createsimple 16 osdmap \-\-clobber .ft P .fi .UNINDENT .UNINDENT .sp To view the result: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C osdmaptool \-\-print osdmap .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBosdmaptool\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBcrushtool\fP(8), .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/rbd.80000664000175100017510000004221512623076744016314 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "RBD" "8" "January 12, 2014" "dev" "Ceph" .SH NAME rbd \- manage rados block device (RBD) images . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBrbd\fP [ \-c \fIceph.conf\fP ] [ \-m \fImonaddr\fP ] [ \-p | \-\-pool \fIpool\fP ] [ \-\-size \fIsize\fP ] [ \-\-order \fIbits\fP ] [ \fIcommand\fP ... ] .fi .sp .SH DESCRIPTION .sp \fBrbd\fP is a utility for manipulating rados block device (RBD) images, used by the Linux rbd driver and the rbd storage driver for Qemu/KVM. RBD images are simple block devices that are striped over objects and stored in a RADOS object store. The size of the objects the image is striped over must be a power of two. .SH OPTIONS .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf ceph.conf Use ceph.conf configuration file instead of the default /etc/ceph/ceph.conf to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through ceph.conf). .UNINDENT .INDENT 0.0 .TP .B \-p pool, \-\-pool pool Interact with the given pool. Required by most commands. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-progress Do not output progress information (goes to standard error by default for some commands). .UNINDENT .SH PARAMETERS .INDENT 0.0 .TP .B \-\-image\-format format Specifies which object layout to use. The default is 1. .INDENT 7.0 .IP \(bu 2 format 1 \- Use the original format for a new rbd image. This format is understood by all versions of librbd and the kernel rbd module, but does not support newer features like cloning. .IP \(bu 2 format 2 \- Use the second rbd format, which is supported by librbd (but not the kernel rbd module) at this time. This adds support for cloning and is more easily extensible to allow more features in the future. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B \-\-size size\-in\-mb Specifies the size (in megabytes) of the new rbd image. .UNINDENT .INDENT 0.0 .TP .B \-\-order bits Specifies the object size expressed as a number of bits, such that the object size is \fB1 << order\fP\&. The default is 22 (4 MB). .UNINDENT .INDENT 0.0 .TP .B \-\-stripe\-unit size\-in\-bytes Specifies the stripe unit size in bytes. See striping section (below) for more details. .UNINDENT .INDENT 0.0 .TP .B \-\-stripe\-count num Specifies the number of objects to stripe over before looping back to the first object. See striping section (below) for more details. .UNINDENT .INDENT 0.0 .TP .B \-\-snap snap Specifies the snapshot name for the specific operation. .UNINDENT .INDENT 0.0 .TP .B \-\-id username Specifies the username (without the \fBclient.\fP prefix) to use with the map command. .UNINDENT .INDENT 0.0 .TP .B \-\-keyfile filename Specifies a file containing the secret to use with the map command. If not specified, \fBclient.admin\fP will be used by default. .UNINDENT .INDENT 0.0 .TP .B \-\-keyring filename Specifies a keyring file containing a secret for the specified user to use with the map command. If not specified, the default keyring locations will be searched. .UNINDENT .INDENT 0.0 .TP .B \-\-shared tag Option for \fIlock add\fP that allows multiple clients to lock the same image if they use the same tag. The tag is an arbitrary string. This is useful for situations where an image must be open from more than one client at once, like during live migration of a virtual machine, or for use underneath a clustered filesystem. .UNINDENT .INDENT 0.0 .TP .B \-\-format format Specifies output formatting (default: plain, json, xml) .UNINDENT .INDENT 0.0 .TP .B \-\-pretty\-format Make json or xml formatted output more human\-readable. .UNINDENT .INDENT 0.0 .TP .B \-o map\-options, \-\-options map\-options Specifies which options to use when mapping an image. map\-options is a comma\-separated string of options (similar to mount(8) mount options). See map options section below for more details. .UNINDENT .INDENT 0.0 .TP .B \-\-read\-only Map the image read\-only. Equivalent to \-o ro. .UNINDENT .SH COMMANDS .INDENT 0.0 .TP .B \fBls\fP [\-l | \-\-long] [pool\-name] Will list all rbd images listed in the rbd_directory object. With \-l, also show snapshots, and use longer\-format output including size, parent (if clone), format, etc. .TP .B \fBinfo\fP [\fIimage\-name\fP] Will dump information (such as size and order) about a specific rbd image. If image is a clone, information about its parent is also displayed. If a snapshot is specified, whether it is protected is shown as well. .TP .B \fBcreate\fP [\fIimage\-name\fP] Will create a new rbd image. You must also specify the size via \-\-size. The \-\-stripe\-unit and \-\-stripe\-count arguments are optional, but must be used together. .TP .B \fBclone\fP [\fIparent\-snapname\fP] [\fIimage\-name\fP] Will create a clone (copy\-on\-write child) of the parent snapshot. Object order will be identical to that of the parent image unless specified. Size will be the same as the parent snapshot. .sp The parent snapshot must be protected (see \fIrbd snap protect\fP). This requires image format 2. .TP .B \fBflatten\fP [\fIimage\-name\fP] If image is a clone, copy all shared blocks from the parent snapshot and make the child independent of the parent, severing the link between parent snap and child. The parent snapshot can be unprotected and deleted if it has no further dependent clones. .sp This requires image format 2. .TP .B \fBchildren\fP [\fIimage\-name\fP] List the clones of the image at the given snapshot. This checks every pool, and outputs the resulting poolname/imagename. .sp This requires image format 2. .TP .B \fBresize\fP [\fIimage\-name\fP] [\-\-allow\-shrink] Resizes rbd image. The size parameter also needs to be specified. The \-\-allow\-shrink option lets the size be reduced. .TP .B \fBrm\fP [\fIimage\-name\fP] Deletes an rbd image (including all data blocks). If the image has snapshots, this fails and nothing is deleted. .TP .B \fBexport\fP [\fIimage\-name\fP] [\fIdest\-path\fP] Exports image to dest path (use \- for stdout). .TP .B \fBimport\fP [\fIpath\fP] [\fIdest\-image\fP] Creates a new image and imports its data from path (use \- for stdin). The import operation will try to create sparse rbd images if possible. For import from stdin, the sparsification unit is the data block size of the destination image (1 << order). .TP .B \fBexport\-diff\fP [\fIimage\-name\fP] [\fIdest\-path\fP] [\-\-from\-snap \fIsnapname\fP] Exports an incremental diff for an image to dest path (use \- for stdout). If an initial snapshot is specified, only changes since that snapshot are included; otherwise, any regions of the image that contain data are included. The end snapshot is specified using the standard \-\-snap option or @snap syntax (see below). The image diff format includes metadata about image size changes, and the start and end snapshots. It efficiently represents discarded or \(aqzero\(aq regions of the image. .TP .B \fBimport\-diff\fP [\fIsrc\-path\fP] [\fIimage\-name\fP] Imports an incremental diff of an image and applies it to the current image. If the diff was generated relative to a start snapshot, we verify that snapshot already exists before continuing. If there was an end snapshot we verify it does not already exist before applying the changes, and create the snapshot when we are done. .TP .B \fBdiff\fP [\fIimage\-name\fP] [\-\-from\-snap \fIsnapname\fP] Dump a list of byte extents in the image that have changed since the specified start snapshot, or since the image was created. Each output line includes the starting offset (in bytes), the length of the region (in bytes), and either \(aqzero\(aq or \(aqdata\(aq to indicate whether the region is known to be zeros or may contain other data. .TP .B \fBcp\fP [\fIsrc\-image\fP] [\fIdest\-image\fP] Copies the content of a src\-image into the newly created dest\-image. dest\-image will have the same size, order, and image format as src\-image. .TP .B \fBmv\fP [\fIsrc\-image\fP] [\fIdest\-image\fP] Renames an image. Note: rename across pools is not supported. .TP .B \fBsnap\fP ls [\fIimage\-name\fP] Dumps the list of snapshots inside a specific image. .TP .B \fBsnap\fP create [\fIimage\-name\fP] Creates a new snapshot. Requires the snapshot name parameter specified. .TP .B \fBsnap\fP rollback [\fIimage\-name\fP] Rollback image content to snapshot. This will iterate through the entire blocks array and update the data head content to the snapshotted version. .TP .B \fBsnap\fP rm [\fIimage\-name\fP] Removes the specified snapshot. .TP .B \fBsnap\fP purge [\fIimage\-name\fP] Removes all snapshots from an image. .TP .B \fBsnap\fP protect [\fIimage\-name\fP] Protect a snapshot from deletion, so that clones can be made of it (see \fIrbd clone\fP). Snapshots must be protected before clones are made; protection implies that there exist dependent cloned children that refer to this snapshot. \fIrbd clone\fP will fail on a nonprotected snapshot. .sp This requires image format 2. .TP .B \fBsnap\fP unprotect [\fIimage\-name\fP] Unprotect a snapshot from deletion (undo \fIsnap protect\fP). If cloned children remain, \fIsnap unprotect\fP fails. (Note that clones may exist in different pools than the parent snapshot.) .sp This requires image format 2. .TP .B \fBmap\fP [\fIimage\-name\fP] [\-o | \-\-options \fImap\-options\fP ] [\-\-read\-only] Maps the specified image to a block device via the rbd kernel module. .TP .B \fBunmap\fP [\fIdevice\-path\fP] Unmaps the block device that was mapped via the rbd kernel module. .TP .B \fBshowmapped\fP Show the rbd images that are mapped via the rbd kernel module. .TP .B \fBlock\fP list [\fIimage\-name\fP] Show locks held on the image. The first column is the locker to use with the \fIlock remove\fP command. .TP .B \fBlock\fP add [\fIimage\-name\fP] [\fIlock\-id\fP] Lock an image. The lock\-id is an arbitrary name for the user\(aqs convenience. By default, this is an exclusive lock, meaning it will fail if the image is already locked. The \-\-shared option changes this behavior. Note that locking does not affect any operation other than adding a lock. It does not protect an image from being deleted. .TP .B \fBlock\fP remove [\fIimage\-name\fP] [\fIlock\-id\fP] [\fIlocker\fP] Release a lock on an image. The lock id and locker are as output by lock ls. .TP .B \fBbench\-write\fP [\fIimage\-name\fP] \-\-io\-size [\fIio\-size\-in\-bytes\fP] \-\-io\-threads [\fInum\-ios\-in\-flight\fP] \-\-io\-total [\fItotal\-bytes\-to\-write\fP] Generate a series of sequential writes to the image and measure the write throughput and latency. Defaults are: \-\-io\-size 4096, \-\-io\-threads 16, \-\-io\-total 1GB .UNINDENT .SH IMAGE NAME .sp In addition to using the \-\-pool and the \-\-snap options, the image name can include both the pool name and the snapshot name. The image name format is as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [pool/]image\-name[@snap] .ft P .fi .UNINDENT .UNINDENT .sp Thus an image name that contains a slash character (\(aq/\(aq) requires specifying the pool name explicitly. .SH STRIPING .sp RBD images are striped over many objects, which are then stored by the Ceph distributed object store (RADOS). As a result, read and write requests for the image are distributed across many nodes in the cluster, generally preventing any single node from becoming a bottleneck when individual images get large or busy. .sp The striping is controlled by three parameters: .INDENT 0.0 .TP .B order .TP .B The size of objects we stripe over is a power of two, specifially 2^[*order*] bytes. The default .TP .B is 22, or 4 MB. .UNINDENT .INDENT 0.0 .TP .B stripe_unit .TP .B Each [*stripe_unit*] contiguous bytes are stored adjacently in the same object, before we move on .TP .B to the next object. .UNINDENT .INDENT 0.0 .TP .B stripe_count .TP .B After we write [*stripe_unit*] bytes to [*stripe_count*] objects, we loop back to the initial object .TP .B and write another stripe, until the object reaches its maximum size (as specified by [*order*]. At that .TP .B point, we move on to the next [*stripe_count*] objects. .UNINDENT .sp By default, [\fIstripe_unit\fP] is the same as the object size and [\fIstripe_count\fP] is 1. Specifying a different [\fIstripe_unit\fP] requires that the STRIPINGV2 feature be supported (added in Ceph v0.53) and format 2 images be used. .SH MAP OPTIONS .sp Most of these options are useful mainly for debugging and benchmarking. The default values are set in the kernel and may therefore depend on the version of the running kernel. .INDENT 0.0 .IP \(bu 2 fsid=aaaaaaaa\-bbbb\-cccc\-dddd\-eeeeeeeeeeee \- FSID that should be assumed by the client. .IP \(bu 2 ip=a.b.c.d[:p] \- IP and, optionally, port the client should use. .IP \(bu 2 share \- Enable sharing of client instances with other mappings (default). .IP \(bu 2 noshare \- Disable sharing of client instances with other mappings. .IP \(bu 2 crc \- Enable CRC32C checksumming for data writes (default). .IP \(bu 2 nocrc \- Disable CRC32C checksumming for data writes. .IP \(bu 2 osdkeepalive=x \- OSD keepalive timeout (default is 5 seconds). .IP \(bu 2 osd_idle_ttl=x \- OSD idle TTL (default is 60 seconds). .IP \(bu 2 rw \- Map the image read\-write (default). .IP \(bu 2 ro \- Map the image read\-only. Equivalent to \-\-read\-only. .UNINDENT .SH EXAMPLES .sp To create a new rbd image that is 100 GB: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd \-p mypool create myimage \-\-size 102400 .ft P .fi .UNINDENT .UNINDENT .sp or alternatively: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd create mypool/myimage \-\-size 102400 .ft P .fi .UNINDENT .UNINDENT .sp To use a non\-default object size (8 MB): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd create mypool/myimage \-\-size 102400 \-\-order 23 .ft P .fi .UNINDENT .UNINDENT .sp To delete an rbd image (be careful!): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd rm mypool/myimage .ft P .fi .UNINDENT .UNINDENT .sp To create a new snapshot: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd snap create mypool/myimage@mysnap .ft P .fi .UNINDENT .UNINDENT .sp To create a copy\-on\-write clone of a protected snapshot: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd clone mypool/myimage@mysnap otherpool/cloneimage .ft P .fi .UNINDENT .UNINDENT .sp To see which clones of a snapshot exist: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd children mypool/myimage@mysnap .ft P .fi .UNINDENT .UNINDENT .sp To delete a snapshot: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd snap rm mypool/myimage@mysnap .ft P .fi .UNINDENT .UNINDENT .sp To map an image via the kernel with cephx enabled: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd map mypool/myimage \-\-id admin \-\-keyfile secretfile .ft P .fi .UNINDENT .UNINDENT .sp To unmap an image: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd unmap /dev/rbd0 .ft P .fi .UNINDENT .UNINDENT .sp To create an image and a clone from it: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd import \-\-image\-format 2 image mypool/parent rbd snap create \-\-snap snapname mypool/parent rbd snap protect mypool/parent@snap rbd clone mypool/parent@snap otherpool/child .ft P .fi .UNINDENT .UNINDENT .sp To create an image with a smaller stripe_unit (to better distribute small writes in some workloads): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd \-p mypool create myimage \-\-size 102400 \-\-stripe\-unit 65536 \-\-stripe\-count 16 .ft P .fi .UNINDENT .UNINDENT .sp To change an image from one image format to another, export it and then import it as the desired image format: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd export mypool/myimage@snap /tmp/img rbd import \-\-image\-format 2 /tmp/img mypool/myimage2 .ft P .fi .UNINDENT .UNINDENT .sp To lock an image for exclusive use: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd lock add mypool/myimage mylockid .ft P .fi .UNINDENT .UNINDENT .sp To release a lock: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rbd lock remove mypool/myimage mylockid client.2485 .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBrbd\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBrados\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-disk.80000664000175100017510000002000512623076744017405 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-DISK" "8" "November 26, 2014" "dev" "Ceph" .SH NAME ceph-disk \- Ceph disk preparation and activation utility for OSD . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-disk\fP \fBprepare\fP [\-\-cluster \fIclustername\fP] [\-\-cluster\-uuid \fIuuid\fP] [\-\-fs\-type \fIxfs|ext4|btrfs\fP] [\fIdata\-path\fP] [\fIjournal\-path\fP] .fi .sp .nf \fBceph\-disk\fP \fBactivate\fP [\fIdata\-path\fP] [\-\-activate\-key \fIpath\fP] .fi .sp .nf \fBceph\-disk\fP \fBactivate\-all\fP .fi .sp .nf \fBceph\-disk\fP \fBlist\fP .fi .sp .SH DESCRIPTION .sp \fBceph\-disk\fP is a utility that can prepare and activate a disk, partition or directory as a ceph OSD. It is run directly or triggered by \fBceph\-deploy\fP or udev. .sp It actually automates the multiple steps involved in manual creation and start of an OSD into 2 steps of preparing and activating the OSD by using the subcommands \fBprepare\fP and \fBactivate\fP\&. .SH SUBCOMMANDS .sp \fBprepare\fP: Prepare a directory, disk or drive for a ceph OSD. It creates a GPT partition, marks the partition with ceph type uuid, creates a file system, marks the file system as ready for ceph consumption, uses entire partition and adds a new partition to the journal disk. It is run directly or triggered by \fBceph\-deploy\fP\&. .sp Usage: ceph\-disk prepare \-\-cluster [cluster\-name] \-\-cluster\-uuid [uuid] \-\-fs\-type [ext4|xfs|btrfs] [data\-path] [journal\-path] .sp Other options like \-\-osd\-uuid, \-\-journal\-uuid, \-\-zap\-disk, \-\-data\-dir, \-\-data\-dev, \-\-journal\-file, \-\-journal\-dev, \-\-dmcrypt and \-\-dmcrypt\-key\-dir can also be used with the subcommand. .sp \fBactivate\fP: Activate the ceph OSD. It mounts the volume in a temporary location, allocates an OSD id (if needed), remounts in the correct location /var/lib/ceph/osd/$cluster\-$id and starts ceph\-osd. It is triggered by udev when it sees the OSD GPT partition type or on ceph service start with \(aqceph disk activate\-all\(aq. It is also run directly or triggered by \fBceph\-deploy\fP\&. .sp Usage: ceph\-disk activate [PATH] .sp Here, [PATH] is path to block device or directory. .sp An additional option [\-\-activate\-key PATH] has to be used with this subcommand when a copy of /var/lib/ceph/bootstrap\-osd/{cluster}.keyring isn\(aqt present in the OSD node. .sp Usage: ceph\-disk activate [PATH] [\-\-activate\-key PATH] .sp Another option \-\-mark\-init can also be used with this subcommand. .sp \fBactivate\-journal\fP: Activate an OSD via it\(aqs journal device. udev triggers \(aqceph\-disk activate\-journal \(aq based on the partition type. .sp Usage: ceph\-disk activate\-journal [DEV] .sp Here, [DEV] is the path to journal block device. .sp Others options can also be used with this subcommand like \-\-activate\-key and \-\-mark\-init. .sp Usage: ceph\-disk activate\-journal [\-\-activate\-key PATH] [\-\-mark\-init INITSYSTEM] [DEV] .sp \fBactivate\-all\fP: Activate all tagged OSD partitions. activate\-all relies on /dev/disk/by\-parttype\-uuid/$typeuuid.$uuid to find all partitions. Special udev rules are installed to create these links. It is triggered on ceph service start or run directly. .sp Usage: ceph\-disk activate\-all .sp Others options can also be used with this subcommand like \-\-activate\-key and \-\-mark\-init. .sp Usage: ceph\-disk activate\-all [\-\-activate\-key PATH] [\-\-mark\-init INITSYSTEM] .sp \fBlist\fP: List disk partitions and ceph OSDs. It is run directly or triggered by \fBceph\-deploy\fP\&. .sp Usage: ceph\-disk list .sp \fBsuppress\-activate\fP: Suppress activate on a device (prefix). Mark devices that you want to suppress activate with a file like /var/lib/ceph/tmp/suppress\-activate.sdb where the last bit is the sanitized device name (/dev/X without the /dev/ prefix). A function is_suppressed() checks for and matches a prefix (/dev/). It means suppressing sdb will stop activate on sdb1, sdb2, etc. .sp Usage: ceph\-disk suppress\-activate [PATH] .sp Here, [PATH] is path to block device or directory. .sp \fBunsuppress\-activate\fP: Stop suppressing activate on a device (prefix). .sp Usage: ceph\-disk unsuppress\-activate [PATH] .sp Here, [PATH] is path to block device or directory. .sp \fBzap\fP: Zap/erase/destroy a device\(aqs partition table and contents. It actually uses \(aqsgdisk\(aq and it\(aqs option \(aq\-\-zap\-all\(aq to destroy both GPT and MBR data structures so that the disk becomes suitable for repartitioning. \(aqsgdisk\(aq then uses \(aq\-\-mbrtogpt\(aq to convert the MBR or BSD disklabel disk to a GPT disk. The \fBprepare\fP subcommand can now be executed which will create a new GPT partition. It is also run directly or triggered by \fBceph\-deploy\fP\&. .sp Usage: ceph\-disk zap [DEV] .sp Here, [DEV] is path to block device. .SH OPTIONS .INDENT 0.0 .TP .B \-\-prepend\-to\-path PATH Prepend PATH to $PATH for backward compatibility (default /usr/bin). .UNINDENT .INDENT 0.0 .TP .B \-\-statedir PATH Directory in which ceph configuration is preserved (default /usr/lib/ceph). .UNINDENT .INDENT 0.0 .TP .B \-\-sysconfdir PATH Directory in which ceph configuration files are found (default /etc/ceph). .UNINDENT .INDENT 0.0 .TP .B \-\-cluster Provide name of the ceph cluster in which the OSD is being prepared. .UNINDENT .INDENT 0.0 .TP .B \-\-cluster\-uuid Provide uuid of the ceph cluster in which the OSD is being prepared. .UNINDENT .INDENT 0.0 .TP .B \-\-fs\-type Provide the filesytem type for the OSD. e.g. \(aqxfs/ext4/btrfs\(aq. .UNINDENT .INDENT 0.0 .TP .B \-\-osd\-uuid Unique OSD uuid to assign to the disk. .UNINDENT .INDENT 0.0 .TP .B \-\-journal\-uuid Unique uuid to assign to the journal. .UNINDENT .INDENT 0.0 .TP .B \-\-zap\-disk Destroy the partition table and content of a disk. .UNINDENT .INDENT 0.0 .TP .B \-\-data\-dir Verify that [data\-path] is of a directory. .UNINDENT .INDENT 0.0 .TP .B \-\-data\-dev Verify that [data\-path] is of a block device. .UNINDENT .INDENT 0.0 .TP .B \-\-journal\-file Verify that journal is a file. .UNINDENT .INDENT 0.0 .TP .B \-\-journal\-dev Verify that journal is a block device. .UNINDENT .INDENT 0.0 .TP .B \-\-dmcrypt Encrypt [data\-path] and/or journal devices with dm\-crypt. .UNINDENT .INDENT 0.0 .TP .B \-\-dmcrypt\-key\-dir Directory where dm\-crypt keys are stored. .UNINDENT .INDENT 0.0 .TP .B \-\-activate\-key Use when a copy of /var/lib/ceph/bootstrap\-osd/{cluster}.keyring isn\(aqt present in the OSD node. Suffix the option by the path to the keyring. .UNINDENT .INDENT 0.0 .TP .B \-\-mark\-init Provide init system to manage the OSD directory. .UNINDENT .SH AVAILABILITY .sp \fBceph\-disk\fP is a part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/monmaptool.80000664000175100017510000001076112623076744017733 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "MONMAPTOOL" "8" "January 12, 2014" "dev" "Ceph" .SH NAME monmaptool \- ceph monitor cluster map manipulation tool . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBmonmaptool\fP \fImapfilename\fP [ \-\-clobber ] [ \-\-print ] [ \-\-create ] [ \-\-add \fIip\fP:\fIport\fP \fI\&...\fP ] [ \-\-rm \fIip\fP:\fIport\fP \fI\&...\fP ] .fi .sp .SH DESCRIPTION .sp \fBmonmaptool\fP is a utility to create, view, and modify a monitor cluster map for the Ceph distributed storage system. The monitor map specifies the only fixed addresses in the Ceph distributed system. All other daemons bind to arbitrary addresses and register themselves with the monitors. .sp When creating a map with \-\-create, a new monitor map with a new, random UUID will be created. It should be followed by one or more monitor addresses. .sp The default Ceph monitor port is 6789. .SH OPTIONS .INDENT 0.0 .TP .B \-\-print will print a plaintext dump of the map, after any modifications are made. .UNINDENT .INDENT 0.0 .TP .B \-\-clobber will allow monmaptool to overwrite mapfilename if changes are made. .UNINDENT .INDENT 0.0 .TP .B \-\-create will create a new monitor map with a new UUID (and with it, a new, empty Ceph file system). .UNINDENT .INDENT 0.0 .TP .B \-\-generate generate a new monmap based on the values on the command line or specified in the ceph configuration. This is, in order of preference, .INDENT 7.0 .INDENT 3.5 .INDENT 0.0 .IP 1. 3 \fB\-\-monmap filename\fP to specify a monmap to load .IP 2. 3 \fB\-\-mon\-host \(aqhost1,ip2\(aq\fP to specify a list of hosts or ip addresses .IP 3. 3 \fB[mon.foo]\fP sections containing \fBmon addr\fP settings in the config .UNINDENT .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B \-\-filter\-initial\-members filter the initial monmap by applying the \fBmon initial members\fP setting. Monitors not present in that list will be removed, and initial members not present in the map will be added with dummy addresses. .UNINDENT .INDENT 0.0 .TP .B \-\-add name ip:port will add a monitor with the specified ip:port to the map. .UNINDENT .INDENT 0.0 .TP .B \-\-rm name will remove the monitor with the specified ip:port from the map. .UNINDENT .INDENT 0.0 .TP .B \-\-fsid uuid will set the fsid to the given uuid. If not specified with \-\-create, a random fsid will be generated. .UNINDENT .SH EXAMPLE .sp To create a new map with three monitors (for a fresh Ceph file system): .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C monmaptool \-\-create \-\-add mon.a 192.168.0.10:6789 \-\-add mon.b 192.168.0.11:6789 \e \-\-add mon.c 192.168.0.12:6789 \-\-clobber monmap .ft P .fi .UNINDENT .UNINDENT .sp To display the contents of the map: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C monmaptool \-\-print monmap .ft P .fi .UNINDENT .UNINDENT .sp To replace one monitor: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C monmaptool \-\-rm mon.a \-\-add mon.a 192.168.0.9:6789 \-\-clobber monmap .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBmonmaptool\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBcrushtool\fP(8), .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-clsinfo.80000664000175100017510000000423412623076744020116 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-CLSINFO" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-clsinfo \- show class object information . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-clsinfo\fP [ \fIoptions\fP ] ... \fIfilename\fP .fi .sp .SH DESCRIPTION .sp \fBceph\-clsinfo\fP can show name, version, and architecture information about a specific class object. .SH OPTIONS .INDENT 0.0 .TP .B \-n, \-\-name Shows the class name .UNINDENT .INDENT 0.0 .TP .B \-v, \-\-version Shows the class version .UNINDENT .INDENT 0.0 .TP .B \-a, \-\-arch Shows the class architecture .UNINDENT .SH AVAILABILITY .sp \fBceph\-clsinfo\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-osd.80000664000175100017510000001062712623076744017251 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-OSD" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-osd \- ceph object storage daemon . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-osd\fP \-i \fIosdnum\fP [ \-\-osd\-data \fIdatapath\fP ] [ \-\-osd\-journal \fIjournal\fP ] [ \-\-mkfs ] [ \-\-mkjournal ] [ \-\-mkkey ] .fi .sp .SH DESCRIPTION .sp \fBceph\-osd\fP is the object storage daemon for the Ceph distributed file system. It is responsible for storing objects on a local file system and providing access to them over the network. .sp The datapath argument should be a directory on a btrfs file system where the object data resides. The journal is optional, and is only useful performance\-wise when it resides on a different disk than datapath with low latency (ideally, an NVRAM device). .SH OPTIONS .INDENT 0.0 .TP .B \-f, \-\-foreground Foreground: do not daemonize after startup (run in foreground). Do not generate a pid file. Useful when run via \fBceph\-run\fP(8). .UNINDENT .INDENT 0.0 .TP .B \-d Debug mode: like \fB\-f\fP, but also send all log output to stderr. .UNINDENT .INDENT 0.0 .TP .B \-\-osd\-data osddata Use object store at \fIosddata\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-osd\-journal journal Journal updates to \fIjournal\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-mkfs Create an empty object repository. This also initializes the journal (if one is defined). .UNINDENT .INDENT 0.0 .TP .B \-\-mkkey Generate a new secret key. This is normally used in combination with \fB\-\-mkfs\fP as it is more convenient than generating a key by hand with \fBceph\-authtool\fP(8). .UNINDENT .INDENT 0.0 .TP .B \-\-mkjournal Create a new journal file to match an existing object repository. This is useful if the journal device or file is wiped out due to a disk or file system failure. .UNINDENT .INDENT 0.0 .TP .B \-\-flush\-journal Flush the journal to permanent store. This runs in the foreground so you know when it\(aqs completed. This can be useful if you want to resize the journal or need to otherwise destroy it: this guarantees you won\(aqt lose data. .UNINDENT .INDENT 0.0 .TP .B \-\-get\-cluster\-fsid Print the cluster fsid (uuid) and exit. .UNINDENT .INDENT 0.0 .TP .B \-\-get\-osd\-fsid Print the OSD\(aqs fsid and exit. The OSD\(aqs uuid is generated at \-\-mkfs time and is thus unique to a particular instantiation of this OSD. .UNINDENT .INDENT 0.0 .TP .B \-\-get\-journal\-fsid Print the journal\(aqs uuid. The journal fsid is set to match the OSD fsid at \-\-mkfs time. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP for runtime configuration options. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through \fBceph.conf\fP). .UNINDENT .SH AVAILABILITY .sp \fBceph\-osd\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBceph\-mds\fP(8), \fBceph\-mon\fP(8), \fBceph\-authtool\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-rbdnamer.80000664000175100017510000000423712623076744020256 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-RBDNAMER" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-rbdnamer \- udev helper to name RBD devices . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-rbdnamer\fP \fInum\fP .fi .sp .SH DESCRIPTION .sp \fBceph\-rbdnamer\fP prints the pool and image name for the given RBD devices to stdout. It is used by \fIudev\fP (using a rule like the one below) to set up a device symlink. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C KERNEL=="rbd[0\-9]*", PROGRAM="/usr/bin/ceph\-rbdnamer %n", SYMLINK+="rbd/%c{1}/%c{2}" .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBceph\-rbdnamer\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBrbd\fP(8), \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-fuse.80000664000175100017510000000561012623076744017422 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-FUSE" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-fuse \- FUSE-based client for ceph . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-fuse\fP [ \-m \fImonaddr\fP:\fIport\fP ] \fImountpoint\fP [ \fIfuse options\fP ] .fi .sp .SH DESCRIPTION .sp \fBceph\-fuse\fP is a FUSE (File system in USErspace) client for Ceph distributed file system. It will mount a ceph file system (specified via the \-m option for described by ceph.conf (see below) at the specific mount point. .sp The file system can be unmounted with: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C fusermount \-u mountpoint .ft P .fi .UNINDENT .UNINDENT .sp or by sending \fBSIGINT\fP to the \fBceph\-fuse\fP process. .SH OPTIONS .sp Any options not recognized by ceph\-fuse will be passed on to libfuse. .INDENT 0.0 .TP .B \-d Detach from console and daemonize after startup. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through ceph.conf). .UNINDENT .INDENT 0.0 .TP .B \-r root_directory Use root_directory as the mounted root, rather than the full Ceph tree. .UNINDENT .SH AVAILABILITY .sp \fBceph\-fuse\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp fusermount(8), \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/cephfs.80000664000175100017510000000750012623076744017013 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPHFS" "8" "January 12, 2014" "dev" "Ceph" .SH NAME cephfs \- ceph file system options utility . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBcephfs\fP [ \fIpath\fP \fIcommand\fP \fIoptions\fP ] .fi .sp .SH DESCRIPTION .sp \fBcephfs\fP is a control utility for accessing and manipulating file layout and location data in the Ceph distributed storage system. .sp Choose one of the following three commands: .INDENT 0.0 .IP \(bu 2 \fBshow_layout\fP View the layout information on a file or directory .IP \(bu 2 \fBset_layout\fP Set the layout information on a file or directory .IP \(bu 2 \fBshow_location\fP View the location information on a file .UNINDENT .SH OPTIONS .sp Your applicable options differ depending on whether you are setting or viewing layout/location. .SS Viewing options: .INDENT 0.0 .TP .B \-l \-\-offset Specify an offset for which to retrieve location data .UNINDENT .SS Setting options: .INDENT 0.0 .TP .B \-u \-\-stripe_unit Set the size of each stripe .UNINDENT .INDENT 0.0 .TP .B \-c \-\-stripe_count Set the number of objects to stripe across .UNINDENT .INDENT 0.0 .TP .B \-s \-\-object_size Set the size of the objects to stripe across .UNINDENT .INDENT 0.0 .TP .B \-p \-\-pool Set the pool (by numeric value, not name!) to use .UNINDENT .INDENT 0.0 .TP .B \-o \-\-osd Set the preferred OSD to use as the primary .UNINDENT .SH LIMITATIONS .sp When setting layout data, the specified object size must evenly divide by the specified stripe unit. Any parameters you don\(aqt set explicitly are left at the system defaults. .sp Obviously setting the layout of a file and a directory means different things. Setting the layout of a file specifies exactly how to place the individual file. This must be done before writing \fIany\fP data to it. Truncating a file does not allow you to change the layout either. .sp Setting the layout of a directory sets the "default layout", which is used to set the file layouts on any files subsequently created in the directory (or any subdirectory). Pre\-existing files do not have their layouts changed. .sp You\(aqll notice that the layout information allows you to specify a preferred OSD for placement. This feature is unsupported and ignored in modern versions of the Ceph servers; do not use it. .SH AVAILABILITY .sp \fBcephfs\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/librados-config.80000664000175100017510000000422612623076744020607 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "LIBRADOS-CONFIG" "8" "January 12, 2014" "dev" "Ceph" .SH NAME librados-config \- display information about librados . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBlibrados\-config\fP [ \-\-version ] [ \-\-vernum ] .fi .sp .SH DESCRIPTION .INDENT 0.0 .TP .B \fBlibrados\-config\fP is a utility that displays information about the installed \fBlibrados\fP\&. .UNINDENT .SH OPTIONS .INDENT 0.0 .TP .B \-\-version Display \fBlibrados\fP version .UNINDENT .INDENT 0.0 .TP .B \-\-vernum Display the \fBlibrados\fP version code .UNINDENT .SH AVAILABILITY .sp \fBlibrados\-config\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBrados\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-mds.80000664000175100017510000000653412623076744017251 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-MDS" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-mds \- ceph metadata server daemon . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-mds\fP \-i \fIname\fP [[ \-\-hot\-standby [\fIrank\fP] ]|[\-\-journal_check \fIrank\fP]] .fi .sp .SH DESCRIPTION .sp \fBceph\-mds\fP is the metadata server daemon for the Ceph distributed file system. One or more instances of ceph\-mds collectively manage the file system namespace, coordinating access to the shared OSD cluster. .sp Each ceph\-mds daemon instance should have a unique name. The name is used to identify daemon instances in the ceph.conf. .sp Once the daemon has started, the monitor cluster will normally assign it a logical rank, or put it in a standby pool to take over for another daemon that crashes. Some of the specified options can cause other behaviors. .sp If you specify hot\-standby or journal\-check, you must either specify the rank on the command line, or specify one of the mds_standby_for_[rank|name] parameters in the config. The command line specification overrides the config, and specifying the rank overrides specifying the name. .SH OPTIONS .INDENT 0.0 .TP .B \-f, \-\-foreground Foreground: do not daemonize after startup (run in foreground). Do not generate a pid file. Useful when run via \fBceph\-run\fP(8). .UNINDENT .INDENT 0.0 .TP .B \-d Debug mode: like \fB\-f\fP, but also send all log output to stderr. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through \fBceph.conf\fP). .UNINDENT .SH AVAILABILITY .sp \fBceph\-mon\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBceph\-mon\fP(8), \fBceph\-osd\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-debugpack.80000664000175100017510000000503212623076744020403 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-DEBUGPACK" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-debugpack \- ceph debug packer utility . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-debugpack\fP [ \fIoptions\fP ] \fIfilename.tar.gz\fP .fi .sp .SH DESCRIPTION .sp \fBceph\-debugpack\fP will build a tarball containing various items that are useful for debugging crashes. The resulting tarball can be shared with Ceph developers when debugging a problem. .sp The tarball will include the binaries for ceph\-mds, ceph\-osd, and ceph\-mon, radosgw, any log files, the ceph.conf configuration file, any core files we can find, and (if the system is running) dumps of the current cluster state as reported by \(aqceph report\(aq. .SH OPTIONS .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .SH AVAILABILITY .sp \fBceph\-debugpack\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) \fBceph\-post\-file\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/radosgw-admin.80000664000175100017510000001437512623076744020307 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "RADOSGW-ADMIN" "8" "January 12, 2014" "dev" "Ceph" .SH NAME radosgw-admin \- rados REST gateway user administration utility . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBradosgw\-admin\fP \fIcommand\fP [ \fIoptions\fP \fI\&...\fP ] .fi .sp .SH DESCRIPTION .sp \fBradosgw\-admin\fP is a RADOS gateway user administration utility. It allows creating and modifying users. .SH COMMANDS .sp \fIcommand\fP can be one of the following options: .INDENT 0.0 .TP .B \fBuser create\fP Create a new user .TP .B \fBuser modify\fP Modify a user .TP .B \fBuser info\fP Display information of a user, and any potentially available subusers and keys .TP .B \fBuser rm\fP Remove a user .TP .B \fBsubuser create\fP Create a new subuser (primarily useful for clients using the Swift API) .TP .B \fBsubuser modify\fP Modify a subuser .TP .B \fBsubuser rm\fP Remove a subuser .TP .B \fBbucket list\fP List all buckets .TP .B \fBbucket unlink\fP Remove a bucket .TP .B \fBbucket rm\fP Remove a bucket .TP .B \fBobject rm\fP Remove an object .TP .B \fBkey create\fP Create an access key .TP .B \fBkey rm\fP Remove an access key .TP .B \fBpool add\fP Add an existing pool for data placement .TP .B \fBpool rm\fP Remove an existing pool from data placement set .TP .B \fBpools list\fP List placement active set .TP .B \fBpolicy\fP Display bucket/object policy .TP .B \fBlog show\fP Show the log of a bucket (with a specified date) .TP .B \fBusage show\fP Show the usage information (with optional user and date range) .TP .B \fBusage trim\fP Trim usage information (with optional user and date range) .UNINDENT .SH OPTIONS .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through ceph.conf). .UNINDENT .INDENT 0.0 .TP .B \-\-uid=uid The radosgw user ID. .UNINDENT .INDENT 0.0 .TP .B \-\-secret=secret The secret associated with a given key. .UNINDENT .INDENT 0.0 .TP .B \-\-display\-name=name Configure the display name of the user. .UNINDENT .INDENT 0.0 .TP .B \-\-email=email The e\-mail address of the user .UNINDENT .INDENT 0.0 .TP .B \-\-bucket=bucket Specify the bucket name. .UNINDENT .INDENT 0.0 .TP .B \-\-object=object Specify the object name. .UNINDENT .INDENT 0.0 .TP .B \-\-date=yyyy\-mm\-dd The date needed for some commands .UNINDENT .INDENT 0.0 .TP .B \-\-start\-date=yyyy\-mm\-dd The start date needed for some commands .UNINDENT .INDENT 0.0 .TP .B \-\-end\-date=yyyy\-mm\-dd The end date needed for some commands .UNINDENT .INDENT 0.0 .TP .B \-\-auth\-uid=auid The librados auid .UNINDENT .INDENT 0.0 .TP .B \-\-purge\-data Remove user data before user removal .UNINDENT .INDENT 0.0 .TP .B \-\-purge\-objects Remove all objects before bucket removal .UNINDENT .INDENT 0.0 .TP .B \-\-lazy\-remove Defer removal of object tail .UNINDENT .SH EXAMPLES .sp Generate a new user: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin user create \-\-display\-name="johnny rotten" \-\-uid=johnny { "user_id": "johnny", "rados_uid": 0, "display_name": "johnny rotten", "email": "", "suspended": 0, "subusers": [], "keys": [ { "user": "johnny", "access_key": "TCICW53D9BQ2VGC46I44", "secret_key": "tfm9aHMI8X76L3UdgE+ZQaJag1vJQmE6HDb5Lbrz"}], "swift_keys": []} .ft P .fi .UNINDENT .UNINDENT .sp Remove a user: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin user rm \-\-uid=johnny .ft P .fi .UNINDENT .UNINDENT .sp Remove a user and all associated buckets with their contents: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin user rm \-\-uid=johnny \-\-purge\-data .ft P .fi .UNINDENT .UNINDENT .sp Remove a bucket: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin bucket unlink \-\-bucket=foo .ft P .fi .UNINDENT .UNINDENT .sp Show the logs of a bucket from April 1st, 2012: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin log show \-\-bucket=foo \-\-date=2012=04\-01 .ft P .fi .UNINDENT .UNINDENT .sp Show usage information for user from March 1st to (but not including) April 1st, 2012: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin usage show \-\-uid=johnny \e \-\-start\-date=2012\-03\-01 \-\-end\-date=2012\-04\-01 .ft P .fi .UNINDENT .UNINDENT .sp Show only summary of usage information for all users: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin usage show \-\-show\-log\-entries=false .ft P .fi .UNINDENT .UNINDENT .sp Trim usage information for user until March 1st, 2012: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ radosgw\-admin usage trim \-\-uid=johnny \-\-end\-date=2012\-04\-01 .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBradosgw\-admin\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/Makefile.am0000664000175100017510000000073312623076744017507 0ustar jenkins-buildjenkins-buildAUTOMAKE_OPTIONS = gnu dist_man_MANS = \ ceph-disk.8 \ ceph-osd.8 \ ceph-mds.8 \ ceph-mon.8 \ mkcephfs.8 \ ceph-fuse.8 \ ceph-syn.8 \ crushtool.8 \ osdmaptool.8 \ monmaptool.8 \ ceph-conf.8 \ ceph-run.8 \ ceph.8 \ mount.ceph.8 \ radosgw.8 \ radosgw-admin.8 \ ceph-authtool.8 \ rados.8 \ librados-config.8 \ rbd.8 \ ceph-clsinfo.8 \ ceph-debugpack.8 \ cephfs.8 \ ceph-dencoder.8 \ ceph-rest-api.8 \ ceph-rbdnamer.8 \ ceph-post-file.8 \ rbd-fuse.8 ceph-0.80.11/man/ceph-conf.80000664000175100017510000000774112623076744017414 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-CONF" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-conf \- ceph conf file tool . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-conf\fP \-c \fIconffile\fP \-\-list\-all\-sections \fBceph\-conf\fP \-c \fIconffile\fP \-L \fBceph\-conf\fP \-c \fIconffile\fP \-l \fIprefix\fP \fBceph\-conf\fP \fIkey\fP \-s \fIsection1\fP ... \fBceph\-conf\fP [\-s \fIsection\fP ] \-\-lookup \fIkey\fP \fBceph\-conf\fP [\-s \fIsection\fP ] \fIkey\fP .fi .sp .SH DESCRIPTION .sp \fBceph\-conf\fP is a utility for getting information about a ceph configuration file. As with most Ceph programs, you can specify which Ceph configuration file to use with the \fB\-c\fP flag. .SH ACTIONS .sp \fBceph\-conf\fP will perform one of the following actions: .sp \-\-list\-all\-sections or \-L prints out a list of all the section names in the configuration file. .sp \-\-list\-sections or \-l prints out a list of all the sections that begin with a given prefix. For example, \-\-list\-sections mon would list all sections beginning with mon. .sp \-\-lookup will search the configuration for a given value. By default, the sections that are searched are determined by the Ceph name that we are using. The Ceph name defaults to client.admin. It can be specified with \-\-name. .sp For example, if we specify \-\-name osd.0, the following sections will be searched: [osd.0], [osd], [global] .sp You can specify additional sections to search with \-\-section or \-s. These additional sections will be searched before the sections that would normally be searched. As always, the first matching entry we find will be returned. .sp Note: \-\-lookup is the default action. If no other actions are given on the command line, we will default to doing a lookup. .SH EXAMPLES .sp To find out what value osd 0 will use for the "osd data" option: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-conf \-c foo.conf \-\-name osd.0 \-\-lookup "osd data" .ft P .fi .UNINDENT .UNINDENT .sp To find out what value will mds a use for the "log file" option: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-conf \-c foo.conf \-\-name mds.a "log file" .ft P .fi .UNINDENT .UNINDENT .sp To list all sections that begin with osd: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-conf \-c foo.conf \-l osd .ft P .fi .UNINDENT .UNINDENT .sp To list all sections: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-conf \-c foo.conf \-L .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBceph\-conf\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-mon.80000664000175100017510000000763212623076744017257 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-MON" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-mon \- ceph monitor daemon . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-mon\fP \-i \fImonid\fP [ \-\-mon\-data \fImondatapath\fP ] .fi .sp .SH DESCRIPTION .sp \fBceph\-mon\fP is the cluster monitor daemon for the Ceph distributed file system. One or more instances of \fBceph\-mon\fP form a Paxos part\-time parliament cluster that provides extremely reliable and durable storage of cluster membership, configuration, and state. .sp The \fImondatapath\fP refers to a directory on a local file system storing monitor data. It is normally specified via the \fBmon data\fP option in the configuration file. .SH OPTIONS .INDENT 0.0 .TP .B \-f, \-\-foreground Foreground: do not daemonize after startup (run in foreground). Do not generate a pid file. Useful when run via \fBceph\-run\fP(8). .UNINDENT .INDENT 0.0 .TP .B \-d Debug mode: like \fB\-f\fP, but also send all log output to stderr. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-\-mkfs Initialize the \fBmon data\fP directory with seed information to form and initial ceph file system or to join an existing monitor cluster. Three pieces of information must be provided: .INDENT 7.0 .IP \(bu 2 The cluster fsid. This can come from a monmap (\fB\-\-monmap \fP) or explicitly via \fB\-\-fsid \fP\&. .IP \(bu 2 A list of monitors and their addresses. This list of monitors can come from a monmap (\fB\-\-monmap \fP), the \fBmon host\fP configuration value (in \fIceph.conf\fP or via \fB\-m host1,host2,...\fP), or \fBmon addr\fP lines in \fIceph.conf\fP\&. If this monitor is to be part of the initial monitor quorum for a new Ceph cluster, then it must be included in the initial list, matching either the name or address of a monitor in the list. When matching by address, either the \fBpublic addr\fP or \fBpublic subnet\fP options may be used. .IP \(bu 2 The monitor secret key \fBmon.\fP\&. This must be included in the keyring provided via \fB\-\-keyring \fP\&. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B \-\-keyring Specify a keyring for use with \fB\-\-mkfs\fP\&. .UNINDENT .SH AVAILABILITY .sp \fBceph\-mon\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBceph\-mds\fP(8), \fBceph\-osd\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-dencoder.80000664000175100017510000001135512623076744020246 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-DENCODER" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-dencoder \- ceph encoder/decoder utility . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-dencoder\fP [commands...] .fi .sp .SH DESCRIPTION .sp \fBceph\-dencoder\fP is a utility to encode, decode, and dump ceph data structures. It is used for debugging and for testing inter\-version compatibility. .sp \fBceph\-dencoder\fP takes a simple list of commands and performs them in order. .SH COMMANDS .INDENT 0.0 .TP .B version Print the version string for the \fBceph\-dencoder\fP binary. .UNINDENT .INDENT 0.0 .TP .B import Read a binary blob of encoded data from the given file. It will be placed in an in\-memory buffer. .UNINDENT .INDENT 0.0 .TP .B export Write the contents of the current in\-memory buffer to the given file. .UNINDENT .INDENT 0.0 .TP .B list_types List the data types known to this build of \fBceph\-dencoder\fP\&. .UNINDENT .INDENT 0.0 .TP .B type Select the given type for future \fBencode\fP or \fBdecode\fP operations. .UNINDENT .INDENT 0.0 .TP .B decode Decode the contents of the in\-memory buffer into an instance of the previously selected type. If there is an error, report it. .UNINDENT .INDENT 0.0 .TP .B encode Encode the contents of the in\-memory instance of the previously selected type to the in\-memory buffer. .UNINDENT .INDENT 0.0 .TP .B dump_json Print a JSON\-formatted description of the in\-memory object. .UNINDENT .INDENT 0.0 .TP .B count_tests Print the number of built\-in test instances of the previosly selected type that \fBceph\-dencoder\fP is able to generate. .UNINDENT .INDENT 0.0 .TP .B select_test Select the given build\-in test instance as a the in\-memory instance of the type. .UNINDENT .INDENT 0.0 .TP .B get_features Print the decimal value of the feature set supported by this version of \fBceph\-dencoder\fP\&. Each bit represents a feature. These correspond to CEPH_FEATURE_* defines in src/include/ceph_features.h. .UNINDENT .INDENT 0.0 .TP .B set_features Set the feature bits provided to \fBencode\fP to \fIf\fP\&. This allows you to encode objects such that they can be understood by old versions of the software (for those types that support it). .UNINDENT .SH EXAMPLE .sp Say you want to examine an attribute on an object stored by \fBceph\-osd\fP\&. You can do: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ cd /mnt/osd.12/current/2.b_head $ attr \-l foo_bar_head_EFE6384B Attribute "ceph.snapset" has a 31 byte value for foo_bar_head_EFE6384B Attribute "ceph._" has a 195 byte value for foo_bar_head_EFE6384B $ attr foo_bar_head_EFE6384B \-g ceph._ \-q > /tmp/a $ ceph\-dencoder type object_info_t import /tmp/a decode dump_json { "oid": { "oid": "foo", "key": "bar", "snapid": \-2, "hash": 4024842315, "max": 0}, "locator": { "pool": 2, "preferred": \-1, "key": "bar"}, "category": "", "version": "9\(aq1", "prior_version": "0\(aq0", "last_reqid": "client.4116.0:1", "size": 1681, "mtime": "2012\-02\-21 08:58:23.666639", "lost": 0, "wrlock_by": "unknown.0.0:0", "snaps": [], "truncate_seq": 0, "truncate_size": 0, "watchers": {}} .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBceph\-dencoder\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/rados.80000664000175100017510000001401612623076744016653 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "RADOS" "8" "January 12, 2014" "dev" "Ceph" .SH NAME rados \- rados object storage utility . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBrados\fP [ \-m \fImonaddr\fP ] [ mkpool | rmpool \fIfoo\fP ] [ \-p | \-\-pool \fIpool\fP ] [ \-s | \-\-snap \fIsnap\fP ] [ \-i \fIinfile\fP ] [ \-o \fIoutfile\fP ] \fIcommand\fP ... .fi .sp .SH DESCRIPTION .sp \fBrados\fP is a utility for interacting with a Ceph object storage cluster (RADOS), part of the Ceph distributed storage system. .SH OPTIONS .INDENT 0.0 .TP .B \-p pool, \-\-pool pool Interact with the given pool. Required by most commands. .UNINDENT .INDENT 0.0 .TP .B \-s snap, \-\-snap snap Read from the given pool snapshot. Valid for all pool\-specific read operations. .UNINDENT .INDENT 0.0 .TP .B \-i infile will specify an input file to be passed along as a payload with the command to the monitor cluster. This is only used for specific monitor commands. .UNINDENT .INDENT 0.0 .TP .B \-o outfile will write any payload returned by the monitor cluster with its reply to outfile. Only specific monitor commands (e.g. osd getmap) return a payload. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use ceph.conf configuration file instead of the default /etc/ceph/ceph.conf to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through ceph.conf). .UNINDENT .SH GLOBAL COMMANDS .INDENT 0.0 .TP .B \fBlspools\fP List object pools .TP .B \fBdf\fP Show utilization statistics, including disk usage (bytes) and object counts, over the entire system and broken down by pool. .TP .B \fBmkpool\fP \fIfoo\fP Create a pool with name foo. .TP .B \fBrmpool\fP \fIfoo\fP [ \fIfoo\fP \-\-yes\-i\-really\-really\-mean\-it ] Delete the pool foo (and all its data) .UNINDENT .SH POOL SPECIFIC COMMANDS .INDENT 0.0 .TP .B \fBget\fP \fIname\fP \fIoutfile\fP Read object name from the cluster and write it to outfile. .TP .B \fBput\fP \fIname\fP \fIinfile\fP Write object name to the cluster with contents from infile. .TP .B \fBrm\fP \fIname\fP Remove object name. .TP .B \fBls\fP \fIoutfile\fP List objects in given pool and write to outfile. .TP .B \fBlssnap\fP List snapshots for given pool. .TP .B \fBclonedata\fP \fIsrcname\fP \fIdstname\fP \-\-object\-locator \fIkey\fP Clone object byte data from \fIsrcname\fP to \fIdstname\fP\&. Both objects must be stored with the locator key \fIkey\fP (usually either \fIsrcname\fP or \fIdstname\fP). Object attributes and omap keys are not copied or cloned. .TP .B \fBmksnap\fP \fIfoo\fP Create pool snapshot named \fIfoo\fP\&. .TP .B \fBrmsnap\fP \fIfoo\fP Remove pool snapshot named \fIfoo\fP\&. .TP .B \fBbench\fP \fIseconds\fP \fImode\fP [ \-b \fIobjsize\fP ] [ \-t \fIthreads\fP ] Benchmark for seconds. The mode can be write or read. The default object size is 4 MB, and the default number of simulated threads (parallel writes) is 16. .TP .B \fBlistomapkeys\fP \fIname\fP List all the keys stored in the object map of object name. .TP .B \fBlistomapvals\fP \fIname\fP List all key/value pairs stored in the object map of object name. The values are dumped in hexadecimal. .TP .B \fBgetomapval\fP \fIname\fP \fIkey\fP Dump the hexadecimal value of key in the object map of object name. .TP .B \fBsetomapval\fP \fIname\fP \fIkey\fP \fIvalue\fP Set the value of key in the object map of object name. .TP .B \fBrmomapkey\fP \fIname\fP \fIkey\fP Remove key from the object map of object name. .TP .B \fBgetomapheader\fP \fIname\fP Dump the hexadecimal value of the object map header of object name. .TP .B \fBsetomapheader\fP \fIname\fP \fIvalue\fP Set the value of the object map header of object name. .UNINDENT .SH EXAMPLES .sp To view cluster utilization: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rados df .ft P .fi .UNINDENT .UNINDENT .sp To get a list object in pool foo sent to stdout: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rados \-p foo ls \- .ft P .fi .UNINDENT .UNINDENT .sp To write an object: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rados \-p foo put myobject blah.txt .ft P .fi .UNINDENT .UNINDENT .sp To create a snapshot: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rados \-p foo mksnap mysnap .ft P .fi .UNINDENT .UNINDENT .sp To delete the object: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rados \-p foo rm myobject .ft P .fi .UNINDENT .UNINDENT .sp To read a previously snapshotted version of an object: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C rados \-p foo \-s mysnap get myobject blah.txt.old .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBrados\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-syn.80000664000175100017510000000772512623076744017302 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-SYN" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-syn \- ceph synthetic workload generator . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-syn\fP [ \-m \fImonaddr\fP:\fIport\fP ] \-\-syn \fIcommand\fP \fI\&...\fP .fi .sp .SH DESCRIPTION .sp \fBceph\-syn\fP is a simple synthetic workload generator for the Ceph distributed file system. It uses the userspace client library to generate simple workloads against a currently running file system. The file system need not be mounted via ceph\-fuse(8) or the kernel client. .sp One or more \fB\-\-syn\fP command arguments specify the particular workload, as documented below. .SH OPTIONS .INDENT 0.0 .TP .B \-d Detach from console and daemonize after startup. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-m monaddress[:port] Connect to specified monitor (instead of looking through \fBceph.conf\fP). .UNINDENT .INDENT 0.0 .TP .B \-\-num_client num Run num different clients, each in a separate thread. .UNINDENT .INDENT 0.0 .TP .B \-\-syn workloadspec Run the given workload. May be specified as many times as needed. Workloads will normally run sequentially. .UNINDENT .SH WORKLOADS .sp Each workload should be preceded by \fB\-\-syn\fP on the command line. This is not a complete list. .INDENT 0.0 .TP .B \fBmknap\fP \fIpath\fP \fIsnapname\fP Create a snapshot called \fIsnapname\fP on \fIpath\fP\&. .TP .B \fBrmsnap\fP \fIpath\fP \fIsnapname\fP Delete snapshot called \fIsnapname\fP on \fIpath\fP\&. .TP .B \fBrmfile\fP \fIpath\fP Delete/unlink \fIpath\fP\&. .TP .B \fBwritefile\fP \fIsizeinmb\fP \fIblocksize\fP Create a file, named after our client id, that is \fIsizeinmb\fP MB by writing \fIblocksize\fP chunks. .TP .B \fBreadfile\fP \fIsizeinmb\fP \fIblocksize\fP Read file, named after our client id, that is \fIsizeinmb\fP MB by writing \fIblocksize\fP chunks. .TP .B \fBrw\fP \fIsizeinmb\fP \fIblocksize\fP Write file, then read it back, as above. .TP .B \fBmakedirs\fP \fInumsubdirs\fP \fInumfiles\fP \fIdepth\fP Create a hierarchy of directories that is \fIdepth\fP levels deep. Give each directory \fInumsubdirs\fP subdirectories and \fInumfiles\fP files. .TP .B \fBwalk\fP Recursively walk the file system (like find). .UNINDENT .SH AVAILABILITY .sp \fBceph\-syn\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBceph\-fuse\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/rbd-fuse.80000664000175100017510000000525312623076744017255 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "RBD-FUSE" "8" "January 12, 2014" "dev" "Ceph" .SH NAME rbd-fuse \- expose rbd images as files . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBrbd\-fuse\fP [ \-p pool ] [\-c conffile] \fImountpoint\fP [ \fIfuse options\fP ] .fi .sp .SH DESCRIPTION .sp \fBrbd\-fuse\fP is a FUSE (File system in USErspace) client for RADOS block device (rbd) images. Given a pool containing rbd images, it will mount a userspace filesystem allowing access to those images as regular files at \fBmountpoint\fP\&. .sp The file system can be unmounted with: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C fusermount \-u mountpoint .ft P .fi .UNINDENT .UNINDENT .sp or by sending \fBSIGINT\fP to the \fBrbd\-fuse\fP process. .SH OPTIONS .sp Any options not recognized by rbd\-fuse will be passed on to libfuse. .INDENT 0.0 .TP .B \-c ceph.conf Use \fIceph.conf\fP configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-p pool Use \fIpool\fP as the pool to search for rbd images. Default is \fBrbd\fP\&. .UNINDENT .SH AVAILABILITY .sp \fBrbd\-fuse\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp fusermount(8), \fBrbd\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/Makefile.in0000664000175100017510000004234012623076764017522 0ustar jenkins-buildjenkins-build# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = man DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(dist_man_MANS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_check_classpath.m4 \ $(top_srcdir)/m4/ac_prog_jar.m4 \ $(top_srcdir)/m4/ac_prog_javac.m4 \ $(top_srcdir)/m4/ac_prog_javac_works.m4 \ $(top_srcdir)/m4/ac_prog_javah.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/ax_c_pretty_func.m4 \ $(top_srcdir)/m4/ax_c_var_func.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_cxx_static_cast.m4 \ $(top_srcdir)/m4/ax_intel.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/acconfig.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man8dir = $(mandir)/man8 am__installdirs = "$(DESTDIR)$(man8dir)" NROFF = nroff MANS = $(dist_man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CXXFLAGS = @AM_CXXFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@ CC = @CC@ CCAS = @CCAS@ CCASDEPMODE = @CCASDEPMODE@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOPP_CFLAGS = @CRYPTOPP_CFLAGS@ CRYPTOPP_LIBS = @CRYPTOPP_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CLASSPATH_JAR = @EXTRA_CLASSPATH_JAR@ FGREP = @FGREP@ GCOV_PREFIX_STRIP = @GCOV_PREFIX_STRIP@ GIT_CHECK = @GIT_CHECK@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTEL_FLAGS = @INTEL_FLAGS@ INTEL_PCLMUL_FLAGS = @INTEL_PCLMUL_FLAGS@ INTEL_SSE2_FLAGS = @INTEL_SSE2_FLAGS@ INTEL_SSE3_FLAGS = @INTEL_SSE3_FLAGS@ INTEL_SSE4_1_FLAGS = @INTEL_SSE4_1_FLAGS@ INTEL_SSE4_2_FLAGS = @INTEL_SSE4_2_FLAGS@ INTEL_SSE_FLAGS = @INTEL_SSE_FLAGS@ INTEL_SSSE3_FLAGS = @INTEL_SSSE3_FLAGS@ JAR = @JAR@ JAVAC = @JAVAC@ JAVAH = @JAVAH@ JDK_CPPFLAGS = @JDK_CPPFLAGS@ KEYUTILS_LIB = @KEYUTILS_LIB@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEDIT_CFLAGS = @LIBEDIT_CFLAGS@ LIBEDIT_LIBS = @LIBEDIT_LIBS@ LIBFUSE = @LIBFUSE@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTCMALLOC = @LIBTCMALLOC@ LIBTOOL = @LIBTOOL@ LIBZFS_CFLAGS = @LIBZFS_CFLAGS@ LIBZFS_LIBS = @LIBZFS_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NSS_CFLAGS = @NSS_CFLAGS@ NSS_LIBS = @NSS_LIBS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RESOLV_LIBS = @RESOLV_LIBS@ RPM_RELEASE = @RPM_RELEASE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WARN_IGNORED_QUALIFIERS = @WARN_IGNORED_QUALIFIERS@ WARN_TYPE_LIMITS = @WARN_TYPE_LIMITS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = gnu dist_man_MANS = \ ceph-disk.8 \ ceph-osd.8 \ ceph-mds.8 \ ceph-mon.8 \ mkcephfs.8 \ ceph-fuse.8 \ ceph-syn.8 \ crushtool.8 \ osdmaptool.8 \ monmaptool.8 \ ceph-conf.8 \ ceph-run.8 \ ceph.8 \ mount.ceph.8 \ radosgw.8 \ radosgw-admin.8 \ ceph-authtool.8 \ rados.8 \ librados-config.8 \ rbd.8 \ ceph-clsinfo.8 \ ceph-debugpack.8 \ cephfs.8 \ ceph-dencoder.8 \ ceph-rest-api.8 \ ceph-rbdnamer.8 \ ceph-post-file.8 \ rbd-fuse.8 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu man/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu man/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man8: $(dist_man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(dist_man_MANS)'; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man8 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man8 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-man \ uninstall-man8 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ceph-0.80.11/man/ceph.80000664000175100017510000011175212623076744016467 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH" "8" "March 13, 2015" "dev" "Ceph" .SH NAME ceph \- ceph administration tool . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\fP \fBauth\fP [ \fIadd\fP | \fIcaps\fP | \fIdel\fP | \fIexport\fP | \fIget\fP | \fIget\-key\fP | \fIget\-or\-create\fP | \fIget\-or\-create\-key\fP | \fIimport\fP | \fIlist\fP | \fIprint\-key\fP | \fIprint_key\fP ] ... .fi .sp .nf \fBceph\fP \fBcompact\fP .fi .sp .nf \fBceph\fP \fBconfig\-key\fP [ \fIdel\fP | \fIexists\fP | \fIget\fP | \fIlist\fP | \fIput\fP ] ... .fi .sp .nf \fBceph\fP \fBdf\fP \fI{detail}\fP .fi .sp .nf \fBceph\fP \fBfsid\fP .fi .sp .nf \fBceph\fP \fBhealth\fP \fI{detail}\fP .fi .sp .nf \fBceph\fP \fBheap\fP [ \fIdump\fP | \fIstart_profiler\fP | \fIstop_profiler\fP | \fIrelease\fP | \fIstats\fP ] ... .fi .sp .nf \fBceph\fP \fBinjectargs\fP \fI\fP [ \fI\fP\&... ] .fi .sp .nf \fBceph\fP \fBlog\fP \fI\fP [ \fI\fP\&... ] .fi .sp .nf \fBceph\fP \fBmds\fP [ \fIadd_data_pool\fP | \fIcluster_down\fP | \fIcluster_up\fP | \fIcompat\fP | \fIdeactivate\fP | \fIdump\fP | \fIfail\fP | \fIgetmap\fP | \fInewfs\fP | \fIremove_data_pool\fP | \fIrm\fP | \fIrmfailed\fP | \fIset\fP | \fIset_max_mds\fP | \fIset_state\fP | \fIsetmap\fP | \fIstat\fP | \fIstop\fP | \fItell\fP ] ... .fi .sp .nf \fBceph\fP \fBmon\fP [ \fIadd\fP | \fIdump\fP | \fIgetmap\fP | \fIremove\fP | \fIstat\fP ] ... .fi .sp .nf \fBceph\fP \fBmon_status\fP .fi .sp .nf \fBceph\fP \fBosd\fP [ \fIblacklist\fP | \fIcreate\fP | \fIdeep\-scrub\fP | \fIdown\fP | \fIdump\fP | \fIerasure\-code\-profile\fP | \fIfind\fP | \fIgetcrushmap\fP | \fIgetmap\fP | \fIgetmaxosd\fP | \fIin\fP | \fIlost\fP | \fIls\fP | \fIlspools\fP | \fImap\fP | \fImetadata\fP | \fIout\fP | \fIpause\fP | \fIperf\fP | \fIprimary\-affinity\fP | \fIprimary\-temp\fP | \fIrepair\fP | \fIreweight\fP | \fIreweight\-by\-utilization\fP | \fIrm\fP | \fIscrub\fP | \fIset\fP | \fIsetcrushmap\fP | \fIsetmaxosd\fP | \fIstat\fP | \fIthrash\fP | \fItree\fP | \fIunpause\fP | \fIunset\fP ] ... .fi .sp .nf \fBceph\fP \fBosd\fP \fBcrush\fP [ \fIadd\fP | \fIadd\-bucket\fP | \fIcreate\-or\-move\fP | \fIdump\fP | \fIget\-tunable\fP | \fIlink\fP | \fImove\fP | \fIremove\fP | \fIreweight\fP | \fIreweight\-all\fP | \fIrm\fP | \fIrule\fP | \fIset\fP | \fIset\-tunable\fP | \fIshow\-tunables\fP | \fItunables\fP | \fIunlink\fP ] ... .fi .sp .nf \fBceph\fP \fBosd\fP \fBpool\fP [ \fIcreate\fP | \fIdelete\fP | \fIget\fP | \fIget\-quota\fP | \fImksnap\fP | \fIrename\fP | \fIrmsnap\fP | \fIset\fP | \fIset\-quota\fP | \fIstats\fP ] ... .fi .sp .nf \fBceph\fP \fBosd\fP \fBtier\fP [ \fIadd\fP | \fIadd\-cache\fP | \fIcache\-mode\fP | \fIremove\fP | \fIremove\-overlay\fP | \fIset\-overlay\fP ] ... .fi .sp .nf \fBceph\fP \fBpg\fP [ \fIdebug\fP | \fIdeep\-scrub\fP | \fIdump\fP | \fIdump_json\fP | \fIdump_pools_json\fP | \fIdump_stuck\fP | \fIforce_create_pg\fP | \fIgetmap\fP | \fImap\fP | \fIrepair\fP | \fIscrub\fP | \fIsend_pg_creates\fP | \fIset_full_ratio\fP | \fIset_nearfull_ratio\fP | \fIstat\fP ] ... .fi .sp .nf \fBceph\fP \fBquorum\fP [ \fIenter\fP | \fIexit\fP ] .fi .sp .nf \fBceph\fP \fBquorum_status\fP .fi .sp .nf \fBceph\fP \fBreport\fP { \fI\fP [ \fI...\fP ] } .fi .sp .nf \fBceph\fP \fBscrub\fP .fi .sp .nf \fBceph\fP \fBstatus\fP .fi .sp .nf \fBceph\fP \fBsync\fP \fBforce\fP {\-\-yes\-i\-really\-mean\-it} {\-\-i\-know\-what\-i\-am\-doing} .fi .sp .nf \fBceph\fP \fBtell\fP \fI [...]\fP .fi .sp .SH DESCRIPTION .sp \fBceph\fP is a control utility which is used for manual deployment and maintenance of a Ceph cluster. It provides a diverse set of commands that allows deployment of monitors, OSDs, placement groups, MDS and overall maintenance, administration of the cluster. .SH COMMANDS .SS auth .sp Manage authentication keys. It is used for adding, removing, exporting or updating of authentication keys for a particular entity such as a monitor or OSD. It uses some additional subcommands. .sp Subcommand \fBadd\fP adds authentication info for a particular entity from input file, or random key if no input given and/or any caps specified in the command. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth add { [...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcaps\fP updates caps for \fBname\fP from caps specified in the command. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth caps [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdel\fP deletes all caps for \fBname\fP\&. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth del .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBexport\fP writes keyring for requested entity, or master keyring if none given. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth export {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\fP writes keyring file with requested key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth get .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\-key\fP displays requested key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth get\-key .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\-or\-create\fP adds authentication info for a particular entity from input file, or random key if no input given and/or any caps specified in the command. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth get\-or\-create { [...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\-or\-create\-key\fP gets or adds key for \fBname\fP from system/caps pairs specified in the command. If key already exists, any given caps must match the existing caps for that key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth get\-or\-create\-key { [...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBimport\fP reads keyring from input file. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth import .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBlist\fP lists authentication state. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth list .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBprint\-key\fP displays requested key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth print\-key .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBprint_key\fP displays requested key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph auth print_key .ft P .fi .UNINDENT .UNINDENT .SS compact .sp Causes compaction of monitor\(aqs leveldb storage. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph compact .ft P .fi .UNINDENT .UNINDENT .SS config\-key .sp Manage configuration key. It uses some additional subcommands. .sp Subcommand \fBdel\fP deletes configuration key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph config\-key del .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBexists\fP checks for configuration keys existence. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph config\-key exists .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\fP gets the configuration key. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph config\-key get .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBlist\fP lists configuration keys. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph config\-key list .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBput\fP puts configuration key and values. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph config\-key put {} .ft P .fi .UNINDENT .UNINDENT .SS df .sp Show cluster\(aqs free space status. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph df {detail} .ft P .fi .UNINDENT .UNINDENT .SS fsid .sp Show cluster\(aqs FSID/UUID. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph fsid .ft P .fi .UNINDENT .UNINDENT .SS health .sp Show cluster\(aqs health. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph health {detail} .ft P .fi .UNINDENT .UNINDENT .SS heap .sp Show heap usage info (available only if compiled with tcmalloc) .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph heap dump|start_profiler|stop_profiler|release|stats .ft P .fi .UNINDENT .UNINDENT .SS injectargs .sp Inject configuration arguments into monitor. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph injectargs [...] .ft P .fi .UNINDENT .UNINDENT .SS log .sp Log supplied text to the monitor log. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph log [...] .ft P .fi .UNINDENT .UNINDENT .SS mds .sp Manage metadata server configuration and administration. It uses some additional subcommands. .sp Subcommand \fBadd_data_pool\fP adds data pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds add_data_pool .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcluster_down\fP takes mds cluster down. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds cluster_down .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcluster_up\fP brings mds cluster up. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds cluster_up .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcompat\fP manages compatible features. It uses some additional subcommands. .sp Subcommand \fBrm_compat\fP removes compatible feature. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds compat rm_compat .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm_incompat\fP removes incompatible feature. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds compat rm_incompat .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBshow\fP shows mds compatibility settings. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds compat show .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdeactivate\fP stops mds. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds deactivate .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump\fP dumps information, optionally from epoch. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds dump {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBfail\fP forces mds to status fail. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds fail .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBgetmap\fP gets MDS map, optionally from epoch. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds getmap {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBnewfs\fP makes new filesystem using pools and . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds newfs {\-\-yes\-i\-really\-mean\-it} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBremove_data_pool\fP removes data pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds remove_data_pool .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm\fP removes inactive mds. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds rm (type.id)> .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrmfailed\fP removes failed mds. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds rmfailed .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\fP set mds parameter to .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds set max_mds|max_file_size|allow_new_snaps|inline_data {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset_max_mds\fP sets max MDS index. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds set_max_mds .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset_state\fP sets mds state of to . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds set_state .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBsetmap\fP sets mds map; must supply correct epoch number. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds setmap .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBstat\fP shows MDS status. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds stat .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBstop\fP stops mds. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds stop .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBtell\fP sends command to particular mds. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mds tell [...] .ft P .fi .UNINDENT .UNINDENT .SS mon .sp Manage monitor configuration and administration. It uses some additional subcommands. .sp Subcommand \fBadd\fP adds new monitor named at . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mon add .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump\fP dumps formatted monmap (optionally from epoch) .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mon dump {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBgetmap\fP gets monmap. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mon getmap {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBremove\fP removes monitor named . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mon remove .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBstat\fP summarizes monitor status. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mon stat .ft P .fi .UNINDENT .UNINDENT .SS mon_status .sp Reports status of monitors. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph mon_status .ft P .fi .UNINDENT .UNINDENT .SS osd .sp Manage OSD configuration and administration. It uses some additional subcommands. .sp Subcommand \fBblacklist\fP manage blacklisted clients. It uses some additional subcommands. .sp Subcommand \fBadd\fP add to blacklist (optionally until seconds from now) .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd blacklist add {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBls\fP show blacklisted clients .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd blacklist ls .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm\fP remove from blacklist .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd blacklist rm .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcreate\fP creates new osd (with optional UUID). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd create {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcrush\fP is used for CRUSH management. It uses some additional subcommands. .sp Subcommand \fBadd\fP adds or updates crushmap position and weight for with and location . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush add [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBadd\-bucket\fP adds no\-parent (probably root) crush bucket of type . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush add\-bucket .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcreate\-or\-move\fP creates entry or moves existing entry for at/to location . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush create\-or\-move [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump\fP dumps crush map. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush dump .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\-tunable\fP get crush tunable straw_calc_version .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush get\-tunable straw_calc_version .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBlink\fP links existing entry for under location . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush link [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBmove\fP moves existing entry for to location . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush move [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBremove\fP removes from crush map (everywhere, or just at ). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush remove {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBreweight\fP change \(aqs weight to in crush map. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush reweight .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBreweight\-all\fP recalculate the weights for the tree to ensure they sum correctly .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush reweight\-all .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm\fP removes from crush map (everywhere, or just at ). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rm {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrule\fP is used for creating crush rules. It uses some additional subcommands. .sp Subcommand \fBcreate\-erasure\fP creates crush rule for erasure coded pool created with (default default). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rule create\-erasure {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcreate\-simple\fP creates crush rule to start from , replicate across buckets of type , using a choose mode of (default firstn; indep best for erasure pools). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rule create\-simple {firstn|indep} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump\fP dumps crush rule (default all). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rule dump {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBlist\fP lists crush rules. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rule list .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBls\fP lists crush rules. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rule ls .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm\fP removes crush rule . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush rule rm .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\fP used alone, sets crush map from input file. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush set .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\fP with osdname/osd.id update crushmap position and weight for to with location . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush set [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\-tunable\fP set crush tunable to . The only tunable that can be set is straw_calc_version. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush set\-tunable straw_calc_version .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBshow\-tunables\fP shows current crush tunables. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush show\-tunables .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBtunables\fP sets crush tunables values to . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush tunables legacy|argonaut|bobtail|firefly|optimal|default .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBunlink\fP unlinks from crush map (everywhere, or just at ). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd crush unlink {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdeep\-scrub\fP initiates deep scrub on specified osd. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd deep\-scrub .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdown\fP sets osd(s) [...] down. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd down [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump\fP prints summary of OSD map. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd dump {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBerasure\-code\-profile\fP is used for managing the erasure code profiles. It uses some additional subcommands. .sp Subcommand \fBget\fP gets erasure code profile . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd erasure\-code\-profile get .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBls\fP lists all erasure code profiles. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd erasure\-code\-profile ls .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm\fP removes erasure code profile . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd erasure\-code\-profile rm .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\fP creates erasure code profile with [ ...] pairs. Add a \-\-force at the end to override an existing profile (IT IS RISKY). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd erasure\-code\-profile set { [...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBfind\fP find osd in the CRUSH map and shows its location. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd find .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBgetcrushmap\fP gets CRUSH map. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd getcrushmap {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBgetmap\fP gets OSD map. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd getmap {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBgetmaxosd\fP shows largest OSD id. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd getmaxosd .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBin\fP sets osd(s) [...] in. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd in [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBlost\fP marks osd as permanently lost. THIS DESTROYS DATA IF NO MORE REPLICAS EXIST, BE CAREFUL. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd lost {\-\-yes\-i\-really\-mean\-it} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBls\fP shows all OSD ids. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd ls {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBlspools\fP lists pools. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd lspools {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBmap\fP finds pg for in . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd map .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBmetadata\fP fetches metadata for osd . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd metadata .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBout\fP sets osd(s) [...] out. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd out [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBpause\fP pauses osd. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pause .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBperf\fP prints dump of OSD perf summary stats. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd perf .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBpg\-temp\fP set pg_temp mapping pgid:[ [...]] (developers only). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pg\-temp { [...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBpool\fP is used for managing data pools. It uses some additional subcommands. .sp Subcommand \fBcreate\fP creates pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool create {} {replicated|erasure} {} {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdelete\fP deletes pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool delete {} {\-\-yes\-i\-really\-really\-mean\-it} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\fP gets pool parameter . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool get size|min_size|crash_replay_interval|pg_num| pgp_num|crush_ruleset|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp ceph osd pool get auid|target_max_objects|target_max_bytes ceph osd pool get cache_target_dirty_ratio|cache_target_full_ratio ceph osd pool get cache_min_flush_age|cache_min_evict_age| erasure_code_profile .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBget\-quota\fP obtains object or byte limits for pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool get\-quota .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBmksnap\fP makes snapshot in . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool mksnap .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrename\fP renames to . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool rename .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrmsnap\fP removes snapshot from . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool rmsnap .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\fP sets pool parameter to . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool set size|min_size|crash_replay_interval| pg_num|pgp_num|crush_ruleset|hashpspool|hit_set_type|hit_set_period| hit_set_count|hit_set_fpp|debug_fake_ec_pool| target_max_bytes| target_max_objects|cache_target_dirty_ratio|cache_target_full_ratio| cache_min_flush_age|cache_min_evict_age|auid {\-\-yes\-i\-really\-mean\-it} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\-quota\fP sets object or byte limit on pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool set\-quota max_objects|max_bytes .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBstats\fP obtain stats from all pools, or from specified pool. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd pool stats {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBprimary\-affinity\fP adjust osd primary\-affinity from 0.0 <= <= 1.0 .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd primary\-affinity .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBprimary\-temp\fP sets primary_temp mapping pgid:|\-1 (developers only). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd primary\-temp .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrepair\fP initiates repair on a specified osd. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd repair .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBreweight\fP reweights osd to 0.0 < < 1.0. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C osd reweight .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBreweight\-by\-utilization\fP reweight OSDs by utilization [overload\-percentage\-for\-consideration, default 120]. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd reweight\-by\-utilization {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrm\fP removes osd(s) [...] in the cluster. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd rm [...] .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBscrub\fP initiates scrub on specified osd. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd scrub .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\fP sets . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd set pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub| nodeep\-scrub|notieragent .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBsetcrushmap\fP sets crush map from input file. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd setcrushmap .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBsetmaxosd\fP sets new maximum osd value. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd setmaxosd .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBstat\fP prints summary of OSD map. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd stat .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBthrash\fP thrashes OSDs for . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd thrash .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBtier\fP is used for managing tiers. It uses some additional subcommands. .sp Subcommand \fBadd\fP adds the tier (the second one) to base pool (the first one). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tier add {\-\-force\-nonempty} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBadd\-cache\fP adds a cache (the second one) of size to existing pool (the first one). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tier add\-cache .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBcache\-mode\fP specifies the caching mode for cache tier . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tier cache\-mode none|writeback|forward|readonly .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBremove\fP removes the tier (the second one) from base pool (the first one). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tier remove .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBremove\-overlay\fP removes the overlay pool for base pool . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tier remove\-overlay .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset\-overlay\fP set the overlay pool for base pool to be . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tier set\-overlay .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBtree\fP prints OSD tree. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd tree {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBunpause\fP unpauses osd. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph osd unpause .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBunset\fP unsets . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C osd unset pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub| nodeep\-scrub|notieragent .ft P .fi .UNINDENT .UNINDENT .SS pg .sp It is used for managing the placement groups in OSDs. It uses some additional subcommands. .sp Subcommand \fBdebug\fP shows debug info about pgs. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg debug unfound_objects_exist|degraded_pgs_exist .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdeep\-scrub\fP starts deep\-scrub on . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg deep\-scrub .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump\fP shows human\-readable versions of pg map (only \(aqall\(aq valid with plain). .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg dump {all|summary|sum|delta|pools|osds|pgs|pgs_brief} [{all|summary|sum|delta|pools|osds|pgs|pgs_brief...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump_json\fP shows human\-readable version of pg map in json only. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg dump_json {all|summary|sum|delta|pools|osds|pgs|pgs_brief} [{all|summary|sum|delta|pools|osds|pgs|pgs_brief...]} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump_pools_json\fP shows pg pools info in json only. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg dump_pools_json .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBdump_stuck\fP shows information about stuck pgs. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg dump_stuck {inactive|unclean|stale [inactive|unclean|stale...]} {} .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBforce_create_pg\fP forces creation of pg . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg force_create_pg .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBgetmap\fP gets binary pg map to \-o/stdout. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg getmap .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBmap\fP shows mapping of pg to osds. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg map .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBrepair\fP starts repair on . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg repair .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBscrub\fP starts scrub on . .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg scrub .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBsend_pg_creates\fP triggers pg creates to be issued. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg send_pg_creates .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset_full_ratio\fP sets ratio at which pgs are considered full. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg set_full_ratio .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBset_nearfull_ratio\fP sets ratio at which pgs are considered nearly full. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg set_nearfull_ratio .ft P .fi .UNINDENT .UNINDENT .sp Subcommand \fBstat\fP shows placement group status. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph pg stat .ft P .fi .UNINDENT .UNINDENT .SS quorum .sp Enter or exit quorum. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph quorum enter|exit .ft P .fi .UNINDENT .UNINDENT .SS quorum_status .sp Reports status of monitor quorum. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph quorum_status .ft P .fi .UNINDENT .UNINDENT .SS report .sp Reports full status of cluster, optional title tag strings. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph report { [...]} .ft P .fi .UNINDENT .UNINDENT .SS scrub .sp Scrubs the monitor stores. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph scrub .ft P .fi .UNINDENT .UNINDENT .SS status .sp Shows cluster status. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph status .ft P .fi .UNINDENT .UNINDENT .SS sync force .sp Forces sync of and clear monitor store. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph sync force {\-\-yes\-i\-really\-mean\-it} {\-\-i\-know\-what\-i\-am\-doing} .ft P .fi .UNINDENT .UNINDENT .SS tell .sp Sends a command to a specific daemon. .sp Usage: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph tell [...] .ft P .fi .UNINDENT .UNINDENT .SH OPTIONS .INDENT 0.0 .TP .B \-i infile will specify an input file to be passed along as a payload with the command to the monitor cluster. This is only used for specific monitor commands. .UNINDENT .INDENT 0.0 .TP .B \-o outfile will write any payload returned by the monitor cluster with its reply to outfile. Only specific monitor commands (e.g. osd getmap) return a payload. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use ceph.conf configuration file instead of the default \fB/etc/ceph/ceph.conf\fP to determine monitor addresses during startup. .UNINDENT .INDENT 0.0 .TP .B \-\-id CLIENT_ID, \-\-user CLIENT_ID Client id for authentication. .UNINDENT .INDENT 0.0 .TP .B \-\-name CLIENT_NAME, \-n CLIENT_NAME Client name for authentication. .UNINDENT .INDENT 0.0 .TP .B \-\-cluster CLUSTER Name of the Ceph cluster. .UNINDENT .INDENT 0.0 .TP .B \-\-admin\-daemon ADMIN_SOCKET Submit admin\-socket commands. .UNINDENT .INDENT 0.0 .TP .B \-\-admin\-socket ADMIN_SOCKET_NOPE You probably mean \-\-admin\-daemon .UNINDENT .INDENT 0.0 .TP .B \-s, \-\-status Show cluster status. .UNINDENT .INDENT 0.0 .TP .B \-w, \-\-watch Watch live cluster changes. .UNINDENT .INDENT 0.0 .TP .B \-\-watch\-debug Watch debug events. .UNINDENT .INDENT 0.0 .TP .B \-\-watch\-info Watch info events. .UNINDENT .INDENT 0.0 .TP .B \-\-watch\-sec Watch security events. .UNINDENT .INDENT 0.0 .TP .B \-\-watch\-warn Watch warning events. .UNINDENT .INDENT 0.0 .TP .B \-\-watch\-error Watch error events. .UNINDENT .INDENT 0.0 .TP .B \-\-version, \-v Display version. .UNINDENT .INDENT 0.0 .TP .B \-\-verbose Make verbose. .UNINDENT .INDENT 0.0 .TP .B \-\-concise Make less verbose. .UNINDENT .INDENT 0.0 .TP .B \-f {json,json\-pretty,xml,xml\-pretty,plain}, \-\-format Format of output. .UNINDENT .INDENT 0.0 .TP .B \-\-connect\-timeout CLUSTER_TIMEOUT Set a timeout for connecting to the cluster. .UNINDENT .SH AVAILABILITY .sp \fBceph\fP is a part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\-mon\fP(8), \fBceph\-osd\fP(8), \fBceph\-mds\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-post-file.80000664000175100017510000000646412623076744020372 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-POST-FILE" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-post-file \- post files for ceph developers . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-post\-file\fP [\-d \fIdescription] [\-u *user\fP] \fIfile or dir\fP ... .fi .sp .SH DESCRIPTION .sp \fBceph\-post\-file\fP will upload files or directories to ceph.com for later analysis by Ceph developers. .sp Each invocation uploads files or directories to a separate directory with a unique tag. That tag can be passed to a developer or referenced in a bug report (\fI\%http://tracker.ceph.com/\fP). Once the upload completes, the directory is marked non\-readable and non\-writeable to prevent access or modification by other users. .SH WARNING .sp Basic measures are taken to make posted data be visible only to developers with access to ceph.com infrastructure. However, users should think twice and/or take appropriate precautions before posting potentially sensitive data (for example, logs or data directories that contain Ceph secrets). .SH OPTIONS .INDENT 0.0 .TP .B \-d *description*, \-\-description *description* Add a short description for the upload. This is a good opportunity to reference a bug number. There is no default value. .UNINDENT .INDENT 0.0 .TP .B \-u *user* Set the user metadata for the upload. This defaults to \fIwhoami\(ga@\(gahostname \-f\fP\&. .UNINDENT .SH EXAMPLES .sp To upload a single log: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-post\-file /var/log/ceph/ceph\-mon.\(gahostname\(ga.log .ft P .fi .UNINDENT .UNINDENT .sp To upload several directories: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ceph\-post\-file \-d \(aqmon data directories\(aq /var/log/ceph/mon/* .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBceph\-post\-file\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBceph\-debugpack\fP(8), .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/mkcephfs.80000664000175100017510000001107612623076744017346 0ustar jenkins-buildjenkins-build.TH "MKCEPHFS" "8" "April 29, 2013" "dev" "Ceph" .SH NAME mkcephfs \- create a ceph file system . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .SH SYNOPSIS .nf \fBmkcephfs\fP \-c \fIceph.conf\fP [ \-\-mkfs ] [ \-a, \-\-all\-hosts [ \-k \fI/path/to/admin.keyring\fP ] ] .fi .sp .SH DESCRIPTION .sp \fBmkcephfs\fP is used to create an empty Ceph file system, possibly spanning multiple hosts. The ceph.conf file describes the composition of the entire Ceph cluster, including which hosts are participating, which daemons run where, and which paths are used to store file system data or metadata. .sp The mkcephfs tool can be used in two ways. If \-a is used, it will use ssh and scp to connect to remote hosts on your behalf and do the setup of the entire cluster. This is the easiest solution, but can also be inconvenient (if you don\(aqt have ssh to connect without prompting for passwords) or slow (if you have a large cluster). .sp Alternatively, you can run each setup phase manually. First, you need to prepare a monmap that will be shared by each node: .sp .nf .ft C # prepare master# mkdir /tmp/foo master# mkcephfs \-c /etc/ceph/ceph.conf \e \-\-prepare\-monmap \-d /tmp/foo .ft P .fi .sp Share the \fB/tmp/foo\fP directory with other nodes in whatever way is convenient for you. On each OSD and MDS node: .sp .nf .ft C osdnode# mkcephfs \-\-init\-local\-daemons osd \-d /tmp/foo mdsnode# mkcephfs \-\-init\-local\-daemons mds \-d /tmp/foo .ft P .fi .sp Collect the contents of the /tmp/foo directories back onto a single node, and then: .sp .nf .ft C master# mkcephfs \-\-prepare\-mon \-d /tmp/foo .ft P .fi .sp Finally, distribute \fB/tmp/foo\fP to all monitor nodes and, on each of those nodes: .sp .nf .ft C monnode# mkcephfs \-\-init\-local\-daemons mon \-d /tmp/foo .ft P .fi .SH OPTIONS .INDENT 0.0 .TP .B \-a, \-\-allhosts Performs the necessary initialization steps on all hosts in the cluster, executing commands via SSH. .UNINDENT .INDENT 0.0 .TP .B \-c ceph.conf, \-\-conf=ceph.conf Use the given conf file instead of the default \fB/etc/ceph/ceph.conf\fP. .UNINDENT .INDENT 0.0 .TP .B \-k /path/to/keyring When \fB\-a\fP is used, we can specify a location to copy the client.admin keyring, which is used to administer the cluster. The default is \fB/etc/ceph/keyring\fP (or whatever is specified in the config file). .UNINDENT .INDENT 0.0 .TP .B \-\-mkfs Create and mount the file systems specified in the ceph.conf for OSD data storage using mkfs.$type. The \fBdevs\fP option in ceph.conf must specify the device(s) and the \fBosd mkfs type\fP option must specify the file system type (normally one of btrfs, xfs, or ext4). .UNINDENT .INDENT 0.0 .TP .B \-\-no\-copy\-conf By default, mkcephfs with \-a will copy the new configuration to /etc/ceph/ceph.conf on each node in the cluster. This option disables that behavior. .UNINDENT .SH SUBCOMMANDS .sp The sub\-commands performed during cluster setup can be run individually with .INDENT 0.0 .TP .B \-\-prepare\-monmap \-d dir \-c ceph.conf Create an initial monmap with a random fsid/uuid and store it and the ceph.conf in dir. .UNINDENT .INDENT 0.0 .TP .B \-\-init\-local\-daemons type \-d dir Initialize any daemons of type type on the local host using the monmap in dir. For types osd and mds, the resulting authentication keys will be placed in dir. For type mon, the initial data files generated by \-\-prepare\-mon (below) are expected in dir. .UNINDENT .INDENT 0.0 .TP .B \-\-prepare\-mon \-d dir Prepare the initial monitor data based on the monmap, OSD, and MDS authentication keys collected in dir, and put the result in dir. .UNINDENT .SH AVAILABILITY .sp \fBmkcephfs\fP is part of the Ceph distributed file system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8), \fBmonmaptool\fP(8), \fBosdmaptool\fP(8), \fBcrushtool\fP(8) .SH COPYRIGHT 2010-2013, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/mount.ceph.80000664000175100017510000001334612623076744017630 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "MOUNT.CEPH" "8" "January 12, 2014" "dev" "Ceph" .SH NAME mount.ceph \- mount a ceph file system . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBmount.ceph\fP \fImonaddr1\fP[,\fImonaddr2\fP,...]:/[\fIsubdir\fP] \fIdir\fP [ \-o \fIoptions\fP ] .fi .sp .SH DESCRIPTION .sp \fBmount.ceph\fP is a simple helper for mounting the Ceph file system on a Linux host. It serves to resolve monitor hostname(s) into IP addresses and read authentication keys from disk; the Linux kernel client component does most of the real work. In fact, it is possible to mount a non\-authenticated Ceph file system without mount.ceph by specifying monitor address(es) by IP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount \-t ceph 1.2.3.4:/ mountpoint .ft P .fi .UNINDENT .UNINDENT .sp Each monitor address monaddr takes the form host[:port]. If the port is not specified, the Ceph default of 6789 is assumed. .sp Multiple monitor addresses can be separated by commas. Only one responsible monitor is needed to successfully mount; the client will learn about all monitors from any responsive monitor. However, it is a good idea to specify more than one in case one happens to be down at the time of mount. .sp A subdirectory subdir may be specified if a subset of the file system is to be mounted. .sp Mount helper application conventions dictate that the first two options are device to be mounted and destination path. Options must be passed only after these fixed arguments. .SH OPTIONS .INDENT 0.0 .TP .B \fBwsize\fP int, max write size. Default: none (writeback uses smaller of wsize and stripe unit) .TP .B \fBrsize\fP int (bytes), max readahead, multiple of 1024, Default: 524288 (512*1024) .TP .B \fBosdtimeout\fP int (seconds), Default: 60 .TP .B \fBosdkeepalivetimeout\fP int, Default: 5 .TP .B \fBmount_timeout\fP int (seconds), Default: 60 .TP .B \fBosd_idle_ttl\fP int (seconds), Default: 60 .TP .B \fBcaps_wanted_delay_min\fP int, cap release delay, Default: 5 .TP .B \fBcaps_wanted_delay_max\fP int, cap release delay, Default: 60 .TP .B \fBcap_release_safety\fP int, Default: calculated .TP .B \fBreaddir_max_entries\fP int, Default: 1024 .TP .B \fBreaddir_max_bytes\fP int, Default: 524288 (512*1024) .TP .B \fBwrite_congestion_kb\fP int (kb), max writeback in flight. scale with available memory. Default: calculated from available memory .TP .B \fBsnapdirname\fP string, set the name of the hidden snapdir. Default: .snap .TP .B \fBname\fP RADOS user to authenticate as when using cephx. Default: guest .TP .B \fBsecret\fP secret key for use with cephx. This option is insecure because it exposes the secret on the command line. To avoid this, use the secretfile option. .TP .B \fBsecretfile\fP path to file containing the secret key to use with cephx .TP .B \fBip\fP my ip .TP .B \fBnoshare\fP create a new client instance, instead of sharing an existing instance of a client mounting the same cluster .TP .B \fBdirstat\fP funky \fIcat dirname\fP for stats, Default: off .TP .B \fBnodirstat\fP no funky \fIcat dirname\fP for stats .TP .B \fBrbytes\fP Report the recursive size of the directory contents for st_size on directories. Default: on .TP .B \fBnorbytes\fP Do not report the recursive size of the directory contents for st_size on directories. .TP .B \fBnocrc\fP no data crc on writes .TP .B \fBnoasyncreaddir\fP no dcache readdir .UNINDENT .SH EXAMPLES .sp Mount the full file system: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount.ceph monhost:/ /mnt/foo .ft P .fi .UNINDENT .UNINDENT .sp If there are multiple monitors: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount.ceph monhost1,monhost2,monhost3:/ /mnt/foo .ft P .fi .UNINDENT .UNINDENT .sp If \fBceph\-mon\fP(8) is running on a non\-standard port: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount.ceph monhost1:7000,monhost2:7000,monhost3:7000:/ /mnt/foo .ft P .fi .UNINDENT .UNINDENT .sp To mount only part of the namespace: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount.ceph monhost1:/some/small/thing /mnt/thing .ft P .fi .UNINDENT .UNINDENT .sp Assuming mount.ceph(8) is installed properly, it should be automatically invoked by mount(8) like so: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C mount \-t ceph monhost:/ /mnt/foo .ft P .fi .UNINDENT .UNINDENT .SH AVAILABILITY .sp \fBmount.ceph\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\-fuse\fP(8), \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/man/ceph-rest-api.80000664000175100017510000001545012623076744020207 0ustar jenkins-buildjenkins-build.\" Man page generated from reStructuredText. . .TH "CEPH-REST-API" "8" "January 12, 2014" "dev" "Ceph" .SH NAME ceph-rest-api \- ceph RESTlike administration server . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .nf \fBceph\-rest\-api\fP [ \-c \fIconffile\fP ] [\-\-cluster \fIclustername\fP ] [ \-n \fIname\fP ] [\-i \fIid\fP ] .fi .sp .SH DESCRIPTION .sp \fBceph\-rest\-api\fP is a WSGI application that can run as a standalone web service or run under a web server that supports WSGI. It provides much of the functionality of the \fBceph\fP command\-line tool through an HTTP\-accessible interface. .SH OPTIONS .INDENT 0.0 .TP .B \-c/\-\-conf conffile names the ceph.conf file to use for configuration. If \-c is not specified, the default depends on the state of the \-\-cluster option (default \(aqceph\(aq; see below). The configuration file is searched for in this order: .INDENT 7.0 .IP \(bu 2 $CEPH_CONF .IP \(bu 2 /etc/ceph/${cluster}.conf .IP \(bu 2 ~/.ceph/${cluster}.conf .IP \(bu 2 ${cluster}.conf (in the current directory) .UNINDENT .sp so you can also pass this option in the environment as CEPH_CONF. .UNINDENT .INDENT 0.0 .TP .B \-\-cluster clustername set \fIclustername\fP for use in the $cluster metavariable, for locating the ceph.conf file. The default is \(aqceph\(aq. .UNINDENT .INDENT 0.0 .TP .B \-n/\-\-name name specifies the client \(aqname\(aq, which is used to find the client\-specific configuration options in the config file, and also is the name used for authentication when connecting to the cluster (the entity name appearing in ceph auth list output, for example). The default is \(aqclient.restapi\(aq. .UNINDENT .INDENT 0.0 .TP .B \-i/\-\-id id specifies the client \(aqid\(aq, which will form the clientname as \(aqclient.\(aq if clientname is not set. If \-n/\-name is set, that takes precedence. .sp Also, global Ceph options are supported. .UNINDENT .SH CONFIGURATION PARAMETERS .sp Supported configuration parameters include: .INDENT 0.0 .IP \(bu 2 \fBkeyring\fP the keyring file holding the key for \(aqclientname\(aq .IP \(bu 2 \fBpublic addr\fP ip:port to listen on (default 0.0.0.0:5000) .IP \(bu 2 \fBlog file\fP (usual Ceph default) .IP \(bu 2 \fBrestapi base url\fP the base URL to answer requests on (default /api/v0.1) .IP \(bu 2 \fBrestapi log level\fP critical, error, warning, info, debug (default warning) .UNINDENT .sp Configuration parameters are searched in the standard order: first in the section named \(aq\(aq, then \(aqclient\(aq, then \(aqglobal\(aq. .sp is either supplied by \-n/\-\-name, "client." where is supplied by \-i/\-\-id, or \(aqclient.restapi\(aq if neither option is present. .sp A single\-threaded server will run on \fBpublic addr\fP if the ceph\-rest\-api executed directly; otherwise, configuration is specified by the enclosing WSGI web server. .SH COMMANDS .sp Commands are submitted with HTTP GET requests (for commands that primarily return data) or PUT (for commands that affect cluster state). HEAD and OPTIONS are also supported. Standard HTTP status codes are returned. .sp For commands that return bulk data, the request can include Accept: application/json or Accept: application/xml to select the desired structured output, or you may use a .json or .xml addition to the requested PATH. Parameters are supplied as query parameters in the request; for parameters that take more than one value, repeat the key=val construct. For instance, to remove OSDs 2 and 3, send a PUT request to \fBosd/rm?ids=2&ids=3\fP\&. .SH DISCOVERY .sp Human\-readable discovery of supported commands and parameters, along with a small description of each command, is provided when the requested path is incomplete/partially matching. Requesting / will redirect to the value of \fBrestapi base url\fP, and that path will give a full list of all known commands. For example, requesting \fBapi/vX.X/mon\fP will return the list of API calls for monitors \- \fBapi/vX.X/osd\fP will return the list of API calls for OSD and so on. .sp The command set is very similar to the commands supported by the \fBceph\fP tool. One notable exception is that the \fBceph pg \fP style of commands is supported here as \fBtell//command?args\fP\&. .SH DEPLOYMENT AS WSGI APPLICATION .sp When deploying as WSGI application (say, with Apache/mod_wsgi, or nginx/uwsgi, or gunicorn, etc.), use the \fBceph_rest_api.py\fP module (\fBceph\-rest\-api\fP is a thin layer around this module). The standalone web server is of course not used, so address/port configuration is done in the WSGI server. Use a python .wsgi module or the equivalent to call \fBapp = generate_app(conf, cluster, clientname, clientid, args)\fP where: .INDENT 0.0 .IP \(bu 2 conf is as \-c/\-\-conf above .IP \(bu 2 cluster is as \-\-cluster above .IP \(bu 2 clientname, \-n/\-\-name .IP \(bu 2 clientid, \-i/\-\-id, and .IP \(bu 2 args are any other generic Ceph arguments .UNINDENT .sp When app is returned, it will have attributes \(aqceph_addr\(aq and \(aqceph_port\(aq set to what the address and port are in the Ceph configuration; those may be used for the server, or ignored. .sp Any errors reading configuration or connecting to the cluster cause an exception to be raised; see your WSGI server documentation for how to see those messages in case of problem. .SH AVAILABILITY .sp \fBceph\-rest\-api\fP is part of the Ceph distributed storage system. Please refer to the Ceph documentation at \fI\%http://ceph.com/docs\fP for more information. .SH SEE ALSO .sp \fBceph\fP(8) .SH COPYRIGHT 2010-2014, Inktank Storage, Inc. and contributors. Licensed under Creative Commons BY-SA .\" Generated by docutils manpage writer. . ceph-0.80.11/Makefile.am0000664000175100017510000000334612623076744016737 0ustar jenkins-buildjenkins-buildAUTOMAKE_OPTIONS = gnu ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = autogen.sh ceph.spec.in ceph.spec # the "." here makes sure check-local builds gtest before it is used SUBDIRS = . src man EXTRA_DIST += \ src/test/run-cli-tests \ src/test/run-cli-tests-maybe-unset-ccache \ src/test/cli \ src/test/downloads \ udev/50-rbd.rules \ udev/60-ceph-partuuid-workaround.rules \ udev/95-ceph-osd.rules \ udev/95-ceph-osd-alt.rules \ share/known_hosts_drop.ceph.com \ share/id_dsa_drop.ceph.com \ share/id_dsa_drop.ceph.com.pub # why is it so hard to make autotools to this? install-data-local: -mkdir -p $(DESTDIR)$(datadir)/ceph -install -m 600 share/known_hosts_drop.ceph.com $(DESTDIR)$(datadir)/ceph/known_hosts_drop.ceph.com -install -m 600 share/id_dsa_drop.ceph.com $(DESTDIR)$(datadir)/ceph/id_dsa_drop.ceph.com -install -m 600 share/id_dsa_drop.ceph.com.pub $(DESTDIR)$(datadir)/ceph/id_dsa_drop.ceph.com.pub all-local: if WITH_DEBUG # We need gtest to build the rados-api tests. We only build those in # a debug build, though. @cd src/gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.a lib/libgtest_main.a endif check-local: # We build gtest this way, instead of using SUBDIRS, because with that, # gtest's own tests would be run and that would slow us down. @cd src/gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.a lib/libgtest_main.a # exercise cli tools $(srcdir)/src/test/run-cli-tests '$(top_builddir)/src/test' # "make distclean" both runs this and recurses into src/gtest, if # gtest is in DIST_SUBDIRS. Take extra care to not fail when # effectively cleaned twice. clean-local: @if test -e src/gtest/Makefile; then \ echo "Making clean in src/gtest"; \ cd src/gtest && $(MAKE) $(AM_MAKEFLAGS) clean; \ fi @rm -rf src/test/virtualenv ceph-0.80.11/ceph.spec0000664000175100017510000005273012623077023016466 0ustar jenkins-buildjenkins-build%bcond_with ocf %if ! (0%{?fedora} > 12 || 0%{?rhel} > 5) %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} %{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} %endif %{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d} ################################################################################# # common ################################################################################# Name: ceph Version: 0.80.11 Release: 0%{?dist} Summary: User space components of the Ceph file system License: GPL-2.0 Group: System Environment/Base URL: http://ceph.com/ Source0: http://ceph.com/download/%{name}-%{version}.tar.bz2 %if 0%{?fedora} || 0%{?centos} || 0%{?rhel} Patch0: init-ceph.in-fedora.patch %endif Requires: librbd1 = %{version}-%{release} Requires: librados2 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} Requires: ceph-common = %{version}-%{release} Requires: python Requires: python-ceph Requires: python-requests Requires: python-flask Requires: xfsprogs Requires: cryptsetup Requires: parted Requires: util-linux Requires: hdparm Requires(post): binutils BuildRequires: make BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: boost-devel BuildRequires: libedit-devel BuildRequires: perl BuildRequires: gdbm BuildRequires: pkgconfig BuildRequires: python BuildRequires: python-nose BuildRequires: libaio-devel BuildRequires: libcurl-devel BuildRequires: libxml2-devel BuildRequires: libuuid-devel BuildRequires: libblkid-devel >= 2.17 BuildRequires: leveldb-devel > 1.2 BuildRequires: xfsprogs-devel BuildRequires: yasm %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} BuildRequires: snappy-devel %endif ################################################################################# # specific ################################################################################# %if ! 0%{?rhel} || 0%{?fedora} BuildRequires: sharutils %endif %if 0%{defined suse_version} %if 0%{?suse_version} > 1210 Requires: gptfdisk BuildRequires: gperftools-devel %else Requires: scsirastools BuildRequires: google-perftools-devel %endif Recommends: logrotate BuildRequires: %insserv_prereq BuildRequires: mozilla-nss-devel BuildRequires: keyutils-devel BuildRequires: libatomic-ops-devel %else Requires: gdisk BuildRequires: nss-devel BuildRequires: keyutils-libs-devel BuildRequires: libatomic_ops-devel Requires: gdisk Requires(post): chkconfig Requires(preun):chkconfig Requires(preun):initscripts BuildRequires: gperftools-devel %endif %description Ceph is a massively scalable, open-source, distributed storage system that runs on commodity hardware and delivers object, block and file system storage. ################################################################################# # packages ################################################################################# %package -n ceph-common Summary: Ceph Common Group: System Environment/Base Requires: librbd1 = %{version}-%{release} Requires: librados2 = %{version}-%{release} Requires: python-ceph = %{version}-%{release} Requires: python-requests Requires: redhat-lsb-core # python-argparse is only needed in distros with Python 2.6 or lower %if (0%{?rhel} && 0%{?rhel} <= 6) || (0%{?suse_version} && 0%{?suse_version} <= 1110) Requires: python-argparse BuildRequires: python-argparse %endif %description -n ceph-common common utilities to mount and interact with a ceph storage cluster %package fuse Summary: Ceph fuse-based client Group: System Environment/Base Requires: %{name} BuildRequires: fuse-devel %description fuse FUSE based client for Ceph distributed network file system %package -n rbd-fuse Summary: Ceph fuse-based client Group: System Environment/Base Requires: %{name} Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} BuildRequires: fuse-devel %description -n rbd-fuse FUSE based client to map Ceph rbd images to files %package devel Summary: Ceph headers Group: Development/Libraries License: LGPL-2.0 Requires: %{name} = %{version}-%{release} Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} Requires: libcephfs_jni1 = %{version}-%{release} %description devel This package contains libraries and headers needed to develop programs that use Ceph. %package radosgw Summary: Rados REST gateway Group: Development/Libraries Requires: ceph-common = %{version}-%{release} Requires: librados2 = %{version}-%{release} %if 0%{defined suse_version} BuildRequires: libexpat-devel BuildRequires: FastCGI-devel Requires: apache2-mod_fcgid %else BuildRequires: expat-devel BuildRequires: fcgi-devel %endif %description radosgw radosgw is an S3 HTTP REST gateway for the RADOS object store. It is implemented as a FastCGI module using libfcgi, and can be used in conjunction with any FastCGI capable web server. %if %{with ocf} %package resource-agents Summary: OCF-compliant resource agents for Ceph daemons Group: System Environment/Base License: LGPL-2.0 Requires: %{name} = %{version} Requires: resource-agents %description resource-agents Resource agents for monitoring and managing Ceph daemons under Open Cluster Framework (OCF) compliant resource managers such as Pacemaker. %endif %package -n librados2 Summary: RADOS distributed object store client library Group: System Environment/Libraries License: LGPL-2.0 %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} Obsoletes: ceph-libs < %{version}-%{release} %endif %description -n librados2 RADOS is a reliable, autonomic distributed object storage cluster developed as part of the Ceph distributed storage system. This is a shared library allowing applications to access the distributed object store using a simple file-like interface. %package -n librbd1 Summary: RADOS block device client library Group: System Environment/Libraries License: LGPL-2.0 Requires: librados2 = %{version}-%{release} %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} Obsoletes: ceph-libs < %{version}-%{release} %endif %description -n librbd1 RBD is a block device striped across multiple distributed objects in RADOS, a reliable, autonomic distributed object storage cluster developed as part of the Ceph distributed storage system. This is a shared library allowing applications to manage these block devices. %package -n libcephfs1 Summary: Ceph distributed file system client library Group: System Environment/Libraries License: LGPL-2.0 %if 0%{?rhel} || 0%{?centos} || 0%{?fedora} Obsoletes: ceph-libs < %{version}-%{release} Obsoletes: ceph-libcephfs %endif %description -n libcephfs1 Ceph is a distributed network file system designed to provide excellent performance, reliability, and scalability. This is a shared library allowing applications to access a Ceph distributed file system via a POSIX-like interface. %package -n python-ceph Summary: Python libraries for the Ceph distributed filesystem Group: System Environment/Libraries License: LGPL-2.0 Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} %description -n python-ceph This package contains Python libraries for interacting with Cephs RADOS object storage. %package -n rest-bench Summary: RESTful benchmark Group: System Environment/Libraries License: LGPL-2.0 Requires: ceph-common = %{version}-%{release} %description -n rest-bench RESTful bencher that can be used to benchmark radosgw performance. %package -n ceph-test Summary: Ceph benchmarks and test tools Group: System Environment/Libraries License: LGPL-2.0 Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} %description -n ceph-test This package contains Ceph benchmarks and test tools. %package -n libcephfs_jni1 Summary: Java Native Interface library for CephFS Java bindings. Group: System Environment/Libraries License: LGPL-2.0 Requires: java Requires: libcephfs1 = %{version}-%{release} BuildRequires: java-devel %description -n libcephfs_jni1 This package contains the Java Native Interface library for CephFS Java bindings. %package -n cephfs-java Summary: Java libraries for the Ceph File System. Group: System Environment/Libraries License: LGPL-2.0 Requires: java Requires: libcephfs_jni1 = %{version}-%{release} BuildRequires: java-devel %if 0%{?el6} Requires: junit4 BuildRequires: junit4 %else Requires: junit BuildRequires: junit %endif %description -n cephfs-java This package contains the Java libraries for the Ceph File System. %package libs-compat Summary: Meta package to include ceph libraries. Group: System Environment/Libraries License: LGPL-2.0 Obsoletes: ceph-libs Requires: librados2 = %{version}-%{release} Requires: librbd1 = %{version}-%{release} Requires: libcephfs1 = %{version}-%{release} Provides: ceph-libs %description libs-compat This is a meta package, that pulls in librados2, librbd1 and libcephfs1. It is included for backwards compatibility with distributions that depend on the former ceph-libs package, which is now split up into these three subpackages. Packages still depending on ceph-libs should be fixed to depend on librados2, librbd1 or libcephfs1 instead. %if 0%{?opensuse} || 0%{?suse_version} %debug_package %endif ################################################################################# # common ################################################################################# %prep %setup -q %if 0%{?fedora} || 0%{?rhel} || 0%{?centos} %patch0 -p1 -b .init %endif %build # Find jni.h for i in /usr/{lib64,lib}/jvm/java/include{,/linux}; do [ -d $i ] && java_inc="$java_inc -I$i" done ./autogen.sh MY_CONF_OPT="" MY_CONF_OPT="$MY_CONF_OPT --with-radosgw" export RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS | sed -e 's/i386/i486/'` %{configure} CPPFLAGS="$java_inc" \ --prefix=/usr \ --localstatedir=/var \ --sysconfdir=/etc \ --docdir=%{_docdir}/ceph \ --with-nss \ --without-cryptopp \ --with-rest-bench \ --with-debug \ --enable-cephfs-java \ $MY_CONF_OPT \ %{?_with_ocf} \ CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" # fix bug in specific version of libedit-devel %if 0%{defined suse_version} sed -i -e "s/-lcurses/-lncurses/g" Makefile sed -i -e "s/-lcurses/-lncurses/g" src/Makefile sed -i -e "s/-lcurses/-lncurses/g" man/Makefile sed -i -e "s/-lcurses/-lncurses/g" src/ocf/Makefile sed -i -e "s/-lcurses/-lncurses/g" src/java/Makefile %endif make -j$(getconf _NPROCESSORS_ONLN) %install make DESTDIR=$RPM_BUILD_ROOT install find $RPM_BUILD_ROOT -type f -name "*.la" -exec rm -f {} ';' find $RPM_BUILD_ROOT -type f -name "*.a" -exec rm -f {} ';' install -D src/init-ceph $RPM_BUILD_ROOT%{_initrddir}/ceph install -D src/init-radosgw.sysv $RPM_BUILD_ROOT%{_initrddir}/ceph-radosgw install -D src/init-rbdmap $RPM_BUILD_ROOT%{_initrddir}/rbdmap install -D src/rbdmap $RPM_BUILD_ROOT%{_sysconfdir}/ceph/rbdmap mkdir -p $RPM_BUILD_ROOT%{_sbindir} ln -sf ../../etc/init.d/ceph %{buildroot}/%{_sbindir}/rcceph ln -sf ../../etc/init.d/ceph-radosgw %{buildroot}/%{_sbindir}/rcceph-radosgw install -m 0644 -D src/logrotate.conf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/ceph install -m 0644 -D src/rgw/logrotate.conf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/radosgw chmod 0644 $RPM_BUILD_ROOT%{_docdir}/ceph/sample.ceph.conf chmod 0644 $RPM_BUILD_ROOT%{_docdir}/ceph/sample.fetch_config # udev rules install -m 0644 -D udev/50-rbd.rules $RPM_BUILD_ROOT%{_udevrulesdir}/50-rbd.rules install -m 0644 -D udev/60-ceph-partuuid-workaround.rules $RPM_BUILD_ROOT%{_udevrulesdir}/60-ceph-partuuid-workaround.rules %if (0%{?rhel} && 0%{?rhel} < 7) install -m 0644 -D udev/95-ceph-osd-alt.rules $RPM_BUILD_ROOT/lib/udev/rules.d/95-ceph-osd.rules %else install -m 0644 -D udev/95-ceph-osd.rules $RPM_BUILD_ROOT/lib/udev/rules.d/95-ceph-osd.rules %endif %if 0%{?rhel} >= 7 || 0%{?fedora} mv $RPM_BUILD_ROOT/lib/udev/rules.d/95-ceph-osd.rules $RPM_BUILD_ROOT/usr/lib/udev/rules.d/95-ceph-osd.rules mv $RPM_BUILD_ROOT/sbin/mkcephfs $RPM_BUILD_ROOT/usr/sbin/mkcephfs mv $RPM_BUILD_ROOT/sbin/mount.ceph $RPM_BUILD_ROOT/usr/sbin/mount.ceph mv $RPM_BUILD_ROOT/sbin/mount.fuse.ceph $RPM_BUILD_ROOT/usr/sbin/mount.fuse.ceph %endif #set up placeholder directories mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/ceph mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/ceph mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/ceph mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/tmp mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/mon mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/osd mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/mds mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/bootstrap-osd mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/ceph/bootstrap-mds mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/radosgw %clean rm -rf $RPM_BUILD_ROOT %post /sbin/ldconfig /sbin/chkconfig --add ceph mkdir -p %{_localstatedir}/run/ceph/ %preun %if %{defined suse_version} %stop_on_removal ceph %endif if [ $1 = 0 ] ; then /sbin/service ceph stop >/dev/null 2>&1 /sbin/chkconfig --del ceph fi %postun /sbin/ldconfig %if %{defined suse_version} %insserv_cleanup %endif ################################################################################# # files ################################################################################# %files %defattr(-,root,root,-) %docdir %{_docdir} %dir %{_docdir}/ceph %{_docdir}/ceph/sample.ceph.conf %{_docdir}/ceph/sample.fetch_config %{_bindir}/cephfs %{_bindir}/ceph-clsinfo %{_bindir}/ceph-rest-api %{python_sitelib}/ceph_rest_api.py* %{_bindir}/crushtool %{_bindir}/monmaptool %{_bindir}/osdmaptool %{_bindir}/ceph-run %{_bindir}/ceph-mon %{_bindir}/ceph-mds %{_bindir}/ceph-osd %{_bindir}/ceph-rbdnamer %{_bindir}/librados-config %{_bindir}/ceph-client-debug %{_bindir}/ceph-debugpack %{_bindir}/ceph-coverage %{_bindir}/ceph_mon_store_converter %{_initrddir}/ceph %{_sbindir}/ceph-disk %{_sbindir}/ceph-disk-activate %{_sbindir}/ceph-disk-prepare %{_sbindir}/ceph-disk-udev %{_sbindir}/ceph-create-keys %{_sbindir}/rcceph %if 0%{?rhel} >= 7 || 0%{?fedora} %{_sbindir}/mkcephfs %{_sbindir}/mount.ceph %else /sbin/mkcephfs /sbin/mount.ceph %endif %dir %{_libdir}/ceph %{_libdir}/ceph/ceph_common.sh %dir %{_libdir}/rados-classes %{_libdir}/rados-classes/libcls_rbd.so* %{_libdir}/rados-classes/libcls_hello.so* %{_libdir}/rados-classes/libcls_rgw.so* %{_libdir}/rados-classes/libcls_lock.so* %{_libdir}/rados-classes/libcls_kvs.so* %{_libdir}/rados-classes/libcls_refcount.so* %{_libdir}/rados-classes/libcls_log.so* %{_libdir}/rados-classes/libcls_replica_log.so* %{_libdir}/rados-classes/libcls_statelog.so* %{_libdir}/rados-classes/libcls_user.so* %{_libdir}/rados-classes/libcls_version.so* %dir %{_libdir}/ceph/erasure-code %{_libdir}/ceph/erasure-code/libec_example.so* %{_libdir}/ceph/erasure-code/libec_fail_to_initialize.so* %{_libdir}/ceph/erasure-code/libec_fail_to_register.so* %{_libdir}/ceph/erasure-code/libec_hangs.so* %{_libdir}/ceph/erasure-code/libec_jerasure*.so* %{_libdir}/ceph/erasure-code/libec_test_jerasure*.so* %{_libdir}/ceph/erasure-code/libec_missing_entry_point.so* %{_udevrulesdir}/60-ceph-partuuid-workaround.rules %{_udevrulesdir}/95-ceph-osd.rules %config %{_sysconfdir}/bash_completion.d/ceph %config(noreplace) %{_sysconfdir}/logrotate.d/ceph %config(noreplace) %{_sysconfdir}/logrotate.d/radosgw %{_mandir}/man8/ceph-disk.8* %{_mandir}/man8/ceph-mon.8* %{_mandir}/man8/ceph-mds.8* %{_mandir}/man8/ceph-osd.8* %{_mandir}/man8/mkcephfs.8* %{_mandir}/man8/ceph-run.8* %{_mandir}/man8/ceph-rest-api.8* %{_mandir}/man8/crushtool.8* %{_mandir}/man8/osdmaptool.8* %{_mandir}/man8/monmaptool.8* %{_mandir}/man8/cephfs.8* %{_mandir}/man8/mount.ceph.8* %{_mandir}/man8/ceph-rbdnamer.8* %{_mandir}/man8/ceph-debugpack.8* %{_mandir}/man8/ceph-clsinfo.8.gz %{_mandir}/man8/librados-config.8.gz #set up placeholder directories %dir %{_localstatedir}/lib/ceph/ %dir %{_localstatedir}/lib/ceph/tmp %dir %{_localstatedir}/lib/ceph/mon %dir %{_localstatedir}/lib/ceph/osd %dir %{_localstatedir}/lib/ceph/mds %dir %{_localstatedir}/lib/ceph/bootstrap-osd %dir %{_localstatedir}/lib/ceph/bootstrap-mds %ghost %dir %{_localstatedir}/run/ceph/ ################################################################################# %files -n ceph-common %defattr(-,root,root,-) %{_bindir}/ceph %{_bindir}/ceph-authtool %{_bindir}/ceph-conf %{_bindir}/ceph-dencoder %{_bindir}/ceph-syn %{_bindir}/ceph-crush-location %{_bindir}/rados %{_bindir}/rbd %{_bindir}/ceph-post-file %{_bindir}/ceph-brag %{_mandir}/man8/ceph-authtool.8* %{_mandir}/man8/ceph-conf.8* %{_mandir}/man8/ceph-dencoder.8* %{_mandir}/man8/ceph-syn.8* %{_mandir}/man8/ceph-post-file.8* %{_mandir}/man8/ceph.8* %{_mandir}/man8/rados.8* %{_mandir}/man8/rbd.8* %{_datadir}/ceph/known_hosts_drop.ceph.com %{_datadir}/ceph/id_dsa_drop.ceph.com %{_datadir}/ceph/id_dsa_drop.ceph.com.pub %dir %{_sysconfdir}/ceph/ %dir %{_localstatedir}/log/ceph/ %config %{_sysconfdir}/bash_completion.d/rados %config %{_sysconfdir}/bash_completion.d/rbd %config(noreplace) %{_sysconfdir}/ceph/rbdmap %{_initrddir}/rbdmap %{_udevrulesdir}/50-rbd.rules %postun -n ceph-common # Package removal cleanup if [ "$1" -eq "0" ] ; then rm -rf /var/log/ceph rm -rf /etc/ceph fi ################################################################################# %files fuse %defattr(-,root,root,-) %{_bindir}/ceph-fuse %{_mandir}/man8/ceph-fuse.8* %if 0%{?rhel} >= 7 || 0%{?fedora} %{_sbindir}/mount.fuse.ceph %else /sbin/mount.fuse.ceph %endif ################################################################################# %files -n rbd-fuse %defattr(-,root,root,-) %{_bindir}/rbd-fuse %{_mandir}/man8/rbd-fuse.8* ################################################################################# %files devel %defattr(-,root,root,-) %dir %{_includedir}/cephfs %{_includedir}/cephfs/libcephfs.h %dir %{_includedir}/rados %{_includedir}/rados/librados.h %{_includedir}/rados/librados.hpp %{_includedir}/rados/buffer.h %{_includedir}/rados/page.h %{_includedir}/rados/crc32c.h %{_includedir}/rados/rados_types.h %{_includedir}/rados/rados_types.hpp %{_includedir}/rados/memory.h %dir %{_includedir}/rbd %{_includedir}/rbd/librbd.h %{_includedir}/rbd/librbd.hpp %{_includedir}/rbd/features.h %{_libdir}/libcephfs.so %{_libdir}/librbd.so %{_libdir}/librados.so %{_libdir}/libcephfs_jni.so ################################################################################# %files radosgw %defattr(-,root,root,-) %{_initrddir}/ceph-radosgw %{_bindir}/radosgw %{_bindir}/radosgw-admin %{_mandir}/man8/radosgw.8* %{_mandir}/man8/radosgw-admin.8* %{_sbindir}/rcceph-radosgw %config %{_sysconfdir}/bash_completion.d/radosgw-admin %dir %{_localstatedir}/log/radosgw/ %post radosgw /sbin/ldconfig %if %{defined suse_version} %fillup_and_insserv -f -y ceph-radosgw %endif %preun radosgw %if %{defined suse_version} %stop_on_removal ceph-radosgw %endif %postun radosgw /sbin/ldconfig %if %{defined suse_version} %restart_on_update ceph-radosgw %insserv_cleanup %endif # Package removal cleanup if [ "$1" -eq "0" ] ; then rm -rf /var/log/radosgw fi ################################################################################# %if %{with ocf} %files resource-agents %defattr(0755,root,root,-) %dir /usr/lib/ocf %dir /usr/lib/ocf/resource.d %dir /usr/lib/ocf/resource.d/ceph /usr/lib/ocf/resource.d/%{name}/* %endif ################################################################################# %files -n librados2 %defattr(-,root,root,-) %{_libdir}/librados.so.* %post -n librados2 /sbin/ldconfig %postun -n librados2 /sbin/ldconfig ################################################################################# %files -n librbd1 %defattr(-,root,root,-) %{_libdir}/librbd.so.* %if 0%{?rhel} >= 7 || 0%{?fedora} /usr/lib/udev/rules.d/50-rbd.rules %else /lib/udev/rules.d/50-rbd.rules %endif %post -n librbd1 /sbin/ldconfig mkdir -p /usr/lib64/qemu/ ln -sf %{_libdir}/librbd.so.1 /usr/lib64/qemu/librbd.so.1 %postun -n librbd1 /sbin/ldconfig ################################################################################# %files -n libcephfs1 %defattr(-,root,root,-) %{_libdir}/libcephfs.so.* %post -n libcephfs1 /sbin/ldconfig %postun -n libcephfs1 /sbin/ldconfig ################################################################################# %files -n python-ceph %defattr(-,root,root,-) %{python_sitelib}/rados.py* %{python_sitelib}/rbd.py* %{python_sitelib}/cephfs.py* %{python_sitelib}/ceph_argparse.py* ################################################################################# %files -n rest-bench %defattr(-,root,root,-) %{_bindir}/rest-bench ################################################################################# %files -n ceph-test %defattr(-,root,root,-) %{_bindir}/ceph_bench_log %{_bindir}/ceph_dupstore %{_bindir}/ceph_kvstorebench %{_bindir}/ceph_multi_stress_watch %{_bindir}/ceph_erasure_code %{_bindir}/ceph_erasure_code_benchmark %{_bindir}/ceph_omapbench %{_bindir}/ceph_psim %{_bindir}/ceph_radosacl %{_bindir}/ceph_rgw_jsonparser %{_bindir}/ceph_rgw_multiparser %{_bindir}/ceph_scratchtool %{_bindir}/ceph_scratchtoolpp %{_bindir}/ceph_smalliobench %{_bindir}/ceph_smalliobenchdumb %{_bindir}/ceph_smalliobenchfs %{_bindir}/ceph_smalliobenchrbd %{_bindir}/ceph-objectstore-tool %{_bindir}/ceph_streamtest %{_bindir}/ceph_test_* %{_bindir}/ceph_tpbench %{_bindir}/ceph_xattr_bench %{_bindir}/ceph-monstore-tool %{_bindir}/ceph-osdomap-tool %{_bindir}/ceph-kvstore-tool %files -n libcephfs_jni1 %defattr(-,root,root,-) %{_libdir}/libcephfs_jni.so.* %files -n cephfs-java %defattr(-,root,root,-) %{_javadir}/libcephfs.jar %{_javadir}/libcephfs-test.jar %files libs-compat # We need an empty %files list for ceph-libs-compat, to tell rpmbuild to actually # build this meta package. %changelog ceph-0.80.11/missing0000755000175100017510000001533012261335263016264 0ustar jenkins-buildjenkins-build#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/depcomp0000755000175100017510000005601612261335263016250 0ustar jenkins-buildjenkins-build#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/COPYING0000664000175100017510000001346712623076744015743 0ustar jenkins-buildjenkins-buildFormat-Specification: http://anonscm.debian.org/viewvc/dep/web/deps/dep5/copyright-format.xml?revision=279&view=markup Name: ceph Maintainer: Sage Weil Source: http://ceph.com/ Files: * Copyright: (c) 2004-2010 by Sage Weil License: LGPL2.1 (see COPYING-LGPL2.1) Files: doc/* Copyright: (c) 2010-2012 New Dream Network and contributors License: Creative Commons Attribution-ShareAlike (CC BY-SA) Files: src/mount/canonicalize.c Copyright: Copyright (C) 1993 Rick Sladkey License: LGPL2 or later Files: src/os/btrfs_ioctl.h Copyright: Copyright (C) 2007 Oracle. All rights reserved. License: GPL2 Files: src/include/ceph_hash.cc Copyright: None License: Public domain Files: src/common/bloom_filter.hpp Copyright: Copyright (C) 2000 Arash Partow License: Boost Software License, Version 1.0 Files: m4/acx_pthread.m4 Copyright: Steven G. Johnson License: GPLWithACException Files: src/common/crc32c_intel*: Copyright: Copyright 2012-2013 Intel Corporation All Rights Reserved. License: BSD 3-clause Files: src/common/sctp_crc32.c: Copyright: Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b) 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. c) Neither the name of Cisco Systems, 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. Files: src/json_spirit Copyright: Copyright John W. Wilkinson 2007 - 2011 License: The MIT License Copyright (c) 2007 - 2010 John W. Wilkinson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Files: src/test/common/Throttle.cc src/test/filestore/chain_xattr.cc Copyright: Copyright (C) 2013 Cloudwatt License: LGPL2 or later Files: src/osd/ErasureCodePluginJerasure/*.{c,h} Copyright: Copyright (c) 2011, James S. Plank License: 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 the University of Tennessee 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 HOLDER 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. Packaging: Copyright (C) 2004-2009 by Sage Weil Copyright (C) 2010 Canonical, Ltd. Licensed under LGPL-2.1 ceph-0.80.11/test-driver0000755000175100017510000001027712261335263017070 0ustar jenkins-buildjenkins-build#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2013-07-13.22; # UTC # Copyright (C) 2011-2013 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <$log_file 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then estatus=1 fi case $estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/ltmain.sh0000644000175100017510000105204412623076760016517 0ustar jenkins-buildjenkins-build # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.7ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1.7ubuntu1" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 ceph-0.80.11/Makefile.in0000664000175100017510000007030012623076764016744 0ustar jenkins-buildjenkins-build# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program 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. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/ceph.spec.in COPYING ar-lib compile config.guess \ config.sub install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_check_classpath.m4 \ $(top_srcdir)/m4/ac_prog_jar.m4 \ $(top_srcdir)/m4/ac_prog_javac.m4 \ $(top_srcdir)/m4/ac_prog_javac_works.m4 \ $(top_srcdir)/m4/ac_prog_javah.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/ax_c_pretty_func.m4 \ $(top_srcdir)/m4/ax_c_var_func.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_cxx_static_cast.m4 \ $(top_srcdir)/m4/ax_intel.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/acconfig.h CONFIG_CLEAN_FILES = ceph.spec CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CXXFLAGS = @AM_CXXFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@ CC = @CC@ CCAS = @CCAS@ CCASDEPMODE = @CCASDEPMODE@ CCASFLAGS = @CCASFLAGS@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOPP_CFLAGS = @CRYPTOPP_CFLAGS@ CRYPTOPP_LIBS = @CRYPTOPP_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXTRA_CLASSPATH_JAR = @EXTRA_CLASSPATH_JAR@ FGREP = @FGREP@ GCOV_PREFIX_STRIP = @GCOV_PREFIX_STRIP@ GIT_CHECK = @GIT_CHECK@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTEL_FLAGS = @INTEL_FLAGS@ INTEL_PCLMUL_FLAGS = @INTEL_PCLMUL_FLAGS@ INTEL_SSE2_FLAGS = @INTEL_SSE2_FLAGS@ INTEL_SSE3_FLAGS = @INTEL_SSE3_FLAGS@ INTEL_SSE4_1_FLAGS = @INTEL_SSE4_1_FLAGS@ INTEL_SSE4_2_FLAGS = @INTEL_SSE4_2_FLAGS@ INTEL_SSE_FLAGS = @INTEL_SSE_FLAGS@ INTEL_SSSE3_FLAGS = @INTEL_SSSE3_FLAGS@ JAR = @JAR@ JAVAC = @JAVAC@ JAVAH = @JAVAH@ JDK_CPPFLAGS = @JDK_CPPFLAGS@ KEYUTILS_LIB = @KEYUTILS_LIB@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEDIT_CFLAGS = @LIBEDIT_CFLAGS@ LIBEDIT_LIBS = @LIBEDIT_LIBS@ LIBFUSE = @LIBFUSE@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTCMALLOC = @LIBTCMALLOC@ LIBTOOL = @LIBTOOL@ LIBZFS_CFLAGS = @LIBZFS_CFLAGS@ LIBZFS_LIBS = @LIBZFS_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NSS_CFLAGS = @NSS_CFLAGS@ NSS_LIBS = @NSS_LIBS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RESOLV_LIBS = @RESOLV_LIBS@ RPM_RELEASE = @RPM_RELEASE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WARN_IGNORED_QUALIFIERS = @WARN_IGNORED_QUALIFIERS@ WARN_TYPE_LIMITS = @WARN_TYPE_LIMITS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = gnu ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = autogen.sh ceph.spec.in ceph.spec src/test/run-cli-tests \ src/test/run-cli-tests-maybe-unset-ccache src/test/cli \ src/test/downloads udev/50-rbd.rules \ udev/60-ceph-partuuid-workaround.rules udev/95-ceph-osd.rules \ udev/95-ceph-osd-alt.rules share/known_hosts_drop.ceph.com \ share/id_dsa_drop.ceph.com share/id_dsa_drop.ceph.com.pub # the "." here makes sure check-local builds gtest before it is used SUBDIRS = . src man all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): ceph.spec: $(top_builddir)/config.status $(srcdir)/ceph.spec.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-recursive all-am: Makefile all-local installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-data-local install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) check-am install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ am--refresh check check-am check-local clean clean-cscope \ clean-generic clean-libtool clean-local cscope cscopelist-am \ ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \ dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \ distclean-generic distclean-libtool distclean-tags \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-data-local install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # why is it so hard to make autotools to this? install-data-local: -mkdir -p $(DESTDIR)$(datadir)/ceph -install -m 600 share/known_hosts_drop.ceph.com $(DESTDIR)$(datadir)/ceph/known_hosts_drop.ceph.com -install -m 600 share/id_dsa_drop.ceph.com $(DESTDIR)$(datadir)/ceph/id_dsa_drop.ceph.com -install -m 600 share/id_dsa_drop.ceph.com.pub $(DESTDIR)$(datadir)/ceph/id_dsa_drop.ceph.com.pub all-local: # We need gtest to build the rados-api tests. We only build those in # a debug build, though. @WITH_DEBUG_TRUE@ @cd src/gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.a lib/libgtest_main.a check-local: # We build gtest this way, instead of using SUBDIRS, because with that, # gtest's own tests would be run and that would slow us down. @cd src/gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.a lib/libgtest_main.a # exercise cli tools $(srcdir)/src/test/run-cli-tests '$(top_builddir)/src/test' # "make distclean" both runs this and recurses into src/gtest, if # gtest is in DIST_SUBDIRS. Take extra care to not fail when # effectively cleaned twice. clean-local: @if test -e src/gtest/Makefile; then \ echo "Making clean in src/gtest"; \ cd src/gtest && $(MAKE) $(AM_MAKEFLAGS) clean; \ fi @rm -rf src/test/virtualenv # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ceph-0.80.11/compile0000755000175100017510000001624512261335263016251 0ustar jenkins-buildjenkins-build#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ceph-0.80.11/README0000664000175100017510000001121212623076744015552 0ustar jenkins-buildjenkins-build============================================ Ceph - a scalable distributed storage system ============================================ Please see http://ceph.com/ for current info. Contributing Code ================= Most of Ceph is licensed under the LGPL version 2.1. Some miscellaneous code is under BSD-style license or is public domain. The documentation is licensed under Creative Commons Attribution-ShareAlike (CC BY-SA). There are a handful of headers included here that are licensed under the GPL. Please see the file COPYING for a full inventory of licenses by file. Code contributions must include a valid "Signed-off-by" acknowledging the license for the modified or contributed file. Please see the file SubmittingPatches for details on what that means and on how to generate and submit patches. We do not require assignment of copyright to contribute code; code is contributed under the terms of the applicable license. Building Ceph ============= To prepare the source tree after it has been git cloned, $ git submodule update --init To build the server daemons, and FUSE client, execute the following: $ ./autogen.sh $ ./configure $ make (Note that the FUSE client will only be built if libfuse is present.) Dependencies ------------ The configure script will complain about any missing dependencies as it goes. You can also refer to debian/control or ceph.spec.in for the package build dependencies on those platforms. In many cases, dependencies can be avoided with --with-foo or --without-bar switches. For example, $ ./configure --with-nss # use libnss instead of libcrypto++ $ ./configure --without-radosgw # do not build radosgw and avoid libfcgi-dev $ ./configure --without-tcmalloc # avoid google-perftools dependency Building packages ----------------- You can build packages for Debian or Debian-derived (e.g., Ubuntu) systems with $ sudo apt-get install dpkg-dev $ dpkg-checkbuilddeps # make sure we have all dependencies $ dpkg-buildpackage For RPM-based systems (Redhat, Suse, etc.), $ rpmbuild Building the Documentation ========================== Prerequisites ------------- To build the documentation, you must install the following: - python-dev - python-pip - python-virtualenv - doxygen - ditaa - libxml2-dev - libxslt-dev - dot - graphviz For example: sudo apt-get install python-dev python-pip python-virtualenv doxygen ditaa libxml2-dev libxslt-dev dot graphviz Building the Documentation -------------------------- To build the documentation, ensure that you are in the top-level `/ceph directory, and execute the build script. For example: $ admin/build-doc Build Prerequisites =================== debian-based ------------ To build the source code, you must install the following: - automake - autoconf - pkg-config - gcc - g++ - make - libboost-dev - libedit-dev - libssl-dev - libtool - libfcgi - libfcgi-dev - xfslibs-dev - libfuse-dev - linux-kernel-headers - libcrypto++-dev - libaio-dev - libgoogle-perftools-dev - libkeyutils-dev - uuid-dev - libblkid-dev - libatomic-ops-dev - libboost-program-options-dev - libboost-system-dev - libboost-thread-dev - libexpat1-dev - libleveldb-dev - libsnappy-dev - libcurl4-gnutls-dev - python-argparse - python-flask For example: $ apt-get install automake autoconf pkg-config gcc g++ make libboost-dev libedit-dev libssl-dev libtool libfcgi libfcgi-dev xfslibs-dev libfuse-dev linux-kernel-headers libcrypto++-dev libaio-dev libgoogle-perftools-dev libkeyutils-dev uuid-dev libblkid-dev libatomic-ops-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libexpat1-dev libleveldb-dev libsnappy-dev libcurl4-gnutls-dev python-argparse python-flask python-nose Note: libsnappy-dev and libleveldb-dev are not available upstream for natty, oneiric, and squeeze. Backports for Ceph can be found at ceph.com/debian-leveldb. rpm-based --------- These are the rpm packages needed to install in an rpm-based OS: autoconf automake gcc gcc-c++ make libtool python-argparse python-flask libuuid-devel libblkid-devel keyutils-libs-devel cryptopp-devel nss-devel fcgi-devel expat-devel libcurl-devel xfsprogs-devel fuse-devel gperftools-devel libedit-devel libatomic_ops-devel snappy-devel leveldb-devel libaio-devel boost-devel For example: $ yum install autoconf automake gcc gcc-c++ make libtool python-argparse python-flask libuuid-devel libblkid-devel keyutils-libs-devel cryptopp-devel nss-devel fcgi-devel expat-devel libcurl-devel xfsprogs-devel fuse-devel gperftools-devel libedit-devel libatomic_ops-devel snappy-devel leveldb-devel libaio-devel boost-devel python-nose